pax_global_header00006660000000000000000000000064145037220710014513gustar00rootroot0000000000000052 comment=a2d5928911535ca37c266dd50899a6eacb0250cc golang-gonum-v1-gonum-0.14.0/000077500000000000000000000000001450372207100156365ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/.codecov.yml000066400000000000000000000000471450372207100200620ustar00rootroot00000000000000fixes: - "src/gonum.org/v1/gonum/::" golang-gonum-v1-gonum-0.14.0/.github/000077500000000000000000000000001450372207100171765ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001450372207100213615ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000015611450372207100240560ustar00rootroot00000000000000--- name: Bug Report about: Report a problem with Gonum --- ### What are you trying to do? ### What did you do? ### What did you expect to happen? ### What actually happened? ### What version of Go and Gonum are you using? ### Does this issue reproduce with the current master? golang-gonum-v1-gonum-0.14.0/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000015201450372207100251040ustar00rootroot00000000000000--- name: Feature request about: Request an addition to an existing package --- ### What are you trying to do? ### What did you try? ### How does Gonum not allow you to achieve your goal? ### What version of Go and Gonum are you using? ### Is this feature absent from the current master? ### Are you able to help contribute the feature? golang-gonum-v1-gonum-0.14.0/.github/ISSUE_TEMPLATE/proposal.md000066400000000000000000000010501450372207100235360ustar00rootroot00000000000000--- name: Proposal about: Propose a new package or significant addition of functionality --- ### Background ### Proposal ### Potential impact of proposal golang-gonum-v1-gonum-0.14.0/.github/ISSUE_TEMPLATE/question.md000066400000000000000000000005031450372207100235500ustar00rootroot00000000000000--- name: Question about: Ask at the Gonum discussion list https://groups.google.com/forum/#!forum/gonum-dev --- # :no_entry_sign: INVALID :no_entry_sign: golang-gonum-v1-gonum-0.14.0/.github/PULL_REQUEST_TEMPLATE000066400000000000000000000007341450372207100224040ustar00rootroot00000000000000Please take a look. golang-gonum-v1-gonum-0.14.0/.github/workflows/000077500000000000000000000000001450372207100212335ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/.github/workflows/ci.yml000066400000000000000000000055171450372207100223610ustar00rootroot00000000000000name: CI on: pull_request: branches: [ master ] jobs: build: name: Build strategy: matrix: # Do not move this line; it is referred to by README.md. # Versions of Go that are explicitly supported by Gonum. go-version: [1.21.x, 1.20.x] platform: [ubuntu-latest, macos-latest] force-goarch: ["", "386"] tags: - "" - "-tags bounds" - "-tags noasm" - "-tags safe" exclude: - platform: ubuntu-latest tags: "-tags bounds" force-goarch: "386" - platform: ubuntu-latest tags: "-tags noasm" force-goarch: "386" - platform: ubuntu-latest tags: "-tags safe" force-goarch: "386" - platform: macos-latest force-goarch: "386" - platform: macos-latest tags: "-tags bounds" - platform: macos-latest tags: "-tags noasm" - platform: macos-latest tags: "-tags safe" runs-on: ${{ matrix.platform }} env: GO111MODULE: on GOPATH: ${{ github.workspace }} TAGS: ${{ matrix.tags }} FORCE_GOARCH: ${{ matrix.force-goarch }} defaults: run: working-directory: ${{ env.GOPATH }}/src/gonum.org/v1/gonum steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 with: path: ${{ env.GOPATH }}/src/gonum.org/v1/gonum - name: Cache-Go uses: actions/cache@v2 with: # In order: # * Module download cache # * Build cache (Linux) # * Build cache (Mac) # * Build cache (Windows) path: | ~/go/pkg/mod ~/.cache/go-build ~/Library/Caches/go-build '%LocalAppData%\go-build' key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - name: Check copyrights+imports+formatting+generate if: matrix.platform == 'ubuntu-latest' && matrix.tags == '' run: | sudo apt-get update sudo apt-get install -qq ragel ./.github/workflows/script.d/deps.sh ./.github/workflows/script.d/check-copyright.sh ./.github/workflows/script.d/check-imports.sh ./.github/workflows/script.d/check-formatting.sh ./.github/workflows/script.d/check-generate.sh - name: Test run: | ./.github/workflows/script.d/test.sh - name: Coverage if: matrix.platform == 'ubuntu-latest' run: | ./.github/workflows/script.d/test-coverage.sh - name: Upload-Coverage if: matrix.platform == 'ubuntu-latest' uses: codecov/codecov-action@v1 golang-gonum-v1-gonum-0.14.0/.github/workflows/codecov.yml000066400000000000000000000034051450372207100234020ustar00rootroot00000000000000name: Codecov on: pull_request: branches: [ master ] types: - closed jobs: build: name: Build if: github.event.pull_request.merged == true strategy: matrix: go-version: [1.21.x] platform: [ubuntu-latest] tags: - "" - "-tags bounds" - "-tags noasm" - "-tags safe" runs-on: ${{ matrix.platform }} env: GO111MODULE: on GOPATH: ${{ github.workspace }} TAGS: ${{ matrix.tags }} defaults: run: working-directory: ${{ env.GOPATH }}/src/gonum.org/v1/gonum steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 with: path: ${{ env.GOPATH }}/src/gonum.org/v1/gonum - name: Cache-Go uses: actions/cache@v2 with: # In order: # * Module download cache # * Build cache (Linux) # * Build cache (Mac) # * Build cache (Windows) path: | ~/go/pkg/mod ~/.cache/go-build ~/Library/Caches/go-build '%LocalAppData%\go-build' key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - name: Coverage if: matrix.platform == 'ubuntu-latest' run: | ./.github/workflows/script.d/test-coverage.sh - name: Upload-Coverage if: matrix.platform == 'ubuntu-latest' uses: codecov/codecov-action@v1 with: override_pr: ${{ github.event.pull_request.number }} override_commit: ${{ github.event.pull_request.merge_commit_sha }} override_branch: "refs/heads/master" golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/000077500000000000000000000000001450372207100227615ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/check-copyright.sh000077500000000000000000000002301450372207100263760ustar00rootroot00000000000000#!/bin/bash set -e check-copyright -notice "(Copyright ©20[0-9]{2} The Gonum Authors\. All rights reserved\.|[Cc]ode generated by .*; DO NOT EDIT\.)" golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/check-formatting.sh000077500000000000000000000002431450372207100265440ustar00rootroot00000000000000#!/bin/bash test -z "$(goimports -d .)" if [[ -n "$(gofmt -s -l .)" ]]; then echo -e '\e[31mCode not gofmt simplified in:\n\n' gofmt -s -l . echo -e "\e[0" fi golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/check-generate.sh000077500000000000000000000007511450372207100261700ustar00rootroot00000000000000#!/bin/bash # Reset the tree to the current commit to handle # any writes during the build. git reset --hard go generate gonum.org/v1/gonum/blas go generate gonum.org/v1/gonum/blas/gonum go generate gonum.org/v1/gonum/unit go generate gonum.org/v1/gonum/unit/constant go generate gonum.org/v1/gonum/graph/formats/dot go generate gonum.org/v1/gonum/graph/formats/rdf go generate gonum.org/v1/gonum/stat/card if [ -n "$(git diff)" ]; then git diff exit 1 fi rm -rf * git reset --hard golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/check-imports.sh000077500000000000000000000001051450372207100260640ustar00rootroot00000000000000#!/bin/bash set -e check-imports -b "math/rand,github.com/gonum/.*" golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/deps.sh000077500000000000000000000007751450372207100242640ustar00rootroot00000000000000#!/bin/bash set -ex # Required for format check. go install golang.org/x/tools/cmd/goimports@latest # Required for imports check. go install gonum.org/v1/tools/cmd/check-imports@latest # Required for copyright header check. go install gonum.org/v1/tools/cmd/check-copyright@latest # Required for coverage. go install golang.org/x/tools/cmd/cover@latest # Required for dot parser checks. go install github.com/goccmack/gocc # Required for rdf parser checks. go install golang.org/x/tools/cmd/stringer@latest golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/test-coverage.sh000077500000000000000000000024001450372207100260640ustar00rootroot00000000000000#!/bin/bash MODE=set PROFILE_OUT="${PWD}/profile.out" ACC_OUT="${PWD}/coverage.txt" testCover() { # set the return value to 0 (successful) retval=0 # get the directory to check from the parameter. Default to '.' d=${1:-.} # skip if there are no Go files here ls $d/*.go &> /dev/null || return $retval # switch to the directory to check pushd $d > /dev/null # create the coverage profile coverageresult=$(go test $TAGS -coverprofile="${PROFILE_OUT}" -covermode=${MODE}) # output the result so we can check the shell output echo ${coverageresult} # append the results to acc.out if coverage didn't fail, else set the retval to 1 (failed) ( [[ ${coverageresult} == *FAIL* ]] && retval=1 ) || ( [ -f "${PROFILE_OUT}" ] && grep -v "mode: ${MODE}" "${PROFILE_OUT}" >> "${ACC_OUT}" ) # return to our working dir popd > /dev/null # return our return value return $retval } # Init coverage.txt echo "mode: ${MODE}" > $ACC_OUT # Run test coverage on all directories containing go files except testlapack, testblas, testgraph and testrand. find . -type d -not -path '*testlapack*' -and -not -path '*testblas*' -and -not -path '*testgraph*' -and -not -path '*testrand*' | while read d; do testCover $d || exit; done golang-gonum-v1-gonum-0.14.0/.github/workflows/script.d/test.sh000077500000000000000000000003071450372207100242770ustar00rootroot00000000000000#!/bin/bash # Travis clobbers GOARCH env vars so this is necessary here. if [[ -n $FORCE_GOARCH ]]; then export GOARCH=$FORCE_GOARCH fi go get -d -v ./... go build -v ./... go test $TAGS -v ./... golang-gonum-v1-gonum-0.14.0/.github/workflows/staticcheck.yml000066400000000000000000000004641450372207100242470ustar00rootroot00000000000000name: Staticcheck on: pull_request: branches: [master] jobs: ci: name: lint runs-on: ubuntu-latest env: GO111MODULE: on steps: - uses: actions/checkout@v2 with: fetch-depth: 1 - uses: dominikh/staticcheck-action@v1 with: version: "2022.1" golang-gonum-v1-gonum-0.14.0/AUTHORS000066400000000000000000000113101450372207100167020ustar00rootroot00000000000000# 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 # The email address is not required for organizations. # Please keep the list sorted. Alexander Egurnov Andrei Blinnikov antichris Bailey Lissington Bill Gray Bill Noon Brendan Tracey Brent Pedersen Bulat Khasanov Chad Kunde Chan Kwan Yin Chih-Wei Chang Chong-Yeol Nah Chris Tessum Christophe Meessen Christopher Waldon Clayton Northey Dan Kortschak Daniel Fireman Dario Heinisch David Kleiven David Samborski Davor Kapsa DeepMind Technologies Delaney Gillilan Dezmond Goff Dong-hee Na Dustin Spicuzza Egon Elbre Ekaterina Efimova Ethan Burns Evert Lammerts Evgeny Savinov Fabian Wickborn Facundo Gaich Fazlul Shahriar Francesc Campoy Google Inc Gustaf Johansson Hossein Zolfi Iakov Davydov Igor Mikushkin Iskander Sharipov Jalem Raj Rohit James Bell James Bowman James Holmes <32bitkid@gmail.com> Janne Snabb Jeremy Atkinson Jes Cok Jinesi Yelizati Jonas Kahler Jonas Schulze Jonathan J Lawlor Jonathan Reiter Jonathan Schroeder Joost van Amersfoort Joseph Watson Josh Wilson Julien Roland Kai Trukenmüller Kent English Kevin C. Zimmerman Kirill Motkov Konstantin Shaposhnikov Leonid Kneller Lyron Winderbaum Marco Leogrande Mark Canning Mark Skilbeck Martin Diz Matthew Connelly Matthieu Di Mercurio Max Halford Maxim Sergeev Microsoft Corporation MinJae Kwon Nathan Edwards Nick Potts Nils Wogatzky Olivier Wulveryck Or Rikon Patricio Whittingslow Patrick DeVivo Pontus Melke Renee French Rishi Desai Robin Eklind Roger Welin Rondall Jones Sam Zaydel Samuel Kelemen Saran Ahluwalia Scott Holden Scott Kiesel Sebastien Binet Shawn Smith Sintela Ltd source{d} Spencer Lyon Steve McCoy Taesu Pyo Takeshi Yoneda Tamir Hyman The University of Adelaide The University of Minnesota The University of Washington Thomas Berg Tobin Harding Valentin Deleplace Vincent Thiery Vladimír Chalupecký Will Tekulve Yasuhiro Matsumoto Yevgeniy Vahlis Yucheng Zhu Yunomi Zoe Juozapaitis golang-gonum-v1-gonum-0.14.0/CONDUCT.md000066400000000000000000000170501450372207100172620ustar00rootroot00000000000000# [](https://github.com/gonum) Gonum Community Code of Conduct ## About Online communities include people from many different backgrounds. The Gonum contributors are committed to providing a friendly, safe and welcoming environment for all, regardless of gender identity and expression, sexual orientation, disabilities, neurodiversity, physical appearance, body size, ethnicity, nationality, race, age, religion, or similar personal characteristics. The first goal of the Code of Conduct is to specify a baseline standard of behavior so that people with different social values and communication styles can talk about Gonum effectively, productively, and respectfully. The second goal is to provide a mechanism for resolving conflicts in the community when they arise. The third goal of the Code of Conduct is to make our community welcoming to people from different backgrounds. Diversity is critical to the project; for Gonum to be successful, it needs contributors and users from all backgrounds. (See [Go, Open Source, Community.](https://blog.golang.org/open-source)) We believe that healthy debate and disagreement are essential to a healthy project and community. However, it is never ok to be disrespectful. We value diverse opinions, but we value respectful behavior more. ## Numerical Gopher values These are the values to which people in the Gonum community (“Numerical Gophers”) should aspire. - Be friendly and welcoming - Be patient - Remember that people have varying communication styles and that not everyone is using their native language. (Meaning and tone can be lost in translation.) - Be thoughtful - Productive communication requires effort. Think about how your words will be interpreted. - Remember that sometimes it is best to refrain entirely from commenting. - Be respectful - In particular, respect differences of opinion. - Be charitable - Interpret the arguments of others in good faith, do not seek to disagree. - When we do disagree, try to understand why. - Avoid destructive behavior: - Derailing: stay on topic; if you want to talk about something else, start a new conversation. - Unconstructive criticism: don't merely decry the current state of affairs; offer—or at least solicit—suggestions as to how things may be improved. - Snarking (pithy, unproductive, sniping comments) - Discussing potentially offensive or sensitive issues; this all too often leads to unnecessary conflict. - Microaggressions: brief and commonplace verbal, behavioral and environmental indignities that communicate hostile, derogatory or negative slights and insults to a person or group. People are complicated. You should expect to be misunderstood and to misunderstand others; when this inevitably occurs, resist the urge to be defensive or assign blame. Try not to take offense where no offense was intended. Give people the benefit of the doubt. Even if the intent was to provoke, do not rise to it. It is the responsibility of *all parties* to de-escalate conflict when it arises. ## Code of Conduct ### Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ### Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ### Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ### Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. This Code of Conduct also applies outside the project spaces when the Code of Conduct Committee have a reasonable belief that an individual's behavior may have a negative impact on the project or its community. ### Conflict Resolution We do not believe that all conflict is bad; healthy debate and disagreement often yield positive results. However, it is never okay to be disrespectful or to engage in behavior that violates the project's code of conduct. If you see someone violating the code of conduct, you are encouraged to address the behavior directly with those involved. Many issues can be resolved quickly and easily, and this gives people more control over the outcome of their dispute. If you are unable to resolve the matter for any reason, or if the behavior is threatening or harassing, report it. We are dedicated to providing an environment where participants feel welcome and safe. Reports should be directed to Sebastien Binet, Dan Kortschak and Roman Werpachowski, the Gonum Code of Conduct Committee, at gonum-conduct@googlegroups.com. It is the Code of Conduct Committee's duty to receive and address reported violations of the code of conduct. If for any reason you are uncomfortable reaching out the Code of Conduct Committee, please email the NumFOCUS Code of Conduct Enforcement Team by emailing conduct@numfocus.org. We will investigate every complaint, but you may not receive a direct response. We will use our discretion in determining when and how to follow up on reported incidents, which may range from not taking action to permanent expulsion from the project and project-sponsored spaces. We will notify the accused of the report and provide them an opportunity to discuss it before any action is taken. The identity of the reporter will be omitted from the details of the report supplied to the accused. In potentially harmful situations, such as ongoing harassment or threats to anyone's safety, we may take action without notice. ### Attribution This Code of Conduct is adapted from the Go Community Code of Conduct available at https://golang.org/conduct ## Summary - Treat everyone with respect and kindness. - Be thoughtful in how you communicate. - Don't be destructive or inflammatory. - If you encounter an issue, please mail gonum-conduct@googlegroups.com.golang-gonum-v1-gonum-0.14.0/CONTRIBUTING.md000066400000000000000000000157751450372207100201060ustar00rootroot00000000000000# [](https://github.com/gonum) Contribution Guidelines #### Introduction The Gonum project provides general purpose numerical computing and data science libraries for the Go programming language, and we would like you to join us in improving Gonum's quality and scope. This document is for anyone who is contributing or interested in contributing. Questions about Gonum or the use of its libraries can be directed to [gonum-dev](https://groups.google.com/forum/#!forum/gonum-dev). #### Table of Contents [Project Scope](#project-scope) [The Gonum Repositories](#the-gonum-repositories) [Contributing](#Contributing) * [Working Together](#working-together) * [Reporting Bugs](#reporting-bugs) * [Suggesting Enhancements](#suggesting-enhancements) * [Your First Code Contribution](#your-first-code-contribution) * [Code Contribution](#code-contribution) * [Code Review](#code-review) * [What Can I Do to Help?](#what-can-i-do-to-help) * [Style](#style) ## Project Scope The purpose of the Gonum project is to provide general purpose numerical computing and data science libraries for the Go programming language. The libraries should aim to provide building blocks for disciplinary work and advanced algorithms. Code should be implemented in pure Go. Calls to C, Fortran, or other languages may be justified with performance considerations, but should be opt-in for users. Calls to assembly should be opt-out, if included. Code should favor readability and explicitness over cleverness. This makes code easy to review and verify, not only at submission, but also for users who want to understand how the algorithms work. Where possible, the source of algorithms should be referenced in the comments. ## The Gonum Repositories Here are the current repositories for the Gonum project. If code you want to contribute doesn't quite fit in any of them, then please start a discussion on the [mailing list](https://groups.google.com/forum/#!forum/gonum-dev). Code can be found at [github.com/gonum/](https://github.com/gonum/)\, and documentation at gonum.org/v1/\. * [gonum](https://github.com/gonum/gonum) — The gonum repository contains the majority of Gonum packages * [plot](https://github.com/gonum/plot) — A repository for plotting and visualizing data * [netlib](https://github.com/gonum/netlib) — The netlib repository contains Cgo wrappers for C implementations of BLAS and LAPACKE * [hdf5](https://github.com/gonum/hdf5) — The hdf5 repository contains a Cgo wrapper for the HDF5 data storage and access library * [exp](https://github.com/gonum/exp) — The exp repository contains experimental and incomplete package implementations * [tools](https://github.com/gonum/tools) — Tools for working with Go code * [talks](https://github.com/gonum/talks) — Talks given about Go and Gonum delivered by Gonum developers * [gonum.github.io](https://github.com/gonum/gonum.github.io) — Gonum website ## Contributing ### Working Together When contributing or otherwise participating please follow the [Gonum community's conduct expectations](CONDUCT.md). ### Reporting Bugs When you encounter a bug, please open an issue on the corresponding repository. Start the issue title with the repository/sub-repository name, like `stat/distmv: issue name`. Be specific about the environment you encountered the bug in. If you are able to write a test that reproduces the bug, please include it in the issue. As a rule we keep all tests OK. ### Suggesting Enhancements If the scope of the enhancement is small, open an issue. If it is large, such as suggesting a new repository, sub-repository, or interface refactoring, then please start a discussion on [the gonum-dev list](https://groups.google.com/forum/#!forum/gonum-dev). ### Your First Code Contribution If you are a new contributor, thank you! Before your first merge, you will need to be added to the [CONTRIBUTORS](https://github.com/gonum/gonum/blob/master/CONTRIBUTORS) and [AUTHORS](https://github.com/gonum/gonum/blob/master/AUTHORS) file; after your contribution has been accepted you will be asked to open a pull request adding yourself to them. All Gonum code follows the BSD license in the [license document](https://github.com/gonum/gonum/blob/master/LICENSE). We prefer that code contributions do not come with additional licensing. For exceptions, added code must also follow a BSD license. ### Code Contribution If it is possible to split a large pull request into two or more smaller pull requests, please try to do so. Pull requests should include tests for any new code before merging. It is ok to start a pull request on partially implemented code to get feedback, and see if your approach to a problem is sound. You don't need to have tests, or even have code that compiles to open a pull request, although both will be needed before merge. When tests use magic numbers, please include a comment explaining the source of the number. Benchmarks are optional for new features, but if you are submitting a pull request justified by performance improvement, you will need benchmarks to measure the impact of your change, and the pull request should include a report from [benchcmp](https://pkg.go.dev/golang.org/x/tools/cmd/benchcmp) or, preferably, [benchstat](https://github.com/rsc/benchstat). ### Code Review If you are a contributor, please be welcoming to new contributors. [Here](https://sage.thesharps.us/2014/09/01/the-gentle-art-of-patch-review/) is a good guide. There are several terms code reviews may use that you should become familiar with. * ` LGTM ` — looks good to me * ` SGTM ` — sounds good to me * ` s/foo/bar/ ` — please replace ` foo ` with ` bar `; this is [sed syntax](http://en.wikipedia.org/wiki/Sed#Usage) * ` s/foo/bar/g ` — please replace ` foo ` with ` bar ` throughout your entire change We follow the convention of requiring at least 1 reviewer to say LGTM before a merge. When code is tricky or controversial, submitters and reviewers can request additional review from others and more LGTMs before merge. You can ask for more review by saying PTAL in a comment in a pull request. You can follow a PTAL with one or more @someone to get the attention of particular people. If you don't know who to ask, and aren't getting enough review after saying PTAL, then PTAL @gonum/developers will get more attention. Also note that you do not have to be the pull request submitter to request additional review. ### What Can I Do to Help? If you are looking for some way to help the Gonum project, there are good places to start, depending on what you are comfortable with. You can [search](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+user%3Agonum) for open issues in need of resolution. You can improve documentation, or improve examples. You can add and improve tests. You can improve performance, either by improving accuracy, speed, or both. You can suggest and implement new features that you think belong in Gonum. ### Style We use [Go style](https://github.com/golang/go/wiki/CodeReviewComments). golang-gonum-v1-gonum-0.14.0/CONTRIBUTORS000066400000000000000000000116331450372207100175220ustar00rootroot00000000000000# This is the official list of people who can contribute # (and typically have contributed) code to the Gonum # project. # # 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 # # Please keep the list sorted. Alexander Egurnov Andrei Blinnikov Andrew Brampton antichris Bailey Lissington Bill Gray Bill Noon Brendan Tracey Brent Pedersen Bulat Khasanov Chad Kunde Chan Kwan Yin Chih-Wei Chang Chong-Yeol Nah Chris Tessum Christophe Meessen Christopher Waldon Clayton Northey Dan Kortschak Dan Lorenc Daniel Fireman Dario Heinisch David Kleiven David Samborski Davor Kapsa Delaney Gillilan Dezmond Goff Dong-hee Na Dustin Spicuzza Egon Elbre Ekaterina Efimova Ethan Burns Evert Lammerts Evgeny Savinov Fabian Wickborn Facundo Gaich Fazlul Shahriar Francesc Campoy Gustaf Johansson Hossein Zolfi Iakov Davydov Igor Mikushkin Iskander Sharipov Jalem Raj Rohit James Bell James Bowman James Holmes <32bitkid@gmail.com> Janne Snabb Jeremy Atkinson Jes Cok Jinesi Yelizati Jon Richards Jonas Kahler Jonas Schulze Jonathan J Lawlor Jonathan Reiter Jonathan Schroeder Joost van Amersfoort Joseph Watson Josh Wilson Julien Roland Kai Trukenmüller Kent English Kevin C. Zimmerman Kirill Motkov Konstantin Shaposhnikov Leonid Kneller Lyron Winderbaum Marco Leogrande Mark Canning Mark Skilbeck Martin Diz Matthew Connelly Matthieu Di Mercurio Max Halford Maxim Sergeev MinJae Kwon Nathan Edwards Nick Potts Nils Wogatzky Olivier Wulveryck Or Rikon Patricio Whittingslow Patrick DeVivo Pontus Melke Renee French Rishi Desai Robin Eklind Roger Welin Roman Werpachowski Rondall Jones Sam Zaydel Samuel Kelemen Saran Ahluwalia Scott Holden Scott Kiesel Sebastien Binet Shawn Smith Spencer Lyon Steve McCoy Taesu Pyo Takeshi Yoneda Tamir Hyman Thomas Berg Tobin Harding Valentin Deleplace Vincent Thiery Vladimír Chalupecký Will Tekulve Yasuhiro Matsumoto Yevgeniy Vahlis Yucheng Zhu Yunomi Zoe Juozapaitis golang-gonum-v1-gonum-0.14.0/GOPHER000066400000000000000000000001511450372207100165420ustar00rootroot00000000000000The Go gopher was designed by Renee French and is licensed under the Creative Commons Attributions 3.0. golang-gonum-v1-gonum-0.14.0/LICENSE000066400000000000000000000027721450372207100166530ustar00rootroot00000000000000Copyright ©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.golang-gonum-v1-gonum-0.14.0/README.md000066400000000000000000000071621450372207100171230ustar00rootroot00000000000000# Gonum [![Build status](https://github.com/gonum/gonum/workflows/CI/badge.svg)](https://github.com/gonum/gonum/actions) [![Build status](https://ci.appveyor.com/api/projects/status/valslkp8sr50eepn/branch/master?svg=true)](https://ci.appveyor.com/project/Gonum/gonum/branch/master) [![codecov.io](https://codecov.io/gh/gonum/gonum/branch/master/graph/badge.svg)](https://codecov.io/gh/gonum/gonum) [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum)](https://pkg.go.dev/gonum.org/v1/gonum) [![GoDoc](https://godocs.io/gonum.org/v1/gonum?status.svg)](https://godocs.io/gonum.org/v1/gonum) [![Go Report Card](https://goreportcard.com/badge/github.com/gonum/gonum)](https://goreportcard.com/report/github.com/gonum/gonum) [![stability-unstable](https://img.shields.io/badge/stability-unstable-yellow.svg)](https://github.com/emersion/stability-badges#unstable) ## Installation The core packages of the Gonum suite are written in pure Go with some assembly. Installation is done using `go get`. ``` go get -u gonum.org/v1/gonum/... ``` ## Supported Go versions Gonum supports and tests using the gc compiler on the [two most recent Go releases](https://github.com/gonum/gonum/blob/master/.github/workflows/ci.yml#L14-L15) on Linux (386, amd64 and arm64), macOS and Windows (both on amd64). Note that floating point behavior may differ between compiler versions and between architectures due to differences in floating point operation implementations. ## Release schedule The Gonum modules are released on a six-month release schedule, aligned with the Go releases. _i.e.:_ when `Go-1.x` is released, `Gonum-v0.n.0` is released around the same time. Six months after, `Go-1.x+1` is released, and `Gonum-v0.n+1.0` as well. The release schedule, based on the current Go release schedule is thus: - `Gonum-v0.n.0`: February - `Gonum-v0.n+1.0`: August ## Build tags The Gonum packages use a variety of build tags to set non-standard build conditions. Building Gonum applications will work without knowing how to use these tags, but they can be used during testing and to control the use of assembly and CGO code. The current list of non-internal tags is as follows: - safe — do not use assembly or unsafe - bounds — use bounds checks even in internal calls - noasm — do not use assembly implementations - tomita — use [Tomita, Tanaka, Takahashi pivot choice](https://doi.org/10.1016%2Fj.tcs.2006.06.015) for maximimal clique calculation, otherwise use random pivot (only in [topo package](https://pkg.go.dev/gonum.org/v1/gonum/graph/topo)) ## Issues [![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/gonum/gonum)](https://www.tickgit.com/browse?repo=github.com/gonum/gonum) If you find any bugs, feel free to file an issue on the github issue tracker. Discussions on API changes, added features, code review, or similar requests are preferred on the gonum-dev Google Group. https://groups.google.com/forum/#!forum/gonum-dev ## License Original code is licensed under the Gonum License found in the LICENSE file. Portions of the code are subject to the additional licenses found in THIRD_PARTY_LICENSES. All third party code is licensed either under a BSD or MIT license. Code in graph/formats/dot is dual licensed [Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/) and Gonum License, and users are free to choose the license which suits their needs for this code. The W3C test suites in graph/formats/rdf are distributed under both the [W3C Test Suite License](http://www.w3.org/Consortium/Legal/2008/04-testsuite-license) and the [W3C 3-clause BSD License](http://www.w3.org/Consortium/Legal/2008/03-bsd-license). golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/000077500000000000000000000000001450372207100207545ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Bogaert-LICENSE000066400000000000000000000025501450372207100233440ustar00rootroot00000000000000******************************************* Copyright (C) 2014 by Ignace Bogaert * ******************************************* This software package is based on the paper I. Bogaert, "Iteration-Free Computation of Gauss-Legendre Quadrature Nodes and Weights", to be published in the SIAM Journal of Scientific Computing. The main features of this software are: - Speed: due to the simple formulas and the O(1) complexity computation of individual Gauss-Legendre quadrature nodes and weights. This makes it compatible with parallel computing paradigms. - Accuracy: the error on the nodes and weights is within a few ulps (see the paper for details). Disclaimer: THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 REGENTS 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. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Boost-LICENSE000066400000000000000000000024721450372207100230520ustar00rootroot00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Cephes-LICENSE000066400000000000000000000027241450372207100231730ustar00rootroot00000000000000Copyright (c) 1984, 1987, 1989, 1992, 2000 Stephen L. Moshier 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 Stephen L. Moshier nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Fike-LICENSE000066400000000000000000000021061450372207100226340ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2006 Jeffrey A. Fike Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Go-LICENSE000066400000000000000000000027071450372207100223320ustar00rootroot00000000000000Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/MT19937-64-LICENSE000066400000000000000000000043711450372207100231500ustar00rootroot00000000000000A C-program for MT19937-64 (2004/9/29 version). Coded by Takuji Nishimura and Makoto Matsumoto. This is a 64-bit version of Mersenne Twister pseudorandom number generator. Before using, initialize the state by using init_genrand64(seed) or init_by_array64(init_key, key_length). Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. References: T. Nishimura, ``Tables of 64-bit Mersenne Twisters'' ACM Transactions on Modeling and Computer Simulation 10. (2000) 348--357. M. Matsumoto and T. Nishimura, ``Mersenne Twister: a 623-dimensionally equidistributed uniform pseudorandom number generator'' ACM Transactions on Modeling and Computer Simulation 8. (Jan. 1998) 3--30. Any feedback is very welcome. http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces) golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/MT19937-LICENSE000066400000000000000000000035441450372207100227220ustar00rootroot00000000000000A C-program for MT19937, with initialization improved 2002/1/26. Coded by Takuji Nishimura and Makoto Matsumoto. Before using, initialize the state by using init_genrand(seed) or init_by_array(init_key, key_length). Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Any feedback is very welcome. http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Oxford-LICENSE000066400000000000000000000031101450372207100232130ustar00rootroot00000000000000Copyright (c) 2015, The Chancellor, Masters and Scholars of the University of Oxford, and the Chebfun Developers. 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 University of Oxford nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Probab-LICENSE000066400000000000000000000027121450372207100231660ustar00rootroot00000000000000Copyright (c) 2012 The Probab Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/Sun-LICENSE000066400000000000000000000003641450372207100225270ustar00rootroot00000000000000Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. Developed at SunPro, a Sun Microsystems, Inc. business. Permission to use, copy, modify, and distribute this software is freely granted, provided that this notice is preserved. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/W3C-BSD-LICENSE000066400000000000000000000027571450372207100227740ustar00rootroot00000000000000Copyright © 2008 World Wide Web Consortium®, (MIT, ERCIM, Keio, Beihang) and others. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of works must retain the original copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the original 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 W3C nor the names of its contributors may be used to endorse or promote products derived from this work without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-gonum-v1-gonum-0.14.0/THIRD_PARTY_LICENSES/W3C-TestSuite-LICENSE000066400000000000000000000066721450372207100243150ustar00rootroot00000000000000Copyright © 2008 World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang) and others. All Rights Reserved. http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html This document, Test Suites and other documents that link to this statement are provided by the copyright holders under the following license: By using and/or copying this document, or the W3C document from which this statement is linked, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: Permission to copy, and distribute the contents of this document, or the W3C document from which this statement is linked, in any medium for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the document, or portions thereof, that you use: 1. A link or URL to the original W3C document. 2. The pre-existing copyright notice of the original author, or if it doesn't exist, a notice (hypertext is preferred, but a textual representation is permitted) of the form: "Copyright © [$date-of-document] World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang) and others. All Rights Reserved. http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html" 3. If it exists, the STATUS of the W3C document. When space permits, inclusion of the full text of this NOTICE should be provided. We request that authorship attribution be provided in any software, documents, or other items or products that you create pursuant to the implementation of the contents of this document, or any portion thereof. No right to create modifications or derivatives of W3C documents is granted pursuant to this license. However, if additional requirements (documented in the Copyright FAQ) are satisfied, the right to create modifications or derivatives is sometimes granted by the W3C to individuals complying with those requirements. If a Test Suite distinguishes the test harness (or, framework for navigation) and the actual tests, permission is given to remove or alter the harness or navigation if the Test Suite in question allows to do so. The tests themselves shall NOT be changed in any way. The name and trademarks of W3C and other copyright holders may NOT be used in advertising or publicity pertaining to this document or other documents that link to this statement without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. Permission is given to use the trademarked string "W3C" within claims of performance concerning W3C Specifications or features described therein, and there only, if the test suite so authorizes. THIS WORK IS PROVIDED BY W3C, MIT, ERCIM, KEIO, BEIHANG, 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 W3C, MIT, ERCIM, KEIO, BEIHANG, THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-gonum-v1-gonum-0.14.0/appveyor.yml000066400000000000000000000004431450372207100202270ustar00rootroot00000000000000build: off image: Visual Studio 2019 stack: go 1.17 clone_folder: c:\gopath\src\gonum.org\v1\gonum cache: - '%LocalAppData%\go-build' environment: GO111MODULE: 'on' branches: only: - master build_script: - go version - go get -v -t ./... test_script: - go test ./... golang-gonum-v1-gonum-0.14.0/blas/000077500000000000000000000000001450372207100165575ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/README.md000066400000000000000000000023611450372207100200400ustar00rootroot00000000000000# Gonum BLAS [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/blas)](https://pkg.go.dev/gonum.org/v1/gonum/blas) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/blas?status.svg)](https://godocs.io/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}} v.N = len(v.Data) fmt.Println("v has length:", blas64.Nrm2(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. golang-gonum-v1-gonum-0.14.0/blas/blas.go000066400000000000000000000413241450372207100200330ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/blas/blas32/000077500000000000000000000000001450372207100176455ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/blas32/blas32.go000066400000000000000000000371661450372207100212770ustar00rootroot00000000000000// 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 blas32 import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/gonum" ) var blas32 blas.Float32 = gonum.Implementation{} // Use sets the BLAS float32 implementation to be used by subsequent BLAS calls. // The default implementation is // gonum.org/v1/gonum/blas/gonum.Implementation. func Use(b blas.Float32) { blas32 = b } // Implementation returns the current BLAS float32 implementation. // // Implementation allows direct calls to the current the BLAS float32 implementation // giving finer control of parameters. func Implementation() blas.Float32 { return blas32 } // Vector represents a vector with an associated element increment. type Vector struct { N int Inc int Data []float32 } // General represents a matrix using the conventional storage scheme. type General struct { Rows, Cols int Stride int Data []float32 } // Band represents a band matrix using the band storage scheme. type Band struct { Rows, Cols int KL, KU int Stride int Data []float32 } // Triangular represents a triangular matrix using the conventional storage scheme. type Triangular struct { N int Stride int Data []float32 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 []float32 Uplo blas.Uplo Diag blas.Diag } // TriangularPacked represents a triangular matrix using the packed storage scheme. type TriangularPacked struct { N int Data []float32 Uplo blas.Uplo Diag blas.Diag } // Symmetric represents a symmetric matrix using the conventional storage scheme. type Symmetric struct { N int Stride int Data []float32 Uplo blas.Uplo } // SymmetricBand represents a symmetric matrix using the band storage scheme. type SymmetricBand struct { N, K int Stride int Data []float32 Uplo blas.Uplo } // SymmetricPacked represents a symmetric matrix using the packed storage scheme. type SymmetricPacked struct { N int Data []float32 Uplo blas.Uplo } // Level 1 const ( negInc = "blas32: negative vector increment" badLength = "blas32: 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) float32 { if x.N != y.N { panic(badLength) } return blas32.Sdot(x.N, x.Data, x.Inc, y.Data, y.Inc) } // DDot computes the dot product of the two vectors: // // \sum_i x[i]*y[i]. // // DDot will panic if the lengths of x and y do not match. func DDot(x, y Vector) float64 { if x.N != y.N { panic(badLength) } return blas32.Dsdot(x.N, x.Data, x.Inc, y.Data, y.Inc) } // SDDot computes the dot product of the two vectors adding a constant: // // alpha + \sum_i x[i]*y[i]. // // SDDot will panic if the lengths of x and y do not match. func SDDot(alpha float32, x, y Vector) float32 { if x.N != y.N { panic(badLength) } return blas32.Sdsdot(x.N, alpha, 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) float32 { if x.Inc < 0 { panic(negInc) } return blas32.Snrm2(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) float32 { if x.Inc < 0 { panic(negInc) } return blas32.Sasum(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 blas32.Isamax(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) } blas32.Sswap(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) } blas32.Scopy(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 float32, x, y Vector) { if x.N != y.N { panic(badLength) } blas32.Saxpy(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 float32) (c, s, r, z float32) { return blas32.Srotg(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 float32) (p blas.SrotmParams, rd1, rd2, rb1 float32) { return blas32.Srotmg(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(n int, x, y Vector, c, s float32) { blas32.Srot(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(n int, x, y Vector, p blas.SrotmParams) { blas32.Srotm(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 float32, x Vector) { if x.Inc < 0 { panic(negInc) } blas32.Sscal(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 float32, a General, x Vector, beta float32, y Vector) { blas32.Sgemv(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 float32, a Band, x Vector, beta float32, y Vector) { blas32.Sgbmv(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) { blas32.Strmv(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) { blas32.Stbmv(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) { blas32.Stpmv(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) { blas32.Strsv(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) { blas32.Stbsv(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) { blas32.Stpsv(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 float32, a Symmetric, x Vector, beta float32, y Vector) { blas32.Ssymv(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 float32, a SymmetricBand, x Vector, beta float32, y Vector) { blas32.Ssbmv(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 float32, a SymmetricPacked, x Vector, beta float32, y Vector) { blas32.Sspmv(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 float32, x, y Vector, a General) { blas32.Sger(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 float32, x Vector, a Symmetric) { blas32.Ssyr(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 float32, x Vector, a SymmetricPacked) { blas32.Sspr(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 float32, x, y Vector, a Symmetric) { blas32.Ssyr2(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 float32, x, y Vector, a SymmetricPacked) { blas32.Sspr2(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 float32, a, b General, beta float32, 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 } blas32.Sgemm(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 float32, a Symmetric, b General, beta float32, c General) { var m, n int if s == blas.Left { m, n = a.N, b.Cols } else { m, n = b.Rows, a.N } blas32.Ssymm(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 float32, a General, beta float32, c Symmetric) { var n, k int if t == blas.NoTrans { n, k = a.Rows, a.Cols } else { n, k = a.Cols, a.Rows } blas32.Ssyrk(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 float32, a, b General, beta float32, c Symmetric) { var n, k int if t == blas.NoTrans { n, k = a.Rows, a.Cols } else { n, k = a.Cols, a.Rows } blas32.Ssyr2k(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 float32, a Triangular, b General) { blas32.Strmm(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 float32, a Triangular, b General) { blas32.Strsm(s, a.Uplo, tA, a.Diag, b.Rows, b.Cols, alpha, a.Data, a.Stride, b.Data, b.Stride) } golang-gonum-v1-gonum-0.14.0/blas/blas32/conv.go000066400000000000000000000152401450372207100211430ustar00rootroot00000000000000// 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 blas32 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("blas32: mismatched dimension") } if len(t.Data) < (t.Cols-1)*t.Stride+t.Rows { panic("blas32: 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("blas32: mismatched dimension") } if len(t.Data) < (t.Rows-1)*t.Stride+t.Cols { panic("blas32: 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("blas32: mismatched dimension") } if t.Uplo != a.Uplo { panic("blas32: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("blas32: mismatched BLAS diag") } switch a.Uplo { default: panic("blas32: 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("blas32: mismatched dimension") } if t.Uplo != a.Uplo { panic("blas32: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("blas32: mismatched BLAS diag") } switch a.Uplo { default: panic("blas32: 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("blas32: mismatched dimension") } if t.KL != a.KL || t.KU != a.KU { panic("blas32: mismatched bandwidth") } if a.Stride < a.KL+a.KU+1 { panic("blas32: short stride for source") } if t.Stride < t.KL+t.KU+1 { panic("blas32: 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("blas32: mismatched dimension") } if t.KL != a.KL || t.KU != a.KU { panic("blas32: mismatched bandwidth") } if a.Stride < a.KL+a.KU+1 { panic("blas32: short stride for source") } if t.Stride < t.KL+t.KU+1 { panic("blas32: 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("blas32: mismatched dimension") } if t.K != a.K { panic("blas32: mismatched bandwidth") } if a.Stride < a.K+1 { panic("blas32: short stride for source") } if t.Stride < t.K+1 { panic("blas32: short stride for destination") } if t.Uplo != a.Uplo { panic("blas32: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("blas32: 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("blas32: 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("blas32: mismatched dimension") } if t.K != a.K { panic("blas32: mismatched bandwidth") } if a.Stride < a.K+1 { panic("blas32: short stride for source") } if t.Stride < t.K+1 { panic("blas32: short stride for destination") } if t.Uplo != a.Uplo { panic("blas32: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("blas32: 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("blas32: 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 } golang-gonum-v1-gonum-0.14.0/blas/blas32/conv_symmetric.go000066400000000000000000000070361450372207100232430ustar00rootroot00000000000000// 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 blas32 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("blas32: mismatched dimension") } if t.Uplo != a.Uplo { panic("blas32: mismatched BLAS uplo") } switch a.Uplo { default: panic("blas32: 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("blas32: mismatched dimension") } if t.Uplo != a.Uplo { panic("blas32: mismatched BLAS uplo") } switch a.Uplo { default: panic("blas32: 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("blas32: mismatched dimension") } if t.K != a.K { panic("blas32: mismatched bandwidth") } if a.Stride < a.K+1 { panic("blas32: short stride for source") } if t.Stride < t.K+1 { panic("blas32: short stride for destination") } if t.Uplo != a.Uplo { panic("blas32: 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("blas32: 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("blas32: mismatched dimension") } if t.K != a.K { panic("blas32: mismatched bandwidth") } if a.Stride < a.K+1 { panic("blas32: short stride for source") } if t.Stride < t.K+1 { panic("blas32: short stride for destination") } if t.Uplo != a.Uplo { panic("blas32: 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("blas32: 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) } golang-gonum-v1-gonum-0.14.0/blas/blas32/conv_symmetric_test.go000066400000000000000000000143631450372207100243030ustar00rootroot00000000000000// 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 blas32 import ( math "gonum.org/v1/gonum/internal/math32" "testing" "gonum.org/v1/gonum/blas" ) func newSymmetricFrom(a SymmetricCols) Symmetric { t := Symmetric{ N: a.N, Stride: a.N, Data: make([]float32, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m Symmetric) n() int { return m.N } func (m Symmetric) at(i, j int) float32 { if m.Uplo == blas.Lower && i < j && j < m.N { i, j = j, i } if m.Uplo == blas.Upper && i > j { i, j = j, i } return m.Data[i*m.Stride+j] } func (m Symmetric) uplo() blas.Uplo { return m.Uplo } func newSymmetricColsFrom(a Symmetric) SymmetricCols { t := SymmetricCols{ N: a.N, Stride: a.N, Data: make([]float32, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m SymmetricCols) n() int { return m.N } func (m SymmetricCols) at(i, j int) float32 { if m.Uplo == blas.Lower && i < j { i, j = j, i } if m.Uplo == blas.Upper && i > j && i < m.N { i, j = j, i } return m.Data[i+j*m.Stride] } func (m SymmetricCols) uplo() blas.Uplo { return m.Uplo } type symmetric interface { n() int at(i, j int) float32 uplo() blas.Uplo } func sameSymmetric(a, b symmetric) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var symmetricTests = []Symmetric{ {N: 3, Stride: 3, Data: []float32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []float32{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertSymmetric(t *testing.T) { for _, test := range symmetricTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { test.Uplo = uplo colmajor := newSymmetricColsFrom(test) if !sameSymmetric(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newSymmetricFrom(colmajor) if !sameSymmetric(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } func newSymmetricBandFrom(a SymmetricBandCols) SymmetricBand { t := SymmetricBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float32, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m SymmetricBand) n() (n int) { return m.N } func (m SymmetricBand) at(i, j int) float32 { b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas32: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m SymmetricBand) bandwidth() (k int) { return m.K } func (m SymmetricBand) uplo() blas.Uplo { return m.Uplo } func newSymmetricBandColsFrom(a SymmetricBand) SymmetricBandCols { t := SymmetricBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float32, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m SymmetricBandCols) n() (n int) { return m.N } func (m SymmetricBandCols) at(i, j int) float32 { b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas32: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m SymmetricBandCols) bandwidth() (k int) { return m.K } func (m SymmetricBandCols) uplo() blas.Uplo { return m.Uplo } type symmetricBand interface { n() (n int) at(i, j int) float32 bandwidth() (k int) uplo() blas.Uplo } func sameSymmetricBand(a, b symmetricBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var symmetricBandTests = []SymmetricBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []float32{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []float32{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []float32{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []float32{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []float32{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []float32{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []float32{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []float32{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertSymBand(t *testing.T) { for _, test := range symmetricBandTests { colmajor := newSymmetricBandColsFrom(test) if !sameSymmetricBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newSymmetricBandFrom(colmajor) if !sameSymmetricBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/blas32/conv_test.go000066400000000000000000000316241450372207100222060ustar00rootroot00000000000000// 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 blas32 import ( math "gonum.org/v1/gonum/internal/math32" "testing" "gonum.org/v1/gonum/blas" ) func newGeneralFrom(a GeneralCols) General { t := General{ Rows: a.Rows, Cols: a.Cols, Stride: a.Cols, Data: make([]float32, a.Rows*a.Cols), } t.From(a) return t } func (m General) dims() (r, c int) { return m.Rows, m.Cols } func (m General) at(i, j int) float32 { return m.Data[i*m.Stride+j] } func newGeneralColsFrom(a General) GeneralCols { t := GeneralCols{ Rows: a.Rows, Cols: a.Cols, Stride: a.Rows, Data: make([]float32, a.Rows*a.Cols), } t.From(a) return t } func (m GeneralCols) dims() (r, c int) { return m.Rows, m.Cols } func (m GeneralCols) at(i, j int) float32 { return m.Data[i+j*m.Stride] } type general interface { dims() (r, c int) at(i, j int) float32 } func sameGeneral(a, b general) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var generalTests = []General{ {Rows: 2, Cols: 3, Stride: 3, Data: []float32{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 2, Stride: 2, Data: []float32{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 3, Stride: 3, Data: []float32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 2, Cols: 3, Stride: 5, Data: []float32{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, }}, {Rows: 3, Cols: 2, Stride: 5, Data: []float32{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 3, Stride: 5, Data: []float32{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertGeneral(t *testing.T) { for _, test := range generalTests { colmajor := newGeneralColsFrom(test) if !sameGeneral(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newGeneralFrom(colmajor) if !sameGeneral(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularFrom(a TriangularCols) Triangular { t := Triangular{ N: a.N, Stride: a.N, Data: make([]float32, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m Triangular) n() int { return m.N } func (m Triangular) at(i, j int) float32 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j && j < m.N { return 0 } if m.Uplo == blas.Upper && i > j { return 0 } return m.Data[i*m.Stride+j] } func (m Triangular) uplo() blas.Uplo { return m.Uplo } func (m Triangular) diag() blas.Diag { return m.Diag } func newTriangularColsFrom(a Triangular) TriangularCols { t := TriangularCols{ N: a.N, Stride: a.N, Data: make([]float32, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m TriangularCols) n() int { return m.N } func (m TriangularCols) at(i, j int) float32 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j { return 0 } if m.Uplo == blas.Upper && i > j && i < m.N { return 0 } return m.Data[i+j*m.Stride] } func (m TriangularCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularCols) diag() blas.Diag { return m.Diag } type triangular interface { n() int at(i, j int) float32 uplo() blas.Uplo diag() blas.Diag } func sameTriangular(a, b triangular) bool { an := a.n() bn := b.n() if an != bn { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularTests = []Triangular{ {N: 3, Stride: 3, Data: []float32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []float32{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertTriangular(t *testing.T) { for _, test := range triangularTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower, blas.All} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { test.Uplo = uplo test.Diag = diag colmajor := newTriangularColsFrom(test) if !sameTriangular(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularFrom(colmajor) if !sameTriangular(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } } func newBandFrom(a BandCols) Band { t := Band{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]float32, a.Rows*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m Band) dims() (r, c int) { return m.Rows, m.Cols } func (m Band) at(i, j int) float32 { pj := j + m.KL - i if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[i*m.Stride+pj] } func (m Band) bandwidth() (kl, ku int) { return m.KL, m.KU } func newBandColsFrom(a Band) BandCols { t := BandCols{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]float32, a.Cols*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m BandCols) dims() (r, c int) { return m.Rows, m.Cols } func (m BandCols) at(i, j int) float32 { pj := i + m.KU - j if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[j*m.Stride+pj] } func (m BandCols) bandwidth() (kl, ku int) { return m.KL, m.KU } type band interface { dims() (r, c int) at(i, j int) float32 bandwidth() (kl, ku int) } func sameBand(a, b band) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } akl, aku := a.bandwidth() bkl, bku := b.bandwidth() if akl != bkl || aku != bku { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var bandTests = []Band{ {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 1, Data: []float32{ 1, 2, 3, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []float32{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []float32{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 2, Data: []float32{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 2, Data: []float32{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 3, Data: []float32{ -1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 3, Data: []float32{ -1, 2, 3, 4, 5, 6, 7, 8, -2, 9, -3, -4, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 4, Data: []float32{ -2, -1, 3, 4, -3, 5, 6, 7, 8, 9, 10, 11, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 4, Data: []float32{ -2, -1, 2, 3, -3, 4, 5, 6, 7, 8, 9, -4, 10, 11, -5, -6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 5, Data: []float32{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []float32{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []float32{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 5, Data: []float32{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 5, Data: []float32{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 5, Data: []float32{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 5, Data: []float32{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, -2, 0, 0, 9, -3, -4, 0, 0, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 5, Data: []float32{ -2, -1, 3, 4, 0, -3, 5, 6, 7, 0, 8, 9, 10, 11, 0, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 5, Data: []float32{ -2, -1, 2, 3, 0, -3, 4, 5, 6, 0, 7, 8, 9, -4, 0, 10, 11, -5, -6, 0, }}, } func TestConvertBand(t *testing.T) { for _, test := range bandTests { colmajor := newBandColsFrom(test) if !sameBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newBandFrom(colmajor) if !sameBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularBandFrom(a TriangularBandCols) TriangularBand { t := TriangularBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float32, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBand) n() (n int) { return m.N } func (m TriangularBand) at(i, j int) float32 { if m.Diag == blas.Unit && i == j { return 1 } b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas32: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBand) bandwidth() (k int) { return m.K } func (m TriangularBand) uplo() blas.Uplo { return m.Uplo } func (m TriangularBand) diag() blas.Diag { return m.Diag } func newTriangularBandColsFrom(a TriangularBand) TriangularBandCols { t := TriangularBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float32, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBandCols) n() (n int) { return m.N } func (m TriangularBandCols) at(i, j int) float32 { if m.Diag == blas.Unit && i == j { return 1 } b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas32: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBandCols) bandwidth() (k int) { return m.K } func (m TriangularBandCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularBandCols) diag() blas.Diag { return m.Diag } type triangularBand interface { n() (n int) at(i, j int) float32 bandwidth() (k int) uplo() blas.Uplo diag() blas.Diag } func sameTriangularBand(a, b triangularBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } if a.diag() != b.diag() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularBandTests = []TriangularBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []float32{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []float32{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []float32{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []float32{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []float32{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []float32{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []float32{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []float32{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []float32{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertTriBand(t *testing.T) { for _, test := range triangularBandTests { colmajor := newTriangularBandColsFrom(test) if !sameTriangularBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularBandFrom(colmajor) if !sameTriangularBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/blas32/doc.go000066400000000000000000000004461450372207100207450ustar00rootroot00000000000000// 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 blas32 provides a simple interface to the float32 BLAS API. package blas32 // import "gonum.org/v1/gonum/blas/blas32" golang-gonum-v1-gonum-0.14.0/blas/blas64/000077500000000000000000000000001450372207100176525ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/blas64/blas64.go000066400000000000000000000361521450372207100213030ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/blas/blas64/blas64_test.go000066400000000000000000000251641450372207100223430ustar00rootroot00000000000000// Copyright ©2019 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 ( "fmt" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/testblas" ) var impl = b64{} func TestDasum(t *testing.T) { testblas.DasumTest(t, impl) } func TestDaxpy(t *testing.T) { testblas.DaxpyTest(t, impl) } func TestDdot(t *testing.T) { testblas.DdotTest(t, impl) } func TestDnrm2(t *testing.T) { testblas.Dnrm2Test(t, impl) } func TestIdamax(t *testing.T) { testblas.IdamaxTest(t, impl) } func TestDswap(t *testing.T) { testblas.DswapTest(t, impl) } func TestDcopy(t *testing.T) { testblas.DcopyTest(t, impl) } func TestDrotg(t *testing.T) { testblas.DrotgTest(t, impl, false) } func TestDrotmg(t *testing.T) { testblas.DrotmgTest(t, impl) } func TestDrot(t *testing.T) { testblas.DrotTest(t, impl) } func TestDrotm(t *testing.T) { testblas.DrotmTest(t, impl) } func TestDscal(t *testing.T) { testblas.DscalTest(t, impl) } func TestDgemv(t *testing.T) { testblas.DgemvTest(t, impl) } func TestDger(t *testing.T) { testblas.DgerTest(t, impl) } func TestDtxmv(t *testing.T) { testblas.DtxmvTest(t, impl) } func TestDgbmv(t *testing.T) { testblas.DgbmvTest(t, impl) } func TestDtbsv(t *testing.T) { testblas.DtbsvTest(t, impl) } func TestDsbmv(t *testing.T) { testblas.DsbmvTest(t, impl) } func TestDtbmv(t *testing.T) { testblas.DtbmvTest(t, impl) } func TestDtrsv(t *testing.T) { testblas.DtrsvTest(t, impl) } func TestDtrmv(t *testing.T) { testblas.DtrmvTest(t, impl) } func TestDsymv(t *testing.T) { testblas.DsymvTest(t, impl) } func TestDsyr(t *testing.T) { testblas.DsyrTest(t, impl) } func TestDsyr2(t *testing.T) { testblas.Dsyr2Test(t, impl) } func TestDspr2(t *testing.T) { testblas.Dspr2Test(t, impl) } func TestDspr(t *testing.T) { testblas.DsprTest(t, impl) } func TestDspmv(t *testing.T) { testblas.DspmvTest(t, impl) } func TestDtpsv(t *testing.T) { testblas.DtpsvTest(t, impl) } func TestDtpmv(t *testing.T) { testblas.DtpmvTest(t, impl) } func TestDgemm(t *testing.T) { testblas.TestDgemm(t, impl) } func TestDsymm(t *testing.T) { testblas.DsymmTest(t, impl) } func TestDtrsm(t *testing.T) { testblas.DtrsmTest(t, impl) } func TestDsyrk(t *testing.T) { testblas.DsyrkTest(t, impl) } func TestDsyr2k(t *testing.T) { testblas.Dsyr2kTest(t, impl) } func TestDtrmm(t *testing.T) { testblas.DtrmmTest(t, impl) } type b64 struct{} var _ blas.Float64 = b64{} func (b64) Ddot(n int, x []float64, incX int, y []float64, incY int) float64 { return Dot(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (b64) Dnrm2(n int, x []float64, incX int) float64 { if incX < 0 { return 0 } return Nrm2(Vector{N: n, Inc: incX, Data: x}) } func (b64) Dasum(n int, x []float64, incX int) float64 { if incX < 0 { return 0 } return Asum(Vector{N: n, Inc: incX, Data: x}) } func (b64) Idamax(n int, x []float64, incX int) int { if incX < 0 { return -1 } return Iamax(Vector{N: n, Inc: incX, Data: x}) } func (b64) Dswap(n int, x []float64, incX int, y []float64, incY int) { Swap(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (b64) Dcopy(n int, x []float64, incX int, y []float64, incY int) { Copy(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (b64) Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int) { Axpy(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (b64) Drotg(a, b float64) (c, s, r, z float64) { return Rotg(a, b) } func (b64) Drotmg(d1, d2, b1, b2 float64) (p blas.DrotmParams, rd1, rd2, rb1 float64) { return Rotmg(d1, d2, b1, b2) } func (b64) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) { Rot(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, c, s) } func (b64) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) { Rotm(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, p) } func (b64) Dscal(n int, alpha float64, x []float64, incX int) { if incX < 0 { return } Scal(alpha, Vector{N: n, Inc: incX, Data: x}) } func (b64) Dgemv(tA blas.Transpose, m, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) { lenX := m lenY := n if tA == blas.NoTrans { lenX = n lenY = m } Gemv(tA, alpha, General{Rows: m, Cols: n, Data: a, Stride: lda}, Vector{N: lenX, Inc: incX, Data: x}, beta, Vector{N: lenY, Inc: incY, Data: y}) } func (b64) Dgbmv(tA blas.Transpose, m, n, kL, kU int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) { lenX := m lenY := n if tA == blas.NoTrans { lenX = n lenY = m } Gbmv(tA, alpha, Band{Rows: m, Cols: n, KL: kL, KU: kU, Data: a, Stride: lda}, Vector{N: lenX, Inc: incX, Data: x}, beta, Vector{N: lenY, Inc: incY, Data: y}) } func (b64) Dtrmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) { Trmv(tA, Triangular{Uplo: ul, Diag: d, N: n, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (b64) Dtbmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float64, lda int, x []float64, incX int) { Tbmv(tA, TriangularBand{Uplo: ul, Diag: d, N: n, K: k, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (b64) Dtpmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float64, x []float64, incX int) { Tpmv(tA, TriangularPacked{Uplo: ul, Diag: d, N: n, Data: ap}, Vector{N: n, Inc: incX, Data: x}) } func (b64) Dtrsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) { Trsv(tA, Triangular{Uplo: ul, Diag: d, N: n, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (b64) Dtbsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float64, lda int, x []float64, incX int) { Tbsv(tA, TriangularBand{Uplo: ul, Diag: d, N: n, K: k, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (b64) Dtpsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float64, x []float64, incX int) { Tpsv(tA, TriangularPacked{Uplo: ul, Diag: d, N: n, Data: ap}, Vector{N: n, Inc: incX, Data: x}) } func (b64) Dsymv(ul blas.Uplo, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) { Symv(alpha, Symmetric{Uplo: ul, N: n, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}, beta, Vector{N: n, Inc: incY, Data: y}) } func (b64) Dsbmv(ul blas.Uplo, n, k int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) { Sbmv(alpha, SymmetricBand{Uplo: ul, N: n, K: k, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}, beta, Vector{N: n, Inc: incY, Data: y}) } func (b64) Dspmv(ul blas.Uplo, n int, alpha float64, ap []float64, x []float64, incX int, beta float64, y []float64, incY int) { Spmv(alpha, SymmetricPacked{Uplo: ul, N: n, Data: ap}, Vector{N: n, Inc: incX, Data: x}, beta, Vector{N: n, Inc: incY, Data: y}) } func (b64) Dger(m, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int) { Ger(alpha, Vector{N: m, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, General{Rows: m, Cols: n, Data: a, Stride: lda}) } func (b64) Dsyr(ul blas.Uplo, n int, alpha float64, x []float64, incX int, a []float64, lda int) { Syr(alpha, Vector{N: n, Inc: incX, Data: x}, Symmetric{Uplo: ul, N: n, Data: a, Stride: lda}) } func (b64) Dspr(ul blas.Uplo, n int, alpha float64, x []float64, incX int, ap []float64) { Spr(alpha, Vector{N: n, Inc: incX, Data: x}, SymmetricPacked{Uplo: ul, N: n, Data: ap}) } func (b64) Dsyr2(ul blas.Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int) { Syr2(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, Symmetric{Uplo: ul, N: n, Data: a, Stride: lda}) } func (b64) Dspr2(ul blas.Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64) { Spr2(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, SymmetricPacked{Uplo: ul, N: n, Data: a}) } func (b64) 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) { am, an := m, k if tA != blas.NoTrans { am, an = an, am } bm, bn := k, n if tB != blas.NoTrans { bm, bn = bn, bm } Gemm(tA, tB, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, General{Rows: bm, Cols: bn, Data: b, Stride: ldb}, beta, General{Rows: m, Cols: n, Data: c, Stride: ldc}) } func (b64) 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) { var an int switch s { case blas.Left: an = m case blas.Right: an = n default: panic(fmt.Sprintf("blas64: bad test: invalid side: %q", s)) } Symm(s, alpha, Symmetric{Uplo: ul, N: an, Data: a, Stride: lda}, General{Rows: m, Cols: n, Data: b, Stride: ldb}, beta, General{Rows: m, Cols: n, Data: c, Stride: ldc}) } func (b64) Dsyrk(ul blas.Uplo, t blas.Transpose, n, k int, alpha float64, a []float64, lda int, beta float64, c []float64, ldc int) { am, an := n, k if t != blas.NoTrans { am, an = an, am } Syrk(t, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, beta, Symmetric{Uplo: ul, N: n, Data: c, Stride: ldc}) } func (b64) Dsyr2k(ul blas.Uplo, t blas.Transpose, n, k int, alpha float64, a []float64, lda int, b []float64, ldb int, beta float64, c []float64, ldc int) { am, an := n, k if t != blas.NoTrans { am, an = an, am } Syr2k(t, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, General{Rows: am, Cols: an, Data: b, Stride: ldb}, beta, Symmetric{Uplo: ul, N: n, Data: c, Stride: ldc}) } func (b64) 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) { var k int switch s { case blas.Left: k = m case blas.Right: k = n default: panic(fmt.Sprintf("blas64: bad test: invalid side: %q", s)) } Trmm(s, tA, alpha, Triangular{Uplo: ul, Diag: d, N: k, Data: a, Stride: lda}, General{Rows: m, Cols: n, Data: b, Stride: ldb}) } func (b64) 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) { var k int switch s { case blas.Left: k = m case blas.Right: k = n default: panic(fmt.Sprintf("blas64: bad test: invalid side: %q", s)) } Trsm(s, tA, alpha, Triangular{Uplo: ul, Diag: d, N: k, Data: a, Stride: lda}, General{Rows: m, Cols: n, Data: b, Stride: ldb}) } golang-gonum-v1-gonum-0.14.0/blas/blas64/conv.go000066400000000000000000000151241450372207100211510ustar00rootroot00000000000000// 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 } golang-gonum-v1-gonum-0.14.0/blas/blas64/conv_symmetric.go000066400000000000000000000067221450372207100232510ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/blas/blas64/conv_symmetric_test.go000066400000000000000000000142041450372207100243020ustar00rootroot00000000000000// 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 ( "math" "testing" "gonum.org/v1/gonum/blas" ) func newSymmetricFrom(a SymmetricCols) Symmetric { t := Symmetric{ N: a.N, Stride: a.N, Data: make([]float64, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m Symmetric) n() int { return m.N } func (m Symmetric) at(i, j int) float64 { if m.Uplo == blas.Lower && i < j && j < m.N { i, j = j, i } if m.Uplo == blas.Upper && i > j { i, j = j, i } return m.Data[i*m.Stride+j] } func (m Symmetric) uplo() blas.Uplo { return m.Uplo } func newSymmetricColsFrom(a Symmetric) SymmetricCols { t := SymmetricCols{ N: a.N, Stride: a.N, Data: make([]float64, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m SymmetricCols) n() int { return m.N } func (m SymmetricCols) at(i, j int) float64 { if m.Uplo == blas.Lower && i < j { i, j = j, i } if m.Uplo == blas.Upper && i > j && i < m.N { i, j = j, i } return m.Data[i+j*m.Stride] } func (m SymmetricCols) uplo() blas.Uplo { return m.Uplo } type symmetric interface { n() int at(i, j int) float64 uplo() blas.Uplo } func sameSymmetric(a, b symmetric) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var symmetricTests = []Symmetric{ {N: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertSymmetric(t *testing.T) { for _, test := range symmetricTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { test.Uplo = uplo colmajor := newSymmetricColsFrom(test) if !sameSymmetric(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newSymmetricFrom(colmajor) if !sameSymmetric(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } func newSymmetricBandFrom(a SymmetricBandCols) SymmetricBand { t := SymmetricBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float64, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m SymmetricBand) n() (n int) { return m.N } func (m SymmetricBand) at(i, j int) float64 { b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas64: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m SymmetricBand) bandwidth() (k int) { return m.K } func (m SymmetricBand) uplo() blas.Uplo { return m.Uplo } func newSymmetricBandColsFrom(a SymmetricBand) SymmetricBandCols { t := SymmetricBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float64, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m SymmetricBandCols) n() (n int) { return m.N } func (m SymmetricBandCols) at(i, j int) float64 { b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas64: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m SymmetricBandCols) bandwidth() (k int) { return m.K } func (m SymmetricBandCols) uplo() blas.Uplo { return m.Uplo } type symmetricBand interface { n() (n int) at(i, j int) float64 bandwidth() (k int) uplo() blas.Uplo } func sameSymmetricBand(a, b symmetricBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var symmetricBandTests = []SymmetricBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []float64{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []float64{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []float64{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []float64{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []float64{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertSymBand(t *testing.T) { for _, test := range symmetricBandTests { colmajor := newSymmetricBandColsFrom(test) if !sameSymmetricBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newSymmetricBandFrom(colmajor) if !sameSymmetricBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/blas64/conv_test.go000066400000000000000000000314451450372207100222140ustar00rootroot00000000000000// 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 ( "math" "testing" "gonum.org/v1/gonum/blas" ) func newGeneralFrom(a GeneralCols) General { t := General{ Rows: a.Rows, Cols: a.Cols, Stride: a.Cols, Data: make([]float64, a.Rows*a.Cols), } t.From(a) return t } func (m General) dims() (r, c int) { return m.Rows, m.Cols } func (m General) at(i, j int) float64 { return m.Data[i*m.Stride+j] } func newGeneralColsFrom(a General) GeneralCols { t := GeneralCols{ Rows: a.Rows, Cols: a.Cols, Stride: a.Rows, Data: make([]float64, a.Rows*a.Cols), } t.From(a) return t } func (m GeneralCols) dims() (r, c int) { return m.Rows, m.Cols } func (m GeneralCols) at(i, j int) float64 { return m.Data[i+j*m.Stride] } type general interface { dims() (r, c int) at(i, j int) float64 } func sameGeneral(a, b general) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var generalTests = []General{ {Rows: 2, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 2, Stride: 2, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 2, Cols: 3, Stride: 5, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, }}, {Rows: 3, Cols: 2, Stride: 5, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 3, Stride: 5, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertGeneral(t *testing.T) { for _, test := range generalTests { colmajor := newGeneralColsFrom(test) if !sameGeneral(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newGeneralFrom(colmajor) if !sameGeneral(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularFrom(a TriangularCols) Triangular { t := Triangular{ N: a.N, Stride: a.N, Data: make([]float64, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m Triangular) n() int { return m.N } func (m Triangular) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j && j < m.N { return 0 } if m.Uplo == blas.Upper && i > j { return 0 } return m.Data[i*m.Stride+j] } func (m Triangular) uplo() blas.Uplo { return m.Uplo } func (m Triangular) diag() blas.Diag { return m.Diag } func newTriangularColsFrom(a Triangular) TriangularCols { t := TriangularCols{ N: a.N, Stride: a.N, Data: make([]float64, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m TriangularCols) n() int { return m.N } func (m TriangularCols) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j { return 0 } if m.Uplo == blas.Upper && i > j && i < m.N { return 0 } return m.Data[i+j*m.Stride] } func (m TriangularCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularCols) diag() blas.Diag { return m.Diag } type triangular interface { n() int at(i, j int) float64 uplo() blas.Uplo diag() blas.Diag } func sameTriangular(a, b triangular) bool { an := a.n() bn := b.n() if an != bn { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularTests = []Triangular{ {N: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertTriangular(t *testing.T) { for _, test := range triangularTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower, blas.All} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { test.Uplo = uplo test.Diag = diag colmajor := newTriangularColsFrom(test) if !sameTriangular(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularFrom(colmajor) if !sameTriangular(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } } func newBandFrom(a BandCols) Band { t := Band{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]float64, a.Rows*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m Band) dims() (r, c int) { return m.Rows, m.Cols } func (m Band) at(i, j int) float64 { pj := j + m.KL - i if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[i*m.Stride+pj] } func (m Band) bandwidth() (kl, ku int) { return m.KL, m.KU } func newBandColsFrom(a Band) BandCols { t := BandCols{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]float64, a.Cols*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m BandCols) dims() (r, c int) { return m.Rows, m.Cols } func (m BandCols) at(i, j int) float64 { pj := i + m.KU - j if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[j*m.Stride+pj] } func (m BandCols) bandwidth() (kl, ku int) { return m.KL, m.KU } type band interface { dims() (r, c int) at(i, j int) float64 bandwidth() (kl, ku int) } func sameBand(a, b band) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } akl, aku := a.bandwidth() bkl, bku := b.bandwidth() if akl != bkl || aku != bku { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var bandTests = []Band{ {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 1, Data: []float64{ 1, 2, 3, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []float64{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []float64{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 2, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 2, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 3, Data: []float64{ -1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 3, Data: []float64{ -1, 2, 3, 4, 5, 6, 7, 8, -2, 9, -3, -4, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 4, Data: []float64{ -2, -1, 3, 4, -3, 5, 6, 7, 8, 9, 10, 11, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 4, Data: []float64{ -2, -1, 2, 3, -3, 4, 5, 6, 7, 8, 9, -4, 10, 11, -5, -6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 5, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 5, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 5, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 5, Data: []float64{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 5, Data: []float64{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, -2, 0, 0, 9, -3, -4, 0, 0, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 5, Data: []float64{ -2, -1, 3, 4, 0, -3, 5, 6, 7, 0, 8, 9, 10, 11, 0, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 5, Data: []float64{ -2, -1, 2, 3, 0, -3, 4, 5, 6, 0, 7, 8, 9, -4, 0, 10, 11, -5, -6, 0, }}, } func TestConvertBand(t *testing.T) { for _, test := range bandTests { colmajor := newBandColsFrom(test) if !sameBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newBandFrom(colmajor) if !sameBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularBandFrom(a TriangularBandCols) TriangularBand { t := TriangularBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float64, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBand) n() (n int) { return m.N } func (m TriangularBand) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas64: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBand) bandwidth() (k int) { return m.K } func (m TriangularBand) uplo() blas.Uplo { return m.Uplo } func (m TriangularBand) diag() blas.Diag { return m.Diag } func newTriangularBandColsFrom(a TriangularBand) TriangularBandCols { t := TriangularBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float64, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBandCols) n() (n int) { return m.N } func (m TriangularBandCols) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas64: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBandCols) bandwidth() (k int) { return m.K } func (m TriangularBandCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularBandCols) diag() blas.Diag { return m.Diag } type triangularBand interface { n() (n int) at(i, j int) float64 bandwidth() (k int) uplo() blas.Uplo diag() blas.Diag } func sameTriangularBand(a, b triangularBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } if a.diag() != b.diag() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularBandTests = []TriangularBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []float64{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []float64{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []float64{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []float64{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []float64{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertTriBand(t *testing.T) { for _, test := range triangularBandTests { colmajor := newTriangularBandColsFrom(test) if !sameTriangularBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularBandFrom(colmajor) if !sameTriangularBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/blas64/doc.go000066400000000000000000000004461450372207100207520ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/blas/cblas128/000077500000000000000000000000001450372207100200765ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/cblas128/cblas128.go000066400000000000000000000427101450372207100217500ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/blas/cblas128/cblas128_test.go000066400000000000000000000306271450372207100230130ustar00rootroot00000000000000// Copyright ©2019 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 ( "fmt" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/blas/testblas" ) var impl = c128{} func TestDzasum(t *testing.T) { testblas.DzasumTest(t, impl) } func TestDznrm2(t *testing.T) { testblas.Dznrm2Test(t, impl) } func TestIzamax(t *testing.T) { testblas.IzamaxTest(t, impl) } func TestZaxpy(t *testing.T) { testblas.ZaxpyTest(t, impl) } func TestZcopy(t *testing.T) { testblas.ZcopyTest(t, impl) } func TestZdotc(t *testing.T) { testblas.ZdotcTest(t, impl) } func TestZdotu(t *testing.T) { testblas.ZdotuTest(t, impl) } func TestZdscal(t *testing.T) { testblas.ZdscalTest(t, impl) } func TestZscal(t *testing.T) { testblas.ZscalTest(t, impl) } func TestZswap(t *testing.T) { testblas.ZswapTest(t, impl) } func TestZgbmv(t *testing.T) { testblas.ZgbmvTest(t, impl) } func TestZgemv(t *testing.T) { testblas.ZgemvTest(t, impl) } func TestZgerc(t *testing.T) { testblas.ZgercTest(t, impl) } func TestZgeru(t *testing.T) { testblas.ZgeruTest(t, impl) } func TestZhbmv(t *testing.T) { testblas.ZhbmvTest(t, impl) } func TestZhemv(t *testing.T) { testblas.ZhemvTest(t, impl) } func TestZher(t *testing.T) { testblas.ZherTest(t, impl) } func TestZher2(t *testing.T) { testblas.Zher2Test(t, impl) } func TestZhpmv(t *testing.T) { testblas.ZhpmvTest(t, impl) } func TestZhpr(t *testing.T) { testblas.ZhprTest(t, impl) } func TestZhpr2(t *testing.T) { testblas.Zhpr2Test(t, impl) } func TestZtbmv(t *testing.T) { testblas.ZtbmvTest(t, impl) } func TestZtbsv(t *testing.T) { testblas.ZtbsvTest(t, impl) } func TestZtpmv(t *testing.T) { testblas.ZtpmvTest(t, impl) } func TestZtpsv(t *testing.T) { testblas.ZtpsvTest(t, impl) } func TestZtrmv(t *testing.T) { testblas.ZtrmvTest(t, impl) } func TestZtrsv(t *testing.T) { testblas.ZtrsvTest(t, impl) } func TestZgemm(t *testing.T) { testblas.ZgemmTest(t, impl) } func TestZhemm(t *testing.T) { testblas.ZhemmTest(t, impl) } func TestZherk(t *testing.T) { testblas.ZherkTest(t, impl) } func TestZher2k(t *testing.T) { testblas.Zher2kTest(t, impl) } func TestZsymm(t *testing.T) { testblas.ZsymmTest(t, impl) } func TestZsyrk(t *testing.T) { testblas.ZsyrkTest(t, impl) } func TestZsyr2k(t *testing.T) { testblas.Zsyr2kTest(t, impl) } func TestZtrmm(t *testing.T) { testblas.ZtrmmTest(t, impl) } func TestZtrsm(t *testing.T) { testblas.ZtrsmTest(t, impl) } type c128 struct{} var _ blas.Complex128 = c128{} func (c128) Zdotu(n int, x []complex128, incX int, y []complex128, incY int) complex128 { return Dotu(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (c128) Zdotc(n int, x []complex128, incX int, y []complex128, incY int) complex128 { return Dotc(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (c128) Dznrm2(n int, x []complex128, incX int) float64 { if incX < 0 { return 0 } return Nrm2(Vector{N: n, Inc: incX, Data: x}) } func (c128) Dnrm2(n int, x []float64, incX int) float64 { return blas64.Nrm2(blas64.Vector{N: n, Inc: incX, Data: x}) } func (c128) Dzasum(n int, x []complex128, incX int) float64 { if incX < 0 { return 0 } return Asum(Vector{N: n, Inc: incX, Data: x}) } func (c128) Izamax(n int, x []complex128, incX int) int { if incX < 0 { return -1 } return Iamax(Vector{N: n, Inc: incX, Data: x}) } func (c128) Zswap(n int, x []complex128, incX int, y []complex128, incY int) { Swap(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (c128) Zcopy(n int, x []complex128, incX int, y []complex128, incY int) { Copy(Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (c128) Zaxpy(n int, alpha complex128, x []complex128, incX int, y []complex128, incY int) { Axpy(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}) } func (c128) Zscal(n int, alpha complex128, x []complex128, incX int) { if incX < 0 { return } Scal(alpha, Vector{N: n, Inc: incX, Data: x}) } func (c128) Zdscal(n int, alpha float64, x []complex128, incX int) { if incX < 0 { return } Dscal(alpha, Vector{N: n, Inc: incX, Data: x}) } func (c128) Zgemv(tA blas.Transpose, m, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { lenX := m lenY := n if tA == blas.NoTrans { lenX = n lenY = m } Gemv(tA, alpha, General{Rows: m, Cols: n, Data: a, Stride: lda}, Vector{N: lenX, Inc: incX, Data: x}, beta, Vector{N: lenY, Inc: incY, Data: y}) } func (c128) Zgbmv(tA blas.Transpose, m, n, kL, kU int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { lenX := m lenY := n if tA == blas.NoTrans { lenX = n lenY = m } Gbmv(tA, alpha, Band{Rows: m, Cols: n, KL: kL, KU: kU, Data: a, Stride: lda}, Vector{N: lenX, Inc: incX, Data: x}, beta, Vector{N: lenY, Inc: incY, Data: y}) } func (c128) Ztrmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []complex128, lda int, x []complex128, incX int) { Trmv(tA, Triangular{Uplo: ul, Diag: d, N: n, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (c128) Ztbmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []complex128, lda int, x []complex128, incX int) { Tbmv(tA, TriangularBand{Uplo: ul, Diag: d, N: n, K: k, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (c128) Ztpmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []complex128, x []complex128, incX int) { Tpmv(tA, TriangularPacked{Uplo: ul, Diag: d, N: n, Data: ap}, Vector{N: n, Inc: incX, Data: x}) } func (c128) Ztrsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []complex128, lda int, x []complex128, incX int) { Trsv(tA, Triangular{Uplo: ul, Diag: d, N: n, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (c128) Ztbsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []complex128, lda int, x []complex128, incX int) { Tbsv(tA, TriangularBand{Uplo: ul, Diag: d, N: n, K: k, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}) } func (c128) Ztpsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []complex128, x []complex128, incX int) { Tpsv(tA, TriangularPacked{Uplo: ul, Diag: d, N: n, Data: ap}, Vector{N: n, Inc: incX, Data: x}) } func (c128) Zhemv(ul blas.Uplo, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { Hemv(alpha, Hermitian{Uplo: ul, N: n, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}, beta, Vector{N: n, Inc: incY, Data: y}) } func (c128) Zhbmv(ul blas.Uplo, n, k int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { Hbmv(alpha, HermitianBand{Uplo: ul, N: n, K: k, Data: a, Stride: lda}, Vector{N: n, Inc: incX, Data: x}, beta, Vector{N: n, Inc: incY, Data: y}) } func (c128) Zhpmv(ul blas.Uplo, n int, alpha complex128, ap []complex128, x []complex128, incX int, beta complex128, y []complex128, incY int) { Hpmv(alpha, HermitianPacked{Uplo: ul, N: n, Data: ap}, Vector{N: n, Inc: incX, Data: x}, beta, Vector{N: n, Inc: incY, Data: y}) } func (c128) Zgeru(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) { Geru(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, General{Rows: m, Cols: n, Data: a, Stride: lda}) } func (c128) Zgerc(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) { Gerc(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, General{Rows: m, Cols: n, Data: a, Stride: lda}) } func (c128) Zher(ul blas.Uplo, n int, alpha float64, x []complex128, incX int, a []complex128, lda int) { Her(alpha, Vector{N: n, Inc: incX, Data: x}, Hermitian{Uplo: ul, N: n, Data: a, Stride: lda}) } func (c128) Zhpr(ul blas.Uplo, n int, alpha float64, x []complex128, incX int, ap []complex128) { Hpr(alpha, Vector{N: n, Inc: incX, Data: x}, HermitianPacked{Uplo: ul, N: n, Data: ap}) } func (c128) Zher2(ul blas.Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) { Her2(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, Hermitian{Uplo: ul, N: n, Data: a, Stride: lda}) } func (c128) Zhpr2(ul blas.Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128) { Hpr2(alpha, Vector{N: n, Inc: incX, Data: x}, Vector{N: n, Inc: incY, Data: y}, HermitianPacked{Uplo: ul, N: n, Data: a}) } func (c128) Zgemm(tA, tB blas.Transpose, m, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) { am, an := m, k if tA != blas.NoTrans { am, an = an, am } bm, bn := k, n if tB != blas.NoTrans { bm, bn = bn, bm } Gemm(tA, tB, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, General{Rows: bm, Cols: bn, Data: b, Stride: ldb}, beta, General{Rows: m, Cols: n, Data: c, Stride: ldc}) } func (c128) Zsymm(s blas.Side, ul blas.Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) { var an int switch s { case blas.Left: an = m case blas.Right: an = n default: panic(fmt.Sprintf("blas64: bad test: invalid side: %q", s)) } Symm(s, alpha, Symmetric{Uplo: ul, N: an, Data: a, Stride: lda}, General{Rows: m, Cols: n, Data: b, Stride: ldb}, beta, General{Rows: m, Cols: n, Data: c, Stride: ldc}) } func (c128) Zsyrk(ul blas.Uplo, t blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, beta complex128, c []complex128, ldc int) { am, an := n, k if t != blas.NoTrans { am, an = an, am } Syrk(t, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, beta, Symmetric{Uplo: ul, N: n, Data: c, Stride: ldc}) } func (c128) Zsyr2k(ul blas.Uplo, t blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) { am, an := n, k if t != blas.NoTrans { am, an = an, am } Syr2k(t, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, General{Rows: am, Cols: an, Data: b, Stride: ldb}, beta, Symmetric{Uplo: ul, N: n, Data: c, Stride: ldc}) } func (c128) Zhemm(s blas.Side, ul blas.Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) { var an int switch s { case blas.Left: an = m case blas.Right: an = n default: panic(fmt.Sprintf("blas64: bad test: invalid side: %q", s)) } Hemm(s, alpha, Hermitian{Uplo: ul, N: an, Data: a, Stride: lda}, General{Rows: m, Cols: n, Data: b, Stride: ldb}, beta, General{Rows: m, Cols: n, Data: c, Stride: ldc}) } func (c128) Zherk(ul blas.Uplo, t blas.Transpose, n, k int, alpha float64, a []complex128, lda int, beta float64, c []complex128, ldc int) { am, an := n, k if t != blas.NoTrans { am, an = an, am } Herk(t, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, beta, Hermitian{Uplo: ul, N: n, Data: c, Stride: ldc}) } func (c128) Zher2k(ul blas.Uplo, t blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta float64, c []complex128, ldc int) { am, an := n, k if t != blas.NoTrans { am, an = an, am } Her2k(t, alpha, General{Rows: am, Cols: an, Data: a, Stride: lda}, General{Rows: am, Cols: an, Data: b, Stride: ldb}, beta, Hermitian{Uplo: ul, N: n, Data: c, Stride: ldc}) } func (c128) Ztrmm(s blas.Side, ul blas.Uplo, tA blas.Transpose, d blas.Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int) { var k int switch s { case blas.Left: k = m case blas.Right: k = n default: panic(fmt.Sprintf("blas64: bad test: invalid side: %q", s)) } Trmm(s, tA, alpha, Triangular{Uplo: ul, Diag: d, N: k, Data: a, Stride: lda}, General{Rows: m, Cols: n, Data: b, Stride: ldb}) } func (c128) Ztrsm(s blas.Side, ul blas.Uplo, tA blas.Transpose, d blas.Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int) { var k int switch s { case blas.Left: k = m case blas.Right: k = n default: panic(fmt.Sprintf("blas64: bad test: invalid side: %q", s)) } Trsm(s, tA, alpha, Triangular{Uplo: ul, Diag: d, N: k, Data: a, Stride: lda}, General{Rows: m, Cols: n, Data: b, Stride: ldb}) } golang-gonum-v1-gonum-0.14.0/blas/cblas128/conv.go000066400000000000000000000153461450372207100214030ustar00rootroot00000000000000// 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 } golang-gonum-v1-gonum-0.14.0/blas/cblas128/conv_hermitian.go000066400000000000000000000071051450372207100234350ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/blas/cblas128/conv_hermitian_test.go000066400000000000000000000144521450372207100244770ustar00rootroot00000000000000// 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 ( math "math/cmplx" "testing" "gonum.org/v1/gonum/blas" ) func newHermitianFrom(a HermitianCols) Hermitian { t := Hermitian{ N: a.N, Stride: a.N, Data: make([]complex128, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m Hermitian) n() int { return m.N } func (m Hermitian) at(i, j int) complex128 { if m.Uplo == blas.Lower && i < j && j < m.N { i, j = j, i } if m.Uplo == blas.Upper && i > j { i, j = j, i } return m.Data[i*m.Stride+j] } func (m Hermitian) uplo() blas.Uplo { return m.Uplo } func newHermitianColsFrom(a Hermitian) HermitianCols { t := HermitianCols{ N: a.N, Stride: a.N, Data: make([]complex128, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m HermitianCols) n() int { return m.N } func (m HermitianCols) at(i, j int) complex128 { if m.Uplo == blas.Lower && i < j { i, j = j, i } if m.Uplo == blas.Upper && i > j && i < m.N { i, j = j, i } return m.Data[i+j*m.Stride] } func (m HermitianCols) uplo() blas.Uplo { return m.Uplo } type hermitian interface { n() int at(i, j int) complex128 uplo() blas.Uplo } func sameHermitian(a, b hermitian) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var hermitianTests = []Hermitian{ {N: 3, Stride: 3, Data: []complex128{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertHermitian(t *testing.T) { for _, test := range hermitianTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { test.Uplo = uplo colmajor := newHermitianColsFrom(test) if !sameHermitian(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newHermitianFrom(colmajor) if !sameHermitian(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } func newHermitianBandFrom(a HermitianBandCols) HermitianBand { t := HermitianBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex128, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m HermitianBand) n() (n int) { return m.N } func (m HermitianBand) at(i, j int) complex128 { b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas128: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m HermitianBand) bandwidth() (k int) { return m.K } func (m HermitianBand) uplo() blas.Uplo { return m.Uplo } func newHermitianBandColsFrom(a HermitianBand) HermitianBandCols { t := HermitianBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex128, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m HermitianBandCols) n() (n int) { return m.N } func (m HermitianBandCols) at(i, j int) complex128 { b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas128: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m HermitianBandCols) bandwidth() (k int) { return m.K } func (m HermitianBandCols) uplo() blas.Uplo { return m.Uplo } type hermitianBand interface { n() (n int) at(i, j int) complex128 bandwidth() (k int) uplo() blas.Uplo } func sameHermitianBand(a, b hermitianBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var hermitianBandTests = []HermitianBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []complex128{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []complex128{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []complex128{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []complex128{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []complex128{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertHermBand(t *testing.T) { for _, test := range hermitianBandTests { colmajor := newHermitianBandColsFrom(test) if !sameHermitianBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newHermitianBandFrom(colmajor) if !sameHermitianBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/cblas128/conv_symmetric.go000066400000000000000000000071041450372207100234700ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/blas/cblas128/conv_symmetric_test.go000066400000000000000000000144511450372207100245320ustar00rootroot00000000000000// 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 ( math "math/cmplx" "testing" "gonum.org/v1/gonum/blas" ) func newSymmetricFrom(a SymmetricCols) Symmetric { t := Symmetric{ N: a.N, Stride: a.N, Data: make([]complex128, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m Symmetric) n() int { return m.N } func (m Symmetric) at(i, j int) complex128 { if m.Uplo == blas.Lower && i < j && j < m.N { i, j = j, i } if m.Uplo == blas.Upper && i > j { i, j = j, i } return m.Data[i*m.Stride+j] } func (m Symmetric) uplo() blas.Uplo { return m.Uplo } func newSymmetricColsFrom(a Symmetric) SymmetricCols { t := SymmetricCols{ N: a.N, Stride: a.N, Data: make([]complex128, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m SymmetricCols) n() int { return m.N } func (m SymmetricCols) at(i, j int) complex128 { if m.Uplo == blas.Lower && i < j { i, j = j, i } if m.Uplo == blas.Upper && i > j && i < m.N { i, j = j, i } return m.Data[i+j*m.Stride] } func (m SymmetricCols) uplo() blas.Uplo { return m.Uplo } type symmetric interface { n() int at(i, j int) complex128 uplo() blas.Uplo } func sameSymmetric(a, b symmetric) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var symmetricTests = []Symmetric{ {N: 3, Stride: 3, Data: []complex128{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertSymmetric(t *testing.T) { for _, test := range symmetricTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { test.Uplo = uplo colmajor := newSymmetricColsFrom(test) if !sameSymmetric(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newSymmetricFrom(colmajor) if !sameSymmetric(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } func newSymmetricBandFrom(a SymmetricBandCols) SymmetricBand { t := SymmetricBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex128, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m SymmetricBand) n() (n int) { return m.N } func (m SymmetricBand) at(i, j int) complex128 { b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas128: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m SymmetricBand) bandwidth() (k int) { return m.K } func (m SymmetricBand) uplo() blas.Uplo { return m.Uplo } func newSymmetricBandColsFrom(a SymmetricBand) SymmetricBandCols { t := SymmetricBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex128, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m SymmetricBandCols) n() (n int) { return m.N } func (m SymmetricBandCols) at(i, j int) complex128 { b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas128: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m SymmetricBandCols) bandwidth() (k int) { return m.K } func (m SymmetricBandCols) uplo() blas.Uplo { return m.Uplo } type symmetricBand interface { n() (n int) at(i, j int) complex128 bandwidth() (k int) uplo() blas.Uplo } func sameSymmetricBand(a, b symmetricBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var symmetricBandTests = []SymmetricBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []complex128{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []complex128{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []complex128{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []complex128{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []complex128{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertSymBand(t *testing.T) { for _, test := range symmetricBandTests { colmajor := newSymmetricBandColsFrom(test) if !sameSymmetricBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newSymmetricBandFrom(colmajor) if !sameSymmetricBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/cblas128/conv_test.go000066400000000000000000000320661450372207100224400ustar00rootroot00000000000000// 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 ( math "math/cmplx" "testing" "gonum.org/v1/gonum/blas" ) func newGeneralFrom(a GeneralCols) General { t := General{ Rows: a.Rows, Cols: a.Cols, Stride: a.Cols, Data: make([]complex128, a.Rows*a.Cols), } t.From(a) return t } func (m General) dims() (r, c int) { return m.Rows, m.Cols } func (m General) at(i, j int) complex128 { return m.Data[i*m.Stride+j] } func newGeneralColsFrom(a General) GeneralCols { t := GeneralCols{ Rows: a.Rows, Cols: a.Cols, Stride: a.Rows, Data: make([]complex128, a.Rows*a.Cols), } t.From(a) return t } func (m GeneralCols) dims() (r, c int) { return m.Rows, m.Cols } func (m GeneralCols) at(i, j int) complex128 { return m.Data[i+j*m.Stride] } type general interface { dims() (r, c int) at(i, j int) complex128 } func sameGeneral(a, b general) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var generalTests = []General{ {Rows: 2, Cols: 3, Stride: 3, Data: []complex128{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 2, Stride: 2, Data: []complex128{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 3, Stride: 3, Data: []complex128{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 2, Cols: 3, Stride: 5, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, }}, {Rows: 3, Cols: 2, Stride: 5, Data: []complex128{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 3, Stride: 5, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertGeneral(t *testing.T) { for _, test := range generalTests { colmajor := newGeneralColsFrom(test) if !sameGeneral(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newGeneralFrom(colmajor) if !sameGeneral(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularFrom(a TriangularCols) Triangular { t := Triangular{ N: a.N, Stride: a.N, Data: make([]complex128, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m Triangular) n() int { return m.N } func (m Triangular) at(i, j int) complex128 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j && j < m.N { return 0 } if m.Uplo == blas.Upper && i > j { return 0 } return m.Data[i*m.Stride+j] } func (m Triangular) uplo() blas.Uplo { return m.Uplo } func (m Triangular) diag() blas.Diag { return m.Diag } func newTriangularColsFrom(a Triangular) TriangularCols { t := TriangularCols{ N: a.N, Stride: a.N, Data: make([]complex128, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m TriangularCols) n() int { return m.N } func (m TriangularCols) at(i, j int) complex128 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j { return 0 } if m.Uplo == blas.Upper && i > j && i < m.N { return 0 } return m.Data[i+j*m.Stride] } func (m TriangularCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularCols) diag() blas.Diag { return m.Diag } type triangular interface { n() int at(i, j int) complex128 uplo() blas.Uplo diag() blas.Diag } func sameTriangular(a, b triangular) bool { an := a.n() bn := b.n() if an != bn { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularTests = []Triangular{ {N: 3, Stride: 3, Data: []complex128{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertTriangular(t *testing.T) { for _, test := range triangularTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower, blas.All} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { test.Uplo = uplo test.Diag = diag colmajor := newTriangularColsFrom(test) if !sameTriangular(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularFrom(colmajor) if !sameTriangular(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } } func newBandFrom(a BandCols) Band { t := Band{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]complex128, a.Rows*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m Band) dims() (r, c int) { return m.Rows, m.Cols } func (m Band) at(i, j int) complex128 { pj := j + m.KL - i if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[i*m.Stride+pj] } func (m Band) bandwidth() (kl, ku int) { return m.KL, m.KU } func newBandColsFrom(a Band) BandCols { t := BandCols{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]complex128, a.Cols*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m BandCols) dims() (r, c int) { return m.Rows, m.Cols } func (m BandCols) at(i, j int) complex128 { pj := i + m.KU - j if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[j*m.Stride+pj] } func (m BandCols) bandwidth() (kl, ku int) { return m.KL, m.KU } type band interface { dims() (r, c int) at(i, j int) complex128 bandwidth() (kl, ku int) } func sameBand(a, b band) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } akl, aku := a.bandwidth() bkl, bku := b.bandwidth() if akl != bkl || aku != bku { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var bandTests = []Band{ {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 1, Data: []complex128{ 1, 2, 3, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []complex128{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []complex128{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 2, Data: []complex128{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 2, Data: []complex128{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 3, Data: []complex128{ -1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 3, Data: []complex128{ -1, 2, 3, 4, 5, 6, 7, 8, -2, 9, -3, -4, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 4, Data: []complex128{ -2, -1, 3, 4, -3, 5, 6, 7, 8, 9, 10, 11, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 4, Data: []complex128{ -2, -1, 2, 3, -3, 4, 5, 6, 7, 8, 9, -4, 10, 11, -5, -6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 5, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 5, Data: []complex128{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 5, Data: []complex128{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 5, Data: []complex128{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 5, Data: []complex128{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, -2, 0, 0, 9, -3, -4, 0, 0, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 5, Data: []complex128{ -2, -1, 3, 4, 0, -3, 5, 6, 7, 0, 8, 9, 10, 11, 0, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 5, Data: []complex128{ -2, -1, 2, 3, 0, -3, 4, 5, 6, 0, 7, 8, 9, -4, 0, 10, 11, -5, -6, 0, }}, } func TestConvertBand(t *testing.T) { for _, test := range bandTests { colmajor := newBandColsFrom(test) if !sameBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newBandFrom(colmajor) if !sameBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularBandFrom(a TriangularBandCols) TriangularBand { t := TriangularBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex128, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBand) n() (n int) { return m.N } func (m TriangularBand) at(i, j int) complex128 { if m.Diag == blas.Unit && i == j { return 1 } b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas128: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBand) bandwidth() (k int) { return m.K } func (m TriangularBand) uplo() blas.Uplo { return m.Uplo } func (m TriangularBand) diag() blas.Diag { return m.Diag } func newTriangularBandColsFrom(a TriangularBand) TriangularBandCols { t := TriangularBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex128, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBandCols) n() (n int) { return m.N } func (m TriangularBandCols) at(i, j int) complex128 { if m.Diag == blas.Unit && i == j { return 1 } b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas128: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBandCols) bandwidth() (k int) { return m.K } func (m TriangularBandCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularBandCols) diag() blas.Diag { return m.Diag } type triangularBand interface { n() (n int) at(i, j int) complex128 bandwidth() (k int) uplo() blas.Uplo diag() blas.Diag } func sameTriangularBand(a, b triangularBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } if a.diag() != b.diag() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularBandTests = []TriangularBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []complex128{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []complex128{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []complex128{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []complex128{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []complex128{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []complex128{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []complex128{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertTriBand(t *testing.T) { for _, test := range triangularBandTests { colmajor := newTriangularBandColsFrom(test) if !sameTriangularBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularBandFrom(colmajor) if !sameTriangularBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/cblas128/doc.go000066400000000000000000000004571450372207100212000ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/blas/cblas64/000077500000000000000000000000001450372207100200155ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/cblas64/cblas64.go000066400000000000000000000425571450372207100216170ustar00rootroot00000000000000// 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 cblas64 import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/gonum" ) var cblas64 blas.Complex64 = gonum.Implementation{} // Use sets the BLAS complex64 implementation to be used by subsequent BLAS calls. // The default implementation is // gonum.org/v1/gonum/blas/gonum.Implementation. func Use(b blas.Complex64) { cblas64 = b } // Implementation returns the current BLAS complex64 implementation. // // Implementation allows direct calls to the current the BLAS complex64 implementation // giving finer control of parameters. func Implementation() blas.Complex64 { return cblas64 } // Vector represents a vector with an associated element increment. type Vector struct { N int Inc int Data []complex64 } // General represents a matrix using the conventional storage scheme. type General struct { Rows, Cols int Stride int Data []complex64 } // Band represents a band matrix using the band storage scheme. type Band struct { Rows, Cols int KL, KU int Stride int Data []complex64 } // Triangular represents a triangular matrix using the conventional storage scheme. type Triangular struct { N int Stride int Data []complex64 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 []complex64 Uplo blas.Uplo Diag blas.Diag } // TriangularPacked represents a triangular matrix using the packed storage scheme. type TriangularPacked struct { N int Data []complex64 Uplo blas.Uplo Diag blas.Diag } // Symmetric represents a symmetric matrix using the conventional storage scheme. type Symmetric struct { N int Stride int Data []complex64 Uplo blas.Uplo } // SymmetricBand represents a symmetric matrix using the band storage scheme. type SymmetricBand struct { N, K int Stride int Data []complex64 Uplo blas.Uplo } // SymmetricPacked represents a symmetric matrix using the packed storage scheme. type SymmetricPacked struct { N int Data []complex64 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 = "cblas64: negative vector increment" badLength = "cblas64: 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) complex64 { if x.N != y.N { panic(badLength) } return cblas64.Cdotu(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) complex64 { if x.N != y.N { panic(badLength) } return cblas64.Cdotc(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) float32 { if x.Inc < 0 { panic(negInc) } return cblas64.Scnrm2(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) float32 { if x.Inc < 0 { panic(negInc) } return cblas64.Scasum(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 cblas64.Icamax(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) } cblas64.Cswap(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) } cblas64.Ccopy(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 complex64, x, y Vector) { if x.N != y.N { panic(badLength) } cblas64.Caxpy(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 complex64, x Vector) { if x.Inc < 0 { panic(negInc) } cblas64.Cscal(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 float32, x Vector) { if x.Inc < 0 { panic(negInc) } cblas64.Csscal(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 complex64, a General, x Vector, beta complex64, y Vector) { cblas64.Cgemv(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 complex64, a Band, x Vector, beta complex64, y Vector) { cblas64.Cgbmv(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) { cblas64.Ctrmv(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) { cblas64.Ctbmv(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) { cblas64.Ctpmv(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) { cblas64.Ctrsv(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) { cblas64.Ctbsv(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) { cblas64.Ctpsv(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 complex64, a Hermitian, x Vector, beta complex64, y Vector) { cblas64.Chemv(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 complex64, a HermitianBand, x Vector, beta complex64, y Vector) { cblas64.Chbmv(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 complex64, a HermitianPacked, x Vector, beta complex64, y Vector) { cblas64.Chpmv(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 complex64, x, y Vector, a General) { cblas64.Cgeru(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 complex64, x, y Vector, a General) { cblas64.Cgerc(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 float32, x Vector, a Hermitian) { cblas64.Cher(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 float32, x Vector, a HermitianPacked) { cblas64.Chpr(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 complex64, x, y Vector, a Hermitian) { cblas64.Cher2(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 complex64, x, y Vector, a HermitianPacked) { cblas64.Chpr2(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 complex64, a, b General, beta complex64, 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 } cblas64.Cgemm(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 complex64, a Symmetric, b General, beta complex64, c General) { var m, n int if s == blas.Left { m, n = a.N, b.Cols } else { m, n = b.Rows, a.N } cblas64.Csymm(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 complex64, a General, beta complex64, c Symmetric) { var n, k int if t == blas.NoTrans { n, k = a.Rows, a.Cols } else { n, k = a.Cols, a.Rows } cblas64.Csyrk(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 complex64, a, b General, beta complex64, c Symmetric) { var n, k int if t == blas.NoTrans { n, k = a.Rows, a.Cols } else { n, k = a.Cols, a.Rows } cblas64.Csyr2k(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 complex64, a Triangular, b General) { cblas64.Ctrmm(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 complex64, a Triangular, b General) { cblas64.Ctrsm(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 complex64, a Hermitian, b General, beta complex64, c General) { var m, n int if s == blas.Left { m, n = a.N, b.Cols } else { m, n = b.Rows, a.N } cblas64.Chemm(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 float32, a General, beta float32, c Hermitian) { var n, k int if t == blas.NoTrans { n, k = a.Rows, a.Cols } else { n, k = a.Cols, a.Rows } cblas64.Cherk(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 complex64, a, b General, beta float32, c Hermitian) { var n, k int if t == blas.NoTrans { n, k = a.Rows, a.Cols } else { n, k = a.Cols, a.Rows } cblas64.Cher2k(c.Uplo, t, n, k, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride) } golang-gonum-v1-gonum-0.14.0/blas/cblas64/conv.go000066400000000000000000000153031450372207100213130ustar00rootroot00000000000000// 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 cblas64 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("cblas64: mismatched dimension") } if len(t.Data) < (t.Cols-1)*t.Stride+t.Rows { panic("cblas64: 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("cblas64: mismatched dimension") } if len(t.Data) < (t.Rows-1)*t.Stride+t.Cols { panic("cblas64: 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("cblas64: mismatched dimension") } if t.Uplo != a.Uplo { panic("cblas64: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("cblas64: mismatched BLAS diag") } switch a.Uplo { default: panic("cblas64: 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("cblas64: mismatched dimension") } if t.Uplo != a.Uplo { panic("cblas64: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("cblas64: mismatched BLAS diag") } switch a.Uplo { default: panic("cblas64: 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("cblas64: mismatched dimension") } if t.KL != a.KL || t.KU != a.KU { panic("cblas64: mismatched bandwidth") } if a.Stride < a.KL+a.KU+1 { panic("cblas64: short stride for source") } if t.Stride < t.KL+t.KU+1 { panic("cblas64: 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("cblas64: mismatched dimension") } if t.KL != a.KL || t.KU != a.KU { panic("cblas64: mismatched bandwidth") } if a.Stride < a.KL+a.KU+1 { panic("cblas64: short stride for source") } if t.Stride < t.KL+t.KU+1 { panic("cblas64: 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("cblas64: mismatched dimension") } if t.K != a.K { panic("cblas64: mismatched bandwidth") } if a.Stride < a.K+1 { panic("cblas64: short stride for source") } if t.Stride < t.K+1 { panic("cblas64: short stride for destination") } if t.Uplo != a.Uplo { panic("cblas64: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("cblas64: 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("cblas64: 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("cblas64: mismatched dimension") } if t.K != a.K { panic("cblas64: mismatched bandwidth") } if a.Stride < a.K+1 { panic("cblas64: short stride for source") } if t.Stride < t.K+1 { panic("cblas64: short stride for destination") } if t.Uplo != a.Uplo { panic("cblas64: mismatched BLAS uplo") } if t.Diag != a.Diag { panic("cblas64: 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("cblas64: 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 } golang-gonum-v1-gonum-0.14.0/blas/cblas64/conv_hermitian.go000066400000000000000000000070621450372207100233560ustar00rootroot00000000000000// 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 cblas64 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("cblas64: mismatched dimension") } if t.Uplo != a.Uplo { panic("cblas64: mismatched BLAS uplo") } switch a.Uplo { default: panic("cblas64: 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("cblas64: mismatched dimension") } if t.Uplo != a.Uplo { panic("cblas64: mismatched BLAS uplo") } switch a.Uplo { default: panic("cblas64: 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("cblas64: mismatched dimension") } if t.K != a.K { panic("cblas64: mismatched bandwidth") } if a.Stride < a.K+1 { panic("cblas64: short stride for source") } if t.Stride < t.K+1 { panic("cblas64: short stride for destination") } if t.Uplo != a.Uplo { panic("cblas64: 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("cblas64: 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("cblas64: mismatched dimension") } if t.K != a.K { panic("cblas64: mismatched bandwidth") } if a.Stride < a.K+1 { panic("cblas64: short stride for source") } if t.Stride < t.K+1 { panic("cblas64: short stride for destination") } if t.Uplo != a.Uplo { panic("cblas64: 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("cblas64: 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) } golang-gonum-v1-gonum-0.14.0/blas/cblas64/conv_hermitian_test.go000066400000000000000000000144501450372207100244140ustar00rootroot00000000000000// 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 cblas64 import ( math "gonum.org/v1/gonum/internal/cmplx64" "testing" "gonum.org/v1/gonum/blas" ) func newHermitianFrom(a HermitianCols) Hermitian { t := Hermitian{ N: a.N, Stride: a.N, Data: make([]complex64, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m Hermitian) n() int { return m.N } func (m Hermitian) at(i, j int) complex64 { if m.Uplo == blas.Lower && i < j && j < m.N { i, j = j, i } if m.Uplo == blas.Upper && i > j { i, j = j, i } return m.Data[i*m.Stride+j] } func (m Hermitian) uplo() blas.Uplo { return m.Uplo } func newHermitianColsFrom(a Hermitian) HermitianCols { t := HermitianCols{ N: a.N, Stride: a.N, Data: make([]complex64, a.N*a.N), Uplo: a.Uplo, } t.From(a) return t } func (m HermitianCols) n() int { return m.N } func (m HermitianCols) at(i, j int) complex64 { if m.Uplo == blas.Lower && i < j { i, j = j, i } if m.Uplo == blas.Upper && i > j && i < m.N { i, j = j, i } return m.Data[i+j*m.Stride] } func (m HermitianCols) uplo() blas.Uplo { return m.Uplo } type hermitian interface { n() int at(i, j int) complex64 uplo() blas.Uplo } func sameHermitian(a, b hermitian) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var hermitianTests = []Hermitian{ {N: 3, Stride: 3, Data: []complex64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []complex64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertHermitian(t *testing.T) { for _, test := range hermitianTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { test.Uplo = uplo colmajor := newHermitianColsFrom(test) if !sameHermitian(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newHermitianFrom(colmajor) if !sameHermitian(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } func newHermitianBandFrom(a HermitianBandCols) HermitianBand { t := HermitianBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex64, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m HermitianBand) n() (n int) { return m.N } func (m HermitianBand) at(i, j int) complex64 { b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas64: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m HermitianBand) bandwidth() (k int) { return m.K } func (m HermitianBand) uplo() blas.Uplo { return m.Uplo } func newHermitianBandColsFrom(a HermitianBand) HermitianBandCols { t := HermitianBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex64, a.N*(a.K+1)), Uplo: a.Uplo, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m HermitianBandCols) n() (n int) { return m.N } func (m HermitianBandCols) at(i, j int) complex64 { b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas64: bad BLAS uplo") case blas.Upper: b.KU = m.K if i > j { i, j = j, i } case blas.Lower: b.KL = m.K if i < j { i, j = j, i } } return b.at(i, j) } func (m HermitianBandCols) bandwidth() (k int) { return m.K } func (m HermitianBandCols) uplo() blas.Uplo { return m.Uplo } type hermitianBand interface { n() (n int) at(i, j int) complex64 bandwidth() (k int) uplo() blas.Uplo } func sameHermitianBand(a, b hermitianBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var hermitianBandTests = []HermitianBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []complex64{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []complex64{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []complex64{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []complex64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []complex64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []complex64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []complex64{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []complex64{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertHermBand(t *testing.T) { for _, test := range hermitianBandTests { colmajor := newHermitianBandColsFrom(test) if !sameHermitianBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newHermitianBandFrom(colmajor) if !sameHermitianBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/cblas64/conv_test.go000066400000000000000000000320201450372207100223450ustar00rootroot00000000000000// 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 cblas64 import ( math "gonum.org/v1/gonum/internal/cmplx64" "testing" "gonum.org/v1/gonum/blas" ) func newGeneralFrom(a GeneralCols) General { t := General{ Rows: a.Rows, Cols: a.Cols, Stride: a.Cols, Data: make([]complex64, a.Rows*a.Cols), } t.From(a) return t } func (m General) dims() (r, c int) { return m.Rows, m.Cols } func (m General) at(i, j int) complex64 { return m.Data[i*m.Stride+j] } func newGeneralColsFrom(a General) GeneralCols { t := GeneralCols{ Rows: a.Rows, Cols: a.Cols, Stride: a.Rows, Data: make([]complex64, a.Rows*a.Cols), } t.From(a) return t } func (m GeneralCols) dims() (r, c int) { return m.Rows, m.Cols } func (m GeneralCols) at(i, j int) complex64 { return m.Data[i+j*m.Stride] } type general interface { dims() (r, c int) at(i, j int) complex64 } func sameGeneral(a, b general) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var generalTests = []General{ {Rows: 2, Cols: 3, Stride: 3, Data: []complex64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 2, Stride: 2, Data: []complex64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 3, Stride: 3, Data: []complex64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 2, Cols: 3, Stride: 5, Data: []complex64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, }}, {Rows: 3, Cols: 2, Stride: 5, Data: []complex64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 3, Stride: 5, Data: []complex64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertGeneral(t *testing.T) { for _, test := range generalTests { colmajor := newGeneralColsFrom(test) if !sameGeneral(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newGeneralFrom(colmajor) if !sameGeneral(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularFrom(a TriangularCols) Triangular { t := Triangular{ N: a.N, Stride: a.N, Data: make([]complex64, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m Triangular) n() int { return m.N } func (m Triangular) at(i, j int) complex64 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j && j < m.N { return 0 } if m.Uplo == blas.Upper && i > j { return 0 } return m.Data[i*m.Stride+j] } func (m Triangular) uplo() blas.Uplo { return m.Uplo } func (m Triangular) diag() blas.Diag { return m.Diag } func newTriangularColsFrom(a Triangular) TriangularCols { t := TriangularCols{ N: a.N, Stride: a.N, Data: make([]complex64, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m TriangularCols) n() int { return m.N } func (m TriangularCols) at(i, j int) complex64 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j { return 0 } if m.Uplo == blas.Upper && i > j && i < m.N { return 0 } return m.Data[i+j*m.Stride] } func (m TriangularCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularCols) diag() blas.Diag { return m.Diag } type triangular interface { n() int at(i, j int) complex64 uplo() blas.Uplo diag() blas.Diag } func sameTriangular(a, b triangular) bool { an := a.n() bn := b.n() if an != bn { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularTests = []Triangular{ {N: 3, Stride: 3, Data: []complex64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []complex64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertTriangular(t *testing.T) { for _, test := range triangularTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower, blas.All} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { test.Uplo = uplo test.Diag = diag colmajor := newTriangularColsFrom(test) if !sameTriangular(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularFrom(colmajor) if !sameTriangular(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } } func newBandFrom(a BandCols) Band { t := Band{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]complex64, a.Rows*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m Band) dims() (r, c int) { return m.Rows, m.Cols } func (m Band) at(i, j int) complex64 { pj := j + m.KL - i if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[i*m.Stride+pj] } func (m Band) bandwidth() (kl, ku int) { return m.KL, m.KU } func newBandColsFrom(a Band) BandCols { t := BandCols{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]complex64, a.Cols*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m BandCols) dims() (r, c int) { return m.Rows, m.Cols } func (m BandCols) at(i, j int) complex64 { pj := i + m.KU - j if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[j*m.Stride+pj] } func (m BandCols) bandwidth() (kl, ku int) { return m.KL, m.KU } type band interface { dims() (r, c int) at(i, j int) complex64 bandwidth() (kl, ku int) } func sameBand(a, b band) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } akl, aku := a.bandwidth() bkl, bku := b.bandwidth() if akl != bkl || aku != bku { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var bandTests = []Band{ {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 1, Data: []complex64{ 1, 2, 3, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []complex64{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []complex64{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 2, Data: []complex64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 2, Data: []complex64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 3, Data: []complex64{ -1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 3, Data: []complex64{ -1, 2, 3, 4, 5, 6, 7, 8, -2, 9, -3, -4, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 4, Data: []complex64{ -2, -1, 3, 4, -3, 5, 6, 7, 8, 9, 10, 11, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 4, Data: []complex64{ -2, -1, 2, 3, -3, 4, 5, 6, 7, 8, 9, -4, 10, 11, -5, -6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 5, Data: []complex64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []complex64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []complex64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 5, Data: []complex64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 5, Data: []complex64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 5, Data: []complex64{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 5, Data: []complex64{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, -2, 0, 0, 9, -3, -4, 0, 0, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 5, Data: []complex64{ -2, -1, 3, 4, 0, -3, 5, 6, 7, 0, 8, 9, 10, 11, 0, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 5, Data: []complex64{ -2, -1, 2, 3, 0, -3, 4, 5, 6, 0, 7, 8, 9, -4, 0, 10, 11, -5, -6, 0, }}, } func TestConvertBand(t *testing.T) { for _, test := range bandTests { colmajor := newBandColsFrom(test) if !sameBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newBandFrom(colmajor) if !sameBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularBandFrom(a TriangularBandCols) TriangularBand { t := TriangularBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex64, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBand) n() (n int) { return m.N } func (m TriangularBand) at(i, j int) complex64 { if m.Diag == blas.Unit && i == j { return 1 } b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas64: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBand) bandwidth() (k int) { return m.K } func (m TriangularBand) uplo() blas.Uplo { return m.Uplo } func (m TriangularBand) diag() blas.Diag { return m.Diag } func newTriangularBandColsFrom(a TriangularBand) TriangularBandCols { t := TriangularBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]complex64, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBandCols) n() (n int) { return m.N } func (m TriangularBandCols) at(i, j int) complex64 { if m.Diag == blas.Unit && i == j { return 1 } b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("cblas64: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBandCols) bandwidth() (k int) { return m.K } func (m TriangularBandCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularBandCols) diag() blas.Diag { return m.Diag } type triangularBand interface { n() (n int) at(i, j int) complex64 bandwidth() (k int) uplo() blas.Uplo diag() blas.Diag } func sameTriangularBand(a, b triangularBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } if a.diag() != b.diag() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularBandTests = []TriangularBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []complex64{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []complex64{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []complex64{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []complex64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []complex64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []complex64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []complex64{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []complex64{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []complex64{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertTriBand(t *testing.T) { for _, test := range triangularBandTests { colmajor := newTriangularBandColsFrom(test) if !sameTriangularBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularBandFrom(colmajor) if !sameTriangularBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } golang-gonum-v1-gonum-0.14.0/blas/cblas64/doc.go000066400000000000000000000004531450372207100211130ustar00rootroot00000000000000// 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 cblas64 provides a simple interface to the complex64 BLAS API. package cblas64 // import "gonum.org/v1/gonum/blas/cblas64" golang-gonum-v1-gonum-0.14.0/blas/conversions.bash000077500000000000000000000120701450372207100217710ustar00rootroot00000000000000#!/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 golang-gonum-v1-gonum-0.14.0/blas/doc.go000066400000000000000000000134251450372207100176600ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/blas/gonum/000077500000000000000000000000001450372207100177045ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/gonum/bench_test.go000066400000000000000000000006341450372207100223540ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/testblas" ) const ( Sm = testblas.SmallMat Med = testblas.MediumMat Lg = testblas.LargeMat Hg = testblas.HugeMat ) const ( T = blas.Trans NT = blas.NoTrans ) golang-gonum-v1-gonum-0.14.0/blas/gonum/dgemm.go000066400000000000000000000174631450372207100213370ustar00rootroot00000000000000// 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 } // workerLimit acts a number of maximum concurrent workers, // with the limit set to the number of procs available. workerLimit := make(chan struct{}, runtime.GOMAXPROCS(0)) // wg is used to wait for all var wg sync.WaitGroup wg.Add(parBlocks) defer wg.Wait() for i := 0; i < m; i += blockSize { for j := 0; j < n; j += blockSize { workerLimit <- struct{}{} go func(i, j int) { defer func() { wg.Done() <-workerLimit }() 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) } }(i, j) } } } // 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] } golang-gonum-v1-gonum-0.14.0/blas/gonum/dgemmbench_test.go000066400000000000000000000023551450372207100233700ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func BenchmarkDgemmSmSmSm(b *testing.B) { testblas.DgemmBenchmark(b, impl, Sm, Sm, Sm, NT, NT) } func BenchmarkDgemmMedMedMed(b *testing.B) { testblas.DgemmBenchmark(b, impl, Med, Med, Med, NT, NT) } func BenchmarkDgemmMedLgMed(b *testing.B) { testblas.DgemmBenchmark(b, impl, Med, Lg, Med, NT, NT) } func BenchmarkDgemmLgLgLg(b *testing.B) { testblas.DgemmBenchmark(b, impl, Lg, Lg, Lg, NT, NT) } func BenchmarkDgemmLgSmLg(b *testing.B) { testblas.DgemmBenchmark(b, impl, Lg, Sm, Lg, NT, NT) } func BenchmarkDgemmLgLgSm(b *testing.B) { testblas.DgemmBenchmark(b, impl, Lg, Lg, Sm, NT, NT) } func BenchmarkDgemmHgHgSm(b *testing.B) { testblas.DgemmBenchmark(b, impl, Hg, Hg, Sm, NT, NT) } func BenchmarkDgemmMedMedMedTNT(b *testing.B) { testblas.DgemmBenchmark(b, impl, Med, Med, Med, T, NT) } func BenchmarkDgemmMedMedMedNTT(b *testing.B) { testblas.DgemmBenchmark(b, impl, Med, Med, Med, NT, T) } func BenchmarkDgemmMedMedMedTT(b *testing.B) { testblas.DgemmBenchmark(b, impl, Med, Med, Med, T, T) } golang-gonum-v1-gonum-0.14.0/blas/gonum/dgemvbench_test.go000066400000000000000000000044511450372207100234000ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func BenchmarkDgemvSmSmNoTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Sm, Sm, 1, 1) } func BenchmarkDgemvSmSmNoTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Sm, Sm, 2, 3) } func BenchmarkDgemvSmSmTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Sm, Sm, 1, 1) } func BenchmarkDgemvSmSmTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Sm, Sm, 2, 3) } func BenchmarkDgemvMedMedNoTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Med, Med, 1, 1) } func BenchmarkDgemvMedMedNoTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Med, Med, 2, 3) } func BenchmarkDgemvMedMedTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Med, Med, 1, 1) } func BenchmarkDgemvMedMedTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Med, Med, 2, 3) } func BenchmarkDgemvLgLgNoTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Lg, Lg, 1, 1) } func BenchmarkDgemvLgLgNoTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Lg, Lg, 2, 3) } func BenchmarkDgemvLgLgTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Lg, Lg, 1, 1) } func BenchmarkDgemvLgLgTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Lg, Lg, 2, 3) } func BenchmarkDgemvLgSmNoTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Lg, Sm, 1, 1) } func BenchmarkDgemvLgSmNoTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Lg, Sm, 2, 3) } func BenchmarkDgemvLgSmTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Lg, Sm, 1, 1) } func BenchmarkDgemvLgSmTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Lg, Sm, 2, 3) } func BenchmarkDgemvSmLgNoTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Sm, Lg, 1, 1) } func BenchmarkDgemvSmLgNoTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, NT, Sm, Lg, 2, 3) } func BenchmarkDgemvSmLgTransInc1(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Sm, Lg, 1, 1) } func BenchmarkDgemvSmLgTransIncN(b *testing.B) { testblas.DgemvBenchmark(b, impl, T, Sm, Lg, 2, 3) } golang-gonum-v1-gonum-0.14.0/blas/gonum/dgerbench_test.go000066400000000000000000000022311450372207100232110ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func BenchmarkDgerSmSmInc1(b *testing.B) { testblas.DgerBenchmark(b, impl, Sm, Sm, 1, 1) } func BenchmarkDgerSmSmIncN(b *testing.B) { testblas.DgerBenchmark(b, impl, Sm, Sm, 2, 3) } func BenchmarkDgerMedMedInc1(b *testing.B) { testblas.DgerBenchmark(b, impl, Med, Med, 1, 1) } func BenchmarkDgerMedMedIncN(b *testing.B) { testblas.DgerBenchmark(b, impl, Med, Med, 2, 3) } func BenchmarkDgerLgLgInc1(b *testing.B) { testblas.DgerBenchmark(b, impl, Lg, Lg, 1, 1) } func BenchmarkDgerLgLgIncN(b *testing.B) { testblas.DgerBenchmark(b, impl, Lg, Lg, 2, 3) } func BenchmarkDgerLgSmInc1(b *testing.B) { testblas.DgerBenchmark(b, impl, Lg, Sm, 1, 1) } func BenchmarkDgerLgSmIncN(b *testing.B) { testblas.DgerBenchmark(b, impl, Lg, Sm, 2, 3) } func BenchmarkDgerSmLgInc1(b *testing.B) { testblas.DgerBenchmark(b, impl, Sm, Lg, 1, 1) } func BenchmarkDgerSmLgIncN(b *testing.B) { testblas.DgerBenchmark(b, impl, Sm, Lg, 2, 3) } golang-gonum-v1-gonum-0.14.0/blas/gonum/doc.go000066400000000000000000000066051450372207100210070ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/blas/gonum/dtrmvbench_test.go000066400000000000000000000023551450372207100234330ustar00rootroot00000000000000// 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 ( "strconv" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/testblas" ) func BenchmarkDtrmv(b *testing.B) { for _, n := range []int{testblas.MediumMat, testblas.LargeMat} { for _, incX := range []int{1, 5} { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, unit := range []blas.Diag{blas.NonUnit, blas.Unit} { var str string if n == testblas.MediumMat { str += "Med" } else if n == testblas.LargeMat { str += "Large" } str += "_Inc" + strconv.Itoa(incX) if uplo == blas.Upper { str += "_UP" } else { str += "_LO" } if trans == blas.NoTrans { str += "_NT" } else { str += "_TR" } if unit == blas.NonUnit { str += "_NU" } else { str += "_UN" } lda := n b.Run(str, func(b *testing.B) { testblas.DtrmvBenchmark(b, Implementation{}, n, lda, incX, uplo, trans, unit) }) } } } } } } golang-gonum-v1-gonum-0.14.0/blas/gonum/errors.go000066400000000000000000000021271450372207100215510ustar00rootroot00000000000000// 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" ) golang-gonum-v1-gonum-0.14.0/blas/gonum/gonum.go000066400000000000000000000021021450372207100213530ustar00rootroot00000000000000// 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 generation. const ( blockSize = 64 // b x b matrix minParBlock = 4 // minimum number of blocks needed to go parallel ) 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)) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1cmplx128.go000066400000000000000000000201701450372207100227220ustar00rootroot00000000000000// 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 } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1cmplx128_bench_test.go000066400000000000000000000033301450372207100251170ustar00rootroot00000000000000// 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 ( "testing" "golang.org/x/exp/rand" ) func benchmarkZdscal(b *testing.B, n, inc int) { rnd := rand.New(rand.NewSource(1)) alpha := rnd.NormFloat64() x := make([]complex128, (n-1)*inc+1) for i := range x { x[i] = complex(rnd.NormFloat64(), rnd.NormFloat64()) } b.ResetTimer() for i := 0; i < b.N; i++ { impl.Zdscal(n, alpha, x, inc) } } func BenchmarkZdscalN10Inc1(b *testing.B) { benchmarkZdscal(b, 10, 1) } func BenchmarkZdscalN100Inc1(b *testing.B) { benchmarkZdscal(b, 100, 1) } func BenchmarkZdscalN1000Inc1(b *testing.B) { benchmarkZdscal(b, 1000, 1) } func BenchmarkZdscalN10000Inc1(b *testing.B) { benchmarkZdscal(b, 10000, 1) } func BenchmarkZdscalN100000Inc1(b *testing.B) { benchmarkZdscal(b, 100000, 1) } func BenchmarkZdscalN10Inc10(b *testing.B) { benchmarkZdscal(b, 10, 10) } func BenchmarkZdscalN100Inc10(b *testing.B) { benchmarkZdscal(b, 100, 10) } func BenchmarkZdscalN1000Inc10(b *testing.B) { benchmarkZdscal(b, 1000, 10) } func BenchmarkZdscalN10000Inc10(b *testing.B) { benchmarkZdscal(b, 10000, 10) } func BenchmarkZdscalN100000Inc10(b *testing.B) { benchmarkZdscal(b, 100000, 10) } func BenchmarkZdscalN10Inc1000(b *testing.B) { benchmarkZdscal(b, 10, 1000) } func BenchmarkZdscalN100Inc1000(b *testing.B) { benchmarkZdscal(b, 100, 1000) } func BenchmarkZdscalN1000Inc1000(b *testing.B) { benchmarkZdscal(b, 1000, 1000) } func BenchmarkZdscalN10000Inc1000(b *testing.B) { benchmarkZdscal(b, 10000, 1000) } func BenchmarkZdscalN100000Inc1000(b *testing.B) { benchmarkZdscal(b, 100000, 1000) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1cmplx128_test.go000066400000000000000000000015551450372207100237670ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func TestDzasum(t *testing.T) { testblas.DzasumTest(t, impl) } func TestDznrm2(t *testing.T) { testblas.Dznrm2Test(t, impl) } func TestIzamax(t *testing.T) { testblas.IzamaxTest(t, impl) } func TestZaxpy(t *testing.T) { testblas.ZaxpyTest(t, impl) } func TestZcopy(t *testing.T) { testblas.ZcopyTest(t, impl) } func TestZdotc(t *testing.T) { testblas.ZdotcTest(t, impl) } func TestZdotu(t *testing.T) { testblas.ZdotuTest(t, impl) } func TestZdscal(t *testing.T) { testblas.ZdscalTest(t, impl) } func TestZscal(t *testing.T) { testblas.ZscalTest(t, impl) } func TestZswap(t *testing.T) { testblas.ZswapTest(t, impl) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1cmplx64.go000066400000000000000000000216761450372207100226550ustar00rootroot00000000000000// 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 } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float32.go000066400000000000000000000312521450372207100226210ustar00rootroot00000000000000// 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) } if incX == 1 { return f32.L2NormUnitary(x[:n]) } return f32.L2NormInc(x, uintptr(n), uintptr(incX)) } // 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 a plane rotation // // ⎡ c s ⎤ ⎡ a ⎤ = ⎡ r ⎤ // ⎣ -s c ⎦ ⎣ b ⎦ ⎣ 0 ⎦ // // satisfying c^2 + s^2 = 1. // // The computation uses the formulas // // sigma = sgn(a) if |a| > |b| // = sgn(b) if |b| >= |a| // r = sigma*sqrt(a^2 + b^2) // c = 1; s = 0 if r = 0 // c = a/r; s = b/r if r != 0 // c >= 0 if |a| > |b| // // The subroutine also computes // // z = s if |a| > |b|, // = 1/c if |b| >= |a| and c != 0 // = 1 if c = 0 // // This allows c and s to be reconstructed from z as follows: // // If z = 1, set c = 0, s = 1. // If |z| < 1, set c = sqrt(1 - z^2) and s = z. // If |z| > 1, set c = 1/z and s = sqrt(1 - c^2). // // 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. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Srotg(a, b float32) (c, s, r, z float32) { // Implementation based on Supplemental Material to: // Edward Anderson. 2017. Algorithm 978: Safe Scaling in the Level 1 BLAS. // ACM Trans. Math. Softw. 44, 1, Article 12 (July 2017), 28 pages. // DOI: https://doi.org/10.1145/3061665 const ( safmin = 0x1p-126 safmax = 1 / safmin ) anorm := math.Abs(a) bnorm := math.Abs(b) switch { case bnorm == 0: c = 1 s = 0 r = a z = 0 case anorm == 0: c = 0 s = 1 r = b z = 1 default: maxab := math.Max(anorm, bnorm) scl := math.Min(math.Max(safmin, maxab), safmax) var sigma float32 if anorm > bnorm { sigma = math.Copysign(1, a) } else { sigma = math.Copysign(1, b) } ascl := a / scl bscl := b / scl r = sigma * (scl * math.Sqrt(ascl*ascl+bscl*bscl)) c = a / r s = b / r switch { case anorm > bnorm: z = s case c != 0: z = 1 / c default: z = 1 } } return c, s, r, z } // 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 - float32(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 + float32(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] = float32(vx*h11)+float32(vy*h12), float32(vx*h21)+float32(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] = float32(vx*h11)+float32(vy*h12), float32(vx*h21)+float32(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+float32(vy*h12), float32(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+float32(vy*h12), float32(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] = float32(vx*h11)+vy, -vx+float32(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] = float32(vx*h11)+vy, -vx+float32(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)) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float32_dsdot.go000066400000000000000000000022101450372207100240060ustar00rootroot00000000000000// 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)) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float32_sdot.go000066400000000000000000000022041450372207100236450ustar00rootroot00000000000000// 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)) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float32_sdsdot.go000066400000000000000000000023231450372207100241760ustar00rootroot00000000000000// 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))) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float64.go000066400000000000000000000274231450372207100226330ustar00rootroot00000000000000// 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) } if incX == 1 { return f64.L2NormUnitary(x[:n]) } return f64.L2NormInc(x, uintptr(n), uintptr(incX)) } // 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 a plane rotation // // ⎡ c s ⎤ ⎡ a ⎤ = ⎡ r ⎤ // ⎣ -s c ⎦ ⎣ b ⎦ ⎣ 0 ⎦ // // satisfying c^2 + s^2 = 1. // // The computation uses the formulas // // sigma = sgn(a) if |a| > |b| // = sgn(b) if |b| >= |a| // r = sigma*sqrt(a^2 + b^2) // c = 1; s = 0 if r = 0 // c = a/r; s = b/r if r != 0 // c >= 0 if |a| > |b| // // The subroutine also computes // // z = s if |a| > |b|, // = 1/c if |b| >= |a| and c != 0 // = 1 if c = 0 // // This allows c and s to be reconstructed from z as follows: // // If z = 1, set c = 0, s = 1. // If |z| < 1, set c = sqrt(1 - z^2) and s = z. // If |z| > 1, set c = 1/z and s = sqrt(1 - c^2). // // 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) { // Implementation based on Supplemental Material to: // Edward Anderson. 2017. Algorithm 978: Safe Scaling in the Level 1 BLAS. // ACM Trans. Math. Softw. 44, 1, Article 12 (July 2017), 28 pages. // DOI: https://doi.org/10.1145/3061665 const ( safmin = 0x1p-1022 safmax = 1 / safmin ) anorm := math.Abs(a) bnorm := math.Abs(b) switch { case bnorm == 0: c = 1 s = 0 r = a z = 0 case anorm == 0: c = 0 s = 1 r = b z = 1 default: maxab := math.Max(anorm, bnorm) scl := math.Min(math.Max(safmin, maxab), safmax) var sigma float64 if anorm > bnorm { sigma = math.Copysign(1, a) } else { sigma = math.Copysign(1, b) } ascl := a / scl bscl := b / scl r = sigma * (scl * math.Sqrt(ascl*ascl+bscl*bscl)) c = a / r s = b / r switch { case anorm > bnorm: z = s case c != 0: z = 1 / c default: z = 1 } } return c, s, r, z } // 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 - float64(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 + float64(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] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(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] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(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+float64(vy*h12), float64(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+float64(vy*h12), float64(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] = float64(vx*h11)+vy, -vx+float64(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] = float64(vx*h11)+vy, -vx+float64(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)) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float64_bench_test.go000066400000000000000000001122671450372207100250320ustar00rootroot00000000000000// Code generated by "go run gonum.org/v1/gonum/blas/testblas/benchautogen/autogen_bench_level1double.go"; DO NOT EDIT. // Copyright ©2014 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 gonum import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) const ( posInc1 = 5 posInc2 = 3 negInc1 = -3 negInc2 = -4 SMALL_SLICE = 10 MEDIUM_SLICE = 1000 LARGE_SLICE = 100000 HUGE_SLICE = 10000000 ) func randomSlice(l, idx int) []float64 { if idx < 0 { idx = -idx } s := make([]float64, l*idx) for i := range s { s[i] = rand.Float64() } return s } func benchmarkDdot(b *testing.B, n int, x []float64, incX int, y []float64, incY int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Ddot(n, x, incX, y, incY) } } func BenchmarkDdotSmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotSmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotSmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotSmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } func BenchmarkDdotHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDdot(b, n, x, incX, y, incY) } /* ------------------ */ func benchmarkDnrm2(b *testing.B, n int, x []float64, incX int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Dnrm2(n, x, incX) } } func BenchmarkDnrm2SmallUnitaryInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } func BenchmarkDnrm2SmallPosInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } func BenchmarkDnrm2MediumUnitaryInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } func BenchmarkDnrm2MediumPosInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } func BenchmarkDnrm2LargeUnitaryInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } func BenchmarkDnrm2LargePosInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } func BenchmarkDnrm2HugeUnitaryInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } func BenchmarkDnrm2HugePosInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDnrm2(b, n, x, incX) } /* ------------------ */ func benchmarkDasum(b *testing.B, n int, x []float64, incX int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Dasum(n, x, incX) } } func BenchmarkDasumSmallUnitaryInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } func BenchmarkDasumSmallPosInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } func BenchmarkDasumMediumUnitaryInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } func BenchmarkDasumMediumPosInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } func BenchmarkDasumLargeUnitaryInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } func BenchmarkDasumLargePosInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } func BenchmarkDasumHugeUnitaryInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } func BenchmarkDasumHugePosInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkDasum(b, n, x, incX) } /* ------------------ */ func benchmarkIdamax(b *testing.B, n int, x []float64, incX int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Idamax(n, x, incX) } } func BenchmarkIdamaxSmallUnitaryInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } func BenchmarkIdamaxSmallPosInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } func BenchmarkIdamaxMediumUnitaryInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } func BenchmarkIdamaxMediumPosInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } func BenchmarkIdamaxLargeUnitaryInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } func BenchmarkIdamaxLargePosInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } func BenchmarkIdamaxHugeUnitaryInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } func BenchmarkIdamaxHugePosInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) benchmarkIdamax(b, n, x, incX) } /* ------------------ */ func benchmarkDswap(b *testing.B, n int, x []float64, incX int, y []float64, incY int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Dswap(n, x, incX, y, incY) } } func BenchmarkDswapSmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapSmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapSmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapSmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } func BenchmarkDswapHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDswap(b, n, x, incX, y, incY) } /* ------------------ */ func benchmarkDcopy(b *testing.B, n int, x []float64, incX int, y []float64, incY int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Dcopy(n, x, incX, y, incY) } } func BenchmarkDcopySmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopySmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopySmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopySmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } func BenchmarkDcopyHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) benchmarkDcopy(b, n, x, incX, y, incY) } /* ------------------ */ func benchmarkDaxpy(b *testing.B, n int, alpha float64, x []float64, incX int, y []float64, incY int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Daxpy(n, alpha, x, incX, y, incY) } } func BenchmarkDaxpySmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpySmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpySmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpySmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } func BenchmarkDaxpyHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) alpha := 2.4 benchmarkDaxpy(b, n, alpha, x, incX, y, incY) } /* ------------------ */ func benchmarkDrot(b *testing.B, n int, x []float64, incX int, y []float64, incY int, c, s float64) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Drot(n, x, incX, y, incY, c, s) } } func BenchmarkDrotSmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotSmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotSmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotSmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } func BenchmarkDrotHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) c := 0.89725836967 s := 0.44150585279 benchmarkDrot(b, n, x, incX, y, incY, c, s) } /* ------------------ */ func benchmarkDrotmOffDia(b *testing.B, n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Drotm(n, x, incX, y, incY, p) } } func BenchmarkDrotmOffDiaSmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaSmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaSmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaSmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmOffDiaHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}} benchmarkDrotmOffDia(b, n, x, incX, y, incY, p) } /* ------------------ */ func benchmarkDrotmDia(b *testing.B, n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Drotm(n, x, incX, y, incY, p) } } func BenchmarkDrotmDiaSmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaSmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaSmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaSmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } func BenchmarkDrotmDiaHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}} benchmarkDrotmDia(b, n, x, incX, y, incY, p) } /* ------------------ */ func benchmarkDrotmResc(b *testing.B, n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Drotm(n, x, incX, y, incY, p) } } func BenchmarkDrotmRescSmallBothUnitary(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescSmallIncUni(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescSmallUniInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescSmallBothInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescMediumBothUnitary(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescMediumIncUni(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescMediumUniInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescMediumBothInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescLargeBothUnitary(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescLargeIncUni(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescLargeUniInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescLargeBothInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescHugeBothUnitary(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescHugeIncUni(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := 1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescHugeUniInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } func BenchmarkDrotmRescHugeBothInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) incY := negInc1 y := randomSlice(n, incY) p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}} benchmarkDrotmResc(b, n, x, incX, y, incY, p) } /* ------------------ */ func benchmarkDscal(b *testing.B, n int, alpha float64, x []float64, incX int) { b.ResetTimer() for i := 0; i < b.N; i++ { impl.Dscal(n, alpha, x, incX) } } func BenchmarkDscalSmallUnitaryInc(b *testing.B) { n := SMALL_SLICE incX := 1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } func BenchmarkDscalSmallPosInc(b *testing.B) { n := SMALL_SLICE incX := posInc1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } func BenchmarkDscalMediumUnitaryInc(b *testing.B) { n := MEDIUM_SLICE incX := 1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } func BenchmarkDscalMediumPosInc(b *testing.B) { n := MEDIUM_SLICE incX := posInc1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } func BenchmarkDscalLargeUnitaryInc(b *testing.B) { n := LARGE_SLICE incX := 1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } func BenchmarkDscalLargePosInc(b *testing.B) { n := LARGE_SLICE incX := posInc1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } func BenchmarkDscalHugeUnitaryInc(b *testing.B) { n := HUGE_SLICE incX := 1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } func BenchmarkDscalHugePosInc(b *testing.B) { n := HUGE_SLICE incX := posInc1 x := randomSlice(n, incX) alpha := 2.4 benchmarkDscal(b, n, alpha, x, incX) } /* ------------------ */ golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float64_ddot.go000066400000000000000000000017511450372207100236410ustar00rootroot00000000000000// 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)) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level1float64_test.go000066400000000000000000000020031450372207100236550ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) var impl Implementation func TestDasum(t *testing.T) { testblas.DasumTest(t, impl) } func TestDaxpy(t *testing.T) { testblas.DaxpyTest(t, impl) } func TestDdot(t *testing.T) { testblas.DdotTest(t, impl) } func TestDnrm2(t *testing.T) { testblas.Dnrm2Test(t, impl) } func TestIdamax(t *testing.T) { testblas.IdamaxTest(t, impl) } func TestDswap(t *testing.T) { testblas.DswapTest(t, impl) } func TestDcopy(t *testing.T) { testblas.DcopyTest(t, impl) } func TestDrotg(t *testing.T) { testblas.DrotgTest(t, impl, false) } func TestDrotmg(t *testing.T) { testblas.DrotmgTest(t, impl) } func TestDrot(t *testing.T) { testblas.DrotTest(t, impl) } func TestDrotm(t *testing.T) { testblas.DrotmTest(t, impl) } func TestDscal(t *testing.T) { testblas.DscalTest(t, impl) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level2cmplx128.go000066400000000000000000001706751450372207100227430ustar00rootroot00000000000000// 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/cmplx" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/internal/asm/c128" ) var _ blas.Complex128Level2 = Implementation{} // Zgbmv performs one of the matrix-vector operations // // y = alpha * A * x + beta * y if trans = blas.NoTrans // y = alpha * Aᵀ * x + beta * y if trans = blas.Trans // y = alpha * Aᴴ * x + beta * y if trans = blas.ConjTrans // // where alpha and beta are scalars, x and y are vectors, and A is an m×n band matrix // with kL sub-diagonals and kU super-diagonals. func (Implementation) Zgbmv(trans blas.Transpose, m, n, kL, kU int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } if m < 0 { panic(mLT0) } if n < 0 { panic(nLT0) } if kL < 0 { panic(kLLT0) } if kU < 0 { panic(kULT0) } if lda < kL+kU+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // 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*(min(m, n+kL)-1)+kL+kU+1 { panic(shortA) } var lenX, lenY int if trans == blas.NoTrans { lenX, lenY = n, m } else { lenX, lenY = m, n } if (incX > 0 && len(x) <= (lenX-1)*incX) || (incX < 0 && len(x) <= (1-lenX)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (lenY-1)*incY) || (incY < 0 && len(y) <= (1-lenY)*incY) { panic(shortY) } // Quick return if possible. if alpha == 0 && beta == 1 { return } var kx int if incX < 0 { kx = (1 - lenX) * incX } var ky int if incY < 0 { ky = (1 - lenY) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:lenY] { y[i] = 0 } } else { c128.ScalUnitary(beta, y[:lenY]) } } else { iy := ky if beta == 0 { for i := 0; i < lenY; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { c128.ScalInc(beta, y, uintptr(lenY), uintptr(incY)) } else { c128.ScalInc(beta, y, uintptr(lenY), uintptr(-incY)) } } } } nRow := min(m, n+kL) nCol := kL + 1 + kU switch trans { case blas.NoTrans: iy := ky if incX == 1 { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) xtmp := x[off : off+u-l] var sum complex128 for j, v := range aRow { sum += xtmp[j] * v } y[iy] += alpha * sum iy += incY } } else { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incX jx := kx var sum complex128 for _, v := range aRow { sum += x[off+jx] * v jx += incX } y[iy] += alpha * sum iy += incY } } case blas.Trans: if incX == 1 { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[i] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * v jy += incY } } } else { ix := kx for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[ix] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * v jy += incY } ix += incX } } case blas.ConjTrans: if incX == 1 { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[i] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * cmplx.Conj(v) jy += incY } } } else { ix := kx for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[ix] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * cmplx.Conj(v) jy += incY } ix += incX } } } } // Zgemv performs one of the matrix-vector operations // // y = alpha * A * x + beta * y if trans = blas.NoTrans // y = alpha * Aᵀ * x + beta * y if trans = blas.Trans // y = alpha * Aᴴ * x + beta * y if trans = blas.ConjTrans // // where alpha and beta are scalars, x and y are vectors, and A is an m×n dense matrix. func (Implementation) Zgemv(trans blas.Transpose, m, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } 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 } // For zero matrix size the following slice length checks are trivially satisfied. var lenX, lenY int if trans == blas.NoTrans { lenX = n lenY = m } else { lenX = m lenY = n } if len(a) < lda*(m-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (lenX-1)*incX) || (incX < 0 && len(x) <= (1-lenX)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (lenY-1)*incY) || (incY < 0 && len(y) <= (1-lenY)*incY) { panic(shortY) } // Quick return if possible. if alpha == 0 && beta == 1 { return } var kx int if incX < 0 { kx = (1 - lenX) * incX } var ky int if incY < 0 { ky = (1 - lenY) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:lenY] { y[i] = 0 } } else { c128.ScalUnitary(beta, y[:lenY]) } } else { iy := ky if beta == 0 { for i := 0; i < lenY; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { c128.ScalInc(beta, y, uintptr(lenY), uintptr(incY)) } else { c128.ScalInc(beta, y, uintptr(lenY), uintptr(-incY)) } } } } if alpha == 0 { return } switch trans { default: // Form y = alpha*A*x + y. iy := ky if incX == 1 { for i := 0; i < m; i++ { y[iy] += alpha * c128.DotuUnitary(a[i*lda:i*lda+n], x[:n]) iy += incY } return } for i := 0; i < m; i++ { y[iy] += alpha * c128.DotuInc(a[i*lda:i*lda+n], x, uintptr(n), 1, uintptr(incX), 0, uintptr(kx)) iy += incY } return case blas.Trans: // Form y = alpha*Aᵀ*x + y. ix := kx if incY == 1 { for i := 0; i < m; i++ { c128.AxpyUnitary(alpha*x[ix], a[i*lda:i*lda+n], y[:n]) ix += incX } return } for i := 0; i < m; i++ { c128.AxpyInc(alpha*x[ix], a[i*lda:i*lda+n], y, uintptr(n), 1, uintptr(incY), 0, uintptr(ky)) ix += incX } return case blas.ConjTrans: // Form y = alpha*Aᴴ*x + y. ix := kx if incY == 1 { for i := 0; i < m; i++ { tmp := alpha * x[ix] for j := 0; j < n; j++ { y[j] += tmp * cmplx.Conj(a[i*lda+j]) } ix += incX } return } for i := 0; i < m; i++ { tmp := alpha * x[ix] jy := ky for j := 0; j < n; j++ { y[jy] += tmp * cmplx.Conj(a[i*lda+j]) jy += incY } ix += incX } return } } // Zgerc performs the rank-one operation // // A += alpha * x * yᴴ // // where A is an m×n dense matrix, alpha is a scalar, x is an m element vector, // and y is an n element vector. func (Implementation) Zgerc(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) { 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 } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (m-1)*incX) || (incX < 0 && len(x) <= (1-m)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { panic(shortY) } if len(a) < lda*(m-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx, jy int if incX < 0 { kx = (1 - m) * incX } if incY < 0 { jy = (1 - n) * incY } for j := 0; j < n; j++ { if y[jy] != 0 { tmp := alpha * cmplx.Conj(y[jy]) c128.AxpyInc(tmp, x, a[j:], uintptr(m), uintptr(incX), uintptr(lda), uintptr(kx), 0) } jy += incY } } // Zgeru performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, alpha is a scalar, x is an m element vector, // and y is an n element vector. func (Implementation) Zgeru(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) { 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 } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (m-1)*incX) || (incX < 0 && len(x) <= (1-m)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { panic(shortY) } if len(a) < lda*(m-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx int if incX < 0 { kx = (1 - m) * incX } if incY == 1 { for i := 0; i < m; i++ { if x[kx] != 0 { tmp := alpha * x[kx] c128.AxpyUnitary(tmp, y[:n], a[i*lda:i*lda+n]) } kx += incX } return } var jy int if incY < 0 { jy = (1 - n) * incY } for i := 0; i < m; i++ { if x[kx] != 0 { tmp := alpha * x[kx] c128.AxpyInc(tmp, y, a[i*lda:i*lda+n], uintptr(n), uintptr(incY), 1, uintptr(jy), 0) } kx += incX } } // Zhbmv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where alpha and beta are scalars, x and y are vectors, and A is an n×n // Hermitian band matrix with k super-diagonals. The imaginary parts of // the diagonal elements of A are ignored and assumed to be zero. func (Implementation) Zhbmv(uplo blas.Uplo, n, k int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up the start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { for i, v := range y[:n] { y[i] = beta * v } } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { for i := 0; i < n; i++ { y[iy] = beta * y[iy] iy += incY } } } } if alpha == 0 { return } // The elements of A are accessed sequentially with one pass through a. switch uplo { case blas.Upper: iy := ky if incX == 1 { for i := 0; i < n; i++ { aRow := a[i*lda:] alphaxi := alpha * x[i] sum := alphaxi * complex(real(aRow[0]), 0) u := min(k+1, n-i) jy := incY for j := 1; j < u; j++ { v := aRow[j] sum += alpha * x[i+j] * v y[iy+jy] += alphaxi * cmplx.Conj(v) jy += incY } y[iy] += sum iy += incY } } else { ix := kx for i := 0; i < n; i++ { aRow := a[i*lda:] alphaxi := alpha * x[ix] sum := alphaxi * complex(real(aRow[0]), 0) u := min(k+1, n-i) jx := incX jy := incY for j := 1; j < u; j++ { v := aRow[j] sum += alpha * x[ix+jx] * v y[iy+jy] += alphaxi * cmplx.Conj(v) jx += incX jy += incY } y[iy] += sum ix += incX iy += incY } } case blas.Lower: iy := ky if incX == 1 { for i := 0; i < n; i++ { l := max(0, k-i) alphaxi := alpha * x[i] jy := l * incY aRow := a[i*lda:] for j := l; j < k; j++ { v := aRow[j] y[iy] += alpha * v * x[i-k+j] y[iy-k*incY+jy] += alphaxi * cmplx.Conj(v) jy += incY } y[iy] += alphaxi * complex(real(aRow[k]), 0) iy += incY } } else { ix := kx for i := 0; i < n; i++ { l := max(0, k-i) alphaxi := alpha * x[ix] jx := l * incX jy := l * incY aRow := a[i*lda:] for j := l; j < k; j++ { v := aRow[j] y[iy] += alpha * v * x[ix-k*incX+jx] y[iy-k*incY+jy] += alphaxi * cmplx.Conj(v) jx += incX jy += incY } y[iy] += alphaxi * complex(real(aRow[k]), 0) ix += incX iy += incY } } } } // Zhemv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where alpha and beta are scalars, x and y are vectors, and A is an n×n // Hermitian matrix. The imaginary parts of the diagonal elements of A are // ignored and assumed to be zero. func (Implementation) Zhemv(uplo blas.Uplo, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up the start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { for i, v := range y[:n] { y[i] = beta * v } } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { for i := 0; i < n; i++ { y[iy] = beta * y[iy] iy += incY } } } } if alpha == 0 { return } // The elements of A are accessed sequentially with one pass through // the triangular part of A. if uplo == blas.Upper { // Form y when A is stored in upper triangle. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] var tmp2 complex128 for j := i + 1; j < n; j++ { y[j] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[j] } aii := complex(real(a[i*lda+i]), 0) y[i] += tmp1*aii + alpha*tmp2 } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] var tmp2 complex128 jx := ix jy := iy for j := i + 1; j < n; j++ { jx += incX jy += incY y[jy] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[jx] } aii := complex(real(a[i*lda+i]), 0) y[iy] += tmp1*aii + alpha*tmp2 ix += incX iy += incY } } return } // Form y when A is stored in lower triangle. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] var tmp2 complex128 for j := 0; j < i; j++ { y[j] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[j] } aii := complex(real(a[i*lda+i]), 0) y[i] += tmp1*aii + alpha*tmp2 } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] var tmp2 complex128 jx := kx jy := ky for j := 0; j < i; j++ { y[jy] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[jx] jx += incX jy += incY } aii := complex(real(a[i*lda+i]), 0) y[iy] += tmp1*aii + alpha*tmp2 ix += incX iy += incY } } } // Zher performs the Hermitian rank-one operation // // A += alpha * x * xᴴ // // where A is an n×n Hermitian matrix, alpha is a real scalar, and x is an n // element vector. On entry, the imaginary parts of the diagonal elements of A // are ignored and assumed to be zero, on return they will be set to zero. func (Implementation) Zher(uplo blas.Uplo, n int, alpha float64, x []complex128, incX int, a []complex128, lda int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx int if incX < 0 { kx = (1 - n) * incX } if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if x[i] != 0 { tmp := complex(alpha*real(x[i]), alpha*imag(x[i])) aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[i])) a[i*lda+i] = complex(aii+xtmp, 0) for j := i + 1; j < n; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[j]) } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } ix := kx for i := 0; i < n; i++ { if x[ix] != 0 { tmp := complex(alpha*real(x[ix]), alpha*imag(x[ix])) aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii+xtmp, 0) jx := ix + incX for j := i + 1; j < n; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[jx]) jx += incX } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX } return } if incX == 1 { for i := 0; i < n; i++ { if x[i] != 0 { tmp := complex(alpha*real(x[i]), alpha*imag(x[i])) for j := 0; j < i; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[j]) } aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[i])) a[i*lda+i] = complex(aii+xtmp, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } ix := kx for i := 0; i < n; i++ { if x[ix] != 0 { tmp := complex(alpha*real(x[ix]), alpha*imag(x[ix])) jx := kx for j := 0; j < i; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[jx]) jx += incX } aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii+xtmp, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX } } // Zher2 performs the Hermitian rank-two operation // // A += alpha * x * yᴴ + conj(alpha) * y * xᴴ // // where alpha is a scalar, x and y are n element vectors and A is an n×n // Hermitian matrix. On entry, the imaginary parts of the diagonal elements are // ignored and assumed to be zero. On return they will be set to zero. func (Implementation) Zher2(uplo blas.Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx, ky int var ix, iy int if incX != 1 || incY != 1 { if incX < 0 { kx = (1 - n) * incX } if incY < 0 { ky = (1 - n) * incY } ix = kx iy = ky } if uplo == blas.Upper { if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) a[i*lda+i] = complex(aii, 0) for j := i + 1; j < n; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii, 0) jx := ix + incX jy := iy + incY for j := i + 1; j < n; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX iy += incY } return } if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] for j := 0; j < i; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) } aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) a[i*lda+i] = complex(aii, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] jx := kx jy := ky for j := 0; j < i; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX iy += incY } } // Zhpmv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where alpha and beta are scalars, x and y are vectors, and A is an n×n // Hermitian matrix in packed form. The imaginary parts of the diagonal // elements of A are ignored and assumed to be zero. func (Implementation) Zhpmv(uplo blas.Uplo, n int, alpha complex128, ap []complex128, x []complex128, incX int, beta complex128, y []complex128, incY int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up the start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { for i, v := range y[:n] { y[i] = beta * v } } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { for i := 0; i < n; i++ { y[iy] *= beta iy += incY } } } } if alpha == 0 { return } // The elements of A are accessed sequentially with one pass through ap. var kk int if uplo == blas.Upper { // Form y when ap contains the upper triangle. // Here, kk points to the current diagonal element in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] y[i] += tmp1 * complex(real(ap[kk]), 0) var tmp2 complex128 k := kk + 1 for j := i + 1; j < n; j++ { y[j] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[j] k++ } y[i] += alpha * tmp2 kk += n - i } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] y[iy] += tmp1 * complex(real(ap[kk]), 0) var tmp2 complex128 jx := ix jy := iy for k := kk + 1; k < kk+n-i; k++ { jx += incX jy += incY y[jy] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[jx] } y[iy] += alpha * tmp2 ix += incX iy += incY kk += n - i } } return } // Form y when ap contains the lower triangle. // Here, kk points to the beginning of current row in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] var tmp2 complex128 k := kk for j := 0; j < i; j++ { y[j] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[j] k++ } aii := complex(real(ap[kk+i]), 0) y[i] += tmp1*aii + alpha*tmp2 kk += i + 1 } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] var tmp2 complex128 jx := kx jy := ky for k := kk; k < kk+i; k++ { y[jy] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[jx] jx += incX jy += incY } aii := complex(real(ap[kk+i]), 0) y[iy] += tmp1*aii + alpha*tmp2 ix += incX iy += incY kk += i + 1 } } } // Zhpr performs the Hermitian rank-1 operation // // A += alpha * x * xᴴ // // where alpha is a real scalar, x is a vector, and A is an n×n hermitian matrix // in packed form. On entry, the imaginary parts of the diagonal elements are // assumed to be zero, and on return they are set to zero. func (Implementation) Zhpr(uplo blas.Uplo, n int, alpha float64, x []complex128, incX int, ap []complex128) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through ap. var kk int if uplo == blas.Upper { // Form A when upper triangle is stored in AP. // Here, kk points to the current diagonal element in ap. if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if xi != 0 { aii := real(ap[kk]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk] = complex(aii, 0) tmp := complex(alpha, 0) * xi a := ap[kk+1 : kk+n-i] x := x[i+1 : n] for j, v := range x { a[j] += tmp * cmplx.Conj(v) } } else { ap[kk] = complex(real(ap[kk]), 0) } kk += n - i } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] if xi != 0 { aii := real(ap[kk]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk] = complex(aii, 0) tmp := complex(alpha, 0) * xi jx := ix + incX a := ap[kk+1 : kk+n-i] for k := range a { a[k] += tmp * cmplx.Conj(x[jx]) jx += incX } } else { ap[kk] = complex(real(ap[kk]), 0) } ix += incX kk += n - i } } return } // Form A when lower triangle is stored in AP. // Here, kk points to the beginning of current row in ap. if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if xi != 0 { tmp := complex(alpha, 0) * xi a := ap[kk : kk+i] for j, v := range x[:i] { a[j] += tmp * cmplx.Conj(v) } aii := real(ap[kk+i]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] if xi != 0 { tmp := complex(alpha, 0) * xi a := ap[kk : kk+i] jx := kx for k := range a { a[k] += tmp * cmplx.Conj(x[jx]) jx += incX } aii := real(ap[kk+i]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } ix += incX kk += i + 1 } } } // Zhpr2 performs the Hermitian rank-2 operation // // A += alpha * x * yᴴ + conj(alpha) * y * xᴴ // // where alpha is a complex scalar, x and y are n element vectors, and A is an // n×n Hermitian matrix, supplied in packed form. On entry, the imaginary parts // of the diagonal elements are assumed to be zero, and on return they are set to zero. func (Implementation) Zhpr2(uplo blas.Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, ap []complex128) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } // Set up start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // The elements of A are accessed sequentially with one pass through ap. var kk int if uplo == blas.Upper { // Form A when upper triangle is stored in AP. // Here, kk points to the current diagonal element in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] aii := real(ap[kk]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) ap[kk] = complex(aii, 0) k := kk + 1 for j := i + 1; j < n; j++ { ap[k] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) k++ } } else { ap[kk] = complex(real(ap[kk]), 0) } kk += n - i } } else { ix := kx iy := ky for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] aii := real(ap[kk]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) ap[kk] = complex(aii, 0) jx := ix + incX jy := iy + incY for k := kk + 1; k < kk+n-i; k++ { ap[k] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } } else { ap[kk] = complex(real(ap[kk]), 0) } ix += incX iy += incY kk += n - i } } return } // Form A when lower triangle is stored in AP. // Here, kk points to the beginning of current row in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] k := kk for j := 0; j < i; j++ { ap[k] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) k++ } aii := real(ap[kk+i]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } kk += i + 1 } } else { ix := kx iy := ky for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] jx := kx jy := ky for k := kk; k < kk+i; k++ { ap[k] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } aii := real(ap[kk+i]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } ix += incX iy += incY kk += i + 1 } } } // Ztbmv performs one of the matrix-vector operations // // x = A * x if trans = blas.NoTrans // x = Aᵀ * x if trans = blas.Trans // x = Aᴴ * x if trans = blas.ConjTrans // // where x is an n element vector and A is an n×n triangular band matrix, with // (k+1) diagonals. func (Implementation) Ztbmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k int, a []complex128, lda int, x []complex128, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } switch trans { case blas.NoTrans: if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if diag == blas.NonUnit { xi *= a[i*lda] } kk := min(k, n-i-1) for j, aij := range a[i*lda+1 : i*lda+kk+1] { xi += x[i+j+1] * aij } x[i] = xi } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] if diag == blas.NonUnit { xi *= a[i*lda] } kk := min(k, n-i-1) jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { xi += x[jx] * aij jx += incX } x[ix] = xi ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { xi *= a[i*lda+k] } kk := min(k, i) for j, aij := range a[i*lda+k-kk : i*lda+k] { xi += x[i-kk+j] * aij } x[i] = xi } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { xi *= a[i*lda+k] } kk := min(k, i) jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { xi += x[jx] * aij jx += incX } x[ix] = xi ix -= incX } } } case blas.Trans: if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+j+1] += xi * aij } if diag == blas.NonUnit { x[i] *= a[i*lda] } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) jx := ix + incX xi := x[ix] for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] += xi * aij jx += incX } if diag == blas.NonUnit { x[ix] *= a[i*lda] } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] += xi * aij } if diag == blas.NonUnit { x[i] *= a[i*lda+k] } } } else { ix := kx for i := 0; i < n; i++ { kk := min(k, i) jx := ix - kk*incX xi := x[ix] for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] += xi * aij jx += incX } if diag == blas.NonUnit { x[ix] *= a[i*lda+k] } ix += incX } } } case blas.ConjTrans: if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+j+1] += xi * cmplx.Conj(aij) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) jx := ix + incX xi := x[ix] for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] += xi * cmplx.Conj(aij) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda]) } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] += xi * cmplx.Conj(aij) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda+k]) } } } else { ix := kx for i := 0; i < n; i++ { kk := min(k, i) jx := ix - kk*incX xi := x[ix] for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] += xi * cmplx.Conj(aij) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda+k]) } ix += incX } } } } } // Ztbsv solves one of the systems of equations // // A * x = b if trans == blas.NoTrans // Aᵀ * x = b if trans == blas.Trans // Aᴴ * x = b if trans == blas.ConjTrans // // where b and x are n element vectors and A is an n×n triangular band matrix // with (k+1) diagonals. // // On entry, x contains the values of b, and the solution 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 (Implementation) Ztbsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k int, a []complex128, lda int, x []complex128, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } switch trans { case blas.NoTrans: if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) var sum complex128 for j, aij := range a[i*lda+1 : i*lda+kk+1] { sum += x[i+1+j] * aij } x[i] -= sum if diag == blas.NonUnit { x[i] /= a[i*lda] } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) var sum complex128 jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { sum += x[jx] * aij jx += incX } x[ix] -= sum if diag == blas.NonUnit { x[ix] /= a[i*lda] } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { kk := min(k, i) var sum complex128 for j, aij := range a[i*lda+k-kk : i*lda+k] { sum += x[i-kk+j] * aij } x[i] -= sum if diag == blas.NonUnit { x[i] /= a[i*lda+k] } } } else { ix := kx for i := 0; i < n; i++ { kk := min(k, i) var sum complex128 jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { sum += x[jx] * aij jx += incX } x[ix] -= sum if diag == blas.NonUnit { x[ix] /= a[i*lda+k] } ix += incX } } } case blas.Trans: if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if diag == blas.NonUnit { x[i] /= a[i*lda] } kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+1+j] -= xi * aij } } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] /= a[i*lda] } kk := min(k, n-i-1) xi := x[ix] jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] -= xi * aij jx += incX } ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] /= a[i*lda+k] } kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] -= xi * aij } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] /= a[i*lda+k] } kk := min(k, i) xi := x[ix] jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] -= xi * aij jx += incX } ix -= incX } } } case blas.ConjTrans: if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if diag == blas.NonUnit { x[i] /= cmplx.Conj(a[i*lda]) } kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+1+j] -= xi * cmplx.Conj(aij) } } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] /= cmplx.Conj(a[i*lda]) } kk := min(k, n-i-1) xi := x[ix] jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] -= xi * cmplx.Conj(aij) jx += incX } ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] /= cmplx.Conj(a[i*lda+k]) } kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] -= xi * cmplx.Conj(aij) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] /= cmplx.Conj(a[i*lda+k]) } kk := min(k, i) xi := x[ix] jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] -= xi * cmplx.Conj(aij) jx += incX } ix -= incX } } } } } // Ztpmv performs one of the matrix-vector operations // // x = A * x if trans = blas.NoTrans // x = Aᵀ * x if trans = blas.Trans // x = Aᴴ * x if trans = blas.ConjTrans // // where x is an n element vector and A is an n×n triangular matrix, supplied in // packed form. func (Implementation) Ztpmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, ap []complex128, x []complex128, incX int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through A. if trans == blas.NoTrans { // Form x = A*x. if uplo == blas.Upper { // kk points to the current diagonal element in ap. kk := 0 if incX == 1 { x = x[:n] for i := range x { if diag == blas.NonUnit { x[i] *= ap[kk] } if n-i-1 > 0 { x[i] += c128.DotuUnitary(ap[kk+1:kk+n-i], x[i+1:]) } kk += n - i } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] *= ap[kk] } if n-i-1 > 0 { x[ix] += c128.DotuInc(ap[kk+1:kk+n-i], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix += incX kk += n - i } } } else { // kk points to the beginning of current row in ap. kk := n*(n+1)/2 - n if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] *= ap[kk+i] } if i > 0 { x[i] += c128.DotuUnitary(ap[kk:kk+i], x[:i]) } kk -= i } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] *= ap[kk+i] } if i > 0 { x[ix] += c128.DotuInc(ap[kk:kk+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } ix -= incX kk -= i } } } return } if trans == blas.Trans { // Form x = Aᵀ*x. if uplo == blas.Upper { // kk points to the current diagonal element in ap. kk := n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= ap[kk] } if n-i-1 > 0 { c128.AxpyUnitary(xi, ap[kk+1:kk+n-i], x[i+1:n]) } kk -= n - i + 1 } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= ap[kk] } if n-i-1 > 0 { c128.AxpyInc(xi, ap[kk+1:kk+n-i], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix -= incX kk -= n - i + 1 } } } else { // kk points to the beginning of current row in ap. kk := 0 if incX == 1 { x = x[:n] for i := range x { if i > 0 { c128.AxpyUnitary(x[i], ap[kk:kk+i], x[:i]) } if diag == blas.NonUnit { x[i] *= ap[kk+i] } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { c128.AxpyInc(x[ix], ap[kk:kk+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } if diag == blas.NonUnit { x[ix] *= ap[kk+i] } ix += incX kk += i + 1 } } } return } // Form x = Aᴴ*x. if uplo == blas.Upper { // kk points to the current diagonal element in ap. kk := n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= cmplx.Conj(ap[kk]) } k := kk + 1 for j := i + 1; j < n; j++ { x[j] += xi * cmplx.Conj(ap[k]) k++ } kk -= n - i + 1 } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= cmplx.Conj(ap[kk]) } jx := ix + incX k := kk + 1 for j := i + 1; j < n; j++ { x[jx] += xi * cmplx.Conj(ap[k]) jx += incX k++ } ix -= incX kk -= n - i + 1 } } } else { // kk points to the beginning of current row in ap. kk := 0 if incX == 1 { x = x[:n] for i, xi := range x { for j := 0; j < i; j++ { x[j] += xi * cmplx.Conj(ap[kk+j]) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(ap[kk+i]) } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] jx := kx for j := 0; j < i; j++ { x[jx] += xi * cmplx.Conj(ap[kk+j]) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(ap[kk+i]) } ix += incX kk += i + 1 } } } } // Ztpsv solves one of the systems of equations // // A * x = b if trans == blas.NoTrans // Aᵀ * x = b if trans == blas.Trans // Aᴴ * x = b if trans == blas.ConjTrans // // where b and x are n element vectors and A is an n×n triangular matrix in // packed form. // // On entry, x contains the values of b, and the solution 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 (Implementation) Ztpsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, ap []complex128, x []complex128, incX int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through ap. if trans == blas.NoTrans { // Form x = inv(A)*x. if uplo == blas.Upper { kk := n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { aii := ap[kk] if n-i-1 > 0 { x[i] -= c128.DotuUnitary(x[i+1:n], ap[kk+1:kk+n-i]) } if diag == blas.NonUnit { x[i] /= aii } kk -= n - i + 1 } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { aii := ap[kk] if n-i-1 > 0 { x[ix] -= c128.DotuInc(x, ap[kk+1:kk+n-i], uintptr(n-i-1), uintptr(incX), 1, uintptr(ix+incX), 0) } if diag == blas.NonUnit { x[ix] /= aii } ix -= incX kk -= n - i + 1 } } } else { kk := 0 if incX == 1 { for i := 0; i < n; i++ { if i > 0 { x[i] -= c128.DotuUnitary(x[:i], ap[kk:kk+i]) } if diag == blas.NonUnit { x[i] /= ap[kk+i] } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { x[ix] -= c128.DotuInc(x, ap[kk:kk+i], uintptr(i), uintptr(incX), 1, uintptr(kx), 0) } if diag == blas.NonUnit { x[ix] /= ap[kk+i] } ix += incX kk += i + 1 } } } return } if trans == blas.Trans { // Form x = inv(Aᵀ)*x. if uplo == blas.Upper { kk := 0 if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= ap[kk] } if n-j-1 > 0 { c128.AxpyUnitary(-x[j], ap[kk+1:kk+n-j], x[j+1:n]) } kk += n - j } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= ap[kk] } if n-j-1 > 0 { c128.AxpyInc(-x[jx], ap[kk+1:kk+n-j], x, uintptr(n-j-1), 1, uintptr(incX), 0, uintptr(jx+incX)) } jx += incX kk += n - j } } } else { kk := n*(n+1)/2 - n if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= ap[kk+j] } if j > 0 { c128.AxpyUnitary(-x[j], ap[kk:kk+j], x[:j]) } kk -= j } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= ap[kk+j] } if j > 0 { c128.AxpyInc(-x[jx], ap[kk:kk+j], x, uintptr(j), 1, uintptr(incX), 0, uintptr(kx)) } jx -= incX kk -= j } } } return } // Form x = inv(Aᴴ)*x. if uplo == blas.Upper { kk := 0 if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= cmplx.Conj(ap[kk]) } xj := x[j] k := kk + 1 for i := j + 1; i < n; i++ { x[i] -= xj * cmplx.Conj(ap[k]) k++ } kk += n - j } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(ap[kk]) } xj := x[jx] ix := jx + incX k := kk + 1 for i := j + 1; i < n; i++ { x[ix] -= xj * cmplx.Conj(ap[k]) ix += incX k++ } jx += incX kk += n - j } } } else { kk := n*(n+1)/2 - n if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= cmplx.Conj(ap[kk+j]) } xj := x[j] for i := 0; i < j; i++ { x[i] -= xj * cmplx.Conj(ap[kk+i]) } kk -= j } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(ap[kk+j]) } xj := x[jx] ix := kx for i := 0; i < j; i++ { x[ix] -= xj * cmplx.Conj(ap[kk+i]) ix += incX } jx -= incX kk -= j } } } } // Ztrmv performs one of the matrix-vector operations // // x = A * x if trans = blas.NoTrans // x = Aᵀ * x if trans = blas.Trans // x = Aᴴ * x if trans = blas.ConjTrans // // where x is a vector, and A is an n×n triangular matrix. func (Implementation) Ztrmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []complex128, lda int, x []complex128, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through A. if trans == blas.NoTrans { // Form x = A*x. if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if diag == blas.NonUnit { x[i] *= a[i*lda+i] } if n-i-1 > 0 { x[i] += c128.DotuUnitary(a[i*lda+i+1:i*lda+n], x[i+1:n]) } } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } if n-i-1 > 0 { x[ix] += c128.DotuInc(a[i*lda+i+1:i*lda+n], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] *= a[i*lda+i] } if i > 0 { x[i] += c128.DotuUnitary(a[i*lda:i*lda+i], x[:i]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } if i > 0 { x[ix] += c128.DotuInc(a[i*lda:i*lda+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } ix -= incX } } } return } if trans == blas.Trans { // Form x = Aᵀ*x. if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= a[i*lda+i] } if n-i-1 > 0 { c128.AxpyUnitary(xi, a[i*lda+i+1:i*lda+n], x[i+1:n]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } if n-i-1 > 0 { c128.AxpyInc(xi, a[i*lda+i+1:i*lda+n], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { if i > 0 { c128.AxpyUnitary(x[i], a[i*lda:i*lda+i], x[:i]) } if diag == blas.NonUnit { x[i] *= a[i*lda+i] } } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { c128.AxpyInc(x[ix], a[i*lda:i*lda+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } ix += incX } } } return } // Form x = Aᴴ*x. if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda+i]) } for j := i + 1; j < n; j++ { x[j] += xi * cmplx.Conj(a[i*lda+j]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda+i]) } jx := ix + incX for j := i + 1; j < n; j++ { x[jx] += xi * cmplx.Conj(a[i*lda+j]) jx += incX } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { for j := 0; j < i; j++ { x[j] += x[i] * cmplx.Conj(a[i*lda+j]) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda+i]) } } } else { ix := kx for i := 0; i < n; i++ { jx := kx for j := 0; j < i; j++ { x[jx] += x[ix] * cmplx.Conj(a[i*lda+j]) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda+i]) } ix += incX } } } } // Ztrsv solves one of the systems of equations // // A * x = b if trans == blas.NoTrans // Aᵀ * x = b if trans == blas.Trans // Aᴴ * x = b if trans == blas.ConjTrans // // where b and x are n element vectors and A is an n×n triangular matrix. // // On entry, x contains the values of b, and the solution 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 (Implementation) Ztrsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []complex128, lda int, x []complex128, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through A. if trans == blas.NoTrans { // Form x = inv(A)*x. if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { aii := a[i*lda+i] if n-i-1 > 0 { x[i] -= c128.DotuUnitary(x[i+1:n], a[i*lda+i+1:i*lda+n]) } if diag == blas.NonUnit { x[i] /= aii } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { aii := a[i*lda+i] if n-i-1 > 0 { x[ix] -= c128.DotuInc(x, a[i*lda+i+1:i*lda+n], uintptr(n-i-1), uintptr(incX), 1, uintptr(ix+incX), 0) } if diag == blas.NonUnit { x[ix] /= aii } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { if i > 0 { x[i] -= c128.DotuUnitary(x[:i], a[i*lda:i*lda+i]) } if diag == blas.NonUnit { x[i] /= a[i*lda+i] } } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { x[ix] -= c128.DotuInc(x, a[i*lda:i*lda+i], uintptr(i), uintptr(incX), 1, uintptr(kx), 0) } if diag == blas.NonUnit { x[ix] /= a[i*lda+i] } ix += incX } } } return } if trans == blas.Trans { // Form x = inv(Aᵀ)*x. if uplo == blas.Upper { if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= a[j*lda+j] } if n-j-1 > 0 { c128.AxpyUnitary(-x[j], a[j*lda+j+1:j*lda+n], x[j+1:n]) } } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= a[j*lda+j] } if n-j-1 > 0 { c128.AxpyInc(-x[jx], a[j*lda+j+1:j*lda+n], x, uintptr(n-j-1), 1, uintptr(incX), 0, uintptr(jx+incX)) } jx += incX } } } else { if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= a[j*lda+j] } xj := x[j] if j > 0 { c128.AxpyUnitary(-xj, a[j*lda:j*lda+j], x[:j]) } } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= a[j*lda+j] } if j > 0 { c128.AxpyInc(-x[jx], a[j*lda:j*lda+j], x, uintptr(j), 1, uintptr(incX), 0, uintptr(kx)) } jx -= incX } } } return } // Form x = inv(Aᴴ)*x. if uplo == blas.Upper { if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= cmplx.Conj(a[j*lda+j]) } xj := x[j] for i := j + 1; i < n; i++ { x[i] -= xj * cmplx.Conj(a[j*lda+i]) } } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(a[j*lda+j]) } xj := x[jx] ix := jx + incX for i := j + 1; i < n; i++ { x[ix] -= xj * cmplx.Conj(a[j*lda+i]) ix += incX } jx += incX } } } else { if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= cmplx.Conj(a[j*lda+j]) } xj := x[j] for i := 0; i < j; i++ { x[i] -= xj * cmplx.Conj(a[j*lda+i]) } } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(a[j*lda+j]) } xj := x[jx] ix := kx for i := 0; i < j; i++ { x[ix] -= xj * cmplx.Conj(a[j*lda+i]) ix += incX } jx -= incX } } } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level2cmplx128_bench_test.go000066400000000000000000000022241450372207100251210ustar00rootroot00000000000000// 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 ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) var benchSinkZ []complex128 func BenchmarkZher(b *testing.B) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, n := range []int{10, 100, 1000, 10000} { for _, inc := range []int{1, 10, 1000} { benchmarkZher(b, uplo, n, inc) } } } } func benchmarkZher(b *testing.B, uplo blas.Uplo, n, inc int) { b.Run(fmt.Sprintf("Uplo%d-N%d-Inc%d", uplo, n, inc), func(b *testing.B) { rnd := rand.New(rand.NewSource(1)) alpha := rnd.NormFloat64() x := make([]complex128, (n-1)*inc+1) for i := range x { x[i] = complex(rnd.NormFloat64(), rnd.NormFloat64()) } a := make([]complex128, len(benchSinkZ)) for i := range a { a[i] = complex(rnd.NormFloat64(), rnd.NormFloat64()) } benchSinkZ = make([]complex128, n*n) copy(benchSinkZ, a) b.ResetTimer() for i := 0; i < b.N; i++ { impl.Zher(uplo, n, alpha, x, inc, benchSinkZ, n) copy(benchSinkZ, a) } }) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level2cmplx128_test.go000066400000000000000000000024321450372207100237630ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func TestZgbmv(t *testing.T) { testblas.ZgbmvTest(t, impl) } func TestZgemv(t *testing.T) { testblas.ZgemvTest(t, impl) } func TestZgerc(t *testing.T) { testblas.ZgercTest(t, impl) } func TestZgeru(t *testing.T) { testblas.ZgeruTest(t, impl) } func TestZhbmv(t *testing.T) { testblas.ZhbmvTest(t, impl) } func TestZhemv(t *testing.T) { testblas.ZhemvTest(t, impl) } func TestZher(t *testing.T) { testblas.ZherTest(t, impl) } func TestZher2(t *testing.T) { testblas.Zher2Test(t, impl) } func TestZhpmv(t *testing.T) { testblas.ZhpmvTest(t, impl) } func TestZhpr(t *testing.T) { testblas.ZhprTest(t, impl) } func TestZhpr2(t *testing.T) { testblas.Zhpr2Test(t, impl) } func TestZtbmv(t *testing.T) { testblas.ZtbmvTest(t, impl) } func TestZtbsv(t *testing.T) { testblas.ZtbsvTest(t, impl) } func TestZtpmv(t *testing.T) { testblas.ZtpmvTest(t, impl) } func TestZtpsv(t *testing.T) { testblas.ZtpsvTest(t, impl) } func TestZtrmv(t *testing.T) { testblas.ZtrmvTest(t, impl) } func TestZtrsv(t *testing.T) { testblas.ZtrsvTest(t, impl) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level2cmplx64.go000066400000000000000000001732631450372207100226560ustar00rootroot00000000000000// 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 ( cmplx "gonum.org/v1/gonum/internal/cmplx64" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/internal/asm/c64" ) var _ blas.Complex64Level2 = Implementation{} // Cgbmv performs one of the matrix-vector operations // // y = alpha * A * x + beta * y if trans = blas.NoTrans // y = alpha * Aᵀ * x + beta * y if trans = blas.Trans // y = alpha * Aᴴ * x + beta * y if trans = blas.ConjTrans // // where alpha and beta are scalars, x and y are vectors, and A is an m×n band matrix // with kL sub-diagonals and kU super-diagonals. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cgbmv(trans blas.Transpose, m, n, kL, kU int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } if m < 0 { panic(mLT0) } if n < 0 { panic(nLT0) } if kL < 0 { panic(kLLT0) } if kU < 0 { panic(kULT0) } if lda < kL+kU+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // 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*(min(m, n+kL)-1)+kL+kU+1 { panic(shortA) } var lenX, lenY int if trans == blas.NoTrans { lenX, lenY = n, m } else { lenX, lenY = m, n } if (incX > 0 && len(x) <= (lenX-1)*incX) || (incX < 0 && len(x) <= (1-lenX)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (lenY-1)*incY) || (incY < 0 && len(y) <= (1-lenY)*incY) { panic(shortY) } // Quick return if possible. if alpha == 0 && beta == 1 { return } var kx int if incX < 0 { kx = (1 - lenX) * incX } var ky int if incY < 0 { ky = (1 - lenY) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:lenY] { y[i] = 0 } } else { c64.ScalUnitary(beta, y[:lenY]) } } else { iy := ky if beta == 0 { for i := 0; i < lenY; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { c64.ScalInc(beta, y, uintptr(lenY), uintptr(incY)) } else { c64.ScalInc(beta, y, uintptr(lenY), uintptr(-incY)) } } } } nRow := min(m, n+kL) nCol := kL + 1 + kU switch trans { case blas.NoTrans: iy := ky if incX == 1 { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) xtmp := x[off : off+u-l] var sum complex64 for j, v := range aRow { sum += xtmp[j] * v } y[iy] += alpha * sum iy += incY } } else { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incX jx := kx var sum complex64 for _, v := range aRow { sum += x[off+jx] * v jx += incX } y[iy] += alpha * sum iy += incY } } case blas.Trans: if incX == 1 { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[i] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * v jy += incY } } } else { ix := kx for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[ix] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * v jy += incY } ix += incX } } case blas.ConjTrans: if incX == 1 { for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[i] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * cmplx.Conj(v) jy += incY } } } else { ix := kx for i := 0; i < nRow; i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) aRow := a[i*lda+l : i*lda+u] off := max(0, i-kL) * incY alphaxi := alpha * x[ix] jy := ky for _, v := range aRow { y[off+jy] += alphaxi * cmplx.Conj(v) jy += incY } ix += incX } } } } // Cgemv performs one of the matrix-vector operations // // y = alpha * A * x + beta * y if trans = blas.NoTrans // y = alpha * Aᵀ * x + beta * y if trans = blas.Trans // y = alpha * Aᴴ * x + beta * y if trans = blas.ConjTrans // // where alpha and beta are scalars, x and y are vectors, and A is an m×n dense matrix. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cgemv(trans blas.Transpose, m, n int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } 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 } // For zero matrix size the following slice length checks are trivially satisfied. var lenX, lenY int if trans == blas.NoTrans { lenX = n lenY = m } else { lenX = m lenY = n } if len(a) < lda*(m-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (lenX-1)*incX) || (incX < 0 && len(x) <= (1-lenX)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (lenY-1)*incY) || (incY < 0 && len(y) <= (1-lenY)*incY) { panic(shortY) } // Quick return if possible. if alpha == 0 && beta == 1 { return } var kx int if incX < 0 { kx = (1 - lenX) * incX } var ky int if incY < 0 { ky = (1 - lenY) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:lenY] { y[i] = 0 } } else { c64.ScalUnitary(beta, y[:lenY]) } } else { iy := ky if beta == 0 { for i := 0; i < lenY; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { c64.ScalInc(beta, y, uintptr(lenY), uintptr(incY)) } else { c64.ScalInc(beta, y, uintptr(lenY), uintptr(-incY)) } } } } if alpha == 0 { return } switch trans { default: // Form y = alpha*A*x + y. iy := ky if incX == 1 { for i := 0; i < m; i++ { y[iy] += alpha * c64.DotuUnitary(a[i*lda:i*lda+n], x[:n]) iy += incY } return } for i := 0; i < m; i++ { y[iy] += alpha * c64.DotuInc(a[i*lda:i*lda+n], x, uintptr(n), 1, uintptr(incX), 0, uintptr(kx)) iy += incY } return case blas.Trans: // Form y = alpha*Aᵀ*x + y. ix := kx if incY == 1 { for i := 0; i < m; i++ { c64.AxpyUnitary(alpha*x[ix], a[i*lda:i*lda+n], y[:n]) ix += incX } return } for i := 0; i < m; i++ { c64.AxpyInc(alpha*x[ix], a[i*lda:i*lda+n], y, uintptr(n), 1, uintptr(incY), 0, uintptr(ky)) ix += incX } return case blas.ConjTrans: // Form y = alpha*Aᴴ*x + y. ix := kx if incY == 1 { for i := 0; i < m; i++ { tmp := alpha * x[ix] for j := 0; j < n; j++ { y[j] += tmp * cmplx.Conj(a[i*lda+j]) } ix += incX } return } for i := 0; i < m; i++ { tmp := alpha * x[ix] jy := ky for j := 0; j < n; j++ { y[jy] += tmp * cmplx.Conj(a[i*lda+j]) jy += incY } ix += incX } return } } // Cgerc performs the rank-one operation // // A += alpha * x * yᴴ // // where A is an m×n dense matrix, alpha is a scalar, x is an m element vector, // and y is an n element vector. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cgerc(m, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, a []complex64, lda int) { 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 } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (m-1)*incX) || (incX < 0 && len(x) <= (1-m)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { panic(shortY) } if len(a) < lda*(m-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx, jy int if incX < 0 { kx = (1 - m) * incX } if incY < 0 { jy = (1 - n) * incY } for j := 0; j < n; j++ { if y[jy] != 0 { tmp := alpha * cmplx.Conj(y[jy]) c64.AxpyInc(tmp, x, a[j:], uintptr(m), uintptr(incX), uintptr(lda), uintptr(kx), 0) } jy += incY } } // Cgeru performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, alpha is a scalar, x is an m element vector, // and y is an n element vector. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cgeru(m, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, a []complex64, lda int) { 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 } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (m-1)*incX) || (incX < 0 && len(x) <= (1-m)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { panic(shortY) } if len(a) < lda*(m-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx int if incX < 0 { kx = (1 - m) * incX } if incY == 1 { for i := 0; i < m; i++ { if x[kx] != 0 { tmp := alpha * x[kx] c64.AxpyUnitary(tmp, y[:n], a[i*lda:i*lda+n]) } kx += incX } return } var jy int if incY < 0 { jy = (1 - n) * incY } for i := 0; i < m; i++ { if x[kx] != 0 { tmp := alpha * x[kx] c64.AxpyInc(tmp, y, a[i*lda:i*lda+n], uintptr(n), uintptr(incY), 1, uintptr(jy), 0) } kx += incX } } // Chbmv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where alpha and beta are scalars, x and y are vectors, and A is an n×n // Hermitian band matrix with k super-diagonals. The imaginary parts of // the diagonal elements of A are ignored and assumed to be zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Chbmv(uplo blas.Uplo, n, k int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up the start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { for i, v := range y[:n] { y[i] = beta * v } } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { for i := 0; i < n; i++ { y[iy] = beta * y[iy] iy += incY } } } } if alpha == 0 { return } // The elements of A are accessed sequentially with one pass through a. switch uplo { case blas.Upper: iy := ky if incX == 1 { for i := 0; i < n; i++ { aRow := a[i*lda:] alphaxi := alpha * x[i] sum := alphaxi * complex(real(aRow[0]), 0) u := min(k+1, n-i) jy := incY for j := 1; j < u; j++ { v := aRow[j] sum += alpha * x[i+j] * v y[iy+jy] += alphaxi * cmplx.Conj(v) jy += incY } y[iy] += sum iy += incY } } else { ix := kx for i := 0; i < n; i++ { aRow := a[i*lda:] alphaxi := alpha * x[ix] sum := alphaxi * complex(real(aRow[0]), 0) u := min(k+1, n-i) jx := incX jy := incY for j := 1; j < u; j++ { v := aRow[j] sum += alpha * x[ix+jx] * v y[iy+jy] += alphaxi * cmplx.Conj(v) jx += incX jy += incY } y[iy] += sum ix += incX iy += incY } } case blas.Lower: iy := ky if incX == 1 { for i := 0; i < n; i++ { l := max(0, k-i) alphaxi := alpha * x[i] jy := l * incY aRow := a[i*lda:] for j := l; j < k; j++ { v := aRow[j] y[iy] += alpha * v * x[i-k+j] y[iy-k*incY+jy] += alphaxi * cmplx.Conj(v) jy += incY } y[iy] += alphaxi * complex(real(aRow[k]), 0) iy += incY } } else { ix := kx for i := 0; i < n; i++ { l := max(0, k-i) alphaxi := alpha * x[ix] jx := l * incX jy := l * incY aRow := a[i*lda:] for j := l; j < k; j++ { v := aRow[j] y[iy] += alpha * v * x[ix-k*incX+jx] y[iy-k*incY+jy] += alphaxi * cmplx.Conj(v) jx += incX jy += incY } y[iy] += alphaxi * complex(real(aRow[k]), 0) ix += incX iy += incY } } } } // Chemv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where alpha and beta are scalars, x and y are vectors, and A is an n×n // Hermitian matrix. The imaginary parts of the diagonal elements of A are // ignored and assumed to be zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Chemv(uplo blas.Uplo, n int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up the start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { for i, v := range y[:n] { y[i] = beta * v } } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { for i := 0; i < n; i++ { y[iy] = beta * y[iy] iy += incY } } } } if alpha == 0 { return } // The elements of A are accessed sequentially with one pass through // the triangular part of A. if uplo == blas.Upper { // Form y when A is stored in upper triangle. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] var tmp2 complex64 for j := i + 1; j < n; j++ { y[j] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[j] } aii := complex(real(a[i*lda+i]), 0) y[i] += tmp1*aii + alpha*tmp2 } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] var tmp2 complex64 jx := ix jy := iy for j := i + 1; j < n; j++ { jx += incX jy += incY y[jy] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[jx] } aii := complex(real(a[i*lda+i]), 0) y[iy] += tmp1*aii + alpha*tmp2 ix += incX iy += incY } } return } // Form y when A is stored in lower triangle. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] var tmp2 complex64 for j := 0; j < i; j++ { y[j] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[j] } aii := complex(real(a[i*lda+i]), 0) y[i] += tmp1*aii + alpha*tmp2 } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] var tmp2 complex64 jx := kx jy := ky for j := 0; j < i; j++ { y[jy] += tmp1 * cmplx.Conj(a[i*lda+j]) tmp2 += a[i*lda+j] * x[jx] jx += incX jy += incY } aii := complex(real(a[i*lda+i]), 0) y[iy] += tmp1*aii + alpha*tmp2 ix += incX iy += incY } } } // Cher performs the Hermitian rank-one operation // // A += alpha * x * xᴴ // // where A is an n×n Hermitian matrix, alpha is a real scalar, and x is an n // element vector. On entry, the imaginary parts of the diagonal elements of A // are ignored and assumed to be zero, on return they will be set to zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cher(uplo blas.Uplo, n int, alpha float32, x []complex64, incX int, a []complex64, lda int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx int if incX < 0 { kx = (1 - n) * incX } if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if x[i] != 0 { tmp := complex(alpha*real(x[i]), alpha*imag(x[i])) aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[i])) a[i*lda+i] = complex(aii+xtmp, 0) for j := i + 1; j < n; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[j]) } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } ix := kx for i := 0; i < n; i++ { if x[ix] != 0 { tmp := complex(alpha*real(x[ix]), alpha*imag(x[ix])) aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii+xtmp, 0) jx := ix + incX for j := i + 1; j < n; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[jx]) jx += incX } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX } return } if incX == 1 { for i := 0; i < n; i++ { if x[i] != 0 { tmp := complex(alpha*real(x[i]), alpha*imag(x[i])) for j := 0; j < i; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[j]) } aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[i])) a[i*lda+i] = complex(aii+xtmp, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } ix := kx for i := 0; i < n; i++ { if x[ix] != 0 { tmp := complex(alpha*real(x[ix]), alpha*imag(x[ix])) jx := kx for j := 0; j < i; j++ { a[i*lda+j] += tmp * cmplx.Conj(x[jx]) jx += incX } aii := real(a[i*lda+i]) xtmp := real(tmp * cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii+xtmp, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX } } // Cher2 performs the Hermitian rank-two operation // // A += alpha * x * yᴴ + conj(alpha) * y * xᴴ // // where alpha is a scalar, x and y are n element vectors and A is an n×n // Hermitian matrix. On entry, the imaginary parts of the diagonal elements are // ignored and assumed to be zero. On return they will be set to zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cher2(uplo blas.Uplo, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, a []complex64, lda int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var kx, ky int var ix, iy int if incX != 1 || incY != 1 { if incX < 0 { kx = (1 - n) * incX } if incY < 0 { ky = (1 - n) * incY } ix = kx iy = ky } if uplo == blas.Upper { if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) a[i*lda+i] = complex(aii, 0) for j := i + 1; j < n; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii, 0) jx := ix + incX jy := iy + incY for j := i + 1; j < n; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX iy += incY } return } if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] for j := 0; j < i; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) } aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) a[i*lda+i] = complex(aii, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } } return } for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] jx := kx jy := ky for j := 0; j < i; j++ { a[i*lda+j] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } aii := real(a[i*lda+i]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) a[i*lda+i] = complex(aii, 0) } else { aii := real(a[i*lda+i]) a[i*lda+i] = complex(aii, 0) } ix += incX iy += incY } } // Chpmv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where alpha and beta are scalars, x and y are vectors, and A is an n×n // Hermitian matrix in packed form. The imaginary parts of the diagonal // elements of A are ignored and assumed to be zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Chpmv(uplo blas.Uplo, n int, alpha complex64, ap []complex64, x []complex64, incX int, beta complex64, y []complex64, incY int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up the start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // Form y = beta*y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { for i, v := range y[:n] { y[i] = beta * v } } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { for i := 0; i < n; i++ { y[iy] *= beta iy += incY } } } } if alpha == 0 { return } // The elements of A are accessed sequentially with one pass through ap. var kk int if uplo == blas.Upper { // Form y when ap contains the upper triangle. // Here, kk points to the current diagonal element in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] y[i] += tmp1 * complex(real(ap[kk]), 0) var tmp2 complex64 k := kk + 1 for j := i + 1; j < n; j++ { y[j] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[j] k++ } y[i] += alpha * tmp2 kk += n - i } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] y[iy] += tmp1 * complex(real(ap[kk]), 0) var tmp2 complex64 jx := ix jy := iy for k := kk + 1; k < kk+n-i; k++ { jx += incX jy += incY y[jy] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[jx] } y[iy] += alpha * tmp2 ix += incX iy += incY kk += n - i } } return } // Form y when ap contains the lower triangle. // Here, kk points to the beginning of current row in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { tmp1 := alpha * x[i] var tmp2 complex64 k := kk for j := 0; j < i; j++ { y[j] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[j] k++ } aii := complex(real(ap[kk+i]), 0) y[i] += tmp1*aii + alpha*tmp2 kk += i + 1 } } else { ix := kx iy := ky for i := 0; i < n; i++ { tmp1 := alpha * x[ix] var tmp2 complex64 jx := kx jy := ky for k := kk; k < kk+i; k++ { y[jy] += tmp1 * cmplx.Conj(ap[k]) tmp2 += ap[k] * x[jx] jx += incX jy += incY } aii := complex(real(ap[kk+i]), 0) y[iy] += tmp1*aii + alpha*tmp2 ix += incX iy += incY kk += i + 1 } } } // Chpr performs the Hermitian rank-1 operation // // A += alpha * x * xᴴ // // where alpha is a real scalar, x is a vector, and A is an n×n hermitian matrix // in packed form. On entry, the imaginary parts of the diagonal elements are // assumed to be zero, and on return they are set to zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Chpr(uplo blas.Uplo, n int, alpha float32, x []complex64, incX int, ap []complex64) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through ap. var kk int if uplo == blas.Upper { // Form A when upper triangle is stored in AP. // Here, kk points to the current diagonal element in ap. if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if xi != 0 { aii := real(ap[kk]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk] = complex(aii, 0) tmp := complex(alpha, 0) * xi a := ap[kk+1 : kk+n-i] x := x[i+1 : n] for j, v := range x { a[j] += tmp * cmplx.Conj(v) } } else { ap[kk] = complex(real(ap[kk]), 0) } kk += n - i } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] if xi != 0 { aii := real(ap[kk]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk] = complex(aii, 0) tmp := complex(alpha, 0) * xi jx := ix + incX a := ap[kk+1 : kk+n-i] for k := range a { a[k] += tmp * cmplx.Conj(x[jx]) jx += incX } } else { ap[kk] = complex(real(ap[kk]), 0) } ix += incX kk += n - i } } return } // Form A when lower triangle is stored in AP. // Here, kk points to the beginning of current row in ap. if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if xi != 0 { tmp := complex(alpha, 0) * xi a := ap[kk : kk+i] for j, v := range x[:i] { a[j] += tmp * cmplx.Conj(v) } aii := real(ap[kk+i]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] if xi != 0 { tmp := complex(alpha, 0) * xi a := ap[kk : kk+i] jx := kx for k := range a { a[k] += tmp * cmplx.Conj(x[jx]) jx += incX } aii := real(ap[kk+i]) + alpha*real(cmplx.Conj(xi)*xi) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } ix += incX kk += i + 1 } } } // Chpr2 performs the Hermitian rank-2 operation // // A += alpha * x * yᴴ + conj(alpha) * y * xᴴ // // where alpha is a complex scalar, x and y are n element vectors, and A is an // n×n Hermitian matrix, supplied in packed form. On entry, the imaginary parts // of the diagonal elements are assumed to be zero, and on return they are set to zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Chpr2(uplo blas.Uplo, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, ap []complex64) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } // Set up start indices in X and Y. var kx int if incX < 0 { kx = (1 - n) * incX } var ky int if incY < 0 { ky = (1 - n) * incY } // The elements of A are accessed sequentially with one pass through ap. var kk int if uplo == blas.Upper { // Form A when upper triangle is stored in AP. // Here, kk points to the current diagonal element in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] aii := real(ap[kk]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) ap[kk] = complex(aii, 0) k := kk + 1 for j := i + 1; j < n; j++ { ap[k] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) k++ } } else { ap[kk] = complex(real(ap[kk]), 0) } kk += n - i } } else { ix := kx iy := ky for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] aii := real(ap[kk]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) ap[kk] = complex(aii, 0) jx := ix + incX jy := iy + incY for k := kk + 1; k < kk+n-i; k++ { ap[k] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } } else { ap[kk] = complex(real(ap[kk]), 0) } ix += incX iy += incY kk += n - i } } return } // Form A when lower triangle is stored in AP. // Here, kk points to the beginning of current row in ap. if incX == 1 && incY == 1 { for i := 0; i < n; i++ { if x[i] != 0 || y[i] != 0 { tmp1 := alpha * x[i] tmp2 := cmplx.Conj(alpha) * y[i] k := kk for j := 0; j < i; j++ { ap[k] += tmp1*cmplx.Conj(y[j]) + tmp2*cmplx.Conj(x[j]) k++ } aii := real(ap[kk+i]) + real(tmp1*cmplx.Conj(y[i])) + real(tmp2*cmplx.Conj(x[i])) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } kk += i + 1 } } else { ix := kx iy := ky for i := 0; i < n; i++ { if x[ix] != 0 || y[iy] != 0 { tmp1 := alpha * x[ix] tmp2 := cmplx.Conj(alpha) * y[iy] jx := kx jy := ky for k := kk; k < kk+i; k++ { ap[k] += tmp1*cmplx.Conj(y[jy]) + tmp2*cmplx.Conj(x[jx]) jx += incX jy += incY } aii := real(ap[kk+i]) + real(tmp1*cmplx.Conj(y[iy])) + real(tmp2*cmplx.Conj(x[ix])) ap[kk+i] = complex(aii, 0) } else { ap[kk+i] = complex(real(ap[kk+i]), 0) } ix += incX iy += incY kk += i + 1 } } } // Ctbmv performs one of the matrix-vector operations // // x = A * x if trans = blas.NoTrans // x = Aᵀ * x if trans = blas.Trans // x = Aᴴ * x if trans = blas.ConjTrans // // where x is an n element vector and A is an n×n triangular band matrix, with // (k+1) diagonals. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctbmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k int, a []complex64, lda int, x []complex64, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } switch trans { case blas.NoTrans: if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if diag == blas.NonUnit { xi *= a[i*lda] } kk := min(k, n-i-1) for j, aij := range a[i*lda+1 : i*lda+kk+1] { xi += x[i+j+1] * aij } x[i] = xi } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] if diag == blas.NonUnit { xi *= a[i*lda] } kk := min(k, n-i-1) jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { xi += x[jx] * aij jx += incX } x[ix] = xi ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { xi *= a[i*lda+k] } kk := min(k, i) for j, aij := range a[i*lda+k-kk : i*lda+k] { xi += x[i-kk+j] * aij } x[i] = xi } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { xi *= a[i*lda+k] } kk := min(k, i) jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { xi += x[jx] * aij jx += incX } x[ix] = xi ix -= incX } } } case blas.Trans: if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+j+1] += xi * aij } if diag == blas.NonUnit { x[i] *= a[i*lda] } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) jx := ix + incX xi := x[ix] for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] += xi * aij jx += incX } if diag == blas.NonUnit { x[ix] *= a[i*lda] } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] += xi * aij } if diag == blas.NonUnit { x[i] *= a[i*lda+k] } } } else { ix := kx for i := 0; i < n; i++ { kk := min(k, i) jx := ix - kk*incX xi := x[ix] for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] += xi * aij jx += incX } if diag == blas.NonUnit { x[ix] *= a[i*lda+k] } ix += incX } } } case blas.ConjTrans: if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+j+1] += xi * cmplx.Conj(aij) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) jx := ix + incX xi := x[ix] for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] += xi * cmplx.Conj(aij) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda]) } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] += xi * cmplx.Conj(aij) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda+k]) } } } else { ix := kx for i := 0; i < n; i++ { kk := min(k, i) jx := ix - kk*incX xi := x[ix] for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] += xi * cmplx.Conj(aij) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda+k]) } ix += incX } } } } } // Ctbsv solves one of the systems of equations // // A * x = b if trans == blas.NoTrans // Aᵀ * x = b if trans == blas.Trans // Aᴴ * x = b if trans == blas.ConjTrans // // where b and x are n element vectors and A is an n×n triangular band matrix // with (k+1) diagonals. // // On entry, x contains the values of b, and the solution 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. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctbsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k int, a []complex64, lda int, x []complex64, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } switch trans { case blas.NoTrans: if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) var sum complex64 for j, aij := range a[i*lda+1 : i*lda+kk+1] { sum += x[i+1+j] * aij } x[i] -= sum if diag == blas.NonUnit { x[i] /= a[i*lda] } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { kk := min(k, n-i-1) var sum complex64 jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { sum += x[jx] * aij jx += incX } x[ix] -= sum if diag == blas.NonUnit { x[ix] /= a[i*lda] } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { kk := min(k, i) var sum complex64 for j, aij := range a[i*lda+k-kk : i*lda+k] { sum += x[i-kk+j] * aij } x[i] -= sum if diag == blas.NonUnit { x[i] /= a[i*lda+k] } } } else { ix := kx for i := 0; i < n; i++ { kk := min(k, i) var sum complex64 jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { sum += x[jx] * aij jx += incX } x[ix] -= sum if diag == blas.NonUnit { x[ix] /= a[i*lda+k] } ix += incX } } } case blas.Trans: if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if diag == blas.NonUnit { x[i] /= a[i*lda] } kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+1+j] -= xi * aij } } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] /= a[i*lda] } kk := min(k, n-i-1) xi := x[ix] jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] -= xi * aij jx += incX } ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] /= a[i*lda+k] } kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] -= xi * aij } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] /= a[i*lda+k] } kk := min(k, i) xi := x[ix] jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] -= xi * aij jx += incX } ix -= incX } } } case blas.ConjTrans: if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if diag == blas.NonUnit { x[i] /= cmplx.Conj(a[i*lda]) } kk := min(k, n-i-1) xi := x[i] for j, aij := range a[i*lda+1 : i*lda+kk+1] { x[i+1+j] -= xi * cmplx.Conj(aij) } } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] /= cmplx.Conj(a[i*lda]) } kk := min(k, n-i-1) xi := x[ix] jx := ix + incX for _, aij := range a[i*lda+1 : i*lda+kk+1] { x[jx] -= xi * cmplx.Conj(aij) jx += incX } ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] /= cmplx.Conj(a[i*lda+k]) } kk := min(k, i) xi := x[i] for j, aij := range a[i*lda+k-kk : i*lda+k] { x[i-kk+j] -= xi * cmplx.Conj(aij) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] /= cmplx.Conj(a[i*lda+k]) } kk := min(k, i) xi := x[ix] jx := ix - kk*incX for _, aij := range a[i*lda+k-kk : i*lda+k] { x[jx] -= xi * cmplx.Conj(aij) jx += incX } ix -= incX } } } } } // Ctpmv performs one of the matrix-vector operations // // x = A * x if trans = blas.NoTrans // x = Aᵀ * x if trans = blas.Trans // x = Aᴴ * x if trans = blas.ConjTrans // // where x is an n element vector and A is an n×n triangular matrix, supplied in // packed form. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctpmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, ap []complex64, x []complex64, incX int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through A. if trans == blas.NoTrans { // Form x = A*x. if uplo == blas.Upper { // kk points to the current diagonal element in ap. kk := 0 if incX == 1 { x = x[:n] for i := range x { if diag == blas.NonUnit { x[i] *= ap[kk] } if n-i-1 > 0 { x[i] += c64.DotuUnitary(ap[kk+1:kk+n-i], x[i+1:]) } kk += n - i } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] *= ap[kk] } if n-i-1 > 0 { x[ix] += c64.DotuInc(ap[kk+1:kk+n-i], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix += incX kk += n - i } } } else { // kk points to the beginning of current row in ap. kk := n*(n+1)/2 - n if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] *= ap[kk+i] } if i > 0 { x[i] += c64.DotuUnitary(ap[kk:kk+i], x[:i]) } kk -= i } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] *= ap[kk+i] } if i > 0 { x[ix] += c64.DotuInc(ap[kk:kk+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } ix -= incX kk -= i } } } return } if trans == blas.Trans { // Form x = Aᵀ*x. if uplo == blas.Upper { // kk points to the current diagonal element in ap. kk := n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= ap[kk] } if n-i-1 > 0 { c64.AxpyUnitary(xi, ap[kk+1:kk+n-i], x[i+1:n]) } kk -= n - i + 1 } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= ap[kk] } if n-i-1 > 0 { c64.AxpyInc(xi, ap[kk+1:kk+n-i], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix -= incX kk -= n - i + 1 } } } else { // kk points to the beginning of current row in ap. kk := 0 if incX == 1 { x = x[:n] for i := range x { if i > 0 { c64.AxpyUnitary(x[i], ap[kk:kk+i], x[:i]) } if diag == blas.NonUnit { x[i] *= ap[kk+i] } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { c64.AxpyInc(x[ix], ap[kk:kk+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } if diag == blas.NonUnit { x[ix] *= ap[kk+i] } ix += incX kk += i + 1 } } } return } // Form x = Aᴴ*x. if uplo == blas.Upper { // kk points to the current diagonal element in ap. kk := n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= cmplx.Conj(ap[kk]) } k := kk + 1 for j := i + 1; j < n; j++ { x[j] += xi * cmplx.Conj(ap[k]) k++ } kk -= n - i + 1 } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= cmplx.Conj(ap[kk]) } jx := ix + incX k := kk + 1 for j := i + 1; j < n; j++ { x[jx] += xi * cmplx.Conj(ap[k]) jx += incX k++ } ix -= incX kk -= n - i + 1 } } } else { // kk points to the beginning of current row in ap. kk := 0 if incX == 1 { x = x[:n] for i, xi := range x { for j := 0; j < i; j++ { x[j] += xi * cmplx.Conj(ap[kk+j]) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(ap[kk+i]) } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { xi := x[ix] jx := kx for j := 0; j < i; j++ { x[jx] += xi * cmplx.Conj(ap[kk+j]) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(ap[kk+i]) } ix += incX kk += i + 1 } } } } // Ctpsv solves one of the systems of equations // // A * x = b if trans == blas.NoTrans // Aᵀ * x = b if trans == blas.Trans // Aᴴ * x = b if trans == blas.ConjTrans // // where b and x are n element vectors and A is an n×n triangular matrix in // packed form. // // On entry, x contains the values of b, and the solution 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. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctpsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, ap []complex64, x []complex64, incX int) { switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through ap. if trans == blas.NoTrans { // Form x = inv(A)*x. if uplo == blas.Upper { kk := n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { aii := ap[kk] if n-i-1 > 0 { x[i] -= c64.DotuUnitary(x[i+1:n], ap[kk+1:kk+n-i]) } if diag == blas.NonUnit { x[i] /= aii } kk -= n - i + 1 } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { aii := ap[kk] if n-i-1 > 0 { x[ix] -= c64.DotuInc(x, ap[kk+1:kk+n-i], uintptr(n-i-1), uintptr(incX), 1, uintptr(ix+incX), 0) } if diag == blas.NonUnit { x[ix] /= aii } ix -= incX kk -= n - i + 1 } } } else { kk := 0 if incX == 1 { for i := 0; i < n; i++ { if i > 0 { x[i] -= c64.DotuUnitary(x[:i], ap[kk:kk+i]) } if diag == blas.NonUnit { x[i] /= ap[kk+i] } kk += i + 1 } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { x[ix] -= c64.DotuInc(x, ap[kk:kk+i], uintptr(i), uintptr(incX), 1, uintptr(kx), 0) } if diag == blas.NonUnit { x[ix] /= ap[kk+i] } ix += incX kk += i + 1 } } } return } if trans == blas.Trans { // Form x = inv(Aᵀ)*x. if uplo == blas.Upper { kk := 0 if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= ap[kk] } if n-j-1 > 0 { c64.AxpyUnitary(-x[j], ap[kk+1:kk+n-j], x[j+1:n]) } kk += n - j } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= ap[kk] } if n-j-1 > 0 { c64.AxpyInc(-x[jx], ap[kk+1:kk+n-j], x, uintptr(n-j-1), 1, uintptr(incX), 0, uintptr(jx+incX)) } jx += incX kk += n - j } } } else { kk := n*(n+1)/2 - n if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= ap[kk+j] } if j > 0 { c64.AxpyUnitary(-x[j], ap[kk:kk+j], x[:j]) } kk -= j } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= ap[kk+j] } if j > 0 { c64.AxpyInc(-x[jx], ap[kk:kk+j], x, uintptr(j), 1, uintptr(incX), 0, uintptr(kx)) } jx -= incX kk -= j } } } return } // Form x = inv(Aᴴ)*x. if uplo == blas.Upper { kk := 0 if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= cmplx.Conj(ap[kk]) } xj := x[j] k := kk + 1 for i := j + 1; i < n; i++ { x[i] -= xj * cmplx.Conj(ap[k]) k++ } kk += n - j } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(ap[kk]) } xj := x[jx] ix := jx + incX k := kk + 1 for i := j + 1; i < n; i++ { x[ix] -= xj * cmplx.Conj(ap[k]) ix += incX k++ } jx += incX kk += n - j } } } else { kk := n*(n+1)/2 - n if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= cmplx.Conj(ap[kk+j]) } xj := x[j] for i := 0; i < j; i++ { x[i] -= xj * cmplx.Conj(ap[kk+i]) } kk -= j } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(ap[kk+j]) } xj := x[jx] ix := kx for i := 0; i < j; i++ { x[ix] -= xj * cmplx.Conj(ap[kk+i]) ix += incX } jx -= incX kk -= j } } } } // Ctrmv performs one of the matrix-vector operations // // x = A * x if trans = blas.NoTrans // x = Aᵀ * x if trans = blas.Trans // x = Aᴴ * x if trans = blas.ConjTrans // // where x is a vector, and A is an n×n triangular matrix. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctrmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []complex64, lda int, x []complex64, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through A. if trans == blas.NoTrans { // Form x = A*x. if uplo == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if diag == blas.NonUnit { x[i] *= a[i*lda+i] } if n-i-1 > 0 { x[i] += c64.DotuUnitary(a[i*lda+i+1:i*lda+n], x[i+1:n]) } } } else { ix := kx for i := 0; i < n; i++ { if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } if n-i-1 > 0 { x[ix] += c64.DotuInc(a[i*lda+i+1:i*lda+n], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix += incX } } } else { if incX == 1 { for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[i] *= a[i*lda+i] } if i > 0 { x[i] += c64.DotuUnitary(a[i*lda:i*lda+i], x[:i]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } if i > 0 { x[ix] += c64.DotuInc(a[i*lda:i*lda+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } ix -= incX } } } return } if trans == blas.Trans { // Form x = Aᵀ*x. if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= a[i*lda+i] } if n-i-1 > 0 { c64.AxpyUnitary(xi, a[i*lda+i+1:i*lda+n], x[i+1:n]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } if n-i-1 > 0 { c64.AxpyInc(xi, a[i*lda+i+1:i*lda+n], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(ix+incX)) } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { if i > 0 { c64.AxpyUnitary(x[i], a[i*lda:i*lda+i], x[:i]) } if diag == blas.NonUnit { x[i] *= a[i*lda+i] } } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { c64.AxpyInc(x[ix], a[i*lda:i*lda+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) } if diag == blas.NonUnit { x[ix] *= a[i*lda+i] } ix += incX } } } return } // Form x = Aᴴ*x. if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { xi := x[i] if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda+i]) } for j := i + 1; j < n; j++ { x[j] += xi * cmplx.Conj(a[i*lda+j]) } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { xi := x[ix] if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda+i]) } jx := ix + incX for j := i + 1; j < n; j++ { x[jx] += xi * cmplx.Conj(a[i*lda+j]) jx += incX } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { for j := 0; j < i; j++ { x[j] += x[i] * cmplx.Conj(a[i*lda+j]) } if diag == blas.NonUnit { x[i] *= cmplx.Conj(a[i*lda+i]) } } } else { ix := kx for i := 0; i < n; i++ { jx := kx for j := 0; j < i; j++ { x[jx] += x[ix] * cmplx.Conj(a[i*lda+j]) jx += incX } if diag == blas.NonUnit { x[ix] *= cmplx.Conj(a[i*lda+i]) } ix += incX } } } } // Ctrsv solves one of the systems of equations // // A * x = b if trans == blas.NoTrans // Aᵀ * x = b if trans == blas.Trans // Aᴴ * x = b if trans == blas.ConjTrans // // where b and x are n element vectors and A is an n×n triangular matrix. // // On entry, x contains the values of b, and the solution 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. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctrsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []complex64, lda int, x []complex64, incX int) { switch trans { default: panic(badTranspose) case blas.NoTrans, blas.Trans, blas.ConjTrans: } switch uplo { default: panic(badUplo) case blas.Upper, blas.Lower: } switch diag { default: panic(badDiag) case blas.NonUnit, blas.Unit: } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } // Set up start index in X. var kx int if incX < 0 { kx = (1 - n) * incX } // The elements of A are accessed sequentially with one pass through A. if trans == blas.NoTrans { // Form x = inv(A)*x. if uplo == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { aii := a[i*lda+i] if n-i-1 > 0 { x[i] -= c64.DotuUnitary(x[i+1:n], a[i*lda+i+1:i*lda+n]) } if diag == blas.NonUnit { x[i] /= aii } } } else { ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { aii := a[i*lda+i] if n-i-1 > 0 { x[ix] -= c64.DotuInc(x, a[i*lda+i+1:i*lda+n], uintptr(n-i-1), uintptr(incX), 1, uintptr(ix+incX), 0) } if diag == blas.NonUnit { x[ix] /= aii } ix -= incX } } } else { if incX == 1 { for i := 0; i < n; i++ { if i > 0 { x[i] -= c64.DotuUnitary(x[:i], a[i*lda:i*lda+i]) } if diag == blas.NonUnit { x[i] /= a[i*lda+i] } } } else { ix := kx for i := 0; i < n; i++ { if i > 0 { x[ix] -= c64.DotuInc(x, a[i*lda:i*lda+i], uintptr(i), uintptr(incX), 1, uintptr(kx), 0) } if diag == blas.NonUnit { x[ix] /= a[i*lda+i] } ix += incX } } } return } if trans == blas.Trans { // Form x = inv(Aᵀ)*x. if uplo == blas.Upper { if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= a[j*lda+j] } if n-j-1 > 0 { c64.AxpyUnitary(-x[j], a[j*lda+j+1:j*lda+n], x[j+1:n]) } } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= a[j*lda+j] } if n-j-1 > 0 { c64.AxpyInc(-x[jx], a[j*lda+j+1:j*lda+n], x, uintptr(n-j-1), 1, uintptr(incX), 0, uintptr(jx+incX)) } jx += incX } } } else { if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= a[j*lda+j] } xj := x[j] if j > 0 { c64.AxpyUnitary(-xj, a[j*lda:j*lda+j], x[:j]) } } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= a[j*lda+j] } if j > 0 { c64.AxpyInc(-x[jx], a[j*lda:j*lda+j], x, uintptr(j), 1, uintptr(incX), 0, uintptr(kx)) } jx -= incX } } } return } // Form x = inv(Aᴴ)*x. if uplo == blas.Upper { if incX == 1 { for j := 0; j < n; j++ { if diag == blas.NonUnit { x[j] /= cmplx.Conj(a[j*lda+j]) } xj := x[j] for i := j + 1; i < n; i++ { x[i] -= xj * cmplx.Conj(a[j*lda+i]) } } } else { jx := kx for j := 0; j < n; j++ { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(a[j*lda+j]) } xj := x[jx] ix := jx + incX for i := j + 1; i < n; i++ { x[ix] -= xj * cmplx.Conj(a[j*lda+i]) ix += incX } jx += incX } } } else { if incX == 1 { for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[j] /= cmplx.Conj(a[j*lda+j]) } xj := x[j] for i := 0; i < j; i++ { x[i] -= xj * cmplx.Conj(a[j*lda+i]) } } } else { jx := kx + (n-1)*incX for j := n - 1; j >= 0; j-- { if diag == blas.NonUnit { x[jx] /= cmplx.Conj(a[j*lda+j]) } xj := x[jx] ix := kx for i := 0; i < j; i++ { x[ix] -= xj * cmplx.Conj(a[j*lda+i]) ix += incX } jx -= incX } } } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level2float32.go000066400000000000000000001322101450372207100226160ustar00rootroot00000000000000// 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.Float32Level2 = Implementation{} // Sger performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Sger(m, n int, alpha float32, x []float32, incX int, y []float32, incY int, a []float32, lda int) { 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 } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (m-1)*incX) || (incX < 0 && len(x) <= (1-m)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { panic(shortY) } if len(a) < lda*(m-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } f32.Ger(uintptr(m), uintptr(n), alpha, x, uintptr(incX), y, uintptr(incY), a, uintptr(lda)) } // Sgbmv performs one of the matrix-vector operations // // 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 band matrix with kL sub-diagonals and kU super-diagonals, // x and y are vectors, and alpha and beta are scalars. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Sgbmv(tA blas.Transpose, m, n, kL, kU 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 kL < 0 { panic(kLLT0) } if kU < 0 { panic(kULT0) } if lda < kL+kU+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // 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*(min(m, n+kL)-1)+kL+kU+1 { panic(shortA) } lenX := m lenY := n if tA == blas.NoTrans { lenX = n lenY = m } if (incX > 0 && len(x) <= (lenX-1)*incX) || (incX < 0 && len(x) <= (1-lenX)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (lenY-1)*incY) || (incY < 0 && len(y) <= (1-lenY)*incY) { panic(shortY) } // Quick return if possible. if alpha == 0 && beta == 1 { return } var kx, ky int if incX < 0 { kx = -(lenX - 1) * incX } if incY < 0 { ky = -(lenY - 1) * incY } // Form y = beta * y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:lenY] { y[i] = 0 } } else { f32.ScalUnitary(beta, y[:lenY]) } } else { iy := ky if beta == 0 { for i := 0; i < lenY; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f32.ScalInc(beta, y, uintptr(lenY), uintptr(incY)) } else { f32.ScalInc(beta, y, uintptr(lenY), uintptr(-incY)) } } } } if alpha == 0 { return } // i and j are indices of the compacted banded matrix. // off is the offset into the dense matrix (off + j = densej) nCol := kU + 1 + kL if tA == blas.NoTrans { iy := ky if incX == 1 { for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] xtmp := x[off : off+u-l] var sum float32 for j, v := range atmp { sum += xtmp[j] * v } y[iy] += sum * alpha iy += incY } return } for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] jx := kx var sum float32 for _, v := range atmp { sum += x[off*incX+jx] * v jx += incX } y[iy] += sum * alpha iy += incY } return } if incX == 1 { for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] tmp := alpha * x[i] jy := ky for _, v := range atmp { y[jy+off*incY] += tmp * v jy += incY } } return } ix := kx for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] tmp := alpha * x[ix] jy := ky for _, v := range atmp { y[jy+off*incY] += tmp * v jy += incY } ix += incX } } // 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) } // 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{}.Sscal(lenY, beta, y, incY) } else { Implementation{}.Sscal(lenY, beta, y, -incY) } return } // Form y = alpha * A * x + y if tA == blas.NoTrans { f32.GemvN(uintptr(m), uintptr(n), alpha, a, uintptr(lda), x, uintptr(incX), beta, y, uintptr(incY)) return } // Cases where a is transposed. f32.GemvT(uintptr(m), uintptr(n), alpha, a, uintptr(lda), x, uintptr(incX), beta, y, uintptr(incY)) } // Strmv performs one of the matrix-vector operations // // x = A * x if tA == blas.NoTrans // x = Aᵀ * x if tA == blas.Trans or blas.ConjTrans // // where A is an n×n triangular matrix, and x is a vector. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Strmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float32, lda int, x []float32, incX int) { 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 n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } nonUnit := d != blas.Unit if n == 1 { if nonUnit { x[0] *= a[0] } return } var kx int if incX <= 0 { kx = -(n - 1) * incX } if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { ilda := i * lda var tmp float32 if nonUnit { tmp = a[ilda+i] * x[i] } else { tmp = x[i] } x[i] = tmp + f32.DotUnitary(a[ilda+i+1:ilda+n], x[i+1:n]) } return } ix := kx for i := 0; i < n; i++ { ilda := i * lda var tmp float32 if nonUnit { tmp = a[ilda+i] * x[ix] } else { tmp = x[ix] } x[ix] = tmp + f32.DotInc(x, a[ilda+i+1:ilda+n], uintptr(n-i-1), uintptr(incX), 1, uintptr(ix+incX), 0) ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { ilda := i * lda var tmp float32 if nonUnit { tmp += a[ilda+i] * x[i] } else { tmp = x[i] } x[i] = tmp + f32.DotUnitary(a[ilda:ilda+i], x[:i]) } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { ilda := i * lda var tmp float32 if nonUnit { tmp = a[ilda+i] * x[ix] } else { tmp = x[ix] } x[ix] = tmp + f32.DotInc(x, a[ilda:ilda+i], uintptr(i), uintptr(incX), 1, uintptr(kx), 0) ix -= incX } return } // Cases where a is transposed. if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { ilda := i * lda xi := x[i] f32.AxpyUnitary(xi, a[ilda+i+1:ilda+n], x[i+1:n]) if nonUnit { x[i] *= a[ilda+i] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { ilda := i * lda xi := x[ix] f32.AxpyInc(xi, a[ilda+i+1:ilda+n], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(kx+(i+1)*incX)) if nonUnit { x[ix] *= a[ilda+i] } ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { ilda := i * lda xi := x[i] f32.AxpyUnitary(xi, a[ilda:ilda+i], x[:i]) if nonUnit { x[i] *= a[i*lda+i] } } return } ix := kx for i := 0; i < n; i++ { ilda := i * lda xi := x[ix] f32.AxpyInc(xi, a[ilda:ilda+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) if nonUnit { x[ix] *= a[ilda+i] } ix += incX } } // Strsv solves one of the systems of equations // // A * x = b if tA == blas.NoTrans // Aᵀ * x = b if tA == 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. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Strsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float32, lda int, x []float32, incX int) { 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 n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if n == 1 { if d == blas.NonUnit { x[0] /= a[0] } return } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { var sum float32 atmp := a[i*lda+i+1 : i*lda+n] for j, v := range atmp { jv := i + j + 1 sum += x[jv] * v } x[i] -= sum if nonUnit { x[i] /= a[i*lda+i] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { var sum float32 jx := ix + incX atmp := a[i*lda+i+1 : i*lda+n] for _, v := range atmp { sum += x[jx] * v jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda+i] } ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { var sum float32 atmp := a[i*lda : i*lda+i] for j, v := range atmp { sum += x[j] * v } x[i] -= sum if nonUnit { x[i] /= a[i*lda+i] } } return } ix := kx for i := 0; i < n; i++ { jx := kx var sum float32 atmp := a[i*lda : i*lda+i] for _, v := range atmp { sum += x[jx] * v jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda+i] } ix += incX } return } // Cases where a is transposed. if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if nonUnit { x[i] /= a[i*lda+i] } xi := x[i] atmp := a[i*lda+i+1 : i*lda+n] for j, v := range atmp { jv := j + i + 1 x[jv] -= v * xi } } return } ix := kx for i := 0; i < n; i++ { if nonUnit { x[ix] /= a[i*lda+i] } xi := x[ix] jx := kx + (i+1)*incX atmp := a[i*lda+i+1 : i*lda+n] for _, v := range atmp { x[jx] -= v * xi jx += incX } ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { if nonUnit { x[i] /= a[i*lda+i] } xi := x[i] atmp := a[i*lda : i*lda+i] for j, v := range atmp { x[j] -= v * xi } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if nonUnit { x[ix] /= a[i*lda+i] } xi := x[ix] jx := kx atmp := a[i*lda : i*lda+i] for _, v := range atmp { x[jx] -= v * xi jx += incX } ix -= incX } } // Ssymv performs the matrix-vector operation // // 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. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Ssymv(ul blas.Uplo, n int, alpha float32, a []float32, lda int, x []float32, incX int, beta float32, y []float32, incY int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up start points var kx, ky int if incX < 0 { kx = -(n - 1) * incX } if incY < 0 { ky = -(n - 1) * incY } // Form y = beta * y if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { f32.ScalUnitary(beta, y[:n]) } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f32.ScalInc(beta, y, uintptr(n), uintptr(incY)) } else { f32.ScalInc(beta, y, uintptr(n), uintptr(-incY)) } } } } if alpha == 0 { return } if n == 1 { y[0] += alpha * a[0] * x[0] return } if ul == blas.Upper { if incX == 1 { iy := ky for i := 0; i < n; i++ { xv := x[i] * alpha sum := x[i] * a[i*lda+i] jy := ky + (i+1)*incY atmp := a[i*lda+i+1 : i*lda+n] for j, v := range atmp { jp := j + i + 1 sum += x[jp] * v y[jy] += xv * v jy += incY } y[iy] += alpha * sum iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { xv := x[ix] * alpha sum := x[ix] * a[i*lda+i] jx := kx + (i+1)*incX jy := ky + (i+1)*incY atmp := a[i*lda+i+1 : i*lda+n] for _, v := range atmp { sum += x[jx] * v y[jy] += xv * v jx += incX jy += incY } y[iy] += alpha * sum ix += incX iy += incY } return } // Cases where a is lower triangular. if incX == 1 { iy := ky for i := 0; i < n; i++ { jy := ky xv := alpha * x[i] atmp := a[i*lda : i*lda+i] var sum float32 for j, v := range atmp { sum += x[j] * v y[jy] += xv * v jy += incY } sum += x[i] * a[i*lda+i] sum *= alpha y[iy] += sum iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx jy := ky xv := alpha * x[ix] atmp := a[i*lda : i*lda+i] var sum float32 for _, v := range atmp { sum += x[jx] * v y[jy] += xv * v jx += incX jy += incY } sum += x[ix] * a[i*lda+i] sum *= alpha y[iy] += sum ix += incX iy += incY } } // Stbmv performs one of the matrix-vector operations // // x = A * x if tA == blas.NoTrans // x = Aᵀ * x if tA == blas.Trans or blas.ConjTrans // // where A is an n×n triangular band matrix with k+1 diagonals, and x is a vector. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Stbmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float32, lda int, x []float32, incX int) { 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 n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonunit := d != blas.Unit if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { u := min(1+k, n-i) var sum float32 atmp := a[i*lda:] xtmp := x[i:] for j := 1; j < u; j++ { sum += xtmp[j] * atmp[j] } if nonunit { sum += xtmp[0] * atmp[0] } else { sum += xtmp[0] } x[i] = sum } return } ix := kx for i := 0; i < n; i++ { u := min(1+k, n-i) var sum float32 atmp := a[i*lda:] jx := incX for j := 1; j < u; j++ { sum += x[ix+jx] * atmp[j] jx += incX } if nonunit { sum += x[ix] * atmp[0] } else { sum += x[ix] } x[ix] = sum ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { l := max(0, k-i) atmp := a[i*lda:] var sum float32 for j := l; j < k; j++ { sum += x[i-k+j] * atmp[j] } if nonunit { sum += x[i] * atmp[k] } else { sum += x[i] } x[i] = sum } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { l := max(0, k-i) atmp := a[i*lda:] var sum float32 jx := l * incX for j := l; j < k; j++ { sum += x[ix-k*incX+jx] * atmp[j] jx += incX } if nonunit { sum += x[ix] * atmp[k] } else { sum += x[ix] } x[ix] = sum ix -= incX } return } if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { u := k + 1 if i < u { u = i + 1 } var sum float32 for j := 1; j < u; j++ { sum += x[i-j] * a[(i-j)*lda+j] } if nonunit { sum += x[i] * a[i*lda] } else { sum += x[i] } x[i] = sum } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { u := k + 1 if i < u { u = i + 1 } var sum float32 jx := incX for j := 1; j < u; j++ { sum += x[ix-jx] * a[(i-j)*lda+j] jx += incX } if nonunit { sum += x[ix] * a[i*lda] } else { sum += x[ix] } x[ix] = sum ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { u := k if i+k >= n { u = n - i - 1 } var sum float32 for j := 0; j < u; j++ { sum += x[i+j+1] * a[(i+j+1)*lda+k-j-1] } if nonunit { sum += x[i] * a[i*lda+k] } else { sum += x[i] } x[i] = sum } return } ix := kx for i := 0; i < n; i++ { u := k if i+k >= n { u = n - i - 1 } var ( sum float32 jx int ) for j := 0; j < u; j++ { sum += x[ix+jx+incX] * a[(i+j+1)*lda+k-j-1] jx += incX } if nonunit { sum += x[ix] * a[i*lda+k] } else { sum += x[ix] } x[ix] = sum ix += incX } } // Stpmv performs one of the matrix-vector operations // // x = A * x if tA == blas.NoTrans // x = Aᵀ * x if tA == blas.Trans or blas.ConjTrans // // where A is an n×n triangular matrix in packed format, and x is a vector. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Stpmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float32, x []float32, incX int) { 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 n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit var offset int // Offset is the index of (i,i) if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if nonUnit { xi *= ap[offset] } atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] for j, v := range atmp { xi += v * xtmp[j] } x[i] = xi offset += n - i } return } ix := kx for i := 0; i < n; i++ { xix := x[ix] if nonUnit { xix *= ap[offset] } atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX for _, v := range atmp { xix += v * x[jx] jx += incX } x[ix] = xix offset += n - i ix += incX } return } if incX == 1 { offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xi := x[i] if nonUnit { xi *= ap[offset] } atmp := ap[offset-i : offset] for j, v := range atmp { xi += v * x[j] } x[i] = xi offset -= i + 1 } return } ix := kx + (n-1)*incX offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xix := x[ix] if nonUnit { xix *= ap[offset] } atmp := ap[offset-i : offset] jx := kx for _, v := range atmp { xix += v * x[jx] jx += incX } x[ix] = xix offset -= i + 1 ix -= incX } return } // Cases where ap is transposed. if ul == blas.Upper { if incX == 1 { offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xi := x[i] atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] for j, v := range atmp { xtmp[j] += v * xi } if nonUnit { x[i] *= ap[offset] } offset -= n - i + 1 } return } ix := kx + (n-1)*incX offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xix := x[ix] jx := kx + (i+1)*incX atmp := ap[offset+1 : offset+n-i] for _, v := range atmp { x[jx] += v * xix jx += incX } if nonUnit { x[ix] *= ap[offset] } offset -= n - i + 1 ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { xi := x[i] atmp := ap[offset-i : offset] for j, v := range atmp { x[j] += v * xi } if nonUnit { x[i] *= ap[offset] } offset += i + 2 } return } ix := kx for i := 0; i < n; i++ { xix := x[ix] jx := kx atmp := ap[offset-i : offset] for _, v := range atmp { x[jx] += v * xix jx += incX } if nonUnit { x[ix] *= ap[offset] } ix += incX offset += i + 2 } } // Stbsv solves one of the systems of equations // // A * x = b if tA == blas.NoTrans // Aᵀ * x = b if tA == blas.Trans or tA == blas.ConjTrans // // where A is an n×n triangular band matrix with k+1 diagonals, // 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. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Stbsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float32, lda int, x []float32, incX int) { 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 n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit // Form x = A^-1 x. // Several cases below use subslices for speed improvement. // The incX != 1 cases usually do not because incX may be negative. if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { bands := k if i+bands >= n { bands = n - i - 1 } atmp := a[i*lda+1:] xtmp := x[i+1 : i+bands+1] var sum float32 for j, v := range xtmp { sum += v * atmp[j] } x[i] -= sum if nonUnit { x[i] /= a[i*lda] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { max := k + 1 if i+max > n { max = n - i } atmp := a[i*lda:] var ( jx int sum float32 ) for j := 1; j < max; j++ { jx += incX sum += x[ix+jx] * atmp[j] } x[ix] -= sum if nonUnit { x[ix] /= atmp[0] } ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } atmp := a[i*lda+k-bands:] xtmp := x[i-bands : i] var sum float32 for j, v := range xtmp { sum += v * atmp[j] } x[i] -= sum if nonUnit { x[i] /= atmp[bands] } } return } ix := kx for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } atmp := a[i*lda+k-bands:] var ( sum float32 jx int ) for j := 0; j < bands; j++ { sum += x[ix-bands*incX+jx] * atmp[j] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= atmp[bands] } ix += incX } return } // Cases where a is transposed. if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } var sum float32 for j := 0; j < bands; j++ { sum += x[i-bands+j] * a[(i-bands+j)*lda+bands-j] } x[i] -= sum if nonUnit { x[i] /= a[i*lda] } } return } ix := kx for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } var ( sum float32 jx int ) for j := 0; j < bands; j++ { sum += x[ix-bands*incX+jx] * a[(i-bands+j)*lda+bands-j] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda] } ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { bands := k if i+bands >= n { bands = n - i - 1 } var sum float32 xtmp := x[i+1 : i+1+bands] for j, v := range xtmp { sum += v * a[(i+j+1)*lda+k-j-1] } x[i] -= sum if nonUnit { x[i] /= a[i*lda+k] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { bands := k if i+bands >= n { bands = n - i - 1 } var ( sum float32 jx int ) for j := 0; j < bands; j++ { sum += x[ix+jx+incX] * a[(i+j+1)*lda+k-j-1] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda+k] } ix -= incX } } // Ssbmv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where A is an n×n symmetric band matrix with k super-diagonals, x and y are // vectors, and alpha and beta are scalars. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Ssbmv(ul blas.Uplo, n, k int, alpha float32, a []float32, lda int, x []float32, incX int, beta float32, y []float32, incY int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up indexes lenX := n lenY := n var kx, ky int if incX < 0 { kx = -(lenX - 1) * incX } if incY < 0 { ky = -(lenY - 1) * incY } // Form y = beta * y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { f32.ScalUnitary(beta, y[:n]) } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f32.ScalInc(beta, y, uintptr(n), uintptr(incY)) } else { f32.ScalInc(beta, y, uintptr(n), uintptr(-incY)) } } } } if alpha == 0 { return } if ul == blas.Upper { if incX == 1 { iy := ky for i := 0; i < n; i++ { atmp := a[i*lda:] tmp := alpha * x[i] sum := tmp * atmp[0] u := min(k, n-i-1) jy := incY for j := 1; j <= u; j++ { v := atmp[j] sum += alpha * x[i+j] * v y[iy+jy] += tmp * v jy += incY } y[iy] += sum iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { atmp := a[i*lda:] tmp := alpha * x[ix] sum := tmp * atmp[0] u := min(k, n-i-1) jx := incX jy := incY for j := 1; j <= u; j++ { v := atmp[j] sum += alpha * x[ix+jx] * v y[iy+jy] += tmp * v jx += incX jy += incY } y[iy] += sum ix += incX iy += incY } return } // Cases where a has bands below the diagonal. if incX == 1 { iy := ky for i := 0; i < n; i++ { l := max(0, k-i) tmp := alpha * x[i] jy := l * incY atmp := a[i*lda:] for j := l; j < k; j++ { v := atmp[j] y[iy] += alpha * v * x[i-k+j] y[iy-k*incY+jy] += tmp * v jy += incY } y[iy] += tmp * atmp[k] iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { l := max(0, k-i) tmp := alpha * x[ix] jx := l * incX jy := l * incY atmp := a[i*lda:] for j := l; j < k; j++ { v := atmp[j] y[iy] += alpha * v * x[ix-k*incX+jx] y[iy-k*incY+jy] += tmp * v jx += incX jy += incY } y[iy] += tmp * atmp[k] ix += incX iy += incY } } // Ssyr performs the symmetric rank-one update // // A += alpha * x * xᵀ // // where A is an n×n symmetric matrix, and x is a vector. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Ssyr(ul blas.Uplo, n int, alpha float32, x []float32, incX int, a []float32, lda int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } lenX := n var kx int if incX < 0 { kx = -(lenX - 1) * incX } if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { tmp := x[i] * alpha if tmp != 0 { atmp := a[i*lda+i : i*lda+n] xtmp := x[i:n] for j, v := range xtmp { atmp[j] += v * tmp } } } return } ix := kx for i := 0; i < n; i++ { tmp := x[ix] * alpha if tmp != 0 { jx := ix atmp := a[i*lda:] for j := i; j < n; j++ { atmp[j] += x[jx] * tmp jx += incX } } ix += incX } return } // Cases where a is lower triangular. if incX == 1 { for i := 0; i < n; i++ { tmp := x[i] * alpha if tmp != 0 { atmp := a[i*lda:] xtmp := x[:i+1] for j, v := range xtmp { atmp[j] += tmp * v } } } return } ix := kx for i := 0; i < n; i++ { tmp := x[ix] * alpha if tmp != 0 { atmp := a[i*lda:] jx := kx for j := 0; j < i+1; j++ { atmp[j] += tmp * x[jx] jx += incX } } ix += incX } } // Ssyr2 performs the symmetric rank-two update // // A += alpha * x * yᵀ + alpha * y * xᵀ // // where A is an n×n symmetric matrix, x and y are vectors, and alpha is a scalar. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Ssyr2(ul blas.Uplo, n int, alpha float32, x []float32, incX int, y []float32, incY int, a []float32, lda int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var ky, kx int if incY < 0 { ky = -(n - 1) * incY } if incX < 0 { kx = -(n - 1) * incX } if ul == blas.Upper { if incX == 1 && incY == 1 { for i := 0; i < n; i++ { xi := x[i] yi := y[i] atmp := a[i*lda:] for j := i; j < n; j++ { atmp[j] += alpha * (xi*y[j] + x[j]*yi) } } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx + i*incX jy := ky + i*incY xi := x[ix] yi := y[iy] atmp := a[i*lda:] for j := i; j < n; j++ { atmp[j] += alpha * (xi*y[jy] + x[jx]*yi) jx += incX jy += incY } ix += incX iy += incY } return } if incX == 1 && incY == 1 { for i := 0; i < n; i++ { xi := x[i] yi := y[i] atmp := a[i*lda:] for j := 0; j <= i; j++ { atmp[j] += alpha * (xi*y[j] + x[j]*yi) } } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx jy := ky xi := x[ix] yi := y[iy] atmp := a[i*lda:] for j := 0; j <= i; j++ { atmp[j] += alpha * (xi*y[jy] + x[jx]*yi) jx += incX jy += incY } ix += incX iy += incY } } // Stpsv solves one of the systems of equations // // A * x = b if tA == blas.NoTrans // Aᵀ * x = b if tA == 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. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Stpsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float32, x []float32, incX int) { 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 n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit var offset int // Offset is the index of (i,i) if tA == blas.NoTrans { if ul == blas.Upper { offset = n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] var sum float32 for j, v := range atmp { sum += v * xtmp[j] } x[i] -= sum if nonUnit { x[i] /= ap[offset] } offset -= n - i + 1 } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX var sum float32 for _, v := range atmp { sum += v * x[jx] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= ap[offset] } ix -= incX offset -= n - i + 1 } return } if incX == 1 { for i := 0; i < n; i++ { atmp := ap[offset-i : offset] var sum float32 for j, v := range atmp { sum += v * x[j] } x[i] -= sum if nonUnit { x[i] /= ap[offset] } offset += i + 2 } return } ix := kx for i := 0; i < n; i++ { jx := kx atmp := ap[offset-i : offset] var sum float32 for _, v := range atmp { sum += v * x[jx] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= ap[offset] } ix += incX offset += i + 2 } return } // Cases where ap is transposed. if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if nonUnit { x[i] /= ap[offset] } xi := x[i] atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] for j, v := range atmp { xtmp[j] -= v * xi } offset += n - i } return } ix := kx for i := 0; i < n; i++ { if nonUnit { x[ix] /= ap[offset] } xix := x[ix] atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX for _, v := range atmp { x[jx] -= v * xix jx += incX } ix += incX offset += n - i } return } if incX == 1 { offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { if nonUnit { x[i] /= ap[offset] } xi := x[i] atmp := ap[offset-i : offset] for j, v := range atmp { x[j] -= v * xi } offset -= i + 1 } return } ix := kx + (n-1)*incX offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { if nonUnit { x[ix] /= ap[offset] } xix := x[ix] atmp := ap[offset-i : offset] jx := kx for _, v := range atmp { x[jx] -= v * xix jx += incX } ix -= incX offset -= i + 1 } } // Sspmv performs the matrix-vector operation // // 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. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Sspmv(ul blas.Uplo, n int, alpha float32, ap []float32, x []float32, incX int, beta float32, y []float32, incY int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up start points var kx, ky int if incX < 0 { kx = -(n - 1) * incX } if incY < 0 { ky = -(n - 1) * incY } // Form y = beta * y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { f32.ScalUnitary(beta, y[:n]) } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f32.ScalInc(beta, y, uintptr(n), uintptr(incY)) } else { f32.ScalInc(beta, y, uintptr(n), uintptr(-incY)) } } } } if alpha == 0 { return } if n == 1 { y[0] += alpha * ap[0] * x[0] return } var offset int // Offset is the index of (i,i). if ul == blas.Upper { if incX == 1 { iy := ky for i := 0; i < n; i++ { xv := x[i] * alpha sum := ap[offset] * x[i] atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] jy := ky + (i+1)*incY for j, v := range atmp { sum += v * xtmp[j] y[jy] += v * xv jy += incY } y[iy] += alpha * sum iy += incY offset += n - i } return } ix := kx iy := ky for i := 0; i < n; i++ { xv := x[ix] * alpha sum := ap[offset] * x[ix] atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX jy := ky + (i+1)*incY for _, v := range atmp { sum += v * x[jx] y[jy] += v * xv jx += incX jy += incY } y[iy] += alpha * sum ix += incX iy += incY offset += n - i } return } if incX == 1 { iy := ky for i := 0; i < n; i++ { xv := x[i] * alpha atmp := ap[offset-i : offset] jy := ky var sum float32 for j, v := range atmp { sum += v * x[j] y[jy] += v * xv jy += incY } sum += ap[offset] * x[i] y[iy] += alpha * sum iy += incY offset += i + 2 } return } ix := kx iy := ky for i := 0; i < n; i++ { xv := x[ix] * alpha atmp := ap[offset-i : offset] jx := kx jy := ky var sum float32 for _, v := range atmp { sum += v * x[jx] y[jy] += v * xv jx += incX jy += incY } sum += ap[offset] * x[ix] y[iy] += alpha * sum ix += incX iy += incY offset += i + 2 } } // Sspr performs the symmetric rank-one operation // // A += alpha * x * xᵀ // // where A is an n×n symmetric matrix in packed format, x is a vector, and // alpha is a scalar. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Sspr(ul blas.Uplo, n int, alpha float32, x []float32, incX int, ap []float32) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } lenX := n var kx int if incX < 0 { kx = -(lenX - 1) * incX } var offset int // Offset is the index of (i,i). if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { atmp := ap[offset:] xv := alpha * x[i] xtmp := x[i:n] for j, v := range xtmp { atmp[j] += xv * v } offset += n - i } return } ix := kx for i := 0; i < n; i++ { jx := kx + i*incX atmp := ap[offset:] xv := alpha * x[ix] for j := 0; j < n-i; j++ { atmp[j] += xv * x[jx] jx += incX } ix += incX offset += n - i } return } if incX == 1 { for i := 0; i < n; i++ { atmp := ap[offset-i:] xv := alpha * x[i] xtmp := x[:i+1] for j, v := range xtmp { atmp[j] += xv * v } offset += i + 2 } return } ix := kx for i := 0; i < n; i++ { jx := kx atmp := ap[offset-i:] xv := alpha * x[ix] for j := 0; j <= i; j++ { atmp[j] += xv * x[jx] jx += incX } ix += incX offset += i + 2 } } // Sspr2 performs the symmetric 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. // // Float32 implementations are autogenerated and not directly tested. func (Implementation) Sspr2(ul blas.Uplo, n int, alpha float32, x []float32, incX int, y []float32, incY int, ap []float32) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } var ky, kx int if incY < 0 { ky = -(n - 1) * incY } if incX < 0 { kx = -(n - 1) * incX } var offset int // Offset is the index of (i,i). if ul == blas.Upper { if incX == 1 && incY == 1 { for i := 0; i < n; i++ { atmp := ap[offset:] xi := x[i] yi := y[i] xtmp := x[i:n] ytmp := y[i:n] for j, v := range xtmp { atmp[j] += alpha * (xi*ytmp[j] + v*yi) } offset += n - i } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx + i*incX jy := ky + i*incY atmp := ap[offset:] xi := x[ix] yi := y[iy] for j := 0; j < n-i; j++ { atmp[j] += alpha * (xi*y[jy] + x[jx]*yi) jx += incX jy += incY } ix += incX iy += incY offset += n - i } return } if incX == 1 && incY == 1 { for i := 0; i < n; i++ { atmp := ap[offset-i:] xi := x[i] yi := y[i] xtmp := x[:i+1] for j, v := range xtmp { atmp[j] += alpha * (xi*y[j] + v*yi) } offset += i + 2 } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx jy := ky atmp := ap[offset-i:] for j := 0; j <= i; j++ { atmp[j] += alpha * (x[ix]*y[jy] + x[jx]*y[iy]) jx += incX jy += incY } ix += incX iy += incY offset += i + 2 } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level2float64.go000066400000000000000000001276461450372207100226440ustar00rootroot00000000000000// 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.Float64Level2 = Implementation{} // Dger performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar. func (Implementation) Dger(m, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int) { 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 } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (m-1)*incX) || (incX < 0 && len(x) <= (1-m)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { panic(shortY) } if len(a) < lda*(m-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } f64.Ger(uintptr(m), uintptr(n), alpha, x, uintptr(incX), y, uintptr(incY), a, uintptr(lda)) } // Dgbmv performs one of the matrix-vector operations // // 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 band matrix with kL sub-diagonals and kU super-diagonals, // x and y are vectors, and alpha and beta are scalars. func (Implementation) Dgbmv(tA blas.Transpose, m, n, kL, kU 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 kL < 0 { panic(kLLT0) } if kU < 0 { panic(kULT0) } if lda < kL+kU+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // 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*(min(m, n+kL)-1)+kL+kU+1 { panic(shortA) } lenX := m lenY := n if tA == blas.NoTrans { lenX = n lenY = m } if (incX > 0 && len(x) <= (lenX-1)*incX) || (incX < 0 && len(x) <= (1-lenX)*incX) { panic(shortX) } if (incY > 0 && len(y) <= (lenY-1)*incY) || (incY < 0 && len(y) <= (1-lenY)*incY) { panic(shortY) } // Quick return if possible. if alpha == 0 && beta == 1 { return } var kx, ky int if incX < 0 { kx = -(lenX - 1) * incX } if incY < 0 { ky = -(lenY - 1) * incY } // Form y = beta * y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:lenY] { y[i] = 0 } } else { f64.ScalUnitary(beta, y[:lenY]) } } else { iy := ky if beta == 0 { for i := 0; i < lenY; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f64.ScalInc(beta, y, uintptr(lenY), uintptr(incY)) } else { f64.ScalInc(beta, y, uintptr(lenY), uintptr(-incY)) } } } } if alpha == 0 { return } // i and j are indices of the compacted banded matrix. // off is the offset into the dense matrix (off + j = densej) nCol := kU + 1 + kL if tA == blas.NoTrans { iy := ky if incX == 1 { for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] xtmp := x[off : off+u-l] var sum float64 for j, v := range atmp { sum += xtmp[j] * v } y[iy] += sum * alpha iy += incY } return } for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] jx := kx var sum float64 for _, v := range atmp { sum += x[off*incX+jx] * v jx += incX } y[iy] += sum * alpha iy += incY } return } if incX == 1 { for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] tmp := alpha * x[i] jy := ky for _, v := range atmp { y[jy+off*incY] += tmp * v jy += incY } } return } ix := kx for i := 0; i < min(m, n+kL); i++ { l := max(0, kL-i) u := min(nCol, n+kL-i) off := max(0, i-kL) atmp := a[i*lda+l : i*lda+u] tmp := alpha * x[ix] jy := ky for _, v := range atmp { y[jy+off*incY] += tmp * v jy += incY } ix += incX } } // 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)) } // Dtrmv performs one of the matrix-vector operations // // x = A * x if tA == blas.NoTrans // x = Aᵀ * x if tA == blas.Trans or blas.ConjTrans // // where A is an n×n triangular matrix, and x is a vector. func (Implementation) Dtrmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) { 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 n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } nonUnit := d != blas.Unit if n == 1 { if nonUnit { x[0] *= a[0] } return } var kx int if incX <= 0 { kx = -(n - 1) * incX } if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { ilda := i * lda var tmp float64 if nonUnit { tmp = a[ilda+i] * x[i] } else { tmp = x[i] } x[i] = tmp + f64.DotUnitary(a[ilda+i+1:ilda+n], x[i+1:n]) } return } ix := kx for i := 0; i < n; i++ { ilda := i * lda var tmp float64 if nonUnit { tmp = a[ilda+i] * x[ix] } else { tmp = x[ix] } x[ix] = tmp + f64.DotInc(x, a[ilda+i+1:ilda+n], uintptr(n-i-1), uintptr(incX), 1, uintptr(ix+incX), 0) ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { ilda := i * lda var tmp float64 if nonUnit { tmp += a[ilda+i] * x[i] } else { tmp = x[i] } x[i] = tmp + f64.DotUnitary(a[ilda:ilda+i], x[:i]) } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { ilda := i * lda var tmp float64 if nonUnit { tmp = a[ilda+i] * x[ix] } else { tmp = x[ix] } x[ix] = tmp + f64.DotInc(x, a[ilda:ilda+i], uintptr(i), uintptr(incX), 1, uintptr(kx), 0) ix -= incX } return } // Cases where a is transposed. if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { ilda := i * lda xi := x[i] f64.AxpyUnitary(xi, a[ilda+i+1:ilda+n], x[i+1:n]) if nonUnit { x[i] *= a[ilda+i] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { ilda := i * lda xi := x[ix] f64.AxpyInc(xi, a[ilda+i+1:ilda+n], x, uintptr(n-i-1), 1, uintptr(incX), 0, uintptr(kx+(i+1)*incX)) if nonUnit { x[ix] *= a[ilda+i] } ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { ilda := i * lda xi := x[i] f64.AxpyUnitary(xi, a[ilda:ilda+i], x[:i]) if nonUnit { x[i] *= a[i*lda+i] } } return } ix := kx for i := 0; i < n; i++ { ilda := i * lda xi := x[ix] f64.AxpyInc(xi, a[ilda:ilda+i], x, uintptr(i), 1, uintptr(incX), 0, uintptr(kx)) if nonUnit { x[ix] *= a[ilda+i] } ix += incX } } // Dtrsv solves one of the systems of equations // // A * x = b if tA == blas.NoTrans // Aᵀ * x = b if tA == 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 (Implementation) Dtrsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) { 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 n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if n == 1 { if d == blas.NonUnit { x[0] /= a[0] } return } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { var sum float64 atmp := a[i*lda+i+1 : i*lda+n] for j, v := range atmp { jv := i + j + 1 sum += x[jv] * v } x[i] -= sum if nonUnit { x[i] /= a[i*lda+i] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { var sum float64 jx := ix + incX atmp := a[i*lda+i+1 : i*lda+n] for _, v := range atmp { sum += x[jx] * v jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda+i] } ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { var sum float64 atmp := a[i*lda : i*lda+i] for j, v := range atmp { sum += x[j] * v } x[i] -= sum if nonUnit { x[i] /= a[i*lda+i] } } return } ix := kx for i := 0; i < n; i++ { jx := kx var sum float64 atmp := a[i*lda : i*lda+i] for _, v := range atmp { sum += x[jx] * v jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda+i] } ix += incX } return } // Cases where a is transposed. if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if nonUnit { x[i] /= a[i*lda+i] } xi := x[i] atmp := a[i*lda+i+1 : i*lda+n] for j, v := range atmp { jv := j + i + 1 x[jv] -= v * xi } } return } ix := kx for i := 0; i < n; i++ { if nonUnit { x[ix] /= a[i*lda+i] } xi := x[ix] jx := kx + (i+1)*incX atmp := a[i*lda+i+1 : i*lda+n] for _, v := range atmp { x[jx] -= v * xi jx += incX } ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { if nonUnit { x[i] /= a[i*lda+i] } xi := x[i] atmp := a[i*lda : i*lda+i] for j, v := range atmp { x[j] -= v * xi } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { if nonUnit { x[ix] /= a[i*lda+i] } xi := x[ix] jx := kx atmp := a[i*lda : i*lda+i] for _, v := range atmp { x[jx] -= v * xi jx += incX } ix -= incX } } // Dsymv performs the matrix-vector operation // // 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 (Implementation) Dsymv(ul blas.Uplo, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+n { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up start points var kx, ky int if incX < 0 { kx = -(n - 1) * incX } if incY < 0 { ky = -(n - 1) * incY } // Form y = beta * y if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { f64.ScalUnitary(beta, y[:n]) } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f64.ScalInc(beta, y, uintptr(n), uintptr(incY)) } else { f64.ScalInc(beta, y, uintptr(n), uintptr(-incY)) } } } } if alpha == 0 { return } if n == 1 { y[0] += alpha * a[0] * x[0] return } if ul == blas.Upper { if incX == 1 { iy := ky for i := 0; i < n; i++ { xv := x[i] * alpha sum := x[i] * a[i*lda+i] jy := ky + (i+1)*incY atmp := a[i*lda+i+1 : i*lda+n] for j, v := range atmp { jp := j + i + 1 sum += x[jp] * v y[jy] += xv * v jy += incY } y[iy] += alpha * sum iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { xv := x[ix] * alpha sum := x[ix] * a[i*lda+i] jx := kx + (i+1)*incX jy := ky + (i+1)*incY atmp := a[i*lda+i+1 : i*lda+n] for _, v := range atmp { sum += x[jx] * v y[jy] += xv * v jx += incX jy += incY } y[iy] += alpha * sum ix += incX iy += incY } return } // Cases where a is lower triangular. if incX == 1 { iy := ky for i := 0; i < n; i++ { jy := ky xv := alpha * x[i] atmp := a[i*lda : i*lda+i] var sum float64 for j, v := range atmp { sum += x[j] * v y[jy] += xv * v jy += incY } sum += x[i] * a[i*lda+i] sum *= alpha y[iy] += sum iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx jy := ky xv := alpha * x[ix] atmp := a[i*lda : i*lda+i] var sum float64 for _, v := range atmp { sum += x[jx] * v y[jy] += xv * v jx += incX jy += incY } sum += x[ix] * a[i*lda+i] sum *= alpha y[iy] += sum ix += incX iy += incY } } // Dtbmv performs one of the matrix-vector operations // // x = A * x if tA == blas.NoTrans // x = Aᵀ * x if tA == blas.Trans or blas.ConjTrans // // where A is an n×n triangular band matrix with k+1 diagonals, and x is a vector. func (Implementation) Dtbmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float64, lda int, x []float64, incX int) { 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 n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonunit := d != blas.Unit if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { u := min(1+k, n-i) var sum float64 atmp := a[i*lda:] xtmp := x[i:] for j := 1; j < u; j++ { sum += xtmp[j] * atmp[j] } if nonunit { sum += xtmp[0] * atmp[0] } else { sum += xtmp[0] } x[i] = sum } return } ix := kx for i := 0; i < n; i++ { u := min(1+k, n-i) var sum float64 atmp := a[i*lda:] jx := incX for j := 1; j < u; j++ { sum += x[ix+jx] * atmp[j] jx += incX } if nonunit { sum += x[ix] * atmp[0] } else { sum += x[ix] } x[ix] = sum ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { l := max(0, k-i) atmp := a[i*lda:] var sum float64 for j := l; j < k; j++ { sum += x[i-k+j] * atmp[j] } if nonunit { sum += x[i] * atmp[k] } else { sum += x[i] } x[i] = sum } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { l := max(0, k-i) atmp := a[i*lda:] var sum float64 jx := l * incX for j := l; j < k; j++ { sum += x[ix-k*incX+jx] * atmp[j] jx += incX } if nonunit { sum += x[ix] * atmp[k] } else { sum += x[ix] } x[ix] = sum ix -= incX } return } if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { u := k + 1 if i < u { u = i + 1 } var sum float64 for j := 1; j < u; j++ { sum += x[i-j] * a[(i-j)*lda+j] } if nonunit { sum += x[i] * a[i*lda] } else { sum += x[i] } x[i] = sum } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { u := k + 1 if i < u { u = i + 1 } var sum float64 jx := incX for j := 1; j < u; j++ { sum += x[ix-jx] * a[(i-j)*lda+j] jx += incX } if nonunit { sum += x[ix] * a[i*lda] } else { sum += x[ix] } x[ix] = sum ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { u := k if i+k >= n { u = n - i - 1 } var sum float64 for j := 0; j < u; j++ { sum += x[i+j+1] * a[(i+j+1)*lda+k-j-1] } if nonunit { sum += x[i] * a[i*lda+k] } else { sum += x[i] } x[i] = sum } return } ix := kx for i := 0; i < n; i++ { u := k if i+k >= n { u = n - i - 1 } var ( sum float64 jx int ) for j := 0; j < u; j++ { sum += x[ix+jx+incX] * a[(i+j+1)*lda+k-j-1] jx += incX } if nonunit { sum += x[ix] * a[i*lda+k] } else { sum += x[ix] } x[ix] = sum ix += incX } } // Dtpmv performs one of the matrix-vector operations // // x = A * x if tA == blas.NoTrans // x = Aᵀ * x if tA == blas.Trans or blas.ConjTrans // // where A is an n×n triangular matrix in packed format, and x is a vector. func (Implementation) Dtpmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float64, x []float64, incX int) { 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 n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit var offset int // Offset is the index of (i,i) if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { xi := x[i] if nonUnit { xi *= ap[offset] } atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] for j, v := range atmp { xi += v * xtmp[j] } x[i] = xi offset += n - i } return } ix := kx for i := 0; i < n; i++ { xix := x[ix] if nonUnit { xix *= ap[offset] } atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX for _, v := range atmp { xix += v * x[jx] jx += incX } x[ix] = xix offset += n - i ix += incX } return } if incX == 1 { offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xi := x[i] if nonUnit { xi *= ap[offset] } atmp := ap[offset-i : offset] for j, v := range atmp { xi += v * x[j] } x[i] = xi offset -= i + 1 } return } ix := kx + (n-1)*incX offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xix := x[ix] if nonUnit { xix *= ap[offset] } atmp := ap[offset-i : offset] jx := kx for _, v := range atmp { xix += v * x[jx] jx += incX } x[ix] = xix offset -= i + 1 ix -= incX } return } // Cases where ap is transposed. if ul == blas.Upper { if incX == 1 { offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xi := x[i] atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] for j, v := range atmp { xtmp[j] += v * xi } if nonUnit { x[i] *= ap[offset] } offset -= n - i + 1 } return } ix := kx + (n-1)*incX offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { xix := x[ix] jx := kx + (i+1)*incX atmp := ap[offset+1 : offset+n-i] for _, v := range atmp { x[jx] += v * xix jx += incX } if nonUnit { x[ix] *= ap[offset] } offset -= n - i + 1 ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { xi := x[i] atmp := ap[offset-i : offset] for j, v := range atmp { x[j] += v * xi } if nonUnit { x[i] *= ap[offset] } offset += i + 2 } return } ix := kx for i := 0; i < n; i++ { xix := x[ix] jx := kx atmp := ap[offset-i : offset] for _, v := range atmp { x[jx] += v * xix jx += incX } if nonUnit { x[ix] *= ap[offset] } ix += incX offset += i + 2 } } // Dtbsv solves one of the systems of equations // // A * x = b if tA == blas.NoTrans // Aᵀ * x = b if tA == blas.Trans or tA == blas.ConjTrans // // where A is an n×n triangular band matrix with k+1 diagonals, // 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 (Implementation) Dtbsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float64, lda int, x []float64, incX int) { 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 n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit // Form x = A^-1 x. // Several cases below use subslices for speed improvement. // The incX != 1 cases usually do not because incX may be negative. if tA == blas.NoTrans { if ul == blas.Upper { if incX == 1 { for i := n - 1; i >= 0; i-- { bands := k if i+bands >= n { bands = n - i - 1 } atmp := a[i*lda+1:] xtmp := x[i+1 : i+bands+1] var sum float64 for j, v := range xtmp { sum += v * atmp[j] } x[i] -= sum if nonUnit { x[i] /= a[i*lda] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { max := k + 1 if i+max > n { max = n - i } atmp := a[i*lda:] var ( jx int sum float64 ) for j := 1; j < max; j++ { jx += incX sum += x[ix+jx] * atmp[j] } x[ix] -= sum if nonUnit { x[ix] /= atmp[0] } ix -= incX } return } if incX == 1 { for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } atmp := a[i*lda+k-bands:] xtmp := x[i-bands : i] var sum float64 for j, v := range xtmp { sum += v * atmp[j] } x[i] -= sum if nonUnit { x[i] /= atmp[bands] } } return } ix := kx for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } atmp := a[i*lda+k-bands:] var ( sum float64 jx int ) for j := 0; j < bands; j++ { sum += x[ix-bands*incX+jx] * atmp[j] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= atmp[bands] } ix += incX } return } // Cases where a is transposed. if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } var sum float64 for j := 0; j < bands; j++ { sum += x[i-bands+j] * a[(i-bands+j)*lda+bands-j] } x[i] -= sum if nonUnit { x[i] /= a[i*lda] } } return } ix := kx for i := 0; i < n; i++ { bands := k if i-k < 0 { bands = i } var ( sum float64 jx int ) for j := 0; j < bands; j++ { sum += x[ix-bands*incX+jx] * a[(i-bands+j)*lda+bands-j] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda] } ix += incX } return } if incX == 1 { for i := n - 1; i >= 0; i-- { bands := k if i+bands >= n { bands = n - i - 1 } var sum float64 xtmp := x[i+1 : i+1+bands] for j, v := range xtmp { sum += v * a[(i+j+1)*lda+k-j-1] } x[i] -= sum if nonUnit { x[i] /= a[i*lda+k] } } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { bands := k if i+bands >= n { bands = n - i - 1 } var ( sum float64 jx int ) for j := 0; j < bands; j++ { sum += x[ix+jx+incX] * a[(i+j+1)*lda+k-j-1] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= a[i*lda+k] } ix -= incX } } // Dsbmv performs the matrix-vector operation // // y = alpha * A * x + beta * y // // where A is an n×n symmetric band matrix with k super-diagonals, x and y are // vectors, and alpha and beta are scalars. func (Implementation) Dsbmv(ul blas.Uplo, n, k int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if k < 0 { panic(kLT0) } if lda < k+1 { panic(badLdA) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(a) < lda*(n-1)+k+1 { panic(shortA) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up indexes lenX := n lenY := n var kx, ky int if incX < 0 { kx = -(lenX - 1) * incX } if incY < 0 { ky = -(lenY - 1) * incY } // Form y = beta * y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { f64.ScalUnitary(beta, y[:n]) } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f64.ScalInc(beta, y, uintptr(n), uintptr(incY)) } else { f64.ScalInc(beta, y, uintptr(n), uintptr(-incY)) } } } } if alpha == 0 { return } if ul == blas.Upper { if incX == 1 { iy := ky for i := 0; i < n; i++ { atmp := a[i*lda:] tmp := alpha * x[i] sum := tmp * atmp[0] u := min(k, n-i-1) jy := incY for j := 1; j <= u; j++ { v := atmp[j] sum += alpha * x[i+j] * v y[iy+jy] += tmp * v jy += incY } y[iy] += sum iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { atmp := a[i*lda:] tmp := alpha * x[ix] sum := tmp * atmp[0] u := min(k, n-i-1) jx := incX jy := incY for j := 1; j <= u; j++ { v := atmp[j] sum += alpha * x[ix+jx] * v y[iy+jy] += tmp * v jx += incX jy += incY } y[iy] += sum ix += incX iy += incY } return } // Cases where a has bands below the diagonal. if incX == 1 { iy := ky for i := 0; i < n; i++ { l := max(0, k-i) tmp := alpha * x[i] jy := l * incY atmp := a[i*lda:] for j := l; j < k; j++ { v := atmp[j] y[iy] += alpha * v * x[i-k+j] y[iy-k*incY+jy] += tmp * v jy += incY } y[iy] += tmp * atmp[k] iy += incY } return } ix := kx iy := ky for i := 0; i < n; i++ { l := max(0, k-i) tmp := alpha * x[ix] jx := l * incX jy := l * incY atmp := a[i*lda:] for j := l; j < k; j++ { v := atmp[j] y[iy] += alpha * v * x[ix-k*incX+jx] y[iy-k*incY+jy] += tmp * v jx += incX jy += incY } y[iy] += tmp * atmp[k] ix += incX iy += incY } } // Dsyr performs the symmetric rank-one update // // A += alpha * x * xᵀ // // where A is an n×n symmetric matrix, and x is a vector. func (Implementation) Dsyr(ul blas.Uplo, n int, alpha float64, x []float64, incX int, a []float64, lda int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if lda < max(1, n) { panic(badLdA) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } lenX := n var kx int if incX < 0 { kx = -(lenX - 1) * incX } if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { tmp := x[i] * alpha if tmp != 0 { atmp := a[i*lda+i : i*lda+n] xtmp := x[i:n] for j, v := range xtmp { atmp[j] += v * tmp } } } return } ix := kx for i := 0; i < n; i++ { tmp := x[ix] * alpha if tmp != 0 { jx := ix atmp := a[i*lda:] for j := i; j < n; j++ { atmp[j] += x[jx] * tmp jx += incX } } ix += incX } return } // Cases where a is lower triangular. if incX == 1 { for i := 0; i < n; i++ { tmp := x[i] * alpha if tmp != 0 { atmp := a[i*lda:] xtmp := x[:i+1] for j, v := range xtmp { atmp[j] += tmp * v } } } return } ix := kx for i := 0; i < n; i++ { tmp := x[ix] * alpha if tmp != 0 { atmp := a[i*lda:] jx := kx for j := 0; j < i+1; j++ { atmp[j] += tmp * x[jx] jx += incX } } ix += incX } } // Dsyr2 performs the symmetric rank-two update // // A += alpha * x * yᵀ + alpha * y * xᵀ // // where A is an n×n symmetric matrix, x and y are vectors, and alpha is a scalar. func (Implementation) Dsyr2(ul blas.Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } 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 n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(a) < lda*(n-1)+n { panic(shortA) } // Quick return if possible. if alpha == 0 { return } var ky, kx int if incY < 0 { ky = -(n - 1) * incY } if incX < 0 { kx = -(n - 1) * incX } if ul == blas.Upper { if incX == 1 && incY == 1 { for i := 0; i < n; i++ { xi := x[i] yi := y[i] atmp := a[i*lda:] for j := i; j < n; j++ { atmp[j] += alpha * (xi*y[j] + x[j]*yi) } } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx + i*incX jy := ky + i*incY xi := x[ix] yi := y[iy] atmp := a[i*lda:] for j := i; j < n; j++ { atmp[j] += alpha * (xi*y[jy] + x[jx]*yi) jx += incX jy += incY } ix += incX iy += incY } return } if incX == 1 && incY == 1 { for i := 0; i < n; i++ { xi := x[i] yi := y[i] atmp := a[i*lda:] for j := 0; j <= i; j++ { atmp[j] += alpha * (xi*y[j] + x[j]*yi) } } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx jy := ky xi := x[ix] yi := y[iy] atmp := a[i*lda:] for j := 0; j <= i; j++ { atmp[j] += alpha * (xi*y[jy] + x[jx]*yi) jx += incX jy += incY } ix += incX iy += incY } } // Dtpsv solves one of the systems of equations // // A * x = b if tA == blas.NoTrans // Aᵀ * x = b if tA == 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 (Implementation) Dtpsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float64, x []float64, incX int) { 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 n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } var kx int if incX < 0 { kx = -(n - 1) * incX } nonUnit := d == blas.NonUnit var offset int // Offset is the index of (i,i) if tA == blas.NoTrans { if ul == blas.Upper { offset = n*(n+1)/2 - 1 if incX == 1 { for i := n - 1; i >= 0; i-- { atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] var sum float64 for j, v := range atmp { sum += v * xtmp[j] } x[i] -= sum if nonUnit { x[i] /= ap[offset] } offset -= n - i + 1 } return } ix := kx + (n-1)*incX for i := n - 1; i >= 0; i-- { atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX var sum float64 for _, v := range atmp { sum += v * x[jx] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= ap[offset] } ix -= incX offset -= n - i + 1 } return } if incX == 1 { for i := 0; i < n; i++ { atmp := ap[offset-i : offset] var sum float64 for j, v := range atmp { sum += v * x[j] } x[i] -= sum if nonUnit { x[i] /= ap[offset] } offset += i + 2 } return } ix := kx for i := 0; i < n; i++ { jx := kx atmp := ap[offset-i : offset] var sum float64 for _, v := range atmp { sum += v * x[jx] jx += incX } x[ix] -= sum if nonUnit { x[ix] /= ap[offset] } ix += incX offset += i + 2 } return } // Cases where ap is transposed. if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { if nonUnit { x[i] /= ap[offset] } xi := x[i] atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] for j, v := range atmp { xtmp[j] -= v * xi } offset += n - i } return } ix := kx for i := 0; i < n; i++ { if nonUnit { x[ix] /= ap[offset] } xix := x[ix] atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX for _, v := range atmp { x[jx] -= v * xix jx += incX } ix += incX offset += n - i } return } if incX == 1 { offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { if nonUnit { x[i] /= ap[offset] } xi := x[i] atmp := ap[offset-i : offset] for j, v := range atmp { x[j] -= v * xi } offset -= i + 1 } return } ix := kx + (n-1)*incX offset = n*(n+1)/2 - 1 for i := n - 1; i >= 0; i-- { if nonUnit { x[ix] /= ap[offset] } xix := x[ix] atmp := ap[offset-i : offset] jx := kx for _, v := range atmp { x[jx] -= v * xix jx += incX } ix -= incX offset -= i + 1 } } // Dspmv performs the matrix-vector operation // // 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 (Implementation) Dspmv(ul blas.Uplo, n int, alpha float64, ap []float64, x []float64, incX int, beta float64, y []float64, incY int) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if len(ap) < n*(n+1)/2 { panic(shortAP) } 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) } // Quick return if possible. if alpha == 0 && beta == 1 { return } // Set up start points var kx, ky int if incX < 0 { kx = -(n - 1) * incX } if incY < 0 { ky = -(n - 1) * incY } // Form y = beta * y. if beta != 1 { if incY == 1 { if beta == 0 { for i := range y[:n] { y[i] = 0 } } else { f64.ScalUnitary(beta, y[:n]) } } else { iy := ky if beta == 0 { for i := 0; i < n; i++ { y[iy] = 0 iy += incY } } else { if incY > 0 { f64.ScalInc(beta, y, uintptr(n), uintptr(incY)) } else { f64.ScalInc(beta, y, uintptr(n), uintptr(-incY)) } } } } if alpha == 0 { return } if n == 1 { y[0] += alpha * ap[0] * x[0] return } var offset int // Offset is the index of (i,i). if ul == blas.Upper { if incX == 1 { iy := ky for i := 0; i < n; i++ { xv := x[i] * alpha sum := ap[offset] * x[i] atmp := ap[offset+1 : offset+n-i] xtmp := x[i+1:] jy := ky + (i+1)*incY for j, v := range atmp { sum += v * xtmp[j] y[jy] += v * xv jy += incY } y[iy] += alpha * sum iy += incY offset += n - i } return } ix := kx iy := ky for i := 0; i < n; i++ { xv := x[ix] * alpha sum := ap[offset] * x[ix] atmp := ap[offset+1 : offset+n-i] jx := kx + (i+1)*incX jy := ky + (i+1)*incY for _, v := range atmp { sum += v * x[jx] y[jy] += v * xv jx += incX jy += incY } y[iy] += alpha * sum ix += incX iy += incY offset += n - i } return } if incX == 1 { iy := ky for i := 0; i < n; i++ { xv := x[i] * alpha atmp := ap[offset-i : offset] jy := ky var sum float64 for j, v := range atmp { sum += v * x[j] y[jy] += v * xv jy += incY } sum += ap[offset] * x[i] y[iy] += alpha * sum iy += incY offset += i + 2 } return } ix := kx iy := ky for i := 0; i < n; i++ { xv := x[ix] * alpha atmp := ap[offset-i : offset] jx := kx jy := ky var sum float64 for _, v := range atmp { sum += v * x[jx] y[jy] += v * xv jx += incX jy += incY } sum += ap[offset] * x[ix] y[iy] += alpha * sum ix += incX iy += incY offset += i + 2 } } // Dspr performs the symmetric rank-one operation // // 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 (Implementation) Dspr(ul blas.Uplo, n int, alpha float64, x []float64, incX int, ap []float64) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { panic(shortX) } if len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } lenX := n var kx int if incX < 0 { kx = -(lenX - 1) * incX } var offset int // Offset is the index of (i,i). if ul == blas.Upper { if incX == 1 { for i := 0; i < n; i++ { atmp := ap[offset:] xv := alpha * x[i] xtmp := x[i:n] for j, v := range xtmp { atmp[j] += xv * v } offset += n - i } return } ix := kx for i := 0; i < n; i++ { jx := kx + i*incX atmp := ap[offset:] xv := alpha * x[ix] for j := 0; j < n-i; j++ { atmp[j] += xv * x[jx] jx += incX } ix += incX offset += n - i } return } if incX == 1 { for i := 0; i < n; i++ { atmp := ap[offset-i:] xv := alpha * x[i] xtmp := x[:i+1] for j, v := range xtmp { atmp[j] += xv * v } offset += i + 2 } return } ix := kx for i := 0; i < n; i++ { jx := kx atmp := ap[offset-i:] xv := alpha * x[ix] for j := 0; j <= i; j++ { atmp[j] += xv * x[jx] jx += incX } ix += incX offset += i + 2 } } // Dspr2 performs the symmetric 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 (Implementation) Dspr2(ul blas.Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, ap []float64) { if ul != blas.Lower && ul != blas.Upper { panic(badUplo) } if n < 0 { panic(nLT0) } if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } // Quick return if possible. if n == 0 { return } // For zero matrix size the following slice length checks are trivially satisfied. 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 len(ap) < n*(n+1)/2 { panic(shortAP) } // Quick return if possible. if alpha == 0 { return } var ky, kx int if incY < 0 { ky = -(n - 1) * incY } if incX < 0 { kx = -(n - 1) * incX } var offset int // Offset is the index of (i,i). if ul == blas.Upper { if incX == 1 && incY == 1 { for i := 0; i < n; i++ { atmp := ap[offset:] xi := x[i] yi := y[i] xtmp := x[i:n] ytmp := y[i:n] for j, v := range xtmp { atmp[j] += alpha * (xi*ytmp[j] + v*yi) } offset += n - i } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx + i*incX jy := ky + i*incY atmp := ap[offset:] xi := x[ix] yi := y[iy] for j := 0; j < n-i; j++ { atmp[j] += alpha * (xi*y[jy] + x[jx]*yi) jx += incX jy += incY } ix += incX iy += incY offset += n - i } return } if incX == 1 && incY == 1 { for i := 0; i < n; i++ { atmp := ap[offset-i:] xi := x[i] yi := y[i] xtmp := x[:i+1] for j, v := range xtmp { atmp[j] += alpha * (xi*y[j] + v*yi) } offset += i + 2 } return } ix := kx iy := ky for i := 0; i < n; i++ { jx := kx jy := ky atmp := ap[offset-i:] for j := 0; j <= i; j++ { atmp[j] += alpha * (x[ix]*y[jy] + x[jx]*y[iy]) jx += incX jy += incY } ix += incX iy += incY offset += i + 2 } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level2float64_test.go000066400000000000000000000024301450372207100236620ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func TestDgemv(t *testing.T) { testblas.DgemvTest(t, impl) } func TestDger(t *testing.T) { testblas.DgerTest(t, impl) } func TestDtxmv(t *testing.T) { testblas.DtxmvTest(t, impl) } func TestDgbmv(t *testing.T) { testblas.DgbmvTest(t, impl) } func TestDtbsv(t *testing.T) { testblas.DtbsvTest(t, impl) } func TestDsbmv(t *testing.T) { testblas.DsbmvTest(t, impl) } func TestDtbmv(t *testing.T) { testblas.DtbmvTest(t, impl) } func TestDtrsv(t *testing.T) { testblas.DtrsvTest(t, impl) } func TestDtrmv(t *testing.T) { testblas.DtrmvTest(t, impl) } func TestDsymv(t *testing.T) { testblas.DsymvTest(t, impl) } func TestDsyr(t *testing.T) { testblas.DsyrTest(t, impl) } func TestDsyr2(t *testing.T) { testblas.Dsyr2Test(t, impl) } func TestDspr2(t *testing.T) { testblas.Dspr2Test(t, impl) } func TestDspr(t *testing.T) { testblas.DsprTest(t, impl) } func TestDspmv(t *testing.T) { testblas.DspmvTest(t, impl) } func TestDtpsv(t *testing.T) { testblas.DtpsvTest(t, impl) } func TestDtpmv(t *testing.T) { testblas.DtpmvTest(t, impl) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level3cmplx128.go000066400000000000000000001171641450372207100227360ustar00rootroot00000000000000// Copyright ©2019 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/cmplx" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/internal/asm/c128" ) var _ blas.Complex128Level3 = Implementation{} // Zgemm performs one of the matrix-matrix operations // // C = alpha * op(A) * op(B) + beta * C // // where op(X) is one of // // op(X) = X or op(X) = Xᵀ or op(X) = Xᴴ, // // alpha and beta are scalars, and A, B and C are matrices, with op(A) an m×k matrix, // op(B) a k×n matrix and C an m×n matrix. func (Implementation) Zgemm(tA, tB blas.Transpose, m, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, 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: } switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) } rowA, colA := m, k if tA != blas.NoTrans { rowA, colA = k, m } if lda < max(1, colA) { panic(badLdA) } rowB, colB := k, n if tB != blas.NoTrans { rowB, colB = n, k } if ldb < max(1, colB) { 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) < (rowA-1)*lda+colA { panic(shortA) } if len(b) < (rowB-1)*ldb+colB { panic(shortB) } if len(c) < (m-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if beta == 0 { for i := 0; i < m; i++ { for j := 0; j < n; j++ { c[i*ldc+j] = 0 } } } else { for i := 0; i < m; i++ { for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } } return } switch tA { case blas.NoTrans: switch tB { case blas.NoTrans: // Form C = alpha * A * B + beta * C. for i := 0; i < m; i++ { switch { case beta == 0: for j := 0; j < n; j++ { c[i*ldc+j] = 0 } case beta != 1: for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } for l := 0; l < k; l++ { tmp := alpha * a[i*lda+l] for j := 0; j < n; j++ { c[i*ldc+j] += tmp * b[l*ldb+j] } } } case blas.Trans: // Form C = alpha * A * Bᵀ + beta * C. for i := 0; i < m; i++ { switch { case beta == 0: for j := 0; j < n; j++ { c[i*ldc+j] = 0 } case beta != 1: for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } for l := 0; l < k; l++ { tmp := alpha * a[i*lda+l] for j := 0; j < n; j++ { c[i*ldc+j] += tmp * b[j*ldb+l] } } } case blas.ConjTrans: // Form C = alpha * A * Bᴴ + beta * C. for i := 0; i < m; i++ { switch { case beta == 0: for j := 0; j < n; j++ { c[i*ldc+j] = 0 } case beta != 1: for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } for l := 0; l < k; l++ { tmp := alpha * a[i*lda+l] for j := 0; j < n; j++ { c[i*ldc+j] += tmp * cmplx.Conj(b[j*ldb+l]) } } } } case blas.Trans: switch tB { case blas.NoTrans: // Form C = alpha * Aᵀ * B + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex128 for l := 0; l < k; l++ { tmp += a[l*lda+i] * b[l*ldb+j] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.Trans: // Form C = alpha * Aᵀ * Bᵀ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex128 for l := 0; l < k; l++ { tmp += a[l*lda+i] * b[j*ldb+l] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.ConjTrans: // Form C = alpha * Aᵀ * Bᴴ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex128 for l := 0; l < k; l++ { tmp += a[l*lda+i] * cmplx.Conj(b[j*ldb+l]) } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } } case blas.ConjTrans: switch tB { case blas.NoTrans: // Form C = alpha * Aᴴ * B + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex128 for l := 0; l < k; l++ { tmp += cmplx.Conj(a[l*lda+i]) * b[l*ldb+j] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.Trans: // Form C = alpha * Aᴴ * Bᵀ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex128 for l := 0; l < k; l++ { tmp += cmplx.Conj(a[l*lda+i]) * b[j*ldb+l] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.ConjTrans: // Form C = alpha * Aᴴ * Bᴴ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex128 for l := 0; l < k; l++ { tmp += cmplx.Conj(a[l*lda+i]) * cmplx.Conj(b[j*ldb+l]) } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } } } } // Zhemm 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 alpha and beta are scalars, A is an m×m or n×n hermitian matrix and B // and C are m×n matrices. The imaginary parts of the diagonal elements of A are // assumed to be zero. func (Implementation) Zhemm(side blas.Side, uplo blas.Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case ldb < max(1, n): panic(badLdB) case 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*(na-1)+na { 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++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] c128.ScalUnitary(beta, ci) } } return } if side == blas.Left { // Form C = alpha*A*B + beta*C. for i := 0; i < m; i++ { atmp := alpha * complex(real(a[i*lda+i]), 0) bi := b[i*ldb : i*ldb+n] ci := c[i*ldc : i*ldc+n] if beta == 0 { for j, bij := range bi { ci[j] = atmp * bij } } else { for j, bij := range bi { ci[j] = atmp*bij + beta*ci[j] } } if uplo == blas.Upper { for k := 0; k < i; k++ { atmp = alpha * cmplx.Conj(a[k*lda+i]) c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * a[i*lda+k] c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } else { for k := 0; k < i; k++ { atmp = alpha * a[i*lda+k] c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * cmplx.Conj(a[k*lda+i]) c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } } } else { // Form C = alpha*B*A + beta*C. if uplo == blas.Upper { for i := 0; i < m; i++ { for j := n - 1; j >= 0; j-- { abij := alpha * b[i*ldb+j] aj := a[j*lda+j+1 : j*lda+n] bi := b[i*ldb+j+1 : i*ldb+n] ci := c[i*ldc+j+1 : i*ldc+n] var tmp complex128 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * cmplx.Conj(ajk) } ajj := complex(real(a[j*lda+j]), 0) if beta == 0 { c[i*ldc+j] = abij*ajj + alpha*tmp } else { c[i*ldc+j] = abij*ajj + alpha*tmp + beta*c[i*ldc+j] } } } } else { for i := 0; i < m; i++ { for j := 0; j < n; j++ { abij := alpha * b[i*ldb+j] aj := a[j*lda : j*lda+j] bi := b[i*ldb : i*ldb+j] ci := c[i*ldc : i*ldc+j] var tmp complex128 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * cmplx.Conj(ajk) } ajj := complex(real(a[j*lda+j]), 0) if beta == 0 { c[i*ldc+j] = abij*ajj + alpha*tmp } else { c[i*ldc+j] = abij*ajj + alpha*tmp + beta*c[i*ldc+j] } } } } } } // Zherk performs one of the hermitian rank-k operations // // C = alpha*A*Aᴴ + beta*C if trans == blas.NoTrans // C = alpha*Aᴴ*A + beta*C if trans == blas.ConjTrans // // where alpha and beta are real scalars, C is an n×n hermitian matrix and A is // an n×k matrix in the first case and a k×n matrix in the second case. // // The imaginary parts of the diagonal elements of C are assumed to be zero, and // on return they will be set to zero. func (Implementation) Zherk(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha float64, a []complex128, lda int, beta float64, c []complex128, ldc int) { var rowA, colA int switch trans { default: panic(badTranspose) case blas.NoTrans: rowA, colA = n, k case blas.ConjTrans: rowA, colA = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, colA): panic(badLdA) case 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) < (rowA-1)*lda+colA { panic(shortA) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ci[0] = complex(beta*real(ci[0]), 0) if i != n-1 { c128.DscalUnitary(beta, ci[1:]) } } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] if i != 0 { c128.DscalUnitary(beta, ci[:i]) } ci[i] = complex(beta*real(ci[i]), 0) } } } return } calpha := complex(alpha, 0) if trans == blas.NoTrans { // Form C = alpha*A*Aᴴ + beta*C. cbeta := complex(beta, 0) if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ai := a[i*lda : i*lda+k] switch { case beta == 0: // Handle the i-th diagonal element of C. ci[0] = complex(alpha*real(c128.DotcUnitary(ai, ai)), 0) // Handle the remaining elements on the i-th row of C. for jc := range ci[1:] { j := i + 1 + jc ci[jc+1] = calpha * c128.DotcUnitary(a[j*lda:j*lda+k], ai) } case beta != 1: cii := calpha*c128.DotcUnitary(ai, ai) + cbeta*ci[0] ci[0] = complex(real(cii), 0) for jc, cij := range ci[1:] { j := i + 1 + jc ci[jc+1] = calpha*c128.DotcUnitary(a[j*lda:j*lda+k], ai) + cbeta*cij } default: cii := calpha*c128.DotcUnitary(ai, ai) + ci[0] ci[0] = complex(real(cii), 0) for jc, cij := range ci[1:] { j := i + 1 + jc ci[jc+1] = calpha*c128.DotcUnitary(a[j*lda:j*lda+k], ai) + cij } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] ai := a[i*lda : i*lda+k] switch { case beta == 0: // Handle the first i-1 elements on the i-th row of C. for j := range ci[:i] { ci[j] = calpha * c128.DotcUnitary(a[j*lda:j*lda+k], ai) } // Handle the i-th diagonal element of C. ci[i] = complex(alpha*real(c128.DotcUnitary(ai, ai)), 0) case beta != 1: for j, cij := range ci[:i] { ci[j] = calpha*c128.DotcUnitary(a[j*lda:j*lda+k], ai) + cbeta*cij } cii := calpha*c128.DotcUnitary(ai, ai) + cbeta*ci[i] ci[i] = complex(real(cii), 0) default: for j, cij := range ci[:i] { ci[j] = calpha*c128.DotcUnitary(a[j*lda:j*lda+k], ai) + cij } cii := calpha*c128.DotcUnitary(ai, ai) + ci[i] ci[i] = complex(real(cii), 0) } } } } else { // Form C = alpha*Aᴴ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: c128.DscalUnitary(beta, ci) ci[0] = complex(real(ci[0]), 0) default: ci[0] = complex(real(ci[0]), 0) } for j := 0; j < k; j++ { aji := cmplx.Conj(a[j*lda+i]) if aji != 0 { c128.AxpyUnitary(calpha*aji, a[j*lda+i:j*lda+n], ci) } } c[i*ldc+i] = complex(real(c[i*ldc+i]), 0) } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: c128.DscalUnitary(beta, ci) ci[i] = complex(real(ci[i]), 0) default: ci[i] = complex(real(ci[i]), 0) } for j := 0; j < k; j++ { aji := cmplx.Conj(a[j*lda+i]) if aji != 0 { c128.AxpyUnitary(calpha*aji, a[j*lda:j*lda+i+1], ci) } } c[i*ldc+i] = complex(real(c[i*ldc+i]), 0) } } } } // Zher2k performs one of the hermitian rank-2k operations // // C = alpha*A*Bᴴ + conj(alpha)*B*Aᴴ + beta*C if trans == blas.NoTrans // C = alpha*Aᴴ*B + conj(alpha)*Bᴴ*A + beta*C if trans == blas.ConjTrans // // where alpha and beta are scalars with beta real, C is an n×n hermitian matrix // and A and B are n×k matrices in the first case and k×n matrices in the second case. // // The imaginary parts of the diagonal elements of C are assumed to be zero, and // on return they will be set to zero. func (Implementation) Zher2k(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta float64, c []complex128, ldc int) { var row, col int switch trans { default: panic(badTranspose) case blas.NoTrans: row, col = n, k case blas.ConjTrans: row, col = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, col): panic(badLdA) case ldb < max(1, col): panic(badLdB) case 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) < (row-1)*lda+col { panic(shortA) } if len(b) < (row-1)*ldb+col { panic(shortB) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ci[0] = complex(beta*real(ci[0]), 0) if i != n-1 { c128.DscalUnitary(beta, ci[1:]) } } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] if i != 0 { c128.DscalUnitary(beta, ci[:i]) } ci[i] = complex(beta*real(ci[i]), 0) } } } return } conjalpha := cmplx.Conj(alpha) cbeta := complex(beta, 0) if trans == blas.NoTrans { // Form C = alpha*A*Bᴴ + conj(alpha)*B*Aᴴ + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i+1 : i*ldc+n] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { cii := alpha*c128.DotcUnitary(bi, ai) + conjalpha*c128.DotcUnitary(ai, bi) c[i*ldc+i] = complex(real(cii), 0) for jc := range ci { j := i + 1 + jc ci[jc] = alpha*c128.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c128.DotcUnitary(a[j*lda:j*lda+k], bi) } } else { cii := alpha*c128.DotcUnitary(bi, ai) + conjalpha*c128.DotcUnitary(ai, bi) + cbeta*c[i*ldc+i] c[i*ldc+i] = complex(real(cii), 0) for jc, cij := range ci { j := i + 1 + jc ci[jc] = alpha*c128.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c128.DotcUnitary(a[j*lda:j*lda+k], bi) + cbeta*cij } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { for j := range ci { ci[j] = alpha*c128.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c128.DotcUnitary(a[j*lda:j*lda+k], bi) } cii := alpha*c128.DotcUnitary(bi, ai) + conjalpha*c128.DotcUnitary(ai, bi) c[i*ldc+i] = complex(real(cii), 0) } else { for j, cij := range ci { ci[j] = alpha*c128.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c128.DotcUnitary(a[j*lda:j*lda+k], bi) + cbeta*cij } cii := alpha*c128.DotcUnitary(bi, ai) + conjalpha*c128.DotcUnitary(ai, bi) + cbeta*c[i*ldc+i] c[i*ldc+i] = complex(real(cii), 0) } } } } else { // Form C = alpha*Aᴴ*B + conj(alpha)*Bᴴ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: c128.DscalUnitary(beta, ci) ci[0] = complex(real(ci[0]), 0) default: ci[0] = complex(real(ci[0]), 0) } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c128.AxpyUnitary(alpha*cmplx.Conj(aji), b[j*ldb+i:j*ldb+n], ci) } if bji != 0 { c128.AxpyUnitary(conjalpha*cmplx.Conj(bji), a[j*lda+i:j*lda+n], ci) } } ci[0] = complex(real(ci[0]), 0) } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: c128.DscalUnitary(beta, ci) ci[i] = complex(real(ci[i]), 0) default: ci[i] = complex(real(ci[i]), 0) } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c128.AxpyUnitary(alpha*cmplx.Conj(aji), b[j*ldb:j*ldb+i+1], ci) } if bji != 0 { c128.AxpyUnitary(conjalpha*cmplx.Conj(bji), a[j*lda:j*lda+i+1], ci) } } ci[i] = complex(real(ci[i]), 0) } } } } // Zsymm 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 alpha and beta are scalars, A is an m×m or n×n symmetric matrix and B // and C are m×n matrices. func (Implementation) Zsymm(side blas.Side, uplo blas.Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case ldb < max(1, n): panic(badLdB) case 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*(na-1)+na { 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++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] c128.ScalUnitary(beta, ci) } } return } if side == blas.Left { // Form C = alpha*A*B + beta*C. for i := 0; i < m; i++ { atmp := alpha * a[i*lda+i] bi := b[i*ldb : i*ldb+n] ci := c[i*ldc : i*ldc+n] if beta == 0 { for j, bij := range bi { ci[j] = atmp * bij } } else { for j, bij := range bi { ci[j] = atmp*bij + beta*ci[j] } } if uplo == blas.Upper { for k := 0; k < i; k++ { atmp = alpha * a[k*lda+i] c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * a[i*lda+k] c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } else { for k := 0; k < i; k++ { atmp = alpha * a[i*lda+k] c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * a[k*lda+i] c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } } } else { // Form C = alpha*B*A + beta*C. if uplo == blas.Upper { for i := 0; i < m; i++ { for j := n - 1; j >= 0; j-- { abij := alpha * b[i*ldb+j] aj := a[j*lda+j+1 : j*lda+n] bi := b[i*ldb+j+1 : i*ldb+n] ci := c[i*ldc+j+1 : i*ldc+n] var tmp complex128 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * ajk } if beta == 0 { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp } else { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp + beta*c[i*ldc+j] } } } } else { for i := 0; i < m; i++ { for j := 0; j < n; j++ { abij := alpha * b[i*ldb+j] aj := a[j*lda : j*lda+j] bi := b[i*ldb : i*ldb+j] ci := c[i*ldc : i*ldc+j] var tmp complex128 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * ajk } if beta == 0 { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp } else { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp + beta*c[i*ldc+j] } } } } } } // Zsyrk performs one of the symmetric rank-k operations // // C = alpha*A*Aᵀ + beta*C if trans == blas.NoTrans // C = alpha*Aᵀ*A + beta*C if trans == blas.Trans // // where alpha and beta are scalars, C is an n×n symmetric matrix and A is // an n×k matrix in the first case and a k×n matrix in the second case. func (Implementation) Zsyrk(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, beta complex128, c []complex128, ldc int) { var rowA, colA int switch trans { default: panic(badTranspose) case blas.NoTrans: rowA, colA = n, k case blas.Trans: rowA, colA = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, colA): panic(badLdA) case 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) < (rowA-1)*lda+colA { panic(shortA) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] c128.ScalUnitary(beta, ci) } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] c128.ScalUnitary(beta, ci) } } } return } if trans == blas.NoTrans { // Form C = alpha*A*Aᵀ + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ai := a[i*lda : i*lda+k] if beta == 0 { for jc := range ci { j := i + jc ci[jc] = alpha * c128.DotuUnitary(ai, a[j*lda:j*lda+k]) } } else { for jc, cij := range ci { j := i + jc ci[jc] = beta*cij + alpha*c128.DotuUnitary(ai, a[j*lda:j*lda+k]) } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] ai := a[i*lda : i*lda+k] if beta == 0 { for j := range ci { ci[j] = alpha * c128.DotuUnitary(ai, a[j*lda:j*lda+k]) } } else { for j, cij := range ci { ci[j] = beta*cij + alpha*c128.DotuUnitary(ai, a[j*lda:j*lda+k]) } } } } } else { // Form C = alpha*Aᵀ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: for jc := range ci { ci[jc] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] if aji != 0 { c128.AxpyUnitary(alpha*aji, a[j*lda+i:j*lda+n], ci) } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: for j := range ci { ci[j] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] if aji != 0 { c128.AxpyUnitary(alpha*aji, a[j*lda:j*lda+i+1], ci) } } } } } } // Zsyr2k performs one of the symmetric rank-2k operations // // C = alpha*A*Bᵀ + alpha*B*Aᵀ + beta*C if trans == blas.NoTrans // C = alpha*Aᵀ*B + alpha*Bᵀ*A + beta*C if trans == blas.Trans // // where alpha and beta are scalars, C is an n×n symmetric matrix and A and B // are n×k matrices in the first case and k×n matrices in the second case. func (Implementation) Zsyr2k(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) { var row, col int switch trans { default: panic(badTranspose) case blas.NoTrans: row, col = n, k case blas.Trans: row, col = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, col): panic(badLdA) case ldb < max(1, col): panic(badLdB) case 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) < (row-1)*lda+col { panic(shortA) } if len(b) < (row-1)*ldb+col { panic(shortB) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] c128.ScalUnitary(beta, ci) } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] c128.ScalUnitary(beta, ci) } } } return } if trans == blas.NoTrans { // Form C = alpha*A*Bᵀ + alpha*B*Aᵀ + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { for jc := range ci { j := i + jc ci[jc] = alpha*c128.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c128.DotuUnitary(bi, a[j*lda:j*lda+k]) } } else { for jc, cij := range ci { j := i + jc ci[jc] = alpha*c128.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c128.DotuUnitary(bi, a[j*lda:j*lda+k]) + beta*cij } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { for j := range ci { ci[j] = alpha*c128.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c128.DotuUnitary(bi, a[j*lda:j*lda+k]) } } else { for j, cij := range ci { ci[j] = alpha*c128.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c128.DotuUnitary(bi, a[j*lda:j*lda+k]) + beta*cij } } } } } else { // Form C = alpha*Aᵀ*B + alpha*Bᵀ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: for jc := range ci { ci[jc] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c128.AxpyUnitary(alpha*aji, b[j*ldb+i:j*ldb+n], ci) } if bji != 0 { c128.AxpyUnitary(alpha*bji, a[j*lda+i:j*lda+n], ci) } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: for j := range ci { ci[j] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c128.AxpyUnitary(alpha*aji, b[j*ldb:j*ldb+i+1], ci) } if bji != 0 { c128.AxpyUnitary(alpha*bji, a[j*lda:j*lda+i+1], ci) } } } } } } // Ztrmm performs one of the matrix-matrix operations // // B = alpha * op(A) * B if side == blas.Left, // B = alpha * B * op(A) if side == blas.Right, // // where alpha is a scalar, B is an m×n matrix, A is a unit, or non-unit, // upper or lower triangular matrix and op(A) is one of // // op(A) = A if trans == blas.NoTrans, // op(A) = Aᵀ if trans == blas.Trans, // op(A) = Aᴴ if trans == blas.ConjTrans. func (Implementation) Ztrmm(side blas.Side, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTranspose) case diag != blas.Unit && diag != blas.NonUnit: panic(badDiag) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case 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) < (na-1)*lda+na { panic(shortA) } if len(b) < (m-1)*ldb+n { panic(shortB) } // Quick return if possible. if alpha == 0 { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j := range bi { bi[j] = 0 } } return } noConj := trans != blas.ConjTrans noUnit := diag == blas.NonUnit if side == blas.Left { if trans == blas.NoTrans { // Form B = alpha*A*B. if uplo == blas.Upper { for i := 0; i < m; i++ { aii := alpha if noUnit { aii *= a[i*lda+i] } bi := b[i*ldb : i*ldb+n] for j := range bi { bi[j] *= aii } for ja, aij := range a[i*lda+i+1 : i*lda+m] { j := ja + i + 1 if aij != 0 { c128.AxpyUnitary(alpha*aij, b[j*ldb:j*ldb+n], bi) } } } } else { for i := m - 1; i >= 0; i-- { aii := alpha if noUnit { aii *= a[i*lda+i] } bi := b[i*ldb : i*ldb+n] for j := range bi { bi[j] *= aii } for j, aij := range a[i*lda : i*lda+i] { if aij != 0 { c128.AxpyUnitary(alpha*aij, b[j*ldb:j*ldb+n], bi) } } } } } else { // Form B = alpha*Aᵀ*B or B = alpha*Aᴴ*B. if uplo == blas.Upper { for k := m - 1; k >= 0; k-- { bk := b[k*ldb : k*ldb+n] for ja, ajk := range a[k*lda+k+1 : k*lda+m] { if ajk == 0 { continue } j := k + 1 + ja if noConj { c128.AxpyUnitary(alpha*ajk, bk, b[j*ldb:j*ldb+n]) } else { c128.AxpyUnitary(alpha*cmplx.Conj(ajk), bk, b[j*ldb:j*ldb+n]) } } akk := alpha if noUnit { if noConj { akk *= a[k*lda+k] } else { akk *= cmplx.Conj(a[k*lda+k]) } } if akk != 1 { c128.ScalUnitary(akk, bk) } } } else { for k := 0; k < m; k++ { bk := b[k*ldb : k*ldb+n] for j, ajk := range a[k*lda : k*lda+k] { if ajk == 0 { continue } if noConj { c128.AxpyUnitary(alpha*ajk, bk, b[j*ldb:j*ldb+n]) } else { c128.AxpyUnitary(alpha*cmplx.Conj(ajk), bk, b[j*ldb:j*ldb+n]) } } akk := alpha if noUnit { if noConj { akk *= a[k*lda+k] } else { akk *= cmplx.Conj(a[k*lda+k]) } } if akk != 1 { c128.ScalUnitary(akk, bk) } } } } } else { if trans == blas.NoTrans { // Form B = alpha*B*A. if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for k := n - 1; k >= 0; k-- { abik := alpha * bi[k] if abik == 0 { continue } bi[k] = abik if noUnit { bi[k] *= a[k*lda+k] } c128.AxpyUnitary(abik, a[k*lda+k+1:k*lda+n], bi[k+1:]) } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for k := 0; k < n; k++ { abik := alpha * bi[k] if abik == 0 { continue } bi[k] = abik if noUnit { bi[k] *= a[k*lda+k] } c128.AxpyUnitary(abik, a[k*lda:k*lda+k], bi[:k]) } } } } else { // Form B = alpha*B*Aᵀ or B = alpha*B*Aᴴ. if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j, bij := range bi { if noConj { if noUnit { bij *= a[j*lda+j] } bij += c128.DotuUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) } else { if noUnit { bij *= cmplx.Conj(a[j*lda+j]) } bij += c128.DotcUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) } bi[j] = alpha * bij } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j := n - 1; j >= 0; j-- { bij := bi[j] if noConj { if noUnit { bij *= a[j*lda+j] } bij += c128.DotuUnitary(a[j*lda:j*lda+j], bi[:j]) } else { if noUnit { bij *= cmplx.Conj(a[j*lda+j]) } bij += c128.DotcUnitary(a[j*lda:j*lda+j], bi[:j]) } bi[j] = alpha * bij } } } } } } // Ztrsm solves one of the matrix equations // // op(A) * X = alpha * B if side == blas.Left, // X * op(A) = alpha * B if side == blas.Right, // // where alpha is a scalar, X and B are m×n matrices, A is a unit or // non-unit, upper or lower triangular matrix and op(A) is one of // // op(A) = A if transA == blas.NoTrans, // op(A) = Aᵀ if transA == blas.Trans, // op(A) = Aᴴ if transA == blas.ConjTrans. // // On return the matrix X is overwritten on B. func (Implementation) Ztrsm(side blas.Side, uplo blas.Uplo, transA blas.Transpose, diag blas.Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case transA != blas.NoTrans && transA != blas.Trans && transA != blas.ConjTrans: panic(badTranspose) case diag != blas.Unit && diag != blas.NonUnit: panic(badDiag) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case 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) < (na-1)*lda+na { panic(shortA) } if len(b) < (m-1)*ldb+n { panic(shortB) } if alpha == 0 { for i := 0; i < m; i++ { for j := 0; j < n; j++ { b[i*ldb+j] = 0 } } return } noConj := transA != blas.ConjTrans noUnit := diag == blas.NonUnit if side == blas.Left { if transA == blas.NoTrans { // Form B = alpha*inv(A)*B. if uplo == blas.Upper { for i := m - 1; i >= 0; i-- { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c128.ScalUnitary(alpha, bi) } for ka, aik := range a[i*lda+i+1 : i*lda+m] { k := i + 1 + ka if aik != 0 { c128.AxpyUnitary(-aik, b[k*ldb:k*ldb+n], bi) } } if noUnit { c128.ScalUnitary(1/a[i*lda+i], bi) } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c128.ScalUnitary(alpha, bi) } for j, aij := range a[i*lda : i*lda+i] { if aij != 0 { c128.AxpyUnitary(-aij, b[j*ldb:j*ldb+n], bi) } } if noUnit { c128.ScalUnitary(1/a[i*lda+i], bi) } } } } else { // Form B = alpha*inv(Aᵀ)*B or B = alpha*inv(Aᴴ)*B. if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if noUnit { if noConj { c128.ScalUnitary(1/a[i*lda+i], bi) } else { c128.ScalUnitary(1/cmplx.Conj(a[i*lda+i]), bi) } } for ja, aij := range a[i*lda+i+1 : i*lda+m] { if aij == 0 { continue } j := i + 1 + ja if noConj { c128.AxpyUnitary(-aij, bi, b[j*ldb:j*ldb+n]) } else { c128.AxpyUnitary(-cmplx.Conj(aij), bi, b[j*ldb:j*ldb+n]) } } if alpha != 1 { c128.ScalUnitary(alpha, bi) } } } else { for i := m - 1; i >= 0; i-- { bi := b[i*ldb : i*ldb+n] if noUnit { if noConj { c128.ScalUnitary(1/a[i*lda+i], bi) } else { c128.ScalUnitary(1/cmplx.Conj(a[i*lda+i]), bi) } } for j, aij := range a[i*lda : i*lda+i] { if aij == 0 { continue } if noConj { c128.AxpyUnitary(-aij, bi, b[j*ldb:j*ldb+n]) } else { c128.AxpyUnitary(-cmplx.Conj(aij), bi, b[j*ldb:j*ldb+n]) } } if alpha != 1 { c128.ScalUnitary(alpha, bi) } } } } } else { if transA == blas.NoTrans { // Form B = alpha*B*inv(A). if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c128.ScalUnitary(alpha, bi) } for j, bij := range bi { if bij == 0 { continue } if noUnit { bi[j] /= a[j*lda+j] } c128.AxpyUnitary(-bi[j], a[j*lda+j+1:j*lda+n], bi[j+1:n]) } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c128.ScalUnitary(alpha, bi) } for j := n - 1; j >= 0; j-- { if bi[j] == 0 { continue } if noUnit { bi[j] /= a[j*lda+j] } c128.AxpyUnitary(-bi[j], a[j*lda:j*lda+j], bi[:j]) } } } } else { // Form B = alpha*B*inv(Aᵀ) or B = alpha*B*inv(Aᴴ). if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j := n - 1; j >= 0; j-- { bij := alpha * bi[j] if noConj { bij -= c128.DotuUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) if noUnit { bij /= a[j*lda+j] } } else { bij -= c128.DotcUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) if noUnit { bij /= cmplx.Conj(a[j*lda+j]) } } bi[j] = bij } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j, bij := range bi { bij *= alpha if noConj { bij -= c128.DotuUnitary(a[j*lda:j*lda+j], bi[:j]) if noUnit { bij /= a[j*lda+j] } } else { bij -= c128.DotcUnitary(a[j*lda:j*lda+j], bi[:j]) if noUnit { bij /= cmplx.Conj(a[j*lda+j]) } } bi[j] = bij } } } } } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level3cmplx128_test.go000066400000000000000000000014401450372207100237620ustar00rootroot00000000000000// Copyright ©2019 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func TestZgemm(t *testing.T) { testblas.ZgemmTest(t, impl) } func TestZhemm(t *testing.T) { testblas.ZhemmTest(t, impl) } func TestZherk(t *testing.T) { testblas.ZherkTest(t, impl) } func TestZher2k(t *testing.T) { testblas.Zher2kTest(t, impl) } func TestZsymm(t *testing.T) { testblas.ZsymmTest(t, impl) } func TestZsyrk(t *testing.T) { testblas.ZsyrkTest(t, impl) } func TestZsyr2k(t *testing.T) { testblas.Zsyr2kTest(t, impl) } func TestZtrmm(t *testing.T) { testblas.ZtrmmTest(t, impl) } func TestZtrsm(t *testing.T) { testblas.ZtrsmTest(t, impl) } golang-gonum-v1-gonum-0.14.0/blas/gonum/level3cmplx64.go000066400000000000000000001203501450372207100226440ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT. // Copyright ©2019 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 ( cmplx "gonum.org/v1/gonum/internal/cmplx64" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/internal/asm/c64" ) var _ blas.Complex64Level3 = Implementation{} // Cgemm performs one of the matrix-matrix operations // // C = alpha * op(A) * op(B) + beta * C // // where op(X) is one of // // op(X) = X or op(X) = Xᵀ or op(X) = Xᴴ, // // alpha and beta are scalars, and A, B and C are matrices, with op(A) an m×k matrix, // op(B) a k×n matrix and C an m×n matrix. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cgemm(tA, tB blas.Transpose, m, n, k int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, 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: } switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) } rowA, colA := m, k if tA != blas.NoTrans { rowA, colA = k, m } if lda < max(1, colA) { panic(badLdA) } rowB, colB := k, n if tB != blas.NoTrans { rowB, colB = n, k } if ldb < max(1, colB) { 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) < (rowA-1)*lda+colA { panic(shortA) } if len(b) < (rowB-1)*ldb+colB { panic(shortB) } if len(c) < (m-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if beta == 0 { for i := 0; i < m; i++ { for j := 0; j < n; j++ { c[i*ldc+j] = 0 } } } else { for i := 0; i < m; i++ { for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } } return } switch tA { case blas.NoTrans: switch tB { case blas.NoTrans: // Form C = alpha * A * B + beta * C. for i := 0; i < m; i++ { switch { case beta == 0: for j := 0; j < n; j++ { c[i*ldc+j] = 0 } case beta != 1: for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } for l := 0; l < k; l++ { tmp := alpha * a[i*lda+l] for j := 0; j < n; j++ { c[i*ldc+j] += tmp * b[l*ldb+j] } } } case blas.Trans: // Form C = alpha * A * Bᵀ + beta * C. for i := 0; i < m; i++ { switch { case beta == 0: for j := 0; j < n; j++ { c[i*ldc+j] = 0 } case beta != 1: for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } for l := 0; l < k; l++ { tmp := alpha * a[i*lda+l] for j := 0; j < n; j++ { c[i*ldc+j] += tmp * b[j*ldb+l] } } } case blas.ConjTrans: // Form C = alpha * A * Bᴴ + beta * C. for i := 0; i < m; i++ { switch { case beta == 0: for j := 0; j < n; j++ { c[i*ldc+j] = 0 } case beta != 1: for j := 0; j < n; j++ { c[i*ldc+j] *= beta } } for l := 0; l < k; l++ { tmp := alpha * a[i*lda+l] for j := 0; j < n; j++ { c[i*ldc+j] += tmp * cmplx.Conj(b[j*ldb+l]) } } } } case blas.Trans: switch tB { case blas.NoTrans: // Form C = alpha * Aᵀ * B + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex64 for l := 0; l < k; l++ { tmp += a[l*lda+i] * b[l*ldb+j] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.Trans: // Form C = alpha * Aᵀ * Bᵀ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex64 for l := 0; l < k; l++ { tmp += a[l*lda+i] * b[j*ldb+l] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.ConjTrans: // Form C = alpha * Aᵀ * Bᴴ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex64 for l := 0; l < k; l++ { tmp += a[l*lda+i] * cmplx.Conj(b[j*ldb+l]) } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } } case blas.ConjTrans: switch tB { case blas.NoTrans: // Form C = alpha * Aᴴ * B + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex64 for l := 0; l < k; l++ { tmp += cmplx.Conj(a[l*lda+i]) * b[l*ldb+j] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.Trans: // Form C = alpha * Aᴴ * Bᵀ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex64 for l := 0; l < k; l++ { tmp += cmplx.Conj(a[l*lda+i]) * b[j*ldb+l] } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } case blas.ConjTrans: // Form C = alpha * Aᴴ * Bᴴ + beta * C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { var tmp complex64 for l := 0; l < k; l++ { tmp += cmplx.Conj(a[l*lda+i]) * cmplx.Conj(b[j*ldb+l]) } if beta == 0 { c[i*ldc+j] = alpha * tmp } else { c[i*ldc+j] = alpha*tmp + beta*c[i*ldc+j] } } } } } } // Chemm 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 alpha and beta are scalars, A is an m×m or n×n hermitian matrix and B // and C are m×n matrices. The imaginary parts of the diagonal elements of A are // assumed to be zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Chemm(side blas.Side, uplo blas.Uplo, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, ldc int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case ldb < max(1, n): panic(badLdB) case 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*(na-1)+na { 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++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] c64.ScalUnitary(beta, ci) } } return } if side == blas.Left { // Form C = alpha*A*B + beta*C. for i := 0; i < m; i++ { atmp := alpha * complex(real(a[i*lda+i]), 0) bi := b[i*ldb : i*ldb+n] ci := c[i*ldc : i*ldc+n] if beta == 0 { for j, bij := range bi { ci[j] = atmp * bij } } else { for j, bij := range bi { ci[j] = atmp*bij + beta*ci[j] } } if uplo == blas.Upper { for k := 0; k < i; k++ { atmp = alpha * cmplx.Conj(a[k*lda+i]) c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * a[i*lda+k] c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } else { for k := 0; k < i; k++ { atmp = alpha * a[i*lda+k] c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * cmplx.Conj(a[k*lda+i]) c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } } } else { // Form C = alpha*B*A + beta*C. if uplo == blas.Upper { for i := 0; i < m; i++ { for j := n - 1; j >= 0; j-- { abij := alpha * b[i*ldb+j] aj := a[j*lda+j+1 : j*lda+n] bi := b[i*ldb+j+1 : i*ldb+n] ci := c[i*ldc+j+1 : i*ldc+n] var tmp complex64 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * cmplx.Conj(ajk) } ajj := complex(real(a[j*lda+j]), 0) if beta == 0 { c[i*ldc+j] = abij*ajj + alpha*tmp } else { c[i*ldc+j] = abij*ajj + alpha*tmp + beta*c[i*ldc+j] } } } } else { for i := 0; i < m; i++ { for j := 0; j < n; j++ { abij := alpha * b[i*ldb+j] aj := a[j*lda : j*lda+j] bi := b[i*ldb : i*ldb+j] ci := c[i*ldc : i*ldc+j] var tmp complex64 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * cmplx.Conj(ajk) } ajj := complex(real(a[j*lda+j]), 0) if beta == 0 { c[i*ldc+j] = abij*ajj + alpha*tmp } else { c[i*ldc+j] = abij*ajj + alpha*tmp + beta*c[i*ldc+j] } } } } } } // Cherk performs one of the hermitian rank-k operations // // C = alpha*A*Aᴴ + beta*C if trans == blas.NoTrans // C = alpha*Aᴴ*A + beta*C if trans == blas.ConjTrans // // where alpha and beta are real scalars, C is an n×n hermitian matrix and A is // an n×k matrix in the first case and a k×n matrix in the second case. // // The imaginary parts of the diagonal elements of C are assumed to be zero, and // on return they will be set to zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cherk(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha float32, a []complex64, lda int, beta float32, c []complex64, ldc int) { var rowA, colA int switch trans { default: panic(badTranspose) case blas.NoTrans: rowA, colA = n, k case blas.ConjTrans: rowA, colA = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, colA): panic(badLdA) case 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) < (rowA-1)*lda+colA { panic(shortA) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ci[0] = complex(beta*real(ci[0]), 0) if i != n-1 { c64.SscalUnitary(beta, ci[1:]) } } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] if i != 0 { c64.SscalUnitary(beta, ci[:i]) } ci[i] = complex(beta*real(ci[i]), 0) } } } return } calpha := complex(alpha, 0) if trans == blas.NoTrans { // Form C = alpha*A*Aᴴ + beta*C. cbeta := complex(beta, 0) if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ai := a[i*lda : i*lda+k] switch { case beta == 0: // Handle the i-th diagonal element of C. ci[0] = complex(alpha*real(c64.DotcUnitary(ai, ai)), 0) // Handle the remaining elements on the i-th row of C. for jc := range ci[1:] { j := i + 1 + jc ci[jc+1] = calpha * c64.DotcUnitary(a[j*lda:j*lda+k], ai) } case beta != 1: cii := calpha*c64.DotcUnitary(ai, ai) + cbeta*ci[0] ci[0] = complex(real(cii), 0) for jc, cij := range ci[1:] { j := i + 1 + jc ci[jc+1] = calpha*c64.DotcUnitary(a[j*lda:j*lda+k], ai) + cbeta*cij } default: cii := calpha*c64.DotcUnitary(ai, ai) + ci[0] ci[0] = complex(real(cii), 0) for jc, cij := range ci[1:] { j := i + 1 + jc ci[jc+1] = calpha*c64.DotcUnitary(a[j*lda:j*lda+k], ai) + cij } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] ai := a[i*lda : i*lda+k] switch { case beta == 0: // Handle the first i-1 elements on the i-th row of C. for j := range ci[:i] { ci[j] = calpha * c64.DotcUnitary(a[j*lda:j*lda+k], ai) } // Handle the i-th diagonal element of C. ci[i] = complex(alpha*real(c64.DotcUnitary(ai, ai)), 0) case beta != 1: for j, cij := range ci[:i] { ci[j] = calpha*c64.DotcUnitary(a[j*lda:j*lda+k], ai) + cbeta*cij } cii := calpha*c64.DotcUnitary(ai, ai) + cbeta*ci[i] ci[i] = complex(real(cii), 0) default: for j, cij := range ci[:i] { ci[j] = calpha*c64.DotcUnitary(a[j*lda:j*lda+k], ai) + cij } cii := calpha*c64.DotcUnitary(ai, ai) + ci[i] ci[i] = complex(real(cii), 0) } } } } else { // Form C = alpha*Aᴴ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: c64.SscalUnitary(beta, ci) ci[0] = complex(real(ci[0]), 0) default: ci[0] = complex(real(ci[0]), 0) } for j := 0; j < k; j++ { aji := cmplx.Conj(a[j*lda+i]) if aji != 0 { c64.AxpyUnitary(calpha*aji, a[j*lda+i:j*lda+n], ci) } } c[i*ldc+i] = complex(real(c[i*ldc+i]), 0) } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: c64.SscalUnitary(beta, ci) ci[i] = complex(real(ci[i]), 0) default: ci[i] = complex(real(ci[i]), 0) } for j := 0; j < k; j++ { aji := cmplx.Conj(a[j*lda+i]) if aji != 0 { c64.AxpyUnitary(calpha*aji, a[j*lda:j*lda+i+1], ci) } } c[i*ldc+i] = complex(real(c[i*ldc+i]), 0) } } } } // Cher2k performs one of the hermitian rank-2k operations // // C = alpha*A*Bᴴ + conj(alpha)*B*Aᴴ + beta*C if trans == blas.NoTrans // C = alpha*Aᴴ*B + conj(alpha)*Bᴴ*A + beta*C if trans == blas.ConjTrans // // where alpha and beta are scalars with beta real, C is an n×n hermitian matrix // and A and B are n×k matrices in the first case and k×n matrices in the second case. // // The imaginary parts of the diagonal elements of C are assumed to be zero, and // on return they will be set to zero. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Cher2k(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta float32, c []complex64, ldc int) { var row, col int switch trans { default: panic(badTranspose) case blas.NoTrans: row, col = n, k case blas.ConjTrans: row, col = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, col): panic(badLdA) case ldb < max(1, col): panic(badLdB) case 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) < (row-1)*lda+col { panic(shortA) } if len(b) < (row-1)*ldb+col { panic(shortB) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ci[0] = complex(beta*real(ci[0]), 0) if i != n-1 { c64.SscalUnitary(beta, ci[1:]) } } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] if i != 0 { c64.SscalUnitary(beta, ci[:i]) } ci[i] = complex(beta*real(ci[i]), 0) } } } return } conjalpha := cmplx.Conj(alpha) cbeta := complex(beta, 0) if trans == blas.NoTrans { // Form C = alpha*A*Bᴴ + conj(alpha)*B*Aᴴ + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i+1 : i*ldc+n] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { cii := alpha*c64.DotcUnitary(bi, ai) + conjalpha*c64.DotcUnitary(ai, bi) c[i*ldc+i] = complex(real(cii), 0) for jc := range ci { j := i + 1 + jc ci[jc] = alpha*c64.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c64.DotcUnitary(a[j*lda:j*lda+k], bi) } } else { cii := alpha*c64.DotcUnitary(bi, ai) + conjalpha*c64.DotcUnitary(ai, bi) + cbeta*c[i*ldc+i] c[i*ldc+i] = complex(real(cii), 0) for jc, cij := range ci { j := i + 1 + jc ci[jc] = alpha*c64.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c64.DotcUnitary(a[j*lda:j*lda+k], bi) + cbeta*cij } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { for j := range ci { ci[j] = alpha*c64.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c64.DotcUnitary(a[j*lda:j*lda+k], bi) } cii := alpha*c64.DotcUnitary(bi, ai) + conjalpha*c64.DotcUnitary(ai, bi) c[i*ldc+i] = complex(real(cii), 0) } else { for j, cij := range ci { ci[j] = alpha*c64.DotcUnitary(b[j*ldb:j*ldb+k], ai) + conjalpha*c64.DotcUnitary(a[j*lda:j*lda+k], bi) + cbeta*cij } cii := alpha*c64.DotcUnitary(bi, ai) + conjalpha*c64.DotcUnitary(ai, bi) + cbeta*c[i*ldc+i] c[i*ldc+i] = complex(real(cii), 0) } } } } else { // Form C = alpha*Aᴴ*B + conj(alpha)*Bᴴ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: c64.SscalUnitary(beta, ci) ci[0] = complex(real(ci[0]), 0) default: ci[0] = complex(real(ci[0]), 0) } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c64.AxpyUnitary(alpha*cmplx.Conj(aji), b[j*ldb+i:j*ldb+n], ci) } if bji != 0 { c64.AxpyUnitary(conjalpha*cmplx.Conj(bji), a[j*lda+i:j*lda+n], ci) } } ci[0] = complex(real(ci[0]), 0) } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: c64.SscalUnitary(beta, ci) ci[i] = complex(real(ci[i]), 0) default: ci[i] = complex(real(ci[i]), 0) } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c64.AxpyUnitary(alpha*cmplx.Conj(aji), b[j*ldb:j*ldb+i+1], ci) } if bji != 0 { c64.AxpyUnitary(conjalpha*cmplx.Conj(bji), a[j*lda:j*lda+i+1], ci) } } ci[i] = complex(real(ci[i]), 0) } } } } // Csymm 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 alpha and beta are scalars, A is an m×m or n×n symmetric matrix and B // and C are m×n matrices. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Csymm(side blas.Side, uplo blas.Uplo, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, ldc int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case ldb < max(1, n): panic(badLdB) case 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*(na-1)+na { 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++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] c64.ScalUnitary(beta, ci) } } return } if side == blas.Left { // Form C = alpha*A*B + beta*C. for i := 0; i < m; i++ { atmp := alpha * a[i*lda+i] bi := b[i*ldb : i*ldb+n] ci := c[i*ldc : i*ldc+n] if beta == 0 { for j, bij := range bi { ci[j] = atmp * bij } } else { for j, bij := range bi { ci[j] = atmp*bij + beta*ci[j] } } if uplo == blas.Upper { for k := 0; k < i; k++ { atmp = alpha * a[k*lda+i] c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * a[i*lda+k] c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } else { for k := 0; k < i; k++ { atmp = alpha * a[i*lda+k] c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } for k := i + 1; k < m; k++ { atmp = alpha * a[k*lda+i] c64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci) } } } } else { // Form C = alpha*B*A + beta*C. if uplo == blas.Upper { for i := 0; i < m; i++ { for j := n - 1; j >= 0; j-- { abij := alpha * b[i*ldb+j] aj := a[j*lda+j+1 : j*lda+n] bi := b[i*ldb+j+1 : i*ldb+n] ci := c[i*ldc+j+1 : i*ldc+n] var tmp complex64 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * ajk } if beta == 0 { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp } else { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp + beta*c[i*ldc+j] } } } } else { for i := 0; i < m; i++ { for j := 0; j < n; j++ { abij := alpha * b[i*ldb+j] aj := a[j*lda : j*lda+j] bi := b[i*ldb : i*ldb+j] ci := c[i*ldc : i*ldc+j] var tmp complex64 for k, ajk := range aj { ci[k] += abij * ajk tmp += bi[k] * ajk } if beta == 0 { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp } else { c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp + beta*c[i*ldc+j] } } } } } } // Csyrk performs one of the symmetric rank-k operations // // C = alpha*A*Aᵀ + beta*C if trans == blas.NoTrans // C = alpha*Aᵀ*A + beta*C if trans == blas.Trans // // where alpha and beta are scalars, C is an n×n symmetric matrix and A is // an n×k matrix in the first case and a k×n matrix in the second case. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Csyrk(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex64, a []complex64, lda int, beta complex64, c []complex64, ldc int) { var rowA, colA int switch trans { default: panic(badTranspose) case blas.NoTrans: rowA, colA = n, k case blas.Trans: rowA, colA = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, colA): panic(badLdA) case 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) < (rowA-1)*lda+colA { panic(shortA) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] c64.ScalUnitary(beta, ci) } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] c64.ScalUnitary(beta, ci) } } } return } if trans == blas.NoTrans { // Form C = alpha*A*Aᵀ + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ai := a[i*lda : i*lda+k] if beta == 0 { for jc := range ci { j := i + jc ci[jc] = alpha * c64.DotuUnitary(ai, a[j*lda:j*lda+k]) } } else { for jc, cij := range ci { j := i + jc ci[jc] = beta*cij + alpha*c64.DotuUnitary(ai, a[j*lda:j*lda+k]) } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] ai := a[i*lda : i*lda+k] if beta == 0 { for j := range ci { ci[j] = alpha * c64.DotuUnitary(ai, a[j*lda:j*lda+k]) } } else { for j, cij := range ci { ci[j] = beta*cij + alpha*c64.DotuUnitary(ai, a[j*lda:j*lda+k]) } } } } } else { // Form C = alpha*Aᵀ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: for jc := range ci { ci[jc] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] if aji != 0 { c64.AxpyUnitary(alpha*aji, a[j*lda+i:j*lda+n], ci) } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: for j := range ci { ci[j] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] if aji != 0 { c64.AxpyUnitary(alpha*aji, a[j*lda:j*lda+i+1], ci) } } } } } } // Csyr2k performs one of the symmetric rank-2k operations // // C = alpha*A*Bᵀ + alpha*B*Aᵀ + beta*C if trans == blas.NoTrans // C = alpha*Aᵀ*B + alpha*Bᵀ*A + beta*C if trans == blas.Trans // // where alpha and beta are scalars, C is an n×n symmetric matrix and A and B // are n×k matrices in the first case and k×n matrices in the second case. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Csyr2k(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, ldc int) { var row, col int switch trans { default: panic(badTranspose) case blas.NoTrans: row, col = n, k case blas.Trans: row, col = k, n } switch { case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case lda < max(1, col): panic(badLdA) case ldb < max(1, col): panic(badLdB) case 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) < (row-1)*lda+col { panic(shortA) } if len(b) < (row-1)*ldb+col { panic(shortB) } if len(c) < (n-1)*ldc+n { panic(shortC) } // Quick return if possible. if (alpha == 0 || k == 0) && beta == 1 { return } if alpha == 0 { if uplo == blas.Upper { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] c64.ScalUnitary(beta, ci) } } } else { if beta == 0 { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] c64.ScalUnitary(beta, ci) } } } return } if trans == blas.NoTrans { // Form C = alpha*A*Bᵀ + alpha*B*Aᵀ + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { for jc := range ci { j := i + jc ci[jc] = alpha*c64.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c64.DotuUnitary(bi, a[j*lda:j*lda+k]) } } else { for jc, cij := range ci { j := i + jc ci[jc] = alpha*c64.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c64.DotuUnitary(bi, a[j*lda:j*lda+k]) + beta*cij } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] ai := a[i*lda : i*lda+k] bi := b[i*ldb : i*ldb+k] if beta == 0 { for j := range ci { ci[j] = alpha*c64.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c64.DotuUnitary(bi, a[j*lda:j*lda+k]) } } else { for j, cij := range ci { ci[j] = alpha*c64.DotuUnitary(ai, b[j*ldb:j*ldb+k]) + alpha*c64.DotuUnitary(bi, a[j*lda:j*lda+k]) + beta*cij } } } } } else { // Form C = alpha*Aᵀ*B + alpha*Bᵀ*A + beta*C. if uplo == blas.Upper { for i := 0; i < n; i++ { ci := c[i*ldc+i : i*ldc+n] switch { case beta == 0: for jc := range ci { ci[jc] = 0 } case beta != 1: for jc := range ci { ci[jc] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c64.AxpyUnitary(alpha*aji, b[j*ldb+i:j*ldb+n], ci) } if bji != 0 { c64.AxpyUnitary(alpha*bji, a[j*lda+i:j*lda+n], ci) } } } } else { for i := 0; i < n; i++ { ci := c[i*ldc : i*ldc+i+1] switch { case beta == 0: for j := range ci { ci[j] = 0 } case beta != 1: for j := range ci { ci[j] *= beta } } for j := 0; j < k; j++ { aji := a[j*lda+i] bji := b[j*ldb+i] if aji != 0 { c64.AxpyUnitary(alpha*aji, b[j*ldb:j*ldb+i+1], ci) } if bji != 0 { c64.AxpyUnitary(alpha*bji, a[j*lda:j*lda+i+1], ci) } } } } } } // Ctrmm performs one of the matrix-matrix operations // // B = alpha * op(A) * B if side == blas.Left, // B = alpha * B * op(A) if side == blas.Right, // // where alpha is a scalar, B is an m×n matrix, A is a unit, or non-unit, // upper or lower triangular matrix and op(A) is one of // // op(A) = A if trans == blas.NoTrans, // op(A) = Aᵀ if trans == blas.Trans, // op(A) = Aᴴ if trans == blas.ConjTrans. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctrmm(side blas.Side, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTranspose) case diag != blas.Unit && diag != blas.NonUnit: panic(badDiag) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case 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) < (na-1)*lda+na { panic(shortA) } if len(b) < (m-1)*ldb+n { panic(shortB) } // Quick return if possible. if alpha == 0 { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j := range bi { bi[j] = 0 } } return } noConj := trans != blas.ConjTrans noUnit := diag == blas.NonUnit if side == blas.Left { if trans == blas.NoTrans { // Form B = alpha*A*B. if uplo == blas.Upper { for i := 0; i < m; i++ { aii := alpha if noUnit { aii *= a[i*lda+i] } bi := b[i*ldb : i*ldb+n] for j := range bi { bi[j] *= aii } for ja, aij := range a[i*lda+i+1 : i*lda+m] { j := ja + i + 1 if aij != 0 { c64.AxpyUnitary(alpha*aij, b[j*ldb:j*ldb+n], bi) } } } } else { for i := m - 1; i >= 0; i-- { aii := alpha if noUnit { aii *= a[i*lda+i] } bi := b[i*ldb : i*ldb+n] for j := range bi { bi[j] *= aii } for j, aij := range a[i*lda : i*lda+i] { if aij != 0 { c64.AxpyUnitary(alpha*aij, b[j*ldb:j*ldb+n], bi) } } } } } else { // Form B = alpha*Aᵀ*B or B = alpha*Aᴴ*B. if uplo == blas.Upper { for k := m - 1; k >= 0; k-- { bk := b[k*ldb : k*ldb+n] for ja, ajk := range a[k*lda+k+1 : k*lda+m] { if ajk == 0 { continue } j := k + 1 + ja if noConj { c64.AxpyUnitary(alpha*ajk, bk, b[j*ldb:j*ldb+n]) } else { c64.AxpyUnitary(alpha*cmplx.Conj(ajk), bk, b[j*ldb:j*ldb+n]) } } akk := alpha if noUnit { if noConj { akk *= a[k*lda+k] } else { akk *= cmplx.Conj(a[k*lda+k]) } } if akk != 1 { c64.ScalUnitary(akk, bk) } } } else { for k := 0; k < m; k++ { bk := b[k*ldb : k*ldb+n] for j, ajk := range a[k*lda : k*lda+k] { if ajk == 0 { continue } if noConj { c64.AxpyUnitary(alpha*ajk, bk, b[j*ldb:j*ldb+n]) } else { c64.AxpyUnitary(alpha*cmplx.Conj(ajk), bk, b[j*ldb:j*ldb+n]) } } akk := alpha if noUnit { if noConj { akk *= a[k*lda+k] } else { akk *= cmplx.Conj(a[k*lda+k]) } } if akk != 1 { c64.ScalUnitary(akk, bk) } } } } } else { if trans == blas.NoTrans { // Form B = alpha*B*A. if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for k := n - 1; k >= 0; k-- { abik := alpha * bi[k] if abik == 0 { continue } bi[k] = abik if noUnit { bi[k] *= a[k*lda+k] } c64.AxpyUnitary(abik, a[k*lda+k+1:k*lda+n], bi[k+1:]) } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for k := 0; k < n; k++ { abik := alpha * bi[k] if abik == 0 { continue } bi[k] = abik if noUnit { bi[k] *= a[k*lda+k] } c64.AxpyUnitary(abik, a[k*lda:k*lda+k], bi[:k]) } } } } else { // Form B = alpha*B*Aᵀ or B = alpha*B*Aᴴ. if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j, bij := range bi { if noConj { if noUnit { bij *= a[j*lda+j] } bij += c64.DotuUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) } else { if noUnit { bij *= cmplx.Conj(a[j*lda+j]) } bij += c64.DotcUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) } bi[j] = alpha * bij } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j := n - 1; j >= 0; j-- { bij := bi[j] if noConj { if noUnit { bij *= a[j*lda+j] } bij += c64.DotuUnitary(a[j*lda:j*lda+j], bi[:j]) } else { if noUnit { bij *= cmplx.Conj(a[j*lda+j]) } bij += c64.DotcUnitary(a[j*lda:j*lda+j], bi[:j]) } bi[j] = alpha * bij } } } } } } // Ctrsm solves one of the matrix equations // // op(A) * X = alpha * B if side == blas.Left, // X * op(A) = alpha * B if side == blas.Right, // // where alpha is a scalar, X and B are m×n matrices, A is a unit or // non-unit, upper or lower triangular matrix and op(A) is one of // // op(A) = A if transA == blas.NoTrans, // op(A) = Aᵀ if transA == blas.Trans, // op(A) = Aᴴ if transA == blas.ConjTrans. // // On return the matrix X is overwritten on B. // // Complex64 implementations are autogenerated and not directly tested. func (Implementation) Ctrsm(side blas.Side, uplo blas.Uplo, transA blas.Transpose, diag blas.Diag, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int) { na := m if side == blas.Right { na = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case uplo != blas.Lower && uplo != blas.Upper: panic(badUplo) case transA != blas.NoTrans && transA != blas.Trans && transA != blas.ConjTrans: panic(badTranspose) case diag != blas.Unit && diag != blas.NonUnit: panic(badDiag) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, na): panic(badLdA) case 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) < (na-1)*lda+na { panic(shortA) } if len(b) < (m-1)*ldb+n { panic(shortB) } if alpha == 0 { for i := 0; i < m; i++ { for j := 0; j < n; j++ { b[i*ldb+j] = 0 } } return } noConj := transA != blas.ConjTrans noUnit := diag == blas.NonUnit if side == blas.Left { if transA == blas.NoTrans { // Form B = alpha*inv(A)*B. if uplo == blas.Upper { for i := m - 1; i >= 0; i-- { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c64.ScalUnitary(alpha, bi) } for ka, aik := range a[i*lda+i+1 : i*lda+m] { k := i + 1 + ka if aik != 0 { c64.AxpyUnitary(-aik, b[k*ldb:k*ldb+n], bi) } } if noUnit { c64.ScalUnitary(1/a[i*lda+i], bi) } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c64.ScalUnitary(alpha, bi) } for j, aij := range a[i*lda : i*lda+i] { if aij != 0 { c64.AxpyUnitary(-aij, b[j*ldb:j*ldb+n], bi) } } if noUnit { c64.ScalUnitary(1/a[i*lda+i], bi) } } } } else { // Form B = alpha*inv(Aᵀ)*B or B = alpha*inv(Aᴴ)*B. if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if noUnit { if noConj { c64.ScalUnitary(1/a[i*lda+i], bi) } else { c64.ScalUnitary(1/cmplx.Conj(a[i*lda+i]), bi) } } for ja, aij := range a[i*lda+i+1 : i*lda+m] { if aij == 0 { continue } j := i + 1 + ja if noConj { c64.AxpyUnitary(-aij, bi, b[j*ldb:j*ldb+n]) } else { c64.AxpyUnitary(-cmplx.Conj(aij), bi, b[j*ldb:j*ldb+n]) } } if alpha != 1 { c64.ScalUnitary(alpha, bi) } } } else { for i := m - 1; i >= 0; i-- { bi := b[i*ldb : i*ldb+n] if noUnit { if noConj { c64.ScalUnitary(1/a[i*lda+i], bi) } else { c64.ScalUnitary(1/cmplx.Conj(a[i*lda+i]), bi) } } for j, aij := range a[i*lda : i*lda+i] { if aij == 0 { continue } if noConj { c64.AxpyUnitary(-aij, bi, b[j*ldb:j*ldb+n]) } else { c64.AxpyUnitary(-cmplx.Conj(aij), bi, b[j*ldb:j*ldb+n]) } } if alpha != 1 { c64.ScalUnitary(alpha, bi) } } } } } else { if transA == blas.NoTrans { // Form B = alpha*B*inv(A). if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c64.ScalUnitary(alpha, bi) } for j, bij := range bi { if bij == 0 { continue } if noUnit { bi[j] /= a[j*lda+j] } c64.AxpyUnitary(-bi[j], a[j*lda+j+1:j*lda+n], bi[j+1:n]) } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] if alpha != 1 { c64.ScalUnitary(alpha, bi) } for j := n - 1; j >= 0; j-- { if bi[j] == 0 { continue } if noUnit { bi[j] /= a[j*lda+j] } c64.AxpyUnitary(-bi[j], a[j*lda:j*lda+j], bi[:j]) } } } } else { // Form B = alpha*B*inv(Aᵀ) or B = alpha*B*inv(Aᴴ). if uplo == blas.Upper { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j := n - 1; j >= 0; j-- { bij := alpha * bi[j] if noConj { bij -= c64.DotuUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) if noUnit { bij /= a[j*lda+j] } } else { bij -= c64.DotcUnitary(a[j*lda+j+1:j*lda+n], bi[j+1:n]) if noUnit { bij /= cmplx.Conj(a[j*lda+j]) } } bi[j] = bij } } } else { for i := 0; i < m; i++ { bi := b[i*ldb : i*ldb+n] for j, bij := range bi { bij *= alpha if noConj { bij -= c64.DotuUnitary(a[j*lda:j*lda+j], bi[:j]) if noUnit { bij /= a[j*lda+j] } } else { bij -= c64.DotcUnitary(a[j*lda:j*lda+j], bi[:j]) if noUnit { bij /= cmplx.Conj(a[j*lda+j]) } } bi[j] = bij } } } } } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level3float32.go000066400000000000000000000464251450372207100226330ustar00rootroot00000000000000// 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 beta == 0 { for i := 0; i < m; i++ { ctmp := c[i*ldc : i*ldc+n] for j := range ctmp { ctmp[j] = 0 } } } if alpha == 0 { if beta != 0 { 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] if beta == 0 { 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] = alpha * (tmp1 + tmp2) } } else { 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] if beta == 0 { 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] = alpha * (tmp1 + tmp2) } } else { 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] switch beta { case 0: for j := range ctmp { ctmp[j] = 0 } case 1: default: 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] switch beta { case 0: for j := range ctmp { ctmp[j] = 0 } case 1: default: 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 } } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level3float64.go000066400000000000000000000455261450372207100226410ustar00rootroot00000000000000// 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 beta == 0 { for i := 0; i < m; i++ { ctmp := c[i*ldc : i*ldc+n] for j := range ctmp { ctmp[j] = 0 } } } if alpha == 0 { if beta != 0 { 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] if beta == 0 { 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] = alpha * (tmp1 + tmp2) } } else { 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] if beta == 0 { 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] = alpha * (tmp1 + tmp2) } } else { 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] switch beta { case 0: for j := range ctmp { ctmp[j] = 0 } case 1: default: 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] switch beta { case 0: for j := range ctmp { ctmp[j] = 0 } case 1: default: 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 } } } golang-gonum-v1-gonum-0.14.0/blas/gonum/level3float64_test.go000066400000000000000000000011531450372207100236640ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/blas/testblas" ) func TestDgemm(t *testing.T) { testblas.TestDgemm(t, impl) } func TestDsymm(t *testing.T) { testblas.DsymmTest(t, impl) } func TestDtrsm(t *testing.T) { testblas.DtrsmTest(t, impl) } func TestDsyrk(t *testing.T) { testblas.DsyrkTest(t, impl) } func TestDsyr2k(t *testing.T) { testblas.Dsyr2kTest(t, impl) } func TestDtrmm(t *testing.T) { testblas.DtrmmTest(t, impl) } golang-gonum-v1-gonum-0.14.0/blas/gonum/pardgemm_test.go000066400000000000000000000074301450372207100230720ustar00rootroot00000000000000// 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 ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) func TestDgemmParallel(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i, test := range []struct { m int n int k int alpha float64 tA blas.Transpose tB blas.Transpose }{ { m: 3, n: 4, k: 2, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: blockSize*2 + 5, n: 3, k: 2, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: 3, n: blockSize * 2, k: 2, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: 2, n: 3, k: blockSize*3 - 2, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: blockSize * minParBlock, n: 3, k: 2, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: 3, n: blockSize * minParBlock, k: 2, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: 2, n: 3, k: blockSize * minParBlock, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: blockSize*minParBlock + 1, n: blockSize * minParBlock, k: 3, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: 3, n: blockSize*minParBlock + 2, k: blockSize * 3, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: blockSize * minParBlock, n: 3, k: blockSize * minParBlock, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: blockSize * minParBlock, n: blockSize * minParBlock, k: blockSize * 3, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, { m: blockSize + blockSize/2, n: blockSize + blockSize/2, k: blockSize + blockSize/2, alpha: 2.5, tA: blas.NoTrans, tB: blas.NoTrans, }, } { testMatchParallelSerial(t, rnd, i, blas.NoTrans, blas.NoTrans, test.m, test.n, test.k, test.alpha) testMatchParallelSerial(t, rnd, i, blas.Trans, blas.NoTrans, test.m, test.n, test.k, test.alpha) testMatchParallelSerial(t, rnd, i, blas.NoTrans, blas.Trans, test.m, test.n, test.k, test.alpha) testMatchParallelSerial(t, rnd, i, blas.Trans, blas.Trans, test.m, test.n, test.k, test.alpha) } } func testMatchParallelSerial(t *testing.T, rnd *rand.Rand, i int, tA, tB blas.Transpose, m, n, k int, alpha float64) { var ( rowA, colA int rowB, colB int ) if tA == blas.NoTrans { rowA = m colA = k } else { rowA = k colA = m } if tB == blas.NoTrans { rowB = k colB = n } else { rowB = n colB = k } lda := colA a := randmat(rowA, colA, lda, rnd) aCopy := make([]float64, len(a)) copy(aCopy, a) ldb := colB b := randmat(rowB, colB, ldb, rnd) bCopy := make([]float64, len(b)) copy(bCopy, b) ldc := n c := randmat(m, n, ldc, rnd) want := make([]float64, len(c)) copy(want, c) dgemmSerial(tA == blas.Trans, tB == blas.Trans, m, n, k, a, lda, b, ldb, want, ldc, alpha) dgemmParallel(tA == blas.Trans, tB == blas.Trans, m, n, k, a, lda, b, ldb, c, ldc, alpha) if !floats.Equal(a, aCopy) { t.Errorf("Case %v: a changed during call to dgemmParallel", i) } if !floats.Equal(b, bCopy) { t.Errorf("Case %v: b changed during call to dgemmParallel", i) } if !floats.EqualApprox(c, want, 1e-12) { t.Errorf("Case %v: answer not equal parallel and serial", i) } } func randmat(r, c, stride int, rnd *rand.Rand) []float64 { data := make([]float64, r*stride+c) for i := range data { data[i] = rnd.NormFloat64() } return data } golang-gonum-v1-gonum-0.14.0/blas/gonum/sgemm.go000066400000000000000000000177161450372207100213570ustar00rootroot00000000000000// 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 } // workerLimit acts a number of maximum concurrent workers, // with the limit set to the number of procs available. workerLimit := make(chan struct{}, runtime.GOMAXPROCS(0)) // wg is used to wait for all var wg sync.WaitGroup wg.Add(parBlocks) defer wg.Wait() for i := 0; i < m; i += blockSize { for j := 0; j < n; j += blockSize { workerLimit <- struct{}{} go func(i, j int) { defer func() { wg.Done() <-workerLimit }() 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) } }(i, j) } } } // 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] } golang-gonum-v1-gonum-0.14.0/blas/gonum/single_precision.bash000077500000000000000000000216731450372207100241130ustar00rootroot00000000000000#!/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.L2NormInc -> f32.L2NormInc' \ | gofmt -r 'f64.L2NormUnitary -> f32.L2NormUnitary' \ | 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"_' \ -e 's_safmin = 0x1p-1022_safmin = 0x1p-126_' \ >> 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' \ | gofmt -r 'f64.GemvN -> f32.GemvN' \ | gofmt -r 'f64.GemvT -> f32.GemvT' \ | gofmt -r 'Implementation{}.Dscal -> Implementation{}.Sscal' \ \ | 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 golang-gonum-v1-gonum-0.14.0/blas/testblas/000077500000000000000000000000001450372207100204005ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/testblas/benchautogen/000077500000000000000000000000001450372207100230425ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/blas/testblas/benchautogen/autogen_bench_level1double.go000066400000000000000000000164201450372207100306400ustar00rootroot00000000000000// Copyright ©2014 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 // Script for automatic code generation of the benchmark routines. package main import ( "fmt" "os" "os/exec" "path/filepath" "strconv" ) var gopath string var copyrightnotice = []byte(`// Copyright ©2014 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`) var autogen = []byte("// Code generated by \"go run $GOPATH/src/gonum.org/v1/gonum/blas/testblas/benchautogen/autogen_bench_level1double.go\"; DO NOT EDIT.\n") var imports = []byte(`import( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" )`) var randomSliceFunction = []byte(`func randomSlice(l, idx int) ([]float64) { if idx < 0{ idx = -idx } s := make([]float64, l * idx) for i := range s { s[i] = rand.Float64() } return s }`) const ( posInc1 = 5 posInc2 = 3 negInc1 = -3 negInc2 = -4 ) var level1Sizes = []struct { lower string upper string camel string size int }{ { lower: "small", upper: "SMALL_SLICE", camel: "Small", size: 10, }, { lower: "medium", upper: "MEDIUM_SLICE", camel: "Medium", size: 1000, }, { lower: "large", upper: "LARGE_SLICE", camel: "Large", size: 100000, }, { lower: "huge", upper: "HUGE_SLICE", camel: "Huge", size: 10000000, }, } type level1functionStruct struct { camel string sig string call string extraSetup string oneInput bool extraName string // if have a couple different cases for the same function } var level1Functions = []level1functionStruct{ { camel: "Ddot", sig: "n int, x []float64, incX int, y []float64, incY int", call: "n, x, incX, y, incY", oneInput: false, }, { camel: "Dnrm2", sig: "n int, x []float64, incX int", call: "n, x, incX", oneInput: true, }, { camel: "Dasum", sig: "n int, x []float64, incX int", call: "n, x, incX", oneInput: true, }, { camel: "Idamax", sig: "n int, x []float64, incX int", call: "n, x, incX", oneInput: true, }, { camel: "Dswap", sig: "n int, x []float64, incX int, y []float64, incY int", call: "n, x, incX, y, incY", oneInput: false, }, { camel: "Dcopy", sig: "n int, x []float64, incX int, y []float64, incY int", call: "n, x, incX, y, incY", oneInput: false, }, { camel: "Daxpy", sig: "n int, alpha float64, x []float64, incX int, y []float64, incY int", call: "n, alpha, x, incX, y, incY", extraSetup: "alpha := 2.4", oneInput: false, }, { camel: "Drot", sig: "n int, x []float64, incX int, y []float64, incY int, c, s float64", call: "n, x, incX, y, incY, c, s", extraSetup: "c := 0.89725836967\ns:= 0.44150585279", oneInput: false, }, { camel: "Drotm", sig: "n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams", call: "n, x, incX, y, incY, p", extraSetup: "p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375,0}}", oneInput: false, extraName: "OffDia", }, { camel: "Drotm", sig: "n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams", call: "n, x, incX, y, incY, p", extraSetup: "p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}}", oneInput: false, extraName: "Dia", }, { camel: "Drotm", sig: "n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams", call: "n, x, incX, y, incY, p", extraSetup: "p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}}", oneInput: false, extraName: "Resc", }, { camel: "Dscal", sig: "n int, alpha float64, x []float64, incX int", call: "n, alpha, x, incX", extraSetup: "alpha := 2.4", oneInput: true, }, } func init() { gopath = os.Getenv("GOPATH") if gopath == "" { panic("gopath not set") } } func main() { pkgs := []string{"gonum", "netlib"} for _, pkg := range pkgs { blasPath := filepath.Join(gopath, "src", "gonum.org", "v1", pkg, "blas", pkg) err := level1(blasPath, pkg) if err != nil { fmt.Println(err) os.Exit(1) } err = exec.Command("goimports", "-w", blasPath).Run() if err != nil { fmt.Println(err) os.Exit(1) } } } func printHeader(f errFile, name string) { f.Write(autogen) f.WriteString("\n\n") f.Write(copyrightnotice) f.WriteString("\n\n") f.WriteString("package " + name) f.WriteString("\n\n") f.Write(imports) f.WriteString("\n\n") } // Generate the benchmark scripts for level1 func level1(benchPath string, pkgname string) error { // Generate level 1 benchmarks level1Filepath := filepath.Join(benchPath, "level1float64_bench_test.go") var f errFile f.file, f.err = os.Create(level1Filepath) if f.err != nil { return f.err } defer f.file.Close() printHeader(f, pkgname) // Print all of the constants f.WriteString("const (\n") f.WriteString("\tposInc1 = " + strconv.Itoa(posInc1) + "\n") f.WriteString("\tposInc2 = " + strconv.Itoa(posInc2) + "\n") f.WriteString("\tnegInc1 = " + strconv.Itoa(negInc1) + "\n") f.WriteString("\tnegInc2 = " + strconv.Itoa(negInc2) + "\n") for _, con := range level1Sizes { f.WriteString("\t" + con.upper + " = " + strconv.Itoa(con.size) + "\n") } f.WriteString(")\n") f.WriteString("\n") // Write the randomSlice function f.Write(randomSliceFunction) f.WriteString("\n\n") // Start writing the benchmarks for _, fun := range level1Functions { writeLevel1Benchmark(fun, f) f.WriteString("\n/* ------------------ */ \n") } return f.err } func writeLevel1Benchmark(fun level1functionStruct, f errFile) { // First, write the base benchmark file f.WriteString("func benchmark" + fun.camel + fun.extraName + "(b *testing.B, ") f.WriteString(fun.sig) f.WriteString(") {\n") f.WriteString("b.ResetTimer()\n") f.WriteString("for i := 0; i < b.N; i++{\n") f.WriteString("\timpl." + fun.camel + "(") f.WriteString(fun.call) f.WriteString(")\n}\n}\n") f.WriteString("\n") // Write all of the benchmarks to call it for _, sz := range level1Sizes { lambda := func(incX, incY, name string, twoInput bool) { f.WriteString("func Benchmark" + fun.camel + fun.extraName + sz.camel + name + "(b *testing.B){\n") f.WriteString("n := " + sz.upper + "\n") f.WriteString("incX := " + incX + "\n") f.WriteString("x := randomSlice(n, incX)\n") if twoInput { f.WriteString("incY := " + incY + "\n") f.WriteString("y := randomSlice(n, incY)\n") } f.WriteString(fun.extraSetup + "\n") f.WriteString("benchmark" + fun.camel + fun.extraName + "(b, " + fun.call + ")\n") f.WriteString("}\n\n") } if fun.oneInput { lambda("1", "", "UnitaryInc", false) lambda("posInc1", "", "PosInc", false) } else { lambda("1", "1", "BothUnitary", true) lambda("posInc1", "1", "IncUni", true) lambda("1", "negInc1", "UniInc", true) lambda("posInc1", "negInc1", "BothInc", true) } } } type errFile struct { file *os.File err error } func (f *errFile) Write(b []byte) { if f.err != nil { return } _, f.err = f.file.Write(b) } func (f *errFile) WriteString(s string) { if f.err != nil { return } _, f.err = f.file.WriteString(s) } golang-gonum-v1-gonum-0.14.0/blas/testblas/benchsize.go000066400000000000000000000004071450372207100227020ustar00rootroot00000000000000// 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 testblas const ( SmallMat = 10 MediumMat = 100 LargeMat = 1000 HugeMat = 10000 ) golang-gonum-v1-gonum-0.14.0/blas/testblas/common.go000066400000000000000000000350061450372207100222230ustar00rootroot00000000000000// 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 testblas import ( "math" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats/scalar" ) // throwPanic will throw unexpected panics if true, or will just report them as errors if false const throwPanic = true var znan = cmplx.NaN() func dTolEqual(a, b float64) bool { if math.IsNaN(a) && math.IsNaN(b) { return true } if a == b { return true } m := math.Max(math.Abs(a), math.Abs(b)) if m > 1 { a /= m b /= m } if math.Abs(a-b) < 1e-14 { return true } return false } func dSliceTolEqual(a, b []float64) bool { if len(a) != len(b) { return false } for i := range a { if !dTolEqual(a[i], b[i]) { return false } } return true } func dStridedSliceTolEqual(n int, a []float64, inca int, b []float64, incb int) bool { ia := 0 ib := 0 if inca <= 0 { ia = -(n - 1) * inca } if incb <= 0 { ib = -(n - 1) * incb } for i := 0; i < n; i++ { if !dTolEqual(a[ia], b[ib]) { return false } ia += inca ib += incb } return true } func dSliceEqual(a, b []float64) bool { if len(a) != len(b) { return false } for i := range a { if !dTolEqual(a[i], b[i]) { return false } } return true } func dCopyTwoTmp(x, xTmp, y, yTmp []float64) { if len(x) != len(xTmp) { panic("x size mismatch") } if len(y) != len(yTmp) { panic("y size mismatch") } copy(xTmp, x) copy(yTmp, y) } // returns true if the function panics func panics(f func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() f() return } func testpanics(f func(), name string, t *testing.T) { b := panics(f) if !b { t.Errorf("%v should panic and does not", name) } } func sliceOfSliceCopy(a [][]float64) [][]float64 { n := make([][]float64, len(a)) for i := range a { n[i] = make([]float64, len(a[i])) copy(n[i], a[i]) } return n } func sliceCopy(a []float64) []float64 { n := make([]float64, len(a)) copy(n, a) return n } func flatten(a [][]float64) []float64 { if len(a) == 0 { return nil } m := len(a) n := len(a[0]) s := make([]float64, m*n) for i := 0; i < m; i++ { for j := 0; j < n; j++ { s[i*n+j] = a[i][j] } } return s } func unflatten(a []float64, m, n int) [][]float64 { s := make([][]float64, m) for i := 0; i < m; i++ { s[i] = make([]float64, n) for j := 0; j < n; j++ { s[i][j] = a[i*n+j] } } return s } // flattenTriangular turns the upper or lower triangle of a dense slice of slice // into a single slice with packed storage. a must be a square matrix. func flattenTriangular(a [][]float64, ul blas.Uplo) []float64 { m := len(a) aFlat := make([]float64, m*(m+1)/2) var k int if ul == blas.Upper { for i := 0; i < m; i++ { k += copy(aFlat[k:], a[i][i:]) } return aFlat } for i := 0; i < m; i++ { k += copy(aFlat[k:], a[i][:i+1]) } return aFlat } // flattenBanded turns a dense banded slice of slice into the compact banded matrix format func flattenBanded(a [][]float64, ku, kl int) []float64 { m := len(a) n := len(a[0]) if ku < 0 || kl < 0 { panic("testblas: negative band length") } nRows := m nCols := (ku + kl + 1) aflat := make([]float64, nRows*nCols) for i := range aflat { aflat[i] = math.NaN() } // loop over the rows, and then the bands // elements in the ith row stay in the ith row // order in bands is kept for i := 0; i < nRows; i++ { min := -kl if i-kl < 0 { min = -i } max := ku if i+ku >= n { max = n - i - 1 } for j := min; j <= max; j++ { col := kl + j aflat[i*nCols+col] = a[i][i+j] } } return aflat } // makeIncremented takes a float64 slice with inc == 1 and makes an incremented version // and adds extra values on the end func makeIncremented(x []float64, inc int, extra int) []float64 { if inc == 0 { panic("zero inc") } absinc := inc if absinc < 0 { absinc = -inc } xcopy := make([]float64, len(x)) if inc > 0 { copy(xcopy, x) } else { for i := 0; i < len(x); i++ { xcopy[i] = x[len(x)-i-1] } } // don't use NaN because it makes comparison hard // Do use a weird unique value for easier debugging counter := 100.0 var xnew []float64 for i, v := range xcopy { xnew = append(xnew, v) if i != len(x)-1 { for j := 0; j < absinc-1; j++ { xnew = append(xnew, counter) counter++ } } } for i := 0; i < extra; i++ { xnew = append(xnew, counter) counter++ } return xnew } // makeIncremented32 takes a float32 slice with inc == 1 and makes an incremented version // and adds extra values on the end func makeIncremented32(x []float32, inc int, extra int) []float32 { if inc == 0 { panic("zero inc") } absinc := inc if absinc < 0 { absinc = -inc } xcopy := make([]float32, len(x)) if inc > 0 { copy(xcopy, x) } else { for i := 0; i < len(x); i++ { xcopy[i] = x[len(x)-i-1] } } // don't use NaN because it makes comparison hard // Do use a weird unique value for easier debugging var counter float32 = 100.0 var xnew []float32 for i, v := range xcopy { xnew = append(xnew, v) if i != len(x)-1 { for j := 0; j < absinc-1; j++ { xnew = append(xnew, counter) counter++ } } } for i := 0; i < extra; i++ { xnew = append(xnew, counter) counter++ } return xnew } func abs(x int) int { if x < 0 { return -x } return x } func allPairs(x, y []int) [][2]int { var p [][2]int for _, v0 := range x { for _, v1 := range y { p = append(p, [2]int{v0, v1}) } } return p } func sameFloat64(a, b float64) bool { return a == b || math.IsNaN(a) && math.IsNaN(b) } func sameComplex128(x, y complex128) bool { return sameFloat64(real(x), real(y)) && sameFloat64(imag(x), imag(y)) } func zsame(x, y []complex128) bool { if len(x) != len(y) { return false } for i, v := range x { w := y[i] if !sameComplex128(v, w) { return false } } return true } // zSameAtNonstrided returns whether elements at non-stride positions of vectors // x and y are same. func zSameAtNonstrided(x, y []complex128, inc int) bool { if len(x) != len(y) { return false } if inc < 0 { inc = -inc } for i, v := range x { if i%inc == 0 { continue } w := y[i] if !sameComplex128(v, w) { return false } } return true } // zEqualApproxAtStrided returns whether elements at stride positions of vectors // x and y are approximately equal within tol. func zEqualApproxAtStrided(x, y []complex128, inc int, tol float64) bool { if len(x) != len(y) { return false } if inc < 0 { inc = -inc } for i := 0; i < len(x); i += inc { v := x[i] w := y[i] if !(cmplx.Abs(v-w) <= tol) { return false } } return true } func makeZVector(data []complex128, inc int) []complex128 { if inc == 0 { panic("bad test") } if len(data) == 0 { return nil } inc = abs(inc) x := make([]complex128, (len(data)-1)*inc+1) for i := range x { x[i] = znan } for i, v := range data { x[i*inc] = v } return x } func makeZGeneral(data []complex128, m, n int, ld int) []complex128 { if m < 0 || n < 0 { panic("bad test") } if data != nil && len(data) != m*n { panic("bad test") } if ld < max(1, n) { panic("bad test") } if m == 0 || n == 0 { return nil } a := make([]complex128, (m-1)*ld+n) for i := range a { a[i] = znan } if data != nil { for i := 0; i < m; i++ { copy(a[i*ld:i*ld+n], data[i*n:i*n+n]) } } return a } func max(a, b int) int { if a < b { return b } return a } func min(a, b int) int { if a < b { return a } return b } // zPack returns the uplo triangle of an n×n matrix A in packed format. func zPack(uplo blas.Uplo, n int, a []complex128, lda int) []complex128 { if n == 0 { return nil } ap := make([]complex128, n*(n+1)/2) var ii int if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { ap[ii] = a[i*lda+j] ii++ } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { ap[ii] = a[i*lda+j] ii++ } } } return ap } // zUnpackAsHermitian returns an n×n general Hermitian matrix (with stride n) // whose packed uplo triangle is stored on entry in ap. func zUnpackAsHermitian(uplo blas.Uplo, n int, ap []complex128) []complex128 { if n == 0 { return nil } a := make([]complex128, n*n) lda := n var ii int if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { a[i*lda+j] = ap[ii] if i != j { a[j*lda+i] = cmplx.Conj(ap[ii]) } ii++ } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { a[i*lda+j] = ap[ii] if i != j { a[j*lda+i] = cmplx.Conj(ap[ii]) } ii++ } } } return a } // zPackBand returns the (kL+1+kU) band of an m×n general matrix A in band // matrix format with ldab stride. Out-of-range elements are filled with NaN. func zPackBand(kL, kU, ldab int, m, n int, a []complex128, lda int) []complex128 { if m == 0 || n == 0 { return nil } nRow := min(m, n+kL) ab := make([]complex128, (nRow-1)*ldab+kL+1+kU) for i := range ab { ab[i] = znan } for i := 0; i < m; i++ { off := max(0, kL-i) var k int for j := max(0, i-kL); j < min(n, i+kU+1); j++ { ab[i*ldab+off+k] = a[i*lda+j] k++ } } return ab } // zPackTriBand returns in band matrix format the (k+1) band in the uplo // triangle of an n×n matrix A. Out-of-range elements are filled with NaN. func zPackTriBand(k, ldab int, uplo blas.Uplo, n int, a []complex128, lda int) []complex128 { if n == 0 { return nil } ab := make([]complex128, (n-1)*ldab+k+1) for i := range ab { ab[i] = znan } if uplo == blas.Upper { for i := 0; i < n; i++ { var k int for j := i; j < min(n, i+k+1); j++ { ab[i*ldab+k] = a[i*lda+j] k++ } } } else { for i := 0; i < n; i++ { off := max(0, k-i) var kk int for j := max(0, i-k); j <= i; j++ { ab[i*ldab+off+kk] = a[i*lda+j] kk++ } } } return ab } // zEqualApprox returns whether the slices a and b are approximately equal. func zEqualApprox(a, b []complex128, tol float64) bool { if len(a) != len(b) { panic("mismatched slice length") } for i, ai := range a { if !scalar.EqualWithinAbs(cmplx.Abs(ai), cmplx.Abs(b[i]), tol) { return false } } return true } // rndComplex128 returns a complex128 with random components. func rndComplex128(rnd *rand.Rand) complex128 { return complex(rnd.NormFloat64(), rnd.NormFloat64()) } // zmm returns the result of one of the matrix-matrix operations // // alpha * op(A) * op(B) + beta * C // // where op(X) is one of // // op(X) = X or op(X) = Xᵀ or op(X) = Xᴴ, // // alpha and beta are scalars, and A, B and C are matrices, with op(A) an m×k matrix, // op(B) a k×n matrix and C an m×n matrix. // // The returned slice is newly allocated, has the same length as c and the // matrix it represents has the stride ldc. Out-of-range elements are equal to // those of C to ease comparison of results from BLAS Level 3 functions. func zmm(tA, tB blas.Transpose, m, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) []complex128 { r := make([]complex128, len(c)) copy(r, c) for i := 0; i < m; i++ { for j := 0; j < n; j++ { r[i*ldc+j] = 0 } } switch tA { case blas.NoTrans: switch tB { case blas.NoTrans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += a[i*lda+l] * b[l*ldb+j] } } } case blas.Trans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += a[i*lda+l] * b[j*ldb+l] } } } case blas.ConjTrans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += a[i*lda+l] * cmplx.Conj(b[j*ldb+l]) } } } } case blas.Trans: switch tB { case blas.NoTrans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += a[l*lda+i] * b[l*ldb+j] } } } case blas.Trans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += a[l*lda+i] * b[j*ldb+l] } } } case blas.ConjTrans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += a[l*lda+i] * cmplx.Conj(b[j*ldb+l]) } } } } case blas.ConjTrans: switch tB { case blas.NoTrans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += cmplx.Conj(a[l*lda+i]) * b[l*ldb+j] } } } case blas.Trans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += cmplx.Conj(a[l*lda+i]) * b[j*ldb+l] } } } case blas.ConjTrans: for i := 0; i < m; i++ { for j := 0; j < n; j++ { for l := 0; l < k; l++ { r[i*ldc+j] += cmplx.Conj(a[l*lda+i]) * cmplx.Conj(b[j*ldb+l]) } } } } } for i := 0; i < m; i++ { for j := 0; j < n; j++ { r[i*ldc+j] = alpha * r[i*ldc+j] if beta != 0 { r[i*ldc+j] += beta * c[i*ldc+j] } } } return r } // transString returns a string representation of blas.Transpose. func transString(t blas.Transpose) string { switch t { case blas.NoTrans: return "NoTrans" case blas.Trans: return "Trans" case blas.ConjTrans: return "ConjTrans" } return "unknown trans" } // uploString returns a string representation of blas.Uplo. func uploString(uplo blas.Uplo) string { switch uplo { case blas.Lower: return "Lower" case blas.Upper: return "Upper" } return "unknown uplo" } // sideString returns a string representation of blas.Side. func sideString(side blas.Side) string { switch side { case blas.Left: return "Left" case blas.Right: return "Right" } return "unknown side" } // diagString returns a string representation of blas.Diag. func diagString(diag blas.Diag) string { switch diag { case blas.Unit: return "Unit" case blas.NonUnit: return "NonUnit" } return "unknown diag" } // zSameLowerTri returns whether n×n matrices A and B are same under the diagonal. func zSameLowerTri(n int, a []complex128, lda int, b []complex128, ldb int) bool { for i := 1; i < n; i++ { for j := 0; j < i; j++ { aij := a[i*lda+j] bij := b[i*ldb+j] if !sameComplex128(aij, bij) { return false } } } return true } // zSameUpperTri returns whether n×n matrices A and B are same above the diagonal. func zSameUpperTri(n int, a []complex128, lda int, b []complex128, ldb int) bool { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { aij := a[i*lda+j] bij := b[i*ldb+j] if !sameComplex128(aij, bij) { return false } } } return true } golang-gonum-v1-gonum-0.14.0/blas/testblas/common_test.go000066400000000000000000000110771450372207100232640ustar00rootroot00000000000000// 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 testblas import ( "math" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) func TestFlattenBanded(t *testing.T) { for i, test := range []struct { dense [][]float64 ku int kl int condensed [][]float64 }{ { dense: [][]float64{{3}}, ku: 0, kl: 0, condensed: [][]float64{{3}}, }, { dense: [][]float64{ {3, 4, 0}, }, ku: 1, kl: 0, condensed: [][]float64{ {3, 4}, }, }, { dense: [][]float64{ {3, 4, 0, 0, 0}, }, ku: 1, kl: 0, condensed: [][]float64{ {3, 4}, }, }, { dense: [][]float64{ {3, 4, 0}, {0, 5, 8}, {0, 0, 2}, {0, 0, 0}, {0, 0, 0}, }, ku: 1, kl: 0, condensed: [][]float64{ {3, 4}, {5, 8}, {2, math.NaN()}, {math.NaN(), math.NaN()}, {math.NaN(), math.NaN()}, }, }, { dense: [][]float64{ {3, 4, 6}, {0, 5, 8}, {0, 0, 2}, {0, 0, 0}, {0, 0, 0}, }, ku: 2, kl: 0, condensed: [][]float64{ {3, 4, 6}, {5, 8, math.NaN()}, {2, math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, }, }, { dense: [][]float64{ {3, 4, 6}, {1, 5, 8}, {0, 6, 2}, {0, 0, 7}, {0, 0, 0}, }, ku: 2, kl: 1, condensed: [][]float64{ {math.NaN(), 3, 4, 6}, {1, 5, 8, math.NaN()}, {6, 2, math.NaN(), math.NaN()}, {7, math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, }, { dense: [][]float64{ {1, 2, 0}, {3, 4, 5}, {6, 7, 8}, {0, 9, 10}, {0, 0, 11}, }, ku: 1, kl: 2, condensed: [][]float64{ {math.NaN(), math.NaN(), 1, 2}, {math.NaN(), 3, 4, 5}, {6, 7, 8, math.NaN()}, {9, 10, math.NaN(), math.NaN()}, {11, math.NaN(), math.NaN(), math.NaN()}, }, }, { dense: [][]float64{ {1, 0, 0}, {3, 4, 0}, {6, 7, 8}, {0, 9, 10}, {0, 0, 11}, }, ku: 0, kl: 2, condensed: [][]float64{ {math.NaN(), math.NaN(), 1}, {math.NaN(), 3, 4}, {6, 7, 8}, {9, 10, math.NaN()}, {11, math.NaN(), math.NaN()}, }, }, { dense: [][]float64{ {1, 0, 0, 0, 0}, {3, 4, 0, 0, 0}, {1, 3, 5, 0, 0}, }, ku: 0, kl: 2, condensed: [][]float64{ {math.NaN(), math.NaN(), 1}, {math.NaN(), 3, 4}, {1, 3, 5}, }, }, } { condensed := flattenBanded(test.dense, test.ku, test.kl) correct := flatten(test.condensed) if !floats.Same(condensed, correct) { t.Errorf("Case %v mismatch. Want %v, got %v.", i, correct, condensed) } } } func TestFlattenTriangular(t *testing.T) { for i, test := range []struct { a [][]float64 ans []float64 ul blas.Uplo }{ { a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, ul: blas.Upper, ans: []float64{1, 2, 3, 4, 5, 6}, }, { a: [][]float64{ {1, 0, 0}, {2, 3, 0}, {4, 5, 6}, }, ul: blas.Lower, ans: []float64{1, 2, 3, 4, 5, 6}, }, } { a := flattenTriangular(test.a, test.ul) if !floats.Equal(a, test.ans) { t.Errorf("Case %v. Want %v, got %v.", i, test.ans, a) } } } func TestPackUnpackAsHermitian(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, n := range []int{1, 2, 5, 50} { for _, lda := range []int{max(1, n), n + 11} { a := makeZGeneral(nil, n, n, lda) for i := 0; i < n; i++ { for j := i; j < n; j++ { a[i*lda+j] = complex(rnd.NormFloat64(), rnd.NormFloat64()) if i != j { a[j*lda+i] = cmplx.Conj(a[i*lda+j]) } } } aCopy := make([]complex128, len(a)) copy(aCopy, a) ap := zPack(uplo, n, a, lda) if !zsame(a, aCopy) { t.Errorf("Case uplo=%v,n=%v,lda=%v: zPack modified a", uplo, n, lda) } apCopy := make([]complex128, len(ap)) copy(apCopy, ap) art := zUnpackAsHermitian(uplo, n, ap) if !zsame(ap, apCopy) { t.Errorf("Case uplo=%v,n=%v,lda=%v: zUnpackAsHermitian modified ap", uplo, n, lda) } // Copy the round-tripped A into a matrix with the same stride // as the original. got := makeZGeneral(nil, n, n, lda) for i := 0; i < n; i++ { copy(got[i*lda:i*lda+n], art[i*n:i*n+n]) } if !zsame(got, a) { t.Errorf("Case uplo=%v,n=%v,lda=%v: zPack and zUnpackAsHermitian do not roundtrip", uplo, n, lda) } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dgbmv.go000066400000000000000000000063331450372207100220330ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dgbmver interface { Dgbmv(tA blas.Transpose, m, n, kL, kU int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) } func DgbmvTest(t *testing.T, blasser Dgbmver) { for i, test := range []struct { tA blas.Transpose m, n int kL, kU int alpha float64 a [][]float64 lda int x []float64 beta float64 y []float64 ans []float64 }{ { tA: blas.NoTrans, m: 9, n: 6, lda: 4, kL: 2, kU: 1, alpha: 3.0, beta: 2.0, a: [][]float64{ {5, 3, 0, 0, 0, 0}, {-1, 2, 9, 0, 0, 0}, {4, 8, 3, 6, 0, 0}, {0, -1, 8, 2, 1, 0}, {0, 0, 9, 9, 9, 5}, {0, 0, 0, 2, -3, 2}, {0, 0, 0, 0, 1, 5}, {0, 0, 0, 0, 0, 6}, }, x: []float64{1, 2, 3, 4, 5, 6}, y: []float64{-1, -2, -3, -4, -5, -6, -7, -8, -9}, ans: []float64{31, 86, 153, 97, 404, 3, 91, 92, -18}, }, { tA: blas.Trans, m: 9, n: 6, lda: 4, kL: 2, kU: 1, alpha: 3.0, beta: 2.0, a: [][]float64{ {5, 3, 0, 0, 0, 0}, {-1, 2, 9, 0, 0, 0}, {4, 8, 3, 6, 0, 0}, {0, -1, 8, 2, 1, 0}, {0, 0, 9, 9, 9, 5}, {0, 0, 0, 2, -3, 2}, {0, 0, 0, 0, 1, 5}, {0, 0, 0, 0, 0, 6}, }, x: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}, y: []float64{-1, -2, -3, -4, -5, -6}, ans: []float64{43, 77, 306, 241, 104, 348}, }, { tA: blas.NoTrans, m: 6, n: 3, lda: 1, kL: 0, kU: 0, alpha: 2.0, beta: 1.0, a: [][]float64{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, }, x: []float64{1, 2, 3}, y: []float64{-1, -2, -3, -4, -5, -6}, ans: []float64{1, 2, 3, -4, -5, -6}, }, { tA: blas.Trans, m: 6, n: 3, lda: 1, kL: 0, kU: 0, alpha: 2.0, beta: 1.0, a: [][]float64{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, }, x: []float64{1, 2, 3, 4, 5, 6}, y: []float64{-1, -2, -3}, ans: []float64{1, 2, 3}, }, { tA: blas.NoTrans, m: 3, n: 5, lda: 4, kL: 1, kU: 2, alpha: 2.0, beta: 1.0, a: [][]float64{ {1, 2, 3, 0, 0}, {1, 3, 6, 9, 0}, {0, 1, 1, 1, 1}, }, x: []float64{1, 2, 3, 4, 5}, y: []float64{-1, -2, -3}, ans: []float64{-1 + 2*(1+4+9), -2 + 2*(1+6+18+36), -3 + 2*(2+3+4+5)}, }, } { extra := 3 aFlat := flattenBanded(test.a, test.kU, test.kL) incTest := func(incX, incY, extra int) { xnew := makeIncremented(test.x, incX, extra) ynew := makeIncremented(test.y, incY, extra) ans := makeIncremented(test.ans, incY, extra) blasser.Dgbmv(test.tA, test.m, test.n, test.kL, test.kU, test.alpha, aFlat, test.lda, xnew, incX, test.beta, ynew, incY) if !dSliceTolEqual(ans, ynew) { t.Errorf("Case %v: Want %v, got %v", i, ans, ynew) } } incTest(1, 1, extra) incTest(1, 3, extra) incTest(1, -3, extra) incTest(2, 3, extra) incTest(2, -3, extra) incTest(3, 2, extra) incTest(-3, 2, extra) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dgemm.go000066400000000000000000000117151450372207100220250ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dgemmer interface { 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) } type DgemmCase struct { m, n, k int alpha, beta float64 a [][]float64 b [][]float64 c [][]float64 ans [][]float64 } var DgemmCases = []DgemmCase{ { m: 4, n: 3, k: 2, alpha: 2, beta: 0.5, a: [][]float64{ {1, 2}, {4, 5}, {7, 8}, {10, 11}, }, b: [][]float64{ {1, 5, 6}, {5, -8, 8}, }, c: [][]float64{ {4, 8, -9}, {12, 16, -8}, {1, 5, 15}, {-3, -4, 7}, }, ans: [][]float64{ {24, -18, 39.5}, {64, -32, 124}, {94.5, -55.5, 219.5}, {128.5, -78, 299.5}, }, }, { m: 4, n: 2, k: 3, alpha: 2, beta: 0.5, a: [][]float64{ {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}, }, b: [][]float64{ {1, 5}, {5, -8}, {6, 2}, }, c: [][]float64{ {4, 8}, {12, 16}, {1, 5}, {-3, -4}, }, ans: [][]float64{ {60, -6}, {136, -8}, {202.5, -19.5}, {272.5, -30}, }, }, { m: 3, n: 2, k: 4, alpha: 2, beta: 0.5, a: [][]float64{ {1, 2, 3, 4}, {4, 5, 6, 7}, {8, 9, 10, 11}, }, b: [][]float64{ {1, 5}, {5, -8}, {6, 2}, {8, 10}, }, c: [][]float64{ {4, 8}, {12, 16}, {9, -10}, }, ans: [][]float64{ {124, 74}, {248, 132}, {406.5, 191}, }, }, { m: 3, n: 4, k: 2, alpha: 2, beta: 0.5, a: [][]float64{ {1, 2}, {4, 5}, {8, 9}, }, b: [][]float64{ {1, 5, 2, 1}, {5, -8, 2, 1}, }, c: [][]float64{ {4, 8, 2, 2}, {12, 16, 8, 9}, {9, -10, 10, 10}, }, ans: [][]float64{ {24, -18, 13, 7}, {64, -32, 40, 22.5}, {110.5, -69, 73, 39}, }, }, { m: 2, n: 4, k: 3, alpha: 2, beta: 0.5, a: [][]float64{ {1, 2, 3}, {4, 5, 6}, }, b: [][]float64{ {1, 5, 8, 8}, {5, -8, 9, 10}, {6, 2, -3, 2}, }, c: [][]float64{ {4, 8, 7, 8}, {12, 16, -2, 6}, }, ans: [][]float64{ {60, -6, 37.5, 72}, {136, -8, 117, 191}, }, }, { m: 2, n: 3, k: 4, alpha: 2, beta: 0.5, a: [][]float64{ {1, 2, 3, 4}, {4, 5, 6, 7}, }, b: [][]float64{ {1, 5, 8}, {5, -8, 9}, {6, 2, -3}, {8, 10, 2}, }, c: [][]float64{ {4, 8, 1}, {12, 16, 6}, }, ans: [][]float64{ {124, 74, 50.5}, {248, 132, 149}, }, }, { m: 2, n: 3, k: 4, alpha: 2, beta: 0, a: [][]float64{ {1, 2, 3, 4}, {4, 5, 6, 7}, }, b: [][]float64{ {1, 5, 8}, {5, -8, 9}, {6, 2, -3}, {8, 10, 2}, }, c: [][]float64{ {4, 8, 1}, {12, 16, 6}, }, ans: [][]float64{ {122, 70, 50}, {242, 124, 146}, }, }, } // assumes [][]float64 is actually a matrix func transpose(a [][]float64) [][]float64 { b := make([][]float64, len(a[0])) for i := range b { b[i] = make([]float64, len(a)) for j := range b[i] { b[i][j] = a[j][i] } } return b } func TestDgemm(t *testing.T, blasser Dgemmer) { for i, test := range DgemmCases { // Test that it passes row major dgemmcomp(i, "RowMajorNoTrans", t, blasser, blas.NoTrans, blas.NoTrans, test.m, test.n, test.k, test.alpha, test.beta, test.a, test.b, test.c, test.ans) // Try with A transposed dgemmcomp(i, "RowMajorTransA", t, blasser, blas.Trans, blas.NoTrans, test.m, test.n, test.k, test.alpha, test.beta, transpose(test.a), test.b, test.c, test.ans) // Try with B transposed dgemmcomp(i, "RowMajorTransB", t, blasser, blas.NoTrans, blas.Trans, test.m, test.n, test.k, test.alpha, test.beta, test.a, transpose(test.b), test.c, test.ans) // Try with both transposed dgemmcomp(i, "RowMajorTransBoth", t, blasser, blas.Trans, blas.Trans, test.m, test.n, test.k, test.alpha, test.beta, transpose(test.a), transpose(test.b), test.c, test.ans) } } func dgemmcomp(i int, name string, t *testing.T, blasser Dgemmer, tA, tB blas.Transpose, m, n, k int, alpha, beta float64, a [][]float64, b [][]float64, c [][]float64, ans [][]float64) { aFlat := flatten(a) aCopy := flatten(a) bFlat := flatten(b) bCopy := flatten(b) cFlat := flatten(c) ansFlat := flatten(ans) lda := len(a[0]) ldb := len(b[0]) ldc := len(c[0]) // Compute the matrix multiplication blasser.Dgemm(tA, tB, m, n, k, alpha, aFlat, lda, bFlat, ldb, beta, cFlat, ldc) if !dSliceEqual(aFlat, aCopy) { t.Errorf("Test %v case %v: a changed during call to Dgemm", i, name) } if !dSliceEqual(bFlat, bCopy) { t.Errorf("Test %v case %v: b changed during call to Dgemm", i, name) } if !dSliceTolEqual(ansFlat, cFlat) { t.Errorf("Test %v case %v: answer mismatch. Expected %v, Found %v", i, name, ansFlat, cFlat) } // TODO: Need to add a sub-slice test where don't use up full matrix } golang-gonum-v1-gonum-0.14.0/blas/testblas/dgemmbench.go000066400000000000000000000014731450372207100230250ustar00rootroot00000000000000// 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 testblas import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) func DgemmBenchmark(b *testing.B, dgemm Dgemmer, m, n, k int, tA, tB blas.Transpose) { a := make([]float64, m*k) for i := range a { a[i] = rand.Float64() } bv := make([]float64, k*n) for i := range bv { bv[i] = rand.Float64() } c := make([]float64, m*n) for i := range c { c[i] = rand.Float64() } var lda, ldb int if tA == blas.Trans { lda = m } else { lda = k } if tB == blas.Trans { ldb = k } else { ldb = n } ldc := n b.ResetTimer() for i := 0; i < b.N; i++ { dgemm.Dgemm(tA, tB, m, n, k, 3.0, a, lda, bv, ldb, 1.0, c, ldc) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dgemv.go000066400000000000000000000352561450372207100220440ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type DgemvCase struct { Name string m int n int A [][]float64 tA blas.Transpose x []float64 incX int y []float64 incY int Subcases []DgemvSubcase } type DgemvSubcase struct { mulXNeg1 bool mulYNeg1 bool alpha float64 beta float64 ans []float64 } var DgemvCases = []DgemvCase{ { Name: "M_gt_N_Inc1_NoTrans", tA: blas.NoTrans, m: 5, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, {1, 1, 2}, {9, 2, 5}, }, incX: 1, incY: 1, x: []float64{1, 2, 3}, y: []float64{7, 8, 9, 10, 11}, Subcases: []DgemvSubcase{ { alpha: 0, beta: 0, ans: []float64{0, 0, 0, 0, 0}, }, { alpha: 0, beta: 1, ans: []float64{7, 8, 9, 10, 11}, }, { alpha: 1, beta: 0, ans: []float64{40.8, 43.9, 33, 9, 28}, }, { alpha: 8, beta: -6, ans: []float64{284.4, 303.2, 210, 12, 158}, }, }, }, { Name: "M_gt_N_Inc1_Trans", tA: blas.Trans, m: 5, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, {1, 1, 2}, {9, 2, 5}, }, incX: 1, incY: 1, x: []float64{1, 2, 3, -4, 5}, y: []float64{7, 8, 9}, Subcases: []DgemvSubcase{ { alpha: 0, beta: 0, ans: []float64{0, 0, 0}, }, { alpha: 0, beta: 1, ans: []float64{7, 8, 9}, }, { alpha: 1, beta: 0, ans: []float64{94.3, 40.2, 52.3}, }, { alpha: 8, beta: -6, ans: []float64{712.4, 273.6, 364.4}, }, }, }, { Name: "M_eq_N_Inc1_NoTrans", tA: blas.NoTrans, m: 3, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, }, incX: 1, incY: 1, x: []float64{1, 2, 3}, y: []float64{7, 2, 2}, Subcases: []DgemvSubcase{ { alpha: 0, beta: 0, ans: []float64{0, 0, 0}, }, { alpha: 0, beta: 1, ans: []float64{7, 2, 2}, }, { alpha: 1, beta: 0, ans: []float64{40.8, 43.9, 33}, }, { alpha: 8, beta: -6, ans: []float64{40.8*8 - 6*7, 43.9*8 - 6*2, 33*8 - 6*2}, }, }, }, { Name: "M_eq_N_Inc1_Trans", tA: blas.Trans, m: 3, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, }, incX: 1, incY: 1, x: []float64{1, 2, 3}, y: []float64{7, 2, 2}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{384.4, 261.6, 270.4}, }, }, }, { Name: "M_lt_N_Inc1_NoTrans", tA: blas.NoTrans, m: 3, n: 5, A: [][]float64{ {4.1, 6.2, 8.1, 10, 7}, {9.6, 3.5, 9.1, -2, 9}, {10, 7, 3, 1, -5}, }, incX: 1, incY: 1, x: []float64{1, 2, 3, -7.6, 8.1}, y: []float64{7, 2, 2}, Subcases: []DgemvSubcase{ { alpha: 0, beta: 0, ans: []float64{0, 0, 0}, }, { alpha: 0, beta: 1, ans: []float64{7, 2, 2}, }, { alpha: 1, beta: 0, ans: []float64{21.5, 132, -15.1}, }, { alpha: 8, beta: -6, ans: []float64{21.5*8 - 6*7, 132*8 - 6*2, -15.1*8 - 6*2}, }, }, }, { Name: "M_lt_N_Inc1_Trans", tA: blas.Trans, m: 3, n: 5, A: [][]float64{ {4.1, 6.2, 8.1, 10, 7}, {9.6, 3.5, 9.1, -2, 9}, {10, 7, 3, 1, -5}, }, incX: 1, incY: 1, x: []float64{1, 2, 3}, y: []float64{7, 2, 2, -3, 5}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{384.4, 261.6, 270.4, 90, 50}, }, }, }, { Name: "M_gt_N_Part1_NoTrans", tA: blas.NoTrans, m: 5, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, {1, 1, 2}, {9, 2, 5}, }, incX: 1, incY: 2, x: []float64{1, 2, 3}, y: []float64{7, 100, 8, 101, 9, 102, 10, 103, 11}, Subcases: []DgemvSubcase{ { alpha: 0, beta: 0, ans: []float64{0, 100, 0, 101, 0, 102, 0, 103, 0}, }, { alpha: 0, beta: 1, ans: []float64{7, 100, 8, 101, 9, 102, 10, 103, 11}, }, { alpha: 1, beta: 0, ans: []float64{40.8, 100, 43.9, 101, 33, 102, 9, 103, 28}, }, { alpha: 8, beta: -6, ans: []float64{284.4, 100, 303.2, 101, 210, 102, 12, 103, 158}, }, }, }, { Name: "M_gt_N_Part1_Trans", tA: blas.Trans, m: 5, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, {1, 1, 2}, {9, 2, 5}, }, incX: 1, incY: 2, x: []float64{1, 2, 3, -4, 5}, y: []float64{7, 100, 8, 101, 9}, Subcases: []DgemvSubcase{ { alpha: 0, beta: 0, ans: []float64{0, 100, 0, 101, 0}, }, { alpha: 0, beta: 1, ans: []float64{7, 100, 8, 101, 9}, }, { alpha: 1, beta: 0, ans: []float64{94.3, 100, 40.2, 101, 52.3}, }, { alpha: 8, beta: -6, ans: []float64{712.4, 100, 273.6, 101, 364.4}, }, }, }, { Name: "M_gt_N_IncNot1_NoTrans", tA: blas.NoTrans, m: 5, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, {1, 1, 2}, {9, 2, 5}, }, incX: 2, incY: 3, x: []float64{1, 15, 2, 150, 3}, y: []float64{7, 2, 6, 8, -4, -5, 9, 1, 1, 10, 19, 22, 11}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{284.4, 2, 6, 303.2, -4, -5, 210, 1, 1, 12, 19, 22, 158}, }, { mulXNeg1: true, alpha: 8, beta: -6, ans: []float64{220.4, 2, 6, 311.2, -4, -5, 322, 1, 1, -4, 19, 22, 222}, }, { mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{182, 2, 6, 24, -4, -5, 210, 1, 1, 291.2, 19, 22, 260.4}, }, { mulXNeg1: true, mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{246, 2, 6, 8, -4, -5, 322, 1, 1, 299.2, 19, 22, 196.4}, }, }, }, { Name: "M_gt_N_IncNot1_Trans", tA: blas.Trans, m: 5, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, {1, 1, 2}, {9, 2, 5}, }, incX: 2, incY: 3, x: []float64{1, 15, 2, 150, 3, 8, -3, 6, 5}, y: []float64{7, 2, 6, 8, -4, -5, 9}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{720.4, 2, 6, 281.6, -4, -5, 380.4}, }, { mulXNeg1: true, alpha: 8, beta: -6, ans: []float64{219.6, 2, 6, 316, -4, -5, 195.6}, }, { mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{392.4, 2, 6, 281.6, -4, -5, 708.4}, }, { mulXNeg1: true, mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{207.6, 2, 6, 316, -4, -5, 207.6}, }, }, }, { Name: "M_eq_N_IncNot1_NoTrans", tA: blas.NoTrans, m: 3, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, }, incX: 2, incY: 3, x: []float64{1, 15, 2, 150, 3}, y: []float64{7, 2, 6, 8, -4, -5, 9}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{284.4, 2, 6, 303.2, -4, -5, 210}, }, { mulXNeg1: true, alpha: 8, beta: -6, ans: []float64{220.4, 2, 6, 311.2, -4, -5, 322}, }, { mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{222, 2, 6, 303.2, -4, -5, 272.4}, }, { mulXNeg1: true, mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{334, 2, 6, 311.2, -4, -5, 208.4}, }, }, }, { Name: "M_eq_N_IncNot1_Trans", tA: blas.Trans, m: 3, n: 3, A: [][]float64{ {4.1, 6.2, 8.1}, {9.6, 3.5, 9.1}, {10, 7, 3}, }, incX: 2, incY: 3, x: []float64{1, 15, 2, 150, 3}, y: []float64{7, 2, 6, 8, -4, -5, 9}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{384.4, 2, 6, 225.6, -4, -5, 228.4}, }, { mulXNeg1: true, alpha: 8, beta: -6, ans: []float64{290, 2, 6, 212.8, -4, -5, 310}, }, { mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{240.4, 2, 6, 225.6, -4, -5, 372.4}, }, { mulXNeg1: true, mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{322, 2, 6, 212.8, -4, -5, 278}, }, }, }, { Name: "M_lt_N_IncNot1_NoTrans", tA: blas.NoTrans, m: 3, n: 5, A: [][]float64{ {4.1, 6.2, 8.1, 10, 11}, {9.6, 3.5, 9.1, -3, -2}, {10, 7, 3, -7, -4}, }, incX: 2, incY: 3, x: []float64{1, 15, 2, 150, 3, -2, -4, 8, -9}, y: []float64{7, 2, 6, 8, -4, -5, 9}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{-827.6, 2, 6, 543.2, -4, -5, 722}, }, { mulXNeg1: true, alpha: 8, beta: -6, ans: []float64{-93.2, 2, 6, -696.8, -4, -5, -1070}, }, { mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{734, 2, 6, 543.2, -4, -5, -839.6}, }, { mulXNeg1: true, mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{-1058, 2, 6, -696.8, -4, -5, -105.2}, }, }, }, { Name: "M_lt_N_IncNot1_Trans", tA: blas.Trans, m: 3, n: 5, A: [][]float64{ {4.1, 6.2, 8.1, 10, 11}, {9.6, 3.5, 9.1, -3, -2}, {10, 7, 3, -7, -4}, }, incX: 2, incY: 3, x: []float64{1, 15, 2, 150, 3}, y: []float64{7, 2, 6, 8, -4, -5, 9, -4, -1, -9, 1, 1, 2}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{384.4, 2, 6, 225.6, -4, -5, 228.4, -4, -1, -82, 1, 1, -52}, }, { mulXNeg1: true, alpha: 8, beta: -6, ans: []float64{290, 2, 6, 212.8, -4, -5, 310, -4, -1, 190, 1, 1, 188}, }, { mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{-82, 2, 6, -184, -4, -5, 228.4, -4, -1, 327.6, 1, 1, 414.4}, }, { mulXNeg1: true, mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{158, 2, 6, 88, -4, -5, 310, -4, -1, 314.8, 1, 1, 320}, }, }, }, { Name: "M_eq_N_Lg_IncNot1_Trans", tA: blas.Trans, m: 7, n: 7, A: [][]float64{ {4.1, 6.2, 8.1, 2.5, 3.3, 7.4, 9.3}, {9.6, 3.5, 9.1, 1.2, 5.4, 4.8, 8.7}, {10, 7, 3, 2, 4, 1, 12}, {9.6, 3.5, 9.1, 1.2, 5.4, 4.8, 8.7}, {4.1, 6.2, 8.1, 2.5, 3.3, 7.4, 9.3}, {10, 7, 3, 2, 4, 1, 12}, {9.6, 3.5, 9.1, 1.2, 5.4, 4.8, 8.7}, }, incX: 2, incY: 3, x: []float64{1, 105, 2, 150, 3, 200, 4, 300, 5, 600, 6, 700, 7}, y: []float64{7, 200, 600, 8, -400, -500, 9, 600, 700, 10, 500, 400, 11, 200, 300, 12, 100, 200, 13, 300, 400, 14}, Subcases: []DgemvSubcase{ { alpha: 8, beta: -6, ans: []float64{1873.1999999999998, 200, 600, 1117.6, -400, -500, 1497.1999999999998, 600, 700, 328.8, 500, 400, 942, 200, 300, 854.4000000000001, 100, 200, 2137.2, 300, 400, 14}, }, { mulXNeg1: true, alpha: 8, beta: -6, ans: []float64{1690.8, 200, 600, 1148, -400, -500, 1562.8, 600, 700, 357.6, 500, 400, 897.2, 200, 300, 998.4, 100, 200, 2103.6000000000004, 300, 400, 14}, }, { mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{2173.2, 200, 600, 878.4000000000001, -400, -500, 954, 600, 700, 328.8, 500, 400, 1485.1999999999998, 200, 300, 1093.6, 100, 200, 1837.1999999999998, 300, 400, 14}, }, { mulXNeg1: true, mulYNeg1: true, alpha: 8, beta: -6, ans: []float64{2139.6, 200, 600, 1022.4, -400, -500, 909.2, 600, 700, 357.6, 500, 400, 1550.8, 200, 300, 1124, 100, 200, 1654.8, 300, 400, 14}, }, }, }, // TODO: A can be longer than mxn. Add cases where it is longer // TODO: x and y can also be longer. Add tests for these // TODO: Add tests for dimension mismatch // TODO: Add places with a "submatrix view", where lda != m } type Dgemver interface { Dgemv(tA blas.Transpose, m, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) } func DgemvTest(t *testing.T, blasser Dgemver) { for _, test := range DgemvCases { for i, cas := range test.Subcases { // Test that it passes with row-major dgemvcomp(t, test, cas, i, blasser) // Test the bad inputs dgemvbad(t, test, cas, i, blasser) } } } func dgemvcomp(t *testing.T, test DgemvCase, cas DgemvSubcase, i int, blasser Dgemver) { x := sliceCopy(test.x) y := sliceCopy(test.y) a := sliceOfSliceCopy(test.A) aFlat := flatten(a) lda := test.n incX := test.incX if cas.mulXNeg1 { incX *= -1 } incY := test.incY if cas.mulYNeg1 { incY *= -1 } f := func() { blasser.Dgemv(test.tA, test.m, test.n, cas.alpha, aFlat, lda, x, incX, cas.beta, y, incY) } if panics(f) { t.Errorf("Test %v case %v: unexpected panic", test.Name, i) if throwPanic { blasser.Dgemv(test.tA, test.m, test.n, cas.alpha, aFlat, lda, x, incX, cas.beta, y, incY) } return } // Check that x and a are unchanged if !dSliceEqual(x, test.x) { t.Errorf("Test %v, case %v: x modified during call", test.Name, i) } aFlat2 := flatten(sliceOfSliceCopy(test.A)) if !dSliceEqual(aFlat2, aFlat) { t.Errorf("Test %v, case %v: a modified during call", test.Name, i) } // Check that the answer matches if !dSliceTolEqual(cas.ans, y) { t.Errorf("Test %v, case %v: answer mismatch: Expected %v, Found %v", test.Name, i, cas.ans, y) } } func dgemvbad(t *testing.T, test DgemvCase, cas DgemvSubcase, i int, blasser Dgemver) { x := sliceCopy(test.x) y := sliceCopy(test.y) a := sliceOfSliceCopy(test.A) aFlatRow := flatten(a) ldaRow := test.n f := func() { blasser.Dgemv('X', test.m, test.n, cas.alpha, aFlatRow, ldaRow, x, test.incX, cas.beta, y, test.incY) } if !panics(f) { t.Errorf("Test %v case %v: no panic for bad transpose", test.Name, i) } f = func() { blasser.Dgemv(test.tA, -2, test.n, cas.alpha, aFlatRow, ldaRow, x, test.incX, cas.beta, y, test.incY) } if !panics(f) { t.Errorf("Test %v case %v: no panic for m negative", test.Name, i) } f = func() { blasser.Dgemv(test.tA, test.m, -4, cas.alpha, aFlatRow, ldaRow, x, test.incX, cas.beta, y, test.incY) } if !panics(f) { t.Errorf("Test %v case %v: no panic for n negative", test.Name, i) } f = func() { blasser.Dgemv(test.tA, test.m, test.n, cas.alpha, aFlatRow, ldaRow, x, 0, cas.beta, y, test.incY) } if !panics(f) { t.Errorf("Test %v case %v: no panic for incX zero", test.Name, i) } f = func() { blasser.Dgemv(test.tA, test.m, test.n, cas.alpha, aFlatRow, ldaRow, x, test.incX, cas.beta, y, 0) } if !panics(f) { t.Errorf("Test %v case %v: no panic for incY zero", test.Name, i) } f = func() { blasser.Dgemv(test.tA, test.m, test.n, cas.alpha, aFlatRow, ldaRow-1, x, test.incX, cas.beta, y, test.incY) } if !panics(f) { t.Errorf("Test %v case %v: no panic for lda too small row major", test.Name, i) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dger.go000066400000000000000000000152361450372207100216570ustar00rootroot00000000000000// 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 testblas import ( "math" "testing" ) type Dgerer interface { Dger(m, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int) } func DgerTest(t *testing.T, blasser Dgerer) { for _, test := range []struct { name string a [][]float64 m int n int x []float64 y []float64 incX int incY int want [][]float64 }{ { name: "M gt N inc 1", m: 5, n: 3, a: [][]float64{ {1.3, 2.4, 3.5}, {2.6, 2.8, 3.3}, {-1.3, -4.3, -9.7}, {8, 9, -10}, {-12, -14, -6}, }, x: []float64{-2, -3, 0, 1, 2}, y: []float64{-1.1, 5, 0}, incX: 1, incY: 1, want: [][]float64{{3.5, -7.6, 3.5}, {5.9, -12.2, 3.3}, {-1.3, -4.3, -9.7}, {6.9, 14, -10}, {-14.2, -4, -6}}, }, { name: "M eq N inc 1", m: 3, n: 3, a: [][]float64{ {1.3, 2.4, 3.5}, {2.6, 2.8, 3.3}, {-1.3, -4.3, -9.7}, }, x: []float64{-2, -3, 0}, y: []float64{-1.1, 5, 0}, incX: 1, incY: 1, want: [][]float64{{3.5, -7.6, 3.5}, {5.9, -12.2, 3.3}, {-1.3, -4.3, -9.7}}, }, { name: "M lt N inc 1", m: 3, n: 6, a: [][]float64{ {1.3, 2.4, 3.5, 4.8, 1.11, -9}, {2.6, 2.8, 3.3, -3.4, 6.2, -8.7}, {-1.3, -4.3, -9.7, -3.1, 8.9, 8.9}, }, x: []float64{-2, -3, 0}, y: []float64{-1.1, 5, 0, 9, 19, 22}, incX: 1, incY: 1, want: [][]float64{{3.5, -7.6, 3.5, -13.2, -36.89, -53}, {5.9, -12.2, 3.3, -30.4, -50.8, -74.7}, {-1.3, -4.3, -9.7, -3.1, 8.9, 8.9}}, }, { name: "M gt N inc not 1", m: 5, n: 3, a: [][]float64{ {1.3, 2.4, 3.5}, {2.6, 2.8, 3.3}, {-1.3, -4.3, -9.7}, {8, 9, -10}, {-12, -14, -6}, }, x: []float64{-2, -3, 0, 1, 2, 6, 0, 9, 7}, y: []float64{-1.1, 5, 0, 8, 7, -5, 7}, incX: 2, incY: 3, want: [][]float64{{3.5, -13.6, -10.5}, {2.6, 2.8, 3.3}, {-3.5, 11.7, 4.3}, {8, 9, -10}, {-19.700000000000003, 42, 43}}, }, { name: "M eq N inc not 1", m: 3, n: 3, a: [][]float64{ {1.3, 2.4, 3.5}, {2.6, 2.8, 3.3}, {-1.3, -4.3, -9.7}, }, x: []float64{-2, -3, 0, 8, 7, -9, 7, -6, 12, 6, 6, 6, -11}, y: []float64{-1.1, 5, 0, 0, 9, 8, 6}, incX: 4, incY: 3, want: [][]float64{{3.5, 2.4, -8.5}, {-5.1, 2.8, 45.3}, {-14.5, -4.3, 62.3}}, }, { name: "M lt N inc not 1", m: 3, n: 6, a: [][]float64{ {1.3, 2.4, 3.5, 4.8, 1.11, -9}, {2.6, 2.8, 3.3, -3.4, 6.2, -8.7}, {-1.3, -4.3, -9.7, -3.1, 8.9, 8.9}, }, x: []float64{-2, -3, 0, 0, 8, 0, 9, -3}, y: []float64{-1.1, 5, 0, 9, 19, 22, 11, -8.11, -9.22, 9.87, 7}, incX: 3, incY: 2, want: [][]float64{{3.5, 2.4, -34.5, -17.2, 19.55, -23}, {2.6, 2.8, 3.3, -3.4, 6.2, -8.7}, {-11.2, -4.3, 161.3, 95.9, -74.08, 71.9}}, }, { name: "Y NaN element", m: 1, n: 1, a: [][]float64{{1.3}}, x: []float64{1.3}, y: []float64{math.NaN()}, incX: 1, incY: 1, want: [][]float64{{math.NaN()}}, }, { name: "M eq N large inc 1", m: 7, n: 7, x: []float64{6.2, -5, 88.68, 43.4, -30.5, -40.2, 19.9}, y: []float64{1.5, 21.7, -28.7, -11.9, 18.1, 3.1, 21}, a: [][]float64{ {-20.5, 17.1, -8.4, -23.8, 3.9, 7.7, 6.25}, {2.9, -0.29, 25.6, -9.4, 36.5, 9.7, 2.3}, {4.1, -34.1, 10.3, 4.5, -42.05, 9.4, 4}, {19.2, 9.8, -32.7, 4.1, 4.4, -22.5, -7.8}, {3.6, -24.5, 21.7, 8.6, -13.82, 38.05, -2.29}, {39.4, -40.5, 7.9, -2.5, -7.7, 18.1, -25.5}, {-18.5, 43.2, 2.1, 30.1, 3.02, -31.1, -7.6}, }, incX: 1, incY: 1, want: [][]float64{ {-11.2, 151.64, -186.34, -97.58, 116.12, 26.92, 136.45}, {-4.6, -108.79, 169.1, 50.1, -54, -5.8, -102.7}, {137.12, 1890.256, -2534.816, -1050.792, 1563.058, 284.308, 1866.28}, {84.3, 951.58, -1278.28, -512.36, 789.94, 112.04, 903.6}, {-42.15, -686.35, 897.05, 371.55, -565.87, -56.5, -642.79}, {-20.9, -912.84, 1161.64, 475.88, -735.32, -106.52, -869.7}, {11.35, 475.03, -569.03, -206.71, 363.21, 30.59, 410.3}, }, }, { name: "M eq N large inc not 1", m: 7, n: 7, x: []float64{6.2, 100, 200, -5, 300, 400, 88.68, 100, 200, 43.4, 300, 400, -30.5, 100, 200, -40.2, 300, 400, 19.9}, y: []float64{1.5, 100, 200, 300, 21.7, 100, 200, 300, -28.7, 100, 200, 300, -11.9, 100, 200, 300, 18.1, 100, 200, 300, 3.1, 100, 200, 300, 21}, a: [][]float64{ {-20.5, 17.1, -8.4, -23.8, 3.9, 7.7, 6.25}, {2.9, -0.29, 25.6, -9.4, 36.5, 9.7, 2.3}, {4.1, -34.1, 10.3, 4.5, -42.05, 9.4, 4}, {19.2, 9.8, -32.7, 4.1, 4.4, -22.5, -7.8}, {3.6, -24.5, 21.7, 8.6, -13.82, 38.05, -2.29}, {39.4, -40.5, 7.9, -2.5, -7.7, 18.1, -25.5}, {-18.5, 43.2, 2.1, 30.1, 3.02, -31.1, -7.6}, }, incX: 3, incY: 4, want: [][]float64{ {-11.2, 151.64, -186.34, -97.58, 116.12, 26.92, 136.45}, {-4.6, -108.79, 169.1, 50.1, -54, -5.8, -102.7}, {137.12, 1890.256, -2534.816, -1050.792, 1563.058, 284.308, 1866.28}, {84.3, 951.58, -1278.28, -512.36, 789.94, 112.04, 903.6}, {-42.15, -686.35, 897.05, 371.55, -565.87, -56.5, -642.79}, {-20.9, -912.84, 1161.64, 475.88, -735.32, -106.52, -869.7}, {11.35, 475.03, -569.03, -206.71, 363.21, 30.59, 410.3}, }, }, } { // TODO: Add tests where a is longer // TODO: Add panic tests // TODO: Add negative increment tests x := sliceCopy(test.x) y := sliceCopy(test.y) a := sliceOfSliceCopy(test.a) // Test with row major alpha := 1.0 aFlat := flatten(a) blasser.Dger(test.m, test.n, alpha, x, test.incX, y, test.incY, aFlat, test.n) ans := unflatten(aFlat, test.m, test.n) dgercomp(t, x, test.x, y, test.y, ans, test.want, test.name+" row maj") // Test with different alpha alpha = 4.0 aFlat = flatten(a) blasser.Dger(test.m, test.n, alpha, x, test.incX, y, test.incY, aFlat, test.n) ans = unflatten(aFlat, test.m, test.n) trueCopy := sliceOfSliceCopy(test.want) for i := range trueCopy { for j := range trueCopy[i] { trueCopy[i][j] = alpha*(trueCopy[i][j]-a[i][j]) + a[i][j] } } dgercomp(t, x, test.x, y, test.y, ans, trueCopy, test.name+" row maj alpha") } } func dgercomp(t *testing.T, x, xCopy, y, yCopy []float64, ans [][]float64, trueAns [][]float64, name string) { if !dSliceEqual(x, xCopy) { t.Errorf("case %v: x modified during call to dger\n%v\n%v", name, x, xCopy) } if !dSliceEqual(y, yCopy) { t.Errorf("case %v: y modified during call to dger\n%v\n%v", name, y, yCopy) } for i := range ans { if !dSliceTolEqual(ans[i], trueAns[i]) { t.Errorf("case %v: answer mismatch at %v.\nExpected %v,\nFound %v", name, i, trueAns, ans) break } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/doc.go000066400000000000000000000004401450372207100214720ustar00rootroot00000000000000// 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 testblas provides tests for blas implementations. package testblas // import "gonum.org/v1/gonum/blas/testblas" golang-gonum-v1-gonum-0.14.0/blas/testblas/dsbmv.go000066400000000000000000000036001450372207100220410ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dsbmver interface { Dsbmv(ul blas.Uplo, n, k int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) } func DsbmvTest(t *testing.T, blasser Dsbmver) { for i, test := range []struct { ul blas.Uplo n int k int alpha float64 beta float64 a [][]float64 x []float64 y []float64 ans []float64 }{ { ul: blas.Upper, n: 4, k: 2, alpha: 2, beta: 3, a: [][]float64{ {7, 8, 2, 0}, {0, 8, 2, -3}, {0, 0, 3, 6}, {0, 0, 0, 9}, }, x: []float64{1, 2, 3, 4}, y: []float64{-1, -2, -3, -4}, ans: []float64{55, 30, 69, 84}, }, { ul: blas.Lower, n: 4, k: 2, alpha: 2, beta: 3, a: [][]float64{ {7, 0, 0, 0}, {8, 8, 0, 0}, {2, 2, 3, 0}, {0, -3, 6, 9}, }, x: []float64{1, 2, 3, 4}, y: []float64{-1, -2, -3, -4}, ans: []float64{55, 30, 69, 84}, }, } { extra := 0 var aFlat []float64 if test.ul == blas.Upper { aFlat = flattenBanded(test.a, test.k, 0) } else { aFlat = flattenBanded(test.a, 0, test.k) } incTest := func(incX, incY, extra int) { xnew := makeIncremented(test.x, incX, extra) ynew := makeIncremented(test.y, incY, extra) ans := makeIncremented(test.ans, incY, extra) blasser.Dsbmv(test.ul, test.n, test.k, test.alpha, aFlat, test.k+1, xnew, incX, test.beta, ynew, incY) if !dSliceTolEqual(ans, ynew) { t.Errorf("Case %v: Want %v, got %v", i, ans, ynew) } } incTest(1, 1, extra) incTest(1, 3, extra) incTest(1, -3, extra) incTest(2, 3, extra) incTest(2, -3, extra) incTest(3, 2, extra) incTest(-3, 2, extra) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dspmv.go000066400000000000000000000032461450372207100220650ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dspmver interface { Dspmv(ul blas.Uplo, n int, alpha float64, ap []float64, x []float64, incX int, beta float64, y []float64, incY int) } func DspmvTest(t *testing.T, blasser Dspmver) { for i, test := range []struct { ul blas.Uplo n int a [][]float64 x []float64 y []float64 alpha float64 beta float64 ans []float64 }{ { ul: blas.Upper, n: 3, a: [][]float64{ {5, 6, 7}, {0, 8, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, y: []float64{6, 7, 8}, alpha: 2.1, beta: -3, ans: []float64{137.4, 189, 240.6}, }, { ul: blas.Lower, n: 3, a: [][]float64{ {5, 0, 0}, {6, 8, 0}, {7, 10, 13}, }, x: []float64{3, 4, 5}, y: []float64{6, 7, 8}, alpha: 2.1, beta: -3, ans: []float64{137.4, 189, 240.6}, }, } { incTest := func(incX, incY, extra int) { x := makeIncremented(test.x, incX, extra) y := makeIncremented(test.y, incY, extra) aFlat := flattenTriangular(test.a, test.ul) ans := makeIncremented(test.ans, incY, extra) blasser.Dspmv(test.ul, test.n, test.alpha, aFlat, x, incX, test.beta, y, incY) if !floats.EqualApprox(ans, y, 1e-14) { t.Errorf("Case %v, incX=%v, incY=%v: Want %v, got %v.", i, incX, incY, ans, y) } } incTest(1, 1, 0) incTest(2, 3, 0) incTest(3, 2, 0) incTest(-3, 2, 0) incTest(-2, 4, 0) incTest(2, -1, 0) incTest(-3, -4, 3) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dspr.go000066400000000000000000000027101450372207100216770ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dsprer interface { Dspr(ul blas.Uplo, n int, alpha float64, x []float64, incX int, a []float64) } func DsprTest(t *testing.T, blasser Dsprer) { for i, test := range []struct { ul blas.Uplo n int a [][]float64 x []float64 alpha float64 ans [][]float64 }{ { ul: blas.Upper, n: 4, a: [][]float64{ {10, 2, 0, 1}, {0, 1, 2, 3}, {0, 0, 9, 15}, {0, 0, 0, -6}, }, x: []float64{1, 2, 0, 5}, alpha: 8, ans: [][]float64{ {18, 18, 0, 41}, {0, 33, 2, 83}, {0, 0, 9, 15}, {0, 0, 0, 194}, }, }, { ul: blas.Lower, n: 3, a: [][]float64{ {10, 2, 0}, {4, 1, 2}, {2, 7, 9}, }, x: []float64{3, 0, 5}, alpha: 8, ans: [][]float64{ {82, 2, 0}, {4, 1, 2}, {122, 7, 209}, }, }, } { incTest := func(incX, extra int) { xnew := makeIncremented(test.x, incX, extra) aFlat := flattenTriangular(test.a, test.ul) ans := flattenTriangular(test.ans, test.ul) blasser.Dspr(test.ul, test.n, test.alpha, xnew, incX, aFlat) if !dSliceTolEqual(aFlat, ans) { t.Errorf("Case %v, idx %v: Want %v, got %v.", i, incX, ans, aFlat) } } incTest(1, 3) incTest(1, 0) incTest(3, 2) incTest(-2, 2) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dspr2.go000066400000000000000000000032571450372207100217700ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dspr2er interface { Dspr2(ul blas.Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64) } func Dspr2Test(t *testing.T, blasser Dspr2er) { for i, test := range []struct { n int a [][]float64 ul blas.Uplo x []float64 y []float64 alpha float64 ans [][]float64 }{ { n: 3, a: [][]float64{ {7, 2, 4}, {0, 3, 5}, {0, 0, 6}, }, x: []float64{2, 3, 4}, y: []float64{5, 6, 7}, alpha: 2, ul: blas.Upper, ans: [][]float64{ {47, 56, 72}, {0, 75, 95}, {0, 0, 118}, }, }, { n: 3, a: [][]float64{ {7, 0, 0}, {2, 3, 0}, {4, 5, 6}, }, x: []float64{2, 3, 4}, y: []float64{5, 6, 7}, alpha: 2, ul: blas.Lower, ans: [][]float64{ {47, 0, 0}, {56, 75, 0}, {72, 95, 118}, }, }, } { incTest := func(incX, incY, extra int) { aFlat := flattenTriangular(test.a, test.ul) x := makeIncremented(test.x, incX, extra) y := makeIncremented(test.y, incY, extra) blasser.Dspr2(test.ul, test.n, test.alpha, x, incX, y, incY, aFlat) ansFlat := flattenTriangular(test.ans, test.ul) if !floats.EqualApprox(aFlat, ansFlat, 1e-14) { t.Errorf("Case %v, incX = %v, incY = %v. Want %v, got %v.", i, incX, incY, ansFlat, aFlat) } } incTest(1, 1, 0) incTest(-2, 1, 0) incTest(-2, 3, 0) incTest(2, -3, 0) incTest(3, -2, 0) incTest(-3, -4, 0) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dsymm.go000066400000000000000000000225471450372207100220720ustar00rootroot00000000000000// 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 testblas import ( "math" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dsymmer interface { 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) } func DsymmTest(t *testing.T, blasser Dsymmer) { for i, test := range []struct { m int n int side blas.Side ul blas.Uplo a [][]float64 b [][]float64 c [][]float64 alpha float64 beta float64 ans [][]float64 }{ { side: blas.Left, ul: blas.Upper, m: 3, n: 4, a: [][]float64{ {2, 3, 4}, {0, 6, 7}, {0, 0, 10}, }, b: [][]float64{ {2, 3, 4, 8}, {5, 6, 7, 15}, {8, 9, 10, 20}, }, c: [][]float64{ {8, 12, 2, 1}, {9, 12, 9, 9}, {12, 1, -1, 5}, }, alpha: 2, beta: 3, ans: [][]float64{ {126, 156, 144, 285}, {211, 252, 275, 535}, {282, 291, 327, 689}, }, }, { side: blas.Left, ul: blas.Upper, m: 3, n: 4, a: [][]float64{ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, }, b: [][]float64{ {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, }, c: [][]float64{ {8, 12, 2, 1}, {9, 12, 9, 9}, {12, 1, -1, 5}, }, alpha: 0, beta: 2, ans: [][]float64{ {16, 24, 4, 2}, {18, 24, 18, 18}, {24, 2, -2, 10}, }, }, { side: blas.Left, ul: blas.Upper, m: 4, n: 3, a: [][]float64{ {2, 3, 4, 8}, {0, 6, 7, 9}, {0, 0, 10, 10}, {0, 0, 0, 11}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {8, 12, 2}, {9, 12, 9}, {12, 1, -1}, {1, 9, 5}, }, alpha: 2, beta: 3, ans: [][]float64{ {158, 172, 160}, {247, 270, 293}, {322, 311, 347}, {329, 385, 427}, }, }, { side: blas.Left, ul: blas.Lower, m: 3, n: 4, a: [][]float64{ {2, 0, 0}, {3, 6, 0}, {4, 7, 10}, }, b: [][]float64{ {2, 3, 4, 8}, {5, 6, 7, 15}, {8, 9, 10, 20}, }, c: [][]float64{ {8, 12, 2, 1}, {9, 12, 9, 9}, {12, 1, -1, 5}, }, alpha: 2, beta: 3, ans: [][]float64{ {126, 156, 144, 285}, {211, 252, 275, 535}, {282, 291, 327, 689}, }, }, { side: blas.Left, ul: blas.Lower, m: 4, n: 3, a: [][]float64{ {2, 0, 0, 0}, {3, 6, 0, 0}, {4, 7, 10, 0}, {8, 9, 10, 11}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {8, 12, 2}, {9, 12, 9}, {12, 1, -1}, {1, 9, 5}, }, alpha: 2, beta: 3, ans: [][]float64{ {158, 172, 160}, {247, 270, 293}, {322, 311, 347}, {329, 385, 427}, }, }, { side: blas.Right, ul: blas.Upper, m: 3, n: 4, a: [][]float64{ {2, 0, 0, 0}, {3, 6, 0, 0}, {4, 7, 10, 0}, {3, 4, 5, 6}, }, b: [][]float64{ {2, 3, 4, 9}, {5, 6, 7, -3}, {8, 9, 10, -2}, }, c: [][]float64{ {8, 12, 2, 10}, {9, 12, 9, 10}, {12, 1, -1, 10}, }, alpha: 2, beta: 3, ans: [][]float64{ {32, 72, 86, 138}, {47, 108, 167, -6}, {68, 111, 197, 6}, }, }, { side: blas.Right, ul: blas.Upper, m: 4, n: 3, a: [][]float64{ {2, 0, 0}, {3, 6, 0}, {4, 7, 10}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {8, 12, 2}, {9, 12, 9}, {12, 1, -1}, {1, 9, 5}, }, alpha: 2, beta: 3, ans: [][]float64{ {32, 72, 86}, {47, 108, 167}, {68, 111, 197}, {11, 39, 35}, }, }, { side: blas.Right, ul: blas.Lower, m: 3, n: 4, a: [][]float64{ {2, 0, 0, 0}, {3, 6, 0, 0}, {4, 7, 10, 0}, {3, 4, 5, 6}, }, b: [][]float64{ {2, 3, 4, 2}, {5, 6, 7, 1}, {8, 9, 10, 1}, }, c: [][]float64{ {8, 12, 2, 1}, {9, 12, 9, 9}, {12, 1, -1, 5}, }, alpha: 2, beta: 3, ans: [][]float64{ {94, 156, 164, 103}, {145, 244, 301, 187}, {208, 307, 397, 247}, }, }, { side: blas.Right, ul: blas.Lower, m: 4, n: 3, a: [][]float64{ {2, 0, 0}, {3, 6, 0}, {4, 7, 10}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {8, 12, 2}, {9, 12, 9}, {12, 1, -1}, {1, 9, 5}, }, alpha: 2, beta: 3, ans: [][]float64{ {82, 140, 144}, {139, 236, 291}, {202, 299, 387}, {25, 65, 65}, }, }, { side: blas.Left, ul: blas.Upper, m: 3, n: 4, a: [][]float64{ {2, 3, 4}, {0, 6, 7}, {0, 0, 10}, }, b: [][]float64{ {2, 3, 4, 8}, {5, 6, 7, 15}, {8, 9, 10, 20}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {102, 120, 138, 282}, {184, 216, 248, 508}, {246, 288, 330, 674}, }, }, { side: blas.Left, ul: blas.Upper, m: 4, n: 3, a: [][]float64{ {2, 3, 4, 8}, {0, 6, 7, 9}, {0, 0, 10, 10}, {0, 0, 0, 11}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {134, 136, 154}, {220, 234, 266}, {286, 308, 350}, {326, 358, 412}, }, }, { side: blas.Left, ul: blas.Lower, m: 3, n: 4, a: [][]float64{ {2, 0, 0}, {3, 6, 0}, {4, 7, 10}, }, b: [][]float64{ {2, 3, 4, 8}, {5, 6, 7, 15}, {8, 9, 10, 20}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {102, 120, 138, 282}, {184, 216, 248, 508}, {246, 288, 330, 674}, }, }, { side: blas.Left, ul: blas.Lower, m: 4, n: 3, a: [][]float64{ {2, 0, 0, 0}, {3, 6, 0, 0}, {4, 7, 10, 0}, {8, 9, 10, 11}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {134, 136, 154}, {220, 234, 266}, {286, 308, 350}, {326, 358, 412}, }, }, { side: blas.Right, ul: blas.Upper, m: 3, n: 4, a: [][]float64{ {2, 0, 0, 0}, {3, 6, 0, 0}, {4, 7, 10, 0}, {3, 4, 5, 6}, }, b: [][]float64{ {2, 3, 4, 9}, {5, 6, 7, -3}, {8, 9, 10, -2}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {8, 36, 80, 108}, {20, 72, 140, -36}, {32, 108, 200, -24}, }, }, { side: blas.Right, ul: blas.Upper, m: 4, n: 3, a: [][]float64{ {2, 0, 0}, {3, 6, 0}, {4, 7, 10}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {8, 36, 80, 20}, {72, 140, 32, 108}, {200, 8, 12, 20}, }, }, { side: blas.Right, ul: blas.Lower, m: 3, n: 4, a: [][]float64{ {2, 0, 0, 0}, {3, 6, 0, 0}, {4, 7, 10, 0}, {3, 4, 5, 6}, }, b: [][]float64{ {2, 3, 4, 2}, {5, 6, 7, 1}, {8, 9, 10, 1}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {70, 120, 158, 100}, {118, 208, 274, 160}, {172, 304, 400, 232}, }, }, { side: blas.Right, ul: blas.Lower, m: 4, n: 3, a: [][]float64{ {2, 0, 0}, {3, 6, 0}, {4, 7, 10}, }, b: [][]float64{ {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {2, 1, 1}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, {math.NaN(), math.NaN(), math.NaN()}, }, alpha: 2, ans: [][]float64{ {58, 104, 138}, {112, 200, 264}, {166, 296, 390}, {22, 38, 50}, }, }, } { aFlat := flatten(test.a) bFlat := flatten(test.b) cFlat := flatten(test.c) ansFlat := flatten(test.ans) blasser.Dsymm(test.side, test.ul, test.m, test.n, test.alpha, aFlat, len(test.a[0]), bFlat, test.n, test.beta, cFlat, test.n) if !floats.EqualApprox(cFlat, ansFlat, 1e-14) { t.Errorf("Case %v: Want %v, got %v.", i, ansFlat, cFlat) } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dsymv.go000066400000000000000000000032431450372207100220730ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dsymver interface { Dsymv(ul blas.Uplo, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) } func DsymvTest(t *testing.T, blasser Dsymver) { for i, test := range []struct { ul blas.Uplo n int a [][]float64 x []float64 y []float64 alpha float64 beta float64 ans []float64 }{ { ul: blas.Upper, n: 3, a: [][]float64{ {5, 6, 7}, {0, 8, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, y: []float64{6, 7, 8}, alpha: 2.1, beta: -3, ans: []float64{137.4, 189, 240.6}, }, { ul: blas.Lower, n: 3, a: [][]float64{ {5, 0, 0}, {6, 8, 0}, {7, 10, 13}, }, x: []float64{3, 4, 5}, y: []float64{6, 7, 8}, alpha: 2.1, beta: -3, ans: []float64{137.4, 189, 240.6}, }, } { incTest := func(incX, incY, extra int) { x := makeIncremented(test.x, incX, extra) y := makeIncremented(test.y, incY, extra) aFlat := flatten(test.a) ans := makeIncremented(test.ans, incY, extra) blasser.Dsymv(test.ul, test.n, test.alpha, aFlat, test.n, x, incX, test.beta, y, incY) if !floats.EqualApprox(ans, y, 1e-14) { t.Errorf("Case %v, incX=%v, incY=%v: Want %v, got %v.", i, incX, incY, ans, y) } } incTest(1, 1, 0) incTest(2, 3, 0) incTest(3, 2, 0) incTest(-3, 2, 0) incTest(-2, 4, 0) incTest(2, -1, 0) incTest(-3, -4, 3) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dsyr.go000066400000000000000000000027011450372207100217100ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dsyrer interface { Dsyr(ul blas.Uplo, n int, alpha float64, x []float64, incX int, a []float64, lda int) } func DsyrTest(t *testing.T, blasser Dsyrer) { for i, test := range []struct { ul blas.Uplo n int a [][]float64 x []float64 alpha float64 ans [][]float64 }{ { ul: blas.Upper, n: 4, a: [][]float64{ {10, 2, 0, 1}, {0, 1, 2, 3}, {0, 0, 9, 15}, {0, 0, 0, -6}, }, x: []float64{1, 2, 0, 5}, alpha: 8, ans: [][]float64{ {18, 18, 0, 41}, {0, 33, 2, 83}, {0, 0, 9, 15}, {0, 0, 0, 194}, }, }, { ul: blas.Lower, n: 3, a: [][]float64{ {10, 2, 0}, {4, 1, 2}, {2, 7, 9}, }, x: []float64{3, 0, 5}, alpha: 8, ans: [][]float64{ {82, 2, 0}, {4, 1, 2}, {122, 7, 209}, }, }, } { incTest := func(incX, extra int) { xnew := makeIncremented(test.x, incX, extra) aFlat := flatten(test.a) ans := flatten(test.ans) lda := test.n blasser.Dsyr(test.ul, test.n, test.alpha, xnew, incX, aFlat, lda) if !dSliceTolEqual(aFlat, ans) { t.Errorf("Case %v, idx %v: Want %v, got %v.", i, incX, ans, aFlat) } } incTest(1, 3) incTest(1, 0) incTest(3, 2) incTest(-2, 2) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dsyr2.go000066400000000000000000000032321450372207100217720ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dsyr2er interface { Dsyr2(ul blas.Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int) } func Dsyr2Test(t *testing.T, blasser Dsyr2er) { for i, test := range []struct { n int a [][]float64 ul blas.Uplo x []float64 y []float64 alpha float64 ans [][]float64 }{ { n: 3, a: [][]float64{ {7, 2, 4}, {0, 3, 5}, {0, 0, 6}, }, x: []float64{2, 3, 4}, y: []float64{5, 6, 7}, alpha: 2, ul: blas.Upper, ans: [][]float64{ {47, 56, 72}, {0, 75, 95}, {0, 0, 118}, }, }, { n: 3, a: [][]float64{ {7, 0, 0}, {2, 3, 0}, {4, 5, 6}, }, x: []float64{2, 3, 4}, y: []float64{5, 6, 7}, alpha: 2, ul: blas.Lower, ans: [][]float64{ {47, 0, 0}, {56, 75, 0}, {72, 95, 118}, }, }, } { incTest := func(incX, incY, extra int) { aFlat := flatten(test.a) x := makeIncremented(test.x, incX, extra) y := makeIncremented(test.y, incY, extra) blasser.Dsyr2(test.ul, test.n, test.alpha, x, incX, y, incY, aFlat, test.n) ansFlat := flatten(test.ans) if !floats.EqualApprox(aFlat, ansFlat, 1e-14) { t.Errorf("Case %v, incX = %v, incY = %v. Want %v, got %v.", i, incX, incY, ansFlat, aFlat) } } incTest(1, 1, 0) incTest(-2, 1, 0) incTest(-2, 3, 0) incTest(2, -3, 0) incTest(3, -2, 0) incTest(-3, -4, 0) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dsyr2k.go000066400000000000000000000141631450372207100221520ustar00rootroot00000000000000// 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 testblas import ( "math" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dsyr2ker interface { 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) } func Dsyr2kTest(t *testing.T, blasser Dsyr2ker) { for i, test := range []struct { ul blas.Uplo tA blas.Transpose n int k int alpha float64 a [][]float64 b [][]float64 c [][]float64 beta float64 ans [][]float64 }{ { ul: blas.Upper, tA: blas.NoTrans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {1, 2, 3}, {0, 5, 6}, {0, 0, 9}, }, beta: 2, ans: [][]float64{ {2, 4, 6}, {0, 10, 12}, {0, 0, 18}, }, }, { ul: blas.Lower, tA: blas.NoTrans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {1, 0, 0}, {2, 3, 0}, {4, 5, 6}, }, beta: 2, ans: [][]float64{ {2, 0, 0}, {4, 6, 0}, {8, 10, 12}, }, }, { ul: blas.Upper, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, beta: 2, ans: [][]float64{ {140, 250, 360}, {0, 410, 568}, {0, 0, 774}, }, }, { ul: blas.Lower, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, beta: 2, ans: [][]float64{ {140, 0, 0}, {250, 410, 0}, {360, 568, 774}, }, }, { ul: blas.Upper, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, b: [][]float64{ {7, 9, 11}, {8, 10, 12}, }, c: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, beta: 2, ans: [][]float64{ {140, 250, 360}, {0, 410, 568}, {0, 0, 774}, }, }, { ul: blas.Lower, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, b: [][]float64{ {7, 9, 11}, {8, 10, 12}, }, c: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, beta: 2, ans: [][]float64{ {140, 0, 0}, {250, 410, 0}, {360, 568, 774}, }, }, { ul: blas.Upper, tA: blas.NoTrans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN()}, {math.Inf(-1), math.NaN(), math.NaN()}, {math.Inf(-1), math.Inf(-1), math.NaN()}, }, ans: [][]float64{ {0, 0, 0}, {math.Inf(-1), 0, 0}, {math.Inf(-1), math.Inf(-1), 0}, }, }, { ul: blas.Lower, tA: blas.NoTrans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {math.NaN(), math.Inf(-1), math.Inf(-1)}, {math.NaN(), math.NaN(), math.Inf(-1)}, {math.NaN(), math.NaN(), math.NaN()}, }, ans: [][]float64{ {0, math.Inf(-1), math.Inf(-1)}, {0, 0, math.Inf(-1)}, {0, 0, 0}, }, }, { ul: blas.Upper, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN()}, {math.Inf(-1), math.NaN(), math.NaN()}, {math.Inf(-1), math.Inf(-1), math.NaN()}, }, ans: [][]float64{ {138, 246, 354}, {math.Inf(-1), 402, 558}, {math.Inf(-1), math.Inf(-1), 762}, }, }, { ul: blas.Lower, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, b: [][]float64{ {7, 8}, {9, 10}, {11, 12}, }, c: [][]float64{ {math.NaN(), math.Inf(-1), math.Inf(-1)}, {math.NaN(), math.NaN(), math.Inf(-1)}, {math.NaN(), math.NaN(), math.NaN()}, }, ans: [][]float64{ {138, math.Inf(-1), math.Inf(-1)}, {246, 402, math.Inf(-1)}, {354, 558, 762}, }, }, { ul: blas.Upper, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, b: [][]float64{ {7, 9, 11}, {8, 10, 12}, }, c: [][]float64{ {math.NaN(), math.NaN(), math.NaN()}, {math.Inf(-1), math.NaN(), math.NaN()}, {math.Inf(-1), math.Inf(-1), math.NaN()}, }, ans: [][]float64{ {138, 246, 354}, {math.Inf(-1), 402, 558}, {math.Inf(-1), math.Inf(-1), 762}, }, }, { ul: blas.Lower, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, b: [][]float64{ {7, 9, 11}, {8, 10, 12}, }, c: [][]float64{ {math.NaN(), math.Inf(-1), math.Inf(-1)}, {math.NaN(), math.NaN(), math.Inf(-1)}, {math.NaN(), math.NaN(), math.NaN()}, }, ans: [][]float64{ {138, math.Inf(-1), math.Inf(-1)}, {246, 402, math.Inf(-1)}, {354, 558, 762}, }, }, } { aFlat := flatten(test.a) bFlat := flatten(test.b) cFlat := flatten(test.c) ansFlat := flatten(test.ans) blasser.Dsyr2k(test.ul, test.tA, test.n, test.k, test.alpha, aFlat, len(test.a[0]), bFlat, len(test.b[0]), test.beta, cFlat, len(test.c[0])) if !floats.EqualApprox(ansFlat, cFlat, 1e-14) { t.Errorf("Case %v. Want %v, got %v.", i, ansFlat, cFlat) } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dsyrk.go000066400000000000000000000111471450372207100220670ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dsyker interface { Dsyrk(ul blas.Uplo, tA blas.Transpose, n, k int, alpha float64, a []float64, lda int, beta float64, c []float64, ldc int) } func DsyrkTest(t *testing.T, blasser Dsyker) { for i, test := range []struct { ul blas.Uplo tA blas.Transpose n int k int alpha float64 a [][]float64 c [][]float64 beta float64 ans [][]float64 }{ { ul: blas.Upper, tA: blas.NoTrans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, c: [][]float64{ {1, 2, 3}, {0, 5, 6}, {0, 0, 9}, }, beta: 2, ans: [][]float64{ {2, 4, 6}, {0, 10, 12}, {0, 0, 18}, }, }, { ul: blas.Lower, tA: blas.NoTrans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, c: [][]float64{ {1, 0, 0}, {2, 3, 0}, {4, 5, 6}, }, beta: 2, ans: [][]float64{ {2, 0, 0}, {4, 6, 0}, {8, 10, 12}, }, }, { ul: blas.Upper, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, c: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, beta: 2, ans: [][]float64{ {17, 37, 57}, {0, 83, 127}, {0, 0, 195}, }, }, { ul: blas.Upper, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, c: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, beta: 0, ans: [][]float64{ {15, 33, 51}, {0, 75, 117}, {0, 0, 183}, }, }, { ul: blas.Lower, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, c: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, beta: 2, ans: [][]float64{ {17, 0, 0}, {37, 83, 0}, {57, 127, 195}, }, }, { ul: blas.Lower, tA: blas.NoTrans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 2}, {3, 4}, {5, 6}, }, c: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, beta: 0, ans: [][]float64{ {15, 0, 0}, {33, 75, 0}, {51, 117, 183}, }, }, { ul: blas.Upper, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, c: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, beta: 2, ans: [][]float64{ {17, 37, 57}, {0, 83, 127}, {0, 0, 195}, }, }, { ul: blas.Lower, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, c: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, beta: 2, ans: [][]float64{ {17, 0, 0}, {37, 83, 0}, {57, 127, 195}, }, }, { ul: blas.Upper, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, c: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, beta: 0, ans: [][]float64{ {15, 33, 51}, {0, 75, 117}, {0, 0, 183}, }, }, { ul: blas.Lower, tA: blas.Trans, n: 3, k: 2, alpha: 3, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, c: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, beta: 0, ans: [][]float64{ {15, 0, 0}, {33, 75, 0}, {51, 117, 183}, }, }, { ul: blas.Lower, tA: blas.Trans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, c: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, beta: 0, ans: [][]float64{ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, }, }, { ul: blas.Upper, tA: blas.Trans, n: 3, k: 2, alpha: 0, a: [][]float64{ {1, 3, 5}, {2, 4, 6}, }, c: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, beta: 0, ans: [][]float64{ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, }, }, } { aFlat := flatten(test.a) cFlat := flatten(test.c) ansFlat := flatten(test.ans) blasser.Dsyrk(test.ul, test.tA, test.n, test.k, test.alpha, aFlat, len(test.a[0]), test.beta, cFlat, len(test.c[0])) if !floats.EqualApprox(ansFlat, cFlat, 1e-14) { t.Errorf("Case %v. Want %v, got %v.", i, ansFlat, cFlat) } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtbmv.go000066400000000000000000000047751450372207100220600ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dtbmver interface { Dtbmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float64, lda int, x []float64, incX int) } func DtbmvTest(t *testing.T, blasser Dtbmver) { for i, test := range []struct { ul blas.Uplo tA blas.Transpose d blas.Diag n int k int a [][]float64 x []float64 ans []float64 }{ { ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, n: 3, k: 1, a: [][]float64{ {1, 2, 0}, {0, 1, 4}, {0, 0, 1}, }, x: []float64{2, 3, 4}, ans: []float64{8, 19, 4}, }, { ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 1, a: [][]float64{ {1, 3, 0, 0, 0}, {0, 6, 7, 0, 0}, {0, 0, 2, 1, 0}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, 2, 3, 4, 5}, ans: []float64{7, 33, 10, 63, -5}, }, { ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 1, a: [][]float64{ {7, 0, 0, 0, 0}, {3, 6, 0, 0, 0}, {0, 7, 2, 0, 0}, {0, 0, 1, 12, 0}, {0, 0, 0, 3, -1}, }, x: []float64{1, 2, 3, 4, 5}, ans: []float64{7, 15, 20, 51, 7}, }, { ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {7, 3, 9, 0, 0}, {0, 6, 7, 10, 0}, {0, 0, 2, 1, 11}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, 2, 3, 4, 5}, ans: []float64{7, 15, 29, 71, 40}, }, { ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {7, 0, 0, 0, 0}, {3, 6, 0, 0, 0}, {9, 7, 2, 0, 0}, {0, 10, 1, 12, 0}, {0, 0, 11, 3, -1}, }, x: []float64{1, 2, 3, 4, 5}, ans: []float64{40, 73, 65, 63, -5}, }, } { extra := 0 var aFlat []float64 if test.ul == blas.Upper { aFlat = flattenBanded(test.a, test.k, 0) } else { aFlat = flattenBanded(test.a, 0, test.k) } incTest := func(incX, extra int) { xnew := makeIncremented(test.x, incX, extra) ans := makeIncremented(test.ans, incX, extra) lda := test.k + 1 blasser.Dtbmv(test.ul, test.tA, test.d, test.n, test.k, aFlat, lda, xnew, incX) if !dSliceTolEqual(ans, xnew) { t.Errorf("Case %v, Inc %v: Want %v, got %v", i, incX, ans, xnew) } } incTest(1, extra) incTest(3, extra) incTest(-2, extra) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtbsv.go000066400000000000000000000151331450372207100220540ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dtbsver interface { Dtbsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float64, lda int, x []float64, incX int) Dtrsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) } func DtbsvTest(t *testing.T, blasser Dtbsver) { for i, test := range []struct { ul blas.Uplo tA blas.Transpose d blas.Diag n, k int a [][]float64 x []float64 incX int ans []float64 }{ { ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 1, a: [][]float64{ {1, 3, 0, 0, 0}, {0, 6, 7, 0, 0}, {0, 0, 2, 1, 0}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, 2, 3, 4, 5}, incX: 1, ans: []float64{2.479166666666667, -0.493055555555556, 0.708333333333333, 1.583333333333333, -5.000000000000000}, }, { ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 3, 5, 0, 0}, {0, 6, 7, 5, 0}, {0, 0, 2, 1, 5}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, 2, 3, 4, 5}, incX: 1, ans: []float64{-15.854166666666664, -16.395833333333336, 13.208333333333334, 1.583333333333333, -5.000000000000000}, }, { ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 1, a: [][]float64{ {1, 3, 0, 0, 0}, {0, 6, 7, 0, 0}, {0, 0, 2, 1, 0}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, -101, 2, -201, 3, -301, 4, -401, 5, -501, -601, -701}, incX: 2, ans: []float64{2.479166666666667, -101, -0.493055555555556, -201, 0.708333333333333, -301, 1.583333333333333, -401, -5.000000000000000, -501, -601, -701}, }, { ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 3, 5, 0, 0}, {0, 6, 7, 5, 0}, {0, 0, 2, 1, 5}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, -101, 2, -201, 3, -301, 4, -401, 5, -501, -601, -701}, incX: 2, ans: []float64{-15.854166666666664, -101, -16.395833333333336, -201, 13.208333333333334, -301, 1.583333333333333, -401, -5.000000000000000, -501, -601, -701}, }, { ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 0, 0, 0, 0}, {3, 6, 0, 0, 0}, {5, 7, 2, 0, 0}, {0, 5, 1, 12, 0}, {0, 0, 5, 3, -1}, }, x: []float64{1, 2, 3, 4, 5}, incX: 1, ans: []float64{1, -0.166666666666667, -0.416666666666667, 0.437500000000000, -5.770833333333334}, }, { ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 0, 0, 0, 0}, {3, 6, 0, 0, 0}, {5, 7, 2, 0, 0}, {0, 5, 1, 12, 0}, {0, 0, 5, 3, -1}, }, x: []float64{1, -101, 2, -201, 3, -301, 4, -401, 5, -501, -601, -701}, incX: 2, ans: []float64{1, -101, -0.166666666666667, -201, -0.416666666666667, -301, 0.437500000000000, -401, -5.770833333333334, -501, -601, -701}, }, { ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 3, 5, 0, 0}, {0, 6, 7, 5, 0}, {0, 0, 2, 1, 5}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, 2, 3, 4, 5}, incX: 1, ans: []float64{1, -0.166666666666667, -0.416666666666667, 0.437500000000000, -5.770833333333334}, }, { ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 3, 5, 0, 0}, {0, 6, 7, 5, 0}, {0, 0, 2, 1, 5}, {0, 0, 0, 12, 3}, {0, 0, 0, 0, -1}, }, x: []float64{1, -101, 2, -201, 3, -301, 4, -401, 5, -501, -601, -701}, incX: 2, ans: []float64{1, -101, -0.166666666666667, -201, -0.416666666666667, -301, 0.437500000000000, -401, -5.770833333333334, -501, -601, -701}, }, { ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 0, 0, 0, 0}, {3, 6, 0, 0, 0}, {5, 7, 2, 0, 0}, {0, 5, 1, 12, 0}, {0, 0, 5, 3, -1}, }, x: []float64{1, 2, 3, 4, 5}, incX: 1, ans: []float64{-15.854166666666664, -16.395833333333336, 13.208333333333334, 1.583333333333333, -5.000000000000000}, }, { ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, n: 5, k: 2, a: [][]float64{ {1, 0, 0, 0, 0}, {3, 6, 0, 0, 0}, {5, 7, 2, 0, 0}, {0, 5, 1, 12, 0}, {0, 0, 5, 3, -1}, }, x: []float64{1, -101, 2, -201, 3, -301, 4, -401, 5, -501, -601, -701}, incX: 2, ans: []float64{-15.854166666666664, -101, -16.395833333333336, -201, 13.208333333333334, -301, 1.583333333333333, -401, -5.000000000000000, -501, -601, -701}, }, } { var aFlat []float64 if test.ul == blas.Upper { aFlat = flattenBanded(test.a, test.k, 0) } else { aFlat = flattenBanded(test.a, 0, test.k) } xCopy := sliceCopy(test.x) // TODO: Have tests where the banded matrix is constructed explicitly // to allow testing for lda =! k+1 blasser.Dtbsv(test.ul, test.tA, test.d, test.n, test.k, aFlat, test.k+1, xCopy, test.incX) if !dSliceTolEqual(test.ans, xCopy) { t.Errorf("Case %v: Want %v, got %v", i, test.ans, xCopy) } } /* // TODO: Uncomment when Dtrsv is fixed // Compare with dense for larger matrices for _, ul := range [...]blas.Uplo{blas.Upper, blas.Lower} { for _, tA := range [...]blas.Transpose{blas.NoTrans, blas.Trans} { for _, n := range [...]int{7, 8, 11} { for _, d := range [...]blas.Diag{blas.NonUnit, blas.Unit} { for _, k := range [...]int{0, 1, 3} { for _, incX := range [...]int{1, 3} { a := make([][]float64, n) for i := range a { a[i] = make([]float64, n) for j := range a[i] { a[i][j] = rand.Float64() } } x := make([]float64, n) for i := range x { x[i] = rand.Float64() } extra := 3 xinc := makeIncremented(x, incX, extra) bandX := sliceCopy(xinc) var aFlatBand []float64 if ul == blas.Upper { aFlatBand = flattenBanded(a, k, 0) } else { aFlatBand = flattenBanded(a, 0, k) } blasser.Dtbsv(ul, tA, d, n, k, aFlatBand, k+1, bandX, incX) aFlatDense := flatten(a) denseX := sliceCopy(xinc) blasser.Dtrsv(ul, tA, d, n, aFlatDense, n, denseX, incX) if !dSliceTolEqual(denseX, bandX) { t.Errorf("Case %v: dense banded mismatch") } } } } } } } */ } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtpmv.go000066400000000000000000000046621450372207100220710ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dtpmver interface { Dtpmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float64, x []float64, incX int) } func DtpmvTest(t *testing.T, blasser Dtpmver) { for i, test := range []struct { n int a [][]float64 x []float64 d blas.Diag ul blas.Uplo tA blas.Transpose ans []float64 }{ { n: 3, a: [][]float64{ {5, 6, 7}, {0, 9, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Upper, tA: blas.NoTrans, ans: []float64{74, 86, 65}, }, { n: 3, a: [][]float64{ {5, 6, 7}, {0, 9, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, d: blas.Unit, ul: blas.Upper, tA: blas.NoTrans, ans: []float64{62, 54, 5}, }, { n: 3, a: [][]float64{ {5, 0, 0}, {6, 9, 0}, {7, 10, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Lower, tA: blas.NoTrans, ans: []float64{15, 54, 126}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {6, 1, 0}, {7, 10, 1}, }, x: []float64{3, 4, 5}, d: blas.Unit, ul: blas.Lower, tA: blas.NoTrans, ans: []float64{3, 22, 66}, }, { n: 3, a: [][]float64{ {5, 6, 7}, {0, 9, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Upper, tA: blas.Trans, ans: []float64{15, 54, 126}, }, { n: 3, a: [][]float64{ {1, 6, 7}, {0, 1, 10}, {0, 0, 1}, }, x: []float64{3, 4, 5}, d: blas.Unit, ul: blas.Upper, tA: blas.Trans, ans: []float64{3, 22, 66}, }, { n: 3, a: [][]float64{ {5, 0, 0}, {6, 9, 0}, {7, 10, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Lower, tA: blas.Trans, ans: []float64{74, 86, 65}, }, } { incTest := func(incX, extra int) { aFlat := flattenTriangular(test.a, test.ul) x := makeIncremented(test.x, incX, extra) blasser.Dtpmv(test.ul, test.tA, test.d, test.n, aFlat, x, incX) ans := makeIncremented(test.ans, incX, extra) if !floats.EqualApprox(x, ans, 1e-14) { t.Errorf("Case %v, idx %v: Want %v, got %v.", i, incX, ans, x) } } incTest(1, 0) incTest(-3, 3) incTest(4, 3) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtpsv.go000066400000000000000000000053131450372207100220710ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dtpsver interface { Dtpsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, ap []float64, x []float64, incX int) } func DtpsvTest(t *testing.T, blasser Dtpsver) { for i, test := range []struct { n int a [][]float64 ul blas.Uplo tA blas.Transpose d blas.Diag x []float64 ans []float64 }{ { n: 3, a: [][]float64{ {1, 2, 3}, {0, 8, 15}, {0, 0, 8}, }, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{4.15625, -0.890625, 0.875}, }, { n: 3, a: [][]float64{ {1, 2, 3}, {0, 1, 15}, {0, 0, 1}, }, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{182, -99, 7}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 8, 0}, {3, 15, 8}, }, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{5, -0.5, -0.0625}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 8, 0}, {3, 15, 8}, }, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{5, -4, 52}, }, { n: 3, a: [][]float64{ {1, 2, 3}, {0, 8, 15}, {0, 0, 8}, }, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{5, -0.5, -0.0625}, }, { n: 3, a: [][]float64{ {1, 2, 3}, {0, 8, 15}, {0, 0, 8}, }, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{5, -4, 52}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 8, 0}, {3, 15, 8}, }, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{4.15625, -0.890625, 0.875}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 1, 0}, {3, 15, 1}, }, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{182, -99, 7}, }, } { incTest := func(incX, extra int) { aFlat := flattenTriangular(test.a, test.ul) x := makeIncremented(test.x, incX, extra) blasser.Dtpsv(test.ul, test.tA, test.d, test.n, aFlat, x, incX) ans := makeIncremented(test.ans, incX, extra) if !floats.EqualApprox(x, ans, 1e-14) { t.Errorf("Case %v, incX = %v: Want %v, got %v.", i, incX, ans, x) } } incTest(1, 0) incTest(-2, 0) incTest(3, 0) incTest(-3, 8) incTest(4, 2) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtrmm.go000066400000000000000000000320221450372207100220510ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dtrmmer interface { 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) } func DtrmmTest(t *testing.T, blasser Dtrmmer) { for i, test := range []struct { s blas.Side ul blas.Uplo tA blas.Transpose d blas.Diag m int n int alpha float64 a [][]float64 b [][]float64 ans [][]float64 }{ { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3, 4}, {0, 5, 6, 7}, {0, 0, 8, 9}, {0, 0, 0, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {320, 340, 360}, {588, 624, 660}, {598, 632, 666}, {380, 400, 420}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2}, {0, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {72, 78, 84}, {130, 140, 150}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3, 4}, {0, 5, 6, 7}, {0, 0, 8, 9}, {0, 0, 0, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {320, 340, 360}, {484, 512, 540}, {374, 394, 414}, {38, 40, 42}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2}, {0, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {72, 78, 84}, {26, 28, 30}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0, 0}, {2, 5, 0, 0}, {3, 6, 8, 0}, {4, 7, 9, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 22, 24}, {170, 184, 198}, {472, 506, 540}, {930, 990, 1050}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0}, {2, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 22, 24}, {170, 184, 198}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0, 0}, {2, 5, 0, 0}, {3, 6, 8, 0}, {4, 7, 9, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 22, 24}, {66, 72, 78}, {248, 268, 288}, {588, 630, 672}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0}, {2, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 22, 24}, {66, 72, 78}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3, 4}, {0, 5, 6, 7}, {0, 0, 8, 9}, {0, 0, 0, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 22, 24}, {170, 184, 198}, {472, 506, 540}, {930, 990, 1050}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2}, {0, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 22, 24}, {170, 184, 198}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3, 4}, {0, 5, 6, 7}, {0, 0, 8, 9}, {0, 0, 0, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 22, 24}, {66, 72, 78}, {248, 268, 288}, {588, 630, 672}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2}, {0, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 22, 24}, {66, 72, 78}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0, 0}, {2, 5, 0, 0}, {3, 6, 8, 0}, {4, 7, 9, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {320, 340, 360}, {588, 624, 660}, {598, 632, 666}, {380, 400, 420}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0}, {2, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {72, 78, 84}, {130, 140, 150}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0, 0}, {2, 5, 0, 0}, {3, 6, 8, 0}, {4, 7, 9, 10}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {320, 340, 360}, {484, 512, 540}, {374, 394, 414}, {38, 40, 42}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0}, {2, 5}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {72, 78, 84}, {26, 28, 30}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 128, 314}, {26, 164, 398}, {32, 200, 482}, {38, 236, 566}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 128, 314}, {26, 164, 398}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 62, 194}, {26, 80, 248}, {32, 98, 302}, {38, 116, 356}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 62, 194}, {26, 80, 248}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {136, 208, 144}, {172, 262, 180}, {208, 316, 216}, {244, 370, 252}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {136, 208, 144}, {172, 262, 180}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {136, 142, 24}, {172, 178, 30}, {208, 214, 36}, {244, 250, 42}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {136, 142, 24}, {172, 178, 30}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {136, 208, 144}, {172, 262, 180}, {208, 316, 216}, {244, 370, 252}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {136, 208, 144}, {172, 262, 180}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {136, 142, 24}, {172, 178, 30}, {208, 214, 36}, {244, 250, 42}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {136, 142, 24}, {172, 178, 30}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 128, 314}, {26, 164, 398}, {32, 200, 482}, {38, 236, 566}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 128, 314}, {26, 164, 398}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 4, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, ans: [][]float64{ {20, 62, 194}, {26, 80, 248}, {32, 98, 302}, {38, 116, 356}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 2, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {20, 62, 194}, {26, 80, 248}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 0, a: [][]float64{ {1, 0, 0}, {2, 4, 0}, {3, 5, 6}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, ans: [][]float64{ {0, 0, 0}, {0, 0, 0}, }, }, } { aFlat := flatten(test.a) bFlat := flatten(test.b) ansFlat := flatten(test.ans) blasser.Dtrmm(test.s, test.ul, test.tA, test.d, test.m, test.n, test.alpha, aFlat, len(test.a[0]), bFlat, len(test.b[0])) if !floats.EqualApprox(ansFlat, bFlat, 1e-14) { t.Errorf("Case %v. Want %v, got %v.", i, ansFlat, bFlat) } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtrmv.go000066400000000000000000000053411450372207100220660ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dtrmver interface { Dtrmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) } func DtrmvTest(t *testing.T, blasser Dtrmver) { for i, test := range []struct { n int a [][]float64 x []float64 d blas.Diag ul blas.Uplo tA blas.Transpose ans []float64 }{ { n: 1, a: [][]float64{{5}}, x: []float64{2}, d: blas.NonUnit, ul: blas.Upper, tA: blas.NoTrans, ans: []float64{10}, }, { n: 1, a: [][]float64{{5}}, x: []float64{2}, d: blas.Unit, ul: blas.Upper, tA: blas.NoTrans, ans: []float64{2}, }, { n: 3, a: [][]float64{ {5, 6, 7}, {0, 9, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Upper, tA: blas.NoTrans, ans: []float64{74, 86, 65}, }, { n: 3, a: [][]float64{ {5, 6, 7}, {0, 9, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, d: blas.Unit, ul: blas.Upper, tA: blas.NoTrans, ans: []float64{62, 54, 5}, }, { n: 3, a: [][]float64{ {5, 0, 0}, {6, 9, 0}, {7, 10, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Lower, tA: blas.NoTrans, ans: []float64{15, 54, 126}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {6, 1, 0}, {7, 10, 1}, }, x: []float64{3, 4, 5}, d: blas.Unit, ul: blas.Lower, tA: blas.NoTrans, ans: []float64{3, 22, 66}, }, { n: 3, a: [][]float64{ {5, 6, 7}, {0, 9, 10}, {0, 0, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Upper, tA: blas.Trans, ans: []float64{15, 54, 126}, }, { n: 3, a: [][]float64{ {1, 6, 7}, {0, 1, 10}, {0, 0, 1}, }, x: []float64{3, 4, 5}, d: blas.Unit, ul: blas.Upper, tA: blas.Trans, ans: []float64{3, 22, 66}, }, { n: 3, a: [][]float64{ {5, 0, 0}, {6, 9, 0}, {7, 10, 13}, }, x: []float64{3, 4, 5}, d: blas.NonUnit, ul: blas.Lower, tA: blas.Trans, ans: []float64{74, 86, 65}, }, } { incTest := func(incX, extra int) { aFlat := flatten(test.a) x := makeIncremented(test.x, incX, extra) blasser.Dtrmv(test.ul, test.tA, test.d, test.n, aFlat, test.n, x, incX) ans := makeIncremented(test.ans, incX, extra) if !floats.EqualApprox(x, ans, 1e-14) { t.Errorf("Case %v, idx %v: Want %v, got %v.", i, incX, ans, x) } } incTest(1, 3) incTest(-3, 3) incTest(4, 3) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtrmvbench.go000066400000000000000000000012221450372207100230600ustar00rootroot00000000000000// 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 testblas import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) func DtrmvBenchmark(b *testing.B, dtrmv Dtrmver, n, lda, incX int, ul blas.Uplo, tA blas.Transpose, d blas.Diag) { rnd := rand.New(rand.NewSource(0)) a := make([]float64, n*lda) for i := range a { a[i] = rnd.Float64() } x := make([]float64, n*incX) for i := range x { x[i] = rnd.Float64() } b.ResetTimer() for i := 0; i < b.N; i++ { dtrmv.Dtrmv(ul, tA, d, n, a, lda, x, incX) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtrsm.go000066400000000000000000000334171450372207100220700ustar00rootroot00000000000000// 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 testblas import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dtrsmer interface { 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) } func DtrsmTest(t *testing.T, impl Dtrsmer) { rnd := rand.New(rand.NewSource(1)) for i, test := range []struct { s blas.Side ul blas.Uplo tA blas.Transpose d blas.Diag m int n int alpha float64 a [][]float64 b [][]float64 want [][]float64 }{ { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 3, n: 2, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 5}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {1, 3.4}, {-0.5, -0.5}, {2, 3.2}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 3, n: 2, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 5}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {60, 96}, {-42, -66}, {10, 16}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 3, n: 4, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 5}, }, b: [][]float64{ {3, 6, 2, 9}, {4, 7, 1, 3}, {5, 8, 9, 10}, }, want: [][]float64{ {1, 3.4, 1.2, 13}, {-0.5, -0.5, -4, -3.5}, {2, 3.2, 3.6, 4}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 3, n: 4, alpha: 2, a: [][]float64{ {1, 2, 3}, {0, 4, 5}, {0, 0, 5}, }, b: [][]float64{ {3, 6, 2, 9}, {4, 7, 1, 3}, {5, 8, 9, 10}, }, want: [][]float64{ {60, 96, 126, 146}, {-42, -66, -88, -94}, {10, 16, 18, 20}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 3, n: 2, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 7}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {4.5, 9}, {-0.375, -1.5}, {-0.75, -12.0 / 7}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 3, n: 2, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 7}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {9, 18}, {-15, -33}, {60, 132}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 3, n: 4, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 7}, }, b: [][]float64{ {3, 6, 2, 9}, {4, 7, 1, 3}, {5, 8, 9, 10}, }, want: [][]float64{ {4.5, 9, 3, 13.5}, {-0.375, -1.5, -1.5, -63.0 / 8}, {-0.75, -12.0 / 7, 3, 39.0 / 28}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 3, n: 4, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 7}, }, b: [][]float64{ {3, 6, 2, 9}, {4, 7, 1, 3}, {5, 8, 9, 10}, }, want: [][]float64{ {9, 18, 6, 27}, {-15, -33, -15, -72}, {60, 132, 87, 327}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 3, n: 2, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 7}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {4.5, 9}, {-0.30, -1.2}, {-6.0 / 35, -24.0 / 35}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 3, n: 2, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 7}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {9, 18}, {-15, -33}, {69, 150}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 3, n: 4, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 7}, }, b: [][]float64{ {3, 6, 6, 7}, {4, 7, 8, 9}, {5, 8, 10, 11}, }, want: [][]float64{ {4.5, 9, 9, 10.5}, {-0.3, -1.2, -0.6, -0.9}, {-6.0 / 35, -24.0 / 35, -12.0 / 35, -18.0 / 35}, }, }, { s: blas.Left, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 3, n: 4, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 7}, }, b: [][]float64{ {3, 6, 6, 7}, {4, 7, 8, 9}, {5, 8, 10, 11}, }, want: [][]float64{ {9, 18, 18, 21}, {-15, -33, -30, -36}, {69, 150, 138, 165}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 3, n: 2, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 8}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {-0.46875, 0.375}, {0.1875, 0.75}, {1.875, 3}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 3, n: 2, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 8}, }, b: [][]float64{ {3, 6}, {4, 7}, {5, 8}, }, want: [][]float64{ {168, 267}, {-78, -123}, {15, 24}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 3, n: 4, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 8}, }, b: [][]float64{ {3, 6, 2, 3}, {4, 7, 4, 5}, {5, 8, 6, 7}, }, want: [][]float64{ {-0.46875, 0.375, -2.0625, -1.78125}, {0.1875, 0.75, -0.375, -0.1875}, {1.875, 3, 2.25, 2.625}, }, }, { s: blas.Left, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 3, n: 4, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 4, 0}, {5, 6, 8}, }, b: [][]float64{ {3, 6, 2, 3}, {4, 7, 4, 5}, {5, 8, 6, 7}, }, want: [][]float64{ {168, 267, 204, 237}, {-78, -123, -96, -111}, {15, 24, 18, 21}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 7}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {15, -2.4, -48.0 / 35}, {19.5, -3.3, -66.0 / 35}, {24, -4.2, -2.4}, {28.5, -5.1, -102.0 / 35}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {30, -57, 258}, {39, -75, 339}, {48, -93, 420}, {57, -111, 501}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 7}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {15, -2.4, -48.0 / 35}, {19.5, -3.3, -66.0 / 35}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {30, -57, 258}, {39, -75, 339}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {4.2, 1.2, 4.5}, {5.775, 1.65, 5.625}, {7.35, 2.1, 6.75}, {8.925, 2.55, 7.875}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {435, -183, 36}, {543, -228, 45}, {651, -273, 54}, {759, -318, 63}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {4.2, 1.2, 4.5}, {5.775, 1.65, 5.625}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {435, -183, 36}, {543, -228, 45}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {4.2, 1.2, 4.5}, {5.775, 1.65, 5.625}, {7.35, 2.1, 6.75}, {8.925, 2.55, 7.875}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {435, -183, 36}, {543, -228, 45}, {651, -273, 54}, {759, -318, 63}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {4.2, 1.2, 4.5}, {5.775, 1.65, 5.625}, }, }, { s: blas.Right, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 3, 4}, {0, 5, 6}, {0, 0, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {435, -183, 36}, {543, -228, 45}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {15, -2.4, -1.2}, {19.5, -3.3, -1.65}, {24, -4.2, -2.1}, {28.5, -5.1, -2.55}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 4, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, {16, 17, 18}, {19, 20, 21}, }, want: [][]float64{ {30, -57, 258}, {39, -75, 339}, {48, -93, 420}, {57, -111, 501}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {15, -2.4, -1.2}, {19.5, -3.3, -1.65}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 3, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {30, -57, 258}, {39, -75, 339}, }, }, { s: blas.Right, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, m: 2, n: 3, alpha: 0, a: [][]float64{ {2, 0, 0}, {3, 5, 0}, {4, 6, 8}, }, b: [][]float64{ {10, 11, 12}, {13, 14, 15}, }, want: [][]float64{ {0, 0, 0}, {0, 0, 0}, }, }, } { m := test.m n := test.n na := m if test.s == blas.Right { na = n } for _, lda := range []int{na, na + 3} { for _, ldb := range []int{n, n + 5} { a := make([]float64, na*lda) for i := range a { a[i] = rnd.NormFloat64() } for i := 0; i < na; i++ { for j := 0; j < na; j++ { a[i*lda+j] = test.a[i][j] } } b := make([]float64, m*ldb) for i := range b { b[i] = rnd.NormFloat64() } for i := 0; i < m; i++ { for j := 0; j < n; j++ { b[i*ldb+j] = test.b[i][j] } } impl.Dtrsm(test.s, test.ul, test.tA, test.d, test.m, test.n, test.alpha, a, lda, b, ldb) want := make([]float64, len(b)) copy(want, b) for i := 0; i < m; i++ { for j := 0; j < n; j++ { want[i*ldb+j] = test.want[i][j] } } if !floats.EqualApprox(want, b, 1e-13) { t.Errorf("Case %v: Want %v, got %v.", i, want, b) } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtrsv.go000066400000000000000000000053101450372207100220700ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dtrsver interface { Dtrsv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) } func DtrsvTest(t *testing.T, blasser Dtrsver) { for i, test := range []struct { n int a [][]float64 ul blas.Uplo tA blas.Transpose d blas.Diag x []float64 ans []float64 }{ { n: 3, a: [][]float64{ {1, 2, 3}, {0, 8, 15}, {0, 0, 8}, }, ul: blas.Upper, tA: blas.NoTrans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{4.15625, -0.890625, 0.875}, }, { n: 3, a: [][]float64{ {1, 2, 3}, {0, 1, 15}, {0, 0, 1}, }, ul: blas.Upper, tA: blas.NoTrans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{182, -99, 7}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 8, 0}, {3, 15, 8}, }, ul: blas.Lower, tA: blas.NoTrans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{5, -0.5, -0.0625}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 8, 0}, {3, 15, 8}, }, ul: blas.Lower, tA: blas.NoTrans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{5, -4, 52}, }, { n: 3, a: [][]float64{ {1, 2, 3}, {0, 8, 15}, {0, 0, 8}, }, ul: blas.Upper, tA: blas.Trans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{5, -0.5, -0.0625}, }, { n: 3, a: [][]float64{ {1, 2, 3}, {0, 8, 15}, {0, 0, 8}, }, ul: blas.Upper, tA: blas.Trans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{5, -4, 52}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 8, 0}, {3, 15, 8}, }, ul: blas.Lower, tA: blas.Trans, d: blas.NonUnit, x: []float64{5, 6, 7}, ans: []float64{4.15625, -0.890625, 0.875}, }, { n: 3, a: [][]float64{ {1, 0, 0}, {2, 1, 0}, {3, 15, 1}, }, ul: blas.Lower, tA: blas.Trans, d: blas.Unit, x: []float64{5, 6, 7}, ans: []float64{182, -99, 7}, }, } { incTest := func(incX, extra int) { aFlat := flatten(test.a) x := makeIncremented(test.x, incX, extra) blasser.Dtrsv(test.ul, test.tA, test.d, test.n, aFlat, test.n, x, incX) ans := makeIncremented(test.ans, incX, extra) if !floats.EqualApprox(x, ans, 1e-14) { t.Errorf("Case %v, incX = %v: Want %v, got %v.", i, incX, ans, x) } } incTest(1, 0) incTest(-2, 0) incTest(3, 0) incTest(-3, 8) incTest(4, 2) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dtxmv.go000066400000000000000000000077621450372207100221050ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Dtxmver interface { Dtrmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, lda int, x []float64, incX int) Dtbmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n, k int, a []float64, lda int, x []float64, incX int) Dtpmv(ul blas.Uplo, tA blas.Transpose, d blas.Diag, n int, a []float64, x []float64, incX int) } type vec struct { data []float64 inc int } var cases = []struct { n, k int ul blas.Uplo d blas.Diag ldab int tr, tb, tp []float64 ins []vec solNoTrans []float64 solTrans []float64 }{ { n: 3, k: 1, ul: blas.Upper, d: blas.NonUnit, tr: []float64{1, 2, 0, 0, 3, 4, 0, 0, 5}, tb: []float64{1, 2, 3, 4, 5, 0}, ldab: 2, tp: []float64{1, 2, 0, 3, 4, 5}, ins: []vec{ {[]float64{2, 3, 4}, 1}, {[]float64{2, 1, 3, 1, 4}, 2}, {[]float64{4, 1, 3, 1, 2}, -2}, }, solNoTrans: []float64{8, 25, 20}, solTrans: []float64{2, 13, 32}, }, { n: 3, k: 1, ul: blas.Upper, d: blas.Unit, tr: []float64{1, 2, 0, 0, 3, 4, 0, 0, 5}, tb: []float64{1, 2, 3, 4, 5, 0}, ldab: 2, tp: []float64{1, 2, 0, 3, 4, 5}, ins: []vec{ {[]float64{2, 3, 4}, 1}, {[]float64{2, 1, 3, 1, 4}, 2}, {[]float64{4, 1, 3, 1, 2}, -2}, }, solNoTrans: []float64{8, 19, 4}, solTrans: []float64{2, 7, 16}, }, { n: 3, k: 1, ul: blas.Lower, d: blas.NonUnit, tr: []float64{1, 0, 0, 2, 3, 0, 0, 4, 5}, tb: []float64{0, 1, 2, 3, 4, 5}, ldab: 2, tp: []float64{1, 2, 3, 0, 4, 5}, ins: []vec{ {[]float64{2, 3, 4}, 1}, {[]float64{2, 1, 3, 1, 4}, 2}, {[]float64{4, 1, 3, 1, 2}, -2}, }, solNoTrans: []float64{2, 13, 32}, solTrans: []float64{8, 25, 20}, }, { n: 3, k: 1, ul: blas.Lower, d: blas.Unit, tr: []float64{1, 0, 0, 2, 3, 0, 0, 4, 5}, tb: []float64{0, 1, 2, 3, 4, 5}, ldab: 2, tp: []float64{1, 2, 3, 0, 4, 5}, ins: []vec{ {[]float64{2, 3, 4}, 1}, {[]float64{2, 1, 3, 1, 4}, 2}, {[]float64{4, 1, 3, 1, 2}, -2}, }, solNoTrans: []float64{2, 7, 16}, solTrans: []float64{8, 19, 4}, }, } func DtxmvTest(t *testing.T, blasser Dtxmver) { for nc, c := range cases { for nx, x := range c.ins { in := make([]float64, len(x.data)) copy(in, x.data) blasser.Dtrmv(c.ul, blas.NoTrans, c.d, c.n, c.tr, c.n, in, x.inc) if !dStridedSliceTolEqual(c.n, in, x.inc, c.solNoTrans, 1) { t.Error("Wrong Dtrmv result for: NoTrans in Case:", nc, "input:", nx) } in = make([]float64, len(x.data)) copy(in, x.data) blasser.Dtrmv(c.ul, blas.Trans, c.d, c.n, c.tr, c.n, in, x.inc) if !dStridedSliceTolEqual(c.n, in, x.inc, c.solTrans, 1) { t.Error("Wrong Dtrmv result for: Trans in Case:", nc, "input:", nx) } in = make([]float64, len(x.data)) copy(in, x.data) blasser.Dtbmv(c.ul, blas.NoTrans, c.d, c.n, c.k, c.tb, c.ldab, in, x.inc) if !dStridedSliceTolEqual(c.n, in, x.inc, c.solNoTrans, 1) { t.Error("Wrong Dtbmv result for: NoTrans in Case:", nc, "input:", nx) } in = make([]float64, len(x.data)) copy(in, x.data) blasser.Dtbmv(c.ul, blas.Trans, c.d, c.n, c.k, c.tb, c.ldab, in, x.inc) if !dStridedSliceTolEqual(c.n, in, x.inc, c.solTrans, 1) { t.Error("Wrong Dtbmv result for: Trans in Case:", nc, "input:", nx) } in = make([]float64, len(x.data)) copy(in, x.data) blasser.Dtpmv(c.ul, blas.NoTrans, c.d, c.n, c.tp, in, x.inc) if !dStridedSliceTolEqual(c.n, in, x.inc, c.solNoTrans, 1) { t.Error("Wrong Dtpmv result for: NoTrans in Case:", nc, "input:", nx) } in = make([]float64, len(x.data)) copy(in, x.data) blasser.Dtpmv(c.ul, blas.Trans, c.d, c.n, c.tp, in, x.inc) if !dStridedSliceTolEqual(c.n, in, x.inc, c.solTrans, 1) { t.Error("Wrong Dtpmv result for: Trans in Case:", nc, "input:", nx) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dzasum.go000066400000000000000000000024421450372207100222340ustar00rootroot00000000000000// 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 testblas import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) type Dzasumer interface { Dzasum(n int, x []complex128, incX int) float64 } func DzasumTest(t *testing.T, impl Dzasumer) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 50, 100} { for _, incX := range []int{-5, 1, 2, 10} { aincX := abs(incX) var x []complex128 if n > 0 { x = make([]complex128, (n-1)*aincX+1) } for i := range x { x[i] = znan } for i := 0; i < n; i++ { re := float64(2*i + 1) if rnd.Intn(2) == 0 { re *= -1 } im := float64(2 * (i + 1)) if rnd.Intn(2) == 0 { im *= -1 } x[i*aincX] = complex(re, im) } want := float64(n * (2*n + 1)) got := impl.Dzasum(n, x, incX) if incX < 0 { if got != 0 { t.Errorf("Case n=%v,incX=%v: non-zero result when incX < 0. got %v", n, incX, got) } continue } if !scalar.EqualWithinAbsOrRel(got, want, tol, tol) { t.Errorf("Case n=%v,incX=%v: unexpected result. want %v, got %v", n, incX, want, got) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/dznrm2.go000066400000000000000000000063631450372207100221530ustar00rootroot00000000000000// 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 testblas import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) type Dznrm2er interface { Dznrm2(n int, x []complex128, incX int) float64 Dnrm2er } func Dznrm2Test(t *testing.T, impl Dznrm2er) { tol := 1e-12 for tc, test := range []struct { x []complex128 want float64 }{ { x: nil, want: 0, }, { x: []complex128{1 + 2i}, want: 2.2360679774998, }, { x: []complex128{1 + 2i, 3 + 4i}, want: 5.4772255750517, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i}, want: 9.5393920141695, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i}, want: 1.4282856857086e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i}, want: 1.9621416870349e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i}, want: 2.5495097567964e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i}, want: 3.1859064644148e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i}, want: 3.8678159211627e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i}, want: 4.5923850012820e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, want: 5.3572380943915e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i}, want: 6.1603571325046e+01, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, want: 70, }, } { n := len(test.x) for _, incX := range []int{-10, -1, 1, 2, 9, 17} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) got := impl.Dznrm2(n, x, incX) prefix := fmt.Sprintf("Case %v (n=%v,incX=%v):", tc, n, incX) if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x", prefix) } if incX < 0 { if got != 0 { t.Errorf("%v: non-zero result when incX < 0. got %v", prefix, got) } continue } if !scalar.EqualWithinAbsOrRel(test.want, got, tol, tol) { t.Errorf("%v: unexpected result. want %v, got %v", prefix, test.want, got) } } } tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{10, 50, 100} { for _, incX := range []int{1, 2, 10} { re := make([]float64, n) for i := range re { re[i] = rnd.NormFloat64() } im := make([]float64, n) for i := range im { im[i] = rnd.NormFloat64() } want := math.Hypot(impl.Dnrm2(n, re, 1), impl.Dnrm2(n, im, 1)) x := make([]complex128, (n-1)*incX+1) for i := range x { x[i] = znan } for i := range re { x[i*incX] = complex(re[i], im[i]) } got := impl.Dznrm2(n, x, incX) if !scalar.EqualWithinAbsOrRel(want, got, tol, tol) { t.Errorf("Case n=%v,incX=%v: unexpected result using Dnrm2. want %v, got %v", n, incX, want, got) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/izamax.go000066400000000000000000000020221450372207100222140ustar00rootroot00000000000000// 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 testblas import ( "testing" "golang.org/x/exp/rand" ) type Izamaxer interface { Izamax(n int, x []complex128, incX int) int } func IzamaxTest(t *testing.T, impl Izamaxer) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 50, 100} { for _, incX := range []int{-5, 1, 2, 10} { aincX := abs(incX) var x []complex128 if n > 0 { x = make([]complex128, (n-1)*aincX+1) } for i := range x { x[i] = znan } for i := 0; i < n; i++ { re := 2*rnd.Float64() - 1 im := 2*rnd.Float64() - 1 x[i*aincX] = complex(re, im) } want := -1 if incX > 0 && n > 0 { want = rnd.Intn(n) x[want*incX] = 10 + 10i } got := impl.Izamax(n, x, incX) if got != want { t.Errorf("Case n=%v,incX=%v: unexpected result. want %v, got %v", n, incX, want, got) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/level1double.go000066400000000000000000001432231450372207100233170ustar00rootroot00000000000000// 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 testblas import ( "fmt" "math" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) type DoubleOneVectorCase struct { Name string X []float64 Incx int N int Panic bool Dasum float64 Dnrm2 float64 Idamax int DscalCases []DScalCase } type DScalCase struct { Alpha float64 Ans []float64 Name string } var DoubleOneVectorCases = []DoubleOneVectorCase{ { Name: "AllPositive", X: []float64{6, 5, 4, 2, 6}, Incx: 1, N: 5, Panic: false, Dasum: 23, Dnrm2: 10.81665382639196787935766380241148783875388972153573863813135, Idamax: 0, DscalCases: []DScalCase{ { Alpha: 0, Ans: []float64{0, 0, 0, 0, 0}, }, { Alpha: 1, Ans: []float64{6, 5, 4, 2, 6}, }, { Alpha: -2, Ans: []float64{-12, -10, -8, -4, -12}, }, }, }, { Name: "LeadingZero", X: []float64{0, 1}, Incx: 1, N: 2, Panic: false, Dasum: 1, Dnrm2: 1, Idamax: 1, DscalCases: []DScalCase{ { Alpha: 0, Ans: []float64{0, 0}, }, { Alpha: 1, Ans: []float64{0, 1}, }, { Alpha: -2, Ans: []float64{0, -2}, }, }, }, { Name: "MaxInMiddle", X: []float64{6, 5, 9, 0, 6}, Incx: 1, N: 5, Panic: false, Dasum: 26, Dnrm2: 13.34166406412633371248943627250846646911846482744007727141318, Idamax: 2, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-12, -10, -18, 0, -12}, }, }, }, { Name: "MaxAtEnd", X: []float64{6, 5, -9, 0, 10}, Incx: 1, N: 5, Panic: false, Dasum: 30, Dnrm2: 15.55634918610404553681857596630667886426639062914642880494347, Idamax: 4, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-12, -10, 18, 0, -20}, }, }, }, { Name: "AllNegative", X: []float64{-6, -5, -4, -2, -6}, Incx: 1, N: 5, Panic: false, Dasum: 23, Dnrm2: 10.81665382639196787935766380241148783875388972153573863813135, Idamax: 0, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{12, 10, 8, 4, 12}, }, }, }, { Name: "AllMixed", X: []float64{-6, 5, 4, -2, -6}, Incx: 1, N: 5, Panic: false, Dasum: 23, Dnrm2: 10.81665382639196787935766380241148783875388972153573863813135, Idamax: 0, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{12, -10, -8, 4, 12}, }, }, }, { Name: "ZeroN", X: []float64{-6, 5, 4, -2, -6}, Incx: 1, N: 0, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6}, }, }, }, { Name: "OneN", X: []float64{-6, 5, 4, -2, -6}, Incx: 1, N: 1, Panic: false, Dasum: 6, Dnrm2: 6, Idamax: 0, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{12, 5, 4, -2, -6}, }, }, }, { Name: "PositiveExactInc", X: []float64{-6, 5, 10, -2, -5}, Incx: 2, N: 3, Panic: false, Dasum: 21, Dnrm2: 12.68857754044952038019377274608948979173952662752515253090272, Idamax: 1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{12, 5, -20, -2, 10}, }, }, }, { Name: "PositiveOffInc", X: []float64{-6, 5, 4, -2, -6, 8, 10, 11}, Incx: 3, N: 3, Panic: false, Dasum: 18, Dnrm2: 11.83215956619923208513465658312323409683100246158868064575943, Idamax: 2, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{12, 5, 4, 4, -6, 8, -20, 11}, }, }, }, { Name: "PositiveShortInc", X: []float64{-6, 5, 4, -2, -6, 8, 10, 11}, Incx: 3, N: 2, Panic: false, Dasum: 8, Dnrm2: 6.324555320336758663997787088865437067439110278650433653715009, Idamax: 0, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{12, 5, 4, 4, -6, 8, 10, 11}, }, }, }, { Name: "NegativeInc", X: []float64{-6, 5, 4, -2, -6}, Incx: -1, N: 5, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6}, }, }, }, { Name: "NegativeExactInc", X: []float64{-6, 5, 4, -2, -6}, Incx: -2, N: 3, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6}, }, }, }, { Name: "NegativeOffInc", X: []float64{-6, 5, 4, -2, -6, 8, 10, 11}, Incx: -3, N: 2, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6, 8, 10, 11}, }, }, }, { Name: "NegativeShortInc", X: []float64{-6, 5, 4, -2, -6, 8, 10, 11}, Incx: -3, N: 2, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6, 8, 10, 11}, }, }, }, { Name: "NegativeN", X: []float64{-6, 5, 4, -2, -6}, Incx: 2, N: -5, Panic: true, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6}, }, }, }, { Name: "ZeroInc", X: []float64{-6, 5, 4, -2, -6}, Incx: 0, N: 5, Panic: true, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6}, }, }, }, { Name: "OutOfBounds", X: []float64{-6, 5, 4, -2, -6}, Incx: 2, N: 6, Panic: true, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6}, }, }, }, { Name: "NegativeOutOfBounds", X: []float64{-6, 5, 4, -2, -6}, Incx: -2, N: 6, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-6, 5, 4, -2, -6}, }, }, }, { Name: "NaN", X: []float64{math.NaN(), 2.0}, Incx: 1, N: 2, Panic: false, Dasum: math.NaN(), Dnrm2: math.NaN(), Idamax: 0, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{math.NaN(), -4.0}, }, { Alpha: 0, Ans: []float64{0, 0}, }, }, }, { Name: "NaNInc", X: []float64{math.NaN(), math.NaN(), 2.0}, Incx: 2, N: 2, Panic: false, Dasum: math.NaN(), Dnrm2: math.NaN(), Idamax: 0, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{math.NaN(), math.NaN(), -4.0}, }, { Alpha: 0, Ans: []float64{0, math.NaN(), 0}, }, }, }, { Name: "Empty", X: []float64{}, Incx: 1, N: 0, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{}, }, { Alpha: 0, Ans: []float64{}, }, }, }, { Name: "EmptyZeroInc", X: []float64{}, Incx: 0, N: 0, Panic: true, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{}, }, { Alpha: 0, Ans: []float64{}, }, }, }, { Name: "EmptyReverse", X: []float64{}, Incx: -1, N: 0, Panic: false, Dasum: 0, Dnrm2: 0, Idamax: -1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{}, }, { Alpha: 0, Ans: []float64{}, }, }, }, { Name: "MultiInf", X: []float64{5, math.Inf(1), math.Inf(-1), 8, 9}, Incx: 1, N: 5, Panic: false, Dasum: math.Inf(1), Dnrm2: math.Inf(1), Idamax: 1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-10, math.Inf(-1), math.Inf(1), -16, -18}, }, { Alpha: 0, Ans: []float64{0, 0, 0, 0, 0}, }, }, }, { Name: "NaNInf", X: []float64{5, math.NaN(), math.Inf(-1), 8, 9}, Incx: 1, N: 5, Panic: false, Dasum: math.NaN(), Dnrm2: math.NaN(), Idamax: 2, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-10, math.NaN(), math.Inf(1), -16, -18}, }, { Alpha: 0, Ans: []float64{0, 0, 0, 0, 0}, }, }, }, { Name: "InfNaN", X: []float64{5, math.Inf(1), math.NaN(), 8, 9}, Incx: 1, N: 5, Panic: false, Dasum: math.NaN(), Dnrm2: math.NaN(), Idamax: 1, DscalCases: []DScalCase{ { Alpha: -2, Ans: []float64{-10, math.Inf(-1), math.NaN(), -16, -18}, }, { Alpha: 0, Ans: []float64{0, 0, 0, 0, 0}, }, }, }, } type DoubleTwoVectorCase struct { Name string X []float64 Y []float64 XTmp []float64 YTmp []float64 Incx int Incy int N int Panic bool // For Daxpy DaxpyCases []DaxpyCase DdotAns float64 DswapAns DTwoVecAnswer DcopyAns DTwoVecAnswer DrotCases []DrotCase DrotmCases []DrotmCase } type DaxpyCase struct { Alpha float64 Ans []float64 } type DrotCase struct { C float64 S float64 XAns []float64 YAns []float64 } type DrotmCase struct { P blas.DrotmParams XAns []float64 YAns []float64 Name string } type DTwoVecAnswer struct { X []float64 Y []float64 } var DoubleTwoVectorCases = []DoubleTwoVectorCase{ { Name: "UnitaryInc", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0}, Incx: 1, Incy: 1, N: 6, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 1, Ans: []float64{18, 13, -2, 10, 20, 4}, }, { Alpha: 2, Ans: []float64{28, 28, -8, 13, 34, 11}, }, { Alpha: -3, Ans: []float64{-22, -47, 22, -2, -36, -24}, }, { Alpha: 0, Ans: []float64{8, -2, 4, 7, 6, -3}, }, }, DdotAns: 110, DswapAns: DTwoVecAnswer{ X: []float64{8, -2, 4, 7, 6, -3}, Y: []float64{10, 15, -6, 3, 14, 7}, }, DcopyAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{10, 15, -6, 3, 14, 7}, }, DrotCases: []DrotCase{ { C: math.Cos(0), S: math.Sin(0), XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3}, }, { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{12.444023964292095, 12.749380282068351, -3.7473736752571014, 5.677251193294846, 15.224018588957296, 5.076299724034451}, YAns: []float64{3.024279678886205, -8.151889500183792, 6.160940718590796, 5.076299724034451, -0.4788089421498931, -5.677251193294846}, }, { C: math.Cos(0.5 * math.Pi), S: math.Sin(0.5 * math.Pi), XAns: []float64{8, -2, 4, 7, 6, -3}, YAns: []float64{-10, -15, 6, -3, -14, -7}, }, { C: math.Cos(math.Pi), S: math.Sin(math.Pi), XAns: []float64{-10, -15, 6, -3, -14, -7}, YAns: []float64{-8, 2, -4, -7, -6, 3}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Identity, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3}, Name: "Neg2Flag", }, { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 13.7, -5.8, 2, 12, 6.6}, YAns: []float64{5, 0.5, 1.4, 3.8, 4.4, -0.8}, Name: "Neg1Flag", }, { P: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{1, 0.1, -0.1, 1}, }, XAns: []float64{9.2, 15.2, -6.4, 2.3, 13.4, 7.3}, YAns: []float64{9, -0.5, 3.4, 7.3, 7.4, -2.3}, Name: "ZeroFlag", }, { P: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0.5, -1, 1, 0.7}, }, XAns: []float64{13, 5.5, 1, 8.5, 13, 0.5}, YAns: []float64{-4.4, -16.4, 8.8, 1.9, -9.8, -9.1}, Name: "OneFlag", }, }, }, { Name: "UnitaryIncLong", X: []float64{10, 15, -6, 3, 14, 7, 8, -9, 10}, Y: []float64{8, -2, 4, 7, 6, -3, 7, -6}, XTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: 1, Incy: 1, N: 6, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 1, Ans: []float64{18, 13, -2, 10, 20, 4, 7, -6}, }, { Alpha: 2, Ans: []float64{28, 28, -8, 13, 34, 11, 7, -6}, }, { Alpha: -3, Ans: []float64{-22, -47, 22, -2, -36, -24, 7, -6}, }, { Alpha: 0, Ans: []float64{8, -2, 4, 7, 6, -3, 7, -6}, }, }, DdotAns: 110, DswapAns: DTwoVecAnswer{ X: []float64{8, -2, 4, 7, 6, -3, 8, -9, 10}, Y: []float64{10, 15, -6, 3, 14, 7, 7, -6}, }, DcopyAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7, 8, -9, 10}, Y: []float64{10, 15, -6, 3, 14, 7, 7, -6}, }, DrotCases: []DrotCase{ { C: math.Cos(0), S: math.Sin(0), XAns: []float64{10, 15, -6, 3, 14, 7, 8, -9, 10}, YAns: []float64{8, -2, 4, 7, 6, -3, 7, -6}, }, { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{12.444023964292095, 12.749380282068351, -3.7473736752571014, 5.677251193294846, 15.224018588957296, 5.076299724034451, 8, -9, 10}, YAns: []float64{3.024279678886205, -8.151889500183792, 6.160940718590796, 5.076299724034451, -0.4788089421498931, -5.677251193294846, 7, -6}, }, { C: math.Cos(0.5 * math.Pi), S: math.Sin(0.5 * math.Pi), XAns: []float64{8, -2, 4, 7, 6, -3, 8, -9, 10}, YAns: []float64{-10, -15, 6, -3, -14, -7, 7, -6}, }, { C: math.Cos(math.Pi), S: math.Sin(math.Pi), XAns: []float64{-10, -15, 6, -3, -14, -7, 8, -9, 10}, YAns: []float64{-8, 2, -4, -7, -6, 3, 7, -6}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Identity, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{10, 15, -6, 3, 14, 7, 8, -9, 10}, YAns: []float64{8, -2, 4, 7, 6, -3, 7, -6}, Name: "Neg2Flag", }, { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 13.7, -5.8, 2, 12, 6.6, 8, -9, 10}, YAns: []float64{5, 0.5, 1.4, 3.8, 4.4, -0.8, 7, -6}, Name: "Neg1Flag", }, { P: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{1, 0.1, -0.1, 1}, }, XAns: []float64{9.2, 15.2, -6.4, 2.3, 13.4, 7.3, 8, -9, 10}, YAns: []float64{9, -0.5, 3.4, 7.3, 7.4, -2.3, 7, -6}, Name: "ZeroFlag", }, { P: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0.5, -1, 1, 0.7}, }, XAns: []float64{13, 5.5, 1, 8.5, 13, 0.5, 8, -9, 10}, YAns: []float64{-4.4, -16.4, 8.8, 1.9, -9.8, -9.1, 7, -6}, Name: "OneFlag", }, }, }, { Name: "PositiveInc", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: 2, Incy: 3, N: 3, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{28, -2, 4, -5, 6, -3, 24, 10}, }, }, DdotAns: -18, DswapAns: DTwoVecAnswer{ X: []float64{8, 15, 7, 3, -4, 7}, Y: []float64{10, -2, 4, -6, 6, -3, 14, 10}, }, DcopyAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{10, -2, 4, -6, 6, -3, 14, 10}, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{12.444023964292095, 15, -2.479518890035003, 3, 10.997835971550302, 7}, YAns: []float64{3.024279678886205, -2, 4, 8.879864079700745, 6, -3, -9.541886812516392, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 15, -6.1, 3, 13, 7}, YAns: []float64{5, -2, 4, 2.9, 6, -3, -0.6, 10}, }, { P: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{1, 0.1, -0.1, 1}, }, XAns: []float64{9.2, 15, -6.7, 3, 14.4, 7}, YAns: []float64{9, -2, 4, 6.4, 6, -3, -2.6, 10}, }, { P: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0.5, -1, 1, 0.7}, }, XAns: []float64{13, 15, 4, 3, 3, 7}, YAns: []float64{-4.4, -2, 4, 10.9, 6, -3, -16.8, 10}, }, }, }, { Name: "NegativeInc", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: -2, Incy: -3, N: 3, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{28, -2, 4, -5, 6, -3, 24, 10}, }, }, DdotAns: -18, DswapAns: DTwoVecAnswer{ X: []float64{8, 15, 7, 3, -4, 7}, Y: []float64{10, -2, 4, -6, 6, -3, 14, 10}, }, DcopyAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{10, -2, 4, -6, 6, -3, 14, 10}, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{12.444023964292095, 15, -2.479518890035003, 3, 10.997835971550302, 7}, YAns: []float64{3.024279678886205, -2, 4, 8.879864079700745, 6, -3, -9.541886812516392, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 15, -6.1, 3, 13, 7}, YAns: []float64{5, -2, 4, 2.9, 6, -3, -0.6, 10}, }, { P: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{1, 0.1, -0.1, 1}, }, XAns: []float64{9.2, 15, -6.7, 3, 14.4, 7}, YAns: []float64{9, -2, 4, 6.4, 6, -3, -2.6, 10}, }, { P: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0.5, -1, 1, 0.7}, }, XAns: []float64{13, 15, 4, 3, 3, 7}, YAns: []float64{-4.4, -2, 4, 10.9, 6, -3, -16.8, 10}, }, }, }, { Name: "MixedInc1", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: 2, Incy: -3, N: 3, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{36, -2, 4, -5, 6, -3, 16, 10}, }, }, DdotAns: 30, DswapAns: DTwoVecAnswer{ X: []float64{-4, 15, 7, 3, 8, 7}, Y: []float64{14, -2, 4, -6, 6, -3, 10, 10}, }, DcopyAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{14, -2, 4, -6, 6, -3, 10, 10}, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{7.372604823403701, 15, -2.479518890035003, 3, 16.069255112438693, 7}, YAns: []float64{1.333806631923407, -2, 4, 8.879864079700745, 6, -3, -7.851413765553595, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{9.4, 15, -6.1, 3, 11.8, 7}, YAns: []float64{5.4, -2, 4, 2.9, 6, -3, -1, 10}, }, { P: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{1, 0.1, -0.1, 1}, }, XAns: []float64{10.4, 15, -6.7, 3, 13.2, 7}, YAns: []float64{9.4, -2, 4, 6.4, 6, -3, -3, 10}, }, { P: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0.5, -1, 1, 0.7}, }, XAns: []float64{1, 15, 4, 3, 15, 7}, YAns: []float64{-8.4, -2, 4, 10.9, 6, -3, -12.8, 10}, }, }, }, { Name: "MixedInc2", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: -2, Incy: 3, N: 3, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{36, -2, 4, -5, 6, -3, 16, 10}, }, }, DdotAns: 30, DswapAns: DTwoVecAnswer{ X: []float64{-4, 15, 7, 3, 8, 7}, Y: []float64{14, -2, 4, -6, 6, -3, 10, 10}, }, DcopyAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{14, -2, 4, -6, 6, -3, 10, 10}, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{7.372604823403701, 15, -2.479518890035003, 3, 16.069255112438693, 7}, YAns: []float64{1.333806631923407, -2, 4, 8.879864079700745, 6, -3, -7.851413765553595, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{9.4, 15, -6.1, 3, 11.8, 7}, YAns: []float64{5.4, -2, 4, 2.9, 6, -3, -1, 10}, }, { P: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{1, 0.1, -0.1, 1}, }, XAns: []float64{10.4, 15, -6.7, 3, 13.2, 7}, YAns: []float64{9.4, -2, 4, 6.4, 6, -3, -3, 10}, }, { P: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0.5, -1, 1, 0.7}, }, XAns: []float64{1, 15, 4, 3, 15, 7}, YAns: []float64{-8.4, -2, 4, 10.9, 6, -3, -12.8, 10}, }, }, }, { Name: "ZeroN", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: -2, Incy: 3, N: 0, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, DswapAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, DcopyAns: DTwoVecAnswer{ X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, }, { Name: "NegativeN", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: -2, Incy: 3, N: -3, Panic: true, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{36, -2, 4, -5, 6, -3, 16, 10}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 13.7, -5.8, 2, 12, 6.6}, YAns: []float64{5, 0.5, 1.4, 3.8, 4.4, -0.8}, }, }, }, { Name: "ZeroIncX", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: 0, Incy: 3, N: 2, Panic: true, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{36, -2, 4, -5, 6, -3, 16, 10}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 13.7, -5.8, 2, 12, 6.6}, YAns: []float64{5, 0.5, 1.4, 3.8, 4.4, -0.8}, }, }, }, { Name: "ZeroIncY", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: 1, Incy: 0, N: 2, Panic: true, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{36, -2, 4, -5, 6, -3, 16, 10}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 13.7, -5.8, 2, 12, 6.6}, YAns: []float64{5, 0.5, 1.4, 3.8, 4.4, -0.8}, }, }, }, { Name: "OutOfBoundsX", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: 8, Incy: 2, N: 2, Panic: true, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{36, -2, 4, -5, 6, -3, 16, 10}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{8.2, 13.7, -5.8, 2, 12, 6.6}, YAns: []float64{5, 0.5, 1.4, 3.8, 4.4, -0.8}, }, }, }, { Name: "OutOfBoundsY", X: []float64{10, 15, -6, 3, 14, 7}, Y: []float64{8, -2, 4, 7, 6, -3, -4, 10}, XTmp: []float64{0, 0, 0, 0, 0, 0}, YTmp: []float64{0, 0, 0, 0, 0, 0, 0, 0}, Incx: 2, Incy: 8, N: 2, Panic: true, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{36, -2, 4, -5, 6, -3, 16, 10}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{10, 15, -6, 3, 14, 7}, YAns: []float64{8, -2, 4, 7, 6, -3, -4, 10}, }, }, }, { Name: "Empty", X: []float64{}, Y: []float64{}, Incx: 1, Incy: 1, N: 0, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{}, YAns: []float64{}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{}, YAns: []float64{}, }, }, }, { Name: "EmptyZeroIncX", X: []float64{}, Y: []float64{}, Incx: 0, Incy: 1, N: 0, Panic: true, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{}, YAns: []float64{}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{}, YAns: []float64{}, }, }, }, { Name: "EmptyZeroIncY", X: []float64{}, Y: []float64{}, Incx: 1, Incy: 0, N: 0, Panic: true, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{}, YAns: []float64{}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{}, YAns: []float64{}, }, }, }, { Name: "EmptyReverse", X: []float64{}, Y: []float64{}, Incx: -1, Incy: -1, N: 0, Panic: false, DaxpyCases: []DaxpyCase{ { Alpha: 2, Ans: []float64{}, }, }, DrotCases: []DrotCase{ { C: math.Cos(25 * math.Pi / 180), S: math.Sin(25 * math.Pi / 180), XAns: []float64{}, YAns: []float64{}, }, }, DrotmCases: []DrotmCase{ { P: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.9, 0.1, -0.1, 0.5}, }, XAns: []float64{}, YAns: []float64{}, }, }, }, } type Ddotter interface { Ddot(n int, x []float64, incX int, y []float64, incY int) float64 } func DdotTest(t *testing.T, d Ddotter) { ddot := d.Ddot for _, c := range DoubleTwoVectorCases { dCopyTwoTmp(c.X, c.XTmp, c.Y, c.YTmp) if c.Panic { f := func() { ddot(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy) } testpanics(f, c.Name, t) continue } dot := ddot(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy) if !dTolEqual(dot, c.DdotAns) { t.Errorf("ddot: mismatch %v: expected %v, found %v", c.Name, c.DdotAns, dot) } } // check it works for 16-byte unaligned slices x := []float64{1, 1, 1, 1, 1} if n := ddot(4, x[:4], 1, x[1:], 1); n != 4 { t.Errorf("ddot: mismatch Unaligned: expected %v, found %v", 4, n) } if n := ddot(2, x[:4], 2, x[1:], 2); n != 2 { t.Errorf("ddot: mismatch Unaligned: expected %v, found %v", 2, n) } if n := ddot(2, x[:4], 3, x[1:], 3); n != 2 { t.Errorf("ddot: mismatch Unaligned: expected %v, found %v", 2, n) } } type Dnrm2er interface { Dnrm2(n int, x []float64, incX int) float64 } func Dnrm2Test(t *testing.T, blasser Dnrm2er) { dnrm2 := blasser.Dnrm2 for _, c := range DoubleOneVectorCases { if c.Panic { f := func() { dnrm2(c.N, c.X, c.Incx) } testpanics(f, c.Name, t) continue } v := dnrm2(c.N, c.X, c.Incx) if !dTolEqual(v, c.Dnrm2) { t.Errorf("dnrm2: mismatch %v: expected %v, found %v", c.Name, c.Dnrm2, v) } } } type Dasumer interface { Dasum(n int, x []float64, incX int) float64 } func DasumTest(t *testing.T, blasser Dasumer) { dasum := blasser.Dasum for _, c := range DoubleOneVectorCases { if c.Panic { f := func() { dasum(c.N, c.X, c.Incx) } testpanics(f, c.Name, t) continue } v := dasum(c.N, c.X, c.Incx) if !dTolEqual(v, c.Dasum) { t.Errorf("dasum: mismatch %v: expected %v, found %v", c.Name, c.Dasum, v) } } } type Idamaxer interface { Idamax(n int, x []float64, incX int) int } func IdamaxTest(t *testing.T, blasser Idamaxer) { idamax := blasser.Idamax for _, c := range DoubleOneVectorCases { if c.Panic { f := func() { idamax(c.N, c.X, c.Incx) } testpanics(f, c.Name, t) continue } v := idamax(c.N, c.X, c.Incx) if v != c.Idamax { s := fmt.Sprintf("idamax: mismatch %v: expected %v, found %v", c.Name, c.Idamax, v) if floats.HasNaN(c.X) { t.Log(s) } else { t.Errorf(s) } } } } type Dswapper interface { Dswap(n int, x []float64, incX int, y []float64, incY int) } func DswapTest(t *testing.T, d Dswapper) { dswap := d.Dswap for _, c := range DoubleTwoVectorCases { dCopyTwoTmp(c.X, c.XTmp, c.Y, c.YTmp) if c.Panic { f := func() { dswap(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy) } testpanics(f, c.Name, t) continue } dswap(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy) if !dSliceTolEqual(c.XTmp, c.DswapAns.X) { t.Errorf("dswap: x mismatch %v: expected %v, found %v", c.Name, c.DswapAns.X, c.XTmp) } if !dSliceTolEqual(c.YTmp, c.DswapAns.Y) { t.Errorf("dswap: y mismatch %v: expected %v, found %v", c.Name, c.DswapAns.Y, c.YTmp) } } } type Dcopier interface { Dcopy(n int, x []float64, incX int, y []float64, incY int) } func DcopyTest(t *testing.T, d Dcopier) { dcopy := d.Dcopy for _, c := range DoubleTwoVectorCases { dCopyTwoTmp(c.X, c.XTmp, c.Y, c.YTmp) if c.Panic { f := func() { dcopy(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy) } testpanics(f, c.Name, t) continue } dcopy(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy) if !dSliceTolEqual(c.XTmp, c.DcopyAns.X) { t.Errorf("dswap: x mismatch %v: expected %v, found %v", c.Name, c.DcopyAns.X, c.XTmp) } if !dSliceTolEqual(c.YTmp, c.DcopyAns.Y) { t.Errorf("dswap: y mismatch %v: expected %v, found %v", c.Name, c.DcopyAns.Y, c.YTmp) } } } type Daxpyer interface { Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int) } func DaxpyTest(t *testing.T, d Daxpyer) { daxpy := d.Daxpy for _, c := range DoubleTwoVectorCases { for _, kind := range c.DaxpyCases { dCopyTwoTmp(c.X, c.XTmp, c.Y, c.YTmp) if c.Panic { f := func() { daxpy(c.N, kind.Alpha, c.XTmp, c.Incx, c.YTmp, c.Incy) } testpanics(f, c.Name, t) continue } daxpy(c.N, kind.Alpha, c.XTmp, c.Incx, c.YTmp, c.Incy) if !dSliceTolEqual(c.YTmp, kind.Ans) { t.Errorf("daxpy: mismatch %v: expected %v, found %v", c.Name, kind.Ans, c.YTmp) } } } } type DrotgTestStruct struct { Name string A, B float64 C, S, R, Z float64 } var DrotgTests = []DrotgTestStruct{ { Name: "ZeroAB", C: 1, }, { Name: "PosA_ZeroB", A: 0.5, C: 1, R: 0.5, }, { Name: "NegA_ZeroB", A: -4.6, C: 1, R: -4.6, }, { Name: "ZeroA_PosB", B: 3, S: 1, R: 3, Z: 1, }, { Name: "ZeroA_NegB", B: -0.3, S: 1, R: -0.3, Z: 1, }, { Name: "PosA_PosB_AGTB", A: 5, B: 0.3, C: 0.99820484546577868593549038000, S: 0.05989229072794672115612942280, R: 5.00899191454727744602429072688, Z: 0.05989229072794672115612942280, }, { Name: "PosA_PosB_ALTB", A: 3, B: 4, C: 3.0 / 5, S: 4.0 / 5, R: 5, Z: 5.0 / 3.0, }, { Name: "PosA_NegB_AGTB", A: 2.6, B: -0.9, C: 0.94498607344025815971847507095, S: -0.32711056388316628605639521686, R: 2.751363298439520872718790879655, Z: -0.3271105638831662860563952168, }, { Name: "PosA_NegB_ALTB", A: 2.6, B: -2.9, C: -0.6675450157520258540548049558, S: 0.7445694406464903756765132200, R: -3.8948684188300893100043812234, Z: 1 / -0.6675450157520258540548049558, }, { Name: "NegA_PosB_AGTB", A: -11.4, B: 10.3, C: 0.7419981952497362418487847947, S: -0.6704018781642353764072353847, R: -15.363918770938617534070671122, Z: -0.6704018781642353764072353847, }, { Name: "NegA_PosB_ALTB", A: -1.4, B: 10.3, C: -0.1346838895922121112404717523, S: 0.9908886162855605326977564640, R: 10.394710193170370442523552032, Z: 1 / -0.1346838895922121112404717523, }, { Name: "NegA_NegB_AGTB", A: -11.4, B: 10.3, C: 0.7419981952497362418487847947, S: -0.6704018781642353764072353847, R: -15.363918770938617534070671122, Z: -0.6704018781642353764072353847, }, { Name: "NegA_NegB_ALTB", A: -1.4, B: -10.3, C: 0.1346838895922121112404717523, S: 0.9908886162855605326977564640, R: -10.394710193170370442523552032, Z: 1 / 0.1346838895922121112404717523, }, } type Drotger interface { Drotg(a, b float64) (c, s, r, z float64) } func DrotgTest(t *testing.T, d Drotger, skipExtreme bool) { drotg := d.Drotg for _, test := range DrotgTests { c, s, r, z := drotg(test.A, test.B) if !dTolEqual(c, test.C) { t.Errorf("drotg: c mismatch %v: expected %v, found %v", test.Name, test.C, c) } if !dTolEqual(s, test.S) { t.Errorf("drotg: s mismatch %v: expected %v, found %v", test.Name, test.S, s) } if !dTolEqual(r, test.R) { t.Errorf("drotg: r mismatch %v: expected %v, found %v", test.Name, test.R, r) } if !dTolEqual(z, test.Z) { t.Errorf("drotg: z mismatch %v: expected %v, found %v", test.Name, test.Z, z) } } const ( ulp = 0x1p-52 safmin = 0x1p-1022 safmax = 1 / safmin tol = 20 * ulp ) values := []float64{ -1 / ulp, -1, -1.0 / 3, -ulp, 0, ulp, 1.0 / 3, 1, 1 / ulp, math.Inf(-1), math.Inf(1), math.NaN(), } if !skipExtreme { values = append(values, -safmax, -safmin, safmin, safmax) } for _, f := range values { for _, g := range values { name := fmt.Sprintf("Case f=%v,g=%v", f, g) // Generate a plane rotation so that // [ cs sn] * [f] = [r] // [-sn cs] [g] = [0] // where cs*cs + sn*sn = 1. cs, sn, r, _ := drotg(f, g) switch { case math.IsNaN(f) || math.IsNaN(g): if !math.IsNaN(r) { t.Errorf("%v: unexpected r=%v; want NaN", name, r) } case math.IsInf(f, 0) || math.IsInf(g, 0): if !math.IsNaN(r) && !math.IsInf(r, 0) { t.Errorf("%v: unexpected r=%v; want NaN or Inf", name, r) } default: d := math.Max(math.Abs(f), math.Abs(g)) d = math.Min(math.Max(safmin, d), safmax) fs := f / d gs := g / d rs := r / d // Check that cs*f + sn*g = r. rnorm := math.Abs(rs) if rnorm == 0 { rnorm = math.Max(math.Abs(fs), math.Abs(gs)) if rnorm == 0 { rnorm = 1 } } resid := math.Abs(rs-(cs*fs+sn*gs)) / rnorm if resid > tol { t.Errorf("%v: cs*f + sn*g != r; resid=%v", name, resid) } // Check that -sn*f + cs*g = 0. resid = math.Abs(-sn*fs + cs*gs) if resid > tol { t.Errorf("%v: -sn*f + cs*g != 0; resid=%v", name, resid) } // Check that cs*cs + sn*sn = 1. resid = math.Abs(1 - (cs*cs + sn*sn)) if resid > tol { t.Errorf("%v: cs*cs + sn*sn != 1; resid=%v", name, resid) } // Check that cs is non-negative. if math.Abs(f) > math.Abs(g) { if cs < 0 { t.Errorf("%v: cs is negative; cs=%v", name, cs) } } else { if cs*math.Copysign(1, f)*math.Copysign(1, g) < 0 { t.Errorf("%v: sign of cs doesn't match sign of f and g; cs=%v, sign(f)=%v, sign(g)=%v", name, cs, math.Copysign(1, f), math.Copysign(1, g)) } } } } } } type Drotmger interface { Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) Drotmer } func DrotmgTest(t *testing.T, d Drotmger) { const tol = 1e-14 var tests = []struct { name string d1, d2, x1, y1 float64 d1Want, d2Want, x1Want float64 pWant blas.DrotmParams }{ { name: "NegD1", d1: -4, d2: 6, x1: 8, y1: -4, d1Want: 0, d2Want: 0, x1Want: 0, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0, 0, 0, 0}, }, }, { name: "ZeroD2", d1: 4, d2: 0, x1: 8, y1: -5, d1Want: 4, d2Want: 0, x1Want: 8, pWant: blas.DrotmParams{ Flag: blas.Identity, H: [4]float64{0, 0, 0, 0}, }, }, { name: "ZeroY1", d1: 4, d2: -6, x1: 8, y1: 0, d1Want: 4, d2Want: -6, x1Want: 8, pWant: blas.DrotmParams{ Flag: blas.Identity, H: [4]float64{0, 0, 0, 0}, }, }, { name: "NegQ2_and_AQ1_LT_AQ2", d1: 8, d2: -6, x1: 4, y1: 8, d1Want: 0, d2Want: 0, x1Want: 0, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0, 0, 0, 0}, }, }, { name: "ZeroD1", d1: 0, d2: 2, x1: 8, y1: 4, d1Want: 2, d2Want: 0, x1Want: 4, pWant: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0, 0, 0, 0}, }, }, { name: "AbsQ1_GT_AbsQU__D2_Pos", d1: 2, d2: 3, x1: 8, y1: 5, d1Want: 1.2610837438423645, d2Want: 1.8916256157635467, x1Want: 12.6875, pWant: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375, 0}, }, }, { name: "AbsQ1_GT_AbsQU__D2_Neg", d1: 2, d2: -3, x1: 8, y1: 5, d1Want: 4.830188679245283, d2Want: -7.245283018867925, x1Want: 3.3125, pWant: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, -0.9375, 0}, }, }, { name: "AbsQ1_LT_AbsQU__D2_Pos", d1: 2, d2: 3, x1: 5, y1: 8, d1Want: 2.3801652892561984, d2Want: 1.586776859504132, x1Want: 121.0 / 12, pWant: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}, }, }, { name: "D1=D2_X1=X2", d1: 2, d2: 2, x1: 8, y1: 8, d1Want: 1, d2Want: 1, x1Want: 16, pWant: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{1, 0, 0, 1}, }, }, { name: "RD1_Big_RD2_Big_Flag_0", d1: 1600000000, d2: 800000000, x1: 8, y1: 7, d1Want: 68.96627824858757, d2Want: 34.483139124293785, x1Want: 45312, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{4096, -3584, 1792, 4096}, }, }, { name: "RD1_Big_RD2_Big_Flag_1", d1: 800000000, d2: 1600000000, x1: 8, y1: 7, d1Want: 57.6914092640818, d2Want: 28.8457046320409, x1Want: 47396.57142857142, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{2340.5714285714284, -4096, 4096, 4681.142857142857}, }, }, { name: "RD1_Big_RD2_Med_Flag_0", d1: 20000000, d2: 2, x1: 8, y1: 8, d1Want: 1.1920927762985347, d2Want: 1.9999998000000199, x1Want: 32768.0032768, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{4096, -1, 0.0004096, 1}, }, }, { name: "RD1_Big_RD2_Med_Flag_1", d1: 2, d2: 20000000000, x1: 8, y1: 80000000000, d1Want: 1192.0928955078125, d2Want: 2, x1Want: 3.2768e+14, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{4.096e-17, -1, 4096, 1e-10}, }, }, { name: "D1_Big_D2_Small_Flag_1", d1: 0.000000014, d2: 2000000000, x1: 0.000008, y1: 8000000, d1Want: 119.20928955078125, d2Want: 0.234881024, x1Want: 3.2768e+10, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{2.8671999999999997e-26, -0.000244140625, 4096, 2.44140625e-16}, }, }, { name: "RD1_Med_RD2_Big_Flag_0", d1: 2, d2: 20000000000, x1: 80000000, y1: 8, d1Want: 1.9998000199980002, d2Want: 1191.9736981379988, x1Want: 8.0008e+07, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{1, -0.0004096, 1000, 4096}, }, }, { name: "D1_Med_D2_Big_Flag_1", d1: 20000000000, d2: 0.4, x1: 80000000, y1: 80000000000000000, d1Want: 0.39999998000000103, d2Want: 1192.092835903171, x1Want: 8.0000004e+16, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{50, -4096, 1, 4.096e-06}, }, }, { name: "RD1_Med_RD2_Small_Flag_0", d1: 1.2, d2: 0.000000000045, x1: 2.7, y1: 8, d1Want: 1.1999999996049382, d2Want: 0.0007549747197514486, x1Want: 2.700000000888889, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{1, -0.0007233796296296296, 1.1111111111111111e-10, 0.000244140625}, }, }, { name: "RD1_Med_RD2_Small_Flag_1", d1: 1.2, d2: 0.000000000045, x1: 2.7, y1: 80000000000, d1Want: 0.0007549747199770676, d2Want: 1.19999999996355, x1Want: 1.9531250000593264e+07, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.0002197265625, -1, 0.000244140625, 3.375e-11}, }, }, { name: "D1_Small_D2_Big_Flag_1", d1: 120000000000000000, d2: 0.000000000012345, x1: 0.08, y1: 8000000000000, d1Want: 0.00010502490698765249, d2Want: 216.1836123957717, x1Want: 3.8516669198055897e+09, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{2.3731773997569866e+10, -1.6777216e+07, 0.000244140625, 1.6777216e-07}, }, }, { name: "RD1_Small_RD2_Med_Flag_0", d1: 0.0000000002, d2: 20, x1: 0.8, y1: 0.000000008, d1Want: 0.003355409645903541, d2Want: 19.99980000199998, x1Want: 0.000195314453125, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.000244140625, -1e-08, 0.24414062499999997, 1}, }, }, { name: "RD1_Small_RD2_Med_Flag_1", d1: 0.02, d2: 0.000000000004, x1: 0.008, y1: 8000000, d1Want: 6.710886366445568e-05, d2Want: 0.019999999900000003, x1Want: 1953.125009765625, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0.0012207031250000002, -1, 0.000244140625, 1e-09}, }, }, { // Values consistent with the low precision output posted at the OpenBLAS issue. // See https://github.com/xianyi/OpenBLAS/issues/1452. name: "OpenBLAS#1452", d1: 5.9e-8, d2: 5.960464e-8, x1: 1, y1: 150, d1Want: 0.9999559282289687, d2Want: 0.9898121986058326, x1Want: 0.03662270484346241, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{1.6110934624105326e-06, -0.000244140625, 0.000244140625, 1.6276041666666668e-06}, }, }, // Test cases with values taken from BLAS/TESTING/dblat1.f in the reference. { name: "netlib/BLAS/TESTING#1", d1: 0.1, d2: 0.3, x1: 1.2, y1: 0.2, d1Want: 12 / 130.0, d2Want: 36 / 130.0, x1Want: 1.3, pWant: blas.DrotmParams{ Flag: blas.OffDiagonal, H: [4]float64{0, -1 / 6.0, 0.5, 0}, }, }, { name: "netlib/BLAS/TESTING#2", d1: 0.7, d2: 0.2, x1: 0.6, y1: 4.2, d1Want: 14 / 75.0, d2Want: 49 / 75.0, x1Want: 4.5, pWant: blas.DrotmParams{ Flag: blas.Diagonal, H: [4]float64{0.5, 0, 0, 1 / 7.0}, }, }, { name: "netlib/BLAS/TESTING#3", d1: 0, d2: 0, x1: 0, y1: 0, d1Want: 0, d2Want: 0, x1Want: 0, pWant: blas.DrotmParams{ Flag: blas.Identity, H: [4]float64{0, 0, 0, 0}, }, }, { name: "netlib/BLAS/TESTING#4", d1: 4, d2: -1, x1: 2, y1: 4, d1Want: 0, d2Want: 0, x1Want: 0, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{0, 0, 0, 0}, }, }, { name: "netlib/BLAS/TESTING#5", d1: 6e-10, d2: 2e-2, x1: 1e5, y1: 10, d1Want: 45e-11 * 4096 * 4096, d2Want: 15e-3, x1Want: 4e5 / (3 * 4096), pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{1 / 4096.0, -1e-4, 1e4 / (3 * 4096), 1}, }, }, { name: "netlib/BLAS/TESTING#6", d1: 4e10, d2: 2e-2, x1: 1e-5, y1: 10, d1Want: 4e10 / (1.5 * 4096 * 4096), d2Want: 2e-2 / 1.5, x1Want: 6.144e-2, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{4096, -1e6, 5e-7 * 4096, 1}, }, }, { name: "netlib/BLAS/TESTING#7", d1: 2e-10, d2: 4e-2, x1: 1e5, y1: 10, d1Want: 4 / 150.0, d2Want: (2e-10 / 1.5) * 4096 * 4096, x1Want: 15, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{5e-5, -1 / 4096.0, 1, 1e4 / 4096}, }, }, { name: "netlib/BLAS/TESTING#8", d1: 2e10, d2: 4e-2, x1: 1e-5, y1: 10, d1Want: 4 / 150.0, d2Want: 2e10 / (1.5 * 4096 * 4096), x1Want: 15, pWant: blas.DrotmParams{ Flag: blas.Rescaling, H: [4]float64{5e5, -4096, 1, 4.096e-3}, }, }, } for _, test := range tests { p, d1, d2, x1 := d.Drotmg(test.d1, test.d2, test.x1, test.y1) if p.Flag != test.pWant.Flag { t.Errorf("%v: unexpected flag, want %v, got %v", test.name, test.pWant.Flag, p.Flag) } for i, hi := range p.H { if !scalar.EqualWithinAbsOrRel(test.pWant.H[i], hi, tol, tol) { t.Errorf("%v: unexpected H, want %v, got %v", test.name, test.pWant.H, p.H) break } } if !scalar.EqualWithinAbsOrRel(d1, test.d1Want, tol, tol) { t.Errorf("%v: unexpected d1, want %v, got %v", test.name, test.d1Want, d1) } if !scalar.EqualWithinAbsOrRel(d2, test.d2Want, tol, tol) { t.Errorf("%v: unexpected d2, want %v, got %v", test.name, test.d2Want, d2) } if !scalar.EqualWithinAbsOrRel(x1, test.x1Want, tol, tol) { t.Errorf("%v: unexpected x1, want %v, got %v", test.name, test.x1Want, x1) } // Drotmg routines compute the components of a modified Givens transformation // matrix H that zeros the y-component of the resulting vector, // // [x1; 0] := H[x1 sqrt(d1); y1 sqrt(d2)]. // // Drotm performs a modified Givens rotation of points in the plane, // // [x1; y1] := H[x1; y1]. y := []float64{test.y1} d.Drotm(1, []float64{test.x1}, 1, y, 1, p) if d2 >= 0 { y[0] *= math.Sqrt(d2) } if !scalar.EqualWithinAbs(y[0], 0, 1e-10) { t.Errorf("%v: y1 not zeroed out, got %v", test.name, y[0]) } } } type Droter interface { Drot(n int, x []float64, incX int, y []float64, incY int, c, s float64) } func DrotTest(t *testing.T, d Droter) { drot := d.Drot for _, c := range DoubleTwoVectorCases { for _, kind := range c.DrotCases { dCopyTwoTmp(c.X, c.XTmp, c.Y, c.YTmp) if c.Panic { f := func() { drot(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy, kind.C, kind.S) } testpanics(f, c.Name, t) continue } drot(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy, kind.C, kind.S) if !dSliceTolEqual(c.XTmp, kind.XAns) { t.Errorf("drot: x mismatch %v: expected %v, found %v", c.Name, kind.XAns, c.XTmp) } if !dSliceTolEqual(c.YTmp, kind.YAns) { t.Errorf("drot: y mismatch %v: expected %v, found %v", c.Name, kind.YAns, c.YTmp) } } } } type Drotmer interface { Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) } func DrotmTest(t *testing.T, d Drotmer) { drotm := d.Drotm for _, c := range DoubleTwoVectorCases { for _, kind := range c.DrotmCases { dCopyTwoTmp(c.X, c.XTmp, c.Y, c.YTmp) if c.Panic { f := func() { drotm(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy, kind.P) } testpanics(f, c.Name+", "+kind.Name, t) continue } drotm(c.N, c.XTmp, c.Incx, c.YTmp, c.Incy, kind.P) if !dSliceTolEqual(c.XTmp, kind.XAns) { t.Errorf("drotm: mismatch %v: expected %v, found %v", c.Name, kind.XAns, c.XTmp) } if !dSliceTolEqual(c.YTmp, kind.YAns) { t.Errorf("drotm: mismatch %v: expected %v, found %v", c.Name, kind.YAns, c.YTmp) } } } } type Dscaler interface { Dscal(n int, alpha float64, x []float64, incX int) } func DscalTest(t *testing.T, blasser Dscaler) { dscal := blasser.Dscal for _, c := range DoubleOneVectorCases { for _, kind := range c.DscalCases { xTmp := make([]float64, len(c.X)) copy(xTmp, c.X) if c.Panic { f := func() { dscal(c.N, kind.Alpha, xTmp, c.Incx) } testpanics(f, c.Name, t) continue } dscal(c.N, kind.Alpha, xTmp, c.Incx) if !dSliceTolEqual(xTmp, kind.Ans) { t.Errorf("dscal: mismatch %v, %v: expected %v, found %v", c.Name, kind.Name, kind.Ans, xTmp) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/level2bench.go000066400000000000000000000035701450372207100231250ustar00rootroot00000000000000// 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 testblas import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) func DgemvBenchmark(b *testing.B, impl Dgemver, tA blas.Transpose, m, n, incX, incY int) { var lenX, lenY int if tA == blas.NoTrans { lenX = n lenY = m } else { lenX = m lenY = n } xr := make([]float64, lenX) for i := range xr { xr[i] = rand.Float64() } x := makeIncremented(xr, incX, 0) yr := make([]float64, lenY) for i := range yr { yr[i] = rand.Float64() } y := makeIncremented(yr, incY, 0) a := make([]float64, m*n) for i := range a { a[i] = rand.Float64() } b.ResetTimer() for i := 0; i < b.N; i++ { impl.Dgemv(tA, m, n, 2, a, n, x, incX, 3, y, incY) } } func DgerBenchmark(b *testing.B, impl Dgerer, m, n, incX, incY int) { xr := make([]float64, m) for i := range xr { xr[i] = rand.Float64() } x := makeIncremented(xr, incX, 0) yr := make([]float64, n) for i := range yr { yr[i] = rand.Float64() } y := makeIncremented(yr, incY, 0) a := make([]float64, m*n) for i := range a { a[i] = rand.Float64() } b.ResetTimer() for i := 0; i < b.N; i++ { impl.Dger(m, n, 2, x, incX, y, incY, a, n) } } type Sgerer interface { Sger(m, n int, alpha float32, x []float32, incX int, y []float32, incY int, a []float32, lda int) } func SgerBenchmark(b *testing.B, blasser Sgerer, m, n, incX, incY int) { xr := make([]float32, m) for i := range xr { xr[i] = rand.Float32() } x := makeIncremented32(xr, incX, 0) yr := make([]float32, n) for i := range yr { yr[i] = rand.Float32() } y := makeIncremented32(yr, incY, 0) a := make([]float32, m*n) for i := range a { a[i] = rand.Float32() } b.ResetTimer() for i := 0; i < b.N; i++ { blasser.Sger(m, n, 2, x, incX, y, incY, a, n) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zaxpy.go000066400000000000000000000162761450372207100221160ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" ) type Zaxpyer interface { Zaxpy(n int, alpha complex128, x []complex128, incX int, y []complex128, incY int) } func ZaxpyTest(t *testing.T, impl Zaxpyer) { for tc, test := range []struct { alpha complex128 x, y []complex128 want []complex128 // Result when both increments have the same sign. wantRev []complex128 // Result when the increments have opposite sign. }{ { alpha: 0, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i, 63 + 64i}, want: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i, 63 + 64i}, wantRev: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i, 63 + 64i}, }, { alpha: 1, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i, 63 + 64i}, want: []complex128{31 + 33i, 36 + 38i, 41 + 43i, 46 + 48i, 51 + 53i, 56 + 58i, 61 + 63i, 66 + 68i, 71 + 73i, 76 + 78i, 81 + 83i, 86 + 88i}, wantRev: []complex128{53 + 55i, 54 + 56i, 55 + 57i, 56 + 58i, 57 + 59i, 58 + 60i, 59 + 61i, 60 + 62i, 61 + 63i, 62 + 64i, 63 + 65i, 64 + 66i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i}, y: []complex128{30 + 31i}, want: []complex128{19 + 44i}, wantRev: []complex128{19 + 44i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i}, y: []complex128{30 + 31i, 33 + 34i}, want: []complex128{19 + 44i, 14 + 67i}, wantRev: []complex128{11 + 64i, 22 + 47i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i}, wantRev: []complex128{3 + 84i, 14 + 67i, 25 + 50i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i}, wantRev: []complex128{-5 + 104i, 6 + 87i, 17 + 70i, 28 + 53i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i}, wantRev: []complex128{-13 + 124i, -2 + 107i, 9 + 90i, 20 + 73i, 31 + 56i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i, -6 + 159i}, wantRev: []complex128{-21 + 144i, -10 + 127i, 1 + 110i, 12 + 93i, 23 + 76i, 34 + 59i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i, -6 + 159i, -11 + 182i}, wantRev: []complex128{-29 + 164i, -18 + 147i, -7 + 130i, 4 + 113i, 15 + 96i, 26 + 79i, 37 + 62i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i, -6 + 159i, -11 + 182i, -16 + 205i}, wantRev: []complex128{-37 + 184i, -26 + 167i, -15 + 150i, -4 + 133i, 7 + 116i, 18 + 99i, 29 + 82i, 40 + 65i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i, -6 + 159i, -11 + 182i, -16 + 205i, -21 + 228i}, wantRev: []complex128{-45 + 204i, -34 + 187i, -23 + 170i, -12 + 153i, -1 + 136i, 10 + 119i, 21 + 102i, 32 + 85i, 43 + 68i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i, -6 + 159i, -11 + 182i, -16 + 205i, -21 + 228i, -26 + 251i}, wantRev: []complex128{-53 + 224i, -42 + 207i, -31 + 190i, -20 + 173i, -9 + 156i, 2 + 139i, 13 + 122i, 24 + 105i, 35 + 88i, 46 + 71i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i, -6 + 159i, -11 + 182i, -16 + 205i, -21 + 228i, -26 + 251i, -31 + 274i}, wantRev: []complex128{-61 + 244i, -50 + 227i, -39 + 210i, -28 + 193i, -17 + 176i, -6 + 159i, 5 + 142i, 16 + 125i, 27 + 108i, 38 + 91i, 49 + 74i}, }, { alpha: 3 + 7i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i, 63 + 64i}, want: []complex128{19 + 44i, 14 + 67i, 9 + 90i, 4 + 113i, -1 + 136i, -6 + 159i, -11 + 182i, -16 + 205i, -21 + 228i, -26 + 251i, -31 + 274i, -36 + 297i}, wantRev: []complex128{-69 + 264i, -58 + 247i, -47 + 230i, -36 + 213i, -25 + 196i, -14 + 179i, -3 + 162i, 8 + 145i, 19 + 128i, 30 + 111i, 41 + 94i, 52 + 77i}, }, } { n := len(test.x) if len(test.y) != n || len(test.want) != n || len(test.wantRev) != n { panic("bad test") } for _, inc := range allPairs([]int{-7, -3, 1, 13}, []int{-11, -5, 1, 17}) { incX := inc[0] incY := inc[1] x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) var want []complex128 if incX*incY > 0 { want = makeZVector(test.want, incY) } else { want = makeZVector(test.wantRev, incY) } impl.Zaxpy(n, test.alpha, x, incX, y, incY) prefix := fmt.Sprintf("Case %v (incX=%v,incY=%v):", tc, incX, incY) if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x", prefix) } if !zsame(y, want) { t.Errorf("%v: unexpected y:\nwant %v\ngot %v", prefix, want, y) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zcopy.go000066400000000000000000000030471450372207100220770ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" ) type Zcopyer interface { Zcopy(n int, x []complex128, incX int, y []complex128, incY int) } func ZcopyTest(t *testing.T, impl Zcopyer) { rnd := rand.New(rand.NewSource(1)) for n := 0; n <= 20; n++ { for _, inc := range allPairs([]int{-7, -3, 1, 13}, []int{-11, -5, 1, 17}) { incX := inc[0] incY := inc[1] aincX := abs(incX) aincY := abs(incY) var x []complex128 if n > 0 { x = make([]complex128, (n-1)*aincX+1) } for i := range x { x[i] = znan } for i := 0; i < n; i++ { x[i*aincX] = complex(rnd.NormFloat64(), rnd.NormFloat64()) } xCopy := make([]complex128, len(x)) copy(xCopy, x) var y []complex128 if n > 0 { y = make([]complex128, (n-1)*aincY+1) } for i := range y { y[i] = znan } want := make([]complex128, len(y)) for i := range want { want[i] = znan } if incX*incY > 0 { for i := 0; i < n; i++ { want[i*aincY] = x[i*aincX] } } else { for i := 0; i < n; i++ { want[i*aincY] = x[(n-1-i)*aincX] } } impl.Zcopy(n, x, incX, y, incY) prefix := fmt.Sprintf("Case n=%v,incX=%v,incY=%v:", n, incX, incY) if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x", prefix) } if !zsame(y, want) { t.Errorf("%v: unexpected y:\nwant %v\ngot %v", prefix, want, y) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zdotc.go000066400000000000000000000102601450372207100220510ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" ) type Zdotcer interface { Zdotc(n int, x []complex128, incX int, y []complex128, incY int) complex128 } func ZdotcTest(t *testing.T, impl Zdotcer) { for tc, test := range []struct { x, y []complex128 want complex128 // Result when both increments have the same sign. wantRev complex128 // Result when the increments have opposite sign. }{ { x: nil, y: nil, want: 0, wantRev: 0, }, { x: []complex128{1 + 2i}, y: []complex128{30 + 31i}, want: 92 - 29i, wantRev: 92 - 29i, }, { x: []complex128{1 + 2i, 3 + 4i}, y: []complex128{30 + 31i, 33 + 34i}, want: 327 - 59i, wantRev: 315 - 59i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i}, want: 729 - 90i, wantRev: 681 - 90i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i}, want: 1322 - 122i, wantRev: 1202 - 122i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i}, want: 2130 - 155i, wantRev: 1890 - 155i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i}, want: 3177 - 189i, wantRev: 2757 - 189i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i}, want: 4487 - 224i, wantRev: 3815 - 224i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i}, want: 6084 - 260i, wantRev: 5076 - 260i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i}, want: 7992 - 297i, wantRev: 6552 - 297i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i}, want: 10235 - 335i, wantRev: 8255 - 335i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i}, want: 12837 - 374i, wantRev: 10197 - 374i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i, 63 + 64i}, want: 15822 - 414i, wantRev: 12390 - 414i, }, } { n := len(test.x) if len(test.y) != n { panic("bad test") } for _, inc := range allPairs([]int{-7, -3, 1, 13}, []int{-11, -5, 1, 17}) { incX := inc[0] incY := inc[1] x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) yCopy := make([]complex128, len(y)) copy(yCopy, y) want := test.want if incX*incY < 0 { want = test.wantRev } got := impl.Zdotc(n, x, incX, y, incY) prefix := fmt.Sprintf("Case %v (incX=%v,incY=%v):", tc, incX, incY) if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x", prefix) } if !zsame(y, yCopy) { t.Errorf("%v: unexpected modification of y", prefix) } if got != want { t.Errorf("%v: unexpected result. want %v, got %v", prefix, want, got) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zdotu.go000066400000000000000000000103121450372207100220710ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" ) type Zdotuer interface { Zdotu(n int, x []complex128, incX int, y []complex128, incY int) complex128 } func ZdotuTest(t *testing.T, impl Zdotuer) { for tc, test := range []struct { x, y []complex128 want complex128 // Result when both increments have the same sign. wantRev complex128 // Result when the increments have opposite sign. }{ { x: nil, y: nil, want: 0, wantRev: 0, }, { x: []complex128{1 + 2i}, y: []complex128{30 + 31i}, want: -32 + 91i, wantRev: -32 + 91i, }, { x: []complex128{1 + 2i, 3 + 4i}, y: []complex128{30 + 31i, 33 + 34i}, want: -69 + 325i, wantRev: -69 + 313i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i}, want: -111 + 726i, wantRev: -111 + 678i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i}, want: -158 + 1318i, wantRev: -158 + 1198i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i}, want: -210 + 2125i, wantRev: -210 + 1885i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i}, want: -267 + 3171i, wantRev: -267 + 2751i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i}, want: -329 + 4480i, wantRev: -329 + 3808i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i}, want: -396 + 6076i, wantRev: -396 + 5068i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i}, want: -468 + 7983i, wantRev: -468 + 6543i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i}, want: -545 + 10225i, wantRev: -545 + 8245i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i}, want: -627 + 12826i, wantRev: -627 + 10186i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, y: []complex128{30 + 31i, 33 + 34i, 36 + 37i, 39 + 40i, 42 + 43i, 45 + 46i, 48 + 49i, 51 + 52i, 54 + 55i, 57 + 58i, 60 + 61i, 63 + 64i}, want: -714 + 15810i, wantRev: -714 + 12378i, }, } { n := len(test.x) if len(test.y) != n { panic("bad test") } for _, inc := range allPairs([]int{-7, -3, 1, 13}, []int{-11, -5, 1, 17}) { incX := inc[0] incY := inc[1] x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) yCopy := make([]complex128, len(y)) copy(yCopy, y) want := test.want if incX*incY < 0 { want = test.wantRev } got := impl.Zdotu(n, x, incX, y, incY) prefix := fmt.Sprintf("Case %v (incX=%v,incY=%v):", tc, incX, incY) if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x", prefix) } if !zsame(y, yCopy) { t.Errorf("%v: unexpected modification of y", prefix) } if got != want { t.Errorf("%v: unexpected result. want %v, got %v", prefix, want, got) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zdscal.go000066400000000000000000000070411450372207100222110ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" ) type Zdscaler interface { Zdscal(n int, alpha float64, x []complex128, incX int) } func ZdscalTest(t *testing.T, impl Zdscaler) { for tc, test := range []struct { alpha float64 x []complex128 want []complex128 }{ { alpha: 3, x: nil, want: nil, }, { alpha: 3, x: []complex128{1 + 2i}, want: []complex128{3 + 6i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i}, want: []complex128{3 + 6i, 9 + 12i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i, 33 + 36i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i, 33 + 36i, 39 + 42i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i, 33 + 36i, 39 + 42i, 45 + 48i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i, 33 + 36i, 39 + 42i, 45 + 48i, 51 + 54i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i, 33 + 36i, 39 + 42i, 45 + 48i, 51 + 54i, 57 + 60i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i, 33 + 36i, 39 + 42i, 45 + 48i, 51 + 54i, 57 + 60i, 63 + 66i}, }, { alpha: 3, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, want: []complex128{3 + 6i, 9 + 12i, 15 + 18i, 21 + 24i, 27 + 30i, 33 + 36i, 39 + 42i, 45 + 48i, 51 + 54i, 57 + 60i, 63 + 66i, 69 + 72i}, }, { alpha: 0, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, want: []complex128{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, } { n := len(test.x) if len(test.want) != n { panic("bad test") } for _, incX := range []int{-3, -1, 1, 2, 4, 7, 10} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) want := makeZVector(test.want, incX) impl.Zdscal(n, test.alpha, x, incX) prefix := fmt.Sprintf("Case %v (n=%v,incX=%v):", tc, n, incX) if incX < 0 { if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x\nwant %v\ngot %v", prefix, want, x) } continue } if !zsame(x, want) { t.Errorf("%v: unexpected result:\nwant: %v\ngot: %v", prefix, want, x) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zgbmv.go000066400000000000000000000102511450372207100220530ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zgbmver interface { Zgbmv(trans blas.Transpose, m, n, kL, kU int, alpha complex128, ab []complex128, ldab int, x []complex128, incX int, beta complex128, y []complex128, incY int) Zgemver } func ZgbmvTest(t *testing.T, impl Zgbmver) { rnd := rand.New(rand.NewSource(1)) for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { // Generate all possible size combinations. for _, mn := range allPairs([]int{1, 2, 3, 5}, []int{1, 2, 3, 5}) { m := mn[0] n := mn[1] // Generate all possible numbers of lower and upper // diagonals. Use slices to reduce indentation. kLs := make([]int, max(1, m)) for i := range kLs { kLs[i] = i } kUs := make([]int, max(1, n)) for i := range kUs { kUs[i] = i } for _, ks := range allPairs(kLs, kUs) { kL := ks[0] kU := ks[1] for _, ab := range []struct { alpha complex128 beta complex128 }{ // All potentially relevant values of // alpha and beta. {0, 0}, {0, 1}, {0, complex(rnd.NormFloat64(), rnd.NormFloat64())}, {complex(rnd.NormFloat64(), rnd.NormFloat64()), 0}, {complex(rnd.NormFloat64(), rnd.NormFloat64()), 1}, {complex(rnd.NormFloat64(), rnd.NormFloat64()), complex(rnd.NormFloat64(), rnd.NormFloat64())}, } { for _, ldab := range []int{kL + kU + 1, kL + kU + 20} { for _, inc := range allPairs([]int{-3, -2, -1, 1, 2, 3}, []int{-3, -2, -1, 1, 2, 3}) { incX := inc[0] incY := inc[1] testZgbmv(t, impl, rnd, trans, m, n, kL, kU, ab.alpha, ab.beta, ldab, incX, incY) } } } } } } } // testZgbmv tests Zgbmv by comparing its output to that of Zgemv. func testZgbmv(t *testing.T, impl Zgbmver, rnd *rand.Rand, trans blas.Transpose, m, n, kL, kU int, alpha, beta complex128, ldab, incX, incY int) { const tol = 1e-13 // Allocate a dense-storage band matrix filled with NaNs that will be // used as the reference matrix for Zgemv. lda := max(1, n) a := makeZGeneral(nil, m, n, lda) // Fill the matrix with zeros. for i := 0; i < m; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 } } // Fill the band with random data. for i := 0; i < m; i++ { for j := max(0, i-kL); j < min(n, i+kU+1); j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } // Create the actual band matrix. ab := zPackBand(kL, kU, ldab, m, n, a, lda) abCopy := make([]complex128, len(ab)) copy(abCopy, ab) // Compute correct lengths of vectors x and y. var lenX, lenY int switch trans { case blas.NoTrans: lenX = n lenY = m case blas.Trans, blas.ConjTrans: lenX = m lenY = n } // Generate a random complex vector x. xtest := make([]complex128, lenX) for i := range xtest { re := rnd.NormFloat64() im := rnd.NormFloat64() xtest[i] = complex(re, im) } x := makeZVector(xtest, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) // Generate a random complex vector y. ytest := make([]complex128, lenY) for i := range ytest { re := rnd.NormFloat64() im := rnd.NormFloat64() ytest[i] = complex(re, im) } y := makeZVector(ytest, incY) want := make([]complex128, len(y)) copy(want, y) // Compute the reference result of alpha*op(A)*x + beta*y, storing it // into want. impl.Zgemv(trans, m, n, alpha, a, lda, x, incX, beta, want, incY) // Compute alpha*op(A)*x + beta*y, storing the result in-place into y. impl.Zgbmv(trans, m, n, kL, kU, alpha, ab, ldab, x, incX, beta, y, incY) name := fmt.Sprintf("trans=%v,m=%v,n=%v,kL=%v,kU=%v,lda=%v,incX=%v,incY=%v", trans, m, n, kL, kU, lda, incX, incY) if !zsame(ab, abCopy) { t.Errorf("%v: unexpected modification of ab", name) } if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x", name) } if !zSameAtNonstrided(y, want, incY) { t.Errorf("%v: unexpected modification of y", name) } if !zEqualApproxAtStrided(y, want, incY, tol) { t.Errorf("%v: unexpected result\ngot %v\nwant %v\n", name, y, want) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zgemm.go000066400000000000000000000056471450372207100220620ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zgemmer interface { Zgemm(tA, tB blas.Transpose, m, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) } func ZgemmTest(t *testing.T, impl Zgemmer) { for _, tA := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, tB := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { name := transString(tA) + "-" + transString(tB) t.Run(name, func(t *testing.T) { for _, m := range []int{0, 1, 2, 5, 10} { for _, n := range []int{0, 1, 2, 5, 10} { for _, k := range []int{0, 1, 2, 7, 11} { zgemmTest(t, impl, tA, tB, m, n, k) } } } }) } } } func zgemmTest(t *testing.T, impl Zgemmer, tA, tB blas.Transpose, m, n, k int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) rowA, colA := m, k if tA != blas.NoTrans { rowA, colA = k, m } rowB, colB := k, n if tB != blas.NoTrans { rowB, colB = n, k } for _, lda := range []int{max(1, colA), colA + 2} { for _, ldb := range []int{max(1, colB), colB + 3} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { for _, beta := range []complex128{0, 1, complex(1.3, -1.1)} { // Allocate the matrix A and fill it with random numbers. a := make([]complex128, rowA*lda) for i := range a { a[i] = rndComplex128(rnd) } // Create a copy of A. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Allocate the matrix B and fill it with random numbers. b := make([]complex128, rowB*ldb) for i := range b { b[i] = rndComplex128(rnd) } // Create a copy of B. bCopy := make([]complex128, len(b)) copy(bCopy, b) // Allocate the matrix C and fill it with random numbers. c := make([]complex128, m*ldc) for i := range c { c[i] = rndComplex128(rnd) } // Compute the expected result using an internal Zgemm implementation. want := zmm(tA, tB, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc) // Compute a result using Zgemm. impl.Zgemm(tA, tB, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc) prefix := fmt.Sprintf("m=%v,n=%v,k=%v,lda=%v,ldb=%v,ldc=%v,alpha=%v,beta=%v", m, n, k, lda, ldb, ldc, alpha, beta) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if !zsame(b, bCopy) { t.Errorf("%v: unexpected modification of B", prefix) continue } if !zEqualApprox(c, want, tol) { t.Errorf("%v: unexpected result,\nwant=%v\ngot =%v\n", prefix, want, c) } } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zgemv.go000066400000000000000000000146541450372207100220710ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Zgemver interface { Zgemv(trans blas.Transpose, m, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) } func ZgemvTest(t *testing.T, impl Zgemver) { for tc, test := range []struct { trans blas.Transpose alpha complex128 a []complex128 x []complex128 beta complex128 y []complex128 want []complex128 wantXNeg []complex128 wantYNeg []complex128 wantXYNeg []complex128 }{ { trans: blas.NoTrans, alpha: 1 + 2i, beta: 3 + 4i, }, { trans: blas.NoTrans, alpha: 1 + 2i, a: []complex128{ 9 + 5i, -2 + 6i, 5 + 1i, 9 + 2i, 10 + 4i, 0 - 7i, 9 - 9i, 5 + 3i, -8 - 1i, 7 - 7i, 10 - 7i, -1 + 3i, 2 + 2i, 7 + 6i, 9 + 1i, 10 + 0i, 8 - 6i, 4 - 6i, -2 - 10i, -5 + 0i, }, x: []complex128{ 4 - 9i, 8 + 5i, -2 - 10i, 2 - 4i, -6 + 6i, }, beta: 3 + 4i, y: []complex128{ -2 + 3i, 10 + 5i, -8 - 5i, -8 + 7i, }, want: []complex128{ 101 - 116i, 58 + 166i, 126 - 242i, 336 - 75i, }, wantXNeg: []complex128{ 98 + 128i, 374 - 252i, -113 + 205i, -60 - 312i, }, wantYNeg: []complex128{ 370 - 63i, 140 - 140i, 44 + 64i, 67 - 128i, }, wantXYNeg: []complex128{ -26 - 300i, -99 + 307i, 360 - 354i, 64 + 116i, }, }, { trans: blas.Trans, alpha: 1 + 2i, a: []complex128{ 9 + 5i, -2 + 6i, 5 + 1i, 9 + 2i, 10 + 4i, 0 - 7i, 9 - 9i, 5 + 3i, -8 - 1i, 7 - 7i, 10 - 7i, -1 + 3i, 2 + 2i, 7 + 6i, 9 + 1i, 10 + 0i, 8 - 6i, 4 - 6i, -2 - 10i, -5 + 0i, }, x: []complex128{ 4 - 9i, 8 + 5i, -2 - 10i, 2 - 4i, }, beta: 3 + 4i, y: []complex128{ 8 - 6i, -8 - 2i, 9 + 5i, 4 - 1i, 6 - 4i, }, want: []complex128{ 580 - 137i, 221 + 311i, 149 + 115i, 443 - 208i, 517 + 143i, }, wantXNeg: []complex128{ 387 + 152i, 109 - 433i, 225 - 53i, -246 + 44i, 13 + 20i, }, wantYNeg: []complex128{ 531 + 145i, 411 - 259i, 149 + 115i, 253 + 362i, 566 - 139i, }, wantXYNeg: []complex128{ 27 + 22i, -278 - 7i, 225 - 53i, 141 - 382i, 373 + 150i, }, }, { trans: blas.ConjTrans, alpha: 1 + 2i, a: []complex128{ 9 + 5i, -2 + 6i, 5 + 1i, 9 + 2i, 10 + 4i, 0 - 7i, 9 - 9i, 5 + 3i, -8 - 1i, 7 - 7i, 10 - 7i, -1 + 3i, 2 + 2i, 7 + 6i, 9 + 1i, 10 + 0i, 8 - 6i, 4 - 6i, -2 - 10i, -5 + 0i, }, x: []complex128{ 4 - 9i, 8 + 5i, -2 - 10i, 2 - 4i, }, beta: 3 + 4i, y: []complex128{ 8 - 6i, -8 - 2i, 9 + 5i, 4 - 1i, 6 - 4i, }, want: []complex128{ 472 - 133i, -253 + 23i, 217 + 131i, 229 - 316i, 187 - 97i, }, wantXNeg: []complex128{ 289 + 276i, 499 + 47i, 237 + 91i, 54 + 504i, 251 + 196i, }, wantYNeg: []complex128{ 201 - 95i, 197 - 367i, 217 + 131i, -221 + 74i, 458 - 135i, }, wantXYNeg: []complex128{ 265 + 198i, 22 + 453i, 237 + 91i, 531 + 98i, 275 + 274i, }, }, { trans: blas.ConjTrans, alpha: 1 + 2i, a: []complex128{ 9 + 5i, -2 + 6i, 5 + 1i, 9 + 2i, 10 + 4i, 0 - 7i, 9 - 9i, 5 + 3i, -8 - 1i, 7 - 7i, 10 - 7i, -1 + 3i, 2 + 2i, 7 + 6i, 9 + 1i, 10 + 0i, 8 - 6i, 4 - 6i, -2 - 10i, -5 + 0i, }, x: []complex128{ 4 - 9i, 8 + 5i, -2 - 10i, 2 - 4i, }, beta: 0, y: []complex128{ 8 - 6i, -8 - 2i, 9 + 5i, 4 - 1i, 6 - 4i, }, want: []complex128{ 424 - 147i, -237 + 61i, 210 + 80i, 213 - 329i, 153 - 109i, }, wantXNeg: []complex128{ 241 + 262i, 515 + 85i, 230 + 40i, 38 + 491i, 217 + 184i, }, wantYNeg: []complex128{ 153 - 109i, 213 - 329i, 210 + 80i, -237 + 61i, 424 - 147i, }, wantXYNeg: []complex128{ 217 + 184i, 38 + 491i, 230 + 40i, 515 + 85i, 241 + 262i, }, }, { trans: blas.ConjTrans, alpha: 0, a: []complex128{ 9 + 5i, -2 + 6i, 5 + 1i, 9 + 2i, 10 + 4i, 0 - 7i, 9 - 9i, 5 + 3i, -8 - 1i, 7 - 7i, 10 - 7i, -1 + 3i, 2 + 2i, 7 + 6i, 9 + 1i, 10 + 0i, 8 - 6i, 4 - 6i, -2 - 10i, -5 + 0i, }, x: []complex128{ 4 - 9i, 8 + 5i, -2 - 10i, 2 - 4i, }, beta: 3 + 4i, y: []complex128{ 8 - 6i, -8 - 2i, 9 + 5i, 4 - 1i, 6 - 4i, }, want: []complex128{ 48 + 14i, -16 - 38i, 7 + 51i, 16 + 13i, 34 + 12i, }, wantXNeg: []complex128{ 48 + 14i, -16 - 38i, 7 + 51i, 16 + 13i, 34 + 12i, }, wantYNeg: []complex128{ 48 + 14i, -16 - 38i, 7 + 51i, 16 + 13i, 34 + 12i, }, wantXYNeg: []complex128{ 48 + 14i, -16 - 38i, 7 + 51i, 16 + 13i, 34 + 12i, }, }, } { var m, n int switch test.trans { case blas.NoTrans: m = len(test.y) n = len(test.x) case blas.Trans, blas.ConjTrans: m = len(test.x) n = len(test.y) } for _, incX := range []int{-11, -2, -1, 1, 2, 7} { for _, incY := range []int{-11, -2, -1, 1, 2, 7} { for _, lda := range []int{max(1, n), n + 11} { alpha := test.alpha a := makeZGeneral(test.a, m, n, lda) aCopy := make([]complex128, len(a)) copy(aCopy, a) x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) impl.Zgemv(test.trans, m, n, alpha, a, lda, x, incX, test.beta, y, incY) if !zsame(x, xCopy) { t.Errorf("Case %v (incX=%v,incY=%v,lda=%v): unexpected modification of x", tc, incX, incY, lda) } if !zsame(a, aCopy) { t.Errorf("Case %v (incX=%v,incY=%v,lda=%v): unexpected modification of A", tc, incX, incY, lda) } var want []complex128 switch { case incX > 0 && incY > 0: want = makeZVector(test.want, incY) case incX < 0 && incY > 0: want = makeZVector(test.wantXNeg, incY) case incX > 0 && incY < 0: want = makeZVector(test.wantYNeg, incY) default: want = makeZVector(test.wantXYNeg, incY) } if !zsame(y, want) { t.Errorf("Case %v (incX=%v,incY=%v,lda=%v): unexpected result\nwant %v\ngot %v", tc, incX, incY, lda, want, y) } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zgerc.go000066400000000000000000000113261450372207100220440ustar00rootroot00000000000000// 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 testblas import ( "testing" ) type Zgercer interface { Zgerc(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) } func ZgercTest(t *testing.T, impl Zgercer) { for tc, test := range []struct { alpha complex128 x []complex128 incX int y []complex128 incY int a []complex128 want []complex128 }{ { incX: 1, incY: 1, alpha: 1 + 2i, }, { incX: 1, incY: 1, alpha: 1 + 2i, x: []complex128{1 + 13i, 18 + 15i, 10 + 18i}, y: []complex128{15 + 12i, 4 + 8i, 5 + 16i, 19 + 12i}, a: []complex128{ 10 + 9i, 6 + 17i, 3 + 10i, 6 + 7i, 3 + 4i, 11 + 16i, 5 + 14i, 11 + 18i, 18 + 6i, 4 + 1i, 13 + 2i, 14 + 3i}, want: []complex128{ -185 + 534i, 26 + 277i, 118 + 485i, -289 + 592i, 435 + 913i, 371 + 316i, 761 + 461i, 395 + 1131i, 84 + 888i, 204 + 361i, 491 + 608i, -24 + 1037i}, }, { incX: 7, incY: 13, alpha: 1 + 2i, x: []complex128{1 + 13i, 18 + 15i, 10 + 18i}, y: []complex128{15 + 12i, 4 + 8i, 5 + 16i, 19 + 12i}, a: []complex128{ 10 + 9i, 6 + 17i, 3 + 10i, 6 + 7i, 3 + 4i, 11 + 16i, 5 + 14i, 11 + 18i, 18 + 6i, 4 + 1i, 13 + 2i, 14 + 3i}, want: []complex128{ -185 + 534i, 26 + 277i, 118 + 485i, -289 + 592i, 435 + 913i, 371 + 316i, 761 + 461i, 395 + 1131i, 84 + 888i, 204 + 361i, 491 + 608i, -24 + 1037i}, }, { incX: -7, incY: -13, alpha: 1 + 2i, x: []complex128{10 + 18i, 18 + 15i, 1 + 13i}, y: []complex128{19 + 12i, 5 + 16i, 4 + 8i, 15 + 12i}, a: []complex128{ 10 + 9i, 6 + 17i, 3 + 10i, 6 + 7i, 3 + 4i, 11 + 16i, 5 + 14i, 11 + 18i, 18 + 6i, 4 + 1i, 13 + 2i, 14 + 3i}, want: []complex128{ -185 + 534i, 26 + 277i, 118 + 485i, -289 + 592i, 435 + 913i, 371 + 316i, 761 + 461i, 395 + 1131i, 84 + 888i, 204 + 361i, 491 + 608i, -24 + 1037i}, }, { incX: 1, incY: 1, alpha: 1 + 2i, x: []complex128{5 + 16i, 12 + 19i, 9 + 7i, 2 + 4i}, y: []complex128{18 + 7i, 20 + 15i, 12 + 14i}, a: []complex128{ 11 + 4i, 17 + 18i, 7 + 13i, 14 + 20i, 14 + 10i, 7 + 5i, 7 + 17i, 10 + 6i, 11 + 13i, 7 + 6i, 19 + 16i, 8 + 8i, }, want: []complex128{ -293 + 661i, -133 + 943i, 47 + 703i, -153 + 976i, 139 + 1260i, 297 + 885i, 92 + 502i, 285 + 581i, 301 + 383i, -45 + 192i, 19 + 266i, 48 + 188i, }, }, { incX: 7, incY: 13, alpha: 1 + 2i, x: []complex128{5 + 16i, 12 + 19i, 9 + 7i, 2 + 4i}, y: []complex128{18 + 7i, 20 + 15i, 12 + 14i}, a: []complex128{ 11 + 4i, 17 + 18i, 7 + 13i, 14 + 20i, 14 + 10i, 7 + 5i, 7 + 17i, 10 + 6i, 11 + 13i, 7 + 6i, 19 + 16i, 8 + 8i, }, want: []complex128{ -293 + 661i, -133 + 943i, 47 + 703i, -153 + 976i, 139 + 1260i, 297 + 885i, 92 + 502i, 285 + 581i, 301 + 383i, -45 + 192i, 19 + 266i, 48 + 188i, }, }, { incX: -7, incY: -13, alpha: 1 + 2i, x: []complex128{2 + 4i, 9 + 7i, 12 + 19i, 5 + 16i}, y: []complex128{12 + 14i, 20 + 15i, 18 + 7i}, a: []complex128{ 11 + 4i, 17 + 18i, 7 + 13i, 14 + 20i, 14 + 10i, 7 + 5i, 7 + 17i, 10 + 6i, 11 + 13i, 7 + 6i, 19 + 16i, 8 + 8i, }, want: []complex128{ -293 + 661i, -133 + 943i, 47 + 703i, -153 + 976i, 139 + 1260i, 297 + 885i, 92 + 502i, 285 + 581i, 301 + 383i, -45 + 192i, 19 + 266i, 48 + 188i, }, }, { incX: -7, incY: -13, alpha: 0, x: []complex128{2 + 4i, 9 + 7i, 12 + 19i, 5 + 16i}, y: []complex128{12 + 14i, 20 + 15i, 18 + 7i}, a: []complex128{ 11 + 4i, 17 + 18i, 7 + 13i, 14 + 20i, 14 + 10i, 7 + 5i, 7 + 17i, 10 + 6i, 11 + 13i, 7 + 6i, 19 + 16i, 8 + 8i, }, want: []complex128{ 11 + 4i, 17 + 18i, 7 + 13i, 14 + 20i, 14 + 10i, 7 + 5i, 7 + 17i, 10 + 6i, 11 + 13i, 7 + 6i, 19 + 16i, 8 + 8i, }, }, } { m := len(test.x) n := len(test.y) incX := test.incX incY := test.incY for _, lda := range []int{max(1, n), n + 20} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) yCopy := make([]complex128, len(y)) copy(yCopy, y) a := makeZGeneral(test.a, m, n, lda) want := makeZGeneral(test.want, m, n, lda) impl.Zgerc(m, n, test.alpha, x, incX, y, incY, a, lda) if !zsame(x, xCopy) { t.Errorf("Case %v: unexpected modification of x", tc) } if !zsame(y, yCopy) { t.Errorf("Case %v: unexpected modification of y", tc) } if !zsame(want, a) { t.Errorf("Case %v: unexpected result\nwant %v\ngot %v", tc, want, a) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zgeru.go000066400000000000000000000153651450372207100220750ustar00rootroot00000000000000// 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 testblas import ( "testing" ) type Zgeruer interface { Zgeru(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) } func ZgeruTest(t *testing.T, impl Zgeruer) { for tc, test := range []struct { alpha complex128 x []complex128 incX int y []complex128 incY int a []complex128 want []complex128 }{ { incX: 1, incY: 1, alpha: 1 + 2i, }, { incX: 1, incY: 1, alpha: 1 + 2i, x: []complex128{1 + 13i, 18 + 15i, 10 + 18i}, y: []complex128{15 + 12i, 4 + 8i, 5 + 16i, 19 + 12i}, a: []complex128{ 4 + 7i, 4 + 7i, 12 + 3i, 9 + 10i, 3 + 3i, 1 + 2i, 17 + 17i, 9 + 18i, 14 + 12i, 9 + 16i, 1 + 1i, 9 + 1i, }, want: []complex128{ -551 - 68i, -216 - 133i, -353 - 322i, -646 - 5i, -789 + 624i, -455 + 110i, -859 + 80i, -831 + 843i, -832 + 270i, -399 - 40i, -737 - 225i, -941 + 411i, }, }, { incX: 7, incY: 13, alpha: 1 + 2i, x: []complex128{1 + 13i, 18 + 15i, 10 + 18i}, y: []complex128{15 + 12i, 4 + 8i, 5 + 16i, 19 + 12i}, a: []complex128{ 4 + 7i, 4 + 7i, 12 + 3i, 9 + 10i, 3 + 3i, 1 + 2i, 17 + 17i, 9 + 18i, 14 + 12i, 9 + 16i, 1 + 1i, 9 + 1i, }, want: []complex128{ -551 - 68i, -216 - 133i, -353 - 322i, -646 - 5i, -789 + 624i, -455 + 110i, -859 + 80i, -831 + 843i, -832 + 270i, -399 - 40i, -737 - 225i, -941 + 411i, }, }, { incX: 1, incY: 13, alpha: 1 + 2i, x: []complex128{1 + 13i, 18 + 15i, 10 + 18i}, y: []complex128{15 + 12i, 4 + 8i, 5 + 16i, 19 + 12i}, a: []complex128{ 4 + 7i, 4 + 7i, 12 + 3i, 9 + 10i, 3 + 3i, 1 + 2i, 17 + 17i, 9 + 18i, 14 + 12i, 9 + 16i, 1 + 1i, 9 + 1i, }, want: []complex128{ -551 - 68i, -216 - 133i, -353 - 322i, -646 - 5i, -789 + 624i, -455 + 110i, -859 + 80i, -831 + 843i, -832 + 270i, -399 - 40i, -737 - 225i, -941 + 411i, }, }, { incX: 1, incY: -13, alpha: 1 + 2i, x: []complex128{1 + 13i, 18 + 15i, 10 + 18i}, y: []complex128{19 + 12i, 5 + 16i, 4 + 8i, 15 + 12i}, a: []complex128{ 4 + 7i, 4 + 7i, 12 + 3i, 9 + 10i, 3 + 3i, 1 + 2i, 17 + 17i, 9 + 18i, 14 + 12i, 9 + 16i, 1 + 1i, 9 + 1i, }, want: []complex128{ -551 - 68i, -216 - 133i, -353 - 322i, -646 - 5i, -789 + 624i, -455 + 110i, -859 + 80i, -831 + 843i, -832 + 270i, -399 - 40i, -737 - 225i, -941 + 411i, }, }, { incX: 7, incY: 1, alpha: 1 + 2i, x: []complex128{1 + 13i, 18 + 15i, 10 + 18i}, y: []complex128{15 + 12i, 4 + 8i, 5 + 16i, 19 + 12i}, a: []complex128{ 4 + 7i, 4 + 7i, 12 + 3i, 9 + 10i, 3 + 3i, 1 + 2i, 17 + 17i, 9 + 18i, 14 + 12i, 9 + 16i, 1 + 1i, 9 + 1i, }, want: []complex128{ -551 - 68i, -216 - 133i, -353 - 322i, -646 - 5i, -789 + 624i, -455 + 110i, -859 + 80i, -831 + 843i, -832 + 270i, -399 - 40i, -737 - 225i, -941 + 411i, }, }, { incX: -7, incY: 1, alpha: 1 + 2i, x: []complex128{10 + 18i, 18 + 15i, 1 + 13i}, y: []complex128{15 + 12i, 4 + 8i, 5 + 16i, 19 + 12i}, a: []complex128{ 4 + 7i, 4 + 7i, 12 + 3i, 9 + 10i, 3 + 3i, 1 + 2i, 17 + 17i, 9 + 18i, 14 + 12i, 9 + 16i, 1 + 1i, 9 + 1i, }, want: []complex128{ -551 - 68i, -216 - 133i, -353 - 322i, -646 - 5i, -789 + 624i, -455 + 110i, -859 + 80i, -831 + 843i, -832 + 270i, -399 - 40i, -737 - 225i, -941 + 411i, }, }, { incX: -7, incY: -13, alpha: 1 + 2i, x: []complex128{10 + 18i, 18 + 15i, 1 + 13i}, y: []complex128{19 + 12i, 5 + 16i, 4 + 8i, 15 + 12i}, a: []complex128{ 4 + 7i, 4 + 7i, 12 + 3i, 9 + 10i, 3 + 3i, 1 + 2i, 17 + 17i, 9 + 18i, 14 + 12i, 9 + 16i, 1 + 1i, 9 + 1i, }, want: []complex128{ -551 - 68i, -216 - 133i, -353 - 322i, -646 - 5i, -789 + 624i, -455 + 110i, -859 + 80i, -831 + 843i, -832 + 270i, -399 - 40i, -737 - 225i, -941 + 411i, }, }, { incX: 1, incY: 1, alpha: 1 + 2i, x: []complex128{5 + 16i, 12 + 19i, 9 + 7i, 2 + 4i}, y: []complex128{18 + 7i, 20 + 15i, 12 + 14i}, a: []complex128{ 8 + 17i, 2 + 2i, 8 + 17i, 1 + 10i, 10 + 15i, 4 + 18i, 11 + 3i, 15 + 7i, 12 + 15i, 20 + 10i, 8 + 13i, 19 + 10i, }, want: []complex128{ -660 + 296i, -928 + 117i, -680 - 49i, -768 + 602i, -1155 + 485i, -910 + 170i, -254 + 418i, -460 + 432i, -398 + 245i, -144 + 112i, -232 + 83i, -165 + 22i, }, }, { incX: 7, incY: 13, alpha: 1 + 2i, x: []complex128{5 + 16i, 12 + 19i, 9 + 7i, 2 + 4i}, y: []complex128{18 + 7i, 20 + 15i, 12 + 14i}, a: []complex128{ 8 + 17i, 2 + 2i, 8 + 17i, 1 + 10i, 10 + 15i, 4 + 18i, 11 + 3i, 15 + 7i, 12 + 15i, 20 + 10i, 8 + 13i, 19 + 10i, }, want: []complex128{ -660 + 296i, -928 + 117i, -680 - 49i, -768 + 602i, -1155 + 485i, -910 + 170i, -254 + 418i, -460 + 432i, -398 + 245i, -144 + 112i, -232 + 83i, -165 + 22i, }, }, { incX: -7, incY: -13, alpha: 1 + 2i, x: []complex128{2 + 4i, 9 + 7i, 12 + 19i, 5 + 16i}, y: []complex128{12 + 14i, 20 + 15i, 18 + 7i}, a: []complex128{ 8 + 17i, 2 + 2i, 8 + 17i, 1 + 10i, 10 + 15i, 4 + 18i, 11 + 3i, 15 + 7i, 12 + 15i, 20 + 10i, 8 + 13i, 19 + 10i, }, want: []complex128{ -660 + 296i, -928 + 117i, -680 - 49i, -768 + 602i, -1155 + 485i, -910 + 170i, -254 + 418i, -460 + 432i, -398 + 245i, -144 + 112i, -232 + 83i, -165 + 22i, }, }, { incX: -7, incY: -13, alpha: 0, x: []complex128{5 + 16i, 12 + 19i, 9 + 7i, 2 + 4i}, y: []complex128{18 + 7i, 20 + 15i, 12 + 14i}, a: []complex128{ 8 + 17i, 2 + 2i, 8 + 17i, 1 + 10i, 10 + 15i, 4 + 18i, 11 + 3i, 15 + 7i, 12 + 15i, 20 + 10i, 8 + 13i, 19 + 10i, }, want: []complex128{ 8 + 17i, 2 + 2i, 8 + 17i, 1 + 10i, 10 + 15i, 4 + 18i, 11 + 3i, 15 + 7i, 12 + 15i, 20 + 10i, 8 + 13i, 19 + 10i, }, }, } { m := len(test.x) n := len(test.y) incX := test.incX incY := test.incY for _, lda := range []int{max(1, n), n + 20} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) yCopy := make([]complex128, len(y)) copy(yCopy, y) a := makeZGeneral(test.a, m, n, lda) want := makeZGeneral(test.want, m, n, lda) impl.Zgeru(m, n, test.alpha, x, incX, y, incY, a, lda) if !zsame(x, xCopy) { t.Errorf("Case %v: unexpected modification of x", tc) } if !zsame(y, yCopy) { t.Errorf("Case %v: unexpected modification of y", tc) } if !zsame(want, a) { t.Errorf("Case %v: unexpected result\nwant %v\ngot %v", tc, want, a) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zhbmv.go000066400000000000000000000100571450372207100220600ustar00rootroot00000000000000// 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 testblas import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zhbmver interface { Zhbmv(uplo blas.Uplo, n, k int, alpha complex128, ab []complex128, ldab int, x []complex128, incX int, beta complex128, y []complex128, incY int) Zhemver } func ZhbmvTest(t *testing.T, impl Zhbmver) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, n := range []int{0, 1, 2, 3, 5} { for k := 0; k < n; k++ { for _, ldab := range []int{k + 1, k + 1 + 10} { // Generate all possible combinations of given increments. // Use slices to reduce indentation. for _, inc := range allPairs([]int{-11, 1, 7}, []int{-3, 1, 5}) { incX := inc[0] incY := inc[1] for _, ab := range []struct { alpha complex128 beta complex128 }{ // All potentially relevant values of // alpha and beta. {0, 0}, {0, 1}, {0, complex(rnd.NormFloat64(), rnd.NormFloat64())}, {complex(rnd.NormFloat64(), rnd.NormFloat64()), 0}, {complex(rnd.NormFloat64(), rnd.NormFloat64()), 1}, {complex(rnd.NormFloat64(), rnd.NormFloat64()), complex(rnd.NormFloat64(), rnd.NormFloat64())}, } { testZhbmv(t, impl, rnd, uplo, n, k, ab.alpha, ab.beta, ldab, incX, incY) } } } } } } } // testZhbmv tests Zhbmv by comparing its output to that of Zhemv. func testZhbmv(t *testing.T, impl Zhbmver, rnd *rand.Rand, uplo blas.Uplo, n, k int, alpha, beta complex128, ldab, incX, incY int) { const tol = 1e-13 // Allocate a dense-storage Hermitian band matrix filled with NaNs that will be // used as the reference matrix for Zhemv. lda := max(1, n) a := makeZGeneral(nil, n, n, lda) // Fill the matrix with zeros. for i := 0; i < n; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 } } // Fill the triangle band with random data, invalidating the imaginary // part of diagonal elements because it should not be referenced by // Zhbmv and Zhemv. if uplo == blas.Upper { for i := 0; i < n; i++ { a[i*lda+i] = complex(rnd.NormFloat64(), math.NaN()) for j := i + 1; j < min(n, i+k+1); j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } } else { for i := 0; i < n; i++ { for j := max(0, i-k); j < i; j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } a[i*lda+i] = complex(rnd.NormFloat64(), math.NaN()) } } // Create the actual Hermitian band matrix. ab := zPackTriBand(k, ldab, uplo, n, a, lda) abCopy := make([]complex128, len(ab)) copy(abCopy, ab) // Generate a random complex vector x. xtest := make([]complex128, n) for i := range xtest { re := rnd.NormFloat64() im := rnd.NormFloat64() xtest[i] = complex(re, im) } x := makeZVector(xtest, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) // Generate a random complex vector y. ytest := make([]complex128, n) for i := range ytest { re := rnd.NormFloat64() im := rnd.NormFloat64() ytest[i] = complex(re, im) } y := makeZVector(ytest, incY) want := make([]complex128, len(y)) copy(want, y) // Compute the reference result of alpha*op(A)*x + beta*y, storing it // into want. impl.Zhemv(uplo, n, alpha, a, lda, x, incX, beta, want, incY) // Compute alpha*op(A)*x + beta*y, storing the result in-place into y. impl.Zhbmv(uplo, n, k, alpha, ab, ldab, x, incX, beta, y, incY) prefix := fmt.Sprintf("uplo=%v,n=%v,k=%v,incX=%v,incY=%v,ldab=%v", uplo, n, k, incX, incY, ldab) if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x", prefix) } if !zsame(ab, abCopy) { t.Errorf("%v: unexpected modification of ab", prefix) } if !zSameAtNonstrided(y, want, incY) { t.Errorf("%v: unexpected modification of y", prefix) } if !zEqualApproxAtStrided(y, want, incY, tol) { t.Errorf("%v: unexpected result\nwant %v\ngot %v", prefix, want, y) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zhemm.go000066400000000000000000000101141450372207100220440ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zhemmer interface { Zhemm(side blas.Side, uplo blas.Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) } func ZhemmTest(t *testing.T, impl Zhemmer) { for _, side := range []blas.Side{blas.Left, blas.Right} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { name := sideString(side) + "-" + uploString(uplo) t.Run(name, func(t *testing.T) { for _, m := range []int{0, 1, 2, 3, 4, 5} { for _, n := range []int{0, 1, 2, 3, 4, 5} { zhemmTest(t, impl, side, uplo, m, n) } } }) } } } func zhemmTest(t *testing.T, impl Zhemmer, side blas.Side, uplo blas.Uplo, m, n int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) nA := m if side == blas.Right { nA = n } for _, lda := range []int{max(1, nA), nA + 2} { for _, ldb := range []int{max(1, n), n + 3} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { for _, beta := range []complex128{0, 1, complex(1.3, -1.1)} { for _, nanC := range []bool{false, true} { if nanC && beta != 0 { // Skip tests with C containing NaN values // unless beta would zero out the NaNs. continue } // Allocate the matrix A and fill it with random numbers. a := make([]complex128, nA*lda) for i := range a { a[i] = rndComplex128(rnd) } // Create a copy of A for checking that // Zhemm does not modify its triangle // opposite to uplo. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Create a copy of A expanded into a // full hermitian matrix for computing // the expected result using zmm. aHem := make([]complex128, len(a)) copy(aHem, a) if uplo == blas.Upper { for i := 0; i < nA; i++ { aHem[i*lda+i] = complex(real(aHem[i*lda+i]), 0) for j := i + 1; j < nA; j++ { aHem[j*lda+i] = cmplx.Conj(aHem[i*lda+j]) } } } else { for i := 0; i < nA; i++ { for j := 0; j < i; j++ { aHem[j*lda+i] = cmplx.Conj(aHem[i*lda+j]) } aHem[i*lda+i] = complex(real(aHem[i*lda+i]), 0) } } // Allocate the matrix B and fill it with random numbers. b := make([]complex128, m*ldb) for i := range b { b[i] = rndComplex128(rnd) } // Create a copy of B for checking that // Zhemm does not modify B. bCopy := make([]complex128, len(b)) copy(bCopy, b) // Allocate the matrix C and fill it with random numbers. c := make([]complex128, m*ldc) for i := range c { c[i] = rndComplex128(rnd) } if nanC { for i := 0; i < n; i++ { for j := 0; j < m; j++ { c[i+j*ldc] = cmplx.NaN() } } } // Compute the expected result using an internal Zgemm implementation. var want []complex128 if side == blas.Left { want = zmm(blas.NoTrans, blas.NoTrans, m, n, m, alpha, aHem, lda, b, ldb, beta, c, ldc) } else { want = zmm(blas.NoTrans, blas.NoTrans, m, n, n, alpha, b, ldb, aHem, lda, beta, c, ldc) } // Compute the result using Zhemm. impl.Zhemm(side, uplo, m, n, alpha, a, lda, b, ldb, beta, c, ldc) prefix := fmt.Sprintf("m=%v,n=%v,lda=%v,ldb=%v,ldc=%v,alpha=%v,beta=%v", m, n, lda, ldb, ldc, alpha, beta) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if !zsame(b, bCopy) { t.Errorf("%v: unexpected modification of B", prefix) continue } if !zEqualApprox(c, want, tol) { t.Errorf("%v: unexpected result", prefix) } } } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zhemv.go000066400000000000000000000115361450372207100220660ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) var zhemvTestCases = []struct { uplo blas.Uplo alpha complex128 a []complex128 x []complex128 beta complex128 y []complex128 want []complex128 wantXNeg []complex128 wantYNeg []complex128 wantXYNeg []complex128 }{ { uplo: blas.Upper, alpha: 6 + 2i, beta: -6 - 7i, }, { uplo: blas.Lower, alpha: 6 + 2i, beta: -6 - 7i, }, { uplo: blas.Upper, alpha: 6 + 2i, a: []complex128{ 7, 8 + 4i, -9 - 6i, -9 + 3i, znan, -3, -10 - 6i, 0 + 3i, znan, znan, 6, 2 + 8i, znan, znan, znan, -4, }, x: []complex128{ -4 + 0i, -2 - 5i, 8 + 0i, 6 - 1i, }, beta: -6 - 7i, y: []complex128{ 1 - 5i, -2 - 5i, 0 - 4i, 7 + 7i, }, want: []complex128{ -785 - 685i, -643 - 156i, 776 + 692i, 169 - 317i, }, wantXNeg: []complex128{ 599 + 703i, 1 + 172i, -978 - 86i, -449 - 423i, }, wantYNeg: []complex128{ 121 - 203i, 781 + 712i, -648 - 176i, -737 - 799i, }, wantXYNeg: []complex128{ -497 - 309i, -973 - 66i, -4 + 152i, 647 + 589i, }, }, { uplo: blas.Lower, alpha: 6 + 2i, a: []complex128{ 7, znan, znan, znan, 8 - 4i, -3, znan, znan, -9 + 6i, -10 + 6i, 6, znan, -9 - 3i, 0 - 3i, 2 - 8i, -4, }, x: []complex128{ -4 + 0i, -2 - 5i, 8 + 0i, 6 - 1i, }, beta: -6 - 7i, y: []complex128{ 1 - 5i, -2 - 5i, 0 - 4i, 7 + 7i, }, want: []complex128{ -785 - 685i, -643 - 156i, 776 + 692i, 169 - 317i, }, wantXNeg: []complex128{ 599 + 703i, 1 + 172i, -978 - 86i, -449 - 423i, }, wantYNeg: []complex128{ 121 - 203i, 781 + 712i, -648 - 176i, -737 - 799i, }, wantXYNeg: []complex128{ -497 - 309i, -973 - 66i, -4 + 152i, 647 + 589i, }, }, { uplo: blas.Upper, alpha: 0, a: []complex128{ 7, 8 + 4i, -9 - 6i, -9 + 3i, znan, -3, -10 - 6i, 0 + 3i, znan, znan, 6, 2 + 8i, znan, znan, znan, -4, }, x: []complex128{ -4 + 0i, -2 - 5i, 8 + 0i, 6 - 1i, }, beta: -6 - 7i, y: []complex128{ 1 - 5i, -2 - 5i, 0 - 4i, 7 + 7i, }, want: []complex128{ -41 + 23i, -23 + 44i, -28 + 24i, 7 - 91i, }, wantXNeg: []complex128{ -41 + 23i, -23 + 44i, -28 + 24i, 7 - 91i, }, wantYNeg: []complex128{ -41 + 23i, -23 + 44i, -28 + 24i, 7 - 91i, }, wantXYNeg: []complex128{ -41 + 23i, -23 + 44i, -28 + 24i, 7 - 91i, }, }, { uplo: blas.Upper, alpha: 6 + 2i, a: []complex128{ 7, 8 + 4i, -9 - 6i, -9 + 3i, znan, -3, -10 - 6i, 0 + 3i, znan, znan, 6, 2 + 8i, znan, znan, znan, -4, }, x: []complex128{ -4 + 0i, -2 - 5i, 8 + 0i, 6 - 1i, }, beta: 0, y: []complex128{ 1 - 5i, -2 - 5i, 0 - 4i, 7 + 7i, }, want: []complex128{ -744 - 708i, -620 - 200i, 804 + 668i, 162 - 226i, }, wantXNeg: []complex128{ 640 + 680i, 24 + 128i, -950 - 110i, -456 - 332i, }, wantYNeg: []complex128{ 162 - 226i, 804 + 668i, -620 - 200i, -744 - 708i, }, wantXYNeg: []complex128{ -456 - 332i, -950 - 110i, 24 + 128i, 640 + 680i, }, }, } type Zhemver interface { Zhemv(uplo blas.Uplo, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int) } func ZhemvTest(t *testing.T, impl Zhemver) { for tc, test := range zhemvTestCases { n := len(test.x) for _, incX := range []int{-11, -2, -1, 1, 2, 7} { for _, incY := range []int{-11, -2, -1, 1, 2, 7} { for _, lda := range []int{max(1, n), n + 11} { alpha := test.alpha beta := test.beta a := makeZGeneral(test.a, n, n, lda) aCopy := make([]complex128, len(a)) copy(aCopy, a) x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) impl.Zhemv(test.uplo, n, alpha, a, lda, x, incX, beta, y, incY) if !zsame(x, xCopy) { t.Errorf("Case %v (incX=%v,incY=%v,lda=%v): unexpected modification of x", tc, incX, incY, lda) } if !zsame(a, aCopy) { t.Errorf("Case %v (incX=%v,incY=%v,lda=%v): unexpected modification of A", tc, incX, incY, lda) } var want []complex128 switch { case incX > 0 && incY > 0: want = makeZVector(test.want, incY) case incX < 0 && incY > 0: want = makeZVector(test.wantXNeg, incY) case incX > 0 && incY < 0: want = makeZVector(test.wantYNeg, incY) default: want = makeZVector(test.wantXYNeg, incY) } if !zsame(y, want) { t.Errorf("Case %v (incX=%v,incY=%v,lda=%v): unexpected result\nwant %v\ngot %v", tc, incX, incY, lda, want, y) } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zher.go000066400000000000000000000070011450372207100216750ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) var zherTestCases = []struct { alpha float64 x []complex128 a []complex128 want []complex128 wantRev []complex128 // Result when incX is negative. }{ { alpha: 1, }, { alpha: 3, x: []complex128{ 0 - 3i, 6 + 10i, -2 - 7i, }, a: []complex128{ -2 + 3i, -3 - 11i, 0 + 4i, -3 + 11i, -6 + 3i, 7 + 2i, 0 - 4i, 7 - 2i, 18 + 3i, }, want: []complex128{ 25 + 0i, -93 - 65i, 63 + 22i, -93 + 65i, 402 + 0i, -239 + 68i, 63 - 22i, -239 - 68i, 177 + 0i}, wantRev: []complex128{ 157 + 0i, -249 - 77i, 63 - 14i, -249 + 77i, 402 + 0i, -83 + 56i, 63 + 14i, -83 - 56i, 45 + 0i, }, }, { alpha: 3, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, a: []complex128{ 2 + 3i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 3i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 3i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 3i, }, want: []complex128{ 122 + 0i, 3 - 77i, 3 + 11i, 52 + 125i, 3 + 77i, 76 + 0i, -5 + 2i, -91 + 37i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 52 - 125i, -91 - 37i, 2 + 1i, 165 + 0i, }, wantRev: []complex128{ 149 + 0i, -9 + 7i, -81 - 31i, 52 - 127i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, -81 + 31i, -5 - 2i, 74 + 0i, 14 + 83i, 52 + 127i, -7 + 5i, 14 - 83i, 138 + 0i, }, }, { alpha: 0, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, wantRev: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, }, } type Zherer interface { Zher(uplo blas.Uplo, n int, alpha float64, x []complex128, incX int, a []complex128, lda int) } func ZherTest(t *testing.T, impl Zherer) { for tc, test := range zherTestCases { n := len(test.x) for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, incX := range []int{-11, -2, -1, 1, 2, 7} { for _, lda := range []int{max(1, n), n + 11} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) a := makeZGeneral(test.a, n, n, lda) var want []complex128 if incX > 0 { want = makeZGeneral(test.want, n, n, lda) } else { want = makeZGeneral(test.wantRev, n, n, lda) } if uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = znan want[i*lda+j] = znan } } } else { for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { a[i*lda+j] = znan want[i*lda+j] = znan } } } impl.Zher(uplo, n, test.alpha, x, incX, a, lda) if !zsame(x, xCopy) { t.Errorf("Case %v (uplo=%v,incX=%v,lda=%v,alpha=%v): unexpected modification of x", tc, uplo, incX, test.alpha, lda) } if !zsame(want, a) { t.Errorf("Case %v (uplo=%v,incX=%v,lda=%v,alpha=%v): unexpected result\nwant: %v\ngot: %v", tc, uplo, incX, lda, test.alpha, want, a) } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zher2.go000066400000000000000000000145221450372207100217650ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) var zher2TestCases = []struct { alpha complex128 incX, incY int x []complex128 y []complex128 a []complex128 want []complex128 }{ { alpha: 1 + 2i, incX: 1, incY: 1, }, { alpha: 1 + 2i, incX: 1, incY: 1, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, y: []complex128{ 2 - 5i, 0 + 0i, -8 - 9i, 6 + 6i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 62 + 0i, 43 - 7i, 173 + 1i, -173 + 55i, 43 + 7i, 16 + 0i, 19 + 120i, -19 - 89i, 173 - 1i, 19 - 120i, 14 + 0i, 51 + 181i, -173 - 55i, -19 + 89i, 51 - 181i, -66 + 0i, }, }, { alpha: 1 + 2i, incX: 1, incY: 1, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, y: []complex128{ 2 - 5i, -8 - 9i, 0 + 0i, 6 + 6i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 62 + 0i, 213 - 17i, 3 + 11i, -173 + 55i, 213 + 17i, 64 + 0i, -5 + 2i, 30 + 93i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, -173 - 55i, 30 - 93i, 2 + 1i, -66 + 0i, }, }, { alpha: 1 + 2i, incX: 2, incY: 4, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, y: []complex128{ 2 - 5i, -8 - 9i, 0 + 0i, 6 + 6i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 62 + 0i, 213 - 17i, 3 + 11i, -173 + 55i, 213 + 17i, 64 + 0i, -5 + 2i, 30 + 93i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, -173 - 55i, 30 - 93i, 2 + 1i, -66 + 0i, }, }, { alpha: 1 + 2i, incX: 3, incY: 7, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, y: []complex128{ 2 - 5i, 0 + 0i, -8 - 9i, 6 + 6i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 62 + 0i, 43 - 7i, 173 + 1i, -173 + 55i, 43 + 7i, 16 + 0i, 19 + 120i, -19 - 89i, 173 - 1i, 19 - 120i, 14 + 0i, 51 + 181i, -173 - 55i, -19 + 89i, 51 - 181i, -66 + 0i, }, }, { alpha: 1 + 2i, incX: -3, incY: 7, x: []complex128{ 0 + 7i, 0 + 0i, -2 - 4i, -6 + 2i, }, y: []complex128{ 2 - 5i, 0 + 0i, -8 - 9i, 6 + 6i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 62 + 0i, 43 - 7i, 173 + 1i, -173 + 55i, 43 + 7i, 16 + 0i, 19 + 120i, -19 - 89i, 173 - 1i, 19 - 120i, 14 + 0i, 51 + 181i, -173 - 55i, -19 + 89i, 51 - 181i, -66 + 0i, }, }, { alpha: 1 + 2i, incX: 3, incY: -7, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, y: []complex128{ 6 + 6i, -8 - 9i, 0 + 0i, 2 - 5i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 62 + 0i, 43 - 7i, 173 + 1i, -173 + 55i, 43 + 7i, 16 + 0i, 19 + 120i, -19 - 89i, 173 - 1i, 19 - 120i, 14 + 0i, 51 + 181i, -173 - 55i, -19 + 89i, 51 - 181i, -66 + 0i, }, }, { alpha: 1 + 2i, incX: -3, incY: -7, x: []complex128{ 0 + 7i, 0 + 0i, -2 - 4i, -6 + 2i, }, y: []complex128{ 6 + 6i, -8 - 9i, 0 + 0i, 2 - 5i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 62 + 0i, 43 - 7i, 173 + 1i, -173 + 55i, 43 + 7i, 16 + 0i, 19 + 120i, -19 - 89i, 173 - 1i, 19 - 120i, 14 + 0i, 51 + 181i, -173 - 55i, -19 + 89i, 51 - 181i, -66 + 0i, }, }, { alpha: 0, incX: 1, incY: 1, x: []complex128{ -6 + 2i, -2 - 4i, 0 + 0i, 0 + 7i, }, y: []complex128{ 2 - 5i, 0 + 0i, -8 - 9i, 6 + 6i, }, a: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, want: []complex128{ 2 + 0i, -9 + 7i, 3 + 11i, 10 - 1i, -9 - 7i, 16 + 0i, -5 + 2i, -7 - 5i, 3 - 11i, -5 - 2i, 14 + 0i, 2 - 1i, 10 + 1i, -7 + 5i, 2 + 1i, 18 + 0i, }, }, } type Zher2er interface { Zher2(uplo blas.Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int) } func Zher2Test(t *testing.T, impl Zher2er) { for tc, test := range zher2TestCases { n := len(test.x) incX := test.incX incY := test.incY for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, lda := range []int{max(1, n), n + 11} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) yCopy := make([]complex128, len(y)) copy(yCopy, y) a := makeZGeneral(test.a, n, n, lda) want := makeZGeneral(test.want, n, n, lda) if uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = znan want[i*lda+j] = znan } } } else { for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { a[i*lda+j] = znan want[i*lda+j] = znan } } } impl.Zher2(uplo, n, test.alpha, x, incX, y, incY, a, lda) if !zsame(x, xCopy) { t.Errorf("Case %v (uplo=%v,incX=%v,incY=%v,lda=%v: unexpected modification of x", tc, uplo, incX, incY, lda) } if !zsame(y, yCopy) { t.Errorf("Case %v (uplo=%v,incX=%v,incY=%v,lda=%v: unexpected modification of y", tc, uplo, incX, incY, lda) } if !zsame(want, a) { t.Errorf("Case %v (uplo=%v,incX=%v,incY=%v,lda=%v: unexpected result\nwant: %v\ngot: %v", tc, uplo, incX, incY, lda, want, a) } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zher2k.go000066400000000000000000000130071450372207100221350ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zher2ker interface { Zher2k(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta float64, c []complex128, ldc int) } func Zher2kTest(t *testing.T, impl Zher2ker) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.ConjTrans} { name := uploString(uplo) + "-" + transString(trans) t.Run(name, func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5} { for _, k := range []int{0, 1, 2, 3, 4, 5, 7} { zher2kTest(t, impl, uplo, trans, n, k) } } }) } } } func zher2kTest(t *testing.T, impl Zher2ker, uplo blas.Uplo, trans blas.Transpose, n, k int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) row, col := n, k if trans == blas.ConjTrans { row, col = k, n } for _, lda := range []int{max(1, col), col + 2} { for _, ldb := range []int{max(1, col), col + 3} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { for _, beta := range []float64{0, 1, 1.3} { // Allocate the matrix A and fill it with random numbers. a := make([]complex128, row*lda) for i := range a { a[i] = rndComplex128(rnd) } // Create a copy of A for checking that // Zher2k does not modify A. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Allocate the matrix B and fill it with random numbers. b := make([]complex128, row*ldb) for i := range b { b[i] = rndComplex128(rnd) } // Create a copy of B for checking that // Zher2k does not modify B. bCopy := make([]complex128, len(b)) copy(bCopy, b) // Allocate the matrix C and fill it with random numbers. c := make([]complex128, n*ldc) for i := range c { c[i] = rndComplex128(rnd) } if (alpha == 0 || k == 0) && beta == 1 { // In case of a quick return // zero out the diagonal. for i := 0; i < n; i++ { c[i*ldc+i] = complex(real(c[i*ldc+i]), 0) } } // Create a copy of C for checking that // Zher2k does not modify its triangle // opposite to uplo. cCopy := make([]complex128, len(c)) copy(cCopy, c) // Create a copy of C expanded into a // full hermitian matrix for computing // the expected result using zmm. cHer := make([]complex128, len(c)) copy(cHer, c) if uplo == blas.Upper { for i := 0; i < n; i++ { cHer[i*ldc+i] = complex(real(cHer[i*ldc+i]), 0) for j := i + 1; j < n; j++ { cHer[j*ldc+i] = cmplx.Conj(cHer[i*ldc+j]) } } } else { for i := 0; i < n; i++ { for j := 0; j < i; j++ { cHer[j*ldc+i] = cmplx.Conj(cHer[i*ldc+j]) } cHer[i*ldc+i] = complex(real(cHer[i*ldc+i]), 0) } } // Compute the expected result using an internal Zgemm implementation. var want []complex128 if trans == blas.NoTrans { // C = alpha*A*Bᴴ + conj(alpha)*B*Aᴴ + beta*C tmp := zmm(blas.NoTrans, blas.ConjTrans, n, n, k, alpha, a, lda, b, ldb, complex(beta, 0), cHer, ldc) want = zmm(blas.NoTrans, blas.ConjTrans, n, n, k, cmplx.Conj(alpha), b, ldb, a, lda, 1, tmp, ldc) } else { // C = alpha*Aᴴ*B + conj(alpha)*Bᴴ*A + beta*C tmp := zmm(blas.ConjTrans, blas.NoTrans, n, n, k, alpha, a, lda, b, ldb, complex(beta, 0), cHer, ldc) want = zmm(blas.ConjTrans, blas.NoTrans, n, n, k, cmplx.Conj(alpha), b, ldb, a, lda, 1, tmp, ldc) } // Compute the result using Zher2k. impl.Zher2k(uplo, trans, n, k, alpha, a, lda, b, ldb, beta, c, ldc) prefix := fmt.Sprintf("n=%v,k=%v,lda=%v,ldb=%v,ldc=%v,alpha=%v,beta=%v", n, k, lda, ldb, ldc, alpha, beta) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if !zsame(b, bCopy) { t.Errorf("%v: unexpected modification of B", prefix) continue } if uplo == blas.Upper && !zSameLowerTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in lower triangle of C", prefix) continue } if uplo == blas.Lower && !zSameUpperTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in upper triangle of C", prefix) continue } // Check that the diagonal of C has only real elements. hasRealDiag := true for i := 0; i < n; i++ { if imag(c[i*ldc+i]) != 0 { hasRealDiag = false break } } if !hasRealDiag { t.Errorf("%v: diagonal of C has imaginary elements\ngot=%v", prefix, c) continue } // Expand C into a full hermitian matrix // for comparison with the result from zmm. if uplo == blas.Upper { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { c[j*ldc+i] = cmplx.Conj(c[i*ldc+j]) } } } else { for i := 1; i < n; i++ { for j := 0; j < i; j++ { c[j*ldc+i] = cmplx.Conj(c[i*ldc+j]) } } } if !zEqualApprox(c, want, tol) { t.Errorf("%v: unexpected result\nwant=%v\ngot= %v", prefix, want, c) } } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zherk.go000066400000000000000000000111121450372207100220460ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zherker interface { Zherk(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha float64, a []complex128, lda int, beta float64, c []complex128, ldc int) } func ZherkTest(t *testing.T, impl Zherker) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.ConjTrans} { name := uploString(uplo) + "-" + transString(trans) t.Run(name, func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5} { for _, k := range []int{0, 1, 2, 3, 4, 5, 7} { zherkTest(t, impl, uplo, trans, n, k) } } }) } } } func zherkTest(t *testing.T, impl Zherker, uplo blas.Uplo, trans blas.Transpose, n, k int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) rowA, colA := n, k if trans == blas.ConjTrans { rowA, colA = k, n } for _, lda := range []int{max(1, colA), colA + 2} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []float64{0, 1, 0.7} { for _, beta := range []float64{0, 1, 1.3} { // Allocate the matrix A and fill it with random numbers. a := make([]complex128, rowA*lda) for i := range a { a[i] = rndComplex128(rnd) } // Create a copy of A for checking that // Zherk does not modify A. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Allocate the matrix C and fill it with random numbers. c := make([]complex128, n*ldc) for i := range c { c[i] = rndComplex128(rnd) } if (alpha == 0 || k == 0) && beta == 1 { // In case of a quick return // zero out the diagonal. for i := 0; i < n; i++ { c[i*ldc+i] = complex(real(c[i*ldc+i]), 0) } } // Create a copy of C for checking that // Zherk does not modify its triangle // opposite to uplo. cCopy := make([]complex128, len(c)) copy(cCopy, c) // Create a copy of C expanded into a // full hermitian matrix for computing // the expected result using zmm. cHer := make([]complex128, len(c)) copy(cHer, c) if uplo == blas.Upper { for i := 0; i < n; i++ { cHer[i*ldc+i] = complex(real(cHer[i*ldc+i]), 0) for j := i + 1; j < n; j++ { cHer[j*ldc+i] = cmplx.Conj(cHer[i*ldc+j]) } } } else { for i := 0; i < n; i++ { for j := 0; j < i; j++ { cHer[j*ldc+i] = cmplx.Conj(cHer[i*ldc+j]) } cHer[i*ldc+i] = complex(real(cHer[i*ldc+i]), 0) } } // Compute the expected result using an internal Zgemm implementation. var want []complex128 if trans == blas.NoTrans { want = zmm(blas.NoTrans, blas.ConjTrans, n, n, k, complex(alpha, 0), a, lda, a, lda, complex(beta, 0), cHer, ldc) } else { want = zmm(blas.ConjTrans, blas.NoTrans, n, n, k, complex(alpha, 0), a, lda, a, lda, complex(beta, 0), cHer, ldc) } // Compute the result using Zherk. impl.Zherk(uplo, trans, n, k, alpha, a, lda, beta, c, ldc) prefix := fmt.Sprintf("n=%v,k=%v,lda=%v,ldc=%v,alpha=%v,beta=%v", n, k, lda, ldc, alpha, beta) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if uplo == blas.Upper && !zSameLowerTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in lower triangle of C", prefix) continue } if uplo == blas.Lower && !zSameUpperTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in upper triangle of C", prefix) continue } // Check that the diagonal of C has only real elements. hasRealDiag := true for i := 0; i < n; i++ { if imag(c[i*ldc+i]) != 0 { hasRealDiag = false break } } if !hasRealDiag { t.Errorf("%v: diagonal of C has imaginary elements\ngot=%v", prefix, c) continue } // Expand C into a full hermitian matrix // for comparison with the result from zmm. if uplo == blas.Upper { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { c[j*ldc+i] = cmplx.Conj(c[i*ldc+j]) } } } else { for i := 1; i < n; i++ { for j := 0; j < i; j++ { c[j*ldc+i] = cmplx.Conj(c[i*ldc+j]) } } } if !zEqualApprox(c, want, tol) { t.Errorf("%v: unexpected result\nwant=%v\ngot= %v", prefix, want, c) } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zhpmv.go000066400000000000000000000032301450372207100220710ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Zhpmver interface { Zhpmv(uplo blas.Uplo, n int, alpha complex128, ap []complex128, x []complex128, incX int, beta complex128, y []complex128, incY int) } func ZhpmvTest(t *testing.T, impl Zhpmver) { for tc, test := range zhemvTestCases { uplo := test.uplo n := len(test.x) alpha := test.alpha beta := test.beta for _, incX := range []int{-11, -2, -1, 1, 2, 7} { for _, incY := range []int{-11, -2, -1, 1, 2, 7} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) ap := zPack(uplo, n, test.a, n) apCopy := make([]complex128, len(ap)) copy(apCopy, ap) impl.Zhpmv(test.uplo, n, alpha, ap, x, incX, beta, y, incY) if !zsame(x, xCopy) { t.Errorf("Case %v (incX=%v,incY=%v): unexpected modification of x", tc, incX, incY) } if !zsame(ap, apCopy) { t.Errorf("Case %v (incX=%v,incY=%v): unexpected modification of A", tc, incX, incY) } var want []complex128 switch { case incX > 0 && incY > 0: want = makeZVector(test.want, incY) case incX < 0 && incY > 0: want = makeZVector(test.wantXNeg, incY) case incX > 0 && incY < 0: want = makeZVector(test.wantYNeg, incY) default: want = makeZVector(test.wantXYNeg, incY) } if !zsame(y, want) { t.Errorf("Case %v (incX=%v,incY=%v): unexpected result\nwant %v\ngot %v", tc, incX, incY, want, y) } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zhpr.go000066400000000000000000000023711450372207100217150ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Zhprer interface { Zhpr(uplo blas.Uplo, n int, alpha float64, x []complex128, incX int, ap []complex128) } func ZhprTest(t *testing.T, impl Zhprer) { for tc, test := range zherTestCases { n := len(test.x) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, incX := range []int{-11, -2, -1, 1, 2, 7} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) ap := zPack(uplo, n, test.a, n) impl.Zhpr(uplo, n, test.alpha, x, incX, ap) a := zUnpackAsHermitian(uplo, n, ap) var want []complex128 if incX > 0 { want = makeZGeneral(test.want, n, n, max(1, n)) } else { want = makeZGeneral(test.wantRev, n, n, max(1, n)) } if !zsame(x, xCopy) { t.Errorf("Case %v (uplo=%v,incX=%v,alpha=%v): unexpected modification of x", tc, uplo, incX, test.alpha) } if !zsame(want, a) { t.Errorf("Case %v (uplo=%v,incX=%v,alpha=%v): unexpected result\nwant: %v\ngot: %v", tc, uplo, incX, test.alpha, want, a) } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zhpr2.go000066400000000000000000000024651450372207100220030ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Zhpr2er interface { Zhpr2(uplo blas.Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, ap []complex128) } func Zhpr2Test(t *testing.T, impl Zhpr2er) { for tc, test := range zher2TestCases { n := len(test.x) incX := test.incX incY := test.incY for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) y := makeZVector(test.y, incY) yCopy := make([]complex128, len(y)) copy(yCopy, y) ap := zPack(uplo, n, test.a, n) impl.Zhpr2(uplo, n, test.alpha, x, incX, y, incY, ap) a := zUnpackAsHermitian(uplo, n, ap) if !zsame(x, xCopy) { t.Errorf("Case %v (uplo=%v,incX=%v,incY=%v): unexpected modification of x", tc, uplo, incX, incY) } if !zsame(y, yCopy) { t.Errorf("Case %v (uplo=%v,incX=%v,incY=%v): unexpected modification of y", tc, uplo, incX, incY) } if !zsame(test.want, a) { t.Errorf("Case %v (uplo=%v,incX=%v,incY=%v): unexpected result\nwant: %v\ngot: %v", tc, uplo, incX, incY, test.want, a) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zscal.go000066400000000000000000000073131450372207100220470ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" ) type Zscaler interface { Zscal(n int, alpha complex128, x []complex128, incX int) } func ZscalTest(t *testing.T, impl Zscaler) { for tc, test := range []struct { alpha complex128 x []complex128 want []complex128 }{ { alpha: 2 + 5i, x: nil, want: nil, }, { alpha: 2 + 5i, x: []complex128{1 + 2i}, want: []complex128{-8 + 9i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i}, want: []complex128{-8 + 9i, -14 + 23i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i, -38 + 79i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i, -38 + 79i, -44 + 93i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i, -38 + 79i, -44 + 93i, -50 + 107i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i, -38 + 79i, -44 + 93i, -50 + 107i, -56 + 121i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i, -38 + 79i, -44 + 93i, -50 + 107i, -56 + 121i, -62 + 135i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i, -38 + 79i, -44 + 93i, -50 + 107i, -56 + 121i, -62 + 135i, -68 + 149i}, }, { alpha: 2 + 5i, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, want: []complex128{-8 + 9i, -14 + 23i, -20 + 37i, -26 + 51i, -32 + 65i, -38 + 79i, -44 + 93i, -50 + 107i, -56 + 121i, -62 + 135i, -68 + 149i, -74 + 163i}, }, { alpha: 0, x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i, 21 + 22i, 23 + 24i}, want: []complex128{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, } { n := len(test.x) if len(test.want) != n { panic("bad test") } for _, incX := range []int{-3, -1, 1, 2, 4, 7, 10} { x := makeZVector(test.x, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) want := makeZVector(test.want, incX) impl.Zscal(n, test.alpha, x, incX) prefix := fmt.Sprintf("Case %v (n=%v,incX=%v):", tc, n, incX) if incX < 0 { if !zsame(x, xCopy) { t.Errorf("%v: unexpected modification of x\nwant %v\ngot %v", prefix, want, x) } continue } if !zsame(x, want) { t.Errorf("%v: unexpected result:\nwant: %v\ngot: %v", prefix, want, x) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zswap.go000066400000000000000000000033041450372207100220730ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" ) type Zswaper interface { Zswap(n int, x []complex128, incX int, y []complex128, incY int) } func ZswapTest(t *testing.T, impl Zswaper) { rnd := rand.New(rand.NewSource(1)) for n := 0; n < 20; n++ { for _, inc := range allPairs([]int{-5, -1, 1, 2, 5, 10}, []int{-3, -1, 1, 3, 7, 12}) { incX := inc[0] incY := inc[1] aincX := abs(incX) aincY := abs(incY) var x, y []complex128 if n > 0 { x = make([]complex128, (n-1)*aincX+1) y = make([]complex128, (n-1)*aincY+1) } for i := range x { x[i] = znan } for i := range y { y[i] = znan } for i := 0; i < n; i++ { x[i*aincX] = complex(rnd.NormFloat64(), rnd.NormFloat64()) y[i*aincY] = complex(rnd.NormFloat64(), rnd.NormFloat64()) } xWant := make([]complex128, len(x)) for i := range xWant { xWant[i] = znan } yWant := make([]complex128, len(y)) for i := range yWant { yWant[i] = znan } if incX*incY > 0 { for i := 0; i < n; i++ { xWant[i*aincX] = y[i*aincY] yWant[i*aincY] = x[i*aincX] } } else { for i := 0; i < n; i++ { xWant[(n-i-1)*aincX] = y[i*aincY] yWant[(n-i-1)*aincY] = x[i*aincX] } } impl.Zswap(n, x, incX, y, incY) prefix := fmt.Sprintf("Case n=%v,incX=%v,incY=%v:", n, incX, incY) if !zsame(x, xWant) { t.Errorf("%v: unexpected x:\nwant %v\ngot %v", prefix, xWant, x) } if !zsame(y, yWant) { t.Errorf("%v: unexpected y:\nwant %v\ngot %v", prefix, yWant, y) } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zsymm.go000066400000000000000000000077041450372207100221160ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zsymmer interface { Zsymm(side blas.Side, uplo blas.Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) } func ZsymmTest(t *testing.T, impl Zsymmer) { for _, side := range []blas.Side{blas.Left, blas.Right} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { name := sideString(side) + "-" + uploString(uplo) t.Run(name, func(t *testing.T) { for _, m := range []int{0, 1, 2, 3, 4, 5} { for _, n := range []int{0, 1, 2, 3, 4, 5} { zsymmTest(t, impl, side, uplo, m, n) } } }) } } } func zsymmTest(t *testing.T, impl Zsymmer, side blas.Side, uplo blas.Uplo, m, n int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) nA := m if side == blas.Right { nA = n } for _, lda := range []int{max(1, nA), nA + 2} { for _, ldb := range []int{max(1, n), n + 3} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { for _, beta := range []complex128{0, 1, complex(1.3, -1.1)} { for _, nanC := range []bool{false, true} { if nanC && beta != 0 { // Skip tests with C containing NaN values // unless beta would zero out the NaNs. continue } // Allocate the matrix A and fill it with random numbers. a := make([]complex128, nA*lda) for i := range a { a[i] = rndComplex128(rnd) } // Create a copy of A for checking that // Zsymm does not modify its triangle // opposite to uplo. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Create a copy of A expanded into a // full symmetric matrix for computing // the expected result using zmm. aSym := make([]complex128, len(a)) copy(aSym, a) if uplo == blas.Upper { for i := 0; i < nA-1; i++ { for j := i + 1; j < nA; j++ { aSym[j*lda+i] = aSym[i*lda+j] } } } else { for i := 1; i < nA; i++ { for j := 0; j < i; j++ { aSym[j*lda+i] = aSym[i*lda+j] } } } // Allocate the matrix B and fill it with random numbers. b := make([]complex128, m*ldb) for i := range b { b[i] = rndComplex128(rnd) } // Create a copy of B for checking that // Zsymm does not modify B. bCopy := make([]complex128, len(b)) copy(bCopy, b) // Allocate the matrix C and fill it with random numbers. c := make([]complex128, m*ldc) for i := range c { c[i] = rndComplex128(rnd) } if nanC { for i := 0; i < n; i++ { for j := 0; j < m; j++ { c[i+j*ldc] = cmplx.NaN() } } } // Compute the expected result using an internal Zgemm implementation. var want []complex128 if side == blas.Left { want = zmm(blas.NoTrans, blas.NoTrans, m, n, m, alpha, aSym, lda, b, ldb, beta, c, ldc) } else { want = zmm(blas.NoTrans, blas.NoTrans, m, n, n, alpha, b, ldb, aSym, lda, beta, c, ldc) } // Compute the result using Zsymm. impl.Zsymm(side, uplo, m, n, alpha, a, lda, b, ldb, beta, c, ldc) prefix := fmt.Sprintf("m=%v,n=%v,lda=%v,ldb=%v,ldc=%v,alpha=%v,beta=%v", m, n, lda, ldb, ldc, alpha, beta) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if !zsame(b, bCopy) { t.Errorf("%v: unexpected modification of B", prefix) continue } if !zEqualApprox(c, want, tol) { t.Errorf("%v: unexpected result", prefix) } } } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zsyr2k.go000066400000000000000000000113271450372207100221770ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zsyr2ker interface { Zsyr2k(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) } func Zsyr2kTest(t *testing.T, impl Zsyr2ker) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { name := uploString(uplo) + "-" + transString(trans) t.Run(name, func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5} { for _, k := range []int{0, 1, 2, 3, 4, 5, 7} { zsyr2kTest(t, impl, uplo, trans, n, k) } } }) } } } func zsyr2kTest(t *testing.T, impl Zsyr2ker, uplo blas.Uplo, trans blas.Transpose, n, k int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) row, col := n, k if trans == blas.Trans { row, col = k, n } for _, lda := range []int{max(1, col), col + 2} { for _, ldb := range []int{max(1, col), col + 3} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { for _, beta := range []complex128{0, 1, complex(1.3, -1.1)} { // Allocate the matrix A and fill it with random numbers. a := make([]complex128, row*lda) for i := range a { a[i] = rndComplex128(rnd) } // Create a copy of A for checking that // Zsyr2k does not modify A. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Allocate the matrix B and fill it with random numbers. b := make([]complex128, row*ldb) for i := range b { b[i] = rndComplex128(rnd) } // Create a copy of B for checking that // Zsyr2k does not modify B. bCopy := make([]complex128, len(b)) copy(bCopy, b) // Allocate the matrix C and fill it with random numbers. c := make([]complex128, n*ldc) for i := range c { c[i] = rndComplex128(rnd) } // Create a copy of C for checking that // Zsyr2k does not modify its triangle // opposite to uplo. cCopy := make([]complex128, len(c)) copy(cCopy, c) // Create a copy of C expanded into a // full symmetric matrix for computing // the expected result using zmm. cSym := make([]complex128, len(c)) copy(cSym, c) if uplo == blas.Upper { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { cSym[j*ldc+i] = cSym[i*ldc+j] } } } else { for i := 1; i < n; i++ { for j := 0; j < i; j++ { cSym[j*ldc+i] = cSym[i*ldc+j] } } } // Compute the expected result using an internal Zgemm implementation. var want []complex128 if trans == blas.NoTrans { // C = alpha*A*Bᵀ + alpha*B*Aᵀ + beta*C tmp := zmm(blas.NoTrans, blas.Trans, n, n, k, alpha, a, lda, b, ldb, beta, cSym, ldc) want = zmm(blas.NoTrans, blas.Trans, n, n, k, alpha, b, ldb, a, lda, 1, tmp, ldc) } else { // C = alpha*Aᵀ*B + alpha*Bᵀ*A + beta*C tmp := zmm(blas.Trans, blas.NoTrans, n, n, k, alpha, a, lda, b, ldb, beta, cSym, ldc) want = zmm(blas.Trans, blas.NoTrans, n, n, k, alpha, b, ldb, a, lda, 1, tmp, ldc) } // Compute the result using Zsyr2k. impl.Zsyr2k(uplo, trans, n, k, alpha, a, lda, b, ldb, beta, c, ldc) prefix := fmt.Sprintf("n=%v,k=%v,lda=%v,ldb=%v,ldc=%v,alpha=%v,beta=%v", n, k, lda, ldb, ldc, alpha, beta) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if !zsame(b, bCopy) { t.Errorf("%v: unexpected modification of B", prefix) continue } if uplo == blas.Upper && !zSameLowerTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in lower triangle of C", prefix) continue } if uplo == blas.Lower && !zSameUpperTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in upper triangle of C", prefix) continue } // Expand C into a full symmetric matrix // for comparison with the result from zmm. if uplo == blas.Upper { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { c[j*ldc+i] = c[i*ldc+j] } } } else { for i := 1; i < n; i++ { for j := 0; j < i; j++ { c[j*ldc+i] = c[i*ldc+j] } } } if !zEqualApprox(c, want, tol) { t.Errorf("%v: unexpected result", prefix) } } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/zsyrk.go000066400000000000000000000104171450372207100221140ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Zsyrker interface { Zsyrk(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, beta complex128, c []complex128, ldc int) } func ZsyrkTest(t *testing.T, impl Zsyrker) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { name := uploString(uplo) + "-" + transString(trans) t.Run(name, func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5} { for _, k := range []int{0, 1, 2, 3, 4, 5, 7} { zsyrkTest(t, impl, uplo, trans, n, k) } } }) } } } func zsyrkTest(t *testing.T, impl Zsyrker, uplo blas.Uplo, trans blas.Transpose, n, k int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) rowA, colA := n, k if trans == blas.Trans { rowA, colA = k, n } for _, lda := range []int{max(1, colA), colA + 2} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { for _, beta := range []complex128{0, 1, complex(1.3, -1.1)} { for _, nanC := range []bool{false, true} { if nanC && beta != 0 { // Skip tests with C containing NaN values // unless beta would zero out the NaNs. continue } // Allocate the matrix A and fill it with random numbers. a := make([]complex128, rowA*lda) for i := range a { a[i] = rndComplex128(rnd) } // Create a copy of A for checking that // Zsyrk does not modify A. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Allocate the matrix C and fill it with random numbers. c := make([]complex128, n*ldc) for i := range c { c[i] = rndComplex128(rnd) } if nanC { for i := 0; i < n; i++ { for j := 0; j < n; j++ { c[i+j*ldc] = cmplx.NaN() } } } // Create a copy of C for checking that // Zsyrk does not modify its triangle // opposite to uplo. cCopy := make([]complex128, len(c)) copy(cCopy, c) // Create a copy of C expanded into a // full symmetric matrix for computing // the expected result using zmm. cSym := make([]complex128, len(c)) copy(cSym, c) if uplo == blas.Upper { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { cSym[j*ldc+i] = cSym[i*ldc+j] } } } else { for i := 1; i < n; i++ { for j := 0; j < i; j++ { cSym[j*ldc+i] = cSym[i*ldc+j] } } } // Compute the expected result using an internal Zgemm implementation. var want []complex128 if trans == blas.NoTrans { want = zmm(blas.NoTrans, blas.Trans, n, n, k, alpha, a, lda, a, lda, beta, cSym, ldc) } else { want = zmm(blas.Trans, blas.NoTrans, n, n, k, alpha, a, lda, a, lda, beta, cSym, ldc) } // Compute the result using Zsyrk. impl.Zsyrk(uplo, trans, n, k, alpha, a, lda, beta, c, ldc) prefix := fmt.Sprintf("n=%v,k=%v,lda=%v,ldc=%v,alpha=%v,beta=%v", n, k, lda, ldc, alpha, beta) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if uplo == blas.Upper && !zSameLowerTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in lower triangle of C", prefix) continue } if uplo == blas.Lower && !zSameUpperTri(n, c, ldc, cCopy, ldc) { t.Errorf("%v: unexpected modification in upper triangle of C", prefix) continue } // Expand C into a full symmetric matrix // for comparison with the result from zmm. if uplo == blas.Upper { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { c[j*ldc+i] = c[i*ldc+j] } } } else { for i := 1; i < n; i++ { for j := 0; j < i; j++ { c[j*ldc+i] = c[i*ldc+j] } } } if !zEqualApprox(c, want, tol) { t.Errorf("%v: unexpected result", prefix) } } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztbmv.go000066400000000000000000000063001450372207100220700ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Ztbmver interface { Ztbmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k int, ab []complex128, ldab int, x []complex128, incX int) Ztrmver } func ZtbmvTest(t *testing.T, impl Ztbmver) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, n := range []int{1, 2, 3, 5} { for k := 0; k < n; k++ { for _, ldab := range []int{k + 1, k + 1 + 10} { for _, incX := range []int{-4, 1, 5} { testZtbmv(t, impl, rnd, uplo, trans, diag, n, k, ldab, incX) } } } } } } } } // testZtbmv tests Ztbmv by comparing its output to that of Ztrmv. func testZtbmv(t *testing.T, impl Ztbmver, rnd *rand.Rand, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k, ldab, incX int) { const tol = 1e-13 // Allocate a dense-storage triangular band matrix filled with NaNs that // will be used as the reference matrix for Ztrmv. lda := max(1, n) a := makeZGeneral(nil, n, n, lda) // Fill the referenced triangle with random data within the band and // with zeros outside. if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < min(n, i+k+1); j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } for j := i + k + 1; j < n; j++ { a[i*lda+j] = 0 } } } else { for i := 0; i < n; i++ { for j := 0; j < i-k; j++ { a[i*lda+j] = 0 } for j := max(0, i-k); j <= i; j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } } if diag == blas.Unit { // The diagonal should not be referenced by Ztbmv and Ztrmv, so // invalidate it with NaNs. for i := 0; i < n; i++ { a[i*lda+i] = znan } } // Create the triangular band matrix. ab := zPackTriBand(k, ldab, uplo, n, a, lda) abCopy := make([]complex128, len(ab)) copy(abCopy, ab) // Generate a random complex vector x. xtest := make([]complex128, n) for i := range xtest { re := rnd.NormFloat64() im := rnd.NormFloat64() xtest[i] = complex(re, im) } x := makeZVector(xtest, incX) xCopy := make([]complex128, len(x)) copy(xCopy, x) want := make([]complex128, len(x)) copy(want, x) // Compute the reference result of op(A)*x, storing it into want. impl.Ztrmv(uplo, trans, diag, n, a, lda, want, incX) // Compute op(A)*x, storing the result in-place into x. impl.Ztbmv(uplo, trans, diag, n, k, ab, ldab, x, incX) name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,k=%v,ldab=%v,incX=%v", uplo, trans, diag, n, k, ldab, incX) if !zsame(ab, abCopy) { t.Errorf("%v: unexpected modification of ab", name) } if !zSameAtNonstrided(x, want, incX) { t.Errorf("%v: unexpected modification of x", name) } if !zEqualApproxAtStrided(x, want, incX, tol) { t.Errorf("%v: unexpected result\nwant %v\ngot %v", name, want, x) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztbsv.go000066400000000000000000000065261450372207100221100ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Ztbsver interface { Ztbsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k int, ab []complex128, ldab int, x []complex128, incX int) Ztbmver } func ZtbsvTest(t *testing.T, impl Ztbsver) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, n := range []int{1, 2, 3, 4, 10} { for k := 0; k < n; k++ { for _, ldab := range []int{k + 1, k + 1 + 10} { for _, incX := range []int{-4, 1, 5} { ztbsvTest(t, impl, rnd, uplo, trans, diag, n, k, ldab, incX) } } } } } } } } // ztbsvTest tests Ztbsv by checking whether Ztbmv followed by Ztbsv // round-trip. func ztbsvTest(t *testing.T, impl Ztbsver, rnd *rand.Rand, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k, ldab, incX int) { const tol = 1e-10 // Allocate a dense-storage triangular band matrix filled with NaNs that // will be used as a for creating the actual triangular band matrix. lda := max(1, n) a := makeZGeneral(nil, n, n, lda) // Fill the referenced triangle of A with random data within the band // and with zeros outside. if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < min(n, i+k+1); j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } for j := i + k + 1; j < n; j++ { a[i*lda+j] = 0 } } } else { for i := 0; i < n; i++ { for j := 0; j < i-k; j++ { a[i*lda+j] = 0 } for j := max(0, i-k); j <= i; j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } } if diag == blas.Unit { // The diagonal should not be referenced by Ztbmv and Ztbsv, so // invalidate it with NaNs. for i := 0; i < n; i++ { a[i*lda+i] = znan } } // Create the triangular band matrix. ab := zPackTriBand(k, ldab, uplo, n, a, lda) abCopy := make([]complex128, len(ab)) copy(abCopy, ab) // Generate a random complex vector x. xtest := make([]complex128, n) for i := range xtest { re := rnd.NormFloat64() im := rnd.NormFloat64() xtest[i] = complex(re, im) } x := makeZVector(xtest, incX) // Store a copy of x as the correct result that we want. want := make([]complex128, len(x)) copy(want, x) // Compute A*x, denoting the result by b and storing it in x. impl.Ztbmv(uplo, trans, diag, n, k, ab, ldab, x, incX) // Solve A*x = b, that is, x = A^{-1}*b = A^{-1}*A*x. impl.Ztbsv(uplo, trans, diag, n, k, ab, ldab, x, incX) // If Ztbsv is correct, A^{-1}*A = I and x contains again its original value. name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,k=%v,ldab=%v,incX=%v", uplo, trans, diag, n, k, ldab, incX) if !zsame(ab, abCopy) { t.Errorf("%v: unexpected modification of A", name) } if !zSameAtNonstrided(x, want, incX) { t.Errorf("%v: unexpected modification of x\nwant %v\ngot %v", name, want, x) } if !zEqualApproxAtStrided(x, want, incX, tol) { t.Errorf("%v: unexpected result\nwant %v\ngot %v", name, want, x) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztpmv.go000066400000000000000000000047411450372207100221150ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) type Ztpmver interface { Ztpmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, ap []complex128, x []complex128, incX int) } func ZtpmvTest(t *testing.T, impl Ztpmver) { for tc, test := range ztrmvTestCases { n := len(test.x) uplo := test.uplo for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, incX := range []int{-11, -2, -1, 1, 2, 7} { ap := zPack(uplo, n, test.a, n) apCopy := make([]complex128, len(ap)) copy(apCopy, ap) x := makeZVector(test.x, incX) impl.Ztpmv(uplo, trans, diag, n, ap, x, incX) if !zsame(ap, apCopy) { t.Errorf("Case %v (uplo=%v,trans=%v,diag=%v,incX=%v): unexpected modification of A", tc, uplo, trans, diag, incX) } var want []complex128 if diag == blas.NonUnit { switch { case trans == blas.NoTrans && incX > 0: want = makeZVector(test.want, incX) case trans == blas.NoTrans && incX < 0: want = makeZVector(test.wantNeg, incX) case trans == blas.Trans && incX > 0: want = makeZVector(test.wantTrans, incX) case trans == blas.Trans && incX < 0: want = makeZVector(test.wantTransNeg, incX) case trans == blas.ConjTrans && incX > 0: want = makeZVector(test.wantConjTrans, incX) case trans == blas.ConjTrans && incX < 0: want = makeZVector(test.wantConjTransNeg, incX) } } else { switch { case trans == blas.NoTrans && incX > 0: want = makeZVector(test.wantUnit, incX) case trans == blas.NoTrans && incX < 0: want = makeZVector(test.wantUnitNeg, incX) case trans == blas.Trans && incX > 0: want = makeZVector(test.wantUnitTrans, incX) case trans == blas.Trans && incX < 0: want = makeZVector(test.wantUnitTransNeg, incX) case trans == blas.ConjTrans && incX > 0: want = makeZVector(test.wantUnitConjTrans, incX) case trans == blas.ConjTrans && incX < 0: want = makeZVector(test.wantUnitConjTransNeg, incX) } } if !zsame(x, want) { t.Errorf("Case %v (uplo=%v,trans=%v,diag=%v,incX=%v): unexpected result\nwant %v\ngot %v", tc, uplo, trans, diag, incX, want, x) } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztpsv.go000066400000000000000000000060211450372207100221140ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Ztpsver interface { Ztpsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, ap []complex128, x []complex128, incX int) Ztpmver } func ZtpsvTest(t *testing.T, impl Ztpsver) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, n := range []int{0, 1, 2, 3, 4, 10} { for _, incX := range []int{-11, -3, -2, -1, 1, 2, 3, 7} { ztpsvTest(t, impl, uplo, trans, diag, n, incX, rnd) } } } } } } // ztpsvTest tests Ztpsv by checking whether Ztpmv followed by Ztpsv // round-trip. func ztpsvTest(t *testing.T, impl Ztpsver, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, incX int, rnd *rand.Rand) { const tol = 1e-10 // Allocate a dense-storage triangular matrix filled with NaNs that // will be used as a for creating the actual triangular matrix in packed // storage. lda := n a := makeZGeneral(nil, n, n, max(1, lda)) // Fill the referenced triangle of A with random data. if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } } if diag == blas.Unit { // The diagonal should not be referenced by Ztpmv and Ztpsv, so // invalidate it with NaNs. for i := 0; i < n; i++ { a[i*lda+i] = znan } } // Create the triangular matrix in packed storage. ap := zPack(uplo, n, a, n) apCopy := make([]complex128, len(ap)) copy(apCopy, ap) // Generate a random complex vector x. xtest := make([]complex128, n) for i := range xtest { re := rnd.NormFloat64() im := rnd.NormFloat64() xtest[i] = complex(re, im) } x := makeZVector(xtest, incX) // Store a copy of x as the correct result that we want. want := make([]complex128, len(x)) copy(want, x) // Compute A*x, denoting the result by b and storing it in x. impl.Ztpmv(uplo, trans, diag, n, ap, x, incX) // Solve A*x = b, that is, x = A^{-1}*b = A^{-1}*A*x. impl.Ztpsv(uplo, trans, diag, n, ap, x, incX) // If Ztpsv is correct, A^{-1}*A = I and x contains again its original value. name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,incX=%v", uplo, trans, diag, n, incX) if !zsame(ap, apCopy) { t.Errorf("%v: unexpected modification of ap", name) } if !zSameAtNonstrided(x, want, incX) { t.Errorf("%v: unexpected modification of x\nwant %v\ngot %v", name, want, x) } if !zEqualApproxAtStrided(x, want, incX, tol) { t.Errorf("%v: unexpected result\nwant %v\ngot %v", name, want, x) } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztrmm.go000066400000000000000000000070071450372207100221040ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Ztrmmer interface { Ztrmm(side blas.Side, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int) } func ZtrmmTest(t *testing.T, impl Ztrmmer) { for _, side := range []blas.Side{blas.Left, blas.Right} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { name := sideString(side) + "-" + uploString(uplo) + "-" + transString(trans) + "-" + diagString(diag) t.Run(name, func(t *testing.T) { for _, m := range []int{0, 1, 2, 3, 4, 5} { for _, n := range []int{0, 1, 2, 3, 4, 5} { ztrmmTest(t, impl, side, uplo, trans, diag, m, n) } } }) } } } } } func ztrmmTest(t *testing.T, impl Ztrmmer, side blas.Side, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, m, n int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) nA := m if side == blas.Right { nA = n } for _, lda := range []int{max(1, nA), nA + 2} { for _, ldb := range []int{max(1, n), n + 3} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { // Allocate the matrix A and fill it with random numbers. a := make([]complex128, nA*lda) for i := range a { a[i] = rndComplex128(rnd) } // Put a zero into A to cover special cases in Ztrmm. if nA > 1 { if uplo == blas.Upper { a[nA-1] = 0 } else { a[(nA-1)*lda] = 0 } } // Create a copy of A for checking that Ztrmm // does not modify its triangle opposite to // uplo. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Create a dense representation of A for // computing the expected result using zmm. aTri := make([]complex128, len(a)) copy(aTri, a) if uplo == blas.Upper { for i := 0; i < nA; i++ { // Zero out the lower triangle. for j := 0; j < i; j++ { aTri[i*lda+j] = 0 } if diag == blas.Unit { aTri[i*lda+i] = 1 } } } else { for i := 0; i < nA; i++ { if diag == blas.Unit { aTri[i*lda+i] = 1 } // Zero out the upper triangle. for j := i + 1; j < nA; j++ { aTri[i*lda+j] = 0 } } } // Allocate the matrix B and fill it with random numbers. b := make([]complex128, m*ldb) for i := range b { b[i] = rndComplex128(rnd) } // Put a zero into B to cover special cases in Ztrmm. if m > 0 && n > 0 { b[0] = 0 } // Compute the expected result using an internal Zgemm implementation. var want []complex128 if side == blas.Left { want = zmm(trans, blas.NoTrans, m, n, m, alpha, aTri, lda, b, ldb, 0, b, ldb) } else { want = zmm(blas.NoTrans, trans, m, n, n, alpha, b, ldb, aTri, lda, 0, b, ldb) } // Compute the result using Ztrmm. impl.Ztrmm(side, uplo, trans, diag, m, n, alpha, a, lda, b, ldb) prefix := fmt.Sprintf("m=%v,n=%v,lda=%v,ldb=%v,alpha=%v", m, n, lda, ldb, alpha) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } if !zEqualApprox(b, want, tol) { t.Errorf("%v: unexpected result", prefix) } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztrmv.go000066400000000000000000000136211450372207100221140ustar00rootroot00000000000000// 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 testblas import ( "testing" "gonum.org/v1/gonum/blas" ) var ztrmvTestCases = []struct { uplo blas.Uplo a []complex128 x []complex128 // Results with non-unit diagonal. want []complex128 wantNeg []complex128 wantTrans []complex128 wantTransNeg []complex128 wantConjTrans []complex128 wantConjTransNeg []complex128 // Results with unit diagonal. wantUnit []complex128 wantUnitNeg []complex128 wantUnitTrans []complex128 wantUnitTransNeg []complex128 wantUnitConjTrans []complex128 wantUnitConjTransNeg []complex128 }{ {uplo: blas.Upper}, {uplo: blas.Lower}, { uplo: blas.Upper, a: []complex128{ 6 - 8i, -10 + 10i, -6 - 3i, -1 - 8i, znan, 7 + 8i, -7 + 9i, 3 + 6i, znan, znan, 6 - 4i, -2 - 5i, znan, znan, znan, 4 - 8i, }, x: []complex128{ 10 - 5i, -2 + 2i, 8 - 1i, -7 + 9i, }, want: []complex128{ 48 - 121i, -152 + 62i, 103 - 21i, 44 + 92i, }, wantNeg: []complex128{ 0 - 100i, -49 - 20i, 120 + 70i, -72 + 119i, }, wantTrans: []complex128{ 20 - 110i, -80 + 148i, -35 - 70i, -45 - 27i, }, wantTransNeg: []complex128{ 123 - 2i, 18 + 66i, 44 - 103i, 30 + 110i, }, wantConjTrans: []complex128{ 100 + 50i, -148 - 20i, 39 + 90i, -75 + 125i, }, wantConjTransNeg: []complex128{ 27 - 70i, -70 - 136i, 208 - 91i, -114 - 2i, }, wantUnit: []complex128{ 38 - 16i, -124 + 66i, 67 + 16i, -7 + 9i, }, wantUnitNeg: []complex128{ 10 - 5i, -47 - 38i, 64 + 12i, -109 + 18i, }, wantUnitTrans: []complex128{ 10 - 5i, -52 + 152i, -71 - 33i, -96 - 110i, }, wantUnitTransNeg: []complex128{ 133 + 93i, 20 + 48i, -12 - 161i, -7 + 9i, }, wantUnitConjTrans: []complex128{ 10 - 5i, -152 - 48i, -5 + 63i, 18 + 154i, }, wantUnitConjTransNeg: []complex128{ -43 - 135i, -52 - 138i, 168 - 21i, -7 + 9i, }, }, { uplo: blas.Lower, a: []complex128{ 10 - 8i, znan, znan, znan, 1 - 6i, -4 + 8i, znan, znan, 2 - 6i, 4 - 8i, 5 + 3i, znan, -7 - 4i, 1 + 3i, -2 - 4i, 9 + 8i, }, x: []complex128{ 10 + 5i, -7 + 1i, 3 - 1i, 9 + 10i, }, want: []complex128{ 140 - 30i, 60 - 115i, 48 + 14i, -69 + 57i, }, wantNeg: []complex128{ 51 + 53i, 44 - 78i, 65 - 16i, 170 + 28i, }, wantTrans: []complex128{ 116 - 113i, 3 - 51i, 40 - 52i, 1 + 162i, }, wantTransNeg: []complex128{ 50 + 125i, -38 - 66i, -29 + 123i, 109 - 22i, }, wantConjTrans: []complex128{ -44 + 71i, 95 + 55i, -46 + 2i, 161 + 18i, }, wantConjTransNeg: []complex128{ 130 - 35i, -72 + 56i, -31 - 97i, -91 + 154i, }, wantUnit: []complex128{ 10 + 5i, 33 - 54i, 33 + 9i, -61 - 95i, }, wantUnitNeg: []complex128{ 11 - 67i, 75 - 61i, 72 - 45i, 9 + 10i, }, wantUnitTrans: []complex128{ -14 - 78i, -24 + 10i, 25 - 57i, 9 + 10i, }, wantUnitTransNeg: []complex128{ 10 + 5i, -7 - 49i, -22 + 94i, -52 - 40i, }, wantUnitConjTrans: []complex128{ -94 - 54i, 52 + 4i, -55 + 15i, 9 + 10i, }, wantUnitConjTransNeg: []complex128{ 10 + 5i, -47 + 31i, -8 - 78i, -92 - 8i, }, }, } type Ztrmver interface { Ztrmv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []complex128, lda int, x []complex128, incX int) } func ZtrmvTest(t *testing.T, impl Ztrmver) { for tc, test := range ztrmvTestCases { n := len(test.x) uplo := test.uplo for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, incX := range []int{-11, -2, -1, 1, 2, 7} { for _, lda := range []int{max(1, n), n + 11} { a := makeZGeneral(test.a, n, n, lda) if diag == blas.Unit { for i := 0; i < n; i++ { a[i*lda+i] = znan } } aCopy := make([]complex128, len(a)) copy(aCopy, a) x := makeZVector(test.x, incX) impl.Ztrmv(uplo, trans, diag, n, a, lda, x, incX) if !zsame(a, aCopy) { t.Errorf("Case %v (uplo=%v,trans=%v,diag=%v,lda=%v,incX=%v): unexpected modification of A", tc, uplo, trans, diag, lda, incX) } var want []complex128 if diag == blas.NonUnit { switch { case trans == blas.NoTrans && incX > 0: want = makeZVector(test.want, incX) case trans == blas.NoTrans && incX < 0: want = makeZVector(test.wantNeg, incX) case trans == blas.Trans && incX > 0: want = makeZVector(test.wantTrans, incX) case trans == blas.Trans && incX < 0: want = makeZVector(test.wantTransNeg, incX) case trans == blas.ConjTrans && incX > 0: want = makeZVector(test.wantConjTrans, incX) case trans == blas.ConjTrans && incX < 0: want = makeZVector(test.wantConjTransNeg, incX) } } else { switch { case trans == blas.NoTrans && incX > 0: want = makeZVector(test.wantUnit, incX) case trans == blas.NoTrans && incX < 0: want = makeZVector(test.wantUnitNeg, incX) case trans == blas.Trans && incX > 0: want = makeZVector(test.wantUnitTrans, incX) case trans == blas.Trans && incX < 0: want = makeZVector(test.wantUnitTransNeg, incX) case trans == blas.ConjTrans && incX > 0: want = makeZVector(test.wantUnitConjTrans, incX) case trans == blas.ConjTrans && incX < 0: want = makeZVector(test.wantUnitConjTransNeg, incX) } } if !zsame(x, want) { t.Errorf("Case %v (uplo=%v,trans=%v,diag=%v,lda=%v,incX=%v): unexpected result\nwant %v\ngot %v", tc, uplo, trans, diag, lda, incX, want, x) } } } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztrsm.go000066400000000000000000000076701450372207100221200ustar00rootroot00000000000000// Copyright ©2019 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Ztrsmer interface { Ztrsm(side blas.Side, uplo blas.Uplo, transA blas.Transpose, diag blas.Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int) } func ZtrsmTest(t *testing.T, impl Ztrsmer) { for _, side := range []blas.Side{blas.Left, blas.Right} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { name := sideString(side) + "-" + uploString(uplo) + "-" + transString(trans) + "-" + diagString(diag) t.Run(name, func(t *testing.T) { for _, m := range []int{0, 1, 2, 3, 4, 5} { for _, n := range []int{0, 1, 2, 3, 4, 5} { ztrsmTest(t, impl, side, uplo, trans, diag, m, n) } } }) } } } } } func ztrsmTest(t *testing.T, impl Ztrsmer, side blas.Side, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, m, n int) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) nA := m if side == blas.Right { nA = n } for _, lda := range []int{max(1, nA), nA + 2} { for _, ldb := range []int{max(1, n), n + 3} { for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} { // Allocate the matrix A and fill it with random numbers. a := make([]complex128, nA*lda) for i := range a { a[i] = rndComplex128(rnd) } // Set some elements of A to 0 and 1 to cover special cases in Ztrsm. if nA > 2 { if uplo == blas.Upper { a[nA-2] = 1 a[nA-1] = 0 } else { a[(nA-2)*lda] = 1 a[(nA-1)*lda] = 0 } } // Create a copy of A for checking that Ztrsm // does not modify its triangle opposite to uplo. aCopy := make([]complex128, len(a)) copy(aCopy, a) // Create a dense representation of A for // computing the right-hand side matrix using zmm. aTri := make([]complex128, len(a)) copy(aTri, a) if uplo == blas.Upper { for i := 0; i < nA; i++ { // Zero out the lower triangle. for j := 0; j < i; j++ { aTri[i*lda+j] = 0 } if diag == blas.Unit { aTri[i*lda+i] = 1 } } } else { for i := 0; i < nA; i++ { if diag == blas.Unit { aTri[i*lda+i] = 1 } // Zero out the upper triangle. for j := i + 1; j < nA; j++ { aTri[i*lda+j] = 0 } } } // Allocate the right-hand side matrix B and fill it with random numbers. b := make([]complex128, m*ldb) for i := range b { b[i] = rndComplex128(rnd) } // Set some elements of B to 0 to cover special cases in Ztrsm. if m > 1 && n > 1 { b[0] = 0 b[(m-1)*ldb+n-1] = 0 } bCopy := make([]complex128, len(b)) copy(bCopy, b) // Compute the solution matrix X using Ztrsm. // X is overwritten on B. impl.Ztrsm(side, uplo, trans, diag, m, n, alpha, a, lda, b, ldb) x := b prefix := fmt.Sprintf("m=%v,n=%v,lda=%v,ldb=%v,alpha=%v", m, n, lda, ldb, alpha) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", prefix) continue } // Compute the left-hand side matrix of op(A)*X=alpha*B or X*op(A)=alpha*B // using an internal Zgemm implementation. var lhs []complex128 if side == blas.Left { lhs = zmm(trans, blas.NoTrans, m, n, m, 1, aTri, lda, x, ldb, 0, b, ldb) } else { lhs = zmm(blas.NoTrans, trans, m, n, n, 1, x, ldb, aTri, lda, 0, b, ldb) } // Compute the right-hand side matrix alpha*B. rhs := bCopy for i := 0; i < m; i++ { for j := 0; j < n; j++ { rhs[i*ldb+j] *= alpha } } if !zEqualApprox(lhs, rhs, tol) { t.Errorf("%v: unexpected result", prefix) } } } } } golang-gonum-v1-gonum-0.14.0/blas/testblas/ztrsv.go000066400000000000000000000056631450372207100221310ustar00rootroot00000000000000// 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 testblas import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Ztrsver interface { Ztrsv(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []complex128, lda int, x []complex128, incX int) Ztrmver } func ZtrsvTest(t *testing.T, impl Ztrsver) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, n := range []int{0, 1, 2, 3, 4, 10} { for _, lda := range []int{max(1, n), n + 11} { for _, incX := range []int{-11, -3, -2, -1, 1, 2, 3, 7} { ztrsvTest(t, impl, uplo, trans, diag, n, lda, incX, rnd) } } } } } } } // ztrsvTest tests Ztrsv by checking whether Ztrmv followed by Ztrsv // round-trip. func ztrsvTest(t *testing.T, impl Ztrsver, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, lda, incX int, rnd *rand.Rand) { const tol = 1e-10 // Allocate a dense-storage triangular matrix A filled with NaNs. a := makeZGeneral(nil, n, n, lda) // Fill the referenced triangle of A with random data. if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { re := rnd.NormFloat64() im := rnd.NormFloat64() a[i*lda+j] = complex(re, im) } } } if diag == blas.Unit { // The diagonal should not be referenced by Ztrmv and Ztrsv, so // invalidate it with NaNs. for i := 0; i < n; i++ { a[i*lda+i] = znan } } aCopy := make([]complex128, len(a)) copy(aCopy, a) // Generate a random complex vector x. xtest := make([]complex128, n) for i := range xtest { re := rnd.NormFloat64() im := rnd.NormFloat64() xtest[i] = complex(re, im) } x := makeZVector(xtest, incX) // Store a copy of x as the correct result that we want. want := make([]complex128, len(x)) copy(want, x) // Compute A*x, denoting the result by b and storing it in x. impl.Ztrmv(uplo, trans, diag, n, a, lda, x, incX) // Solve A*x = b, that is, x = A^{-1}*b = A^{-1}*A*x. impl.Ztrsv(uplo, trans, diag, n, a, lda, x, incX) // If Ztrsv is correct, A^{-1}*A = I and x contains again its original value. name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,lda=%v,incX=%v", uplo, trans, diag, n, lda, incX) if !zsame(a, aCopy) { t.Errorf("%v: unexpected modification of A", name) } if !zSameAtNonstrided(x, want, incX) { t.Errorf("%v: unexpected modification of x\nwant %v\ngot %v", name, want, x) } if !zEqualApproxAtStrided(x, want, incX, tol) { t.Errorf("%v: unexpected result\nwant %v\ngot %v", name, want, x) } } golang-gonum-v1-gonum-0.14.0/cmplxs/000077500000000000000000000000001450372207100171445ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/cmplxs/README.md000066400000000000000000000006721450372207100204300ustar00rootroot00000000000000# Gonum cmplxs [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/cmplxs)](https://pkg.go.dev/gonum.org/v1/gonum/cmplxs) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/cmplxs?status.svg)](https://godocs.io/gonum.org/v1/gonum/cmplxs) Package cmplxs provides a set of helper routines for dealing with slices of complex128. The functions avoid allocations to allow for use within tight loops without garbage collection overhead. golang-gonum-v1-gonum-0.14.0/cmplxs/cmplxs.go000066400000000000000000000412371450372207100210100ustar00rootroot00000000000000// 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 cmplxs import ( "errors" "math" "math/cmplx" "gonum.org/v1/gonum/cmplxs/cscalar" "gonum.org/v1/gonum/internal/asm/c128" ) const ( zeroLength = "cmplxs: zero length slice" shortSpan = "cmplxs: slice length less than 2" badLength = "cmplxs: slice lengths do not match" badDstLength = "cmplxs: destination slice length does not match input" ) // Abs calculates the absolute values of the elements of s, and stores them in dst. // It panics if the argument lengths do not match. func Abs(dst []float64, s []complex128) { if len(dst) != len(s) { panic(badDstLength) } for i, v := range s { dst[i] = cmplx.Abs(v) } } // Add adds, element-wise, the elements of s and dst, and stores the result in dst. // It panics if the argument lengths do not match. func Add(dst, s []complex128) { if len(dst) != len(s) { panic(badLength) } c128.AxpyUnitaryTo(dst, 1, s, dst) } // AddTo adds, element-wise, the elements of s and t and // stores the result in dst. // It panics if the argument lengths do not match. func AddTo(dst, s, t []complex128) []complex128 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } c128.AxpyUnitaryTo(dst, 1, s, t) return dst } // AddConst adds the scalar c to all of the values in dst. func AddConst(c complex128, dst []complex128) { c128.AddConst(c, dst) } // AddScaled performs dst = dst + alpha * s. // It panics if the slice argument lengths do not match. func AddScaled(dst []complex128, alpha complex128, s []complex128) { if len(dst) != len(s) { panic(badLength) } c128.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 slice argument lengths do not match. // // At the return of the function, dst[i] = y[i] + alpha * s[i] func AddScaledTo(dst, y []complex128, alpha complex128, s []complex128) []complex128 { if len(s) != len(y) { panic(badLength) } if len(dst) != len(y) { panic(badDstLength) } c128.AxpyUnitaryTo(dst, alpha, s, y) return dst } // Count applies the function f to every element of s and returns the number // of times the function returned true. func Count(f func(complex128) bool, s []complex128) int { var n int for _, val := range s { if f(val) { n++ } } return n } // Complex fills each of the elements of dst with the complex number // constructed from the corresponding elements of real and imag. // It panics if the argument lengths do not match. func Complex(dst []complex128, real, imag []float64) []complex128 { if len(real) != len(imag) { panic(badLength) } if len(dst) != len(real) { panic(badDstLength) } if len(dst) == 0 { return dst } for i, r := range real { dst[i] = complex(r, imag[i]) } return dst } // CumProd finds the cumulative product of elements of s and store it in // place into dst so that // // dst[i] = s[i] * s[i-1] * s[i-2] * ... * s[0] // // It panics if the argument lengths do not match. func CumProd(dst, s []complex128) []complex128 { if len(dst) != len(s) { panic(badDstLength) } if len(dst) == 0 { return dst } return c128.CumProd(dst, s) } // CumSum finds the cumulative sum of elements of s and stores it in place // into dst so that // // dst[i] = s[i] + s[i-1] + s[i-2] + ... + s[0] // // It panics if the argument lengths do not match. func CumSum(dst, s []complex128) []complex128 { if len(dst) != len(s) { panic(badDstLength) } if len(dst) == 0 { return dst } return c128.CumSum(dst, s) } // Distance computes the L-norm of s - t. See Norm for special cases. // It panics if the slice argument lengths do not match. func Distance(s, t []complex128, L float64) float64 { if len(s) != len(t) { panic(badLength) } if len(s) == 0 { return 0 } var norm float64 switch { case L == 2: return c128.L2DistanceUnitary(s, t) case L == 1: for i, v := range s { norm += cmplx.Abs(t[i] - v) } return norm case math.IsInf(L, 1): for i, v := range s { absDiff := cmplx.Abs(t[i] - v) if absDiff > norm { norm = absDiff } } return norm default: for i, v := range s { norm += math.Pow(cmplx.Abs(t[i]-v), L) } return math.Pow(norm, 1/L) } } // Div performs element-wise division dst / s // and stores the result in dst. // It panics if the argument lengths do not match. func Div(dst, s []complex128) { if len(dst) != len(s) { panic(badLength) } c128.Div(dst, s) } // DivTo performs element-wise division s / t // and stores the result in dst. // It panics if the argument lengths do not match. func DivTo(dst, s, t []complex128) []complex128 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } return c128.DivTo(dst, s, t) } // Dot computes the dot product of s1 and s2, i.e. // sum_{i = 1}^N conj(s1[i])*s2[i]. // It panics if the argument lengths do not match. func Dot(s1, s2 []complex128) complex128 { if len(s1) != len(s2) { panic(badLength) } return c128.DotUnitary(s1, s2) } // Equal returns true when the slices have equal lengths and // all elements are numerically identical. func Equal(s1, s2 []complex128) bool { if len(s1) != len(s2) { return false } for i, val := range s1 { if s2[i] != val { return false } } return true } // EqualApprox returns true when 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 []complex128, tol float64) bool { if len(s1) != len(s2) { return false } for i, a := range s1 { if !cscalar.EqualWithinAbsOrRel(a, s2[i], tol, tol) { return false } } return true } // EqualFunc returns true when the slices have the same lengths // and the function returns true for all element pairs. func EqualFunc(s1, s2 []complex128, f func(complex128, complex128) bool) bool { if len(s1) != len(s2) { return false } for i, val := range s1 { if !f(val, s2[i]) { return false } } return true } // EqualLengths returns true when all of the slices have equal length, // and false otherwise. It also returns true when there are no input slices. func EqualLengths(slices ...[]complex128) 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(complex128) bool, s []complex128, 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("cmplxs: insufficient elements found") } // HasNaN returns true when the slice s has any values that are NaN and false // otherwise. func HasNaN(s []complex128) bool { for _, v := range s { if cmplx.IsNaN(v) { return true } } return false } // Imag places the imaginary components of src into dst. // It panics if the argument lengths do not match. func Imag(dst []float64, src []complex128) []float64 { if len(dst) != len(src) { panic(badDstLength) } if len(dst) == 0 { return dst } for i, z := range src { dst[i] = imag(z) } return dst } // 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 []complex128, l, u complex128) []complex128 { Span(dst, cmplx.Log(l), cmplx.Log(u)) for i := range dst { dst[i] = cmplx.Exp(dst[i]) } return dst } // MaxAbs returns the maximum absolute value in the input slice. // It panics if s is zero length. func MaxAbs(s []complex128) complex128 { return s[MaxAbsIdx(s)] } // MaxAbsIdx returns the index of the maximum absolute value in the input slice. // If several entries have the maximum absolute value, the first such index is // returned. // It panics if s is zero length. func MaxAbsIdx(s []complex128) int { if len(s) == 0 { panic(zeroLength) } max := math.NaN() var ind int for i, v := range s { if cmplx.IsNaN(v) { continue } if a := cmplx.Abs(v); a > max || math.IsNaN(max) { max = a ind = i } } return ind } // MinAbs returns the minimum absolute value in the input slice. // It panics if s is zero length. func MinAbs(s []complex128) complex128 { return s[MinAbsIdx(s)] } // MinAbsIdx returns the index of the minimum absolute value in the input slice. If several // entries have the minimum absolute value, the first such index is returned. // It panics if s is zero length. func MinAbsIdx(s []complex128) int { if len(s) == 0 { panic(zeroLength) } min := math.NaN() var ind int for i, v := range s { if cmplx.IsNaN(v) { continue } if a := cmplx.Abs(v); a < min || math.IsNaN(min) { min = a ind = i } } return ind } // Mul performs element-wise multiplication between dst // and s and stores the result in dst. // It panics if the argument lengths do not match. func Mul(dst, s []complex128) { if len(dst) != len(s) { panic(badLength) } for i, val := range s { dst[i] *= val } } // MulConj performs element-wise multiplication between dst // and the conjugate of s and stores the result in dst. // It panics if the argument lengths do not match. func MulConj(dst, s []complex128) { if len(dst) != len(s) { panic(badLength) } for i, val := range s { dst[i] *= cmplx.Conj(val) } } // MulConjTo performs element-wise multiplication between s // and the conjugate of t and stores the result in dst. // It panics if the argument lengths do not match. func MulConjTo(dst, s, t []complex128) []complex128 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } for i, val := range t { dst[i] = cmplx.Conj(val) * s[i] } return dst } // MulTo performs element-wise multiplication between s // and t and stores the result in dst. // It panics if the argument lengths do not match. func MulTo(dst, s, t []complex128) []complex128 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } for i, val := range t { dst[i] = val * s[i] } return dst } // 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. // It panics if s is zero length. func NearestIdx(s []complex128, v complex128) int { if len(s) == 0 { panic(zeroLength) } switch { case cmplx.IsNaN(v): return 0 case cmplx.IsInf(v): return MaxAbsIdx(s) } var ind int dist := math.NaN() for i, val := range s { newDist := cmplx.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 } // Norm returns the L-norm of the slice S, defined as // (sum_{i=1}^N abs(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 []complex128, 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 } var norm float64 switch { case L == 2: return c128.L2NormUnitary(s) case L == 1: for _, v := range s { norm += cmplx.Abs(v) } return norm case math.IsInf(L, 1): for _, v := range s { norm = math.Max(norm, cmplx.Abs(v)) } return norm default: for _, v := range s { norm += math.Pow(cmplx.Abs(v), L) } return math.Pow(norm, 1/L) } } // Prod returns the product of the elements of the slice. // Returns 1 if len(s) = 0. func Prod(s []complex128) complex128 { prod := 1 + 0i for _, val := range s { prod *= val } return prod } // Real places the real components of src into dst. // It panics if the argument lengths do not match. func Real(dst []float64, src []complex128) []float64 { if len(dst) != len(src) { panic(badDstLength) } if len(dst) == 0 { return dst } for i, z := range src { dst[i] = real(z) } return dst } // Reverse reverses the order of elements in the slice. func Reverse(s []complex128) { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { s[i], s[j] = s[j], s[i] } } // Same returns true when the input slices have the same length and all // elements have the same value with NaN treated as the same. func Same(s, t []complex128) bool { if len(s) != len(t) { return false } for i, v := range s { w := t[i] if v != w && !(cmplx.IsNaN(v) && cmplx.IsNaN(w)) { return false } } return true } // Scale multiplies every element in dst by the scalar c. func Scale(c complex128, dst []complex128) { if len(dst) > 0 { c128.ScalUnitary(c, dst) } } // ScaleReal multiplies every element in dst by the real scalar f. func ScaleReal(f float64, dst []complex128) { for i, z := range dst { dst[i] = complex(f*real(z), f*imag(z)) } } // ScaleRealTo multiplies the elements in s by the real scalar f and // stores the result in dst. // It panics if the slice argument lengths do not match. func ScaleRealTo(dst []complex128, f float64, s []complex128) []complex128 { if len(dst) != len(s) { panic(badDstLength) } for i, z := range s { dst[i] = complex(f*real(z), f*imag(z)) } return dst } // ScaleTo multiplies the elements in s by c and stores the result in dst. // It panics if the slice argument lengths do not match. func ScaleTo(dst []complex128, c complex128, s []complex128) []complex128 { if len(dst) != len(s) { panic(badDstLength) } if len(dst) > 0 { c128.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. // It panics if the length of dst is less than 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 []complex128, l, u complex128) []complex128 { n := len(dst) if n < 2 { panic(shortSpan) } // Special cases for Inf and NaN. switch { case cmplx.IsNaN(l): for i := range dst[:len(dst)-1] { dst[i] = cmplx.NaN() } dst[len(dst)-1] = u return dst case cmplx.IsNaN(u): for i := range dst[1:] { dst[i+1] = cmplx.NaN() } dst[0] = l return dst case cmplx.IsInf(l) && cmplx.IsInf(u): for i := range dst { dst[i] = cmplx.Inf() } return dst case cmplx.IsInf(l): for i := range dst[:len(dst)-1] { dst[i] = l } dst[len(dst)-1] = u return dst case cmplx.IsInf(u): for i := range dst[1:] { dst[i+1] = u } dst[0] = l return dst } step := (u - l) / complex(float64(n-1), 0) for i := range dst { dst[i] = l + step*complex(float64(i), 0) } return dst } // Sub subtracts, element-wise, the elements of s from dst. // It panics if the argument lengths do not match. func Sub(dst, s []complex128) { if len(dst) != len(s) { panic(badLength) } c128.AxpyUnitaryTo(dst, -1, s, dst) } // SubTo subtracts, element-wise, the elements of t from s and // stores the result in dst. // It panics if the argument lengths do not match. func SubTo(dst, s, t []complex128) []complex128 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } c128.AxpyUnitaryTo(dst, -1, t, s) return dst } // Sum returns the sum of the elements of the slice. func Sum(s []complex128) complex128 { return c128.Sum(s) } golang-gonum-v1-gonum-0.14.0/cmplxs/cmplxs_test.go000066400000000000000000001150371450372207100220470ustar00rootroot00000000000000// 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 cmplxs import ( "fmt" "math" "math/cmplx" "strconv" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/cmplxs/cscalar" "gonum.org/v1/gonum/floats" ) const ( EqTolerance = 1e-14 Small = 10 Medium = 1000 Large = 100000 Huge = 10000000 ) func areSlicesEqual(t *testing.T, truth, comp []complex128, str string) { if !EqualApprox(comp, truth, EqTolerance) { t.Errorf(str+". Expected %v, returned %v", truth, comp) } } func areSlicesSame(t *testing.T, truth, comp []complex128, str string) { ok := len(truth) == len(comp) if ok { for i, a := range truth { if !cscalar.EqualWithinAbsOrRel(a, comp[i], EqTolerance, EqTolerance) && !cscalar.Same(a, comp[i]) { ok = false break } } } if !ok { t.Errorf(str+". Expected %v, returned %v", truth, comp) } } func Panics(fun func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() fun() return } func TestAdd(t *testing.T) { a := []complex128{1 + 1i, 2 + 2i, 3 + 3i} b := []complex128{4 + 4i, 5 + 5i, 6 + 6i} c := []complex128{7 + 7i, 8 + 8i, 9 + 9i} truth := []complex128{12 + 12i, 15 + 15i, 18 + 18i} n := make([]complex128, len(a)) Add(n, a) Add(n, b) Add(n, c) areSlicesEqual(t, truth, n, "Wrong addition of slices new receiver") Add(a, b) Add(a, c) areSlicesEqual(t, truth, n, "Wrong addition of slices for no new receiver") // Test that it panics if !Panics(func() { Add(make([]complex128, 2), make([]complex128, 3)) }) { t.Errorf("Did not panic with length mismatch") } } func TestAddTo(t *testing.T) { a := []complex128{1 + 1i, 2 + 2i, 3 + 3i} b := []complex128{4 + 4i, 5 + 5i, 6 + 6i} truth := []complex128{5 + 5i, 7 + 7i, 9 + 9i} n1 := make([]complex128, len(a)) n2 := AddTo(n1, a, b) areSlicesEqual(t, truth, n1, "Bad addition from mutator") areSlicesEqual(t, truth, n2, "Bad addition from returned slice") // Test that it panics if !Panics(func() { AddTo(make([]complex128, 2), make([]complex128, 3), make([]complex128, 3)) }) { t.Errorf("Did not panic with length mismatch") } if !Panics(func() { AddTo(make([]complex128, 3), make([]complex128, 3), make([]complex128, 2)) }) { t.Errorf("Did not panic with length mismatch") } } func TestAddConst(t *testing.T) { s := []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i} c := 6 + 1i truth := []complex128{9 + 2i, 10 + 3i, 7 + 4i, 13 + 5i, 11 + 6i} AddConst(c, s) areSlicesEqual(t, truth, s, "Wrong addition of constant") } func TestAddScaled(t *testing.T) { s := []complex128{3, 4, 1, 7, 5} alpha := 6 + 1i dst := []complex128{1, 2, 3, 4, 5} ans := []complex128{19 + 3i, 26 + 4i, 9 + 1i, 46 + 7i, 35 + 5i} AddScaled(dst, alpha, s) if !EqualApprox(dst, ans, EqTolerance) { t.Errorf("Adding scaled did not match. Expected %v, returned %v", ans, dst) } short := []complex128{1} if !Panics(func() { AddScaled(dst, alpha, short) }) { t.Errorf("Doesn't panic if s is smaller than dst") } if !Panics(func() { AddScaled(short, alpha, s) }) { t.Errorf("Doesn't panic if dst is smaller than s") } } func TestAddScaledTo(t *testing.T) { s := []complex128{3, 4, 1, 7, 5} alpha := 6 + 1i y := []complex128{1, 2, 3, 4, 5} dst1 := make([]complex128, 5) ans := []complex128{19 + 3i, 26 + 4i, 9 + 1i, 46 + 7i, 35 + 5i} dst2 := AddScaledTo(dst1, y, alpha, s) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("AddScaledTo did not match for mutator") } if !EqualApprox(dst2, ans, EqTolerance) { t.Errorf("AddScaledTo did not match for returned slice") } AddScaledTo(dst1, y, alpha, s) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("Reusing dst did not match") } short := []complex128{1} if !Panics(func() { AddScaledTo(dst1, y, alpha, short) }) { t.Errorf("Doesn't panic if s is smaller than dst") } if !Panics(func() { AddScaledTo(short, y, alpha, s) }) { t.Errorf("Doesn't panic if dst is smaller than s") } if !Panics(func() { AddScaledTo(dst1, short, alpha, s) }) { t.Errorf("Doesn't panic if y is smaller than dst") } } func TestCount(t *testing.T) { s := []complex128{3, 4, 1, 7, 5} f := func(v complex128) bool { return cmplx.Abs(v) > 3.5 } truth := 3 n := Count(f, s) if n != truth { t.Errorf("Wrong number of elements counted") } } func TestCumProd(t *testing.T) { s := []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i} receiver := make([]complex128, len(s)) result := CumProd(receiver, s) truth := []complex128{3 + 1i, 10 + 10i, -20 + 40i, -300 + 200i, -2500 - 500i} areSlicesEqual(t, truth, receiver, "Wrong cumprod mutated with new receiver") areSlicesEqual(t, truth, result, "Wrong cumprod result with new receiver") CumProd(receiver, s) areSlicesEqual(t, truth, receiver, "Wrong cumprod returned with reused receiver") // Test that it panics if !Panics(func() { CumProd(make([]complex128, 2), make([]complex128, 3)) }) { t.Errorf("Did not panic with length mismatch") } // Test empty CumProd emptyReceiver := make([]complex128, 0) truth = []complex128{} CumProd(emptyReceiver, emptyReceiver) areSlicesEqual(t, truth, emptyReceiver, "Wrong cumprod returned with empty receiver") } func TestComplex(t *testing.T) { for i, test := range []struct { dst []complex128 real, imag []float64 want []complex128 panics bool }{ {}, { dst: make([]complex128, 4), real: []float64{1, 2, 3, 4}, imag: []float64{1, 2, 3, 4}, want: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, }, { dst: make([]complex128, 3), real: []float64{1, 2, 3, 4}, imag: []float64{1, 2, 3, 4}, panics: true, }, { dst: make([]complex128, 4), real: []float64{1, 2, 3}, imag: []float64{1, 2, 3, 4}, panics: true, }, { dst: make([]complex128, 4), real: []float64{1, 2, 3, 4}, imag: []float64{1, 2, 3}, panics: true, }, { dst: make([]complex128, 4), real: []float64{1, 2, 3, 4}, imag: []float64{1, 2, 3, math.NaN()}, want: []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()}, }, } { var got []complex128 panicked := Panics(func() { got = Complex(test.dst, test.real, test.imag) }) if panicked != test.panics { if panicked { t.Errorf("unexpected panic for test %d", i) } else { t.Errorf("expected panic for test %d", i) } } if panicked || test.panics { continue } if !Same(got, test.dst) { t.Errorf("mismatch between dst and return test %d: got:%v want:%v", i, got, test.dst) } if !Same(got, test.want) { t.Errorf("unexpected result for test %d: got:%v want:%v", i, got, test.want) } } } func TestCumSum(t *testing.T) { s := []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i} receiver := make([]complex128, len(s)) result := CumSum(receiver, s) truth := []complex128{3 + 1i, 7 + 3i, 8 + 6i, 15 + 10i, 20 + 15i} areSlicesEqual(t, truth, receiver, "Wrong cumsum mutated with new receiver") areSlicesEqual(t, truth, result, "Wrong cumsum returned with new receiver") CumSum(receiver, s) areSlicesEqual(t, truth, receiver, "Wrong cumsum returned with reused receiver") // Test that it panics if !Panics(func() { CumSum(make([]complex128, 2), make([]complex128, 3)) }) { t.Errorf("Did not panic with length mismatch") } // Test empty CumSum emptyReceiver := make([]complex128, 0) truth = []complex128{} CumSum(emptyReceiver, emptyReceiver) areSlicesEqual(t, truth, emptyReceiver, "Wrong cumsum returned with empty receiver") } func TestDistance(t *testing.T) { norms := []float64{1, 2, 4, math.Inf(1)} slices := []struct { s []complex128 t []complex128 }{ { nil, nil, }, { []complex128{8 + 1i, 9 + 2i, 10 + 3i, -12 + 4i}, []complex128{8 + 1i, 9 + 2i, 10 + 3i, -12 + 4i}, }, { []complex128{1 + 1i, 2 + 2i, 3 + 3i, -4 + 4i, -5 + 5i, 8 + 6i}, []complex128{-9.2 - 1i, -6.8 - 2i, 9 - 3i, -3 - 4i, -2 - 5i, 1 - 6i}, }, } for j, test := range slices { tmp := make([]complex128, len(test.s)) for i, L := range norms { dist := Distance(test.s, test.t, L) copy(tmp, test.s) Sub(tmp, test.t) norm := Norm(tmp, L) if dist != norm { // Use equality because they should be identical. t.Errorf("Distance does not match norm for case %v, %v. Expected %v, Found %v.", i, j, norm, dist) } } } if !Panics(func() { Distance([]complex128{}, []complex128{1}, 1) }) { t.Errorf("Did not panic with unequal lengths") } } func TestDiv(t *testing.T) { s1 := []complex128{5 - 5i, 12 + 2i, 27 - 3i} s2 := []complex128{1 - 1i, 2 + 2i, 3 - 1i} ans := []complex128{5 + 0i, 3.5 - 2.5i, 8.4 + 1.8i} Div(s1, s2) if !EqualApprox(s1, ans, EqTolerance) { t.Errorf("Div doesn't give correct answer. Expected %v, Found %v.", ans, s1) } s1short := []complex128{1} if !Panics(func() { Div(s1short, s2) }) { t.Errorf("Did not panic with unequal lengths") } s2short := []complex128{1} if !Panics(func() { Div(s1, s2short) }) { t.Errorf("Did not panic with unequal lengths") } } func TestDivTo(t *testing.T) { s1 := []complex128{5 - 5i, 12 + 2i, 27 - 3i} s1orig := []complex128{5 - 5i, 12 + 2i, 27 - 3i} s2 := []complex128{1 - 1i, 2 + 2i, 3 - 1i} s2orig := []complex128{1 - 1i, 2 + 2i, 3 - 1i} dst1 := make([]complex128, 3) ans := []complex128{5 + 0i, 3.5 - 2.5i, 8.4 + 1.8i} dst2 := DivTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("DivTo doesn't give correct answer in mutated slice") } if !EqualApprox(dst2, ans, EqTolerance) { t.Errorf("DivTo doesn't give correct answer in returned slice") } if !EqualApprox(s1, s1orig, EqTolerance) { t.Errorf("S1 changes during multo") } if !EqualApprox(s2, s2orig, EqTolerance) { t.Errorf("s2 changes during multo") } DivTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("DivTo doesn't give correct answer reusing dst") } dstShort := []complex128{1} if !Panics(func() { DivTo(dstShort, s1, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s1short := []complex128{1} if !Panics(func() { DivTo(dst1, s1short, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s2short := []complex128{1} if !Panics(func() { DivTo(dst1, s1, s2short) }) { t.Errorf("Did not panic with s2 wrong length") } } func TestDot(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i} s2 := []complex128{-3 + 4i, 4 + 3i, 5 + 2i, -6 + 1i} truth := 16 + 24i ans := Dot(s1, s2) if ans != truth { t.Errorf("Dot product computed incorrectly. Expected %v, Found %v.", truth, ans) } // Test that it panics if !Panics(func() { Dot(make([]complex128, 2), make([]complex128, 3)) }) { t.Errorf("Did not panic with length mismatch") } } func TestEquals(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i} s2 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i} if !Equal(s1, s2) { t.Errorf("Equal slices returned as unequal") } s2 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i + 1e-14} if Equal(s1, s2) { t.Errorf("Unequal slices returned as equal") } if Equal(s1, []complex128{}) { t.Errorf("Unequal slice lengths returned as equal") } } func TestEqualApprox(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i} s2 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i + 1e-10} if EqualApprox(s1, s2, 1e-13) { t.Errorf("Unequal slices returned as equal for absolute") } if !EqualApprox(s1, s2, 1e-5) { t.Errorf("Equal slices returned as unequal for absolute") } s1 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, 1000 + 1000i} s2 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, (1000 + 1000i) * (1 + 1e-7)} if EqualApprox(s1, s2, 1e-8) { t.Errorf("Unequal slices returned as equal for relative") } if !EqualApprox(s1, s2, 1e-5) { t.Errorf("Equal slices returned as unequal for relative") } if EqualApprox(s1, []complex128{}, 1e-5) { t.Errorf("Unequal slice lengths returned as equal") } } func TestEqualFunc(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i} s2 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i} eq := func(x, y complex128) bool { return x == y } if !EqualFunc(s1, s2, eq) { t.Errorf("Equal slices returned as unequal") } s2 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i + 1e-14} if EqualFunc(s1, s2, eq) { t.Errorf("Unequal slices returned as equal") } if EqualFunc(s1, []complex128{}, eq) { t.Errorf("Unequal slice lengths returned as equal") } } func TestEqualLengths(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i} s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i} s3 := []complex128{1 + 1i, 2 + 2i, 3 + 3i} if !EqualLengths(s1, s2) { t.Errorf("Equal lengths returned as unequal") } if EqualLengths(s1, s3) { t.Errorf("Unequal lengths returned as equal") } if !EqualLengths(s1) { t.Errorf("Single slice returned as unequal") } if !EqualLengths() { t.Errorf("No slices returned as unequal") } } func eqIntSlice(one, two []int) string { if len(one) != len(two) { return "Length mismatch" } for i, val := range one { if val != two[i] { return "Index " + strconv.Itoa(i) + " mismatch" } } return "" } func TestFind(t *testing.T) { s := []complex128{3 + 1i, 4 - 1i, 1 + 2i, 7 + 10i, 5 - 100i} f := func(v complex128) bool { return cmplx.Abs(v) > 3.5 } allTrueInds := []int{1, 3, 4} // Test finding first two elements inds, err := Find(nil, f, s, 2) if err != nil { t.Errorf("Find first two: Improper error return") } trueInds := allTrueInds[:2] str := eqIntSlice(inds, trueInds) if str != "" { t.Errorf("Find first two: " + str) } // Test finding no elements with non nil slice inds = []int{1, 2, 3, 4, 5, 6} inds, err = Find(inds, f, s, 0) if err != nil { t.Errorf("Find no elements: Improper error return") } str = eqIntSlice(inds, []int{}) if str != "" { t.Errorf("Find no non-nil: " + str) } // Test finding first two elements with non nil slice inds = []int{1, 2, 3, 4, 5, 6} inds, err = Find(inds, f, s, 2) if err != nil { t.Errorf("Find first two non-nil: Improper error return") } str = eqIntSlice(inds, trueInds) if str != "" { t.Errorf("Find first two non-nil: " + str) } // Test finding too many elements inds, err = Find(inds, f, s, 4) if err == nil { t.Errorf("Request too many: No error returned") } str = eqIntSlice(inds, allTrueInds) if str != "" { t.Errorf("Request too many: Does not match all of the inds: " + str) } // Test finding all elements inds, err = Find(nil, f, s, -1) if err != nil { t.Errorf("Find all: Improper error returned") } str = eqIntSlice(inds, allTrueInds) if str != "" { t.Errorf("Find all: Does not match all of the inds: " + str) } } func TestHasNaN(t *testing.T) { for i, test := range []struct { s []complex128 ans bool }{ {}, { s: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, }, { s: []complex128{1 + 1i, cmplx.NaN(), 3 + 3i, 4 + 4i}, ans: true, }, { s: []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()}, ans: true, }, } { b := HasNaN(test.s) if b != test.ans { t.Errorf("HasNaN mismatch case %d. Expected %v, Found %v", i, test.ans, b) } } } func TestImag(t *testing.T) { for i, test := range []struct { dst []float64 src []complex128 want []float64 panics bool }{ {}, { dst: make([]float64, 4), src: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, want: []float64{1, 2, 3, 4}, }, { dst: make([]float64, 3), src: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, panics: true, }, { dst: make([]float64, 4), src: []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()}, want: []float64{1, 2, 3, math.NaN()}, }, } { var got []float64 panicked := Panics(func() { got = Imag(test.dst, test.src) }) if panicked != test.panics { if panicked { t.Errorf("unexpected panic for test %d", i) } else { t.Errorf("expected panic for test %d", i) } } if panicked || test.panics { continue } if !floats.Same(got, test.dst) { t.Errorf("mismatch between dst and return test %d: got:%v want:%v", i, got, test.dst) } if !floats.Same(got, test.want) { t.Errorf("unexpected result for test %d: got:%v want:%v", i, got, test.want) } } } func TestLogSpan(t *testing.T) { // FIXME(kortschak) receiver1 := make([]complex128, 6) truth := []complex128{0.001, 0.01, 0.1, 1, 10, 100} receiver2 := LogSpan(receiver1, 0.001, 100) tst := make([]complex128, 6) for i := range truth { tst[i] = receiver1[i] / truth[i] } comp := make([]complex128, 6) for i := range comp { comp[i] = 1 } areSlicesEqual(t, comp, tst, "Improper logspace from mutator") for i := range truth { tst[i] = receiver2[i] / truth[i] } areSlicesEqual(t, comp, tst, "Improper logspace from returned slice") if !Panics(func() { LogSpan(nil, 1, 5) }) { t.Errorf("Span accepts nil argument") } if !Panics(func() { LogSpan(make([]complex128, 1), 1, 5) }) { t.Errorf("Span accepts argument of len = 1") } } func TestMaxAbsAndIdx(t *testing.T) { for _, test := range []struct { in []complex128 wantIdx int wantVal complex128 desc string }{ { in: []complex128{3 + 1i, 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i}, wantIdx: 3, wantVal: 7 + 1i, desc: "with only finite entries", }, { in: []complex128{cmplx.NaN(), 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i}, wantIdx: 3, wantVal: 7 + 1i, desc: "with leading NaN", }, { in: []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN()}, wantIdx: 0, wantVal: cmplx.NaN(), desc: "when only NaN elements exist", }, { in: []complex128{cmplx.NaN(), cmplx.Inf()}, wantIdx: 1, wantVal: cmplx.Inf(), desc: "leading NaN followed by Inf", }, } { ind := MaxAbsIdx(test.in) if ind != test.wantIdx { t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx) } val := MaxAbs(test.in) if !cscalar.Same(val, test.wantVal) { t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal) } } } func TestMinAbsAndIdx(t *testing.T) { for _, test := range []struct { in []complex128 wantIdx int wantVal complex128 desc string }{ { in: []complex128{3 + 1i, 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i}, wantIdx: 2, wantVal: 1 + 1i, desc: "with only finite entries", }, { in: []complex128{cmplx.NaN(), 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i}, wantIdx: 2, wantVal: 1 + 1i, desc: "with leading NaN", }, { in: []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN()}, wantIdx: 0, wantVal: cmplx.NaN(), desc: "when only NaN elements exist", }, { in: []complex128{cmplx.NaN(), cmplx.Inf()}, wantIdx: 1, wantVal: cmplx.Inf(), desc: "leading NaN followed by Inf", }, } { ind := MinAbsIdx(test.in) if ind != test.wantIdx { t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx) } val := MinAbs(test.in) if !cscalar.Same(val, test.wantVal) { t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal) } } } func TestMul(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i} s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i} ans := []complex128{0 + 2i, 0 + 8i, 0 + 18i} Mul(s1, s2) if !EqualApprox(s1, ans, EqTolerance) { t.Errorf("Mul doesn't give correct answer. Expected %v, Found %v", ans, s1) } s1short := []complex128{1} if !Panics(func() { Mul(s1short, s2) }) { t.Errorf("Did not panic with unequal lengths") } s2short := []complex128{1} if !Panics(func() { Mul(s1, s2short) }) { t.Errorf("Did not panic with unequal lengths") } } func TestMulConj(t *testing.T) { s1 := []complex128{2 + 1i, 3 + 2i, 4 + 3i} s2 := []complex128{1 + 2i, 2 + 3i, 3 + 4i} s2orig := []complex128{1 + 2i, 2 + 3i, 3 + 4i} ans := []complex128{4 - 3i, 12 - 5i, 24 - 7i} MulConj(s1, s2) if !Equal(s1, ans) { t.Errorf("MulConj doesn't give correct answer. Expected %v, Found %v", ans, s1) } if !Equal(s2, s2orig) { t.Errorf("s2 changes during MulTo") } s1short := []complex128{1} if !Panics(func() { MulConj(s1short, s2) }) { t.Errorf("Did not panic with unequal lengths") } s2short := []complex128{1} if !Panics(func() { MulConj(s1, s2short) }) { t.Errorf("Did not panic with unequal lengths") } } func TestMulConjTo(t *testing.T) { s1 := []complex128{2 + 1i, 3 + 2i, 4 + 3i} s1orig := []complex128{2 + 1i, 3 + 2i, 4 + 3i} s2 := []complex128{1 + 2i, 2 + 3i, 3 + 4i} s2orig := []complex128{1 + 2i, 2 + 3i, 3 + 4i} dst1 := make([]complex128, 3) ans := []complex128{4 - 3i, 12 - 5i, 24 - 7i} dst2 := MulConjTo(dst1, s1, s2) if !Equal(dst1, ans) { t.Errorf("MulConjTo doesn't give correct answer in mutated slice") } if !Equal(dst2, ans) { t.Errorf("MulConjTo doesn't give correct answer in returned slice") } if !Equal(s1, s1orig) { t.Errorf("S1 changes during MulConjTo") } if !Equal(s2, s2orig) { t.Errorf("s2 changes during MulConjTo") } MulConjTo(dst1, s1, s2) if !Equal(dst1, ans) { t.Errorf("MulConjTo doesn't give correct answer reusing dst") } dstShort := []complex128{1} if !Panics(func() { MulConjTo(dstShort, s1, s2) }) { t.Errorf("Did not panic with dst wrong length") } s1short := []complex128{1} if !Panics(func() { MulConjTo(dst1, s1short, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s2short := []complex128{1} if !Panics(func() { MulConjTo(dst1, s1, s2short) }) { t.Errorf("Did not panic with s2 wrong length") } } func TestMulTo(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i} s1orig := []complex128{1 + 1i, 2 + 2i, 3 + 3i} s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i} s2orig := []complex128{1 + 1i, 2 + 2i, 3 + 3i} dst1 := make([]complex128, 3) ans := []complex128{0 + 2i, 0 + 8i, 0 + 18i} dst2 := MulTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("MulTo doesn't give correct answer in mutated slice") } if !EqualApprox(dst2, ans, EqTolerance) { t.Errorf("MulTo doesn't give correct answer in returned slice") } if !EqualApprox(s1, s1orig, EqTolerance) { t.Errorf("S1 changes during multo") } if !EqualApprox(s2, s2orig, EqTolerance) { t.Errorf("s2 changes during multo") } MulTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("MulTo doesn't give correct answer reusing dst") } dstShort := []complex128{1} if !Panics(func() { MulTo(dstShort, s1, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s1short := []complex128{1} if !Panics(func() { MulTo(dst1, s1short, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s2short := []complex128{1} if !Panics(func() { MulTo(dst1, s1, s2short) }) { t.Errorf("Did not panic with s2 wrong length") } } // Complexify func TestNearestIdx(t *testing.T) { for _, test := range []struct { in []complex128 query complex128 want int desc string }{ { in: []complex128{6.2, 3, 5, 6.2, 8}, query: 2, want: 1, desc: "Wrong index returned when value is less than all of elements", }, { in: []complex128{6.2, 3, 5, 6.2, 8}, query: 9, want: 4, desc: "Wrong index returned when value is greater than all of elements", }, { in: []complex128{6.2, 3, 5, 6.2, 8}, query: 3.1, want: 1, desc: "Wrong index returned when value is greater than closest element", }, { in: []complex128{6.2, 3, 5, 6.2, 8}, query: 2.9, want: 1, desc: "Wrong index returned when value is less than closest element", }, { in: []complex128{6.2, 3, 5, 6.2, 8}, query: 3, want: 1, desc: "Wrong index returned when value is equal to element", }, { in: []complex128{6.2, 3, 5, 6.2, 8}, query: 6.2, want: 0, desc: "Wrong index returned when value is equal to several elements", }, { in: []complex128{6.2, 3, 5, 6.2, 8}, query: 4, want: 1, desc: "Wrong index returned when value is exactly between two closest elements", }, { in: []complex128{cmplx.NaN(), 3, 2, -1}, query: 2, want: 2, desc: "Wrong index returned when initial element is NaN", }, { in: []complex128{0, cmplx.NaN(), -1, 2}, query: cmplx.NaN(), want: 0, desc: "Wrong index returned when query is NaN and a NaN element exists", }, { in: []complex128{0, cmplx.NaN(), -1, 2}, query: cmplx.Inf(), want: 3, desc: "Wrong index returned when query is Inf and no Inf element exists", }, { in: []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN()}, query: 1, want: 0, desc: "Wrong index returned when query is a number and only NaN elements exist", }, { in: []complex128{cmplx.NaN(), cmplx.Inf()}, query: 1, want: 1, desc: "Wrong index returned when query is a number and single NaN precedes Inf", }, } { ind := NearestIdx(test.in, test.query) if ind != test.want { t.Errorf(test.desc+": got:%d want:%d", ind, test.want) } } } func TestNorm(t *testing.T) { s := []complex128{-1, -3.4, 5, -6} val := Norm(s, math.Inf(1)) truth := 6.0 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } // http://www.wolframalpha.com/input/?i=%28%28-1%29%5E2+%2B++%28-3.4%29%5E2+%2B+5%5E2%2B++6%5E2%29%5E%281%2F2%29 val = Norm(s, 2) truth = 8.5767126569566267590651614132751986658027271236078592 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } // http://www.wolframalpha.com/input/?i=%28%28%7C-1%7C%29%5E3+%2B++%28%7C-3.4%7C%29%5E3+%2B+%7C5%7C%5E3%2B++%7C6%7C%5E3%29%5E%281%2F3%29 val = Norm(s, 3) truth = 7.2514321388020228478109121239004816430071237369356233 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } //http://www.wolframalpha.com/input/?i=%7C-1%7C+%2B+%7C-3.4%7C+%2B+%7C5%7C%2B++%7C6%7C val = Norm(s, 1) truth = 15.4 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } } func TestProd(t *testing.T) { s := []complex128{} val := Prod(s) if val != 1 { t.Errorf("Val not returned as default when slice length is zero") } s = []complex128{3, 4, 1, 7, 5} val = Prod(s) if val != 420 { t.Errorf("Wrong prod returned. Expected %v returned %v", 420, val) } } func TestReverse(t *testing.T) { for _, s := range [][]complex128{ {0}, {1, 0}, {2, 1, 0}, {3, 2, 1, 0}, {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, } { Reverse(s) for i, v := range s { if v != complex(float64(i), 0) { t.Errorf("unexpected values for element %d: got:%v want:%v", i, v, i) } } } } func TestReal(t *testing.T) { for i, test := range []struct { dst []float64 src []complex128 want []float64 panics bool }{ {}, { dst: make([]float64, 4), src: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, want: []float64{1, 2, 3, 4}, }, { dst: make([]float64, 3), src: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, panics: true, }, { dst: make([]float64, 4), src: []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()}, want: []float64{1, 2, 3, math.NaN()}, }, } { var got []float64 panicked := Panics(func() { got = Real(test.dst, test.src) }) if panicked != test.panics { if panicked { t.Errorf("unexpected panic for test %d", i) } else { t.Errorf("expected panic for test %d", i) } } if panicked || test.panics { continue } if !floats.Same(got, test.dst) { t.Errorf("mismatch between dst and return test %d: got:%v want:%v", i, got, test.dst) } if !floats.Same(got, test.want) { t.Errorf("unexpected result for test %d: got:%v want:%v", i, got, test.want) } } } func TestSame(t *testing.T) { s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i} s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i} if !Same(s1, s2) { t.Errorf("Equal slices returned as unequal") } s2 = []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i + 1e-14} if Same(s1, s2) { t.Errorf("Unequal slices returned as equal") } if Same(s1, []complex128{}) { t.Errorf("Unequal slice lengths returned as equal") } s1 = []complex128{1 + 1i, 2 + 2i, cmplx.NaN(), 4 + 4i} s2 = []complex128{1 + 1i, 2 + 2i, cmplx.NaN(), 4 + 4i} if !Same(s1, s2) { t.Errorf("Slices with matching NaN values returned as unequal") } s1 = []complex128{1 + 1i, 2 + 2i, cmplx.NaN(), 4 + 4i} s2 = []complex128{1 + 1i, cmplx.NaN(), 3 + 3i, 4 + 4i} if Same(s1, s2) { t.Errorf("Slices with unmatching NaN values returned as equal") } } func TestScale(t *testing.T) { s := []complex128{3, 4, 1, 7, 5} c := 4 + 5i truth := []complex128{12 + 15i, 16 + 20i, 4 + 5i, 28 + 35i, 20 + 25i} Scale(c, s) areSlicesEqual(t, truth, s, "Bad scaling") } func TestScaleReal(t *testing.T) { s := []complex128{3 + 4i, 4 + 5i, 1 + 2i, 7 + 6i, 5 + 2i} f := 5.0 truth := []complex128{15 + 20i, 20 + 25i, 5 + 10i, 35 + 30i, 25 + 10i} ScaleReal(f, s) areSlicesEqual(t, truth, s, "Bad scaling") } func TestScaleRealTo(t *testing.T) { s := []complex128{3 + 4i, 4 + 5i, 1 + 2i, 7 + 6i, 5 + 2i} sCopy := make([]complex128, len(s)) copy(sCopy, s) f := 5.0 truth := []complex128{15 + 20i, 20 + 25i, 5 + 10i, 35 + 30i, 25 + 10i} dst := make([]complex128, len(s)) ScaleRealTo(dst, f, s) if !Same(dst, truth) { t.Errorf("ScaleRealTo dst does not match. Got %v, want %v", dst, truth) } if !Same(s, sCopy) { t.Errorf("SourceRealTo s modified during call. Got %v, want %v", s, sCopy) } } func TestScaleTo(t *testing.T) { s := []complex128{3, 4, 1, 7, 5} sCopy := make([]complex128, len(s)) copy(sCopy, s) c := 4 + 5i truth := []complex128{12 + 15i, 16 + 20i, 4 + 5i, 28 + 35i, 20 + 25i} dst := make([]complex128, len(s)) ScaleTo(dst, c, s) if !Same(dst, truth) { t.Errorf("ScaleTo dst does not match. Got %v, want %v", dst, truth) } if !Same(s, sCopy) { t.Errorf("SourceTo s modified during call. Got %v, want %v", s, sCopy) } } func TestSpan(t *testing.T) { receiver1 := make([]complex128, 5) truth := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i, 5 + 5i} receiver2 := Span(receiver1, 1+1i, 5+5i) areSlicesEqual(t, truth, receiver1, "Improper linspace from mutator") areSlicesEqual(t, truth, receiver2, "Improper linspace from returned slice") receiver1 = make([]complex128, 6) truth = []complex128{0, 0.2 + 0.4i, 0.4 + 0.8i, 0.6 + 1.2i, 0.8 + 1.6i, 1 + 2i} Span(receiver1, 0, 1+2i) areSlicesEqual(t, truth, receiver1, "Improper linspace") if !Panics(func() { Span(nil, 1, 5) }) { t.Errorf("Span accepts nil argument") } if !Panics(func() { Span(make([]complex128, 1), 1, 5) }) { t.Errorf("Span accepts argument of len = 1") } for _, test := range []struct { n int l, u complex128 want []complex128 }{ { n: 5, l: cmplx.Inf(), u: cmplx.Inf(), want: []complex128{cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf()}, }, { n: 5, l: cmplx.Inf(), u: cmplx.NaN(), want: []complex128{cmplx.Inf(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN()}, }, { n: 5, l: cmplx.NaN(), u: cmplx.Inf(), want: []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.Inf()}, }, { n: 5, l: 42, u: cmplx.Inf(), want: []complex128{42, cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf()}, }, { n: 5, l: 42, u: cmplx.NaN(), want: []complex128{42, cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN()}, }, { n: 5, l: cmplx.Inf(), u: 42, want: []complex128{cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), 42}, }, { n: 5, l: cmplx.NaN(), u: 42, want: []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), 42}, }, } { got := Span(make([]complex128, test.n), test.l, test.u) areSlicesSame(t, test.want, got, fmt.Sprintf("Unexpected slice of length %d for %f to %f", test.n, test.l, test.u)) } } func TestSub(t *testing.T) { s := []complex128{3 + 2i, 4 + 3i, 1 + 7i, 7 + 1i, 5 - 1i} v := []complex128{1 + 1i, 2 + 4i, 3, 4, 5 - 1i} truth := []complex128{2 + 1i, 2 - 1i, -2 + 7i, 3 + 1i, 0} Sub(s, v) areSlicesEqual(t, truth, s, "Bad subtract") // Test that it panics if !Panics(func() { Sub(make([]complex128, 2), make([]complex128, 3)) }) { t.Errorf("Did not panic with length mismatch") } } func TestSubTo(t *testing.T) { s := []complex128{3 + 2i, 4 + 3i, 1 + 7i, 7 + 1i, 5 - 1i} v := []complex128{1 + 1i, 2 + 4i, 3, 4, 5 - 1i} truth := []complex128{2 + 1i, 2 - 1i, -2 + 7i, 3 + 1i, 0} dst1 := make([]complex128, len(s)) dst2 := SubTo(dst1, s, v) areSlicesEqual(t, truth, dst1, "Bad subtract from mutator") areSlicesEqual(t, truth, dst2, "Bad subtract from returned slice") // Test that all mismatch combinations panic if !Panics(func() { SubTo(make([]complex128, 2), make([]complex128, 3), make([]complex128, 3)) }) { t.Errorf("Did not panic with dst different length") } if !Panics(func() { SubTo(make([]complex128, 3), make([]complex128, 2), make([]complex128, 3)) }) { t.Errorf("Did not panic with subtractor different length") } if !Panics(func() { SubTo(make([]complex128, 3), make([]complex128, 3), make([]complex128, 2)) }) { t.Errorf("Did not panic with subtractee different length") } } func TestSum(t *testing.T) { s := []complex128{} val := Sum(s) if val != 0 { t.Errorf("Val not returned as default when slice length is zero") } s = []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i} val = Sum(s) if val != 20+15i { t.Errorf("Wrong sum returned") } } func randomSlice(l int, src rand.Source) []complex128 { rnd := rand.New(src) s := make([]complex128, l) for i := range s { s[i] = complex(rnd.Float64(), rnd.Float64()) } return s } func benchmarkAdd(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Add(s1, s2) } } func BenchmarkAddSmall(b *testing.B) { benchmarkAdd(b, Small) } func BenchmarkAddMed(b *testing.B) { benchmarkAdd(b, Medium) } func BenchmarkAddLarge(b *testing.B) { benchmarkAdd(b, Large) } func BenchmarkAddHuge(b *testing.B) { benchmarkAdd(b, Huge) } func benchmarkAddTo(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { AddTo(dst, s1, s2) } } func BenchmarkAddToSmall(b *testing.B) { benchmarkAddTo(b, Small) } func BenchmarkAddToMed(b *testing.B) { benchmarkAddTo(b, Medium) } func BenchmarkAddToLarge(b *testing.B) { benchmarkAddTo(b, Large) } func BenchmarkAddToHuge(b *testing.B) { benchmarkAddTo(b, Huge) } func benchmarkCumProd(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { CumProd(dst, s) } } func BenchmarkCumProdSmall(b *testing.B) { benchmarkCumProd(b, Small) } func BenchmarkCumProdMed(b *testing.B) { benchmarkCumProd(b, Medium) } func BenchmarkCumProdLarge(b *testing.B) { benchmarkCumProd(b, Large) } func BenchmarkCumProdHuge(b *testing.B) { benchmarkCumProd(b, Huge) } func benchmarkCumSum(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { CumSum(dst, s) } } func BenchmarkCumSumSmall(b *testing.B) { benchmarkCumSum(b, Small) } func BenchmarkCumSumMed(b *testing.B) { benchmarkCumSum(b, Medium) } func BenchmarkCumSumLarge(b *testing.B) { benchmarkCumSum(b, Large) } func BenchmarkCumSumHuge(b *testing.B) { benchmarkCumSum(b, Huge) } func benchmarkDiv(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Div(dst, s) } } func BenchmarkDivSmall(b *testing.B) { benchmarkDiv(b, Small) } func BenchmarkDivMed(b *testing.B) { benchmarkDiv(b, Medium) } func BenchmarkDivLarge(b *testing.B) { benchmarkDiv(b, Large) } func BenchmarkDivHuge(b *testing.B) { benchmarkDiv(b, Huge) } func benchmarkDivTo(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { DivTo(dst, s1, s2) } } func BenchmarkDivToSmall(b *testing.B) { benchmarkDivTo(b, Small) } func BenchmarkDivToMed(b *testing.B) { benchmarkDivTo(b, Medium) } func BenchmarkDivToLarge(b *testing.B) { benchmarkDivTo(b, Large) } func BenchmarkDivToHuge(b *testing.B) { benchmarkDivTo(b, Huge) } func benchmarkSub(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Sub(s1, s2) } } func BenchmarkSubSmall(b *testing.B) { benchmarkSub(b, Small) } func BenchmarkSubMed(b *testing.B) { benchmarkSub(b, Medium) } func BenchmarkSubLarge(b *testing.B) { benchmarkSub(b, Large) } func BenchmarkSubHuge(b *testing.B) { benchmarkSub(b, Huge) } func benchmarkSubTo(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { SubTo(dst, s1, s2) } } func BenchmarkSubToSmall(b *testing.B) { benchmarkSubTo(b, Small) } func BenchmarkSubToMed(b *testing.B) { benchmarkSubTo(b, Medium) } func BenchmarkSubToLarge(b *testing.B) { benchmarkSubTo(b, Large) } func BenchmarkSubToHuge(b *testing.B) { benchmarkSubTo(b, Huge) } func benchmarkDot(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Dot(s1, s2) } } func BenchmarkDotSmall(b *testing.B) { benchmarkDot(b, Small) } func BenchmarkDotMed(b *testing.B) { benchmarkDot(b, Medium) } func BenchmarkDotLarge(b *testing.B) { benchmarkDot(b, Large) } func BenchmarkDotHuge(b *testing.B) { benchmarkDot(b, Huge) } func benchmarkAddScaledTo(b *testing.B, size int) { src := rand.NewSource(1) dst := randomSlice(size, src) y := randomSlice(size, src) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { AddScaledTo(dst, y, 2.3, s) } } func BenchmarkAddScaledToSmall(b *testing.B) { benchmarkAddScaledTo(b, Small) } func BenchmarkAddScaledToMedium(b *testing.B) { benchmarkAddScaledTo(b, Medium) } func BenchmarkAddScaledToLarge(b *testing.B) { benchmarkAddScaledTo(b, Large) } func BenchmarkAddScaledToHuge(b *testing.B) { benchmarkAddScaledTo(b, Huge) } func benchmarkScale(b *testing.B, size int) { src := rand.NewSource(1) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i += 2 { Scale(2.0, dst) Scale(0.5, dst) } } func BenchmarkScaleSmall(b *testing.B) { benchmarkScale(b, Small) } func BenchmarkScaleMedium(b *testing.B) { benchmarkScale(b, Medium) } func BenchmarkScaleLarge(b *testing.B) { benchmarkScale(b, Large) } func BenchmarkScaleHuge(b *testing.B) { benchmarkScale(b, Huge) } func benchmarkNorm2(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Norm(s, 2) } } func BenchmarkNorm2Small(b *testing.B) { benchmarkNorm2(b, Small) } func BenchmarkNorm2Medium(b *testing.B) { benchmarkNorm2(b, Medium) } func BenchmarkNorm2Large(b *testing.B) { benchmarkNorm2(b, Large) } func BenchmarkNorm2Huge(b *testing.B) { benchmarkNorm2(b, Huge) } golang-gonum-v1-gonum-0.14.0/cmplxs/cscalar/000077500000000000000000000000001450372207100205545ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/cmplxs/cscalar/cscalar.go000066400000000000000000000052221450372207100225140ustar00rootroot00000000000000// 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 cscalar import ( "math" "math/cmplx" "gonum.org/v1/gonum/floats/scalar" ) // EqualWithinAbs returns true when a and b have an absolute difference // not greater than tol. func EqualWithinAbs(a, b complex128, tol float64) bool { return a == b || cmplx.Abs(a-b) <= tol } // minNormalFloat64 is the smallest normal number. For 64 bit IEEE-754 // floats this is 2^{-1022}. const minNormalFloat64 = 0x1p-1022 // EqualWithinRel returns true when the difference between a and b // is not greater than tol times the greater absolute value of a and b, // // abs(a-b) <= tol * max(abs(a), abs(b)). func EqualWithinRel(a, b complex128, tol float64) bool { if a == b { return true } delta := cmplx.Abs(a - b) if delta <= minNormalFloat64 { return delta <= tol*minNormalFloat64 } // We depend on the division in this relationship to identify // infinities. return delta/math.Max(cmplx.Abs(a), cmplx.Abs(b)) <= tol } // EqualWithinAbsOrRel returns true when a and b are equal to within // the absolute or relative tolerances. See EqualWithinAbs and // EqualWithinRel for details. func EqualWithinAbsOrRel(a, b complex128, absTol, relTol float64) bool { return EqualWithinAbs(a, b, absTol) || EqualWithinRel(a, b, relTol) } // ParseWithNA converts the string s to a complex128 in value. // If s equals missing, weight is returned as 0, otherwise 1. func ParseWithNA(s, missing string) (value complex128, weight float64, err error) { if s == missing { return 0, 0, nil } value, err = parse(s) if err == nil { weight = 1 } return value, weight, err } // 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 complex128, prec int) complex128 { if x == 0 { // Make sure zero is returned // without the negative bit set. return 0 } return complex(scalar.Round(real(x), prec), scalar.Round(imag(x), prec)) } // 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 complex128, prec int) complex128 { if x == 0 { // Make sure zero is returned // without the negative bit set. return 0 } return complex(scalar.RoundEven(real(x), prec), scalar.RoundEven(imag(x), prec)) } // Same returns true when the inputs have the same value, allowing NaN equality. func Same(a, b complex128) bool { return a == b || (cmplx.IsNaN(a) && cmplx.IsNaN(b)) } golang-gonum-v1-gonum-0.14.0/cmplxs/cscalar/cscalar_test.go000066400000000000000000000150611450372207100235550ustar00rootroot00000000000000// 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 cscalar import ( "math" "math/cmplx" "testing" ) func TestEqualsRelative(t *testing.T) { equalityTests := []struct { a, b float64 tol float64 equal bool }{ {1000000, 1000001, 0, true}, {1000001, 1000000, 0, true}, {10000, 10001, 0, false}, {10001, 10000, 0, false}, {-1000000, -1000001, 0, true}, {-1000001, -1000000, 0, true}, {-10000, -10001, 0, false}, {-10001, -10000, 0, false}, {1.0000001, 1.0000002, 0, true}, {1.0000002, 1.0000001, 0, true}, {1.0002, 1.0001, 0, false}, {1.0001, 1.0002, 0, false}, {-1.000001, -1.000002, 0, true}, {-1.000002, -1.000001, 0, true}, {-1.0001, -1.0002, 0, false}, {-1.0002, -1.0001, 0, false}, {0.000000001000001, 0.000000001000002, 0, true}, {0.000000001000002, 0.000000001000001, 0, true}, {0.000000000001002, 0.000000000001001, 0, false}, {0.000000000001001, 0.000000000001002, 0, false}, {-0.000000001000001, -0.000000001000002, 0, true}, {-0.000000001000002, -0.000000001000001, 0, true}, {-0.000000000001002, -0.000000000001001, 0, false}, {-0.000000000001001, -0.000000000001002, 0, false}, {0, 0, 0, true}, {0, -0, 0, true}, {-0, -0, 0, true}, {0.00000001, 0, 0, false}, {0, 0.00000001, 0, false}, {-0.00000001, 0, 0, false}, {0, -0.00000001, 0, false}, {0, 1e-310, 0.01, true}, {1e-310, 0, 0.01, true}, {1e-310, 0, 0.000001, false}, {0, 1e-310, 0.000001, false}, {0, -1e-310, 0.1, true}, {-1e-310, 0, 0.1, true}, {-1e-310, 0, 0.00000001, false}, {0, -1e-310, 0.00000001, false}, {math.Inf(1), math.Inf(1), 0, true}, {math.Inf(1), math.MaxFloat64, 0, false}, {math.NaN(), math.NaN(), 0, false}, {math.NaN(), 0, 0, false}, {-0, math.NaN(), 0, false}, {math.NaN(), -0, 0, false}, {0, math.NaN(), 0, false}, {math.NaN(), math.Inf(1), 0, false}, {math.Inf(1), math.NaN(), 0, false}, {math.NaN(), math.MaxFloat64, 0, false}, {math.MaxFloat64, math.NaN(), 0, false}, {math.NaN(), -math.MaxFloat64, 0, false}, {-math.MaxFloat64, math.NaN(), 0, false}, {math.NaN(), math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, math.NaN(), 0, false}, {math.NaN(), -math.SmallestNonzeroFloat64, 0, false}, {-math.SmallestNonzeroFloat64, math.NaN(), 0, false}, {1.000000001, -1.0, 0, false}, {-1.0, 1.000000001, 0, false}, {-1.000000001, 1.0, 0, false}, {1.0, -1.000000001, 0, false}, {10 * math.SmallestNonzeroFloat64, 10 * -math.SmallestNonzeroFloat64, 0, true}, {1e11 * math.SmallestNonzeroFloat64, 1e11 * -math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, -math.SmallestNonzeroFloat64, 0, true}, {-math.SmallestNonzeroFloat64, math.SmallestNonzeroFloat64, 0, true}, {math.SmallestNonzeroFloat64, 0, 0, true}, {0, math.SmallestNonzeroFloat64, 0, true}, {-math.SmallestNonzeroFloat64, 0, 0, true}, {0, -math.SmallestNonzeroFloat64, 0, true}, {0.000000001, -math.SmallestNonzeroFloat64, 0, false}, {0.000000001, math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, 0.000000001, 0, false}, {-math.SmallestNonzeroFloat64, 0.000000001, 0, false}, } for _, ts := range equalityTests { if ts.tol == 0 { ts.tol = 1e-5 } for _, comp := range []struct{ a, b complex128 }{ {a: complex(ts.a, 0), b: complex(ts.b, 0)}, {a: complex(0, ts.a), b: complex(0, ts.b)}, {a: complex(ts.a, ts.a), b: complex(ts.b, ts.b)}, } { if equal := EqualWithinRel(comp.a, comp.b, ts.tol); equal != ts.equal { t.Errorf("Relative equality of %g and %g with tolerance %g returned: %v. Expected: %v", comp.a, comp.b, ts.tol, equal, ts.equal) } } } } func TestRoundEven(t *testing.T) { for _, test := range []struct { x complex128 prec int want complex128 }{ {x: 0, prec: 1, want: 0}, {x: cmplx.Inf(), prec: 1, want: cmplx.Inf()}, {x: cmplx.NaN(), prec: 1, want: cmplx.NaN()}, {x: func() complex128 { var f complex128; return -f }(), prec: 1, want: 0}, {x: math.MaxFloat64 / 2, prec: 1, want: math.MaxFloat64 / 2}, {x: 1 << 64, prec: 1, want: 1 << 64}, {x: 454.4445, prec: 3, want: 454.444}, {x: 454.44445, prec: 4, want: 454.4444}, {x: 0.42499, prec: 4, want: 0.425}, {x: 0.42599, prec: 4, want: 0.426}, {x: 0.424999999999993, prec: 2, want: 0.42}, {x: 0.425, prec: 2, want: 0.42}, {x: 0.425000000000001, prec: 2, want: 0.43}, {x: 123.4244999999999, prec: 3, want: 123.424}, {x: 123.4245, prec: 3, want: 123.424}, {x: 123.4245000000001, prec: 3, want: 123.425}, {x: 454.45, prec: 0, want: 454}, {x: 454.45, prec: 1, want: 454.4}, {x: 454.45, prec: 2, want: 454.45}, {x: 454.45, prec: 3, want: 454.45}, {x: 454.445, prec: 0, want: 454}, {x: 454.445, prec: 1, want: 454.4}, {x: 454.445, prec: 2, want: 454.44}, {x: 454.445, prec: 3, want: 454.445}, {x: 454.445, prec: 4, want: 454.445}, {x: 454.55, prec: 0, want: 455}, {x: 454.55, prec: 1, want: 454.6}, {x: 454.55, prec: 2, want: 454.55}, {x: 454.55, prec: 3, want: 454.55}, {x: 454.455, prec: 0, want: 454}, {x: 454.455, prec: 1, want: 454.5}, {x: 454.455, prec: 2, want: 454.46}, {x: 454.455, prec: 3, want: 454.455}, {x: 454.455, prec: 4, want: 454.455}, // Negative precision. {x: 454.45, prec: -1, want: 450}, {x: 454.45, prec: -2, want: 500}, {x: 500, prec: -3, want: 0}, {x: 500, prec: -4, want: 0}, {x: 1500, prec: -3, want: 2000}, {x: 1500, prec: -4, want: 0}, } { for _, sign := range []complex128{1, -1} { got := RoundEven(sign*test.x, test.prec) want := sign * test.want if want == 0 { want = 0 } // FIXME(kortschak): Complexify this. if (got != want || math.Signbit(real(got)) != math.Signbit(real(want))) && !(math.IsNaN(real(got)) && math.IsNaN(real(want))) { t.Errorf("unexpected result for RoundEven(%g, %d): got: %g, want: %g", sign*test.x, test.prec, got, want) } } } } func TestSame(t *testing.T) { t.Parallel() for _, test := range []struct { a, b complex128 want bool }{ {a: 0, b: 0, want: true}, {a: 1, b: 1, want: true}, {a: -1, b: 1, want: false}, {a: 0, b: 1, want: false}, {a: 1, b: 0, want: false}, {a: -1, b: 1, want: false}, {a: cmplx.NaN(), b: cmplx.NaN(), want: true}, {a: 1, b: cmplx.NaN(), want: false}, {a: cmplx.Inf(), b: cmplx.NaN(), want: false}, {a: cmplx.NaN(), b: cmplx.Inf(), want: false}, {a: cmplx.NaN(), b: 1, want: false}, {a: cmplx.Inf(), b: cmplx.Inf(), want: true}, } { got := Same(test.a, test.b) if got != test.want { t.Errorf("unexpected results for a=%f b=%f: got:%t want:%t", test.a, test.b, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/cmplxs/cscalar/doc.go000066400000000000000000000004741450372207100216550ustar00rootroot00000000000000// Copyright ©2020 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 cscalar provides a set of helper routines for dealing with complex128 values. package cscalar // import "gonum.org/v1/gonum/cmplxs/cscalar" golang-gonum-v1-gonum-0.14.0/cmplxs/cscalar/parse.go000066400000000000000000000130331450372207100222150ustar00rootroot00000000000000// Copyright ©2020 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 cscalar import ( "fmt" "math/cmplx" "strconv" "strings" ) // parse converts the string s to a complex128. The string may be parenthesized and // has the format [±]N±Ni. The order of the components is not strict. func parse(s string) (complex128, error) { if len(s) == 0 { return 0, parseError{state: -1} } orig := s wantClose := s[0] == '(' if wantClose { if s[len(s)-1] != ')' { return 0, parseError{string: orig, state: -1} } s = s[1 : len(s)-1] } if len(s) == 0 { return 0, parseError{string: orig, state: -1} } switch s[0] { case 'n', 'N': if strings.ToLower(s) == "nan" { return cmplx.NaN(), nil } case 'i', 'I': if strings.ToLower(s) == "inf" { return cmplx.Inf(), nil } } var q complex128 var parts byte for i := 0; i < 4; i++ { beg, end, p, err := floatPart(s) if err != nil { return q, parseError{string: orig, state: -1} } if parts&(1< tol { t.Errorf("Case %v: ans mismatch serial: expected %v, found %v", i, test.ans, ans) } ans = Derivative(test.f, test.loc, &Settings{ Formula: formula, OriginKnown: true, OriginValue: test.fofx, }) if math.Abs(test.ans-ans) > tol { t.Errorf("Case %v: ans mismatch serial origin known: expected %v, found %v", i, test.ans, ans) } ans = Derivative(test.f, test.loc, &Settings{ Formula: formula, Concurrent: true, }) if math.Abs(test.ans-ans) > tol { t.Errorf("Case %v: ans mismatch concurrent: expected %v, found %v", i, test.ans, ans) } ans = Derivative(test.f, test.loc, &Settings{ Formula: formula, OriginKnown: true, OriginValue: test.fofx, Concurrent: true, }) if math.Abs(test.ans-ans) > tol { t.Errorf("Case %v: ans mismatch concurrent: expected %v, found %v", i, test.ans, ans) } } } func TestForward(t *testing.T) { t.Parallel() testDerivative(t, Forward, 2e-4, testsFirst) } func TestBackward(t *testing.T) { t.Parallel() testDerivative(t, Backward, 2e-4, testsFirst) } func TestCentral(t *testing.T) { t.Parallel() testDerivative(t, Central, 1e-6, testsFirst) } func TestCentralSecond(t *testing.T) { t.Parallel() testDerivative(t, Central2nd, 1e-3, testsSecond) } // TestDerivativeDefault checks that the derivative works when settings is nil // or zero value. func TestDerivativeDefault(t *testing.T) { t.Parallel() tol := 1e-6 for i, test := range testsFirst { ans := Derivative(test.f, test.loc, nil) if math.Abs(test.ans-ans) > tol { t.Errorf("Case %v: ans mismatch default: expected %v, found %v", i, test.ans, ans) } ans = Derivative(test.f, test.loc, &Settings{}) if math.Abs(test.ans-ans) > tol { t.Errorf("Case %v: ans mismatch zero value: expected %v, found %v", i, test.ans, ans) } } } golang-gonum-v1-gonum-0.14.0/diff/fd/diff.go000066400000000000000000000103731450372207100204020ustar00rootroot00000000000000// 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 fd import ( "math" "runtime" ) // A Point is a stencil location in a finite difference formula. type Point struct { Loc float64 Coeff float64 } // Formula represents a finite difference formula on a regularly spaced grid // that approximates the derivative of order k of a function f at x as // // d^k f(x) ≈ (1 / Step^k) * \sum_i Coeff_i * f(x + Step * Loc_i). // // Step must be positive, or the finite difference formula will panic. type Formula struct { // Stencil is the set of sampling Points which are used to estimate the // derivative. The locations will be scaled by Step and are relative to x. Stencil []Point Derivative int // The order of the approximated derivative. Step float64 // Default step size for the formula. } func (f Formula) isZero() bool { return f.Stencil == nil && f.Derivative == 0 && f.Step == 0 } // Settings is the settings structure for computing finite differences. type Settings struct { // Formula is the finite difference formula used // for approximating the derivative. // Zero value indicates a default formula. Formula Formula // Step is the distance between points of the stencil. // If equal to 0, formula's default step will be used. Step float64 OriginKnown bool // Flag that the value at the origin x is known. OriginValue float64 // Value at the origin (only used if OriginKnown is true). Concurrent bool // Should the function calls be executed concurrently. } // Forward represents a first-order accurate forward approximation // to the first derivative. var Forward = Formula{ Stencil: []Point{{Loc: 0, Coeff: -1}, {Loc: 1, Coeff: 1}}, Derivative: 1, Step: 2e-8, } // Forward2nd represents a first-order accurate forward approximation // to the second derivative. var Forward2nd = Formula{ Stencil: []Point{{Loc: 0, Coeff: 1}, {Loc: 1, Coeff: -2}, {Loc: 2, Coeff: 1}}, Derivative: 2, Step: 1e-4, } // Backward represents a first-order accurate backward approximation // to the first derivative. var Backward = Formula{ Stencil: []Point{{Loc: -1, Coeff: -1}, {Loc: 0, Coeff: 1}}, Derivative: 1, Step: 2e-8, } // Backward2nd represents a first-order accurate forward approximation // to the second derivative. var Backward2nd = Formula{ Stencil: []Point{{Loc: 0, Coeff: 1}, {Loc: -1, Coeff: -2}, {Loc: -2, Coeff: 1}}, Derivative: 2, Step: 1e-4, } // Central represents a second-order accurate centered approximation // to the first derivative. var Central = Formula{ Stencil: []Point{{Loc: -1, Coeff: -0.5}, {Loc: 1, Coeff: 0.5}}, Derivative: 1, Step: 6e-6, } // Central2nd represents a second-order accurate centered approximation // to the second derivative. var Central2nd = Formula{ Stencil: []Point{{Loc: -1, Coeff: 1}, {Loc: 0, Coeff: -2}, {Loc: 1, Coeff: 1}}, Derivative: 2, Step: 1e-4, } var negativeStep = "fd: negative step" // checkFormula checks if the formula is valid, and panics otherwise. func checkFormula(formula Formula) { if formula.Derivative == 0 || formula.Stencil == nil || formula.Step <= 0 { panic("fd: bad formula") } } // computeWorkers returns the desired number of workers given the concurrency // level and number of evaluations. func computeWorkers(concurrent bool, evals int) int { if !concurrent { return 1 } nWorkers := runtime.GOMAXPROCS(0) if nWorkers > evals { nWorkers = evals } return nWorkers } // usesOrigin returns whether the stencil uses the origin, which is true iff // one of the locations in the stencil equals 0. func usesOrigin(stencil []Point) bool { for _, pt := range stencil { if pt.Loc == 0 { return true } } return false } // getOrigin returns the value at the origin. It returns originValue if originKnown // is true. It returns the value returned by f if stencil contains a point with // zero location, and NaN otherwise. func getOrigin(originKnown bool, originValue float64, f func() float64, stencil []Point) float64 { if originKnown { return originValue } for _, pt := range stencil { if pt.Loc == 0 { return f() } } return math.NaN() } const ( badDerivOrder = "fd: invalid derivative order" ) golang-gonum-v1-gonum-0.14.0/diff/fd/doc.go000066400000000000000000000004551450372207100202370ustar00rootroot00000000000000// 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 fd provides functions to approximate derivatives using finite differences. package fd // import "gonum.org/v1/gonum/diff/fd" golang-gonum-v1-gonum-0.14.0/diff/fd/example_test.go000066400000000000000000000033271450372207100221650ustar00rootroot00000000000000// Copyright ©2016 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 fd_test import ( "fmt" "math" "gonum.org/v1/gonum/diff/fd" "gonum.org/v1/gonum/mat" ) func ExampleDerivative() { f := func(x float64) float64 { return math.Sin(x) } // Compute the first derivative of f at 0 using the default settings. fmt.Println("f′(0) ≈", fd.Derivative(f, 0, nil)) // Compute the first derivative of f at 0 using the forward approximation // with a custom step size. df := fd.Derivative(f, 0, &fd.Settings{ Formula: fd.Forward, Step: 1e-3, }) fmt.Println("f′(0) ≈", df) f = func(x float64) float64 { return math.Pow(math.Cos(x), 3) } // Compute the second derivative of f at 0 using // the centered approximation, concurrent evaluation, // and a known function value at x. df = fd.Derivative(f, 0, &fd.Settings{ Formula: fd.Central2nd, Concurrent: true, OriginKnown: true, OriginValue: f(0), }) fmt.Println("f′′(0) ≈", df) // Output: // f′(0) ≈ 1 // f′(0) ≈ 0.9999998333333416 // f′′(0) ≈ -2.999999981767587 } func ExampleJacobian() { f := func(dst, x []float64) { dst[0] = x[0] + 1 dst[1] = 5 * x[2] dst[2] = 4*x[1]*x[1] - 2*x[2] dst[3] = x[2] * math.Sin(x[0]) } jac := mat.NewDense(4, 3, nil) fd.Jacobian(jac, f, []float64{1, 2, 3}, &fd.JacobianSettings{ Formula: fd.Central, Concurrent: true, }) fmt.Printf("J ≈ %.6v\n", mat.Formatted(jac, mat.Prefix(" "))) // Output: // J ≈ ⎡ 1 0 0⎤ // ⎢ 0 0 5⎥ // ⎢ 0 16 -2⎥ // ⎣ 1.62091 0 0.841471⎦ } golang-gonum-v1-gonum-0.14.0/diff/fd/gradient.go000066400000000000000000000073031450372207100212660ustar00rootroot00000000000000// 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 fd import "gonum.org/v1/gonum/floats" // Gradient estimates the gradient of the multivariate function f at the // location x. If dst is not nil, the result will be stored in-place into dst // and returned, otherwise a new slice will be allocated first. Finite // difference formula and other options are specified by settings. If settings is // nil, the gradient will be estimated using the Forward formula and a default // step size. // // Gradient panics if the length of dst and x is not equal, or if the derivative // order of the formula is not 1. func Gradient(dst []float64, f func([]float64) float64, x []float64, settings *Settings) []float64 { if dst == nil { dst = make([]float64, len(x)) } if len(dst) != len(x) { panic("fd: slice length mismatch") } // Default settings. formula := Forward step := formula.Step var originValue float64 var originKnown, concurrent bool // Use user settings if provided. if settings != nil { if !settings.Formula.isZero() { formula = settings.Formula step = formula.Step checkFormula(formula) if formula.Derivative != 1 { panic(badDerivOrder) } } if settings.Step != 0 { step = settings.Step } originKnown = settings.OriginKnown originValue = settings.OriginValue concurrent = settings.Concurrent } evals := len(formula.Stencil) * len(x) nWorkers := computeWorkers(concurrent, evals) hasOrigin := usesOrigin(formula.Stencil) // Copy x in case it is modified during the call. xcopy := make([]float64, len(x)) if hasOrigin && !originKnown { copy(xcopy, x) originValue = f(xcopy) } if nWorkers == 1 { for i := range xcopy { var deriv float64 for _, pt := range formula.Stencil { if pt.Loc == 0 { deriv += pt.Coeff * originValue continue } // Copying the data anew has two benefits. First, it // avoids floating point issues where adding and then // subtracting the step don't return to the exact same // location. Secondly, it protects against the function // modifying the input data. copy(xcopy, x) xcopy[i] += pt.Loc * step deriv += pt.Coeff * f(xcopy) } dst[i] = deriv / step } return dst } sendChan := make(chan fdrun, evals) ansChan := make(chan fdrun, evals) quit := make(chan struct{}) defer close(quit) // Launch workers. Workers receive an index and a step, and compute the answer. for i := 0; i < nWorkers; i++ { go func(sendChan <-chan fdrun, ansChan chan<- fdrun, quit <-chan struct{}) { xcopy := make([]float64, len(x)) for { select { case <-quit: return case run := <-sendChan: // See above comment on the copy. copy(xcopy, x) xcopy[run.idx] += run.pt.Loc * step run.result = f(xcopy) ansChan <- run } } }(sendChan, ansChan, quit) } // Launch the distributor. Distributor sends the cases to be computed. go func(sendChan chan<- fdrun, ansChan chan<- fdrun) { for i := range x { for _, pt := range formula.Stencil { if pt.Loc == 0 { // Answer already known. Send the answer on the answer channel. ansChan <- fdrun{ idx: i, pt: pt, result: originValue, } continue } // Answer not known, send the answer to be computed. sendChan <- fdrun{ idx: i, pt: pt, } } } }(sendChan, ansChan) for i := range dst { dst[i] = 0 } // Read in all of the results. for i := 0; i < evals; i++ { run := <-ansChan dst[run.idx] += run.pt.Coeff * run.result } floats.Scale(1/step, dst) return dst } type fdrun struct { idx int pt Point result float64 } golang-gonum-v1-gonum-0.14.0/diff/fd/gradient_test.go000066400000000000000000000112011450372207100223150ustar00rootroot00000000000000// 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 fd import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Rosenbrock struct { nDim int } func (r Rosenbrock) F(x []float64) (sum float64) { deriv := make([]float64, len(x)) return r.FDf(x, deriv) } func (r Rosenbrock) FDf(x []float64, deriv []float64) (sum float64) { for i := range deriv { deriv[i] = 0 } for i := 0; i < len(x)-1; i++ { sum += math.Pow(1-x[i], 2) + 100*math.Pow(x[i+1]-math.Pow(x[i], 2), 2) } for i := 0; i < len(x)-1; i++ { deriv[i] += -1 * 2 * (1 - x[i]) deriv[i] += 2 * 100 * (x[i+1] - math.Pow(x[i], 2)) * (-2 * x[i]) } for i := 1; i < len(x); i++ { deriv[i] += 2 * 100 * (x[i] - math.Pow(x[i-1], 2)) } return sum } func TestGradient(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i, test := range []struct { nDim int tol float64 formula Formula }{ { nDim: 2, tol: 2e-4, formula: Forward, }, { nDim: 2, tol: 1e-6, formula: Central, }, { nDim: 40, tol: 2e-4, formula: Forward, }, { nDim: 40, tol: 1e-5, formula: Central, }, } { x := make([]float64, test.nDim) for i := range x { x[i] = rnd.Float64() } xcopy := make([]float64, len(x)) copy(xcopy, x) r := Rosenbrock{len(x)} trueGradient := make([]float64, len(x)) r.FDf(x, trueGradient) // Try with gradient nil. gradient := Gradient(nil, r.F, x, &Settings{ Formula: test.formula, }) if !floats.EqualApprox(gradient, trueGradient, test.tol) { t.Errorf("Case %v: gradient mismatch in serial with nil. Want: %v, Got: %v.", i, trueGradient, gradient) } if !floats.Equal(x, xcopy) { t.Errorf("Case %v: x modified during call to gradient in serial with nil.", i) } // Try with provided gradient. for i := range gradient { gradient[i] = rnd.Float64() } Gradient(gradient, r.F, x, &Settings{ Formula: test.formula, }) if !floats.EqualApprox(gradient, trueGradient, test.tol) { t.Errorf("Case %v: gradient mismatch in serial. Want: %v, Got: %v.", i, trueGradient, gradient) } if !floats.Equal(x, xcopy) { t.Errorf("Case %v: x modified during call to gradient in serial with non-nil.", i) } // Try with known value. for i := range gradient { gradient[i] = rnd.Float64() } Gradient(gradient, r.F, x, &Settings{ Formula: test.formula, OriginKnown: true, OriginValue: r.F(x), }) if !floats.EqualApprox(gradient, trueGradient, test.tol) { t.Errorf("Case %v: gradient mismatch with known origin in serial. Want: %v, Got: %v.", i, trueGradient, gradient) } // Try with concurrent evaluation. for i := range gradient { gradient[i] = rnd.Float64() } Gradient(gradient, r.F, x, &Settings{ Formula: test.formula, Concurrent: true, }) if !floats.EqualApprox(gradient, trueGradient, test.tol) { t.Errorf("Case %v: gradient mismatch with unknown origin in parallel. Want: %v, Got: %v.", i, trueGradient, gradient) } if !floats.Equal(x, xcopy) { t.Errorf("Case %v: x modified during call to gradient in parallel", i) } // Try with concurrent evaluation with origin known. for i := range gradient { gradient[i] = rnd.Float64() } Gradient(gradient, r.F, x, &Settings{ Formula: test.formula, Concurrent: true, OriginKnown: true, OriginValue: r.F(x), }) if !floats.EqualApprox(gradient, trueGradient, test.tol) { t.Errorf("Case %v: gradient mismatch with known origin in parallel. Want: %v, Got: %v.", i, trueGradient, gradient) } // Try with nil settings. for i := range gradient { gradient[i] = rnd.Float64() } Gradient(gradient, r.F, x, nil) if !floats.EqualApprox(gradient, trueGradient, test.tol) { t.Errorf("Case %v: gradient mismatch with default settings. Want: %v, Got: %v.", i, trueGradient, gradient) } // Try with zero-valued settings. for i := range gradient { gradient[i] = rnd.Float64() } Gradient(gradient, r.F, x, &Settings{}) if !floats.EqualApprox(gradient, trueGradient, test.tol) { t.Errorf("Case %v: gradient mismatch with zero settings. Want: %v, Got: %v.", i, trueGradient, gradient) } } } func Panics(fun func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() fun() return } func TestGradientPanics(t *testing.T) { t.Parallel() // Test that it panics if !Panics(func() { Gradient([]float64{0.0}, func(x []float64) float64 { return x[0] * x[0] }, []float64{0.0, 0.0}, nil) }) { t.Errorf("Gradient did not panic with length mismatch") } } golang-gonum-v1-gonum-0.14.0/diff/fd/hessian.go000066400000000000000000000117521450372207100211260ustar00rootroot00000000000000// 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 fd import ( "math" "sync" "gonum.org/v1/gonum/mat" ) // Hessian approximates the Hessian matrix of the multivariate function f at // the location x. That is // // H_{i,j} = ∂^2 f(x)/∂x_i ∂x_j // // The resulting H will be stored in dst. Finite difference formula and other // options are specified by settings. If settings is nil, the Hessian will be // estimated using the Forward formula and a default step size. // // If the dst matrix is empty it will be resized to the correct dimensions, // otherwise the dimensions of dst must match the length of x or Hessian will panic. // Hessian will panic if the derivative order of the formula is not 1. func Hessian(dst *mat.SymDense, f func(x []float64) float64, x []float64, settings *Settings) { n := len(x) if dst.IsEmpty() { *dst = *(dst.GrowSym(n).(*mat.SymDense)) } else if dst.SymmetricDim() != n { panic("hessian: dst size mismatch") } dst.Zero() // Default settings. formula := Forward step := math.Sqrt(formula.Step) // Use the sqrt because taking derivatives of derivatives. var originValue float64 var originKnown, concurrent bool // Use user settings if provided. if settings != nil { if !settings.Formula.isZero() { formula = settings.Formula step = math.Sqrt(formula.Step) checkFormula(formula) if formula.Derivative != 1 { panic(badDerivOrder) } } if settings.Step != 0 { if settings.Step < 0 { panic(negativeStep) } step = settings.Step } originKnown = settings.OriginKnown originValue = settings.OriginValue concurrent = settings.Concurrent } evals := n * (n + 1) / 2 * len(formula.Stencil) * len(formula.Stencil) for _, pt := range formula.Stencil { if pt.Loc == 0 { evals -= n * (n + 1) / 2 break } } nWorkers := computeWorkers(concurrent, evals) if nWorkers == 1 { hessianSerial(dst, f, x, formula.Stencil, step, originKnown, originValue) return } hessianConcurrent(dst, nWorkers, evals, f, x, formula.Stencil, step, originKnown, originValue) } func hessianSerial(dst *mat.SymDense, f func(x []float64) float64, x []float64, stencil []Point, step float64, originKnown bool, originValue float64) { n := len(x) xCopy := make([]float64, n) fo := func() float64 { // Copy x in case it is modified during the call. copy(xCopy, x) return f(x) } is2 := 1 / (step * step) origin := getOrigin(originKnown, originValue, fo, stencil) for i := 0; i < n; i++ { for j := i; j < n; j++ { var hess float64 for _, pti := range stencil { for _, ptj := range stencil { var v float64 if pti.Loc == 0 && ptj.Loc == 0 { v = origin } else { // Copying the data anew has two benefits. First, it // avoids floating point issues where adding and then // subtracting the step don't return to the exact same // location. Secondly, it protects against the function // modifying the input data. copy(xCopy, x) xCopy[i] += pti.Loc * step xCopy[j] += ptj.Loc * step v = f(xCopy) } hess += v * pti.Coeff * ptj.Coeff * is2 } } dst.SetSym(i, j, hess) } } } func hessianConcurrent(dst *mat.SymDense, nWorkers, evals int, f func(x []float64) float64, x []float64, stencil []Point, step float64, originKnown bool, originValue float64) { n := dst.SymmetricDim() type run struct { i, j int iIdx, jIdx int result float64 } send := make(chan run, evals) ans := make(chan run, evals) var originWG sync.WaitGroup hasOrigin := usesOrigin(stencil) if hasOrigin { originWG.Add(1) // Launch worker to compute the origin. go func() { defer originWG.Done() xCopy := make([]float64, len(x)) copy(xCopy, x) originValue = f(xCopy) }() } var workerWG sync.WaitGroup // Launch workers. for i := 0; i < nWorkers; i++ { workerWG.Add(1) go func(send <-chan run, ans chan<- run) { defer workerWG.Done() xCopy := make([]float64, len(x)) for r := range send { if stencil[r.iIdx].Loc == 0 && stencil[r.jIdx].Loc == 0 { originWG.Wait() r.result = originValue } else { // See hessianSerial for comment on the copy. copy(xCopy, x) xCopy[r.i] += stencil[r.iIdx].Loc * step xCopy[r.j] += stencil[r.jIdx].Loc * step r.result = f(xCopy) } ans <- r } }(send, ans) } // Launch the distributor, which sends all of runs. go func(send chan<- run) { for i := 0; i < n; i++ { for j := i; j < n; j++ { for iIdx := range stencil { for jIdx := range stencil { send <- run{ i: i, j: j, iIdx: iIdx, jIdx: jIdx, } } } } } close(send) // Wait for all the workers to quit, then close the ans channel. workerWG.Wait() close(ans) }(send) is2 := 1 / (step * step) // Read in the results. for r := range ans { v := r.result * stencil[r.iIdx].Coeff * stencil[r.jIdx].Coeff * is2 v += dst.At(r.i, r.j) dst.SetSym(r.i, r.j, v) } } golang-gonum-v1-gonum-0.14.0/diff/fd/hessian_test.go000066400000000000000000000044051450372207100221620ustar00rootroot00000000000000// 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 fd import ( "testing" "gonum.org/v1/gonum/mat" ) type HessianTester interface { Func(x []float64) float64 Grad(grad, x []float64) Hess(dst mat.MutableSymmetric, x []float64) } type hessianTestCase struct { h HessianTester x []float64 settings *Settings tol float64 } var _hessianTestCases = []hessianTestCase{ { h: Watson{}, x: []float64{0.2, 0.3, 0.1, 0.4}, tol: 1e-3, }, { h: Watson{}, x: []float64{2, 3, 1, 4}, tol: 1e-3, settings: &Settings{ Step: 1e-5, Formula: Central, }, }, { h: Watson{}, x: []float64{2, 3, 1}, tol: 1e-3, settings: &Settings{ OriginKnown: true, OriginValue: 7606.529501201192, }, }, { h: ConstFunc(5), x: []float64{1, 9}, tol: 1e-16, }, { h: LinearFunc{w: []float64{10, 6, -1}, c: 5}, x: []float64{3, 1, 8}, tol: 1e-6, }, { h: QuadFunc{ a: mat.NewSymDense(3, []float64{ 10, 2, 1, 2, 5, -3, 1, -3, 6, }), b: mat.NewVecDense(3, []float64{3, -2, -1}), c: 5, }, x: []float64{-1.6, -3, 2}, tol: 1e-6, }, } func hessianTestCases() []hessianTestCase { xs := []hessianTestCase{} for _, test := range _hessianTestCases { n := test if test.settings != nil { clone := *test.settings n.settings = &clone } xs = append(xs, n) } return xs } func TestHessian(t *testing.T) { t.Parallel() for cas, test := range hessianTestCases() { n := len(test.x) var got mat.SymDense Hessian(&got, test.h.Func, test.x, test.settings) want := mat.NewSymDense(n, nil) test.h.Hess(want, test.x) if !mat.EqualApprox(&got, want, test.tol) { t.Errorf("Cas %d: Hessian mismatch\ngot=\n%0.4v\nwant=\n%0.4v\n", cas, mat.Formatted(&got), mat.Formatted(want)) } // Test that concurrency works. settings := test.settings if settings == nil { settings = &Settings{} } settings.Concurrent = true var got2 mat.SymDense Hessian(&got2, test.h.Func, test.x, settings) if !mat.EqualApprox(&got, &got2, 1e-5) { t.Errorf("Cas %d: Hessian mismatch concurrent\ngot=\n%0.6v\nwant=\n%0.6v\n", cas, mat.Formatted(&got2), mat.Formatted(&got)) } } } golang-gonum-v1-gonum-0.14.0/diff/fd/jacobian.go000066400000000000000000000114341450372207100212370ustar00rootroot00000000000000// Copyright ©2016 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 fd import ( "sync" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) type JacobianSettings struct { Formula Formula OriginValue []float64 Step float64 Concurrent bool } // Jacobian approximates the Jacobian matrix of a vector-valued function f at // the location x and stores the result in-place into dst. // // Finite difference formula and other options are specified by settings. If // settings is nil, the Jacobian will be estimated using the Forward formula and // a default step size. // // The Jacobian matrix J is the matrix of all first-order partial derivatives of f. // If f maps an n-dimensional vector x to an m-dimensional vector y = f(x), J is // an m×n matrix whose elements are given as // // J_{i,j} = ∂f_i/∂x_j, // // or expanded out // // [ ∂f_1/∂x_1 ... ∂f_1/∂x_n ] // [ . . . ] // J = [ . . . ] // [ . . . ] // [ ∂f_m/∂x_1 ... ∂f_m/∂x_n ] // // dst must be non-nil, the number of its columns must equal the length of x, and // the derivative order of the formula must be 1, otherwise Jacobian will panic. func Jacobian(dst *mat.Dense, f func(y, x []float64), x []float64, settings *JacobianSettings) { n := len(x) if n == 0 { panic("jacobian: x has zero length") } m, c := dst.Dims() if c != n { panic("jacobian: mismatched matrix size") } // Default settings. formula := Forward step := formula.Step var originValue []float64 var concurrent bool // Use user settings if provided. if settings != nil { if !settings.Formula.isZero() { formula = settings.Formula step = formula.Step checkFormula(formula) if formula.Derivative != 1 { panic(badDerivOrder) } } if settings.Step != 0 { step = settings.Step } originValue = settings.OriginValue if originValue != nil && len(originValue) != m { panic("jacobian: mismatched OriginValue slice length") } concurrent = settings.Concurrent } evals := n * len(formula.Stencil) for _, pt := range formula.Stencil { if pt.Loc == 0 { evals -= n - 1 break } } nWorkers := computeWorkers(concurrent, evals) if nWorkers == 1 { jacobianSerial(dst, f, x, originValue, formula, step) return } jacobianConcurrent(dst, f, x, originValue, formula, step, nWorkers) } func jacobianSerial(dst *mat.Dense, f func([]float64, []float64), x, origin []float64, formula Formula, step float64) { m, n := dst.Dims() xcopy := make([]float64, n) y := make([]float64, m) col := make([]float64, m) for j := 0; j < n; j++ { for i := range col { col[i] = 0 } for _, pt := range formula.Stencil { if pt.Loc == 0 { if origin == nil { origin = make([]float64, m) copy(xcopy, x) f(origin, xcopy) } floats.AddScaled(col, pt.Coeff, origin) } else { copy(xcopy, x) xcopy[j] += pt.Loc * step f(y, xcopy) floats.AddScaled(col, pt.Coeff, y) } } dst.SetCol(j, col) } dst.Scale(1/step, dst) } func jacobianConcurrent(dst *mat.Dense, f func([]float64, []float64), x, origin []float64, formula Formula, step float64, nWorkers int) { m, n := dst.Dims() for i := 0; i < m; i++ { for j := 0; j < n; j++ { dst.Set(i, j, 0) } } var ( wg sync.WaitGroup mu = make([]sync.Mutex, n) // Guard access to individual columns. ) worker := func(jobs <-chan jacJob) { defer wg.Done() xcopy := make([]float64, n) y := make([]float64, m) yVec := mat.NewVecDense(m, y) var col mat.VecDense for job := range jobs { copy(xcopy, x) xcopy[job.j] += job.pt.Loc * step f(y, xcopy) col.ColViewOf(dst, job.j) mu[job.j].Lock() col.AddScaledVec(&col, job.pt.Coeff, yVec) mu[job.j].Unlock() } } jobs := make(chan jacJob, nWorkers) for i := 0; i < nWorkers; i++ { wg.Add(1) go worker(jobs) } var hasOrigin bool for _, pt := range formula.Stencil { if pt.Loc == 0 { hasOrigin = true continue } for j := 0; j < n; j++ { jobs <- jacJob{j, pt} } } close(jobs) if hasOrigin && origin == nil { wg.Add(1) go func() { defer wg.Done() origin = make([]float64, m) xcopy := make([]float64, n) copy(xcopy, x) f(origin, xcopy) }() } wg.Wait() if hasOrigin { // The formula evaluated at x, we need to add scaled origin to // all columns of dst. Iterate again over all Formula points // because we don't forbid repeated locations. originVec := mat.NewVecDense(m, origin) for _, pt := range formula.Stencil { if pt.Loc != 0 { continue } var col mat.VecDense for j := 0; j < n; j++ { col.ColViewOf(dst, j) col.AddScaledVec(&col, pt.Coeff, originVec) } } } dst.Scale(1/step, dst) } type jacJob struct { j int pt Point } golang-gonum-v1-gonum-0.14.0/diff/fd/jacobian_test.go000066400000000000000000000135471450372207100223050ustar00rootroot00000000000000// Copyright ©2016 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 fd import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) func vecFunc13(y, x []float64) { y[0] = 5*x[0] + x[2]*math.Sin(x[1]) + 1 } func vecFunc13Jac(jac *mat.Dense, x []float64) { jac.Set(0, 0, 5) jac.Set(0, 1, x[2]*math.Cos(x[1])) jac.Set(0, 2, math.Sin(x[1])) } func vecFunc22(y, x []float64) { y[0] = x[0]*x[0]*x[1] + 1 y[1] = 5*x[0] + math.Sin(x[1]) + 1 } func vecFunc22Jac(jac *mat.Dense, x []float64) { jac.Set(0, 0, 2*x[0]*x[1]) jac.Set(0, 1, x[0]*x[0]) jac.Set(1, 0, 5) jac.Set(1, 1, math.Cos(x[1])) } func vecFunc43(y, x []float64) { y[0] = x[0] + 1 y[1] = 5*x[2] + 1 y[2] = 4*x[1]*x[1] - 2*x[2] + 1 y[3] = x[2]*math.Sin(x[0]) + 1 } func vecFunc43Jac(jac *mat.Dense, x []float64) { jac.Set(0, 0, 1) jac.Set(0, 1, 0) jac.Set(0, 2, 0) jac.Set(1, 0, 0) jac.Set(1, 1, 0) jac.Set(1, 2, 5) jac.Set(2, 0, 0) jac.Set(2, 1, 8*x[1]) jac.Set(2, 2, -2) jac.Set(3, 0, x[2]*math.Cos(x[0])) jac.Set(3, 1, 0) jac.Set(3, 2, math.Sin(x[0])) } func TestJacobian(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) // Test with default settings. for tc, test := range []struct { m, n int f func([]float64, []float64) jac func(*mat.Dense, []float64) }{ { m: 1, n: 3, f: vecFunc13, jac: vecFunc13Jac, }, { m: 2, n: 2, f: vecFunc22, jac: vecFunc22Jac, }, { m: 4, n: 3, f: vecFunc43, jac: vecFunc43Jac, }, } { const tol = 1e-6 x := randomSlice(rnd, test.n, 10) xcopy := make([]float64, test.n) copy(xcopy, x) want := mat.NewDense(test.m, test.n, nil) test.jac(want, x) got := mat.NewDense(test.m, test.n, nil) fillNaNDense(got) Jacobian(got, test.f, x, nil) if !mat.EqualApprox(want, got, tol) { t.Errorf("Case %d (default settings): unexpected Jacobian.\nwant: %v\ngot: %v", tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" "))) } if !floats.Equal(x, xcopy) { t.Errorf("Case %d (default settings): x modified", tc) } } // Test with non-default settings. for tc, test := range []struct { m, n int f func([]float64, []float64) jac func(*mat.Dense, []float64) tol float64 formula Formula }{ { m: 1, n: 3, f: vecFunc13, jac: vecFunc13Jac, tol: 1e-6, formula: Forward, }, { m: 1, n: 3, f: vecFunc13, jac: vecFunc13Jac, tol: 1e-6, formula: Backward, }, { m: 1, n: 3, f: vecFunc13, jac: vecFunc13Jac, tol: 1e-9, formula: Central, }, { m: 2, n: 2, f: vecFunc22, jac: vecFunc22Jac, tol: 1e-6, formula: Forward, }, { m: 2, n: 2, f: vecFunc22, jac: vecFunc22Jac, tol: 1e-6, formula: Backward, }, { m: 2, n: 2, f: vecFunc22, jac: vecFunc22Jac, tol: 1e-9, formula: Central, }, { m: 4, n: 3, f: vecFunc43, jac: vecFunc43Jac, tol: 1e-6, formula: Forward, }, { m: 4, n: 3, f: vecFunc43, jac: vecFunc43Jac, tol: 1e-6, formula: Backward, }, { m: 4, n: 3, f: vecFunc43, jac: vecFunc43Jac, tol: 1e-9, formula: Central, }, } { x := randomSlice(rnd, test.n, 10) xcopy := make([]float64, test.n) copy(xcopy, x) want := mat.NewDense(test.m, test.n, nil) test.jac(want, x) got := mat.NewDense(test.m, test.n, nil) fillNaNDense(got) Jacobian(got, test.f, x, &JacobianSettings{ Formula: test.formula, }) if !mat.EqualApprox(want, got, test.tol) { t.Errorf("Case %d: unexpected Jacobian.\nwant: %v\ngot: %v", tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" "))) } if !floats.Equal(x, xcopy) { t.Errorf("Case %d: x modified", tc) } fillNaNDense(got) Jacobian(got, test.f, x, &JacobianSettings{ Formula: test.formula, Concurrent: true, }) if !mat.EqualApprox(want, got, test.tol) { t.Errorf("Case %d (concurrent): unexpected Jacobian.\nwant: %v\ngot: %v", tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" "))) } if !floats.Equal(x, xcopy) { t.Errorf("Case %d (concurrent): x modified", tc) } fillNaNDense(got) origin := make([]float64, test.m) test.f(origin, x) Jacobian(got, test.f, x, &JacobianSettings{ Formula: test.formula, OriginValue: origin, }) if !mat.EqualApprox(want, got, test.tol) { t.Errorf("Case %d (origin): unexpected Jacobian.\nwant: %v\ngot: %v", tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" "))) } if !floats.Equal(x, xcopy) { t.Errorf("Case %d (origin): x modified", tc) } fillNaNDense(got) Jacobian(got, test.f, x, &JacobianSettings{ Formula: test.formula, OriginValue: origin, Concurrent: true, }) if !mat.EqualApprox(want, got, test.tol) { t.Errorf("Case %d (concurrent, origin): unexpected Jacobian.\nwant: %v\ngot: %v", tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" "))) } if !floats.Equal(x, xcopy) { t.Errorf("Case %d (concurrent, origin): x modified", tc) } } } // randomSlice returns a slice of n elements from the interval [-bound,bound). func randomSlice(rnd *rand.Rand, n int, bound float64) []float64 { x := make([]float64, n) for i := range x { x[i] = 2*bound*rnd.Float64() - bound } return x } // fillNaNDense fills the matrix m with NaN values. func fillNaNDense(m *mat.Dense) { r, c := m.Dims() for i := 0; i < r; i++ { for j := 0; j < c; j++ { m.Set(i, j, math.NaN()) } } } golang-gonum-v1-gonum-0.14.0/diff/fd/laplacian.go000066400000000000000000000100101450372207100214020ustar00rootroot00000000000000// 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 fd import "sync" // Laplacian computes the Laplacian of the multivariate function f at the location // x. That is, Laplacian returns // // ∆ f(x) = ∇ · ∇ f(x) = \sum_i ∂^2 f(x)/∂x_i^2 // // The finite difference formula and other options are specified by settings. // The order of the difference formula must be 2 or Laplacian will panic. func Laplacian(f func(x []float64) float64, x []float64, settings *Settings) float64 { n := len(x) if n == 0 { panic("laplacian: x has zero length") } // Default settings. formula := Central2nd step := formula.Step var originValue float64 var originKnown, concurrent bool // Use user settings if provided. if settings != nil { if !settings.Formula.isZero() { formula = settings.Formula step = formula.Step checkFormula(formula) if formula.Derivative != 2 { panic(badDerivOrder) } } if settings.Step != 0 { if settings.Step < 0 { panic(negativeStep) } step = settings.Step } originKnown = settings.OriginKnown originValue = settings.OriginValue concurrent = settings.Concurrent } evals := n * len(formula.Stencil) if usesOrigin(formula.Stencil) { evals -= n } nWorkers := computeWorkers(concurrent, evals) if nWorkers == 1 { return laplacianSerial(f, x, formula.Stencil, step, originKnown, originValue) } return laplacianConcurrent(nWorkers, evals, f, x, formula.Stencil, step, originKnown, originValue) } func laplacianSerial(f func(x []float64) float64, x []float64, stencil []Point, step float64, originKnown bool, originValue float64) float64 { n := len(x) xCopy := make([]float64, n) fo := func() float64 { // Copy x in case it is modified during the call. copy(xCopy, x) return f(x) } is2 := 1 / (step * step) origin := getOrigin(originKnown, originValue, fo, stencil) var laplacian float64 for i := 0; i < n; i++ { for _, pt := range stencil { var v float64 if pt.Loc == 0 { v = origin } else { // Copying the data anew has two benefits. First, it // avoids floating point issues where adding and then // subtracting the step don't return to the exact same // location. Secondly, it protects against the function // modifying the input data. copy(xCopy, x) xCopy[i] += pt.Loc * step v = f(xCopy) } laplacian += v * pt.Coeff * is2 } } return laplacian } func laplacianConcurrent(nWorkers, evals int, f func(x []float64) float64, x []float64, stencil []Point, step float64, originKnown bool, originValue float64) float64 { type run struct { i int idx int result float64 } n := len(x) send := make(chan run, evals) ans := make(chan run, evals) var originWG sync.WaitGroup hasOrigin := usesOrigin(stencil) if hasOrigin { originWG.Add(1) // Launch worker to compute the origin. go func() { defer originWG.Done() xCopy := make([]float64, len(x)) copy(xCopy, x) originValue = f(xCopy) }() } var workerWG sync.WaitGroup // Launch workers. for i := 0; i < nWorkers; i++ { workerWG.Add(1) go func(send <-chan run, ans chan<- run) { defer workerWG.Done() xCopy := make([]float64, len(x)) for r := range send { if stencil[r.idx].Loc == 0 { originWG.Wait() r.result = originValue } else { // See laplacianSerial for comment on the copy. copy(xCopy, x) xCopy[r.i] += stencil[r.idx].Loc * step r.result = f(xCopy) } ans <- r } }(send, ans) } // Launch the distributor, which sends all of runs. go func(send chan<- run) { for i := 0; i < n; i++ { for idx := range stencil { send <- run{ i: i, idx: idx, } } } close(send) // Wait for all the workers to quit, then close the ans channel. workerWG.Wait() close(ans) }(send) // Read in the results. is2 := 1 / (step * step) var laplacian float64 for r := range ans { laplacian += r.result * stencil[r.idx].Coeff * is2 } return laplacian } golang-gonum-v1-gonum-0.14.0/diff/fd/laplacian_test.go000066400000000000000000000022531450372207100224530ustar00rootroot00000000000000// 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 fd import ( "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func TestLaplacian(t *testing.T) { t.Parallel() for cas, test := range hessianTestCases() { // Modify the test cases where the formula is set. settings := test.settings if settings != nil && !settings.Formula.isZero() { settings.Formula = Forward2nd } n := len(test.x) got := Laplacian(test.h.Func, test.x, test.settings) hess := mat.NewSymDense(n, nil) test.h.Hess(hess, test.x) var want float64 for i := 0; i < n; i++ { want += hess.At(i, i) } if !scalar.EqualWithinAbsOrRel(got, want, test.tol, test.tol) { t.Errorf("Cas %d: Laplacian mismatch. got %v, want %v", cas, got, want) } // Test that concurrency works. if settings == nil { settings = &Settings{} } settings.Concurrent = true got2 := Laplacian(test.h.Func, test.x, settings) if !scalar.EqualWithinAbsOrRel(got, got2, 1e-5, 1e-5) { t.Errorf("Cas %d: Laplacian mismatch. got %v, want %v", cas, got2, got) } } } golang-gonum-v1-gonum-0.14.0/diff/fd/simplefunctions_test.go000066400000000000000000000033371450372207100237550ustar00rootroot00000000000000// 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 fd import ( "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) // ConstFunc is a constant function returning the value held by the type. type ConstFunc float64 func (c ConstFunc) Func(x []float64) float64 { return float64(c) } func (c ConstFunc) Grad(grad, x []float64) { for i := range grad { grad[i] = 0 } } func (c ConstFunc) Hess(dst mat.MutableSymmetric, x []float64) { n := len(x) for i := 0; i < n; i++ { for j := i; j < n; j++ { dst.SetSym(i, j, 0) } } } // LinearFunc is a linear function returning w*x+c. type LinearFunc struct { w []float64 c float64 } func (l LinearFunc) Func(x []float64) float64 { return floats.Dot(l.w, x) + l.c } func (l LinearFunc) Grad(grad, x []float64) { copy(grad, l.w) } func (l LinearFunc) Hess(dst mat.MutableSymmetric, x []float64) { n := len(x) for i := 0; i < n; i++ { for j := i; j < n; j++ { dst.SetSym(i, j, 0) } } } // QuadFunc is a quadratic function returning 0.5*x'*a*x + b*x + c. type QuadFunc struct { a *mat.SymDense b *mat.VecDense c float64 } func (q QuadFunc) Func(x []float64) float64 { v := mat.NewVecDense(len(x), x) var tmp mat.VecDense tmp.MulVec(q.a, v) return 0.5*mat.Dot(&tmp, v) + mat.Dot(q.b, v) + q.c } func (q QuadFunc) Grad(grad, x []float64) { var tmp mat.VecDense v := mat.NewVecDense(len(x), x) tmp.MulVec(q.a, v) for i := range grad { grad[i] = tmp.At(i, 0) + q.b.At(i, 0) } } func (q QuadFunc) Hess(dst mat.MutableSymmetric, x []float64) { n := len(x) for i := 0; i < n; i++ { for j := i; j < n; j++ { dst.SetSym(i, j, q.a.At(i, j)) } } } golang-gonum-v1-gonum-0.14.0/diff/fd/watson_test.go000066400000000000000000000052731450372207100220470ustar00rootroot00000000000000// 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 fd import "gonum.org/v1/gonum/mat" // Watson implements the Watson's function. // Dimension of the problem should be 2 <= dim <= 31. For dim == 9, the problem // of minimizing the function is very ill conditioned. // // This is copied from gonum.org/v1/optimize/functions for testing Hessian-like // derivative methods. // // References: // - Kowalik, J.S., Osborne, M.R.: Methods for Unconstrained Optimization // Problems. Elsevier North-Holland, New York, 1968 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type Watson struct{} func (Watson) Func(x []float64) (sum float64) { for i := 1; i <= 29; i++ { d1 := float64(i) / 29 d2 := 1.0 var s1 float64 for j := 1; j < len(x); j++ { s1 += float64(j) * d2 * x[j] d2 *= d1 } d2 = 1.0 var s2 float64 for _, v := range x { s2 += d2 * v d2 *= d1 } t := s1 - s2*s2 - 1 sum += t * t } t := x[1] - x[0]*x[0] - 1 sum += x[0]*x[0] + t*t return sum } func (Watson) Grad(grad, x []float64) { if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 29; i++ { d1 := float64(i) / 29 d2 := 1.0 var s1 float64 for j := 1; j < len(x); j++ { s1 += float64(j) * d2 * x[j] d2 *= d1 } d2 = 1.0 var s2 float64 for _, v := range x { s2 += d2 * v d2 *= d1 } t := s1 - s2*s2 - 1 s3 := 2 * d1 * s2 d2 = 2 / d1 for j := range x { grad[j] += d2 * (float64(j) - s3) * t d2 *= d1 } } t := x[1] - x[0]*x[0] - 1 grad[0] += x[0] * (2 - 4*t) grad[1] += 2 * t } func (Watson) Hess(hess mat.MutableSymmetric, x []float64) { dim := len(x) if dim != hess.SymmetricDim() { panic("incorrect size of the Hessian") } for j := 0; j < dim; j++ { for k := j; k < dim; k++ { hess.SetSym(j, k, 0) } } for i := 1; i <= 29; i++ { d1 := float64(i) / 29 d2 := 1.0 var s1 float64 for j := 1; j < dim; j++ { s1 += float64(j) * d2 * x[j] d2 *= d1 } d2 = 1.0 var s2 float64 for _, v := range x { s2 += d2 * v d2 *= d1 } t := s1 - s2*s2 - 1 s3 := 2 * d1 * s2 d2 = 2 / d1 th := 2 * d1 * d1 * t for j := 0; j < dim; j++ { v := float64(j) - s3 d3 := 1 / d1 for k := 0; k <= j; k++ { hess.SetSym(k, j, hess.At(k, j)+d2*d3*(v*(float64(k)-s3)-th)) d3 *= d1 } d2 *= d1 } } t1 := x[1] - x[0]*x[0] - 1 hess.SetSym(0, 0, hess.At(0, 0)+8*x[0]*x[0]+2-4*t1) hess.SetSym(0, 1, hess.At(0, 1)-4*x[0]) hess.SetSym(1, 1, hess.At(1, 1)+2) } golang-gonum-v1-gonum-0.14.0/doc.go000066400000000000000000000011001450372207100167220ustar00rootroot00000000000000// Copyright ©2019 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. // Gonum is a set of packages designed to make writing numerical and // scientific algorithms productive, performant, and scalable. // // Gonum contains libraries for matrices and linear algebra; statistics, // probability distributions, and sampling; tools for function // differentiation, integration, and optimization; network creation and // analysis; and more. package gonum // import "gonum.org/v1/gonum" golang-gonum-v1-gonum-0.14.0/dsp/000077500000000000000000000000001450372207100164245ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/dsp/fourier/000077500000000000000000000000001450372207100200775ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/dsp/fourier/doc.go000066400000000000000000000004561450372207100212000ustar00rootroot00000000000000// 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 fourier provides functions to perform Discrete Fourier Transforms. package fourier // import "gonum.org/v1/gonum/dsp/fourier" golang-gonum-v1-gonum-0.14.0/dsp/fourier/fourier.go000066400000000000000000000177741450372207100221210ustar00rootroot00000000000000// 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 fourier import "gonum.org/v1/gonum/dsp/fourier/internal/fftpack" // FFT implements Fast Fourier Transform and its inverse for real sequences. type FFT struct { work []float64 ifac [15]int // real temporarily store complex data as // pairs of real values to allow passing to // the backing code. The length of real // must always be half the length of work. real []float64 } // NewFFT returns an FFT initialized for work on sequences of length n. func NewFFT(n int) *FFT { var t FFT t.Reset(n) return &t } // Len returns the length of the acceptable input. func (t *FFT) Len() int { return len(t.real) } // Reset reinitializes the FFT for work on sequences of length n. func (t *FFT) Reset(n int) { if 2*n <= cap(t.work) { t.work = t.work[:2*n] t.real = t.real[:n] } else { t.work = make([]float64, 2*n) t.real = make([]float64, n) } fftpack.Rffti(n, t.work, t.ifac[:]) } // Coefficients computes the Fourier coefficients of the input sequence, // converting the time series in seq into the frequency spectrum, placing // the result in dst and returning it. This transform is unnormalized; a // call to Coefficients followed by a call of Sequence will multiply the // input sequence by the length of the sequence. // // If the length of seq is not t.Len(), Coefficients will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal t.Len()/2+1, Coefficients will panic. func (t *FFT) Coefficients(dst []complex128, seq []float64) []complex128 { if len(seq) != t.Len() { panic("fourier: sequence length mismatch") } if dst == nil { dst = make([]complex128, t.Len()/2+1) } else if len(dst) != t.Len()/2+1 { panic("fourier: destination length mismatch") } copy(t.real, seq) fftpack.Rfftf(len(t.real), t.real, t.work, t.ifac[:]) dst[0] = complex(t.real[0], 0) if len(seq) < 2 { return dst } if len(seq)%2 == 1 { dst[len(dst)-1] = complex(t.real[len(t.real)-2], t.real[len(t.real)-1]) } else { dst[len(dst)-1] = complex(t.real[len(t.real)-1], 0) } for i := 1; i < len(dst)-1; i++ { dst[i] = complex(t.real[2*i-1], t.real[2*i]) } return dst } // Sequence computes the real periodic sequence from the Fourier coefficients, // converting the frequency spectrum in coeff into a time series, placing the // result in dst and returning it. This transform is unnormalized; a call to // Coefficients followed by a call of Sequence will multiply the input sequence // by the length of the sequence. // // If the length of coeff is not t.Len()/2+1, Sequence will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal the length of coeff, Sequence will panic. func (t *FFT) Sequence(dst []float64, coeff []complex128) []float64 { if len(coeff) != t.Len()/2+1 { panic("fourier: coefficients length mismatch") } if dst == nil { dst = make([]float64, t.Len()) } else if len(dst) != t.Len() { panic("fourier: destination length mismatch") } dst[0] = real(coeff[0]) if len(dst) < 2 { return dst } nf := coeff[len(coeff)-1] if len(dst)%2 == 1 { dst[len(dst)-2] = real(nf) dst[len(dst)-1] = imag(nf) } else { dst[len(dst)-1] = real(nf) } for i, cv := range coeff[1 : len(coeff)-1] { dst[2*i+1] = real(cv) dst[2*i+2] = imag(cv) } fftpack.Rfftb(len(dst), dst, t.work, t.ifac[:]) return dst } // Freq returns the relative frequency center for coefficient i. // Freq will panic if i is negative or greater than or equal to t.Len(). func (t *FFT) Freq(i int) float64 { if i < 0 || t.Len() <= i { panic("fourier: index out of range") } step := 1 / float64(t.Len()) return step * float64(i) } // CmplxFFT implements Fast Fourier Transform and its inverse for complex sequences. type CmplxFFT struct { work []float64 ifac [15]int // real temporarily store complex data as // pairs of real values to allow passing to // the backing code. The length of real // must always be half the length of work. real []float64 } // NewCmplxFFT returns an CmplxFFT initialized for work on sequences of length n. func NewCmplxFFT(n int) *CmplxFFT { var t CmplxFFT t.Reset(n) return &t } // Len returns the length of the acceptable input. func (t *CmplxFFT) Len() int { return len(t.work) / 4 } // Reset reinitializes the FFT for work on sequences of length n. func (t *CmplxFFT) Reset(n int) { if 4*n <= cap(t.work) { t.work = t.work[:4*n] t.real = t.real[:2*n] } else { t.work = make([]float64, 4*n) t.real = make([]float64, 2*n) } fftpack.Cffti(n, t.work, t.ifac[:]) } // Coefficients computes the Fourier coefficients of a complex input sequence, // converting the time series in seq into the frequency spectrum, placing // the result in dst and returning it. This transform is unnormalized; a call // to Coefficients followed by a call of Sequence will multiply the input // sequence by the length of the sequence. // // If the length of seq is not t.Len(), Coefficients will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal the length of seq, Coefficients will panic. // It is safe to use the same slice for dst and seq. func (t *CmplxFFT) Coefficients(dst, seq []complex128) []complex128 { if len(seq) != t.Len() { panic("fourier: sequence length mismatch") } if dst == nil { dst = make([]complex128, len(seq)) } else if len(dst) != len(seq) { panic("fourier: destination length mismatch") } for i, cv := range seq { t.real[2*i] = real(cv) t.real[2*i+1] = imag(cv) } fftpack.Cfftf(len(dst), t.real, t.work, t.ifac[:]) for i := range dst { dst[i] = complex(t.real[2*i], t.real[2*i+1]) } return dst } // Sequence computes the complex periodic sequence from the Fourier coefficients, // converting the frequency spectrum in coeff into a time series, placing the // result in dst and returning it. This transform is unnormalized; a call to // Coefficients followed by a call of Sequence will multiply the input sequence // by the length of the sequence. // // If the length of coeff is not t.Len(), Sequence will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal the length of coeff, Sequence will panic. // It is safe to use the same slice for dst and coeff. func (t *CmplxFFT) Sequence(dst, coeff []complex128) []complex128 { if len(coeff) != t.Len() { panic("fourier: coefficients length mismatch") } if dst == nil { dst = make([]complex128, len(coeff)) } else if len(dst) != len(coeff) { panic("fourier: destination length mismatch") } for i, cv := range coeff { t.real[2*i] = real(cv) t.real[2*i+1] = imag(cv) } fftpack.Cfftb(len(dst), t.real, t.work, t.ifac[:]) for i := range dst { dst[i] = complex(t.real[2*i], t.real[2*i+1]) } return dst } // Freq returns the relative frequency center for coefficient i. // Freq will panic if i is negative or greater than or equal to t.Len(). func (t *CmplxFFT) Freq(i int) float64 { if i < 0 || t.Len() <= i { panic("fourier: index out of range") } step := 1 / float64(t.Len()) if i < (t.Len()-1)/2+1 { return step * float64(i) } return step * float64(i-t.Len()) } // ShiftIdx returns a shifted index into a slice of coefficients // returned by the CmplxFFT so that indexing into the coefficients // places the zero frequency component at the center of the spectrum. // ShiftIdx will panic if i is negative or greater than or equal to // t.Len(). func (t *CmplxFFT) ShiftIdx(i int) int { if i < 0 || t.Len() <= i { panic("fourier: index out of range") } h := t.Len() / 2 if i < h { return i + (t.Len()+1)/2 } return i - h } // UnshiftIdx returns inverse of ShiftIdx. UnshiftIdx will panic if i is // negative or greater than or equal to t.Len(). func (t *CmplxFFT) UnshiftIdx(i int) int { if i < 0 || t.Len() <= i { panic("fourier: index out of range") } h := (t.Len() + 1) / 2 if i < h { return i + t.Len()/2 } return i - h } golang-gonum-v1-gonum-0.14.0/dsp/fourier/fourier_example_test.go000066400000000000000000000147171450372207100246650ustar00rootroot00000000000000// 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 fourier_test import ( "fmt" "math" "math/cmplx" "gonum.org/v1/gonum/dsp/fourier" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func ExampleFFT_Coefficients() { // Samples is a set of samples over a given period. samples := []float64{1, 0, 2, 0, 4, 0, 2, 0} period := float64(len(samples)) // Initialize an FFT and perform the analysis. fft := fourier.NewFFT(len(samples)) coeff := fft.Coefficients(nil, samples) for i, c := range coeff { fmt.Printf("freq=%v cycles/period, magnitude=%v, phase=%.4g\n", fft.Freq(i)*period, cmplx.Abs(c), cmplx.Phase(c)) } // Output: // // freq=0 cycles/period, magnitude=9, phase=0 // freq=1 cycles/period, magnitude=3, phase=3.142 // freq=2 cycles/period, magnitude=1, phase=-0 // freq=3 cycles/period, magnitude=3, phase=3.142 // freq=4 cycles/period, magnitude=9, phase=0 } func ExampleFFT_Coefficients_tone() { // Tone is a set of samples over a second of a pure Middle C. const ( mC = 261.625565 // Hz samples = 44100 ) tone := make([]float64, samples) for i := range tone { tone[i] = math.Sin(mC * 2 * math.Pi * float64(i) / samples) } // Initialize an FFT and perform the analysis. fft := fourier.NewFFT(samples) coeff := fft.Coefficients(nil, tone) var maxFreq, magnitude, mean float64 for i, c := range coeff { m := cmplx.Abs(c) mean += m if m > magnitude { magnitude = m maxFreq = fft.Freq(i) * samples } } fmt.Printf("freq=%v Hz, magnitude=%.0f, mean=%.4f\n", maxFreq, magnitude, mean/samples) // Output: // // freq=262 Hz, magnitude=17296, mean=2.7835 } func ExampleCmplxFFT_Coefficients() { // Samples is a set of samples over a given period. samples := []complex128{1, 0, 2, 0, 4, 0, 2, 0} period := float64(len(samples)) // Initialize a complex FFT and perform the analysis. fft := fourier.NewCmplxFFT(len(samples)) coeff := fft.Coefficients(nil, samples) for i := range coeff { // Center the spectrum. i = fft.ShiftIdx(i) fmt.Printf("freq=%v cycles/period, magnitude=%v, phase=%.4g\n", fft.Freq(i)*period, cmplx.Abs(coeff[i]), cmplx.Phase(coeff[i])) } // Output: // // freq=-4 cycles/period, magnitude=9, phase=0 // freq=-3 cycles/period, magnitude=3, phase=3.142 // freq=-2 cycles/period, magnitude=1, phase=0 // freq=-1 cycles/period, magnitude=3, phase=3.142 // freq=0 cycles/period, magnitude=9, phase=0 // freq=1 cycles/period, magnitude=3, phase=3.142 // freq=2 cycles/period, magnitude=1, phase=0 // freq=3 cycles/period, magnitude=3, phase=3.142 } func Example_fFT2() { // This example shows how to perform a 2D fourier transform // on an image. The transform identifies the lines present // in the image. // Image is a set of diagonal lines. image := mat.NewDense(11, 11, []float64{ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, }) // Make appropriately sized real and complex FFT types. r, c := image.Dims() fft := fourier.NewFFT(c) cfft := fourier.NewCmplxFFT(r) // Only c/2+1 coefficients will be returned for // the real FFT. c = c/2 + 1 // Perform the first axis transform. rows := make([]complex128, r*c) for i := 0; i < r; i++ { fft.Coefficients(rows[c*i:c*(i+1)], image.RawRowView(i)) } // Perform the second axis transform, storing // the result in freqs. freqs := mat.NewDense(c, c, nil) column := make([]complex128, r) for j := 0; j < c; j++ { for i := 0; i < r; i++ { column[i] = rows[i*c+j] } cfft.Coefficients(column, column) for i, v := range column[:c] { freqs.Set(i, j, scalar.Round(cmplx.Abs(v), 1)) } } fmt.Printf("%v\n", mat.Formatted(freqs)) // Output: // // ⎡ 40 0.4 0.5 1.4 3.2 1.1⎤ // ⎢ 0.4 0.5 0.7 1.8 4 1.2⎥ // ⎢ 0.5 0.7 1.1 2.8 5.9 1.7⎥ // ⎢ 1.4 1.8 2.8 6.8 14.1 3.8⎥ // ⎢ 3.2 4 5.9 14.1 27.5 6.8⎥ // ⎣ 1.1 1.2 1.7 3.8 6.8 1.6⎦ } func Example_cmplxFFT2() { // Image is a set of diagonal lines. image := mat.NewDense(11, 11, []float64{ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, }) // Make appropriately sized complex FFT. // Rows and columns are the same, so the same // CmplxFFT can be used for both axes. r, c := image.Dims() cfft := fourier.NewCmplxFFT(r) // Perform the first axis transform. rows := make([]complex128, r*c) for i := 0; i < r; i++ { row := rows[c*i : c*(i+1)] for j, v := range image.RawRowView(i) { row[j] = complex(v, 0) } cfft.Coefficients(row, row) } // Perform the second axis transform, storing // the result in freqs. freqs := mat.NewDense(c, c, nil) column := make([]complex128, r) for j := 0; j < c; j++ { for i := 0; i < r; i++ { column[i] = rows[i*c+j] } cfft.Coefficients(column, column) for i, v := range column { // Center the frequencies. freqs.Set(cfft.UnshiftIdx(i), cfft.UnshiftIdx(j), scalar.Round(cmplx.Abs(v), 1)) } } fmt.Printf("%v\n", mat.Formatted(freqs)) // Output: // // ⎡ 1.6 6.8 3.8 1.7 1.2 1.1 1.1 1.4 2.6 3.9 1.1⎤ // ⎢ 6.8 27.5 14.1 5.9 4 3.2 3 3 3.9 3.2 3.9⎥ // ⎢ 3.8 14.1 6.8 2.8 1.8 1.4 1.2 1.1 1.4 3.9 2.6⎥ // ⎢ 1.7 5.9 2.8 1.1 0.7 0.5 0.5 0.5 1.1 3 1.4⎥ // ⎢ 1.2 4 1.8 0.7 0.5 0.4 0.4 0.5 1.2 3 1.1⎥ // ⎢ 1.1 3.2 1.4 0.5 0.4 40 0.4 0.5 1.4 3.2 1.1⎥ // ⎢ 1.1 3 1.2 0.5 0.4 0.4 0.5 0.7 1.8 4 1.2⎥ // ⎢ 1.4 3 1.1 0.5 0.5 0.5 0.7 1.1 2.8 5.9 1.7⎥ // ⎢ 2.6 3.9 1.4 1.1 1.2 1.4 1.8 2.8 6.8 14.1 3.8⎥ // ⎢ 3.9 3.2 3.9 3 3 3.2 4 5.9 14.1 27.5 6.8⎥ // ⎣ 1.1 3.9 2.6 1.4 1.1 1.1 1.2 1.7 3.8 6.8 1.6⎦ } golang-gonum-v1-gonum-0.14.0/dsp/fourier/fourier_test.go000066400000000000000000000262011450372207100231410ustar00rootroot00000000000000// 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 fourier import ( "fmt" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) func TestFFT(t *testing.T) { t.Parallel() const tol = 1e-10 rnd := rand.New(rand.NewSource(1)) t.Run("NewFFT", func(t *testing.T) { for n := 1; n <= 200; n++ { fft := NewFFT(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } coeff := fft.Coefficients(nil, want) got := fft.Sequence(nil, coeff) floats.Scale(1/float64(n), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for sequence(coefficients(x)) for length %d", n) } } }) t.Run("Reset FFT", func(t *testing.T) { fft := NewFFT(1000) for n := 1; n <= 2000; n++ { fft.Reset(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } coeff := fft.Coefficients(nil, want) got := fft.Sequence(nil, coeff) floats.Scale(1/float64(n), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for sequence(coefficients(x)) for length %d", n) } } }) t.Run("known FFT", func(t *testing.T) { // Values confirmed with reference to numpy rfft. fft := NewFFT(1000) cases := []struct { in []float64 want []complex128 }{ { in: []float64{1, 0, 1, 0, 1, 0, 1, 0}, want: []complex128{4, 0, 0, 0, 4}, }, { in: []float64{1, 0, 1, 0, 1, 0, 1}, want: []complex128{ 4, 0.5 + 0.24078730940376442i, 0.5 + 0.6269801688313512i, 0.5 + 2.190643133767413i, }, }, { in: []float64{1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0}, want: []complex128{ 12, -2.301937735804838 - 1.108554787638881i, 0.7469796037174659 + 0.9366827961047095i, -0.9450418679126271 - 4.140498958131061i, -0.9450418679126271 + 4.140498958131061i, 0.7469796037174659 - 0.9366827961047095i, -2.301937735804838 + 1.108554787638881i, 12, }, }, } for _, test := range cases { fft.Reset(len(test.in)) got := fft.Coefficients(nil, test.in) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for coefficients(%g):\ngot: %g\nwant:%g", test.in, got, test.want) } } }) t.Run("Freq", func(t *testing.T) { var fft FFT cases := []struct { n int want []float64 }{ {n: 1, want: []float64{0}}, {n: 2, want: []float64{0, 0.5}}, {n: 3, want: []float64{0, 1.0 / 3.0}}, {n: 4, want: []float64{0, 0.25, 0.5}}, } for _, test := range cases { fft.Reset(test.n) for i, want := range test.want { if got := fft.Freq(i); got != want { t.Errorf("unexpected result for freq(%d) for length %d: got:%v want:%v", i, test.n, got, want) } } } }) } func TestCmplxFFT(t *testing.T) { const tol = 1e-12 rnd := rand.New(rand.NewSource(1)) t.Run("NewFFT", func(t *testing.T) { for n := 1; n <= 200; n++ { fft := NewCmplxFFT(n) want := make([]complex128, n) for i := range want { want[i] = complex(rnd.Float64(), rnd.Float64()) } coeff := fft.Coefficients(nil, want) got := fft.Sequence(nil, coeff) sf := complex(1/float64(n), 0) for i := range got { got[i] *= sf } if !equalApprox(got, want, tol) { t.Errorf("unexpected result for complex sequence(coefficients(x)) for length %d", n) } } }) t.Run("Reset FFT", func(t *testing.T) { fft := NewCmplxFFT(1000) for n := 1; n <= 2000; n++ { fft.Reset(n) want := make([]complex128, n) for i := range want { want[i] = complex(rnd.Float64(), rnd.Float64()) } coeff := fft.Coefficients(nil, want) got := fft.Sequence(nil, coeff) sf := complex(1/float64(n), 0) for i := range got { got[i] *= sf } if !equalApprox(got, want, tol) { t.Errorf("unexpected result for complex sequence(coefficients(x)) for length %d", n) } } }) t.Run("Freq", func(t *testing.T) { var fft CmplxFFT cases := []struct { want []float64 }{ {want: []float64{0}}, {want: []float64{0, -0.5}}, {want: []float64{0, 1.0 / 3.0, -1.0 / 3.0}}, {want: []float64{0, 0.25, -0.5, -0.25}}, } for _, test := range cases { fft.Reset(len(test.want)) for i, want := range test.want { if got := fft.Freq(i); got != want { t.Errorf("unexpected result for freq(%d) for length %d: got:%v want:%v", i, len(test.want), got, want) } } } }) t.Run("Shift", func(t *testing.T) { var fft CmplxFFT cases := []struct { index []int want []int }{ {index: []int{0}, want: []int{0}}, {index: []int{0, -1}, want: []int{-1, 0}}, {index: []int{0, 1, -1}, want: []int{-1, 0, 1}}, {index: []int{0, 1, -2, -1}, want: []int{-2, -1, 0, 1}}, {index: []int{0, 1, 2, -2, -1}, want: []int{-2, -1, 0, 1, 2}}, } for _, test := range cases { fft.Reset(len(test.index)) got := make([]int, len(test.index)) for i := range test.index { got[i] = test.index[fft.ShiftIdx(i)] su := fft.UnshiftIdx(fft.ShiftIdx(i)) if su != i { t.Errorf("unexpected result for unshift(shift(%d)) with length %d:\ngot: %d\nwant:%d", i, len(test.index), su, i) } } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for shift(%d):\ngot: %d\nwant:%d", test.index, got, test.want) } } }) } func TestDCT(t *testing.T) { t.Parallel() const tol = 1e-10 rnd := rand.New(rand.NewSource(1)) t.Run("NewDCT", func(t *testing.T) { for n := 2; n <= 200; n++ { dct := NewDCT(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } coeff := dct.Transform(nil, want) got := dct.Transform(nil, coeff) floats.Scale(1/float64(2*(n-1)), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for transform(transform(x)) for length %d", n) } } }) t.Run("Reset DCT", func(t *testing.T) { dct := NewDCT(1000) for n := 2; n <= 2000; n++ { dct.Reset(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } coeff := dct.Transform(nil, want) got := dct.Transform(nil, coeff) floats.Scale(1/float64(2*(n-1)), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for transform(transform(x)) for length %d", n) } } }) } func TestDST(t *testing.T) { t.Parallel() const tol = 1e-10 rnd := rand.New(rand.NewSource(1)) t.Run("NewDST", func(t *testing.T) { for n := 1; n <= 200; n++ { dst := NewDST(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } coeff := dst.Transform(nil, want) got := dst.Transform(nil, coeff) floats.Scale(1/float64(2*(n+1)), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for transform(transform(x)) for length %d", n) } } }) t.Run("Reset DST", func(t *testing.T) { dst := NewDST(1000) for n := 1; n <= 2000; n++ { dst.Reset(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } coeff := dst.Transform(nil, want) got := dst.Transform(nil, coeff) floats.Scale(1/float64(2*(n+1)), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for transform(transform(x)) for length %d", n) } } }) } func TestQuarterWaveFFT(t *testing.T) { t.Parallel() const tol = 1e-10 rnd := rand.New(rand.NewSource(1)) t.Run("NewQuarterWaveFFT", func(t *testing.T) { for n := 1; n <= 200; n++ { qw := NewQuarterWaveFFT(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } { coeff := qw.CosCoefficients(nil, want) got := qw.CosSequence(nil, coeff) floats.Scale(1/float64(4*n), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for cossequence(coscoefficient(x)) for length %d", n) } } { coeff := qw.SinCoefficients(nil, want) got := qw.SinSequence(nil, coeff) floats.Scale(1/float64(4*n), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for sinsequence(sincoefficient(x)) for length %d", n) } } } }) t.Run("Reset QuarterWaveFFT", func(t *testing.T) { qw := NewQuarterWaveFFT(1000) for n := 1; n <= 2000; n++ { qw.Reset(n) want := make([]float64, n) for i := range want { want[i] = rnd.Float64() } { coeff := qw.CosCoefficients(nil, want) got := qw.CosSequence(nil, coeff) floats.Scale(1/float64(4*n), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for cossequence(coscoefficient(x)) for length %d", n) } } { coeff := qw.SinCoefficients(nil, want) got := qw.SinSequence(nil, coeff) floats.Scale(1/float64(4*n), got) if !floats.EqualApprox(got, want, tol) { t.Errorf("unexpected result for sinsequence(sincoefficient(x)) for length %d", n) } } } }) } func equalApprox(a, b []complex128, tol float64) bool { if len(a) != len(b) { return false } ar := make([]float64, len(a)) br := make([]float64, len(a)) ai := make([]float64, len(a)) bi := make([]float64, len(a)) for i, cv := range a { ar[i] = real(cv) ai[i] = imag(cv) } for i, cv := range b { br[i] = real(cv) bi[i] = imag(cv) } return floats.EqualApprox(ar, br, tol) && floats.EqualApprox(ai, bi, tol) } func BenchmarkRealFFTCoefficients(b *testing.B) { var sizes []int for n := 16; n < 1<<24; n <<= 3 { sizes = append(sizes, n) } sizes = append(sizes, 100, 4000, 1e6) for _, n := range sizes { fft := NewFFT(n) seq := randFloats(n, rand.NewSource(1)) dst := make([]complex128, n/2+1) b.Run(fmt.Sprint(n), func(b *testing.B) { for i := 0; i < b.N; i++ { fft.Coefficients(dst, seq) } }) } } func BenchmarkRealFFTSequence(b *testing.B) { var sizes []int for n := 16; n < 1<<24; n <<= 3 { sizes = append(sizes, n) } sizes = append(sizes, 100, 4000, 1e6) for _, n := range sizes { fft := NewFFT(n) coeff := randComplexes(n/2+1, rand.NewSource(1)) dst := make([]float64, n) b.Run(fmt.Sprint(n), func(b *testing.B) { for i := 0; i < b.N; i++ { fft.Sequence(dst, coeff) } }) } } func BenchmarkCmplxFFTCoefficients(b *testing.B) { var sizes []int for n := 16; n < 1<<24; n <<= 3 { sizes = append(sizes, n) } sizes = append(sizes, 100, 4000, 1e6) for _, n := range sizes { fft := NewCmplxFFT(n) d := randComplexes(n, rand.NewSource(1)) b.Run(fmt.Sprint(n), func(b *testing.B) { for i := 0; i < b.N; i++ { fft.Coefficients(d, d) } }) } } func BenchmarkCmplxFFTSequence(b *testing.B) { var sizes []int for n := 16; n < 1<<24; n <<= 3 { sizes = append(sizes, n) } sizes = append(sizes, 100, 4000, 1e6) for _, n := range sizes { fft := NewCmplxFFT(n) d := randComplexes(n, rand.NewSource(1)) b.Run(fmt.Sprint(n), func(b *testing.B) { for i := 0; i < b.N; i++ { fft.Sequence(d, d) } }) } } func randFloats(n int, src rand.Source) []float64 { rnd := rand.New(src) f := make([]float64, n) for i := range f { f[i] = rnd.Float64() } return f } func randComplexes(n int, src rand.Source) []complex128 { rnd := rand.New(src) c := make([]complex128, n) for i := range c { c[i] = complex(rnd.Float64(), rnd.Float64()) } return c } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/000077500000000000000000000000001450372207100217135ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/000077500000000000000000000000001450372207100233315ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/array_bounds_checks.go000066400000000000000000000066251450372207100277010ustar00rootroot00000000000000// 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. // This file must be kept in sync with array_no_bound_checks.go. //go:build bounds // +build bounds package fftpack import "fmt" // The types in array.go implement Fortran-like arrays for bootstrapping // the implementation of the FFT functions translated from FFTPACK; they // are column-major. type twoArray struct { i, j int jStride int data []float64 } func newTwoArray(i, j int, data []float64) twoArray { if len(data) < i*j { panic(fmt.Sprintf("short data: len(data)=%d, i=%d, j=%d", len(data), i, j)) } return twoArray{ i: i, j: j, jStride: i, data: data[:i*j], } } func (a twoArray) at(i, j int) float64 { if i < 0 || a.i <= i || j < 0 || a.j <= j { panic(fmt.Sprintf("out of bounds at(%d, %d): bounds i=%d, j=%d", i, j, a.i, a.j)) } return a.data[i+a.jStride*j] } func (a twoArray) atCmplx(i, j int) complex128 { if i < 0 || a.i <= i || j < 0 || a.j <= j { panic(fmt.Sprintf("out of bounds at(%d, %d): bounds i=%d, j=%d", i, j, a.i, a.j)) } return complex(a.data[i+a.jStride*j], a.data[i+a.jStride*j+1]) } func (a twoArray) set(i, j int, v float64) { if i < 0 || a.i <= i || j < 0 || a.j <= j { panic(fmt.Sprintf("out of bounds set(%d, %d): bounds i=%d, j=%d", i, j, a.i, a.j)) } a.data[i+a.jStride*j] = v } func (a twoArray) setCmplx(i, j int, v complex128) { if i < 0 || a.i <= i || j < 0 || a.j <= j { panic(fmt.Sprintf("out of bounds set(%d, %d): bounds i=%d, j=%d", i, j, a.i, a.j)) } a.data[i+a.jStride*j] = real(v) a.data[i+a.jStride*j+1] = imag(v) } func (a twoArray) add(i, j int, v float64) { if i < 0 || a.i <= i || j < 0 || a.j <= j { panic(fmt.Sprintf("out of bounds set(%d, %d): bounds i=%d, j=%d", i, j, a.i, a.j)) } a.data[i+a.jStride*j] += v } type threeArray struct { i, j, k int jStride, kStride int data []float64 } func newThreeArray(i, j, k int, data []float64) threeArray { if len(data) < i*j*k { panic(fmt.Sprintf("short data: len(data)=%d, i=%d, j=%d, k=%d", len(data), i, j, k)) } return threeArray{ i: i, j: j, k: k, jStride: i, kStride: i * j, data: data[:i*j*k], } } func (a threeArray) at(i, j, k int) float64 { if i < 0 || a.i <= i || j < 0 || a.j <= j || k < 0 || a.k <= k { panic(fmt.Sprintf("out of bounds at(%d, %d, %d): bounds i=%d, j=%d, k=%d", i, j, k, a.i, a.j, a.k)) } return a.data[i+a.jStride*j+a.kStride*k] } func (a threeArray) atCmplx(i, j, k int) complex128 { if i < 0 || a.i <= i || j < 0 || a.j <= j || k < 0 || a.k <= k { panic(fmt.Sprintf("out of bounds at(%d, %d, %d): bounds i=%d, j=%d, k=%d", i, j, k, a.i, a.j, a.k)) } return complex(a.data[i+a.jStride*j+a.kStride*k], a.data[i+a.jStride*j+a.kStride*k+1]) } func (a threeArray) set(i, j, k int, v float64) { if i < 0 || a.i <= i || j < 0 || a.j <= j || k < 0 || a.k <= k { panic(fmt.Sprintf("out of bounds set(%d, %d, %d): bounds i=%d, j=%d, k=%d", i, j, k, a.i, a.j, a.k)) } a.data[i+a.jStride*j+a.kStride*k] = v } func (a threeArray) setCmplx(i, j, k int, v complex128) { if i < 0 || a.i <= i || j < 0 || a.j <= j || k < 0 || a.k <= k { panic(fmt.Sprintf("out of bounds set(%d, %d, %d): bounds i=%d, j=%d, k=%d", i, j, k, a.i, a.j, a.k)) } a.data[i+a.jStride*j+a.kStride*k] = real(v) a.data[i+a.jStride*j+a.kStride*k+1] = imag(v) } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/array_no_bounds_checks.go000066400000000000000000000035611450372207100303710ustar00rootroot00000000000000// 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. // This file must be kept in sync with array_bound_checks.go. //go:build !bounds // +build !bounds package fftpack // The types in array.go implement Fortran-like arrays for bootstrapping // the implementation of the FFT functions translated from FFTPACK; they // are column-major. type twoArray struct { jStride int data []float64 } func newTwoArray(i, j int, data []float64) twoArray { if len(data) < i*j { panic("fourier: short data") } return twoArray{ jStride: i, data: data[:i*j], } } func (a twoArray) at(i, j int) float64 { return a.data[i+a.jStride*j] } func (a twoArray) atCmplx(i, j int) complex128 { return complex(a.data[i+a.jStride*j], a.data[i+a.jStride*j+1]) } func (a twoArray) set(i, j int, v float64) { a.data[i+a.jStride*j] = v } func (a twoArray) setCmplx(i, j int, v complex128) { a.data[i+a.jStride*j] = real(v) a.data[i+a.jStride*j+1] = imag(v) } func (a twoArray) add(i, j int, v float64) { a.data[i+a.jStride*j] += v } type threeArray struct { jStride, kStride int data []float64 } func newThreeArray(i, j, k int, data []float64) threeArray { if len(data) < i*j*k { panic("fourier: short data") } return threeArray{ jStride: i, kStride: i * j, data: data[:i*j*k], } } func (a threeArray) at(i, j, k int) float64 { return a.data[i+a.jStride*j+a.kStride*k] } func (a threeArray) atCmplx(i, j, k int) complex128 { return complex(a.data[i+a.jStride*j+a.kStride*k], a.data[i+a.jStride*j+a.kStride*k+1]) } func (a threeArray) set(i, j, k int, v float64) { a.data[i+a.jStride*j+a.kStride*k] = v } func (a threeArray) setCmplx(i, j, k int, v complex128) { a.data[i+a.jStride*j+a.kStride*k] = real(v) a.data[i+a.jStride*j+a.kStride*k+1] = imag(v) } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/cfft.go000066400000000000000000000365551450372207100246200ustar00rootroot00000000000000// 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. // This is a translation of the FFTPACK cfft functions by // Paul N Swarztrauber, placed in the public domain at // http://www.netlib.org/fftpack/. package fftpack import ( "math" "math/cmplx" ) // Cffti initializes the array work which is used in both Cfftf // and Cfftb. the prime factorization of n together with a // tabulation of the trigonometric functions are computed and // stored in work. // // Input parameter: // // n The length of the sequence to be transformed. // // Output parameters: // // work A work array which must be dimensioned at least 4*n. // the same work array can be used for both Cfftf and Cfftb // as long as n remains unchanged. Different work arrays // are required for different values of n. The contents of // work must not be changed between calls of Cfftf or Cfftb. // // ifac A work array containing the factors of n. ifac must have // length 15. func Cffti(n int, work []float64, ifac []int) { if len(work) < 4*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 1 { return } cffti1(n, work[2*n:4*n], ifac[:15]) } func cffti1(n int, wa []float64, ifac []int) { ntryh := [4]int{3, 4, 2, 5} nl := n nf := 0 outer: for j, ntry := 0, 0; ; j++ { if j < 4 { ntry = ntryh[j] } else { ntry += 2 } for { if nl%ntry != 0 { continue outer } ifac[nf+2] = ntry nl /= ntry nf++ if ntry == 2 && nf != 1 { for i := 1; i < nf; i++ { ib := nf - i + 1 ifac[ib+1] = ifac[ib] } ifac[2] = 2 } if nl == 1 { break outer } } } ifac[0] = n ifac[1] = nf argh := 2 * math.Pi / float64(n) i := 1 l1 := 1 for k1 := 0; k1 < nf; k1++ { ip := ifac[k1+2] ld := 0 l2 := l1 * ip ido := n / l2 idot := 2*ido + 2 for j := 0; j < ip-1; j++ { i1 := i wa[i-1] = 1 wa[i] = 0 ld += l1 var fi float64 argld := float64(ld) * argh for ii := 3; ii < idot; ii += 2 { i += 2 fi++ arg := fi * argld wa[i-1] = math.Cos(arg) wa[i] = math.Sin(arg) } if ip > 5 { wa[i1-1] = wa[i-1] wa[i1] = wa[i] } } l1 = l2 } } // Cfftf computes the forward complex Discrete Fourier transform // (the Fourier analysis). Equivalently, Cfftf computes the // Fourier coefficients of a complex periodic sequence. The // transform is defined below at output parameter c. // // Input parameters: // // n The length of the array c to be transformed. The method // is most efficient when n is a product of small primes. // n may change so long as different work arrays are provided. // // c A complex array of length n which contains the sequence // to be transformed. // // work A real work array which must be dimensioned at least 4*n. // in the program that calls Cfftf. The work array must be // initialized by calling subroutine Cffti(n,work,ifac) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // the same work array can be used by Cfftf and Cfftb. // // ifac A work array containing the factors of n. ifac must have // length of at least 15. // // Output parameters: // // c for j=0, ..., n-1 // c[j]=the sum from k=0, ..., n-1 of // c[k]*exp(-i*j*k*2*pi/n) // // where i=sqrt(-1) // // This transform is unnormalized since a call of Cfftf // followed by a call of Cfftb will multiply the input // sequence by n. // // The n elements of c are represented in n pairs of real // values in r where c[j] = r[j*2]+r[j*2+1]i. // // work Contains results which must not be destroyed between // calls of Cfftf or Cfftb. // ifac Contains results which must not be destroyed between // calls of Cfftf or Cfftb. func Cfftf(n int, r, work []float64, ifac []int) { if len(r) < 2*n { panic("fourier: short sequence") } if len(work) < 4*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 1 { return } cfft1(n, r[:2*n], work[:2*n], work[2*n:4*n], ifac[:15], -1) } // Cfftb computes the backward complex Discrete Fourier Transform // (the Fourier synthesis). Equivalently, Cfftf computes the computes // a complex periodic sequence from its Fourier coefficients. The // transform is defined below at output parameter c. // // Input parameters: // // n The length of the array c to be transformed. The method // is most efficient when n is a product of small primes. // n may change so long as different work arrays are provided. // // c A complex array of length n which contains the sequence // to be transformed. // // work A real work array which must be dimensioned at least 4*n. // in the program that calls Cfftb. The work array must be // initialized by calling subroutine Cffti(n,work,ifac) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // The same work array can be used by Cfftf and Cfftb. // // ifac A work array containing the factors of n. ifac must have // length of at least 15. // // Output parameters: // // c for j=0, ..., n-1 // c[j]=the sum from k=0, ..., n-1 of // c[k]*exp(i*j*k*2*pi/n) // // where i=sqrt(-1) // // This transform is unnormalized since a call of Cfftf // followed by a call of Cfftb will multiply the input // sequence by n. // // The n elements of c are represented in n pairs of real // values in r where c[j] = r[j*2]+r[j*2+1]i. // // work Contains results which must not be destroyed between // calls of Cfftf or Cfftb. // ifac Contains results which must not be destroyed between // calls of Cfftf or Cfftb. func Cfftb(n int, c, work []float64, ifac []int) { if len(c) < 2*n { panic("fourier: short sequence") } if len(work) < 4*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 1 { return } cfft1(n, c[:2*n], work[:2*n], work[2*n:4*n], ifac[:15], 1) } // cfft1 implements cfftf1 and cfftb1 depending on sign. func cfft1(n int, c, ch, wa []float64, ifac []int, sign float64) { nf := ifac[1] na := false l1 := 1 iw := 0 for k1 := 1; k1 <= nf; k1++ { ip := ifac[k1+1] l2 := ip * l1 ido := n / l2 idot := 2 * ido idl1 := idot * l1 switch ip { case 4: ix2 := iw + idot ix3 := ix2 + idot if na { pass4(idot, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], sign) } else { pass4(idot, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], sign) } na = !na case 2: if na { pass2(idot, l1, ch, c, wa[iw:], sign) } else { pass2(idot, l1, c, ch, wa[iw:], sign) } na = !na case 3: ix2 := iw + idot if na { pass3(idot, l1, ch, c, wa[iw:], wa[ix2:], sign) } else { pass3(idot, l1, c, ch, wa[iw:], wa[ix2:], sign) } na = !na case 5: ix2 := iw + idot ix3 := ix2 + idot ix4 := ix3 + idot if na { pass5(idot, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:], sign) } else { pass5(idot, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:], sign) } na = !na default: var nac bool if na { nac = pass(idot, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:], sign) } else { nac = pass(idot, ip, l1, idl1, c, c, c, ch, ch, wa[iw:], sign) } if nac { na = !na } } l1 = l2 iw += (ip - 1) * idot } if na { for i := 0; i < 2*n; i++ { c[i] = ch[i] } } } // pass2 implements passf2 and passb2 depending on sign. func pass2(ido, l1 int, cc, ch, wa1 []float64, sign float64) { cc3 := newThreeArray(ido, 2, l1, cc) ch3 := newThreeArray(ido, l1, 2, ch) if ido <= 2 { for k := 0; k < l1; k++ { ch3.setCmplx(0, k, 0, cc3.atCmplx(0, 0, k)+cc3.atCmplx(0, 1, k)) ch3.setCmplx(0, k, 1, cc3.atCmplx(0, 0, k)-cc3.atCmplx(0, 1, k)) } return } for k := 0; k < l1; k++ { for i := 1; i < ido; i += 2 { ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+cc3.atCmplx(i-1, 1, k)) t2 := cc3.atCmplx(i-1, 0, k) - cc3.atCmplx(i-1, 1, k) ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*t2) } } } // pass3 implements passf3 and passb3 depending on sign. func pass3(ido, l1 int, cc, ch, wa1, wa2 []float64, sign float64) { const ( taur = -0.5 taui = 0.866025403784439 // sqrt(3)/2 ) cc3 := newThreeArray(ido, 3, l1, cc) ch3 := newThreeArray(ido, l1, 3, ch) if ido == 2 { for k := 0; k < l1; k++ { t2 := cc3.atCmplx(0, 1, k) + cc3.atCmplx(0, 2, k) ch3.setCmplx(0, k, 0, cc3.atCmplx(0, 0, k)+t2) c2 := cc3.atCmplx(0, 0, k) + scale(taur, t2) c3 := cmplx.Conj(swap(scale(sign*taui, cc3.atCmplx(0, 1, k)-cc3.atCmplx(0, 2, k)))) ch3.setCmplx(0, k, 1, c2-c3) ch3.setCmplx(0, k, 2, c2+c3) } return } for k := 0; k < l1; k++ { for i := 1; i < ido; i += 2 { t2 := cc3.atCmplx(i-1, 1, k) + cc3.atCmplx(i-1, 2, k) ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2) c2 := cc3.atCmplx(i-1, 0, k) + scale(taur, t2) c3 := cmplx.Conj(swap(scale(sign*taui, cc3.atCmplx(i-1, 1, k)-cc3.atCmplx(i-1, 2, k)))) d2 := c2 - c3 d3 := c2 + c3 ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*d2) ch3.setCmplx(i-1, k, 2, complex(wa2[i-1], sign*wa2[i])*d3) } } } // pass4 implements passf4 and passb4 depending on sign. func pass4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64, sign float64) { cc3 := newThreeArray(ido, 4, l1, cc) ch3 := newThreeArray(ido, l1, 4, ch) if ido == 2 { for k := 0; k < l1; k++ { t1 := cc3.atCmplx(0, 0, k) - cc3.atCmplx(0, 2, k) t2 := cc3.atCmplx(0, 0, k) + cc3.atCmplx(0, 2, k) t3 := cc3.atCmplx(0, 1, k) + cc3.atCmplx(0, 3, k) t4 := cmplx.Conj(swap(scale(sign, cc3.atCmplx(0, 3, k)-cc3.atCmplx(0, 1, k)))) ch3.setCmplx(0, k, 0, t2+t3) ch3.setCmplx(0, k, 1, t1+t4) ch3.setCmplx(0, k, 2, t2-t3) ch3.setCmplx(0, k, 3, t1-t4) } return } for k := 0; k < l1; k++ { for i := 1; i < ido; i += 2 { t1 := cc3.atCmplx(i-1, 0, k) - cc3.atCmplx(i-1, 2, k) t2 := cc3.atCmplx(i-1, 0, k) + cc3.atCmplx(i-1, 2, k) t3 := cc3.atCmplx(i-1, 1, k) + cc3.atCmplx(i-1, 3, k) t4 := cmplx.Conj(swap(scale(sign, cc3.atCmplx(i-1, 3, k)-cc3.atCmplx(i-1, 1, k)))) ch3.setCmplx(i-1, k, 0, t2+t3) c2 := t1 + t4 c3 := t2 - t3 c4 := t1 - t4 ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*c2) ch3.setCmplx(i-1, k, 2, complex(wa2[i-1], sign*wa2[i])*c3) ch3.setCmplx(i-1, k, 3, complex(wa3[i-1], sign*wa3[i])*c4) } } } // pass5 implements passf5 and passb5 depending on sign. func pass5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64, sign float64) { const ( tr11 = 0.309016994374947 ti11 = 0.951056516295154 tr12 = -0.809016994374947 ti12 = 0.587785252292473 ) cc3 := newThreeArray(ido, 5, l1, cc) ch3 := newThreeArray(ido, l1, 5, ch) if ido == 2 { for k := 0; k < l1; k++ { t2 := cc3.atCmplx(0, 1, k) + cc3.atCmplx(0, 4, k) t3 := cc3.atCmplx(0, 2, k) + cc3.atCmplx(0, 3, k) t4 := cc3.atCmplx(0, 2, k) - cc3.atCmplx(0, 3, k) t5 := cc3.atCmplx(0, 1, k) - cc3.atCmplx(0, 4, k) ch3.setCmplx(0, k, 0, cc3.atCmplx(0, 0, k)+t2+t3) c2 := cc3.atCmplx(0, 0, k) + scale(tr11, t2) + scale(tr12, t3) c3 := cc3.atCmplx(0, 0, k) + scale(tr12, t2) + scale(tr11, t3) c4 := cmplx.Conj(swap(scale(sign, scale(ti12, t5)-scale(ti11, t4)))) c5 := cmplx.Conj(swap(scale(sign, scale(ti11, t5)+scale(ti12, t4)))) ch3.setCmplx(0, k, 1, c2-c5) ch3.setCmplx(0, k, 2, c3-c4) ch3.setCmplx(0, k, 3, c3+c4) ch3.setCmplx(0, k, 4, c2+c5) } return } for k := 0; k < l1; k++ { for i := 1; i < ido; i += 2 { t2 := cc3.atCmplx(i-1, 1, k) + cc3.atCmplx(i-1, 4, k) t3 := cc3.atCmplx(i-1, 2, k) + cc3.atCmplx(i-1, 3, k) t4 := cc3.atCmplx(i-1, 2, k) - cc3.atCmplx(i-1, 3, k) t5 := cc3.atCmplx(i-1, 1, k) - cc3.atCmplx(i-1, 4, k) ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2+t3) c2 := cc3.atCmplx(i-1, 0, k) + scale(tr11, t2) + scale(tr12, t3) c3 := cc3.atCmplx(i-1, 0, k) + scale(tr12, t2) + scale(tr11, t3) c4 := cmplx.Conj(swap(scale(sign, scale(ti12, t5)-scale(ti11, t4)))) c5 := cmplx.Conj(swap(scale(sign, scale(ti11, t5)+scale(ti12, t4)))) d2 := c2 - c5 d3 := c3 - c4 d4 := c3 + c4 d5 := c2 + c5 ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*d2) ch3.setCmplx(i-1, k, 2, complex(wa2[i-1], sign*wa2[i])*d3) ch3.setCmplx(i-1, k, 3, complex(wa3[i-1], sign*wa3[i])*d4) ch3.setCmplx(i-1, k, 4, complex(wa4[i-1], sign*wa4[i])*d5) } } } // pass implements passf and passb depending on sign. func pass(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64, sign float64) (nac bool) { cc3 := newThreeArray(ido, ip, l1, cc) c13 := newThreeArray(ido, l1, ip, c1) ch3 := newThreeArray(ido, l1, ip, ch) c2m := newTwoArray(idl1, ip, c2) ch2m := newTwoArray(idl1, ip, ch2) idot := ido / 2 ipph := (ip + 1) / 2 idp := ip * ido if ido < l1 { for j := 1; j < ipph; j++ { jc := ip - j for i := 0; i < ido; i++ { for k := 0; k < l1; k++ { ch3.set(i, k, j, cc3.at(i, j, k)+cc3.at(i, jc, k)) ch3.set(i, k, jc, cc3.at(i, j, k)-cc3.at(i, jc, k)) } } } for i := 0; i < ido; i++ { for k := 0; k < l1; k++ { ch3.set(i, k, 0, cc3.at(i, 0, k)) } } } else { for j := 1; j < ipph; j++ { jc := ip - j for k := 0; k < l1; k++ { for i := 0; i < ido; i++ { ch3.set(i, k, j, cc3.at(i, j, k)+cc3.at(i, jc, k)) ch3.set(i, k, jc, cc3.at(i, j, k)-cc3.at(i, jc, k)) } } } for k := 0; k < l1; k++ { for i := 0; i < ido; i++ { ch3.set(i, k, 0, cc3.at(i, 0, k)) } } } idl := 1 - ido inc := 0 for l := 1; l < ipph; l++ { lc := ip - l idl += ido for ik := 0; ik < idl1; ik++ { c2m.set(ik, l, ch2m.at(ik, 0)+wa[idl-1]*ch2m.at(ik, 1)) c2m.set(ik, lc, sign*wa[idl]*ch2m.at(ik, ip-1)) } idlj := idl inc += ido for j := 2; j < ipph; j++ { jc := ip - j idlj += inc if idlj > idp { idlj -= idp } war := wa[idlj-1] wai := wa[idlj] for ik := 0; ik < idl1; ik++ { c2m.add(ik, l, war*ch2m.at(ik, j)) c2m.add(ik, lc, sign*wai*ch2m.at(ik, jc)) } } } for j := 1; j < ipph; j++ { for ik := 0; ik < idl1; ik++ { ch2m.add(ik, 0, ch2m.at(ik, j)) } } for j := 1; j < ipph; j++ { jc := ip - j for ik := 1; ik < idl1; ik += 2 { ch2m.setCmplx(ik-1, j, c2m.atCmplx(ik-1, j)-cmplx.Conj(swap(c2m.atCmplx(ik-1, jc)))) ch2m.setCmplx(ik-1, jc, c2m.atCmplx(ik-1, j)+cmplx.Conj(swap(c2m.atCmplx(ik-1, jc)))) } } if ido == 2 { return true } for ik := 0; ik < idl1; ik++ { c2m.set(ik, 0, ch2m.at(ik, 0)) } for j := 1; j < ip; j++ { for k := 0; k < l1; k++ { c13.setCmplx(0, k, j, ch3.atCmplx(0, k, j)) } } if idot > l1 { idj := 1 - ido for j := 1; j < ip; j++ { idj += ido for k := 0; k < l1; k++ { idij := idj for i := 3; i < ido; i += 2 { idij += 2 c13.setCmplx(i-1, k, j, complex(wa[idij-1], sign*wa[idij])*ch3.atCmplx(i-1, k, j)) } } } return false } idij := -1 for j := 1; j < ip; j++ { idij += 2 for i := 3; i < ido; i += 2 { idij += 2 for k := 0; k < l1; k++ { c13.setCmplx(i-1, k, j, complex(wa[idij-1], sign*wa[idij])*ch3.atCmplx(i-1, k, j)) } } } return false } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/cosq.go000066400000000000000000000145731450372207100246370ustar00rootroot00000000000000// 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. // This is a translation of the FFTPACK cosq functions by // Paul N Swarztrauber, placed in the public domain at // http://www.netlib.org/fftpack/. package fftpack import "math" // Cosqi initializes the array work which is used in both Cosqf // and Cosqb. The prime factorization of n together with a // tabulation of the trigonometric functions are computed and // stored in work. // // Input parameter: // // n The length of the sequence to be transformed. the method // is most efficient when n+1 is a product of small primes. // // Output parameters: // // work A work array which must be dimensioned at least 3*n. // The same work array can be used for both Cosqf and Cosqb // as long as n remains unchanged. Different work arrays // are required for different values of n. The contents of // work must not be changed between calls of Cosqf or Cosqb. // // ifac An integer work array of length at least 15. func Cosqi(n int, work []float64, ifac []int) { if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } dt := 0.5 * math.Pi / float64(n) for k := range work[:n] { work[k] = math.Cos(float64(k+1) * dt) } Rffti(n, work[n:], ifac) } // Cosqf computes the Fast Fourier Transform of quarter wave data. // That is, Cosqf computes the coefficients in a cosine series // representation with only odd wave numbers. The transform is // defined below at output parameter x. // // Cosqb is the unnormalized inverse of Cosqf since a call of Cosqf // followed by a call of Cosqb will multiply the input sequence x // by 4*n. // // The array work which is used by subroutine Cosqf must be // initialized by calling subroutine Cosqi(n,work). // // Input parameters: // // n The length of the array x to be transformed. The method // is most efficient when n is a product of small primes. // // x An array which contains the sequence to be transformed. // // work A work array which must be dimensioned at least 3*n // in the program that calls Cosqf. The work array must be // initialized by calling subroutine Cosqi(n,work) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // // ifac An integer work array of length at least 15. // // Output parameters: // // x for i=0, ..., n-1 // x[i] = x[i] + the sum from k=0 to k=n-2 of // 2*x[k]*cos((2*i+1)*k*pi/(2*n)) // // A call of Cosqf followed by a call of // Cosqb will multiply the sequence x by 4*n. // Therefore Cosqb is the unnormalized inverse // of Cosqf. // // work Contains initialization calculations which must not // be destroyed between calls of Cosqf or Cosqb. func Cosqf(n int, x, work []float64, ifac []int) { if len(x) < n { panic("fourier: short sequence") } if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n < 2 { return } if n == 2 { tsqx := math.Sqrt2 * x[1] x[1] = x[0] - tsqx x[0] += tsqx return } cosqf1(n, x, work, work[n:], ifac) } func cosqf1(n int, x, w, xh []float64, ifac []int) { for k := 1; k < (n+1)/2; k++ { kc := n - k xh[k] = x[k] + x[kc] xh[kc] = x[k] - x[kc] } if n%2 == 0 { xh[(n+1)/2] = 2 * x[(n+1)/2] } for k := 1; k < (n+1)/2; k++ { kc := n - k x[k] = w[k-1]*xh[kc] + w[kc-1]*xh[k] x[kc] = w[k-1]*xh[k] - w[kc-1]*xh[kc] } if n%2 == 0 { x[(n+1)/2] = w[(n-1)/2] * xh[(n+1)/2] } Rfftf(n, x, xh, ifac) for i := 2; i < n; i += 2 { x[i-1], x[i] = x[i-1]-x[i], x[i-1]+x[i] } } // Cosqb computes the Fast Fourier Transform of quarter wave data. // That is, Cosqb computes a sequence from its representation in // terms of a cosine series with odd wave numbers. The transform // is defined below at output parameter x. // // Cosqf is the unnormalized inverse of Cosqb since a call of Cosqb // followed by a call of Cosqf will multiply the input sequence x // by 4*n. // // The array work which is used by subroutine Cosqb must be // initialized by calling subroutine Cosqi(n,work). // // Input parameters: // // n The length of the array x to be transformed. The method // is most efficient when n is a product of small primes. // // x An array which contains the sequence to be transformed. // // work A work array which must be dimensioned at least 3*n // in the program that calls Cosqb. The work array must be // initialized by calling subroutine Cosqi(n,work) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // // ifac An integer work array of length at least 15. // // Output parameters: // // x for i=0, ..., n-1 // x[i]= the sum from k=0 to k=n-1 of // 4*x[k]*cos((2*k+1)*i*pi/(2*n)) // // A call of Cosqb followed by a call of // Cosqf will multiply the sequence x by 4*n. // Therefore Cosqf is the unnormalized inverse // of Cosqb. // // work Contains initialization calculations which must not // be destroyed between calls of Cosqb or Cosqf. func Cosqb(n int, x, work []float64, ifac []int) { if len(x) < n { panic("fourier: short sequence") } if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n < 2 { x[0] *= 4 return } if n == 2 { x[0], x[1] = 4*(x[0]+x[1]), 2*math.Sqrt2*(x[0]-x[1]) return } cosqb1(n, x, work, work[n:], ifac) } func cosqb1(n int, x, w, xh []float64, ifac []int) { for i := 2; i < n; i += 2 { x[i-1], x[i] = x[i-1]+x[i], x[i]-x[i-1] } x[0] *= 2 if n%2 == 0 { x[n-1] *= 2 } Rfftb(n, x, xh, ifac) for k := 1; k < (n+1)/2; k++ { kc := n - k xh[k] = w[k-1]*x[kc] + w[kc-1]*x[k] xh[kc] = w[k-1]*x[k] - w[kc-1]*x[kc] } if n%2 == 0 { x[(n+1)/2] *= 2 * w[(n-1)/2] } for k := 1; k < (n+1)/2; k++ { x[k] = xh[k] + xh[n-k] x[n-k] = xh[k] - xh[n-k] } x[0] *= 2 } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/cost.go000066400000000000000000000076611450372207100246420ustar00rootroot00000000000000// 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. // This is a translation of the FFTPACK cost functions by // Paul N Swarztrauber, placed in the public domain at // http://www.netlib.org/fftpack/. package fftpack import "math" // Costi initializes the array work which is used in subroutine // Cost. The prime factorization of n together with a tabulation // of the trigonometric functions are computed and stored in work. // // Input parameter: // // n The length of the sequence to be transformed. The method // is most efficient when n-1 is a product of small primes. // // Output parameters: // // work A work array which must be dimensioned at least 3*n. // Different work arrays are required for different values // of n. The contents of work must not be changed between // calls of Cost. // // ifac An integer work array of length at least 15. func Costi(n int, work []float64, ifac []int) { if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n < 4 { return } dt := math.Pi / float64(n-1) for k := 1; k < n/2; k++ { fk := float64(k) work[k] = 2 * math.Sin(fk*dt) work[n-k-1] = 2 * math.Cos(fk*dt) } Rffti(n-1, work[n:], ifac) } // Cost computes the Discrete Fourier Cosine Transform of an even // sequence x(i). The transform is defined below at output parameter x. // // Cost is the unnormalized inverse of itself since a call of Cost // followed by another call of Cost will multiply the input sequence // x by 2*(n-1). The transform is defined below at output parameter x // // The array work which is used by subroutine Cost must be // initialized by calling subroutine Costi(n,work). // // Input parameters: // // n The length of the sequence x. n must be greater than 1. // The method is most efficient when n-1 is a product of // small primes. // // x An array which contains the sequence to be transformed. // // work A work array which must be dimensioned at least 3*n // in the program that calls Cost. The work array must be // initialized by calling subroutine Costi(n,work) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // // ifac An integer work array of length at least 15. // // Output parameters: // // x for i=1,...,n // x(i) = x(1)+(-1)**(i-1)*x(n) // + the sum from k=2 to k=n-1 // 2*x(k)*cos((k-1)*(i-1)*pi/(n-1)) // // A call of Cost followed by another call of // Cost will multiply the sequence x by 2*(n-1). // Hence Cost is the unnormalized inverse // of itself. // // work Contains initialization calculations which must not be // destroyed between calls of Cost. // // ifac An integer work array of length at least 15. func Cost(n int, x, work []float64, ifac []int) { if len(x) < n { panic("fourier: short sequence") } if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n < 2 { return } switch n { case 2: x[0], x[1] = x[0]+x[1], x[0]-x[1] case 3: x1p3 := x[0] + x[2] tx2 := 2 * x[1] x[1] = x[0] - x[2] x[0] = x1p3 + tx2 x[2] = x1p3 - tx2 default: c1 := x[0] - x[n-1] x[0] += x[n-1] for k := 1; k < n/2; k++ { kc := n - k - 1 t1 := x[k] + x[kc] t2 := x[k] - x[kc] c1 += work[kc] * t2 t2 *= work[k] x[k] = t1 - t2 x[kc] = t1 + t2 } if n%2 != 0 { x[n/2] *= 2 } Rfftf(n-1, x, work[n:], ifac) xim2 := x[1] x[1] = c1 for i := 3; i < n; i += 2 { xi := x[i] x[i] = x[i-2] - x[i-1] x[i-1] = xim2 xim2 = xi } if n%2 != 0 { x[n-1] = xim2 } } } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/doc.go000066400000000000000000000005521450372207100244270ustar00rootroot00000000000000// 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 fftpack implements Discrete Fourier Transform functions // ported from the Fortran implementation of FFTPACK. package fftpack // import "gonum.org/v1/gonum/dsp/fourier/internal/fftpack" golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/fftpack_test.go000066400000000000000000002061411450372207100263410ustar00rootroot00000000000000// 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. // This is a translation and extension of the FFTPACK test // functions by Paul N Swarztrauber, placed in the public // domain at http://www.netlib.org/fftpack/. package fftpack import ( "math" "math/cmplx" "reflect" "testing" "gonum.org/v1/gonum/cmplxs" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestRfft(t *testing.T) { t.Parallel() // Golden value cases where golden values have // been obtained from the original Fortran code. for _, test := range rfftTests { const tol = 1e-12 testRfft(t, test.n, tol, test.wantiwork, test.wantiifac) } // General cases based purely on FFT behaviour. for n := 1; n < 500; n++ { const tol = 1e-9 testRfft(t, n, tol, nil, nil) } } func testRfft(t *testing.T, n int, tol float64, wantiwork []float64, wantiifac []int) { // Compute the work and factor slices and compare to known values. work := make([]float64, 2*n) ifac := make([]int, 15) Rffti(n, work, ifac) var failed bool if wantiwork != nil && !floats.EqualApprox(work, wantiwork, 1e-6) { failed = true t.Errorf("unexpected work after call to rffti for n=%d", n) } if wantiifac != nil && !reflect.DeepEqual(ifac, wantiifac) { failed = true t.Errorf("unexpected ifac after call to rffti for n=%d", n) } if failed { return } // Construct a sequence with known a frequency spectrum and compare // the computed spectrum. modn := n % 2 fn := float64(n) nm1 := n - 1 x, y, xh := series(n) dt := 2 * math.Pi / fn ns2 := (n + 1) / 2 if ns2 >= 2 { for k := 1; k < ns2; k++ { //eek var sum1, sum2 float64 arg := float64(k) * dt for i := 0; i < n; i++ { arg1 := float64(i) * arg sum1 += x[i] * math.Cos(arg1) sum2 += x[i] * math.Sin(arg1) } y[2*k-1] = sum1 y[2*k] = -sum2 } } var sum1, sum2 float64 for i := 0; i < nm1; i += 2 { sum1 += x[i] sum2 += x[i+1] } if modn == 1 { sum1 += x[n-1] } y[0] = sum1 + sum2 if modn == 0 { y[n-1] = sum1 - sum2 } want := naiveDFTreal(x) Rfftf(n, x, work, ifac) // Compare the result to a naive DFT implementation. if got := packCoeffs(x); !cmplxs.EqualApprox(got, want, tol) { t.Errorf("unexpected coefficients for n=%d: got:%f want:%f", n, got, want) } var rftf float64 for i := 0; i < n; i++ { rftf = math.Max(rftf, math.Abs(x[i]-y[i])) x[i] = xh[i] } rftf /= fn if !scalar.EqualWithinAbsOrRel(rftf, 0, tol, tol) { t.Errorf("unexpected rftf value for n=%d: got:%f want:0", n, rftf) } // Construct a frequency spectrum and compare the computed sequence. for i := 0; i < n; i++ { sum := x[0] / 2 arg := float64(i) * dt if ns2 >= 2 { for k := 1; k < ns2; k++ { //eek arg1 := float64(k) * arg sum += x[2*k-1]*math.Cos(arg1) - x[2*k]*math.Sin(arg1) } } if modn == 0 { // This is how it was written in FFTPACK. sum += 0.5 * math.Pow(-1, float64(i)) * x[n-1] } y[i] = 2 * sum } Rfftb(n, x, work, ifac) var rftb float64 for i := 0; i < n; i++ { rftb = math.Max(rftb, math.Abs(x[i]-y[i])) x[i] = xh[i] y[i] = xh[i] } if !scalar.EqualWithinAbsOrRel(rftb, 0, tol, tol) { t.Errorf("unexpected rftb value for n=%d: got:%g want:0", n, rftb) } // Check that Rfftb and Rfftf are inverses. Rfftb(n, y, work, ifac) Rfftf(n, y, work, ifac) cf := 1.0 / fn var rftfb float64 for i := 0; i < n; i++ { rftfb = math.Max(rftfb, math.Abs(cf*y[i]-x[i])) } if !scalar.EqualWithinAbsOrRel(rftfb, 0, tol, tol) { t.Errorf("unexpected rftfb value for n=%d: got:%f want:0", n, rftfb) } } // naiveDFTreal is the naive O(n^2) DFT implementation. func naiveDFTreal(x []float64) (y []complex128) { y = make([]complex128, len(x)) dt := -2 * math.Pi / float64(len(x)) for i := range x { arg1 := float64(i) * dt for k, xv := range x { arg2 := float64(k) * arg1 y[i] += complex(xv*math.Cos(arg2), xv*math.Sin(arg2)) } } return y[:len(x)/2+1] } func packCoeffs(x []float64) []complex128 { y := make([]complex128, len(x)/2+1) y[0] = complex(x[0], 0) if len(x) < 2 { return y } if len(x)%2 == 1 { y[len(y)-1] = complex(x[len(x)-2], x[len(x)-1]) } else { y[len(y)-1] = complex(x[len(x)-1], 0) } for i := 1; i < len(y)-1; i++ { y[i] = complex(x[2*i-1], x[2*i]) } return y } var rfftTests = []struct { n int // The following two fields are added as there is no unit testing in // FFTPACK for RFFTI. // // wantiwork is obtained from the FFTPACK test.f with modification. // The W array is zeroed at each iteration and the first 2n elements // of W are printed after the call to RFFTI. wantiwork []float64 // wantiifac is obtained from the FFTPACK rffti1.f with modification. // The IFAC array is zeroed at each iteration of test.f and the 15 elements // of IFAC are printed before RFFTI1 returns. wantiifac []int }{ { n: 120, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 54, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 49, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 32, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068, 0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000, 0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000, 0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 25, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.968583, 0.248690, 0.876307, 0.481754, 0.00000, 0.876307, 0.481754, 0.535827, 0.844328, 0.00000, 0.728969, 0.684547, 0.627904e-01, 0.998027, 0.00000, 0.535827, 0.844328, -0.425779, 0.904827, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, }, wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 4, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 3, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 2, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, } func TestCfft(t *testing.T) { t.Parallel() const tol = 1e-12 // Golden value cases where golden values have // been obtained from the original Fortran code. for _, test := range cfftTests { testCfft(t, test.n, tol, test.wantiwork, test.wantiifac) } // General cases based purely on FFT behaviour. for n := 1; n < 500; n++ { testCfft(t, n, tol, nil, nil) } } func testCfft(t *testing.T, n int, tol float64, wantiwork []float64, wantiifac []int) { // Compute the work and factor slices and compare to known values. work := make([]float64, 4*n) ifac := make([]int, 15) Cffti(n, work, ifac) var failed bool if wantiwork != nil && !floats.EqualApprox(work, wantiwork, 1e-6) { failed = true t.Errorf("unexpected work after call to cffti for n=%d", n) } if wantiifac != nil && !reflect.DeepEqual(ifac, wantiifac) { failed = true t.Errorf("unexpected ifac after call to cffti for n=%d", n) } if failed { return } // Construct a sequence with known a frequency spectrum and compare // the computed spectrum. fn := float64(n) cn := complex(fn, 0) x, y1 := cmplxSeries(n) want := naiveDFT(x) cx := cmplxAsFloat(x) Cfftf(n, cx, work, ifac) x = floatAsCmplx(cx) // Compare the result to a naive DFT implementation. if !cmplxs.EqualApprox(x, want, tol*10) { t.Errorf("unexpected coefficients for n=%d: got:%f want:%f", n, x, want) } var cftf float64 for i := 0; i < n; i++ { cftf = math.Max(cftf, cmplx.Abs(x[i]-y1[i])) x[i] /= cn } cftf /= fn if !scalar.EqualWithinAbsOrRel(cftf, 0, tol, tol) { t.Errorf("unexpected cftf value for n=%d: got:%f want:0", n, cftf) } // Construct a frequency spectrum and compare the computed sequence. y2 := updatedCmplxSeries(x) cx = cmplxAsFloat(x) Cfftb(n, cx, work, ifac) x = floatAsCmplx(cx) var cftb float64 for i := 0; i < n; i++ { cftb = math.Max(cftb, cmplx.Abs(x[i]-y2[i])) x[i] = y2[i] } if !scalar.EqualWithinAbsOrRel(cftb, 0, tol, tol) { t.Errorf("unexpected cftb value for n=%d: got:%f want:0", n, cftb) } // Check that Cfftb and Cfftf are inverses. cx = cmplxAsFloat(x) Cfftf(n, cx, work, ifac) Cfftb(n, cx, work, ifac) x = floatAsCmplx(cx) var cftfb float64 for i := 0; i < n; i++ { cftfb = math.Max(cftfb, cmplx.Abs(x[i]/cn-y2[i])) } if !scalar.EqualWithinAbsOrRel(cftfb, 0, tol, tol) { t.Errorf("unexpected cftfb value for n=%d: got:%f want:0", n, cftfb) } } // naiveDFT is the naive O(n^2) DFT implementation. func naiveDFT(x []complex128) (y []complex128) { y = make([]complex128, len(x)) dt := -2 * math.Pi / float64(len(x)) for i := range x { arg1 := float64(i) * dt for k, xv := range x { arg2 := float64(k) * arg1 y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * xv } } return y } func cmplxSeries(n int) (x, y []complex128) { x = make([]complex128, n) for i := 0; i < n; i++ { x[i] = complex(math.Cos(math.Sqrt2*float64(i+1)), math.Sin(math.Sqrt2*float64((i+1)*(i+1)))) } y = make([]complex128, n) dt := 2 * math.Pi / float64(n) for i := 0; i < n; i++ { arg1 := -float64(i) * dt for k := 0; k < n; k++ { arg2 := float64(k) * arg1 y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * x[k] } } return x, y } func updatedCmplxSeries(x []complex128) (y []complex128) { y = make([]complex128, len(x)) dt := 2 * math.Pi / float64(len(x)) for i := range x { arg1 := float64(i) * dt for k, xv := range x { arg2 := float64(k) * arg1 y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * xv } } return y } func cmplxAsFloat(c []complex128) []float64 { f := make([]float64, 2*len(c)) for i, v := range c { f[2*i] = real(v) f[2*i+1] = imag(v) } return f } func floatAsCmplx(f []float64) []complex128 { c := make([]complex128, len(f)/2) for i := range c { c[i] = complex(f[2*i], f[2*i+1]) } return c } var cfftTests = []struct { n int // The following two fields are added as there is no unit testing in // FFTPACK for RFFTI. // // wantiwork is obtained from the FFTPACK test.f with modification. // The W array is zeroed at each iteration and the first 4n elements // of W are printed after the call to RFFTI. wantiwork []float64 // wantiifac is obtained from the FFTPACK rffti1.f with modification. // The IFAC array is zeroed at each iteration of test.f and the 15 elements // of IFAC are printed before RFFTI1 returns. wantiifac []int }{ { n: 120, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.998630, 0.523360e-01, 0.994522, 0.104528, 0.987688, 0.156434, 0.978148, 0.207912, 0.965926, 0.258819, 0.951057, 0.309017, 0.933580, 0.358368, 0.913545, 0.406737, 0.891007, 0.453991, 0.866025, 0.500000, 0.838671, 0.544639, 0.809017, 0.587785, 0.777146, 0.629320, 0.743145, 0.669131, 0.707107, 0.707107, 0.669131, 0.743145, 0.629320, 0.777146, 0.587785, 0.809017, 0.544639, 0.838671, 0.500000, 0.866025, 0.453991, 0.891007, 0.406737, 0.913545, 0.358368, 0.933580, 0.309017, 0.951057, 0.258819, 0.965926, 0.207912, 0.978148, 0.156434, 0.987688, 0.104528, 0.994522, 0.523360e-01, 0.998630, -0.437114e-07, 1.00000, -0.523361e-01, 0.998630, -0.104529, 0.994522, -0.156434, 0.987688, -0.207912, 0.978148, -0.258819, 0.965926, -0.309017, 0.951056, -0.358368, 0.933580, -0.406737, 0.913545, -0.453991, 0.891006, -0.500000, 0.866025, -0.544639, 0.838671, -0.587785, 0.809017, -0.629321, 0.777146, -0.669131, 0.743145, -0.707107, 0.707107, -0.743145, 0.669130, -0.777146, 0.629320, -0.809017, 0.587785, -0.838671, 0.544639, -0.866025, 0.500000, -0.891007, 0.453990, -0.913545, 0.406737, -0.933580, 0.358368, -0.951057, 0.309017, -0.965926, 0.258819, -0.978148, 0.207912, -0.987688, 0.156434, -0.994522, 0.104528, -0.998630, 0.523358e-01, 1.00000, 0.00000, 0.994522, 0.104528, 0.978148, 0.207912, 0.951057, 0.309017, 0.913545, 0.406737, 0.866025, 0.500000, 0.809017, 0.587785, 0.743145, 0.669131, 0.669131, 0.743145, 0.587785, 0.809017, 0.500000, 0.866025, 0.406737, 0.913545, 0.309017, 0.951057, 0.207912, 0.978148, 0.104528, 0.994522, -0.437114e-07, 1.00000, -0.104529, 0.994522, -0.207912, 0.978148, -0.309017, 0.951056, -0.406737, 0.913545, 1.00000, 0.00000, 0.978148, 0.207912, 0.913545, 0.406737, 0.809017, 0.587785, 0.669131, 0.743145, 0.500000, 0.866025, 0.309017, 0.951057, 0.104528, 0.994522, -0.104529, 0.994522, -0.309017, 0.951056, -0.500000, 0.866025, -0.669131, 0.743145, -0.809017, 0.587785, -0.913545, 0.406737, -0.978148, 0.207912, -1.00000, -0.874228e-07, -0.978148, -0.207912, -0.913545, -0.406737, -0.809017, -0.587785, -0.669131, -0.743145, 1.00000, 0.00000, 0.951057, 0.309017, 0.809017, 0.587785, 0.587785, 0.809017, 0.309017, 0.951057, 1.00000, 0.00000, 0.809017, 0.587785, 0.309017, 0.951057, -0.309017, 0.951056, -0.809017, 0.587785, 1.00000, 0.00000, 0.587785, 0.809017, -0.309017, 0.951056, -0.951057, 0.309017, -0.809017, -0.587785, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.309017, -0.951056, }, wantiifac: []int{120, 4, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 54, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.993238, 0.116093, 0.973045, 0.230616, 0.939693, 0.342020, 0.893633, 0.448799, 0.835488, 0.549509, 0.766044, 0.642788, 0.686242, 0.727374, 0.597159, 0.802123, 0.500000, 0.866025, 0.396080, 0.918216, 0.286803, 0.957990, 0.173648, 0.984808, 0.581449e-01, 0.998308, -0.581448e-01, 0.998308, -0.173648, 0.984808, -0.286803, 0.957990, -0.396080, 0.918216, -0.500000, 0.866025, -0.597159, 0.802123, -0.686242, 0.727374, -0.766044, 0.642788, -0.835488, 0.549509, -0.893633, 0.448799, -0.939693, 0.342020, -0.973045, 0.230616, -0.993238, 0.116093, 1.00000, 0.00000, 0.973045, 0.230616, 0.893633, 0.448799, 0.766044, 0.642788, 0.597159, 0.802123, 0.396080, 0.918216, 0.173648, 0.984808, -0.581448e-01, 0.998308, -0.286803, 0.957990, 1.00000, 0.00000, 0.893633, 0.448799, 0.597159, 0.802123, 0.173648, 0.984808, -0.286803, 0.957990, -0.686242, 0.727374, -0.939693, 0.342020, -0.993238, -0.116093, -0.835488, -0.549509, 1.00000, 0.00000, 0.766044, 0.642788, 0.173648, 0.984808, 1.00000, 0.00000, 0.173648, 0.984808, -0.939693, 0.342020, 1.00000, 0.00000, 1.00000, 0.00000, -0.500000, -0.866025, }, wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 49, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.623490, 0.781832, 0.991790, 0.127877, 0.967295, 0.253655, 0.926917, 0.375267, 0.871319, 0.490718, 0.801414, 0.598111, 0.718349, 0.695683, -0.222521, 0.974928, 0.967295, 0.253655, 0.871319, 0.490718, 0.718349, 0.695683, 0.518393, 0.855143, 0.284527, 0.958668, 0.320515e-01, 0.999486, -0.900969, 0.433884, 0.926917, 0.375267, 0.718349, 0.695683, 0.404783, 0.914413, 0.320515e-01, 0.999486, -0.345365, 0.938468, -0.672301, 0.740278, -0.900969, -0.433884, 0.871319, 0.490718, 0.518393, 0.855143, 0.320515e-01, 0.999486, -0.462538, 0.886599, -0.838088, 0.545535, -0.997945, 0.640701e-01, -0.222521, -0.974928, 0.801414, 0.598111, 0.284527, 0.958668, -0.345365, 0.938468, -0.838088, 0.545535, -0.997945, -0.640705e-01, -0.761446, -0.648229, 0.623490, -0.781831, 0.718349, 0.695683, 0.320515e-01, 0.999486, -0.672301, 0.740278, -0.997945, 0.640701e-01, -0.761446, -0.648228, -0.960227e-01, -0.995379, 0.623490, 0.781832, -0.222521, 0.974928, -0.900969, 0.433884, -0.900969, -0.433884, -0.222521, -0.974928, 0.623490, -0.781831, 0.623490, -0.781831, }, wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 32, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.980785, 0.195090, 0.923880, 0.382683, 0.831470, 0.555570, 0.707107, 0.707107, 0.555570, 0.831470, 0.382683, 0.923880, 0.195090, 0.980785, -0.437114e-07, 1.00000, -0.195090, 0.980785, -0.382684, 0.923880, -0.555570, 0.831470, -0.707107, 0.707107, -0.831470, 0.555570, -0.923880, 0.382683, -0.980785, 0.195090, 1.00000, 0.00000, 0.923880, 0.382683, 0.707107, 0.707107, 0.382683, 0.923880, 1.00000, 0.00000, 0.707107, 0.707107, -0.437114e-07, 1.00000, -0.707107, 0.707107, 1.00000, 0.00000, 0.382683, 0.923880, -0.707107, 0.707107, -0.923880, -0.382683, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.119249e-07, -1.00000, }, wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 25, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.968583, 0.248690, 0.876307, 0.481754, 0.728969, 0.684547, 0.535827, 0.844328, 1.00000, 0.00000, 0.876307, 0.481754, 0.535827, 0.844328, 0.627904e-01, 0.998027, -0.425779, 0.904827, 1.00000, 0.00000, 0.728969, 0.684547, 0.627904e-01, 0.998027, -0.637424, 0.770513, -0.992115, 0.125333, 1.00000, 0.00000, 0.535827, 0.844328, -0.425779, 0.904827, -0.992115, 0.125333, -0.637424, -0.770513, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.309017, -0.951056, }, wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 4, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.119249e-07, -1.00000, }, wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 3, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, -0.500000, -0.866025, }, wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 2, wantiwork: []float64{ 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, -1.00000, -0.874228e-07, }, wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, } func TestSint(t *testing.T) { t.Parallel() const tol = 1e-12 for _, test := range sintTests { // Compute the work and factor slices and compare to known values. work := make([]float64, 5*(test.n)/2) ifac := make([]int, 15) Sinti(test.n-1, work, ifac) var failed bool if !floats.EqualApprox(work, test.wantiwork, 1e-6) { failed = true t.Errorf("unexpected work after call to sinti for n=%d", test.n) } if !reflect.DeepEqual(ifac, test.wantiifac) { failed = true t.Errorf("unexpected ifac after call to sinti for n=%d", test.n) } if failed { continue } // Construct a sequence with known a frequency spectrum and compare // the computed spectrum. fn := float64(test.n) x, _, xh := series(test.n - 1) y := make([]float64, test.n-1) dt := math.Pi / fn for i := 0; i < test.n-1; i++ { arg1 := float64(i+1) * dt for k := 0; k < test.n-1; k++ { //eek y[i] += x[k] * math.Sin(float64(k+1)*arg1) } y[i] *= 2 } Sint(test.n-1, x, work, ifac) cf := 0.5 / fn var sintt float64 for i := 0; i < test.n-1; i++ { sintt = math.Max(sintt, math.Abs(x[i]-y[i])) x[i] = xh[i] y[i] = x[i] } sintt *= cf if !scalar.EqualWithinAbsOrRel(sintt, 0, tol, tol) { t.Errorf("unexpected sintt value for n=%d: got:%f want:0", test.n, sintt) } // Check that the transform is its own inverse. Sint(test.n-1, x, work, ifac) Sint(test.n-1, x, work, ifac) var sintfb float64 for i := 0; i < test.n-1; i++ { sintfb = math.Max(sintfb, math.Abs(cf*x[i]-y[i])) } if !scalar.EqualWithinAbsOrRel(sintfb, 0, tol, tol) { t.Errorf("unexpected sintfb value for n=%d: got:%f want:0", test.n, sintfb) } } } var sintTests = []struct { n int // The following two fields are added as there is no unit testing in // FFTPACK for SINTI. // // wantiwork is obtained from the FFTPACK test.f with modification. // The W array is zeroed at each iteration and the first 2.5n elements // of W are printed after the call to RFFTI. wantiwork []float64 // wantiifac is obtained from the FFTPACK sint.f with modification. // The IFAC array is zeroed at each iteration of test.f and the 15 elements // of IFAC are printed before RFFTI returns. wantiifac []int }{ { n: 120, wantiwork: []float64{ 0.5235390e-01, 0.1046719, 0.1569182, 0.2090569, 0.2610524, 0.3128690, 0.3644710, 0.4158234, 0.4668908, 0.5176381, 0.5680307, 0.6180340, 0.6676137, 0.7167359, 0.7653669, 0.8134733, 0.8610222, 0.9079810, 0.9543176, 1.000000, 1.044997, 1.089278, 1.132812, 1.175570, 1.217523, 1.258641, 1.298896, 1.338261, 1.376709, 1.414214, 1.450749, 1.486290, 1.520812, 1.554292, 1.586707, 1.618034, 1.648252, 1.677341, 1.705280, 1.732051, 1.757634, 1.782013, 1.805171, 1.827091, 1.847759, 1.867161, 1.885283, 1.902113, 1.917639, 1.931852, 1.944740, 1.956295, 1.966510, 1.975377, 1.982890, 1.989044, 1.993835, 1.997259, 1.999315, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.1681558e-42, }, wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 54, wantiwork: []float64{ 0.1162897, 0.2321858, 0.3472964, 0.4612317, 0.5736065, 0.6840402, 0.7921596, 0.8975984, 1.000000, 1.099018, 1.194317, 1.285575, 1.372483, 1.454747, 1.532089, 1.604246, 1.670976, 1.732051, 1.787265, 1.836432, 1.879385, 1.915979, 1.946090, 1.969615, 1.986477, 1.996616, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000, 0.000000, 0.000000, 0.000000, 0.7567012e-43, }, wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 49, wantiwork: []float64{ 0.1281404, 0.2557543, 0.3823173, 0.5073092, 0.6302165, 0.7505341, 0.8677675, 0.9814351, 1.091070, 1.196221, 1.296457, 1.391365, 1.480556, 1.563663, 1.640345, 1.710286, 1.773199, 1.828825, 1.876937, 1.917336, 1.949856, 1.974364, 1.990758, 1.998972, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 32, wantiwork: []float64{ 0.1960343, 0.3901806, 0.5805693, 0.7653669, 0.9427935, 1.111140, 1.268787, 1.414214, 1.546021, 1.662939, 1.763843, 1.847759, 1.913881, 1.961571, 1.990369, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068, 0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000, 0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000, 0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.4484155e-43, }, wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 25, wantiwork: []float64{ 0.2506665, 0.4973798, 0.7362491, 0.9635074, 1.175570, 1.369094, 1.541027, 1.688656, 1.809654, 1.902113, 1.964575, 1.996053, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067, 0.4817537, 0.000000, 0.8763067, 0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686, 0.6845471, 0.6279038e-01, 0.9980267, 0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 4, wantiwork: []float64{ 1.414214, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 3, wantiwork: []float64{ 1.732051, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 2, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, } func TestCost(t *testing.T) { t.Parallel() const tol = 1e-12 for _, test := range costTests { // Compute the work and factor slices and compare to known values. work := make([]float64, 3*(test.n+1)) ifac := make([]int, 15) Costi(test.n+1, work, ifac) var failed bool if !floats.EqualApprox(work, test.wantiwork, 1e-6) { failed = true t.Errorf("unexpected work after call to costi for n=%d", test.n) } if !reflect.DeepEqual(ifac, test.wantiifac) { failed = true t.Errorf("unexpected ifac after call to costi for n=%d", test.n) } if failed { continue } // Construct a sequence with known a frequency spectrum and compare // the computed spectrum. fn := float64(test.n) x, _, xh := series(test.n + 1) y := make([]float64, test.n+1) dt := math.Pi / fn for i := 0; i < test.n+1; i++ { y[i] = 0.5 * (x[0] + math.Pow(-1, float64(i))*x[test.n]) arg1 := float64(i) * dt for k := 1; k < test.n; k++ { //eek y[i] += x[k] * math.Cos(float64(k)*arg1) } y[i] *= 2 } Cost(test.n+1, x, work, ifac) cf := 0.5 / fn var costt float64 for i := 0; i < test.n; i++ { costt = math.Max(costt, math.Abs(x[i]-y[i])) x[i] = xh[i] y[i] = x[i] } costt *= cf if !scalar.EqualWithinAbsOrRel(costt, 0, tol, tol) { t.Errorf("unexpected costt value for n=%d: got:%f want:0", test.n, costt) } // Check that the transform is its own inverse. Cost(test.n+1, x, work, ifac) Cost(test.n+1, x, work, ifac) var costfb float64 for i := 0; i < test.n-1; i++ { costfb = math.Max(costfb, math.Abs(cf*x[i]-y[i])) } if !scalar.EqualWithinAbsOrRel(costfb, 0, tol, tol) { t.Errorf("unexpected costfb value for n=%d: got:%f want:0", test.n, costfb) } } } var costTests = []struct { n int // The following two fields are added as there is no unit testing in // FFTPACK for SINTI. // // wantiwork is obtained from the FFTPACK test.f with modification. // The W array is zeroed at each iteration and the first 3n elements // of W are printed after the call to RFFTI. wantiwork []float64 // wantiifac is obtained from the FFTPACK sint.f with modification. // The IFAC array is zeroed at each iteration of test.f and the 15 elements // of IFAC are printed before RFFTI returns. wantiifac []int }{ { n: 120, wantiwork: []float64{ 0.000000, 0.5235390e-01, 0.1046719, 0.1569182, 0.2090569, 0.2610524, 0.3128690, 0.3644710, 0.4158234, 0.4668908, 0.5176381, 0.5680307, 0.6180340, 0.6676137, 0.7167359, 0.7653669, 0.8134733, 0.8610222, 0.9079810, 0.9543176, 1.000000, 1.044997, 1.089278, 1.132812, 1.175570, 1.217523, 1.258641, 1.298896, 1.338261, 1.376709, 1.414214, 1.450749, 1.486290, 1.520812, 1.554292, 1.586707, 1.618034, 1.648252, 1.677341, 1.705280, 1.732051, 1.757634, 1.782013, 1.805171, 1.827091, 1.847759, 1.867161, 1.885283, 1.902113, 1.917639, 1.931852, 1.944740, 1.956295, 1.966510, 1.975377, 1.982890, 1.989044, 1.993835, 1.997259, 1.999315, 0.000000, 0.5235375e-01, 0.1046719, 0.1569182, 0.2090568, 0.2610523, 0.3128687, 0.3644710, 0.4158233, 0.4668906, 0.5176381, 0.5680307, 0.6180339, 0.6676136, 0.7167357, 0.7653669, 0.8134732, 0.8610221, 0.9079810, 0.9543175, 1.000000, 1.044997, 1.089278, 1.132812, 1.175570, 1.217523, 1.258641, 1.298896, 1.338261, 1.376709, 1.414214, 1.450749, 1.486290, 1.520812, 1.554292, 1.586707, 1.618034, 1.648252, 1.677341, 1.705280, 1.732051, 1.757634, 1.782013, 1.805171, 1.827091, 1.847759, 1.867161, 1.885283, 1.902113, 1.917639, 1.931852, 1.944740, 1.956295, 1.966510, 1.975377, 1.982890, 1.989044, 1.993835, 1.997259, 1.999315, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.1681558e-42, 0.5605194e-44, }, wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 54, wantiwork: []float64{ 0.000000, 0.1162897, 0.2321858, 0.3472964, 0.4612317, 0.5736065, 0.6840402, 0.7921596, 0.8975984, 1.000000, 1.099018, 1.194317, 1.285575, 1.372483, 1.454747, 1.532089, 1.604246, 1.670976, 1.732051, 1.787265, 1.836432, 1.879385, 1.915979, 1.946090, 1.969615, 1.986477, 1.996616, 0.000000, 0.1162897, 0.2321858, 0.3472964, 0.4612317, 0.5736064, 0.6840403, 0.7921594, 0.8975984, 1.000000, 1.099018, 1.194317, 1.285575, 1.372483, 1.454747, 1.532089, 1.604246, 1.670976, 1.732051, 1.787265, 1.836432, 1.879385, 1.915979, 1.946090, 1.969615, 1.986477, 1.996616, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000, 0.000000, 0.000000, 0.000000, 0.7567012e-43, 0.5605194e-44, }, wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 49, wantiwork: []float64{ 0.000000, 0.1281404, 0.2557543, 0.3823173, 0.5073092, 0.6302165, 0.7505341, 0.8677675, 0.9814351, 1.091070, 1.196221, 1.296457, 1.391365, 1.480556, 1.563663, 1.640345, 1.710286, 1.773199, 1.828825, 1.876937, 1.917336, 1.949856, 1.974364, 1.990758, 1.998972, 0.6410302e-01, 0.1920458, 0.3191997, 0.4450417, 0.5690550, 0.6907300, 0.8095666, 0.9250766, 1.036785, 1.144233, 1.246980, 1.344602, 1.436699, 1.522892, 1.602827, 1.676176, 1.742637, 1.801938, 1.853834, 1.898111, 1.934590, 1.963118, 1.983580, 1.995891, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.6866362e-43, 0.2802597e-44, }, wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 32, wantiwork: []float64{ 0.000000, 0.1960343, 0.3901806, 0.5805693, 0.7653669, 0.9427935, 1.111140, 1.268787, 1.414214, 1.546021, 1.662939, 1.763843, 1.847759, 1.913881, 1.961571, 1.990369, 0.000000, 0.1960343, 0.3901805, 0.5805693, 0.7653669, 0.9427933, 1.111140, 1.268787, 1.414214, 1.546021, 1.662939, 1.763842, 1.847759, 1.913881, 1.961571, 1.990369, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068, 0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000, 0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000, 0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.4484155e-43, 0.4203895e-44, }, wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 25, wantiwork: []float64{ 0.000000, 0.2506665, 0.4973798, 0.7362491, 0.9635074, 1.175570, 1.369094, 1.541027, 1.688656, 1.809654, 1.902113, 1.964575, 1.996053, 0.1255808, 0.3747624, 0.6180339, 0.8515584, 1.071653, 1.274848, 1.457937, 1.618034, 1.752613, 1.859553, 1.937166, 1.984229, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067, 0.4817537, 0.000000, 0.8763067, 0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686, 0.6845471, 0.6279038e-01, 0.9980267, 0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.3503246e-43, 0.2802597e-44, }, wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 4, wantiwork: []float64{ 0.000000, 1.414214, 0.000000, 1.414214, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.5605194e-44, 0.1401298e-44, }, wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 3, wantiwork: []float64{ 0.000000, 1.732051, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.4203895e-44, 0.1401298e-44, }, wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 2, wantiwork: []float64{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, } func TestCosq(t *testing.T) { t.Parallel() const tol = 1e-12 for _, test := range sincosqTests { // Compute the work and factor slices and compare to known values. work := make([]float64, 3*test.n) ifac := make([]int, 15) Cosqi(test.n, work, ifac) var failed bool if !floats.EqualApprox(work, test.wantiwork, 1e-6) { failed = true t.Errorf("unexpected work after call to cosqi for n=%d", test.n) t.Logf("\n%v\n%v", work, test.wantiwork) } if !reflect.DeepEqual(ifac, test.wantiifac) { failed = true t.Errorf("unexpected ifac after call to cosqi for n=%d", test.n) } if failed { continue } // Construct a sequence with known a frequency spectrum and compare // the computed spectrum. fn := float64(test.n) x := make([]float64, test.n) y, _, xh := series(test.n) dt := math.Pi / (2 * fn) for i := 0; i < test.n; i++ { arg := float64(i) * dt for k := 0; k < test.n; k++ { x[i] += y[k] * math.Cos(float64(2*k+1)*arg) } x[i] *= 4 } Cosqb(test.n, y, work, ifac) cf := 0.25 / fn var cosqbt float64 for i := 0; i < test.n; i++ { cosqbt = math.Max(cosqbt, math.Abs(x[i]-y[i])) x[i] = xh[i] } cosqbt *= cf if !scalar.EqualWithinAbsOrRel(cosqbt, 0, tol, tol) { t.Errorf("unexpected cosqbt value for n=%d: got:%f want:0", test.n, cosqbt) } // Construct a frequency spectrum and compare the computed sequence. for i := 0; i < test.n; i++ { y[i] = 0.5 * x[0] arg := float64(2*i+1) * dt for k := 1; k < test.n; k++ { y[i] += x[k] * math.Cos(float64(k)*arg) } y[i] *= 2 } Cosqf(test.n, x, work, ifac) var cosqft float64 for i := 0; i < test.n; i++ { cosqft = math.Max(cosqft, math.Abs(x[i]-y[i])) x[i] = xh[i] y[i] = xh[i] } cosqft *= cf if !scalar.EqualWithinAbsOrRel(cosqft, 0, tol, tol) { t.Errorf("unexpected cosqft value for n=%d: got:%f want:0", test.n, cosqft) } // Check that Cosqb and Cosqf are inverses. Cosqb(test.n, x, work, ifac) Cosqf(test.n, x, work, ifac) var cosqfb float64 for i := 0; i < test.n; i++ { cosqfb = math.Max(cosqfb, math.Abs(cf*x[i]-y[i])) } if !scalar.EqualWithinAbsOrRel(cosqfb, 0, tol, tol) { t.Errorf("unexpected cosqfb value for n=%d: got:%f want:0", test.n, cosqfb) } } } func TestSinq(t *testing.T) { t.Parallel() const tol = 1e-12 for _, test := range sincosqTests { // Compute the work and factor slices and compare to known values. work := make([]float64, 3*test.n) ifac := make([]int, 15) Sinqi(test.n, work, ifac) var failed bool if !floats.EqualApprox(work, test.wantiwork, 1e-6) { failed = true t.Errorf("unexpected work after call to sinqi for n=%d", test.n) t.Logf("\n%v\n%v", work, test.wantiwork) } if !reflect.DeepEqual(ifac, test.wantiifac) { failed = true t.Errorf("unexpected ifac after call to sinqi for n=%d", test.n) } if failed { continue } // Construct a sequence with known a frequency spectrum and compare // the computed spectrum. fn := float64(test.n) x := make([]float64, test.n) y, _, xh := series(test.n) dt := math.Pi / (2 * fn) for i := 0; i < test.n; i++ { arg := float64(i+1) * dt for k := 0; k < test.n; k++ { x[i] += y[k] * math.Sin(float64(2*k+1)*arg) } x[i] *= 4 } Sinqb(test.n, y, work, ifac) cf := 0.25 / fn var sinqbt float64 for i := 0; i < test.n; i++ { sinqbt = math.Max(sinqbt, math.Abs(x[i]-y[i])) x[i] = xh[i] } sinqbt *= cf if !scalar.EqualWithinAbsOrRel(sinqbt, 0, tol, tol) { t.Errorf("unexpected sinqbt value for n=%d: got:%f want:0", test.n, sinqbt) } // Construct a frequency spectrum and compare the computed sequence. for i := 0; i < test.n; i++ { arg := float64(2*i+1) * dt y[i] = 0.5 * math.Pow(-1, float64(i)) * x[test.n-1] for k := 0; k < test.n-1; k++ { y[i] += x[k] * math.Sin(float64(k+1)*arg) } y[i] *= 2 } Sinqf(test.n, x, work, ifac) var sinqft float64 for i := 0; i < test.n; i++ { sinqft = math.Max(sinqft, math.Abs(x[i]-y[i])) x[i] = xh[i] y[i] = xh[i] } sinqft *= cf if !scalar.EqualWithinAbsOrRel(sinqft, 0, tol, tol) { t.Errorf("unexpected sinqft value for n=%d: got:%f want:0", test.n, sinqft) } // Check that Sinqb and Sinqf are inverses. Sinqb(test.n, x, work, ifac) Sinqf(test.n, x, work, ifac) var sinqfb float64 for i := 0; i < test.n; i++ { sinqfb = math.Max(sinqfb, math.Abs(cf*x[i]-y[i])) } if !scalar.EqualWithinAbsOrRel(sinqfb, 0, tol, tol) { t.Errorf("unexpected sinqfb value for n=%d: got:%f want:0", test.n, sinqfb) } } } var sincosqTests = []struct { n int // The following two fields are added as there is no unit testing in // FFTPACK for SINTI. // // wantiwork is obtained from the FFTPACK test.f with modification. // The W array is zeroed at each iteration and the first 3n elements // of W are printed after the call to RFFTI. wantiwork []float64 // wantiifac is obtained from the FFTPACK sint.f with modification. // The IFAC array is zeroed at each iteration of test.f and the 15 elements // of IFAC are printed before RFFTI returns. wantiifac []int }{ { n: 120, wantiwork: []float64{ 0.9999143, 0.9996573, 0.9992290, 0.9986295, 0.9978589, 0.9969173, 0.9958049, 0.9945219, 0.9930685, 0.9914449, 0.9896514, 0.9876884, 0.9855561, 0.9832549, 0.9807853, 0.9781476, 0.9753423, 0.9723699, 0.9692309, 0.9659258, 0.9624552, 0.9588197, 0.9550200, 0.9510565, 0.9469301, 0.9426415, 0.9381914, 0.9335804, 0.9288096, 0.9238795, 0.9187912, 0.9135454, 0.9081432, 0.9025853, 0.8968728, 0.8910065, 0.8849877, 0.8788171, 0.8724960, 0.8660254, 0.8594064, 0.8526402, 0.8457278, 0.8386706, 0.8314696, 0.8241262, 0.8166415, 0.8090170, 0.8012538, 0.7933533, 0.7853169, 0.7771459, 0.7688418, 0.7604060, 0.7518398, 0.7431448, 0.7343225, 0.7253744, 0.7163019, 0.7071068, 0.6977904, 0.6883546, 0.6788007, 0.6691306, 0.6593458, 0.6494480, 0.6394390, 0.6293204, 0.6190940, 0.6087614, 0.5983246, 0.5877852, 0.5771452, 0.5664062, 0.5555702, 0.5446390, 0.5336145, 0.5224985, 0.5112931, 0.5000000, 0.4886212, 0.4771588, 0.4656145, 0.4539905, 0.4422887, 0.4305110, 0.4186597, 0.4067366, 0.3947438, 0.3826834, 0.3705574, 0.3583679, 0.3461170, 0.3338068, 0.3214395, 0.3090170, 0.2965415, 0.2840153, 0.2714404, 0.2588191, 0.2461533, 0.2334453, 0.2206974, 0.2079117, 0.1950902, 0.1822355, 0.1693494, 0.1564344, 0.1434926, 0.1305261, 0.1175374, 0.1045284, 0.9150153e-01, 0.7845908e-01, 0.6540307e-01, 0.5233597e-01, 0.3925979e-01, 0.2617688e-01, 0.1308960e-01, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 54, wantiwork: []float64{ 0.9995769, 0.9983082, 0.9961947, 0.9932383, 0.9894416, 0.9848077, 0.9793406, 0.9730449, 0.9659258, 0.9579895, 0.9492427, 0.9396926, 0.9293475, 0.9182161, 0.9063078, 0.8936327, 0.8802014, 0.8660254, 0.8511167, 0.8354878, 0.8191521, 0.8021232, 0.7844157, 0.7660444, 0.7470251, 0.7273737, 0.7071068, 0.6862416, 0.6647958, 0.6427876, 0.6202354, 0.5971586, 0.5735765, 0.5495090, 0.5249766, 0.5000000, 0.4746003, 0.4487992, 0.4226182, 0.3960797, 0.3692062, 0.3420202, 0.3145447, 0.2868032, 0.2588191, 0.2306159, 0.2022175, 0.1736482, 0.1449319, 0.1160929, 0.8715568e-01, 0.5814485e-01, 0.2908471e-01, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 49, wantiwork: []float64{ 0.9994862, 0.9979454, 0.9953791, 0.9917900, 0.9871818, 0.9815592, 0.9749279, 0.9672949, 0.9586679, 0.9490557, 0.9384684, 0.9269168, 0.9144126, 0.9009688, 0.8865993, 0.8713187, 0.8551428, 0.8380881, 0.8201723, 0.8014136, 0.7818314, 0.7614459, 0.7402779, 0.7183493, 0.6956825, 0.6723009, 0.6482283, 0.6234898, 0.5981105, 0.5721166, 0.5455348, 0.5183925, 0.4907175, 0.4625383, 0.4338836, 0.4047833, 0.3752669, 0.3453650, 0.3151082, 0.2845275, 0.2536545, 0.2225209, 0.1911586, 0.1595999, 0.1278771, 0.9602292e-01, 0.6407014e-01, 0.3205151e-01, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 32, wantiwork: []float64{ 0.9987954, 0.9951847, 0.9891765, 0.9807853, 0.9700313, 0.9569404, 0.9415441, 0.9238795, 0.9039893, 0.8819212, 0.8577286, 0.8314696, 0.8032075, 0.7730104, 0.7409511, 0.7071068, 0.6715589, 0.6343933, 0.5956993, 0.5555702, 0.5141027, 0.4713967, 0.4275551, 0.3826834, 0.3368898, 0.2902846, 0.2429801, 0.1950902, 0.1467305, 0.9801713e-01, 0.4906765e-01, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068, 0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000, 0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000, 0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 25, wantiwork: []float64{ 0.9980267, 0.9921147, 0.9822872, 0.9685832, 0.9510565, 0.9297765, 0.9048271, 0.8763067, 0.8443279, 0.8090170, 0.7705132, 0.7289686, 0.6845471, 0.6374239, 0.5877852, 0.5358267, 0.4817536, 0.4257792, 0.3681245, 0.3090170, 0.2486898, 0.1873812, 0.1253331, 0.6279038e-01, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067, 0.4817537, 0.000000, 0.8763067, 0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686, 0.6845471, 0.6279038e-01, 0.9980267, 0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 4, wantiwork: []float64{ 0.9238795, 0.7071068, 0.3826834, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 3, wantiwork: []float64{ 0.8660254, 0.5000000, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { n: 2, wantiwork: []float64{ 0.7071068, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, }, wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, } // series returns three copies of a sinusoidal sequence n samples long. func series(n int) (x, y, xh []float64) { x = make([]float64, n) y = make([]float64, n) xh = make([]float64, n) for i := 0; i < n; i++ { x[i] = math.Sin(float64(i+1) * math.Sqrt2) y[i] = x[i] xh[i] = x[i] } return x, y, xh } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/helpers.go000066400000000000000000000007011450372207100253200ustar00rootroot00000000000000// Copyright ©2020 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 fftpack // swap returns c with the real and imaginary parts swapped. func swap(c complex128) complex128 { return complex(imag(c), real(c)) } // scale scales the complex number c by f. func scale(f float64, c complex128) complex128 { return complex(f*real(c), f*imag(c)) } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/rfft.go000066400000000000000000000645611450372207100246350ustar00rootroot00000000000000// 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. // This is a translation of the FFTPACK rfft functions by // Paul N Swarztrauber, placed in the public domain at // http://www.netlib.org/fftpack/. package fftpack import ( "math" "math/cmplx" ) // Rffti initializes the array work which is used in both Rfftf // and Rfftb. The prime factorization of n together with a // tabulation of the trigonometric functions are computed and // stored in work. // // Input parameter: // // n The length of the sequence to be transformed. // // Output parameters: // // work A work array which must be dimensioned at least 2*n. // The same work array can be used for both Rfftf and Rfftb // as long as n remains unchanged. different work arrays // are required for different values of n. The contents of // work must not be changed between calls of Rfftf or Rfftb. // // ifac A work array containing the factors of n. ifac must have // length of at least 15. func Rffti(n int, work []float64, ifac []int) { if len(work) < 2*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 1 { return } rffti1(n, work[n:2*n], ifac[:15]) } func rffti1(n int, wa []float64, ifac []int) { ntryh := [4]int{4, 2, 3, 5} nl := n nf := 0 outer: for j, ntry := 0, 0; ; j++ { if j < 4 { ntry = ntryh[j] } else { ntry += 2 } for { if nl%ntry != 0 { continue outer } ifac[nf+2] = ntry nl /= ntry nf++ if ntry == 2 && nf != 1 { for i := 1; i < nf; i++ { ib := nf - i + 1 ifac[ib+1] = ifac[ib] } ifac[2] = 2 } if nl == 1 { break outer } } } ifac[0] = n ifac[1] = nf if nf == 1 { return } argh := 2 * math.Pi / float64(n) is := 0 l1 := 1 for k1 := 0; k1 < nf-1; k1++ { ip := ifac[k1+2] ld := 0 l2 := l1 * ip ido := n / l2 for j := 0; j < ip-1; j++ { ld += l1 i := is fi := 0.0 argld := float64(ld) * argh for ii := 2; ii < ido; ii += 2 { fi++ arg := fi * argld wa[i] = math.Cos(arg) wa[i+1] = math.Sin(arg) i += 2 } is += ido } l1 = l2 } } // Rfftf computes the Fourier coefficients of a real perodic sequence // (Fourier analysis). The transform is defined below at output // parameter r. // // Input parameters: // // n The length of the array r to be transformed. The method // is most efficient when n is a product of small primes. // n may change so long as different work arrays are provided. // // r A real array of length n which contains the sequence // to be transformed. // // work a work array which must be dimensioned at least 2*n. // in the program that calls Rfftf. the work array must be // initialized by calling subroutine rffti(n,work,ifac) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged. Thus subsequent // transforms can be obtained faster than the first. // The same work array can be used by Rfftf and Rfftb. // // ifac A work array containing the factors of n. ifac must have // length of at least 15. // // Output parameters: // // r r[0] = the sum from i=0 to i=n-1 of r[i] // // if n is even set l=n/2, if n is odd set l = (n+1)/2 // then for k = 1, ..., l-1 // r[2*k-1] = the sum from i = 0 to i = n-1 of // r[i]*cos(k*i*2*pi/n) // r[2*k] = the sum from i = 0 to i = n-1 of // -r[i]*sin(k*i*2*pi/n) // // if n is even // r[n-1] = the sum from i = 0 to i = n-1 of // (-1)^i*r[i] // // This transform is unnormalized since a call of Rfftf // followed by a call of Rfftb will multiply the input // sequence by n. // // work contains results which must not be destroyed between // calls of Rfftf or Rfftb. // ifac contains results which must not be destroyed between // calls of Rfftf or Rfftb. func Rfftf(n int, r, work []float64, ifac []int) { if len(r) < n { panic("fourier: short sequence") } if len(work) < 2*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 1 { return } rfftf1(n, r[:n], work[:n], work[n:2*n], ifac[:15]) } func rfftf1(n int, c, ch, wa []float64, ifac []int) { nf := ifac[1] na := true l2 := n iw := n - 1 for k1 := 1; k1 <= nf; k1++ { kh := nf - k1 ip := ifac[kh+2] l1 := l2 / ip ido := n / l2 idl1 := ido * l1 iw -= (ip - 1) * ido na = !na switch ip { case 4: ix2 := iw + ido ix3 := ix2 + ido if na { radf4(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:]) } else { radf4(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:]) } case 2: if na { radf2(ido, l1, ch, c, wa[iw:]) } else { radf2(ido, l1, c, ch, wa[iw:]) } case 3: ix2 := iw + ido if na { radf3(ido, l1, ch, c, wa[iw:], wa[ix2:]) } else { radf3(ido, l1, c, ch, wa[iw:], wa[ix2:]) } case 5: ix2 := iw + ido ix3 := ix2 + ido ix4 := ix3 + ido if na { radf5(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:]) } else { radf5(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:]) } default: if ido == 1 { na = !na } if na { radfg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:]) na = false } else { radfg(ido, ip, l1, idl1, c, c, c, ch, ch, wa[iw:]) na = true } } l2 = l1 } if na { return } for i := 0; i < n; i++ { c[i] = ch[i] } } func radf2(ido, l1 int, cc, ch, wa1 []float64) { cc3 := newThreeArray(ido, l1, 2, cc) ch3 := newThreeArray(ido, 2, l1, ch) for k := 0; k < l1; k++ { ch3.set(0, 0, k, cc3.at(0, k, 0)+cc3.at(0, k, 1)) ch3.set(ido-1, 1, k, cc3.at(0, k, 0)-cc3.at(0, k, 1)) } if ido < 2 { return } if ido > 2 { idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) t2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1) ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+t2) // This is left as conj(z1)-conj(z2) rather than conj(z1-z2) // to retain current signed zero behaviour. ch3.setCmplx(ic-1, 1, k, cmplx.Conj(cc3.atCmplx(i-1, k, 0))-cmplx.Conj(t2)) } } if ido%2 == 1 { return } } for k := 0; k < l1; k++ { ch3.set(0, 1, k, -cc3.at(ido-1, k, 1)) ch3.set(ido-1, 0, k, cc3.at(ido-1, k, 0)) } } func radf3(ido, l1 int, cc, ch, wa1, wa2 []float64) { const ( taur = -0.5 taui = 0.866025403784439 // sqrt(3)/2 ) cc3 := newThreeArray(ido, l1, 3, cc) ch3 := newThreeArray(ido, 3, l1, ch) for k := 0; k < l1; k++ { cr2 := cc3.at(0, k, 1) + cc3.at(0, k, 2) ch3.set(0, 0, k, cc3.at(0, k, 0)+cr2) ch3.set(0, 2, k, taui*(cc3.at(0, k, 2)-cc3.at(0, k, 1))) ch3.set(ido-1, 1, k, cc3.at(0, k, 0)+taur*cr2) } if ido < 2 { return } idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) d2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1) d3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2) c2 := d2 + d3 ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+c2) t2 := cc3.atCmplx(i-1, k, 0) + scale(taur, c2) t3 := scale(taui, cmplx.Conj(swap(d2-d3))) ch3.setCmplx(i-1, 2, k, t2+t3) ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t2-t3)) } } } func radf4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64) { const hsqt2 = math.Sqrt2 / 2 cc3 := newThreeArray(ido, l1, 4, cc) ch3 := newThreeArray(ido, 4, l1, ch) for k := 0; k < l1; k++ { tr1 := cc3.at(0, k, 1) + cc3.at(0, k, 3) tr2 := cc3.at(0, k, 0) + cc3.at(0, k, 2) ch3.set(0, 0, k, tr1+tr2) ch3.set(ido-1, 3, k, tr2-tr1) ch3.set(ido-1, 1, k, cc3.at(0, k, 0)-cc3.at(0, k, 2)) ch3.set(0, 2, k, cc3.at(0, k, 3)-cc3.at(0, k, 1)) } if ido < 2 { return } if ido > 2 { idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) c2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1) c3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2) c4 := complex(wa3[i-2], -wa3[i-1]) * cc3.atCmplx(i-1, k, 3) t1 := c2 + c4 t2 := cc3.atCmplx(i-1, k, 0) + c3 t3 := cc3.atCmplx(i-1, k, 0) - c3 t4 := cmplx.Conj(c4 - c2) ch3.setCmplx(i-1, 0, k, t1+t2) ch3.setCmplx(ic-1, 3, k, cmplx.Conj(t2-t1)) ch3.setCmplx(i-1, 2, k, swap(t4)+t3) ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t3-swap(t4))) } } if ido%2 == 1 { return } } for k := 0; k < l1; k++ { ti1 := -hsqt2 * (cc3.at(ido-1, k, 1) + cc3.at(ido-1, k, 3)) tr1 := hsqt2 * (cc3.at(ido-1, k, 1) - cc3.at(ido-1, k, 3)) ch3.set(ido-1, 0, k, tr1+cc3.at(ido-1, k, 0)) ch3.set(ido-1, 2, k, cc3.at(ido-1, k, 0)-tr1) ch3.set(0, 1, k, ti1-cc3.at(ido-1, k, 2)) ch3.set(0, 3, k, ti1+cc3.at(ido-1, k, 2)) } } func radf5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64) { const ( tr11 = 0.309016994374947 ti11 = 0.951056516295154 tr12 = -0.809016994374947 ti12 = 0.587785252292473 ) cc3 := newThreeArray(ido, l1, 5, cc) ch3 := newThreeArray(ido, 5, l1, ch) for k := 0; k < l1; k++ { cr2 := cc3.at(0, k, 4) + cc3.at(0, k, 1) cr3 := cc3.at(0, k, 3) + cc3.at(0, k, 2) ci4 := cc3.at(0, k, 3) - cc3.at(0, k, 2) ci5 := cc3.at(0, k, 4) - cc3.at(0, k, 1) ch3.set(0, 0, k, cc3.at(0, k, 0)+cr2+cr3) ch3.set(ido-1, 1, k, cc3.at(0, k, 0)+tr11*cr2+tr12*cr3) ch3.set(0, 2, k, ti11*ci5+ti12*ci4) ch3.set(ido-1, 3, k, cc3.at(0, k, 0)+tr12*cr2+tr11*cr3) ch3.set(0, 4, k, ti12*ci5-ti11*ci4) } if ido < 2 { return } idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) d2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1) d3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2) d4 := complex(wa3[i-2], -wa3[i-1]) * cc3.atCmplx(i-1, k, 3) d5 := complex(wa4[i-2], -wa4[i-1]) * cc3.atCmplx(i-1, k, 4) c2 := d2 + d5 c3 := d3 + d4 c4 := cmplx.Conj(swap(d3 - d4)) c5 := cmplx.Conj(swap(d2 - d5)) ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+c2+c3) t2 := cc3.atCmplx(i-1, k, 0) + scale(tr11, c2) + scale(tr12, c3) t3 := cc3.atCmplx(i-1, k, 0) + scale(tr12, c2) + scale(tr11, c3) t4 := scale(ti12, c5) - scale(ti11, c4) t5 := scale(ti11, c5) + scale(ti12, c4) ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t2-t5)) ch3.setCmplx(i-1, 2, k, t2+t5) ch3.setCmplx(ic-1, 3, k, cmplx.Conj(t3-t4)) ch3.setCmplx(i-1, 4, k, t3+t4) } } } func radfg(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64) { cc3 := newThreeArray(ido, ip, l1, cc) c13 := newThreeArray(ido, l1, ip, c1) ch3 := newThreeArray(ido, l1, ip, ch) c2m := newTwoArray(idl1, ip, c2) ch2m := newTwoArray(idl1, ip, ch2) arg := 2 * math.Pi / float64(ip) dcp := math.Cos(arg) dsp := math.Sin(arg) ipph := (ip + 1) / 2 nbd := (ido - 1) / 2 if ido == 1 { for ik := 0; ik < idl1; ik++ { c2m.set(ik, 0, ch2m.at(ik, 0)) } } else { for ik := 0; ik < idl1; ik++ { ch2m.set(ik, 0, c2m.at(ik, 0)) } for j := 1; j < ip; j++ { for k := 0; k < l1; k++ { ch3.set(0, k, j, c13.at(0, k, j)) } } is := -ido - 1 if nbd > l1 { for j := 1; j < ip; j++ { is += ido for k := 0; k < l1; k++ { idij := is for i := 2; i < ido; i += 2 { idij += 2 ch3.setCmplx(i-1, k, j, complex(wa[idij-1], -wa[idij])*c13.atCmplx(i-1, k, j)) } } } } else { for j := 1; j < ip; j++ { is += ido idij := is for i := 2; i < ido; i += 2 { idij += 2 for k := 0; k < l1; k++ { ch3.setCmplx(i-1, k, j, complex(wa[idij-1], -wa[idij])*c13.atCmplx(i-1, k, j)) } } } } if nbd < l1 { for j := 1; j < ipph; j++ { jc := ip - j for i := 2; i < ido; i += 2 { for k := 0; k < l1; k++ { c13.setCmplx(i-1, k, j, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc)) c13.setCmplx(i-1, k, jc, cmplx.Conj(swap(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc)))) } } } } else { for j := 1; j < ipph; j++ { jc := ip - j for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { c13.setCmplx(i-1, k, j, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc)) c13.setCmplx(i-1, k, jc, cmplx.Conj(swap(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc)))) } } } } } for j := 1; j < ipph; j++ { jc := ip - j for k := 0; k < l1; k++ { c13.set(0, k, j, ch3.at(0, k, j)+ch3.at(0, k, jc)) c13.set(0, k, jc, ch3.at(0, k, jc)-ch3.at(0, k, j)) } } ar1 := 1.0 ai1 := 0.0 for l := 1; l < ipph; l++ { lc := ip - l ar1h := dcp*ar1 - dsp*ai1 ai1 = dcp*ai1 + dsp*ar1 ar1 = ar1h for ik := 0; ik < idl1; ik++ { ch2m.set(ik, l, c2m.at(ik, 0)+ar1*c2m.at(ik, 1)) ch2m.set(ik, lc, ai1*c2m.at(ik, ip-1)) } dc2 := ar1 ds2 := ai1 ar2 := ar1 ai2 := ai1 for j := 2; j < ipph; j++ { jc := ip - j ar2h := dc2*ar2 - ds2*ai2 ai2 = dc2*ai2 + ds2*ar2 ar2 = ar2h for ik := 0; ik < idl1; ik++ { ch2m.add(ik, l, ar2*c2m.at(ik, j)) ch2m.add(ik, lc, ai2*c2m.at(ik, jc)) } } } for j := 1; j < ipph; j++ { for ik := 0; ik < idl1; ik++ { ch2m.add(ik, 0, c2m.at(ik, j)) } } if ido < l1 { for i := 0; i < ido; i++ { for k := 0; k < l1; k++ { cc3.set(i, 0, k, ch3.at(i, k, 0)) } } } else { for k := 0; k < l1; k++ { for i := 0; i < ido; i++ { cc3.set(i, 0, k, ch3.at(i, k, 0)) } } } for j := 1; j < ipph; j++ { jc := ip - j j2 := 2 * j for k := 0; k < l1; k++ { cc3.set(ido-1, j2-1, k, ch3.at(0, k, j)) cc3.set(0, j2, k, ch3.at(0, k, jc)) } } if ido == 1 { return } if nbd < l1 { for j := 1; j < ipph; j++ { jc := ip - j j2 := 2 * j for i := 2; i < ido; i += 2 { ic := ido - i for k := 0; k < l1; k++ { cc3.setCmplx(i-1, j2, k, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc)) cc3.setCmplx(ic-1, j2-1, k, cmplx.Conj(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc))) } } } return } for j := 1; j < ipph; j++ { jc := ip - j j2 := 2 * j for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := ido - i cc3.setCmplx(i-1, j2, k, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc)) cc3.setCmplx(ic-1, j2-1, k, cmplx.Conj(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc))) } } } } // Rfftb computes the real perodic sequence from its Fourier // coefficients (Fourier synthesis). The transform is defined // below at output parameter r. // // Input parameters // // n The length of the array r to be transformed. The method // is most efficient when n is a product of small primes. // n may change so long as different work arrays are provided. // // r A real array of length n which contains the sequence // to be transformed. // // work A work array which must be dimensioned at least 2*n. // in the program that calls Rfftb. The work array must be // initialized by calling subroutine rffti(n,work,ifac) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // The same work array can be used by Rfftf and Rfftb. // // ifac A work array containing the factors of n. ifac must have // length of at least 15. // // output parameters // // r for n even and for i = 0, ..., n // r[i] = r[0]+(-1)^i*r[n-1] // plus the sum from k=1 to k=n/2-1 of // 2*r(2*k-1)*cos(k*i*2*pi/n) // -2*r(2*k)*sin(k*i*2*pi/n) // // for n odd and for i = 0, ..., n-1 // r[i] = r[0] plus the sum from k=1 to k=(n-1)/2 of // 2*r(2*k-1)*cos(k*i*2*pi/n) // -2*r(2*k)*sin(k*i*2*pi/n) // // This transform is unnormalized since a call of Rfftf // followed by a call of Rfftb will multiply the input // sequence by n. // // work Contains results which must not be destroyed between // calls of Rfftf or Rfftb. // ifac Contains results which must not be destroyed between // calls of Rfftf or Rfftb. func Rfftb(n int, r, work []float64, ifac []int) { if len(r) < n { panic("fourier: short sequence") } if len(work) < 2*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 1 { return } rfftb1(n, r[:n], work[:n], work[n:2*n], ifac[:15]) } func rfftb1(n int, c, ch, wa []float64, ifac []int) { nf := ifac[1] na := false l1 := 1 iw := 0 for k1 := 1; k1 <= nf; k1++ { ip := ifac[k1+1] l2 := ip * l1 ido := n / l2 idl1 := ido * l1 switch ip { case 4: ix2 := iw + ido ix3 := ix2 + ido if na { radb4(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:]) } else { radb4(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:]) } na = !na case 2: if na { radb2(ido, l1, ch, c, wa[iw:]) } else { radb2(ido, l1, c, ch, wa[iw:]) } na = !na case 3: ix2 := iw + ido if na { radb3(ido, l1, ch, c, wa[iw:], wa[ix2:]) } else { radb3(ido, l1, c, ch, wa[iw:], wa[ix2:]) } na = !na case 5: ix2 := iw + ido ix3 := ix2 + ido ix4 := ix3 + ido if na { radb5(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:]) } else { radb5(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:]) } na = !na default: if na { radbg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:]) } else { radbg(ido, ip, l1, idl1, c, c, c, ch, ch, wa[iw:]) } if ido == 1 { na = !na } } l1 = l2 iw += (ip - 1) * ido } if na { for i := 0; i < n; i++ { c[i] = ch[i] } } } func radb2(ido, l1 int, cc, ch, wa1 []float64) { cc3 := newThreeArray(ido, 2, l1, cc) ch3 := newThreeArray(ido, l1, 2, ch) for k := 0; k < l1; k++ { ch3.set(0, k, 0, cc3.at(0, 0, k)+cc3.at(ido-1, 1, k)) ch3.set(0, k, 1, cc3.at(0, 0, k)-cc3.at(ido-1, 1, k)) } if ido < 2 { return } if ido > 2 { idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+cmplx.Conj(cc3.atCmplx(ic-1, 1, k))) t2 := cc3.atCmplx(i-1, 0, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k)) ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*t2) } } if ido%2 == 1 { return } } for k := 0; k < l1; k++ { ch3.set(ido-1, k, 0, 2*cc3.at(ido-1, 0, k)) ch3.set(ido-1, k, 1, -2*cc3.at(0, 1, k)) } } func radb3(ido, l1 int, cc, ch, wa1, wa2 []float64) { const ( taur = -0.5 taui = 0.866025403784439 // sqrt(3)/2 ) cc3 := newThreeArray(ido, 3, l1, cc) ch3 := newThreeArray(ido, l1, 3, ch) for k := 0; k < l1; k++ { tr2 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k) cr2 := cc3.at(0, 0, k) + taur*tr2 ch3.set(0, k, 0, cc3.at(0, 0, k)+tr2) ci3 := taui * (cc3.at(0, 2, k) + cc3.at(0, 2, k)) ch3.set(0, k, 1, cr2-ci3) ch3.set(0, k, 2, cr2+ci3) } if ido == 1 { return } idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) t2 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k)) c2 := cc3.atCmplx(i-1, 0, k) + scale(taur, t2) ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2) c3 := scale(taui, cc3.atCmplx(i-1, 2, k)-cmplx.Conj(cc3.atCmplx(ic-1, 1, k))) d2 := c2 - cmplx.Conj(swap(c3)) d3 := c2 + cmplx.Conj(swap(c3)) ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*d2) ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*d3) } } } func radb4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64) { cc3 := newThreeArray(ido, 4, l1, cc) ch3 := newThreeArray(ido, l1, 4, ch) for k := 0; k < l1; k++ { tr1 := cc3.at(0, 0, k) - cc3.at(ido-1, 3, k) tr2 := cc3.at(0, 0, k) + cc3.at(ido-1, 3, k) tr3 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k) tr4 := cc3.at(0, 2, k) + cc3.at(0, 2, k) ch3.set(0, k, 0, tr2+tr3) ch3.set(0, k, 1, tr1-tr4) ch3.set(0, k, 2, tr2-tr3) ch3.set(0, k, 3, tr1+tr4) } if ido < 2 { return } if ido > 2 { idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) t1 := cc3.atCmplx(i-1, 0, k) - cmplx.Conj(cc3.atCmplx(ic-1, 3, k)) t2 := cc3.atCmplx(i-1, 0, k) + cmplx.Conj(cc3.atCmplx(ic-1, 3, k)) t3 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k)) t4 := swap(cc3.atCmplx(i-1, 2, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k))) ch3.setCmplx(i-1, k, 0, t2+t3) c2 := t1 - cmplx.Conj(t4) c3 := t2 - t3 c4 := t1 + cmplx.Conj(t4) ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*c2) ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*c3) ch3.setCmplx(i-1, k, 3, complex(wa3[i-2], wa3[i-1])*c4) } } if ido%2 == 1 { return } } for k := 0; k < l1; k++ { tr1 := cc3.at(ido-1, 0, k) - cc3.at(ido-1, 2, k) ti1 := cc3.at(0, 1, k) + cc3.at(0, 3, k) tr2 := cc3.at(ido-1, 0, k) + cc3.at(ido-1, 2, k) ti2 := cc3.at(0, 3, k) - cc3.at(0, 1, k) ch3.set(ido-1, k, 0, tr2+tr2) ch3.set(ido-1, k, 1, math.Sqrt2*(tr1-ti1)) ch3.set(ido-1, k, 2, ti2+ti2) ch3.set(ido-1, k, 3, -math.Sqrt2*(tr1+ti1)) } } func radb5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64) { const ( tr11 = 0.309016994374947 ti11 = 0.951056516295154 tr12 = -0.809016994374947 ti12 = 0.587785252292473 ) cc3 := newThreeArray(ido, 5, l1, cc) ch3 := newThreeArray(ido, l1, 5, ch) for k := 0; k < l1; k++ { tr2 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k) tr3 := cc3.at(ido-1, 3, k) + cc3.at(ido-1, 3, k) ti4 := cc3.at(0, 4, k) + cc3.at(0, 4, k) ti5 := cc3.at(0, 2, k) + cc3.at(0, 2, k) ch3.set(0, k, 0, cc3.at(0, 0, k)+tr2+tr3) cr2 := cc3.at(0, 0, k) + tr11*tr2 + tr12*tr3 cr3 := cc3.at(0, 0, k) + tr12*tr2 + tr11*tr3 ci4 := ti12*ti5 - ti11*ti4 ci5 := ti11*ti5 + ti12*ti4 ch3.set(0, k, 1, cr2-ci5) ch3.set(0, k, 2, cr3-ci4) ch3.set(0, k, 3, cr3+ci4) ch3.set(0, k, 4, cr2+ci5) } if ido == 1 { return } idp2 := ido + 1 for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := idp2 - (i + 1) t2 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k)) t3 := cc3.atCmplx(i-1, 4, k) + cmplx.Conj(cc3.atCmplx(ic-1, 3, k)) t4 := cc3.atCmplx(i-1, 4, k) - cmplx.Conj(cc3.atCmplx(ic-1, 3, k)) t5 := cc3.atCmplx(i-1, 2, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k)) ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2+t3) c2 := cc3.atCmplx(i-1, 0, k) + scale(tr11, t2) + scale(tr12, t3) c3 := cc3.atCmplx(i-1, 0, k) + scale(tr12, t2) + scale(tr11, t3) c4 := scale(ti12, t5) - scale(ti11, t4) c5 := scale(ti11, t5) + scale(ti12, t4) d2 := c2 - cmplx.Conj(swap(c5)) d3 := c3 - cmplx.Conj(swap(c4)) d4 := c3 + cmplx.Conj(swap(c4)) d5 := c2 + cmplx.Conj(swap(c5)) ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*d2) ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*d3) ch3.setCmplx(i-1, k, 3, complex(wa3[i-2], wa3[i-1])*d4) ch3.setCmplx(i-1, k, 4, complex(wa4[i-2], wa4[i-1])*d5) } } } func radbg(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64) { cc3 := newThreeArray(ido, ip, l1, cc) c13 := newThreeArray(ido, l1, ip, c1) ch3 := newThreeArray(ido, l1, ip, ch) c2m := newTwoArray(idl1, ip, c2) ch2m := newTwoArray(idl1, ip, ch2) arg := 2 * math.Pi / float64(ip) dcp := math.Cos(arg) dsp := math.Sin(arg) ipph := (ip + 1) / 2 nbd := (ido - 1) / 2 if ido < l1 { for i := 0; i < ido; i++ { for k := 0; k < l1; k++ { ch3.set(i, k, 0, cc3.at(i, 0, k)) } } } else { for k := 0; k < l1; k++ { for i := 0; i < ido; i++ { ch3.set(i, k, 0, cc3.at(i, 0, k)) } } } for j := 1; j < ipph; j++ { jc := ip - j j2 := 2 * j for k := 0; k < l1; k++ { ch3.set(0, k, j, cc3.at(ido-1, j2-1, k)+cc3.at(ido-1, j2-1, k)) ch3.set(0, k, jc, cc3.at(0, j2, k)+cc3.at(0, j2, k)) } } if ido != 1 { if nbd < l1 { for j := 1; j < ipph; j++ { jc := ip - j j2 := 2 * j for i := 2; i < ido; i += 2 { ic := ido - i for k := 0; k < l1; k++ { ch3.setCmplx(i-1, k, j, cc3.atCmplx(i-1, j2, k)+cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k))) ch3.setCmplx(i-1, k, jc, cc3.atCmplx(i-1, j2, k)-cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k))) } } } } else { for j := 1; j < ipph; j++ { jc := ip - j j2 := 2 * j for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ic := ido - i ch3.setCmplx(i-1, k, j, cc3.atCmplx(i-1, j2, k)+cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k))) ch3.setCmplx(i-1, k, jc, cc3.atCmplx(i-1, j2, k)-cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k))) } } } } } ar1 := 1.0 ai1 := 0.0 for l := 1; l < ipph; l++ { lc := ip - l ar1h := dcp*ar1 - dsp*ai1 ai1 = dcp*ai1 + dsp*ar1 ar1 = ar1h for ik := 0; ik < idl1; ik++ { c2m.set(ik, l, ch2m.at(ik, 0)+ar1*ch2m.at(ik, 1)) c2m.set(ik, lc, ai1*ch2m.at(ik, ip-1)) } dc2 := ar1 ds2 := ai1 ar2 := ar1 ai2 := ai1 for j := 2; j < ipph; j++ { jc := ip - j ar2h := dc2*ar2 - ds2*ai2 ai2 = dc2*ai2 + ds2*ar2 ar2 = ar2h for ik := 0; ik < idl1; ik++ { c2m.add(ik, l, ar2*ch2m.at(ik, j)) c2m.add(ik, lc, ai2*ch2m.at(ik, jc)) } } } for j := 1; j < ipph; j++ { for ik := 0; ik < idl1; ik++ { ch2m.add(ik, 0, ch2m.at(ik, j)) } } for j := 1; j < ipph; j++ { jc := ip - j for k := 0; k < l1; k++ { ch3.set(0, k, j, c13.at(0, k, j)-c13.at(0, k, jc)) ch3.set(0, k, jc, c13.at(0, k, j)+c13.at(0, k, jc)) } } if ido != 1 { if nbd < l1 { for j := 1; j < ipph; j++ { jc := ip - j for i := 2; i < ido; i += 2 { for k := 0; k < l1; k++ { ch3.setCmplx(i-1, k, j, c13.atCmplx(i-1, k, j)-cmplx.Conj(swap(c13.atCmplx(i-1, k, jc)))) ch3.setCmplx(i-1, k, jc, c13.atCmplx(i-1, k, j)+cmplx.Conj(swap(c13.atCmplx(i-1, k, jc)))) } } } } else { for j := 1; j < ipph; j++ { jc := ip - j for k := 0; k < l1; k++ { for i := 2; i < ido; i += 2 { ch3.setCmplx(i-1, k, j, c13.atCmplx(i-1, k, j)-cmplx.Conj(swap(c13.atCmplx(i-1, k, jc)))) ch3.setCmplx(i-1, k, jc, c13.atCmplx(i-1, k, j)+cmplx.Conj(swap(c13.atCmplx(i-1, k, jc)))) } } } } } if ido == 1 { return } for ik := 0; ik < idl1; ik++ { c2m.set(ik, 0, ch2m.at(ik, 0)) } for j := 1; j < ip; j++ { for k := 0; k < l1; k++ { c13.set(0, k, j, ch3.at(0, k, j)) } } is := -ido - 1 if nbd > l1 { for j := 1; j < ip; j++ { is += ido for k := 0; k < l1; k++ { idij := is for i := 2; i < ido; i += 2 { idij += 2 c13.setCmplx(i-1, k, j, complex(wa[idij-1], wa[idij])*ch3.atCmplx(i-1, k, j)) } } } return } for j := 1; j < ip; j++ { is += ido idij := is for i := 2; i < ido; i += 2 { idij += 2 for k := 0; k < l1; k++ { c13.setCmplx(i-1, k, j, complex(wa[idij-1], wa[idij])*ch3.atCmplx(i-1, k, j)) } } } } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/sinq.go000066400000000000000000000131011450372207100246260ustar00rootroot00000000000000// 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. // This is a translation of the FFTPACK sinq functions by // Paul N Swarztrauber, placed in the public domain at // http://www.netlib.org/fftpack/. package fftpack import "math" // Sinqi initializes the array work which is used in both Sinqf and // Sinqb. The prime factorization of n together with a tabulation // of the trigonometric functions are computed and stored in work. // // Input parameter: // // n The length of the sequence to be transformed. The method // is most efficient when n+1 is a product of small primes. // // Output parameter: // // work A work array which must be dimensioned at least 3*n. // The same work array can be used for both Sinqf and Sinqb // as long as n remains unchanged. Different work arrays // are required for different values of n. The contents of // work must not be changed between calls of Sinqf or Sinqb. // // ifac An integer work array of length at least 15. func Sinqi(n int, work []float64, ifac []int) { if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } dt := 0.5 * math.Pi / float64(n) for k := range work[:n] { work[k] = math.Cos(float64(k+1) * dt) } Rffti(n, work[n:], ifac) } // Sinqf computes the Fast Fourier Transform of quarter wave data. // That is, Sinqf computes the coefficients in a sine series // representation with only odd wave numbers. The transform is // defined below at output parameter x. // // Sinqb is the unnormalized inverse of Sinqf since a call of Sinqf // followed by a call of Sinqb will multiply the input sequence x // by 4*n. // // The array work which is used by subroutine Sinqf must be // initialized by calling subroutine Sinqi(n,work). // // Input parameters: // // n The length of the array x to be transformed. The method // is most efficient when n is a product of small primes. // // x An array which contains the sequence to be transformed. // // work A work array which must be dimensioned at least 3*n. // in the program that calls Sinqf. The work array must be // initialized by calling subroutine Sinqi(n,work) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // // ifac An integer work array of length at least 15. // // Output parameters: // // x for i=0, ..., n-1 // x[i] = (-1)^(i)*x[n-1] // + the sum from k=0 to k=n-2 of // 2*x[k]*sin((2*i+1)*k*pi/(2*n)) // // A call of Sinqf followed by a call of // Sinqb will multiply the sequence x by 4*n. // Therefore Sinqb is the unnormalized inverse // of Sinqf. // // work Contains initialization calculations which must not // be destroyed between calls of Sinqf or Sinqb. func Sinqf(n int, x, work []float64, ifac []int) { if len(x) < n { panic("fourier: short sequence") } if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 1 { return } for k := 0; k < n/2; k++ { kc := n - k - 1 x[k], x[kc] = x[kc], x[k] } Cosqf(n, x, work, ifac) for k := 1; k < n; k += 2 { x[k] = -x[k] } } // Sinqb computes the Fast Fourier Transform of quarter wave data. // That is, Sinqb computes a sequence from its representation in // terms of a sine series with odd wave numbers. The transform is // defined below at output parameter x. // // Sinqf is the unnormalized inverse of Sinqb since a call of Sinqb // followed by a call of Sinqf will multiply the input sequence x // by 4*n. // // The array work which is used by subroutine Sinqb must be // initialized by calling subroutine Sinqi(n,work). // // Input parameters: // // n The length of the array x to be transformed. The method // is most efficient when n is a product of small primes. // // x An array which contains the sequence to be transformed. // // work A work array which must be dimensioned at least 3*n. // in the program that calls Sinqb. The work array must be // initialized by calling subroutine Sinqi(n,work) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // // ifac An integer work array of length at least 15. // // Output parameters: // // x for i=0, ..., n-1 // x[i]= the sum from k=0 to k=n-1 of // 4*x[k]*sin((2*k+1)*i*pi/(2*n)) // // A call of Sinqb followed by a call of // Sinqf will multiply the sequence x by 4*n. // Therefore Sinqf is the unnormalized inverse // of Sinqb. // // work Contains initialization calculations which must not // be destroyed between calls of Sinqb or Sinqf. func Sinqb(n int, x, work []float64, ifac []int) { if len(x) < n { panic("fourier: short sequence") } if len(work) < 3*n { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } switch n { case 1: x[0] *= 4 fallthrough case 0: return default: for k := 1; k < n; k += 2 { x[k] = -x[k] } Cosqb(n, x, work, ifac) for k := 0; k < n/2; k++ { kc := n - k - 1 x[k], x[kc] = x[kc], x[k] } } } golang-gonum-v1-gonum-0.14.0/dsp/fourier/internal/fftpack/sint.go000066400000000000000000000077231450372207100246460ustar00rootroot00000000000000// 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. // This is a translation of the FFTPACK sint functions by // Paul N Swarztrauber, placed in the public domain at // http://www.netlib.org/fftpack/. package fftpack import "math" // Sinti initializes the array work which is used in subroutine Sint. // The prime factorization of n together with a tabulation of the // trigonometric functions are computed and stored in work. // // Input parameter: // // n The length of the sequence to be transformed. The method // is most efficient when n+1 is a product of small primes. // // Output parameter: // // work A work array with at least ceil(2.5*n) locations. // Different work arrays are required for different values // of n. The contents of work must not be changed between // calls of Sint. // // ifac An integer work array of length at least 15. func Sinti(n int, work []float64, ifac []int) { if len(work) < 5*(n+1)/2 { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n <= 1 { return } dt := math.Pi / float64(n+1) for k := 0; k < n/2; k++ { work[k] = 2 * math.Sin(float64(k+1)*dt) } Rffti(n+1, work[n/2:], ifac) } // Sint computes the Discrete Fourier Sine Transform of an odd // sequence x(i). The transform is defined below at output parameter x. // // Sint is the unnormalized inverse of itself since a call of Sint // followed by another call of Sint will multiply the input sequence // x by 2*(n+1). // // The array work which is used by subroutine Sint must be // initialized by calling subroutine Sinti(n,work). // // Input parameters: // // n The length of the sequence to be transformed. The method // is most efficient when n+1 is the product of small primes. // // x An array which contains the sequence to be transformed. // // // work A work array with dimension at least ceil(2.5*n) // in the program that calls Sint. The work array must be // initialized by calling subroutine Sinti(n,work) and a // different work array must be used for each different // value of n. This initialization does not have to be // repeated so long as n remains unchanged thus subsequent // transforms can be obtained faster than the first. // // ifac An integer work array of length at least 15. // // Output parameters: // // x for i=1,...,n // x(i)= the sum from k=1 to k=n // 2*x(k)*sin(k*i*pi/(n+1)) // // A call of Sint followed by another call of // Sint will multiply the sequence x by 2*(n+1). // Hence Sint is the unnormalized inverse // of itself. // // work Contains initialization calculations which must not be // destroyed between calls of Sint. // ifac Contains initialization calculations which must not be // destroyed between calls of Sint. func Sint(n int, x, work []float64, ifac []int) { if len(x) < n { panic("fourier: short sequence") } if len(work) < 5*(n+1)/2 { panic("fourier: short work") } if len(ifac) < 15 { panic("fourier: short ifac") } if n == 0 { return } sint1(n, x, work, work[n/2:], work[n/2+n+1:], ifac) } func sint1(n int, war, was, xh, x []float64, ifac []int) { const sqrt3 = 1.73205080756888 for i := 0; i < n; i++ { xh[i] = war[i] war[i] = x[i] } switch n { case 1: xh[0] *= 2 case 2: xh[0], xh[1] = sqrt3*(xh[0]+xh[1]), sqrt3*(xh[0]-xh[1]) default: x[0] = 0 for k := 0; k < n/2; k++ { kc := n - k - 1 t1 := xh[k] - xh[kc] t2 := was[k] * (xh[k] + xh[kc]) x[k+1] = t1 + t2 x[kc+1] = t2 - t1 } if n%2 != 0 { x[n/2+1] = 4 * xh[n/2] } rfftf1(n+1, x, xh, war, ifac) xh[0] = 0.5 * x[0] for i := 2; i < n; i += 2 { xh[i-1] = -x[i] xh[i] = xh[i-2] + x[i-1] } if n%2 == 0 { xh[n-1] = -x[n] } } for i := 0; i < n; i++ { x[i] = war[i] war[i] = xh[i] } } golang-gonum-v1-gonum-0.14.0/dsp/fourier/quarter.go000066400000000000000000000114641450372207100221170ustar00rootroot00000000000000// 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 fourier import "gonum.org/v1/gonum/dsp/fourier/internal/fftpack" // QuarterWaveFFT implements Fast Fourier Transform for quarter wave data. type QuarterWaveFFT struct { work []float64 ifac [15]int } // NewQuarterWaveFFT returns a QuarterWaveFFT initialized for work on sequences of length n. func NewQuarterWaveFFT(n int) *QuarterWaveFFT { var t QuarterWaveFFT t.Reset(n) return &t } // Len returns the length of the acceptable input. func (t *QuarterWaveFFT) Len() int { return len(t.work) / 3 } // Reset reinitializes the QuarterWaveFFT for work on sequences of length n. func (t *QuarterWaveFFT) Reset(n int) { if 3*n <= cap(t.work) { t.work = t.work[:3*n] } else { t.work = make([]float64, 3*n) } fftpack.Cosqi(n, t.work, t.ifac[:]) } // CosCoefficients computes the Fast Fourier Transform of quarter wave data for // the input sequence, seq, placing the cosine series coefficients in dst and // returning it. // This transform is unnormalized; a call to CosCoefficients followed by a call // to CosSequence will multiply the input sequence by 4*n, where n is the length // of the sequence. // // If the length of seq is not t.Len(), CosCoefficients will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal t.Len(), CosCoefficients will panic. // It is safe to use the same slice for dst and seq. func (t *QuarterWaveFFT) CosCoefficients(dst, seq []float64) []float64 { if len(seq) != t.Len() { panic("fourier: sequence length mismatch") } if dst == nil { dst = make([]float64, t.Len()) } else if len(dst) != t.Len() { panic("fourier: destination length mismatch") } copy(dst, seq) fftpack.Cosqf(len(dst), dst, t.work, t.ifac[:]) return dst } // CosSequence computes the Inverse Fast Fourier Transform of quarter wave data for // the input cosine series coefficients, coeff, placing the sequence data in dst // and returning it. // This transform is unnormalized; a call to CosSequence followed by a call // to CosCoefficients will multiply the input sequence by 4*n, where n is the length // of the sequence. // // If the length of seq is not t.Len(), CosSequence will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal t.Len(), CosSequence will panic. // It is safe to use the same slice for dst and seq. func (t *QuarterWaveFFT) CosSequence(dst, coeff []float64) []float64 { if len(coeff) != t.Len() { panic("fourier: coefficients length mismatch") } if dst == nil { dst = make([]float64, t.Len()) } else if len(dst) != t.Len() { panic("fourier: destination length mismatch") } copy(dst, coeff) fftpack.Cosqb(len(dst), dst, t.work, t.ifac[:]) return dst } // SinCoefficients computes the Fast Fourier Transform of quarter wave data for // the input sequence, seq, placing the sine series coefficients in dst and // returning it. // This transform is unnormalized; a call to SinCoefficients followed by a call // to SinSequence will multiply the input sequence by 4*n, where n is the length // of the sequence. // // If the length of seq is not t.Len(), SinCoefficients will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal t.Len(), SinCoefficients will panic. // It is safe to use the same slice for dst and seq. func (t *QuarterWaveFFT) SinCoefficients(dst, seq []float64) []float64 { if len(seq) != t.Len() { panic("fourier: sequence length mismatch") } if dst == nil { dst = make([]float64, t.Len()) } else if len(dst) != t.Len() { panic("fourier: destination length mismatch") } copy(dst, seq) fftpack.Sinqf(len(dst), dst, t.work, t.ifac[:]) return dst } // SinSequence computes the Inverse Fast Fourier Transform of quarter wave data for // the input sine series coefficients, coeff, placing the sequence data in dst // and returning it. // This transform is unnormalized; a call to SinSequence followed by a call // to SinCoefficients will multiply the input sequence by 4*n, where n is the length // of the sequence. // // If the length of seq is not t.Len(), SinSequence will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal t.Len(), SinSequence will panic. // It is safe to use the same slice for dst and seq. func (t *QuarterWaveFFT) SinSequence(dst, coeff []float64) []float64 { if len(coeff) != t.Len() { panic("fourier: coefficients length mismatch") } if dst == nil { dst = make([]float64, t.Len()) } else if len(dst) != t.Len() { panic("fourier: destination length mismatch") } copy(dst, coeff) fftpack.Sinqb(len(dst), dst, t.work, t.ifac[:]) return dst } golang-gonum-v1-gonum-0.14.0/dsp/fourier/radix24.go000066400000000000000000000213711450372207100217070ustar00rootroot00000000000000// Copyright ©2020 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 fourier import ( "math" "math/bits" "math/cmplx" ) // CoefficientsRadix2 computes the Fourier coefficients of the input // sequence, converting the time series in seq into the frequency spectrum, // in place and returning it. This transform is unnormalized; a call to // CoefficientsRadix2 followed by a call of SequenceRadix2 will multiply the // input sequence by the length of the sequence. // // CoefficientsRadix2 does not allocate, requiring that FFT twiddle factors // be calculated lazily. For performance reasons, this is done by successive // multiplication, so numerical accuracies can accumulate for large inputs. // If accuracy is needed, the FFT or CmplxFFT types should be used. // // If the length of seq is not an integer power of 2, CoefficientsRadix2 will // panic. func CoefficientsRadix2(seq []complex128) []complex128 { x := seq switch len(x) { default: if bits.OnesCount(uint(len(x))) != 1 { panic("fourier: radix-2 fft called with non-power 2 length") } case 0, 1: return x case 2: x[0], x[1] = x[0]+x[1], x[0]-x[1] return x case 4: t := x[1] + x[3] u := x[2] v := negi(x[1] - x[3]) x[0], x[1], x[2], x[3] = x[0]+u+t, x[0]-u+v, x[0]+u-t, x[0]-u-v return x } bitReversePermute(x) for k := 0; k < len(x); k += 4 { t := x[k+2] + x[k+3] u := x[k+1] v := negi(x[k+2] - x[k+3]) x[k], x[k+1], x[k+2], x[k+3] = x[k]+u+t, x[k]-u+v, x[k]+u-t, x[k]-u-v } for m := 4; m < len(x); m *= 2 { f := swap(complex(math.Sincos(-math.Pi / float64(m)))) for k := 0; k < len(x); k += 2 * m { w := 1 + 0i for j := 0; j < m; j++ { i := j + k u := w * x[i+m] x[i], x[i+m] = x[i]+u, x[i]-u w *= f } } } return x } // bitReversePermute performs a bit-reversal permutation on x. func bitReversePermute(x []complex128) { if len(x) < 2 || bits.OnesCount(uint(len(x))) != 1 { panic("fourier: invalid bitReversePermute call") } lz := bits.LeadingZeros(uint(len(x) - 1)) i := 0 for ; i < len(x)/2; i++ { j := int(bits.Reverse(uint(i)) >> lz) if i < j { x[i], x[j] = x[j], x[i] } } for i++; i < len(x); i += 2 { j := int(bits.Reverse(uint(i)) >> lz) if i < j { x[i], x[j] = x[j], x[i] } } } // SequenceRadix2 computes the real periodic sequence from the Fourier // coefficients, converting the frequency spectrum in coeff into a time // series, in place and returning it. This transform is unnormalized; a // call to CoefficientsRadix2 followed by a call of SequenceRadix2 will // multiply the input sequence by the length of the sequence. // // SequenceRadix2 does not allocate, requiring that FFT twiddle factors // be calculated lazily. For performance reasons, this is done by successive // multiplication, so numerical accuracies can accumulate for large inputs. // If accuracy is needed, the FFT or CmplxFFT types should be used. // // If the length of coeff is not an integer power of 2, SequenceRadix2 // will panic. func SequenceRadix2(coeff []complex128) []complex128 { x := coeff for i, j := 1, len(x)-1; i < j; i, j = i+1, j-1 { x[i], x[j] = x[j], x[i] } CoefficientsRadix2(x) return x } // PadRadix2 returns the values in x in a slice that is an integer // power of 2 long. If x already has an integer power of 2 length // it is returned unaltered. func PadRadix2(x []complex128) []complex128 { if len(x) == 0 { return x } b := bits.Len(uint(len(x))) if len(x) == 1<<(b-1) { return x } p := make([]complex128, 1<> lz) if i < j { x[i], x[j] = x[j], x[i] } } for i++; i < len(x); i += 2 { j := int(reversePairs(uint(i)) >> lz) if i < j { x[i], x[j] = x[j], x[i] } } } // SequenceRadix4 computes the real periodic sequence from the Fourier // coefficients, converting the frequency spectrum in coeff into a time // series, in place and returning it. This transform is unnormalized; a // call to CoefficientsRadix4 followed by a call of SequenceRadix4 will // multiply the input sequence by the length of the sequence. // // SequenceRadix4 does not allocate, requiring that FFT twiddle factors // be calculated lazily. For performance reasons, this is done by successive // multiplication, so numerical accuracies can accumulate for large inputs. // If accuracy is needed, the FFT or CmplxFFT types should be used. // // If the length of coeff is not an integer power of 4, SequenceRadix4 // will panic. func SequenceRadix4(coeff []complex128) []complex128 { x := coeff for i, j := 1, len(x)-1; i < j; i, j = i+1, j-1 { x[i], x[j] = x[j], x[i] } CoefficientsRadix4(x) return x } // PadRadix4 returns the values in x in a slice that is an integer // power of 4 long. If x already has an integer power of 4 length // it is returned unaltered. func PadRadix4(x []complex128) []complex128 { if len(x) == 0 { return x } b := bits.Len(uint(len(x))) if len(x) == 1<<(b-1) && b&0x1 == 1 { return x } p := make([]complex128, 1<<((b+1)&^0x1)) copy(p, x) return p } // TrimRadix4 returns the largest slice of x that is has an integer // power of 4 length, and a slice holding the remaining elements. func TrimRadix4(x []complex128) (even, remains []complex128) { if len(x) == 0 { return x, nil } n := 1 << ((bits.Len(uint(len(x))) - 1) &^ 0x1) return x[:n], x[n:] } // reversePairs returns the value of x with its bit pairs in reversed order. func reversePairs(x uint) uint { if bits.UintSize == 32 { return uint(reversePairs32(uint32(x))) } return uint(reversePairs64(uint64(x))) } const ( m1 = 0x3333333333333333 m2 = 0x0f0f0f0f0f0f0f0f ) // reversePairs32 returns the value of x with its bit pairs in reversed order. func reversePairs32(x uint32) uint32 { const m = 1<<32 - 1 x = x>>2&(m1&m) | x&(m1&m)<<2 x = x>>4&(m2&m) | x&(m2&m)<<4 return bits.ReverseBytes32(x) } // reversePairs64 returns the value of x with its bit pairs in reversed order. func reversePairs64(x uint64) uint64 { const m = 1<<64 - 1 x = x>>2&(m1&m) | x&(m1&m)<<2 x = x>>4&(m2&m) | x&(m2&m)<<4 return bits.ReverseBytes64(x) } func negi(c complex128) complex128 { return cmplx.Conj(swap(c)) } func swap(c complex128) complex128 { return complex(imag(c), real(c)) } golang-gonum-v1-gonum-0.14.0/dsp/fourier/radix24_test.go000066400000000000000000000172551450372207100227540ustar00rootroot00000000000000// Copyright ©2020 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 fourier import ( "bytes" "fmt" "math/bits" "strconv" "testing" "unsafe" "golang.org/x/exp/rand" "gonum.org/v1/gonum/cmplxs" ) func TestCoefficients(t *testing.T) { const tol = 1e-8 src := rand.NewSource(1) for n := 4; n < 1<<20; n <<= 1 { for i := 0; i < 10; i++ { t.Run(fmt.Sprintf("Radix2/%d", n), func(t *testing.T) { d := randComplexes(n, src) fft := NewCmplxFFT(n) want := fft.Coefficients(nil, d) CoefficientsRadix2(d) got := d if !cmplxs.EqualApprox(got, want, tol) { t.Errorf("unexpected result for n=%d |got-want|^2=%g", n, cmplxs.Distance(got, want, 2)) } want = fft.Sequence(nil, got) scale(1/float64(n), want) SequenceRadix2(got) scale(1/float64(n), got) if !cmplxs.EqualApprox(got, want, tol) { t.Errorf("unexpected ifft result for n=%d |got-want|^2=%g", n, cmplxs.Distance(got, want, 2)) } }) if bits.Len(uint(n))&0x1 == 0 { continue } t.Run(fmt.Sprintf("Radix4/%d", n), func(t *testing.T) { d := randComplexes(n, src) fft := NewCmplxFFT(n) want := fft.Coefficients(nil, d) CoefficientsRadix4(d) got := d if !cmplxs.EqualApprox(got, want, tol) { t.Errorf("unexpected fft result for n=%d |got-want|^2=%g", n, cmplxs.Distance(got, want, 2)) } want = fft.Sequence(nil, got) scale(1/float64(n), want) SequenceRadix4(got) scale(1/float64(n), got) if !cmplxs.EqualApprox(got, want, tol) { t.Errorf("unexpected ifft result for n=%d |got-want|^2=%g", n, cmplxs.Distance(got, want, 2)) } }) } } } func TestSequence(t *testing.T) { const tol = 1e-10 src := rand.NewSource(1) for n := 4; n < 1<<20; n <<= 1 { for i := 0; i < 10; i++ { t.Run(fmt.Sprintf("Radix2/%d", n), func(t *testing.T) { d := randComplexes(n, src) want := make([]complex128, n) copy(want, d) SequenceRadix2(CoefficientsRadix2(d)) got := d scale(1/float64(n), got) if !cmplxs.EqualApprox(got, want, tol) { t.Errorf("unexpected result for ifft(fft(d)) n=%d |got-want|^2=%g", n, cmplxs.Distance(got, want, 2)) } }) if bits.Len(uint(n))&0x1 == 0 { continue } t.Run(fmt.Sprintf("Radix4/%d", n), func(t *testing.T) { d := randComplexes(n, src) want := make([]complex128, n) copy(want, d) SequenceRadix4(CoefficientsRadix4(d)) got := d scale(1/float64(n), got) if !cmplxs.EqualApprox(got, want, tol) { t.Errorf("unexpected result for ifft(fft(d)) n=%d |got-want|^2=%g", n, cmplxs.Distance(got, want, 2)) } }) } } } func scale(f float64, c []complex128) { for i, v := range c { c[i] = complex(f*real(v), f*imag(v)) } } func TestBitReversePermute(t *testing.T) { for n := 2; n <= 1024; n <<= 1 { x := make([]complex128, n) for i := range x { x[i] = complex(float64(i), float64(i)) } bitReversePermute(x) for i, got := range x { j := bits.Reverse(uint(i)) >> bits.LeadingZeros(uint(n-1)) want := complex(float64(j), float64(j)) if got != want { t.Errorf("unexpected value at %d: got:%f want:%f", i, got, want) } } } } func TestPadRadix2(t *testing.T) { for n := 1; n <= 1025; n++ { x := make([]complex128, n) y := PadRadix2(x) if bits.OnesCount(uint(len(y))) != 1 { t.Errorf("unexpected length of padded slice: not a power of 2: %d", len(y)) } if len(x) == len(y) && &y[0] != &x[0] { t.Errorf("unexpected new allocation for power of 2 input length: len(x)=%d", n) } if len(y) < len(x) { t.Errorf("unexpected short result: len(y)=%d < len(x)=%d", len(y), len(x)) } } } func TestTrimRadix2(t *testing.T) { for n := 1; n <= 1025; n++ { x := make([]complex128, n) y, r := TrimRadix2(x) if bits.OnesCount(uint(len(y))) != 1 { t.Errorf("unexpected length of trimmed slice: not a power of 2: %d", len(y)) } if len(y)+len(r) != len(x) { t.Errorf("unexpected total result: len(y)=%d + len(r)%d != len(x)=%d", len(y), len(r), len(x)) } if len(x) == len(y) && &y[0] != &x[0] { t.Errorf("unexpected new allocation for power of 2 input length: len(x)=%d", n) } if len(y) > len(x) { t.Errorf("unexpected long result: len(y)=%d > len(x)=%d", len(y), len(x)) } } } func TestBitPairReversePermute(t *testing.T) { for n := 4; n <= 1024; n <<= 2 { x := make([]complex128, n) for i := range x { x[i] = complex(float64(i), float64(i)) } bitPairReversePermute(x) for i, got := range x { j := reversePairs(uint(i)) >> bits.LeadingZeros(uint(n-1)) want := complex(float64(j), float64(j)) if got != want { t.Errorf("unexpected value at %d: got:%f want:%f", i, got, want) } } } } func TestReversePairs(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 1000; i++ { x := uint(rnd.Uint64()) got := reversePairs(x) want := naiveReversePairs(x) if got != want { t.Errorf("unexpected bit-pair reversal for 0b%064b:\ngot: 0b%064b\nwant:0b%064b", x, got, want) } } } // naiveReversePairs does a bit-pair reversal by formatting as a base-4 string, // reversing the digits of the formatted number and then re-parsing the value. func naiveReversePairs(x uint) uint { bits := int(unsafe.Sizeof(uint(0)) * 8) // Format the number as a quaternary, padded with zeros. // We avoid the leftpad issue by doing it ourselves. b := strconv.AppendUint(bytes.Repeat([]byte("0"), bits/2), uint64(x), 4) b = b[len(b)-bits/2:] // Reverse the quits. for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { b[i], b[j] = b[j], b[i] } // Re-parse the reversed number. y, err := strconv.ParseUint(string(b), 4, 64) if err != nil { panic(fmt.Sprintf("unexpected parse error: %v", err)) } return uint(y) } func TestPadRadix4(t *testing.T) { for n := 1; n <= 1025; n++ { x := make([]complex128, n) y := PadRadix4(x) if bits.OnesCount(uint(len(y))) != 1 || bits.Len(uint(len(y)))&0x1 == 0 { t.Errorf("unexpected length of padded slice: not a power of 4: %d", len(y)) } if len(x) == len(y) && &y[0] != &x[0] { t.Errorf("unexpected new allocation for power of 2 input length: len(x)=%d", n) } if len(y) < len(x) { t.Errorf("unexpected short result: len(y)=%d < len(x)=%d", len(y), len(x)) } } } func TestTrimRadix4(t *testing.T) { for n := 1; n <= 1025; n++ { x := make([]complex128, n) y, r := TrimRadix4(x) if bits.OnesCount(uint(len(y))) != 1 || bits.Len(uint(len(y)))&0x1 == 0 { t.Errorf("unexpected length of trimmed slice: not a power of 4: %d", len(y)) } if len(y)+len(r) != len(x) { t.Errorf("unexpected total result: len(y)=%d + len(r)%d != len(x)=%d", len(y), len(r), len(x)) } if len(x) == len(y) && &y[0] != &x[0] { t.Errorf("unexpected new allocation for power of 2 input length: len(x)=%d", n) } if len(y) > len(x) { t.Errorf("unexpected long result: len(y)=%d > len(x)=%d", len(y), len(x)) } } } func BenchmarkCoefficients(b *testing.B) { for n := 16; n < 1<<24; n <<= 3 { d := randComplexes(n, rand.NewSource(1)) b.Run(fmt.Sprintf("Radix2/%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { CoefficientsRadix2(d) } }) if bits.Len(uint(n))&0x1 == 0 { continue } b.Run(fmt.Sprintf("Radix4/%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { CoefficientsRadix4(d) } }) } } func BenchmarkSequence(b *testing.B) { for n := 16; n < 1<<24; n <<= 3 { d := randComplexes(n, rand.NewSource(1)) b.Run(fmt.Sprintf("Radix2/%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { SequenceRadix2(d) } }) if bits.Len(uint(n))&0x1 == 0 { continue } b.Run(fmt.Sprintf("Radix4/%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { SequenceRadix4(d) } }) } } golang-gonum-v1-gonum-0.14.0/dsp/fourier/sincos.go000066400000000000000000000065101450372207100217260ustar00rootroot00000000000000// 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 fourier import "gonum.org/v1/gonum/dsp/fourier/internal/fftpack" // DCT implements Discrete Cosine Transform for real sequences. type DCT struct { work []float64 ifac [15]int } // NewDCT returns a DCT initialized for work on sequences of length n. // NewDCT will panic is n is not greater than 1. func NewDCT(n int) *DCT { var t DCT t.Reset(n) return &t } // Len returns the length of the acceptable input. func (t *DCT) Len() int { return len(t.work) / 3 } // Reset reinitializes the DCT for work on sequences of length n. // Reset will panic is n is not greater than 1. func (t *DCT) Reset(n int) { if n <= 1 { panic("fourier: n less than 2") } if 3*n <= cap(t.work) { t.work = t.work[:3*n] } else { t.work = make([]float64, 3*n) } fftpack.Costi(n, t.work, t.ifac[:]) } // Transform computes the Discrete Fourier Cosine Transform of // the input data, src, placing the result in dst and returning it. // This transform is unnormalized; a call to Transform followed by // another call to Transform will multiply the input sequence by 2*(n-1), // where n is the length of the sequence. // // If the length of src is not t.Len(), Transform will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal t.Len(), FFT will panic. // It is safe to use the same slice for dst and src. func (t *DCT) Transform(dst, src []float64) []float64 { if len(src) != t.Len() { panic("fourier: sequence length mismatch") } if dst == nil { dst = make([]float64, t.Len()) } else if len(dst) != t.Len() { panic("fourier: destination length mismatch") } copy(dst, src) fftpack.Cost(len(dst), dst, t.work, t.ifac[:]) return dst } // DST implements Discrete Sine Transform for real sequences. type DST struct { work []float64 ifac [15]int } // NewDST returns a DST initialized for work on sequences of length n. func NewDST(n int) *DST { var t DST t.Reset(n) return &t } // Len returns the length of the acceptable input. func (t *DST) Len() int { return (2*len(t.work)+1)/5 - 1 } // Reset reinitializes the DCT for work on sequences of length n. func (t *DST) Reset(n int) { if 5*(n+1)/2 <= cap(t.work) { t.work = t.work[:5*(n+1)/2] } else { t.work = make([]float64, 5*(n+1)/2) } fftpack.Sinti(n, t.work, t.ifac[:]) } // Transform computes the Discrete Fourier Sine Transform of the input // data, src, placing the result in dst and returning it. // This transform is unnormalized; a call to Transform followed by // another call to Transform will multiply the input sequence by 2*(n-1), // where n is the length of the sequence. // // If the length of src is not t.Len(), Transform will panic. // If dst is nil, a new slice is allocated and returned. If dst is not nil and // the length of dst does not equal t.Len(), FFT will panic. // It is safe to use the same slice for dst and src. func (t *DST) Transform(dst, src []float64) []float64 { if len(src) != t.Len() { panic("fourier: sequence length mismatch") } if dst == nil { dst = make([]float64, t.Len()) } else if len(dst) != t.Len() { panic("fourier: destination length mismatch") } copy(dst, src) fftpack.Sint(len(dst), dst, t.work, t.ifac[:]) return dst } golang-gonum-v1-gonum-0.14.0/dsp/window/000077500000000000000000000000001450372207100177335ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/dsp/window/cmd/000077500000000000000000000000001450372207100204765ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/dsp/window/cmd/leakage/000077500000000000000000000000001450372207100220675ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/dsp/window/cmd/leakage/leakage.go000066400000000000000000000255321450372207100240160ustar00rootroot00000000000000// Copyright ©2021 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. // The leakage program provides summary characteristics and a plot // of spectral response for window functions or csv input. It is intended // to be used to verify window behaviour against foreign implementations. // For example, the behavior of a NumPy window can be captured using this // python code: // // import matplotlib.pyplot as plt // import numpy as np // from numpy.fft import fft // // window = np.blackman(20) // print("# beta = %f" % np.mean(window)) // // plt.figure() // // A = fft(window, 1000) // mag = np.abs(A) // with np.errstate(divide='ignore', invalid='ignore'): // mag = 20 * np.log10(mag) // mag -= max(mag) // freq = np.linspace(0, len(window)/2, len(A)/2) // // for m in mag[:len(mag)/2]: // print(m) // // plt.plot(freq, mag[:len(mag)/2]) // plt.title("Spectral leakage") // plt.ylabel("Amplitude (dB)") // plt.xlabel("DFT bin") // // plt.show() // // and then be exported to leakage and compared with the Gonum // implementation. package main import ( "bufio" "flag" "fmt" "image/color" "io" "log" "math" "math/cmplx" "os" "strconv" "strings" "gonum.org/v1/gonum/dsp/fourier" "gonum.org/v1/gonum/dsp/window" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/stat" "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" ) var windows = map[string]*builtin{ "rectangular": { name: func(_ float64) string { return "Rectangular" }, fn: func(_ float64) func([]float64) []float64 { return window.Rectangular }, ok: func(_ float64) bool { return true }, }, "sine": { name: func(_ float64) string { return "Sine" }, fn: func(_ float64) func([]float64) []float64 { return window.Sine }, ok: func(_ float64) bool { return true }, }, "lanczos": { name: func(_ float64) string { return "Lanczos" }, fn: func(_ float64) func([]float64) []float64 { return window.Lanczos }, ok: func(_ float64) bool { return true }, }, "triangular": { name: func(_ float64) string { return "Triangular" }, fn: func(_ float64) func([]float64) []float64 { return window.Triangular }, ok: func(_ float64) bool { return true }, }, "hann": { name: func(_ float64) string { return "Hann" }, fn: func(_ float64) func([]float64) []float64 { return window.Hann }, ok: func(_ float64) bool { return true }, }, "bartletthann": { name: func(_ float64) string { return "BartlettHann" }, fn: func(_ float64) func([]float64) []float64 { return window.BartlettHann }, ok: func(_ float64) bool { return true }, }, "hamming": { name: func(_ float64) string { return "Hamming" }, fn: func(_ float64) func([]float64) []float64 { return window.Hamming }, ok: func(_ float64) bool { return true }, }, "blackman": { name: func(_ float64) string { return "Blackman" }, fn: func(_ float64) func([]float64) []float64 { return window.Blackman }, ok: func(_ float64) bool { return true }, }, "blackmanharris": { name: func(_ float64) string { return "BlackmanHarris" }, fn: func(_ float64) func([]float64) []float64 { return window.BlackmanHarris }, ok: func(_ float64) bool { return true }, }, "nuttall": { name: func(_ float64) string { return "Nuttall" }, fn: func(_ float64) func([]float64) []float64 { return window.Nuttall }, ok: func(_ float64) bool { return true }, }, "blackmannuttall": { name: func(_ float64) string { return "BlackmanNuttall" }, fn: func(_ float64) func([]float64) []float64 { return window.BlackmanNuttall }, ok: func(_ float64) bool { return true }, }, "flattop": { name: func(_ float64) string { return "FlatTop" }, fn: func(_ float64) func([]float64) []float64 { return window.FlatTop }, ok: func(_ float64) bool { return true }, }, "gaussian": { name: func(p float64) string { return fmt.Sprintf("Gaussian σ=%v", p) }, fn: func(p float64) func([]float64) []float64 { return window.Gaussian{Sigma: p}.Transform }, ok: func(p float64) bool { return !math.IsNaN(p) }, }, "tukey": { name: func(p float64) string { return fmt.Sprintf("Tukey α=%v", p) }, fn: func(p float64) func([]float64) []float64 { return window.Tukey{Alpha: p}.Transform }, ok: func(p float64) bool { return !math.IsNaN(p) }, }, } type builtin struct { name func(float64) string fn func(float64) func([]float64) []float64 ok func(float64) bool } func main() { name := flag.String("window", "", "specify a built-in window name (required if csv not given)") param := flag.Float64("param", math.NaN(), "specify parameter for parametric windows") symm := flag.Bool("symm", true, "specify whether the window is symmetric") n := flag.Int("n", 20, "specify window length") m := flag.Int("m", 1000, "specify sample length (must be greater than n)") csv := flag.String("csv", "", "specify an input file of dB transformed frequency amplitudes (required if window not given)") out := flag.String("o", "", "specify output file for plot (required, formats eps, jpg, jpeg, pdf, png, svg, tex or tif)") width := flag.Float64("width", 16, "specify plot width (cm)") height := flag.Float64("height", 8, "specify plot height (cm)") comment := flag.Bool("comment", false, "output a comment line for the window (only for window function)") flag.Parse() win := windows[strings.ToLower(*name)] if win == nil && *csv == "" { fmt.Fprintln(os.Stderr, "missing function name or csv input") flag.Usage() os.Exit(2) } if *csv == "" && !win.ok(*param) { fmt.Fprintln(os.Stderr, "missing parameter") flag.Usage() os.Exit(2) } if *out == "" { fmt.Fprintln(os.Stderr, "missing output filename") flag.Usage() os.Exit(2) } p := plot.New() p.X.Label.Text = "DFT bin" p.Y.Label.Text = "Amplitude [dB]" p.Add(plotter.NewGrid()) var ( c *characteristics spectrum plotter.XYs min float64 err error ) if win != nil { symmetry := "(symmetric)" if !*symm { symmetry = "(periodic)" } p.Title.Text = fmt.Sprintf("Spectral Leakage for %s %s", win.name(*param), symmetry) c, spectrum, min, err = funcCharacteristics(win.fn(*param), *n, *m, *symm) if err != nil { log.Fatal(err) } if *comment { fmt.Printf("// Spectral leakage parameters: ΔF_0 = %2f, ΔF_0.5 = %.2f, K = %.2f, ɣ_max = %2f, β = %2f.\n", c.deltaF0, c.deltaFhalf, c.k(), c.gammaMax, c.beta) } } else { f, err := os.Open(*csv) if err != nil { log.Fatal(err) } defer f.Close() p.Title.Text = fmt.Sprintf("Spectral Leakage for %s", *csv) c, spectrum, min, err = csvCharacteristics(f, *n, *m) if err != nil { log.Fatal(err) } } spectrumLines, err := plotter.NewLine(spectrum) if err != nil { log.Fatalf("spectrum: %v", err) } gammaLine, err := plotter.NewLine(plotter.XYs{ {X: 0, Y: c.gammaMax}, {X: float64(*n) / 2, Y: c.gammaMax}, }) if err != nil { log.Fatalf("ɣ_max: %v", err) } gammaLine.Color = color.RGBA{R: 0x40, G: 0x80, B: 0xff, A: 0xff} deltaF0Line, err := plotter.NewLine(plotter.XYs{ {X: c.deltaF0 / 2, Y: 0}, {X: c.deltaF0 / 2, Y: min}, }) if err != nil { log.Fatalf("ΔF_0: %v", err) } deltaF0Line.Color = color.RGBA{R: 0xff, A: 0xff} deltaFhalfLine, err := plotter.NewLine(plotter.XYs{ {X: c.deltaFhalf / 2, Y: 0}, {X: c.deltaFhalf / 2, Y: min}, }) if err != nil { log.Fatalf("ΔF_0.5: %v", err) } deltaFhalfLine.Color = color.RGBA{G: 0xff, A: 0xff} var blank plotter.Line p.Add( gammaLine, deltaF0Line, deltaFhalfLine, spectrumLines, ) p.Legend.Add(fmt.Sprintf("ΔF_0 = %.3v", c.deltaF0), deltaF0Line) p.Legend.Add(fmt.Sprintf("ΔF_0.5 = %.3v", c.deltaFhalf), deltaFhalfLine) p.Legend.Add(fmt.Sprintf("K = %.3v", c.k()), &blank) p.Legend.Add(fmt.Sprintf("ɣ_max = %.3v", c.gammaMax), gammaLine) p.Legend.Add(fmt.Sprintf("β = %.3v", c.beta), &blank) p.Legend.Top = true p.Legend.XOffs = -10 p.Legend.YOffs = -10 err = p.Save(vg.Length(*width)*vg.Centimeter, vg.Length(*height)*vg.Centimeter, *out) if err != nil { log.Fatal(err) } } // characteristics hold DFT window characteristic statistics. // See http://www.dsplib.ru/content/win/win.html for details. type characteristics struct { deltaF0 float64 deltaFhalf float64 gammaMax float64 beta float64 } // k returns the K window parameter which is the ratio of the window's // ΔF_0 to the ΔF_0 of the rectangular window. func (c *characteristics) k() float64 { return c.deltaF0 / 2 } func funcCharacteristics(fn func([]float64) []float64, n, m int, symm bool) (c *characteristics, xy plotter.XYs, min float64, err error) { if m < n { return nil, nil, 0, fmt.Errorf("window: sequence too short for window: %d < %d", m, n) } var w []float64 t := make([]float64, m) if symm { w = window.NewValues(fn, n) } else { w = window.NewValues(fn, n+1)[:n] } copy(t, w) var max float64 xy = make(plotter.XYs, m/2+1) fft := fourier.NewFFT(len(t)) for i, c := range fft.Coefficients(nil, t) { a := db(cmplx.Abs(c)) t[i] = a if !math.IsInf(a, -1) && a < min { min = a } if i == 0 { max = a } } for i, a := range t[:m/2+1] { if math.IsInf(a, -1) { a = min } xy[i] = plotter.XY{X: float64(i) * float64(n) / float64(m), Y: a - max} } c = &characteristics{beta: db(stat.Mean(w, nil))} c.deltaF0, c.deltaFhalf, c.gammaMax = parameters(t, n, m) return c, xy, min - max, nil } func csvCharacteristics(r io.Reader, n, m int) (c *characteristics, xy plotter.XYs, min float64, err error) { if m < n { return nil, nil, 0, fmt.Errorf("window: sequence too short for window: %d < %d", m, n) } sc := bufio.NewScanner(r) max := math.Inf(-1) var t []float64 for sc.Scan() { text := sc.Text() if strings.HasPrefix(text, "#") { continue } v, err := strconv.ParseFloat(text, 64) if err != nil { log.Fatal(err) } if v > max { max = v } t = append(t, v) } xy = make(plotter.XYs, len(t)) for i, a := range t { if math.IsInf(a, -1) { a = min } else if a < min { min = a } if i == 0 { max = a } xy[i] = plotter.XY{X: float64(i) * float64(n) / float64(m), Y: a - max} } err = sc.Err() if err != nil { return nil, nil, 0, err } c = &characteristics{beta: math.NaN()} c.deltaF0, c.deltaFhalf, c.gammaMax = parameters(t, n, m) return c, xy, min - max, nil } func parameters(spectrum []float64, n, m int) (deltaF0, deltaFhalf, gammaMax float64) { max := spectrum[0] var peaks []float64 for i, r := range spectrum { if i > 1 { if spectrum[i-1] < r && deltaF0 == 0 { deltaF0 = 2 * float64((i-1)*n) / float64(m) } if thresh := max - 3; thresh < spectrum[i-1] && r <= thresh { deltaFhalf = 2 * float64((i-1)*n) / float64(m) } } if i > 2 && spectrum[i-2] <= spectrum[i-1] && spectrum[i-1] > r { peaks = append(peaks, spectrum[i-1]) } } if len(peaks) == 0 { gammaMax = math.NaN() } else { gammaMax = floats.Max(peaks) - max } return deltaF0, deltaFhalf, gammaMax } func db(m float64) float64 { return 20 * math.Log10(m) } golang-gonum-v1-gonum-0.14.0/dsp/window/doc.go000066400000000000000000000042151450372207100210310ustar00rootroot00000000000000// Copyright ©2020 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 window provides a set of functions to perform the transformation // of sequence by different window functions. // // Window functions can be used to control spectral leakage parameters // when performing a Fourier transform on a signal of limited length. // See https://en.wikipedia.org/wiki/Window_function for more details. // // # Spectral leakage parameters // // Application of window functions to an input will result in changes // to the frequency content of the signal in an effect called spectral // leakage. See https://en.wikipedia.org/wiki/Spectral_leakage. // // The characteristic changes associated with each window function may // be described using a set of spectral leakage parameters; β, ΔF_0, ΔF_0.5, // K and ɣ_max. // // The β, attenuation, coefficient of a window is the ratio of the // constant component of the spectrum resulting from use of the window // compared to that produced using the rectangular window, expressed in // a logarithmic scale. // // β_w = 20 log10(A_w / A_rect) dB // // The ΔF_0 parameter describes the normalized width of the main lobe of // the frequency spectrum at zero amplitude. // // The ΔF_0.5 parameter describes the normalized width of the main lobe of // the frequency spectrum at -3 dB (half maximum amplitude). // // The K parameter describes the relative width of the main lobe of the // frequency spectrum produced by the window compared with the rectangular // window. The rectangular window has the lowest ΔF_0 at a value of 2. // // K_w = ΔF_0_w/ΔF_0_rect. // // The value of K divides windows into high resolution windows (K≤3) and // low resolution windows (K>3). // // The ɣ_max parameter is the maximum level of the side lobes of the // normalized spectrum, in decibels. package window // import "gonum.org/v1/gonum/dsp/window" // The article at http://www.dsplib.ru/content/win/win.html is the origin // of much of the information used in this package. It is in Russian, but // Google translate does a pretty good job with it. golang-gonum-v1-gonum-0.14.0/dsp/window/window.go000066400000000000000000000227001450372207100215720ustar00rootroot00000000000000// Copyright ©2020 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 window import "math" // Rectangular modifies seq in place by the Rectangular window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Rectangular_window and // https://www.recordingblogs.com/wiki/rectangular-window for details. // // The rectangular window has the lowest width of the main lobe and largest // level of the side lobes. The result corresponds to a selection of // limited length sequence of values without any modification. // // The sequence weights are // // w[k] = 1, // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 2, ΔF_0.5 = 0.89, K = 1, ɣ_max = -13, β = 0. func Rectangular(seq []float64) []float64 { return seq } // Sine modifies seq in place by the Sine window and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Sine_window and // https://www.recordingblogs.com/wiki/sine-window for details. // // Sine window is a high-resolution window. // // The sequence weights are // // w[k] = sin(π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 3, ΔF_0.5 = 1.23, K = 1.5, ɣ_max = -23, β = -3.93. func Sine(seq []float64) []float64 { k := math.Pi / float64(len(seq)-1) for i := range seq { seq[i] *= math.Sin(k * float64(i)) } return seq } // Lanczos modifies seq in place by the Lanczos window and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Lanczos_window and // https://www.recordingblogs.com/wiki/lanczos-window for details. // // The Lanczos window is a high-resolution window. // // The sequence weights are // // w[k] = sinc(2*k/(N-1) - 1), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 3.24, ΔF_0.5 = 1.3, K = 1.62, ɣ_max = -26.4, β = -4.6. func Lanczos(seq []float64) []float64 { k := 2 / float64(len(seq)-1) for i := range seq { x := math.Pi * (k*float64(i) - 1) if x == 0 { // Avoid NaN. continue } seq[i] *= math.Sin(x) / x } return seq } // Triangular modifies seq in place by the Triangular window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Triangular_window and // https://www.recordingblogs.com/wiki/triangular-window for details. // // The Triangular window is a high-resolution window. // // The sequence weights are // // w[k] = 1 - |k/A -1|, A=(N-1)/2, // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.33, K = 2, ɣ_max = -26.5, β = -6. func Triangular(seq []float64) []float64 { a := float64(len(seq)-1) / 2 for i := range seq { seq[i] *= 1 - math.Abs(float64(i)/a-1) } return seq } // Hann modifies seq in place by the Hann window and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows // and https://www.recordingblogs.com/wiki/hann-window for details. // // The Hann window is a high-resolution window. // // The sequence weights are // // w[k] = 0.5*(1 - cos(2*π*k/(N-1))), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.5, K = 2, ɣ_max = -31.5, β = -6. func Hann(seq []float64) []float64 { k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { seq[i] *= 0.5 * (1 - math.Cos(k*float64(i))) } return seq } // BartlettHann modifies seq in place by the Bartlett-Hann window and returns // result. // See https://en.wikipedia.org/wiki/Window_function#Bartlett%E2%80%93Hann_window // and https://www.recordingblogs.com/wiki/bartlett-hann-window for details. // // The Bartlett-Hann window is a high-resolution window. // // The sequence weights are // // w[k] = 0.62 - 0.48*|k/(N-1)-0.5| - 0.38*cos(2*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.45, K = 2, ɣ_max = -35.9, β = -6. func BartlettHann(seq []float64) []float64 { const ( a0 = 0.62 a1 = 0.48 a2 = 0.38 ) k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { seq[i] *= a0 - a1*math.Abs(float64(i)/float64(len(seq)-1)-0.5) - a2*math.Cos(k*float64(i)) } return seq } // Hamming modifies seq in place by the Hamming window and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows // and https://www.recordingblogs.com/wiki/hamming-window for details. // // The Hamming window is a high-resolution window. Among K=2 windows it has // the highest ɣ_max. // // The sequence weights are // // w[k] = 25/46 - 21/46 * cos(2*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.33, K = 2, ɣ_max = -42, β = -5.37. func Hamming(seq []float64) []float64 { const ( a0 = 0.54 a1 = 0.46 ) k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { seq[i] *= a0 - a1*math.Cos(k*float64(i)) } return seq } // Blackman modifies seq in place by the Blackman window and returns the // result. // See https://en.wikipedia.org/wiki/Window_function#Blackman_window and // https://www.recordingblogs.com/wiki/blackman-window for details. // // The Blackman window is a high-resolution window. // // The sequence weights are // // w[k] = 0.42 - 0.5*cos(2*π*k/(N-1)) + 0.08*cos(4*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 6, ΔF_0.5 = 1.7, K = 3, ɣ_max = -58, β = -7.54. func Blackman(seq []float64) []float64 { const ( a0 = 0.42 a1 = 0.5 a2 = 0.08 ) k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { x := k * float64(i) seq[i] *= a0 - a1*math.Cos(x) + a2*math.Cos(2*x) } return seq } // BlackmanHarris modifies seq in place by the Blackman-Harris window and // returns the result. // See https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Harris_window // and https://www.recordingblogs.com/wiki/blackman-harris-window for details. // // The Blackman-Harris window is a low-resolution window. // // The sequence weights are // // w[k] = 0.35875 - 0.48829*cos(2*π*k/(N-1)) + // 0.14128*cos(4*π*k/(N-1)) - 0.01168*cos(6*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 8, ΔF_0.5 = 1.97, K = 4, ɣ_max = -92, β = -8.91. func BlackmanHarris(seq []float64) []float64 { const ( a0 = 0.35875 a1 = 0.48829 a2 = 0.14128 a3 = 0.01168 ) k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { x := k * float64(i) seq[i] *= a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) } return seq } // Nuttall modifies seq in place by the Nuttall window and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Nuttall_window,_continuous_first_derivative // and https://www.recordingblogs.com/wiki/nuttall-window for details. // // The Nuttall window is a low-resolution window. // // The sequence weights are // // w[k] = 0.355768 - 0.487396*cos(2*π*k/(N-1)) + 0.144232*cos(4*π*k/(N-1)) - // 0.012604*cos(6*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 8, ΔF_0.5 = 1.98, K = 4, ɣ_max = -93, β = -9. func Nuttall(seq []float64) []float64 { const ( a0 = 0.355768 a1 = 0.487396 a2 = 0.144232 a3 = 0.012604 ) k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { x := k * float64(i) seq[i] *= a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) } return seq } // BlackmanNuttall modifies seq in place by the Blackman-Nuttall window and // returns the result. // See https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Nuttall_window // and https://www.recordingblogs.com/wiki/blackman-nuttall-window for details. // // The Blackman-Nuttall window is a low-resolution window. // // The sequence weights are // // w[k] = 0.3635819 - 0.4891775*cos(2*π*k/(N-1)) + 0.1365995*cos(4*π*k/(N-1)) - // 0.0106411*cos(6*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 8, ΔF_0.5 = 1.94, K = 4, ɣ_max = -98, β = -8.8. func BlackmanNuttall(seq []float64) []float64 { const ( a0 = 0.3635819 a1 = 0.4891775 a2 = 0.1365995 a3 = 0.0106411 ) k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { x := k * float64(i) seq[i] *= a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) } return seq } // FlatTop modifies seq in place by the Flat Top window and returns the // result. // See https://en.wikipedia.org/wiki/Window_function#Flat_top_window and // https://www.recordingblogs.com/wiki/flat-top-window for details. // // The Flat Top window is a low-resolution window. // // The sequence weights are // // w[k] = 0.21557895 - 0.41663158*cos(2*π*k/(N-1)) + // 0.277263158*cos(4*π*k/(N-1)) - 0.083578947*cos(6*π*k/(N-1)) + // 0.006947368*cos(4*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 10, ΔF_0.5 = 3.72, K = 5, ɣ_max = -93.0, β = -13.34. func FlatTop(seq []float64) []float64 { const ( a0 = 0.21557895 a1 = 0.41663158 a2 = 0.277263158 a3 = 0.083578947 a4 = 0.006947368 ) k := 2 * math.Pi / float64(len(seq)-1) for i := range seq { x := k * float64(i) seq[i] *= a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) + a4*math.Cos(4*x) } return seq } golang-gonum-v1-gonum-0.14.0/dsp/window/window_complex.go000066400000000000000000000241421450372207100233230ustar00rootroot00000000000000// Copyright ©2020 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 window import "math" // Rectangular modifies seq in place by the Rectangular window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Rectangular_window and // https://www.recordingblogs.com/wiki/rectangular-window for details. // // The rectangular window has the lowest width of the main lobe and largest // level of the side lobes. The result corresponds to a selection of // limited length sequence of values without any modification. // // The sequence weights are // // w[k] = 1, // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 2, ΔF_0.5 = 0.89, K = 1, ɣ_max = -13, β = 0. func RectangularComplex(seq []complex128) []complex128 { return seq } // SineComplex modifies seq in place by the Sine window and returns the // result. // See https://en.wikipedia.org/wiki/Window_function#Sine_window and // https://www.recordingblogs.com/wiki/sine-window for details. // // Sine window is a high-resolution window. // // The sequence weights are // // w[k] = sin(π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 3, ΔF_0.5 = 1.23, K = 1.5, ɣ_max = -23, β = -3.93. func SineComplex(seq []complex128) []complex128 { k := math.Pi / float64(len(seq)-1) for i, v := range seq { w := math.Sin(k * float64(i)) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // LanczosComplex modifies seq in place by the Lanczos window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Lanczos_window and // https://www.recordingblogs.com/wiki/lanczos-window for details. // // The Lanczos window is a high-resolution window. // // The sequence weights are // // w[k] = sinc(2*k/(N-1) - 1), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 3.24, ΔF_0.5 = 1.3, K = 1.62, ɣ_max = -26.4, β = -4.6. func LanczosComplex(seq []complex128) []complex128 { k := 2 / float64(len(seq)-1) for i, v := range seq { x := math.Pi * (k*float64(i) - 1) if x == 0 { // Avoid NaN. continue } w := math.Sin(x) / x seq[i] = complex(w*real(v), w*imag(v)) } return seq } // TriangularComplex modifies seq in place by the Triangular window and // returns the result. // See https://en.wikipedia.org/wiki/Window_function#Triangular_window and // https://www.recordingblogs.com/wiki/triangular-window for details. // // The Triangular window is a high-resolution window. // // The sequence weights are // // w[k] = 1 - |k/A -1|, A=(N-1)/2, // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.33, K = 2, ɣ_max = -26.5, β = -6. func TriangularComplex(seq []complex128) []complex128 { a := float64(len(seq)-1) / 2 for i, v := range seq { w := 1 - math.Abs(float64(i)/a-1) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // HannComplex modifies seq in place by the Hann window and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows // and https://www.recordingblogs.com/wiki/hann-window for details. // // The Hann window is a high-resolution window. // // The sequence weights are // // w[k] = 0.5*(1 - cos(2*π*k/(N-1))), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.5, K = 2, ɣ_max = -31.5, β = -6. func HannComplex(seq []complex128) []complex128 { k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { w := 0.5 * (1 - math.Cos(k*float64(i))) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // BartlettHannComplex modifies seq in place by the Bartlett-Hann window // and returns result. // See https://en.wikipedia.org/wiki/Window_function#Bartlett%E2%80%93Hann_window // and https://www.recordingblogs.com/wiki/bartlett-hann-window for details. // // The Bartlett-Hann window is a high-resolution window. // // The sequence weights are // // w[k] = 0.62 - 0.48*|k/(N-1)-0.5| - 0.38*cos(2*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.45, K = 2, ɣ_max = -35.9, β = -6. func BartlettHannComplex(seq []complex128) []complex128 { const ( a0 = 0.62 a1 = 0.48 a2 = 0.38 ) k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { w := a0 - a1*math.Abs(float64(i)/float64(len(seq)-1)-0.5) - a2*math.Cos(k*float64(i)) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // HammingComplex modifies seq in place by the Hamming window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows // and https://www.recordingblogs.com/wiki/hamming-window for details. // // The Hamming window is a high-resolution window. Among K=2 windows it has // the highest ɣ_max. // // The sequence weights are // // w[k] = 25/46 - 21/46 * cos(2*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 4, ΔF_0.5 = 1.33, K = 2, ɣ_max = -42, β = -5.37. func HammingComplex(seq []complex128) []complex128 { const ( a0 = 0.54 a1 = 0.46 ) k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { w := a0 - a1*math.Cos(k*float64(i)) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // BlackmanComplex modifies seq in place by the Blackman window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Blackman_window and // https://www.recordingblogs.com/wiki/blackman-window for details. // // The Blackman window is a high-resolution window. // // The sequence weights are // // w[k] = 0.42 - 0.5*cos(2*π*k/(N-1)) + 0.08*cos(4*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 6, ΔF_0.5 = 1.7, K = 3, ɣ_max = -58, β = -7.54. func BlackmanComplex(seq []complex128) []complex128 { const ( a0 = 0.42 a1 = 0.5 a2 = 0.08 ) k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { x := k * float64(i) w := a0 - a1*math.Cos(x) + a2*math.Cos(2*x) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // BlackmanHarrisComplex modifies seq in place by the Blackman-Harris window // and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Harris_window // and https://www.recordingblogs.com/wiki/blackman-harris-window for details. // // The Blackman-Harris window is a low-resolution window. // // The sequence weights are // // w[k] = 0.35875 - 0.48829*cos(2*π*k/(N-1)) + // 0.14128*cos(4*π*k/(N-1)) - 0.01168*cos(6*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 8, ΔF_0.5 = 1.97, K = 4, ɣ_max = -92, β = -8.91. func BlackmanHarrisComplex(seq []complex128) []complex128 { const ( a0 = 0.35875 a1 = 0.48829 a2 = 0.14128 a3 = 0.01168 ) k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { x := k * float64(i) w := a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // NuttallComplex modifies seq in place by the Nuttall window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Nuttall_window,_continuous_first_derivative // and https://www.recordingblogs.com/wiki/nuttall-window for details. // // The Nuttall window is a low-resolution window. // // The sequence weights are // // w[k] = 0.355768 - 0.487396*cos(2*π*k/(N-1)) + 0.144232*cos(4*π*k/(N-1)) - // 0.012604*cos(6*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 8, ΔF_0.5 = 1.98, K = 4, ɣ_max = -93, β = -9. func NuttallComplex(seq []complex128) []complex128 { const ( a0 = 0.355768 a1 = 0.487396 a2 = 0.144232 a3 = 0.012604 ) k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { x := k * float64(i) w := a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // BlackmanNuttallComplex modifies seq in place by the Blackman-Nuttall // window and returns the result. // See https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Nuttall_window // and https://www.recordingblogs.com/wiki/blackman-nuttall-window for details. // // The Blackman-Nuttall window is a low-resolution window. // // The sequence weights are // // w[k] = 0.3635819 - 0.4891775*cos(2*π*k/(N-1)) + 0.1365995*cos(4*π*k/(N-1)) - // 0.0106411*cos(6*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 8, ΔF_0.5 = 1.94, K = 4, ɣ_max = -98, β = -8.8. func BlackmanNuttallComplex(seq []complex128) []complex128 { const ( a0 = 0.3635819 a1 = 0.4891775 a2 = 0.1365995 a3 = 0.0106411 ) k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { x := k * float64(i) w := a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // FlatTopComplex modifies seq in place by the Flat Top window and returns // the result. // See https://en.wikipedia.org/wiki/Window_function#Flat_top_window and // https://www.recordingblogs.com/wiki/flat-top-window for details. // // The Flat Top window is a low-resolution window. // // The sequence weights are // // w[k] = 0.21557895 - 0.41663158*cos(2*π*k/(N-1)) + // 0.277263158*cos(4*π*k/(N-1)) - 0.083578947*cos(6*π*k/(N-1)) + // 0.006947368*cos(4*π*k/(N-1)), // // for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters: ΔF_0 = 10, ΔF_0.5 = 3.72, K = 5, ɣ_max = -93.0, β = -13.34. func FlatTopComplex(seq []complex128) []complex128 { const ( a0 = 0.21557895 a1 = 0.41663158 a2 = 0.277263158 a3 = 0.083578947 a4 = 0.006947368 ) k := 2 * math.Pi / float64(len(seq)-1) for i, v := range seq { x := k * float64(i) w := a0 - a1*math.Cos(x) + a2*math.Cos(2*x) - a3*math.Cos(3*x) + a4*math.Cos(4*x) seq[i] = complex(w*real(v), w*imag(v)) } return seq } golang-gonum-v1-gonum-0.14.0/dsp/window/window_example_test.go000066400000000000000000000152651450372207100243540ustar00rootroot00000000000000// Copyright ©2020 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 window_test import ( "fmt" "math" "math/cmplx" "gonum.org/v1/gonum/dsp/fourier" "gonum.org/v1/gonum/dsp/window" ) func Example() { // The input sequence is a 2.5 period of the Sin function. src := make([]float64, 20) k := 5 * math.Pi / float64(len(src)-1) for i := range src { src[i] = math.Sin(k * float64(i)) } // Initialize an FFT and perform the analysis. fft := fourier.NewFFT(len(src)) coeff := fft.Coefficients(nil, src) // The result shows that width of the main lobe with center // between frequencies 0.1 and 0.15 is small, but that the // height of the side lobes is large. fmt.Println("Rectangular window (or no window):") for i, c := range coeff { fmt.Printf("freq=%.4f\tcycles/period, magnitude=%.4f,\tphase=%.4f\n", fft.Freq(i), cmplx.Abs(c), cmplx.Phase(c)) } // Initialize an FFT and perform the analysis on a sequence // transformed by the Hamming window function. fft = fourier.NewFFT(len(src)) coeff = fft.Coefficients(nil, window.Hamming(src)) // The result shows that width of the main lobe is wider, // but height of the side lobes is lower. fmt.Println("Hamming window:") // The magnitude of all bins has been decreased by β. // Generally in an analysis amplification may be omitted, but to // make a comparable data, the result should be amplified by -β // of the window function — +5.37 dB for the Hamming window. // -β = 20 log_10(amplifier). amplifier := math.Pow(10, 5.37/20.0) for i, c := range coeff { fmt.Printf("freq=%.4f\tcycles/period, magnitude=%.4f,\tphase=%.4f\n", fft.Freq(i), amplifier*cmplx.Abs(c), cmplx.Phase(c)) } // Output: // // Rectangular window (or no window): // freq=0.0000 cycles/period, magnitude=2.2798, phase=0.0000 // freq=0.0500 cycles/period, magnitude=2.6542, phase=0.1571 // freq=0.1000 cycles/period, magnitude=5.3115, phase=0.3142 // freq=0.1500 cycles/period, magnitude=7.3247, phase=-2.6704 // freq=0.2000 cycles/period, magnitude=1.6163, phase=-2.5133 // freq=0.2500 cycles/period, magnitude=0.7681, phase=-2.3562 // freq=0.3000 cycles/period, magnitude=0.4385, phase=-2.1991 // freq=0.3500 cycles/period, magnitude=0.2640, phase=-2.0420 // freq=0.4000 cycles/period, magnitude=0.1530, phase=-1.8850 // freq=0.4500 cycles/period, magnitude=0.0707, phase=-1.7279 // freq=0.5000 cycles/period, magnitude=0.0000, phase=0.0000 // Hamming window: // freq=0.0000 cycles/period, magnitude=0.0542, phase=3.1416 // freq=0.0500 cycles/period, magnitude=0.8458, phase=-2.9845 // freq=0.1000 cycles/period, magnitude=7.1519, phase=0.3142 // freq=0.1500 cycles/period, magnitude=8.5907, phase=-2.6704 // freq=0.2000 cycles/period, magnitude=2.0804, phase=0.6283 // freq=0.2500 cycles/period, magnitude=0.0816, phase=0.7854 // freq=0.3000 cycles/period, magnitude=0.0156, phase=-2.1991 // freq=0.3500 cycles/period, magnitude=0.0224, phase=-2.0420 // freq=0.4000 cycles/period, magnitude=0.0163, phase=-1.8850 // freq=0.4500 cycles/period, magnitude=0.0083, phase=-1.7279 // freq=0.5000 cycles/period, magnitude=0.0000, phase=0.0000 } func ExampleHamming() { src := []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} // Window functions change data in place. So, if input data // needs to stay unchanged, it must be copied. srcCpy := append([]float64(nil), src...) // Apply window function to srcCpy. dst := window.Hamming(srcCpy) // src is unchanged. fmt.Printf("src: %f\n", src) // srcCpy is altered. fmt.Printf("srcCpy: %f\n", srcCpy) // dst mirrors the srcCpy slice. fmt.Printf("dst: %f\n", dst) // Output: // // src: [1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000] // srcCpy: [0.080000 0.104924 0.176995 0.288404 0.427077 0.577986 0.724780 0.851550 0.944558 0.993726 0.993726 0.944558 0.851550 0.724780 0.577986 0.427077 0.288404 0.176995 0.104924 0.080000] // dst: [0.080000 0.104924 0.176995 0.288404 0.427077 0.577986 0.724780 0.851550 0.944558 0.993726 0.993726 0.944558 0.851550 0.724780 0.577986 0.427077 0.288404 0.176995 0.104924 0.080000] } func ExampleValues() { src := []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} // Create a Sine Window lookup table. sine := window.NewValues(window.Sine, len(src)) // Apply the transformation to the src. fmt.Printf("dst: %f\n", sine.Transform(src)) // Output: // // dst: [0.000000 0.164595 0.324699 0.475947 0.614213 0.735724 0.837166 0.915773 0.969400 0.996584 0.996584 0.969400 0.915773 0.837166 0.735724 0.614213 0.475947 0.324699 0.164595 0.000000] } func ExampleValues_TransformTo_gabor() { src := []float64{1, 2, 1, 0, -1, -1, -2, -2, -1, -1, 0, 1, 1, 2, 1, 0, -1, -2, -1, 0} // Create a Gaussian Window lookup table for 4 samples. gaussian := window.NewValues(window.Gaussian{0.5}.Transform, 4) // Prepare a destination. dst := make([]float64, 8) // Apply the transformation to the src, placing it in dst. for i := 0; i < len(src)-len(gaussian); i++ { gaussian.TransformTo(dst[0:len(gaussian)], src[i:i+len(gaussian)]) // To perform the Gabor transform, we would calculate // the FFT on dst for each iteration. fmt.Printf("FFT(%f)\n", dst) } // Output: // // FFT([0.135335 1.601475 0.800737 0.000000 0.000000 0.000000 0.000000 0.000000]) // FFT([0.270671 0.800737 0.000000 -0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([0.135335 0.000000 -0.800737 -0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([0.000000 -0.800737 -0.800737 -0.270671 0.000000 0.000000 0.000000 0.000000]) // FFT([-0.135335 -0.800737 -1.601475 -0.270671 0.000000 0.000000 0.000000 0.000000]) // FFT([-0.135335 -1.601475 -1.601475 -0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([-0.270671 -1.601475 -0.800737 -0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([-0.270671 -0.800737 -0.800737 0.000000 0.000000 0.000000 0.000000 0.000000]) // FFT([-0.135335 -0.800737 0.000000 0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([-0.135335 0.000000 0.800737 0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([0.000000 0.800737 0.800737 0.270671 0.000000 0.000000 0.000000 0.000000]) // FFT([0.135335 0.800737 1.601475 0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([0.135335 1.601475 0.800737 0.000000 0.000000 0.000000 0.000000 0.000000]) // FFT([0.270671 0.800737 0.000000 -0.135335 0.000000 0.000000 0.000000 0.000000]) // FFT([0.135335 0.000000 -0.800737 -0.270671 0.000000 0.000000 0.000000 0.000000]) // FFT([0.000000 -0.800737 -1.601475 -0.135335 0.000000 0.000000 0.000000 0.000000]) } golang-gonum-v1-gonum-0.14.0/dsp/window/window_parametric.go000066400000000000000000000136551450372207100240120ustar00rootroot00000000000000// Copyright ©2020 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 window import "math" // Gaussian can modify a sequence using the Gaussian window and return the // result. // See https://en.wikipedia.org/wiki/Window_function#Gaussian_window // and https://www.recordingblogs.com/wiki/gaussian-window for details. // // The Gaussian window is an adjustable window. // // The sequence weights are // // w[k] = exp(-0.5 * ((k-M)/(σ*M))² ), M = (N-1)/2, // // for k=0,1,...,N-1 where N is the length of the window. // // The properties of the window depend on the value of σ (sigma). // It can be used as high or low resolution window, depending of the σ value. // // Spectral leakage parameters are summarized in the table: // // | σ=0.3 | σ=0.5 | σ=1.2 | // -------|---------------------------| // ΔF_0 | 8 | 3.4 | 2.2 | // ΔF_0.5 | 1.82 | 1.2 | 0.94 | // K | 4 | 1.7 | 1.1 | // ɣ_max | -65 | -31.5 | -15.5 | // β | -8.52 | -4.48 | -0.96 | type Gaussian struct { Sigma float64 } // Transform applies the Gaussian transformation to seq in place, using the // value of the receiver as the sigma parameter, and returning the result. func (g Gaussian) Transform(seq []float64) []float64 { a := float64(len(seq)-1) / 2 for i := range seq { x := -0.5 * math.Pow((float64(i)-a)/(g.Sigma*a), 2) seq[i] *= math.Exp(x) } return seq } // TransformComplex applies the Gaussian transformation to seq in place, // using the value of the receiver as the sigma parameter, and returning // the result. func (g Gaussian) TransformComplex(seq []complex128) []complex128 { a := float64(len(seq)-1) / 2 for i, v := range seq { x := -0.5 * math.Pow((float64(i)-a)/(g.Sigma*a), 2) w := math.Exp(x) seq[i] = complex(w*real(v), w*imag(v)) } return seq } // Tukey can modify a sequence using the Tukey window and return the result. // See https://en.wikipedia.org/wiki/Window_function#Tukey_window // and https://www.recordingblogs.com/wiki/tukey-window for details. // // The Tukey window is an adjustable window. // // The sequence weights are // // w[k] = 0.5 * (1 + cos(π*(|k - M| - αM)/((1-α) * M))), |k - M| ≥ αM // = 1, |k - M| < αM // // with M = (N - 1)/2 for k=0,1,...,N-1 where N is the length of the window. // // Spectral leakage parameters are summarized in the table: // // | α=0.3 | α=0.5 | α=0.7 | // -------|--------------------------| // ΔF_0 | 1.33 | 1.22 | 1.13 | // ΔF_0.5 | 1.28 | 1.16 | 1.04 | // K | 0.67 | 0.61 | 0.57 | // ɣ_max | -18.2 | -15.1 | -13.8 | // β | -1.41 | -2.50 | -3.74 | type Tukey struct { Alpha float64 } // Transform applies the Tukey transformation to seq in place, using the // value of the receiver as the Alpha parameter, and returning the result. func (t Tukey) Transform(seq []float64) []float64 { switch { case t.Alpha <= 0: return Rectangular(seq) case t.Alpha >= 1: return Hann(seq) default: alphaL := t.Alpha * float64(len(seq)-1) width := int(0.5*alphaL) + 1 for i := range seq[:width] { w := 0.5 * (1 - math.Cos(2*math.Pi*float64(i)/alphaL)) seq[i] *= w seq[len(seq)-1-i] *= w } return seq } } // TransformComplex applies the Tukey transformation to seq in place, using // the value of the receiver as the Alpha parameter, and returning the result. func (t Tukey) TransformComplex(seq []complex128) []complex128 { switch { case t.Alpha <= 0: return RectangularComplex(seq) case t.Alpha >= 1: return HannComplex(seq) default: alphaL := t.Alpha * float64(len(seq)-1) width := int(0.5*alphaL) + 1 for i, v := range seq[:width] { w := 0.5 * (1 - math.Cos(2*math.Pi*float64(i)/alphaL)) v = complex(w*real(v), w*imag(v)) seq[i] = v seq[len(seq)-1-i] = v } return seq } } // Values is an arbitrary real window function. type Values []float64 // NewValues returns a Values of length n with weights corresponding to the // provided window function. func NewValues(window func([]float64) []float64, n int) Values { v := make(Values, n) for i := range v { v[i] = 1 } return window(v) } // Transform applies the weights in the receiver to seq in place, returning the // result. If v is nil, Transform is a no-op, otherwise the length of v must // match the length of seq. func (v Values) Transform(seq []float64) []float64 { if v == nil { return seq } if len(v) != len(seq) { panic("window: length mismatch") } for i, w := range v { seq[i] *= w } return seq } // TransformTo applies the weights in the receiver to src placing the result // in dst. If v is nil, TransformTo is a no-op, otherwise the length of v must // match the length of src and dst. func (v Values) TransformTo(dst, src []float64) { if v == nil { return } if len(v) != len(src) { panic("window: seq length mismatch") } if len(v) != len(dst) { panic("window: dst length mismatch") } for i, w := range v { dst[i] = w * src[i] } } // TransformComplex applies the weights in the receiver to seq in place, // returning the result. If v is nil, TransformComplex is a no-op, otherwise // the length of v must match the length of seq. func (v Values) TransformComplex(seq []complex128) []complex128 { if v == nil { return seq } if len(v) != len(seq) { panic("window: length mismatch") } for i, w := range v { sv := seq[i] seq[i] = complex(w*real(sv), w*imag(sv)) } return seq } // TransformComplexTo applies the weights in the receiver to src placing the // result in dst. If v is nil, TransformComplexTo is a no-op, otherwise the // length of v must match the length of src and dst. func (v Values) TransformComplexTo(dst, src []complex128) { if v == nil { return } if len(v) != len(src) { panic("window: seq length mismatch") } if len(v) != len(dst) { panic("window: dst length mismatch") } for i, w := range v { sv := src[i] dst[i] = complex(w*real(sv), w*imag(sv)) } } golang-gonum-v1-gonum-0.14.0/dsp/window/window_test.go000066400000000000000000000206111450372207100226300ustar00rootroot00000000000000// Copyright ©2020 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 window import ( "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) var windowTests = []struct { name string fn func([]float64) []float64 fnCmplx func([]complex128) []complex128 want []float64 }{ { name: "Rectangular", fn: Rectangular, fnCmplx: RectangularComplex, want: []float64{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, }, { name: "Sine", fn: Sine, fnCmplx: SineComplex, want: []float64{ 0.000000, 0.164595, 0.324699, 0.475947, 0.614213, 0.735724, 0.837166, 0.915773, 0.969400, 0.996584, 0.996584, 0.969400, 0.915773, 0.837166, 0.735724, 0.614213, 0.475947, 0.324699, 0.164595, 0.000000, }, }, { name: "Lanczos", fn: Lanczos, fnCmplx: LanczosComplex, want: []float64{ 0.000000, 0.115514, 0.247646, 0.389468, 0.532984, 0.669692, 0.791213, 0.889915, 0.959492, 0.995450, 0.995450, 0.959492, 0.889915, 0.791213, 0.669692, 0.532984, 0.389468, 0.247646, 0.115514, 0.000000, }, }, // This case tests Lanczos for a NaN condition. The Lanczos NaN condition is k=(N-1)/2, that is when N is odd. { name: "LanczosOdd", fn: Lanczos, fnCmplx: LanczosComplex, want: []float64{ 0.000000, 0.109292, 0.233872, 0.367883, 0.504551, 0.636620, 0.756827, 0.858394, 0.935489, 0.983632, 1.000000, 0.983632, 0.935489, 0.858394, 0.756827, 0.636620, 0.504551, 0.367883, 0.233872, 0.109292, 0.000000, }, }, { name: "Triangular", fn: Triangular, fnCmplx: TriangularComplex, want: []float64{ 0.000000, 0.105263, 0.210526, 0.315789, 0.421053, 0.526316, 0.631579, 0.736842, 0.842105, 0.947368, 0.947368, 0.842105, 0.736842, 0.631579, 0.526316, 0.421053, 0.315789, 0.210526, 0.105263, 0.000000, }, }, { name: "Hann", fn: Hann, fnCmplx: HannComplex, want: []float64{ 0.000000, 0.027091, 0.105430, 0.226526, 0.377257, 0.541290, 0.700848, 0.838641, 0.939737, 0.993181, 0.993181, 0.939737, 0.838641, 0.700848, 0.541290, 0.377257, 0.226526, 0.105430, 0.027091, 0.000000, }, }, { name: "BartlettHann", fn: BartlettHann, fnCmplx: BartlettHannComplex, want: []float64{ 0.000000, 0.045853, 0.130653, 0.247949, 0.387768, 0.537696, 0.684223, 0.814209, 0.916305, 0.982186, 0.982186, 0.916305, 0.814209, 0.684223, 0.537696, 0.387768, 0.247949, 0.130653, 0.045853, 0.000000, }, }, { name: "Hamming", fn: Hamming, fnCmplx: HammingComplex, want: []float64{ 0.08, 0.104924, 0.176995, 0.288404, 0.427077, 0.577986, 0.72478, 0.85155, 0.944558, 0.993726, 0.993726, 0.944558, 0.85155, 0.72478, 0.577986, 0.427077, 0.288404, 0.176995, 0.104924, 0.08, }, }, { name: "Blackman", fn: Blackman, fnCmplx: BlackmanComplex, want: []float64{ 0.000000, 0.010223, 0.045069, 0.114390, 0.226899, 0.382381, 0.566665, 0.752034, 0.903493, 0.988846, 0.988846, 0.903493, 0.752034, 0.566665, 0.382381, 0.226899, 0.114390, 0.045069, 0.010223, 0.000000, }, }, { name: "BlackmanHarris", fn: BlackmanHarris, fnCmplx: BlackmanHarrisComplex, want: []float64{ 0.000060, 0.002018, 0.012795, 0.046450, 0.122540, 0.256852, 0.448160, 0.668576, 0.866426, 0.984278, 0.984278, 0.866426, 0.668576, 0.448160, 0.256852, 0.122540, 0.046450, 0.012795, 0.002018, 0.000060, }, }, { name: "Nuttall", fn: Nuttall, fnCmplx: NuttallComplex, want: []float64{ 0.000000, 0.001706, 0.011614, 0.043682, 0.117808, 0.250658, 0.441946, 0.664015, 0.864348, 0.984019, 0.984019, 0.864348, 0.664015, 0.441946, 0.250658, 0.117808, 0.043682, 0.011614, 0.001706, 0.000000, }, }, { name: "BlackmanNuttall", fn: BlackmanNuttall, fnCmplx: BlackmanNuttallComplex, want: []float64{ 0.000363, 0.002885, 0.015360, 0.051652, 0.130567, 0.266629, 0.457501, 0.675215, 0.869392, 0.984644, 0.984644, 0.869392, 0.675215, 0.457501, 0.266629, 0.130567, 0.051652, 0.015360, 0.002885, 0.000363, }, }, { name: "FlatTop", fn: FlatTop, fnCmplx: FlatTopComplex, want: []float64{ -0.000421, -0.003687, -0.017675, -0.045939, -0.070137, -0.037444, 0.115529, 0.402051, 0.737755, 0.967756, 0.967756, 0.737755, 0.402051, 0.115529, -0.037444, -0.070137, -0.045939, -0.017675, -0.003687, -0.000421, }, }, { name: "Gaussian{0.3}.Transform", fn: Gaussian{0.3}.Transform, fnCmplx: Gaussian{0.3}.TransformComplex, want: []float64{ 0.003866, 0.011708, 0.031348, 0.074214, 0.155344, 0.287499, 0.470444, 0.680632, 0.870660, 0.984728, 0.984728, 0.870660, 0.680632, 0.470444, 0.287499, 0.155344, 0.074214, 0.031348, 0.011708, 0.003866, }, }, { name: "Gaussian{0.5}.Transform", fn: Gaussian{0.5}.Transform, fnCmplx: Gaussian{0.5}.TransformComplex, want: []float64{ 0.135335, 0.201673, 0.287499, 0.392081, 0.511524, 0.638423, 0.762260, 0.870660, 0.951361, 0.994475, 0.994475, 0.951361, 0.870660, 0.762260, 0.638423, 0.511524, 0.392081, 0.287499, 0.201673, 0.135335, }, }, { name: "Gaussian{1.2}.Transform", fn: Gaussian{1.2}.Transform, fnCmplx: Gaussian{1.2}.TransformComplex, want: []float64{ 0.706648, 0.757319, 0.805403, 0.849974, 0.890135, 0.925049, 0.953963, 0.976241, 0.991381, 0.999039, 0.999039, 0.991381, 0.976241, 0.953963, 0.925049, 0.890135, 0.849974, 0.805403, 0.757319, 0.706648, }, }, { name: "Tukey{1}.Transform", fn: Tukey{1}.Transform, fnCmplx: Tukey{1}.TransformComplex, want: []float64{ // Hann window case. 0.000000, 0.027091, 0.105430, 0.226526, 0.377257, 0.541290, 0.700848, 0.838641, 0.939737, 0.993181, 0.993181, 0.939737, 0.838641, 0.700848, 0.541290, 0.377257, 0.226526, 0.105430, 0.027091, 0.000000, }, }, { name: "Tukey{0}.Transform", fn: Tukey{0}.Transform, fnCmplx: Tukey{0}.TransformComplex, want: []float64{ // Rectangular window case. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, }, { name: "Tukey{0.5}.Transform", fn: Tukey{0.5}.Transform, fnCmplx: Tukey{0.5}.TransformComplex, want: []float64{ 0.000000, 0.105430, 0.377257, 0.700847, 0.939737, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.939737, 0.700847, 0.377257, 0.105429, 0.000000, }, }, } func TestWindows(t *testing.T) { t.Parallel() const tol = 1e-6 for _, test := range windowTests { t.Run(test.name, func(t *testing.T) { src := make([]float64, len(test.want)) for i := range src { src[i] = 1 } dst := test.fn(src) if !floats.EqualApprox(dst, test.want, tol) { t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#v", test.name, dst, test.want) } for i := range src { src[i] = 1 } vals := NewValues(test.fn, len(src)) dst = vals.Transform(src) if !floats.EqualApprox(dst, test.want, tol) { t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want) } for i := range src { src[i] = 1 } dst = make([]float64, len(src)) vals.TransformTo(dst, src) if !floats.EqualApprox(dst, test.want, tol) { t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want) } }) } } func TestWindowsComplex(t *testing.T) { t.Parallel() const tol = 1e-6 for _, test := range windowTests { t.Run(test.name+"Complex", func(t *testing.T) { src := make([]complex128, len(test.want)) for i := range src { src[i] = complex(1, 1) } dst := test.fnCmplx(src) if !equalApprox(dst, test.want, tol) { t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want) } for i := range src { src[i] = complex(1, 1) } vals := NewValues(test.fn, len(src)) dst = vals.TransformComplex(src) if !equalApprox(dst, test.want, tol) { t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want) } for i := range src { src[i] = complex(1, 1) } dst = make([]complex128, len(src)) vals.TransformComplexTo(dst, src) if !equalApprox(dst, test.want, tol) { t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want) } }) } } func equalApprox(seq1 []complex128, seq2 []float64, tol float64) bool { if len(seq1) != len(seq2) { return false } for i := range seq1 { if !scalar.EqualWithinAbsOrRel(real(seq1[i]), seq2[i], tol, tol) { return false } if !scalar.EqualWithinAbsOrRel(imag(seq1[i]), seq2[i], tol, tol) { return false } } return true } golang-gonum-v1-gonum-0.14.0/floats/000077500000000000000000000000001450372207100171265ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/floats/README.md000066400000000000000000000006671450372207100204160ustar00rootroot00000000000000# Gonum floats [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/floats)](https://pkg.go.dev/gonum.org/v1/gonum/floats) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/floats?status.svg)](https://godocs.io/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. golang-gonum-v1-gonum-0.14.0/floats/doc.go000066400000000000000000000010041450372207100202150ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/floats/examples_test.go000066400000000000000000000037711450372207100223420ustar00rootroot00000000000000// 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_test import ( "fmt" "gonum.org/v1/gonum/floats" ) // Set of examples for all the functions func ExampleAdd_simple() { // Adding three slices together. Note that // the result is stored in the first slice s1 := []float64{1, 2, 3, 4} s2 := []float64{5, 6, 7, 8} s3 := []float64{1, 1, 1, 1} floats.Add(s1, s2) floats.Add(s1, s3) fmt.Println("s1 =", s1) fmt.Println("s2 =", s2) fmt.Println("s3 =", s3) // Output: // s1 = [7 9 11 13] // s2 = [5 6 7 8] // s3 = [1 1 1 1] } func ExampleAdd_newslice() { // If one wants to store the result in a // new container, just make a new slice s1 := []float64{1, 2, 3, 4} s2 := []float64{5, 6, 7, 8} s3 := []float64{1, 1, 1, 1} dst := make([]float64, len(s1)) floats.AddTo(dst, s1, s2) floats.Add(dst, s3) fmt.Println("dst =", dst) fmt.Println("s1 =", s1) fmt.Println("s2 =", s2) fmt.Println("s3 =", s3) // Output: // dst = [7 9 11 13] // s1 = [1 2 3 4] // s2 = [5 6 7 8] // s3 = [1 1 1 1] } func ExampleAdd_unequallengths() { // If the lengths of the slices are unknown, // use EqualLengths to check s1 := []float64{1, 2, 3} s2 := []float64{5, 6, 7, 8} eq := floats.EqualLengths(s1, s2) if eq { floats.Add(s1, s2) } else { fmt.Println("Unequal lengths") } // Output: // Unequal lengths } func ExampleAddConst() { s := []float64{1, -2, 3, -4} c := 5.0 floats.AddConst(c, s) fmt.Println("s =", s) // Output: // s = [6 3 8 1] } func ExampleCumProd() { s := []float64{1, -2, 3, -4} dst := make([]float64, len(s)) floats.CumProd(dst, s) fmt.Println("dst =", dst) fmt.Println("s =", s) // Output: // dst = [1 -2 -6 24] // s = [1 -2 3 -4] } func ExampleCumSum() { s := []float64{1, -2, 3, -4} dst := make([]float64, len(s)) floats.CumSum(dst, s) fmt.Println("dst =", dst) fmt.Println("s =", s) // Output: // dst = [1 -1 2 -2] // s = [1 -2 3 -4] } golang-gonum-v1-gonum-0.14.0/floats/floats.go000066400000000000000000000453551450372207100207610ustar00rootroot00000000000000// 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" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/internal/asm/f64" ) const ( zeroLength = "floats: zero length slice" shortSpan = "floats: slice length less than 2" badLength = "floats: slice lengths do not match" badDstLength = "floats: destination slice length does not match input" ) // Add adds, element-wise, the elements of s and dst, and stores the result in dst. // It panics if the argument lengths do not match. func Add(dst, s []float64) { if len(dst) != len(s) { panic(badDstLength) } f64.AxpyUnitaryTo(dst, 1, s, dst) } // AddTo adds, element-wise, the elements of s and t and // stores the result in dst. // It panics if the argument lengths do not match. func AddTo(dst, s, t []float64) []float64 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } 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 slice argument lengths do not match. func AddScaled(dst []float64, alpha float64, s []float64) { if len(dst) != len(s) { panic(badLength) } 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 slice argument lengths do not match. // // 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(s) != len(y) { panic(badLength) } if len(dst) != len(y) { panic(badDstLength) } f64.AxpyUnitaryTo(dst, alpha, s, y) return dst } // argsort is a helper that implements sort.Interface, as used by // Argsort and ArgsortStable. 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 argument lengths do not match. func Argsort(dst []float64, inds []int) { if len(dst) != len(inds) { panic(badDstLength) } for i := range dst { inds[i] = i } a := argsort{s: dst, inds: inds} sort.Sort(a) } // ArgsortStable sorts the elements of dst while tracking their original order and // keeping the original order of equal elements. At the conclusion of ArgsortStable, // 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 argument lengths do not match. func ArgsortStable(dst []float64, inds []int) { if len(dst) != len(inds) { panic(badDstLength) } for i := range dst { inds[i] = i } a := argsort{s: dst, inds: inds} sort.Stable(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. // It panics if the argument lengths 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(badDstLength) } 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. // It panics if the argument lengths 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(badDstLength) } if len(dst) == 0 { return dst } return f64.CumSum(dst, s) } // Distance computes the L-norm of s - t. See Norm for special cases. // It panics if the slice argument lengths do not match. func Distance(s, t []float64, L float64) float64 { if len(s) != len(t) { panic(badLength) } if len(s) == 0 { return 0 } if L == 2 { return f64.L2DistanceUnitary(s, t) } var norm float64 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 argument lengths do not match. func Div(dst, s []float64) { if len(dst) != len(s) { panic(badLength) } f64.Div(dst, s) } // DivTo performs element-wise division s / t // and stores the value in dst. // It panics if the argument lengths do not match. func DivTo(dst, s, t []float64) []float64 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } 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]. // It panics if the argument lengths do not match. func Dot(s1, s2 []float64) float64 { if len(s1) != len(s2) { panic(badLength) } return f64.DotUnitary(s1, s2) } // Equal returns true when 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 when 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 !scalar.EqualWithinAbsOrRel(a, s2[i], tol, tol) { return false } } return true } // EqualFunc returns true when 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 } // EqualLengths returns true when all of the slices have equal length, // and false otherwise. It also returns true when 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 when 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. // It panics if the length of dst is less than 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. // It panics if s is zero length. func MaxIdx(s []float64) int { if len(s) == 0 { panic(zeroLength) } 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 minimum value in the input slice. // It panics if s is zero length. 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 minimum value, the first such index is returned. // It panics if s is zero length. func MinIdx(s []float64) int { if len(s) == 0 { panic(zeroLength) } 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. // It panics if the argument lengths do not match. func Mul(dst, s []float64) { if len(dst) != len(s) { panic(badLength) } for i, val := range s { dst[i] *= val } } // MulTo performs element-wise multiplication between s // and t and stores the value in dst. // It panics if the argument lengths do not match. func MulTo(dst, s, t []float64) []float64 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } for i, val := range t { dst[i] = val * s[i] } return dst } // 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. // It panics if s is zero length. func NearestIdx(s []float64, v float64) int { if len(s) == 0 { panic(zeroLength) } 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. // It panics if n is less than two. func NearestIdxForSpan(n int, l, u float64, v float64) int { if n < 2 { panic(shortSpan) } 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 { return f64.L2NormUnitary(s) } 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) } // 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] } } // Same returns true when the input slices have the same length and 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. // It panics if the slice argument lengths do not match. func ScaleTo(dst []float64, c float64, s []float64) []float64 { if len(dst) != len(s) { panic(badDstLength) } 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. // It panics if the length of dst is less than 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(shortSpan) } // 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. // It panics if the argument lengths do not match. func Sub(dst, s []float64) { if len(dst) != len(s) { panic(badLength) } f64.AxpyUnitaryTo(dst, -1, s, dst) } // SubTo subtracts, element-wise, the elements of t from s and // stores the result in dst. // It panics if the argument lengths do not match. func SubTo(dst, s, t []float64) []float64 { if len(s) != len(t) { panic(badLength) } if len(dst) != len(s) { panic(badDstLength) } 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(shortSpan) } 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 } // SumCompensated returns the sum of the elements of the slice calculated with greater // accuracy than Sum at the expense of additional computation. func SumCompensated(s []float64) float64 { // SumCompensated uses an improved version of Kahan's compensated // summation algorithm proposed by Neumaier. // See https://en.wikipedia.org/wiki/Kahan_summation_algorithm for details. var sum, c float64 for _, x := range s { // This type conversion is here to prevent a sufficiently smart compiler // from optimising away these operations. t := float64(sum + x) if math.Abs(sum) >= math.Abs(x) { c += (sum - t) + x } else { c += (x - t) + sum } sum = t } return sum + c } golang-gonum-v1-gonum-0.14.0/floats/floats_test.go000066400000000000000000001333571450372207100220200ustar00rootroot00000000000000// 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 ( "fmt" "math" "sort" "strconv" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) const ( EqTolerance = 1e-14 Small = 10 Medium = 1000 Large = 100000 Huge = 10000000 ) func areSlicesEqual(t *testing.T, truth, comp []float64, str string) { if !EqualApprox(comp, truth, EqTolerance) { t.Errorf(str+". Expected %v, returned %v", truth, comp) } } func areSlicesSame(t *testing.T, truth, comp []float64, str string) { ok := len(truth) == len(comp) if ok { for i, a := range truth { if !scalar.EqualWithinAbsOrRel(a, comp[i], EqTolerance, EqTolerance) && !scalar.Same(a, comp[i]) { ok = false break } } } if !ok { t.Errorf(str+". Expected %v, returned %v", truth, comp) } } func Panics(fun func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() fun() return } func TestAdd(t *testing.T) { t.Parallel() a := []float64{1, 2, 3} b := []float64{4, 5, 6} c := []float64{7, 8, 9} truth := []float64{12, 15, 18} n := make([]float64, len(a)) Add(n, a) Add(n, b) Add(n, c) areSlicesEqual(t, truth, n, "Wrong addition of slices new receiver") Add(a, b) Add(a, c) areSlicesEqual(t, truth, n, "Wrong addition of slices for no new receiver") // Test that it panics if !Panics(func() { Add(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Did not panic with length mismatch") } } func TestAddTo(t *testing.T) { t.Parallel() a := []float64{1, 2, 3} b := []float64{4, 5, 6} truth := []float64{5, 7, 9} n1 := make([]float64, len(a)) n2 := AddTo(n1, a, b) areSlicesEqual(t, truth, n1, "Bad addition from mutator") areSlicesEqual(t, truth, n2, "Bad addition from returned slice") // Test that it panics if !Panics(func() { AddTo(make([]float64, 2), make([]float64, 3), make([]float64, 3)) }) { t.Errorf("Did not panic with length mismatch") } if !Panics(func() { AddTo(make([]float64, 3), make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Did not panic with length mismatch") } } func TestAddConst(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} c := 6.0 truth := []float64{9, 10, 7, 13, 11} AddConst(c, s) areSlicesEqual(t, truth, s, "Wrong addition of constant") } func TestAddScaled(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} alpha := 6.0 dst := []float64{1, 2, 3, 4, 5} ans := []float64{19, 26, 9, 46, 35} AddScaled(dst, alpha, s) if !EqualApprox(dst, ans, EqTolerance) { t.Errorf("Adding scaled did not match") } short := []float64{1} if !Panics(func() { AddScaled(dst, alpha, short) }) { t.Errorf("Doesn't panic if s is smaller than dst") } if !Panics(func() { AddScaled(short, alpha, s) }) { t.Errorf("Doesn't panic if dst is smaller than s") } } func TestAddScaledTo(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} alpha := 6.0 y := []float64{1, 2, 3, 4, 5} dst1 := make([]float64, 5) ans := []float64{19, 26, 9, 46, 35} dst2 := AddScaledTo(dst1, y, alpha, s) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("AddScaledTo did not match for mutator") } if !EqualApprox(dst2, ans, EqTolerance) { t.Errorf("AddScaledTo did not match for returned slice") } AddScaledTo(dst1, y, alpha, s) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("Reusing dst did not match") } short := []float64{1} if !Panics(func() { AddScaledTo(dst1, y, alpha, short) }) { t.Errorf("Doesn't panic if s is smaller than dst") } if !Panics(func() { AddScaledTo(short, y, alpha, s) }) { t.Errorf("Doesn't panic if dst is smaller than s") } if !Panics(func() { AddScaledTo(dst1, short, alpha, s) }) { t.Errorf("Doesn't panic if y is smaller than dst") } } func TestArgsort(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} inds := make([]int, len(s)) Argsort(s, inds) sortedS := []float64{1, 3, 4, 5, 7} trueInds := []int{2, 0, 1, 4, 3} if !Equal(s, sortedS) { t.Error("elements not sorted correctly") } for i := range trueInds { if trueInds[i] != inds[i] { t.Error("inds not correct") } } inds = []int{1, 2} if !Panics(func() { Argsort(s, inds) }) { t.Error("does not panic if lengths do not match") } } func TestArgsortStable(t *testing.T) { for i := 1; i <= 100; i++ { data := make([]float64, i+2) data[0] = 2 data[len(data)-1] = 2 for j := 1; j <= i; j++ { data[j] = 1 } idx := make([]int, len(data)) ArgsortStable(data, idx) if !sort.Float64sAreSorted(data) { t.Errorf("unexpected data sort order for case %d", i) } if !sort.IntsAreSorted(idx[:i]) { t.Errorf("unexpected index sort order for case %d", i) } } if !Panics(func() { ArgsortStable([]float64{1, 2, 3}, []int{0, 0}) }) { t.Error("does not panic if lengths do not match") } } func TestCount(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} f := func(v float64) bool { return v > 3.5 } truth := 3 n := Count(f, s) if n != truth { t.Errorf("Wrong number of elements counted") } } func TestCumProd(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} receiver := make([]float64, len(s)) result := CumProd(receiver, s) truth := []float64{3, 12, 12, 84, 420} areSlicesEqual(t, truth, receiver, "Wrong cumprod mutated with new receiver") areSlicesEqual(t, truth, result, "Wrong cumprod result with new receiver") CumProd(receiver, s) areSlicesEqual(t, truth, receiver, "Wrong cumprod returned with reused receiver") // Test that it panics if !Panics(func() { CumProd(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Did not panic with length mismatch") } // Test empty CumProd emptyReceiver := make([]float64, 0) truth = []float64{} CumProd(emptyReceiver, emptyReceiver) areSlicesEqual(t, truth, emptyReceiver, "Wrong cumprod returned with empty receiver") } func TestCumSum(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} receiver := make([]float64, len(s)) result := CumSum(receiver, s) truth := []float64{3, 7, 8, 15, 20} areSlicesEqual(t, truth, receiver, "Wrong cumsum mutated with new receiver") areSlicesEqual(t, truth, result, "Wrong cumsum returned with new receiver") CumSum(receiver, s) areSlicesEqual(t, truth, receiver, "Wrong cumsum returned with reused receiver") // Test that it panics if !Panics(func() { CumSum(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Did not panic with length mismatch") } // Test empty CumSum emptyReceiver := make([]float64, 0) truth = []float64{} CumSum(emptyReceiver, emptyReceiver) areSlicesEqual(t, truth, emptyReceiver, "Wrong cumsum returned with empty receiver") } func TestDistance(t *testing.T) { t.Parallel() norms := []float64{1, 2, 4, math.Inf(1)} slices := []struct { s []float64 t []float64 }{ { nil, nil, }, { []float64{8, 9, 10, -12}, []float64{8, 9, 10, -12}, }, { []float64{1, 2, 3, -4, -5, 8}, []float64{-9.2, -6.8, 9, -3, -2, 1}, }, } for j, test := range slices { tmp := make([]float64, len(test.s)) for i, L := range norms { dist := Distance(test.s, test.t, L) copy(tmp, test.s) Sub(tmp, test.t) norm := Norm(tmp, L) if dist != norm { // Use equality because they should be identical. t.Errorf("Distance does not match norm for case %v, %v. Expected %v, Found %v.", i, j, norm, dist) } } } if !Panics(func() { Distance([]float64{}, norms, 1) }) { t.Errorf("Did not panic with unequal lengths") } } func TestDiv(t *testing.T) { t.Parallel() s1 := []float64{5, 12, 27} s2 := []float64{1, 2, 3} ans := []float64{5, 6, 9} Div(s1, s2) if !EqualApprox(s1, ans, EqTolerance) { t.Errorf("Div doesn't give correct answer") } s1short := []float64{1} if !Panics(func() { Div(s1short, s2) }) { t.Errorf("Did not panic with unequal lengths") } s2short := []float64{1} if !Panics(func() { Div(s1, s2short) }) { t.Errorf("Did not panic with unequal lengths") } } func TestDivTo(t *testing.T) { t.Parallel() s1 := []float64{5, 12, 27} s1orig := []float64{5, 12, 27} s2 := []float64{1, 2, 3} s2orig := []float64{1, 2, 3} dst1 := make([]float64, 3) ans := []float64{5, 6, 9} dst2 := DivTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("DivTo doesn't give correct answer in mutated slice") } if !EqualApprox(dst2, ans, EqTolerance) { t.Errorf("DivTo doesn't give correct answer in returned slice") } if !EqualApprox(s1, s1orig, EqTolerance) { t.Errorf("S1 changes during multo") } if !EqualApprox(s2, s2orig, EqTolerance) { t.Errorf("s2 changes during multo") } DivTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("DivTo doesn't give correct answer reusing dst") } dstShort := []float64{1} if !Panics(func() { DivTo(dstShort, s1, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s1short := []float64{1} if !Panics(func() { DivTo(dst1, s1short, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s2short := []float64{1} if !Panics(func() { DivTo(dst1, s1, s2short) }) { t.Errorf("Did not panic with s2 wrong length") } } func TestDot(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3, 4} s2 := []float64{-3, 4, 5, -6} truth := -4.0 ans := Dot(s1, s2) if ans != truth { t.Errorf("Dot product computed incorrectly") } // Test that it panics if !Panics(func() { Dot(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Did not panic with length mismatch") } } func TestEquals(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3, 4} s2 := []float64{1, 2, 3, 4} if !Equal(s1, s2) { t.Errorf("Equal slices returned as unequal") } s2 = []float64{1, 2, 3, 4 + 1e-14} if Equal(s1, s2) { t.Errorf("Unequal slices returned as equal") } if Equal(s1, []float64{}) { t.Errorf("Unequal slice lengths returned as equal") } } func TestEqualApprox(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3, 4} s2 := []float64{1, 2, 3, 4 + 1e-10} if EqualApprox(s1, s2, 1e-13) { t.Errorf("Unequal slices returned as equal for absolute") } if !EqualApprox(s1, s2, 1e-5) { t.Errorf("Equal slices returned as unequal for absolute") } s1 = []float64{1, 2, 3, 1000} s2 = []float64{1, 2, 3, 1000 * (1 + 1e-7)} if EqualApprox(s1, s2, 1e-8) { t.Errorf("Unequal slices returned as equal for relative") } if !EqualApprox(s1, s2, 1e-5) { t.Errorf("Equal slices returned as unequal for relative") } if EqualApprox(s1, []float64{}, 1e-5) { t.Errorf("Unequal slice lengths returned as equal") } } func TestEqualFunc(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3, 4} s2 := []float64{1, 2, 3, 4} eq := func(x, y float64) bool { return x == y } if !EqualFunc(s1, s2, eq) { t.Errorf("Equal slices returned as unequal") } s2 = []float64{1, 2, 3, 4 + 1e-14} if EqualFunc(s1, s2, eq) { t.Errorf("Unequal slices returned as equal") } if EqualFunc(s1, []float64{}, eq) { t.Errorf("Unequal slice lengths returned as equal") } } func TestEqualsRelative(t *testing.T) { t.Parallel() equalityTests := []struct { a, b float64 tol float64 equal bool }{ {1000000, 1000001, 0, true}, {1000001, 1000000, 0, true}, {10000, 10001, 0, false}, {10001, 10000, 0, false}, {-1000000, -1000001, 0, true}, {-1000001, -1000000, 0, true}, {-10000, -10001, 0, false}, {-10001, -10000, 0, false}, {1.0000001, 1.0000002, 0, true}, {1.0000002, 1.0000001, 0, true}, {1.0002, 1.0001, 0, false}, {1.0001, 1.0002, 0, false}, {-1.000001, -1.000002, 0, true}, {-1.000002, -1.000001, 0, true}, {-1.0001, -1.0002, 0, false}, {-1.0002, -1.0001, 0, false}, {0.000000001000001, 0.000000001000002, 0, true}, {0.000000001000002, 0.000000001000001, 0, true}, {0.000000000001002, 0.000000000001001, 0, false}, {0.000000000001001, 0.000000000001002, 0, false}, {-0.000000001000001, -0.000000001000002, 0, true}, {-0.000000001000002, -0.000000001000001, 0, true}, {-0.000000000001002, -0.000000000001001, 0, false}, {-0.000000000001001, -0.000000000001002, 0, false}, {0, 0, 0, true}, {0, -0, 0, true}, {-0, -0, 0, true}, {0.00000001, 0, 0, false}, {0, 0.00000001, 0, false}, {-0.00000001, 0, 0, false}, {0, -0.00000001, 0, false}, {0, 1e-310, 0.01, true}, {1e-310, 0, 0.01, true}, {1e-310, 0, 0.000001, false}, {0, 1e-310, 0.000001, false}, {0, -1e-310, 0.1, true}, {-1e-310, 0, 0.1, true}, {-1e-310, 0, 0.00000001, false}, {0, -1e-310, 0.00000001, false}, {math.Inf(1), math.Inf(1), 0, true}, {math.Inf(-1), math.Inf(-1), 0, true}, {math.Inf(-1), math.Inf(1), 0, false}, {math.Inf(1), math.MaxFloat64, 0, false}, {math.Inf(-1), -math.MaxFloat64, 0, false}, {math.NaN(), math.NaN(), 0, false}, {math.NaN(), 0, 0, false}, {-0, math.NaN(), 0, false}, {math.NaN(), -0, 0, false}, {0, math.NaN(), 0, false}, {math.NaN(), math.Inf(1), 0, false}, {math.Inf(1), math.NaN(), 0, false}, {math.NaN(), math.Inf(-1), 0, false}, {math.Inf(-1), math.NaN(), 0, false}, {math.NaN(), math.MaxFloat64, 0, false}, {math.MaxFloat64, math.NaN(), 0, false}, {math.NaN(), -math.MaxFloat64, 0, false}, {-math.MaxFloat64, math.NaN(), 0, false}, {math.NaN(), math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, math.NaN(), 0, false}, {math.NaN(), -math.SmallestNonzeroFloat64, 0, false}, {-math.SmallestNonzeroFloat64, math.NaN(), 0, false}, {1.000000001, -1.0, 0, false}, {-1.0, 1.000000001, 0, false}, {-1.000000001, 1.0, 0, false}, {1.0, -1.000000001, 0, false}, {10 * math.SmallestNonzeroFloat64, 10 * -math.SmallestNonzeroFloat64, 0, true}, {1e11 * math.SmallestNonzeroFloat64, 1e11 * -math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, -math.SmallestNonzeroFloat64, 0, true}, {-math.SmallestNonzeroFloat64, math.SmallestNonzeroFloat64, 0, true}, {math.SmallestNonzeroFloat64, 0, 0, true}, {0, math.SmallestNonzeroFloat64, 0, true}, {-math.SmallestNonzeroFloat64, 0, 0, true}, {0, -math.SmallestNonzeroFloat64, 0, true}, {0.000000001, -math.SmallestNonzeroFloat64, 0, false}, {0.000000001, math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, 0.000000001, 0, false}, {-math.SmallestNonzeroFloat64, 0.000000001, 0, false}, } for _, ts := range equalityTests { if ts.tol == 0 { ts.tol = 1e-5 } if equal := scalar.EqualWithinRel(ts.a, ts.b, ts.tol); equal != ts.equal { t.Errorf("Relative equality of %g and %g with tolerance %g returned: %v. Expected: %v", ts.a, ts.b, ts.tol, equal, ts.equal) } } } func TestEqualLengths(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3, 4} s2 := []float64{1, 2, 3, 4} s3 := []float64{1, 2, 3} if !EqualLengths(s1, s2) { t.Errorf("Equal lengths returned as unequal") } if EqualLengths(s1, s3) { t.Errorf("Unequal lengths returned as equal") } if !EqualLengths(s1) { t.Errorf("Single slice returned as unequal") } if !EqualLengths() { t.Errorf("No slices returned as unequal") } } func eqIntSlice(one, two []int) string { if len(one) != len(two) { return "Length mismatch" } for i, val := range one { if val != two[i] { return "Index " + strconv.Itoa(i) + " mismatch" } } return "" } func TestFind(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} f := func(v float64) bool { return v > 3.5 } allTrueInds := []int{1, 3, 4} // Test finding first two elements inds, err := Find(nil, f, s, 2) if err != nil { t.Errorf("Find first two: Improper error return") } trueInds := allTrueInds[:2] str := eqIntSlice(inds, trueInds) if str != "" { t.Errorf("Find first two: " + str) } // Test finding no elements with non nil slice inds = []int{1, 2, 3, 4, 5, 6} inds, err = Find(inds, f, s, 0) if err != nil { t.Errorf("Find no elements: Improper error return") } str = eqIntSlice(inds, []int{}) if str != "" { t.Errorf("Find no non-nil: " + str) } // Test finding first two elements with non nil slice inds = []int{1, 2, 3, 4, 5, 6} inds, err = Find(inds, f, s, 2) if err != nil { t.Errorf("Find first two non-nil: Improper error return") } str = eqIntSlice(inds, trueInds) if str != "" { t.Errorf("Find first two non-nil: " + str) } // Test finding too many elements inds, err = Find(inds, f, s, 4) if err == nil { t.Errorf("Request too many: No error returned") } str = eqIntSlice(inds, allTrueInds) if str != "" { t.Errorf("Request too many: Does not match all of the inds: " + str) } // Test finding all elements inds, err = Find(nil, f, s, -1) if err != nil { t.Errorf("Find all: Improper error returned") } str = eqIntSlice(inds, allTrueInds) if str != "" { t.Errorf("Find all: Does not match all of the inds: " + str) } } func TestHasNaN(t *testing.T) { t.Parallel() for i, test := range []struct { s []float64 ans bool }{ {}, { s: []float64{1, 2, 3, 4}, }, { s: []float64{1, math.NaN(), 3, 4}, ans: true, }, { s: []float64{1, 2, 3, math.NaN()}, ans: true, }, } { b := HasNaN(test.s) if b != test.ans { t.Errorf("HasNaN mismatch case %d. Expected %v, Found %v", i, test.ans, b) } } } func TestLogSpan(t *testing.T) { t.Parallel() receiver1 := make([]float64, 6) truth := []float64{0.001, 0.01, 0.1, 1, 10, 100} receiver2 := LogSpan(receiver1, 0.001, 100) tst := make([]float64, 6) for i := range truth { tst[i] = receiver1[i] / truth[i] } comp := make([]float64, 6) for i := range comp { comp[i] = 1 } areSlicesEqual(t, comp, tst, "Improper logspace from mutator") for i := range truth { tst[i] = receiver2[i] / truth[i] } areSlicesEqual(t, comp, tst, "Improper logspace from returned slice") if !Panics(func() { LogSpan(nil, 1, 5) }) { t.Errorf("Span accepts nil argument") } if !Panics(func() { LogSpan(make([]float64, 1), 1, 5) }) { t.Errorf("Span accepts argument of len = 1") } } func TestLogSumExp(t *testing.T) { t.Parallel() s := []float64{1, 2, 3, 4, 5} val := LogSumExp(s) // http://www.wolframalpha.com/input/?i=log%28exp%281%29+%2B+exp%282%29+%2B+exp%283%29+%2B+exp%284%29+%2B+exp%285%29%29 truth := 5.4519143959375933331957225109748087179338972737576824 if math.Abs(val-truth) > EqTolerance { t.Errorf("Wrong logsumexp for many values") } s = []float64{1, 2} // http://www.wolframalpha.com/input/?i=log%28exp%281%29+%2B+exp%282%29%29 truth = 2.3132616875182228340489954949678556419152800856703483 val = LogSumExp(s) if math.Abs(val-truth) > EqTolerance { t.Errorf("Wrong logsumexp for two values. %v expected, %v found", truth, val) } // This case would normally underflow s = []float64{-1001, -1002, -1003, -1004, -1005} // http://www.wolframalpha.com/input/?i=log%28exp%28-1001%29%2Bexp%28-1002%29%2Bexp%28-1003%29%2Bexp%28-1004%29%2Bexp%28-1005%29%29 truth = -1000.54808560406240666680427748902519128206610272624 val = LogSumExp(s) if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for underflow case. %v expected, %v found", truth, val) } // positive infinite case s = []float64{1, 2, 3, 4, 5, math.Inf(1)} val = LogSumExp(s) truth = math.Inf(1) if val != truth { t.Errorf("Doesn't match for pos Infinity case. %v expected, %v found", truth, val) } // negative infinite case s = []float64{1, 2, 3, 4, 5, math.Inf(-1)} val = LogSumExp(s) truth = 5.4519143959375933331957225109748087179338972737576824 // same as first case if math.Abs(val-truth) > EqTolerance { t.Errorf("Wrong logsumexp for values with negative infinity") } } func TestMaxAndIdx(t *testing.T) { t.Parallel() for _, test := range []struct { in []float64 wantIdx int wantVal float64 desc string }{ { in: []float64{3, 4, 1, 7, 5}, wantIdx: 3, wantVal: 7, desc: "with only finite entries", }, { in: []float64{math.NaN(), 4, 1, 7, 5}, wantIdx: 3, wantVal: 7, desc: "with leading NaN", }, { in: []float64{math.NaN(), math.NaN(), math.NaN()}, wantIdx: 0, wantVal: math.NaN(), desc: "when only NaN elements exist", }, { in: []float64{math.NaN(), math.Inf(-1)}, wantIdx: 1, wantVal: math.Inf(-1), desc: "leading NaN followed by -Inf", }, { in: []float64{math.NaN(), math.Inf(1)}, wantIdx: 1, wantVal: math.Inf(1), desc: "leading NaN followed by +Inf", }, } { ind := MaxIdx(test.in) if ind != test.wantIdx { t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx) } val := Max(test.in) if !scalar.Same(val, test.wantVal) { t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal) } } if !Panics(func() { MaxIdx([]float64{}) }) { t.Errorf("Expected panic with zero length") } } func TestMinAndIdx(t *testing.T) { t.Parallel() for _, test := range []struct { in []float64 wantIdx int wantVal float64 desc string }{ { in: []float64{3, 4, 1, 7, 5}, wantIdx: 2, wantVal: 1, desc: "with only finite entries", }, { in: []float64{math.NaN(), 4, 1, 7, 5}, wantIdx: 2, wantVal: 1, desc: "with leading NaN", }, { in: []float64{math.NaN(), math.NaN(), math.NaN()}, wantIdx: 0, wantVal: math.NaN(), desc: "when only NaN elements exist", }, { in: []float64{math.NaN(), math.Inf(-1)}, wantIdx: 1, wantVal: math.Inf(-1), desc: "leading NaN followed by -Inf", }, { in: []float64{math.NaN(), math.Inf(1)}, wantIdx: 1, wantVal: math.Inf(1), desc: "leading NaN followed by +Inf", }, } { ind := MinIdx(test.in) if ind != test.wantIdx { t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx) } val := Min(test.in) if !scalar.Same(val, test.wantVal) { t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal) } } if !Panics(func() { MinIdx([]float64{}) }) { t.Errorf("Expected panic with zero length") } } func TestMul(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3} s2 := []float64{1, 2, 3} ans := []float64{1, 4, 9} Mul(s1, s2) if !EqualApprox(s1, ans, EqTolerance) { t.Errorf("Mul doesn't give correct answer") } s1short := []float64{1} if !Panics(func() { Mul(s1short, s2) }) { t.Errorf("Did not panic with unequal lengths") } s2short := []float64{1} if !Panics(func() { Mul(s1, s2short) }) { t.Errorf("Did not panic with unequal lengths") } } func TestMulTo(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3} s1orig := []float64{1, 2, 3} s2 := []float64{1, 2, 3} s2orig := []float64{1, 2, 3} dst1 := make([]float64, 3) ans := []float64{1, 4, 9} dst2 := MulTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("MulTo doesn't give correct answer in mutated slice") } if !EqualApprox(dst2, ans, EqTolerance) { t.Errorf("MulTo doesn't give correct answer in returned slice") } if !EqualApprox(s1, s1orig, EqTolerance) { t.Errorf("S1 changes during multo") } if !EqualApprox(s2, s2orig, EqTolerance) { t.Errorf("s2 changes during multo") } MulTo(dst1, s1, s2) if !EqualApprox(dst1, ans, EqTolerance) { t.Errorf("MulTo doesn't give correct answer reusing dst") } dstShort := []float64{1} if !Panics(func() { MulTo(dstShort, s1, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s1short := []float64{1} if !Panics(func() { MulTo(dst1, s1short, s2) }) { t.Errorf("Did not panic with s1 wrong length") } s2short := []float64{1} if !Panics(func() { MulTo(dst1, s1, s2short) }) { t.Errorf("Did not panic with s2 wrong length") } } func TestNearestIdx(t *testing.T) { t.Parallel() for _, test := range []struct { in []float64 query float64 want int desc string }{ { in: []float64{6.2, 3, 5, 6.2, 8}, query: 2, want: 1, desc: "Wrong index returned when value is less than all of elements", }, { in: []float64{6.2, 3, 5, 6.2, 8}, query: 9, want: 4, desc: "Wrong index returned when value is greater than all of elements", }, { in: []float64{6.2, 3, 5, 6.2, 8}, query: 3.1, want: 1, desc: "Wrong index returned when value is greater than closest element", }, { in: []float64{6.2, 3, 5, 6.2, 8}, query: 2.9, want: 1, desc: "Wrong index returned when value is less than closest element", }, { in: []float64{6.2, 3, 5, 6.2, 8}, query: 3, want: 1, desc: "Wrong index returned when value is equal to element", }, { in: []float64{6.2, 3, 5, 6.2, 8}, query: 6.2, want: 0, desc: "Wrong index returned when value is equal to several elements", }, { in: []float64{6.2, 3, 5, 6.2, 8}, query: 4, want: 1, desc: "Wrong index returned when value is exactly between two closest elements", }, { in: []float64{math.NaN(), 3, 2, -1}, query: 2, want: 2, desc: "Wrong index returned when initial element is NaN", }, { in: []float64{0, math.NaN(), -1, 2}, query: math.NaN(), want: 0, desc: "Wrong index returned when query is NaN and a NaN element exists", }, { in: []float64{0, math.NaN(), -1, 2}, query: math.Inf(1), want: 3, desc: "Wrong index returned when query is +Inf and no +Inf element exists", }, { in: []float64{0, math.NaN(), -1, 2}, query: math.Inf(-1), want: 2, desc: "Wrong index returned when query is -Inf and no -Inf element exists", }, { in: []float64{math.NaN(), math.NaN(), math.NaN()}, query: 1, want: 0, desc: "Wrong index returned when query is a number and only NaN elements exist", }, { in: []float64{math.NaN(), math.Inf(-1)}, query: 1, want: 1, desc: "Wrong index returned when query is a number and single NaN precedes -Inf", }, } { ind := NearestIdx(test.in, test.query) if ind != test.want { t.Errorf(test.desc+": got:%d want:%d", ind, test.want) } } if !Panics(func() { NearestIdx([]float64{}, 0) }) { t.Errorf("Expected panic with zero length") } } func TestNearestIdxForSpan(t *testing.T) { t.Parallel() for i, test := range []struct { length int lower float64 upper float64 value float64 idx int }{ { length: 13, lower: 7, upper: 8.2, value: 6, idx: 0, }, { length: 13, lower: 7, upper: 8.2, value: 10, idx: 12, }, { length: 13, lower: 7, upper: 8.2, value: 7.19, idx: 2, }, { length: 13, lower: 7, upper: 8.2, value: 7.21, idx: 2, }, { length: 13, lower: 7, upper: 8.2, value: 7.2, idx: 2, }, { length: 13, lower: 7, upper: 8.2, value: 7.151, idx: 2, }, { length: 13, lower: 7, upper: 8.2, value: 7.249, idx: 2, }, { length: 4, lower: math.Inf(-1), upper: math.Inf(1), value: math.Copysign(0, -1), idx: 0, }, { length: 5, lower: math.Inf(-1), upper: math.Inf(1), value: 0, idx: 2, }, { length: 5, lower: math.Inf(-1), upper: math.Inf(1), value: math.Inf(-1), idx: 0, }, { length: 5, lower: math.Inf(-1), upper: math.Inf(1), value: math.Inf(1), idx: 3, }, { length: 4, lower: math.Inf(-1), upper: math.Inf(1), value: 0, idx: 2, }, { length: 4, lower: math.Inf(-1), upper: math.Inf(1), value: math.Inf(1), idx: 2, }, { length: 4, lower: math.Inf(-1), upper: math.Inf(1), value: math.Inf(-1), idx: 0, }, { length: 5, lower: math.Inf(1), upper: math.Inf(1), value: 1, idx: 0, }, { length: 5, lower: math.NaN(), upper: math.NaN(), value: 1, idx: 0, }, { length: 5, lower: 0, upper: 1, value: math.NaN(), idx: 0, }, { length: 5, lower: math.NaN(), upper: 1, value: 0, idx: 4, }, { length: 5, lower: math.Inf(-1), upper: 1, value: math.Inf(-1), idx: 0, }, { length: 5, lower: math.Inf(-1), upper: 1, value: 0, idx: 4, }, { length: 5, lower: math.Inf(1), upper: 1, value: math.Inf(1), idx: 0, }, { length: 5, lower: math.Inf(1), upper: 1, value: 0, idx: 4, }, { length: 5, lower: 100, upper: math.Inf(-1), value: math.Inf(-1), idx: 4, }, { length: 5, lower: 100, upper: math.Inf(-1), value: 200, idx: 0, }, { length: 5, lower: 100, upper: math.Inf(1), value: math.Inf(1), idx: 4, }, { length: 5, lower: 100, upper: math.Inf(1), value: 200, idx: 0, }, { length: 5, lower: -1, upper: 2, value: math.Inf(-1), idx: 0, }, { length: 5, lower: -1, upper: 2, value: math.Inf(1), idx: 4, }, { length: 5, lower: 1, upper: -2, value: math.Inf(-1), idx: 4, }, { length: 5, lower: 1, upper: -2, value: math.Inf(1), idx: 0, }, { length: 5, lower: 2, upper: 0, value: 3, idx: 0, }, { length: 5, lower: 2, upper: 0, value: -1, idx: 4, }, } { if idx := NearestIdxForSpan(test.length, test.lower, test.upper, test.value); test.idx != idx { t.Errorf("Case %v mismatch: Want: %v, Got: %v", i, test.idx, idx) } } if !Panics(func() { NearestIdxForSpan(1, 0, 1, 0.5) }) { t.Errorf("Expected panic for short span length") } } func TestNorm(t *testing.T) { t.Parallel() s := []float64{-1, -3.4, 5, -6} val := Norm(s, math.Inf(1)) truth := 6.0 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } // http://www.wolframalpha.com/input/?i=%28%28-1%29%5E2+%2B++%28-3.4%29%5E2+%2B+5%5E2%2B++6%5E2%29%5E%281%2F2%29 val = Norm(s, 2) truth = 8.5767126569566267590651614132751986658027271236078592 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } // http://www.wolframalpha.com/input/?i=%28%28%7C-1%7C%29%5E3+%2B++%28%7C-3.4%7C%29%5E3+%2B+%7C5%7C%5E3%2B++%7C6%7C%5E3%29%5E%281%2F3%29 val = Norm(s, 3) truth = 7.2514321388020228478109121239004816430071237369356233 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } //http://www.wolframalpha.com/input/?i=%7C-1%7C+%2B+%7C-3.4%7C+%2B+%7C5%7C%2B++%7C6%7C val = Norm(s, 1) truth = 15.4 if math.Abs(val-truth) > EqTolerance { t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) } } func TestProd(t *testing.T) { t.Parallel() s := []float64{} val := Prod(s) if val != 1 { t.Errorf("Val not returned as default when slice length is zero") } s = []float64{3, 4, 1, 7, 5} val = Prod(s) if val != 420 { t.Errorf("Wrong prod returned. Expected %v returned %v", 420, val) } } func TestReverse(t *testing.T) { t.Parallel() for _, s := range [][]float64{ {0}, {1, 0}, {2, 1, 0}, {3, 2, 1, 0}, {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, } { Reverse(s) for i, v := range s { if v != float64(i) { t.Errorf("unexpected values for element %d: got:%v want:%v", i, v, i) } } } } func TestSame(t *testing.T) { t.Parallel() s1 := []float64{1, 2, 3, 4} s2 := []float64{1, 2, 3, 4} if !Same(s1, s2) { t.Errorf("Equal slices returned as unequal") } s2 = []float64{1, 2, 3, 4 + 1e-14} if Same(s1, s2) { t.Errorf("Unequal slices returned as equal") } if Same(s1, []float64{}) { t.Errorf("Unequal slice lengths returned as equal") } s1 = []float64{1, 2, math.NaN(), 4} s2 = []float64{1, 2, math.NaN(), 4} if !Same(s1, s2) { t.Errorf("Slices with matching NaN values returned as unequal") } s1 = []float64{1, 2, math.NaN(), 4} s2 = []float64{1, math.NaN(), 3, 4} if Same(s1, s2) { t.Errorf("Slices with unmatching NaN values returned as equal") } } func TestScale(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} c := 5.0 truth := []float64{15, 20, 5, 35, 25} Scale(c, s) areSlicesEqual(t, truth, s, "Bad scaling") } func TestScaleTo(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} sCopy := make([]float64, len(s)) copy(sCopy, s) c := 5.0 truth := []float64{15, 20, 5, 35, 25} dst := make([]float64, len(s)) ScaleTo(dst, c, s) if !Same(dst, truth) { t.Errorf("Scale to does not match. Got %v, want %v", dst, truth) } if !Same(s, sCopy) { t.Errorf("Source modified during call. Got %v, want %v", s, sCopy) } if !Panics(func() { ScaleTo(dst, 0, []float64{1}) }) { t.Errorf("Expected panic with different slice lengths") } } func TestSpan(t *testing.T) { t.Parallel() receiver1 := make([]float64, 5) truth := []float64{1, 2, 3, 4, 5} receiver2 := Span(receiver1, 1, 5) areSlicesEqual(t, truth, receiver1, "Improper linspace from mutator") areSlicesEqual(t, truth, receiver2, "Improper linspace from returned slice") receiver1 = make([]float64, 6) truth = []float64{0, 0.2, 0.4, 0.6, 0.8, 1.0} Span(receiver1, 0, 1) areSlicesEqual(t, truth, receiver1, "Improper linspace") if !Panics(func() { Span(nil, 1, 5) }) { t.Errorf("Span accepts nil argument") } if !Panics(func() { Span(make([]float64, 1), 1, 5) }) { t.Errorf("Span accepts argument of len = 1") } for _, test := range []struct { n int l, u float64 want []float64 }{ { n: 4, l: math.Inf(-1), u: math.Inf(1), want: []float64{math.Inf(-1), math.Inf(-1), math.Inf(1), math.Inf(1)}, }, { n: 4, l: math.Inf(1), u: math.Inf(-1), want: []float64{math.Inf(1), math.Inf(1), math.Inf(-1), math.Inf(-1)}, }, { n: 5, l: math.Inf(-1), u: math.Inf(1), want: []float64{math.Inf(-1), math.Inf(-1), 0, math.Inf(1), math.Inf(1)}, }, { n: 5, l: math.Inf(1), u: math.Inf(-1), want: []float64{math.Inf(1), math.Inf(1), 0, math.Inf(-1), math.Inf(-1)}, }, { n: 5, l: math.Inf(1), u: math.Inf(1), want: []float64{math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1)}, }, { n: 5, l: math.Inf(-1), u: math.Inf(-1), want: []float64{math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1)}, }, { n: 5, l: math.Inf(-1), u: math.NaN(), want: []float64{math.Inf(-1), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, { n: 5, l: math.Inf(1), u: math.NaN(), want: []float64{math.Inf(1), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, { n: 5, l: math.NaN(), u: math.Inf(-1), want: []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.Inf(-1)}, }, { n: 5, l: math.NaN(), u: math.Inf(1), want: []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.Inf(1)}, }, { n: 5, l: 42, u: math.Inf(-1), want: []float64{42, math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1)}, }, { n: 5, l: 42, u: math.Inf(1), want: []float64{42, math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1)}, }, { n: 5, l: 42, u: math.NaN(), want: []float64{42, math.NaN(), math.NaN(), math.NaN(), math.NaN()}, }, { n: 5, l: math.Inf(-1), u: 42, want: []float64{math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1), 42}, }, { n: 5, l: math.Inf(1), u: 42, want: []float64{math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1), 42}, }, { n: 5, l: math.NaN(), u: 42, want: []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), 42}, }, } { got := Span(make([]float64, test.n), test.l, test.u) areSlicesSame(t, test.want, got, fmt.Sprintf("Unexpected slice of length %d for %f to %f", test.n, test.l, test.u)) } } func TestSub(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} v := []float64{1, 2, 3, 4, 5} truth := []float64{2, 2, -2, 3, 0} Sub(s, v) areSlicesEqual(t, truth, s, "Bad subtract") // Test that it panics if !Panics(func() { Sub(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Did not panic with length mismatch") } } func TestSubTo(t *testing.T) { t.Parallel() s := []float64{3, 4, 1, 7, 5} v := []float64{1, 2, 3, 4, 5} truth := []float64{2, 2, -2, 3, 0} dst1 := make([]float64, len(s)) dst2 := SubTo(dst1, s, v) areSlicesEqual(t, truth, dst1, "Bad subtract from mutator") areSlicesEqual(t, truth, dst2, "Bad subtract from returned slice") // Test that all mismatch combinations panic if !Panics(func() { SubTo(make([]float64, 2), make([]float64, 3), make([]float64, 3)) }) { t.Errorf("Did not panic with dst different length") } if !Panics(func() { SubTo(make([]float64, 3), make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Did not panic with subtractor different length") } if !Panics(func() { SubTo(make([]float64, 3), make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Did not panic with subtractee different length") } } func TestSum(t *testing.T) { t.Parallel() s := []float64{} val := Sum(s) if val != 0 { t.Errorf("Val not returned as default when slice length is zero") } s = []float64{3, 4, 1, 7, 5} val = Sum(s) if val != 20 { t.Errorf("Wrong sum returned") } } func TestWithin(t *testing.T) { t.Parallel() for i, test := range []struct { s []float64 v float64 idx int panics bool }{ { s: []float64{1, 2, 5, 9}, v: 1, idx: 0, }, { s: []float64{1, 2, 5, 9}, v: 9, idx: -1, }, { s: []float64{1, 2, 5, 9}, v: 1.5, idx: 0, }, { s: []float64{1, 2, 5, 9}, v: 2, idx: 1, }, { s: []float64{1, 2, 5, 9}, v: 2.5, idx: 1, }, { s: []float64{1, 2, 5, 9}, v: -3, idx: -1, }, { s: []float64{1, 2, 5, 9}, v: 15, idx: -1, }, { s: []float64{1, 2, 5, 9}, v: math.NaN(), idx: -1, }, { s: []float64{5, 2, 6}, panics: true, }, { panics: true, }, { s: []float64{1}, panics: true, }, } { var idx int panics := Panics(func() { idx = Within(test.s, test.v) }) if panics { if !test.panics { t.Errorf("Case %v: bad panic", i) } continue } if test.panics { if !panics { t.Errorf("Case %v: did not panic when it should", i) } continue } if idx != test.idx { t.Errorf("Case %v: Idx mismatch. Want: %v, got: %v", i, test.idx, idx) } } } func TestSumCompensated(t *testing.T) { t.Parallel() k := 100000 s1 := make([]float64, 2*k+1) for i := -k; i <= k; i++ { s1[i+k] = 0.2 * float64(i) } s2 := make([]float64, k+1) for i := 0; i < k; i++ { s2[i] = 10. / float64(k) } s2[k] = -10 for i, test := range []struct { s []float64 want float64 }{ { // Fails if we use simple Sum. s: s1, want: 0, }, { // Fails if we use simple Sum. s: s2, want: 0, }, { s: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, want: 55, }, { s: []float64{1.2e20, 0.1, -2.4e20, -0.1, 1.2e20, 0.2, 0.2}, want: 0.4, }, { s: []float64{1, 1e100, 1, -1e100}, want: 2, }, } { got := SumCompensated(test.s) if math.Abs(got-test.want) > EqTolerance { t.Errorf("Wrong sum returned in test case %d. Want: %g, got: %g", i, test.want, got) } } } func randomSlice(l int, src rand.Source) []float64 { rnd := rand.New(src) s := make([]float64, l) for i := range s { s[i] = rnd.Float64() } return s } func benchmarkMin(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Min(s) } } func BenchmarkMinSmall(b *testing.B) { benchmarkMin(b, Small) } func BenchmarkMinMed(b *testing.B) { benchmarkMin(b, Medium) } func BenchmarkMinLarge(b *testing.B) { benchmarkMin(b, Large) } func BenchmarkMinHuge(b *testing.B) { benchmarkMin(b, Huge) } func benchmarkAdd(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Add(s1, s2) } } func BenchmarkAddSmall(b *testing.B) { benchmarkAdd(b, Small) } func BenchmarkAddMed(b *testing.B) { benchmarkAdd(b, Medium) } func BenchmarkAddLarge(b *testing.B) { benchmarkAdd(b, Large) } func BenchmarkAddHuge(b *testing.B) { benchmarkAdd(b, Huge) } func benchmarkAddTo(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { AddTo(dst, s1, s2) } } func BenchmarkAddToSmall(b *testing.B) { benchmarkAddTo(b, Small) } func BenchmarkAddToMed(b *testing.B) { benchmarkAddTo(b, Medium) } func BenchmarkAddToLarge(b *testing.B) { benchmarkAddTo(b, Large) } func BenchmarkAddToHuge(b *testing.B) { benchmarkAddTo(b, Huge) } func benchmarkCumProd(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { CumProd(dst, s) } } func BenchmarkCumProdSmall(b *testing.B) { benchmarkCumProd(b, Small) } func BenchmarkCumProdMed(b *testing.B) { benchmarkCumProd(b, Medium) } func BenchmarkCumProdLarge(b *testing.B) { benchmarkCumProd(b, Large) } func BenchmarkCumProdHuge(b *testing.B) { benchmarkCumProd(b, Huge) } func benchmarkCumSum(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { CumSum(dst, s) } } func BenchmarkCumSumSmall(b *testing.B) { benchmarkCumSum(b, Small) } func BenchmarkCumSumMed(b *testing.B) { benchmarkCumSum(b, Medium) } func BenchmarkCumSumLarge(b *testing.B) { benchmarkCumSum(b, Large) } func BenchmarkCumSumHuge(b *testing.B) { benchmarkCumSum(b, Huge) } func benchmarkDiv(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Div(dst, s) } } func BenchmarkDivSmall(b *testing.B) { benchmarkDiv(b, Small) } func BenchmarkDivMed(b *testing.B) { benchmarkDiv(b, Medium) } func BenchmarkDivLarge(b *testing.B) { benchmarkDiv(b, Large) } func BenchmarkDivHuge(b *testing.B) { benchmarkDiv(b, Huge) } func benchmarkDivTo(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { DivTo(dst, s1, s2) } } func BenchmarkDivToSmall(b *testing.B) { benchmarkDivTo(b, Small) } func BenchmarkDivToMed(b *testing.B) { benchmarkDivTo(b, Medium) } func BenchmarkDivToLarge(b *testing.B) { benchmarkDivTo(b, Large) } func BenchmarkDivToHuge(b *testing.B) { benchmarkDivTo(b, Huge) } func benchmarkSub(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Sub(s1, s2) } } func BenchmarkSubSmall(b *testing.B) { benchmarkSub(b, Small) } func BenchmarkSubMed(b *testing.B) { benchmarkSub(b, Medium) } func BenchmarkSubLarge(b *testing.B) { benchmarkSub(b, Large) } func BenchmarkSubHuge(b *testing.B) { benchmarkSub(b, Huge) } func benchmarkSubTo(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { SubTo(dst, s1, s2) } } func BenchmarkSubToSmall(b *testing.B) { benchmarkSubTo(b, Small) } func BenchmarkSubToMed(b *testing.B) { benchmarkSubTo(b, Medium) } func BenchmarkSubToLarge(b *testing.B) { benchmarkSubTo(b, Large) } func BenchmarkSubToHuge(b *testing.B) { benchmarkSubTo(b, Huge) } func benchmarkLogSumExp(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { LogSumExp(s) } } func BenchmarkLogSumExpSmall(b *testing.B) { benchmarkLogSumExp(b, Small) } func BenchmarkLogSumExpMed(b *testing.B) { benchmarkLogSumExp(b, Medium) } func BenchmarkLogSumExpLarge(b *testing.B) { benchmarkLogSumExp(b, Large) } func BenchmarkLogSumExpHuge(b *testing.B) { benchmarkLogSumExp(b, Huge) } func benchmarkDot(b *testing.B, size int) { src := rand.NewSource(1) s1 := randomSlice(size, src) s2 := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Dot(s1, s2) } } func BenchmarkDotSmall(b *testing.B) { benchmarkDot(b, Small) } func BenchmarkDotMed(b *testing.B) { benchmarkDot(b, Medium) } func BenchmarkDotLarge(b *testing.B) { benchmarkDot(b, Large) } func BenchmarkDotHuge(b *testing.B) { benchmarkDot(b, Huge) } func benchmarkAddScaledTo(b *testing.B, size int) { src := rand.NewSource(1) dst := randomSlice(size, src) y := randomSlice(size, src) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { AddScaledTo(dst, y, 2.3, s) } } func BenchmarkAddScaledToSmall(b *testing.B) { benchmarkAddScaledTo(b, Small) } func BenchmarkAddScaledToMedium(b *testing.B) { benchmarkAddScaledTo(b, Medium) } func BenchmarkAddScaledToLarge(b *testing.B) { benchmarkAddScaledTo(b, Large) } func BenchmarkAddScaledToHuge(b *testing.B) { benchmarkAddScaledTo(b, Huge) } func benchmarkScale(b *testing.B, size int) { src := rand.NewSource(1) dst := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i += 2 { Scale(2.0, dst) Scale(0.5, dst) } } func BenchmarkScaleSmall(b *testing.B) { benchmarkScale(b, Small) } func BenchmarkScaleMedium(b *testing.B) { benchmarkScale(b, Medium) } func BenchmarkScaleLarge(b *testing.B) { benchmarkScale(b, Large) } func BenchmarkScaleHuge(b *testing.B) { benchmarkScale(b, Huge) } func benchmarkNorm2(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Norm(s, 2) } } func BenchmarkNorm2Small(b *testing.B) { benchmarkNorm2(b, Small) } func BenchmarkNorm2Medium(b *testing.B) { benchmarkNorm2(b, Medium) } func BenchmarkNorm2Large(b *testing.B) { benchmarkNorm2(b, Large) } func BenchmarkNorm2Huge(b *testing.B) { benchmarkNorm2(b, Huge) } func benchmarkSumCompensated(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { SumCompensated(s) } } func BenchmarkSumCompensatedSmall(b *testing.B) { benchmarkSumCompensated(b, Small) } func BenchmarkSumCompensatedMedium(b *testing.B) { benchmarkSumCompensated(b, Medium) } func BenchmarkSumCompensatedLarge(b *testing.B) { benchmarkSumCompensated(b, Large) } func BenchmarkSumCompensatedHuge(b *testing.B) { benchmarkSumCompensated(b, Huge) } func benchmarkSum(b *testing.B, size int) { src := rand.NewSource(1) s := randomSlice(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { Sum(s) } } func BenchmarkSumSmall(b *testing.B) { benchmarkSum(b, Small) } func BenchmarkSumMedium(b *testing.B) { benchmarkSum(b, Medium) } func BenchmarkSumLarge(b *testing.B) { benchmarkSum(b, Large) } func BenchmarkSumHuge(b *testing.B) { benchmarkSum(b, Huge) } golang-gonum-v1-gonum-0.14.0/floats/scalar/000077500000000000000000000000001450372207100203735ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/floats/scalar/doc.go000066400000000000000000000004661450372207100214750ustar00rootroot00000000000000// 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 scalar provides a set of helper routines for dealing with float64 values. package scalar // import "gonum.org/v1/gonum/floats/scalar" golang-gonum-v1-gonum-0.14.0/floats/scalar/parse_example_test.go000066400000000000000000000014201450372207100246030ustar00rootroot00000000000000// Copyright ©2017 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 scalar_test import ( "bufio" "fmt" "log" "strings" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/stat" ) func ExampleParseWithNA() { // Calculate the mean of a list of numbers // ignoring missing values. const data = `6 missing 4 ` var vals, weights []float64 sc := bufio.NewScanner(strings.NewReader(data)) for sc.Scan() { v, w, err := scalar.ParseWithNA(sc.Text(), "missing") if err != nil { log.Fatal(err) } vals = append(vals, v) weights = append(weights, w) } err := sc.Err() if err != nil { log.Fatal(err) } fmt.Println(stat.Mean(vals, weights)) // Output: // 5 } golang-gonum-v1-gonum-0.14.0/floats/scalar/scalar.go000066400000000000000000000104161450372207100221710ustar00rootroot00000000000000// 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 scalar import ( "math" "strconv" ) // EqualWithinAbs returns true when a and b have an absolute difference // not greater than tol. func EqualWithinAbs(a, b, tol float64) bool { return a == b || math.Abs(a-b) <= tol } // minNormalFloat64 is the smallest normal number. For 64 bit IEEE-754 // floats this is 2^{-1022}. const minNormalFloat64 = 0x1p-1022 // EqualWithinRel returns true when the difference between a and b // is not greater than tol times the greater absolute value of a and b, // // abs(a-b) <= tol * max(abs(a), abs(b)). 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 when a and b are equal to within // the absolute or relative tolerances. See EqualWithinAbs and // EqualWithinRel for details. func EqualWithinAbsOrRel(a, b, absTol, relTol float64) bool { return EqualWithinAbs(a, b, absTol) || EqualWithinRel(a, b, relTol) } // EqualWithinULP returns true when 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 } 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 } // ParseWithNA converts the string s to a float64 in value. // If s equals missing, weight is returned as 0, otherwise 1. func ParseWithNA(s, missing string) (value, weight float64, err error) { if s == missing { return 0, 0, nil } value, err = strconv.ParseFloat(s, 64) if err == nil { weight = 1 } return value, weight, err } // 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 } x = math.Round(intermed) 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 } x = math.RoundToEven(intermed) if x == 0 { return 0 } return x / pow } // Same returns true when the inputs have the same value, allowing NaN equality. func Same(a, b float64) bool { return a == b || (math.IsNaN(a) && math.IsNaN(b)) } golang-gonum-v1-gonum-0.14.0/floats/scalar/scalar_test.go000066400000000000000000000276041450372207100232370ustar00rootroot00000000000000// 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 scalar import ( "math" "testing" ) func TestEqualsRelative(t *testing.T) { t.Parallel() equalityTests := []struct { a, b float64 tol float64 equal bool }{ {1000000, 1000001, 0, true}, {1000001, 1000000, 0, true}, {10000, 10001, 0, false}, {10001, 10000, 0, false}, {-1000000, -1000001, 0, true}, {-1000001, -1000000, 0, true}, {-10000, -10001, 0, false}, {-10001, -10000, 0, false}, {1.0000001, 1.0000002, 0, true}, {1.0000002, 1.0000001, 0, true}, {1.0002, 1.0001, 0, false}, {1.0001, 1.0002, 0, false}, {-1.000001, -1.000002, 0, true}, {-1.000002, -1.000001, 0, true}, {-1.0001, -1.0002, 0, false}, {-1.0002, -1.0001, 0, false}, {0.000000001000001, 0.000000001000002, 0, true}, {0.000000001000002, 0.000000001000001, 0, true}, {0.000000000001002, 0.000000000001001, 0, false}, {0.000000000001001, 0.000000000001002, 0, false}, {-0.000000001000001, -0.000000001000002, 0, true}, {-0.000000001000002, -0.000000001000001, 0, true}, {-0.000000000001002, -0.000000000001001, 0, false}, {-0.000000000001001, -0.000000000001002, 0, false}, {0, 0, 0, true}, {0, -0, 0, true}, {-0, -0, 0, true}, {0.00000001, 0, 0, false}, {0, 0.00000001, 0, false}, {-0.00000001, 0, 0, false}, {0, -0.00000001, 0, false}, {0, 1e-310, 0.01, true}, {1e-310, 0, 0.01, true}, {1e-310, 0, 0.000001, false}, {0, 1e-310, 0.000001, false}, {0, -1e-310, 0.1, true}, {-1e-310, 0, 0.1, true}, {-1e-310, 0, 0.00000001, false}, {0, -1e-310, 0.00000001, false}, {math.Inf(1), math.Inf(1), 0, true}, {math.Inf(-1), math.Inf(-1), 0, true}, {math.Inf(-1), math.Inf(1), 0, false}, {math.Inf(1), math.MaxFloat64, 0, false}, {math.Inf(-1), -math.MaxFloat64, 0, false}, {math.NaN(), math.NaN(), 0, false}, {math.NaN(), 0, 0, false}, {-0, math.NaN(), 0, false}, {math.NaN(), -0, 0, false}, {0, math.NaN(), 0, false}, {math.NaN(), math.Inf(1), 0, false}, {math.Inf(1), math.NaN(), 0, false}, {math.NaN(), math.Inf(-1), 0, false}, {math.Inf(-1), math.NaN(), 0, false}, {math.NaN(), math.MaxFloat64, 0, false}, {math.MaxFloat64, math.NaN(), 0, false}, {math.NaN(), -math.MaxFloat64, 0, false}, {-math.MaxFloat64, math.NaN(), 0, false}, {math.NaN(), math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, math.NaN(), 0, false}, {math.NaN(), -math.SmallestNonzeroFloat64, 0, false}, {-math.SmallestNonzeroFloat64, math.NaN(), 0, false}, {1.000000001, -1.0, 0, false}, {-1.0, 1.000000001, 0, false}, {-1.000000001, 1.0, 0, false}, {1.0, -1.000000001, 0, false}, {10 * math.SmallestNonzeroFloat64, 10 * -math.SmallestNonzeroFloat64, 0, true}, {1e11 * math.SmallestNonzeroFloat64, 1e11 * -math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, -math.SmallestNonzeroFloat64, 0, true}, {-math.SmallestNonzeroFloat64, math.SmallestNonzeroFloat64, 0, true}, {math.SmallestNonzeroFloat64, 0, 0, true}, {0, math.SmallestNonzeroFloat64, 0, true}, {-math.SmallestNonzeroFloat64, 0, 0, true}, {0, -math.SmallestNonzeroFloat64, 0, true}, {0.000000001, -math.SmallestNonzeroFloat64, 0, false}, {0.000000001, math.SmallestNonzeroFloat64, 0, false}, {math.SmallestNonzeroFloat64, 0.000000001, 0, false}, {-math.SmallestNonzeroFloat64, 0.000000001, 0, false}, } for _, ts := range equalityTests { if ts.tol == 0 { ts.tol = 1e-5 } if equal := EqualWithinRel(ts.a, ts.b, ts.tol); equal != ts.equal { t.Errorf("Relative equality of %g and %g with tolerance %g returned: %v. Expected: %v", ts.a, ts.b, ts.tol, equal, ts.equal) } } } func TestEqualsULP(t *testing.T) { t.Parallel() if f := 67329.242; !EqualWithinULP(f, nextAfterN(f, math.Inf(1), 10), 10) { t.Errorf("Equal values returned as unequal") } if f := 67329.242; EqualWithinULP(f, nextAfterN(f, math.Inf(1), 5), 1) { t.Errorf("Unequal values returned as equal") } if f := 67329.242; EqualWithinULP(nextAfterN(f, math.Inf(1), 5), f, 1) { t.Errorf("Unequal values returned as equal") } if f := nextAfterN(0, math.Inf(1), 2); !EqualWithinULP(f, nextAfterN(f, math.Inf(-1), 5), 10) { t.Errorf("Equal values returned as unequal") } if !EqualWithinULP(67329.242, 67329.242, 10) { t.Errorf("Equal float64s not returned as equal") } if EqualWithinULP(1, math.NaN(), 10) { t.Errorf("NaN returned as equal") } } func nextAfterN(x, y float64, n int) float64 { for i := 0; i < n; i++ { x = math.Nextafter(x, y) } return x } func TestNaNWith(t *testing.T) { t.Parallel() tests := []struct { payload uint64 bits uint64 }{ {0, math.Float64bits(0 / func() float64 { return 0 }())}, // Hide the division by zero from the compiler. {1, math.Float64bits(math.NaN())}, {1954, 0x7ff80000000007a2}, // R NA. } for _, test := range tests { nan := NaNWith(test.payload) if !math.IsNaN(nan) { t.Errorf("expected NaN value, got:%f", nan) } bits := math.Float64bits(nan) // Strip sign bit. const sign = 1 << 63 bits &^= sign test.bits &^= sign if bits != test.bits { t.Errorf("expected NaN bit representation: got:%x want:%x", bits, test.bits) } } } func TestNaNPayload(t *testing.T) { t.Parallel() tests := []struct { f float64 payload uint64 ok bool }{ {0 / func() float64 { return 0 }(), 0, true}, // Hide the division by zero from the compiler. // The following two line are written explicitly to defend against potential changes to math.Copysign. {math.Float64frombits(math.Float64bits(math.NaN()) | (1 << 63)), 1, true}, // math.Copysign(math.NaN(), -1) {math.Float64frombits(math.Float64bits(math.NaN()) &^ (1 << 63)), 1, true}, // math.Copysign(math.NaN(), 1) {NaNWith(1954), 1954, true}, // R NA. {math.Copysign(0, -1), 0, false}, {0, 0, false}, {math.Inf(-1), 0, false}, {math.Inf(1), 0, false}, {math.Float64frombits(0x7ff0000000000001), 0, false}, // Signalling NaN. } for _, test := range tests { payload, ok := NaNPayload(test.f) if payload != test.payload { t.Errorf("expected NaN payload: got:%x want:%x", payload, test.payload) } if ok != test.ok { t.Errorf("expected NaN status: got:%t want:%t", ok, test.ok) } } } func TestRound(t *testing.T) { t.Parallel() for _, test := range []struct { x float64 prec int want float64 }{ {x: 0, prec: 1, want: 0}, {x: math.Inf(1), prec: 1, want: math.Inf(1)}, {x: math.Inf(-1), prec: 1, want: math.Inf(-1)}, {x: math.NaN(), prec: 1, want: math.NaN()}, {x: func() float64 { var f float64; return -f }(), prec: 1, want: 0}, {x: math.MaxFloat64 / 2, prec: 1, want: math.MaxFloat64 / 2}, {x: 1 << 64, prec: 1, want: 1 << 64}, {x: 454.4445, prec: 3, want: 454.445}, {x: 454.44445, prec: 4, want: 454.4445}, {x: 0.42499, prec: 4, want: 0.425}, {x: 0.42599, prec: 4, want: 0.426}, {x: 0.424999999999993, prec: 2, want: 0.42}, {x: 0.425, prec: 2, want: 0.43}, {x: 0.425000000000001, prec: 2, want: 0.43}, {x: 123.4244999999999, prec: 3, want: 123.424}, {x: 123.4245, prec: 3, want: 123.425}, {x: 123.4245000000001, prec: 3, want: 123.425}, {x: -0.49999999999999994, prec: 0, want: 0}, {x: 0.49999999999999994, prec: 0, want: 0}, {x: 454.45, prec: 0, want: 454}, {x: 454.45, prec: 1, want: 454.5}, {x: 454.45, prec: 2, want: 454.45}, {x: 454.45, prec: 3, want: 454.45}, {x: 454.445, prec: 0, want: 454}, {x: 454.445, prec: 1, want: 454.4}, {x: 454.445, prec: 2, want: 454.45}, {x: 454.445, prec: 3, want: 454.445}, {x: 454.445, prec: 4, want: 454.445}, {x: 454.55, prec: 0, want: 455}, {x: 454.55, prec: 1, want: 454.6}, {x: 454.55, prec: 2, want: 454.55}, {x: 454.55, prec: 3, want: 454.55}, {x: 454.455, prec: 0, want: 454}, {x: 454.455, prec: 1, want: 454.5}, {x: 454.455, prec: 2, want: 454.46}, {x: 454.455, prec: 3, want: 454.455}, {x: 454.455, prec: 4, want: 454.455}, // Negative precision. {x: math.Inf(1), prec: -1, want: math.Inf(1)}, {x: math.Inf(-1), prec: -1, want: math.Inf(-1)}, {x: math.NaN(), prec: -1, want: math.NaN()}, {x: func() float64 { var f float64; return -f }(), prec: -1, want: 0}, {x: 454.45, prec: -1, want: 450}, {x: 454.45, prec: -2, want: 500}, {x: 500, prec: -3, want: 1000}, {x: 500, prec: -4, want: 0}, {x: 1500, prec: -3, want: 2000}, {x: 1500, prec: -4, want: 0}, } { for _, sign := range []float64{1, -1} { got := Round(sign*test.x, test.prec) want := sign * test.want if want == 0 { want = 0 } if (got != want || math.Signbit(got) != math.Signbit(want)) && !(math.IsNaN(got) && math.IsNaN(want)) { t.Errorf("unexpected result for Round(%g, %d): got: %g, want: %g", sign*test.x, test.prec, got, want) } } } } func TestRoundEven(t *testing.T) { t.Parallel() for _, test := range []struct { x float64 prec int want float64 }{ {x: 0, prec: 1, want: 0}, {x: math.Inf(1), prec: 1, want: math.Inf(1)}, {x: math.Inf(-1), prec: 1, want: math.Inf(-1)}, {x: math.NaN(), prec: 1, want: math.NaN()}, {x: func() float64 { var f float64; return -f }(), prec: 1, want: 0}, {x: math.MaxFloat64 / 2, prec: 1, want: math.MaxFloat64 / 2}, {x: 1 << 64, prec: 1, want: 1 << 64}, {x: 454.4445, prec: 3, want: 454.444}, {x: 454.44445, prec: 4, want: 454.4444}, {x: 0.42499, prec: 4, want: 0.425}, {x: 0.42599, prec: 4, want: 0.426}, {x: 0.424999999999993, prec: 2, want: 0.42}, {x: 0.425, prec: 2, want: 0.42}, {x: 0.425000000000001, prec: 2, want: 0.43}, {x: 123.4244999999999, prec: 3, want: 123.424}, {x: 123.4245, prec: 3, want: 123.424}, {x: 123.4245000000001, prec: 3, want: 123.425}, {x: -0.49999999999999994, prec: 0, want: 0}, {x: 0.49999999999999994, prec: 0, want: 0}, {x: 454.45, prec: 0, want: 454}, {x: 454.45, prec: 1, want: 454.4}, {x: 454.45, prec: 2, want: 454.45}, {x: 454.45, prec: 3, want: 454.45}, {x: 454.445, prec: 0, want: 454}, {x: 454.445, prec: 1, want: 454.4}, {x: 454.445, prec: 2, want: 454.44}, {x: 454.445, prec: 3, want: 454.445}, {x: 454.445, prec: 4, want: 454.445}, {x: 454.55, prec: 0, want: 455}, {x: 454.55, prec: 1, want: 454.6}, {x: 454.55, prec: 2, want: 454.55}, {x: 454.55, prec: 3, want: 454.55}, {x: 454.455, prec: 0, want: 454}, {x: 454.455, prec: 1, want: 454.5}, {x: 454.455, prec: 2, want: 454.46}, {x: 454.455, prec: 3, want: 454.455}, {x: 454.455, prec: 4, want: 454.455}, // Negative precision. {x: math.Inf(1), prec: -1, want: math.Inf(1)}, {x: math.Inf(-1), prec: -1, want: math.Inf(-1)}, {x: math.NaN(), prec: -1, want: math.NaN()}, {x: func() float64 { var f float64; return -f }(), prec: -1, want: 0}, {x: 454.45, prec: -1, want: 450}, {x: 454.45, prec: -2, want: 500}, {x: 500, prec: -3, want: 0}, {x: 500, prec: -4, want: 0}, {x: 1500, prec: -3, want: 2000}, {x: 1500, prec: -4, want: 0}, } { for _, sign := range []float64{1, -1} { got := RoundEven(sign*test.x, test.prec) want := sign * test.want if want == 0 { want = 0 } if (got != want || math.Signbit(got) != math.Signbit(want)) && !(math.IsNaN(got) && math.IsNaN(want)) { t.Errorf("unexpected result for RoundEven(%g, %d): got: %g, want: %g", sign*test.x, test.prec, got, want) } } } } func TestSame(t *testing.T) { t.Parallel() for _, test := range []struct { a, b float64 want bool }{ {a: 0, b: 0, want: true}, {a: 1, b: 1, want: true}, {a: -1, b: 1, want: false}, {a: 0, b: 1, want: false}, {a: 1, b: 0, want: false}, {a: -1, b: 1, want: false}, {a: math.NaN(), b: math.NaN(), want: true}, {a: 1, b: math.NaN(), want: false}, {a: math.Inf(1), b: math.NaN(), want: false}, {a: math.NaN(), b: math.Inf(1), want: false}, {a: math.NaN(), b: 1, want: false}, {a: math.Inf(1), b: math.Inf(1), want: true}, {a: math.Inf(-1), b: math.Inf(1), want: false}, {a: math.Inf(1), b: math.Inf(-1), want: false}, } { got := Same(test.a, test.b) if got != test.want { t.Errorf("unexpected results for a=%f b=%f: got:%t want:%t", test.a, test.b, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/go.mod000066400000000000000000000013741450372207100167510ustar00rootroot00000000000000module gonum.org/v1/gonum go 1.20 require ( github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198 github.com/google/go-cmp v0.5.8 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/tools v0.7.0 gonum.org/v1/plot v0.10.1 ) require ( git.sr.ht/~sbinet/gg v0.3.1 // indirect github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect github.com/go-fonts/liberation v0.3.0 // indirect github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 // indirect github.com/go-pdf/fpdf v0.6.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect golang.org/x/image v0.6.0 // indirect golang.org/x/mod v0.9.0 // indirect golang.org/x/text v0.8.0 // indirect rsc.io/pdf v0.1.1 // indirect ) golang-gonum-v1-gonum-0.14.0/go.sum000066400000000000000000000331031450372207100167710ustar00rootroot00000000000000dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1 h1:LNhjNn8DerC8f9DHLz6lS0YYul/b602DUxDgGkd/Aik= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= 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/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/go-fonts/dejavu v0.1.0 h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= github.com/go-fonts/latin-modern v0.3.0 h1:CIDlMm0djMO3XIKHVz2na9lFKt3kdC/YCy7k7lLpyjE= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.3.0 h1:3BI2iaE7R/s6uUUtzNCjo3QijJu3aS4wmrMgfSpYQ+8= github.com/go-fonts/liberation v0.3.0/go.mod h1:jdJ+cqF+F4SUL2V+qxBth8fvBpBDS7yloUL5Fi8GTGY= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 h1:NxXI5pTAtpEaU49bpLpQoDsu1zrteW/vxzTz8Cd2UAs= github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9/go.mod h1:gWuR/CrFDDeVRFQwHPvsv9soJVB/iqymhuZQuJ3a9OM= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0 h1:MlgtGIfsdMEEQJr2le6b/HNr1ZlQwxyWr77r2aj2U/8= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198 h1:FSii2UQeSLngl3jFoR4tUKZLprO7qUlh/TKKticc0BM= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4= golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= gonum.org/v1/plot v0.10.1 h1:dnifSs43YJuNMDzB7v8wV64O4ABBHReuAVAoBxqBqS4= gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= golang-gonum-v1-gonum-0.14.0/gopher.png000066400000000000000000004524271450372207100176460ustar00rootroot00000000000000PNG  IHDRW3 pHYs.#.#x?v OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FJBIDATxw|wwf-ɲl5-.)8=FB  Џr qk7Yz>1hVuWhfv~?_-]0eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP eP ePZ0c27-a@Nep23R*$.iI>2zNd]x2B$`%1B2Èc02q)_e\b0b&#I!ͧA F=e0CoM:uʔ)gfo1JcHnq }iv%" 'Odo1`8eP>|{n۶{;#[o7o޲eVZtRvH!Ki,{zf*[~08;v۷o=܁'Y֭[xuϟYg԰Op` _~W~1v] /n yטd%pZصk׋/?# uvmsΚ5k8ʠP8Y3<}]18H~Ħ2I}2eȣ_W=ȯs~#+Hgp#AA|?_ Vs-B4324$iYrȯ]v7Qd|;ˌ ɉc>O+PD3t$RJ@_G?QVw2 ;sw{W+FP^>F{TP-Ne7wuw/}aJ*;D&˛"PPlrw0~ӑ;dW`#ڵk=C8gAIvyDc:nݺoK.eW`"߿b?ӟ/gcħp%ieydd>eb@ |]P v@SS{N뮯|+!K1Ô, ϾTR"Xsb#;J >|&ivW]qyWLO]vtM Wi{g>ìL22Y:䲞Ay2 Ç*pZ;w>;{lvB{b?4v~_e? hh7Ih 8@!geL/ _("k_FJҐ"I644#;ڈK P G{qP+_ |Ap$1Y(nF0 *O~:28C\uU|aqKL3͛';I1Y(#5=e|b?”L/e03ܹsoN_ǀ.i^2ffN vZlg `\`F Xp&d)1hDcp: m(SDNPvLԗ@O$ b(=@l7!Ph>ϱ /a>vHHN;ӟtSSPCi&vO׷6H*0;:R,Crch @AV j`.Ӹ XL7֩1 vR4l/+<ٹOyJdnݺ^zAO ÇId\ΔR=YR4iS죖r)Gp.$2ƅ]v֯_øC(!ڶm;Rj1iS0HVܽi2=+XLO1j 񢡡Ж8B(!z Nhh!E2K=iWTu,-F&`at9@[ @'IA9TM6`ܣĒ% 0ze0g'x뭷[HQ%Sݴ0%~4=J+CH{9v@ ĉ e7N4JZery쑍dM?mD0^!Z48mxʕgLT,EjG韞2Rڍɥpq(@B EKK ;8]2Q.vהNfzn.+Ͻ0E 7 {4( xI-zܯ]iWܤܤ2Ag^=u[CIΓanq \@ NP,'ZJț@]fJdZ@IȣOO{P//aH  g2%51A:$͚i Qc>,nnҀGO&o NIJ$v8Jr!p/9`B@\7Jjn2թKp'܃\*NN"@1%6LVsضH8& ঴O̽LS\ݞA0)[o-LDIKR,eR IuJ6J]vcH^mqjݺuGe`UWWZ;Lb`QRuOj1#Rܤ-q?]R-IL=e6/^NqPFъ+6]4o։&-( a%y gnJ&Jv#ԔQTWWW:.)SǓ>2iNۏ&GX<8#/ pfneٲeGe`͛7]GfA@C6yqBJ&zR{8]͟?bH  7~ͽvRCR ܋+ٻdy$uC `hjj 0'?0\.m1IJU%Kf¤>+uk3=eO2L555\ {V a,09XSSSP[5߽@dR2bTJidJj6I{ \BKdv_]%IΊ)1qL埙zp(ڵk BԄoo s;>4 ɶmwᘤ"2*}w"oR,㕒cRRR|P"Aw}ҥKY"eZ81F)SqHʾ[bj*n:*3G?Qv>B wf~Pk] dRS3[g/ђKKII;${2$`*j8 L555_Pe`${eM-Sd*;!B~.QrO0$%^@G,P"mX0wܿ?mcjp4=vIH;I&XwԒ:%v%&;LVSS}ݬDTsxgʂx,vӀSbgk)Y(e$m̀Ga?&c202IdnAdI?J[/&sr:8͞=Ge?@a"\e Νd\ͥ0{ 9܇]Zz$~T8{Lgn@ƈ4M3ȟ;w3<3{.e&Խgd4NN}nR@v@e\1mbp bx+6mڴf͚qq{"#Ra%G)a% 0`3wLdvGڱ%z9I];IʃNT8f@'z+ ]C0wܧ~F-9U7m"vII")yJIILi8Rb Yeˈe@S=[o-D&uр˧N*fz1)s (e^vD[Z Oꬑœk)R2iL4H2wf&GcHy.dQD Ns'~;w7oq|UX:SLYLڊK gz0K:0.Hk׮{g h 0| Kjc۸qca&2Yn2Җ(N`,HI ge g6YtO>o}]yktbU>׭[K.-t1pR I6Vrv\;eZ?}^`555=v(Q)K}_|3vgYrNo%0i>.T&  ~;w0-A  w{͚5*%i\BdA_\;f$UTq0>|7pz-h}p bȭV; kjjD.LڢIaD&u@S%j1^~gyk_{+(5"r:idݺu^{g,f,LjI?2ufWʴ_1 6]vׯ N3QkD 帡q-bŊUV͙34HMX2e.H*3`3,0|9|pcc};vᖖGy݂& Claܹ ^ĝ$/sf茤B%vڵl2ØGcٗഽȒŤΦIjg8Ce^afg5_ 3iv>Y{ӍLqG*nO\F'>C`!%oK-4؃z)ǚ2=Iw+8c 3ʾ@2ٓ,Ej`B(P0%~aT]T&iB\83QSƙ,=^q>(0i_.mu1]t@a oI%].c*Jp]7SԕMVB"EO( I#d82)LL)!|LebGtIޤStڤ!e o>9 JoR$ҖۓHj9u'/@Y丒*zLVu0W鍞20din&ypԞ2_G60+A(yKBv!1^IUܴ{g _%U~I5}bIS5I)g \ʴ٣ ȎP`gN5#S!VMZ{R%$TL`Kȸiۖ:6j@ev/'N]砪r? $ `щS JoKDF6i7;1MB`0e`,\IE, uVD"F-%T&K#=@(yLgiW5DYHJH% GԔ32vI[\fhEdctr%ӚS#20Z=XLWC e]{%t20*2UoqdIde1GٷaY:Y3乺SF؀]Hr(i KKiL~4)CF(Õɀ.T =QAF &fL"{ǸԎ0/4.6C~:N5e mfJCTqyR=OS5I/}ۀ3AOV\ijL:"ChҞ*z>-QD&Sx٧jJ>5ϩTS/1Μ ; SFIɀOwg:iԃ&rBo@!pyu V.H'T#&3Nb<r9?2-@*BZ?s4`"3ɰѤV%3,Nm"Mcpz Qi#Z=YϬ!JcqRpz`%\ I2`X |-7sjZD WBO/һ(8/-LMX9f@zR'fR"ӌi7#01y  ڀqFjd3$LS_'L6z]{p&^ROy5`,7rP #K&. FN tЏ`5?+PgJoj͗ן%Sr_39<'k  &K0ZDK&&MJm2g`2'AA9M;x,.88UQi tSLm\A<ň!9O$,*CtuzY`@ro^ddLLۖ.r*m{T  ,Z$e.2waY-%=%ÙctH<%Jכ[IzJ:f>BȩY2D d Jrћ\'[^!Ǯ:yly̟8Q*'E# ZK^{3  q\.%pQ.2FE $ j̟_b 2z7.Y`%27+jƤf.y,R;L,`~xRJpN(6(XN*gDzfWȤ b1#ٛ:a}v~`hNA ?ZD)*N-9]%zS26m+[&>2ૻ %u~zƃc6PG+J[7K}][kI {m1ݙ#12B"@e }Bm4MIL! `FJksߕضWh4+//zZz<ChtLa=Yj$.$!B4L"5yDhtafm'Zk۶Re`0DR%%%eee'˶`0gϞǏa0 нaJ:u*:=tСC̙3{l/˗{^?#c;QJٶm- 20@c D܀I*k(plw@ ޽[k}ԩÇwvvjhOOOggg /_|ʔ)eHqq)S֡PԩSJX,?7pλp8lYVjG9g۶9bqF)u!#"i˗/-˺,X RC?#{3InΌ Nc#kΝK.e?}d, Y;~m;JZ񝺆Ǐ777k#mkk{:::ԩ'NB'NP( ci`ڒh4ښ]DN<)" ׯ_?a۶:R˲JKKLR^^>eʔ &(LӜ6mZ]]]b&u+'+Mҵ+q5s_R8@~vHTj9\IZ,un8(3]]eaRv, Vcé=|78iӦp86HOPh.Ծ ÖxXFNÔ}7$V*M-WGkɬAA{ݻw?<}.좋.z;QUUU\\#"J)#2\P޹$L'q3~APLIb>#=8V/l?_$455m޼_ܰaam8q©Y.K^Rx]gC %v'FѢD)Ckݯ`Ct/bJDUJ]wu_\P]]6E*1_N2ҙѻ]ͅ#BcsFyk\s bȷq29ةL,;9̃677kjjZ~mL_4ƙ3zCgNY\~ ݫM8ce`H/z=Lj|I7d."sIOqQ's9tΝ;Cѣǎ ZD$1q@pAUJs;]3ٍ܎ن񖖋iƂ=VSZ>q)ly+ͰB{+*R +uw[2L)lƬeڲRT maX΃b9vk#MV$ֺckQl!tksVLS۶ֺCD^ٰg[0oL8a͚5SLDeDR7RHRG&զi:$j;Co<+rw g,/aH K+SN+b[ D$!رc8vkvС;vᆆ#{{)ۖ֩=l!\Ho(kx̲sɕ͘뱔㯘 t*&T-_U:cW^\3;At)/E~~h[%cDD (OoEbCGXC@s,;ecAuu>hQ"ZV (ʲ@X*1 U_ĉU]|qݴUV5w)SM6N7R_;H9HRhtR$5۶RN4:,h{)Ջ0|iT?L ;zPԅՖn1T(uFNؿSO=۷oP gybt91|>Lv|`fQ/V r٦7ʦO-S>W)v$%CDD$$= ̴ѓJ/dX'ŒIf!$#X4H{2VNnֶPS}7 i">g Uix}Q^_״|B䩆HG"Zke}C@z[m,..9lYMz bJ, Kض3ˋFMf~O P4nr쩟{fmYڶ-ZkѶvVJk=&NzꕫW_{͵sNii~3LIYVR4:4uOb_ɳ_/mYVRnOH$M %U&A=eF  eppLرW^yW^Ǐ[evbRS*vr5֕MS{ 'NF2s1QZ+SS Ҷĺp%m۶Q؈\U e_mFqW_ 6 j:/cPkS,ةh}hӉ/O~W\vYjD28NS>ފ$ՋI[+4y⾒R7QGG4JRfܓC&8ir9 No _3"ˠ&`7|7Ph/a`=_(нc+ez'YV9%k/1Evmmk߄EUE׎iUJ*l_YAzWmVq`qwӱ71wDD[VfCU%:F:VZQlKܲ \^P t,˲h4Oٽ.;/D8cIG&:Ӆ+5ȥL('xIM;^bSbMH*,gJ,$2**/:eAI/~owww{5MNbe83XgnvjLл@?uY'N]w+nuɴiVekpk;D(+":&oIYJt2$g.OٯEk h1a([! QZtoj}#NnxX8бPS})#"b8~C8ڿ'^ݺuڵ7xӻF%E'c5$uIE?M&uXPpvI/L'{_#8'WEۙ%IIݏ]:]@p0| 8]Cr>xS?}vsر{FT_23@Ѥ%uT-;wk\xNżŞ"1tI;M/ DbGSfʜnKJ2E}3C9TE#mGPۮ#VڿݝB=}Tl+eW>+Xf͹?kƌ\IC /Jp?G* %UTyĝ_'IG3`WAwhկo-I7tJ4`t[S+| e@(BoN>{ljjooo߽{;;vGE߹bŊ'Nyeee9lW0BL)6H D:2IiKh w(3;,2éN4>:%S=& rG372  e@( ^,D"߸q?K/^Q-,:˵i:kZa(TSkϻST6iE+QmGcYqmqqJHGbѶh[X!D?q:b["<>WIDzӏ45j+m[|n'4=kqx2xaL1DR>H q\cy&e4;HH9{p?F(BʀP2~3}b<ȫc؀~Fs^ x'.]U\Si%Sg^pi:f+T.,hZmy/e);*VLE׌ֽg> H*D~۾hem\ێL:sWiy<gƌMk,]jVrI'AO%kחnmۦi&MQt'I37d5Qb#$(UVw 7 @(BʀP2w׿K;zhsss$6UJ9ܦh¼űPxOZUWW-[WVVΛn.tuӦ^IW#&)N;QIC)ʤvJIOD0$1P)1ęKwS"Pε%i ' e@(BgP(~XÇ9k.۶C{14UwIRXܮu#۷}С/G Coiz'TM8kj5W+lyJ|ﯜPT-/b"bKĂ}}(K11RT)r-oڰ7^8y2 tkJ(o; W^qŕW]f&TTT+43]N{KJ*IEdMM1֟rSYuƆ^x᭷*..ǏokkרR];J_u͂ysf-^hƴ)%Ee~i1Elm'U[9Z e@(B4SȐݿwLJu#eYm??O?vtt@J)+Z+e^ożuP:}f5W%DL(%ŲDsQk8x#QhAîINbMOD`[[{NOu9lテ!"Zے=dmm5^{M7]ue0;25_pΚUW\9rx1%ФײlY(m;ؾߴiӖ-[ۇ(Xps%W.VY|JRNgKؖ:Ղ&P2  epD"===N)ă\ ܍8?Gчz藿֭[;::1:\HIWLwu]vE &{5&yJM+t8}NgLO?>EZVfbv,l uKzƗ7/X뮻?[0~"p""ũݏHIswRDԚII^3__|ŮH$2ĹRy}~ǜhg͞j_n1QJ;{1 BB228㴴l޼4׷&5555|ٕJ)0-Zt~w۾}ɓ'hWN'Њ __Y}) O%{vLU qJ:8 hǥvFQ^2ED hhhiپOc=]'H_&8M&L:uڵ~%\N:^_ddU #ϑpkf7~gyf߾}Nc {{hNzr\+3Dbki(i2  e@(»p_vvvn޼9 nܸԩSmmmTJuvvd [YYYRR⬶v~ԩ{)S/^\UU6(WJ΃G}g^xM6k$}5ۥ_U`ŗzUg/Mh[D:HEѮ5pGKR6 x"Eg2KB2%tĆ͇{5yId2 4X,q{=V-Y/>{9G%F!h&b]ik'2v_sLc.zNRe2&׀ -<__DEim=ww.  Ӝ>}EK.~kc"+PE22  e@(»m(O'Nڵk]WBΝ;G-ZT[[p?Μ9 .KU%޽{۶mO<ij>{Iuk6G>OkNf\ssUzmKB7"FDC(3BwzWֽOܳ,(OjQ^iw=ȯ tNW0$]Ӧ-[lժU篹`g9k#L{"vבqw+OVshÆ |_?qRbiׯ Sy2㱒ee@(F7y'lޜtj͇y{{=,_"6Xb`^x^xܯNKN)eҢIk9v͚57N\0dXKSD቗ <=ӶO-Ji[ۖxKb;'_z2eCv4}L\f̜y|˭^>qDUf~×$]_M.cnݺ_s=<0 2` UT-]9‹=e_YjGD+am2DXB 1moml{ϩW p \sz߅C}!ӣl1;ee@(BʀP(mܸG?{+qw:^tHT:H %;ovܹy!ht?>o>_N"ǕϚS+n3'WK]E igGކOd* 3Qew[`|O*;8 6u.YS%>}mۉk;\|d՗x?&ޡLoҜى YF׾oBF|P AJMWY9*fϭ]{yղ 'ʦI$*c@Eіk>5eCY,E@S}ކM/4nTcP09@n/?[MSE?T e@(B`Zr3<o{㍎Ύ` k$O=ߊL2GfΜy-|#={v}p.5[#X~Otuu%Ia͔ }^xEfQY,\bUmi.1"w?Ij'cȒr fҞZqֿκK) 52l1F|V5mjHkqKoGh,ЩPvmM?Ų0ʀP2  L,f8q|~_>cm--Nb%ފJoYiQuݤ&L-OqiZmޥ; 4oZpǾÝw+CbP%5Ukjj/qeeeCtر[>O>d}}}WOކoBuYxܛofz 0½ L>ra]8bDRT<%-XX::٣O>޲HGsuJeDDę|=9{jITbloV&|սZ+ĉ6lg?o; 'B)-+1gʅ͹}S.h%pJ֦7Ygv.UUn ns~p[2Mg=˾_sWlI΍P2  e0 7"XgW<߅AwC)7}5S^2ie&/0W&`RV1bEPs"<|qon9z" {0D+_w%Eq۶oo?Y>MQYsnx?Zr%ڣI^ }@k-Z)Cڊ)O/fմuS㖧;_{؊ /fZ{ %t! e@(BDAmDzmI|WDJjj.y+Y{sk1 vpұx=L[T:EʴM7w{w`ñ~Ij R]]s-_)[ӂJT9v?q|ȒٶD4D+m'Rb?M^&eH`هj1󥷾P0ū~U+=akeQP2  e0޾JD:/?o=,Φu_2wϭVVq,ػNKX^ٶ@D2%Z x-+ѶԱ:I +b(x(Ok׮PYY_.>677/yNI:k)2 ͼXx'Ǻ +,vL/ )qbSG(OݝG<|c!%IR\\ҿ}y(.357vKֹ~wsp8,"b$f6=KS?|WŬY mym1L+'7l}/mKs4gϝ~.ĥ7BʀP2 ܉6lhkmMKz76ʫ&^<2&j[%VXPfRocom[Tmu{{=e}l_Fk}m?U߭>S>kv)q~))~uu]9ujhX-<sU9mK=ņD%bEz^{v MwH\.÷qG<&m۶?'?9~xbJ),Oz'q_)H->2 vXMR_?G#VLރs]b}}=;͐7BʀP2 7(/zof)_F̳inv,KZ iQb#Ck-ZlKh,HbݡO?/~UӑxH :ILa{W}M^ĉ[nݶm/k577+rQZ7gW]y锵Zhx%.NZai250RWVexJ<%8q|?ط/I[׹͟?nλ> eRgbJqӦGNxJ4j/|uu@Xa[o"b[|/էs-_3{nY6 e@(B`( Jz_'cxy~zpL:$!ТF0_ X0U H'?Ӄeˎ7D6UnD.SQQϏF"x;^x>7` *.ZbL˴%f ~T]bzGm*VXR6CDˉ6l-í#[=QR-m/\7iysoc7I$$=bD 1L:`4>%aR+&%5R1Yx߿|EtrJ8iҤ[ne̙Z'Zy={x'Soc֢<_vɷ3mY<₽ ;* R:w_vwMo|۶Pfo<_91;a4 ӍR*??رDbޒ s{t cm*bt{~Gek=F_;>ěOW_RT%=MimpuI77qsFFal‘y-+NHR)URRRWW>zh,bOrMmxϿ翬^:Dl;iKL=~i[oNP^`>qkb Q<_"jEU{ޝp ~zɱP ډ'>/gV-"ZMP@OhXCBj3VꓡeѶ+ѩMG</[~{n 6e3\3c+ND2LmJӇŹΉH,$+کwc횋]~'l|ŞGŭzŚ} pVvj ,Kt vNeAOy( 2PЯy?z;CY+3nYzmTʧH6ԐPJL;mQ>{gKolcޭDilh-"IϽh?8릛%S/.1]ծ^x c˕̾JGuST%ywt跿_Yh_Ms:,L8oq9=Zy\=!PJ:]( _ٺ29@U^}_W})Kl_E~`ko`mL%\CkHuDʦ}e;GjRElZ{.f;,m%ک s?h#!b[ZSD S> I>c]TSr|+5JO̔PvLDzܝJ3|^g>׷P0e@ٶGqÆlm[0f рDڵh¿k5hȌk/5 ,-=e.mh ߘϯDX d= HŇwl+:R{޼;3Qa ! Q!1qFY&SPOgmaHQd߄jj'|q>8͛CuP8e;[l~eKL/<h99 ekֶ֖Z]o2h钒qSZ]n9+Z&D2\0nƵŲrɍ~:-q#x:;{C>DkQG)3ͧB͛7wwwdQS 3)"O=khhss+VuEl*$PbD))_Z<)r*#VXH[b]ZD^g5T)U'M 6WN Jk9xoݕPޮ$% Uxm+ehI0/먪9{ٺ#{4K$%iǦJkEKex(cU] %i 8L,{`JP U˧[^~@ "Jk[?7Z7ڭM0mxˤF"HKݻ{BAeZ|UESj*T 5K,D2t(ɽKFD͹γcS]n[R 0]7HXDjV_0FxK$ܡwLU{\׉ 1T*+;,bDZU-$  _}iPhe%̳?w^DOy+~kqĶb m-6I"t8?ԼPˎ]}{z2e]2VjsL/RT"m2PD,-|UY0.C Z%h+6 Ol4j Ex^&T-]5l߻f^8'-&2ZlK S *H-рz;9*f֕ZP<:G]4}t4(42P~666m;»jHXA)◴,6|$p'{uފv.#Ҷug_EUUO5Ma$):*)  snS\6i>]yHG{Y"J %08eVzSW-}iPSW.n'e:>2NA.#21}+k=-;v4n~)x2tB[Vesne-/Jʥb(`B(6ֺ+޺uk8mZk1Ӧ_N%=KS|Wbr\Eq󳍛f]{;﮽pBYMιp2e4eC""iRvZa:ax+*gs_'.jp-4OtTbBQ.ΣZ v,1v3yTb=zP& Zk{],2;:劕54?q(Yj ^Dk[2D2?AZw;s^Ӵ9~/j;1`O2E)UTSs>c>07A&/h[dٸiWܑ ÎEbeۢD!ն!U2ը^ph׷ܰ>r%2*ͪXy۫;M6}2@!% oґ#G:;;9S Kw0n2N(+(5_ώPڹJHH?c;{D)u~%<_;m Dy%_>/ǭcd|r]U.\QѱN5MʂTtQOWbjWdTZiYw(;&be/vL]?'`t;Uў΃ߌg*Q='mhO-X"Z'SsHLe:3]neT˙9<<--R:[G (<2P@/onlh%_Ѥk+O# 2XPJW&ehW{ jv+%"Pϡ=䭘?QT#і(OR%ʔqqX+Ѻ}$hҴsy*pJ]A>?3+9 :/3@uDb ĢCZ2#b{~ŵW :&LcZDy["o=}\M L_ ~NJO|ȊHqB<ԍ:#Y~Ⱦ3Zk/\-QN Zjhsx}, lmJC"ʈOG:["]mv,|` 3+-Z)ݶ{9Q=JkHYQQV+%ZmD'铎G=Gh'Wܒ¤[I+ϫ\8)*vx2Jjq={mes!D( ۶-c[j)0m򊧨_;!L%RJDY5/50Ͷu/l-Z+oX`ʸZ_۶+'M+SS.Znbbx9Xrm'ItMb %W *DAkG;CPk[^Y߶w[Sb9_q*ܹ`'%ֶVJٮ~SXOOh~?x௿|0ʫW\/@h;kaDH:o4]$PաÇ')H{oVhPJmodLeڶYE %J%4_sUtybxz'cSV[>pk%)>Y1mr1 whӧ'SBQ>2{(OXtEt,tli~ca{NkbSy`%bh-k>ɲ=Mf,RZT"ˌG+Z e[jso~N_u˸{DUV7cںwZD3$#on 6b4EDkPPeX1^_Qdj8-imXHra]wƢ6[S%[IJ(4ngk@=hKT.\u9ٲGkц7Q#@AҢmQMoh[Zv5Dkش}>r^[QZu 唼2&Ue{7:S~ٖXTbĢbGD>SãPԿ; 34ك+rmK^tՓ:X-:ѢL1}nS[6F[D)SP  P8x1maJ"VJѶԬZ=;w}b0\m /?wݫnفv.Q=]-u@DR}b_|P'mh%=<eDyF*Ŷhmo7l|Jl|eSD=v$$JٱH z/}偣/uszlœroIeۡp(v{ğnٱe+HW(ehU`ftn;Jy_-fl4H0;ޒ%K~ s`@hin>o}w<̮!J2%$E&λ#O=}]tʳhѝ>P%_iy4bkQQHPKc-t'{&N wHKDDyT&ywERi֖ؖKT1}(G|77m>~$h<.JzrX}ݛl("#w7l𗗋2=E%ŕUV,lE#4"ݝ㑎m'j(-Q9Ƚ ok1i]'zd)CC0؜.],[|B"P R*_2: 4H(CbAe%gnt}pwo'{%WEU5] J"Ҝ;"DkmmkOW*"]G7tZwy`8B'&?E͉ s|TیowۭHC _װS,RiyӿKvi-Z;e~-7L6P EeeܳnV,noUʔH'~76V8P8{_Yw+jٯEaPw! `Wm-W<,m]G5l~_zāg}4ҳEKq͌Esڏ3Gx'XQyik^Z]]} P Eqqqԩouo`+SnĎHUJjG:ϣݝւS9ZD|*+Z'ҹ X"dƀQejډ>oc~'G(S S/Z ISLOEҲ($oR|k׮]hQ_LPpeam}bŢѮ"_B1]&Sm{V8&S}oVem{0QֶA;e2JHO}鵷7ӿo۳۵J;HOH2F3{  `4eU~:.*_@ 2sƌYg>t85 /жi2IG+S 0RGH)#kׂNo94Bt_ԭPMт;wuX!b()7EZ*oN;"m{>izmv4~YzԶGd%rJ|DB c]\2҆75O(_4?zW ̟/OځB(zG-='qr{/ ixdeٟPy+w~GE)2j EʥW2J'ZET0--EVĐ@|OǞya@p[}(m-+DF[Z>*ke pմ2atw@oVD-Z}rD@!#RQ^d钧zR\~ Ϲ銊ʶ01ĊHM]ziiӯs6l|2٥-~Q}-IuKyS3~Ѝӈm;IT$-Moݰi^l߻ȾXOwYrhרBE).[*M ly;&"G<\eWsh@#iiQj„ ^z7ߓiooϻgTս#G4h_1qXո/nhٱc[v44oYUymbt_i!i !QJWZ[31Mߊ& #Nk_!RmQ ԟ8ċ[_ں@y8c8w^\:yeF7j)r|=|'|lX;*/+c?@ p+W477vOSj;[R he@O e2TˎvʨYx3yoO_߰icX%y&_n͠R ފ)^\V+3@k*+CLv;Q*>?Ѫӻ;6I}DR~%}\JZD+$QokQQy!Y$bQXHs۞i|o&]/z )]4r„ ^Wk]TT4eʔj˲R~ҤI%%%XBT$EkmR*444ض çN:uips[;]_2Vb)P_FMY.OЇ>tE%Pe|k/|'pJ#^|7fZ_, r{ Cx]oC-bK^;k[w5z剦׷7lz)x>eڶD0(ߊA3<"vTpH[jAL1M%F,(2cDXʰDنRZ$FV4h)WHfVJv,JCV7\ʶ-mh-OFcD,-ZǟbLBK+C RJ"1}HW[[v-oj"vTONs(<OEEEQQm'N+-˚4iE]b 2z=O_\_rÖey͛7oݺ󵶶nܸ5tuuE"`0ʤ=#;"E]^RD-bh_xo|?^ItZX ㉌;!BJJ/X{ pRFkݺsg_{'h-Z)sd(%;&=ǤGD&̯YHtim\_ڶw-mYc2D'cZO$PZkmgn&<.ο )o ѶXA Ns0%%]Cǵm)ӣ CtE۬HHy<ڶ: 5bS( C Ѯ1="2ͪū]r3PlU{uLy+ W:ʲ2F(: _'5-;Onv쩟7bdh;vgV3%1QHN7}+WVWWxK. SLIOxQBLG\Yw~馛n& `p<̡C6llvz֌MZї.v2)M~@,ء!*eN+C)[)UD# d7S mkÝ_kifqtb#Vw֩7i%ؠZER<N߄9s_Ť)^^dt%3+Ŋh@[(z81x˥bZNm}#'O=v$RJa iӦs9wE]TWW7yd4~3d)i~%wįR3'BU̮Vk=}kFC=zO?0Fr2|E_I?JBR2U߼L:mۉ@g\wb& cZkdzbŊ '73k}Æ~#5͐hPi%j٪Ѣ-K m)+7L̊sn:kg]˛ߌlJin[?zp_ݢm1+P["xu+wݯ-K[hOWS[1~;yiFV$ 4SL_ed9MVhU'N\Ăih(CH.D_#UK0i?lDӆgʰ=*))Y`^;uUVUTTTVV'KM lNt|d7a"baΌѕK.=s}mٲ婧ڿ3v,8uB V˵2be/ 57įu:%չ-}﬙3#D qÇعsҥKgx(_?zĉoS|6%+ΛҺ/ZvY,J$#VHXX"ڙVcuDP{gP{goxS"Gڸ_myccP(%E{ߝuWpav,Ծgo䮎ͭ;u8l8l:n#r }_[o\I2fZ̳JLryUKΟ0aqmX@=+ }]h{CE(;*ʔ嫒#~#?ѼhWG>A$c*,Xp+V\vD{ɀ=9FB}!'~#Gl߾}Æ j7;{i뛸h5P=4-@_.\f-o}6aZDlO/tΪUӴm[(tvڵl2h]*BʀPֶ;'p0he Ϥϫ\zIK&-2M^Q)K,$vw%VX3-2-ږ:) W?c/3hC)sί\ֶwPkk,S2I'O`Մ&Y]|zZɔ)#D:ĊhPbv(^~1m-VŵJҸ?GJ0;̝{ŤD|͛7b ,7oނ 21ùH/ě[:oooߺuM|ݻw{y8h_|~Gnhm[a%ʣPsˮ_,x|ly]op ʀP2  ʈijj2MSe V_Pd2k^[jr/q}-;"vD+'S<l/_󣯍L3ꙺ_&Njfc73mwvv>|~H\S1%7xI9HBOQ= ;z@aqEEErˁկJoyaG#v4 ۛv{WYUhQe]ު嵆) RmbxضSxiO2"h?yTC\Kggo%F ο&h+hnLу'j]~)(SbxD"ZxT ZrީӜMx97t^tɒ)'NE,?G8WcnJi0&Nr)S~6lx'|Iy(ץN?4)4zbŊ˿T],KAg7(3=eWJ577??яv!#ں%^xь/\r!Z-(іM9~džy7q}YuɽaL1wB %pKwi]zT¥\.ɅB-7؋e|?9N^3y~>tNI)<RDQSS1#KOύ1p@$(Mb)*3rB"BT~ 3q  4i xioz{ٴioV^^^jZc͙3`04`L{k4DԖ2Hzҥ}ٺuV /=bF 0DRCtP#m狯UG^ KOɊ7̢LU-T}$vd0#5Uo28o ʨRJlb(ιvBIdN請Bz̹E3I<ՠtقH,H;}16 TSH4haÆM4qƏo0_g~-]tժU{n2dSO=5|*Ң+NCQAQAQAQAQi*?sffn^`9kҴ εtK=3<.ݺ r"08#'fd4uKI9rĀ~=^_XXXLLVe-ec1Iû}WUYU} us| <'<'rRu bc111IIIcƍ73g4,$6ȐzՌ1J>voꫯ8''?4U36_`;f̅fuuqqqz!<,L; aYNټye^o! R!.>kGr.L K~?>>5e ]y͵}W>}"##uZ-6dLKK{7o, Lyj#FXhرc92B^ !"A!m2H 𹹹7n?9R]]I)SM6|Ĉ=zth2 yg!X:thΝo>Eh}+%ǜ{UKNuĔHXpI+9R`pRZ;yyo香3.蝚-xfmu޽oy뭷dY*op~[>c6;AQ-C` tXѣG0~CnݺرcǏ?|p%~{E?"s̘1'N3f̐!C,K5ҌXH,IRRRRRR\{nٲe޽%%%Mu!֬?Nǽ\xJzlj1Vl )ٲ3>3c\t%wÊsQiGTvԨQ)))ݫ(ҒX2uTA@EA32ȩ;H2HG!r:eg>t(--xvv~^^vvvYYCVsL/ۯ_O2eʔ)))) ocY_si[߿֭;v8p@zz(A\$}_<@D~jTg@YSZ#;ٯ:Gr¼d/)9+[ 'Aq5!tgI+0~իWOk.:u… Ǎ6;H3B3 A:M-7L  tRPA9+}^=nܰ!==}Ŋyyy]#e\F1IIIӧO9s'ٌ,Ə0~Ν;~晍7ΏIUƞO`l2 )gf8 Ēl/YhJ1O<_n C`f&9mݶ{n׫jDުL4 HC An1*/)ݺ]s5/ x Bm GtB~׿^zdwTOȑ#?'~Zjy@)Rٿ^h 7.s>+8'DKzBɎ[}| l~oF'/^xܹ- WT`41APA9GDVq?U ={?_y啉FQ`NS*Sػo~Q zD)o# c=TKbzC۟|tzq F|płZߥG:|8RڣG7x޳X,ERMMW_7o^=*aLKZ;9opA 㾿dZ @((n3YMҍmٿ6d>Z}ՕWZf*ݺuy睁9̭͟[Ǹ A,s +(I͛}vA 5axyƍ?~K8f8]Ɵ7{AoX\2u[!\z[mm꾌RHZNT x";`W \ 8 667߼:[,[n%!!>_kkk7o\ZZ g( 3]־1=z5jgϞݳgOLhT+SC4qO>A֬Y-|:R(W㳹wk[αSrBAF8sxqoߞPd$9៛nIUdP /w}Z\ܿ?=, IAQA^ZY)66vذa ,k<Z樾פ dz.k Ob K{qюyoJ0PSy0~Xq+|tEFDp%!: m^rƌym/@g}[ dP=c-@ګ)^eхO>}Ѹ8艡Ytϙ3l6OW~*--{jjjpE( r. Cj'iSJ%I$I%_~+Om%!s`G}GRqsg6݇>gmגD8giHU ^P}4odzo۫XQ&GDF^}CJdH) Νh:]{<As` C>^W%nc[z9GԋÆ 裏ᄄS1f0g}o7\Kn:ɿt !P/ǠdPy g/+P~>85ͩ!3 y=/_{ Nk0K>3fDԠ( rn9 X6lZӁs( cr7{W\qE\\ns]w='dNuڊ?~Y;ÈpSt2"#j[eⲝԧ~Cy_#SOP/<~{2jTcAAo]XX yAQABhAy~+V@_8 =ɓ%IB?|vůx#<#%pw5G22P&q Ѕ>SܶN6L=#<"QgطoGy[oj$I~ҥ%AN2ZK19ƖxⲲ @!L0vD:=,F^뮻oRuiŞcZ#ӘWp A21.qJ{s} /7b>3`jj>{Wxv?͛7c"tRPA9G)))y衇vܩi,4k2NhѢ \0mz.\[o ?q@(犧FI@Y&rS=Er{^ևoeg1%DWf-…M X j5!e&99_ӧO;I oVWWA鄠( r..m6߾rJud)/$+O `t4#r믽~Y9vbb⫯j0#ԍN%+VXhQ HEAsdztWUԂ QQQo[oս{wPΫdx j\Mf+5Z1/1u _] P(\Q;oXkP9k 1:n鯽ZDDƓvMMi&A:? rcǎ'|%8o7E}B$48 >>;x駛_^c߭`^Lō-04aTYpB(P"e8c0hzhQhg1"RF7pÔ)SmM z-YA:( +{ //GNNԧ-۫+.]\s+vĈjHH&}>&1(%=8&9ò? e jZ}b#zٳgt:}#:<<駟nJe}}/ߞJ8cU\ ᇯ ;g>鯈O䜏5OMMmjl7|ȑ#-I ʄM u,_f12^{[ozYYP֤_}տ/'dS B %O>x??iM^}4!usKdrd: `tW,OquNEFE_6oEn_:g {H g8pmAαl&@9+b#x[omذYw qY߹=KLL[nV8WyI+/V<3cjqJ)@4dޚy+2>p &Lh$XYN8񩧞uM6n_ !2 혵[lHf͚W_}fYާOw_NYy#Gj{BvM{cQ &'Ec WW5Tv`dl0Dd2x㍳fjD͛7 r( s3)Ž#G%%%T!C뒘 @8R8__xSUb%h7@୭? wz~ɉ]`k! l;? k1oذaՀ;ABeA:cl|8QsU###;S]͋dXAME-7?]x>5pZxlZ 8㸏aBx徼˙ xְ# @pPC]p6Odddt:qVG 5PA9;녅K.P:8>k֬[oճdkf?w>G> %\C,pve_ABȀzp# q5% ?ѣ#1tR /! ( HIH[t:-Zo߾f^.߹pccbRE 9yVk=E@upj;̱`[+}“j .N8&ZŘ1cnF`uYNx/^vABeAEi[UV|Ƣ)ӎAtmuBKuN9%2|N u̙`ҭT}FEEa!Mbu6gϞH[XHSTTpŠ FIIIyWTA"X(!`ѱPP9~RH` N2WBdάe^Su TPIIIÇj o@ wCt:UQx<@CB APA9{555oFyyycccQF5k%91wi6 eTC(D;&@ n9cr|VsC,L.HA}{h4QF1B[ۉMV*)) z( !NǠbG<(--ODB 7oV9t"o<X2@B/XsB$BUr@V_ 2Dn-D q뭷Ɠ9!~J%A\  n7ZdIMMMwIKKC3@ 54rvȹZ?&|]v9r088gΜ+9a?&'5u ǎe\. b!-۹Ӗǘ=U,tRK kE5YAN9sPd?|paa!BZ,V<|p=zUۧrw޽qƱcA$ ݵ#G|p3󯸄mԙ @mۚ pn(ټzB= 2!V›+1dU /X8 ؘ=z8igggo޼y֭7o>xVx<j5MgϞݯ_QF 0 1XBH~;L-D%٭[fgg A$t@QAÖH=g[[nժUDlι`x'Ǝ-d"XL6mĈt9 {~VފS\H48p{xg {ޯ+]eP_#o߾ Bl*++wj E|>KKK|fΜy;6***ĥ՚ăK/tSb8ܹsݺu(  ґklWߡ03XidE'*h4C tv) &{*:TT ݌ qP8^фzK T 5hFgǏ?-=L_;wW_}%OU PJYz|ɬP91&MJMMm<nݺA$@QAw}/4pp=ݻ?YomǑ6[P*I':T䁮sZ]YZE!~!1P.r9R[W h}7nw㹅1_z?E |' jt 2dx⢢_A6 H'E8+VpM IҰa h_[Ӎ]78M8B l  8[W)Ou?HNJT&0y2C QiU4Qnڴ{wm (7t^[o}UCU:BDh0B ֧Oh>|xʕ t,SAs;ݻ>%V{5ר};pfb0u)D$teС;Y&0Y>l{Z#H+'Z:L!4P+`G^iyڶfOOII1lX!/^v;vx<;w,..ZW^yC)&N8jԨG6^h* 2ґ5z&oyyy+WlA ,))if ۛ䔕UUUݻtRJKKK(#*t522{&L2dmo$I4xpBBBiii9Jr_ R%c4T@9ՂĚ?}0`ޥӘv,aۿ~iҥ+^[PPc޽wߔ)S("Kh4rȯq'"+q "( c# \tI<裏JJJZ^s΍FɓE ?1]:;;tG-))+2" <۷oWR((8|^?rH/h/ުpɴlhQTn9LFsy%$$ܪUk!#?'|Nv͖-[z)˿SHu\JJlA( F@2aZ_|ڀjqY,v]sEX͞={ݸqQ Q.8~8t'bcc?a\Pe 3`F#Zf4&Tа[/$fG}tɒ%Oq=ƈ;v<{%~Nlq%{ݻwgEA 2lAPÿ&t@dY޽{wZZcL8 ^z]xz"g}veee^Ki"}݇LTn$%%]~}Zۙz ^w?sȑIII5Aꫯtغv(^'m-2u6{O/_<#S( 9_ggg;ꑦ|3]|>8vVիTUU5E~l[d:Q'!ے-5: 9] ieϜ:ujJJ ,B!߿wU/fc+VxzFQN5̝;W=(ltIpD PAXPb#ܒgEQnݺf͚bl>|biKsrss}g}vRPW_}_8NBm'Oqrgi^MJ)Aqό6p TVV녅4nlI1/.[L" aBZv]vegg  ( #h Orrr/_~C?~|{\x_{=|p׉6*M(,,|w~t7xcttߛnk0e^iI*-]hl^0j+儾⋶sZ2#7 ڨ#7{TJEs5 Tޓ:3n[x4,Pk}}_Ԙ% lbZ7lбf֭K,l!8t7u|>AE QA[XO5[gZ 4d2A[߶%8·zhɒ%>=l|deeK8TC8鮾j5zhisWOwLD SD`> BfСCV"Gq>M6\ǎ~<ϲeD>AcAQA$$<6lضm[Ϙ1c̘1B9.$EQ6m7֪Ydmӹ~LEQ0=Z`srVߡ v h@(hઅB 45SRRІO~*GՎ92>>DEQ1! H( HrOl_ޠ6e=wWWWCW:X\\v2Ey+""b̙qqqjwNd@ |GUF}|:W(KKK㒹s/[ϊ͢jkQ7رcYYY AAQA:v@Z޻wnol6LRRҘ1c E΁BnneСm?̙3p䩮(=]G>lu :ְNUXXQ \ZZO? (^̺). AcAQA:v&B,++ɁōaQsi0C_)1VPP( L{0hРQF=>O徴%:  qҰBx\%ϕ$iܸq?~<33nQK;rY+fŭ[$ &>>^4۷!t,( [wj^F$g;wnLLL^!СC?HR.ܼy@i'(6toMUoK4(sbL[֔);j@jtIf̘-Z>sЙKKKr+tIBHDDVUk֬9~8Z Hǂ HuV^-"eXq%I߿éNP*|ٲeVF{B´2G|||bbbC#| *DR#P-HVs4ϖ{\X)&/B:6ʣNNS݀Ӂ1&:ѣ|>:tc;({b! Hǂ+`g ͚ljnX=X,GFF}5XܷY;|26G @x`b=ْt&`8pΉR.̜< ^2 -rcZesS3iNH--))Ow_u֥E!t ( :[` .VKfsz>t]v;;n1cFtj:999j^ m{}mٝ$lVBe{QSBjG1tP7%J14kܣGꫧOn4Clc [/6mR+a;A#iRAEIOO?zh`xq3R:pAz]677U uA3 n_Bfrq<%.SQQ:sƘF?-ܢqF9Zo߾Ml]U&ٞpDҶdz.!rI&M裏 EFy&N8}6 0T̕+WVVV~3D( t( H,q7҄a珬|A܀nݺ1-swjKvJUW]埵A-!J,U+#әRRRӔ@YLu#At]vK`&`0@ <l5j8h4#Fh[=Bۑ#GB==,> A A>oʕ555Mi2"; (lpEXV87,r' 8 +ʲf/QJf32my9gV0,m;d[,NQQK`iAW)$mE9t萸DqqG0~WER|Vqqq8Ń.](4n:LqWhFuuiɻw]Ft:WZrqtXQLi ҁ(  G؆z?D$,񩩩t%GiBdY^x7|駟>p\QDDM;Ъ>(###X}SEN!v ҁ`" H:(G-,, 6_m &&&h75j1)}v5/O$''!2/CupY rI$kea9Z?K{y'e@-%"Z5݉`056WE)ym~98@t"&E,Kdd$ ¨7Ljj@ODʄb# N*AEAPw|sRyfs'(: Aal  BUUj xSLNNnÇ:1)$''_)Dj:oL YXh4z ?C-p/J#p r@QA$Q%;;;(3fLjjj{_ɬY &`C3&& 44Emj*a`රCP#""ƍj{$5 i r Hzt뭬 %&&9e3iҤ ;B+islY?x`2:Z0R0pqƅ% Sιk*$IA3 2 !<:ST~F ܔޱ({@}@i'_EŁQ-pNGpPКôfKKF2lݻVwTp G7b1y<(JEEAA 6 Hh">f9-<<<11]p7nA()2ꕌ?gϞh6g;G2K (>~\ 9)B5p| f6lĉ;v^ebccğ!")R^^TTAse$$ʐʜ.: N)L8W^g7ҙ3gy!ӷo_?3UY/Dc^]`2CׅH͘f@۷綾^ 'ʈFFF2$1u;j!t,M 4孉ulll>c|w0 DÆ KHH@SX|ڜeK6bqs΁h@(er.-m6Lyw*\pb[Z+`+!t ( 4$ nxxBȠA{ɪ9RRRZΘ 4TVIl#B•Ū/(h4p:Gj/g v,?~\$G3C APA i|> ѝu Ҭ~DK.$""L>[ GB ZNGXXmaMDEEM4),,C&Ʀx|^k9Yrsyg9Jt\iii'11Gh9 &@97mQG]?~ԨQ|͒%K222;&9jh'LONvAQj~{P-.t7i,WUUaR"""kݿʕ+ۭg9\]tE?*HLGlܸ1xAEAsKqD]W_}e/^sNp8dY>MG#GӟqĢ(sp\rL`wn9Bt0` ~-..x6jvN6l؋/VVVN1}~РA'S.t:KKKNGA: 0FAN9ވ Zv޼y}LJIt jGBQ? 9"At 2VF3jâtMI}v3`^zIiҸ;wQBB'BiA:A u/Eݎq<\yv裏矿Vtt)S &DFF+t l#gN4p ίD)5 hm;)y\{キA%&BH@m?Lc W;nƌ>fs Nyϴ h< 2 !Mpo+"Y,2q޽{_uU;w\z={3ݻwOHH۷̙3{B ops@D)E*bٰ|XOJ]w(=R8:I͗_`K//?~|߾}C\D>rHH ֥KAEAs&O WUUuIHHHHH:t_PPqFUYYYQQa2),4gϞ%..O>!ح-0Y)V0CX8rȐ!CXym/YdBPgg8 .`ڴi&M2dH'wnxVւ Q( t:5H> )ʀf V8pN*++FcRRe""":X_)VLc5b^zjqqCg4bf7qh9 geAB𔔔}F;CnI!mK|5vF [n!w@Bky|KW@椮x=д h|>Vnc<`׮]۷oOOO/,,|^fy^j9IIIÇ fDgv-..AAQA$ѣGSnιVmy6 ~[|N=UNz!@$6TS_z%L&]jck׮]vnwVVn:xjҥˀ, cW^M% JAfԃ?mʔ)CU geAB{hh(9n[Ӽ҆+[qЄ>e#D dN3xJo!4b0,_tE!n///n27'"tA$et~z:qj+qK(^Z%i` g1Q.*99M LPe޽㻬Eӛ=m",qcÀ HHWADp/D&&CI82ШZ{˖-555hDg~2I(---..=Ҕu*2 2 !l3fLtttㅵ8ҪKr*=A90Gwz9555̛t3&~to{n!4erп9 rf@QA$IHHlj,IR"xeu(@&Gql#G2mڴDAW  #2E1 }q\"q]x yEEEAA9kҚ n Q?#FC9( 35ZgkjjjkkCSTT$,-d1Ytwo_"xl?vhn|Zs^VV}v͆>k׮=vjf ûv뱹A:xM tDڨnfNTqV!˲jmV4,f W%0 7L`ND>1!@^^t- nxTdAB 6 H诳gSen^ -=5fv缾7pт>ta@h4"G+ು8'JfA>=h[jt ) !xlYK  :A$a^+ѣ555hH,UUUϷt3x!S0'\a@3Fj2Yq9Js΁P}xK.L4:%6;0dZ9q!m d'#újLg͚8AU!0[^^?jGe4A:eA:1s۽{cF .+'''>H$d! 4u> Tp P y=5#{js3*-r*n'*ՉDO΀HHsbwmX8ºH<oc>(CX2 ٪UVV+Rg/bʕjƍ3 2 !JkqnjZ;9=#T;ҠDk#FvʀHDhZ;WUǫ2vn*򫻢UYw8gú^03yDK$k)|gR\\'1CFZgcKJJJKKXi CmݺUdNTTn}E p.F Qw4XX,ɤ%!oLQczƹ+('"t ȩ.ݵlwsA Wb!uJcEINkf]M }ųR¼.Jx_h Ⱦe={L4 N5J9g*s|$I&AL H5`1]PPPZZ-VQQp8xqh-`/Ut:.fA80ƵbvjfpELarkW\s+t|{w@ˮ:s~G1xm@%N k%9.jfOUEiu8n7{f^A:eA:c,j6Evv;Νm9jlIa4KzWN?Js80 nlIߧEֻJ5՜ʊ".4qʴ%y rsN5e "H܈Tsr/GWWWiN_~qO3L C PA uEAa[[[lG113i$|)D2@e?~Wfy偽we؂Ap*TwJ|oaiy(>F߬(s윜=z!7nzO?V% ( |A N`,:<---ޖn=NW!dbLbS/cr@h2B], \v+l=Z_#Sjr@h6Ղ!6)a̜܊=z ݾn:5*z>} Ac !(6-9999GL܈)1aQYYYV ~2We[s R{_ګom{5?!'LB'zk}3Ea@cݒw ⵁōOC\Q7*,(@CZ0fN2?<111]vYXX" ( &ktw^F]is9tPs>""C(HКAcvxǾy_򢆞0r^a2~R!P}$*fOdCŧFwݥ>'D٦F `N2'Rqq59Xv.g$olܸqÆ @bߍ78tPKCB PA iE Ȩdffb!mKvvvFFk Bc{1oDs $=GvفRWS^;+߻Wdd,ˌq^g0%* (CP*˲kew}3vH+֬~#_1&`207zrَ͊Uꓶ>|jP7|.@@Q_!^w͚5"8-aÆ?^cc"( 4"%gz.vҸQƏ#bq8^Yz<’2'>;D|A@~<hfL?qUXӯyFEpFy ׮<ܾ79 S8iKa {d!"LKZ[lh6FRM<9""! 2 c(6-`1]m%}vuRsh皒.Ѷ} A͑ڂ?5MaK4mɽ{vΫ5e՗h4G~GB!sWY+#/9w};v7BXBo7CWlpL!MWYQs׻~ ~*҈?,Y&-- .u\1"99 HH HHKp8/_ޭ[7}) E DLv!F*nhaj}[y6Q'6?ڃZQY%ˊRQ1<uONۮ/L&Uer偽e[ĎJLM& L1J_mUdz~ݺZ=:::#ׇɲ^dGdAB E i|> ~Mz9ЖTivӦM7TMq{rN R>Ղh2BδLn9Hm7(&&Us.aaeU6BM~Au=T&|Q Hkwd^l-50֯[WPTag:믗B 2 ~I[AEA^Kd0u6ȑ#-q$1 l̐8Ct\GYD@5@Tg/cN.9der5ts Ҳ{?scǁ˒r{(G1D J>%|2p 9a%Ï?^n-Jy@Qݎ ( Ҹf#jBV^-6v $+V7h 2%pEgj`ݶ 91>]nAV0X!?v3<̜j `*l]8A"e >yM~Æ<`8ȹzƹAC|P+.՟Z?uv'l_AEAرc˗/ov:l6Z$A#/* 5 H9᠏G~N偺Jۤ$Hs/ޭkxjj>k? ꀱLL:}7 X۹ 15>wƠ^ >Bf36& HȂ? !nmGU\\ܱ~,Q%''g֭͞?Egjފ[UtaCȲt%ÛE0SSREHpK :sJ |*n]OxҔ@|p[K3'wڄBp[c r/;ֆ(pŲ_3mjH@v%_g~2<4HeɁw5hhn-,}sA"v?}oBR-)PGpPA Q? %z{񧟄#+o)c999}`B)>dtWqiGp΁CT̯<̙ԙwOcޠ1ϼ4#s""´ Zj]<_35& N8^hiN#iM"^BHvW6{a2pA "_lFJL-(W?V[k VL[B(g+CҬMsb''VlRJ !۶n]|PlcJT}/?| 0AEA[ >l HUB:OqQϷVU80F@E-MXHnn|ZWc3SsgSMKz:aomקA)uٱWA:eABB>A}-B_+.~s=.΃C  ##cҥMI 8S|̠840AwmgIaK8m{~ݒ*kM=Ɣvd( q1=l۽?޴u(iNDD3ˠsZރe,*󂧒%F_z;kp8^.Bq-iP:k"~}-$֌PtA:|IM RKvxعsȿ۹t!X߫ Ut Сw}f?N)c\Aw>73(S F 8㧲q"+ q=WYkfaɲҶDt ڳNq٪?m\n; xyu13X8hs(cUWxk9R۫ 'Kfҷ~^ҙq\oW.jT !A$ٷ_EEEs$cDҤM TktUVUQ DxsŮZ_W\/螔d7z>N)ZIGVa4^テ}-%s f#0nG&VkoLvC0U\ xBRjkq=sٟw^sTD 5{AG,gzFƢE\UMUjomYM3}~A:eAB*I4خb֫ϟopMnT|"{ޑJJ>= s{m7"ÜjN`(0n  u! E ï˙}Ç H2 S8O!;PsVC 9uWƭ;>ͪӠѠ=yMJx%Ѭ-رkomM}#ܖwzLWSyL"'7PRȍdm7Ko]Un=#kҥK AED=ii//\h2A.hAPAAc@lh&DΦ.G9Aq@dQoFf'oF gꭷڷo8Ğ ËmtpFJś(F1]'?ksVw%ubAȀGI?|dĐF 6_|\AȊ9f0x:qm I(%-(,s cߏn0  "F?mꄫOǑd-@C/ߊM~ qhgw.8W!yn6$wӵ%wΙm|juQO@]&DF_]z3z嗿;6FFݻ7#! (  ptښO!$Ox}w9,sp {szgBA TLQ~= Jyvl'lsΟ{;wBxg }׽VWI"s!pʹ@,Z۸N$q`7V yZa=%ݫT)Qnku"XsN8LEBs838TRV5`q%G{~LFWC +T0IW^^88K2be7.^7R3]G)Q*M=Eo"s//%w,تUIdx@ul<ۺEmGpuQ]\e1rD #^W_ײW>/gX6Xsl}>>E#8xM9jX{ <}ݷvԩSo?OY iTITxEB$i<APAAZpe ̨kwS89p(WKc} z_qIo$_Sx,oc?}ݷJx  ==سgԇ4t sPc^sIx32X$)55U0kZ< |۶[E}wYua-'zA}T _ݺ]~韮ֱ%&HRj |H:!_xTQY[BmHUB9prC'.|*vh*;ex>|m߾Q[>&.x]&G}ׯ_ZfśK~)N1kaȮi7.d2a ( stXlѳ1^okqz!Jc}MU9 [BG6mڂR"vJyy+n:sєKI%myz^yI]rم@[&)p#۷"9 ?~/4&Y{_,]d#ǃ .O?@|% G]`΂" D nI.^'Tso׫MFgP]{s`k!rO>f:/9'Dq:tСoK/9S@LD"U?㧟g˖- M7`S zƏ;|Tܨ!'ia#Q|5;v,0/FNAAQAi)۾uKuUUpMh+P_opYKJX"uGs8^_LN;vVa";;g9!j~_~eP9:=Gp=PeΨ̙hmٳ;kIP(ݓ|&_ˀJ@@J;~qCF?tl8N3Zm\lTnI̜rR#0k] I>/TOxAeA!bT<78jkֽ91yGB8 z 暪W"w/9D:#93 !?|s}e)Zs@Z;E%ô#lwyYuxB| 1a*Xsxu[b !.n5Θ>}K+N(d'qLF0͜狧E`P7Hz-u9ǯX>xέGvf}&0S^Dj,A(TStdJ2?wxղIP*fvv]w5^#"8m"q[kj׮_mZ-C1Pҽ?%qD= Dgaxxf HEFF&&&b!t A =!DуD Dp=Q]Ə{۔~5k$Ib3?+پ}~Z]]ݒL>o2.ފ"-SzʵuPX2dP]BeaTޖKh #x汕K>}{~+ObBw\ˏ(9ǹ"sNa[M;K\L#u5V|W{! Nai G9 ӏ|쾋7¢8H}dɟf|'333qD@`@p 'Ǟ[~߰^$Toa2BF9`:CrU! ᒖ)>^CS !8LTTTrr2v H2 iڦ3RIT-n(x.e^'ԕ>Q1 /vML|"L%]v{キcǎ`U( ~c~:O(PҢ<2࠰(6^wEYUG1Kܵ/袠2|>zrI]b#J*֣o-wWǎ%k7ڱ]Yen!C~^rarAq8d+ (%G74#(◾s&y(X-(ֶ8=% \UF<$M:§jk 8IfeUWW.[vYwyÉ_J)5LH -F$!˜LHP"˟|?WqnVj7@ONY>["vQ_ |է~3%ta *>xP0dYBAQAiOi-aq#G"̞f;8Ko.ٴ8OJhZ^Z/7ANr p|r 3H?gO4^\i"C΍FMf/ymJs/STԉbEazcXJRræ]Ps4/p=YEE32+ /x3N]'u GEN4vȄq# n(H#QJOΟ]l]sWr%(t Kώ/'Rrlv_~k׮ &,X`ʔ)prL 'ǙBXj]eG%sqvue-~t}T&:lO`꒤1YT2oAEAIdY> $hLὓufɖDAEŝ%޳Y}^gIobaݺɫ/H 9H idz)5o82͘ou@߃XlVn#G.^>bpdj?^u9l\np@]zti'X6k}G2h<_z$UUW$*u 㜛wB޵WJ\nFcxE#9,a@u \TjEf֧Q]%OߏHPM|69'Na#~,5~OBسgϞ={vu3.`̙:NN92{s#Pb!%KV,挂B 96,i&w5=`+nuhe4:E'kȐ!e (  @aZcUU9Z=e <|TK|6 o<xn7isfL@s FzW>]L)b轏iPFA֌_|Tĸmw5*T8TWBuhFuJ  4J񼣹E.Wպ]‚RI8 3j_ c I$X+ /dKATI dV[HrPP[:D=ڨ?~_k^u)0ƶm۶m۶5kl۶mԩÆ ӄ1B펴_7mY귽6L::Y)΍ԓjU SJ?H@F5t AEAp*ISKu3G2Q'lS `wV^qTqc(/﹧3lhb\@fLg7㏅& >27 *[rU:FpXL݇o)>ݻM;8VE^I✃b R0YBSH<~=8B@c>x@)=Pe8c%@(hm9${5vxsNNyPydnMz[=?[v94ٔR;~ =?/nݺ JD&55Gsr]/2 Ŭ^ 8hLԾ=.;c1{!x'gAc 2lBAQAi=oҥ|ԧsЅGᆰx]A!@P5NgJzH>78ʉDOmG(E$I<xu_Z9_8!D]ɽ^NK|}Jq;cdUHZΙpTYνvٿW_qzeOB1^/:Q~^?^ve\rOtOR0,>⧟~:YUF \TF>kr^l8ꈰ4ΔRٍx<81"( `L:sVk&X @14^YwJ%'l_#Gr,^q3pJ0ggBtʕ+xflsКv'd^pp8phU< :޹DE董dgy5Ne[8ovphԥ9˨2?B6$#$?yؙυ~p8rv~ȑ#ګ*::Z(28@d~MuSIP@ܾc犕+"چ e8U/&wvɠ A}V ch3UzgEAeAQ]]]ZZj SZJ]wiyZ^S}8¹$9m?D4IC P8'믿>sG$ &'ad#ygB$rjg<*tA(%ĸstfڢ3cݖC(I0cwx]U 1 JY>m۶hV/Ϲk&KDD, SbT!Fݽ%lٲztZ]]]f+UD 9{\6ݔiV`rw59(ABeAB˩v6-9E% qT˰rUep/ $G[Ӈ 4I;:x-[/ܹSu)B&\8Μsjܕ+)W#)!f3Tn?\=0_A נA'M&֢1uMtͱec?| N3SXWO>ɓ&;ڬ=8( //o߾}6m:~xQQQAA,D Ƴ5$^ycyōE:o v M -"###""p!>( R{.9*R#<>*¹Bj!r@x}7~Y^|~ʈD C,[߱c!ֹjg"u`'?gg1'I?#@ց.+QL*8&vцoO|(>;L=̈7_ߣ~Ysd?kH9z9h6|#1jTj>&Ne{Cm0?]QYnC7nXRRrMO] aK. 81"( ̳_m7⧄)(r+=g{ 9`(gloK<=i 0,e?{ȑgrŹo5O<ѯ@uD?9,WKũgdXK ]Gz p(.:g '6@7jdXz DD |6;eGEw{*H tl[6e&iSa6&&wпȨ.]Y, X񠶶rm۶:۷v@c#dL?D4ݿE\sSD߮E9f>Mhv6~2...66:HCAPA0ƪ|>_B'|69>p B},ƿPy%ո"Ipue//|y W!3p#G|Ճ'mHJpƨV)))"IXXlnJbn|AQ 5EjWUUx;}ڜ:^ Ym4GwYU7ōزAvPo\ x=:"[+7⌍  :\.ѣG'g\Q" R \t Wohruޗ8g@(0sW.xɧ醨^*Z T匌g}vɒ%'T5a z m%Tf (-+B :wx(#Q<휉E$ w0W91%Fy_}O>NDϵX`߾~ 1.1cԨQ:VwMՊ/I`b 24"!cLs8NRZ\\7dggo߾A,錂:Zv{ͽ]5;(`V@[7ڃ2D09`IlXAAEAx<$@k4ܖú.%o>.'D zVUSOx]+", l+IExhůJVVn]xcyԪcϷ)' *<5U nwL7k j9=':mYe b;ffϞs#FW^sTuW\~e˒ɤqzKھ> B뮻vŬ޹s}ɤN 2ȧɂ]8 3KӼdw?=#;a&p <-[r$"bRN+>b``Oaj_h%1>b~_O7V7?E ^J_7t"w7ڟtL\ٳ/ #aTѭ\ϻb}QeHD@l」s8ϙ7ģh1S#]YYÏ4g̟I,Fxe5g{tߞ_c9!seV򧟵6myQpNYY644TWUc|}Rӻ0q;;;[ZZDL&;::djd2drhrC~D0ܗ~7&`F69lk- - zv1)CDD'֎!\dcj8n(ٴOu-Z|:r>͛6"XMFec80p^n;c==JZ\ dzɛ^M;.5q!bd ?ŀp QLUQ>ܖHrsT.^1|2" zUVU/*hk d:22#8l3<~9S{]NϘ YV-YG^bp*阢=Hsx  /R""&ehL2Lkkt~PFՌOg Z`?|zY3V') G?<|'ot&m۶wo۶mcD"C=*^%SryY"FiʏuLwwȱ 8V@"fʺhCx x)daˆԆ\dSӥﹻk3iܒL^e4N6B22v&KY޷7]h}8قT'=_iأ33eFPd;F=֬Y3}tDD2DDH6mkk;Da"Dżؚxa/mO=`p ";nѣ_nwhJ"LUY/bCyکq;g?0EK'.?~Ų фƤ bFX&TQ@) ٫Y򆗅+j?=E2OA5ks>7ϙ3'R_Wϵ0K/~hݴ%zw%⨦ǣ1L:{˄Ky_Y'$4 jW,T#Ձ2H#Ĕ7Us~[o_twWGNO |/h?mD =%ܠ%kaafB͆h"cRh"tƸp;N?5"/9/}qO6 10ο>OhѢº4~A&nwuW:.WcOD "qT':U2EEk'2@TB|?&Vljܼ6\}0 @T"R+ ^Ҧi~h?޴w?ݳ4vEDq%k>O@XJPaqG CQ& Xh2`Rh=?1L(k$\U ͎9Zfѽ .UOP~QHxUy晿y[ c, #E# 7m۾??﷿-e3\AOjm83< m EÄ Gf.3T,-LϿ}"X(7Ϲ|L *LF`~b~ai,}۷m}oKutt|fGɿA ;0C'/>"Q dp΅/$АjC?kYO` D vC!q@DDLII$w&V# j_bUc<M AO?v .8ᴦCX;w|߮]1p7XxU񓳯(fa32۷2iv=UL!T"d1giǏK3Rue.T6#l)d"P UṰ(`edz_">RU-LjD*b+g\R ]=u8aOe۞zk360aL>L T~2zjO8>#bp,Z? nպi5l$X[6)RjC.&,Ɲ*i'ȪH""&eb0Cqn 7@&$Z4*uk__s3=tJeg>s 7^[__NjMNͥ@}יL[n׿bdzr:aX;=ᄥPqG"H!TU.n끋^z˥*)HJYPEmkC;(PqFאv *"TU&\d]2xzwU*'ۿ U;xAZSI-Sn$ @kQ1{D4]xcEY5QPV$ZU@UX ͗ ׁO1Aimu̞/2DDLX+gLlZDlܪ(5 :y~y?O&n۶#׾׼5o|W\Y5l;WrwR 0ʄ 6T^>ݐ\l|@=Xl wR{fɊ'+"qFT==w]wL{7#Fz].*g52/hZ0F)~JD,BbB>ҝҽw@M/s?P-dPK)d{{m6mO!"sՑC crfU^B{H~f^r_ޣc"7$c}Ν7~\xozӛZq(}3Us|{{mёNݨ'U4xLO~ߜ5f30Yiև5VW*ݝ0"[.༪z` l<U" H֭]2Xh11/|i{ߨmѽp gI[l~:XSU7"ѪJrQ9'v>?k( d`}v Q1"e2CĐDaqáBm ("֭ O^DDLѩ# q呚zU=?CDBP_{ \-ukVOkkwO۟y"|hvڵk7߼~/xƍMMMӧO-'Zc_SW~&qD) mCwx%4%F\q8h_O#C}nuz>p{g&ٽ@kg"h'Y-1w޶Y>s'ԇL[(B*5F^J{ * g:cja|[TA*:1\Lu^M5lne5\yō*1)CDD'K~j U@6lRx1D6T΍5[WfzUʵ[o[omllܼy믾jk+**3hM_zTBkN]]]=н߿0~LYrpZĦϚuٵ>%ݭՈM8X손߮eE,X޶AoGG_oX#p+d3VU Ba 9x={vtkɈl}ǟޖ3w?žW 447^^4w>un箢 _85(j kq6t0>gh&h|`0D=]] ~iccc81)CDDcyOr~a풳\@!Fkk/\x>ݥ/ aZZZn馛ns\x6lbpxڵ\r6B!u]םhUf2N8t讻:tws*Ooo,^WoyE'Ȁ c׋%]] =>^+6]q-O2d1Hdoﱖg{{;x߃[ݱ=6z"jl՟b٧ _9(Rʂ/A'վ}Mq鴵d r'V,diU3]Yqї~%g{v?=ţi>?\D}߰aù瞻aÆ 6֞CA{-֭d1X xBL; +fHVL0TqߢMU뿕ns[cm9K:{*WvP7M7?{އoypKT- #c1xS:d+YOK ea*r}<2Ix۞m]]͛2DD4)0)CD4C1&Xf @=$$TV/m8wnމ* \3Loo/zʕ^x VZ5{?5=CO?o'x[omin}R{P{$RX &Px咷oXhq~Lq"ٴ&{~>>}k _}oP9Cࣳ},2JEQlcBE-{ןthcaN*­'qj*ëꥳS]? 32t pcpl2l1纋.7o'.1)CDD'&1Ƚ5 ln@uklOկ?wսɢ$Yd+U*L&<{oUUU]]ݒ%KL6mƍ5"b}?ԌȠߞ{'z衣Gds[lmmmkm=1XOg7XJ. Pf_teV9LJncIv!]=r豯|.w2X4v77ؾcㆵu-_45s@-D 3vX KڿmGزؑ%Q>Y|9ܫrkB-0>xt&r dP(FDĤ jz椮1CnTӦ|Uz9ߚlͥc 棇}?tСCs=A-˗WTT1peUU}]]Ӝ9Օ.\pb|p$/ L2"bȑ]; \޻}۶T_8nmkTJO-,Հԃԯ;oWι^?GaN]#CN,[_Nu d=?diUW̞5d"!S`@ǘDo?V㨘':=~vsyb.gs[f{^Nbب| ' kѳ呻󊫒p8ʕ!"Kk{0aivMW_Sݿ?{da"*† ioo,[kee׮]feF"H4L%:28p={>Xkss82O]Ez\ljTו^8 (RTzfԸb&|XU^J{9Sn4;_;o vvν;v>oڥdx$\[[j=wƨ1-mw=x_"_(83[Pꍛ>"цD+ aqP )i{zYqeceew^MLM̆NRU;pT-l8WÍm~: _S.$ T;;lf',b6~"TQotKzՌׇH}&&"/tԠzsxZ۹GjȹXog}~fd`Spڻ~ǻ U-pf23UWDOPDIL 81B'e.yы‘$¤ ٧ˀWU)rب?=j"RbNÚ/ǻǝ?;P߃ Sa@Ⲭet1gRܥR@I/, T#+T̙7+f^z6WΟ&P+p5䅧R cо]˧˺~O9gu'rȘ܂ߦ8%c>XOɗ1L'3%/Yg/< ?at,E6WܼD"<&&e&kj\:ЈH{K_t-nh>4}1A1zCr2ق܊]U-^ָqC:'^pn*lJ!Eg4F ~ Wk_~˶~߭6ՏTEj1۫ YY42Q߄rEDBf93x^/p / t]~6 Xd2ɝDD40)CD4 ݝ}=ݪ4rdդ d%&0%Wx9#wݹ~#2Hr&ַ}<3@5WzjѪ+~EL8n?JN &g{NqOs/v#@{Р*kȘ&q[U Es7d3Fg OZ\αqٲe=dVh>=)cܐqN"A% F5nVzܗw-n;th Iɽ±3WW/]R6](R=ZWaՐźOivw"V7}k.jذqO{y 2v8/2a^_S8NiX4uhTzAh8Yby GlM*LM p!od|c&$VܘD˦zŦ+6c۵}[Oɪ/X||Ce5U,[X1wie3倏L72=Vcr&l:{D  zjN-_u_{d둓DO̜9sөg}.J^/~׮]f{7(H,12K7̨[؉P?zH4 爈&&e&B`aLoL2(ZcE6lX7?p{ijKpO%'cd 8 ꅭ* W׊Xq1q]U5֙pp.vz' WΨZ<UH>Wx=mYfASR1?Ϯk8=7^[J:ZN27/{źu=/kH~7۝;wrDž o>Gя~_ǧ5K5 KðKETȪ㊟M$Xcc#wѤD6Xy@SLW@:Ic6 0aH! 'y3vk^۹m𣭏?joLW}$2)/5Dr%fh&vqZ7~Jլktbj͘VkBP"0@"يfb fH01 (zv#TU|C'tGgLoKDD^z^!.?#A /~uɒ׿/Y~?!jee?w7mڴiӦX,o~3L熈H GdϸgLZ .ڈ͙3ڗ K2DD4h}pޑbHNΌ̰oE^GLkNTu{ݻvSOG e ˀ 1 E~J>>6nDBumxIveh$ v~w{ T|+_}*q豇ln {K4?v .A^1HnMoܸhQ[W^/24wꫯw=mo9X=8}dJt>4q>)#LeU1|`:ha'hhkۻkyqq[?kn%،10.bUrco|[Xɖ޽;21rTZD"T{'ȴny|3 _ayVzL26}V-f}/"U.yi܅eUl_ *2݀L Z`y:aX41>¸3cᢗ- ]-D]=%׵kݸPc1ßN>͛7(,TyP__u}[joo4Цկ~Ӈ>ҥK/ )Sx75nh"nڟؽnd2==ͽDDĤ |*@oOϑ#GP`YpJ0 zPzMsf) {@ɍqOm۳CO>ĖtgqC*ЬfUM3+=ߊFffj@L؍4뇵Ӏ [PQOR(GMęC}QqEP$(AoX1%-|җڷ> ?( `ӦMW*h466VUUutt JٳgcNqg -c`i('$5X,VDDĤ RVl&=0{YWl W5`WHͨąJqo`Mޙy<.$rOqqʛV+(Bja=g"Kfk-(L/TB}I $㊸ nH40o55=>v aP׽s?hZSp8{8Ht7 i9a0g81ТKګ6)W\=;OEj2444ڵ4owExyy5dϤכUVemO |…pM:GMx>`qb4\F`)Lq25OCS*^'8Hct]ZTYt`_nߍ(}}l6/_ JʐA&y^6Ew!$¤ Dqa{ժ& ~7TJS53.vOA4w\7 >04p12b ]): ' AG#r#2I)CD4'AD4Qtuuwwu.ɣwp"PrwT_v\)2b`OC TjhD4X负FGw>7֊ʺaOl""!"(^֎mQjttBaBU4U5u#m>"=w'MC-G8mڼKDD2DD&53Lo7Θ90u1Z3BqY#nh~dN1}gDDDDEjYKTUYʄo0$7 RܶOeeqp%"pMN~,&ehHvHt' i;S Y 7oVsKbs_MhBqCbw-CA :/6U5N wWAru:_NnIwg^0"&8i=,DD4 1)CD4i80c 4T3|M>/z W:Q\<8Ɯp籠I81tO %h*\)#PZI ^fSM C^k-rzgb . $ڽtMau.]՜DD4AD4y:^6۟,˝AS'6oΞI^N:S10?D(^g׬]d Q2DD2DDFHϥMS"\͜k Z[ d<)ulā igv' Ѥä dҽs{-Re փ*un܅ Beɰk6%Yy|-HiTUzCUgl""8h2qa㺖0q"a'lk׏}؀yd2#m6 ^6~8]1P1s إ'"Ѥ[r&)T@fzd(fB1$";Ld>w/cq4ʉtz^\wپ|Vw_z⅋@D4y1)CD4$ێ)((*N ")Im--dey5J O \<-2NԌUھNڢBp8IBD4y1)CD4$L4L&33^ bTtwvf2Q󼖖;d`__߯~|{<#sΛd"q^x m۶yW#<q1t|zQ[en1v8KW9g ѤƤ d Ds#er324#vQV%KCe.㸪Gfc?CGW:U&4w]Zd %f ٙXu](^x@NC7)4Ia"lk?v-jȘEVUYz"Ɍ?M8dpS& R$jW]EUQf"%/~ӟnoo/+J}_>/N:Rt:ߟL&Aшy L?g0{.b@)B7Aqf={w ^rC_qeUM @D4q M6#݉sV.\еI\^G~_g-Zd B{>,DP !h?Ǹa(G3+['qnfm\/ Ĥ d SE𓨜4]ym;Ԟoq'I.x0NC7K?[Gֺ1ߖl=2w\wft(@D4qMJ$1ڗ8|$+TA_BܚRNxEݺ%p9{d\1R|AsȔ&\-~o}t{ϞmXY%W, r dƤ  @ {5Kf_u/ %.jg)U'[7[,)Ζ`J41B&TbyP!8hRcR&i6m$^%{U#q PUqC.yWlfwHG9 tLg $X  ~oUp]v"Ɍ8QD,DSqMYu_{ U͏Gʨ:R*\QB1!$[uxzV 1DD MphJ3Ь5rɊ?wr"5Y/}j-KwKqJ䢿^̔H͈8!$h0=PaB`1xBDD2DDD?Մ1l8sΜs[m 5,HnI*,y[ks2S*"LȌѯW^*=+ ϜĉKDD%I"QG¸HZ^ngp莋ᦎ;/>$C6mY4 Ms_v ÌiiF)S2hgz,;~iHD41)CD4L DcT8$оMeYW>xogR}{wY1پLwZ?_zFU5pqVŜKy׽)jGu"b؁:Mi1~U|Bq ;؜*XlF&e&=)&K¹KDFzȜ/Hxi}ƍt<uGz鴪BU}O"*/kl{X,>;M6V蟋lF~.;Cgiі%֣PkށӶ{@{^~ <ѤƮDBF&\ɟBN~=QBfbp9-GRm[DDI"!E&\{JKabtT?|(ە:h8I(MrLM555sŨ!LF͔ U@={޽@7r]'d "* )CD4aZd׍b}?\jT3Lk3+$X xɾp\EEESSSn '"8Rh}?J#L_:#K"3c5K:E#p7z++ΛWQU9hbRh$1-g-zDtOeiVEACsm0=vʼn,hr`Rh(Ԕ3TDGLD44o?y(T!,z<%o`Ȍ82""!"(6mT.@p}јRwo9L=xO5Uբ(2s欍7!"* LMeeeguGHdS^2NgT0oªV(|54͞bR6DDI" \2HTg{[ M8LhT؟ qb"ڳPe j0DD%I" Pw@MDӴd*a E(nyT0Ic  y3O" 2{ӧi뚐+DTBFmJ|'U?ViiӦ!"*LMA f{1f2zY!lĚ):;S ?{`(Y3͛dzdSOD4B3fJi"4lNZJ}@jO?N 5bŊK$!"*LMz{{GSxDteCLQ ѱ}@dw[93sL-DDI"ea2PK&m6 eEo l ~멟N \3}3gT!"*%LM +Vw fdב#Pq\fw9lXsJ 2DDHUUy{:r]N!" mƥGUtWߛ:d ӆ0)CD483k,uj`BDS(u|O*q3YY+Cf;Fj3fD~6&e&X!"*QNb  &wp6۰aCmM "R~?Ēd{DD%mPPhVU([6$V"R #M)20tLifLV{FڦPӗJ+hBihhXre(=t9׉hRѢ]9,7o?m#mk^:<0#CDTZ!"Xu^`1]X^@2-Fn9z֊ ?>}Z,BDTb!"`1ӧOe DjDTtyL%~}Dk=cA#/CyYrUmmO"RsM4֎V""fVVЩH 6'н{gw"4$Y.*/&e&t:=J^z?cfᮟU >>|Ϟg@]1fμy3gLADTz!"XDq7g8J+*MCn*YV#H6'۟zZ}/NULu8蒋0QIbRhbD"7o.++|CS?)q*nD ykSnZ Eg4 &u׬YSYY9b8qYJϰ cV7jYo{ЮA7 SYY1  &e&HxX,Fo_Cdph F[S}+j,X.-^H" фf=LoWE-KQi2%)JnݻS}^8*v8i5lJ2DD/ fCzﹺm}f2DTJt`RcD$I$3w?(eCDDI" pc$>}0 0RmG9MrYx%CBcɡI|"K.3DDI"pgƍ5HD8C MCL ZےjSrru,"CDT!"/^\]]!IЗ{Ԅ9X$:t2x}jƁsB5 J"Ť D bO_й!ַh߆ٙ3狋hS80۱l_0X  ˗-[`1<J2DD} cg2;r%VX@Y'PyPΰ5eDO51mcw ےGci\!"*]LvQFfٙB_%eQw 92DT"d*Ϳ7U++͞7oA"Ť  -VS:///V?h=NH˝M4,9gŰcJ2!.EdϮTۧ͘ `Rt1)CD4||ݺu3gЃ)ڞ0#Ѹ,IC'deU00z{./?Җsf4+.&e&N7] 5ejkkMI2ޞOg2~$hFo O1lwQs9RPjB0~uDDk1666VUUaq7gR^ª}v"$'ז~*l>s%"Ƥ Ѹwǧ<~jws{p#\&7=tSֺ;6?|(XrfSSYKDD%I"q 'ƻ\^QF|d=IMzȔrBDq͇Fٰ:PH"RƤ xǹltH|l_"ThTtH"FK/L$>I3{<ɉJ2DDLelv j?vm';"Pǁ"WB`~Q4Xtˈ!ٚHww{:6tڷlӉF]@D4Eђ "?.83J_x#eK4kT-5gMcZ('Nvnj[sU&ډvቈ#ȳ#k}!AB@ۍ3$>ڧ nrK3%uBZ:ˢ(P8h*`Rh\[/nXijl/+/bҝmn'OD%M9wd=²rDDS"|. "nv>$_s.cLp\-\pђ u=JLp}Ә)Mnw4:+++yMLS6$oR(l2_i3g͝7?xQٞ/k jM`?42%KDoLo4͙/ " \"+2/1یemb1sx~?hb1\SDOm3 DDS2DD!(*dj*'8l&Iì=\ׄBD-%NgoR' :(1ǒ'" ++ H4  EpXU*f2bNmnŌj ߸iLMlSq^&X!{ - kY֬ khpe=]fp#'ZkM ܨ+qf55TV="I"qs@EY|Ų9JG>R>2>WLZŀh(iNjk ^=jv+VTM)CDtcӗ^UUw2]ɶ#!32A_WX BM'ESI6AjUDcӥs[[SOIXf˖-3U1QcR贅"Ƙ`L)*;#UTp3۱3At DtR}c #8|;{20uu\zYa{DDS/FA"&VC//ixd蘚vR/#""AR2.Ӥ{׾'zZkzɜYiDDS 2DDW ;jqV.^\U[7ڙL4ÍCNf%"C+(Q5lO["5 (B-ˌ Mr5АڸxEvM:HDŽ`GMg.Y0= MMLMhArEwG"Ʉ7v}^/=lO_ǶnÞgϞN{~󝅯{9ٺsGV 8HSpPj!G P_A,v{ZU@|?y~_0qЕ߹qMdmX4 B].)JXdd`ge 32DtInH:@Ll5U{12P@{ ׮tK"Scwy &&e&P(NF 4Zle쐀Am[y_eȤƏ Æ`!( x$$UP sƊ":06,~^9{¶'u.Z4~#c^k-sVWW(MMLM_y孷3Oe=Q,"rKwߜ|VX:UqQdTR0i8 8=p{II)DLV -D4+ahHl\ldŋ!ij1r*khix &&e&W)jnjRW[a4Wi4? %Ȫa SCu!Mq47jG M &e⇏9۷z8pd]UO='"¤ TEeR X'a 6񀌚~u5T!^LmjKNj&a((l֌}n~z;<DDS2DDF$.//?;gؙe:ǫE/$ +W ~DmֵaVE$+y[h W7?Er__itձXhj2DDEӬYVv]w1QCáMa' ?+PTO. C$ )ilx.5LVԴ4kD4\SP k1A^bX( "!"L.\8ifLp8<$!c]>)V2i0:T*hM\AE ꈆDLRFEم5lZh^p6X\fΜYQQAD45qdߟH&O#xy]5E6;QeU0}W')&0~hӢL JLKcz lܸ1<8}3o޼½hdR]YYQVv:uiuN$tKbjlxeGhhBM.#]k;"A;-p|A1=H$'"_@DD4 ?n޼yէc5/ \] (N`J5/&6 { Y!E=ciErU~7 7%~uhskPԿTa00 u#\&:9G N2}py]~ǘ T^eÉhRcRh \ի+++,=|MjnB22 Ætj0/CDuTFp(xc菦yt'""*=LMiO=)t͞O_7ѥ}<~^AHԅuqGDk_pjFhDfL ܪ:zuݵkyvN_""!"$!C>8N4}!tMogozmm{ט[Pֺbh,8R&~ 5yJL<|Z?7eǩ۸qc,'"!"d<˜ȏܿo "־Kd%upF8DD@BDákV>>woN_""a&"Z^{գGcBna @12KD4)M=GdԊqPUkǜA:9 kbQ!R2DDS2DD$rgUʪN1fOX\i>٬DƭKLO52CDo5TVQ=ϳBUcש"a$[2%8Nuu8DDS2DDT K/zû)G4= Dԅ#Vbe_"*"nv^2ǚ%^]8X{R)k16{c'8Ncc#2DDS]@D4cNzHxʏ*ks?oj(\ RU R1M>7ZmZ}&!>VR%.;s>ڒLGi#Ǥ $H$zzzN:PTĢozW_t*:EUE`DEiu~i8$tp M$iұȃ_7|=v`{7n C5IKοGiesk-w?Ǥ $v w|K/U/tt  j% &cQUQ^ڹsד?3d33DU/N~W0ϞudWCOW׷f"17 \pNBRFdp}Uʤ Tn1PXZ޷ }?U FՕG{?wśw%BU•FNCb:پׂݷO?IucmuE EO˂+-^8Ǘє"""DW6Zl}pix PkM$o3__mex7M6ebh>}@0I7EY oއ ZCҋfOk@~0)5JDDS2DD'u]vTVW[76uCfv? awhW#)8!2x$܂xm? 'ߝ@.u|'nӧalCE"@+XHDD42DDC'n߾ӗgCB~ޚl29]ALkR;<1' WǧOw"o,:_Fz0抹K7H\ϐQወ&&e&~G=a<|T`ŒowC}ׯ UEQ6W?~p}2%->~Fq`#00yһͷܰzZ|S{~>A#Xp"W\?Վ0MqLM&~Ν;Oj/TV{4crII&-i[t(̖}{;BMҕ+:1DW9 'eJgOj:p2m1H-_6^0|CN$MqLM<ߟfG_8IX8+.~;ޢ.dn8a8$Vs9e55T󼖖fM TĤ yo۶ #&l95W&L~rn7_sKӥ/ԇ`At0?v?H6wt=##RVTzP3ͪW_":l#"I"_5}駟ӟ'"aǼ}Quox+7\"mQ@cd\G\++o{B2i>_!좮CxG:Wn-E/.>-DDt(čA^vk`Č8GVm\;i+ѱm6-at"I" 2(tn鴌#ma9wo|eehkszVVēKz7yzWP@hUʷiVrMKz 7oG1/zS?wޕotЃw*2DDS2DDWٶm+|Fmhjb-ĢiE_Ow:%ZUe گD4qܔ/1{l۽n Eu8[,75)" }`Ґ;֟ӫYݽ}_%T^heSCDOHE ƒdI$ly:@1?h__l ,>;> T>2ĕJn1XwUug׼i"acƻWVga7 WT~_UE6G`"0DHp]wMkV$n}.V}x^ܹ]uiUy٠ۓ-]w1@TGDD2DDKq'Ux%U TV ׹5 M" J狳jo>Yx lqi6_$z/׆! EUPr{>>b^Fdr"Ǔ5G21&:&j '71*[L")I" $Hm2n@!S_sqIfTIǹK"xdmD_C&^xUQeK"H-D_Sm~ì+^DTP2yޓ[It#D*lv^rCn{zqarh!T b R07|M7 &3J^&)kW#@*qJӛz{ XFkf|^wI~V!*aIDZG_ݸw\xepHKV|bk"aCN&)HP;㒋67TF1jNoqUl")I" '_p >l5gվWp4oYehztLvؗ`U/[7'H&fdhbȵMP?dV֮?W-Z`JUDO \=fVa/jYA.^*#Zqa}MLMHA-[lْd _MbE]җ^N}`|0ķ2hlڽ}_7v7)r `5wVuXse!f\ @K^w݉U!mZ{Ïv ּKZ_i9cT\`; "I" &CC%sf]o7αz+jeڼ7.䇿pe_aj~ѤMX.| ;xPVaYZ]T˗ϛjU-pWgw~#¼ є. "PT;e3)RuQ9qIXDƽG? /~Uǝu/Ʒj.j?T׀"62گ3.FU*8>^&HE'?V=d.+/-=ѣ_/Nż T DD/˶nlZ!}-o:Yg< L$ Ool,*ٛ-*0 +]+8Lu#M"i?esgCep(O|NTѓ{cha%W]:ft{{ч|/+"ZDDS2DDK2/90|цU':Gb49=v~?رcL0y)x i/>l: M:NX2Ha e7^+ 6kn~[CR?  LȜq뮹l"ҙ?6&e&<AO~\q=&gA69`ZUyj\ wGB6o̧c3{B5BD%QvV+f\r s?}è`CZD,l\R[U♤y[x⎻jaTk ΢B f֧>=m➃" ;ii?~{s2zd J_+WZrms__֧L'9"CMDtuvv>ܶ7aK6\r/ M̺o/= s-# {m_+6J"m_L Q |7l$*jጵw-E"X㕗]2 &~s )CDT!":{|޽{k͛t:n?IEe6SfDKaV%eL(Uo]71c@D4ɉͪEln?@(V6dxmrAe5^׷]8g֐/8p>ģ@DT˜!":}£>zѷ8+ʣݩfZoq mvXB"*bmlŻQձND냈Ud+њanCz9T׏5)kO\xY2ġCydK0d$WMDt6H:޺uk__(s5ӗ,UO8̜zW?=?=ӯjUz٦[{@JDSvM6t\PYv2޻婻xp>SUߏWWp..MDT!":ˎ=|n#W[[""AbF#_W/2W!P o֟tgdXQ 2$>^^w=gqZQS;JS4ZfcDc>|'gRT1)CDtqǚu B]m.0br UU\ħ?|ϭϚ;Te8І~a.$T"Jzo/osc{O~Zj/ "jG s~y|a{Hw#R'bQ3aַ;[$MDt֨j[[۳>J Urq9^ߥ /"RUj5W}mh~<Q@UlħBD lVa"ڍ6LcW,_46x=u-ZY  .]T_Sܴ&7PսmynL%MjL5l駟޻wo8]̜x^ \HʒMGuo* ZՋ~]жPՖh=E׬7nMjnk¡NDD]f睛2h R'|2H ?}y"^6YL&l6;&Up k.DO?)]e|<ي{?kr1*T8+xUQج}]Ma~nU[`@_V~DC 3Wqh4Fn*knbt8eex J2DDgTqg:w}T*~/3o:g-JMg`=UUZQ-v}o>ןH r,}û靉 ]j#Ɯp>є`eQUz&4uiBe`Ωy^&=K;vJcJt"3gP楯ѣ] )hޜ^~r$/9zh's{S_ *ŵm<1oAaڠMwoGVTrPKtEY kL͚}t CtƨfQ|̋_6L@D/}ǏQd6]lY4 &epo>ןd2]]]V9Uߞt< kEy̘qp/~3ڢ'T V@k?YWlkCKݨ@k`ӄO(2tO>Mw!>cK. `*js+gwmGP7(Շj!D}q  " qرo9!9aĄ:"yU]=7j7Q*DʛG6ퟧq$g&fP H2p; 6-Zv@۫Vm(~{W:a,QU[oUZU˻-\.1"R¤ u凯)mʳ8c `|8"3v[_mP#_ U xhRH2tF E̦yxKJc)Z:_=@\WXmrgᓪN.GDD2DDg0,JBX,v»?|GLeGPE|ZM>Hd @/귗-N7i!L@1Cgd:ՉT{e@$4R,6?mOc3xiYج5 +{|ˏw}"6N4JDD%. ":=BwٽO~+֝= χ䫽YPE$z*h7W}=z5x`"K^sMNUOs1t6O?U)QSlΊc_ͤ5%z+.^|!/0};G1S.ZvmP藈J 2DDg7td"8Tww;g.*,^p8Ԧ{vy[o{QT @-K%sHuq!":1A&^7{Cݤ~fPà8{߲{׾?]3ժhyz)+>c_He9s%K'"*=L9cX<>:{ի^[?}f$"Pd*!\okU}^& ._CD4A[)ޝGUs}dPEQXubmqѶV[k꣭_jkתD@7Y}s~ffB:_p23LN3|((i|hͮFGV_z~:77qpXc;G͑1/0M Q!ٳ^tv$1홿wf$ԥUUuM򊃇S%I[0lۓ'7WR$nlj$1btf=r8XWّ(/h֨46-==U~B!bAReuueuu'BHʙ>kOz,3US8t$= ~QscSNNe]* ;@ϱNJ^pi}/cs9rzuȘA{wK7S$( p:1|^+ cv̰a.rHTez>dee͙3/i8fj%>&M55\њ"ƌW1Uu!(L9,?Bآ|0]}aa᭷ޚjĄPOy9s椦vz%9E)O,WIZ؋bppf\;;҅3ywzҥK) $ 21VXXxl6!DeGgFqxG_s~!KBm>A"H\AХ$Fis^r%vm17þ+zǃ* @q7t1Y+Ru4sYG8']1"T'gZ~޼%g؁9s 7dffvAezn_`ŋNY,+|үO)E܆1ݢ4*+rg&HJ:5G|IcѣN8Ѽ zjҥƞNg[_],IHl0FcSƸ9YK9:ts=gV.J } B$LIIy'nVuSsS ֓1rTf#NBCgޜ[wY}޼yڤIN>tWW>EE4/K"IL JΒ:)Psfז'xpظd| s/L7'0F %F„P@א(XW^G;qpXu}][*M l,R2D|1ЕZbF0Rݵ6lD @(9]ƔdqU%K~L-D0н" "SEQF;rP5h9 ԔG=ap2 BR?`RRR ad茱dʯRD3eoSyfSU7/Z GHI!5Z̑զk+̔C6>_ez$=HMǪ߁ &c@(o487K6L3R2N=huS$F/pijZ:1~ @?:oʯ>h'g\/;!C:.224*'=c$qEeMD$%c|x9 G 8#$qnuGJI!j`@(83}p$n'17I";CTMQWM1>Iq‹ ](DA(Џq2IIU+Ns 2 @rݗzfOlL'DPHcoTm!S=4'eQFuDH^!ƣnu=cD>o  B~#''3, azu{[42N"Se B~CJ¥}N=3 Bĝ SԨNtMHa@@ӴvFR׈" o&T/ PY,䔔aÍ^QN1$&=Qsezps] |8 ;tg$ @"B(?N8qȑNɕ]#)e$%Qá=J&ѣG3ڝؑ߀H<e&7Ih$`.i1G$'Ӝ~(c<>$0Ԕ@  ➹Kc՘QtOLHe͎MH_|r>%鎧`z @L~5hkR?G#9p=n⒈)$!'t=)CwX[illlll<=/8)$.2h$r^>xpEOZb-#Xe_W$$ 1mIb;Xaü^i]`Y*c6  r.2a„8gB+B Whٻ0X#%Imvݾdɒ=k! 3e%Eq DX㑽 ^ !|eM%蟕ltY/[)E͔P_rIII'mN$X8z 0+6j>w$CaDb"˦K-I$2gΜ*Eu)҃L%㌞*@a8#)PWcĉ.%-WFB`?lDP_#F0Bj=GseijGa@c$1, JRSS/^t:;H'mkݥu BăP_BAs~5 VbSIV5p& O65=Qa0&*'33nS;HH_ )+dO[V*[$/sEQ(j kKf#@+%._2?8-,,LKKCSUYyb2'1I ?Q&ɓMFm,A ūk0Bp΍ @C?TǍ5> ")DI9$A @0Ɖ1Px'PNcƌ2e)v~c̬k\6z{2 ]<@%0";vk̳y";u'd#C)vltkQ]L<ٺR]u֌X"; e7;bUUcoj<~ؚ_rnCbi:)fs+Xq3t & Pd/Yd?lg&sddzy~z>f̘<24ER-Esq;z >u8H7~,Zh帅~.xJQɎQ<B,+3f̘:Z'5򲊍yW}y Cr}%$Q͗W -3fΜ9dfڃZO[{، B9L6lx# WI7>-Wi>[&i>vXF*Xeee7蓣vKQw1v_v+$02@zziOM ?wԧ(D\!xa(-DmgѢER7#ƌf3hXlg=A܈iPP ᡣ]9#F(((0.saHJ|rWRaRk):#-e @Dq5_dD1SWAQۅԙ SSd.[WE(gh0rӧesV׋ߤ:H1IRSX?[ 0?̓>@j${Jwl3gΜ:unMdb+E-hj) !yF.P ᡣHC 7oY PxuU^.4Gz3Y' QIAt?X|$Y"#=q:I0KNl2F"5GeBDv>lU)sI!#b {#)-FW~T=jtK:j;@F3qwf5f_L$9sPE _9)󷮜B&LJ)'j;Uzf-t8ӦO53lw?lkg})%B}=@"(++΋{X]G>ڪ5;N=,~{&a~>@}>{#GrhQzZ̸2zz+N%I2NIzz$b@glpD+Yauo*( .h+Zh AK Q Q!H!!C̘1fJ]J>\nveV.).-̙J>zzٺdO0#=[~#^Px{{JJwn=g1cz(PL$)IF !g:A"}$IuSzwh.t0ӭ˖Q1 . 4 ̑CԦ vjsD_j{Hz rHxR'#]_rFFAJ"2d 8KyFij^Lұ| `@(sK{cכǪЂ;Ou Cd=ЇzTFN$Cڪ &9jcû(ˑ1 h{i_?rHTnlغ5\DQGc CD%%ܤdҏ֚2Ф)S|KVMg6/U~Nk 3'N5k Y2X{nAG2)N/k=HT#H رc'MduL dcT5ct2z|D979W^y'X×@Ueӡ]^IARHj? b )q el9s̛7Nv8cј: sx4@0?t9s4*+&;X!%%Il)ll<%IXݩcӦMKNN6ɴ<ҸdNc4, P r]|cǎ5T|z9$Wu0li] $ƈȖLz΃>}9EҏJ)Ȳ钱e ti̙^ziwf#)NAɡ@"B<$U}bGDDm#^zzl7iuVg䜓e eSRRҌ3<O)*p4~ZE A0䱦>M$s=ytN>=55-NWi,# mQP`A(pg#F8cl;ak\щ,!(¹~6Q4j=s>cƌm k=Yډk]?P a;vҥׇ|M֭l:P-4=A\UP銵R2Hc/sW4?T1'~ eѮ(&LHKK>˗ N{bB\}mu@̕J埭3Ԗ &%%ulź%'gpXn !!Hd^`A~Ͽ _-$gQ$&IHuSGG}x7Q]vsssۉNX%1.Yb%]?@"v3e˖ Z}P~/'ݙJcqrPMP|p8|XkUKFc֬1o09`\.ٳ333/fcD2o+4$e{bXxjDIuґw^i,9hdG̬$++K.`(#[1Qd[[^ @̼ N'Yk0FDRs&K$I Am} j@'1.|%٭&8s :ȚD`5d#% ?@_~yjj* !pW٦FW&0>n7i ~I T̕W~Q"bS낻Fygy睧C,,((1cQ7JŖ%SH\HnICo52ƮEϡ@;jWlL$8t_ѣc(9_ e,"F$NKt əHӎl ;K*))(].BK92Q`B(wyq"T~]Jq?τ O6JJ:YRJu]w}OͶ}$Hcnmf1X0! 1ea.|[/O!JHƖ9ct|~uo6.0aȘqX+SfNv)0!H|~K,7aX [#=L$I!IJ10]! A$5RQCoCRKD(M7ݔ㵱RkdHa$06.kҥӧOEZ>U}OZRmYX#)IҕAh?^?]2R\p)Sm'Vs~'#2ĉofm%I)%1&Љu,_$%̑a鏃F`Tц#Tk+ꦒofKM_FhfBOe}e )].ג%Kf̘%27Z[1e0!u3l5{}"7]E8qExdӭ"q k[7` b -RSS|]III$ 1<([oZȕvrJ?.@6dҾ~Xc)‘ZNg5mF-YB(P` 0&pDv^xرc9Ҙ?LD_z~.g#&v錞@Br'˺[W~V8SN+ɘq?ݮsd BHQeW\{SƏq]0rz syh(>u,YriFf%vB_B(09+X;bBWb~ $=@tH#:yT,b\`7Nv:Kih\(H<ecx9R0gmރv@:f@)nrQݞ/?T_MRg.KIIHh"۾F~Xj]G˗ b sdɒV#"bH,g_t!")g$IR2J˾xZ2… ckXװ^/`C(0̢E 5圛-K]DeRj& _ם d"3f̘*##NÓm|i<8,@; A96(,,1r($1Pi&1"?wC$U:FПz;xȞR-IɈQKht:ӟ3ʦ  ,Q;Κ5+7/?&1~~L +IƒUϯ|Ad'1ֲ'#!f;_p_Z-<d}epE+Mj!%IcMgmIdOBC@qr1O{T΍ZXBnrwtWߗھP`NRP0ydsp ĘO$ew\q3'̗z 6_1cEy^{m?}1GځP`@3FËn5xh9'~hhve1jތg<.q?1Ϭknt&u"e4c*Y,Yb٢nRH!}nO VR{yRJ! Kb2. Z]ڣF%8%2@Dq( Ya,ev &%9!KX5Z7.]Y-#~>kL' ;SM%_Qܗ8k{1)(cǎ\N'2pɓ/6H7{38cq/+"D6/RͿe-gFdlft:ws$88̪SNS4gl{쑲_8R%1T4̗F3ȁȉ˥#ZfRU_}vk{Q- tr)G9|%l#!"۳~>xwIѿ[@*gLuLuTrʦC_@|s#uhkx힍x@q>?gz^aX%Dy#X]~@Gx%nN BLx=˲ԢǓ5')$NIdO"[ 1ҏZ//lȲNu{<WDͧ j@|PeǤ¸\&G*1I mDT79(|b ѝW=8g\aR[@(ēB"= XFFD2i&2D+ԃ;OɖL"U9@Jalrfjvݚ][Z(z+gŊGA{@߄K=1F>~~PcN$vqEJ& >} 5}5r3O.5՝Owb 3}GFouֲ#G )9zc@Ƹ\QQv 7@ޒ1V?ͤ1S`RJ)BdOeh?cuO7"34!۷JdP;zBh5PB( nbĈl6-eMgͥD1 0`;c6J8ջc}Ped%ƤHItF1.c, m߾/x 9׬YsFC/$Ͳڑx˱o BuLIƉqg NJIL83JU7yKzNbsT ?1u{oΜ9vݸ+h]ꪑ񰌨fkMbVޕI;9"g1Q}䝏W|禝O=*ikb- o+DFv"9'+Wn޼|(2G VO?aÆ.~(h[~}Z4WdƐ$6IRCCV}x^˫wm&Kr/\w5ٴiӳ>:cLuсQ=˗o7ޠȬ) 2RlIw]ָ*+yĘ Љ)s#AX|#8!ƅgʹI o۰)R7ׯ\޼etIp h2ȸ_ Fu̸~g$))̑T큚:a܇sqsFZk}5JUe}qTܦBHD,=mּE;ﯼ E=<999 ,06f"$2{ h<chs:{Q* iD";Qc .!i1ƹ"PS폿,lŤ;2d<55t O2V gr(XQ{oӣU{6q2AZ˙uYpdEvyTxb|ɸ"9uyst8~WVORc뺾wާz*//Ϙj/ð| :uĥ{`կ~USSc6}_0 On@*1bĹ1$9/%O>aӶP8L#5}eNj*P^Ou DD$șL)y$_Ϗ_ Փ.#K$Kߚx9 :Q.,'!+$s(+G+y͇+"?YU|sϯ~+s'&@Kݡ"tK@(=v bW\dӦMmXܔ{wxX9`|\bƾ yA|~nñ<ɮ?u7;j"qqEgd># Dd,=lD6m}á"EBˏzDtL)zLʎ% yZzÏ[jHF jQuR MB_P{5\@7u2ГV^lP{'+ЉReg=!)HQ"A}w}GKOIseLVx׆^rePc$c|ȐEJ)sL8Btu^~5GqN1fa,L.eEÇ?LMM J!i&#RJ)R۟{j{^ZZM7&vxS;tkF^2ʕ+_Z1ƄDt92e~uR6c.dc SRϞqvasf\{~:O|奾;K?YYdCr`-H ")HSs%$/ӣ6bֲPsn$&)kѥ_Ir jhun 벶FMM7|s?As0kkk|IEQ>n>1$2c0S:ud{` ]7lp=21 |?ͽp Ֆɚ::H"B,{k*>t_~㖭;v`f W ^$)጑p1r3BJșDƃ}U;>;'Zf7^Rb%s[cG=_(TK凥3U7i4fQ~m{mp(+BO|ߵlB2`Lwvq C\@78Ye[O;W7|EBĭk_s ߑJY^B'uxiT!)"撚B>n#GK5]Ԉ+jb{9Ƙ~*??_6m6Ɇ>L83 TB&ƨs|ɻAƾvUh9Ͽi'*HHv&/5Lrhx=ǿ۴w;gkyfg&Iqf#E4p$c\1E%Ra{7_8|K~*m;|IW*F|wQ}]}{w_AA6cLwy CCaysND//~ Kc޾1f)ٙ}H #QUR#¯}t߳Y ~nZe_ ' # $IA,NO邸Jd? )6,宗\W9bt g9Q_TSJvg.FTVf埿3l߾@@_g 0nk|>"2&PgD>)6*D @ a 粡ٷ1~'>߽|o˦Bh~k=3.`9 aGvH""]#&w2KI&$kvݫ?>wkCf?Roo(3=cp m M㌝;kڌcxM;uߟ4ijP ~z͚5D974Re9܋.c2hEV"!DPci)}cu۽+n;2ܬ>*/wx啜ٳ-\1n(@*D\r"(2v'FRIUI(x^|rR=sFE\jfaI]2ŇXdxJ>5o;Jb(dc8S$nr㤇HwhޝU_|Yc[M5^:0;3vV"#8'"&˟+ATYʌPNqrD*J ;𲫮zO.Q#+WX_cw_ɘ4={ڢwْIn"-yq#~oײ~}횂dLJb UDDZM0&4!j XD%3N\%L1nIYIzx}? ՜8qe M>MU&[r:xެ)F(sU8 2 Gmjjx#Hn8g%\'+1ƕL*ɺ9ٙg23~ RQlӿy˘4#oΥgd'ߦ:dRkVM8 Z">Sg$HjKg4h>U|e'*TZaE;_FHmϝ63tR07.F$ە5ٶ~ÇP qlim۶;vnbklz".E^︕fq[aqɉ&?<_eFdA_R]ubg_#-){Ј9 ݹz 2ɓ$R1 TSf$IjPL R"nP#1I dͺ}|劝UR "&uM Kyp"CD.6TsStQ8Ư{͛7#P ^{- Ďk RUuDK% uNV6hI] UkpqͶ f#!7yGrgKTVecW^YwlWWIM菉yEV/JFS]913744]ySD>?t9iTWKg73 MJZȉc=^fjp,@A(]No.oS}l3z:SRjnWGDgPaҐ"ỏԱSDbK fH$5.%Hkn:c-Y>c \qlFR0$ML?{;㶜K@2pF~͛ڿ۬&Jz#SՖ;JID(v>(OBW95QLR =Z$"1^f͊+4Mkhh0ǜuPg8vy6[1zyIiKNO?9pԘbϝ8cxRba)$~(Lz@2NlkHɄ6sxCIICSsyO[QsrքZ8 z!aV~Sd#6V;o޼3f̟?ĉd3}YL+_J0kt]7#!+Ѱc<’ !#uƕst===mڄ1md5 0,Qz~v洹մc DRH"2 o-_}z",zi2eʔna֬Y xo~ӦM[l1>Ύ%!-[j'II%7ig fM;?hݫ$3(XOz1I>DR2cMYƌX̲' ${M ]JRKi&4TݾƣUV-Rts̋15jE]5ܔTRj7jKNPݾp›oR*BĄУ'Mn'~LJ r kvm.cl`/E(֫ @Gِ EC6HQdOY82)mDű=g^?_(D,N` Nn_9m4ue\HII:t(=:?~r׮]{i֯[ 1'Ҫ]oݳŞƈ{ tdO44SJgڸ9tЉ3T;#b-H4Ij? LN-K,SU(c/H/DOF%+#Х+# IIRRH'ɖ.u3.UH$1ng(Ώ- ܭ-a51 3L|)ujYv#%`uV׷DNFH22UKʖȘ\Nl)+Ioh$1JRW"f3-qX]S VVVZm{/*MdqHyaZ%gff&%%%''fee͞=hСC >8|d>/6#.?v9%_Tnw=nWyS( lqn, 򳓼."Td^\nqݴ̀a-Z|ß޷3LNN>h۶m;w<~5k:Y&YǮm婊cnO*4M;\9TGhaƸ-)ՙINՑBH!K*,%%I6[8cRD s؜ivťR2t3Em&$Laq~6Bf72)NBSH &tB2G-7M$iIY Ĉqs8oIJdL![cQ^ քtΤTm3anl3r59\jЂ!FCb[τs> 5RU . d=k<+33;~Q^YmbbhxOk䳥$)Wʃ15?04iҤI讻jhh())>u5k(i$θQEW^Rm>6UK )5͑a\1rݓ;8p=5M̞y^ژ1ۅ7II օj)\!f#ܪIkH0nE$jdZeR)q6l̮`D:΍aT'N8IATS䯑bW}>rr҆5L U1k>_se C?h5^=ι>g͚xbLzjZËF#GŸ͜X%0urڛ b Q_yiO#=ۘqnhowS]+3-M&cN-EoCP]ofI& MG#Ϡ4qGzN\'qaj*"Y+ 3=DWH Rsi]#zTq ׄ*9Un]a Z_DRH ")Een-Ac)Tg~|1c|XtСC-HZE3-1{7|͛8{ !+xsԩSfj;y(dg@'iiZ;RU:Tuyߌ*!L fW)wpMYg+otѪ&)[fK!1I]=֊x<"JII)(( QF)eiicǚK)wYWWwōkPJi\2mZc)YM',5M ꖹ9 _<2qO*RI!D8(t(^#5MHu.dDqfe0PXq8ܙYdƴ1qB$%W$DqC'uR[͊pXÌIb29Q}c+){䟖>{ʔ)͛4iRAAQ:*Φ#(s}?#bJ w^iۛ>e,#7 bL9b"jll4 ruMa2Fؑ9ƨkltRY(XiШҲ~sEVsSsÛǝwgQ˖B785Æ 39qÇܿ7˵lٲ#?q1 ^}yf.[԰M aD\-x:mU@(2lذÇo۶1}xJMnyZ2:{/ !Dƕi)W_}}"#+WHZGr999999D4k,c g28VRP|up1&llh57755asԲZEOC_4ϘP;,NdСx75oߑ¤s2E^ 28'(Psdg HL3gΜ5kֶm2FuM?YE)CeM=ٺv'E&e,R+ kc?p~H$˖qbFzzƌ3f̰>LDqʊ I*Z][k%GIgLӴz9Iɲ X^e,nYhn222Ӎ/ 4(%%%77K.NԖ$%~[e7nnNoBamՆ-o>5?.IQz!bk!2pz%K<폟}zlX PMĘc̨(QsíN.#və5kV~~i;N!-((5רeٌƱlX9((lv׾>lǎo_g̘2y,5~Fկ:|ɨۍ Nvɓꪗ_~0ƕKJػo\ݬIgANBk/Y$E̘JL Ɔ-[֮Xj>YA7F݂93򗿜u""-'>\ޒn^olmz4Q3_@p8(JEEšC;o߾Cn۶-# +sss'NĉƾB 1iZpͩ%vv_*bٌpخ|>pnUUfQUkKҤ1cL>=##cܸqn'|mj;m!:)shҤIW_Gu^rVSX8?ŷ96;@(l6=ܳrݻw˶Y+/>VA2 lcG?c̙KRJ]g cNG쟲 z{,]Ը|7n\.߷o߱cB(sUUUA666a#p8FIәd5jTJJ1כmLu\uTKk\S fQ)#G8P__5z輼쳧z1ɾ+_E-3.ff\BNZ#;;{ĉt:f7BG>(++\K//7j>\U: >MJɈS|Bğ3h[XXx饗= q_nrQ;/r 7`I)c)Dzh/9iEZt۝6,flA֣:G>!5WŸuRr3g?={[GCG~wwm4tIM2q*?aNF5j.3$>cTSTTtw>SL\rZ0.0^iHOO/X3`B:TN:&'8<˸ b>AnkqUv-1š/Ń`䑪P(t!9dW޾wXb{g̝;%11ƴ?Ǎ/_8nͱ8ڕtDJ"B0ƌw-?ohܺuG4~[kʑ$dlw-$!a'k=/Q&ҴV6m9@A(0@o~W]uՆ ~_~Bucb8Pʼ`#;|뮻[V~~q1ad~D:!˗-Sm{ݻ; 炨't`c mLDU5o<'`{lsرG_zB\83f̘4i7߼v-[Zj/cԩSK.$77tR$Ak@G0_xpo?Zr,NBJHJnjz?MwzIJ RיEDy8gF-\0@wC(0G>'󪪪:o۷=ztժUk֬4G;묳9 L6mРA&2pNIJiוRK/*;^zntY%ƪI:|W]{nΞq6DA"I2eŻ{Ha[]2ΝFB:r\QF555-YDڍ734MRJ#?~Q +:)7nz,yMl$U<̚6b]MOr:ee>Yj5 d L"KN8,- Cx.AعsqGWUU555q5M RJ-LKK3>U$#oeb[S"R=V]Z*:3Ƅƕ꥗^p8ڐڵkhn:A#@Lh(cc2%aq6r{x-[]Sqq0IsG7nܬYzG@'QKM f8Mwȑ7#Gs^ʨ"V1k:CFFƽޛa^ z Bh51鸣"Фp, }?n馛uhb- c6nGJ*k^0\a̙sWn<<29E .05肾{nFdkƨ|QIM˒(Klܔft2\u[ӟ"iM3'J)裏5 ` a}GZZڷ|5Gկ~m 3e 9;'@_莌n"z饗6l79&ۭˍgϞ}뭷^}ՄzBz[̜\Eя~4q'|r%%%Q&͖?o޼oyل!6G2dz/͟?ܹo3СCьx^0g)1cɒg݀o8Z/ pB_2zf͚%KX˱cǮ^xYXd֑!5JQe} 18-ȰS f;Ob|>cǎ]}Շ6cicNH:L)vclB [ 0S~,O,Y/ ;v5\c$2#s1XgED͑1JN(3eS f>cQw|JKKb|qQZ׈]23 &vl %_ }f7@_obc]Ąaccsn}3gĘ/YҘb?ӅP ZGV3E .8|0_W֭3e XKX5w%BNhF> |>7|ke2k12-9|A4ǎیn,\V5Zj\̈́D!>9݌mo2w<֨źE7ףp @KЩ̻̀mٲvw}gW_}5bS,K1؉)vk0p0C_2~9=cB#YX'XHdȲRж]3eS ތG~+n*++B@oϮJs"Yƺ5EfD-\2nډA@b }f;wg\_\Ћ{1Ƙ5sօcY3z?&}Ct92ᔥa{l-[lٰasnnm^ʘf7%!2Լ}Z zg}fWuݺ}yu:XwȎJpBd2?RCMر ebW0X%0$2EJyqcǎ+gUKDd hnv nP^=ȑ#Jss]|9@R,+ȺRԮ2&3=/A{0tcG,뒬uz'$ a @ 5̈́:k&_k ` Vzj$AzvLIeQA(Iu!4ܡ-h |>4:,_HzXW- e n4:̔^h1fb.31[J&MPV:u`.+gx^k_fA $ `@B.J2&ȴ" ˔z/Agk^4J Ѡ/@(pB4@_z5m.hB@2iiih0ГN uIq1`D@g?zR72 0-e3FFڟc0XѠ/@(ǎS7oz̜9s } 5 Ѡ/@(&@G$%%x^#127` dB;@_P:iҥhS1bzLQQĝ 2@_ s?|4)7=fرkqK`,[0S:i„ h-[ =_*˔̩1Q-a `,F> t~衇0,Xwk ࡇrh#| 0.SNE#@2e F1h;:e8{իq^'?yN%2o޼UV%8#wy' '?ysd0~ ŋ:+-Zd(Kgh 3v~@[… +?Ç~,3e`Q2py4o"[_c%"7o޵^v lذa֬YhSEEEVVzKeeeNNq'D~3gL3gDMSC=DzWVV֯ksww# 3ek|' 3e+=Sr ,|} 2<7|3,̔t7xhy$2wGy֍7ވD82gٲeh]v. lٲA;@K|>߅^zj4 X} `7oᅬs3@8|EΝ;Ǎvi׮]ǏG;QTTG)%}1G!lܸq}e˖!~ t{ $'|r…h.\O -[C"rlK.jh HH=w܁v~a?FS@B{1ԑ5e' image/svg+xml golang-gonum-v1-gonum-0.14.0/graph/000077500000000000000000000000001450372207100167375ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/.gitignore000066400000000000000000000000101450372207100207160ustar00rootroot00000000000000test.outgolang-gonum-v1-gonum-0.14.0/graph/README.md000066400000000000000000000004551450372207100202220ustar00rootroot00000000000000# Gonum graph [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/graph)](https://pkg.go.dev/gonum.org/v1/gonum/graph) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/graph?status.svg)](https://godocs.io/gonum.org/v1/gonum/graph) This is a generalized graph package for the Go language. golang-gonum-v1-gonum-0.14.0/graph/coloring/000077500000000000000000000000001450372207100205535ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/coloring/coloring.go000066400000000000000000000566061450372207100227330ustar00rootroot00000000000000// Copyright ©2021 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. // See Lewis, A Guide to Graph Colouring: Algorithms and Applications // doi:10.1007/978-3-319-25730-3 for significant discussion of approaches. package coloring import ( "errors" "sort" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/topo" ) // ErrInvalidPartialColoring is returned when a partial coloring // is provided for a graph with inadmissible color assignments. var ErrInvalidPartialColoring = errors.New("coloring: invalid partial coloring") // Sets returns the mapping from colors to sets of node IDs. Each set of // node IDs is sorted by ascending value. func Sets(colors map[int64]int) map[int][]int64 { sets := make(map[int][]int64) for id, c := range colors { sets[c] = append(sets[c], id) } for _, s := range sets { sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) } return sets } // Dsatur returns an approximate minimal chromatic number of g and a // corresponding vertex coloring using the heuristic Dsatur coloring algorithm. // If a partial coloring is provided the coloring will be consistent with // that partial coloring if possible. Otherwise Dsatur will return // ErrInvalidPartialColoring. // See Brélaz doi:10.1145/359094.359101 for details of the algorithm. func Dsatur(g graph.Undirected, partial map[int64]int) (k int, colors map[int64]int, err error) { nodes := g.Nodes() n := nodes.Len() if n == 0 { return } partial, ok := newPartial(partial, g) if !ok { return -1, nil, ErrInvalidPartialColoring } order := bySaturationDegree(nodes, g, partial) order.heuristic = order.dsatur k, colors = greedyColoringOf(g, order, order.colors) return k, colors, nil } // Terminator is a cancellation-only context type. A context.Context // may be used as a Terminator. type Terminator interface { // Done returns a channel that is closed when work // should be terminated. Done may return nil if this // work can never be canceled. // Successive calls to Done should return the same value. Done() <-chan struct{} // If Done is not yet closed, Err returns nil. // If Done is closed, Err returns a non-nil error // explaining why. // After Err returns a non-nil error, successive // calls to Err should return the same error. Err() error } // DsaturExact returns the exact minimal chromatic number of g and a // corresponding vertex coloring using the branch-and-bound Dsatur coloring // algorithm of Brélaz. If the provided terminator is cancelled or times out // before completion, the terminator's reason for termination will be returned // along with a potentially sub-optimal chromatic number and coloring. If // term is nil, DsaturExact will run to completion. // See Brélaz doi:10.1145/359094.359101 for details of the algorithm. func DsaturExact(term Terminator, g graph.Undirected) (k int, colors map[int64]int, err error) { // This is implemented essentially as described in algorithm 1 of // doi:10.1002/net.21716 with the exception that we obtain a // tighter upper bound by doing a single run of an approximate // Brélaz Dsatur coloring, using the result if the recurrence is // cancelled. // We also use the initial maximum clique as a starting point for // the exact search. If there is more than one maximum clique, we // need to ensure that we pick the one that will lead us down the // easiest branch of the search tree. This will be the maximum // clique with the lowest degree into the remainder of the graph. nodes := g.Nodes() n := nodes.Len() if n == 0 { return } lb, maxClique, cliques := maximumClique(g) if lb == n { return lb, colorClique(maxClique), nil } order := bySaturationDegree(nodes, g, make(map[int64]int)) order.heuristic = order.dsatur // Find initial coloring via Dsatur heuristic. ub, initial := greedyColoringOf(g, order, order.colors) if lb == ub { return ub, initial, nil } selector := &order.saturationDegree cand := newDsaturColoring(order.nodes, bestMaximumClique(g, cliques)) k, colors, err = dSaturExact(term, selector, cand, len(cand.colors), ub, nil) if colors == nil { return ub, initial, err } if k == lb { err = nil } return k, colors, err } // dSaturColoring is a partial graph coloring. type dSaturColoring struct { colors map[int64]int uncolored set.Int64s } // newDsaturColoring returns a dSaturColoring representing a partial coloring // of a graph with the given nodes and colors. func newDsaturColoring(nodes []graph.Node, colors map[int64]int) dSaturColoring { uncolored := make(set.Int64s) for _, v := range nodes { vid := v.ID() if _, ok := colors[vid]; !ok { uncolored.Add(vid) } } return dSaturColoring{ colors: colors, uncolored: uncolored, } } // color moves a node from the uncolored set to the colored set. func (c dSaturColoring) color(id int64) { if !c.uncolored.Has(id) { if _, ok := c.colors[id]; ok { panic("coloring: coloring already colored node") } panic("coloring: coloring non-existent node") } // The node has its uncolored mark removed, but is // not explicitly colored until the dSaturExact // caller has completed its recursive exploration // of the feasible colors. c.uncolored.Remove(id) } // uncolor moves a node from the colored set to the uncolored set. func (c dSaturColoring) uncolor(id int64) { if _, ok := c.colors[id]; !ok { if c.uncolored.Has(id) { panic("coloring: uncoloring already uncolored node") } panic("coloring: uncoloring non-existent node") } delete(c.colors, id) c.uncolored.Add(id) } // dSaturExact recursively searches for an exact minimum vertex coloring of the // full graph in cand. If no chromatic number lower than ub is found, colors is // returned as nil. func dSaturExact(term Terminator, selector *saturationDegree, cand dSaturColoring, k, ub int, best map[int64]int) (newK int, colors map[int64]int, err error) { if len(cand.uncolored) == 0 { // In the published algorithm, this is guarded by k < ub, // but dSaturExact is never called with k >= ub; in the // initial call we have excluded cases where k == ub and // it cannot be greater, and in the recursive call, we // have already checked that k < ub. return k, clone(cand.colors), nil } if term != nil { select { case <-term.Done(): if best == nil { return -1, nil, term.Err() } colors := make(set.Ints) for _, c := range best { colors.Add(c) } return colors.Count(), best, term.Err() default: } } // Select the next node. selector.reset(cand.colors) vid := selector.nodes[selector.dsatur()].ID() cand.color(vid) // If uncolor panics, we have failed to find a // feasible color. This should never happen. defer cand.uncolor(vid) // Keep the adjacent colors set as it will be // overwritten by child recurrences. adjColors := selector.adjColors[selector.indexOf[vid]] // Collect all feasible existing colors plus one, remembering it. feasible := make(set.Ints) for _, c := range cand.colors { if adjColors.Has(c) { continue } feasible.Add(c) } var newCol int for c := 0; c < ub; c++ { if feasible.Has(c) || adjColors.Has(c) { continue } feasible.Add(c) newCol = c break } // Recur over every feasible color. for c := range feasible { cand.colors[vid] = c effK := k if c == newCol { effK++ } // In the published algorithm, the expression max(effK, lb) < ub is // used, but lb < ub always since it is not updated and dSaturExact // is not called if lb == ub, and it cannot be greater. if effK < ub { ub, best, err = dSaturExact(term, selector, cand, effK, ub, best) if err != nil { return ub, best, err } } } return ub, best, nil } // maximumClique returns a maximum clique in g and its order. func maximumClique(g graph.Undirected) (k int, maxClique []graph.Node, cliques [][]graph.Node) { cliques = topo.BronKerbosch(g) for _, c := range topo.BronKerbosch(g) { if len(c) > len(maxClique) { maxClique = c } } return len(maxClique), maxClique, cliques } // bestMaximumClique returns the maximum clique in g with the lowest degree into // the remainder of the graph. func bestMaximumClique(g graph.Undirected, cliques [][]graph.Node) (colors map[int64]int) { switch len(cliques) { case 0: return nil case 1: return colorClique(cliques[0]) } sort.Slice(cliques, func(i, j int) bool { return len(cliques[i]) > len(cliques[j]) }) maxClique := cliques[0] minDegree := cliqueDegree(g, maxClique) for _, c := range cliques[1:] { if len(c) < len(maxClique) { break } d := cliqueDegree(g, c) if d < minDegree { minDegree = d maxClique = c } } return colorClique(maxClique) } // cliqueDegree returns the degree of the clique to nodes outside the clique. func cliqueDegree(g graph.Undirected, clique []graph.Node) int { n := make(set.Int64s) for _, u := range clique { to := g.From(u.ID()) for to.Next() { n.Add(to.Node().ID()) } } return n.Count() - len(clique) } // colorClique returns a valid coloring for the given clique. func colorClique(clique []graph.Node) map[int64]int { colors := make(map[int64]int, len(clique)) for c, u := range clique { colors[u.ID()] = c } return colors } // Randomized returns an approximate minimal chromatic number of g and a // corresponding vertex coloring using a greedy coloring algorithm with a // random node ordering. If src is non-nil it will be used as the random // source, otherwise the global random source will be used. If a partial // coloring is provided the coloring will be consistent with that partial // coloring if possible. Otherwise Randomized will return // ErrInvalidPartialColoring. func Randomized(g graph.Undirected, partial map[int64]int, src rand.Source) (k int, colors map[int64]int, err error) { nodes := g.Nodes() n := nodes.Len() if n == 0 { return } partial, ok := newPartial(partial, g) if !ok { return -1, nil, ErrInvalidPartialColoring } k, colors = greedyColoringOf(g, randomize(nodes, src), partial) return k, colors, nil } // randomize returns a graph.Node iterator that returns nodes in a random // order. func randomize(it graph.Nodes, src rand.Source) graph.Nodes { nodes := graph.NodesOf(it) var shuffle func(int, func(i, j int)) if src == nil { shuffle = rand.Shuffle } else { shuffle = rand.New(src).Shuffle } shuffle(len(nodes), func(i, j int) { nodes[i], nodes[j] = nodes[j], nodes[i] }) return iterator.NewOrderedNodes(nodes) } // RecursiveLargestFirst returns an approximate minimal chromatic number // of g and a corresponding vertex coloring using the Recursive Largest // First coloring algorithm. // See Leighton doi:10.6028/jres.084.024 for details of the algorithm. func RecursiveLargestFirst(g graph.Undirected) (k int, colors map[int64]int) { it := g.Nodes() n := it.Len() if n == 0 { return } nodes := graph.NodesOf(it) colors = make(map[int64]int) // The names of variable here have been changed from the original PL-1 // for clarity, but the correspondence is as follows: // E -> isolated // F -> boundary // L -> current // COL -> k // C -> colors // Initialize the boundary vector to the node degrees. boundary := make([]int, len(nodes)) indexOf := make(map[int64]int) for i, u := range nodes { uid := u.ID() indexOf[uid] = i boundary[i] = g.From(uid).Len() } deleteFrom := func(vec []int, idx int) { vec[idx] = -1 to := g.From(nodes[idx].ID()) for to.Next() { vec[indexOf[to.Node().ID()]]-- } } isolated := make([]int, len(nodes)) // If there are any uncolored nodes, initiate the assignment of the next color. // Incrementing color happens at the end of the loop in this implementation. var current int for j := 0; j < n; { // Reinitialize the isolated vector. copy(isolated, boundary) // Select the node in U₁ with maximal degree in U₁. for i := range nodes { if boundary[i] > boundary[current] { current = i } } // Color the node just selected and continue to // color nodes with color k until U₁ is empty. for isolated[current] >= 0 { // Color node and modify U₁ and U₂ accordingly. deleteFrom(isolated, current) deleteFrom(boundary, current) colors[nodes[current].ID()] = k j++ to := g.From(nodes[current].ID()) for to.Next() { i := indexOf[to.Node().ID()] if isolated[i] >= 0 { deleteFrom(isolated, i) } } // Find the first node in U₁, if any. for i := range nodes { if isolated[i] < 0 { continue } // If U₁ is not empty, select the next node for coloring. current = i currAvail := boundary[current] - isolated[current] for j := i; j < n; j++ { if isolated[j] < 0 { continue } nextAvail := boundary[j] - isolated[j] switch { case nextAvail > currAvail, nextAvail == currAvail && isolated[j] < isolated[current]: current = j currAvail = boundary[current] - isolated[current] } } break } } k++ } return k, colors } // SanSegundo returns an approximate minimal chromatic number of g and a // corresponding vertex coloring using the PASS rule with a single run of a // greedy coloring algorithm. If a partial coloring is provided the coloring // will be consistent with that partial coloring if possible. Otherwise // SanSegundo will return ErrInvalidPartialColoring. // See San Segundo doi:10.1016/j.cor.2011.10.008 for details of the algorithm. func SanSegundo(g graph.Undirected, partial map[int64]int) (k int, colors map[int64]int, err error) { nodes := g.Nodes() n := nodes.Len() if n == 0 { return } partial, ok := newPartial(partial, g) if !ok { return -1, nil, ErrInvalidPartialColoring } order := bySaturationDegree(nodes, g, partial) order.heuristic = order.pass k, colors = greedyColoringOf(g, order, order.colors) return k, colors, nil } // WelshPowell returns an approximate minimal chromatic number of g and a // corresponding vertex coloring using the Welsh and Powell coloring algorithm. // If a partial coloring is provided the coloring will be consistent with that // partial coloring if possible. Otherwise WelshPowell will return // ErrInvalidPartialColoring. // See Welsh and Powell doi:10.1093/comjnl/10.1.85 for details of the algorithm. func WelshPowell(g graph.Undirected, partial map[int64]int) (k int, colors map[int64]int, err error) { nodes := g.Nodes() n := nodes.Len() if n == 0 { return } partial, ok := newPartial(partial, g) if !ok { return -1, nil, ErrInvalidPartialColoring } k, colors = greedyColoringOf(g, byDescendingDegree(nodes, g), partial) return k, colors, nil } // byDescendingDegree returns a graph.Node iterator that returns nodes // in order of descending degree. func byDescendingDegree(it graph.Nodes, g graph.Undirected) graph.Nodes { nodes := graph.NodesOf(it) n := byDescDegree{nodes: nodes, degrees: make([]int, len(nodes))} for i, u := range nodes { n.degrees[i] = g.From(u.ID()).Len() } sort.Sort(n) return iterator.NewOrderedNodes(nodes) } // byDescDegree sorts a slice of graph.Node descending by the corresponding // value of the degrees slice. type byDescDegree struct { nodes []graph.Node degrees []int } func (n byDescDegree) Len() int { return len(n.nodes) } func (n byDescDegree) Less(i, j int) bool { return n.degrees[i] > n.degrees[j] } func (n byDescDegree) Swap(i, j int) { n.nodes[i], n.nodes[j] = n.nodes[j], n.nodes[i] n.degrees[i], n.degrees[j] = n.degrees[j], n.degrees[i] } // newPartial returns a new valid partial coloring is valid for g. An empty // partial coloring is valid. If the partial coloring is not valid, a nil map // is returned, otherwise a new non-nil map is returned. If the input partial // coloring is nil, a new map is created and returned. func newPartial(partial map[int64]int, g graph.Undirected) (map[int64]int, bool) { if partial == nil { return make(map[int64]int), true } for id, c := range partial { if g.Node(id) == nil { return nil, false } to := g.From(id) for to.Next() { if oc, ok := partial[to.Node().ID()]; ok && c == oc { return nil, false } } } return clone(partial), true } func clone(colors map[int64]int) map[int64]int { new := make(map[int64]int, len(colors)) for id, c := range colors { new[id] = c } return new } // greedyColoringOf returns the chromatic number and a graph coloring of g // based on the sequential coloring of nodes given by order and starting from // the given partial coloring. func greedyColoringOf(g graph.Undirected, order graph.Nodes, partial map[int64]int) (k int, colors map[int64]int) { colors = partial constrained := false for _, c := range colors { if c > k { k = c constrained = true } } // Next nodes are chosen by the specified heuristic in order. for order.Next() { uid := order.Node().ID() used := colorsOf(g.From(uid), colors) if c, ok := colors[uid]; ok { if used.Has(c) { return -1, nil } continue } // Color the chosen vertex with the least possible // (lowest numbered) color. for c := 0; c <= k+1; c++ { if !used.Has(c) { colors[uid] = c if c > k { k = c } break } } } if !constrained { return k + 1, colors } seen := make(set.Ints) for _, c := range colors { seen.Add(c) } return seen.Count(), colors } // colorsOf returns all the colors in the coloring that are used by the // given nodes. func colorsOf(nodes graph.Nodes, coloring map[int64]int) set.Ints { c := make(set.Ints, nodes.Len()) for nodes.Next() { used, ok := coloring[nodes.Node().ID()] if ok { c.Add(used) } } return c } // saturationDegreeIterator is a graph.Nodes iterator that returns nodes ordered // by decreasing saturation degree. type saturationDegreeIterator struct { // cnt is the number of nodes that // have been returned and curr is // the current selection. cnt, curr int // heuristic determines the // iterator's node selection // heuristic. It can be either // saturationDegree.dsatur or // saturationDegree.pass. heuristic func() int saturationDegree } // bySaturationDegree returns a new saturationDegreeIterator that will // iterate over the node in it based on the given graph and partial coloring. // The saturationDegreeIterator holds a reference to colors allowing // greedyColoringOf to update its coloring. func bySaturationDegree(it graph.Nodes, g graph.Undirected, colors map[int64]int) *saturationDegreeIterator { return &saturationDegreeIterator{ cnt: -1, curr: -1, saturationDegree: newSaturationDegree(it, g, colors), } } // Len returns the number of elements remaining in the iterator. // saturationDegreeIterator is an indeterminate iterator, so Len always // returns -1. This is required to satisfy the graph.Iterator interface. func (n *saturationDegreeIterator) Len() int { return -1 } // Next advances the iterator to the next node and returns whether // the next call to the Node method will return a valid Node. func (n *saturationDegreeIterator) Next() bool { if uint(n.cnt)+1 < uint(len(n.nodes)) { n.cnt++ switch n.cnt { case 0: max := -1 for i, d := range n.degrees { if d > max { max = d n.curr = i } } default: prev := n.Node().ID() c := n.colors[prev] to := n.g.From(prev) for to.Next() { n.adjColors[n.indexOf[to.Node().ID()]].Add(c) } chosen := n.heuristic() if chosen < 0 || chosen == n.curr { return false } n.curr = chosen } return true } n.cnt = len(n.nodes) return false } // Node returns the current node. func (n *saturationDegreeIterator) Node() graph.Node { return n.nodes[n.curr] } // Reset implements the graph.Iterator interface. It should not be called. func (n *saturationDegreeIterator) Reset() { panic("coloring: invalid call to Reset") } // saturationDegree is a saturation degree node choice heuristic. type saturationDegree struct { // nodes is the set of nodes being // iterated over. nodes []graph.Node // indexOf is a mapping between node // IDs and elements of degree and // adjColors. degrees holds the // degree of each node and adjColors // holds the current adjacent // colors of each node. indexOf map[int64]int degrees []int adjColors []set.Ints // g and colors are the graph coloring. // colors is held by both the iterator // and greedyColoringOf. g graph.Undirected colors map[int64]int // work is a temporary workspace. work []int } // newSaturationDegree returns a saturationDegree heuristic based on the // nodes in the given node iterator and graph, using the provided coloring. func newSaturationDegree(it graph.Nodes, g graph.Undirected, colors map[int64]int) saturationDegree { nodes := graph.NodesOf(it) sd := saturationDegree{ nodes: nodes, indexOf: make(map[int64]int, len(nodes)), degrees: make([]int, len(nodes)), adjColors: make([]set.Ints, len(nodes)), g: g, colors: colors, } for i, u := range nodes { sd.degrees[i] = g.From(u.ID()).Len() sd.adjColors[i] = make(set.Ints) sd.indexOf[u.ID()] = i } for uid, c := range colors { to := g.From(uid) for to.Next() { sd.adjColors[sd.indexOf[to.Node().ID()]].Add(c) } } return sd } // reset re-initializes the saturation with the provided colors. func (sd *saturationDegree) reset(colors map[int64]int) { sd.colors = colors for i := range sd.nodes { sd.adjColors[i] = make(set.Ints) } for uid, c := range colors { to := sd.g.From(uid) for to.Next() { sd.adjColors[sd.indexOf[to.Node().ID()]].Add(c) } } } // dsatur implements the Dsatur heuristic from Brélaz doi:10.1145/359094.359101. func (sd *saturationDegree) dsatur() int { maxSat, maxDeg, chosen := -1, -1, -1 for i, u := range sd.nodes { uid := u.ID() if _, ok := sd.colors[uid]; ok { continue } s := saturationDegreeOf(uid, sd.g, sd.colors) d := sd.degrees[i] switch { // Choose a vertex with a maximal saturation degree. // If there is an equality, choose any vertex of maximal // degree in the uncolored subgraph. case s > maxSat, s == maxSat && d > maxDeg: maxSat = s maxDeg = d chosen = i } } return chosen } // pass implements the PASS heuristic from San Segundo doi:10.1016/j.cor.2011.10.008. func (sd *saturationDegree) pass() int { maxSat, chosen := -1, -1 sd.work = sd.work[:0] for i, u := range sd.nodes { uid := u.ID() if _, ok := sd.colors[uid]; ok { continue } s := saturationDegreeOf(uid, sd.g, sd.colors) switch { case s > maxSat: maxSat = s sd.work = sd.work[:0] fallthrough case s == maxSat: sd.work = append(sd.work, i) } } maxAvail := -1 for _, vs := range sd.work { var avail int for _, v := range sd.work { if v != vs { avail += sd.same(sd.adjColors[vs], sd.adjColors[v]) } } switch { case avail > maxAvail, avail == maxAvail && sd.nodes[chosen].ID() < sd.nodes[vs].ID(): maxAvail = avail chosen = vs } } return chosen } // same implements the same function from San Segundo doi:10.1016/j.cor.2011.10.008. func (sd *saturationDegree) same(vi, vj set.Ints) int { valid := make(set.Ints) for _, c := range sd.colors { if !vi.Has(c) { valid.Add(c) } } for c := range vj { valid.Remove(c) } return valid.Count() } // saturationDegreeOf returns the saturation degree of the node corresponding to // vid in g with the given coloring. func saturationDegreeOf(vid int64, g graph.Undirected, colors map[int64]int) int { if _, ok := colors[vid]; ok { panic("coloring: saturation degree not defined for colored node") } adjColors := make(set.Ints) to := g.From(vid) for to.Next() { if c, ok := colors[to.Node().ID()]; ok { adjColors.Add(c) } } return adjColors.Count() } golang-gonum-v1-gonum-0.14.0/graph/coloring/coloring_test.go000066400000000000000000000612521450372207100237630ustar00rootroot00000000000000// Copyright ©2021 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 coloring import ( "context" "flag" "testing" "time" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding/graph6" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/simple" ) var runLong = flag.Bool("color.long", false, "run long exact coloring tests") var coloringTests = []struct { name string g graph.Undirected colors int long bool partial map[int64]int dsatur set.Ints randomized set.Ints rlf set.Ints sanSegundo set.Ints welshPowell set.Ints }{ { name: "empty", g: simple.NewUndirectedGraph(), colors: 0, }, { name: "singleton", // https://hog.grinvin.org/ViewGraphInfo.action?id=1310 g: graph6.Graph("@"), colors: 1, }, { name: "kite", // https://hog.grinvin.org/ViewGraphInfo.action?id=782 g: graph6.Graph("DzC"), colors: 3, randomized: setOf(3, 4), partial: map[int64]int{1: 2}, }, { name: "triangle+1", g: graph6.Graph("Cw"), colors: 3, partial: map[int64]int{1: 2}, }, { name: "bipartite halves", g: graph6.Graph("G?]uf?"), colors: 2, randomized: setOf(2, 3, 4), partial: map[int64]int{1: 3}, }, { name: "bipartite alternating", g: graph6.Graph("GKUalO"), colors: 2, randomized: setOf(2, 3, 4), welshPowell: setOf(2, 3, 4), partial: map[int64]int{1: 1}, }, { name: "3/4 bipartite", // https://hog.grinvin.org/ViewGraphInfo.action?id=466 g: graph6.Graph("F?~v_"), colors: 2, partial: map[int64]int{1: 1}, }, { name: "cubical", // https://hog.grinvin.org/ViewGraphInfo.action?id=1022 g: graph6.Graph("Gs@ipo"), colors: 2, randomized: setOf(2, 3, 4), welshPowell: setOf(2, 3), partial: map[int64]int{1: 1}, }, { name: "HoG33106", // https://hog.grinvin.org/ViewGraphInfo.action?id=33106 g: graph6.Graph("K???WWKKxf]C"), colors: 2, randomized: setOf(2, 3, 4), partial: map[int64]int{1: 1}, }, { name: "HoG41237", // https://hog.grinvin.org/ViewGraphInfo.action?id=41237 g: graph6.Graph("~?BCs?GO?@?O??@?A????G?A?????G??O????????????????????G????_???O??????????????????????OC????A???????????????@@?????A?????????????????????????C??????G??????O?????????????????????????G?@????????@???????D????????_??????CG???????@???????????????????????ACG???????EA???????O?G??????S????????C???_?????O??C?????@??????????W????????B??????????????O?????G??????????_????o????A????A_???@O_????????@?O????G???W???????????@G?????????A??????@?????S??????????????????????????????B????????????K????????????????????????@_????????????o??G????????????A?????????????_?????????_??G?????????G????@_???????????C?_????????????@????????A???A?????????A???O?????????????C???????????K??_??????????@O??_??????????C??@???????????G??????????E????????A??G??????????????????C????A???@???????????O??O???????????????_????????????@_?_????????????@O?C?????????????_?@?????????????G????C???O???????????????G?O????????????????O???????O???C????????????O?A?????????????????_??????????????@_C???????????????I?C??????????????@??G???????????????_???CA??????????????????_???????O????????O???????????????A??????????????????G?????????????????_C?????????????????OC?????????????????g????????D?????????????????@?G?????????????????GA??????????????????K??????????????????@O???????????????G????????G????????????????????P???????????????????OO???????????????????@_??????????????????????????????????????????????????????????????????@?????????????????????_???A?????????????????????????????????????????????????????????????O?????????????????????_??@????????????????????????????????????????G???????????@????????????????????????????????C?????????????????????????????????????????????????K??????????????????????I??????????????????????C_???????????????????_C????????????????????????K???????????????????????K???????????????????????`???????????????????????`??????????????????????I???????????????????????C?O?????????????????????A?O??????????????????????O?G??????????????????????@?C???????????????????????H????????????????????????OG???????????????????????GC?????????????????????????B?????????????????????????I?????????????????????????????????????????????????????????????????????????????????????????????????????????????c?????????????????????????CO???????????????????????A?A????????????????????????C?@????????????????????????C??_???????????????????????O??O?????????????????????????o???????????????????????????K???????????????????????????E??????????????????????????@_?????????????????????????D????????????????????????????`???????????????????????????????CG??????????????????????????@?O??????????????????????????@O???????????????????????????CG???????????????????????????C@???????????????????????????A?_?????????????????????C?????????????????????????????G?????????????????????????????@????????????????????????????????????AA?????????????????????????????B?????????????????????????????AG?????????????????????????????G_????????????????????????????CA?????????????????????????????CG??????????????????????????A???????????????????????????????O??????????????????????????????G????A?????????????????????????????AAG?????????????????????????????CCC??????????????????????????????cG?????????????????????????????@CA?????????????????????????????AG@??????????????????????????????P?"), colors: 2, randomized: setOf(2, 3, 4), welshPowell: setOf(2, 3), partial: map[int64]int{1: 1}, }, // Test graphs from Leighton doi:10.6028/jres.084.024. { name: "exams", // Figure 4 induced by the nodes in E. g: graph6.Graph("EDZw"), colors: 3, randomized: setOf(3, 4), partial: map[int64]int{1: 2}, }, { name: "exam_scheduler_1", // Figure 4. g: graph6.Graph("JQ?HaWN{l~?"), colors: 5, randomized: setOf(5, 6), }, { name: "exam_scheduler_2", // Figure 11. g: graph6.Graph("GTPHz{"), colors: 4, randomized: setOf(4, 5), partial: map[int64]int{1: 3}, }, // Test graph from Brélaz doi:10.1145/359094.359101. { name: "Brélaz", // Figure 1. g: graph6.Graph(`I??GG\rmg`), colors: 3, randomized: setOf(3, 4), rlf: setOf(3, 4), welshPowell: setOf(3, 4), partial: map[int64]int{1: 2}, }, // Test graph from Lima and Carmo doi:10.22456/2175-2745.80721. { name: "Lima Carmo", // Figure 2. g: graph6.Graph("Gh]S?G"), colors: 3, randomized: setOf(3, 4), sanSegundo: setOf(3, 4), partial: map[int64]int{1: 2}, }, // Test graph from San Segundo doi:10.1016/j.cor.2011.10.008. { name: "San Segundo", // Figure 1 A. g: graph6.Graph(`HMn\r\v`), colors: 5, randomized: setOf(5, 6), partial: map[int64]int{1: 4}, }, { name: "tetrahedron", // https://hog.grinvin.org/ViewGraphInfo.action?id=74 g: graph6.Graph("C~"), colors: 4, partial: map[int64]int{1: 3}, }, { name: "triangle", // https://hog.grinvin.org/ViewGraphInfo.action?id=1374 g: graph6.Graph("Bw"), colors: 3, partial: map[int64]int{1: 2}, }, { name: "square", // https://hog.grinvin.org/ViewGraphInfo.action?id=674 g: graph6.Graph("Cl"), colors: 2, partial: map[int64]int{1: 1}, }, { name: "cycle-5", // https://hog.grinvin.org/ViewGraphInfo.action?id=340 g: graph6.Graph("Dhc"), colors: 3, partial: map[int64]int{1: 2}, }, { name: "cycle-6", // https://hog.grinvin.org/ViewGraphInfo.action?id=670 g: graph6.Graph("EhEG"), colors: 2, randomized: setOf(2, 3), partial: map[int64]int{1: 1}, }, { name: "wheel-5", // https://hog.grinvin.org/ViewGraphInfo.action?id=442 g: graph6.Graph("D|s"), colors: 3, partial: map[int64]int{1: 2}, }, { name: "wheel-6", // https://hog.grinvin.org/ViewGraphInfo.action?id=204 g: graph6.Graph("E|fG"), colors: 4, partial: map[int64]int{1: 3}, }, { name: "wheel-7", g: graph6.Graph("F|eMG"), colors: 3, randomized: setOf(3, 4), partial: map[int64]int{1: 2}, }, { name: "sudoku board", // The graph of the constraints of a sudoku puzzle board. g: graph6.Graph("~?@P~~~~~~wF?{BFFFFbbwF~?~{B~~?wF?wF_[BF?wwwFFb_[^?wF~?wF~_[B~{?_C?OA?OC_C?_W_C?_wOA?O{C?_C^?_C?fwA?OA~_C?_F~_C?_F?OA?OF?c?_CB_W_C?_FFA?OA?w{C?_CBbwC?_C?~wA?OA?~{?_C?_^~_C?_F?wA?OA?wF?c?_CB_[BC?_C?wFFA?OA?wFF__C?_[BbwC?_C?wF~?OA?OF?~{?_C?_[B~{?_C?_C?_A?OA?OA?OC_C?_C?_CBC?_C?_C?_wOA?OA?OAF__C?_C?_C^?_C?_C?_C~?OA?OA?OA~_C?_C?_C?~{?_C?_C?_F?OA?OA?OA?wC_C?_C?_CB_W_C?_C?_C?wwOA?OA?OA?w{C?_C?_C?_[^?_C?_C?_C?~wA?OA?OA?OF~_C?_C?_C?_^~_C?_C?_C?wF?OA?OA?OA?wF?c?_C?_C?_[B_W_C?_C?_C?wFFA?OA?OA?OF?w{C?_C?_C?_[BbwC?_C?_C?_F?~wA?OA?OA?OF?~{?_C?_C?_CB_^~"), colors: 9, randomized: setOf(9, 10, 11, 12, 13), sanSegundo: setOf(9, 10), welshPowell: setOf(9, 10, 11, 12, 13, 14), partial: map[int64]int{1: 3}, }, { name: "sudoku problem", // The constraint graph for the problem in the sudoku example. g: graph6.Graph("~?@Y~~~~~~?F|_B?F?F_Bw?~?F{?^w?w??wC?[Bzwww?FF_?[^??F~??F~~kB~w?wF?v~?wFz{B_W?F?w|~F?w{?B_[^??F?~w??wF~_?B_^~?C?_C??A?OA?_?_C?_W?C?_CF??OA?O~|__C?bw??_C?fw??OA?V~}_C?_F~?C?_C?wD~OA?OF?_?_C?_[B??_C?_FF}wOA?OFF_?C?_CBbw??_C?_F~~oA?OA?~{??C?_CB~~^_C?_F?w??OA?OF?wC?C?_CB_[B|w_C?_F?ww?A?OA?wFF_?C?_CB_[^??C?_C?wF~??A?OA?wF~_??_C?_[B~w?_C?_C?_C??A?OA?OA?OC?C?_C?_C?_W?C?_C?_C?_~}A?OA?OA?O{??_C?_C?_C^vwC?_C?_C?f|~?OA?OA?OA~_??_C?_C?_F~|{?_C?_C?_F??A?OA?OA?OF?_?_C?_C?_CB_W?C?_C?_C?_FF??OA?OA?OA?w|~__C?_C?_CBbw??_C?_C?_C?~w??OA?OA?OA?~{??C?_C?_C?_^~?C?_C?_C?_F?w??OA?OA?OA?wF?_?_C?_C?_CB_[B??_C?_C?_C?wFF??OA?OA?OA?wFF_?C?_C?_C?_[Bbw??_C?_C?_C?wF~}wA?OA?OA?OF?~{??C?_C?_C?_[B~w"), colors: 9, dsatur: setOf(9, 10, 11), randomized: setOf(9, 10, 11, 12, 13, 14, 15, 16, 17), rlf: setOf(9, 10, 11, 12), sanSegundo: setOf(9, 10, 11), welshPowell: setOf(9, 10, 11, 12, 13), partial: map[int64]int{1: 3}, }, // Test graphs from NetworkX. { name: "cs_shc", g: graph6.Graph("Djs"), colors: 3, randomized: setOf(3, 4), }, { name: "gis_hc", g: graph6.Graph("E?ow"), colors: 2, randomized: setOf(2, 3), }, { name: "gis_shc|rs_shc", // https://hog.grinvin.org/ViewGraphInfo.action?id=594 g: graph6.Graph("CR"), colors: 2, randomized: setOf(2, 3), }, { name: "lf_hc", g: graph6.Graph(`F\^E?`), colors: 3, dsatur: setOf(3, 4), randomized: setOf(3, 4), rlf: setOf(3, 4), sanSegundo: setOf(3, 4), welshPowell: setOf(3, 4), }, { name: "lf_shc", g: graph6.Graph("ELQ?"), colors: 2, randomized: setOf(2, 3), welshPowell: setOf(2, 3), }, { name: "lfi_hc", g: graph6.Graph("Hhe[b@_"), colors: 3, dsatur: setOf(3, 4), randomized: setOf(3, 4), sanSegundo: setOf(3, 4), welshPowell: setOf(3, 4), }, { name: "lfi_shc|slf_shc", g: graph6.Graph("FheZ?"), colors: 3, dsatur: setOf(3, 4), randomized: setOf(3, 4), welshPowell: setOf(3, 4), }, { name: "no_solo", // https://hog.grinvin.org/ViewGraphInfo.action?id=264, https://hog.grinvin.org/ViewGraphInfo.action?id=498 g: graph6.Graph("K????AccaQHG"), colors: 2, randomized: setOf(2, 3), }, { name: "sl_hc", g: graph6.Graph("Gzg[Yk"), colors: 4, dsatur: setOf(4, 5), randomized: setOf(4, 5), sanSegundo: setOf(4, 5), welshPowell: setOf(4, 5), }, { name: "sl_shc", g: graph6.Graph("E{Sw"), colors: 3, dsatur: setOf(3, 4), randomized: setOf(3, 4), welshPowell: setOf(3, 4), }, { name: "slf_hc", g: graph6.Graph("G}`?W["), colors: 3, dsatur: setOf(3, 4), randomized: setOf(3, 4), rlf: setOf(3, 4), welshPowell: setOf(3, 4), }, { name: "sli_hc", g: graph6.Graph("H{czYtt"), colors: 4, dsatur: setOf(4, 5), randomized: setOf(4, 5), welshPowell: setOf(4, 5), }, { name: "sli_shc", g: graph6.Graph("FxdSW"), colors: 3, dsatur: setOf(3, 4), randomized: setOf(3, 4), sanSegundo: setOf(3, 4), welshPowell: setOf(3, 4), }, { name: "rsi_shc", g: graph6.Graph("EheW"), colors: 3, randomized: setOf(3, 4), }, { name: "V_plus_not_in_A_cal", g: graph6.Graph("HQQ?W__"), colors: 2, randomized: setOf(2, 3), }, // DIMACS queens graphs { name: "queen5_5", g: graph6.Graph("X~~FJk~F|KIxizS^dF{iWQjcdV[dFyQb}KiWOdVHAT\\acg~acg~"), colors: 5, dsatur: setOf(5), randomized: setOf(5, 6, 7, 8, 9, 10), rlf: setOf(5), sanSegundo: setOf(5), welshPowell: setOf(5, 6, 7), }, { name: "queen6_6", g: graph6.Graph("c~~}FDrMw~`~goSwtMYhvIF{SN{dEAQfCehrcTMyPO~ca`~acgoPQSwcCtMWcahvaQIF|CcSN{KSdEAAIQfC__ehrCCcTMwSQPO~ogca`~"), colors: 7, dsatur: setOf(7, 8, 9), randomized: setOf(7, 8, 9, 10, 11, 12), rlf: setOf(7, 8), sanSegundo: setOf(7, 8), welshPowell: setOf(7, 8, 9), }, { name: "queen7_7", g: graph6.Graph("p~~~}B`[XrbnB~@~sKAb`iMLS[xS\\wgN{IB~cSKAPPocibbcibfQDPvc`O^wcIB~aQIE@CcS[HCdS[WaQiM]GcIbnPC`O^xCQD@~ogca`_Ogcab`GCQTPpa@CdS[wQGcIbn`GaOgN|APC`O^{EDCcSKA@AaQIMC_OGcibbCA@CdS[wOHCQDPv_gQGcIB~_gQGcIB~"), colors: 7, dsatur: setOf(7, 8, 9, 10, 11), randomized: setOf(7, 8, 9, 10, 11, 12, 13), rlf: setOf(7, 8, 9), sanSegundo: setOf(7, 8, 9), welshPowell: setOf(7, 8, 9, 10, 11, 12), }, { name: "queen8_8", long: true, g: graph6.Graph("~?@?~~~~~?wJ`fFFNBn_~wF~gK@OwLOwYg[[iFNDOzwSB~_gF~cIB?QDB_cdOw[ciFFQQg[{cDOzwcD?~wQA_^}GcIB?PC`OwHCQTB`aKciFFaCciFNPAOTBncOcD?~waC_gF~`GaOgK@APC`OwHAPCdOwW_GqQg[[GaCciFN`COcDOzyCPAOSB~cGaC_gF~_gQGcIB?OSHCQDB_c@APCdOwW_GAKciFFA?aGQQg[{C`COcDOz{C`COcD?~yAOaGQA_^}@_gQGcIB?OCDAPC`OwH?OCHCQTB`a?_GAKciFFA?_GaCciFN@?QCPAOTBn_SC`COcD?~{A_cGaC_gF~"), colors: 9, dsatur: setOf(9, 10, 11, 12), randomized: setOf(9, 10, 11, 12, 13, 14, 15), rlf: setOf(9, 10), sanSegundo: setOf(9, 10, 11), welshPowell: setOf(9, 10, 11, 12, 13, 14, 15), }, } func setOf(vals ...int) set.Ints { s := make(set.Ints) for _, v := range vals { s.Add(v) } return s } func TestDsatur(t *testing.T) { for _, test := range coloringTests { for _, partial := range []map[int64]int{nil, test.partial} { k, colors, err := Dsatur(test.g, partial) if partial == nil && k != test.colors && !test.dsatur.Has(k) { t.Errorf("unexpected chromatic number for %q: got:%d want:%d or in %v\ncolors:%v", test.name, k, test.colors, test.dsatur, colors) } if s := Sets(colors); len(s) != k { t.Errorf("mismatch between number of color sets and k: |sets|=%d k=%d", len(s), k) } if missing, ok := isCompleteColoring(colors, test.g); !ok { t.Errorf("incomplete coloring for %q: missing %d\ngot:%v", test.name, missing, colors) } if xid, yid, ok := isValidColoring(colors, test.g); !ok { t.Errorf("invalid coloring for %q: %d--%d match color\ncolors:%v", test.name, xid, yid, colors) } if err != nil { t.Errorf("unexpected error: %v", err) } for id, c := range partial { if colors[id] != c { t.Errorf("coloring not consistent with input partial for %q:\ngot:%v\nwant superset of:%v", test.name, colors, partial) break } } } } } func TestDsaturExact(t *testing.T) { timeout := time.Microsecond for _, test := range coloringTests { for _, useTimeout := range []bool{false, true} { if test.long && !*runLong && !useTimeout { continue } var ( term Terminator cancel func() ) if useTimeout { term, cancel = context.WithTimeout(context.Background(), timeout) } else { // Set a backstop to safeguard against occasional long running // cases crashing the entire test set so get as much time as we can. deadline, ok := t.Deadline() if ok { // But make sure we are faster than the watchdog. deadline = deadline.Add(-10 * time.Second) if deadline.Before(time.Now()) { t.Errorf("we ran out of time by %q", test.name) } term, cancel = context.WithDeadline(context.Background(), deadline) } else { cancel = func() {} } } k, colors, err := DsaturExact(term, test.g) cancel() if k != test.colors && (useTimeout && !test.dsatur.Has(k)) { t.Errorf("unexpected chromatic number for %q timeout=%t: got:%d want:%d or in %v\ncolors:%v", test.name, useTimeout, k, test.colors, test.dsatur, colors) } if s := Sets(colors); len(s) != k { t.Errorf("mismatch between number of color sets and k: |sets|=%d k=%d", len(s), k) } if missing, ok := isCompleteColoring(colors, test.g); !ok { t.Errorf("incomplete coloring for %q: missing %d\ngot:%v", test.name, missing, colors) } if xid, yid, ok := isValidColoring(colors, test.g); !ok { t.Errorf("invalid coloring for %q: %d--%d match color\ncolors:%v", test.name, xid, yid, colors) } if err != nil && !useTimeout { if err != context.DeadlineExceeded { t.Errorf("unexpected error for %q: %v", test.name, err) } else { t.Logf("test ran too long for %q", test.name) } } } } } func TestRandomized(t *testing.T) { for seed := uint64(1); seed <= 1000; seed++ { for _, test := range coloringTests { for _, partial := range []map[int64]int{nil, test.partial} { k, colors, err := Randomized(test.g, partial, rand.NewSource(seed)) if partial == nil && k != test.colors && !test.randomized.Has(k) { t.Errorf("unexpected chromatic number for %q with seed=%d: got:%d want:%d or in %v\ncolors:%v", test.name, seed, k, test.colors, test.randomized, colors) } if s := Sets(colors); len(s) != k { t.Errorf("mismatch between number of color sets and k: |sets|=%d k=%d", len(s), k) } if missing, ok := isCompleteColoring(colors, test.g); !ok { t.Errorf("incomplete coloring for %q: missing %d\ngot:%v", test.name, missing, colors) } if xid, yid, ok := isValidColoring(colors, test.g); !ok { t.Errorf("invalid coloring for %q: %d--%d match color\ncolors:%v", test.name, xid, yid, colors) } if err != nil { t.Errorf("unexpected error: %v", err) } for id, c := range partial { if colors[id] != c { t.Errorf("coloring not consistent with input partial for %q:\ngot:%v\nwant superset of:%v", test.name, colors, partial) break } } } } } } func TestRecursiveLargestFirst(t *testing.T) { for _, test := range coloringTests { k, colors := RecursiveLargestFirst(test.g) if k != test.colors && !test.rlf.Has(k) { t.Errorf("unexpected chromatic number for %q: got:%d want:%d", test.name, k, test.colors) } if s := Sets(colors); len(s) != k { t.Errorf("mismatch between number of color sets and k: |sets|=%d k=%d", len(s), k) } if missing, ok := isCompleteColoring(colors, test.g); !ok { t.Errorf("incomplete coloring for %q: missing %d\ngot:%v", test.name, missing, colors) } if xid, yid, ok := isValidColoring(colors, test.g); !ok { t.Errorf("invalid coloring for %q: %d--%d match color\ncolors:%v", test.name, xid, yid, colors) } } } func TestSanSegundo(t *testing.T) { for _, test := range coloringTests { for _, partial := range []map[int64]int{nil, test.partial} { k, colors, err := SanSegundo(test.g, partial) if partial == nil && k != test.colors && !test.sanSegundo.Has(k) { t.Errorf("unexpected chromatic number for %q: got:%d want:%d\ncolors:%v", test.name, k, test.colors, colors) } if s := Sets(colors); len(s) != k { t.Errorf("mismatch between number of color sets and k: |sets|=%d k=%d", len(s), k) } if missing, ok := isCompleteColoring(colors, test.g); !ok { t.Errorf("incomplete coloring for %q: missing %d\ngot:%v", test.name, missing, colors) } if xid, yid, ok := isValidColoring(colors, test.g); !ok { t.Errorf("invalid coloring for %q: %d--%d match color\ncolors:%v", test.name, xid, yid, colors) } if err != nil { t.Errorf("unexpected error: %v", err) } for id, c := range partial { if colors[id] != c { t.Errorf("coloring not consistent with input partial for %q:\ngot:%v\nwant superset of:%v", test.name, colors, partial) break } } } } } func TestWelshPowell(t *testing.T) { for _, test := range coloringTests { for _, partial := range []map[int64]int{nil, test.partial} { k, colors, err := WelshPowell(test.g, partial) if partial == nil && k != test.colors && !test.welshPowell.Has(k) { t.Errorf("unexpected chromatic number for %q: got:%d want:%d", test.name, k, test.colors) } if s := Sets(colors); len(s) != k { t.Errorf("mismatch between number of color sets and k: |sets|=%d k=%d", len(s), k) } if missing, ok := isCompleteColoring(colors, test.g); !ok { t.Errorf("incomplete coloring for %q: missing %d\ngot:%v", test.name, missing, colors) } if xid, yid, ok := isValidColoring(colors, test.g); !ok { t.Errorf("invalid coloring for %q: %d--%d match color\ncolors:%v", test.name, xid, yid, colors) } if err != nil { t.Errorf("unexpected error: %v", err) } for id, c := range partial { if colors[id] != c { t.Errorf("coloring not consistent with input partial for %q:\ngot:%v\nwant superset of:%v", test.name, colors, partial) break } } } } } var newPartialTests = []struct { partial map[int64]int g graph.Undirected wantValid bool }{ { partial: map[int64]int{0: 1, 1: 1}, g: undirectedGraphFrom([]intset{ 0: linksTo(1, 2), 1: linksTo(2), 2: nil, }), wantValid: false, }, { partial: map[int64]int{0: 0, 1: 1}, g: undirectedGraphFrom([]intset{ 0: linksTo(1, 2), 1: linksTo(2), 2: nil, }), wantValid: true, }, { partial: map[int64]int{0: 0, 1: 1, 3: 3}, g: undirectedGraphFrom([]intset{ 0: linksTo(1, 2), 1: linksTo(2), 2: nil, }), wantValid: false, }, { partial: map[int64]int{0: 0, 1: 1, 2: 2}, g: undirectedGraphFrom([]intset{ 0: linksTo(1, 2), 1: linksTo(2), 2: nil, }), wantValid: true, }, { partial: nil, g: undirectedGraphFrom([]intset{ 0: linksTo(1, 2), 1: linksTo(2), 2: nil, }), wantValid: true, }, } func TestNewPartial(t *testing.T) { for i, test := range newPartialTests { gotPartial, gotValid := newPartial(test.partial, test.g) if gotValid != test.wantValid { t.Errorf("unexpected validity for test %d: got:%t want:%t", i, gotValid, test.wantValid) } xid, yid, ok := isValidColoring(gotPartial, test.g) if !ok { t.Errorf("invalid partial returned for test %d: %d--%d match color\ncolors:%v", i, xid, yid, gotPartial) } } } func isCompleteColoring(colors map[int64]int, g graph.Undirected) (missing int64, ok bool) { for _, n := range graph.NodesOf(g.Nodes()) { if _, ok := colors[n.ID()]; !ok { return n.ID(), false } } return 0, true } func isValidColoring(colors map[int64]int, g graph.Undirected) (x, y int64, ok bool) { for xid, c := range colors { to := g.From(xid) for to.Next() { yid := to.Node().ID() if oc, ok := colors[yid]; ok && c == oc { return xid, yid, false } } } return 0, 0, true } // intset is an integer set. type intset map[int64]struct{} func linksTo(i ...int64) intset { if len(i) == 0 { return nil } s := make(intset) for _, v := range i { s[v] = struct{}{} } return s } func undirectedGraphFrom(g []intset) graph.Undirected { dg := simple.NewUndirectedGraph() for u, e := range g { for v := range e { dg.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } return dg } func BenchmarkColoring(b *testing.B) { for _, bench := range coloringTests { b.Run(bench.name, func(b *testing.B) { b.Run("Dsatur", func(b *testing.B) { for i := 0; i < b.N; i++ { _, _, err := Dsatur(bench.g, nil) if err != nil { b.Fatalf("coloring failed: %v", err) } } }) if !bench.long || *runLong { b.Run("DsaturExact", func(b *testing.B) { for i := 0; i < b.N; i++ { _, _, err := DsaturExact(nil, bench.g) if err != nil { b.Fatalf("coloring failed: %v", err) } } }) } b.Run("RecursiveLargestFirst", func(b *testing.B) { for i := 0; i < b.N; i++ { RecursiveLargestFirst(bench.g) } }) b.Run("SanSegundo", func(b *testing.B) { for i := 0; i < b.N; i++ { _, _, err := SanSegundo(bench.g, nil) if err != nil { b.Fatalf("coloring failed: %v", err) } } }) b.Run("WelshPowell", func(b *testing.B) { for i := 0; i < b.N; i++ { _, _, err := WelshPowell(bench.g, nil) if err != nil { b.Fatalf("coloring failed: %v", err) } } }) }) } } golang-gonum-v1-gonum-0.14.0/graph/coloring/doc.go000066400000000000000000000004331450372207100216470ustar00rootroot00000000000000// Copyright ©2021 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 coloring provides graph coloring functions. package coloring // import "gonum.org/v1/gonum/graph/coloring" golang-gonum-v1-gonum-0.14.0/graph/coloring/sudoku_example_test.go000066400000000000000000000061001450372207100251630ustar00rootroot00000000000000// Copyright ©2021 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 coloring_test import ( "fmt" "log" "gonum.org/v1/gonum/graph/coloring" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/simple" ) // A hard sudoku problem graded at a level of difficulty, "not fun". // https://dingo.sbs.arizona.edu/~sandiway/sudoku/examples.html var grid = [9][9]int{ {0, 2, 0 /**/, 0, 0, 0 /**/, 0, 0, 0}, {0, 0, 0 /**/, 6, 0, 0 /**/, 0, 0, 3}, {0, 7, 4 /**/, 0, 8, 0 /**/, 0, 0, 0}, {0, 0, 0 /**/, 0, 0, 3 /**/, 0, 0, 2}, {0, 8, 0 /**/, 0, 4, 0 /**/, 0, 1, 0}, {6, 0, 0 /**/, 5, 0, 0 /**/, 0, 0, 0}, {0, 0, 0 /**/, 0, 1, 0 /**/, 7, 8, 0}, {5, 0, 0 /**/, 0, 0, 9 /**/, 0, 0, 0}, {0, 0, 0 /**/, 0, 0, 0 /**/, 0, 4, 0}, } func Example_sudoku() { g := simple.NewUndirectedGraph() // Build the sudoku board constraints. for i := 0; i < 9; i++ { gen.Complete(g, row(i)) gen.Complete(g, col(i)) } for r := 0; r < 3; r++ { for c := 0; c < 3; c++ { gen.Complete(g, block{r, c}) } } // Add constraints for the digits. gen.Complete(g, gen.IDRange{First: -9, Last: -1}) // Mark constraints onto the graph. for r, row := range &grid { for c, val := range &row { if val == 0 { continue } for i := 1; i <= 9; i++ { if i != val { g.SetEdge(simple.Edge{F: simple.Node(-i), T: simple.Node(id(r, c))}) } } } } k, colors, err := coloring.DsaturExact(nil, g) if err != nil { log.Fatal(err) } if k != 9 { log.Fatalln("could not solve problem", k) } sets := coloring.Sets(colors) for r := 0; r < 9; r++ { if r != 0 && r%3 == 0 { fmt.Println() } for c := 0; c < 9; c++ { if c != 0 { fmt.Print(" ") if c%3 == 0 { fmt.Print(" ") } } got := -int(sets[colors[id(r, c)]][0]) if want := grid[r][c]; want != 0 && got != want { log.Fatalf("mismatch at row=%d col=%d: %d != %d", r, c, got, want) } fmt.Print(got) } fmt.Println() } // Output: // // 1 2 6 4 3 7 9 5 8 // 8 9 5 6 2 1 4 7 3 // 3 7 4 9 8 5 1 2 6 // // 4 5 7 1 9 3 8 6 2 // 9 8 3 2 4 6 5 1 7 // 6 1 2 5 7 8 3 9 4 // // 2 6 9 3 1 4 7 8 5 // 5 4 8 7 6 9 2 3 1 // 7 3 1 8 5 2 6 4 9 } // row is a gen.IDer that enumerates the IDs of graph // nodes representing a row of cells of a sudoku board. type row int func (r row) Len() int { return 9 } func (r row) ID(i int) int64 { return id(int(r), i) } // col is a gen.IDer that enumerates the IDs of graph // nodes representing a column of cells of a sudoku board. type col int func (c col) Len() int { return 9 } func (c col) ID(i int) int64 { return id(i, int(c)) } // block is a gen.IDer that enumerates the IDs of graph // nodes representing a 3×3 block of cells of a sudoku board. type block struct { r, c int } func (b block) Len() int { return 9 } func (b block) ID(i int) int64 { return id(b.r*3, b.c*3) + int64(i%3) + int64(i/3)*9 } // id returns the graph node ID of a cell in a sudoku board. func id(row, col int) int64 { return int64(row*9 + col) } golang-gonum-v1-gonum-0.14.0/graph/community/000077500000000000000000000000001450372207100207635ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/community/bisect.go000066400000000000000000000156041450372207100225710ustar00rootroot00000000000000// Copyright ©2016 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 community import ( "errors" "fmt" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" ) // Interval is an interval of resolutions with a common score. type Interval struct { // Low and High delimit the interval // such that the interval is [low, high). Low, High float64 // Score is the score of the interval. Score float64 // Reduced is the best scoring // community membership found for the // interval. Reduced } // Reduced is a graph reduction. type Reduced interface { // Communities returns the community // structure of the reduction. Communities() [][]graph.Node } // Size is a score function that is the reciprocal of the number of communities. func Size(g ReducedGraph) float64 { return 1 / float64(len(g.Structure())) } // Weight is a score function that is the sum of community weights. The concrete // type of g must be a pointer to a ReducedUndirected or a ReducedDirected, otherwise // Weight will panic. func Weight(g ReducedGraph) float64 { var w float64 switch g := g.(type) { case *ReducedUndirected: for _, n := range g.nodes { w += n.weight } case *ReducedDirected: for _, n := range g.nodes { w += n.weight } default: panic(fmt.Sprintf("community: invalid graph type: %T", g)) } return w } // ModularScore returns a modularized scoring function for Profile based on the // graph g and the given score function. The effort parameter determines how // many attempts will be made to get an improved score for any given resolution. func ModularScore(g graph.Graph, score func(ReducedGraph) float64, effort int, src rand.Source) func(float64) (float64, Reduced) { return func(resolution float64) (float64, Reduced) { max := math.Inf(-1) var best Reduced for i := 0; i < effort; i++ { r := Modularize(g, resolution, src) s := score(r) if s > max { max = s best = r } } return max, best } } // SizeMultiplex is a score function that is the reciprocal of the number of communities. func SizeMultiplex(g ReducedMultiplex) float64 { return 1 / float64(len(g.Structure())) } // WeightMultiplex is a score function that is the sum of community weights. The concrete // type of g must be pointer to a ReducedUndirectedMultiplex or a ReducedDirectedMultiplex, // otherwise WeightMultiplex will panic. func WeightMultiplex(g ReducedMultiplex) float64 { var w float64 switch g := g.(type) { case *ReducedUndirectedMultiplex: for _, n := range g.nodes { for _, lw := range n.weights { w += lw } } case *ReducedDirectedMultiplex: for _, n := range g.nodes { for _, lw := range n.weights { w += lw } } default: panic(fmt.Sprintf("community: invalid graph type: %T", g)) } return w } // ModularMultiplexScore returns a modularized scoring function for Profile based // on the graph g and the given score function. The effort parameter determines how // many attempts will be made to get an improved score for any given resolution. func ModularMultiplexScore(g Multiplex, weights []float64, all bool, score func(ReducedMultiplex) float64, effort int, src rand.Source) func(float64) (float64, Reduced) { return func(resolution float64) (float64, Reduced) { max := math.Inf(-1) var best Reduced for i := 0; i < effort; i++ { r := ModularizeMultiplex(g, weights, []float64{resolution}, all, src) s := score(r) if s > max { max = s best = r } } return max, best } } // Profile returns an approximate profile of score values in the resolution domain [low,high) // at the given granularity. The score is calculated by bisecting calls to fn. If log is true, // log space bisection is used, otherwise bisection is linear. The function fn should be // monotonically decreasing in at least 1/grain evaluations. Profile will attempt to detect // non-monotonicity during the bisection. // // Since exact modularity optimization is known to be NP-hard and Profile calls modularization // routines repeatedly, it is unlikely to return the exact resolution profile. func Profile(fn func(float64) (float64, Reduced), log bool, grain, low, high float64) (profile []Interval, err error) { if low >= high { return nil, errors.New("community: zero or negative width domain") } defer func() { r := recover() e, ok := r.(nonDecreasing) if ok { err = e return } if r != nil { panic(r) } }() left, comm := fn(low) right, _ := fn(high) for i := 1; i < int(1/grain); i++ { rt, _ := fn(high) right = math.Max(right, rt) } profile = bisect(fn, log, grain, low, left, high, right, comm) // We may have missed some non-monotonicity, // so merge low score discordant domains into // their lower resolution neighbours. return fixUp(profile), nil } type nonDecreasing int func (n nonDecreasing) Error() string { return fmt.Sprintf("community: profile does not reliably monotonically decrease: tried %d times", n) } func bisect(fn func(float64) (float64, Reduced), log bool, grain, low, scoreLow, high, scoreHigh float64, comm Reduced) []Interval { if low >= high { panic("community: zero or negative width domain") } if math.IsNaN(scoreLow) || math.IsNaN(scoreHigh) { return nil } // Heuristically determine a reasonable number // of times to try to get a higher value. maxIter := int(1 / grain) lowComm := comm for n := 0; scoreLow < scoreHigh; n++ { if n > maxIter { panic(nonDecreasing(n)) } scoreLow, lowComm = fn(low) } if scoreLow == scoreHigh || tooSmall(low, high, grain, log) { return []Interval{{Low: low, High: high, Score: scoreLow, Reduced: lowComm}} } var mid float64 if log { mid = math.Sqrt(low * high) } else { mid = (low + high) / 2 } scoreMid := math.Inf(-1) var midComm Reduced for n := 0; scoreMid < scoreHigh; n++ { if n > maxIter { panic(nonDecreasing(n)) } scoreMid, midComm = fn(mid) } lower := bisect(fn, log, grain, low, scoreLow, mid, scoreMid, lowComm) higher := bisect(fn, log, grain, mid, scoreMid, high, scoreHigh, midComm) for n := 0; lower[len(lower)-1].Score < higher[0].Score; n++ { if n > maxIter { panic(nonDecreasing(n)) } lower[len(lower)-1].Score, lower[len(lower)-1].Reduced = fn(low) } if lower[len(lower)-1].Score == higher[0].Score { higher[0].Low = lower[len(lower)-1].Low lower = lower[:len(lower)-1] if len(lower) == 0 { return higher } } return append(lower, higher...) } // fixUp non-monotonically decreasing interval scores. func fixUp(profile []Interval) []Interval { max := profile[len(profile)-1].Score for i := len(profile) - 2; i >= 0; i-- { if profile[i].Score > max { max = profile[i].Score continue } profile[i+1].Low = profile[i].Low profile = append(profile[:i], profile[i+1:]...) } return profile } func tooSmall(low, high, grain float64, log bool) bool { if log { return math.Log(high/low) < grain } return high-low < grain } golang-gonum-v1-gonum-0.14.0/graph/community/bisect_example_test.go000066400000000000000000000147271450372207100253500ustar00rootroot00000000000000// Copyright ©2016 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 community_test import ( "fmt" "log" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph/community" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) func ExampleProfile_simple() { // Profile calls Modularize which implements the Louvain modularization algorithm. // Since this is a randomized algorithm we use a defined random source to ensure // consistency between test runs. In practice, results will not differ greatly // between runs with different PRNG seeds. src := rand.NewSource(1) // Create dumbell graph: // // 0 4 // |\ /| // | 2 - 3 | // |/ \| // 1 5 // g := simple.NewUndirectedGraph() for u, e := range smallDumbell { for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } // Get the profile of internal node weight for resolutions // between 0.1 and 10 using logarithmic bisection. p, err := community.Profile( community.ModularScore(g, community.Weight, 10, src), true, 1e-3, 0.1, 10, ) if err != nil { log.Fatal(err) } // Print out each step with communities ordered. for _, d := range p { comm := d.Communities() for _, c := range comm { ordered.ByID(c) } ordered.BySliceIDs(comm) fmt.Printf("Low:%.2v High:%.2v Score:%v Communities:%v Q=%.3v\n", d.Low, d.High, d.Score, comm, community.Q(g, comm, d.Low)) } // Output: // Low:0.1 High:0.29 Score:14 Communities:[[0 1 2 3 4 5]] Q=0.9 // Low:0.29 High:2.3 Score:12 Communities:[[0 1 2] [3 4 5]] Q=0.714 // Low:2.3 High:3.5 Score:4 Communities:[[0 1] [2] [3] [4 5]] Q=-0.31 // Low:3.5 High:10 Score:0 Communities:[[0] [1] [2] [3] [4] [5]] Q=-0.607 } // intset is an integer set. type intset map[int]struct{} func linksTo(i ...int) intset { if len(i) == 0 { return nil } s := make(intset) for _, v := range i { s[v] = struct{}{} } return s } var ( smallDumbell = []intset{ 0: linksTo(1, 2), 1: linksTo(2), 2: linksTo(3), 3: linksTo(4, 5), 4: linksTo(5), 5: nil, } // http://www.slate.com/blogs/the_world_/2014/07/17/the_middle_east_friendship_chart.html middleEast = struct{ friends, complicated, enemies []intset }{ // green cells friends: []intset{ 0: nil, 1: linksTo(5, 7, 9, 12), 2: linksTo(11), 3: linksTo(4, 5, 10), 4: linksTo(3, 5, 10), 5: linksTo(1, 3, 4, 8, 10, 12), 6: nil, 7: linksTo(1, 12), 8: linksTo(5, 9, 11), 9: linksTo(1, 8, 12), 10: linksTo(3, 4, 5), 11: linksTo(2, 8), 12: linksTo(1, 5, 7, 9), }, // yellow cells complicated: []intset{ 0: linksTo(2, 4), 1: linksTo(4, 8), 2: linksTo(0, 3, 4, 5, 8, 9), 3: linksTo(2, 8, 11), 4: linksTo(0, 1, 2, 8), 5: linksTo(2), 6: nil, 7: linksTo(9, 11), 8: linksTo(1, 2, 3, 4, 10, 12), 9: linksTo(2, 7, 11), 10: linksTo(8), 11: linksTo(3, 7, 9, 12), 12: linksTo(8, 11), }, // red cells enemies: []intset{ 0: linksTo(1, 3, 5, 6, 7, 8, 9, 10, 11, 12), 1: linksTo(0, 2, 3, 6, 10, 11), 2: linksTo(1, 6, 7, 10, 12), 3: linksTo(0, 1, 6, 7, 9, 12), 4: linksTo(6, 7, 9, 11, 12), 5: linksTo(0, 6, 7, 9, 11), 6: linksTo(0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12), 7: linksTo(0, 2, 3, 4, 5, 6, 8, 10), 8: linksTo(0, 6, 7), 9: linksTo(0, 3, 4, 5, 6, 10), 10: linksTo(0, 1, 2, 6, 7, 9, 11, 12), 11: linksTo(0, 1, 4, 5, 6, 10), 12: linksTo(0, 2, 3, 4, 6, 10), }, } ) var friends, enemies *simple.WeightedUndirectedGraph func init() { friends = simple.NewWeightedUndirectedGraph(0, 0) for u, e := range middleEast.friends { // Ensure unconnected nodes are included. if friends.Node(int64(u)) == nil { friends.AddNode(simple.Node(u)) } for v := range e { friends.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } enemies = simple.NewWeightedUndirectedGraph(0, 0) for u, e := range middleEast.enemies { // Ensure unconnected nodes are included. if enemies.Node(int64(u)) == nil { enemies.AddNode(simple.Node(u)) } for v := range e { enemies.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: -1}) } } } func ExampleProfile_multiplex() { // Profile calls ModularizeMultiplex which implements the Louvain modularization // algorithm. Since this is a randomized algorithm we use a defined random source // to ensure consistency between test runs. In practice, results will not differ // greatly between runs with different PRNG seeds. src := rand.NewSource(1) // The undirected graphs, friends and enemies, are the political relationships // in the Middle East as described in the Slate article: // http://www.slate.com/blogs/the_world_/2014/07/17/the_middle_east_friendship_chart.html g, err := community.NewUndirectedLayers(friends, enemies) if err != nil { log.Fatal(err) } weights := []float64{1, -1} // Get the profile of internal node weight for resolutions // between 0.1 and 10 using logarithmic bisection. p, err := community.Profile( community.ModularMultiplexScore(g, weights, true, community.WeightMultiplex, 10, src), true, 1e-3, 0.1, 10, ) if err != nil { log.Fatal(err) } // Print out each step with communities ordered. for _, d := range p { comm := d.Communities() for _, c := range comm { ordered.ByID(c) } ordered.BySliceIDs(comm) fmt.Printf("Low:%.2v High:%.2v Score:%v Communities:%v Q=%.3v\n", d.Low, d.High, d.Score, comm, community.QMultiplex(g, comm, weights, []float64{d.Low})) } // Output: // Low:0.1 High:0.72 Score:26 Communities:[[0] [1 7 9 12] [2 8 11] [3 4 5 10] [6]] Q=[24.7 1.97] // Low:0.72 High:1.1 Score:24 Communities:[[0 6] [1 7 9 12] [2 8 11] [3 4 5 10]] Q=[16.9 14.1] // Low:1.1 High:1.2 Score:18 Communities:[[0 2 6 11] [1 7 9 12] [3 4 5 8 10]] Q=[9.16 25.1] // Low:1.2 High:1.6 Score:10 Communities:[[0 3 4 5 6 10] [1 7 9 12] [2 8 11]] Q=[10.5 26.7] // Low:1.6 High:1.6 Score:8 Communities:[[0 1 6 7 9 12] [2 8 11] [3 4 5 10]] Q=[5.56 39.8] // Low:1.6 High:1.8 Score:2 Communities:[[0 2 3 4 5 6 10] [1 7 8 9 11 12]] Q=[-1.82 48.6] // Low:1.8 High:2.3 Score:-6 Communities:[[0 2 3 4 5 6 8 10 11] [1 7 9 12]] Q=[-5 57.5] // Low:2.3 High:2.4 Score:-10 Communities:[[0 1 2 6 7 8 9 11 12] [3 4 5 10]] Q=[-11.2 79] // Low:2.4 High:4.3 Score:-52 Communities:[[0 1 2 3 4 5 6 7 8 9 10 11 12]] Q=[-46.1 117] // Low:4.3 High:10 Score:-54 Communities:[[0 1 2 3 4 6 7 8 9 10 11 12] [5]] Q=[-82 254] } golang-gonum-v1-gonum-0.14.0/graph/community/bisect_test.go000066400000000000000000000120321450372207100236200ustar00rootroot00000000000000// Copyright ©2016 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 community import ( "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) func TestProfileUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testProfileUndirected(t, test, g) } } func TestProfileWeightedUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewWeightedUndirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testProfileUndirected(t, test, g) } } func testProfileUndirected(t *testing.T, test communityUndirectedQTest, g graph.Undirected) { fn := ModularScore(g, Weight, 10, nil) p, err := Profile(fn, true, 1e-3, 0.1, 10) if err != nil { t.Errorf("%s: unexpected error: %v", test.name, err) } const tries = 1000 for i, d := range p { var score float64 for i := 0; i < tries; i++ { score, _ = fn(d.Low) if score >= d.Score { break } } if score < d.Score { t.Errorf("%s: failed to recover low end score: got: %v want: %v", test.name, score, d.Score) } if i != 0 && d.Score >= p[i-1].Score { t.Errorf("%s: not monotonically decreasing: %v -> %v", test.name, p[i-1], d) } } } func TestProfileDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testProfileDirected(t, test, g) } } func TestProfileWeightedDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewWeightedDirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testProfileDirected(t, test, g) } } func testProfileDirected(t *testing.T, test communityDirectedQTest, g graph.Directed) { fn := ModularScore(g, Weight, 10, nil) p, err := Profile(fn, true, 1e-3, 0.1, 10) if err != nil { t.Errorf("%s: unexpected error: %v", test.name, err) } const tries = 1000 for i, d := range p { var score float64 for i := 0; i < tries; i++ { score, _ = fn(d.Low) if score >= d.Score { break } } if score < d.Score { t.Errorf("%s: failed to recover low end score: got: %v want: %v", test.name, score, d.Score) } if i != 0 && d.Score >= p[i-1].Score { t.Errorf("%s: not monotonically decreasing: %v -> %v", test.name, p[i-1], d) } } } func TestProfileUndirectedMultiplex(t *testing.T) { for _, test := range communityUndirectedMultiplexQTests { g, weights, err := undirectedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } const all = true fn := ModularMultiplexScore(g, weights, all, WeightMultiplex, 10, nil) p, err := Profile(fn, true, 1e-3, 0.1, 10) if err != nil { t.Errorf("%s: unexpected error: %v", test.name, err) } const tries = 1000 for i, d := range p { var score float64 for i := 0; i < tries; i++ { score, _ = fn(d.Low) if score >= d.Score { break } } if score < d.Score { t.Errorf("%s: failed to recover low end score: got: %v want: %v", test.name, score, d.Score) } if i != 0 && d.Score >= p[i-1].Score { t.Errorf("%s: not monotonically decreasing: %v -> %v", test.name, p[i-1], d) } } } } func TestProfileDirectedMultiplex(t *testing.T) { for _, test := range communityDirectedMultiplexQTests { g, weights, err := directedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } const all = true fn := ModularMultiplexScore(g, weights, all, WeightMultiplex, 10, nil) p, err := Profile(fn, true, 1e-3, 0.1, 10) if err != nil { t.Errorf("%s: unexpected error: %v", test.name, err) } const tries = 1000 for i, d := range p { var score float64 for i := 0; i < tries; i++ { score, _ = fn(d.Low) if score >= d.Score { break } } if score < d.Score { t.Errorf("%s: failed to recover low end score: got: %v want: %v", test.name, score, d.Score) } if i != 0 && d.Score >= p[i-1].Score { t.Errorf("%s: not monotonically decreasing: %v -> %v", test.name, p[i-1], d) } } } } golang-gonum-v1-gonum-0.14.0/graph/community/doc.go000066400000000000000000000004511450372207100220570ustar00rootroot00000000000000// 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 community provides graph community detection functions. package community // import "gonum.org/v1/gonum/graph/community" golang-gonum-v1-gonum-0.14.0/graph/community/k_communities.go000066400000000000000000000051601450372207100241620ustar00rootroot00000000000000// 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 community import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" "gonum.org/v1/gonum/graph/traverse" ) // KCliqueCommunities returns the k-clique communities of the undirected graph g for // k greater than zero. The returned communities are identified by linkage via k-clique // adjacency, where adjacency is defined as having k-1 common nodes. KCliqueCommunities // returns a single component including the full set of nodes of g when k is 1, // and the classical connected components of g when k is 2. Note that k-clique // communities may contain common nodes from g. // // k-clique communities are described in Palla et al. doi:10.1038/nature03607. func KCliqueCommunities(k int, g graph.Undirected) [][]graph.Node { if k < 1 { panic("community: invalid k for k-clique communities") } switch k { case 1: return [][]graph.Node{graph.NodesOf(g.Nodes())} case 2: return topo.ConnectedComponents(g) default: cg := simple.NewUndirectedGraph() topo.CliqueGraph(cg, g) cc := kConnectedComponents(k, cg) // Extract the nodes in g from cg, // removing duplicates and separating // cliques smaller than k into separate // single nodes. var kcc [][]graph.Node single := set.NewNodes() inCommunity := set.NewNodes() for _, c := range cc { nodes := set.NewNodesSize(len(c)) for _, cn := range c { for _, n := range cn.(topo.Clique).Nodes() { nodes.Add(n) } } if len(nodes) < k { for _, n := range nodes { single.Add(n) } continue } var kc []graph.Node for _, n := range nodes { inCommunity.Add(n) kc = append(kc, n) } kcc = append(kcc, kc) } for _, n := range single { if !inCommunity.Has(n) { kcc = append(kcc, []graph.Node{n}) } } return kcc } } // kConnectedComponents returns the connected components of topo.Clique nodes that // are joined by k-1 underlying shared nodes in the graph that created the clique // graph cg. func kConnectedComponents(k int, cg graph.Undirected) [][]graph.Node { var ( c []graph.Node cc [][]graph.Node ) during := func(n graph.Node) { c = append(c, n) } after := func() { cc = append(cc, []graph.Node(nil)) cc[len(cc)-1] = append(cc[len(cc)-1], c...) c = c[:0] } w := traverse.DepthFirst{ Traverse: func(e graph.Edge) bool { return len(e.(topo.CliqueGraphEdge).Nodes()) >= k-1 }, } w.WalkAll(cg, nil, after, during) return cc } golang-gonum-v1-gonum-0.14.0/graph/community/k_communities_test.go000066400000000000000000000073111450372207100252210ustar00rootroot00000000000000// 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 community import ( "fmt" "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) // batageljZaversnikGraph is the example graph from // figure 1 of http://arxiv.org/abs/cs/0310049v1 var batageljZaversnikGraph = []intset{ 0: nil, 1: linksTo(2, 3), 2: linksTo(4), 3: linksTo(4), 4: linksTo(5), 5: nil, 6: linksTo(7, 8, 14), 7: linksTo(8, 11, 12, 14), 8: linksTo(14), 9: linksTo(11), 10: linksTo(11), 11: linksTo(12), 12: linksTo(18), 13: linksTo(14, 15), 14: linksTo(15, 17), 15: linksTo(16, 17), 16: nil, 17: linksTo(18, 19, 20), 18: linksTo(19, 20), 19: linksTo(20), 20: nil, } var kCliqueCommunitiesTests = []struct { name string g []intset k int want [][]graph.Node }{ { name: "simple", g: []intset{ 0: linksTo(1, 2, 4, 6), 1: linksTo(2, 4, 6), 2: linksTo(3, 6), 3: linksTo(4, 5), 4: linksTo(6), 5: nil, 6: nil, }, k: 3, want: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(4), simple.Node(6)}, {simple.Node(3)}, {simple.Node(5)}, }, }, { name: "Batagelj-Zaversnik Graph", g: batageljZaversnikGraph, k: 3, want: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6), simple.Node(7), simple.Node(8), simple.Node(14)}, {simple.Node(7), simple.Node(11), simple.Node(12)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(13), simple.Node(14), simple.Node(15), simple.Node(17)}, {simple.Node(16)}, {simple.Node(17), simple.Node(18), simple.Node(19), simple.Node(20)}, }, }, { name: "Batagelj-Zaversnik Graph", g: batageljZaversnikGraph, k: 4, want: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6), simple.Node(7), simple.Node(8), simple.Node(14)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(11)}, {simple.Node(12)}, {simple.Node(13)}, {simple.Node(15)}, {simple.Node(16)}, {simple.Node(17), simple.Node(18), simple.Node(19), simple.Node(20)}, }, }, } func TestKCliqueCommunities(t *testing.T) { for _, test := range kCliqueCommunitiesTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := KCliqueCommunities(test.k, g) for _, c := range got { ordered.ByID(c) } ordered.BySliceIDs(got) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected k-connected components for %q k=%d:\ngot: %v\nwant:%v", test.name, test.k, got, test.want) } } } func BenchmarkKCliqueCommunities(b *testing.B) { for _, test := range kCliqueCommunitiesTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } b.Run(fmt.Sprintf("%s-k=%d", test.name, test.k), func(b *testing.B) { var got [][]graph.Node for i := 0; i < b.N; i++ { got = KCliqueCommunities(test.k, g) } if len(got) != len(test.want) { b.Errorf("unexpected k-connected components for %q k=%d:\ngot: %v\nwant:%v", test.name, test.k, got, test.want) } }) } } golang-gonum-v1-gonum-0.14.0/graph/community/louvain.tex000066400000000000000000000541441450372207100231720ustar00rootroot00000000000000% 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. \documentclass{article} \usepackage{amsmath,amsfonts} \usepackage[margin=4cm]{geometry} \title{Louvain algorithm for undirected and directed graphs} \author{The {\tt Gonum} Authors} \begin{document} \maketitle The algorithm attempts to find communities (highly connected sub-graphs), and it does this by minimising the modularity function \begin{equation} Q(c) = \frac{1}{2m}\sum_i\sum_j\left[ A_{ij} - \gamma \frac{k_ik_j}{2m} \right] \delta_{ij}(c), \end{equation} where $c$ is a partition of nodes into subsets or communities, $A_{ij}$ is the edge weight between nodes $i$ and $j$, $\gamma$ is a tuning parameter, \begin{equation} m = \frac{1}{2}\sum_i\sum_jA_{ij}, \end{equation} \begin{equation} k_i = \sum_j{A_{ij}}, \end{equation} and \begin{equation} \delta_{ij}(c) = \left \{ \begin{array}{ll} 1 & \text{if} \quad c(i) = c(j) \\ 0 & \text{otherwise} \end{array} \right .. \end{equation} Here $c(i)$ denotes the community to which node $i$ belongs in the partitioning $c$. The algorithm finds a hierarchical community structure by iterating between two phases: \begin{enumerate} \item Find a set of communities that minimise $Q$. \item Construct a new graph, whose nodes are the communities found in the preceding phase one step. \end{enumerate} Each iteration of these two phases is called a `pass'. In this way, the algorithm obtains a nested community structure, where at each level $Q$ is minimised for the relevant graph. We consider this process in more detail, in particular looking at phase one first in the first pass, when each node is a single node, and then how this generalises to later passes when each node is a community. \section{Undirected Graphs} \subsection{Initial Pass} \label{sec:initialPass} The initial pass is simple as the initial pass uses the original graph, and in all following passes graphs constructed in the previous pass's phase two are used. Here we will consider this initial simple formulation for phase one, and in Section~\ref{sec:laterPasses} we consider how this generalises for passes two and onwards. Phase one works by initially allocating each node to a separate community, and then iterating through each node $a$ and checking if moving it into a different community $\beta$ will reduce $Q$. If there are possible moves that will reduce $Q$, $a$ is moved into the the community which will generate the largest reduction in $Q$. This process is continued until there are no moves left to reduce $Q$ further, meaning a local minimum for $Q$ has been achieved. Then the algorithm moves to phase two (constructing a new graph where each node in the new graph is a community in the old graph). Note that we assume the original graph to be simple and undirected. First, we introduce some notation that will be useful: Let $c(i)$ denote the community to which node $i$ belongs, and let $\alpha$ be the community that the node $a$ mentioned above belongs to, i.e., $\alpha = c_a$. Then we define \newcommand{\Stot}[1]{\Sigma_{\text{tot}}^{#1}} \begin{equation} \Stot{\alpha} = \sum_{i \in \alpha}\sum_{j}A_{ij} = \sum_{i \in \alpha}k_i, \end{equation} \newcommand{\kin}[2]{k_{#1}^{#2}} \begin{equation} \kin{i}{\alpha} = \sum_{j \in \alpha}A_{ij}, \end{equation} and \newcommand{\Sin}[1]{\Sigma_{\text{in}}^{#1}} \begin{equation} \Sin{\alpha} = \sum_{i \in \alpha}\sum_{j \in \alpha}A_{ij} = \sum_{i \in \alpha}\kin{i}{\alpha}. \end{equation} We are interested in how $Q$ will change if we move a node $a$ from its current community $\alpha$, to a new community $\beta$. This will have two effects, it will remove the terms from $Q$ related to $a$ in $\alpha$, which we will call $Q^-$ and it will add terms related to $a$ in $\beta$, which we will call $Q^+$. The total change in $Q$ caused by the movement of $a$ from $\alpha$ to $\beta$ is \begin{equation} \Delta Q = Q^{+} - Q^{-}, \end{equation} where \begin{align*} Q^- &= \frac{1}{2m}\left[ \left( A_{aa} - \gamma \frac{k_a^2}{2m} \right) + 2\sum_{i \in \alpha, \, i \neq a} \left( A_{ia} - \gamma \frac{k_ik_a}{2m} \right) \right] \\ &= \frac{1}{2m}\left[ \left( A_{aa} - \gamma \frac{k_a^2}{2m} \right) + 2 \left( \kin{a}{\alpha} -A_{aa}\right) - \gamma \frac{2k_a}{2m}\sum_{i \in \alpha, \, i \neq a} k_i \right] \\ &= \frac{1}{2m}\left[ \left( A_{aa} - \gamma \frac{k_a^2}{2m} \right) + 2 \left( \kin{a}{\alpha} -A_{aa}\right) - \gamma \frac{2k_a}{2m}\left( \Stot{\alpha} - k_a \right) \right], \\ \end{align*} and \begin{align*} Q^+ &= \frac{1}{2m}\left[ \left( A_{aa} - \gamma \frac{k_a^2}{2m} \right) + 2\sum_{i \in \beta} \left( A_{ia} - \gamma \frac{k_ik_a}{2m} \right) \right] \\ &= \frac{1}{2m}\left[ \left( A_{aa} - \gamma \frac{k_a^2}{2m} \right) + 2\kin{a}{\beta} - \gamma \frac{2k_a}{2m}\sum_{i \in \beta} k_i \right] \\ &= \frac{1}{2m}\left[ \left( A_{aa} - \gamma \frac{k_a^2}{2m} \right) + 2\kin{a}{\beta} - \gamma \frac{2k_a\Stot{\beta}}{2m} \right]. \\ \end{align*} The first term in both these expressions ($Q^-$ and $Q^+$) is the same, and so cancels: \begin{equation} \Delta Q = \frac{1}{2m}\left[ \left( 2\kin{a}{\beta} - \gamma \frac{2k_a\Stot{\beta}}{2m} \right) - \left( 2 \left( \kin{a}{\alpha} -A_{aa}\right) - \gamma \frac{2k_a}{2m}\left( \Stot{\alpha} - k_a \right) \right) \right]. \end{equation} \subsection{Later Passes} \label{sec:laterPasses} In phase two a `meta-graph' is constructed where nodes correspond to the communities found in the preceding phase one step, and edge weight between two such communities (nodes, in the meta-graph) $\alpha$ and $\beta$ are defined to be \begin{equation} A_{\alpha \beta}^* = \sum_{i \in \alpha}\sum_{j \in \beta}A_{ij}. \label{eqn:Aij*} \end{equation} Note that $i$ and $j$ refer to nodes in the original graph, not nodes in the previous graph, and so holds any meta-graph, not just the first. Also note that this definition of $A^*_{\alpha \beta}$ allows for $A^*_{\alpha \alpha}$ to be non-zero as \begin{equation} A_{\alpha \alpha}^* = \sum_{i \in \alpha}\sum_{j \in \alpha}A_{ij} = \Sin{\alpha}. \end{equation} In this newly constructed graph, $\alpha$ and $\beta$ are nodes, but also refer to communities (sets of nodes) in the original graph, and I use these two interpretations interchangeably. This should be the only ambiguous bit of notation in this document, I hope. The results of Section~\ref{sec:initialPass} generalise to these meta-graphs, and the generalised results mirror those of Section~\ref{sec:initialPass} closely -- I distinguish the new results from those of Section~\ref{sec:initialPass} by a superscript $*$. I use $i$ and $j$ to denote nodes of the original graph as in Section~\ref{sec:initialPass}, and use $z$ and $w$ to denote nodes of the meta-graph (communities of the original). I use analogous notation to Section~\ref{sec:initialPass}, $c^*(z)$, to denote the community to which node $z$ of the meta-graph belongs, and let $\mathfrak{a}$ be the community that the node $\alpha$ belongs to ($c^*(\alpha) = \mathfrak{a}$), i.e. \begin{equation} \mathfrak{a} = \{z | c^*(z) = c^*(\alpha) \}. \end{equation} Given this notation, we can observe that \begin{equation} m^* = \frac{1}{2}\sum_{z}\sum_{w}{A_{zw}^*} = \frac{1}{2}\sum_{z}\sum_{w}{\sum_{i \in z}\sum_{j \in w}A_{ij}} = \frac{1}{2}\sum_i\sum_jA_{ij} = m, \end{equation} \begin{equation} k_{z}^* = \sum_{w}{A_{zw}^*} = \sum_{w}{\sum_{i \in z}\sum_{j \in w}A_{ij}} = \sum_{i \in z}\sum_{j}A_{ij} = \Stot{z}, \end{equation} \begin{equation} \Stot{\mathfrak{a} *} = \sum_{z \in \mathfrak{a}}\sum_{w}A_{zw}^* = \sum_{z \in \mathfrak{a}}k_z^* = \sum_{z \in \mathfrak{a}}\Stot{z}, \end{equation} \begin{equation} \kin{z}{\mathfrak{a} *} = \sum_{w \in \mathfrak{a}}{A_{zw}^*} = \sum_{w \in \mathfrak{a}}{\sum_{i \in z}\sum_{j \in w}A_{ij}}, \end{equation} and \begin{equation} \Sin{\mathfrak{a} *} = \sum_{z \in \mathfrak{a}}\sum_{w \in \mathfrak{a}}A_{zw}^* = \sum_{z \in \mathfrak{a}}\kin{z}{\mathfrak{a} *} = \sum_{z \in \mathfrak{a}}\sum_{w \in \mathfrak{a}}{\sum_{i \in z}\sum_{j \in w}A_{ij}}. %\label{eqn:Sin} \end{equation} If we let $\mathfrak{b}$ denote the community to which we are considering moving $\alpha$, then the expression for $\Delta Q$ from Section~\ref{sec:initialPass} trivially generalises to \begin{equation} \Delta Q = \frac{1}{2m}\left[ \left( 2 \kin{\alpha}{\mathfrak{b} *} - \gamma \frac{2k_{\alpha}^*\Stot{\mathfrak{b} *}}{2m} \right) - \left( 2\left( \kin{\alpha}{\mathfrak{a} *} - A_{\alpha \alpha}^* \right) - \gamma \frac{2k_{\alpha}^*}{2m} \left( \Stot{\mathfrak{a} *} - k_{\alpha}^* \right ) \right) \right] \\ \end{equation} \section{Directed Graphs} \label{sec:directedGraphs} It is of interest to consider how this generalises to directed graphs. If we are to treat incoming and outgoing nodes equally, there are several thoughts on how to extend the algorithm to directed graphs, of which we will explore three: \begin{itemize} \item Construct an undirected graph first, and then use the undirected case. \item Generalise the expressions from the undirected case to the directed case, we will consider two different suggestions for such generalisations. \end{itemize} We will show that one of the two `generalisation of expressions' approaches is equivalent to constructing an undirected graph, and the other is not. \subsection{Construction of an undirected graph} A simple approach to generalising to directed graphs is to construct an undirected graph with edge weights \begin{equation} A_{ij} = B_{ij} + B_{ji}, \label{eqn:undirectedAB} \end{equation} and simply use the undirected algorithm. Another suggestion is to average the directed edges to make an undirected graph, i.e. to use a directed graph with edge weights \begin{equation} A_{ij} = \frac{B_{ij} + B_{ji}}{2}. \end{equation} This raises an important question: does scaling all edge weights across the entire graph by a constant affect the results of the algorithm? Hopefully not, but worth checking. We can follow this through the results for the undirected graph by substituting $A_{ij}^{(1)} = pA_{ij}$, $p \in \mathbb{R}$, and distinguishing the new expressions by a superscript ${(1)}$. These new expressions are: \begin{equation} m^{(1)} = \frac{1}{2}\sum_i\sum_jpA_{ij} = p\frac{1}{2}\sum_i\sum_j A_{ij} = pm , \end{equation} \begin{equation} k_i^{(1)} = \sum_j{pA_{ij}} = p\sum_j{A_{ij}} = pk_i, \end{equation} and so \begin{align*} Q^{(1)}(c) &= \frac{1}{2pm}\sum_i\sum_j\left[ pA_{ij} - \gamma \frac{pk_ipk_j}{2pm} \right] \delta_{ij}(c) \\ &= \frac{1}{2m}\sum_i\sum_j\left[ A_{ij} - \gamma \frac{k_ik_j}{2m} \right] \delta_{ij}(c) \\ &= Q(c) \end{align*} Note that as we have shown $Q^{(1)} = Q$ there is no need to go into the remainder of the terms involved in the algorithm, as they all derive from $Q$. \subsection{First generalisation of expressions approach} One suggested extension to directed graphs is to modify the expressions involved by adding the `from' case and the `to' case for each term. If we let $B_{ij}$ be the edge weight between nodes $i$ and $j$ in the directed graph, and distinguishing these extended expressions by a superscript $(2)$, the extended expressions become: \begin{equation} m^{(2)} = \frac{1}{2}\left ( \sum_i\sum_jB_{ij} + \sum_i\sum_jB_{ji}\right) = \frac{1}{2}\sum_i\sum_j \left( B_{ij} + B_{ji} \right) , \end{equation} \begin{equation} k_i^{(2)} = \sum_jB_{ij} + \sum_jB_{ji} = \sum_j{\left( B_{ij} + B_{ji} \right)}, \end{equation} and similarly \begin{equation} Q^{(2)}(c) = \frac{1}{2m}\sum_i\sum_j\left[ \left( B_{ij} + B_{ji} \right) - \gamma \frac{k_i^{(2)}k_j^{(2)}}{2m} \right] \delta_{ij}(c). \end{equation} Note how this is equivalent to the construction of an undirected graph as per Equation~(\ref{eqn:undirectedAB}). Similarly to above, there is no need to go into the remainder of the terms involved in the algorithm, as they all derive from $Q$. \subsection{Second generalisation of expressions approach} Another approach to generalising the expressions to the directed case, that still treats incoming and outgoing edges as equally important, is to propose an alternative modularity expression: \newcommand{\dkin}[1]{k_{#1}^{\text{in}}} \newcommand{\dkout}[1]{k_{#1}^{\text{out}}} \begin{equation} Q^{(3)}(c) = \frac{1}{2m}\sum_i\sum_j\left[ 2B_{ij} - 2\gamma \frac{\dkin{i}\dkout{j}}{2m} \right] \delta_{ij}(c), \\ \end{equation} where \begin{equation} \dkout{i} = \sum_j{B_{ij}} \quad \quad \text{and} \quad \quad \dkin{i} = \sum_j{B_{ji}}, \end{equation} so $k_i^{(2)} = \dkin{i} + \dkout{i}$. Note I leave the factor of two in the expression for $Q^{(3)}$ so that it remains as comparable to that for $Q^{(2)}$ as possible. There is no need for alternative $m$, as it will still be the same as above. $Q^{(3)}$ will differ from $Q^{(2)}$ in two ways. Firstly, as $k_i^{(2)} = \dkin{i} + \dkout{i}$, \begin{align*} \sum_i\sum_j k_i^{(2)} k_j^{(2)} \delta_{ij}(c) &= \sum_i\sum_j (\dkin{i} + \dkout{i}) (\dkin{j} + \dkout{j}) \delta_{ij}(c) \\ &= \sum_i\sum_j \left[ (\dkin{i}\dkin{j} + \dkout{i}\dkout{j}) + (\dkin{i}\dkout{j} + \dkin{j}\dkout{i}) \right] \delta_{ij}(c). \\ &= \sum_i\sum_j \left[ (\dkin{i}\dkin{j} + \dkout{i}\dkout{j}) + 2\dkin{i}\dkout{j} \right] \delta_{ij}(c), \\ \end{align*} and similarly, \begin{equation} \sum_i\sum_j \left( B_{ij} + B_{ji} \right) \delta_{ij}(c) = 2\sum_i\sum_j B_{ij} \delta_{ij}(c). \end{equation} From these two expressions, we can see that \begin{equation} Q^{(3)} - Q^{(2)} = \frac{1}{2m}\sum_i\sum_j \gamma \frac{\dkin{i}\dkin{j} + \dkout{i}\dkout{j}}{2m} \delta_{ij}(c). \end{equation} \section{Directed Graphs in more detail} \label{sec:directedGraphsDetail} In Section \ref{sec:directedGraphs} we essentially showed three things: \begin{itemize} \item How an undirected graph could be constructed from a directed graph, thereby allowing the undirected algorithm to be used for directed graphs. \item How scaling all edge weights by a non-zero constant would not affect the modularity function. \item An alternative approach to extending the algorithm to directed graphs that is not equivalent to first reducing it to an undirected graph. \end{itemize} It is this third point that we will explore here. Analogously to Sections \ref{sec:initialPass} and \ref{sec:laterPasses} we will break this up into the initial pass and the later passes. \subsection{Initial pass} \label{sec:initialPassDirected} Continuing with the notation of Section \ref{sec:initialPass}, in which $c(i)$ denotes the community to which node $i$ belongs, and $\alpha = c(a)$, we define \newcommand{\dinStot}[1]{\Sigma_{\text{tot}}^{\text{in}(#1)}} \newcommand{\doutStot}[1]{\Sigma_{\text{tot}}^{\text{out}(#1)}} \begin{equation} \doutStot{\alpha} = \sum_{i \in \alpha}\sum_{j}B_{ij} = \sum_{i \in \alpha}\dkout{i} \quad \quad \text{and} \quad \quad \dinStot{\alpha} = \sum_{i \in \alpha}\sum_{j}B_{ji} = \sum_{i \in \alpha}\dkin{i}, \end{equation} \newcommand{\dinkin}[2]{k_{#1}^{\text{in}(#2)}} \newcommand{\doutkin}[2]{k_{#1}^{\text{out}(#2)}} \begin{equation} \doutkin{i}{\alpha} = \sum_{j \in \alpha}B_{ij} \quad \quad \text{and} \quad \quad \dinkin{i}{\alpha} = \sum_{j \in \alpha}B_{ji}, \end{equation} and we will entertain one more ambiguous notation choice: %\newcommand{\Sin}[1]{\Sigma_{\text{in}}^{#1}} \begin{equation} \Sin{\alpha} = \sum_{i \in \alpha}\sum_{j \in \alpha}B_{ij} = \sum_{i \in \alpha}\doutkin{i}{\alpha} = \sum_{i \in \alpha}\dinkin{i}{\alpha}. \end{equation} Analogously to Section \ref{sec:initialPass}, we are interested in how $Q^{(3)}$ will change if we move a node $a$ from its current community $\alpha$, to a new community $\beta$, and analogously this will have two effects -- it will remove the terms from $Q^{(3)}$ related to $a$ in $\alpha$, which we will call $Q^{-(3)}$ and it will add terms related to $a$ in $\beta$, which we will call $Q^{+(3)}$. The total change in $Q^{(3)}$ caused by the movement of $a$ from $\alpha$ to $\beta$ is \begin{equation} \Delta Q^{(3)} = Q^{+(3)} - Q^{-(3)}, \end{equation} where \begin{align*} Q^{-(3)} &= \frac{1}{2m}\left[ \left( 2B_{aa} - 2\gamma \frac{\dkin{a}\dkout{a}}{2m} \right) + \sum_{i \in \alpha, \, i \neq a} \left( 2B_{ia} + 2B_{ai} - 2\gamma \frac{\dkin{i}\dkout{a}}{2m} - 2\gamma \frac{\dkin{a}\dkout{i}}{2m} \right) \right] \\ &= \frac{1}{2m}\left[ \left( 2B_{aa} - 2\gamma \frac{\dkin{a}\dkout{a}}{2m} \right) + 2(\dinkin{a}{\alpha} - B_{aa}) + 2(\doutkin{a}{\alpha} - B_{aa}) \hdots \right . \\ & \quad \quad \quad \quad \quad \quad \left . - \frac{2\gamma\dkout{a}}{2m} (\dinStot{\alpha} - \dkin{a}) - \frac{2\gamma\dkin{a}}{2m} (\doutStot{\alpha} - \dkout{a}) \right] \\ \end{align*} and \begin{align*} Q^{+(3)} &= \frac{1}{2m}\left[ \left( 2B_{aa} - 2\gamma \frac{\dkin{a}\dkout{a}}{2m} \right) + \sum_{i \in \beta} \left( 2B_{ia} + 2B_{ai} - 2\gamma \frac{\dkin{i}\dkout{a}}{2m} - 2\gamma \frac{\dkin{a}\dkout{i}}{2m} \right) \right] \\ &= \frac{1}{2m}\left[ \left( 2B_{aa} - 2\gamma \frac{\dkin{a}\dkout{a}}{2m} \right) + 2\dinkin{a}{\beta} + 2\doutkin{a}{\beta} - \frac{2\gamma\dkout{a}}{2m} \dinStot{\beta} - \frac{2\gamma\dkin{a}}{2m} \doutStot{\beta} \right] \\ \end{align*} Similarly to Section \ref{sec:initialPass}, the first term in both these expressions is the same, and so cancels, leaving: \begin{align*} \Delta Q^{(3)} &= \frac{2}{2m}\left[ \left( \dinkin{a}{\beta} + \doutkin{a}{\beta} - \frac{\gamma\dkout{a}}{2m} \dinStot{\beta} - \frac{\gamma\dkin{a}}{2m} \doutStot{\beta} \right) \right. \\ & \hspace{-1cm} - \left. \left( (\dinkin{a}{\alpha} - B_{aa}) + (\doutkin{a}{\alpha} - B_{aa}) - \frac{\gamma\dkout{a}}{2m} (\dinStot{\alpha} - \dkin{a}) - \frac{\gamma\dkin{a}}{2m} (\doutStot{\alpha} - \dkout{a}) \right) \right] \\ &= \frac{2}{2m}\left[ (\dinkin{a}{\beta}-\dinkin{a}{\alpha}) + (\doutkin{a}{\beta}-\doutkin{a}{\alpha}) + 2B_{aa} \right. \\ & \hspace{-1cm} \left. - \frac{\gamma\dkout{a}}{2m} (\dinStot{\beta}-\dinStot{\alpha}) - \frac{\gamma\dkin{a}}{2m} (\doutStot{\beta} - \doutStot{\alpha}) - \frac{2\gamma\dkin{a}\dkout{a}}{2m} \right] \end{align*} \subsection{Later passes} \label{sec:laterPassesDirected} In phase two a `meta-graph' is constructed where nodes correspond to the communities found in the preceding phase one step, and edge weight between two such communities (nodes, in the meta-graph) $\alpha$ and $\beta$ are defined to be \begin{equation} B_{\alpha \beta}^* = \sum_{i \in \alpha}\sum_{j \in \beta}B_{ij}. \label{eqn:Bij*} \end{equation} Note that $i$ and $j$ refer to nodes in the original graph, not nodes in the previous graph, and so holds any meta-graph, not just the first. Also note that this definition of $B^*_{\alpha \beta}$ allows for $B^*_{\alpha \alpha}$ to be non-zero, in fact \begin{equation} B_{\alpha \alpha}^* = \sum_{i \in \alpha}\sum_{j \in \alpha}B_{ij} = \Sin{\alpha}. \end{equation} In this newly constructed graph, $\alpha$ and $\beta$ are nodes, but also refer to communities (sets of nodes) in the original graph, and I use these two interpretations interchangeably, completely analogously to Section \ref{sec:laterPasses}. The results of Section~\ref{sec:initialPassDirected} generalise to these meta-graphs, and the generalised results mirror those of Section~\ref{sec:initialPassDirected} closely -- I distinguish the new results from those of Section~\ref{sec:initialPassDirected} by a superscript $*$. I use $i$ and $j$ to denote nodes of the original graph as in Sections~\ref{sec:initialPass} and \ref{sec:initialPassDirected}, and use $z$ and $w$ to denote nodes of the meta-graph (communities of the original). I use analogous notation to Section~\ref{sec:initialPass}, $c^*(z)$, to denote the community to which node $z$ of the meta-graph belongs, and let $\mathfrak{a}$ be the community that the node $\alpha$ belongs to, i.e., $\mathfrak{a} = c^*(\alpha) $. Given this notation, we get all the same results as in \ref{sec:laterPasses}, but each split into two cases `out' and `in', separating by direction, essentially, so \newcommand{\dkinStar}[1]{k_{#1}^{\text{in} *}} \newcommand{\dkoutStar}[1]{k_{#1}^{\text{out} *}} \begin{equation} \dkoutStar{z} = \sum_w{B_{zw}^*} = \sum_w\sum_{i \in z}\sum_{j \in w}B_{ij} = \sum_{i \in z}\sum_jB_{ij} = \doutStot{z}, \end{equation} \begin{equation} \dkinStar{z} = \sum_w{B_{wz}^*} = \sum_w\sum_{i \in z}\sum_{j \in w}B_{ji} = \sum_{i \in z}\sum_jB_{ji} = \dinStot{z}, \end{equation} \newcommand{\dinStotStar}[1]{\Sigma_{\text{tot}}^{\text{in}(#1) *}} \newcommand{\doutStotStar}[1]{\Sigma_{\text{tot}}^{\text{out}(#1) *}} \begin{equation} \doutStotStar{\mathfrak{a}} = \sum_{z \in \mathfrak{a}}\sum_{w}B_{zw}^* = \sum_{z \in \mathfrak{a}}\dkoutStar{z} = \sum_{z \in \mathfrak{a}}\doutStot{z}, \end{equation} \begin{equation} \dinStotStar{\mathfrak{a}} = \sum_{z \in \mathfrak{a}}\sum_{w}B_{wz}^* = \sum_{z \in \mathfrak{a}}\dkinStar{z} = \sum_{z \in \mathfrak{a}}\dinStot{z}, \end{equation} \newcommand{\dinkinStar}[2]{k_{#1}^{\text{in}(#2) *}} \newcommand{\doutkinStar}[2]{k_{#1}^{\text{out}(#2) *}} \begin{equation} \doutkinStar{z}{\mathfrak{a}} = \sum_{w \in \mathfrak{a}}{B_{zw}^*} = \sum_{w \in \mathfrak{a}}{\sum_{i \in z}\sum_{j \in w}B_{ij}}, \end{equation} \begin{equation} \dinkinStar{z}{\mathfrak{a}} = \sum_{w \in \mathfrak{a}}{B_{wz}^*} = \sum_{w \in \mathfrak{a}}{\sum_{i \in z}\sum_{j \in w}B_{ji}}, \end{equation} and \begin{equation} \Sin{\mathfrak{a} *} = \sum_{z \in \mathfrak{a}}\sum_{w \in \mathfrak{a}}A_{zw}^* = \sum_{z \in \mathfrak{a}}\kin{z}{\mathfrak{a} *} = \sum_{z \in \mathfrak{a}}\sum_{w \in \mathfrak{a}}{\sum_{i \in z}\sum_{j \in w}A_{ij}}. %\label{eqn:Sin} \end{equation} If we let $\mathfrak{b}$ denote the community to which we are considering moving $\alpha$, then the expression for $\Delta Q$ from Section~\ref{sec:initialPassDirected} simply generalises as \begin{align*} \Delta Q^{(3)} &= \frac{2}{2m}\left[ (\dinkinStar{\alpha}{\mathfrak{b}}-\dinkinStar{\alpha}{\mathfrak{a}}) + (\doutkinStar{\alpha}{\mathfrak{b}}-\doutkinStar{\alpha}{\mathfrak{a}}) + 2B_{\alpha\alpha}^* \right. \\ & \hspace{-1cm} \left. - \frac{\gamma\dkoutStar{\alpha}}{2m} (\dinStotStar{\mathfrak{b}}-\dinStotStar{\mathfrak{a}}) - \frac{\gamma\dkinStar{\alpha}}{2m} (\doutStotStar{\mathfrak{b}} - \doutStotStar{\mathfrak{a}}) - \frac{2\gamma\dkinStar{\alpha}\dkoutStar{\alpha}}{2m} \right] \end{align*} \end{document} golang-gonum-v1-gonum-0.14.0/graph/community/louvain_common.go000066400000000000000000000326501450372207100243450ustar00rootroot00000000000000// 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 community import ( "fmt" "sort" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" ) // Q returns the modularity Q score of the graph g subdivided into the // given communities at the given resolution. If communities is nil, the // unclustered modularity score is returned. The resolution parameter // is γ as defined in Reichardt and Bornholdt doi:10.1103/PhysRevE.74.016110. // Q will panic if g has any edge with negative edge weight. // // If g is undirected, Q is calculated according to // // Q = 1/2m \sum_{ij} [ A_{ij} - (\gamma k_i k_j)/2m ] \delta(c_i,c_j), // // If g is directed, it is calculated according to // // Q = 1/m \sum_{ij} [ A_{ij} - (\gamma k_i^in k_j^out)/m ] \delta(c_i,c_j). // // graph.Undirect may be used as a shim to allow calculation of Q for // directed graphs with the undirected modularity function. func Q(g graph.Graph, communities [][]graph.Node, resolution float64) float64 { switch g := g.(type) { case graph.Undirected: return qUndirected(g, communities, resolution) case graph.Directed: return qDirected(g, communities, resolution) default: panic(fmt.Sprintf("community: invalid graph type: %T", g)) } } // ReducedGraph is a modularised graph. type ReducedGraph interface { graph.Graph // Communities returns the community memberships // of the nodes in the graph used to generate // the reduced graph. Communities() [][]graph.Node // Structure returns the community structure of // the current level of the module clustering. // Each slice in the returned value recursively // describes the membership of a community at // the current level by indexing via the node // ID into the structure of the non-nil // ReducedGraph returned by Expanded, or when the // ReducedGraph is nil, by containing nodes // from the original input graph. // // The returned value should not be mutated. Structure() [][]graph.Node // Expanded returns the next lower level of the // module clustering or nil if at the lowest level. // // The returned ReducedGraph will be the same // concrete type as the receiver. Expanded() ReducedGraph } // Modularize returns the hierarchical modularization of g at the given resolution // using the Louvain algorithm. If src is nil, rand.Intn is used as the random // generator. Modularize will panic if g has any edge with negative edge weight. // // If g is undirected it is modularised to minimise // // Q = 1/2m \sum_{ij} [ A_{ij} - (\gamma k_i k_j)/2m ] \delta(c_i,c_j), // // If g is directed it is modularised to minimise // // Q = 1/m \sum_{ij} [ A_{ij} - (\gamma k_i^in k_j^out)/m ] \delta(c_i,c_j). // // The concrete type of the ReducedGraph will be a pointer to either a // ReducedUndirected or a ReducedDirected depending on the type of g. // // graph.Undirect may be used as a shim to allow modularization of // directed graphs with the undirected modularity function. func Modularize(g graph.Graph, resolution float64, src rand.Source) ReducedGraph { switch g := g.(type) { case graph.Undirected: return louvainUndirected(g, resolution, src) case graph.Directed: return louvainDirected(g, resolution, src) default: panic(fmt.Sprintf("community: invalid graph type: %T", g)) } } // Multiplex is a multiplex graph. type Multiplex interface { // Nodes returns the nodes // for the multiplex graph. // All layers must refer to the same // set of nodes. Nodes() graph.Nodes // Depth returns the number of layers // in the multiplex graph. Depth() int } // QMultiplex returns the modularity Q score of the multiplex graph layers // subdivided into the given communities at the given resolutions and weights. Q is // returned as the vector of weighted Q scores for each layer of the multiplex graph. // If communities is nil, the unclustered modularity score is returned. // If weights is nil layers are equally weighted, otherwise the length of // weights must equal the number of layers. If resolutions is nil, a resolution // of 1.0 is used for all layers, otherwise either a single element slice may be used // to specify a global resolution, or the length of resolutions must equal the number // of layers. The resolution parameter is γ as defined in Reichardt and Bornholdt // doi:10.1103/PhysRevE.74.016110. // QMultiplex will panic if the graph has any layer weight-scaled edge with // negative edge weight. // // If g is undirected, Q is calculated according to // // Q_{layer} = w_{layer} \sum_{ij} [ A_{layer}*_{ij} - (\gamma_{layer} k_i k_j)/2m_{layer} ] \delta(c_i,c_j), // // If g is directed, it is calculated according to // // Q_{layer} = w_{layer} \sum_{ij} [ A_{layer}*_{ij} - (\gamma_{layer} k_i^in k_j^out)/m_{layer} ] \delta(c_i,c_j). // // Note that Q values for multiplex graphs are not scaled by the total layer edge weight. // // graph.Undirect may be used as a shim to allow calculation of Q for // directed graphs. func QMultiplex(g Multiplex, communities [][]graph.Node, weights, resolutions []float64) []float64 { if weights != nil && len(weights) != g.Depth() { panic("community: weights vector length mismatch") } if resolutions != nil && len(resolutions) != 1 && len(resolutions) != g.Depth() { panic("community: resolutions vector length mismatch") } switch g := g.(type) { case UndirectedMultiplex: return qUndirectedMultiplex(g, communities, weights, resolutions) case DirectedMultiplex: return qDirectedMultiplex(g, communities, weights, resolutions) default: panic(fmt.Sprintf("community: invalid graph type: %T", g)) } } // ReducedMultiplex is a modularised multiplex graph. type ReducedMultiplex interface { Multiplex // Communities returns the community memberships // of the nodes in the graph used to generate // the reduced graph. Communities() [][]graph.Node // Structure returns the community structure of // the current level of the module clustering. // Each slice in the returned value recursively // describes the membership of a community at // the current level by indexing via the node // ID into the structure of the non-nil // ReducedGraph returned by Expanded, or when the // ReducedGraph is nil, by containing nodes // from the original input graph. // // The returned value should not be mutated. Structure() [][]graph.Node // Expanded returns the next lower level of the // module clustering or nil if at the lowest level. // // The returned ReducedGraph will be the same // concrete type as the receiver. Expanded() ReducedMultiplex } // ModularizeMultiplex returns the hierarchical modularization of g at the given resolution // using the Louvain algorithm. If all is true and g have negatively weighted layers, all // communities will be searched during the modularization. If src is nil, rand.Intn is // used as the random generator. ModularizeMultiplex will panic if g has any edge with // edge weight that does not sign-match the layer weight. // // If g is undirected it is modularised to minimise // // Q = \sum w_{layer} \sum_{ij} [ A_{layer}*_{ij} - (\gamma_{layer} k_i k_j)/2m ] \delta(c_i,c_j). // // If g is directed it is modularised to minimise // // Q = \sum w_{layer} \sum_{ij} [ A_{layer}*_{ij} - (\gamma_{layer} k_i^in k_j^out)/m_{layer} ] \delta(c_i,c_j). // // The concrete type of the ReducedMultiplex will be a pointer to a // ReducedUndirectedMultiplex. // // graph.Undirect may be used as a shim to allow modularization of // directed graphs with the undirected modularity function. func ModularizeMultiplex(g Multiplex, weights, resolutions []float64, all bool, src rand.Source) ReducedMultiplex { if weights != nil && len(weights) != g.Depth() { panic("community: weights vector length mismatch") } if resolutions != nil && len(resolutions) != 1 && len(resolutions) != g.Depth() { panic("community: resolutions vector length mismatch") } switch g := g.(type) { case UndirectedMultiplex: return louvainUndirectedMultiplex(g, weights, resolutions, all, src) case DirectedMultiplex: return louvainDirectedMultiplex(g, weights, resolutions, all, src) default: panic(fmt.Sprintf("community: invalid graph type: %T", g)) } } // undirectedEdges is the edge structure of a reduced undirected graph. type undirectedEdges struct { // edges and weights is the set // of edges between nodes. // weights is keyed such that // the first element of the key // is less than the second. edges [][]int weights map[[2]int]float64 } // directedEdges is the edge structure of a reduced directed graph. type directedEdges struct { // edgesFrom, edgesTo and weights // is the set of edges between nodes. edgesFrom [][]int edgesTo [][]int weights map[[2]int]float64 } // isValidID returns whether id is a valid ID for a community, // multiplexCommunity or node. These are all graph.Node types // stored in []T with a mapping between their index and their ID // so IDs must be positive and fit within the int type. func isValidID(id int64) bool { return id == int64(int(id)) && id >= 0 } // community is a reduced graph node describing its membership. type community struct { // community graphs are internal, in-memory // with dense IDs, so id is always an int. id int nodes []graph.Node weight float64 } func (n community) ID() int64 { return int64(n.id) } // edge is a reduced graph edge. type edge struct { from, to community weight float64 } func (e edge) From() graph.Node { return e.from } func (e edge) To() graph.Node { return e.to } func (e edge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from; return e } func (e edge) Weight() float64 { return e.weight } // multiplexCommunity is a reduced multiplex graph node describing its membership. type multiplexCommunity struct { // community graphs are internal, in-memory // with dense IDs, so id is always an int. id int nodes []graph.Node weights []float64 } func (n multiplexCommunity) ID() int64 { return int64(n.id) } // multiplexEdge is a reduced graph edge for a multiplex graph. type multiplexEdge struct { from, to multiplexCommunity weight float64 } func (e multiplexEdge) From() graph.Node { return e.from } func (e multiplexEdge) To() graph.Node { return e.to } func (e multiplexEdge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from; return e } func (e multiplexEdge) Weight() float64 { return e.weight } // commIdx is an index of a node in a community held by a localMover. type commIdx struct { community int node int } // node is defined to avoid an import of .../graph/simple. node is // used in in-memory, dense ID graphs and so is always an int. type node int func (n node) ID() int64 { return int64(n) } // minTaker is a set iterator. type minTaker interface { TakeMin(p *int) bool } // dense is a dense integer set iterator. type dense struct { pos int n int } // TakeMin mimics intsets.Sparse TakeMin for dense sets. If the dense // iterator position is less than the iterator size, TakeMin sets *p // to the iterator position and increments the position and returns // true. // Otherwise, it returns false and *p is undefined. func (d *dense) TakeMin(p *int) bool { if d.pos >= d.n { return false } *p = d.pos d.pos++ return true } // slice is a sparse integer set iterator. type slice struct { pos int elems []int } // newSlice returns a new slice of elements from s, sorted ascending. func newSlice(s set.Ints) *slice { elems := make([]int, 0, len(s)) for i := range s { elems = append(elems, i) } sort.Ints(elems) return &slice{elems: elems} } // TakeMin mimics intsets.Sparse TakeMin for a sorted set. If the set // iterator position is less than the iterator size, TakeMin sets *p // to the iterator position's element and increments the position // and returns true. // Otherwise, it returns false and *p is undefined. func (s *slice) TakeMin(p *int) bool { if s.pos >= len(s.elems) { return false } *p = s.elems[s.pos] s.pos++ return true } const ( negativeWeight = "community: unexpected negative edge weight" positiveWeight = "community: unexpected positive edge weight" // deltaQtol is the tolerance for progression of the local moving heuristic's improvement of Q. deltaQtol = 1e-15 ) // positiveWeightFuncFor returns a constructed weight function for the // positively weighted g. Unweighted graphs have unit weight for existing // edges. func positiveWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 { if wg, ok := g.(graph.Weighted); ok { return func(xid, yid int64) float64 { w, ok := wg.Weight(xid, yid) if !ok { return 0 } if w < 0 { panic(negativeWeight) } return w } } return func(xid, yid int64) float64 { e := g.Edge(xid, yid) if e == nil { return 0 } return 1 } } // negativeWeightFuncFor returns a constructed weight function for the // negatively weighted g. Unweighted graphs have unit weight for existing // edges. func negativeWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 { if wg, ok := g.(graph.Weighted); ok { return func(xid, yid int64) float64 { w, ok := wg.Weight(xid, yid) if !ok { return 0 } if w > 0 { panic(positiveWeight) } return -w } } return func(xid, yid int64) float64 { e := g.Edge(xid, yid) if e == nil { return 0 } return 1 } } // depth returns max(1, len(weights)). It is used to ensure // that multiplex community weights are properly initialised. func depth(weights []float64) int { if weights == nil { return 1 } return len(weights) } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_directed.go000066400000000000000000000441741450372207100246440ustar00rootroot00000000000000// 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 community import ( "math" "sort" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" ) // qDirected returns the modularity Q score of the graph g subdivided into the // given communities at the given resolution. If communities is nil, the // unclustered modularity score is returned. The resolution parameter // is γ as defined in Reichardt and Bornholdt doi:10.1103/PhysRevE.74.016110. // qDirected will panic if g has any edge with negative edge weight. // // Q = 1/m \sum_{ij} [ A_{ij} - (\gamma k_i^in k_j^out)/m ] \delta(c_i,c_j) func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64) float64 { nodes := graph.NodesOf(g.Nodes()) weight := positiveWeightFuncFor(g) // Calculate the total edge weight of the graph // and the table of penetrating edge weight sums. var m float64 k := make(map[int64]directedWeights, len(nodes)) for _, n := range nodes { var wOut float64 u := n uid := u.ID() to := g.From(uid) for to.Next() { wOut += weight(uid, to.Node().ID()) } var wIn float64 v := n vid := v.ID() from := g.To(vid) for from.Next() { wIn += weight(from.Node().ID(), vid) } id := n.ID() w := weight(id, id) m += w + wOut // We only need to count edges once. k[id] = directedWeights{out: w + wOut, in: w + wIn} } if communities == nil { var q float64 for _, u := range nodes { uid := u.ID() kU := k[uid] q += weight(uid, uid) - resolution*kU.out*kU.in/m } return q / m } var q float64 for _, c := range communities { for _, u := range c { uid := u.ID() kU := k[uid] for _, v := range c { vid := v.ID() kV := k[vid] q += weight(uid, vid) - resolution*kU.out*kV.in/m } } } return q / m } // louvainDirected returns the hierarchical modularization of g at the given // resolution using the Louvain algorithm. If src is nil, rand.Intn is used // as the random generator. louvainDirected will panic if g has any edge with negative // edge weight. func louvainDirected(g graph.Directed, resolution float64, src rand.Source) ReducedGraph { // See louvain.tex for a detailed description // of the algorithm used here. c := reduceDirected(g, nil) rnd := rand.Intn if src != nil { rnd = rand.New(src).Intn } for { l := newDirectedLocalMover(c, c.communities, resolution) if l == nil { return c } if done := l.localMovingHeuristic(rnd); done { return c } c = reduceDirected(c, l.communities) } } // ReducedDirected is a directed graph of communities derived from a // parent graph by reduction. type ReducedDirected struct { // nodes is the set of nodes held // by the graph. In a ReducedDirected // the node ID is the index into // nodes. nodes []community directedEdges // communities is the community // structure of the graph. communities [][]graph.Node parent *ReducedDirected } var ( reducedDirected = (*ReducedDirected)(nil) _ graph.WeightedDirected = reducedDirected _ ReducedGraph = reducedDirected ) // Communities returns the community memberships of the nodes in the // graph used to generate the reduced graph. func (g *ReducedDirected) Communities() [][]graph.Node { communities := make([][]graph.Node, len(g.communities)) if g.parent == nil { for i, members := range g.communities { comm := make([]graph.Node, len(members)) for j, n := range members { nodes := g.nodes[n.ID()].nodes if len(nodes) != 1 { panic("community: unexpected number of nodes in base graph community") } comm[j] = nodes[0] } communities[i] = comm } return communities } sub := g.parent.Communities() for i, members := range g.communities { var comm []graph.Node for _, n := range members { comm = append(comm, sub[n.ID()]...) } communities[i] = comm } return communities } // Structure returns the community structure of the current level of // the module clustering. The first index of the returned value // corresponds to the index of the nodes in the next higher level if // it exists. The returned value should not be mutated. func (g *ReducedDirected) Structure() [][]graph.Node { return g.communities } // Expanded returns the next lower level of the module clustering or nil // if at the lowest level. func (g *ReducedDirected) Expanded() ReducedGraph { return g.parent } // reduceDirected returns a reduced graph constructed from g divided // into the given communities. The communities value is mutated // by the call to reduceDirected. If communities is nil and g is a // ReducedDirected, it is returned unaltered. func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirected { if communities == nil { if r, ok := g.(*ReducedDirected); ok { return r } nodes := graph.NodesOf(g.Nodes()) // TODO(kortschak) This sort is necessary really only // for testing. In practice we would not be using the // community provided by the user for a Q calculation. // Probably we should use a function to map the // communities in the test sets to the remapped order. ordered.ByID(nodes) communities = make([][]graph.Node, len(nodes)) for i := range nodes { communities[i] = []graph.Node{node(i)} } weight := positiveWeightFuncFor(g) r := ReducedDirected{ nodes: make([]community, len(nodes)), directedEdges: directedEdges{ edgesFrom: make([][]int, len(nodes)), edgesTo: make([][]int, len(nodes)), weights: make(map[[2]int]float64), }, communities: communities, } communityOf := make(map[int64]int, len(nodes)) for i, n := range nodes { r.nodes[i] = community{id: i, nodes: []graph.Node{n}} communityOf[n.ID()] = i } for _, n := range nodes { id := communityOf[n.ID()] var out []int u := n uid := u.ID() to := g.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] if vcid != id { out = append(out, vcid) } r.weights[[2]int{id, vcid}] = weight(uid, vid) } r.edgesFrom[id] = out var in []int v := n vid := v.ID() from := g.To(vid) for from.Next() { uid := from.Node().ID() ucid := communityOf[uid] if ucid != id { in = append(in, ucid) } r.weights[[2]int{ucid, id}] = weight(uid, vid) } r.edgesTo[id] = in } return &r } // Remove zero length communities destructively. var commNodes int for i := 0; i < len(communities); { comm := communities[i] if len(comm) == 0 { communities[i] = communities[len(communities)-1] communities[len(communities)-1] = nil communities = communities[:len(communities)-1] } else { commNodes += len(comm) i++ } } r := ReducedDirected{ nodes: make([]community, len(communities)), directedEdges: directedEdges{ edgesFrom: make([][]int, len(communities)), edgesTo: make([][]int, len(communities)), weights: make(map[[2]int]float64), }, } r.communities = make([][]graph.Node, len(communities)) for i := range r.communities { r.communities[i] = []graph.Node{node(i)} } if g, ok := g.(*ReducedDirected); ok { // Make sure we retain the truncated // community structure. g.communities = communities r.parent = g } weight := positiveWeightFuncFor(g) communityOf := make(map[int64]int, commNodes) for i, comm := range communities { r.nodes[i] = community{id: i, nodes: comm} for _, n := range comm { communityOf[n.ID()] = i } } for id, comm := range communities { var out, in []int for _, n := range comm { u := n uid := u.ID() for _, v := range comm { r.nodes[id].weight += weight(uid, v.ID()) } to := g.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] found := false for _, e := range out { if e == vcid { found = true break } } if !found && vcid != id { out = append(out, vcid) } // Add half weights because the other // ends of edges are also counted. r.weights[[2]int{id, vcid}] += weight(uid, vid) / 2 } v := n vid := v.ID() from := g.To(vid) for from.Next() { uid := from.Node().ID() ucid := communityOf[uid] found := false for _, e := range in { if e == ucid { found = true break } } if !found && ucid != id { in = append(in, ucid) } // Add half weights because the other // ends of edges are also counted. r.weights[[2]int{ucid, id}] += weight(uid, vid) / 2 } } r.edgesFrom[id] = out r.edgesTo[id] = in } return &r } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *ReducedDirected) Node(id int64) graph.Node { if g.has(id) { return g.nodes[id] } return nil } // has returns whether the node exists within the graph. func (g *ReducedDirected) has(id int64) bool { return 0 <= id && id < int64(len(g.nodes)) } // Nodes returns all the nodes in the graph. func (g *ReducedDirected) Nodes() graph.Nodes { nodes := make([]graph.Node, len(g.nodes)) for i := range g.nodes { nodes[i] = node(i) } return iterator.NewOrderedNodes(nodes) } // From returns all nodes in g that can be reached directly from u. func (g *ReducedDirected) From(uid int64) graph.Nodes { out := g.edgesFrom[uid] nodes := make([]graph.Node, len(out)) for i, vid := range out { nodes[i] = g.nodes[vid] } return iterator.NewOrderedNodes(nodes) } // To returns all nodes in g that can reach directly to v. func (g *ReducedDirected) To(vid int64) graph.Nodes { in := g.edgesTo[vid] nodes := make([]graph.Node, len(in)) for i, uid := range in { nodes[i] = g.nodes[uid] } return iterator.NewOrderedNodes(nodes) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g *ReducedDirected) HasEdgeBetween(xid, yid int64) bool { if xid == yid || !isValidID(xid) || !isValidID(yid) { return false } _, ok := g.weights[[2]int{int(xid), int(yid)}] if ok { return true } _, ok = g.weights[[2]int{int(yid), int(xid)}] return ok } // HasEdgeFromTo returns whether an edge exists from node u to v. func (g *ReducedDirected) HasEdgeFromTo(uid, vid int64) bool { if uid == vid || !isValidID(uid) || !isValidID(vid) { return false } _, ok := g.weights[[2]int{int(uid), int(vid)}] return ok } // 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 *ReducedDirected) Edge(uid, vid int64) graph.Edge { return g.WeightedEdge(uid, vid) } // 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 *ReducedDirected) WeightedEdge(uid, vid int64) graph.WeightedEdge { if uid == vid || !isValidID(uid) || !isValidID(vid) { return nil } w, ok := g.weights[[2]int{int(uid), int(vid)}] if !ok { return nil } return edge{from: g.nodes[uid], to: g.nodes[vid], weight: w} } // 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 the internal node weight is returned. If there is no joining // edge between the two nodes the weight value returned is zero. Weight returns true if an edge // exists between x and y or if x and y have the same ID, false otherwise. func (g *ReducedDirected) Weight(xid, yid int64) (w float64, ok bool) { if !isValidID(xid) || !isValidID(yid) { return 0, false } if xid == yid { return g.nodes[xid].weight, true } w, ok = g.weights[[2]int{int(xid), int(yid)}] return w, ok } // directedLocalMover is a step in graph modularity optimization. type directedLocalMover struct { g *ReducedDirected // nodes is the set of working nodes. nodes []graph.Node // edgeWeightsOf is the weighted degree // of each node indexed by ID. edgeWeightsOf []directedWeights // m is the total sum of edge // weights in g. m float64 // weight is the weight function // provided by g or a function // that returns the Weight value // of the non-nil edge between x // and y. weight func(xid, yid int64) float64 // communities is the current // division of g. communities [][]graph.Node // memberships is a mapping between // node ID and community membership. memberships []int // resolution is the Reichardt and // Bornholdt γ parameter as defined // in doi:10.1103/PhysRevE.74.016110. resolution float64 // moved indicates that a call to // move has been made since the last // call to shuffle. moved bool // changed indicates that a move // has been made since the creation // of the local mover. changed bool } type directedWeights struct { out, in float64 } // newDirectedLocalMover returns a new directedLocalMover initialized with // the graph g, a set of communities and a modularity resolution parameter. // The node IDs of g must be contiguous in [0,n) where n is the number of // nodes. // If g has a zero edge weight sum, nil is returned. func newDirectedLocalMover(g *ReducedDirected, communities [][]graph.Node, resolution float64) *directedLocalMover { nodes := graph.NodesOf(g.Nodes()) l := directedLocalMover{ g: g, nodes: nodes, edgeWeightsOf: make([]directedWeights, len(nodes)), communities: communities, memberships: make([]int, len(nodes)), resolution: resolution, weight: positiveWeightFuncFor(g), } // Calculate the total edge weight of the graph // and degree weights for each node. for _, n := range l.nodes { u := n var wOut float64 uid := u.ID() to := g.From(uid) for to.Next() { wOut += l.weight(uid, to.Node().ID()) } v := n var wIn float64 vid := v.ID() from := g.To(vid) for from.Next() { wIn += l.weight(from.Node().ID(), vid) } id := n.ID() w := l.weight(id, id) l.edgeWeightsOf[id] = directedWeights{out: w + wOut, in: w + wIn} l.m += w + wOut } // Assign membership mappings. for i, c := range communities { for _, n := range c { l.memberships[n.ID()] = i } } return &l } // localMovingHeuristic performs the Louvain local moving heuristic until // no further moves can be made. It returns a boolean indicating that the // directedLocalMover has not made any improvement to the community structure and // so the Louvain algorithm is done. func (l *directedLocalMover) localMovingHeuristic(rnd func(int) int) (done bool) { for { l.shuffle(rnd) for _, n := range l.nodes { dQ, dst, src := l.deltaQ(n) if dQ <= deltaQtol { continue } l.move(dst, src) } if !l.moved { return !l.changed } } } // shuffle performs a Fisher-Yates shuffle on the nodes held by the // directedLocalMover using the random source rnd which should return an // integer in the range [0,n). func (l *directedLocalMover) shuffle(rnd func(n int) int) { l.moved = false for i := range l.nodes[:len(l.nodes)-1] { j := i + rnd(len(l.nodes)-i) l.nodes[i], l.nodes[j] = l.nodes[j], l.nodes[i] } } // move moves the node at src to the community at dst. func (l *directedLocalMover) move(dst int, src commIdx) { l.moved = true l.changed = true srcComm := l.communities[src.community] n := srcComm[src.node] l.memberships[n.ID()] = dst l.communities[dst] = append(l.communities[dst], n) srcComm[src.node], srcComm[len(srcComm)-1] = srcComm[len(srcComm)-1], nil l.communities[src.community] = srcComm[:len(srcComm)-1] } // deltaQ returns the highest gain in modularity attainable by moving // n from its current community to another connected community and // the index of the chosen destination. The index into the directedLocalMover's // communities field is returned in src if n is in communities. func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) { id := n.ID() a_aa := l.weight(id, id) k_a := l.edgeWeightsOf[id] m := l.m gamma := l.resolution // Find communities connected to n. connected := make(set.Ints) // The following for loop is equivalent to: // // for _, v := range l.g.From(n) { // connected.Add(l.memberships[v.ID()]) // } // for _, v := range l.g.To(n) { // connected.Add(l.memberships[v.ID()]) // } // // This is done to avoid two allocations. for _, vid := range l.g.edgesFrom[id] { connected.Add(l.memberships[vid]) } for _, vid := range l.g.edgesTo[id] { connected.Add(l.memberships[vid]) } // Insert the node's own community. connected.Add(l.memberships[id]) candidates := make([]int, 0, len(connected)) for i := range connected { candidates = append(candidates, i) } sort.Ints(candidates) // Calculate the highest modularity gain // from moving into another community and // keep the index of that community. var dQremove float64 dQadd, dst, src := math.Inf(-1), -1, commIdx{-1, -1} for _, i := range candidates { c := l.communities[i] var k_aC, sigma_totC directedWeights // C is a substitution for ^𝛼 or ^𝛽. var removal bool for j, u := range c { uid := u.ID() if uid == id { if src.community != -1 { panic("community: multiple sources") } src = commIdx{i, j} removal = true } k_aC.in += l.weight(uid, id) k_aC.out += l.weight(id, uid) // sigma_totC could be kept for each community // and updated for moves, changing the calculation // of sigma_totC here from O(n_c) to O(1), but // in practice the time savings do not appear // to be compelling and do not make up for the // increase in code complexity and space required. w := l.edgeWeightsOf[uid] sigma_totC.in += w.in sigma_totC.out += w.out } // See louvain.tex for a derivation of these equations. switch { case removal: // The community c was the current community, // so calculate the change due to removal. dQremove = (k_aC.in /*^𝛼*/ - a_aa) + (k_aC.out /*^𝛼*/ - a_aa) - gamma*(k_a.in*(sigma_totC.out /*^𝛼*/ -k_a.out)+k_a.out*(sigma_totC.in /*^𝛼*/ -k_a.in))/m default: // Otherwise calculate the change due to an addition // to c and retain if it is the current best. dQ := k_aC.in /*^𝛽*/ + k_aC.out /*^𝛽*/ - gamma*(k_a.in*sigma_totC.out /*^𝛽*/ +k_a.out*sigma_totC.in /*^𝛽*/)/m if dQ > dQadd { dQadd = dQ dst = i } } } return (dQadd - dQremove) / m, dst, src } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_directed_multiplex.go000066400000000000000000000633001450372207100267370ustar00rootroot00000000000000// 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 community import ( "fmt" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" ) // DirectedMultiplex is a directed multiplex graph. type DirectedMultiplex interface { Multiplex // Layer returns the lth layer of the // multiplex graph. Layer(l int) graph.Directed } // qDirectedMultiplex returns the modularity Q score of the multiplex graph layers // subdivided into the given communities at the given resolutions and weights. Q is // returned as the vector of weighted Q scores for each layer of the multiplex graph. // If communities is nil, the unclustered modularity score is returned. // If weights is nil layers are equally weighted, otherwise the length of // weights must equal the number of layers. If resolutions is nil, a resolution // of 1.0 is used for all layers, otherwise either a single element slice may be used // to specify a global resolution, or the length of resolutions must equal the number // of layers. The resolution parameter is γ as defined in Reichardt and Bornholdt // doi:10.1103/PhysRevE.74.016110. // qUndirectedMultiplex will panic if the graph has any layer weight-scaled edge with // negative edge weight. // // Q_{layer} = w_{layer} \sum_{ij} [ A_{layer}*_{ij} - (\gamma_{layer} k_i k_j)/2m ] \delta(c_i,c_j) // // Note that Q values for multiplex graphs are not scaled by the total layer edge weight. func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64) []float64 { q := make([]float64, g.Depth()) nodes := graph.NodesOf(g.Nodes()) layerWeight := 1.0 layerResolution := 1.0 if len(resolutions) == 1 { layerResolution = resolutions[0] } for l := 0; l < g.Depth(); l++ { layer := g.Layer(l) if weights != nil { layerWeight = weights[l] } if layerWeight == 0 { continue } if len(resolutions) > 1 { layerResolution = resolutions[l] } var weight func(xid, yid int64) float64 if layerWeight < 0 { weight = negativeWeightFuncFor(layer) } else { weight = positiveWeightFuncFor(layer) } // Calculate the total edge weight of the layer // and the table of penetrating edge weight sums. var m float64 k := make(map[int64]directedWeights, len(nodes)) for _, n := range nodes { var wOut float64 u := n uid := u.ID() to := layer.From(uid) for to.Next() { wOut += weight(uid, to.Node().ID()) } var wIn float64 v := n vid := v.ID() from := layer.To(vid) for from.Next() { wIn += weight(from.Node().ID(), vid) } id := n.ID() w := weight(id, id) m += w + wOut // We only need to count edges once. k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn} } if communities == nil { var qLayer float64 for _, u := range nodes { uid := u.ID() kU := k[uid] qLayer += weight(uid, uid) - layerResolution*kU.out*kU.in/m } q[l] = layerWeight * qLayer continue } var qLayer float64 for _, c := range communities { for _, u := range c { uid := u.ID() kU := k[uid] for _, v := range c { vid := v.ID() kV := k[vid] qLayer += weight(uid, vid) - layerResolution*kU.out*kV.in/m } } } q[l] = layerWeight * qLayer } return q } // DirectedLayers implements DirectedMultiplex. type DirectedLayers []graph.Directed // NewDirectedLayers returns a DirectedLayers using the provided layers // ensuring there is a match between IDs for each layer. func NewDirectedLayers(layers ...graph.Directed) (DirectedLayers, error) { if len(layers) == 0 { return nil, nil } base := make(set.Int64s) nodes := layers[0].Nodes() for nodes.Next() { base.Add(nodes.Node().ID()) } for i, l := range layers[1:] { next := make(set.Int64s) nodes := l.Nodes() for nodes.Next() { next.Add(nodes.Node().ID()) } if !set.Int64sEqual(base, next) { return nil, fmt.Errorf("community: layer ID mismatch between layers: %d", i+1) } } return layers, nil } // Nodes returns the nodes of the receiver. func (g DirectedLayers) Nodes() graph.Nodes { if len(g) == 0 { return nil } return g[0].Nodes() } // Depth returns the depth of the multiplex graph. func (g DirectedLayers) Depth() int { return len(g) } // Layer returns the lth layer of the multiplex graph. func (g DirectedLayers) Layer(l int) graph.Directed { return g[l] } // louvainDirectedMultiplex returns the hierarchical modularization of g at the given resolution // using the Louvain algorithm. If all is true and g has negatively weighted layers, all // communities will be searched during the modularization. If src is nil, rand.Intn is // used as the random generator. louvainDirectedMultiplex will panic if g has any edge with // edge weight that does not sign-match the layer weight. // // graph.Undirect may be used as a shim to allow modularization of directed graphs. func louvainDirectedMultiplex(g DirectedMultiplex, weights, resolutions []float64, all bool, src rand.Source) *ReducedDirectedMultiplex { if weights != nil && len(weights) != g.Depth() { panic("community: weights vector length mismatch") } if resolutions != nil && len(resolutions) != 1 && len(resolutions) != g.Depth() { panic("community: resolutions vector length mismatch") } // See louvain.tex for a detailed description // of the algorithm used here. c := reduceDirectedMultiplex(g, nil, weights) rnd := rand.Intn if src != nil { rnd = rand.New(src).Intn } for { l := newDirectedMultiplexLocalMover(c, c.communities, weights, resolutions, all) if l == nil { return c } if done := l.localMovingHeuristic(rnd); done { return c } c = reduceDirectedMultiplex(c, l.communities, weights) } } // ReducedDirectedMultiplex is a directed graph of communities derived from a // parent graph by reduction. type ReducedDirectedMultiplex struct { // nodes is the set of nodes held // by the graph. In a ReducedDirectedMultiplex // the node ID is the index into // nodes. nodes []multiplexCommunity layers []directedEdges // communities is the community // structure of the graph. communities [][]graph.Node parent *ReducedDirectedMultiplex } var ( _ DirectedMultiplex = (*ReducedDirectedMultiplex)(nil) _ graph.WeightedDirected = (*directedLayerHandle)(nil) ) // Nodes returns all the nodes in the graph. func (g *ReducedDirectedMultiplex) Nodes() graph.Nodes { nodes := make([]graph.Node, len(g.nodes)) for i := range g.nodes { nodes[i] = node(i) } return iterator.NewOrderedNodes(nodes) } // Depth returns the number of layers in the multiplex graph. func (g *ReducedDirectedMultiplex) Depth() int { return len(g.layers) } // Layer returns the lth layer of the multiplex graph. func (g *ReducedDirectedMultiplex) Layer(l int) graph.Directed { return directedLayerHandle{multiplex: g, layer: l} } // Communities returns the community memberships of the nodes in the // graph used to generate the reduced graph. func (g *ReducedDirectedMultiplex) Communities() [][]graph.Node { communities := make([][]graph.Node, len(g.communities)) if g.parent == nil { for i, members := range g.communities { comm := make([]graph.Node, len(members)) for j, n := range members { nodes := g.nodes[n.ID()].nodes if len(nodes) != 1 { panic("community: unexpected number of nodes in base graph community") } comm[j] = nodes[0] } communities[i] = comm } return communities } sub := g.parent.Communities() for i, members := range g.communities { var comm []graph.Node for _, n := range members { comm = append(comm, sub[n.ID()]...) } communities[i] = comm } return communities } // Structure returns the community structure of the current level of // the module clustering. The first index of the returned value // corresponds to the index of the nodes in the next higher level if // it exists. The returned value should not be mutated. func (g *ReducedDirectedMultiplex) Structure() [][]graph.Node { return g.communities } // Expanded returns the next lower level of the module clustering or nil // if at the lowest level. func (g *ReducedDirectedMultiplex) Expanded() ReducedMultiplex { return g.parent } // reduceDirectedMultiplex returns a reduced graph constructed from g divided // into the given communities. The communities value is mutated // by the call to reduceDirectedMultiplex. If communities is nil and g is a // ReducedDirectedMultiplex, it is returned unaltered. func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights []float64) *ReducedDirectedMultiplex { if communities == nil { if r, ok := g.(*ReducedDirectedMultiplex); ok { return r } nodes := graph.NodesOf(g.Nodes()) // TODO(kortschak) This sort is necessary really only // for testing. In practice we would not be using the // community provided by the user for a Q calculation. // Probably we should use a function to map the // communities in the test sets to the remapped order. ordered.ByID(nodes) communities = make([][]graph.Node, len(nodes)) for i := range nodes { communities[i] = []graph.Node{node(i)} } r := ReducedDirectedMultiplex{ nodes: make([]multiplexCommunity, len(nodes)), layers: make([]directedEdges, g.Depth()), communities: communities, } communityOf := make(map[int64]int, len(nodes)) for i, n := range nodes { r.nodes[i] = multiplexCommunity{id: i, nodes: []graph.Node{n}, weights: make([]float64, depth(weights))} communityOf[n.ID()] = i } for i := range r.layers { r.layers[i] = directedEdges{ edgesFrom: make([][]int, len(nodes)), edgesTo: make([][]int, len(nodes)), weights: make(map[[2]int]float64), } } w := 1.0 for l := 0; l < g.Depth(); l++ { layer := g.Layer(l) if weights != nil { w = weights[l] } if w == 0 { continue } var sign float64 var weight func(xid, yid int64) float64 if w < 0 { sign, weight = -1, negativeWeightFuncFor(layer) } else { sign, weight = 1, positiveWeightFuncFor(layer) } for _, n := range nodes { id := communityOf[n.ID()] var out []int u := n uid := u.ID() to := layer.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] if vcid != id { out = append(out, vcid) } r.layers[l].weights[[2]int{id, vcid}] = sign * weight(uid, vid) } r.layers[l].edgesFrom[id] = out var in []int v := n vid := v.ID() from := layer.To(vid) for from.Next() { uid := from.Node().ID() ucid := communityOf[uid] if ucid != id { in = append(in, ucid) } r.layers[l].weights[[2]int{ucid, id}] = sign * weight(uid, vid) } r.layers[l].edgesTo[id] = in } } return &r } // Remove zero length communities destructively. var commNodes int for i := 0; i < len(communities); { comm := communities[i] if len(comm) == 0 { communities[i] = communities[len(communities)-1] communities[len(communities)-1] = nil communities = communities[:len(communities)-1] } else { commNodes += len(comm) i++ } } r := ReducedDirectedMultiplex{ nodes: make([]multiplexCommunity, len(communities)), layers: make([]directedEdges, g.Depth()), } communityOf := make(map[int64]int, commNodes) for i, comm := range communities { r.nodes[i] = multiplexCommunity{id: i, nodes: comm, weights: make([]float64, depth(weights))} for _, n := range comm { communityOf[n.ID()] = i } } for i := range r.layers { r.layers[i] = directedEdges{ edgesFrom: make([][]int, len(communities)), edgesTo: make([][]int, len(communities)), weights: make(map[[2]int]float64), } } r.communities = make([][]graph.Node, len(communities)) for i := range r.communities { r.communities[i] = []graph.Node{node(i)} } if g, ok := g.(*ReducedDirectedMultiplex); ok { // Make sure we retain the truncated // community structure. g.communities = communities r.parent = g } w := 1.0 for l := 0; l < g.Depth(); l++ { layer := g.Layer(l) if weights != nil { w = weights[l] } if w == 0 { continue } var sign float64 var weight func(xid, yid int64) float64 if w < 0 { sign, weight = -1, negativeWeightFuncFor(layer) } else { sign, weight = 1, positiveWeightFuncFor(layer) } for id, comm := range communities { var out, in []int for _, n := range comm { u := n uid := u.ID() for _, v := range comm { r.nodes[id].weights[l] += sign * weight(uid, v.ID()) } to := layer.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] found := false for _, e := range out { if e == vcid { found = true break } } if !found && vcid != id { out = append(out, vcid) } // Add half weights because the other // ends of edges are also counted. r.layers[l].weights[[2]int{id, vcid}] += sign * weight(uid, vid) / 2 } v := n vid := v.ID() from := layer.To(vid) for from.Next() { uid := from.Node().ID() ucid := communityOf[uid] found := false for _, e := range in { if e == ucid { found = true break } } if !found && ucid != id { in = append(in, ucid) } // Add half weights because the other // ends of edges are also counted. r.layers[l].weights[[2]int{ucid, id}] += sign * weight(uid, vid) / 2 } } r.layers[l].edgesFrom[id] = out r.layers[l].edgesTo[id] = in } } return &r } // directedLayerHandle is a handle to a multiplex graph layer. type directedLayerHandle struct { // multiplex is the complete // multiplex graph. multiplex *ReducedDirectedMultiplex // layer is an index into the // multiplex for the current // layer. layer int } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g directedLayerHandle) Node(id int64) graph.Node { if g.has(id) { return g.multiplex.nodes[id] } return nil } // has returns whether the node exists within the graph. func (g directedLayerHandle) has(id int64) bool { return 0 <= id && id < int64(len(g.multiplex.nodes)) } // Nodes returns all the nodes in the graph. func (g directedLayerHandle) Nodes() graph.Nodes { nodes := make([]graph.Node, len(g.multiplex.nodes)) for i := range g.multiplex.nodes { nodes[i] = node(i) } return iterator.NewOrderedNodes(nodes) } // From returns all nodes in g that can be reached directly from u. func (g directedLayerHandle) From(uid int64) graph.Nodes { out := g.multiplex.layers[g.layer].edgesFrom[uid] nodes := make([]graph.Node, len(out)) for i, vid := range out { nodes[i] = g.multiplex.nodes[vid] } return iterator.NewOrderedNodes(nodes) } // To returns all nodes in g that can reach directly to v. func (g directedLayerHandle) To(vid int64) graph.Nodes { in := g.multiplex.layers[g.layer].edgesTo[vid] nodes := make([]graph.Node, len(in)) for i, uid := range in { nodes[i] = g.multiplex.nodes[uid] } return iterator.NewOrderedNodes(nodes) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g directedLayerHandle) HasEdgeBetween(xid, yid int64) bool { if xid == yid { return false } if xid == yid || !isValidID(xid) || !isValidID(yid) { return false } _, ok := g.multiplex.layers[g.layer].weights[[2]int{int(xid), int(yid)}] if ok { return true } _, ok = g.multiplex.layers[g.layer].weights[[2]int{int(yid), int(xid)}] return ok } // HasEdgeFromTo returns whether an edge exists from node u to v. func (g directedLayerHandle) HasEdgeFromTo(uid, vid int64) bool { if uid == vid || !isValidID(uid) || !isValidID(vid) { return false } _, ok := g.multiplex.layers[g.layer].weights[[2]int{int(uid), int(vid)}] return ok } // 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 directedLayerHandle) Edge(uid, vid int64) graph.Edge { return g.WeightedEdge(uid, vid) } // 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 directedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge { if uid == vid || !isValidID(uid) || !isValidID(vid) { return nil } w, ok := g.multiplex.layers[g.layer].weights[[2]int{int(uid), int(vid)}] if !ok { return nil } return multiplexEdge{from: g.multiplex.nodes[uid], to: g.multiplex.nodes[vid], weight: w} } // 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 the internal node weight is returned. If there is no joining // edge between the two nodes the weight value returned is zero. Weight returns true if an edge // exists between x and y or if x and y have the same ID, false otherwise. func (g directedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) { if !isValidID(xid) || !isValidID(yid) { return 0, false } if xid == yid { return g.multiplex.nodes[xid].weights[g.layer], true } w, ok = g.multiplex.layers[g.layer].weights[[2]int{int(xid), int(yid)}] return w, ok } // directedMultiplexLocalMover is a step in graph modularity optimization. type directedMultiplexLocalMover struct { g *ReducedDirectedMultiplex // nodes is the set of working nodes. nodes []graph.Node // edgeWeightsOf is the weighted degree // of each node indexed by ID. edgeWeightsOf [][]directedWeights // m is the total sum of // edge weights in g. m []float64 // weight is the weight function // provided by g or a function // that returns the Weight value // of the non-nil edge between x // and y. weight []func(xid, yid int64) float64 // communities is the current // division of g. communities [][]graph.Node // memberships is a mapping between // node ID and community membership. memberships []int // resolution is the Reichardt and // Bornholdt γ parameter as defined // in doi:10.1103/PhysRevE.74.016110. resolutions []float64 // weights is the layer weights for // the modularisation. weights []float64 // searchAll specifies whether the local // mover should consider non-connected // communities during the local moving // heuristic. searchAll bool // moved indicates that a call to // move has been made since the last // call to shuffle. moved bool // changed indicates that a move // has been made since the creation // of the local mover. changed bool } // newDirectedMultiplexLocalMover returns a new directedMultiplexLocalMover initialized with // the graph g, a set of communities and a modularity resolution parameter. The // node IDs of g must be contiguous in [0,n) where n is the number of nodes. // If g has a zero edge weight sum, nil is returned. func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64, all bool) *directedMultiplexLocalMover { nodes := graph.NodesOf(g.Nodes()) l := directedMultiplexLocalMover{ g: g, nodes: nodes, edgeWeightsOf: make([][]directedWeights, g.Depth()), m: make([]float64, g.Depth()), communities: communities, memberships: make([]int, len(nodes)), resolutions: resolutions, weights: weights, weight: make([]func(xid, yid int64) float64, g.Depth()), } // Calculate the total edge weight of the graph // and degree weights for each node. var zero int for i := 0; i < g.Depth(); i++ { l.edgeWeightsOf[i] = make([]directedWeights, len(nodes)) var weight func(xid, yid int64) float64 if weights != nil { if weights[i] == 0 { zero++ continue } if weights[i] < 0 { weight = negativeWeightFuncFor(g.Layer(i)) l.searchAll = all } else { weight = positiveWeightFuncFor(g.Layer(i)) } } else { weight = positiveWeightFuncFor(g.Layer(i)) } l.weight[i] = weight layer := g.Layer(i) for _, n := range l.nodes { u := n uid := u.ID() var wOut float64 to := layer.From(uid) for to.Next() { wOut += weight(uid, to.Node().ID()) } v := n vid := v.ID() var wIn float64 from := layer.To(vid) for from.Next() { wIn += weight(from.Node().ID(), vid) } id := n.ID() w := weight(id, id) l.edgeWeightsOf[i][uid] = directedWeights{out: w + wOut, in: w + wIn} l.m[i] += w + wOut } if l.m[i] == 0 { zero++ } } if zero == g.Depth() { return nil } // Assign membership mappings. for i, c := range communities { for _, n := range c { l.memberships[n.ID()] = i } } return &l } // localMovingHeuristic performs the Louvain local moving heuristic until // no further moves can be made. It returns a boolean indicating that the // directedMultiplexLocalMover has not made any improvement to the community // structure and so the Louvain algorithm is done. func (l *directedMultiplexLocalMover) localMovingHeuristic(rnd func(int) int) (done bool) { for { l.shuffle(rnd) for _, n := range l.nodes { dQ, dst, src := l.deltaQ(n) if dQ <= deltaQtol { continue } l.move(dst, src) } if !l.moved { return !l.changed } } } // shuffle performs a Fisher-Yates shuffle on the nodes held by the // directedMultiplexLocalMover using the random source rnd which should return // an integer in the range [0,n). func (l *directedMultiplexLocalMover) shuffle(rnd func(n int) int) { l.moved = false for i := range l.nodes[:len(l.nodes)-1] { j := i + rnd(len(l.nodes)-i) l.nodes[i], l.nodes[j] = l.nodes[j], l.nodes[i] } } // move moves the node at src to the community at dst. func (l *directedMultiplexLocalMover) move(dst int, src commIdx) { l.moved = true l.changed = true srcComm := l.communities[src.community] n := srcComm[src.node] l.memberships[n.ID()] = dst l.communities[dst] = append(l.communities[dst], n) srcComm[src.node], srcComm[len(srcComm)-1] = srcComm[len(srcComm)-1], nil l.communities[src.community] = srcComm[:len(srcComm)-1] } // deltaQ returns the highest gain in modularity attainable by moving // n from its current community to another connected community and // the index of the chosen destination. The index into the // directedMultiplexLocalMover's communities field is returned in src if n // is in communities. func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) { id := n.ID() var iterator minTaker if l.searchAll { iterator = &dense{n: len(l.communities)} } else { // Find communities connected to n. connected := make(set.Ints) // The following for loop is equivalent to: // // for i := 0; i < l.g.Depth(); i++ { // for _, v := range l.g.Layer(i).From(n) { // connected.Add(l.memberships[v.ID()]) // } // for _, v := range l.g.Layer(i).To(n) { // connected.Add(l.memberships[v.ID()]) // } // } // // This is done to avoid an allocation for // each layer. for _, layer := range l.g.layers { for _, vid := range layer.edgesFrom[id] { connected.Add(l.memberships[vid]) } for _, vid := range layer.edgesTo[id] { connected.Add(l.memberships[vid]) } } // Insert the node's own community. connected.Add(l.memberships[id]) iterator = newSlice(connected) } // Calculate the highest modularity gain // from moving into another community and // keep the index of that community. var dQremove float64 dQadd, dst, src := math.Inf(-1), -1, commIdx{-1, -1} var i int for iterator.TakeMin(&i) { c := l.communities[i] var removal bool var _dQadd float64 for layer := 0; layer < l.g.Depth(); layer++ { m := l.m[layer] if m == 0 { // Do not consider layers with zero sum edge weight. continue } w := 1.0 if l.weights != nil { w = l.weights[layer] } if w == 0 { // Do not consider layers with zero weighting. continue } var k_aC, sigma_totC directedWeights // C is a substitution for ^𝛼 or ^𝛽. removal = false for j, u := range c { uid := u.ID() if uid == id { // Only mark and check src community on the first layer. if layer == 0 { if src.community != -1 { panic("community: multiple sources") } src = commIdx{i, j} } removal = true } k_aC.in += l.weight[layer](id, uid) k_aC.out += l.weight[layer](uid, id) // sigma_totC could be kept for each community // and updated for moves, changing the calculation // of sigma_totC here from O(n_c) to O(1), but // in practice the time savings do not appear // to be compelling and do not make up for the // increase in code complexity and space required. w := l.edgeWeightsOf[layer][uid] sigma_totC.in += w.in sigma_totC.out += w.out } a_aa := l.weight[layer](id, id) k_a := l.edgeWeightsOf[layer][id] gamma := 1.0 if l.resolutions != nil { if len(l.resolutions) == 1 { gamma = l.resolutions[0] } else { gamma = l.resolutions[layer] } } // See louvain.tex for a derivation of these equations. // The weighting term, w, is described in V Traag, // "Algorithms and dynamical models for communities and // reputation in social networks", chapter 5. // http://www.traag.net/wp/wp-content/papercite-data/pdf/traag_algorithms_2013.pdf switch { case removal: // The community c was the current community, // so calculate the change due to removal. dQremove += w * ((k_aC.in /*^𝛼*/ - a_aa) + (k_aC.out /*^𝛼*/ - a_aa) - gamma*(k_a.in*(sigma_totC.out /*^𝛼*/ -k_a.out)+k_a.out*(sigma_totC.in /*^𝛼*/ -k_a.in))/m) default: // Otherwise calculate the change due to an addition // to c. _dQadd += w * (k_aC.in /*^𝛽*/ + k_aC.out /*^𝛽*/ - gamma*(k_a.in*sigma_totC.out /*^𝛽*/ +k_a.out*sigma_totC.in /*^𝛽*/)/m) } } if !removal && _dQadd > dQadd { dQadd = _dQadd dst = i } } return dQadd - dQremove, dst, src } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_directed_multiplex_test.go000066400000000000000000000450211450372207100277760ustar00rootroot00000000000000// 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 community import ( "math" "reflect" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var communityDirectedMultiplexQTests = []struct { name string layers []layer structures []structure wantLevels []level }{ { name: "unconnected", layers: []layer{{g: unconnected, weight: 1}}, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0), 1: linksTo(1), 2: linksTo(2), 3: linksTo(3), 4: linksTo(4), 5: linksTo(5), }, want: math.NaN(), }, }, wantLevels: []level{ { q: math.Inf(-1), // Here math.Inf(-1) is used as a place holder for NaN to allow use of reflect.DeepEqual. communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "simple_directed", layers: []layer{{g: simpleDirected, weight: 1}}, // community structure and modularity calculated by C++ implementation: louvain igraph. // Note that louvain igraph returns Q as an unscaled value. structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1), 1: linksTo(2, 3, 4), }, want: 0.5714285714285716, tol: 1e-10, }, }, wantLevels: []level{ { communities: [][]graph.Node{ {simple.Node(0), simple.Node(1)}, {simple.Node(2), simple.Node(3), simple.Node(4)}, }, q: 0.5714285714285716, }, { communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, }, q: -1.2857142857142856, }, }, }, { name: "simple_directed_twice", layers: []layer{ {g: simpleDirected, weight: 0.5}, {g: simpleDirected, weight: 0.5}, }, // community structure and modularity calculated by C++ implementation: louvain igraph. // Note that louvain igraph returns Q as an unscaled value. structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1), 1: linksTo(2, 3, 4), }, want: 0.5714285714285716, tol: 1e-10, }, }, wantLevels: []level{ { q: 0.5714285714285716, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1)}, {simple.Node(2), simple.Node(3), simple.Node(4)}, }, }, { q: -1.2857142857142856, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, }, }, }, }, { name: "small_dumbell", layers: []layer{ {g: smallDumbell, edgeWeight: 1, weight: 1}, {g: dumbellRepulsion, edgeWeight: -1, weight: -1}, }, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2), 1: linksTo(3, 4, 5), }, want: 2.5714285714285716, tol: 1e-10, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5), }, want: 0, tol: 1e-14, }, }, wantLevels: []level{ { q: 2.5714285714285716, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2)}, {simple.Node(3), simple.Node(4), simple.Node(5)}, }, }, { q: -0.857142857142857, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "repulsion", layers: []layer{{g: repulsion, edgeWeight: -1, weight: -1}}, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2), 1: linksTo(3, 4, 5), }, want: 9.0, tol: 1e-10, }, { resolution: 1, memberships: []intset{ 0: linksTo(0), 1: linksTo(1), 2: linksTo(2), 3: linksTo(3), 4: linksTo(4), 5: linksTo(5), }, want: 3, tol: 1e-14, }, }, wantLevels: []level{ { q: 9.0, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2)}, {simple.Node(3), simple.Node(4), simple.Node(5)}, }, }, { q: 3.0, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "middle_east", layers: []layer{ {g: middleEast.friends, edgeWeight: 1, weight: 1}, {g: middleEast.enemies, edgeWeight: -1, weight: -1}, }, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 6), 1: linksTo(1, 7, 9, 12), 2: linksTo(2, 8, 11), 3: linksTo(3, 4, 5, 10), }, want: 33.818057455540355, tol: 1e-9, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 2, 3, 4, 5, 10), 1: linksTo(1, 7, 9, 12), 2: linksTo(6), 3: linksTo(8, 11), }, want: 30.92749658, tol: 1e-7, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), }, want: 0, tol: 1e-14, }, }, wantLevels: []level{ { q: 33.818057455540355, communities: [][]graph.Node{ {simple.Node(0), simple.Node(6)}, {simple.Node(1), simple.Node(7), simple.Node(9), simple.Node(12)}, {simple.Node(2), simple.Node(8), simple.Node(11)}, {simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(10)}, }, }, { q: 3.8071135430916545, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6)}, {simple.Node(7)}, {simple.Node(8)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(11)}, {simple.Node(12)}, }, }, }, }, } func TestCommunityQDirectedMultiplex(t *testing.T) { for _, test := range communityDirectedMultiplexQTests { g, weights, err := directedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } } q := QMultiplex(g, communities, weights, []float64{structure.resolution}) got := floats.Sum(q) if !scalar.EqualWithinAbsOrRel(got, structure.want, structure.tol, structure.tol) && !math.IsNaN(structure.want) { for _, c := range communities { ordered.ByID(c) } t.Errorf("unexpected Q value for %q %v: got: %v %.3v want: %v", test.name, communities, got, q, structure.want) } } } } func TestCommunityDeltaQDirectedMultiplex(t *testing.T) { tests: for _, test := range communityDirectedMultiplexQTests { g, weights, err := directedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } rnd := rand.New(rand.NewSource(1)).Intn for _, structure := range test.structures { communityOf := make(map[int64]int) communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) communityOf[n] = i communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } resolution := []float64{structure.resolution} before := QMultiplex(g, communities, weights, resolution) // We test exhaustively. const all = true l := newDirectedMultiplexLocalMover( reduceDirectedMultiplex(g, nil, weights), communities, weights, resolution, all) if l == nil { if !math.IsNaN(floats.Sum(before)) { t.Errorf("unexpected nil localMover with non-NaN Q graph: Q=%.4v", before) } continue tests } // This is done to avoid run-to-run // variation due to map iteration order. ordered.ByID(l.nodes) l.shuffle(rnd) for _, target := range l.nodes { got, gotDst, gotSrc := l.deltaQ(target) want, wantDst := math.Inf(-1), -1 migrated := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) if n == target.ID() { continue } migrated[i] = append(migrated[i], simple.Node(n)) } ordered.ByID(migrated[i]) } for i, c := range structure.memberships { if i == communityOf[target.ID()] { continue } if !(all && hasNegative(weights)) { connected := false search: for l := 0; l < g.Depth(); l++ { if weights[l] < 0 { connected = true break search } layer := g.Layer(l) for n := range c { if layer.HasEdgeBetween(int64(n), target.ID()) { connected = true break search } } } if !connected { continue } } migrated[i] = append(migrated[i], target) after := QMultiplex(g, migrated, weights, resolution) migrated[i] = migrated[i][:len(migrated[i])-1] if delta := floats.Sum(after) - floats.Sum(before); delta > want { want = delta wantDst = i } } if !scalar.EqualWithinAbsOrRel(got, want, structure.tol, structure.tol) || gotDst != wantDst { t.Errorf("unexpected result moving n=%d in c=%d of %s/%.4v: got: %.4v,%d want: %.4v,%d"+ "\n\t%v\n\t%v", target.ID(), communityOf[target.ID()], test.name, structure.resolution, got, gotDst, want, wantDst, communities, migrated) } if gotSrc.community != communityOf[target.ID()] { t.Errorf("unexpected source community index: got: %d want: %d", gotSrc, communityOf[target.ID()]) } else if communities[gotSrc.community][gotSrc.node].ID() != target.ID() { wantNodeIdx := -1 for i, n := range communities[gotSrc.community] { if n.ID() == target.ID() { wantNodeIdx = i break } } t.Errorf("unexpected source node index: got: %d want: %d", gotSrc.node, wantNodeIdx) } } } } } func TestReduceQConsistencyDirectedMultiplex(t *testing.T) { tests: for _, test := range communityDirectedMultiplexQTests { g, weights, err := directedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } for _, structure := range test.structures { if math.IsNaN(structure.want) { continue tests } communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } gQ := QMultiplex(g, communities, weights, []float64{structure.resolution}) gQnull := QMultiplex(g, nil, weights, nil) cg0 := reduceDirectedMultiplex(g, nil, weights) cg0Qnull := QMultiplex(cg0, cg0.Structure(), weights, nil) if !scalar.EqualWithinAbsOrRel(floats.Sum(gQnull), floats.Sum(cg0Qnull), structure.tol, structure.tol) { t.Errorf("disagreement between null Q from method: %v and function: %v", cg0Qnull, gQnull) } cg0Q := QMultiplex(cg0, communities, weights, []float64{structure.resolution}) if !scalar.EqualWithinAbsOrRel(floats.Sum(gQ), floats.Sum(cg0Q), structure.tol, structure.tol) { t.Errorf("unexpected Q result after initial reduction: got: %v want :%v", cg0Q, gQ) } cg1 := reduceDirectedMultiplex(cg0, communities, weights) cg1Q := QMultiplex(cg1, cg1.Structure(), weights, []float64{structure.resolution}) if !scalar.EqualWithinAbsOrRel(floats.Sum(gQ), floats.Sum(cg1Q), structure.tol, structure.tol) { t.Errorf("unexpected Q result after second reduction: got: %v want :%v", cg1Q, gQ) } } } } var localDirectedMultiplexMoveTests = []struct { name string layers []layer structures []moveStructures }{ { name: "blondel", layers: []layer{{g: blondel, weight: 1}, {g: blondel, weight: 0.5}}, structures: []moveStructures{ { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(0)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(3)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, // Case to demonstrate when A_aa != k_a^𝛼. targetNodes: []graph.Node{simple.Node(3), simple.Node(2)}, resolution: 1, tol: 1e-14, }, }, }, } func TestMoveLocalDirectedMultiplex(t *testing.T) { for _, test := range localDirectedMultiplexMoveTests { g, weights, err := directedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } r := reduceDirectedMultiplex(reduceDirectedMultiplex(g, nil, weights), communities, weights) l := newDirectedMultiplexLocalMover(r, r.communities, weights, []float64{structure.resolution}, true) for _, n := range structure.targetNodes { dQ, dst, src := l.deltaQ(n) if dQ > 0 { before := floats.Sum(QMultiplex(r, l.communities, weights, []float64{structure.resolution})) l.move(dst, src) after := floats.Sum(QMultiplex(r, l.communities, weights, []float64{structure.resolution})) want := after - before if !scalar.EqualWithinAbsOrRel(dQ, want, structure.tol, structure.tol) { t.Errorf("unexpected deltaQ: got: %v want: %v", dQ, want) } } } } } } func TestLouvainDirectedMultiplex(t *testing.T) { const louvainIterations = 20 for _, test := range communityDirectedMultiplexQTests { g, weights, err := directedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } if test.structures[0].resolution != 1 { panic("bad test: expect resolution=1") } want := make([][]graph.Node, len(test.structures[0].memberships)) for i, c := range test.structures[0].memberships { for n := range c { want[i] = append(want[i], simple.Node(n)) } ordered.ByID(want[i]) } ordered.BySliceIDs(want) var ( got *ReducedDirectedMultiplex bestQ = math.Inf(-1) ) // Modularize is randomised so we do this to // ensure the level tests are consistent. src := rand.New(rand.NewSource(1)) for i := 0; i < louvainIterations; i++ { r := ModularizeMultiplex(g, weights, nil, true, src).(*ReducedDirectedMultiplex) if q := floats.Sum(QMultiplex(r, nil, weights, nil)); q > bestQ || math.IsNaN(q) { bestQ = q got = r if math.IsNaN(q) { // Don't try again for non-connected case. break } } var qs []float64 for p := r; p != nil; p = p.Expanded().(*ReducedDirectedMultiplex) { qs = append(qs, floats.Sum(QMultiplex(p, nil, weights, nil))) } // Recovery of Q values is reversed. if reverse(qs); !sort.Float64sAreSorted(qs) { t.Errorf("Q values not monotonically increasing: %.5v", qs) } } gotCommunities := got.Communities() for _, c := range gotCommunities { ordered.ByID(c) } ordered.BySliceIDs(gotCommunities) if !reflect.DeepEqual(gotCommunities, want) { t.Errorf("unexpected community membership for %s Q=%.4v:\n\tgot: %v\n\twant:%v", test.name, bestQ, gotCommunities, want) continue } var levels []level for p := got; p != nil; p = p.Expanded().(*ReducedDirectedMultiplex) { var communities [][]graph.Node if p.parent != nil { communities = p.parent.Communities() for _, c := range communities { ordered.ByID(c) } ordered.BySliceIDs(communities) } else { communities = reduceDirectedMultiplex(g, nil, weights).Communities() } q := floats.Sum(QMultiplex(p, nil, weights, nil)) if math.IsNaN(q) { // Use an equalable flag value in place of NaN. q = math.Inf(-1) } levels = append(levels, level{q: q, communities: communities}) } if !reflect.DeepEqual(levels, test.wantLevels) { t.Errorf("unexpected level structure:\n\tgot: %v\n\twant:%v", levels, test.wantLevels) } } } func TestNonContiguousDirectedMultiplex(t *testing.T) { g := simple.NewDirectedGraph() for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(4), T: simple.Node(5)}, } { g.SetEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() ModularizeMultiplex(DirectedLayers{g}, nil, nil, true, nil) }() } func TestNonContiguousWeightedDirectedMultiplex(t *testing.T) { g := simple.NewWeightedDirectedGraph(0, 0) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(4), T: simple.Node(5), W: 1}, } { g.SetWeightedEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() ModularizeMultiplex(DirectedLayers{g}, nil, nil, true, nil) }() } func BenchmarkLouvainDirectedMultiplex(b *testing.B) { src := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { ModularizeMultiplex(DirectedLayers{dupGraphDirected}, nil, nil, true, src) } } func directedMultiplexFrom(raw []layer) (DirectedLayers, []float64, error) { var layers []graph.Directed var weights []float64 for _, l := range raw { g := simple.NewWeightedDirectedGraph(0, 0) for u, e := range l.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { w := 1.0 if l.edgeWeight != 0 { w = l.edgeWeight } g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: w}) } } layers = append(layers, g) weights = append(weights, l.weight) } g, err := NewDirectedLayers(layers...) if err != nil { return nil, nil, err } return g, weights, nil } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_directed_test.go000066400000000000000000000470051450372207100256770ustar00rootroot00000000000000// 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 community import ( "math" "reflect" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) type communityDirectedQTest struct { name string g []intset structures []structure wantLevels []level } var communityDirectedQTests = []communityDirectedQTest{ { name: "simple_directed", g: simpleDirected, // community structure and modularity calculated by C++ implementation: louvain igraph. // Note that louvain igraph returns Q as an unscaled value. structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1), 1: linksTo(2, 3, 4), }, want: 0.5714285714285716 / 7, tol: 1e-10, }, }, wantLevels: []level{ { communities: [][]graph.Node{ {simple.Node(0), simple.Node(1)}, {simple.Node(2), simple.Node(3), simple.Node(4)}, }, q: 0.5714285714285716 / 7, }, { communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, }, q: -1.2857142857142856 / 7, }, }, }, { name: "zachary", g: zachary, // community structure and modularity calculated by C++ implementation: louvain igraph. // Note that louvain igraph returns Q as an unscaled value. structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 7, 11, 12, 13, 17, 19, 21), 1: linksTo(4, 5, 6, 10, 16), 2: linksTo(8, 9, 14, 15, 18, 20, 22, 26, 29, 30, 32, 33), 3: linksTo(23, 24, 25, 27, 28, 31), }, want: 34.3417721519 / 79 /* 5->6 and 6->5 because of co-equal rank */, tol: 1e-4, }, }, wantLevels: []level{ { q: 0.43470597660631316, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(7), simple.Node(11), simple.Node(12), simple.Node(13), simple.Node(17), simple.Node(19), simple.Node(21)}, {simple.Node(4), simple.Node(5), simple.Node(6), simple.Node(10), simple.Node(16)}, {simple.Node(8), simple.Node(9), simple.Node(14), simple.Node(15), simple.Node(18), simple.Node(20), simple.Node(22), simple.Node(26), simple.Node(29), simple.Node(30), simple.Node(32), simple.Node(33)}, {simple.Node(23), simple.Node(24), simple.Node(25), simple.Node(27), simple.Node(28), simple.Node(31)}, }, }, { q: 0.3911232174331037, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(7), simple.Node(11), simple.Node(12), simple.Node(13), simple.Node(17), simple.Node(19), simple.Node(21)}, {simple.Node(4), simple.Node(10)}, {simple.Node(5), simple.Node(6), simple.Node(16)}, {simple.Node(8), simple.Node(30)}, {simple.Node(9), simple.Node(14), simple.Node(15), simple.Node(18), simple.Node(20), simple.Node(22), simple.Node(32), simple.Node(33)}, {simple.Node(23), simple.Node(24), simple.Node(25), simple.Node(27), simple.Node(28), simple.Node(31)}, {simple.Node(26), simple.Node(29)}, }, }, { q: -0.014580996635154624, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6)}, {simple.Node(7)}, {simple.Node(8)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(11)}, {simple.Node(12)}, {simple.Node(13)}, {simple.Node(14)}, {simple.Node(15)}, {simple.Node(16)}, {simple.Node(17)}, {simple.Node(18)}, {simple.Node(19)}, {simple.Node(20)}, {simple.Node(21)}, {simple.Node(22)}, {simple.Node(23)}, {simple.Node(24)}, {simple.Node(25)}, {simple.Node(26)}, {simple.Node(27)}, {simple.Node(28)}, {simple.Node(29)}, {simple.Node(30)}, {simple.Node(31)}, {simple.Node(32)}, {simple.Node(33)}, }, }, }, }, { name: "blondel", g: blondel, // community structure and modularity calculated by C++ implementation: louvain igraph. // Note that louvain igraph returns Q as an unscaled value. structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5, 6, 7), 1: linksTo(8, 9, 10, 11, 12, 13, 14, 15), }, want: 11.1428571429 / 28, tol: 1e-4, }, }, wantLevels: []level{ { q: 0.3979591836734694, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6), simple.Node(7)}, {simple.Node(8), simple.Node(9), simple.Node(10), simple.Node(11), simple.Node(12), simple.Node(13), simple.Node(14), simple.Node(15)}, }, }, { q: 0.36862244897959184, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(4), simple.Node(5)}, {simple.Node(3), simple.Node(6), simple.Node(7)}, {simple.Node(8), simple.Node(9), simple.Node(10), simple.Node(11), simple.Node(12), simple.Node(13), simple.Node(14), simple.Node(15)}, }, }, { q: -0.022959183673469385, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6)}, {simple.Node(7)}, {simple.Node(8)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(11)}, {simple.Node(12)}, {simple.Node(13)}, {simple.Node(14)}, {simple.Node(15)}, }, }, }, }, } func TestCommunityQDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testCommunityQDirected(t, test, g) } } func TestCommunityQWeightedDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewWeightedDirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testCommunityQDirected(t, test, g) } } func testCommunityQDirected(t *testing.T, test communityDirectedQTest, g graph.Directed) { for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } } got := Q(g, communities, structure.resolution) if !scalar.EqualWithinAbsOrRel(got, structure.want, structure.tol, structure.tol) && !math.IsNaN(structure.want) { for _, c := range communities { ordered.ByID(c) } t.Errorf("unexpected Q value for %q %v: got: %v want: %v", test.name, communities, got, structure.want) } } } func TestCommunityDeltaQDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testCommunityDeltaQDirected(t, test, g) } } func TestCommunityDeltaQWeightedDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewWeightedDirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testCommunityDeltaQDirected(t, test, g) } } func testCommunityDeltaQDirected(t *testing.T, test communityDirectedQTest, g graph.Directed) { rnd := rand.New(rand.NewSource(1)).Intn for _, structure := range test.structures { communityOf := make(map[int64]int) communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) communityOf[n] = i communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } before := Q(g, communities, structure.resolution) l := newDirectedLocalMover(reduceDirected(g, nil), communities, structure.resolution) if l == nil { if !math.IsNaN(before) { t.Errorf("unexpected nil localMover with non-NaN Q graph: Q=%.4v", before) } return } // This is done to avoid run-to-run // variation due to map iteration order. ordered.ByID(l.nodes) l.shuffle(rnd) for _, target := range l.nodes { got, gotDst, gotSrc := l.deltaQ(target) want, wantDst := math.Inf(-1), -1 migrated := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) if n == target.ID() { continue } migrated[i] = append(migrated[i], simple.Node(n)) } ordered.ByID(migrated[i]) } for i, c := range structure.memberships { if i == communityOf[target.ID()] { continue } connected := false for n := range c { if g.HasEdgeBetween(int64(n), target.ID()) { connected = true break } } if !connected { continue } migrated[i] = append(migrated[i], target) after := Q(g, migrated, structure.resolution) migrated[i] = migrated[i][:len(migrated[i])-1] if after-before > want { want = after - before wantDst = i } } if !scalar.EqualWithinAbsOrRel(got, want, structure.tol, structure.tol) || gotDst != wantDst { t.Errorf("unexpected result moving n=%d in c=%d of %s/%.4v: got: %.4v,%d want: %.4v,%d"+ "\n\t%v\n\t%v", target.ID(), communityOf[target.ID()], test.name, structure.resolution, got, gotDst, want, wantDst, communities, migrated) } if gotSrc.community != communityOf[target.ID()] { t.Errorf("unexpected source community index: got: %d want: %d", gotSrc, communityOf[target.ID()]) } else if communities[gotSrc.community][gotSrc.node].ID() != target.ID() { wantNodeIdx := -1 for i, n := range communities[gotSrc.community] { if n.ID() == target.ID() { wantNodeIdx = i break } } t.Errorf("unexpected source node index: got: %d want: %d", gotSrc.node, wantNodeIdx) } } } } func TestReduceQConsistencyDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testReduceQConsistencyDirected(t, test, g) } } func TestReduceQConsistencyWeightedDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewWeightedDirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testReduceQConsistencyDirected(t, test, g) } } func testReduceQConsistencyDirected(t *testing.T, test communityDirectedQTest, g graph.Directed) { for _, structure := range test.structures { if math.IsNaN(structure.want) { return } communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } gQ := Q(g, communities, structure.resolution) gQnull := Q(g, nil, 1) cg0 := reduceDirected(g, nil) cg0Qnull := Q(cg0, cg0.Structure(), 1) if !scalar.EqualWithinAbsOrRel(gQnull, cg0Qnull, structure.tol, structure.tol) { t.Errorf("disagreement between null Q from method: %v and function: %v", cg0Qnull, gQnull) } cg0Q := Q(cg0, communities, structure.resolution) if !scalar.EqualWithinAbsOrRel(gQ, cg0Q, structure.tol, structure.tol) { t.Errorf("unexpected Q result after initial reduction: got: %v want :%v", cg0Q, gQ) } cg1 := reduceDirected(cg0, communities) cg1Q := Q(cg1, cg1.Structure(), structure.resolution) if !scalar.EqualWithinAbsOrRel(gQ, cg1Q, structure.tol, structure.tol) { t.Errorf("unexpected Q result after second reduction: got: %v want :%v", cg1Q, gQ) } } } type localDirectedMoveTest struct { name string g []intset structures []moveStructures } var localDirectedMoveTests = []localDirectedMoveTest{ { name: "blondel", g: blondel, structures: []moveStructures{ { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(0)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(3)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, // Case to demonstrate when A_aa != k_a^𝛼. targetNodes: []graph.Node{simple.Node(3), simple.Node(2)}, resolution: 1, tol: 1e-14, }, }, }, } func TestMoveLocalDirected(t *testing.T) { for _, test := range localDirectedMoveTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testMoveLocalDirected(t, test, g) } } func TestMoveLocalWeightedDirected(t *testing.T) { for _, test := range localDirectedMoveTests { g := simple.NewWeightedDirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testMoveLocalDirected(t, test, g) } } func testMoveLocalDirected(t *testing.T, test localDirectedMoveTest, g graph.Directed) { for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } r := reduceDirected(reduceDirected(g, nil), communities) l := newDirectedLocalMover(r, r.communities, structure.resolution) for _, n := range structure.targetNodes { dQ, dst, src := l.deltaQ(n) if dQ > 0 { before := Q(r, l.communities, structure.resolution) l.move(dst, src) after := Q(r, l.communities, structure.resolution) want := after - before if !scalar.EqualWithinAbsOrRel(dQ, want, structure.tol, structure.tol) { t.Errorf("unexpected deltaQ for %q: got: %v want: %v", test.name, dQ, want) } } } } } func TestModularizeDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testModularizeDirected(t, test, g) } } func TestModularizeWeightedDirected(t *testing.T) { for _, test := range communityDirectedQTests { g := simple.NewWeightedDirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testModularizeDirected(t, test, g) } } func testModularizeDirected(t *testing.T, test communityDirectedQTest, g graph.Directed) { const louvainIterations = 20 if test.structures[0].resolution != 1 { panic("bad test: expect resolution=1") } want := make([][]graph.Node, len(test.structures[0].memberships)) for i, c := range test.structures[0].memberships { for n := range c { want[i] = append(want[i], simple.Node(n)) } ordered.ByID(want[i]) } ordered.BySliceIDs(want) var ( got *ReducedDirected bestQ = math.Inf(-1) ) // Modularize is randomised so we do this to // ensure the level tests are consistent. src := rand.New(rand.NewSource(1)) for i := 0; i < louvainIterations; i++ { r := Modularize(g, 1, src).(*ReducedDirected) if q := Q(r, nil, 1); q > bestQ || math.IsNaN(q) { bestQ = q got = r if math.IsNaN(q) { // Don't try again for non-connected case. break } } var qs []float64 for p := r; p != nil; p = p.Expanded().(*ReducedDirected) { qs = append(qs, Q(p, nil, 1)) } // Recovery of Q values is reversed. if reverse(qs); !sort.Float64sAreSorted(qs) { t.Errorf("Q values not monotonically increasing: %.5v", qs) } } gotCommunities := got.Communities() for _, c := range gotCommunities { ordered.ByID(c) } ordered.BySliceIDs(gotCommunities) if !reflect.DeepEqual(gotCommunities, want) { t.Errorf("unexpected community membership for %s Q=%.4v:\n\tgot: %v\n\twant:%v", test.name, bestQ, gotCommunities, want) return } var levels []level for p := got; p != nil; p = p.Expanded().(*ReducedDirected) { var communities [][]graph.Node if p.parent != nil { communities = p.parent.Communities() for _, c := range communities { ordered.ByID(c) } ordered.BySliceIDs(communities) } else { communities = reduceDirected(g, nil).Communities() } q := Q(p, nil, 1) if math.IsNaN(q) { // Use an equalable flag value in place of NaN. q = math.Inf(-1) } levels = append(levels, level{q: q, communities: communities}) } if !reflect.DeepEqual(levels, test.wantLevels) { t.Errorf("unexpected level structure:\n\tgot: %v\n\twant:%v", levels, test.wantLevels) } } func TestNonContiguousDirected(t *testing.T) { g := simple.NewDirectedGraph() for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(4), T: simple.Node(5)}, } { g.SetEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() Modularize(g, 1, nil) }() } func TestNonContiguousWeightedDirected(t *testing.T) { g := simple.NewWeightedDirectedGraph(0, 0) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(4), T: simple.Node(5), W: 1}, } { g.SetWeightedEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() Modularize(g, 1, nil) }() } func BenchmarkLouvainDirected(b *testing.B) { src := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { Modularize(dupGraphDirected, 1, src) } } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_test.go000066400000000000000000000164471450372207100240420ustar00rootroot00000000000000// 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 community import ( "fmt" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/simple" ) // intset is an integer set. type intset map[int]struct{} func linksTo(i ...int) intset { if len(i) == 0 { return nil } s := make(intset) for _, v := range i { s[v] = struct{}{} } return s } type layer struct { g []intset edgeWeight float64 // Zero edge weight is interpreted as 1.0. weight float64 } var ( unconnected = []intset{ /* Nodes 0-4 are implicit .*/ 5: nil} smallDumbell = []intset{ 0: linksTo(1, 2), 1: linksTo(2), 2: linksTo(3), 3: linksTo(4, 5), 4: linksTo(5), 5: nil, } dumbellRepulsion = []intset{ 0: linksTo(4), 1: linksTo(5), 2: nil, 3: nil, 4: nil, 5: nil, } repulsion = []intset{ 0: linksTo(3, 4, 5), 1: linksTo(3, 4, 5), 2: linksTo(3, 4, 5), 3: linksTo(0, 1, 2), 4: linksTo(0, 1, 2), 5: linksTo(0, 1, 2), } simpleDirected = []intset{ 0: linksTo(1), 1: linksTo(0, 4), 2: linksTo(1), 3: linksTo(0, 4), 4: linksTo(2), } // http://www.slate.com/blogs/the_world_/2014/07/17/the_middle_east_friendship_chart.html middleEast = struct{ friends, complicated, enemies []intset }{ // green cells friends: []intset{ 0: nil, 1: linksTo(5, 7, 9, 12), 2: linksTo(11), 3: linksTo(4, 5, 10), 4: linksTo(3, 5, 10), 5: linksTo(1, 3, 4, 8, 10, 12), 6: nil, 7: linksTo(1, 12), 8: linksTo(5, 9, 11), 9: linksTo(1, 8, 12), 10: linksTo(3, 4, 5), 11: linksTo(2, 8), 12: linksTo(1, 5, 7, 9), }, // yellow cells complicated: []intset{ 0: linksTo(2, 4), 1: linksTo(4, 8), 2: linksTo(0, 3, 4, 5, 8, 9), 3: linksTo(2, 8, 11), 4: linksTo(0, 1, 2, 8), 5: linksTo(2), 6: nil, 7: linksTo(9, 11), 8: linksTo(1, 2, 3, 4, 10, 12), 9: linksTo(2, 7, 11), 10: linksTo(8), 11: linksTo(3, 7, 9, 12), 12: linksTo(8, 11), }, // red cells enemies: []intset{ 0: linksTo(1, 3, 5, 6, 7, 8, 9, 10, 11, 12), 1: linksTo(0, 2, 3, 6, 10, 11), 2: linksTo(1, 6, 7, 10, 12), 3: linksTo(0, 1, 6, 7, 9, 12), 4: linksTo(6, 7, 9, 11, 12), 5: linksTo(0, 6, 7, 9, 11), 6: linksTo(0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12), 7: linksTo(0, 2, 3, 4, 5, 6, 8, 10), 8: linksTo(0, 6, 7), 9: linksTo(0, 3, 4, 5, 6, 10), 10: linksTo(0, 1, 2, 6, 7, 9, 11, 12), 11: linksTo(0, 1, 4, 5, 6, 10), 12: linksTo(0, 2, 3, 4, 6, 10), }, } // W. W. Zachary, An information flow model for conflict and fission in small groups, // Journal of Anthropological Research 33, 452-473 (1977). // // The edge list here is constructed such that all link descriptions // head from a node with lower Page Rank to a node with higher Page // Rank. This has no impact on undirected tests, but allows a sensible // view for directed tests. zachary = []intset{ 0: nil, // rank=0.097 1: linksTo(0, 2), // rank=0.05288 2: linksTo(0, 32), // rank=0.05708 3: linksTo(0, 1, 2), // rank=0.03586 4: linksTo(0, 6, 10), // rank=0.02198 5: linksTo(0, 6), // rank=0.02911 6: linksTo(0, 5), // rank=0.02911 7: linksTo(0, 1, 2, 3), // rank=0.02449 8: linksTo(0, 2, 32, 33), // rank=0.02977 9: linksTo(2, 33), // rank=0.01431 10: linksTo(0, 5), // rank=0.02198 11: linksTo(0), // rank=0.009565 12: linksTo(0, 3), // rank=0.01464 13: linksTo(0, 1, 2, 3, 33), // rank=0.02954 14: linksTo(32, 33), // rank=0.01454 15: linksTo(32, 33), // rank=0.01454 16: linksTo(5, 6), // rank=0.01678 17: linksTo(0, 1), // rank=0.01456 18: linksTo(32, 33), // rank=0.01454 19: linksTo(0, 1, 33), // rank=0.0196 20: linksTo(32, 33), // rank=0.01454 21: linksTo(0, 1), // rank=0.01456 22: linksTo(32, 33), // rank=0.01454 23: linksTo(32, 33), // rank=0.03152 24: linksTo(27, 31), // rank=0.02108 25: linksTo(23, 24, 31), // rank=0.02101 26: linksTo(29, 33), // rank=0.01504 27: linksTo(2, 23, 33), // rank=0.02564 28: linksTo(2, 31, 33), // rank=0.01957 29: linksTo(23, 32, 33), // rank=0.02629 30: linksTo(1, 8, 32, 33), // rank=0.02459 31: linksTo(0, 32, 33), // rank=0.03716 32: linksTo(33), // rank=0.07169 33: nil, // rank=0.1009 } // doi:10.1088/1742-5468/2008/10/P10008 figure 1 // // The edge list here is constructed such that all link descriptions // head from a node with lower Page Rank to a node with higher Page // Rank. This has no impact on undirected tests, but allows a sensible // view for directed tests. blondel = []intset{ 0: linksTo(2), // rank=0.06858 1: linksTo(2, 4, 7), // rank=0.05264 2: nil, // rank=0.08249 3: linksTo(0, 7), // rank=0.03884 4: linksTo(0, 2, 10), // rank=0.06754 5: linksTo(0, 2, 7, 11), // rank=0.06738 6: linksTo(2, 7, 11), // rank=0.0528 7: nil, // rank=0.07008 8: linksTo(10), // rank=0.09226 9: linksTo(8), // rank=0.05821 10: nil, // rank=0.1035 11: linksTo(8, 10), // rank=0.08538 12: linksTo(9, 10), // rank=0.04052 13: linksTo(10, 11), // rank=0.03855 14: linksTo(8, 9, 10), // rank=0.05621 15: linksTo(8), // rank=0.02506 } ) type structure struct { resolution float64 memberships []intset want, tol float64 } type level struct { q float64 communities [][]graph.Node } type moveStructures struct { memberships []intset targetNodes []graph.Node resolution float64 tol float64 } func reverse(f []float64) { for i, j := 0, len(f)-1; i < j; i, j = i+1, j-1 { f[i], f[j] = f[j], f[i] } } func hasNegative(f []float64) bool { for _, v := range f { if v < 0 { return true } } return false } var ( dupGraph = simple.NewUndirectedGraph() dupGraphDirected = simple.NewDirectedGraph() ) func init() { err := gen.Duplication(dupGraph, 1000, 0.8, 0.1, 0.5, rand.New(rand.NewSource(1))) if err != nil { panic(err) } // Construct a directed graph from dupGraph // such that every edge dupGraph is replaced // with an edge that flows from the low node // ID to the high node ID. for _, e := range graph.EdgesOf(dupGraph.Edges()) { if e.To().ID() < e.From().ID() { se := e.(simple.Edge) se.F, se.T = se.T, se.F e = se } dupGraphDirected.SetEdge(e) } } // This init function checks the Middle East relationship data. func init() { world := make([]intset, len(middleEast.friends)) for i := range world { world[i] = make(intset) } for _, relationships := range [][]intset{middleEast.friends, middleEast.complicated, middleEast.enemies} { for i, rel := range relationships { for inter := range rel { if _, ok := world[i][inter]; ok { panic(fmt.Sprintf("unexpected relationship: %v--%v", i, inter)) } world[i][inter] = struct{}{} } } } for i := range world { if len(world[i]) != len(middleEast.friends)-1 { panic(fmt.Sprintf("missing relationship in %v: %v", i, world[i])) } } } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_undirected.go000066400000000000000000000415031450372207100252000ustar00rootroot00000000000000// 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 community import ( "math" "sort" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" ) // qUndirected returns the modularity Q score of the graph g subdivided into the // given communities at the given resolution. If communities is nil, the // unclustered modularity score is returned. The resolution parameter // is γ as defined in Reichardt and Bornholdt doi:10.1103/PhysRevE.74.016110. // qUndirected will panic if g has any edge with negative edge weight. // // Q = 1/2m \sum_{ij} [ A_{ij} - (\gamma k_i k_j)/2m ] \delta(c_i,c_j) // // graph.Undirect may be used as a shim to allow calculation of Q for // directed graphs. func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution float64) float64 { nodes := graph.NodesOf(g.Nodes()) weight := positiveWeightFuncFor(g) // Calculate the total edge weight of the graph // and the table of penetrating edge weight sums. var m2 float64 k := make(map[int64]float64, len(nodes)) for _, u := range nodes { uid := u.ID() w := weight(uid, uid) to := g.From(uid) for to.Next() { w += weight(uid, to.Node().ID()) } m2 += w k[uid] = w } if communities == nil { var q float64 for _, u := range nodes { uid := u.ID() kU := k[uid] q += weight(uid, uid) - resolution*kU*kU/m2 } return q / m2 } // Iterate over the communities, calculating // the non-self edge weights for the upper // triangle and adjust the diagonal. var q float64 for _, c := range communities { for i, u := range c { uid := u.ID() kU := k[uid] q += weight(uid, uid) - resolution*kU*kU/m2 for _, v := range c[i+1:] { vid := v.ID() q += 2 * (weight(uid, vid) - resolution*kU*k[vid]/m2) } } } return q / m2 } // louvainUndirected returns the hierarchical modularization of g at the given // resolution using the Louvain algorithm. If src is nil, rand.Intn is used as // the random generator. louvainUndirected will panic if g has any edge with negative edge // weight. // // graph.Undirect may be used as a shim to allow modularization of directed graphs. func louvainUndirected(g graph.Undirected, resolution float64, src rand.Source) *ReducedUndirected { // See louvain.tex for a detailed description // of the algorithm used here. c := reduceUndirected(g, nil) rnd := rand.Intn if src != nil { rnd = rand.New(src).Intn } for { l := newUndirectedLocalMover(c, c.communities, resolution) if l == nil { return c } if done := l.localMovingHeuristic(rnd); done { return c } c = reduceUndirected(c, l.communities) } } // ReducedUndirected is an undirected graph of communities derived from a // parent graph by reduction. type ReducedUndirected struct { // nodes is the set of nodes held // by the graph. In a ReducedUndirected // the node ID is the index into // nodes. nodes []community undirectedEdges // communities is the community // structure of the graph. communities [][]graph.Node parent *ReducedUndirected } var ( reducedUndirected = (*ReducedUndirected)(nil) _ graph.WeightedUndirected = reducedUndirected _ ReducedGraph = reducedUndirected ) // Communities returns the community memberships of the nodes in the // graph used to generate the reduced graph. func (g *ReducedUndirected) Communities() [][]graph.Node { communities := make([][]graph.Node, len(g.communities)) if g.parent == nil { for i, members := range g.communities { comm := make([]graph.Node, len(members)) for j, n := range members { nodes := g.nodes[n.ID()].nodes if len(nodes) != 1 { panic("community: unexpected number of nodes in base graph community") } comm[j] = nodes[0] } communities[i] = comm } return communities } sub := g.parent.Communities() for i, members := range g.communities { var comm []graph.Node for _, n := range members { comm = append(comm, sub[n.ID()]...) } communities[i] = comm } return communities } // Structure returns the community structure of the current level of // the module clustering. The first index of the returned value // corresponds to the index of the nodes in the next higher level if // it exists. The returned value should not be mutated. func (g *ReducedUndirected) Structure() [][]graph.Node { return g.communities } // Expanded returns the next lower level of the module clustering or nil // if at the lowest level. func (g *ReducedUndirected) Expanded() ReducedGraph { return g.parent } // reduceUndirected returns a reduced graph constructed from g divided // into the given communities. The communities value is mutated // by the call to reduceUndirected. If communities is nil and g is a // ReducedUndirected, it is returned unaltered. func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUndirected { if communities == nil { if r, ok := g.(*ReducedUndirected); ok { return r } nodes := graph.NodesOf(g.Nodes()) // TODO(kortschak) This sort is necessary really only // for testing. In practice we would not be using the // community provided by the user for a Q calculation. // Probably we should use a function to map the // communities in the test sets to the remapped order. ordered.ByID(nodes) communities = make([][]graph.Node, len(nodes)) for i := range nodes { communities[i] = []graph.Node{node(i)} } weight := positiveWeightFuncFor(g) r := ReducedUndirected{ nodes: make([]community, len(nodes)), undirectedEdges: undirectedEdges{ edges: make([][]int, len(nodes)), weights: make(map[[2]int]float64), }, communities: communities, } communityOf := make(map[int64]int, len(nodes)) for i, n := range nodes { r.nodes[i] = community{id: i, nodes: []graph.Node{n}} communityOf[n.ID()] = i } for _, u := range nodes { uid := u.ID() ucid := communityOf[uid] var out []int to := g.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] if vcid != ucid { out = append(out, vcid) } if ucid < vcid { // Only store the weight once. r.weights[[2]int{ucid, vcid}] = weight(uid, vid) } } r.edges[ucid] = out } return &r } // Remove zero length communities destructively. var commNodes int for i := 0; i < len(communities); { comm := communities[i] if len(comm) == 0 { communities[i] = communities[len(communities)-1] communities[len(communities)-1] = nil communities = communities[:len(communities)-1] } else { commNodes += len(comm) i++ } } r := ReducedUndirected{ nodes: make([]community, len(communities)), undirectedEdges: undirectedEdges{ edges: make([][]int, len(communities)), weights: make(map[[2]int]float64), }, } r.communities = make([][]graph.Node, len(communities)) for i := range r.communities { r.communities[i] = []graph.Node{node(i)} } if g, ok := g.(*ReducedUndirected); ok { // Make sure we retain the truncated // community structure. g.communities = communities r.parent = g } weight := positiveWeightFuncFor(g) communityOf := make(map[int64]int, commNodes) for i, comm := range communities { r.nodes[i] = community{id: i, nodes: comm} for _, n := range comm { communityOf[n.ID()] = i } } for ucid, comm := range communities { var out []int for i, u := range comm { uid := u.ID() r.nodes[ucid].weight += weight(uid, uid) for _, v := range comm[i+1:] { r.nodes[ucid].weight += 2 * weight(uid, v.ID()) } to := g.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] found := false for _, e := range out { if e == vcid { found = true break } } if !found && vcid != ucid { out = append(out, vcid) } if ucid < vcid { // Only store the weight once. r.weights[[2]int{ucid, vcid}] += weight(uid, vid) } } } r.edges[ucid] = out } return &r } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *ReducedUndirected) Node(id int64) graph.Node { if g.has(id) { return g.nodes[id] } return nil } // has returns whether the node exists within the graph. func (g *ReducedUndirected) has(id int64) bool { return 0 <= id && id < int64(len(g.nodes)) } // Nodes returns all the nodes in the graph. func (g *ReducedUndirected) Nodes() graph.Nodes { nodes := make([]graph.Node, len(g.nodes)) for i := range g.nodes { nodes[i] = node(i) } return iterator.NewOrderedNodes(nodes) } // From returns all nodes in g that can be reached directly from u. func (g *ReducedUndirected) From(uid int64) graph.Nodes { out := g.edges[uid] nodes := make([]graph.Node, len(out)) for i, vid := range out { nodes[i] = g.nodes[vid] } return iterator.NewOrderedNodes(nodes) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g *ReducedUndirected) HasEdgeBetween(xid, yid int64) bool { if xid == yid || !isValidID(xid) || !isValidID(yid) { return false } if xid > yid { xid, yid = yid, xid } _, ok := g.weights[[2]int{int(xid), int(yid)}] return ok } // 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 *ReducedUndirected) Edge(uid, vid int64) graph.Edge { return g.WeightedEdgeBetween(uid, vid) } // 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 *ReducedUndirected) WeightedEdge(uid, vid int64) graph.WeightedEdge { return g.WeightedEdgeBetween(uid, vid) } // EdgeBetween returns the edge between nodes x and y. func (g *ReducedUndirected) EdgeBetween(xid, yid int64) graph.Edge { return g.WeightedEdgeBetween(xid, yid) } // WeightedEdgeBetween returns the weighted edge between nodes x and y. func (g *ReducedUndirected) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge { if xid == yid || !isValidID(xid) || !isValidID(yid) { return nil } if yid < xid { xid, yid = yid, xid } w, ok := g.weights[[2]int{int(xid), int(yid)}] if !ok { return nil } return edge{from: g.nodes[xid], to: g.nodes[yid], weight: w} } // 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 the internal node weight is returned. If there is no joining // edge between the two nodes the weight value returned is zero. Weight returns true if an edge // exists between x and y or if x and y have the same ID, false otherwise. func (g *ReducedUndirected) Weight(xid, yid int64) (w float64, ok bool) { if !isValidID(xid) || !isValidID(yid) { return 0, false } if xid == yid { return g.nodes[xid].weight, true } if xid > yid { xid, yid = yid, xid } w, ok = g.weights[[2]int{int(xid), int(yid)}] return w, ok } // undirectedLocalMover is a step in graph modularity optimization. type undirectedLocalMover struct { g *ReducedUndirected // nodes is the set of working nodes. nodes []graph.Node // edgeWeightOf is the weighted degree // of each node indexed by ID. edgeWeightOf []float64 // m2 is the total sum of // edge weights in g. m2 float64 // weight is the weight function // provided by g or a function // that returns the Weight value // of the non-nil edge between x // and y. weight func(xid, yid int64) float64 // communities is the current // division of g. communities [][]graph.Node // memberships is a mapping between // node ID and community membership. memberships []int // resolution is the Reichardt and // Bornholdt γ parameter as defined // in doi:10.1103/PhysRevE.74.016110. resolution float64 // moved indicates that a call to // move has been made since the last // call to shuffle. moved bool // changed indicates that a move // has been made since the creation // of the local mover. changed bool } // newUndirectedLocalMover returns a new undirectedLocalMover initialized with // the graph g, a set of communities and a modularity resolution parameter. The // node IDs of g must be contiguous in [0,n) where n is the number of nodes. // If g has a zero edge weight sum, nil is returned. func newUndirectedLocalMover(g *ReducedUndirected, communities [][]graph.Node, resolution float64) *undirectedLocalMover { nodes := graph.NodesOf(g.Nodes()) l := undirectedLocalMover{ g: g, nodes: nodes, edgeWeightOf: make([]float64, len(nodes)), communities: communities, memberships: make([]int, len(nodes)), resolution: resolution, weight: positiveWeightFuncFor(g), } // Calculate the total edge weight of the graph // and degree weights for each node. for _, u := range l.nodes { uid := u.ID() w := l.weight(uid, uid) to := g.From(uid) for to.Next() { w += l.weight(uid, to.Node().ID()) } l.edgeWeightOf[uid] = w l.m2 += w } if l.m2 == 0 { return nil } // Assign membership mappings. for i, c := range communities { for _, u := range c { l.memberships[u.ID()] = i } } return &l } // localMovingHeuristic performs the Louvain local moving heuristic until // no further moves can be made. It returns a boolean indicating that the // undirectedLocalMover has not made any improvement to the community // structure and so the Louvain algorithm is done. func (l *undirectedLocalMover) localMovingHeuristic(rnd func(int) int) (done bool) { for { l.shuffle(rnd) for _, n := range l.nodes { dQ, dst, src := l.deltaQ(n) if dQ <= deltaQtol { continue } l.move(dst, src) } if !l.moved { return !l.changed } } } // shuffle performs a Fisher-Yates shuffle on the nodes held by the // undirectedLocalMover using the random source rnd which should return // an integer in the range [0,n). func (l *undirectedLocalMover) shuffle(rnd func(n int) int) { l.moved = false for i := range l.nodes[:len(l.nodes)-1] { j := i + rnd(len(l.nodes)-i) l.nodes[i], l.nodes[j] = l.nodes[j], l.nodes[i] } } // move moves the node at src to the community at dst. func (l *undirectedLocalMover) move(dst int, src commIdx) { l.moved = true l.changed = true srcComm := l.communities[src.community] n := srcComm[src.node] l.memberships[n.ID()] = dst l.communities[dst] = append(l.communities[dst], n) srcComm[src.node], srcComm[len(srcComm)-1] = srcComm[len(srcComm)-1], nil l.communities[src.community] = srcComm[:len(srcComm)-1] } // deltaQ returns the highest gain in modularity attainable by moving // n from its current community to another connected community and // the index of the chosen destination. The index into the // undirectedLocalMover's communities field is returned in src if n // is in communities. func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) { id := n.ID() a_aa := l.weight(id, id) k_a := l.edgeWeightOf[id] m2 := l.m2 gamma := l.resolution // Find communities connected to n. connected := make(set.Ints) // The following for loop is equivalent to: // // for _, v := range l.g.From(n) { // connected.Add(l.memberships[v.ID()]) // } // // This is done to avoid an allocation. for _, vid := range l.g.edges[id] { connected.Add(l.memberships[vid]) } // Insert the node's own community. connected.Add(l.memberships[id]) candidates := make([]int, 0, len(connected)) for i := range connected { candidates = append(candidates, i) } sort.Ints(candidates) // Calculate the highest modularity gain // from moving into another community and // keep the index of that community. var dQremove float64 dQadd, dst, src := math.Inf(-1), -1, commIdx{-1, -1} for _, i := range candidates { c := l.communities[i] var k_aC, sigma_totC float64 // C is a substitution for ^𝛼 or ^𝛽. var removal bool for j, u := range c { uid := u.ID() if uid == id { if src.community != -1 { panic("community: multiple sources") } src = commIdx{i, j} removal = true } k_aC += l.weight(id, uid) // sigma_totC could be kept for each community // and updated for moves, changing the calculation // of sigma_totC here from O(n_c) to O(1), but // in practice the time savings do not appear // to be compelling and do not make up for the // increase in code complexity and space required. sigma_totC += l.edgeWeightOf[uid] } // See louvain.tex for a derivation of these equations. switch { case removal: // The community c was the current community, // so calculate the change due to removal. dQremove = k_aC /*^𝛼*/ - a_aa - gamma*k_a*(sigma_totC /*^𝛼*/ -k_a)/m2 default: // Otherwise calculate the change due to an addition // to c and retain if it is the current best. dQ := k_aC /*^𝛽*/ - gamma*k_a*sigma_totC /*^𝛽*/ /m2 if dQ > dQadd { dQadd = dQ dst = i } } } return 2 * (dQadd - dQremove) / m2, dst, src } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_undirected_multiplex.go000066400000000000000000000601501450372207100273020ustar00rootroot00000000000000// 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 community import ( "fmt" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" ) // UndirectedMultiplex is an undirected multiplex graph. type UndirectedMultiplex interface { Multiplex // Layer returns the lth layer of the // multiplex graph. Layer(l int) graph.Undirected } // qUndirectedMultiplex returns the modularity Q score of the multiplex graph layers // subdivided into the given communities at the given resolutions and weights. Q is // returned as the vector of weighted Q scores for each layer of the multiplex graph. // If communities is nil, the unclustered modularity score is returned. // If weights is nil layers are equally weighted, otherwise the length of // weights must equal the number of layers. If resolutions is nil, a resolution // of 1.0 is used for all layers, otherwise either a single element slice may be used // to specify a global resolution, or the length of resolutions must equal the number // of layers. The resolution parameter is γ as defined in Reichardt and Bornholdt // doi:10.1103/PhysRevE.74.016110. // qUndirectedMultiplex will panic if the graph has any layer weight-scaled edge with // negative edge weight. // // Q_{layer} = w_{layer} \sum_{ij} [ A_{layer}*_{ij} - (\gamma_{layer} k_i k_j)/2m ] \delta(c_i,c_j) // // Note that Q values for multiplex graphs are not scaled by the total layer edge weight. // // graph.Undirect may be used as a shim to allow calculation of Q for // directed graphs. func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64) []float64 { q := make([]float64, g.Depth()) nodes := graph.NodesOf(g.Nodes()) layerWeight := 1.0 layerResolution := 1.0 if len(resolutions) == 1 { layerResolution = resolutions[0] } for l := 0; l < g.Depth(); l++ { layer := g.Layer(l) if weights != nil { layerWeight = weights[l] } if layerWeight == 0 { continue } if len(resolutions) > 1 { layerResolution = resolutions[l] } var weight func(xid, yid int64) float64 if layerWeight < 0 { weight = negativeWeightFuncFor(layer) } else { weight = positiveWeightFuncFor(layer) } // Calculate the total edge weight of the layer // and the table of penetrating edge weight sums. var m2 float64 k := make(map[int64]float64, len(nodes)) for _, u := range nodes { uid := u.ID() w := weight(uid, uid) to := layer.From(uid) for to.Next() { w += weight(uid, to.Node().ID()) } m2 += w k[uid] = w } if communities == nil { var qLayer float64 for _, u := range nodes { uid := u.ID() kU := k[uid] qLayer += weight(uid, uid) - layerResolution*kU*kU/m2 } q[l] = layerWeight * qLayer continue } // Iterate over the communities, calculating // the non-self edge weights for the upper // triangle and adjust the diagonal. var qLayer float64 for _, c := range communities { for i, u := range c { uid := u.ID() kU := k[uid] qLayer += weight(uid, uid) - layerResolution*kU*kU/m2 for _, v := range c[i+1:] { vid := v.ID() qLayer += 2 * (weight(uid, vid) - layerResolution*kU*k[vid]/m2) } } } q[l] = layerWeight * qLayer } return q } // UndirectedLayers implements UndirectedMultiplex. type UndirectedLayers []graph.Undirected // NewUndirectedLayers returns an UndirectedLayers using the provided layers // ensuring there is a match between IDs for each layer. func NewUndirectedLayers(layers ...graph.Undirected) (UndirectedLayers, error) { if len(layers) == 0 { return nil, nil } base := make(set.Int64s) nodes := layers[0].Nodes() for nodes.Next() { base.Add(nodes.Node().ID()) } for i, l := range layers[1:] { next := make(set.Int64s) nodes := l.Nodes() for nodes.Next() { next.Add(nodes.Node().ID()) } if !set.Int64sEqual(next, base) { return nil, fmt.Errorf("community: layer ID mismatch between layers: %d", i+1) } } return layers, nil } // Nodes returns the nodes of the receiver. func (g UndirectedLayers) Nodes() graph.Nodes { if len(g) == 0 { return nil } return g[0].Nodes() } // Depth returns the depth of the multiplex graph. func (g UndirectedLayers) Depth() int { return len(g) } // Layer returns the lth layer of the multiplex graph. func (g UndirectedLayers) Layer(l int) graph.Undirected { return g[l] } // louvainUndirectedMultiplex returns the hierarchical modularization of g at the given resolution // using the Louvain algorithm. If all is true and g has negatively weighted layers, all // communities will be searched during the modularization. If src is nil, rand.Intn is // used as the random generator. louvainUndirectedMultiplex will panic if g has any edge with // edge weight that does not sign-match the layer weight. // // graph.Undirect may be used as a shim to allow modularization of directed graphs. func louvainUndirectedMultiplex(g UndirectedMultiplex, weights, resolutions []float64, all bool, src rand.Source) *ReducedUndirectedMultiplex { if weights != nil && len(weights) != g.Depth() { panic("community: weights vector length mismatch") } if resolutions != nil && len(resolutions) != 1 && len(resolutions) != g.Depth() { panic("community: resolutions vector length mismatch") } // See louvain.tex for a detailed description // of the algorithm used here. c := reduceUndirectedMultiplex(g, nil, weights) rnd := rand.Intn if src != nil { rnd = rand.New(src).Intn } for { l := newUndirectedMultiplexLocalMover(c, c.communities, weights, resolutions, all) if l == nil { return c } if done := l.localMovingHeuristic(rnd); done { return c } c = reduceUndirectedMultiplex(c, l.communities, weights) } } // ReducedUndirectedMultiplex is an undirected graph of communities derived from a // parent graph by reduction. type ReducedUndirectedMultiplex struct { // nodes is the set of nodes held // by the graph. In a ReducedUndirectedMultiplex // the node ID is the index into // nodes. nodes []multiplexCommunity layers []undirectedEdges // communities is the community // structure of the graph. communities [][]graph.Node parent *ReducedUndirectedMultiplex } var ( _ UndirectedMultiplex = (*ReducedUndirectedMultiplex)(nil) _ graph.WeightedUndirected = (*undirectedLayerHandle)(nil) ) // Nodes returns all the nodes in the graph. func (g *ReducedUndirectedMultiplex) Nodes() graph.Nodes { nodes := make([]graph.Node, len(g.nodes)) for i := range g.nodes { nodes[i] = node(i) } return iterator.NewOrderedNodes(nodes) } // Depth returns the number of layers in the multiplex graph. func (g *ReducedUndirectedMultiplex) Depth() int { return len(g.layers) } // Layer returns the lth layer of the multiplex graph. func (g *ReducedUndirectedMultiplex) Layer(l int) graph.Undirected { return undirectedLayerHandle{multiplex: g, layer: l} } // Communities returns the community memberships of the nodes in the // graph used to generate the reduced graph. func (g *ReducedUndirectedMultiplex) Communities() [][]graph.Node { communities := make([][]graph.Node, len(g.communities)) if g.parent == nil { for i, members := range g.communities { comm := make([]graph.Node, len(members)) for j, n := range members { nodes := g.nodes[n.ID()].nodes if len(nodes) != 1 { panic("community: unexpected number of nodes in base graph community") } comm[j] = nodes[0] } communities[i] = comm } return communities } sub := g.parent.Communities() for i, members := range g.communities { var comm []graph.Node for _, n := range members { comm = append(comm, sub[n.ID()]...) } communities[i] = comm } return communities } // Structure returns the community structure of the current level of // the module clustering. The first index of the returned value // corresponds to the index of the nodes in the next higher level if // it exists. The returned value should not be mutated. func (g *ReducedUndirectedMultiplex) Structure() [][]graph.Node { return g.communities } // Expanded returns the next lower level of the module clustering or nil // if at the lowest level. func (g *ReducedUndirectedMultiplex) Expanded() ReducedMultiplex { return g.parent } // reduceUndirectedMultiplex returns a reduced graph constructed from g divided // into the given communities. The communities value is mutated // by the call to reduceUndirectedMultiplex. If communities is nil and g is a // ReducedUndirectedMultiplex, it is returned unaltered. func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, weights []float64) *ReducedUndirectedMultiplex { if communities == nil { if r, ok := g.(*ReducedUndirectedMultiplex); ok { return r } nodes := graph.NodesOf(g.Nodes()) // TODO(kortschak) This sort is necessary really only // for testing. In practice we would not be using the // community provided by the user for a Q calculation. // Probably we should use a function to map the // communities in the test sets to the remapped order. ordered.ByID(nodes) communities = make([][]graph.Node, len(nodes)) for i := range nodes { communities[i] = []graph.Node{node(i)} } r := ReducedUndirectedMultiplex{ nodes: make([]multiplexCommunity, len(nodes)), layers: make([]undirectedEdges, g.Depth()), communities: communities, } communityOf := make(map[int64]int, len(nodes)) for i, n := range nodes { r.nodes[i] = multiplexCommunity{id: i, nodes: []graph.Node{n}, weights: make([]float64, depth(weights))} communityOf[n.ID()] = i } for i := range r.layers { r.layers[i] = undirectedEdges{ edges: make([][]int, len(nodes)), weights: make(map[[2]int]float64), } } w := 1.0 for l := 0; l < g.Depth(); l++ { layer := g.Layer(l) if weights != nil { w = weights[l] } if w == 0 { continue } var sign float64 var weight func(xid, yid int64) float64 if w < 0 { sign, weight = -1, negativeWeightFuncFor(layer) } else { sign, weight = 1, positiveWeightFuncFor(layer) } for _, u := range nodes { var out []int uid := u.ID() ucid := communityOf[uid] to := layer.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] if vcid != ucid { out = append(out, vcid) } if ucid < vcid { // Only store the weight once. r.layers[l].weights[[2]int{ucid, vcid}] = sign * weight(uid, vid) } } r.layers[l].edges[ucid] = out } } return &r } // Remove zero length communities destructively. var commNodes int for i := 0; i < len(communities); { comm := communities[i] if len(comm) == 0 { communities[i] = communities[len(communities)-1] communities[len(communities)-1] = nil communities = communities[:len(communities)-1] } else { commNodes += len(comm) i++ } } r := ReducedUndirectedMultiplex{ nodes: make([]multiplexCommunity, len(communities)), layers: make([]undirectedEdges, g.Depth()), } communityOf := make(map[int64]int, commNodes) for i, comm := range communities { r.nodes[i] = multiplexCommunity{id: i, nodes: comm, weights: make([]float64, depth(weights))} for _, n := range comm { communityOf[n.ID()] = i } } for i := range r.layers { r.layers[i] = undirectedEdges{ edges: make([][]int, len(communities)), weights: make(map[[2]int]float64), } } r.communities = make([][]graph.Node, len(communities)) for i := range r.communities { r.communities[i] = []graph.Node{node(i)} } if g, ok := g.(*ReducedUndirectedMultiplex); ok { // Make sure we retain the truncated // community structure. g.communities = communities r.parent = g } w := 1.0 for l := 0; l < g.Depth(); l++ { layer := g.Layer(l) if weights != nil { w = weights[l] } if w == 0 { continue } var sign float64 var weight func(xid, yid int64) float64 if w < 0 { sign, weight = -1, negativeWeightFuncFor(layer) } else { sign, weight = 1, positiveWeightFuncFor(layer) } for ucid, comm := range communities { var out []int for i, u := range comm { uid := u.ID() r.nodes[ucid].weights[l] += sign * weight(uid, uid) for _, v := range comm[i+1:] { r.nodes[ucid].weights[l] += 2 * sign * weight(uid, v.ID()) } to := layer.From(uid) for to.Next() { vid := to.Node().ID() vcid := communityOf[vid] found := false for _, e := range out { if e == vcid { found = true break } } if !found && vcid != ucid { out = append(out, vcid) } if ucid < vcid { // Only store the weight once. r.layers[l].weights[[2]int{ucid, vcid}] += sign * weight(uid, vid) } } } r.layers[l].edges[ucid] = out } } return &r } // undirectedLayerHandle is a handle to a multiplex graph layer. type undirectedLayerHandle struct { // multiplex is the complete // multiplex graph. multiplex *ReducedUndirectedMultiplex // layer is an index into the // multiplex for the current // layer. layer int } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g undirectedLayerHandle) Node(id int64) graph.Node { if g.has(id) { return g.multiplex.nodes[id] } return nil } // has returns whether the node exists within the graph. func (g undirectedLayerHandle) has(id int64) bool { return 0 <= id && id < int64(len(g.multiplex.nodes)) } // Nodes returns all the nodes in the graph. func (g undirectedLayerHandle) Nodes() graph.Nodes { nodes := make([]graph.Node, len(g.multiplex.nodes)) for i := range g.multiplex.nodes { nodes[i] = node(i) } return iterator.NewOrderedNodes(nodes) } // From returns all nodes in g that can be reached directly from u. func (g undirectedLayerHandle) From(uid int64) graph.Nodes { out := g.multiplex.layers[g.layer].edges[uid] nodes := make([]graph.Node, len(out)) for i, vid := range out { nodes[i] = g.multiplex.nodes[vid] } return iterator.NewOrderedNodes(nodes) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g undirectedLayerHandle) HasEdgeBetween(xid, yid int64) bool { if xid == yid || !isValidID(xid) || !isValidID(yid) { return false } if xid > yid { xid, yid = yid, xid } _, ok := g.multiplex.layers[g.layer].weights[[2]int{int(xid), int(yid)}] return ok } // 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 undirectedLayerHandle) Edge(uid, vid int64) graph.Edge { return g.WeightedEdgeBetween(uid, vid) } // 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 undirectedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge { return g.WeightedEdgeBetween(uid, vid) } // EdgeBetween returns the edge between nodes x and y. func (g undirectedLayerHandle) EdgeBetween(xid, yid int64) graph.Edge { return g.WeightedEdgeBetween(xid, yid) } // WeightedEdgeBetween returns the weighted edge between nodes x and y. func (g undirectedLayerHandle) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge { if xid == yid || !isValidID(xid) || !isValidID(yid) { return nil } if yid < xid { xid, yid = yid, xid } w, ok := g.multiplex.layers[g.layer].weights[[2]int{int(xid), int(yid)}] if !ok { return nil } return multiplexEdge{from: g.multiplex.nodes[xid], to: g.multiplex.nodes[yid], weight: w} } // 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 the internal node weight is returned. If there is no joining // edge between the two nodes the weight value returned is zero. Weight returns true if an edge // exists between x and y or if x and y have the same ID, false otherwise. func (g undirectedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) { if !isValidID(xid) || !isValidID(yid) { return 0, false } if xid == yid { return g.multiplex.nodes[xid].weights[g.layer], true } if xid > yid { xid, yid = yid, xid } w, ok = g.multiplex.layers[g.layer].weights[[2]int{int(xid), int(yid)}] return w, ok } // undirectedMultiplexLocalMover is a step in graph modularity optimization. type undirectedMultiplexLocalMover struct { g *ReducedUndirectedMultiplex // nodes is the set of working nodes. nodes []graph.Node // edgeWeightOf is the weighted degree // of each node indexed by ID. edgeWeightOf [][]float64 // m2 is the total sum of // edge weights in g. m2 []float64 // weight is the weight function // provided by g or a function // that returns the Weight value // of the non-nil edge between x // and y. weight []func(xid, yid int64) float64 // communities is the current // division of g. communities [][]graph.Node // memberships is a mapping between // node ID and community membership. memberships []int // resolution is the Reichardt and // Bornholdt γ parameter as defined // in doi:10.1103/PhysRevE.74.016110. resolutions []float64 // weights is the layer weights for // the modularisation. weights []float64 // searchAll specifies whether the local // mover should consider non-connected // communities during the local moving // heuristic. searchAll bool // moved indicates that a call to // move has been made since the last // call to shuffle. moved bool // changed indicates that a move // has been made since the creation // of the local mover. changed bool } // newUndirectedMultiplexLocalMover returns a new undirectedMultiplexLocalMover initialized with // the graph g, a set of communities and a modularity resolution parameter. The // node IDs of g must be contiguous in [0,n) where n is the number of nodes. // If g has a zero edge weight sum, nil is returned. func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64, all bool) *undirectedMultiplexLocalMover { nodes := graph.NodesOf(g.Nodes()) l := undirectedMultiplexLocalMover{ g: g, nodes: nodes, edgeWeightOf: make([][]float64, g.Depth()), m2: make([]float64, g.Depth()), communities: communities, memberships: make([]int, len(nodes)), resolutions: resolutions, weights: weights, weight: make([]func(xid, yid int64) float64, g.Depth()), } // Calculate the total edge weight of the graph // and degree weights for each node. var zero int for i := 0; i < g.Depth(); i++ { l.edgeWeightOf[i] = make([]float64, len(nodes)) var weight func(xid, yid int64) float64 if weights != nil { if weights[i] == 0 { zero++ continue } if weights[i] < 0 { weight = negativeWeightFuncFor(g.Layer(i)) l.searchAll = all } else { weight = positiveWeightFuncFor(g.Layer(i)) } } else { weight = positiveWeightFuncFor(g.Layer(i)) } l.weight[i] = weight layer := g.Layer(i) for _, u := range l.nodes { uid := u.ID() w := weight(uid, uid) to := layer.From(uid) for to.Next() { w += weight(uid, to.Node().ID()) } l.edgeWeightOf[i][uid] = w l.m2[i] += w } if l.m2[i] == 0 { zero++ } } if zero == g.Depth() { return nil } // Assign membership mappings. for i, c := range communities { for _, u := range c { l.memberships[u.ID()] = i } } return &l } // localMovingHeuristic performs the Louvain local moving heuristic until // no further moves can be made. It returns a boolean indicating that the // undirectedMultiplexLocalMover has not made any improvement to the community // structure and so the Louvain algorithm is done. func (l *undirectedMultiplexLocalMover) localMovingHeuristic(rnd func(int) int) (done bool) { for { l.shuffle(rnd) for _, n := range l.nodes { dQ, dst, src := l.deltaQ(n) if dQ <= deltaQtol { continue } l.move(dst, src) } if !l.moved { return !l.changed } } } // shuffle performs a Fisher-Yates shuffle on the nodes held by the // undirectedMultiplexLocalMover using the random source rnd which should return // an integer in the range [0,n). func (l *undirectedMultiplexLocalMover) shuffle(rnd func(n int) int) { l.moved = false for i := range l.nodes[:len(l.nodes)-1] { j := i + rnd(len(l.nodes)-i) l.nodes[i], l.nodes[j] = l.nodes[j], l.nodes[i] } } // move moves the node at src to the community at dst. func (l *undirectedMultiplexLocalMover) move(dst int, src commIdx) { l.moved = true l.changed = true srcComm := l.communities[src.community] n := srcComm[src.node] l.memberships[n.ID()] = dst l.communities[dst] = append(l.communities[dst], n) srcComm[src.node], srcComm[len(srcComm)-1] = srcComm[len(srcComm)-1], nil l.communities[src.community] = srcComm[:len(srcComm)-1] } // deltaQ returns the highest gain in modularity attainable by moving // n from its current community to another connected community and // the index of the chosen destination. The index into the // undirectedMultiplexLocalMover's communities field is returned in src if n // is in communities. func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) { id := n.ID() var iterator minTaker if l.searchAll { iterator = &dense{n: len(l.communities)} } else { // Find communities connected to n. connected := make(set.Ints) // The following for loop is equivalent to: // // for i := 0; i < l.g.Depth(); i++ { // for _, v := range l.g.Layer(i).From(n) { // connected.Add(l.memberships[v.ID()]) // } // } // // This is done to avoid an allocation for // each layer. for _, layer := range l.g.layers { for _, vid := range layer.edges[id] { connected.Add(l.memberships[vid]) } } // Insert the node's own community. connected.Add(l.memberships[id]) iterator = newSlice(connected) } // Calculate the highest modularity gain // from moving into another community and // keep the index of that community. var dQremove float64 dQadd, dst, src := math.Inf(-1), -1, commIdx{-1, -1} var i int for iterator.TakeMin(&i) { c := l.communities[i] var removal bool var _dQadd float64 for layer := 0; layer < l.g.Depth(); layer++ { m2 := l.m2[layer] if m2 == 0 { // Do not consider layers with zero sum edge weight. continue } w := 1.0 if l.weights != nil { w = l.weights[layer] } if w == 0 { // Do not consider layers with zero weighting. continue } var k_aC, sigma_totC float64 // C is a substitution for ^𝛼 or ^𝛽. removal = false for j, u := range c { uid := u.ID() if uid == id { // Only mark and check src community on the first layer. if layer == 0 { if src.community != -1 { panic("community: multiple sources") } src = commIdx{i, j} } removal = true } k_aC += l.weight[layer](id, uid) // sigma_totC could be kept for each community // and updated for moves, changing the calculation // of sigma_totC here from O(n_c) to O(1), but // in practice the time savings do not appear // to be compelling and do not make up for the // increase in code complexity and space required. sigma_totC += l.edgeWeightOf[layer][uid] } a_aa := l.weight[layer](id, id) k_a := l.edgeWeightOf[layer][id] gamma := 1.0 if l.resolutions != nil { if len(l.resolutions) == 1 { gamma = l.resolutions[0] } else { gamma = l.resolutions[layer] } } // See louvain.tex for a derivation of these equations. // The weighting term, w, is described in V Traag, // "Algorithms and dynamical models for communities and // reputation in social networks", chapter 5. // http://www.traag.net/wp/wp-content/papercite-data/pdf/traag_algorithms_2013.pdf switch { case removal: // The community c was the current community, // so calculate the change due to removal. dQremove += w * (k_aC /*^𝛼*/ - a_aa - gamma*k_a*(sigma_totC /*^𝛼*/ -k_a)/m2) default: // Otherwise calculate the change due to an addition // to c. _dQadd += w * (k_aC /*^𝛽*/ - gamma*k_a*sigma_totC /*^𝛽*/ /m2) } } if !removal && _dQadd > dQadd { dQadd = _dQadd dst = i } } return 2 * (dQadd - dQremove), dst, src } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_undirected_multiplex_test.go000066400000000000000000000433541450372207100303500ustar00rootroot00000000000000// 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 community import ( "math" "reflect" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var communityUndirectedMultiplexQTests = []struct { name string layers []layer structures []structure wantLevels []level }{ { name: "unconnected", layers: []layer{{g: unconnected, weight: 1}}, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0), 1: linksTo(1), 2: linksTo(2), 3: linksTo(3), 4: linksTo(4), 5: linksTo(5), }, want: math.NaN(), }, }, wantLevels: []level{ { q: math.Inf(-1), // Here math.Inf(-1) is used as a place holder for NaN to allow use of reflect.DeepEqual. communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "small_dumbell", layers: []layer{ {g: smallDumbell, edgeWeight: 1, weight: 1}, {g: dumbellRepulsion, edgeWeight: -1, weight: -1}, }, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2), 1: linksTo(3, 4, 5), }, want: 7.0, tol: 1e-10, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5), }, want: 0, tol: 1e-14, }, }, wantLevels: []level{ { q: 7.0, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2)}, {simple.Node(3), simple.Node(4), simple.Node(5)}, }, }, { q: -1.4285714285714284, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "small_dumbell_twice", layers: []layer{ {g: smallDumbell, weight: 0.5}, {g: smallDumbell, weight: 0.5}, }, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2), 1: linksTo(3, 4, 5), }, want: 5, tol: 1e-10, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5), }, want: 0, tol: 1e-14, }, }, wantLevels: []level{ { q: 0.35714285714285715 * 14, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2)}, {simple.Node(3), simple.Node(4), simple.Node(5)}, }, }, { q: -0.17346938775510204 * 14, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "repulsion", layers: []layer{{g: repulsion, edgeWeight: -1, weight: -1}}, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2), 1: linksTo(3, 4, 5), }, want: 9.0, tol: 1e-10, }, { resolution: 1, memberships: []intset{ 0: linksTo(0), 1: linksTo(1), 2: linksTo(2), 3: linksTo(3), 4: linksTo(4), 5: linksTo(5), }, want: 3, tol: 1e-14, }, }, wantLevels: []level{ { q: 9.0, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2)}, {simple.Node(3), simple.Node(4), simple.Node(5)}, }, }, { q: 3.0, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "middle_east", layers: []layer{ {g: middleEast.friends, edgeWeight: 1, weight: 1}, {g: middleEast.enemies, edgeWeight: -1, weight: -1}, }, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0, 6), 1: linksTo(1, 7, 9, 12), 2: linksTo(2, 8, 11), 3: linksTo(3, 4, 5, 10), }, want: 33.8180574555, tol: 1e-9, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 2, 3, 4, 5, 10), 1: linksTo(1, 7, 9, 12), 2: linksTo(6), 3: linksTo(8, 11), }, want: 30.92749658, tol: 1e-7, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), }, want: 0, tol: 1e-14, }, }, wantLevels: []level{ { q: 33.818057455540355, communities: [][]graph.Node{ {simple.Node(0), simple.Node(6)}, {simple.Node(1), simple.Node(7), simple.Node(9), simple.Node(12)}, {simple.Node(2), simple.Node(8), simple.Node(11)}, {simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(10)}, }, }, { q: 3.8071135430916545, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6)}, {simple.Node(7)}, {simple.Node(8)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(11)}, {simple.Node(12)}, }, }, }, }, } func TestCommunityQUndirectedMultiplex(t *testing.T) { for _, test := range communityUndirectedMultiplexQTests { g, weights, err := undirectedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } } q := QMultiplex(g, communities, weights, []float64{structure.resolution}) got := floats.Sum(q) if !scalar.EqualWithinAbsOrRel(got, structure.want, structure.tol, structure.tol) && !math.IsNaN(structure.want) { for _, c := range communities { ordered.ByID(c) } t.Errorf("unexpected Q value for %q %v: got: %v %.3v want: %v", test.name, communities, got, q, structure.want) } } } } func TestCommunityDeltaQUndirectedMultiplex(t *testing.T) { tests: for _, test := range communityUndirectedMultiplexQTests { g, weights, err := undirectedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } rnd := rand.New(rand.NewSource(1)).Intn for _, structure := range test.structures { communityOf := make(map[int64]int) communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) communityOf[n] = i communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } resolution := []float64{structure.resolution} before := QMultiplex(g, communities, weights, resolution) // We test exhaustively. const all = true l := newUndirectedMultiplexLocalMover( reduceUndirectedMultiplex(g, nil, weights), communities, weights, resolution, all) if l == nil { if !math.IsNaN(floats.Sum(before)) { t.Errorf("unexpected nil localMover with non-NaN Q graph: Q=%.4v", before) } continue tests } // This is done to avoid run-to-run // variation due to map iteration order. ordered.ByID(l.nodes) l.shuffle(rnd) for _, target := range l.nodes { got, gotDst, gotSrc := l.deltaQ(target) want, wantDst := math.Inf(-1), -1 migrated := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) if n == target.ID() { continue } migrated[i] = append(migrated[i], simple.Node(n)) } ordered.ByID(migrated[i]) } for i, c := range structure.memberships { if i == communityOf[target.ID()] { continue } if !(all && hasNegative(weights)) { connected := false search: for l := 0; l < g.Depth(); l++ { if weights[l] < 0 { connected = true break search } layer := g.Layer(l) for n := range c { if layer.HasEdgeBetween(int64(n), target.ID()) { connected = true break search } } } if !connected { continue } } migrated[i] = append(migrated[i], target) after := QMultiplex(g, migrated, weights, resolution) migrated[i] = migrated[i][:len(migrated[i])-1] if delta := floats.Sum(after) - floats.Sum(before); delta > want { want = delta wantDst = i } } if !scalar.EqualWithinAbsOrRel(got, want, structure.tol, structure.tol) || gotDst != wantDst { t.Errorf("unexpected result moving n=%d in c=%d of %s/%.4v: got: %.4v,%d want: %.4v,%d"+ "\n\t%v\n\t%v", target.ID(), communityOf[target.ID()], test.name, structure.resolution, got, gotDst, want, wantDst, communities, migrated) } if gotSrc.community != communityOf[target.ID()] { t.Errorf("unexpected source community index: got: %d want: %d", gotSrc, communityOf[target.ID()]) } else if communities[gotSrc.community][gotSrc.node].ID() != target.ID() { wantNodeIdx := -1 for i, n := range communities[gotSrc.community] { if n.ID() == target.ID() { wantNodeIdx = i break } } t.Errorf("unexpected source node index: got: %d want: %d", gotSrc.node, wantNodeIdx) } } } } } func TestReduceQConsistencyUndirectedMultiplex(t *testing.T) { tests: for _, test := range communityUndirectedMultiplexQTests { g, weights, err := undirectedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } for _, structure := range test.structures { if math.IsNaN(structure.want) { continue tests } communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } gQ := QMultiplex(g, communities, weights, []float64{structure.resolution}) gQnull := QMultiplex(g, nil, weights, nil) cg0 := reduceUndirectedMultiplex(g, nil, weights) cg0Qnull := QMultiplex(cg0, cg0.Structure(), weights, nil) if !scalar.EqualWithinAbsOrRel(floats.Sum(gQnull), floats.Sum(cg0Qnull), structure.tol, structure.tol) { t.Errorf("disagreement between null Q from method: %v and function: %v", cg0Qnull, gQnull) } cg0Q := QMultiplex(cg0, communities, weights, []float64{structure.resolution}) if !scalar.EqualWithinAbsOrRel(floats.Sum(gQ), floats.Sum(cg0Q), structure.tol, structure.tol) { t.Errorf("unexpected Q result after initial reduction: got: %v want :%v", cg0Q, gQ) } cg1 := reduceUndirectedMultiplex(cg0, communities, weights) cg1Q := QMultiplex(cg1, cg1.Structure(), weights, []float64{structure.resolution}) if !scalar.EqualWithinAbsOrRel(floats.Sum(gQ), floats.Sum(cg1Q), structure.tol, structure.tol) { t.Errorf("unexpected Q result after second reduction: got: %v want :%v", cg1Q, gQ) } } } } var localUndirectedMultiplexMoveTests = []struct { name string layers []layer structures []moveStructures }{ { name: "blondel", layers: []layer{{g: blondel, weight: 1}, {g: blondel, weight: 0.5}}, structures: []moveStructures{ { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(0)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(3)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, // Case to demonstrate when A_aa != k_a^𝛼. targetNodes: []graph.Node{simple.Node(3), simple.Node(2)}, resolution: 1, tol: 1e-14, }, }, }, } func TestMoveLocalUndirectedMultiplex(t *testing.T) { for _, test := range localUndirectedMultiplexMoveTests { g, weights, err := undirectedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } r := reduceUndirectedMultiplex(reduceUndirectedMultiplex(g, nil, weights), communities, weights) l := newUndirectedMultiplexLocalMover(r, r.communities, weights, []float64{structure.resolution}, true) for _, n := range structure.targetNodes { dQ, dst, src := l.deltaQ(n) if dQ > 0 { before := floats.Sum(QMultiplex(r, l.communities, weights, []float64{structure.resolution})) l.move(dst, src) after := floats.Sum(QMultiplex(r, l.communities, weights, []float64{structure.resolution})) want := after - before if !scalar.EqualWithinAbsOrRel(dQ, want, structure.tol, structure.tol) { t.Errorf("unexpected deltaQ: got: %v want: %v", dQ, want) } } } } } } func TestLouvainMultiplex(t *testing.T) { const louvainIterations = 20 for _, test := range communityUndirectedMultiplexQTests { g, weights, err := undirectedMultiplexFrom(test.layers) if err != nil { t.Errorf("unexpected error creating multiplex: %v", err) continue } if test.structures[0].resolution != 1 { panic("bad test: expect resolution=1") } want := make([][]graph.Node, len(test.structures[0].memberships)) for i, c := range test.structures[0].memberships { for n := range c { want[i] = append(want[i], simple.Node(n)) } ordered.ByID(want[i]) } ordered.BySliceIDs(want) var ( got *ReducedUndirectedMultiplex bestQ = math.Inf(-1) ) // Modularize is randomised so we do this to // ensure the level tests are consistent. src := rand.New(rand.NewSource(1)) for i := 0; i < louvainIterations; i++ { r := ModularizeMultiplex(g, weights, nil, true, src).(*ReducedUndirectedMultiplex) if q := floats.Sum(QMultiplex(r, nil, weights, nil)); q > bestQ || math.IsNaN(q) { bestQ = q got = r if math.IsNaN(q) { // Don't try again for non-connected case. break } } var qs []float64 for p := r; p != nil; p = p.Expanded().(*ReducedUndirectedMultiplex) { qs = append(qs, floats.Sum(QMultiplex(p, nil, weights, nil))) } // Recovery of Q values is reversed. if reverse(qs); !sort.Float64sAreSorted(qs) { t.Errorf("Q values not monotonically increasing: %.5v", qs) } } gotCommunities := got.Communities() for _, c := range gotCommunities { ordered.ByID(c) } ordered.BySliceIDs(gotCommunities) if !reflect.DeepEqual(gotCommunities, want) { t.Errorf("unexpected community membership for %s Q=%.4v:\n\tgot: %v\n\twant:%v", test.name, bestQ, gotCommunities, want) continue } var levels []level for p := got; p != nil; p = p.Expanded().(*ReducedUndirectedMultiplex) { var communities [][]graph.Node if p.parent != nil { communities = p.parent.Communities() for _, c := range communities { ordered.ByID(c) } ordered.BySliceIDs(communities) } else { communities = reduceUndirectedMultiplex(g, nil, weights).Communities() } q := floats.Sum(QMultiplex(p, nil, weights, nil)) if math.IsNaN(q) { // Use an equalable flag value in place of NaN. q = math.Inf(-1) } levels = append(levels, level{q: q, communities: communities}) } if !reflect.DeepEqual(levels, test.wantLevels) { t.Errorf("unexpected level structure:\n\tgot: %v\n\twant:%v", levels, test.wantLevels) } } } func TestNonContiguousUndirectedMultiplex(t *testing.T) { g := simple.NewUndirectedGraph() for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(4), T: simple.Node(5)}, } { g.SetEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() ModularizeMultiplex(UndirectedLayers{g}, nil, nil, true, nil) }() } func TestNonContiguousWeightedUndirectedMultiplex(t *testing.T) { g := simple.NewWeightedUndirectedGraph(0, 0) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(4), T: simple.Node(5), W: 1}, } { g.SetWeightedEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() ModularizeMultiplex(UndirectedLayers{g}, nil, nil, true, nil) }() } func BenchmarkLouvainMultiplex(b *testing.B) { src := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { ModularizeMultiplex(UndirectedLayers{dupGraph}, nil, nil, true, src) } } func undirectedMultiplexFrom(raw []layer) (UndirectedLayers, []float64, error) { var layers []graph.Undirected var weights []float64 for _, l := range raw { g := simple.NewWeightedUndirectedGraph(0, 0) for u, e := range l.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { w := 1.0 if l.edgeWeight != 0 { w = l.edgeWeight } g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: w}) } } layers = append(layers, g) weights = append(weights, l.weight) } g, err := NewUndirectedLayers(layers...) if err != nil { return nil, nil, err } return g, weights, nil } golang-gonum-v1-gonum-0.14.0/graph/community/louvain_undirected_test.go000066400000000000000000000520611450372207100262400ustar00rootroot00000000000000// 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 community import ( "math" "reflect" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) type communityUndirectedQTest struct { name string g []intset structures []structure wantLevels []level } var communityUndirectedQTests = []communityUndirectedQTest{ // The java reference implementation is available from http://www.ludowaltman.nl/slm/. { name: "unconnected", g: unconnected, structures: []structure{ { resolution: 1, memberships: []intset{ 0: linksTo(0), 1: linksTo(1), 2: linksTo(2), 3: linksTo(3), 4: linksTo(4), 5: linksTo(5), }, want: math.NaN(), }, }, wantLevels: []level{ { q: math.Inf(-1), // Here math.Inf(-1) is used as a place holder for NaN to allow use of reflect.DeepEqual. communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "small_dumbell", g: smallDumbell, structures: []structure{ { resolution: 1, // community structure and modularity calculated by java reference implementation. memberships: []intset{ 0: linksTo(0, 1, 2), 1: linksTo(3, 4, 5), }, want: 0.357, tol: 1e-3, }, { resolution: 1, memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5), }, // theoretical expectation. want: 0, tol: 1e-14, }, }, wantLevels: []level{ { q: 0.35714285714285715, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2)}, {simple.Node(3), simple.Node(4), simple.Node(5)}, }, }, { q: -0.17346938775510204, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, }, }, }, }, { name: "zachary", g: zachary, structures: []structure{ { resolution: 1, // community structure and modularity from doi: 10.1140/epjb/e2013-40829-0 memberships: []intset{ 0: linksTo(0, 1, 2, 3, 7, 11, 12, 13, 17, 19, 21), 1: linksTo(4, 5, 6, 10, 16), 2: linksTo(8, 9, 14, 15, 18, 20, 22, 26, 29, 30, 32, 33), 3: linksTo(23, 24, 25, 27, 28, 31), }, // Noted to be the optimal modularisation in the paper above. want: 0.4198, tol: 1e-4, }, { resolution: 0.5, // community structure and modularity calculated by java reference implementation. memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 16, 17, 19, 21), 1: linksTo(8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33), }, want: 0.6218, tol: 1e-3, }, { resolution: 2, // community structure and modularity calculated by java reference implementation. memberships: []intset{ 0: linksTo(14, 18, 20, 22, 32, 33, 15), 1: linksTo(0, 1, 11, 17, 19, 21), 2: linksTo(2, 3, 7, 9, 12, 13), 3: linksTo(4, 5, 6, 10, 16), 4: linksTo(24, 25, 28, 31), 5: linksTo(23, 26, 27, 29), 6: linksTo(8, 30), }, want: 0.1645, tol: 1e-3, }, }, wantLevels: []level{ { q: 0.4197896120973044, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(7), simple.Node(11), simple.Node(12), simple.Node(13), simple.Node(17), simple.Node(19), simple.Node(21)}, {simple.Node(4), simple.Node(5), simple.Node(6), simple.Node(10), simple.Node(16)}, {simple.Node(8), simple.Node(9), simple.Node(14), simple.Node(15), simple.Node(18), simple.Node(20), simple.Node(22), simple.Node(26), simple.Node(29), simple.Node(30), simple.Node(32), simple.Node(33)}, {simple.Node(23), simple.Node(24), simple.Node(25), simple.Node(27), simple.Node(28), simple.Node(31)}, }, }, { q: 0.3496877054569362, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(7), simple.Node(11), simple.Node(12), simple.Node(13), simple.Node(17), simple.Node(19), simple.Node(21)}, {simple.Node(4), simple.Node(10)}, {simple.Node(5), simple.Node(6), simple.Node(16)}, {simple.Node(8), simple.Node(9), simple.Node(14), simple.Node(15), simple.Node(18), simple.Node(20), simple.Node(22), simple.Node(30), simple.Node(32), simple.Node(33)}, {simple.Node(23), simple.Node(25)}, {simple.Node(24), simple.Node(27)}, {simple.Node(26), simple.Node(29)}, {simple.Node(28), simple.Node(31)}, }, }, { q: -0.04980276134122286, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6)}, {simple.Node(7)}, {simple.Node(8)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(11)}, {simple.Node(12)}, {simple.Node(13)}, {simple.Node(14)}, {simple.Node(15)}, {simple.Node(16)}, {simple.Node(17)}, {simple.Node(18)}, {simple.Node(19)}, {simple.Node(20)}, {simple.Node(21)}, {simple.Node(22)}, {simple.Node(23)}, {simple.Node(24)}, {simple.Node(25)}, {simple.Node(26)}, {simple.Node(27)}, {simple.Node(28)}, {simple.Node(29)}, {simple.Node(30)}, {simple.Node(31)}, {simple.Node(32)}, {simple.Node(33)}, }, }, }, }, { name: "blondel", g: blondel, structures: []structure{ { resolution: 1, // community structure and modularity calculated by java reference implementation. memberships: []intset{ 0: linksTo(0, 1, 2, 3, 4, 5, 6, 7), 1: linksTo(8, 9, 10, 11, 12, 13, 14, 15), }, want: 0.3922, tol: 1e-4, }, }, wantLevels: []level{ { q: 0.39221938775510207, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6), simple.Node(7)}, {simple.Node(8), simple.Node(9), simple.Node(10), simple.Node(11), simple.Node(12), simple.Node(13), simple.Node(14), simple.Node(15)}, }, }, { q: 0.3463010204081633, communities: [][]graph.Node{ {simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(4), simple.Node(5)}, {simple.Node(3), simple.Node(6), simple.Node(7)}, {simple.Node(8), simple.Node(9), simple.Node(10), simple.Node(12), simple.Node(14), simple.Node(15)}, {simple.Node(11), simple.Node(13)}, }, }, { q: -0.07142857142857144, communities: [][]graph.Node{ {simple.Node(0)}, {simple.Node(1)}, {simple.Node(2)}, {simple.Node(3)}, {simple.Node(4)}, {simple.Node(5)}, {simple.Node(6)}, {simple.Node(7)}, {simple.Node(8)}, {simple.Node(9)}, {simple.Node(10)}, {simple.Node(11)}, {simple.Node(12)}, {simple.Node(13)}, {simple.Node(14)}, {simple.Node(15)}, }, }, }, }, } func TestCommunityQUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testCommunityQUndirected(t, test, g) } } func TestCommunityQWeightedUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewWeightedUndirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testCommunityQUndirected(t, test, g) } } func testCommunityQUndirected(t *testing.T, test communityUndirectedQTest, g graph.Undirected) { for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } } got := Q(g, communities, structure.resolution) if !scalar.EqualWithinAbsOrRel(got, structure.want, structure.tol, structure.tol) && !math.IsNaN(structure.want) { for _, c := range communities { ordered.ByID(c) } t.Errorf("unexpected Q value for %q %v: got: %v want: %v", test.name, communities, got, structure.want) } } } func TestCommunityDeltaQUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testCommunityDeltaQUndirected(t, test, g) } } func TestCommunityDeltaQWeightedUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewWeightedUndirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testCommunityDeltaQUndirected(t, test, g) } } func testCommunityDeltaQUndirected(t *testing.T, test communityUndirectedQTest, g graph.Undirected) { rnd := rand.New(rand.NewSource(1)).Intn for _, structure := range test.structures { communityOf := make(map[int64]int) communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) communityOf[n] = i communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } before := Q(g, communities, structure.resolution) l := newUndirectedLocalMover(reduceUndirected(g, nil), communities, structure.resolution) if l == nil { if !math.IsNaN(before) { t.Errorf("unexpected nil localMover with non-NaN Q graph: Q=%.4v", before) } return } // This is done to avoid run-to-run // variation due to map iteration order. ordered.ByID(l.nodes) l.shuffle(rnd) for _, target := range l.nodes { got, gotDst, gotSrc := l.deltaQ(target) want, wantDst := math.Inf(-1), -1 migrated := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { n := int64(n) if n == target.ID() { continue } migrated[i] = append(migrated[i], simple.Node(n)) } ordered.ByID(migrated[i]) } for i, c := range structure.memberships { if i == communityOf[target.ID()] { continue } connected := false for n := range c { if g.HasEdgeBetween(int64(n), target.ID()) { connected = true break } } if !connected { continue } migrated[i] = append(migrated[i], target) after := Q(g, migrated, structure.resolution) migrated[i] = migrated[i][:len(migrated[i])-1] if after-before > want { want = after - before wantDst = i } } if !scalar.EqualWithinAbsOrRel(got, want, structure.tol, structure.tol) || gotDst != wantDst { t.Errorf("unexpected result moving n=%d in c=%d of %s/%.4v: got: %.4v,%d want: %.4v,%d"+ "\n\t%v\n\t%v", target.ID(), communityOf[target.ID()], test.name, structure.resolution, got, gotDst, want, wantDst, communities, migrated) } if gotSrc.community != communityOf[target.ID()] { t.Errorf("unexpected source community index: got: %d want: %d", gotSrc, communityOf[target.ID()]) } else if communities[gotSrc.community][gotSrc.node].ID() != target.ID() { wantNodeIdx := -1 for i, n := range communities[gotSrc.community] { if n.ID() == target.ID() { wantNodeIdx = i break } } t.Errorf("unexpected source node index: got: %d want: %d", gotSrc.node, wantNodeIdx) } } } } func TestReduceQConsistencyUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testReduceQConsistencyUndirected(t, test, g) } } func TestReduceQConsistencyWeightedUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewWeightedUndirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testReduceQConsistencyUndirected(t, test, g) } } func testReduceQConsistencyUndirected(t *testing.T, test communityUndirectedQTest, g graph.Undirected) { for _, structure := range test.structures { if math.IsNaN(structure.want) { return } communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } gQ := Q(g, communities, structure.resolution) gQnull := Q(g, nil, 1) cg0 := reduceUndirected(g, nil) cg0Qnull := Q(cg0, cg0.Structure(), 1) if !scalar.EqualWithinAbsOrRel(gQnull, cg0Qnull, structure.tol, structure.tol) { t.Errorf("disagreement between null Q from method: %v and function: %v", cg0Qnull, gQnull) } cg0Q := Q(cg0, communities, structure.resolution) if !scalar.EqualWithinAbsOrRel(gQ, cg0Q, structure.tol, structure.tol) { t.Errorf("unexpected Q result after initial reduction: got: %v want :%v", cg0Q, gQ) } cg1 := reduceUndirected(cg0, communities) cg1Q := Q(cg1, cg1.Structure(), structure.resolution) if !scalar.EqualWithinAbsOrRel(gQ, cg1Q, structure.tol, structure.tol) { t.Errorf("unexpected Q result after second reduction: got: %v want :%v", cg1Q, gQ) } } } type localUndirectedMoveTest struct { name string g []intset structures []moveStructures } var localUndirectedMoveTests = []localUndirectedMoveTest{ { name: "blondel", g: blondel, structures: []moveStructures{ { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(0)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, targetNodes: []graph.Node{simple.Node(3)}, resolution: 1, tol: 1e-14, }, { memberships: []intset{ 0: linksTo(0, 1, 2, 4, 5), 1: linksTo(3, 6, 7), 2: linksTo(8, 9, 10, 12, 14, 15), 3: linksTo(11, 13), }, // Case to demonstrate when A_aa != k_a^𝛼. targetNodes: []graph.Node{simple.Node(3), simple.Node(2)}, resolution: 1, tol: 1e-14, }, }, }, } func TestMoveLocalUndirected(t *testing.T) { for _, test := range localUndirectedMoveTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testMoveLocalUndirected(t, test, g) } } func TestMoveLocalWeightedUndirected(t *testing.T) { for _, test := range localUndirectedMoveTests { g := simple.NewWeightedUndirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testMoveLocalUndirected(t, test, g) } } func testMoveLocalUndirected(t *testing.T, test localUndirectedMoveTest, g graph.Undirected) { for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } ordered.ByID(communities[i]) } r := reduceUndirected(reduceUndirected(g, nil), communities) l := newUndirectedLocalMover(r, r.communities, structure.resolution) for _, n := range structure.targetNodes { dQ, dst, src := l.deltaQ(n) if dQ > 0 { before := Q(r, l.communities, structure.resolution) l.move(dst, src) after := Q(r, l.communities, structure.resolution) want := after - before if !scalar.EqualWithinAbsOrRel(dQ, want, structure.tol, structure.tol) { t.Errorf("unexpected deltaQ for %q: got: %v want: %v", test.name, dQ, want) } } } } } func TestModularizeUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } testModularizeUndirected(t, test, g) } } func TestModularizeWeightedUndirected(t *testing.T) { for _, test := range communityUndirectedQTests { g := simple.NewWeightedUndirectedGraph(0, 0) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } testModularizeUndirected(t, test, g) } } func testModularizeUndirected(t *testing.T, test communityUndirectedQTest, g graph.Undirected) { const louvainIterations = 20 if test.structures[0].resolution != 1 { panic("bad test: expect resolution=1") } want := make([][]graph.Node, len(test.structures[0].memberships)) for i, c := range test.structures[0].memberships { for n := range c { want[i] = append(want[i], simple.Node(n)) } ordered.ByID(want[i]) } ordered.BySliceIDs(want) var ( got *ReducedUndirected bestQ = math.Inf(-1) ) // Modularize is randomised so we do this to // ensure the level tests are consistent. src := rand.New(rand.NewSource(1)) for i := 0; i < louvainIterations; i++ { r := Modularize(g, 1, src).(*ReducedUndirected) if q := Q(r, nil, 1); q > bestQ || math.IsNaN(q) { bestQ = q got = r if math.IsNaN(q) { // Don't try again for non-connected case. break } } var qs []float64 for p := r; p != nil; p = p.Expanded().(*ReducedUndirected) { qs = append(qs, Q(p, nil, 1)) } // Recovery of Q values is reversed. if reverse(qs); !sort.Float64sAreSorted(qs) { t.Errorf("Q values not monotonically increasing: %.5v", qs) } } gotCommunities := got.Communities() for _, c := range gotCommunities { ordered.ByID(c) } ordered.BySliceIDs(gotCommunities) if !reflect.DeepEqual(gotCommunities, want) { t.Errorf("unexpected community membership for %s Q=%.4v:\n\tgot: %v\n\twant:%v", test.name, bestQ, gotCommunities, want) return } var levels []level for p := got; p != nil; p = p.Expanded().(*ReducedUndirected) { var communities [][]graph.Node if p.parent != nil { communities = p.parent.Communities() for _, c := range communities { ordered.ByID(c) } ordered.BySliceIDs(communities) } else { communities = reduceUndirected(g, nil).Communities() } q := Q(p, nil, 1) if math.IsNaN(q) { // Use an equalable flag value in place of NaN. q = math.Inf(-1) } levels = append(levels, level{q: q, communities: communities}) } if !reflect.DeepEqual(levels, test.wantLevels) { t.Errorf("unexpected level structure:\n\tgot: %v\n\twant:%v", levels, test.wantLevels) } } func TestNonContiguousUndirected(t *testing.T) { g := simple.NewUndirectedGraph() for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(4), T: simple.Node(5)}, } { g.SetEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() Modularize(g, 1, nil) }() } func TestNonContiguousWeightedUndirected(t *testing.T) { g := simple.NewWeightedUndirectedGraph(0, 0) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(4), T: simple.Node(5), W: 1}, } { g.SetWeightedEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() Modularize(g, 1, nil) }() } func BenchmarkLouvain(b *testing.B) { src := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { Modularize(dupGraph, 1, src) } } golang-gonum-v1-gonum-0.14.0/graph/complement.go000066400000000000000000000054621450372207100214400ustar00rootroot00000000000000// Copyright ©2019 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 // Complement provides the complement of a graph. The complement will not include // self-edges, and edges within the complement will not hold any information other // than the nodes in the original graph and the connection topology. Nodes returned // by the Complement directly or via queries to returned Edges will be those stored // in the original graph. type Complement struct { Graph } // 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 Complement) Edge(uid, vid int64) Edge { if g.Graph.Edge(uid, vid) != nil || uid == vid { return nil } u := g.Node(uid) v := g.Node(vid) if u == nil || v == nil { return nil } return shadow{F: u, T: v} } // From returns all nodes in g that can be reached directly from u in // the complement. func (g Complement) From(uid int64) Nodes { if g.Node(uid) == nil { return Empty } // At this point, we guarantee that g.Graph.From(uid) returns a set of // nodes in g.Nodes(), and that uid corresponds to a node in g.Nodes(). return newNodeFilterIterator(g.Nodes(), g.Graph.From(uid), uid) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g Complement) HasEdgeBetween(xid, yid int64) bool { return xid != yid && g.Node(xid) != nil && g.Node(yid) != nil && !g.Graph.HasEdgeBetween(xid, yid) } // shadow is an edge that is not exposed to the user. type shadow struct{ F, T Node } func (e shadow) From() Node { return e.F } func (e shadow) To() Node { return e.T } func (e shadow) ReversedEdge() Edge { return shadow{F: e.T, T: e.F} } // nodeFilterIterator combines Nodes to produce a single stream of // filtered nodes. type nodeFilterIterator struct { src Nodes // filter indicates the node in n with the key ID should be filtered out. filter map[int64]bool } // newNodeFilterIterator returns a new nodeFilterIterator. The nodes in filter and // the nodes corresponding the root node ID must be in the src set of nodes. This // invariant is not checked. func newNodeFilterIterator(src, filter Nodes, root int64) *nodeFilterIterator { n := nodeFilterIterator{src: src, filter: map[int64]bool{root: true}} for filter.Next() { n.filter[filter.Node().ID()] = true } filter.Reset() n.src.Reset() return &n } func (n *nodeFilterIterator) Len() int { return n.src.Len() - len(n.filter) } func (n *nodeFilterIterator) Next() bool { for n.src.Next() { if !n.filter[n.src.Node().ID()] { return true } } return false } func (n *nodeFilterIterator) Node() Node { return n.src.Node() } func (n *nodeFilterIterator) Reset() { n.src.Reset() } golang-gonum-v1-gonum-0.14.0/graph/complement_test.go000066400000000000000000000046631450372207100225010ustar00rootroot00000000000000// Copyright ©2019 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_test import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) var complementTests = []struct { g graph.Graph }{ {g: gnp(100, 0, rand.NewSource(1))}, {g: gnp(100, 0.05, rand.NewSource(1))}, {g: gnp(100, 0.5, rand.NewSource(1))}, {g: gnp(100, 0.95, rand.NewSource(1))}, {g: gnp(100, 1, rand.NewSource(1))}, } func TestComplement(t *testing.T) { for _, test := range complementTests { n := len(graph.NodesOf(test.g.Nodes())) wantM := n * (n - 1) // Double counting edges, but no self-loops. var gotM int iter := test.g.Nodes() for iter.Next() { id := iter.Node().ID() to := test.g.From(id) for to.Next() { gotM++ } toC := graph.Complement{test.g}.From(id) for toC.Next() { gotM++ } } if gotM != wantM { t.Errorf("unexpected number of edges in sum of input and complement: got:%d want:%d", gotM, wantM) } } } func gnp(n int, p float64, src rand.Source) *simple.UndirectedGraph { g := simple.NewUndirectedGraph() err := gen.Gnp(g, n, p, src) if err != nil { panic(fmt.Sprintf("gnp: bad test: %v", err)) } return g } var nodeFilterIteratorTests = []struct { src, filter graph.Nodes root int64 len int }{ {src: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), filter: graph.Empty, root: 0, len: 0}, {src: iterator.NewOrderedNodes([]graph.Node{simple.Node(0), simple.Node(1)}), filter: graph.Empty, root: 0, len: 1}, {src: iterator.NewOrderedNodes([]graph.Node{simple.Node(0), simple.Node(1), simple.Node(2)}), filter: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), root: 0, len: 1}, } func TestNodeFilterIterator(t *testing.T) { for _, test := range nodeFilterIteratorTests { it := graph.NewNodeFilterIterator(test.src, test.filter, test.root) if it.Len() < 0 { t.Logf("don't test indeterminate iterators: %T", it) continue } for i := 0; i < 2; i++ { n := it.Len() if n != test.len { t.Errorf("unexpected length of iterator construction/reset: got:%d want:%d", n, test.len) } for it.Next() { n-- } if n != 0 { t.Errorf("unexpected remaining nodes after iterator completion: got:%d want:0", n) } it.Reset() } } } golang-gonum-v1-gonum-0.14.0/graph/doc.go000066400000000000000000000006061450372207100200350ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/encoding/000077500000000000000000000000001450372207100205255ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/encoding/digraph6/000077500000000000000000000000001450372207100222315ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/encoding/digraph6/digraph6.go000066400000000000000000000176561450372207100243030ustar00rootroot00000000000000// 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 digraph6 implements graphs specified by digraph6 strings. package digraph6 // import "gonum.org/v1/gonum/graph/encoding/digraph6" import ( "fmt" "math/big" "strings" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) // Graph is a digraph6-represented directed graph. // // See https://users.cecs.anu.edu.au/~bdm/data/formats.txt for details. // // Note that the digraph6 format specifies that the first character of the graph // string is a '&'. This character must be present for use in the digraph6 package. // A Graph without this prefix is treated as the null graph. type Graph string var ( d6 Graph _ graph.Graph = d6 _ graph.Directed = d6 ) // Encode returns a graph6 encoding of the topology of the given graph using a // lexical ordering of the nodes by ID to map them to [0, n). func Encode(g graph.Graph) Graph { nodes := graph.NodesOf(g.Nodes()) n := len(nodes) ordered.ByID(nodes) indexOf := make(map[int64]int, n) for i, n := range nodes { indexOf[n.ID()] = i } size := n * n var b big.Int for i, u := range nodes { it := g.From(u.ID()) for it.Next() { vid := it.Node().ID() j := indexOf[vid] b.SetBit(&b, bitFor(int64(i), int64(j), int64(n)), 1) } } var buf strings.Builder buf.WriteByte('&') // digraph6 specifies graphs of order up to 2^36-1 which // overflows int on 32-bit architectures. We know that on // those machines n will not be this large, since it came // from a length, but explicitly convert to 64 bits to // allow the package to build on those architectures. // // See the section Small nonnegative integers in the spec // for details of this section. switch n := int64(n); { case n < 63: buf.WriteByte(byte(n) + 63) case n < 258048: buf.Write([]byte{126, bit6(n>>12) + 63, bit6(n>>6) + 63, bit6(n) + 63}) case n < 68719476736: buf.Write([]byte{126, 126, bit6(n>>30) + 63, bit6(n>>24) + 63, bit6(n>>18) + 63, bit6(n>>12) + 63, bit6(n>>6) + 63, bit6(n) + 63}) default: panic("digraph6: too large") } var c byte for i := 0; i < size; i++ { bit := i % 6 c |= byte(b.Bit(i)) << uint(5-bit) if bit == 5 { buf.WriteByte(c + 63) c = 0 } } if size%6 != 0 { buf.WriteByte(c + 63) } return Graph(buf.String()) } // bit6 returns only the lower 6 bits of b. func bit6(b int64) byte { return byte(b) & 0x3f } // IsValid returns whether the graph is a valid digraph6 encoding. An invalid Graph // behaves as the null graph. func IsValid(g Graph) bool { n := int(numberOf(g)) if n < 0 { return false } size := (n*n + 5) / 6 // ceil(n^2 / 6) g = g[1:] switch { case g[0] != 126: return len(g[1:]) == size case g[1] != 126: return len(g[4:]) == size default: return len(g[8:]) == size } } // 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. func (g Graph) Edge(uid, vid int64) graph.Edge { if !IsValid(g) { return nil } if !g.HasEdgeFromTo(uid, vid) { return nil } return simple.Edge{F: simple.Node(uid), T: simple.Node(vid)} } // From returns all nodes that can be reached directly from the node with the // given ID. func (g Graph) From(id int64) graph.Nodes { if !IsValid(g) { return graph.Empty } if g.Node(id) == nil { return nil } return &d6ForwardIterator{g: g, from: id, to: -1} } // HasEdgeBetween returns whether an edge exists between nodes with IDs xid // and yid without considering direction. func (g Graph) HasEdgeBetween(xid, yid int64) bool { if !IsValid(g) { return false } return g.HasEdgeFromTo(xid, yid) || g.HasEdgeFromTo(yid, xid) } // HasEdgeFromTo returns whether an edge exists in the graph from u to v with // IDs uid and vid. func (g Graph) HasEdgeFromTo(uid, vid int64) bool { if !IsValid(g) { return false } if uid == vid { return false } n := numberOf(g) if uid < 0 || n <= uid { return false } if vid < 0 || n <= vid { return false } return isSet(bitFor(uid, vid, n), g) } // Node returns the node with the given ID if it exists in the graph, and nil // otherwise. func (g Graph) Node(id int64) graph.Node { if !IsValid(g) { return nil } if id < 0 || numberOf(g) <= id { return nil } return simple.Node(id) } // Nodes returns all the nodes in the graph. func (g Graph) Nodes() graph.Nodes { if !IsValid(g) { return graph.Empty } return iterator.NewImplicitNodes(0, int(numberOf(g)), func(id int) graph.Node { return simple.Node(id) }) } // To returns all nodes that can reach directly to the node with the given ID. func (g Graph) To(id int64) graph.Nodes { if !IsValid(g) || g.Node(id) == nil { return graph.Empty } return &d6ReverseIterator{g: g, from: -1, to: id} } // d6ForwardIterator is a graph.Nodes for digraph6 graph edges for forward hops. type d6ForwardIterator struct { g Graph from int64 to int64 } var _ graph.Nodes = (*d6ForwardIterator)(nil) func (i *d6ForwardIterator) Next() bool { n := numberOf(i.g) for i.to < n-1 { i.to++ if i.to != i.from && isSet(bitFor(i.from, i.to, n), i.g) { return true } } return false } func (i *d6ForwardIterator) Len() int { var cnt int n := numberOf(i.g) for to := i.to; to < n-1; { to++ if to != i.from && isSet(bitFor(i.from, to, n), i.g) { cnt++ } } return cnt } func (i *d6ForwardIterator) Reset() { i.to = -1 } func (i *d6ForwardIterator) Node() graph.Node { return simple.Node(i.to) } // d6ReverseIterator is a graph.Nodes for digraph6 graph edges for reverse hops. type d6ReverseIterator struct { g Graph from int64 to int64 } var _ graph.Nodes = (*d6ReverseIterator)(nil) func (i *d6ReverseIterator) Next() bool { n := numberOf(i.g) for i.from < n-1 { i.from++ if i.to != i.from && isSet(bitFor(i.from, i.to, n), i.g) { return true } } return false } func (i *d6ReverseIterator) Len() int { var cnt int n := numberOf(i.g) for from := i.from; from < n-1; { from++ if from != i.to && isSet(bitFor(from, i.to, n), i.g) { cnt++ } } return cnt } func (i *d6ReverseIterator) Reset() { i.from = -1 } func (i *d6ReverseIterator) Node() graph.Node { return simple.Node(i.from) } // numberOf returns the digraph6-encoded number corresponding to g. func numberOf(g Graph) int64 { if len(g) < 2 { return -1 } if g[0] != '&' { return -1 } g = g[1:] for _, b := range []byte(g) { if b < 63 || 126 < b { return -1 } } if g[0] != 126 { return int64(g[0] - 63) } if len(g) < 4 { return -1 } if g[1] != 126 { return int64(g[1]-63)<<12 | int64(g[2]-63)<<6 | int64(g[3]-63) } if len(g) < 8 { return -1 } return int64(g[2]-63)<<30 | int64(g[3]-63)<<24 | int64(g[4]-63)<<18 | int64(g[5]-63)<<12 | int64(g[6]-63)<<6 | int64(g[7]-63) } // bitFor returns the index into the digraph6 adjacency matrix for uid->vid in a graph // order n. func bitFor(uid, vid, n int64) int { return int(uid*n + vid) } // isSet returns whether the given bit of the adjacency matrix is set. func isSet(bit int, g Graph) bool { g = g[1:] switch { case g[0] != 126: g = g[1:] case g[1] != 126: g = g[4:] default: g = g[8:] } if bit/6 >= len(g) { panic("digraph6: index out of range") } return (g[bit/6]-63)&(1< 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 } golang-gonum-v1-gonum-0.14.0/graph/encoding/dot/decode_test.go000066400000000000000000000361561450372207100241370ustar00rootroot00000000000000// 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" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/simple" ) func TestRoundTrip(t *testing.T) { golden := []struct { want string directed bool }{ { want: directed, directed: true, }, { want: undirected, directed: false, }, { want: directedID, directed: true, }, { want: undirectedID, directed: false, }, { want: directedWithPorts, directed: true, }, { want: undirectedWithPorts, directed: false, }, { want: directedAttrs, directed: true, }, { want: undirectedAttrs, directed: false, }, } for i, g := range golden { var dst encoding.Builder if g.directed { dst = newDotDirectedGraph() } else { dst = newDotUndirectedGraph() } data := []byte(g.want) if err := Unmarshal(data, dst); err != nil { t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err) continue } buf, err := Marshal(dst, "", "", "\t") if err != nil { t.Errorf("i=%d: unable to marshal graph; %v", i, dst) continue } got := string(buf) if got != g.want { t.Errorf("i=%d: graph content mismatch; want:\n%s\n\ngot:\n%s", i, g.want, got) continue } } } const directed = `strict digraph { graph [ outputorder=edgesfirst ]; node [ shape=circle style=filled ]; edge [ penwidth=5 color=gray ]; // Node definitions. A [label="foo 2"]; B [label="bar 2"]; // Edge definitions. A -> B [label="baz 2"]; }` const undirected = `strict graph { graph [ outputorder=edgesfirst ]; node [ shape=circle style=filled ]; edge [ penwidth=5 color=gray ]; // Node definitions. A [label="foo 2"]; B [label="bar 2"]; // Edge definitions. A -- B [label="baz 2"]; }` const directedID = `strict digraph G { // Node definitions. A; B; // Edge definitions. A -> B; }` const undirectedID = `strict graph H { // Node definitions. A; B; // Edge definitions. A -- B; }` const directedWithPorts = `strict digraph { // Node definitions. A; B; C; D; E; F; // Edge definitions. A:foo -> B:bar; A -> C:bar; B:foo -> C; D:foo:n -> E:bar:s; D:e -> F:bar:w; E:_ -> F:c; }` const undirectedWithPorts = `strict graph { // Node definitions. A; B; C; D; E; F; // Edge definitions. A:foo -- B:bar; A -- C:bar; B:foo -- C; D:foo:n -- E:bar:s; D:e -- F:bar:w; E:_ -- F:c; }` const directedAttrs = `strict digraph { node [ shape=circle style=filled label="NODE" ]; edge [ penwidth=5 color=gray label=3.14 ]; // Node definitions. A [label=
]; B [label=-14]; // Edge definitions. A -> B [label="hello world"]; }` const undirectedAttrs = `strict graph { node [ shape=circle style=filled label="NODE" ]; edge [ penwidth=5 color=gray label=3.14 ]; // Node definitions. A [label=
]; B [label=-14]; // Edge definitions. A -- B [label="hello world"]; }` func TestChainedEdgeAttributes(t *testing.T) { golden := []struct { in, want string directed bool }{ { in: directedChained, want: directedNonchained, directed: true, }, { in: undirectedChained, want: undirectedNonchained, directed: false, }, } for i, g := range golden { var dst encoding.Builder if g.directed { dst = newDotDirectedGraph() } else { dst = newDotUndirectedGraph() } data := []byte(g.in) if err := Unmarshal(data, dst); err != nil { t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err) continue } buf, err := Marshal(dst, "", "", "\t") if err != nil { t.Errorf("i=%d: unable to marshal graph; %v", i, dst) continue } got := string(buf) if got != g.want { t.Errorf("i=%d: graph content mismatch; want:\n%s\n\ngot:\n%s", i, g.want, got) continue } } } const directedChained = `strict digraph { graph [ outputorder=edgesfirst ]; node [ shape=circle style=filled ]; edge [ penwidth=5 color=gray ]; // Node definitions. A [label="foo 2"]; B [label="bar 2"]; // Edge definitions. A -> B -> A [label="baz 2"]; }` const directedNonchained = `strict digraph { graph [ outputorder=edgesfirst ]; node [ shape=circle style=filled ]; edge [ penwidth=5 color=gray ]; // Node definitions. A [label="foo 2"]; B [label="bar 2"]; // Edge definitions. A -> B [label="baz 2"]; B -> A [label="baz 2"]; }` const undirectedChained = `graph { graph [ outputorder=edgesfirst ]; node [ shape=circle style=filled ]; edge [ penwidth=5 color=gray ]; // Node definitions. A [label="foo 2"]; B [label="bar 2"]; C [label="bif 2"]; // Edge definitions. A -- B -- C [label="baz 2"]; }` const undirectedNonchained = `strict graph { graph [ outputorder=edgesfirst ]; node [ shape=circle style=filled ]; edge [ penwidth=5 color=gray ]; // Node definitions. A [label="foo 2"]; B [label="bar 2"]; C [label="bif 2"]; // Edge definitions. A -- B [label="baz 2"]; B -- C [label="baz 2"]; }` func TestMultigraphDecoding(t *testing.T) { for i, test := range []struct { directed bool input string expected string }{ { directed: true, input: directedMultigraph, expected: directedMultigraph, }, { directed: false, input: undirectedMultigraph, expected: undirectedMultigraph, }, { directed: true, input: directedSelfLoopMultigraph, expected: directedSelfLoopMultigraph, }, { directed: false, input: undirectedSelfLoopMultigraph, expected: undirectedSelfLoopMultigraph, }, } { var dst encoding.MultiBuilder if test.directed { dst = multi.NewDirectedGraph() } else { dst = multi.NewUndirectedGraph() } if err := UnmarshalMulti([]byte(test.input), dst); err != nil { t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err) continue } buf, err := MarshalMulti(dst, "", "", "\t") if err != nil { t.Errorf("i=%d: unable to marshal graph; %v", i, dst) continue } actual := string(buf) if actual != test.expected { t.Errorf("i=%d: graph content mismatch; want:\n%s\n\nactual:\n%s", i, test.expected, actual) continue } } } func TestMultigraphLineIDsharing(t *testing.T) { for i, test := range []struct { directed bool lines []multi.Line expected string }{ { directed: true, lines: []multi.Line{ {F: multi.Node(0), T: multi.Node(1), UID: 0}, {F: multi.Node(0), T: multi.Node(1), UID: 1}, {F: multi.Node(0), T: multi.Node(2), UID: 0}, {F: multi.Node(2), T: multi.Node(0), UID: 0}, }, expected: directedMultigraph, }, { directed: false, lines: []multi.Line{ {F: multi.Node(0), T: multi.Node(1), UID: 0}, {F: multi.Node(0), T: multi.Node(1), UID: 1}, {F: multi.Node(0), T: multi.Node(2), UID: 0}, {F: multi.Node(0), T: multi.Node(2), UID: 1}, }, expected: undirectedMultigraph, }, { directed: true, lines: []multi.Line{ {F: multi.Node(0), T: multi.Node(0), UID: 0}, {F: multi.Node(0), T: multi.Node(0), UID: 1}, {F: multi.Node(1), T: multi.Node(1), UID: 0}, {F: multi.Node(1), T: multi.Node(1), UID: 1}, }, expected: directedSelfLoopMultigraph, }, { directed: false, lines: []multi.Line{ {F: multi.Node(0), T: multi.Node(0), UID: 0}, {F: multi.Node(0), T: multi.Node(0), UID: 1}, {F: multi.Node(1), T: multi.Node(1), UID: 0}, {F: multi.Node(1), T: multi.Node(1), UID: 1}, }, expected: undirectedSelfLoopMultigraph, }, } { var dst encoding.MultiBuilder if test.directed { dst = multi.NewDirectedGraph() } else { dst = multi.NewUndirectedGraph() } for _, l := range test.lines { dst.SetLine(l) } buf, err := MarshalMulti(dst, "", "", "\t") if err != nil { t.Errorf("i=%d: unable to marshal graph; %v", i, dst) continue } actual := string(buf) if actual != test.expected { t.Errorf("i=%d: graph content mismatch; want:\n%s\n\nactual:\n%s", i, test.expected, actual) continue } } } const directedMultigraph = `digraph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -> 1; 0 -> 1; 0 -> 2; 2 -> 0; }` const undirectedMultigraph = `graph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -- 1; 0 -- 1; 0 -- 2; 0 -- 2; }` const directedSelfLoopMultigraph = `digraph { // Node definitions. 0; 1; // Edge definitions. 0 -> 0; 0 -> 0; 1 -> 1; 1 -> 1; }` const undirectedSelfLoopMultigraph = `graph { // Node definitions. 0; 1; // Edge definitions. 0 -- 0; 0 -- 0; 1 -- 1; 1 -- 1; }` // Below follows a minimal implementation of a graph capable of validating the // round-trip encoding and decoding of DOT graphs with nodes and edges // containing DOT attributes. // dotDirectedGraph extends simple.DirectedGraph to add NewNode and NewEdge // methods for creating user-defined nodes and edges. // // dotDirectedGraph implements the encoding.Builder and the dot.Graph // interfaces. type dotDirectedGraph struct { *simple.DirectedGraph id string graph, node, edge attributes } // newDotDirectedGraph returns a new directed capable of creating user-defined // nodes and edges. func newDotDirectedGraph() *dotDirectedGraph { return &dotDirectedGraph{ DirectedGraph: simple.NewDirectedGraph(), graph: &encoding.Attributes{}, node: &encoding.Attributes{}, edge: &encoding.Attributes{}, } } // NewNode returns a new node with a unique node ID for the graph. func (g *dotDirectedGraph) NewNode() graph.Node { return &dotNode{Node: g.DirectedGraph.NewNode()} } // NewEdge returns a new Edge from the source to the destination node. func (g *dotDirectedGraph) NewEdge(from, to graph.Node) graph.Edge { return &dotEdge{Edge: g.DirectedGraph.NewEdge(from, to)} } // DOTAttributers implements the dot.Attributers interface. func (g *dotDirectedGraph) DOTAttributers() (graph, node, edge encoding.Attributer) { return g.graph, g.node, g.edge } // DOTAttributeSetters implements the dot.AttributeSetters interface. func (g *dotDirectedGraph) DOTAttributeSetters() (graph, node, edge encoding.AttributeSetter) { return g.graph, g.node, g.edge } // SetDOTID sets the DOT ID of the graph. func (g *dotDirectedGraph) SetDOTID(id string) { g.id = id } // DOTID returns the DOT ID of the graph. func (g *dotDirectedGraph) DOTID() string { return g.id } // dotUndirectedGraph extends simple.UndirectedGraph to add NewNode and NewEdge // methods for creating user-defined nodes and edges. // // dotUndirectedGraph implements the encoding.Builder and the dot.Graph // interfaces. type dotUndirectedGraph struct { *simple.UndirectedGraph id string graph, node, edge attributes } // newDotUndirectedGraph returns a new undirected capable of creating user- // defined nodes and edges. func newDotUndirectedGraph() *dotUndirectedGraph { return &dotUndirectedGraph{ UndirectedGraph: simple.NewUndirectedGraph(), graph: &encoding.Attributes{}, node: &encoding.Attributes{}, edge: &encoding.Attributes{}, } } // NewNode adds a new node with a unique node ID to the graph. func (g *dotUndirectedGraph) NewNode() graph.Node { return &dotNode{Node: g.UndirectedGraph.NewNode()} } // NewEdge returns a new Edge from the source to the destination node. func (g *dotUndirectedGraph) NewEdge(from, to graph.Node) graph.Edge { return &dotEdge{Edge: g.UndirectedGraph.NewEdge(from, to)} } // DOTAttributers implements the dot.Attributers interface. func (g *dotUndirectedGraph) DOTAttributers() (graph, node, edge encoding.Attributer) { return g.graph, g.node, g.edge } // DOTUnmarshalerAttrs implements the dot.UnmarshalerAttrs interface. func (g *dotUndirectedGraph) DOTAttributeSetters() (graph, node, edge encoding.AttributeSetter) { return g.graph, g.node, g.edge } // SetDOTID sets the DOT ID of the graph. func (g *dotUndirectedGraph) SetDOTID(id string) { g.id = id } // DOTID returns the DOT ID of the graph. func (g *dotUndirectedGraph) DOTID() string { return g.id } // dotNode extends simple.Node with a label field to test round-trip encoding // and decoding of node DOT label attributes. type dotNode struct { graph.Node dotID string // Node label. Label string } // DOTID returns the node's DOT ID. func (n *dotNode) DOTID() string { return n.dotID } // SetDOTID sets a DOT ID. func (n *dotNode) SetDOTID(id string) { n.dotID = id } // SetAttribute sets a DOT attribute. func (n *dotNode) SetAttribute(attr encoding.Attribute) error { if attr.Key != "label" { return fmt.Errorf("unable to unmarshal node DOT attribute with key %q", attr.Key) } n.Label = attr.Value return nil } // Attributes returns the DOT attributes of the node. func (n *dotNode) Attributes() []encoding.Attribute { if len(n.Label) == 0 { return nil } return []encoding.Attribute{{ Key: "label", Value: n.Label, }} } type dotPortLabels struct { Port, Compass string } // dotEdge extends simple.Edge with a label field to test round-trip encoding and // decoding of edge DOT label attributes. type dotEdge struct { graph.Edge // Edge label. Label string FromPortLabels dotPortLabels ToPortLabels dotPortLabels } // SetAttribute sets a DOT attribute. func (e *dotEdge) SetAttribute(attr encoding.Attribute) error { if attr.Key != "label" { return fmt.Errorf("unable to unmarshal node DOT attribute with key %q", attr.Key) } e.Label = attr.Value return nil } // Attributes returns the DOT attributes of the edge. func (e *dotEdge) Attributes() []encoding.Attribute { if len(e.Label) == 0 { return nil } return []encoding.Attribute{{ Key: "label", Value: e.Label, }} } func (e *dotEdge) SetFromPort(port, compass string) error { e.FromPortLabels.Port = port e.FromPortLabels.Compass = compass return nil } func (e *dotEdge) SetToPort(port, compass string) error { e.ToPortLabels.Port = port e.ToPortLabels.Compass = compass return nil } func (e *dotEdge) FromPort() (port, compass string) { return e.FromPortLabels.Port, e.FromPortLabels.Compass } func (e *dotEdge) ToPort() (port, compass string) { return e.ToPortLabels.Port, e.ToPortLabels.Compass } type attributes interface { encoding.Attributer encoding.AttributeSetter } const undirectedSelfLoopGraph = `graph { // Node definitions. 0; 1; // Edge definitions. 0 -- 0; 1 -- 1; }` const directedSelfLoopGraph = `digraph { // Node definitions. 0; 1; // Edge definitions. 0 -> 0; 1 -> 1; }` func TestSelfLoopSimple(t *testing.T) { for _, test := range []struct { dst func() encoding.Builder src string }{ { dst: func() encoding.Builder { return simple.NewUndirectedGraph() }, src: undirectedSelfLoopGraph, }, { dst: func() encoding.Builder { return simple.NewDirectedGraph() }, src: directedSelfLoopGraph, }, } { dst := test.dst() message, panicked := panics(func() { err := Unmarshal([]byte(test.src), dst) if err == nil { t.Errorf("expected error for self loop addition to %T", dst) } }) if panicked { t.Errorf("unexpected panic for self loop addition to %T: %s", dst, message) } } } func panics(fn func()) (message string, ok bool) { defer func() { r := recover() message = fmt.Sprint(r) ok = r != nil }() fn() return } golang-gonum-v1-gonum-0.14.0/graph/encoding/dot/doc.go000066400000000000000000000016341450372207100224130ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/encoding/dot/encode.go000066400000000000000000000374521450372207100231120ustar00rootroot00000000000000// 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" "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()) 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)) ordered.ByID(to) for _, t := range to { tid := t.ID() f := edge{inGraph: name, from: nid, to: tid} if isDirected { if p.visited[f] { continue } p.visited[f] = true } else { if p.visited[f] { continue } p.visited[f] = true p.visited[edge{inGraph: name, from: tid, to: nid}] = 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} { if a == nil { continue } 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 from int64 to int64 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()) 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)) ordered.ByID(to) for _, t := range to { tid := t.ID() lines := graph.LinesOf(g.Lines(nid, tid)) ordered.LinesByIDs(lines) for _, l := range lines { lid := l.ID() f := line{inGraph: name, from: nid, to: tid, id: lid} if isDirected { if p.visited[f] { continue } p.visited[f] = true } else { if p.visited[f] { continue } p.visited[f] = true p.visited[line{inGraph: name, from: tid, to: nid, 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. ). 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, ">") } golang-gonum-v1-gonum-0.14.0/graph/encoding/dot/encode_test.go000066400000000000000000000670441450372207100241510ustar00rootroot00000000000000// 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" "os/exec" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/simple" ) // intset is an integer set. type intset map[int64]struct{} func linksTo(i ...int64) intset { if len(i) == 0 { return nil } s := make(intset) for _, v := range i { s[v] = struct{}{} } return s } var ( // Example graph from http://en.wikipedia.org/wiki/File:PageRanks-Example.svg 16:17, 8 July 2009 // Node identities are rewritten here to use integers from 0 to match with the DOT output. pageRankGraph = []intset{ 0: nil, 1: linksTo(2), 2: linksTo(1), 3: linksTo(0, 1), 4: linksTo(3, 1, 5), 5: linksTo(1, 4), 6: linksTo(1, 4), 7: linksTo(1, 4), 8: linksTo(1, 4), 9: linksTo(4), 10: linksTo(4), } // Example graph from http://en.wikipedia.org/w/index.php?title=PageRank&oldid=659286279#Power_Method powerMethodGraph = []intset{ 0: linksTo(1, 2), 1: linksTo(3), 2: linksTo(3, 4), 3: linksTo(4), 4: linksTo(0), } ) func directedGraphFrom(g []intset) graph.Directed { dg := simple.NewDirectedGraph() for u, e := range g { for v := range e { dg.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } return dg } func undirectedGraphFrom(g []intset) graph.Graph { dg := simple.NewUndirectedGraph() for u, e := range g { for v := range e { dg.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } return dg } const alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" type namedNode struct { id int64 name string } func (n namedNode) ID() int64 { return n.id } func (n namedNode) DOTID() string { return n.name } func directedNamedIDGraphFrom(g []intset) graph.Directed { dg := simple.NewDirectedGraph() for u, e := range g { u := int64(u) nu := namedNode{id: u, name: alpha[u : u+1]} for v := range e { nv := namedNode{id: v, name: alpha[v : v+1]} dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg } func undirectedNamedIDGraphFrom(g []intset) graph.Graph { dg := simple.NewUndirectedGraph() for u, e := range g { u := int64(u) nu := namedNode{id: u, name: alpha[u : u+1]} for v := range e { nv := namedNode{id: v, name: alpha[v : v+1]} dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg } type attrNode struct { id int64 attr []encoding.Attribute } func (n attrNode) ID() int64 { return n.id } func (n attrNode) Attributes() []encoding.Attribute { return n.attr } func directedNodeAttrGraphFrom(g []intset, attr [][]encoding.Attribute) graph.Directed { dg := simple.NewDirectedGraph() for u, e := range g { u := int64(u) var at []encoding.Attribute if u < int64(len(attr)) { at = attr[u] } nu := attrNode{id: u, attr: at} for v := range e { if v < int64(len(attr)) { at = attr[v] } nv := attrNode{id: v, attr: at} dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg } func undirectedNodeAttrGraphFrom(g []intset, attr [][]encoding.Attribute) graph.Graph { dg := simple.NewUndirectedGraph() for u, e := range g { u := int64(u) var at []encoding.Attribute if u < int64(len(attr)) { at = attr[u] } nu := attrNode{id: u, attr: at} for v := range e { if v < int64(len(attr)) { at = attr[v] } nv := attrNode{id: v, attr: at} dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg } type namedAttrNode struct { id int64 name string attr []encoding.Attribute } func (n namedAttrNode) ID() int64 { return n.id } func (n namedAttrNode) DOTID() string { return n.name } func (n namedAttrNode) Attributes() []encoding.Attribute { return n.attr } func directedNamedIDNodeAttrGraphFrom(g []intset, attr [][]encoding.Attribute) graph.Directed { dg := simple.NewDirectedGraph() for u, e := range g { u := int64(u) var at []encoding.Attribute if u < int64(len(attr)) { at = attr[u] } nu := namedAttrNode{id: u, name: alpha[u : u+1], attr: at} for v := range e { if v < int64(len(attr)) { at = attr[v] } nv := namedAttrNode{id: v, name: alpha[v : v+1], attr: at} dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg } func undirectedNamedIDNodeAttrGraphFrom(g []intset, attr [][]encoding.Attribute) graph.Graph { dg := simple.NewUndirectedGraph() for u, e := range g { u := int64(u) var at []encoding.Attribute if u < int64(len(attr)) { at = attr[u] } nu := namedAttrNode{id: u, name: alpha[u : u+1], attr: at} for v := range e { if v < int64(len(attr)) { at = attr[v] } nv := namedAttrNode{id: v, name: alpha[v : v+1], attr: at} dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg } type attrEdge struct { from, to graph.Node attr []encoding.Attribute } func (e attrEdge) From() graph.Node { return e.from } func (e attrEdge) To() graph.Node { return e.to } func (e attrEdge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from; return e } func (e attrEdge) Weight() float64 { return 0 } func (e attrEdge) Attributes() []encoding.Attribute { return e.attr } func directedEdgeAttrGraphFrom(g []intset, attr map[edge][]encoding.Attribute) graph.Directed { dg := simple.NewDirectedGraph() for u, e := range g { u := int64(u) for v := range e { dg.SetEdge(attrEdge{from: simple.Node(u), to: simple.Node(v), attr: attr[edge{from: u, to: v}]}) } } return dg } func undirectedEdgeAttrGraphFrom(g []intset, attr map[edge][]encoding.Attribute) graph.Graph { dg := simple.NewUndirectedGraph() for u, e := range g { u := int64(u) for v := range e { dg.SetEdge(attrEdge{from: simple.Node(u), to: simple.Node(v), attr: attr[edge{from: u, to: v}]}) } } return dg } type portedEdge struct { from, to graph.Node fromPort string fromCompass string toPort string toCompass string } func (e portedEdge) From() graph.Node { return e.from } func (e portedEdge) To() graph.Node { return e.to } func (e portedEdge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from e.fromPort, e.toPort = e.toPort, e.fromPort e.fromCompass, e.toCompass = e.toCompass, e.fromCompass return e } func (e portedEdge) Weight() float64 { return 0 } func (e portedEdge) FromPort() (port, compass string) { return e.fromPort, e.fromCompass } func (e portedEdge) ToPort() (port, compass string) { return e.toPort, e.toCompass } func directedPortedAttrGraphFrom(g []intset, attr [][]encoding.Attribute, ports map[edge]portedEdge) graph.Directed { dg := simple.NewDirectedGraph() for u, e := range g { u := int64(u) var at []encoding.Attribute if u < int64(len(attr)) { at = attr[u] } nu := attrNode{id: u, attr: at} for v := range e { if v < int64(len(attr)) { at = attr[v] } pe := ports[edge{from: u, to: v}] pe.from = nu pe.to = attrNode{id: v, attr: at} dg.SetEdge(pe) } } return dg } func undirectedPortedAttrGraphFrom(g []intset, attr [][]encoding.Attribute, ports map[edge]portedEdge) graph.Graph { dg := simple.NewUndirectedGraph() for u, e := range g { u := int64(u) var at []encoding.Attribute if u < int64(len(attr)) { at = attr[u] } nu := attrNode{id: u, attr: at} for v := range e { if v < int64(len(attr)) { at = attr[v] } pe := ports[edge{from: u, to: v}] pe.from = nu pe.to = attrNode{id: v, attr: at} dg.SetEdge(pe) } } return dg } type graphAttributer struct { graph.Graph graph encoding.Attributer node encoding.Attributer edge encoding.Attributer } func (g graphAttributer) DOTAttributers() (graph, node, edge encoding.Attributer) { return g.graph, g.node, g.edge } type structuredGraph struct { *simple.UndirectedGraph sub []Graph } func undirectedStructuredGraphFrom(c []edge, g ...[]intset) graph.Graph { s := &structuredGraph{UndirectedGraph: simple.NewUndirectedGraph()} var base int64 for i, sg := range g { sub := simple.NewUndirectedGraph() for u, e := range sg { u := int64(u) for v := range e { ce := simple.Edge{F: simple.Node(u + base), T: simple.Node(v + base)} sub.SetEdge(ce) } } s.sub = append(s.sub, namedGraph{id: int64(i), Graph: sub}) base += int64(len(sg)) } for _, e := range c { s.SetEdge(simple.Edge{F: simple.Node(e.from), T: simple.Node(e.to)}) } return s } func (g structuredGraph) Structure() []Graph { return g.sub } type namedGraph struct { id int64 graph.Graph } func (g namedGraph) DOTID() string { return alpha[g.id : g.id+1] } type subGraph struct { id int64 graph.Graph } func (g subGraph) ID() int64 { return g.id } func (g subGraph) Subgraph() graph.Graph { return namedGraph(g) } func undirectedSubGraphFrom(g []intset, s map[int64][]intset) graph.Graph { var base int64 subs := make(map[int64]subGraph) for i, sg := range s { sub := simple.NewUndirectedGraph() for u, e := range sg { u := int64(u) for v := range e { ce := simple.Edge{F: simple.Node(u + base), T: simple.Node(v + base)} sub.SetEdge(ce) } } subs[i] = subGraph{id: i, Graph: sub} base += int64(len(sg)) } dg := simple.NewUndirectedGraph() for u, e := range g { u := int64(u) var nu graph.Node if sg, ok := subs[u]; ok { sg.id += base nu = sg } else { nu = simple.Node(u + base) } for v := range e { var nv graph.Node if sg, ok := subs[v]; ok { sg.id += base nv = sg } else { nv = simple.Node(v + base) } dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg } var encodeTests = []struct { name string g graph.Graph prefix string want string }{ // Empty graph. { name: "Empty Undirected", g: simple.NewUndirectedGraph(), want: `strict graph "Empty Undirected" { }`, }, { name: "Empty Directed", g: simple.NewDirectedGraph(), want: `strict digraph "Empty Directed" { }`, }, // Basic graph.Graph handling. { name: "PageRank", g: directedGraphFrom(pageRankGraph), want: `strict digraph PageRank { // Node definitions. 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; // Edge definitions. 1 -> 2; 2 -> 1; 3 -> 0; 3 -> 1; 4 -> 1; 4 -> 3; 4 -> 5; 5 -> 1; 5 -> 4; 6 -> 1; 6 -> 4; 7 -> 1; 7 -> 4; 8 -> 1; 8 -> 4; 9 -> 4; 10 -> 4; }`, }, { g: undirectedGraphFrom(pageRankGraph), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; // Edge definitions. 0 -- 3; 1 -- 2; 1 -- 3; 1 -- 4; 1 -- 5; 1 -- 6; 1 -- 7; 1 -- 8; 3 -- 4; 4 -- 5; 4 -- 6; 4 -- 7; 4 -- 8; 4 -- 9; 4 -- 10; }`, }, { g: directedGraphFrom(powerMethodGraph), want: `strict digraph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2; 1 -> 3; 2 -> 3; 2 -> 4; 3 -> 4; 4 -> 0; }`, }, { g: undirectedGraphFrom(powerMethodGraph), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; }`, }, { g: undirectedGraphFrom(powerMethodGraph), prefix: "# ", want: `# strict graph { # // Node definitions. # 0; # 1; # 2; # 3; # 4; # # // Edge definitions. # 0 -- 1; # 0 -- 2; # 0 -- 4; # 1 -- 3; # 2 -- 3; # 2 -- 4; # 3 -- 4; # }`, }, // Names named nodes. { name: "PageRank", g: directedNamedIDGraphFrom(pageRankGraph), want: `strict digraph PageRank { // Node definitions. A; B; C; D; E; F; G; H; I; J; K; // Edge definitions. B -> C; C -> B; D -> A; D -> B; E -> B; E -> D; E -> F; F -> B; F -> E; G -> B; G -> E; H -> B; H -> E; I -> B; I -> E; J -> E; K -> E; }`, }, { g: undirectedNamedIDGraphFrom(pageRankGraph), want: `strict graph { // Node definitions. A; B; C; D; E; F; G; H; I; J; K; // Edge definitions. A -- D; B -- C; B -- D; B -- E; B -- F; B -- G; B -- H; B -- I; D -- E; E -- F; E -- G; E -- H; E -- I; E -- J; E -- K; }`, }, { g: directedNamedIDGraphFrom(powerMethodGraph), want: `strict digraph { // Node definitions. A; B; C; D; E; // Edge definitions. A -> B; A -> C; B -> D; C -> D; C -> E; D -> E; E -> A; }`, }, { g: undirectedNamedIDGraphFrom(powerMethodGraph), want: `strict graph { // Node definitions. A; B; C; D; E; // Edge definitions. A -- B; A -- C; A -- E; B -- D; C -- D; C -- E; D -- E; }`, }, { g: undirectedNamedIDGraphFrom(powerMethodGraph), prefix: "# ", want: `# strict graph { # // Node definitions. # A; # B; # C; # D; # E; # # // Edge definitions. # A -- B; # A -- C; # A -- E; # B -- D; # C -- D; # C -- E; # D -- E; # }`, }, // Handling nodes with attributes. { g: directedNodeAttrGraphFrom(powerMethodGraph, nil), want: `strict digraph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2; 1 -> 3; 2 -> 3; 2 -> 4; 3 -> 4; 4 -> 0; }`, }, { g: undirectedNodeAttrGraphFrom(powerMethodGraph, nil), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; }`, }, { g: directedNodeAttrGraphFrom(powerMethodGraph, [][]encoding.Attribute{ 2: {{Key: "fontsize", Value: "16"}, {Key: "shape", Value: "ellipse"}}, 4: {}, }), want: `strict digraph { // Node definitions. 0; 1; 2 [ fontsize=16 shape=ellipse ]; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2; 1 -> 3; 2 -> 3; 2 -> 4; 3 -> 4; 4 -> 0; }`, }, { g: undirectedNodeAttrGraphFrom(powerMethodGraph, [][]encoding.Attribute{ 2: {{Key: "fontsize", Value: "16"}, {Key: "shape", Value: "ellipse"}}, 4: {}, }), want: `strict graph { // Node definitions. 0; 1; 2 [ fontsize=16 shape=ellipse ]; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; }`, }, { g: directedNamedIDNodeAttrGraphFrom(powerMethodGraph, [][]encoding.Attribute{ 2: {{Key: "fontsize", Value: "16"}, {Key: "shape", Value: "ellipse"}}, 4: {}, }), want: `strict digraph { // Node definitions. A; B; C [ fontsize=16 shape=ellipse ]; D; E; // Edge definitions. A -> B; A -> C; B -> D; C -> D; C -> E; D -> E; E -> A; }`, }, { g: undirectedNamedIDNodeAttrGraphFrom(powerMethodGraph, [][]encoding.Attribute{ 0: nil, 1: nil, 2: {{Key: "fontsize", Value: "16"}, {Key: "shape", Value: "ellipse"}}, 3: nil, 4: {}, }), want: `strict graph { // Node definitions. A; B; C [ fontsize=16 shape=ellipse ]; D; E; // Edge definitions. A -- B; A -- C; A -- E; B -- D; C -- D; C -- E; D -- E; }`, }, // Handling edge with attributes. { g: directedEdgeAttrGraphFrom(powerMethodGraph, nil), want: `strict digraph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2; 1 -> 3; 2 -> 3; 2 -> 4; 3 -> 4; 4 -> 0; }`, }, { g: undirectedEdgeAttrGraphFrom(powerMethodGraph, nil), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; }`, }, { g: directedEdgeAttrGraphFrom(powerMethodGraph, map[edge][]encoding.Attribute{ {from: 0, to: 2}: {{Key: "label", Value: `"???"`}, {Key: "style", Value: "dashed"}}, {from: 2, to: 4}: {}, {from: 3, to: 4}: {{Key: "color", Value: "red"}}, }), want: `strict digraph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2 [ label="???" style=dashed ]; 1 -> 3; 2 -> 3; 2 -> 4; 3 -> 4 [color=red]; 4 -> 0; }`, }, { g: undirectedEdgeAttrGraphFrom(powerMethodGraph, map[edge][]encoding.Attribute{ {from: 0, to: 2}: {{Key: "label", Value: `"???"`}, {Key: "style", Value: "dashed"}}, {from: 2, to: 4}: {}, {from: 3, to: 4}: {{Key: "color", Value: "red"}}, }), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2 [ label="???" style=dashed ]; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4 [color=red]; }`, }, { g: undirectedEdgeAttrGraphFrom(powerMethodGraph, map[edge][]encoding.Attribute{ // label attribute not quoted and containing spaces. {from: 0, to: 2}: {{Key: "label", Value: `hello world`}, {Key: "style", Value: "dashed"}}, {from: 2, to: 4}: {}, {from: 3, to: 4}: {{Key: "label", Value: `foo bar`}}, }), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2 [ label="hello world" style=dashed ]; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4 [label="foo bar"]; }`, }, { g: undirectedEdgeAttrGraphFrom(powerMethodGraph, map[edge][]encoding.Attribute{ // keywords must be quoted if used as attributes. {from: 0, to: 2}: {{Key: "label", Value: `NODE`}, {Key: "style", Value: "dashed"}}, {from: 2, to: 4}: {}, {from: 3, to: 4}: {{Key: "label", Value: `subgraph`}}, }), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2 [ label="NODE" style=dashed ]; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4 [label="subgraph"]; }`, }, // Handling nodes with ports. { g: directedPortedAttrGraphFrom(powerMethodGraph, nil, nil), want: `strict digraph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2; 1 -> 3; 2 -> 3; 2 -> 4; 3 -> 4; 4 -> 0; }`, }, { g: undirectedPortedAttrGraphFrom(powerMethodGraph, nil, nil), want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; }`, }, { g: directedPortedAttrGraphFrom(powerMethodGraph, [][]encoding.Attribute{ 2: {{Key: "shape", Value: "record"}, {Key: "label", Value: `"English|German"`}}, 4: {{Key: "shape", Value: "record"}, {Key: "label", Value: `"English|German"`}}, }, map[edge]portedEdge{ {from: 0, to: 1}: {fromCompass: "s"}, {from: 0, to: 2}: {fromCompass: "s", toPort: "Zwei", toCompass: "e"}, {from: 2, to: 3}: {fromPort: "Zwei", fromCompass: "e"}, {from: 2, to: 4}: {fromPort: "Two", fromCompass: "w", toPort: "Four", toCompass: "w"}, {from: 3, to: 4}: {toPort: "Four", toCompass: "w"}, {from: 4, to: 0}: {fromPort: "Four", fromCompass: "_", toCompass: "s"}, }, ), want: `strict digraph { // Node definitions. 0; 1; 2 [ shape=record label="English|German" ]; 3; 4 [ shape=record label="English|German" ]; // Edge definitions. 0:s -> 1; 0:s -> 2:Zwei:e; 1 -> 3; 2:Zwei:e -> 3; 2:Two:w -> 4:Four:w; 3 -> 4:Four:w; 4:Four:_ -> 0:s; }`, }, { g: undirectedPortedAttrGraphFrom(powerMethodGraph, [][]encoding.Attribute{ 2: {{Key: "shape", Value: "record"}, {Key: "label", Value: `"English|German"`}}, 4: {{Key: "shape", Value: "record"}, {Key: "label", Value: `"English|German"`}}, }, map[edge]portedEdge{ {from: 0, to: 1}: {fromCompass: "s"}, {from: 0, to: 2}: {fromCompass: "s", toPort: "Zwei", toCompass: "e"}, {from: 2, to: 3}: {fromPort: "Zwei", fromCompass: "e"}, {from: 2, to: 4}: {fromPort: "Two", fromCompass: "w", toPort: "Four", toCompass: "w"}, {from: 3, to: 4}: {toPort: "Four", toCompass: "w"}, {from: 4, to: 0}: {fromPort: "Four", fromCompass: "_", toCompass: "s"}, }, ), want: `strict graph { // Node definitions. 0; 1; 2 [ shape=record label="English|German" ]; 3; 4 [ shape=record label="English|German" ]; // Edge definitions. 0:s -- 1; 0:s -- 2:Zwei:e; 0:s -- 4:Four:_; 1 -- 3; 2:Zwei:e -- 3; 2:Two:w -- 4:Four:w; 3 -- 4:Four:w; }`, }, // Handling graph attributes. { g: graphAttributer{ Graph: undirectedEdgeAttrGraphFrom(powerMethodGraph, map[edge][]encoding.Attribute{ {from: 0, to: 2}: {{Key: "label", Value: `"???"`}, {Key: "style", Value: "dashed"}}, {from: 2, to: 4}: {}, {from: 3, to: 4}: {{Key: "color", Value: "red"}}, }), graph: nil, node: nil, edge: nil, }, want: `strict graph { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2 [ label="???" style=dashed ]; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4 [color=red]; }`, }, { g: graphAttributer{ Graph: undirectedEdgeAttrGraphFrom(powerMethodGraph, map[edge][]encoding.Attribute{ {from: 0, to: 2}: {{Key: "label", Value: `"???"`}, {Key: "style", Value: "dashed"}}, {from: 2, to: 4}: {}, {from: 3, to: 4}: {{Key: "color", Value: "red"}}, }), graph: &encoding.Attributes{{Key: "rankdir", Value: `"LR"`}}, node: &encoding.Attributes{{Key: "fontsize", Value: "16"}, {Key: "shape", Value: "ellipse"}}, edge: nil, }, want: `strict graph { graph [ rankdir="LR" ]; node [ fontsize=16 shape=ellipse ]; // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2 [ label="???" style=dashed ]; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4 [color=red]; }`, }, // Handling structured graphs. { g: undirectedStructuredGraphFrom(nil, powerMethodGraph, pageRankGraph), want: `strict graph { subgraph A { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; } subgraph B { // Node definitions. 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; // Edge definitions. 5 -- 8; 6 -- 7; 6 -- 8; 6 -- 9; 6 -- 10; 6 -- 11; 6 -- 12; 6 -- 13; 8 -- 9; 9 -- 10; 9 -- 11; 9 -- 12; 9 -- 13; 9 -- 14; 9 -- 15; } }`, }, { g: undirectedStructuredGraphFrom([]edge{{from: 0, to: 9}}, powerMethodGraph, pageRankGraph), want: `strict graph { subgraph A { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; } subgraph B { // Node definitions. 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; // Edge definitions. 5 -- 8; 6 -- 7; 6 -- 8; 6 -- 9; 6 -- 10; 6 -- 11; 6 -- 12; 6 -- 13; 8 -- 9; 9 -- 10; 9 -- 11; 9 -- 12; 9 -- 13; 9 -- 14; 9 -- 15; } // Node definitions. 0; 9; // Edge definitions. 0 -- 9; }`, }, // Handling subgraphs. { g: undirectedSubGraphFrom(pageRankGraph, map[int64][]intset{2: powerMethodGraph}), want: `strict graph { // Node definitions. 5; 6; 8; 9; 10; 11; 12; 13; 14; 15; // Edge definitions. 5 -- 8; 6 -- subgraph H { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; }; 6 -- 8; 6 -- 9; 6 -- 10; 6 -- 11; 6 -- 12; 6 -- 13; 8 -- 9; 9 -- 10; 9 -- 11; 9 -- 12; 9 -- 13; 9 -- 14; 9 -- 15; }`, }, { name: "H", g: undirectedSubGraphFrom(pageRankGraph, map[int64][]intset{1: powerMethodGraph}), want: `strict graph H { // Node definitions. 5; 7; 8; 9; 10; 11; 12; 13; 14; 15; // Edge definitions. 5 -- 8; subgraph G { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 4; 1 -- 3; 2 -- 3; 2 -- 4; 3 -- 4; } -- 7; subgraph G { // Node definitions. 0; 1; 2; 3; 4; } -- 8; subgraph G { // Node definitions. 0; 1; 2; 3; 4; } -- 9; subgraph G { // Node definitions. 0; 1; 2; 3; 4; } -- 10; subgraph G { // Node definitions. 0; 1; 2; 3; 4; } -- 11; subgraph G { // Node definitions. 0; 1; 2; 3; 4; } -- 12; subgraph G { // Node definitions. 0; 1; 2; 3; 4; } -- 13; 8 -- 9; 9 -- 10; 9 -- 11; 9 -- 12; 9 -- 13; 9 -- 14; 9 -- 15; }`, }, } func TestEncode(t *testing.T) { for i, test := range encodeTests { got, err := Marshal(test.g, test.name, test.prefix, "\t") if err != nil { t.Errorf("unexpected error: %v", err) continue } if string(got) != test.want { t.Errorf("unexpected DOT result for test %d:\ngot: %s\nwant:%s", i, got, test.want) } checkDOT(t, got) } } type intlist []int64 func createMultigraph(g []intlist) graph.Multigraph { dg := multi.NewUndirectedGraph() for u, e := range g { u := int64(u) nu := multi.Node(u) for _, v := range e { nv := multi.Node(v) dg.SetLine(dg.NewLine(nu, nv)) } } return dg } func createNamedMultigraph(g []intlist) graph.Multigraph { dg := multi.NewUndirectedGraph() for u, e := range g { u := int64(u) nu := namedNode{id: u, name: alpha[u : u+1]} for _, v := range e { nv := namedNode{id: v, name: alpha[v : v+1]} dg.SetLine(dg.NewLine(nu, nv)) } } return dg } func createDirectedMultigraph(g []intlist) graph.Multigraph { dg := multi.NewDirectedGraph() for u, e := range g { u := int64(u) nu := multi.Node(u) for _, v := range e { nv := multi.Node(v) dg.SetLine(dg.NewLine(nu, nv)) } } return dg } func createNamedDirectedMultigraph(g []intlist) graph.Multigraph { dg := multi.NewDirectedGraph() for u, e := range g { u := int64(u) nu := namedNode{id: u, name: alpha[u : u+1]} for _, v := range e { nv := namedNode{id: v, name: alpha[v : v+1]} dg.SetLine(dg.NewLine(nu, nv)) } } return dg } var encodeMultiTests = []struct { name string g graph.Multigraph prefix string want string }{ { g: createMultigraph([]intlist{}), want: `graph { }`, }, { g: createMultigraph([]intlist{ 0: {1}, 1: {0, 2}, 2: {}, }), want: `graph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -- 1; 0 -- 1; 1 -- 2; }`, }, { g: createMultigraph([]intlist{ 0: {1}, 1: {2, 2}, 2: {0, 0, 0}, }), want: `graph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 2; 0 -- 2; 1 -- 2; 1 -- 2; }`, }, { g: createNamedMultigraph([]intlist{ 0: {1}, 1: {2, 2}, 2: {0, 0, 0}, }), want: `graph { // Node definitions. A; B; C; // Edge definitions. A -- B; A -- C; A -- C; A -- C; B -- C; B -- C; }`, }, { g: createMultigraph([]intlist{ 0: {2, 1, 0}, 1: {2, 1, 0}, 2: {2, 1, 0}, }), want: `graph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -- 0; 0 -- 1; 0 -- 1; 0 -- 2; 0 -- 2; 1 -- 1; 1 -- 2; 1 -- 2; 2 -- 2; }`, }, { g: createDirectedMultigraph([]intlist{}), want: `digraph { }`, }, { g: createDirectedMultigraph([]intlist{ 0: {1}, 1: {0, 2}, 2: {}, }), want: `digraph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -> 1; 1 -> 0; 1 -> 2; }`, }, { g: createDirectedMultigraph([]intlist{ 0: {1}, 1: {2, 2}, 2: {0, 0, 0}, }), want: `digraph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -> 1; 1 -> 2; 1 -> 2; 2 -> 0; 2 -> 0; 2 -> 0; }`, }, { g: createNamedDirectedMultigraph([]intlist{ 0: {1}, 1: {2, 2}, 2: {0, 0, 0}, }), want: `digraph { // Node definitions. A; B; C; // Edge definitions. A -> B; B -> C; B -> C; C -> A; C -> A; C -> A; }`, }, { g: createDirectedMultigraph([]intlist{ 0: {2, 1, 0}, 1: {2, 1, 0}, 2: {2, 1, 0}, }), want: `digraph { // Node definitions. 0; 1; 2; // Edge definitions. 0 -> 0; 0 -> 1; 0 -> 2; 1 -> 0; 1 -> 1; 1 -> 2; 2 -> 0; 2 -> 1; 2 -> 2; }`, }, } func TestEncodeMulti(t *testing.T) { for i, test := range encodeMultiTests { got, err := MarshalMulti(test.g, test.name, test.prefix, "\t") if err != nil { t.Errorf("unexpected error: %v", err) continue } if string(got) != test.want { t.Errorf("unexpected DOT result for test %d:\ngot: %s\nwant:%s", i, got, test.want) } checkDOT(t, got) } } // checkDOT hands b to the dot executable if it exists and fails t if dot // returns an error. func checkDOT(t *testing.T, b []byte) { dot, err := exec.LookPath("dot") if err != nil { t.Logf("skipping DOT syntax check: %v", err) return } cmd := exec.Command(dot) cmd.Stdin = bytes.NewReader(b) stderr := &bytes.Buffer{} cmd.Stderr = stderr err = cmd.Run() if err != nil { t.Errorf("invalid DOT syntax: %v\n%s\ninput:\n%s", err, stderr.String(), b) } } golang-gonum-v1-gonum-0.14.0/graph/encoding/dot/example_test.go000066400000000000000000000020351450372207100243340ustar00rootroot00000000000000// 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 dot_test import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/simple" ) type edgeWithPorts struct { simple.Edge fromPort, toPort string } func (e edgeWithPorts) ReversedEdge() graph.Edge { e.F, e.T = e.T, e.F e.fromPort, e.toPort = e.toPort, e.fromPort return e } func (e edgeWithPorts) FromPort() (string, string) { return e.fromPort, "" } func (e edgeWithPorts) ToPort() (string, string) { return e.toPort, "" } func ExamplePorter() { g := simple.NewUndirectedGraph() g.SetEdge(edgeWithPorts{ Edge: simple.Edge{F: simple.Node(1), T: simple.Node(0)}, fromPort: "p1", toPort: "p2", }) result, _ := dot.Marshal(g, "", "", " ") fmt.Print(string(result)) // Output: // strict graph { // // Node definitions. // 0; // 1; // // // Edge definitions. // 0:p2 -- 1:p1; // } } golang-gonum-v1-gonum-0.14.0/graph/encoding/dot/weighted_example_test.go000066400000000000000000000042661450372207100262240ustar00rootroot00000000000000// Copyright ©2019 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_test import ( "fmt" "log" "math" "strconv" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/simple" ) // dotGraph provides a shim for interaction between the DOT // unmarshaler and a simple.WeightedUndirectedGraph. type dotGraph struct { *simple.WeightedUndirectedGraph } func newDotGraph() *dotGraph { return &dotGraph{WeightedUndirectedGraph: simple.NewWeightedUndirectedGraph(0, 0)} } // NewEdge returns a DOT-aware edge. func (g *dotGraph) NewEdge(from, to graph.Node) graph.Edge { e := g.WeightedUndirectedGraph.NewWeightedEdge(from, to, math.NaN()).(simple.WeightedEdge) return &weightedEdge{WeightedEdge: e} } // NewNode returns a DOT-aware node. func (g *dotGraph) NewNode() graph.Node { return &node{Node: g.WeightedUndirectedGraph.NewNode()} } // SetEdge is a shim to allow the DOT unmarshaler to // add weighted edges to a graph. func (g *dotGraph) SetEdge(e graph.Edge) { g.WeightedUndirectedGraph.SetWeightedEdge(e.(*weightedEdge)) } // weightedEdge is a DOT-aware weighted edge. type weightedEdge struct { simple.WeightedEdge } // SetAttribute sets the weight of the receiver. func (e *weightedEdge) SetAttribute(attr encoding.Attribute) error { if attr.Key != "weight" { return fmt.Errorf("unable to unmarshal node DOT attribute with key %q", attr.Key) } var err error e.W, err = strconv.ParseFloat(attr.Value, 64) return err } // node is a DOT-aware node. type node struct { graph.Node dotID string } // SetDOTID sets the DOT ID of the node. func (n *node) SetDOTID(id string) { n.dotID = id } func (n *node) String() string { return n.dotID } const ug = ` graph { a b c a--b ["weight"=0.5] a--c ["weight"=1] } ` func ExampleUnmarshal_weighted() { dst := newDotGraph() err := dot.Unmarshal([]byte(ug), dst) if err != nil { log.Fatal(err) } for _, e := range graph.EdgesOf(dst.Edges()) { fmt.Printf("%+v\n", e.(*weightedEdge).WeightedEdge) } // Unordered output: // {F:a T:b W:0.5} // {F:a T:c W:1} } golang-gonum-v1-gonum-0.14.0/graph/encoding/encoding.go000066400000000000000000000033571450372207100226520ustar00rootroot00000000000000// 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 } // Attributes is a helper type providing simple attribute handling. type Attributes []Attribute // Attributes returns all of the receiver's attributes. func (a *Attributes) Attributes() []Attribute { return *a } // SetAttribute sets attr in the receiver. Calling SetAttribute with an // Attribute with a Key that is in the collection replaces the existing // value and calling with an empty Value removes the attribute from the // collection if it exists. SetAttribute always returns nil. func (a *Attributes) SetAttribute(attr Attribute) error { if attr.Key == "" { return nil } for i, v := range *a { if v.Key == attr.Key { if attr.Value == "" { (*a)[i] = (*a)[len(*a)-1] *a = (*a)[:len(*a)-1] return nil } (*a)[i].Value = attr.Value return nil } } if attr.Value != "" { *a = append(*a, attr) } return nil } golang-gonum-v1-gonum-0.14.0/graph/encoding/encoding_test.go000066400000000000000000000065621450372207100237120ustar00rootroot00000000000000// Copyright ©2021 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 ( "sort" "testing" ) var setAttributesTests = []struct { attr *Attributes opName string op func(AttributeSetter) error want *Attributes }{ { attr: &Attributes{}, opName: "noop", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "", Value: "bar"}) }, want: &Attributes{}, }, { attr: &Attributes{}, opName: "add attr to empty", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "foo", Value: "bar"}) }, want: &Attributes{{Key: "foo", Value: "bar"}}, }, { attr: &Attributes{}, opName: "remove attr from empty", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "foo", Value: ""}) }, want: &Attributes{}, }, { attr: &Attributes{{Key: "foo", Value: "bar"}}, opName: "add attr to non-empty", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "bif", Value: "fud"}) }, want: &Attributes{{Key: "foo", Value: "bar"}, {Key: "bif", Value: "fud"}}, }, { attr: &Attributes{{Key: "foo", Value: "bar"}}, opName: "remove attr from singleton", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "foo", Value: ""}) }, want: &Attributes{}, }, { attr: &Attributes{{Key: "foo", Value: "bar"}, {Key: "bif", Value: "fud"}}, opName: "remove first attr from pair", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "foo", Value: ""}) }, want: &Attributes{{Key: "bif", Value: "fud"}}, }, { attr: &Attributes{{Key: "foo", Value: "bar"}, {Key: "bif", Value: "fud"}}, opName: "remove second attr from pair", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "bif", Value: ""}) }, want: &Attributes{{Key: "foo", Value: "bar"}}, }, { attr: &Attributes{{Key: "foo", Value: "bar"}, {Key: "bif", Value: "fud"}}, opName: "replace first attr in pair", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "foo", Value: "not bar"}) }, want: &Attributes{{Key: "foo", Value: "not bar"}, {Key: "bif", Value: "fud"}}, }, { attr: &Attributes{{Key: "foo", Value: "bar"}, {Key: "bif", Value: "fud"}}, opName: "replace second attr in pair", op: func(a AttributeSetter) error { return a.SetAttribute(Attribute{Key: "bif", Value: "not fud"}) }, want: &Attributes{{Key: "foo", Value: "bar"}, {Key: "bif", Value: "not fud"}}, }, } func TestSetAttributes(t *testing.T) { for _, test := range setAttributesTests { err := test.op(test.attr) if err != nil { t.Errorf("unexpected error for %q: %v", test.opName, err) continue } if !sameAttributes(test.attr, test.want) { t.Errorf("unexpected result from %q:\ngot: %+v\nwant:%+v", test.opName, test.attr, test.want) } } } func sameAttributes(a, b Attributer) bool { aAttr := a.Attributes() bAttr := b.Attributes() if len(aAttr) != len(bAttr) { return false } aAttr = append(aAttr[:0:0], aAttr...) sort.Slice(aAttr, func(i, j int) bool { return aAttr[i].Key < aAttr[j].Key }) bAttr = append(bAttr[:0:0], bAttr...) sort.Slice(bAttr, func(i, j int) bool { return bAttr[i].Key < bAttr[j].Key }) for i, a := range aAttr { if bAttr[i] != a { return false } } return true } golang-gonum-v1-gonum-0.14.0/graph/encoding/graph6/000077500000000000000000000000001450372207100217145ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/encoding/graph6/graph6.go000066400000000000000000000151731450372207100234410ustar00rootroot00000000000000// 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 graph6 implements graphs specified by graph6 strings. package graph6 // import "gonum.org/v1/gonum/graph/encoding/graph6" import ( "fmt" "math/big" "strings" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) // Graph is a graph6-represented undirected graph. // // See https://users.cecs.anu.edu.au/~bdm/data/formats.txt for details // and https://hog.grinvin.org/ for a source of interesting graphs in graph6 // format. type Graph string var ( g6 Graph _ graph.Graph = g6 _ graph.Undirected = g6 ) // Encode returns a graph6 encoding of the topology of the given graph using a // lexical ordering of the nodes by ID to map them to [0, n). func Encode(g graph.Graph) Graph { nodes := graph.NodesOf(g.Nodes()) n := len(nodes) ordered.ByID(nodes) indexOf := make(map[int64]int, n) for i, n := range nodes { indexOf[n.ID()] = i } size := (n*n - n) / 2 var b big.Int for i, u := range nodes { uid := u.ID() it := g.From(uid) for it.Next() { vid := it.Node().ID() if vid < uid { continue } j := indexOf[vid] b.SetBit(&b, bitFor(int64(i), int64(j)), 1) } } var buf strings.Builder // graph6 specifies graphs of order up to 2^36-1 which // overflows int on 32-bit architectures. We know that on // those machines n will not be this large, since it came // from a length, but explicitly convert to 64 bits to // allow the package to build on those architectures. // // See the section Small nonnegative integers in the spec // for details of this section. switch n := int64(n); { case n < 63: buf.WriteByte(byte(n) + 63) case n < 258048: buf.Write([]byte{126, bit6(n>>12) + 63, bit6(n>>6) + 63, bit6(n) + 63}) case n < 68719476736: buf.Write([]byte{126, 126, bit6(n>>30) + 63, bit6(n>>24) + 63, bit6(n>>18) + 63, bit6(n>>12) + 63, bit6(n>>6) + 63, bit6(n) + 63}) default: panic("graph6: too large") } var c byte for i := 0; i < size; i++ { bit := i % 6 c |= byte(b.Bit(i)) << uint(5-bit) if bit == 5 { buf.WriteByte(c + 63) c = 0 } } if size%6 != 0 { buf.WriteByte(c + 63) } return Graph(buf.String()) } // bit6 returns only the lower 6 bits of b. func bit6(b int64) byte { return byte(b) & 0x3f } // IsValid returns whether the graph is a valid graph6 encoding. An invalid Graph // behaves as the null graph. func IsValid(g Graph) bool { n := int(numberOf(g)) if n < 0 { return false } size := ((n*n-n)/2 + 5) / 6 // ceil(((n*n-n)/2) / 6) switch { case g[0] != 126: return len(g[1:]) == size case g[1] != 126: return len(g[4:]) == size default: return len(g[8:]) == size } } // 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. func (g Graph) Edge(uid, vid int64) graph.Edge { if !IsValid(g) { return nil } if !g.HasEdgeBetween(uid, vid) { return nil } return simple.Edge{F: simple.Node(uid), T: simple.Node(vid)} } // EdgeBetween returns the edge between nodes x and y with IDs xid and yid. func (g Graph) EdgeBetween(xid, yid int64) graph.Edge { return g.Edge(xid, yid) } // From returns all nodes that can be reached directly from the node with the // given ID. func (g Graph) From(id int64) graph.Nodes { if !IsValid(g) { return graph.Empty } if g.Node(id) == nil { return nil } return &g6Iterator{g: g, from: id, to: -1} } // HasEdgeBetween returns whether an edge exists between nodes with IDs xid // and yid without considering direction. func (g Graph) HasEdgeBetween(xid, yid int64) bool { if !IsValid(g) { return false } if xid == yid { return false } if xid < 0 || numberOf(g) <= xid { return false } if yid < 0 || numberOf(g) <= yid { return false } return isSet(bitFor(xid, yid), g) } // Node returns the node with the given ID if it exists in the graph, and nil // otherwise. func (g Graph) Node(id int64) graph.Node { if !IsValid(g) { return nil } if id < 0 || numberOf(g) <= id { return nil } return simple.Node(id) } // Nodes returns all the nodes in the graph. func (g Graph) Nodes() graph.Nodes { if !IsValid(g) { return graph.Empty } return iterator.NewImplicitNodes(0, int(numberOf(g)), func(id int) graph.Node { return simple.Node(id) }) } // g6Iterator is a graph.Nodes for graph6 graph edges. type g6Iterator struct { g Graph from int64 to int64 } var _ graph.Nodes = (*g6Iterator)(nil) func (i *g6Iterator) Next() bool { n := numberOf(i.g) for i.to < n-1 { i.to++ if i.to != i.from && isSet(bitFor(i.from, i.to), i.g) { return true } } return false } func (i *g6Iterator) Len() int { var cnt int n := numberOf(i.g) for to := i.to; to < n-1; { to++ if to != i.from && isSet(bitFor(i.from, to), i.g) { cnt++ } } return cnt } func (i *g6Iterator) Reset() { i.to = -1 } func (i *g6Iterator) Node() graph.Node { return simple.Node(i.to) } // numberOf returns the graph6-encoded number corresponding to g. func numberOf(g Graph) int64 { if len(g) < 1 { return -1 } for _, b := range []byte(g) { if b < 63 || 126 < b { return -1 } } if g[0] != 126 { return int64(g[0] - 63) } if len(g) < 4 { return -1 } if g[1] != 126 { return int64(g[1]-63)<<12 | int64(g[2]-63)<<6 | int64(g[3]-63) } if len(g) < 8 { return -1 } return int64(g[2]-63)<<30 | int64(g[3]-63)<<24 | int64(g[4]-63)<<18 | int64(g[5]-63)<<12 | int64(g[6]-63)<<6 | int64(g[7]-63) } // bitFor returns the index into the graph6 adjacency matrix for xid--yid. func bitFor(xid, yid int64) int { if xid < yid { xid, yid = yid, xid } return int((xid*xid-xid)/2 + yid) } // isSet returns whether the given bit of the adjacency matrix is set. func isSet(bit int, g Graph) bool { switch { case g[0] != 126: g = g[1:] case g[1] != 126: g = g[4:] default: g = g[8:] } if bit/6 >= len(g) { panic("g6: index out of range") } return (g[bit/6]-63)&(1< "0x0312de17a7ee89f9" [label=starring]; "0xa3cff1a4c3ef3bb6" -> "0x3da8d1dcab1bb381" [label=starring]; "0xa3cff1a4c3ef3bb6" -> "0x4a7d0b5fe91e78a4" [label=director]; "0xa3cff1a4c3ef3bb6" -> "0x718337b9dcbaa7d9" [label=starring]; "0xb39aa14d66aedad5" -> "0x8a10d5a2611fd03f" [label=director]; "0xb39aa14d66aedad5" -> "0x0312de17a7ee89f9" [label=starring]; "0xb39aa14d66aedad5" -> "0x3da8d1dcab1bb381" [label=starring]; "0xb39aa14d66aedad5" -> "0x718337b9dcbaa7d9" [label=starring]; }`, }, { name: "tutorial", json: dgraphTutorial, roots: map[uint64]bool{ 0xfd90205a458151f: true, 0x52a80955d40ec819: true, }, wantDOT: `strict digraph { // Node definitions. "0x892a6da7ee1fbdec" [ age=55 name=Sarah ]; "0x99b74c1b5ab100ec" [ age=35 name=Artyom ]; "0xb9e12a67e34d6acc" [ age=19 name=Catalina ]; "0xbf104824c777525d" [name=Perro]; "0xf590a923ea1fccaa" [name=Goldie]; "0xf92d7dbe272d680b" [name="Hyung Sin"]; "0x0fd90205a458151f" [ age=39 name=Michael ]; "0x37734fcf0a6fcc69" [name="Rammy the sheep"]; "0x52a80955d40ec819" [ age=35 name=Amit ]; "0x5e9ad1cd9466228c" [ age=24 name="Sang Hyun" ]; // Edge definitions. "0xb9e12a67e34d6acc" -> "0xbf104824c777525d" [label=owns_pet]; "0xb9e12a67e34d6acc" -> "0x5e9ad1cd9466228c" [label=friend]; "0xf92d7dbe272d680b" -> "0x5e9ad1cd9466228c" [label=friend]; "0x0fd90205a458151f" -> "0x892a6da7ee1fbdec" [label=friend]; "0x0fd90205a458151f" -> "0x99b74c1b5ab100ec" [label=friend]; "0x0fd90205a458151f" -> "0xb9e12a67e34d6acc" [label=friend]; "0x0fd90205a458151f" -> "0x37734fcf0a6fcc69" [label=owns_pet]; "0x0fd90205a458151f" -> "0x52a80955d40ec819" [label=friend]; "0x0fd90205a458151f" -> "0x5e9ad1cd9466228c" [label=friend]; "0x52a80955d40ec819" -> "0x99b74c1b5ab100ec" [label=friend]; "0x52a80955d40ec819" -> "0x0fd90205a458151f" [label=friend]; "0x52a80955d40ec819" -> "0x5e9ad1cd9466228c" [label=friend]; "0x5e9ad1cd9466228c" -> "0xb9e12a67e34d6acc" [label=friend]; "0x5e9ad1cd9466228c" -> "0xf590a923ea1fccaa" [label=owns_pet]; "0x5e9ad1cd9466228c" -> "0xf92d7dbe272d680b" [label=friend]; "0x5e9ad1cd9466228c" -> "0x52a80955d40ec819" [label=friend]; }`, }, { name: "tutorial missing IDs", json: dgraphTutorialMissingIDs, wantErr: errors.New("graphql: no UID for node"), // Incomplete error string. }, } func TestDecode(t *testing.T) { for _, test := range decodeTests { dst := newDirectedGraph() err := Unmarshal([]byte(test.json), "_uid_", dst) if test.wantErr == nil && err != nil { t.Errorf("failed to unmarshal GraphQL JSON graph for %q: %v", test.name, err) } else if test.wantErr != nil { if err == nil { t.Errorf("expected error for %q: got:%v want:%v", test.name, err, test.wantErr) } continue } b, err := dot.Marshal(dst, "", "", " ") if err != nil { t.Fatalf("failed to DOT marshal graph %q: %v", test.name, err) } gotDOT := string(b) if gotDOT != test.wantDOT { t.Errorf("unexpected DOT encoding for %q:\ngot:\n%s\nwant:\n%s", test.name, gotDOT, test.wantDOT) } checkDOT(t, b) } } type directedGraph struct { *simple.DirectedGraph } func newDirectedGraph() *directedGraph { return &directedGraph{DirectedGraph: simple.NewDirectedGraph()} } func (g *directedGraph) NewNode() graph.Node { return &node{attributes: make(attributes)} } func (g *directedGraph) NewEdge(from, to graph.Node) graph.Edge { return &edge{Edge: g.DirectedGraph.NewEdge(from, to)} } type node struct { id uint64 attributes } func (n *node) ID() int64 { return int64(n.id) } func (n *node) DOTID() string { return fmt.Sprintf("0x%016x", n.id) } func (n *node) SetIDFromString(uid string) error { if !strings.HasPrefix(uid, "0x") { return fmt.Errorf("uid is not hex value: %q", uid) } var err error n.id, err = strconv.ParseUint(uid[2:], 16, 64) return err } type edge struct { graph.Edge label string } func (e *edge) SetLabel(l string) { e.label = l } func (e *edge) Attributes() []encoding.Attribute { return []encoding.Attribute{{Key: "label", Value: e.label}} } type attributes map[string]encoding.Attribute func (a attributes) SetAttribute(attr encoding.Attribute) error { a[attr.Key] = attr return nil } func (a attributes) Attributes() []encoding.Attribute { keys := make([]string, 0, len(a)) for k := range a { keys = append(keys, k) } sort.Strings(keys) attr := make([]encoding.Attribute, 0, len(keys)) for _, k := range keys { v := a[k] if strings.Contains(v.Value, " ") { v.Value = `"` + v.Value + `"` } attr = append(attr, v) } return attr } // checkDOT hands b to the dot executable if it exists and fails t if dot // returns an error. func checkDOT(t *testing.T, b []byte) { dot, err := exec.LookPath("dot") if err != nil { t.Logf("skipping DOT syntax check: %v", err) return } cmd := exec.Command(dot) cmd.Stdin = bytes.NewReader(b) stderr := &bytes.Buffer{} cmd.Stderr = stderr err = cmd.Run() if err != nil { t.Errorf("invalid DOT syntax: %v\n%s\ninput:\n%s", err, stderr.String(), b) } } golang-gonum-v1-gonum-0.14.0/graph/encoding/graphql/doc.go000066400000000000000000000005111450372207100232540ustar00rootroot00000000000000// 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 graphql implements JSON marshaling and unmarshaling of graph as // used by GraphQL package graphql // import "gonum.org/v1/gonum/graph/encoding/graphql" golang-gonum-v1-gonum-0.14.0/graph/encoding/graphql/graphql.go000066400000000000000000000002651450372207100241530ustar00rootroot00000000000000// 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 graphql golang-gonum-v1-gonum-0.14.0/graph/encoding/graphql/graphs_test.go000066400000000000000000000746331450372207100250520ustar00rootroot00000000000000// 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 graphql const ( starwars = `{ "movie": [ { "_uid_": "0xa3cff1a4c3ef3bb6", "director": [ { "_uid_": "0x4a7d0b5fe91e78a4", "name": "Irvin Kernshner" } ], "name": "Star Wars: Episode V - The Empire Strikes Back", "release_date": "1980-05-21T00:00:00Z", "revenue": 534000000, "running_time": 124, "starring": [ { "_uid_": "0x312de17a7ee89f9", "name": "Luke Skywalker" }, { "_uid_": "0x3da8d1dcab1bb381", "name": "Han Solo" }, { "_uid_": "0x718337b9dcbaa7d9", "name": "Princess Leia" } ] }, { "_uid_": "0xb39aa14d66aedad5", "director": [ { "_uid_": "0x8a10d5a2611fd03f", "name": "Richard Marquand" } ], "name": "Star Wars: Episode VI - Return of the Jedi", "release_date": "1983-05-25T00:00:00Z", "revenue": 572000000, "running_time": 131, "starring": [ { "_uid_": "0x312de17a7ee89f9", "name": "Luke Skywalker" }, { "_uid_": "0x3da8d1dcab1bb381", "name": "Han Solo" }, { "_uid_": "0x718337b9dcbaa7d9", "name": "Princess Leia" } ] } ] } ` dgraphTutorialMissingIDs = `{ "everyone": [ { "_uid_": "0xfd90205a458151f", "friend": [ { "_uid_": "0x52a80955d40ec819", "friend": [ { "_uid_": "0xfd90205a458151f", "age": 39, "friend": [ { "age": 35, "name": "Amit" }, { "age": 24, "name": "Sang Hyun" }, { "age": 55, "name": "Sarah" }, { "age": 35, "name": "Artyom" }, { "age": 19, "name": "Catalina" } ], "name": "Michael", "owns_pet": [ { "name": "Rammy the sheep" } ] }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "age": 35, "name": "Amit" }, { "age": 19, "name": "Catalina" }, { "name": "Hyung Sin" } ], "name": "Sang Hyun", "owns_pet": [ { "name": "Goldie" } ] }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0x5e9ad1cd9466228c", "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "age": 39, "name": "Michael" }, { "age": 24, "name": "Sang Hyun" }, { "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "age": 24, "name": "Sang Hyun" } ], "name": "Catalina", "owns_pet": [ { "name": "Perro" } ] }, { "_uid_": "0xf92d7dbe272d680b", "friend": [ { "age": 24, "name": "Sang Hyun" } ], "name": "Hyung Sin" } ], "name": "Sang Hyun" }, { "_uid_": "0x892a6da7ee1fbdec", "name": "Sarah" }, { "_uid_": "0x99b74c1b5ab100ec", "name": "Artyom" }, { "_uid_": "0xb9e12a67e34d6acc", "friend": [ { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "age": 35, "name": "Amit" }, { "age": 19, "name": "Catalina" }, { "name": "Hyung Sin" } ], "name": "Sang Hyun", "owns_pet": [ { "name": "Goldie" } ] } ], "name": "Catalina" } ], "name": "Michael" }, { "_uid_": "0x52a80955d40ec819", "friend": [ { "_uid_": "0xfd90205a458151f", "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "age": 39, "name": "Michael" }, { "age": 24, "name": "Sang Hyun" }, { "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "age": 35, "name": "Amit" }, { "age": 19, "name": "Catalina" }, { "name": "Hyung Sin" } ], "name": "Sang Hyun", "owns_pet": [ { "name": "Goldie" } ] }, { "_uid_": "0x892a6da7ee1fbdec", "age": 55, "name": "Sarah" }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "age": 24, "name": "Sang Hyun" } ], "name": "Catalina", "owns_pet": [ { "name": "Perro" } ] } ], "name": "Michael" }, { "_uid_": "0x5e9ad1cd9466228c", "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "age": 39, "name": "Michael" }, { "age": 24, "name": "Sang Hyun" }, { "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "age": 24, "name": "Sang Hyun" } ], "name": "Catalina", "owns_pet": [ { "name": "Perro" } ] }, { "_uid_": "0xf92d7dbe272d680b", "friend": [ { "age": 24, "name": "Sang Hyun" } ], "name": "Hyung Sin" } ], "name": "Sang Hyun" }, { "_uid_": "0x99b74c1b5ab100ec", "name": "Artyom" } ], "name": "Amit" } ] } ` dgraphTutorial = `{ "everyone": [ { "_uid_": "0xfd90205a458151f", "friend": [ { "_uid_": "0x52a80955d40ec819", "friend": [ { "_uid_": "0xfd90205a458151f", "age": 39, "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "_uid_": "0xfd90205a458151f" }, { "_uid_": "0x5e9ad1cd9466228c" }, { "_uid_": "0x99b74c1b5ab100ec" } ], "name": "Amit" }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] }, { "_uid_": "0x892a6da7ee1fbdec", "age": 55, "name": "Sarah" }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "_uid_": "0x5e9ad1cd9466228c" } ], "name": "Catalina", "owns_pet": [ { "_uid_": "0xbf104824c777525d" } ] } ], "name": "Michael", "owns_pet": [ { "_uid_": "0x37734fcf0a6fcc69", "name": "Rammy the sheep" } ] }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "_uid_": "0xfd90205a458151f" }, { "_uid_": "0x5e9ad1cd9466228c" }, { "_uid_": "0x99b74c1b5ab100ec" } ], "name": "Amit" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "_uid_": "0x5e9ad1cd9466228c" } ], "name": "Catalina", "owns_pet": [ { "_uid_": "0xbf104824c777525d" } ] }, { "_uid_": "0xf92d7dbe272d680b", "friend": [ { "_uid_": "0x5e9ad1cd9466228c" } ], "name": "Hyung Sin" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa", "name": "Goldie" } ] }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0x5e9ad1cd9466228c", "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "_uid_": "0xfd90205a458151f", "age": 39, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0x5e9ad1cd9466228c" }, { "_uid_": "0x892a6da7ee1fbdec" }, { "_uid_": "0x99b74c1b5ab100ec" }, { "_uid_": "0xb9e12a67e34d6acc" } ], "name": "Michael", "owns_pet": [ { "_uid_": "0x37734fcf0a6fcc69" } ] }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] } ], "name": "Catalina", "owns_pet": [ { "_uid_": "0xbf104824c777525d", "name": "Perro" } ] }, { "_uid_": "0xf92d7dbe272d680b", "friend": [ { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] } ], "name": "Hyung Sin" } ], "name": "Sang Hyun" }, { "_uid_": "0x892a6da7ee1fbdec", "name": "Sarah" }, { "_uid_": "0x99b74c1b5ab100ec", "name": "Artyom" }, { "_uid_": "0xb9e12a67e34d6acc", "friend": [ { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "_uid_": "0xfd90205a458151f" }, { "_uid_": "0x5e9ad1cd9466228c" }, { "_uid_": "0x99b74c1b5ab100ec" } ], "name": "Amit" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "_uid_": "0x5e9ad1cd9466228c" } ], "name": "Catalina", "owns_pet": [ { "_uid_": "0xbf104824c777525d" } ] }, { "_uid_": "0xf92d7dbe272d680b", "friend": [ { "_uid_": "0x5e9ad1cd9466228c" } ], "name": "Hyung Sin" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa", "name": "Goldie" } ] } ], "name": "Catalina" } ], "name": "Michael" }, { "_uid_": "0x52a80955d40ec819", "friend": [ { "_uid_": "0xfd90205a458151f", "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "_uid_": "0xfd90205a458151f", "age": 39, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0x5e9ad1cd9466228c" }, { "_uid_": "0x892a6da7ee1fbdec" }, { "_uid_": "0x99b74c1b5ab100ec" }, { "_uid_": "0xb9e12a67e34d6acc" } ], "name": "Michael", "owns_pet": [ { "_uid_": "0x37734fcf0a6fcc69" } ] }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "_uid_": "0xfd90205a458151f" }, { "_uid_": "0x5e9ad1cd9466228c" }, { "_uid_": "0x99b74c1b5ab100ec" } ], "name": "Amit" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "_uid_": "0x5e9ad1cd9466228c" } ], "name": "Catalina", "owns_pet": [ { "_uid_": "0xbf104824c777525d" } ] }, { "_uid_": "0xf92d7dbe272d680b", "friend": [ { "_uid_": "0x5e9ad1cd9466228c" } ], "name": "Hyung Sin" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa", "name": "Goldie" } ] }, { "_uid_": "0x892a6da7ee1fbdec", "age": 55, "name": "Sarah" }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] } ], "name": "Catalina", "owns_pet": [ { "_uid_": "0xbf104824c777525d", "name": "Perro" } ] } ], "name": "Michael" }, { "_uid_": "0x5e9ad1cd9466228c", "friend": [ { "_uid_": "0x52a80955d40ec819", "age": 35, "friend": [ { "_uid_": "0xfd90205a458151f", "age": 39, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0x5e9ad1cd9466228c" }, { "_uid_": "0x892a6da7ee1fbdec" }, { "_uid_": "0x99b74c1b5ab100ec" }, { "_uid_": "0xb9e12a67e34d6acc" } ], "name": "Michael", "owns_pet": [ { "_uid_": "0x37734fcf0a6fcc69" } ] }, { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] }, { "_uid_": "0x99b74c1b5ab100ec", "age": 35, "name": "Artyom" } ], "name": "Amit" }, { "_uid_": "0xb9e12a67e34d6acc", "age": 19, "friend": [ { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] } ], "name": "Catalina", "owns_pet": [ { "_uid_": "0xbf104824c777525d", "name": "Perro" } ] }, { "_uid_": "0xf92d7dbe272d680b", "friend": [ { "_uid_": "0x5e9ad1cd9466228c", "age": 24, "friend": [ { "_uid_": "0x52a80955d40ec819" }, { "_uid_": "0xb9e12a67e34d6acc" }, { "_uid_": "0xf92d7dbe272d680b" } ], "name": "Sang Hyun", "owns_pet": [ { "_uid_": "0xf590a923ea1fccaa" } ] } ], "name": "Hyung Sin" } ], "name": "Sang Hyun" }, { "_uid_": "0x99b74c1b5ab100ec", "name": "Artyom" } ], "name": "Amit" } ] } ` ) golang-gonum-v1-gonum-0.14.0/graph/export_test.go000066400000000000000000000004301450372207100216430ustar00rootroot00000000000000// Copyright ©2019 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 var ( NewNodeFilterIterator = newNodeFilterIterator NewNodeIteratorPair = newNodeIteratorPair ) golang-gonum-v1-gonum-0.14.0/graph/flow/000077500000000000000000000000001450372207100177065ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/flow/control_flow_bench_test.go000066400000000000000000000156021450372207100251460ustar00rootroot00000000000000// 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 flow import ( "flag" "fmt" "math" "os" "path/filepath" "strings" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" ) var slta = flag.Bool("slta", false, "specify DominatorsSLT benchmark") func BenchmarkDominators(b *testing.B) { testdata := filepath.FromSlash("./testdata/flow") fis, err := os.ReadDir(testdata) if err != nil { if os.IsNotExist(err) { b.Skipf("no control flow testdata: %v", err) } b.Fatalf("failed to open control flow testdata: %v", err) } for _, fi := range fis { name := fi.Name() ext := filepath.Ext(name) if ext != ".dot" { continue } test := name[:len(name)-len(ext)] data, err := os.ReadFile(filepath.Join(testdata, name)) if err != nil { b.Errorf("failed to open control flow case: %v", err) continue } g := &labeled{DirectedGraph: simple.NewDirectedGraph()} err = dot.Unmarshal(data, g) if err != nil { b.Errorf("failed to unmarshal graph data: %v", err) continue } want := g.root if want == nil { b.Error("no entry node label for graph") continue } if *slta { b.Run(test, func(b *testing.B) { for i := 0; i < b.N; i++ { d := DominatorsSLT(g.root, g) if got := d.Root(); got.ID() != want.ID() { b.Fatalf("unexpected root node: got:%d want:%d", got.ID(), want.ID()) } } }) } else { b.Run(test, func(b *testing.B) { for i := 0; i < b.N; i++ { d := Dominators(g.root, g) if got := d.Root(); got.ID() != want.ID() { b.Fatalf("unexpected root node: got:%d want:%d", got.ID(), want.ID()) } } }) } } } type labeled struct { *simple.DirectedGraph root *node } func (g *labeled) NewNode() graph.Node { return &node{Node: g.DirectedGraph.NewNode(), g: g} } func (g *labeled) SetEdge(e graph.Edge) { if e.To().ID() == e.From().ID() { // Do not attempt to add self edges. return } g.DirectedGraph.SetEdge(e) } type node struct { graph.Node name string g *labeled } func (n *node) SetDOTID(id string) { n.name = id } func (n *node) SetAttribute(attr encoding.Attribute) error { if attr.Key != "label" { return nil } switch attr.Value { default: if attr.Value != `"{%0}"` && !strings.HasPrefix(attr.Value, `"{%0|`) { return nil } fallthrough case "entry", "root": if n.g.root != nil { return fmt.Errorf("set root for graph with existing root: old=%q new=%q", n.g.root.name, n.name) } n.g.root = n } return nil } func BenchmarkRandomGraphDominators(b *testing.B) { tests := []struct { name string g func() *simple.DirectedGraph }{ {name: "gnm-n=1e3-m=1e3", g: gnm(1e3, 1e3)}, {name: "gnm-n=1e3-m=3e3", g: gnm(1e3, 3e3)}, {name: "gnm-n=1e3-m=1e4", g: gnm(1e3, 1e4)}, {name: "gnm-n=1e3-m=3e4", g: gnm(1e3, 3e4)}, {name: "gnm-n=1e4-m=1e4", g: gnm(1e4, 1e4)}, {name: "gnm-n=1e4-m=3e4", g: gnm(1e4, 3e4)}, {name: "gnm-n=1e4-m=1e5", g: gnm(1e4, 1e5)}, {name: "gnm-n=1e4-m=3e5", g: gnm(1e4, 3e5)}, {name: "gnm-n=1e5-m=1e5", g: gnm(1e5, 1e5)}, {name: "gnm-n=1e5-m=3e5", g: gnm(1e5, 3e5)}, {name: "gnm-n=1e5-m=1e6", g: gnm(1e5, 1e6)}, {name: "gnm-n=1e5-m=3e6", g: gnm(1e5, 3e6)}, {name: "gnm-n=1e6-m=1e6", g: gnm(1e6, 1e6)}, {name: "gnm-n=1e6-m=3e6", g: gnm(1e6, 3e6)}, {name: "gnm-n=1e6-m=1e7", g: gnm(1e6, 1e7)}, {name: "gnm-n=1e6-m=3e7", g: gnm(1e6, 3e7)}, {name: "dup-n=1e3-d=0.8-a=0.1", g: duplication(1e3, 0.8, 0.1, math.NaN())}, {name: "dup-n=1e3-d=0.5-a=0.2", g: duplication(1e3, 0.5, 0.2, math.NaN())}, {name: "dup-n=1e4-d=0.8-a=0.1", g: duplication(1e4, 0.8, 0.1, math.NaN())}, {name: "dup-n=1e4-d=0.5-a=0.2", g: duplication(1e4, 0.5, 0.2, math.NaN())}, {name: "dup-n=1e5-d=0.8-a=0.1", g: duplication(1e5, 0.8, 0.1, math.NaN())}, {name: "dup-n=1e5-d=0.5-a=0.2", g: duplication(1e5, 0.5, 0.2, math.NaN())}, } for _, test := range tests { rnd := rand.New(rand.NewSource(1)) g := test.g() // Guess a maximally expensive entry to the graph. sort, err := topo.Sort(g) root := sort[0] if root == nil { // If we did not get a node in the first position // then there must be an unorderable set of nodes // in the first position of the error. Pick one // of the nodes at random. unordered := err.(topo.Unorderable) root = unordered[0][rnd.Intn(len(unordered[0]))] } if root == nil { b.Error("no entry node label for graph") continue } if len(sort) > 1 { // Ensure that the graph has a complete path // through the sorted nodes. // unordered will only be accessed if there is // a sort element that is nil, in which case // unordered will contain a set of nodes from // an SCC. unordered, _ := err.(topo.Unorderable) var ui int for i, v := range sort[1:] { u := sort[i] if u == nil { u = unordered[ui][rnd.Intn(len(unordered[ui]))] ui++ } if v == nil { v = unordered[ui][rnd.Intn(len(unordered[ui]))] } if !g.HasEdgeFromTo(u.ID(), v.ID()) { g.SetEdge(g.NewEdge(u, v)) } } } b.Run(test.name, func(b *testing.B) { for i := 0; i < b.N; i++ { d := Dominators(root, g) if got := d.Root(); got.ID() != root.ID() { b.Fatalf("unexpected root node: got:%d want:%d", got.ID(), root.ID()) } } }) } } // gnm returns a directed G(n,m) Erdõs-Rényi graph. func gnm(n, m int) func() *simple.DirectedGraph { return func() *simple.DirectedGraph { dg := simple.NewDirectedGraph() err := gen.Gnm(dg, n, m, rand.New(rand.NewSource(1))) if err != nil { panic(err) } return dg } } // duplication returns an edge-induced directed subgraph of a // duplication graph. func duplication(n int, delta, alpha, sigma float64) func() *simple.DirectedGraph { return func() *simple.DirectedGraph { g := undirected{simple.NewDirectedGraph()} rnd := rand.New(rand.NewSource(1)) err := gen.Duplication(g, n, delta, alpha, sigma, rnd) if err != nil { panic(err) } for _, e := range graph.EdgesOf(g.Edges()) { if rnd.Intn(2) == 0 { g.RemoveEdge(e.From().ID(), e.To().ID()) } } return g.DirectedGraph } } type undirected struct { *simple.DirectedGraph } func (g undirected) From(id int64) graph.Nodes { return iterator.NewOrderedNodes(append( graph.NodesOf(g.DirectedGraph.From(id)), graph.NodesOf(g.DirectedGraph.To(id))...)) } func (g undirected) HasEdgeBetween(xid, yid int64) bool { return g.DirectedGraph.HasEdgeFromTo(xid, yid) } func (g undirected) EdgeBetween(xid, yid int64) graph.Edge { return g.DirectedGraph.Edge(xid, yid) } func (g undirected) SetEdge(e graph.Edge) { g.DirectedGraph.SetEdge(e) g.DirectedGraph.SetEdge(g.DirectedGraph.NewEdge(e.To(), e.From())) } golang-gonum-v1-gonum-0.14.0/graph/flow/control_flow_lt.go000066400000000000000000000127021450372207100234450ustar00rootroot00000000000000// 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 flow import "gonum.org/v1/gonum/graph" // Dominators returns a dominator tree for all nodes in the flow graph // g starting from the given root node. func Dominators(root graph.Node, g graph.Directed) DominatorTree { // The algorithm used here is essentially the Lengauer and Tarjan // algorithm described in https://doi.org/10.1145%2F357062.357071 lt := lengauerTarjan{ indexOf: make(map[int64]int), } // step 1. lt.dfs(g, root) for i := len(lt.nodes) - 1; i > 0; i-- { w := lt.nodes[i] // step 2. for _, v := range w.pred { u := lt.eval(v) if u.semi < w.semi { w.semi = u.semi } } lt.nodes[w.semi].bucket[w] = struct{}{} lt.link(w.parent, w) // step 3. for v := range w.parent.bucket { delete(w.parent.bucket, v) u := lt.eval(v) if u.semi < v.semi { v.dom = u } else { v.dom = w.parent } } } // step 4. for _, w := range lt.nodes[1:] { if w.dom.node.ID() != lt.nodes[w.semi].node.ID() { w.dom = w.dom.dom } } // Construct the public-facing dominator tree structure. dominatorOf := make(map[int64]graph.Node) dominatedBy := make(map[int64][]graph.Node) for _, w := range lt.nodes[1:] { dominatorOf[w.node.ID()] = w.dom.node did := w.dom.node.ID() dominatedBy[did] = append(dominatedBy[did], w.node) } return DominatorTree{root: root, dominatorOf: dominatorOf, dominatedBy: dominatedBy} } // lengauerTarjan holds global state of the Lengauer-Tarjan algorithm. // This is a mapping between nodes and the postordering of the nodes. type lengauerTarjan struct { // nodes is the nodes traversed during the // Lengauer-Tarjan depth-first-search. nodes []*ltNode // indexOf contains a mapping between // the id-dense representation of the // graph and the potentially id-sparse // nodes held in nodes. // // This corresponds to the vertex // number of the node in the Lengauer- // Tarjan algorithm. indexOf map[int64]int } // ltNode is a graph node with accounting for the Lengauer-Tarjan // algorithm. // // For the purposes of documentation the ltNode is given the name w. type ltNode struct { node graph.Node // parent is vertex which is the parent of w // in the spanning tree generated by the search. parent *ltNode // pred is the set of vertices v such that (v, w) // is an edge of the graph. pred []*ltNode // semi is a number defined as follows: // (i) After w is numbered but before its semidominator // is computed, semi is the number of w. // (ii) After the semidominator of w is computed, semi // is the number of the semidominator of w. semi int // bucket is the set of vertices whose // semidominator is w. bucket map[*ltNode]struct{} // dom is vertex defined as follows: // (i) After step 3, if the semidominator of w is its // immediate dominator, then dom is the immediate // dominator of w. Otherwise dom is a vertex v // whose number is smaller than w and whose immediate // dominator is also w's immediate dominator. // (ii) After step 4, dom is the immediate dominator of w. dom *ltNode // In general ancestor is nil only if w is a tree root // in the forest; otherwise ancestor is an ancestor // of w in the forest. ancestor *ltNode // Initially label is w. It is adjusted during // the algorithm to maintain invariant (3) in the // Lengauer and Tarjan paper. label *ltNode } // dfs is the Lengauer-Tarjan DFS procedure. func (lt *lengauerTarjan) dfs(g graph.Directed, v graph.Node) { i := len(lt.nodes) lt.indexOf[v.ID()] = i ltv := <Node{ node: v, semi: i, bucket: make(map[*ltNode]struct{}), } ltv.label = ltv lt.nodes = append(lt.nodes, ltv) to := g.From(v.ID()) for to.Next() { w := to.Node() wid := w.ID() idx, ok := lt.indexOf[wid] if !ok { lt.dfs(g, w) // We place this below the recursive call // in contrast to the original algorithm // since w needs to be initialised, and // this happens in the child call to dfs. idx, ok = lt.indexOf[wid] if !ok { panic("path: unintialized node") } lt.nodes[idx].parent = ltv } ltw := lt.nodes[idx] ltw.pred = append(ltw.pred, ltv) } } // compress is the Lengauer-Tarjan COMPRESS procedure. func (lt *lengauerTarjan) compress(v *ltNode) { if v.ancestor.ancestor != nil { lt.compress(v.ancestor) if v.ancestor.label.semi < v.label.semi { v.label = v.ancestor.label } v.ancestor = v.ancestor.ancestor } } // eval is the Lengauer-Tarjan EVAL function. func (lt *lengauerTarjan) eval(v *ltNode) *ltNode { if v.ancestor == nil { return v } lt.compress(v) return v.label } // link is the Lengauer-Tarjan LINK procedure. func (*lengauerTarjan) link(v, w *ltNode) { w.ancestor = v } // DominatorTree is a flow graph dominator tree. type DominatorTree struct { root graph.Node dominatorOf map[int64]graph.Node dominatedBy map[int64][]graph.Node } // Root returns the root of the tree. func (d DominatorTree) Root() graph.Node { return d.root } // DominatorOf returns the immediate dominator of the node with the given ID. func (d DominatorTree) DominatorOf(id int64) graph.Node { return d.dominatorOf[id] } // DominatedBy returns a slice of all nodes immediately dominated by the node // with the given ID. Elements of the slice are retained by the DominatorTree. func (d DominatorTree) DominatedBy(id int64) []graph.Node { return d.dominatedBy[id] } golang-gonum-v1-gonum-0.14.0/graph/flow/control_flow_slt.go000066400000000000000000000135461450372207100236370ustar00rootroot00000000000000// 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 flow import "gonum.org/v1/gonum/graph" // DominatorsSLT returns a dominator tree for all nodes in the flow graph // g starting from the given root node using the sophisticated version of // the Lengauer-Tarjan algorithm. The SLT algorithm may outperform the // simple LT algorithm for very large dense graphs. func DominatorsSLT(root graph.Node, g graph.Directed) DominatorTree { // The algorithm used here is essentially the // sophisticated Lengauer and Tarjan algorithm // described in // https://doi.org/10.1145%2F357062.357071 lt := sLengauerTarjan{ indexOf: make(map[int64]int), base: sltNode{semi: -1}, } lt.base.label = <.base // step 1. lt.dfs(g, root) for i := len(lt.nodes) - 1; i > 0; i-- { w := lt.nodes[i] // step 2. for _, v := range w.pred { u := lt.eval(v) if u.semi < w.semi { w.semi = u.semi } } lt.nodes[w.semi].bucket[w] = struct{}{} lt.link(w.parent, w) // step 3. for v := range w.parent.bucket { delete(w.parent.bucket, v) u := lt.eval(v) if u.semi < v.semi { v.dom = u } else { v.dom = w.parent } } } // step 4. for _, w := range lt.nodes[1:] { if w.dom.node.ID() != lt.nodes[w.semi].node.ID() { w.dom = w.dom.dom } } // Construct the public-facing dominator tree structure. dominatorOf := make(map[int64]graph.Node) dominatedBy := make(map[int64][]graph.Node) for _, w := range lt.nodes[1:] { dominatorOf[w.node.ID()] = w.dom.node did := w.dom.node.ID() dominatedBy[did] = append(dominatedBy[did], w.node) } return DominatorTree{root: root, dominatorOf: dominatorOf, dominatedBy: dominatedBy} } // sLengauerTarjan holds global state of the Lengauer-Tarjan algorithm. // This is a mapping between nodes and the postordering of the nodes. type sLengauerTarjan struct { // nodes is the nodes traversed during the // Lengauer-Tarjan depth-first-search. nodes []*sltNode // indexOf contains a mapping between // the id-dense representation of the // graph and the potentially id-sparse // nodes held in nodes. // // This corresponds to the vertex // number of the node in the Lengauer- // Tarjan algorithm. indexOf map[int64]int // base is the base label for balanced // tree path compression used in the // sophisticated Lengauer-Tarjan // algorith, base sltNode } // sltNode is a graph node with accounting for the Lengauer-Tarjan // algorithm. // // For the purposes of documentation the ltNode is given the name w. type sltNode struct { node graph.Node // parent is vertex which is the parent of w // in the spanning tree generated by the search. parent *sltNode // pred is the set of vertices v such that (v, w) // is an edge of the graph. pred []*sltNode // semi is a number defined as follows: // (i) After w is numbered but before its semidominator // is computed, semi is the number of w. // (ii) After the semidominator of w is computed, semi // is the number of the semidominator of w. semi int // size is the tree size of w used in the // sophisticated algorithm. size int // child is the child node of w used in the // sophisticated algorithm. child *sltNode // bucket is the set of vertices whose // semidominator is w. bucket map[*sltNode]struct{} // dom is vertex defined as follows: // (i) After step 3, if the semidominator of w is its // immediate dominator, then dom is the immediate // dominator of w. Otherwise dom is a vertex v // whose number is smaller than w and whose immediate // dominator is also w's immediate dominator. // (ii) After step 4, dom is the immediate dominator of w. dom *sltNode // In general ancestor is nil only if w is a tree root // in the forest; otherwise ancestor is an ancestor // of w in the forest. ancestor *sltNode // Initially label is w. It is adjusted during // the algorithm to maintain invariant (3) in the // Lengauer and Tarjan paper. label *sltNode } // dfs is the Sophisticated Lengauer-Tarjan DFS procedure. func (lt *sLengauerTarjan) dfs(g graph.Directed, v graph.Node) { i := len(lt.nodes) lt.indexOf[v.ID()] = i ltv := &sltNode{ node: v, semi: i, size: 1, child: <.base, bucket: make(map[*sltNode]struct{}), } ltv.label = ltv lt.nodes = append(lt.nodes, ltv) to := g.From(v.ID()) for to.Next() { w := to.Node() wid := w.ID() idx, ok := lt.indexOf[wid] if !ok { lt.dfs(g, w) // We place this below the recursive call // in contrast to the original algorithm // since w needs to be initialised, and // this happens in the child call to dfs. idx, ok = lt.indexOf[wid] if !ok { panic("path: unintialized node") } lt.nodes[idx].parent = ltv } ltw := lt.nodes[idx] ltw.pred = append(ltw.pred, ltv) } } // compress is the Sophisticated Lengauer-Tarjan COMPRESS procedure. func (lt *sLengauerTarjan) compress(v *sltNode) { if v.ancestor.ancestor != nil { lt.compress(v.ancestor) if v.ancestor.label.semi < v.label.semi { v.label = v.ancestor.label } v.ancestor = v.ancestor.ancestor } } // eval is the Sophisticated Lengauer-Tarjan EVAL function. func (lt *sLengauerTarjan) eval(v *sltNode) *sltNode { if v.ancestor == nil { return v.label } lt.compress(v) if v.ancestor.label.semi >= v.label.semi { return v.label } return v.ancestor.label } // link is the Sophisticated Lengauer-Tarjan LINK procedure. func (*sLengauerTarjan) link(v, w *sltNode) { s := w for w.label.semi < s.child.label.semi { if s.size+s.child.child.size >= 2*s.child.size { s.child.ancestor = s s.child = s.child.child } else { s.child.size = s.size s.ancestor = s.child s = s.child } } s.label = w.label v.size += w.size if v.size < 2*w.size { s, v.child = v.child, s } for s != nil { s.ancestor = v s = s.child } } golang-gonum-v1-gonum-0.14.0/graph/flow/control_flow_test.go000066400000000000000000000123631450372207100240100ustar00rootroot00000000000000// 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 flow import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var dominatorsTests = []struct { n graph.Node edges []simple.Edge want DominatorTree }{ { // Example from Lengauer and Tarjan http://www.dtic.mil/dtic/tr/fulltext/u2/a054144.pdf fig 1. n: char('R'), edges: []simple.Edge{ {F: char('A'), T: char('D')}, {F: char('B'), T: char('A')}, {F: char('B'), T: char('D')}, {F: char('B'), T: char('E')}, {F: char('C'), T: char('F')}, {F: char('C'), T: char('G')}, {F: char('D'), T: char('L')}, {F: char('E'), T: char('H')}, {F: char('F'), T: char('I')}, {F: char('G'), T: char('I')}, {F: char('G'), T: char('J')}, {F: char('H'), T: char('E')}, {F: char('H'), T: char('K')}, {F: char('I'), T: char('K')}, {F: char('J'), T: char('I')}, {F: char('K'), T: char('I')}, {F: char('K'), T: char('R')}, {F: char('L'), T: char('H')}, {F: char('R'), T: char('A')}, {F: char('R'), T: char('B')}, {F: char('R'), T: char('C')}, }, want: DominatorTree{ root: char('R'), dominatorOf: map[int64]graph.Node{ 'A': char('R'), 'B': char('R'), 'C': char('R'), 'D': char('R'), 'E': char('R'), 'F': char('C'), 'G': char('C'), 'H': char('R'), 'I': char('R'), 'J': char('G'), 'K': char('R'), 'L': char('D'), }, dominatedBy: map[int64][]graph.Node{ 'C': {char('F'), char('G')}, 'D': {char('L')}, 'G': {char('J')}, 'R': {char('A'), char('B'), char('C'), char('D'), char('E'), char('H'), char('I'), char('K')}, }, }, }, { // WP example: https://en.wikipedia.org/w/index.php?title=Dominator_(graph_theory)&oldid=758099236. n: simple.Node(1), edges: []simple.Edge{ {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(2), T: simple.Node(3)}, {F: simple.Node(2), T: simple.Node(4)}, {F: simple.Node(2), T: simple.Node(6)}, {F: simple.Node(3), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(5), T: simple.Node(2)}, }, want: DominatorTree{ root: simple.Node(1), dominatorOf: map[int64]graph.Node{ 2: simple.Node(1), 3: simple.Node(2), 4: simple.Node(2), 5: simple.Node(2), 6: simple.Node(2), }, dominatedBy: map[int64][]graph.Node{ 1: {simple.Node(2)}, 2: {simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6)}, }, }, }, { // WP example with node IDs decremented by 1. n: simple.Node(0), edges: []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(5)}, {F: simple.Node(2), T: simple.Node(4)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(4), T: simple.Node(1)}, }, want: DominatorTree{ root: simple.Node(0), dominatorOf: map[int64]graph.Node{ 1: simple.Node(0), 2: simple.Node(1), 3: simple.Node(1), 4: simple.Node(1), 5: simple.Node(1), }, dominatedBy: map[int64][]graph.Node{ 0: {simple.Node(1)}, 1: {simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5)}, }, }, }, } type char rune func (n char) ID() int64 { return int64(n) } func (n char) String() string { return string(n) } func TestDominators(t *testing.T) { // The dominator functions are non-deterministic due // to map iteration ordering, so repeat the tests to // ensure consistent coverage. The value of 100 was // chosen empirically to have no observed reduction // in coverage in several hundred runs of go test -cover. for i := 0; i < 100; i++ { for _, test := range dominatorsTests { g := simple.NewDirectedGraph() for _, e := range test.edges { g.SetEdge(e) } for _, alg := range []struct { name string fn func(graph.Node, graph.Directed) DominatorTree }{ {"Dominators", Dominators}, {"DominatorsSLT", DominatorsSLT}, } { got := alg.fn(test.n, g) if !reflect.DeepEqual(got.Root(), test.want.root) { t.Errorf("unexpected dominator tree root from %s: got:%v want:%v", alg.name, got.root, test.want.root) } if !reflect.DeepEqual(got.dominatorOf, test.want.dominatorOf) { t.Errorf("unexpected dominator tree from %s: got:%v want:%v", alg.name, got.dominatorOf, test.want.dominatorOf) } for q, want := range test.want.dominatorOf { node := got.DominatorOf(q) if node != want { t.Errorf("unexpected dominator tree result from %s dominated of %v: got:%v want:%v", alg.name, q, node, want) } } for _, nodes := range got.dominatedBy { ordered.ByID(nodes) } if !reflect.DeepEqual(got.dominatedBy, test.want.dominatedBy) { t.Errorf("unexpected dominator tree from %s: got:%v want:%v", alg.name, got.dominatedBy, test.want.dominatedBy) } for q, want := range test.want.dominatedBy { nodes := got.DominatedBy(q) if !reflect.DeepEqual(nodes, want) { t.Errorf("unexpected dominator tree result from %s dominated by %v: got:%v want:%v", alg.name, q, nodes, want) } } } } } } golang-gonum-v1-gonum-0.14.0/graph/flow/doc.go000066400000000000000000000004261450372207100210040ustar00rootroot00000000000000// Copyright ©2019 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 flow provides control flow analysis functions. package flow // import "gonum.org/v1/gonum/graph/flow" golang-gonum-v1-gonum-0.14.0/graph/formats/000077500000000000000000000000001450372207100204125ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/000077500000000000000000000000001450372207100227415ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/cytoscapejs.go000066400000000000000000000177151450372207100256320ustar00rootroot00000000000000// 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 cytoscapejs implements marshaling and unmarshaling of Cytoscape.js JSON documents. // // See http://js.cytoscape.org/ for Cytoscape.js documentation. package cytoscapejs // import "gonum.org/v1/gonum/graph/formats/cytoscapejs" import ( "encoding/json" "errors" "fmt" ) // GraphElem is a Cytoscape.js graph with mixed graph elements. type GraphElem struct { Elements []Element `json:"elements"` Layout interface{} `json:"layout,omitempty"` Style []interface{} `json:"style,omitempty"` } // Element is a mixed graph element. type Element struct { Group string `json:"group,omitempty"` Data ElemData `json:"data"` Position *Position `json:"position,omitempty"` RenderedPosition *Position `json:"renderedPosition,omitempty"` Selected bool `json:"selected,omitempty"` Selectable bool `json:"selectable,omitempty"` Locked bool `json:"locked,omitempty"` Grabbable bool `json:"grabbable,omitempty"` Classes string `json:"classes,omitempty"` Scratch interface{} `json:"scratch,omitempty"` } // ElemType describes an Element type. type ElemType int const ( InvalidElement ElemType = iota - 1 NodeElement EdgeElement ) // Type returns the element type of the receiver. It returns an error if the Element Group // is invalid or does not match the Element Data, or if the Element Data is an incomplete // edge. func (e Element) Type() (ElemType, error) { et := InvalidElement switch { case e.Data.Source == "" && e.Data.Target == "": et = NodeElement case e.Data.Source != "" && e.Data.Target != "": et = EdgeElement default: return et, errors.New("cytoscapejs: invalid element: incomplete edge") } switch { case e.Group == "": return et, nil case e.Group == "node" && et == NodeElement: return NodeElement, nil case e.Group == "edge" && et == EdgeElement: return NodeElement, nil default: return InvalidElement, errors.New("cytoscapejs: invalid element: mismatched group") } } // ElemData is a graph element's data container. type ElemData struct { ID string Source string Target string Parent string Attributes map[string]interface{} } var ( _ json.Marshaler = (*ElemData)(nil) _ json.Unmarshaler = (*ElemData)(nil) ) // MarshalJSON implements the json.Marshaler interface. func (e *ElemData) MarshalJSON() ([]byte, error) { if e.Attributes == nil { type elem struct { ID string `json:"id"` Source string `json:"source,omitempty"` Target string `json:"target,omitempty"` Parent string `json:"parent,omitempty"` } return json.Marshal(elem{ID: e.ID, Source: e.Source, Target: e.Target, Parent: e.Parent}) } e.Attributes["id"] = e.ID if e.Source != "" { e.Attributes["source"] = e.Source } if e.Target != "" { e.Attributes["target"] = e.Target } if e.Parent != "" { e.Attributes["parent"] = e.Parent } b, err := json.Marshal(e.Attributes) delete(e.Attributes, "id") if e.Source != "" { delete(e.Attributes, "source") } if e.Target != "" { delete(e.Attributes, "target") } if e.Parent != "" { delete(e.Attributes, "parent") } return b, err } // UnmarshalJSON implements the json.Unmarshaler interface. func (e *ElemData) UnmarshalJSON(data []byte) error { var attrs map[string]interface{} err := json.Unmarshal(data, &attrs) if err != nil { return err } id, ok := attrs["id"] if !ok { return errors.New("cytoscapejs: no ID") } e.ID = fmt.Sprint(id) source, ok := attrs["source"] if ok { e.Source = fmt.Sprint(source) } target, ok := attrs["target"] if ok { e.Target = fmt.Sprint(target) } p, ok := attrs["parent"] if ok { e.Parent = fmt.Sprint(p) } delete(attrs, "id") delete(attrs, "source") delete(attrs, "target") delete(attrs, "parent") if len(attrs) != 0 { e.Attributes = attrs } return nil } // GraphNodeEdge is a Cytoscape.js graph with separated nodes and edges. type GraphNodeEdge struct { Elements Elements `json:"elements"` Layout interface{} `json:"layout,omitempty"` Style []interface{} `json:"style,omitempty"` } // Elements contains the nodes and edges of a GraphNodeEdge. type Elements struct { Nodes []Node `json:"nodes"` Edges []Edge `json:"edges"` } // Node is a Cytoscape.js node. type Node struct { Data NodeData `json:"data"` Position *Position `json:"position,omitempty"` RenderedPosition *Position `json:"renderedPosition,omitempty"` Selected bool `json:"selected,omitempty"` Selectable bool `json:"selectable,omitempty"` Locked bool `json:"locked,omitempty"` Grabbable bool `json:"grabbable,omitempty"` Classes string `json:"classes,omitempty"` Scratch interface{} `json:"scratch,omitempty"` } // NodeData is a graph node's data container. type NodeData struct { ID string Parent string Attributes map[string]interface{} } var ( _ json.Marshaler = (*NodeData)(nil) _ json.Unmarshaler = (*NodeData)(nil) ) // MarshalJSON implements the json.Marshaler interface. func (n *NodeData) MarshalJSON() ([]byte, error) { if n.Attributes == nil { type node struct { ID string `json:"id"` Parent string `json:"parent,omitempty"` } return json.Marshal(node{ID: n.ID, Parent: n.Parent}) } n.Attributes["id"] = n.ID n.Attributes["parent"] = n.Parent b, err := json.Marshal(n.Attributes) delete(n.Attributes, "id") delete(n.Attributes, "parent") return b, err } // UnmarshalJSON implements the json.Unmarshaler interface. func (n *NodeData) UnmarshalJSON(data []byte) error { var attrs map[string]interface{} err := json.Unmarshal(data, &attrs) if err != nil { return err } id, ok := attrs["id"] if !ok { return errors.New("cytoscapejs: no ID") } n.ID = fmt.Sprint(id) delete(attrs, "id") p, ok := attrs["parent"] if ok { n.Parent = fmt.Sprint(p) } delete(attrs, "parent") if len(attrs) != 0 { n.Attributes = attrs } return nil } // Edge is a Cytoscape.js edge. type Edge struct { Data EdgeData `json:"data"` Selected bool `json:"selected,omitempty"` Selectable bool `json:"selectable,omitempty"` Classes string `json:"classes,omitempty"` Scratch interface{} `json:"scratch,omitempty"` } // EdgeData is a graph edge's data container. type EdgeData struct { ID string Source string Target string Attributes map[string]interface{} } var ( _ json.Marshaler = (*EdgeData)(nil) _ json.Unmarshaler = (*EdgeData)(nil) ) // MarshalJSON implements the json.Marshaler interface. func (e *EdgeData) MarshalJSON() ([]byte, error) { if e.Attributes == nil { type edge struct { ID string `json:"id"` Source string `json:"source"` Target string `json:"target"` } return json.Marshal(edge{ID: e.ID, Source: e.Source, Target: e.Target}) } e.Attributes["id"] = e.ID e.Attributes["source"] = e.Source e.Attributes["target"] = e.Target b, err := json.Marshal(e.Attributes) delete(e.Attributes, "id") delete(e.Attributes, "source") delete(e.Attributes, "target") return b, err } // UnmarshalJSON implements the json.Unmarshaler interface. func (e *EdgeData) UnmarshalJSON(data []byte) error { var attrs map[string]interface{} err := json.Unmarshal(data, &attrs) if err != nil { return err } id, ok := attrs["id"] if !ok { return errors.New("cytoscapejs: no ID") } source, ok := attrs["source"] if !ok { return errors.New("cytoscapejs: no source") } target, ok := attrs["target"] if !ok { return errors.New("cytoscapejs: no target") } e.ID = fmt.Sprint(id) e.Source = fmt.Sprint(source) e.Target = fmt.Sprint(target) delete(attrs, "id") delete(attrs, "source") delete(attrs, "target") if len(attrs) != 0 { e.Attributes = attrs } return nil } // Position is a node position. type Position struct { X float64 `json:"x"` Y float64 `json:"y"` } golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/cytoscapejs_test.go000066400000000000000000000265721450372207100266720ustar00rootroot00000000000000// 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 cytoscapejs import ( "encoding/json" "os" "path/filepath" "reflect" "testing" ) var cytoscapejsElementsTests = []struct { path string wantNodes int wantEdges int wantGraph []Element wantAttributes []string }{ { path: "edge-type.json", wantNodes: 10, wantEdges: 10, wantGraph: []Element{ {Data: ElemData{ID: "n01", Attributes: map[string]interface{}{"type": "bezier"}}}, {Data: ElemData{ID: "n02"}}, {Data: ElemData{ID: "e01", Source: "n01", Target: "n02"}, Classes: "bezier"}, {Data: ElemData{ID: "e02", Source: "n01", Target: "n02"}, Classes: "bezier"}, {Data: ElemData{ID: "e03", Source: "n02", Target: "n01"}, Classes: "bezier"}, {Data: ElemData{ID: "n03", Attributes: map[string]interface{}{"type": "unbundled-bezier"}}}, {Data: ElemData{ID: "n04"}}, {Data: ElemData{ID: "e04", Source: "n03", Target: "n04"}, Classes: "unbundled-bezier"}, {Data: ElemData{ID: "n05", Attributes: map[string]interface{}{"type": "unbundled-bezier(multiple)"}}}, {Data: ElemData{ID: "n06"}}, {Data: ElemData{ID: "e05", Source: "n05", Target: "n06", Parent: ""}, Classes: "multi-unbundled-bezier"}, {Data: ElemData{ID: "n07", Attributes: map[string]interface{}{"type": "haystack"}}}, {Data: ElemData{ID: "n08"}}, {Data: ElemData{ID: "e06", Source: "n08", Target: "n07"}, Classes: "haystack"}, {Data: ElemData{ID: "e07", Source: "n08", Target: "n07"}, Classes: "haystack"}, {Data: ElemData{ID: "e08", Source: "n08", Target: "n07"}, Classes: "haystack"}, {Data: ElemData{ID: "e09", Source: "n08", Target: "n07"}, Classes: "haystack"}, {Data: ElemData{ID: "n09", Attributes: map[string]interface{}{"type": "segments"}}}, {Data: ElemData{ID: "n10"}}, {Data: ElemData{ID: "e10", Source: "n09", Target: "n10"}, Classes: "segments"}, }, }, } func TestUnmarshalElements(t *testing.T) { for _, test := range cytoscapejsElementsTests { data, err := os.ReadFile(filepath.Join("testdata", test.path)) if err != nil { t.Errorf("failed to read %q: %v", test.path, err) continue } var got []Element err = json.Unmarshal(data, &got) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } var gotNodes, gotEdges int for _, e := range got { typ, err := e.Type() if err != nil { t.Errorf("unexpected error finding element type for %+v: %v", e, err) } switch typ { case NodeElement: gotNodes++ case EdgeElement: gotEdges++ } } if gotNodes != test.wantNodes { t.Errorf("unexpected result for order of %q: got:%d want:%d", test.path, gotNodes, test.wantNodes) } if gotEdges != test.wantEdges { t.Errorf("unexpected result for size of %q: got:%d want:%d", test.path, gotEdges, test.wantEdges) } if test.wantGraph != nil && !reflect.DeepEqual(got, test.wantGraph) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, test.wantGraph) } } } func TestMarshalElements(t *testing.T) { for _, test := range cytoscapejsElementsTests { data, err := os.ReadFile(filepath.Join("testdata", test.path)) if err != nil { t.Errorf("failed to read %q: %v", test.path, err) continue } var want []Element err = json.Unmarshal(data, &want) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } marshaled, err := json.Marshal(want) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } var got []Element err = json.Unmarshal(marshaled, &got) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } if !reflect.DeepEqual(got, want) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, want) } } } var cytoscapejsNodeEdgeTests = []struct { path string wantNodes int wantEdges int wantGraph *Elements firstNode Node firstEdge Edge wantNodeAttributes map[string]bool wantEdgeAttributes map[string]bool }{ { path: "cola-compound.json", wantNodes: 9, wantEdges: 7, wantGraph: &Elements{ Nodes: []Node{ {Data: NodeData{ID: "compound-1", Parent: ""}}, {Data: NodeData{ID: "compound-2", Parent: ""}}, {Data: NodeData{ID: "compound-3", Parent: ""}}, {Data: NodeData{ID: "b", Parent: "compound-1"}}, {Data: NodeData{ID: "c", Parent: "compound-1"}}, {Data: NodeData{ID: "a", Parent: "compound-2"}}, {Data: NodeData{ID: "d", Parent: "compound-3"}}, {Data: NodeData{ID: "e", Parent: "compound-3"}}, {Data: NodeData{ID: "f", Parent: ""}}, }, Edges: []Edge{ {Data: EdgeData{ID: "ab", Source: "a", Target: "b"}}, {Data: EdgeData{ID: "bc", Source: "b", Target: "c"}}, {Data: EdgeData{ID: "ac", Source: "a", Target: "c"}}, {Data: EdgeData{ID: "cd", Source: "c", Target: "d"}}, {Data: EdgeData{ID: "de", Source: "d", Target: "e"}}, {Data: EdgeData{ID: "df", Source: "d", Target: "f"}}, {Data: EdgeData{ID: "af", Source: "a", Target: "f"}}, }, }, }, { path: "tokyo-railways.json", wantNodes: 943, wantEdges: 860, firstNode: Node{ Data: NodeData{ ID: "8220", Attributes: map[string]interface{}{ "station_name": "京成高砂", "close_ymd": "", "lon": 139.866875, "post": "", "e_status": 0.0, "SUID": 8220.0, "station_g_cd": 2300110.0, "add": "東京都葛飾区高砂五丁目28-1", "line_cd": 99340.0, "selected": false, "open_ymd": "", "name": "9934001", "pref_name": "東京都", "shared_name": "9934001", "lat": 35.750932, "x": 1398668.75, "y": -357509.32, }, }, Position: &Position{ X: 1398668.75, Y: -357509.32, }, }, firstEdge: Edge{ Data: EdgeData{ ID: "18417", Source: "8220", Target: "8221", Attributes: map[string]interface{}{ "line_name_k": "ホクソウテツドウホクソウセン", "is_bullet": false, "lon": 140.03784499075186, "company_name_k": "ホクソウテツドウ", "zoom": 11.0, "SUID": 18417.0, "company_type": 0.0, "company_name_h": "北総鉄道株式会社", "interaction": "99340", "shared_interaction": "99340", "company_url": "http://www.hokuso-railway.co.jp/", "line_name": "北総鉄道北総線", "selected": false, "company_name": "北総鉄道", "company_cd": 152.0, "name": "9934001 (99340) 9934002", "rr_cd": 99.0, "company_name_r": "北総鉄道", "e_status_x": 0.0, "shared_name": "9934001 (99340) 9934002", "lat": 35.78346285846615, "e_status_y": 0.0, "line_name_h": "北総鉄道北総線", }, }, }, wantNodeAttributes: map[string]bool{ "station_name": true, "close_ymd": true, "lon": true, "post": true, "e_status": true, "SUID": true, "station_g_cd": true, "add": true, "line_cd": true, "selected": true, "open_ymd": true, "name": true, "pref_name": true, "shared_name": true, "lat": true, "x": true, "y": true, }, wantEdgeAttributes: map[string]bool{ "line_name_k": true, "is_bullet": true, "lon": true, "company_name_k": true, "zoom": true, "SUID": true, "company_type": true, "company_name_h": true, "interaction": true, "shared_interaction": true, "company_url": true, "line_name": true, "selected": true, "company_name": true, "company_cd": true, "name": true, "rr_cd": true, "company_name_r": true, "e_status_x": true, "shared_name": true, "lat": true, "e_status_y": true, "line_name_h": true, }, }, } func TestUnmarshalNodeEdge(t *testing.T) { for _, test := range cytoscapejsNodeEdgeTests { data, err := os.ReadFile(filepath.Join("testdata", test.path)) if err != nil { t.Errorf("failed to read %q: %v", test.path, err) continue } var got Elements err = json.Unmarshal(data, &got) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } if len(got.Nodes) != test.wantNodes { t.Errorf("unexpected result for order of %q: got:%d want:%d", test.path, len(got.Nodes), test.wantNodes) } if len(got.Edges) != test.wantEdges { t.Errorf("unexpected result for size of %q: got:%d want:%d", test.path, len(got.Edges), test.wantEdges) } if test.wantGraph != nil { if !reflect.DeepEqual(&got, test.wantGraph) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got.Nodes, test.wantGraph.Nodes) } } else { if !reflect.DeepEqual(got.Nodes[0], test.firstNode) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got.Nodes[0], test.firstNode) } if !reflect.DeepEqual(got.Edges[0], test.firstEdge) { t.Errorf("unexpected result for %q:\ngot:\n%v\nwant:\n%#v", test.path, got.Edges[0].Data.Source, test.firstEdge.Data.Source) } } if test.wantNodeAttributes != nil { var paths []string for _, n := range got.Nodes { paths = attrPaths(paths, "", n.Data.Attributes) } gotAttrs := make(map[string]bool) for _, p := range paths { gotAttrs[p] = true } if !reflect.DeepEqual(gotAttrs, test.wantNodeAttributes) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, gotAttrs, test.wantNodeAttributes) } } if test.wantEdgeAttributes != nil { var paths []string for _, e := range got.Edges { paths = attrPaths(paths, "", e.Data.Attributes) } gotAttrs := make(map[string]bool) for _, p := range paths { gotAttrs[p] = true } if !reflect.DeepEqual(gotAttrs, test.wantEdgeAttributes) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, gotAttrs, test.wantEdgeAttributes) } } } } func TestMarshalNodeEdge(t *testing.T) { for _, test := range cytoscapejsNodeEdgeTests { data, err := os.ReadFile(filepath.Join("testdata", test.path)) if err != nil { t.Errorf("failed to read %q: %v", test.path, err) continue } var want Elements err = json.Unmarshal(data, &want) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } marshaled, err := json.Marshal(want) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } var got Elements err = json.Unmarshal(marshaled, &got) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } if !reflect.DeepEqual(got, want) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, want) } } } func attrPaths(dst []string, prefix string, m map[string]interface{}) []string { for k, v := range m { path := prefix if path != "" { path += "." } if v, ok := v.(map[string]interface{}); ok { dst = attrPaths(dst, path+k, v) } dst = append(dst, path+k) } return dst } golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/testdata/000077500000000000000000000000001450372207100245525ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/testdata/LICENSE000066400000000000000000000020741450372207100255620ustar00rootroot00000000000000 Copyright (c) 2016-2018, The Cytoscape Consortium. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/testdata/cola-compound.json000066400000000000000000000015201450372207100302030ustar00rootroot00000000000000{ "nodes": [ { "data": { "id": "compound-1" } }, { "data": { "id": "compound-2" } }, { "data": { "id": "compound-3" } }, { "data": { "id": "b", "parent": "compound-1" } }, { "data": { "id": "c", "parent": "compound-1" } }, { "data": { "id": "a", "parent": "compound-2" } }, { "data": { "id": "d", "parent": "compound-3" } }, { "data": { "id": "e", "parent": "compound-3" } }, { "data": { "id": "f" } } ], "edges": [ { "data": { "id": "ab", "source": "a", "target": "b" } }, { "data": { "id": "bc", "source": "b", "target": "c" } }, { "data": { "id": "ac", "source": "a", "target": "c" } }, { "data": { "id": "cd", "source": "c", "target": "d" } }, { "data": { "id": "de", "source": "d", "target": "e" } }, { "data": { "id": "df", "source": "d", "target": "f" } }, { "data": { "id": "af", "source": "a", "target": "f" } } ] }golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/testdata/edge-type.json000066400000000000000000000030431450372207100273300ustar00rootroot00000000000000[{ "data": { "id": "n01", "type": "bezier" } }, { "data": { "id": "n02" } }, { "data": { "id": "e01", "source": "n01", "target": "n02" }, "classes": "bezier" }, { "data": { "id": "e02", "source": "n01", "target": "n02" }, "classes": "bezier" }, { "data": { "id": "e03", "source": "n02", "target": "n01" }, "classes": "bezier" }, { "data": { "id": "n03", "type": "unbundled-bezier" } }, { "data": { "id": "n04" } }, { "data": { "id": "e04", "source": "n03", "target": "n04" }, "classes": "unbundled-bezier" }, { "data": { "id": "n05", "type": "unbundled-bezier(multiple)" } }, { "data": { "id": "n06" } }, { "data": { "id": "e05", "source": "n05", "target": "n06" }, "classes": "multi-unbundled-bezier" }, { "data": { "id": "n07", "type": "haystack" } }, { "data": { "id": "n08" } }, { "data": { "id": "e06", "source": "n08", "target": "n07" }, "classes": "haystack" }, { "data": { "id": "e07", "source": "n08", "target": "n07" }, "classes": "haystack" }, { "data": { "id": "e08", "source": "n08", "target": "n07" }, "classes": "haystack" }, { "data": { "id": "e09", "source": "n08", "target": "n07" }, "classes": "haystack" }, { "data": { "id": "n09", "type": "segments" } }, { "data": { "id": "n10" } }, { "data": { "id": "e10", "source": "n09", "target": "n10" }, "classes": "segments" }] golang-gonum-v1-gonum-0.14.0/graph/formats/cytoscapejs/testdata/tokyo-railways.json000066400000000000000000053074721450372207100304650ustar00rootroot00000000000000{ "nodes" : [ { "data" : { "id" : "8220", "station_name" : "京成高砂", "close_ymd" : "", "lon" : 139.866875, "post" : "", "e_status" : 0, "SUID" : 8220, "station_g_cd" : 2300110, "add" : "東京都葛飾区高砂五丁目28-1", "line_cd" : 99340, "selected" : false, "open_ymd" : "", "name" : "9934001", "pref_name" : "東京都", "shared_name" : "9934001", "lat" : 35.750932, "y" : -357509.32, "x" : 1398668.75 }, "position" : { "x" : 1398668.75, "y" : -357509.32 }, "selected" : false }, { "data" : { "id" : "8221", "station_name" : "新柴又", "close_ymd" : "", "lon" : 139.879376, "post" : "125-0052", "e_status" : 0, "SUID" : 8221, "station_g_cd" : 9934002, "add" : "葛飾区柴又5-7-1", "line_cd" : 99340, "selected" : false, "open_ymd" : "", "name" : "9934002", "pref_name" : "東京都", "shared_name" : "9934002", "lat" : 35.75101, "y" : -357510.10000000003, "x" : 1398793.76 }, "position" : { "x" : 1398793.76, "y" : -357510.10000000003 }, "selected" : false }, { "data" : { "id" : "5901", "station_name" : "日本橋", "close_ymd" : "", "lon" : 139.773516, "post" : "103-0027", "e_status" : 0, "SUID" : 5901, "station_g_cd" : 2800109, "add" : "中央区日本橋1丁目", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800109", "pref_name" : "東京都", "shared_name" : "2800109", "lat" : 35.682078000000004, "y" : -356820.78, "x" : 1397735.16 }, "position" : { "x" : 1397735.16, "y" : -356820.78 }, "selected" : false }, { "data" : { "id" : "5902", "station_name" : "京橋", "close_ymd" : "", "lon" : 139.770126, "post" : "104-0031", "e_status" : 0, "SUID" : 5902, "station_g_cd" : 2800110, "add" : "中央区京橋2-2-10", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800110", "pref_name" : "東京都", "shared_name" : "2800110", "lat" : 35.676856, "y" : -356768.56, "x" : 1397701.26 }, "position" : { "x" : 1397701.26, "y" : -356768.56 }, "selected" : false }, { "data" : { "id" : "5903", "station_name" : "銀座", "close_ymd" : "", "lon" : 139.76396499999998, "post" : "104-0061", "e_status" : 0, "SUID" : 5903, "station_g_cd" : 2800111, "add" : "中央区銀座4-1-2", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800111", "pref_name" : "東京都", "shared_name" : "2800111", "lat" : 35.671989, "y" : -356719.89, "x" : 1397639.65 }, "position" : { "x" : 1397639.65, "y" : -356719.89 }, "selected" : false }, { "data" : { "id" : "5904", "station_name" : "新橋", "close_ymd" : "", "lon" : 139.758432, "post" : "", "e_status" : 0, "SUID" : 5904, "station_g_cd" : 1130102, "add" : "東京都港区新橋二丁目17-5", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800112", "pref_name" : "東京都", "shared_name" : "2800112", "lat" : 35.667434, "y" : -356674.34, "x" : 1397584.32 }, "position" : { "x" : 1397584.32, "y" : -356674.34 }, "selected" : false }, { "data" : { "id" : "5905", "station_name" : "虎ノ門", "close_ymd" : "", "lon" : 139.749832, "post" : "105-0001", "e_status" : 0, "SUID" : 5905, "station_g_cd" : 2800113, "add" : "港区虎ノ門1-1-21", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800113", "pref_name" : "東京都", "shared_name" : "2800113", "lat" : 35.670235999999996, "y" : -356702.3599999999, "x" : 1397498.32 }, "position" : { "x" : 1397498.32, "y" : -356702.3599999999 }, "selected" : false }, { "data" : { "id" : "5906", "station_name" : "溜池山王", "close_ymd" : "", "lon" : 139.741419, "post" : "100-0014", "e_status" : 0, "SUID" : 5906, "station_g_cd" : 2800114, "add" : "千代田区永田町2-11-1", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800114", "pref_name" : "東京都", "shared_name" : "2800114", "lat" : 35.673621000000004, "y" : -356736.21, "x" : 1397414.1900000002 }, "position" : { "x" : 1397414.1900000002, "y" : -356736.21 }, "selected" : false }, { "data" : { "id" : "5907", "station_name" : "赤坂見附", "close_ymd" : "", "lon" : 139.737047, "post" : "107-0052", "e_status" : 0, "SUID" : 5907, "station_g_cd" : 2800115, "add" : "港区赤坂3-1-6", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800115", "pref_name" : "東京都", "shared_name" : "2800115", "lat" : 35.677021, "y" : -356770.21, "x" : 1397370.47 }, "position" : { "x" : 1397370.47, "y" : -356770.21 }, "selected" : false }, { "data" : { "id" : "5908", "station_name" : "青山一丁目", "close_ymd" : "", "lon" : 139.72415900000001, "post" : "107-0062", "e_status" : 0, "SUID" : 5908, "station_g_cd" : 2800116, "add" : "港区南青山1-1-19", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800116", "pref_name" : "東京都", "shared_name" : "2800116", "lat" : 35.672765000000005, "y" : -356727.6500000001, "x" : 1397241.59 }, "position" : { "x" : 1397241.59, "y" : -356727.6500000001 }, "selected" : false }, { "data" : { "id" : "5893", "station_name" : "浅草", "close_ymd" : "", "lon" : 139.79759199999998, "post" : "", "e_status" : 0, "SUID" : 5893, "station_g_cd" : 2100201, "add" : "東京都台東区", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800101", "pref_name" : "東京都", "shared_name" : "2800101", "lat" : 35.710733000000005, "y" : -357107.3300000001, "x" : 1397975.9199999997 }, "position" : { "x" : 1397975.9199999997, "y" : -357107.3300000001 }, "selected" : false }, { "data" : { "id" : "5894", "station_name" : "田原町", "close_ymd" : "", "lon" : 139.790897, "post" : "111-0035", "e_status" : 0, "SUID" : 5894, "station_g_cd" : 2800102, "add" : "台東区西浅草1-1-18", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800102", "pref_name" : "東京都", "shared_name" : "2800102", "lat" : 35.709897, "y" : -357098.97, "x" : 1397908.97 }, "position" : { "x" : 1397908.97, "y" : -357098.97 }, "selected" : false }, { "data" : { "id" : "5895", "station_name" : "稲荷町", "close_ymd" : "", "lon" : 139.782593, "post" : "110-0015", "e_status" : 0, "SUID" : 5895, "station_g_cd" : 2800103, "add" : "台東区東上野3-33-11", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800103", "pref_name" : "東京都", "shared_name" : "2800103", "lat" : 35.711273, "y" : -357112.73, "x" : 1397825.93 }, "position" : { "x" : 1397825.93, "y" : -357112.73 }, "selected" : false }, { "data" : { "id" : "5896", "station_name" : "上野", "close_ymd" : "", "lon" : 139.777122, "post" : "", "e_status" : 0, "SUID" : 5896, "station_g_cd" : 1130220, "add" : "東京都台東区東上野三丁目19-6", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800104", "pref_name" : "東京都", "shared_name" : "2800104", "lat" : 35.711482000000004, "y" : -357114.82000000007, "x" : 1397771.22 }, "position" : { "x" : 1397771.22, "y" : -357114.82000000007 }, "selected" : false }, { "data" : { "id" : "5897", "station_name" : "上野広小路", "close_ymd" : "", "lon" : 139.772877, "post" : "110-0005", "e_status" : 0, "SUID" : 5897, "station_g_cd" : 1130221, "add" : "台東区上野3-29-3", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800105", "pref_name" : "東京都", "shared_name" : "2800105", "lat" : 35.707679999999996, "y" : -357076.8, "x" : 1397728.77 }, "position" : { "x" : 1397728.77, "y" : -357076.8 }, "selected" : false }, { "data" : { "id" : "5898", "station_name" : "末広町", "close_ymd" : "", "lon" : 139.77171299999998, "post" : "101-0021", "e_status" : 0, "SUID" : 5898, "station_g_cd" : 2800106, "add" : "千代田区外神田4-7-3", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800106", "pref_name" : "東京都", "shared_name" : "2800106", "lat" : 35.702971999999995, "y" : -357029.72, "x" : 1397717.1299999997 }, "position" : { "x" : 1397717.1299999997, "y" : -357029.72 }, "selected" : false }, { "data" : { "id" : "5899", "station_name" : "神田", "close_ymd" : "", "lon" : 139.770899, "post" : "", "e_status" : 0, "SUID" : 5899, "station_g_cd" : 1130223, "add" : "東京都千代田区神田須田町一丁目16", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800107", "pref_name" : "東京都", "shared_name" : "2800107", "lat" : 35.693587, "y" : -356935.87, "x" : 1397708.9899999998 }, "position" : { "x" : 1397708.9899999998, "y" : -356935.87 }, "selected" : false }, { "data" : { "id" : "5900", "station_name" : "三越前", "close_ymd" : "", "lon" : 139.773594, "post" : "103-0022", "e_status" : 0, "SUID" : 5900, "station_g_cd" : 1131402, "add" : "中央区日本橋室町1-8-1", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800108", "pref_name" : "東京都", "shared_name" : "2800108", "lat" : 35.687101, "y" : -356871.01, "x" : 1397735.94 }, "position" : { "x" : 1397735.94, "y" : -356871.01 }, "selected" : false }, { "data" : { "id" : "5871", "station_name" : "羽田空港国際線ターミナル", "close_ymd" : "", "lon" : 139.768968, "post" : "144-0041", "e_status" : 0, "SUID" : 5871, "station_g_cd" : 2700207, "add" : "東京都大田区羽田空港二丁目6番5号", "line_cd" : 27002, "selected" : false, "open_ymd" : "2010-10-21", "name" : "2700207", "pref_name" : "東京都", "shared_name" : "2700207", "lat" : 35.544676, "y" : -355446.76, "x" : 1397689.68 }, "position" : { "x" : 1397689.68, "y" : -355446.76 }, "selected" : false }, { "data" : { "id" : "5872", "station_name" : "羽田空港", "close_ymd" : "", "lon" : 139.785962, "post" : "144-0041", "e_status" : 0, "SUID" : 5872, "station_g_cd" : 2700206, "add" : "大田区羽田空港3-3-4", "line_cd" : 27002, "selected" : false, "open_ymd" : "", "name" : "2700206", "pref_name" : "東京都", "shared_name" : "2700206", "lat" : 35.549809, "y" : -355498.09, "x" : 1397859.62 }, "position" : { "x" : 1397859.62, "y" : -355498.09 }, "selected" : false }, { "data" : { "id" : "5869", "station_name" : "穴守稲荷", "close_ymd" : "", "lon" : 139.746669, "post" : "144-0043", "e_status" : 0, "SUID" : 5869, "station_g_cd" : 2700204, "add" : "大田区羽田4-6-11", "line_cd" : 27002, "selected" : false, "open_ymd" : "", "name" : "2700204", "pref_name" : "東京都", "shared_name" : "2700204", "lat" : 35.550326, "y" : -355503.26, "x" : 1397466.69 }, "position" : { "x" : 1397466.69, "y" : -355503.26 }, "selected" : false }, { "data" : { "id" : "5870", "station_name" : "天空橋", "close_ymd" : "", "lon" : 139.75423, "post" : "144-0041", "e_status" : 0, "SUID" : 5870, "station_g_cd" : 2700205, "add" : "大田区羽田空港1-1-2", "line_cd" : 27002, "selected" : false, "open_ymd" : "", "name" : "2700205", "pref_name" : "東京都", "shared_name" : "2700205", "lat" : 35.548908000000004, "y" : -355489.08, "x" : 1397542.3 }, "position" : { "x" : 1397542.3, "y" : -355489.08 }, "selected" : false }, { "data" : { "id" : "5867", "station_name" : "糀谷", "close_ymd" : "", "lon" : 139.72961999999998, "post" : "144-0034", "e_status" : 0, "SUID" : 5867, "station_g_cd" : 2700202, "add" : "大田区西糀谷4-13-17", "line_cd" : 27002, "selected" : false, "open_ymd" : "", "name" : "2700202", "pref_name" : "東京都", "shared_name" : "2700202", "lat" : 35.5545, "y" : -355545.0, "x" : 1397296.1999999997 }, "position" : { "x" : 1397296.1999999997, "y" : -355545.0 }, "selected" : false }, { "data" : { "id" : "5868", "station_name" : "大鳥居", "close_ymd" : "", "lon" : 139.73935600000002, "post" : "144-0034", "e_status" : 0, "SUID" : 5868, "station_g_cd" : 2700203, "add" : "大田区西糀谷3-37-18", "line_cd" : 27002, "selected" : false, "open_ymd" : "", "name" : "2700203", "pref_name" : "東京都", "shared_name" : "2700203", "lat" : 35.552531, "y" : -355525.31, "x" : 1397393.56 }, "position" : { "x" : 1397393.56, "y" : -355525.31 }, "selected" : false }, { "data" : { "id" : "5866", "station_name" : "京急蒲田", "close_ymd" : "", "lon" : 139.723681, "post" : "144-0052", "e_status" : 0, "SUID" : 5866, "station_g_cd" : 2700112, "add" : "大田区蒲田4-50-10", "line_cd" : 27002, "selected" : false, "open_ymd" : "", "name" : "2700201", "pref_name" : "東京都", "shared_name" : "2700201", "lat" : 35.560796, "y" : -355607.96, "x" : 1397236.81 }, "position" : { "x" : 1397236.81, "y" : -355607.96 }, "selected" : false }, { "data" : { "id" : "5826", "station_name" : "梅屋敷", "close_ymd" : "", "lon" : 139.728266, "post" : "144-0052", "e_status" : 0, "SUID" : 5826, "station_g_cd" : 2700111, "add" : "大田区蒲田2-28-1", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700111", "pref_name" : "東京都", "shared_name" : "2700111", "lat" : 35.566873, "y" : -355668.73000000004, "x" : 1397282.66 }, "position" : { "x" : 1397282.66, "y" : -355668.73000000004 }, "selected" : false }, { "data" : { "id" : "5825", "station_name" : "大森町", "close_ymd" : "", "lon" : 139.732027, "post" : "143-0015", "e_status" : 0, "SUID" : 5825, "station_g_cd" : 2700110, "add" : "大田区大森西3-24-7", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700110", "pref_name" : "東京都", "shared_name" : "2700110", "lat" : 35.572431, "y" : -355724.31, "x" : 1397320.2699999998 }, "position" : { "x" : 1397320.2699999998, "y" : -355724.31 }, "selected" : false }, { "data" : { "id" : "5828", "station_name" : "雑色", "close_ymd" : "", "lon" : 139.715005, "post" : "144-0055", "e_status" : 0, "SUID" : 5828, "station_g_cd" : 2700113, "add" : "大田区仲六郷2-42-1", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700113", "pref_name" : "東京都", "shared_name" : "2700113", "lat" : 35.549725, "y" : -355497.25, "x" : 1397150.0499999998 }, "position" : { "x" : 1397150.0499999998, "y" : -355497.25 }, "selected" : false }, { "data" : { "id" : "5827", "station_name" : "京急蒲田", "close_ymd" : "", "lon" : 139.723681, "post" : "144-0052", "e_status" : 0, "SUID" : 5827, "station_g_cd" : 2700112, "add" : "大田区蒲田4-50-10", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700112", "pref_name" : "東京都", "shared_name" : "2700112", "lat" : 35.560796, "y" : -355607.96, "x" : 1397236.81 }, "position" : { "x" : 1397236.81, "y" : -355607.96 }, "selected" : false }, { "data" : { "id" : "5822", "station_name" : "立会川", "close_ymd" : "", "lon" : 139.738886, "post" : "140-0011", "e_status" : 0, "SUID" : 5822, "station_g_cd" : 2700107, "add" : "品川区東大井2-23-1", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700107", "pref_name" : "東京都", "shared_name" : "2700107", "lat" : 35.598489, "y" : -355984.89, "x" : 1397388.86 }, "position" : { "x" : 1397388.86, "y" : -355984.89 }, "selected" : false }, { "data" : { "id" : "5821", "station_name" : "鮫洲", "close_ymd" : "", "lon" : 139.742227, "post" : "140-0011", "e_status" : 0, "SUID" : 5821, "station_g_cd" : 2700106, "add" : "品川区東大井1-2-20", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700106", "pref_name" : "東京都", "shared_name" : "2700106", "lat" : 35.604977000000005, "y" : -356049.7700000001, "x" : 1397422.2700000003 }, "position" : { "x" : 1397422.2700000003, "y" : -356049.7700000001 }, "selected" : false }, { "data" : { "id" : "5824", "station_name" : "平和島", "close_ymd" : "", "lon" : 139.73491, "post" : "143-0016", "e_status" : 0, "SUID" : 5824, "station_g_cd" : 2700109, "add" : "大田区大森北6-13-11", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700109", "pref_name" : "東京都", "shared_name" : "2700109", "lat" : 35.57868, "y" : -355786.8, "x" : 1397349.1 }, "position" : { "x" : 1397349.1, "y" : -355786.8 }, "selected" : false }, { "data" : { "id" : "5823", "station_name" : "大森海岸", "close_ymd" : "", "lon" : 139.73543999999998, "post" : "140-0013", "e_status" : 0, "SUID" : 5823, "station_g_cd" : 2700108, "add" : "品川区南大井3-32-1", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700108", "pref_name" : "東京都", "shared_name" : "2700108", "lat" : 35.587576, "y" : -355875.76, "x" : 1397354.4 }, "position" : { "x" : 1397354.4, "y" : -355875.76 }, "selected" : false }, { "data" : { "id" : "5818", "station_name" : "北品川", "close_ymd" : "", "lon" : 139.739191, "post" : "140-0001", "e_status" : 0, "SUID" : 5818, "station_g_cd" : 2700103, "add" : "品川区北品川1-1-4", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700103", "pref_name" : "東京都", "shared_name" : "2700103", "lat" : 35.622458, "y" : -356224.58, "x" : 1397391.9100000001 }, "position" : { "x" : 1397391.9100000001, "y" : -356224.58 }, "selected" : false }, { "data" : { "id" : "5817", "station_name" : "品川", "close_ymd" : "", "lon" : 139.73809, "post" : "", "e_status" : 0, "SUID" : 5817, "station_g_cd" : 1130103, "add" : "東京都港区高輪三丁目26-26", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700102", "pref_name" : "東京都", "shared_name" : "2700102", "lat" : 35.628284, "y" : -356282.84, "x" : 1397380.9 }, "position" : { "x" : 1397380.9, "y" : -356282.84 }, "selected" : false }, { "data" : { "id" : "5820", "station_name" : "青物横丁", "close_ymd" : "", "lon" : 139.74295800000002, "post" : "140-0004", "e_status" : 0, "SUID" : 5820, "station_g_cd" : 2700105, "add" : "品川区南品川3-1-20", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700105", "pref_name" : "東京都", "shared_name" : "2700105", "lat" : 35.609351000000004, "y" : -356093.51, "x" : 1397429.58 }, "position" : { "x" : 1397429.58, "y" : -356093.51 }, "selected" : false }, { "data" : { "id" : "5819", "station_name" : "新馬場", "close_ymd" : "", "lon" : 139.741366, "post" : "140-0001", "e_status" : 0, "SUID" : 5819, "station_g_cd" : 2700104, "add" : "品川区北品川2-18-1", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700104", "pref_name" : "東京都", "shared_name" : "2700104", "lat" : 35.61762, "y" : -356176.2, "x" : 1397413.66 }, "position" : { "x" : 1397413.66, "y" : -356176.2 }, "selected" : false }, { "data" : { "id" : "5816", "station_name" : "泉岳寺", "close_ymd" : "", "lon" : 139.74002, "post" : "108-0074", "e_status" : 0, "SUID" : 5816, "station_g_cd" : 2700101, "add" : "港区高輪2-16-34", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700101", "pref_name" : "東京都", "shared_name" : "2700101", "lat" : 35.638692, "y" : -356386.92, "x" : 1397400.2 }, "position" : { "x" : 1397400.2, "y" : -356386.92 }, "selected" : false }, { "data" : { "id" : "5829", "station_name" : "六郷土手", "close_ymd" : "", "lon" : 139.7076, "post" : "144-0055", "e_status" : 0, "SUID" : 5829, "station_g_cd" : 2700114, "add" : "大田区仲六郷4-27-11", "line_cd" : 27001, "selected" : false, "open_ymd" : "", "name" : "2700114", "pref_name" : "東京都", "shared_name" : "2700114", "lat" : 35.540577, "y" : -355405.77, "x" : 1397076.0000000002 }, "position" : { "x" : 1397076.0000000002, "y" : -355405.77 }, "selected" : false }, { "data" : { "id" : "5796", "station_name" : "多摩川", "close_ymd" : "", "lon" : 139.668723, "post" : "145-0071", "e_status" : 0, "SUID" : 5796, "station_g_cd" : 2600109, "add" : "大田区田園調布1-53-8", "line_cd" : 26006, "selected" : false, "open_ymd" : "", "name" : "2600601", "pref_name" : "東京都", "shared_name" : "2600601", "lat" : 35.589591, "y" : -355895.91, "x" : 1396687.23 }, "position" : { "x" : 1396687.23, "y" : -355895.91 }, "selected" : false }, { "data" : { "id" : "5795", "station_name" : "蒲田", "close_ymd" : "", "lon" : 139.714626, "post" : "144-0052", "e_status" : 0, "SUID" : 5795, "station_g_cd" : 1133230, "add" : "大田区蒲田5丁目", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600515", "pref_name" : "東京都", "shared_name" : "2600515", "lat" : 35.561766999999996, "y" : -355617.67, "x" : 1397146.26 }, "position" : { "x" : 1397146.26, "y" : -355617.67 }, "selected" : false }, { "data" : { "id" : "5794", "station_name" : "蓮沼", "close_ymd" : "", "lon" : 139.708544, "post" : "144-0051", "e_status" : 0, "SUID" : 5794, "station_g_cd" : 2600514, "add" : "大田区西蒲田7-17-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600514", "pref_name" : "東京都", "shared_name" : "2600514", "lat" : 35.564173, "y" : -355641.73, "x" : 1397085.44 }, "position" : { "x" : 1397085.44, "y" : -355641.73 }, "selected" : false }, { "data" : { "id" : "5793", "station_name" : "池上", "close_ymd" : "", "lon" : 139.702822, "post" : "146-0082", "e_status" : 0, "SUID" : 5793, "station_g_cd" : 2600513, "add" : "大田区池上6-3-10", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600513", "pref_name" : "東京都", "shared_name" : "2600513", "lat" : 35.572025, "y" : -355720.24999999994, "x" : 1397028.22 }, "position" : { "x" : 1397028.22, "y" : -355720.24999999994 }, "selected" : false }, { "data" : { "id" : "5792", "station_name" : "千鳥町", "close_ymd" : "", "lon" : 139.69142, "post" : "146-0083", "e_status" : 0, "SUID" : 5792, "station_g_cd" : 2600512, "add" : "大田区千鳥1-20-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600512", "pref_name" : "東京都", "shared_name" : "2600512", "lat" : 35.572983, "y" : -355729.83, "x" : 1396914.2 }, "position" : { "x" : 1396914.2, "y" : -355729.83 }, "selected" : false }, { "data" : { "id" : "5791", "station_name" : "久が原", "close_ymd" : "", "lon" : 139.685678, "post" : "146-0084", "e_status" : 0, "SUID" : 5791, "station_g_cd" : 2600511, "add" : "大田区南久が原2-6-10", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600511", "pref_name" : "東京都", "shared_name" : "2600511", "lat" : 35.579499, "y" : -355794.99, "x" : 1396856.78 }, "position" : { "x" : 1396856.78, "y" : -355794.99 }, "selected" : false }, { "data" : { "id" : "5790", "station_name" : "御嶽山", "close_ymd" : "", "lon" : 139.682473, "post" : "145-0073", "e_status" : 0, "SUID" : 5790, "station_g_cd" : 2600510, "add" : "大田区北嶺町32-17", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600510", "pref_name" : "東京都", "shared_name" : "2600510", "lat" : 35.585236, "y" : -355852.36000000004, "x" : 1396824.73 }, "position" : { "x" : 1396824.73, "y" : -355852.36000000004 }, "selected" : false }, { "data" : { "id" : "5789", "station_name" : "雪が谷大塚", "close_ymd" : "", "lon" : 139.681083, "post" : "145-0066", "e_status" : 0, "SUID" : 5789, "station_g_cd" : 2600509, "add" : "大田区南雪谷2-2-16", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600509", "pref_name" : "東京都", "shared_name" : "2600509", "lat" : 35.592038, "y" : -355920.38, "x" : 1396810.83 }, "position" : { "x" : 1396810.83, "y" : -355920.38 }, "selected" : false }, { "data" : { "id" : "5788", "station_name" : "石川台", "close_ymd" : "", "lon" : 139.68506299999999, "post" : "145-0065", "e_status" : 0, "SUID" : 5788, "station_g_cd" : 2600508, "add" : "大田区東雪谷2-23-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600508", "pref_name" : "東京都", "shared_name" : "2600508", "lat" : 35.596888, "y" : -355968.88, "x" : 1396850.63 }, "position" : { "x" : 1396850.63, "y" : -355968.88 }, "selected" : false }, { "data" : { "id" : "5787", "station_name" : "洗足池", "close_ymd" : "", "lon" : 139.690896, "post" : "145-0065", "e_status" : 0, "SUID" : 5787, "station_g_cd" : 2600507, "add" : "大田区東雪谷1-1-6", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600507", "pref_name" : "東京都", "shared_name" : "2600507", "lat" : 35.599647999999995, "y" : -355996.4799999999, "x" : 1396908.9600000002 }, "position" : { "x" : 1396908.9600000002, "y" : -355996.4799999999 }, "selected" : false }, { "data" : { "id" : "5786", "station_name" : "長原", "close_ymd" : "", "lon" : 139.697881, "post" : "145-0064", "e_status" : 0, "SUID" : 5786, "station_g_cd" : 2600506, "add" : "大田区上池台1-10-10", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600506", "pref_name" : "東京都", "shared_name" : "2600506", "lat" : 35.60219, "y" : -356021.9, "x" : 1396978.81 }, "position" : { "x" : 1396978.81, "y" : -356021.9 }, "selected" : false }, { "data" : { "id" : "5785", "station_name" : "旗の台", "close_ymd" : "", "lon" : 139.70228600000002, "post" : "142-0064", "e_status" : 0, "SUID" : 5785, "station_g_cd" : 2600406, "add" : "品川区旗の台2-13-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600505", "pref_name" : "東京都", "shared_name" : "2600505", "lat" : 35.604923, "y" : -356049.23, "x" : 1397022.86 }, "position" : { "x" : 1397022.86, "y" : -356049.23 }, "selected" : false }, { "data" : { "id" : "5784", "station_name" : "荏原中延", "close_ymd" : "", "lon" : 139.712196, "post" : "142-0053", "e_status" : 0, "SUID" : 5784, "station_g_cd" : 2600504, "add" : "品川区中延2-8-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600504", "pref_name" : "東京都", "shared_name" : "2600504", "lat" : 35.610056, "y" : -356100.56, "x" : 1397121.96 }, "position" : { "x" : 1397121.96, "y" : -356100.56 }, "selected" : false }, { "data" : { "id" : "5783", "station_name" : "戸越銀座", "close_ymd" : "", "lon" : 139.714862, "post" : "142-0051", "e_status" : 0, "SUID" : 5783, "station_g_cd" : 2600503, "add" : "品川区平塚2-16-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600503", "pref_name" : "東京都", "shared_name" : "2600503", "lat" : 35.615928000000004, "y" : -356159.28, "x" : 1397148.62 }, "position" : { "x" : 1397148.62, "y" : -356159.28 }, "selected" : false }, { "data" : { "id" : "5782", "station_name" : "大崎広小路", "close_ymd" : "", "lon" : 139.72233899999998, "post" : "141-0032", "e_status" : 0, "SUID" : 5782, "station_g_cd" : 2600502, "add" : "品川区大崎4-1-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600502", "pref_name" : "東京都", "shared_name" : "2600502", "lat" : 35.622244, "y" : -356222.44, "x" : 1397223.3899999997 }, "position" : { "x" : 1397223.3899999997, "y" : -356222.44 }, "selected" : false }, { "data" : { "id" : "5781", "station_name" : "五反田", "close_ymd" : "", "lon" : 139.724175, "post" : "", "e_status" : 0, "SUID" : 5781, "station_g_cd" : 1130202, "add" : "東京都品川区東五反田二丁目1-1", "line_cd" : 26005, "selected" : false, "open_ymd" : "", "name" : "2600501", "pref_name" : "東京都", "shared_name" : "2600501", "lat" : 35.625262, "y" : -356252.62, "x" : 1397241.75 }, "position" : { "x" : 1397241.75, "y" : -356252.62 }, "selected" : false }, { "data" : { "id" : "5811", "station_name" : "松原", "close_ymd" : "", "lon" : 139.642, "post" : "156-0043", "e_status" : 0, "SUID" : 5811, "station_g_cd" : 2600709, "add" : "世田谷区松原4-10-8", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600709", "pref_name" : "東京都", "shared_name" : "2600709", "lat" : 35.660047999999996, "y" : -356600.48, "x" : 1396420.0 }, "position" : { "x" : 1396420.0, "y" : -356600.48 }, "selected" : false }, { "data" : { "id" : "5812", "station_name" : "下高井戸", "close_ymd" : "", "lon" : 139.641372, "post" : "156-0043", "e_status" : 0, "SUID" : 5812, "station_g_cd" : 2400107, "add" : "世田谷区松原3-29-17", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600710", "pref_name" : "東京都", "shared_name" : "2600710", "lat" : 35.66615, "y" : -356661.5, "x" : 1396413.72 }, "position" : { "x" : 1396413.72, "y" : -356661.5 }, "selected" : false }, { "data" : { "id" : "5809", "station_name" : "宮の坂", "close_ymd" : "", "lon" : 139.64494, "post" : "156-0051", "e_status" : 0, "SUID" : 5809, "station_g_cd" : 2600707, "add" : "世田谷区宮坂1-24-7", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600707", "pref_name" : "東京都", "shared_name" : "2600707", "lat" : 35.647508, "y" : -356475.08, "x" : 1396449.4 }, "position" : { "x" : 1396449.4, "y" : -356475.08 }, "selected" : false }, { "data" : { "id" : "5810", "station_name" : "山下", "close_ymd" : "", "lon" : 139.646509, "post" : "154-0021", "e_status" : 0, "SUID" : 5810, "station_g_cd" : 2500110, "add" : "世田谷区豪徳寺1-44-5", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600708", "pref_name" : "東京都", "shared_name" : "2600708", "lat" : 35.653844, "y" : -356538.44, "x" : 1396465.09 }, "position" : { "x" : 1396465.09, "y" : -356538.44 }, "selected" : false }, { "data" : { "id" : "5807", "station_name" : "世田谷", "close_ymd" : "", "lon" : 139.650945, "post" : "154-0017", "e_status" : 0, "SUID" : 5807, "station_g_cd" : 2600705, "add" : "世田谷区世田谷4-9-6", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600705", "pref_name" : "東京都", "shared_name" : "2600705", "lat" : 35.643564000000005, "y" : -356435.6400000001, "x" : 1396509.4500000002 }, "position" : { "x" : 1396509.4500000002, "y" : -356435.6400000001 }, "selected" : false }, { "data" : { "id" : "5808", "station_name" : "上町", "close_ymd" : "", "lon" : 139.646276, "post" : "154-0017", "e_status" : 0, "SUID" : 5808, "station_g_cd" : 2600706, "add" : "世田谷区世田谷3-4-3", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600706", "pref_name" : "東京都", "shared_name" : "2600706", "lat" : 35.643656, "y" : -356436.56, "x" : 1396462.76 }, "position" : { "x" : 1396462.76, "y" : -356436.56 }, "selected" : false }, { "data" : { "id" : "5805", "station_name" : "若林", "close_ymd" : "", "lon" : 139.65991100000002, "post" : "154-0023", "e_status" : 0, "SUID" : 5805, "station_g_cd" : 2600703, "add" : "世田谷区若林4-3-15", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600703", "pref_name" : "東京都", "shared_name" : "2600703", "lat" : 35.645933, "y" : -356459.33, "x" : 1396599.1100000003 }, "position" : { "x" : 1396599.1100000003, "y" : -356459.33 }, "selected" : false }, { "data" : { "id" : "5806", "station_name" : "松陰神社前", "close_ymd" : "", "lon" : 139.655211, "post" : "154-0023", "e_status" : 0, "SUID" : 5806, "station_g_cd" : 2600704, "add" : "世田谷区若林4-21-16", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600704", "pref_name" : "東京都", "shared_name" : "2600704", "lat" : 35.643947, "y" : -356439.47, "x" : 1396552.11 }, "position" : { "x" : 1396552.11, "y" : -356439.47 }, "selected" : false }, { "data" : { "id" : "5803", "station_name" : "三軒茶屋", "close_ymd" : "", "lon" : 139.670156, "post" : "154-0004", "e_status" : 0, "SUID" : 5803, "station_g_cd" : 2600303, "add" : "世田谷区太子堂4-21-1", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600701", "pref_name" : "東京都", "shared_name" : "2600701", "lat" : 35.643716, "y" : -356437.16, "x" : 1396701.5599999998 }, "position" : { "x" : 1396701.5599999998, "y" : -356437.16 }, "selected" : false }, { "data" : { "id" : "5804", "station_name" : "西太子堂", "close_ymd" : "", "lon" : 139.666382, "post" : "154-0004", "e_status" : 0, "SUID" : 5804, "station_g_cd" : 2600702, "add" : "世田谷区太子堂4-10-3", "line_cd" : 26007, "selected" : false, "open_ymd" : "", "name" : "2600702", "pref_name" : "東京都", "shared_name" : "2600702", "lat" : 35.644545, "y" : -356445.45, "x" : 1396663.82 }, "position" : { "x" : 1396663.82, "y" : -356445.45 }, "selected" : false }, { "data" : { "id" : "5801", "station_name" : "矢口渡", "close_ymd" : "", "lon" : 139.700389, "post" : "146-0095", "e_status" : 0, "SUID" : 5801, "station_g_cd" : 2600606, "add" : "大田区多摩川1-20-15", "line_cd" : 26006, "selected" : false, "open_ymd" : "", "name" : "2600606", "pref_name" : "東京都", "shared_name" : "2600606", "lat" : 35.562462, "y" : -355624.61999999994, "x" : 1397003.89 }, "position" : { "x" : 1397003.89, "y" : -355624.61999999994 }, "selected" : false }, { "data" : { "id" : "5802", "station_name" : "蒲田", "close_ymd" : "", "lon" : 139.714626, "post" : "144-0052", "e_status" : 0, "SUID" : 5802, "station_g_cd" : 1133230, "add" : "大田区蒲田5丁目", "line_cd" : 26006, "selected" : false, "open_ymd" : "", "name" : "2600607", "pref_name" : "東京都", "shared_name" : "2600607", "lat" : 35.561766999999996, "y" : -355617.67, "x" : 1397146.26 }, "position" : { "x" : 1397146.26, "y" : -355617.67 }, "selected" : false }, { "data" : { "id" : "5799", "station_name" : "下丸子", "close_ymd" : "", "lon" : 139.685576, "post" : "146-0092", "e_status" : 0, "SUID" : 5799, "station_g_cd" : 2600604, "add" : "大田区下丸子3-7-1", "line_cd" : 26006, "selected" : false, "open_ymd" : "", "name" : "2600604", "pref_name" : "東京都", "shared_name" : "2600604", "lat" : 35.571397, "y" : -355713.97, "x" : 1396855.76 }, "position" : { "x" : 1396855.76, "y" : -355713.97 }, "selected" : false }, { "data" : { "id" : "5800", "station_name" : "武蔵新田", "close_ymd" : "", "lon" : 139.692506, "post" : "146-0093", "e_status" : 0, "SUID" : 5800, "station_g_cd" : 2600605, "add" : "大田区矢口1-18-1", "line_cd" : 26006, "selected" : false, "open_ymd" : "", "name" : "2600605", "pref_name" : "東京都", "shared_name" : "2600605", "lat" : 35.567806, "y" : -355678.06, "x" : 1396925.06 }, "position" : { "x" : 1396925.06, "y" : -355678.06 }, "selected" : false }, { "data" : { "id" : "5797", "station_name" : "沼部", "close_ymd" : "", "lon" : 139.67326, "post" : "145-0072", "e_status" : 0, "SUID" : 5797, "station_g_cd" : 2600602, "add" : "大田区田園調布本町28-1", "line_cd" : 26006, "selected" : false, "open_ymd" : "", "name" : "2600602", "pref_name" : "東京都", "shared_name" : "2600602", "lat" : 35.582526, "y" : -355825.26, "x" : 1396732.6 }, "position" : { "x" : 1396732.6, "y" : -355825.26 }, "selected" : false }, { "data" : { "id" : "5798", "station_name" : "鵜の木", "close_ymd" : "", "lon" : 139.680554, "post" : "146-0091", "e_status" : 0, "SUID" : 5798, "station_g_cd" : 2600603, "add" : "大田区鵜の木2-4-1", "line_cd" : 26006, "selected" : false, "open_ymd" : "", "name" : "2600603", "pref_name" : "東京都", "shared_name" : "2600603", "lat" : 35.575452, "y" : -355754.51999999996, "x" : 1396805.54 }, "position" : { "x" : 1396805.54, "y" : -355754.51999999996 }, "selected" : false }, { "data" : { "id" : "8157", "station_name" : "立川北", "close_ymd" : "", "lon" : 139.41253999999998, "post" : "190-0012", "e_status" : 0, "SUID" : 8157, "station_g_cd" : 9933412, "add" : "立川市曙町2-4", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933412", "pref_name" : "東京都", "shared_name" : "9933412", "lat" : 35.699502, "y" : -356995.02, "x" : 1394125.3999999997 }, "position" : { "x" : 1394125.3999999997, "y" : -356995.02 }, "selected" : false }, { "data" : { "id" : "8158", "station_name" : "高松", "close_ymd" : "", "lon" : 139.413242, "post" : "190-0011", "e_status" : 0, "SUID" : 8158, "station_g_cd" : 9933413, "add" : "立川市高松町1-100", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933413", "pref_name" : "東京都", "shared_name" : "9933413", "lat" : 35.710158, "y" : -357101.58, "x" : 1394132.42 }, "position" : { "x" : 1394132.42, "y" : -357101.58 }, "selected" : false }, { "data" : { "id" : "8159", "station_name" : "立飛", "close_ymd" : "", "lon" : 139.41738700000002, "post" : "190-0015", "e_status" : 0, "SUID" : 8159, "station_g_cd" : 9933414, "add" : "立川市泉町935", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933414", "pref_name" : "東京都", "shared_name" : "9933414", "lat" : 35.714717, "y" : -357147.17, "x" : 1394173.87 }, "position" : { "x" : 1394173.87, "y" : -357147.17 }, "selected" : false }, { "data" : { "id" : "8160", "station_name" : "泉体育館", "close_ymd" : "", "lon" : 139.419525, "post" : "190-0015", "e_status" : 0, "SUID" : 8160, "station_g_cd" : 9933415, "add" : "立川市泉町841", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933415", "pref_name" : "東京都", "shared_name" : "9933415", "lat" : 35.718775, "y" : -357187.75, "x" : 1394195.25 }, "position" : { "x" : 1394195.25, "y" : -357187.75 }, "selected" : false }, { "data" : { "id" : "8161", "station_name" : "砂川七番", "close_ymd" : "", "lon" : 139.418097, "post" : "190-0002", "e_status" : 0, "SUID" : 8161, "station_g_cd" : 9933416, "add" : "立川市幸町5-1", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933416", "pref_name" : "東京都", "shared_name" : "9933416", "lat" : 35.723319000000004, "y" : -357233.19000000006, "x" : 1394180.97 }, "position" : { "x" : 1394180.97, "y" : -357233.19000000006 }, "selected" : false }, { "data" : { "id" : "8162", "station_name" : "玉川上水", "close_ymd" : "", "lon" : 139.417866, "post" : "190-0002", "e_status" : 0, "SUID" : 8162, "station_g_cd" : 2200805, "add" : "立川市幸町6-36-1", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933417", "pref_name" : "東京都", "shared_name" : "9933417", "lat" : 35.73223, "y" : -357322.3, "x" : 1394178.6600000001 }, "position" : { "x" : 1394178.6600000001, "y" : -357322.3 }, "selected" : false }, { "data" : { "id" : "8163", "station_name" : "桜街道", "close_ymd" : "", "lon" : 139.416653, "post" : "207-0023", "e_status" : 0, "SUID" : 8163, "station_g_cd" : 9933418, "add" : "東大和市上北台3-470", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933418", "pref_name" : "東京都", "shared_name" : "9933418", "lat" : 35.739000000000004, "y" : -357390.00000000006, "x" : 1394166.53 }, "position" : { "x" : 1394166.53, "y" : -357390.00000000006 }, "selected" : false }, { "data" : { "id" : "8164", "station_name" : "上北台", "close_ymd" : "", "lon" : 139.415822, "post" : "207-0023", "e_status" : 0, "SUID" : 8164, "station_g_cd" : 9933419, "add" : "東大和市上北台1-742", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933419", "pref_name" : "東京都", "shared_name" : "9933419", "lat" : 35.745824, "y" : -357458.24, "x" : 1394158.22 }, "position" : { "x" : 1394158.22, "y" : -357458.24 }, "selected" : false }, { "data" : { "id" : "8149", "station_name" : "中央大学・明星大学", "close_ymd" : "", "lon" : 139.408672, "post" : "192-0351", "e_status" : 0, "SUID" : 8149, "station_g_cd" : 9933404, "add" : "八王子市東中野742", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933404", "pref_name" : "東京都", "shared_name" : "9933404", "lat" : 35.64197, "y" : -356419.7, "x" : 1394086.72 }, "position" : { "x" : 1394086.72, "y" : -356419.7 }, "selected" : false }, { "data" : { "id" : "5758", "station_name" : "つくし野", "close_ymd" : "", "lon" : 139.485139, "post" : "194-0001", "e_status" : 0, "SUID" : 5758, "station_g_cd" : 2600323, "add" : "町田市つくし野4-1", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600323", "pref_name" : "東京都", "shared_name" : "2600323", "lat" : 35.527559000000004, "y" : -355275.59, "x" : 1394851.3900000001 }, "position" : { "x" : 1394851.3900000001, "y" : -355275.59 }, "selected" : false }, { "data" : { "id" : "8150", "station_name" : "多摩動物公園", "close_ymd" : "", "lon" : 139.403672, "post" : "191-0042", "e_status" : 0, "SUID" : 8150, "station_g_cd" : 2400502, "add" : "日野市程久保3-36-39", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933405", "pref_name" : "東京都", "shared_name" : "9933405", "lat" : 35.648666, "y" : -356486.66, "x" : 1394036.72 }, "position" : { "x" : 1394036.72, "y" : -356486.66 }, "selected" : false }, { "data" : { "id" : "5759", "station_name" : "すずかけ台", "close_ymd" : "", "lon" : 139.481684, "post" : "194-0001", "e_status" : 0, "SUID" : 5759, "station_g_cd" : 2600324, "add" : "町田市つくし野3-1", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600324", "pref_name" : "東京都", "shared_name" : "2600324", "lat" : 35.517094, "y" : -355170.94, "x" : 1394816.84 }, "position" : { "x" : 1394816.84, "y" : -355170.94 }, "selected" : false }, { "data" : { "id" : "8151", "station_name" : "程久保", "close_ymd" : "", "lon" : 139.410698, "post" : "191-0042", "e_status" : 0, "SUID" : 8151, "station_g_cd" : 9933406, "add" : "日野市程久保8-1", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933406", "pref_name" : "東京都", "shared_name" : "9933406", "lat" : 35.655093, "y" : -356550.93, "x" : 1394106.98 }, "position" : { "x" : 1394106.98, "y" : -356550.93 }, "selected" : false }, { "data" : { "id" : "5760", "station_name" : "南町田", "close_ymd" : "", "lon" : 139.470318, "post" : "194-0004", "e_status" : 0, "SUID" : 5760, "station_g_cd" : 2600325, "add" : "町田市鶴間3-3-2", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600325", "pref_name" : "東京都", "shared_name" : "2600325", "lat" : 35.511502, "y" : -355115.02, "x" : 1394703.18 }, "position" : { "x" : 1394703.18, "y" : -355115.02 }, "selected" : false }, { "data" : { "id" : "8152", "station_name" : "高幡不動", "close_ymd" : "", "lon" : 139.415184, "post" : "191-0031", "e_status" : 0, "SUID" : 8152, "station_g_cd" : 2400129, "add" : "日野市高幡139", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933407", "pref_name" : "東京都", "shared_name" : "9933407", "lat" : 35.66148, "y" : -356614.8, "x" : 1394151.84 }, "position" : { "x" : 1394151.84, "y" : -356614.8 }, "selected" : false }, { "data" : { "id" : "8153", "station_name" : "万願寺", "close_ymd" : "", "lon" : 139.42007900000002, "post" : "191-0022", "e_status" : 0, "SUID" : 8153, "station_g_cd" : 9933408, "add" : "日野市新井124", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933408", "pref_name" : "東京都", "shared_name" : "9933408", "lat" : 35.671248999999996, "y" : -356712.48999999993, "x" : 1394200.7900000003 }, "position" : { "x" : 1394200.7900000003, "y" : -356712.48999999993 }, "selected" : false }, { "data" : { "id" : "8154", "station_name" : "甲州街道", "close_ymd" : "", "lon" : 139.409191, "post" : "191-0012", "e_status" : 0, "SUID" : 8154, "station_g_cd" : 9933409, "add" : "日野市日野1030", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933409", "pref_name" : "東京都", "shared_name" : "9933409", "lat" : 35.678262, "y" : -356782.61999999994, "x" : 1394091.91 }, "position" : { "x" : 1394091.91, "y" : -356782.61999999994 }, "selected" : false }, { "data" : { "id" : "5763", "station_name" : "大井町", "close_ymd" : "", "lon" : 139.735025, "post" : "140-0014", "e_status" : 0, "SUID" : 5763, "station_g_cd" : 1133228, "add" : "品川区大井1丁目", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600401", "pref_name" : "東京都", "shared_name" : "2600401", "lat" : 35.607535, "y" : -356075.35, "x" : 1397350.25 }, "position" : { "x" : 1397350.25, "y" : -356075.35 }, "selected" : false }, { "data" : { "id" : "8155", "station_name" : "柴崎体育館", "close_ymd" : "", "lon" : 139.409191, "post" : "190-0023", "e_status" : 0, "SUID" : 8155, "station_g_cd" : 9933410, "add" : "立川市柴崎町6-107", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933410", "pref_name" : "東京都", "shared_name" : "9933410", "lat" : 35.689475, "y" : -356894.75, "x" : 1394091.91 }, "position" : { "x" : 1394091.91, "y" : -356894.75 }, "selected" : false }, { "data" : { "id" : "8156", "station_name" : "立川南", "close_ymd" : "", "lon" : 139.412546, "post" : "190-0023", "e_status" : 0, "SUID" : 8156, "station_g_cd" : 9933411, "add" : "立川市柴崎町3-7", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933411", "pref_name" : "東京都", "shared_name" : "9933411", "lat" : 35.696077, "y" : -356960.77, "x" : 1394125.46 }, "position" : { "x" : 1394125.46, "y" : -356960.77 }, "selected" : false }, { "data" : { "id" : "5764", "station_name" : "下神明", "close_ymd" : "", "lon" : 139.726256, "post" : "141-0033", "e_status" : 0, "SUID" : 5764, "station_g_cd" : 2600402, "add" : "品川区西品川1-29-6", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600402", "pref_name" : "東京都", "shared_name" : "2600402", "lat" : 35.608703999999996, "y" : -356087.04, "x" : 1397262.56 }, "position" : { "x" : 1397262.56, "y" : -356087.04 }, "selected" : false }, { "data" : { "id" : "5766", "station_name" : "中延", "close_ymd" : "", "lon" : 139.712526, "post" : "142-0053", "e_status" : 0, "SUID" : 5766, "station_g_cd" : 2600404, "add" : "品川区中延4-5-5", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600404", "pref_name" : "東京都", "shared_name" : "2600404", "lat" : 35.605709999999995, "y" : -356057.1, "x" : 1397125.26 }, "position" : { "x" : 1397125.26, "y" : -356057.1 }, "selected" : false }, { "data" : { "id" : "5765", "station_name" : "戸越公園", "close_ymd" : "", "lon" : 139.718159, "post" : "142-0041", "e_status" : 0, "SUID" : 5765, "station_g_cd" : 2600403, "add" : "品川区戸越5-10-15", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600403", "pref_name" : "東京都", "shared_name" : "2600403", "lat" : 35.608856, "y" : -356088.56000000006, "x" : 1397181.59 }, "position" : { "x" : 1397181.59, "y" : -356088.56000000006 }, "selected" : false }, { "data" : { "id" : "8176", "station_name" : "天王洲アイル", "close_ymd" : "", "lon" : 139.750675, "post" : "140-0002", "e_status" : 0, "SUID" : 8176, "station_g_cd" : 9933602, "add" : "品川区東品川2-5-19", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933602", "pref_name" : "東京都", "shared_name" : "9933602", "lat" : 35.622908, "y" : -356229.08, "x" : 1397506.75 }, "position" : { "x" : 1397506.75, "y" : -356229.08 }, "selected" : false }, { "data" : { "id" : "5768", "station_name" : "旗の台", "close_ymd" : "", "lon" : 139.70228600000002, "post" : "142-0064", "e_status" : 0, "SUID" : 5768, "station_g_cd" : 2600406, "add" : "品川区旗の台2-13-1", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600406", "pref_name" : "東京都", "shared_name" : "2600406", "lat" : 35.604923, "y" : -356049.23, "x" : 1397022.86 }, "position" : { "x" : 1397022.86, "y" : -356049.23 }, "selected" : false }, { "data" : { "id" : "8175", "station_name" : "浜松町", "close_ymd" : "", "lon" : 139.756747, "post" : "", "e_status" : 0, "SUID" : 8175, "station_g_cd" : 1130227, "add" : "東京都港区", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933601", "pref_name" : "東京都", "shared_name" : "9933601", "lat" : 35.655666, "y" : -356556.66, "x" : 1397567.47 }, "position" : { "x" : 1397567.47, "y" : -356556.66 }, "selected" : false }, { "data" : { "id" : "5767", "station_name" : "荏原町", "close_ymd" : "", "lon" : 139.707571, "post" : "142-0053", "e_status" : 0, "SUID" : 5767, "station_g_cd" : 2600405, "add" : "品川区中延5-2-1", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600405", "pref_name" : "東京都", "shared_name" : "2600405", "lat" : 35.60382, "y" : -356038.2, "x" : 1397075.71 }, "position" : { "x" : 1397075.71, "y" : -356038.2 }, "selected" : false }, { "data" : { "id" : "8178", "station_name" : "流通センター", "close_ymd" : "", "lon" : 139.748964, "post" : "143-0006", "e_status" : 0, "SUID" : 8178, "station_g_cd" : 9933604, "add" : "大田区平和島6-1-2", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933604", "pref_name" : "東京都", "shared_name" : "9933604", "lat" : 35.58186, "y" : -355818.6, "x" : 1397489.64 }, "position" : { "x" : 1397489.64, "y" : -355818.6 }, "selected" : false }, { "data" : { "id" : "5770", "station_name" : "大岡山", "close_ymd" : "", "lon" : 139.685909, "post" : "145-0062", "e_status" : 0, "SUID" : 5770, "station_g_cd" : 2600206, "add" : "大田区北千束3-27-1", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600408", "pref_name" : "東京都", "shared_name" : "2600408", "lat" : 35.607456, "y" : -356074.56, "x" : 1396859.09 }, "position" : { "x" : 1396859.09, "y" : -356074.56 }, "selected" : false }, { "data" : { "id" : "8177", "station_name" : "大井競馬場前", "close_ymd" : "", "lon" : 139.74708, "post" : "140-0012", "e_status" : 0, "SUID" : 8177, "station_g_cd" : 9933603, "add" : "品川区勝島2-2-35", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933603", "pref_name" : "東京都", "shared_name" : "9933603", "lat" : 35.595006, "y" : -355950.06, "x" : 1397470.8 }, "position" : { "x" : 1397470.8, "y" : -355950.06 }, "selected" : false }, { "data" : { "id" : "5769", "station_name" : "北千束", "close_ymd" : "", "lon" : 139.69330300000001, "post" : "145-0062", "e_status" : 0, "SUID" : 5769, "station_g_cd" : 2600407, "add" : "大田区北千束2-16-1", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600407", "pref_name" : "東京都", "shared_name" : "2600407", "lat" : 35.606311, "y" : -356063.11, "x" : 1396933.0300000003 }, "position" : { "x" : 1396933.0300000003, "y" : -356063.11 }, "selected" : false }, { "data" : { "id" : "8180", "station_name" : "整備場", "close_ymd" : "", "lon" : 139.753366, "post" : "144-0041", "e_status" : 0, "SUID" : 8180, "station_g_cd" : 9933606, "add" : "大田区羽田空港1-7-4", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933606", "pref_name" : "東京都", "shared_name" : "9933606", "lat" : 35.555125, "y" : -355551.24999999994, "x" : 1397533.66 }, "position" : { "x" : 1397533.66, "y" : -355551.24999999994 }, "selected" : false }, { "data" : { "id" : "5772", "station_name" : "自由が丘", "close_ymd" : "", "lon" : 139.66866399999998, "post" : "152-0035", "e_status" : 0, "SUID" : 5772, "station_g_cd" : 2600107, "add" : "目黒区自由が丘1-30-1", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600410", "pref_name" : "東京都", "shared_name" : "2600410", "lat" : 35.607224, "y" : -356072.24000000005, "x" : 1396686.64 }, "position" : { "x" : 1396686.64, "y" : -356072.24000000005 }, "selected" : false }, { "data" : { "id" : "8179", "station_name" : "昭和島", "close_ymd" : "", "lon" : 139.74991799999998, "post" : "143-0004", "e_status" : 0, "SUID" : 8179, "station_g_cd" : 9933605, "add" : "大田区昭和島2-2-1", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933605", "pref_name" : "東京都", "shared_name" : "9933605", "lat" : 35.570656, "y" : -355706.56, "x" : 1397499.1799999997 }, "position" : { "x" : 1397499.1799999997, "y" : -355706.56 }, "selected" : false }, { "data" : { "id" : "5771", "station_name" : "緑が丘", "close_ymd" : "", "lon" : 139.679482, "post" : "152-0034", "e_status" : 0, "SUID" : 5771, "station_g_cd" : 2600409, "add" : "目黒区緑が丘3-1-12", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600409", "pref_name" : "東京都", "shared_name" : "2600409", "lat" : 35.60638, "y" : -356063.8, "x" : 1396794.82 }, "position" : { "x" : 1396794.82, "y" : -356063.8 }, "selected" : false }, { "data" : { "id" : "5774", "station_name" : "尾山台", "close_ymd" : "", "lon" : 139.653862, "post" : "158-0082", "e_status" : 0, "SUID" : 5774, "station_g_cd" : 2600412, "add" : "世田谷区等々力5-5-7", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600412", "pref_name" : "東京都", "shared_name" : "2600412", "lat" : 35.606971, "y" : -356069.71, "x" : 1396538.62 }, "position" : { "x" : 1396538.62, "y" : -356069.71 }, "selected" : false }, { "data" : { "id" : "5773", "station_name" : "九品仏", "close_ymd" : "", "lon" : 139.660992, "post" : "158-0083", "e_status" : 0, "SUID" : 5773, "station_g_cd" : 2600411, "add" : "世田谷区奥沢7-20-1", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600411", "pref_name" : "東京都", "shared_name" : "2600411", "lat" : 35.60538, "y" : -356053.8, "x" : 1396609.92 }, "position" : { "x" : 1396609.92, "y" : -356053.8 }, "selected" : false }, { "data" : { "id" : "5776", "station_name" : "上野毛", "close_ymd" : "", "lon" : 139.638917, "post" : "158-0093", "e_status" : 0, "SUID" : 5776, "station_g_cd" : 2600414, "add" : "世田谷区上野毛1-26-6", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600414", "pref_name" : "東京都", "shared_name" : "2600414", "lat" : 35.611957000000004, "y" : -356119.57000000007, "x" : 1396389.17 }, "position" : { "x" : 1396389.17, "y" : -356119.57000000007 }, "selected" : false }, { "data" : { "id" : "5775", "station_name" : "等々力", "close_ymd" : "", "lon" : 139.64793799999998, "post" : "158-0082", "e_status" : 0, "SUID" : 5775, "station_g_cd" : 2600413, "add" : "世田谷区等々力3-1-1", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600413", "pref_name" : "東京都", "shared_name" : "2600413", "lat" : 35.608369, "y" : -356083.69000000006, "x" : 1396479.38 }, "position" : { "x" : 1396479.38, "y" : -356083.69000000006 }, "selected" : false }, { "data" : { "id" : "5777", "station_name" : "二子玉川", "close_ymd" : "", "lon" : 139.626685, "post" : "158-0094", "e_status" : 0, "SUID" : 5777, "station_g_cd" : 2600307, "add" : "世田谷区玉川2-22-13", "line_cd" : 26004, "selected" : false, "open_ymd" : "", "name" : "2600415", "pref_name" : "東京都", "shared_name" : "2600415", "lat" : 35.611788, "y" : -356117.87999999995, "x" : 1396266.85 }, "position" : { "x" : 1396266.85, "y" : -356117.87999999995 }, "selected" : false }, { "data" : { "id" : "8191", "station_name" : "品川シーサイド", "close_ymd" : "", "lon" : 139.749549, "post" : "140-0002", "e_status" : 0, "SUID" : 8191, "station_g_cd" : 9933706, "add" : "品川区東品川4-12-22", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933706", "pref_name" : "東京都", "shared_name" : "9933706", "lat" : 35.608523999999996, "y" : -356085.23999999993, "x" : 1397495.49 }, "position" : { "x" : 1397495.49, "y" : -356085.23999999993 }, "selected" : false }, { "data" : { "id" : "8192", "station_name" : "大井町", "close_ymd" : "", "lon" : 139.735025, "post" : "140-0014", "e_status" : 0, "SUID" : 8192, "station_g_cd" : 1133228, "add" : "品川区大井1丁目", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933707", "pref_name" : "東京都", "shared_name" : "9933707", "lat" : 35.607535, "y" : -356075.35, "x" : 1397350.25 }, "position" : { "x" : 1397350.25, "y" : -356075.35 }, "selected" : false }, { "data" : { "id" : "8189", "station_name" : "東京テレポート", "close_ymd" : "", "lon" : 139.778896, "post" : "135-0064", "e_status" : 0, "SUID" : 8189, "station_g_cd" : 9933704, "add" : "江東区青海1-2", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933704", "pref_name" : "東京都", "shared_name" : "9933704", "lat" : 35.62753, "y" : -356275.3, "x" : 1397788.96 }, "position" : { "x" : 1397788.96, "y" : -356275.3 }, "selected" : false }, { "data" : { "id" : "8190", "station_name" : "天王洲アイル", "close_ymd" : "", "lon" : 139.750793, "post" : "140-0002", "e_status" : 0, "SUID" : 8190, "station_g_cd" : 9933602, "add" : "品川区東品川2-5-19", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933705", "pref_name" : "東京都", "shared_name" : "9933705", "lat" : 35.620562, "y" : -356205.62, "x" : 1397507.93 }, "position" : { "x" : 1397507.93, "y" : -356205.62 }, "selected" : false }, { "data" : { "id" : "5723", "station_name" : "目黒", "close_ymd" : "", "lon" : 139.7155, "post" : "", "e_status" : 0, "SUID" : 5723, "station_g_cd" : 1130203, "add" : "東京都品川区上大崎四丁目2-1", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600201", "pref_name" : "東京都", "shared_name" : "2600201", "lat" : 35.633272, "y" : -356332.72, "x" : 1397155.0 }, "position" : { "x" : 1397155.0, "y" : -356332.72 }, "selected" : false }, { "data" : { "id" : "5724", "station_name" : "不動前", "close_ymd" : "", "lon" : 139.71469, "post" : "141-0031", "e_status" : 0, "SUID" : 5724, "station_g_cd" : 2600202, "add" : "品川区西五反田5-12-1", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600202", "pref_name" : "東京都", "shared_name" : "2600202", "lat" : 35.626526, "y" : -356265.26, "x" : 1397146.9 }, "position" : { "x" : 1397146.9, "y" : -356265.26 }, "selected" : false }, { "data" : { "id" : "8193", "station_name" : "大崎", "close_ymd" : "", "lon" : 139.72843899999998, "post" : "", "e_status" : 0, "SUID" : 8193, "station_g_cd" : 1130201, "add" : "東京都品川区大崎一丁目21-4", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933708", "pref_name" : "東京都", "shared_name" : "9933708", "lat" : 35.619772, "y" : -356197.72, "x" : 1397284.39 }, "position" : { "x" : 1397284.39, "y" : -356197.72 }, "selected" : false }, { "data" : { "id" : "5727", "station_name" : "洗足", "close_ymd" : "", "lon" : 139.694367, "post" : "152-0012", "e_status" : 0, "SUID" : 5727, "station_g_cd" : 2600205, "add" : "目黒区洗足2-21-1", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600205", "pref_name" : "東京都", "shared_name" : "2600205", "lat" : 35.61043, "y" : -356104.3, "x" : 1396943.67 }, "position" : { "x" : 1396943.67, "y" : -356104.3 }, "selected" : false }, { "data" : { "id" : "8183", "station_name" : "新整備場", "close_ymd" : "", "lon" : 139.786777, "post" : "144-0041", "e_status" : 0, "SUID" : 8183, "station_g_cd" : 9933608, "add" : "大田区羽田空港3-5-1", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933608", "pref_name" : "東京都", "shared_name" : "9933608", "lat" : 35.542773, "y" : -355427.73, "x" : 1397867.77 }, "position" : { "x" : 1397867.77, "y" : -355427.73 }, "selected" : false }, { "data" : { "id" : "5728", "station_name" : "大岡山", "close_ymd" : "", "lon" : 139.685909, "post" : "145-0062", "e_status" : 0, "SUID" : 5728, "station_g_cd" : 2600206, "add" : "大田区北千束3-27-1", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600206", "pref_name" : "東京都", "shared_name" : "2600206", "lat" : 35.607456, "y" : -356074.56, "x" : 1396859.09 }, "position" : { "x" : 1396859.09, "y" : -356074.56 }, "selected" : false }, { "data" : { "id" : "8184", "station_name" : "羽田空港第1ビル", "close_ymd" : "", "lon" : 139.784653, "post" : "144-0041", "e_status" : 0, "SUID" : 8184, "station_g_cd" : 2700206, "add" : "大田区羽田空港3-3-2", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933609", "pref_name" : "東京都", "shared_name" : "9933609", "lat" : 35.549163, "y" : -355491.63, "x" : 1397846.53 }, "position" : { "x" : 1397846.53, "y" : -355491.63 }, "selected" : false }, { "data" : { "id" : "5725", "station_name" : "武蔵小山", "close_ymd" : "", "lon" : 139.704524, "post" : "142-0062", "e_status" : 0, "SUID" : 5725, "station_g_cd" : 2600203, "add" : "品川区小山3-4-8", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600203", "pref_name" : "東京都", "shared_name" : "2600203", "lat" : 35.620538, "y" : -356205.38, "x" : 1397045.24 }, "position" : { "x" : 1397045.24, "y" : -356205.38 }, "selected" : false }, { "data" : { "id" : "8181", "station_name" : "天空橋", "close_ymd" : "", "lon" : 139.75423, "post" : "144-0041", "e_status" : 0, "SUID" : 8181, "station_g_cd" : 2700205, "add" : "大田区羽田空港1-1-2", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933607", "pref_name" : "東京都", "shared_name" : "9933607", "lat" : 35.548908000000004, "y" : -355489.08, "x" : 1397542.3 }, "position" : { "x" : 1397542.3, "y" : -355489.08 }, "selected" : false }, { "data" : { "id" : "5726", "station_name" : "西小山", "close_ymd" : "", "lon" : 139.698694, "post" : "142-0062", "e_status" : 0, "SUID" : 5726, "station_g_cd" : 2600204, "add" : "品川区小山6-3-10", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600204", "pref_name" : "東京都", "shared_name" : "2600204", "lat" : 35.615455, "y" : -356154.55, "x" : 1396986.94 }, "position" : { "x" : 1396986.94, "y" : -356154.55 }, "selected" : false }, { "data" : { "id" : "8182", "station_name" : "羽田空港国際線ビル", "close_ymd" : "", "lon" : 139.768206, "post" : "144-0041", "e_status" : 0, "SUID" : 8182, "station_g_cd" : 2700207, "add" : "東京都大田区羽田空港二丁目6-5", "line_cd" : 99336, "selected" : false, "open_ymd" : "2010-10-21", "name" : "9933611", "pref_name" : "東京都", "shared_name" : "9933611", "lat" : 35.544169000000004, "y" : -355441.69000000006, "x" : 1397682.0599999998 }, "position" : { "x" : 1397682.0599999998, "y" : -355441.69000000006 }, "selected" : false }, { "data" : { "id" : "5731", "station_name" : "多摩川", "close_ymd" : "", "lon" : 139.668723, "post" : "145-0071", "e_status" : 0, "SUID" : 5731, "station_g_cd" : 2600109, "add" : "大田区田園調布1-53-8", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600209", "pref_name" : "東京都", "shared_name" : "2600209", "lat" : 35.589591, "y" : -355895.91, "x" : 1396687.23 }, "position" : { "x" : 1396687.23, "y" : -355895.91 }, "selected" : false }, { "data" : { "id" : "8187", "station_name" : "東雲", "close_ymd" : "", "lon" : 139.804395, "post" : "135-0062", "e_status" : 0, "SUID" : 8187, "station_g_cd" : 9933702, "add" : "江東区東雲2-8-10", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933702", "pref_name" : "東京都", "shared_name" : "9933702", "lat" : 35.640987, "y" : -356409.87000000005, "x" : 1398043.95 }, "position" : { "x" : 1398043.95, "y" : -356409.87000000005 }, "selected" : false }, { "data" : { "id" : "8188", "station_name" : "国際展示場", "close_ymd" : "", "lon" : 139.791617, "post" : "135-0063", "e_status" : 0, "SUID" : 8188, "station_g_cd" : 9933703, "add" : "江東区有明2-5-25", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933703", "pref_name" : "東京都", "shared_name" : "9933703", "lat" : 35.634409999999995, "y" : -356344.1, "x" : 1397916.17 }, "position" : { "x" : 1397916.17, "y" : -356344.1 }, "selected" : false }, { "data" : { "id" : "5729", "station_name" : "奥沢", "close_ymd" : "", "lon" : 139.672355, "post" : "158-0083", "e_status" : 0, "SUID" : 5729, "station_g_cd" : 2600207, "add" : "世田谷区奥沢3-47-17", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600207", "pref_name" : "東京都", "shared_name" : "2600207", "lat" : 35.603947, "y" : -356039.47, "x" : 1396723.55 }, "position" : { "x" : 1396723.55, "y" : -356039.47 }, "selected" : false }, { "data" : { "id" : "8185", "station_name" : "羽田空港第2ビル", "close_ymd" : "", "lon" : 139.787979, "post" : "144-0041", "e_status" : 0, "SUID" : 8185, "station_g_cd" : 2700206, "add" : "大田区羽田空港3-4-2", "line_cd" : 99336, "selected" : false, "open_ymd" : "", "name" : "9933610", "pref_name" : "東京都", "shared_name" : "9933610", "lat" : 35.550734000000006, "y" : -355507.3400000001, "x" : 1397879.79 }, "position" : { "x" : 1397879.79, "y" : -355507.3400000001 }, "selected" : false }, { "data" : { "id" : "5730", "station_name" : "田園調布", "close_ymd" : "", "lon" : 139.667356, "post" : "145-0071", "e_status" : 0, "SUID" : 5730, "station_g_cd" : 2600108, "add" : "大田区田園調布3-25-18", "line_cd" : 26002, "selected" : false, "open_ymd" : "", "name" : "2600208", "pref_name" : "東京都", "shared_name" : "2600208", "lat" : 35.596815, "y" : -355968.15, "x" : 1396673.56 }, "position" : { "x" : 1396673.56, "y" : -355968.15 }, "selected" : false }, { "data" : { "id" : "8186", "station_name" : "新木場", "close_ymd" : "", "lon" : 139.827402, "post" : "", "e_status" : 0, "SUID" : 8186, "station_g_cd" : 1132605, "add" : "東京都江東区新木場一丁目6", "line_cd" : 99337, "selected" : false, "open_ymd" : "", "name" : "9933701", "pref_name" : "東京都", "shared_name" : "9933701", "lat" : 35.646172, "y" : -356461.72, "x" : 1398274.02 }, "position" : { "x" : 1398274.02, "y" : -356461.72 }, "selected" : false }, { "data" : { "id" : "5736", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.702148, "post" : "", "e_status" : 0, "SUID" : 5736, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂二丁目1-1", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600301", "pref_name" : "東京都", "shared_name" : "2600301", "lat" : 35.65802, "y" : -356580.2, "x" : 1397021.48 }, "position" : { "x" : 1397021.48, "y" : -356580.2 }, "selected" : false }, { "data" : { "id" : "5740", "station_name" : "桜新町", "close_ymd" : "", "lon" : 139.644779, "post" : "154-0015", "e_status" : 0, "SUID" : 5740, "station_g_cd" : 2600305, "add" : "世田谷区桜新町2-8", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600305", "pref_name" : "東京都", "shared_name" : "2600305", "lat" : 35.631665999999996, "y" : -356316.66, "x" : 1396447.79 }, "position" : { "x" : 1396447.79, "y" : -356316.66 }, "selected" : false }, { "data" : { "id" : "5739", "station_name" : "駒沢大学", "close_ymd" : "", "lon" : 139.661702, "post" : "154-0011", "e_status" : 0, "SUID" : 5739, "station_g_cd" : 2600304, "add" : "世田谷区上馬4-3", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600304", "pref_name" : "東京都", "shared_name" : "2600304", "lat" : 35.633471, "y" : -356334.71, "x" : 1396617.02 }, "position" : { "x" : 1396617.02, "y" : -356334.71 }, "selected" : false }, { "data" : { "id" : "5738", "station_name" : "三軒茶屋", "close_ymd" : "", "lon" : 139.670156, "post" : "154-0004", "e_status" : 0, "SUID" : 5738, "station_g_cd" : 2600303, "add" : "世田谷区太子堂4-21-1", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600303", "pref_name" : "東京都", "shared_name" : "2600303", "lat" : 35.643716, "y" : -356437.16, "x" : 1396701.5599999998 }, "position" : { "x" : 1396701.5599999998, "y" : -356437.16 }, "selected" : false }, { "data" : { "id" : "5737", "station_name" : "池尻大橋", "close_ymd" : "", "lon" : 139.684319, "post" : "154-0001", "e_status" : 0, "SUID" : 5737, "station_g_cd" : 2600302, "add" : "世田谷区池尻3-2", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600302", "pref_name" : "東京都", "shared_name" : "2600302", "lat" : 35.650603000000004, "y" : -356506.03, "x" : 1396843.19 }, "position" : { "x" : 1396843.19, "y" : -356506.03 }, "selected" : false }, { "data" : { "id" : "5742", "station_name" : "二子玉川", "close_ymd" : "", "lon" : 139.626685, "post" : "158-0094", "e_status" : 0, "SUID" : 5742, "station_g_cd" : 2600307, "add" : "世田谷区玉川2-22-13", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600307", "pref_name" : "東京都", "shared_name" : "2600307", "lat" : 35.611788, "y" : -356117.87999999995, "x" : 1396266.85 }, "position" : { "x" : 1396266.85, "y" : -356117.87999999995 }, "selected" : false }, { "data" : { "id" : "5741", "station_name" : "用賀", "close_ymd" : "", "lon" : 139.633928, "post" : "158-0097", "e_status" : 0, "SUID" : 5741, "station_g_cd" : 2600306, "add" : "世田谷区用賀2-39", "line_cd" : 26003, "selected" : false, "open_ymd" : "", "name" : "2600306", "pref_name" : "東京都", "shared_name" : "2600306", "lat" : 35.626436, "y" : -356264.36, "x" : 1396339.28 }, "position" : { "x" : 1396339.28, "y" : -356264.36 }, "selected" : false }, { "data" : { "id" : "5699", "station_name" : "小田急永山", "close_ymd" : "", "lon" : 139.44794299999998, "post" : "206-0025", "e_status" : 0, "SUID" : 5699, "station_g_cd" : 2400207, "add" : "多摩市永山1丁目", "line_cd" : 25003, "selected" : false, "open_ymd" : "", "name" : "2500306", "pref_name" : "東京都", "shared_name" : "2500306", "lat" : 35.629971999999995, "y" : -356299.72, "x" : 1394479.4299999997 }, "position" : { "x" : 1394479.4299999997, "y" : -356299.72 }, "selected" : false }, { "data" : { "id" : "5700", "station_name" : "小田急多摩センター", "close_ymd" : "", "lon" : 139.424298, "post" : "206-0033", "e_status" : 0, "SUID" : 5700, "station_g_cd" : 2400208, "add" : "多摩市落合1丁目", "line_cd" : 25003, "selected" : false, "open_ymd" : "", "name" : "2500307", "pref_name" : "東京都", "shared_name" : "2500307", "lat" : 35.624902, "y" : -356249.01999999996, "x" : 1394242.98 }, "position" : { "x" : 1394242.98, "y" : -356249.01999999996 }, "selected" : false }, { "data" : { "id" : "5706", "station_name" : "学芸大学", "close_ymd" : "", "lon" : 139.68522, "post" : "152-0004", "e_status" : 0, "SUID" : 5706, "station_g_cd" : 2600105, "add" : "目黒区鷹番3-2-1", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600105", "pref_name" : "東京都", "shared_name" : "2600105", "lat" : 35.628786, "y" : -356287.86, "x" : 1396852.2 }, "position" : { "x" : 1396852.2, "y" : -356287.86 }, "selected" : false }, { "data" : { "id" : "5705", "station_name" : "祐天寺", "close_ymd" : "", "lon" : 139.69075800000002, "post" : "153-0052", "e_status" : 0, "SUID" : 5705, "station_g_cd" : 2600104, "add" : "目黒区祐天寺2-13-3", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600104", "pref_name" : "東京都", "shared_name" : "2600104", "lat" : 35.637163, "y" : -356371.63, "x" : 1396907.58 }, "position" : { "x" : 1396907.58, "y" : -356371.63 }, "selected" : false }, { "data" : { "id" : "5708", "station_name" : "自由が丘", "close_ymd" : "", "lon" : 139.66866399999998, "post" : "152-0035", "e_status" : 0, "SUID" : 5708, "station_g_cd" : 2600107, "add" : "目黒区自由が丘1-30-1", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600107", "pref_name" : "東京都", "shared_name" : "2600107", "lat" : 35.607224, "y" : -356072.24000000005, "x" : 1396686.64 }, "position" : { "x" : 1396686.64, "y" : -356072.24000000005 }, "selected" : false }, { "data" : { "id" : "5707", "station_name" : "都立大学", "close_ymd" : "", "lon" : 139.676393, "post" : "152-0031", "e_status" : 0, "SUID" : 5707, "station_g_cd" : 2600106, "add" : "目黒区中根1-5-1", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600106", "pref_name" : "東京都", "shared_name" : "2600106", "lat" : 35.617835, "y" : -356178.35, "x" : 1396763.93 }, "position" : { "x" : 1396763.93, "y" : -356178.35 }, "selected" : false }, { "data" : { "id" : "5702", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.702417, "post" : "-", "e_status" : 0, "SUID" : 5702, "station_g_cd" : 1130205, "add" : "東京都渋谷区渋谷二丁目24-1", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600101", "pref_name" : "東京都", "shared_name" : "2600101", "lat" : 35.659545, "y" : -356595.45, "x" : 1397024.17 }, "position" : { "x" : 1397024.17, "y" : -356595.45 }, "selected" : false }, { "data" : { "id" : "5701", "station_name" : "唐木田", "close_ymd" : "", "lon" : 139.411622, "post" : "206-0033", "e_status" : 0, "SUID" : 5701, "station_g_cd" : 2500308, "add" : "多摩市落合", "line_cd" : 25003, "selected" : false, "open_ymd" : "", "name" : "2500308", "pref_name" : "東京都", "shared_name" : "2500308", "lat" : 35.616671999999994, "y" : -356166.7199999999, "x" : 1394116.22 }, "position" : { "x" : 1394116.22, "y" : -356166.7199999999 }, "selected" : false }, { "data" : { "id" : "5704", "station_name" : "中目黒", "close_ymd" : "", "lon" : 139.698621, "post" : "153-0051", "e_status" : 0, "SUID" : 5704, "station_g_cd" : 2600103, "add" : "目黒区上目黒3-4-1", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600103", "pref_name" : "東京都", "shared_name" : "2600103", "lat" : 35.643854, "y" : -356438.54, "x" : 1396986.21 }, "position" : { "x" : 1396986.21, "y" : -356438.54 }, "selected" : false }, { "data" : { "id" : "5703", "station_name" : "代官山", "close_ymd" : "", "lon" : 139.703284, "post" : "150-0034", "e_status" : 0, "SUID" : 5703, "station_g_cd" : 2600102, "add" : "渋谷区代官山町19-4", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600102", "pref_name" : "東京都", "shared_name" : "2600102", "lat" : 35.648193, "y" : -356481.93, "x" : 1397032.8399999999 }, "position" : { "x" : 1397032.8399999999, "y" : -356481.93 }, "selected" : false }, { "data" : { "id" : "5710", "station_name" : "多摩川", "close_ymd" : "", "lon" : 139.668723, "post" : "145-0071", "e_status" : 0, "SUID" : 5710, "station_g_cd" : 2600109, "add" : "大田区田園調布1-53-8", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600109", "pref_name" : "東京都", "shared_name" : "2600109", "lat" : 35.589591, "y" : -355895.91, "x" : 1396687.23 }, "position" : { "x" : 1396687.23, "y" : -355895.91 }, "selected" : false }, { "data" : { "id" : "5709", "station_name" : "田園調布", "close_ymd" : "", "lon" : 139.667356, "post" : "145-0071", "e_status" : 0, "SUID" : 5709, "station_g_cd" : 2600108, "add" : "大田区田園調布3-25-18", "line_cd" : 26001, "selected" : false, "open_ymd" : "", "name" : "2600108", "pref_name" : "東京都", "shared_name" : "2600108", "lat" : 35.596815, "y" : -355968.15, "x" : 1396673.56 }, "position" : { "x" : 1396673.56, "y" : -355968.15 }, "selected" : false }, { "data" : { "id" : "5655", "station_name" : "玉川学園前", "close_ymd" : "", "lon" : 139.46338799999998, "post" : "194-0041", "e_status" : 0, "SUID" : 5655, "station_g_cd" : 2500126, "add" : "町田市玉川学園2丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500126", "pref_name" : "東京都", "shared_name" : "2500126", "lat" : 35.563486, "y" : -355634.86, "x" : 1394633.88 }, "position" : { "x" : 1394633.88, "y" : -355634.86 }, "selected" : false }, { "data" : { "id" : "5656", "station_name" : "町田", "close_ymd" : "", "lon" : 139.44523600000002, "post" : "194-0013", "e_status" : 0, "SUID" : 5656, "station_g_cd" : 1130611, "add" : "町田市原町田1丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500127", "pref_name" : "東京都", "shared_name" : "2500127", "lat" : 35.544222, "y" : -355442.22, "x" : 1394452.3600000003 }, "position" : { "x" : 1394452.3600000003, "y" : -355442.22 }, "selected" : false }, { "data" : { "id" : "5654", "station_name" : "鶴川", "close_ymd" : "", "lon" : 139.481759, "post" : "195-0053", "e_status" : 0, "SUID" : 5654, "station_g_cd" : 2500125, "add" : "町田市能ケ谷町", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500125", "pref_name" : "東京都", "shared_name" : "2500125", "lat" : 35.583077, "y" : -355830.77, "x" : 1394817.59 }, "position" : { "x" : 1394817.59, "y" : -355830.77 }, "selected" : false }, { "data" : { "id" : "8148", "station_name" : "大塚・帝京大学", "close_ymd" : "", "lon" : 139.416461, "post" : "192-0352", "e_status" : 0, "SUID" : 8148, "station_g_cd" : 9933403, "add" : "八王子市大塚1473", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933403", "pref_name" : "東京都", "shared_name" : "9933403", "lat" : 35.636878, "y" : -356368.78, "x" : 1394164.6099999999 }, "position" : { "x" : 1394164.6099999999, "y" : -356368.78 }, "selected" : false }, { "data" : { "id" : "8147", "station_name" : "松が谷", "close_ymd" : "", "lon" : 139.422201, "post" : "192-0354", "e_status" : 0, "SUID" : 8147, "station_g_cd" : 9933402, "add" : "八王子市松が谷40", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933402", "pref_name" : "東京都", "shared_name" : "9933402", "lat" : 35.63169, "y" : -356316.89999999997, "x" : 1394222.01 }, "position" : { "x" : 1394222.01, "y" : -356316.89999999997 }, "selected" : false }, { "data" : { "id" : "8146", "station_name" : "多摩センター", "close_ymd" : "", "lon" : 139.422782, "post" : "206-0033", "e_status" : 0, "SUID" : 8146, "station_g_cd" : 2400208, "add" : "多摩市落合1-48-1", "line_cd" : 99334, "selected" : false, "open_ymd" : "", "name" : "9933401", "pref_name" : "東京都", "shared_name" : "9933401", "lat" : 35.623723999999996, "y" : -356237.23999999993, "x" : 1394227.82 }, "position" : { "x" : 1394227.82, "y" : -356237.23999999993 }, "selected" : false }, { "data" : { "id" : "7783", "station_name" : "新御徒町", "close_ymd" : "", "lon" : 139.781958, "post" : "111-0041", "e_status" : 0, "SUID" : 7783, "station_g_cd" : 9930111, "add" : "台東区元浅草1-5-2", "line_cd" : 99309, "selected" : false, "open_ymd" : "", "name" : "9930902", "pref_name" : "東京都", "shared_name" : "9930902", "lat" : 35.707045, "y" : -357070.45, "x" : 1397819.58 }, "position" : { "x" : 1397819.58, "y" : -357070.45 }, "selected" : false }, { "data" : { "id" : "7784", "station_name" : "浅草", "close_ymd" : "", "lon" : 139.792389, "post" : "", "e_status" : 0, "SUID" : 7784, "station_g_cd" : 9930903, "add" : "東京都台東区", "line_cd" : 99309, "selected" : false, "open_ymd" : "", "name" : "9930903", "pref_name" : "東京都", "shared_name" : "9930903", "lat" : 35.713817, "y" : -357138.17, "x" : 1397923.89 }, "position" : { "x" : 1397923.89, "y" : -357138.17 }, "selected" : false }, { "data" : { "id" : "7782", "station_name" : "秋葉原", "close_ymd" : "", "lon" : 139.774273, "post" : "", "e_status" : 0, "SUID" : 7782, "station_g_cd" : 1130222, "add" : "東京都千代田区", "line_cd" : 99309, "selected" : false, "open_ymd" : "", "name" : "9930901", "pref_name" : "東京都", "shared_name" : "9930901", "lat" : 35.698889, "y" : -356988.89, "x" : 1397742.73 }, "position" : { "x" : 1397742.73, "y" : -356988.89 }, "selected" : false }, { "data" : { "id" : "7787", "station_name" : "青井", "close_ymd" : "", "lon" : 139.82038, "post" : "120-0012", "e_status" : 0, "SUID" : 7787, "station_g_cd" : 9930906, "add" : "足立区青井三丁目", "line_cd" : 99309, "selected" : false, "open_ymd" : "", "name" : "9930906", "pref_name" : "東京都", "shared_name" : "9930906", "lat" : 35.771782, "y" : -357717.82, "x" : 1398203.8 }, "position" : { "x" : 1398203.8, "y" : -357717.82 }, "selected" : false }, { "data" : { "id" : "7788", "station_name" : "六町", "close_ymd" : "", "lon" : 139.82181599999998, "post" : "121-0073", "e_status" : 0, "SUID" : 7788, "station_g_cd" : 9930907, "add" : "足立区六町四丁目", "line_cd" : 99309, "selected" : false, "open_ymd" : "", "name" : "9930907", "pref_name" : "東京都", "shared_name" : "9930907", "lat" : 35.784963, "y" : -357849.63, "x" : 1398218.16 }, "position" : { "x" : 1398218.16, "y" : -357849.63 }, "selected" : false }, { "data" : { "id" : "7785", "station_name" : "南千住", "close_ymd" : "", "lon" : 139.79878300000001, "post" : "116-0003", "e_status" : 0, "SUID" : 7785, "station_g_cd" : 1132004, "add" : "荒川区南千住4丁目", "line_cd" : 99309, "selected" : false, "open_ymd" : "", "name" : "9930904", "pref_name" : "東京都", "shared_name" : "9930904", "lat" : 35.732413, "y" : -357324.13, "x" : 1397987.83 }, "position" : { "x" : 1397987.83, "y" : -357324.13 }, "selected" : false }, { "data" : { "id" : "7786", "station_name" : "北千住", "close_ymd" : "", "lon" : 139.805092, "post" : "120-0026", "e_status" : 0, "SUID" : 7786, "station_g_cd" : 1132005, "add" : "足立区千住旭町", "line_cd" : 99309, "selected" : false, "open_ymd" : "", "name" : "9930905", "pref_name" : "東京都", "shared_name" : "9930905", "lat" : 35.74949, "y" : -357494.9, "x" : 1398050.92 }, "position" : { "x" : 1398050.92, "y" : -357494.9 }, "selected" : false }, { "data" : { "id" : "7813", "station_name" : "お台場海浜公園", "close_ymd" : "", "lon" : 139.778607, "post" : "135-0091", "e_status" : 0, "SUID" : 7813, "station_g_cd" : 9931106, "add" : "港区台場2-3", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931106", "pref_name" : "東京都", "shared_name" : "9931106", "lat" : 35.629813, "y" : -356298.13, "x" : 1397786.0699999998 }, "position" : { "x" : 1397786.0699999998, "y" : -356298.13 }, "selected" : false }, { "data" : { "id" : "7814", "station_name" : "台場", "close_ymd" : "", "lon" : 139.771435, "post" : "135-0091", "e_status" : 0, "SUID" : 7814, "station_g_cd" : 9931107, "add" : "港区台場2-6", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931107", "pref_name" : "東京都", "shared_name" : "9931107", "lat" : 35.625908, "y" : -356259.08, "x" : 1397714.3499999999 }, "position" : { "x" : 1397714.3499999999, "y" : -356259.08 }, "selected" : false }, { "data" : { "id" : "7815", "station_name" : "船の科学館", "close_ymd" : "", "lon" : 139.773157, "post" : "135-0064", "e_status" : 0, "SUID" : 7815, "station_g_cd" : 9931108, "add" : "江東区青海1", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931108", "pref_name" : "東京都", "shared_name" : "9931108", "lat" : 35.621462, "y" : -356214.62, "x" : 1397731.57 }, "position" : { "x" : 1397731.57, "y" : -356214.62 }, "selected" : false }, { "data" : { "id" : "7816", "station_name" : "テレコムセンター", "close_ymd" : "", "lon" : 139.779327, "post" : "135-0064", "e_status" : 0, "SUID" : 7816, "station_g_cd" : 9931109, "add" : "江東区青海2-29", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931109", "pref_name" : "東京都", "shared_name" : "9931109", "lat" : 35.617593, "y" : -356175.93, "x" : 1397793.27 }, "position" : { "x" : 1397793.27, "y" : -356175.93 }, "selected" : false }, { "data" : { "id" : "7817", "station_name" : "青海", "close_ymd" : "", "lon" : 139.781132, "post" : "135-0064", "e_status" : 0, "SUID" : 7817, "station_g_cd" : 9931110, "add" : "江東区青海1", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931110", "pref_name" : "東京都", "shared_name" : "9931110", "lat" : 35.62467, "y" : -356246.7, "x" : 1397811.32 }, "position" : { "x" : 1397811.32, "y" : -356246.7 }, "selected" : false }, { "data" : { "id" : "7818", "station_name" : "国際展示場正門", "close_ymd" : "", "lon" : 139.791228, "post" : "135-0063", "e_status" : 0, "SUID" : 7818, "station_g_cd" : 9931111, "add" : "江東区有明3-1", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931111", "pref_name" : "東京都", "shared_name" : "9931111", "lat" : 35.630158, "y" : -356301.58, "x" : 1397912.2799999998 }, "position" : { "x" : 1397912.2799999998, "y" : -356301.58 }, "selected" : false }, { "data" : { "id" : "7819", "station_name" : "有明", "close_ymd" : "", "lon" : 139.79326899999998, "post" : "135-0063", "e_status" : 0, "SUID" : 7819, "station_g_cd" : 9931112, "add" : "江東区有明2-5", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931112", "pref_name" : "東京都", "shared_name" : "9931112", "lat" : 35.634596, "y" : -356345.96, "x" : 1397932.6899999997 }, "position" : { "x" : 1397932.6899999997, "y" : -356345.96 }, "selected" : false }, { "data" : { "id" : "7820", "station_name" : "有明テニスの森", "close_ymd" : "", "lon" : 139.78888, "post" : "135-0063", "e_status" : 0, "SUID" : 7820, "station_g_cd" : 9931113, "add" : "江東区有明1丁目", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931113", "pref_name" : "東京都", "shared_name" : "9931113", "lat" : 35.639964, "y" : -356399.64, "x" : 1397888.8 }, "position" : { "x" : 1397888.8, "y" : -356399.64 }, "selected" : false }, { "data" : { "id" : "7821", "station_name" : "市場前", "close_ymd" : "", "lon" : 139.78564, "post" : "135-0061", "e_status" : 0, "SUID" : 7821, "station_g_cd" : 9931114, "add" : "江東区豊洲6丁目", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931114", "pref_name" : "東京都", "shared_name" : "9931114", "lat" : 35.645684, "y" : -356456.84, "x" : 1397856.4 }, "position" : { "x" : 1397856.4, "y" : -356456.84 }, "selected" : false }, { "data" : { "id" : "7822", "station_name" : "新豊洲", "close_ymd" : "", "lon" : 139.789996, "post" : "135-0061", "e_status" : 0, "SUID" : 7822, "station_g_cd" : 9931115, "add" : "江東区豊洲6丁目", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931115", "pref_name" : "東京都", "shared_name" : "9931115", "lat" : 35.648718, "y" : -356487.18000000005, "x" : 1397899.96 }, "position" : { "x" : 1397899.96, "y" : -356487.18000000005 }, "selected" : false }, { "data" : { "id" : "7823", "station_name" : "豊洲", "close_ymd" : "", "lon" : 139.795414, "post" : "", "e_status" : 0, "SUID" : 7823, "station_g_cd" : 2800622, "add" : "東京都江東区豊洲", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931116", "pref_name" : "東京都", "shared_name" : "9931116", "lat" : 35.653791999999996, "y" : -356537.92, "x" : 1397954.14 }, "position" : { "x" : 1397954.14, "y" : -356537.92 }, "selected" : false }, { "data" : { "id" : "7808", "station_name" : "新橋", "close_ymd" : "", "lon" : 139.75964399999998, "post" : "", "e_status" : 0, "SUID" : 7808, "station_g_cd" : 1130102, "add" : "東京都港区東新橋一丁目5-13", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931101", "pref_name" : "東京都", "shared_name" : "9931101", "lat" : 35.665503, "y" : -356655.03, "x" : 1397596.4399999997 }, "position" : { "x" : 1397596.4399999997, "y" : -356655.03 }, "selected" : false }, { "data" : { "id" : "7810", "station_name" : "竹芝", "close_ymd" : "", "lon" : 139.76203700000002, "post" : "105-0022", "e_status" : 0, "SUID" : 7810, "station_g_cd" : 9931103, "add" : "港区海岸1-13-10", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931103", "pref_name" : "東京都", "shared_name" : "9931103", "lat" : 35.654099, "y" : -356540.99000000005, "x" : 1397620.37 }, "position" : { "x" : 1397620.37, "y" : -356540.99000000005 }, "selected" : false }, { "data" : { "id" : "7809", "station_name" : "汐留", "close_ymd" : "", "lon" : 139.759985, "post" : "105-0021", "e_status" : 0, "SUID" : 7809, "station_g_cd" : 9930120, "add" : "港区東新橋1丁目5", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931102", "pref_name" : "東京都", "shared_name" : "9931102", "lat" : 35.662871, "y" : -356628.71, "x" : 1397599.85 }, "position" : { "x" : 1397599.85, "y" : -356628.71 }, "selected" : false }, { "data" : { "id" : "7812", "station_name" : "芝浦ふ頭", "close_ymd" : "", "lon" : 139.757852, "post" : "108-0022", "e_status" : 0, "SUID" : 7812, "station_g_cd" : 9931105, "add" : "港区海岸3-22-12", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931105", "pref_name" : "東京都", "shared_name" : "9931105", "lat" : 35.641773, "y" : -356417.73, "x" : 1397578.5200000003 }, "position" : { "x" : 1397578.5200000003, "y" : -356417.73 }, "selected" : false }, { "data" : { "id" : "7811", "station_name" : "日の出", "close_ymd" : "", "lon" : 139.75906, "post" : "105-0022", "e_status" : 0, "SUID" : 7811, "station_g_cd" : 9931104, "add" : "港区海岸2-7-68", "line_cd" : 99311, "selected" : false, "open_ymd" : "", "name" : "9931104", "pref_name" : "東京都", "shared_name" : "9931104", "lat" : 35.649136, "y" : -356491.36, "x" : 1397590.6 }, "position" : { "x" : 1397590.6, "y" : -356491.36 }, "selected" : false }, { "data" : { "id" : "7723", "station_name" : "舎人", "close_ymd" : "", "lon" : 139.770108, "post" : "121-0831", "e_status" : 0, "SUID" : 7723, "station_g_cd" : 9934212, "add" : "足立区舎人1-16-15", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934212", "pref_name" : "東京都", "shared_name" : "9934212", "lat" : 35.8057, "y" : -358057.0, "x" : 1397701.0799999998 }, "position" : { "x" : 1397701.0799999998, "y" : -358057.0 }, "selected" : false }, { "data" : { "id" : "7724", "station_name" : "見沼代親水公園", "close_ymd" : "", "lon" : 139.77071899999999, "post" : "121-0831", "e_status" : 0, "SUID" : 7724, "station_g_cd" : 9934213, "add" : "足立区舎人2-21-13", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934213", "pref_name" : "東京都", "shared_name" : "9934213", "lat" : 35.814544, "y" : -358145.44, "x" : 1397707.19 }, "position" : { "x" : 1397707.19, "y" : -358145.44 }, "selected" : false }, { "data" : { "id" : "7721", "station_name" : "谷在家", "close_ymd" : "", "lon" : 139.770043, "post" : "123-0863", "e_status" : 0, "SUID" : 7721, "station_g_cd" : 9934210, "add" : "足立区谷在家3-20-23", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934210", "pref_name" : "東京都", "shared_name" : "9934210", "lat" : 35.788774, "y" : -357887.74, "x" : 1397700.43 }, "position" : { "x" : 1397700.43, "y" : -357887.74 }, "selected" : false }, { "data" : { "id" : "7722", "station_name" : "舎人公園", "close_ymd" : "", "lon" : 139.770183, "post" : "121-0837", "e_status" : 0, "SUID" : 7722, "station_g_cd" : 9934211, "add" : "足立区舎人公園1-10", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934211", "pref_name" : "東京都", "shared_name" : "9934211", "lat" : 35.79623, "y" : -357962.3, "x" : 1397701.83 }, "position" : { "x" : 1397701.83, "y" : -357962.3 }, "selected" : false }, { "data" : { "id" : "7719", "station_name" : "江北", "close_ymd" : "", "lon" : 139.770306, "post" : "123-0872", "e_status" : 0, "SUID" : 7719, "station_g_cd" : 9934208, "add" : "足立区江北4-30-27", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934208", "pref_name" : "東京都", "shared_name" : "9934208", "lat" : 35.774021000000005, "y" : -357740.21, "x" : 1397703.06 }, "position" : { "x" : 1397703.06, "y" : -357740.21 }, "selected" : false }, { "data" : { "id" : "7720", "station_name" : "西新井大師西", "close_ymd" : "", "lon" : 139.770094, "post" : "123-0872", "e_status" : 0, "SUID" : 7720, "station_g_cd" : 9934209, "add" : "足立区江北6-30-23", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934209", "pref_name" : "東京都", "shared_name" : "9934209", "lat" : 35.781504999999996, "y" : -357815.04999999993, "x" : 1397700.94 }, "position" : { "x" : 1397700.94, "y" : -357815.04999999993 }, "selected" : false }, { "data" : { "id" : "7717", "station_name" : "扇大橋", "close_ymd" : "", "lon" : 139.77080800000002, "post" : "123-0873", "e_status" : 0, "SUID" : 7717, "station_g_cd" : 9934206, "add" : "足立区扇2-25-7", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934206", "pref_name" : "東京都", "shared_name" : "9934206", "lat" : 35.763897, "y" : -357638.97, "x" : 1397708.08 }, "position" : { "x" : 1397708.08, "y" : -357638.97 }, "selected" : false }, { "data" : { "id" : "7718", "station_name" : "高野", "close_ymd" : "", "lon" : 139.770679, "post" : "123-0873", "e_status" : 0, "SUID" : 7718, "station_g_cd" : 9934207, "add" : "足立区扇2-45-1", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934207", "pref_name" : "東京都", "shared_name" : "9934207", "lat" : 35.768359000000004, "y" : -357683.59, "x" : 1397706.79 }, "position" : { "x" : 1397706.79, "y" : -357683.59 }, "selected" : false }, { "data" : { "id" : "7708", "station_name" : "鬼子母神前", "close_ymd" : "", "lon" : 139.714916, "post" : "171-0032", "e_status" : 0, "SUID" : 7708, "station_g_cd" : 2801010, "add" : "豊島区雑司が谷2", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930527", "pref_name" : "東京都", "shared_name" : "9930527", "lat" : 35.720403000000005, "y" : -357204.03, "x" : 1397149.16 }, "position" : { "x" : 1397149.16, "y" : -357204.03 }, "selected" : false }, { "data" : { "id" : "7707", "station_name" : "都電雑司ヶ谷", "close_ymd" : "", "lon" : 139.718006, "post" : "", "e_status" : 0, "SUID" : 7707, "station_g_cd" : 9930526, "add" : "東京都豊島区南池袋", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930526", "pref_name" : "東京都", "shared_name" : "9930526", "lat" : 35.724261, "y" : -357242.61, "x" : 1397180.06 }, "position" : { "x" : 1397180.06, "y" : -357242.61 }, "selected" : false }, { "data" : { "id" : "7706", "station_name" : "東池袋四丁目", "close_ymd" : "", "lon" : 139.720012, "post" : "170-0013", "e_status" : 0, "SUID" : 7706, "station_g_cd" : 2800610, "add" : "豊島区東池袋5", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930525", "pref_name" : "東京都", "shared_name" : "9930525", "lat" : 35.72528, "y" : -357252.8, "x" : 1397200.1199999999 }, "position" : { "x" : 1397200.1199999999, "y" : -357252.8 }, "selected" : false }, { "data" : { "id" : "7705", "station_name" : "向原", "close_ymd" : "", "lon" : 139.724894, "post" : "170-0005", "e_status" : 0, "SUID" : 7705, "station_g_cd" : 9930524, "add" : "豊島区南大塚3", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930524", "pref_name" : "東京都", "shared_name" : "9930524", "lat" : 35.728938, "y" : -357289.38, "x" : 1397248.9400000002 }, "position" : { "x" : 1397248.9400000002, "y" : -357289.38 }, "selected" : false }, { "data" : { "id" : "7704", "station_name" : "大塚駅前", "close_ymd" : "", "lon" : 139.729593, "post" : "170-0005", "e_status" : 0, "SUID" : 7704, "station_g_cd" : 1130213, "add" : "豊島区南大塚3", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930523", "pref_name" : "東京都", "shared_name" : "9930523", "lat" : 35.732082, "y" : -357320.82, "x" : 1397295.93 }, "position" : { "x" : 1397295.93, "y" : -357320.82 }, "selected" : false }, { "data" : { "id" : "7703", "station_name" : "巣鴨新田", "close_ymd" : "", "lon" : 139.727769, "post" : "170-0001", "e_status" : 0, "SUID" : 7703, "station_g_cd" : 9930522, "add" : "豊島区西巣鴨1", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930522", "pref_name" : "東京都", "shared_name" : "9930522", "lat" : 35.735488000000004, "y" : -357354.88000000006, "x" : 1397277.69 }, "position" : { "x" : 1397277.69, "y" : -357354.88000000006 }, "selected" : false }, { "data" : { "id" : "6078", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.702417, "post" : "", "e_status" : 0, "SUID" : 6078, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂二丁目1-1", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801016", "pref_name" : "東京都", "shared_name" : "2801016", "lat" : 35.659545, "y" : -356595.45, "x" : 1397024.17 }, "position" : { "x" : 1397024.17, "y" : -356595.45 }, "selected" : false }, { "data" : { "id" : "7702", "station_name" : "庚申塚", "close_ymd" : "", "lon" : 139.72974299999998, "post" : "170-0001", "e_status" : 0, "SUID" : 7702, "station_g_cd" : 9930521, "add" : "豊島区西巣鴨3", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930521", "pref_name" : "東京都", "shared_name" : "9930521", "lat" : 35.739563000000004, "y" : -357395.63000000006, "x" : 1397297.43 }, "position" : { "x" : 1397297.43, "y" : -357395.63000000006 }, "selected" : false }, { "data" : { "id" : "6077", "station_name" : "明治神宮前〈原宿〉", "close_ymd" : "", "lon" : 139.705367, "post" : "150-0001", "e_status" : 0, "SUID" : 6077, "station_g_cd" : 1130206, "add" : "渋谷区神宮前1丁目", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801015", "pref_name" : "東京都", "shared_name" : "2801015", "lat" : 35.668496999999995, "y" : -356684.97, "x" : 1397053.67 }, "position" : { "x" : 1397053.67, "y" : -356684.97 }, "selected" : false }, { "data" : { "id" : "7701", "station_name" : "新庚申塚", "close_ymd" : "", "lon" : 139.730451, "post" : "170-0001", "e_status" : 0, "SUID" : 7701, "station_g_cd" : 9930520, "add" : "豊島区西巣鴨4", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930520", "pref_name" : "東京都", "shared_name" : "9930520", "lat" : 35.741347999999995, "y" : -357413.4799999999, "x" : 1397304.5099999998 }, "position" : { "x" : 1397304.5099999998, "y" : -357413.4799999999 }, "selected" : false }, { "data" : { "id" : "7716", "station_name" : "足立小台", "close_ymd" : "", "lon" : 139.77038100000001, "post" : "120-0046", "e_status" : 0, "SUID" : 7716, "station_g_cd" : 9934205, "add" : "足立区小台1-20-1", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934205", "pref_name" : "東京都", "shared_name" : "9934205", "lat" : 35.754658, "y" : -357546.58, "x" : 1397703.81 }, "position" : { "x" : 1397703.81, "y" : -357546.58 }, "selected" : false }, { "data" : { "id" : "6076", "station_name" : "北参道", "close_ymd" : "", "lon" : 139.705453, "post" : "151-0051", "e_status" : 0, "SUID" : 6076, "station_g_cd" : 2801014, "add" : "渋谷区千駄ヶ谷4丁目", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801014", "pref_name" : "東京都", "shared_name" : "2801014", "lat" : 35.678459000000004, "y" : -356784.59, "x" : 1397054.53 }, "position" : { "x" : 1397054.53, "y" : -356784.59 }, "selected" : false }, { "data" : { "id" : "6075", "station_name" : "新宿三丁目", "close_ymd" : "", "lon" : 139.704828, "post" : "160-0022", "e_status" : 0, "SUID" : 6075, "station_g_cd" : 2800217, "add" : "新宿区新宿3-14-1", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801013", "pref_name" : "東京都", "shared_name" : "2801013", "lat" : 35.690853000000004, "y" : -356908.53, "x" : 1397048.28 }, "position" : { "x" : 1397048.28, "y" : -356908.53 }, "selected" : false }, { "data" : { "id" : "7715", "station_name" : "熊野前", "close_ymd" : "", "lon" : 139.76969499999998, "post" : "116-0012", "e_status" : 0, "SUID" : 7715, "station_g_cd" : 9930509, "add" : "荒川区東尾久5", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934204", "pref_name" : "東京都", "shared_name" : "9934204", "lat" : 35.748971999999995, "y" : -357489.72, "x" : 1397696.95 }, "position" : { "x" : 1397696.95, "y" : -357489.72 }, "selected" : false }, { "data" : { "id" : "6074", "station_name" : "東新宿", "close_ymd" : "", "lon" : 139.707593, "post" : "160-0022", "e_status" : 0, "SUID" : 6074, "station_g_cd" : 2801012, "add" : "新宿区新宿7-27-3", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801012", "pref_name" : "東京都", "shared_name" : "2801012", "lat" : 35.698915, "y" : -356989.15, "x" : 1397075.93 }, "position" : { "x" : 1397075.93, "y" : -356989.15 }, "selected" : false }, { "data" : { "id" : "7714", "station_name" : "赤土小学校前", "close_ymd" : "", "lon" : 139.76898899999998, "post" : "116-0012", "e_status" : 0, "SUID" : 7714, "station_g_cd" : 9934203, "add" : "荒川区東尾久4-7-7", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934203", "pref_name" : "東京都", "shared_name" : "9934203", "lat" : 35.742453999999995, "y" : -357424.54, "x" : 1397689.8899999997 }, "position" : { "x" : 1397689.8899999997, "y" : -357424.54 }, "selected" : false }, { "data" : { "id" : "6073", "station_name" : "西早稲田", "close_ymd" : "", "lon" : 139.709101, "post" : "162-0051", "e_status" : 0, "SUID" : 6073, "station_g_cd" : 2801011, "add" : "新宿区西早稲田二丁目", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801011", "pref_name" : "東京都", "shared_name" : "2801011", "lat" : 35.708242, "y" : -357082.42, "x" : 1397091.01 }, "position" : { "x" : 1397091.01, "y" : -357082.42 }, "selected" : false }, { "data" : { "id" : "7713", "station_name" : "西日暮里", "close_ymd" : "", "lon" : 139.76685700000002, "post" : "", "e_status" : 0, "SUID" : 7713, "station_g_cd" : 1130217, "add" : "東京都荒川区西日暮里五丁目31-7", "line_cd" : 99342, "selected" : false, "open_ymd" : "", "name" : "9934202", "pref_name" : "東京都", "shared_name" : "9934202", "lat" : 35.731953999999995, "y" : -357319.5399999999, "x" : 1397668.57 }, "position" : { "x" : 1397668.57, "y" : -357319.5399999999 }, "selected" : false }, { "data" : { "id" : "6072", "station_name" : "雑司が谷", "close_ymd" : "", "lon" : 139.714795, "post" : "171-0032", "e_status" : 0, "SUID" : 6072, "station_g_cd" : 2801010, "add" : "豊島区雑司が谷二丁目", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801010", "pref_name" : "東京都", "shared_name" : "2801010", "lat" : 35.720233, "y" : -357202.33, "x" : 1397147.9500000002 }, "position" : { "x" : 1397147.9500000002, "y" : -357202.33 }, "selected" : false }, { "data" : { "id" : "7712", "station_name" : "日暮里", "close_ymd" : "", "lon" : 139.771287, "post" : "116-0013", "e_status" : 0, "SUID" : 7712, "station_g_cd" : 1130218, "add" : "東京都荒川区西日暮里二丁目19-1", "line_cd" : 99342, "selected" : false, "open_ymd" : "1905-04-01", "name" : "9934201", "pref_name" : "東京都", "shared_name" : "9934201", "lat" : 35.727908, "y" : -357279.08, "x" : 1397712.87 }, "position" : { "x" : 1397712.87, "y" : -357279.08 }, "selected" : false }, { "data" : { "id" : "6071", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.708291, "post" : "", "e_status" : 0, "SUID" : 6071, "station_g_cd" : 1130212, "add" : "東京都豊島区", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801009", "pref_name" : "東京都", "shared_name" : "2801009", "lat" : 35.731464, "y" : -357314.64, "x" : 1397082.91 }, "position" : { "x" : 1397082.91, "y" : -357314.64 }, "selected" : false }, { "data" : { "id" : "7711", "station_name" : "早稲田", "close_ymd" : "", "lon" : 139.718928, "post" : "", "e_status" : 0, "SUID" : 7711, "station_g_cd" : 9930530, "add" : "東京都新宿区", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930530", "pref_name" : "東京都", "shared_name" : "9930530", "lat" : 35.711847999999996, "y" : -357118.48, "x" : 1397189.28 }, "position" : { "x" : 1397189.28, "y" : -357118.48 }, "selected" : false }, { "data" : { "id" : "6070", "station_name" : "要町", "close_ymd" : "", "lon" : 139.698715, "post" : "", "e_status" : 0, "SUID" : 6070, "station_g_cd" : 2800608, "add" : "東京都豊島区要町一丁目1-10", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801008", "pref_name" : "東京都", "shared_name" : "2801008", "lat" : 35.73323, "y" : -357332.3, "x" : 1396987.15 }, "position" : { "x" : 1396987.15, "y" : -357332.3 }, "selected" : false }, { "data" : { "id" : "7710", "station_name" : "面影橋", "close_ymd" : "", "lon" : 139.714444, "post" : "169-0051", "e_status" : 0, "SUID" : 7710, "station_g_cd" : 9930529, "add" : "新宿区西早稲田3", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930529", "pref_name" : "東京都", "shared_name" : "9930529", "lat" : 35.712981, "y" : -357129.81, "x" : 1397144.44 }, "position" : { "x" : 1397144.44, "y" : -357129.81 }, "selected" : false }, { "data" : { "id" : "6069", "station_name" : "千川", "close_ymd" : "", "lon" : 139.689271, "post" : "", "e_status" : 0, "SUID" : 6069, "station_g_cd" : 2800607, "add" : "東京都豊島区要町三丁目10-7", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801007", "pref_name" : "東京都", "shared_name" : "2801007", "lat" : 35.738229, "y" : -357382.29, "x" : 1396892.71 }, "position" : { "x" : 1396892.71, "y" : -357382.29 }, "selected" : false }, { "data" : { "id" : "7709", "station_name" : "学習院下", "close_ymd" : "", "lon" : 139.71247, "post" : "171-0033", "e_status" : 0, "SUID" : 7709, "station_g_cd" : 9930528, "add" : "豊島区高田2", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930528", "pref_name" : "東京都", "shared_name" : "9930528", "lat" : 35.716248, "y" : -357162.48, "x" : 1397124.7 }, "position" : { "x" : 1397124.7, "y" : -357162.48 }, "selected" : false }, { "data" : { "id" : "6065", "station_name" : "地下鉄赤塚", "close_ymd" : "", "lon" : 139.644021, "post" : "", "e_status" : 0, "SUID" : 6065, "station_g_cd" : 2100109, "add" : "東京都練馬区北町八丁目37-16", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801003", "pref_name" : "東京都", "shared_name" : "2801003", "lat" : 35.769939, "y" : -357699.39, "x" : 1396440.2100000002 }, "position" : { "x" : 1396440.2100000002, "y" : -357699.39 }, "selected" : false }, { "data" : { "id" : "6066", "station_name" : "平和台", "close_ymd" : "", "lon" : 139.653762, "post" : "", "e_status" : 0, "SUID" : 6066, "station_g_cd" : 2800604, "add" : "東京都練馬区早宮2-17-48", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801004", "pref_name" : "東京都", "shared_name" : "2801004", "lat" : 35.757863, "y" : -357578.63, "x" : 1396537.62 }, "position" : { "x" : 1396537.62, "y" : -357578.63 }, "selected" : false }, { "data" : { "id" : "6067", "station_name" : "氷川台", "close_ymd" : "", "lon" : 139.66556699999998, "post" : "", "e_status" : 0, "SUID" : 6067, "station_g_cd" : 2800605, "add" : "東京都練馬区氷川台三丁目38-18", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801005", "pref_name" : "東京都", "shared_name" : "2801005", "lat" : 35.74955, "y" : -357495.5, "x" : 1396655.67 }, "position" : { "x" : 1396655.67, "y" : -357495.5 }, "selected" : false }, { "data" : { "id" : "6068", "station_name" : "小竹向原", "close_ymd" : "", "lon" : 139.678572, "post" : "", "e_status" : 0, "SUID" : 6068, "station_g_cd" : 2200301, "add" : "東京都練馬区小竹町二丁目16-15", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801006", "pref_name" : "東京都", "shared_name" : "2801006", "lat" : 35.743803, "y" : -357438.02999999997, "x" : 1396785.72 }, "position" : { "x" : 1396785.72, "y" : -357438.02999999997 }, "selected" : false }, { "data" : { "id" : "6061", "station_name" : "白金台", "close_ymd" : "", "lon" : 139.726133, "post" : "108-0071", "e_status" : 0, "SUID" : 6061, "station_g_cd" : 2800918, "add" : "港区白金台3-2", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800918", "pref_name" : "東京都", "shared_name" : "2800918", "lat" : 35.637917, "y" : -356379.17000000004, "x" : 1397261.33 }, "position" : { "x" : 1397261.33, "y" : -356379.17000000004 }, "selected" : false }, { "data" : { "id" : "6062", "station_name" : "目黒", "close_ymd" : "", "lon" : 139.7155, "post" : "", "e_status" : 0, "SUID" : 6062, "station_g_cd" : 1130203, "add" : "東京都品川区上大崎四丁目2-1", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800919", "pref_name" : "東京都", "shared_name" : "2800919", "lat" : 35.633272, "y" : -356332.72, "x" : 1397155.0 }, "position" : { "x" : 1397155.0, "y" : -356332.72 }, "selected" : false }, { "data" : { "id" : "6064", "station_name" : "地下鉄成増", "close_ymd" : "", "lon" : 139.631497, "post" : "", "e_status" : 0, "SUID" : 6064, "station_g_cd" : 2100110, "add" : "東京都板橋区成増二丁目11-3", "line_cd" : 28010, "selected" : false, "open_ymd" : "", "name" : "2801002", "pref_name" : "東京都", "shared_name" : "2801002", "lat" : 35.776557000000004, "y" : -357765.57000000007, "x" : 1396314.97 }, "position" : { "x" : 1396314.97, "y" : -357765.57000000007 }, "selected" : false }, { "data" : { "id" : "6057", "station_name" : "溜池山王", "close_ymd" : "", "lon" : 139.741419, "post" : "100-0014", "e_status" : 0, "SUID" : 6057, "station_g_cd" : 2800114, "add" : "千代田区永田町2-11-1", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800914", "pref_name" : "東京都", "shared_name" : "2800914", "lat" : 35.673621000000004, "y" : -356736.21, "x" : 1397414.1900000002 }, "position" : { "x" : 1397414.1900000002, "y" : -356736.21 }, "selected" : false }, { "data" : { "id" : "6058", "station_name" : "六本木一丁目", "close_ymd" : "", "lon" : 139.739, "post" : "106-0032", "e_status" : 0, "SUID" : 6058, "station_g_cd" : 2800915, "add" : "港区六本木1-4-1", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800915", "pref_name" : "東京都", "shared_name" : "2800915", "lat" : 35.665595, "y" : -356655.95, "x" : 1397390.0 }, "position" : { "x" : 1397390.0, "y" : -356655.95 }, "selected" : false }, { "data" : { "id" : "6059", "station_name" : "麻布十番", "close_ymd" : "", "lon" : 139.737051, "post" : "106-0045", "e_status" : 0, "SUID" : 6059, "station_g_cd" : 2800916, "add" : "港区麻布十番4-4-9", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800916", "pref_name" : "東京都", "shared_name" : "2800916", "lat" : 35.654682, "y" : -356546.82, "x" : 1397370.51 }, "position" : { "x" : 1397370.51, "y" : -356546.82 }, "selected" : false }, { "data" : { "id" : "6060", "station_name" : "白金高輪", "close_ymd" : "", "lon" : 139.734104, "post" : "108-0074", "e_status" : 0, "SUID" : 6060, "station_g_cd" : 2800917, "add" : "港区高輪1-3-20", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800917", "pref_name" : "東京都", "shared_name" : "2800917", "lat" : 35.642903000000004, "y" : -356429.03, "x" : 1397341.04 }, "position" : { "x" : 1397341.04, "y" : -356429.03 }, "selected" : false }, { "data" : { "id" : "6053", "station_name" : "飯田橋", "close_ymd" : "", "lon" : 139.74366899999998, "post" : "", "e_status" : 0, "SUID" : 6053, "station_g_cd" : 1131205, "add" : "東京都新宿区神楽坂一丁目13", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800910", "pref_name" : "東京都", "shared_name" : "2800910", "lat" : 35.701934, "y" : -357019.34, "x" : 1397436.69 }, "position" : { "x" : 1397436.69, "y" : -357019.34 }, "selected" : false }, { "data" : { "id" : "6054", "station_name" : "市ケ谷", "close_ymd" : "", "lon" : 139.736642, "post" : "", "e_status" : 0, "SUID" : 6054, "station_g_cd" : 1131206, "add" : "東京都千代田区五番町2-1", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800911", "pref_name" : "東京都", "shared_name" : "2800911", "lat" : 35.691295000000004, "y" : -356912.95, "x" : 1397366.42 }, "position" : { "x" : 1397366.42, "y" : -356912.95 }, "selected" : false }, { "data" : { "id" : "6055", "station_name" : "四ツ谷", "close_ymd" : "", "lon" : 139.72955, "post" : "160-0004", "e_status" : 0, "SUID" : 6055, "station_g_cd" : 1131102, "add" : "新宿区四谷1丁目", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800912", "pref_name" : "東京都", "shared_name" : "2800912", "lat" : 35.686032, "y" : -356860.31999999995, "x" : 1397295.5 }, "position" : { "x" : 1397295.5, "y" : -356860.31999999995 }, "selected" : false }, { "data" : { "id" : "6056", "station_name" : "永田町", "close_ymd" : "", "lon" : 139.740258, "post" : "", "e_status" : 0, "SUID" : 6056, "station_g_cd" : 2800115, "add" : "東京都千代田区永田町一丁目11-28", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800913", "pref_name" : "東京都", "shared_name" : "2800913", "lat" : 35.678757, "y" : -356787.56999999995, "x" : 1397402.58 }, "position" : { "x" : 1397402.58, "y" : -356787.56999999995 }, "selected" : false }, { "data" : { "id" : "7760", "station_name" : "赤羽岩淵", "close_ymd" : "", "lon" : 139.722103, "post" : "115-0045", "e_status" : 0, "SUID" : 7760, "station_g_cd" : 2800901, "add" : "北区赤羽1-52-8", "line_cd" : 99307, "selected" : false, "open_ymd" : "", "name" : "9930701", "pref_name" : "東京都", "shared_name" : "9930701", "lat" : 35.783417, "y" : -357834.17, "x" : 1397221.03 }, "position" : { "x" : 1397221.03, "y" : -357834.17 }, "selected" : false }, { "data" : { "id" : "6050", "station_name" : "本駒込", "close_ymd" : "", "lon" : 139.753828, "post" : "113-0023", "e_status" : 0, "SUID" : 6050, "station_g_cd" : 2800907, "add" : "文京区向丘2-37-1", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800907", "pref_name" : "東京都", "shared_name" : "2800907", "lat" : 35.724154999999996, "y" : -357241.55, "x" : 1397538.28 }, "position" : { "x" : 1397538.28, "y" : -357241.55 }, "selected" : false }, { "data" : { "id" : "6049", "station_name" : "駒込", "close_ymd" : "", "lon" : 139.746442, "post" : "", "e_status" : 0, "SUID" : 6049, "station_g_cd" : 1130215, "add" : "東京都豊島区駒込二丁目", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800906", "pref_name" : "東京都", "shared_name" : "2800906", "lat" : 35.736959000000006, "y" : -357369.5900000001, "x" : 1397464.42 }, "position" : { "x" : 1397464.42, "y" : -357369.5900000001 }, "selected" : false }, { "data" : { "id" : "6052", "station_name" : "後楽園", "close_ymd" : "", "lon" : 139.75186399999998, "post" : "112-0003", "e_status" : 0, "SUID" : 6052, "station_g_cd" : 2800204, "add" : "文京区春日1-2-3", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800909", "pref_name" : "東京都", "shared_name" : "2800909", "lat" : 35.707898, "y" : -357078.98, "x" : 1397518.64 }, "position" : { "x" : 1397518.64, "y" : -357078.98 }, "selected" : false }, { "data" : { "id" : "6051", "station_name" : "東大前", "close_ymd" : "", "lon" : 139.758025, "post" : "113-0023", "e_status" : 0, "SUID" : 6051, "station_g_cd" : 2800908, "add" : "文京区向丘1-19-2", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800908", "pref_name" : "東京都", "shared_name" : "2800908", "lat" : 35.717633, "y" : -357176.33, "x" : 1397580.25 }, "position" : { "x" : 1397580.25, "y" : -357176.33 }, "selected" : false }, { "data" : { "id" : "6046", "station_name" : "王子神谷", "close_ymd" : "", "lon" : 139.73593300000002, "post" : "114-0002", "e_status" : 0, "SUID" : 6046, "station_g_cd" : 2800903, "add" : "北区王子5-2-11", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800903", "pref_name" : "東京都", "shared_name" : "2800903", "lat" : 35.765172, "y" : -357651.72, "x" : 1397359.33 }, "position" : { "x" : 1397359.33, "y" : -357651.72 }, "selected" : false }, { "data" : { "id" : "6045", "station_name" : "志茂", "close_ymd" : "", "lon" : 139.732599, "post" : "115-0042", "e_status" : 0, "SUID" : 6045, "station_g_cd" : 2800902, "add" : "北区志茂2-1-18", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800902", "pref_name" : "東京都", "shared_name" : "2800902", "lat" : 35.777947999999995, "y" : -357779.4799999999, "x" : 1397325.99 }, "position" : { "x" : 1397325.99, "y" : -357779.4799999999 }, "selected" : false }, { "data" : { "id" : "6048", "station_name" : "西ケ原", "close_ymd" : "", "lon" : 139.742322, "post" : "114-0024", "e_status" : 0, "SUID" : 6048, "station_g_cd" : 2800905, "add" : "東京都北区西ヶ原二丁目3-8", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800905", "pref_name" : "東京都", "shared_name" : "2800905", "lat" : 35.746008, "y" : -357460.08, "x" : 1397423.22 }, "position" : { "x" : 1397423.22, "y" : -357460.08 }, "selected" : false }, { "data" : { "id" : "6047", "station_name" : "王子", "close_ymd" : "", "lon" : 139.737618, "post" : "114-0002", "e_status" : 0, "SUID" : 6047, "station_g_cd" : 1133212, "add" : "北区王子1丁目", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800904", "pref_name" : "東京都", "shared_name" : "2800904", "lat" : 35.753966, "y" : -357539.66, "x" : 1397376.18 }, "position" : { "x" : 1397376.18, "y" : -357539.66 }, "selected" : false }, { "data" : { "id" : "6042", "station_name" : "錦糸町", "close_ymd" : "", "lon" : 139.814941, "post" : "130-0022", "e_status" : 0, "SUID" : 6042, "station_g_cd" : 1131322, "add" : "墨田区江東橋3丁目", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800812", "pref_name" : "東京都", "shared_name" : "2800812", "lat" : 35.697578, "y" : -356975.78, "x" : 1398149.4100000001 }, "position" : { "x" : 1398149.4100000001, "y" : -356975.78 }, "selected" : false }, { "data" : { "id" : "6041", "station_name" : "住吉", "close_ymd" : "", "lon" : 139.815681, "post" : "135-0002", "e_status" : 0, "SUID" : 6041, "station_g_cd" : 2800814, "add" : "江東区住吉2-23-12", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800814", "pref_name" : "東京都", "shared_name" : "2800814", "lat" : 35.689073, "y" : -356890.73, "x" : 1398156.81 }, "position" : { "x" : 1398156.81, "y" : -356890.73 }, "selected" : false }, { "data" : { "id" : "6044", "station_name" : "赤羽岩淵", "close_ymd" : "", "lon" : 139.722103, "post" : "115-0045", "e_status" : 0, "SUID" : 6044, "station_g_cd" : 2800901, "add" : "北区赤羽1-52-8", "line_cd" : 28009, "selected" : false, "open_ymd" : "", "name" : "2800901", "pref_name" : "東京都", "shared_name" : "2800901", "lat" : 35.783417, "y" : -357834.17, "x" : 1397221.03 }, "position" : { "x" : 1397221.03, "y" : -357834.17 }, "selected" : false }, { "data" : { "id" : "6043", "station_name" : "押上〈スカイツリー前〉", "close_ymd" : "", "lon" : 139.812935, "post" : "131-0045", "e_status" : 0, "SUID" : 6043, "station_g_cd" : 2100203, "add" : "墨田区押上一丁目", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800813", "pref_name" : "東京都", "shared_name" : "2800813", "lat" : 35.710702000000005, "y" : -357107.0200000001, "x" : 1398129.35 }, "position" : { "x" : 1398129.35, "y" : -357107.0200000001 }, "selected" : false }, { "data" : { "id" : "6038", "station_name" : "三越前", "close_ymd" : "", "lon" : 139.773147, "post" : "103-0022", "e_status" : 0, "SUID" : 6038, "station_g_cd" : 1131402, "add" : "中央区日本橋室町1-8-1", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800809", "pref_name" : "東京都", "shared_name" : "2800809", "lat" : 35.684908, "y" : -356849.08, "x" : 1397731.47 }, "position" : { "x" : 1397731.47, "y" : -356849.08 }, "selected" : false }, { "data" : { "id" : "6037", "station_name" : "大手町", "close_ymd" : "", "lon" : 139.764107, "post" : "100-0004", "e_status" : 0, "SUID" : 6037, "station_g_cd" : 2800208, "add" : "千代田区大手町1丁目", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800808", "pref_name" : "東京都", "shared_name" : "2800808", "lat" : 35.686859999999996, "y" : -356868.6, "x" : 1397641.07 }, "position" : { "x" : 1397641.07, "y" : -356868.6 }, "selected" : false }, { "data" : { "id" : "6040", "station_name" : "清澄白河", "close_ymd" : "", "lon" : 139.798851, "post" : "135-0021", "e_status" : 0, "SUID" : 6040, "station_g_cd" : 2800811, "add" : "江東区白河1-7-14", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800811", "pref_name" : "東京都", "shared_name" : "2800811", "lat" : 35.682105, "y" : -356821.05, "x" : 1397988.5100000002 }, "position" : { "x" : 1397988.5100000002, "y" : -356821.05 }, "selected" : false }, { "data" : { "id" : "6039", "station_name" : "水天宮前", "close_ymd" : "", "lon" : 139.785377, "post" : "103-0014", "e_status" : 0, "SUID" : 6039, "station_g_cd" : 2800810, "add" : "中央区日本橋蛎殻町2-1-1", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800810", "pref_name" : "東京都", "shared_name" : "2800810", "lat" : 35.682683000000004, "y" : -356826.83, "x" : 1397853.77 }, "position" : { "x" : 1397853.77, "y" : -356826.83 }, "selected" : false }, { "data" : { "id" : "6024", "station_name" : "月島", "close_ymd" : "", "lon" : 139.784233, "post" : "104-0052", "e_status" : 0, "SUID" : 6024, "station_g_cd" : 2800621, "add" : "東京都中央区月島一丁目3-9", "line_cd" : 28006, "selected" : false, "open_ymd" : "1988-06-08", "name" : "2800621", "pref_name" : "東京都", "shared_name" : "2800621", "lat" : 35.664871000000005, "y" : -356648.7100000001, "x" : 1397842.33 }, "position" : { "x" : 1397842.33, "y" : -356648.7100000001 }, "selected" : false }, { "data" : { "id" : "6023", "station_name" : "新富町", "close_ymd" : "", "lon" : 139.77371100000002, "post" : "104-0045", "e_status" : 0, "SUID" : 6023, "station_g_cd" : 2800620, "add" : "東京都中央区築地一丁目1-1", "line_cd" : 28006, "selected" : false, "open_ymd" : "1980-03-27", "name" : "2800620", "pref_name" : "東京都", "shared_name" : "2800620", "lat" : 35.670462, "y" : -356704.62, "x" : 1397737.11 }, "position" : { "x" : 1397737.11, "y" : -356704.62 }, "selected" : false }, { "data" : { "id" : "6022", "station_name" : "銀座一丁目", "close_ymd" : "", "lon" : 139.767045, "post" : "104-0061", "e_status" : 0, "SUID" : 6022, "station_g_cd" : 2800619, "add" : "東京都中央区銀座一丁目7-12", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800619", "pref_name" : "東京都", "shared_name" : "2800619", "lat" : 35.67435, "y" : -356743.49999999994, "x" : 1397670.45 }, "position" : { "x" : 1397670.45, "y" : -356743.49999999994 }, "selected" : false }, { "data" : { "id" : "6021", "station_name" : "有楽町", "close_ymd" : "", "lon" : 139.763265, "post" : "100-0006", "e_status" : 0, "SUID" : 6021, "station_g_cd" : 1130225, "add" : "東京都千代田区有楽町一丁目11-1", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800618", "pref_name" : "東京都", "shared_name" : "2800618", "lat" : 35.675714, "y" : -356757.14, "x" : 1397632.65 }, "position" : { "x" : 1397632.65, "y" : -356757.14 }, "selected" : false }, { "data" : { "id" : "6028", "station_name" : "新線池袋", "close_ymd" : "2008-06-14", "lon" : 139.710388, "post" : "171-0021", "e_status" : 2, "SUID" : 6028, "station_g_cd" : 1130212, "add" : "東京都豊島区西池袋", "line_cd" : 28007, "selected" : false, "open_ymd" : "1994-12-07", "name" : "2800701", "pref_name" : "東京都", "shared_name" : "2800701", "lat" : 35.730645, "y" : -357306.45, "x" : 1397103.88 }, "position" : { "x" : 1397103.88, "y" : -357306.45 }, "selected" : false }, { "data" : { "id" : "6027", "station_name" : "新木場", "close_ymd" : "", "lon" : 139.826254, "post" : "136-0082", "e_status" : 0, "SUID" : 6027, "station_g_cd" : 1132605, "add" : "東京都江東区新木場一丁目6", "line_cd" : 28006, "selected" : false, "open_ymd" : "1988-06-08", "name" : "2800624", "pref_name" : "東京都", "shared_name" : "2800624", "lat" : 35.645832, "y" : -356458.32, "x" : 1398262.54 }, "position" : { "x" : 1398262.54, "y" : -356458.32 }, "selected" : false }, { "data" : { "id" : "6026", "station_name" : "辰巳", "close_ymd" : "", "lon" : 139.81052, "post" : "135-0053", "e_status" : 0, "SUID" : 6026, "station_g_cd" : 2800623, "add" : "東京都江東区辰巳一丁目1-44", "line_cd" : 28006, "selected" : false, "open_ymd" : "1988-06-08", "name" : "2800623", "pref_name" : "東京都", "shared_name" : "2800623", "lat" : 35.645576, "y" : -356455.76, "x" : 1398105.2 }, "position" : { "x" : 1398105.2, "y" : -356455.76 }, "selected" : false }, { "data" : { "id" : "6025", "station_name" : "豊洲", "close_ymd" : "", "lon" : 139.79621, "post" : "135-0061", "e_status" : 0, "SUID" : 6025, "station_g_cd" : 2800622, "add" : "東京都江東区豊洲四丁目1-1", "line_cd" : 28006, "selected" : false, "open_ymd" : "1988-06-08", "name" : "2800622", "pref_name" : "東京都", "shared_name" : "2800622", "lat" : 35.654908, "y" : -356549.08, "x" : 1397962.1 }, "position" : { "x" : 1397962.1, "y" : -356549.08 }, "selected" : false }, { "data" : { "id" : "6032", "station_name" : "青山一丁目", "close_ymd" : "", "lon" : 139.72415900000001, "post" : "107-0062", "e_status" : 0, "SUID" : 6032, "station_g_cd" : 2800116, "add" : "港区南青山1-1-19", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800803", "pref_name" : "東京都", "shared_name" : "2800803", "lat" : 35.672765000000005, "y" : -356727.6500000001, "x" : 1397241.59 }, "position" : { "x" : 1397241.59, "y" : -356727.6500000001 }, "selected" : false }, { "data" : { "id" : "6031", "station_name" : "表参道", "close_ymd" : "", "lon" : 139.712314, "post" : "107-0061", "e_status" : 0, "SUID" : 6031, "station_g_cd" : 2800118, "add" : "港区北青山3丁目", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800802", "pref_name" : "東京都", "shared_name" : "2800802", "lat" : 35.665246999999994, "y" : -356652.4699999999, "x" : 1397123.14 }, "position" : { "x" : 1397123.14, "y" : -356652.4699999999 }, "selected" : false }, { "data" : { "id" : "6030", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.701, "post" : "", "e_status" : 0, "SUID" : 6030, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂二丁目1-1", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800801", "pref_name" : "東京都", "shared_name" : "2800801", "lat" : 35.659065999999996, "y" : -356590.66, "x" : 1397010.0 }, "position" : { "x" : 1397010.0, "y" : -356590.66 }, "selected" : false }, { "data" : { "id" : "6029", "station_name" : "小竹向原", "close_ymd" : "", "lon" : 139.678572, "post" : "176-0004", "e_status" : 2, "SUID" : 6029, "station_g_cd" : 2200301, "add" : "東京都練馬区小竹町二丁目16-15", "line_cd" : 28007, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800702", "pref_name" : "東京都", "shared_name" : "2800702", "lat" : 35.743803, "y" : -357438.02999999997, "x" : 1396785.72 }, "position" : { "x" : 1396785.72, "y" : -357438.02999999997 }, "selected" : false }, { "data" : { "id" : "6036", "station_name" : "神保町", "close_ymd" : "", "lon" : 139.757606, "post" : "101-0051", "e_status" : 0, "SUID" : 6036, "station_g_cd" : 2800807, "add" : "千代田区神田神保町2-2", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800807", "pref_name" : "東京都", "shared_name" : "2800807", "lat" : 35.695966, "y" : -356959.66, "x" : 1397576.06 }, "position" : { "x" : 1397576.06, "y" : -356959.66 }, "selected" : false }, { "data" : { "id" : "6035", "station_name" : "九段下", "close_ymd" : "", "lon" : 139.751948, "post" : "102-0074", "e_status" : 0, "SUID" : 6035, "station_g_cd" : 2800407, "add" : "千代田区九段南1-6-1", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800806", "pref_name" : "東京都", "shared_name" : "2800806", "lat" : 35.695589, "y" : -356955.88999999996, "x" : 1397519.48 }, "position" : { "x" : 1397519.48, "y" : -356955.88999999996 }, "selected" : false }, { "data" : { "id" : "6034", "station_name" : "半蔵門", "close_ymd" : "", "lon" : 139.74163000000001, "post" : "102-0083", "e_status" : 0, "SUID" : 6034, "station_g_cd" : 2800805, "add" : "千代田区麹町1-6", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800805", "pref_name" : "東京都", "shared_name" : "2800805", "lat" : 35.685703000000004, "y" : -356857.03, "x" : 1397416.3 }, "position" : { "x" : 1397416.3, "y" : -356857.03 }, "selected" : false }, { "data" : { "id" : "6033", "station_name" : "永田町", "close_ymd" : "", "lon" : 139.740258, "post" : "", "e_status" : 0, "SUID" : 6033, "station_g_cd" : 2800115, "add" : "東京都千代田区永田町一丁目11-29", "line_cd" : 28008, "selected" : false, "open_ymd" : "", "name" : "2800804", "pref_name" : "東京都", "shared_name" : "2800804", "lat" : 35.678757, "y" : -356787.56999999995, "x" : 1397402.58 }, "position" : { "x" : 1397402.58, "y" : -356787.56999999995 }, "selected" : false }, { "data" : { "id" : "6007", "station_name" : "平和台", "close_ymd" : "", "lon" : 139.653762, "post" : "179-0085", "e_status" : 0, "SUID" : 6007, "station_g_cd" : 2800604, "add" : "東京都練馬区早宮2-17-48", "line_cd" : 28006, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800604", "pref_name" : "東京都", "shared_name" : "2800604", "lat" : 35.757863, "y" : -357578.63, "x" : 1396537.62 }, "position" : { "x" : 1396537.62, "y" : -357578.63 }, "selected" : false }, { "data" : { "id" : "6008", "station_name" : "氷川台", "close_ymd" : "", "lon" : 139.66556699999998, "post" : "179-0084", "e_status" : 0, "SUID" : 6008, "station_g_cd" : 2800605, "add" : "東京都練馬区氷川台三丁目38-18", "line_cd" : 28006, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800605", "pref_name" : "東京都", "shared_name" : "2800605", "lat" : 35.74955, "y" : -357495.5, "x" : 1396655.67 }, "position" : { "x" : 1396655.67, "y" : -357495.5 }, "selected" : false }, { "data" : { "id" : "6005", "station_name" : "地下鉄成増", "close_ymd" : "", "lon" : 139.631497, "post" : "175-0094", "e_status" : 0, "SUID" : 6005, "station_g_cd" : 2100110, "add" : "東京都板橋区成増二丁目11-3", "line_cd" : 28006, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800602", "pref_name" : "東京都", "shared_name" : "2800602", "lat" : 35.776557000000004, "y" : -357765.57000000007, "x" : 1396314.97 }, "position" : { "x" : 1396314.97, "y" : -357765.57000000007 }, "selected" : false }, { "data" : { "id" : "6006", "station_name" : "地下鉄赤塚", "close_ymd" : "", "lon" : 139.644021, "post" : "179-0081", "e_status" : 0, "SUID" : 6006, "station_g_cd" : 2100109, "add" : "東京都練馬区北町八丁目37-16", "line_cd" : 28006, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800603", "pref_name" : "東京都", "shared_name" : "2800603", "lat" : 35.769939, "y" : -357699.39, "x" : 1396440.2100000002 }, "position" : { "x" : 1396440.2100000002, "y" : -357699.39 }, "selected" : false }, { "data" : { "id" : "6011", "station_name" : "要町", "close_ymd" : "", "lon" : 139.698715, "post" : "171-0043", "e_status" : 0, "SUID" : 6011, "station_g_cd" : 2800608, "add" : "東京都豊島区要町一丁目1-10", "line_cd" : 28006, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800608", "pref_name" : "東京都", "shared_name" : "2800608", "lat" : 35.73323, "y" : -357332.3, "x" : 1396987.15 }, "position" : { "x" : 1396987.15, "y" : -357332.3 }, "selected" : false }, { "data" : { "id" : "6012", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.71008799999998, "post" : "171-0021", "e_status" : 0, "SUID" : 6012, "station_g_cd" : 1130212, "add" : "東京都豊島区西池袋三丁目28-14", "line_cd" : 28006, "selected" : false, "open_ymd" : "1954-01-20", "name" : "2800609", "pref_name" : "東京都", "shared_name" : "2800609", "lat" : 35.729565, "y" : -357295.65, "x" : 1397100.88 }, "position" : { "x" : 1397100.88, "y" : -357295.65 }, "selected" : false }, { "data" : { "id" : "6009", "station_name" : "小竹向原", "close_ymd" : "", "lon" : 139.678572, "post" : "176-0004", "e_status" : 0, "SUID" : 6009, "station_g_cd" : 2200301, "add" : "東京都練馬区小竹町二丁目16-15", "line_cd" : 28006, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800606", "pref_name" : "東京都", "shared_name" : "2800606", "lat" : 35.743803, "y" : -357438.02999999997, "x" : 1396785.72 }, "position" : { "x" : 1396785.72, "y" : -357438.02999999997 }, "selected" : false }, { "data" : { "id" : "6010", "station_name" : "千川", "close_ymd" : "", "lon" : 139.689271, "post" : "171-0043", "e_status" : 0, "SUID" : 6010, "station_g_cd" : 2800607, "add" : "東京都豊島区要町三丁目10-7", "line_cd" : 28006, "selected" : false, "open_ymd" : "1983-06-24", "name" : "2800607", "pref_name" : "東京都", "shared_name" : "2800607", "lat" : 35.738229, "y" : -357382.29, "x" : 1396892.71 }, "position" : { "x" : 1396892.71, "y" : -357382.29 }, "selected" : false }, { "data" : { "id" : "6015", "station_name" : "江戸川橋", "close_ymd" : "", "lon" : 139.73353799999998, "post" : "112-0014", "e_status" : 0, "SUID" : 6015, "station_g_cd" : 2800612, "add" : "東京都文京区関口一丁目19-6", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800612", "pref_name" : "東京都", "shared_name" : "2800612", "lat" : 35.709495000000004, "y" : -357094.95, "x" : 1397335.38 }, "position" : { "x" : 1397335.38, "y" : -357094.95 }, "selected" : false }, { "data" : { "id" : "6016", "station_name" : "飯田橋", "close_ymd" : "", "lon" : 139.74366899999998, "post" : "162-0825", "e_status" : 0, "SUID" : 6016, "station_g_cd" : 1131205, "add" : "東京都新宿区神楽坂一丁目13", "line_cd" : 28006, "selected" : false, "open_ymd" : "1964-12-23", "name" : "2800613", "pref_name" : "東京都", "shared_name" : "2800613", "lat" : 35.701934, "y" : -357019.34, "x" : 1397436.69 }, "position" : { "x" : 1397436.69, "y" : -357019.34 }, "selected" : false }, { "data" : { "id" : "6013", "station_name" : "東池袋", "close_ymd" : "", "lon" : 139.719546, "post" : "170-0013", "e_status" : 0, "SUID" : 6013, "station_g_cd" : 2800610, "add" : "東京都豊島区東池袋四丁目4-4", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800610", "pref_name" : "東京都", "shared_name" : "2800610", "lat" : 35.725732, "y" : -357257.32, "x" : 1397195.4600000002 }, "position" : { "x" : 1397195.4600000002, "y" : -357257.32 }, "selected" : false }, { "data" : { "id" : "6014", "station_name" : "護国寺", "close_ymd" : "", "lon" : 139.72754, "post" : "112-0012", "e_status" : 0, "SUID" : 6014, "station_g_cd" : 2800611, "add" : "東京都文京区大塚五丁目40-8", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800611", "pref_name" : "東京都", "shared_name" : "2800611", "lat" : 35.719044, "y" : -357190.43999999994, "x" : 1397275.4000000001 }, "position" : { "x" : 1397275.4000000001, "y" : -357190.43999999994 }, "selected" : false }, { "data" : { "id" : "6019", "station_name" : "永田町", "close_ymd" : "", "lon" : 139.740258, "post" : "100-0014", "e_status" : 0, "SUID" : 6019, "station_g_cd" : 2800115, "add" : "東京都千代田区永田町一丁目11-28", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800616", "pref_name" : "東京都", "shared_name" : "2800616", "lat" : 35.678757, "y" : -356787.56999999995, "x" : 1397402.58 }, "position" : { "x" : 1397402.58, "y" : -356787.56999999995 }, "selected" : false }, { "data" : { "id" : "6020", "station_name" : "桜田門", "close_ymd" : "", "lon" : 139.75149, "post" : "100-0013", "e_status" : 0, "SUID" : 6020, "station_g_cd" : 2800617, "add" : "東京都千代田区霞が関二丁目1-1", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800617", "pref_name" : "東京都", "shared_name" : "2800617", "lat" : 35.677405, "y" : -356774.05, "x" : 1397514.9 }, "position" : { "x" : 1397514.9, "y" : -356774.05 }, "selected" : false }, { "data" : { "id" : "6017", "station_name" : "市ケ谷", "close_ymd" : "", "lon" : 139.73647, "post" : "162-0843", "e_status" : 0, "SUID" : 6017, "station_g_cd" : 1131206, "add" : "東京都新宿区市谷田町一丁目1", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800614", "pref_name" : "東京都", "shared_name" : "2800614", "lat" : 35.691958, "y" : -356919.58, "x" : 1397364.7 }, "position" : { "x" : 1397364.7, "y" : -356919.58 }, "selected" : false }, { "data" : { "id" : "6018", "station_name" : "麹町", "close_ymd" : "", "lon" : 139.73761299999998, "post" : "102-0083", "e_status" : 0, "SUID" : 6018, "station_g_cd" : 2800615, "add" : "東京都千代田区麹町三丁目2", "line_cd" : 28006, "selected" : false, "open_ymd" : "1974-10-30", "name" : "2800615", "pref_name" : "東京都", "shared_name" : "2800615", "lat" : 35.684006, "y" : -356840.05999999994, "x" : 1397376.13 }, "position" : { "x" : 1397376.13, "y" : -356840.05999999994 }, "selected" : false }, { "data" : { "id" : "5990", "station_name" : "根津", "close_ymd" : "", "lon" : 139.765655, "post" : "113-0031", "e_status" : 0, "SUID" : 5990, "station_g_cd" : 2800507, "add" : "文京区根津1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800507", "pref_name" : "東京都", "shared_name" : "2800507", "lat" : 35.7174, "y" : -357174.0, "x" : 1397656.55 }, "position" : { "x" : 1397656.55, "y" : -357174.0 }, "selected" : false }, { "data" : { "id" : "5989", "station_name" : "千駄木", "close_ymd" : "", "lon" : 139.763243, "post" : "113-0022", "e_status" : 0, "SUID" : 5989, "station_g_cd" : 2800506, "add" : "文京区千駄木2丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800506", "pref_name" : "東京都", "shared_name" : "2800506", "lat" : 35.725549, "y" : -357255.49, "x" : 1397632.43 }, "position" : { "x" : 1397632.43, "y" : -357255.49 }, "selected" : false }, { "data" : { "id" : "5992", "station_name" : "新御茶ノ水", "close_ymd" : "", "lon" : 139.76601399999998, "post" : "101-0062", "e_status" : 0, "SUID" : 5992, "station_g_cd" : 1131203, "add" : "千代田区神田駿河台3丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800509", "pref_name" : "東京都", "shared_name" : "2800509", "lat" : 35.698071999999996, "y" : -356980.72, "x" : 1397660.14 }, "position" : { "x" : 1397660.14, "y" : -356980.72 }, "selected" : false }, { "data" : { "id" : "5991", "station_name" : "湯島", "close_ymd" : "", "lon" : 139.769916, "post" : "113-0034", "e_status" : 0, "SUID" : 5991, "station_g_cd" : 2800508, "add" : "文京区湯島3丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800508", "pref_name" : "東京都", "shared_name" : "2800508", "lat" : 35.708242999999996, "y" : -357082.42999999993, "x" : 1397699.16 }, "position" : { "x" : 1397699.16, "y" : -357082.42999999993 }, "selected" : false }, { "data" : { "id" : "5994", "station_name" : "二重橋前", "close_ymd" : "", "lon" : 139.761948, "post" : "100-0005", "e_status" : 0, "SUID" : 5994, "station_g_cd" : 2800511, "add" : "千代田区丸の内2丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800511", "pref_name" : "東京都", "shared_name" : "2800511", "lat" : 35.681071, "y" : -356810.71, "x" : 1397619.48 }, "position" : { "x" : 1397619.48, "y" : -356810.71 }, "selected" : false }, { "data" : { "id" : "5993", "station_name" : "大手町", "close_ymd" : "", "lon" : 139.763399, "post" : "100-0004", "e_status" : 0, "SUID" : 5993, "station_g_cd" : 2800208, "add" : "千代田区大手町1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800510", "pref_name" : "東京都", "shared_name" : "2800510", "lat" : 35.686153999999995, "y" : -356861.5399999999, "x" : 1397633.99 }, "position" : { "x" : 1397633.99, "y" : -356861.5399999999 }, "selected" : false }, { "data" : { "id" : "5996", "station_name" : "霞ケ関", "close_ymd" : "", "lon" : 139.750899, "post" : "100-0013", "e_status" : 0, "SUID" : 5996, "station_g_cd" : 2800211, "add" : "千代田区霞が関2丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800513", "pref_name" : "東京都", "shared_name" : "2800513", "lat" : 35.673838, "y" : -356738.38000000006, "x" : 1397508.99 }, "position" : { "x" : 1397508.99, "y" : -356738.38000000006 }, "selected" : false }, { "data" : { "id" : "5995", "station_name" : "日比谷", "close_ymd" : "", "lon" : 139.758732, "post" : "100-0006", "e_status" : 0, "SUID" : 5995, "station_g_cd" : 2800315, "add" : "千代田区有楽町1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800512", "pref_name" : "東京都", "shared_name" : "2800512", "lat" : 35.674240999999995, "y" : -356742.41, "x" : 1397587.32 }, "position" : { "x" : 1397587.32, "y" : -356742.41 }, "selected" : false }, { "data" : { "id" : "5998", "station_name" : "赤坂", "close_ymd" : "", "lon" : 139.738348, "post" : "107-0052", "e_status" : 0, "SUID" : 5998, "station_g_cd" : 2800515, "add" : "港区赤坂5丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800515", "pref_name" : "東京都", "shared_name" : "2800515", "lat" : 35.67323, "y" : -356732.3, "x" : 1397383.48 }, "position" : { "x" : 1397383.48, "y" : -356732.3 }, "selected" : false }, { "data" : { "id" : "5997", "station_name" : "国会議事堂前", "close_ymd" : "", "lon" : 139.745219, "post" : "100-0014", "e_status" : 0, "SUID" : 5997, "station_g_cd" : 2800212, "add" : "千代田区永田町1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800514", "pref_name" : "東京都", "shared_name" : "2800514", "lat" : 35.67393, "y" : -356739.3, "x" : 1397452.19 }, "position" : { "x" : 1397452.19, "y" : -356739.3 }, "selected" : false }, { "data" : { "id" : "6000", "station_name" : "表参道", "close_ymd" : "", "lon" : 139.712314, "post" : "107-0061", "e_status" : 0, "SUID" : 6000, "station_g_cd" : 2800118, "add" : "港区北青山3丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800517", "pref_name" : "東京都", "shared_name" : "2800517", "lat" : 35.665246999999994, "y" : -356652.4699999999, "x" : 1397123.14 }, "position" : { "x" : 1397123.14, "y" : -356652.4699999999 }, "selected" : false }, { "data" : { "id" : "5999", "station_name" : "乃木坂", "close_ymd" : "", "lon" : 139.726215, "post" : "107-0062", "e_status" : 0, "SUID" : 5999, "station_g_cd" : 2800516, "add" : "港区南青山1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800516", "pref_name" : "東京都", "shared_name" : "2800516", "lat" : 35.666571999999995, "y" : -356665.72, "x" : 1397262.15 }, "position" : { "x" : 1397262.15, "y" : -356665.72 }, "selected" : false }, { "data" : { "id" : "6002", "station_name" : "代々木公園", "close_ymd" : "", "lon" : 139.689099, "post" : "151-0063", "e_status" : 0, "SUID" : 6002, "station_g_cd" : 2500104, "add" : "渋谷区富ケ谷1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800519", "pref_name" : "東京都", "shared_name" : "2800519", "lat" : 35.669187, "y" : -356691.87, "x" : 1396890.99 }, "position" : { "x" : 1396890.99, "y" : -356691.87 }, "selected" : false }, { "data" : { "id" : "6001", "station_name" : "明治神宮前〈原宿〉", "close_ymd" : "", "lon" : 139.703995, "post" : "150-0001", "e_status" : 0, "SUID" : 6001, "station_g_cd" : 1130206, "add" : "渋谷区神宮前1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800518", "pref_name" : "東京都", "shared_name" : "2800518", "lat" : 35.669071, "y" : -356690.71, "x" : 1397039.95 }, "position" : { "x" : 1397039.95, "y" : -356690.71 }, "selected" : false }, { "data" : { "id" : "6003", "station_name" : "代々木上原", "close_ymd" : "", "lon" : 139.680153, "post" : "151-0066", "e_status" : 0, "SUID" : 6003, "station_g_cd" : 2500105, "add" : "渋谷区西原3丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800520", "pref_name" : "東京都", "shared_name" : "2800520", "lat" : 35.669159, "y" : -356691.59, "x" : 1396801.5299999998 }, "position" : { "x" : 1396801.5299999998, "y" : -356691.59 }, "selected" : false }, { "data" : { "id" : "5973", "station_name" : "木場", "close_ymd" : "", "lon" : 139.807042, "post" : "135-0042", "e_status" : 0, "SUID" : 5973, "station_g_cd" : 2800413, "add" : "江東区木場5-5-1", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800413", "pref_name" : "東京都", "shared_name" : "2800413", "lat" : 35.669351, "y" : -356693.51, "x" : 1398070.42 }, "position" : { "x" : 1398070.42, "y" : -356693.51 }, "selected" : false }, { "data" : { "id" : "5974", "station_name" : "東陽町", "close_ymd" : "", "lon" : 139.817596, "post" : "135-0016", "e_status" : 0, "SUID" : 5974, "station_g_cd" : 2800414, "add" : "江東区東陽4-2-1", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800414", "pref_name" : "東京都", "shared_name" : "2800414", "lat" : 35.669629, "y" : -356696.29, "x" : 1398175.9600000002 }, "position" : { "x" : 1398175.9600000002, "y" : -356696.29 }, "selected" : false }, { "data" : { "id" : "5975", "station_name" : "南砂町", "close_ymd" : "", "lon" : 139.83065, "post" : "136-0076", "e_status" : 0, "SUID" : 5975, "station_g_cd" : 2800415, "add" : "江東区南砂3-11-85", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800415", "pref_name" : "東京都", "shared_name" : "2800415", "lat" : 35.668796, "y" : -356687.96, "x" : 1398306.5 }, "position" : { "x" : 1398306.5, "y" : -356687.96 }, "selected" : false }, { "data" : { "id" : "5976", "station_name" : "西葛西", "close_ymd" : "", "lon" : 139.859259, "post" : "134-0088", "e_status" : 0, "SUID" : 5976, "station_g_cd" : 2800416, "add" : "江戸川区西葛西6-14-1", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800416", "pref_name" : "東京都", "shared_name" : "2800416", "lat" : 35.664631, "y" : -356646.31, "x" : 1398592.59 }, "position" : { "x" : 1398592.59, "y" : -356646.31 }, "selected" : false }, { "data" : { "id" : "5977", "station_name" : "葛西", "close_ymd" : "", "lon" : 139.872458, "post" : "134-0083", "e_status" : 0, "SUID" : 5977, "station_g_cd" : 2800417, "add" : "江戸川区中葛西5-43-11", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800417", "pref_name" : "東京都", "shared_name" : "2800417", "lat" : 35.663554, "y" : -356635.54, "x" : 1398724.5799999998 }, "position" : { "x" : 1398724.5799999998, "y" : -356635.54 }, "selected" : false }, { "data" : { "id" : "5984", "station_name" : "北綾瀬", "close_ymd" : "", "lon" : 139.83203500000002, "post" : "120-0006", "e_status" : 0, "SUID" : 5984, "station_g_cd" : 2800501, "add" : "足立区谷中2丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800501", "pref_name" : "東京都", "shared_name" : "2800501", "lat" : 35.777117, "y" : -357771.17, "x" : 1398320.35 }, "position" : { "x" : 1398320.35, "y" : -357771.17 }, "selected" : false }, { "data" : { "id" : "5985", "station_name" : "綾瀬", "close_ymd" : "", "lon" : 139.825019, "post" : "120-0005", "e_status" : 0, "SUID" : 5985, "station_g_cd" : 1132006, "add" : "足立区綾瀬3丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800502", "pref_name" : "東京都", "shared_name" : "2800502", "lat" : 35.762221999999994, "y" : -357622.2199999999, "x" : 1398250.19 }, "position" : { "x" : 1398250.19, "y" : -357622.2199999999 }, "selected" : false }, { "data" : { "id" : "5986", "station_name" : "北千住", "close_ymd" : "", "lon" : 139.804276, "post" : "120-0026", "e_status" : 0, "SUID" : 5986, "station_g_cd" : 1132005, "add" : "足立区千住旭町", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800503", "pref_name" : "東京都", "shared_name" : "2800503", "lat" : 35.748915999999994, "y" : -357489.1599999999, "x" : 1398042.7599999998 }, "position" : { "x" : 1398042.7599999998, "y" : -357489.1599999999 }, "selected" : false }, { "data" : { "id" : "5987", "station_name" : "町屋", "close_ymd" : "", "lon" : 139.780501, "post" : "116-0001", "e_status" : 0, "SUID" : 5987, "station_g_cd" : 2300104, "add" : "荒川区町屋1丁目", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800504", "pref_name" : "東京都", "shared_name" : "2800504", "lat" : 35.742733, "y" : -357427.33, "x" : 1397805.0099999998 }, "position" : { "x" : 1397805.0099999998, "y" : -357427.33 }, "selected" : false }, { "data" : { "id" : "5988", "station_name" : "西日暮里", "close_ymd" : "", "lon" : 139.766511, "post" : "", "e_status" : 0, "SUID" : 5988, "station_g_cd" : 1130217, "add" : "東京都荒川区西日暮里五丁目14-1", "line_cd" : 28005, "selected" : false, "open_ymd" : "", "name" : "2800505", "pref_name" : "東京都", "shared_name" : "2800505", "lat" : 35.732257000000004, "y" : -357322.57000000007, "x" : 1397665.11 }, "position" : { "x" : 1397665.11, "y" : -357322.57000000007 }, "selected" : false }, { "data" : { "id" : "5964", "station_name" : "早稲田", "close_ymd" : "", "lon" : 139.721319, "post" : "", "e_status" : 0, "SUID" : 5964, "station_g_cd" : 2800404, "add" : "東京都新宿区", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800404", "pref_name" : "東京都", "shared_name" : "2800404", "lat" : 35.705723, "y" : -357057.23, "x" : 1397213.19 }, "position" : { "x" : 1397213.19, "y" : -357057.23 }, "selected" : false }, { "data" : { "id" : "5963", "station_name" : "高田馬場", "close_ymd" : "", "lon" : 139.704745, "post" : "", "e_status" : 0, "SUID" : 5963, "station_g_cd" : 1130210, "add" : "東京都新宿区高田馬場一丁目35-1", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800403", "pref_name" : "東京都", "shared_name" : "2800403", "lat" : 35.713338, "y" : -357133.38, "x" : 1397047.45 }, "position" : { "x" : 1397047.45, "y" : -357133.38 }, "selected" : false }, { "data" : { "id" : "5962", "station_name" : "落合", "close_ymd" : "", "lon" : 139.687284, "post" : "161-0034", "e_status" : 0, "SUID" : 5962, "station_g_cd" : 2800402, "add" : "新宿区上落合2-13-7", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800402", "pref_name" : "東京都", "shared_name" : "2800402", "lat" : 35.710976, "y" : -357109.76, "x" : 1396872.84 }, "position" : { "x" : 1396872.84, "y" : -357109.76 }, "selected" : false }, { "data" : { "id" : "5961", "station_name" : "中野", "close_ymd" : "", "lon" : 139.66583500000002, "post" : "164-0001", "e_status" : 0, "SUID" : 5961, "station_g_cd" : 1131214, "add" : "中野区中野5丁目", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800401", "pref_name" : "東京都", "shared_name" : "2800401", "lat" : 35.705765, "y" : -357057.65, "x" : 1396658.35 }, "position" : { "x" : 1396658.35, "y" : -357057.65 }, "selected" : false }, { "data" : { "id" : "5960", "station_name" : "中目黒", "close_ymd" : "", "lon" : 139.698621, "post" : "153-0051", "e_status" : 0, "SUID" : 5960, "station_g_cd" : 2600103, "add" : "目黒区上目黒3-4-1", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800321", "pref_name" : "東京都", "shared_name" : "2800321", "lat" : 35.643854, "y" : -356438.54, "x" : 1396986.21 }, "position" : { "x" : 1396986.21, "y" : -356438.54 }, "selected" : false }, { "data" : { "id" : "5959", "station_name" : "恵比寿", "close_ymd" : "", "lon" : 139.70898799999998, "post" : "", "e_status" : 0, "SUID" : 5959, "station_g_cd" : 1130204, "add" : "東京都渋谷区恵比寿南一丁目5-5", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800320", "pref_name" : "東京都", "shared_name" : "2800320", "lat" : 35.647332, "y" : -356473.32, "x" : 1397089.8799999997 }, "position" : { "x" : 1397089.8799999997, "y" : -356473.32 }, "selected" : false }, { "data" : { "id" : "5958", "station_name" : "広尾", "close_ymd" : "", "lon" : 139.722202, "post" : "106-0047", "e_status" : 0, "SUID" : 5958, "station_g_cd" : 2800319, "add" : "港区南麻布5-10-28", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800319", "pref_name" : "東京都", "shared_name" : "2800319", "lat" : 35.652279, "y" : -356522.79, "x" : 1397222.02 }, "position" : { "x" : 1397222.02, "y" : -356522.79 }, "selected" : false }, { "data" : { "id" : "5957", "station_name" : "六本木", "close_ymd" : "", "lon" : 139.73144299999998, "post" : "106-0032", "e_status" : 0, "SUID" : 5957, "station_g_cd" : 2800318, "add" : "港区六本木6-1-25", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800318", "pref_name" : "東京都", "shared_name" : "2800318", "lat" : 35.662836, "y" : -356628.36, "x" : 1397314.43 }, "position" : { "x" : 1397314.43, "y" : -356628.36 }, "selected" : false }, { "data" : { "id" : "5972", "station_name" : "門前仲町", "close_ymd" : "", "lon" : 139.796209, "post" : "135-0048", "e_status" : 0, "SUID" : 5972, "station_g_cd" : 2800412, "add" : "江東区門前仲町1丁目", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800412", "pref_name" : "東京都", "shared_name" : "2800412", "lat" : 35.671851000000004, "y" : -356718.51, "x" : 1397962.09 }, "position" : { "x" : 1397962.09, "y" : -356718.51 }, "selected" : false }, { "data" : { "id" : "5971", "station_name" : "茅場町", "close_ymd" : "", "lon" : 139.78000500000002, "post" : "103-0025", "e_status" : 0, "SUID" : 5971, "station_g_cd" : 2800310, "add" : "中央区日本橋茅場町1-4-6", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800411", "pref_name" : "東京都", "shared_name" : "2800411", "lat" : 35.679752, "y" : -356797.52, "x" : 1397800.0500000003 }, "position" : { "x" : 1397800.0500000003, "y" : -356797.52 }, "selected" : false }, { "data" : { "id" : "5970", "station_name" : "日本橋", "close_ymd" : "", "lon" : 139.773516, "post" : "103-0027", "e_status" : 0, "SUID" : 5970, "station_g_cd" : 2800109, "add" : "中央区日本橋1丁目", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800410", "pref_name" : "東京都", "shared_name" : "2800410", "lat" : 35.682078000000004, "y" : -356820.78, "x" : 1397735.16 }, "position" : { "x" : 1397735.16, "y" : -356820.78 }, "selected" : false }, { "data" : { "id" : "5969", "station_name" : "大手町", "close_ymd" : "", "lon" : 139.766086, "post" : "100-0004", "e_status" : 0, "SUID" : 5969, "station_g_cd" : 2800208, "add" : "千代田区大手町1丁目", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800409", "pref_name" : "東京都", "shared_name" : "2800409", "lat" : 35.684801, "y" : -356848.01, "x" : 1397660.86 }, "position" : { "x" : 1397660.86, "y" : -356848.01 }, "selected" : false }, { "data" : { "id" : "5968", "station_name" : "竹橋", "close_ymd" : "", "lon" : 139.75681699999998, "post" : "100-0003", "e_status" : 0, "SUID" : 5968, "station_g_cd" : 2800408, "add" : "千代田区一ツ橋1-1-1", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800408", "pref_name" : "東京都", "shared_name" : "2800408", "lat" : 35.690661999999996, "y" : -356906.61999999994, "x" : 1397568.17 }, "position" : { "x" : 1397568.17, "y" : -356906.61999999994 }, "selected" : false }, { "data" : { "id" : "5967", "station_name" : "九段下", "close_ymd" : "", "lon" : 139.751948, "post" : "102-0074", "e_status" : 0, "SUID" : 5967, "station_g_cd" : 2800407, "add" : "千代田区九段南1-6-1", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800407", "pref_name" : "東京都", "shared_name" : "2800407", "lat" : 35.695589, "y" : -356955.88999999996, "x" : 1397519.48 }, "position" : { "x" : 1397519.48, "y" : -356955.88999999996 }, "selected" : false }, { "data" : { "id" : "5966", "station_name" : "飯田橋", "close_ymd" : "", "lon" : 139.74598600000002, "post" : "", "e_status" : 0, "SUID" : 5966, "station_g_cd" : 1131205, "add" : "東京都千代田区飯田橋四丁目10-3", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800406", "pref_name" : "東京都", "shared_name" : "2800406", "lat" : 35.701725, "y" : -357017.25000000006, "x" : 1397459.86 }, "position" : { "x" : 1397459.86, "y" : -357017.25000000006 }, "selected" : false }, { "data" : { "id" : "5965", "station_name" : "神楽坂", "close_ymd" : "", "lon" : 139.734546, "post" : "162-0805", "e_status" : 0, "SUID" : 5965, "station_g_cd" : 2800405, "add" : "新宿区矢来町112", "line_cd" : 28004, "selected" : false, "open_ymd" : "", "name" : "2800405", "pref_name" : "東京都", "shared_name" : "2800405", "lat" : 35.703790000000005, "y" : -357037.9, "x" : 1397345.46 }, "position" : { "x" : 1397345.46, "y" : -357037.9 }, "selected" : false }, { "data" : { "id" : "5947", "station_name" : "小伝馬町", "close_ymd" : "", "lon" : 139.778433, "post" : "103-0001", "e_status" : 0, "SUID" : 5947, "station_g_cd" : 2800308, "add" : "中央区日本橋小伝馬町11-1", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800308", "pref_name" : "東京都", "shared_name" : "2800308", "lat" : 35.690737, "y" : -356907.37, "x" : 1397784.33 }, "position" : { "x" : 1397784.33, "y" : -356907.37 }, "selected" : false }, { "data" : { "id" : "5948", "station_name" : "人形町", "close_ymd" : "", "lon" : 139.782285, "post" : "103-0013", "e_status" : 0, "SUID" : 5948, "station_g_cd" : 2800309, "add" : "中央区日本橋人形町2-6-5", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800309", "pref_name" : "東京都", "shared_name" : "2800309", "lat" : 35.686307, "y" : -356863.07, "x" : 1397822.85 }, "position" : { "x" : 1397822.85, "y" : -356863.07 }, "selected" : false }, { "data" : { "id" : "5945", "station_name" : "仲御徒町", "close_ymd" : "", "lon" : 139.77613799999997, "post" : "110-0005", "e_status" : 0, "SUID" : 5945, "station_g_cd" : 1130221, "add" : "台東区上野5-24-12", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800306", "pref_name" : "東京都", "shared_name" : "2800306", "lat" : 35.706649, "y" : -357066.49, "x" : 1397761.3799999997 }, "position" : { "x" : 1397761.3799999997, "y" : -357066.49 }, "selected" : false }, { "data" : { "id" : "5946", "station_name" : "秋葉原", "close_ymd" : "", "lon" : 139.775459, "post" : "", "e_status" : 0, "SUID" : 5946, "station_g_cd" : 1130222, "add" : "東京都千代田区神田佐久間町一丁目21", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800307", "pref_name" : "東京都", "shared_name" : "2800307", "lat" : 35.698161999999996, "y" : -356981.61999999994, "x" : 1397754.59 }, "position" : { "x" : 1397754.59, "y" : -356981.61999999994 }, "selected" : false }, { "data" : { "id" : "5943", "station_name" : "入谷", "close_ymd" : "", "lon" : 139.783924, "post" : "110-0013", "e_status" : 0, "SUID" : 5943, "station_g_cd" : 2800304, "add" : "台東区入谷1-6-4", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800304", "pref_name" : "東京都", "shared_name" : "2800304", "lat" : 35.719862, "y" : -357198.62, "x" : 1397839.2400000002 }, "position" : { "x" : 1397839.2400000002, "y" : -357198.62 }, "selected" : false }, { "data" : { "id" : "5944", "station_name" : "上野", "close_ymd" : "", "lon" : 139.777122, "post" : "", "e_status" : 0, "SUID" : 5944, "station_g_cd" : 1130220, "add" : "東京都台東区東上野三丁目19-6", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800305", "pref_name" : "東京都", "shared_name" : "2800305", "lat" : 35.711482000000004, "y" : -357114.82000000007, "x" : 1397771.22 }, "position" : { "x" : 1397771.22, "y" : -357114.82000000007 }, "selected" : false }, { "data" : { "id" : "5941", "station_name" : "南千住", "close_ymd" : "", "lon" : 139.799273, "post" : "116-0003", "e_status" : 0, "SUID" : 5941, "station_g_cd" : 1132004, "add" : "荒川区南千住4丁目", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800302", "pref_name" : "東京都", "shared_name" : "2800302", "lat" : 35.733398, "y" : -357333.98000000004, "x" : 1397992.73 }, "position" : { "x" : 1397992.73, "y" : -357333.98000000004 }, "selected" : false }, { "data" : { "id" : "5942", "station_name" : "三ノ輪", "close_ymd" : "", "lon" : 139.79148500000002, "post" : "110-0011", "e_status" : 0, "SUID" : 5942, "station_g_cd" : 2800303, "add" : "台東区三ノ輪2-14-7", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800303", "pref_name" : "東京都", "shared_name" : "2800303", "lat" : 35.729623, "y" : -357296.23, "x" : 1397914.8500000003 }, "position" : { "x" : 1397914.8500000003, "y" : -357296.23 }, "selected" : false }, { "data" : { "id" : "5955", "station_name" : "霞ケ関", "close_ymd" : "", "lon" : 139.750899, "post" : "100-0013", "e_status" : 0, "SUID" : 5955, "station_g_cd" : 2800211, "add" : "千代田区霞が関2丁目", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800316", "pref_name" : "東京都", "shared_name" : "2800316", "lat" : 35.673838, "y" : -356738.38000000006, "x" : 1397508.99 }, "position" : { "x" : 1397508.99, "y" : -356738.38000000006 }, "selected" : false }, { "data" : { "id" : "5956", "station_name" : "神谷町", "close_ymd" : "", "lon" : 139.745069, "post" : "105-0001", "e_status" : 0, "SUID" : 5956, "station_g_cd" : 2800317, "add" : "港区虎ノ門5-12-11", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800317", "pref_name" : "東京都", "shared_name" : "2800317", "lat" : 35.662978, "y" : -356629.78, "x" : 1397450.69 }, "position" : { "x" : 1397450.69, "y" : -356629.78 }, "selected" : false }, { "data" : { "id" : "5953", "station_name" : "銀座", "close_ymd" : "", "lon" : 139.76396499999998, "post" : "104-0061", "e_status" : 0, "SUID" : 5953, "station_g_cd" : 2800111, "add" : "中央区銀座4-1-2", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800314", "pref_name" : "東京都", "shared_name" : "2800314", "lat" : 35.671989, "y" : -356719.89, "x" : 1397639.65 }, "position" : { "x" : 1397639.65, "y" : -356719.89 }, "selected" : false }, { "data" : { "id" : "5954", "station_name" : "日比谷", "close_ymd" : "", "lon" : 139.76017, "post" : "100-0006", "e_status" : 0, "SUID" : 5954, "station_g_cd" : 2800315, "add" : "千代田区有楽町1丁目", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800315", "pref_name" : "東京都", "shared_name" : "2800315", "lat" : 35.67459, "y" : -356745.9, "x" : 1397601.7 }, "position" : { "x" : 1397601.7, "y" : -356745.9 }, "selected" : false }, { "data" : { "id" : "5951", "station_name" : "築地", "close_ymd" : "", "lon" : 139.772603, "post" : "104-0045", "e_status" : 0, "SUID" : 5951, "station_g_cd" : 2800312, "add" : "中央区築地3-15-1", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800312", "pref_name" : "東京都", "shared_name" : "2800312", "lat" : 35.668115, "y" : -356681.15, "x" : 1397726.03 }, "position" : { "x" : 1397726.03, "y" : -356681.15 }, "selected" : false }, { "data" : { "id" : "5952", "station_name" : "東銀座", "close_ymd" : "", "lon" : 139.767253, "post" : "104-0061", "e_status" : 0, "SUID" : 5952, "station_g_cd" : 2800313, "add" : "中央区銀座4-12-15", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800313", "pref_name" : "東京都", "shared_name" : "2800313", "lat" : 35.669464000000005, "y" : -356694.6400000001, "x" : 1397672.53 }, "position" : { "x" : 1397672.53, "y" : -356694.6400000001 }, "selected" : false }, { "data" : { "id" : "5949", "station_name" : "茅場町", "close_ymd" : "", "lon" : 139.78000500000002, "post" : "103-0025", "e_status" : 0, "SUID" : 5949, "station_g_cd" : 2800310, "add" : "中央区日本橋茅場町1-4-6", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800310", "pref_name" : "東京都", "shared_name" : "2800310", "lat" : 35.679752, "y" : -356797.52, "x" : 1397800.0500000003 }, "position" : { "x" : 1397800.0500000003, "y" : -356797.52 }, "selected" : false }, { "data" : { "id" : "5950", "station_name" : "八丁堀", "close_ymd" : "", "lon" : 139.776982, "post" : "104-0032", "e_status" : 0, "SUID" : 5950, "station_g_cd" : 1132602, "add" : "中央区八丁堀3丁目", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800311", "pref_name" : "東京都", "shared_name" : "2800311", "lat" : 35.674851000000004, "y" : -356748.51000000007, "x" : 1397769.82 }, "position" : { "x" : 1397769.82, "y" : -356748.51000000007 }, "selected" : false }, { "data" : { "id" : "5930", "station_name" : "西新宿", "close_ymd" : "", "lon" : 139.692778, "post" : "160-0023", "e_status" : 0, "SUID" : 5930, "station_g_cd" : 2800219, "add" : "新宿区西新宿6-7-51", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800219", "pref_name" : "東京都", "shared_name" : "2800219", "lat" : 35.694297999999996, "y" : -356942.98, "x" : 1396927.78 }, "position" : { "x" : 1396927.78, "y" : -356942.98 }, "selected" : false }, { "data" : { "id" : "5929", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.700711, "post" : "-", "e_status" : 0, "SUID" : 5929, "station_g_cd" : 1130208, "add" : "東京都新宿区西新宿一丁目 西口地下街1号", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800218", "pref_name" : "東京都", "shared_name" : "2800218", "lat" : 35.69235, "y" : -356923.5, "x" : 1397007.11 }, "position" : { "x" : 1397007.11, "y" : -356923.5 }, "selected" : false }, { "data" : { "id" : "5932", "station_name" : "新中野", "close_ymd" : "", "lon" : 139.66903, "post" : "164-0011", "e_status" : 0, "SUID" : 5932, "station_g_cd" : 2800221, "add" : "中野区中央4-2-15", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800221", "pref_name" : "東京都", "shared_name" : "2800221", "lat" : 35.697491, "y" : -356974.91, "x" : 1396690.2999999998 }, "position" : { "x" : 1396690.2999999998, "y" : -356974.91 }, "selected" : false }, { "data" : { "id" : "5931", "station_name" : "中野坂上", "close_ymd" : "", "lon" : 139.68291000000002, "post" : "164-0011", "e_status" : 0, "SUID" : 5931, "station_g_cd" : 2800220, "add" : "中野区中央2-1-2", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800220", "pref_name" : "東京都", "shared_name" : "2800220", "lat" : 35.69792, "y" : -356979.2, "x" : 1396829.1000000003 }, "position" : { "x" : 1396829.1000000003, "y" : -356979.2 }, "selected" : false }, { "data" : { "id" : "5926", "station_name" : "四谷三丁目", "close_ymd" : "", "lon" : 139.720103, "post" : "160-0004", "e_status" : 0, "SUID" : 5926, "station_g_cd" : 2800215, "add" : "新宿区四谷3-8", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800215", "pref_name" : "東京都", "shared_name" : "2800215", "lat" : 35.687958, "y" : -356879.58, "x" : 1397201.03 }, "position" : { "x" : 1397201.03, "y" : -356879.58 }, "selected" : false }, { "data" : { "id" : "5925", "station_name" : "四ツ谷", "close_ymd" : "", "lon" : 139.729947, "post" : "160-0004", "e_status" : 0, "SUID" : 5925, "station_g_cd" : 1131102, "add" : "新宿区四谷1丁目", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800214", "pref_name" : "東京都", "shared_name" : "2800214", "lat" : 35.684585999999996, "y" : -356845.86, "x" : 1397299.4700000002 }, "position" : { "x" : 1397299.4700000002, "y" : -356845.86 }, "selected" : false }, { "data" : { "id" : "5928", "station_name" : "新宿三丁目", "close_ymd" : "", "lon" : 139.704895, "post" : "160-0022", "e_status" : 0, "SUID" : 5928, "station_g_cd" : 2800217, "add" : "新宿区新宿3-14-1", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800217", "pref_name" : "東京都", "shared_name" : "2800217", "lat" : 35.690847, "y" : -356908.47, "x" : 1397048.95 }, "position" : { "x" : 1397048.95, "y" : -356908.47 }, "selected" : false }, { "data" : { "id" : "5927", "station_name" : "新宿御苑前", "close_ymd" : "", "lon" : 139.71069, "post" : "160-0022", "e_status" : 0, "SUID" : 5927, "station_g_cd" : 2800216, "add" : "新宿区新宿1-8-1", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800216", "pref_name" : "東京都", "shared_name" : "2800216", "lat" : 35.688588, "y" : -356885.88, "x" : 1397106.9 }, "position" : { "x" : 1397106.9, "y" : -356885.88 }, "selected" : false }, { "data" : { "id" : "5938", "station_name" : "中野富士見町", "close_ymd" : "", "lon" : 139.666933, "post" : "164-0013", "e_status" : 0, "SUID" : 5938, "station_g_cd" : 2800227, "add" : "中野区弥生町5-24-4", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800227", "pref_name" : "東京都", "shared_name" : "2800227", "lat" : 35.690514, "y" : -356905.14, "x" : 1396669.33 }, "position" : { "x" : 1396669.33, "y" : -356905.14 }, "selected" : false }, { "data" : { "id" : "5937", "station_name" : "荻窪", "close_ymd" : "", "lon" : 139.620116, "post" : "167-0043", "e_status" : 0, "SUID" : 5937, "station_g_cd" : 1131217, "add" : "杉並区上荻1丁目", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800225", "pref_name" : "東京都", "shared_name" : "2800225", "lat" : 35.704304, "y" : -357043.04, "x" : 1396201.16 }, "position" : { "x" : 1396201.16, "y" : -357043.04 }, "selected" : false }, { "data" : { "id" : "5940", "station_name" : "北千住", "close_ymd" : "", "lon" : 139.804276, "post" : "120-0026", "e_status" : 0, "SUID" : 5940, "station_g_cd" : 1132005, "add" : "足立区千住旭町", "line_cd" : 28003, "selected" : false, "open_ymd" : "", "name" : "2800301", "pref_name" : "東京都", "shared_name" : "2800301", "lat" : 35.748915999999994, "y" : -357489.1599999999, "x" : 1398042.7599999998 }, "position" : { "x" : 1398042.7599999998, "y" : -357489.1599999999 }, "selected" : false }, { "data" : { "id" : "5939", "station_name" : "方南町", "close_ymd" : "", "lon" : 139.656498, "post" : "166-0013", "e_status" : 0, "SUID" : 5939, "station_g_cd" : 2800228, "add" : "杉並区堀ノ内1-1-1", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800228", "pref_name" : "東京都", "shared_name" : "2800228", "lat" : 35.683496000000005, "y" : -356834.9600000001, "x" : 1396564.98 }, "position" : { "x" : 1396564.98, "y" : -356834.9600000001 }, "selected" : false }, { "data" : { "id" : "5934", "station_name" : "東高円寺", "close_ymd" : "", "lon" : 139.657822, "post" : "166-0012", "e_status" : 0, "SUID" : 5934, "station_g_cd" : 2800222, "add" : "杉並区和田3-55-42", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800222", "pref_name" : "東京都", "shared_name" : "2800222", "lat" : 35.697802, "y" : -356978.02, "x" : 1396578.2200000002 }, "position" : { "x" : 1396578.2200000002, "y" : -356978.02 }, "selected" : false }, { "data" : { "id" : "5933", "station_name" : "中野新橋", "close_ymd" : "", "lon" : 139.67399699999999, "post" : "164-0013", "e_status" : 0, "SUID" : 5933, "station_g_cd" : 2800226, "add" : "中野区弥生町2-26-8", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800226", "pref_name" : "東京都", "shared_name" : "2800226", "lat" : 35.692122999999995, "y" : -356921.2299999999, "x" : 1396739.97 }, "position" : { "x" : 1396739.97, "y" : -356921.2299999999 }, "selected" : false }, { "data" : { "id" : "5936", "station_name" : "南阿佐ケ谷", "close_ymd" : "", "lon" : 139.63576, "post" : "166-0004", "e_status" : 0, "SUID" : 5936, "station_g_cd" : 2800224, "add" : "杉並区阿佐谷南1-15-7", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800224", "pref_name" : "東京都", "shared_name" : "2800224", "lat" : 35.699624, "y" : -356996.24, "x" : 1396357.6 }, "position" : { "x" : 1396357.6, "y" : -356996.24 }, "selected" : false }, { "data" : { "id" : "5935", "station_name" : "新高円寺", "close_ymd" : "", "lon" : 139.648068, "post" : "166-0003", "e_status" : 0, "SUID" : 5935, "station_g_cd" : 2800223, "add" : "杉並区高円寺南2-20-1", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800223", "pref_name" : "東京都", "shared_name" : "2800223", "lat" : 35.697984999999996, "y" : -356979.85, "x" : 1396480.68 }, "position" : { "x" : 1396480.68, "y" : -356979.85 }, "selected" : false }, { "data" : { "id" : "5913", "station_name" : "新大塚", "close_ymd" : "", "lon" : 139.729971, "post" : "112-0012", "e_status" : 0, "SUID" : 5913, "station_g_cd" : 2800202, "add" : "文京区大塚4-51-5", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800202", "pref_name" : "東京都", "shared_name" : "2800202", "lat" : 35.72569, "y" : -357256.9, "x" : 1397299.71 }, "position" : { "x" : 1397299.71, "y" : -357256.9 }, "selected" : false }, { "data" : { "id" : "5914", "station_name" : "茗荷谷", "close_ymd" : "", "lon" : 139.737184, "post" : "112-0006", "e_status" : 0, "SUID" : 5914, "station_g_cd" : 2800203, "add" : "文京区小日向4-6-15", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800203", "pref_name" : "東京都", "shared_name" : "2800203", "lat" : 35.716989, "y" : -357169.88999999996, "x" : 1397371.84 }, "position" : { "x" : 1397371.84, "y" : -357169.88999999996 }, "selected" : false }, { "data" : { "id" : "5915", "station_name" : "後楽園", "close_ymd" : "", "lon" : 139.75186399999998, "post" : "112-0003", "e_status" : 0, "SUID" : 5915, "station_g_cd" : 2800204, "add" : "文京区春日1-2-3", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800204", "pref_name" : "東京都", "shared_name" : "2800204", "lat" : 35.707898, "y" : -357078.98, "x" : 1397518.64 }, "position" : { "x" : 1397518.64, "y" : -357078.98 }, "selected" : false }, { "data" : { "id" : "5916", "station_name" : "本郷三丁目", "close_ymd" : "", "lon" : 139.75991399999998, "post" : "113-0033", "e_status" : 0, "SUID" : 5916, "station_g_cd" : 2800205, "add" : "文京区本郷2-39-1", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800205", "pref_name" : "東京都", "shared_name" : "2800205", "lat" : 35.706671, "y" : -357066.71, "x" : 1397599.14 }, "position" : { "x" : 1397599.14, "y" : -357066.71 }, "selected" : false }, { "data" : { "id" : "5909", "station_name" : "外苑前", "close_ymd" : "", "lon" : 139.717857, "post" : "107-0061", "e_status" : 0, "SUID" : 5909, "station_g_cd" : 2800117, "add" : "港区北青山2-7-16", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800117", "pref_name" : "東京都", "shared_name" : "2800117", "lat" : 35.670527, "y" : -356705.27, "x" : 1397178.57 }, "position" : { "x" : 1397178.57, "y" : -356705.27 }, "selected" : false }, { "data" : { "id" : "5910", "station_name" : "表参道", "close_ymd" : "", "lon" : 139.712314, "post" : "107-0061", "e_status" : 0, "SUID" : 5910, "station_g_cd" : 2800118, "add" : "港区北青山3丁目", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800118", "pref_name" : "東京都", "shared_name" : "2800118", "lat" : 35.665246999999994, "y" : -356652.4699999999, "x" : 1397123.14 }, "position" : { "x" : 1397123.14, "y" : -356652.4699999999 }, "selected" : false }, { "data" : { "id" : "5911", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.701, "post" : "", "e_status" : 0, "SUID" : 5911, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂一丁目1-1", "line_cd" : 28001, "selected" : false, "open_ymd" : "", "name" : "2800119", "pref_name" : "東京都", "shared_name" : "2800119", "lat" : 35.659065999999996, "y" : -356590.66, "x" : 1397010.0 }, "position" : { "x" : 1397010.0, "y" : -356590.66 }, "selected" : false }, { "data" : { "id" : "5912", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.71108600000002, "post" : "", "e_status" : 0, "SUID" : 5912, "station_g_cd" : 1130212, "add" : "東京都豊島区", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800201", "pref_name" : "東京都", "shared_name" : "2800201", "lat" : 35.730256, "y" : -357302.56, "x" : 1397110.8600000003 }, "position" : { "x" : 1397110.8600000003, "y" : -357302.56 }, "selected" : false }, { "data" : { "id" : "5921", "station_name" : "銀座", "close_ymd" : "", "lon" : 139.76396499999998, "post" : "104-0061", "e_status" : 0, "SUID" : 5921, "station_g_cd" : 2800111, "add" : "中央区銀座4-1-2", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800210", "pref_name" : "東京都", "shared_name" : "2800210", "lat" : 35.671989, "y" : -356719.89, "x" : 1397639.65 }, "position" : { "x" : 1397639.65, "y" : -356719.89 }, "selected" : false }, { "data" : { "id" : "5922", "station_name" : "霞ケ関", "close_ymd" : "", "lon" : 139.750899, "post" : "100-0013", "e_status" : 0, "SUID" : 5922, "station_g_cd" : 2800211, "add" : "千代田区霞が関2丁目", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800211", "pref_name" : "東京都", "shared_name" : "2800211", "lat" : 35.673838, "y" : -356738.38000000006, "x" : 1397508.99 }, "position" : { "x" : 1397508.99, "y" : -356738.38000000006 }, "selected" : false }, { "data" : { "id" : "5923", "station_name" : "国会議事堂前", "close_ymd" : "", "lon" : 139.745219, "post" : "100-0014", "e_status" : 0, "SUID" : 5923, "station_g_cd" : 2800212, "add" : "千代田区永田町1丁目", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800212", "pref_name" : "東京都", "shared_name" : "2800212", "lat" : 35.67393, "y" : -356739.3, "x" : 1397452.19 }, "position" : { "x" : 1397452.19, "y" : -356739.3 }, "selected" : false }, { "data" : { "id" : "5924", "station_name" : "赤坂見附", "close_ymd" : "", "lon" : 139.737047, "post" : "107-0052", "e_status" : 0, "SUID" : 5924, "station_g_cd" : 2800115, "add" : "港区赤坂3-1-6", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800213", "pref_name" : "東京都", "shared_name" : "2800213", "lat" : 35.677021, "y" : -356770.21, "x" : 1397370.47 }, "position" : { "x" : 1397370.47, "y" : -356770.21 }, "selected" : false }, { "data" : { "id" : "5917", "station_name" : "御茶ノ水", "close_ymd" : "", "lon" : 139.763952, "post" : "101-0062", "e_status" : 0, "SUID" : 5917, "station_g_cd" : 1131203, "add" : "千代田区神田駿河台2丁目", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800206", "pref_name" : "東京都", "shared_name" : "2800206", "lat" : 35.700614, "y" : -357006.14, "x" : 1397639.5199999998 }, "position" : { "x" : 1397639.5199999998, "y" : -357006.14 }, "selected" : false }, { "data" : { "id" : "5918", "station_name" : "淡路町", "close_ymd" : "", "lon" : 139.767575, "post" : "101-0063", "e_status" : 0, "SUID" : 5918, "station_g_cd" : 2800207, "add" : "千代田区神田淡路町1-2", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800207", "pref_name" : "東京都", "shared_name" : "2800207", "lat" : 35.695434000000006, "y" : -356954.3400000001, "x" : 1397675.75 }, "position" : { "x" : 1397675.75, "y" : -356954.3400000001 }, "selected" : false }, { "data" : { "id" : "5919", "station_name" : "大手町", "close_ymd" : "", "lon" : 139.7662, "post" : "100-0004", "e_status" : 0, "SUID" : 5919, "station_g_cd" : 2800208, "add" : "千代田区大手町1丁目", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800208", "pref_name" : "東京都", "shared_name" : "2800208", "lat" : 35.686564000000004, "y" : -356865.64, "x" : 1397662.0 }, "position" : { "x" : 1397662.0, "y" : -356865.64 }, "selected" : false }, { "data" : { "id" : "5920", "station_name" : "東京", "close_ymd" : "", "lon" : 139.764708, "post" : "", "e_status" : 0, "SUID" : 5920, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 28002, "selected" : false, "open_ymd" : "", "name" : "2800209", "pref_name" : "東京都", "shared_name" : "2800209", "lat" : 35.681753, "y" : -356817.53, "x" : 1397647.08 }, "position" : { "x" : 1397647.08, "y" : -356817.53 }, "selected" : false }, { "data" : { "id" : "3103", "station_name" : "赤羽", "close_ymd" : "", "lon" : 139.72092800000001, "post" : "115-0045", "e_status" : 0, "SUID" : 3103, "station_g_cd" : 1131903, "add" : "北区赤羽1丁目", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132108", "pref_name" : "東京都", "shared_name" : "1132108", "lat" : 35.778026000000004, "y" : -357780.26000000007, "x" : 1397209.2800000003 }, "position" : { "x" : 1397209.2800000003, "y" : -357780.26000000007 }, "selected" : false }, { "data" : { "id" : "3104", "station_name" : "北赤羽", "close_ymd" : "", "lon" : 139.70569, "post" : "115-0052", "e_status" : 0, "SUID" : 3104, "station_g_cd" : 1132109, "add" : "北区赤羽北2丁目", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132109", "pref_name" : "東京都", "shared_name" : "1132109", "lat" : 35.787007, "y" : -357870.07, "x" : 1397056.9000000001 }, "position" : { "x" : 1397056.9000000001, "y" : -357870.07 }, "selected" : false }, { "data" : { "id" : "3101", "station_name" : "板橋", "close_ymd" : "", "lon" : 139.719507, "post" : "173-0004", "e_status" : 0, "SUID" : 3101, "station_g_cd" : 1132106, "add" : "板橋区板橋1丁目", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132106", "pref_name" : "東京都", "shared_name" : "1132106", "lat" : 35.745435, "y" : -357454.35, "x" : 1397195.0699999998 }, "position" : { "x" : 1397195.0699999998, "y" : -357454.35 }, "selected" : false }, { "data" : { "id" : "3102", "station_name" : "十条", "close_ymd" : "", "lon" : 139.72223300000002, "post" : "114-0034", "e_status" : 0, "SUID" : 3102, "station_g_cd" : 1132107, "add" : "北区上十条1丁目", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132107", "pref_name" : "東京都", "shared_name" : "1132107", "lat" : 35.760321000000005, "y" : -357603.21, "x" : 1397222.33 }, "position" : { "x" : 1397222.33, "y" : -357603.21 }, "selected" : false }, { "data" : { "id" : "3105", "station_name" : "浮間舟渡", "close_ymd" : "", "lon" : 139.691341, "post" : "115-0051", "e_status" : 0, "SUID" : 3105, "station_g_cd" : 1132110, "add" : "北区浮間4丁目", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132110", "pref_name" : "東京都", "shared_name" : "1132110", "lat" : 35.791209, "y" : -357912.09, "x" : 1396913.41 }, "position" : { "x" : 1396913.41, "y" : -357912.09 }, "selected" : false }, { "data" : { "id" : "3096", "station_name" : "大崎", "close_ymd" : "", "lon" : 139.72843899999998, "post" : "141-0032", "e_status" : 0, "SUID" : 3096, "station_g_cd" : 1130201, "add" : "東京都品川区大崎一丁目21-4", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132101", "pref_name" : "東京都", "shared_name" : "1132101", "lat" : 35.619772, "y" : -356197.72, "x" : 1397284.39 }, "position" : { "x" : 1397284.39, "y" : -356197.72 }, "selected" : false }, { "data" : { "id" : "3099", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.70046399999998, "post" : "160-0022", "e_status" : 0, "SUID" : 3099, "station_g_cd" : 1130208, "add" : "東京都新宿区新宿三丁目38-1", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132104", "pref_name" : "東京都", "shared_name" : "1132104", "lat" : 35.689729, "y" : -356897.29, "x" : 1397004.64 }, "position" : { "x" : 1397004.64, "y" : -356897.29 }, "selected" : false }, { "data" : { "id" : "5300", "station_name" : "曳舟", "close_ymd" : "", "lon" : 139.81663400000002, "post" : "131-0032", "e_status" : 0, "SUID" : 5300, "station_g_cd" : 2100204, "add" : "墨田区東向島2丁目", "line_cd" : 21005, "selected" : false, "open_ymd" : "", "name" : "2100501", "pref_name" : "東京都", "shared_name" : "2100501", "lat" : 35.718418, "y" : -357184.18, "x" : 1398166.3400000003 }, "position" : { "x" : 1398166.3400000003, "y" : -357184.18 }, "selected" : false }, { "data" : { "id" : "3100", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.71108600000002, "post" : "170-0000", "e_status" : 0, "SUID" : 3100, "station_g_cd" : 1130212, "add" : "東京都豊島区", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132105", "pref_name" : "東京都", "shared_name" : "1132105", "lat" : 35.730256, "y" : -357302.56, "x" : 1397110.8600000003 }, "position" : { "x" : 1397110.8600000003, "y" : -357302.56 }, "selected" : false }, { "data" : { "id" : "3097", "station_name" : "恵比寿", "close_ymd" : "", "lon" : 139.71007, "post" : "151-0022", "e_status" : 0, "SUID" : 3097, "station_g_cd" : 1130204, "add" : "東京都渋谷区恵比寿南一丁目5-5", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132102", "pref_name" : "東京都", "shared_name" : "1132102", "lat" : 35.646685, "y" : -356466.85, "x" : 1397100.7 }, "position" : { "x" : 1397100.7, "y" : -356466.85 }, "selected" : false }, { "data" : { "id" : "3098", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.701238, "post" : "150-0043", "e_status" : 0, "SUID" : 3098, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂一丁目1-1", "line_cd" : 11321, "selected" : false, "open_ymd" : "", "name" : "1132103", "pref_name" : "東京都", "shared_name" : "1132103", "lat" : 35.658871000000005, "y" : -356588.71, "x" : 1397012.38 }, "position" : { "x" : 1397012.38, "y" : -356588.71 }, "selected" : false }, { "data" : { "id" : "5302", "station_name" : "東あずま", "close_ymd" : "", "lon" : 139.831883, "post" : "131-0043", "e_status" : 0, "SUID" : 5302, "station_g_cd" : 2100503, "add" : "墨田区立花4-23-8", "line_cd" : 21005, "selected" : false, "open_ymd" : "", "name" : "2100503", "pref_name" : "東京都", "shared_name" : "2100503", "lat" : 35.707066999999995, "y" : -357070.6699999999, "x" : 1398318.83 }, "position" : { "x" : 1398318.83, "y" : -357070.6699999999 }, "selected" : false }, { "data" : { "id" : "5301", "station_name" : "小村井", "close_ymd" : "", "lon" : 139.827595, "post" : "131-0044", "e_status" : 0, "SUID" : 5301, "station_g_cd" : 2100502, "add" : "墨田区文花2-20-1", "line_cd" : 21005, "selected" : false, "open_ymd" : "", "name" : "2100502", "pref_name" : "東京都", "shared_name" : "2100502", "lat" : 35.710316, "y" : -357103.16, "x" : 1398275.95 }, "position" : { "x" : 1398275.95, "y" : -357103.16 }, "selected" : false }, { "data" : { "id" : "5304", "station_name" : "亀戸", "close_ymd" : "", "lon" : 139.826791, "post" : "136-0071", "e_status" : 0, "SUID" : 5304, "station_g_cd" : 1131323, "add" : "江東区亀戸5丁目", "line_cd" : 21005, "selected" : false, "open_ymd" : "", "name" : "2100505", "pref_name" : "東京都", "shared_name" : "2100505", "lat" : 35.697708, "y" : -356977.07999999996, "x" : 1398267.91 }, "position" : { "x" : 1398267.91, "y" : -356977.07999999996 }, "selected" : false }, { "data" : { "id" : "5303", "station_name" : "亀戸水神", "close_ymd" : "", "lon" : 139.83342199999998, "post" : "136-0071", "e_status" : 0, "SUID" : 5303, "station_g_cd" : 2100504, "add" : "江東区亀戸8-5-1", "line_cd" : 21005, "selected" : false, "open_ymd" : "", "name" : "2100504", "pref_name" : "東京都", "shared_name" : "2100504", "lat" : 35.699976, "y" : -356999.76, "x" : 1398334.2199999997 }, "position" : { "x" : 1398334.2199999997, "y" : -356999.76 }, "selected" : false }, { "data" : { "id" : "5306", "station_name" : "大師前", "close_ymd" : "", "lon" : 139.781647, "post" : "123-0841", "e_status" : 0, "SUID" : 5306, "station_g_cd" : 2100602, "add" : "足立区西新井1-3-1", "line_cd" : 21006, "selected" : false, "open_ymd" : "", "name" : "2100602", "pref_name" : "東京都", "shared_name" : "2100602", "lat" : 35.778989, "y" : -357789.89, "x" : 1397816.47 }, "position" : { "x" : 1397816.47, "y" : -357789.89 }, "selected" : false }, { "data" : { "id" : "5305", "station_name" : "西新井", "close_ymd" : "", "lon" : 139.790372, "post" : "123-0843", "e_status" : 0, "SUID" : 5305, "station_g_cd" : 2100213, "add" : "足立区西新井栄町2丁目", "line_cd" : 21006, "selected" : false, "open_ymd" : "", "name" : "2100601", "pref_name" : "東京都", "shared_name" : "2100601", "lat" : 35.777322999999996, "y" : -357773.23, "x" : 1397903.72 }, "position" : { "x" : 1397903.72, "y" : -357773.23 }, "selected" : false }, { "data" : { "id" : "3126", "station_name" : "上野", "close_ymd" : "", "lon" : 139.777043, "post" : "", "e_status" : 0, "SUID" : 3126, "station_g_cd" : 1130220, "add" : "東京都台東区上野七丁目1-1", "line_cd" : 11323, "selected" : false, "open_ymd" : "", "name" : "1132301", "pref_name" : "東京都", "shared_name" : "1132301", "lat" : 35.71379, "y" : -357137.9, "x" : 1397770.43 }, "position" : { "x" : 1397770.43, "y" : -357137.9 }, "selected" : false }, { "data" : { "id" : "3127", "station_name" : "尾久", "close_ymd" : "", "lon" : 139.753846, "post" : "114-0011", "e_status" : 0, "SUID" : 3127, "station_g_cd" : 1131902, "add" : "北区昭和町1丁目", "line_cd" : 11323, "selected" : false, "open_ymd" : "", "name" : "1132302", "pref_name" : "東京都", "shared_name" : "1132302", "lat" : 35.746829999999996, "y" : -357468.29999999993, "x" : 1397538.4600000002 }, "position" : { "x" : 1397538.4600000002, "y" : -357468.29999999993 }, "selected" : false }, { "data" : { "id" : "3128", "station_name" : "赤羽", "close_ymd" : "", "lon" : 139.72092800000001, "post" : "115-0045", "e_status" : 0, "SUID" : 3128, "station_g_cd" : 1131903, "add" : "北区赤羽1丁目", "line_cd" : 11323, "selected" : false, "open_ymd" : "", "name" : "1132303", "pref_name" : "東京都", "shared_name" : "1132303", "lat" : 35.778026000000004, "y" : -357780.26000000007, "x" : 1397209.2800000003 }, "position" : { "x" : 1397209.2800000003, "y" : -357780.26000000007 }, "selected" : false }, { "data" : { "id" : "5363", "station_name" : "椎名町", "close_ymd" : "", "lon" : 139.69436299999998, "post" : "171-0051", "e_status" : 0, "SUID" : 5363, "station_g_cd" : 2200102, "add" : "豊島区長崎1-1-22", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200102", "pref_name" : "東京都", "shared_name" : "2200102", "lat" : 35.726572, "y" : -357265.72, "x" : 1396943.63 }, "position" : { "x" : 1396943.63, "y" : -357265.72 }, "selected" : false }, { "data" : { "id" : "5364", "station_name" : "東長崎", "close_ymd" : "", "lon" : 139.683294, "post" : "171-0051", "e_status" : 0, "SUID" : 5364, "station_g_cd" : 2200103, "add" : "豊島区長崎5-1-1", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200103", "pref_name" : "東京都", "shared_name" : "2200103", "lat" : 35.73003, "y" : -357300.3, "x" : 1396832.94 }, "position" : { "x" : 1396832.94, "y" : -357300.3 }, "selected" : false }, { "data" : { "id" : "5362", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.711461, "post" : "171-0022", "e_status" : 0, "SUID" : 5362, "station_g_cd" : 1130212, "add" : "東京都豊島区南池袋一丁目28-2", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200101", "pref_name" : "東京都", "shared_name" : "2200101", "lat" : 35.72913, "y" : -357291.3, "x" : 1397114.61 }, "position" : { "x" : 1397114.61, "y" : -357291.3 }, "selected" : false }, { "data" : { "id" : "5370", "station_name" : "練馬高野台", "close_ymd" : "", "lon" : 139.616749, "post" : "177-0033", "e_status" : 0, "SUID" : 5370, "station_g_cd" : 2200109, "add" : "練馬区高野台1-7-27", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200109", "pref_name" : "東京都", "shared_name" : "2200109", "lat" : 35.740621999999995, "y" : -357406.22, "x" : 1396167.49 }, "position" : { "x" : 1396167.49, "y" : -357406.22 }, "selected" : false }, { "data" : { "id" : "5369", "station_name" : "富士見台", "close_ymd" : "", "lon" : 139.62968999999998, "post" : "176-0021", "e_status" : 0, "SUID" : 5369, "station_g_cd" : 2200108, "add" : "練馬区貫井3-7-4", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200108", "pref_name" : "東京都", "shared_name" : "2200108", "lat" : 35.735867, "y" : -357358.67, "x" : 1396296.9 }, "position" : { "x" : 1396296.9, "y" : -357358.67 }, "selected" : false }, { "data" : { "id" : "5372", "station_name" : "大泉学園", "close_ymd" : "", "lon" : 139.586732, "post" : "178-0063", "e_status" : 0, "SUID" : 5372, "station_g_cd" : 2200111, "add" : "練馬区東大泉1-29-7", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200111", "pref_name" : "東京都", "shared_name" : "2200111", "lat" : 35.749406, "y" : -357494.06, "x" : 1395867.32 }, "position" : { "x" : 1395867.32, "y" : -357494.06 }, "selected" : false }, { "data" : { "id" : "5371", "station_name" : "石神井公園", "close_ymd" : "", "lon" : 139.60698100000002, "post" : "177-0041", "e_status" : 0, "SUID" : 5371, "station_g_cd" : 2200110, "add" : "練馬区石神井町3-23-10", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200110", "pref_name" : "東京都", "shared_name" : "2200110", "lat" : 35.743563, "y" : -357435.63, "x" : 1396069.8100000003 }, "position" : { "x" : 1396069.8100000003, "y" : -357435.63 }, "selected" : false }, { "data" : { "id" : "3214", "station_name" : "葛西臨海公園", "close_ymd" : "", "lon" : 139.861529, "post" : "134-0086", "e_status" : 0, "SUID" : 3214, "station_g_cd" : 1132606, "add" : "江戸川区臨海町6丁目", "line_cd" : 11326, "selected" : false, "open_ymd" : "", "name" : "1132606", "pref_name" : "東京都", "shared_name" : "1132606", "lat" : 35.644391999999996, "y" : -356443.92, "x" : 1398615.2899999998 }, "position" : { "x" : 1398615.2899999998, "y" : -356443.92 }, "selected" : false }, { "data" : { "id" : "5366", "station_name" : "桜台", "close_ymd" : "", "lon" : 139.662602, "post" : "176-0002", "e_status" : 0, "SUID" : 5366, "station_g_cd" : 2200105, "add" : "練馬区桜台1-5-1", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200105", "pref_name" : "東京都", "shared_name" : "2200105", "lat" : 35.738797, "y" : -357387.97, "x" : 1396626.02 }, "position" : { "x" : 1396626.02, "y" : -357387.97 }, "selected" : false }, { "data" : { "id" : "3213", "station_name" : "新木場", "close_ymd" : "", "lon" : 139.827402, "post" : "", "e_status" : 0, "SUID" : 3213, "station_g_cd" : 1132605, "add" : "東京都江東区新木場一丁目5", "line_cd" : 11326, "selected" : false, "open_ymd" : "", "name" : "1132605", "pref_name" : "東京都", "shared_name" : "1132605", "lat" : 35.646172, "y" : -356461.72, "x" : 1398274.02 }, "position" : { "x" : 1398274.02, "y" : -356461.72 }, "selected" : false }, { "data" : { "id" : "5365", "station_name" : "江古田", "close_ymd" : "", "lon" : 139.672814, "post" : "176-0005", "e_status" : 0, "SUID" : 5365, "station_g_cd" : 2200104, "add" : "練馬区旭丘1-78-7", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200104", "pref_name" : "東京都", "shared_name" : "2200104", "lat" : 35.737557, "y" : -357375.57, "x" : 1396728.14 }, "position" : { "x" : 1396728.14, "y" : -357375.57 }, "selected" : false }, { "data" : { "id" : "5368", "station_name" : "中村橋", "close_ymd" : "", "lon" : 139.63745600000001, "post" : "176-0023", "e_status" : 0, "SUID" : 5368, "station_g_cd" : 2200107, "add" : "練馬区中村北4-2-1", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200107", "pref_name" : "東京都", "shared_name" : "2200107", "lat" : 35.736767, "y" : -357367.67, "x" : 1396374.56 }, "position" : { "x" : 1396374.56, "y" : -357367.67 }, "selected" : false }, { "data" : { "id" : "5367", "station_name" : "練馬", "close_ymd" : "", "lon" : 139.654368, "post" : "176-0001", "e_status" : 0, "SUID" : 5367, "station_g_cd" : 2200106, "add" : "練馬区練馬1-3-5", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200106", "pref_name" : "東京都", "shared_name" : "2200106", "lat" : 35.737893, "y" : -357378.93, "x" : 1396543.6800000002 }, "position" : { "x" : 1396543.6800000002, "y" : -357378.93 }, "selected" : false }, { "data" : { "id" : "3210", "station_name" : "八丁堀", "close_ymd" : "", "lon" : 139.777705, "post" : "104-0032", "e_status" : 0, "SUID" : 3210, "station_g_cd" : 1132602, "add" : "中央区八丁堀3丁目", "line_cd" : 11326, "selected" : false, "open_ymd" : "", "name" : "1132602", "pref_name" : "東京都", "shared_name" : "1132602", "lat" : 35.674617, "y" : -356746.17, "x" : 1397777.05 }, "position" : { "x" : 1397777.05, "y" : -356746.17 }, "selected" : false }, { "data" : { "id" : "3209", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "-", "e_status" : 0, "SUID" : 3209, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11326, "selected" : false, "open_ymd" : "", "name" : "1132601", "pref_name" : "東京都", "shared_name" : "1132601", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "5377", "station_name" : "秋津", "close_ymd" : "", "lon" : 139.49653899999998, "post" : "189-0001", "e_status" : 0, "SUID" : 5377, "station_g_cd" : 2200116, "add" : "東村山市秋津町5-7-8", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200116", "pref_name" : "東京都", "shared_name" : "2200116", "lat" : 35.778614000000005, "y" : -357786.1400000001, "x" : 1394965.39 }, "position" : { "x" : 1394965.39, "y" : -357786.1400000001 }, "selected" : false }, { "data" : { "id" : "3212", "station_name" : "潮見", "close_ymd" : "", "lon" : 139.817341, "post" : "135-0052", "e_status" : 0, "SUID" : 3212, "station_g_cd" : 1132604, "add" : "江東区潮見2丁目", "line_cd" : 11326, "selected" : false, "open_ymd" : "", "name" : "1132604", "pref_name" : "東京都", "shared_name" : "1132604", "lat" : 35.658702000000005, "y" : -356587.0200000001, "x" : 1398173.41 }, "position" : { "x" : 1398173.41, "y" : -356587.0200000001 }, "selected" : false }, { "data" : { "id" : "3211", "station_name" : "越中島", "close_ymd" : "", "lon" : 139.792713, "post" : "135-0044", "e_status" : 0, "SUID" : 3211, "station_g_cd" : 1132603, "add" : "江東区越中島2丁目", "line_cd" : 11326, "selected" : false, "open_ymd" : "", "name" : "1132603", "pref_name" : "東京都", "shared_name" : "1132603", "lat" : 35.667946, "y" : -356679.46, "x" : 1397927.13 }, "position" : { "x" : 1397927.13, "y" : -356679.46 }, "selected" : false }, { "data" : { "id" : "5374", "station_name" : "ひばりヶ丘", "close_ymd" : "", "lon" : 139.545852, "post" : "202-0005", "e_status" : 0, "SUID" : 5374, "station_g_cd" : 2200113, "add" : "東京都西東京市住吉町三丁目", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200113", "pref_name" : "東京都", "shared_name" : "2200113", "lat" : 35.751484999999995, "y" : -357514.85, "x" : 1395458.52 }, "position" : { "x" : 1395458.52, "y" : -357514.85 }, "selected" : false }, { "data" : { "id" : "5373", "station_name" : "保谷", "close_ymd" : "", "lon" : 139.567753, "post" : "202-0012", "e_status" : 0, "SUID" : 5373, "station_g_cd" : 2200112, "add" : "西東京市東町3-14-30", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200112", "pref_name" : "東京都", "shared_name" : "2200112", "lat" : 35.748222, "y" : -357482.22, "x" : 1395677.53 }, "position" : { "x" : 1395677.53, "y" : -357482.22 }, "selected" : false }, { "data" : { "id" : "5376", "station_name" : "清瀬", "close_ymd" : "", "lon" : 139.519917, "post" : "204-0021", "e_status" : 0, "SUID" : 5376, "station_g_cd" : 2200115, "add" : "清瀬市元町1-2-4", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200115", "pref_name" : "東京都", "shared_name" : "2200115", "lat" : 35.772221, "y" : -357722.21, "x" : 1395199.17 }, "position" : { "x" : 1395199.17, "y" : -357722.21 }, "selected" : false }, { "data" : { "id" : "5375", "station_name" : "東久留米", "close_ymd" : "", "lon" : 139.533739, "post" : "203-0014", "e_status" : 0, "SUID" : 5375, "station_g_cd" : 2200114, "add" : "東久留米市東本町1-8", "line_cd" : 22001, "selected" : false, "open_ymd" : "", "name" : "2200114", "pref_name" : "東京都", "shared_name" : "2200114", "lat" : 35.760445000000004, "y" : -357604.45000000007, "x" : 1395337.39 }, "position" : { "x" : 1395337.39, "y" : -357604.45000000007 }, "selected" : false }, { "data" : { "id" : "7607", "station_name" : "中井", "close_ymd" : "", "lon" : 139.68635600000002, "post" : "161-0032", "e_status" : 0, "SUID" : 7607, "station_g_cd" : 2200704, "add" : "新宿区中落合1-19-1", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930132", "pref_name" : "東京都", "shared_name" : "9930132", "lat" : 35.714034999999996, "y" : -357140.35, "x" : 1396863.5600000003 }, "position" : { "x" : 1396863.5600000003, "y" : -357140.35 }, "selected" : false }, { "data" : { "id" : "5151", "station_name" : "ときわ台", "close_ymd" : "", "lon" : 139.68901499999998, "post" : "174-0071", "e_status" : 0, "SUID" : 5151, "station_g_cd" : 2100106, "add" : "板橋区常盤台1-43-1", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100106", "pref_name" : "東京都", "shared_name" : "2100106", "lat" : 35.758771, "y" : -357587.71, "x" : 1396890.15 }, "position" : { "x" : 1396890.15, "y" : -357587.71 }, "selected" : false }, { "data" : { "id" : "7608", "station_name" : "落合南長崎", "close_ymd" : "", "lon" : 139.683303, "post" : "161-0031", "e_status" : 0, "SUID" : 7608, "station_g_cd" : 9930133, "add" : "新宿区西落合3-1-18", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930133", "pref_name" : "東京都", "shared_name" : "9930133", "lat" : 35.723608, "y" : -357236.07999999996, "x" : 1396833.03 }, "position" : { "x" : 1396833.03, "y" : -357236.07999999996 }, "selected" : false }, { "data" : { "id" : "5152", "station_name" : "上板橋", "close_ymd" : "", "lon" : 139.67641, "post" : "174-0076", "e_status" : 0, "SUID" : 5152, "station_g_cd" : 2100107, "add" : "板橋区上板橋2-36-7", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100107", "pref_name" : "東京都", "shared_name" : "2100107", "lat" : 35.763596, "y" : -357635.96, "x" : 1396764.1 }, "position" : { "x" : 1396764.1, "y" : -357635.96 }, "selected" : false }, { "data" : { "id" : "7605", "station_name" : "中野坂上", "close_ymd" : "", "lon" : 139.682279, "post" : "164-0011", "e_status" : 0, "SUID" : 7605, "station_g_cd" : 2800220, "add" : "中野区中央2-1-2", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930130", "pref_name" : "東京都", "shared_name" : "9930130", "lat" : 35.69709, "y" : -356970.9, "x" : 1396822.79 }, "position" : { "x" : 1396822.79, "y" : -356970.9 }, "selected" : false }, { "data" : { "id" : "5149", "station_name" : "大山", "close_ymd" : "", "lon" : 139.702589, "post" : "173-0023", "e_status" : 0, "SUID" : 5149, "station_g_cd" : 2100104, "add" : "板橋区大山町4-1", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100104", "pref_name" : "東京都", "shared_name" : "2100104", "lat" : 35.748398, "y" : -357483.98000000004, "x" : 1397025.89 }, "position" : { "x" : 1397025.89, "y" : -357483.98000000004 }, "selected" : false }, { "data" : { "id" : "7606", "station_name" : "東中野", "close_ymd" : "", "lon" : 139.682987, "post" : "164-0003", "e_status" : 0, "SUID" : 7606, "station_g_cd" : 1131213, "add" : "中野区東中野4丁目", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930131", "pref_name" : "東京都", "shared_name" : "9930131", "lat" : 35.706891, "y" : -357068.91, "x" : 1396829.8699999999 }, "position" : { "x" : 1396829.8699999999, "y" : -357068.91 }, "selected" : false }, { "data" : { "id" : "5150", "station_name" : "中板橋", "close_ymd" : "", "lon" : 139.694628, "post" : "173-0021", "e_status" : 0, "SUID" : 5150, "station_g_cd" : 2100105, "add" : "板橋区弥生町33-1", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100105", "pref_name" : "東京都", "shared_name" : "2100105", "lat" : 35.756214, "y" : -357562.14, "x" : 1396946.28 }, "position" : { "x" : 1396946.28, "y" : -357562.14 }, "selected" : false }, { "data" : { "id" : "7611", "station_name" : "豊島園", "close_ymd" : "", "lon" : 139.64911, "post" : "176-0001", "e_status" : 0, "SUID" : 7611, "station_g_cd" : 2200402, "add" : "練馬区練馬4-16-5", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930136", "pref_name" : "東京都", "shared_name" : "9930136", "lat" : 35.742067, "y" : -357420.67, "x" : 1396491.1 }, "position" : { "x" : 1396491.1, "y" : -357420.67 }, "selected" : false }, { "data" : { "id" : "5155", "station_name" : "成増", "close_ymd" : "", "lon" : 139.632708, "post" : "175-0094", "e_status" : 0, "SUID" : 5155, "station_g_cd" : 2100110, "add" : "板橋区成増2-13-1", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100110", "pref_name" : "東京都", "shared_name" : "2100110", "lat" : 35.777722999999995, "y" : -357777.2299999999, "x" : 1396327.08 }, "position" : { "x" : 1396327.08, "y" : -357777.2299999999 }, "selected" : false }, { "data" : { "id" : "7612", "station_name" : "練馬春日町", "close_ymd" : "", "lon" : 139.64023600000002, "post" : "179-0074", "e_status" : 0, "SUID" : 7612, "station_g_cd" : 9930137, "add" : "練馬区春日町3-29-25", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930137", "pref_name" : "東京都", "shared_name" : "9930137", "lat" : 35.751452, "y" : -357514.52, "x" : 1396402.36 }, "position" : { "x" : 1396402.36, "y" : -357514.52 }, "selected" : false }, { "data" : { "id" : "7609", "station_name" : "新江古田", "close_ymd" : "", "lon" : 139.67065300000002, "post" : "165-0023", "e_status" : 0, "SUID" : 7609, "station_g_cd" : 9930134, "add" : "中野区江原町2-29-13", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930134", "pref_name" : "東京都", "shared_name" : "9930134", "lat" : 35.732538, "y" : -357325.38, "x" : 1396706.5300000003 }, "position" : { "x" : 1396706.5300000003, "y" : -357325.38 }, "selected" : false }, { "data" : { "id" : "5153", "station_name" : "東武練馬", "close_ymd" : "", "lon" : 139.66196399999998, "post" : "175-0083", "e_status" : 0, "SUID" : 5153, "station_g_cd" : 2100108, "add" : "板橋区徳丸2-2-14", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100108", "pref_name" : "東京都", "shared_name" : "2100108", "lat" : 35.768698, "y" : -357686.98, "x" : 1396619.64 }, "position" : { "x" : 1396619.64, "y" : -357686.98 }, "selected" : false }, { "data" : { "id" : "7610", "station_name" : "練馬", "close_ymd" : "", "lon" : 139.65476999999998, "post" : "176-0001", "e_status" : 0, "SUID" : 7610, "station_g_cd" : 2200106, "add" : "練馬区練馬1-3-5", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930135", "pref_name" : "東京都", "shared_name" : "9930135", "lat" : 35.737404, "y" : -357374.04, "x" : 1396547.7 }, "position" : { "x" : 1396547.7, "y" : -357374.04 }, "selected" : false }, { "data" : { "id" : "5154", "station_name" : "下赤塚", "close_ymd" : "", "lon" : 139.644482, "post" : "175-0093", "e_status" : 0, "SUID" : 5154, "station_g_cd" : 2100109, "add" : "板橋区赤塚新町1-23-1", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100109", "pref_name" : "東京都", "shared_name" : "2100109", "lat" : 35.770558, "y" : -357705.58, "x" : 1396444.82 }, "position" : { "x" : 1396444.82, "y" : -357705.58 }, "selected" : false }, { "data" : { "id" : "7615", "station_name" : "馬込", "close_ymd" : "", "lon" : 139.711772, "post" : "143-0021", "e_status" : 0, "SUID" : 7615, "station_g_cd" : 9930202, "add" : "大田区北馬込2-31-9", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930202", "pref_name" : "東京都", "shared_name" : "9930202", "lat" : 35.596435, "y" : -355964.35, "x" : 1397117.72 }, "position" : { "x" : 1397117.72, "y" : -355964.35 }, "selected" : false }, { "data" : { "id" : "7616", "station_name" : "中延", "close_ymd" : "", "lon" : 139.713736, "post" : "142-0053", "e_status" : 0, "SUID" : 7616, "station_g_cd" : 2600404, "add" : "品川区中延4-5-5", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930203", "pref_name" : "東京都", "shared_name" : "9930203", "lat" : 35.605769, "y" : -356057.69, "x" : 1397137.36 }, "position" : { "x" : 1397137.36, "y" : -356057.69 }, "selected" : false }, { "data" : { "id" : "7613", "station_name" : "光が丘", "close_ymd" : "", "lon" : 139.628603, "post" : "179-0072", "e_status" : 0, "SUID" : 7613, "station_g_cd" : 9930138, "add" : "練馬区光が丘2-9-5", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930138", "pref_name" : "東京都", "shared_name" : "9930138", "lat" : 35.758526, "y" : -357585.26, "x" : 1396286.03 }, "position" : { "x" : 1396286.03, "y" : -357585.26 }, "selected" : false }, { "data" : { "id" : "7614", "station_name" : "西馬込", "close_ymd" : "", "lon" : 139.705942, "post" : "143-0026", "e_status" : 0, "SUID" : 7614, "station_g_cd" : 9930201, "add" : "大田区西馬込2-1-6", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930201", "pref_name" : "東京都", "shared_name" : "9930201", "lat" : 35.586859000000004, "y" : -355868.59, "x" : 1397059.42 }, "position" : { "x" : 1397059.42, "y" : -355868.59 }, "selected" : false }, { "data" : { "id" : "5147", "station_name" : "北池袋", "close_ymd" : "", "lon" : 139.716749, "post" : "170-0011", "e_status" : 0, "SUID" : 5147, "station_g_cd" : 2100102, "add" : "豊島区池袋本町1-36-6", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100102", "pref_name" : "東京都", "shared_name" : "2100102", "lat" : 35.741283, "y" : -357412.83, "x" : 1397167.49 }, "position" : { "x" : 1397167.49, "y" : -357412.83 }, "selected" : false }, { "data" : { "id" : "7619", "station_name" : "高輪台", "close_ymd" : "", "lon" : 139.73030500000002, "post" : "108-0071", "e_status" : 0, "SUID" : 7619, "station_g_cd" : 9930206, "add" : "港区白金台2-26-7", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930206", "pref_name" : "東京都", "shared_name" : "9930206", "lat" : 35.631679, "y" : -356316.79, "x" : 1397303.05 }, "position" : { "x" : 1397303.05, "y" : -356316.79 }, "selected" : false }, { "data" : { "id" : "7620", "station_name" : "泉岳寺", "close_ymd" : "", "lon" : 139.74002, "post" : "108-0074", "e_status" : 0, "SUID" : 7620, "station_g_cd" : 2700101, "add" : "港区高輪2-16-34", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930207", "pref_name" : "東京都", "shared_name" : "9930207", "lat" : 35.638692, "y" : -356386.92, "x" : 1397400.2 }, "position" : { "x" : 1397400.2, "y" : -356386.92 }, "selected" : false }, { "data" : { "id" : "5148", "station_name" : "下板橋", "close_ymd" : "", "lon" : 139.714785, "post" : "170-0011", "e_status" : 0, "SUID" : 5148, "station_g_cd" : 2100103, "add" : "豊島区池袋本町4-43-11", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100103", "pref_name" : "東京都", "shared_name" : "2100103", "lat" : 35.745721, "y" : -357457.21, "x" : 1397147.85 }, "position" : { "x" : 1397147.85, "y" : -357457.21 }, "selected" : false }, { "data" : { "id" : "7617", "station_name" : "戸越", "close_ymd" : "", "lon" : 139.716495, "post" : "142-0041", "e_status" : 0, "SUID" : 7617, "station_g_cd" : 2600503, "add" : "品川区戸越3-4-17", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930204", "pref_name" : "東京都", "shared_name" : "9930204", "lat" : 35.614633000000005, "y" : -356146.3300000001, "x" : 1397164.9500000002 }, "position" : { "x" : 1397164.9500000002, "y" : -356146.3300000001 }, "selected" : false }, { "data" : { "id" : "5146", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.710678, "post" : "", "e_status" : 0, "SUID" : 5146, "station_g_cd" : 1130212, "add" : "東京都豊島区", "line_cd" : 21001, "selected" : false, "open_ymd" : "", "name" : "2100101", "pref_name" : "東京都", "shared_name" : "2100101", "lat" : 35.730924, "y" : -357309.24, "x" : 1397106.78 }, "position" : { "x" : 1397106.78, "y" : -357309.24 }, "selected" : false }, { "data" : { "id" : "7618", "station_name" : "五反田", "close_ymd" : "", "lon" : 139.724175, "post" : "", "e_status" : 0, "SUID" : 7618, "station_g_cd" : 1130202, "add" : "東京都品川区東五反田一丁目26-14", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930205", "pref_name" : "東京都", "shared_name" : "9930205", "lat" : 35.627102, "y" : -356271.02, "x" : 1397241.75 }, "position" : { "x" : 1397241.75, "y" : -356271.02 }, "selected" : false }, { "data" : { "id" : "7624", "station_name" : "東銀座", "close_ymd" : "", "lon" : 139.767253, "post" : "104-0061", "e_status" : 0, "SUID" : 7624, "station_g_cd" : 2800313, "add" : "中央区銀座4-12-15", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930211", "pref_name" : "東京都", "shared_name" : "9930211", "lat" : 35.669464000000005, "y" : -356694.6400000001, "x" : 1397672.53 }, "position" : { "x" : 1397672.53, "y" : -356694.6400000001 }, "selected" : false }, { "data" : { "id" : "7623", "station_name" : "新橋", "close_ymd" : "", "lon" : 139.759451, "post" : "", "e_status" : 0, "SUID" : 7623, "station_g_cd" : 1130102, "add" : "東京都港区新橋二丁目21-1", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930210", "pref_name" : "東京都", "shared_name" : "9930210", "lat" : 35.665577, "y" : -356655.77, "x" : 1397594.5100000002 }, "position" : { "x" : 1397594.5100000002, "y" : -356655.77 }, "selected" : false }, { "data" : { "id" : "7622", "station_name" : "大門", "close_ymd" : "", "lon" : 139.75466, "post" : "105-0013", "e_status" : 0, "SUID" : 7622, "station_g_cd" : 9930121, "add" : "港区浜松町1-27-12", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930209", "pref_name" : "東京都", "shared_name" : "9930209", "lat" : 35.656785, "y" : -356567.85, "x" : 1397546.6 }, "position" : { "x" : 1397546.6, "y" : -356567.85 }, "selected" : false }, { "data" : { "id" : "7621", "station_name" : "三田", "close_ymd" : "", "lon" : 139.748775, "post" : "108-0014", "e_status" : 0, "SUID" : 7621, "station_g_cd" : 9930208, "add" : "港区芝5-34-10", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930208", "pref_name" : "東京都", "shared_name" : "9930208", "lat" : 35.648179999999996, "y" : -356481.8, "x" : 1397487.75 }, "position" : { "x" : 1397487.75, "y" : -356481.8 }, "selected" : false }, { "data" : { "id" : "7628", "station_name" : "東日本橋", "close_ymd" : "", "lon" : 139.784821, "post" : "103-0004", "e_status" : 0, "SUID" : 7628, "station_g_cd" : 1131403, "add" : "中央区東日本橋3-11-8", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930215", "pref_name" : "東京都", "shared_name" : "9930215", "lat" : 35.692126, "y" : -356921.26, "x" : 1397848.21 }, "position" : { "x" : 1397848.21, "y" : -356921.26 }, "selected" : false }, { "data" : { "id" : "7627", "station_name" : "人形町", "close_ymd" : "", "lon" : 139.782285, "post" : "103-0013", "e_status" : 0, "SUID" : 7627, "station_g_cd" : 2800309, "add" : "中央区日本橋人形町2-6-5", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930214", "pref_name" : "東京都", "shared_name" : "9930214", "lat" : 35.686307, "y" : -356863.07, "x" : 1397822.85 }, "position" : { "x" : 1397822.85, "y" : -356863.07 }, "selected" : false }, { "data" : { "id" : "7626", "station_name" : "日本橋", "close_ymd" : "", "lon" : 139.775721, "post" : "103-0027", "e_status" : 0, "SUID" : 7626, "station_g_cd" : 2800109, "add" : "中央区日本橋1丁目", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930213", "pref_name" : "東京都", "shared_name" : "9930213", "lat" : 35.681688, "y" : -356816.88, "x" : 1397757.21 }, "position" : { "x" : 1397757.21, "y" : -356816.88 }, "selected" : false }, { "data" : { "id" : "7625", "station_name" : "宝町", "close_ymd" : "", "lon" : 139.77176699999998, "post" : "104-0031", "e_status" : 0, "SUID" : 7625, "station_g_cd" : 2800110, "add" : "中央区京橋2-13-11", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930212", "pref_name" : "東京都", "shared_name" : "9930212", "lat" : 35.675461, "y" : -356754.61, "x" : 1397717.67 }, "position" : { "x" : 1397717.67, "y" : -356754.61 }, "selected" : false }, { "data" : { "id" : "7632", "station_name" : "本所吾妻橋", "close_ymd" : "", "lon" : 139.804624, "post" : "130-0001", "e_status" : 0, "SUID" : 7632, "station_g_cd" : 9930219, "add" : "墨田区吾妻橋3-7-16", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930219", "pref_name" : "東京都", "shared_name" : "9930219", "lat" : 35.70858, "y" : -357085.8, "x" : 1398046.24 }, "position" : { "x" : 1398046.24, "y" : -357085.8 }, "selected" : false }, { "data" : { "id" : "7631", "station_name" : "浅草", "close_ymd" : "", "lon" : 139.79697, "post" : "", "e_status" : 0, "SUID" : 7631, "station_g_cd" : 2100201, "add" : "東京都台東区", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930218", "pref_name" : "東京都", "shared_name" : "9930218", "lat" : 35.709461, "y" : -357094.61, "x" : 1397969.7 }, "position" : { "x" : 1397969.7, "y" : -357094.61 }, "selected" : false }, { "data" : { "id" : "7630", "station_name" : "蔵前", "close_ymd" : "", "lon" : 139.790931, "post" : "111-0051", "e_status" : 0, "SUID" : 7630, "station_g_cd" : 9930112, "add" : "台東区蔵前2-3-1", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930217", "pref_name" : "東京都", "shared_name" : "9930217", "lat" : 35.703236, "y" : -357032.36, "x" : 1397909.31 }, "position" : { "x" : 1397909.31, "y" : -357032.36 }, "selected" : false }, { "data" : { "id" : "7629", "station_name" : "浅草橋", "close_ymd" : "", "lon" : 139.786305, "post" : "111-0053", "e_status" : 0, "SUID" : 7629, "station_g_cd" : 1131320, "add" : "台東区浅草橋1丁目", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930216", "pref_name" : "東京都", "shared_name" : "9930216", "lat" : 35.697451, "y" : -356974.51, "x" : 1397863.05 }, "position" : { "x" : 1397863.05, "y" : -356974.51 }, "selected" : false }, { "data" : { "id" : "7636", "station_name" : "白金高輪", "close_ymd" : "", "lon" : 139.734104, "post" : "108-0074", "e_status" : 0, "SUID" : 7636, "station_g_cd" : 2800917, "add" : "港区高輪1-3-20", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930303", "pref_name" : "東京都", "shared_name" : "9930303", "lat" : 35.642903000000004, "y" : -356429.03, "x" : 1397341.04 }, "position" : { "x" : 1397341.04, "y" : -356429.03 }, "selected" : false }, { "data" : { "id" : "7635", "station_name" : "白金台", "close_ymd" : "", "lon" : 139.726133, "post" : "108-0071", "e_status" : 0, "SUID" : 7635, "station_g_cd" : 2800918, "add" : "港区白金台3-2", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930302", "pref_name" : "東京都", "shared_name" : "9930302", "lat" : 35.637917, "y" : -356379.17000000004, "x" : 1397261.33 }, "position" : { "x" : 1397261.33, "y" : -356379.17000000004 }, "selected" : false }, { "data" : { "id" : "7634", "station_name" : "目黒", "close_ymd" : "", "lon" : 139.7155, "post" : "", "e_status" : 0, "SUID" : 7634, "station_g_cd" : 1130203, "add" : "東京都品川区上大崎四丁目2-1", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930301", "pref_name" : "東京都", "shared_name" : "9930301", "lat" : 35.633272, "y" : -356332.72, "x" : 1397155.0 }, "position" : { "x" : 1397155.0, "y" : -356332.72 }, "selected" : false }, { "data" : { "id" : "7633", "station_name" : "押上(スカイツリー前)", "close_ymd" : "", "lon" : 139.812935, "post" : "131-0045", "e_status" : 0, "SUID" : 7633, "station_g_cd" : 2100203, "add" : "墨田区押上一丁目", "line_cd" : 99302, "selected" : false, "open_ymd" : "", "name" : "9930220", "pref_name" : "東京都", "shared_name" : "9930220", "lat" : 35.710702000000005, "y" : -357107.0200000001, "x" : 1398129.35 }, "position" : { "x" : 1398129.35, "y" : -357107.0200000001 }, "selected" : false }, { "data" : { "id" : "3270", "station_name" : "高尾", "close_ymd" : "", "lon" : 139.282288, "post" : "193-0844", "e_status" : 0, "SUID" : 3270, "station_g_cd" : 1131112, "add" : "八王子市高尾町", "line_cd" : 11328, "selected" : false, "open_ymd" : "", "name" : "1132815", "pref_name" : "東京都", "shared_name" : "1132815", "lat" : 35.642026, "y" : -356420.26, "x" : 1392822.88 }, "position" : { "x" : 1392822.88, "y" : -356420.26 }, "selected" : false }, { "data" : { "id" : "3271", "station_name" : "八王子", "close_ymd" : "", "lon" : 139.338998, "post" : "-", "e_status" : 0, "SUID" : 3271, "station_g_cd" : 1130620, "add" : "東京都八王子市旭町1-1", "line_cd" : 11328, "selected" : false, "open_ymd" : "1889-08-11", "name" : "1132816", "pref_name" : "東京都", "shared_name" : "1132816", "lat" : 35.655555, "y" : -356555.55, "x" : 1393389.98 }, "position" : { "x" : 1393389.98, "y" : -356555.55 }, "selected" : false }, { "data" : { "id" : "3272", "station_name" : "立川", "close_ymd" : "", "lon" : 139.413704, "post" : "-", "e_status" : 0, "SUID" : 3272, "station_g_cd" : 1130325, "add" : "東京都立川市曙町二丁目1-1", "line_cd" : 11328, "selected" : false, "open_ymd" : "1889-04-11", "name" : "1132817", "pref_name" : "東京都", "shared_name" : "1132817", "lat" : 35.698202, "y" : -356982.02, "x" : 1394137.04 }, "position" : { "x" : 1394137.04, "y" : -356982.02 }, "selected" : false }, { "data" : { "id" : "7576", "station_name" : "都庁前", "close_ymd" : "", "lon" : 139.69257, "post" : "160-0023", "e_status" : 0, "SUID" : 7576, "station_g_cd" : 9930101, "add" : "新宿区西新宿2-8-1", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930101", "pref_name" : "東京都", "shared_name" : "9930101", "lat" : 35.690551, "y" : -356905.51, "x" : 1396925.7 }, "position" : { "x" : 1396925.7, "y" : -356905.51 }, "selected" : false }, { "data" : { "id" : "5184", "station_name" : "浅草", "close_ymd" : "", "lon" : 139.798214, "post" : "", "e_status" : 0, "SUID" : 5184, "station_g_cd" : 2100201, "add" : "東京都台東区", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100201", "pref_name" : "東京都", "shared_name" : "2100201", "lat" : 35.711883, "y" : -357118.83, "x" : 1397982.1400000001 }, "position" : { "x" : 1397982.1400000001, "y" : -357118.83 }, "selected" : false }, { "data" : { "id" : "3273", "station_name" : "国分寺", "close_ymd" : "", "lon" : 139.480841, "post" : "-", "e_status" : 0, "SUID" : 3273, "station_g_cd" : 1131106, "add" : "東京都国分寺市本町二丁目", "line_cd" : 11328, "selected" : false, "open_ymd" : "1889-04-11", "name" : "1132818", "pref_name" : "東京都", "shared_name" : "1132818", "lat" : 35.700123, "y" : -357001.23, "x" : 1394808.41 }, "position" : { "x" : 1394808.41, "y" : -357001.23 }, "selected" : false }, { "data" : { "id" : "7577", "station_name" : "西新宿五丁目", "close_ymd" : "", "lon" : 139.684304, "post" : "160-0023", "e_status" : 0, "SUID" : 7577, "station_g_cd" : 9930129, "add" : "新宿区西新宿5-25-9", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930129", "pref_name" : "東京都", "shared_name" : "9930129", "lat" : 35.689797999999996, "y" : -356897.98, "x" : 1396843.04 }, "position" : { "x" : 1396843.04, "y" : -356897.98 }, "selected" : false }, { "data" : { "id" : "5185", "station_name" : "とうきょうスカイツリー", "close_ymd" : "", "lon" : 139.809332, "post" : "131-0045", "e_status" : 0, "SUID" : 5185, "station_g_cd" : 2100202, "add" : "墨田区押上1丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "1902-04-01", "name" : "2100202", "pref_name" : "東京都", "shared_name" : "2100202", "lat" : 35.71043, "y" : -357104.30000000005, "x" : 1398093.32 }, "position" : { "x" : 1398093.32, "y" : -357104.30000000005 }, "selected" : false }, { "data" : { "id" : "3274", "station_name" : "三鷹", "close_ymd" : "", "lon" : 139.560325, "post" : "-", "e_status" : 0, "SUID" : 3274, "station_g_cd" : 1131105, "add" : "東京都三鷹市下連雀三丁目46-1", "line_cd" : 11328, "selected" : false, "open_ymd" : "1930-06-25", "name" : "1132819", "pref_name" : "東京都", "shared_name" : "1132819", "lat" : 35.702683, "y" : -357026.83, "x" : 1395603.25 }, "position" : { "x" : 1395603.25, "y" : -357026.83 }, "selected" : false }, { "data" : { "id" : "7578", "station_name" : "新宿西口", "close_ymd" : "", "lon" : 139.69915500000002, "post" : "160-0023", "e_status" : 0, "SUID" : 7578, "station_g_cd" : 9930102, "add" : "新宿区西新宿1-3-17", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930102", "pref_name" : "東京都", "shared_name" : "9930102", "lat" : 35.693315000000005, "y" : -356933.1500000001, "x" : 1396991.5500000003 }, "position" : { "x" : 1396991.5500000003, "y" : -356933.1500000001 }, "selected" : false }, { "data" : { "id" : "5186", "station_name" : "押上〈スカイツリー前〉", "close_ymd" : "", "lon" : 139.812935, "post" : "131-0045", "e_status" : 0, "SUID" : 5186, "station_g_cd" : 2100203, "add" : "墨田区押上一丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100203", "pref_name" : "東京都", "shared_name" : "2100203", "lat" : 35.710702000000005, "y" : -357107.0200000001, "x" : 1398129.35 }, "position" : { "x" : 1398129.35, "y" : -357107.0200000001 }, "selected" : false }, { "data" : { "id" : "3275", "station_name" : "吉祥寺", "close_ymd" : "", "lon" : 139.57976499999998, "post" : "-", "e_status" : 0, "SUID" : 3275, "station_g_cd" : 1131104, "add" : "東京都武蔵野市吉祥寺南町", "line_cd" : 11328, "selected" : false, "open_ymd" : "1899-12-30", "name" : "1132820", "pref_name" : "東京都", "shared_name" : "1132820", "lat" : 35.703119, "y" : -357031.19, "x" : 1395797.65 }, "position" : { "x" : 1395797.65, "y" : -357031.19 }, "selected" : false }, { "data" : { "id" : "7579", "station_name" : "東新宿", "close_ymd" : "", "lon" : 139.707549, "post" : "160-0022", "e_status" : 0, "SUID" : 7579, "station_g_cd" : 2801012, "add" : "新宿区新宿7-27-3", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930103", "pref_name" : "東京都", "shared_name" : "9930103", "lat" : 35.69792, "y" : -356979.2, "x" : 1397075.49 }, "position" : { "x" : 1397075.49, "y" : -356979.2 }, "selected" : false }, { "data" : { "id" : "5187", "station_name" : "曳舟", "close_ymd" : "", "lon" : 139.81663400000002, "post" : "131-0032", "e_status" : 0, "SUID" : 5187, "station_g_cd" : 2100204, "add" : "墨田区東向島2丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100204", "pref_name" : "東京都", "shared_name" : "2100204", "lat" : 35.718418, "y" : -357184.18, "x" : 1398166.3400000003 }, "position" : { "x" : 1398166.3400000003, "y" : -357184.18 }, "selected" : false }, { "data" : { "id" : "5188", "station_name" : "東向島", "close_ymd" : "", "lon" : 139.819306, "post" : "131-0032", "e_status" : 0, "SUID" : 5188, "station_g_cd" : 2100205, "add" : "墨田区東向島4丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100205", "pref_name" : "東京都", "shared_name" : "2100205", "lat" : 35.724323999999996, "y" : -357243.23999999993, "x" : 1398193.06 }, "position" : { "x" : 1398193.06, "y" : -357243.23999999993 }, "selected" : false }, { "data" : { "id" : "7580", "station_name" : "若松河田", "close_ymd" : "", "lon" : 139.718184, "post" : "162-0054", "e_status" : 0, "SUID" : 7580, "station_g_cd" : 9930104, "add" : "新宿区河田町10-10", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930104", "pref_name" : "東京都", "shared_name" : "9930104", "lat" : 35.699218, "y" : -356992.18, "x" : 1397181.84 }, "position" : { "x" : 1397181.84, "y" : -356992.18 }, "selected" : false }, { "data" : { "id" : "7581", "station_name" : "牛込柳町", "close_ymd" : "", "lon" : 139.725027, "post" : "162-0053", "e_status" : 0, "SUID" : 7581, "station_g_cd" : 9930105, "add" : "新宿区原町2-32", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930105", "pref_name" : "東京都", "shared_name" : "9930105", "lat" : 35.699518, "y" : -356995.18, "x" : 1397250.27 }, "position" : { "x" : 1397250.27, "y" : -356995.18 }, "selected" : false }, { "data" : { "id" : "7582", "station_name" : "牛込神楽坂", "close_ymd" : "", "lon" : 139.735802, "post" : "162-0833", "e_status" : 0, "SUID" : 7582, "station_g_cd" : 9930106, "add" : "新宿区箪笥町15", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930106", "pref_name" : "東京都", "shared_name" : "9930106", "lat" : 35.700851, "y" : -357008.51, "x" : 1397358.02 }, "position" : { "x" : 1397358.02, "y" : -357008.51 }, "selected" : false }, { "data" : { "id" : "7583", "station_name" : "飯田橋", "close_ymd" : "", "lon" : 139.744999, "post" : "", "e_status" : 0, "SUID" : 7583, "station_g_cd" : 1131205, "add" : "東京都文京区後楽一丁目9-5", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930107", "pref_name" : "東京都", "shared_name" : "9930107", "lat" : 35.702927, "y" : -357029.27, "x" : 1397449.99 }, "position" : { "x" : 1397449.99, "y" : -357029.27 }, "selected" : false }, { "data" : { "id" : "7584", "station_name" : "春日", "close_ymd" : "", "lon" : 139.75325, "post" : "112-0003", "e_status" : 0, "SUID" : 7584, "station_g_cd" : 9930108, "add" : "文京区春日1-16-17", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930108", "pref_name" : "東京都", "shared_name" : "9930108", "lat" : 35.709598, "y" : -357095.98, "x" : 1397532.5 }, "position" : { "x" : 1397532.5, "y" : -357095.98 }, "selected" : false }, { "data" : { "id" : "7585", "station_name" : "本郷三丁目", "close_ymd" : "", "lon" : 139.760095, "post" : "113-0033", "e_status" : 0, "SUID" : 7585, "station_g_cd" : 2800205, "add" : "文京区本郷2-39-1", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930109", "pref_name" : "東京都", "shared_name" : "9930109", "lat" : 35.707462, "y" : -357074.62, "x" : 1397600.95 }, "position" : { "x" : 1397600.95, "y" : -357074.62 }, "selected" : false }, { "data" : { "id" : "7586", "station_name" : "上野御徒町", "close_ymd" : "", "lon" : 139.77433200000002, "post" : "110-0005", "e_status" : 0, "SUID" : 7586, "station_g_cd" : 1130221, "add" : "台東区上野5-26-6", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930110", "pref_name" : "東京都", "shared_name" : "9930110", "lat" : 35.707893, "y" : -357078.93, "x" : 1397743.32 }, "position" : { "x" : 1397743.32, "y" : -357078.93 }, "selected" : false }, { "data" : { "id" : "7587", "station_name" : "新御徒町", "close_ymd" : "", "lon" : 139.781958, "post" : "111-0041", "e_status" : 0, "SUID" : 7587, "station_g_cd" : 9930111, "add" : "台東区元浅草1-5-2", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930111", "pref_name" : "東京都", "shared_name" : "9930111", "lat" : 35.707045, "y" : -357070.45, "x" : 1397819.58 }, "position" : { "x" : 1397819.58, "y" : -357070.45 }, "selected" : false }, { "data" : { "id" : "7588", "station_name" : "蔵前", "close_ymd" : "", "lon" : 139.790931, "post" : "111-0051", "e_status" : 0, "SUID" : 7588, "station_g_cd" : 9930112, "add" : "台東区蔵前2-3-1", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930112", "pref_name" : "東京都", "shared_name" : "9930112", "lat" : 35.703236, "y" : -357032.36, "x" : 1397909.31 }, "position" : { "x" : 1397909.31, "y" : -357032.36 }, "selected" : false }, { "data" : { "id" : "7590", "station_name" : "森下", "close_ymd" : "", "lon" : 139.797042, "post" : "135-0004", "e_status" : 0, "SUID" : 7590, "station_g_cd" : 9930114, "add" : "江東区森下2-17-17", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930114", "pref_name" : "東京都", "shared_name" : "9930114", "lat" : 35.68796, "y" : -356879.6, "x" : 1397970.4200000002 }, "position" : { "x" : 1397970.4200000002, "y" : -356879.6 }, "selected" : false }, { "data" : { "id" : "5197", "station_name" : "竹ノ塚", "close_ymd" : "", "lon" : 139.790788, "post" : "121-0813", "e_status" : 0, "SUID" : 5197, "station_g_cd" : 2100214, "add" : "足立区竹の塚6丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100214", "pref_name" : "東京都", "shared_name" : "2100214", "lat" : 35.794368, "y" : -357943.68, "x" : 1397907.88 }, "position" : { "x" : 1397907.88, "y" : -357943.68 }, "selected" : false }, { "data" : { "id" : "7589", "station_name" : "両国", "close_ymd" : "", "lon" : 139.79742099999999, "post" : "130-0015", "e_status" : 0, "SUID" : 7589, "station_g_cd" : 1131321, "add" : "墨田区横網1丁目", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930113", "pref_name" : "東京都", "shared_name" : "9930113", "lat" : 35.696881, "y" : -356968.81, "x" : 1397974.21 }, "position" : { "x" : 1397974.21, "y" : -356968.81 }, "selected" : false }, { "data" : { "id" : "7592", "station_name" : "門前仲町", "close_ymd" : "", "lon" : 139.796209, "post" : "135-0048", "e_status" : 0, "SUID" : 7592, "station_g_cd" : 2800412, "add" : "江東区門前仲町1丁目", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930116", "pref_name" : "東京都", "shared_name" : "9930116", "lat" : 35.671851000000004, "y" : -356718.51, "x" : 1397962.09 }, "position" : { "x" : 1397962.09, "y" : -356718.51 }, "selected" : false }, { "data" : { "id" : "7591", "station_name" : "清澄白河", "close_ymd" : "", "lon" : 139.798851, "post" : "135-0021", "e_status" : 0, "SUID" : 7591, "station_g_cd" : 2800811, "add" : "江東区白河1-7-14", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930115", "pref_name" : "東京都", "shared_name" : "9930115", "lat" : 35.682105, "y" : -356821.05, "x" : 1397988.5100000002 }, "position" : { "x" : 1397988.5100000002, "y" : -356821.05 }, "selected" : false }, { "data" : { "id" : "7594", "station_name" : "勝どき", "close_ymd" : "", "lon" : 139.776442, "post" : "104-0054", "e_status" : 0, "SUID" : 7594, "station_g_cd" : 9930118, "add" : "中央区勝どき2-10-15", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930118", "pref_name" : "東京都", "shared_name" : "9930118", "lat" : 35.658507, "y" : -356585.07, "x" : 1397764.42 }, "position" : { "x" : 1397764.42, "y" : -356585.07 }, "selected" : false }, { "data" : { "id" : "7593", "station_name" : "月島", "close_ymd" : "", "lon" : 139.784233, "post" : "", "e_status" : 0, "SUID" : 7593, "station_g_cd" : 2800621, "add" : "東京都中央区月島一丁目3-9", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930117", "pref_name" : "東京都", "shared_name" : "9930117", "lat" : 35.664871000000005, "y" : -356648.7100000001, "x" : 1397842.33 }, "position" : { "x" : 1397842.33, "y" : -356648.7100000001 }, "selected" : false }, { "data" : { "id" : "3260", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.71108600000002, "post" : "", "e_status" : 0, "SUID" : 3260, "station_g_cd" : 1130212, "add" : "東京都豊島区", "line_cd" : 11328, "selected" : false, "open_ymd" : "", "name" : "1132805", "pref_name" : "東京都", "shared_name" : "1132805", "lat" : 35.730256, "y" : -357302.56, "x" : 1397110.8600000003 }, "position" : { "x" : 1397110.8600000003, "y" : -357302.56 }, "selected" : false }, { "data" : { "id" : "7596", "station_name" : "汐留", "close_ymd" : "", "lon" : 139.760642, "post" : "105-0021", "e_status" : 0, "SUID" : 7596, "station_g_cd" : 9930120, "add" : "港区東新橋1丁目5", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930120", "pref_name" : "東京都", "shared_name" : "9930120", "lat" : 35.663703000000005, "y" : -356637.03, "x" : 1397606.42 }, "position" : { "x" : 1397606.42, "y" : -356637.03 }, "selected" : false }, { "data" : { "id" : "7595", "station_name" : "築地市場", "close_ymd" : "", "lon" : 139.76691499999998, "post" : "104-0045", "e_status" : 0, "SUID" : 7595, "station_g_cd" : 9930119, "add" : "中央区築地5-1-2", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930119", "pref_name" : "東京都", "shared_name" : "9930119", "lat" : 35.664895, "y" : -356648.95, "x" : 1397669.15 }, "position" : { "x" : 1397669.15, "y" : -356648.95 }, "selected" : false }, { "data" : { "id" : "5190", "station_name" : "堀切", "close_ymd" : "", "lon" : 139.817727, "post" : "120-0023", "e_status" : 0, "SUID" : 5190, "station_g_cd" : 2100207, "add" : "足立区千住曙町", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100207", "pref_name" : "東京都", "shared_name" : "2100207", "lat" : 35.742977, "y" : -357429.77, "x" : 1398177.27 }, "position" : { "x" : 1398177.27, "y" : -357429.77 }, "selected" : false }, { "data" : { "id" : "3262", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.701238, "post" : "", "e_status" : 0, "SUID" : 3262, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂一丁目1-1", "line_cd" : 11328, "selected" : false, "open_ymd" : "", "name" : "1132807", "pref_name" : "東京都", "shared_name" : "1132807", "lat" : 35.658871000000005, "y" : -356588.71, "x" : 1397012.38 }, "position" : { "x" : 1397012.38, "y" : -356588.71 }, "selected" : false }, { "data" : { "id" : "7598", "station_name" : "赤羽橋", "close_ymd" : "", "lon" : 139.743642, "post" : "106-0044", "e_status" : 0, "SUID" : 7598, "station_g_cd" : 9930122, "add" : "港区東麻布1-28-13", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930122", "pref_name" : "東京都", "shared_name" : "9930122", "lat" : 35.655007, "y" : -356550.06999999995, "x" : 1397436.42 }, "position" : { "x" : 1397436.42, "y" : -356550.06999999995 }, "selected" : false }, { "data" : { "id" : "5189", "station_name" : "鐘ヶ淵", "close_ymd" : "", "lon" : 139.820344, "post" : "", "e_status" : 0, "SUID" : 5189, "station_g_cd" : 2100206, "add" : "東京都墨田区墨田5丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100206", "pref_name" : "東京都", "shared_name" : "2100206", "lat" : 35.733712, "y" : -357337.12, "x" : 1398203.44 }, "position" : { "x" : 1398203.44, "y" : -357337.12 }, "selected" : false }, { "data" : { "id" : "3261", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.70046399999998, "post" : "", "e_status" : 0, "SUID" : 3261, "station_g_cd" : 1130208, "add" : "東京都新宿区新宿三丁目38-1", "line_cd" : 11328, "selected" : false, "open_ymd" : "", "name" : "1132806", "pref_name" : "東京都", "shared_name" : "1132806", "lat" : 35.689729, "y" : -356897.29, "x" : 1397004.64 }, "position" : { "x" : 1397004.64, "y" : -356897.29 }, "selected" : false }, { "data" : { "id" : "7597", "station_name" : "大門", "close_ymd" : "", "lon" : 139.75466, "post" : "105-0013", "e_status" : 0, "SUID" : 7597, "station_g_cd" : 9930121, "add" : "港区浜松町1-27-12", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930121", "pref_name" : "東京都", "shared_name" : "9930121", "lat" : 35.656785, "y" : -356567.85, "x" : 1397546.6 }, "position" : { "x" : 1397546.6, "y" : -356567.85 }, "selected" : false }, { "data" : { "id" : "5192", "station_name" : "北千住", "close_ymd" : "", "lon" : 139.805564, "post" : "120-0026", "e_status" : 0, "SUID" : 5192, "station_g_cd" : 1132005, "add" : "足立区千住旭町", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100209", "pref_name" : "東京都", "shared_name" : "2100209", "lat" : 35.749891, "y" : -357498.91, "x" : 1398055.6400000001 }, "position" : { "x" : 1398055.6400000001, "y" : -357498.91 }, "selected" : false }, { "data" : { "id" : "3264", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "", "e_status" : 0, "SUID" : 3264, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11328, "selected" : false, "open_ymd" : "", "name" : "1132809", "pref_name" : "東京都", "shared_name" : "1132809", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "7600", "station_name" : "六本木", "close_ymd" : "", "lon" : 139.73156699999998, "post" : "106-0032", "e_status" : 0, "SUID" : 7600, "station_g_cd" : 2800318, "add" : "港区六本木6-1-25", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930124", "pref_name" : "東京都", "shared_name" : "9930124", "lat" : 35.663921, "y" : -356639.21, "x" : 1397315.67 }, "position" : { "x" : 1397315.67, "y" : -356639.21 }, "selected" : false }, { "data" : { "id" : "5191", "station_name" : "牛田", "close_ymd" : "", "lon" : 139.811816, "post" : "120-0023", "e_status" : 0, "SUID" : 5191, "station_g_cd" : 2100208, "add" : "足立区千住曙町", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100208", "pref_name" : "東京都", "shared_name" : "2100208", "lat" : 35.744555, "y" : -357445.55, "x" : 1398118.16 }, "position" : { "x" : 1398118.16, "y" : -357445.55 }, "selected" : false }, { "data" : { "id" : "3263", "station_name" : "品川", "close_ymd" : "", "lon" : 139.738999, "post" : "", "e_status" : 0, "SUID" : 3263, "station_g_cd" : 1130103, "add" : "東京都港区高輪三丁目26-26", "line_cd" : 11328, "selected" : false, "open_ymd" : "", "name" : "1132808", "pref_name" : "東京都", "shared_name" : "1132808", "lat" : 35.62876, "y" : -356287.6, "x" : 1397389.99 }, "position" : { "x" : 1397389.99, "y" : -356287.6 }, "selected" : false }, { "data" : { "id" : "7599", "station_name" : "麻布十番", "close_ymd" : "", "lon" : 139.73611599999998, "post" : "106-0045", "e_status" : 0, "SUID" : 7599, "station_g_cd" : 2800916, "add" : "港区麻布十番4-4-9", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930123", "pref_name" : "東京都", "shared_name" : "9930123", "lat" : 35.656503, "y" : -356565.03, "x" : 1397361.16 }, "position" : { "x" : 1397361.16, "y" : -356565.03 }, "selected" : false }, { "data" : { "id" : "5194", "station_name" : "五反野", "close_ymd" : "", "lon" : 139.809643, "post" : "120-0015", "e_status" : 0, "SUID" : 5194, "station_g_cd" : 2100211, "add" : "足立区足立3丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100211", "pref_name" : "東京都", "shared_name" : "2100211", "lat" : 35.765852, "y" : -357658.52, "x" : 1398096.43 }, "position" : { "x" : 1398096.43, "y" : -357658.52 }, "selected" : false }, { "data" : { "id" : "7602", "station_name" : "国立競技場", "close_ymd" : "", "lon" : 139.714932, "post" : "160-0013", "e_status" : 0, "SUID" : 7602, "station_g_cd" : 9930126, "add" : "新宿区霞ケ丘町10-3", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930126", "pref_name" : "東京都", "shared_name" : "9930126", "lat" : 35.679831, "y" : -356798.31, "x" : 1397149.32 }, "position" : { "x" : 1397149.32, "y" : -356798.31 }, "selected" : false }, { "data" : { "id" : "5193", "station_name" : "小菅", "close_ymd" : "", "lon" : 139.812935, "post" : "120-0015", "e_status" : 0, "SUID" : 5193, "station_g_cd" : 2100210, "add" : "足立区足立2丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100210", "pref_name" : "東京都", "shared_name" : "2100210", "lat" : 35.759039, "y" : -357590.39, "x" : 1398129.35 }, "position" : { "x" : 1398129.35, "y" : -357590.39 }, "selected" : false }, { "data" : { "id" : "7601", "station_name" : "青山一丁目", "close_ymd" : "", "lon" : 139.72396, "post" : "107-0062", "e_status" : 0, "SUID" : 7601, "station_g_cd" : 2800116, "add" : "港区南青山1-1-19", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930125", "pref_name" : "東京都", "shared_name" : "9930125", "lat" : 35.672928999999996, "y" : -356729.29, "x" : 1397239.6 }, "position" : { "x" : 1397239.6, "y" : -356729.29 }, "selected" : false }, { "data" : { "id" : "5196", "station_name" : "西新井", "close_ymd" : "", "lon" : 139.790372, "post" : "123-0843", "e_status" : 0, "SUID" : 5196, "station_g_cd" : 2100213, "add" : "足立区西新井栄町2丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100213", "pref_name" : "東京都", "shared_name" : "2100213", "lat" : 35.777322999999996, "y" : -357773.23, "x" : 1397903.72 }, "position" : { "x" : 1397903.72, "y" : -357773.23 }, "selected" : false }, { "data" : { "id" : "7604", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.698812, "post" : "", "e_status" : 0, "SUID" : 7604, "station_g_cd" : 1130208, "add" : "東京都渋谷区代々木二丁目1-1", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930128", "pref_name" : "東京都", "shared_name" : "9930128", "lat" : 35.68869, "y" : -356886.9, "x" : 1396988.12 }, "position" : { "x" : 1396988.12, "y" : -356886.9 }, "selected" : false }, { "data" : { "id" : "5195", "station_name" : "梅島", "close_ymd" : "", "lon" : 139.797916, "post" : "123-0851", "e_status" : 0, "SUID" : 5195, "station_g_cd" : 2100212, "add" : "足立区梅田7丁目", "line_cd" : 21002, "selected" : false, "open_ymd" : "", "name" : "2100212", "pref_name" : "東京都", "shared_name" : "2100212", "lat" : 35.772437, "y" : -357724.36999999994, "x" : 1397979.16 }, "position" : { "x" : 1397979.16, "y" : -357724.36999999994 }, "selected" : false }, { "data" : { "id" : "7603", "station_name" : "代々木", "close_ymd" : "", "lon" : 139.701666, "post" : "", "e_status" : 0, "SUID" : 7603, "station_g_cd" : 1130207, "add" : "東京都渋谷区代々木一丁目35-5", "line_cd" : 99301, "selected" : false, "open_ymd" : "", "name" : "9930127", "pref_name" : "東京都", "shared_name" : "9930127", "lat" : 35.683218, "y" : -356832.18, "x" : 1397016.66 }, "position" : { "x" : 1397016.66, "y" : -356832.18 }, "selected" : false }, { "data" : { "id" : "7675", "station_name" : "大島", "close_ymd" : "", "lon" : 139.83565, "post" : "136-0072", "e_status" : 0, "SUID" : 7675, "station_g_cd" : 9930415, "add" : "江東区大島5-10-8", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930415", "pref_name" : "東京都", "shared_name" : "9930415", "lat" : 35.689904999999996, "y" : -356899.05, "x" : 1398356.4999999998 }, "position" : { "x" : 1398356.4999999998, "y" : -356899.05 }, "selected" : false }, { "data" : { "id" : "7676", "station_name" : "東大島", "close_ymd" : "", "lon" : 139.84596299999998, "post" : "136-0072", "e_status" : 0, "SUID" : 7676, "station_g_cd" : 9930416, "add" : "江東区大島9-3-14", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930416", "pref_name" : "東京都", "shared_name" : "9930416", "lat" : 35.690355, "y" : -356903.55, "x" : 1398459.63 }, "position" : { "x" : 1398459.63, "y" : -356903.55 }, "selected" : false }, { "data" : { "id" : "7673", "station_name" : "住吉", "close_ymd" : "", "lon" : 139.815681, "post" : "135-0002", "e_status" : 0, "SUID" : 7673, "station_g_cd" : 2800814, "add" : "江東区住吉2-23-12", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930413", "pref_name" : "東京都", "shared_name" : "9930413", "lat" : 35.689073, "y" : -356890.73, "x" : 1398156.81 }, "position" : { "x" : 1398156.81, "y" : -356890.73 }, "selected" : false }, { "data" : { "id" : "7674", "station_name" : "西大島", "close_ymd" : "", "lon" : 139.826206, "post" : "136-0072", "e_status" : 0, "SUID" : 7674, "station_g_cd" : 9930414, "add" : "江東区大島2-41-19", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930414", "pref_name" : "東京都", "shared_name" : "9930414", "lat" : 35.689349, "y" : -356893.49, "x" : 1398262.06 }, "position" : { "x" : 1398262.06, "y" : -356893.49 }, "selected" : false }, { "data" : { "id" : "7671", "station_name" : "森下", "close_ymd" : "", "lon" : 139.797042, "post" : "135-0004", "e_status" : 0, "SUID" : 7671, "station_g_cd" : 9930114, "add" : "江東区森下2-17-17", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930411", "pref_name" : "東京都", "shared_name" : "9930411", "lat" : 35.68796, "y" : -356879.6, "x" : 1397970.4200000002 }, "position" : { "x" : 1397970.4200000002, "y" : -356879.6 }, "selected" : false }, { "data" : { "id" : "7672", "station_name" : "菊川", "close_ymd" : "", "lon" : 139.806016, "post" : "130-0024", "e_status" : 0, "SUID" : 7672, "station_g_cd" : 9930412, "add" : "墨田区菊川3-16-2", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930412", "pref_name" : "東京都", "shared_name" : "9930412", "lat" : 35.688379, "y" : -356883.79, "x" : 1398060.16 }, "position" : { "x" : 1398060.16, "y" : -356883.79 }, "selected" : false }, { "data" : { "id" : "7669", "station_name" : "馬喰横山", "close_ymd" : "", "lon" : 139.782768, "post" : "103-0003", "e_status" : 0, "SUID" : 7669, "station_g_cd" : 1131403, "add" : "中央区日本橋横山町4-13", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930409", "pref_name" : "東京都", "shared_name" : "9930409", "lat" : 35.69212, "y" : -356921.2, "x" : 1397827.68 }, "position" : { "x" : 1397827.68, "y" : -356921.2 }, "selected" : false }, { "data" : { "id" : "7670", "station_name" : "浜町", "close_ymd" : "", "lon" : 139.788154, "post" : "103-0007", "e_status" : 0, "SUID" : 7670, "station_g_cd" : 9930410, "add" : "中央区日本橋浜町2-59-3", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930410", "pref_name" : "東京都", "shared_name" : "9930410", "lat" : 35.688516, "y" : -356885.16, "x" : 1397881.5399999998 }, "position" : { "x" : 1397881.5399999998, "y" : -356885.16 }, "selected" : false }, { "data" : { "id" : "3315", "station_name" : "田端", "close_ymd" : "", "lon" : 139.76122900000001, "post" : "", "e_status" : 0, "SUID" : 3315, "station_g_cd" : 1130216, "add" : "東京都北区東田端一丁目17-1", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133214", "pref_name" : "東京都", "shared_name" : "1133214", "lat" : 35.737781, "y" : -357377.81, "x" : 1397612.29 }, "position" : { "x" : 1397612.29, "y" : -357377.81 }, "selected" : false }, { "data" : { "id" : "7683", "station_name" : "荒川一中前", "close_ymd" : "", "lon" : 139.788988, "post" : "116-0003", "e_status" : 0, "SUID" : 7683, "station_g_cd" : 9930502, "add" : "荒川区南千住1-1", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930502", "pref_name" : "東京都", "shared_name" : "9930502", "lat" : 35.733659, "y" : -357336.59, "x" : 1397889.88 }, "position" : { "x" : 1397889.88, "y" : -357336.59 }, "selected" : false }, { "data" : { "id" : "3316", "station_name" : "西日暮里", "close_ymd" : "", "lon" : 139.76685700000002, "post" : "", "e_status" : 0, "SUID" : 3316, "station_g_cd" : 1130217, "add" : "東京都荒川区西日暮里五丁目22-1", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133215", "pref_name" : "東京都", "shared_name" : "1133215", "lat" : 35.731953999999995, "y" : -357319.5399999999, "x" : 1397668.57 }, "position" : { "x" : 1397668.57, "y" : -357319.5399999999 }, "selected" : false }, { "data" : { "id" : "7684", "station_name" : "荒川区役所前", "close_ymd" : "", "lon" : 139.78645600000002, "post" : "116-0002", "e_status" : 0, "SUID" : 7684, "station_g_cd" : 9930503, "add" : "荒川区荒川1", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930503", "pref_name" : "東京都", "shared_name" : "9930503", "lat" : 35.73493, "y" : -357349.3, "x" : 1397864.56 }, "position" : { "x" : 1397864.56, "y" : -357349.3 }, "selected" : false }, { "data" : { "id" : "3313", "station_name" : "王子", "close_ymd" : "", "lon" : 139.73809, "post" : "114-0002", "e_status" : 0, "SUID" : 3313, "station_g_cd" : 1133212, "add" : "北区王子1丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133212", "pref_name" : "東京都", "shared_name" : "1133212", "lat" : 35.752538, "y" : -357525.38, "x" : 1397380.9 }, "position" : { "x" : 1397380.9, "y" : -357525.38 }, "selected" : false }, { "data" : { "id" : "3314", "station_name" : "上中里", "close_ymd" : "", "lon" : 139.745769, "post" : "114-0016", "e_status" : 0, "SUID" : 3314, "station_g_cd" : 1133213, "add" : "北区上中里1丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133213", "pref_name" : "東京都", "shared_name" : "1133213", "lat" : 35.747279999999996, "y" : -357472.8, "x" : 1397457.69 }, "position" : { "x" : 1397457.69, "y" : -357472.8 }, "selected" : false }, { "data" : { "id" : "7682", "station_name" : "三ノ輪橋", "close_ymd" : "", "lon" : 139.791412, "post" : "116-0003", "e_status" : 0, "SUID" : 7682, "station_g_cd" : 9930501, "add" : "荒川区南千住1", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930501", "pref_name" : "東京都", "shared_name" : "9930501", "lat" : 35.732248, "y" : -357322.48, "x" : 1397914.12 }, "position" : { "x" : 1397914.12, "y" : -357322.48 }, "selected" : false }, { "data" : { "id" : "3311", "station_name" : "赤羽", "close_ymd" : "", "lon" : 139.72092800000001, "post" : "115-0045", "e_status" : 0, "SUID" : 3311, "station_g_cd" : 1131903, "add" : "北区赤羽1丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133210", "pref_name" : "東京都", "shared_name" : "1133210", "lat" : 35.778026000000004, "y" : -357780.26000000007, "x" : 1397209.2800000003 }, "position" : { "x" : 1397209.2800000003, "y" : -357780.26000000007 }, "selected" : false }, { "data" : { "id" : "7679", "station_name" : "瑞江", "close_ymd" : "", "lon" : 139.89761000000001, "post" : "132-0011", "e_status" : 0, "SUID" : 7679, "station_g_cd" : 9930419, "add" : "江戸川区瑞江2-2-1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930419", "pref_name" : "東京都", "shared_name" : "9930419", "lat" : 35.693318, "y" : -356933.18, "x" : 1398976.1 }, "position" : { "x" : 1398976.1, "y" : -356933.18 }, "selected" : false }, { "data" : { "id" : "3312", "station_name" : "東十条", "close_ymd" : "", "lon" : 139.72685800000002, "post" : "114-0001", "e_status" : 0, "SUID" : 3312, "station_g_cd" : 1133211, "add" : "北区東十条3丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133211", "pref_name" : "東京都", "shared_name" : "1133211", "lat" : 35.763803, "y" : -357638.03, "x" : 1397268.5800000003 }, "position" : { "x" : 1397268.5800000003, "y" : -357638.03 }, "selected" : false }, { "data" : { "id" : "7680", "station_name" : "篠崎", "close_ymd" : "", "lon" : 139.903698, "post" : "133-0061", "e_status" : 0, "SUID" : 7680, "station_g_cd" : 9930420, "add" : "江戸川区篠崎町7-27-1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930420", "pref_name" : "東京都", "shared_name" : "9930420", "lat" : 35.706016999999996, "y" : -357060.17, "x" : 1399036.98 }, "position" : { "x" : 1399036.98, "y" : -357060.17 }, "selected" : false }, { "data" : { "id" : "7677", "station_name" : "船堀", "close_ymd" : "", "lon" : 139.864258, "post" : "134-0091", "e_status" : 0, "SUID" : 7677, "station_g_cd" : 9930417, "add" : "江戸川区船堀3-6-1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930417", "pref_name" : "東京都", "shared_name" : "9930417", "lat" : 35.683795, "y" : -356837.95, "x" : 1398642.58 }, "position" : { "x" : 1398642.58, "y" : -356837.95 }, "selected" : false }, { "data" : { "id" : "7678", "station_name" : "一之江", "close_ymd" : "", "lon" : 139.882934, "post" : "134-0003", "e_status" : 0, "SUID" : 7678, "station_g_cd" : 9930418, "add" : "江戸川区春江町4-2", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930418", "pref_name" : "東京都", "shared_name" : "9930418", "lat" : 35.686054999999996, "y" : -356860.55, "x" : 1398829.34 }, "position" : { "x" : 1398829.34, "y" : -356860.55 }, "selected" : false }, { "data" : { "id" : "7692", "station_name" : "小台", "close_ymd" : "", "lon" : 139.761779, "post" : "116-0011", "e_status" : 0, "SUID" : 7692, "station_g_cd" : 9930511, "add" : "荒川区西尾久5", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930511", "pref_name" : "東京都", "shared_name" : "9930511", "lat" : 35.750578999999995, "y" : -357505.7899999999, "x" : 1397617.7899999998 }, "position" : { "x" : 1397617.7899999998, "y" : -357505.7899999999 }, "selected" : false }, { "data" : { "id" : "7691", "station_name" : "宮ノ前", "close_ymd" : "", "lon" : 139.76495500000001, "post" : "116-0012", "e_status" : 0, "SUID" : 7691, "station_g_cd" : 9930510, "add" : "荒川区東尾久5", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930510", "pref_name" : "東京都", "shared_name" : "9930510", "lat" : 35.750135, "y" : -357501.35, "x" : 1397649.55 }, "position" : { "x" : 1397649.55, "y" : -357501.35 }, "selected" : false }, { "data" : { "id" : "7690", "station_name" : "熊野前", "close_ymd" : "", "lon" : 139.769204, "post" : "116-0012", "e_status" : 0, "SUID" : 7690, "station_g_cd" : 9930509, "add" : "荒川区東尾久5", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930509", "pref_name" : "東京都", "shared_name" : "9930509", "lat" : 35.749212, "y" : -357492.12, "x" : 1397692.04 }, "position" : { "x" : 1397692.04, "y" : -357492.12 }, "selected" : false }, { "data" : { "id" : "7689", "station_name" : "東尾久三丁目", "close_ymd" : "", "lon" : 139.77438600000002, "post" : "116-0012", "e_status" : 0, "SUID" : 7689, "station_g_cd" : 9930508, "add" : "荒川区東尾久3", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930508", "pref_name" : "東京都", "shared_name" : "9930508", "lat" : 35.745398, "y" : -357453.98000000004, "x" : 1397743.86 }, "position" : { "x" : 1397743.86, "y" : -357453.98000000004 }, "selected" : false }, { "data" : { "id" : "7688", "station_name" : "町屋二丁目", "close_ymd" : "", "lon" : 139.776625, "post" : "116-0002", "e_status" : 0, "SUID" : 7688, "station_g_cd" : 9930507, "add" : "荒川区荒川6", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930507", "pref_name" : "東京都", "shared_name" : "9930507", "lat" : 35.743837, "y" : -357438.37, "x" : 1397766.25 }, "position" : { "x" : 1397766.25, "y" : -357438.37 }, "selected" : false }, { "data" : { "id" : "7687", "station_name" : "町屋駅前", "close_ymd" : "", "lon" : 139.781145, "post" : "116-0002", "e_status" : 0, "SUID" : 7687, "station_g_cd" : 2300104, "add" : "荒川区荒川7", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930506", "pref_name" : "東京都", "shared_name" : "9930506", "lat" : 35.74275, "y" : -357427.5, "x" : 1397811.4500000002 }, "position" : { "x" : 1397811.4500000002, "y" : -357427.5 }, "selected" : false }, { "data" : { "id" : "7686", "station_name" : "荒川七丁目", "close_ymd" : "", "lon" : 139.78417, "post" : "116-0002", "e_status" : 0, "SUID" : 7686, "station_g_cd" : 9930505, "add" : "荒川区荒川7", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930505", "pref_name" : "東京都", "shared_name" : "9930505", "lat" : 35.741975, "y" : -357419.74999999994, "x" : 1397841.7 }, "position" : { "x" : 1397841.7, "y" : -357419.74999999994 }, "selected" : false }, { "data" : { "id" : "7685", "station_name" : "荒川二丁目", "close_ymd" : "", "lon" : 139.784696, "post" : "116-0002", "e_status" : 0, "SUID" : 7685, "station_g_cd" : 9930504, "add" : "荒川区荒川2", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930504", "pref_name" : "東京都", "shared_name" : "9930504", "lat" : 35.738623, "y" : -357386.23, "x" : 1397846.96 }, "position" : { "x" : 1397846.96, "y" : -357386.23 }, "selected" : false }, { "data" : { "id" : "7700", "station_name" : "西ヶ原四丁目", "close_ymd" : "", "lon" : 139.732779, "post" : "", "e_status" : 0, "SUID" : 7700, "station_g_cd" : 9930519, "add" : "東京都北区西ヶ原四丁目", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930519", "pref_name" : "東京都", "shared_name" : "9930519", "lat" : 35.744501, "y" : -357445.01, "x" : 1397327.79 }, "position" : { "x" : 1397327.79, "y" : -357445.01 }, "selected" : false }, { "data" : { "id" : "7699", "station_name" : "滝野川一丁目", "close_ymd" : "", "lon" : 139.735376, "post" : "114-0023", "e_status" : 0, "SUID" : 7699, "station_g_cd" : 9930518, "add" : "北区滝野川1", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930518", "pref_name" : "東京都", "shared_name" : "9930518", "lat" : 35.747374, "y" : -357473.74, "x" : 1397353.76 }, "position" : { "x" : 1397353.76, "y" : -357473.74 }, "selected" : false }, { "data" : { "id" : "7698", "station_name" : "飛鳥山", "close_ymd" : "", "lon" : 139.737382, "post" : "114-0023", "e_status" : 0, "SUID" : 7698, "station_g_cd" : 9930517, "add" : "北区滝野川1", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930517", "pref_name" : "東京都", "shared_name" : "9930517", "lat" : 35.750248, "y" : -357502.48, "x" : 1397373.82 }, "position" : { "x" : 1397373.82, "y" : -357502.48 }, "selected" : false }, { "data" : { "id" : "7697", "station_name" : "王子駅前", "close_ymd" : "", "lon" : 139.737661, "post" : "114-0002", "e_status" : 0, "SUID" : 7697, "station_g_cd" : 1133212, "add" : "北区王子1", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930516", "pref_name" : "東京都", "shared_name" : "9930516", "lat" : 35.753199, "y" : -357531.99000000005, "x" : 1397376.61 }, "position" : { "x" : 1397376.61, "y" : -357531.99000000005 }, "selected" : false }, { "data" : { "id" : "7696", "station_name" : "栄町", "close_ymd" : "", "lon" : 139.742124, "post" : "114-0005", "e_status" : 0, "SUID" : 7696, "station_g_cd" : 9930515, "add" : "北区栄町", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930515", "pref_name" : "東京都", "shared_name" : "9930515", "lat" : 35.750909, "y" : -357509.09, "x" : 1397421.24 }, "position" : { "x" : 1397421.24, "y" : -357509.09 }, "selected" : false }, { "data" : { "id" : "7695", "station_name" : "梶原", "close_ymd" : "", "lon" : 139.747403, "post" : "114-0004", "e_status" : 0, "SUID" : 7695, "station_g_cd" : 9930514, "add" : "北区堀船3", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930514", "pref_name" : "東京都", "shared_name" : "9930514", "lat" : 35.751162, "y" : -357511.62, "x" : 1397474.03 }, "position" : { "x" : 1397474.03, "y" : -357511.62 }, "selected" : false }, { "data" : { "id" : "7694", "station_name" : "荒川車庫前", "close_ymd" : "", "lon" : 139.752617, "post" : "116-0011", "e_status" : 0, "SUID" : 7694, "station_g_cd" : 9930513, "add" : "荒川区西尾久7", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930513", "pref_name" : "東京都", "shared_name" : "9930513", "lat" : 35.750909, "y" : -357509.09, "x" : 1397526.17 }, "position" : { "x" : 1397526.17, "y" : -357509.09 }, "selected" : false }, { "data" : { "id" : "7693", "station_name" : "荒川遊園地前", "close_ymd" : "", "lon" : 139.757767, "post" : "116-0011", "e_status" : 0, "SUID" : 7693, "station_g_cd" : 9930512, "add" : "荒川区西尾久5", "line_cd" : 99305, "selected" : false, "open_ymd" : "", "name" : "9930512", "pref_name" : "東京都", "shared_name" : "9930512", "lat" : 35.750744, "y" : -357507.44, "x" : 1397577.67 }, "position" : { "x" : 1397577.67, "y" : -357507.44 }, "selected" : false }, { "data" : { "id" : "7641", "station_name" : "日比谷", "close_ymd" : "", "lon" : 139.759998, "post" : "100-0006", "e_status" : 0, "SUID" : 7641, "station_g_cd" : 2800315, "add" : "千代田区有楽町1丁目", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930308", "pref_name" : "東京都", "shared_name" : "9930308", "lat" : 35.676035999999996, "y" : -356760.36, "x" : 1397599.98 }, "position" : { "x" : 1397599.98, "y" : -356760.36 }, "selected" : false }, { "data" : { "id" : "7642", "station_name" : "大手町", "close_ymd" : "", "lon" : 139.762959, "post" : "100-0004", "e_status" : 0, "SUID" : 7642, "station_g_cd" : 2800208, "add" : "千代田区大手町1丁目", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930309", "pref_name" : "東京都", "shared_name" : "9930309", "lat" : 35.684855999999996, "y" : -356848.55999999994, "x" : 1397629.5899999999 }, "position" : { "x" : 1397629.5899999999, "y" : -356848.55999999994 }, "selected" : false }, { "data" : { "id" : "3339", "station_name" : "赤羽", "close_ymd" : "", "lon" : 139.72092800000001, "post" : "115-0045", "e_status" : 0, "SUID" : 3339, "station_g_cd" : 1131903, "add" : "北区赤羽1丁目", "line_cd" : 11333, "selected" : false, "open_ymd" : "", "name" : "1133302", "pref_name" : "東京都", "shared_name" : "1133302", "lat" : 35.778026000000004, "y" : -357780.26000000007, "x" : 1397209.2800000003 }, "position" : { "x" : 1397209.2800000003, "y" : -357780.26000000007 }, "selected" : false }, { "data" : { "id" : "7643", "station_name" : "神保町", "close_ymd" : "", "lon" : 139.75812, "post" : "101-0051", "e_status" : 0, "SUID" : 7643, "station_g_cd" : 2800807, "add" : "千代田区神田神保町2-2", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930310", "pref_name" : "東京都", "shared_name" : "9930310", "lat" : 35.695492, "y" : -356954.92000000004, "x" : 1397581.2 }, "position" : { "x" : 1397581.2, "y" : -356954.92000000004 }, "selected" : false }, { "data" : { "id" : "3340", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.71108600000002, "post" : "", "e_status" : 0, "SUID" : 3340, "station_g_cd" : 1130212, "add" : "東京都豊島区", "line_cd" : 11333, "selected" : false, "open_ymd" : "", "name" : "1133303", "pref_name" : "東京都", "shared_name" : "1133303", "lat" : 35.730256, "y" : -357302.56, "x" : 1397110.8600000003 }, "position" : { "x" : 1397110.8600000003, "y" : -357302.56 }, "selected" : false }, { "data" : { "id" : "7644", "station_name" : "水道橋", "close_ymd" : "", "lon" : 139.75516000000002, "post" : "101-0061", "e_status" : 0, "SUID" : 7644, "station_g_cd" : 1131204, "add" : "千代田区三崎町2丁目", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930311", "pref_name" : "東京都", "shared_name" : "9930311", "lat" : 35.703398, "y" : -357033.98, "x" : 1397551.6 }, "position" : { "x" : 1397551.6, "y" : -357033.98 }, "selected" : false }, { "data" : { "id" : "7637", "station_name" : "三田", "close_ymd" : "", "lon" : 139.748775, "post" : "108-0014", "e_status" : 0, "SUID" : 7637, "station_g_cd" : 9930208, "add" : "港区芝5-34-10", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930304", "pref_name" : "東京都", "shared_name" : "9930304", "lat" : 35.648179999999996, "y" : -356481.8, "x" : 1397487.75 }, "position" : { "x" : 1397487.75, "y" : -356481.8 }, "selected" : false }, { "data" : { "id" : "7638", "station_name" : "芝公園", "close_ymd" : "", "lon" : 139.749824, "post" : "105-0011", "e_status" : 0, "SUID" : 7638, "station_g_cd" : 9930305, "add" : "港区芝公園4-8-14", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930305", "pref_name" : "東京都", "shared_name" : "9930305", "lat" : 35.654074, "y" : -356540.74, "x" : 1397498.24 }, "position" : { "x" : 1397498.24, "y" : -356540.74 }, "selected" : false }, { "data" : { "id" : "7639", "station_name" : "御成門", "close_ymd" : "", "lon" : 139.75153500000002, "post" : "105-0003", "e_status" : 0, "SUID" : 7639, "station_g_cd" : 9930306, "add" : "港区西新橋3-24-6", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930306", "pref_name" : "東京都", "shared_name" : "9930306", "lat" : 35.661215000000006, "y" : -356612.1500000001, "x" : 1397515.35 }, "position" : { "x" : 1397515.35, "y" : -356612.1500000001 }, "selected" : false }, { "data" : { "id" : "7640", "station_name" : "内幸町", "close_ymd" : "", "lon" : 139.75561000000002, "post" : "100-0011", "e_status" : 0, "SUID" : 7640, "station_g_cd" : 9930307, "add" : "千代田区内幸町2-2-3", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930307", "pref_name" : "東京都", "shared_name" : "9930307", "lat" : 35.66975, "y" : -356697.5, "x" : 1397556.1 }, "position" : { "x" : 1397556.1, "y" : -356697.5 }, "selected" : false }, { "data" : { "id" : "3345", "station_name" : "西大井", "close_ymd" : "", "lon" : 139.721729, "post" : "140-0015", "e_status" : 0, "SUID" : 3345, "station_g_cd" : 1130804, "add" : "品川区西大井1丁目", "line_cd" : 11333, "selected" : false, "open_ymd" : "", "name" : "1133308", "pref_name" : "東京都", "shared_name" : "1133308", "lat" : 35.601616, "y" : -356016.16, "x" : 1397217.29 }, "position" : { "x" : 1397217.29, "y" : -356016.16 }, "selected" : false }, { "data" : { "id" : "7649", "station_name" : "西巣鴨", "close_ymd" : "", "lon" : 139.728712, "post" : "170-0001", "e_status" : 0, "SUID" : 7649, "station_g_cd" : 9930316, "add" : "豊島区西巣鴨3-25-13", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930316", "pref_name" : "東京都", "shared_name" : "9930316", "lat" : 35.743508, "y" : -357435.07999999996, "x" : 1397287.12 }, "position" : { "x" : 1397287.12, "y" : -357435.07999999996 }, "selected" : false }, { "data" : { "id" : "7650", "station_name" : "新板橋", "close_ymd" : "", "lon" : 139.720101, "post" : "173-0004", "e_status" : 0, "SUID" : 7650, "station_g_cd" : 9930317, "add" : "板橋区板橋1-53-17", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930317", "pref_name" : "東京都", "shared_name" : "9930317", "lat" : 35.748785, "y" : -357487.85, "x" : 1397201.01 }, "position" : { "x" : 1397201.01, "y" : -357487.85 }, "selected" : false }, { "data" : { "id" : "7651", "station_name" : "板橋区役所前", "close_ymd" : "", "lon" : 139.710102, "post" : "173-0004", "e_status" : 0, "SUID" : 7651, "station_g_cd" : 9930318, "add" : "板橋区板橋2-66-17", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930318", "pref_name" : "東京都", "shared_name" : "9930318", "lat" : 35.751284000000005, "y" : -357512.84, "x" : 1397101.02 }, "position" : { "x" : 1397101.02, "y" : -357512.84 }, "selected" : false }, { "data" : { "id" : "7652", "station_name" : "板橋本町", "close_ymd" : "", "lon" : 139.705535, "post" : "173-0012", "e_status" : 0, "SUID" : 7652, "station_g_cd" : 9930319, "add" : "板橋区大和町17-1", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930319", "pref_name" : "東京都", "shared_name" : "9930319", "lat" : 35.761339, "y" : -357613.39, "x" : 1397055.3499999999 }, "position" : { "x" : 1397055.3499999999, "y" : -357613.39 }, "selected" : false }, { "data" : { "id" : "3341", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.70046399999998, "post" : "", "e_status" : 0, "SUID" : 3341, "station_g_cd" : 1130208, "add" : "東京都新宿区新宿三丁目38-1", "line_cd" : 11333, "selected" : false, "open_ymd" : "", "name" : "1133304", "pref_name" : "東京都", "shared_name" : "1133304", "lat" : 35.689729, "y" : -356897.29, "x" : 1397004.64 }, "position" : { "x" : 1397004.64, "y" : -356897.29 }, "selected" : false }, { "data" : { "id" : "7645", "station_name" : "春日", "close_ymd" : "", "lon" : 139.75325, "post" : "112-0003", "e_status" : 0, "SUID" : 7645, "station_g_cd" : 9930108, "add" : "文京区春日1-16-17", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930312", "pref_name" : "東京都", "shared_name" : "9930312", "lat" : 35.709598, "y" : -357095.98, "x" : 1397532.5 }, "position" : { "x" : 1397532.5, "y" : -357095.98 }, "selected" : false }, { "data" : { "id" : "3342", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.701238, "post" : "", "e_status" : 0, "SUID" : 3342, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂一丁目1-1", "line_cd" : 11333, "selected" : false, "open_ymd" : "", "name" : "1133305", "pref_name" : "東京都", "shared_name" : "1133305", "lat" : 35.658871000000005, "y" : -356588.71, "x" : 1397012.38 }, "position" : { "x" : 1397012.38, "y" : -356588.71 }, "selected" : false }, { "data" : { "id" : "7646", "station_name" : "白山", "close_ymd" : "", "lon" : 139.752136, "post" : "112-0001", "e_status" : 0, "SUID" : 7646, "station_g_cd" : 9930313, "add" : "文京区白山5-36-10", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930313", "pref_name" : "東京都", "shared_name" : "9930313", "lat" : 35.721408000000004, "y" : -357214.08, "x" : 1397521.36 }, "position" : { "x" : 1397521.36, "y" : -357214.08 }, "selected" : false }, { "data" : { "id" : "3343", "station_name" : "恵比寿", "close_ymd" : "", "lon" : 139.71007, "post" : "", "e_status" : 0, "SUID" : 3343, "station_g_cd" : 1130204, "add" : "東京都渋谷区恵比寿南一丁目5-5", "line_cd" : 11333, "selected" : false, "open_ymd" : "", "name" : "1133306", "pref_name" : "東京都", "shared_name" : "1133306", "lat" : 35.646685, "y" : -356466.85, "x" : 1397100.7 }, "position" : { "x" : 1397100.7, "y" : -356466.85 }, "selected" : false }, { "data" : { "id" : "7647", "station_name" : "千石", "close_ymd" : "", "lon" : 139.744792, "post" : "112-0011", "e_status" : 0, "SUID" : 7647, "station_g_cd" : 9930314, "add" : "文京区千石1-29-13", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930314", "pref_name" : "東京都", "shared_name" : "9930314", "lat" : 35.727957, "y" : -357279.57, "x" : 1397447.92 }, "position" : { "x" : 1397447.92, "y" : -357279.57 }, "selected" : false }, { "data" : { "id" : "3344", "station_name" : "大崎", "close_ymd" : "", "lon" : 139.72843899999998, "post" : "", "e_status" : 0, "SUID" : 3344, "station_g_cd" : 1130201, "add" : "東京都品川区大崎一丁目21-4", "line_cd" : 11333, "selected" : false, "open_ymd" : "", "name" : "1133307", "pref_name" : "東京都", "shared_name" : "1133307", "lat" : 35.619772, "y" : -356197.72, "x" : 1397284.39 }, "position" : { "x" : 1397284.39, "y" : -356197.72 }, "selected" : false }, { "data" : { "id" : "7648", "station_name" : "巣鴨", "close_ymd" : "", "lon" : 139.738519, "post" : "", "e_status" : 0, "SUID" : 7648, "station_g_cd" : 1130214, "add" : "東京都豊島区巣鴨", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930315", "pref_name" : "東京都", "shared_name" : "9930315", "lat" : 35.733502, "y" : -357335.02, "x" : 1397385.19 }, "position" : { "x" : 1397385.19, "y" : -357335.02 }, "selected" : false }, { "data" : { "id" : "3322", "station_name" : "神田", "close_ymd" : "", "lon" : 139.77064099999998, "post" : "", "e_status" : 0, "SUID" : 3322, "station_g_cd" : 1130223, "add" : "東京都千代田区鍛冶町二丁目13-1", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133221", "pref_name" : "東京都", "shared_name" : "1133221", "lat" : 35.691173, "y" : -356911.73, "x" : 1397706.41 }, "position" : { "x" : 1397706.41, "y" : -356911.73 }, "selected" : false }, { "data" : { "id" : "7658", "station_name" : "高島平", "close_ymd" : "", "lon" : 139.661216, "post" : "175-0082", "e_status" : 0, "SUID" : 7658, "station_g_cd" : 9930325, "add" : "板橋区高島平8-2-1", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930325", "pref_name" : "東京都", "shared_name" : "9930325", "lat" : 35.789056, "y" : -357890.56, "x" : 1396612.16 }, "position" : { "x" : 1396612.16, "y" : -357890.56 }, "selected" : false }, { "data" : { "id" : "3321", "station_name" : "秋葉原", "close_ymd" : "", "lon" : 139.77328799999998, "post" : "", "e_status" : 0, "SUID" : 3321, "station_g_cd" : 1130222, "add" : "東京都千代田区外神田一丁目17-6", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133220", "pref_name" : "東京都", "shared_name" : "1133220", "lat" : 35.698619, "y" : -356986.19, "x" : 1397732.88 }, "position" : { "x" : 1397732.88, "y" : -356986.19 }, "selected" : false }, { "data" : { "id" : "7657", "station_name" : "西台", "close_ymd" : "", "lon" : 139.673971, "post" : "175-0082", "e_status" : 0, "SUID" : 7657, "station_g_cd" : 9930324, "add" : "板橋区高島平9-1-1", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930324", "pref_name" : "東京都", "shared_name" : "9930324", "lat" : 35.78699, "y" : -357869.9, "x" : 1396739.71 }, "position" : { "x" : 1396739.71, "y" : -357869.9 }, "selected" : false }, { "data" : { "id" : "3324", "station_name" : "有楽町", "close_ymd" : "", "lon" : 139.76380600000002, "post" : "", "e_status" : 0, "SUID" : 3324, "station_g_cd" : 1130225, "add" : "東京都千代田区有楽町二丁目9-17", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133223", "pref_name" : "東京都", "shared_name" : "1133223", "lat" : 35.675441, "y" : -356754.41, "x" : 1397638.06 }, "position" : { "x" : 1397638.06, "y" : -356754.41 }, "selected" : false }, { "data" : { "id" : "7660", "station_name" : "西高島平", "close_ymd" : "", "lon" : 139.64594, "post" : "175-0082", "e_status" : 0, "SUID" : 7660, "station_g_cd" : 9930327, "add" : "板橋区高島平6-1", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930327", "pref_name" : "東京都", "shared_name" : "9930327", "lat" : 35.791833000000004, "y" : -357918.33, "x" : 1396459.4 }, "position" : { "x" : 1396459.4, "y" : -357918.33 }, "selected" : false }, { "data" : { "id" : "3323", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "", "e_status" : 0, "SUID" : 3323, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133222", "pref_name" : "東京都", "shared_name" : "1133222", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "7659", "station_name" : "新高島平", "close_ymd" : "", "lon" : 139.654275, "post" : "175-0082", "e_status" : 0, "SUID" : 7659, "station_g_cd" : 9930326, "add" : "板橋区高島平7-1", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930326", "pref_name" : "東京都", "shared_name" : "9930326", "lat" : 35.790189, "y" : -357901.88999999996, "x" : 1396542.7500000002 }, "position" : { "x" : 1396542.7500000002, "y" : -357901.88999999996 }, "selected" : false }, { "data" : { "id" : "3318", "station_name" : "鶯谷", "close_ymd" : "", "lon" : 139.77801499999998, "post" : "", "e_status" : 0, "SUID" : 3318, "station_g_cd" : 1130219, "add" : "東京都台東区根岸一丁目4-1", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133217", "pref_name" : "東京都", "shared_name" : "1133217", "lat" : 35.721484000000004, "y" : -357214.84, "x" : 1397780.15 }, "position" : { "x" : 1397780.15, "y" : -357214.84 }, "selected" : false }, { "data" : { "id" : "7654", "station_name" : "志村坂上", "close_ymd" : "", "lon" : 139.69538, "post" : "174-0056", "e_status" : 0, "SUID" : 7654, "station_g_cd" : 9930321, "add" : "板橋区志村1-14-13", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930321", "pref_name" : "東京都", "shared_name" : "9930321", "lat" : 35.775725, "y" : -357757.25, "x" : 1396953.8 }, "position" : { "x" : 1396953.8, "y" : -357757.25 }, "selected" : false }, { "data" : { "id" : "3317", "station_name" : "日暮里", "close_ymd" : "", "lon" : 139.771287, "post" : "", "e_status" : 0, "SUID" : 3317, "station_g_cd" : 1130218, "add" : "東京都荒川区西日暮里二丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133216", "pref_name" : "東京都", "shared_name" : "1133216", "lat" : 35.727908, "y" : -357279.08, "x" : 1397712.87 }, "position" : { "x" : 1397712.87, "y" : -357279.08 }, "selected" : false }, { "data" : { "id" : "7653", "station_name" : "本蓮沼", "close_ymd" : "", "lon" : 139.702324, "post" : "174-0052", "e_status" : 0, "SUID" : 7653, "station_g_cd" : 9930320, "add" : "板橋区蓮沼町19-8", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930320", "pref_name" : "東京都", "shared_name" : "9930320", "lat" : 35.768782, "y" : -357687.82, "x" : 1397023.24 }, "position" : { "x" : 1397023.24, "y" : -357687.82 }, "selected" : false }, { "data" : { "id" : "3320", "station_name" : "御徒町", "close_ymd" : "", "lon" : 139.774727, "post" : "", "e_status" : 0, "SUID" : 3320, "station_g_cd" : 1130221, "add" : "東京都台東区上野五丁目27", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133219", "pref_name" : "東京都", "shared_name" : "1133219", "lat" : 35.707282, "y" : -357072.82, "x" : 1397747.27 }, "position" : { "x" : 1397747.27, "y" : -357072.82 }, "selected" : false }, { "data" : { "id" : "7656", "station_name" : "蓮根", "close_ymd" : "", "lon" : 139.678993, "post" : "174-0046", "e_status" : 0, "SUID" : 7656, "station_g_cd" : 9930323, "add" : "板橋区蓮根2-31-30", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930323", "pref_name" : "東京都", "shared_name" : "9930323", "lat" : 35.784335, "y" : -357843.35, "x" : 1396789.93 }, "position" : { "x" : 1396789.93, "y" : -357843.35 }, "selected" : false }, { "data" : { "id" : "3319", "station_name" : "上野", "close_ymd" : "", "lon" : 139.777043, "post" : "", "e_status" : 0, "SUID" : 3319, "station_g_cd" : 1130220, "add" : "東京都台東区上野七丁目1-1", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133218", "pref_name" : "東京都", "shared_name" : "1133218", "lat" : 35.71379, "y" : -357137.9, "x" : 1397770.43 }, "position" : { "x" : 1397770.43, "y" : -357137.9 }, "selected" : false }, { "data" : { "id" : "7655", "station_name" : "志村三丁目", "close_ymd" : "", "lon" : 139.68593700000002, "post" : "174-0056", "e_status" : 0, "SUID" : 7655, "station_g_cd" : 9930322, "add" : "板橋区志村3-23-1", "line_cd" : 99303, "selected" : false, "open_ymd" : "", "name" : "9930322", "pref_name" : "東京都", "shared_name" : "9930322", "lat" : 35.777390999999994, "y" : -357773.9099999999, "x" : 1396859.3700000003 }, "position" : { "x" : 1396859.3700000003, "y" : -357773.9099999999 }, "selected" : false }, { "data" : { "id" : "3330", "station_name" : "大森", "close_ymd" : "", "lon" : 139.728079, "post" : "143-0016", "e_status" : 0, "SUID" : 3330, "station_g_cd" : 1133229, "add" : "大田区大森北1丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133229", "pref_name" : "東京都", "shared_name" : "1133229", "lat" : 35.588903, "y" : -355889.03, "x" : 1397280.79 }, "position" : { "x" : 1397280.79, "y" : -355889.03 }, "selected" : false }, { "data" : { "id" : "7666", "station_name" : "神保町", "close_ymd" : "", "lon" : 139.757606, "post" : "101-0051", "e_status" : 0, "SUID" : 7666, "station_g_cd" : 2800807, "add" : "千代田区神田神保町2-2", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930406", "pref_name" : "東京都", "shared_name" : "9930406", "lat" : 35.695966, "y" : -356959.66, "x" : 1397576.06 }, "position" : { "x" : 1397576.06, "y" : -356959.66 }, "selected" : false }, { "data" : { "id" : "3329", "station_name" : "大井町", "close_ymd" : "", "lon" : 139.73485, "post" : "140-0014", "e_status" : 0, "SUID" : 3329, "station_g_cd" : 1133228, "add" : "品川区大井1丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133228", "pref_name" : "東京都", "shared_name" : "1133228", "lat" : 35.606257, "y" : -356062.57, "x" : 1397348.5 }, "position" : { "x" : 1397348.5, "y" : -356062.57 }, "selected" : false }, { "data" : { "id" : "7665", "station_name" : "九段下", "close_ymd" : "", "lon" : 139.751948, "post" : "102-0074", "e_status" : 0, "SUID" : 7665, "station_g_cd" : 2800407, "add" : "千代田区九段南1-6-1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930405", "pref_name" : "東京都", "shared_name" : "9930405", "lat" : 35.695589, "y" : -356955.88999999996, "x" : 1397519.48 }, "position" : { "x" : 1397519.48, "y" : -356955.88999999996 }, "selected" : false }, { "data" : { "id" : "7668", "station_name" : "岩本町", "close_ymd" : "", "lon" : 139.77586599999998, "post" : "101-0033", "e_status" : 0, "SUID" : 7668, "station_g_cd" : 9930408, "add" : "千代田区神田岩本町1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930408", "pref_name" : "東京都", "shared_name" : "9930408", "lat" : 35.695534, "y" : -356955.34, "x" : 1397758.6599999997 }, "position" : { "x" : 1397758.6599999997, "y" : -356955.34 }, "selected" : false }, { "data" : { "id" : "3331", "station_name" : "蒲田", "close_ymd" : "", "lon" : 139.716032, "post" : "144-0052", "e_status" : 0, "SUID" : 3331, "station_g_cd" : 1133230, "add" : "大田区蒲田5丁目", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133230", "pref_name" : "東京都", "shared_name" : "1133230", "lat" : 35.562517, "y" : -355625.17, "x" : 1397160.32 }, "position" : { "x" : 1397160.32, "y" : -355625.17 }, "selected" : false }, { "data" : { "id" : "7667", "station_name" : "小川町", "close_ymd" : "", "lon" : 139.767551, "post" : "101-0052", "e_status" : 0, "SUID" : 7667, "station_g_cd" : 2800207, "add" : "千代田区神田小川町1-6", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930407", "pref_name" : "東京都", "shared_name" : "9930407", "lat" : 35.695487, "y" : -356954.87, "x" : 1397675.51 }, "position" : { "x" : 1397675.51, "y" : -356954.87 }, "selected" : false }, { "data" : { "id" : "3326", "station_name" : "浜松町", "close_ymd" : "", "lon" : 139.757135, "post" : "", "e_status" : 0, "SUID" : 3326, "station_g_cd" : 1130227, "add" : "東京都港区海岸一丁目3-1", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133225", "pref_name" : "東京都", "shared_name" : "1133225", "lat" : 35.655390999999995, "y" : -356553.9099999999, "x" : 1397571.35 }, "position" : { "x" : 1397571.35, "y" : -356553.9099999999 }, "selected" : false }, { "data" : { "id" : "7662", "station_name" : "新宿三丁目", "close_ymd" : "", "lon" : 139.706271, "post" : "160-0022", "e_status" : 0, "SUID" : 7662, "station_g_cd" : 2800217, "add" : "新宿区新宿3-14-1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930402", "pref_name" : "東京都", "shared_name" : "9930402", "lat" : 35.690616, "y" : -356906.16, "x" : 1397062.71 }, "position" : { "x" : 1397062.71, "y" : -356906.16 }, "selected" : false }, { "data" : { "id" : "3325", "station_name" : "新橋", "close_ymd" : "", "lon" : 139.758587, "post" : "", "e_status" : 0, "SUID" : 3325, "station_g_cd" : 1130102, "add" : "東京都港区新橋二丁目17", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133224", "pref_name" : "東京都", "shared_name" : "1133224", "lat" : 35.666195, "y" : -356661.95, "x" : 1397585.87 }, "position" : { "x" : 1397585.87, "y" : -356661.95 }, "selected" : false }, { "data" : { "id" : "7661", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.698812, "post" : "", "e_status" : 0, "SUID" : 7661, "station_g_cd" : 1130208, "add" : "東京都新宿区西新宿一丁目18", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930401", "pref_name" : "東京都", "shared_name" : "9930401", "lat" : 35.68869, "y" : -356886.9, "x" : 1396988.12 }, "position" : { "x" : 1396988.12, "y" : -356886.9 }, "selected" : false }, { "data" : { "id" : "3328", "station_name" : "品川", "close_ymd" : "", "lon" : 139.738999, "post" : "", "e_status" : 0, "SUID" : 3328, "station_g_cd" : 1130103, "add" : "東京都港区高輪三丁目26-26", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133227", "pref_name" : "東京都", "shared_name" : "1133227", "lat" : 35.62876, "y" : -356287.6, "x" : 1397389.99 }, "position" : { "x" : 1397389.99, "y" : -356287.6 }, "selected" : false }, { "data" : { "id" : "7664", "station_name" : "市ヶ谷", "close_ymd" : "", "lon" : 139.735794, "post" : "162-0843", "e_status" : 0, "SUID" : 7664, "station_g_cd" : 1131206, "add" : "東京都新宿区市谷田町一丁目1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930404", "pref_name" : "東京都", "shared_name" : "9930404", "lat" : 35.692594, "y" : -356925.94, "x" : 1397357.94 }, "position" : { "x" : 1397357.94, "y" : -356925.94 }, "selected" : false }, { "data" : { "id" : "3327", "station_name" : "田町", "close_ymd" : "", "lon" : 139.747575, "post" : "", "e_status" : 0, "SUID" : 3327, "station_g_cd" : 1130228, "add" : "東京都港区芝五丁目33-36", "line_cd" : 11332, "selected" : false, "open_ymd" : "", "name" : "1133226", "pref_name" : "東京都", "shared_name" : "1133226", "lat" : 35.645736, "y" : -356457.36, "x" : 1397475.7500000002 }, "position" : { "x" : 1397475.7500000002, "y" : -356457.36 }, "selected" : false }, { "data" : { "id" : "7663", "station_name" : "曙橋", "close_ymd" : "", "lon" : 139.722881, "post" : "162-0065", "e_status" : 0, "SUID" : 7663, "station_g_cd" : 9930403, "add" : "新宿区住吉町7-1", "line_cd" : 99304, "selected" : false, "open_ymd" : "", "name" : "9930403", "pref_name" : "東京都", "shared_name" : "9930403", "lat" : 35.692402, "y" : -356924.02, "x" : 1397228.81 }, "position" : { "x" : 1397228.81, "y" : -356924.02 }, "selected" : false }, { "data" : { "id" : "5541", "station_name" : "京成上野", "close_ymd" : "", "lon" : 139.773571, "post" : "-", "e_status" : 0, "SUID" : 5541, "station_g_cd" : 2300101, "add" : "東京都台東区上野公園1-60", "line_cd" : 23006, "selected" : false, "open_ymd" : "1933-12-10", "name" : "2300601", "pref_name" : "東京都", "shared_name" : "2300601", "lat" : 35.711232, "y" : -357112.32, "x" : 1397735.71 }, "position" : { "x" : 1397735.71, "y" : -357112.32 }, "selected" : false }, { "data" : { "id" : "5542", "station_name" : "日暮里", "close_ymd" : "", "lon" : 139.771287, "post" : "-", "e_status" : 0, "SUID" : 5542, "station_g_cd" : 1130218, "add" : "東京都荒川区西日暮里二丁目19-1", "line_cd" : 23006, "selected" : false, "open_ymd" : "1931-12-19", "name" : "2300602", "pref_name" : "東京都", "shared_name" : "2300602", "lat" : 35.727908, "y" : -357279.08, "x" : 1397712.87 }, "position" : { "x" : 1397712.87, "y" : -357279.08 }, "selected" : false }, { "data" : { "id" : "5543", "station_name" : "青砥", "close_ymd" : "", "lon" : 139.856292, "post" : "-", "e_status" : 0, "SUID" : 5543, "station_g_cd" : 2300109, "add" : "東京都葛飾区青戸三丁目36番1号", "line_cd" : 23006, "selected" : false, "open_ymd" : "1928-11-01", "name" : "2300603", "pref_name" : "東京都", "shared_name" : "2300603", "lat" : 35.745883, "y" : -357458.83, "x" : 1398562.92 }, "position" : { "x" : 1398562.92, "y" : -357458.83 }, "selected" : false }, { "data" : { "id" : "5544", "station_name" : "京成高砂", "close_ymd" : "", "lon" : 139.866875, "post" : "-", "e_status" : 0, "SUID" : 5544, "station_g_cd" : 2300110, "add" : "東京都葛飾区高砂五丁目28-1", "line_cd" : 23006, "selected" : false, "open_ymd" : "", "name" : "2300604", "pref_name" : "東京都", "shared_name" : "2300604", "lat" : 35.750932, "y" : -357509.32, "x" : 1398668.75 }, "position" : { "x" : 1398668.75, "y" : -357509.32 }, "selected" : false }, { "data" : { "id" : "5552", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.69918700000002, "post" : "", "e_status" : 0, "SUID" : 5552, "station_g_cd" : 1130208, "add" : "東京都新宿区西新宿一丁目1-4", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400101", "pref_name" : "東京都", "shared_name" : "2400101", "lat" : 35.690163, "y" : -356901.63, "x" : 1396991.8700000003 }, "position" : { "x" : 1396991.8700000003, "y" : -356901.63 }, "selected" : false }, { "data" : { "id" : "5553", "station_name" : "初台", "close_ymd" : "", "lon" : 139.686354, "post" : "151-0061", "e_status" : 0, "SUID" : 5553, "station_g_cd" : 2400102, "add" : "渋谷区初台1-53-7", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400102", "pref_name" : "東京都", "shared_name" : "2400102", "lat" : 35.68123, "y" : -356812.3, "x" : 1396863.54 }, "position" : { "x" : 1396863.54, "y" : -356812.3 }, "selected" : false }, { "data" : { "id" : "5554", "station_name" : "幡ヶ谷", "close_ymd" : "", "lon" : 139.676183, "post" : "", "e_status" : 0, "SUID" : 5554, "station_g_cd" : 2400103, "add" : "東京都渋谷区幡ヶ谷一丁目", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400103", "pref_name" : "東京都", "shared_name" : "2400103", "lat" : 35.677061, "y" : -356770.61000000004, "x" : 1396761.83 }, "position" : { "x" : 1396761.83, "y" : -356770.61000000004 }, "selected" : false }, { "data" : { "id" : "5555", "station_name" : "笹塚", "close_ymd" : "", "lon" : 139.667251, "post" : "151-0073", "e_status" : 0, "SUID" : 5555, "station_g_cd" : 2400104, "add" : "渋谷区笹塚1-56-7", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400104", "pref_name" : "東京都", "shared_name" : "2400104", "lat" : 35.673758, "y" : -356737.58, "x" : 1396672.51 }, "position" : { "x" : 1396672.51, "y" : -356737.58 }, "selected" : false }, { "data" : { "id" : "5556", "station_name" : "代田橋", "close_ymd" : "", "lon" : 139.659413, "post" : "156-0041", "e_status" : 0, "SUID" : 5556, "station_g_cd" : 2400105, "add" : "世田谷区大原2-18-9", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400105", "pref_name" : "東京都", "shared_name" : "2400105", "lat" : 35.671092, "y" : -356710.92000000004, "x" : 1396594.1300000001 }, "position" : { "x" : 1396594.1300000001, "y" : -356710.92000000004 }, "selected" : false }, { "data" : { "id" : "5575", "station_name" : "府中", "close_ymd" : "", "lon" : 139.4799, "post" : "183-0023", "e_status" : 0, "SUID" : 5575, "station_g_cd" : 2400124, "add" : "府中市宮町1-1-10", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400124", "pref_name" : "東京都", "shared_name" : "2400124", "lat" : 35.672245000000004, "y" : -356722.45, "x" : 1394798.9999999998 }, "position" : { "x" : 1394798.9999999998, "y" : -356722.45 }, "selected" : false }, { "data" : { "id" : "5576", "station_name" : "分倍河原", "close_ymd" : "", "lon" : 139.468798, "post" : "183-0021", "e_status" : 0, "SUID" : 5576, "station_g_cd" : 1130321, "add" : "府中市片町2丁目", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400125", "pref_name" : "東京都", "shared_name" : "2400125", "lat" : 35.668493, "y" : -356684.93, "x" : 1394687.98 }, "position" : { "x" : 1394687.98, "y" : -356684.93 }, "selected" : false }, { "data" : { "id" : "5573", "station_name" : "多磨霊園", "close_ymd" : "", "lon" : 139.502615, "post" : "183-0015", "e_status" : 0, "SUID" : 5573, "station_g_cd" : 2400122, "add" : "府中市清水が丘3-26-11", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400122", "pref_name" : "東京都", "shared_name" : "2400122", "lat" : 35.666197, "y" : -356661.97, "x" : 1395026.15 }, "position" : { "x" : 1395026.15, "y" : -356661.97 }, "selected" : false }, { "data" : { "id" : "5574", "station_name" : "東府中", "close_ymd" : "", "lon" : 139.495257, "post" : "183-0015", "e_status" : 0, "SUID" : 5574, "station_g_cd" : 2400123, "add" : "府中市清水が丘1-8-3", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400123", "pref_name" : "東京都", "shared_name" : "2400123", "lat" : 35.668766, "y" : -356687.66, "x" : 1394952.57 }, "position" : { "x" : 1394952.57, "y" : -356687.66 }, "selected" : false }, { "data" : { "id" : "5579", "station_name" : "百草園", "close_ymd" : "", "lon" : 139.431285, "post" : "191-0033", "e_status" : 0, "SUID" : 5579, "station_g_cd" : 2400128, "add" : "日野市百草209", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400128", "pref_name" : "東京都", "shared_name" : "2400128", "lat" : 35.657362, "y" : -356573.62, "x" : 1394312.85 }, "position" : { "x" : 1394312.85, "y" : -356573.62 }, "selected" : false }, { "data" : { "id" : "5580", "station_name" : "高幡不動", "close_ymd" : "", "lon" : 139.41295300000002, "post" : "191-0031", "e_status" : 0, "SUID" : 5580, "station_g_cd" : 2400129, "add" : "日野市高幡139", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400129", "pref_name" : "東京都", "shared_name" : "2400129", "lat" : 35.662361, "y" : -356623.61, "x" : 1394129.5300000003 }, "position" : { "x" : 1394129.5300000003, "y" : -356623.61 }, "selected" : false }, { "data" : { "id" : "5577", "station_name" : "中河原", "close_ymd" : "", "lon" : 139.457602, "post" : "183-0034", "e_status" : 0, "SUID" : 5577, "station_g_cd" : 2400126, "add" : "府中市住吉町2-1-16", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400126", "pref_name" : "東京都", "shared_name" : "2400126", "lat" : 35.659549, "y" : -356595.49, "x" : 1394576.02 }, "position" : { "x" : 1394576.02, "y" : -356595.49 }, "selected" : false }, { "data" : { "id" : "5578", "station_name" : "聖蹟桜ヶ丘", "close_ymd" : "", "lon" : 139.446979, "post" : "", "e_status" : 0, "SUID" : 5578, "station_g_cd" : 2400127, "add" : "東京都多摩市関戸一丁目10-10", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400127", "pref_name" : "東京都", "shared_name" : "2400127", "lat" : 35.650814000000004, "y" : -356508.14, "x" : 1394469.79 }, "position" : { "x" : 1394469.79, "y" : -356508.14 }, "selected" : false }, { "data" : { "id" : "5583", "station_name" : "長沼", "close_ymd" : "", "lon" : 139.365849, "post" : "192-0907", "e_status" : 0, "SUID" : 5583, "station_g_cd" : 2400132, "add" : "八王子市長沼町700", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400132", "pref_name" : "東京都", "shared_name" : "2400132", "lat" : 35.642788, "y" : -356427.88, "x" : 1393658.49 }, "position" : { "x" : 1393658.49, "y" : -356427.88 }, "selected" : false }, { "data" : { "id" : "5584", "station_name" : "北野", "close_ymd" : "", "lon" : 139.354489, "post" : "192-0911", "e_status" : 0, "SUID" : 5584, "station_g_cd" : 2400133, "add" : "八王子市打越町335-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400133", "pref_name" : "東京都", "shared_name" : "2400133", "lat" : 35.644479, "y" : -356444.79, "x" : 1393544.89 }, "position" : { "x" : 1393544.89, "y" : -356444.79 }, "selected" : false }, { "data" : { "id" : "5581", "station_name" : "南平", "close_ymd" : "", "lon" : 139.392008, "post" : "191-0041", "e_status" : 0, "SUID" : 5581, "station_g_cd" : 2400130, "add" : "日野市南平6-9-31", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400130", "pref_name" : "東京都", "shared_name" : "2400130", "lat" : 35.654559000000006, "y" : -356545.5900000001, "x" : 1393920.08 }, "position" : { "x" : 1393920.08, "y" : -356545.5900000001 }, "selected" : false }, { "data" : { "id" : "5582", "station_name" : "平山城址公園", "close_ymd" : "", "lon" : 139.379926, "post" : "191-0043", "e_status" : 0, "SUID" : 5582, "station_g_cd" : 2400131, "add" : "日野市平山5-18-10", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400131", "pref_name" : "東京都", "shared_name" : "2400131", "lat" : 35.647371, "y" : -356473.71, "x" : 1393799.26 }, "position" : { "x" : 1393799.26, "y" : -356473.71 }, "selected" : false }, { "data" : { "id" : "5587", "station_name" : "京王多摩川", "close_ymd" : "", "lon" : 139.536606, "post" : "182-0025", "e_status" : 0, "SUID" : 5587, "station_g_cd" : 2400202, "add" : "調布市多摩川4-40-1", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400202", "pref_name" : "東京都", "shared_name" : "2400202", "lat" : 35.644498999999996, "y" : -356444.99, "x" : 1395366.06 }, "position" : { "x" : 1395366.06, "y" : -356444.99 }, "selected" : false }, { "data" : { "id" : "5585", "station_name" : "京王八王子", "close_ymd" : "", "lon" : 139.343851, "post" : "192-0046", "e_status" : 0, "SUID" : 5585, "station_g_cd" : 2400134, "add" : "八王子市明神町3-27-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400134", "pref_name" : "東京都", "shared_name" : "2400134", "lat" : 35.657416, "y" : -356574.16, "x" : 1393438.51 }, "position" : { "x" : 1393438.51, "y" : -356574.16 }, "selected" : false }, { "data" : { "id" : "5586", "station_name" : "調布", "close_ymd" : "", "lon" : 139.54398799999998, "post" : "182-0024", "e_status" : 0, "SUID" : 5586, "station_g_cd" : 2400118, "add" : "調布市布田4-32-1", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400201", "pref_name" : "東京都", "shared_name" : "2400201", "lat" : 35.652181, "y" : -356521.81, "x" : 1395439.88 }, "position" : { "x" : 1395439.88, "y" : -356521.81 }, "selected" : false }, { "data" : { "id" : "5560", "station_name" : "上北沢", "close_ymd" : "", "lon" : 139.62329, "post" : "156-0057", "e_status" : 0, "SUID" : 5560, "station_g_cd" : 2400109, "add" : "世田谷区上北沢4-14-3", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400109", "pref_name" : "東京都", "shared_name" : "2400109", "lat" : 35.668857, "y" : -356688.57, "x" : 1396232.9 }, "position" : { "x" : 1396232.9, "y" : -356688.57 }, "selected" : false }, { "data" : { "id" : "5559", "station_name" : "桜上水", "close_ymd" : "", "lon" : 139.63128999999998, "post" : "156-0045", "e_status" : 0, "SUID" : 5559, "station_g_cd" : 2400108, "add" : "世田谷区桜上水5-29-52", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400108", "pref_name" : "東京都", "shared_name" : "2400108", "lat" : 35.66768, "y" : -356676.8, "x" : 1396312.8999999997 }, "position" : { "x" : 1396312.8999999997, "y" : -356676.8 }, "selected" : false }, { "data" : { "id" : "5558", "station_name" : "下高井戸", "close_ymd" : "", "lon" : 139.641372, "post" : "156-0043", "e_status" : 0, "SUID" : 5558, "station_g_cd" : 2400107, "add" : "世田谷区松原3-29-17", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400107", "pref_name" : "東京都", "shared_name" : "2400107", "lat" : 35.66615, "y" : -356661.5, "x" : 1396413.72 }, "position" : { "x" : 1396413.72, "y" : -356661.5 }, "selected" : false }, { "data" : { "id" : "5557", "station_name" : "明大前", "close_ymd" : "", "lon" : 139.650352, "post" : "156-0043", "e_status" : 0, "SUID" : 5557, "station_g_cd" : 2400106, "add" : "世田谷区松原2-45-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400106", "pref_name" : "東京都", "shared_name" : "2400106", "lat" : 35.668758000000004, "y" : -356687.58, "x" : 1396503.52 }, "position" : { "x" : 1396503.52, "y" : -356687.58 }, "selected" : false }, { "data" : { "id" : "5564", "station_name" : "仙川", "close_ymd" : "", "lon" : 139.584908, "post" : "182-0002", "e_status" : 0, "SUID" : 5564, "station_g_cd" : 2400113, "add" : "調布市仙川町1-43", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400113", "pref_name" : "東京都", "shared_name" : "2400113", "lat" : 35.662257000000004, "y" : -356622.57000000007, "x" : 1395849.08 }, "position" : { "x" : 1395849.08, "y" : -356622.57000000007 }, "selected" : false }, { "data" : { "id" : "5563", "station_name" : "千歳烏山", "close_ymd" : "", "lon" : 139.60067, "post" : "157-0062", "e_status" : 0, "SUID" : 5563, "station_g_cd" : 2400112, "add" : "世田谷区南烏山6-1-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400112", "pref_name" : "東京都", "shared_name" : "2400112", "lat" : 35.667921, "y" : -356679.21, "x" : 1396006.7000000002 }, "position" : { "x" : 1396006.7000000002, "y" : -356679.21 }, "selected" : false }, { "data" : { "id" : "5562", "station_name" : "芦花公園", "close_ymd" : "", "lon" : 139.608247, "post" : "157-0062", "e_status" : 0, "SUID" : 5562, "station_g_cd" : 2400111, "add" : "世田谷区南烏山3-1-16", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400111", "pref_name" : "東京都", "shared_name" : "2400111", "lat" : 35.670479, "y" : -356704.79, "x" : 1396082.47 }, "position" : { "x" : 1396082.47, "y" : -356704.79 }, "selected" : false }, { "data" : { "id" : "5561", "station_name" : "八幡山", "close_ymd" : "", "lon" : 139.614927, "post" : "168-0074", "e_status" : 0, "SUID" : 5561, "station_g_cd" : 2400110, "add" : "杉並区上高井戸1-1-11", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400110", "pref_name" : "東京都", "shared_name" : "2400110", "lat" : 35.669982, "y" : -356699.81999999995, "x" : 1396149.27 }, "position" : { "x" : 1396149.27, "y" : -356699.81999999995 }, "selected" : false }, { "data" : { "id" : "5568", "station_name" : "布田", "close_ymd" : "", "lon" : 139.551557, "post" : "182-0022", "e_status" : 0, "SUID" : 5568, "station_g_cd" : 2400117, "add" : "調布市国領町5-67-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400117", "pref_name" : "東京都", "shared_name" : "2400117", "lat" : 35.649904, "y" : -356499.04, "x" : 1395515.57 }, "position" : { "x" : 1395515.57, "y" : -356499.04 }, "selected" : false }, { "data" : { "id" : "5567", "station_name" : "国領", "close_ymd" : "", "lon" : 139.55803600000002, "post" : "182-0022", "e_status" : 0, "SUID" : 5567, "station_g_cd" : 2400116, "add" : "調布市国領町3-18-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400116", "pref_name" : "東京都", "shared_name" : "2400116", "lat" : 35.650087, "y" : -356500.87, "x" : 1395580.36 }, "position" : { "x" : 1395580.36, "y" : -356500.87 }, "selected" : false }, { "data" : { "id" : "5566", "station_name" : "柴崎", "close_ymd" : "", "lon" : 139.56658000000002, "post" : "182-0007", "e_status" : 0, "SUID" : 5566, "station_g_cd" : 2400115, "add" : "調布市菊野台2-67-11", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400115", "pref_name" : "東京都", "shared_name" : "2400115", "lat" : 35.653997, "y" : -356539.97, "x" : 1395665.8 }, "position" : { "x" : 1395665.8, "y" : -356539.97 }, "selected" : false }, { "data" : { "id" : "5565", "station_name" : "つつじヶ丘", "close_ymd" : "", "lon" : 139.575103, "post" : "", "e_status" : 0, "SUID" : 5565, "station_g_cd" : 2400114, "add" : "東京都調布市西つつじヶ丘三丁目35-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400114", "pref_name" : "東京都", "shared_name" : "2400114", "lat" : 35.657936, "y" : -356579.36, "x" : 1395751.03 }, "position" : { "x" : 1395751.03, "y" : -356579.36 }, "selected" : false }, { "data" : { "id" : "5572", "station_name" : "武蔵野台", "close_ymd" : "", "lon" : 139.51128899999998, "post" : "183-0011", "e_status" : 0, "SUID" : 5572, "station_g_cd" : 2400121, "add" : "府中市白糸台4-18-4", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400121", "pref_name" : "東京都", "shared_name" : "2400121", "lat" : 35.664159000000005, "y" : -356641.59, "x" : 1395112.8899999997 }, "position" : { "x" : 1395112.8899999997, "y" : -356641.59 }, "selected" : false }, { "data" : { "id" : "5571", "station_name" : "飛田給", "close_ymd" : "", "lon" : 139.523666, "post" : "182-0036", "e_status" : 0, "SUID" : 5571, "station_g_cd" : 2400120, "add" : "調布市飛田給1-42-11", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400120", "pref_name" : "東京都", "shared_name" : "2400120", "lat" : 35.660121000000004, "y" : -356601.21, "x" : 1395236.66 }, "position" : { "x" : 1395236.66, "y" : -356601.21 }, "selected" : false }, { "data" : { "id" : "5570", "station_name" : "西調布", "close_ymd" : "", "lon" : 139.529822, "post" : "182-0035", "e_status" : 0, "SUID" : 5570, "station_g_cd" : 2400119, "add" : "調布市上石原1-25-17", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400119", "pref_name" : "東京都", "shared_name" : "2400119", "lat" : 35.657169, "y" : -356571.69000000006, "x" : 1395298.22 }, "position" : { "x" : 1395298.22, "y" : -356571.69000000006 }, "selected" : false }, { "data" : { "id" : "5569", "station_name" : "調布", "close_ymd" : "", "lon" : 139.54398799999998, "post" : "182-0024", "e_status" : 0, "SUID" : 5569, "station_g_cd" : 2400118, "add" : "調布市布田4-32-1", "line_cd" : 24001, "selected" : false, "open_ymd" : "", "name" : "2400118", "pref_name" : "東京都", "shared_name" : "2400118", "lat" : 35.652181, "y" : -356521.81, "x" : 1395439.88 }, "position" : { "x" : 1395439.88, "y" : -356521.81 }, "selected" : false }, { "data" : { "id" : "5609", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.700872, "post" : "-", "e_status" : 0, "SUID" : 5609, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂一丁目4-1", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400601", "pref_name" : "東京都", "shared_name" : "2400601", "lat" : 35.6587, "y" : -356587.00000000006, "x" : 1397008.72 }, "position" : { "x" : 1397008.72, "y" : -356587.00000000006 }, "selected" : false }, { "data" : { "id" : "5610", "station_name" : "神泉", "close_ymd" : "", "lon" : 139.693579, "post" : "150-0045", "e_status" : 0, "SUID" : 5610, "station_g_cd" : 2400602, "add" : "渋谷区神泉町4-6", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400602", "pref_name" : "東京都", "shared_name" : "2400602", "lat" : 35.657244, "y" : -356572.44, "x" : 1396935.79 }, "position" : { "x" : 1396935.79, "y" : -356572.44 }, "selected" : false }, { "data" : { "id" : "5611", "station_name" : "駒場東大前", "close_ymd" : "", "lon" : 139.68430800000002, "post" : "153-0041", "e_status" : 0, "SUID" : 5611, "station_g_cd" : 2400603, "add" : "目黒区駒場3-9-1", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400603", "pref_name" : "東京都", "shared_name" : "2400603", "lat" : 35.65868, "y" : -356586.8, "x" : 1396843.08 }, "position" : { "x" : 1396843.08, "y" : -356586.8 }, "selected" : false }, { "data" : { "id" : "5612", "station_name" : "池ノ上", "close_ymd" : "", "lon" : 139.67344, "post" : "155-0032", "e_status" : 0, "SUID" : 5612, "station_g_cd" : 2400104, "add" : "世田谷区代沢2-43-8", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400604", "pref_name" : "東京都", "shared_name" : "2400604", "lat" : 35.660402000000005, "y" : -356604.0200000001, "x" : 1396734.4 }, "position" : { "x" : 1396734.4, "y" : -356604.0200000001 }, "selected" : false }, { "data" : { "id" : "5605", "station_name" : "東府中", "close_ymd" : "", "lon" : 139.495257, "post" : "183-0015", "e_status" : 0, "SUID" : 5605, "station_g_cd" : 2400123, "add" : "府中市清水が丘1-8-3", "line_cd" : 24004, "selected" : false, "open_ymd" : "", "name" : "2400401", "pref_name" : "東京都", "shared_name" : "2400401", "lat" : 35.668766, "y" : -356687.66, "x" : 1394952.57 }, "position" : { "x" : 1394952.57, "y" : -356687.66 }, "selected" : false }, { "data" : { "id" : "5606", "station_name" : "府中競馬正門前", "close_ymd" : "", "lon" : 139.485019, "post" : "183-0016", "e_status" : 0, "SUID" : 5606, "station_g_cd" : 2400402, "add" : "府中市八幡町1-18", "line_cd" : 24004, "selected" : false, "open_ymd" : "", "name" : "2400402", "pref_name" : "東京都", "shared_name" : "2400402", "lat" : 35.668288000000004, "y" : -356682.88000000006, "x" : 1394850.19 }, "position" : { "x" : 1394850.19, "y" : -356682.88000000006 }, "selected" : false }, { "data" : { "id" : "5607", "station_name" : "高幡不動", "close_ymd" : "", "lon" : 139.41295300000002, "post" : "191-0031", "e_status" : 0, "SUID" : 5607, "station_g_cd" : 2400129, "add" : "日野市高幡139", "line_cd" : 24005, "selected" : false, "open_ymd" : "", "name" : "2400501", "pref_name" : "東京都", "shared_name" : "2400501", "lat" : 35.662361, "y" : -356623.61, "x" : 1394129.5300000003 }, "position" : { "x" : 1394129.5300000003, "y" : -356623.61 }, "selected" : false }, { "data" : { "id" : "5608", "station_name" : "多摩動物公園", "close_ymd" : "", "lon" : 139.404627, "post" : "191-0042", "e_status" : 0, "SUID" : 5608, "station_g_cd" : 2400502, "add" : "日野市程久保3-36-39", "line_cd" : 24005, "selected" : false, "open_ymd" : "", "name" : "2400502", "pref_name" : "東京都", "shared_name" : "2400502", "lat" : 35.649215000000005, "y" : -356492.15, "x" : 1394046.27 }, "position" : { "x" : 1394046.27, "y" : -356492.15 }, "selected" : false }, { "data" : { "id" : "5617", "station_name" : "永福町", "close_ymd" : "", "lon" : 139.64273300000002, "post" : "168-0064", "e_status" : 0, "SUID" : 5617, "station_g_cd" : 2400609, "add" : "杉並区永福2-60-31", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400609", "pref_name" : "東京都", "shared_name" : "2400609", "lat" : 35.67629, "y" : -356762.9, "x" : 1396427.3300000003 }, "position" : { "x" : 1396427.3300000003, "y" : -356762.9 }, "selected" : false }, { "data" : { "id" : "5618", "station_name" : "西永福", "close_ymd" : "", "lon" : 139.634936, "post" : "168-0064", "e_status" : 0, "SUID" : 5618, "station_g_cd" : 2400610, "add" : "杉並区永福3-36-1", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400610", "pref_name" : "東京都", "shared_name" : "2400610", "lat" : 35.678917999999996, "y" : -356789.17999999993, "x" : 1396349.36 }, "position" : { "x" : 1396349.36, "y" : -356789.17999999993 }, "selected" : false }, { "data" : { "id" : "5619", "station_name" : "浜田山", "close_ymd" : "", "lon" : 139.627528, "post" : "168-0065", "e_status" : 0, "SUID" : 5619, "station_g_cd" : 2400611, "add" : "杉並区浜田山3-31-2", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400611", "pref_name" : "東京都", "shared_name" : "2400611", "lat" : 35.681603, "y" : -356816.03, "x" : 1396275.28 }, "position" : { "x" : 1396275.28, "y" : -356816.03 }, "selected" : false }, { "data" : { "id" : "5620", "station_name" : "高井戸", "close_ymd" : "", "lon" : 139.615115, "post" : "168-0071", "e_status" : 0, "SUID" : 5620, "station_g_cd" : 2400612, "add" : "杉並区高井戸西2-1-26", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400612", "pref_name" : "東京都", "shared_name" : "2400612", "lat" : 35.683253, "y" : -356832.53, "x" : 1396151.1500000001 }, "position" : { "x" : 1396151.1500000001, "y" : -356832.53 }, "selected" : false }, { "data" : { "id" : "5613", "station_name" : "下北沢", "close_ymd" : "", "lon" : 139.66691, "post" : "155-0031", "e_status" : 0, "SUID" : 5613, "station_g_cd" : 2400605, "add" : "世田谷区北沢2丁目", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400605", "pref_name" : "東京都", "shared_name" : "2400605", "lat" : 35.661539000000005, "y" : -356615.3900000001, "x" : 1396669.1 }, "position" : { "x" : 1396669.1, "y" : -356615.3900000001 }, "selected" : false }, { "data" : { "id" : "5614", "station_name" : "新代田", "close_ymd" : "", "lon" : 139.660524, "post" : "155-0033", "e_status" : 0, "SUID" : 5614, "station_g_cd" : 2400606, "add" : "世田谷区代田5-30-18", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400606", "pref_name" : "東京都", "shared_name" : "2400606", "lat" : 35.662593, "y" : -356625.93, "x" : 1396605.24 }, "position" : { "x" : 1396605.24, "y" : -356625.93 }, "selected" : false }, { "data" : { "id" : "5615", "station_name" : "東松原", "close_ymd" : "", "lon" : 139.65553500000001, "post" : "156-0043", "e_status" : 0, "SUID" : 5615, "station_g_cd" : 2400607, "add" : "世田谷区松原5-2-6", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400607", "pref_name" : "東京都", "shared_name" : "2400607", "lat" : 35.662634000000004, "y" : -356626.34, "x" : 1396555.35 }, "position" : { "x" : 1396555.35, "y" : -356626.34 }, "selected" : false }, { "data" : { "id" : "5616", "station_name" : "明大前", "close_ymd" : "", "lon" : 139.650352, "post" : "156-0043", "e_status" : 0, "SUID" : 5616, "station_g_cd" : 2400106, "add" : "世田谷区松原2-45-1", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400608", "pref_name" : "東京都", "shared_name" : "2400608", "lat" : 35.668758000000004, "y" : -356687.58, "x" : 1396503.52 }, "position" : { "x" : 1396503.52, "y" : -356687.58 }, "selected" : false }, { "data" : { "id" : "5594", "station_name" : "京王堀之内", "close_ymd" : "", "lon" : 139.40031399999998, "post" : "192-0355", "e_status" : 0, "SUID" : 5594, "station_g_cd" : 2400209, "add" : "八王子市堀之内3-24-4", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400209", "pref_name" : "東京都", "shared_name" : "2400209", "lat" : 35.624438, "y" : -356244.38, "x" : 1394003.14 }, "position" : { "x" : 1394003.14, "y" : -356244.38 }, "selected" : false }, { "data" : { "id" : "5593", "station_name" : "京王多摩センター", "close_ymd" : "", "lon" : 139.42401999999998, "post" : "206-0033", "e_status" : 0, "SUID" : 5593, "station_g_cd" : 2400208, "add" : "多摩市落合1-10-2", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400208", "pref_name" : "東京都", "shared_name" : "2400208", "lat" : 35.62518, "y" : -356251.8, "x" : 1394240.2 }, "position" : { "x" : 1394240.2, "y" : -356251.8 }, "selected" : false }, { "data" : { "id" : "5596", "station_name" : "多摩境", "close_ymd" : "", "lon" : 139.36698700000002, "post" : "194-0212", "e_status" : 0, "SUID" : 5596, "station_g_cd" : 2400211, "add" : "町田市小山町2718-1", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400211", "pref_name" : "東京都", "shared_name" : "2400211", "lat" : 35.601826, "y" : -356018.26, "x" : 1393669.8700000003 }, "position" : { "x" : 1393669.8700000003, "y" : -356018.26 }, "selected" : false }, { "data" : { "id" : "5595", "station_name" : "南大沢", "close_ymd" : "", "lon" : 139.3798, "post" : "192-0364", "e_status" : 0, "SUID" : 5595, "station_g_cd" : 2400210, "add" : "八王子市南大沢2-1-6", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400210", "pref_name" : "東京都", "shared_name" : "2400210", "lat" : 35.6141, "y" : -356141.0, "x" : 1393798.0 }, "position" : { "x" : 1393798.0, "y" : -356141.0 }, "selected" : false }, { "data" : { "id" : "5590", "station_name" : "稲城", "close_ymd" : "", "lon" : 139.500398, "post" : "206-0802", "e_status" : 0, "SUID" : 5590, "station_g_cd" : 2400205, "add" : "稲城市東長沼3108", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400205", "pref_name" : "東京都", "shared_name" : "2400205", "lat" : 35.636165999999996, "y" : -356361.66, "x" : 1395003.98 }, "position" : { "x" : 1395003.98, "y" : -356361.66 }, "selected" : false }, { "data" : { "id" : "5589", "station_name" : "京王よみうりランド", "close_ymd" : "", "lon" : 139.517597, "post" : "", "e_status" : 0, "SUID" : 5589, "station_g_cd" : 2400204, "add" : "東京都稲城市矢野口", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400204", "pref_name" : "東京都", "shared_name" : "2400204", "lat" : 35.632934000000006, "y" : -356329.3400000001, "x" : 1395175.97 }, "position" : { "x" : 1395175.97, "y" : -356329.3400000001 }, "selected" : false }, { "data" : { "id" : "5592", "station_name" : "京王永山", "close_ymd" : "", "lon" : 139.448204, "post" : "206-0025", "e_status" : 0, "SUID" : 5592, "station_g_cd" : 2400207, "add" : "多摩市永山1-18-1", "line_cd" : 24002, "selected" : false, "open_ymd" : "", "name" : "2400207", "pref_name" : "東京都", "shared_name" : "2400207", "lat" : 35.630102, "y" : -356301.02, "x" : 1394482.04 }, "position" : { "x" : 1394482.04, "y" : -356301.02 }, "selected" : false }, { "data" : { "id" : "5602", "station_name" : "狭間", "close_ymd" : "", "lon" : 139.293808, "post" : "193-0834", "e_status" : 0, "SUID" : 5602, "station_g_cd" : 2400305, "add" : "八王子市東浅川町773", "line_cd" : 24003, "selected" : false, "open_ymd" : "", "name" : "2400305", "pref_name" : "東京都", "shared_name" : "2400305", "lat" : 35.640637, "y" : -356406.37, "x" : 1392938.08 }, "position" : { "x" : 1392938.08, "y" : -356406.37 }, "selected" : false }, { "data" : { "id" : "5601", "station_name" : "めじろ台", "close_ymd" : "", "lon" : 139.308446, "post" : "193-0833", "e_status" : 0, "SUID" : 5601, "station_g_cd" : 2400304, "add" : "八王子市めじろ台1-100-1", "line_cd" : 24003, "selected" : false, "open_ymd" : "", "name" : "2400304", "pref_name" : "東京都", "shared_name" : "2400304", "lat" : 35.643601000000004, "y" : -356436.01000000007, "x" : 1393084.46 }, "position" : { "x" : 1393084.46, "y" : -356436.01000000007 }, "selected" : false }, { "data" : { "id" : "5604", "station_name" : "高尾山口", "close_ymd" : "", "lon" : 139.269856, "post" : "193-0844", "e_status" : 0, "SUID" : 5604, "station_g_cd" : 2400307, "add" : "八王子市高尾町2241", "line_cd" : 24003, "selected" : false, "open_ymd" : "", "name" : "2400307", "pref_name" : "東京都", "shared_name" : "2400307", "lat" : 35.632377000000005, "y" : -356323.7700000001, "x" : 1392698.56 }, "position" : { "x" : 1392698.56, "y" : -356323.7700000001 }, "selected" : false }, { "data" : { "id" : "5603", "station_name" : "高尾", "close_ymd" : "", "lon" : 139.281551, "post" : "193-0844", "e_status" : 0, "SUID" : 5603, "station_g_cd" : 1131112, "add" : "八王子市高尾町", "line_cd" : 24003, "selected" : false, "open_ymd" : "", "name" : "2400306", "pref_name" : "東京都", "shared_name" : "2400306", "lat" : 35.641645000000004, "y" : -356416.45, "x" : 1392815.51 }, "position" : { "x" : 1392815.51, "y" : -356416.45 }, "selected" : false }, { "data" : { "id" : "5598", "station_name" : "北野", "close_ymd" : "", "lon" : 139.354489, "post" : "192-0911", "e_status" : 0, "SUID" : 5598, "station_g_cd" : 2400133, "add" : "八王子市打越町335-1", "line_cd" : 24003, "selected" : false, "open_ymd" : "", "name" : "2400301", "pref_name" : "東京都", "shared_name" : "2400301", "lat" : 35.644479, "y" : -356444.79, "x" : 1393544.89 }, "position" : { "x" : 1393544.89, "y" : -356444.79 }, "selected" : false }, { "data" : { "id" : "5600", "station_name" : "山田", "close_ymd" : "", "lon" : 139.32108200000002, "post" : "193-0932", "e_status" : 0, "SUID" : 5600, "station_g_cd" : 2400303, "add" : "八王子市緑町434", "line_cd" : 24003, "selected" : false, "open_ymd" : "", "name" : "2400303", "pref_name" : "東京都", "shared_name" : "2400303", "lat" : 35.644411, "y" : -356444.11, "x" : 1393210.8200000003 }, "position" : { "x" : 1393210.8200000003, "y" : -356444.11 }, "selected" : false }, { "data" : { "id" : "5599", "station_name" : "京王片倉", "close_ymd" : "", "lon" : 139.33703500000001, "post" : "192-0914", "e_status" : 0, "SUID" : 5599, "station_g_cd" : 2400302, "add" : "八王子市片倉町34-9", "line_cd" : 24003, "selected" : false, "open_ymd" : "", "name" : "2400302", "pref_name" : "東京都", "shared_name" : "2400302", "lat" : 35.644343, "y" : -356443.43, "x" : 1393370.35 }, "position" : { "x" : 1393370.35, "y" : -356443.43 }, "selected" : false }, { "data" : { "id" : "5643", "station_name" : "成城学園前", "close_ymd" : "", "lon" : 139.598958, "post" : "157-0066", "e_status" : 0, "SUID" : 5643, "station_g_cd" : 2500114, "add" : "世田谷区成城6丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500114", "pref_name" : "東京都", "shared_name" : "2500114", "lat" : 35.640114000000004, "y" : -356401.14, "x" : 1395989.58 }, "position" : { "x" : 1395989.58, "y" : -356401.14 }, "selected" : false }, { "data" : { "id" : "5644", "station_name" : "喜多見", "close_ymd" : "", "lon" : 139.587445, "post" : "157-0067", "e_status" : 0, "SUID" : 5644, "station_g_cd" : 2500115, "add" : "世田谷区喜多見9丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500115", "pref_name" : "東京都", "shared_name" : "2500115", "lat" : 35.636697, "y" : -356366.97, "x" : 1395874.45 }, "position" : { "x" : 1395874.45, "y" : -356366.97 }, "selected" : false }, { "data" : { "id" : "5641", "station_name" : "千歳船橋", "close_ymd" : "", "lon" : 139.624544, "post" : "156-0055", "e_status" : 0, "SUID" : 5641, "station_g_cd" : 2500112, "add" : "世田谷区船橋1丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500112", "pref_name" : "東京都", "shared_name" : "2500112", "lat" : 35.647616, "y" : -356476.16, "x" : 1396245.44 }, "position" : { "x" : 1396245.44, "y" : -356476.16 }, "selected" : false }, { "data" : { "id" : "5642", "station_name" : "祖師ヶ谷大蔵", "close_ymd" : "", "lon" : 139.60965900000002, "post" : "", "e_status" : 0, "SUID" : 5642, "station_g_cd" : 2500113, "add" : "東京都世田谷区祖師谷1丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500113", "pref_name" : "東京都", "shared_name" : "2500113", "lat" : 35.643236, "y" : -356432.36000000004, "x" : 1396096.5900000003 }, "position" : { "x" : 1396096.5900000003, "y" : -356432.36000000004 }, "selected" : false }, { "data" : { "id" : "5639", "station_name" : "豪徳寺", "close_ymd" : "", "lon" : 139.647381, "post" : "154-0021", "e_status" : 0, "SUID" : 5639, "station_g_cd" : 2500110, "add" : "世田谷区豪徳寺1丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500110", "pref_name" : "東京都", "shared_name" : "2500110", "lat" : 35.653807, "y" : -356538.07, "x" : 1396473.81 }, "position" : { "x" : 1396473.81, "y" : -356538.07 }, "selected" : false }, { "data" : { "id" : "5640", "station_name" : "経堂", "close_ymd" : "", "lon" : 139.63599299999998, "post" : "156-0052", "e_status" : 0, "SUID" : 5640, "station_g_cd" : 2500111, "add" : "世田谷区経堂1丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500111", "pref_name" : "東京都", "shared_name" : "2500111", "lat" : 35.650991, "y" : -356509.91, "x" : 1396359.93 }, "position" : { "x" : 1396359.93, "y" : -356509.91 }, "selected" : false }, { "data" : { "id" : "5637", "station_name" : "世田谷代田", "close_ymd" : "", "lon" : 139.66155700000002, "post" : "155-0033", "e_status" : 0, "SUID" : 5637, "station_g_cd" : 2500108, "add" : "世田谷区代田2丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500108", "pref_name" : "東京都", "shared_name" : "2500108", "lat" : 35.65834, "y" : -356583.4, "x" : 1396615.57 }, "position" : { "x" : 1396615.57, "y" : -356583.4 }, "selected" : false }, { "data" : { "id" : "5638", "station_name" : "梅ヶ丘", "close_ymd" : "", "lon" : 139.653628, "post" : "", "e_status" : 0, "SUID" : 5638, "station_g_cd" : 2500109, "add" : "東京都世田谷区梅丘", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500109", "pref_name" : "東京都", "shared_name" : "2500109", "lat" : 35.656024, "y" : -356560.24000000005, "x" : 1396536.28 }, "position" : { "x" : 1396536.28, "y" : -356560.24000000005 }, "selected" : false }, { "data" : { "id" : "5645", "station_name" : "狛江", "close_ymd" : "", "lon" : 139.577127, "post" : "201-0014", "e_status" : 0, "SUID" : 5645, "station_g_cd" : 2500116, "add" : "狛江市東和泉1丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500116", "pref_name" : "東京都", "shared_name" : "2500116", "lat" : 35.632001, "y" : -356320.01, "x" : 1395771.2699999998 }, "position" : { "x" : 1395771.2699999998, "y" : -356320.01 }, "selected" : false }, { "data" : { "id" : "5646", "station_name" : "和泉多摩川", "close_ymd" : "", "lon" : 139.573695, "post" : "201-0014", "e_status" : 0, "SUID" : 5646, "station_g_cd" : 2500117, "add" : "狛江市東和泉4丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500117", "pref_name" : "東京都", "shared_name" : "2500117", "lat" : 35.627349, "y" : -356273.49000000005, "x" : 1395736.95 }, "position" : { "x" : 1395736.95, "y" : -356273.49000000005 }, "selected" : false }, { "data" : { "id" : "5628", "station_name" : "幡ヶ谷", "close_ymd" : "", "lon" : 139.676183, "post" : "-", "e_status" : 0, "SUID" : 5628, "station_g_cd" : 2400103, "add" : "東京都渋谷区幡ヶ谷一丁目", "line_cd" : 24007, "selected" : false, "open_ymd" : "", "name" : "2400703", "pref_name" : "東京都", "shared_name" : "2400703", "lat" : 35.677061, "y" : -356770.61000000004, "x" : 1396761.83 }, "position" : { "x" : 1396761.83, "y" : -356770.61000000004 }, "selected" : false }, { "data" : { "id" : "5627", "station_name" : "初台", "close_ymd" : "", "lon" : 139.686354, "post" : "151-0061", "e_status" : 0, "SUID" : 5627, "station_g_cd" : 2400102, "add" : "渋谷区初台1-53-7", "line_cd" : 24007, "selected" : false, "open_ymd" : "", "name" : "2400702", "pref_name" : "東京都", "shared_name" : "2400702", "lat" : 35.68123, "y" : -356812.3, "x" : 1396863.54 }, "position" : { "x" : 1396863.54, "y" : -356812.3 }, "selected" : false }, { "data" : { "id" : "5626", "station_name" : "新線新宿", "close_ymd" : "", "lon" : 139.698812, "post" : "-", "e_status" : 0, "SUID" : 5626, "station_g_cd" : 1130208, "add" : "東京都新宿区西新宿一丁目18", "line_cd" : 24007, "selected" : false, "open_ymd" : "", "name" : "2400701", "pref_name" : "東京都", "shared_name" : "2400701", "lat" : 35.68869, "y" : -356886.9, "x" : 1396988.12 }, "position" : { "x" : 1396988.12, "y" : -356886.9 }, "selected" : false }, { "data" : { "id" : "5625", "station_name" : "吉祥寺", "close_ymd" : "", "lon" : 139.580306, "post" : "", "e_status" : 0, "SUID" : 5625, "station_g_cd" : 1131104, "add" : "東京都武蔵野市吉祥寺南町", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400617", "pref_name" : "東京都", "shared_name" : "2400617", "lat" : 35.702290999999995, "y" : -357022.91, "x" : 1395803.06 }, "position" : { "x" : 1395803.06, "y" : -357022.91 }, "selected" : false }, { "data" : { "id" : "5624", "station_name" : "井の頭公園", "close_ymd" : "", "lon" : 139.583112, "post" : "181-0001", "e_status" : 0, "SUID" : 5624, "station_g_cd" : 2400616, "add" : "三鷹市井の頭3-35-12", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400616", "pref_name" : "東京都", "shared_name" : "2400616", "lat" : 35.697303999999995, "y" : -356973.04, "x" : 1395831.12 }, "position" : { "x" : 1395831.12, "y" : -356973.04 }, "selected" : false }, { "data" : { "id" : "5623", "station_name" : "三鷹台", "close_ymd" : "", "lon" : 139.58929799999999, "post" : "181-0001", "e_status" : 0, "SUID" : 5623, "station_g_cd" : 2400615, "add" : "三鷹市井の頭1-32-1", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400615", "pref_name" : "東京都", "shared_name" : "2400615", "lat" : 35.692046000000005, "y" : -356920.46, "x" : 1395892.9799999997 }, "position" : { "x" : 1395892.9799999997, "y" : -356920.46 }, "selected" : false }, { "data" : { "id" : "5622", "station_name" : "久我山", "close_ymd" : "", "lon" : 139.599211, "post" : "168-0082", "e_status" : 0, "SUID" : 5622, "station_g_cd" : 2400614, "add" : "杉並区久我山4-1-11", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400614", "pref_name" : "東京都", "shared_name" : "2400614", "lat" : 35.688138, "y" : -356881.38, "x" : 1395992.1099999999 }, "position" : { "x" : 1395992.1099999999, "y" : -356881.38 }, "selected" : false }, { "data" : { "id" : "5621", "station_name" : "富士見ヶ丘", "close_ymd" : "", "lon" : 139.607072, "post" : "", "e_status" : 0, "SUID" : 5621, "station_g_cd" : 2400613, "add" : "東京都杉並区久我山五丁目1番25号", "line_cd" : 24006, "selected" : false, "open_ymd" : "", "name" : "2400613", "pref_name" : "東京都", "shared_name" : "2400613", "lat" : 35.684805, "y" : -356848.05, "x" : 1396070.72 }, "position" : { "x" : 1396070.72, "y" : -356848.05 }, "selected" : false }, { "data" : { "id" : "5636", "station_name" : "下北沢", "close_ymd" : "", "lon" : 139.66751599999998, "post" : "155-0031", "e_status" : 0, "SUID" : 5636, "station_g_cd" : 2400605, "add" : "世田谷区北沢2丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500107", "pref_name" : "東京都", "shared_name" : "2500107", "lat" : 35.661654999999996, "y" : -356616.55, "x" : 1396675.1599999997 }, "position" : { "x" : 1396675.1599999997, "y" : -356616.55 }, "selected" : false }, { "data" : { "id" : "5635", "station_name" : "東北沢", "close_ymd" : "", "lon" : 139.673014, "post" : "155-0031", "e_status" : 0, "SUID" : 5635, "station_g_cd" : 2500106, "add" : "世田谷区北沢3丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500106", "pref_name" : "東京都", "shared_name" : "2500106", "lat" : 35.665378999999994, "y" : -356653.7899999999, "x" : 1396730.14 }, "position" : { "x" : 1396730.14, "y" : -356653.7899999999 }, "selected" : false }, { "data" : { "id" : "5634", "station_name" : "代々木上原", "close_ymd" : "", "lon" : 139.680153, "post" : "151-0066", "e_status" : 0, "SUID" : 5634, "station_g_cd" : 2500105, "add" : "渋谷区西原3丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500105", "pref_name" : "東京都", "shared_name" : "2500105", "lat" : 35.669159, "y" : -356691.59, "x" : 1396801.5299999998 }, "position" : { "x" : 1396801.5299999998, "y" : -356691.59 }, "selected" : false }, { "data" : { "id" : "5633", "station_name" : "代々木八幡", "close_ymd" : "", "lon" : 139.68891299999999, "post" : "151-0053", "e_status" : 0, "SUID" : 5633, "station_g_cd" : 2500104, "add" : "渋谷区代々木5丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500104", "pref_name" : "東京都", "shared_name" : "2500104", "lat" : 35.669715000000004, "y" : -356697.15, "x" : 1396889.13 }, "position" : { "x" : 1396889.13, "y" : -356697.15 }, "selected" : false }, { "data" : { "id" : "5632", "station_name" : "参宮橋", "close_ymd" : "", "lon" : 139.693568, "post" : "151-0053", "e_status" : 0, "SUID" : 5632, "station_g_cd" : 2500103, "add" : "渋谷区代々木4丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500103", "pref_name" : "東京都", "shared_name" : "2500103", "lat" : 35.678585999999996, "y" : -356785.86, "x" : 1396935.68 }, "position" : { "x" : 1396935.68, "y" : -356785.86 }, "selected" : false }, { "data" : { "id" : "5631", "station_name" : "南新宿", "close_ymd" : "", "lon" : 139.69867, "post" : "151-0053", "e_status" : 0, "SUID" : 5631, "station_g_cd" : 2500102, "add" : "渋谷区代々木2丁目", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500102", "pref_name" : "東京都", "shared_name" : "2500102", "lat" : 35.683483, "y" : -356834.83, "x" : 1396986.7 }, "position" : { "x" : 1396986.7, "y" : -356834.83 }, "selected" : false }, { "data" : { "id" : "5630", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.699574, "post" : "", "e_status" : 0, "SUID" : 5630, "station_g_cd" : 1130208, "add" : "東京都新宿区西新宿一丁目1-3", "line_cd" : 25001, "selected" : false, "open_ymd" : "", "name" : "2500101", "pref_name" : "東京都", "shared_name" : "2500101", "lat" : 35.691435, "y" : -356914.35, "x" : 1396995.7400000002 }, "position" : { "x" : 1396995.7400000002, "y" : -356914.35 }, "selected" : false }, { "data" : { "id" : "5629", "station_name" : "笹塚", "close_ymd" : "", "lon" : 139.667251, "post" : "151-0073", "e_status" : 0, "SUID" : 5629, "station_g_cd" : 2400104, "add" : "渋谷区笹塚1-56-7", "line_cd" : 24007, "selected" : false, "open_ymd" : "", "name" : "2400704", "pref_name" : "東京都", "shared_name" : "2400704", "lat" : 35.673758, "y" : -356737.58, "x" : 1396672.51 }, "position" : { "x" : 1396672.51, "y" : -356737.58 }, "selected" : false }, { "data" : { "id" : "5422", "station_name" : "都立家政", "close_ymd" : "", "lon" : 139.644839, "post" : "165-0032", "e_status" : 0, "SUID" : 5422, "station_g_cd" : 2200708, "add" : "中野区鷺宮1-16-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200708", "pref_name" : "東京都", "shared_name" : "2200708", "lat" : 35.722313, "y" : -357223.13, "x" : 1396448.39 }, "position" : { "x" : 1396448.39, "y" : -357223.13 }, "selected" : false }, { "data" : { "id" : "5421", "station_name" : "野方", "close_ymd" : "", "lon" : 139.652733, "post" : "165-0027", "e_status" : 0, "SUID" : 5421, "station_g_cd" : 2200707, "add" : "中野区野方6-3-3", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200707", "pref_name" : "東京都", "shared_name" : "2200707", "lat" : 35.719658, "y" : -357196.58, "x" : 1396527.33 }, "position" : { "x" : 1396527.33, "y" : -357196.58 }, "selected" : false }, { "data" : { "id" : "5424", "station_name" : "下井草", "close_ymd" : "", "lon" : 139.624688, "post" : "167-0022", "e_status" : 0, "SUID" : 5424, "station_g_cd" : 2200710, "add" : "杉並区下井草2-44-10", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200710", "pref_name" : "東京都", "shared_name" : "2200710", "lat" : 35.723852, "y" : -357238.52, "x" : 1396246.88 }, "position" : { "x" : 1396246.88, "y" : -357238.52 }, "selected" : false }, { "data" : { "id" : "5423", "station_name" : "鷺ノ宮", "close_ymd" : "", "lon" : 139.63891999999998, "post" : "165-0032", "e_status" : 0, "SUID" : 5423, "station_g_cd" : 2200709, "add" : "中野区鷺宮3-15-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200709", "pref_name" : "東京都", "shared_name" : "2200709", "lat" : 35.722605, "y" : -357226.05, "x" : 1396389.2 }, "position" : { "x" : 1396389.2, "y" : -357226.05 }, "selected" : false }, { "data" : { "id" : "5426", "station_name" : "上井草", "close_ymd" : "", "lon" : 139.602937, "post" : "167-0023", "e_status" : 0, "SUID" : 5426, "station_g_cd" : 2200712, "add" : "杉並区上井草3-32-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200712", "pref_name" : "東京都", "shared_name" : "2200712", "lat" : 35.725326, "y" : -357253.26, "x" : 1396029.3699999999 }, "position" : { "x" : 1396029.3699999999, "y" : -357253.26 }, "selected" : false }, { "data" : { "id" : "5425", "station_name" : "井荻", "close_ymd" : "", "lon" : 139.615303, "post" : "167-0022", "e_status" : 0, "SUID" : 5425, "station_g_cd" : 2200711, "add" : "杉並区下井草5-23-15", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200711", "pref_name" : "東京都", "shared_name" : "2200711", "lat" : 35.72469, "y" : -357246.9, "x" : 1396153.03 }, "position" : { "x" : 1396153.03, "y" : -357246.9 }, "selected" : false }, { "data" : { "id" : "5428", "station_name" : "武蔵関", "close_ymd" : "", "lon" : 139.576417, "post" : "177-0051", "e_status" : 0, "SUID" : 5428, "station_g_cd" : 2200714, "add" : "練馬区関町北2-29-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200714", "pref_name" : "東京都", "shared_name" : "2200714", "lat" : 35.7276, "y" : -357276.0, "x" : 1395764.17 }, "position" : { "x" : 1395764.17, "y" : -357276.0 }, "selected" : false }, { "data" : { "id" : "5427", "station_name" : "上石神井", "close_ymd" : "", "lon" : 139.592266, "post" : "177-0044", "e_status" : 0, "SUID" : 5427, "station_g_cd" : 2200713, "add" : "練馬区上石神井1-2-45", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200713", "pref_name" : "東京都", "shared_name" : "2200713", "lat" : 35.726189, "y" : -357261.88999999996, "x" : 1395922.66 }, "position" : { "x" : 1395922.66, "y" : -357261.88999999996 }, "selected" : false }, { "data" : { "id" : "5416", "station_name" : "高田馬場", "close_ymd" : "", "lon" : 139.703715, "post" : "169-0075", "e_status" : 0, "SUID" : 5416, "station_g_cd" : 1130210, "add" : "東京都新宿区高田馬場一丁目35-2", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200702", "pref_name" : "東京都", "shared_name" : "2200702", "lat" : 35.712677, "y" : -357126.77, "x" : 1397037.15 }, "position" : { "x" : 1397037.15, "y" : -357126.77 }, "selected" : false }, { "data" : { "id" : "5415", "station_name" : "西武新宿", "close_ymd" : "", "lon" : 139.7, "post" : "160-0021", "e_status" : 0, "SUID" : 5415, "station_g_cd" : 2200701, "add" : "新宿区歌舞伎町1-30-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200701", "pref_name" : "東京都", "shared_name" : "2200701", "lat" : 35.696253999999996, "y" : -356962.54, "x" : 1397000.0 }, "position" : { "x" : 1397000.0, "y" : -356962.54 }, "selected" : false }, { "data" : { "id" : "5418", "station_name" : "中井", "close_ymd" : "", "lon" : 139.68696699999998, "post" : "161-0032", "e_status" : 0, "SUID" : 5418, "station_g_cd" : 2200704, "add" : "新宿区中落合1-19-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200704", "pref_name" : "東京都", "shared_name" : "2200704", "lat" : 35.715106, "y" : -357151.06, "x" : 1396869.67 }, "position" : { "x" : 1396869.67, "y" : -357151.06 }, "selected" : false }, { "data" : { "id" : "5417", "station_name" : "下落合", "close_ymd" : "", "lon" : 139.695391, "post" : "161-0033", "e_status" : 0, "SUID" : 5417, "station_g_cd" : 2200703, "add" : "新宿区下落合1-16-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200703", "pref_name" : "東京都", "shared_name" : "2200703", "lat" : 35.715846, "y" : -357158.45999999996, "x" : 1396953.91 }, "position" : { "x" : 1396953.91, "y" : -357158.45999999996 }, "selected" : false }, { "data" : { "id" : "5420", "station_name" : "沼袋", "close_ymd" : "", "lon" : 139.663841, "post" : "165-0025", "e_status" : 0, "SUID" : 5420, "station_g_cd" : 2200706, "add" : "中野区沼袋1-35-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200706", "pref_name" : "東京都", "shared_name" : "2200706", "lat" : 35.719458, "y" : -357194.58, "x" : 1396638.41 }, "position" : { "x" : 1396638.41, "y" : -357194.58 }, "selected" : false }, { "data" : { "id" : "5419", "station_name" : "新井薬師前", "close_ymd" : "", "lon" : 139.672582, "post" : "164-0002", "e_status" : 0, "SUID" : 5419, "station_g_cd" : 2200705, "add" : "中野区上高田5-43-20", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200705", "pref_name" : "東京都", "shared_name" : "2200705", "lat" : 35.715778, "y" : -357157.78, "x" : 1396725.82 }, "position" : { "x" : 1396725.82, "y" : -357157.78 }, "selected" : false }, { "data" : { "id" : "5405", "station_name" : "新桜台", "close_ymd" : "", "lon" : 139.6683, "post" : "176-0002", "e_status" : 0, "SUID" : 5405, "station_g_cd" : 2200302, "add" : "練馬区桜台1-28-11", "line_cd" : 22003, "selected" : false, "open_ymd" : "", "name" : "2200302", "pref_name" : "東京都", "shared_name" : "2200302", "lat" : 35.74077, "y" : -357407.69999999995, "x" : 1396682.9999999998 }, "position" : { "x" : 1396682.9999999998, "y" : -357407.69999999995 }, "selected" : false }, { "data" : { "id" : "5406", "station_name" : "練馬", "close_ymd" : "", "lon" : 139.654368, "post" : "176-0001", "e_status" : 0, "SUID" : 5406, "station_g_cd" : 2200106, "add" : "練馬区練馬1-3-5", "line_cd" : 22003, "selected" : false, "open_ymd" : "", "name" : "2200303", "pref_name" : "東京都", "shared_name" : "2200303", "lat" : 35.737893, "y" : -357378.93, "x" : 1396543.6800000002 }, "position" : { "x" : 1396543.6800000002, "y" : -357378.93 }, "selected" : false }, { "data" : { "id" : "5407", "station_name" : "練馬", "close_ymd" : "", "lon" : 139.654368, "post" : "176-0001", "e_status" : 0, "SUID" : 5407, "station_g_cd" : 2200106, "add" : "練馬区練馬1-3-5", "line_cd" : 22004, "selected" : false, "open_ymd" : "", "name" : "2200401", "pref_name" : "東京都", "shared_name" : "2200401", "lat" : 35.737893, "y" : -357378.93, "x" : 1396543.6800000002 }, "position" : { "x" : 1396543.6800000002, "y" : -357378.93 }, "selected" : false }, { "data" : { "id" : "5408", "station_name" : "豊島園", "close_ymd" : "", "lon" : 139.647979, "post" : "176-0001", "e_status" : 0, "SUID" : 5408, "station_g_cd" : 2200402, "add" : "練馬区練馬4-16-5", "line_cd" : 22004, "selected" : false, "open_ymd" : "", "name" : "2200402", "pref_name" : "東京都", "shared_name" : "2200402", "lat" : 35.742053999999996, "y" : -357420.54, "x" : 1396479.79 }, "position" : { "x" : 1396479.79, "y" : -357420.54 }, "selected" : false }, { "data" : { "id" : "5412", "station_name" : "西武遊園地", "close_ymd" : "", "lon" : 139.442747, "post" : "189-0026", "e_status" : 0, "SUID" : 5412, "station_g_cd" : 2200601, "add" : "東村山市多摩湖町3-15-18", "line_cd" : 22006, "selected" : false, "open_ymd" : "", "name" : "2200601", "pref_name" : "東京都", "shared_name" : "2200601", "lat" : 35.765881, "y" : -357658.81, "x" : 1394427.47 }, "position" : { "x" : 1394427.47, "y" : -357658.81 }, "selected" : false }, { "data" : { "id" : "5404", "station_name" : "小竹向原", "close_ymd" : "", "lon" : 139.678572, "post" : "176-0004", "e_status" : 0, "SUID" : 5404, "station_g_cd" : 2200301, "add" : "東京都練馬区小竹町二丁目16-15", "line_cd" : 22003, "selected" : false, "open_ymd" : "", "name" : "2200301", "pref_name" : "東京都", "shared_name" : "2200301", "lat" : 35.743803, "y" : -357438.02999999997, "x" : 1396785.72 }, "position" : { "x" : 1396785.72, "y" : -357438.02999999997 }, "selected" : false }, { "data" : { "id" : "5456", "station_name" : "鷹の台", "close_ymd" : "", "lon" : 139.461155, "post" : "187-0024", "e_status" : 0, "SUID" : 5456, "station_g_cd" : 2201003, "add" : "小平市たかの台45-4", "line_cd" : 22010, "selected" : false, "open_ymd" : "", "name" : "2201003", "pref_name" : "東京都", "shared_name" : "2201003", "lat" : 35.723096999999996, "y" : -357230.97, "x" : 1394611.5499999998 }, "position" : { "x" : 1394611.5499999998, "y" : -357230.97 }, "selected" : false }, { "data" : { "id" : "5455", "station_name" : "恋ヶ窪", "close_ymd" : "", "lon" : 139.463944, "post" : "", "e_status" : 0, "SUID" : 5455, "station_g_cd" : 2201002, "add" : "東京都国分寺市戸倉一丁目1-4", "line_cd" : 22010, "selected" : false, "open_ymd" : "", "name" : "2201002", "pref_name" : "東京都", "shared_name" : "2201002", "lat" : 35.711385, "y" : -357113.85, "x" : 1394639.44 }, "position" : { "x" : 1394639.44, "y" : -357113.85 }, "selected" : false }, { "data" : { "id" : "5454", "station_name" : "国分寺", "close_ymd" : "", "lon" : 139.480841, "post" : "", "e_status" : 0, "SUID" : 5454, "station_g_cd" : 1131106, "add" : "東京都国分寺市本町二丁目1-23", "line_cd" : 22010, "selected" : false, "open_ymd" : "", "name" : "2201001", "pref_name" : "東京都", "shared_name" : "2201001", "lat" : 35.700123, "y" : -357001.23, "x" : 1394808.41 }, "position" : { "x" : 1394808.41, "y" : -357001.23 }, "selected" : false }, { "data" : { "id" : "5453", "station_name" : "西武園", "close_ymd" : "", "lon" : 139.448904, "post" : "189-0026", "e_status" : 0, "SUID" : 5453, "station_g_cd" : 2200902, "add" : "東村山市多摩湖町4-29-1", "line_cd" : 22009, "selected" : false, "open_ymd" : "", "name" : "2200902", "pref_name" : "東京都", "shared_name" : "2200902", "lat" : 35.767684, "y" : -357676.84, "x" : 1394489.04 }, "position" : { "x" : 1394489.04, "y" : -357676.84 }, "selected" : false }, { "data" : { "id" : "5460", "station_name" : "一橋学園", "close_ymd" : "", "lon" : 139.48003899999998, "post" : "187-0045", "e_status" : 0, "SUID" : 5460, "station_g_cd" : 2201102, "add" : "小平市学園西町2-1-1", "line_cd" : 22011, "selected" : false, "open_ymd" : "", "name" : "2201102", "pref_name" : "東京都", "shared_name" : "2201102", "lat" : 35.72217, "y" : -357221.7, "x" : 1394800.3899999997 }, "position" : { "x" : 1394800.3899999997, "y" : -357221.7 }, "selected" : false }, { "data" : { "id" : "5459", "station_name" : "国分寺", "close_ymd" : "", "lon" : 139.479547, "post" : "", "e_status" : 0, "SUID" : 5459, "station_g_cd" : 1131106, "add" : "東京都国分寺市本町二丁目1-23", "line_cd" : 22011, "selected" : false, "open_ymd" : "", "name" : "2201101", "pref_name" : "東京都", "shared_name" : "2201101", "lat" : 35.700835999999995, "y" : -357008.3599999999, "x" : 1394795.47 }, "position" : { "x" : 1394795.47, "y" : -357008.3599999999 }, "selected" : false }, { "data" : { "id" : "5458", "station_name" : "東村山", "close_ymd" : "", "lon" : 139.465839, "post" : "189-0014", "e_status" : 0, "SUID" : 5458, "station_g_cd" : 2200721, "add" : "東村山市本町2-3-32", "line_cd" : 22010, "selected" : false, "open_ymd" : "", "name" : "2201005", "pref_name" : "東京都", "shared_name" : "2201005", "lat" : 35.760059999999996, "y" : -357600.6, "x" : 1394658.39 }, "position" : { "x" : 1394658.39, "y" : -357600.6 }, "selected" : false }, { "data" : { "id" : "5457", "station_name" : "小川", "close_ymd" : "", "lon" : 139.463493, "post" : "187-0031", "e_status" : 0, "SUID" : 5457, "station_g_cd" : 2200803, "add" : "小平市小川東町1-20-1", "line_cd" : 22010, "selected" : false, "open_ymd" : "", "name" : "2201004", "pref_name" : "東京都", "shared_name" : "2201004", "lat" : 35.737573, "y" : -357375.73, "x" : 1394634.93 }, "position" : { "x" : 1394634.93, "y" : -357375.73 }, "selected" : false }, { "data" : { "id" : "5448", "station_name" : "玉川上水", "close_ymd" : "", "lon" : 139.41843500000002, "post" : "190-0002", "e_status" : 0, "SUID" : 5448, "station_g_cd" : 2200805, "add" : "立川市幸町6-36-1", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200805", "pref_name" : "東京都", "shared_name" : "2200805", "lat" : 35.731751, "y" : -357317.51, "x" : 1394184.35 }, "position" : { "x" : 1394184.35, "y" : -357317.51 }, "selected" : false }, { "data" : { "id" : "5447", "station_name" : "東大和市", "close_ymd" : "", "lon" : 139.434249, "post" : "207-0022", "e_status" : 0, "SUID" : 5447, "station_g_cd" : 2200804, "add" : "東大和市桜が丘1-1415-1", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200804", "pref_name" : "東京都", "shared_name" : "2200804", "lat" : 35.732828999999995, "y" : -357328.29, "x" : 1394342.49 }, "position" : { "x" : 1394342.49, "y" : -357328.29 }, "selected" : false }, { "data" : { "id" : "5446", "station_name" : "小川", "close_ymd" : "", "lon" : 139.463493, "post" : "187-0031", "e_status" : 0, "SUID" : 5446, "station_g_cd" : 2200803, "add" : "小平市小川東町1-20-1", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200803", "pref_name" : "東京都", "shared_name" : "2200803", "lat" : 35.737573, "y" : -357375.73, "x" : 1394634.93 }, "position" : { "x" : 1394634.93, "y" : -357375.73 }, "selected" : false }, { "data" : { "id" : "5445", "station_name" : "萩山", "close_ymd" : "", "lon" : 139.476903, "post" : "189-0012", "e_status" : 0, "SUID" : 5445, "station_g_cd" : 2200802, "add" : "東村山市萩山町2-1-1", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200802", "pref_name" : "東京都", "shared_name" : "2200802", "lat" : 35.740759000000004, "y" : -357407.59, "x" : 1394769.03 }, "position" : { "x" : 1394769.03, "y" : -357407.59 }, "selected" : false }, { "data" : { "id" : "5452", "station_name" : "東村山", "close_ymd" : "", "lon" : 139.465839, "post" : "189-0014", "e_status" : 0, "SUID" : 5452, "station_g_cd" : 2200721, "add" : "東村山市本町2-3-32", "line_cd" : 22009, "selected" : false, "open_ymd" : "", "name" : "2200901", "pref_name" : "東京都", "shared_name" : "2200901", "lat" : 35.760059999999996, "y" : -357600.6, "x" : 1394658.39 }, "position" : { "x" : 1394658.39, "y" : -357600.6 }, "selected" : false }, { "data" : { "id" : "5451", "station_name" : "拝島", "close_ymd" : "", "lon" : 139.343468, "post" : "196-0003", "e_status" : 0, "SUID" : 5451, "station_g_cd" : 1131506, "add" : "昭島市松原町4丁目", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200808", "pref_name" : "東京都", "shared_name" : "2200808", "lat" : 35.721278000000005, "y" : -357212.78, "x" : 1393434.68 }, "position" : { "x" : 1393434.68, "y" : -357212.78 }, "selected" : false }, { "data" : { "id" : "5450", "station_name" : "西武立川", "close_ymd" : "", "lon" : 139.370124, "post" : "190-0034", "e_status" : 0, "SUID" : 5450, "station_g_cd" : 2200807, "add" : "立川市西砂町1-21-2", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200807", "pref_name" : "東京都", "shared_name" : "2200807", "lat" : 35.7262, "y" : -357262.0, "x" : 1393701.24 }, "position" : { "x" : 1393701.24, "y" : -357262.0 }, "selected" : false }, { "data" : { "id" : "5449", "station_name" : "武蔵砂川", "close_ymd" : "", "lon" : 139.392319, "post" : "190-0032", "e_status" : 0, "SUID" : 5449, "station_g_cd" : 2200806, "add" : "立川市上砂町5-44-4", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200806", "pref_name" : "東京都", "shared_name" : "2200806", "lat" : 35.728876, "y" : -357288.76, "x" : 1393923.19 }, "position" : { "x" : 1393923.19, "y" : -357288.76 }, "selected" : false }, { "data" : { "id" : "5444", "station_name" : "小平", "close_ymd" : "", "lon" : 139.48849099999998, "post" : "187-0041", "e_status" : 0, "SUID" : 5444, "station_g_cd" : 2200719, "add" : "小平市美園町1-34-1", "line_cd" : 22008, "selected" : false, "open_ymd" : "", "name" : "2200801", "pref_name" : "東京都", "shared_name" : "2200801", "lat" : 35.736963, "y" : -357369.63, "x" : 1394884.91 }, "position" : { "x" : 1394884.91, "y" : -357369.63 }, "selected" : false }, { "data" : { "id" : "5431", "station_name" : "田無", "close_ymd" : "", "lon" : 139.53925900000002, "post" : "188-0011", "e_status" : 0, "SUID" : 5431, "station_g_cd" : 2200717, "add" : "西東京市田無町4-1-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200717", "pref_name" : "東京都", "shared_name" : "2200717", "lat" : 35.727307, "y" : -357273.07, "x" : 1395392.59 }, "position" : { "x" : 1395392.59, "y" : -357273.07 }, "selected" : false }, { "data" : { "id" : "5432", "station_name" : "花小金井", "close_ymd" : "", "lon" : 139.513228, "post" : "187-0002", "e_status" : 0, "SUID" : 5432, "station_g_cd" : 2200718, "add" : "小平市花小金井1-10-5", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200718", "pref_name" : "東京都", "shared_name" : "2200718", "lat" : 35.726129, "y" : -357261.29, "x" : 1395132.28 }, "position" : { "x" : 1395132.28, "y" : -357261.29 }, "selected" : false }, { "data" : { "id" : "5429", "station_name" : "東伏見", "close_ymd" : "", "lon" : 139.56352900000002, "post" : "202-0021", "e_status" : 0, "SUID" : 5429, "station_g_cd" : 2200715, "add" : "西東京市東伏見2-5-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200715", "pref_name" : "東京都", "shared_name" : "2200715", "lat" : 35.728761, "y" : -357287.61, "x" : 1395635.2900000003 }, "position" : { "x" : 1395635.2900000003, "y" : -357287.61 }, "selected" : false }, { "data" : { "id" : "5430", "station_name" : "西武柳沢", "close_ymd" : "", "lon" : 139.552477, "post" : "202-0015", "e_status" : 0, "SUID" : 5430, "station_g_cd" : 2200716, "add" : "西東京市保谷町3-11-24", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200716", "pref_name" : "東京都", "shared_name" : "2200716", "lat" : 35.728621000000004, "y" : -357286.21, "x" : 1395524.77 }, "position" : { "x" : 1395524.77, "y" : -357286.21 }, "selected" : false }, { "data" : { "id" : "5435", "station_name" : "東村山", "close_ymd" : "", "lon" : 139.465839, "post" : "189-0014", "e_status" : 0, "SUID" : 5435, "station_g_cd" : 2200721, "add" : "東村山市本町2-3-32", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200721", "pref_name" : "東京都", "shared_name" : "2200721", "lat" : 35.760059999999996, "y" : -357600.6, "x" : 1394658.39 }, "position" : { "x" : 1394658.39, "y" : -357600.6 }, "selected" : false }, { "data" : { "id" : "5433", "station_name" : "小平", "close_ymd" : "", "lon" : 139.48849099999998, "post" : "187-0041", "e_status" : 0, "SUID" : 5433, "station_g_cd" : 2200719, "add" : "小平市美園町1-34-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200719", "pref_name" : "東京都", "shared_name" : "2200719", "lat" : 35.736963, "y" : -357369.63, "x" : 1394884.91 }, "position" : { "x" : 1394884.91, "y" : -357369.63 }, "selected" : false }, { "data" : { "id" : "5434", "station_name" : "久米川", "close_ymd" : "", "lon" : 139.472653, "post" : "189-0013", "e_status" : 0, "SUID" : 5434, "station_g_cd" : 2200720, "add" : "東村山市栄町2-3-1", "line_cd" : 22007, "selected" : false, "open_ymd" : "", "name" : "2200720", "pref_name" : "東京都", "shared_name" : "2200720", "lat" : 35.749575, "y" : -357495.75, "x" : 1394726.53 }, "position" : { "x" : 1394726.53, "y" : -357495.75 }, "selected" : false }, { "data" : { "id" : "5482", "station_name" : "京成小岩", "close_ymd" : "", "lon" : 139.88371, "post" : "133-0051", "e_status" : 0, "SUID" : 5482, "station_g_cd" : 2300111, "add" : "江戸川区北小岩2-10-9", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300111", "pref_name" : "東京都", "shared_name" : "2300111", "lat" : 35.742158, "y" : -357421.58, "x" : 1398837.1 }, "position" : { "x" : 1398837.1, "y" : -357421.58 }, "selected" : false }, { "data" : { "id" : "5481", "station_name" : "京成高砂", "close_ymd" : "", "lon" : 139.866875, "post" : "", "e_status" : 0, "SUID" : 5481, "station_g_cd" : 2300110, "add" : "東京都葛飾区高砂五丁目28-1", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300110", "pref_name" : "東京都", "shared_name" : "2300110", "lat" : 35.750932, "y" : -357509.32, "x" : 1398668.75 }, "position" : { "x" : 1398668.75, "y" : -357509.32 }, "selected" : false }, { "data" : { "id" : "5483", "station_name" : "江戸川", "close_ymd" : "", "lon" : 139.896226, "post" : "133-0051", "e_status" : 0, "SUID" : 5483, "station_g_cd" : 2300112, "add" : "江戸川区北小岩3-24-15", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300112", "pref_name" : "東京都", "shared_name" : "2300112", "lat" : 35.737722999999995, "y" : -357377.23, "x" : 1398962.2600000002 }, "position" : { "x" : 1398962.2600000002, "y" : -357377.23 }, "selected" : false }, { "data" : { "id" : "5478", "station_name" : "堀切菖蒲園", "close_ymd" : "", "lon" : 139.827545, "post" : "124-0006", "e_status" : 0, "SUID" : 5478, "station_g_cd" : 2300107, "add" : "葛飾区堀切5-1-1", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300107", "pref_name" : "東京都", "shared_name" : "2300107", "lat" : 35.747648999999996, "y" : -357476.48999999993, "x" : 1398275.45 }, "position" : { "x" : 1398275.45, "y" : -357476.48999999993 }, "selected" : false }, { "data" : { "id" : "5477", "station_name" : "京成関屋", "close_ymd" : "", "lon" : 139.81183000000001, "post" : "120-0023", "e_status" : 0, "SUID" : 5477, "station_g_cd" : 2100208, "add" : "足立区千住曙町2-2", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300106", "pref_name" : "東京都", "shared_name" : "2300106", "lat" : 35.744008, "y" : -357440.08, "x" : 1398118.3 }, "position" : { "x" : 1398118.3, "y" : -357440.08 }, "selected" : false }, { "data" : { "id" : "5480", "station_name" : "青砥", "close_ymd" : "", "lon" : 139.856292, "post" : "", "e_status" : 0, "SUID" : 5480, "station_g_cd" : 2300109, "add" : "東京都葛飾区青戸三丁目36番1号", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300109", "pref_name" : "東京都", "shared_name" : "2300109", "lat" : 35.745883, "y" : -357458.83, "x" : 1398562.92 }, "position" : { "x" : 1398562.92, "y" : -357458.83 }, "selected" : false }, { "data" : { "id" : "5479", "station_name" : "お花茶屋", "close_ymd" : "", "lon" : 139.83988, "post" : "124-0005", "e_status" : 0, "SUID" : 5479, "station_g_cd" : 2300108, "add" : "葛飾区宝町2-37-1", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300108", "pref_name" : "東京都", "shared_name" : "2300108", "lat" : 35.747585, "y" : -357475.85000000003, "x" : 1398398.8 }, "position" : { "x" : 1398398.8, "y" : -357475.85000000003 }, "selected" : false }, { "data" : { "id" : "5473", "station_name" : "日暮里", "close_ymd" : "", "lon" : 139.771287, "post" : "", "e_status" : 0, "SUID" : 5473, "station_g_cd" : 1130218, "add" : "東京都荒川区西日暮里二丁目", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300102", "pref_name" : "東京都", "shared_name" : "2300102", "lat" : 35.727908, "y" : -357279.08, "x" : 1397712.87 }, "position" : { "x" : 1397712.87, "y" : -357279.08 }, "selected" : false }, { "data" : { "id" : "5474", "station_name" : "新三河島", "close_ymd" : "", "lon" : 139.77383400000002, "post" : "116-0013", "e_status" : 0, "SUID" : 5474, "station_g_cd" : 2300103, "add" : "荒川区西日暮里6-2-1", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300103", "pref_name" : "東京都", "shared_name" : "2300103", "lat" : 35.737140000000004, "y" : -357371.4, "x" : 1397738.3400000003 }, "position" : { "x" : 1397738.3400000003, "y" : -357371.4 }, "selected" : false }, { "data" : { "id" : "5475", "station_name" : "町屋", "close_ymd" : "", "lon" : 139.781499, "post" : "116-0001", "e_status" : 0, "SUID" : 5475, "station_g_cd" : 2300104, "add" : "荒川区町屋1丁目", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300104", "pref_name" : "東京都", "shared_name" : "2300104", "lat" : 35.742354, "y" : -357423.54, "x" : 1397814.99 }, "position" : { "x" : 1397814.99, "y" : -357423.54 }, "selected" : false }, { "data" : { "id" : "5476", "station_name" : "千住大橋", "close_ymd" : "", "lon" : 139.79693400000002, "post" : "120-0038", "e_status" : 0, "SUID" : 5476, "station_g_cd" : 2300105, "add" : "足立区千住橋戸町11-1", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300105", "pref_name" : "東京都", "shared_name" : "2300105", "lat" : 35.74243, "y" : -357424.3, "x" : 1397969.3400000003 }, "position" : { "x" : 1397969.3400000003, "y" : -357424.3 }, "selected" : false }, { "data" : { "id" : "5469", "station_name" : "白糸台", "close_ymd" : "", "lon" : 139.509862, "post" : "183-0011", "e_status" : 0, "SUID" : 5469, "station_g_cd" : 2201204, "add" : "府中市白糸台2-71-6", "line_cd" : 22012, "selected" : false, "open_ymd" : "", "name" : "2201204", "pref_name" : "東京都", "shared_name" : "2201204", "lat" : 35.666517, "y" : -356665.17, "x" : 1395098.6199999999 }, "position" : { "x" : 1395098.6199999999, "y" : -356665.17 }, "selected" : false }, { "data" : { "id" : "5470", "station_name" : "競艇場前", "close_ymd" : "", "lon" : 139.499721, "post" : "183-0013", "e_status" : 0, "SUID" : 5470, "station_g_cd" : 2201205, "add" : "府中市小柳町4-10-11", "line_cd" : 22012, "selected" : false, "open_ymd" : "", "name" : "2201205", "pref_name" : "東京都", "shared_name" : "2201205", "lat" : 35.656232, "y" : -356562.32, "x" : 1394997.21 }, "position" : { "x" : 1394997.21, "y" : -356562.32 }, "selected" : false }, { "data" : { "id" : "5471", "station_name" : "是政", "close_ymd" : "", "lon" : 139.48859199999998, "post" : "183-0014", "e_status" : 0, "SUID" : 5471, "station_g_cd" : 2201206, "add" : "府中市是政5-8-2", "line_cd" : 22012, "selected" : false, "open_ymd" : "", "name" : "2201206", "pref_name" : "東京都", "shared_name" : "2201206", "lat" : 35.656242, "y" : -356562.42, "x" : 1394885.92 }, "position" : { "x" : 1394885.92, "y" : -356562.42 }, "selected" : false }, { "data" : { "id" : "5472", "station_name" : "京成上野", "close_ymd" : "", "lon" : 139.773571, "post" : "", "e_status" : 0, "SUID" : 5472, "station_g_cd" : 2300101, "add" : "東京都台東区上野公園1-60", "line_cd" : 23001, "selected" : false, "open_ymd" : "", "name" : "2300101", "pref_name" : "東京都", "shared_name" : "2300101", "lat" : 35.711232, "y" : -357112.32, "x" : 1397735.71 }, "position" : { "x" : 1397735.71, "y" : -357112.32 }, "selected" : false }, { "data" : { "id" : "5465", "station_name" : "西武遊園地", "close_ymd" : "", "lon" : 139.442747, "post" : "189-0026", "e_status" : 0, "SUID" : 5465, "station_g_cd" : 2200601, "add" : "東村山市多摩湖町3-15-18", "line_cd" : 22011, "selected" : false, "open_ymd" : "", "name" : "2201108", "pref_name" : "東京都", "shared_name" : "2201108", "lat" : 35.765881, "y" : -357658.81, "x" : 1394427.47 }, "position" : { "x" : 1394427.47, "y" : -357658.81 }, "selected" : false }, { "data" : { "id" : "5466", "station_name" : "武蔵境", "close_ymd" : "", "lon" : 139.54340200000001, "post" : "180-0022", "e_status" : 0, "SUID" : 5466, "station_g_cd" : 1131221, "add" : "武蔵野市境1丁目", "line_cd" : 22012, "selected" : false, "open_ymd" : "", "name" : "2201201", "pref_name" : "東京都", "shared_name" : "2201201", "lat" : 35.702083, "y" : -357020.83, "x" : 1395434.0200000003 }, "position" : { "x" : 1395434.0200000003, "y" : -357020.83 }, "selected" : false }, { "data" : { "id" : "5467", "station_name" : "新小金井", "close_ymd" : "", "lon" : 139.526603, "post" : "184-0011", "e_status" : 0, "SUID" : 5467, "station_g_cd" : 2201202, "add" : "小金井市東町4-24-1", "line_cd" : 22012, "selected" : false, "open_ymd" : "", "name" : "2201202", "pref_name" : "東京都", "shared_name" : "2201202", "lat" : 35.695908, "y" : -356959.08, "x" : 1395266.03 }, "position" : { "x" : 1395266.03, "y" : -356959.08 }, "selected" : false }, { "data" : { "id" : "5468", "station_name" : "多磨", "close_ymd" : "", "lon" : 139.51713, "post" : "183-0004", "e_status" : 0, "SUID" : 5468, "station_g_cd" : 2201203, "add" : "府中市紅葉丘3-42-2", "line_cd" : 22012, "selected" : false, "open_ymd" : "", "name" : "2201203", "pref_name" : "東京都", "shared_name" : "2201203", "lat" : 35.676821000000004, "y" : -356768.21, "x" : 1395171.3 }, "position" : { "x" : 1395171.3, "y" : -356768.21 }, "selected" : false }, { "data" : { "id" : "5461", "station_name" : "青梅街道", "close_ymd" : "", "lon" : 139.476628, "post" : "187-0032", "e_status" : 0, "SUID" : 5461, "station_g_cd" : 2201103, "add" : "小平市小川町2-1846", "line_cd" : 22011, "selected" : false, "open_ymd" : "", "name" : "2201103", "pref_name" : "東京都", "shared_name" : "2201103", "lat" : 35.730979999999995, "y" : -357309.79999999993, "x" : 1394766.28 }, "position" : { "x" : 1394766.28, "y" : -357309.79999999993 }, "selected" : false }, { "data" : { "id" : "5462", "station_name" : "萩山", "close_ymd" : "", "lon" : 139.476903, "post" : "189-0012", "e_status" : 0, "SUID" : 5462, "station_g_cd" : 2200802, "add" : "東村山市萩山町2-1-1", "line_cd" : 22011, "selected" : false, "open_ymd" : "", "name" : "2201105", "pref_name" : "東京都", "shared_name" : "2201105", "lat" : 35.740759000000004, "y" : -357407.59, "x" : 1394769.03 }, "position" : { "x" : 1394769.03, "y" : -357407.59 }, "selected" : false }, { "data" : { "id" : "5463", "station_name" : "八坂", "close_ymd" : "", "lon" : 139.467676, "post" : "189-0013", "e_status" : 0, "SUID" : 5463, "station_g_cd" : 2201106, "add" : "東村山市栄町3-18-1", "line_cd" : 22011, "selected" : false, "open_ymd" : "", "name" : "2201106", "pref_name" : "東京都", "shared_name" : "2201106", "lat" : 35.744925, "y" : -357449.25, "x" : 1394676.76 }, "position" : { "x" : 1394676.76, "y" : -357449.25 }, "selected" : false }, { "data" : { "id" : "5464", "station_name" : "武蔵大和", "close_ymd" : "", "lon" : 139.444008, "post" : "189-0025", "e_status" : 0, "SUID" : 5464, "station_g_cd" : 2201107, "add" : "東村山市廻田町3-9-19", "line_cd" : 22011, "selected" : false, "open_ymd" : "", "name" : "2201107", "pref_name" : "東京都", "shared_name" : "2201107", "lat" : 35.756427, "y" : -357564.27, "x" : 1394440.08 }, "position" : { "x" : 1394440.08, "y" : -357564.27 }, "selected" : false }, { "data" : { "id" : "5524", "station_name" : "京成金町", "close_ymd" : "", "lon" : 139.87038700000002, "post" : "125-0042", "e_status" : 0, "SUID" : 5524, "station_g_cd" : 1132008, "add" : "葛飾区金町5-37-9", "line_cd" : 23003, "selected" : false, "open_ymd" : "", "name" : "2300303", "pref_name" : "東京都", "shared_name" : "2300303", "lat" : 35.768471000000005, "y" : -357684.7100000001, "x" : 1398703.87 }, "position" : { "x" : 1398703.87, "y" : -357684.7100000001 }, "selected" : false }, { "data" : { "id" : "5523", "station_name" : "柴又", "close_ymd" : "", "lon" : 139.87518799999998, "post" : "125-0052", "e_status" : 0, "SUID" : 5523, "station_g_cd" : 2300302, "add" : "葛飾区柴又4-8-14", "line_cd" : 23003, "selected" : false, "open_ymd" : "", "name" : "2300302", "pref_name" : "東京都", "shared_name" : "2300302", "lat" : 35.756322999999995, "y" : -357563.2299999999, "x" : 1398751.88 }, "position" : { "x" : 1398751.88, "y" : -357563.2299999999 }, "selected" : false }, { "data" : { "id" : "5522", "station_name" : "京成高砂", "close_ymd" : "", "lon" : 139.866875, "post" : "", "e_status" : 0, "SUID" : 5522, "station_g_cd" : 2300110, "add" : "東京都葛飾区高砂五丁目28-1", "line_cd" : 23003, "selected" : false, "open_ymd" : "", "name" : "2300301", "pref_name" : "東京都", "shared_name" : "2300301", "lat" : 35.750932, "y" : -357509.32, "x" : 1398668.75 }, "position" : { "x" : 1398668.75, "y" : -357509.32 }, "selected" : false }, { "data" : { "id" : "5521", "station_name" : "京成高砂", "close_ymd" : "", "lon" : 139.866875, "post" : "", "e_status" : 0, "SUID" : 5521, "station_g_cd" : 2300110, "add" : "東京都葛飾区高砂五丁目28-1", "line_cd" : 23002, "selected" : false, "open_ymd" : "", "name" : "2300207", "pref_name" : "東京都", "shared_name" : "2300207", "lat" : 35.750932, "y" : -357509.32, "x" : 1398668.75 }, "position" : { "x" : 1398668.75, "y" : -357509.32 }, "selected" : false }, { "data" : { "id" : "5520", "station_name" : "青砥", "close_ymd" : "", "lon" : 139.856292, "post" : "", "e_status" : 0, "SUID" : 5520, "station_g_cd" : 2300109, "add" : "東京都葛飾区青戸三丁目36番1号", "line_cd" : 23002, "selected" : false, "open_ymd" : "", "name" : "2300206", "pref_name" : "東京都", "shared_name" : "2300206", "lat" : 35.745883, "y" : -357458.83, "x" : 1398562.92 }, "position" : { "x" : 1398562.92, "y" : -357458.83 }, "selected" : false }, { "data" : { "id" : "5519", "station_name" : "京成立石", "close_ymd" : "", "lon" : 139.848558, "post" : "124-0012", "e_status" : 0, "SUID" : 5519, "station_g_cd" : 2300205, "add" : "葛飾区立石4-24-1", "line_cd" : 23002, "selected" : false, "open_ymd" : "", "name" : "2300205", "pref_name" : "東京都", "shared_name" : "2300205", "lat" : 35.738281, "y" : -357382.81, "x" : 1398485.58 }, "position" : { "x" : 1398485.58, "y" : -357382.81 }, "selected" : false }, { "data" : { "id" : "5518", "station_name" : "四ツ木", "close_ymd" : "", "lon" : 139.834918, "post" : "124-0011", "e_status" : 0, "SUID" : 5518, "station_g_cd" : 2300204, "add" : "葛飾区四つ木1-1-1", "line_cd" : 23002, "selected" : false, "open_ymd" : "", "name" : "2300204", "pref_name" : "東京都", "shared_name" : "2300204", "lat" : 35.731962, "y" : -357319.62000000005, "x" : 1398349.18 }, "position" : { "x" : 1398349.18, "y" : -357319.62000000005 }, "selected" : false }, { "data" : { "id" : "5517", "station_name" : "八広", "close_ymd" : "", "lon" : 139.828738, "post" : "131-0041", "e_status" : 0, "SUID" : 5517, "station_g_cd" : 2300203, "add" : "墨田区八広6-25-20", "line_cd" : 23002, "selected" : false, "open_ymd" : "", "name" : "2300203", "pref_name" : "東京都", "shared_name" : "2300203", "lat" : 35.727687, "y" : -357276.87000000005, "x" : 1398287.38 }, "position" : { "x" : 1398287.38, "y" : -357276.87000000005 }, "selected" : false }, { "data" : { "id" : "5516", "station_name" : "京成曳舟", "close_ymd" : "", "lon" : 139.82001200000002, "post" : "131-0046", "e_status" : 0, "SUID" : 5516, "station_g_cd" : 2300202, "add" : "墨田区京島1-39-1", "line_cd" : 23002, "selected" : false, "open_ymd" : "", "name" : "2300202", "pref_name" : "東京都", "shared_name" : "2300202", "lat" : 35.718441, "y" : -357184.41, "x" : 1398200.12 }, "position" : { "x" : 1398200.12, "y" : -357184.41 }, "selected" : false }, { "data" : { "id" : "5515", "station_name" : "押上(スカイツリー前)", "close_ymd" : "", "lon" : 139.812935, "post" : "131-0045", "e_status" : 0, "SUID" : 5515, "station_g_cd" : 2100203, "add" : "墨田区押上一丁目", "line_cd" : 23002, "selected" : false, "open_ymd" : "", "name" : "2300201", "pref_name" : "東京都", "shared_name" : "2300201", "lat" : 35.710702000000005, "y" : -357107.0200000001, "x" : 1398129.35 }, "position" : { "x" : 1398129.35, "y" : -357107.0200000001 }, "selected" : false }, { "data" : { "id" : "2702", "station_name" : "品川", "close_ymd" : "", "lon" : 139.738999, "post" : "108-0074", "e_status" : 0, "SUID" : 2702, "station_g_cd" : 1130103, "add" : "東京都港区高輪三丁目26-26", "line_cd" : 11302, "selected" : false, "open_ymd" : "1872-06-12", "name" : "1130229", "pref_name" : "東京都", "shared_name" : "1130229", "lat" : 35.62876, "y" : -356287.6, "x" : 1397389.99 }, "position" : { "x" : 1397389.99, "y" : -356287.6 }, "selected" : false }, { "data" : { "id" : "2701", "station_name" : "田町", "close_ymd" : "", "lon" : 139.747575, "post" : "108-0014", "e_status" : 0, "SUID" : 2701, "station_g_cd" : 1130228, "add" : "東京都港区芝五丁目33-36", "line_cd" : 11302, "selected" : false, "open_ymd" : "1906-12-16", "name" : "1130228", "pref_name" : "東京都", "shared_name" : "1130228", "lat" : 35.645736, "y" : -356457.36, "x" : 1397475.7500000002 }, "position" : { "x" : 1397475.7500000002, "y" : -356457.36 }, "selected" : false }, { "data" : { "id" : "2694", "station_name" : "御徒町", "close_ymd" : "", "lon" : 139.774727, "post" : "110-0005", "e_status" : 0, "SUID" : 2694, "station_g_cd" : 1130221, "add" : "東京都台東区上野五丁目27", "line_cd" : 11302, "selected" : false, "open_ymd" : "1925-11-01", "name" : "1130221", "pref_name" : "東京都", "shared_name" : "1130221", "lat" : 35.707282, "y" : -357072.82, "x" : 1397747.27 }, "position" : { "x" : 1397747.27, "y" : -357072.82 }, "selected" : false }, { "data" : { "id" : "2693", "station_name" : "上野", "close_ymd" : "", "lon" : 139.777043, "post" : "110-0005", "e_status" : 0, "SUID" : 2693, "station_g_cd" : 1130220, "add" : "東京都台東区上野七丁目1-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1883-07-28", "name" : "1130220", "pref_name" : "東京都", "shared_name" : "1130220", "lat" : 35.71379, "y" : -357137.9, "x" : 1397770.43 }, "position" : { "x" : 1397770.43, "y" : -357137.9 }, "selected" : false }, { "data" : { "id" : "2696", "station_name" : "神田", "close_ymd" : "", "lon" : 139.77064099999998, "post" : "101-0044", "e_status" : 0, "SUID" : 2696, "station_g_cd" : 1130223, "add" : "東京都千代田区鍛冶町二丁目13-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1919-03-01", "name" : "1130223", "pref_name" : "東京都", "shared_name" : "1130223", "lat" : 35.691173, "y" : -356911.73, "x" : 1397706.41 }, "position" : { "x" : 1397706.41, "y" : -356911.73 }, "selected" : false }, { "data" : { "id" : "2695", "station_name" : "秋葉原", "close_ymd" : "", "lon" : 139.77328799999998, "post" : "101-0021", "e_status" : 0, "SUID" : 2695, "station_g_cd" : 1130222, "add" : "東京都千代田区外神田一丁目17", "line_cd" : 11302, "selected" : false, "open_ymd" : "1890-11-01", "name" : "1130222", "pref_name" : "東京都", "shared_name" : "1130222", "lat" : 35.698619, "y" : -356986.19, "x" : 1397732.88 }, "position" : { "x" : 1397732.88, "y" : -356986.19 }, "selected" : false }, { "data" : { "id" : "2698", "station_name" : "有楽町", "close_ymd" : "", "lon" : 139.76380600000002, "post" : "100-0006", "e_status" : 0, "SUID" : 2698, "station_g_cd" : 1130225, "add" : "東京都千代田区有楽町二丁目9", "line_cd" : 11302, "selected" : false, "open_ymd" : "1910-06-25", "name" : "1130225", "pref_name" : "東京都", "shared_name" : "1130225", "lat" : 35.675441, "y" : -356754.41, "x" : 1397638.06 }, "position" : { "x" : 1397638.06, "y" : -356754.41 }, "selected" : false }, { "data" : { "id" : "2697", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "100-0005", "e_status" : 0, "SUID" : 2697, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目9-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1914-12-20", "name" : "1130224", "pref_name" : "東京都", "shared_name" : "1130224", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "2700", "station_name" : "浜松町", "close_ymd" : "", "lon" : 139.757135, "post" : "105-0022", "e_status" : 0, "SUID" : 2700, "station_g_cd" : 1130227, "add" : "東京都港区海岸一丁目3-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1909-12-16", "name" : "1130227", "pref_name" : "東京都", "shared_name" : "1130227", "lat" : 35.655390999999995, "y" : -356553.9099999999, "x" : 1397571.35 }, "position" : { "x" : 1397571.35, "y" : -356553.9099999999 }, "selected" : false }, { "data" : { "id" : "2699", "station_name" : "新橋", "close_ymd" : "", "lon" : 139.758587, "post" : "105-0004", "e_status" : 0, "SUID" : 2699, "station_g_cd" : 1130102, "add" : "東京都港区新橋二丁目17", "line_cd" : 11302, "selected" : false, "open_ymd" : "1909-12-16", "name" : "1130226", "pref_name" : "東京都", "shared_name" : "1130226", "lat" : 35.666195, "y" : -356661.95, "x" : 1397585.87 }, "position" : { "x" : 1397585.87, "y" : -356661.95 }, "selected" : false }, { "data" : { "id" : "2685", "station_name" : "池袋", "close_ymd" : "", "lon" : 139.71108600000002, "post" : "171-0022", "e_status" : 0, "SUID" : 2685, "station_g_cd" : 1130212, "add" : "東京都豊島区南池袋一丁目28-2", "line_cd" : 11302, "selected" : false, "open_ymd" : "1903-04-01", "name" : "1130212", "pref_name" : "東京都", "shared_name" : "1130212", "lat" : 35.730256, "y" : -357302.56, "x" : 1397110.8600000003 }, "position" : { "x" : 1397110.8600000003, "y" : -357302.56 }, "selected" : false }, { "data" : { "id" : "2686", "station_name" : "大塚", "close_ymd" : "", "lon" : 139.728584, "post" : "170-0005", "e_status" : 0, "SUID" : 2686, "station_g_cd" : 1130213, "add" : "東京都豊島区南大塚三丁目33-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1903-04-01", "name" : "1130213", "pref_name" : "東京都", "shared_name" : "1130213", "lat" : 35.731412, "y" : -357314.12, "x" : 1397285.84 }, "position" : { "x" : 1397285.84, "y" : -357314.12 }, "selected" : false }, { "data" : { "id" : "2687", "station_name" : "巣鴨", "close_ymd" : "", "lon" : 139.739303, "post" : "170-0002", "e_status" : 0, "SUID" : 2687, "station_g_cd" : 1130214, "add" : "東京都豊島区巣鴨一丁目16-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1903-04-01", "name" : "1130214", "pref_name" : "東京都", "shared_name" : "1130214", "lat" : 35.733445, "y" : -357334.45, "x" : 1397393.03 }, "position" : { "x" : 1397393.03, "y" : -357334.45 }, "selected" : false }, { "data" : { "id" : "2688", "station_name" : "駒込", "close_ymd" : "", "lon" : 139.748053, "post" : "170-0003", "e_status" : 0, "SUID" : 2688, "station_g_cd" : 1130215, "add" : "東京都豊島区駒込二丁目1-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1910-11-15", "name" : "1130215", "pref_name" : "東京都", "shared_name" : "1130215", "lat" : 35.736825, "y" : -357368.25000000006, "x" : 1397480.53 }, "position" : { "x" : 1397480.53, "y" : -357368.25000000006 }, "selected" : false }, { "data" : { "id" : "2689", "station_name" : "田端", "close_ymd" : "", "lon" : 139.76122900000001, "post" : "114-0013", "e_status" : 0, "SUID" : 2689, "station_g_cd" : 1130216, "add" : "東京都北区東田端一丁目17-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1896-04-01", "name" : "1130216", "pref_name" : "東京都", "shared_name" : "1130216", "lat" : 35.737781, "y" : -357377.81, "x" : 1397612.29 }, "position" : { "x" : 1397612.29, "y" : -357377.81 }, "selected" : false }, { "data" : { "id" : "2690", "station_name" : "西日暮里", "close_ymd" : "", "lon" : 139.76685700000002, "post" : "116-0013", "e_status" : 0, "SUID" : 2690, "station_g_cd" : 1130217, "add" : "東京都荒川区西日暮里五丁目22-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1971-04-20", "name" : "1130217", "pref_name" : "東京都", "shared_name" : "1130217", "lat" : 35.731953999999995, "y" : -357319.5399999999, "x" : 1397668.57 }, "position" : { "x" : 1397668.57, "y" : -357319.5399999999 }, "selected" : false }, { "data" : { "id" : "2691", "station_name" : "日暮里", "close_ymd" : "", "lon" : 139.771287, "post" : "116-0013", "e_status" : 0, "SUID" : 2691, "station_g_cd" : 1130218, "add" : "東京都荒川区西日暮里二丁目19-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1905-04-01", "name" : "1130218", "pref_name" : "東京都", "shared_name" : "1130218", "lat" : 35.727908, "y" : -357279.08, "x" : 1397712.87 }, "position" : { "x" : 1397712.87, "y" : -357279.08 }, "selected" : false }, { "data" : { "id" : "2692", "station_name" : "鶯谷", "close_ymd" : "", "lon" : 139.77801499999998, "post" : "110-0003", "e_status" : 0, "SUID" : 2692, "station_g_cd" : 1130219, "add" : "東京都台東区根岸一丁目4-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1912-07-11", "name" : "1130219", "pref_name" : "東京都", "shared_name" : "1130219", "lat" : 35.721484000000004, "y" : -357214.84, "x" : 1397780.15 }, "position" : { "x" : 1397780.15, "y" : -357214.84 }, "selected" : false }, { "data" : { "id" : "2677", "station_name" : "恵比寿", "close_ymd" : "", "lon" : 139.71007, "post" : "150-0022", "e_status" : 0, "SUID" : 2677, "station_g_cd" : 1130204, "add" : "東京都渋谷区恵比寿南一丁目5-5", "line_cd" : 11302, "selected" : false, "open_ymd" : "1901-02-25", "name" : "1130204", "pref_name" : "東京都", "shared_name" : "1130204", "lat" : 35.646685, "y" : -356466.85, "x" : 1397100.7 }, "position" : { "x" : 1397100.7, "y" : -356466.85 }, "selected" : false }, { "data" : { "id" : "2678", "station_name" : "渋谷", "close_ymd" : "", "lon" : 139.701238, "post" : "150-0043", "e_status" : 0, "SUID" : 2678, "station_g_cd" : 1130205, "add" : "東京都渋谷区道玄坂一丁目1-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1885-03-01", "name" : "1130205", "pref_name" : "東京都", "shared_name" : "1130205", "lat" : 35.658871000000005, "y" : -356588.71, "x" : 1397012.38 }, "position" : { "x" : 1397012.38, "y" : -356588.71 }, "selected" : false }, { "data" : { "id" : "2679", "station_name" : "原宿", "close_ymd" : "", "lon" : 139.70259199999998, "post" : "150-0001", "e_status" : 0, "SUID" : 2679, "station_g_cd" : 1130206, "add" : "東京都渋谷区神宮前一丁目18", "line_cd" : 11302, "selected" : false, "open_ymd" : "1906-10-30", "name" : "1130206", "pref_name" : "東京都", "shared_name" : "1130206", "lat" : 35.670646000000005, "y" : -356706.46, "x" : 1397025.92 }, "position" : { "x" : 1397025.92, "y" : -356706.46 }, "selected" : false }, { "data" : { "id" : "2680", "station_name" : "代々木", "close_ymd" : "", "lon" : 139.702042, "post" : "151-0053", "e_status" : 0, "SUID" : 2680, "station_g_cd" : 1130207, "add" : "東京都渋谷区代々木一丁目34-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1906-09-23", "name" : "1130207", "pref_name" : "東京都", "shared_name" : "1130207", "lat" : 35.683061, "y" : -356830.61000000004, "x" : 1397020.4200000002 }, "position" : { "x" : 1397020.4200000002, "y" : -356830.61000000004 }, "selected" : false }, { "data" : { "id" : "2681", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.70046399999998, "post" : "160-0022", "e_status" : 0, "SUID" : 2681, "station_g_cd" : 1130208, "add" : "東京都新宿区新宿三丁目38-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1885-03-01", "name" : "1130208", "pref_name" : "東京都", "shared_name" : "1130208", "lat" : 35.689729, "y" : -356897.29, "x" : 1397004.64 }, "position" : { "x" : 1397004.64, "y" : -356897.29 }, "selected" : false }, { "data" : { "id" : "2682", "station_name" : "新大久保", "close_ymd" : "", "lon" : 139.700261, "post" : "169-0073", "e_status" : 0, "SUID" : 2682, "station_g_cd" : 1130209, "add" : "東京都新宿区百人町一丁目10-15", "line_cd" : 11302, "selected" : false, "open_ymd" : "1914-11-15", "name" : "1130209", "pref_name" : "東京都", "shared_name" : "1130209", "lat" : 35.700875, "y" : -357008.75000000006, "x" : 1397002.61 }, "position" : { "x" : 1397002.61, "y" : -357008.75000000006 }, "selected" : false }, { "data" : { "id" : "2683", "station_name" : "高田馬場", "close_ymd" : "", "lon" : 139.703715, "post" : "169-0075", "e_status" : 0, "SUID" : 2683, "station_g_cd" : 1130210, "add" : "東京都新宿区高田馬場一丁目35-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1910-09-15", "name" : "1130210", "pref_name" : "東京都", "shared_name" : "1130210", "lat" : 35.712677, "y" : -357126.77, "x" : 1397037.15 }, "position" : { "x" : 1397037.15, "y" : -357126.77 }, "selected" : false }, { "data" : { "id" : "2684", "station_name" : "目白", "close_ymd" : "", "lon" : 139.706228, "post" : "171-0031", "e_status" : 0, "SUID" : 2684, "station_g_cd" : 1130211, "add" : "東京都豊島区目白三丁目3-1", "line_cd" : 11302, "selected" : false, "open_ymd" : "1885-03-16", "name" : "1130211", "pref_name" : "東京都", "shared_name" : "1130211", "lat" : 35.720476, "y" : -357204.75999999995, "x" : 1397062.28 }, "position" : { "x" : 1397062.28, "y" : -357204.75999999995 }, "selected" : false }, { "data" : { "id" : "2676", "station_name" : "目黒", "close_ymd" : "", "lon" : 139.715775, "post" : "141-0021", "e_status" : 0, "SUID" : 2676, "station_g_cd" : 1130203, "add" : "東京都品川区上大崎二丁目16-9", "line_cd" : 11302, "selected" : false, "open_ymd" : "1885-03-16", "name" : "1130203", "pref_name" : "東京都", "shared_name" : "1130203", "lat" : 35.633922999999996, "y" : -356339.23, "x" : 1397157.75 }, "position" : { "x" : 1397157.75, "y" : -356339.23 }, "selected" : false }, { "data" : { "id" : "2675", "station_name" : "五反田", "close_ymd" : "", "lon" : 139.72382199999998, "post" : "141-0022", "e_status" : 0, "SUID" : 2675, "station_g_cd" : 1130202, "add" : "東京都品川区東五反田一丁目26", "line_cd" : 11302, "selected" : false, "open_ymd" : "1911-10-15", "name" : "1130202", "pref_name" : "東京都", "shared_name" : "1130202", "lat" : 35.625974, "y" : -356259.74, "x" : 1397238.2199999997 }, "position" : { "x" : 1397238.2199999997, "y" : -356259.74 }, "selected" : false }, { "data" : { "id" : "2674", "station_name" : "大崎", "close_ymd" : "", "lon" : 139.72843899999998, "post" : "141-0032", "e_status" : 0, "SUID" : 2674, "station_g_cd" : 1130201, "add" : "東京都品川区大崎一丁目21-4", "line_cd" : 11302, "selected" : false, "open_ymd" : "1901-02-25", "name" : "1130201", "pref_name" : "東京都", "shared_name" : "1130201", "lat" : 35.619772, "y" : -356197.72, "x" : 1397284.39 }, "position" : { "x" : 1397284.39, "y" : -356197.72 }, "selected" : false }, { "data" : { "id" : "2655", "station_name" : "品川", "close_ymd" : "", "lon" : 139.738999, "post" : "108-0074", "e_status" : 0, "SUID" : 2655, "station_g_cd" : 1130103, "add" : "東京都港区高輪三丁目26-27", "line_cd" : 11301, "selected" : false, "open_ymd" : "", "name" : "1130103", "pref_name" : "東京都", "shared_name" : "1130103", "lat" : 35.62876, "y" : -356287.6, "x" : 1397389.99 }, "position" : { "x" : 1397389.99, "y" : -356287.6 }, "selected" : false }, { "data" : { "id" : "2653", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "100-0005", "e_status" : 0, "SUID" : 2653, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11301, "selected" : false, "open_ymd" : "", "name" : "1130101", "pref_name" : "東京都", "shared_name" : "1130101", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "2654", "station_name" : "新橋", "close_ymd" : "", "lon" : 139.758587, "post" : "105-0004", "e_status" : 0, "SUID" : 2654, "station_g_cd" : 1130102, "add" : "東京都港区新橋二丁目17", "line_cd" : 11301, "selected" : false, "open_ymd" : "", "name" : "1130102", "pref_name" : "東京都", "shared_name" : "1130102", "lat" : 35.666195, "y" : -356661.95, "x" : 1397585.87 }, "position" : { "x" : 1397585.87, "y" : -356661.95 }, "selected" : false }, { "data" : { "id" : "2746", "station_name" : "北府中", "close_ymd" : "", "lon" : 139.471792, "post" : "183-0057", "e_status" : 0, "SUID" : 2746, "station_g_cd" : 1130502, "add" : "府中市晴見町2丁目", "line_cd" : 11305, "selected" : false, "open_ymd" : "", "name" : "1130502", "pref_name" : "東京都", "shared_name" : "1130502", "lat" : 35.68088, "y" : -356808.80000000005, "x" : 1394717.92 }, "position" : { "x" : 1394717.92, "y" : -356808.80000000005 }, "selected" : false }, { "data" : { "id" : "2745", "station_name" : "府中本町", "close_ymd" : "", "lon" : 139.477142, "post" : "183-0027", "e_status" : 0, "SUID" : 2745, "station_g_cd" : 1130320, "add" : "府中市本町1丁目", "line_cd" : 11305, "selected" : false, "open_ymd" : "", "name" : "1130501", "pref_name" : "東京都", "shared_name" : "1130501", "lat" : 35.665766, "y" : -356657.66, "x" : 1394771.42 }, "position" : { "x" : 1394771.42, "y" : -356657.66 }, "selected" : false }, { "data" : { "id" : "2748", "station_name" : "新小平", "close_ymd" : "", "lon" : 139.470745, "post" : "187-0032", "e_status" : 0, "SUID" : 2748, "station_g_cd" : 1130504, "add" : "小平市小川町2丁目", "line_cd" : 11305, "selected" : false, "open_ymd" : "", "name" : "1130504", "pref_name" : "東京都", "shared_name" : "1130504", "lat" : 35.73128, "y" : -357312.8, "x" : 1394707.45 }, "position" : { "x" : 1394707.45, "y" : -357312.8 }, "selected" : false }, { "data" : { "id" : "2747", "station_name" : "西国分寺", "close_ymd" : "", "lon" : 139.465994, "post" : "185-0013", "e_status" : 0, "SUID" : 2747, "station_g_cd" : 1130503, "add" : "国分寺市西恋ケ窪2丁目", "line_cd" : 11305, "selected" : false, "open_ymd" : "", "name" : "1130503", "pref_name" : "東京都", "shared_name" : "1130503", "lat" : 35.699744, "y" : -356997.44, "x" : 1394659.94 }, "position" : { "x" : 1394659.94, "y" : -356997.44 }, "selected" : false }, { "data" : { "id" : "2749", "station_name" : "新秋津", "close_ymd" : "", "lon" : 139.493592, "post" : "189-0001", "e_status" : 0, "SUID" : 2749, "station_g_cd" : 1130505, "add" : "東村山市秋津町5丁目", "line_cd" : 11305, "selected" : false, "open_ymd" : "", "name" : "1130505", "pref_name" : "東京都", "shared_name" : "1130505", "lat" : 35.778331, "y" : -357783.31, "x" : 1394935.9200000002 }, "position" : { "x" : 1394935.9200000002, "y" : -357783.31 }, "selected" : false }, { "data" : { "id" : "2729", "station_name" : "立川", "close_ymd" : "", "lon" : 139.413704, "post" : "190-0012", "e_status" : 0, "SUID" : 2729, "station_g_cd" : 1130325, "add" : "東京都立川市曙町二丁目1-1", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130325", "pref_name" : "東京都", "shared_name" : "1130325", "lat" : 35.698202, "y" : -356982.02, "x" : 1394137.04 }, "position" : { "x" : 1394137.04, "y" : -356982.02 }, "selected" : false }, { "data" : { "id" : "2727", "station_name" : "矢川", "close_ymd" : "", "lon" : 139.431611, "post" : "186-0011", "e_status" : 0, "SUID" : 2727, "station_g_cd" : 1130323, "add" : "国立市谷保石田", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130323", "pref_name" : "東京都", "shared_name" : "1130323", "lat" : 35.685078999999995, "y" : -356850.7899999999, "x" : 1394316.11 }, "position" : { "x" : 1394316.11, "y" : -356850.7899999999 }, "selected" : false }, { "data" : { "id" : "2728", "station_name" : "西国立", "close_ymd" : "", "lon" : 139.423887, "post" : "190-0021", "e_status" : 0, "SUID" : 2728, "station_g_cd" : 1130324, "add" : "立川市羽衣町1丁目", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130324", "pref_name" : "東京都", "shared_name" : "1130324", "lat" : 35.69375, "y" : -356937.5, "x" : 1394238.87 }, "position" : { "x" : 1394238.87, "y" : -356937.5 }, "selected" : false }, { "data" : { "id" : "2725", "station_name" : "西府", "close_ymd" : "", "lon" : 139.457477, "post" : "183-0032", "e_status" : 0, "SUID" : 2725, "station_g_cd" : 1130329, "add" : "東京都府中市本宿町一丁目40-6", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130329", "pref_name" : "東京都", "shared_name" : "1130329", "lat" : 35.670912, "y" : -356709.12, "x" : 1394574.77 }, "position" : { "x" : 1394574.77, "y" : -356709.12 }, "selected" : false }, { "data" : { "id" : "2726", "station_name" : "谷保", "close_ymd" : "", "lon" : 139.446724, "post" : "186-0011", "e_status" : 0, "SUID" : 2726, "station_g_cd" : 1130322, "add" : "国立市谷保町", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130322", "pref_name" : "東京都", "shared_name" : "1130322", "lat" : 35.681377000000005, "y" : -356813.7700000001, "x" : 1394467.24 }, "position" : { "x" : 1394467.24, "y" : -356813.7700000001 }, "selected" : false }, { "data" : { "id" : "2724", "station_name" : "分倍河原", "close_ymd" : "", "lon" : 139.468798, "post" : "183-0021", "e_status" : 0, "SUID" : 2724, "station_g_cd" : 1130321, "add" : "府中市片町2丁目", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130321", "pref_name" : "東京都", "shared_name" : "1130321", "lat" : 35.668493, "y" : -356684.93, "x" : 1394687.98 }, "position" : { "x" : 1394687.98, "y" : -356684.93 }, "selected" : false }, { "data" : { "id" : "2723", "station_name" : "府中本町", "close_ymd" : "", "lon" : 139.477142, "post" : "183-0027", "e_status" : 0, "SUID" : 2723, "station_g_cd" : 1130320, "add" : "府中市本町1丁目", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130320", "pref_name" : "東京都", "shared_name" : "1130320", "lat" : 35.665766, "y" : -356657.66, "x" : 1394771.42 }, "position" : { "x" : 1394771.42, "y" : -356657.66 }, "selected" : false }, { "data" : { "id" : "2722", "station_name" : "南多摩", "close_ymd" : "", "lon" : 139.489781, "post" : "206-0801", "e_status" : 0, "SUID" : 2722, "station_g_cd" : 1130319, "add" : "稲城市大丸", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130319", "pref_name" : "東京都", "shared_name" : "1130319", "lat" : 35.649249, "y" : -356492.49, "x" : 1394897.8099999998 }, "position" : { "x" : 1394897.8099999998, "y" : -356492.49 }, "selected" : false }, { "data" : { "id" : "2721", "station_name" : "稲城長沼", "close_ymd" : "", "lon" : 139.502811, "post" : "206-0802", "e_status" : 0, "SUID" : 2721, "station_g_cd" : 1130318, "add" : "稲城市東長沼", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130318", "pref_name" : "東京都", "shared_name" : "1130318", "lat" : 35.644184, "y" : -356441.84, "x" : 1395028.11 }, "position" : { "x" : 1395028.11, "y" : -356441.84 }, "selected" : false }, { "data" : { "id" : "2720", "station_name" : "矢野口", "close_ymd" : "", "lon" : 139.520849, "post" : "206-0812", "e_status" : 0, "SUID" : 2720, "station_g_cd" : 1130317, "add" : "稲城市矢野口", "line_cd" : 11303, "selected" : false, "open_ymd" : "", "name" : "1130317", "pref_name" : "東京都", "shared_name" : "1130317", "lat" : 35.641304999999996, "y" : -356413.04999999993, "x" : 1395208.49 }, "position" : { "x" : 1395208.49, "y" : -356413.04999999993 }, "selected" : false }, { "data" : { "id" : "2806", "station_name" : "西大井", "close_ymd" : "", "lon" : 139.721729, "post" : "140-0015", "e_status" : 0, "SUID" : 2806, "station_g_cd" : 1130804, "add" : "品川区西大井1丁目", "line_cd" : 11308, "selected" : false, "open_ymd" : "", "name" : "1130804", "pref_name" : "東京都", "shared_name" : "1130804", "lat" : 35.601616, "y" : -356016.16, "x" : 1397217.29 }, "position" : { "x" : 1397217.29, "y" : -356016.16 }, "selected" : false }, { "data" : { "id" : "2805", "station_name" : "品川", "close_ymd" : "", "lon" : 139.738999, "post" : "108-0074", "e_status" : 0, "SUID" : 2805, "station_g_cd" : 1130103, "add" : "東京都港区高輪三丁目26-26", "line_cd" : 11308, "selected" : false, "open_ymd" : "", "name" : "1130803", "pref_name" : "東京都", "shared_name" : "1130803", "lat" : 35.62876, "y" : -356287.6, "x" : 1397389.99 }, "position" : { "x" : 1397389.99, "y" : -356287.6 }, "selected" : false }, { "data" : { "id" : "2789", "station_name" : "片倉", "close_ymd" : "", "lon" : 139.34118999999998, "post" : "192-0914", "e_status" : 0, "SUID" : 2789, "station_g_cd" : 1130619, "add" : "八王子市片倉町", "line_cd" : 11306, "selected" : false, "open_ymd" : "", "name" : "1130619", "pref_name" : "東京都", "shared_name" : "1130619", "lat" : 35.639703999999995, "y" : -356397.0399999999, "x" : 1393411.9 }, "position" : { "x" : 1393411.9, "y" : -356397.0399999999 }, "selected" : false }, { "data" : { "id" : "2790", "station_name" : "八王子", "close_ymd" : "", "lon" : 139.338998, "post" : "192-0083", "e_status" : 0, "SUID" : 2790, "station_g_cd" : 1130620, "add" : "東京都八王子市旭町1-1", "line_cd" : 11306, "selected" : false, "open_ymd" : "", "name" : "1130620", "pref_name" : "東京都", "shared_name" : "1130620", "lat" : 35.655555, "y" : -356555.55, "x" : 1393389.98 }, "position" : { "x" : 1393389.98, "y" : -356555.55 }, "selected" : false }, { "data" : { "id" : "2803", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "100-0005", "e_status" : 0, "SUID" : 2803, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11308, "selected" : false, "open_ymd" : "", "name" : "1130801", "pref_name" : "東京都", "shared_name" : "1130801", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "2804", "station_name" : "新橋", "close_ymd" : "", "lon" : 139.758587, "post" : "105-0004", "e_status" : 0, "SUID" : 2804, "station_g_cd" : 1130102, "add" : "東京都港区新橋二丁目17", "line_cd" : 11308, "selected" : false, "open_ymd" : "", "name" : "1130802", "pref_name" : "東京都", "shared_name" : "1130802", "lat" : 35.666195, "y" : -356661.95, "x" : 1397585.87 }, "position" : { "x" : 1397585.87, "y" : -356661.95 }, "selected" : false }, { "data" : { "id" : "2780", "station_name" : "成瀬", "close_ymd" : "", "lon" : 139.472875, "post" : "194-0045", "e_status" : 0, "SUID" : 2780, "station_g_cd" : 1130610, "add" : "町田市南成瀬1丁目", "line_cd" : 11306, "selected" : false, "open_ymd" : "", "name" : "1130610", "pref_name" : "東京都", "shared_name" : "1130610", "lat" : 35.535412, "y" : -355354.12, "x" : 1394728.7499999998 }, "position" : { "x" : 1394728.7499999998, "y" : -355354.12 }, "selected" : false }, { "data" : { "id" : "2781", "station_name" : "町田", "close_ymd" : "", "lon" : 139.445579, "post" : "194-0013", "e_status" : 0, "SUID" : 2781, "station_g_cd" : 1130611, "add" : "町田市原町田1丁目", "line_cd" : 11306, "selected" : false, "open_ymd" : "", "name" : "1130611", "pref_name" : "東京都", "shared_name" : "1130611", "lat" : 35.542004, "y" : -355420.04, "x" : 1394455.79 }, "position" : { "x" : 1394455.79, "y" : -355420.04 }, "selected" : false }, { "data" : { "id" : "2788", "station_name" : "八王子みなみ野", "close_ymd" : "", "lon" : 139.330678, "post" : "192-0915", "e_status" : 0, "SUID" : 2788, "station_g_cd" : 1130618, "add" : "八王子市宇津貫町", "line_cd" : 11306, "selected" : false, "open_ymd" : "", "name" : "1130618", "pref_name" : "東京都", "shared_name" : "1130618", "lat" : 35.630664, "y" : -356306.64, "x" : 1393306.78 }, "position" : { "x" : 1393306.78, "y" : -356306.64 }, "selected" : false }, { "data" : { "id" : "2787", "station_name" : "相原", "close_ymd" : "", "lon" : 139.33168999999998, "post" : "194-0211", "e_status" : 0, "SUID" : 2787, "station_g_cd" : 1130617, "add" : "町田市相原町", "line_cd" : 11306, "selected" : false, "open_ymd" : "", "name" : "1130617", "pref_name" : "東京都", "shared_name" : "1130617", "lat" : 35.60694, "y" : -356069.4, "x" : 1393316.9 }, "position" : { "x" : 1393316.9, "y" : -356069.4 }, "selected" : false }, { "data" : { "id" : "2900", "station_name" : "阿佐ケ谷", "close_ymd" : "", "lon" : 139.635868, "post" : "166-0004", "e_status" : 0, "SUID" : 2900, "station_g_cd" : 1131216, "add" : "東京都杉並区阿佐谷南三丁目36-3", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131216", "pref_name" : "東京都", "shared_name" : "1131216", "lat" : 35.704817999999996, "y" : -357048.17999999993, "x" : 1396358.68 }, "position" : { "x" : 1396358.68, "y" : -357048.17999999993 }, "selected" : false }, { "data" : { "id" : "2899", "station_name" : "高円寺", "close_ymd" : "", "lon" : 139.649664, "post" : "166-0003", "e_status" : 0, "SUID" : 2899, "station_g_cd" : 1131215, "add" : "杉並区高円寺南4丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131215", "pref_name" : "東京都", "shared_name" : "1131215", "lat" : 35.705326, "y" : -357053.26, "x" : 1396496.64 }, "position" : { "x" : 1396496.64, "y" : -357053.26 }, "selected" : false }, { "data" : { "id" : "2898", "station_name" : "中野", "close_ymd" : "", "lon" : 139.66583500000002, "post" : "164-0001", "e_status" : 0, "SUID" : 2898, "station_g_cd" : 1131214, "add" : "中野区中野5丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131214", "pref_name" : "東京都", "shared_name" : "1131214", "lat" : 35.705765, "y" : -357057.65, "x" : 1396658.35 }, "position" : { "x" : 1396658.35, "y" : -357057.65 }, "selected" : false }, { "data" : { "id" : "2897", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.70046399999998, "post" : "160-0022", "e_status" : 0, "SUID" : 2897, "station_g_cd" : 1130208, "add" : "東京都新宿区新宿三丁目38-1", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131211", "pref_name" : "東京都", "shared_name" : "1131211", "lat" : 35.689729, "y" : -356897.29, "x" : 1397004.64 }, "position" : { "x" : 1397004.64, "y" : -356897.29 }, "selected" : false }, { "data" : { "id" : "2896", "station_name" : "四ツ谷", "close_ymd" : "", "lon" : 139.73064399999998, "post" : "160-0004", "e_status" : 0, "SUID" : 2896, "station_g_cd" : 1131102, "add" : "東京都新宿区四谷一丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131207", "pref_name" : "東京都", "shared_name" : "1131207", "lat" : 35.686040999999996, "y" : -356860.41, "x" : 1397306.44 }, "position" : { "x" : 1397306.44, "y" : -356860.41 }, "selected" : false }, { "data" : { "id" : "2895", "station_name" : "御茶ノ水", "close_ymd" : "", "lon" : 139.76495500000001, "post" : "101-0062", "e_status" : 0, "SUID" : 2895, "station_g_cd" : 1131203, "add" : "千代田区神田駿河台2丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131203", "pref_name" : "東京都", "shared_name" : "1131203", "lat" : 35.699605, "y" : -356996.05, "x" : 1397649.55 }, "position" : { "x" : 1397649.55, "y" : -356996.05 }, "selected" : false }, { "data" : { "id" : "2894", "station_name" : "神田", "close_ymd" : "", "lon" : 139.77064099999998, "post" : "101-0044", "e_status" : 0, "SUID" : 2894, "station_g_cd" : 1130223, "add" : "東京都千代田区鍛冶町二丁目13-1", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131202", "pref_name" : "東京都", "shared_name" : "1131202", "lat" : 35.691173, "y" : -356911.73, "x" : 1397706.41 }, "position" : { "x" : 1397706.41, "y" : -356911.73 }, "selected" : false }, { "data" : { "id" : "2893", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "100-0005", "e_status" : 0, "SUID" : 2893, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131201", "pref_name" : "東京都", "shared_name" : "1131201", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "2849", "station_name" : "八王子", "close_ymd" : "", "lon" : 139.338998, "post" : "192-0083", "e_status" : 0, "SUID" : 2849, "station_g_cd" : 1130620, "add" : "東京都八王子市旭町1-1", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131110", "pref_name" : "東京都", "shared_name" : "1131110", "lat" : 35.655555, "y" : -356555.55, "x" : 1393389.98 }, "position" : { "x" : 1393389.98, "y" : -356555.55 }, "selected" : false }, { "data" : { "id" : "2850", "station_name" : "西八王子", "close_ymd" : "", "lon" : 139.31264, "post" : "193-0835", "e_status" : 0, "SUID" : 2850, "station_g_cd" : 1131111, "add" : "八王子市千人町2丁目", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131111", "pref_name" : "東京都", "shared_name" : "1131111", "lat" : 35.656621, "y" : -356566.21, "x" : 1393126.4 }, "position" : { "x" : 1393126.4, "y" : -356566.21 }, "selected" : false }, { "data" : { "id" : "2851", "station_name" : "高尾", "close_ymd" : "", "lon" : 139.282288, "post" : "193-0844", "e_status" : 0, "SUID" : 2851, "station_g_cd" : 1131112, "add" : "八王子市高尾町", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131112", "pref_name" : "東京都", "shared_name" : "1131112", "lat" : 35.642026, "y" : -356420.26, "x" : 1392822.88 }, "position" : { "x" : 1392822.88, "y" : -356420.26 }, "selected" : false }, { "data" : { "id" : "2845", "station_name" : "国分寺", "close_ymd" : "", "lon" : 139.480841, "post" : "185-0012", "e_status" : 0, "SUID" : 2845, "station_g_cd" : 1131106, "add" : "東京都国分寺市本町二丁目1-23", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131106", "pref_name" : "東京都", "shared_name" : "1131106", "lat" : 35.700123, "y" : -357001.23, "x" : 1394808.41 }, "position" : { "x" : 1394808.41, "y" : -357001.23 }, "selected" : false }, { "data" : { "id" : "2846", "station_name" : "立川", "close_ymd" : "", "lon" : 139.413704, "post" : "190-0012", "e_status" : 0, "SUID" : 2846, "station_g_cd" : 1130325, "add" : "東京都立川市曙町二丁目1-1", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131107", "pref_name" : "東京都", "shared_name" : "1131107", "lat" : 35.698202, "y" : -356982.02, "x" : 1394137.04 }, "position" : { "x" : 1394137.04, "y" : -356982.02 }, "selected" : false }, { "data" : { "id" : "2847", "station_name" : "日野", "close_ymd" : "", "lon" : 139.39393, "post" : "191-0061", "e_status" : 0, "SUID" : 2847, "station_g_cd" : 1131108, "add" : "日野市大坂上1丁目", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131108", "pref_name" : "東京都", "shared_name" : "1131108", "lat" : 35.679244, "y" : -356792.43999999994, "x" : 1393939.3 }, "position" : { "x" : 1393939.3, "y" : -356792.43999999994 }, "selected" : false }, { "data" : { "id" : "2848", "station_name" : "豊田", "close_ymd" : "", "lon" : 139.381495, "post" : "191-0053", "e_status" : 0, "SUID" : 2848, "station_g_cd" : 1131109, "add" : "日野市豊田4丁目", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131109", "pref_name" : "東京都", "shared_name" : "1131109", "lat" : 35.659502, "y" : -356595.02, "x" : 1393814.95 }, "position" : { "x" : 1393814.95, "y" : -356595.02 }, "selected" : false }, { "data" : { "id" : "2841", "station_name" : "四ツ谷", "close_ymd" : "", "lon" : 139.73064399999998, "post" : "160-0004", "e_status" : 0, "SUID" : 2841, "station_g_cd" : 1131102, "add" : "東京都新宿区四谷一丁目", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131102", "pref_name" : "東京都", "shared_name" : "1131102", "lat" : 35.686040999999996, "y" : -356860.41, "x" : 1397306.44 }, "position" : { "x" : 1397306.44, "y" : -356860.41 }, "selected" : false }, { "data" : { "id" : "2842", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.70046399999998, "post" : "160-0022", "e_status" : 0, "SUID" : 2842, "station_g_cd" : 1130208, "add" : "東京都新宿区新宿三丁目38-1", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131103", "pref_name" : "東京都", "shared_name" : "1131103", "lat" : 35.689729, "y" : -356897.29, "x" : 1397004.64 }, "position" : { "x" : 1397004.64, "y" : -356897.29 }, "selected" : false }, { "data" : { "id" : "2843", "station_name" : "吉祥寺", "close_ymd" : "", "lon" : 139.57976499999998, "post" : "180-0003", "e_status" : 0, "SUID" : 2843, "station_g_cd" : 1131104, "add" : "東京都武蔵野市吉祥寺南町", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131104", "pref_name" : "東京都", "shared_name" : "1131104", "lat" : 35.703119, "y" : -357031.19, "x" : 1395797.65 }, "position" : { "x" : 1395797.65, "y" : -357031.19 }, "selected" : false }, { "data" : { "id" : "2844", "station_name" : "三鷹", "close_ymd" : "", "lon" : 139.560325, "post" : "181-0013", "e_status" : 0, "SUID" : 2844, "station_g_cd" : 1131105, "add" : "東京都三鷹市下連雀三丁目46-1", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131105", "pref_name" : "東京都", "shared_name" : "1131105", "lat" : 35.702683, "y" : -357026.83, "x" : 1395603.25 }, "position" : { "x" : 1395603.25, "y" : -357026.83 }, "selected" : false }, { "data" : { "id" : "2840", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "100-0005", "e_status" : 0, "SUID" : 2840, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11311, "selected" : false, "open_ymd" : "", "name" : "1131101", "pref_name" : "東京都", "shared_name" : "1131101", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "2941", "station_name" : "新小岩", "close_ymd" : "", "lon" : 139.857777, "post" : "124-0024", "e_status" : 0, "SUID" : 2941, "station_g_cd" : 1131325, "add" : "葛飾区新小岩1丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131325", "pref_name" : "東京都", "shared_name" : "1131325", "lat" : 35.716903, "y" : -357169.03, "x" : 1398577.77 }, "position" : { "x" : 1398577.77, "y" : -357169.03 }, "selected" : false }, { "data" : { "id" : "2942", "station_name" : "小岩", "close_ymd" : "", "lon" : 139.881755, "post" : "133-0056", "e_status" : 0, "SUID" : 2942, "station_g_cd" : 1131326, "add" : "江戸川区南小岩7丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131326", "pref_name" : "東京都", "shared_name" : "1131326", "lat" : 35.733207, "y" : -357332.07, "x" : 1398817.55 }, "position" : { "x" : 1398817.55, "y" : -357332.07 }, "selected" : false }, { "data" : { "id" : "2935", "station_name" : "秋葉原", "close_ymd" : "", "lon" : 139.77328799999998, "post" : "101-0021", "e_status" : 0, "SUID" : 2935, "station_g_cd" : 1130222, "add" : "東京都千代田区外神田一丁目17-6", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131319", "pref_name" : "東京都", "shared_name" : "1131319", "lat" : 35.698619, "y" : -356986.19, "x" : 1397732.88 }, "position" : { "x" : 1397732.88, "y" : -356986.19 }, "selected" : false }, { "data" : { "id" : "2936", "station_name" : "浅草橋", "close_ymd" : "", "lon" : 139.784427, "post" : "111-0053", "e_status" : 0, "SUID" : 2936, "station_g_cd" : 1131320, "add" : "台東区浅草橋1丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131320", "pref_name" : "東京都", "shared_name" : "1131320", "lat" : 35.697403, "y" : -356974.03, "x" : 1397844.27 }, "position" : { "x" : 1397844.27, "y" : -356974.03 }, "selected" : false }, { "data" : { "id" : "2933", "station_name" : "水道橋", "close_ymd" : "", "lon" : 139.754312, "post" : "101-0061", "e_status" : 0, "SUID" : 2933, "station_g_cd" : 1131204, "add" : "千代田区三崎町2丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131317", "pref_name" : "東京都", "shared_name" : "1131317", "lat" : 35.702039, "y" : -357020.39, "x" : 1397543.1199999999 }, "position" : { "x" : 1397543.1199999999, "y" : -357020.39 }, "selected" : false }, { "data" : { "id" : "2934", "station_name" : "御茶ノ水", "close_ymd" : "", "lon" : 139.76495500000001, "post" : "101-0062", "e_status" : 0, "SUID" : 2934, "station_g_cd" : 1131203, "add" : "千代田区神田駿河台2丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131318", "pref_name" : "東京都", "shared_name" : "1131318", "lat" : 35.699605, "y" : -356996.05, "x" : 1397649.55 }, "position" : { "x" : 1397649.55, "y" : -356996.05 }, "selected" : false }, { "data" : { "id" : "2939", "station_name" : "亀戸", "close_ymd" : "", "lon" : 139.826262, "post" : "136-0071", "e_status" : 0, "SUID" : 2939, "station_g_cd" : 1131323, "add" : "江東区亀戸5丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131323", "pref_name" : "東京都", "shared_name" : "1131323", "lat" : 35.697345, "y" : -356973.45, "x" : 1398262.62 }, "position" : { "x" : 1398262.62, "y" : -356973.45 }, "selected" : false }, { "data" : { "id" : "2940", "station_name" : "平井", "close_ymd" : "", "lon" : 139.842181, "post" : "132-0035", "e_status" : 0, "SUID" : 2940, "station_g_cd" : 1131324, "add" : "江戸川区平井3丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131324", "pref_name" : "東京都", "shared_name" : "1131324", "lat" : 35.70643, "y" : -357064.3, "x" : 1398421.81 }, "position" : { "x" : 1398421.81, "y" : -357064.3 }, "selected" : false }, { "data" : { "id" : "2937", "station_name" : "両国", "close_ymd" : "", "lon" : 139.79333400000002, "post" : "130-0015", "e_status" : 0, "SUID" : 2937, "station_g_cd" : 1131321, "add" : "墨田区横網1丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131321", "pref_name" : "東京都", "shared_name" : "1131321", "lat" : 35.69579, "y" : -356957.9, "x" : 1397933.34 }, "position" : { "x" : 1397933.34, "y" : -356957.9 }, "selected" : false }, { "data" : { "id" : "2938", "station_name" : "錦糸町", "close_ymd" : "", "lon" : 139.81413600000002, "post" : "130-0022", "e_status" : 0, "SUID" : 2938, "station_g_cd" : 1131322, "add" : "墨田区江東橋3丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131322", "pref_name" : "東京都", "shared_name" : "1131322", "lat" : 35.696802000000005, "y" : -356968.0200000001, "x" : 1398141.36 }, "position" : { "x" : 1398141.36, "y" : -356968.0200000001 }, "selected" : false }, { "data" : { "id" : "2960", "station_name" : "新小岩", "close_ymd" : "", "lon" : 139.857777, "post" : "124-0024", "e_status" : 0, "SUID" : 2960, "station_g_cd" : 1131325, "add" : "葛飾区新小岩1丁目", "line_cd" : 11314, "selected" : false, "open_ymd" : "", "name" : "1131405", "pref_name" : "東京都", "shared_name" : "1131405", "lat" : 35.716903, "y" : -357169.03, "x" : 1398577.77 }, "position" : { "x" : 1398577.77, "y" : -357169.03 }, "selected" : false }, { "data" : { "id" : "2959", "station_name" : "錦糸町", "close_ymd" : "", "lon" : 139.81413600000002, "post" : "130-0022", "e_status" : 0, "SUID" : 2959, "station_g_cd" : 1131322, "add" : "墨田区江東橋3丁目", "line_cd" : 11314, "selected" : false, "open_ymd" : "", "name" : "1131404", "pref_name" : "東京都", "shared_name" : "1131404", "lat" : 35.696802000000005, "y" : -356968.0200000001, "x" : 1398141.36 }, "position" : { "x" : 1398141.36, "y" : -356968.0200000001 }, "selected" : false }, { "data" : { "id" : "2958", "station_name" : "馬喰町", "close_ymd" : "", "lon" : 139.78238000000002, "post" : "103-0002", "e_status" : 0, "SUID" : 2958, "station_g_cd" : 1131403, "add" : "中央区日本橋馬喰町1丁目", "line_cd" : 11314, "selected" : false, "open_ymd" : "", "name" : "1131403", "pref_name" : "東京都", "shared_name" : "1131403", "lat" : 35.693365, "y" : -356933.65, "x" : 1397823.8000000003 }, "position" : { "x" : 1397823.8000000003, "y" : -356933.65 }, "selected" : false }, { "data" : { "id" : "2957", "station_name" : "新日本橋", "close_ymd" : "", "lon" : 139.77323, "post" : "103-0022", "e_status" : 0, "SUID" : 2957, "station_g_cd" : 1131402, "add" : "中央区日本橋室町4丁目", "line_cd" : 11314, "selected" : false, "open_ymd" : "", "name" : "1131402", "pref_name" : "東京都", "shared_name" : "1131402", "lat" : 35.688687, "y" : -356886.87, "x" : 1397732.3 }, "position" : { "x" : 1397732.3, "y" : -356886.87 }, "selected" : false }, { "data" : { "id" : "2956", "station_name" : "東京", "close_ymd" : "", "lon" : 139.76610300000002, "post" : "100-0005", "e_status" : 0, "SUID" : 2956, "station_g_cd" : 1130101, "add" : "東京都千代田区丸の内一丁目", "line_cd" : 11314, "selected" : false, "open_ymd" : "", "name" : "1131401", "pref_name" : "東京都", "shared_name" : "1131401", "lat" : 35.681391, "y" : -356813.91, "x" : 1397661.0300000003 }, "position" : { "x" : 1397661.0300000003, "y" : -356813.91 }, "selected" : false }, { "data" : { "id" : "2909", "station_name" : "西国分寺", "close_ymd" : "", "lon" : 139.465994, "post" : "185-0013", "e_status" : 0, "SUID" : 2909, "station_g_cd" : 1130503, "add" : "国分寺市西恋ケ窪2丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131225", "pref_name" : "東京都", "shared_name" : "1131225", "lat" : 35.699744, "y" : -356997.44, "x" : 1394659.94 }, "position" : { "x" : 1394659.94, "y" : -356997.44 }, "selected" : false }, { "data" : { "id" : "2910", "station_name" : "国立", "close_ymd" : "", "lon" : 139.44634, "post" : "186-0001", "e_status" : 0, "SUID" : 2910, "station_g_cd" : 1131226, "add" : "国立市北1丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131226", "pref_name" : "東京都", "shared_name" : "1131226", "lat" : 35.69923, "y" : -356992.3, "x" : 1394463.4 }, "position" : { "x" : 1394463.4, "y" : -356992.3 }, "selected" : false }, { "data" : { "id" : "2911", "station_name" : "立川", "close_ymd" : "", "lon" : 139.413704, "post" : "190-0012", "e_status" : 0, "SUID" : 2911, "station_g_cd" : 1130325, "add" : "東京都立川市曙町二丁目1-1", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131227", "pref_name" : "東京都", "shared_name" : "1131227", "lat" : 35.698202, "y" : -356982.02, "x" : 1394137.04 }, "position" : { "x" : 1394137.04, "y" : -356982.02 }, "selected" : false }, { "data" : { "id" : "2912", "station_name" : "日野", "close_ymd" : "", "lon" : 139.39393, "post" : "191-0061", "e_status" : 0, "SUID" : 2912, "station_g_cd" : 1131108, "add" : "日野市大坂上1丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131228", "pref_name" : "東京都", "shared_name" : "1131228", "lat" : 35.679244, "y" : -356792.43999999994, "x" : 1393939.3 }, "position" : { "x" : 1393939.3, "y" : -356792.43999999994 }, "selected" : false }, { "data" : { "id" : "2913", "station_name" : "豊田", "close_ymd" : "", "lon" : 139.381495, "post" : "191-0053", "e_status" : 0, "SUID" : 2913, "station_g_cd" : 1131109, "add" : "日野市豊田4丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131229", "pref_name" : "東京都", "shared_name" : "1131229", "lat" : 35.659502, "y" : -356595.02, "x" : 1393814.95 }, "position" : { "x" : 1393814.95, "y" : -356595.02 }, "selected" : false }, { "data" : { "id" : "2914", "station_name" : "八王子", "close_ymd" : "", "lon" : 139.338998, "post" : "192-0083", "e_status" : 0, "SUID" : 2914, "station_g_cd" : 1130620, "add" : "東京都八王子市旭町1-1", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131230", "pref_name" : "東京都", "shared_name" : "1131230", "lat" : 35.655555, "y" : -356555.55, "x" : 1393389.98 }, "position" : { "x" : 1393389.98, "y" : -356555.55 }, "selected" : false }, { "data" : { "id" : "2915", "station_name" : "西八王子", "close_ymd" : "", "lon" : 139.31264, "post" : "193-0835", "e_status" : 0, "SUID" : 2915, "station_g_cd" : 1131111, "add" : "八王子市千人町2丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131231", "pref_name" : "東京都", "shared_name" : "1131231", "lat" : 35.656621, "y" : -356566.21, "x" : 1393126.4 }, "position" : { "x" : 1393126.4, "y" : -356566.21 }, "selected" : false }, { "data" : { "id" : "2916", "station_name" : "高尾", "close_ymd" : "", "lon" : 139.282288, "post" : "193-0844", "e_status" : 0, "SUID" : 2916, "station_g_cd" : 1131112, "add" : "八王子市高尾町", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131232", "pref_name" : "東京都", "shared_name" : "1131232", "lat" : 35.642026, "y" : -356420.26, "x" : 1392822.88 }, "position" : { "x" : 1392822.88, "y" : -356420.26 }, "selected" : false }, { "data" : { "id" : "2901", "station_name" : "荻窪", "close_ymd" : "", "lon" : 139.620109, "post" : "167-0043", "e_status" : 0, "SUID" : 2901, "station_g_cd" : 1131217, "add" : "杉並区上荻1丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131217", "pref_name" : "東京都", "shared_name" : "1131217", "lat" : 35.704522999999995, "y" : -357045.2299999999, "x" : 1396201.09 }, "position" : { "x" : 1396201.09, "y" : -357045.2299999999 }, "selected" : false }, { "data" : { "id" : "2902", "station_name" : "西荻窪", "close_ymd" : "", "lon" : 139.59936100000002, "post" : "167-0053", "e_status" : 0, "SUID" : 2902, "station_g_cd" : 1131218, "add" : "杉並区西荻南3丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131218", "pref_name" : "東京都", "shared_name" : "1131218", "lat" : 35.703842, "y" : -357038.42000000004, "x" : 1395993.61 }, "position" : { "x" : 1395993.61, "y" : -357038.42000000004 }, "selected" : false }, { "data" : { "id" : "2903", "station_name" : "吉祥寺", "close_ymd" : "", "lon" : 139.57976499999998, "post" : "180-0003", "e_status" : 0, "SUID" : 2903, "station_g_cd" : 1131104, "add" : "東京都武蔵野市吉祥寺南町", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131219", "pref_name" : "東京都", "shared_name" : "1131219", "lat" : 35.703119, "y" : -357031.19, "x" : 1395797.65 }, "position" : { "x" : 1395797.65, "y" : -357031.19 }, "selected" : false }, { "data" : { "id" : "2904", "station_name" : "三鷹", "close_ymd" : "", "lon" : 139.560325, "post" : "181-0013", "e_status" : 0, "SUID" : 2904, "station_g_cd" : 1131105, "add" : "東京都三鷹市下連雀三丁目46-1", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131220", "pref_name" : "東京都", "shared_name" : "1131220", "lat" : 35.702683, "y" : -357026.83, "x" : 1395603.25 }, "position" : { "x" : 1395603.25, "y" : -357026.83 }, "selected" : false }, { "data" : { "id" : "2905", "station_name" : "武蔵境", "close_ymd" : "", "lon" : 139.54340200000001, "post" : "180-0022", "e_status" : 0, "SUID" : 2905, "station_g_cd" : 1131221, "add" : "武蔵野市境1丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131221", "pref_name" : "東京都", "shared_name" : "1131221", "lat" : 35.702083, "y" : -357020.83, "x" : 1395434.0200000003 }, "position" : { "x" : 1395434.0200000003, "y" : -357020.83 }, "selected" : false }, { "data" : { "id" : "2906", "station_name" : "東小金井", "close_ymd" : "", "lon" : 139.52483700000002, "post" : "184-0002", "e_status" : 0, "SUID" : 2906, "station_g_cd" : 1131222, "add" : "小金井市梶野町5丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131222", "pref_name" : "東京都", "shared_name" : "1131222", "lat" : 35.701643, "y" : -357016.43, "x" : 1395248.37 }, "position" : { "x" : 1395248.37, "y" : -357016.43 }, "selected" : false }, { "data" : { "id" : "2907", "station_name" : "武蔵小金井", "close_ymd" : "", "lon" : 139.506483, "post" : "184-0004", "e_status" : 0, "SUID" : 2907, "station_g_cd" : 1131223, "add" : "小金井市本町6丁目", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131223", "pref_name" : "東京都", "shared_name" : "1131223", "lat" : 35.701337, "y" : -357013.37, "x" : 1395064.83 }, "position" : { "x" : 1395064.83, "y" : -357013.37 }, "selected" : false }, { "data" : { "id" : "2908", "station_name" : "国分寺", "close_ymd" : "", "lon" : 139.480841, "post" : "185-0012", "e_status" : 0, "SUID" : 2908, "station_g_cd" : 1131106, "add" : "東京都国分寺市本町二丁目1-23", "line_cd" : 11312, "selected" : false, "open_ymd" : "", "name" : "1131224", "pref_name" : "東京都", "shared_name" : "1131224", "lat" : 35.700123, "y" : -357001.23, "x" : 1394808.41 }, "position" : { "x" : 1394808.41, "y" : -357001.23 }, "selected" : false }, { "data" : { "id" : "2926", "station_name" : "新宿", "close_ymd" : "", "lon" : 139.70046399999998, "post" : "160-0022", "e_status" : 0, "SUID" : 2926, "station_g_cd" : 1130208, "add" : "東京都新宿区新宿三丁目38-1", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131310", "pref_name" : "東京都", "shared_name" : "1131310", "lat" : 35.689729, "y" : -356897.29, "x" : 1397004.64 }, "position" : { "x" : 1397004.64, "y" : -356897.29 }, "selected" : false }, { "data" : { "id" : "2925", "station_name" : "大久保", "close_ymd" : "", "lon" : 139.69732, "post" : "169-0073", "e_status" : 0, "SUID" : 2925, "station_g_cd" : 1131212, "add" : "新宿区百人町1丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131309", "pref_name" : "東京都", "shared_name" : "1131309", "lat" : 35.700784000000006, "y" : -357007.8400000001, "x" : 1396973.2 }, "position" : { "x" : 1396973.2, "y" : -357007.8400000001 }, "selected" : false }, { "data" : { "id" : "2928", "station_name" : "千駄ケ谷", "close_ymd" : "", "lon" : 139.711644, "post" : "151-0051", "e_status" : 0, "SUID" : 2928, "station_g_cd" : 1131209, "add" : "東京都渋谷区千駄ヶ谷一丁目35-10", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131312", "pref_name" : "東京都", "shared_name" : "1131312", "lat" : 35.681231, "y" : -356812.30999999994, "x" : 1397116.4400000002 }, "position" : { "x" : 1397116.4400000002, "y" : -356812.30999999994 }, "selected" : false }, { "data" : { "id" : "2927", "station_name" : "代々木", "close_ymd" : "", "lon" : 139.702042, "post" : "151-0053", "e_status" : 0, "SUID" : 2927, "station_g_cd" : 1130207, "add" : "東京都渋谷区代々木一丁目34-1", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131311", "pref_name" : "東京都", "shared_name" : "1131311", "lat" : 35.683061, "y" : -356830.61000000004, "x" : 1397020.4200000002 }, "position" : { "x" : 1397020.4200000002, "y" : -356830.61000000004 }, "selected" : false }, { "data" : { "id" : "2930", "station_name" : "四ツ谷", "close_ymd" : "", "lon" : 139.73064399999998, "post" : "160-0004", "e_status" : 0, "SUID" : 2930, "station_g_cd" : 1131102, "add" : "東京都新宿区四谷一丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131314", "pref_name" : "東京都", "shared_name" : "1131314", "lat" : 35.686040999999996, "y" : -356860.41, "x" : 1397306.44 }, "position" : { "x" : 1397306.44, "y" : -356860.41 }, "selected" : false }, { "data" : { "id" : "2929", "station_name" : "信濃町", "close_ymd" : "", "lon" : 139.720729, "post" : "160-0016", "e_status" : 0, "SUID" : 2929, "station_g_cd" : 1131208, "add" : "新宿区信濃町", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131313", "pref_name" : "東京都", "shared_name" : "1131313", "lat" : 35.680031, "y" : -356800.31, "x" : 1397207.29 }, "position" : { "x" : 1397207.29, "y" : -356800.31 }, "selected" : false }, { "data" : { "id" : "2932", "station_name" : "飯田橋", "close_ymd" : "", "lon" : 139.74514299999998, "post" : "102-0072", "e_status" : 0, "SUID" : 2932, "station_g_cd" : 1131205, "add" : "東京都千代田区飯田橋四丁目10-2", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131316", "pref_name" : "東京都", "shared_name" : "1131316", "lat" : 35.701834999999996, "y" : -357018.35, "x" : 1397451.43 }, "position" : { "x" : 1397451.43, "y" : -357018.35 }, "selected" : false }, { "data" : { "id" : "2931", "station_name" : "市ケ谷", "close_ymd" : "", "lon" : 139.735241, "post" : "162-0843", "e_status" : 0, "SUID" : 2931, "station_g_cd" : 1131206, "add" : "東京都新宿区市谷田町一丁目1", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131315", "pref_name" : "東京都", "shared_name" : "1131315", "lat" : 35.691105, "y" : -356911.05, "x" : 1397352.41 }, "position" : { "x" : 1397352.41, "y" : -356911.05 }, "selected" : false }, { "data" : { "id" : "2918", "station_name" : "吉祥寺", "close_ymd" : "", "lon" : 139.57976499999998, "post" : "180-0003", "e_status" : 0, "SUID" : 2918, "station_g_cd" : 1131104, "add" : "東京都武蔵野市吉祥寺南町", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131302", "pref_name" : "東京都", "shared_name" : "1131302", "lat" : 35.703119, "y" : -357031.19, "x" : 1395797.65 }, "position" : { "x" : 1395797.65, "y" : -357031.19 }, "selected" : false }, { "data" : { "id" : "2917", "station_name" : "三鷹", "close_ymd" : "", "lon" : 139.560325, "post" : "181-0013", "e_status" : 0, "SUID" : 2917, "station_g_cd" : 1131105, "add" : "東京都三鷹市下連雀三丁目46-1", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131301", "pref_name" : "東京都", "shared_name" : "1131301", "lat" : 35.702683, "y" : -357026.83, "x" : 1395603.25 }, "position" : { "x" : 1395603.25, "y" : -357026.83 }, "selected" : false }, { "data" : { "id" : "2920", "station_name" : "荻窪", "close_ymd" : "", "lon" : 139.620109, "post" : "167-0043", "e_status" : 0, "SUID" : 2920, "station_g_cd" : 1131217, "add" : "杉並区上荻1丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131304", "pref_name" : "東京都", "shared_name" : "1131304", "lat" : 35.704522999999995, "y" : -357045.2299999999, "x" : 1396201.09 }, "position" : { "x" : 1396201.09, "y" : -357045.2299999999 }, "selected" : false }, { "data" : { "id" : "2919", "station_name" : "西荻窪", "close_ymd" : "", "lon" : 139.59936100000002, "post" : "167-0053", "e_status" : 0, "SUID" : 2919, "station_g_cd" : 1131218, "add" : "杉並区西荻南3丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131303", "pref_name" : "東京都", "shared_name" : "1131303", "lat" : 35.703842, "y" : -357038.42000000004, "x" : 1395993.61 }, "position" : { "x" : 1395993.61, "y" : -357038.42000000004 }, "selected" : false }, { "data" : { "id" : "2922", "station_name" : "高円寺", "close_ymd" : "", "lon" : 139.649664, "post" : "166-0003", "e_status" : 0, "SUID" : 2922, "station_g_cd" : 1131215, "add" : "杉並区高円寺南4丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131306", "pref_name" : "東京都", "shared_name" : "1131306", "lat" : 35.705326, "y" : -357053.26, "x" : 1396496.64 }, "position" : { "x" : 1396496.64, "y" : -357053.26 }, "selected" : false }, { "data" : { "id" : "2921", "station_name" : "阿佐ケ谷", "close_ymd" : "", "lon" : 139.635868, "post" : "166-0004", "e_status" : 0, "SUID" : 2921, "station_g_cd" : 1131216, "add" : "東京都杉並区阿佐谷南三丁目36-2", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131305", "pref_name" : "東京都", "shared_name" : "1131305", "lat" : 35.704817999999996, "y" : -357048.17999999993, "x" : 1396358.68 }, "position" : { "x" : 1396358.68, "y" : -357048.17999999993 }, "selected" : false }, { "data" : { "id" : "2924", "station_name" : "東中野", "close_ymd" : "", "lon" : 139.684436, "post" : "164-0003", "e_status" : 0, "SUID" : 2924, "station_g_cd" : 1131213, "add" : "中野区東中野4丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131308", "pref_name" : "東京都", "shared_name" : "1131308", "lat" : 35.706528999999996, "y" : -357065.29, "x" : 1396844.36 }, "position" : { "x" : 1396844.36, "y" : -357065.29 }, "selected" : false }, { "data" : { "id" : "2923", "station_name" : "中野", "close_ymd" : "", "lon" : 139.66583500000002, "post" : "164-0001", "e_status" : 0, "SUID" : 2923, "station_g_cd" : 1131214, "add" : "中野区中野5丁目", "line_cd" : 11313, "selected" : false, "open_ymd" : "", "name" : "1131307", "pref_name" : "東京都", "shared_name" : "1131307", "lat" : 35.705765, "y" : -357057.65, "x" : 1396658.35 }, "position" : { "x" : 1396658.35, "y" : -357057.65 }, "selected" : false }, { "data" : { "id" : "3004", "station_name" : "軍畑", "close_ymd" : "", "lon" : 139.207431, "post" : "198-0172", "e_status" : 0, "SUID" : 3004, "station_g_cd" : 1131518, "add" : "青梅市沢井1丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131518", "pref_name" : "東京都", "shared_name" : "1131518", "lat" : 35.807382000000004, "y" : -358073.82000000007, "x" : 1392074.31 }, "position" : { "x" : 1392074.31, "y" : -358073.82000000007 }, "selected" : false }, { "data" : { "id" : "3003", "station_name" : "二俣尾", "close_ymd" : "", "lon" : 139.216161, "post" : "198-0171", "e_status" : 0, "SUID" : 3003, "station_g_cd" : 1131517, "add" : "青梅市二俣尾4丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131517", "pref_name" : "東京都", "shared_name" : "1131517", "lat" : 35.803946, "y" : -358039.46, "x" : 1392161.61 }, "position" : { "x" : 1392161.61, "y" : -358039.46 }, "selected" : false }, { "data" : { "id" : "3002", "station_name" : "石神前", "close_ymd" : "", "lon" : 139.225096, "post" : "198-0171", "e_status" : 0, "SUID" : 3002, "station_g_cd" : 1131516, "add" : "青梅市二俣尾1丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131516", "pref_name" : "東京都", "shared_name" : "1131516", "lat" : 35.79683, "y" : -357968.3, "x" : 1392250.96 }, "position" : { "x" : 1392250.96, "y" : -357968.3 }, "selected" : false }, { "data" : { "id" : "3001", "station_name" : "日向和田", "close_ymd" : "", "lon" : 139.229515, "post" : "198-0046", "e_status" : 0, "SUID" : 3001, "station_g_cd" : 1131515, "add" : "青梅市日向和田3丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131515", "pref_name" : "東京都", "shared_name" : "1131515", "lat" : 35.788665, "y" : -357886.65, "x" : 1392295.15 }, "position" : { "x" : 1392295.15, "y" : -357886.65 }, "selected" : false }, { "data" : { "id" : "3000", "station_name" : "宮ノ平", "close_ymd" : "", "lon" : 139.23728899999998, "post" : "198-0046", "e_status" : 0, "SUID" : 3000, "station_g_cd" : 1131514, "add" : "青梅市日向和田2丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131514", "pref_name" : "東京都", "shared_name" : "1131514", "lat" : 35.787545, "y" : -357875.45, "x" : 1392372.8899999997 }, "position" : { "x" : 1392372.8899999997, "y" : -357875.45 }, "selected" : false }, { "data" : { "id" : "2999", "station_name" : "青梅", "close_ymd" : "", "lon" : 139.258096, "post" : "198-0000", "e_status" : 0, "SUID" : 2999, "station_g_cd" : 1131513, "add" : "青梅市青梅", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131513", "pref_name" : "東京都", "shared_name" : "1131513", "lat" : 35.790512, "y" : -357905.12, "x" : 1392580.96 }, "position" : { "x" : 1392580.96, "y" : -357905.12 }, "selected" : false }, { "data" : { "id" : "2998", "station_name" : "東青梅", "close_ymd" : "", "lon" : 139.272841, "post" : "198-0042", "e_status" : 0, "SUID" : 2998, "station_g_cd" : 1131512, "add" : "青梅市東青梅1丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131512", "pref_name" : "東京都", "shared_name" : "1131512", "lat" : 35.789768, "y" : -357897.68000000005, "x" : 1392728.41 }, "position" : { "x" : 1392728.41, "y" : -357897.68000000005 }, "selected" : false }, { "data" : { "id" : "2997", "station_name" : "河辺", "close_ymd" : "", "lon" : 139.284032, "post" : "198-0036", "e_status" : 0, "SUID" : 2997, "station_g_cd" : 1131511, "add" : "青梅市河辺町5丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131511", "pref_name" : "東京都", "shared_name" : "1131511", "lat" : 35.784729999999996, "y" : -357847.3, "x" : 1392840.32 }, "position" : { "x" : 1392840.32, "y" : -357847.3 }, "selected" : false }, { "data" : { "id" : "3012", "station_name" : "拝島", "close_ymd" : "", "lon" : 139.343468, "post" : "196-0003", "e_status" : 0, "SUID" : 3012, "station_g_cd" : 1131506, "add" : "昭島市松原町4丁目", "line_cd" : 11316, "selected" : false, "open_ymd" : "", "name" : "1131601", "pref_name" : "東京都", "shared_name" : "1131601", "lat" : 35.721278000000005, "y" : -357212.78, "x" : 1393434.68 }, "position" : { "x" : 1393434.68, "y" : -357212.78 }, "selected" : false }, { "data" : { "id" : "3011", "station_name" : "奥多摩", "close_ymd" : "", "lon" : 139.09696100000002, "post" : "198-0212", "e_status" : 0, "SUID" : 3011, "station_g_cd" : 1131525, "add" : "西多摩郡奥多摩町氷川", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131525", "pref_name" : "東京都", "shared_name" : "1131525", "lat" : 35.809357, "y" : -358093.57, "x" : 1390969.61 }, "position" : { "x" : 1390969.61, "y" : -358093.57 }, "selected" : false }, { "data" : { "id" : "3010", "station_name" : "白丸", "close_ymd" : "", "lon" : 139.11486100000002, "post" : "198-0107", "e_status" : 0, "SUID" : 3010, "station_g_cd" : 1131524, "add" : "西多摩郡奥多摩町白丸", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131524", "pref_name" : "東京都", "shared_name" : "1131524", "lat" : 35.811735, "y" : -358117.35, "x" : 1391148.61 }, "position" : { "x" : 1391148.61, "y" : -358117.35 }, "selected" : false }, { "data" : { "id" : "3009", "station_name" : "鳩ノ巣", "close_ymd" : "", "lon" : 139.12893200000002, "post" : "198-0106", "e_status" : 0, "SUID" : 3009, "station_g_cd" : 1131523, "add" : "西多摩郡奥多摩町棚沢", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131523", "pref_name" : "東京都", "shared_name" : "1131523", "lat" : 35.815127000000004, "y" : -358151.27, "x" : 1391289.3200000003 }, "position" : { "x" : 1391289.3200000003, "y" : -358151.27 }, "selected" : false }, { "data" : { "id" : "3008", "station_name" : "古里", "close_ymd" : "", "lon" : 139.152102, "post" : "198-0105", "e_status" : 0, "SUID" : 3008, "station_g_cd" : 1131522, "add" : "西多摩郡奥多摩町小丹波", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131522", "pref_name" : "東京都", "shared_name" : "1131522", "lat" : 35.816247, "y" : -358162.47, "x" : 1391521.02 }, "position" : { "x" : 1391521.02, "y" : -358162.47 }, "selected" : false }, { "data" : { "id" : "3007", "station_name" : "川井", "close_ymd" : "", "lon" : 139.16429, "post" : "198-0102", "e_status" : 0, "SUID" : 3007, "station_g_cd" : 1131521, "add" : "西多摩郡奥多摩町川井", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131521", "pref_name" : "東京都", "shared_name" : "1131521", "lat" : 35.813697, "y" : -358136.97, "x" : 1391642.9 }, "position" : { "x" : 1391642.9, "y" : -358136.97 }, "selected" : false }, { "data" : { "id" : "3006", "station_name" : "御嶽", "close_ymd" : "", "lon" : 139.18258899999998, "post" : "198-0173", "e_status" : 0, "SUID" : 3006, "station_g_cd" : 1131520, "add" : "青梅市御岳本町", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131520", "pref_name" : "東京都", "shared_name" : "1131520", "lat" : 35.801468, "y" : -358014.68, "x" : 1391825.89 }, "position" : { "x" : 1391825.89, "y" : -358014.68 }, "selected" : false }, { "data" : { "id" : "3005", "station_name" : "沢井", "close_ymd" : "", "lon" : 139.193324, "post" : "198-0172", "e_status" : 0, "SUID" : 3005, "station_g_cd" : 1131519, "add" : "青梅市沢井2丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131519", "pref_name" : "東京都", "shared_name" : "1131519", "lat" : 35.80594, "y" : -358059.4, "x" : 1391933.24 }, "position" : { "x" : 1391933.24, "y" : -358059.4 }, "selected" : false }, { "data" : { "id" : "3019", "station_name" : "八王子", "close_ymd" : "", "lon" : 139.338998, "post" : "192-0083", "e_status" : 0, "SUID" : 3019, "station_g_cd" : 1130620, "add" : "東京都八王子市旭町1-1", "line_cd" : 11317, "selected" : false, "open_ymd" : "", "name" : "1131701", "pref_name" : "東京都", "shared_name" : "1131701", "lat" : 35.655555, "y" : -356555.55, "x" : 1393389.98 }, "position" : { "x" : 1393389.98, "y" : -356555.55 }, "selected" : false }, { "data" : { "id" : "3020", "station_name" : "北八王子", "close_ymd" : "", "lon" : 139.363348, "post" : "192-0032", "e_status" : 0, "SUID" : 3020, "station_g_cd" : 1131702, "add" : "八王子市石川町", "line_cd" : 11317, "selected" : false, "open_ymd" : "", "name" : "1131702", "pref_name" : "東京都", "shared_name" : "1131702", "lat" : 35.669232, "y" : -356692.32, "x" : 1393633.48 }, "position" : { "x" : 1393633.48, "y" : -356692.32 }, "selected" : false }, { "data" : { "id" : "3017", "station_name" : "武蔵増戸", "close_ymd" : "", "lon" : 139.256355, "post" : "190-0142", "e_status" : 0, "SUID" : 3017, "station_g_cd" : 1131606, "add" : "あきる野市伊奈", "line_cd" : 11316, "selected" : false, "open_ymd" : "", "name" : "1131606", "pref_name" : "東京都", "shared_name" : "1131606", "lat" : 35.730961, "y" : -357309.61, "x" : 1392563.55 }, "position" : { "x" : 1392563.55, "y" : -357309.61 }, "selected" : false }, { "data" : { "id" : "3018", "station_name" : "武蔵五日市", "close_ymd" : "", "lon" : 139.228039, "post" : "190-0163", "e_status" : 0, "SUID" : 3018, "station_g_cd" : 1131607, "add" : "あきる野市舘谷", "line_cd" : 11316, "selected" : false, "open_ymd" : "", "name" : "1131607", "pref_name" : "東京都", "shared_name" : "1131607", "lat" : 35.732248, "y" : -357322.48, "x" : 1392280.39 }, "position" : { "x" : 1392280.39, "y" : -357322.48 }, "selected" : false }, { "data" : { "id" : "3015", "station_name" : "秋川", "close_ymd" : "", "lon" : 139.286715, "post" : "197-0827", "e_status" : 0, "SUID" : 3015, "station_g_cd" : 1131604, "add" : "あきる野市油平", "line_cd" : 11316, "selected" : false, "open_ymd" : "", "name" : "1131604", "pref_name" : "東京都", "shared_name" : "1131604", "lat" : 35.727998, "y" : -357279.98, "x" : 1392867.15 }, "position" : { "x" : 1392867.15, "y" : -357279.98 }, "selected" : false }, { "data" : { "id" : "3016", "station_name" : "武蔵引田", "close_ymd" : "", "lon" : 139.26990700000002, "post" : "190-0100", "e_status" : 0, "SUID" : 3016, "station_g_cd" : 1131605, "add" : "あきる野市下引田", "line_cd" : 11316, "selected" : false, "open_ymd" : "", "name" : "1131605", "pref_name" : "東京都", "shared_name" : "1131605", "lat" : 35.729711, "y" : -357297.11000000004, "x" : 1392699.07 }, "position" : { "x" : 1392699.07, "y" : -357297.11000000004 }, "selected" : false }, { "data" : { "id" : "3013", "station_name" : "熊川", "close_ymd" : "", "lon" : 139.33584, "post" : "197-0003", "e_status" : 0, "SUID" : 3013, "station_g_cd" : 1131602, "add" : "福生市熊川北", "line_cd" : 11316, "selected" : false, "open_ymd" : "", "name" : "1131602", "pref_name" : "東京都", "shared_name" : "1131602", "lat" : 35.728321, "y" : -357283.21, "x" : 1393358.4 }, "position" : { "x" : 1393358.4, "y" : -357283.21 }, "selected" : false }, { "data" : { "id" : "3014", "station_name" : "東秋留", "close_ymd" : "", "lon" : 139.31166499999998, "post" : "197-0823", "e_status" : 0, "SUID" : 3014, "station_g_cd" : 1131603, "add" : "あきる野市野辺", "line_cd" : 11316, "selected" : false, "open_ymd" : "", "name" : "1131603", "pref_name" : "東京都", "shared_name" : "1131603", "lat" : 35.725904, "y" : -357259.04, "x" : 1393116.6499999997 }, "position" : { "x" : 1393116.6499999997, "y" : -357259.04 }, "selected" : false }, { "data" : { "id" : "3023", "station_name" : "東福生", "close_ymd" : "", "lon" : 139.33594, "post" : "197-0013", "e_status" : 0, "SUID" : 3023, "station_g_cd" : 1131705, "add" : "福生市武蔵野台1丁目", "line_cd" : 11317, "selected" : false, "open_ymd" : "", "name" : "1131705", "pref_name" : "東京都", "shared_name" : "1131705", "lat" : 35.745810999999996, "y" : -357458.11, "x" : 1393359.4 }, "position" : { "x" : 1393359.4, "y" : -357458.11 }, "selected" : false }, { "data" : { "id" : "3024", "station_name" : "箱根ケ崎", "close_ymd" : "", "lon" : 139.34680500000002, "post" : "190-1221", "e_status" : 0, "SUID" : 3024, "station_g_cd" : 1131706, "add" : "東京都西多摩郡瑞穂町大字箱根ケ崎397", "line_cd" : 11317, "selected" : false, "open_ymd" : "", "name" : "1131706", "pref_name" : "東京都", "shared_name" : "1131706", "lat" : 35.771158, "y" : -357711.58, "x" : 1393468.0500000003 }, "position" : { "x" : 1393468.0500000003, "y" : -357711.58 }, "selected" : false }, { "data" : { "id" : "3021", "station_name" : "小宮", "close_ymd" : "", "lon" : 139.368481, "post" : "192-0031", "e_status" : 0, "SUID" : 3021, "station_g_cd" : 1131703, "add" : "八王子市小宮町", "line_cd" : 11317, "selected" : false, "open_ymd" : "", "name" : "1131703", "pref_name" : "東京都", "shared_name" : "1131703", "lat" : 35.685798999999996, "y" : -356857.98999999993, "x" : 1393684.81 }, "position" : { "x" : 1393684.81, "y" : -356857.98999999993 }, "selected" : false }, { "data" : { "id" : "3022", "station_name" : "拝島", "close_ymd" : "", "lon" : 139.343468, "post" : "196-0003", "e_status" : 0, "SUID" : 3022, "station_g_cd" : 1131506, "add" : "昭島市松原町4丁目", "line_cd" : 11317, "selected" : false, "open_ymd" : "", "name" : "1131704", "pref_name" : "東京都", "shared_name" : "1131704", "lat" : 35.721278000000005, "y" : -357212.78, "x" : 1393434.68 }, "position" : { "x" : 1393434.68, "y" : -357212.78 }, "selected" : false }, { "data" : { "id" : "2987", "station_name" : "立川", "close_ymd" : "", "lon" : 139.413704, "post" : "190-0012", "e_status" : 0, "SUID" : 2987, "station_g_cd" : 1130325, "add" : "東京都立川市曙町二丁目1-1", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131501", "pref_name" : "東京都", "shared_name" : "1131501", "lat" : 35.698202, "y" : -356982.02, "x" : 1394137.04 }, "position" : { "x" : 1394137.04, "y" : -356982.02 }, "selected" : false }, { "data" : { "id" : "2988", "station_name" : "西立川", "close_ymd" : "", "lon" : 139.39355600000002, "post" : "190-0013", "e_status" : 0, "SUID" : 2988, "station_g_cd" : 1131502, "add" : "立川市富士見町1丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131502", "pref_name" : "東京都", "shared_name" : "1131502", "lat" : 35.703526000000004, "y" : -357035.26, "x" : 1393935.5600000003 }, "position" : { "x" : 1393935.5600000003, "y" : -357035.26 }, "selected" : false }, { "data" : { "id" : "2993", "station_name" : "牛浜", "close_ymd" : "", "lon" : 139.333677, "post" : "197-0024", "e_status" : 0, "SUID" : 2993, "station_g_cd" : 1131507, "add" : "福生市牛浜", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131507", "pref_name" : "東京都", "shared_name" : "1131507", "lat" : 35.734547, "y" : -357345.47, "x" : 1393336.77 }, "position" : { "x" : 1393336.77, "y" : -357345.47 }, "selected" : false }, { "data" : { "id" : "2994", "station_name" : "福生", "close_ymd" : "", "lon" : 139.32776299999998, "post" : "197-0022", "e_status" : 0, "SUID" : 2994, "station_g_cd" : 1131508, "add" : "福生市本町", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131508", "pref_name" : "東京都", "shared_name" : "1131508", "lat" : 35.742456, "y" : -357424.56, "x" : 1393277.6299999997 }, "position" : { "x" : 1393277.6299999997, "y" : -357424.56 }, "selected" : false }, { "data" : { "id" : "2995", "station_name" : "羽村", "close_ymd" : "", "lon" : 139.31618799999998, "post" : "205-0014", "e_status" : 0, "SUID" : 2995, "station_g_cd" : 1131509, "add" : "羽村市羽東1丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131509", "pref_name" : "東京都", "shared_name" : "1131509", "lat" : 35.758072999999996, "y" : -357580.73, "x" : 1393161.88 }, "position" : { "x" : 1393161.88, "y" : -357580.73 }, "selected" : false }, { "data" : { "id" : "2996", "station_name" : "小作", "close_ymd" : "", "lon" : 139.302233, "post" : "205-0001", "e_status" : 0, "SUID" : 2996, "station_g_cd" : 1131510, "add" : "羽村市小作台", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131510", "pref_name" : "東京都", "shared_name" : "1131510", "lat" : 35.776047999999996, "y" : -357760.48, "x" : 1393022.33 }, "position" : { "x" : 1393022.33, "y" : -357760.48 }, "selected" : false }, { "data" : { "id" : "2989", "station_name" : "東中神", "close_ymd" : "", "lon" : 139.38452900000001, "post" : "196-0034", "e_status" : 0, "SUID" : 2989, "station_g_cd" : 1131503, "add" : "昭島市玉川町1丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131503", "pref_name" : "東京都", "shared_name" : "1131503", "lat" : 35.706337, "y" : -357063.37, "x" : 1393845.29 }, "position" : { "x" : 1393845.29, "y" : -357063.37 }, "selected" : false }, { "data" : { "id" : "2990", "station_name" : "中神", "close_ymd" : "", "lon" : 139.375816, "post" : "196-0025", "e_status" : 0, "SUID" : 2990, "station_g_cd" : 1131504, "add" : "昭島市朝日町1丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131504", "pref_name" : "東京都", "shared_name" : "1131504", "lat" : 35.709058, "y" : -357090.58, "x" : 1393758.16 }, "position" : { "x" : 1393758.16, "y" : -357090.58 }, "selected" : false }, { "data" : { "id" : "2991", "station_name" : "昭島", "close_ymd" : "", "lon" : 139.361564, "post" : "196-0015", "e_status" : 0, "SUID" : 2991, "station_g_cd" : 1131505, "add" : "昭島市昭和町2丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131505", "pref_name" : "東京都", "shared_name" : "1131505", "lat" : 35.713305, "y" : -357133.05, "x" : 1393615.64 }, "position" : { "x" : 1393615.64, "y" : -357133.05 }, "selected" : false }, { "data" : { "id" : "2992", "station_name" : "拝島", "close_ymd" : "", "lon" : 139.343468, "post" : "196-0003", "e_status" : 0, "SUID" : 2992, "station_g_cd" : 1131506, "add" : "昭島市松原町4丁目", "line_cd" : 11315, "selected" : false, "open_ymd" : "", "name" : "1131506", "pref_name" : "東京都", "shared_name" : "1131506", "lat" : 35.721278000000005, "y" : -357212.78, "x" : 1393434.68 }, "position" : { "x" : 1393434.68, "y" : -357212.78 }, "selected" : false }, { "data" : { "id" : "3079", "station_name" : "三河島", "close_ymd" : "", "lon" : 139.777131, "post" : "116-0013", "e_status" : 0, "SUID" : 3079, "station_g_cd" : 1132003, "add" : "荒川区西日暮里1丁目", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132003", "pref_name" : "東京都", "shared_name" : "1132003", "lat" : 35.733383, "y" : -357333.83, "x" : 1397771.31 }, "position" : { "x" : 1397771.31, "y" : -357333.83 }, "selected" : false }, { "data" : { "id" : "3080", "station_name" : "南千住", "close_ymd" : "", "lon" : 139.7994, "post" : "116-0003", "e_status" : 0, "SUID" : 3080, "station_g_cd" : 1132004, "add" : "荒川区南千住4丁目", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132004", "pref_name" : "東京都", "shared_name" : "1132004", "lat" : 35.734033000000004, "y" : -357340.33, "x" : 1397994.0 }, "position" : { "x" : 1397994.0, "y" : -357340.33 }, "selected" : false }, { "data" : { "id" : "3077", "station_name" : "上野", "close_ymd" : "", "lon" : 139.777043, "post" : "110-0005", "e_status" : 0, "SUID" : 3077, "station_g_cd" : 1130220, "add" : "東京都台東区上野七丁目1-1", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132001", "pref_name" : "東京都", "shared_name" : "1132001", "lat" : 35.71379, "y" : -357137.9, "x" : 1397770.43 }, "position" : { "x" : 1397770.43, "y" : -357137.9 }, "selected" : false }, { "data" : { "id" : "3078", "station_name" : "日暮里", "close_ymd" : "", "lon" : 139.771287, "post" : "116-0013", "e_status" : 0, "SUID" : 3078, "station_g_cd" : 1130218, "add" : "東京都荒川区西日暮里二丁目", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132002", "pref_name" : "東京都", "shared_name" : "1132002", "lat" : 35.727908, "y" : -357279.08, "x" : 1397712.87 }, "position" : { "x" : 1397712.87, "y" : -357279.08 }, "selected" : false }, { "data" : { "id" : "3083", "station_name" : "亀有", "close_ymd" : "", "lon" : 139.847573, "post" : "125-0061", "e_status" : 0, "SUID" : 3083, "station_g_cd" : 1132007, "add" : "葛飾区亀有3", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132007", "pref_name" : "東京都", "shared_name" : "1132007", "lat" : 35.766527, "y" : -357665.27, "x" : 1398475.7300000002 }, "position" : { "x" : 1398475.7300000002, "y" : -357665.27 }, "selected" : false }, { "data" : { "id" : "3084", "station_name" : "金町", "close_ymd" : "", "lon" : 139.870482, "post" : "125-0042", "e_status" : 0, "SUID" : 3084, "station_g_cd" : 1132008, "add" : "葛飾区金町6丁目", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132008", "pref_name" : "東京都", "shared_name" : "1132008", "lat" : 35.769582, "y" : -357695.82, "x" : 1398704.82 }, "position" : { "x" : 1398704.82, "y" : -357695.82 }, "selected" : false }, { "data" : { "id" : "3081", "station_name" : "北千住", "close_ymd" : "", "lon" : 139.804872, "post" : "120-0026", "e_status" : 0, "SUID" : 3081, "station_g_cd" : 1132005, "add" : "足立区千住旭町", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132005", "pref_name" : "東京都", "shared_name" : "1132005", "lat" : 35.749677, "y" : -357496.76999999996, "x" : 1398048.72 }, "position" : { "x" : 1398048.72, "y" : -357496.76999999996 }, "selected" : false }, { "data" : { "id" : "3082", "station_name" : "綾瀬", "close_ymd" : "", "lon" : 139.825019, "post" : "120-0005", "e_status" : 0, "SUID" : 3082, "station_g_cd" : 1132006, "add" : "足立区綾瀬3丁目", "line_cd" : 11320, "selected" : false, "open_ymd" : "", "name" : "1132006", "pref_name" : "東京都", "shared_name" : "1132006", "lat" : 35.762221999999994, "y" : -357622.2199999999, "x" : 1398250.19 }, "position" : { "x" : 1398250.19, "y" : -357622.2199999999 }, "selected" : false }, { "data" : { "id" : "3044", "station_name" : "上野", "close_ymd" : "", "lon" : 139.777043, "post" : "110-0005", "e_status" : 0, "SUID" : 3044, "station_g_cd" : 1130220, "add" : "東京都台東区上野七丁目1-1", "line_cd" : 11319, "selected" : false, "open_ymd" : "", "name" : "1131901", "pref_name" : "東京都", "shared_name" : "1131901", "lat" : 35.71379, "y" : -357137.9, "x" : 1397770.43 }, "position" : { "x" : 1397770.43, "y" : -357137.9 }, "selected" : false }, { "data" : { "id" : "3045", "station_name" : "尾久", "close_ymd" : "", "lon" : 139.753846, "post" : "114-0011", "e_status" : 0, "SUID" : 3045, "station_g_cd" : 1131902, "add" : "北区昭和町1丁目", "line_cd" : 11319, "selected" : false, "open_ymd" : "", "name" : "1131902", "pref_name" : "東京都", "shared_name" : "1131902", "lat" : 35.746829999999996, "y" : -357468.29999999993, "x" : 1397538.4600000002 }, "position" : { "x" : 1397538.4600000002, "y" : -357468.29999999993 }, "selected" : false }, { "data" : { "id" : "3046", "station_name" : "赤羽", "close_ymd" : "", "lon" : 139.72092800000001, "post" : "115-0045", "e_status" : 0, "SUID" : 3046, "station_g_cd" : 1131903, "add" : "北区赤羽1丁目", "line_cd" : 11319, "selected" : false, "open_ymd" : "", "name" : "1131903", "pref_name" : "東京都", "shared_name" : "1131903", "lat" : 35.778026000000004, "y" : -357780.26000000007, "x" : 1397209.2800000003 }, "position" : { "x" : 1397209.2800000003, "y" : -357780.26000000007 }, "selected" : false } ], "edges" : [ { "data" : { "id" : "18417", "source" : "8220", "target" : "8221", "line_name_k" : "ホクソウテツドウホクソウセン", "is_bullet" : false, "lon" : 140.03784499075186, "company_name_k" : "ホクソウテツドウ", "zoom" : 11, "SUID" : 18417, "company_type" : 0, "company_name_h" : "北総鉄道株式会社", "interaction" : "99340", "shared_interaction" : "99340", "company_url" : "http://www.hokuso-railway.co.jp/", "line_name" : "北総鉄道北総線", "selected" : false, "company_name" : "北総鉄道", "company_cd" : 152, "name" : "9934001 (99340) 9934002", "rr_cd" : 99, "company_name_r" : "北総鉄道", "e_status_x" : 0, "shared_name" : "9934001 (99340) 9934002", "lat" : 35.78346285846615, "e_status_y" : 0, "line_name_h" : "北総鉄道北総線" }, "selected" : false }, { "data" : { "id" : "16253", "source" : "5901", "target" : "5902", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16253, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800109 (28001) 2800110", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800109 (28001) 2800110", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16254", "source" : "5902", "target" : "5903", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16254, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800110 (28001) 2800111", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800110 (28001) 2800111", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16255", "source" : "5903", "target" : "5904", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16255, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800111 (28001) 2800112", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800111 (28001) 2800112", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16256", "source" : "5904", "target" : "5905", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16256, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800112 (28001) 2800113", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800112 (28001) 2800113", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16257", "source" : "5905", "target" : "5906", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16257, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800113 (28001) 2800114", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800113 (28001) 2800114", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16258", "source" : "5906", "target" : "5907", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16258, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800114 (28001) 2800115", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800114 (28001) 2800115", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16259", "source" : "5907", "target" : "5908", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16259, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800115 (28001) 2800116", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800115 (28001) 2800116", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16260", "source" : "5908", "target" : "5909", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16260, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800116 (28001) 2800117", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800116 (28001) 2800117", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16245", "source" : "5893", "target" : "5894", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16245, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800101 (28001) 2800102", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800101 (28001) 2800102", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16246", "source" : "5894", "target" : "5895", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16246, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800102 (28001) 2800103", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800102 (28001) 2800103", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16247", "source" : "5895", "target" : "5896", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16247, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800103 (28001) 2800104", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800103 (28001) 2800104", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16248", "source" : "5896", "target" : "5897", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16248, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800104 (28001) 2800105", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800104 (28001) 2800105", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16249", "source" : "5897", "target" : "5898", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16249, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800105 (28001) 2800106", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800105 (28001) 2800106", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16250", "source" : "5898", "target" : "5899", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16250, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800106 (28001) 2800107", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800106 (28001) 2800107", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16251", "source" : "5899", "target" : "5900", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16251, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800107 (28001) 2800108", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800107 (28001) 2800108", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16252", "source" : "5900", "target" : "5901", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16252, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800108 (28001) 2800109", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800108 (28001) 2800109", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16227", "source" : "5871", "target" : "5872", "line_name_k" : "ケイキュウクウコウセン", "is_bullet" : false, "lon" : 139.74978371429006, "company_name_k" : "ケイキュウデンテツ", "zoom" : 13, "SUID" : 16227, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27002", "shared_interaction" : "27002", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急空港線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700207 (27002) 2700206", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700207 (27002) 2700206", "lat" : 35.5550012530646, "e_status_y" : 0, "line_name_h" : "京急空港線" }, "selected" : false }, { "data" : { "id" : "16225", "source" : "5869", "target" : "5870", "line_name_k" : "ケイキュウクウコウセン", "is_bullet" : false, "lon" : 139.74978371429006, "company_name_k" : "ケイキュウデンテツ", "zoom" : 13, "SUID" : 16225, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27002", "shared_interaction" : "27002", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急空港線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700204 (27002) 2700205", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700204 (27002) 2700205", "lat" : 35.5550012530646, "e_status_y" : 0, "line_name_h" : "京急空港線" }, "selected" : false }, { "data" : { "id" : "16226", "source" : "5870", "target" : "5871", "line_name_k" : "ケイキュウクウコウセン", "is_bullet" : false, "lon" : 139.74978371429006, "company_name_k" : "ケイキュウデンテツ", "zoom" : 13, "SUID" : 16226, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27002", "shared_interaction" : "27002", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急空港線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700205 (27002) 2700207", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700205 (27002) 2700207", "lat" : 35.5550012530646, "e_status_y" : 0, "line_name_h" : "京急空港線" }, "selected" : false }, { "data" : { "id" : "16223", "source" : "5867", "target" : "5868", "line_name_k" : "ケイキュウクウコウセン", "is_bullet" : false, "lon" : 139.74978371429006, "company_name_k" : "ケイキュウデンテツ", "zoom" : 13, "SUID" : 16223, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27002", "shared_interaction" : "27002", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急空港線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700202 (27002) 2700203", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700202 (27002) 2700203", "lat" : 35.5550012530646, "e_status_y" : 0, "line_name_h" : "京急空港線" }, "selected" : false }, { "data" : { "id" : "16224", "source" : "5868", "target" : "5869", "line_name_k" : "ケイキュウクウコウセン", "is_bullet" : false, "lon" : 139.74978371429006, "company_name_k" : "ケイキュウデンテツ", "zoom" : 13, "SUID" : 16224, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27002", "shared_interaction" : "27002", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急空港線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700203 (27002) 2700204", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700203 (27002) 2700204", "lat" : 35.5550012530646, "e_status_y" : 0, "line_name_h" : "京急空港線" }, "selected" : false }, { "data" : { "id" : "16222", "source" : "5866", "target" : "5867", "line_name_k" : "ケイキュウクウコウセン", "is_bullet" : false, "lon" : 139.74978371429006, "company_name_k" : "ケイキュウデンテツ", "zoom" : 13, "SUID" : 16222, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27002", "shared_interaction" : "27002", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急空港線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700201 (27002) 2700202", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700201 (27002) 2700202", "lat" : 35.5550012530646, "e_status_y" : 0, "line_name_h" : "京急空港線" }, "selected" : false }, { "data" : { "id" : "16183", "source" : "5826", "target" : "5827", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16183, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700111 (27001) 2700112", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700111 (27001) 2700112", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16182", "source" : "5825", "target" : "5826", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16182, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700110 (27001) 2700111", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700110 (27001) 2700111", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16185", "source" : "5828", "target" : "5829", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16185, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700113 (27001) 2700114", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700113 (27001) 2700114", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16184", "source" : "5827", "target" : "5828", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16184, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700112 (27001) 2700113", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700112 (27001) 2700113", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16179", "source" : "5822", "target" : "5823", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16179, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700107 (27001) 2700108", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700107 (27001) 2700108", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16178", "source" : "5821", "target" : "5822", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16178, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700106 (27001) 2700107", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700106 (27001) 2700107", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16181", "source" : "5824", "target" : "5825", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16181, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700109 (27001) 2700110", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700109 (27001) 2700110", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16180", "source" : "5823", "target" : "5824", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16180, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700108 (27001) 2700109", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700108 (27001) 2700109", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16175", "source" : "5818", "target" : "5819", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16175, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700103 (27001) 2700104", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700103 (27001) 2700104", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16174", "source" : "5817", "target" : "5818", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16174, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700102 (27001) 2700103", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700102 (27001) 2700103", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16177", "source" : "5820", "target" : "5821", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16177, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700105 (27001) 2700106", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700105 (27001) 2700106", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16176", "source" : "5819", "target" : "5820", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16176, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700104 (27001) 2700105", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700104 (27001) 2700105", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16173", "source" : "5816", "target" : "5817", "line_name_k" : "ケイキュウホンセン", "is_bullet" : false, "lon" : 139.66542155593754, "company_name_k" : "ケイキュウデンテツ", "zoom" : 10, "SUID" : 16173, "company_type" : 2, "company_name_h" : "京浜急行電鉄株式会社", "interaction" : "27001", "shared_interaction" : "27001", "company_url" : "http://www.keikyu.co.jp/", "line_name" : "京急本線", "selected" : false, "company_name" : "京急電鉄", "company_cd" : 17, "name" : "2700101 (27001) 2700102", "rr_cd" : 27, "company_name_r" : "京急", "e_status_x" : 0, "shared_name" : "2700101 (27001) 2700102", "lat" : 35.470013165246186, "e_status_y" : 0, "line_name_h" : "京急本線" }, "selected" : false }, { "data" : { "id" : "16156", "source" : "5796", "target" : "5797", "line_name_k" : "トウキュウタマガワセン", "is_bullet" : false, "lon" : 139.68743273015912, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16156, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26006", "shared_interaction" : "26006", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急多摩川線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600601 (26006) 2600602", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600601 (26006) 2600602", "lat" : 35.5724416406283, "e_status_y" : 0, "line_name_h" : "東急多摩川線" }, "selected" : false }, { "data" : { "id" : "16155", "source" : "5794", "target" : "5795", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16155, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600514 (26005) 2600515", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600514 (26005) 2600515", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16154", "source" : "5793", "target" : "5794", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16154, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600513 (26005) 2600514", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600513 (26005) 2600514", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16153", "source" : "5792", "target" : "5793", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16153, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600512 (26005) 2600513", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600512 (26005) 2600513", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16152", "source" : "5791", "target" : "5792", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16152, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600511 (26005) 2600512", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600511 (26005) 2600512", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16151", "source" : "5790", "target" : "5791", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16151, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600510 (26005) 2600511", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600510 (26005) 2600511", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16150", "source" : "5789", "target" : "5790", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16150, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600509 (26005) 2600510", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600509 (26005) 2600510", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16149", "source" : "5788", "target" : "5789", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16149, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600508 (26005) 2600509", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600508 (26005) 2600509", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16148", "source" : "5787", "target" : "5788", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16148, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600507 (26005) 2600508", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600507 (26005) 2600508", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16147", "source" : "5786", "target" : "5787", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16147, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600506 (26005) 2600507", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600506 (26005) 2600507", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16146", "source" : "5785", "target" : "5786", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16146, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600505 (26005) 2600506", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600505 (26005) 2600506", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16145", "source" : "5784", "target" : "5785", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16145, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600504 (26005) 2600505", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600504 (26005) 2600505", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16144", "source" : "5783", "target" : "5784", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16144, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600503 (26005) 2600504", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600503 (26005) 2600504", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16143", "source" : "5782", "target" : "5783", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16143, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600502 (26005) 2600503", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600502 (26005) 2600503", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16142", "source" : "5781", "target" : "5782", "line_name_k" : "トウキュウイケガミセン", "is_bullet" : false, "lon" : 139.70623944130853, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16142, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26005", "shared_interaction" : "26005", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急池上線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600501 (26005) 2600502", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600501 (26005) 2600502", "lat" : 35.59393651096109, "e_status_y" : 0, "line_name_h" : "東急池上線" }, "selected" : false }, { "data" : { "id" : "16170", "source" : "5811", "target" : "5812", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16170, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600709 (26007) 2600710", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600709 (26007) 2600710", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16168", "source" : "5809", "target" : "5810", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16168, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600707 (26007) 2600708", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600707 (26007) 2600708", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16169", "source" : "5810", "target" : "5811", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16169, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600708 (26007) 2600709", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600708 (26007) 2600709", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16166", "source" : "5807", "target" : "5808", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16166, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600705 (26007) 2600706", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600705 (26007) 2600706", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16167", "source" : "5808", "target" : "5809", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16167, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600706 (26007) 2600707", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600706 (26007) 2600707", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16164", "source" : "5805", "target" : "5806", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16164, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600703 (26007) 2600704", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600703 (26007) 2600704", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16165", "source" : "5806", "target" : "5807", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16165, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600704 (26007) 2600705", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600704 (26007) 2600705", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16162", "source" : "5803", "target" : "5804", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16162, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600701 (26007) 2600702", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600701 (26007) 2600702", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16163", "source" : "5804", "target" : "5805", "line_name_k" : "トウキュウセタガヤセン", "is_bullet" : false, "lon" : 139.6525418613769, "company_name_k" : "トウキョウデンテツ", "zoom" : 14, "SUID" : 16163, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26007", "shared_interaction" : "26007", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急世田谷線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600702 (26007) 2600703", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600702 (26007) 2600703", "lat" : 35.653196779881476, "e_status_y" : 0, "line_name_h" : "東急世田谷線" }, "selected" : false }, { "data" : { "id" : "16161", "source" : "5801", "target" : "5802", "line_name_k" : "トウキュウタマガワセン", "is_bullet" : false, "lon" : 139.68743273015912, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16161, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26006", "shared_interaction" : "26006", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急多摩川線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600606 (26006) 2600607", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600606 (26006) 2600607", "lat" : 35.5724416406283, "e_status_y" : 0, "line_name_h" : "東急多摩川線" }, "selected" : false }, { "data" : { "id" : "16159", "source" : "5799", "target" : "5800", "line_name_k" : "トウキュウタマガワセン", "is_bullet" : false, "lon" : 139.68743273015912, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16159, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26006", "shared_interaction" : "26006", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急多摩川線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600604 (26006) 2600605", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600604 (26006) 2600605", "lat" : 35.5724416406283, "e_status_y" : 0, "line_name_h" : "東急多摩川線" }, "selected" : false }, { "data" : { "id" : "16160", "source" : "5800", "target" : "5801", "line_name_k" : "トウキュウタマガワセン", "is_bullet" : false, "lon" : 139.68743273015912, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16160, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26006", "shared_interaction" : "26006", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急多摩川線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600605 (26006) 2600606", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600605 (26006) 2600606", "lat" : 35.5724416406283, "e_status_y" : 0, "line_name_h" : "東急多摩川線" }, "selected" : false }, { "data" : { "id" : "16157", "source" : "5797", "target" : "5798", "line_name_k" : "トウキュウタマガワセン", "is_bullet" : false, "lon" : 139.68743273015912, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16157, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26006", "shared_interaction" : "26006", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急多摩川線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600602 (26006) 2600603", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600602 (26006) 2600603", "lat" : 35.5724416406283, "e_status_y" : 0, "line_name_h" : "東急多摩川線" }, "selected" : false }, { "data" : { "id" : "16158", "source" : "5798", "target" : "5799", "line_name_k" : "トウキュウタマガワセン", "is_bullet" : false, "lon" : 139.68743273015912, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16158, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26006", "shared_interaction" : "26006", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急多摩川線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600603 (26006) 2600604", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600603 (26006) 2600604", "lat" : 35.5724416406283, "e_status_y" : 0, "line_name_h" : "東急多摩川線" }, "selected" : false }, { "data" : { "id" : "18361", "source" : "8157", "target" : "8158", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18361, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933412 (99334) 9933413", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933412 (99334) 9933413", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18362", "source" : "8158", "target" : "8159", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18362, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933413 (99334) 9933414", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933413 (99334) 9933414", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18363", "source" : "8159", "target" : "8160", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18363, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933414 (99334) 9933415", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933414 (99334) 9933415", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18364", "source" : "8160", "target" : "8161", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18364, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933415 (99334) 9933416", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933415 (99334) 9933416", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18365", "source" : "8161", "target" : "8162", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18365, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933416 (99334) 9933417", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933416 (99334) 9933417", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18366", "source" : "8162", "target" : "8163", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18366, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933417 (99334) 9933418", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933417 (99334) 9933418", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18367", "source" : "8163", "target" : "8164", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18367, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933418 (99334) 9933419", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933418 (99334) 9933419", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18353", "source" : "8149", "target" : "8150", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18353, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933404 (99334) 9933405", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933404 (99334) 9933405", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "16121", "source" : "5758", "target" : "5759", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16121, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600323 (26003) 2600324", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600323 (26003) 2600324", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "18354", "source" : "8150", "target" : "8151", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18354, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933405 (99334) 9933406", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933405 (99334) 9933406", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "16122", "source" : "5759", "target" : "5760", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16122, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600324 (26003) 2600325", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600324 (26003) 2600325", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "18355", "source" : "8151", "target" : "8152", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18355, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933406 (99334) 9933407", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933406 (99334) 9933407", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18356", "source" : "8152", "target" : "8153", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18356, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933407 (99334) 9933408", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933407 (99334) 9933408", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18357", "source" : "8153", "target" : "8154", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18357, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933408 (99334) 9933409", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933408 (99334) 9933409", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18358", "source" : "8154", "target" : "8155", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18358, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933409 (99334) 9933410", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933409 (99334) 9933410", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "16125", "source" : "5763", "target" : "5764", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16125, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600401 (26004) 2600402", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600401 (26004) 2600402", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18359", "source" : "8155", "target" : "8156", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18359, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933410 (99334) 9933411", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933410 (99334) 9933411", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18360", "source" : "8156", "target" : "8157", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18360, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933411 (99334) 9933412", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933411 (99334) 9933412", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "16126", "source" : "5764", "target" : "5765", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16126, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600402 (26004) 2600403", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600402 (26004) 2600403", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "16128", "source" : "5766", "target" : "5767", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16128, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600404 (26004) 2600405", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600404 (26004) 2600405", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "16127", "source" : "5765", "target" : "5766", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16127, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600403 (26004) 2600404", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600403 (26004) 2600404", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18378", "source" : "8176", "target" : "8177", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18378, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933602 (99336) 9933603", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933602 (99336) 9933603", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16130", "source" : "5768", "target" : "5769", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16130, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600406 (26004) 2600407", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600406 (26004) 2600407", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18377", "source" : "8175", "target" : "8176", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18377, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933601 (99336) 9933602", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933601 (99336) 9933602", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16129", "source" : "5767", "target" : "5768", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16129, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600405 (26004) 2600406", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600405 (26004) 2600406", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18380", "source" : "8178", "target" : "8179", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18380, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933604 (99336) 9933605", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933604 (99336) 9933605", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16132", "source" : "5770", "target" : "5771", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16132, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600408 (26004) 2600409", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600408 (26004) 2600409", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18379", "source" : "8177", "target" : "8178", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18379, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933603 (99336) 9933604", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933603 (99336) 9933604", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16131", "source" : "5769", "target" : "5770", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16131, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600407 (26004) 2600408", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600407 (26004) 2600408", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18382", "source" : "8180", "target" : "8181", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18382, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933606 (99336) 9933607", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933606 (99336) 9933607", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16134", "source" : "5772", "target" : "5773", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16134, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600410 (26004) 2600411", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600410 (26004) 2600411", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18381", "source" : "8179", "target" : "8180", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18381, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933605 (99336) 9933606", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933605 (99336) 9933606", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16133", "source" : "5771", "target" : "5772", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16133, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600409 (26004) 2600410", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600409 (26004) 2600410", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "16136", "source" : "5774", "target" : "5775", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16136, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600412 (26004) 2600413", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600412 (26004) 2600413", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "16135", "source" : "5773", "target" : "5774", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16135, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600411 (26004) 2600412", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600411 (26004) 2600412", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "16138", "source" : "5776", "target" : "5777", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16138, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600414 (26004) 2600415", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600414 (26004) 2600415", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "16137", "source" : "5775", "target" : "5776", "line_name_k" : "トウキュウオオイマチセン", "is_bullet" : false, "lon" : 139.67537624870124, "company_name_k" : "トウキョウデンテツ", "zoom" : 12, "SUID" : 16137, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26004", "shared_interaction" : "26004", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急大井町線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600413 (26004) 2600414", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600413 (26004) 2600414", "lat" : 35.607027243076224, "e_status_y" : 0, "line_name_h" : "東急大井町線" }, "selected" : false }, { "data" : { "id" : "18392", "source" : "8191", "target" : "8192", "line_name_k" : "リンカイセン", "is_bullet" : false, "lon" : 139.7661296428223, "company_name_k" : "トウキョウリンカイコウソクテツドウ", "zoom" : 13, "SUID" : 18392, "company_type" : 0, "company_name_h" : "東京臨海高速鉄道株式会社", "interaction" : "99337", "shared_interaction" : "99337", "company_url" : "http://www.twr.co.jp/", "line_name" : "りんかい線", "selected" : false, "company_name" : "東京臨海高速鉄道", "company_cd" : 149, "name" : "9933706 (99337) 9933707", "rr_cd" : 99, "company_name_r" : "東京臨海高速鉄道", "e_status_x" : 0, "shared_name" : "9933706 (99337) 9933707", "lat" : 35.62373301157322, "e_status_y" : 0, "line_name_h" : "東京臨海高速鉄道りんかい線" }, "selected" : false }, { "data" : { "id" : "18393", "source" : "8192", "target" : "8193", "line_name_k" : "リンカイセン", "is_bullet" : false, "lon" : 139.7661296428223, "company_name_k" : "トウキョウリンカイコウソクテツドウ", "zoom" : 13, "SUID" : 18393, "company_type" : 0, "company_name_h" : "東京臨海高速鉄道株式会社", "interaction" : "99337", "shared_interaction" : "99337", "company_url" : "http://www.twr.co.jp/", "line_name" : "りんかい線", "selected" : false, "company_name" : "東京臨海高速鉄道", "company_cd" : 149, "name" : "9933707 (99337) 9933708", "rr_cd" : 99, "company_name_r" : "東京臨海高速鉄道", "e_status_x" : 0, "shared_name" : "9933707 (99337) 9933708", "lat" : 35.62373301157322, "e_status_y" : 0, "line_name_h" : "東京臨海高速鉄道りんかい線" }, "selected" : false }, { "data" : { "id" : "18390", "source" : "8189", "target" : "8190", "line_name_k" : "リンカイセン", "is_bullet" : false, "lon" : 139.7661296428223, "company_name_k" : "トウキョウリンカイコウソクテツドウ", "zoom" : 13, "SUID" : 18390, "company_type" : 0, "company_name_h" : "東京臨海高速鉄道株式会社", "interaction" : "99337", "shared_interaction" : "99337", "company_url" : "http://www.twr.co.jp/", "line_name" : "りんかい線", "selected" : false, "company_name" : "東京臨海高速鉄道", "company_cd" : 149, "name" : "9933704 (99337) 9933705", "rr_cd" : 99, "company_name_r" : "東京臨海高速鉄道", "e_status_x" : 0, "shared_name" : "9933704 (99337) 9933705", "lat" : 35.62373301157322, "e_status_y" : 0, "line_name_h" : "東京臨海高速鉄道りんかい線" }, "selected" : false }, { "data" : { "id" : "18391", "source" : "8190", "target" : "8191", "line_name_k" : "リンカイセン", "is_bullet" : false, "lon" : 139.7661296428223, "company_name_k" : "トウキョウリンカイコウソクテツドウ", "zoom" : 13, "SUID" : 18391, "company_type" : 0, "company_name_h" : "東京臨海高速鉄道株式会社", "interaction" : "99337", "shared_interaction" : "99337", "company_url" : "http://www.twr.co.jp/", "line_name" : "りんかい線", "selected" : false, "company_name" : "東京臨海高速鉄道", "company_cd" : 149, "name" : "9933705 (99337) 9933706", "rr_cd" : 99, "company_name_r" : "東京臨海高速鉄道", "e_status_x" : 0, "shared_name" : "9933705 (99337) 9933706", "lat" : 35.62373301157322, "e_status_y" : 0, "line_name_h" : "東京臨海高速鉄道りんかい線" }, "selected" : false }, { "data" : { "id" : "16087", "source" : "5723", "target" : "5724", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16087, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600201 (26002) 2600202", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600201 (26002) 2600202", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "16088", "source" : "5724", "target" : "5725", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16088, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600202 (26002) 2600203", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600202 (26002) 2600203", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "16091", "source" : "5727", "target" : "5728", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16091, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600205 (26002) 2600206", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600205 (26002) 2600206", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "18385", "source" : "8183", "target" : "8184", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18385, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933608 (99336) 9933609", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933608 (99336) 9933609", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16092", "source" : "5728", "target" : "5729", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16092, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600206 (26002) 2600207", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600206 (26002) 2600207", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "18386", "source" : "8184", "target" : "8185", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18386, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933609 (99336) 9933610", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933609 (99336) 9933610", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16089", "source" : "5725", "target" : "5726", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16089, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600203 (26002) 2600204", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600203 (26002) 2600204", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "18383", "source" : "8181", "target" : "8182", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18383, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933607 (99336) 9933611", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933607 (99336) 9933611", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "16090", "source" : "5726", "target" : "5727", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16090, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600204 (26002) 2600205", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600204 (26002) 2600205", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "18384", "source" : "8182", "target" : "8183", "line_name_k" : "トウキョウモノレール", "is_bullet" : false, "lon" : 139.76328619095784, "company_name_k" : "トウキョウモノレール", "zoom" : 12, "SUID" : 18384, "company_type" : 0, "company_name_h" : "東京モノレール株式会社", "interaction" : "99336", "shared_interaction" : "99336", "company_url" : "http://www.tokyo-monorail.co.jp/", "line_name" : "東京モノレール", "selected" : false, "company_name" : "東京モノレール", "company_cd" : 148, "name" : "9933611 (99336) 9933608", "rr_cd" : 99, "company_name_r" : "東京モノレール", "e_status_x" : 0, "shared_name" : "9933611 (99336) 9933608", "lat" : 35.59102280877391, "e_status_y" : 0, "line_name_h" : "東京モノレール羽田空港線" }, "selected" : false }, { "data" : { "id" : "18388", "source" : "8187", "target" : "8188", "line_name_k" : "リンカイセン", "is_bullet" : false, "lon" : 139.7661296428223, "company_name_k" : "トウキョウリンカイコウソクテツドウ", "zoom" : 13, "SUID" : 18388, "company_type" : 0, "company_name_h" : "東京臨海高速鉄道株式会社", "interaction" : "99337", "shared_interaction" : "99337", "company_url" : "http://www.twr.co.jp/", "line_name" : "りんかい線", "selected" : false, "company_name" : "東京臨海高速鉄道", "company_cd" : 149, "name" : "9933702 (99337) 9933703", "rr_cd" : 99, "company_name_r" : "東京臨海高速鉄道", "e_status_x" : 0, "shared_name" : "9933702 (99337) 9933703", "lat" : 35.62373301157322, "e_status_y" : 0, "line_name_h" : "東京臨海高速鉄道りんかい線" }, "selected" : false }, { "data" : { "id" : "18389", "source" : "8188", "target" : "8189", "line_name_k" : "リンカイセン", "is_bullet" : false, "lon" : 139.7661296428223, "company_name_k" : "トウキョウリンカイコウソクテツドウ", "zoom" : 13, "SUID" : 18389, "company_type" : 0, "company_name_h" : "東京臨海高速鉄道株式会社", "interaction" : "99337", "shared_interaction" : "99337", "company_url" : "http://www.twr.co.jp/", "line_name" : "りんかい線", "selected" : false, "company_name" : "東京臨海高速鉄道", "company_cd" : 149, "name" : "9933703 (99337) 9933704", "rr_cd" : 99, "company_name_r" : "東京臨海高速鉄道", "e_status_x" : 0, "shared_name" : "9933703 (99337) 9933704", "lat" : 35.62373301157322, "e_status_y" : 0, "line_name_h" : "東京臨海高速鉄道りんかい線" }, "selected" : false }, { "data" : { "id" : "16093", "source" : "5729", "target" : "5730", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16093, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600207 (26002) 2600208", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600207 (26002) 2600208", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "16094", "source" : "5730", "target" : "5731", "line_name_k" : "トウキュウメグロセン", "is_bullet" : false, "lon" : 139.67835129424657, "company_name_k" : "トウキョウデンテツ", "zoom" : 13, "SUID" : 16094, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26002", "shared_interaction" : "26002", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急目黒線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600208 (26002) 2600209", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600208 (26002) 2600209", "lat" : 35.603755429181255, "e_status_y" : 0, "line_name_h" : "東急目黒線" }, "selected" : false }, { "data" : { "id" : "18387", "source" : "8186", "target" : "8187", "line_name_k" : "リンカイセン", "is_bullet" : false, "lon" : 139.7661296428223, "company_name_k" : "トウキョウリンカイコウソクテツドウ", "zoom" : 13, "SUID" : 18387, "company_type" : 0, "company_name_h" : "東京臨海高速鉄道株式会社", "interaction" : "99337", "shared_interaction" : "99337", "company_url" : "http://www.twr.co.jp/", "line_name" : "りんかい線", "selected" : false, "company_name" : "東京臨海高速鉄道", "company_cd" : 149, "name" : "9933701 (99337) 9933702", "rr_cd" : 99, "company_name_r" : "東京臨海高速鉄道", "e_status_x" : 0, "shared_name" : "9933701 (99337) 9933702", "lat" : 35.62373301157322, "e_status_y" : 0, "line_name_h" : "東京臨海高速鉄道りんかい線" }, "selected" : false }, { "data" : { "id" : "16099", "source" : "5736", "target" : "5737", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16099, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600301 (26003) 2600302", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600301 (26003) 2600302", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "16103", "source" : "5740", "target" : "5741", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16103, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600305 (26003) 2600306", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600305 (26003) 2600306", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "16102", "source" : "5739", "target" : "5740", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16102, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600304 (26003) 2600305", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600304 (26003) 2600305", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "16101", "source" : "5738", "target" : "5739", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16101, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600303 (26003) 2600304", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600303 (26003) 2600304", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "16100", "source" : "5737", "target" : "5738", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16100, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600302 (26003) 2600303", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600302 (26003) 2600303", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "16104", "source" : "5741", "target" : "5742", "line_name_k" : "トウキュウデンエントシセン", "is_bullet" : false, "lon" : 139.58465916941623, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16104, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26003", "shared_interaction" : "26003", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急田園都市線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600306 (26003) 2600307", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600306 (26003) 2600307", "lat" : 35.58324215005882, "e_status_y" : 0, "line_name_h" : "東急田園都市線" }, "selected" : false }, { "data" : { "id" : "16065", "source" : "5699", "target" : "5700", "line_name_k" : "オダキュウタマセン", "is_bullet" : false, "lon" : 139.4602937407226, "company_name_k" : "オダキュウデンテツ", "zoom" : 13, "SUID" : 16065, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25003", "shared_interaction" : "25003", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急多摩線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500306 (25003) 2500307", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500306 (25003) 2500307", "lat" : 35.61945834975, "e_status_y" : 0, "line_name_h" : "小田急多摩線" }, "selected" : false }, { "data" : { "id" : "16066", "source" : "5700", "target" : "5701", "line_name_k" : "オダキュウタマセン", "is_bullet" : false, "lon" : 139.4602937407226, "company_name_k" : "オダキュウデンテツ", "zoom" : 13, "SUID" : 16066, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25003", "shared_interaction" : "25003", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急多摩線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500307 (25003) 2500308", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500307 (25003) 2500308", "lat" : 35.61945834975, "e_status_y" : 0, "line_name_h" : "小田急多摩線" }, "selected" : false }, { "data" : { "id" : "16071", "source" : "5706", "target" : "5707", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16071, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600105 (26001) 2600106", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600105 (26001) 2600106", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16070", "source" : "5705", "target" : "5706", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16070, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600104 (26001) 2600105", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600104 (26001) 2600105", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16073", "source" : "5708", "target" : "5709", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16073, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600107 (26001) 2600108", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600107 (26001) 2600108", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16072", "source" : "5707", "target" : "5708", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16072, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600106 (26001) 2600107", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600106 (26001) 2600107", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16067", "source" : "5702", "target" : "5703", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16067, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600101 (26001) 2600102", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600101 (26001) 2600102", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16069", "source" : "5704", "target" : "5705", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16069, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600103 (26001) 2600104", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600103 (26001) 2600104", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16068", "source" : "5703", "target" : "5704", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16068, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600102 (26001) 2600103", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600102 (26001) 2600103", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16074", "source" : "5709", "target" : "5710", "line_name_k" : "トウキュウトウヨコセン", "is_bullet" : false, "lon" : 139.66832596832717, "company_name_k" : "トウキョウデンテツ", "zoom" : 11, "SUID" : 16074, "company_type" : 2, "company_name_h" : "東京急行電鉄株式会社", "interaction" : "26001", "shared_interaction" : "26001", "company_url" : "http://www.tokyu.co.jp/", "line_name" : "東急東横線", "selected" : false, "company_name" : "東急電鉄", "company_cd" : 16, "name" : "2600108 (26001) 2600109", "rr_cd" : 26, "company_name_r" : "東急", "e_status_x" : 0, "shared_name" : "2600108 (26001) 2600109", "lat" : 35.58608048810499, "e_status_y" : 0, "line_name_h" : "東急東横線" }, "selected" : false }, { "data" : { "id" : "16023", "source" : "5655", "target" : "5656", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16023, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500126 (25001) 2500127", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500126 (25001) 2500127", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16022", "source" : "5654", "target" : "5655", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16022, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500125 (25001) 2500126", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500125 (25001) 2500126", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "18352", "source" : "8148", "target" : "8149", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18352, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933403 (99334) 9933404", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933403 (99334) 9933404", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18351", "source" : "8147", "target" : "8148", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18351, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933402 (99334) 9933403", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933402 (99334) 9933403", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18350", "source" : "8146", "target" : "8147", "line_name_k" : "タマモノレール", "is_bullet" : false, "lon" : 139.42169850770813, "company_name_k" : "タマトシモノレール", "zoom" : 12, "SUID" : 18350, "company_type" : 0, "company_name_h" : "多摩都市モノレール株式会社", "interaction" : "99334", "shared_interaction" : "99334", "company_url" : "http://www.tama-monorail.co.jp/", "line_name" : "多摩モノレール", "selected" : false, "company_name" : "多摩都市モノレール", "company_cd" : 146, "name" : "9933401 (99334) 9933402", "rr_cd" : 99, "company_name_r" : "多摩モノレール", "e_status_x" : 0, "shared_name" : "9933401 (99334) 9933402", "lat" : 35.69743141486103, "e_status_y" : 0, "line_name_h" : "多摩都市モノレール線" }, "selected" : false }, { "data" : { "id" : "18012", "source" : "7783", "target" : "7784", "line_name_k" : "ツクバエクスプレス", "is_bullet" : false, "lon" : 139.93750930625004, "company_name_k" : "シュトケンシントシテツドウ", "zoom" : 10, "SUID" : 18012, "company_type" : 0, "company_name_h" : "首都圏新都市鉄道株式会社", "interaction" : "99309", "shared_interaction" : "99309", "company_url" : "http://www.mir.co.jp/", "line_name" : "つくばエクスプレス", "selected" : false, "company_name" : "首都圏新都市鉄道", "company_cd" : 123, "name" : "9930902 (99309) 9930903", "rr_cd" : 99, "company_name_r" : "首都圏新都市鉄道", "e_status_x" : 0, "shared_name" : "9930902 (99309) 9930903", "lat" : 35.90577190655735, "e_status_y" : 0, "line_name_h" : "首都圏新都市鉄道つくばエクスプレス" }, "selected" : false }, { "data" : { "id" : "18013", "source" : "7784", "target" : "7785", "line_name_k" : "ツクバエクスプレス", "is_bullet" : false, "lon" : 139.93750930625004, "company_name_k" : "シュトケンシントシテツドウ", "zoom" : 10, "SUID" : 18013, "company_type" : 0, "company_name_h" : "首都圏新都市鉄道株式会社", "interaction" : "99309", "shared_interaction" : "99309", "company_url" : "http://www.mir.co.jp/", "line_name" : "つくばエクスプレス", "selected" : false, "company_name" : "首都圏新都市鉄道", "company_cd" : 123, "name" : "9930903 (99309) 9930904", "rr_cd" : 99, "company_name_r" : "首都圏新都市鉄道", "e_status_x" : 0, "shared_name" : "9930903 (99309) 9930904", "lat" : 35.90577190655735, "e_status_y" : 0, "line_name_h" : "首都圏新都市鉄道つくばエクスプレス" }, "selected" : false }, { "data" : { "id" : "18011", "source" : "7782", "target" : "7783", "line_name_k" : "ツクバエクスプレス", "is_bullet" : false, "lon" : 139.93750930625004, "company_name_k" : "シュトケンシントシテツドウ", "zoom" : 10, "SUID" : 18011, "company_type" : 0, "company_name_h" : "首都圏新都市鉄道株式会社", "interaction" : "99309", "shared_interaction" : "99309", "company_url" : "http://www.mir.co.jp/", "line_name" : "つくばエクスプレス", "selected" : false, "company_name" : "首都圏新都市鉄道", "company_cd" : 123, "name" : "9930901 (99309) 9930902", "rr_cd" : 99, "company_name_r" : "首都圏新都市鉄道", "e_status_x" : 0, "shared_name" : "9930901 (99309) 9930902", "lat" : 35.90577190655735, "e_status_y" : 0, "line_name_h" : "首都圏新都市鉄道つくばエクスプレス" }, "selected" : false }, { "data" : { "id" : "18016", "source" : "7787", "target" : "7788", "line_name_k" : "ツクバエクスプレス", "is_bullet" : false, "lon" : 139.93750930625004, "company_name_k" : "シュトケンシントシテツドウ", "zoom" : 10, "SUID" : 18016, "company_type" : 0, "company_name_h" : "首都圏新都市鉄道株式会社", "interaction" : "99309", "shared_interaction" : "99309", "company_url" : "http://www.mir.co.jp/", "line_name" : "つくばエクスプレス", "selected" : false, "company_name" : "首都圏新都市鉄道", "company_cd" : 123, "name" : "9930906 (99309) 9930907", "rr_cd" : 99, "company_name_r" : "首都圏新都市鉄道", "e_status_x" : 0, "shared_name" : "9930906 (99309) 9930907", "lat" : 35.90577190655735, "e_status_y" : 0, "line_name_h" : "首都圏新都市鉄道つくばエクスプレス" }, "selected" : false }, { "data" : { "id" : "18014", "source" : "7785", "target" : "7786", "line_name_k" : "ツクバエクスプレス", "is_bullet" : false, "lon" : 139.93750930625004, "company_name_k" : "シュトケンシントシテツドウ", "zoom" : 10, "SUID" : 18014, "company_type" : 0, "company_name_h" : "首都圏新都市鉄道株式会社", "interaction" : "99309", "shared_interaction" : "99309", "company_url" : "http://www.mir.co.jp/", "line_name" : "つくばエクスプレス", "selected" : false, "company_name" : "首都圏新都市鉄道", "company_cd" : 123, "name" : "9930904 (99309) 9930905", "rr_cd" : 99, "company_name_r" : "首都圏新都市鉄道", "e_status_x" : 0, "shared_name" : "9930904 (99309) 9930905", "lat" : 35.90577190655735, "e_status_y" : 0, "line_name_h" : "首都圏新都市鉄道つくばエクスプレス" }, "selected" : false }, { "data" : { "id" : "18015", "source" : "7786", "target" : "7787", "line_name_k" : "ツクバエクスプレス", "is_bullet" : false, "lon" : 139.93750930625004, "company_name_k" : "シュトケンシントシテツドウ", "zoom" : 10, "SUID" : 18015, "company_type" : 0, "company_name_h" : "首都圏新都市鉄道株式会社", "interaction" : "99309", "shared_interaction" : "99309", "company_url" : "http://www.mir.co.jp/", "line_name" : "つくばエクスプレス", "selected" : false, "company_name" : "首都圏新都市鉄道", "company_cd" : 123, "name" : "9930905 (99309) 9930906", "rr_cd" : 99, "company_name_r" : "首都圏新都市鉄道", "e_status_x" : 0, "shared_name" : "9930905 (99309) 9930906", "lat" : 35.90577190655735, "e_status_y" : 0, "line_name_h" : "首都圏新都市鉄道つくばエクスプレス" }, "selected" : false }, { "data" : { "id" : "18040", "source" : "7813", "target" : "7814", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18040, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931106 (99311) 9931107", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931106 (99311) 9931107", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18041", "source" : "7814", "target" : "7815", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18041, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931107 (99311) 9931108", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931107 (99311) 9931108", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18042", "source" : "7815", "target" : "7816", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18042, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931108 (99311) 9931109", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931108 (99311) 9931109", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18043", "source" : "7816", "target" : "7817", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18043, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931109 (99311) 9931110", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931109 (99311) 9931110", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18044", "source" : "7817", "target" : "7818", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18044, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931110 (99311) 9931111", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931110 (99311) 9931111", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18045", "source" : "7818", "target" : "7819", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18045, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931111 (99311) 9931112", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931111 (99311) 9931112", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18046", "source" : "7819", "target" : "7820", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18046, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931112 (99311) 9931113", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931112 (99311) 9931113", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18047", "source" : "7820", "target" : "7821", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18047, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931113 (99311) 9931114", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931113 (99311) 9931114", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18048", "source" : "7821", "target" : "7822", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18048, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931114 (99311) 9931115", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931114 (99311) 9931115", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18049", "source" : "7822", "target" : "7823", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18049, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931115 (99311) 9931116", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931115 (99311) 9931116", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18035", "source" : "7808", "target" : "7809", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18035, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931101 (99311) 9931102", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931101 (99311) 9931102", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18037", "source" : "7810", "target" : "7811", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18037, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931103 (99311) 9931104", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931103 (99311) 9931104", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18036", "source" : "7809", "target" : "7810", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18036, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931102 (99311) 9931103", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931102 (99311) 9931103", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18039", "source" : "7812", "target" : "7813", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18039, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931105 (99311) 9931106", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931105 (99311) 9931106", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "18038", "source" : "7811", "target" : "7812", "line_name_k" : "ユリカモメ", "is_bullet" : false, "lon" : 139.77494982373048, "company_name_k" : "ユリカモメ", "zoom" : 13, "SUID" : 18038, "company_type" : 0, "company_name_h" : "株式会社ゆりかもめ", "interaction" : "99311", "shared_interaction" : "99311", "company_url" : "http://www.yurikamome.co.jp/", "line_name" : "ゆりかもめ", "selected" : false, "company_name" : "ゆりかもめ", "company_cd" : 125, "name" : "9931104 (99311) 9931105", "rr_cd" : 99, "company_name_r" : "ゆりかもめ", "e_status_x" : 0, "shared_name" : "9931104 (99311) 9931105", "lat" : 35.64286984685855, "e_status_y" : 0, "line_name_h" : "ゆりかもめ東京臨海新交通臨海線" }, "selected" : false }, { "data" : { "id" : "17956", "source" : "7723", "target" : "7724", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17956, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934212 (99342) 9934213", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934212 (99342) 9934213", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "17954", "source" : "7721", "target" : "7722", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17954, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934210 (99342) 9934211", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934210 (99342) 9934211", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "17955", "source" : "7722", "target" : "7723", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17955, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934211 (99342) 9934212", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934211 (99342) 9934212", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "17952", "source" : "7719", "target" : "7720", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17952, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934208 (99342) 9934209", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934208 (99342) 9934209", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "17953", "source" : "7720", "target" : "7721", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17953, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934209 (99342) 9934210", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934209 (99342) 9934210", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "17950", "source" : "7717", "target" : "7718", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17950, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934206 (99342) 9934207", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934206 (99342) 9934207", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "17951", "source" : "7718", "target" : "7719", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17951, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934207 (99342) 9934208", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934207 (99342) 9934208", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "17942", "source" : "7708", "target" : "7709", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17942, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930527 (99305) 9930528", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930527 (99305) 9930528", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17941", "source" : "7707", "target" : "7708", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17941, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930526 (99305) 9930527", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930526 (99305) 9930527", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17940", "source" : "7706", "target" : "7707", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17940, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930525 (99305) 9930526", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930525 (99305) 9930526", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17939", "source" : "7705", "target" : "7706", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17939, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930524 (99305) 9930525", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930524 (99305) 9930525", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17938", "source" : "7704", "target" : "7705", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17938, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930523 (99305) 9930524", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930523 (99305) 9930524", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17937", "source" : "7703", "target" : "7704", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17937, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930522 (99305) 9930523", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930522 (99305) 9930523", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17936", "source" : "7702", "target" : "7703", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17936, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930521 (99305) 9930522", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930521 (99305) 9930522", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "16420", "source" : "6077", "target" : "6078", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16420, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801015 (28010) 2801016", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801015 (28010) 2801016", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "17935", "source" : "7701", "target" : "7702", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17935, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930520 (99305) 9930521", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930520 (99305) 9930521", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17949", "source" : "7716", "target" : "7717", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17949, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934205 (99342) 9934206", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934205 (99342) 9934206", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "16419", "source" : "6076", "target" : "6077", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16419, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801014 (28010) 2801015", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801014 (28010) 2801015", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "16418", "source" : "6075", "target" : "6076", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16418, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801013 (28010) 2801014", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801013 (28010) 2801014", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "17948", "source" : "7715", "target" : "7716", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17948, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934204 (99342) 9934205", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934204 (99342) 9934205", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "16417", "source" : "6074", "target" : "6075", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16417, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801012 (28010) 2801013", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801012 (28010) 2801013", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "17947", "source" : "7714", "target" : "7715", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17947, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934203 (99342) 9934204", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934203 (99342) 9934204", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "16416", "source" : "6073", "target" : "6074", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16416, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801011 (28010) 2801012", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801011 (28010) 2801012", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "17946", "source" : "7713", "target" : "7714", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17946, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934202 (99342) 9934203", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934202 (99342) 9934203", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "16415", "source" : "6072", "target" : "6073", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16415, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801010 (28010) 2801011", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801010 (28010) 2801011", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "17945", "source" : "7712", "target" : "7713", "line_name_k" : "ニッポリ・トネリライナー", "is_bullet" : false, "lon" : 139.76949647740912, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17945, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99342", "shared_interaction" : "99342", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "日暮里・舎人ライナー", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9934201 (99342) 9934202", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9934201 (99342) 9934202", "lat" : 35.78182568612205, "e_status_y" : 0, "line_name_h" : "日暮里・舎人ライナー" }, "selected" : false }, { "data" : { "id" : "16414", "source" : "6071", "target" : "6072", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16414, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801009 (28010) 2801010", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801009 (28010) 2801010", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "16413", "source" : "6070", "target" : "6071", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16413, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801008 (28010) 2801009", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801008 (28010) 2801009", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "17944", "source" : "7710", "target" : "7711", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17944, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930529 (99305) 9930530", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930529 (99305) 9930530", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "16412", "source" : "6069", "target" : "6070", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16412, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801007 (28010) 2801008", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801007 (28010) 2801008", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "17943", "source" : "7709", "target" : "7710", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17943, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930528 (99305) 9930529", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930528 (99305) 9930529", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "16408", "source" : "6065", "target" : "6066", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16408, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801003 (28010) 2801004", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801003 (28010) 2801004", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "16409", "source" : "6066", "target" : "6067", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16409, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801004 (28010) 2801005", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801004 (28010) 2801005", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "16410", "source" : "6067", "target" : "6068", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16410, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801005 (28010) 2801006", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801005 (28010) 2801006", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "16411", "source" : "6068", "target" : "6069", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16411, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801006 (28010) 2801007", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801006 (28010) 2801007", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "16405", "source" : "6061", "target" : "6062", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16405, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800918 (28009) 2800919", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800918 (28009) 2800919", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16407", "source" : "6064", "target" : "6065", "line_name_k" : "フクトシンセン", "is_bullet" : false, "lon" : 139.686663477539, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16407, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28010", "shared_interaction" : "28010", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ副都心線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2801002 (28010) 2801003", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2801002 (28010) 2801003", "lat" : 35.731442005432505, "e_status_y" : 0, "line_name_h" : "東京メトロ副都心線" }, "selected" : false }, { "data" : { "id" : "16401", "source" : "6057", "target" : "6058", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16401, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800914 (28009) 2800915", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800914 (28009) 2800915", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16402", "source" : "6058", "target" : "6059", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16402, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800915 (28009) 2800916", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800915 (28009) 2800916", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16403", "source" : "6059", "target" : "6060", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16403, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800916 (28009) 2800917", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800916 (28009) 2800917", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16404", "source" : "6060", "target" : "6061", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16404, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800917 (28009) 2800918", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800917 (28009) 2800918", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16397", "source" : "6053", "target" : "6054", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16397, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800910 (28009) 2800911", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800910 (28009) 2800911", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16398", "source" : "6054", "target" : "6055", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16398, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800911 (28009) 2800912", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800911 (28009) 2800912", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16399", "source" : "6055", "target" : "6056", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16399, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800912 (28009) 2800913", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800912 (28009) 2800913", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16400", "source" : "6056", "target" : "6057", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16400, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800913 (28009) 2800914", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800913 (28009) 2800914", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16394", "source" : "6050", "target" : "6051", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16394, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800907 (28009) 2800908", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800907 (28009) 2800908", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16393", "source" : "6049", "target" : "6050", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16393, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800906 (28009) 2800907", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800906 (28009) 2800907", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16396", "source" : "6052", "target" : "6053", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16396, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800909 (28009) 2800910", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800909 (28009) 2800910", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16395", "source" : "6051", "target" : "6052", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16395, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800908 (28009) 2800909", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800908 (28009) 2800909", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16390", "source" : "6046", "target" : "6047", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16390, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800903 (28009) 2800904", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800903 (28009) 2800904", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16389", "source" : "6045", "target" : "6046", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16389, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800902 (28009) 2800903", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800902 (28009) 2800903", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16392", "source" : "6048", "target" : "6049", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16392, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800905 (28009) 2800906", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800905 (28009) 2800906", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16391", "source" : "6047", "target" : "6048", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16391, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800904 (28009) 2800905", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800904 (28009) 2800905", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16387", "source" : "6042", "target" : "6043", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16387, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800812 (28008) 2800813", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800812 (28008) 2800813", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16386", "source" : "6041", "target" : "6042", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16386, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800814 (28008) 2800812", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800814 (28008) 2800812", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16388", "source" : "6044", "target" : "6045", "line_name_k" : "ナンボクセン", "is_bullet" : false, "lon" : 139.73433187075705, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16388, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28009", "shared_interaction" : "28009", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ南北線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800901 (28009) 2800902", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800901 (28009) 2800902", "lat" : 35.710299718407505, "e_status_y" : 0, "line_name_h" : "東京メトロ南北線" }, "selected" : false }, { "data" : { "id" : "16383", "source" : "6038", "target" : "6039", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16383, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800809 (28008) 2800810", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800809 (28008) 2800810", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16382", "source" : "6037", "target" : "6038", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16382, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800808 (28008) 2800809", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800808 (28008) 2800809", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16385", "source" : "6040", "target" : "6041", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16385, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800811 (28008) 2800814", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800811 (28008) 2800814", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16384", "source" : "6039", "target" : "6040", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16384, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800810 (28008) 2800811", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800810 (28008) 2800811", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16371", "source" : "6024", "target" : "6025", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16371, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800621 (28006) 2800622", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800621 (28006) 2800622", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16370", "source" : "6023", "target" : "6024", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16370, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800620 (28006) 2800621", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800620 (28006) 2800621", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16369", "source" : "6022", "target" : "6023", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16369, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800619 (28006) 2800620", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800619 (28006) 2800620", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16368", "source" : "6021", "target" : "6022", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16368, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800618 (28006) 2800619", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800618 (28006) 2800619", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16374", "source" : "6028", "target" : "6029", "line_name_k" : "ユウラクチョウシンセン", "is_bullet" : false, "lon" : 139.69139009521484, "company_name_k" : "トウキョウメトロ", "zoom" : 14, "SUID" : 16374, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28007", "shared_interaction" : "28007", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町新線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800701 (28007) 2800702", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 2, "shared_name" : "2800701 (28007) 2800702", "lat" : 35.73819936189844, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町新線" }, "selected" : false }, { "data" : { "id" : "16373", "source" : "6026", "target" : "6027", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16373, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800623 (28006) 2800624", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800623 (28006) 2800624", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16372", "source" : "6025", "target" : "6026", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16372, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800622 (28006) 2800623", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800622 (28006) 2800623", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16377", "source" : "6032", "target" : "6033", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16377, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800803 (28008) 2800804", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800803 (28008) 2800804", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16376", "source" : "6031", "target" : "6032", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16376, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800802 (28008) 2800803", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800802 (28008) 2800803", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16375", "source" : "6030", "target" : "6031", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16375, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800801 (28008) 2800802", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800801 (28008) 2800802", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16381", "source" : "6036", "target" : "6037", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16381, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800807 (28008) 2800808", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800807 (28008) 2800808", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16380", "source" : "6035", "target" : "6036", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16380, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800806 (28008) 2800807", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800806 (28008) 2800807", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16379", "source" : "6034", "target" : "6035", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16379, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800805 (28008) 2800806", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800805 (28008) 2800806", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16378", "source" : "6033", "target" : "6034", "line_name_k" : "ハンゾウモンセン", "is_bullet" : false, "lon" : 139.76522714815565, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16378, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28008", "shared_interaction" : "28008", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ半蔵門線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800804 (28008) 2800805", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800804 (28008) 2800805", "lat" : 35.68813210626038, "e_status_y" : 0, "line_name_h" : "東京メトロ半蔵門線" }, "selected" : false }, { "data" : { "id" : "16354", "source" : "6007", "target" : "6008", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16354, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800604 (28006) 2800605", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800604 (28006) 2800605", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16355", "source" : "6008", "target" : "6009", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16355, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800605 (28006) 2800606", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800605 (28006) 2800606", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16352", "source" : "6005", "target" : "6006", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16352, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800602 (28006) 2800603", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800602 (28006) 2800603", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16353", "source" : "6006", "target" : "6007", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16353, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800603 (28006) 2800604", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800603 (28006) 2800604", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16358", "source" : "6011", "target" : "6012", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16358, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800608 (28006) 2800609", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800608 (28006) 2800609", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16359", "source" : "6012", "target" : "6013", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16359, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800609 (28006) 2800610", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800609 (28006) 2800610", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16356", "source" : "6009", "target" : "6010", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16356, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800606 (28006) 2800607", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800606 (28006) 2800607", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16357", "source" : "6010", "target" : "6011", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16357, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800607 (28006) 2800608", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800607 (28006) 2800608", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16362", "source" : "6015", "target" : "6016", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16362, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800612 (28006) 2800613", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800612 (28006) 2800613", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16363", "source" : "6016", "target" : "6017", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16363, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800613 (28006) 2800614", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800613 (28006) 2800614", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16360", "source" : "6013", "target" : "6014", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16360, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800610 (28006) 2800611", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800610 (28006) 2800611", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16361", "source" : "6014", "target" : "6015", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16361, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800611 (28006) 2800612", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800611 (28006) 2800612", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16366", "source" : "6019", "target" : "6020", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16366, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800616 (28006) 2800617", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800616 (28006) 2800617", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16367", "source" : "6020", "target" : "6021", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16367, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800617 (28006) 2800618", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800617 (28006) 2800618", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16364", "source" : "6017", "target" : "6018", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16364, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800614 (28006) 2800615", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800614 (28006) 2800615", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16365", "source" : "6018", "target" : "6019", "line_name_k" : "ユウラクチョウセン", "is_bullet" : false, "lon" : 139.70420434309565, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16365, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28006", "shared_interaction" : "28006", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ有楽町線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800615 (28006) 2800616", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800615 (28006) 2800616", "lat" : 35.73316551916096, "e_status_y" : 0, "line_name_h" : "東京メトロ有楽町線" }, "selected" : false }, { "data" : { "id" : "16338", "source" : "5990", "target" : "5991", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16338, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800507 (28005) 2800508", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800507 (28005) 2800508", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16337", "source" : "5989", "target" : "5990", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16337, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800506 (28005) 2800507", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800506 (28005) 2800507", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16340", "source" : "5992", "target" : "5993", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16340, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800509 (28005) 2800510", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800509 (28005) 2800510", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16339", "source" : "5991", "target" : "5992", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16339, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800508 (28005) 2800509", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800508 (28005) 2800509", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16342", "source" : "5994", "target" : "5995", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16342, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800511 (28005) 2800512", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800511 (28005) 2800512", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16341", "source" : "5993", "target" : "5994", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16341, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800510 (28005) 2800511", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800510 (28005) 2800511", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16344", "source" : "5996", "target" : "5997", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16344, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800513 (28005) 2800514", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800513 (28005) 2800514", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16343", "source" : "5995", "target" : "5996", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16343, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800512 (28005) 2800513", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800512 (28005) 2800513", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16346", "source" : "5998", "target" : "5999", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16346, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800515 (28005) 2800516", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800515 (28005) 2800516", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16345", "source" : "5997", "target" : "5998", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16345, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800514 (28005) 2800515", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800514 (28005) 2800515", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16348", "source" : "6000", "target" : "6001", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16348, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800517 (28005) 2800518", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800517 (28005) 2800518", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16347", "source" : "5999", "target" : "6000", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16347, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800516 (28005) 2800517", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800516 (28005) 2800517", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16350", "source" : "6002", "target" : "6003", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16350, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800519 (28005) 2800520", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800519 (28005) 2800520", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16349", "source" : "6001", "target" : "6002", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16349, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800518 (28005) 2800519", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800518 (28005) 2800519", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16322", "source" : "5973", "target" : "5974", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16322, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800413 (28004) 2800414", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800413 (28004) 2800414", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16323", "source" : "5974", "target" : "5975", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16323, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800414 (28004) 2800415", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800414 (28004) 2800415", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16324", "source" : "5975", "target" : "5976", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16324, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800415 (28004) 2800416", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800415 (28004) 2800416", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16325", "source" : "5976", "target" : "5977", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16325, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800416 (28004) 2800417", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800416 (28004) 2800417", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16332", "source" : "5984", "target" : "5985", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16332, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800501 (28005) 2800502", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800501 (28005) 2800502", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16333", "source" : "5985", "target" : "5986", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16333, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800502 (28005) 2800503", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800502 (28005) 2800503", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16334", "source" : "5986", "target" : "5987", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16334, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800503 (28005) 2800504", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800503 (28005) 2800504", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16335", "source" : "5987", "target" : "5988", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16335, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800504 (28005) 2800505", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800504 (28005) 2800505", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16336", "source" : "5988", "target" : "5989", "line_name_k" : "チヨダセン", "is_bullet" : false, "lon" : 139.7558611955078, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16336, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28005", "shared_interaction" : "28005", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ千代田線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800505 (28005) 2800506", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800505 (28005) 2800506", "lat" : 35.723011671551085, "e_status_y" : 0, "line_name_h" : "東京メトロ千代田線" }, "selected" : false }, { "data" : { "id" : "16313", "source" : "5964", "target" : "5965", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16313, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800404 (28004) 2800405", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800404 (28004) 2800405", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16312", "source" : "5963", "target" : "5964", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16312, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800403 (28004) 2800404", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800403 (28004) 2800404", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16311", "source" : "5962", "target" : "5963", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16311, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800402 (28004) 2800403", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800402 (28004) 2800403", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16310", "source" : "5961", "target" : "5962", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16310, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800401 (28004) 2800402", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800401 (28004) 2800402", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16309", "source" : "5959", "target" : "5960", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16309, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800320 (28003) 2800321", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800320 (28003) 2800321", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16308", "source" : "5958", "target" : "5959", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16308, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800319 (28003) 2800320", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800319 (28003) 2800320", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16307", "source" : "5957", "target" : "5958", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16307, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800318 (28003) 2800319", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800318 (28003) 2800319", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16321", "source" : "5972", "target" : "5973", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16321, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800412 (28004) 2800413", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800412 (28004) 2800413", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16320", "source" : "5971", "target" : "5972", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16320, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800411 (28004) 2800412", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800411 (28004) 2800412", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16319", "source" : "5970", "target" : "5971", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16319, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800410 (28004) 2800411", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800410 (28004) 2800411", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16318", "source" : "5969", "target" : "5970", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16318, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800409 (28004) 2800410", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800409 (28004) 2800410", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16317", "source" : "5968", "target" : "5969", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16317, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800408 (28004) 2800409", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800408 (28004) 2800409", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16316", "source" : "5967", "target" : "5968", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16316, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800407 (28004) 2800408", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800407 (28004) 2800408", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16315", "source" : "5966", "target" : "5967", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16315, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800406 (28004) 2800407", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800406 (28004) 2800407", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16314", "source" : "5965", "target" : "5966", "line_name_k" : "トウザイセン", "is_bullet" : false, "lon" : 139.8154913497142, "company_name_k" : "トウキョウメトロ", "zoom" : 11, "SUID" : 16314, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28004", "shared_interaction" : "28004", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ東西線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800405 (28004) 2800406", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800405 (28004) 2800406", "lat" : 35.683265329761525, "e_status_y" : 0, "line_name_h" : "東京メトロ東西線" }, "selected" : false }, { "data" : { "id" : "16297", "source" : "5947", "target" : "5948", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16297, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800308 (28003) 2800309", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800308 (28003) 2800309", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16298", "source" : "5948", "target" : "5949", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16298, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800309 (28003) 2800310", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800309 (28003) 2800310", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16295", "source" : "5945", "target" : "5946", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16295, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800306 (28003) 2800307", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800306 (28003) 2800307", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16296", "source" : "5946", "target" : "5947", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16296, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800307 (28003) 2800308", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800307 (28003) 2800308", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16293", "source" : "5943", "target" : "5944", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16293, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800304 (28003) 2800305", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800304 (28003) 2800305", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16294", "source" : "5944", "target" : "5945", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16294, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800305 (28003) 2800306", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800305 (28003) 2800306", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16291", "source" : "5941", "target" : "5942", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16291, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800302 (28003) 2800303", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800302 (28003) 2800303", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16292", "source" : "5942", "target" : "5943", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16292, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800303 (28003) 2800304", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800303 (28003) 2800304", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16305", "source" : "5955", "target" : "5956", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16305, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800316 (28003) 2800317", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800316 (28003) 2800317", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16306", "source" : "5956", "target" : "5957", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16306, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800317 (28003) 2800318", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800317 (28003) 2800318", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16303", "source" : "5953", "target" : "5954", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16303, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800314 (28003) 2800315", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800314 (28003) 2800315", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16304", "source" : "5954", "target" : "5955", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16304, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800315 (28003) 2800316", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800315 (28003) 2800316", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16301", "source" : "5951", "target" : "5952", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16301, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800312 (28003) 2800313", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800312 (28003) 2800313", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16302", "source" : "5952", "target" : "5953", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16302, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800313 (28003) 2800314", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800313 (28003) 2800314", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16299", "source" : "5949", "target" : "5950", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16299, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800310 (28003) 2800311", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800310 (28003) 2800311", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16300", "source" : "5950", "target" : "5951", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16300, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800311 (28003) 2800312", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800311 (28003) 2800312", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16281", "source" : "5930", "target" : "5931", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16281, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800219 (28002) 2800220", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800219 (28002) 2800220", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16280", "source" : "5929", "target" : "5930", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16280, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800218 (28002) 2800219", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800218 (28002) 2800219", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16284", "source" : "5932", "target" : "5934", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16284, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800221 (28002) 2800222", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800221 (28002) 2800222", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16282", "source" : "5931", "target" : "5932", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16282, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800220 (28002) 2800221", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800220 (28002) 2800221", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16283", "source" : "5931", "target" : "5933", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16283, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800220 (28002) 2800226", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800220 (28002) 2800226", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16277", "source" : "5926", "target" : "5927", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16277, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800215 (28002) 2800216", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800215 (28002) 2800216", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16276", "source" : "5925", "target" : "5926", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16276, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800214 (28002) 2800215", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800214 (28002) 2800215", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16279", "source" : "5928", "target" : "5929", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16279, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800217 (28002) 2800218", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800217 (28002) 2800218", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16278", "source" : "5927", "target" : "5928", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16278, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800216 (28002) 2800217", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800216 (28002) 2800217", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16289", "source" : "5938", "target" : "5939", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16289, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800227 (28002) 2800228", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800227 (28002) 2800228", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16290", "source" : "5940", "target" : "5941", "line_name_k" : "ヒビヤセン", "is_bullet" : false, "lon" : 139.76790012172296, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16290, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28003", "shared_interaction" : "28003", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ日比谷線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800301 (28003) 2800302", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800301 (28003) 2800302", "lat" : 35.69469233873322, "e_status_y" : 0, "line_name_h" : "東京メトロ日比谷線" }, "selected" : false }, { "data" : { "id" : "16286", "source" : "5934", "target" : "5935", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16286, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800222 (28002) 2800223", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800222 (28002) 2800223", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16285", "source" : "5933", "target" : "5938", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16285, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800226 (28002) 2800227", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800226 (28002) 2800227", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16288", "source" : "5936", "target" : "5937", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16288, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800224 (28002) 2800225", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800224 (28002) 2800225", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16287", "source" : "5935", "target" : "5936", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16287, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800223 (28002) 2800224", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800223 (28002) 2800224", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16264", "source" : "5913", "target" : "5914", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16264, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800202 (28002) 2800203", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800202 (28002) 2800203", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16265", "source" : "5914", "target" : "5915", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16265, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800203 (28002) 2800204", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800203 (28002) 2800204", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16266", "source" : "5915", "target" : "5916", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16266, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800204 (28002) 2800205", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800204 (28002) 2800205", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16267", "source" : "5916", "target" : "5917", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16267, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800205 (28002) 2800206", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800205 (28002) 2800206", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16261", "source" : "5909", "target" : "5910", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16261, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800117 (28001) 2800118", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800117 (28001) 2800118", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16262", "source" : "5910", "target" : "5911", "line_name_k" : "ギンザセン", "is_bullet" : false, "lon" : 139.75720810526002, "company_name_k" : "トウキョウメトロ", "zoom" : 13, "SUID" : 16262, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28001", "shared_interaction" : "28001", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ銀座線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800118 (28001) 2800119", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800118 (28001) 2800119", "lat" : 35.68646095045909, "e_status_y" : 0, "line_name_h" : "東京メトロ銀座線" }, "selected" : false }, { "data" : { "id" : "16263", "source" : "5912", "target" : "5913", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16263, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800201 (28002) 2800202", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800201 (28002) 2800202", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16272", "source" : "5921", "target" : "5922", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16272, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800210 (28002) 2800211", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800210 (28002) 2800211", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16273", "source" : "5922", "target" : "5923", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16273, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800211 (28002) 2800212", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800211 (28002) 2800212", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16274", "source" : "5923", "target" : "5924", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16274, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800212 (28002) 2800213", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800212 (28002) 2800213", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16275", "source" : "5924", "target" : "5925", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16275, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800213 (28002) 2800214", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800213 (28002) 2800214", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16268", "source" : "5917", "target" : "5918", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16268, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800206 (28002) 2800207", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800206 (28002) 2800207", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16269", "source" : "5918", "target" : "5919", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16269, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800207 (28002) 2800208", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800207 (28002) 2800208", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16270", "source" : "5919", "target" : "5920", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16270, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800208 (28002) 2800209", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800208 (28002) 2800209", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "16271", "source" : "5920", "target" : "5921", "line_name_k" : "マルノウチセン", "is_bullet" : false, "lon" : 139.70043660044496, "company_name_k" : "トウキョウメトロ", "zoom" : 12, "SUID" : 16271, "company_type" : 2, "company_name_h" : "東京地下鉄株式会社", "interaction" : "28002", "shared_interaction" : "28002", "company_url" : "http://www.tokyometro.jp/", "line_name" : "東京メトロ丸ノ内線", "selected" : false, "company_name" : "東京メトロ", "company_cd" : 18, "name" : "2800209 (28002) 2800210", "rr_cd" : 28, "company_name_r" : "東京メトロ", "e_status_x" : 0, "shared_name" : "2800209 (28002) 2800210", "lat" : 35.70518513577206, "e_status_y" : 0, "line_name_h" : "東京メトロ丸ノ内線" }, "selected" : false }, { "data" : { "id" : "13589", "source" : "3103", "target" : "3104", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13589, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132108 (11321) 1132109", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132108 (11321) 1132109", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "13590", "source" : "3104", "target" : "3105", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13590, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132109 (11321) 1132110", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132109 (11321) 1132110", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "13587", "source" : "3101", "target" : "3102", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13587, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132106 (11321) 1132107", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132106 (11321) 1132107", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "13588", "source" : "3102", "target" : "3103", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13588, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132107 (11321) 1132108", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132107 (11321) 1132108", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "13582", "source" : "3096", "target" : "3097", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13582, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132101 (11321) 1132102", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132101 (11321) 1132102", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "13585", "source" : "3099", "target" : "3100", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13585, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132104 (11321) 1132105", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132104 (11321) 1132105", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "15701", "source" : "5300", "target" : "5301", "line_name_k" : "トウブカメイドセン", "is_bullet" : false, "lon" : 139.8243467565918, "company_name_k" : "トウブテツドウ", "zoom" : 14, "SUID" : 15701, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21005", "shared_interaction" : "21005", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武亀戸線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100501 (21005) 2100502", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100501 (21005) 2100502", "lat" : 35.707951515131064, "e_status_y" : 0, "line_name_h" : "東武亀戸線" }, "selected" : false }, { "data" : { "id" : "13586", "source" : "3100", "target" : "3101", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13586, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132105 (11321) 1132106", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132105 (11321) 1132106", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "13583", "source" : "3097", "target" : "3098", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13583, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132102 (11321) 1132103", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132102 (11321) 1132103", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "13584", "source" : "3098", "target" : "3099", "line_name_k" : "サイキョウセン", "is_bullet" : false, "lon" : 139.6182015405503, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13584, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11321", "shared_interaction" : "11321", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR埼京線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132103 (11321) 1132104", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132103 (11321) 1132104", "lat" : 35.80319581571332, "e_status_y" : 0, "line_name_h" : "JR埼京線" }, "selected" : false }, { "data" : { "id" : "15703", "source" : "5302", "target" : "5303", "line_name_k" : "トウブカメイドセン", "is_bullet" : false, "lon" : 139.8243467565918, "company_name_k" : "トウブテツドウ", "zoom" : 14, "SUID" : 15703, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21005", "shared_interaction" : "21005", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武亀戸線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100503 (21005) 2100504", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100503 (21005) 2100504", "lat" : 35.707951515131064, "e_status_y" : 0, "line_name_h" : "東武亀戸線" }, "selected" : false }, { "data" : { "id" : "15702", "source" : "5301", "target" : "5302", "line_name_k" : "トウブカメイドセン", "is_bullet" : false, "lon" : 139.8243467565918, "company_name_k" : "トウブテツドウ", "zoom" : 14, "SUID" : 15702, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21005", "shared_interaction" : "21005", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武亀戸線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100502 (21005) 2100503", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100502 (21005) 2100503", "lat" : 35.707951515131064, "e_status_y" : 0, "line_name_h" : "東武亀戸線" }, "selected" : false }, { "data" : { "id" : "15704", "source" : "5303", "target" : "5304", "line_name_k" : "トウブカメイドセン", "is_bullet" : false, "lon" : 139.8243467565918, "company_name_k" : "トウブテツドウ", "zoom" : 14, "SUID" : 15704, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21005", "shared_interaction" : "21005", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武亀戸線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100504 (21005) 2100505", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100504 (21005) 2100505", "lat" : 35.707951515131064, "e_status_y" : 0, "line_name_h" : "東武亀戸線" }, "selected" : false }, { "data" : { "id" : "15705", "source" : "5305", "target" : "5306", "line_name_k" : "トウブダイシセン", "is_bullet" : false, "lon" : 139.78532285449214, "company_name_k" : "トウブテツドウ", "zoom" : 15, "SUID" : 15705, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21006", "shared_interaction" : "21006", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武大師線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100601 (21006) 2100602", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100601 (21006) 2100602", "lat" : 35.77906122777853, "e_status_y" : 0, "line_name_h" : "東武大師線" }, "selected" : false }, { "data" : { "id" : "13610", "source" : "3126", "target" : "3127", "line_name_k" : "タカサキセン", "is_bullet" : false, "lon" : 139.45218074609377, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13610, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11323", "shared_interaction" : "11323", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR高崎線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132301 (11323) 1132302", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132301 (11323) 1132302", "lat" : 36.09573564081418, "e_status_y" : 0, "line_name_h" : "JR高崎線" }, "selected" : false }, { "data" : { "id" : "13611", "source" : "3127", "target" : "3128", "line_name_k" : "タカサキセン", "is_bullet" : false, "lon" : 139.45218074609377, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13611, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11323", "shared_interaction" : "11323", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR高崎線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132302 (11323) 1132303", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132302 (11323) 1132303", "lat" : 36.09573564081418, "e_status_y" : 0, "line_name_h" : "JR高崎線" }, "selected" : false }, { "data" : { "id" : "15756", "source" : "5363", "target" : "5364", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15756, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200102 (22001) 2200103", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200102 (22001) 2200103", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15757", "source" : "5364", "target" : "5365", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15757, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200103 (22001) 2200104", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200103 (22001) 2200104", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15755", "source" : "5362", "target" : "5363", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15755, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200101 (22001) 2200102", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200101 (22001) 2200102", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15763", "source" : "5370", "target" : "5371", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15763, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200109 (22001) 2200110", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200109 (22001) 2200110", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15762", "source" : "5369", "target" : "5370", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15762, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200108 (22001) 2200109", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200108 (22001) 2200109", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15765", "source" : "5372", "target" : "5373", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15765, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200111 (22001) 2200112", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200111 (22001) 2200112", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15764", "source" : "5371", "target" : "5372", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15764, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200110 (22001) 2200111", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200110 (22001) 2200111", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15759", "source" : "5366", "target" : "5367", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15759, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200105 (22001) 2200106", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200105 (22001) 2200106", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "13694", "source" : "3213", "target" : "3214", "line_name_k" : "ケイヨウセン", "is_bullet" : false, "lon" : 139.93611002907872, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13694, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11326", "shared_interaction" : "11326", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京葉線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132605 (11326) 1132606", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132605 (11326) 1132606", "lat" : 35.643649620088546, "e_status_y" : 0, "line_name_h" : "JR京葉線" }, "selected" : false }, { "data" : { "id" : "15758", "source" : "5365", "target" : "5366", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15758, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200104 (22001) 2200105", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200104 (22001) 2200105", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15761", "source" : "5368", "target" : "5369", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15761, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200107 (22001) 2200108", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200107 (22001) 2200108", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15760", "source" : "5367", "target" : "5368", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15760, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200106 (22001) 2200107", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200106 (22001) 2200107", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "13691", "source" : "3210", "target" : "3211", "line_name_k" : "ケイヨウセン", "is_bullet" : false, "lon" : 139.93611002907872, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13691, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11326", "shared_interaction" : "11326", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京葉線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132602 (11326) 1132603", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132602 (11326) 1132603", "lat" : 35.643649620088546, "e_status_y" : 0, "line_name_h" : "JR京葉線" }, "selected" : false }, { "data" : { "id" : "13690", "source" : "3209", "target" : "3210", "line_name_k" : "ケイヨウセン", "is_bullet" : false, "lon" : 139.93611002907872, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13690, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11326", "shared_interaction" : "11326", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京葉線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132601 (11326) 1132602", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132601 (11326) 1132602", "lat" : 35.643649620088546, "e_status_y" : 0, "line_name_h" : "JR京葉線" }, "selected" : false }, { "data" : { "id" : "13693", "source" : "3212", "target" : "3213", "line_name_k" : "ケイヨウセン", "is_bullet" : false, "lon" : 139.93611002907872, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13693, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11326", "shared_interaction" : "11326", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京葉線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132604 (11326) 1132605", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132604 (11326) 1132605", "lat" : 35.643649620088546, "e_status_y" : 0, "line_name_h" : "JR京葉線" }, "selected" : false }, { "data" : { "id" : "13692", "source" : "3211", "target" : "3212", "line_name_k" : "ケイヨウセン", "is_bullet" : false, "lon" : 139.93611002907872, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13692, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11326", "shared_interaction" : "11326", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京葉線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132603 (11326) 1132604", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132603 (11326) 1132604", "lat" : 35.643649620088546, "e_status_y" : 0, "line_name_h" : "JR京葉線" }, "selected" : false }, { "data" : { "id" : "15767", "source" : "5374", "target" : "5375", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15767, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200113 (22001) 2200114", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200113 (22001) 2200114", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15766", "source" : "5373", "target" : "5374", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15766, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200112 (22001) 2200113", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200112 (22001) 2200113", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15769", "source" : "5376", "target" : "5377", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15769, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200115 (22001) 2200116", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200115 (22001) 2200116", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "15768", "source" : "5375", "target" : "5376", "line_name_k" : "セイブイケブクロセン", "is_bullet" : false, "lon" : 139.46789285918442, "company_name_k" : "セイブテツドウ", "zoom" : 10, "SUID" : 15768, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22001", "shared_interaction" : "22001", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武池袋線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200114 (22001) 2200115", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200114 (22001) 2200115", "lat" : 35.791261736068634, "e_status_y" : 0, "line_name_h" : "西武池袋線" }, "selected" : false }, { "data" : { "id" : "17845", "source" : "7607", "target" : "7608", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17845, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930132 (99301) 9930133", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930132 (99301) 9930133", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15556", "source" : "5151", "target" : "5152", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15556, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100106 (21001) 2100107", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100106 (21001) 2100107", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17846", "source" : "7608", "target" : "7609", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17846, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930133 (99301) 9930134", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930133 (99301) 9930134", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15557", "source" : "5152", "target" : "5153", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15557, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100107 (21001) 2100108", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100107 (21001) 2100108", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17843", "source" : "7605", "target" : "7606", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17843, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930130 (99301) 9930131", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930130 (99301) 9930131", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15554", "source" : "5149", "target" : "5150", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15554, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100104 (21001) 2100105", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100104 (21001) 2100105", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17844", "source" : "7606", "target" : "7607", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17844, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930131 (99301) 9930132", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930131 (99301) 9930132", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15555", "source" : "5150", "target" : "5151", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15555, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100105 (21001) 2100106", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100105 (21001) 2100106", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17849", "source" : "7611", "target" : "7612", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17849, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930136 (99301) 9930137", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930136 (99301) 9930137", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17850", "source" : "7612", "target" : "7613", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17850, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930137 (99301) 9930138", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930137 (99301) 9930138", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17847", "source" : "7609", "target" : "7610", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17847, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930134 (99301) 9930135", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930134 (99301) 9930135", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15558", "source" : "5153", "target" : "5154", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15558, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100108 (21001) 2100109", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100108 (21001) 2100109", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17848", "source" : "7610", "target" : "7611", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17848, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930135 (99301) 9930136", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930135 (99301) 9930136", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15559", "source" : "5154", "target" : "5155", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15559, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100109 (21001) 2100110", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100109 (21001) 2100110", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17852", "source" : "7615", "target" : "7616", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17852, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930202 (99302) 9930203", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930202 (99302) 9930203", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17853", "source" : "7616", "target" : "7617", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17853, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930203 (99302) 9930204", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930203 (99302) 9930204", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17851", "source" : "7614", "target" : "7615", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17851, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930201 (99302) 9930202", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930201 (99302) 9930202", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "15552", "source" : "5147", "target" : "5148", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15552, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100102 (21001) 2100103", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100102 (21001) 2100103", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17856", "source" : "7619", "target" : "7620", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17856, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930206 (99302) 9930207", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930206 (99302) 9930207", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17857", "source" : "7620", "target" : "7621", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17857, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930207 (99302) 9930208", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930207 (99302) 9930208", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "15553", "source" : "5148", "target" : "5149", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15553, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100103 (21001) 2100104", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100103 (21001) 2100104", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17854", "source" : "7617", "target" : "7618", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17854, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930204 (99302) 9930205", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930204 (99302) 9930205", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "15551", "source" : "5146", "target" : "5147", "line_name_k" : "トウブトウジョウセン", "is_bullet" : false, "lon" : 139.4596378608162, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15551, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21001", "shared_interaction" : "21001", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武東上線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100101 (21001) 2100102", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100101 (21001) 2100102", "lat" : 35.921218671003345, "e_status_y" : 0, "line_name_h" : "東武東上線" }, "selected" : false }, { "data" : { "id" : "17855", "source" : "7618", "target" : "7619", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17855, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930205 (99302) 9930206", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930205 (99302) 9930206", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17861", "source" : "7624", "target" : "7625", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17861, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930211 (99302) 9930212", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930211 (99302) 9930212", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17860", "source" : "7623", "target" : "7624", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17860, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930210 (99302) 9930211", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930210 (99302) 9930211", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17859", "source" : "7622", "target" : "7623", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17859, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930209 (99302) 9930210", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930209 (99302) 9930210", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17858", "source" : "7621", "target" : "7622", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17858, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930208 (99302) 9930209", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930208 (99302) 9930209", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17865", "source" : "7628", "target" : "7629", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17865, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930215 (99302) 9930216", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930215 (99302) 9930216", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17864", "source" : "7627", "target" : "7628", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17864, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930214 (99302) 9930215", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930214 (99302) 9930215", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17863", "source" : "7626", "target" : "7627", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17863, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930213 (99302) 9930214", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930213 (99302) 9930214", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17862", "source" : "7625", "target" : "7626", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17862, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930212 (99302) 9930213", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930212 (99302) 9930213", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17869", "source" : "7632", "target" : "7633", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17869, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930219 (99302) 9930220", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930219 (99302) 9930220", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17868", "source" : "7631", "target" : "7632", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17868, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930218 (99302) 9930219", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930218 (99302) 9930219", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17867", "source" : "7630", "target" : "7631", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17867, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930217 (99302) 9930218", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930217 (99302) 9930218", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17866", "source" : "7629", "target" : "7630", "line_name_k" : "トエイアサクサセン", "is_bullet" : false, "lon" : 139.75860382724613, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17866, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99302", "shared_interaction" : "99302", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営浅草線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930216 (99302) 9930217", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930216 (99302) 9930217", "lat" : 35.66226194441651, "e_status_y" : 0, "line_name_h" : "都営浅草線" }, "selected" : false }, { "data" : { "id" : "17872", "source" : "7636", "target" : "7637", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17872, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930303 (99303) 9930304", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930303 (99303) 9930304", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17871", "source" : "7635", "target" : "7636", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17871, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930302 (99303) 9930303", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930302 (99303) 9930303", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17870", "source" : "7634", "target" : "7635", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17870, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930301 (99303) 9930302", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930301 (99303) 9930302", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13749", "source" : "3270", "target" : "3271", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13749, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132815 (11328) 1132816", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132815 (11328) 1132816", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "13750", "source" : "3271", "target" : "3272", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13750, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132816 (11328) 1132817", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132816 (11328) 1132817", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "13751", "source" : "3272", "target" : "3273", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13751, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132817 (11328) 1132818", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132817 (11328) 1132818", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17813", "source" : "7576", "target" : "7577", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17813, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930101 (99301) 9930129", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930101 (99301) 9930129", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17814", "source" : "7576", "target" : "7578", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17814, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930101 (99301) 9930102", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930101 (99301) 9930102", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15588", "source" : "5184", "target" : "5185", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15588, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100201 (21002) 2100202", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100201 (21002) 2100202", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "13752", "source" : "3273", "target" : "3274", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13752, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132818 (11328) 1132819", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132818 (11328) 1132819", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17815", "source" : "7577", "target" : "7605", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17815, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930129 (99301) 9930130", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930129 (99301) 9930130", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15589", "source" : "5185", "target" : "5186", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15589, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100202 (21002) 2100203", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100202 (21002) 2100203", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "13753", "source" : "3274", "target" : "3275", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13753, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132819 (11328) 1132820", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132819 (11328) 1132820", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17816", "source" : "7578", "target" : "7579", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17816, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930102 (99301) 9930103", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930102 (99301) 9930103", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15590", "source" : "5186", "target" : "5187", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15590, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100203 (21002) 2100204", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100203 (21002) 2100204", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "13754", "source" : "3275", "target" : "3261", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13754, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132820 (11328) 1132806", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132820 (11328) 1132806", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17817", "source" : "7579", "target" : "7580", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17817, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930103 (99301) 9930104", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930103 (99301) 9930104", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15591", "source" : "5187", "target" : "5188", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15591, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100204 (21002) 2100205", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100204 (21002) 2100205", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "15592", "source" : "5188", "target" : "5189", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15592, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100205 (21002) 2100206", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100205 (21002) 2100206", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "17818", "source" : "7580", "target" : "7581", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17818, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930104 (99301) 9930105", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930104 (99301) 9930105", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17819", "source" : "7581", "target" : "7582", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17819, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930105 (99301) 9930106", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930105 (99301) 9930106", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17820", "source" : "7582", "target" : "7583", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17820, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930106 (99301) 9930107", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930106 (99301) 9930107", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17821", "source" : "7583", "target" : "7584", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17821, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930107 (99301) 9930108", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930107 (99301) 9930108", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17822", "source" : "7584", "target" : "7585", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17822, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930108 (99301) 9930109", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930108 (99301) 9930109", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17823", "source" : "7585", "target" : "7586", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17823, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930109 (99301) 9930110", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930109 (99301) 9930110", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17824", "source" : "7586", "target" : "7587", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17824, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930110 (99301) 9930111", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930110 (99301) 9930111", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17825", "source" : "7587", "target" : "7588", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17825, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930111 (99301) 9930112", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930111 (99301) 9930112", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17826", "source" : "7588", "target" : "7589", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17826, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930112 (99301) 9930113", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930112 (99301) 9930113", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17828", "source" : "7590", "target" : "7591", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17828, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930114 (99301) 9930115", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930114 (99301) 9930115", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17827", "source" : "7589", "target" : "7590", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17827, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930113 (99301) 9930114", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930113 (99301) 9930114", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17830", "source" : "7592", "target" : "7593", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17830, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930116 (99301) 9930117", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930116 (99301) 9930117", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17829", "source" : "7591", "target" : "7592", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17829, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930115 (99301) 9930116", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930115 (99301) 9930116", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17832", "source" : "7594", "target" : "7595", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17832, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930118 (99301) 9930119", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930118 (99301) 9930119", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17831", "source" : "7593", "target" : "7594", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17831, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930117 (99301) 9930118", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930117 (99301) 9930118", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "13740", "source" : "3260", "target" : "3261", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13740, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132805 (11328) 1132806", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132805 (11328) 1132806", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17834", "source" : "7596", "target" : "7597", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17834, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930120 (99301) 9930121", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930120 (99301) 9930121", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17833", "source" : "7595", "target" : "7596", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17833, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930119 (99301) 9930120", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930119 (99301) 9930120", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15594", "source" : "5190", "target" : "5191", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15594, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100207 (21002) 2100208", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100207 (21002) 2100208", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "13742", "source" : "3262", "target" : "3263", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13742, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132807 (11328) 1132808", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132807 (11328) 1132808", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17836", "source" : "7598", "target" : "7599", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17836, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930122 (99301) 9930123", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930122 (99301) 9930123", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15593", "source" : "5189", "target" : "5190", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15593, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100206 (21002) 2100207", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100206 (21002) 2100207", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "13741", "source" : "3261", "target" : "3262", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13741, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132806 (11328) 1132807", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132806 (11328) 1132807", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17835", "source" : "7597", "target" : "7598", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17835, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930121 (99301) 9930122", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930121 (99301) 9930122", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15596", "source" : "5192", "target" : "5193", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15596, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100209 (21002) 2100210", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100209 (21002) 2100210", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "17838", "source" : "7600", "target" : "7601", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17838, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930124 (99301) 9930125", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930124 (99301) 9930125", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15595", "source" : "5191", "target" : "5192", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15595, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100208 (21002) 2100209", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100208 (21002) 2100209", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "13743", "source" : "3263", "target" : "3264", "line_name_k" : "ナリタエクスプレス", "is_bullet" : false, "lon" : 139.7571982434863, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13743, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11328", "shared_interaction" : "11328", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR成田エクスプレス", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132808 (11328) 1132809", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132808 (11328) 1132809", "lat" : 35.69212091775545, "e_status_y" : 0, "line_name_h" : "JR成田エクスプレス" }, "selected" : false }, { "data" : { "id" : "17837", "source" : "7599", "target" : "7600", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17837, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930123 (99301) 9930124", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930123 (99301) 9930124", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15598", "source" : "5194", "target" : "5195", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15598, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100211 (21002) 2100212", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100211 (21002) 2100212", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "17840", "source" : "7602", "target" : "7603", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17840, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930126 (99301) 9930127", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930126 (99301) 9930127", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15597", "source" : "5193", "target" : "5194", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15597, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100210 (21002) 2100211", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100210 (21002) 2100211", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "17839", "source" : "7601", "target" : "7602", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17839, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930125 (99301) 9930126", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930125 (99301) 9930126", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15600", "source" : "5196", "target" : "5197", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15600, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100213 (21002) 2100214", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100213 (21002) 2100214", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "17842", "source" : "7604", "target" : "7576", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17842, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930128 (99301) 9930101", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930128 (99301) 9930101", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "15599", "source" : "5195", "target" : "5196", "line_name_k" : "トウブイセサキセン", "is_bullet" : false, "lon" : 139.49934131661746, "company_name_k" : "トウブテツドウ", "zoom" : 10, "SUID" : 15599, "company_type" : 2, "company_name_h" : "東武鉄道株式会社", "interaction" : "21002", "shared_interaction" : "21002", "company_url" : "http://www.tobu.co.jp/", "line_name" : "東武伊勢崎線", "selected" : false, "company_name" : "東武鉄道", "company_cd" : 11, "name" : "2100212 (21002) 2100213", "rr_cd" : 21, "company_name_r" : "東武", "e_status_x" : 0, "shared_name" : "2100212 (21002) 2100213", "lat" : 36.05676642458757, "e_status_y" : 0, "line_name_h" : "東武伊勢崎線" }, "selected" : false }, { "data" : { "id" : "17841", "source" : "7603", "target" : "7604", "line_name_k" : "トエイオオエドセン", "is_bullet" : false, "lon" : 139.7137041757577, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17841, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99301", "shared_interaction" : "99301", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営大江戸線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930127 (99301) 9930128", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930127 (99301) 9930128", "lat" : 35.70754622711237, "e_status_y" : 0, "line_name_h" : "都営大江戸線" }, "selected" : false }, { "data" : { "id" : "17910", "source" : "7675", "target" : "7676", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17910, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930415 (99304) 9930416", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930415 (99304) 9930416", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17911", "source" : "7676", "target" : "7677", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17911, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930416 (99304) 9930417", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930416 (99304) 9930417", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17908", "source" : "7673", "target" : "7674", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17908, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930413 (99304) 9930414", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930413 (99304) 9930414", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17909", "source" : "7674", "target" : "7675", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17909, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930414 (99304) 9930415", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930414 (99304) 9930415", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17906", "source" : "7671", "target" : "7672", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17906, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930411 (99304) 9930412", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930411 (99304) 9930412", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17907", "source" : "7672", "target" : "7673", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17907, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930412 (99304) 9930413", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930412 (99304) 9930413", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17904", "source" : "7669", "target" : "7670", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17904, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930409 (99304) 9930410", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930409 (99304) 9930410", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17905", "source" : "7670", "target" : "7671", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17905, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930410 (99304) 9930411", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930410 (99304) 9930411", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "13791", "source" : "3315", "target" : "3316", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13791, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133214 (11332) 1133215", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133214 (11332) 1133215", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17917", "source" : "7683", "target" : "7684", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17917, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930502 (99305) 9930503", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930502 (99305) 9930503", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "13792", "source" : "3316", "target" : "3317", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13792, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133215 (11332) 1133216", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133215 (11332) 1133216", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17918", "source" : "7684", "target" : "7685", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17918, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930503 (99305) 9930504", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930503 (99305) 9930504", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "13789", "source" : "3313", "target" : "3314", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13789, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133212 (11332) 1133213", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133212 (11332) 1133213", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "13790", "source" : "3314", "target" : "3315", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13790, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133213 (11332) 1133214", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133213 (11332) 1133214", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17916", "source" : "7682", "target" : "7683", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17916, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930501 (99305) 9930502", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930501 (99305) 9930502", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "13787", "source" : "3311", "target" : "3312", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13787, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133210 (11332) 1133211", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133210 (11332) 1133211", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17914", "source" : "7679", "target" : "7680", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17914, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930419 (99304) 9930420", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930419 (99304) 9930420", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "13788", "source" : "3312", "target" : "3313", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13788, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133211 (11332) 1133212", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133211 (11332) 1133212", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17912", "source" : "7677", "target" : "7678", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17912, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930417 (99304) 9930418", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930417 (99304) 9930418", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17913", "source" : "7678", "target" : "7679", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17913, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930418 (99304) 9930419", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930418 (99304) 9930419", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17926", "source" : "7692", "target" : "7693", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17926, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930511 (99305) 9930512", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930511 (99305) 9930512", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17925", "source" : "7691", "target" : "7692", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17925, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930510 (99305) 9930511", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930510 (99305) 9930511", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17924", "source" : "7690", "target" : "7691", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17924, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930509 (99305) 9930510", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930509 (99305) 9930510", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17923", "source" : "7689", "target" : "7690", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17923, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930508 (99305) 9930509", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930508 (99305) 9930509", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17922", "source" : "7688", "target" : "7689", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17922, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930507 (99305) 9930508", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930507 (99305) 9930508", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17921", "source" : "7687", "target" : "7688", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17921, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930506 (99305) 9930507", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930506 (99305) 9930507", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17920", "source" : "7686", "target" : "7687", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17920, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930505 (99305) 9930506", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930505 (99305) 9930506", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17919", "source" : "7685", "target" : "7686", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17919, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930504 (99305) 9930505", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930504 (99305) 9930505", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17934", "source" : "7700", "target" : "7701", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17934, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930519 (99305) 9930520", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930519 (99305) 9930520", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17933", "source" : "7699", "target" : "7700", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17933, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930518 (99305) 9930519", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930518 (99305) 9930519", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17932", "source" : "7698", "target" : "7699", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17932, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930517 (99305) 9930518", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930517 (99305) 9930518", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17931", "source" : "7697", "target" : "7698", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17931, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930516 (99305) 9930517", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930516 (99305) 9930517", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17930", "source" : "7696", "target" : "7697", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17930, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930515 (99305) 9930516", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930515 (99305) 9930516", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17929", "source" : "7695", "target" : "7696", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17929, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930514 (99305) 9930515", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930514 (99305) 9930515", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17928", "source" : "7694", "target" : "7695", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17928, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930513 (99305) 9930514", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930513 (99305) 9930514", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17927", "source" : "7693", "target" : "7694", "line_name_k" : "トデンアラカワセン", "is_bullet" : false, "lon" : 139.74861502275394, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 13, "SUID" : 17927, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99305", "shared_interaction" : "99305", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都電荒川線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930512 (99305) 9930513", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930512 (99305) 9930513", "lat" : 35.735016925780094, "e_status_y" : 0, "line_name_h" : "都営都電荒川線" }, "selected" : false }, { "data" : { "id" : "17877", "source" : "7641", "target" : "7642", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17877, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930308 (99303) 9930309", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930308 (99303) 9930309", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17878", "source" : "7642", "target" : "7643", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17878, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930309 (99303) 9930310", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930309 (99303) 9930310", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13814", "source" : "3339", "target" : "3340", "line_name_k" : "ショウナンシンジュクライン", "is_bullet" : false, "lon" : 139.6229436643263, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13814, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11333", "shared_interaction" : "11333", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR湘南新宿ライン", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133302 (11333) 1133303", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133302 (11333) 1133303", "lat" : 35.65739974071942, "e_status_y" : 0, "line_name_h" : "JR湘南新宿ライン" }, "selected" : false }, { "data" : { "id" : "17879", "source" : "7643", "target" : "7644", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17879, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930310 (99303) 9930311", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930310 (99303) 9930311", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13815", "source" : "3340", "target" : "3341", "line_name_k" : "ショウナンシンジュクライン", "is_bullet" : false, "lon" : 139.6229436643263, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13815, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11333", "shared_interaction" : "11333", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR湘南新宿ライン", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133303 (11333) 1133304", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133303 (11333) 1133304", "lat" : 35.65739974071942, "e_status_y" : 0, "line_name_h" : "JR湘南新宿ライン" }, "selected" : false }, { "data" : { "id" : "17880", "source" : "7644", "target" : "7645", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17880, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930311 (99303) 9930312", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930311 (99303) 9930312", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17873", "source" : "7637", "target" : "7638", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17873, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930304 (99303) 9930305", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930304 (99303) 9930305", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17874", "source" : "7638", "target" : "7639", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17874, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930305 (99303) 9930306", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930305 (99303) 9930306", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17875", "source" : "7639", "target" : "7640", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17875, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930306 (99303) 9930307", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930306 (99303) 9930307", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17876", "source" : "7640", "target" : "7641", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17876, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930307 (99303) 9930308", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930307 (99303) 9930308", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17885", "source" : "7649", "target" : "7650", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17885, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930316 (99303) 9930317", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930316 (99303) 9930317", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17886", "source" : "7650", "target" : "7651", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17886, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930317 (99303) 9930318", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930317 (99303) 9930318", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17887", "source" : "7651", "target" : "7652", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17887, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930318 (99303) 9930319", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930318 (99303) 9930319", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "17888", "source" : "7652", "target" : "7653", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17888, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930319 (99303) 9930320", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930319 (99303) 9930320", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13816", "source" : "3341", "target" : "3342", "line_name_k" : "ショウナンシンジュクライン", "is_bullet" : false, "lon" : 139.6229436643263, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13816, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11333", "shared_interaction" : "11333", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR湘南新宿ライン", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133304 (11333) 1133305", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133304 (11333) 1133305", "lat" : 35.65739974071942, "e_status_y" : 0, "line_name_h" : "JR湘南新宿ライン" }, "selected" : false }, { "data" : { "id" : "17881", "source" : "7645", "target" : "7646", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17881, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930312 (99303) 9930313", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930312 (99303) 9930313", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13817", "source" : "3342", "target" : "3343", "line_name_k" : "ショウナンシンジュクライン", "is_bullet" : false, "lon" : 139.6229436643263, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13817, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11333", "shared_interaction" : "11333", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR湘南新宿ライン", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133305 (11333) 1133306", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133305 (11333) 1133306", "lat" : 35.65739974071942, "e_status_y" : 0, "line_name_h" : "JR湘南新宿ライン" }, "selected" : false }, { "data" : { "id" : "17882", "source" : "7646", "target" : "7647", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17882, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930313 (99303) 9930314", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930313 (99303) 9930314", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13818", "source" : "3343", "target" : "3344", "line_name_k" : "ショウナンシンジュクライン", "is_bullet" : false, "lon" : 139.6229436643263, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13818, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11333", "shared_interaction" : "11333", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR湘南新宿ライン", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133306 (11333) 1133307", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133306 (11333) 1133307", "lat" : 35.65739974071942, "e_status_y" : 0, "line_name_h" : "JR湘南新宿ライン" }, "selected" : false }, { "data" : { "id" : "17883", "source" : "7647", "target" : "7648", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17883, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930314 (99303) 9930315", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930314 (99303) 9930315", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13819", "source" : "3344", "target" : "3345", "line_name_k" : "ショウナンシンジュクライン", "is_bullet" : false, "lon" : 139.6229436643263, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13819, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11333", "shared_interaction" : "11333", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR湘南新宿ライン", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133307 (11333) 1133308", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133307 (11333) 1133308", "lat" : 35.65739974071942, "e_status_y" : 0, "line_name_h" : "JR湘南新宿ライン" }, "selected" : false }, { "data" : { "id" : "17884", "source" : "7648", "target" : "7649", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17884, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930315 (99303) 9930316", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930315 (99303) 9930316", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13798", "source" : "3322", "target" : "3323", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13798, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133221 (11332) 1133222", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133221 (11332) 1133222", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17894", "source" : "7658", "target" : "7659", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17894, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930325 (99303) 9930326", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930325 (99303) 9930326", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13797", "source" : "3321", "target" : "3322", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13797, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133220 (11332) 1133221", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133220 (11332) 1133221", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17893", "source" : "7657", "target" : "7658", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17893, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930324 (99303) 9930325", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930324 (99303) 9930325", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13800", "source" : "3324", "target" : "3325", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13800, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133223 (11332) 1133224", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133223 (11332) 1133224", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "13799", "source" : "3323", "target" : "3324", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13799, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133222 (11332) 1133223", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133222 (11332) 1133223", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17895", "source" : "7659", "target" : "7660", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17895, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930326 (99303) 9930327", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930326 (99303) 9930327", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13794", "source" : "3318", "target" : "3319", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13794, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133217 (11332) 1133218", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133217 (11332) 1133218", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17890", "source" : "7654", "target" : "7655", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17890, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930321 (99303) 9930322", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930321 (99303) 9930322", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13793", "source" : "3317", "target" : "3318", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13793, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133216 (11332) 1133217", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133216 (11332) 1133217", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17889", "source" : "7653", "target" : "7654", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17889, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930320 (99303) 9930321", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930320 (99303) 9930321", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13796", "source" : "3320", "target" : "3321", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13796, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133219 (11332) 1133220", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133219 (11332) 1133220", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17892", "source" : "7656", "target" : "7657", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17892, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930323 (99303) 9930324", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930323 (99303) 9930324", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13795", "source" : "3319", "target" : "3320", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13795, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133218 (11332) 1133219", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133218 (11332) 1133219", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17891", "source" : "7655", "target" : "7656", "line_name_k" : "トエイミタセン", "is_bullet" : false, "lon" : 139.7032176242069, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 12, "SUID" : 17891, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99303", "shared_interaction" : "99303", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営三田線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930322 (99303) 9930323", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930322 (99303) 9930323", "lat" : 35.71883584494032, "e_status_y" : 0, "line_name_h" : "都営三田線" }, "selected" : false }, { "data" : { "id" : "13806", "source" : "3330", "target" : "3331", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13806, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133229 (11332) 1133230", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133229 (11332) 1133230", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17901", "source" : "7666", "target" : "7667", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17901, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930406 (99304) 9930407", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930406 (99304) 9930407", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "13805", "source" : "3329", "target" : "3330", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13805, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133228 (11332) 1133229", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133228 (11332) 1133229", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17900", "source" : "7665", "target" : "7666", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17900, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930405 (99304) 9930406", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930405 (99304) 9930406", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17903", "source" : "7668", "target" : "7669", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17903, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930408 (99304) 9930409", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930408 (99304) 9930409", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "17902", "source" : "7667", "target" : "7668", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17902, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930407 (99304) 9930408", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930407 (99304) 9930408", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "13802", "source" : "3326", "target" : "3327", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13802, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133225 (11332) 1133226", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133225 (11332) 1133226", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17897", "source" : "7662", "target" : "7663", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17897, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930402 (99304) 9930403", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930402 (99304) 9930403", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "13801", "source" : "3325", "target" : "3326", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13801, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133224 (11332) 1133225", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133224 (11332) 1133225", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17896", "source" : "7661", "target" : "7662", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17896, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930401 (99304) 9930402", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930401 (99304) 9930402", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "13804", "source" : "3328", "target" : "3329", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13804, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133227 (11332) 1133228", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133227 (11332) 1133228", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17899", "source" : "7664", "target" : "7665", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17899, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930404 (99304) 9930405", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930404 (99304) 9930405", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "13803", "source" : "3327", "target" : "3328", "line_name_k" : "ケイヒントウホクセン", "is_bullet" : false, "lon" : 139.6425120970631, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13803, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11332", "shared_interaction" : "11332", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR京浜東北線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1133226 (11332) 1133227", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1133226 (11332) 1133227", "lat" : 35.63929555924292, "e_status_y" : 0, "line_name_h" : "JR京浜東北線" }, "selected" : false }, { "data" : { "id" : "17898", "source" : "7663", "target" : "7664", "line_name_k" : "トエイシンジュクセン", "is_bullet" : false, "lon" : 139.80940398416865, "company_name_k" : "トウキョウトコウツウキョク", "zoom" : 11, "SUID" : 17898, "company_type" : 0, "company_name_h" : "東京都交通局", "interaction" : "99304", "shared_interaction" : "99304", "company_url" : "http://www.kotsu.metro.tokyo.jp/", "line_name" : "都営新宿線", "selected" : false, "company_name" : "東京都交通局", "company_cd" : 119, "name" : "9930403 (99304) 9930404", "rr_cd" : 99, "company_name_r" : "東京都交通局", "e_status_x" : 0, "shared_name" : "9930403 (99304) 9930404", "lat" : 35.68917479494153, "e_status_y" : 0, "line_name_h" : "都営新宿線" }, "selected" : false }, { "data" : { "id" : "15917", "source" : "5541", "target" : "5542", "line_name_k" : "ナリタスカイアクセス", "is_bullet" : false, "lon" : 140.04557998117627, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15917, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23006", "shared_interaction" : "23006", "company_url" : "http://www.keisei.co.jp/", "line_name" : "成田スカイアクセス", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300601 (23006) 2300602", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300601 (23006) 2300602", "lat" : 35.783474701668865, "e_status_y" : 0, "line_name_h" : "京成成田空港線" }, "selected" : false }, { "data" : { "id" : "15918", "source" : "5542", "target" : "5543", "line_name_k" : "ナリタスカイアクセス", "is_bullet" : false, "lon" : 140.04557998117627, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15918, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23006", "shared_interaction" : "23006", "company_url" : "http://www.keisei.co.jp/", "line_name" : "成田スカイアクセス", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300602 (23006) 2300603", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300602 (23006) 2300603", "lat" : 35.783474701668865, "e_status_y" : 0, "line_name_h" : "京成成田空港線" }, "selected" : false }, { "data" : { "id" : "15919", "source" : "5543", "target" : "5544", "line_name_k" : "ナリタスカイアクセス", "is_bullet" : false, "lon" : 140.04557998117627, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15919, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23006", "shared_interaction" : "23006", "company_url" : "http://www.keisei.co.jp/", "line_name" : "成田スカイアクセス", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300603 (23006) 2300604", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300603 (23006) 2300604", "lat" : 35.783474701668865, "e_status_y" : 0, "line_name_h" : "京成成田空港線" }, "selected" : false }, { "data" : { "id" : "15927", "source" : "5552", "target" : "5553", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15927, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400101 (24001) 2400102", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400101 (24001) 2400102", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15928", "source" : "5553", "target" : "5554", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15928, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400102 (24001) 2400103", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400102 (24001) 2400103", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15929", "source" : "5554", "target" : "5555", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15929, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400103 (24001) 2400104", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400103 (24001) 2400104", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15930", "source" : "5555", "target" : "5556", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15930, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400104 (24001) 2400105", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400104 (24001) 2400105", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15931", "source" : "5556", "target" : "5557", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15931, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400105 (24001) 2400106", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400105 (24001) 2400106", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15950", "source" : "5575", "target" : "5576", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15950, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400124 (24001) 2400125", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400124 (24001) 2400125", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15951", "source" : "5576", "target" : "5577", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15951, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400125 (24001) 2400126", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400125 (24001) 2400126", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15948", "source" : "5573", "target" : "5574", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15948, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400122 (24001) 2400123", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400122 (24001) 2400123", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15949", "source" : "5574", "target" : "5575", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15949, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400123 (24001) 2400124", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400123 (24001) 2400124", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15954", "source" : "5579", "target" : "5580", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15954, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400128 (24001) 2400129", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400128 (24001) 2400129", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15955", "source" : "5580", "target" : "5581", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15955, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400129 (24001) 2400130", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400129 (24001) 2400130", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15952", "source" : "5577", "target" : "5578", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15952, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400126 (24001) 2400127", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400126 (24001) 2400127", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15953", "source" : "5578", "target" : "5579", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15953, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400127 (24001) 2400128", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400127 (24001) 2400128", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15958", "source" : "5583", "target" : "5584", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15958, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400132 (24001) 2400133", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400132 (24001) 2400133", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15959", "source" : "5584", "target" : "5585", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15959, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400133 (24001) 2400134", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400133 (24001) 2400134", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15956", "source" : "5581", "target" : "5582", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15956, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400130 (24001) 2400131", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400130 (24001) 2400131", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15957", "source" : "5582", "target" : "5583", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15957, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400131 (24001) 2400132", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400131 (24001) 2400132", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15960", "source" : "5586", "target" : "5587", "line_name_k" : "ケイオウサガミハラセン", "is_bullet" : false, "lon" : 139.43751621679692, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15960, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24002", "shared_interaction" : "24002", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王相模原線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400201 (24002) 2400202", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400201 (24002) 2400202", "lat" : 35.625846999999986, "e_status_y" : 0, "line_name_h" : "京王相模原線" }, "selected" : false }, { "data" : { "id" : "15935", "source" : "5560", "target" : "5561", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15935, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400109 (24001) 2400110", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400109 (24001) 2400110", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15934", "source" : "5559", "target" : "5560", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15934, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400108 (24001) 2400109", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400108 (24001) 2400109", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15933", "source" : "5558", "target" : "5559", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15933, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400107 (24001) 2400108", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400107 (24001) 2400108", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15932", "source" : "5557", "target" : "5558", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15932, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400106 (24001) 2400107", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400106 (24001) 2400107", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15939", "source" : "5564", "target" : "5565", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15939, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400113 (24001) 2400114", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400113 (24001) 2400114", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15938", "source" : "5563", "target" : "5564", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15938, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400112 (24001) 2400113", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400112 (24001) 2400113", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15937", "source" : "5562", "target" : "5563", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15937, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400111 (24001) 2400112", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400111 (24001) 2400112", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15936", "source" : "5561", "target" : "5562", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15936, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400110 (24001) 2400111", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400110 (24001) 2400111", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15943", "source" : "5568", "target" : "5569", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15943, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400117 (24001) 2400118", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400117 (24001) 2400118", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15942", "source" : "5567", "target" : "5568", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15942, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400116 (24001) 2400117", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400116 (24001) 2400117", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15941", "source" : "5566", "target" : "5567", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15941, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400115 (24001) 2400116", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400115 (24001) 2400116", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15940", "source" : "5565", "target" : "5566", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15940, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400114 (24001) 2400115", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400114 (24001) 2400115", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15947", "source" : "5572", "target" : "5573", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15947, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400121 (24001) 2400122", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400121 (24001) 2400122", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15946", "source" : "5571", "target" : "5572", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15946, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400120 (24001) 2400121", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400120 (24001) 2400121", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15945", "source" : "5570", "target" : "5571", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15945, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400119 (24001) 2400120", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400119 (24001) 2400120", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15944", "source" : "5569", "target" : "5570", "line_name_k" : "ケイオウセン", "is_bullet" : false, "lon" : 139.53357685914878, "company_name_k" : "ケイオウデンテツ", "zoom" : 11, "SUID" : 15944, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24001", "shared_interaction" : "24001", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400118 (24001) 2400119", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400118 (24001) 2400119", "lat" : 35.67836429466227, "e_status_y" : 0, "line_name_h" : "京王線" }, "selected" : false }, { "data" : { "id" : "15979", "source" : "5609", "target" : "5610", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15979, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400601 (24006) 2400602", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400601 (24006) 2400602", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15980", "source" : "5610", "target" : "5611", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15980, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400602 (24006) 2400603", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400602 (24006) 2400603", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15981", "source" : "5611", "target" : "5612", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15981, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400603 (24006) 2400604", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400603 (24006) 2400604", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15982", "source" : "5612", "target" : "5613", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15982, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400604 (24006) 2400605", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400604 (24006) 2400605", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15977", "source" : "5605", "target" : "5606", "line_name_k" : "ケイオウケイバジョウセン", "is_bullet" : false, "lon" : 139.48962301586914, "company_name_k" : "ケイオウデンテツ", "zoom" : 14, "SUID" : 15977, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24004", "shared_interaction" : "24004", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王競馬場線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400401 (24004) 2400402", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400401 (24004) 2400402", "lat" : 35.66894537404467, "e_status_y" : 0, "line_name_h" : "京王競馬場線" }, "selected" : false }, { "data" : { "id" : "15978", "source" : "5607", "target" : "5608", "line_name_k" : "ケイオウドウブツエンセン", "is_bullet" : false, "lon" : 139.40999162963863, "company_name_k" : "ケイオウデンテツ", "zoom" : 14, "SUID" : 15978, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24005", "shared_interaction" : "24005", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王動物園線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400501 (24005) 2400502", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400501 (24005) 2400502", "lat" : 35.657461750041946, "e_status_y" : 0, "line_name_h" : "京王動物園線" }, "selected" : false }, { "data" : { "id" : "15987", "source" : "5617", "target" : "5618", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15987, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400609 (24006) 2400610", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400609 (24006) 2400610", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15988", "source" : "5618", "target" : "5619", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15988, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400610 (24006) 2400611", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400610 (24006) 2400611", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15989", "source" : "5619", "target" : "5620", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15989, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400611 (24006) 2400612", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400611 (24006) 2400612", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15990", "source" : "5620", "target" : "5621", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15990, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400612 (24006) 2400613", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400612 (24006) 2400613", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15983", "source" : "5613", "target" : "5614", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15983, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400605 (24006) 2400606", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400605 (24006) 2400606", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15984", "source" : "5614", "target" : "5615", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15984, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400606 (24006) 2400607", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400606 (24006) 2400607", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15985", "source" : "5615", "target" : "5616", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15985, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400607 (24006) 2400608", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400607 (24006) 2400608", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15986", "source" : "5616", "target" : "5617", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15986, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400608 (24006) 2400609", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400608 (24006) 2400609", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15968", "source" : "5594", "target" : "5595", "line_name_k" : "ケイオウサガミハラセン", "is_bullet" : false, "lon" : 139.43751621679692, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15968, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24002", "shared_interaction" : "24002", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王相模原線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400209 (24002) 2400210", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400209 (24002) 2400210", "lat" : 35.625846999999986, "e_status_y" : 0, "line_name_h" : "京王相模原線" }, "selected" : false }, { "data" : { "id" : "15967", "source" : "5593", "target" : "5594", "line_name_k" : "ケイオウサガミハラセン", "is_bullet" : false, "lon" : 139.43751621679692, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15967, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24002", "shared_interaction" : "24002", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王相模原線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400208 (24002) 2400209", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400208 (24002) 2400209", "lat" : 35.625846999999986, "e_status_y" : 0, "line_name_h" : "京王相模原線" }, "selected" : false }, { "data" : { "id" : "15969", "source" : "5595", "target" : "5596", "line_name_k" : "ケイオウサガミハラセン", "is_bullet" : false, "lon" : 139.43751621679692, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15969, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24002", "shared_interaction" : "24002", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王相模原線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400210 (24002) 2400211", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400210 (24002) 2400211", "lat" : 35.625846999999986, "e_status_y" : 0, "line_name_h" : "京王相模原線" }, "selected" : false }, { "data" : { "id" : "15963", "source" : "5589", "target" : "5590", "line_name_k" : "ケイオウサガミハラセン", "is_bullet" : false, "lon" : 139.43751621679692, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15963, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24002", "shared_interaction" : "24002", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王相模原線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400204 (24002) 2400205", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400204 (24002) 2400205", "lat" : 35.625846999999986, "e_status_y" : 0, "line_name_h" : "京王相模原線" }, "selected" : false }, { "data" : { "id" : "15966", "source" : "5592", "target" : "5593", "line_name_k" : "ケイオウサガミハラセン", "is_bullet" : false, "lon" : 139.43751621679692, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15966, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24002", "shared_interaction" : "24002", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王相模原線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400207 (24002) 2400208", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400207 (24002) 2400208", "lat" : 35.625846999999986, "e_status_y" : 0, "line_name_h" : "京王相模原線" }, "selected" : false }, { "data" : { "id" : "15975", "source" : "5602", "target" : "5603", "line_name_k" : "ケイオウタカオセン", "is_bullet" : false, "lon" : 139.3084367460283, "company_name_k" : "ケイオウデンテツ", "zoom" : 13, "SUID" : 15975, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24003", "shared_interaction" : "24003", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王高尾線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400305 (24003) 2400306", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400305 (24003) 2400306", "lat" : 35.64331590360225, "e_status_y" : 0, "line_name_h" : "京王高尾線" }, "selected" : false }, { "data" : { "id" : "15974", "source" : "5601", "target" : "5602", "line_name_k" : "ケイオウタカオセン", "is_bullet" : false, "lon" : 139.3084367460283, "company_name_k" : "ケイオウデンテツ", "zoom" : 13, "SUID" : 15974, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24003", "shared_interaction" : "24003", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王高尾線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400304 (24003) 2400305", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400304 (24003) 2400305", "lat" : 35.64331590360225, "e_status_y" : 0, "line_name_h" : "京王高尾線" }, "selected" : false }, { "data" : { "id" : "15976", "source" : "5603", "target" : "5604", "line_name_k" : "ケイオウタカオセン", "is_bullet" : false, "lon" : 139.3084367460283, "company_name_k" : "ケイオウデンテツ", "zoom" : 13, "SUID" : 15976, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24003", "shared_interaction" : "24003", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王高尾線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400306 (24003) 2400307", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400306 (24003) 2400307", "lat" : 35.64331590360225, "e_status_y" : 0, "line_name_h" : "京王高尾線" }, "selected" : false }, { "data" : { "id" : "15971", "source" : "5598", "target" : "5599", "line_name_k" : "ケイオウタカオセン", "is_bullet" : false, "lon" : 139.3084367460283, "company_name_k" : "ケイオウデンテツ", "zoom" : 13, "SUID" : 15971, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24003", "shared_interaction" : "24003", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王高尾線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400301 (24003) 2400302", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400301 (24003) 2400302", "lat" : 35.64331590360225, "e_status_y" : 0, "line_name_h" : "京王高尾線" }, "selected" : false }, { "data" : { "id" : "15973", "source" : "5600", "target" : "5601", "line_name_k" : "ケイオウタカオセン", "is_bullet" : false, "lon" : 139.3084367460283, "company_name_k" : "ケイオウデンテツ", "zoom" : 13, "SUID" : 15973, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24003", "shared_interaction" : "24003", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王高尾線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400303 (24003) 2400304", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400303 (24003) 2400304", "lat" : 35.64331590360225, "e_status_y" : 0, "line_name_h" : "京王高尾線" }, "selected" : false }, { "data" : { "id" : "15972", "source" : "5599", "target" : "5600", "line_name_k" : "ケイオウタカオセン", "is_bullet" : false, "lon" : 139.3084367460283, "company_name_k" : "ケイオウデンテツ", "zoom" : 13, "SUID" : 15972, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24003", "shared_interaction" : "24003", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王高尾線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400302 (24003) 2400303", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400302 (24003) 2400303", "lat" : 35.64331590360225, "e_status_y" : 0, "line_name_h" : "京王高尾線" }, "selected" : false }, { "data" : { "id" : "16011", "source" : "5643", "target" : "5644", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16011, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500114 (25001) 2500115", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500114 (25001) 2500115", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16012", "source" : "5644", "target" : "5645", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16012, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500115 (25001) 2500116", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500115 (25001) 2500116", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16009", "source" : "5641", "target" : "5642", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16009, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500112 (25001) 2500113", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500112 (25001) 2500113", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16010", "source" : "5642", "target" : "5643", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16010, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500113 (25001) 2500114", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500113 (25001) 2500114", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16007", "source" : "5639", "target" : "5640", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16007, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500110 (25001) 2500111", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500110 (25001) 2500111", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16008", "source" : "5640", "target" : "5641", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16008, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500111 (25001) 2500112", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500111 (25001) 2500112", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16005", "source" : "5637", "target" : "5638", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16005, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500108 (25001) 2500109", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500108 (25001) 2500109", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16006", "source" : "5638", "target" : "5639", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16006, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500109 (25001) 2500110", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500109 (25001) 2500110", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16013", "source" : "5645", "target" : "5646", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16013, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500116 (25001) 2500117", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500116 (25001) 2500117", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "15997", "source" : "5628", "target" : "5629", "line_name_k" : "ケイオウシンセン", "is_bullet" : false, "lon" : 139.6852505207062, "company_name_k" : "ケイオウデンテツ", "zoom" : 14, "SUID" : 15997, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24007", "shared_interaction" : "24007", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王新線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400703 (24007) 2400704", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400703 (24007) 2400704", "lat" : 35.6804985281479, "e_status_y" : 0, "line_name_h" : "京王新線" }, "selected" : false }, { "data" : { "id" : "15996", "source" : "5627", "target" : "5628", "line_name_k" : "ケイオウシンセン", "is_bullet" : false, "lon" : 139.6852505207062, "company_name_k" : "ケイオウデンテツ", "zoom" : 14, "SUID" : 15996, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24007", "shared_interaction" : "24007", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王新線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400702 (24007) 2400703", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400702 (24007) 2400703", "lat" : 35.6804985281479, "e_status_y" : 0, "line_name_h" : "京王新線" }, "selected" : false }, { "data" : { "id" : "15995", "source" : "5626", "target" : "5627", "line_name_k" : "ケイオウシンセン", "is_bullet" : false, "lon" : 139.6852505207062, "company_name_k" : "ケイオウデンテツ", "zoom" : 14, "SUID" : 15995, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24007", "shared_interaction" : "24007", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王新線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400701 (24007) 2400702", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400701 (24007) 2400702", "lat" : 35.6804985281479, "e_status_y" : 0, "line_name_h" : "京王新線" }, "selected" : false }, { "data" : { "id" : "15994", "source" : "5624", "target" : "5625", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15994, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400616 (24006) 2400617", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400616 (24006) 2400617", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15993", "source" : "5623", "target" : "5624", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15993, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400615 (24006) 2400616", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400615 (24006) 2400616", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15992", "source" : "5622", "target" : "5623", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15992, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400614 (24006) 2400615", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400614 (24006) 2400615", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "15991", "source" : "5621", "target" : "5622", "line_name_k" : "ケイオウイノガシラセン", "is_bullet" : false, "lon" : 139.63498783283308, "company_name_k" : "ケイオウデンテツ", "zoom" : 12, "SUID" : 15991, "company_type" : 2, "company_name_h" : "京王電鉄株式会社", "interaction" : "24006", "shared_interaction" : "24006", "company_url" : "http://www.keio.co.jp/", "line_name" : "京王井の頭線", "selected" : false, "company_name" : "京王電鉄", "company_cd" : 14, "name" : "2400613 (24006) 2400614", "rr_cd" : 24, "company_name_r" : "京王", "e_status_x" : 0, "shared_name" : "2400613 (24006) 2400614", "lat" : 35.67668499412642, "e_status_y" : 0, "line_name_h" : "京王井の頭線" }, "selected" : false }, { "data" : { "id" : "16004", "source" : "5636", "target" : "5637", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16004, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500107 (25001) 2500108", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500107 (25001) 2500108", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16003", "source" : "5635", "target" : "5636", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16003, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500106 (25001) 2500107", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500106 (25001) 2500107", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16002", "source" : "5634", "target" : "5635", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16002, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500105 (25001) 2500106", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500105 (25001) 2500106", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16001", "source" : "5633", "target" : "5634", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16001, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500104 (25001) 2500105", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500104 (25001) 2500105", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "16000", "source" : "5632", "target" : "5633", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 16000, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500103 (25001) 2500104", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500103 (25001) 2500104", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "15999", "source" : "5631", "target" : "5632", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 15999, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500102 (25001) 2500103", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500102 (25001) 2500103", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "15998", "source" : "5630", "target" : "5631", "line_name_k" : "オダキュウセン", "is_bullet" : false, "lon" : 139.43477539316441, "company_name_k" : "オダキュウデンテツ", "zoom" : 11, "SUID" : 15998, "company_type" : 2, "company_name_h" : "小田急電鉄株式会社", "interaction" : "25001", "shared_interaction" : "25001", "company_url" : "http://www.odakyu.jp/", "line_name" : "小田急線", "selected" : false, "company_name" : "小田急電鉄", "company_cd" : 15, "name" : "2500101 (25001) 2500102", "rr_cd" : 25, "company_name_r" : "小田急", "e_status_x" : 0, "shared_name" : "2500101 (25001) 2500102", "lat" : 35.528535238628024, "e_status_y" : 0, "line_name_h" : "小田急小田原線" }, "selected" : false }, { "data" : { "id" : "15809", "source" : "5422", "target" : "5423", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15809, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200708 (22007) 2200709", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200708 (22007) 2200709", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15808", "source" : "5421", "target" : "5422", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15808, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200707 (22007) 2200708", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200707 (22007) 2200708", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15811", "source" : "5424", "target" : "5425", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15811, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200710 (22007) 2200711", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200710 (22007) 2200711", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15810", "source" : "5423", "target" : "5424", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15810, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200709 (22007) 2200710", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200709 (22007) 2200710", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15813", "source" : "5426", "target" : "5427", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15813, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200712 (22007) 2200713", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200712 (22007) 2200713", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15812", "source" : "5425", "target" : "5426", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15812, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200711 (22007) 2200712", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200711 (22007) 2200712", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15815", "source" : "5428", "target" : "5429", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15815, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200714 (22007) 2200715", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200714 (22007) 2200715", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15814", "source" : "5427", "target" : "5428", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15814, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200713 (22007) 2200714", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200713 (22007) 2200714", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15803", "source" : "5416", "target" : "5417", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15803, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200702 (22007) 2200703", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200702 (22007) 2200703", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15802", "source" : "5415", "target" : "5416", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15802, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200701 (22007) 2200702", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200701 (22007) 2200702", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15805", "source" : "5418", "target" : "5419", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15805, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200704 (22007) 2200705", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200704 (22007) 2200705", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15804", "source" : "5417", "target" : "5418", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15804, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200703 (22007) 2200704", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200703 (22007) 2200704", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15807", "source" : "5420", "target" : "5421", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15807, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200706 (22007) 2200707", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200706 (22007) 2200707", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15806", "source" : "5419", "target" : "5420", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15806, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200705 (22007) 2200706", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200705 (22007) 2200706", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15796", "source" : "5405", "target" : "5406", "line_name_k" : "セイブユウラクチョウセン", "is_bullet" : false, "lon" : 139.6675949841308, "company_name_k" : "セイブテツドウ", "zoom" : 14, "SUID" : 15796, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22003", "shared_interaction" : "22003", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武有楽町線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200302 (22003) 2200303", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200302 (22003) 2200303", "lat" : 35.74040400298963, "e_status_y" : 0, "line_name_h" : "西武有楽町線" }, "selected" : false }, { "data" : { "id" : "15797", "source" : "5407", "target" : "5408", "line_name_k" : "セイブトシマセン", "is_bullet" : false, "lon" : 139.65151682275393, "company_name_k" : "セイブテツドウ", "zoom" : 15, "SUID" : 15797, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22004", "shared_interaction" : "22004", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武豊島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200401 (22004) 2200402", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200401 (22004) 2200402", "lat" : 35.740043166697504, "e_status_y" : 0, "line_name_h" : "西武豊島線" }, "selected" : false }, { "data" : { "id" : "15795", "source" : "5404", "target" : "5405", "line_name_k" : "セイブユウラクチョウセン", "is_bullet" : false, "lon" : 139.6675949841308, "company_name_k" : "セイブテツドウ", "zoom" : 14, "SUID" : 15795, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22003", "shared_interaction" : "22003", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武有楽町線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200301 (22003) 2200302", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200301 (22003) 2200302", "lat" : 35.74040400298963, "e_status_y" : 0, "line_name_h" : "西武有楽町線" }, "selected" : false }, { "data" : { "id" : "15840", "source" : "5456", "target" : "5457", "line_name_k" : "セイブコクブンジセン", "is_bullet" : false, "lon" : 139.46774104550786, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15840, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22010", "shared_interaction" : "22010", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武国分寺線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201003 (22010) 2201004", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201003 (22010) 2201004", "lat" : 35.73062820396875, "e_status_y" : 0, "line_name_h" : "西武国分寺線" }, "selected" : false }, { "data" : { "id" : "15839", "source" : "5455", "target" : "5456", "line_name_k" : "セイブコクブンジセン", "is_bullet" : false, "lon" : 139.46774104550786, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15839, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22010", "shared_interaction" : "22010", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武国分寺線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201002 (22010) 2201003", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201002 (22010) 2201003", "lat" : 35.73062820396875, "e_status_y" : 0, "line_name_h" : "西武国分寺線" }, "selected" : false }, { "data" : { "id" : "15838", "source" : "5454", "target" : "5455", "line_name_k" : "セイブコクブンジセン", "is_bullet" : false, "lon" : 139.46774104550786, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15838, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22010", "shared_interaction" : "22010", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武国分寺線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201001 (22010) 2201002", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201001 (22010) 2201002", "lat" : 35.73062820396875, "e_status_y" : 0, "line_name_h" : "西武国分寺線" }, "selected" : false }, { "data" : { "id" : "15843", "source" : "5460", "target" : "5461", "line_name_k" : "セイブタマコセン", "is_bullet" : false, "lon" : 139.46850918519954, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15843, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22011", "shared_interaction" : "22011", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩湖線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201102 (22011) 2201103", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201102 (22011) 2201103", "lat" : 35.741048131945206, "e_status_y" : 0, "line_name_h" : "西武多摩湖線" }, "selected" : false }, { "data" : { "id" : "15842", "source" : "5459", "target" : "5460", "line_name_k" : "セイブタマコセン", "is_bullet" : false, "lon" : 139.46850918519954, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15842, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22011", "shared_interaction" : "22011", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩湖線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201101 (22011) 2201102", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201101 (22011) 2201102", "lat" : 35.741048131945206, "e_status_y" : 0, "line_name_h" : "西武多摩湖線" }, "selected" : false }, { "data" : { "id" : "15841", "source" : "5457", "target" : "5458", "line_name_k" : "セイブコクブンジセン", "is_bullet" : false, "lon" : 139.46774104550786, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15841, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22010", "shared_interaction" : "22010", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武国分寺線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201004 (22010) 2201005", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201004 (22010) 2201005", "lat" : 35.73062820396875, "e_status_y" : 0, "line_name_h" : "西武国分寺線" }, "selected" : false }, { "data" : { "id" : "15834", "source" : "5448", "target" : "5449", "line_name_k" : "セイブハイジマセン", "is_bullet" : false, "lon" : 139.41313556738282, "company_name_k" : "セイブテツドウ", "zoom" : 12, "SUID" : 15834, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22008", "shared_interaction" : "22008", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武拝島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200805 (22008) 2200806", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200805 (22008) 2200806", "lat" : 35.73286470476111, "e_status_y" : 0, "line_name_h" : "西武拝島線" }, "selected" : false }, { "data" : { "id" : "15833", "source" : "5447", "target" : "5448", "line_name_k" : "セイブハイジマセン", "is_bullet" : false, "lon" : 139.41313556738282, "company_name_k" : "セイブテツドウ", "zoom" : 12, "SUID" : 15833, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22008", "shared_interaction" : "22008", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武拝島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200804 (22008) 2200805", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200804 (22008) 2200805", "lat" : 35.73286470476111, "e_status_y" : 0, "line_name_h" : "西武拝島線" }, "selected" : false }, { "data" : { "id" : "15832", "source" : "5446", "target" : "5447", "line_name_k" : "セイブハイジマセン", "is_bullet" : false, "lon" : 139.41313556738282, "company_name_k" : "セイブテツドウ", "zoom" : 12, "SUID" : 15832, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22008", "shared_interaction" : "22008", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武拝島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200803 (22008) 2200804", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200803 (22008) 2200804", "lat" : 35.73286470476111, "e_status_y" : 0, "line_name_h" : "西武拝島線" }, "selected" : false }, { "data" : { "id" : "15831", "source" : "5445", "target" : "5446", "line_name_k" : "セイブハイジマセン", "is_bullet" : false, "lon" : 139.41313556738282, "company_name_k" : "セイブテツドウ", "zoom" : 12, "SUID" : 15831, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22008", "shared_interaction" : "22008", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武拝島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200802 (22008) 2200803", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200802 (22008) 2200803", "lat" : 35.73286470476111, "e_status_y" : 0, "line_name_h" : "西武拝島線" }, "selected" : false }, { "data" : { "id" : "15837", "source" : "5452", "target" : "5453", "line_name_k" : "セイブセイブエンセン", "is_bullet" : false, "lon" : 139.45737150000002, "company_name_k" : "セイブテツドウ", "zoom" : 14, "SUID" : 15837, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22009", "shared_interaction" : "22009", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武西武園線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200901 (22009) 2200902", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200901 (22009) 2200902", "lat" : 35.764150582754176, "e_status_y" : 0, "line_name_h" : "西武西武園線" }, "selected" : false }, { "data" : { "id" : "15836", "source" : "5450", "target" : "5451", "line_name_k" : "セイブハイジマセン", "is_bullet" : false, "lon" : 139.41313556738282, "company_name_k" : "セイブテツドウ", "zoom" : 12, "SUID" : 15836, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22008", "shared_interaction" : "22008", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武拝島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200807 (22008) 2200808", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200807 (22008) 2200808", "lat" : 35.73286470476111, "e_status_y" : 0, "line_name_h" : "西武拝島線" }, "selected" : false }, { "data" : { "id" : "15835", "source" : "5449", "target" : "5450", "line_name_k" : "セイブハイジマセン", "is_bullet" : false, "lon" : 139.41313556738282, "company_name_k" : "セイブテツドウ", "zoom" : 12, "SUID" : 15835, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22008", "shared_interaction" : "22008", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武拝島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200806 (22008) 2200807", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200806 (22008) 2200807", "lat" : 35.73286470476111, "e_status_y" : 0, "line_name_h" : "西武拝島線" }, "selected" : false }, { "data" : { "id" : "15830", "source" : "5444", "target" : "5445", "line_name_k" : "セイブハイジマセン", "is_bullet" : false, "lon" : 139.41313556738282, "company_name_k" : "セイブテツドウ", "zoom" : 12, "SUID" : 15830, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22008", "shared_interaction" : "22008", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武拝島線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200801 (22008) 2200802", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200801 (22008) 2200802", "lat" : 35.73286470476111, "e_status_y" : 0, "line_name_h" : "西武拝島線" }, "selected" : false }, { "data" : { "id" : "15818", "source" : "5431", "target" : "5432", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15818, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200717 (22007) 2200718", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200717 (22007) 2200718", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15819", "source" : "5432", "target" : "5433", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15819, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200718 (22007) 2200719", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200718 (22007) 2200719", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15816", "source" : "5429", "target" : "5430", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15816, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200715 (22007) 2200716", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200715 (22007) 2200716", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15817", "source" : "5430", "target" : "5431", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15817, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200716 (22007) 2200717", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200716 (22007) 2200717", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15820", "source" : "5433", "target" : "5434", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15820, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200719 (22007) 2200720", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200719 (22007) 2200720", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15821", "source" : "5434", "target" : "5435", "line_name_k" : "セイブシンジュクセン", "is_bullet" : false, "lon" : 139.5308648735163, "company_name_k" : "セイブテツドウ", "zoom" : 11, "SUID" : 15821, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22007", "shared_interaction" : "22007", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武新宿線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2200720 (22007) 2200721", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2200720 (22007) 2200721", "lat" : 35.776946871074955, "e_status_y" : 0, "line_name_h" : "西武新宿線" }, "selected" : false }, { "data" : { "id" : "15863", "source" : "5482", "target" : "5483", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15863, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300111 (23001) 2300112", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300111 (23001) 2300112", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15862", "source" : "5481", "target" : "5482", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15862, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300110 (23001) 2300111", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300110 (23001) 2300111", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15859", "source" : "5478", "target" : "5479", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15859, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300107 (23001) 2300108", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300107 (23001) 2300108", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15858", "source" : "5477", "target" : "5478", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15858, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300106 (23001) 2300107", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300106 (23001) 2300107", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15861", "source" : "5480", "target" : "5481", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15861, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300109 (23001) 2300110", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300109 (23001) 2300110", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15860", "source" : "5479", "target" : "5480", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15860, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300108 (23001) 2300109", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300108 (23001) 2300109", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15854", "source" : "5473", "target" : "5474", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15854, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300102 (23001) 2300103", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300102 (23001) 2300103", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15855", "source" : "5474", "target" : "5475", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15855, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300103 (23001) 2300104", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300103 (23001) 2300104", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15856", "source" : "5475", "target" : "5476", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15856, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300104 (23001) 2300105", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300104 (23001) 2300105", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15857", "source" : "5476", "target" : "5477", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15857, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300105 (23001) 2300106", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300105 (23001) 2300106", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15851", "source" : "5469", "target" : "5470", "line_name_k" : "セイブタマガワセン", "is_bullet" : false, "lon" : 139.51353168782222, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15851, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22012", "shared_interaction" : "22012", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩川線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201204 (22012) 2201205", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201204 (22012) 2201205", "lat" : 35.67702828078765, "e_status_y" : 0, "line_name_h" : "西武多摩川線" }, "selected" : false }, { "data" : { "id" : "15852", "source" : "5470", "target" : "5471", "line_name_k" : "セイブタマガワセン", "is_bullet" : false, "lon" : 139.51353168782222, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15852, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22012", "shared_interaction" : "22012", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩川線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201205 (22012) 2201206", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201205 (22012) 2201206", "lat" : 35.67702828078765, "e_status_y" : 0, "line_name_h" : "西武多摩川線" }, "selected" : false }, { "data" : { "id" : "15853", "source" : "5472", "target" : "5473", "line_name_k" : "ケイセイホンセン", "is_bullet" : false, "lon" : 140.07226251112684, "company_name_k" : "ケイセイデンテツ", "zoom" : 10, "SUID" : 15853, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23001", "shared_interaction" : "23001", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成本線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300101 (23001) 2300102", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300101 (23001) 2300102", "lat" : 35.726288869528844, "e_status_y" : 0, "line_name_h" : "京成本線" }, "selected" : false }, { "data" : { "id" : "15848", "source" : "5466", "target" : "5467", "line_name_k" : "セイブタマガワセン", "is_bullet" : false, "lon" : 139.51353168782222, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15848, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22012", "shared_interaction" : "22012", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩川線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201201 (22012) 2201202", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201201 (22012) 2201202", "lat" : 35.67702828078765, "e_status_y" : 0, "line_name_h" : "西武多摩川線" }, "selected" : false }, { "data" : { "id" : "15849", "source" : "5467", "target" : "5468", "line_name_k" : "セイブタマガワセン", "is_bullet" : false, "lon" : 139.51353168782222, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15849, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22012", "shared_interaction" : "22012", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩川線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201202 (22012) 2201203", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201202 (22012) 2201203", "lat" : 35.67702828078765, "e_status_y" : 0, "line_name_h" : "西武多摩川線" }, "selected" : false }, { "data" : { "id" : "15850", "source" : "5468", "target" : "5469", "line_name_k" : "セイブタマガワセン", "is_bullet" : false, "lon" : 139.51353168782222, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15850, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22012", "shared_interaction" : "22012", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩川線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201203 (22012) 2201204", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201203 (22012) 2201204", "lat" : 35.67702828078765, "e_status_y" : 0, "line_name_h" : "西武多摩川線" }, "selected" : false }, { "data" : { "id" : "15844", "source" : "5461", "target" : "5462", "line_name_k" : "セイブタマコセン", "is_bullet" : false, "lon" : 139.46850918519954, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15844, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22011", "shared_interaction" : "22011", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩湖線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201103 (22011) 2201105", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201103 (22011) 2201105", "lat" : 35.741048131945206, "e_status_y" : 0, "line_name_h" : "西武多摩湖線" }, "selected" : false }, { "data" : { "id" : "15845", "source" : "5462", "target" : "5463", "line_name_k" : "セイブタマコセン", "is_bullet" : false, "lon" : 139.46850918519954, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15845, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22011", "shared_interaction" : "22011", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩湖線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201105 (22011) 2201106", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201105 (22011) 2201106", "lat" : 35.741048131945206, "e_status_y" : 0, "line_name_h" : "西武多摩湖線" }, "selected" : false }, { "data" : { "id" : "15846", "source" : "5463", "target" : "5464", "line_name_k" : "セイブタマコセン", "is_bullet" : false, "lon" : 139.46850918519954, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15846, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22011", "shared_interaction" : "22011", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩湖線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201106 (22011) 2201107", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201106 (22011) 2201107", "lat" : 35.741048131945206, "e_status_y" : 0, "line_name_h" : "西武多摩湖線" }, "selected" : false }, { "data" : { "id" : "15847", "source" : "5464", "target" : "5465", "line_name_k" : "セイブタマコセン", "is_bullet" : false, "lon" : 139.46850918519954, "company_name_k" : "セイブテツドウ", "zoom" : 13, "SUID" : 15847, "company_type" : 2, "company_name_h" : "西武鉄道株式会社", "interaction" : "22011", "shared_interaction" : "22011", "company_url" : "http://www.seibu-group.co.jp/railways/", "line_name" : "西武多摩湖線", "selected" : false, "company_name" : "西武鉄道", "company_cd" : 12, "name" : "2201107 (22011) 2201108", "rr_cd" : 22, "company_name_r" : "西武", "e_status_x" : 0, "shared_name" : "2201107 (22011) 2201108", "lat" : 35.741048131945206, "e_status_y" : 0, "line_name_h" : "西武多摩湖線" }, "selected" : false }, { "data" : { "id" : "15902", "source" : "5523", "target" : "5524", "line_name_k" : "ケイセイカナマチセン", "is_bullet" : false, "lon" : 139.86858506876956, "company_name_k" : "ケイセイデンテツ", "zoom" : 14, "SUID" : 15902, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23003", "shared_interaction" : "23003", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成金町線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300302 (23003) 2300303", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300302 (23003) 2300303", "lat" : 35.76122200631621, "e_status_y" : 0, "line_name_h" : "京成金町線" }, "selected" : false }, { "data" : { "id" : "15901", "source" : "5522", "target" : "5523", "line_name_k" : "ケイセイカナマチセン", "is_bullet" : false, "lon" : 139.86858506876956, "company_name_k" : "ケイセイデンテツ", "zoom" : 14, "SUID" : 15901, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23003", "shared_interaction" : "23003", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成金町線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300301 (23003) 2300302", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300301 (23003) 2300302", "lat" : 35.76122200631621, "e_status_y" : 0, "line_name_h" : "京成金町線" }, "selected" : false }, { "data" : { "id" : "15900", "source" : "5520", "target" : "5521", "line_name_k" : "ケイセイオシアゲセン", "is_bullet" : false, "lon" : 139.84176579896905, "company_name_k" : "ケイセイデンテツ", "zoom" : 13, "SUID" : 15900, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23002", "shared_interaction" : "23002", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成押上線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300206 (23002) 2300207", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300206 (23002) 2300207", "lat" : 35.737000349715125, "e_status_y" : 0, "line_name_h" : "京成押上線" }, "selected" : false }, { "data" : { "id" : "15899", "source" : "5519", "target" : "5520", "line_name_k" : "ケイセイオシアゲセン", "is_bullet" : false, "lon" : 139.84176579896905, "company_name_k" : "ケイセイデンテツ", "zoom" : 13, "SUID" : 15899, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23002", "shared_interaction" : "23002", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成押上線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300205 (23002) 2300206", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300205 (23002) 2300206", "lat" : 35.737000349715125, "e_status_y" : 0, "line_name_h" : "京成押上線" }, "selected" : false }, { "data" : { "id" : "15898", "source" : "5518", "target" : "5519", "line_name_k" : "ケイセイオシアゲセン", "is_bullet" : false, "lon" : 139.84176579896905, "company_name_k" : "ケイセイデンテツ", "zoom" : 13, "SUID" : 15898, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23002", "shared_interaction" : "23002", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成押上線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300204 (23002) 2300205", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300204 (23002) 2300205", "lat" : 35.737000349715125, "e_status_y" : 0, "line_name_h" : "京成押上線" }, "selected" : false }, { "data" : { "id" : "15897", "source" : "5517", "target" : "5518", "line_name_k" : "ケイセイオシアゲセン", "is_bullet" : false, "lon" : 139.84176579896905, "company_name_k" : "ケイセイデンテツ", "zoom" : 13, "SUID" : 15897, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23002", "shared_interaction" : "23002", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成押上線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300203 (23002) 2300204", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300203 (23002) 2300204", "lat" : 35.737000349715125, "e_status_y" : 0, "line_name_h" : "京成押上線" }, "selected" : false }, { "data" : { "id" : "15896", "source" : "5516", "target" : "5517", "line_name_k" : "ケイセイオシアゲセン", "is_bullet" : false, "lon" : 139.84176579896905, "company_name_k" : "ケイセイデンテツ", "zoom" : 13, "SUID" : 15896, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23002", "shared_interaction" : "23002", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成押上線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300202 (23002) 2300203", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300202 (23002) 2300203", "lat" : 35.737000349715125, "e_status_y" : 0, "line_name_h" : "京成押上線" }, "selected" : false }, { "data" : { "id" : "15895", "source" : "5515", "target" : "5516", "line_name_k" : "ケイセイオシアゲセン", "is_bullet" : false, "lon" : 139.84176579896905, "company_name_k" : "ケイセイデンテツ", "zoom" : 13, "SUID" : 15895, "company_type" : 2, "company_name_h" : "京成電鉄株式会社", "interaction" : "23002", "shared_interaction" : "23002", "company_url" : "http://www.keisei.co.jp/", "line_name" : "京成押上線", "selected" : false, "company_name" : "京成電鉄", "company_cd" : 13, "name" : "2300201 (23002) 2300202", "rr_cd" : 23, "company_name_r" : "京成", "e_status_x" : 0, "shared_name" : "2300201 (23002) 2300202", "lat" : 35.737000349715125, "e_status_y" : 0, "line_name_h" : "京成押上線" }, "selected" : false }, { "data" : { "id" : "13204", "source" : "2702", "target" : "2674", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13204, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130229 (11302) 1130201", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130229 (11302) 1130201", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13203", "source" : "2701", "target" : "2702", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13203, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130228 (11302) 1130229", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130228 (11302) 1130229", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13196", "source" : "2694", "target" : "2695", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13196, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130221 (11302) 1130222", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130221 (11302) 1130222", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13195", "source" : "2693", "target" : "2694", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13195, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130220 (11302) 1130221", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130220 (11302) 1130221", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13198", "source" : "2696", "target" : "2697", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13198, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130223 (11302) 1130224", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130223 (11302) 1130224", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13197", "source" : "2695", "target" : "2696", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13197, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130222 (11302) 1130223", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130222 (11302) 1130223", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13200", "source" : "2698", "target" : "2699", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13200, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130225 (11302) 1130226", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130225 (11302) 1130226", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13199", "source" : "2697", "target" : "2698", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13199, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130224 (11302) 1130225", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130224 (11302) 1130225", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13202", "source" : "2700", "target" : "2701", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13202, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130227 (11302) 1130228", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130227 (11302) 1130228", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13201", "source" : "2699", "target" : "2700", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13201, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130226 (11302) 1130227", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130226 (11302) 1130227", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13187", "source" : "2685", "target" : "2686", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13187, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130212 (11302) 1130213", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130212 (11302) 1130213", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13188", "source" : "2686", "target" : "2687", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13188, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130213 (11302) 1130214", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130213 (11302) 1130214", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13189", "source" : "2687", "target" : "2688", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13189, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130214 (11302) 1130215", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130214 (11302) 1130215", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13190", "source" : "2688", "target" : "2689", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13190, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130215 (11302) 1130216", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130215 (11302) 1130216", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13191", "source" : "2689", "target" : "2690", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13191, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130216 (11302) 1130217", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130216 (11302) 1130217", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13192", "source" : "2690", "target" : "2691", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13192, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130217 (11302) 1130218", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130217 (11302) 1130218", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13193", "source" : "2691", "target" : "2692", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13193, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130218 (11302) 1130219", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130218 (11302) 1130219", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13194", "source" : "2692", "target" : "2693", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13194, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130219 (11302) 1130220", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130219 (11302) 1130220", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13179", "source" : "2677", "target" : "2678", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13179, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130204 (11302) 1130205", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130204 (11302) 1130205", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13180", "source" : "2678", "target" : "2679", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13180, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130205 (11302) 1130206", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130205 (11302) 1130206", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13181", "source" : "2679", "target" : "2680", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13181, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130206 (11302) 1130207", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130206 (11302) 1130207", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13182", "source" : "2680", "target" : "2681", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13182, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130207 (11302) 1130208", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130207 (11302) 1130208", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13183", "source" : "2681", "target" : "2682", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13183, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130208 (11302) 1130209", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130208 (11302) 1130209", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13184", "source" : "2682", "target" : "2683", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13184, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130209 (11302) 1130210", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130209 (11302) 1130210", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13185", "source" : "2683", "target" : "2684", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13185, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130210 (11302) 1130211", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130210 (11302) 1130211", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13186", "source" : "2684", "target" : "2685", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13186, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130211 (11302) 1130212", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130211 (11302) 1130212", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13178", "source" : "2676", "target" : "2677", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13178, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130203 (11302) 1130204", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130203 (11302) 1130204", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13177", "source" : "2675", "target" : "2676", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13177, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130202 (11302) 1130203", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130202 (11302) 1130203", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13176", "source" : "2674", "target" : "2675", "line_name_k" : "ヤマノテセン", "is_bullet" : false, "lon" : 139.73522275686264, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13176, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11302", "shared_interaction" : "11302", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR山手線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130201 (11302) 1130202", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130201 (11302) 1130202", "lat" : 35.693027307629926, "e_status_y" : 0, "line_name_h" : "JR山手線" }, "selected" : false }, { "data" : { "id" : "13156", "source" : "2653", "target" : "2654", "line_name_k" : "トウカイドウホンセン", "is_bullet" : false, "lon" : 139.43024413263132, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13156, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11301", "shared_interaction" : "11301", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR東海道本線(東京~熱海)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130101 (11301) 1130102", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130101 (11301) 1130102", "lat" : 35.39507962341528, "e_status_y" : 0, "line_name_h" : "JR東海道本線(東京~熱海)" }, "selected" : false }, { "data" : { "id" : "13157", "source" : "2654", "target" : "2655", "line_name_k" : "トウカイドウホンセン", "is_bullet" : false, "lon" : 139.43024413263132, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13157, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11301", "shared_interaction" : "11301", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR東海道本線(東京~熱海)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130102 (11301) 1130103", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130102 (11301) 1130103", "lat" : 35.39507962341528, "e_status_y" : 0, "line_name_h" : "JR東海道本線(東京~熱海)" }, "selected" : false }, { "data" : { "id" : "13246", "source" : "2746", "target" : "2747", "line_name_k" : "ムサシノセン", "is_bullet" : false, "lon" : 139.70511311944188, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13246, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11305", "shared_interaction" : "11305", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR武蔵野線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130502 (11305) 1130503", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130502 (11305) 1130503", "lat" : 35.802577076922994, "e_status_y" : 0, "line_name_h" : "JR武蔵野線" }, "selected" : false }, { "data" : { "id" : "13245", "source" : "2745", "target" : "2746", "line_name_k" : "ムサシノセン", "is_bullet" : false, "lon" : 139.70511311944188, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13245, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11305", "shared_interaction" : "11305", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR武蔵野線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130501 (11305) 1130502", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130501 (11305) 1130502", "lat" : 35.802577076922994, "e_status_y" : 0, "line_name_h" : "JR武蔵野線" }, "selected" : false }, { "data" : { "id" : "13248", "source" : "2748", "target" : "2749", "line_name_k" : "ムサシノセン", "is_bullet" : false, "lon" : 139.70511311944188, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13248, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11305", "shared_interaction" : "11305", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR武蔵野線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130504 (11305) 1130505", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130504 (11305) 1130505", "lat" : 35.802577076922994, "e_status_y" : 0, "line_name_h" : "JR武蔵野線" }, "selected" : false }, { "data" : { "id" : "13247", "source" : "2747", "target" : "2748", "line_name_k" : "ムサシノセン", "is_bullet" : false, "lon" : 139.70511311944188, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13247, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11305", "shared_interaction" : "11305", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR武蔵野線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130503 (11305) 1130504", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130503 (11305) 1130504", "lat" : 35.802577076922994, "e_status_y" : 0, "line_name_h" : "JR武蔵野線" }, "selected" : false }, { "data" : { "id" : "13230", "source" : "2727", "target" : "2728", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13230, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130323 (11303) 1130324", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130323 (11303) 1130324", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13231", "source" : "2728", "target" : "2729", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13231, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130324 (11303) 1130325", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130324 (11303) 1130325", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13228", "source" : "2725", "target" : "2726", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13228, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130329 (11303) 1130322", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130329 (11303) 1130322", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13229", "source" : "2726", "target" : "2727", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13229, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130322 (11303) 1130323", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130322 (11303) 1130323", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13227", "source" : "2724", "target" : "2725", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13227, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130321 (11303) 1130329", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130321 (11303) 1130329", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13226", "source" : "2723", "target" : "2724", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13226, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130320 (11303) 1130321", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130320 (11303) 1130321", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13225", "source" : "2722", "target" : "2723", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13225, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130319 (11303) 1130320", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130319 (11303) 1130320", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13224", "source" : "2721", "target" : "2722", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13224, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130318 (11303) 1130319", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130318 (11303) 1130319", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13223", "source" : "2720", "target" : "2721", "line_name_k" : "ナンブセン", "is_bullet" : false, "lon" : 139.5621831285025, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13223, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11303", "shared_interaction" : "11303", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR南武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130317 (11303) 1130318", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130317 (11303) 1130318", "lat" : 35.62126801796464, "e_status_y" : 0, "line_name_h" : "JR南武線" }, "selected" : false }, { "data" : { "id" : "13302", "source" : "2805", "target" : "2806", "line_name_k" : "ヨコスカセン", "is_bullet" : false, "lon" : 139.64761859128498, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13302, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11308", "shared_interaction" : "11308", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR横須賀線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130803 (11308) 1130804", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130803 (11308) 1130804", "lat" : 35.48340539219034, "e_status_y" : 0, "line_name_h" : "JR横須賀線" }, "selected" : false }, { "data" : { "id" : "13288", "source" : "2789", "target" : "2790", "line_name_k" : "ヨコハマセン", "is_bullet" : false, "lon" : 139.47111850000002, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13288, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11306", "shared_interaction" : "11306", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR横浜線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130619 (11306) 1130620", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130619 (11306) 1130620", "lat" : 35.56100410614944, "e_status_y" : 0, "line_name_h" : "JR横浜線" }, "selected" : false }, { "data" : { "id" : "13300", "source" : "2803", "target" : "2804", "line_name_k" : "ヨコスカセン", "is_bullet" : false, "lon" : 139.64761859128498, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13300, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11308", "shared_interaction" : "11308", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR横須賀線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130801 (11308) 1130802", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130801 (11308) 1130802", "lat" : 35.48340539219034, "e_status_y" : 0, "line_name_h" : "JR横須賀線" }, "selected" : false }, { "data" : { "id" : "13301", "source" : "2804", "target" : "2805", "line_name_k" : "ヨコスカセン", "is_bullet" : false, "lon" : 139.64761859128498, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13301, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11308", "shared_interaction" : "11308", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR横須賀線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130802 (11308) 1130803", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130802 (11308) 1130803", "lat" : 35.48340539219034, "e_status_y" : 0, "line_name_h" : "JR横須賀線" }, "selected" : false }, { "data" : { "id" : "13279", "source" : "2780", "target" : "2781", "line_name_k" : "ヨコハマセン", "is_bullet" : false, "lon" : 139.47111850000002, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13279, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11306", "shared_interaction" : "11306", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR横浜線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130610 (11306) 1130611", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130610 (11306) 1130611", "lat" : 35.56100410614944, "e_status_y" : 0, "line_name_h" : "JR横浜線" }, "selected" : false }, { "data" : { "id" : "13287", "source" : "2788", "target" : "2789", "line_name_k" : "ヨコハマセン", "is_bullet" : false, "lon" : 139.47111850000002, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13287, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11306", "shared_interaction" : "11306", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR横浜線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130618 (11306) 1130619", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130618 (11306) 1130619", "lat" : 35.56100410614944, "e_status_y" : 0, "line_name_h" : "JR横浜線" }, "selected" : false }, { "data" : { "id" : "13286", "source" : "2787", "target" : "2788", "line_name_k" : "ヨコハマセン", "is_bullet" : false, "lon" : 139.47111850000002, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13286, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11306", "shared_interaction" : "11306", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR横浜線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1130617 (11306) 1130618", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1130617 (11306) 1130618", "lat" : 35.56100410614944, "e_status_y" : 0, "line_name_h" : "JR横浜線" }, "selected" : false }, { "data" : { "id" : "13395", "source" : "2900", "target" : "2901", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13395, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131216 (11312) 1131217", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131216 (11312) 1131217", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13394", "source" : "2899", "target" : "2900", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13394, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131215 (11312) 1131216", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131215 (11312) 1131216", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13393", "source" : "2898", "target" : "2899", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13393, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131214 (11312) 1131215", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131214 (11312) 1131215", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13392", "source" : "2897", "target" : "2898", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13392, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131211 (11312) 1131214", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131211 (11312) 1131214", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13391", "source" : "2896", "target" : "2897", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13391, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131207 (11312) 1131211", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131207 (11312) 1131211", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13390", "source" : "2895", "target" : "2896", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13390, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131203 (11312) 1131207", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131203 (11312) 1131207", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13389", "source" : "2894", "target" : "2895", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13389, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131202 (11312) 1131203", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131202 (11312) 1131203", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13388", "source" : "2893", "target" : "2894", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13388, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131201 (11312) 1131202", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131201 (11312) 1131202", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13344", "source" : "2849", "target" : "2850", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13344, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131110 (11311) 1131111", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131110 (11311) 1131111", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13345", "source" : "2850", "target" : "2851", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13345, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131111 (11311) 1131112", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131111 (11311) 1131112", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13340", "source" : "2845", "target" : "2846", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13340, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131106 (11311) 1131107", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131106 (11311) 1131107", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13341", "source" : "2846", "target" : "2847", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13341, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131107 (11311) 1131108", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131107 (11311) 1131108", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13342", "source" : "2847", "target" : "2848", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13342, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131108 (11311) 1131109", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131108 (11311) 1131109", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13343", "source" : "2848", "target" : "2849", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13343, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131109 (11311) 1131110", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131109 (11311) 1131110", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13336", "source" : "2841", "target" : "2842", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13336, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131102 (11311) 1131103", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131102 (11311) 1131103", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13337", "source" : "2842", "target" : "2843", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13337, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131103 (11311) 1131104", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131103 (11311) 1131104", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13338", "source" : "2843", "target" : "2844", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13338, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131104 (11311) 1131105", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131104 (11311) 1131105", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13339", "source" : "2844", "target" : "2845", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13339, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131105 (11311) 1131106", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131105 (11311) 1131106", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13335", "source" : "2840", "target" : "2841", "line_name_k" : "チュウオウホンセン", "is_bullet" : false, "lon" : 138.61735796977746, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13335, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11311", "shared_interaction" : "11311", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央本線(東京~塩尻)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131101 (11311) 1131102", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131101 (11311) 1131102", "lat" : 35.770367336599776, "e_status_y" : 0, "line_name_h" : "JR中央本線(東京~塩尻)" }, "selected" : false }, { "data" : { "id" : "13435", "source" : "2941", "target" : "2942", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13435, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131325 (11313) 1131326", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131325 (11313) 1131326", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13429", "source" : "2935", "target" : "2936", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13429, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131319 (11313) 1131320", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131319 (11313) 1131320", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13430", "source" : "2936", "target" : "2937", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13430, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131320 (11313) 1131321", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131320 (11313) 1131321", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13427", "source" : "2933", "target" : "2934", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13427, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131317 (11313) 1131318", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131317 (11313) 1131318", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13428", "source" : "2934", "target" : "2935", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13428, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131318 (11313) 1131319", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131318 (11313) 1131319", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13433", "source" : "2939", "target" : "2940", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13433, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131323 (11313) 1131324", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131323 (11313) 1131324", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13434", "source" : "2940", "target" : "2941", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13434, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131324 (11313) 1131325", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131324 (11313) 1131325", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13431", "source" : "2937", "target" : "2938", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13431, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131321 (11313) 1131322", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131321 (11313) 1131322", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13432", "source" : "2938", "target" : "2939", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13432, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131322 (11313) 1131323", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131322 (11313) 1131323", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13452", "source" : "2959", "target" : "2960", "line_name_k" : "ソウブホンセン", "is_bullet" : false, "lon" : 140.25466124558875, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13452, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11314", "shared_interaction" : "11314", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR総武本線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131404 (11314) 1131405", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131404 (11314) 1131405", "lat" : 35.68790263001846, "e_status_y" : 0, "line_name_h" : "JR総武本線" }, "selected" : false }, { "data" : { "id" : "13451", "source" : "2958", "target" : "2959", "line_name_k" : "ソウブホンセン", "is_bullet" : false, "lon" : 140.25466124558875, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13451, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11314", "shared_interaction" : "11314", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR総武本線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131403 (11314) 1131404", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131403 (11314) 1131404", "lat" : 35.68790263001846, "e_status_y" : 0, "line_name_h" : "JR総武本線" }, "selected" : false }, { "data" : { "id" : "13450", "source" : "2957", "target" : "2958", "line_name_k" : "ソウブホンセン", "is_bullet" : false, "lon" : 140.25466124558875, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13450, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11314", "shared_interaction" : "11314", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR総武本線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131402 (11314) 1131403", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131402 (11314) 1131403", "lat" : 35.68790263001846, "e_status_y" : 0, "line_name_h" : "JR総武本線" }, "selected" : false }, { "data" : { "id" : "13449", "source" : "2956", "target" : "2957", "line_name_k" : "ソウブホンセン", "is_bullet" : false, "lon" : 140.25466124558875, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13449, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11314", "shared_interaction" : "11314", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR総武本線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131401 (11314) 1131402", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131401 (11314) 1131402", "lat" : 35.68790263001846, "e_status_y" : 0, "line_name_h" : "JR総武本線" }, "selected" : false }, { "data" : { "id" : "13404", "source" : "2909", "target" : "2910", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13404, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131225 (11312) 1131226", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131225 (11312) 1131226", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13405", "source" : "2910", "target" : "2911", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13405, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131226 (11312) 1131227", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131226 (11312) 1131227", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13406", "source" : "2911", "target" : "2912", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13406, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131227 (11312) 1131228", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131227 (11312) 1131228", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13407", "source" : "2912", "target" : "2913", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13407, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131228 (11312) 1131229", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131228 (11312) 1131229", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13408", "source" : "2913", "target" : "2914", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13408, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131229 (11312) 1131230", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131229 (11312) 1131230", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13409", "source" : "2914", "target" : "2915", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13409, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131230 (11312) 1131231", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131230 (11312) 1131231", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13410", "source" : "2915", "target" : "2916", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13410, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131231 (11312) 1131232", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131231 (11312) 1131232", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13396", "source" : "2901", "target" : "2902", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13396, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131217 (11312) 1131218", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131217 (11312) 1131218", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13397", "source" : "2902", "target" : "2903", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13397, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131218 (11312) 1131219", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131218 (11312) 1131219", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13398", "source" : "2903", "target" : "2904", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13398, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131219 (11312) 1131220", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131219 (11312) 1131220", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13399", "source" : "2904", "target" : "2905", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13399, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131220 (11312) 1131221", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131220 (11312) 1131221", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13400", "source" : "2905", "target" : "2906", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13400, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131221 (11312) 1131222", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131221 (11312) 1131222", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13401", "source" : "2906", "target" : "2907", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13401, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131222 (11312) 1131223", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131222 (11312) 1131223", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13402", "source" : "2907", "target" : "2908", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13402, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131223 (11312) 1131224", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131223 (11312) 1131224", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13403", "source" : "2908", "target" : "2909", "line_name_k" : "チュウオウセン", "is_bullet" : false, "lon" : 139.53798847265622, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13403, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11312", "shared_interaction" : "11312", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央線(快速)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131224 (11312) 1131225", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131224 (11312) 1131225", "lat" : 35.700170421148705, "e_status_y" : 0, "line_name_h" : "JR中央線(快速)" }, "selected" : false }, { "data" : { "id" : "13420", "source" : "2926", "target" : "2927", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13420, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131310 (11313) 1131311", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131310 (11313) 1131311", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13419", "source" : "2925", "target" : "2926", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13419, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131309 (11313) 1131310", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131309 (11313) 1131310", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13422", "source" : "2928", "target" : "2929", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13422, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131312 (11313) 1131313", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131312 (11313) 1131313", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13421", "source" : "2927", "target" : "2928", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13421, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131311 (11313) 1131312", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131311 (11313) 1131312", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13424", "source" : "2930", "target" : "2931", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13424, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131314 (11313) 1131315", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131314 (11313) 1131315", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13423", "source" : "2929", "target" : "2930", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13423, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131313 (11313) 1131314", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131313 (11313) 1131314", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13426", "source" : "2932", "target" : "2933", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13426, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131316 (11313) 1131317", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131316 (11313) 1131317", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13425", "source" : "2931", "target" : "2932", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13425, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131315 (11313) 1131316", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131315 (11313) 1131316", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13412", "source" : "2918", "target" : "2919", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13412, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131302 (11313) 1131303", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131302 (11313) 1131303", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13411", "source" : "2917", "target" : "2918", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13411, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131301 (11313) 1131302", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131301 (11313) 1131302", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13414", "source" : "2920", "target" : "2921", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13414, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131304 (11313) 1131305", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131304 (11313) 1131305", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13413", "source" : "2919", "target" : "2920", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13413, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131303 (11313) 1131304", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131303 (11313) 1131304", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13416", "source" : "2922", "target" : "2923", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13416, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131306 (11313) 1131307", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131306 (11313) 1131307", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13415", "source" : "2921", "target" : "2922", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13415, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131305 (11313) 1131306", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131305 (11313) 1131306", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13418", "source" : "2924", "target" : "2925", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13418, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131308 (11313) 1131309", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131308 (11313) 1131309", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13417", "source" : "2923", "target" : "2924", "line_name_k" : "チュウオウ・ソウブセン", "is_bullet" : false, "lon" : 139.83715522681192, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 10, "SUID" : 13417, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11313", "shared_interaction" : "11313", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR中央・総武線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131307 (11313) 1131308", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131307 (11313) 1131308", "lat" : 35.701641362335245, "e_status_y" : 0, "line_name_h" : "JR中央・総武緩行線" }, "selected" : false }, { "data" : { "id" : "13496", "source" : "3004", "target" : "3005", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13496, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131518 (11315) 1131519", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131518 (11315) 1131519", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13495", "source" : "3003", "target" : "3004", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13495, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131517 (11315) 1131518", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131517 (11315) 1131518", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13494", "source" : "3002", "target" : "3003", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13494, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131516 (11315) 1131517", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131516 (11315) 1131517", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13493", "source" : "3001", "target" : "3002", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13493, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131515 (11315) 1131516", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131515 (11315) 1131516", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13492", "source" : "3000", "target" : "3001", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13492, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131514 (11315) 1131515", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131514 (11315) 1131515", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13491", "source" : "2999", "target" : "3000", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13491, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131513 (11315) 1131514", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131513 (11315) 1131514", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13490", "source" : "2998", "target" : "2999", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13490, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131512 (11315) 1131513", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131512 (11315) 1131513", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13489", "source" : "2997", "target" : "2998", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13489, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131511 (11315) 1131512", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131511 (11315) 1131512", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13503", "source" : "3012", "target" : "3013", "line_name_k" : "イツカイチセン", "is_bullet" : false, "lon" : 139.29165743387557, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13503, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11316", "shared_interaction" : "11316", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR五日市線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131601 (11316) 1131602", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131601 (11316) 1131602", "lat" : 35.725830442825945, "e_status_y" : 0, "line_name_h" : "JR五日市線" }, "selected" : false }, { "data" : { "id" : "13502", "source" : "3010", "target" : "3011", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13502, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131524 (11315) 1131525", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131524 (11315) 1131525", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13501", "source" : "3009", "target" : "3010", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13501, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131523 (11315) 1131524", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131523 (11315) 1131524", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13500", "source" : "3008", "target" : "3009", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13500, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131522 (11315) 1131523", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131522 (11315) 1131523", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13499", "source" : "3007", "target" : "3008", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13499, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131521 (11315) 1131522", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131521 (11315) 1131522", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13498", "source" : "3006", "target" : "3007", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13498, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131520 (11315) 1131521", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131520 (11315) 1131521", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13497", "source" : "3005", "target" : "3006", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13497, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131519 (11315) 1131520", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131519 (11315) 1131520", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13509", "source" : "3019", "target" : "3020", "line_name_k" : "ハチコウセン", "is_bullet" : false, "lon" : 139.33299376182276, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13509, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11317", "shared_interaction" : "11317", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR八高線(八王子~高麗川)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131701 (11317) 1131702", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131701 (11317) 1131702", "lat" : 35.78050242395001, "e_status_y" : 0, "line_name_h" : "JR八高線(八王子~高麗川)" }, "selected" : false }, { "data" : { "id" : "13510", "source" : "3020", "target" : "3021", "line_name_k" : "ハチコウセン", "is_bullet" : false, "lon" : 139.33299376182276, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13510, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11317", "shared_interaction" : "11317", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR八高線(八王子~高麗川)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131702 (11317) 1131703", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131702 (11317) 1131703", "lat" : 35.78050242395001, "e_status_y" : 0, "line_name_h" : "JR八高線(八王子~高麗川)" }, "selected" : false }, { "data" : { "id" : "13508", "source" : "3017", "target" : "3018", "line_name_k" : "イツカイチセン", "is_bullet" : false, "lon" : 139.29165743387557, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13508, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11316", "shared_interaction" : "11316", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR五日市線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131606 (11316) 1131607", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131606 (11316) 1131607", "lat" : 35.725830442825945, "e_status_y" : 0, "line_name_h" : "JR五日市線" }, "selected" : false }, { "data" : { "id" : "13506", "source" : "3015", "target" : "3016", "line_name_k" : "イツカイチセン", "is_bullet" : false, "lon" : 139.29165743387557, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13506, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11316", "shared_interaction" : "11316", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR五日市線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131604 (11316) 1131605", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131604 (11316) 1131605", "lat" : 35.725830442825945, "e_status_y" : 0, "line_name_h" : "JR五日市線" }, "selected" : false }, { "data" : { "id" : "13507", "source" : "3016", "target" : "3017", "line_name_k" : "イツカイチセン", "is_bullet" : false, "lon" : 139.29165743387557, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13507, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11316", "shared_interaction" : "11316", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR五日市線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131605 (11316) 1131606", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131605 (11316) 1131606", "lat" : 35.725830442825945, "e_status_y" : 0, "line_name_h" : "JR五日市線" }, "selected" : false }, { "data" : { "id" : "13504", "source" : "3013", "target" : "3014", "line_name_k" : "イツカイチセン", "is_bullet" : false, "lon" : 139.29165743387557, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13504, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11316", "shared_interaction" : "11316", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR五日市線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131602 (11316) 1131603", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131602 (11316) 1131603", "lat" : 35.725830442825945, "e_status_y" : 0, "line_name_h" : "JR五日市線" }, "selected" : false }, { "data" : { "id" : "13505", "source" : "3014", "target" : "3015", "line_name_k" : "イツカイチセン", "is_bullet" : false, "lon" : 139.29165743387557, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 12, "SUID" : 13505, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11316", "shared_interaction" : "11316", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR五日市線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131603 (11316) 1131604", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131603 (11316) 1131604", "lat" : 35.725830442825945, "e_status_y" : 0, "line_name_h" : "JR五日市線" }, "selected" : false }, { "data" : { "id" : "13513", "source" : "3023", "target" : "3024", "line_name_k" : "ハチコウセン", "is_bullet" : false, "lon" : 139.33299376182276, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13513, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11317", "shared_interaction" : "11317", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR八高線(八王子~高麗川)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131705 (11317) 1131706", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131705 (11317) 1131706", "lat" : 35.78050242395001, "e_status_y" : 0, "line_name_h" : "JR八高線(八王子~高麗川)" }, "selected" : false }, { "data" : { "id" : "13511", "source" : "3021", "target" : "3022", "line_name_k" : "ハチコウセン", "is_bullet" : false, "lon" : 139.33299376182276, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13511, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11317", "shared_interaction" : "11317", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR八高線(八王子~高麗川)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131703 (11317) 1131704", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131703 (11317) 1131704", "lat" : 35.78050242395001, "e_status_y" : 0, "line_name_h" : "JR八高線(八王子~高麗川)" }, "selected" : false }, { "data" : { "id" : "13512", "source" : "3022", "target" : "3023", "line_name_k" : "ハチコウセン", "is_bullet" : false, "lon" : 139.33299376182276, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13512, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11317", "shared_interaction" : "11317", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR八高線(八王子~高麗川)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131704 (11317) 1131705", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131704 (11317) 1131705", "lat" : 35.78050242395001, "e_status_y" : 0, "line_name_h" : "JR八高線(八王子~高麗川)" }, "selected" : false }, { "data" : { "id" : "13479", "source" : "2987", "target" : "2988", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13479, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131501 (11315) 1131502", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131501 (11315) 1131502", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13480", "source" : "2988", "target" : "2989", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13480, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131502 (11315) 1131503", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131502 (11315) 1131503", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13485", "source" : "2993", "target" : "2994", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13485, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131507 (11315) 1131508", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131507 (11315) 1131508", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13486", "source" : "2994", "target" : "2995", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13486, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131508 (11315) 1131509", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131508 (11315) 1131509", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13487", "source" : "2995", "target" : "2996", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13487, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131509 (11315) 1131510", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131509 (11315) 1131510", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13488", "source" : "2996", "target" : "2997", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13488, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131510 (11315) 1131511", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131510 (11315) 1131511", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13481", "source" : "2989", "target" : "2990", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13481, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131503 (11315) 1131504", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131503 (11315) 1131504", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13482", "source" : "2990", "target" : "2991", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13482, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131504 (11315) 1131505", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131504 (11315) 1131505", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13483", "source" : "2991", "target" : "2992", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13483, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131505 (11315) 1131506", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131505 (11315) 1131506", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13484", "source" : "2992", "target" : "2993", "line_name_k" : "オウメセン", "is_bullet" : false, "lon" : 139.2400413547656, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13484, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11315", "shared_interaction" : "11315", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR青梅線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131506 (11315) 1131507", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131506 (11315) 1131507", "lat" : 35.782572650078514, "e_status_y" : 0, "line_name_h" : "JR青梅線" }, "selected" : false }, { "data" : { "id" : "13566", "source" : "3079", "target" : "3080", "line_name_k" : "ジョウバンセン", "is_bullet" : false, "lon" : 139.92381250144126, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13566, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11320", "shared_interaction" : "11320", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR常磐線(上野~取手)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132003 (11320) 1132004", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132003 (11320) 1132004", "lat" : 35.8197193273695, "e_status_y" : 0, "line_name_h" : "JR常磐線(上野~取手)" }, "selected" : false }, { "data" : { "id" : "13567", "source" : "3080", "target" : "3081", "line_name_k" : "ジョウバンセン", "is_bullet" : false, "lon" : 139.92381250144126, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13567, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11320", "shared_interaction" : "11320", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR常磐線(上野~取手)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132004 (11320) 1132005", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132004 (11320) 1132005", "lat" : 35.8197193273695, "e_status_y" : 0, "line_name_h" : "JR常磐線(上野~取手)" }, "selected" : false }, { "data" : { "id" : "13564", "source" : "3077", "target" : "3078", "line_name_k" : "ジョウバンセン", "is_bullet" : false, "lon" : 139.92381250144126, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13564, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11320", "shared_interaction" : "11320", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR常磐線(上野~取手)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132001 (11320) 1132002", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132001 (11320) 1132002", "lat" : 35.8197193273695, "e_status_y" : 0, "line_name_h" : "JR常磐線(上野~取手)" }, "selected" : false }, { "data" : { "id" : "13565", "source" : "3078", "target" : "3079", "line_name_k" : "ジョウバンセン", "is_bullet" : false, "lon" : 139.92381250144126, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13565, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11320", "shared_interaction" : "11320", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR常磐線(上野~取手)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132002 (11320) 1132003", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132002 (11320) 1132003", "lat" : 35.8197193273695, "e_status_y" : 0, "line_name_h" : "JR常磐線(上野~取手)" }, "selected" : false }, { "data" : { "id" : "13570", "source" : "3083", "target" : "3084", "line_name_k" : "ジョウバンセン", "is_bullet" : false, "lon" : 139.92381250144126, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13570, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11320", "shared_interaction" : "11320", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR常磐線(上野~取手)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132007 (11320) 1132008", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132007 (11320) 1132008", "lat" : 35.8197193273695, "e_status_y" : 0, "line_name_h" : "JR常磐線(上野~取手)" }, "selected" : false }, { "data" : { "id" : "13568", "source" : "3081", "target" : "3082", "line_name_k" : "ジョウバンセン", "is_bullet" : false, "lon" : 139.92381250144126, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13568, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11320", "shared_interaction" : "11320", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR常磐線(上野~取手)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132005 (11320) 1132006", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132005 (11320) 1132006", "lat" : 35.8197193273695, "e_status_y" : 0, "line_name_h" : "JR常磐線(上野~取手)" }, "selected" : false }, { "data" : { "id" : "13569", "source" : "3082", "target" : "3083", "line_name_k" : "ジョウバンセン", "is_bullet" : false, "lon" : 139.92381250144126, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 11, "SUID" : 13569, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11320", "shared_interaction" : "11320", "company_url" : "http://www.jreast.co.jp/", "line_name" : "JR常磐線(上野~取手)", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1132006 (11320) 1132007", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1132006 (11320) 1132007", "lat" : 35.8197193273695, "e_status_y" : 0, "line_name_h" : "JR常磐線(上野~取手)" }, "selected" : false }, { "data" : { "id" : "13532", "source" : "3044", "target" : "3045", "line_name_k" : "ウツノミヤセン", "is_bullet" : false, "lon" : 139.8464030031987, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13532, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11319", "shared_interaction" : "11319", "company_url" : "http://www.jreast.co.jp/", "line_name" : "宇都宮線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131901 (11319) 1131902", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131901 (11319) 1131902", "lat" : 36.37943924080079, "e_status_y" : 0, "line_name_h" : "JR東北本線" }, "selected" : false }, { "data" : { "id" : "13533", "source" : "3045", "target" : "3046", "line_name_k" : "ウツノミヤセン", "is_bullet" : false, "lon" : 139.8464030031987, "company_name_k" : "ジェイアールヒガシニホン", "zoom" : 9, "SUID" : 13533, "company_type" : 1, "company_name_h" : "東日本旅客鉄道株式会社", "interaction" : "11319", "shared_interaction" : "11319", "company_url" : "http://www.jreast.co.jp/", "line_name" : "宇都宮線", "selected" : false, "company_name" : "JR東日本", "company_cd" : 2, "name" : "1131902 (11319) 1131903", "rr_cd" : 11, "company_name_r" : "JR東日本", "e_status_x" : 0, "shared_name" : "1131902 (11319) 1131903", "lat" : 36.37943924080079, "e_status_y" : 0, "line_name_h" : "JR東北本線" }, "selected" : false } ] }golang-gonum-v1-gonum-0.14.0/graph/formats/dot/000077500000000000000000000000001450372207100212005ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/README.md000066400000000000000000000006731450372207100224650ustar00rootroot00000000000000# 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. golang-gonum-v1-gonum-0.14.0/graph/formats/dot/ast/000077500000000000000000000000001450372207100217675ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/ast/ast.go000066400000000000000000000213311450372207100231050ustar00rootroot00000000000000// 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() {} golang-gonum-v1-gonum-0.14.0/graph/formats/dot/ast/ast_test.go000066400000000000000000000050601450372207100241450ustar00rootroot00000000000000// 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_test import ( "bytes" "os" "testing" "gonum.org/v1/gonum/graph/formats/dot" "gonum.org/v1/gonum/graph/formats/dot/ast" ) func TestParseFile(t *testing.T) { golden := []struct { in string out string }{ {in: "../internal/testdata/empty.dot"}, {in: "../internal/testdata/graph.dot"}, {in: "../internal/testdata/digraph.dot"}, {in: "../internal/testdata/strict.dot"}, {in: "../internal/testdata/multi.dot"}, {in: "../internal/testdata/named_graph.dot"}, {in: "../internal/testdata/node_stmt.dot"}, {in: "../internal/testdata/edge_stmt.dot"}, {in: "../internal/testdata/attr_stmt.dot"}, {in: "../internal/testdata/attr.dot"}, { in: "../internal/testdata/subgraph.dot", out: "../internal/testdata/subgraph.golden", }, { in: "../internal/testdata/semi.dot", out: "../internal/testdata/semi.golden", }, { in: "../internal/testdata/empty_attr.dot", out: "../internal/testdata/empty_attr.golden", }, { in: "../internal/testdata/attr_lists.dot", out: "../internal/testdata/attr_lists.golden", }, { in: "../internal/testdata/attr_sep.dot", out: "../internal/testdata/attr_sep.golden", }, {in: "../internal/testdata/subgraph_vertex.dot"}, {in: "../internal/testdata/port.dot"}, } for _, g := range golden { file, err := dot.ParseFile(g.in) if err != nil { t.Errorf("%q: unable to parse file; %v", g.in, err) continue } // If no output path is specified, the input is already golden. out := g.in if len(g.out) > 0 { out = g.out } buf, err := os.ReadFile(out) if err != nil { t.Errorf("%q: unable to read file; %v", g.in, err) continue } got := file.String() // Remove trailing newline. want := string(bytes.TrimSpace(buf)) if got != want { t.Errorf("%q: graph mismatch; expected %q, got %q", g.in, want, got) } } } // Verify that all statements implement the Stmt interface. var ( _ ast.Stmt = (*ast.NodeStmt)(nil) _ ast.Stmt = (*ast.EdgeStmt)(nil) _ ast.Stmt = (*ast.AttrStmt)(nil) _ ast.Stmt = (*ast.Attr)(nil) _ ast.Stmt = (*ast.Subgraph)(nil) ) // Verify that all vertices implement the Vertex interface. var ( _ ast.Vertex = (*ast.Node)(nil) _ ast.Vertex = (*ast.Subgraph)(nil) ) golang-gonum-v1-gonum-0.14.0/graph/formats/dot/ast/doc.go000066400000000000000000000005131450372207100230620ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/doc.go000066400000000000000000000004351450372207100222760ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/dot.go000066400000000000000000000031131450372207100223130ustar00rootroot00000000000000// 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" "os" "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 := os.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 := io.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)) } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/fuzz/000077500000000000000000000000001450372207100221765ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/fuzz/corpus.zip000066400000000000000000023003501450372207100242400ustar00rootroot00000000000000PKT eN=<+0008dfc8d866857e77ec5d2d941b791bb20c90cf-22K/J,Ȩ`vm-PK:gN.*001c85f6736d161f1c71ff9cb45c5cb9a5b290df-2K/J,ȨP'Y[ &jjHZZ2 & PKXgND :(002c5c6891289811343ba1c4645e32ebc5845243K/J,Ȩ..MrwSW B)PKmfNSR+0041537909b9755cae7f71dcd470b223e4404c3a-34K/J,ȨL3Fh8.ZPKdaN=0*0053aa4aadeba76453dacd6fd23d51789b268391-6K/J,ȨVz}!HPKaN7 *006e23acf33a2a19da5c168f0d80857b44f5ec1c-9K/J,Ȩv PKaN*0082d70f9efb6b4b63cc48803930f5d432b1b031-8K/J,ȨvtZPKeNᲗu+008a58dde03aa27c465c27bf07dc58654dba04cc-26K/J,Ȩv/J,`PK5eN {R(+0092526ce6998afc19811e1e2f7f4b9898e77fb5-13K/J,Ȩ.}-*&ZPKQgNB"*00b8e761c4b4201920368ed6d794eaf90ee6b5e5-1K/J,Ȩ.Mr/JdPKhdN&+00c4abdd0f26a3054389fc3608064e51e90ef11f-18K/J,ȨյPK /fNc[ *00cb70989ad0ff28b0140d93d9ea4ed044a616a3-5graph{<ﰿ=>}PK LbN'e+010b6055d9e5e97d56bb66544c38f04b0a757666-36graph{St5{St1}}PK/dN^}{ +014fce145fb6f74fa84643ff15a608fc848edd32-41K/J,Ȩ jkA@PK aNrj +015161e322d273d906b940627fa2fb00bfe68037-18graph{N_}PK|3gNG,+(01773c8b1049ccefef339f392134ac5b72817fafK/J,ȨV11Q1 bbL\01jkPKdNE+019ff0d96fc0b1da7cda1a11872b4129c1153a68-23K/J,Ȩv"Z PK YaN?Sw*01a9208477bc839af1038cc08b2191fc2b0dece9-9graph{{s翿}s ̄}PKJaN{+01ac7ec5506dbe106672f7607c903ee03a743bc9-13K/J,ȨvtVm-PKEeN=LO+01da8793833e348e9fde3b277f439f80e67b81d8-33K/J,ȨWwK8B) _PK (hgN-0)7*02033b935876930eb057f73f522c5b59e1c0533e-5graph{m:m t:NodeS}PKKgNSKD+02281995b4a072f1e01554154adb2d794ec6e354-32K/J,Ȩv|?PK KdN\ +02295991ebad764cbfc3cbb12dadf5dd68f44dce-31graph{SUB}PK 3aN\y*023112aba726cde3e740a306b1edea4b1ce34bcc-9graph{"\﷿\"}PKHeNZ+02445f5a8b83e1a13ffde8f1c94cfa774749474b-20K/J,Ȩ4yWgZPK rfN9+02637d43066c5ec74dcaea759cf691c09b23185d-16graph{{{{Sb}}}So}PK҄eN55+027a08436021c49165ec4169a401bb890974f06c-43K/J,ȨԔT ôL#pZPK|aNM-+028631c96f3dcdb7544fe19ada449289d1e06d01-31K/J,ȨvMIZ0PKĤaN2c+0286a10c124234abe5c569ff8acff25adafa7fcd-20K/J,Ȩ..MrPK+0a02a003c03eb90a7b21e718ee269fd26c279051-41K/J,Ȩ3FPKr'eN8+0a130cfc229123a38c9c73b0a93f238e3cef8769-21K/J,Ȩ.M*PKDeNa+*0a20027b2c7ea73c10ab0e7ec8a763c3cd386dce-6KL/J,Ȩ.*.׵CPK sjgNU{v *0a3592d44920e8e3bb6c965bf98155d34bc31242-6graph{gr_}PKaNY^(0a3d88de3800221bd19cc0fa4243058bdb9fe551K/J,Ȩ..M0jkPK ƙaNݲ/*0a3f116a738e4220eef3a3225bf410b7d7a14f84-5graph{{{{grN}}grO}}PKcNwD-+0a41e9843ed3e9bd762606e102fff906e283bb50-21K/J,ȨVB V1@eCX T PKfNC9@*0a482e02efe7f8bd6e3f1d5d9bf2256c2d2ee872-6K/J,ȨN,Z(#CkkApF-PK dN; +0a495bb2adf440a3539ef5e16551fdf52f9e135c-18graph{DiG￿}PK ωfNξ *0a97ecb9191eda2fefc0547b34a3328d336e2100-6graph {{e_}}PKfN(v*0abc3339d9030776ac4f575bad2e955bc2487896-9K/J,ȨvL7HZPKfN̽[=+0affbaec48ba6af4afb96d0d05d09aac3b9ee2d9-37K/J,ȨVVBJ1)J \[KLPKdNذz*+0b10b1031c11b796059e6c9c07afb0b6eb46889f-22K/J,Ȩvr W@"kkQ8PK<\eN'*0b13cbffcf678131477297d3c645ae9aaa69822d-7K/J,Ȩvɩv)Z PK fngN*0b261bbbbce39a88080322ff6c14a47df9808121-9graph{{INVANVNVALID}}PKgfNO-*0b3a3e94f7c27b5c03a435c8a4d29d19ae9caf88-7K/J,Ȩ94#jPK dN% +0b8fe68356e5b192eecca94960b1526fb45af087-13graph{digra_}PKBbNy+0be61a7c8eed566790848d3194a13ba4357929dd-27K/J,Ȩv EPK TdN^h *0bf9790b8be04eef7af71c8a44a039660379ec52-6graph{DigraG}PKaN E%+0c0c5b18e581bfc6ed54d640c82e63bd3c4de227-16K/J,Ȩv/JtS`ҩLB)PKbN+0c27b31e97e4946dbe97d2446de62da92e467b25-36K/J,ȨԔZPK fNCP +0c33f8c323ac722a2f410188c9117036022befb1-16graph{SR{}SS}PK%bNn!+0c668ff77f7598e6bb0f1fd758637bf8d4294987-32K/J,Ȩ.)Z Dm-PKfNƽ*0c7e4ffecbdb24ebb92be66224e19ef418de41dc-8s/J,Ȩ..MJ/JѵPKdN5N *0d80b33a9f6418bae26d6cb7e0e13a674dc5651e-1graph{Nodeh}PKϚaNJ(+0d893ab9bc4c39d3127d6710b64904bbd814ccb2-10K/J,Ȩ.~mPK9cN^r/+0d914e1c753d336b60538507e03f397d01902737-32K/J,Ȩvt/JRPK σfN2*0db22549a24841e76383052cf284266d1a80db84-4graph{<"￿\￿}>}PKQaNf *0dc4c6d8f0fa77f10f1f1018867d1358f7313ed2-4K/J,ȨO0BPKH1bN6=o+0dc85e52a4f4e5fc494e2e4c8dc367b1dbdc30ed-39K/J,ȨPKaNwb>m(0dde96a02221a08581fa0a8fdca5dfe6bf035ff4KL/J,P(.IOINMMM-.ɋαURE"v9&LMH=LNᢵPKeNf!*0e04358aa99c751bd598eca401a676d0961b95c1-9K/J,ȨV}!jPK*7bNsA+0e0786032d48e81fc347f496db1a0383163c44fd-30K/J,Ȩv2jTE-PKaNZIU+0e1cc06dedb043a16b1a4ae59e8df56c4cc4a96c-23K/J,ȨwZPKaNSﲋ((0e22995ed26aa5bb6784556af7231cb78840a339MOA 1J? $1&DB-^{1K 2>˶SIWV@6I%Ӑ,-6COF'C#~ >9śOww](~gPK zfNEI*0e4019cf475fba53c69b79e4e8a4e8c19f14f980-6graph{<ﰿ=ﰿ=>}PKeN]6+0e456b80a388b0a872986fb7a3f24ad0c214b838-26K/J,ȨׂPKReN;*0e4f1f110370e72c52c72aa6c8bd18feced4b80c-1K/J,ȨvPB"x@PKaNe*0e61fb3ccc44c4258eec6df2fbf26007e6622524-8K/J,Ȩ..)L.PK 'aNկ*0e6e1e80ae91dcac5da25106f050b9d5871a2893-3graph{{d.650}}PK QJdNff *0e761bfd9019cd3afcb76de1c0a5efa5e3d30e6f-1graph {nob}PKCaNxS*0e7d234b16764fb0ba9f0aa68c7c79328ba881e0-6K/J,ȨvL/PK9eNe'ܙ#W+0ebb9c52f13ed5ad626bc4652de5a372f3758c3b-14K/J,Ȩvz1}2RPZX ւE l*@4PKwdN#+0ec42298efb0efec9a2f2ae09cd69de5c0cfe4fa-31K/J,Ȩvt/S`Y PKbN> +0eda2097a860cf0534710526f8b33f2e54403c16-38K/J,Ȩ.)ʬPKnagN*0ee39b8e820476e8e68ba86e2f6f86e392df4851-1K/J,ȨV#iZPKfN'GM*0eed9f8fbde76c333dbb2ce4a97890176473191b-2U10 _dmJ#bwe"| ]SH_v4|߸Ϫl]/PK aNN+0ef8065b4709163f3caece38900ee513ce42a84a-10graph{{{DIG }}}PKӚaN~H!+0f1c9ed01ba607dab70958f590184ba40ec4804a-10K/J,ȨׂZ$&PK 'aNHX*0f3055eadfb6b6f1430d752f6c6db44e3d496861-9graph{subGrap8}PKAeNt*+0f416baeb7158aa36d29c65bb7352c5133214b9f-23K/J,Ȩvuqw@PKhfNJ>@*0f5197dac833cbf3ea08d8ba33e811fc64d87b96-1K/J,ȨvtE'PK6gN8 c9+0f628c013456a5de318453f663498a160bdd4c6e-24K/J,Ȩvҥ 2ʆ8%PKfNt *0f6791ea2b53b47502b8919909038182fa807236-5K/J,Ȩ9PKaN_*0f68cd375558c6019c4185bb36dff540189c4a42-9K/J,ȨNy?PKeN/'+0f778ff17403f0bb11056c105a5977d37f6e2edf-25K/J,ȨZ P `PK cgNi*0f8ce12ec72ed33369c8dd53d2a1d2c21fc1f41b-1digraph{el el}PKaN'+0f8d54eacf9d785e493dce2a1c66bd4324ef7d8d-25K/J,Ȩ~?PK agNJ;*0fa1ff4379e4d971ca291ea72e2f0d5a503ee06e-2digraph{Edgee}PK aNO*0fa281a3dfe44ef7f012d49be39b2a56c6b8e54f-3graph{{nodО}}PKaN)*0fb4cf4c83a54cfc9037534e9bef53107187db27-2K/J,ȨO1PK  mgNi*W+0fd32429cdadce0bd2ad44a6931f4f3fe9d4a0c7-10graph{I}PK cNyNZ+0fea3fb92aa6c7f1ba5e8ca3958808787f78e935-17graph{"\I\3\I\#"}PKvaNF+0fff5efaf68d4fd2746622718de21c66507b47bf-12K/J,Ȩv/:LPK xaNQ0+100403be607df07897cf6a9cd1194c980111ac00-32graph{DiGr￿}PKv`cNjqJ(+100a8fdd9dff8af76d91e97ebee00cacb4554c71-28K/J,Ȩ.MJ7$TPKdeN-+1021dac2011318c5d857862aa8b185fd10c84d50-13K/J,Ȩ..y-DfPK 1dNddH *106206d30764771b86a791e7bb938265d3c42bae-9graph{SUBGĄ}PK OJdN"Gx+10764f4d2203d6d910e57714eea6230f97b1339e-29graph{{Dig}}PK9bNyW0+1079544b9a4a3fb4c0e44ecf653d63505a9f4370-33K/J,Ȩ! SH|(PKPaNpǼ*1079adb58a1ae36565e1c987bd6c98ebecb81e69-5K/J,ȨvMa%% PK&aN6+108a57516a53d374e78d31952a68febc3d955a07-15K/J,Ȩ PF-PK:gNtO4*10a1163134aca0c2799d6fc006fc20f25a868536-3K/J,ȨP'Y[ &jj 3Āӵp5JPKd6gNSt4k(10b1cca61d1e22ab749560b27d9bdea58f09e654K/J,ȨvL/UյZZ1B $ U "PKgN1)*10dbcad51857d8d20668477cc07d995a02c03451-2K/J,ȨL ӤFC(PK8gNqu*10fdacd10709173549cd3d1e0c70a5b7adee3924-4K/J,ȨVxx0xd,BxÀJwH̢ʼ`RB0sw(GxZ%% @Pj)HJ< h;JPlhPKbN#+1102668eca37616af74d507f380755e26f58bd31-30K/J,ȨvɌ PKreNg'+112c0b572a04d87f3783e25bc0f20aa3255c4f12-10K/J,ȨvLD jPK+gNUV*1139538b62b3d708d477f5e646682bfdba0d1fb2-2K/J,ȨVRR7777,OL̲(7 t77, 6-5 1J* 0w7rt( PQjkPKrjeN1ޘ&+114e9f69d71f934194582d8312deb6c2067cc74e-16K/J,Ȩ..y`[5z-r@2kPK{BgNϠ|=&*1153c8f64c02ead4b98ac75455b23eb904f45f68-4K/J,Ȩ`Z FspiRC)Rk1L!j,fu @$PKgN#K(11631e1690c82e977d274a9dfab328a6693cb017s/J,Ȩ..MJ2kaj$ jAY}-PK0aN1Z+117d77ddacfe2e9fe05b89f232ffcf1addd42444-26K/J,Ȩ~?&PK bN =k +1192c7f4590d493b6e8f7b2e344e652e265e6210-25graph{{ST}ST}PKlfN+}(11962d5735f0d4614516c3bb1279ff513aa36031K/J,Ȩ΋ZPK mgNP +11acc5fb8e8eb60d7aa858973f05b3295a61c22c-12graph{{diGH}}PKfaNf!4*11ba4006e7d5f564873f93bb84ea56d88aa4a2ed-7K/J,ȨvZ PK׬aN?i+11dcd1f6dc7ed53b87d532af625ef149a80dc3cc-24K/J,Ȩvub(] PKhkfNlT+11f80bd018741956a24f093ab1de83b99663d627-25K/J,Ȩurr (FZ"PKZfN<1*120de720ff87f378b5e2a49152d4e55ef46a3171-2K/J,Ȩurr @jPK pfN VT*121816256254970caf3b558634d29b99281c3720-3graph{nod-9nod}PKjfN(1227139100fd70a70482914a605801874ae3a09bK/J,Ȩ ZPKdN>fA>++123b9d7c1c7713a9c24dd47adea9df29c58acfd4-24K/J,Ȩurr1j4 PK aNpi_*123fe11dd68094b9889dcfe77faaa1fb1ab61f9f-7graph{{r￿r￿}}PK aN*125eb52bd7ebe53877ce2bacb07bea852f095032-2graph{sue nodb}PK aNN *126484e469477112958be816a394a32ce3ec1cc4-7graph{"\￿"}PK aN3*1297ed2488a936cbb1718c249d18447ada98cf17-6graph{{{nО}}}PKaNsIe,1+12a68f22edc4093778b8e6f97879e08b5fcdeb1c-23K/J,ȨWx(!k aPKaN)}7(12ae0928edf6da326837cb0ccd2bd81deeff42c9KL/J,POI5Q9JJ`i` i`Z@JJvJJēPK JdNnQ, +12b3b870660c907ac535a7ad0cad5c5bd70926d9-21graph{Grau}PKmgN/iYu*12c344ec243a26b16f208423b934e2e0cce85c60-2KL/J,ȨNα qtu qȨ.MJϱMͰ---rw-J-qbC YBGW;[%<]h0+].ªPKgNīO%L*12d011c501d9dfd55622c406ddd67ba842904d24-1K/J,ȨNt/ʬPnAm-D" AapE0PKaN%+12d3e32829e8a5860289c2fdd0a636f0d9ba824b-11K/J,ȨNL`62PKeNxh/+12dc04e742d7f0446946a2afdfae8539a1b82524-44K/J,Ȩ.j ΨPK ]fN` *12f89a0b77199e5d50e5f9ffc6f38840c25f3352-7graph{Dig5}PK aN +12fda2e02bc0db610aa1f558d5ce72fcba8cec05-19graph{N_{N_}}PKaN!+1301ccb75ea2f9fe6267beb4a9d69328f7816cd2-18K/J,ȨWB)PK0cN8Š3+133835493e5bbe8bc079937c00377dcb9d9697c1-36K/J,Ȩ.)L6ҨTm- PKF)eNYFc.+136b0578ea6b449e11ea98792a603b925834a0e1-18K/J,Ȩ5 5FFPK"bNaB+1383396c8ea932a5ed6391d5af3bf072851833a2-28K/J,ȨvMI߰JPK5aNA{Vx`*138808b4532cab1c1eacb2ab3929aad3aed21572-1͎ @D y'}BAE3080z5MwU]4u_׭P#/ࣨ N[pv?b+z/b(Fb,&b*fb}Kk[{qGq'uߕpDPKEUeNoel'*138ca00c5c29d235123d83250ecb50beff0d9e58-4mA _ #"%V"H0čW>\ϲZ|U ?UAQ^BXФI52def#"3Q@z: >)6H Pa~PKiaNZ>}PKaN*+13f8c2f348a06c273ef1f410558dd4878539d89b-26K/J,ȨvMIEPKeN$/K*13ffc90636b6dbd5dde363ce87c40edbc6a25a5c-1K/J,Ȩ.Mr/(Z"ccLjkPK bNk)+140f939a0a547f30d72c0fa7c8600fd9818a2b64-35K/J,ȨN 3J!PKȕaN|h*14150e6748a8b73583bf0f4603a78e94625a142a-4K/J,Ȩv5 PK nfN*1419eea034c2a546e569978c2b3d773e27956a09-2Graph{{Subgr4}}PKbN23+143618c80ded036891aeadb99f642c2d977a3ce4-41K/J,ȨNMIFkkPK#gN%*14641f2b1acfd926d50482f347109599a46904b2-1K/J,Ȩ"ZPKqfN@s|*148c20514bedf57ea620a83b4d14be64cc278f90-3s/J,Ȩ..MJ/J4ѵPK oaN!+148c687e18274e54e2185bdddf3ae043a1d33cf6-12graph{subG￿}PKqTgNs*149067ed4c3ce4a4a089e548951ebcd0cdf3a153-7K/J,ȨL 3LBZPK9 cNl+14b8e8348736f6bc8848111a0052e5d34e15b259-37K/J,ȨL ;JՂPKeN`6,*14d980db5aa96755ead256d714f77af1e3685596-1K/J,ȨvuqZ FfעpjPKaNh*14da405e66f3d18e805a50e79c0da97c7ecc833c-4K/J,ȨNtPK nfN +14da6905c6d088f8dfe078940c43774be7a4a97f-14graph{{NU}}PK}PKGaNR+15787c4a3b141e5fa6464855a4342f274ad3ca1e-32K/J,ȨvZPKQbN1b+15890dc5845dc2dc0d32ae3b8028135a30ecb941-39K/J,Ȩ.)@\[ PKjfNh:c*15af24f798767249f0b40b3d1b164bcf39308c35-1K/J,ȨW EFPK kfN4Ib*15b7b89404be2aa18ef9936cadd7f52d9f25ea08-7graph{{e_{e_}}}PKgaN9?D+15c024413c307f8d3152c5aa52dd645d55e72564-11K/J,ȨNL/2F0g^ rPU@PKfNE+15c456d6f9ea1d8497b5615eb2aa1383f657ee17-11K/J,ȨvtPK gNdV!*15dd76ffee8d33281f00033c0c538784faf7d4b6-1K/J,ȨL ӤFCZPK aNC +15de38b841a7c5154ec8322280a40c8399c16f4c-23graph{E￿}PK ZaN +16006b737b3446b851245a5cdd6771e4d8a6666c-11graph{GRAP_}PK2cNj +1609090db0a45d4a8ea6f0fd31023699f3fbb124-28K/J,ȨvtjiPKmfN;'(1623fd191ef4dcdd947f0c04f1342a395d621577K/J,Ȩvt2kZPKdN@A+1636ad09fdec445b6d2a8a0fae0599b4eb6a15d6-11K/J,Ȩ}-PKMfN\S*164a3fe519f6552b22834f784b35ff71dd09e0ca-8s/J,Ȩ."qjPK fNI3&0*1656aded7e026aac8f15bdbfaa0ce53bb0bdf34b-5graph{<©¸¸>}PK8gN˲VA+1663eb04dcaf262390c3185db22c92ea4cfa0c1f-31K/J,ȨvMIGE, bPKOaN%+168c22e6f8473d29a1f008912e5a322b859e2d28-11K/J,ȨNL/&2Y PK8eN,=+*16a019ed55d0e1c69aa0d012dbbffa6b3de16de3-5K/J,Ȩ..)LP&<] PK bN^(+16b8bc2d9b8506f54116276ced274c60d40093be-24K/J,ȨZ õPK9gN+u8+16bd5afa5910d3f54efbf9702fb3f3bd96739bc9-12K/J,ȨvZ(@PKgN)_9*16c32a046259978bfb1f67e3bd0173bb4176d5d6-4K/J,ȨL ӤFC(PKRgNeNL(16c86ec63c3d6b00584a90ffc7ddf29931687edbK/J,ȨvMIORPKdN H2+16cb430a1e398fc54662751c1cbd92a6d24cdb31-42K/J,Ȩ.MJt?EPKzfN *16e80cef525b5779815f98eea9460a6e356d0063-8K/J,Ȩ9 A+5PKfN{I*16f3408c2b94f69e37175b464c942070f2ef8422-7K/J,Ȩ..)LP&<4IjkPK$dN"?+16fccf3223ca6091628fe8a00d1be594545f527c-42K/J,ȨNMMM13PK[eNYլ@+17111b2af2e216ce689f68d27e3bb5a865bf17e6-27K/J,Ȩurr CChZPKfN(3*1739d928e2d8e7509895231e1a940aa4a9e0ad15-2K/J,Ȩ$wZY[ PKۓeNI`D#(174cfba5b0feb7793b82dd1517525486ae700ec7s/J,ȨҤZ] kPK /bgN *175272db8fccbfb3af78d1be13608541e85c341b-3graph{}PKgN`L+*17528574b5315b6f0e49cb677833ec74e5041824-1K/J,Ȩvtr 3jZ8PKfN!+175ecc07c3a9db9f1277f2a34b09bf759604e4ed-35K/J,ȨNɌZsjkPK&dN߭V#+17606203fdca2242617fe7476b00e0211feab82b-42s/J,Ȩ.MrnHZPKt$cN?7+1765170d9359e66f22957994b1381699a98a57ff-43K/J,Ȩ0Fmm-F&PKfN 8+1767d43d95d5acd192fc0edc462392ad77c6a92d-14K/J,Ȩ @PKt#eN}U#+176ed342ed537f6096d2de93c704cb95ddaf723e-23K/J,ȨOb( PK+bgNԍ*17b2068dc2e99db075b191c14322238db3c38db3-2K/J,ȨN@]S PK;gN 7(17c2b113c5c04b620a1b2c19a5d34e7b935b575fK/J,ȨN/EƵEP1L PKfNƛ@*17ccc4f56f6362eb6dd60abe04595c1cc9e7812b-2K/J,Ȩ.MrwFj!;EBPK:bNx+e!+17ce8b02865a13849666cb5cf4bce99c01e12a33-37s/J,Ȩ.MJ/PBPKaNU./+1801adb8353cd6acff6c6477cea24ecfe9143f51-17K/J,Ȩvtw`PKaN`Kd(180395a8d6b0fda878653a7ee4913b7567ee2d64%1 ṷ0̰W2BԄa!xw}-چ9[u.9*-V)8!]Q Һ@=1'OZlNqؒqLlø~PKϵdNA_E+1819ef4add7add0ddeab2ad71daf09bf0991d4fa-23K/J,ȨNt/H,(W,P PK*eN+1820e1ea0edd161100ef1b138b578092d585a583-18K/J,ȨZQ0\ PKnbN"5+182376197b7a0b08db1c10f845fab4a03c7a0fed-37K/J,Ȩ.)LNRZPKIeN&sJ;*182de0535599f29844a86cee85379b968e925619-4K/J,Ȩ.Mr/*E1aZ PKfN*1835489cd4a3c82d9903178bd334e65c22ac0ac4-8K/J,Ȩ9tlgW PKӣbNg3+183852bd240f52cf1e0edb0c37edb4fb9c4b47ba-35K/J,Ȩ..MJҥ`PKfgN~- "*18625b0961cdb820968694be2ef392112b30d580-1KL/J,ȨNαTPP\ @`[ PKcNLO+1872616963d1911bcd0db4eb15a575ce802f89bc-36K/J,ȨL 3Jù0LQPKAeN V(+1877379e20a49531f10d60bd84c488e7d9b78bc7-28K/J,Ȩv|k?еFPK*dNoI.{+187a1322c3eb2eb155cf5170d9af0453dfabd6c7-28K/J,ȨV.0~b2k IcQ 3ZPK:neNpwA*187bd7dd4c807ee1330584da92b1efdfbc0882e1-9s/J,Ȩѱ0FPKOdN]6(+1895260fe3534189670f1d8321177a76d01d965d-17K/J,ȨNt2jPK  9eNyĻ*18c92f34d66af458f1f5d1f45b3b2ca076225205-4graph{_[f=DiGr_]}PK)gNN!1c*18ce152d29176c300d7f4409a3010db7a4f16239-2K/J,Ȩ.37v0 0.6 1LB,=-kJ"S[ PK6aNL+18eb245296e507b512fb335b5366f074bc1411fa-23K/J,ȨvuZPK/eN+18ecbb35ea593c4d863972e8407bb7100fd84115-19K/J,ȨZQ@PKfNN(1902fe8f3d4c9a54ebc3ac1f7203568becb64ec0K/J,Ȩ$Z(U[ PK5eN{%Q3+1905aeedef9f6d3e3891e0b0ee9e98c91fa9106d-11K/J,ȨvL/U@6PK=gNS+*191bf0afcb4def34e947fc66e592a3c12093944f-1K/J,ȨNt2kq2RjkPKweN2:(1939f3440b23a415ca64ea403dbb7ee25fcb98b6s/J,ȨvtPPK AbNu+193dc4ae851d56301cb98b250d8a076d92a1d05c-39graph{{ea""ea}}PK%eN)*193df346dd544f59540be4c2a23d5c63620f0699-2K/J,Ȩ@T PK7aNX)+1984403f72502a6a2977c8f0302b92426ca2d318-12K/J,ȨZlD-PKaN +199d71c190684b2d7f4be300b711ddcc80c57035-22K/J,Ȩvr`PKaN?*&-*19c7073143a806080aae879f471d3a671a800806-7K/J,Ȩ D`ԂPK KdNF +19ce672e1a2359c5b4bdc540b96e0b3c433df5bd-34graph{SUBG_}PKkeN@*19dee813d1d5247cc03719d5fb9d8d82291dc6b3-8s/J,ȨѱPKfN&/+19e906dd72c0d17160663f674412fa3a4094e62e-19K/J,ȨCF`>Pmm-PK*bNE7!+19f0bf58b0730d36147df5a74bcb9688d3cf6874-30K/J,ȨvL/ʨ(ZPKfNh'/*19faf852d322d1fc2de83cb1f203a94c2b8651a4-2K/J,Ȩ CPKdcN@79+19fba322718a52942db13560a6be7e09560dd82f-35K/J,Ȩ..)ʨQ)@PK ɞaN)N +1a10595e8966529a96baed2df445ff4218004157-11graph{{GrΩ}}PKDeN *1a144fbdc662b06d4b34d2300e6787b34b592090-3K/J,Ȩ.Mr/Jt2BkkPK,bNV+1a25e9f2170d3f257501d71151e44377de1b9005-38K/J,ȨԔtZ U PKv3bN+1a262176ad9620ba6baa443cc2f26aa1b84ffee8-33K/J,Ȩ"ZR[[ PK]-eNu*+1a5e986cd76e39eb62b372ecd6e8074ed51a73a4-12K/J,Ȩvz1}2Dj!$PK ׀fN(1a685613f21d457f1c2a34e10b93187546a0a369graph{b5_tF3_mZ7_8QQ6_1Z9JF3SU}PK{dNuO+1a80c584e9f2a98bb3adbb54aed725fb8fb0e968-27K/J,ȨVQc kPK7neNXϽ?#+1aa661e11a2f64bbf7e79d41be7c4e03bb666155-12K/J,Ȩx0Q pPKaNcf+1aa7b96174fe9a253c90bf34190a3cba6deba8a3-15K/J,ȨvT[[ &jPKaNk+1aa7c4304ac29336a8176f43b5bc93164b155de5-23K/J,ȨZPK aN0@ +1ab3ddf2c5315e8122e9c0538bc3231715feec4e-27graph{no}PK bNI+1aeadc5d2571de8fb527900845ade0eb80a1d35f-26K/J,Ȩ1ZPK VaNL *1af452af89cf3419b51f9cf0b1a4db9254449671-7graph{{GRAr}}PK gN^11*1b19b7914e4903fa0a4f0f31832336498fb61947-2K/J,ȨNt/J,R<PKQcN,(4+1b1a31e38af10cee0cf55651dd702dedf42fc2c0-31K/J,ȨLw 'NPK aNOA*1b2a5f733ec3ffa8e755b08ceb6daa7e45a408bb-7graph{{ed}}PK πfNE]g +1b3831a263f4d6231fa526a653eae3eece8f899c-43graph{{Sx}}PKaN (+1b440e3ae446382f1060cb6ef97d4604558b6228-16K/J,Ȩ #] PKMfNS~o#*1b60f2ecef0052914f30169e5d6768796804fd8a-7s/J,Ȩ..MJ2Z8PKIaNP !*1b6d08bd07b813f6b6036e9f15a279e84fb3d39b-6K/J,Ȩ7bS$ڴLPKaN,*1b8bd80e680ae7c163c9886b2c6a71dc457f4f2c-2KL/J,ȨյPKCeN+1ba8b36419d8b986e38d1396e2b564ebbbdf4bcc-21K/J,Ȩ..Mzg5PKSeNS1[U+1bab58c4d7c28c92846f64fadc2a52910d020f7e-25K/J,Ȩ..Mz'] hPPKTcNIp+1bd312275106f088fc15d2e18f1e821ce2a8a497-30K/J,Ȩvt/JSPKHdNyH-+1c1292bcf74c4df5e0548c21b8b27fa423aad1f3-12K/J,ȨNL6 AkkPKaNS+1c16dfb7ba46eeb524d3f8b20b473e9caa9142e1-14K/J,Ȩѷ!]ZPK;SeNM9+1c1b5ef35987a5bec8e7f504f340a4572b583025-16s/J,Ȩvtp&&‚PK0,gN xr,+1c3167ddb426005b4660ed4ccfaa32a1a2bc8fec-21K/J,ȨZ "jaZPKe;bN+'+1c482a1e07452ef8d947c4b708c439ef89e4005a-30K/J,ȨvMIGE!P PK=gN36T*1c61be7249d84f33f0e70698d609d1036a7a0e5c-1K/J,ȨNt2rjZPKdNa++1c6d82b90aefc1fa1c4968d1f40bb78b6f0b377e-29K/J,ȨVQŽZPKaN5,$+1c7bb3ade31de51e3344dff44d77627cf9c18481-11K/J,Ȩ..Mr3,PK}eNLPKgN%=(1d3f8738a0ab8dbc886f408e18ae3b3fa9eb6938K/J,ȨO)NT" +)!jPK8%gN>graߍ}PKZaNF/v+1db3adafa6724dd83818a48cafb73063ba26eb11-14K/J,Ȩv/*ѷ"(#&ĮPK 2dNޒ%+1dd5d648e15985333767eac2a548c6463b7776ad-31K/J,ȨVzqL BPKKaN9+1de0f45f86c9464f5c54d3ad3bad92c017fbda53-22K/J,ȨZ cPKaNo@+1de6ef4fa1cffc00dbf6e42e32c220ed3d313b18-15K/J,ȨvtPK fN+1dff3745765614c286cce87372f7836222c98299-10graph{{subGrap_}}PKۢaNb(*1e081348ae783225212b0c79f132684f713b530e-9K/J,ȨwPKS,gN!++(1e15cb14c92b25e4bc05d334a314fab73ff343d9K/J,ȨZ0 @įAHTI0F3 PKfNHs!+1e3eeef2415c3db6a60588009f4e956848c11623-10K/J,ȨvL7P&PK fN88*1e46fb489b6031649c3a76ae35266dd4d9153df7-3graph{<<34694469519536141888238489627838134765625ΩΩ>>}PK 2aN{2*1e49a85d2133157ee7e0b2ab8c60970b00b3c3d1-4graph{{Ed}Edd""Ed}PKufNu*1e70b2e8fb29566f6f7f6d5c18641da30321a583-8K/J,Ȩya-:PK 4aN;+1e8813370d7e4fe15723ca6816fc1be0d393dd17-10graph{"\"\\￿"}PKcN+1e8b2aaa50850f7cb208f74986f5c67e6ceed8d1-32K/J,Ȩ..)ʄPKfNhSL*1e8fec9971f2914fef0b74fe6799a9bee8856b66-5K/J,ȨEL TPK ReN=,*1ea272e0c81658342c8489cf4977d3a713ac81b5-9K/J,Ȩv/X PK}>bN+ u+1ea6a1190dc808a6a881bfdbc70abf061cbc9a6c-30K/J,ȨNMI?RPKbbN"+1ea899f05a8d0edc74c119fa76d8da6901e2dc7c-21K/J,Ȩ=LPKtdN F!+1eb1cec036e42f03935a832eabd1bb92135bd721-22K/J,ȨVr{5g[Y e*PKՃfN-*1ec2368979c0664c9f0af482128f4d06922c9148-3K/J,Ȩ 9`]-PK cNE3)+1ee689b2bba8bf33a12c77590c8b9bd9e37e41d8-35K/J,ȨNMIO "D"PKܲdN>0ʻ+1ee89c310f393de295eeb56a16764e52e9cb8623-21K/J,Ȩurr43jPK dN(] *1eeb3051a564f75785f14cac893f15fcf3fe0c94-8graph{No0}PK ngN&qB*1ef9cbf9fc7a71c99523130c9d09701b92cbbe84-4graph{e[l=]}PK>gN P4*1efcbc063101f9d6e92f2d06aaad4836a9f9e632-3K/J,ȨP'Y[ &jjH` b>OP` "PKaNa6*+1f27b16ed526465c40e54db9f020275e7a7a8182-13K/J,Ȩה"PZ(PK@1bNy6K+1f3638ebb644a9b908658f9b88c1bdec34969a5f-39K/J,Ȩյ4LCA-@XPKj bNU+1f3b51471e22ce3a7f0203d4d8241dac19f068cd-35K/J,ȨյPKheNz0+1f425398416b836230c9bc00f2b8f62c61c4f1f7-27K/J,ȨvubS !jPK]eNf6*1f4285dd3d0fade4153d18e337087f7349e465a4-7K/J,Ȩ$Z("n- PK#5cNɗ,+1f54b3db66d76cf442b7d5c480fe5b7de7e60f11-30K/J,Ȩvt/JPKaNYٕ$3*1f658d1ba679a03c1ba479ac7b5ff3286f107053-4K/J,Ȩըtj-VPKaN-p*1f66e925d864c7c142179e5f8414dff5980e9b4c-9K/J,ȨvPKY,bNX¢#+1fa5776d7fd1773f8d61682881ade63107caf19e-40K/J,ȨZ0Q gPKEaN"+1faab49d0f28ca01e6c7f78e340327694fe0e18e-22K/J,ȨOy-PK(bN'{N#+1fbd42c0f6facb9db01a77a8e4ae58f523a2c089-36K/J,Ȩ EfPKPeNg@m'*1fbf68be35d57f1ef2a791c2526fddbc7584aadc-3mK DO " W7R4һ7 \<^qBד׳"ß BmRU2بarɨ8y 0y?PKaNܥ\,*1fcc8c9f08f57018cbadb3c9685ede7e20d452c7-9K/J,ȨNL/2`6 sjPKaN{;GD+20004ea24c9ac98bb3ffceefbae9adfb6ec26048-12K/J,ȨNL/*R@*M PK dN0+2006ade66a56ccc1f07b3bd6298152af93a005e7-19graph{{SUBGRAP_}}PK\EgNF&O*200e369d536a8e18dcd58f5977a25d2b7177e928-3K/J,Ȩ..Mk)bPK3bN[Y]+2011b863dfb9a5ef665875b5f0e61fb091bb85c5-40K/J,ȨF-E]O-PK JaNמ$ +2040982c182909aa15999e07eac5e33318573d55-13graph{Gra뿿}PKaNX A(204c74887b81112cb3aac65399847ea0ac96bdebKL/J,P(.)*ѩ):Xv RPK Y eN"\+2053ac4db3c61c7fcf53cce7dd2aab2bbebe5708-13graph{{di}}PKƴdN+205f018526cb5f6eac53089dd071964358cfd779-22K/J,ȨurrRPKQbN,@+208be04cd597d19a8abe0508028bdb2f5c396f81-23K/J,Ȩ PKKaN)+20b1d226f1bd7645c02daeb55306d047e1d0a48a-14K/J,Ȩ..MJ "Y[ PKaN ~n+20c0c1119fc8527f0933636e6b96f220fcc3df76-15K/J,Ȩ.Mb(^ PKSdNsi*20cb14d623606ad9ba57c6f17028ea1733047490-2]K 0 DO{qQ"mvMRbwa2>jNm[8b1O50kjRɐE ( KFT;$/LðyPKkdNEl(b+20d2d34eaaf721bb09c6cf9868f38e9dcf2ed062-40K/J,Ȩ jkAPKqbNO+20d5755ae266f4ff6336f166a07a430e7bf6aee8-31K/J,ȨvɌ@ kPKReN;3-+20de79cd8fee7592148ba5aa02976d90ca222cd5-24K/J,Ȩ..Mz'ҵ0JPK 2cN~L+20f17b18616c4166edfeb1b423510ec7e824af9f-29K/J,Ȩvt/`PKGaNZ v+20f7627bc09a6da3af707ed8349c65d6fd682bab-21K/J,Ȩ..Mr`PKF4eN`gG?+20fa4dbed4ccf6f90ef5d808bb1a2cb2bc50af79-13K/J,Ȩvz1}2RP" PK aN +2100f83e1d56b9cd204ba381e823e3301bb220ba-26graph{Edga}PKS;bNP3+210b7fc36f51bf42c63d09590f87d1687a607c4d-31K/J,ȨvPF-qQ)PK  aN#m +21139c99cf5ede2ee961cc799a20442b06180a88-10graph{GRA￿}PK JdN,*UFٽ&:1X~~^=gZBJX抎TIK W4ҕW@9*]s0X9k77"u,zv3oC;<PKeNW++22324a8b00f797ed45f31a8d75eac633d65c46f7-27K/J,ȨWwY[ "2PK fN(p*2242b3cb7c6975b2104c7e05dc06dacd56144044-3Graph{{SubGr4}}PK)eNV%')+22488def22c2d7f594c9a4097375c4a11de72ee7-17K/J,Ȩ" PK`fN)iD'*225e86a4f884fdc5eaadc7554bc7375f47aa6b33-1K/J,ȨL ӲLB(j(PKAgNvJ*22cb4c227e3b26ff7e5b9945c0d113d1023e8f72-4K/J,ȨNt2r0յVA- CEPKLgN-N *22efa2d36d96e5eb782753602c37e5405cb2c4bf-1K/J,ȨN1k!I5PK eNv9+22f246ae18c4927008c56c09e95f435272363b58-27K/J,ȨurЦ08PKHeN:H@//*22f5822051663b22001cd8274292db6f8b39a839-8K/J,ȨNt/JPJJ8jPKIgNYDŽ=(231b8246190d2a15ff3a11e9cf281a88a7fa5005s/J,Ȩ..MJ/JZZX-PK%eNw+*23218b75bba278a27701ea5c1434b13aa60d5cb2-9K/J,Ȩvz1}2PK LfNפ$+2328509dd9c8041d7ea90db1a1471d0f2fda0d77-22graph{"\#I\I3"}PKbbNR+2339042f8c1f8097a3131f20c8e3bd115c072252-40K/J,Ȩ.5@PK JdN>B[s66*233e5adae535543b70c834634d4bc198dedd7cbe-2graph{{" "#1387778780781445675529539585113525390625 }}PK+bN@E%+2363c483d257da4ba4f9d58fc42192ee6f984aeb-31K/J,ȨҤBBYKPK aN-;,,*237a785429f82a8937b1b9f3c6ab218aee860584-2graph{<< astx.AppendAttrList(X[0], X[2]) >>}PK KaNs+2390e843da23668d4d09c8d779763cc84cb69e5a-11graph{Subgr}PK bgN< *23abe864080c32e2cda61eec5b2c6ad66b60e267-5graph{di}PKaN7x+23c5a90e5b9621a119c3b5a4a037344a6cb0fc13-23K/J,Ȩ..MJ/SPK *bNi!++2405f39fd0499603e2e94dbbaefdbe51d7dfe73b-38K/J,Ȩ⒠Z0PKǤaNE1+240aa41760f04408fbe8a1848e925459c7c8c61e-25K/J,Ȩvuq/XpPKdNޫ-+240e3e5fb667b2b711640123e9a46284130e4ea1-40K/J,PHMɩNM)P:PKjeN]d)*2412e51ba5cd28202960eaebb9ce0ff45b41324c-4K/J,ȨZ P6 PK JdN* +241941e5de27a6cd24baab9bea6346fd33557099-31graph{strA}PKfN&++242b1496b633d010f6ed901fb5785067578ff15c-10s/J,Ȩ9@4CkPKebNЁt+2437b0e0aec554737ed5bf5697ae61e7cfabe5a3-27K/J,Ȩ. Z] PK FaN-*243c629c62a05753a25a1090de7ad207b6aabd86-3graph{EdO""EdP}PK9gN5*244333f4d9ca7592508ee8d18a4e74c4238b6b08-7K/J,ȨvMIOFT-*PK ΀fNjtc +244b60b45d5a4552a0777d090c0823afb7eece0f-18graph{{dy}}PK=fNs"*2451ca6f47dd38b4c3f70fc31165f7e63c869f1b-9K/J,Ȩ9~,ήPKlgN:l*2458eeef66bf85473261bcf9f88f34088a7bf10b-9K/J,ȨδURT[@|m-PK\fNAKW*245e23fdac1aab58adf7946cc75032ebc5ae5417-4 0 ` e*(-b,:]qwu>:e8 &dPp &+KM.slYPKqdN/tK+2463f98d5c5218cf793355bf44f6db0355dcadab-24K/J,ȨV(PKdN Se!+24681a114f61421373ea99ad1cb529221813034a-27K/J,ȨLKBPKfN"5M*2479fdc5a37d9bc90accbf06b1f9c53679d4ddc3-8s/J,ȨҤZT **IhPK=bN!f1+249e49a76ebd2d9e1faa4eea5c7ea2f791c83f98-34K/J,Ȩv2`T-E(PK dN,Y+24a1c30bb7400ef435b10e176936e84ed7f98505-24graph{{{DiGrap￿}}}PK*cN3+24b3d45ce6e1b21afdc523383268707deb5950d7-29K/J,Ȩ10\,P õPKNaN :*24b632d6ab94a973f1a897616110637fb209d20c-7K/J,ȨZZPK!gN)+2535b1e9ae3ad6e63025eb47234dec9b899c2918-36K/J,ȨvuSHm-PKBaNԔ3+253d0b1c8731049af15a4421f02202d8296f82a7-11K/J,Ȩvr|wo-RPPK dNG+254b1d8d340fc0612e3ef55dfe06b61caf92a280-15graph{SUBG￿}PKbN0+255d90d2ef8bd98e907a667ffe560d4a6bc4210f-23K/J,Ȩ rHLPK0bNl+25668bbc20b1b2be1771e7346eeed8b4d771c827-30K/J,ȨvMIPPKfN]~*$%+25678eb4af666b4bc9d950faa1d7d9efb281d82d-36K/J,ȨVVBJ1)J \[ &PK ԬfN+256fc63c93d08a2f04ddc50bd485af7477bcaa96-29graph{{{diGrp}}}PKWYfNGd2*257bdadf6c30b99cdead0c4a527015516db03130-1K/J,Ȩurr EbPKQfN)*25a97e6af8928c45ba92960b75bb21056b71bf96-1K/J,Ȩ..M PK ܂fNV1 *25b10005f05d36a346a4ee92d8be623d7778419e-3graph{<<Ω>>}PKfNm+25bcf7adeb36d93f2ae11a66de24009e111fe3fe-18K/J,ȨZ0PKaNcsU/j(25c6149582ac80ad13e4c4f89d1ae7b1833369dbKL/J,PN-.A]x@R5gk] @H2B PKybN/-+25ee9cfb223550596598247d4262749c83d219cb-41K/J,Ȩ.)LP-PK 9aN_^ *25f6b472544d6654a0620a6c3b7d68d8f451b6b4-4graph{NOȞ}PKYeN43/*263d425f6c75f9635cbd6c8d37c018d737f5f4a0-3K/J,Ȩ$Z0\[ a`PK fN~g%*264904e8d8daa8e247c894a98a3ea032335d1c8d-7K/J,ȨN/2M/20a\ PK fNO*2675a61a7f2fd2172954c35e8861896b06ccae9d-2graph{{sq sq}}PKɥaNS\x+267b0d59a590e1aabc3419af65a89f1dd61e90a4-22K/J,Ȩ..5PKNgN޷@/*26b7f75738c8dfebcdb86c7459e17dad4e5bb46d-1K/J,ȨNL/PZJPKEaN5ի!+26b98e7e7c654125899d868d05d22a41db190949-15K/J,ȨvrtNHl PKUaNeV+26d0563e74f4b713e9b99b156ffcaed6f66c67de-14K/J,ȨւH0 PKZfN~`I*26ef45df28adaa7123c3bc684506f24ac1370171-6s/J,Ȩ..MJ2kZPKNeNk4V/*26fdae67e6042a9d1a6a800740e9e4d48553b6cf-3K/J,ȨvL/2\PK2gN>+270d581eebe1927e2a9a00c7b54c296eccfd696c-36K/J,ȨVR†kPKdN +272010485670a7e6e5d5ca131cf5494a68edf475-17K/J,ȨNt/JP BPK KdNQ= +272c898513953e6f497294fb319470ff596662fc-50graph{{DiG_}}PK@dN~`+2732bc6ce54e8b1f2f373a86762fe577c6813465-14K/J,Ȩ..)ʬV-PK|eNqz!+27354de44fbc8fcf99e08401e83295c7e0360403-42K/J,Ȩյ ®PPKMJdN\K+2751ca01df5d6bf879597628a305eba6b15bb537-15K/J,ȨPKxVeNT-](2765d8f3b623fec0e9a863feb05b6ef680681e14K/J,ȨWwZQ][[[b"h , BuAH0 !PKbN1+27673647dd0ef0972209c3917444a4be81051ef5-23K/J,Ȩ 2PKҌfN%"+27b09b0924ec428af50f6a0f50d782896247b467-10K/J,ȨЫԃP PKgN)t#+27bf1fcccf19fed31a3a2fd0db3eaacb1432452a-14K/J,ȨZ^ $R PKrcNM%*H+27c2ad488070b595d933ce3490bcc3c0957b53d5-36K/J,Ȩ..)̨2PKdN;+27c9d1e7ee471d56e575ce2096df0ebac807ef8b-17K/J,ȨOy?PK &|aNf[ (27f57b897388cfd3c59e59dc148490915b1d9deddigraph{B C}PKEcNT '+280365b21e2454d2874c10eadf3401a37fd997ba-37K/J,ȨvtF`G0kPKKcNS)+28094dc665f9e3d4a6cfec1a5655b4a4bf9d592a-40K/J,Ȩ"jkk݋,jaPK!JcN+2830f7a4bc71a44e5414f188d80a7c63cef088ee-30K/J,Ȩvt/J SPKrbNIx+285711a70cc3df32b5e1c0a3501364b930565f48-39K/J,Ȩ.)L`PKMgN|r-(285e7279a63ca5b2258d17af8b458c82ccb68930K/J,Ȩ tPPKaN++2865ec34b5d2fcbb887e054deb0f86c4216665ea-20s/J,Ȩvuqw$PKgNF+287ae6cbc935c27366b8b7802ce809631c125765-34K/J,ȨVRZPK vv9JJyv`V]U PK4ggN+Mo *2a8a94598241109c0bd06a2a581a0df4469c14eb-3K/J,Ȩ.M1jPK 9dN@i*2a8b6b99bdb77c6a2bd5bc7184880ae3c4ca464f-7graph{Digra藓}PKfNŢ*2a936a078582fea47c7aa6a7c6317ae86a9a9707-5s/J,ȨҤZ(PK'aNa&+2ab3eafd4e7047b76f0d2ffc93ae8cdc93cd844b-13K/J,Ȩ..Mr/Jt1Sm-PKbN{Y++2ae5ec6ea803e1868c1fcc0824608c406699f7bd-25K/J,Ȩ 2`&PKeN]=+2b176ce2e573ba1532096d6951907bfa60c5bb8b-18K/J,Ȩur/\PPKLbN,4+2b291f94d3f68b790c46ba2b535a3c3a3d75045f-22K/J,Ȩ b0] PKveN^5*2b2c162946e6b90463af9d0952abdaac2eeff8a6-3K/J,Ȩ..)LP0+PKsWgN\+2b3c1f10e5d5344bc22e0d11839074e1353bce84-23K/J,ȨOZ$PKgN{`D)(2b57eb71c0b3fbeb5f53a7344a4bb318fb3ab466K/J,ȨNt2k1ڼPKPfN+, !+2b620415c33760cf2030e44480689bfcd8da537e-19K/J,ȨOUkkPK haN16W *2b6328e94d03f54e21c1ea53fe470e7b263b0a89-2graph{_у}PK4aN~<^+2bbcf4c3e462c6fab7a3745a00c58ff514dfc934-14K/J,Ȩvr x?PK;MeNPLA*2bd4e7f2ef05f0ac5e2baf08bd1fbd9df67fc7b8-5K/J,Ȩ.MrE"$0"\] PK0KgN4I3(2be0b54e5666116112f5b62d596570070c146b8cK/J,Ȩ$w ;dPK hfNI5[+2becec8af4175be9e0596df830fb4ed95ddae258-36K/J,Ȩb02Ga90+ PK VdN1*2bf50d9300284ab690a4de1ad670478203e9d840-8graph{{{diGr}}}PKbN,(+2c2125dda8735f5e7c202f1e360a5f3d1a0bdb0a-38s/J,Ȩ.MJ/T-PKpaN8+2c3fdd37dcb3f067d763b3734cc8946db65318b1-14K/J,ȨvtZPKaNsu!+2c4723c3a410e64a44146acd7e0113bf0deee898-15K/J,ȨvtZPKdNI$#+2c49fe39e5e88085fc99095f9a6f7768a6ab0157-28K/J,ȨVQBJpv-PKGbN׫+2c585d5595e5d72fc60e4feaa09f077e6a1519a9-34K/J,Ȩ.)LNԵӵPK aN|+2c93b402a8ed7c4dac3a466b19ef297d2d19e78b-16graph{Gra{}GrA}PK-seNrhi,-(2cad460e1141f90ba28e092d5f3bbc41e1a15613K/J,Ȩwxxxx PK aN+[ *2cd57eca48b2e2f8971b42341a9839eb1e55d542-4graph{Grap}PK aN~Q*2cf20db9e96d09c5e684d4249ff9ab34faf5d159-6graph{di{di GG}}PK aN>ژ(2d1f052904c8a686d317d8336516554c9743f370digraph{A->B C} PKVaN*2d2e4cab5e633809d957211a3513c8994c8c5f66-7K/J,Ȩv2aPK jgNoTl *2d360c53aa4badb2313527bf083bc2503789b7e5-6graph{{digu}}PKIgN`j*2d5a6b86cce0e43694a13341ccfff11868f0fddf-1K/J,Ȩvtrtѵ0[*4Q PKXaN{D0+2d73f235585cf987ce66fb152f46bac6421d54b1-16K/J,ȨPK[bN^꼱5+2d803cde902f21d838349b0594357c8bbf996e30-34s/J,Ȩ.MJ/J2jq BPKbfN&((2d8214b431487d4712047a4587d02192885c566eK/J,Ȩ.MrwP`2 PK #eN*2db662c9188eaca0267103ee866e72201c2f70ce-8graph{DIGRA藓}PK aN;x +2dd0199dc9bb42eb4464d07048ebbea12a628a4d-20graph{Nn{Nn}}PKbNi-#!+2dd3d4f23415aa7a8e9ca4ea8b387cfdea04ff50-29K/J,Ȩ $PKHgNS*2decd5a1a2352166e70ddd36b2019f27cb37bc7d-4K/J,Ȩ..ZkPKZeN* '+2dfecc70d59bb969a544d275e17ecffbb0350344-26K/J,Ȩurr CCkkPKffN+4+2e014c8bc0fc67a729ae5563a5ef2bf0ebf092ef-36K/J,ȨurPPKffNy%+2e060e0452bf0a458d6d0f31fb40fd6bc351331d-10K/J,Ȩwy=R0PK gN@G(*2e0aa280ca1329190e65e719d7d1d98fed97b54a-7K/J,Ȩ.BN a«PK vaNГ*2e125f36c294c2b7989b051bfd4589201f7a1ed3-7graph{{d3{d9}}}PKfNλg+2e2bdde158a587db191ccdb7b0b8396b8e3f93b5-33K/J,P33R@PK JdNn +2e46f7e908fba4e95b09cd3aac50444658695ba5-20graph{Grapu}PKgN\0*2e47e01ba057740ef7df888a1be58552aa1aec05-1K/J,Ȩvtr H1*kZPKaNH%*2e4f5a922a5ed174344091d2767560c42fcd3bef-6K/J,Ȩ^`2PKeN3!+2e509a0ca88497d95f537765f1545438cc103237-26K/J,Ȩv|k5PPKF[eNoľ*2e962d0ccd62cbd1dfdf679f968e12cbf67c6336-5K/J,Ȩ$Z\ PK dN;- *2e98dc06379871dd989f746dccd545b74c52f9b3-8graph{Né}PK7dN^ ++2e9e37a4758ed734279929ddce5ea4495b105c58-23K/J,ȨV!jPK\cN1+2ededde7d91a7dce8f877b07203b06e8308a9c62-35K/J,Ȩ..)D%12k!PKcN*+2efdeee8db27639ea8b18ce3a8544b6b92dddbd4-42K/J,Ȩ.MJE&kPK0fNbU?)+2f0447434a1e68ed41dc4e2d645a0b0890b50f76-10K/J,Ȩ3Z FPKѝaN^*2f1256907aa5eb8ed3f21a8f6849e5255a1b886c-2KL/J,PvMSRŵPK WdN]~ +2f15f1157bb2afbc08c33d15ecb4f6a8791cab57-15graph{SUBGR7}PK5feNQe&+2f183a48460064a4f2bec953e706db4712840296-14K/J,Ȩ..y`?|-] PK aNdJ *2f19d675ddeea2e9f02b1921a4c11db6e4c1f626-6graph{NODA}PK bN+2f1af6f7bba2343318019552912022133c8bca54-23K/J,Ȩ.MJ`PKNeN5+2f1c64596078cc42e1bdb306f053aa535d24d534-20K/J,ȨNtd-PKmgN .*2f1fdad013839d639787200567cdcbc3a9ef948d-3KL/J,ȨNαq!%$v]l-PK qagN:\*2f22e9f5c09dbbcf5bb65e7f5578e78fb4a20b19-1digraph{e[l=<<=>>]}PK aNvf*2f24e82980fb22f91e0fbad3f2f632a774ffbc71-2graph{SubGrapL}PK aNLד8+2f26fd0ccce582ca413ab0a9a91d3598802caf5b-12graph{{DIGRA}}PKUgN%Z*2f595c4fe18c0542add2f3af45c77dca3bd20ac7-4K/J,Ȩ.Mr/Jǀ3bPKRfNo^-(*2f75f0c6d974810b39aeab2fbab2506d400f9fe5-3s/J,Ȩ..MJ/2ѵPK dNV *2f779dd50396145abc1320b067a3fdef413d4d30-9graph{SU￿}PKcgNip(2fb735feab3725e447c45c47268cec80494a9d28 ; F-*' 8t(RPy X}p&z 7#ta)Z SsW;8 ױʨn)Lڪ#l ?em?PKfNS5+2fc0541b37063b7e3952d1114363da8f5f5219ee-19K/J,Ȩ`d26868"p~-PKRgN#8+*2fc3436cd2153c7c81486d5609743138962ecf1a-2K/J,Ȩ.Mr/JèPK^fN)>*2fc48e00922eafb82920b78edcf4e89b2737da37-4K/J,Ȩurr H3SkkPK aN9'(2fca07ef9d1df28253f41b0ae02db773f4ba1b37graph{A[e=d,r=d;r=e]} PK|bN?Jz+2fd4fd7a0e64994f5ad0ce7fedd2e53a6eb8f527-29K/J,ȨZFjPKaNd+2fd5fab1d62501a2004494534c21c23d7d365601-15K/J,Ȩvr x{?޷PK PfNr*2febabe56d13af0a1c3dcafb4c8b11eb17106532-7graph{strict5}PKBaN$(+2ffa679c2c88732851b22becb0ff34e9d59d4dcf-20K/J,Ȩ..MrwR 2†RPK)#gN =a*300cc5af112dce89fd65dc0bde28682523596e25-3K/J,ȨVRR UR7777,OL̲(7 t77, 6-5 1J* 0w7rt(b)9PlhPK@aN+3+301200716caded772692f9d86f90185e47f3ebd6-27K/J,ȨvMIPKEfNȦ %*30165e26edd5d70f7faf0bd995f51b88002cd8de-2K/J,Ȩ..M1KZ8PKifN1*304075f2142f0915edbeaeb35e875b0eb5a97582-7K/J,ȨҤL0\[ " djPKSeN-O3+3059ec161b11c8e71b41dea4911815554be1a5ec-21K/J,Ȩurr,ЉPK]fNS2(3067816ada1e8c2b55018835934f654f27af538e%@DI.5@.p\$ `g t'RQ #"Š* ݗǰO9KGp+"$Xm˼Ayzkٿ"g+F3s[lgmmpĝ7<{׭K]J*.м8"t`ƍCˎBk;l*PK8bNC+30765a62bfe8523b5b65edc6d4db4c062f4f44b0-32K/J,Ȩv1ka4PKi+bN{8+3076ec6bff67a7b3cdfdab4dca1af49fbae228a1-39K/J,Ȩ⒠O8LBPKkfN|I(308ce243529c14784631384ea66a42442d5c087bK/J,Ȩurr 03jX6PKJeNq#+309e3623a19576d3c49cd9d799c97bff9bd7018a-25K/J,Ȩ..MZ©PKaNaVq*30a113bc958ef0cdf73b57f0a88720d6a2fe2543-6K/J,ȨNt/ PKaNWx *30a7521d02bd4f053119972be35a1b1e0b92e75b-2K/J,ȨPPKfeNNU=(30bf715671c01a27b25251b4182d09cfaea5a5c8K/J,Ȩ.Mr/(Z"ccPK>gN+*30c0b268324c870b436df1a88d0f4564df0b0876-2K/J,ȨNt2rZ(PKAfN~l*30f52ee25e26432b5366bb8d1b296cc43ab3bd59-1K/J,Ȩ..M1KZ PKlleNmw3*30fe2af11a7795b42b913863110ba175221a0008-8K/J,Ȩѱ պCiPKreN,2+3120db288036013e2a39ab904b360c17a8c7ba3b-13K/J,Ȩ~-jPKBdN豧I!+313540d36f3ba1a2c8fb05b7a785f8d15eaf6004-15K/J,Ȩ..)ZPK FaNUT? +314aef710e9693a4ea59f612c06eec992ddcd285-11graph{{DIG_}}PKCgN:%f*316f408feb54ba19492954a1a25cba4d78aba111-5K/J,ȨNt2r j.Q c/@PKweN+S*3170b03770d1971daf20101307020a08bd788d77-2K/J,Ȩ tҵ0>*Y Хa0PKrfNɹ .Y(3174f83306fb76b5e464fdd1d6f2e3d9f3061e06KL/J,PSEA 9J9 Jɶ %%@R,DLq ʁrɶpb %D]$("0$J] ZPKdNhP'+317b76bf859d7c47c6f025bad3150c623db5f6f9-22K/J,ȨNt/H,$PK;fNUɹ*318d5497b35eb977be54be89e81c375e47dd7ee8-8K/J,Ȩ3ZPKhfN>{R7*31901d75037759063cf7bdf94d09cc8d41b5a2d1-5s/J,Ȩ.MJ/28pF-PKBbNtY++31a624ade3106bb08dba9a39fe7d487e45fa0743-33K/J,ȨL 3JPK׼dNq"9+31dcaf08b498015361fa1d13555d42d5fe49c7ce-20K/J,Ȩvt?jkkPK 2aNJE+3208b3903df73e464f036e45862f26aaecb7e08c-18graph{{{EDGEG}}}PKfNK*320a95296993cecff04c193704de36ca251bc928-4K/J,ȨN,cLPK aN+aRR *320f0e4c6a1bfa3965ed4ae974aa9e92c2093819-4graph{Digrp}PK jgNR^*3210034a5335b092e73a5e1fa9b32ebfc6e36a5f-7graph{{edgeW}}PKtdN!S1+32152745c7cb49f040f71e3001d641af1397690b-25K/J,ȨVzw#:VPKwfN*321f5da6e90da60307ce5ce910242d4e793d4799-4K/J,ȨNL0\ PK NfN`*32234895a602a04791f461cdbc6277f62db70f2a-4graph{}PKaN.Z*3236470709830fac6e00a8b990d9512f55b6ea80-9K/J,ȨvtZ8PK3#eNW+3236f0f3cd099069d2e4eaee0924365478f49dd0-20K/J,Ȩ.M1`tm-PKaNe&+32511507d6b0a6e6e7d5c86b16ee8ee50c12674d-26K/J,ȨҤ$U jPK!bNf,+325c712701d233a1bd8e2dd006c4e54f2a13bb37-29K/J,Ȩ.)@\[ PKaN+32706d231cc0898d553eb553545c67fc73191f88-25K/J,Ȩvuuu3PKdN*32a7cf23d31f755b2b45190f7a91320842496a75-9K/J,ȨuPK KdN]'l +32ab0d66eb8e84236c47d67e8154e6d87dc392f8-21graph{SubGra}PKkgNbO*32c1cda892cefcf139eff76a9fed8138540628fa-7K/J,Ȩ..MyPK$bNxi%+32c5f0d2efdcfc999f6b3c679200aff35fdf2287-34K/J,Ȩ"Z0 e9!PK đfNG>1*32c8c013fb594bb7513659b1b9c910762c74c639-1graph{{Subg_}}PKeN µ+32e1e100fa98d68c5fdf09d94b9e8f29fdb549ec-43K/J,Ȩ.jPK fgNXB *32e99bffa0a6d1c0649de8eaeb897dad51e5d3c5-1digraph{e6s}PKaNJ*32ebd24355f6cc34fc016cfa1676a45cb8dedcf9-9K/J,ȨN-PK @cN{:+32f2331de2e358993ee9ec0595366727488dcd93-34graph{{GrG{}GrC}}PKV`fN1*331cd0d41effe69baad38079a51227e1a85cbf07-1KL/J,Ȩv*׵s**еPKCdN*334ef11e88e7c1e72f50156037e71e4ce670a876-38Ӌ 2kPKeNF;+335257cc8c05c86927eea3d73a08d5638019d14c-21K/J,ȨӵPKXaNs*336b873bb5c721fe5e02f047a8c9b95740977abe-9K/J,ȨN}-PKcNc+3382d781682e82eaefd622aff4fe5ef23a0bfe3e-18K/J,ȨVBc(VVPKjgfN܉/(339d9fe4ea7eefe68054b2cac6e285524e66b0ceK/J,Ȩ..M1KZL PK 3aNN+33c267548ac31a0757eba8e403332520dd3cd2e4-14graph sG{{sG}}PKKdN.+33c68f91179737bb55fb62380020be5c457885d3-50K/J,Ȩ..MkkPKaN+33d5ea2601ff4c989aede00ac0a64270ec3b1b18-16K/J,ȨהPKAQgN,S/(33fd512c0b5b193d8dbec57a100c47051ff3bca0s/J,Ȩ.Mr/2%DPK4bN6P+34234c0c586035ef0bf9557ee9200102bee34667-35K/J,ȨNMI0\ &DcJPK aNumQ+343d8a0696c0fb4fe5cdbffbdf17a46bab0208c9-10graph{{{g}g}}PKױeNx/(344a8127a0df9a5d1a0cda324d39e3fcd1583ff2K/J,Ȩ..)LѵPKeN`dD4+34ab99b645314668f214f020f6ec38fe02eb7f70-35K/J,ȨuZ*P PK bNg +34d8d0148dd7ba3e9e332ad40cafe6be6a69b0a2-20graph{SUΩ}PKd2gNf*34e1fe80ed7bc097728c47cd0eab1144ba2c1749-1s/J,ȨQѱ`BPKeNl+34ea67cdb2a055cccbd35d913fb13f876fc1e6b8-17K/J,Ȱ"jPKfN; J3+3516c5bbf827e6637e9d59a09594d1c1c0b6e236-13K/J,Ȩ..)ʌPxPK gN['+35341d09f94ae20f59ad5ebcdc996a827baaedfb-15K/J,ȨZ^ $R@PKfN+|(3539a2c813d9849808c9266eba040449607b5d00K/J,Ȩ..MEPK gNT(354657dfff8df2c237d7b4e0ad47c6c1aff2236cK/J,ȨL ӤFPKVcNF3+356533a9fe665f071d77aa53c8b94d35c35cef00-39K/J,Ȩva4EBPKbN +35907cee70a40394fe75e832bda198d7093fa0b5-29K/J,Ȩ..-ZPKKeNp,.+3590fbe7cdb56c1371a9e2911d16a1626fed0328-23K/J,ȨN/ `ٵPK #aNyŅ+35a4f4ef3914e8363d130f511159f2e2107589a4-27graph{subGra￿}PKSfNv<(35bf6166e94e2154d81eac17fa4059c956f3f8f4s/J,ȨvMZ "XjPKp-eNO ~{%+35ecc84536bfc3e3d95af448143498481fce8768-23K/J,ȨN.M2Z PKָfN!$sP+35fde9e8540cf97b21578fd11b4a953e3f414e0c-30K/J,Ȩ10\Ʈsp PK *eNr+3601d49a8a5aefd3db2a5b8929baf2da5afb30ce-19graph{stri￿}PK LbNp+3602b611d7ccbd85b9ae1bb66647d3b4bae73e69-22graph{{STN}STH}PKfN0,+3604d52ed1aec8de1539a4906ad0a77871f82bae-11K/J,Ȩ3Z F( PKTaNI!+3609461aa90ed33bb807d8dfb3097d6a443c2b55-20K/J,ȨRZ !PK=fNX,5K*3613bc3740ffc8268c44833c2ab8a25d79f80c36-8K/J,Ȩ3050207334461Cb[@!ssT!ZPK%+gN;&,*3626dab80f49efe0267c0f9fd01e7fd89f678db5-2K/J,ȨP' GZ4O-PKxaN߬gb++3637b3f4efa530279118aa9f4c5ba872b772639a-19K/J,Ȩ..Mr/Jj!tm-PKtfN I*3670645e0d3dc26f842360676fa2614ba4218046-5s/J,Ȩ..M*HZPKfNG+367fc73fa2eb68fabbd74350bdd603528b382767-33K/J,ȨVAZ#EPK aN\+3699e141aa931f519c7880e5feeddef94af23339-17Graph{{{EDGG}}}PK-dN++369cef041a3cfef4249ac80328bd31f7f9f2be41-29K/J,ȨVB1R-PKbNLI+36b463f4894723a421a9957204170039b0b03f4d-39K/J,ȨZ PK5bN +36e95701b5a2d1bb499b591ffa05b7ed50ef5a21-26K/J,Ȩ"(PKcNZA+36ef88cee1478e4d1cc066400b89333f52ffa813-20K/J,ȨV1 %dvm-PK fN"*3709361e44728701eb6b8e254232aa72be342c02-9K/J,Ȩ..)4P`nm-PK/dN- +3730d7353b34881730c7ac1467186caa793a77ee-10K/J,ȨuGPKLdNHi+37324f26e6c886a2bdd4846f2d825e1ed23dc65a-16K/J,ȨNt/JP PK bdN]e+3737e2fb3e2b47f40f38ecaf1f37e5b6bd28dbef-11graph{{grap}}PK]fN=)*374f7728a10c2c4c841f3fd3e04d792d2875acb5-3K/J,Ȩurr p3jkPK9eNf h*37544dac6d708320b5df49caca56a161e0c1e5fa-5K/J,ȨNNut/PK%gN͛(37631a97fd140db831909519eb0a090720ab728fK/J,ȨvM1F@Vmm-PK6aNi*3770ad2051cdaf3935dbd55189cdf12062b8c406-9K/J,ȨVQy? R-PK bN*(+378a5a880c4837c444bb2575466a6244762e26cf-21graph{{Sub1}Sub5}PK ̥aN+37913dae30aabf6067a46904b8967958ae83c798-17graph{{{EDGD}}}PK fgN *379ba90442ff773b1d69d558709b82adbbebe59f-4Graph{iФd}PK bN% +37a1b3c100d6d3054cf009d99f2531acb564a055-23graph{{STRIA}}PKmaNk3=+37be614e6696a9451054bebd2c5be93a82798083-19K/J,Ȩ$D]Q[ a֢ PK WaNP *37d7257c11261b947cad01ff28ec1fc671ddc7e4-8graph{{GRAス}}PK "eNy- +37d80e97bc35ef7e26fd7d75d5ba1483c54d2286-13graph{dig￿}PKgN[+*37eafffbf62024a6da8cc015bc749a8372c9c432-5K/J,Ȩ^Z^^^ LCIPK.cN,Jg-+37eb23e5bc71541aaf8f9ca0a6fb14f984e944f7-35K/J,Ȩ.)L6ҨTm-PK;5gNŷ6*3873c098a3c26b47419cd30e73c9edc69608d36d-4s/J,ȨQѱZ PKaNݏ*38803a3d290720e1385aece6f3f348eb0bd6ff1e-3K/J,ȨNLPK8bNuc++388855e72a1600932c51c1d3c864554d38b92230-32K/J,Ȩv2kTm-PK+gNnY'(388aaab3cb9259a73a873ee93ac34bda98be0ad8K/J,Ȩvt/JLhZPKfNE:S_+388c97035ac5f4202c890c7dcafeed89e16181cc-32K/J,ȨNL. v-PK.bNd-+3897d449c1fa7b64a41fa5cb04c848d9b542b366-32K/J,ȨҤaPKeNthQ*389ebf70d95a15e922817318392acaea95e89be7-2K/J,ȨvPBBy0BPK GaN5c+38bbc8d3271124a9519311ddae89ff9e691aedd0-28graph{subGra9}PKKdNGU++38e1c90521d30a8db8e5ed181846b2c47efea09d-21K/J,Ȩ.MZPKcN!+38e5e7740a7fcaa686b8b421f3f333911fa1d450-42K/J,ȨNMI7HւPK oagNӊH*38e5ee08056dbf5fa2b789cf7b181abd9ffdf19c-2graph{"\\"}PK}.gN: "(38e710db728e59a9cda8de902bdf243eaaf159ees/J,ȨҤZ] k0tP]?P1BPK aN +38eaa155496c21e316c03aada2894e9f51c58be7-14graph{SubG_}PKQIeN/$+391a15e5c284cf8c0e1baf819e0871b6d618836b-24K/J,Ȩ..MZQ«PKdNeH&+392fe63b660bea991d119a5da07587929a700bab-46K/J,Ȩ..MJHjPK ™aN7{ *393e9042f4fefe36f64f4b6adc897a8fbe1c8658-5graph{{DIi}}PK&gNK'+39460e0757abe5be94cc2cea5e413f561e6cb5ed-25K/J,Ȩ.MJFhD-PKeN|BX*3950a31dbec29ae4660a457dc3e4fdb95fc5783b-2K/J,Ȩ..)LNйPK\*bN){!+397a3016a40f86439e51d42ec636237833019db2-22K/J,Ȩ `BZPKb4bNJ]a)+3998a87b8a293fb96e1681216701286f05b0a15c-30K/J,Ȩ tF!g-PK5HgNn]++3998d7837ef1b18863f9ffb60f7b6fc6769293e3-38K/J,ȨW' " `PKGaNLLH+39a1c157da49851e0c53df204ccda62b9c948244-11K/J,Ȩvt2PK SlgN*39a6c07433bcfbb78794ec9176070c4af55135ed-9graph{{{{GrI}}GrH}}PKaN:$/+39f44332af6a3fd552d7de98873f1d55d6044d71-15K/J,Ȩvr (@"SkpjPK aNh5Bp+3a3b40a7853a93a1928c40b156973d413d45e631-10K/J,ȨvtO@PKdN +3a4900ad9b0a6782c4bb20bd251be3ff63f24f4b-17K/J,Ȩur7PK6fN_F+3a79e5a467649f64cc7e30c2956a69367b257fe5-13K/J,Ȩ..)L2j$] a "xPK06gNe Y*3a7e78b5e7da43f0e9103283021687d5ad7bd879-2K/J,Ȩv Z ][ "jkPKaN@Ym+3a82ce72e50066b954940f9cbf377f33687194dc-25K/J,ȨҤZV PKebNuÂ+3aa0a4faed21d5c6acb74b4daec30b4ce43d1db0-41K/J,Ȩ.5bjPKZbeNDE*3aa527d596bd296639cac185f55d553629a4e8f8-1K/J,ȨN5ZPK ՕaN *3ac41b3afa6478ce510286f484bb371f520e4abc-3graph{NO5}PK  dN* *3ad127c10c6b23dd87ae49861912642b7dac93e0-5graph{Sub_}PK:5bN71+3ad63bea4cf975c2443e1681230c90106d3e1f12-41K/J,ȨLbBPK%4eN"!+3ae6a05cfbb94fbc25c53fcf115ca003a62bb26e-12K/J,Ȩ.}-Pv-PKfNj,+3b0dfd1d2bf0ded91300e464a87cde81831c2532-41K/J,Ȩv,Z(PK aNOƆ +3b27f9caeb88a2aa99d399da1b7538d0ac3b679c-18graph{{EDG}}PKbN}+3b6320314a5f7a58d5ad858500071cc8d4dc5df4-21K/J,Ȩ9LPK:eN8-+3b68b2151fb36073964f964723cd97332175e9b5-13K/J,Ȩ?EHPKTeN&D+3b6ca5b839566b716e665282d0a6a0b215ba0fc6-10K/J,Ȩv/XEAPKpbN?D+3b753db25e84b83a257d104891bbab7afc62fb4c-24K/J,Ȩ PK aN( +3b75f2f243e9bfeaa6a85dfb5445be27d6d97394-16graph{DiGrΩ}PKKdNV+3b9ed451803ca305ffa3c317367df1e8cafea228-32K/J,ȨsZZPKafN*3bae07df735ef320fd46b5818678d7594094d492-6K/J,ȨI|)h;ZPKheNDv+3bb29aafdb19ffdfd0f99d54bca8100599042142-14K/J,ȨS BPKaNn*3bc7a0970704e683be39d11adc04cdf1b34126b5-5K/J,ȨVzPKdN&S+3bca912ff6fb8175a958e77075d426a83c88d760-17K/J,ȨN0 JR.Y8PK>bN~"-+3bce21f3e66d7cb2a86b091c10661268a6724a09-33K/J,ȨvMI7PPSPKaNAF+3bcf14edab4b2a67a45b72b0e272c2efa06d6195-12K/J,ȨvLZD PKl-eNL++3be6eaab260e3c87aac27963c955b62c25399202-23s/J,Ȩu &𬅐`PK qfgN4 *3be73c3db9607e6861f8d3563659fcc4b95f447c-3graph{Edgh}PK xdNJ@*3bf2c48e71a2d89a453d83a0839e9074aa8cd21c-1/**/graph{}PKdNS +3bf75d66ba241bf643ff14047de799b5572f16dc-13K/J,ȨvPK ֱcNaV+3c170710fb413b3dc865f3ffd12b6057a5718800-20graph{"\\\\"}PK1gNߣDE*3c3d5891667aebd4ad2347ce7b2c316ed713d101-1K/J,ȨN2 k4A"pV-PKbN# K+3c3d97a97113a7aa0af4307de8287921700a233b-34K/J,ȨNMI)յ PK ;bN½ +3c5e71802f08d7d0544165b94dd903697eafd0e6-22graph{ST􏿩}PK 0fN+3c62eed307967f62bb599c572179a4acec999a69-16graph{{{noe not}}}PK9bNJ_/+3c66d37356de0fc90f37fc63f59edf068dfaa360-32K/J,Ȩv2PZ$FPKceN~ +3c6b2a7c79bd41ab0833d3b693641d3f30361222-12K/J,Ȩ..y?PKjaNL%+3c9827f766142fe05c5e682f0d054ee96060b66c-10K/J,Ȩv/v%p!R PK лaNo +3cba5671b8f316d04b9d38bac4e0f489042752d6-30graph{E_{E_}}PKubN\ 5+3cc878f1831b1c9598049af400629ff737b93949-40K/J,Ȩ.)LF&k!d-PK$aN\f=+3cebc43c6cf5e14c84eb697eef0bb8e8099c5ee8-12s/J,ȨvZ FabaPKCfN>H|*3cebcdc33eaf3b1673b3f84f392ef26a7c896fdd-6K/J,ȨI}acFPK1;bNnw+3d2bca33e9f0c8c2fe3b5e3daa38c54225fb5171-38K/J,ȨNMQRJMP0^-PKaN!`%+3d381fb69e60e68eb04cc2e964928f5b76c8b6da-11K/J,ȨN7N7F@PKngN͡*3d7017ca6299804256559a79d552ad2f0c8d0a98-3K/J,Ȩα}3}˫M o6ٹܖM3^/|ӽ6%6(nʹ6|m֝oo:,-@u@Fl PI!( ZӵF kHnD񚫫nS)~6m Jvѩ PKdN8Q+3d7bb6b4aef493b89b840c3c679cbe408566522b-30K/J,Ȩ>L Z PK bdNňJ+ +3d8d1d7d9a1f3b14938aa682bc31cfe4731087a4-11graph{{ST_}}PKM=ٮ067 ߃<- |x NO.zmԢ2ZL?,)  [Yv]/=EGsϤEgLpUj HuIUjN"sq5 PKNgNHfL(424aae5076414eac94a1824bf53dad808a95755bK/J,Ȩ0OւYPPKieN2.q"+4265237085e4ae1991aa5f69cc7dbb5c20875924-15K/J,Ȩ] `BPK 96gN#:+427c76ccc4d1c3f13bd57bc2f4d39cf577c9b37d-14graph{Subgrap￾}PK fNkh +428ce867c1f586153e97db11f3e6f567ea5fe430-14graph{{nodU}}PKdNQ~6+42a8a29ed1204a5320f2200186d604e09cd348b9-24K/J,ȨZa gUÉZ4PK eueNl *42e922c91e332e54826d968765f87707f77d7175-1digraph{nod_}PK9eNb׎+*42fb9cfdbff915a6343432d66f2d515f69fc8722-9K/J,Ȩ.MSLԂ PK ɀfNQd +430b010f80b41d7dc88f1ccca854b600a2e5abe9-42graph{KSK}PKCgN\/*430c1142aed47820966762cb3c262231e57d5959-6K/J,ȨvMIO JբR@PK aN| *430dd93db1f72ae2a138ab1496b1da8868418d76-9graph{su￿}PKFaN" `+4315c0e7a6aa75a5595a2bceef15db028f250048-33K/J,Ȩvt/z?PK KdN, +431f0e8ff5ffec7362760c3cc21eafbc42ad7840-21graph{subgrS}PKbN{K+43537ef6194dbc4cac726c3a0e233521ad6bb087-33K/J,ȨZ $PPK]fN!g*43649564492896c0316bb62c6d037e992af29c04-7s/J,Ȩ..MJ/J4L`t-@ظeb!PK8gNdLa@+4388dce9a25b7fc2de32eaf9c9d656790cfd171b-25K/J,Ȩvҥ 2ʆhi<PK aN@~!*438bb4d256ec503b9580ae2aecf3dc84c4e89d43-8K/J,ȨwI_ PK+eNrf&+43f85769086a0d931e829f5fa41983f054b83d7e-17K/J,ȨN|p?ZN.PK6dN%>}PKaN9@(44a24c6b9dc82d052b4d612a2d2c042de46aa261R@EJJթѩJJ9J1~J VqFIf}%%]]L ϳ5qGǵPK JdN‡ +44d5ad3d9cdbdbdffc0bfd57d957ee33807eddf4-30graph{DIGRC}PKcN)DT++44e15e88ef9058af4ea0d859635c96b1661d0666-41K/J,ȨԔTZ0 PKHfN]G˟+44e2d098053e6348d20ae12cbba3b3d3d79cde6f-24K/J,ȨVVPKbeNuK3+44f3800bd54a47a91eb3c1c29e6104c2453095f6-20K/J,Ȩur PQյ.BPK ˀfN *451a7e606286d7bef75c11b01b0fe7c1fb3ab552-9graph{SOBGR}PK;bN\k"+451a9e6e6c797f6ece18fac7f74d0ffa80d4728f-32K/J,ȨvuPK4dNO%S+4552ad221df858aba6fcb7fa3dd2afd9da0a4298-31K/J,ȨVyc‚3^٘ *87 (PKdNc+4579e762e3fae1412696df6261e69db061b46b7e-21K/J,Ȩvr W@"kkPK laN$4(458dae5514f28fe6c0995079e234bb3c69b1fa75graph{{__{_M__O__Z_B___}}}PKY$bNbw3+45960d3bb892c553f453fee1c9b3db862b457767-37K/J,ȨNu"%% WEPKaN.^+45975f0583ff788dfd42665b0dfac345c68f3948-27K/J,Ȩ..ZPKBeN+459cc52abd056e99d7e15dd4c590a592fc45f9b7-22K/J,ȨurrPK bN +45a86b3c1e529764d5db04cc6d76c6ed2bbf7d47-22graph{{STRIR}}PKKdNQ+45b3f4b0da10715bb26c57333cf7223f54af02f5-32K/J,ȨvtrNPK5aNK*45b7ff3daa9927c96cf9928cfea16bdb39dc7e50-9K/J,ȨNL/*PKdN?շ-+45cae88f7a16a570b146c063c11b1999fbff3147-47K/J,Ȩ..MJP`FHPKdN#@+45d4efb7b7fe8d7f342b34b1bd56788b88ada7b6-26K/J,ȨZ ѵ`PK}*bNe479+45e04e68744ca0b7760e65c64287631917ab947b-38K/J,Ȩյ4x-@YPK PJdNh +45e558c4f5c0092749654e4528888054615e94ba-32graph{noG}PK dN8e01+45edf184bea232942f6e4469187d14c3bdbe646c-32K/J,Ȩv1Z `CHZPKWaNs*46003753fab7cf5d37a97682d83c05b9085eb0b7-7K/J,ȨNt/ LԂPKdQgN=*46040014efa7bfe752ab66a57ec8060751ee85f1-9K/J,ȨNt/JJ#PK--gN0G%*+4619648237f1f63bca21b99b4221efb913f5ecb2-10K/J,ȨNɴ \K4PKaN6V4+463a840c449afe3f3c6e198400fb15b03aea0600-31K/J,Ȩv)s+ZLZPKgNxRB*464ab7c676b0528ddd90ed3e61d8764bd2b5bbfe-5K/J,Ȩ+#NoaPKܹaNh!+4659fa02b1adf434030f909e2c3f3784b6294241-27K/J,ȨҤtZ_ PK aNA}*467bd9b50b3e3a6fc93ee8b5508956e32261fd8c-7graph{{No￿}}PKBdN63J*4693793b70a7f9e33e053426146650e0a0b37af5-3K/J,ȨOÌPKbN}"م+46a490d9b392ea37963c145773880905a2a5f406-25K/J,Ȩ 򴀐 JPK7,gN$|*46aa31dd175e740f82cbf854d66fcf231e7131ed-9K/J,ȨNɴ \i\[[ PK fgNc/H*46bbb223e4233e2c1d23f00d2d8276216b202c95-4graph{Stm:Stm O}PKaNK-+46d215892e581a080ef76a311cdd49566561c0ad-16K/J,Ȩvt-rDkPKjaNLQ*46d2d9aba50c590d1b3cfaa308c1f4d2c59d5670-8K/J,Ȩ-PKaN+46dc8b151db2ae8f8e523baca90d4fa64a8dd638-15K/J,Ȩv/*ѷ"dF-PKlfNN"*470b26a3157d34edb0410fbf5c8b038434dfd4d1-7K/J,Ȩ9 A N]-PK%UeNKr)+470ef8dd9130e2c35044bc528791d506af322207-22K/J,Ȩurr,PKrbN~jc2+47173b728aff1f23aa4bb30082188d1969f79f83-24K/J,Ȩ &PK3gN5 *4728316acfd21cc82838e11926cf756b5edde73d-2KL/J,Ȩv-ѵs-t-3kPKJeN9"*472bc28b47c80b48e8bb63711b962c7d04086a84-5K/J,Ȩ.Mr/EkPK aNS*4739ec64cee07de732b546f3d1f7469685eafb29-9graph{{diGrapg}}PK0eNz;'+47702b59f172ab175997bd9c635d292ef91b89bb-23K/J,Ȩ.M*VQ-PK dN`8<+478e87e9283424c3c56498d1e07caf005f6a56de-15graph{{digrapߖ}}PKaN%+479a36367d08dc3a664a3251a20dcc7678f4c14a-13s/J,ȨZZ Q[ PKdN^ $N+47c41083c7c8b4ebba97013b6c1adc60e0f9f9d5-25K/J,ȨV.Q]~hk6+PPKueN45+47c46a64a32d3609376cf75ce6c8b3503ba3cb86-20K/J,Ȩur'@ԂPK eNf-3*47d46bcffd7703c74f1390d4f5b999f89b6db75e-3s/J,ȨҤT][ kѸPKfaN* *47d8af680c059b1e2a975f529a8e372983383486-8K/J,Ȩw1EPKdNv"+480054d073b327f17044a036b198e00ec367e811-25K/J,ȨZ3,PK )aNQ e*480af9253d0e7beed64991c71dce19c625571aba-8graph{Digrap￯}PKfN@A*48216eef169eccfba46bf26884a552fe7a1bcaf4-1KL/J,Ȩ0RkIcPKs*gN3*4838e40790f60c53742ad48beadaa482ed229edf-3K/J,Ȩvt/2PK1aeNT(48675ad5a7ce699206588c631d522235f397c2f5K/J,ȨN5ZPKfNSX5*486e4c25a16bda54d5e557a98b85cea0625c4396-3K/J,Ȩ.MJG&kkkPKcN{4*487f54c86af8d63028a0b95f838f5b49d6f3c1d7-2K/J,ȨNL/ P`N-"PKaN@U+48948023f62d0afc95965dae54f04ef45f40f6f3-11K/J,ȨvtZPK}@bNC#+48a23756c58b263b7adc09c5c20f6302a15b042f-31K/J,ȨNMI5EPK-eN5 P&*48b32b73232c0f4ba8d91eb93c9f61f77b1dceee-5KL/J,Ȩ..*.׵CHLPK*dNpܒQ-*48dba6573870cf18f7c537a2b72ee8d6c616cb93-58ZӋ 24BPKyeNm1*48f73201bf07435d436ea5216b95d7d301701fd4-2K/J,ȨLtY @:CPK ՕaNl *48f7439399770502b3dea31be7bcf2ba1045b7b0-3graph{NoȞ}PKKeN 9"5*48fb89a6582321c6613a8a6a7533b242efd5a4f0-6K/J,Ȩ.MrE"rkPK*eN+490df494c66207c1e784c9aca6e4cde887bdd72d-21s/J,Ȩu  ³PKKdN+4920f043e274d5412fe0a4e4501b0017bee7cac4-34K/J,ȨurPK:gN#*494ff30e14d6c2ea909482cac4e5d574fe2ac937-2K/J,ȨZ PKQaNc?^1+4972f63085d12fa3059eae9b91f0281a05b24c6c-11K/J,ȨNL/*R@XQ-PK@dNh*498462e885ba1ce07502a520b1f3db195eeea9f2-2K/J,ȨOIPKBgNTC*4988cca62187a9c6cd917bd16bb9d4ed689a905f-5K/J,Ȩ`Z FspiRC)D9@$X@ba`Յ !@4PK7aN8m%+4991fbf3493f64266b59ce7c7f46dcb90126ced3-12K/J,ȨvZ FaBPm-PKteN~=+49b7f8a95a091eba84f7f2e1681ae0059fe2a97d-11K/J,ȨvL`8~-PKjgN32p *49b8630253044dad8a3564aa54f3b3575f15aea7-2KL/J,ȨΈαUz3}˫M o6ٹܖM3^/|ӽ6%V)ܔs;m<|㹍έ; =tn XnϹ[뀬@lBfQ&Ą+.kM]@ " k ٴ ?nl16(ŦU%ɢTPK%*gN=!*49cb2f8686a713120a3371b997f10d40a9c8b610-1K/J,ȨP' GZçPK aN%J*49f70f376ca50d8ee916a0c9fd06a61743568f83-1digraph{z[ܣI=e]}PKz!bNIu+4a412d78141ab1191545ddd90b7a58c100cbac0a-34K/J,ȨNuQRcZPK IbN5+4a4f3b4d32ec4ca4955f2cb04a8914ce578989e3-36K/J,Ȩ.)LRPKfdN1#+4a6bc85d0d6350fdc3cc633d8e12f3bb2e3b56bb-13K/J,Ȩu`k PKaNW'+4a81468965e471dc888c225dc5292f59506481d8-24K/J,Ȩ..MJ/ӵ`NPKdPgNv'*4ab508b5c35305a679ba142c10b970857edbd1c4-4K/J,ȨNj!PKaNG_*4ade38f7bfb75a7b204b0c33817ebe8d4d30af2b-7K/J,ȨvwZ PK[?eNB+4aec981cd22806f8e52b01c7c233094a632969c4-13K/J,ȨD άPK aN> *4afffe4c27d4ec79d580ff53dcabfd3de779dc5c-1digraph{S_}PKugNI'(*4b060b1ce985591deaacd4483e65e34f9b416287-4K/J,Ȩ++&@-PKD3fN|=(4b127b9fcf267dc851300b395be6513e0b5a283fK/J,ȨNt/E"ADI- A,PKSbNJ(w7+4b143989a7f116a1a35a03f3f2fb47ba67a0d463-31K/J,Ȩ..MJ0V-򯭅ӨPK(-cN9+4b1bb10dfef4c8296eea91f2966590a2b8bda127-34K/J,Ȩ.)L6EjkkPKbNL+4b21e3df38f73c6e2db293524689e2a5dfa39c3e-33K/J,Ȩ`PK=aN"lx)+4b3609835d99938b055aee93be682cf53cd54374-15K/J,ȨCZ PK aNjHJ *4b6bbbc3326e02f236751fcae8f9e7579346ff1a-4graph{{DIE}}PK OJdNN *4bb547052a36254e256c25ebec2549e10c263ced-1digraph{n_}PK dN^I_+4bd0b1ff277d4a206f2b9ae0a4333df60cda47b4-44K/J,Ȩ.MJt?EfħPKeNLR+4bfe4597c913f6557c80068067f666abcceab704-23K/J,ȨxPK:eNڷD+4c013050f8753e2470c49c29700f184c2918a664-14K/J,Ȩ.}~-ܿ7*V& PK aNq\ +4c062e689708a84754539ed0550f78a36e263a24-22graph{ED_}PK<bNA++4c38503980cee0ea15cf75ed5a34e6bab1ff0306-26K/J,Ȩ 򴀐 ҤSPKfNy'+4c426becc840d1aa7c00db6d5957ba6aae7c3db6-11K/J,ȨvL7ZPKaN{+4c52db8ad42b925e8bab795b6192bef299824280-13K/J,Ȩ..MJ "BPK dN!XS*4c61d2c019021ec5147ca1ff210476369f6d07dd-3graph{""[diGrai=""]}PK  1bN?ܞ+4c62c3a8a2ba3e5313df2879835ba1e25eb8767e-39graph{strict_}PK `fN{T2+4c70f8c566c2d3d49208d63c52b5ede46fd0f642-33graph{{{EI}EI}}PK XdNIz*4c716550b708fcf819a701f342b71da54fcc3d72-9graph{{{dig}}}PKxgNF`%*4c8996c321e8a55f7a75c9e7e7363d1fc654fbcc-3KL/J,ȨNαQ!}d[ PKbfN 4^!+4c9fd93d4d33e3225e2054951be8c1884bedd4d5-20K/J,Ȩ- 3ҪD!PKbNc +4cb31460676a00f5986d4b46776a276664e35534-27K/J,ȨvPK.cN蓸K+4cc20ca0ed63e29510edb5321765c771f11dd8f0-45K/J,Ȩ..)2ϲ$V h2P PKaN}O+4cf5c989b9e8104dfedaee5cd485acc0d83aba67-25K/J,Ȩ>}PKubNZXw1+4e7400a66227e11148b574be2f2e4f6f01453e0b-41K/J,Ȩ.)L3jk4:PK@feNW6 *4e881aafca36163a13c12cd0eff41b1fd437db74-2K/J,ȨN5Z"(PKkueNF*4e895c8e4cacad067e75a81b4a7089c0d0da07de-3K/J,Ȩvtr%PKQ!gNއp9(4eb408ffe1035f2105ddb6c8f6c71d4cd5a5a0d5K/J,ȨZ1`b`,PKfN*s(4ec3449814916e54ac4884295549fcd87851072as/J,Ȩ..MJ/J`T"$k0U#1kk1PKofNIGY*4ec662eae731932f0448d3a219134797e3e05d3f-7%ɱ P Еbr@JKrgmz\nYAXZPKX'dN"+520eaf051be774ef17ec30a7d1b6fda01c76c58d-29K/J,ȨVzqL T PKnhfN`1+521780263bde61153d267bd7f99c7051124f6cb6-34K/J,ȨsZQP\ PK cfN*5220478ec1c7f95eee467d05d5ab0d5fe438738f-7graph{}PKpeN0+522594627336c19cb630c7d88dd5defca8aa9d8e-23K/J,ȨvuqZʁ1PK ofNX *5249e734c79669b9d032272e76230f6a71f77360-3Graph{{gr4}}PKaN<*525b264b9a3fecd8c178b5d6a239c0b2404f7056-7K/J,ȨVz}R-PKybN+527aa25c096917d10dccdf1b7d7e12fbea1712b7-34K/J,ȨNɌZ8PK aNo/+528145a7a451aa03fa15e086e65ed61548fd989f-10graph{{Dib}Dia}PK aN'P *5294a1a94bb9295dd1c53d828cfafe7f5992b544-4graph{{Digr0}}PKaN_+52a7de2a18e99ea18ff1c5d9c38519b14be97107-19K/J,Ȩ..Mrw!Pvm-PKeNvp)+52b4d13288fa89166f48645a8f81f5f1556c47d1-23K/J,Ȩurr 1`t-PK aNoƦ *52b80d96b2d8e64c27a8c381f51d8c76418f1da9-2graph{Strig}PK `CbN`D +52c3de56225db3e6c95db7561dd422b3120026dd-32graph{Stric5}PKfN= !*52d0f35a88c3a30fe0e1c20e07c48ac6ace0ccf5-6K/J,Ȩ9Lp-PK ],bNQ{+52dfd959eff0d75b98735ba7647e06c9860be10d-25graph{STRICtR}PKfNx,)*52ea660772e8148fd202d0094c330779473d47ce-6s/J,Ȩ.MJ/J1`tm-PK bNhC+52edf67cb8a8d35432db1c8e031c7b6d42f048dd-26graph{{STRI￿}}PKfNA !>5+52fcec3a4555420ab219c660914ac69e162a04b8-26K/J,ȨwcdN-Q[DPK aN@ *52fe5e64998791f6800028f6812c60e6f2f466f4-8graph{{e￿}}PKXbN̝+5307cccd1dfa00480642190728129c34ba521c37-40K/J,Ȩ.)ʬPKkmgN~+530ec401855a0f9c8fb6760f8dd256590f214f7f-10K/J,Ȩ⒢Z PK gNi(5316c02533c04b9490feb7b7ed23178957f7a29eK/J,Ȩ "PK jgN *5318038f8bb16bac6b08bc5890830b04f7071654-7graph{{Grapc}}PKbNa=V$++531e66841dd168ea8ec4d1bee0991026f6ade1e8-40K/J,ȨNMIHzAIPKgN5!'+536e21ad8ab2cf3e01e24474eac2b9a0f2db6bf3-53K/J,Ȩ.Mr  PKcgNfn(539c59e94e2ef1c6a2031a175397ab835533b17dMPN@M~GlH@ 1#!  [FE*Ђbۋ%m7%ҏpU03ox:@.ut6٦Ce}va+O>z{x>y%;t',I@)Z EE U)*QNQj EWnS4k)jRtAsV+00˧cN&1ވY'FHWb^ 0[S\/z~W;jPF^`Olv }ˮ Ӏ]♭2ň!VŨt6-w;KgRV2C/,,gʲ[^X<8\0|ZVʘ<~B p]X$(t ho`7KDbPK ngNb<2*53ba3528628e2787e3220a06e0c970941ef56a93-5graph{e[l=<•>]}PK&aNŶ-*53bdad46fdd5d8ada3e48575a20f5efe12d6fdc2-9K/J,Ȩvt2j!TA-PKNeNBM5*53ffdc238fb3310a39874392be7a8ff88763e223-7K/J,Ȩv/PKɼdN>\+541a94cec9eafbad8031ca564a7d8adc491c3c0d-24K/J,ȨZPK  aNAF+54201e181c51ac9118400356292a3ef009ea2b0d-24graph{{{subgh}}}PK LaNp#+54265ac66dc4b48b84ecfc66aa4d6b5e41f4f81c-17graph{{DIGRAPG}}PK bNl{+545aa45d539a5ac767bce95680206a3271b9b78f-22K/J,Ȩ.Mr/UPKaNd+54711db82b8294c98b3ed33853f1ee1f3065cef9-18K/J,Ȩv/b PKFgNAAg*547c9b14d48c6376fa3abc348c55497b6e75508e-2K/J,Ȩ..Z0Q PK aN&S +5482dbbb8fd42d2b30254400488a03cbdb56aa92-21graph{NOA}PK 3@eNs+54a678bf1a553ee78b3fdd341c504bf329899e2e-19graph{i4￿{i2￿}}PKcNH+54b40e396157bc6393e852cd324146e6dcbf3a5a-19K/J,ȨVBc VPR-PK\.gNc5*54b871d41dcc28d8834e476c11907ade72bbd80f-2K/J,ȨLZ MƭPK CjgNB# *54ba2995d322ea0f881d0e5e6d61ba37e773fe36-6graph{sW{sW}}PKfcND0W+54c511d5be306f43b2c83b0ccc1fe06399ecde6d-39K/J,Ȩ..)ʨFZT.(8PK aN} +54d7cad0efcdeaf3f84bedffab70d9e0b3069864-12graph{sub￿}PK ͞aN'J+54e217186c0784ce98dec1a5ad431ac0955ad2b3-10graph{{diGrap￿}}PKcNcI'+54e92d2cbca1e7cf09a3026bec391c13640e43cb-38K/J,ȨL 7LPKgN_-(54edd2b7cd7244267d7c1a9e81a282034afcf4edK/J,Ȩvj,ZPK8gN{4*55056d845ccae5adcfacf89c6c420590dc771172-4K/J,Ȩv  HVZ4.PK;eN z)+555dc2e58de1ef2e342ee4b454c33b7724f7b45c-12K/J,ȨuDPK=/dN2u+556ba0cd2cb57c80500d598aebc36564610296c2-29K/J,ȨV.0~I8@ *b3b@PK aNŊ *556bf75dad5243d2e15dd8cbf97b09dc87bc8d17-2graph{Nod0}PK3bN0Y,+55804abf7031a3e8887da608b1041eff1511d415-29K/J,Ȩ tPPN-qPK[fNs(+*558d7f31bf6d7aa5637ab2de4b2f940ae5e1dd46-3K/J,ȨP' ǀT3PKaN@W*5590d5f3baddc77823b8ef61526e050d1f9b76c8-7K/J,ȨwIV-PKaN+2+55a514e0494f36b16e5900fb1bcc8e3a52154feb-29K/J,ȨvMI`[[ PK!#bN+55a8703303972e661ab02fac41305247caefa8cd-36K/J,ȨNuQR~PK0 cNc෭!+55c1533bc194a2198db872954fbe56f560584e86-37K/J,ȨNMIG#jk!$PK5AbNO'"+55c870fc7c4703f6ff08d48df37b6ade8c4418d5-33K/J,ȨvjZPKqfNldQ*55da054c810347fbb082f07c8d4e91cd1a77077b-4K/J,ȨZ&) @T PK jgN >*55eb4a065345360e67d5700ed9425e39e1aa8109-7graph{{o o q}}PKnfNk3*55fafac06fe2081c45e413f2c78d9f7edf6d2c0d-1K/J,ȨLZ|Tm-vPKj@gNƺ#(561b8acf9e4a5fa7c697bfd24e2f7651dc5e2479K/J,ȨvtE&kPKbN  +5662fe13cc31d6f24021536d98310826f41c317d-28KL/J,Ȩv׵s.0PKVeN0;+566f9a4ef658faf636e2e0f874a5be228f4170a3-23K/J,Ȩurr,H":PK^eNԄ1*567303745506032692bcef8715830a478485003e-9K/J,Ȩvb R(|PKeN&k69*56791932eb6663e327c617a95594bdb4f5b51f5a-4s/J,ȨҤT][ kqpPKG2bN~+5690981900f59ac4c7bdc051246dada1f6127104-40K/J,ȨBPKfN=f"S(5a9d94f42a39eb4066a09573abfc475ccb2e3845K/J,ȨNLPRI B kz \ q!PKqbNe4)+5abbd1c4b6340ba9007f586800561b5b9d653c83-35K/J,Ȩ`HqkAPK)aN܎%+5abf2722b9512172ad0fb3d652b0940850b4a040-21s/J,Ȩvtr JPKaN]5+5ac3cad831fbaf5ec98f4f8733227337be0fa0e6-15K/J,Ȩ ZբPKBfN&}*U(5ac4f0a99528aa9a3c9613221b6f857a3b595118K/J,ȨNMI7LAI,R][[ dVWCiPKdNc1+5ac5f30a40c4507f6c2373f6a06530786668bb77-31K/J,ȨLZ QV[[ PKKdN3ް+5aeecc67a8ed5b3332c979b50da2dd3b9c7b1a30-33K/J,ȨN|-PKӌeNwk+5af5365ae9163e8f5661b467c5e345332acd0744-17K/J,Ȩa jkkPK .fNp*5b194e69bcdf49322196b6a542703fffed8e0520-5graph{}PKdN 2:+5b35f60f51c4f28008e79c85760077aa847127ec-30K/J,Ȩvt/SPK:fN#%[*5b4ce1c0e4387f3cb94eca76f525628887b10962-8K/J,Ȩ;]-PK*gNbl#=*5b568b47b63600cc7a56d034a49cfabc0cf39286-1K/J,Ȩurphu-PKZ,bN}<+5b809a88f676d945f808348b8bf00d647219a1a4-31K/J,ȨvLE ST[UPK HeNirƌ*5b9807c30e16279e851ccb0586c1f64a2ac243fd-3# graph{# {# }}PK ʀfNU (5bb2c565e5c550e26546825829c92923e83aef6egraph{{_2F}}PK aNL +5bc48daea509a1d96f5e0fd570e8855c2bdde0d1-15graph{<><>}PKNgNx*5bf714585862c29591b76d52799d73e7c60785fd-6K/J,ȨVRNt/UR3jPKjaN+5c0a237537b066300ce5fa3b96a14b856a4f0531-12K/J,Ȩ..)LWPKyaNnsrY*5c18f6179430256ac41cbb409cfef578c4ff3d9b-5K/J,Ȩյ@PK̛fNQ"+5c50ef8f8c86446dacfbfae09158636a749c4101-12K/J,ȨEvvPK&dNN%)+5c66de921f2a658edf8577a39b435bb36a993a49-36s/J,Ȩ.MJ/0˯J@PKdN;ȋ$+5c7f7d4947572b114fb02692c1370ad2132ddba9-25K/J,ȨvWpu2lY[ PKc}eNq>rG*5c811f2fcfb86159ac396b417556b1a259e5eb05-8K/J,ȨNZ8 @#kPK haN->+5c8ea1d05cdbe83fb9f68259550d7ecd3a027c10-20graph{DIGR￿}PK QJdNikn +5c99a370ede488afe8c5415afc3c9f372fbd1b4e-31graph{DI￿}PK aNƕ- *5c9d844e747a3e84ff2683454fad1b2ba7ce940d-2graph{Str}PKCgN6".o+5c9ebcb2fc1ba420e36e9364af3369e091d8b094-36K/J,Ȩvvu0|0^>)`PKp~eN3*5ca377d2c9dd089c9ddbdae2b0e7b40c6ca18359-2s/J,ȨPJbPK RaNh *5caef7a30c6d179d7cefda01a9d2e37c06d69324-6graph{diG׆}PKw&bN6/+5cb1348bee9960bfd55c6382fce89013ff52c15e-32K/J,ȨN/z?PKTdNeZ$+5cb5acf5ebc04e4b8b9e5890e86a203c3d741501-31K/J,Ȩ?|#kIPKյPKEpeN0`+5d99c1172c68e93362d8f352e0dc4a7e3c11220b-12K/J,Ȩ~-PKbN%FZ+5da1e8dce0fb134c143f3d6a9c559c7ea430e009-43K/J,ȨNtjY[[ VceBUᕬPK gaNd *5dafd9796cfc6bd1d680ed2a0c54d029b2bcaef6-2graph{dig_}PKЩdN%+5dbd94109da01958389ef4c330340c1d3faee80d-18K/J,ȨP'w0iY[[PKKgNMʫ3*5de94c50b1706b1a1bdff913b4cbee94e2c8d76d-6K/J,ȨvM)a%%ה<Q\ dPK aNyxB+5df936279dd7dd28b1e2255f1d7bfdbfee008b52-14K/J,ȨvRhPKUbgNl *5e0ac4ae4d5e0155b36c2075237a8bd56caef930-4K/J,ȨPKgNb&*5e0af4a7a73ee94d24df550f7889a013a42e1332-3K/J,ȨNαqK%DbkPK m@bNQ%+5e0faf4cc5c4fe464fdba9d9ccaf319a69b2da9b-31graph{edN{edG}}PK.bNc+5e2261182bcc85209ce755d282a62af4d9af8c24-27K/J,Ȩ tRPKgNwq9(5e43fc9e3afa7094a5c28ea811b7ebb248cb0e7fK/J,ȨյY,FPK8+gN *5e565a5641fd02f2532fd10c3cd96f87e28de955-4K/J,Ȩvt/2PPK aN_ *5e587c7edc69c8b75cf0bdc5322faa6399e87a17-2digraph{E4}PKcN/>M<*5e8d011c7cc8934b383fd42f3487bc71d3e0cc0d-2K/J,Ȩx0P["PKeN F*5e958a030e62c9d902758fd8cea2c11f14007f15-3K/J,Ȩ..)EjPK>gNY O(5ea2619b0b1f0e3ae14435c1a8947dce2db6eaa8K/J,Ȩ..M1KZ$ZqjZPK*gNK*5ea37db9e4fe271b6c794fa79e66ea6f562ca7ef-1s/J,ȨvMIOFT-BEPK/eN4+5eadba5013e42020b5f16b0365551f5ce3092d1b-16K/J,Ȩa(U[[ PKeNX!+5eb023039e682b6a095a8dce06b0349a6d2e62d8-17K/J,Ȩur/Z PKfNҫu#S*5eb12dde6817179466e0efff7fa7002ae84c4fc0-9K/J,Ȩx Z Q `bA`PK%gNj'+*5eb1a010420b39d5e9747df7d30bd63cc19c88eb-5K/J,ȨNt@a:Bj PK ghgNP *5eb1a1fa220731f2c7601bef884afd1849df5e83-4graph{grф}PKnlgNm u*5ebba4dcd8f61e675090c76b531ad2bc54945f2c-9K/J,Ȩ..MrkaZPKQdNmT +5ec7abb6cf79a20d0c3a6256a0c78cdad5133811-31K/J,ȨVJPKaNC+5ed6cebfc652795cef77430db28ac063b93ace35-26K/J,Ȩvu9H@XPK BfNU( +5ed771fcc8ff94d053797391fbb76b03a7412b78-23graph{"\Z"}PKaNI+5edf9a68d30bfaa2bf17a8008798771d2c44d7b1-16K/J,Ȩ..Mr?JPKKdN^M+5ee5c9a235d4752b81eeecd1760f2bef89d26a04-32K/J,Ȩ..)rPK hgNj *5eea126bacae5d5c97e72a8aba65d6abd0a46112-7graph{{S}S}PK [!bN"I +5efb37fc99012ccaafcb9772766f6695c6b90fee-27graph{Edg}PKdaNſ2]8+5f14edb10030d998d84ce9a0b3ead1cce665b576-20K/J,Ȩ$b( ™PK YaN+5f20d5deb6e0d93343c8c171d1fa96c46209aaa3-13graph{"\=""\t"}PKnyeN0/*5f289c3359c02c49bfa0fc68241e6608bb5e7039-5K/J,Ȩvtrtѵ0[[ PK KdN9D# +5f2fddedc6b98bcd2e1d841d70dce78ca5f459ab-21graph{GrapA}PK {KdNFG +5f3ef96ee1d811d3a27bdf3eb4837c6b4b5a446c-21graph{Gra_}PK gNa*5f4300b5d68f86a6661eb13b0e7529bd91e1d24c-3K/J,ȨNtk!tpm-PKRKdNW<=*5f4c7d0c46d3e0c32ad1b041a0dd2798cb792d3b-3KL/J,Ȩ0jjPKeN(\*5f5a922f3d702b982bcf851360b7104df3085c95-4K/J,ȨvMņkPK VdNm1lb*5f8a1dc8721e8aa46108dff17cfa67687ceedc83-7graph{{{diGrap}}}PK cNQpa*5f8b46427cd6136131b39d97e483e17a38a124f9-4K/J,Ȩx8@b"|52PKaN,0+5f8c4c4c4e49d7e2dcb6b251ff8d6dfaf1dc1903-13K/J,Ȩvr PKgNv*+5f96469b2d6fb2f511fcf282c58d9e5a2eef9b05-15K/J,Ȩvr Pf-PK!gN@6q.B(5f9a499807f5cc32298786245833960dcd3c703cK/J,Ȩ YAk1ZPKMeN+.+5fd9c6976d4c867ee79a7f54b35e70b82d819696-29K/J,ȨׂIT^m-PK fNj+5fdb3d7494f940c2e8b2228298529faa64d2ad03-31graph{{DG{DG}}}PKJbN+5fe4ff6dcb0cdd0a5eea15e60b6347762f74f2dc-36K/J,Ȩ.)JԵPK"bNEM+5fe756b6a68e96c48cac629c6c12bbec5f9380f0-35K/J,ȨNuQRB~PKQdN3!P+5fed593ffe61a8f6b26c691fa2aa58506d4e9d78-24K/J,ȨVA?߿D_#ص1XR-PKhefNz>.+600b9bd9d4053916edd0cbcf119fa3cb9db7aa0c-21K/J,Ȩ- 3P8@PK#0gNh+*600dc810067290c04813fbc2cc1499028010fe48-1K/J,ȨZc9`PK+aN[*601619da846fab5fd0353bd884059ad0bad97bff-8K/J,Ȩv|?PKOdN=*601b7430a92f8d956683dc63d204bbf12026b119-6K/J,Ȩ.MPK8bNc_b+6021311ab37a5d48769e6d1acd2017ccc37bc710-23K/J,Ȩ bPKdfNKD!*602ab9c2c787c3bff7182de16d6d24cbbf79d2a7-5KL/J,Ȩvѵ!+@PKaN%+602b800e829feade52e18c9d04e33c8d7cfc5ad0-11K/J,ȨZ0QPKXgN߁"*602c1e9dd5a44a89602a155dd43d70507e820810-2K/J,Ȩvtr p3`t-PKģaN^*602fa5bc3fb7565787ffbe1c704bcff1339cd542-9K/J,ȨעPKfNJn*60482e3bb9085599feb5abc2e0ca1fe41c9c1c43-5K/J,Ȩ9kPK fNvp+c%+6056ec0d5691ce9574b54e75349f1e7f10ecd4ef-20K/J,ȨaZ4.PK<bNW+6068b042250701138bb9f53394134f6055c40f08-28K/J,Ȩv E PKaN_8]+6084b85bbecb9c5ea6dfa30f52e7a102b9c490a2-13K/J,Ȩvt PKlaNsցl*6086ea13b41644f80334bd21e5a8762643476fa6-5K/J,Ȩ^`2PKT,gN*3*609f6727ae915abc1e525b3145a38aa8fec8dfa1-3K/J,ȨP' GZ4H-PK aN] *60ae106a39224b8733312bcbf2cc2b0f6ae11eb6-5graph{SuȞ}PKEfNo5#*60c418e56927b94acefb5a83e88021a0430bc02c-2K/J,Ȩvt2j,qU*),DPK8cN{C+60cd07af0c84aeff6e71497ff8502bc4960a16b4-33K/J,Ȩ tF!!T-|?\-PKieNN"+60e341138f95beba1fe55ed3316d012e0e8c4e59-24K/J,Ȩurr 3jZPK fN J]g 6*60e957d044e00fa1473b84a412176a5fae17b0ad-8K/J,ȨN/2M/2@$DLւH>}PKKdN[@+625fc3260cc982c9f326aa5216cacbd1340688a3-13K/J,Ȩ{-PK.aNeφ=+627ea422b7a920b975d467749b18b47dcfce2ce5-11K/J,ȨvZ FabaPK gN¤aT7+627fa6adc9502d6ea8a8fd9aff1ebac8abf869df-43K/J,ȨBZ . PK1aN(',*6297e756965abff1bf6c25bb103000b3a3becde7-7K/J,ȨNtG–@CPKgN#[-A*629aba6b839f9d7320196fdb1508f425eb2b0a5a-5K/J,ȨNαQ!}4DvPKcgbNR['+62d07a3ce41ab13cb470bd3b8b8bb3a9dca5c0b4-42K/J,Ȩ.5@l f2PK :aNbt+62df3189217188ec14407058cffd87847ce4b99d-20graph{{sub1{}sub8}}PK aNYV *62ea44e7a6189f9fa37039cf7ffd8b124f17d8e3-3graph{Edged}PKeNw+Z(62eee5c7ffae2984a4eb292a9b3ce152185d6c84K/J,Ȩ..MJR@P[ bPI\4!(qPK)fN<+C+62f82e46d34dfec76c84514914c14d4a8aa32d2d-37K/J,ȨN/zR[ _~?Z HPKaNǯ7 *6359c2d498eb6cf0bdca259c7afe1e21fdb354fd-3K/J,ȨNѵPK˙fNJJ+635cb156bfe7abf709d9157ac0faafcfe65566b6-10K/J,ȨIPKfN{8+638515fc6e549abe0af93b7f6ebb9a7b3ae2a48b-36K/J,ȨNɌZ)P[ !kPKzeNNq5*6391bad243a53a164117609a2d58f3402bb3ab22-6K/J,ȨvtrtPPK;[eNH <*6396d5c00c05a1037f94af157943df46e96b85a9-4K/J,Ȩ$Z0I0a0PK/cNv/+63a637accaac861fa3d9f0db78a856e58cefbce9-39s/J,Ȩ.MJ/PP*U PK0aNgn=+63ac2f6394c0f04fc64312ed1bc8399604423d35-17K/J,Ȩvuq{-PK&NgN^@# (63ae161a29818cbb37ba9f82340b6f90afc63b3dK/J,Ȩv1k! (\ PK aNO *63af712695794a0c6be3ecee45b4603ab3793edc-8graph{subGr7}PKc?eN/+63d737a35130a92e8e06c401231a59b444c80bd8-10K/J,Ȩur?jkPK!gN#*63fa8c5071281735a4cbd31e2dce535e5c921ae6-1K/J,ȨvMIORPJPKrfN21+640f18bf235dc84d33ddfa15e05af54eec253de3-17K/J,Ȩ Z BbPK aNNA*64199a0e6b7c0e839e9bbc169ce26a981dc137c0-9graph{{{DiGrc}}}PKAbN^p!+642f538343f33fbbd96590a7ff512dab90f77733-38K/J,ȨNtw$PKdN;1+6434039995ea9acea9d9ca2f6be8de74bd33b79e-37s/J,Ȩ.MJ/0˯FqPKfN+643685ddf24330c21e01103b31253103181e3b24-30K/J,ȨNt/*PK|aN@o3k(644b64970f24441f2bfb8c8cc57a761aed38b784K/J,PNN-.)ҩ@nRl^UidNqI%,UT]]RRk˳530*Z,l`t)&hKRL^R-PKVbgNo٪ *645abba47886bb2d467b5f85decfa5ae428f2691-4K/J,ȨvZPKNbN+64687726425e0fc64420616fb021302a648595c2-37K/J,Ȩ.1bZPKzbN 0+6479bdb584fd933547d43fd8036665a8f9dc781c-25K/J,Ȩ b8 @i8PKaN:w+647e588f5bd3196ee92d13b43471c1a15b3b7604-31K/J,ȨNL.PK\dNH++64848995994ee4ed25d77bea6b32ff7503cf272d-32K/J,Ȩ?|#kٵ PK-gN(6497cfd266c5954b052c0dddc6cf75d5440d29ebK/J,ȨvLE#@PKJ3eN+7 .+64ad07b6967fa3d800e8a45546bcfb538ceb64a1-10K/J,ȨvL/` ] PK4aNI/+64b576e06b36ff46a674b5abbb6987a8716a0fd8-24K/J,ȨvuqZPKaN]+64bb8a9b1d4f95ffa7093d2adfbcef3e4021e9e3-18s/J,ȨvuqwPK JdN[4 +64cae06fd77f87ff1576fbea8f5c97988ab54052-32graph{di￿}PK ݝaNI[h+64d0bf38c1d2d91c32aa7538420b8b9321faf6c7-13graph{{DIGRƳ}}PK bNy+64ddc7fbf9c0857e46255d928f6778c7c30e0805-34K/J,ȨN Z(V PK ҚaN2X+64e6f5a768e7314dd8d61d57e82afef71e113803-16graph{SubPʿ{SubWʿ}}PKPbNZ8W+64e991a9614a33310ddc64f00379dd8191f9de82-22K/J,Ȩ b] PKaN{56+650054700a6b431748cf7f5c93664ce475f17b3a-14K/J,Ȩvr EPK-dNpm 7Q+650531ef9b773e06a6ed6f7eb383fac5fe16b3f6-29K/J,ȨV?߿H! iaib`ljbjajfbnjal``nahd JPK9KdN赉 +650cd9541206c7775291af1ef05517f089245fdf-31s/J,ȨS鵵PK maN\+6549ab65559d6ea8d7c7dc3e3286269892675a0a-11graph{{{ED￿}}}PK&5bN[Ν9+6554a05712eb3fb46062a0b378f1cb0b3699f067-31K/J,Ȩ tOBZ PK eN #+6558b5927b204a5f6de6a0263ac5165cd2cdb4d9-19s/J,ȨZQ0\ PK+eNlz%+6563e3247a65e32f9d6d3353fba320ca29ecc0d2-22K/J,Ȩurr 0Z PKaN*65685d8741bfb1bb5956eae19c334edce82e9ca0-6K/J,Ȩ LPK1gNGX*65920a2f2c6a2b534cb58a2c655a49d9c8e85b9f-3K/J,ȨvL@TWV ص0PK >bNo+65b1ac5d2f83e537290258dcb202e98e13587bee-31graph{Stric迿}PK̡aN0*65beb7ac2cde16506111210fc224a23616c25ccb-6K/J,ȨvMbFJJ@ PK aNM *65d04f3f78e5032803eaf4c260f64eb6d2a1c315-3graph{diGo}PKieND+65d8ea1311e904c886d2be4e327d295340328a30-15K/J,Ȩ..y`|- PKݣbN7S'+661034c3d645beb0d0f83aad646ea4f566831d27-32s/J,Ȩ.MJ/J2jPK aN*"*66272378a49934d9fe01467a36d16eb5cc269fc8-5graph{"跽￿￿"}PK]dNkL)+662b8cf6b39f1a4f7d12b139cc749ece41c83894-12K/J,Ȩ T-*PK aN7%$+6635b4e39df28a788ddb79feacefa520e79bde87-12graph{"\"k\\t"}PK aN *663bbac210ff8d95f466a05363cb52ca1724800b-3graph{gz{gv}}PK f bNc +664059b10d04031087c91e260effd16200a29bb4-19graph{STRU}PK"aN6s+6656016f2001a20ad570446e11c13b2a3ac139f5-18K/J,Ȩ$ZU\[ PK݈cN;+6663ac68e1e5a0e1a990800c17e2fb330bd12bbc-38K/J,Ȩ..)ʨFZPKFaNSt2}{(667fcfe9d63305023f90814ffd591f15a632da3de 0г~Y1i&"GJAR{x 3dxS&rCwt[&RG&P_ԳTC&꠶eC&rPD^ oֲ)Y՛4gC麟PKgNď+*6687f78af73037cf852ad1ffefba687b6eca2c4c-4K/J,Ȩ..ME"1jkkPKbNa +66908ae39fd45671f971c733206f068bd80c91eb-28K/J,ȨNPKbN2nD;+6692057f69423cd9b5eb518985d2ebf93bf2bef2-35s/J,Ȩ.MJ/J2jq PK!eND9+66a047b5cd9308a5f8a02d2ef731dea9519764fa-20s/J,Ȩur'(PKHfN" *66a8302e697a525652afe4249123c17dde02a9f9-2K/J,Ȩ..Mr/P!PKlfNl/#*66c389b71ae234ad4eec6409e8b5775d0bd919f0-9s/J,Ȩ."y`PK=bNn+66e7a871723dbf816e8122abd4bcdfcaa6dfd1a7-32K/J,ȨvMI7SPK  aN +66fe04495b7e9d897d66e085a847a82379e2ea72-15graph s􏿿{}PK!gN\V?*67023e1b58be54cd1ae7ef49316594b6b23060eb-2K/J,Ȩvtr 3jL8PKpeN 95+67071af22dd9e62540673eac6c73a20f7967e35c-12s/J,ȨѱĒPK aNKn:+670b3813ee60267053ec07cf37cd555b019d5527-11graph{"\"\"\\\￿"}PKaN+6720ed948d94a558a82848b71b44269a9d20cbdd-11K/J,Ȩv|w/ׂ8PK`gN=(67210f46d300cbbad9ff48cf583c165094e2c860eM ,Ĥ*H.$.(Rtx3ZJJD^IOR#mW (uevM\@ѱ@n |pR"]Rv4J|f:|c̗;ϟ^]ݏPK -aN:+6724ac39e5d6e134052774d39867467e60e056df-21graph{Su{{Su}}}PK eN.@xJ+672f426d8390285e36eaeba9f1839d0ebeac29df-17graph{subgra￿}PKFgN|%+672f75bbdecad5747c663d06fd78b506ef80989b-37K/J,ȨWZW' @| PK5gN1I(674b63bfb6bb690dbec23414a073bc99f6a1626dK/J,Ȩ Z8FPK>dN#+67750daa08efeae3df5b84e15b42155cf0f02ea0-13K/J,Ȩ..)PKÚaNi*67910671746af75015eb5be435cbae87b85bde2c-6K/J,Ȩv̬ZPKlaN+6792c45ad750acdd91369d65eb8e4e643b5937f7-17K/J,Ȩv/JL T PK3bNj+67aa9f449899f78bd7ad3275c9081d7b54d6c369-31K/J,Ȩv1ka4PKq!eNMg[/+67be91068558811252e5dfa2de923bf177c5258e-13K/J,Ȩ}- *!kPK ;dNˬ+67cfc00f8e95728f4714868486287f9e10341904-23graph{{{SUBGRA￿}}}PKؤaN;7\+67d8d6965e0146dbc3b5d5cc73f0beb704efb376-12K/J,Ȩ..Mr2__]PKQaNj|;+67dd72feb91d131c6572c98a9bb9086bb12a5af2-11K/J,Ȩv/vF 9ZPKfN'e(67f403a815978599138f2616297a9984bb7c9f0eK/J,Ȩ$X WY@a"d,E5PK aNj +68299e83d15ef0e60ff44869066fbc4862718f44-14graph{subg޿}PKeN=T-+682b07d86c02c0f6fd8aca329d391ad327da0561-11K/J,ȨVz |ZPK bN PZ+6831708dbdc89efef3e1a5d3428cce875655a320-38graph{{Stricy}}PKbN+684a81f936db37f5325f5c920ad195d17aaa1ed8-27KL/J,Ȩv׵s3PK akgNBi *684feaeefdcaebdb429dfdda8059e136e5949a22-7graph{{digr}}PK aN&ɠ +685b21b20c804ff7017e94702757780158900cf1-22graph{EDG￿}PK bNR+685df89972e1d9675d24124ba16c1bd71f33982c-24K/J,Ȩ 2HZPK)7dN<+687557fec52b8881cda32a0d95e789288f1c3e65-33K/J,ȨVy1T PK aNE+6897b9897e3663f82ff20c4696cae5fa4ffdbcdf-17graph{{DIGRAP_}}PKfN˸<$*68a1362cda6d124a0a3ec7e34dc82cd4abd4857e-1K/J,ȨVzR*塣ZPK4fN.p M*68a5cf10d36eb703ad2919b04befd2ec9cf0cc0e-1K/J,ȨNt/E"ADI- E"1 PKbN=+68dde7575b969f2c03d14694fb1d5e2e2d41bbdf-25K/J,Ȩ r`&BPKlBgNeNΥ**693dcc4d57c0784b1013f6448c04bc480fbc8734-7K/J,ȨNt/JUR0jPK#gN!(695c60976742e9f672883237009f12b39a03b5b4K/J,Ȩ.M1at-_[[)MX1L5PKcNUD#+69671a8d24aaf46042b73fd067908ea45bc8a36b-42s/J,Ȩ.MJ%6TPK bNCPc5+69a376fdee1d2794513705f0b5f2ab422517c0b1-23K/J,ȨOAƵ~p&P-PKTdN%J*69b2ddd8c4313593e7002c0cd2570deaaa1f6699-6K/J,ȨLZ PK+aN0R*69bc114fd1c32ffb71c3e69bd96907c0435a0018-7K/J,ȨvLuS PK8bNoQ@+69c6924259aa6577c77e874e0b1d04a2190f5803-32K/J,Ȩ tF!!T-D-PK(eN|&+69edd4fba86185fd7d0d996a9f4d9c5f9e92e734-17K/J,Ȩ5b80ӵPKbNR)+69ede99a4413eed56e179d74d7033bb53652dc45-30K/J,ȨZS0PK bNRuU+6a19481e56e746b8b28b2901378340530475e529-23K/J,Ȩ`ZPKieN%+6a1df76861decddc140cd70d14175bd187f979d7-26K/J,ȨvuZ 1"PKaNVB*6a203c8963cbb476c50ffb6a89955d01558373af-9K/J,Ȩvr,`PKfNx+6a48b566849b0326dd02fd3d1ec5afe8d3c1e73d-15K/J,Ȩ.U@õPK dN[w+6a5e87e6dd519a83f391a0ca1a1af479c11ca3c2-20graph{{no9}{no6}}PK fNnS>Z+6a637e2851aa801474322e64640ac53c0182a921-11s/J,Ȩ."E DjƯJPKuaNʥ*6a6479eba7501f357a4fd9c9c5b07856e68347b7-8K/J,Ȩ.z?ׂPK XaNn~!w+6a6bb83fdd63d31a81d6183a45645c145964f98b-10graph{"\"\"\\￿"}PK ̛dNKrk *6a72a7a4bc3354bc849f1efa9d6762fad2cb0b11-6graph{Dig_}PK|-bN2K0++6a744ebd913fbedf73b2d3311a01071a61de77cc-41K/J,ȨZ0PKgN'(6a830731e1eeb7b94f1773135102ddaf91cca688  w RotF?NoD@gwsyֿ((M+SS=x{Ro9aNi% 0w0w-lR\JQ#WӶi1 .nֲޯ44vUo5?5%1u Xr{Q<{jkPK=bNUl6+6a9141d1dff890f8de2b937b2cccfa1a40dd0d32-28K/J,Ȩv3k PKaN +6a9213de9621270b40d9cb109487eda54f721f41-28K/J,ȨvMIV-PKgNi/,!+6a9627213ad965132c82d79f016a8ef56d404d54-18K/J,Ȩ@Z] PK gNq;&9+6ab6b3d4c273a09f784614c31efe61e26fce2525-58K/J,Ȩ.Mr/J1jatm-T]PK aNRmK> *6abedd0d40aaf1652bcd7ed88c02adf1698533cc-4graph{diGS}PK $bN5 +6ad94f09dca95333705fa1731f6d89d95061c4bd-28graph{edg￿}PKaN俦*6ae956100de9a38fe5f0e4359e65f2fb967e038b-3K/J,Ȩ:JPKb5gN f*6af334c16949c481a3873b714b5fe592c1f8310c-1K/J,ȨZjQ[ PKgN;%=*6af4fcb391f63c9f225cca891e6fd259c9e566c3-2K/J,ȨF.@x(U[& $(APKaN!}@+6afdfd3039ffe3675c79974f9a522ee42c62d9b7-14K/J,Ȩ PKpcNx(*6b2e56b81ad9aec535646013634f5ee9dcfb0244-1K/J,ȨNL/ P2*R[ PKbNIy++6b2ee52a0c6f27d3d5b25463ebf5737257bb84d7-29K/J,Ȩ..MJ0V-PKiTgN|U}I*6b3c2533f7a2a38fd2ffa70aedf1e4220a549bc2-7K/J,ȨNT-PyPKEgN$+6b64f5e3697627c526686718bc19496a504fe3e3-36K/J,ȨWZW' jPKm`bN F+6b6b991b2c8a3c8e3e0208c8b8bc46917178d209-39K/J,Ȩ.)򇐵@»BPKaNwW*6b807e707a974a5defbaaf18f35214da7410d7ef-5K/J,ȨO"8 PKNpeNc#(6ba4f500236c078e1bda05dd012172d053d7f83dK/J,ȨvtrJPKtfN"B-*6bb82524fcbe987b547957e76081dc33570e14a8-1K/J,ȨZPKJbeNq+(6bb9b60236a5d21db90e56e9258d6cb94f0788f5K/J,Ȩ.)L6JR0Yp> ߿\C-PKʬfNCmm5*6cabcacb6054d1bc20a8289ac6160b0a6adeb8a7-3K/J,ȨN"Z PKaNm +6cc526fdbf08a08efbb92ff0b832f0c2c4fede9e-17K/J,Ȩv/b aPK ]aN+6ccc9e9c6499a1d0bfcbbdaedcb06d81b400ed63-28graph{no{no迿}}PKfNhB.5(6cd1406c508518260ef1424d31b91c578a9dd28cK/J,Ȩ#DV)Pmm5PK  dN f +6ceda5e980736875537aa6a1d42725bb4a924f28-27graph{Edg￿}PK")bNN@4+6d0c869ba88460a24cbbcdc684c3fdbc2989f8dc-37K/J,Ȩ⒠Z0 PKMEeN$[+6d2297affcc0ab6d04175fdf80a051eb1ecef3ae-22K/J,Ȩ..MZPK3igN$[*6d2297affcc0ab6d04175fdf80a051eb1ecef3ae-5K/J,Ȩ..MZPKAeNߐI2*6d27a1d0c615660ed6dcbc435bd42da0df2f45b0-1K/J,Ȩ.Mr/J,2J0`4PK aNwa+6d306c1d8a323696367c76359c469f1deab535b0-23graph{{nN{nN}}}PK4aN_M$*6d5a02ac1510cec5c27d6daaf960f91399f47b18-4K/J,ȨvMIaPKFdNI.L!*6d8144d9ed5fd5bab7ada3f8b44438a27da17a9f-6K/J,ȨOI PK {KdNk I +6daff0f6d263d74a587fac5af7a0595d90c09064-21graph{Gr_}PKe[cNeX+6dd855b97641e8a3d5eb52723a3aadf8350028ad-26K/J,Ȩ.MJ7RPK -bNTC+6dfab8e80dadbcfa6c86d3b8189c0a8fb28275d1-26graph{STRICTR}PK ŝaNË *6e08d2604b4b82fc3c931bf176e5f290314cc0fa-6graph{NODG}PKncN0ɏ +6e119e55456c68f3f746881699d139bfd88ad8f1-39K/J,Ȩ"0Q PPK :eN`{*6e290d6ac3f477182fb8a18a358deb2c2c93cece-4graph{""[diGra_=""]}PKgN7*6e33ec7ff8cdbccfa9deba58d162e740458658c1-9K/J,Ȩ+ZPK#fNm0`%*6e44ffa93a7b2cbb5597c84efaed9423c9464674-5K/J,Ȩ..a R(."( jPK EeNGl-*6e5513f1022a1dc0dd1ef6464f3d14ff83046737-5graph{""[diGr_=""]}PK*%gN݌K_V(6e5e62ab2c1bea9228ba07621d3bf46b629b2b1cs/J,Ȩ..MJ2at-ƐAPKbN:^l+6e7bd5f02184654049f78a29efbc4f8f46298f07-29K/J,Ȩt/_ PKZ3eN!+6ed77d57d790e9ba2c2c583938324b8015416011-11K/J,Ȩ;kQ \ PK aND l +6ee3741897c93a3859fa8c66d0a1fb5f64e22062-15graph{subGΩ}PK aN*6eedd0450c074b37423ea0170326b4e2600b648f-9graph{{digra￿}}PK.UeNt^ڏ=(6f07568cf8e9fea1fc31d62a30d171eb8cb6105fK/J,Ȩ$Zί2PKBgN/;7-+6f1c4fe5a63dbc51f8f7baec0da77059e88260eb-16K/J,ȨZ^ $R Q3PK  aN+6f20b550aee382baa3eea1180d3f9df40d0ec9ad-27graph{{D5Ω5Ω}}PKFcN17+6f2db50da4269b560aa7374536e49b99c8231ea8-37K/J,Ȩv/rZ"s-QPK bN +6fadcc5f939be3600eb0d0f97ad01973702e1f6f-22K/J,Ȩ r`PKXYcN'+6fbc5177d8c45e99c52a32c25e548b9592728e8f-25K/J,Ȩ.MJw^PPKCeNqL?++6fbc5ae3bcc9e3955e908f1c11c57a8dc94f316d-30K/J,Ȩvuq70Dz$ PKKcNH+6fce5fe5eefc689845e13b9773487b03c4f22892-31K/J,Ȩvt/J P^-PK bNT +70088e5e0caa70c7de649708a838476e9e5d172e-21graph{STRh}PKaNi+7010a5052f75059bb44ec8623c12d9093d882ef9-10K/J,ȨvrZ$PKbNn|1%+702bbbfb36b3018215f4c99784a04ac04e2f4ac4-41K/J,ȨNMMM"ׂ8 PKաaNgB+7042b0f6168816367940690b445094e1159b6b51-16K/J,Ȩvr PJ PKXgN}G?(704ced899f9ca42e32a1058a3f29d34ba64fc76dK/J,Ȩvt2RTZJ(PKS_eN;鸟+705878c40d6ecfee82bbd4514a2eb233cc55a598-19K/J,ȨP' ǀPK(TgN*705f339a3291664ab8a92f264b6f031297931c10-1K/J,Ȩ..Mr7Pvm-PK 1aN-!+7069b3dba509bd4d80021bc231e85ade21a6f41f-18Graph{DIGRAPΩ}PKaNn/&+706c15b129f9fb64e9e68b58fe90a9ce94123b5d-15K/J,ȨL$f-PK fNɇ*707344fc85f5944fd27d675113804672bcbef4a3-1graph{{digr_}}PKڂfNh *7087c7fd1f6ffeff7a5b933fb349a40da580464a-2K/J,Ȩ.Ubs+ήPKpfNZ+709c99f2f9327e5659254e7b572bbcc76c25271b-17K/J,ȨZPKBbN&+70a8ded4b108513a8b1dc7c9af13fa4acc2a815e-32K/J,ȨNMIZPK KgNRm+70d4f94e7cd9f51a30f900b79e03ed435ac06191-11graph{su{su﷿}}PKGeN!+70d5c1e7ba765fa52a9b1b212e0197b06bcaa64b-21K/J,ȨOaPK IdNk(70df04ee42a082c249f6ca07e29288fd03e5d494graph{A[ne="\ "]}PK aN +70e8a025c42e9a0343b3ed00753994852f4aa9f9-10graph{{DI9}}PKcN]z#+70fcf2300a3c67c80679cb63d48e8e5ef98672df-37K/J,ȨNMID(N PK9bN;Ÿx)+70ffc42357cd566447bc42575133f5bb53f39ed4-34K/J,ȨvLEA"@"PK PJdNo +71041fbd7039de63d5be997947c9187ca189c700-50graph{{su_}}PKzaN[e i+7119e6689c87083a81f9c02552d46cff042e5412-21K/J,ȨZY PKbN= s+71232d77edf8a2f57f4edcf2429a47716d9bd307-31K/J,Ȩ..MJҵPKҖaN%d%*712a71da17f7a89af258f5e623a13131643953e2-5K/J,Ȩ dmm-*PKrgN|=*713c4f3671238a084f70258293a38a7d4460ac9e-2K/J,ȨvjZL( PKBddN $;(713c80d846d8463eedf59fdde600e632545038e3O/J,PRNNURʱUS286L+)ꒇlLc˩PK zfgNmR *713d803d46eed50c3ba1030f010fbd63033e2a2c-1graph{/**/}PKjgNSo*7169ebaa30791c83a765780c890ce8712dcb6842-1K/J,Ȩvtr p3jPKaNA(~+7176c1339ddd7da8f647d5b7c1adb24a6454d1ea-16K/J,ȨvL/:JPKUdN X+717cf053bb349d41d457ff84783acb44d2d23596-19K/J,Ȩv/JPK aN *71a55b71348e64c9badf6f6af3f78114f7b669a9-7graph{Gs{Gt}}PK &aNV!%*71af31391c423ea7aa62e516410776b1ecdcc0d8-1/**/digraph{}PK!eN|A1*71f29a8c44f00a8ae87edc937b8447d6bda1b661-4K/J,Ȩ⒢Z[[ cPK 6bNU\+71f49e7db18c8ac45fe1dfcd3de39fa0af1bbc3c-24graph{􏿩--􏿩}PK aNQ҆ +7209a7df5b20689afdaba7467434bd27272a4c17-16graph{SubgΩ}PKdNpeH+7209abd9212dab43259531d494d2a1e295009ca6-22K/J,ȨNt/JE$L .& PK ԴaN-Vs+7209f2a46fc2f10bcf6e740dc75c34aec8985bc5-28graph{subGr￿}PKKKdN~+720d5699b84684102a8f50835f9f877d6c4e941e-31K/J,ȨvL߰JBZPK eN?!*722de1c9d9758afa41536654fde28ff17cfa718a-4K/J,Ȩ..)R`ʮPKLueN\/'+724bf9440d0eac792c394b2363319d4c645c78de-15K/J,Ȩ~-@b!PKp2gN n-+725268ca288af84bf1186c40f45c582a8cbc6c23-32K/J,ȨV!*PK}bN+725c16b341b127387eb45bc93716d2f9929bee10-42K/J,Ȩ.)L.I3jkPKMfN>i0+7266c996cd5ccabdc8a7b0acc3c3198e4af97ab0-28K/J,ȨVV "E"PKVfNR'-(7297718ff85031ebed9922ff94430d859950d34bKL/J,Ȩ0Rk0jPKuKdNWʷ+72b284ca30ee885b247e5f5ddb3237a33e0379b2-17K/J,ȨPKdaNP\/*72bd5c2879a191722450f453fb9eb9ef3aaa8504-7K/J,ȨvMbFJJPK aN/b\*72e790f39d8968020258490d745b232828700177-3graph{SubGrap}PK!YgN㝇*72eca6ed4bc33398d9e182e5892a97309306f583-5K/J,ȨVx$ DAYEy9&!&UIaQN%`3B!?O*(_!,14lr@-pɒd1K0pYas KW(jkPK )aNm*72f45a0f45b7dbf07e2587b1835000cfa927ea4f-1digraph {{ }}PK aN7 (7308925fa5dc3d74c5c202de9af56900944d6a63graph {sw sw}PKgN8XMGx*73104b75c6756f805d2eee6b56efb27b75a73111-7K/J,ȨҿetI,FpDC0%fpNXYC\z \CX 0 ,ͦXXPK eN'99(734ea08dc410d1ed0d5e8f64cc785bf8477e2469graph{r9u2j9c5y{{}B9a2z7e1i8w4l5g3g9p8w8x8u2a6n9y8c{}{}}}PKAaN6GD+73943e2f48b59e4791066661c86b587ee53a3683-14K/J,Ȩ..):BPK۪dN/Ѯ_+73ae2a121d01e9930b3a11efbf76621296aebb6f-18K/J,ȨurEjkPKbN#%+73b5086d4d1a4abbe5c066f1f0fd82d836e69b05-36K/J,ȨNMID(Na PKdNC+73cce91ea5f1796dca03dac152b686e3494392f1-33K/J,Ȩ?|#kQ8Z$&PKvnfN@{'*73d53188fc28be3b1ce39e06661aca571b28223b-3K/J,Ȩ΋Z aPK  bN J+73f8bb0f382f930d5be1807330e598c762388927-28graph{Stt{St}}PKBbN]D#+7417c25b930012e1e34677121d542ab3f9b9b79a-33K/J,ȨNMbZ0ʫPKfN*K&*74196ba221a5cf7ae7d56240ec9f2936d382c6a4-5K/J,Ȩ92J e ؉vvPKfN9[S%+741c6c1cafffce1a8cdda838821cf826c0972731-13K/J,Ȩ3ZTv-PKueNߒ*7424020cb9399b4be1882943a7749cc95f6619d5-3K/J,ȨvtrtѵPK&oeN%+7429e9b917e887d675199d5a9c4855dcd39b6069-10s/J,Ȩѱ0JhPKbNX5'+7454fd29ca8ad324671c6388134e14ec25a22c36-42K/J,Ȩ.)ʬP&DPKeN& *746f277d801762d4f453cecfcea2fd1109085542-4K/J,Ȩ%~/@صPKkdN 0]+746f7cc95807bc71af04516fd43498a1dfb5272e-14K/J,ȨNPPK aNZN*7479fa7544ac9b226409114e9e9472e5c015dafe-9graph{subGrapd}PKUbN ԁ+7481177aef5080e31d1759e3ce33d1d2e2bd94da-41K/J,Ȩ.)*ҵD'kPK+74aaff1c2cfddecd42b101b324f63b7ad27023b0-14K/J,Ȩvt-PK{MgNP?)*74b5234a0ed1e547297eb599630eb2f4c8951977-2K/J,Ȩ$w ϯR[ PK OJdNc +74c7b62bfe09df2f31b13532df3a2a2ac6249cab-20graph{Subgra}PKXeN "+74f6991c0755b775667ed3fc11883dc95c0b7db6-24K/J,Ȩurr 2BkkkPKgNͥ6;*75049c680dc4375282650dd13c342e1763e7c636-4K/J,ȨL LPKlgN*7516f2619f6bf40695f09051ed1f6906e2b443b2-8K/J,ȨZ PK aN,z +7528d32fbeb3d26b27cf780541aa28c85cd57ca1-15graph{DigrΩ}PKӡaN-+7530a135b4f563c1565d62e5d0a5d322050259d8-19K/J,ȨCZ*PKNaN8*753722b67210b5d07dc6b789352837be6058892c-8K/J,ȨN/M/ DPK fNd3&*753b3ac48bab7b1e934b6b1f71d2d2bd1e614c75-5K/J,Ȩ "Y[ jPK JdNn+753f385fb5052ed78f84ee0b01e3b7bf4b5f0074-20graph{Subgrau}PK fN?0*75436d6aea6f024d0d67caac9a3d8bc2dca331f3-4Graph{{subgra_}}PKaNq1T+754a6907f0ff6d0face85d2f85a682e0a4e6ff02-19K/J,Ȩ.MrέEPKbN+755cb64583b657a4e8b3f52fe61f5568fb03c3ba-27K/J,Ȩ `PK KdNck+755d3f20d60c5d1a4da81ca18332ee4b76118ce5-14graph{{stricN}}PKNaN#84 F+757284c4ae63b4e7a2b5db981398b0153b348f4f-12K/J,Ȩ.~1|-Y[1_cWQ PK8eN֞/+75cf997698c34f85871550d6c421e9854d4962f6-14K/J,Ȩ.}-*&QjPKqbNK+75d995f833ff65375c04f1ac87c6cb4382f7af3c-38K/J,Ȩ.)LdѵPK qlgN["*75e50d77eea8f4a270ebeadc04956826c67f7037-9graph{{subGra͉}}PK LaN <f+75f224fb34c5501c25f1ac9c8d0bd529c2245a23-18graph{SubGrapΩ}PKYdfN/r3*75f87357bccc902088b1e96c66180030912aa9ed-3K/J,Ȩv҆PBYւiZ(W PKaN;*761a133ac7b3bc486b37c44f08cf81b593d4309c-2K/J,Ȩ..MrPKcN7M+761d67153e831943476f6443f136384ce38c464c-42K/J,Ȩ⒢Z f.T PKxeN*762ac96bbf77df9d24fc7c3437eab3e0dac7ad3e-4K/J,ȨNZPK aN P%+7644052e2afeaa2b1ea13e7e184a75e5c89fcfc6-15graph{{digra뿿}}PK bN~) +764c1d526ba94822ab385a242f56e5bbfe4c593b-20graph{STRE}PKV_fN$E+7650e8d02acb4bc3a361f923c4dd2bf27dc5848f-25K/J,ȨOIHd-2L6ZPK KdNh_ +768c25bfd3002c47f8eab59397e38971d372af61-30graph{DIGS}PKNgN6|A*769b144141cb33a79c6117e5de0b968d2579b129-3K/J,Ȩ$w ][ ghHm-PKeNݒ.y(76c1c297864b7d69c064af86024ff19a1d39834cK/J,Ȩ$b(F0"Gs PKaNB@ *76d68261ab5911868761e293c6eedca52c02daae-1KL/J,ȨPKYaN/+76d745310f377562291b7bea7d87d5d4738c21a5-29K/J,ȨZPKeN+76fd052881d7048f358cc53b2b485f5f5a21f6ba-34K/J,Ȩb02PK {bN% +770e9ab470d840900cc3c4cdd65cd2eac9b42dfc-37graph{{Stri}}PK+eNﶼ,9?+771046debf482c941d4c67afbc0420fac70fd5fa-23K/J,Ȩv3420500323BKS#33s#c3c# C#WWߵt-PK WgNꅿ+x(773b92f75a62bcaebb9867b51fecf9fde7a743feK/J,Ȩvtr 𯮆3kk΃+`뫭FPKKeNM%*773f3040afffbd009e6a5afa9c37a2251c1e98b8-6K/J,Ȩ.Mr/Rt-PK2fNz&*7763722e6203ca6eef7d617d15a46599df153a9e-5K/J,Ȩ 9\$`PKdN3(+778d0df3331560f1b3f035895d07c98cdf579af8-12K/J,Ȩ}-BBZPK%)bN(+7799b6b7596250bf185f028be4836f65286bccd2-29K/J,ȨvL/ʨEPK JdN[M +77a2c21270ad6dca849782ad9b23f18d592d9a55-20graph{Sua}PKfN-ʂR1*77c00214b6c080bc57a142675a92cd3b1450bfd7-6K/J,ȨNLZ(&V[[ PK&7bN+77d8dec84c82c7bf028e855c0483fa5da976297f-32K/J,Ȩ! R PK"gN +7808cae9ec0fcc9ceea9a2534dd50144f04964e5-17K/J,Ȩ..)L~-PKfNaS/*781a867a394e60a235c7d07e3fa101555035dde7-8K/J,ȨNMaPK PJdN= +783f655b22bb7536db032ffc60beeb11a1ee4fda-29graph{subGrp}PKbNe+78542cea782f1002bf73b3948d5623335b7bbd86-36s/J,Ȩ.MJ/R PKrjgNE "*785b9526ea824c4470d4c74c9a238cc960d669a6-6K/J,ȨF&斆 ljfdzPK eN9@+78688f26d9eaf9ade286745a337bd7560bd10a0e-25K/J,ȨBiPK KdNd,+787eeccaf62f0d072884bca993b052a902e9a13f-22graph{diGrap_}PKkgN}"*7880f1ba90d2cee9f272035f3102b66aaf8b1960-7K/J,Ȩ..MJDAIPKelbN'4+78b0af321b7c13cdc3781485f09c4cb3ad891772-37K/J,Ȩ.)LNRxZPK'qfNUd!+78c3e37d35f4a79d601d09fdda1e353403938f83-22K/J,ȨO)p­PK'aN*78c7ec558c0084714e2d6b0eb1df11e0bb199977-8K/J,Ȩv@PKǕaNX)*78dccc59c1b2b9eb5ab5037fa38d89b9b5caf89d-4K/J,ȨN5Z PK rfN (78e751266dc2f052bc26b25262a50721f2c1c218graph {h[t=0.575]} PKeNZ+78ec55f86b99bae50f9880ea0ba8fef11be03fe1-27K/J,Ȩv/J,PKaNg!+78ef57bfc543bf048cc0d9f885bc17418412efac-19K/J,Ȩ$+`ՂPKPfN**78ff45e8fcfc03f3ca1857eb87e6a83e6f213304-9K/J,ȨNMZPKP)eN^(+794278c960ba2d57ddb29202b796c0f39302a20d-23K/J,Ȩ.M2J1XPK aNk*(795ce3991b31bd0d37b937868e94f4c53147e2e7digraph {a:0b:1}PK[aNL\,+79b6b4032596fb1869eb76365f07d4dd1582c406-20K/J,Ȩ$+U PKKdNxBK+79c0a9e2c3fcca37d1dc9d7756b80de59ec78eb4-20K/J,ȨurS`TY" PK ƄfNF *79c17aff952a6a7cac73220b0de9c64a0176ba8d-5graph{<պ>}PKǙaN8k*79c4cad832c28fc42f8c69551c87a828ba1162f7-6K/J,ȨNL/2PKZaN~B+79f4073fbc43a242ab21a4337f2b653e7e5f577a-16K/J,ȨL UƄPKeNz*79fbc2d661f2b657393ee9a6abad5ea494307803-2K/J,Ȩ..)L&PKqeNoG*7a1c89768a4dddd6126b4ab501f209bbb605ad56-2K/J,Ȩ.M24g"X@P] $PDPK aNSV& *7a30daae201b600cfd986b830e36ef64aec5b20c-1digraph{E_}PK2gN,)$(7a3b1408c7e42d0c972f503cdc94e6dacbfda8f4K/J,Ȩvr PJ ƣM%@PKnfN%$*7a3d56c9e63e836451e84b68defc02bb1fbe5a2f-1K/J,Ȩvt2Z8PK gngN˷*7a458a04a9e83e5a80c2bb1420a36e4df42677c4-9graph{{digrʮ}}PKFZdN@]+7a4691de8b8457712e54ab34883a9ead5918886e-10K/J,ȨNL߰JPK &aNLA*7a64e55e5aa11e1fc39a712ffe141b7d09b2724f-4graph{{strictg}}PKfN_*7a665cbd2e8c116078d69eae050504cd2b45a005-8K/J,Ȩ9 PK0bN +7a8a7b148631627c997f613a501442d9caf2a4f3-28K/J,Ȩ t΅PPKdN1+7a8da460c6e4285a29bc7af356f30fb77c645202-19K/J,ȨurSPXXm-PKeN(#+7a95356e8542eae8fef18ba719da887f983641f8-28K/J,Ȩv/J,`LBPK paN~H *7a9dba67ce927eb15678a72c1916a6099f7d382e-3graph{E4}PK YaNT +7aa99dfd14feebc4243751c2eb4ba61b2a78a4a8-12graph{GR￿}PKʜaN+7aaab2915676a5d8926073e01d4720ff4bb4d5d7-14K/J,ȨvrtNPK JdNq +7aacf05247fafaab2df49e5b6ab73ceff19b4ac0-31graph{SUA}PKJcN+7ad9d3671f19ee3da77e8cfc2c9696cd584d9e63-39K/J,Ȩ"u/PKjaNi'+7adbb6495f21d9bf634fc7c0fa1142aba3d139c4-19K/J,Ȩvuq;R0nm-PKaNV*7adc5817ec77a9cdcc40ac712250bd12d159857b-9K/J,Ȩ"Z PK NfNm> *7ae33df5284d2703271f510fde03061fdd49244c-7graph{Str5}PKn)eNt6U$++7b17732a3ea6d87fb52935bcd55f3162b92268f1-22K/J,Ȩ.M1at-:PKA-cN'w1+7b27c0f12da6fe20162acaeb589febc1b768a6b0-30K/J,Ȩv b̮( PKɽfN/޼<*7b508c7b138c9a0c746465ff58c64370491b9f80-6K/J,ȨEj ]]PK%fN/*7b5c9e83c4809916d5a7f45c852206d2364ce45b-2K/J,Ȩvt2jLѢZ83& B8.JJP&PK fNё*7b77db1fadb4445386dd7728b6d0182c2d0e3d77-1graph{{DIGRAe}}PK}bNl2+7b8ba2d99ce0df3bd7f6f42dfd0f9ef6ee430cb0-30K/J,Ȩ..MJ0V-TPKveNEss*7b9ad2ce1c58ef7af26b5daef791fc1995816444-3K/J,ȨOV-PKCeNO~*7bac6d7e9084e661a6fc04df42a920a69a297ff7-2K/J,Ȩ.Mr/SʻPK5IdN%+7bb0faba272900fdaecb999b39f779680ff21387-17K/J,Ȩ⒢ZY[PKaN}Y3+7bbe76f83bb650235ab79e66e57d04244993a2dd-11K/J,ȨNj$] @ pqPK .bNg +7beb2b9f5b8635f61c9ab9b74c6b337c185c4a77-26graph{STRIC0}PK fNU*7beff40b463075b91323ffa6520df1742209b379-8K/J,Ȩ..)4P PKaNǺ$=*7bfc067edadafdaed89c1d87a7fd176c7cecfcd1-9K/J,Ȩ?Za!ePKJdN+7c086c2b614fd463b5c9097554f1ca77623b4343-17K/J,ȨBH PKKdN TX*7c101881c31e6e96c9cb944b665f6bea3973077c-1KL/J,Ȩ3ΰ3,`ZPKeNΛ+7c67a3ad86621b1d9e0d1d2dc920f180ebeb1395-21K/J,ȨN/pF-PK AfN +7c71a5cf20828f69c67e6222ac9b875f4d944f2f-36graph{Dir}PK :aN9Pb *7c739ecb967bb6bbec45597037f9a8f20664111e-4graph{Stu}PKvaNac+7c77fd6dee1477d0bc61ef6b6721a47aa4760d9b-15K/J,ȨvrPKfNyX1*7c89afbc0d9cb2df394f89ffb3074ee0ee7d5702-9K/J,Ȩ9wvvPKXeN0.w(7cd39c69745c567341b7f2e04c66c4ef2ace72d0K/J,ȨNt7յյ@ڴB%k᪐aY0$PK$bN'+7cec684cbf70870196c720bc9e0c969595f0bfd3-33K/J,Ȩ.b(U[ P6PK aN,A*7d0043b65c0a87bc3930d0985047dbe456a14010-9graph{subgrap￿}PKfN@*7d3d9c6906d455be77546c227f6e82359d01dbd5-5s/J,Ȩ..MJZPK dNI +7d3f18a64e25defac1f0b4bb365b564929162ca6-27K/J,ȨvMIOPK&bNhfe+7d46814bd75ba4f226911e74143577ee1e85da80-36K/J,ȨյFPKeN/!+7d47525f47b49c13203bf1f4e5273deca3c8d327-25K/J,ȨWw0Q[`PKkgN!*7d4b4b9c97e7a64c7b084d2bcad9ac757bf20da5-2K/J,Ȩ..ME"!ZPKPgNw(7d51cb509503ec2b237fd861bf97489b6a61d030K/J,ȨNt/JL`*PKfN6/9(+7d78cb1ffc6d35132d18859bf74981278172c15b-11K/J,Ȩ..)4E" !Z0PK eNC *7da2d48eb0e941708036cbb6221ac5b75a366b2e-1graph{ߍ_ߍ_}PKaN2n+7dbd197db6470f7f981678cd9d520e5cc8e2fc83-13K/J,Ȩvvt`PKEdN*5+7dd05ca3dc8ca213cf6ff5a76380a660719af9f0-16K/J,Ȩ..)ʬh,lPK bN,O+7e0fdf9c56b1280f45718f9f266376538e3ba62b-23graph{STs{STe}}PKaNyE%+7e31c1b1b1d2c13bd7d798a2a7323ae0040a7618-17K/J,ȨהPKdNNo+7e31d659b942b42bc54c2c97de49e79a76db56aa-12K/J,Ȩu \ PKifN``!+7e5617211f5dba6b4ab04122b59f88dde4492022-29K/J,ȨVJQJ 6$\PKdNr]!+7e6911fa3d3b7043acca80ce2601b5fd34bb9bf7-21K/J,ȨNt/H,0Y PK8gNN6!(7e6f4c11c012aa651e766e461b2b4d4ca19f963aK/J,ȨѦ`][ PKKdN^!vC+7e8f8ed4ecd494a8e5f291c7df19353ab71a693c-43K/J,Ȩ.MJt?EfPKXbNԳ?+7e91dd38ad66fa7fffcfcdd8392fd3f8cc7ba512-35K/J,Ȩvvu0pa$PK1bN_ %+7e956187d4b1e5f7d01d64c87eb5dfaa65868561-23K/J,Ȩ `U[ PK aNz +7eb084807b23ee7ac78d17899af537e1b3e60367-12graph{GRAPA}PK WaN!h *7edde21836dcfc9a0d3e0a27addc0e118a72f40e-7graph{{GRA}}PK NbN  +7ee838262348f08d0558228346dc812cdfa5d737-22graph{STR￿}PKΪfN*+7efbe514c8a0e15cf0f32d38400ef86e65771e44-17K/J,Ȩ.U kPK:3cNWKGC+7f185eae45ec6a561eeb3fd8312621f6a9d40a4a-29K/J,Ȩvt/JEPKѢfNg*7f38fde1d97662cd7be60a9a155675136d28ec92-4K/J,Ȩ.. ZPK9bNoݻ!+7f42af99208c1085538160b052dcc6d43d2110b1-29K/J,ȨvMIGE$P PK58eNg?%*7f5039e5d90f8fe48c6b3116f4a1a6ffad656902-8K/J,Ȩ.MSLB)PK JdNe *7f662020b5d30f40a53f64f85e8d1e40516c676a-2graph{G_}PKxeNp%*7f74eab8d97d281b9407fba2081d6c38857eb93a-1K/J,ȨLtY @:PKgN ]Ϋ6(7f7e02c5a6c7ecd896d99738cb355074afffea66K/J,ȨWwZ(  @0bQe)Ԣ6vPK aN&7 *7f7e6d430c7b4832d283be48564112e352ebad69-1graph{subN}PK dgNGư *7f8231920aec3f5643f8783a21a5412666519222-3graph{strn}PK ӚaN/l(7fa269db0b57f314a850852daebd8906c27aa759graph{/**/}PKfN~9 *7fc359225972b5ebd72dc39ceb6cfad372262753-1K/J,ȨQPK kdNGJ8 *7fc90586d16c5145dde689916eb64b32b1fd8c6a-9graph{SUBH}PK]eNu$(7fd2002cfe2949c11b15eb0678ef2d663ae528b0K/J,ȨNtPKřaNX*7fd545bcdb7e982caa73169e85a1e509759464aa-9K/J,Ȩvr|wo-PKϛaN+7fe274ea394d30ef73d7b7fc697232404b510985-13K/J,Ȩvr PPKLgNkec*80107f5fe3d99428e9fe91d6ab58167f5a2ebc2f-1K/J,Ȩ$w ۯ PK cNn,r;1+801311eb506c8ed05ef8c0d4bb4c10565ee142b8-38K/J,ȨNMIG#jkPKu?bNU+801ef9b341fd2e245df00b5a2ef31b32c18ea710-36K/J,ȨL ӲLBPKcN}A+80466c04188aae5e091d35b37ef459aa585d4a9b-34K/J,ȨvMI7P PKd+gNZw*804b86430fba6ed56edca0a3572bdc5cd2449b5b-8K/J,ȨNɴڔLZPKlgNT*80513d23465060a7f6548db3ead56eb1d378c3a0-9K/J,ȨNZPK aN+805d27efe284ed047b83f7db8032566e228a3c0c-19graph{SubG￿}PKjdNZhw)+805f5fe58ae2da07a5f374eed38b45ad61bb4096-32K/J,Ȩvt/SY PKbN?c1+80616dad0c9617cb66bcbeb1efaef290c667f8ce-24K/J,Ȩ r`& PKĞaN)h+807aa427e99e0dd88926d0720fd1db948fe3fd5d-15K/J,Ȩvt-qkPK }fNhU+807febe13afed872fe3687ae5810f8a5fa8dff05-10graph{{{DIGR_}}}PK7KdNƥ9*81494fc4b8ee60780c5e8afabcbf6c43dbfb0055-2K/J,Ȩ..MkePKndN_z#+814d50273d89a60921b14418e8a6ee52cc6e460f-19K/J,ȨOy?EPKyleN!*81610d4684dcd08530db2dc07ea4e37642423440-9s/J,Ȩѱd-PKeNZj+81bc05d2f3e832631a40b6eee163077827dc2957-28K/J,Ȩ"PK6eN>o)A+81ebbcfd8acb24021c1fc7992e2343d3175033e0-36K/J,ȨvtrNl*PKL/bN \&2+81ed6b096307a63b4a837b57493600028cd10792-36K/J,ȨN/zR[ _~j )PK !+8704e15d3f69f4d117415a87c8a2bc936244ce83-18K/J,ȨNt2jA PK dNz*87077747f6c0fb0aac69f884a94c2015d4dbf090-4graph{""[diGraA=""]}PKbNCSr++8709a9753badf42f012e6e8aadcbe0a881283f42-39K/J,Ȩ.)LR<7PK BbN +870a1889cd979b1f4485f9e4d7172927a8e381ec-40graph{ea{ea""ea}}PKQfN(=+8710578511d9a2b104d8d4cd5ed686c9a7b04d68-32K/J,ȨV?߿H/!c`BQ d$ů"@"51`jPKJ-bN%+872c72247ddf699988183d35462573975e5b660a-31K/J,ȨҤPKJneNPj-(872cc69765b7e3a16a1f75c07ebed8005c5bf400K/J,Ȩ.M24V[`PK fNvS+8747def6cf063087e1f630f9e5e6135e3de0734b-10graph{{Edge_}}PK dN+874bceedce5609203db0067d69059cdcb5b45b53-20graph{{SUBGRAP0}}PK aNB *875eeb58847d8266c3cb3699b52f7cbc2bbb8060-5graph{dS{dG}}PKaNVn+87692b2f870d570cbd49aa4a14fb7b97fc84d3b2-20K/J,ȨO)`PK laNLw& +87710ce3e6d951807cff7cbceaa92c3a4fec636c-19graph{{{ED}}}PK&bN+879e496773ea19a9c1ff16a49fd1ab95c1aec2bb-35K/J,ȨZ "PK`kgN~*87aee811c2618d915d99f830d297cd0c4ec3560b-7K/J,ȨNL/PKbN5m%+87b432e3e9bb94bb2f0a52f170235d7f0dfd78a1-29KL/J,Ȩv׵sG&j]` PKaN9*87b968b75435dd1a5d7273c701e765e3ddcc8d50-6K/J,ȨNtG–@PK 1eN+87be9278a68d20335661ec8a1808d76a84b4e55d-16graph{{<<=><=>>}}PK cN>L +87c94ec52fa96277e96df9edbc5e16ea7120897b-16graph{"\I\#"}PK8bNɹ+87d909e5838ac8be60ff28471b5facbc66ebb73f-29K/J,Ȩv b0 PKieN,*87f45389c8e7f072cbe2dabd2f7a983a91919fe8-7K/J,Ȩѱ PK JdN@+88020be1b031b3d8e90133310ff96881ce4a62b0-31graph{{DiGrap}}PK jaNPw*8818f4f29e87c4df92fc34118c28bda254e3e078-8graph{"\￿."}PK(gN0O(882336a067173cf9f6e13199d6420e6ff37393dbK/J,Ȩ.MF"D-YxUԂTPK UbgN(7 *8874b9ae325fae070a322212b2294de61fffe5d0-5graph{gra}PK gN*887e7b1f425524f62369938aacaa8d6ced477194-1K/J,Ȩ..)L.R0n-PK aN3 *888470f64468d6224acdf528b833bcdd5aeac147-5graph{diGra}PK YpgNEO+88a624f6617861e15821c3424056760b7f2d967d-13graph{<<é>>}PKmgNP?c*88a742a3b3901620176c48c89d86698500831b1b-2KL/J,ȨNαQ S҉6.v @\rP9}T1 ˱URӵKur ZPK%gN0*88c79082471fe2512fc96dc614543cd8089cedd5-3K/J,ȨvJBŵPKdNua+88cafa066ac5fe4442c28d79f114064234607fe8-32K/J,ȨLZ $jkkPKbN s#(+88d204441f43133d21d58c9ddcc478f6c5292618-36K/J,ȨԔt^[ PKaNM*891352f756695704f5a3f9450bc19ca6b562dff1-9K/J,ȨvZPKaN0*8915fec8b421d8375e9cfd3c9b1d34ffda13edd7-7K/J,ȨY`:=PKѪdN.+8929502aec3e3167a70ff4a80237e668d65aafa4-18K/J,Ȩurw PKdNW+892ddabda03dd110883d7852cbd68786f26f6312-22K/J,Ȩvr pTPKaNE+893dd6baede02e6d05be32d3a33410ca8f3ba0c3-13K/J,ȨNL/@2DkkL PKbdN)+8952c0cf92ba21a5f9051bc32da6dfeda742014b-43s/J,Ȩ.Mr wZPK[fN m*896eb2a063370cf58f58eade68a1627c931042e3-7s/J,Ȩ."] PK%CeNXɳ;*897d345ef24b831e955bcddd445d8b39c5861cc5-2K/J,Ȩ.Mr/J,2J0 PK.bNSWB-+899da24a1afc174c30fe6fc2de6648b99a6ff450-32K/J,Ȩ..MJ/zy?U a_ e-_ PKaN 0+89b015e83598cdf0ad990a0b909e134a549f4e4f-20K/J,ȨWZ0Q[ PKaN2 %+8a0c93e44e7ab83a71e5246d5a170b8f361c27f0-13K/J,ȨvcQ[PK aN iE +8a208d0429705fe7c029c7584c56f69d74d7514f-28graph{no{no}}PKbNR=\'+8a2492a4fd11a05a70e8bdbee7721e898c9fea9c-31K/J,ȨvMIV5 &jPK+ifN$(+8a272332ab59a4c28ba46979a5b5808d4ec49f9e-38K/J,ȨurP6*U PK gNH+Q*8a420c88414c6a0dead440ea49a14cee4a758486-1K/J,ȨV7777,OL̲(7 t77, 6-5 1J* 0w7rt( U5 PKbN(i+8a43e53da8daf7aeea4319c5bea65d2ebf720f1f-30KL/J,Ȩvr׵sGjkPKqbND0+8a58c106a9816960a6c2dd10edea47cff8662f34-31K/J,Ȩ..-pF-Z8PK ageN9 Q>*8a9ef8e8bf8218ebc9bc64d932ff8830d8b7d5a8-1graph{{NO{}NO}}PK@bN\+8ace78478d2e789e70c61ab5b0b0bf20552ca820-37K/J,ȨNtwPKaNN+8ade284edd86955d6400ac2fee0ce853e4e5fd49-26K/J,ȨW2Y PKaN |@+8b0e4f2c7f9206c43f7226ba35dfd189d4f77f1a-17K/J,Ȩ !0] PKSaNO]^*8b118eaa9ce18191e11d76c389e339889b2227f5-6K/J,ȨNt/JPK:fN!+8b212040712a41727239cea4bdca190e0a7da3bf-36K/J,Ȩur6TPK aNiZ +8b46a74f6625379b0aa6fabdc614efb8fe96f698-12graph{su￞}PK dN~l+8b7b1a93abf2f1edeeb700ab07a09a810cc3af1f-28K/J,ȨvMIOEPK RaN?# *8b900f7c65a32ec8053d5b9056bfe3a48a217c73-4graph{nod}PKOcN!(8bad7816b991492b3e8452207887766de3db508cK/J,ȨNL/ ZPKdNʏ+8bad9beca328900f65761e22540b92541b7e64ec-21K/J,Ȩurr 03jkPKdNِ *8bba9d131a05cfa9f3f0418b7e1648fa013740c9-2KL/J,ȨVRNtURPK$geN,++8bbad9a6d3abbe6f5eeaf406249a3dcfdcc3216d-26K/J,ȨvubkD-PK TgN@-=*8bd56b3f5c678505417ae89760dc50d4fc9356a6-3K/J,Ȩ.Mr/J%Q PK aNx+8c058b058da4b90e9c261a773eec684e3ff846d9-12graph{{DIGRAT}}PKbNH<+8c1726017a5e4f2fa95a7fde463af65a085cfb14-21K/J,Ȩ aPK#bN1y+8c1aab345830fad18d570d30b5435b842adfdef9-29K/J,Ȩ..MJ/z-PKQfNe&%r*8c372c9e804929603ab98b7ef40e8379130ea89a-2K/J,Ȩvt2j,Zl&T PKؔaN#(8c376c0497502baf1109e70b6a8c62eedca5063eKL/J,Ȩv1]jPKpYeNX.(8c55ad88ee80a837cfaa99098ee9db9b04a93cefK/J,Ȩv hDm-\PK XdNgzX*8c641a85f117cda698234124c2ab170ed31aabaa-8graph{{{digr}}}PK7aNMB*8ca41bf6f55b45d176a9140cc22e0746b3e5a8ab-9K/J,ȨVy?A)ZPK gNMǂM*8ca82c1c8c35eb8d5f44c8119b1008619cd212e3-6K/J,ȨvtrL0>LJcPKyaN+8cafb870c129497a8ad6ddf315f64d77c8c0adef-24K/J,ȨvuZ PKHgNs"*8cd10e9efc35ad1d66151cb52c2af430fa499254-3K/J,Ȩ..Z] PKHbNf+8cfecf30d560e7b0b267b7da457af5dcaa6c52c8-23K/J,Ȩ zo?RPKaN#*8d0cefcb2ea748042ff7aef30f6d541565893447-4KL/J,ȨOIMQ)vHTj-PK dN֐m#+8d1a5abed22d7dde2682be65d9a1d82d23d81eb1-25K/J,Ȩ0\[[ePKcNb)7+8d23968390660ca55a5085054622d974327bced2-35K/J,ȨL 3JqkT:PKSgNjs+*8d3370048be07af2d6520dce71eca6c87f988766-2K/J,ȨNt/JLR`:ʅjPKfNr{*8d3f7f35c9cf286f34bd3e5dab1246760bfececa-4s/J,Ȩ.MJ/20nm-PK dNe+8d8374c1b5d633f7eb76ddc02cd53482885abc7b-19graph{{SUBGRA_}}PKʅeNAb#+8d86ac9542f6d1b2042f41549f930ea4c44711fa-12K/J,ȨN5Y &$PKbbN#+8d9f6cbb479be82e23b4516277f3c71041e5daab-40K/J,Ȩ"Z `BHPKXfNz/+8dad6d20f76d4258fa6ed0ef5d73a049b527c473-12K/J,Ȩ..)LR`ʮEPKf^fNv +8db994b8689e4bf6f1d48140ec89437797cb6c12-33K/J,ȨNL.`$R PKcdNa;!+8dbff7ff2d644d7bf0b6a33202183dcad3d61ccd-25K/J,ȨLw HZPK agNًts *8dc7de7140afeb1d30971b92081885fed451eb31-3graph{Edg}PKUgN|MI(8ddfed25db16759c3d1a8d12b09bda5726c04eedK/J,ȨP' Gj@&Sb W QUdjS'82 ΁gZ04 TœPK@cN't+8df2fb1899f57ebb1b9e9416226747b6a0e13d0f-34K/J,Ȩvt7@PKcN +8df46a67ec3098e07cf134b7026ae54fd214afbe-43K/J,Ȩ.MJLPKeN !+8e35b111a9f36ade36d4e6bd3e6ed3697e9eefa5-18K/J,Ȱ"jPK rbN{y +8e7fe6544b7a217045b18db3b7320023dbf5c548-31graph{{DN}DY}PKeN\}-(8ebbd59097530f37927e3e5e316754f21170d4fcK/J,ȨvPJբPKefNŽ9*8ee5366e2dc491312bc81fe4656042c919bebbfe-5s/J,Ȩ..MJ2at-%PKJdNڎ+8eeeffd73fd023fccbb5e725bf3c5d035b211851-20K/J,Ȩ.M1kPKfNor#'*8ef21bb4d927e9da6499b97bbf90eef709316a2a-7K/J,Ȩ9jPKicNxT+8ef413deb81dd6a0d066075ca20d03f0477627cf-33K/J,Ȩ.)PKJdNq Qb(8f01b37ada47467f87ff9d957f4c12df391183d7KL/J,Pp..M0 u 9a,cN a bs"QRPJATEfׂPmpI5aBL9Afmk R@y ׈H@PK bN . +8f0a2ce66948ae90b241a559086793f5b5349907-36graph{Stri8}PK JdN _*8f13a57e4f91a2944be2bb5b1177f3f34f6a087e-2# graph{{" "# }}PKbN{+8f36a39698d69ff702ac8c3df89bf5043edd370a-35s/J,Ȩ.MJ/PPKjgNm*8f37e947b37bc8be1dc0129570c47a33973e1386-6K/J,Ȩ..MJ PK2eN"m(8f5d4b3dc7c4380fed285d841300f2b1d4c7feffK/J,Ȩ$ZW T<0PKaNnU+8f6568ea0680fa35082e030277a7ac06e8f92d10-14K/J,ȨNvutbPKfN)l$+8f7c00954915b67dc11064cdef357fc26aa21db4-13K/J,Ȩ;I4dW PKbN[|$+8f9ce036a8842abfec380655ef3ff351e018ce4c-23K/J,Ȩ b0aPKaN,%+8fa7e5831cc812ccb457a3c81d69b410ba63a82b-19K/J,ȨvuqZPKaN+8fc2240ad2e1c74960474312c1ccdcc3a136a5dc-14K/J,Ȩ.MrPKbbN1+8fc8a50a0640f7d09696281c4aefb57cb39d9cd4-26K/J,Ȩ PKfN8<*8fca3d36b31bf4a50015591d2b0b28674108ce67-9K/J,Ȩ..Mr/RPPKdND +8fcea3de823e9f5570e9b3f21a55d4e48b07a78f-13K/J,Ȩv)PK=ddNrf(8fd937ca91d3801873941c710b84ab86a2b61a5be 0 "xvR?Z{Ah]QM}6P ?5>3EiWQ*rm8ȷ(AAC>W;8 ;t}q̐{o΄O r{C4I(mK¢P4J*91335fb3d3c6c1d23b6478e58c791e94dc426d39-9K/J,Ȩ6050207334461Cb[@!ssT!ZPK,aNGU*91350f4e88d8d9d1a387b1c35a6c3ee78d367484-3KL/J,ȨOIMQ)v`^-PKbNj7+9138265f7c0f6c574dddbbeac431842fd93fbc37-42K/J,Ȩ.)LQPJkPK9dN`k#+914e97c34b93384aff1dc89185825fdf8d142c8c-22K/J,ȨvuqZ PKbNӵ˟+91721b774c4c22a01ac57b8e26fdd1207b7b4f35-24K/J,Ȩ)ZPKFgN%%\*9181b1535bf9e0d2fefa5d13e2e9ea741a742466-2KL/J,ȨvյCAPKsqeNxj**9183ecbcd21af259fb4f450f8ff47f40a54e4ab1-1K/J,ȨvtrGPK]gNΉ+919b1efaede07181e434a50a2fab5c6bcd9caeed-55K/J,Ȩ$Z(PKaNjU,+919e3ed1a7060790ad2d066c4847062adaa2b80a-13K/J,ȨvvB g!@&PK aN" +91a817d02a97ece03bac7742ffbabef045a84405-22graph{NO_}PKaN;q*91ae816a86af526b7acc49ea320c58baf95c0427-2K/J,Ȩ^ZPKaN>4I+91b5893d693575623a834fd82754d35b33bda318-19s/J,Ȩvtr RPKmgNv+*91c2fc5dc832adcf2ca3649bb2310081af69ad28-3KL/J,ȨNαq qAF ]l-PK:bNA#+91ed5b70c596bb2996a1f1fda2ef75cdc0327634-33K/J,Ȩv2`T-QPK fND *91fae8d10967cac2f0952e219ce94d510cdefa76-1graph{{dig0}}PK ZbN+920801cc128c70fdc48871f18f55364b8b136f3d-35graph{Stric￿}PKs8fN '*9208b703cf2ae1087751e23a012b1aad99d12b5b-7K/J,ȨOjY &B`PKaN*92244fb9f573e57506965140a3bc6a0d78c4f112-7K/J,ȨNL/2& ʨPKPeNd[*923026af0497524a7191d6b4b7d46c8bf9fba458-8K/J,Ȩv/V-PKXgNW!+924599bd34dda6bb8559607f0c64b782e0e79317-22K/J,ȨOZ Ԃ PKsFgN//+925344398831e41ff59719c01835f80e649e29ec-29K/J,Ȩ. Zd6 PKefNA+926dcc9bf3573c899c01a14e1c2e2d5891375c20-10s/J,Ȩ."``@)PK8mfNW,(926e95603ad6358c13f68bac308ec8b711768cb7K/J,ȨLZTm-vPKaN*92769124982aa7372934ab9bee14c0f646d90fb8-6K/J,ȨwIPK ׃fN*928d74b53d349b5a35b0b08537298fd88147a6b9-3graph{<<Ω>￿>}PK gN n"+930520479f0c98f74499e8afa21d02424b9ff533-42K/J,ȨEյ LPKdNhh*9317d86c3557de263825385c26fb18780c9d4140-5K/J,ȨѱPK |-bN+B^ +934c06ea3392abc9fdb2d87e7589fec0046563f3-26graph{STRICU}PK dN隋+93669d32d2c84118c2669dc4708aec81968dda52-20graph{{{gr_{}gr_}}}PK8jfNUTv(93776a95257f990bc01890d61c59cf0464dbead6K/J,Ȩv5aPK hmgN`+9391b00f3659e6acc5756c0618f62c9a176d5695-11graph{I""I<>I}PKeNR'*9393a6dcdaa913f1cd4b5b0345b271c50320f921-2K/J,ȨNtO 2PKaNYm(93a39c3c0e92cde5c6f864d0160d3975bfe7bec4K/J,Pp OI-.)RmSc!b9JJy `T TRtK*dmeBXoP(,TU B@.ZN0+Fh()PKbN:9/+93a8337cee85f44a802fa0533e0b7c7054b7fb9c-39K/J,Ȩ.)ʬEPKJdN˻+93b34e6d9d77fbb0955d4f820e38a8d0529cd39c-12K/J,Ȩvy?PK aN-ؐ+93d15b2a7d9958cf13a41c37a0a1ea6bc8675545-20graph{{NodN}NodF}PK cNz +93e3121029a693b2b88705250041e4341b63aa50-18graph{"\\3\\3"}PKdN d*93fc3afa484df9fef9f308411885ef57480abe5d-9K/J,Ȩ;kkPK gNq**9405a2b4391a27c37803cd4529e66f6a88ba7981-4K/J,ȨF.E`D$I IAmu-) D9PK magNA_ *940bafd8319cce5924aa52a4862a55b6bd122cb7-1digraph{ea}PKafNϘۚ$+940dc97a3c9934133db5fe6ab893bf705aa18f5c-25K/J,ȨVQ4TPK KdNۙ*9410a3fe6c90a56c361313188668274371087368-3graph{{DIGRAP3}}PK;ZdN&|m+941ee8441c383e96a0a304b10fb189b26e670e81-10K/J,ȨN7쯭PK dgN4M*94343f13e2d763495e12947a8aae0b70dcd155ec-1digraph{e5-6e7->e1}PKgN/g&W+9453025a30d19188e9aabef91a8cd4ef3961ff6a-42K/J,Ȩd-Ty y(PKCeNRh-+947ed86bfd1da4630a056818f73a86feab8959e9-21K/J,ȨNtg5^_ ø^mm-PK8bNg"+948b8ecdb1639fb807623b625d8635e830f98762-31K/J,Ȩv2T-PK.gN5;)*94a0c58b239aea3fe0530c312ef2af2ad08a05ad-2K/J,Ȩ 2BBPKgN+%y1+94ad3d1b07e2c4bb88776e6d1cebeff7b39128ea-57K/J,Ȩ.Mr/J1jkk! ZPKaNTj+94aeb8da2f17950cb92d818c10e6ea9cfda0f136-15K/J,P(v.vRPK"fNȥY*94b18314c3e2824d345fc64c0e6e0af6522b7ded-7K/J,Ȩ "(&BN) PK7"dNR^ O+94b68973efae8abbfb519e98c469c719f0bb944e-33K/J,Ȩv1Z k|s()] fՂPKNaN}*94b818417ddfc82c23c6affd86ab38070223861d-9K/J,Ȩw1V-PK5cN6+94c52402bcc3aac91a8a6ef80c984ad2500630a2-30K/J,Ȩvt/rPKfN -*95070a9a02a3bcf68c14a421d6af34c2fbac9826-8s/J,Ȩ..MJ2Z,BPK |SdNDQ*95114eeeb3df2c32e720207b2dd514129f49cc3f-4graph{{{diGrapS}}}PKaNE!*954eb9adcdbd87cc487fe048027eb42424f801a7-8K/J,ȨNL/2P6cT PK 4dNY *954f909d5d0534a10eb7cb32008c6d0c21311ced-1graph{/****/}PKBaeNY|+9566721833b5e6a05d1dde13ca77f16b3b6d538b-17K/J,ȨNt/J,RPKafN*956e78e58c560c27b85d3e05c04b568a7ab64d35-7K/J,Ȩurr pkkPK cN, +958ea928a4aa74bcdc42a754893397a98ab28504-32graph{Str_}PKEgN+959c5b9574f185c99659b57cf5f91ca84c77d26d-35K/J,ȨWZW'0U PK ¡aN+959d8ac2ef9f9f62b3b98b9bfa49d66f3fc39ccc-13graph{{s4 s5}}PK<)dNc +95a2c961cc3a51ec4adfc3f36980809c5f4c42d6-30K/J,ȨVzqL &T PK*dNڲK+95a44750e18af06e6e2e56c23ff6744f6f366439-28K/J,ȨVz$1b EAZIV/<4 lFDABDQT-Po1Psm VT PKeN6*95b0cf1822f865f471a367b61b2262da50a264f3-5SJ/J,ȨVRpFmm-PKdbfN%Y*95c7c2a36d4b65a7b86c72ddf1c404ab364eb0f6-5K/J,ȨLw Ȭj8. rJ%%FPKdNُcX+95fe82dda47a8d758af1de910370a03c36ec90a5-15K/J,ȨurP~m-PK dN *9610d4891a594c23b3f3e40f3fdc1628633f12de-7graph{Nod_}PKeNC<++961722fbbc5903d3b05518b77c6ac45adbb9e45a-22K/J,Ȩvt5޵BxPPKm;dNft*+962bd484db20dee834029880605f9af67edd9759-32K/J,ȨV~1?PB9PK0bNsn$+9642d26dda6bdf7dc4d823a8730cdefb409ddeb2-28K/J,Ȩ tP(Z PK.bgN*965ad8067d9c860fd3551754105f7b8b0ed4cb62-2K/J,ȨqZPK;gN+965fa2c0cfb1596f7a98fc7a8fe3afeffac090e4-33K/J,ȨVRZPKAeN=C+9661e0796c4e52845e2422bd81a72d643c3a9f49-25K/J,Ȩvr p S PKUbN,,8+967f35e56f8d1d5131c9befd53b44dd2d034a3a6-41K/J,Ȩ.)@\ ZLZPKaNa^+9681ad55e3fe936dd0af1537c8fb63aba09db2e0-27K/J,Ȩ?PK׹aN;+968e3acf2b1391fe7375a15564c65e97bd8083bc-29K/J,Ȩv9{kZPKUfN%J_+969eb844b085472b413c3c12c82950ce4ede2d73-11K/J,Ȩ..)LPv-PKgNr+Av(96ad43d2fb6c036116209ebead13958409a81d27UA 0 _%b,xAn-t,:\ h!kiRI]PMPBxPK dN@+96f203f9d686244b1199071e2db9d89fddb5ddf7-20graph{SUBGR￿}PKeN:3+96f291dfe208b3d5de82207b16bb373b4469bde1-22K/J,Ȩ.Z0g0PK`aN 4!+970c82d7cd7fd169c89ebccd7facf0d0003ead96-13K/J,Ȩvr (@"SkTm-PKNgNDXi*9750e10585438d45f1dd6a005a046b689bdb937c-3K/J,ȨNj!W[ PK AaN}y[ *9763543210aaab3f75d8ce6f86b5956d0533be8d-6graph{Diۊ}PK$gN"!_(97641c6b7ed8479209ea944295a84e6d4cb56776s/J,Ȩ.MJ/2յRJJpyPK bN/ +978ce28e5719c85ab16caa46837c7efef02d9d2b-20graph{STΩ}PKdcN+e59+979c057d7aac745a003f9a5eefcb8168f6c0b7c4-30K/J,ȨҤt0Q &h2PKaaN:ڠ$+97bc018875dadeafc4b41c702dded85377f7e6d7-15K/J,ȨvuHl0PKpfgN]k(97e1f08cf1ed655ae75dfdce71adb14282294773KL/J,ȨNα qtUpU2P  @`Zndi`dPnddlbd ThPgR\^R@3R@rlbtңt]PK3`eNA;*980280570143d36450e9f56403b70226b346fe93-8K/J,Ȩ$Z("n-@ PK nagNz Y *98053a8d848ccb7168ec4b592f697efcefff5b9a-1graph{edgd}PK,fN%I+980859a9c4dbf83a706a61e18b5c785b28e1b9f8-16K/J,ȨO PKeN’w*98259529905f89b27e1d19cdd572446f408e7602-1s/J,ȨҤZ0_[[ PK aNVq{?*9840763b4a2dd7f3115f56bcd386ab52bce65b83-1digraph{B:sw->G:sw}PKbN6(!+9843549ccd8e312049a6991f38c542bd4c7aed8f-33s/J,Ȩ.MJ/J2ja4PKDpfN(!+984461f4c9290ec3dfaf4f20467bc4575c4fe0c5-36K/J,ȨvL/ZPKfN{*98545ebe9c95598a3657f02406e7b2a096b7b09a-9K/J,Ȩya-:PKdN Ͻ*+9854ce08d6477df6fc94b427a06f575705f4c51b-27K/J,ȨvtߏĬ0_X[[ PK 4aN *98613a7952891edcb919e9740ac01260a5501ec7-7graph{{DiGrap8}}PK`aN P5+9876dca4083f92bdb3fe9f9327db25f2b5ab3a8b-16K/J,Ȩx0A PKz6gNcR?(9886cc9370ab34e77a9cbcdcc2c59bad4c1036a9K/J,Ȩvt2,j16vXDa4PKsZfNI *98ac3285911590fab30214c2e15a3817c6001b4b-2K/J,Ȩurr HvkAPKaN*98d3a50312b3c0c543d40275a96e090e5f021362-8K/J,ȨvraPKaN5Q%+98d8c361e3e9338b62b729bff9b32c52c64a6d3a-12K/J,ȨNy?2Y[LPK SaN *990b5231088e2f548aa0c043413bade54f3e3cdc-4graph{{NO}}PKeN}?l++990d4159a9d800682eab63dd427b32766ea18f17-20K/J,ȨOy?PPKeNTH+99235cde680854be26d82a6cc95dd982b6c2f3c6-15K/J,ȨZPK qaNX *992b8352ba96293267015a0e492a390abb897c37-3graph{E4؝}PK fNty+992e82cb1e89843587c83c521314bf0736ed470a-15graph{{{NU}NU}}PKgN2U|I2*9939b36f1b4c291bc2b61d0861e864a10ba1327c-1K/J,ȨNt2k0 y-PKaN5J+993e3aeaa40cb88f9a4e5bf7fbe7cee175c8baf2-12K/J,Ȩ..MJ "PK 1aN/@ *997a7398cae674e817fb7e486702fadea495c867-1digraph {edu}PKaN Q +99904610746651ebf3cfbae5dd638ba1b2b2bdc4-12K/J,ȨNM@bwm-PKbNNq+99e4582f48598d430a7434b4432db5fcb72b2566-35K/J,ȨԔZ(PKgNG>W0U*99e911bf2cf71cce9f2d6de1a51b61ff2d9337ea-1K/J,Ȩ777BxS 77DJJյյPKaN,-5+99f9ecaa4af42228e8516962cb3a321f41224761-17K/J,Ȩvt-FdkPK *;bN4#1+9a0e19693c56f94c33889e3fe8bc6fd4c618e5e9-30graph{{{Digp}Digg}}PKefN]M*9a46453e5220d9dd6963de268d5fe450a2fc54b5-2K/J,ȨWwWZ0 eC8d PK aN7Gm*9a5fad04cbc97fa57f8a42b0e254b0faece138c0-9graph{{DiGrapg}}PK+eNI'+9ab7b36b19a0c3fa94db107d67317032107a5479-20K/J,Ȩu2DYFPKogN3m*9ad2ee41c3530d799786fa011f66e7e6df53982b-4K/J,Ȩvtr 1jAPK jdN *9adbf5b2ae95817a0cde442ce64397c273ea8b30-8graph{SUBo}PKgN(*9ae99897b282cdf0f1fc6c451162974148127d7a-3K/J,Ȩvtr H1*kPKaNAϥ+9aec8fb35ab9b7e11c09ff2e439ef9ec84040d03-11K/J,Ȩv@PKsgN*9b1a9f8a6775c417a75c335299d6ec535a381c8e-3K/J,Ȩv++pf-PKqeNr^0+9b1e7036dde5481f20d4a08ce556753043745ece-42K/J,ȨԔTS8LC)`-PK8VgN[a(9b2e6e895384d2f12fa94762cea67fb55189573fK/J,Ȩ@P f¨j> tePKigN#q"*9b3bf65de8bb3333a48dfdac51cc56c1b0e5d9c7-2KL/J,ȨNαqC ;W;ZPKhgN#q"*9b3bf65de8bb3333a48dfdac51cc56c1b0e5d9c7-3KL/J,ȨNαqC ;W;ZPK2aNv+9b42d36b1677e99b114ae76cbe772a94cef48a99-21K/J,ȨWx(U &PKqeNؕ$*9b4719bf74c712638d3cca92d82b1e253ccbecbe-4KL/J,Ȩ.*.׵CPK bN]jO+9b4d139e0c74b9bccda8af171259bf893627179b-28K/J,Ȩ. ZkPK9gNca:(*9b6dd6724fa786df673e238c337545924901bae5-1K/J,ȨôDPKTyeNw#*9b772a154219383f66ef12b69d32d55999e41511-5K/J,ȨOH$DPK1MeNrg(*9bad4da2129f75d86d0b902e2f231ff93f3acb2a-2K/J,ȨvL/2PP2PK0eN'k!+9bba57949e6342662d5c5fb96cbf7b5dfc73c2cf-12K/J,Ȩ.}~-ܿS[ PK $dNCZ+9bc484cb44a8a953423334e57ffeefdc1d613f57-32K/J,Ȩv=Dւpm-PKB#gN?*9bc8b70ff8d8a3f1188dbb92567b78ea780c89f0-1K/J,Ȩvtr dj8.V[ PKaN[3+9bd7dda0c390e773eb1e10873e0867dd37de5a48-21K/J,Ȩ..Mr/PUP,\[ PK "cdNB{99(9be40ee69de04552524a67f46fc1dc6816713f84digraph{A:e->B:w C:o->D:se E:_->G:n H:e I:s J:w K:nw L:c}PK;eNi*9c27e266d2acfca9a8185a1fab43e2021d44442a-9K/J,Ȩ7ZPK [fNk *9c2a2045753b9f5be247e12c03a9c449dd9eff92-8graph{NOD￯}PKaNx<(9c2fb3496adde10108fd54382a0726a12e708ea8K/J,ȨVR%kiCXy3kPKcfN1*9c31c6d395f3906ddc2746a8b6ad4f85320d9038-4KL/J,Ȩv*׵sA&8=1jPK*dN :+9c3376f1106a8bf1c09f2d8373557ee74f9ba4a9-28K/J,ȨV?߿H!  VJPK:aNԆ-+9c352b9bd90d810f16889991d70d7fee6ecef292-13K/J,Ȩv|w/2PK gN *9c3e2a3890d0da0499d13ffb552054efab039134-1K/J,Ȩ..Mfm-PK  FeN"M*9c42ebfa3ab60cb6d1c84328153f7a97d1daf144-3graph{""[Grap8=""]}PKVHeNX<*9c51d485df1d4734c2c4526c3d90c7adaf027ef5-48a k%dTPKœaN 6i5*9c523fe5b6930cf3431e05f4682c2cd02b7b95ce-2K/J,ȨMNC%[ $2h l1Xb4~]tmjl-PK*bNv+9c57095a9a13fd060f617037e82d5da6c816c8e0-37K/J,Ȩbe PKnaNwrR$+9c746def380a6607c2050314382a857bd8621bdd-16K/J,Ȩvr 0lZPK teN\f%+9c860931b40f9e52efa73f9d755821617c596e6c-13graph{{S}S│}PKcNxy*+9c8b99ec788dcc916bc512a144895b685628f79a-40K/J,Ȩ.MJt-!PK}fNS<*9c97933a98e4fa69c5e540c0272bdc45f574bcf9-3K/J,ȨN,ZPK VdNh* +9caa796bbfc5ac047855df33a08c47c08dbad2ac-14graph{SUBGRp}PK NdN5b +9cacc28365fecf86837f73028d28919e1ac956d1-17graph{Sub￿}PKaN/hh(9cad776fef691278329d3a4a426872b6877afe39m; 0Ыb APBN Kl Luuվ[? (D<$(Gb=,B&ʐXO#KҐIIA6s(ˤ$My?PKbN%+9cfb4717ff20ec7f322865595d38b1ac476b2dae-28K/J,Ȩ LPK z-bN”+9d1b648709d002337aa73ffa22f7ce2f5d1252f8-26graph{STRICΌ}PKeNXZI+9d21551f756220dd82132ce4f84359eb7410eb85-18K/J,Ȩ.aPKbN NON+9d27ea86e16dea2b8a9060c5c122617655eefb70-41K/J,ȨLwZ0 c"Z E@PKP)gN]+9d3a39afc10ceba8f8eea309243e25d6c4eddb99-18K/J,Ȩj8Q PKg\eNg]/*9d709cd5f3e0211366227733d00eb15be632556a-6K/J,Ȩ$ZƭPKb_eN\!V#+9d7df6450ec6c4c11b4f66ec4731c62700ea0d8c-19K/J,ȨurQ`:BEPK9aN2w*9d800f166280521a0f1b3bc6f927285d04eb8ea9-4K/J,Ȩ?1LPK xeN *9d8e9dbe0326dbfa027027e2620da480875cf383-4K/J,ȨO`¯PKaNvU(9db50c4a0dafc46f486118fd542f0d7050321658K/J,Ȩ,.M0kLZPKCpeNr8*9dba54cbad395fba36ceb219eb7cfd603a7a2d2c-1K/J,Ȩ.M24g PKbaN҈xG;+9dbc16457767cb6f4ba002cba1ba7e744eadbe7e-15K/J,Ȩ..Mr/Jt1S-@-Q PKڲdNs+9dddbba704268d22a49672ffd35d97de05cb4635-24K/J,ȨvWpu3jkPKb!bN6+9de852cc94d837dcaf1316fbf2d484ab898805ec-27K/J,ȨvMIGEPK paN{ٜT*9df0c655c8ac8442ccfb25e6628defa6f2d1252d-2digraph{grвe}PKeNal**9df4ad12dda9238385fe20acb1723ca55495d548-2K/J,Ȩ..)LPPK@(eN{+9e0bdc7ebb851be52ea5cbb83112ed34caa78fd0-22K/J,Ȩ.M2Z PKfNp,*9e21e4757940fde1f46310e4812911946cd4e4f1-2K/J,Ȩ.MJPKeNM2(++9e230d6b85f236ac3b067b0946232c0329ea8ce0-23K/J,Ȩvt߰L_ `Z( PK^fN},++9e347110478ad0666ed7ee4af9b37b2803f9a066-24K/J,ȨOI` &@PKfN=s&{1*9e57486e8fe8258e52fb5c0da2255020f1b2e0eb-8K/J,Ȩy?*X[ PKRdNgtq*9e6cbe83a1f1776acc495ee4299815c2aa30af85-6K/J,Ȩѱ ʫPKcfN"*9e8b51659959963a8c4c3799a3bd9b75a777b605-4K/J,Ȩ..M1at-PK gNDv_a+9eb41322af7813f5e06d435fa6ae37d7d6cac01e-43K/J,ȨDjAU CCPPK0QfN\U#V(9eb8ab0cf36c9e1f0b6e4135fc471e18ec9862efK/J,ȨԔT ôEjkkgN.m*9eddaad5306803fd5d6b79f36655e0f534a274eb-2K/J,ȨN/jdעĆ) RPKfN,4(9ef5a99a56b7a6633c899aaf68ff87973c84f0fcK/J,ȨZ00N5PK$bŅA+9f064153909c9e37577cc4c4fb09f96ea43f491f-26K/J,Ȩ 2`&,`#+PKmgN*9f16e82788d74d163f67b2874cc10c4bf40398f8-2-0 Dg Sc;N"`* B 'xNn?s7)vr1 "}"b->5ŧVIYEz 9Շ#$%CD%I{ FXbv| \`]mS pWy<PK.{eNk>*9f3c35255cb1d42e5b7559e365f047faa6bd5985-2K/J,ȨW2Y H\ JPKeN'+9f7c28d80fefc95317b52f8a5f4c3c07b9b83f67-33K/J,Ȩvt `ҩBPKaN +9f86d43b8732c6da81fb09cc85e6309497964559-16K/J,ȨvrPKoieN*&*9f91ab0a3fd9062c3c99bbbf2dd32671c0846baf-3K/J,ȨZ P`PKkfN1*9f9bfed29a119bf71a5708b4358696bdb62b3898-2K/J,ȨW EFXPKeNXm )*9f9c64669375b03b34ac9572105de92f6f611576-3K/J,Ȩ⒢Z[[PKaN*9fa59b8d2ef82a71196a6f6a09e63aa71e26aa3c-9K/J,ȨN7M7RPKgN8G6*9fe962f4ad2912fa9ca85fe9343cf836e9558d8e-1K/J,ȨvjZ PKQbN^;+9ff0cbc38f4bdffd2ba1ca7dfc135c4bfa3feac6-39K/J,Ȩ.)*ҵPK!bNxID&+9ff3ea1875a80559df568e5e09a7456416a5824e-23K/J,Ȩ.Mr/@&kkATPK 0cNe?G+9ffc023f61c38b12db7bba0ff481bc59e742e768-27graph{{DiGrap_}}PKVcN꫓+a0284a20ad37367e35e9d293b997c144726eac49-24K/J,Ȩ.MrwP`2PKaNu#+a02c358477ce7af2213a6a9c9380c4d4c0c696ac-26K/J,Ȩ<sPKyaNc+a032452b6429f6789699c7b8fd7183892f2bb091-24K/J,Ȩ+a04afe955ae84ad2778d294830c39e2a884d2882-10graph{Subgr￿}PKcN;a#+a050040dd291e5bd2ffab5caf05526a0aeb321a9-33K/J,ȨvL/@#jkkTzm-PK&bN6+a065fc136b1a509a83c0aa7f644487db687b6f08-30K/J,ȨvjT-PK"fN{p +a07af26b233066e4a2f87cbd1965280852413e2d-10K/J,Ȩ9~,ȮPKaNDW*a082f84e6ab52df281e5a94afa9620ff983b52e8-6K/J,Ȩѩ`2PKKaN++a0a3b94ae84c1335b592a35de062a0d3a7a08a78-33K/J,ȨvZ0`PKcN@,/3+a0a8389977355db9c05cb74caf0ff06270164d34-41K/J,Ȩ⒢Z f2JPK4fNG$+a0b7e5988537f783391ee2cf5fa8cafea0a88809-10K/J,Ȩ;CvvPKkgNEJ*a0d9677695f507626773b7ca03b45882a0bb719b-8K/J,Ȩ..MJ@~rm-PK abNG/+a0e3b8174156e4a6de95654f1870cae7cfee8434-34Graph{{{Subgr}}}PKRcN5LT+a0e78e046d5d92fe65eac69a7fab1c67cd5e80ac-36K/J,Ȩ..)ʨFRj!PK)4gNY((*a0f571ee0f38337c5aafa603cbdf4457d1078a52-3s/J,ȨQѱXZ PK(gNv%*a10e6fd5d1e0abd32fb5966f07c0d05cef97186e-1K/J,Ȩ.Mr7JPKbNM!+a13a65b04135198854be1c4aaabd591c4b21fbd4-41K/J,Ȩ.)ʬAPK qfgN0ù *a164b8774c1481e1192ea8b1468aefee2e372e39-1digraph{DE}PKaN棕++a16abb0df56f336b64e14fd74e15af682f360c79-17K/J,Ȩvr 0v-e-PK1eN^Z*a1703145af845b348cd508f5e1b94f93a3d637fc-4SJ/J,ȨVRPKYeNW++a1703ddef60fe4fee45b46b9c80077a8944d542b-29K/J,Ȩ?&Y !PK bN>l7+a18a7e2519dc6bc02678f978a3a438aefbd98b4d-26digraph{D:_->G:_}PKfNX +a1981dcdb7652cd140c4954a29528ca02f0dbf8e-12K/J,ȨvtPvm-PK уfN:*a1c02f583a1f3c944a33407d82c440d26923d39b-5graph{<￿￿>}PKdN#1+a1c0805ca53929b628ecbc2dede70ee29ecb0497-22K/J,Ȩ˷@¬H`PK;eN/ ŝ*a1c457f157f4d0d744eab190d066c0b713173ecc-6K/J,ȨNt/J4PJJPK aNi v +a1d03d5616cc23a6c7a92af2fa65de7eb6254765-11graph{"\\\\"}PKgNG7K&*a1ea013e29757f9f44cafe8e14b9d84f8420fce3-4K/J,ȨF.E`D$IMXh0@PKaN,dv +a1ee62bb5d1a76f1b9b9244be3ce73e98388777d-34K/J,Ȩvt/z?:][[ PK agNӕZ *a210dd793ecd268b62b94c9b143e4b884a3896a6-3graph{Ed}PKaN!u+a217505d81c8d13e86bc844d0d62f7467f107d84-13K/J,ȨvZ PKթdN%+a233270bf96ce5d529c7945784e2d9c13df1bd09-17K/J,ȨurwPK#3bNN[p+a23818a751960f6ec5f08cf5dbbd5445fea1b6d6-29K/J,Ȩ tʳPK:gN|g2W(a275711434a3873ed0af26da6d3eeada5b51c1afK/J,ȨwxxxZ^!@T.R PKaN}r*a2c7bfdaf458a9af8c2e5c612ec7b1ee6f648dce-6K/J,ȨNtZPKEcdN-%(a2fbcd6a4f97204dba4c293c76bea1a278e8be96KL/J,PQT"[N];[%؁gPKaN+a30f3c5c17e21de58279ab8e49ebc6a566335749-16K/J,Ȩvt gPK(fN/*a31246263ad88869d42ca4f8a43084cb256bbbd0-6K/J,Ȩ..)Ldm-PK dN:= *a32f32bb228decf6e53914460cf896ab89f2b09c-8graph{SUB_}PK4dN>+a335ef5c1f76bc2156ab2c653291e7e7b93feaf4-30K/J,ȨVB/~?3^_ #c*ѯU vm T' (PKٰfN#'*a347e2608d7b677f3a6acf740e6bf3b3a6d56abf-4K/J,ȨNL7L@H PK aNn *a363932d479b9145f91e9f3f557526443f0ad775-4graph{diGrap}PK6\dNH!+a37e8fe77d9e26d1d5cfcdc8c9bf29c0f4bea803-11K/J,ȨNL߰PK&gNm(a38e9742aac82e88c90aed44ab72da8398886083K/J,Ȩ.Mr7EjkPKJdNݴ+a3b15415bf8d444f70ea5b3103385e68ba66e2da-30K/J,ȨvL߰JPKW)eNؚ#+a3b711a733952ca30f23b7dd17bd3d19df7ff081-11K/J,Ȩvz1}2DԂPKaN`+a3da8875c6199d131b2b966af94beadae12b20ba-20s/J,ȨvtJPKPgNQ(a3f01a72ff7d80ae1e06d4b514fd69921018c6f8K/J,Ȩ.Mr/J3jPKvcN-B+a3f32056a8505d4c48a3d9922c2f15628601c3da-36K/J,PHMIO "Da<PK eNߋ%+a441f88ee57c9dfc1323fa83b742793b01c3ae87-26K/J,ȨWw0Q[ĄPK OaN5+a453a69bc36c5a3edf010cdbc0c55e198d945d35-19graph{{{EDG_}}}PKǞaN_JpP+a4609c1a1f09b59c6bb7d9c1ed75244a75b10916-11K/J,ȨvRPKҬfN`4+a4783ae440ca78bb2acd92c1f6c9ff6565bc37e7-18K/J,ȨOU/Z(PK^dNri*a478d0d1f83dd95ffda4522fb90cf013634f0e18-9K/J,ȨNL/z߰FPKOaN"b/+a47c55f82d97744a6641a7f527da3dc648ecb620-14K/J,Ȩ ZբPK:-bNB+a4926b10eee58237552881025fb02ae0c073e943-35K/J,ȨN/z_ &lg~2@ PK aN _*a545ea589ca1692a0b9982ee40cddbff69647871-8graph{{digrai}}PKeNN+a5572c2b99023467e41eed183b7322f107b533fb-21K/J,ȨѵPK GadN0U{*a55ae1f4ab3d2c5c4ed67cbdceb3083931f5aa48-9graph{{{digr￿}}}PKmcNʹ0+a5688f5d9ce0893519969ac06d8e7b7a13357f97-35K/J,ȨNMIPKeN*a56adec16b990176b0a82268ca47c0a544105992-2K/J,Ȩ..)RPKSaN+a583f6127c7c427d7ba76a3ce55b2998f8eedbcf-13K/J,Ȩvr PKGaN;&N+a5a140f840be162f0cdd7acfef7ab35a556c5fc6-10K/J,ȨN7M7BP@PK kaNJu*a5a6f97a0a3d79238efeb381965843984235c6dc-4graph{"￿￿"}PK ofNXk*a5b34b0e40047dbc13fc1b055c218653ea5325c9-5Graph{{Subgr_}}PK aNF=K(a5cf5ab52be61e435c7d5bd6249bf0f832506205KL/J,P.αURPMJԵK*L2ԵK2ҵRRJb7E׮ʅHUPKp'eN )+a5e154ceddc197d19cc8d9f0ac9c863757f5fa4c-22K/J,Ȩ.M2PZT PKJ%eN+a60ab29bf9d401e3b16a774561c46ce4b9a927c0-16K/J,ȨN|p?\ĆPKgN,1*a60bb5a0c1667c810586b713e5244951fad6c21b-3K/J,ȨL ӤFC(tQ PKefN 3+a64470668a5526ed872d29165739fd111d010d08-35K/J,ȨurPK$ gN

eNXe)(a72f84f384e9a5c46062022f4cc333a5c0a3b510K/J,Ȩ.Mr/J,dhPKeN.*a731527b5d07ba3eb61df0d429d9bfe1335e4243-3K/J,Ȩ..)LPIm-PKYeN ,c!+a7338de59564bc31c0508c92300793cb7200dcd6-10K/J,ȨVz @0T PK $gNp&*a734f3fc92daece7b1f9f2d3a188cf58a3aec831-1digraph{G:c J:c}PK+aNTr*a7369b760f49f634b948328434b1ff69864fdb77-1KL/J,P.M"kPKaNhȏ5+a741ee112b96b0452ff00ebc20f1b230c4ddc3ec-10K/J,Ȩvt ̀bPKKeN!/1*a758e7b49e6ecd9a6235b53544ba24333a128dd6-5EXjPKaNK!+a758fd63f5c925c5ecccd1f52130584e5c955be2-22K/J,ȨעPKaN`k+a76943a7501020a4a478d96718fcd4d508b0b6a6-12K/J,ȨvcQ PK  aN.~N+a7ac42f185ce3f627511a739ebeaf96589e2f7f0-26graph{subGrapD}PK+aNğ+a7aea969538bb105f34dd53530f8b6c23efbcd1a-13K/J,Ȩvr HP0^-PKbNӖ9+a7af5a8a39ee058dcc27d2287e604f425f76c934-25K/J,Ȩ..MJ/ӵظ gPKaNP^$+a7b6d437ed432b8e9418a0993de8450b51ff1f09-15K/J,ȨvtaZQ !D-PK0eN-1?*a7bdc69db699ae8fa402d59b4dc953e39ab8c3fc-2s/J,ȨҤD8FZ PK:.eN5e}PK&gN3/+ab45901e445c7334fce50855a9919e8597e2fbaf-37K/J,ȨVR"PK4=eN'(ab486f5a01f444f9d6d0b1c13ff514db912be090K/J,ȨvL/2RPK(JgN[\H*ab607ce11744b7a1face44f2f0251d6e9a8cb78c-4K/J,ȨvM)SRrMŵpPKfN<ܶ;+aba254e60f7efce5d82844a5c34b31133ef43008-32K/J,ȨvMI`[PKdN7:+abb2ccb5377acb0879e3a7fe85b0e8bdd97b0a46-31K/J,ȨvMIOE"1jAU &PKBeNr+abb7d5569085ff4d841ece05d0cc42bc64793873-23K/J,ȨvwWpwRpPKeNs3f*abbf6843c2d771b844fbc00af53a0463aca3f9ff-3K/J,Ȩ%~/APK QJdNO9 +abcd02e47f6c49aa544fded4a9df1393238c776a-33graph{G￿}PKuaNuQ*abe01218a73ed5a18061b4f9045e19a6ba69a4f2-5K/J,ȨN/RD-PKXgNȺ-(abf015f39f610706f9c9227afe2f2ba412aa66b0K/J,Ȩvt2ZLPKaNOw *+abfc6779822241194acc148b1e3084203649286f-14K/J,ȨvvB c!@PK%dNh3)+ac0735632637f6f7cd554e312f284fbf93f2f94b-27K/J,ȨV.0~hdk & *PKZbNVd?+ac17b3b99a1cb21caaa28e044878dea3e0c78f64-39K/J,Ȩ.)J )$PK{eNU+ac2f16e31ffb46e510d187682f4a48ace3346473-41K/J,ȨEյ` «PKaNz!+ac3f03af50df4715a441ab2b47ab114d7de21f81-11K/J,ȨNyu5E&PKafN9-*ac4be534e4e24f8a9ca89727af69b8e60871b086-2K/J,Ȩv҆em-6CyPKfNMt*ac7548cb4a0f7a7782aa3bf472376cbecf82cbc5-3K/J,Ȩ.."Z PK PJdN +ac7c3749277a296d503ee83f13559b5c6e416c49-30graph{DIGRA_}PK aN; *ac82190df26121e40b688fb7ce560fcce81847a6-8graph{{g￿}}PKgN_%A*aca0b86c9daaaf2055d84ca84b02cc50228a9341-2K/J,ȨVJTRJ<Vz1\B)PK\gN)&9*aca4007454afd908d96f42b9ebce2e9067f5427c-1K/J,ȨN1N(ZPK*cN4\+aca94a772cc6e56133829452ec8898be3c48d54e-44K/J,Ȩ..MJPKdNr+acae4824db0e9d80c5d59dcd472b54a0c373d99d-10K/J,Ȩ}-PKL=dN~ݏ/+acbb9f9c7b8d537c896603ad827d249a94d6bce1-23K/J,Ȩ..MrIԂ 0PKaNZO%+acc54b587b31932a02aa17b3c5f9efd48f746bfc-27K/J,Ȩ~?T PKcNHC+ace8061822b2d7a441788684ff2c814e21478849-44K/J,Ȩ..)2ϲ$V XePKPfNNaQMY(ad08c92109bcc009c966212f15411b93d75e5977K/J,Ȩr.*/wKL wL( ˋw(OqiPK3bNL*ad8a71875e40cc8ee7086d3f144e9615f8c17b7f-5graph{{ス￿}}PK. gNHJ*ad90eb81ccf7b7910840420506c2ad9372fe192e-7K/J,Ȩ.*b gPK;(bN1+adab5296a4c32818b707a9b0a08625d8060920d1-37K/J,Ȩյ_ PPK*eNݶ!+adaf5816a60ddad2d85d52c0dff89e8d14d1082d-19K/J,Ȩu2(,ZPK ,aN 7*adaffb3dd2c1d5d0e83ee825743ad274535551d9-9graph{Digr￿}PKgN&@}:+adb453cc35eacbb27023fdcd0df8d624a7895338-54K/J,Ȩ$w Q h\PKfN_!{*adde5d3b006fcdc8412245ffefbf6e3fee6093e3-7K/J,Ȩ9;ZPK dN#*adef2c90f664973c8fdc27e8c4d7f194a4e23878-2graph{/**/}PKc bN:+adf6177400995faa8c76a060e1a709c287159bce-22K/J,ȨOZZPKfN)+adfb623e192d8b19995ac757d6f6b991f58cd92d-34K/J,P33RPK0eNd潘+ae0402004273791273239c6e21654c6aee3aad89-10K/J,Ȩ;kD-PKTeN 9(ae0bd5f161f2342b38221d4bb9b89d9de132d5f6K/J,Ȩurr 0Zl, PKidN>(aed71ca030e1866758060b9ae63257819d6e69c7digraph{A:ne->B:sw C->D:r:se E:_->F G:n H:e I:s J:w K:nw L:c} PKٓfNJV+aeebc77df7a0b0d0b8663ef0f8a677be72739c58-39K/J,Ȩv,ZPKaNw.*af0873420cf7c52468f3787436246f9125d6a756-3K/J,Ȩ "PK;fN}_-+af15a2913e334b5fd15f121cdc58bf4bb82ae13b-37K/J,ȨurH$xm-PKfNvr1+af22d400093f323251962c35b9009fa8afc49f66-19K/J,ȨZ0>PK.eNo|+af31f17a36e60a130770db4d1475b9a920993b5b-22K/J,Ȩ.M*PKMaNe+af37d89d88817e86201893beeec855884ff3ae9f-13K/J,Ȩv/*ѷ ;ZPKMaN^}+af5c74c22f5eab4d14423aefae23d60c6f867063-22K/J,ȨwZPKwfNh*af65a98dab9063bdf1867287699d72bbec832aed-2K/J,ȨNL7@PK-gNyѡC-*af696a970df610283e1e54c309815617832dda40-1K/J,Ȩvt/JLPZPK+eN& "+af7cdbae7b55194f11f3c794cb51e874cb94960f-24K/J,Ȩ.M24V PKoeN)!*af800d84f6475e952da6ed7ddafa747c58faf91a-2K/J,Ȩvtс0FPm-PKpaNP!+af9ed9e20d0dacbe113b9b479d6137a366640f42-19s/J,Ȩvuqw$kkPK 9mgNx\Z +afa1765f3d2eae0adba0c05fa9998b30fd54737c-10graph{{gr}gr}PK`bN^,+afbe31ae6d55857196c903e74cebbca45df0bf47-39K/J,Ȩ.1bZ84 PK eN +afc2e027bf8530a4bf66c6bd9fbb99846d9371d4-17graph{St_}PK>gN8(afc6d63368e48b42674bcf09a27dc6e043121cb1K/J,ȨOjY &BP1PKD)gN6ϱK(b005dadde32580035c55e8126566d2555795d187K/J,ȨvMIOFT-BEPKjeN,Y6+b00e7de947a1ccba3ef398c99d574ab7e0fbdd7f-16K/J,ȨPP BPKřaN%*b0331a971296a09f0ab88d875a621f004637dcf6-8K/J,Ȩv"ZPK2neN*b05095f33e9e038d5e74ff99f1954e971cf27b2d-8K/J,ȨvLV-PKxeNF*b06451bc7574ac8662b949b300aee8406438a365-4s/J,Ȩvtr%PKefNSr*b0675f844139ad4f7372dacd3036ac0ef299101a-5K/J,ȨNLZPK (aNss *b070763d16f33f724eb153945d2b7ede8d0119b7-3graph{{DiGi}}PKfNEŮ*b07cb9672345f12def19ecd9ec49326e50b88bd0-7K/J,ȨKLPK њaN'=_+b0851aa315b325ce64fed622f5dc2d640ea0694c-13graph{Grap}PK aNbl+b08a57f8c0adf76e76edb9cfeb5240cd6cff072b-10graph{{DIGR1}}PKQdNb *b0b1b22b639f2c449e1c2dc17e5062731254fe18-3K/J,Ȩ.Mr/JLѵ0PK aNM+b0efcd013d27a3c14daea4864d5be04dac71f23a-12graph{{DIGRAL}}PKJdNUt*b11a6292fcdaec8f0aa5f1284ae209956b3309b4-2KL/J,ȨvvKյs`PK eeNa+b11ae5e6f47e8521e04ca4c2829c7bea5899b50e-13graph{{st⿿}st}PKifNa%+b11e5a99ebd3a4ac86e821b2eef36cd0b3af023c-47K/J,Ȩ.ZF-PKZfN<s*b12027a53604b09b91346325fed3803dadfc9f97-5K/J,Ȱ9jPK bNB+b1254219c3b3e8f2ab9f67dc04192b38a3d04a7d-36K/J,Ȩ`ƪ,BPK gN*b1295e58a6a482774df3809327fe9e50812af01d-1digraph {Er{}Et->Et Et}PKG eN+!=#N+b14bc14bd71878ae9cc40714725137f5b3d108c0-29K/J,ȨLw pVu5 Z(PK OfN9)D*b1603a0673fbab09321dea8ac5de70cd48265a76-4Graph{{subgrap4}}PK %gNU0*b17cb909298b63798dcdaff761c73bc43f77542d-2K/J,ȨvJZPKwI+b6368c3b5357473f3992046cdbc78b1dbbb813b6-13K/J,ȨVJOUK-*IP/(qMIO崱QH,.K-WڈhXhC0i SPK aNpW>+b66468f23f0d85b03f38892c8a6d8ea87af4d3ff-10graph{SubGrap￿}PKvaNG%ϲ)+b66476040e85da33e53fb61f4f540b49a6034d7c-11K/J,ȨNuuk`JPK+JdNJ(b6665c5ab66937a646bf6f1d4a27fef6d8d28e94+.)L.QHL/J,ȨvԵsPK JaNӳr*b68a3650bc87c68d19b15d55ab75e8461612e399-8graph{{g3{}g2}}PKaNޱ+b6988125943fabd8c625bf045e821b9ef066041d-14K/J,Ȩvtr4RPK LdN}1r +b71604c8ff325412a659e612350e2abdde6879b7-17graph{diG￿}PK0fN'K+b736ce2e6e1b68cb143dae7276b2c01bd8dfdb17-32K/J,ȨVRRz1=߿HQAUpn W PPKDdN=-*b74a792d1bbab44d75fb37f64adf450efea7e4d6-4K/J,ȨOIQPK mgNҚb+b76da8d9212ff6422d7b8d74e3ee0855acd26f3f-11graph{{d}gu{diGrH}}PKIeNI*b77ef2a14a3dd88a2706c987623fd41661bbad1f-4K/J,Ȩ.Mr/ѵPK[fN;!+b78ea575bf19207b541b95188b2b0305a9e5a987-35K/J,ȨvuS(ZPKUeN]:9+b793d0e026424b59242bcbdda5d9eaab21903aa0-19K/J,Ȩur'(PKAdN +b7aba7ed0dcd3329033b9682f1a8b29e095ab590-23K/J,Ȩvr p ҽBPKˑfNMY!A*b7c3ea8c0e45822e4d50077ce3a719e806bb7da5-7K/J,ȨQz Z cPKaN**b7df6a68167b4b9826c2b2cec94db91429e5d3b0-8K/J,Ȩ.~-PKfN*]*b7f51538a9bd9d9e7dd38e73c793eab979238ae1-4K/J,Ȩ..)LP0+XePKgeNF/*b801d0b0236bafcd43ca57f45b7c27ea095c60ac-5K/J,Ȩ%~/\LPKxeND-*b8027e8b1e6133f035625c2a7b05eaf1d25d8788-1K/J,ȨW2Y[[ "1PKdNh++b806d5e41c7b56eac9d1430f678998260108f6cb-41K/J,Ȩ.MJt?dPK9bN)#+b80f25f0a10dfcdea6f4475eb8295535811b8e85-30K/J,ȨvPPK eND+b821c28d17956306ad0f6321e38ea203a56528a0-20graph{grap￿}PKɔaN܏M4(b824d3b4613ea64c12d56207dfd07ccff19ec086=I BA D2ݭ]$Py__ $piJCe|Z(;dbu`Iš?5Ҍ.`8JR40BMTVB5~SSq4>}PK DdN['z*b91be600de23ea7a9aff15813c3d48261ed93937-3graph{_[f=DiGra9]}PK5eNƲ+b941b84a5ec443cde89a5effe57eb463b64b8178-11K/J,Ȩ?PK fNp;# *b9531cfbaf51ce39f495494291d7fd82f2c001db-9graph{<<©><¸>>}PK7bN~*+b985df64eed48378c1846636b24335a58b5859fb-30K/J,Ȩ..-@ kkkPK\fN:+b9903ba5b8c2883cf6e39959cc53a0ad2371cdcf-11K/J,Ȩ..)ʌG&kkkPKSeNC!+b994630428ee8d9072e6f58cbc6d3c684cc8fa9e-21K/J,Ȩ.Z0PK\bNf֠#+b999c0181280927fc5550ceeef31965b7fc891b2-25K/J,Ȩ ZPK; dN+b9d2f39995f96c80ba015d0da0ddac03e1e0bc05-29K/J,ȨvMIOPK dN| +b9d6a07ae2ec7aa34d72d20eeddf029e4889b6d2-16graph{Str￿}PK"`gNC.y(b9dadd9a7478c1aefefa7a1dcef6e25c23160dcdM1 0+Bp-tlIS)yARK{xݕ }k!iN 4 wxVį]GT~=$RukZ[F)+qpΏh.{2sf>PKYaN3Y5*ba11e524073ea6971e9dde763f28bf93a5d95f66-2KL/J,Ȩ׵"3>:VI ';/?%5ǧ'/Hԧ"5PKAgN W*ba2249b230ec5790335d1451eb3ba559470600a1-2KI @ {Q`EpP"^Xī$m.z&]cTDd8x$4K$4J"'ӹP=5No+PKfNN,*ba387a061f8920708267df557f997d536de77330-1- w h]7Kd3ݻvι@ 7%663ךi  \Ὸ%%oq*h2Us ضWZi-2a.@5gPKvJdNZ75(ba4fcef67b112aaa349ed063d79a68d41bce75a8O/J,PRNNURb%@\ı`XIIW<gkK9PKgN@ճp+ba62c2c947e9765281af39d1fd33bffb749eeb02-56K/J,Ȩ.Mr/J2jkk PKbN^" +ba77f3ca4d6af233d01cf8df63d37342b901ba0d-36K/J,Ȩ..MJP PKaNe?Wk+ba84b23ab21bc9f40eeca2c53a9477b4b3de79ed-12K/J,Ȩ..Mr/JtNPKfNQ*baad8a316ff74725a684e877695c98e3d7bc9aff-7K/J,Ȩy?PK,aNS*baae917c1054ed962ac2e038654e2786ae5f1c3e-8K/J,ȨvPK[aN+bab23b104423dd0efb47ab678e3090e6261e57d7-11K/J,Ȩv7ZwZ8PK)bNf9E++bacd0c6c42e4876af35f84fa54d5141017fec23f-32K/J,Ȩ..MJҵ(8PK tJdNuy(bada716a94368a6f7b8db1e8e52be23ed7a34fc0graph{A[r=d;]}PK aNf *bae0034aad4d27946f75f982f3cb261663fa1264-3graph{StriS}PKbN 闉)+bae668a712ac9946544e9f798a823bced8e6c8d3-34K/J,Ȩvvu0|8PKfNae,+baf3240b98bfd0ba0ff2486342ffe082f331fd53-16K/J,ȨvJZ03ȩPKbNi+bb03a6ebc1b9331ab3372054aba493ffae99c687-22K/J,Ȩ9APK/eNY+bb247adc3d459bbade3b238df13bdb6fae1ae406-19K/J,ȨNtPK bNl+bb270f64765d7bee198d219ae08bf2d2dcfe45d4-18graph{subgrapΩ}PKPdNdX6/+bb2a50b09d2c247062394b4f3aae89bc69414b0f-42K/J,Ȩ ;Fׂ ADz-PK$dN$q+bb336543bec00e7fd449515820b35ddef99f239d-43K/J,ȨZ61PK BfNvja +bb451578811b0dba48346d17031b9759f2574405-13graph{{SUU}}PKeN)+bb63cdfff9262c77a7f6d4d4c8b8a58de53871a8-29K/J,ȨF.@H!XPKnfNQ+bb8b103fcb05d87baecc48d98816b775efdb9658-35K/J,ȨvL/Pvm-PK)aNW *bba76d159082967732e53bc5a9c81b179a442787-8K/J,Ȩ \ PK8bN+bbc8596518f0c10c584864f9f93dcc0694db7f02-25K/J,Ȩҿ.PKgNǠ.G*bc08ff0dab4d19ea2b724c5d1cb35f3b967603e6-6K/J,ȨNαQ!}]l-PKMXfN(bc3f42508cbf7cfaa6a28de5381f676824f4d14aK/J,Ȩurr 𰨅3kkkPK'aN]+bc43149bec21a5bff0acce71811b307ca44d9ffd-18K/J,Ȩ..Mrw!PKdN؝+bc53399e6774f090c1e62ea7bd0e7eebe9af7d01-18K/J,ȨOy-jPK"cdNH Cg(bc8c1ef154a803a1b675a851c6b28e27c0fc3636K/J,Pp ..)NMNαURKUZ L).EJ` AJJ`m:yz@i(PMvu@QĀ|]]`V.ӄmQRPK fN(+bc9ddd5393d03096c928847739f201c6400a9141-14K/J,Ȩ.UZPK .eNj+bcbd3ae2a4c0a106052bd5730c36dd9d6a4a9203-11graph{{Suﯿ}Su¥}PK;GgN~bM3e*bcc35779f3596d7d6d1abfe0d5e7e8167dba0d06-4K/J,Ȩ..MklrXPKu3gNk[*bcdd017a3040bb68110e039ccc05af68abdaed43-2K/J,ȨN2 k4`bеXpV-PK cfN5 +bcf840c3b6f2903bec75d906317e042f1e90014e-30graph {n1}PK:=eNOkS9+bd1e5e5ab86e4ed711c9ff96f7743e808e5a7938-13K/J,ȨuJ`Bb2d-PKӴdN4"+bd2561ff70bf07f8bd643164e721288a1315aa29-22K/J,Ȩurr42La@PK ]bN+bd2f25032eba9ead33510f985bec9b9c0c37a028-38graph{{StrO}StrK}PKngNWREvv*bd444f168a75837484dc4a5ecbae35298231f439-3KL/J,ȨΈαUz3}˫M o6ٹܖM3^/|ӽ6%V)ܔs;m<|cpInOfq f(fr($T9楀4" bu" c5m}PK aNP> +be061a7e0831b11f1dbd40d978180b2d866ed330-11graph{Gr￿}PKp[cN@+be131821fd1e6972021875c3f58e6f55ce682feb-26K/J,Ȩ.MJw^BPK#gNC+be197e69bdb7d87df15bf1a26257c09958abfc2d-24K/J,ȨZD#Ψ%GPK ReNoF$+be42acbd66e8c120a5254670cf2df2cf021738be-24K/J,ȨwZw'0aCHPK"eNr~3+be498d671bc261012c666a04ddba01397ce65616-24K/J,ȨZ0pATN-PKPJdNAr+be4a3267abdcc0ec95a5f0028432082a9eaf6415-16K/J,ȨPK=bN +be4b9e8e230b86ed4762a85c7da26f984fad6260-31K/J,Ȩ..)L~?Q[ PKdNw(+be4d264c125ff928e2194fe5f5d39edd6e8add02-21K/J,Ȩ˷@¬LPKadNC=*be66dc47b77c2489aac45bb5ad6485fe1254ef7a-1RӋ 2SSmrDgq ql4yf0.T3PKfNɋ%*be6c91e677d45158b271162f2c8f2bb7db637423-6s/J,Ȩ..M*&PKaN+be6f0248b614a63335b6fdbdd4e4af672cca5fa6-16K/J,ȨZOF`~-PKaN|@H+beae1fdfffede5859162899346f1beb1196b40c2-12K/J,ȨV*IMqMIOUK-*IP/(q9mlK*RA|hXhC0i`gJPKdgNs 2J+a*beb12df2d08964a701cf837fcef3bf5717cba489-1K/J,ȨNNURb%@\űZZJJJJ@u0kPKKdN0Ab@+bebf21350ce74d59c602b27184c5dcb12fbd399b-20K/J,ȨNt2jA.v"6ZPKaNN\+bec2ced044de7ae43f34aa8e8cbbcc58f6e6a65c-14K/J,Ȩvr 0PKCfN!*bec3d175981c78c0a39e4ebd3c5af7960a4468a3-6K/J,ȨKBPKfN'*bed662aedc8e1e1dd748bde77d862772df9e820d-6s/J,ȨҤt ;ΨEjPK aN8+*bed6b7a16231cde960fd8ffffc0c78a680bda320-6graph{"\a￿"}PK ,aNS@ *bee24064fb7f52dcc86b59a102089414c10b2e70-1digraph{STm}PKTdN+bee4c04e2134d3db17eb38e32c0e407e7ae97064-38K/J,PHMɩNMɫMMsjPKraNG+bef1f8a4806dd3d9b99de953f1db5a3ead661db8-31K/J,ȨvZ(PKӫfNS/K*bef935e3c12aa8381106296690415bf04e9dcc6c-8K/J,ȨҤL0\[ @H!L-PKfN&z#+bf1974522cd0272cce7efd88a947f69d6f016ca1-16K/J,Ȩ.UkPK idNQl*bf800950246ebb6f84a2213a7bc1d3dda91c550e-1graph{/**/}PKBmfNf:+bf82e140508c0a9d7b4045ec5103fd137db143c5-23K/J,ȨvrPK Q eNP6 +bf85dd81242f6c25a791646d8b7ddb3124fd4a81-15graph{SUBGR_}PKd1gN\9f.(bf91fea19a4483e69757d30761f820e0a5932b32K/J,Ȩ..Mr2aZ PK6fNˌ "*bf9b7d9bed302d822d1f95323d1cf5b1578064f8-6K/J,ȨOjY ՂPKbNX/C+bfa0414a0adeb2f9d236246c110e5270dca711cc-32K/J,Ȩt R^@j0PKQgNJx-*bfcbf190f67c56c2e1f9a2e11f9fb92dc3b1413c-5K/J,ȨNT-6^mm-PKaN[+bfe00872b61da433e9ec56f093f06f02ab959539-13K/J,ȨԗWצ?6@PK|eN`om+bfe302b5e38b7c9d6b089ea70e2e47aad501beeb-15K/J,Ȩ~{-ؿ­PKeN]M{/+bfe38b02aa7a5c63fdc2fd899d04a130fbf00e5b-29K/J,Ȩv|k?F֢RPK HdN~d +bfe7af43f98d1cea580f8b70b54297673ffb1849-11graph{S￿}PKkKeNMvFB*bfec2b028e32d3458bb28c1a77e60538f76b0bc3-5K/J,Ȩ.MrE"a(0kPKwbNYk+c00a2fc5926e61b45499c4817652008fa463ae14-29KL/J,Ȩvr׵sQPK9cN<3*+c02a69cf58aed201c52e26611b8fc5a263f70cd0-32K/J,Ȩvt/rR ҽʩRPK֞aNB+c02e778093679ea1e9f3de49bb30767685b52aba-10K/J,ȨNL/2`6i!fBCPKPYcNGy!+c037a74c24b35b40c9d9541ea78e8cc9a49dbeef-25K/J,Ȩ.MrwQZ PK eN+56+c0540f6e7940a362943f19ee5b268e65ec83fc92-24K/J,ȨWwZaPKzeN9*c05bf2b4284086223737f682834fb85d3f0eba6b-6K/J,ȨOոHĪPK bN:Q<+c0611ea88e1d5cc9378617b053ec01dc5e775666-37K/J,Ȩ`Ƃ~m-XBPK |eN%/*c0a647d1c496e56fbee5ac27f24bbdaad7c6158e-7K/J,ȨNZ8 @ PK]fN L*c0ad38cd6a6795bddc1938c4648cf152f0c93aa0-6s/J,ȨEL TPKQaN7!+c0af485fb9fb30c54d0eb6ad41422c1808b412da-17K/J,Ȩvt f0PKeN۸B`9+c0dc8f645f384d37478b7f921e47000fc08b6701-24K/J,Ȩurr 1`t-PKreNu9*c0f9def933ae78a85159086ab24d7056e8d667cf-1KL/J,Ȩ6ΰLckPK% gN#+c1020efcfe75c31ae32f2060f99485656dcc0d8b-16K/J,Ȩvr HZ PKRgN,+c145e72adafc88eac05bfe9fd65bce81e8a3d758-15K/J,Ȩ?ׂ PKAgN "/(c1736a0bad93bfcc6d03d14a440a772fea7d40f7K/J,ȨNj$EPKdNZt7+c174711c3eec30c5c836e1e15174aae25693adf8-18K/J,ȨNt?PK+eN ;+c175018c2a813dddabe3e7ab23d683a6ac6a907a-19K/J,Ȱ"j3jPK 6fNi7*c1843cc348215a2ba045314c53a30f2cc953ac60-8graph{<>}PK!fNռ}+c1987052a472a57dd025c01f75152ee05710106e-18K/J,ȨaZPKךfNe+c1b2c77b2cedd0717f3427acc1f66b12ed11f16b-11K/J,ȨIEvvPK GeN$^3*c203de2ce4b1eb90acee715673c98a21cead8ce5-3K/J,Ȩ$"Z0 PK -igNoUk *c2093093c8020ff8114773d97d5efd4297a93c99-4graph{subgф}PK1eNc*c20ffd99952a58fca598b389e599e39b83705b83-9K/J,ȨvL/`PKK%eN`Au3+c22fae6afa1614847cbddcff6228f88105f028dc-24K/J,ȨOZ j] &PKgN{+c24c872a20d43ef0b4859609141cf62e5f8e2c89-14K/J,Ȩ-PKK8gN+c2669af961e283a25fb0a12d825c24a8e524f2a6-10K/J,ȨvZPK`/dNoȂ?+c27a286470254f562d22b386d56e300fa68daae3-36K/J,ȨLZLHbAZPK5bNы+c28cab27a8a0721e8f778167938394fcf15340b9-31K/J,ȨvL@"PK КaN+c2a51c07eea7c029be8d2de94976f91235ce495c-13graph{Grap_￿}PKaNMa8+c2b7fe90bf2306884f8feae8b25900b30014629f-10K/J,ȨNL/*R PK dNi+c2bb5a04281e39a7e0a7de75519de2928edf9c00-22graph{{GG GB GP}}PK91cN.+c2ccb47715c7cba7e36b1fc3902d357c24191cd6-28K/J,Ȩvt/PK ̔dNkw*c2d2c0ae0582797d48d48e131a53152ea1495db4-2/**/graph{}PK gNΝp(c2d7b797b8f1af10803918664cfa5b1a34f7420aK/J,ȨNt/J,P PKr)bNS]@+c2d8ffc2d1fbedcc786a371a86d3c47cc3ac5fea-21K/J,Ȩ PK dNfZ;+c2ee02dba5cc619bd704662fb4cb96dfe461551a-40K/J,ȨL ;B PK JdN^6ޱ*c31023586c6228a6f49cb06e647e371db3d3dc3e-2graph{SubGraB}PKaN+c314725c656a57ce41a40a333bfbd511852fc3b3-28K/J,Ȩ?PKaNG@*c322feffce66fe61d2de0be72e14b26704bffe5c-9K/J,Ȩv|?RPKHeN.6/+c327cea07d65ed552200f656dbe52a2ac56202f5-29K/J,Ȩv/J,`_ PKicN:!+c32bc55964e800f0802bc341860ae19c2035cc7f-21K/J,ȨVc% ƯPK;bN5+c3453b7a9b16b18abd314f6c67bebe20331e23e9-29K/J,Ȩ..MJOhT-JHm-PK6cN,-*c4ace1d3f923401acd0d2abce6366454cdb84be6-7K/J,Ȩ30502073344613710722353254401jPKfNQZ*c4c6c88a1cbb600582c70d182c2364d9ef0a35da-3K/J,ȨZPKwSbNZ2#+c4cc23c3848f004875fc12688f6255447158c860-40K/J,Ȩ.)@\ʫPKfN,Y l**c4e848d11a7a153fbb589582e895e79110565f73-4K/J,Ȩ.MJ PKxWgNW+c5091618b3c581819e1c103348fc4dbb4cfe3c7f-14K/J,Ȩ{-PK63cN&+c534146c072e1dcbce4b6059acaa9d6052c2f322-29K/J,Ȩvt2k!tR-PKDBdN ]4i+c537173f44e811df2b876034ddd816e685f6a0c9-35K/J,ȨVy c_ f-0vL TDWŀB (PK aNS*c55b86e38ff249a4a8c57e07ac356466d6f68698-5graph{"￿\￿}"}PKfNp~ N +c56e65fb52c116db1099dd668a98b41dd3d0ccb1-17K/J,Ȩ E  PKaN;+c56ff84ff03c6340828d19dc2c9170c974b8738f-10K/J,Ȩ..MrGfPKfNkp{*c57a13af10f7dc0550f66048830e5ddde6c35cc2-1 0w?@RcVI""B VHV>q-]^mDCWG'0a O+8j| %6veiN\PK 6eN'~[+c589c5e44e517df68b3a17603a4bb0abecb1ac56-10graph{{SUBGRAPo}}PK haNT *c58b1c87191a7064424d2216b7994033f908065b-7graph{NOD￿}PKhdfN1)*c59b615f75d5fb827cd31422fa1011f7bdb3f5b1-4s/J,Ȩ..MJ2at-3PK`/bNP+c5b18f5923c794266fd885170fa305e5536d2101-27K/J,Ȩ t6RPKdNA#+c5bc76c15816f658100bf812e216d45584d77d47-22K/J,ȨZlPKbNb:ʭ+c5c982379d2e0853aae069429135279d48a0fcba-34K/J,Ȩ`LPK3aNu*+c5d60e0a15ddf43563d5744ce36b8734dae6bb75-23K/J,ȨvuaPKbN&F%+c5d7cc12a43975a6fb4abc383f30dc1d3a49577a-30K/J,Ȩ HLPKc`fNk$3*c5e98d72ea3a0240a0b15943a0aeabc4822543f1-5K/J,Ȩurr p% PK 0reN!~#D*c6394d6900aaebf058ae4a5815ac4b2b887397d6-1digraph{nodo->nodk}PK%bN;&a+c64bc8e346c6288327b3bfb9db00fbe9670ad5f5-34K/J,ȨZPKlfN35*c64c56440b724f71a50dbc6722f1b4d4f9ac97ec-7s/J,Ȩ..MJ/jR0PKώdN'r<*c64f17d8adb118c98dcfb4d7c64044d4f49ac191-3Mϱ0 _cljf>y+iΖtN?<7_;6h+meHޑC-Nbd8 t2Eje Q,g4a-riPK|aNp+c653fb5d6957c0a27cfb0955b3c7281f9553b3d2-10K/J,ȨVy}PK 9bN +c665e51467c328316266589ec948e4795cc45b13-27K/J,Ȩ"PKaN m+c66ed4227cffd258100157b5ae231ef269a40e6f-12K/J,ȨV(~~ZPK{]cNGW&+c67bf6cf2d25db39c886ee2c8db81a8c89a52336-27K/J,Ȩ.MJw^dm-PKfN;~++c69d59658bab1a53a2fe19d742dd08ffb1bc4cec-11K/J,Ȩwy=*U `4PKCcNui+c6e82faedb1f1a934382ab616077cd5b8a27b301-36K/J,Ȩv/rZ"Z8PKEeNiT$*c6ff952f166436c70237a311000c94e04d8e2ad3-4K/J,Ȩ.Mr/Jt3jZ PKeN߀%+c70fe0e4f5ff57faad402922243f2812a407054d-17K/J,Ȩu2FPKLpfN!+c7146544999226b3a93969fee831dc40c75dbb69-18K/J,Ȩvtr 3jPK`gN0>g(c7183e403c0b8ce43f13770cd746f20c21688addKL/J,PNURNMuIαURO0\Ҡt"F!T]]T rIԵsIPiȔ_>P2 Ap gsy`T];pkp0LEPKOaNc}-+c74a591ab796da80f0e31faa13c8225d727eb247-17K/J,ȨjQ PK'gN3E+c755c67987dc6ddde53e4bc1ff1f495545c0e750-11K/J,Ȩv/b`h PKaNhi+c77484b466bcaed905d819ee5e781f10bc7a469e-19K/J,Ȩ..Mr/PU`^m-PK#bN/@8%+c7788bc500a44010c83cdaf99e3738e64e9c3038-32K/J,Ȩ.b(U[ 6PKdN:z+*c78b7889ad5308eaf7aacfd274596673b62c6dd4-48%!HK?( , BZPKYeNY9+c78e497a834651956219dc205a67df8029146ba7-19K/J,Ȩ. PK[aN+c796eea6083d7ee4639fd5f840d434e60d9e76be-13K/J,ȨVQʎ%JPK gN;oyM*c79a12458e50011904b46d8ab4b9ee9bf8fa3677-3K/J,ȨNtji4.ePKÄfN)a*c79a1862fc78e44d9d6ad508d37e04d07487bb40-5K/J,ȨQz BiZPKQeNC9+c7c663fbe99d68050103674041f08cce724b2138-15K/J,Ȩvtp&&‚PKaNI͕#*c7cd14c1a1af48027fa3dedfd42aa8ad19cd2c04-8K/J,ȨNt/ LւPK[eN $C+c7e4e3d7eea6d605d88340c41f18f9675027bfad-33K/J,ȨvMIl0 %kQ0PKeN+c82345f4e3f312450dc017e6822e18893908fb04-19K/J,ȨNt/JLSPKnifNw'+c8497ba4d6fcb694c5efa0b468e9d444237779c1-35K/J,ȨsZQīPKbN+c874b0330121587034481f2d2bf2e949627d5b1c-22K/J,Ȩ=AԂZPK&fN*c88f27dc8f450be0f3e23b1cadd613405ac9944e-6K/J,Ȱy]5PKh-gNbOG*c8920e53fc2cea94c28415fb85fc15d0d613f9b3-6K/J,Ȩvt/2R<iHPKdN;)+c89c562b6b3a1edd864977770fd72e4cfdaa7040-11K/J,ȨuZPKadNܑ-+c89fcd0acb69f30eea29445198cae992555899af-43K/J,Ȩ @8 PK{eNQB)%*c8b92bbbbdea34a4a1e8f3c4c3c8ad279c951293-2K/J,ȨNLGAPKeaN"i+c8d3cb77b3f3f66c4fd2157c044fd6500e7e29fb-30K/J,Ȩv9{k 0PKkeN A*c9127e729ef63ab56a54a5353859c868de70c56c-9s/J,Ȩѱ PKaNq`!+c916fb17e557368043c4e7fef30ef75203337b61-14K/J,Ȩvt@PKaN;+c9316f78381e1b09530a46c22096047f1f0aa9ac-12K/J,Ȩvt2RPKKdN~#`*c9468227cd10803ab30d5fe43ac59992bce5edea-4KL/J,Ȩά0jat-PK+fN-v*c96024b777eb9afe4e2303f85bbf4a3fcdbc457b-4s/J,Ȩ..MJ/J 0|kkPKFeNu*c965fb8ee839e1da09626dc4ee41b4b31ebe5e36-2K/J,Ȩ.Mr/*EkPK0eNʑ*c97862b8a7ae5a826e16f986e2a44e21dd9332dd-8K/J,ȨvPJPKfNn*c978fb572ea8ca43f4380243f619c4bce6e1a579-9K/J,Ȩ3ZPK gNp;fJ*c97bd7ae04c43ea94d0a72302b2193128ed99729-8K/J,Ȩ.*b g񫉯PK )hgN *c9830e35d3d0fea473d91c21eb016bf058c8175d-6graph{Nod}PKZKdN-D+c988470b6b08db7f5bcbbcba45bd44f6e2716f5d-31K/J,ȨvtPKVgNxB3*c99f8cefa84480eea73dfe35f0eda0d27a44398f-3K/J,Ȩ..Mr7f(\C(BPK fNd-K*c9a50fad23b3d93c3ce7bf717adcea17daf41a62-7K/J,Ȩ..)LxZ\t-PKMfNxt6*c9ac9fa1c97283211aa64aff8fe651c58dd5ea02-5s/J,Ȩ..MJ/J41p BPK aNx *c9c083be854bb73b4727c124fdbd452aa5ea4527-8graph{Np{Np}}PK PgN kgT+c9c24d1f2121042dba20ef9188d9914a14caa90f-16graph{{stric￿}}PK aNd+c9d7c09774f75abdaa1a274dd77ad9f419a8aaef-10graph{{{Ed￿}}}PKL9gN\*c9dd34e8dd3d1ba5aea6f59adb0fc7036cdc0a62-3K/J,Ȩvtr 3jL8\-\PKdNҪA*c9e0949c613d7eaee4599b602b128d775f2c0600-7K/J,Ȩ.M`PKmMgNN (c9ecfb6325ed66c3d2d5f130f19d0529d9929f13K/J,Ȩurr3`4PKfNDGd*c9f2558d6eea58b1af62669c91bea450be3cfc1f-3s/J,Ȩ.MJ/2ѵPK bkgNY Y *c9f69a3d6e3214027298fa02a77b9db3ca34dc7d-7graph{{dig_}}PK6cN#c+c9fbd1fa12aec0fff8b9baa51e3b7c1c3fd4acb5-31K/J,Ȩvt/rPN-PK aNw *ca0376968702f48b8c881f79cd90bf2442f301b5-1graph{subF}PK|cfN؏S*ca2e70d7d51bff80b1be3a7b5781090781ab3088-7K/J,Ȩurr pEfS PKbNL+ca3187b448519a5c3a716ff72e79f165c5cc63ea-33K/J,ȨN @V-PKFgNA2"(ca60a62141e51a3ac49bac580658a29ec9d7df4bK/J,Ȩvtrtѵ0[ A0PK4gN.5*ca61203e6bdaa52456b53988764ed08d80a47b47-2K/J,ȨNt/ PEa4PKrfN܏JK(ca66611529460ee7753db675be58cba3b798d1d8KL/J,P.JN, N,H-+NLJͱUR ѵ.*//άJ53Mq2RSlRSckPKi3gN0*cabf490b272a3fb56a3f272063fe9792f5cc373a-1K/J,ȨL`(U[[ "0PK ܝaN+cad43f1c52f5e7a81a719f0c8fc461b4b6f9ea55-13graph{{{DIG￿}}}PK gN7'Is*cad6b9a674884cadc9f96ee6ef5f60ffb37d4907-5s/J,ȨNkat-PKd bN9+caec96a08f38150b1f340d31c79a6ec1795f4d6a-20K/J,Ȩ.Mr/PKfNTh-*caefd8a9f1c0f775a24a128f9a24201791c5a03f-1K/J,Ȩ.MrwP`2 !kkPKcgN4y*caf96efecb5e15e85e0acb4d4a8da9df8eccf54f-1KL/J,ȨNαQG ZPKmfN" )+caf9d87b6fd233e4580f95f3244a79db7f1c9edf-34K/J,ȨvL/PKKdN^2k*cb0b307c6ee3a8531baf33286ec5f836bd2e3727-2K/J,Ȩ3ΰ3,AŦPK fNϕH*cb1c54970f1716fc5f60830db792f2f15a7dfdfe-2Graph{{subgr4}}PKdaNޕ^^*cb49cfcf629885e1d683e8c8b3221c4ee0ea06c3-9K/J,Ȩv/v%PPKeNPo'+cb51652fa10fdb6cfbdf476530bff00a7dd8eb4b-34K/J,ȨvtrVNN5!kPK%'gN\;+cb83e0ebd5a72c8185b30d3d1731258fa842166c-12K/J,Ȩv/b`j Z(PK LdNQ *cbbdb2e01a504ca56fb3666b62d67f2604ba4736-1diGraph{}PK TdNkBX"*cbc9d1ea829d7d3af5582c486771fe1f87320a91-6graph{{{gra￿}}}PK6eNqf!+cbccb3c8bd0de545114c357380df563a61fd4ae9-12K/J,Ȩ?EPK`kfN"Y9+cbe4f373b75ab4d0adf013ab49bdfec2e0779d20-33K/J,ȨL3%^ PK ԭdN+cbef99a9e3f3977beb11ae1881d5fbe6c76f1d0a-20graph{{SUBGRAPR}}PK$cN`yJ+cc12c9793ec592ab5fb2ebb4a04a3066ed3dfc35-41K/J,Ȩ.MJPKdN(F+cc35bae1662be6284273dcb6ce9c310769ba9c44-19K/J,Ȩvt?PKTgNIW*cc59fa6fea73b5e687e530b0974557c9546fc132-2s/J,Ȩ.Mr/2] PK aN(,| *cc5daea22c69df536fc75985838e2537eb1772be-6graph{NOD0}PKngNh)*cc649e0d90afea2b6915eccde01d78be0d10d0e9-4K/J,ȨNαQ!},.PK -aN[0]+cc67274d973ae8ae25f01844a594fef9fd2a24da-29graph{DIGRAP￿}PK [KdN +cc68b5cb5ffc4281a84af3a6dc3a29c94ae13797-32graph{SUBA}PK fN#+cc7bb29a2fb5274b82425f68997dcc2b24cedac9-10K/J,Ȩ..)4PNmm-[[ PKgN+cc7f940daaa4b6262c95b040691c3f11a6c4ec91-52K/J,Ȩ.MrZ PK@fN(/*cc9bd0d9ac01d896eaa5903e99b749e12e0106dc-6s/J,ȨҤZPK1=fN\c@+ccadc6ae8d5f35391d25c69177f7718cc75f3148-38K/J,ȨurH$ZPKDeNb+ccb75f65981fa1e3f3a548a9e8cf3b91990b568c-10K/J,Ȩ7Z] PK[neNg&3)+ccd71871c27eaded96d6dea562b7e1dfe92313ee-11s/J,ȨѱZPKNfNjq+*ccdb6812e91ad250e50d177215b3417bd50d0489-7s/J,ȨҤZ QT΄PK fNexڎ*ccea26c1a7c8d047af9e6448637b8466f768cc48-6graph{8.185791015625}PK adND+cd1b2da5fa6848a0dd393810f2e163579139f2b0-21graph{SUBGRAP}PK YfN *cd1d53d6c42fc82213e61a4484d2d539ba275f9e-1graph{{dir}}PKLfN"*cd23a2eb22f61fc931122620176f1e840e6f6d94-5K/J,ȨvMWRrM bPKIgNLq(cd244cad3c92045a86e30a6226efec64185663ddK/J,Ȩ..MPKocN8VO(-(cd3f779c9bf46ce21b16cfdf90737778ce62e127K/J,Ȩx x ?+>2>'>ȈPK=OeN+p!*cd4ed86b1093774244f6d216190ddfee22d14717-58aǹ A$k%dTPKFHgN2 '*cd5667b19905f21c8fb00e61352899c424a22dbe-9K/J,ȨVz}q!ZPKcfNpv8*cda28487729e3063ed1509068dca1fd1aa7e4af7-1K/J,Ȩvuqwuе`&T PK 0fN *cda4886bae761a53f764030eb7729015abbf568d-3Graph{{subgr_}}PKdN?;+cdab598d0d7bab805c4ea4e0ff70caed4fa84a45-44s/J,Ȩ.Mr`[-]ʬPKoaN+dܿ+cdb444118f148137d12f7a5f8bae9fa941c62f01-23K/J,ȨW2"+k!PKiaNhD*cdbd63972ba4d049c2e594583bbaeecb25fa4302-7K/J,ȨN/#PKeN*$(cde634ac31c15f3a1022a63d395fe441d7db129bK/J,ȨvuqZFPK ;dNh *cdf1079634b33b159145412d8aef097c76ab0717-7graph{SubgraG}PK3ggN,*cdf6ceb73685ae81c390c0c3de5bfaf5ec0fbd2c-2K/J,Ȩ.M3RkPK2UgNz.*ce03ea2e8902c745d9350318c3dc2cd719bac40d-2K/J,Ȩ..Mr7ը\( PKgNya*ce09ad883560befe1b790a55b7982191261071df-1K/J,ȨL 'J֢p1$ PK bNt+ce0fe11fec271b6a49e149ba4bf80ebf0b8dd80c-21K/J,Ȩ aPK  dN//E+ce106e878434ddf19f0eb816126ba53eafdf940c-41graph {{ed8}ed0}PKlfNTl*ce278f68382090847d0feaca324c03218a1b253d-4K/J,Ȩ ϢZ(PKJueN\!+ce4ed68b67faadb128476472e1cca05b97635b44-14K/J,Ȩ~{m+ ZPK aN$p+ced067d35a5a531527f85c6ceb6b2d11b27f4def-17graph{SubGrΩ}PK֭dN^6+ceef86769d667a560553ad31fc07cd2676a93d4f-23K/J,Ȩ˷0¬H $b@PKrcNSl{+cef89a0f8c5db2d8e4efd2c6369f756dc3a0ea0d-42K/J,ȨNMb RRJMZPKaN75*cefeea0b3de49ae203922a046a66203466679684-3KL/J,Ȩ..׵+.R`T PKkgNFn!E(cf0184c6c97fb195f12654b213a73dd744671f28K/J,ȨNt/ʬPnAmm-a貵PK.gN+1*cf050ba7b487f6293894790093f426f294ea1d15-1K/J,Ȩ X 6y``jM)Q1Z$PK cN!+cf121b7443acde7ad235750e06adabb6d7eb7ee1-34K/J,Ȩ..)$3kPK JdN-4 +cf4f6fa83cee052308b208546044df5dffb3e7f2-12graph{N￿}PKgNJ~*cf641bc0b34ce8e6f6b592fbbdcec344a3bff4d3-6K/J,Ȩҿ.N5 Ns N K0 aK!k|9 afᗅZPKdN!"+cf6be2fc585ac675c176f9abd3af7f3a00466d30-15K/J,ȨNTmm-PK OgN^T%5*cf6cca612decea3936f657f6eeb28d94c8b34bde-1K/J,Ȩ tPB PK"cNu9+cf91385a9a8bd915cd95edde647d9cb9acc20203-35K/J,ȨvLE&D!W PK eNٮ55+cfa722f370224ee29fdbf0dc9f2468f3608f9736-28K/J,ȨLw p TPKԠaNcÃA+cfd00dda7e1373502e31fa59dc8c8eca5c6c1633-14K/J,ȨNL/@2DkkaT-PK aN ,*cfe36aa3d9ff51cdc9bb8be98f17692d5ad3b287-1digraph{h[r=ed]}PK}eNZ#+d008d80d5abb07ed40addd5d0ff2b10f298191bd-16K/J,Ȩ"W@jPKeN+d013bdde5e715f99cd4d26e7659ee0206e46690d-42K/J,ȨZPKueN̈o*(d01aecc25158e0f54d34572f2299f3d5984394faK/J,ȨW2Y[[ " PKbNێJ0+d02ae6226560dba17b411fc6c21660014fc19498-24K/J,Ȩ b4LPK OJdN95~ +d038158910cae8d1e7406f1c328320792ea062d3-11graph{D￿}PKbN\TE+d046351c6cbdcdfbde1f0eb284aa24c5b7324d63-24K/J,ȨwDƵ`PK KdNK +d067b3f8dfa2d0820541dc5eac026e7aeefaa487-32graph{N9{N7}}PKaNgH~R(d06cef12b188dc4605f69436ad8e3d953b41d5d3KL/J,Pζ̨VR@f9vvvHII׮2L ($R b@tDǚCT%2d-PKΛfNbo +d07b6dcb2b76ff2f7c17a56327dd211cdb14dc44-15K/J,ȨO PK@aNZ*d082ef0e74ee9322f13c2c3ad8d3cb4d707e5053-6K/J,ȨvLaPKrcN &;++d087efee7536b917dd8bafba28c7abac8a16d46f-33K/J,Ȩv2`T-.P0 PK NbN_"+d0a62147226b5883f3d80f9ffdd6d0b572683043-23graph{{STRI_}}PK%aNb+d0b00b21af3d6fc5ac9420478fd8a4d541c53442-18K/J,Ȩ$+Q PK aN AK*d109c09a70d706d20b0288a9483ba2571a87e0d3-7graph{{striI}}PK fNX†*d11a821734007191adab48086d49542a4469b5fb-2- 0W{jnF`(Qe9wwzﱍsvX7 R>Q&Hғ\$\e%ZhE7:ă* 8<ϩKD,$ť߫ݪ p7@m5PKgdN.(+d1230488cba736b48d3757b73325c04765218f9c-15K/J,ȨNt2k!y-PK gN*d14ed4bc3dea8c21a0cf0d1fa24738c93faaa824-1digraph{G:nw K:nw}PKBaNN*d169dcdf06be2ea7f880550d44c5375e1a39cd4d-6K/J,ȨN1LjkPK[gNB/C$(d169f714cab11e68cb73d3529e2ff03ba4e58d07K/J,Ȩvtr H1*k PKeN]w*d1727491714d733760327e72ddbcf69bcea44c09-1K/J,ȨNtϯPKiibN( '%+d179e34e338d9a53fef9b2c46d79370f730cd081-36K/J,Ȩ.)LNRtm-PKfN^eC*d1895f9c5faa32ec2c9969eee0406ebfc767399a-2K/J,ȨVzR*!8:RPKbN2IK +d1b040f427e7bb232b15b57d7f92f7495038d44e-35K/J,ȨNMID NPK)fN-4*d1b10139b30e3e136aef63d51cb4d383d97f83a2-2s/J,Ȩ..MJ/J10Ejk PKfN,S*d1c1284b9bb7c48040bc82f9c112340ce66aa472-9K/J,ȨNa bPK }aN_pX+d1f3d6246954fe9fa2fe0f91e7866da7efe589ec-32graph{diV{{diY}}}PKbNak+d2034a0a984d538f2e4e1b73d01b8e7ba7c29055-29K/J,ȨvɌaPKklbNW+d2250cccc1a402d591cc616fea88c4eef7f9bbe1-37K/J,Ȩ.)tPK8QcN=1+d226166c990999dd6c2c286f8dc87ecb072ff5fb-33K/J,Ȩvt/J PPF#S.PKgNC"*d24f59930ff654b5fcfbeb49fb4586bd57686917-3K/J,Ȩt Mb A PKy`eN}-(d25afc246228638c21109a90ac18877e3e02f0adK/J,ȨNMI7R PK fNUV*d25bcf8b7bb329b469fe992c9442df8b0b72543f-9graph{{stria}}PK \'dNc'W+d27b64493b288ef26f9c7c3c3fc88e1564ebdc36-29graph{"\{ ̄\L ̄"}PK gN Dl*d28a7ab109c61a68b258f01be7ee5aae65e08816-4K/J,Ȩ^Z^^^ "PKwaN$+d2a51ced9dd8d05239dd4d3bbcb52fff0f81420c-20K/J,ȨvuqZ PK dNȰ@ +d2ba4b9bcdbd18873d60934e99bc13650234a5d4-10graph{NO￿}PK>eN .Z`*d2cd968829978660ed25513a7492ac030f7455f9-7K/J,ȨNt/JSQJJPK8fNKn+d2e6c65fdf6846d5c5717c63617ece6aac6b9305-26K/J,ȨVJQJPK}AeN +d2edf58d67e8da39ae6338cc361687105954bb8a-15K/J,ȨvJZ8ZPK ʛaN+d2f2b47977583d0e884f3f2c3aa341c0504bde86-13graph{{GRAP￿}}PK aN *d3319700c64c5e48f4310521f095f633d8aedce8-8graph{{diGrat}}PK?gN5kG(d34a9a8b60fbaeabd627645abe9ef93c1c24e8d6K/J,Ȩvr Pv-6PKԳaNg+d36d6a0321741cc4bc6ebff5a202eb8c15e78c27-29K/J,Ȩ?|-PK aN`)*d37e8c20fcb33d6129e72ceba3fc2ee965d0f48c-9graph{{diGra￿}}PKfNvy(+d39569943c6525f892a047f16a3440ef4647a00f-35K/J,P33PKUfN݌zX*d3c2d515b3648b2c705ae6d48eb43f6912bad19d-8K/J,ȨQz Z0`#ۮPK-fN!+d3f1da09216e2b21d99af5377613af123fa2ba24-27K/J,ȨV"%0CPK aN81ü*d417eb0b000c39a02c1cf6d1b8921c2aa08408b1-9graph{subGraq}PK&eNa+d422cfe0c71683b661b78c69eccb7b67a16da8e7-25K/J,ȨurЦPK 4fNB**d446529c34d26708044055065e1a98e47ee0388d-4Graph{{subgrapg}}PK$aN9}+d47f93bc17b5abb468d90f5a7e21d31a03cdaf58-12K/J,Ȩv `PK @eN.m*d4a993000f092a619c6f26bb7ec062a62e661e85-8graph{Subgra0}PKÙaNe^*d4cf9b8d2c036f23847d1bb44f4cd07c0fd37da1-9K/J,Ȩ?R@PKfN?aC+d4d9fb9060c811e854eea680686f87c379ebdb94-31K/J,ȨVB/~?3^_ #c*ѥI@@j:cR-PK aN+d4dccc6e405cbd4f0b7df44f439ccf1141cfc543-10graph{{Grapg}}PKJcN4i+d4ea6913bc1f6446cee2cd15a8996015b22d55bd-33K/J,Ȩ..)D&3kkkPK BaN[A *d4efd8ee20d2115c4cde3bf1d7328ca75d348f96-7graph{{GR_}}PKeNQ>}PK eNy+d74b6b313fd77cf145e4a6406639edbee6867618-18graph{diG8{}diG5}PK aNL!*d750cfeb042a451288821f93aef0ff5f827b1131-6graph{{Dl{Dl}}}PKKdNku~*d7593d2903f615c4f588fc8958c3fdaa626bdc78-5KL/J,Ȩ0RkZPKX1bNL+d77b4a4caf44cbd85b9fe0e8034da6ec9e284aa1-32K/J,ȨvLE`,PT["PKfNͽ^*d77f533122dbe1634a72659f4fcc5a76cf9c0f18-9K/J,ȨK`\ZPK5dNt6+d77fc13c92cca56ef9d3d643637c5c41da4bc4f9-23K/J,Ȩurr42Lq BPKeNJ+d7809001239dec4c22f861030e3b68e6e8b314c8-22K/J,ȨN/ ٵPK͖dN *d7957243929ae53d6fc1db4464beb8bed520e638-3K/J,ȨBZPK2(bN&)+d7bae8b256bfa12496874fb687bca56a3ce7c453-20K/J,Ȩ ᵵPKueNʥl*d7c9706a6c0cf179995fbf90570ef9cbd9268222-2K/J,ȨOPK DaNMt*d7f709ad33f1b78e86d0858afd23d97837efefb1-4graph{{NOd{NOr}}}PKdNxF+d7fb81a8567bef348f82b31c37503e8a6389588b-21K/J,ȨNt2ji0ŐKPK!CeN*d80e8b2289639757f01ab2b128e7e0c64f0033d9-1K/J,Ȩ.Mr/S޵PKVdNP 4%+d81d7b6c47cc71ada82018ba05ee5b991feff6ba-17K/J,Ȩur*PZPKLbNS{)+d8352b50c3b66afd8f33805b203a091ba7ffb688-22K/J,Ȩ zo?PK Z4bNרw+d84d53505bc1d541252f0ad856cd4f9d0132276e-30graph{{DigV}DigP}PK0fN>'*d8590e7467c43ea074f4ff2fe56e1b619444ac91-6K/J,ȨVzPK"fNMq*d862440c21b06f0e6f8fe9453c22a8b910b537ab-2K/J,ȨNLZPK1JgNx};*d8911cf7c9435b86e8944b050ba23910a5a10c95-1KL/J,P(.)*ѱ褮T@0kPKeNsq+d8a38e332e8c2a4fd8bbad3ce11b2c9437a2983a-28K/J,ȨWwZ ePKgN*d8acb9bbdbed2e41c3c34cb5ff2f5e4036dd4022-3K/J,Ȩ^Z^PK bNLO+d8d8a0910620694c48b37b210517121dd9a88db7-26graph{{DiGrapR}}PKE*gNM2*d8eeea77b545ea98dbe282b29b4f0e037401e264-1K/J,ȨP' ǀT3c! <sQy nC PKZeN6^6*d8f616477db63039763fa418c66c1f46245fdb12-1K/J,Ȩv hDm-\!PKAaNt'>h+d90546b163ac4a0b19653db1972210d7e19c92ac-10K/J,Ȩvr|wo-RPKaNʡ*d906080bc977fa2974dc112dc85deccf4c9ff773-9K/J,Ȩvt/JLѵPK]bNg>E+d91208152a87fb2b3aa883edac1ad4a80933fcfe-31K/J,Ȩ D#j(PKefN#۴*d91674b2ca71ff95ecd2d85bd187a9f44cd1579a-4s/J,Ȩ.Mr/2ѵPK ebN>q +d92c6bc2762beeb6bdb6cef7447ce2764912e825-18graph{SubGrap1}PKdN+d934e11bfa7df63ad99eebdf4552c5d926a22333-25K/J,ȨVQZPKcNV+d940a280df59d07306c708949512c9d62aab6634-21K/J,ȨVE&jPKEbNB7+d95a7e8627a140b0940eeff14c99e56584247150-38K/J,ȨԔZ0ƭ0PK6gNdxa'(d98ca3788b2243b689d4973a950c0f7782292d66K/J,Ȩ..)L.Rht-PKxeN @E*d9a91813113a8b49f88c6df8b85d8ef13c39bcef-1K/J,ȨNLLPKTKdNV9=*d9ac1ce48cdc75213e84e43456dad7d867a6f73b-4KL/J,Ȩ0RkjPKtfNKz{$*d9af8b5a1f675bece0f89511f5391b6195311e30-1s/J,ȨҤZ8PKb gNa&*d9cce266845c49f93ef106bb8e627d6a9ef4d3ea-3K/J,ȨF.E`D$IMXh0@PKaNu?l+d9e343d49cf906219b15c98e2ca6892e1efabaf3-14K/J,ȨPK 9gNK+da006ed24a66671dfde0623f5432381515d61dad-11K/J,ȨvZU PKfN_f+da1b4167577311f6a162ea296b706886a88fc271-16K/J,Ȩ Z PK aNd`% +da22c62d238a05632add72f28bbedc67d003546d-14graph{SubGʿ}PKaN*da2f993735286c482144b7694a9112d2b9039266-5K/J,ȨNtZPKbN}9++da449159ec1afe3fbb9a9a8c8639efb6a0eb1360-40K/J,ȨZ(ίPKwfN")+da4b011e4f30c637cc6a3729574f0cef056eb854-18K/J,Ȩ Z DhZPK %fN!*da7b4f7f744d7e41de73a0474ab2d7582ef81072-2graph{{dn do}}PK #aN 꺯+da9ee3df356898d45b681d5fc9d7c76b94da67c7-12graph{{{Ed謹}Ed꿿}}PKdNqx+daba687f9f6fe715f178c2267650f433912b591a-29K/J,Ȩv1! PK5nfN7)+daedf637999f53aaf6dbce17c0c8bb970d220769-24K/J,Ȩ Z8ίPKkfN [0;+dafc0f5bd58514bb5a04b1d54cd87a7c99beb8c2-18K/J,Ȩ FԂ0( PKyeN\*db122c9acc63f2c2c2f53b596a6ba4d2a6a95bdd-5K/J,ȨNZaPKMfNNg5*db13274aef812b2514b0ddec8b30814878236ffd-6K/J,ȨvMWRrM b8hmm-PKYbNT +db217fdd0c013ccce34ac00b063a4bb843491c3d-34s/J,Ȩ.MJ/򮮆0jPKeN#q9*db41ed72bb8252a28563694438390083b23c3e94-1s/J,ȨҤZ] k1PKsYeN3Y +db42aedf0ff325aa60ad0784fc5b189d6eb0aeb8-25K/J,Ȩurr 2Bkk"PK $aNͶ*db4f8f057764dc584bf3611fe77d8147d14c78ea-1digraph {subgraD}PKdNw[R!+db58fbc75fd650e42fdf66b1aa6b257b8341810e-29K/J,Ȩv1= 8PK#dNzZ6-+db5cdca3e076610420e835daefe7a23708ad0fa7-35K/J,ȨLZLHAPKmfNez@EN*db61da074b927c50d0eee04866f5a0e8b66326df-7K/J,ȨNLZ3$RP`PKbN"mH+db75b0992895ee97fcc5c31b8586cae60b1eb302-34K/J,ȨNMI(^/U PK TfNgt*db8e232dac6f65060f2681352387c162f6c12c28-2Graph{{subgra4}}PKHaNl%+dba05530335f7ec2f83f5c46110f3631a8fd5586-17K/J,ȨהPKfN;+dbd9c0d5897093930c9542294da04d70f057a468-12K/J,Ȩ3ZT6&PKGgN78=&*dbd9c28fdad0a2ec0b6786fbf9218e1127d29fd4-5K/J,Ȩ`Z FspiRC)蚀` jH0x6 PKfN+dbebcce0922b22caa7d52c7457429c0dc880c305-33K/J,ȨvqZ cPKdNl +dc245a837f5d2c0e28a4361e053cc3c3cc97ead2-30K/J,ȨVCZPK ۴aN8R +dc2c29e54de58bcc1c2cd64e5073288c57019e3e-25graph{Edgr}PKTfN*;+dc4cf63bb7706490e151d1e08bf1db6bad58ea42-13K/J,Ȩֳ3Z`Zl@PKdN~-+dc59200f8b1d54fcd1f3cb8831fcb2e7df3dfb9b-19K/J,ȨNt2jA66PK bNI6+dc5faab3f4d5ee11f18bd237c510a3a5f5071fa6-22K/J,Ȩ.MJPKpfgNv(dc6873c6f9c44494dedb8edd02b2d85ce6c6f46aKL/J,ȨNURNMuIαURO0\Ҡt"F!T]]T rIԵsIPiȔ_>P2 Ap gqIxrjIbjZjbQ]xPJzJZ5Tj͕$W PK gNQv@#*dc6e4100bf3e6961d118e2b2d75c91dec4bedb9a-1K/J,ȨNt/J,RPKteN/:1*dc72e83af16c85d21f1da04535ca0c98869377a5-2K/J,Ȩvtr%PK &aN b*dc77accabff9ca0ecc2d86fe12fe9dcea0921c23-1digraph {nod0}PKRgN)*dc93c3a06104bbb6cec189c126b2cbb97fa97498-2K/J,ȨvtrLRPKaN&Jqc#+dca157ef396fa05a50345b06b5af1f56f7e47f1d-24K/J,Ȩvuq/fe-PKEaNy!+dcb372171ed242df0eaed3b47e48f50f6c75ce1f-10K/J,ȨNL/U(ZPKqaN>,)+dd0e41eb37e3b8433c1c0302a3967dca1759faff-13K/J,Ȩv4HZ8PK ĝaNx" *dd10296bd4dbcc957c2e28ed772312009479ca08-5graph{NODd}PK JaNr\ +dd668e20fa1c307466e334c3c8dd4e6dcdab30bd-11graph{subGv}PKfN&+dd791cd9459011d30504e48b593e3d201874f5e6-28K/J,ȨVJQJ 6PKAddN$MT@(dda11b0b63cf388529773afbb8120cbe28c87021; 9\!Pm},&]|K{=q~ 0R ,To*UMmq5u2!zj@KuLJzH&BLQ;ZR;ڔQ{l ј 4 9uPKBeNO*ddaa5d207f56d145ff5a99cd12e650d9fab121b5-8K/J,ȨV}R-PKecNi 5+ddb76b1e24788bde87f32867745fdc282a9e4f34-29K/J,Ȩ.Mt0Q # <PKzfN67*dde985690760369cfc153fbff7064eea3baae2c3-4s/J,Ȩ..MJ7&PK-$eN +de2aa87a1497dbb993c11d9b47d24e86105b15d1-19K/J,Ȩ.M1BkPK̛aNC^+de402c10188dc5cf2cb2cf222a722eaaf3a82000-12K/J,Ȩvr (@"SkkkPK]VfNq'+de41885d354be2d54d26906cae8991e038a0fc9b-23K/J,Ȩ..M2@3!D-PK bN:PK8(gN[D'(e504ef57f37167d01a735e89a35171dbde85a828K/J,Ȩ.MrZ PK dNby+e50662a30966caac87b9153b8523a67fe04e66c2-18graph{SubGrapi}PKs>bNDZ+e520014d46d929cef2f9b4132e35c1a00888c1de-35K/J,ȨL ӲLPKaN./i+e53128c0a9d6590afbe79d2f439d11454e04bf36-10K/J,ȨNy?PK fNBh/*e53f6312ddf83fe53be07753e63520ad17e55d55-1K/J,Ȩurr BjZ PK8TcN&M+e58ba456c4d876bb56d09df5750fa915f914b62e-37K/J,Ȩ.)L6 h4PK+aN+e5ade8d234cb9753ffca4c9f1342dfe72a3152f5-10K/J,ȨZ0Q DPK UfN$v*e5bc7bf8c944b3cee2c9c721977a2a1a46cde7af-8graph{{stric_}}PK;eN1)*e5bf39632d5db2617ac294c4d2d9b8ef3474caaa-5K/J,ȨVRNtUREPK MdN *e5c05070be02d82fd57d97aef3fbe05fc5b469f6-1digraph{subgraߍ}PK aNb+e5fa118890c0c6d213820d9a530d9e62b2e0c5e8-13graph{{DIGRA0}}PK5 dN1+e60b0a519740d911e0c51a398d63f3d04b446548-45K/J,Ȩ.Z0Q[ PK bN+e620394cd9802249fea10e44980ee1e580b32081-18graph{SubgrapΩ}PK 5bN,(+e62373d409626b579c447e90654eedda255b4d5d-23graph{􏿩􏿩}PK feNE}*e63a528e2b00fe517656b83bfa231779cc56a2d6-7graph{DIGRAPp}PK0igNkT*e63fe2c064b12b7bc20a0d135b6b8db5abf2933b-4K/J,Ȩ.M3.PKdaNJq+e654cc024683153cd57317f67172d7db9769d6ae-12K/J,ȨN..MMPK.fNEA*e682b2522b0674e8f4e79d219dbd18b00d4e58bd-6K/J,Ȩ..)LP&<PK}bN1ֱ#+e69d1eb550b1b7d4d40468ce981a73aff38dbeef-24K/J,Ȩ zo?*U jPKaNn\*e6be220e9ad9487c2cc5828aff6f692bef758349-6K/J,Ȩ..M0jaZPKrfNh(e6c72891aa50440da7cedfb8a68652d5cca79372K/J,PROIUpIM,+VOIN-ɱUrVPMI64@Tg+A-4̼l4ӀEٙy yũ) .9 n@N"XE^~< ߿iPK-#eNc o +ead8eaa7bd2985c74fffc77230499f0fab6b8d6a-14K/J,ȨN|p-PKaNK9(eadf718ab2dc15061a5d678a11db817f75cb4c9bK/J,ȨNαUSJUR .h0yFzf0v*q-PKfN}>e *eae3616c4a030520c5d533cd50b4d2fd56c26130-9K/J,Ȩ9D5PK"aNv+eaf8ad00d973bf48fac76d81e8b2fefd3cc9dab1-11K/J,Ȩ..Mr/JщPKxeN$lo!*eb244a021647e244220eb6731bd9ec92f4be25e2-1s/J,Ȩvt*9P6PKfN=<*eb322bf171db0b32b279617f85b00023b1f51585-8K/J,Ȩ..Mr/RPK2meNGn +eb457d93107c2dc384db95fd33acdfe65a7e18aa-11K/J,ȨZ3PKtaN&!)+eb5a32af43dbcc607181ef86237a8d8102f0abcc-13K/J,ȨNj$][ PKaN +eb5b8641b3dae39a2fb7cb462bc899bd025f53bd-15K/J,ȨѷCFPK-aN.)+eb6357e63a7e8fcc43a6828bb7110f1132b0a421-13K/J,ȨNy?D$PKZaNW+eb66b8ecb9a5dd904f278bff90cfcb10be714909-16K/J,Ȩ.Mb_ PKKBgNe6=*eb8a08a9b69a4f20ab81d34f3184cd1d487d5cc2-2K/J,ȨNt2k)xjPK\dN>/o+eba6c75fa010a9c08b83bcba9ff330f851197eeb-19K/J,ȨյBPK aN' *ebac6e976a213e9eb7dbb455fbcc23b920e3137c-9graph{No{}No}PKfN+k0*ebc4760b5601da55dbc185efb17d8b6e41f72ca2-6K/J,ȨNSHMFpN-PKfN:['*ebd16768e6b0098979ac325f0bc3da8aeb7d4a7f-4K/J,Ȩ.MJɵPKfN%a7%*ebe869d2473f83e2c988a578df446e6b7e91b953-6K/J,ȨQz ׂh4]-PKffNP}&+ec1685e23cda84eee667b1566e5ffb054312c37a-12K/J,Ȩ;I4dgW PKUTgN83*ec4a27305f457c0a0a3875486d8617dc610ba298-3K/J,ȨNt/JLR`:ƅPZPKfN+ec691f365283d2c597c84adbf5c71edd473e50cf-34K/J,ȨvuRPKfNh*ec7c03e204d4223a9003cc29efc77a13743183c5-6K/J,Ȩy?PKVeNSX*ec8183a581f3ab1b1121a9e9f2975135151732c7-1K/J,Ȩ$ZW PK dN[+ec880ea316eeb590feff29e4b65c5aa682225a10-31K/J,Ȩv=DPKMeN+ec8fea7c6edbfe3e742c60f8261d29dd7681e71b-21K/J,Ȩ4y#XPK`cN/+eca47cb0e418bec0d5167fd73d52e92f64af265a-28K/J,Ȩ.MJwS^d-@PKfN;W*eccaedb047e9d735b315fcc8ae3ebd63e5ddbcaf-5s/J,ȨN/2M/23jkPK VfNϞ*ece5570fc2196a98759dd0a7a3c8f6680aba98b9-9graph{{stri_}}PKOSgN;(eceafb97aa34562cacc9124a28fa184149346bcdK/J,Ȩ..Mr7RPK>dNU0_+ececbde63c32e2d1f31169ddde04611971191c1f-34K/J,ȨVy c_ f-0vL z8*R-PK+gNj~{!+ecfd25307c149c3c9ad20cc2fc133f5668ca5f96-20K/J,ȨZ !`"PKdNM5+ecffded13a933efd2bb07b90055823dd104678a0-15K/J,Ȩ5aPKOJdN'+ed15314e94ef7ab67a5e2b97d8b01d79a44313cd-16K/J,ȨPKDdN?*ed19bf4add03e76da392b1a835b780f91c254c77-4K/J,ȨOI Q~PKaNd9*ed26ed10e15fe58d1ca2f9fbf4f10135213f89f0-9K/J,ȨvrZPKeN#*ed325b0b49c88c2d30a725330b50096c047250ca-3K/J,ȨvMEƵPK!+ed95ee95c88724ba9687a861f01040203be36f13-34K/J,ȨL 3FZPKaNcH+edca21d36e03df33e6871e41fa8a066b550f0114-20s/J,Ȩvtr @jkkPKOHgN"O+edd323bd43b6ec59bc5f43bbb2126d28618fc639-30K/J,Ȩ. ZdFj<⵵PKaNF_&+edddf22d981c08b156c2dd6c312b552159250d3e-28K/J,Ȩ..MJ0V-PK aNN*ede550848e196c2b870c3be0213061f01d7d52b9-3digraph{no_->no_}PK%bNx+ee0b5e00d31d37156e11efcea50b473fe28f7f35-29K/J,ȨvjQ)PKAfN2*ee0f9979769a971f38447f97d4d63f566c886bc4-8K/J,ȨK`lZPKfN1+ee32f64f26cb430634371e87764138346f31595a-12K/J,Ȩwy=VJhPK=bNV++ee36d9a9e21b038f9f980d1bfa0d2e706bee0a39-38K/J,Ȩ.)LR`:PK6dNMI8/+ee37b397be1a07eff6daa81b2361128ed23fe9d6-23K/J,Ȩ ǀx$PK ۑfNcfx *ee3ce180a863e8ae0bc06ae07236db3bf3559069-7graph{-.5}PK bNoR +ee68386ef8074c1c2bd5050e6fc01a46768cc433-31graph{g_{g_}}PK-aN!*ee8073b0a29474ae32bc74055013ba8d7d9fb81f-8K/J,ȨVz}1R-PKvdNs%+ee854b7fc36080f6dbdd885c4623560aaf2cb8b1-26K/J,ȨVzw#.T PK2UfNJ#+ee8c813ad4d23922b32aac489246395955e0f031-22K/J,Ȩ..M2HLQ PKpdNPA*ee962a34ddc8810d10dfa43228a26bb618faa9fe-4K/J,ȨiF@DX#8a "cQ 8a f" q5s vCw)%PK:eNt+ee9fd28d3b6e2818096fb795d1aeecf5f53289f0-20K/J,Ȩ.Z0PK ;aNgK*eea1a46b9702893f6d543afdc74c69e2392615de-5graph{{digr4}}PKfNc+eebe19e7dae9bb37b91f93a6b9daac1e8a5dfcee-40K/J,Ȩv,ZkPK 6aN*eedf4c624bfd89700305fa8eae086e85693cdc9b-9graph{{{digu}}digz}PKOfNSf*eee243428e162e0b7608825ccdbb6a0a556dd58c-6K/J,ȨyacыjPKAcN+eee40349213b2e4a453fa6349b61ad821ce6087d-35K/J,Ȩv/rZ"g0PKaN+eef4d9261b11d4e3edbfb60961aedf4f7749abe7-34K/J,Ȩvt/z?~Km-PKaN>]*eef6538fb3d5dc6168e6eee809d565e8f42a5dbc-8K/J,Ȩv/v/PKJ/gN5jn)-(ef0fb09a7aa4792fafc7d5e6cea00929382b33e1K/J,ȨNL/*Rʩ *B@kk1uэDPKffN/*ef183cce647eea9fbf24278d23f88eaf520d7af5-1K/J,Ȩ$Z0 eC)dPKԱcNS-+ef315140bc41872b69ae6ecc55e2280c4419cac0-20K/J,ȨVBc V6JPKȅfNMZU]*ef33997eb6af1790079432540bb72864b6a0d65f-1-K ЫĜ#BµfgLA{/ղ"qJl}.dWqXC`8PKVaN")!+ef3e3bcc373d2c8b3b484d56c86bcb51c1381cd4-30K/J,ȨvMI`[[ PK aN,+ef666c40ad2e7b732fe3e07986f1dd7bf10687f0-15s/J,ȨZ(U $jkAPKdNэ+ef6cafa89c28a479ec3842c17d14215fc03922e5-21K/J,ȨZ0Q`PK RaNND(+ef765d2bff5ba6a1e9b9b9aa3eaa956d9af991d1-16graph 􏿿􏿿{}PKigNȑ *ef9f7c2792e1146bc09fbd8c0a2deb45c5746bd9-5K/J,Ȩ[jPK aN۰4 *efbec01b5ca702eb2389d611ab343ed367c4ce9f-8graph{{n￿}}PK aN2p+efda98fb8a4761e7b35f2da344d36d09ae96019e-12graph{Grap￿}PKFeNkR'+f00f5cf6225625dd027a3bb38f148ddf301a8e31-23K/J,Ȩ..Mzgu5Q Tm-PKKdN 2#+f03b4772ddac4275046670ede833c709edfb9a8e-21K/J,Ȩvt?jk4PKuaNx)#*f041125e40431a90d32b28eb488f3016e7a165b3-7K/J,ȨN NqEP^m-PKcNo#f:+f04fa1a324f745df610c5173b61d6685e802480e-40K/J,ȨL ;Lk‚PK@eN];H+f063e1a7c8e8404a6b3b1535d91dae12f51054ad-14K/J,ȨD ά PKaN&?,*f066132bf0a2bb85039326fd08d40c27988ef697-7K/J,Ȩ^`2APK bNr1+f074f369bd1fa8bb428310ec04637a442c876a50-33K/J,Ȩ..MJҵ0W PKN2bN 2+f077ccb4f88527f529b08b97d0458fcdac73bd30-32K/J,Ȩ"ZR[[ PK۬dN]ؙ+f0873ef153892464c51cd95739cde636766799b4-18K/J,ȨNt/JPPK[dNB+f089db13c8f603552480279b77dad0c14a90bc70-13K/J,ȨurPK 5bNO#ʛ +f090996c84a7b023c1bae22237eaf7686d96dc60-37graph{ed￿}PK",gN<0-*f09bcd1b9d4e0a2da67e2ec9802793c8b5c29675-5K/J,Ȩvt/2R  PKdNچ>+f0a6df541da683e9e23acc0a8e7d1b50ef2e51cc-17K/J,ȨurQaPKJ0gN/O=*f0af317b73fc1064a153a9e0995c31be9ea69cbb-2K/J,ȨvL@aPKCcNcM#+f0bac8f640025dc5263f84d5125a1d60b979bb8d-36K/J,Ȩvt7@Y PK aN0*f0f11a537327c63b3172624a198c82f548649283-6graph{{GRス}}PKZfN2F<+f1103d12ad0e8ea963da66cb698564d3f8c1a7a7-31K/J,ȨL"(Z[ J(PK aNO7 *f1156764badfadcabd88318973292cb1d96a3345-2graph{suF}PKtbNd +f133686fc91cc2b1f588c33c7157477e82e405ae-39K/J,Ȩ.)LP*Qג,<]PK-*bNbk++f164328c234094ea03a4bc64d7bde4489c90a508-26K/J,Ȩ l$!ZPK "bNS߼+f17888405a0753c47d00ca111f5af9d5c82c57a6-28graph{subgr￿}PK /aNA^ +f17ebe3439c7ac9764a6f5cb70d7902212a7c764-30graph{DIGRA￿}PKaNy*f192ff31f2c06fb0db5e276f6cbd84816dc60b63-3K/J,ȨvM SRrMŵpPKfN*f1a1c704f503988bab7746660a057ac4dc182173-9K/J,ȨЫԫRPKdNB7~H+f1a60da91e5e075d61e16c81c9b906dc67f18c28-23s/J,ȨN2jQ)0 ˡ)IPKKgN!be!*f1b58e6f37b5cb8608ca0665cc171238580b431d-5K/J,ȨvM)a%%ה<Q\ gPK bgN"c *f1c1f179661cbc0dfca581dcd2d3dbcf66680469-5graph{dig}PKfNVo*f1eb773b9e453b662cd3c8a076f8c29230735ccd-1K/J,ȨN6dd*2lLj7|,0#Wls ?jZ & Z~ sqյ`u@PK٢aN.E+f2113091be5fcf1fc2008dbeadba884eaae819e2-22K/J,ȨWUY PKّfN#ey+*f218a1b9f074b8235163b6448cde9ca2dac7acf2-9K/J,Ȩ9@4CkPKdfN "(f21f9c12779730e0571fb1703eff2b00bfab6fa1K/J,Ȩvtr 0dPK ZbNƒ +f23415253391dc90cff868cb5742f596cefdfa3c-21graph{STR迿}PK.cNO+f23d4b404f773249fbaceb07fba66ca665a22df7-40s/J,Ȩ.MJ/UPKs)gNN+(f24c7bccd7809b68c8a646637d29679fa6d1fc96K/J,ȨurpEPK XaN5 +f27b98ae180da0fef8d2ef68a32f3a76f13e64e5-11graph{GRAPHe}PK KfNC*f2a2624c30e0fe7a3057cc5411e0fb55cf044685-4graph{<<Ω>¸>}PKaN5(f2a720a96568b5315e71c09cc3ac63f76b5e6f12K 0 D"X'"NPhhK7[Glcy7c_ @$aHEnaB^ A2r4 dکud8 m̠MTa?Xg!4NPKaNrMը+f2aa1f8c1f3870c7f9227c70ed85106aa70a80d4-24K/J,Ȩ~?PK2aNXY+f2c22b6f503a82038e02b9095ec78d299076e350-15K/J,Ȩv/JtN`PK%^fN63*f2c602ed7387b696f9a7ef8352bb9e664da537c1-4K/J,ȨP' ǀT8+Ψ@PK ƙaN`<*f2eba2cb8f7beef8dd72e4f1500661427efe9a67-8graph{{DiGrag}}PK aNH+f306873128833e5b65ac78b726465c4b840867c5-13K/J,ȨvtrPK dN봞*f31a50d1b49664c83d02cdd7b60905ce4e78ac4a-4graph{_[f=DiGr9]}PKfNE6 +*f338404df2dae81d88da9ac2a0608713cb0f17a6-8s/J,Ȩ..MJ/J4LZ d2X4Ä3PKhgN^T*f33d79ea88e8fb964c7748e9cece78b7b6b29538-6K/J,ȨεʨU( aPKjaNӲ+f35e764c4c3f6945b68fe6f8a0896309189ebac1-13K/J,Ȩ'A@PK eN?d+f36196b8c433ca5b1a323c89f360ff5f3c9b7b47-22graph{{S_{}S_}}PKfNPB)+f362869664d31ac301984b940cf5b7e6db97b89d-34K/J,ȨVA%HQPKbN.BT5+f36e9389c38038d83dc7789e6323a48a53d9b353-37K/J,Ȩ..MJPPK lgN(0*f372f4252ddc97371d6dafbf00d55502e2359b0d-8graph{{digra_}}PKAfNط]%*f37c71f51ff74d5fd3a59f334a10c0f115293bb4-1K/J,ȨNLPRI B kz]!PKh$bNx+f37e3f82e3aa468bbf5e156580e43ceed78c41dc-31K/J,Ȩ.)Z fPKybNa+f381014cdbc25d03c9814fb35a00f418e0affef8-40K/J,Ȩ.)LNPԡkIT^ PK kaNA +f39023a1bab39d4e7274c00a90656a3166ce7745-11Graph{Subgra奔}PKaN;sf!+f3b681fd8dec1c35a8ea9b7bd6137bdd31a5e475-26K/J,ȨvuuuѵpPKyeNcE*f3c68af358ef7d23eec4fddc1a159706e8730f97-6K/J,Ȩ..)􃐵0!_PK aN\R,W+f3d679658af49208038351980b646f8a29926ece-15graph{{subGrG}}PK0fNH#*f3d9df20dbed2718a8b2084c0af71daa44a48c07-3K/J,ȨNL7PJPKmgN+f3e1f80e308732936dbb7d5b60daf47c457da572-35K/J,ȨVRBƵPKygN6&%*f41b36497e7c9e531f09b1df75f202d350ff08bf-3K/J,Ȩ..ME"jkPK bgNWwx5 *f42315452baf365331ca16a9bb5944a896d564e5-5graph{dia}PKaNt#b+f430f1890613a4cea09c2dfa9b427c482d572184-16K/J,Ȩ.uaPKFeN8?+f43e61e8fa982be6f0694e47e6eb62bf0fca412b-11K/J,Ȩ7Z FfPK aNq& +f44207aeee40f4c45e8a09be31df0b3e2e6ee974-18graph{Nodr}PKfNeݽ*f44e7d9f4500ecab5905e30885e58daadfa1760e-8K/J,Ȩ9~PK2gNԞ9(f473286536d6f56d219cc9cfde38b6b965ff305dK/J,Ȩ.M*VQ-k!$PKPreNc1b*f47789a4e88559770940e6c9f1e8816f2be3b529-1KL/J,Ȩ6Ե39JJH];C: e! B6*PKfN[8 +f479a8590bfd25bd7ad9a902d9c31e3970ff2a1a-25K/J,ȨV"%0CPK aN{+f47d7b1fda4b6eebc9c2a9c0511385849f90b5f8-14graph s2{{s4 s5}}PKQ!eNBɸ!+f49ea16f03c118ddc8f98d7e8fdf2c74e1e23db7-23K/J,ȨZkkPK8>gN{#D*f4b5f85b70f0509cbc3a4e868478c4701da8778c-1K/J,ȨvL/SJ!PK +3dNp+f4c0866d571d1a6b5310ef3d3637ce6a1083c6de-31graph{"\ ̄E\ ̄Z"}PKaN.]*f51ef7977498f96a9e81b7dd69f9af4c2c2ba0cc-5K/J,Ȩ?1LPKdeN@C*f52c963455a432e435f95a100cd655d3ca59fa17-3K/J,ȨNtO 2G!$PK&eN࿺r"+f56764b8077b1509b8aaff794119e381dea66747-21K/J,Ȩ.M1a ] PK *aN**f5a32762a1af6bdd3d9f0ba641828b4032953890-6graph{{str￿}}PKseN.wl1(f5b823536b329cf185a2e240d4291ffe6d3c0369K/J,Ȩ tҵh|Y PKU&gNAE.(f5d435532b2b3a51dac2fccfaad8d5e2936f8915K/J,ȨP' ǀT3c! <sQ]" PKaNdP!+f5daa4dfed49918305c6f26998d118f7839301ee-11K/J,ȨVy} L8PK aNԂ9+f5e0800c7ae4859bdd47e749a5ce128f08d1b4ac-10graph{SubGr￿}PKEseN=N+f5fd3721e84ca8e2b4a55f6940289b37f7e687f3-12K/J,ȨvQѱPJÄqH`PKaNn#*f61f834e196c069994fee135946a736c8add93ab-6K/J,ȨvMISLPKeNy#*f7c4b6ec3054aa5c040a3a35004336fdc6dab0e8-1K/J,ȨvL/2P(ZPK9fNe+f7cd6ade8cec5e39a843401283893501af5d21d7-18K/J,Ȩ"`PKdNb<$+f7e9349f361c489618b3e33f53651a6b545c98f4-23K/J,ȨurrT-PKffN פ/(f7f145a5461f2a9a05b9a9b2475bff2e1d5a9882K/J,Ȩvt%PKFeN^F+f80904df0f57376abd5ae4ccb53ae010658c73e1-23K/J,Ȩ..MZ0Q PKnfN1+f8106df3a886f9cf30f5fd31dab7671d9bd0a320-20K/J,ȨP'wZ"-kkyPN-PKdNE+f827e82a9cd7cc2c7c034f38f7e055968de8684f-21K/J,Ȩurr,PK dN-+f83b64d9d9498fb70d50d68db6739910810f429c-30K/J,ȨvMIOE&A PK ԌeN| +f84234f38ca1ed56cebbb83ee178c143a7fcf399-16graph{<<=>=>}PK RaNm1 *f84ea00a3c37717e73b7884de49aebdd0826b32b-7graph{Di￿}PKyUgNy'*f864de99bd5009899bd35385f67dfacb74b1f5ba-8K/J,ȨL 3L֢pCkkPK:eNL^X#*f879ec54cc2a467f63710195f2418718387d3fdb-4K/J,ȨVRNtUR$ckPK`fN&R*f87b72f67c4a97d97c88ef7375b44ff63517cb9f-4K/J,ȨLw Ȭ8 9PKbNujX+f88429940d6a10df854cf51bc776ec6b83f8c48a-25K/J,Ȩ)ZPK"aN'S/+f88623f03fed4b63a36ff9383d2830371602e152-20K/J,Ȩvuq{-QkkkPK  eN鰝+f89efe3308d740ea3caaeb0f9e846f3db3b5c079-21graph{SUBGRAA}PKFbNVH+f8ac57ef0114d736468927fa21cbfc083291ab87-25K/J,Ȩ1ZPK aNg+f8b57fa916bd286a30008f84863a9dddf961c4e9-15graph{{{DIG￷}DIG}}PKVaN8+f8c08f4e0beeac1012358fb409377b9a3d273ced-15K/J,Ȩ.Mr?JPKbNt9T++f8d8073fdb3d6e463896af620ace64e342fbe734-44K/J,Ȩ.)L.I34_[ PK aNN +f8e6fdac088292d80aa2a5ccd08bdb24cfe2b3aa-23graph{EDA}PKiSbN5+f8eb897d60a62534af507b07ab25cddf5830c4cf-40K/J,Ȩ.)*ҵDPKQdN]+f90c413f20928bf82e7613219414d823cdf61441-16K/J,Ȩur/PKVgN#M*+f9193b84aa73fed61cfd2943b955bc5290330eb8-21K/J,ȨOZ b߿Ć1APKg]eN,NR+f93fe23527bf1d440de2d6688ea09668bc78ca05-28K/J,Ȩurr a0~m-L 4FX-PK0aNG+f93ffdc4a1fade364f72065925e6ab1500ebd582-17K/J,Ȩ$ZdPKGeNr@*f9528bb8cf0ae17f7a8775da7f8a7aab0aca2346-2K/J,ȨvMZPKfND"*f9622da10a8500df27a4eacdc5d939804454bf61-4K/J,ȨN"Z kPKaNK[-+f998a6a1a60fb4f14256d30ea1e4b47356caa7f0-21K/J,ȨRZ &0EjPKbNez5+f9a274a73319a713908b3a27ee628d0a53a0e920-37K/J,ȨԔZpym-PKUeNt-A1+f9a8a92a465db38555b98dd9f1b9feb9434c9e45-29K/J,Ȩvt/J|t590{mm-PK/dNVW%+f9b17dbe94e41d40f6d11a0dfae895ea870c6c03-29K/J,ȨVyq!JPKgNu}L*f9ba8e075f1b9ffcba2358801f180fe7076a0230-6K/J,Ȩ.BNo p6ZPK NJdNg*f9c168898b23b4154a65ccc52862404d8c6cf3bb-1digraph{A:ne->F:ne}PK]dN!a*f9d9a1f488d5f1e87f6d025fdd73506f73b541a7-1M 0 DEȮt6c2g RdRS(RlF(ffe4573d4aeb1adbd7e9b8e5cf8ff8649b645e80strict digraph{}PK?T eN=<+ 0008dfc8d866857e77ec5d2d941b791bb20c90cf-22PK?:gN.* ^001c85f6736d161f1c71ff9cb45c5cb9a5b290df-2PK?XgND :( 002c5c6891289811343ba1c4645e32ebc5845243PK?mfNSR+ :0041537909b9755cae7f71dcd470b223e4404c3a-34PK?daN=0* 0053aa4aadeba76453dacd6fd23d51789b268391-6PK?aN7 * 006e23acf33a2a19da5c168f0d80857b44f5ec1c-9PK?aN* Q0082d70f9efb6b4b63cc48803930f5d432b1b031-8PK?eNᲗu+ 008a58dde03aa27c465c27bf07dc58654dba04cc-26PK?5eN {R(+ 0092526ce6998afc19811e1e2f7f4b9898e77fb5-13PK?QgNB"* d00b8e761c4b4201920368ed6d794eaf90ee6b5e5-1PK?hdN&+ 00c4abdd0f26a3054389fc3608064e51e90ef11f-18PK? /fNc[ * 00cb70989ad0ff28b0140d93d9ea4ed044a616a3-5PK? LbN'e+ q010b6055d9e5e97d56bb66544c38f04b0a757666-36PK?/dN^}{ + 014fce145fb6f74fa84643ff15a608fc848edd32-41PK? aNrj + %015161e322d273d906b940627fa2fb00bfe68037-18PK?|3gNG,+( w01773c8b1049ccefef339f392134ac5b72817fafPK?dNE+ 019ff0d96fc0b1da7cda1a11872b4129c1153a68-23PK? YaN?Sw* 801a9208477bc839af1038cc08b2191fc2b0dece9-9PK?JaN{+ 01ac7ec5506dbe106672f7607c903ee03a743bc9-13PK?EeN=LO+ 01da8793833e348e9fde3b277f439f80e67b81d8-33PK? (hgN-0)7* R02033b935876930eb057f73f522c5b59e1c0533e-5PK?KgNSKD+ 02281995b4a072f1e01554154adb2d794ec6e354-32PK? KdN\ + 02295991ebad764cbfc3cbb12dadf5dd68f44dce-31PK? 3aN\y* Y023112aba726cde3e740a306b1edea4b1ce34bcc-9PK?HeNZ+ 02445f5a8b83e1a13ffde8f1c94cfa774749474b-20PK? rfN9+  02637d43066c5ec74dcaea759cf691c09b23185d-16PK?҄eN55+ j 027a08436021c49165ec4169a401bb890974f06c-43PK?|aNM-+ 028631c96f3dcdb7544fe19ada449289d1e06d01-31PK?ĤaN2c+ ( 0286a10c124234abe5c569ff8acff25adafa7fcd-20PK?+ '0a02a003c03eb90a7b21e718ee269fd26c279051-41PK?r'eN8+ 6(0a130cfc229123a38c9c73b0a93f238e3cef8769-21PK?DeNa+* (0a20027b2c7ea73c10ab0e7ec8a763c3cd386dce-6PK? sjgNU{v * (0a3592d44920e8e3bb6c965bf98155d34bc31242-6PK?aNY^( =)0a3d88de3800221bd19cc0fa4243058bdb9fe551PK? ƙaNݲ/* )0a3f116a738e4220eef3a3225bf410b7d7a14f84-5PK?cNwD-+ )0a41e9843ed3e9bd762606e102fff906e283bb50-21PK?fNC9@* R*0a482e02efe7f8bd6e3f1d5d9bf2256c2d2ee872-6PK? dN; + *0a495bb2adf440a3539ef5e16551fdf52f9e135c-18PK? ωfNξ * +0a97ecb9191eda2fefc0547b34a3328d336e2100-6PK?fN(v* `+0abc3339d9030776ac4f575bad2e955bc2487896-9PK?fN̽[=+ +0affbaec48ba6af4afb96d0d05d09aac3b9ee2d9-37PK?dNذz*+ ,0b10b1031c11b796059e6c9c07afb0b6eb46889f-22PK?<\eN'* ,0b13cbffcf678131477297d3c645ae9aaa69822d-7PK? fngN* ,0b261bbbbce39a88080322ff6c14a47df9808121-9PK?gfNO-* 6-0b3a3e94f7c27b5c03a435c8a4d29d19ae9caf88-7PK? dN% + -0b8fe68356e5b192eecca94960b1526fb45af087-13PK?BbNy+ -0be61a7c8eed566790848d3194a13ba4357929dd-27PK? TdN^h * B.0bf9790b8be04eef7af71c8a44a039660379ec52-6PK?aN E%+ .0c0c5b18e581bfc6ed54d640c82e63bd3c4de227-16PK?bN+ .0c27b31e97e4946dbe97d2446de62da92e467b25-36PK? fNCP + R/0c33f8c323ac722a2f410188c9117036022befb1-16PK?%bNn!+ /0c668ff77f7598e6bb0f1fd758637bf8d4294987-32PK?fNƽ* 00c7e4ffecbdb24ebb92be66224e19ef418de41dc-8PK?dN5N * 340d80b33a9f6418bae26d6cb7e0e13a674dc5651e-1PK?ϚaNJ(+ 40d893ab9bc4c39d3127d6710b64904bbd814ccb2-10PK?9cN^r/+ 40d914e1c753d336b60538507e03f397d01902737-32PK? σfN2* E50db22549a24841e76383052cf284266d1a80db84-4PK?QaNf * 50dc4c6d8f0fa77f10f1f1018867d1358f7313ed2-4PK?H1bN6=o+ 50dc85e52a4f4e5fc494e2e4c8dc367b1dbdc30ed-39PK?aNwb>m( S60dde96a02221a08581fa0a8fdca5dfe6bf035ff4PK?eNf!* 60e04358aa99c751bd598eca401a676d0961b95c1-9PK?*7bNsA+ 370e0786032d48e81fc347f496db1a0383163c44fd-30PK?aNZIU+ 70e1cc06dedb043a16b1a4ae59e8df56c4cc4a96c-23PK?aNSﲋ(( 70e22995ed26aa5bb6784556af7231cb78840a339PK? zfNEI* 80e4019cf475fba53c69b79e4e8a4e8c19f14f980-6PK?eN]6+ 90e456b80a388b0a872986fb7a3f24ad0c214b838-26PK?ReN;* k90e4f1f110370e72c52c72aa6c8bd18feced4b80c-1PK?aNe* 90e61fb3ccc44c4258eec6df2fbf26007e6622524-8PK? 'aNկ* &:0e6e1e80ae91dcac5da25106f050b9d5871a2893-3PK? QJdNff * |:0e761bfd9019cd3afcb76de1c0a5efa5e3d30e6f-1PK?CaNxS* :0e7d234b16764fb0ba9f0aa68c7c79328ba881e0-6PK?9eNe'ܙ#W+ &;0ebb9c52f13ed5ad626bc4652de5a372f3758c3b-14PK?wdN#+ ;0ec42298efb0efec9a2f2ae09cd69de5c0cfe4fa-31PK?bN> + ;0eda2097a860cf0534710526f8b33f2e54403c16-38PK?nagN* J<0ee39b8e820476e8e68ba86e2f6f86e392df4851-1PK?fN'GM* <0eed9f8fbde76c333dbb2ce4a97890176473191b-2PK? aNN+ 7=0ef8065b4709163f3caece38900ee513ce42a84a-10PK?ӚaN~H!+ =0f1c9ed01ba607dab70958f590184ba40ec4804a-10PK? 'aNHX* =0f3055eadfb6b6f1430d752f6c6db44e3d496861-9PK?AeNt*+ B>0f416baeb7158aa36d29c65bb7352c5133214b9f-23PK?hfNJ>@* >0f5197dac833cbf3ea08d8ba33e811fc64d87b96-1PK?6gN8 c9+ >0f628c013456a5de318453f663498a160bdd4c6e-24PK?fNt * W?0f6791ea2b53b47502b8919909038182fa807236-5PK?aN_* ?0f68cd375558c6019c4185bb36dff540189c4a42-9PK?eN/'+ @0f778ff17403f0bb11056c105a5977d37f6e2edf-25PK? cgNi* g@0f8ce12ec72ed33369c8dd53d2a1d2c21fc1f41b-1PK?aN'+ @0f8d54eacf9d785e493dce2a1c66bd4324ef7d8d-25PK? agNJ;* A0fa1ff4379e4d971ca291ea72e2f0d5a503ee06e-2PK? aNO* jA0fa281a3dfe44ef7f012d49be39b2a56c6b8e54f-3PK?aN)* A0fb4cf4c83a54cfc9037534e9bef53107187db27-2PK?  mgNi*W+ B0fd32429cdadce0bd2ad44a6931f4f3fe9d4a0c7-10PK? cNyNZ+ hB0fea3fb92aa6c7f1ba5e8ca3958808787f78e935-17PK?vaNF+ B0fff5efaf68d4fd2746622718de21c66507b47bf-12PK? xaNQ0+ C100403be607df07897cf6a9cd1194c980111ac00-32PK?v`cNjqJ(+ rC100a8fdd9dff8af76d91e97ebee00cacb4554c71-28PK?deN-+ C1021dac2011318c5d857862aa8b185fd10c84d50-13PK? 1dNddH * .D106206d30764771b86a791e7bb938265d3c42bae-9PK? OJdN"Gx+ D10764f4d2203d6d910e57714eea6230f97b1339e-29PK?9bNyW0+ D1079544b9a4a3fb4c0e44ecf653d63505a9f4370-33PK?PaNpǼ* 8E1079adb58a1ae36565e1c987bd6c98ebecb81e69-5PK?&aN6+ E108a57516a53d374e78d31952a68febc3d955a07-15PK?:gNtO4* E10a1163134aca0c2799d6fc006fc20f25a868536-3PK?d6gNSt4k( jF10b1cca61d1e22ab749560b27d9bdea58f09e654PK?gN1)* F10dbcad51857d8d20668477cc07d995a02c03451-2PK?8gNqu* AG10fdacd10709173549cd3d1e0c70a5b7adee3924-4PK?bN#+ G1102668eca37616af74d507f380755e26f58bd31-30PK?reNg'+ WH112c0b572a04d87f3783e25bc0f20aa3255c4f12-10PK?+gNUV* H1139538b62b3d708d477f5e646682bfdba0d1fb2-2PK?rjeN1ޘ&+ SI114e9f69d71f934194582d8312deb6c2067cc74e-16PK?{BgNϠ|=&* I1153c8f64c02ead4b98ac75455b23eb904f45f68-4PK?gN#K( fA>++ N123b9d7c1c7713a9c24dd47adea9df29c58acfd4-24PK? aNpi_* N123fe11dd68094b9889dcfe77faaa1fb1ab61f9f-7PK? aN* N125eb52bd7ebe53877ce2bacb07bea852f095032-2PK? aNN * 0O126484e469477112958be816a394a32ce3ec1cc4-7PK? aN3* O1297ed2488a936cbb1718c249d18447ada98cf17-6PK?aNsIe,1+ O12a68f22edc4093778b8e6f97879e08b5fcdeb1c-23PK?aN)}7( bN+ u+ 1ea6a1190dc808a6a881bfdbc70abf061cbc9a6c-30PK?bbN"+ L1ea899f05a8d0edc74c119fa76d8da6901e2dc7c-21PK?tdN F!+ 1eb1cec036e42f03935a832eabd1bb92135bd721-22PK?ՃfN-* 1ec2368979c0664c9f0af482128f4d06922c9148-3PK? cNE3)+ b1ee689b2bba8bf33a12c77590c8b9bd9e37e41d8-35PK?ܲdN>0ʻ+ Ö1ee89c310f393de295eeb56a16764e52e9cb8623-21PK? dN(] * 1eeb3051a564f75785f14cac893f15fcf3fe0c94-8PK? ngN&qB* r1ef9cbf9fc7a71c99523130c9d09701b92cbbe84-4PK?>gN P4* ̗1efcbc063101f9d6e92f2d06aaad4836a9f9e632-3PK?aNa6*+ H1f27b16ed526465c40e54db9f020275e7a7a8182-13PK?@1bNy6K+ 1f3638ebb644a9b908658f9b88c1bdec34969a5f-39PK?j bNU+ 1f3b51471e22ce3a7f0203d4d8241dac19f068cd-35PK?heNz0+ f1f425398416b836230c9bc00f2b8f62c61c4f1f7-27PK?]eNf6* ę1f4285dd3d0fade4153d18e337087f7349e465a4-7PK?#5cNɗ,+ &1f54b3db66d76cf442b7d5c480fe5b7de7e60f11-30PK?aNYٕ$3* 1f658d1ba679a03c1ba479ac7b5ff3286f107053-4PK?aN-p* ܚ1f66e925d864c7c142179e5f8414dff5980e9b4c-9PK?Y,bNX¢#+ 51fa5776d7fd1773f8d61682881ade63107caf19e-40PK?EaN"+ 1faab49d0f28ca01e6c7f78e340327694fe0e18e-22PK?(bN'{N#+ 1fbd42c0f6facb9db01a77a8e4ae58f523a2c089-36PK?PeNg@m'* J1fbf68be35d57f1ef2a791c2526fddbc7584aadc-3PK?aNܥ\,* 1fcc8c9f08f57018cbadb3c9685ede7e20d452c7-9PK?aN{;GD+ b20004ea24c9ac98bb3ffceefbae9adfb6ec26048-12PK? dN0+ ȝ2006ade66a56ccc1f07b3bd6298152af93a005e7-19PK?\EgNF&O* "200e369d536a8e18dcd58f5977a25d2b7177e928-3PK?3bN[Y]+ ~2011b863dfb9a5ef665875b5f0e61fb091bb85c5-40PK? JaNמ$ + 2040982c182909aa15999e07eac5e33318573d55-13PK?aNX A( 8204c74887b81112cb3aac65399847ea0ac96bdebPK? Y eN"\+ 2053ac4db3c61c7fcf53cce7dd2aab2bbebe5708-13PK?ƴdN+ 205f018526cb5f6eac53089dd071964358cfd779-22PK?QbN,@+ Q208be04cd597d19a8abe0508028bdb2f5c396f81-23PK?KaN)+ 20b1d226f1bd7645c02daeb55306d047e1d0a48a-14PK?aN ~n+ 20c0c1119fc8527f0933636e6b96f220fcc3df76-15PK?SdNsi* e20cb14d623606ad9ba57c6f17028ea1733047490-2PK?kdNEl(b+ 20d2d34eaaf721bb09c6cf9868f38e9dcf2ed062-40PK?qbNO+ q20d5755ae266f4ff6336f166a07a430e7bf6aee8-31PK?ReN;3-+ ̢20de79cd8fee7592148ba5aa02976d90ca222cd5-24PK? 2cN~L+ -20f17b18616c4166edfeb1b423510ec7e824af9f-29PK?GaNZ v+ 20f7627bc09a6da3af707ed8349c65d6fd682bab-21PK?F4eN`gG?+ 20fa4dbed4ccf6f90ef5d808bb1a2cb2bc50af79-13PK? aN + I2100f83e1d56b9cd204ba381e823e3301bb220ba-26PK?S;bNP3+ 210b7fc36f51bf42c63d09590f87d1687a607c4d-31PK?  aN#m + 21139c99cf5ede2ee961cc799a20442b06180a88-10PK? JdNB[s66* 233e5adae535543b70c834634d4bc198dedd7cbe-2PK?+bN@E%+ p2363c483d257da4ba4f9d58fc42192ee6f984aeb-31PK? aN-;,,* ֭237a785429f82a8937b1b9f3c6ab218aee860584-2PK? KaNs+ J2390e843da23668d4d09c8d779763cc84cb69e5a-11PK? bgN< * 23abe864080c32e2cda61eec5b2c6ad66b60e267-5PK?aN7x+ 23c5a90e5b9621a119c3b5a4a037344a6cb0fc13-23PK? *bNi!++ Q2405f39fd0499603e2e94dbbaefdbe51d7dfe73b-38PK?ǤaNE1+ 240aa41760f04408fbe8a1848e925459c7c8c61e-25PK?dNޫ-+ 240e3e5fb667b2b711640123e9a46284130e4ea1-40PK?jeN]d)* q2412e51ba5cd28202960eaebb9ce0ff45b41324c-4PK? JdN* + ϰ241941e5de27a6cd24baab9bea6346fd33557099-31PK?fN&++ #242b1496b633d010f6ed901fb5785067578ff15c-10PK?ebNЁt+ 2437b0e0aec554737ed5bf5697ae61e7cfabe5a3-27PK? FaN-* ڱ243c629c62a05753a25a1090de7ad207b6aabd86-3PK?9gN5* 1244333f4d9ca7592508ee8d18a4e74c4238b6b08-7PK? ΀fNjtc + 244b60b45d5a4552a0777d090c0823afb7eece0f-18PK?=fNs"* 2451ca6f47dd38b4c3f70fc31165f7e63c869f1b-9PK?lgN:l* >2458eeef66bf85473261bcf9f88f34088a7bf10b-9PK?\fNAKW* 245e23fdac1aab58adf7946cc75032ebc5ae5417-4PK?qdN/tK+ /2463f98d5c5218cf793355bf44f6db0355dcadab-24PK?dN Se!+ 24681a114f61421373ea99ad1cb529221813034a-27PK?fN"5M* 2479fdc5a37d9bc90accbf06b1f9c53679d4ddc3-8PK?=bN!f1+ J249e49a76ebd2d9e1faa4eea5c7ea2f791c83f98-34PK? dN,Y+ 24a1c30bb7400ef435b10e176936e84ed7f98505-24PK?*cN3+ 24b3d45ce6e1b21afdc523383268707deb5950d7-29PK?NaN :* d24b632d6ab94a973f1a897616110637fb209d20c-7PK?!gN)+ 2535b1e9ae3ad6e63025eb47234dec9b899c2918-36PK?BaNԔ3+ 253d0b1c8731049af15a4421f02202d8296f82a7-11PK? dNG+ P254b1d8d340fc0612e3ef55dfe06b61caf92a280-15PK?bN0+ 255d90d2ef8bd98e907a667ffe560d4a6bc4210f-23PK?0bNl+ 25668bbc20b1b2be1771e7346eeed8b4d771c827-30PK?fN]~*$%+ ^25678eb4af666b4bc9d950faa1d7d9efb281d82d-36PK? ԬfN+ 256fc63c93d08a2f04ddc50bd485af7477bcaa96-29PK?WYfNGd2* 257bdadf6c30b99cdead0c4a527015516db03130-1PK?QfN)* v25a97e6af8928c45ba92960b75bb21056b71bf96-1PK? ܂fNV1 * ӻ25b10005f05d36a346a4ee92d8be623d7778419e-3PK?fNm+ (25bcf7adeb36d93f2ae11a66de24009e111fe3fe-18PK?aNcsU/j( 25c6149582ac80ad13e4c4f89d1ae7b1833369dbPK?ybN/-+ 25ee9cfb223550596598247d4262749c83d219cb-41PK? 9aN_^ * V25f6b472544d6654a0620a6c3b7d68d8f451b6b4-4PK?YeN43/* 263d425f6c75f9635cbd6c8d37c018d737f5f4a0-3PK? fN~g%* 264904e8d8daa8e247c894a98a3ea032335d1c8d-7PK? fNO* k2675a61a7f2fd2172954c35e8861896b06ccae9d-2PK?ɥaNS\x+ 267b0d59a590e1aabc3419af65a89f1dd61e90a4-22PK?NgN޷@/* 26b7f75738c8dfebcdb86c7459e17dad4e5bb46d-1PK?EaN5ի!+ y26b98e7e7c654125899d868d05d22a41db190949-15PK?UaNeV+ ׿26d0563e74f4b713e9b99b156ffcaed6f66c67de-14PK?ZfN~`I* 326ef45df28adaa7123c3bc684506f24ac1370171-6PK?NeNk4V/* 26fdae67e6042a9d1a6a800740e9e4d48553b6cf-3PK?2gN>+ 270d581eebe1927e2a9a00c7b54c296eccfd696c-36PK?dN + G272010485670a7e6e5d5ca131cf5494a68edf475-17PK? KdNQ= + 272c898513953e6f497294fb319470ff596662fc-50PK?@dN~`+ 2732bc6ce54e8b1f2f373a86762fe577c6813465-14PK?|eNqz!+ T27354de44fbc8fcf99e08401e83295c7e0360403-42PK?MJdN\K+ 2751ca01df5d6bf879597628a305eba6b15bb537-15PK?xVeNT-]( 2765d8f3b623fec0e9a863feb05b6ef680681e14PK?bN1+ 27673647dd0ef0972209c3917444a4be81051ef5-23PK?ҌfN%"+ 27b09b0924ec428af50f6a0f50d782896247b467-10PK?gN)t#+ 727bf1fcccf19fed31a3a2fd0db3eaacb1432452a-14PK?rcNM%*H+ 27c2ad488070b595d933ce3490bcc3c0957b53d5-36PK?dN;+ 27c9d1e7ee471d56e575ce2096df0ebac807ef8b-17PK? &|aNf[ ( W27f57b897388cfd3c59e59dc148490915b1d9dedPK?EcNT '+ 280365b21e2454d2874c10eadf3401a37fd997ba-37PK?KcNS)+ 28094dc665f9e3d4a6cfec1a5655b4a4bf9d592a-40PK?!JcN+ j2830f7a4bc71a44e5414f188d80a7c63cef088ee-30PK?rbNIx+ 285711a70cc3df32b5e1c0a3501364b930565f48-39PK?MgN|r-( #285e7279a63ca5b2258d17af8b458c82ccb68930PK?aN++ 2865ec34b5d2fcbb887e054deb0f86c4216665ea-20PK?gNF+ 287ae6cbc935c27366b8b7802ce809631c125765-34PK?ژ( 2d1f052904c8a686d317d8336516554c9743f370PK?VaN* G2d2e4cab5e633809d957211a3513c8994c8c5f66-7PK? jgNoTl * 2d360c53aa4badb2313527bf083bc2503789b7e5-6PK?IgN`j* 2d5a6b86cce0e43694a13341ccfff11868f0fddf-1PK?XaN{D0+ Y2d73f235585cf987ce66fb152f46bac6421d54b1-16PK?[bN^꼱5+ 2d803cde902f21d838349b0594357c8bbf996e30-34PK?bfN&(( 2d8214b431487d4712047a4587d02192885c566ePK? #eN* m2db662c9188eaca0267103ee866e72201c2f70ce-8PK? aN;x + 2dd0199dc9bb42eb4464d07048ebbea12a628a4d-20PK?bNi-#!+ 2dd3d4f23415aa7a8e9ca4ea8b387cfdea04ff50-29PK?HgNS* u2decd5a1a2352166e70ddd36b2019f27cb37bc7d-4PK?ZeN* '+ 2dfecc70d59bb969a544d275e17ecffbb0350344-26PK?ffN+4+ -2e014c8bc0fc67a729ae5563a5ef2bf0ebf092ef-36PK?ffNy%+ 2e060e0452bf0a458d6d0f31fb40fd6bc351331d-10PK? gN@G(* 2e0aa280ca1329190e65e719d7d1d98fed97b54a-7PK? vaNГ* C2e125f36c294c2b7989b051bfd4589201f7a1ed3-7PK?fNλg+ 2e2bdde158a587db191ccdb7b0b8396b8e3f93b5-33PK? JdNn + 2e46f7e908fba4e95b09cd3aac50444658695ba5-20PK?gN\0* K2e47e01ba057740ef7df888a1be58552aa1aec05-1PK?aNH%* 2e4f5a922a5ed174344091d2767560c42fcd3bef-6PK?eN3!+ 2e509a0ca88497d95f537765f1545438cc103237-26PK?F[eNoľ* i2e962d0ccd62cbd1dfdf679f968e12cbf67c6336-5PK? dN;- * 2e98dc06379871dd989f746dccd545b74c52f9b3-8PK?7dN^ ++ 2e9e37a4758ed734279929ddce5ea4495b105c58-23PK?\cN1+ m2ededde7d91a7dce8f877b07203b06e8308a9c62-35PK?cN*+ 2efdeee8db27639ea8b18ce3a8544b6b92dddbd4-42PK?0fNbU?)+ "2f0447434a1e68ed41dc4e2d645a0b0890b50f76-10PK?ѝaN^* ~2f1256907aa5eb8ed3f21a8f6849e5255a1b886c-2PK? WdN]~ + 2f15f1157bb2afbc08c33d15ecb4f6a8791cab57-15PK?5feNQe&+ /2f183a48460064a4f2bec953e706db4712840296-14PK? aNdJ * 2f19d675ddeea2e9f02b1921a4c11db6e4c1f626-6PK? bN+ 2f1af6f7bba2343318019552912022133c8bca54-23PK?NeN5+ =2f1c64596078cc42e1bdb306f053aa535d24d534-20PK?mgN .* 2f1fdad013839d639787200567cdcbc3a9ef948d-3PK? qagN:\* 2f22e9f5c09dbbcf5bb65e7f5578e78fb4a20b19-1PK? aNvf* \2f24e82980fb22f91e0fbad3f2f632a774ffbc71-2PK? aNLד8+ 2f26fd0ccce582ca413ab0a9a91d3598802caf5b-12PK?UgN%Z* 2f595c4fe18c0542add2f3af45c77dca3bd20ac7-4PK?RfNo^-(* j2f75f0c6d974810b39aeab2fbab2506d400f9fe5-3PK? dNV * 2f779dd50396145abc1320b067a3fdef413d4d30-9PK?cgNip( 2fb735feab3725e447c45c47268cec80494a9d28PK?fNS5+ 2fc0541b37063b7e3952d1114363da8f5f5219ee-19PK?RgN#8+* 42fc3436cd2153c7c81486d5609743138962ecf1a-2PK?^fN)>* 2fc48e00922eafb82920b78edcf4e89b2737da37-4PK? aN9'( 2fca07ef9d1df28253f41b0ae02db773f4ba1b37PK?|bN?Jz+ K2fd4fd7a0e64994f5ad0ce7fedd2e53a6eb8f527-29PK?aNd+ 2fd5fab1d62501a2004494534c21c23d7d365601-15PK? PfNr* 2febabe56d13af0a1c3dcafb4c8b11eb17106532-7PK?BaN$(+ X2ffa679c2c88732851b22becb0ff34e9d59d4dcf-20PK?)#gN =a* 300cc5af112dce89fd65dc0bde28682523596e25-3PK?@aN+3+ b301200716caded772692f9d86f90185e47f3ebd6-27PK?EfNȦ %* 30165e26edd5d70f7faf0bd995f51b88002cd8de-2PK?ifN1* 304075f2142f0915edbeaeb35e875b0eb5a97582-7PK?SeN-O3+ z3059ec161b11c8e71b41dea4911815554be1a5ec-21PK?]fNS2( 3067816ada1e8c2b55018835934f654f27af538ePK?8bNC+ 30765a62bfe8523b5b65edc6d4db4c062f4f44b0-32PK?i+bN{8+ '3076ec6bff67a7b3cdfdab4dca1af49fbae228a1-39PK?kfN|I( 308ce243529c14784631384ea66a42442d5c087bPK?JeNq#+ 309e3623a19576d3c49cd9d799c97bff9bd7018a-25PK?aNaVq* J30a113bc958ef0cdf73b57f0a88720d6a2fe2543-6PK?aNWx * 30a7521d02bd4f053119972be35a1b1e0b92e75b-2PK?feNNU=( 30bf715671c01a27b25251b4182d09cfaea5a5c8PK?>gN+* ]30c0b268324c870b436df1a88d0f4564df0b0876-2PK?AfN~l* 30f52ee25e26432b5366bb8d1b296cc43ab3bd59-1PK?lleNmw3* 30fe2af11a7795b42b913863110ba175221a0008-8PK?reN,2+ v3120db288036013e2a39ab904b360c17a8c7ba3b-13PK?BdN豧I!+ 313540d36f3ba1a2c8fb05b7a785f8d15eaf6004-15PK? FaNUT? + -314aef710e9693a4ea59f612c06eec992ddcd285-11PK?CgN:%f* 316f408feb54ba19492954a1a25cba4d78aba111-5PK?weN+S* 3170b03770d1971daf20101307020a08bd788d77-2PK?rfNɹ .Y( V3174f83306fb76b5e464fdd1d6f2e3d9f3061e06PK?dNhP'+ 317b76bf859d7c47c6f025bad3150c623db5f6f9-22PK?;fNUɹ* R318d5497b35eb977be54be89e81c375e47dd7ee8-8PK?hfN>{R7* 31901d75037759063cf7bdf94d09cc8d41b5a2d1-5PK?BbNtY++ 31a624ade3106bb08dba9a39fe7d487e45fa0743-33PK?׼dNq"9+ c31dcaf08b498015361fa1d13555d42d5fe49c7ce-20PK? 2aNJE+ 3208b3903df73e464f036e45862f26aaecb7e08c-18PK?fNK* 320a95296993cecff04c193704de36ca251bc928-4PK? aN+aRR * u320f0e4c6a1bfa3965ed4ae974aa9e92c2093819-4PK? jgNR^* 3210034a5335b092e73a5e1fa9b32ebfc6e36a5f-7PK?tdN!S1+ 32152745c7cb49f040f71e3001d641af1397690b-25PK?wfN* y321f5da6e90da60307ce5ce910242d4e793d4799-4PK? NfN`* 32234895a602a04791f461cdbc6277f62db70f2a-4PK?aN.Z* (3236470709830fac6e00a8b990d9512f55b6ea80-9PK?3#eNW+ 3236f0f3cd099069d2e4eaee0924365478f49dd0-20PK?aNe&+ 32511507d6b0a6e6e7d5c86b16ee8ee50c12674d-26PK?!bNf,+ 8325c712701d233a1bd8e2dd006c4e54f2a13bb37-29PK?aN+ 32706d231cc0898d553eb553545c67fc73191f88-25PK?dN* 32a7cf23d31f755b2b45190f7a91320842496a75-9PK? KdN]'l + F32ab0d66eb8e84236c47d67e8154e6d87dc392f8-21PK?kgNbO* 32c1cda892cefcf139eff76a9fed8138540628fa-7PK?$bNxi%+ 32c5f0d2efdcfc999f6b3c679200aff35fdf2287-34PK? đfNG>1* T32c8c013fb594bb7513659b1b9c910762c74c639-1PK?eN µ+ 32e1e100fa98d68c5fdf09d94b9e8f29fdb549ec-43PK? fgNXB * 32e99bffa0a6d1c0649de8eaeb897dad51e5d3c5-1PK?aNJ* Y32ebd24355f6cc34fc016cfa1676a45cb8dedcf9-9PK? @cN{:+ 32f2331de2e358993ee9ec0595366727488dcd93-34PK?V`fN1* 331cd0d41effe69baad38079a51227e1a85cbf07-1PK?CdN* o334ef11e88e7c1e72f50156037e71e4ce670a876-3PK?eNF;+ 335257cc8c05c86927eea3d73a08d5638019d14c-21PK?XaNs* #336b873bb5c721fe5e02f047a8c9b95740977abe-9PK?cNc+ }3382d781682e82eaefd622aff4fe5ef23a0bfe3e-18PK?jgfN܉/( 339d9fe4ea7eefe68054b2cac6e285524e66b0cePK? 3aNN+ 433c267548ac31a0757eba8e403332520dd3cd2e4-14PK?KdN.+ 33c68f91179737bb55fb62380020be5c457885d3-50PK?aN+ 33d5ea2601ff4c989aede00ac0a64270ec3b1b18-16PK?AQgN,S/( @33fd512c0b5b193d8dbec57a100c47051ff3bca0PK?4bN6P+ 34234c0c586035ef0bf9557ee9200102bee34667-35PK? aNumQ+ 343d8a0696c0fb4fe5cdbffbdf17a46bab0208c9-10PK?ױeNx/( Y344a8127a0df9a5d1a0cda324d39e3fcd1583ff2PK?eN`dD4+ 34ab99b645314668f214f020f6ec38fe02eb7f70-35PK? bNg + 34d8d0148dd7ba3e9e332ad40cafe6be6a69b0a2-20PK?d2gNf* a34e1fe80ed7bc097728c47cd0eab1144ba2c1749-1PK?eNl+ 34ea67cdb2a055cccbd35d913fb13f876fc1e6b8-17PK?fN; J3+ 3516c5bbf827e6637e9d59a09594d1c1c0b6e236-13PK? gN['+ v35341d09f94ae20f59ad5ebcdc996a827baaedfb-15PK?fN+|( 3539a2c813d9849808c9266eba040449607b5d00PK? gNT( /354657dfff8df2c237d7b4e0ad47c6c1aff2236cPK?VcNF3+ 356533a9fe665f071d77aa53c8b94d35c35cef00-39PK?bN + 35907cee70a40394fe75e832bda198d7093fa0b5-29PK?KeNp,.+ A 3590fbe7cdb56c1371a9e2911d16a1626fed0328-23PK? #aNyŅ+ 35a4f4ef3914e8363d130f511159f2e2107589a4-27PK?SfNv<( 35bf6166e94e2154d81eac17fa4059c956f3f8f4PK?p-eNO ~{%+ X 35ecc84536bfc3e3d95af448143498481fce8768-23PK?ָfN!$sP+ 35fde9e8540cf97b21578fd11b4a953e3f414e0c-30PK? *eNr+  3601d49a8a5aefd3db2a5b8929baf2da5afb30ce-19PK? LbNp+ r 3602b611d7ccbd85b9ae1bb66647d3b4bae73e69-22PK?fN0,+ 3604d52ed1aec8de1539a4906ad0a77871f82bae-11PK?TaNI!+ ' 3609461aa90ed33bb807d8dfb3097d6a443c2b55-20PK?=fNX,5K* 3613bc3740ffc8268c44833c2ab8a25d79f80c36-8PK?%+gN;&,* 3626dab80f49efe0267c0f9fd01e7fd89f678db5-2PK?xaN߬gb++ _ 3637b3f4efa530279118aa9f4c5ba872b772639a-19PK?tfN I* 3670645e0d3dc26f842360676fa2614ba4218046-5PK?fNG+ 367fc73fa2eb68fabbd74350bdd603528b382767-33PK? aN\+ {3699e141aa931f519c7880e5feeddef94af23339-17PK?-dN++ 369cef041a3cfef4249ac80328bd31f7f9f2be41-29PK?bNLI+ 636b463f4894723a421a9957204170039b0b03f4d-39PK?5bN + 36e95701b5a2d1bb499b591ffa05b7ed50ef5a21-26PK?cNZA+ 36ef88cee1478e4d1cc066400b89333f52ffa813-20PK? fN"* F3709361e44728701eb6b8e254232aa72be342c02-9PK?/dN- + 3730d7353b34881730c7ac1467186caa793a77ee-10PK?LdNHi+ 37324f26e6c886a2bdd4846f2d825e1ed23dc65a-16PK? bdN]e+ Z3737e2fb3e2b47f40f38ecaf1f37e5b6bd28dbef-11PK?]fN=)* 374f7728a10c2c4c841f3fd3e04d792d2875acb5-3PK?9eNf h* 37544dac6d708320b5df49caca56a161e0c1e5fa-5PK?%gN͛( n37631a97fd140db831909519eb0a090720ab728fPK?6aNi* 3770ad2051cdaf3935dbd55189cdf12062b8c406-9PK? bN*(+ &378a5a880c4837c444bb2575466a6244762e26cf-21PK? ̥aN+ 37913dae30aabf6067a46904b8967958ae83c798-17PK? fgN * 379ba90442ff773b1d69d558709b82adbbebe59f-4PK? bN% + +37a1b3c100d6d3054cf009d99f2531acb564a055-23PK?maNk3=+ 37be614e6696a9451054bebd2c5be93a82798083-19PK? WaNP * 37d7257c11261b947cad01ff28ec1fc671ddc7e4-8PK? "eNy- + >37d80e97bc35ef7e26fd7d75d5ba1483c54d2286-13PK?gN[+* 37eafffbf62024a6da8cc015bc749a8372c9c432-5PK?.cN,Jg-+ 37eb23e5bc71541aaf8f9ca0a6fb14f984e944f7-35PK?;5gNŷ6* S3873c098a3c26b47419cd30e73c9edc69608d36d-4PK?aNݏ* 38803a3d290720e1385aece6f3f348eb0bd6ff1e-3PK?8bNuc++ 388855e72a1600932c51c1d3c864554d38b92230-32PK?+gNnY'( _388aaab3cb9259a73a873ee93ac34bda98be0ad8PK?fNE:S_+ 388c97035ac5f4202c890c7dcafeed89e16181cc-32PK?.bNd-+ 3897d449c1fa7b64a41fa5cb04c848d9b542b366-32PK?eNthQ* u389ebf70d95a15e922817318392acaea95e89be7-2PK? GaN5c+ 38bbc8d3271124a9519311ddae89ff9e691aedd0-28PK?KdNGU++ /38e1c90521d30a8db8e5ed181846b2c47efea09d-21PK?cN!+ 38e5e7740a7fcaa686b8b421f3f333911fa1d450-42PK? oagNӊH* 38e5ee08056dbf5fa2b789cf7b181abd9ffdf19c-2PK?}.gN: "( >38e710db728e59a9cda8de902bdf243eaaf159eePK? aN + 38eaa155496c21e316c03aada2894e9f51c58be7-14PK?QIeN/$+ 391a15e5c284cf8c0e1baf819e0871b6d618836b-24PK?dNeH&+ X392fe63b660bea991d119a5da07587929a700bab-46PK? ™aN7{ * 393e9042f4fefe36f64f4b6adc897a8fbe1c8658-5PK?&gNK'+ 39460e0757abe5be94cc2cea5e413f561e6cb5ed-25PK?eN|BX* g3950a31dbec29ae4660a457dc3e4fdb95fc5783b-2PK?\*bN){!+ 397a3016a40f86439e51d42ec636237833019db2-22PK?b4bNJ]a)+ !3998a87b8a293fb96e1681216701286f05b0a15c-30PK?5HgNn]++ 3998d7837ef1b18863f9ffb60f7b6fc6769293e3-38PK?GaNLLH+ 39a1c157da49851e0c53df204ccda62b9c948244-11PK? SlgN* ;39a6c07433bcfbb78794ec9176070c4af55135ed-9PK?aN:$/+ 39f44332af6a3fd552d7de98873f1d55d6044d71-15PK? aNh5Bp+ 3a3b40a7853a93a1928c40b156973d413d45e631-10PK?dN + O3a4900ad9b0a6782c4bb20bd251be3ff63f24f4b-17PK?6fN_F+ 3a79e5a467649f64cc7e30c2956a69367b257fe5-13PK?06gNe Y*  3a7e78b5e7da43f0e9103283021687d5ad7bd879-2PK?aN@Ym+ o 3a82ce72e50066b954940f9cbf377f33687194dc-25PK?ebNuÂ+ 3aa0a4faed21d5c6acb74b4daec30b4ce43d1db0-41PK?ZbeNDE* (!3aa527d596bd296639cac185f55d553629a4e8f8-1PK? ՕaN * !3ac41b3afa6478ce510286f484bb371f520e4abc-3PK?  dN* * !3ad127c10c6b23dd87ae49861912642b7dac93e0-5PK?:5bN71+ &"3ad63bea4cf975c2443e1681230c90106d3e1f12-41PK?%4eN"!+ "3ae6a05cfbb94fbc25c53fcf115ca003a62bb26e-12PK?fNj,+ "3b0dfd1d2bf0ded91300e464a87cde81831c2532-41PK? aNOƆ + >#3b27f9caeb88a2aa99d399da1b7538d0ac3b679c-18PK?bN}+ #3b6320314a5f7a58d5ad858500071cc8d4dc5df4-21PK?:eN8-+ #3b68b2151fb36073964f964723cd97332175e9b5-13PK?TeN&D+ K$3b6ca5b839566b716e665282d0a6a0b215ba0fc6-10PK?pbN?D+ $3b753db25e84b83a257d104891bbab7afc62fb4c-24PK? aN( + %3b75f2f243e9bfeaa6a85dfb5445be27d6d97394-16PK?KdNV+ \%3b9ed451803ca305ffa3c317367df1e8cafea228-32PK?afN* %3bae07df735ef320fd46b5818678d7594094d492-6PK?heNDv+ &3bb29aafdb19ffdfd0f99d54bca8100599042142-14PK?aNn* q&3bc7a0970704e683be39d11adc04cdf1b34126b5-5PK?dN&S+ &3bca912ff6fb8175a958e77075d426a83c88d760-17PK?>bN~"-+ ,'3bce21f3e66d7cb2a86b091c10661268a6724a09-33PK?aNAF+ '3bcf14edab4b2a67a45b72b0e272c2efa06d6195-12PK?l-eNL++ '3be6eaab260e3c87aac27963c955b62c25399202-23PK? qfgN4 * H(3be73c3db9607e6861f8d3563659fcc4b95f447c-3PK? xdNJ@* (3bf2c48e71a2d89a453d83a0839e9074aa8cd21c-1PK?dNS + (3bf75d66ba241bf643ff14047de799b5572f16dc-13PK? ֱcNaV+ G)3c170710fb413b3dc865f3ffd12b6057a5718800-20PK?1gNߣDE* )3c3d5891667aebd4ad2347ce7b2c316ed713d101-1PK?bN# K+ *3c3d97a97113a7aa0af4307de8287921700a233b-34PK? ;bN½ + ]*3c5e71802f08d7d0544165b94dd903697eafd0e6-22PK? 0fN+ *3c62eed307967f62bb599c572179a4acec999a69-16PK?9bNJ_/+ +3c66d37356de0fc90f37fc63f59edf068dfaa360-32PK?ceN~ + l+3c6b2a7c79bd41ab0833d3b693641d3f30361222-12PK?jaNL%+ +3c9827f766142fe05c5e682f0d054ee96060b66c-10PK? лaNo + $,3cba5671b8f316d04b9d38bac4e0f489042752d6-30PK?ubN\ 5+ z,3cc878f1831b1c9598049af400629ff737b93949-40PK?$aN\f=+ ,3cebc43c6cf5e14c84eb697eef0bb8e8099c5ee8-12PK?CfN>H|* 7-3cebcdc33eaf3b1673b3f84f392ef26a7c896fdd-6PK?1;bNnw+ -3d2bca33e9f0c8c2fe3b5e3daa38c54225fb5171-38PK?aN!`%+ -3d381fb69e60e68eb04cc2e964928f5b76c8b6da-11PK?ngN͡* W.3d7017ca6299804256559a79d552ad2f0c8d0a98-3PK?dN8Q+ @/3d7bb6b4aef493b89b840c3c679cbe408566522b-30PK? bdNňJ+ + /3d8d1d7d9a1f3b14938aa682bc31cfe4731087a4-11PK?408f525337324ffa89dfde736656b574a9e57e4ePK?|ZbNW?+ u>409f5de70013992e972f8ab6be21d4ba97aa4652-43PK?aN|-%+ >40a8ea0453a29f8afe4539f52acd09b0fb00da7e-28PK?%gNxr&#+ 0?40cc380aa7d7b86bf50840e3374a38ee042ac759-24PK?fNǭkp( ?40ce8bdbcf4764d80be66d6484ea5783b390679fPK?saN:7+ >@40da93b7da8bdf60f0f0db9b6329266987b1e59a-18PK?aN+ @40f25602eb81eb67437d21b7b49f4cfbcc94a493-11PK?ڴaN {5+ @40f688500bbde81ad009e5d5a6eba695828463d8-25PK?*AgNWa%( WA4121348b155ac2c7fbffff2748fb3d26837b22cfPK?fN+ A414f57f0aefcbfccaa2eba786e8045adae9cecfe-38PK?aN+ B4150384590001fa98d1c0e979dc6d1a3dc3494ad-11PK?\fN:'+ dB41640ae86f9604b377e880a13541ec36cd4ad59d-23PK? řaN '* B4167aabda68356cf0a1d467ed1fbbeffd799fc60-4PK?eNwBA* "C41c27274099d776d585576b573daeae8dbe5bc12-6PK?NaNb\#+ C41d70acf9a75482458e0cd175e731c72479ec804-10PK? fNE* C4202f7534774e951b5e7811a0b3a9ee9ca8a6772-7PK?weN&Y( ;D420b135032ead178ec97a229a0b28d280ee156e8PK?KqfNG-+ D420f7bf26d2da08c92a977a011e9007c701a1316-19PK?4(eN'Nn+ D4226a2b14b9b8b02c7a384e6bfccc807a755916e-22PK? cgNP8 * SE4228d964cfcb1a56ee87dc1137564619d8114b82-1PK? RaNM| * E42315bf553f1a690124aafef448b084e1480471d-6PK?'`gNMw( E423c9b014576997cb078bd055e8be1cd65fbd37aPK?NgNHfL( ;G424aae5076414eac94a1824bf53dad808a95755bPK?ieN2.q"+ G4265237085e4ae1991aa5f69cc7dbb5c20875924-15PK? 96gN#:+ G427c76ccc4d1c3f13bd57bc2f4d39cf577c9b37d-14PK? fNkh + VH428ce867c1f586153e97db11f3e6f567ea5fe430-14PK?dNQ~6+ H42a8a29ed1204a5320f2200186d604e09cd348b9-24PK? eueNl * I42e922c91e332e54826d968765f87707f77d7175-1PK?9eNb׎+* bI42fb9cfdbff915a6343432d66f2d515f69fc8722-9PK? ɀfNQd + I430b010f80b41d7dc88f1ccca854b600a2e5abe9-42PK?CgN\/* J430c1142aed47820966762cb3c262231e57d5959-6PK? aN| * uJ430dd93db1f72ae2a138ab1496b1da8868418d76-9PK?FaN" `+ J4315c0e7a6aa75a5595a2bceef15db028f250048-33PK? KdN, + %K431f0e8ff5ffec7362760c3cc21eafbc42ad7840-21PK?bN{K+ {K43537ef6194dbc4cac726c3a0e233521ad6bb087-33PK?]fN!g* K43649564492896c0316bb62c6d037e992af29c04-7PK?8gNdLa@+ DL4388dce9a25b7fc2de32eaf9c9d656790cfd171b-25PK? aN@~!* L438bb4d256ec503b9580ae2aecf3dc84c4e89d43-8PK?+eNrf&+ M43f85769086a0d931e829f5fa41983f054b83d7e-17PK?6dN% * n4afffe4c27d4ec79d580ff53dcabfd3de779dc5c-1PK?ugNI'(* Vn4b060b1ce985591deaacd4483e65e34f9b416287-4PK?D3fN|=( n4b127b9fcf267dc851300b395be6513e0b5a283fPK?SbNJ(w7+ o4b143989a7f116a1a35a03f3f2fb47ba67a0d463-31PK?(-cN9+ {o4b1bb10dfef4c8296eea91f2966590a2b8bda127-34PK?bNL+ o4b21e3df38f73c6e2db293524689e2a5dfa39c3e-33PK?=aN"lx)+ .p4b3609835d99938b055aee93be682cf53cd54374-15PK? aNjHJ * p4b6bbbc3326e02f236751fcae8f9e7579346ff1a-4PK? OJdNN * p4bb547052a36254e256c25ebec2549e10c263ced-1PK? dN^I_+ 4q4bd0b1ff277d4a206f2b9ae0a4333df60cda47b4-44PK?eNLR+ q4bfe4597c913f6557c80068067f666abcceab704-23PK?:eNڷD+ q4c013050f8753e2470c49c29700f184c2918a664-14PK? aNq\ + Xr4c062e689708a84754539ed0550f78a36e263a24-22PK?<bNA++ r4c38503980cee0ea15cf75ed5a34e6bab1ff0306-26PK?fNy'+ s4c426becc840d1aa7c00db6d5957ba6aae7c3db6-11PK?aN{+ fs4c52db8ad42b925e8bab795b6192bef299824280-13PK? dN!XS* s4c61d2c019021ec5147ca1ff210476369f6d07dd-3PK?  1bN?ܞ+ t4c62c3a8a2ba3e5313df2879835ba1e25eb8767e-39PK? `fN{T2+ wt4c70f8c566c2d3d49208d63c52b5ede46fd0f642-33PK? XdNIz* t4c716550b708fcf819a701f342b71da54fcc3d72-9PK?xgNF`%* (u4c8996c321e8a55f7a75c9e7e7363d1fc654fbcc-3PK?bfN 4^!+ u4c9fd93d4d33e3225e2054951be8c1884bedd4d5-20PK?bNc + u4cb31460676a00f5986d4b46776a276664e35534-27PK?.cN蓸K+ ?v4cc20ca0ed63e29510edb5321765c771f11dd8f0-45PK?aN}O+ v4cf5c989b9e8104dfedaee5cd485acc0d83aba67-25PK? NdN-Y* w4cfdcc424e9f46326643bdb0d55bce212af59711-1PK?{eN#+ Xw4cfe47a71b22a7ba77563aa7e3c1843bf13671bf-21PK?fNRI+ w4d100eedd031ae7796728c6d07d7f2090069ca5b-17PK?4gNI!( x4d22d4abb55d28b84bccd0e86122efcfb80aa60fPK?bNz2+ ix4d3ad35cd0e90f7b08b7138affe068aca0a3c009-37PK? dNy + x4d77702a1bd0ec85dc286cecad1eb09d2321d9b7-16PK? ZaNfI + y4d7dc6a2f8e443f79571179bc8c4c94db38f0707-21PK? EaeNj,L+ uy4d8abc1bc1288d0d1bb3f40670024f7a29302683-14PK?9gNRn7* y4d96226c5fc61304b5dd9682f48d7dc57fab4147-2PK?KfN* +z4dc7039386f631a263aab64747828679c352cac4-4PK? 7gN1* z4dd77eb398df9ea83bfeac8b421dda5f0b28631e-3PK?X1gN;U8* z4ddd874dedd2f1caa3aa23b8e55a88fad56a5061-2PK?ҹfN<'q( G{4deb74a7855ec351fb4474b98f5a0c36abcb9da8PK?fN `z* {4dfd56ff9ac8d8fda20ddbd198ad912e541ca044-1PK?eN%E+ |4e30fedb1176190b3491ca4fd62e4e3acfe0bc71-25PK? 5aNWh + }4e3845d31daa82ad44b6ed42b5c745547dcc6f2f-12PK?HfN$U@* V}4e6634522db1413f053e8b64837c2ab576fdbe31-4PK?  fN* }4e6afd46f11d7efc9d8fece356354f504b37f019-5PK?ubNZXw1+ ~4e7400a66227e11148b574be2f2e4f6f01453e0b-41PK?@feNW6 * e~4e881aafca36163a13c12cd0eff41b1fd437db74-2PK?kueNF* ~4e895c8e4cacad067e75a81b4a7089c0d0da07de-3PK?Q!gNއp9( 4eb408ffe1035f2105ddb6c8f6c71d4cd5a5a0d5PK?fN*s( z4ec3449814916e54ac4884295549fcd87851072aPK?ofNIGY* 4ec662eae731932f0448d3a219134797e3e05d3f-7PK?5aNh.K_* y4eceaaf37056d2b8ecde4d4df468d7c87a1e64a2-1PK?fNPʃ#* 4ef5d396b875275d842a9e750e95921af1b99b79-5PK?cN&3)+ g4ef8af5081dc66662858cbb1a237dcca085edb8e-37PK?9OeN%*Q+ Á4f15a12b41694f1027ac48c51d90b860d31aa16b-23PK?fNw/* *4f2e63dac36c2ed1b5939cffa6d3fc084f5c35d4-1PK?aN/:C( 4f35222cb9d8701f6a5031012cbcc53319ec0f83PK?#gNLf+ 4f439de81a9489c265d493ec5e155458e9790c76-44PK?AeNY'Y#+ l4f51137869a3ba4fd2e6b956bef51e2dabef6a76-11PK? taNA( ȃ4f652c3177083a4b8411fec5a014983eb81a062bPK?aN} * 4f6c5121883d512cd85af67cc8c882445c1c0664-1PK?4dNNj8+ h4f71ec38258a7e6ef8646d79f4c989fe8aeba7dd-32PK?dN"]P73+ ń4f85c6cd452bd339641523a42b42a09c07342048-43PK?{$cNe + )4f88fd1b59939d37c71676738de967d873035c71-27PK? fN** * 4fc595add3ef3b7ed700a5bc6f2af4c2bafaf826-7PK?fN2* ԅ4fd0c5e53c219e9cf1425d71095c9272f42873a3-6PK?ÞaN(+ 44fd4612435ef88264cb2e97a4ed102f21550ffa6-14PK?&eN#yC+ 4ff297e9c68815a33a1824eec98c2b4f305cdfd3-10PK?PeNB -* 504201ebc1529b8996899845ef487bde5f6f670a-6PK?HbN7tV!+ P504949eb49343fba7883e349b73c66c7bbac0501-32PK?fN$ս* 504fb7ff65bcdcfea9ef254908a0b09365016c8c-9PK? fN}++ 50600a5376cb6266916bca19a5c47820f9024e7f-34PK?=,eN p%+ c5062d9191c9ba0f9a6b54e324d1973ab5424b967-22PK?AbN}%%+ ˆ507aa69c92ad6247871757d0f8207575e11371be-39PK?AfN*fqO* !508a1add2b627ba38ebb2bb7e04ff7e038de4477-7PK?ץaNF#^+ 5090022eda4b8cdfba2c804f24815d956819577a-22PK?^fNA"(* 50a251741c1f209217c3be638e720a88c92b6138-4PK?"6bN R+ A50a3af5dab7a66554fb55dfb4bd2f3c3147f3552-28PK?yeNnx2* 50af0078b3974f4c81f1f06713f8089369aecec8-2PK?fN /s#* 50af2283c5e5319028a97e80c8cebfd6bec85d25-4PK? SaNj!+ `50c8908bb8095a41ee56575da41344617aa41ed9-17PK? naNM[V * 50ff4d504d95b4dafead3d94ddb8095e19fd0331-6PK? 5 bN\ + 5100a345dec826c4ea5277b48939e6b61e6dda45-20PK? cNvN+ \51077e27da79abdf95b276e20304e0ed72d21fc0-37PK?O)eNْ:+ 5118126ac89dc3ff6116b03aa668b429aa879d63-23PK? ؜aNϳ0/+ 5127b41576e064a6977297daddd20317691c63e7-12PK?XcN@+ s5134d2ccf7ce901db5f64c7da6491a434bcf1f2d-33PK?&gN3C* ԍ5174cc051fd97ae75ab2ca373d2afbec2bc8c691-4PK?9aN`* +5191f4734f64906ea14fe5fb8251caad1cd631a6-5PK?d@gN{|@6* 51b048cb2faa5fb603403615b3ce94c2c3f0e456-3PK?.eN}j+ 51cd960b5ef3af41fafcc9c35b7bbe8d1cbe816e-11PK?ݴaNr+ ?51df0cf3888d47b7025a5a2590d9e44180976ee7-25PK?YgNRBU+ 51e45b4ad25d6ea934d180718aba422724ad0664-15PK?fNS%+ 51f53d0a25cc7866c3cb52288d2d5d7114d41a1e-31PK?aNqT+ V51fabb8fa606cae2a5451ead195245e51caecd2b-12PK?`=gNp9* 520097d641205162cbc4982a38c7ef3b43968929-5PK?X'dN"+ 520eaf051be774ef17ec30a7d1b6fda01c76c58d-29PK?nhfN`1+ g521780263bde61153d267bd7f99c7051124f6cb6-34PK? cfN* Ñ5220478ec1c7f95eee467d05d5ab0d5fe438738f-7PK?peN0+ 522594627336c19cb630c7d88dd5defca8aa9d8e-23PK? ofNX * x5249e734c79669b9d032272e76230f6a71f77360-3PK?aN<* ̒525b264b9a3fecd8c178b5d6a239c0b2404f7056-7PK?ybN+ '527aa25c096917d10dccdf1b7d7e12fbea1712b7-34PK? aNo/+ 528145a7a451aa03fa15e086e65ed61548fd989f-10PK? aN'P * ٓ5294a1a94bb9295dd1c53d828cfafe7f5992b544-4PK?aN_+ /52a7de2a18e99ea18ff1c5d9c38519b14be97107-19PK?eNvp)+ 52b4d13288fa89166f48645a8f81f5f1556c47d1-23PK? aNoƦ * 52b80d96b2d8e64c27a8c381f51d8c76418f1da9-2PK? `CbN`D + C52c3de56225db3e6c95db7561dd422b3120026dd-32PK?fN= !* 52d0f35a88c3a30fe0e1c20e07c48ac6ace0ccf5-6PK? ],bNQ{+ 52dfd959eff0d75b98735ba7647e06c9860be10d-25PK?fNx,)* J52ea660772e8148fd202d0094c330779473d47ce-6PK? bNhC+ 52edf67cb8a8d35432db1c8e031c7b6d42f048dd-26PK?fNA !>5+ 52fcec3a4555420ab219c660914ac69e162a04b8-26PK? aN@ * `52fe5e64998791f6800028f6812c60e6f2f466f4-8PK?XbN̝+ 5307cccd1dfa00480642190728129c34ba521c37-40PK?kmgN~+ 530ec401855a0f9c8fb6760f8dd256590f214f7f-10PK? gNi( k5316c02533c04b9490feb7b7ed23178957f7a29ePK? jgN * ˜5318038f8bb16bac6b08bc5890830b04f7071654-7PK?bNa=V$++ 531e66841dd168ea8ec4d1bee0991026f6ade1e8-40PK?gN5!'+ {536e21ad8ab2cf3e01e24474eac2b9a0f2db6bf3-53PK?cgNfn( ؙ539c59e94e2ef1c6a2031a175397ab835533b17dPK? ngNb<2* 53ba3528628e2787e3220a06e0c970941ef56a93-5PK?&aNŶ-* 53bdad46fdd5d8ada3e48575a20f5efe12d6fdc2-9PK?NeNBM5* >53ffdc238fb3310a39874392be7a8ff88763e223-7PK?ɼdN>\+ 541a94cec9eafbad8031ca564a7d8adc491c3c0d-24PK?  aNAF+ 54201e181c51ac9118400356292a3ef009ea2b0d-24PK? LaNp#+ G54265ac66dc4b48b84ecfc66aa4d6b5e41f4f81c-17PK? bNl{+ 545aa45d539a5ac767bce95680206a3271b9b78f-22PK?aNd+ 54711db82b8294c98b3ed33853f1ee1f3065cef9-18PK?FgNAAg* V547c9b14d48c6376fa3abc348c55497b6e75508e-2PK? aN&S + 5482dbbb8fd42d2b30254400488a03cbdb56aa92-21PK? 3@eNs+ 54a678bf1a553ee78b3fdd341c504bf329899e2e-19PK?cNH+ ]54b40e396157bc6393e852cd324146e6dcbf3a5a-19PK?\.gNc5* 54b871d41dcc28d8834e476c11907ade72bbd80f-2PK? CjgNB# * 54ba2995d322ea0f881d0e5e6d61ba37e773fe36-6PK?fcND0W+ o54c511d5be306f43b2c83b0ccc1fe06399ecde6d-39PK? aN} + ՠ54d7cad0efcdeaf3f84bedffab70d9e0b3069864-12PK? ͞aN'J+ +54e217186c0784ce98dec1a5ad431ac0955ad2b3-10PK?cNcI'+ 54e92d2cbca1e7cf09a3026bec391c13640e43cb-38PK?gN_-( 54edd2b7cd7244267d7c1a9e81a282034afcf4edPK?8gN{4* A55056d845ccae5adcfacf89c6c420590dc771172-4PK?;eN z)+ 555dc2e58de1ef2e342ee4b454c33b7724f7b45c-12PK?=/dN2u+ 556ba0cd2cb57c80500d598aebc36564610296c2-29PK? aNŊ * ~556bf75dad5243d2e15dd8cbf97b09dc87bc8d17-2PK?3bN0Y,+ ѣ55804abf7031a3e8887da608b1041eff1511d415-29PK?[fNs(+* 1558d7f31bf6d7aa5637ab2de4b2f940ae5e1dd46-3PK?aN@W* 5590d5f3baddc77823b8ef61526e050d1f9b76c8-7PK?aN+2+ 55a514e0494f36b16e5900fb1bcc8e3a52154feb-29PK?!#bN+ J55a8703303972e661ab02fac41305247caefa8cd-36PK?0 cNc෭!+ 55c1533bc194a2198db872954fbe56f560584e86-37PK?5AbNO'"+ 55c870fc7c4703f6ff08d48df37b6ade8c4418d5-33PK?qfNldQ* Z55da054c810347fbb082f07c8d4e91cd1a77077b-4PK? jgN >* 55eb4a065345360e67d5700ed9425e39e1aa8109-7PK?nfNk3* 55fafac06fe2081c45e413f2c78d9f7edf6d2c0d-1PK?j@gNƺ#( o561b8acf9e4a5fa7c697bfd24e2f7651dc5e2479PK?bN  + ŧ5662fe13cc31d6f24021536d98310826f41c317d-28PK?VeN0;+ $566f9a4ef658faf636e2e0f874a5be228f4170a3-23PK?^eNԄ1* 567303745506032692bcef8715830a478485003e-9PK?eN&k69* 56791932eb6663e327c617a95594bdb4f5b51f5a-4PK?G2bN~+ I5690981900f59ac4c7bdc051246dada1f6127104-40PK?fN=f"S( -5a9d94f42a39eb4066a09573abfc475ccb2e3845PK?qbNe4)+ 5abbd1c4b6340ba9007f586800561b5b9d653c83-35PK?)aN܎%+ 5abf2722b9512172ad0fb3d652b0940850b4a040-21PK?aN]5+ N5ac3cad831fbaf5ec98f4f8733227337be0fa0e6-15PK?BfN&}*U( 5ac4f0a99528aa9a3c9613221b6f857a3b595118PK?dNc1+ 5ac5f30a40c4507f6c2373f6a06530786668bb77-31PK?KdN3ް+ |5aeecc67a8ed5b3332c979b50da2dd3b9c7b1a30-33PK?ӌeNwk+ ֿ5af5365ae9163e8f5661b467c5e345332acd0744-17PK? .fNp* 15b194e69bcdf49322196b6a542703fffed8e0520-5PK?dN 2:+ 5b35f60f51c4f28008e79c85760077aa847127ec-30PK?:fN#%[* 5b4ce1c0e4387f3cb94eca76f525628887b10962-8PK?*gNbl#=* E5b568b47b63600cc7a56d034a49cfabc0cf39286-1PK?Z,bN}<+ 5b809a88f676d945f808348b8bf00d647219a1a4-31PK? HeNirƌ* 5b9807c30e16279e851ccb0586c1f64a2ac243fd-3PK? ʀfNU ( ^5bb2c565e5c550e26546825829c92923e83aef6ePK? aNL + 5bc48daea509a1d96f5e0fd570e8855c2bdde0d1-15PK?NgNx* 5bf714585862c29591b76d52799d73e7c60785fd-6PK?jaN+ b5c0a237537b066300ce5fa3b96a14b856a4f0531-12PK?yaNnsrY* 5c18f6179430256ac41cbb409cfef578c4ff3d9b-5PK?̛fNQ"+ 5c50ef8f8c86446dacfbfae09158636a749c4101-12PK?&dNN%)+ r5c66de921f2a658edf8577a39b435bb36a993a49-36PK?dN;ȋ$+ 5c7f7d4947572b114fb02692c1370ad2132ddba9-25PK?c}eNq>rG* 65c811f2fcfb86159ac396b417556b1a259e5eb05-8PK? haN->+ 5c8ea1d05cdbe83fb9f68259550d7ecd3a027c10-20PK? QJdNikn + 5c99a370ede488afe8c5415afc3c9f372fbd1b4e-31PK? aNƕ- * B5c9d844e747a3e84ff2683454fad1b2ba7ce940d-2PK?CgN6".o+ 5c9ebcb2fc1ba420e36e9364af3369e091d8b094-36PK?p~eN3* 5ca377d2c9dd089c9ddbdae2b0e7b40c6ca18359-2PK? RaNh * X5caef7a30c6d179d7cefda01a9d2e37c06d69324-6PK?w&bN6/+ 5cb1348bee9960bfd55c6382fce89013ff52c15e-32PK?TdNeZ$+ 5cb5acf5ebc04e4b8b9e5890e86a203c3d741501-31PK?M<* 5e8d011c7cc8934b383fd42f3487bc71d3e0cc0d-2PK?eN F* 5e958a030e62c9d902758fd8cea2c11f14007f15-3PK?>gNY O( [5ea2619b0b1f0e3ae14435c1a8947dce2db6eaa8PK?*gNK* 5ea37db9e4fe271b6c794fa79e66ea6f562ca7ef-1PK?/eN4+ #5eadba5013e42020b5f16b0365551f5ce3092d1b-16PK?eNX!+ }5eb023039e682b6a095a8dce06b0349a6d2e62d8-17PK?fNҫu#S* 5eb12dde6817179466e0efff7fa7002ae84c4fc0-9PK?%gNj'+* E5eb1a010420b39d5e9747df7d30bd63cc19c88eb-5PK? ghgNP * 5eb1a1fa220731f2c7601bef884afd1849df5e83-4PK?nlgNm u* 5ebba4dcd8f61e675090c76b531ad2bc54945f2c-9PK?QdNmT + U5ec7abb6cf79a20d0c3a6256a0c78cdad5133811-31PK?aNC+ 5ed6cebfc652795cef77430db28ac063b93ace35-26PK? BfNU( + 5ed771fcc8ff94d053797391fbb76b03a7412b78-23PK?aNI+ \5edf9a68d30bfaa2bf17a8008798771d2c44d7b1-16PK?KdN^M+ 5ee5c9a235d4752b81eeecd1760f2bef89d26a04-32PK? hgNj * 5eea126bacae5d5c97e72a8aba65d6abd0a46112-7PK? [!bN"I + b5efb37fc99012ccaafcb9772766f6695c6b90fee-27PK?daNſ2]8+ 5f14edb10030d998d84ce9a0b3ead1cce665b576-20PK? YaN+ 5f20d5deb6e0d93343c8c171d1fa96c46209aaa3-13PK?nyeN0/* v5f289c3359c02c49bfa0fc68241e6608bb5e7039-5PK? KdN9D# + 5f2fddedc6b98bcd2e1d841d70dce78ca5f459ab-21PK? {KdNFG + *5f3ef96ee1d811d3a27bdf3eb4837c6b4b5a446c-21PK? gNa* ~5f4300b5d68f86a6661eb13b0e7529bd91e1d24c-3PK?RKdNW<=* 5f4c7d0c46d3e0c32ad1b041a0dd2798cb792d3b-3PK?eN(\* 35f5a922f3d702b982bcf851360b7104df3085c95-4PK? VdNm1lb* 5f8a1dc8721e8aa46108dff17cfa67687ceedc83-7PK? cNQpa* 5f8b46427cd6136131b39d97e483e17a38a124f9-4PK?aN,0+ H5f8c4c4c4e49d7e2dcb6b251ff8d6dfaf1dc1903-13PK?gNv*+ 5f96469b2d6fb2f511fcf282c58d9e5a2eef9b05-15PK?!gN@6q.B( 5f9a499807f5cc32298786245833960dcd3c703cPK?MeN+.+ [5fd9c6976d4c867ee79a7f54b35e70b82d819696-29PK? fNj+ 5fdb3d7494f940c2e8b2228298529faa64d2ad03-31PK?JbN+ 5fe4ff6dcb0cdd0a5eea15e60b6347762f74f2dc-36PK?"bNEM+ l5fe756b6a68e96c48cac629c6c12bbec5f9380f0-35PK?QdN3!P+ 5fed593ffe61a8f6b26c691fa2aa58506d4e9d78-24PK?hefNz>.+ .600b9bd9d4053916edd0cbcf119fa3cb9db7aa0c-21PK?#0gNh+* 600dc810067290c04813fbc2cc1499028010fe48-1PK?+aN[* 601619da846fab5fd0353bd884059ad0bad97bff-8PK?OdN=* D601b7430a92f8d956683dc63d204bbf12026b119-6PK?8bNc_b+ 6021311ab37a5d48769e6d1acd2017ccc37bc710-23PK?dfNKD!* 602ab9c2c787c3bff7182de16d6d24cbbf79d2a7-5PK?aN%+ P602b800e829feade52e18c9d04e33c8d7cfc5ad0-11PK?XgN߁"* 602c1e9dd5a44a89602a155dd43d70507e820810-2PK?ģaN^* 602fa5bc3fb7565787ffbe1c704bcff1339cd542-9PK?fNJn* d60482e3bb9085599feb5abc2e0ca1fe41c9c1c43-5PK? fNvp+c%+ 6056ec0d5691ce9574b54e75349f1e7f10ecd4ef-20PK?<bNW+ 6068b042250701138bb9f53394134f6055c40f08-28PK?aN_8]+ o6084b85bbecb9c5ea6dfa30f52e7a102b9c490a2-13PK?laNsցl* 6086ea13b41644f80334bd21e5a8762643476fa6-5PK?T,gN*3* "609f6727ae915abc1e525b3145a38aa8fec8dfa1-3PK? aN] * 60ae106a39224b8733312bcbf2cc2b0f6ae11eb6-5PK?EfNo5#* 60c418e56927b94acefb5a83e88021a0430bc02c-2PK?8cN{C+ @60cd07af0c84aeff6e71497ff8502bc4960a16b4-33PK?ieNN"+ 60e341138f95beba1fe55ed3316d012e0e8c4e59-24PK? fN J]g 6* 60e957d044e00fa1473b84a412176a5fae17b0ad-8PK?f(gN-䓀'* n60f08dd6cbbbf55eeddb33735dc3bd299cafe42d-3PK?;eN˹M* 61276c6e171d31b0134b1dacf0c3acf19e00712e-5PK?gN\ * *613506b8ff4c7a56bf482d1b2843cc569c1774c0-3PK? |aN * 616c2e6d98d502a60bbe8b28d002ee897f5f5664-9PK?ʶcN?}gP+ 618765283b5122032ba4160ba1b80ea4f8d717e1-27PK? NaN*'+ @619b2b1ddc3b19bd3e006f6b8c9aac0ad2e06711-11PK?ҬdND&+ 61a33c9f694e85393b9aca9060a8b8d21acf7ecb-18PK?gNcU[* 61a5059e8815526ed9b9155e0308b57acbf381f9-5PK? NJdN/ + W61a52808b3e6724bedba291379a5b05e7c6ceaf2-49PK? aNUXK * 61aabc01420dfe13b0a78eed3c7475259af71075-5PK?;gNa * 61c28a7b4d308d78256269eb8aa3b266348a86dc-3PK? aN׺x + _6206855f134c3b7eaf469104f7a4ef544f0e5f8c-26PK? cNNG7+ 6206b0bf8efbb3bc177f66b7493a1afd0df5ff93-39PK?FdN+ 621172056a699e7dc1358902d2ed5b57677a9f7c-16PK?dN*+ l62178469025788dc03f2648867af99c8636f98d7-20PK?1bN+ 6228bbf012b3e4ff30a1b9ac549f03b21991a604-29PK? XfN0J+* !6252d9d487a99f51c3617c18e8d475173dfee3d4-5PK?KdN[@+ |625fc3260cc982c9f326aa5216cacbd1340688a3-13PK?.aNeφ=+ 627ea422b7a920b975d467749b18b47dcfce2ce5-11PK? gN¤aT7+ 7627fa6adc9502d6ea8a8fd9aff1ebac8abf869df-43PK?1aN(',* 6297e756965abff1bf6c25bb103000b3a3becde7-7PK?gN#[-A* 629aba6b839f9d7320196fdb1508f425eb2b0a5a-5PK?cgbNR['+ T62d07a3ce41ab13cb470bd3b8b8bb3a9dca5c0b4-42PK? :aNbt+ 62df3189217188ec14407058cffd87847ce4b99d-20PK? aNYV * 62ea44e7a6189f9fa37039cf7ffd8b124f17d8e3-3PK?eNw+Z( c62eee5c7ffae2984a4eb292a9b3ce152185d6c84PK?)fN<+C+ 62f82e46d34dfec76c84514914c14d4a8aa32d2d-37PK?aNǯ7 * H6359c2d498eb6cf0bdca259c7afe1e21fdb354fd-3PK?˙fNJJ+ 635cb156bfe7abf709d9157ac0faafcfe65566b6-10PK?fN{8+ 638515fc6e549abe0af93b7f6ebb9a7b3ae2a48b-36PK?zeNNq5* W6391bad243a53a164117609a2d58f3402bb3ab22-6PK?;[eNH <* 6396d5c00c05a1037f94af157943df46e96b85a9-4PK?/cNv/+ 63a637accaac861fa3d9f0db78a856e58cefbce9-39PK?0aNgn=+ {63ac2f6394c0f04fc64312ed1bc8399604423d35-17PK?&NgN^@# ( 63ae161a29818cbb37ba9f82340b6f90afc63b3dPK? aNO * 563af712695794a0c6be3ecee45b4603ab3793edc-8PK?c?eN/+ 63d737a35130a92e8e06c401231a59b444c80bd8-10PK?!gN#* 63fa8c5071281735a4cbd31e2dce535e5c921ae6-1PK?rfN21+ A640f18bf235dc84d33ddfa15e05af54eec253de3-17PK? aNNA* 64199a0e6b7c0e839e9bbc169ce26a981dc137c0-9PK?AbN^p!+ 642f538343f33fbbd96590a7ff512dab90f77733-38PK?dN;1+ R6434039995ea9acea9d9ca2f6be8de74bd33b79e-37PK?fN+ 643685ddf24330c21e01103b31253103181e3b24-30PK?|aN@o3k( 644b64970f24441f2bfb8c8cc57a761aed38b784PK?VbgNo٪ * 645abba47886bb2d467b5f85decfa5ae428f2691-4PK?NbN+ 64687726425e0fc64420616fb021302a648595c2-37PK?zbN 0+ n6479bdb584fd933547d43fd8036665a8f9dc781c-25PK?aN:w+ 647e588f5bd3196ee92d13b43471c1a15b3b7604-31PK?\dNH++ (64848995994ee4ed25d77bea6b32ff7503cf272d-32PK?-gN( 6497cfd266c5954b052c0dddc6cf75d5440d29ebPK?J3eN+7 .+ 64ad07b6967fa3d800e8a45546bcfb538ceb64a1-10PK?4aNI/+ ;64b576e06b36ff46a674b5abbb6987a8716a0fd8-24PK?aN]+ 64bb8a9b1d4f95ffa7093d2adfbcef3e4021e9e3-18PK? JdN[4 + 64cae06fd77f87ff1576fbea8f5c97988ab54052-32PK? ݝaNI[h+ B64d0bf38c1d2d91c32aa7538420b8b9321faf6c7-13PK? bNy+ 64ddc7fbf9c0857e46255d928f6778c7c30e0805-34PK? ҚaN2X+ 64e6f5a768e7314dd8d61d57e82afef71e113803-16PK?PbNZ8W+ W64e991a9614a33310ddc64f00379dd8191f9de82-22PK?aN{56+ 650054700a6b431748cf7f5c93664ce475f17b3a-14PK?-dNpm 7Q+ 650531ef9b773e06a6ed6f7eb383fac5fe16b3f6-29PK?9KdN赉 + 650cd9541206c7775291af1ef05517f089245fdf-31PK? maN\+ 6549ab65559d6ea8d7c7dc3e3286269892675a0a-11PK?&5bN[Ν9+ 96554a05712eb3fb46062a0b378f1cb0b3699f067-31PK? eN #+ 6558b5927b204a5f6de6a0263ac5165cd2cdb4d9-19PK?+eNlz%+ 6563e3247a65e32f9d6d3353fba320ca29ecc0d2-22PK?aN* P65685d8741bfb1bb5956eae19c334edce82e9ca0-6PK?1gNGX* 65920a2f2c6a2b534cb58a2c655a49d9c8e85b9f-3PK? >bNo+ 65b1ac5d2f83e537290258dcb202e98e13587bee-31PK?̡aN0* i65beb7ac2cde16506111210fc224a23616c25ccb-6PK? aNM * 65d04f3f78e5032803eaf4c260f64eb6d2a1c315-3PK?ieND+ 65d8ea1311e904c886d2be4e327d295340328a30-15PK?ݣbN7S'+ z661034c3d645beb0d0f83aad646ea4f566831d27-32PK? aN*"* 66272378a49934d9fe01467a36d16eb5cc269fc8-5PK?]dNkL)+ 1662b8cf6b39f1a4f7d12b139cc749ece41c83894-12PK? aN7%$+ 6635b4e39df28a788ddb79feacefa520e79bde87-12PK? aN * 663bbac210ff8d95f466a05363cb52ca1724800b-3PK? f bNc + <664059b10d04031087c91e260effd16200a29bb4-19PK?"aN6s+ 6656016f2001a20ad570446e11c13b2a3ac139f5-18PK?݈cN;+ 6663ac68e1e5a0e1a990800c17e2fb330bd12bbc-38PK?FaNSt2}{( O667fcfe9d63305023f90814ffd591f15a632da3dPK?gNď+* 6687f78af73037cf852ad1ffefba687b6eca2c4c-4PK?bNa + n66908ae39fd45671f971c733206f068bd80c91eb-28PK?bN2nD;+ 6692057f69423cd9b5eb518985d2ebf93bf2bef2-35PK?!eND9+ &66a047b5cd9308a5f8a02d2ef731dea9519764fa-20PK?HfN" * 66a8302e697a525652afe4249123c17dde02a9f9-2PK?lfNl/#* 66c389b71ae234ad4eec6409e8b5775d0bd919f0-9PK?=bNn+ 966e7a871723dbf816e8122abd4bcdfcaa6dfd1a7-32PK?  aN + 66fe04495b7e9d897d66e085a847a82379e2ea72-15PK?!gN\V?* 67023e1b58be54cd1ae7ef49316594b6b23060eb-2PK?peN 95+ M67071af22dd9e62540673eac6c73a20f7967e35c-12PK? aNKn:+ 670b3813ee60267053ec07cf37cd555b019d5527-11PK?aN+ 6720ed948d94a558a82848b71b44269a9d20cbdd-11PK?`gN=( \67210f46d300cbbad9ff48cf583c165094e2c860PK? -aN:+ (6724ac39e5d6e134052774d39867467e60e056df-21PK? eN.@xJ+ 672f426d8390285e36eaeba9f1839d0ebeac29df-17PK?FgN|%+ 672f75bbdecad5747c663d06fd78b506ef80989b-37PK?5gN1I( 8 674b63bfb6bb690dbec23414a073bc99f6a1626dPK?>dN#+ 67750daa08efeae3df5b84e15b42155cf0f02ea0-13PK?ÚaNi* 67910671746af75015eb5be435cbae87b85bde2c-6PK?laN+ F 6792c45ad750acdd91369d65eb8e4e643b5937f7-17PK?3bNj+ 67aa9f449899f78bd7ad3275c9081d7b54d6c369-31PK?q!eNMg[/+ 67be91068558811252e5dfa2de923bf177c5258e-13PK? ;dNˬ+ Y 67cfc00f8e95728f4714868486287f9e10341904-23PK?ؤaN;7\+ 67d8d6965e0146dbc3b5d5cc73f0beb704efb376-12PK?QaNj|;+  67dd72feb91d131c6572c98a9bb9086bb12a5af2-11PK?fN'e( z 67f403a815978599138f2616297a9984bb7c9f0ePK? aNj + 68299e83d15ef0e60ff44869066fbc4862718f44-14PK?eN=T-+ = 682b07d86c02c0f6fd8aca329d391ad327da0561-11PK? bN PZ+ 6831708dbdc89efef3e1a5d3428cce875655a320-38PK?bN+ 684a81f936db37f5325f5c920ad195d17aaa1ed8-27PK? akgNBi * R684feaeefdcaebdb429dfdda8059e136e5949a22-7PK? aN&ɠ + 685b21b20c804ff7017e94702757780158900cf1-22PK? bNR+ 685df89972e1d9675d24124ba16c1bd71f33982c-24PK?)7dN<+ Z687557fec52b8881cda32a0d95e789288f1c3e65-33PK? aNE+ 6897b9897e3663f82ff20c4696cae5fa4ffdbcdf-17PK?fN˸<$* 68a1362cda6d124a0a3ec7e34dc82cd4abd4857e-1PK?4fN.p M* l68a5cf10d36eb703ad2919b04befd2ec9cf0cc0e-1PK?bN=+ 68dde7575b969f2c03d14694fb1d5e2e2d41bbdf-25PK?lBgNeNΥ** Q693dcc4d57c0784b1013f6448c04bc480fbc8734-7PK?#gN!( 695c60976742e9f672883237009f12b39a03b5b4PK?cNUD#+ 69671a8d24aaf46042b73fd067908ea45bc8a36b-42PK? bNCPc5+ x69a376fdee1d2794513705f0b5f2ab422517c0b1-23PK?TdN%J* 69b2ddd8c4313593e7002c0cd2570deaaa1f6699-6PK?+aN0R* 169bc114fd1c32ffb71c3e69bd96907c0435a0018-7PK?8bNoQ@+ 69c6924259aa6577c77e874e0b1d04a2190f5803-32PK?(eN|&+ 69edd4fba86185fd7d0d996a9f4d9c5f9e92e734-17PK?bNR)+ K69ede99a4413eed56e179d74d7033bb53652dc45-30PK? bNRuU+ 6a19481e56e746b8b28b2901378340530475e529-23PK?ieN%+ 6a1df76861decddc140cd70d14175bd187f979d7-26PK?aNVB* ]6a203c8963cbb476c50ffb6a89955d01558373af-9PK?fNx+ 6a48b566849b0326dd02fd3d1ec5afe8d3c1e73d-15PK? dN[w+ 6a5e87e6dd519a83f391a0ca1a1af479c11ca3c2-20PK? fNnS>Z+ h6a637e2851aa801474322e64640ac53c0182a921-11PK?uaNʥ* 6a6479eba7501f357a4fd9c9c5b07856e68347b7-8PK? XaNn~!w+ '6a6bb83fdd63d31a81d6183a45645c145964f98b-10PK? ̛dNKrk * 6a72a7a4bc3354bc849f1efa9d6762fad2cb0b11-6PK?|-bN2K0++ 6a744ebd913fbedf73b2d3311a01071a61de77cc-41PK?gN'( 06a830731e1eeb7b94f1773135102ddaf91cca688PK?=bNUl6+ 6a9141d1dff890f8de2b937b2cccfa1a40dd0d32-28PK?aN + o6a9213de9621270b40d9cb109487eda54f721f41-28PK?gNi/,!+ 6a9627213ad965132c82d79f016a8ef56d404d54-18PK? gNq;&9+ )6ab6b3d4c273a09f784614c31efe61e26fce2525-58PK? aNRmK> * 6abedd0d40aaf1652bcd7ed88c02adf1698533cc-4PK? $bN5 + 6ad94f09dca95333705fa1731f6d89d95061c4bd-28PK?aN俦* 66ae956100de9a38fe5f0e4359e65f2fb967e038b-3PK?b5gN f* 6af334c16949c481a3873b714b5fe592c1f8310c-1PK?gN;%=* 6af4fcb391f63c9f225cca891e6fd259c9e566c3-2PK?aN!}@+ U6afdfd3039ffe3675c79974f9a522ee42c62d9b7-14PK?pcNx(* 6b2e56b81ad9aec535646013634f5ee9dcfb0244-1PK?bNIy++ 6b2ee52a0c6f27d3d5b25463ebf5737257bb84d7-29PK?iTgN|U}I* q6b3c2533f7a2a38fd2ffa70aedf1e4220a549bc2-7PK?EgN$+ 6b64f5e3697627c526686718bc19496a504fe3e3-36PK?m`bN F+ -6b6b991b2c8a3c8e3e0208c8b8bc46917178d209-39PK?aNwW* 6b807e707a974a5defbaaf18f35214da7410d7ef-5PK?NpeNc#( 6ba4f500236c078e1bda05dd012172d053d7f83dPK?tfN"B-* = 6bb82524fcbe987b547957e76081dc33570e14a8-1PK?JbeNq+( 6bb9b60236a5d21db90e56e9258d6cb94f0788f5PK?  FeNs]* !6bbeef0d7171ed46ee5a096c8d933c4570fb24ac-3PK?gN-( _!6bc25e99337a035b8f706faabf4968bbead47fd8PK?LgNP7+ !6bd277a4faceefc12df611b5b8a2bcf818ad6c92-16PK? pgN+- + "6bd3552dc7e0a0ed440fd629af9fa1e1dbb88a38-38PK?#gN#E`)+ m"6c219159966bc2b3684e4db0ef93285454e0e1b4-12PK?3)gNl1* "6c251f56e62353c53ce4038f1f7a5937a5148618-2PK?fN/@* *#6c2d2b21a756f84e3f7d11448e1b3d84a30853bd-9PK?ʬfNCmm5* #6cabcacb6054d1bc20a8289ac6160b0a6adeb8a7-3PK?aNm + #6cc526fdbf08a08efbb92ff0b832f0c2c4fede9e-17PK? ]aN+ :$6ccc9e9c6499a1d0bfcbbdaedcb06d81b400ed63-28PK?fNhB.5( $6cd1406c508518260ef1424d31b91c578a9dd28cPK?  dN f + $6ceda5e980736875537aa6a1d42725bb4a924f28-27PK?")bNN@4+ M%6d0c869ba88460a24cbbcdc684c3fdbc2989f8dc-37PK?MEeN$[+ %6d2297affcc0ab6d04175fdf80a051eb1ecef3ae-22PK?3igN$[* &6d2297affcc0ab6d04175fdf80a051eb1ecef3ae-5PK?AeNߐI2* W&6d27a1d0c615660ed6dcbc435bd42da0df2f45b0-1PK? aNwa+ &6d306c1d8a323696367c76359c469f1deab535b0-23PK?4aN_M$* '6d5a02ac1510cec5c27d6daaf960f91399f47b18-4PK?FdNI.L!* d'6d8144d9ed5fd5bab7ada3f8b44438a27da17a9f-6PK? {KdNk I + '6daff0f6d263d74a587fac5af7a0595d90c09064-21PK?e[cNeX+ (6dd855b97641e8a3d5eb52723a3aadf8350028ad-26PK? -bNTC+ q(6dfab8e80dadbcfa6c86d3b8189c0a8fb28275d1-26PK? ŝaNË * (6e08d2604b4b82fc3c931bf176e5f290314cc0fa-6PK?ncN0ɏ + )6e119e55456c68f3f746881699d139bfd88ad8f1-39PK? :eN`{* v)6e290d6ac3f477182fb8a18a358deb2c2c93cece-4PK?gN7* )6e33ec7ff8cdbccfa9deba58d162e740458658c1-9PK?#fNm0`%* (*6e44ffa93a7b2cbb5597c84efaed9423c9464674-5PK? EeNGl-* *6e5513f1022a1dc0dd1ef6464f3d14ff83046737-5PK?*%gN݌K_V( *6e5e62ab2c1bea9228ba07621d3bf46b629b2b1cPK?bN:^l+ C+6e7bd5f02184654049f78a29efbc4f8f46298f07-29PK?Z3eN!+ +6ed77d57d790e9ba2c2c583938324b8015416011-11PK? aND l + +6ee3741897c93a3859fa8c66d0a1fb5f64e22062-15PK? aN* N,6eedd0450c074b37423ea0170326b4e2600b648f-9PK?.UeNt^ڏ=( ,6f07568cf8e9fea1fc31d62a30d171eb8cb6105fPK?BgN/;7-+ -6f1c4fe5a63dbc51f8f7baec0da77059e88260eb-16PK?  aN+ m-6f20b550aee382baa3eea1180d3f9df40d0ec9ad-27PK?FcN17+ -6f2db50da4269b560aa7374536e49b99c8231ea8-37PK? bN + ).6fadcc5f939be3600eb0d0f97ad01973702e1f6f-22PK?XYcN'+ .6fbc5177d8c45e99c52a32c25e548b9592728e8f-25PK?CeNqL?++ .6fbc5ae3bcc9e3955e908f1c11c57a8dc94f316d-30PK?KcNH+ C/6fce5fe5eefc689845e13b9773487b03c4f22892-31PK? bNT + /70088e5e0caa70c7de649708a838476e9e5d172e-21PK?aNi+ /7010a5052f75059bb44ec8623c12d9093d882ef9-10PK?bNn|1%+ M0702bbbfb36b3018215f4c99784a04ac04e2f4ac4-41PK?աaNgB+ 07042b0f6168816367940690b445094e1159b6b51-16PK?XgN}G?( 1704ced899f9ca42e32a1058a3f29d34ba64fc76dPK?S_eN;鸟+ p1705878c40d6ecfee82bbd4514a2eb233cc55a598-19PK?(TgN* 1705f339a3291664ab8a92f264b6f031297931c10-1PK? 1aN-!+ ,27069b3dba509bd4d80021bc231e85ade21a6f41f-18PK?aNn/&+ 2706c15b129f9fb64e9e68b58fe90a9ce94123b5d-15PK? fNɇ* 2707344fc85f5944fd27d675113804672bcbef4a3-1PK?ڂfNh * 637087c7fd1f6ffeff7a5b933fb349a40da580464a-2PK?pfNZ+ 3709c99f2f9327e5659254e7b572bbcc76c25271b-17PK?BbN&+ 370a8ded4b108513a8b1dc7c9af13fa4acc2a815e-32PK? KgNRm+ H470d4f94e7cd9f51a30f900b79e03ed435ac06191-11PK?GeN!+ 470d5c1e7ba765fa52a9b1b212e0197b06bcaa64b-21PK? IdNk( 470df04ee42a082c249f6ca07e29288fd03e5d494PK? aN + R570e8a025c42e9a0343b3ed00753994852f4aa9f9-10PK?cN]z#+ 570fcf2300a3c67c80679cb63d48e8e5ef98672df-37PK?9bN;Ÿx)+ 670ffc42357cd566447bc42575133f5bb53f39ed4-34PK? PJdNo + e671041fbd7039de63d5be997947c9187ca189c700-50PK?zaN[e i+ 67119e6689c87083a81f9c02552d46cff042e5412-21PK?bN= s+ 771232d77edf8a2f57f4edcf2429a47716d9bd307-31PK?ҖaN%d%* n7712a71da17f7a89af258f5e623a13131643953e2-5PK?rgN|=* 7713c4f3671238a084f70258293a38a7d4460ac9e-2PK?BddN $;( .8713c80d846d8463eedf59fdde600e632545038e3PK? zfgNmR * 8713d803d46eed50c3ba1030f010fbd63033e2a2c-1PK?jgNSo* 97169ebaa30791c83a765780c890ce8712dcb6842-1PK?aNA(~+ ^97176c1339ddd7da8f647d5b7c1adb24a6454d1ea-16PK?UdN X+ 9717cf053bb349d41d457ff84783acb44d2d23596-19PK? aN * :71a55b71348e64c9badf6f6af3f78114f7b669a9-7PK? &aNV!%* h:71af31391c423ea7aa62e516410776b1ecdcc0d8-1PK?!eN|A1* :71f29a8c44f00a8ae87edc937b8447d6bda1b661-4PK? 6bNU\+ !;71f49e7db18c8ac45fe1dfcd3de39fa0af1bbc3c-24PK? aNQ҆ + {;7209a7df5b20689afdaba7467434bd27272a4c17-16PK?dNpeH+ ;7209abd9212dab43259531d494d2a1e295009ca6-22PK? ԴaN-Vs+ 4<7209f2a46fc2f10bcf6e740dc75c34aec8985bc5-28PK?KKdN~+ <720d5699b84684102a8f50835f9f877d6c4e941e-31PK? eN?!* <722de1c9d9758afa41536654fde28ff17cfa718a-4PK?LueN\/'+ F=724bf9440d0eac792c394b2363319d4c645c78de-15PK?p2gN n-+ =725268ca288af84bf1186c40f45c582a8cbc6c23-32PK?}bN+ =725c16b341b127387eb45bc93716d2f9929bee10-42PK?MfN>i0+ Y>7266c996cd5ccabdc8a7b0acc3c3198e4af97ab0-28PK?VfNR'-( >7297718ff85031ebed9922ff94430d859950d34bPK?uKdNWʷ+ ?72b284ca30ee885b247e5f5ddb3237a33e0379b2-17PK?daNP\/* k?72bd5c2879a191722450f453fb9eb9ef3aaa8504-7PK? aN/b\* ?72e790f39d8968020258490d745b232828700177-3PK?!YgN㝇* @72eca6ed4bc33398d9e182e5892a97309306f583-5PK? )aNm* A72f45a0f45b7dbf07e2587b1835000cfa927ea4f-1PK? aN7 ( ZA7308925fa5dc3d74c5c202de9af56900944d6a63PK?gN8XMGx* A73104b75c6756f805d2eee6b56efb27b75a73111-7PK? eN'99( + H74aaff1c2cfddecd42b101b324f63b7ad27023b0-14PK?{MgNP?)* +I74b5234a0ed1e547297eb599630eb2f4c8951977-2PK? OJdNc + I74c7b62bfe09df2f31b13532df3a2a2ac6249cab-20PK?XeN "+ I74f6991c0755b775667ed3fc11883dc95c0b7db6-24PK?gNͥ6;* >J75049c680dc4375282650dd13c342e1763e7c636-4PK?lgN* J7516f2619f6bf40695f09051ed1f6906e2b443b2-8PK? aN,z + J7528d32fbeb3d26b27cf780541aa28c85cd57ca1-15PK?ӡaN-+ IK7530a135b4f563c1565d62e5d0a5d322050259d8-19PK?NaN8* K753722b67210b5d07dc6b789352837be6058892c-8PK? fNd3&* L753b3ac48bab7b1e934b6b1f71d2d2bd1e614c75-5PK? JdNn+ ]L753f385fb5052ed78f84ee0b01e3b7bf4b5f0074-20PK? fN?0* L75436d6aea6f024d0d67caac9a3d8bc2dca331f3-4PK?aNq1T+ M754a6907f0ff6d0face85d2f85a682e0a4e6ff02-19PK?bN+ hM755cb64583b657a4e8b3f52fe61f5568fb03c3ba-27PK? KdNck+ M755d3f20d60c5d1a4da81ca18332ee4b76118ce5-14PK?NaN#84 F+ N757284c4ae63b4e7a2b5db981398b0153b348f4f-12PK?8eN֞/+ N75cf997698c34f85871550d6c421e9854d4962f6-14PK?qbNK+ N75d995f833ff65375c04f1ac87c6cb4382f7af3c-38PK? qlgN["* >O75e50d77eea8f4a270ebeadc04956826c67f7037-9PK? LaN <f+ O75f224fb34c5501c25f1ac9c8d0bd529c2245a23-18PK?YdfN/r3* O75f87357bccc902088b1e96c66180030912aa9ed-3PK?aN;* TP761a133ac7b3bc486b37c44f08cf81b593d4309c-2PK?cN7M+ P761d67153e831943476f6443f136384ce38c464c-42PK?xeN* Q762ac96bbf77df9d24fc7c3437eab3e0dac7ad3e-4PK? aN P%+ fQ7644052e2afeaa2b1ea13e7e184a75e5c89fcfc6-15PK? bN~) + Q764c1d526ba94822ab385a242f56e5bbfe4c593b-20PK?V_fN$E+ R7650e8d02acb4bc3a361f923c4dd2bf27dc5848f-25PK? KdNh_ + uR768c25bfd3002c47f8eab59397e38971d372af61-30PK?NgN6|A* R769b144141cb33a79c6117e5de0b968d2579b129-3PK?eNݒ.y( -S76c1c297864b7d69c064af86024ff19a1d39834cPK?aNB@ * S76d68261ab5911868761e293c6eedca52c02daae-1PK?YaN/+ S76d745310f377562291b7bea7d87d5d4738c21a5-29PK?eN+ NT76fd052881d7048f358cc53b2b485f5f5a21f6ba-34PK? {bN% + T770e9ab470d840900cc3c4cdd65cd2eac9b42dfc-37PK?+eNﶼ,9?+ U771046debf482c941d4c67afbc0420fac70fd5fa-23PK? WgNꅿ+x( U773b92f75a62bcaebb9867b51fecf9fde7a743fePK?KeNM%* U773f3040afffbd009e6a5afa9c37a2251c1e98b8-6PK?2fNz&* NV7763722e6203ca6eef7d617d15a46599df153a9e-5PK?dN3(+ V778d0df3331560f1b3f035895d07c98cdf579af8-12PK?%)bN(+ W7799b6b7596250bf185f028be4836f65286bccd2-29PK? JdN[M + hW77a2c21270ad6dca849782ad9b23f18d592d9a55-20PK?fN-ʂR1* W77c00214b6c080bc57a142675a92cd3b1450bfd7-6PK?&7bN+ X77d8dec84c82c7bf028e855c0483fa5da976297f-32PK?"gN + rX7808cae9ec0fcc9ceea9a2534dd50144f04964e5-17PK?fNaS/* X781a867a394e60a235c7d07e3fa101555035dde7-8PK? PJdN= + %Y783f655b22bb7536db032ffc60beeb11a1ee4fda-29PK?bNe+ {Y78542cea782f1002bf73b3948d5623335b7bbd86-36PK?rjgNE "* Y785b9526ea824c4470d4c74c9a238cc960d669a6-6PK? eN9@+ ?Z78688f26d9eaf9ade286745a337bd7560bd10a0e-25PK? KdNd,+ Z787eeccaf62f0d072884bca993b052a902e9a13f-22PK?kgN}"* Z7880f1ba90d2cee9f272035f3102b66aaf8b1960-7PK?elbN'4+ N[78b0af321b7c13cdc3781485f09c4cb3ad891772-37PK?'qfNUd!+ [78c3e37d35f4a79d601d09fdda1e353403938f83-22PK?'aN* \78c7ec558c0084714e2d6b0eb1df11e0bb199977-8PK?ǕaNX)* a\78dccc59c1b2b9eb5ab5037fa38d89b9b5caf89d-4PK? rfN ( \78e751266dc2f052bc26b25262a50721f2c1c218PK?eNZ+ ]78ec55f86b99bae50f9880ea0ba8fef11be03fe1-27PK?aNg!+ n]78ef57bfc543bf048cc0d9f885bc17418412efac-19PK?PfN** ]78ff45e8fcfc03f3ca1857eb87e6a83e6f213304-9PK?P)eN^(+ #^794278c960ba2d57ddb29202b796c0f39302a20d-23PK? aNk*( ^795ce3991b31bd0d37b937868e94f4c53147e2e7PK?[aNL\,+ ^79b6b4032596fb1869eb76365f07d4dd1582c406-20PK?KdNxBK+ 4_79c0a9e2c3fcca37d1dc9d7756b80de59ec78eb4-20PK? ƄfNF * _79c17aff952a6a7cac73220b0de9c64a0176ba8d-5PK?ǙaN8k* _79c4cad832c28fc42f8c69551c87a828ba1162f7-6PK?ZaN~B+ H`79f4073fbc43a242ab21a4337f2b653e7e5f577a-16PK?eNz* `79fbc2d661f2b657393ee9a6abad5ea494307803-2PK?qeNoG* a7a1c89768a4dddd6126b4ab501f209bbb605ad56-2PK? aNSV& * ia7a30daae201b600cfd986b830e36ef64aec5b20c-1PK?2gN,)$( a7a3b1408c7e42d0c972f503cdc94e6dacbfda8f4PK?nfN%$* &b7a3d56c9e63e836451e84b68defc02bb1fbe5a2f-1PK? gngN˷* b7a458a04a9e83e5a80c2bb1420a36e4df42677c4-9PK?FZdN@]+ b7a4691de8b8457712e54ab34883a9ead5918886e-10PK? &aNLA* 6c7a64e55e5aa11e1fc39a712ffe141b7d09b2724f-4PK?fN_* c7a665cbd2e8c116078d69eae050504cd2b45a005-8PK?0bN + c7a8a7b148631627c997f613a501442d9caf2a4f3-28PK?dN1+ Cd7a8da460c6e4285a29bc7af356f30fb77c645202-19PK?eN(#+ d7a95356e8542eae8fef18ba719da887f983641f8-28PK? paN~H * e7a9dba67ce927eb15678a72c1916a6099f7d382e-3PK? YaNT + Ze7aa99dfd14feebc4243751c2eb4ba61b2a78a4a8-12PK?ʜaN+ e7aaab2915676a5d8926073e01d4720ff4bb4d5d7-14PK? JdNq + f7aacf05247fafaab2df49e5b6ab73ceff19b4ac0-31PK?JcN+ ]f7ad9d3671f19ee3da77e8cfc2c9696cd584d9e63-39PK?jaNi'+ f7adbb6495f21d9bf634fc7c0fa1142aba3d139c4-19PK?aNV* g7adc5817ec77a9cdcc40ac712250bd12d159857b-9PK? NfNm> * tg7ae33df5284d2703271f510fde03061fdd49244c-7PK?n)eNt6U$++ g7b17732a3ea6d87fb52935bcd55f3162b92268f1-22PK?A-cN'w1+ $h7b27c0f12da6fe20162acaeb589febc1b768a6b0-30PK?ɽfN/޼<* h7b508c7b138c9a0c746465ff58c64370491b9f80-6PK?%fN/* h7b5c9e83c4809916d5a7f45c852206d2364ce45b-2PK? fNё* \i7b77db1fadb4445386dd7728b6d0182c2d0e3d77-1PK?}bNl2+ i7b8ba2d99ce0df3bd7f6f42dfd0f9ef6ee430cb0-30PK?veNEss* j7b9ad2ce1c58ef7af26b5daef791fc1995816444-3PK?CeNO~* pj7bac6d7e9084e661a6fc04df42a920a69a297ff7-2PK?5IdN%+ j7bb0faba272900fdaecb999b39f779680ff21387-17PK?aN}Y3+ ,k7bbe76f83bb650235ab79e66e57d04244993a2dd-11PK? .bNg + k7beb2b9f5b8635f61c9ab9b74c6b337c185c4a77-26PK? fNU* k7beff40b463075b91323ffa6520df1742209b379-8PK?aNǺ$=* Cl7bfc067edadafdaed89c1d87a7fd176c7cecfcd1-9PK?JdN+ l7c086c2b614fd463b5c9097554f1ca77623b4343-17PK?KdN TX* l7c101881c31e6e96c9cb944b665f6bea3973077c-1PK?eNΛ+ [m7c67a3ad86621b1d9e0d1d2dc920f180ebeb1395-21PK? AfN + m7c71a5cf20828f69c67e6222ac9b875f4d944f2f-36PK? :aN9Pb * n7c739ecb967bb6bbec45597037f9a8f20664111e-4PK?vaNac+ ]n7c77fd6dee1477d0bc61ef6b6721a47aa4760d9b-15PK?fNyX1* n7c89afbc0d9cb2df394f89ffb3074ee0ee7d5702-9PK?XeN0.w( o7cd39c69745c567341b7f2e04c66c4ef2ace72d0PK?$bN'+ o7cec684cbf70870196c720bc9e0c969595f0bfd3-33PK? aN,A* o7d0043b65c0a87bc3930d0985047dbe456a14010-9PK?fN@* >p7d3d9c6906d455be77546c227f6e82359d01dbd5-5PK? dNI + p7d3f18a64e25defac1f0b4bb365b564929162ca6-27PK?&bNhfe+ p7d46814bd75ba4f226911e74143577ee1e85da80-36PK?eN/!+ Nq7d47525f47b49c13203bf1f4e5273deca3c8d327-25PK?kgN!* q7d4b4b9c97e7a64c7b084d2bcad9ac757bf20da5-2PK?PgNw( r7d51cb509503ec2b237fd861bf97489b6a61d030PK?fN6/9(+ ar7d78cb1ffc6d35132d18859bf74981278172c15b-11PK? eNC * r7da2d48eb0e941708036cbb6221ac5b75a366b2e-1PK?aN2n+ s7dbd197db6470f7f981678cd9d520e5cc8e2fc83-13PK?EdN*5+ ts7dd05ca3dc8ca213cf6ff5a76380a660719af9f0-16PK? bN,O+ s7e0fdf9c56b1280f45718f9f266376538e3ba62b-23PK?aNyE%+ *t7e31c1b1b1d2c13bd7d798a2a7323ae0040a7618-17PK?dNNo+ t7e31d659b942b42bc54c2c97de49e79a76db56aa-12PK?ifN``!+ t7e5617211f5dba6b4ab04122b59f88dde4492022-29PK?dNr]!+ Du7e6911fa3d3b7043acca80ce2601b5fd34bb9bf7-21PK?8gNN6!( u7e6f4c11c012aa651e766e461b2b4d4ca19f963aPK?KdN^!vC+ u7e8f8ed4ecd494a8e5f291c7df19353ab71a693c-43PK?XbNԳ?+ \v7e91dd38ad66fa7fffcfcdd8392fd3f8cc7ba512-35PK?1bN_ %+ v7e956187d4b1e5f7d01d64c87eb5dfaa65868561-23PK? aNz + w7eb084807b23ee7ac78d17899af537e1b3e60367-12PK? WaN!h * qw7edde21836dcfc9a0d3e0a27addc0e118a72f40e-7PK? NbN  + w7ee838262348f08d0558228346dc812cdfa5d737-22PK?ΪfN*+ x7efbe514c8a0e15cf0f32d38400ef86e65771e44-17PK?:3cNWKGC+ rx7f185eae45ec6a561eeb3fd8312621f6a9d40a4a-29PK?ѢfNg* x7f38fde1d97662cd7be60a9a155675136d28ec92-4PK?9bNoݻ!+ *y7f42af99208c1085538160b052dcc6d43d2110b1-29PK?58eNg?%* y7f5039e5d90f8fe48c6b3116f4a1a6ffad656902-8PK? JdNe * y7f662020b5d30f40a53f64f85e8d1e40516c676a-2PK?xeNp%* 6z7f74eab8d97d281b9407fba2081d6c38857eb93a-1PK?gN ]Ϋ6( z7f7e02c5a6c7ecd896d99738cb355074afffea66PK? aN&7 * {7f7e6d430c7b4832d283be48564112e352ebad69-1PK? dgNGư * c{7f8231920aec3f5643f8783a21a5412666519222-3PK? ӚaN/l( {7fa269db0b57f314a850852daebd8906c27aa759PK?fN~9 * |7fc359225972b5ebd72dc39ceb6cfad372262753-1PK? kdNGJ8 * `|7fc90586d16c5145dde689916eb64b32b1fd8c6a-9PK?]eNu$( |7fd2002cfe2949c11b15eb0678ef2d663ae528b0PK?řaNX* }7fd545bcdb7e982caa73169e85a1e509759464aa-9PK?ϛaN+ d}7fe274ea394d30ef73d7b7fc697232404b510985-13PK?LgNkec* }80107f5fe3d99428e9fe91d6ab58167f5a2ebc2f-1PK? cNn,r;1+ ~801311eb506c8ed05ef8c0d4bb4c10565ee142b8-38PK?u?bNU+ |~801ef9b341fd2e245df00b5a2ef31b32c18ea710-36PK?cN}A+ ~80466c04188aae5e091d35b37ef459aa585d4a9b-34PK?d+gNZw* ;804b86430fba6ed56edca0a3572bdc5cd2449b5b-8PK?lgNT* 80513d23465060a7f6548db3ead56eb1d378c3a0-9PK? aN+ 805d27efe284ed047b83f7db8032566e228a3c0c-19PK?jdNZhw)+ E805f5fe58ae2da07a5f374eed38b45ad61bb4096-32PK?bN?c1+ 80616dad0c9617cb66bcbeb1efaef290c667f8ce-24PK?ĞaN)h+ 807aa427e99e0dd88926d0720fd1db948fe3fd5d-15PK? }fNhU+ a807febe13afed872fe3687ae5810f8a5fa8dff05-10PK?7KdNƥ9* [81494fc4b8ee60780c5e8afabcbf6c43dbfb0055-2PK?ndN_z#+ 814d50273d89a60921b14418e8a6ee52cc6e460f-19PK?yleN!* 81610d4684dcd08530db2dc07ea4e37642423440-9PK?eNZj+ i81bc05d2f3e832631a40b6eee163077827dc2957-28PK?6eN>o)A+ ņ81ebbcfd8acb24021c1fc7992e2343d3175033e0-36PK?L/bN \&2+ *81ed6b096307a63b4a837b57493600028cd10792-36PK? !+ I8704e15d3f69f4d117415a87c8a2bc936244ce83-18PK? dNz* 87077747f6c0fb0aac69f884a94c2015d4dbf090-4PK?bNCSr++ 8709a9753badf42f012e6e8aadcbe0a881283f42-39PK? BbN + a870a1889cd979b1f4485f9e4d7172927a8e381ec-40PK?QfN(=+ 8710578511d9a2b104d8d4cd5ed686c9a7b04d68-32PK?J-bN%+ A872c72247ddf699988183d35462573975e5b660a-31PK?JneNPj-( 872cc69765b7e3a16a1f75c07ebed8005c5bf400PK? fNvS+ 8747def6cf063087e1f630f9e5e6135e3de0734b-10PK? dN+ T874bceedce5609203db0067d69059cdcb5b45b53-20PK? aNB * 875eeb58847d8266c3cb3699b52f7cbc2bbb8060-5PK?aNVn+ 87692b2f870d570cbd49aa4a14fb7b97fc84d3b2-20PK? laNLw& + \87710ce3e6d951807cff7cbceaa92c3a4fec636c-19PK?&bN+ 879e496773ea19a9c1ff16a49fd1ab95c1aec2bb-35PK?`kgN~* 87aee811c2618d915d99f830d297cd0c4ec3560b-7PK?bN5m%+ c87b432e3e9bb94bb2f0a52f170235d7f0dfd78a1-29PK?aN9* ¢87b968b75435dd1a5d7273c701e765e3ddcc8d50-6PK? 1eN+ 87be9278a68d20335661ec8a1808d76a84b4e55d-16PK? cN>L + w87c94ec52fa96277e96df9edbc5e16ea7120897b-16PK?8bNɹ+ ͣ87d909e5838ac8be60ff28471b5facbc66ebb73f-29PK?ieN,* )87f45389c8e7f072cbe2dabd2f7a983a91919fe8-7PK? JdN@+ 88020be1b031b3d8e90133310ff96881ce4a62b0-31PK? jaNPw* 8818f4f29e87c4df92fc34118c28bda254e3e078-8PK?(gN0O( 6882336a067173cf9f6e13199d6420e6ff37393dbPK? UbgN(7 * 8874b9ae325fae070a322212b2294de61fffe5d0-5PK? gN* 887e7b1f425524f62369938aacaa8d6ced477194-1PK? aN3 * I888470f64468d6224acdf528b833bcdd5aeac147-5PK? YpgNEO+ 88a624f6617861e15821c3424056760b7f2d967d-13PK?mgNP?c* 88a742a3b3901620176c48c89d86698500831b1b-2PK?%gN0* {88c79082471fe2512fc96dc614543cd8089cedd5-3PK?dNua+ ҧ88cafa066ac5fe4442c28d79f114064234607fe8-32PK?bN s#(+ 088d204441f43133d21d58c9ddcc478f6c5292618-36PK?aNM* 891352f756695704f5a3f9450bc19ca6b562dff1-9PK?aN0* 8915fec8b421d8375e9cfd3c9b1d34ffda13edd7-7PK?ѪdN.+ A8929502aec3e3167a70ff4a80237e668d65aafa4-18PK?dNW+ 892ddabda03dd110883d7852cbd68786f26f6312-22PK?aNE+ 893dd6baede02e6d05be32d3a33410ca8f3ba0c3-13PK?bdN)+ a8952c0cf92ba21a5f9051bc32da6dfeda742014b-43PK?[fN m* ê896eb2a063370cf58f58eade68a1627c931042e3-7PK?%CeNXɳ;* 897d345ef24b831e955bcddd445d8b39c5861cc5-2PK?.bNSWB-+ ~899da24a1afc174c30fe6fc2de6648b99a6ff450-32PK?aN 0+ 89b015e83598cdf0ad990a0b909e134a549f4e4f-20PK?aN2 %+ @8a0c93e44e7ab83a71e5246d5a170b8f361c27f0-13PK? aN iE + 8a208d0429705fe7c029c7584c56f69d74d7514f-28PK?bNR=\'+ 8a2492a4fd11a05a70e8bdbee7721e898c9fea9c-31PK?+ifN$(+ Q8a272332ab59a4c28ba46979a5b5808d4ec49f9e-38PK? gNH+Q* 8a420c88414c6a0dead440ea49a14cee4a758486-1PK?bN(i+ H8a43e53da8daf7aeea4319c5bea65d2ebf720f1f-30PK?qbND0+ 8a58c106a9816960a6c2dd10edea47cff8662f34-31PK? ageN9 Q>* 8a9ef8e8bf8218ebc9bc64d932ff8830d8b7d5a8-1PK?@bN\+ _8ace78478d2e789e70c61ab5b0b0bf20552ca820-37PK?aNN+ 8ade284edd86955d6400ac2fee0ce853e4e5fd49-26PK?aN |@+ 8b0e4f2c7f9206c43f7226ba35dfd189d4f77f1a-17PK?SaNO]^* s8b118eaa9ce18191e11d76c389e339889b2227f5-6PK?:fN!+ ˰8b212040712a41727239cea4bdca190e0a7da3bf-36PK? aNiZ + *8b46a74f6625379b0aa6fabdc614efb8fe96f698-12PK? dN~l+ 8b7b1a93abf2f1edeeb700ab07a09a810cc3af1f-28PK? RaN?# * ر8b900f7c65a32ec8053d5b9056bfe3a48a217c73-4PK?OcN!( *8bad7816b991492b3e8452207887766de3db508cPK?dNʏ+ 8bad9beca328900f65761e22540b92541b7e64ec-21PK?dNِ * 8bba9d131a05cfa9f3f0418b7e1648fa013740c9-2PK?$geN,++ ?8bbad9a6d3abbe6f5eeaf406249a3dcfdcc3216d-26PK? TgN@-=* 8bd56b3f5c678505417ae89760dc50d4fc9356a6-3PK? aNx+ 8c058b058da4b90e9c261a773eec684e3ff846d9-12PK?bNH<+ S8c1726017a5e4f2fa95a7fde463af65a085cfb14-21PK?#bN1y+ 8c1aab345830fad18d570d30b5435b842adfdef9-29PK?QfNe&%r* 8c372c9e804929603ab98b7ef40e8379130ea89a-2PK?ؔaN#( t8c376c0497502baf1109e70b6a8c62eedca5063ePK?pYeNX.( ʵ8c55ad88ee80a837cfaa99098ee9db9b04a93cefPK? XdNgzX* '8c641a85f117cda698234124c2ab170ed31aabaa-8PK?7aNMB* 8ca41bf6f55b45d176a9140cc22e0746b3e5a8ab-9PK? gNMǂM* ۶8ca82c1c8c35eb8d5f44c8119b1008619cd212e3-6PK?yaN+ >8cafb870c129497a8ad6ddf315f64d77c8c0adef-24PK?HgNs"* 8cd10e9efc35ad1d66151cb52c2af430fa499254-3PK?HbNf+ 8cfecf30d560e7b0b267b7da457af5dcaa6c52c8-23PK?aN#* K8d0cefcb2ea748042ff7aef30f6d541565893447-4PK? dN֐m#+ 8d1a5abed22d7dde2682be65d9a1d82d23d81eb1-25PK?cNb)7+ 8d23968390660ca55a5085054622d974327bced2-35PK?SgNjs+* o8d3370048be07af2d6520dce71eca6c87f988766-2PK?fNr{* й8d3f7f35c9cf286f34bd3e5dab1246760bfececa-4PK? dNe+ -8d8374c1b5d633f7eb76ddc02cd53482885abc7b-19PK?ʅeNAb#+ 8d86ac9542f6d1b2042f41549f930ea4c44711fa-12PK?bbN#+ 8d9f6cbb479be82e23b4516277f3c71041e5daab-40PK?XfNz/+ @8dad6d20f76d4258fa6ed0ef5d73a049b527c473-12PK?f^fNv + 8db994b8689e4bf6f1d48140ec89437797cb6c12-33PK?cdNa;!+ 8dbff7ff2d644d7bf0b6a33202183dcad3d61ccd-25PK? agNًts * _8dc7de7140afeb1d30971b92081885fed451eb31-3PK?UgN|MI( 8ddfed25db16759c3d1a8d12b09bda5726c04eedPK?@cN't+ D8df2fb1899f57ebb1b9e9416226747b6a0e13d0f-34PK?cN + 8df46a67ec3098e07cf134b7026ae54fd214afbe-43PK?eN !+ 8e35b111a9f36ade36d4e6bd3e6ed3697e9eefa5-18PK? rbN{y + Y8e7fe6544b7a217045b18db3b7320023dbf5c548-31PK?eN\}-( 8ebbd59097530f37927e3e5e316754f21170d4fcPK?efNŽ9* 8ee5366e2dc491312bc81fe4656042c919bebbfe-5PK?JdNڎ+ i8eeeffd73fd023fccbb5e725bf3c5d035b211851-20PK?fNor#'* 8ef21bb4d927e9da6499b97bbf90eef709316a2a-7PK?icNxT+ 8ef413deb81dd6a0d066075ca20d03f0477627cf-33PK?JdNq Qb( q8f01b37ada47467f87ff9d957f4c12df391183d7PK? bN . + 8f0a2ce66948ae90b241a559086793f5b5349907-36PK? JdN _* n8f13a57e4f91a2944be2bb5b1177f3f34f6a087e-2PK?bN{+ 8f36a39698d69ff702ac8c3df89bf5043edd370a-35PK?jgNm* !8f37e947b37bc8be1dc0129570c47a33973e1386-6PK?2eN"m( {8f5d4b3dc7c4380fed285d841300f2b1d4c7feffPK?aNnU+ 8f6568ea0680fa35082e030277a7ac06e8f92d10-14PK?fN)l$+ D8f7c00954915b67dc11064cdef357fc26aa21db4-13PK?bN[|$+ 8f9ce036a8842abfec380655ef3ff351e018ce4c-23PK?aN,%+ 8fa7e5831cc812ccb457a3c81d69b410ba63a82b-19PK?aN+ V8fc2240ad2e1c74960474312c1ccdcc3a136a5dc-14PK?bbN1+ 8fc8a50a0640f7d09696281c4aefb57cb39d9cd4-26PK?fN8<* 8fca3d36b31bf4a50015591d2b0b28674108ce67-9PK?dND + c8fcea3de823e9f5570e9b3f21a55d4e48b07a78f-13PK?=ddNrf( 8fd937ca91d3801873941c710b84ab86a2b61a5bPK?!eNW=+ 8ffb9a45479dd6d1f9c941ede7a6d8ce1f5173ac-22PK?bNWB)+ 90004a9731a3facc7b894a45ad5ec14e24f03d69-31PK?IgNE'.* F9014ba99c5be477774bffe7074cf27749d0a876e-5PK?aN&4$+ 901a6898b25754178a1e488c03b1da9d748933e7-13PK?93gNI!* 9030eaf786f6e1498ba6d6640cf929125776217a-2PK?igNXG * ]9038300df5e2a3284953faeacc5ff66a715bcc42-5PK? MJdNn + 90562a1108ac2583457c59746c2f0f80254c9a12-13PK?£aNB?Y+ 906b91e6f01a99477d9ff158ca35a3a843848e0f-11PK?դaN~H+ g90726b4422bb7a9dd724dc8a619ff6e6edb0cd5c-14PK?YbN5F/+ 907f4f61d56793e17bc46eaee4a40598ab502077-42PK? YdNv+ 908cb2424e17b7cc32617b3c0fedad51fbfd5c99-14PK?؂fN= * s908df0ead627637d2aeeea9d51ab091bf78ed48c-2PK?aN|5+ 9093cb8401e98db5875e26fa38ad51195d8c1061-12PK?8dNS&+ (909b10d6580e0f514bc74333fbb365addbc4399f-31PK?dNZ;g-X+ 909ca1ad3158dcdd08fac0166a433aa35d74ae2d-26PK?nbN~ + 90bd7db6f600edec50c9edcd39230dc21c190004-32PK?KdN0+ U90d32dad28b93a0b8c13a58e3704d2cedbf42fcc-22PK?gNtk* 90e2f7719892ba3cf2eb92d7b0b2d5dfab1928d5-2PK?`bN'+ 90ecab4cf08563907a57a8938262960de67b6cbc-31PK? {-bN + h90eed79769fe367167d7842d2caa499f7fb0f648-26PK?ebNz)+ 9119f16ae66242a496be03756190f95b0d29a1e4-41PK?DfNLN>4J* 91335fb3d3c6c1d23b6478e58c791e94dc426d39-9PK?,aNGU* 91350f4e88d8d9d1a387b1c35a6c3ee78d367484-3PK?bNj7+ 9138265f7c0f6c574dddbbeac431842fd93fbc37-42PK?9dN`k#+ ]914e97c34b93384aff1dc89185825fdf8d142c8c-22PK?bNӵ˟+ 91721b774c4c22a01ac57b8e26fdd1207b7b4f35-24PK?FgN%%\* 9181b1535bf9e0d2fefa5d13e2e9ea741a742466-2PK?sqeNxj** i9183ecbcd21af259fb4f450f8ff47f40a54e4ab1-1PK?]gNΉ+ 919b1efaede07181e434a50a2fab5c6bcd9caeed-55PK?aNjU,+ 919e3ed1a7060790ad2d066c4847062adaa2b80a-13PK? aN" + 91a817d02a97ece03bac7742ffbabef045a84405-22PK?aN;q* 91ae816a86af526b7acc49ea320c58baf95c0427-2PK?aN>4I+ +91b5893d693575623a834fd82754d35b33bda318-19PK?mgNv+* 91c2fc5dc832adcf2ca3649bb2310081af69ad28-3PK?:bNA#+ 91ed5b70c596bb2996a1f1fda2ef75cdc0327634-33PK? fND * H91fae8d10967cac2f0952e219ce94d510cdefa76-1PK? ZbN+ 920801cc128c70fdc48871f18f55364b8b136f3d-35PK?s8fN '* 9208b703cf2ae1087751e23a012b1aad99d12b5b-7PK?aN* V92244fb9f573e57506965140a3bc6a0d78c4f112-7PK?PeNd[* 923026af0497524a7191d6b4b7d46c8bf9fba458-8PK?XgNW!+ 924599bd34dda6bb8559607f0c64b782e0e79317-22PK?sFgN//+ k925344398831e41ff59719c01835f80e649e29ec-29PK?efNA+ 926dcc9bf3573c899c01a14e1c2e2d5891375c20-10PK?8mfNW,( *926e95603ad6358c13f68bac308ec8b711768cb7PK?aN* 92769124982aa7372934ab9bee14c0f646d90fb8-6PK? ׃fN* 928d74b53d349b5a35b0b08537298fd88147a6b9-3PK? gN n"+ 6930520479f0c98f74499e8afa21d02424b9ff533-42PK?dNhh* 9317d86c3557de263825385c26fb18780c9d4140-5PK? |-bN+B^ + 934c06ea3392abc9fdb2d87e7589fec0046563f3-26PK? dN隋+ @93669d32d2c84118c2669dc4708aec81968dda52-20PK?8jfNUTv( 93776a95257f990bc01890d61c59cf0464dbead6PK? hmgN`+ 9391b00f3659e6acc5756c0618f62c9a176d5695-11PK?eNR'* I9393a6dcdaa913f1cd4b5b0345b271c50320f921-2PK?aNYm( 93a39c3c0e92cde5c6f864d0160d3975bfe7bec4PK?bN:9/+ [93a8337cee85f44a802fa0533e0b7c7054b7fb9c-39PK?JdN˻+ 93b34e6d9d77fbb0955d4f820e38a8d0529cd39c-12PK? aN-ؐ+ 93d15b2a7d9958cf13a41c37a0a1ea6bc8675545-20PK? cNz + g93e3121029a693b2b88705250041e4341b63aa50-18PK?dN d* 93fc3afa484df9fef9f308411885ef57480abe5d-9PK? gNq** 9405a2b4391a27c37803cd4529e66f6a88ba7981-4PK? magNA_ * 940bafd8319cce5924aa52a4862a55b6bd122cb7-1PK?afNϘۚ$+ 940dc97a3c9934133db5fe6ab893bf705aa18f5c-25PK? KdNۙ* :9410a3fe6c90a56c361313188668274371087368-3PK?;ZdN&|m+ 941ee8441c383e96a0a304b10fb189b26e670e81-10PK? dgN4M* 94343f13e2d763495e12947a8aae0b70dcd155ec-1PK?gN/g&W+ J9453025a30d19188e9aabef91a8cd4ef3961ff6a-42PK?CeNRh-+ 947ed86bfd1da4630a056818f73a86feab8959e9-21PK?8bNg"+ 948b8ecdb1639fb807623b625d8635e830f98762-31PK?.gN5;)* q94a0c58b239aea3fe0530c312ef2af2ad08a05ad-2PK?gN+%y1+ 94ad3d1b07e2c4bb88776e6d1cebeff7b39128ea-57PK?aNTj+ 094aeb8da2f17950cb92d818c10e6ea9cfda0f136-15PK?"fNȥY* 94b18314c3e2824d345fc64c0e6e0af6522b7ded-7PK?7"dNR^ O+ 94b68973efae8abbfb519e98c469c719f0bb944e-33PK?NaN}* Z94b818417ddfc82c23c6affd86ab38070223861d-9PK?5cN6+ 94c52402bcc3aac91a8a6ef80c984ad2500630a2-30PK?fN -* 95070a9a02a3bcf68c14a421d6af34c2fbac9826-8PK? |SdNDQ* q95114eeeb3df2c32e720207b2dd514129f49cc3f-4PK?aNE!* 954eb9adcdbd87cc487fe048027eb42424f801a7-8PK? 4dNY * +954f909d5d0534a10eb7cb32008c6d0c21311ced-1PK?BaeNY|+ 9566721833b5e6a05d1dde13ca77f16b3b6d538b-17PK?afN* 956e78e58c560c27b85d3e05c04b568a7ab64d35-7PK? cN, + 8958ea928a4aa74bcdc42a754893397a98ab28504-32PK?EgN+ 959c5b9574f185c99659b57cf5f91ca84c77d26d-35PK? ¡aN+ 959d8ac2ef9f9f62b3b98b9bfa49d66f3fc39ccc-13PK?<)dNc + >95a2c961cc3a51ec4adfc3f36980809c5f4c42d6-30PK?*dNڲK+ 95a44750e18af06e6e2e56c23ff6744f6f366439-28PK?eN6* -95b0cf1822f865f471a367b61b2262da50a264f3-5PK?dbfN%Y* 95c7c2a36d4b65a7b86c72ddf1c404ab364eb0f6-5PK?dNُcX+ 95fe82dda47a8d758af1de910370a03c36ec90a5-15PK? dN * S9610d4891a594c23b3f3e40f3fdc1628633f12de-7PK?eNC<++ 961722fbbc5903d3b05518b77c6ac45adbb9e45a-22PK?m;dNft*+ 962bd484db20dee834029880605f9af67edd9759-32PK?0bNsn$+ n9642d26dda6bdf7dc4d823a8730cdefb409ddeb2-28PK?.bgN* 965ad8067d9c860fd3551754105f7b8b0ed4cb62-2PK?;gN+ #965fa2c0cfb1596f7a98fc7a8fe3afeffac090e4-33PK?AeN=C+ z9661e0796c4e52845e2422bd81a72d643c3a9f49-25PK?UbN,,8+ 967f35e56f8d1d5131c9befd53b44dd2d034a3a6-41PK?aNa^+ ?9681ad55e3fe936dd0af1537c8fb63aba09db2e0-27PK?׹aN;+ 968e3acf2b1391fe7375a15564c65e97bd8083bc-29PK?UfN%J_+ 969eb844b085472b413c3c12c82950ce4ede2d73-11PK?gNr+Av( S96ad43d2fb6c036116209ebead13958409a81d27PK? dN@+ 96f203f9d686244b1199071e2db9d89fddb5ddf7-20PK?eN:3+ 296f291dfe208b3d5de82207b16bb373b4469bde1-22PK?`aN 4!+ 970c82d7cd7fd169c89ebccd7facf0d0003ead96-13PK?NgNDXi* 9750e10585438d45f1dd6a005a046b689bdb937c-3PK? AaN}y[ * J9763543210aaab3f75d8ce6f86b5956d0533be8d-6PK?$gN"!_( 97641c6b7ed8479209ea944295a84e6d4cb56776PK? bN/ + 978ce28e5719c85ab16caa46837c7efef02d9d2b-20PK?dcN+e59+ X979c057d7aac745a003f9a5eefcb8168f6c0b7c4-30PK?aaN:ڠ$+ 97bc018875dadeafc4b41c702dded85377f7e6d7-15PK?pfgN]k( 97e1f08cf1ed655ae75dfdce71adb14282294773PK?3`eNA;* 980280570143d36450e9f56403b70226b346fe93-8PK? nagNz Y * -98053a8d848ccb7168ec4b592f697efcefff5b9a-1PK?,fN%I+ 980859a9c4dbf83a706a61e18b5c785b28e1b9f8-16PK?eN’w* 98259529905f89b27e1d19cdd572446f408e7602-1PK? aNVq{?* ;9840763b4a2dd7f3115f56bcd386ab52bce65b83-1PK?bN6(!+ 9843549ccd8e312049a6991f38c542bd4c7aed8f-33PK?DpfN(!+ 984461f4c9290ec3dfaf4f20467bc4575c4fe0c5-36PK?fN{* R98545ebe9c95598a3657f02406e7b2a096b7b09a-9PK?dN Ͻ*+ 9854ce08d6477df6fc94b427a06f575705f4c51b-27PK? 4aN * 98613a7952891edcb919e9740ac01260a5501ec7-7PK?`aN P5+ l9876dca4083f92bdb3fe9f9327db25f2b5ab3a8b-16PK?z6gNcR?( 9886cc9370ab34e77a9cbcdcc2c59bad4c1036a9PK?sZfNI * *98ac3285911590fab30214c2e15a3817c6001b4b-2PK?aN* 98d3a50312b3c0c543d40275a96e090e5f021362-8PK?aN5Q%+ 98d8c361e3e9338b62b729bff9b32c52c64a6d3a-12PK? SaN * <990b5231088e2f548aa0c043413bade54f3e3cdc-4PK?eN}?l++ 990d4159a9d800682eab63dd427b32766ea18f17-20PK?eNTH+ 99235cde680854be26d82a6cc95dd982b6c2f3c6-15PK? qaNX * E992b8352ba96293267015a0e492a390abb897c37-3PK? fNty+ 992e82cb1e89843587c83c521314bf0736ed470a-15PK?gN2U|I2* 9939b36f1b4c291bc2b61d0861e864a10ba1327c-1PK?aN5J+ M993e3aeaa40cb88f9a4e5bf7fbe7cee175c8baf2-12PK? 1aN/@ * 997a7398cae674e817fb7e486702fadea495c867-1PK?aN Q + 99904610746651ebf3cfbae5dd638ba1b2b2bdc4-12PK?bNNq+ `99e4582f48598d430a7434b4432db5fcb72b2566-35PK?gNG>W0U* 99e911bf2cf71cce9f2d6de1a51b61ff2d9337ea-1PK?aN,-5+ 399f9ecaa4af42228e8516962cb3a321f41224761-17PK? *;bN4#1+ 9a0e19693c56f94c33889e3fe8bc6fd4c618e5e9-30PK?efN]M* 9a46453e5220d9dd6963de268d5fe450a2fc54b5-2PK? aN7Gm* S9a5fad04cbc97fa57f8a42b0e254b0faece138c0-9PK?+eNI'+ 9ab7b36b19a0c3fa94db107d67317032107a5479-20PK?ogN3m* 9ad2ee41c3530d799786fa011f66e7e6df53982b-4PK? jdN * g9adbf5b2ae95817a0cde442ce64397c273ea8b30-8PK?gN(* 9ae99897b282cdf0f1fc6c451162974148127d7a-3PK?aNAϥ+ 9aec8fb35ab9b7e11c09ff2e439ef9ec84040d03-11PK?sgN* p9b1a9f8a6775c417a75c335299d6ec535a381c8e-3PK?qeNr^0+ 9b1e7036dde5481f20d4a08ce556753043745ece-42PK?8VgN[a( .9b2e6e895384d2f12fa94762cea67fb55189573fPK?igN#q"* 9b3bf65de8bb3333a48dfdac51cc56c1b0e5d9c7-2PK?hgN#q"* 9b3bf65de8bb3333a48dfdac51cc56c1b0e5d9c7-3PK?2aNv+ V9b42d36b1677e99b114ae76cbe772a94cef48a99-21PK?qeNؕ$* 9b4719bf74c712638d3cca92d82b1e253ccbecbe-4PK? bN]jO+ 9b4d139e0c74b9bccda8af171259bf893627179b-28PK?9gNca:(* f9b6dd6724fa786df673e238c337545924901bae5-1PK?TyeNw#* 9b772a154219383f66ef12b69d32d55999e41511-5PK?1MeNrg(* 9bad4da2129f75d86d0b902e2f231ff93f3acb2a-2PK?0eN'k!+ {9bba57949e6342662d5c5fb96cbf7b5dfc73c2cf-12PK? $dNCZ+ 9bc484cb44a8a953423334e57ffeefdc1d613f57-32PK?B#gN?* 79bc8b70ff8d8a3f1188dbb92567b78ea780c89f0-1PK?aN[3+ 9bd7dda0c390e773eb1e10873e0867dd37de5a48-21PK? "cdNB{99( 9be40ee69de04552524a67f46fc1dc6816713f84PK?;eNi* }9c27e266d2acfca9a8185a1fab43e2021d44442a-9PK? [fNk * 9c2a2045753b9f5be247e12c03a9c449dd9eff92-8PK?aNx<( (9c2fb3496adde10108fd54382a0726a12e708ea8PK?cfN1* 9c31c6d395f3906ddc2746a8b6ad4f85320d9038-4PK?*dN :+ 9c3376f1106a8bf1c09f2d8373557ee74f9ba4a9-28PK?:aNԆ-+ P9c352b9bd90d810f16889991d70d7fee6ecef292-13PK? gN * 9c3e2a3890d0da0499d13ffb552054efab039134-1PK?  FeN"M* 9c42ebfa3ab60cb6d1c84328153f7a97d1daf144-3PK?VHeNX<* b9c51d485df1d4734c2c4526c3d90c7adaf027ef5-4PK?œaN 6i5* 9c523fe5b6930cf3431e05f4682c2cd02b7b95ce-2PK?*bNv+ :9c57095a9a13fd060f617037e82d5da6c816c8e0-37PK?naNwrR$+ 9c746def380a6607c2050314382a857bd8621bdd-16PK? teN\f%+ 9c860931b40f9e52efa73f9d755821617c596e6c-13PK?cNxy*+ N9c8b99ec788dcc916bc512a144895b685628f79a-40PK?}fNS<* 9c97933a98e4fa69c5e540c0272bdc45f574bcf9-3PK? VdNh* + 9caa796bbfc5ac047855df33a08c47c08dbad2ac-14PK? NdN5b + ]9cacc28365fecf86837f73028d28919e1ac956d1-17PK?aN/hh( 9cad776fef691278329d3a4a426872b6877afe39PK?bN%+ a 9cfb4717ff20ec7f322865595d38b1ac476b2dae-28PK? z-bN”+ 9d1b648709d002337aa73ffa22f7ce2f5d1252f8-26PK?eNXZI+  9d21551f756220dd82132ce4f84359eb7410eb85-18PK?bN NON+ j 9d27ea86e16dea2b8a9060c5c122617655eefb70-41PK?P)gN]+ 9d3a39afc10ceba8f8eea309243e25d6c4eddb99-18PK?g\eNg]/* ) 9d709cd5f3e0211366227733d00eb15be632556a-6PK?b_eN\!V#+ 9d7df6450ec6c4c11b4f66ec4731c62700ea0d8c-19PK?9aN2w* 9d800f166280521a0f1b3bc6f927285d04eb8ea9-4PK? xeN * ? 9d8e9dbe0326dbfa027027e2620da480875cf383-4PK?aNvU( 9db50c4a0dafc46f486118fd542f0d7050321658PK?CpeNr8* 9dba54cbad395fba36ceb219eb7cfd603a7a2d2c-1PK?baN҈xG;+ W 9dbc16457767cb6f4ba002cba1ba7e744eadbe7e-15PK?ڲdNs+ 9dddbba704268d22a49672ffd35d97de05cb4635-24PK?b!bN6+ 9de852cc94d837dcaf1316fbf2d484ab898805ec-27PK? paN{ٜT* r9df0c655c8ac8442ccfb25e6628defa6f2d1252d-2PK?eNal** 9df4ad12dda9238385fe20acb1723ca55495d548-2PK?@(eN{+ (9e0bdc7ebb851be52ea5cbb83112ed34caa78fd0-22PK?fNp,* 9e21e4757940fde1f46310e4812911946cd4e4f1-2PK?eNM2(++ 9e230d6b85f236ac3b067b0946232c0329ea8ce0-23PK?^fN},++ A9e347110478ad0666ed7ee4af9b37b2803f9a066-24PK?fN=s&{1* 9e57486e8fe8258e52fb5c0da2255020f1b2e0eb-8PK?RdNgtq* 9e6cbe83a1f1776acc495ee4299815c2aa30af85-6PK?cfN"* S9e8b51659959963a8c4c3799a3bd9b75a777b605-4PK? gNDv_a+ 9eb41322af7813f5e06d435fa6ae37d7d6cac01e-43PK?0QfN\U#V( 9eb8ab0cf36c9e1f0b6e4135fc471e18ec9862efPK?$IbNi+ 9ebf615ebf0bbbd29b005ffff4214cd6ab44a919-34PK?fNi"* 9ec362eff154e6755bd134199f6dc6fef6ea73d3-5PK?>gN.m* ;9eddaad5306803fd5d6b79f36655e0f534a274eb-2PK?fN,4( 9ef5a99a56b7a6633c899aaf68ff87973c84f0fcPK?$bŅA+ 9f064153909c9e37577cc4c4fb09f96ea43f491f-26PK?mgN* d9f16e82788d74d163f67b2874cc10c4bf40398f8-2PK?.{eNk>* D9f3c35255cb1d42e5b7559e365f047faa6bd5985-2PK?eN'+ 9f7c28d80fefc95317b52f8a5f4c3c07b9b83f67-33PK?aN + 9f86d43b8732c6da81fb09cc85e6309497964559-16PK?oieN*&* ^9f91ab0a3fd9062c3c99bbbf2dd32671c0846baf-3PK?kfN1* 9f9bfed29a119bf71a5708b4358696bdb62b3898-2PK?eNXm )* 9f9c64669375b03b34ac9572105de92f6f611576-3PK?aN* r9fa59b8d2ef82a71196a6f6a09e63aa71e26aa3c-9PK?gN8G6* 9fe962f4ad2912fa9ca85fe9343cf836e9558d8e-1PK?QbN^;+ .9ff0cbc38f4bdffd2ba1ca7dfc135c4bfa3feac6-39PK?!bNxID&+ 9ff3ea1875a80559df568e5e09a7456416a5824e-23PK? 0cNe?G+ 9ffc023f61c38b12db7bba0ff481bc59e742e768-27PK?VcN꫓+ >a0284a20ad37367e35e9d293b997c144726eac49-24PK?aNu#+ a02c358477ce7af2213a6a9c9380c4d4c0c696ac-26PK?yaNc+ a032452b6429f6789699c7b8fd7183892f2bb091-24PK? aN.>+ Ra04afe955ae84ad2778d294830c39e2a884d2882-10PK?cN;a#+ a050040dd291e5bd2ffab5caf05526a0aeb321a9-33PK?&bN6+ a065fc136b1a509a83c0aa7f644487db687b6f08-30PK?"fN{p + ca07af26b233066e4a2f87cbd1965280852413e2d-10PK?aNDW* a082f84e6ab52df281e5a94afa9620ff983b52e8-6PK?KaN++ a0a3b94ae84c1335b592a35de062a0d3a7a08a78-33PK?cN@,/3+ sa0a8389977355db9c05cb74caf0ff06270164d34-41PK?4fNG$+ a0b7e5988537f783391ee2cf5fa8cafea0a88809-10PK?kgNEJ* 2a0d9677695f507626773b7ca03b45882a0bb719b-8PK? abNG/+ a0e3b8174156e4a6de95654f1870cae7cfee8434-34PK?RcN5LT+ a0e78e046d5d92fe65eac69a7fab1c67cd5e80ac-36PK?)4gNY((* Ea0f571ee0f38337c5aafa603cbdf4457d1078a52-3PK?(gNv%* a10e6fd5d1e0abd32fb5966f07c0d05cef97186e-1PK?bNM!+ a13a65b04135198854be1c4aaabd591c4b21fbd4-41PK? qfgN0ù * Wa164b8774c1481e1192ea8b1468aefee2e372e39-1PK?aN棕++ a16abb0df56f336b64e14fd74e15af682f360c79-17PK?1eN^Z* a1703145af845b348cd508f5e1b94f93a3d637fc-4PK?YeNW++ c a1703ddef60fe4fee45b46b9c80077a8944d542b-29PK? bN>l7+ a18a7e2519dc6bc02678f978a3a438aefbd98b4d-26PK?fNX + !a1981dcdb7652cd140c4954a29528ca02f0dbf8e-12PK? уfN:* w!a1c02f583a1f3c944a33407d82c440d26923d39b-5PK?dN#1+ !a1c0805ca53929b628ecbc2dede70ee29ecb0497-22PK?;eN/ ŝ* 0"a1c457f157f4d0d744eab190d066c0b713173ecc-6PK? aNi v + "a1d03d5616cc23a6c7a92af2fa65de7eb6254765-11PK?gNG7K&* "a1ea013e29757f9f44cafe8e14b9d84f8420fce3-4PK?aN,dv + Q#a1ee62bb5d1a76f1b9b9244be3ce73e98388777d-34PK? agNӕZ * #a210dd793ecd268b62b94c9b143e4b884a3896a6-3PK?aN!u+ #a217505d81c8d13e86bc844d0d62f7467f107d84-13PK?թdN%+ W$a233270bf96ce5d529c7945784e2d9c13df1bd09-17PK?#3bNN[p+ $a23818a751960f6ec5f08cf5dbbd5445fea1b6d6-29PK?:gN|g2W( %a275711434a3873ed0af26da6d3eeada5b51c1afPK?aN}r* %a2c7bfdaf458a9af8c2e5c612ec7b1ee6f648dce-6PK?EcdN-%( %a2fbcd6a4f97204dba4c293c76bea1a278e8be96PK?aN+ J&a30f3c5c17e21de58279ab8e49ebc6a566335749-16PK?(fN/* &a31246263ad88869d42ca4f8a43084cb256bbbd0-6PK? dN:= * 'a32f32bb228decf6e53914460cf896ab89f2b09c-8PK?4dN>+ Y'a335ef5c1f76bc2156ab2c653291e7e7b93feaf4-30PK?ٰfN#'* 'a347e2608d7b677f3a6acf740e6bf3b3a6d56abf-4PK? aNn * @(a363932d479b9145f91e9f3f557526443f0ad775-4PK?6\dNH!+ (a37e8fe77d9e26d1d5cfcdc8c9bf29c0f4bea803-11PK?&gNm( (a38e9742aac82e88c90aed44ab72da8398886083PK?JdNݴ+ K)a3b15415bf8d444f70ea5b3103385e68ba66e2da-30PK?W)eNؚ#+ )a3b711a733952ca30f23b7dd17bd3d19df7ff081-11PK?aN`+ *a3da8875c6199d131b2b966af94beadae12b20ba-20PK?PgNQ( \*a3f01a72ff7d80ae1e06d4b514fd69921018c6f8PK?vcN-B+ *a3f32056a8505d4c48a3d9922c2f15628601c3da-36PK? eNߋ%+ +a441f88ee57c9dfc1323fa83b742793b01c3ae87-26PK? OaN5+ x+a453a69bc36c5a3edf010cdbc0c55e198d945d35-19PK?ǞaN_JpP+ +a4609c1a1f09b59c6bb7d9c1ed75244a75b10916-11PK?ҬfN`4+ (,a4783ae440ca78bb2acd92c1f6c9ff6565bc37e7-18PK?^dNri* ,a478d0d1f83dd95ffda4522fb90cf013634f0e18-9PK?OaN"b/+ ,a47c55f82d97744a6641a7f527da3dc648ecb620-14PK?:-bNB+ D-a4926b10eee58237552881025fb02ae0c073e943-35PK? aN _* -a545ea589ca1692a0b9982ee40cddbff69647871-8PK?eNN+ .a5572c2b99023467e41eed183b7322f107b533fb-21PK? GadN0U{* Z.a55ae1f4ab3d2c5c4ed67cbdceb3083931f5aa48-9PK?mcNʹ0+ .a5688f5d9ce0893519969ac06d8e7b7a13357f97-35PK?eN* /a56adec16b990176b0a82268ca47c0a544105992-2PK?SaN+ e/a583f6127c7c427d7ba76a3ce55b2998f8eedbcf-13PK?GaN;&N+ /a5a140f840be162f0cdd7acfef7ab35a556c5fc6-10PK? kaNJu* 0a5a6f97a0a3d79238efeb381965843984235c6dc-4PK? ofNXk* r0a5b34b0e40047dbc13fc1b055c218653ea5325c9-5PK? aNF=K( 0a5cf5ab52be61e435c7d5bd6249bf0f832506205PK?p'eN )+ L1a5e154ceddc197d19cc8d9f0ac9c863757f5fa4c-22PK?J%eN+ 1a60ab29bf9d401e3b16a774561c46ce4b9a927c0-16PK?gN,1* 2a60bb5a0c1667c810586b713e5244951fad6c21b-3PK?efN 3+ c2a64470668a5526ed872d29165739fd111d010d08-35PK?$ gN

eNXe)( 7a72f84f384e9a5c46062022f4cc333a5c0a3b510PK?eN.* #8a731527b5d07ba3eb61df0d429d9bfe1335e4243-3PK?YeN ,c!+ 8a7338de59564bc31c0508c92300793cb7200dcd6-10PK? $gNp&* 8a734f3fc92daece7b1f9f2d3a188cf58a3aec831-1PK?+aNTr* 79a7369b760f49f634b948328434b1ff69864fdb77-1PK?aNhȏ5+ 9a741ee112b96b0452ff00ebc20f1b230c4ddc3ec-10PK?KeN!/1* 9a758e7b49e6ecd9a6235b53544ba24333a128dd6-5PK?aNK!+ F:a758fd63f5c925c5ecccd1f52130584e5c955be2-22PK?aN`k+ :a76943a7501020a4a478d96718fcd4d508b0b6a6-12PK?  aN.~N+ :a7ac42f185ce3f627511a739ebeaf96589e2f7f0-26PK?+aNğ+ R;a7aea969538bb105f34dd53530f8b6c23efbcd1a-13PK?bNӖ9+ ;a7af5a8a39ee058dcc27d2287e604f425f76c934-25PK?aNP^$+ <a7b6d437ed432b8e9418a0993de8450b51ff1f09-15PK?0eN-1?* r<a7bdc69db699ae8fa402d59b4dc953e39ab8c3fc-2PK?:.eNa831bd2f677e66547d68c8232f4c4bf0149b3762-16PK? aN * >a8338c0603804bb7c051dff3c49ce780d50d8a71-5PK?aN!&+* >a83a7cb545d1f582835053f7743dc8927d2dcf22-1PK? gNq.aJ( c?a879655f61897a3bfbd88b00ef76ea9338326d1dPK?r dN;.+ ?a87d94ec7a0b353cc3f532caec0223915fa81cd2-30PK?"fN5%+ #@a87dac6331ecb9dd4af0c07462bee5f6600aedb0-30PK?gbN[2/+ @a87fc77c4dfd110d036bbe417a2ea45741de6195-35PK?5;gN;( @a8813f117cacddb4b6baf98c4fb0132046987b2fPK?fmeN#+ jAa8cb99b5fb29a4868e8755886a117672ecdc4ac5-10PK? AaNށ+ Aa902724f352153d41c1592c08235127e801dee77-23PK?QgNZy#* Ba90dd8462460541eeff6eb96b4d583b0745b6671-1PK? aNuE8 + |Ba93281a5cf381e21af40b306388f2d6d7c7ef13f-13PK? جaNz+ Ba935a5c00a3c811b3e5095309f12be270c49970c-24PK?{fN=]* )Ca950f6534cd1a8dd70042eba620ca7a7b5045b2c-9PK?cfN9)* Ca9586215bbbc602c551bd1687cc4b81e1b8dd964-3PK? aN * Ca964db4942f68cc1d590aa2a977fa4f808595faf-2PK?cNŁ'+ 4Da9659b5ea20f2b320733e5d69c148a07a2961fba-19PK?qeN;+ Da97a4dec0c53d90e9361a251a7e9b5fa55bf690a-13PK?PgN-z+o( Da98198eeb06ef8e3e4faa24ddf1409099a5dd5e4PK? eNo-+ TEa9a1c6bec8481290a2eb884b01c597b099d211f3-28PK? aN$( + Ea9b5c4277ca1b175a25985d3a7e66fb9c0503be4-13PK?gaNZ* Fa9be3cba8640b2aada2e6ecf3e32d526603a0e03-7PK?aN~G* ]Fa9d029baadce98b5c9ad9bd95e5cc36e973d0e50-2PK? f5gN;С+ Fa9eca224883ed0bd0575805b93961eb0fb35d3c8-13PK?6eN-S+ Ga9fc9ac21fb975153389d6dd58bc011f52e22657-10PK?NbN|l2+ lGaa21a9d8e9aede70a27a53d33d4125a071d2bfc8-38PK?9fNL* Wad8a71875e40cc8ee7086d3f144e9615f8c17b7f-5PK?. gNHJ* FXad90eb81ccf7b7910840420506c2ad9372fe192e-7PK?;(bN1+ Xadab5296a4c32818b707a9b0a08625d8060920d1-37PK?*eNݶ!+ Yadaf5816a60ddad2d85d52c0dff89e8d14d1082d-19PK? ,aN 7* bYadaffb3dd2c1d5d0e83ee825743ad274535551d9-9PK?gN&@}:+ Yadb453cc35eacbb27023fdcd0df8d624a7895338-54PK?fN_!{* Zadde5d3b006fcdc8412245ffefbf6e3fee6093e3-7PK? dN#* uZadef2c90f664973c8fdc27e8c4d7f194a4e23878-2PK?c bN:+ Zadf6177400995faa8c76a060e1a709c287159bce-22PK?fN)+ -[adfb623e192d8b19995ac757d6f6b991f58cd92d-34PK?0eNd潘+ [ae0402004273791273239c6e21654c6aee3aad89-10PK?TeN 9( [ae0bd5f161f2342b38221d4bb9b89d9de132d5f6PK?idN>( _aed71ca030e1866758060b9ae63257819d6e69c7PK?ٓfNJV+ @`aeebc77df7a0b0d0b8663ef0f8a677be72739c58-39PK?aNw.* `af0873420cf7c52468f3787436246f9125d6a756-3PK?;fN}_-+ `af15a2913e334b5fd15f121cdc58bf4bb82ae13b-37PK?fNvr1+ Naaf22d400093f323251962c35b9009fa8afc49f66-19PK?.eNo|+ aaf31f17a36e60a130770db4d1475b9a920993b5b-22PK?MaNe+ baf37d89d88817e86201893beeec855884ff3ae9f-13PK?MaN^}+ ebaf5c74c22f5eab4d14423aefae23d60c6f867063-22PK?wfNh* baf65a98dab9063bdf1867287699d72bbec832aed-2PK?-gNyѡC-* caf696a970df610283e1e54c309815617832dda40-1PK?+eN& "+ ucaf7cdbae7b55194f11f3c794cb51e874cb94960f-24PK?oeN)!* caf800d84f6475e952da6ed7ddafa747c58faf91a-2PK?paNP!+ ,daf9ed9e20d0dacbe113b9b479d6137a366640f42-19PK? 9mgNx\Z + dafa1765f3d2eae0adba0c05fa9998b30fd54737c-10PK?`bN^,+ dafbe31ae6d55857196c903e74cebbca45df0bf47-39PK? eN + gN8( eafc6d63368e48b42674bcf09a27dc6e043121cb1PK?D)gN6ϱK( eb005dadde32580035c55e8126566d2555795d187PK?jeN,Y6+ Sfb00e7de947a1ccba3ef398c99d574ab7e0fbdd7f-16PK?řaN%* fb0331a971296a09f0ab88d875a621f004637dcf6-8PK?2neN* gb05095f33e9e038d5e74ff99f1954e971cf27b2d-8PK?xeNF* ggb06451bc7574ac8662b949b300aee8406438a365-4PK?efNSr* gb0675f844139ad4f7372dacd3036ac0ef299101a-5PK? (aNss * hb070763d16f33f724eb153945d2b7ede8d0119b7-3PK?fNEŮ* ohb07cb9672345f12def19ecd9ec49326e50b88bd0-7PK? њaN'=_+ hb0851aa315b325ce64fed622f5dc2d640ea0694c-13PK? aNbl+ ib08a57f8c0adf76e76edb9cfeb5240cd6cff072b-10PK?QdNb * wib0b1b22b639f2c449e1c2dc17e5062731254fe18-3PK? aNM+ ib0efcd013d27a3c14daea4864d5be04dac71f23a-12PK?JdNUt* ,jb11a6292fcdaec8f0aa5f1284ae209956b3309b4-2PK? eeNa+ jb11ae5e6f47e8521e04ca4c2829c7bea5899b50e-13PK?ifNa%+ jb11e5a99ebd3a4ac86e821b2eef36cd0b3af023c-47PK?ZfN<s* Ckb12027a53604b09b91346325fed3803dadfc9f97-5PK? bNB+ kb1254219c3b3e8f2ab9f67dc04192b38a3d04a7d-36PK? gN* lb1295e58a6a482774df3809327fe9e50812af01d-1PK?G eN+!=#N+ clb14bc14bd71878ae9cc40714725137f5b3d108c0-29PK? OfN9)D* lb1603a0673fbab09321dea8ac5de70cd48265a76-4PK? %gNU0* (mb17cb909298b63798dcdaff761c73bc43f77542d-2PK?wI+ b6368c3b5357473f3992046cdbc78b1dbbb813b6-13PK? aNpW>+ 6b66468f23f0d85b03f38892c8a6d8ea87af4d3ff-10PK?vaNG%ϲ)+ b66476040e85da33e53fb61f4f540b49a6034d7c-11PK?+JdNJ( b6665c5ab66937a646bf6f1d4a27fef6d8d28e94PK? JaNӳr* Pb68a3650bc87c68d19b15d55ab75e8461612e399-8PK?aNޱ+ b6988125943fabd8c625bf045e821b9ef066041d-14PK? LdN}1r + b71604c8ff325412a659e612350e2abdde6879b7-17PK?0fN'K+ Wb736ce2e6e1b68cb143dae7276b2c01bd8dfdb17-32PK?DdN=-* LJb74a792d1bbab44d75fb37f64adf450efea7e4d6-4PK? mgNҚb+ #b76da8d9212ff6422d7b8d74e3ee0855acd26f3f-11PK?IeNI* b77ef2a14a3dd88a2706c987623fd41661bbad1f-4PK?[fN;!+ وb78ea575bf19207b541b95188b2b0305a9e5a987-35PK?UeN]:9+ 6b793d0e026424b59242bcbdda5d9eaab21903aa0-19PK?AdN + b7aba7ed0dcd3329033b9682f1a8b29e095ab590-23PK?ˑfNMY!A* b7c3ea8c0e45822e4d50077ce3a719e806bb7da5-7PK?aN** Sb7df6a68167b4b9826c2b2cec94db91429e5d3b0-8PK?fN*]* b7f51538a9bd9d9e7dd38e73c793eab979238ae1-4PK?geNF/* b801d0b0236bafcd43ca57f45b7c27ea095c60ac-5PK?xeND-* pb8027e8b1e6133f035625c2a7b05eaf1d25d8788-1PK?dNh++ ΋b806d5e41c7b56eac9d1430f678998260108f6cb-41PK?9bN)#+ .b80f25f0a10dfcdea6f4475eb8295535811b8e85-30PK? eND+ b821c28d17956306ad0f6321e38ea203a56528a0-20PK?ɔaN܏M4( ߌb824d3b4613ea64c12d56207dfd07ccff19ec086PK?ufN/%M( b82f20734ec99644c19d145150eee8f85aef2288PK? fNm1* b83d1b53a300d16960113b9d8ef20081541e670c-1PK?bNS3+ gb8710bd9c1df93104d252319c56c570c58a2cdef-31PK?W4bNMq+ ʎb8834a30a71a7ee18c2055e3c7b8fd7e6d0cbb56-30PK? 1dNd+ "b8b98580f35fe5b20d7fa29bc40f68200f7e9ed9-20PK? #bN(+ {b8e5a1aa24e24f374d424fd5ab3e9d203bd94af4-30PK?+EbN7s+ ӏb8ec1e5a3a0bb316ef4c35a51b9d74d88b530c5a-34PK?aNBM=+ -b9051576241c241e26dbc2749fbcb2ad681288d7-16PK? ghgN(* b90a4d7f9ae1030f740f39da6237eafdf3d0c857-3PK? fN* b9128a8abef10dcd83f6bad3df73e108d400f7c9-3PK? DdN['z* :b91be600de23ea7a9aff15813c3d48261ed93937-3PK?5eNƲ+ b941b84a5ec443cde89a5effe57eb463b64b8178-11PK? fNp;# * b9531cfbaf51ce39f495494291d7fd82f2c001db-9PK?7bN~*+ Gb985df64eed48378c1846636b24335a58b5859fb-30PK?\fN:+ b9903ba5b8c2883cf6e39959cc53a0ad2371cdcf-11PK?SeNC!+ b994630428ee8d9072e6f58cbc6d3c684cc8fa9e-21PK?\bNf֠#+ Yb999c0181280927fc5550ceeef31965b7fc891b2-25PK?; dN+ b9d2f39995f96c80ba015d0da0ddac03e1e0bc05-29PK? dN| + b9d6a07ae2ec7aa34d72d20eeddf029e4889b6d2-16PK?"`gNC.y( eb9dadd9a7478c1aefefa7a1dcef6e25c23160dcdPK?YaN3Y5* $ba11e524073ea6971e9dde763f28bf93a5d95f66-2PK?AgN W* ba2249b230ec5790335d1451eb3ba559470600a1-2PK?fNN,* @ba387a061f8920708267df557f997d536de77330-1PK?vJdNZ75( ba4fcef67b112aaa349ed063d79a68d41bce75a8PK?gN@ճp+ ba62c2c947e9765281af39d1fd33bffb749eeb02-56PK?bN^" + ba77f3ca4d6af233d01cf8df63d37342b901ba0d-36PK?aNe?Wk+ Kba84b23ab21bc9f40eeca2c53a9477b4b3de79ed-12PK?fNQ* baad8a316ff74725a684e877695c98e3d7bc9aff-7PK?,aNS* baae917c1054ed962ac2e038654e2786ae5f1c3e-8PK?[aN+ Wbab23b104423dd0efb47ab678e3090e6261e57d7-11PK?)bNf9E++ bacd0c6c42e4876af35f84fa54d5141017fec23f-32PK? tJdNuy( bada716a94368a6f7b8db1e8e52be23ed7a34fc0PK? aNf * dbae0034aad4d27946f75f982f3cb261663fa1264-3PK?bN 闉)+ bae668a712ac9946544e9f798a823bced8e6c8d3-34PK?fNae,+ baf3240b98bfd0ba0ff2486342ffe082f331fd53-16PK?bNi+ {bb03a6ebc1b9331ab3372054aba493ffae99c687-22PK?/eNY+ ՛bb247adc3d459bbade3b238df13bdb6fae1ae406-19PK? bNl+ 1bb270f64765d7bee198d219ae08bf2d2dcfe45d4-18PK?PdNdX6/+ bb2a50b09d2c247062394b4f3aae89bc69414b0f-42PK?$dN$q+ bb336543bec00e7fd449515820b35ddef99f239d-43PK? BfNvja + Gbb451578811b0dba48346d17031b9759f2574405-13PK?eN)+ bb63cdfff9262c77a7f6d4d4c8b8a58de53871a8-29PK?nfNQ+ bb8b103fcb05d87baecc48d98816b775efdb9658-35PK?)aNW * Ybba76d159082967732e53bc5a9c81b179a442787-8PK?8bN+ bbc8596518f0c10c584864f9f93dcc0694db7f02-25PK?gNǠ.G* bc08ff0dab4d19ea2b724c5d1cb35f3b967603e6-6PK?MXfN( mbc3f42508cbf7cfaa6a28de5381f676824f4d14aPK?'aN]+ ˟bc43149bec21a5bff0acce71811b307ca44d9ffd-18PK?dN؝+ (bc53399e6774f090c1e62ea7bd0e7eebe9af7d01-18PK?"cdNH Cg( bc8c1ef154a803a1b675a851c6b28e27c0fc3636PK? fN(+ 2bc9ddd5393d03096c928847739f201c6400a9141-14PK? .eNj+ bcbd3ae2a4c0a106052bd5730c36dd9d6a4a9203-11PK?;GgN~bM3e* bcc35779f3596d7d6d1abfe0d5e7e8167dba0d06-4PK?u3gNk[* Dbcdd017a3040bb68110e039ccc05af68abdaed43-2PK? cfN5 + bcf840c3b6f2903bec75d906317e042f1e90014e-30PK?:=eNOkS9+ bd1e5e5ab86e4ed711c9ff96f7743e808e5a7938-13PK?ӴdN4"+ [bd2561ff70bf07f8bd643164e721288a1315aa29-22PK? ]bN+ bd2f25032eba9ead33510f985bec9b9c0c37a028-38PK?ngNWREvv* bd444f168a75837484dc4a5ecbae35298231f439-3PK?nbN?FM+ nbd51d263b716847d972345e732beda5636e59181-38PK?KdNS+ ̥bd6496512907a87f20d27ecc9396620267bb4b9e-32PK?JPdN` &* #bd6501d3631f8ccbeb3b4b46a3065ab826b6f839-2PK? KdNN3]+ }bd6a8b02dbbeab6a0a1fef40b2ae92ce136eafea-52PK?աaN+^* ֦bd6b3592793ecf1596c4c5f8e7effd9104245581-8PK?dNn-A+ 0bd8c341695aa5d715fd416cb9bd3785908ee38ee-24PK?fNWM3+ bd92f3240da3ddd4f87c2d38dac37c48c387da46-18PK?dN@ K+ bd932662991507019b64a8f532b8ca0b912d7610-25PK? aNB + \bdae85655ba0b51f0dfc9b50204a23edb4a2fed4-14PK?ecNqGG;+ bdbc7053d037dcdb8d07a7fbc406b2772ad82757-34PK?xgN!* bdd48a4e823d39e7935d9b96535bd20f1a0f5136-5PK?fNB!* rbde90fe5cb3c4ff2c60828e232df7d4c050e20a1-8PK?tdNS.*+ ѩbdf7f76d90deeee4da3f5cfee95bd261471b100c-42PK? jaNWm + 0bdffb5a22c0f75d509bee9f1af4fedd83e0834e5-14PK? aNP> + be061a7e0831b11f1dbd40d978180b2d866ed330-11PK?p[cN@+ تbe131821fd1e6972021875c3f58e6f55ce682feb-26PK?#gNC+ 6be197e69bdb7d87df15bf1a26257c09958abfc2d-24PK? ReNoF$+ be42acbd66e8c120a5254670cf2df2cf021738be-24PK?"eNr~3+ be498d671bc261012c666a04ddba01397ce65616-24PK?PJdNAr+ Xbe4a3267abdcc0ec95a5f0028432082a9eaf6415-16PK?=bN + be4b9e8e230b86ed4762a85c7da26f984fad6260-31PK?dNw(+ be4d264c125ff928e2194fe5f5d39edd6e8add02-21PK?adNC=* lbe66dc47b77c2489aac45bb5ad6485fe1254ef7a-1PK?fNɋ%* be6c91e677d45158b271162f2c8f2bb7db637423-6PK?aN+ Pbe6f0248b614a63335b6fdbdd4e4af672cca5fa6-16PK?aN|@H+ beae1fdfffede5859162899346f1beb1196b40c2-12PK?dgNs 2J+a* 7beb12df2d08964a701cf837fcef3bf5717cba489-1PK?KdN0Ab@+ bebf21350ce74d59c602b27184c5dcb12fbd399b-20PK?aNN\+ bec2ced044de7ae43f34aa8e8cbbcc58f6e6a65c-14PK?CfN!* cbec3d175981c78c0a39e4ebd3c5af7960a4468a3-6PK?fN'* bed662aedc8e1e1dd748bde77d862772df9e820d-6PK? aN8+* bed6b7a16231cde960fd8ffffc0c78a680bda320-6PK? ,aNS@ * pbee24064fb7f52dcc86b59a102089414c10b2e70-1PK?TdN+ ıbee4c04e2134d3db17eb38e32c0e407e7ae97064-38PK?raNG+ "bef1f8a4806dd3d9b99de953f1db5a3ead661db8-31PK?ӫfNS/K* {bef935e3c12aa8381106296690415bf04e9dcc6c-8PK?fN&z#+ bf1974522cd0272cce7efd88a947f69d6f016ca1-16PK? idNQl* 7bf800950246ebb6f84a2213a7bc1d3dda91c550e-1PK?BmfNf:+ bf82e140508c0a9d7b4045ec5103fd137db143c5-23PK? Q eNP6 + bf85dd81242f6c25a791646d8b7ddb3124fd4a81-15PK?d1gN\9f.( @bf91fea19a4483e69757d30761f820e0a5932b32PK?6fNˌ "* bf9b7d9bed302d822d1f95323d1cf5b1578064f8-6PK?bNX/C+ bfa0414a0adeb2f9d236246c110e5270dca711cc-32PK?QgNJx-* abfcbf190f67c56c2e1f9a2e11f9fb92dc3b1413c-5PK?aN[+ bfe00872b61da433e9ec56f093f06f02ab959539-13PK?|eN`om+ #bfe302b5e38b7c9d6b089ea70e2e47aad501beeb-15PK?eN]M{/+ bfe38b02aa7a5c63fdc2fd899d04a130fbf00e5b-29PK? HdN~d + bfe7af43f98d1cea580f8b70b54297673ffb1849-11PK?kKeNMvFB* 4bfec2b028e32d3458bb28c1a77e60538f76b0bc3-5PK?wbNYk+ c00a2fc5926e61b45499c4817652008fa463ae14-29PK?9cN<3*+ c02a69cf58aed201c52e26611b8fc5a263f70cd0-32PK?֞aNB+ [c02e778093679ea1e9f3de49bb30767685b52aba-10PK?PYcNGy!+ øc037a74c24b35b40c9d9541ea78e8cc9a49dbeef-25PK? eN+56+ c0540f6e7940a362943f19ee5b268e65ec83fc92-24PK?zeN9* |c05bf2b4284086223737f682834fb85d3f0eba6b-6PK? bN:Q<+ ۹c0611ea88e1d5cc9378617b053ec01dc5e775666-37PK? |eN%/* Ac0a647d1c496e56fbee5ac27f24bbdaad7c6158e-7PK?]fN L* c0ad38cd6a6795bddc1938c4648cf152f0c93aa0-6PK?QaN7!+ c0af485fb9fb30c54d0eb6ad41422c1808b412da-17PK?eN۸B`9+ Zc0dc8f645f384d37478b7f921e47000fc08b6701-24PK?reNu9* c0f9def933ae78a85159086ab24d7056e8d667cf-1PK?% gN#+ c1020efcfe75c31ae32f2060f99485656dcc0d8b-16PK?RgN,+ tc145e72adafc88eac05bfe9fd65bce81e8a3d758-15PK?AgN "/( μc1736a0bad93bfcc6d03d14a440a772fea7d40f7PK?dNZt7+ *c174711c3eec30c5c836e1e15174aae25693adf8-18PK?+eN ;+ c175018c2a813dddabe3e7ab23d683a6ac6a907a-19PK? 6fNi7* c1843cc348215a2ba045314c53a30f2cc953ac60-8PK?!fNռ}+ ?c1987052a472a57dd025c01f75152ee05710106e-18PK?ךfNe+ c1b2c77b2cedd0717f3427acc1f66b12ed11f16b-11PK? GeN$^3* c203de2ce4b1eb90acee715673c98a21cead8ce5-3PK? -igNoUk * Vc2093093c8020ff8114773d97d5efd4297a93c99-4PK?1eNc* c20ffd99952a58fca598b389e599e39b83705b83-9PK?K%eN`Au3+ c22fae6afa1614847cbddcff6228f88105f028dc-24PK?gN{+ gc24c872a20d43ef0b4859609141cf62e5f8e2c89-14PK?K8gN+ c2669af961e283a25fb0a12d825c24a8e524f2a6-10PK?`/dNoȂ?+ c27a286470254f562d22b386d56e300fa68daae3-36PK?5bNы+ {c28cab27a8a0721e8f778167938394fcf15340b9-31PK? КaN+ c2a51c07eea7c029be8d2de94976f91235ce495c-13PK?aNMa8+ /c2b7fe90bf2306884f8feae8b25900b30014629f-10PK? dNi+ c2bb5a04281e39a7e0a7de75519de2928edf9c00-22PK?91cN.+ c2ccb47715c7cba7e36b1fc3902d357c24191cd6-28PK? ̔dNkw* ?c2d2c0ae0582797d48d48e131a53152ea1495db4-2PK? gNΝp( c2d7b797b8f1af10803918664cfa5b1a34f7420aPK?r)bNS]@+ c2d8ffc2d1fbedcc786a371a86d3c47cc3ac5fea-21PK? dNfZ;+ Ic2ee02dba5cc619bd704662fb4cb96dfe461551a-40PK? JdN^6ޱ* c31023586c6228a6f49cb06e647e371db3d3dc3e-2PK?aN+ c314725c656a57ce41a40a333bfbd511852fc3b3-28PK?aNG@* [c322feffce66fe61d2de0be72e14b26704bffe5c-9PK?HeN.6/+ c327cea07d65ed552200f656dbe52a2ac56202f5-29PK?icN:!+ c32bc55964e800f0802bc341860ae19c2035cc7f-21PK?;bN5+ rc3453b7a9b16b18abd314f6c67bebe20331e23e9-29PK?6cN,-* c4ace1d3f923401acd0d2abce6366454cdb84be6-7PK?fNQZ* Ec4c6c88a1cbb600582c70d182c2364d9ef0a35da-3PK?wSbNZ2#+ c4cc23c3848f004875fc12688f6255447158c860-40PK?fN,Y l** c4e848d11a7a153fbb589582e895e79110565f73-4PK?xWgNW+ Wc5091618b3c581819e1c103348fc4dbb4cfe3c7f-14PK?63cN&+ c534146c072e1dcbce4b6059acaa9d6052c2f322-29PK?DBdN ]4i+ c537173f44e811df2b876034ddd816e685f6a0c9-35PK? aNS* c55b86e38ff249a4a8c57e07ac356466d6f68698-5PK?fNp~ N + c56e65fb52c116db1099dd668a98b41dd3d0ccb1-17PK?aN;+ ?c56ff84ff03c6340828d19dc2c9170c974b8738f-10PK?fNkp{* c57a13af10f7dc0550f66048830e5ddde6c35cc2-1PK? 6eN'~[+ Pc589c5e44e517df68b3a17603a4bb0abecb1ac56-10PK? haNT * c58b1c87191a7064424d2216b7994033f908065b-7PK?hdfN1)* c59b615f75d5fb827cd31422fa1011f7bdb3f5b1-4PK?`/bNP+ \c5b18f5923c794266fd885170fa305e5536d2101-27PK?dNA#+ c5bc76c15816f658100bf812e216d45584d77d47-22PK?bNb:ʭ+ c5c982379d2e0853aae069429135279d48a0fcba-34PK?3aNu*+ jc5d60e0a15ddf43563d5744ce36b8734dae6bb75-23PK?bN&F%+ c5d7cc12a43975a6fb4abc383f30dc1d3a49577a-30PK?c`fNk$3* c5e98d72ea3a0240a0b15943a0aeabc4822543f1-5PK? 0reN!~#D* |c6394d6900aaebf058ae4a5815ac4b2b887397d6-1PK?%bN;&a+ c64bc8e346c6288327b3bfb9db00fbe9670ad5f5-34PK?lfN35* /c64c56440b724f71a50dbc6722f1b4d4f9ac97ec-7PK?ώdN'r<* c64f17d8adb118c98dcfb4d7c64044d4f49ac191-3PK?|aNp+ Hc653fb5d6957c0a27cfb0955b3c7281f9553b3d2-10PK? 9bN + c665e51467c328316266589ec948e4795cc45b13-27PK?aN m+ c66ed4227cffd258100157b5ae231ef269a40e6f-12PK?{]cNGW&+ _c67bf6cf2d25db39c886ee2c8db81a8c89a52336-27PK?fN;~++ c69d59658bab1a53a2fe19d742dd08ffb1bc4cec-11PK?CcNui+ c6e82faedb1f1a934382ab616077cd5b8a27b301-36PK?EeNiT$* yc6ff952f166436c70237a311000c94e04d8e2ad3-4PK?eN߀%+ c70fe0e4f5ff57faad402922243f2812a407054d-17PK?LpfN!+ 2c7146544999226b3a93969fee831dc40c75dbb69-18PK?`gN0>g( c7183e403c0b8ce43f13770cd746f20c21688addPK?OaNc}-+ <c74a591ab796da80f0e31faa13c8225d727eb247-17PK?'gN3E+ c755c67987dc6ddde53e4bc1ff1f495545c0e750-11PK?aNhi+ c77484b466bcaed905d819ee5e781f10bc7a469e-19PK?#bN/@8%+ Yc7788bc500a44010c83cdaf99e3738e64e9c3038-32PK?dN:z+* c78b7889ad5308eaf7aacfd274596673b62c6dd4-4PK?YeNY9+ c78e497a834651956219dc205a67df8029146ba7-19PK?[aN+ oc796eea6083d7ee4639fd5f840d434e60d9e76be-13PK? gN;oyM* c79a12458e50011904b46d8ab4b9ee9bf8fa3677-3PK?ÄfN)a* (c79a1862fc78e44d9d6ad508d37e04d07487bb40-5PK?QeNC9+ c7c663fbe99d68050103674041f08cce724b2138-15PK?aNI͕#* c7cd14c1a1af48027fa3dedfd42aa8ad19cd2c04-8PK?[eN $C+ Fc7e4e3d7eea6d605d88340c41f18f9675027bfad-33PK?eN+ c82345f4e3f312450dc017e6822e18893908fb04-19PK?nifNw'+ c8497ba4d6fcb694c5efa0b468e9d444237779c1-35PK?bN+ gc874b0330121587034481f2d2bf2e949627d5b1c-22PK?&fN* c88f27dc8f450be0f3e23b1cadd613405ac9944e-6PK?h-gNbOG* c8920e53fc2cea94c28415fb85fc15d0d613f9b3-6PK?dN;)+ {c89c562b6b3a1edd864977770fd72e4cfdaa7040-11PK?adNܑ-+ c89fcd0acb69f30eea29445198cae992555899af-43PK?{eNQB)%* 6c8b92bbbbdea34a4a1e8f3c4c3c8ad279c951293-2PK?eaN"i+ c8d3cb77b3f3f66c4fd2157c044fd6500e7e29fb-30PK?keN A* c9127e729ef63ab56a54a5353859c868de70c56c-9PK?aNq`!+ Ec916fb17e557368043c4e7fef30ef75203337b61-14PK?aN;+ c9316f78381e1b09530a46c22096047f1f0aa9ac-12PK?KdN~#`* c9468227cd10803ab30d5fe43ac59992bce5edea-4PK?+fN-v* \c96024b777eb9afe4e2303f85bbf4a3fcdbc457b-4PK?FeNu* c965fb8ee839e1da09626dc4ee41b4b31ebe5e36-2PK?0eNʑ* c97862b8a7ae5a826e16f986e2a44e21dd9332dd-8PK?fNn* oc978fb572ea8ca43f4380243f619c4bce6e1a579-9PK? gNp;fJ* c97bd7ae04c43ea94d0a72302b2193128ed99729-8PK? )hgN * 'c9830e35d3d0fea473d91c21eb016bf058c8175d-6PK?ZKdN-D+ yc988470b6b08db7f5bcbbcba45bd44f6e2716f5d-31PK?VgNxB3* c99f8cefa84480eea73dfe35f0eda0d27a44398f-3PK? fNd-K* 5c9a50fad23b3d93c3ce7bf717adcea17daf41a62-7PK?MfNxt6* c9ac9fa1c97283211aa64aff8fe651c58dd5ea02-5PK? aNx * c9c083be854bb73b4727c124fdbd452aa5ea4527-8PK? PgN kgT+ Hc9c24d1f2121042dba20ef9188d9914a14caa90f-16PK? aNd+ c9d7c09774f75abdaa1a274dd77ad9f419a8aaef-10PK?L9gN\* c9dd34e8dd3d1ba5aea6f59adb0fc7036cdc0a62-3PK?dNҪA* ac9e0949c613d7eaee4599b602b128d775f2c0600-7PK?mMgNN ( c9ecfb6325ed66c3d2d5f130f19d0529d9929f13PK?fNDGd* c9f2558d6eea58b1af62669c91bea450be3cfc1f-3PK? bkgNY Y * oc9f69a3d6e3214027298fa02a77b9db3ca34dc7d-7PK?6cN#c+ c9fbd1fa12aec0fff8b9baa51e3b7c1c3fd4acb5-31PK? aNw * #ca0376968702f48b8c881f79cd90bf2442f301b5-1PK?|cfN؏S* vca2e70d7d51bff80b1be3a7b5781090781ab3088-7PK?bNL+ ca3187b448519a5c3a716ff72e79f165c5cc63ea-33PK?FgNA2"( 5ca60a62141e51a3ac49bac580658a29ec9d7df4bPK?4gN.5* ca61203e6bdaa52456b53988764ed08d80a47b47-2PK?rfN܏JK( ca66611529460ee7753db675be58cba3b798d1d8PK?i3gN0* cabf490b272a3fb56a3f272063fe9792f5cc373a-1PK? ܝaN+ cad43f1c52f5e7a81a719f0c8fc461b4b6f9ea55-13PK? gN7'Is* Icad6b9a674884cadc9f96ee6ef5f60ffb37d4907-5PK?d bN9+ caec96a08f38150b1f340d31c79a6ec1795f4d6a-20PK?fNTh-* caefd8a9f1c0f775a24a128f9a24201791c5a03f-1PK?cgN4y* \caf96efecb5e15e85e0acb4d4a8da9df8eccf54f-1PK?mfN" )+ caf9d87b6fd233e4580f95f3244a79db7f1c9edf-34PK?KdN^2k* cb0b307c6ee3a8531baf33286ec5f836bd2e3727-2PK? fNϕH* scb1c54970f1716fc5f60830db792f2f15a7dfdfe-2PK?daNޕ^^* cb49cfcf629885e1d683e8c8b3221c4ee0ea06c3-9PK?eNPo'+ %cb51652fa10fdb6cfbdf476530bff00a7dd8eb4b-34PK?%'gN\;+ cb83e0ebd5a72c8185b30d3d1731258fa842166c-12PK? LdNQ * cbbdb2e01a504ca56fb3666b62d67f2604ba4736-1PK? TdNkBX"* =cbc9d1ea829d7d3af5582c486771fe1f87320a91-6PK?6eNqf!+ cbccb3c8bd0de545114c357380df563a61fd4ae9-12PK?`kfN"Y9+ cbe4f373b75ab4d0adf013ab49bdfec2e0779d20-33PK? ԭdN+ Pcbef99a9e3f3977beb11ae1881d5fbe6c76f1d0a-20PK?$cN`yJ+ cc12c9793ec592ab5fb2ebb4a04a3066ed3dfc35-41PK?dN(F+ cc35bae1662be6284273dcb6ce9c310769ba9c44-19PK?TgNIW* ^cc59fa6fea73b5e687e530b0974557c9546fc132-2PK? aN(,| * cc5daea22c69df536fc75985838e2537eb1772be-6PK?ngNh)* cc649e0d90afea2b6915eccde01d78be0d10d0e9-4PK? -aN[0]+ kcc67274d973ae8ae25f01844a594fef9fd2a24da-29PK? [KdN + cc68b5cb5ffc4281a84af3a6dc3a29c94ae13797-32PK? fN#+ cc7bb29a2fb5274b82425f68997dcc2b24cedac9-10PK?gN+ zcc7f940daaa4b6262c95b040691c3f11a6c4ec91-52PK?@fN(/* cc9bd0d9ac01d896eaa5903e99b749e12e0106dc-6PK?1=fN\c@+ 3ccadc6ae8d5f35391d25c69177f7718cc75f3148-38PK?DeNb+ ccb75f65981fa1e3f3a548a9e8cf3b91990b568c-10PK?[neNg&3)+ ccd71871c27eaded96d6dea562b7e1dfe92313ee-11PK?NfNjq+* Cccdb6812e91ad250e50d177215b3417bd50d0489-7PK? fNexڎ* ccea26c1a7c8d047af9e6448637b8466f768cc48-6PK? adND+ cd1b2da5fa6848a0dd393810f2e163579139f2b0-21PK? YfN * Ucd1d53d6c42fc82213e61a4484d2d539ba275f9e-1PK?LfN"* cd23a2eb22f61fc931122620176f1e840e6f6d94-5PK?IgNLq( cd244cad3c92045a86e30a6226efec64185663ddPK?ocN8VO(-( ]cd3f779c9bf46ce21b16cfdf90737778ce62e127PK?=OeN+p!* cd4ed86b1093774244f6d216190ddfee22d14717-5PK?FHgN2 '* -cd5667b19905f21c8fb00e61352899c424a22dbe-9PK?cfNpv8* cda28487729e3063ed1509068dca1fd1aa7e4af7-1PK? 0fN * cda4886bae761a53f764030eb7729015abbf568d-3PK?dN?;+ @cdab598d0d7bab805c4ea4e0ff70caed4fa84a45-44PK?oaN+dܿ+ cdb444118f148137d12f7a5f8bae9fa941c62f01-23PK?iaNhD* cdbd63972ba4d049c2e594583bbaeecb25fa4302-7PK?eN*$( Zcde634ac31c15f3a1022a63d395fe441d7db129bPK? ;dNh * cdf1079634b33b159145412d8aef097c76ab0717-7PK?3ggN,* cdf6ceb73685ae81c390c0c3de5bfaf5ec0fbd2c-2PK?2UgNz.* ^ce03ea2e8902c745d9350318c3dc2cd719bac40d-2PK?gNya* ce09ad883560befe1b790a55b7982191261071df-1PK? bNt+ ce0fe11fec271b6a49e149ba4bf80ebf0b8dd80c-21PK?  dN//E+ vce106e878434ddf19f0eb816126ba53eafdf940c-41PK?lfNTl* ce278f68382090847d0feaca324c03218a1b253d-4PK?JueN\!+ )ce4ed68b67faadb128476472e1cca05b97635b44-14PK? aN$p+ ced067d35a5a531527f85c6ceb6b2d11b27f4def-17PK?֭dN^6+ ceef86769d667a560553ad31fc07cd2676a93d4f-23PK?rcNSl{+ Bcef89a0f8c5db2d8e4efd2c6369f756dc3a0ea0d-42PK?aN75* cefeea0b3de49ae203922a046a66203466679684-3PK?kgNFn!E( cf0184c6c97fb195f12654b213a73dd744671f28PK?.gN+1* dcf050ba7b487f6293894790093f426f294ea1d15-1PK? cN!+ cf121b7443acde7ad235750e06adabb6d7eb7ee1-34PK? JdN-4 + 7cf4f6fa83cee052308b208546044df5dffb3e7f2-12PK?gNJ~* cf641bc0b34ce8e6f6b592fbbdcec344a3bff4d3-6PK?dN!"+ cf6be2fc585ac675c176f9abd3af7f3a00466d30-15PK? OgN^T%5* wcf6cca612decea3936f657f6eeb28d94c8b34bde-1PK?"cNu9+ cf91385a9a8bd915cd95edde647d9cb9acc20203-35PK? eNٮ55+ 8cfa722f370224ee29fdbf0dc9f2468f3608f9736-28PK?ԠaNcÃA+ cfd00dda7e1373502e31fa59dc8c8eca5c6c1633-14PK? aN ,* cfe36aa3d9ff51cdc9bb8be98f17692d5ad3b287-1PK?}eNZ#+ ]d008d80d5abb07ed40addd5d0ff2b10f298191bd-16PK?eN+ d013bdde5e715f99cd4d26e7659ee0206e46690d-42PK?ueN̈o*( d01aecc25158e0f54d34572f2299f3d5984394faPK?bNێJ0+ od02ae6226560dba17b411fc6c21660014fc19498-24PK? OJdN95~ + d038158910cae8d1e7406f1c328320792ea062d3-11PK?bN\TE+ !d046351c6cbdcdfbde1f0eb284aa24c5b7324d63-24PK? KdNK + zd067b3f8dfa2d0820541dc5eac026e7aeefaa487-32PK?aNgH~R( d06cef12b188dc4605f69436ad8e3d953b41d5d3PK?ΛfNbo + h d07b6dcb2b76ff2f7c17a56327dd211cdb14dc44-15PK?@aNZ* d082ef0e74ee9322f13c2c3ad8d3cb4d707e5053-6PK?rcN &;++  d087efee7536b917dd8bafba28c7abac8a16d46f-33PK? NbN_"+ x d0a62147226b5883f3d80f9ffdd6d0b572683043-23PK?%aNb+ d0b00b21af3d6fc5ac9420478fd8a4d541c53442-18PK? aN AK* * d109c09a70d706d20b0288a9483ba2571a87e0d3-7PK? fNX†* d11a821734007191adab48086d49542a4469b5fb-2PK?gdN.(+ N d1230488cba736b48d3757b73325c04765218f9c-15PK? gN* d14ed4bc3dea8c21a0cf0d1fa24738c93faaa824-1PK?BaNN*  d169dcdf06be2ea7f880550d44c5375e1a39cd4d-6PK?[gNB/C$( [ d169f714cab11e68cb73d3529e2ff03ba4e58d07PK?eN]w* d1727491714d733760327e72ddbcf69bcea44c09-1PK?iibN( '%+ d179e34e338d9a53fef9b2c46d79370f730cd081-36PK?fN^eC* sd1895f9c5faa32ec2c9969eee0406ebfc767399a-2PK?bN2IK + d1b040f427e7bb232b15b57d7f92f7495038d44e-35PK?)fN-4* 0d1b10139b30e3e136aef63d51cb4d383d97f83a2-2PK?fN,S* d1c1284b9bb7c48040bc82f9c112340ce66aa472-9PK? }aN_pX+ d1f3d6246954fe9fa2fe0f91e7866da7efe589ec-32PK?bNak+ Cd2034a0a984d538f2e4e1b73d01b8e7ba7c29055-29PK?klbNW+ d2250cccc1a402d591cc616fea88c4eef7f9bbe1-37PK?8QcN=1+ d226166c990999dd6c2c286f8dc87ecb072ff5fb-33PK?gNC"* Ud24f59930ff654b5fcfbeb49fb4586bd57686917-3PK?y`eN}-( d25afc246228638c21109a90ac18877e3e02f0adPK? fNUV* d25bcf8b7bb329b469fe992c9442df8b0b72543f-9PK? \'dNc'W+ hd27b64493b288ef26f9c7c3c3fc88e1564ebdc36-29PK? gN Dl* d28a7ab109c61a68b258f01be7ee5aae65e08816-4PK?waN$+ d2a51ced9dd8d05239dd4d3bbcb52fff0f81420c-20PK? dNȰ@ + xd2ba4b9bcdbd18873d60934e99bc13650234a5d4-10PK?>eN .Z`* d2cd968829978660ed25513a7492ac030f7455f9-7PK?8fNKn+ +d2e6c65fdf6846d5c5717c63617ece6aac6b9305-26PK?}AeN + d2edf58d67e8da39ae6338cc361687105954bb8a-15PK? ʛaN+ d2f2b47977583d0e884f3f2c3aa341c0504bde86-13PK? aN * >d3319700c64c5e48f4310521f095f633d8aedce8-8PK??gN5kG( d34a9a8b60fbaeabd627645abe9ef93c1c24e8d6PK?ԳaNg+ d36d6a0321741cc4bc6ebff5a202eb8c15e78c27-29PK? aN`)* Td37e8c20fcb33d6129e72ceba3fc2ee965d0f48c-9PK?fNvy(+ d39569943c6525f892a047f16a3440ef4647a00f-35PK?UfN݌zX* d3c2d515b3648b2c705ae6d48eb43f6912bad19d-8PK?-fN!+ qd3f1da09216e2b21d99af5377613af123fa2ba24-27PK? aN81ü* d417eb0b000c39a02c1cf6d1b8921c2aa08408b1-9PK?&eNa+ %d422cfe0c71683b661b78c69eccb7b67a16da8e7-25PK? 4fNB** d446529c34d26708044055065e1a98e47ee0388d-4PK?$aN9}+ d47f93bc17b5abb468d90f5a7e21d31a03cdaf58-12PK? @eN.m* 7d4a993000f092a619c6f26bb7ec062a62e661e85-8PK?ÙaNe^* d4cf9b8d2c036f23847d1bb44f4cd07c0fd37da1-9PK?fN?aC+ d4d9fb9060c811e854eea680686f87c379ebdb94-31PK? aN+ ud4dccc6e405cbd4f0b7df44f439ccf1141cfc543-10PK?JcN4i+ d4ea6913bc1f6446cee2cd15a8996015b22d55bd-33PK? BaN[A * &d4efd8ee20d2115c4cde3bf1d7328ca75d348f96-7PK?eNQ'* ,d8590e7467c43ea074f4ff2fe56e1b619444ac91-6PK?"fNMq* J-d862440c21b06f0e6f8fe9453c22a8b910b537ab-2PK?1JgNx};* -d8911cf7c9435b86e8944b050ba23910a5a10c95-1PK?eNsq+ .d8a38e332e8c2a4fd8bbad3ce11b2c9437a2983a-28PK?gN* b.d8acb9bbdbed2e41c3c34cb5ff2f5e4036dd4022-3PK? bNLO+ .d8d8a0910620694c48b37b210517121dd9a88db7-26PK?E*gNM2* /d8eeea77b545ea98dbe282b29b4f0e037401e264-1PK?ZeN6^6* /d8f616477db63039763fa418c66c1f46245fdb12-1PK?AaNt'>h+ /d90546b163ac4a0b19653db1972210d7e19c92ac-10PK?aNʡ* J0d906080bc977fa2974dc112dc85deccf4c9ff773-9PK?]bNg>E+ 0d91208152a87fb2b3aa883edac1ad4a80933fcfe-31PK?efN#۴* 1d91674b2ca71ff95ecd2d85bd187a9f44cd1579a-4PK? ebN>q + [1d92c6bc2762beeb6bdb6cef7447ce2764912e825-18PK?dN+ 1d934e11bfa7df63ad99eebdf4552c5d926a22333-25PK?cNV+ 2d940a280df59d07306c708949512c9d62aab6634-21PK?EbNB7+ e2d95a7e8627a140b0940eeff14c99e56584247150-38PK?6gNdxa'( 2d98ca3788b2243b689d4973a950c0f7782292d66PK?xeN @E* "3d9a91813113a8b49f88c6df8b85d8ef13c39bcef-1PK?TKdNV9=* |3d9ac1ce48cdc75213e84e43456dad7d867a6f73b-4PK?tfNKz{$* 3d9af8b5a1f675bece0f89511f5391b6195311e30-1PK?b gNa&* 24d9cce266845c49f93ef106bb8e627d6a9ef4d3ea-3PK?aNu?l+ 4d9e343d49cf906219b15c98e2ca6892e1efabaf3-14PK? 9gNK+ 4da006ed24a66671dfde0623f5432381515d61dad-11PK?fN_f+ V5da1b4167577311f6a162ea296b706886a88fc271-16PK? aNd`% + 5da22c62d238a05632add72f28bbedc67d003546d-14PK?aN* 6da2f993735286c482144b7694a9112d2b9039266-5PK?bN}9++ \6da449159ec1afe3fbb9a9a8c8639efb6a0eb1360-40PK?wfN")+ 6da4b011e4f30c637cc6a3729574f0cef056eb854-18PK? %fN!* 7da7b4f7f744d7e41de73a0474ab2d7582ef81072-2PK? #aN 꺯+ n7da9ee3df356898d45b681d5fc9d7c76b94da67c7-12PK?dNqx+ 7daba687f9f6fe715f178c2267650f433912b591a-29PK?5nfN7)+ $8daedf637999f53aaf6dbce17c0c8bb970d220769-24PK?kfN [0;+ 8dafc0f5bd58514bb5a04b1d54cd87a7c99beb8c2-18PK?yeN\* 8db122c9acc63f2c2c2f53b596a6ba4d2a6a95bdd-5PK?MfNNg5* 89db13274aef812b2514b0ddec8b30814878236ffd-6PK?YbNT + 9db217fdd0c013ccce34ac00b063a4bb843491c3d-34PK?eN#q9* 9db41ed72bb8252a28563694438390083b23c3e94-1PK?sYeN3Y + W:db42aedf0ff325aa60ad0784fc5b189d6eb0aeb8-25PK? $aNͶ* :db4f8f057764dc584bf3611fe77d8147d14c78ea-1PK?dNw[R!+ ;db58fbc75fd650e42fdf66b1aa6b257b8341810e-29PK?#dNzZ6-+ m;db5cdca3e076610420e835daefe7a23708ad0fa7-35PK?mfNez@EN* ;db61da074b927c50d0eee04866f5a0e8b66326df-7PK?bN"mH+ 0<db75b0992895ee97fcc5c31b8586cae60b1eb302-34PK? TfNgt* <db8e232dac6f65060f2681352387c162f6c12c28-2PK?HaNl%+ <dba05530335f7ec2f83f5c46110f3631a8fd5586-17PK?fN;+ K=dbd9c0d5897093930c9542294da04d70f057a468-12PK?GgN78=&* =dbd9c28fdad0a2ec0b6786fbf9218e1127d29fd4-5PK?fN+ ->dbebcce0922b22caa7d52c7457429c0dc880c305-33PK?dNl + >dc245a837f5d2c0e28a4361e053cc3c3cc97ead2-30PK? ۴aN8R + >dc2c29e54de58bcc1c2cd64e5073288c57019e3e-25PK?TfN*;+ 4?dc4cf63bb7706490e151d1e08bf1db6bad58ea42-13PK?dN~-+ ?dc59200f8b1d54fcd1f3cb8831fcb2e7df3dfb9b-19PK? bNI6+ ?dc5faab3f4d5ee11f18bd237c510a3a5f5071fa6-22PK?pfgNv( L@dc6873c6f9c44494dedb8edd02b2d85ce6c6f46aPK? gNQv@#* Adc6e4100bf3e6961d118e2b2d75c91dec4bedb9a-1PK?teN/:1* cAdc72e83af16c85d21f1da04535ca0c98869377a5-2PK? &aN b* Adc77accabff9ca0ecc2d86fe12fe9dcea0921c23-1PK?RgN)* Bdc93c3a06104bbb6cec189c126b2cbb97fa97498-2PK?aN&Jqc#+ lBdca157ef396fa05a50345b06b5af1f56f7e47f1d-24PK?EaNy!+ Bdcb372171ed242df0eaed3b47e48f50f6c75ce1f-10PK?qaN>,)+ (Cdd0e41eb37e3b8433c1c0302a3967dca1759faff-13PK? ĝaNx" * Cdd10296bd4dbcc957c2e28ed772312009479ca08-5PK? JaNr\ + Cdd668e20fa1c307466e334c3c8dd4e6dcdab30bd-11PK?fN&+ .Ddd791cd9459011d30504e48b593e3d201874f5e6-28PK?AddN$MT@( Ddda11b0b63cf388529773afbb8120cbe28c87021PK?BeNO* VEddaa5d207f56d145ff5a99cd12e650d9fab121b5-8PK?ecNi 5+ Eddb76b1e24788bde87f32867745fdc282a9e4f34-29PK?zfN67* Fdde985690760369cfc153fbff7064eea3baae2c3-4PK?-$eN + nFde2aa87a1497dbb993c11d9b47d24e86105b15d1-19PK?̛aNC^+ Fde402c10188dc5cf2cb2cf222a722eaaf3a82000-12PK?]VfNq'+ Gde41885d354be2d54d26906cae8991e038a0fc9b-23PK? bNbNDZ+ ge520014d46d929cef2f9b4132e35c1a00888c1de-35PK?aN./i+ yge53128c0a9d6590afbe79d2f439d11454e04bf36-10PK? fNBh/* ge53f6312ddf83fe53be07753e63520ad17e55d55-1PK?8TcN&M+ 4he58ba456c4d876bb56d09df5750fa915f914b62e-37PK?+aN+ he5ade8d234cb9753ffca4c9f1342dfe72a3152f5-10PK? UfN$v* he5bc7bf8c944b3cee2c9c721977a2a1a46cde7af-8PK?;eN1)* Gie5bf39632d5db2617ac294c4d2d9b8ef3474caaa-5PK? MdN * ie5c05070be02d82fd57d97aef3fbe05fc5b469f6-1PK? aNb+ ie5fa118890c0c6d213820d9a530d9e62b2e0c5e8-13PK?5 dN1+ Uje60b0a519740d911e0c51a398d63f3d04b446548-45PK? bN+ je620394cd9802249fea10e44980ee1e580b32081-18PK? 5bN,(+ ke62373d409626b579c447e90654eedda255b4d5d-23PK? feNE}* ake63a528e2b00fe517656b83bfa231779cc56a2d6-7PK?0igNkT* ke63fe2c064b12b7bc20a0d135b6b8db5abf2933b-4PK?daNJq+ le654cc024683153cd57317f67172d7db9769d6ae-12PK?.fNEA* kle682b2522b0674e8f4e79d219dbd18b00d4e58bd-6PK?}bN1ֱ#+ le69d1eb550b1b7d4d40468ce981a73aff38dbeef-24PK?aNn\* &me6be220e9ad9487c2cc5828aff6f692bef758349-6PK?rfNh( me6c72891aa50440da7cedfb8a68652d5cca79372PK? EeN 2* -ne6d5067bf590a11f34b083338a8a026959ea65e5-5PK? /(bN/S + ne6e195b129b01b0a7be464939c75503f76e60f04-20PK? mfNMβ* ne6ef6df8e15e9bbc20573b0d74e01fc0c0692f02-4PK?RfNk7* 3oe729ec2aeee5e18398b8ea0e5268c5bdfd942020-4PK?0eN@#* oe72b1a5504824d8fe5accce44178d2015158e2e2-1PK? aN * oe73104b3b0e979b7116f83a8c2fc5293c592efb0-5PK?&fN"** :pe76f1df75acae97ddd9e3d48ea2ab82e249f57bc-6PK? ihgNt0g * pe786833c866a28a9af26d76ecdfe5b0026ac275d-3PK?2eN;g%+ pe7a640952e1bbbc7365a7c80bc40b9098d37deb9-10PK?MgNnX:* Nqe7ad117e43c2ce82940a4b1e5c9c4d8452d5a3d9-2PK?ǣaNPFQ+ qe7bedcbe112fa32d0d9d9769b92f0ee0a90ad606-14PK?aN)*g3+ re7c8c2c36c222d0b0f7bc1ef741d3d382cc7e622-12PK?p)bNyt+ fre7d43240450c770707eeafaa677950dc8a466472-21PK?CaNE2* re7dbeda2631b31ad8832cf9d700e974bcdff124c-6PK? dgNPI * se813d220e84f893d90cc752935d898d3733eec7c-2PK?VgNR?;+ nse82a1fc9e6c29e00828e4a8f0b591c9f5c37b95d-22PK?eNH+ se8439a3022fa4da0e200ec3d62f28c3704a0b068-26PK?  dN3@+ &te84b16c11245b76d500250202f3c758f8f887135-20PK?fN&* ~te87835c37e81eb9e0899360fe056b4fb85e23612-8PK?"gNb '+ te8937d9030366238092a15cefdad2d9df50af018-11PK? +aN|3 * =ue8ac19e845a8fcbf5257dfc6cb5290070bd13135-7PK? 3KdN8n+ ue8af680cff89d2c8d433a5137415ec656745ff14-20PK?51dN=Ĵ)4+ ue8b6d9e72ade202a9d112e6ebfce764f4ee1911f-30PK?bN]+ Nve8e072f15deddc44ac682ab7609e23e1b76c899d-30PK? dNL + ve8e6a49203a54d89d5f3eb2af670aae1040e0930-19PK?cN&VfY* we8fef31b8254571237b7169579687f6b27bb0cae-3PK?1eN* `we938fd080b9043b6432e8e86b3c25b8fd6afec28-9PK? QdNLɣ* we93c6f0de9b460c1f6d6ab980ae92ed4a9865de8-3PK?aNX+ xe94ca14debee1b32811766888a30f8d03a9f4c22-12PK? eNq.]+ lxe95e20126f3dc8b0c3aae54cb1d552df1fd4daa2-25PK?aN* xe9747f0fd3f218813629be7df86e283fdd139ed8-6PK?˥aN| + #ye987fcebbe583f40df1a4e3704f9f8ea855a0918-14PK?}aNӰ5+ yye9d66d0b59ef2cfff0e248de251c061595d95257-18PK?gNjQ* ye9d71606ceb62a57eacaa231ce6841e3cb21275e-1PK?aN<4!+ Cze9e0efa4be4a72f4fe422f815d290191b70db9fc-14PK?YaN{+ ze9fbfb4c462179caa71ae40c05c3e831dfe31786-11PK? bN+ zea25f6fb688ddd9c36bbe3b44ddea86ef5a168fc-32PK?aNe+ S{ea35d0fd3f35a6d9bdcd0f68774a3d5d6bf48909-10PK? aNj + {ea3b845baf53974b506219f3954f8ac4e7aa9985-10PK? '|aNo5 ( |ea45e85943187ec1324ee7e2fdf7985b713f9e65PK?DbN + S|ea6257f3216c46a4ce14ed86c5a35d1ef6c9e280-33PK?aN| th( |ea8316540a1ed0202e880932e8591ac757f289f9PK?MgN !( [}ea9802bbf057d9aeb32aeba7a627a78b4cdb9e56PK?gN9v * }eaba1bcbf929c8cdd51d1c4ce8eb90f8f525e686-4PK? mgNP+ ~eac6ead35a1212e3f56643aee0174ff7f9a1ee30-10PK?fN"+ s~ead254ae92f11cd81df0e36a21ce01cfc4031827-10PK?-#eNc o + ~ead8eaa7bd2985c74fffc77230499f0fab6b8d6a-14PK?aNK9( ,eadf718ab2dc15061a5d678a11db817f75cb4c9bPK?fN}>e * eae3616c4a030520c5d533cd50b4d2fd56c26130-9PK?"aNv+ eaf8ad00d973bf48fac76d81e8b2fefd3cc9dab1-11PK?xeN$lo!* ceb244a021647e244220eb6731bd9ec92f4be25e2-1PK?fN=<* eb322bf171db0b32b279617f85b00023b1f51585-8PK?2meNGn + eb457d93107c2dc384db95fd33acdfe65a7e18aa-11PK?taN&!)+ ueb5a32af43dbcc607181ef86237a8d8102f0abcc-13PK?aN + ҁeb5b8641b3dae39a2fb7cb462bc899bd025f53bd-15PK?-aN.)+ (eb6357e63a7e8fcc43a6828bb7110f1132b0a421-13PK?ZaNW+ eb66b8ecb9a5dd904f278bff90cfcb10be714909-16PK?KBgNe6=* eb8a08a9b69a4f20ab81d34f3184cd1d487d5cc2-2PK?\dN>/o+ ?eba6c75fa010a9c08b83bcba9ff330f851197eeb-19PK? aN' * ebac6e976a213e9eb7dbb455fbcc23b920e3137c-9PK?fN+k0* ebc4760b5601da55dbc185efb17d8b6e41f72ca2-6PK?fN:['* Nebd16768e6b0098979ac325f0bc3da8aeb7d4a7f-4PK?fN%a7%* ebe869d2473f83e2c988a578df446e6b7e91b953-6PK?ffNP}&+ ec1685e23cda84eee667b1566e5ffb054312c37a-12PK?UTgN83* fec4a27305f457c0a0a3875486d8617dc610ba298-3PK?fN+ Ʌec691f365283d2c597c84adbf5c71edd473e50cf-34PK?fNh* %ec7c03e204d4223a9003cc29efc77a13743183c5-6PK?VeNSX* }ec8183a581f3ab1b1121a9e9f2975135151732c7-1PK? dN[+ چec880ea316eeb590feff29e4b65c5aa682225a10-31PK?MeN+ 4ec8fea7c6edbfe3e742c60f8261d29dd7681e71b-21PK?`cN/+ eca47cb0e418bec0d5167fd73d52e92f64af265a-28PK?fN;W* eccaedb047e9d735b315fcc8ae3ebd63e5ddbcaf-5PK? VfNϞ* Jece5570fc2196a98759dd0a7a3c8f6680aba98b9-9PK?OSgN;( eceafb97aa34562cacc9124a28fa184149346bcdPK?>dNU0_+ ececbde63c32e2d1f31169ddde04611971191c1f-34PK?+gNj~{!+ recfd25307c149c3c9ad20cc2fc133f5668ca5f96-20PK?dNM5+ Ήecffded13a933efd2bb07b90055823dd104678a0-15PK?OJdN'+ %ed15314e94ef7ab67a5e2b97d8b01d79a44313cd-16PK?DdN?* ed19bf4add03e76da392b1a835b780f91c254c77-4PK?aNd9* ۊed26ed10e15fe58d1ca2f9fbf4f10135213f89f0-9PK?eN#* 2ed325b0b49c88c2d30a725330b50096c047250ca-3PK?!+ ed95ee95c88724ba9687a861f01040203be36f13-34PK?aNcH+ cedca21d36e03df33e6871e41fa8a066b550f0114-20PK?OHgN"O+ edd323bd43b6ec59bc5f43bbb2126d28618fc639-30PK?aNF_&+ edddf22d981c08b156c2dd6c312b552159250d3e-28PK? aNN* ede550848e196c2b870c3be0213061f01d7d52b9-3PK?%bNx+ ؎ee0b5e00d31d37156e11efcea50b473fe28f7f35-29PK?AfN2* 1ee0f9979769a971f38447f97d4d63f566c886bc4-8PK?fN1+ ee32f64f26cb430634371e87764138346f31595a-12PK?=bNV++ ee36d9a9e21b038f9f980d1bfa0d2e706bee0a39-38PK?6dNMI8/+ Hee37b397be1a07eff6daa81b2361128ed23fe9d6-23PK? ۑfNcfx * ee3ce180a863e8ae0bc06ae07236db3bf3559069-7PK? bNoR + ee68386ef8074c1c2bd5050e6fc01a46768cc433-31PK?-aN!* Nee8073b0a29474ae32bc74055013ba8d7d9fb81f-8PK?vdNs%+ ee854b7fc36080f6dbdd885c4623560aaf2cb8b1-26PK?2UfNJ#+ ee8c813ad4d23922b32aac489246395955e0f031-22PK?pdNPA* bee962a34ddc8810d10dfa43228a26bb618faa9fe-4PK?:eNt+ ee9fd28d3b6e2818096fb795d1aeecf5f53289f0-20PK? ;aNgK* Eeea1a46b9702893f6d543afdc74c69e2392615de-5PK?fNc+ eebe19e7dae9bb37b91f93a6b9daac1e8a5dfcee-40PK? 6aN* eedf4c624bfd89700305fa8eae086e85693cdc9b-9PK?OfNSf* Peee243428e162e0b7608825ccdbb6a0a556dd58c-6PK?AcN+ eee40349213b2e4a453fa6349b61ad821ce6087d-35PK?aN+ eef4d9261b11d4e3edbfb60961aedf4f7749abe7-34PK?aN>]* meef6538fb3d5dc6168e6eee809d565e8f42a5dbc-8PK?J/gN5jn)-( ŕef0fb09a7aa4792fafc7d5e6cea00929382b33e1PK?ffN/* 8ef183cce647eea9fbf24278d23f88eaf520d7af5-1PK?ԱcNS-+ ef315140bc41872b69ae6ecc55e2280c4419cac0-20PK?ȅfNMZU]* ef33997eb6af1790079432540bb72864b6a0d65f-1PK?VaN")!+ ef3e3bcc373d2c8b3b484d56c86bcb51c1381cd4-30PK? aN,+ ef666c40ad2e7b732fe3e07986f1dd7bf10687f0-15PK?dNэ+ Qef6cafa89c28a479ec3842c17d14215fc03922e5-21PK? RaNND(+ ef765d2bff5ba6a1e9b9b9aa3eaa956d9af991d1-16PK?igNȑ * ef9f7c2792e1146bc09fbd8c0a2deb45c5746bd9-5PK? aN۰4 * Zefbec01b5ca702eb2389d611ab343ed367c4ce9f-8PK? aN2p+ efda98fb8a4761e7b35f2da344d36d09ae96019e-12PK?FeNkR'+ f00f5cf6225625dd027a3bb38f148ddf301a8e31-23PK?KdN 2#+ gf03b4772ddac4275046670ede833c709edfb9a8e-21PK?uaNx)#* ƚf041125e40431a90d32b28eb488f3016e7a165b3-7PK?cNo#f:+ "f04fa1a324f745df610c5173b61d6685e802480e-40PK?@eN];H+ f063e1a7c8e8404a6b3b1535d91dae12f51054ad-14PK?aN&?,* f066132bf0a2bb85039326fd08d40c27988ef697-7PK? bNr1+ >f074f369bd1fa8bb428310ec04637a442c876a50-33PK?N2bN 2+ f077ccb4f88527f529b08b97d0458fcdac73bd30-32PK?۬dN]ؙ+ f0873ef153892464c51cd95739cde636766799b4-18PK?[dNB+ Wf089db13c8f603552480279b77dad0c14a90bc70-13PK? 5bNO#ʛ + f090996c84a7b023c1bae22237eaf7686d96dc60-37PK?",gN<0-* f09bcd1b9d4e0a2da67e2ec9802793c8b5c29675-5PK?dNچ>+ df0a6df541da683e9e23acc0a8e7d1b50ef2e51cc-17PK?J0gN/O=* f0af317b73fc1064a153a9e0995c31be9ea69cbb-2PK?CcNcM#+ f0bac8f640025dc5263f84d5125a1d60b979bb8d-36PK? aN0* ~f0f11a537327c63b3172624a198c82f548649283-6PK?ZfN2F<+ ԟf1103d12ad0e8ea963da66cb698564d3f8c1a7a7-31PK? aNO7 * 8f1156764badfadcabd88318973292cb1d96a3345-2PK?tbNd + f133686fc91cc2b1f588c33c7157477e82e405ae-39PK?-*bNbk++ f164328c234094ea03a4bc64d7bde4489c90a508-26PK? "bNS߼+ Jf17888405a0753c47d00ca111f5af9d5c82c57a6-28PK? /aNA^ + f17ebe3439c7ac9764a6f5cb70d7902212a7c764-30PK?aNy* f192ff31f2c06fb0db5e276f6cbd84816dc60b63-3PK?fN* Xf1a1c704f503988bab7746660a057ac4dc182173-9PK?dNB7~H+ f1a60da91e5e075d61e16c81c9b906dc67f18c28-23PK?KgN!be!* f1b58e6f37b5cb8608ca0665cc171238580b431d-5PK? bgN"c * rf1c1f179661cbc0dfca581dcd2d3dbcf66680469-5PK?fNVo* ģf1eb773b9e453b662cd3c8a076f8c29230735ccd-1PK?٢aN.E+ bf2113091be5fcf1fc2008dbeadba884eaae819e2-22PK?ّfN#ey+* f218a1b9f074b8235163b6448cde9ca2dac7acf2-9PK?dfN "( f21f9c12779730e0571fb1703eff2b00bfab6fa1PK? ZbNƒ + tf23415253391dc90cff868cb5742f596cefdfa3c-21PK?.cNO+ ʥf23d4b404f773249fbaceb07fba66ca665a22df7-40PK?s)gNN+( &f24c7bccd7809b68c8a646637d29679fa6d1fc96PK? XaN5 + f27b98ae180da0fef8d2ef68a32f3a76f13e64e5-11PK? KfNC* ئf2a2624c30e0fe7a3057cc5411e0fb55cf044685-4PK?aN5( /f2a720a96568b5315e71c09cc3ac63f76b5e6f12PK?aNrMը+ f2aa1f8c1f3870c7f9227c70ed85106aa70a80d4-24PK?2aNXY+ Mf2c22b6f503a82038e02b9095ec78d299076e350-15PK?%^fN63* f2c602ed7387b696f9a7ef8352bb9e664da537c1-4PK? ƙaN`<* f2eba2cb8f7beef8dd72e4f1500661427efe9a67-8PK? aNH+ cf306873128833e5b65ac78b726465c4b840867c5-13PK? dN봞* f31a50d1b49664c83d02cdd7b60905ce4e78ac4a-4PK?fNE6 +* f338404df2dae81d88da9ac2a0608713cb0f17a6-8PK?hgN^T* f33d79ea88e8fb964c7748e9cece78b7b6b29538-6PK?jaNӲ+ f35e764c4c3f6945b68fe6f8a0896309189ebac1-13PK? eN?d+ Hf36196b8c433ca5b1a323c89f360ff5f3c9b7b47-22PK?fNPB)+ f362869664d31ac301984b940cf5b7e6db97b89d-34PK?bN.BT5+ f36e9389c38038d83dc7789e6323a48a53d9b353-37PK? lgN(0* bf372f4252ddc97371d6dafbf00d55502e2359b0d-8PK?AfNط]%* f37c71f51ff74d5fd3a59f334a10c0f115293bb4-1PK?h$bNx+ &f37e3f82e3aa468bbf5e156580e43ceed78c41dc-31PK?ybNa+ f381014cdbc25d03c9814fb35a00f418e0affef8-40PK? kaNA + f39023a1bab39d4e7274c00a90656a3166ce7745-11PK?aN;sf!+ >f3b681fd8dec1c35a8ea9b7bd6137bdd31a5e475-26PK?yeNcE* f3c68af358ef7d23eec4fddc1a159706e8730f97-6PK? aN\R,W+ f3d679658af49208038351980b646f8a29926ece-15PK?0fNH#* Tf3d9df20dbed2718a8b2084c0af71daa44a48c07-3PK?mgN+ f3e1f80e308732936dbb7d5b60daf47c457da572-35PK?ygN6&%* f41b36497e7c9e531f09b1df75f202d350ff08bf-3PK? bgNWwx5 * ef42315452baf365331ca16a9bb5944a896d564e5-5PK?aNt#b+ f430f1890613a4cea09c2dfa9b427c482d572184-16PK?FeN8?+ f43e61e8fa982be6f0694e47e6eb62bf0fca412b-11PK? aNq& + jf44207aeee40f4c45e8a09be31df0b3e2e6ee974-18PK?fNeݽ* f44e7d9f4500ecab5905e30885e58daadfa1760e-8PK?2gNԞ9( f473286536d6f56d219cc9cfde38b6b965ff305dPK?PreNc1b* yf47789a4e88559770940e6c9f1e8816f2be3b529-1PK?fN[8 + f479a8590bfd25bd7ad9a902d9c31e3970ff2a1a-25PK? aN{+ Nf47d7b1fda4b6eebc9c2a9c0511385849f90b5f8-14PK?Q!eNBɸ!+ f49ea16f03c118ddc8f98d7e8fdf2c74e1e23db7-23PK?8>gN{#D* f4b5f85b70f0509cbc3a4e868478c4701da8778c-1PK? +3dNp+ jf4c0866d571d1a6b5310ef3d3637ce6a1083c6de-31PK?aN.]* ƴf51ef7977498f96a9e81b7dd69f9af4c2c2ba0cc-5PK?deN@C* f52c963455a432e435f95a100cd655d3ca59fa17-3PK?&eN࿺r"+ f56764b8077b1509b8aaff794119e381dea66747-21PK? *aN** ߵf5a32762a1af6bdd3d9f0ba641828b4032953890-6PK?seN.wl1( 6f5b823536b329cf185a2e240d4291ffe6d3c0369PK?U&gNAE.( f5d435532b2b3a51dac2fccfaad8d5e2936f8915PK?aNdP!+ f5daa4dfed49918305c6f26998d118f7839301ee-11PK? aNԂ9+ if5e0800c7ae4859bdd47e749a5ce128f08d1b4ac-10PK?EseN=N+ f5fd3721e84ca8e2b4a55f6940289b37f7e687f3-12PK?aNn#* #f61f834e196c069994fee135946a736c8add93ab-6PK?eNy#* f7c4b6ec3054aa5c040a3a35004336fdc6dab0e8-1PK?9fNe+ f7cd6ade8cec5e39a843401283893501af5d21d7-18PK?dNb<$+ Ff7e9349f361c489618b3e33f53651a6b545c98f4-23PK?ffN פ/( f7f145a5461f2a9a05b9a9b2475bff2e1d5a9882PK?FeN^F+ f80904df0f57376abd5ae4ccb53ae010658c73e1-23PK?nfN1+ Uf8106df3a886f9cf30f5fd31dab7671d9bd0a320-20PK?dNE+ f827e82a9cd7cc2c7c034f38f7e055968de8684f-21PK? dN-+ f83b64d9d9498fb70d50d68db6739910810f429c-30PK? ԌeN| + vf84234f38ca1ed56cebbb83ee178c143a7fcf399-16PK? RaNm1 * f84ea00a3c37717e73b7884de49aebdd0826b32b-7PK?yUgNy'* f864de99bd5009899bd35385f67dfacb74b1f5ba-8PK?:eNL^X#* f879ec54cc2a467f63710195f2418718387d3fdb-4PK?`fN&R* f87b72f67c4a97d97c88ef7375b44ff63517cb9f-4PK?bNujX+ If88429940d6a10df854cf51bc776ec6b83f8c48a-25PK?"aN'S/+ f88623f03fed4b63a36ff9383d2830371602e152-20PK?  eN鰝+ f89efe3308d740ea3caaeb0f9e846f3db3b5c079-21PK?FbNVH+ Zf8ac57ef0114d736468927fa21cbfc083291ab87-25PK? aNg+ f8b57fa916bd286a30008f84863a9dddf961c4e9-15PK?VaN8+ f8c08f4e0beeac1012358fb409377b9a3d273ced-15PK?bNt9T++ nf8d8073fdb3d6e463896af620ace64e342fbe734-44PK? aNN + f8e6fdac088292d80aa2a5ccd08bdb24cfe2b3aa-23PK?iSbN5+ #f8eb897d60a62534af507b07ab25cddf5830c4cf-40PK?QdN]+ |f90c413f20928bf82e7613219414d823cdf61441-16PK?VgN#M*+ f9193b84aa73fed61cfd2943b955bc5290330eb8-21PK?g]eN,NR+ 8f93fe23527bf1d440de2d6688ea09668bc78ca05-28PK?0aNG+ f93ffdc4a1fade364f72065925e6ab1500ebd582-17PK?GeNr@* f9528bb8cf0ae17f7a8775da7f8a7aab0aca2346-2PK?fND"* Of9622da10a8500df27a4eacdc5d939804454bf61-4PK?aNK[-+ f998a6a1a60fb4f14256d30ea1e4b47356caa7f0-21PK?bNez5+ f9a274a73319a713908b3a27ee628d0a53a0e920-37PK?UeNt-A1+ gf9a8a92a465db38555b98dd9f1b9feb9434c9e45-29PK?/dNVW%+ f9b17dbe94e41d40f6d11a0dfae895ea870c6c03-29PK?gNu}L* 2f9ba8e075f1b9ffcba2358801f180fe7076a0230-6PK? NJdNg* f9c168898b23b4154a65ccc52862404d8c6cf3bb-1PK?]dN!a* f9d9a1f488d5f1e87f6d025fdd73506f73b541a7-1PK?naN*8)+ f9e3c668f1f4abb885efed056c220ba17295e6a9-11PK? aNFP + f9f2c670dd13a2f3253b35e9f8d644b346e0fcf5-15PK? aNXc+ qfa15ce7ba7c6bb53ad0bfdf68fe2f9b0621b352c-18PK?fNu6* fa16d98731026420b0cba0e344f78a455d3fb88d-3PK? }SdNԉH* %fa2b62aefa120368f8164285c1a673322cbdf554-5PK? fN;p* }fa2f84ee6c0436990c25fb598b9a348dfd756af1-1PK?( ffe4573d4aeb1adbd7e9b8e5cf8ff8649b645e80PKI I זgolang-gonum-v1-gonum-0.14.0/graph/formats/dot/fuzz/fuzz.go000066400000000000000000000015501450372207100235240ustar00rootroot00000000000000// Copyright ©2019 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:build gofuzz // +build gofuzz package fuzz import ( "bytes" "os/exec" "gonum.org/v1/gonum/graph/formats/dot" ) // Fuzz implements the fuzzing function required for go-fuzz. // // See documentation at https://github.com/dvyukov/go-fuzz. func Fuzz(data []byte) int { // We don't accept empty data; the dot command does. if len(data) == 0 || bytes.Equal(data, []byte{0}) { return -1 } // Check that dot accepts the input without complaint. cmd := exec.Command("dot") cmd.Stdin = bytes.NewReader(data) err := cmd.Run() if err != nil { return 0 } // Try to parse the data. _, err = dot.Parse(bytes.NewReader(data)) if err != nil { panic("could not parse good dot") } return 1 } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/000077500000000000000000000000001450372207100230145ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/Makefile000066400000000000000000000015141450372207100244550ustar00rootroot00000000000000gen: dot.bnf gocc $< go run paste_copyright.go debug_lexer: dot.bnf gocc -debug_lexer -v -a $< go run paste_copyright.go debug_parser: dot.bnf gocc -debug_parser -v -a $< go run paste_copyright.go clean: rm -f errors/errors.go rm -f lexer/acttab.go rm -f lexer/lexer.go rm -f lexer/transitiontable.go rm -f parser/action.go rm -f parser/actiontable.go rm -f parser/gototable.go rm -f parser/parser.go rm -f parser/productionstable.go rm -f token/token.go rm -f util/litconv.go rm -f util/rune.go -rmdir --ignore-fail-on-non-empty errors -rmdir --ignore-fail-on-non-empty lexer -rmdir --ignore-fail-on-non-empty parser -rmdir --ignore-fail-on-non-empty token -rmdir --ignore-fail-on-non-empty util rm -f terminals.txt LR1_conflicts.txt LR1_sets.txt first.txt lexer_sets.txt .PHONY: gen debug_lexer debug_parser clean golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/astx/000077500000000000000000000000001450372207100237735ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/astx/astx.go000066400000000000000000000253711450372207100253110ustar00rootroot00000000000000// 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 } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/astx/astx_test.go000066400000000000000000000041311450372207100263370ustar00rootroot00000000000000// 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_test import ( "bytes" "os" "testing" "gonum.org/v1/gonum/graph/formats/dot" ) func TestParseFile(t *testing.T) { golden := []struct { in string out string }{ {in: "../testdata/empty.dot"}, {in: "../testdata/graph.dot"}, {in: "../testdata/digraph.dot"}, {in: "../testdata/strict.dot"}, {in: "../testdata/multi.dot"}, {in: "../testdata/named_graph.dot"}, {in: "../testdata/node_stmt.dot"}, {in: "../testdata/edge_stmt.dot"}, {in: "../testdata/attr_stmt.dot"}, {in: "../testdata/attr.dot"}, { in: "../testdata/subgraph.dot", out: "../testdata/subgraph.golden", }, { in: "../testdata/semi.dot", out: "../testdata/semi.golden", }, { in: "../testdata/empty_attr.dot", out: "../testdata/empty_attr.golden", }, { in: "../testdata/attr_lists.dot", out: "../testdata/attr_lists.golden", }, { in: "../testdata/attr_sep.dot", out: "../testdata/attr_sep.golden", }, {in: "../testdata/subgraph_vertex.dot"}, {in: "../testdata/port.dot"}, {in: "../testdata/quoted_id.dot"}, { in: "../testdata/backslash_newline_id.dot", out: "../testdata/backslash_newline_id.golden", }, } for _, g := range golden { file, err := dot.ParseFile(g.in) if err != nil { t.Errorf("%q: unable to parse file; %v", g.in, err) continue } // If no output path is specified, the input is already golden. out := g.in if len(g.out) > 0 { out = g.out } buf, err := os.ReadFile(out) if err != nil { t.Errorf("%q: unable to read file; %v", g.in, err) continue } got := file.String() // Remove trailing newline. want := string(bytes.TrimSpace(buf)) if got != want { t.Errorf("%q: graph mismatch; expected `%s`, got `%s`", g.in, want, got) } } } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/astx/doc.go000066400000000000000000000005361450372207100250730ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/dot.bnf000066400000000000000000000202261450372207100242730ustar00rootroot00000000000000// The DOT Language // // http://www.graphviz.org/doc/info/lang.html // ### [ Tokens ] ############################################################## // The keywords node, edge, graph, digraph, subgraph, and strict are case- // independent. node : 'n' 'o' 'd' 'e' | 'N' 'o' 'd' 'e' | 'N' 'O' 'D' 'E' ; edge : 'e' 'd' 'g' 'e' | 'E' 'd' 'g' 'e' | 'E' 'D' 'G' 'E' ; // TODO: Rename graphx to graph once gocc#20 is fixed [1]. // // [1]: https://github.com/goccmack/gocc/issues/20 graphx : 'g' 'r' 'a' 'p' 'h' | 'G' 'r' 'a' 'p' 'h' | 'G' 'R' 'A' 'P' 'H' ; digraph : 'd' 'i' 'g' 'r' 'a' 'p' 'h' | 'D' 'i' 'g' 'r' 'a' 'p' 'h' | 'd' 'i' 'G' 'r' 'a' 'p' 'h' | 'D' 'i' 'G' 'r' 'a' 'p' 'h' | 'D' 'I' 'G' 'R' 'A' 'P' 'H' ; subgraph : 's' 'u' 'b' 'g' 'r' 'a' 'p' 'h' | 'S' 'u' 'b' 'g' 'r' 'a' 'p' 'h' | 's' 'u' 'b' 'G' 'r' 'a' 'p' 'h' | 'S' 'u' 'b' 'G' 'r' 'a' 'p' 'h' | 'S' 'U' 'B' 'G' 'R' 'A' 'P' 'H' ; strict : 's' 't' 'r' 'i' 'c' 't' | 'S' 't' 'r' 'i' 'c' 't' | 'S' 'T' 'R' 'I' 'C' 'T' ; // An arbitrary ASCII character except null (0x00), double quote (0x22) and // backslash (0x5C). _ascii_char // skip null (0x00) : '\x01' - '\x21' // skip double quote (0x22) | '\x23' - '\x5B' // skip backslash (0x5C) | '\x5D' - '\x7F' ; _ascii_letter : 'a' - 'z' | 'A' - 'Z' ; _ascii_digit : '0' - '9' ; _unicode_char : _ascii_char | _unicode_byte ; _unicode_byte : '\u0080' - '\uFFFC' // skip invalid code point (\uFFFD) | '\uFFFE' - '\U0010FFFF' ; _letter : _ascii_letter | _unicode_byte | '_' ; _decimal_digit : _ascii_digit ; _decimals : _decimal_digit { _decimal_digit } ; // 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 (<...>). id : _letter { _letter | _decimal_digit } | _int_lit | _string_lit | _html_lit ; _int_lit : [ '-' ] '.' _decimals | [ '-' ] _decimals [ '.' { _decimal_digit } ] ; // In quoted strings in DOT, the only escaped character is double-quote ("). // That is, in quoted strings, the dyad \" is converted to "; all other // characters are left unchanged. In particular, \\ remains \\. // 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. // In addition, double-quoted strings can be concatenated using a '+' operator. _escaped_char : '\\' ( _unicode_char | '"' | '\\' ) ; _char : _unicode_char | _escaped_char ; _string_lit : '"' { _char } '"' ; // An arbitrary HTML character except null (0x00), left angle bracket (0x3C) and // right angle bracket (0x3E). _html_char // skip null (0x00) : '\x01' - '\x3B' // skip left angle bracket (0x3C) | '\x3D' // skip right angle bracket (0x3E) | '\x3F' - '\xFF' | _unicode_byte ; _html_chars : { _html_char } ; _html_tag : '<' _html_chars '>' ; _html_lit : '<' { _html_chars | _html_tag } '>' ; // The language supports C++-style comments: /* */ and //. In addition, a line // beginning with a '#' character is considered a line output from a C // preprocessor (e.g., # 34 to indicate line 34 ) and discarded. _line_comment : '/' '/' { . } '\n' | '#' { . } '\n' ; _block_comment : '/' '*' { . | '*' } '*' '/' ; !comment : _line_comment | _block_comment ; !whitespace : ' ' | '\t' | '\r' | '\n' ; // ### [ Syntax ] ############################################################## << import ( "gonum.org/v1/gonum/graph/formats/dot/ast" "gonum.org/v1/gonum/graph/formats/dot/internal/astx" ) >> // === [ Files ] =============================================================== File : Graph << astx.NewFile($0) >> | File Graph << astx.AppendGraph($0, $1) >> ; // === [ Graphs ] ============================================================== // Graph : [ "strict" ] ( "graph" | "digraph" ) [ ID ] "{" [ StmtList ] "}" Graph : OptStrict DirectedGraph OptID "{" OptStmtList "}" << astx.NewGraph($0, $1, $2, $4) >> ; OptStrict : empty << false, nil >> | strict << true, nil >> ; DirectedGraph : graphx << false, nil >> | digraph << true, nil >> ; // === [ Statements ] ========================================================== // StmtList // : Stmt [ ";" ] // | StmtList Stmt [ ";" ] StmtList : Stmt OptSemi << astx.NewStmtList($0) >> | StmtList Stmt OptSemi << astx.AppendStmt($0, $1) >> ; OptStmtList : empty | StmtList ; Stmt : NodeStmt | EdgeStmt | AttrStmt | Attr | Subgraph ; OptSemi : empty | ";" ; // --- [ Node statement ] ------------------------------------------------------ // NodeStmt : Node [ AttrList ] NodeStmt : Node OptAttrList << astx.NewNodeStmt($0, $1) >> ; // --- [ Edge statement ] ------------------------------------------------------ // EdgeStmt : ( Node | Subgraph ) Edge [ AttrList ] EdgeStmt : Vertex Edge OptAttrList << astx.NewEdgeStmt($0, $1, $2) >> ; // Edge : ( "--" | "-->" ) ( Node | Subgraph ) [ Edge ] Edge : DirectedEdge Vertex OptEdge << astx.NewEdge($0, $1, $2) >> ; DirectedEdge : "--" << false, nil >> | "->" << true, nil >> ; OptEdge : empty | Edge ; // --- [ Attribute statement ] ------------------------------------------------- // AttrStmt : ( "graph" | "node" | "edge" ) AttrList AttrStmt : Component AttrList << astx.NewAttrStmt($0, $1) >> ; Component : graphx << ast.GraphKind, nil >> | node << ast.NodeKind, nil >> | edge << ast.EdgeKind, nil >> ; // AttrList : "[" [ AList ] "]" [ AttrList ] AttrList : "[" OptAList "]" << $1, nil >> | AttrList "[" OptAList "]" << astx.AppendAttrList($0, $2) >> ; OptAttrList : empty | AttrList ; // AList // : Attr [ ( ";" | "," ) ] // | AList Attr [ ( ";" | "," ) ] AList : Attr OptSep << astx.NewAttrList($0) >> | AList Attr OptSep << astx.AppendAttr($0, $1) >> ; OptAList : empty | AList ; OptSep : empty | ";" | "," ; // --- [ Attribute ] ----------------------------------------------------------- Attr : ID "=" ID << astx.NewAttr($0, $2) >> ; // --- [ Subgraph ] ------------------------------------------------------------ // Subgraph : [ "subgraph" [ ID ] ] "{" [ StmtList ] "}" Subgraph : OptSubgraphID "{" OptStmtList "}" << astx.NewSubgraph($0, $2) >> ; OptSubgraphID : empty | subgraph OptID << $1, nil >> ; // === [ Vertices ] ============================================================ Vertex : Node | Subgraph ; // --- [ Node identifier ] ----------------------------------------------------- // Node : ID [ Port ] Node : ID OptPort << astx.NewNode($0, $1) >> ; // Port // : ":" ID [ ":" CompassPoint ] // | ":" CompassPoint // // CompassPoint // : "n" | "ne" | "e" | "se" | "s" | "sw" | "w" | "nw" | "c" | "_" // Note also that the allowed compass point values are not keywords, so these // strings can be used elsewhere as ordinary identifiers and, conversely, the // parser will actually accept any identifier. Port : ":" ID << astx.NewPort($1, nil) >> | ":" ID ":" ID << astx.NewPort($1, $3) >> ; OptPort : empty | Port ; // === [ Identifiers ] ========================================================= ID : id << astx.NewID($0) >> ; OptID : empty << "", nil >> | ID ; golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/errors/000077500000000000000000000000001450372207100243305ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/errors/doc.go000066400000000000000000000005031450372207100254220ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/errors/errors.go000066400000000000000000000060341450372207100261760ustar00rootroot00000000000000// 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" "strconv" "strings" "unicode" "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) if e.Err != nil { fmt.Fprintln(w, "Error ", e.Err) } else { fmt.Fprintln(w, "Error") } 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.Fprint(w, "Expected one of: ") for _, sym := range e.ExpectedTokens { fmt.Fprint(w, string(sym), " ") } fmt.Fprintln(w, "ErrorSymbol:") for _, sym := range e.ErrorSymbols { fmt.Fprintf(w, "%v\n", sym) } return w.String() } func DescribeExpected(tokens []string) string { switch len(tokens) { case 0: return "unexpected additional tokens" case 1: return "expected " + tokens[0] case 2: return "expected either " + tokens[0] + " or " + tokens[1] case 3: // Oxford-comma rules require more than 3 items in a list for the // comma to appear before the 'or' return fmt.Sprintf("expected one of %s, %s or %s", tokens[0], tokens[1], tokens[2]) default: // Oxford-comma separated alternatives list. tokens = append(tokens[:len(tokens)-1], "or "+tokens[len(tokens)-1]) return "expected one of " + strings.Join(tokens, ", ") } } func DescribeToken(tok *token.Token) string { switch tok.Type { case token.INVALID: return fmt.Sprintf("unknown/invalid token %q", tok.Lit) case token.EOF: return "end-of-file" default: return fmt.Sprintf("%q", tok.Lit) } } func (e *Error) Error() string { // identify the line and column of the error in 'gnu' style so it can be understood // by editors and IDEs; user will need to prefix it with a filename. text := fmt.Sprintf("%d:%d: error: ", e.ErrorToken.Pos.Line, e.ErrorToken.Pos.Column) // See if the error token can provide us with the filename. switch src := e.ErrorToken.Pos.Context.(type) { case token.Sourcer: text = src.Source() + ":" + text } if e.Err != nil { // Custom error specified, e.g. by << nil, errors.New("missing newline") >> text += e.Err.Error() } else { tokens := make([]string, len(e.ExpectedTokens)) for idx, token := range e.ExpectedTokens { if !unicode.IsLetter(rune(token[0])) { token = strconv.Quote(token) } tokens[idx] = token } text += DescribeExpected(tokens) actual := DescribeToken(e.ErrorToken) text += fmt.Sprintf("; got: %s", actual) } return text } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/000077500000000000000000000000001450372207100241335ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/acttab.go000066400000000000000000000175721450372207100257340ustar00rootroot00000000000000// 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: "", }, } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/doc.go000066400000000000000000000005011450372207100252230ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/lexer.go000066400000000000000000000102711450372207100256020ustar00rootroot00000000000000// 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 ( "os" "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 Context token.Context } func NewLexer(src []byte) *Lexer { lexer := &Lexer{ src: src, pos: 0, line: 1, column: 1, Context: nil, } return lexer } // SourceContext is a simple instance of a token.Context which // contains the name of the source file. type SourceContext struct { Filepath string } func (s *SourceContext) Source() string { return s.Filepath } func NewLexerFile(fpath string) (*Lexer, error) { src, err := os.ReadFile(fpath) if err != nil { return nil, err } lexer := NewLexer(src) lexer.Context = &SourceContext{Filepath: fpath} return lexer, nil } func (l *Lexer) Scan() (tok *token.Token) { tok = &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 tok.Pos.Context = l.Context 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 tok.Pos.Context = l.Context 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: . */ golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/lexer_test.go000066400000000000000000000034751450372207100266510ustar00rootroot00000000000000// 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_test import ( "archive/zip" "bytes" "os" "testing" "gonum.org/v1/gonum/graph/formats/dot" ) func TestParseFile(t *testing.T) { golden := []struct { in string out string }{ { in: "testdata/tokens.dot", out: "testdata/tokens.golden", }, } for _, g := range golden { file, err := dot.ParseFile(g.in) if err != nil { t.Errorf("%q: unable to parse file; %v", g.in, err) continue } // If no output path is specified, the input is already golden. out := g.in if len(g.out) > 0 { out = g.out } buf, err := os.ReadFile(out) if err != nil { t.Errorf("%q: unable to read file; %v", g.in, err) continue } got := file.String() // Remove trailing newline. want := string(bytes.TrimSpace(buf)) if got != want { t.Errorf("%q: graph mismatch; expected %q, got %q", g.in, want, got) } } } func TestParseFuzz(t *testing.T) { r, err := zip.OpenReader("../../fuzz/corpus.zip") if err != nil { if os.IsNotExist(err) { t.Skip("no corpus") } t.Fatalf("failed to open corpus: %v", err) } defer r.Close() for _, f := range r.File { rc, err := f.Open() if err != nil { t.Fatalf("failed to open %q: %v", f.Name, err) } func() { defer func() { p := recover() if p != nil { t.Errorf("unexpected panic parsing %q: %v", f.Name, p) } }() _, err = dot.Parse(rc) if err != nil { t.Errorf("unexpected error parsing %q: %v", f.Name, err) } }() rc.Close() } } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/testdata/000077500000000000000000000000001450372207100257445ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/testdata/tokens.dot000066400000000000000000000007031450372207100277570ustar00rootroot00000000000000# C preprocessing directives act as comments. /* block comment */ // keywords are case-insensitive. graph { node [] Node [] NODE [] edge [] Edge [] EDGE [] subgraph {} subGraph {} Subgraph {} SubGraph {} SUBGRAPH S {} A; B [style=filled, fillcolor=red] C:nw -- D:se "foo" .10 -20 3.14 F [label=<

foo
>] H [label=<
>] _foo a10 } Graph { } GRAPH { } digraph { } Digraph { } diGraph { } DiGraph { } DIGRAPH { } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/testdata/tokens.golden000066400000000000000000000004721450372207100304440ustar00rootroot00000000000000graph { node [] node [] node [] edge [] edge [] edge [] {} {} {} {} subgraph S {} A B [style=filled fillcolor=red] C:nw -- D:se "foo" .10 -20 3.14 F [label=<
foo
>] H [label=<
>] _foo a10 } graph { } graph { } digraph { } digraph { } digraph { } digraph { } digraph { } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/lexer/transitiontable.go000066400000000000000000001702031450372207100276670ustar00rootroot00000000000000// 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 /* Let s be the current state Let r be the current input rune transitionTable[s](r) returns the next state. */ type TransitionTable [NumStates]func(rune) int var TransTab = TransitionTable{ // S0 func(r rune) int { switch { case r == 9: // ['\t','\t'] return 1 case r == 10: // ['\n','\n'] return 1 case r == 13: // ['\r','\r'] return 1 case r == 32: // [' ',' '] return 1 case r == 34: // ['"','"'] return 2 case r == 35: // ['#','#'] return 3 case r == 44: // [',',','] return 4 case r == 45: // ['-','-'] return 5 case r == 46: // ['.','.'] return 6 case r == 47: // ['/','/'] return 7 case 48 <= r && r <= 57: // ['0','9'] return 8 case r == 58: // [':',':'] return 9 case r == 59: // [';',';'] return 10 case r == 60: // ['<','<'] return 11 case r == 61: // ['=','='] return 12 case 65 <= r && r <= 67: // ['A','C'] return 13 case r == 68: // ['D','D'] return 14 case r == 69: // ['E','E'] return 15 case r == 70: // ['F','F'] return 13 case r == 71: // ['G','G'] return 16 case 72 <= r && r <= 77: // ['H','M'] return 13 case r == 78: // ['N','N'] return 17 case 79 <= r && r <= 82: // ['O','R'] return 13 case r == 83: // ['S','S'] return 18 case 84 <= r && r <= 90: // ['T','Z'] return 13 case r == 91: // ['[','['] return 19 case r == 93: // [']',']'] return 20 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 99: // ['a','c'] return 13 case r == 100: // ['d','d'] return 22 case r == 101: // ['e','e'] return 23 case r == 102: // ['f','f'] return 13 case r == 103: // ['g','g'] return 24 case 104 <= r && r <= 109: // ['h','m'] return 13 case r == 110: // ['n','n'] return 25 case 111 <= r && r <= 114: // ['o','r'] return 13 case r == 115: // ['s','s'] return 26 case 116 <= r && r <= 122: // ['t','z'] return 13 case r == 123: // ['{','{'] return 27 case r == 125: // ['}','}'] return 28 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S1 func(r rune) int { switch { } return NoState }, // S2 func(r rune) int { switch { case 1 <= r && r <= 33: // [\u0001,'!'] return 30 case r == 34: // ['"','"'] return 31 case 35 <= r && r <= 91: // ['#','['] return 30 case r == 92: // ['\','\'] return 32 case 93 <= r && r <= 127: // [']',\u007f] return 30 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 33 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 33 } return NoState }, // S3 func(r rune) int { switch { case r == 10: // ['\n','\n'] return 34 default: return 3 } }, // S4 func(r rune) int { switch { } return NoState }, // S5 func(r rune) int { switch { case r == 45: // ['-','-'] return 35 case r == 46: // ['.','.'] return 6 case 48 <= r && r <= 57: // ['0','9'] return 8 case r == 62: // ['>','>'] return 36 } return NoState }, // S6 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 37 } return NoState }, // S7 func(r rune) int { switch { case r == 42: // ['*','*'] return 38 case r == 47: // ['/','/'] return 39 } return NoState }, // S8 func(r rune) int { switch { case r == 46: // ['.','.'] return 40 case 48 <= r && r <= 57: // ['0','9'] return 8 } return NoState }, // S9 func(r rune) int { switch { } return NoState }, // S10 func(r rune) int { switch { } return NoState }, // S11 func(r rune) int { switch { case 1 <= r && r <= 59: // [\u0001,';'] return 41 case r == 60: // ['<','<'] return 42 case r == 61: // ['=','='] return 41 case r == 62: // ['>','>'] return 43 case 63 <= r && r <= 127: // ['?',\u007f] return 41 case 128 <= r && r <= 255: // [\u0080,\u00ff] return 44 case 256 <= r && r <= 65532: // [\u0100,\ufffc] return 44 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 44 } return NoState }, // S12 func(r rune) int { switch { } return NoState }, // S13 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S14 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 72: // ['A','H'] return 13 case r == 73: // ['I','I'] return 46 case 74 <= r && r <= 90: // ['J','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 104: // ['a','h'] return 13 case r == 105: // ['i','i'] return 47 case 106 <= r && r <= 122: // ['j','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S15 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 67: // ['A','C'] return 13 case r == 68: // ['D','D'] return 48 case 69 <= r && r <= 90: // ['E','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 99: // ['a','c'] return 13 case r == 100: // ['d','d'] return 49 case 101 <= r && r <= 122: // ['e','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S16 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 81: // ['A','Q'] return 13 case r == 82: // ['R','R'] return 50 case 83 <= r && r <= 90: // ['S','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 51 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S17 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 78: // ['A','N'] return 13 case r == 79: // ['O','O'] return 52 case 80 <= r && r <= 90: // ['P','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 110: // ['a','n'] return 13 case r == 111: // ['o','o'] return 53 case 112 <= r && r <= 122: // ['p','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S18 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 83: // ['A','S'] return 13 case r == 84: // ['T','T'] return 54 case r == 85: // ['U','U'] return 55 case 86 <= r && r <= 90: // ['V','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 115: // ['a','s'] return 13 case r == 116: // ['t','t'] return 56 case r == 117: // ['u','u'] return 57 case 118 <= r && r <= 122: // ['v','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S19 func(r rune) int { switch { } return NoState }, // S20 func(r rune) int { switch { } return NoState }, // S21 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S22 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 104: // ['a','h'] return 13 case r == 105: // ['i','i'] return 58 case 106 <= r && r <= 122: // ['j','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S23 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 99: // ['a','c'] return 13 case r == 100: // ['d','d'] return 59 case 101 <= r && r <= 122: // ['e','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S24 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 60 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S25 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 110: // ['a','n'] return 13 case r == 111: // ['o','o'] return 61 case 112 <= r && r <= 122: // ['p','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S26 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 115: // ['a','s'] return 13 case r == 116: // ['t','t'] return 62 case r == 117: // ['u','u'] return 63 case 118 <= r && r <= 122: // ['v','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S27 func(r rune) int { switch { } return NoState }, // S28 func(r rune) int { switch { } return NoState }, // S29 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S30 func(r rune) int { switch { case 1 <= r && r <= 33: // [\u0001,'!'] return 30 case r == 34: // ['"','"'] return 31 case 35 <= r && r <= 91: // ['#','['] return 30 case r == 92: // ['\','\'] return 32 case 93 <= r && r <= 127: // [']',\u007f] return 30 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 33 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 33 } return NoState }, // S31 func(r rune) int { switch { } return NoState }, // S32 func(r rune) int { switch { case 1 <= r && r <= 33: // [\u0001,'!'] return 64 case r == 34: // ['"','"'] return 65 case 35 <= r && r <= 91: // ['#','['] return 64 case r == 92: // ['\','\'] return 65 case 93 <= r && r <= 127: // [']',\u007f] return 64 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 66 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 66 } return NoState }, // S33 func(r rune) int { switch { case 1 <= r && r <= 33: // [\u0001,'!'] return 30 case r == 34: // ['"','"'] return 31 case 35 <= r && r <= 91: // ['#','['] return 30 case r == 92: // ['\','\'] return 32 case 93 <= r && r <= 127: // [']',\u007f] return 30 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 33 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 33 } return NoState }, // S34 func(r rune) int { switch { } return NoState }, // S35 func(r rune) int { switch { } return NoState }, // S36 func(r rune) int { switch { } return NoState }, // S37 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 37 } return NoState }, // S38 func(r rune) int { switch { case r == 42: // ['*','*'] return 67 default: return 38 } }, // S39 func(r rune) int { switch { case r == 10: // ['\n','\n'] return 34 default: return 39 } }, // S40 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 68 } return NoState }, // S41 func(r rune) int { switch { case 1 <= r && r <= 59: // [\u0001,';'] return 41 case r == 60: // ['<','<'] return 42 case r == 61: // ['=','='] return 41 case r == 62: // ['>','>'] return 43 case 63 <= r && r <= 127: // ['?',\u007f] return 41 case 128 <= r && r <= 255: // [\u0080,\u00ff] return 44 case 256 <= r && r <= 65532: // [\u0100,\ufffc] return 44 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 44 } return NoState }, // S42 func(r rune) int { switch { case 1 <= r && r <= 59: // [\u0001,';'] return 69 case r == 61: // ['=','='] return 69 case 63 <= r && r <= 127: // ['?',\u007f] return 69 case 128 <= r && r <= 255: // [\u0080,\u00ff] return 70 case 256 <= r && r <= 65532: // [\u0100,\ufffc] return 70 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 70 } return NoState }, // S43 func(r rune) int { switch { } return NoState }, // S44 func(r rune) int { switch { case 1 <= r && r <= 59: // [\u0001,';'] return 41 case r == 60: // ['<','<'] return 42 case r == 61: // ['=','='] return 41 case r == 62: // ['>','>'] return 43 case 63 <= r && r <= 127: // ['?',\u007f] return 41 case 128 <= r && r <= 255: // [\u0080,\u00ff] return 44 case 256 <= r && r <= 65532: // [\u0100,\ufffc] return 44 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 44 } return NoState }, // S45 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S46 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 70: // ['A','F'] return 13 case r == 71: // ['G','G'] return 71 case 72 <= r && r <= 90: // ['H','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S47 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 70: // ['A','F'] return 13 case r == 71: // ['G','G'] return 72 case 72 <= r && r <= 90: // ['H','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 102: // ['a','f'] return 13 case r == 103: // ['g','g'] return 73 case 104 <= r && r <= 122: // ['h','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S48 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 70: // ['A','F'] return 13 case r == 71: // ['G','G'] return 74 case 72 <= r && r <= 90: // ['H','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S49 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 102: // ['a','f'] return 13 case r == 103: // ['g','g'] return 75 case 104 <= r && r <= 122: // ['h','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S50 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case r == 65: // ['A','A'] return 76 case 66 <= r && r <= 90: // ['B','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S51 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 77 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S52 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 67: // ['A','C'] return 13 case r == 68: // ['D','D'] return 78 case 69 <= r && r <= 90: // ['E','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S53 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 99: // ['a','c'] return 13 case r == 100: // ['d','d'] return 79 case 101 <= r && r <= 122: // ['e','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S54 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 81: // ['A','Q'] return 13 case r == 82: // ['R','R'] return 80 case 83 <= r && r <= 90: // ['S','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S55 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case r == 65: // ['A','A'] return 13 case r == 66: // ['B','B'] return 81 case 67 <= r && r <= 90: // ['C','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S56 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 82 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S57 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 13 case r == 98: // ['b','b'] return 83 case 99 <= r && r <= 122: // ['c','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S58 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 70: // ['A','F'] return 13 case r == 71: // ['G','G'] return 84 case 72 <= r && r <= 90: // ['H','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 102: // ['a','f'] return 13 case r == 103: // ['g','g'] return 85 case 104 <= r && r <= 122: // ['h','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S59 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 102: // ['a','f'] return 13 case r == 103: // ['g','g'] return 86 case 104 <= r && r <= 122: // ['h','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S60 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 87 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S61 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 99: // ['a','c'] return 13 case r == 100: // ['d','d'] return 88 case 101 <= r && r <= 122: // ['e','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S62 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 89 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S63 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 13 case r == 98: // ['b','b'] return 90 case 99 <= r && r <= 122: // ['c','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S64 func(r rune) int { switch { case 1 <= r && r <= 33: // [\u0001,'!'] return 30 case r == 34: // ['"','"'] return 31 case 35 <= r && r <= 91: // ['#','['] return 30 case r == 92: // ['\','\'] return 32 case 93 <= r && r <= 127: // [']',\u007f] return 30 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 33 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 33 } return NoState }, // S65 func(r rune) int { switch { case 1 <= r && r <= 33: // [\u0001,'!'] return 30 case r == 34: // ['"','"'] return 31 case 35 <= r && r <= 91: // ['#','['] return 30 case r == 92: // ['\','\'] return 32 case 93 <= r && r <= 127: // [']',\u007f] return 30 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 33 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 33 } return NoState }, // S66 func(r rune) int { switch { case 1 <= r && r <= 33: // [\u0001,'!'] return 30 case r == 34: // ['"','"'] return 31 case 35 <= r && r <= 91: // ['#','['] return 30 case r == 92: // ['\','\'] return 32 case 93 <= r && r <= 127: // [']',\u007f] return 30 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 33 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 33 } return NoState }, // S67 func(r rune) int { switch { case r == 42: // ['*','*'] return 67 case r == 47: // ['/','/'] return 91 default: return 38 } }, // S68 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 68 } return NoState }, // S69 func(r rune) int { switch { case 1 <= r && r <= 59: // [\u0001,';'] return 69 case r == 61: // ['=','='] return 69 case r == 62: // ['>','>'] return 92 case 63 <= r && r <= 127: // ['?',\u007f] return 69 case 128 <= r && r <= 255: // [\u0080,\u00ff] return 70 case 256 <= r && r <= 65532: // [\u0100,\ufffc] return 70 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 70 } return NoState }, // S70 func(r rune) int { switch { case 1 <= r && r <= 59: // [\u0001,';'] return 69 case r == 61: // ['=','='] return 69 case r == 62: // ['>','>'] return 92 case 63 <= r && r <= 127: // ['?',\u007f] return 69 case 128 <= r && r <= 255: // [\u0080,\u00ff] return 70 case 256 <= r && r <= 65532: // [\u0100,\ufffc] return 70 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 70 } return NoState }, // S71 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 81: // ['A','Q'] return 13 case r == 82: // ['R','R'] return 93 case 83 <= r && r <= 90: // ['S','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S72 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 94 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S73 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 95 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S74 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 68: // ['A','D'] return 13 case r == 69: // ['E','E'] return 96 case 70 <= r && r <= 90: // ['F','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S75 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 100: // ['a','d'] return 13 case r == 101: // ['e','e'] return 96 case 102 <= r && r <= 122: // ['f','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S76 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 79: // ['A','O'] return 13 case r == 80: // ['P','P'] return 97 case 81 <= r && r <= 90: // ['Q','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S77 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 98 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S78 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 68: // ['A','D'] return 13 case r == 69: // ['E','E'] return 99 case 70 <= r && r <= 90: // ['F','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S79 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 100: // ['a','d'] return 13 case r == 101: // ['e','e'] return 99 case 102 <= r && r <= 122: // ['f','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S80 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 72: // ['A','H'] return 13 case r == 73: // ['I','I'] return 100 case 74 <= r && r <= 90: // ['J','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S81 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 70: // ['A','F'] return 13 case r == 71: // ['G','G'] return 101 case 72 <= r && r <= 90: // ['H','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S82 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 104: // ['a','h'] return 13 case r == 105: // ['i','i'] return 102 case 106 <= r && r <= 122: // ['j','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S83 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 70: // ['A','F'] return 13 case r == 71: // ['G','G'] return 103 case 72 <= r && r <= 90: // ['H','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 102: // ['a','f'] return 13 case r == 103: // ['g','g'] return 104 case 104 <= r && r <= 122: // ['h','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S84 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 105 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S85 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 106 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S86 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 100: // ['a','d'] return 13 case r == 101: // ['e','e'] return 96 case 102 <= r && r <= 122: // ['f','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S87 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 107 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S88 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 100: // ['a','d'] return 13 case r == 101: // ['e','e'] return 99 case 102 <= r && r <= 122: // ['f','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S89 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 104: // ['a','h'] return 13 case r == 105: // ['i','i'] return 108 case 106 <= r && r <= 122: // ['j','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S90 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 70: // ['A','F'] return 13 case r == 71: // ['G','G'] return 109 case 72 <= r && r <= 90: // ['H','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 102: // ['a','f'] return 13 case r == 103: // ['g','g'] return 110 case 104 <= r && r <= 122: // ['h','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S91 func(r rune) int { switch { } return NoState }, // S92 func(r rune) int { switch { case 1 <= r && r <= 59: // [\u0001,';'] return 41 case r == 60: // ['<','<'] return 42 case r == 61: // ['=','='] return 41 case r == 62: // ['>','>'] return 43 case 63 <= r && r <= 127: // ['?',\u007f] return 41 case 128 <= r && r <= 255: // [\u0080,\u00ff] return 44 case 256 <= r && r <= 65532: // [\u0100,\ufffc] return 44 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 44 } return NoState }, // S93 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case r == 65: // ['A','A'] return 111 case 66 <= r && r <= 90: // ['B','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S94 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 112 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S95 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 113 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S96 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S97 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 71: // ['A','G'] return 13 case r == 72: // ['H','H'] return 114 case 73 <= r && r <= 90: // ['I','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S98 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 114 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S99 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S100 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 66: // ['A','B'] return 13 case r == 67: // ['C','C'] return 115 case 68 <= r && r <= 90: // ['D','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S101 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 81: // ['A','Q'] return 13 case r == 82: // ['R','R'] return 116 case 83 <= r && r <= 90: // ['S','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S102 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 98: // ['a','b'] return 13 case r == 99: // ['c','c'] return 117 case 100 <= r && r <= 122: // ['d','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S103 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 118 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S104 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 119 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S105 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 120 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S106 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 121 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S107 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 114 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S108 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 98: // ['a','b'] return 13 case r == 99: // ['c','c'] return 122 case 100 <= r && r <= 122: // ['d','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S109 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 123 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S110 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 113: // ['a','q'] return 13 case r == 114: // ['r','r'] return 124 case 115 <= r && r <= 122: // ['s','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S111 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 79: // ['A','O'] return 13 case r == 80: // ['P','P'] return 125 case 81 <= r && r <= 90: // ['Q','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S112 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 126 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S113 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 127 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S114 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S115 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 83: // ['A','S'] return 13 case r == 84: // ['T','T'] return 128 case 85 <= r && r <= 90: // ['U','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S116 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case r == 65: // ['A','A'] return 129 case 66 <= r && r <= 90: // ['B','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S117 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 115: // ['a','s'] return 13 case r == 116: // ['t','t'] return 128 case 117 <= r && r <= 122: // ['u','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S118 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 130 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S119 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 131 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S120 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 132 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S121 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 133 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S122 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 115: // ['a','s'] return 13 case r == 116: // ['t','t'] return 128 case 117 <= r && r <= 122: // ['u','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S123 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 134 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S124 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case r == 97: // ['a','a'] return 135 case 98 <= r && r <= 122: // ['b','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S125 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 71: // ['A','G'] return 13 case r == 72: // ['H','H'] return 136 case 73 <= r && r <= 90: // ['I','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S126 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 136 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S127 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 136 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S128 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S129 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 79: // ['A','O'] return 13 case r == 80: // ['P','P'] return 137 case 81 <= r && r <= 90: // ['Q','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S130 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 138 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S131 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 139 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S132 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 136 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S133 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 136 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S134 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 140 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S135 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 111: // ['a','o'] return 13 case r == 112: // ['p','p'] return 141 case 113 <= r && r <= 122: // ['q','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S136 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S137 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 71: // ['A','G'] return 13 case r == 72: // ['H','H'] return 142 case 73 <= r && r <= 90: // ['I','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S138 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 142 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S139 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 142 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S140 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 142 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S141 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 103: // ['a','g'] return 13 case r == 104: // ['h','h'] return 142 case 105 <= r && r <= 122: // ['i','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, // S142 func(r rune) int { switch { case 48 <= r && r <= 57: // ['0','9'] return 45 case 65 <= r && r <= 90: // ['A','Z'] return 13 case r == 95: // ['_','_'] return 21 case 97 <= r && r <= 122: // ['a','z'] return 13 case 128 <= r && r <= 65532: // [\u0080,\ufffc] return 29 case 65534 <= r && r <= 1114111: // [\ufffe,\U0010ffff] return 29 } return NoState }, } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/000077500000000000000000000000001450372207100243105ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/action.go000066400000000000000000000024211450372207100261130ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/actiontable.go000066400000000000000000001457461450372207100271450ustar00rootroot00000000000000// 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 type ( actionTable [numStates]actionRow actionRow struct { canRecover bool actions [numSymbols]action } ) var actionTab = actionTable{ actionRow{ // S0 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty shift(4), // strict reduce(4), // graphx, reduce: OptStrict reduce(4), // digraph, reduce: OptStrict nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S1 canRecover: false, actions: [numSymbols]action{ nil, // INVALID accept(true), // ␚ nil, // { nil, // } nil, // empty shift(4), // strict reduce(4), // graphx, reduce: OptStrict reduce(4), // digraph, reduce: OptStrict nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S2 canRecover: false, actions: [numSymbols]action{ nil, // INVALID reduce(1), // ␚, reduce: File nil, // { nil, // } nil, // empty reduce(1), // strict, reduce: File reduce(1), // graphx, reduce: File reduce(1), // digraph, reduce: File nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S3 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict shift(7), // graphx shift(8), // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S4 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict reduce(5), // graphx, reduce: OptStrict reduce(5), // digraph, reduce: OptStrict nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S5 canRecover: false, actions: [numSymbols]action{ nil, // INVALID reduce(2), // ␚, reduce: File nil, // { nil, // } nil, // empty reduce(2), // strict, reduce: File reduce(2), // graphx, reduce: File reduce(2), // digraph, reduce: File nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S6 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(53), // {, reduce: OptID nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : shift(11), // id }, }, actionRow{ // S7 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(6), // {, reduce: DirectedGraph nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : reduce(6), // id, reduce: DirectedGraph }, }, actionRow{ // S8 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(7), // {, reduce: DirectedGraph nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : reduce(7), // id, reduce: DirectedGraph }, }, actionRow{ // S9 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ shift(12), // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S10 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(54), // {, reduce: OptID nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S11 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(52), // {, reduce: ID nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S12 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(43), // {, reduce: OptSubgraphID reduce(10), // }, reduce: OptStmtList nil, // empty nil, // strict shift(14), // graphx nil, // digraph nil, // ; nil, // -- nil, // -> shift(25), // node shift(26), // edge nil, // [ nil, // ] nil, // , nil, // = shift(29), // subgraph nil, // : shift(30), // id }, }, actionRow{ // S13 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { shift(31), // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S14 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge reduce(27), // [, reduce: Component nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S15 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(43), // {, reduce: OptSubgraphID reduce(11), // }, reduce: OptStmtList nil, // empty nil, // strict shift(14), // graphx nil, // digraph nil, // ; nil, // -- nil, // -> shift(25), // node shift(26), // edge nil, // [ nil, // ] nil, // , nil, // = shift(29), // subgraph nil, // : shift(30), // id }, }, actionRow{ // S16 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(17), // {, reduce: OptSemi reduce(17), // }, reduce: OptSemi nil, // empty nil, // strict reduce(17), // graphx, reduce: OptSemi nil, // digraph shift(34), // ; nil, // -- nil, // -> reduce(17), // node, reduce: OptSemi reduce(17), // edge, reduce: OptSemi nil, // [ nil, // ] nil, // , nil, // = reduce(17), // subgraph, reduce: OptSemi nil, // : reduce(17), // id, reduce: OptSemi }, }, actionRow{ // S17 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(12), // {, reduce: Stmt reduce(12), // }, reduce: Stmt nil, // empty nil, // strict reduce(12), // graphx, reduce: Stmt nil, // digraph reduce(12), // ;, reduce: Stmt nil, // -- nil, // -> reduce(12), // node, reduce: Stmt reduce(12), // edge, reduce: Stmt nil, // [ nil, // ] nil, // , nil, // = reduce(12), // subgraph, reduce: Stmt nil, // : reduce(12), // id, reduce: Stmt }, }, actionRow{ // S18 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(13), // {, reduce: Stmt reduce(13), // }, reduce: Stmt nil, // empty nil, // strict reduce(13), // graphx, reduce: Stmt nil, // digraph reduce(13), // ;, reduce: Stmt nil, // -- nil, // -> reduce(13), // node, reduce: Stmt reduce(13), // edge, reduce: Stmt nil, // [ nil, // ] nil, // , nil, // = reduce(13), // subgraph, reduce: Stmt nil, // : reduce(13), // id, reduce: Stmt }, }, actionRow{ // S19 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(14), // {, reduce: Stmt reduce(14), // }, reduce: Stmt nil, // empty nil, // strict reduce(14), // graphx, reduce: Stmt nil, // digraph reduce(14), // ;, reduce: Stmt nil, // -- nil, // -> reduce(14), // node, reduce: Stmt reduce(14), // edge, reduce: Stmt nil, // [ nil, // ] nil, // , nil, // = reduce(14), // subgraph, reduce: Stmt nil, // : reduce(14), // id, reduce: Stmt }, }, actionRow{ // S20 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(15), // {, reduce: Stmt reduce(15), // }, reduce: Stmt nil, // empty nil, // strict reduce(15), // graphx, reduce: Stmt nil, // digraph reduce(15), // ;, reduce: Stmt nil, // -- nil, // -> reduce(15), // node, reduce: Stmt reduce(15), // edge, reduce: Stmt nil, // [ nil, // ] nil, // , nil, // = reduce(15), // subgraph, reduce: Stmt nil, // : reduce(15), // id, reduce: Stmt }, }, actionRow{ // S21 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(16), // {, reduce: Stmt reduce(16), // }, reduce: Stmt nil, // empty nil, // strict reduce(16), // graphx, reduce: Stmt nil, // digraph reduce(16), // ;, reduce: Stmt reduce(46), // --, reduce: Vertex reduce(46), // ->, reduce: Vertex reduce(16), // node, reduce: Stmt reduce(16), // edge, reduce: Stmt nil, // [ nil, // ] nil, // , nil, // = reduce(16), // subgraph, reduce: Stmt nil, // : reduce(16), // id, reduce: Stmt }, }, actionRow{ // S22 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(32), // {, reduce: OptAttrList reduce(32), // }, reduce: OptAttrList nil, // empty nil, // strict reduce(32), // graphx, reduce: OptAttrList nil, // digraph reduce(32), // ;, reduce: OptAttrList reduce(45), // --, reduce: Vertex reduce(45), // ->, reduce: Vertex reduce(32), // node, reduce: OptAttrList reduce(32), // edge, reduce: OptAttrList shift(37), // [ nil, // ] nil, // , nil, // = reduce(32), // subgraph, reduce: OptAttrList nil, // : reduce(32), // id, reduce: OptAttrList }, }, actionRow{ // S23 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; shift(40), // -- shift(41), // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S24 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge shift(37), // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S25 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge reduce(28), // [, reduce: Component nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S26 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge reduce(29), // [, reduce: Component nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S27 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(50), // {, reduce: OptPort reduce(50), // }, reduce: OptPort nil, // empty nil, // strict reduce(50), // graphx, reduce: OptPort nil, // digraph reduce(50), // ;, reduce: OptPort reduce(50), // --, reduce: OptPort reduce(50), // ->, reduce: OptPort reduce(50), // node, reduce: OptPort reduce(50), // edge, reduce: OptPort reduce(50), // [, reduce: OptPort nil, // ] nil, // , shift(43), // = reduce(50), // subgraph, reduce: OptPort shift(46), // : reduce(50), // id, reduce: OptPort }, }, actionRow{ // S28 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ shift(47), // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S29 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(53), // {, reduce: OptID nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : shift(11), // id }, }, actionRow{ // S30 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(52), // {, reduce: ID reduce(52), // }, reduce: ID nil, // empty nil, // strict reduce(52), // graphx, reduce: ID nil, // digraph reduce(52), // ;, reduce: ID reduce(52), // --, reduce: ID reduce(52), // ->, reduce: ID reduce(52), // node, reduce: ID reduce(52), // edge, reduce: ID reduce(52), // [, reduce: ID nil, // ] nil, // , reduce(52), // =, reduce: ID reduce(52), // subgraph, reduce: ID reduce(52), // :, reduce: ID reduce(52), // id, reduce: ID }, }, actionRow{ // S31 canRecover: false, actions: [numSymbols]action{ nil, // INVALID reduce(3), // ␚, reduce: Graph nil, // { nil, // } nil, // empty reduce(3), // strict, reduce: Graph reduce(3), // graphx, reduce: Graph reduce(3), // digraph, reduce: Graph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S32 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(17), // {, reduce: OptSemi reduce(17), // }, reduce: OptSemi nil, // empty nil, // strict reduce(17), // graphx, reduce: OptSemi nil, // digraph shift(34), // ; nil, // -- nil, // -> reduce(17), // node, reduce: OptSemi reduce(17), // edge, reduce: OptSemi nil, // [ nil, // ] nil, // , nil, // = reduce(17), // subgraph, reduce: OptSemi nil, // : reduce(17), // id, reduce: OptSemi }, }, actionRow{ // S33 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(8), // {, reduce: StmtList reduce(8), // }, reduce: StmtList nil, // empty nil, // strict reduce(8), // graphx, reduce: StmtList nil, // digraph nil, // ; nil, // -- nil, // -> reduce(8), // node, reduce: StmtList reduce(8), // edge, reduce: StmtList nil, // [ nil, // ] nil, // , nil, // = reduce(8), // subgraph, reduce: StmtList nil, // : reduce(8), // id, reduce: StmtList }, }, actionRow{ // S34 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(18), // {, reduce: OptSemi reduce(18), // }, reduce: OptSemi nil, // empty nil, // strict reduce(18), // graphx, reduce: OptSemi nil, // digraph nil, // ; nil, // -- nil, // -> reduce(18), // node, reduce: OptSemi reduce(18), // edge, reduce: OptSemi nil, // [ nil, // ] nil, // , nil, // = reduce(18), // subgraph, reduce: OptSemi nil, // : reduce(18), // id, reduce: OptSemi }, }, actionRow{ // S35 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(19), // {, reduce: NodeStmt reduce(19), // }, reduce: NodeStmt nil, // empty nil, // strict reduce(19), // graphx, reduce: NodeStmt nil, // digraph reduce(19), // ;, reduce: NodeStmt nil, // -- nil, // -> reduce(19), // node, reduce: NodeStmt reduce(19), // edge, reduce: NodeStmt nil, // [ nil, // ] nil, // , nil, // = reduce(19), // subgraph, reduce: NodeStmt nil, // : reduce(19), // id, reduce: NodeStmt }, }, actionRow{ // S36 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(33), // {, reduce: OptAttrList reduce(33), // }, reduce: OptAttrList nil, // empty nil, // strict reduce(33), // graphx, reduce: OptAttrList nil, // digraph reduce(33), // ;, reduce: OptAttrList nil, // -- nil, // -> reduce(33), // node, reduce: OptAttrList reduce(33), // edge, reduce: OptAttrList shift(50), // [ nil, // ] nil, // , nil, // = reduce(33), // subgraph, reduce: OptAttrList nil, // : reduce(33), // id, reduce: OptAttrList }, }, actionRow{ // S37 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(36), // ], reduce: OptAList nil, // , nil, // = nil, // subgraph nil, // : shift(55), // id }, }, actionRow{ // S38 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(32), // {, reduce: OptAttrList reduce(32), // }, reduce: OptAttrList nil, // empty nil, // strict reduce(32), // graphx, reduce: OptAttrList nil, // digraph reduce(32), // ;, reduce: OptAttrList nil, // -- nil, // -> reduce(32), // node, reduce: OptAttrList reduce(32), // edge, reduce: OptAttrList shift(37), // [ nil, // ] nil, // , nil, // = reduce(32), // subgraph, reduce: OptAttrList nil, // : reduce(32), // id, reduce: OptAttrList }, }, actionRow{ // S39 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(43), // {, reduce: OptSubgraphID nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = shift(29), // subgraph nil, // : shift(62), // id }, }, actionRow{ // S40 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(22), // {, reduce: DirectedEdge nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = reduce(22), // subgraph, reduce: DirectedEdge nil, // : reduce(22), // id, reduce: DirectedEdge }, }, actionRow{ // S41 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(23), // {, reduce: DirectedEdge nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = reduce(23), // subgraph, reduce: DirectedEdge nil, // : reduce(23), // id, reduce: DirectedEdge }, }, actionRow{ // S42 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(26), // {, reduce: AttrStmt reduce(26), // }, reduce: AttrStmt nil, // empty nil, // strict reduce(26), // graphx, reduce: AttrStmt nil, // digraph reduce(26), // ;, reduce: AttrStmt nil, // -- nil, // -> reduce(26), // node, reduce: AttrStmt reduce(26), // edge, reduce: AttrStmt shift(50), // [ nil, // ] nil, // , nil, // = reduce(26), // subgraph, reduce: AttrStmt nil, // : reduce(26), // id, reduce: AttrStmt }, }, actionRow{ // S43 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : shift(64), // id }, }, actionRow{ // S44 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(47), // {, reduce: Node reduce(47), // }, reduce: Node nil, // empty nil, // strict reduce(47), // graphx, reduce: Node nil, // digraph reduce(47), // ;, reduce: Node reduce(47), // --, reduce: Node reduce(47), // ->, reduce: Node reduce(47), // node, reduce: Node reduce(47), // edge, reduce: Node reduce(47), // [, reduce: Node nil, // ] nil, // , nil, // = reduce(47), // subgraph, reduce: Node nil, // : reduce(47), // id, reduce: Node }, }, actionRow{ // S45 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(51), // {, reduce: OptPort reduce(51), // }, reduce: OptPort nil, // empty nil, // strict reduce(51), // graphx, reduce: OptPort nil, // digraph reduce(51), // ;, reduce: OptPort reduce(51), // --, reduce: OptPort reduce(51), // ->, reduce: OptPort reduce(51), // node, reduce: OptPort reduce(51), // edge, reduce: OptPort reduce(51), // [, reduce: OptPort nil, // ] nil, // , nil, // = reduce(51), // subgraph, reduce: OptPort nil, // : reduce(51), // id, reduce: OptPort }, }, actionRow{ // S46 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : shift(62), // id }, }, actionRow{ // S47 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(43), // {, reduce: OptSubgraphID reduce(10), // }, reduce: OptStmtList nil, // empty nil, // strict shift(14), // graphx nil, // digraph nil, // ; nil, // -- nil, // -> shift(25), // node shift(26), // edge nil, // [ nil, // ] nil, // , nil, // = shift(29), // subgraph nil, // : shift(30), // id }, }, actionRow{ // S48 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(44), // {, reduce: OptSubgraphID nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S49 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(9), // {, reduce: StmtList reduce(9), // }, reduce: StmtList nil, // empty nil, // strict reduce(9), // graphx, reduce: StmtList nil, // digraph nil, // ; nil, // -- nil, // -> reduce(9), // node, reduce: StmtList reduce(9), // edge, reduce: StmtList nil, // [ nil, // ] nil, // , nil, // = reduce(9), // subgraph, reduce: StmtList nil, // : reduce(9), // id, reduce: StmtList }, }, actionRow{ // S50 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(36), // ], reduce: OptAList nil, // , nil, // = nil, // subgraph nil, // : shift(55), // id }, }, actionRow{ // S51 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph shift(68), // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(38), // ], reduce: OptSep shift(70), // , nil, // = nil, // subgraph nil, // : reduce(38), // id, reduce: OptSep }, }, actionRow{ // S52 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ shift(71), // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S53 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(37), // ], reduce: OptAList nil, // , nil, // = nil, // subgraph nil, // : shift(55), // id }, }, actionRow{ // S54 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , shift(73), // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S55 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , reduce(52), // =, reduce: ID nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S56 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(20), // {, reduce: EdgeStmt reduce(20), // }, reduce: EdgeStmt nil, // empty nil, // strict reduce(20), // graphx, reduce: EdgeStmt nil, // digraph reduce(20), // ;, reduce: EdgeStmt nil, // -- nil, // -> reduce(20), // node, reduce: EdgeStmt reduce(20), // edge, reduce: EdgeStmt nil, // [ nil, // ] nil, // , nil, // = reduce(20), // subgraph, reduce: EdgeStmt nil, // : reduce(20), // id, reduce: EdgeStmt }, }, actionRow{ // S57 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(46), // {, reduce: Vertex reduce(46), // }, reduce: Vertex nil, // empty nil, // strict reduce(46), // graphx, reduce: Vertex nil, // digraph reduce(46), // ;, reduce: Vertex reduce(46), // --, reduce: Vertex reduce(46), // ->, reduce: Vertex reduce(46), // node, reduce: Vertex reduce(46), // edge, reduce: Vertex reduce(46), // [, reduce: Vertex nil, // ] nil, // , nil, // = reduce(46), // subgraph, reduce: Vertex nil, // : reduce(46), // id, reduce: Vertex }, }, actionRow{ // S58 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(45), // {, reduce: Vertex reduce(45), // }, reduce: Vertex nil, // empty nil, // strict reduce(45), // graphx, reduce: Vertex nil, // digraph reduce(45), // ;, reduce: Vertex reduce(45), // --, reduce: Vertex reduce(45), // ->, reduce: Vertex reduce(45), // node, reduce: Vertex reduce(45), // edge, reduce: Vertex reduce(45), // [, reduce: Vertex nil, // ] nil, // , nil, // = reduce(45), // subgraph, reduce: Vertex nil, // : reduce(45), // id, reduce: Vertex }, }, actionRow{ // S59 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(24), // {, reduce: OptEdge reduce(24), // }, reduce: OptEdge nil, // empty nil, // strict reduce(24), // graphx, reduce: OptEdge nil, // digraph reduce(24), // ;, reduce: OptEdge shift(40), // -- shift(41), // -> reduce(24), // node, reduce: OptEdge reduce(24), // edge, reduce: OptEdge reduce(24), // [, reduce: OptEdge nil, // ] nil, // , nil, // = reduce(24), // subgraph, reduce: OptEdge nil, // : reduce(24), // id, reduce: OptEdge }, }, actionRow{ // S60 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(50), // {, reduce: OptPort reduce(50), // }, reduce: OptPort nil, // empty nil, // strict reduce(50), // graphx, reduce: OptPort nil, // digraph reduce(50), // ;, reduce: OptPort reduce(50), // --, reduce: OptPort reduce(50), // ->, reduce: OptPort reduce(50), // node, reduce: OptPort reduce(50), // edge, reduce: OptPort reduce(50), // [, reduce: OptPort nil, // ] nil, // , nil, // = reduce(50), // subgraph, reduce: OptPort shift(46), // : reduce(50), // id, reduce: OptPort }, }, actionRow{ // S61 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ shift(76), // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S62 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(52), // {, reduce: ID reduce(52), // }, reduce: ID nil, // empty nil, // strict reduce(52), // graphx, reduce: ID nil, // digraph reduce(52), // ;, reduce: ID reduce(52), // --, reduce: ID reduce(52), // ->, reduce: ID reduce(52), // node, reduce: ID reduce(52), // edge, reduce: ID reduce(52), // [, reduce: ID nil, // ] nil, // , nil, // = reduce(52), // subgraph, reduce: ID reduce(52), // :, reduce: ID reduce(52), // id, reduce: ID }, }, actionRow{ // S63 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(41), // {, reduce: Attr reduce(41), // }, reduce: Attr nil, // empty nil, // strict reduce(41), // graphx, reduce: Attr nil, // digraph reduce(41), // ;, reduce: Attr nil, // -- nil, // -> reduce(41), // node, reduce: Attr reduce(41), // edge, reduce: Attr nil, // [ nil, // ] nil, // , nil, // = reduce(41), // subgraph, reduce: Attr nil, // : reduce(41), // id, reduce: Attr }, }, actionRow{ // S64 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(52), // {, reduce: ID reduce(52), // }, reduce: ID nil, // empty nil, // strict reduce(52), // graphx, reduce: ID nil, // digraph reduce(52), // ;, reduce: ID nil, // -- nil, // -> reduce(52), // node, reduce: ID reduce(52), // edge, reduce: ID nil, // [ nil, // ] nil, // , nil, // = reduce(52), // subgraph, reduce: ID nil, // : reduce(52), // id, reduce: ID }, }, actionRow{ // S65 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(48), // {, reduce: Port reduce(48), // }, reduce: Port nil, // empty nil, // strict reduce(48), // graphx, reduce: Port nil, // digraph reduce(48), // ;, reduce: Port reduce(48), // --, reduce: Port reduce(48), // ->, reduce: Port reduce(48), // node, reduce: Port reduce(48), // edge, reduce: Port reduce(48), // [, reduce: Port nil, // ] nil, // , nil, // = reduce(48), // subgraph, reduce: Port shift(77), // : reduce(48), // id, reduce: Port }, }, actionRow{ // S66 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { shift(78), // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S67 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ shift(79), // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S68 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(39), // ], reduce: OptSep nil, // , nil, // = nil, // subgraph nil, // : reduce(39), // id, reduce: OptSep }, }, actionRow{ // S69 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(34), // ], reduce: AList nil, // , nil, // = nil, // subgraph nil, // : reduce(34), // id, reduce: AList }, }, actionRow{ // S70 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(40), // ], reduce: OptSep nil, // , nil, // = nil, // subgraph nil, // : reduce(40), // id, reduce: OptSep }, }, actionRow{ // S71 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(30), // {, reduce: AttrList reduce(30), // }, reduce: AttrList nil, // empty nil, // strict reduce(30), // graphx, reduce: AttrList nil, // digraph reduce(30), // ;, reduce: AttrList nil, // -- nil, // -> reduce(30), // node, reduce: AttrList reduce(30), // edge, reduce: AttrList reduce(30), // [, reduce: AttrList nil, // ] nil, // , nil, // = reduce(30), // subgraph, reduce: AttrList nil, // : reduce(30), // id, reduce: AttrList }, }, actionRow{ // S72 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph shift(68), // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(38), // ], reduce: OptSep shift(70), // , nil, // = nil, // subgraph nil, // : reduce(38), // id, reduce: OptSep }, }, actionRow{ // S73 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : shift(82), // id }, }, actionRow{ // S74 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(25), // {, reduce: OptEdge reduce(25), // }, reduce: OptEdge nil, // empty nil, // strict reduce(25), // graphx, reduce: OptEdge nil, // digraph reduce(25), // ;, reduce: OptEdge nil, // -- nil, // -> reduce(25), // node, reduce: OptEdge reduce(25), // edge, reduce: OptEdge reduce(25), // [, reduce: OptEdge nil, // ] nil, // , nil, // = reduce(25), // subgraph, reduce: OptEdge nil, // : reduce(25), // id, reduce: OptEdge }, }, actionRow{ // S75 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(21), // {, reduce: Edge reduce(21), // }, reduce: Edge nil, // empty nil, // strict reduce(21), // graphx, reduce: Edge nil, // digraph reduce(21), // ;, reduce: Edge nil, // -- nil, // -> reduce(21), // node, reduce: Edge reduce(21), // edge, reduce: Edge reduce(21), // [, reduce: Edge nil, // ] nil, // , nil, // = reduce(21), // subgraph, reduce: Edge nil, // : reduce(21), // id, reduce: Edge }, }, actionRow{ // S76 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(43), // {, reduce: OptSubgraphID reduce(10), // }, reduce: OptStmtList nil, // empty nil, // strict shift(14), // graphx nil, // digraph nil, // ; nil, // -- nil, // -> shift(25), // node shift(26), // edge nil, // [ nil, // ] nil, // , nil, // = shift(29), // subgraph nil, // : shift(30), // id }, }, actionRow{ // S77 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : shift(85), // id }, }, actionRow{ // S78 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(42), // {, reduce: Subgraph reduce(42), // }, reduce: Subgraph nil, // empty nil, // strict reduce(42), // graphx, reduce: Subgraph nil, // digraph reduce(42), // ;, reduce: Subgraph reduce(42), // --, reduce: Subgraph reduce(42), // ->, reduce: Subgraph reduce(42), // node, reduce: Subgraph reduce(42), // edge, reduce: Subgraph nil, // [ nil, // ] nil, // , nil, // = reduce(42), // subgraph, reduce: Subgraph nil, // : reduce(42), // id, reduce: Subgraph }, }, actionRow{ // S79 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(31), // {, reduce: AttrList reduce(31), // }, reduce: AttrList nil, // empty nil, // strict reduce(31), // graphx, reduce: AttrList nil, // digraph reduce(31), // ;, reduce: AttrList nil, // -- nil, // -> reduce(31), // node, reduce: AttrList reduce(31), // edge, reduce: AttrList reduce(31), // [, reduce: AttrList nil, // ] nil, // , nil, // = reduce(31), // subgraph, reduce: AttrList nil, // : reduce(31), // id, reduce: AttrList }, }, actionRow{ // S80 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(35), // ], reduce: AList nil, // , nil, // = nil, // subgraph nil, // : reduce(35), // id, reduce: AList }, }, actionRow{ // S81 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph reduce(41), // ;, reduce: Attr nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(41), // ], reduce: Attr reduce(41), // ,, reduce: Attr nil, // = nil, // subgraph nil, // : reduce(41), // id, reduce: Attr }, }, actionRow{ // S82 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { nil, // } nil, // empty nil, // strict nil, // graphx nil, // digraph reduce(52), // ;, reduce: ID nil, // -- nil, // -> nil, // node nil, // edge nil, // [ reduce(52), // ], reduce: ID reduce(52), // ,, reduce: ID nil, // = nil, // subgraph nil, // : reduce(52), // id, reduce: ID }, }, actionRow{ // S83 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ nil, // { shift(86), // } nil, // empty nil, // strict nil, // graphx nil, // digraph nil, // ; nil, // -- nil, // -> nil, // node nil, // edge nil, // [ nil, // ] nil, // , nil, // = nil, // subgraph nil, // : nil, // id }, }, actionRow{ // S84 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(49), // {, reduce: Port reduce(49), // }, reduce: Port nil, // empty nil, // strict reduce(49), // graphx, reduce: Port nil, // digraph reduce(49), // ;, reduce: Port reduce(49), // --, reduce: Port reduce(49), // ->, reduce: Port reduce(49), // node, reduce: Port reduce(49), // edge, reduce: Port reduce(49), // [, reduce: Port nil, // ] nil, // , nil, // = reduce(49), // subgraph, reduce: Port nil, // : reduce(49), // id, reduce: Port }, }, actionRow{ // S85 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(52), // {, reduce: ID reduce(52), // }, reduce: ID nil, // empty nil, // strict reduce(52), // graphx, reduce: ID nil, // digraph reduce(52), // ;, reduce: ID reduce(52), // --, reduce: ID reduce(52), // ->, reduce: ID reduce(52), // node, reduce: ID reduce(52), // edge, reduce: ID reduce(52), // [, reduce: ID nil, // ] nil, // , nil, // = reduce(52), // subgraph, reduce: ID nil, // : reduce(52), // id, reduce: ID }, }, actionRow{ // S86 canRecover: false, actions: [numSymbols]action{ nil, // INVALID nil, // ␚ reduce(42), // {, reduce: Subgraph reduce(42), // }, reduce: Subgraph nil, // empty nil, // strict reduce(42), // graphx, reduce: Subgraph nil, // digraph reduce(42), // ;, reduce: Subgraph reduce(42), // --, reduce: Subgraph reduce(42), // ->, reduce: Subgraph reduce(42), // node, reduce: Subgraph reduce(42), // edge, reduce: Subgraph reduce(42), // [, reduce: Subgraph nil, // ] nil, // , nil, // = reduce(42), // subgraph, reduce: Subgraph nil, // : reduce(42), // id, reduce: Subgraph }, }, } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/context.go000066400000000000000000000010601450372207100263200ustar00rootroot00000000000000// 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 // Parser-specific user-defined and entirely-optional context, // accessible as '$Context' in SDT actions. type Context interface{} golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/doc.go000066400000000000000000000005061450372207100254050ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/gototable.go000066400000000000000000001332201450372207100266200ustar00rootroot00000000000000// 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 const numNTSymbols = 30 type ( gotoTable [numStates]gotoRow gotoRow [numNTSymbols]int ) var gotoTab = gotoTable{ gotoRow{ // S0 -1, // S' 1, // File 2, // Graph 3, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S1 -1, // S' -1, // File 5, // Graph 3, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S2 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S3 -1, // S' -1, // File -1, // Graph -1, // OptStrict 6, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S4 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S5 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S6 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 10, // ID 9, // OptID }, gotoRow{ // S7 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S8 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S9 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S10 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S11 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S12 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph 15, // StmtList 13, // OptStmtList 16, // Stmt -1, // OptSemi 17, // NodeStmt 18, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge 19, // AttrStmt 24, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep 20, // Attr 21, // Subgraph 28, // OptSubgraphID 23, // Vertex 22, // Node -1, // Port -1, // OptPort 27, // ID -1, // OptID }, gotoRow{ // S13 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S14 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S15 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList 32, // Stmt -1, // OptSemi 17, // NodeStmt 18, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge 19, // AttrStmt 24, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep 20, // Attr 21, // Subgraph 28, // OptSubgraphID 23, // Vertex 22, // Node -1, // Port -1, // OptPort 27, // ID -1, // OptID }, gotoRow{ // S16 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt 33, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S17 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S18 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S19 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S20 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S21 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S22 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component 36, // AttrList 35, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S23 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt 38, // Edge 39, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S24 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component 42, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S25 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S26 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S27 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node 45, // Port 44, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S28 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S29 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 10, // ID 48, // OptID }, gotoRow{ // S30 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S31 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S32 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt 49, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S33 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S34 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S35 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S36 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S37 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList 53, // AList 52, // OptAList -1, // OptSep 51, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 54, // ID -1, // OptID }, gotoRow{ // S38 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component 36, // AttrList 56, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S39 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr 57, // Subgraph 61, // OptSubgraphID 59, // Vertex 58, // Node -1, // Port -1, // OptPort 60, // ID -1, // OptID }, gotoRow{ // S40 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S41 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S42 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S43 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 63, // ID -1, // OptID }, gotoRow{ // S44 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S45 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S46 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 65, // ID -1, // OptID }, gotoRow{ // S47 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph 15, // StmtList 66, // OptStmtList 16, // Stmt -1, // OptSemi 17, // NodeStmt 18, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge 19, // AttrStmt 24, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep 20, // Attr 21, // Subgraph 28, // OptSubgraphID 23, // Vertex 22, // Node -1, // Port -1, // OptPort 27, // ID -1, // OptID }, gotoRow{ // S48 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S49 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S50 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList 53, // AList 67, // OptAList -1, // OptSep 51, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 54, // ID -1, // OptID }, gotoRow{ // S51 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList 69, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S52 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S53 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep 72, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 54, // ID -1, // OptID }, gotoRow{ // S54 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S55 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S56 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S57 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S58 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S59 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt 74, // Edge 39, // DirectedEdge 75, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S60 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node 45, // Port 44, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S61 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S62 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S63 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S64 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S65 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S66 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S67 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S68 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S69 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S70 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S71 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S72 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList 80, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S73 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 81, // ID -1, // OptID }, gotoRow{ // S74 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S75 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S76 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph 15, // StmtList 83, // OptStmtList 16, // Stmt -1, // OptSemi 17, // NodeStmt 18, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge 19, // AttrStmt 24, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep 20, // Attr 21, // Subgraph 28, // OptSubgraphID 23, // Vertex 22, // Node -1, // Port -1, // OptPort 27, // ID -1, // OptID }, gotoRow{ // S77 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort 84, // ID -1, // OptID }, gotoRow{ // S78 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S79 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S80 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S81 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S82 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S83 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S84 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S85 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, gotoRow{ // S86 -1, // S' -1, // File -1, // Graph -1, // OptStrict -1, // DirectedGraph -1, // StmtList -1, // OptStmtList -1, // Stmt -1, // OptSemi -1, // NodeStmt -1, // EdgeStmt -1, // Edge -1, // DirectedEdge -1, // OptEdge -1, // AttrStmt -1, // Component -1, // AttrList -1, // OptAttrList -1, // AList -1, // OptAList -1, // OptSep -1, // Attr -1, // Subgraph -1, // OptSubgraphID -1, // Vertex -1, // Node -1, // Port -1, // OptPort -1, // ID -1, // OptID }, } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/parser.go000066400000000000000000000122301450372207100261310ustar00rootroot00000000000000// 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 Context Context } 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), p.Context) 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 } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/parser_test.go000066400000000000000000000064251450372207100272010ustar00rootroot00000000000000// 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_test import ( "archive/zip" "bytes" "os" "testing" "gonum.org/v1/gonum/graph/formats/dot" ) func TestParseFile(t *testing.T) { golden := []struct { in string out string }{ {in: "../testdata/empty.dot"}, {in: "../testdata/graph.dot"}, {in: "../testdata/digraph.dot"}, {in: "../testdata/strict.dot"}, {in: "../testdata/multi.dot"}, {in: "../testdata/named_graph.dot"}, {in: "../testdata/node_stmt.dot"}, {in: "../testdata/edge_stmt.dot"}, {in: "../testdata/attr_stmt.dot"}, {in: "../testdata/attr.dot"}, { in: "../testdata/subgraph.dot", out: "../testdata/subgraph.golden", }, { in: "../testdata/semi.dot", out: "../testdata/semi.golden", }, { in: "../testdata/empty_attr.dot", out: "../testdata/empty_attr.golden", }, { in: "../testdata/attr_lists.dot", out: "../testdata/attr_lists.golden", }, { in: "../testdata/attr_sep.dot", out: "../testdata/attr_sep.golden", }, {in: "../testdata/subgraph_vertex.dot"}, {in: "../testdata/port.dot"}, {in: "../testdata/quoted_id.dot"}, { in: "../testdata/backslash_newline_id.dot", out: "../testdata/backslash_newline_id.golden", }, } for _, g := range golden { file, err := dot.ParseFile(g.in) if err != nil { t.Errorf("%q: unable to parse file; %v", g.in, err) continue } // If no output path is specified, the input is already golden. out := g.in if len(g.out) > 0 { out = g.out } buf, err := os.ReadFile(out) if err != nil { t.Errorf("%q: unable to read file; %v", g.in, err) continue } got := file.String() // Remove trailing newline. want := string(bytes.TrimSpace(buf)) if got != want { t.Errorf("%q: graph mismatch; expected `%s`, got `%s`", g.in, want, got) } } } func TestParseFuzz(t *testing.T) { r, err := zip.OpenReader("../../fuzz/corpus.zip") if err != nil { if os.IsNotExist(err) { t.Skip("no corpus") } t.Fatalf("failed to open corpus: %v", err) } defer r.Close() for _, f := range r.File { rc, err := f.Open() if err != nil { t.Fatalf("failed to open %q: %v", f.Name, err) } func() { defer func() { p := recover() if p != nil { t.Errorf("unexpected panic parsing %q: %v", f.Name, p) } }() _, err = dot.Parse(rc) if err != nil { t.Errorf("unexpected error parsing %q: %v", f.Name, err) } }() rc.Close() } } func TestParseError(t *testing.T) { golden := []struct { path string want string }{ { path: "../testdata/error.dot", want: `2:7: error: expected one of "{", "}", graphx, ";", "--", "->", node, edge, "[", "=", subgraph, ":", or id; got: unknown/invalid token "~"`, }, } for _, g := range golden { _, err := dot.ParseFile(g.path) if err == nil { t.Errorf("%q: expected error, got nil", g.path) continue } got := err.Error() if got != g.want { t.Errorf("%q: error mismatch; expected %#q, got %#q", g.path, g.want, got) continue } } } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/parser/productionstable.go000066400000000000000000000335651450372207100302340ustar00rootroot00000000000000// 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 ( ProdTab [numProductions]ProdTabEntry ProdTabEntry struct { String string Id string NTType int Index int NumSymbols int ReduceFunc func([]Attrib, interface{}) (Attrib, error) } Attrib interface { } ) var productionsTable = ProdTab{ ProdTabEntry{ String: `S' : File << >>`, Id: "S'", NTType: 0, Index: 0, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (Attrib, error) { return false, nil }, }, ProdTabEntry{ String: `OptStrict : strict << true, nil >>`, Id: "OptStrict", NTType: 3, Index: 5, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return true, nil }, }, ProdTabEntry{ String: `DirectedGraph : graphx << false, nil >>`, Id: "DirectedGraph", NTType: 4, Index: 6, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return false, nil }, }, ProdTabEntry{ String: `DirectedGraph : digraph << true, nil >>`, Id: "DirectedGraph", NTType: 4, Index: 7, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (Attrib, error) { return nil, nil }, }, ProdTabEntry{ String: `OptStmtList : StmtList << >>`, Id: "OptStmtList", NTType: 6, Index: 11, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `Stmt : NodeStmt << >>`, Id: "Stmt", NTType: 7, Index: 12, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `Stmt : EdgeStmt << >>`, Id: "Stmt", NTType: 7, Index: 13, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `Stmt : AttrStmt << >>`, Id: "Stmt", NTType: 7, Index: 14, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `Stmt : Attr << >>`, Id: "Stmt", NTType: 7, Index: 15, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `Stmt : Subgraph << >>`, Id: "Stmt", NTType: 7, Index: 16, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `OptSemi : empty << >>`, Id: "OptSemi", NTType: 8, Index: 17, NumSymbols: 0, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return nil, nil }, }, ProdTabEntry{ String: `OptSemi : ";" << >>`, Id: "OptSemi", NTType: 8, Index: 18, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (Attrib, error) { return false, nil }, }, ProdTabEntry{ String: `DirectedEdge : "->" << true, nil >>`, Id: "DirectedEdge", NTType: 12, Index: 23, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return true, nil }, }, ProdTabEntry{ String: `OptEdge : empty << >>`, Id: "OptEdge", NTType: 13, Index: 24, NumSymbols: 0, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return nil, nil }, }, ProdTabEntry{ String: `OptEdge : Edge << >>`, Id: "OptEdge", NTType: 13, Index: 25, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (Attrib, error) { return nil, nil }, }, ProdTabEntry{ String: `OptAttrList : AttrList << >>`, Id: "OptAttrList", NTType: 17, Index: 33, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (Attrib, error) { return nil, nil }, }, ProdTabEntry{ String: `OptAList : AList << >>`, Id: "OptAList", NTType: 19, Index: 37, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `OptSep : empty << >>`, Id: "OptSep", NTType: 20, Index: 38, NumSymbols: 0, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return nil, nil }, }, ProdTabEntry{ String: `OptSep : ";" << >>`, Id: "OptSep", NTType: 20, Index: 39, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `OptSep : "," << >>`, Id: "OptSep", NTType: 20, Index: 40, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (Attrib, error) { return X[1], nil }, }, ProdTabEntry{ String: `Vertex : Node << >>`, Id: "Vertex", NTType: 24, Index: 45, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, ProdTabEntry{ String: `Vertex : Subgraph << >>`, Id: "Vertex", NTType: 24, Index: 46, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (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, C interface{}) (Attrib, error) { return nil, nil }, }, ProdTabEntry{ String: `OptPort : Port << >>`, Id: "OptPort", NTType: 27, Index: 51, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (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, C interface{}) (Attrib, error) { return astx.NewID(X[0]) }, }, ProdTabEntry{ String: `OptID : empty << "", nil >>`, Id: "OptID", NTType: 29, Index: 53, NumSymbols: 0, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return "", nil }, }, ProdTabEntry{ String: `OptID : ID << >>`, Id: "OptID", NTType: 29, Index: 54, NumSymbols: 1, ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { return X[0], nil }, }, } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/paste_copyright.go000066400000000000000000000026731450372207100265570ustar00rootroot00000000000000// 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:build ignore // +build ignore package main import ( "bytes" "fmt" "os" "path/filepath" ) var location = []byte(`// Code generated by gocc; DO NOT EDIT.`) var copyright = []byte(`// 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.`) func main() { err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() || filepath.Dir(path) == "." || filepath.Ext(path) != ".go" { return nil } content, err := os.ReadFile(path) if err != nil { return err } content = bytes.Replace(content, location, copyright, 1) return os.WriteFile(path, content, info.Mode()) }) if err != nil { fmt.Printf("error walking the path: %v\n", err) } } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/staticcheck.conf000066400000000000000000000000401450372207100261420ustar00rootroot00000000000000checks = ["inherit", "-ST1005"] golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/000077500000000000000000000000001450372207100246255ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/attr.dot000066400000000000000000000000441450372207100263050ustar00rootroot00000000000000digraph { bgcolor=transparent A } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/attr_lists.dot000066400000000000000000000000561450372207100275260ustar00rootroot00000000000000digraph { A [style=filled] [fillcolor=red] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/attr_lists.golden000066400000000000000000000000541450372207100302060ustar00rootroot00000000000000digraph { A [style=filled fillcolor=red] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/attr_sep.dot000066400000000000000000000000711450372207100271540ustar00rootroot00000000000000digraph { A [style=filled, fillcolor=red; color=blue] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/attr_sep.golden000066400000000000000000000000671450372207100276430ustar00rootroot00000000000000digraph { A [style=filled fillcolor=red color=blue] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/attr_stmt.dot000066400000000000000000000001471450372207100273600ustar00rootroot00000000000000digraph { graph [bgcolor=transparent] node [style=filled fillcolor=white] edge [minlen=2] A -> B } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/backslash_newline_id.dot000066400000000000000000000000461450372207100314650ustar00rootroot00000000000000digraph { A [name="hello \ world"] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/backslash_newline_id.golden000066400000000000000000000000441450372207100321450ustar00rootroot00000000000000digraph { A [name="hello world"] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/digraph.dot000066400000000000000000000000241450372207100267470ustar00rootroot00000000000000digraph { A -> B } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/edge_stmt.dot000066400000000000000000000000661450372207100273120ustar00rootroot00000000000000digraph { A -> B -> C D -> E [color=red minlen=2] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/empty.dot000066400000000000000000000000121450372207100264640ustar00rootroot00000000000000graph { } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/empty_attr.dot000066400000000000000000000000221450372207100275170ustar00rootroot00000000000000digraph { A [] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/empty_attr.golden000066400000000000000000000000171450372207100302050ustar00rootroot00000000000000digraph { A } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/error.dot000066400000000000000000000000231450372207100264610ustar00rootroot00000000000000digraph { A ~ B } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/graph.dot000066400000000000000000000000221450372207100264300ustar00rootroot00000000000000graph { A -- B } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/multi.dot000066400000000000000000000000501450372207100264620ustar00rootroot00000000000000digraph { A -> B } digraph { C -> D } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/named_graph.dot000066400000000000000000000000171450372207100276000ustar00rootroot00000000000000graph G { A } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/node_stmt.dot000066400000000000000000000000171450372207100273270ustar00rootroot00000000000000digraph { A } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/port.dot000066400000000000000000000001261450372207100263200ustar00rootroot00000000000000digraph { A:ne -> B:sw C:foo -> D:bar:se E:_ -> F G:n H:e I:s J:w K:nw L:c } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/quoted_id.dot000066400000000000000000000000501450372207100273050ustar00rootroot00000000000000digraph { "A" -> "B" ["color"="red"] } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/semi.dot000066400000000000000000000000271450372207100262710ustar00rootroot00000000000000digraph { A -> B; C } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/semi.golden000066400000000000000000000000271450372207100267530ustar00rootroot00000000000000digraph { A -> B C } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/strict.dot000066400000000000000000000000431450372207100266420ustar00rootroot00000000000000strict digraph { A -> B A -> B } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/subgraph.dot000066400000000000000000000000571450372207100271520ustar00rootroot00000000000000digraph { {A} subgraph {B} subgraph S {C} } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/subgraph.golden000066400000000000000000000000461450372207100276320ustar00rootroot00000000000000digraph { {A} {B} subgraph S {C} } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/testdata/subgraph_vertex.dot000066400000000000000000000000301450372207100305360ustar00rootroot00000000000000digraph { {A B} -> C } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/token/000077500000000000000000000000001450372207100241345ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/token/context.go000066400000000000000000000013621450372207100261510ustar00rootroot00000000000000// 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 // Context allows user-defined data to be associated with the // lexer/scanner to be associated with each token that lexer // produces. type Context interface{} // Sourcer is a Context interface which presents a Source() method // identifying e.g the filename for the current code. type Sourcer interface { Source() string } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/token/doc.go000066400000000000000000000005061450372207100252310ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/token/token.go000066400000000000000000000101101450372207100255740ustar00rootroot00000000000000// 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 ( "bytes" "fmt" "strconv" "unicode/utf8" ) type Token struct { Type Lit []byte Pos } type Type int const ( INVALID Type = iota EOF ) type Pos struct { Offset int Line int Column int Context Context } func (p Pos) String() string { // If the context provides a filename, provide a human-readable File:Line:Column representation. switch src := p.Context.(type) { case Sourcer: return fmt.Sprintf("%s:%d:%d", src.Source(), p.Line, p.Column) default: 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 { 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) } // Equals returns returns true if the token Type and Lit are matches. func (t *Token) Equals(rhs interface{}) bool { switch rhsT := rhs.(type) { case *Token: return t == rhsT || (t.Type == rhsT.Type && bytes.Equal(t.Lit, rhsT.Lit)) default: return false } } // CharLiteralValue returns the string value of the char literal. func (t *Token) CharLiteralValue() string { return string(t.Lit[1 : len(t.Lit)-1]) } // Float32Value returns the float32 value of the token or an error if the token literal does not // denote a valid float32. func (t *Token) Float32Value() (float32, error) { if v, err := strconv.ParseFloat(string(t.Lit), 32); err != nil { return 0, err } else { return float32(v), nil } } // Float64Value returns the float64 value of the token or an error if the token literal does not // denote a valid float64. func (t *Token) Float64Value() (float64, error) { return strconv.ParseFloat(string(t.Lit), 64) } // IDValue returns the string representation of an identifier token. func (t *Token) IDValue() string { return string(t.Lit) } // Int32Value returns the int32 value of the token or an error if the token literal does not // denote a valid float64. func (t *Token) Int32Value() (int32, error) { if v, err := strconv.ParseInt(string(t.Lit), 10, 64); err != nil { return 0, err } else { return int32(v), nil } } // Int64Value returns the int64 value of the token or an error if the token literal does not // denote a valid float64. func (t *Token) Int64Value() (int64, error) { return strconv.ParseInt(string(t.Lit), 10, 64) } // UTF8Rune decodes the UTF8 rune in the token literal. It returns utf8.RuneError if // the token literal contains an invalid rune. func (t *Token) UTF8Rune() (rune, error) { r, _ := utf8.DecodeRune(t.Lit) if r == utf8.RuneError { err := fmt.Errorf("Invalid rune") return r, err } return r, nil } // StringValue returns the string value of the token literal. func (t *Token) StringValue() string { return string(t.Lit[1 : len(t.Lit)-1]) } 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, }, } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/tools.go000066400000000000000000000003521450372207100245030ustar00rootroot00000000000000// 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. //go:build tools package tools import _ "github.com/goccmack/gocc" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/util/000077500000000000000000000000001450372207100237715ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/util/doc.go000066400000000000000000000005001450372207100250600ustar00rootroot00000000000000// 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 util provides generated internal utility functions for DOT parsing. package util // import "gonum.org/v1/gonum/graph/formats/dot/internal/util" golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/util/litconv.go000066400000000000000000000050741450372207100260040ustar00rootroot00000000000000// 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 util import ( "fmt" "strconv" "unicode" "unicode/utf8" ) // Interface. // RuneValue will convert the literal value of a scanned token to a rune. func RuneValue(lit []byte) rune { if lit[1] == '\\' { return escapeCharVal(lit) } r, size := utf8.DecodeRune(lit[1:]) if size != len(lit)-2 { panic(fmt.Sprintf("Error decoding rune. Lit: %s, rune: %d, size%d\n", lit, r, size)) } return r } // UintValue will attempt to parse a byte-slice as a signed base-10 64-bit integer. func IntValue(lit []byte) (int64, error) { return strconv.ParseInt(string(lit), 10, 64) } // UintValue will attempt to parse a byte-slice as an unsigned base-10 64-bit integer. func UintValue(lit []byte) (uint64, error) { return strconv.ParseUint(string(lit), 10, 64) } // Helpers. func escapeCharVal(lit []byte) rune { var i, base, max uint32 offset := 2 switch lit[offset] { case 'a': return '\a' case 'b': return '\b' case 'f': return '\f' case 'n': return '\n' case 'r': return '\r' case 't': return '\t' case 'v': return '\v' case '\\': return '\\' case '\'': return '\'' case '0', '1', '2', '3', '4', '5', '6', '7': i, base, max = 3, 8, 255 case 'x': i, base, max = 2, 16, 255 offset++ case 'u': i, base, max = 4, 16, unicode.MaxRune offset++ case 'U': i, base, max = 8, 16, unicode.MaxRune offset++ default: panic(fmt.Sprintf("Error decoding character literal: %s\n", lit)) } var x uint32 for ; i > 0 && offset < len(lit)-1; i-- { ch, size := utf8.DecodeRune(lit[offset:]) offset += size d := uint32(digitVal(ch)) if d >= base { panic(fmt.Sprintf("charVal(%s): illegal character (%c) in escape sequence. size=%d, offset=%d", lit, ch, size, offset)) } x = x*base + d } if x > max || 0xD800 <= x && x < 0xE000 { panic(fmt.Sprintf("Error decoding escape char value. Lit:%s, offset:%d, escape sequence is invalid Unicode code point\n", lit, offset)) } return rune(x) } func digitVal(ch rune) int { switch { case '0' <= ch && ch <= '9': return int(ch) - '0' case 'a' <= ch && ch <= 'f': return int(ch) - 'a' + 10 case 'A' <= ch && ch <= 'F': return int(ch) - 'A' + 10 } return 16 // larger than any legal digit val } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/internal/util/rune.go000066400000000000000000000016601450372207100252740ustar00rootroot00000000000000// 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 util import ( "fmt" ) func RuneToString(r rune) string { if r >= 0x20 && r < 0x7f { return fmt.Sprintf("'%c'", r) } switch r { case 0x07: return "'\\a'" case 0x08: return "'\\b'" case 0x0C: return "'\\f'" case 0x0A: return "'\\n'" case 0x0D: return "'\\r'" case 0x09: return "'\\t'" case 0x0b: return "'\\v'" case 0x5c: return "'\\\\\\'" case 0x27: return "'\\''" case 0x22: return "'\\\"'" } if r < 0x10000 { return fmt.Sprintf("\\u%04x", r) } return fmt.Sprintf("\\U%08x", r) } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/makeinternal.bash000077500000000000000000000000641450372207100245140ustar00rootroot00000000000000#!/usr/bin/env bash cd internal make clean && make golang-gonum-v1-gonum-0.14.0/graph/formats/dot/sem.go000066400000000000000000000107641450372207100223230ustar00rootroot00000000000000// 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 } golang-gonum-v1-gonum-0.14.0/graph/formats/dot/testdata/000077500000000000000000000000001450372207100230115ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/dot/testdata/.gitignore000066400000000000000000000000421450372207100247750ustar00rootroot00000000000000*.dot *.png graphviz input output golang-gonum-v1-gonum-0.14.0/graph/formats/dot/testdata/Makefile000066400000000000000000000050721450372207100244550ustar00rootroot00000000000000# Dependencies: # # * imgcmp # go get github.com/mewkiz/cmd/imgcmp # * dotfmt # go get github.com/graphism/dot/cmd/dotfmt # * dot # sudo pacman -S graphviz # * recode # sudo pacman -S recode DOT=$(wildcard *.dot) # Skip DOT files for which the generated PNG images mismatch. # # ref: https://github.com/graphism/dot/issues/2 # # pixel colors differ at x=550, y=1885 DOT:=$(filter-out b51.dot, $(DOT)) # pixel colors differ at x=5395, y=1920 DOT:=$(filter-out b106.dot, $(DOT)) # Skip segfaulting files. # # Segmentation fault (core dumped) DOT:=$(filter-out b15.dot, $(DOT)) # Segmentation fault (core dumped) DOT:=$(filter-out b81.dot, $(DOT)) # *** stack smashing detected ***: dot terminated DOT:=$(filter-out sides.dot, $(DOT)) # *** stack smashing detected ***: dot terminated DOT:=$(filter-out tee.dot, $(DOT)) # Skip DOT files above 100 kB. DOT:=$(filter-out 4elt.dot, $(DOT)) DOT:=$(filter-out b29.dot, $(DOT)) DOT:=$(filter-out b81.dot, $(DOT)) DOT:=$(filter-out b100.dot, $(DOT)) DOT:=$(filter-out b102.dot, $(DOT)) DOT:=$(filter-out b103.dot, $(DOT)) DOT:=$(filter-out b104.dot, $(DOT)) DOT:=$(filter-out root.dot, $(DOT)) DOT:=$(filter-out root_circo.dot, $(DOT)) DOT:=$(filter-out root_twopi.dot, $(DOT)) # Skip invalid DOT file. # # Error: No or improper image file="eqn.png" # in label of node struct1 DOT:=$(filter-out html4.dot, $(DOT)) # Skip multi-graph DOT file which outputs to standard output. DOT:=$(filter-out multi.dot, $(DOT)) # *.dot -> *.png PNG=$(DOT:.dot=.png) INPUT_PNG=$(addprefix input/,$(PNG)) OUTPUT_PNG=$(addprefix output/,$(PNG)) all: test: input $(INPUT_PNG) output $(OUTPUT_PNG) @echo "PASS" input: mkdir -p $@ dot -V input/%.png: %.dot dot -Tpng -o $@ $< output: mkdir -p $@ output/%.png: %.dot dotfmt -o "output/$<" $< dot -Tpng -o $@ "output/$<" imgcmp "input/$(notdir $@)" $@ fetch: graphviz # Copy *.gv and *.dot files. find graphviz -type f -name '*.gv' -not -wholename "graphviz/rtest/share/b545.gv" -not -name "base.gv" | xargs -I '{}' cp "{}" . find graphviz -type f -name '*.dot' | xargs -I '{}' cp "{}" . # Rename *.gv to *.dot. #rename .gv .dot *.gv ls *.gv | xargs -I '{}' basename "{}" .gv | xargs -I '{}' mv "{}.gv" "{}.dot" # Remove execute permissions. chmod 0644 *.dot # Convert Latin1 encoded files to UTF-8. grep -l "charset=latin1" *.dot | xargs -I '{}' recode ISO-8859-1..UTF8 "{}" recode ISO-8859-1..UTF8 Latin1.dot # Clean up. rm -rf graphviz graphviz: git clone --depth=1 https://github.com/ellson/graphviz.git clean: rm -rf *.dot input output .PHONY: all test fetch clean golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/000077500000000000000000000000001450372207100215065ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/gexf.go000066400000000000000000000243441450372207100227750ustar00rootroot00000000000000// 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 gexf12 implements marshaling and unmarshaling of GEXF1.2 documents. // // For details of GEXF see https://gephi.org/gexf/format/. package gexf12 // import "gonum.org/v1/gonum/graph/formats/gexf12" import ( "bytes" "encoding/xml" "time" ) // BUG(kortschak): The namespace for GEFX1.2 is 1.2draft, though it has // already been deprecated. There is no specification for 1.3, although // it is being used in the wild. // Content holds a GEFX graph and metadata. type Content struct { XMLName xml.Name `xml:"http://www.gexf.net/1.2draft gexf"` Meta *Meta `xml:"meta,omitempty"` Graph Graph `xml:"graph"` // Version must be "1.2". Version string `xml:"version,attr"` Variant string `xml:"variant,attr,omitempty"` } // Meta holds optional metadata associated with the graph. type Meta struct { Creator string `xml:"creator,omitempty"` Keywords string `xml:"keywords,omitempty"` Description string `xml:"description,omitempty"` LastModified time.Time `xml:"lastmodifieddate,attr,omitempty"` } // MarshalXML implements the xml.Marshaler interface. func (t *Meta) MarshalXML(e *xml.Encoder, start xml.StartElement) error { type T Meta var layout struct { *T LastModified *xsdDate `xml:"lastmodifieddate,attr,omitempty"` } layout.T = (*T)(t) layout.LastModified = (*xsdDate)(&layout.T.LastModified) return e.EncodeElement(layout, start) } // UnmarshalXML implements the xml.Unmarshaler interface. func (t *Meta) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { type T Meta var overlay struct { *T LastModified *xsdDate `xml:"lastmodifieddate,attr,omitempty"` } overlay.T = (*T)(t) overlay.LastModified = (*xsdDate)(&overlay.T.LastModified) return d.DecodeElement(&overlay, &start) } // Graph stores the graph nodes, edges, dynamics and visualization data. type Graph struct { Attributes []Attributes `xml:"attributes"` Nodes Nodes `xml:"nodes"` Edges Edges `xml:"edges"` // TimeFormat may be one of "integer", "double", "date" or "dateTime". TimeFormat string `xml:"timeformat,attr,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` // DefaultEdgeType may be one of "directed", "undirected" or "mutual". DefaultEdgeType string `xml:"defaultedgetype,attr,omitempty"` // IDType may be one of "integer" or "string". IDType string `xml:"idtype,attr,omitempty"` // Mode may be "static" or "dynamic". Mode string `xml:"mode,attr,omitempty"` } // Attributes holds a collection of potentially dynamic attributes // associated with a graph. type Attributes struct { Attributes []Attribute `xml:"attribute,omitempty"` // Class be one of "node" or "edge". Class string `xml:"class,attr"` // Mode may be "static" or "dynamic". Mode string `xml:"mode,attr,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // Attribute holds a single graph attribute. type Attribute struct { ID string `xml:"id,attr"` Title string `xml:"title,attr"` // Type may be one of "integer", "long", "double", "float", // "boolean", "liststring", "string", or "anyURI". Type string `xml:"type,attr"` Default string `xml:"default,omitempty"` Options string `xml:"options,omitempty"` } // Nodes holds a collection of nodes constituting a graph or subgraph. type Nodes struct { Count int `xml:"count,attr,omitempty"` Nodes []Node `xml:"node,omitempty"` } // Node is a single node and its associated attributes. type Node struct { ID string `xml:"id,attr,omitempty"` Label string `xml:"label,attr,omitempty"` AttValues *AttValues `xml:"attvalues"` Spells *Spells `xml:"spells"` Nodes *Nodes `xml:"nodes"` Edges *Edges `xml:"edges"` ParentID string `xml:"pid,attr,omitempty"` Parents *Parents `xml:"parents"` Color *Color `xml:"http://www.gexf.net/1.2draft/viz color"` Position *Position `xml:"http://www.gexf.net/1.2draft/viz position"` Size *Size `xml:"http://www.gexf.net/1.2draft/viz size"` Shape *NodeShape `xml:"http://www.gexf.net/1.2draft/viz shape"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // NodeShape holds the visual representation of a node with associated // dynamics. type NodeShape struct { Spells *Spells `xml:"spells,omitempty"` // Value be one of "disc", "square", "triangle", // "diamond" or "image". Shape string `xml:"value,attr"` URI string `xml:"uri,attr,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // Color represents a node or edge color and its associated dynamics. type Color struct { Spells *Spells `xml:"spells,omitempty"` R byte `xml:"r,attr"` G byte `xml:"g,attr"` B byte `xml:"b,attr"` A float64 `xml:"a,attr,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // Edges holds a collection of edges constituting a graph or subgraph. type Edges struct { Count int `xml:"count,attr,omitempty"` Edges []Edge `xml:"edge,omitempty"` } // Edge is a single edge and its associated attributes. type Edge struct { ID string `xml:"id,attr,omitempty"` AttValues *AttValues `xml:"attvalues"` Spells *Spells `xml:"spells"` Color *Color `xml:"http://www.gexf.net/1.2draft/viz color"` Thickness *Thickness `xml:"http://www.gexf.net/1.2draft/viz thickness"` Shape *Edgeshape `xml:"http://www.gexf.net/1.2draft/viz shape"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` // Type may be one of directed, undirected, mutual Type string `xml:"type,attr,omitempty"` Label string `xml:"label,attr,omitempty"` Source string `xml:"source,attr"` Target string `xml:"target,attr"` Weight float64 `xml:"weight,attr,omitempty"` } // AttValues holds a collection of attribute values. type AttValues struct { AttValues []AttValue `xml:"attvalue,omitempty"` } // AttValues holds a single attribute value and its associated dynamics. type AttValue struct { For string `xml:"for,attr"` Value string `xml:"value,attr"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // EdgeShape holds the visual representation of an edge with associated // dynamics. type Edgeshape struct { // Shape be one of solid, dotted, dashed, double Shape string `xml:"value,attr"` Spells *Spells `xml:"spells,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // Parents holds parent relationships between nodes in a hierarchical // graph. type Parents struct { Parents []Parent `xml:"parent,omitempty"` } // Parent is a single parent relationship. type Parent struct { For string `xml:"for,attr"` } // Position hold the spatial position of a node and its dynamics. type Position struct { X float64 `xml:"x,attr"` Y float64 `xml:"y,attr"` Z float64 `xml:"z,attr"` Spells *Spells `xml:"spells,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // Size hold the visual size of a node and its dynamics. type Size struct { Value float64 `xml:"value,attr"` Spells *Spells `xml:"http://www.gexf.net/1.2draft/viz spells,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // Thickness hold the visual thickness of an edge and its dynamics. type Thickness struct { Value float64 `xml:"value,attr"` Spells *Spells `xml:"http://www.gexf.net/1.2draft/viz spells,omitempty"` Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } // Spells holds a collection of time dynamics for a graph entity. type Spells struct { Spells []Spell `xml:"spell"` } // Spell is a time interval. type Spell struct { Start string `xml:"start,attr,omitempty"` StartOpen string `xml:"startopen,attr,omitempty"` End string `xml:"end,attr,omitempty"` EndOpen string `xml:"endopen,attr,omitempty"` } type xsdDate time.Time func (t *xsdDate) UnmarshalText(text []byte) error { return _unmarshalTime(text, (*time.Time)(t), "2006-01-02") } func (t xsdDate) MarshalText() ([]byte, error) { return []byte((time.Time)(t).Format("2006-01-02")), nil } func (t xsdDate) MarshalXML(e *xml.Encoder, start xml.StartElement) error { if (time.Time)(t).IsZero() { return nil } m, err := t.MarshalText() if err != nil { return err } return e.EncodeElement(m, start) } func (t xsdDate) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { if (time.Time)(t).IsZero() { return xml.Attr{}, nil } m, err := t.MarshalText() return xml.Attr{Name: name, Value: string(m)}, err } func _unmarshalTime(text []byte, t *time.Time, format string) (err error) { s := string(bytes.TrimSpace(text)) *t, err = time.Parse(format, s) if _, ok := err.(*time.ParseError); ok { *t, err = time.Parse(format+"Z07:00", s) } return err } golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/gexf_test.go000066400000000000000000000274141450372207100240350ustar00rootroot00000000000000// 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 gexf12 import ( "encoding/xml" "os" "path/filepath" "reflect" "testing" "time" ) var gexfExampleTests = []struct { path string unmarshaled Content marshaled string }{ { path: "basic.gexf", unmarshaled: Content{ XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"}, Meta: nil, Graph: Graph{ Attributes: nil, Nodes: Nodes{ Nodes: []Node{ {ID: "0", Label: "Hello"}, {ID: "1", Label: "Word"}, }, }, Edges: Edges{ Edges: []Edge{ {ID: "0", Source: "0", Target: "1"}, }, }, DefaultEdgeType: "directed", Mode: "static", }, Version: "1.2", }, marshaled: ` `, }, { path: "data.gexf", unmarshaled: Content{ XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"}, Meta: &Meta{ Creator: "Gephi.org", Description: "A Web network", LastModified: time.Date(2009, 03, 20, 0, 0, 0, 0, time.UTC), }, Graph: Graph{ Attributes: []Attributes{{ Class: "node", Attributes: []Attribute{ { ID: "0", Title: "url", Type: "string", }, { ID: "1", Title: "indegree", Type: "float", }, { ID: "2", Title: "frog", Type: "boolean", Default: "true", }, }, }}, Nodes: Nodes{ Nodes: []Node{ { ID: "0", Label: "Gephi", AttValues: &AttValues{AttValues: []AttValue{ {For: "0", Value: "http://gephi.org"}, {For: "1", Value: "1"}, }}, }, { ID: "1", Label: "Webatlas", AttValues: &AttValues{AttValues: []AttValue{ {For: "0", Value: "http://webatlas.fr"}, {For: "1", Value: "2"}, }}, }, { ID: "2", Label: "RTGI", AttValues: &AttValues{AttValues: []AttValue{ {For: "0", Value: "http://rtgi.fr"}, {For: "1", Value: "1"}, }}, }, { ID: "3", Label: "BarabasiLab", AttValues: &AttValues{AttValues: []AttValue{ {For: "0", Value: "http://barabasilab.com"}, {For: "1", Value: "1"}, {For: "2", Value: "false"}, }}, }, }, }, Edges: Edges{ Edges: []Edge{ {ID: "0", Source: "0", Target: "1"}, {ID: "1", Source: "0", Target: "2"}, {ID: "2", Source: "1", Target: "0"}, {ID: "3", Source: "2", Target: "1"}, {ID: "4", Source: "0", Target: "3"}, }, }, DefaultEdgeType: "directed", }, Version: "1.2", }, marshaled: ` Gephi.org A Web network true `, }, { path: "hierarchy1.gexf", unmarshaled: Content{ XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"}, Meta: &Meta{ Creator: "Gephi.org", Description: "A hierarchy file", LastModified: time.Date(2009, 10, 1, 0, 0, 0, 0, time.UTC), }, Graph: Graph{ Nodes: Nodes{ Nodes: []Node{{ ID: "a", Label: "Kevin Bacon", Nodes: &Nodes{ Nodes: []Node{ { ID: "b", Label: "God", Nodes: &Nodes{ Nodes: []Node{ {ID: "c", Label: "human1"}, {ID: "d", Label: "human2"}, {ID: "i", Label: "human3"}, }, }, }, { ID: "e", Label: "Me", Nodes: &Nodes{ Nodes: []Node{ {ID: "f", Label: "frog1"}, {ID: "g", Label: "frog2"}, {ID: "h", Label: "frog3"}, }, }, }, { ID: "j", Label: "You", }, }, }, }}, }, Edges: Edges{ Edges: []Edge{ {ID: "0", Source: "b", Target: "e"}, {ID: "1", Source: "c", Target: "d"}, {ID: "2", Source: "c", Target: "i"}, {ID: "3", Source: "g", Target: "b"}, {ID: "4", Source: "f", Target: "a"}, {ID: "5", Source: "f", Target: "g"}, {ID: "6", Source: "f", Target: "h"}, {ID: "7", Source: "g", Target: "h"}, {ID: "8", Source: "a", Target: "j"}, }, }, DefaultEdgeType: "directed", Mode: "static", }, Version: "1.2", }, marshaled: ` Gephi.org A hierarchy file `, }, { path: "hierarchy4.gexf", unmarshaled: Content{ XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"}, Meta: &Meta{ Creator: "Gephi.org", Keywords: "", Description: "A hierarchy file", LastModified: time.Date(2009, 10, 1, 0, 0, 0, 0, time.UTC), }, Graph: Graph{ Nodes: Nodes{ Nodes: []Node{ {ID: "g", Label: "frog2", ParentID: "e"}, {ID: "a", Label: "Kevin Bacon"}, {ID: "c", Label: "human1", ParentID: "b"}, {ID: "b", Label: "God", ParentID: "a"}, {ID: "e", Label: "Me", ParentID: "a"}, {ID: "d", Label: "human2", ParentID: "b"}, {ID: "f", Label: "frog1", ParentID: "e"}, }, }, Edges: Edges{ Edges: []Edge{ {ID: "0", Source: "b", Target: "e"}, {ID: "1", Source: "c", Target: "d"}, {ID: "2", Source: "g", Target: "b"}, {ID: "3", Source: "f", Target: "a"}, }, }, DefaultEdgeType: "directed", Mode: "static", }, Version: "1.2", }, marshaled: ` Gephi.org A hierarchy file `, }, { path: "phylogeny.gexf", unmarshaled: Content{ XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"}, Graph: Graph{ Nodes: Nodes{ Nodes: []Node{ {ID: "a", Label: "cheese"}, {ID: "b", Label: "cherry"}, {ID: "c", Label: "cake", Parents: &Parents{ Parents: []Parent{ {For: "a"}, {For: "b"}, }, }, }, }, }, Edges: Edges{ Edges: nil, Count: 0, }, }, Version: "1.2", }, marshaled: ` `, }, { path: "viz.gexf", unmarshaled: Content{ XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"}, Graph: Graph{ Nodes: Nodes{ Nodes: []Node{ { ID: "a", Label: "glossy", Color: &Color{ R: 239, G: 173, B: 66, A: 0.6, }, Position: &Position{ X: 15.783598, Y: 40.109245, Z: 0, }, Size: &Size{ Value: 2.0375757, }, }, }, }, Edges: Edges{}, }, Version: "1.2", }, marshaled: ` `, }, } func TestUnmarshal(t *testing.T) { for _, test := range gexfExampleTests { data, err := os.ReadFile(filepath.Join("testdata", test.path)) if err != nil { t.Errorf("failed to read %q: %v", test.path, err) continue } var got Content err = xml.Unmarshal(data, &got) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) } if !reflect.DeepEqual(got, test.unmarshaled) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, test.unmarshaled) } } } // TODO(kortschak): Update this test when/if namespace // prefix handling in encoding/xml is fixed. func TestMarshal(t *testing.T) { for _, test := range gexfExampleTests { got, err := xml.MarshalIndent(test.unmarshaled, "", "\t") if err != nil { t.Errorf("failed to marshal %q: %v", test.path, err) continue } if string(got) != test.marshaled { t.Errorf("unexpected result for %q:\ngot:\n%s\nwant:\n%s", test.path, got, test.marshaled) } } } golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/testdata/000077500000000000000000000000001450372207100233175ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/testdata/basic.gexf000066400000000000000000000005621450372207100252560ustar00rootroot00000000000000 golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/testdata/data.gexf000066400000000000000000000033161450372207100251060ustar00rootroot00000000000000 Gephi.org A Web network true golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/testdata/hierarchy1.gexf000066400000000000000000000032351450372207100262340ustar00rootroot00000000000000 Gephi.org A hierarchy file golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/testdata/hierarchy4.gexf000066400000000000000000000021431450372207100262340ustar00rootroot00000000000000 Gephi.org A hierarchy file golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/testdata/phylogeny.gexf000066400000000000000000000005571450372207100262170ustar00rootroot00000000000000 golang-gonum-v1-gonum-0.14.0/graph/formats/gexf12/testdata/viz.gexf000066400000000000000000000010371450372207100250030ustar00rootroot00000000000000 golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/000077500000000000000000000000001450372207100211655ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/check.go000066400000000000000000000205271450372207100225770ustar00rootroot00000000000000 //line check.rl:1 // Code generated by go generate gonum.org/v1/gonum/graph/formats/rdf; DO NOT EDIT. // Copyright ©2020 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 rdf import ( "fmt" "unicode" ) //line check.go:18 const checkLabel_start int = 1 const checkLabel_first_final int = 3 const checkLabel_error int = 0 const checkLabel_en_value int = 1 //line check.rl:53 func checkLabelText(data []rune) (err error) { var ( cs, p int pe = len(data) eof = pe ) //line check.go:37 { cs = checkLabel_start } //line check.rl:63 //line check.go:45 { if p == pe { goto _test_eof } switch cs { case 1: goto st_case_1 case 0: goto st_case_0 case 3: goto st_case_3 case 2: goto st_case_2 } goto st_out st_case_1: if data[p] == 95 { goto st3 } switch { case data[p] < 895: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st3 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st3 } default: goto st3 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st3 } case data[p] > 767: if 880 <= data[p] && data[p] <= 893 { goto st3 } default: goto st3 } default: goto st3 } case data[p] > 8191: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8204 <= data[p] && data[p] <= 8205 { goto st3 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st3 } default: goto st3 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st3 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st3 } default: goto st3 } default: goto st3 } default: goto st3 } goto tr0 tr0: //line check_actions.rl:12 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return ErrIncompleteTerm goto st0 //line check.go:145 st_case_0: st0: cs = 0 goto _out st3: if p++; p == pe { goto _test_eof3 } st_case_3: switch data[p] { case 45: goto st3 case 46: goto st2 case 95: goto st3 case 183: goto st3 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st3 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st3 } default: goto st3 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st3 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st3 } default: goto st3 } default: goto st3 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st3 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st3 } default: goto st3 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st3 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st3 } default: goto st3 } default: goto st3 } default: goto st3 } goto st0 st2: if p++; p == pe { goto _test_eof2 } st_case_2: switch data[p] { case 45: goto st3 case 46: goto st2 case 95: goto st3 case 183: goto st3 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st3 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st3 } default: goto st3 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st3 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st3 } default: goto st3 } default: goto st3 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st3 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st3 } default: goto st3 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st3 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st3 } default: goto st3 } default: goto st3 } default: goto st3 } goto tr0 st_out: _test_eof3: cs = 3; goto _test_eof _test_eof2: cs = 2; goto _test_eof _test_eof: {} if p == eof { switch cs { case 3: //line check_actions.rl:8 return nil case 1, 2: //line check_actions.rl:12 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return ErrIncompleteTerm //line check.go:338 } } _out: {} } //line check.rl:65 return ErrInvalidTerm } //line check.go:351 const checkLang_start int = 1 const checkLang_first_final int = 4 const checkLang_error int = 0 const checkLang_en_value int = 1 //line check.rl:81 func checkLangText(data []byte) (err error) { var ( cs, p int pe = len(data) eof = pe ) //line check.go:370 { cs = checkLang_start } //line check.rl:91 //line check.go:378 { if p == pe { goto _test_eof } switch cs { case 1: goto st_case_1 case 0: goto st_case_0 case 2: goto st_case_2 case 4: goto st_case_4 case 3: goto st_case_3 case 5: goto st_case_5 } goto st_out st_case_1: if data[p] == 64 { goto st2 } goto tr0 tr0: //line check_actions.rl:12 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return ErrIncompleteTerm goto st0 //line check.go:416 st_case_0: st0: cs = 0 goto _out st2: if p++; p == pe { goto _test_eof2 } st_case_2: switch { case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st4 } case data[p] >= 65: goto st4 } goto tr0 st4: if p++; p == pe { goto _test_eof4 } st_case_4: if data[p] == 45 { goto st3 } switch { case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st4 } case data[p] >= 65: goto st4 } goto st0 st3: if p++; p == pe { goto _test_eof3 } st_case_3: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st5 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st5 } default: goto st5 } goto tr0 st5: if p++; p == pe { goto _test_eof5 } st_case_5: if data[p] == 45 { goto st3 } switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st5 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st5 } default: goto st5 } goto st0 st_out: _test_eof2: cs = 2; goto _test_eof _test_eof4: cs = 4; goto _test_eof _test_eof3: cs = 3; goto _test_eof _test_eof5: cs = 5; goto _test_eof _test_eof: {} if p == eof { switch cs { case 4, 5: //line check_actions.rl:8 return nil case 1, 2, 3: //line check_actions.rl:12 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return ErrIncompleteTerm //line check.go:517 } } _out: {} } //line check.rl:93 return ErrInvalidTerm } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/check.rl000066400000000000000000000034051450372207100226030ustar00rootroot00000000000000// Code generated by go generate gonum.org/v1/gonum/graph/formats/rdf; DO NOT EDIT. // Copyright ©2020 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 rdf import ( "fmt" "unicode" ) %%{ machine checkLabel; alphtype rune; include check "check_actions.rl"; alphtype rune; PN_CHARS_BASE = [A-Za-z] | 0x00c0 .. 0x00d6 | 0x00d8 .. 0x00f6 | 0x00f8 .. 0x02ff | 0x0370 .. 0x037d | 0x037f .. 0x1fff | 0x200c .. 0x200d | 0x2070 .. 0x218f | 0x2c00 .. 0x2fef | 0x3001 .. 0xd7ff | 0xf900 .. 0xfdcf | 0xfdf0 .. 0xfffd | 0x10000 .. 0xeffff ; PN_CHARS_U = PN_CHARS_BASE | '_' | ':' ; PN_CHARS = PN_CHARS_U | '-' | [0-9] | 0xb7 | 0x0300 .. 0x036f | 0x203f .. 0x2040 ; BLANK_NODE_LABEL = (PN_CHARS_U | [0-9]) ((PN_CHARS | '.')* PN_CHARS)? ; value := BLANK_NODE_LABEL %Return @!Error ; write data; }%% func checkLabelText(data []rune) (err error) { var ( cs, p int pe = len(data) eof = pe ) %%write init; %%write exec; return ErrInvalidTerm } %%{ machine checkLang; alphtype byte; include check "check_actions.rl"; LANGTAG = '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* ; value := LANGTAG %Return @!Error ; write data; }%% func checkLangText(data []byte) (err error) { var ( cs, p int pe = len(data) eof = pe ) %%write init; %%write exec; return ErrInvalidTerm } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/check_actions.rl000066400000000000000000000010241450372207100243160ustar00rootroot00000000000000// Copyright ©2020 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. %%{ machine check; action Return { return nil } action Error { if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return ErrIncompleteTerm } }%% golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/debug.go000066400000000000000000000030611450372207100226020ustar00rootroot00000000000000// Copyright ©2020 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:build debug // +build debug package rdf import ( "fmt" "os" "sort" "strings" "text/tabwriter" ) type debugger bool const debug debugger = true func (d debugger) log(depth int, args ...interface{}) { if !d { return } fmt.Fprint(os.Stderr, strings.Repeat("\t", depth)) fmt.Fprintln(os.Stderr, args...) } func (d debugger) logf(depth int, format string, args ...interface{}) { if !d { return } fmt.Fprint(os.Stderr, strings.Repeat("\t", depth)) fmt.Fprintf(os.Stderr, format, args...) } func (d debugger) logHashes(depth int, hashes map[string][]byte, size int) { if !d { return } prefix := strings.Repeat("\t", depth) if len(hashes) != 0 { keys := make([]string, len(hashes)) i := 0 for k := range hashes { keys[i] = k i++ } sort.Strings(keys) w := tabwriter.NewWriter(os.Stderr, 0, 4, 8, ' ', 0) for _, k := range keys { fmt.Fprintf(w, prefix+"%s\t%0*x\n", k, 2*size, hashes[k]) } w.Flush() } else { fmt.Fprintln(os.Stderr, prefix+"none") } fmt.Fprintln(os.Stderr) } func (d debugger) logParts(depth int, parts byLengthHash) { if !d { return } prefix := strings.Repeat("\t", depth) if parts.Len() != 0 { w := tabwriter.NewWriter(os.Stderr, 0, 4, 8, ' ', 0) for i, p := range parts.nodes { fmt.Fprintf(w, prefix+"%v\t%x\n", p, parts.hashes[i]) } w.Flush() } else { fmt.Fprintln(os.Stderr, prefix+"none") } fmt.Fprintln(os.Stderr) } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/disjoint_set.go000066400000000000000000000021401450372207100242070ustar00rootroot00000000000000// Copyright ©2020 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 rdf // djSet implements a disjoint set finder using the union-find algorithm. type djSet map[string]*dsNode // add adds e to the collection of sets held by the disjoint set. func (s djSet) add(e string) { if _, ok := s[e]; ok { return } s[e] = &dsNode{} } // union joins two sets a and b within the collection of sets held by // the disjoint set. func (djSet) union(a, b *dsNode) { ra := find(a) rb := find(b) if ra == rb { return } if ra.rank < rb.rank { ra.parent = rb return } rb.parent = ra if ra.rank == rb.rank { ra.rank++ } } // find returns the root of the set containing e. func (s djSet) find(e string) *dsNode { n, ok := s[e] if !ok { return nil } return find(n) } // find returns the root of the set containing the set node, n. func find(n *dsNode) *dsNode { for ; n.parent != nil; n = n.parent { } return n } // dsNode is a disjoint set element. type dsNode struct { parent *dsNode rank int } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/doc.go000066400000000000000000000006411450372207100222620ustar00rootroot00000000000000// Copyright ©2020 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 rdf implements decoding the RDF 1.1 N-Quads line-based plain text // format for encoding an RDF dataset. // N-Quad parsing is performed as defined by http://www.w3.org/TR/n-quads/ package rdf // import "gonum.org/v1/gonum/graph/formats/rdf" golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/equi_canonical.go000066400000000000000000000324431450372207100244740ustar00rootroot00000000000000// Copyright ©2021 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 rdf import ( "errors" "sort" ) // Throughout, the comments refer to doi:10.1145/3068333 which should be // understood as a synonym for http://aidanhogan.com/docs/rdf-canonicalisation.pdf // although there are differences between the two, see http://aidanhogan.com/#errataH17. // Where there are differences, the document at http://aidanhogan.com/ is the // canonical truth. The DOI reference is referred to for persistence. // Lean returns an RDF core of g that entails g. If g contains any non-zero // labels, Lean will return a non-nil error and a core of g assuming no graph // labels exist. // // See http://aidanhogan.com/docs/rdf-canonicalisation.pdf for details of // the algorithm. func Lean(g []*Statement) ([]*Statement, error) { // BUG(kortschak): Graph leaning does not take into account graph label terms // since the formal semantics for a multiple graph data model have not been // defined. See https://www.w3.org/TR/rdf11-datasets/#declaring. var ( hasBlanks bool err error ) for _, s := range g { if isBlank(s.Subject.Value) || isBlank(s.Object.Value) { hasBlanks = true if err != nil { break } } if s.Label.Value != "" && err == nil { err = errors.New("rdf: data-set contains graph names") if hasBlanks { break } } } if hasBlanks { g = lean(&dfs{}, g) } return g, err } // removeRedundantBnodes removes blank nodes whose edges are a subset of // another term in the RDF graph. // // This is algorithm 4 in doi:10.1145/3068333. func removeRedundantBnodes(g []*Statement) []*Statement { g = append(g[:0:0], g...) for { edges := make(map[string]map[triple]bool) for _, s := range g { for i, t := range []string{ s.Subject.Value, s.Object.Value, } { e, ok := edges[t] if !ok { e = make(map[triple]bool) edges[t] = e } switch i { case 0: e[triple{s.Predicate.Value, s.Object.Value, "+"}] = true case 1: e[triple{s.Predicate.Value, s.Subject.Value, "-"}] = true } } } seen := make(map[string]bool) bNodes := make(map[string]bool) terms := make(map[string]bool) for _, s := range g { for _, t := range []string{ s.Subject.Value, s.Predicate.Value, s.Object.Value, } { terms[t] = true if isBlank(t) { bNodes[t] = true } else { seen[t] = true } } } redundant := make(map[string]bool) for x := range bNodes { for xp := range terms { if isProperSubset(edges[x], edges[xp]) || (seen[xp] && isEqualEdges(edges[x], edges[xp])) { redundant[x] = true break } } seen[x] = true } n := len(g) for i := 0; i < len(g); { if !redundant[g[i].Subject.Value] && !redundant[g[i].Object.Value] { i++ continue } g[i], g = g[len(g)-1], g[:len(g)-1] } if n == len(g) { return g } } } type triple [3]string func isProperSubset(a, b map[triple]bool) bool { for k := range a { if !b[k] { return false } } return len(a) < len(b) } func isEqualEdges(a, b map[triple]bool) bool { if len(a) != len(b) { return false } for k := range a { if !b[k] { return false } } return true } // findCandidates finds candidates for blank nodes and blank nodes that are fixed. // // This is algorithm 5 in doi:10.1145/3068333. func findCandidates(g []*Statement) ([]*Statement, map[string]bool, map[string]map[string]bool, bool) { g = removeRedundantBnodes(g) edges := make(map[triple]bool) f := make(map[string]bool) for _, s := range g { sub := s.Subject.Value prd := s.Predicate.Value obj := s.Object.Value edges[triple{sub, prd, obj}] = true edges[triple{sub, prd, "*"}] = true edges[triple{"*", prd, obj}] = true switch { case isBlank(sub) && isBlank(obj): f[sub] = false f[obj] = false case isBlank(sub): if _, ok := f[sub]; !ok { f[sub] = true } case isBlank(obj): if _, ok := f[obj]; !ok { f[obj] = true } } } for k, v := range f { if !v { delete(f, k) } } if len(f) == 0 { f = nil } cands := make(map[string]map[string]bool) bnodes := make(map[string]bool) for _, s := range g { for _, b := range []string{ s.Subject.Value, s.Object.Value, } { if !isBlank(b) { continue } bnodes[b] = true if f[b] { cands[b] = map[string]bool{b: true} } else { terms := make(map[string]bool) for _, s := range g { for _, t := range []string{ s.Subject.Value, s.Predicate.Value, s.Object.Value, } { terms[t] = true } } cands[b] = terms } } } if isEqualTerms(f, bnodes) { return g, f, cands, true } for { bb := make(map[string]bool) for b := range bnodes { if !f[b] { bb[b] = true } } for b := range bb { for x := range cands[b] { if x == b { continue } for _, s := range g { if s.Subject.Value != b { continue } prd := s.Predicate.Value obj := s.Object.Value if (inILF(obj, f) && !edges[triple{x, prd, obj}]) || (bb[obj] && !edges[triple{x, prd, "*"}]) { delete(cands[b], x) break } } if !cands[b][x] { continue } for _, s := range g { if s.Object.Value != b { continue } sub := s.Subject.Value prd := s.Predicate.Value if (inIF(sub, f) && !edges[triple{sub, prd, x}]) || (bb[sub] && !edges[triple{"*", prd, x}]) { delete(cands[b], x) break } } } } fp := f f = make(map[string]bool) for b := range fp { f[b] = true } for b := range bb { // Mark newly fixed blank nodes. if len(cands[b]) == 1 && cands[b][b] { f[b] = true } } allFixed := isEqualTerms(f, bnodes) if isEqualTerms(fp, f) || allFixed { if len(f) == 0 { f = nil } return g, f, cands, allFixed } } } // inILF returns whether t is in IL or F. func inILF(t string, f map[string]bool) bool { return isIRI(t) || isLiteral(t) || f[t] } // inIF returns whether t is in I or F. func inIF(t string, f map[string]bool) bool { return isIRI(t) || f[t] } // dfs is a depth-first search strategy. type dfs struct{} // lean returns a core of the RDF graph g using the given strategy. // // This is lines 1-9 of algorithm 6 in doi:10.1145/3068333. func lean(strategy *dfs, g []*Statement) []*Statement { foundBnode := false search: for _, s := range g { for _, t := range []string{ s.Subject.Value, s.Object.Value, } { if isBlank(t) { foundBnode = true break search } } } if !foundBnode { return g } g, fixed, cands, allFixed := findCandidates(g) if allFixed { return g } for _, s := range g { if isBlank(s.Subject.Value) && isBlank(s.Object.Value) { mu := make(map[string]string, len(fixed)) for b := range fixed { mu[b] = b } mu = findCoreEndomorphism(strategy, g, cands, mu) return applyMu(g, mu) } } return g } // findCoreEndomorphism returns a core solution using the given strategy. // // This is lines 10-14 of algorithm 6 in doi:10.1145/3068333. func findCoreEndomorphism(strategy *dfs, g []*Statement, cands map[string]map[string]bool, mu map[string]string) map[string]string { var q []*Statement preds := make(map[string]int) seen := make(map[triple]bool) for _, s := range g { preds[s.Predicate.Value]++ if isBlank(s.Subject.Value) && isBlank(s.Object.Value) { if seen[triple{s.Subject.Value, s.Predicate.Value, s.Object.Value}] { continue } seen[triple{s.Subject.Value, s.Predicate.Value, s.Object.Value}] = true q = append(q, s) } } sort.Slice(q, func(i, j int) bool { return selectivity(q[i], cands, preds) < selectivity(q[j], cands, preds) }) return strategy.evaluate(g, q, cands, mu) } // selectivity returns the selectivity heuristic score for s. Lower scores // are more selective. func selectivity(s *Statement, cands map[string]map[string]bool, preds map[string]int) int { return min(len(cands[s.Subject.Value])*len(cands[s.Object.Value]), preds[s.Predicate.Value]) } // evaluate returns an endomorphism using a DFS strategy. // // This is lines 25-32 of algorithm 6 in doi:10.1145/3068333. func (st *dfs) evaluate(g, q []*Statement, cands map[string]map[string]bool, mu map[string]string) map[string]string { mu = st.search(g, q, cands, mu) for len(mu) != len(codom(mu)) { mupp := fixedFrom(cands) mup := findCoreEndomorphism(st, applyMu(g, mu), cands, mupp) if isAutomorphism(mup) { return mu } for b, x := range mu { if _, ok := mup[b]; !ok { mup[b] = x } } mu = mup } return mu } func fixedFrom(cands map[string]map[string]bool) map[string]string { fixed := make(map[string]string) for b, m := range cands { if len(m) == 1 && m[b] { fixed[b] = b } } return fixed } // applyMu applies mu to g returning the result. func applyMu(g []*Statement, mu map[string]string) []*Statement { back := make([]Statement, 0, len(g)) dst := make([]*Statement, 0, len(g)) seen := make(map[Statement]bool) for _, s := range g { n := Statement{ Subject: Term{Value: translate(s.Subject.Value, mu)}, Predicate: Term{Value: s.Predicate.Value}, Object: Term{Value: translate(s.Object.Value, mu)}, Label: Term{Value: s.Label.Value}, } if seen[n] { continue } seen[n] = true back = append(back, n) dst = append(dst, &back[len(back)-1]) } return dst } // search returns a minimum endomorphism using a DFS strategy. // // This is lines 33-46 of algorithm 6 in doi:10.1145/3068333. func (st *dfs) search(g, q []*Statement, cands map[string]map[string]bool, mu map[string]string) map[string]string { qMin := q[0] m := st.join(qMin, g, cands, mu) if len(m) == 0 { // Early exit if no mapping found. return nil } sortByCodom(m) mMin := m[0] qp := q[1:] if len(qp) != 0 { for len(m) != 0 { mMin = m[0] mup := st.search(g, qp, cands, mMin) if !isAutomorphism(mup) { return mup } m = m[1:] } } return mMin } // isAutomorphism returns whether mu is an automorphism, this is equivalent to // dom(mu) == codom(mu). func isAutomorphism(mu map[string]string) bool { return isEqualTerms(dom(mu), codom(mu)) } // dom returns the domain of mu. func dom(mu map[string]string) map[string]bool { d := make(map[string]bool, len(mu)) for v := range mu { d[v] = true } return d } // codom returns the codomain of mu. func codom(mu map[string]string) map[string]bool { cd := make(map[string]bool, len(mu)) for _, v := range mu { cd[v] = true } return cd } // isEqualTerms returns whether a and b are identical. func isEqualTerms(a, b map[string]bool) bool { if len(a) != len(b) { return false } for k := range a { if !b[k] { return false } } return true } // sortByCodom performs a sort of maps ordered by fewest blank nodes in // codomain, then fewest self mappings. func sortByCodom(maps []map[string]string) { m := orderedByCodom{ maps: maps, attrs: make([]attrs, len(maps)), } for i, mu := range maps { m.attrs[i].blanks = make(map[string]bool) for x, y := range mu { if isBlank(y) { m.attrs[i].blanks[y] = true } if x == y { m.attrs[i].selfs++ } } } sort.Sort(m) } type orderedByCodom struct { maps []map[string]string attrs []attrs } type attrs struct { blanks map[string]bool selfs int } func (m orderedByCodom) Len() int { return len(m.maps) } func (m orderedByCodom) Less(i, j int) bool { attrI := m.attrs[i] attrJ := m.attrs[j] switch { case len(attrI.blanks) < len(attrJ.blanks): return true case len(attrI.blanks) > len(attrJ.blanks): return false default: return attrI.selfs < attrJ.selfs } } func (m orderedByCodom) Swap(i, j int) { m.maps[i], m.maps[j] = m.maps[j], m.maps[i] m.attrs[i], m.attrs[j] = m.attrs[j], m.attrs[i] } // join evaluates the given pattern, q, joining with solutions in m. // This takes only a single mapping and so only works for the DFS strategy. // // This is lines 47-51 of algorithm 6 in doi:10.1145/3068333. func (st *dfs) join(q *Statement, g []*Statement, cands map[string]map[string]bool, m map[string]string) []map[string]string { var mp []map[string]string isLoop := q.Subject.Value == q.Object.Value for _, s := range g { // Line 45: M_q ← {µ | µ(q) ∈ G} // | µ(q) ∈ G // // µ(q) ∈ G ↔ (µ(q_s),q_p,µ(q_o)) ∈ G if q.Predicate.Value != s.Predicate.Value { continue } // q_s = q_o ↔ µ(q_s) =_µ(q_o) if isLoop && s.Subject.Value != s.Object.Value { continue } // Line 46: M_q' ← {µ ∈ M_q | for all b ∈ bnodes({q}), µ(b) ∈ cands[b]} // | for all b ∈ bnodes({q}), µ(b) ∈ cands[b] if !cands[q.Subject.Value][s.Subject.Value] || !cands[q.Object.Value][s.Object.Value] { continue } // Line 47: M' ← M_q' ⋈ M // M₁ ⋈ M₂ = {μ₁ ∪ μ₂ | μ₁ ∈ M₁, μ₂ ∈ M₂ and μ₁, μ₂ are compatible mappings} // | μ₁ ∈ M₁, μ₂ ∈ M₂ and μ₁, μ₂ are compatible mappings if mq, ok := m[q.Subject.Value]; ok && mq != s.Subject.Value { continue } if !isLoop { if mq, ok := m[q.Object.Value]; ok && mq != s.Object.Value { continue } } // Line 47: μ₁ ∪ μ₂ var mu map[string]string if isLoop { mu = map[string]string{ q.Subject.Value: s.Subject.Value, } } else { mu = map[string]string{ q.Subject.Value: s.Subject.Value, q.Object.Value: s.Object.Value, } } for b, mb := range m { mu[b] = mb } mp = append(mp, mu) } return mp } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/equi_canonical_example_test.go000066400000000000000000000075101450372207100272430ustar00rootroot00000000000000// Copyright ©2021 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 rdf_test import ( "fmt" "strings" "gonum.org/v1/gonum/graph/formats/rdf" ) func ExampleLean() { for i, statements := range []string{ 0: ` _:author1 _:go . _:author2 _:go . _:author2 _:gonum . _:author3 _:gonum . `, 1: ` _:author1 _:go . _:author2 _:go . _:author2 _:gonum . _:author3 _:gonum . _:gonum _:go . `, 2: ` _:author1 _:go . _:author1 _:gonum . _:author2 _:go . _:author2 _:gonum . _:author3 _:gonum . _:gonum _:go . `, 3: ` _:author1 "Alice" . _:author1 _:go . _:author2 _:go . _:author2 _:gonum . _:author3 _:gonum . _:gonum _:go . `, 4: ` _:author1 _:go . _:author1 _:gonum . _:author2 _:go . _:author2 _:gonum . _:author3 _:gonum . _:author3 _:go . _:gonum _:go . `, 5: ` _:author1 "Alice" . _:author2 "Bob" . _:author1 _:go . _:author2 _:go . _:author2 _:gonum . _:author3 _:gonum . _:gonum _:go . `, 6: ` _:author1 "Alice" . _:author2 "Bob" . _:author3 "Charlie" . _:author1 _:go . _:author2 _:go . _:author2 _:gonum . _:author3 _:gonum . _:gonum _:go . `, } { // Decode the statement stream. dec := rdf.NewDecoder(strings.NewReader(statements)) var s []*rdf.Statement for { l, err := dec.Unmarshal() if err != nil { break } s = append(s, l) } // Lean the graph to remove redundant statements. lean, err := rdf.Lean(s) if err != nil { fmt.Println(err) } // Canonicalize the blank nodes in-place. _, err = rdf.URDNA2015(lean, lean) if err != nil { fmt.Println(err) continue } fmt.Printf("%d:\n", i) for _, s := range lean { fmt.Println(s) } fmt.Println() } // Output: // // 0: // _:c14n0 _:c14n1 . // // 1: // _:c14n0 _:c14n1 . // _:c14n0 _:c14n2 . // _:c14n2 _:c14n1 . // // 2: // _:c14n0 _:c14n1 . // _:c14n0 _:c14n3 . // _:c14n2 _:c14n1 . // _:c14n2 _:c14n3 . // _:c14n3 _:c14n1 . // // 3: // _:c14n0 _:c14n1 . // _:c14n0 _:c14n3 . // _:c14n2 _:c14n1 . // _:c14n2 "Alice" . // _:c14n3 _:c14n1 . // // 4: // _:c14n0 _:c14n1 . // _:c14n0 _:c14n2 . // _:c14n2 _:c14n1 . // _:c14n3 _:c14n1 . // _:c14n3 _:c14n2 . // _:c14n4 _:c14n2 . // _:c14n4 _:c14n1 . // // 5: // _:c14n1 _:c14n0 . // _:c14n1 _:c14n3 . // _:c14n1 "Bob" . // _:c14n2 _:c14n0 . // _:c14n2 "Alice" . // _:c14n3 _:c14n0 . // // 6: // _:c14n0 _:c14n1 . // _:c14n2 _:c14n0 . // _:c14n2 _:c14n1 . // _:c14n2 "Bob" . // _:c14n3 _:c14n1 . // _:c14n3 "Alice" . // _:c14n4 _:c14n0 . // _:c14n4 "Charlie" . } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/equi_canonical_test.go000066400000000000000000000520721450372207100255330ustar00rootroot00000000000000// Copyright ©2021 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 rdf import ( "fmt" "io" "reflect" "strings" "testing" ) func TestRemoveRedundantNodes(t *testing.T) { tests := []struct { name string statements string want string }{ { name: "Example 5.1", statements: ` _:b1 . _:b2 . _:b3 . _:b4 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b2 "23" . _:b3 "23" . `, want: ` _:b3 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b3 "23" . `, }, { name: "Example 5.2", statements: ` _:a _:b . _:a _:d . _:c _:b . _:c _:f . _:e _:b . _:e _:d . _:e _:f . _:e _:h . _:g _:d . _:g _:h . _:i _:f . _:i _:h . `, want: `_:e _:b . `, }, } for _, test := range tests { g := parseStatements(strings.NewReader(test.statements)) gWant := parseStatements(strings.NewReader(test.want)) g = removeRedundantBnodes(g) got := canonicalStatements(g) want := canonicalStatements(gWant) if got != want { got = formatStatements(g) t.Errorf("unexpected result for %s:\ngot: \n%s\nwant:\n%s", test.name, got, test.want) } } } func TestFindCandidates(t *testing.T) { tests := []struct { name string statements string want string wantFixed []map[string]bool wantAllFixed bool wantCands []map[string]map[string]bool }{ { name: "Example 5.1", statements: ` _:b1 . _:b2 . _:b3 . _:b4 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b2 "23" . _:b3 "23" . `, want: ` _:b3 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b3 "23" . `, // Hence, in this particular case, we have managed to fix all blank // nodes, and the graph is thus lean, and we need to go no further. // In other cases we will look at later, however, some blank nodes // may maintain multiple candidates. // // Note that there are two valid labellings of the graph since _:b2 // and _:b3 are not distinguishable. wantFixed: []map[string]bool{ { "_:a1": true, "_:a2": true, "_:a3": true, "_:a4": true, "_:b2": true, "_:c": true, }, { "_:a1": true, "_:a2": true, "_:a3": true, "_:a4": true, "_:b3": true, "_:c": true, }, }, wantAllFixed: true, wantCands: []map[string]map[string]bool{ { "_:a1": {"_:a1": true}, "_:a2": {"_:a2": true}, "_:a3": {"_:a3": true}, "_:a4": {"_:a4": true}, "_:b2": {"_:b2": true}, "_:c": {"_:c": true}, }, { "_:a1": {"_:a1": true}, "_:a2": {"_:a2": true}, "_:a3": {"_:a3": true}, "_:a4": {"_:a4": true}, "_:b3": {"_:b3": true}, "_:c": {"_:c": true}, }, }, }, { name: "Example 5.6", // This is 5.1, but simplified. statements: ` _:b3 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b3 "23" . `, want: ` _:b3 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b3 "23" . `, // Hence, in this particular case, we have managed to fix all blank // nodes, and the graph is thus lean, and we need to go no further. // In other cases we will look at later, however, some blank nodes // may maintain multiple candidates. wantFixed: []map[string]bool{{ "_:a1": true, "_:a2": true, "_:a3": true, "_:a4": true, "_:b3": true, "_:c": true, }}, wantAllFixed: true, wantCands: []map[string]map[string]bool{{ "_:a1": {"_:a1": true}, "_:a2": {"_:a2": true}, "_:a3": {"_:a3": true}, "_:a4": {"_:a4": true}, "_:b3": {"_:b3": true}, "_:c": {"_:c": true}, }}, }, { name: "Example 5.9", statements: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, want: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, wantFixed: []map[string]bool{nil}, wantAllFixed: true, wantCands: []map[string]map[string]bool{{ "_:a1": {"_:a1": true, "_:a2": true, "_:a3": true}, "_:a2": {"_:a2": true, "_:a3": true}, "_:a3": {"_:a2": true, "_:a3": true}, "_:a4": {"_:a2": true, "_:a3": true, "_:a4": true}, }}, }, { name: "Example 5.10", statements: ` _:a _:b . _:a _:d . _:b _:e . _:c _:b . _:c _:f . _:d _:e . _:f _:e . _:g _:d . _:g _:h . _:h _:e . _:i _:f . _:i _:h . `, want: `_:a _:b . _:a _:d . _:b _:e . _:c _:b . _:c _:f . _:d _:e . _:f _:e . _:g _:d . _:g _:h . _:h _:e . _:i _:f . _:i _:h . `, wantFixed: []map[string]bool{{"_:e": true}}, wantAllFixed: false, wantCands: []map[string]map[string]bool{{ "_:a": {"_:a": true, "_:c": true, "_:g": true, "_:i": true}, "_:b": {"_:b": true, "_:d": true, "_:f": true, "_:h": true}, "_:c": {"_:a": true, "_:c": true, "_:g": true, "_:i": true}, "_:d": {"_:b": true, "_:d": true, "_:f": true, "_:h": true}, "_:e": {"_:e": true}, "_:f": {"_:b": true, "_:d": true, "_:f": true, "_:h": true}, "_:g": {"_:a": true, "_:c": true, "_:g": true, "_:i": true}, "_:h": {"_:b": true, "_:d": true, "_:f": true, "_:h": true}, "_:i": {"_:a": true, "_:c": true, "_:g": true, "_:i": true}, }}, }, } for _, test := range tests[:1] { g := parseStatements(strings.NewReader(test.statements)) gWant := parseStatements(strings.NewReader(test.want)) g, fixed, cands, allFixed := findCandidates(g) got := canonicalStatements(g) want := canonicalStatements(gWant) if got != want { got = formatStatements(g) t.Errorf("unexpected result for %s:\ngot: \n%s\nwant:\n%s", test.name, got, test.want) } matchedFixed := false for _, wantFixed := range test.wantFixed { if reflect.DeepEqual(fixed, wantFixed) { matchedFixed = true break } } if !matchedFixed { t.Errorf("unexpected fixed result for %s:\ngot: \n%v\nwant:\n%v", test.name, fixed, test.wantFixed) } if allFixed != test.wantAllFixed { t.Errorf("unexpected all-fixed result for %s:\ngot:%t\nwant:%t", test.name, allFixed, test.wantAllFixed) } matchedCands := false for _, wantCands := range test.wantCands { if reflect.DeepEqual(cands, wantCands) { matchedCands = true break } } if !matchedCands { t.Errorf("unexpected candidates result for %s:\ngot: \n%v\nwant:\n%v", test.name, cands, test.wantCands) } } } func TestLean(t *testing.T) { var tests = []struct { name string statements string want string wantErr error }{ { name: "Example 5.1", statements: ` _:b1 . _:b2 . _:b3 . _:b4 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b2 "23" . _:b3 "23" . `, want: ` _:b3 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b3 "23" . `, }, { name: "Example 5.6", statements: ` _:b3 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b3 "23" . `, want: ` _:b3 . _:a1 . _:a2 . _:a3 . _:a4 . _:c . _:a1 _:a2 . _:a2 _:a3 . _:a2 . _:a3 _:a4 . _:a4 . _:b3 "23" . `, }, { name: "Example 5.9", statements: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, want: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, }, { name: "Example 5.10", statements: ` _:a _:b . _:a _:d . _:b _:e . _:c _:b . _:c _:f . _:d _:e . _:f _:e . _:g _:d . _:g _:h . _:h _:e . _:i _:f . _:i _:h . `, want: `_:a _:b . _:b _:e . `, }, { name: "Example 5.10 halved", statements: ` _:a _:b . _:a _:d . _:b _:e . _:c _:b . _:c _:f . _:d _:e . _:f _:e . `, want: `_:a _:b . _:b _:e . `, }, { name: "Example 5.10 quartered", statements: ` _:a _:b . _:a _:d . _:b _:e . _:d _:e . `, want: `_:a _:b . _:b _:e . `, }, } for _, test := range tests { g := parseStatements(strings.NewReader(test.statements)) gWant := parseStatements(strings.NewReader(test.want)) lean, err := Lean(g) if err != test.wantErr { t.Errorf("unexpected error for %v: got:%v want:%v", test.name, err, test.wantErr) } got := canonicalStatements(lean) want := canonicalStatements(gWant) if got != want { got = formatStatements(g) t.Errorf("unexpected result for %s:\ngot: \n%s\nwant:\n%s", test.name, got, test.want) } } } func TestJoin(t *testing.T) { var tests = []struct { name string q string statements string cands map[string]map[string]bool mu map[string]string want []map[string]string }{ { name: "Identity", q: `_:a _:b .`, statements: ` _:a _:b . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true}, "_:b": {"_:b": true}, }, mu: nil, want: []map[string]string{ {"_:a": "_:a", "_:b": "_:b"}, }, }, { name: "Cross identity", q: `_:a _:b .`, statements: ` _:a _:b . _:b _:a . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: nil, want: []map[string]string{ {"_:a": "_:a", "_:b": "_:b"}, {"_:a": "_:b", "_:b": "_:a"}, }, }, { name: "Cross identity with restriction", q: `_:a _:b .`, statements: ` _:a _:b . _:b _:a . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: map[string]string{"_:a": "_:a"}, want: []map[string]string{ {"_:a": "_:a", "_:b": "_:b"}, }, }, { name: "Cross identity with complete restriction", q: `_:a _:b .`, statements: ` _:a _:b . _:b _:a . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: map[string]string{"_:a": "_:a", "_:b": "_:a"}, want: nil, }, { name: "Cross identity with extension", q: `_:a _:b .`, statements: ` _:a _:b . _:b _:a . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: map[string]string{"_:c": "_:a"}, want: []map[string]string{ {"_:a": "_:a", "_:b": "_:b", "_:c": "_:a"}, {"_:a": "_:b", "_:b": "_:a", "_:c": "_:a"}, }, }, { name: "Loop", q: `_:a _:a .`, statements: ` _:a _:a . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true}, }, mu: nil, want: []map[string]string{ {"_:a": "_:a"}, }, }, { name: "Cross identity loop", q: `_:a _:a .`, statements: ` _:a _:a . _:b _:b . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: nil, want: []map[string]string{ {"_:a": "_:a"}, {"_:a": "_:b"}, }, }, { name: "Cross identity loop with restriction", q: `_:a _:a .`, statements: ` _:a _:a . _:b _:b . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: map[string]string{"_:a": "_:a"}, want: []map[string]string{ {"_:a": "_:a"}, }, }, { name: "Cross identity loop with complete restriction", q: `_:a _:a .`, statements: ` _:a _:a . _:b _:b . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: map[string]string{"_:a": "_:b", "_:b": "_:a"}, want: []map[string]string{ {"_:a": "_:b", "_:b": "_:a"}, }, }, { name: "Cross identity loop with extension", q: `_:a _:a .`, statements: ` _:a _:a . _:b _:b . `, cands: map[string]map[string]bool{ "_:a": {"_:a": true, "_:b": true}, "_:b": {"_:b": true, "_:a": true}, }, mu: map[string]string{"_:c": "_:a"}, want: []map[string]string{ {"_:a": "_:a", "_:c": "_:a"}, {"_:a": "_:b", "_:c": "_:a"}, }, }, { name: "Example 5.9 step 1", q: `_:a1 _:a2 .`, statements: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, cands: map[string]map[string]bool{ "_:a1": {"_:a1": true, "_:a2": true, "_:a3": true}, "_:a2": {"_:a2": true, "_:a3": true}, "_:a3": {"_:a2": true, "_:a3": true}, "_:a4": {"_:a2": true, "_:a3": true, "_:a4": true}, }, mu: map[string]string{}, want: []map[string]string{ {"_:a1": "_:a1", "_:a2": "_:a2"}, {"_:a1": "_:a2", "_:a2": "_:a3"}, }, }, { name: "Example 5.9 step 2", q: `_:a2 _:a3 .`, statements: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, cands: map[string]map[string]bool{ "_:a1": {"_:a1": true, "_:a2": true, "_:a3": true}, "_:a2": {"_:a2": true, "_:a3": true}, "_:a3": {"_:a2": true, "_:a3": true}, "_:a4": {"_:a2": true, "_:a3": true, "_:a4": true}, }, mu: map[string]string{"_:a1": "_:a2", "_:a2": "_:a3"}, want: nil, }, { name: "Example 5.9 step 3", q: `_:a2 _:a3 .`, statements: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, cands: map[string]map[string]bool{ "_:a1": {"_:a1": true, "_:a2": true, "_:a3": true}, "_:a2": {"_:a2": true, "_:a3": true}, "_:a3": {"_:a2": true, "_:a3": true}, "_:a4": {"_:a2": true, "_:a3": true, "_:a4": true}, }, mu: map[string]string{"_:a1": "_:a1", "_:a2": "_:a2"}, want: []map[string]string{ {"_:a1": "_:a1", "_:a2": "_:a2", "_:a3": "_:a3"}, }, }, { name: "Example 5.9 step 4", q: `_:a3 _:a4 .`, statements: ` _:a1 . _:a2 . _:a3 . _:a4 . _:a1 _:a2 . _:a2 _:a3 . _:a3 _:a4 . `, cands: map[string]map[string]bool{ "_:a1": {"_:a1": true, "_:a2": true, "_:a3": true}, "_:a2": {"_:a2": true, "_:a3": true}, "_:a3": {"_:a2": true, "_:a3": true}, "_:a4": {"_:a2": true, "_:a3": true, "_:a4": true}, }, mu: map[string]string{"_:a1": "_:a1", "_:a2": "_:a2", "_:a3": "_:a3"}, want: []map[string]string{ {"_:a1": "_:a1", "_:a2": "_:a2", "_:a3": "_:a3", "_:a4": "_:a4"}, }, }, } for _, test := range tests { q := parseStatement(strings.NewReader(test.q)) g := parseStatements(strings.NewReader(test.statements)) st := dfs{} got := st.join(q, g, test.cands, test.mu) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %s:\ngot:\n%#v\nwant:\n%#v", test.name, got, test.want) } naive := joinNaive(q, g, test.cands, []map[string]string{test.mu}) if !reflect.DeepEqual(naive, test.want) { t.Errorf("unexpected naive result for %s:\ngot:\n%#v\nwant:\n%#v", test.name, naive, test.want) } } } // joinNaive is a direct translation of lines 47-51 of algorithm 6 in doi:10.1145/3068333. func joinNaive(q *Statement, G []*Statement, cands map[string]map[string]bool, M []map[string]string) []map[string]string { isLoop := q.Subject.Value == q.Object.Value // Line 48: M_q ← {µ | µ(q) ∈ G} var M_q []map[string]string for _, s := range G { // µ(q) ∈ G ↔ (µ(q_s),q_p,µ(q_o)) ∈ G if q.Predicate.Value != s.Predicate.Value { continue } // q_s = q_o ↔ µ(q_s) =_µ(q_o) if isLoop && s.Subject.Value != s.Object.Value { continue } var µ map[string]string if isLoop { µ = map[string]string{ q.Subject.Value: s.Subject.Value, } } else { µ = map[string]string{ q.Subject.Value: s.Subject.Value, q.Object.Value: s.Object.Value, } } M_q = append(M_q, µ) } // Line 49: M_q' ← {µ ∈ M_q | for all b ∈ bnodes({q}), µ(b) ∈ cands[b]} var M_qPrime []map[string]string for _, µ := range M_q { if !cands[q.Subject.Value][µ[q.Subject.Value]] { continue } if !cands[q.Object.Value][µ[q.Object.Value]] { continue } M_qPrime = append(M_qPrime, µ) } // Line 50: M' ← M_q' ⋈ M // M₁ ⋈ M₂ = {μ₁ ∪ μ₂ | μ₁ ∈ M₁, μ₂ ∈ M₂ and μ₁, μ₂ are compatible mappings} var MPrime []map[string]string for _, µ := range M { join: for _, µ_qPrime := range M_qPrime { for b, x_qPrime := range µ_qPrime { if x, ok := µ[b]; ok && x != x_qPrime { continue join } } // Line 50: μ₁ ∪ μ₂ for b, x := range µ { µ_qPrime[b] = x } MPrime = append(MPrime, µ_qPrime) } } return MPrime } func parseStatement(r io.Reader) *Statement { g := parseStatements(r) if len(g) != 1 { panic(fmt.Sprintf("invalid statement stream length %d != 1", len(g))) } return g[0] } func parseStatements(r io.Reader) []*Statement { var g []*Statement dec := NewDecoder(r) for { s, err := dec.Unmarshal() if err != nil { if err == io.EOF { break } panic(err) } g = append(g, s) } return g } func canonicalStatements(g []*Statement) string { g, _ = URDNA2015(nil, g) return formatStatements(g) } func formatStatements(g []*Statement) string { var buf strings.Builder for _, s := range g { fmt.Fprintln(&buf, s) } return buf.String() } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/extract.go000066400000000000000000000453621450372207100232000ustar00rootroot00000000000000 //line extract.rl:1 // Code generated by go generate gonum.org/v1/gonum/graph/formats/rdf; DO NOT EDIT. // Copyright ©2020 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 rdf import ( "fmt" "unicode" ) //line extract.go:18 const extract_start int = 1 const extract_first_final int = 31 const extract_error int = 0 const extract_en_value int = 1 //line extract.rl:28 func extract(data []rune) (text, qual string, kind Kind, err error) { var ( cs, p int pe = len(data) eof = pe iri = -1 blank = -1 literal = -1 lang = -1 iriText string blankText string literalText string langText string ) //line extract.go:47 { cs = extract_start } //line extract.rl:48 //line extract.go:55 { if p == pe { goto _test_eof } switch cs { case 1: goto st_case_1 case 0: goto st_case_0 case 2: goto st_case_2 case 3: goto st_case_3 case 31: goto st_case_31 case 4: goto st_case_4 case 32: goto st_case_32 case 5: goto st_case_5 case 33: goto st_case_33 case 6: goto st_case_6 case 7: goto st_case_7 case 8: goto st_case_8 case 9: goto st_case_9 case 34: goto st_case_34 case 10: goto st_case_10 case 11: goto st_case_11 case 12: goto st_case_12 case 13: goto st_case_13 case 14: goto st_case_14 case 15: goto st_case_15 case 16: goto st_case_16 case 17: goto st_case_17 case 18: goto st_case_18 case 19: goto st_case_19 case 20: goto st_case_20 case 21: goto st_case_21 case 22: goto st_case_22 case 23: goto st_case_23 case 24: goto st_case_24 case 25: goto st_case_25 case 26: goto st_case_26 case 27: goto st_case_27 case 28: goto st_case_28 case 29: goto st_case_29 case 35: goto st_case_35 case 30: goto st_case_30 } goto st_out st_case_1: switch data[p] { case 34: goto st2 case 60: goto st8 case 95: goto st28 } goto tr0 tr0: //line extract_actions.rl:74 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return "", "", Invalid, fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return "", "", Invalid, fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return "", "", Invalid, ErrIncompleteTerm goto st0 //line extract.go:158 st_case_0: st0: cs = 0 goto _out st2: if p++; p == pe { goto _test_eof2 } st_case_2: switch data[p] { case 34: goto tr5 case 92: goto tr6 } switch { case data[p] < 11: if 0 <= data[p] && data[p] <= 9 { goto tr4 } case data[p] > 12: if 14 <= data[p] && data[p] <= 1114111 { goto tr4 } default: goto tr4 } goto tr0 tr4: //line extract_actions.rl:34 literal = p goto st3 st3: if p++; p == pe { goto _test_eof3 } st_case_3: //line extract.go:198 switch data[p] { case 34: goto tr8 case 92: goto st19 } switch { case data[p] < 11: if 0 <= data[p] && data[p] <= 9 { goto st3 } case data[p] > 12: if 14 <= data[p] && data[p] <= 1114111 { goto st3 } default: goto st3 } goto tr0 tr5: //line extract_actions.rl:34 literal = p //line extract_actions.rl:38 if literal < 0 { panic("unexpected parser state: literal start not set") } literalText = unEscape(data[literal:p]) kind = Literal goto st31 tr8: //line extract_actions.rl:38 if literal < 0 { panic("unexpected parser state: literal start not set") } literalText = unEscape(data[literal:p]) kind = Literal goto st31 st31: if p++; p == pe { goto _test_eof31 } st_case_31: //line extract.go:247 switch data[p] { case 64: goto tr39 case 94: goto st6 } goto st0 tr39: //line extract_actions.rl:46 lang = p goto st4 st4: if p++; p == pe { goto _test_eof4 } st_case_4: //line extract.go:266 switch { case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st32 } case data[p] >= 65: goto st32 } goto tr0 st32: if p++; p == pe { goto _test_eof32 } st_case_32: if data[p] == 45 { goto st5 } switch { case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st32 } case data[p] >= 65: goto st32 } goto st0 st5: if p++; p == pe { goto _test_eof5 } st_case_5: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st33 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st33 } default: goto st33 } goto tr0 st33: if p++; p == pe { goto _test_eof33 } st_case_33: if data[p] == 45 { goto st5 } switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st33 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st33 } default: goto st33 } goto st0 st6: if p++; p == pe { goto _test_eof6 } st_case_6: if data[p] == 94 { goto st7 } goto tr0 st7: if p++; p == pe { goto _test_eof7 } st_case_7: if data[p] == 60 { goto st8 } goto tr0 st8: if p++; p == pe { goto _test_eof8 } st_case_8: switch data[p] { case 62: goto tr14 case 92: goto tr15 case 95: goto tr13 case 126: goto tr13 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto tr13 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto tr13 } case data[p] >= 97: goto tr13 } default: goto tr13 } goto tr0 tr13: //line extract_actions.rl:8 iri = p goto st9 st9: if p++; p == pe { goto _test_eof9 } st_case_9: //line extract.go:394 switch data[p] { case 62: goto tr17 case 92: goto st10 case 95: goto st9 case 126: goto st9 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto st9 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto st9 } case data[p] >= 97: goto st9 } default: goto st9 } goto tr0 tr14: //line extract_actions.rl:8 iri = p //line extract_actions.rl:12 if iri < 0 { panic("unexpected parser state: iri start not set") } iriText = unEscape(data[iri:p]) if kind == Invalid { kind = IRI } goto st34 tr17: //line extract_actions.rl:12 if iri < 0 { panic("unexpected parser state: iri start not set") } iriText = unEscape(data[iri:p]) if kind == Invalid { kind = IRI } goto st34 st34: if p++; p == pe { goto _test_eof34 } st_case_34: //line extract.go:456 goto st0 tr15: //line extract_actions.rl:8 iri = p goto st10 st10: if p++; p == pe { goto _test_eof10 } st_case_10: //line extract.go:469 switch data[p] { case 85: goto st11 case 117: goto st15 } goto tr0 st11: if p++; p == pe { goto _test_eof11 } st_case_11: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st12 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st12 } default: goto st12 } goto tr0 st12: if p++; p == pe { goto _test_eof12 } st_case_12: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st13 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st13 } default: goto st13 } goto tr0 st13: if p++; p == pe { goto _test_eof13 } st_case_13: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st14 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st14 } default: goto st14 } goto tr0 st14: if p++; p == pe { goto _test_eof14 } st_case_14: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st15 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st15 } default: goto st15 } goto tr0 st15: if p++; p == pe { goto _test_eof15 } st_case_15: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st16 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st16 } default: goto st16 } goto tr0 st16: if p++; p == pe { goto _test_eof16 } st_case_16: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st17 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st17 } default: goto st17 } goto tr0 st17: if p++; p == pe { goto _test_eof17 } st_case_17: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st18 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st18 } default: goto st18 } goto tr0 st18: if p++; p == pe { goto _test_eof18 } st_case_18: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st9 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st9 } default: goto st9 } goto tr0 tr6: //line extract_actions.rl:34 literal = p goto st19 st19: if p++; p == pe { goto _test_eof19 } st_case_19: //line extract.go:632 switch data[p] { case 34: goto st3 case 39: goto st3 case 85: goto st20 case 92: goto st3 case 98: goto st3 case 102: goto st3 case 110: goto st3 case 114: goto st3 case 116: goto st3 case 117: goto st24 } goto tr0 st20: if p++; p == pe { goto _test_eof20 } st_case_20: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st21 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st21 } default: goto st21 } goto tr0 st21: if p++; p == pe { goto _test_eof21 } st_case_21: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st22 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st22 } default: goto st22 } goto tr0 st22: if p++; p == pe { goto _test_eof22 } st_case_22: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st23 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st23 } default: goto st23 } goto tr0 st23: if p++; p == pe { goto _test_eof23 } st_case_23: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st24 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st24 } default: goto st24 } goto tr0 st24: if p++; p == pe { goto _test_eof24 } st_case_24: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st25 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st25 } default: goto st25 } goto tr0 st25: if p++; p == pe { goto _test_eof25 } st_case_25: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st26 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st26 } default: goto st26 } goto tr0 st26: if p++; p == pe { goto _test_eof26 } st_case_26: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st27 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st27 } default: goto st27 } goto tr0 st27: if p++; p == pe { goto _test_eof27 } st_case_27: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st3 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st3 } default: goto st3 } goto tr0 st28: if p++; p == pe { goto _test_eof28 } st_case_28: if data[p] == 58 { goto st29 } goto tr0 st29: if p++; p == pe { goto _test_eof29 } st_case_29: if data[p] == 95 { goto tr36 } switch { case data[p] < 895: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto tr36 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto tr36 } default: goto tr36 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto tr36 } case data[p] > 767: if 880 <= data[p] && data[p] <= 893 { goto tr36 } default: goto tr36 } default: goto tr36 } case data[p] > 8191: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8204 <= data[p] && data[p] <= 8205 { goto tr36 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto tr36 } default: goto tr36 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto tr36 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto tr36 } default: goto tr36 } default: goto tr36 } default: goto tr36 } goto tr0 tr36: //line extract_actions.rl:22 blank = p goto st35 st35: if p++; p == pe { goto _test_eof35 } st_case_35: //line extract.go:895 switch data[p] { case 45: goto st35 case 46: goto st30 case 95: goto st35 case 183: goto st35 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st35 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st35 } default: goto st35 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st35 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st35 } default: goto st35 } default: goto st35 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st35 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st35 } default: goto st35 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st35 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st35 } default: goto st35 } default: goto st35 } default: goto st35 } goto st0 st30: if p++; p == pe { goto _test_eof30 } st_case_30: switch data[p] { case 45: goto st35 case 46: goto st30 case 95: goto st35 case 183: goto st35 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st35 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st35 } default: goto st35 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st35 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st35 } default: goto st35 } default: goto st35 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st35 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st35 } default: goto st35 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st35 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st35 } default: goto st35 } default: goto st35 } default: goto st35 } goto tr0 st_out: _test_eof2: cs = 2; goto _test_eof _test_eof3: cs = 3; goto _test_eof _test_eof31: cs = 31; goto _test_eof _test_eof4: cs = 4; goto _test_eof _test_eof32: cs = 32; goto _test_eof _test_eof5: cs = 5; goto _test_eof _test_eof33: cs = 33; goto _test_eof _test_eof6: cs = 6; goto _test_eof _test_eof7: cs = 7; goto _test_eof _test_eof8: cs = 8; goto _test_eof _test_eof9: cs = 9; goto _test_eof _test_eof34: cs = 34; goto _test_eof _test_eof10: cs = 10; goto _test_eof _test_eof11: cs = 11; goto _test_eof _test_eof12: cs = 12; goto _test_eof _test_eof13: cs = 13; goto _test_eof _test_eof14: cs = 14; goto _test_eof _test_eof15: cs = 15; goto _test_eof _test_eof16: cs = 16; goto _test_eof _test_eof17: cs = 17; goto _test_eof _test_eof18: cs = 18; goto _test_eof _test_eof19: cs = 19; goto _test_eof _test_eof20: cs = 20; goto _test_eof _test_eof21: cs = 21; goto _test_eof _test_eof22: cs = 22; goto _test_eof _test_eof23: cs = 23; goto _test_eof _test_eof24: cs = 24; goto _test_eof _test_eof25: cs = 25; goto _test_eof _test_eof26: cs = 26; goto _test_eof _test_eof27: cs = 27; goto _test_eof _test_eof28: cs = 28; goto _test_eof _test_eof29: cs = 29; goto _test_eof _test_eof35: cs = 35; goto _test_eof _test_eof30: cs = 30; goto _test_eof _test_eof: {} if p == eof { switch cs { case 31, 34: //line extract_actions.rl:57 switch kind { case IRI: return iriText, "", kind, nil case Blank: return blankText, "", kind, nil case Literal: qual = iriText if qual == "" { qual = langText } return literalText, qual, kind, nil default: return "", "", kind, ErrInvalidTerm } case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30: //line extract_actions.rl:74 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return "", "", Invalid, fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return "", "", Invalid, fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return "", "", Invalid, ErrIncompleteTerm case 35: //line extract_actions.rl:26 if blank < 0 { panic("unexpected parser state: blank start not set") } blankText = string(data[blank:p]) kind = Blank //line extract_actions.rl:57 switch kind { case IRI: return iriText, "", kind, nil case Blank: return blankText, "", kind, nil case Literal: qual = iriText if qual == "" { qual = langText } return literalText, qual, kind, nil default: return "", "", kind, ErrInvalidTerm } case 32, 33: //line extract_actions.rl:50 if lang < 0 { panic("unexpected parser state: lang start not set") } langText = string(data[lang:p]) //line extract_actions.rl:57 switch kind { case IRI: return iriText, "", kind, nil case Blank: return blankText, "", kind, nil case Literal: qual = iriText if qual == "" { qual = langText } return literalText, qual, kind, nil default: return "", "", kind, ErrInvalidTerm } //line extract.go:1175 } } _out: {} } //line extract.rl:50 return "", "", 0, ErrInvalidTerm } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/extract.rl000066400000000000000000000017121450372207100231770ustar00rootroot00000000000000// Code generated by go generate gonum.org/v1/gonum/graph/formats/rdf; DO NOT EDIT. // Copyright ©2020 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 rdf import ( "fmt" "unicode" ) %%{ machine extract; include extract "extract_actions.rl"; include nquads "nquads.rl"; value := ( IRIREF | '_:' BLANK_NODE_LABEL >StartBlank %EndBlank | '"' STRING_LITERAL >StartLiteral %EndLiteral '"' ( '^^' IRIREF | LANGTAG >StartLang %EndLang )? ) %Return @!Error ; write data; }%% func extract(data []rune) (text, qual string, kind Kind, err error) { var ( cs, p int pe = len(data) eof = pe iri = -1 blank = -1 literal = -1 lang = -1 iriText string blankText string literalText string langText string ) %%write init; %%write exec; return "", "", 0, ErrInvalidTerm } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/extract_actions.rl000066400000000000000000000031231450372207100247150ustar00rootroot00000000000000// Copyright ©2020 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. %%{ machine extract; action StartIRI { iri = p } action EndIRI { if iri < 0 { panic("unexpected parser state: iri start not set") } iriText = unEscape(data[iri:p]) if kind == Invalid { kind = IRI } } action StartBlank { blank = p } action EndBlank { if blank < 0 { panic("unexpected parser state: blank start not set") } blankText = string(data[blank:p]) kind = Blank } action StartLiteral { literal = p } action EndLiteral { if literal < 0 { panic("unexpected parser state: literal start not set") } literalText = unEscape(data[literal:p]) kind = Literal } action StartLang { lang = p } action EndLang { if lang < 0 { panic("unexpected parser state: lang start not set") } langText = string(data[lang:p]) } action Return { switch kind { case IRI: return iriText, "", kind, nil case Blank: return blankText, "", kind, nil case Literal: qual = iriText if qual == "" { qual = langText } return literalText, qual, kind, nil default: return "", "", kind, ErrInvalidTerm } } action Error { if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return "", "", Invalid, fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalidTerm, data[p], p) } else { return "", "", Invalid, fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalidTerm, data[p], p) } } return "", "", Invalid, ErrIncompleteTerm } }%% golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/graph.go000066400000000000000000000312651450372207100226240ustar00rootroot00000000000000// Copyright ©2022 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 rdf import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/set/uid" ) // Graph implements an RDF graph satisfying the graph.Graph and graph.Multigraph // interfaces. type Graph struct { nodes map[int64]graph.Node from map[int64]map[int64]map[int64]graph.Line to map[int64]map[int64]map[int64]graph.Line pred map[int64]map[*Statement]bool termIDs map[string]int64 ids *uid.Set } // NewGraph returns a new empty Graph. func NewGraph() *Graph { return &Graph{ nodes: make(map[int64]graph.Node), from: make(map[int64]map[int64]map[int64]graph.Line), to: make(map[int64]map[int64]map[int64]graph.Line), pred: make(map[int64]map[*Statement]bool), termIDs: make(map[string]int64), ids: uid.NewSet(), } } // addNode adds n to the graph. It panics if the added node ID matches an // existing node ID. func (g *Graph) addNode(n graph.Node) { if _, exists := g.nodes[n.ID()]; exists { panic(fmt.Sprintf("rdf: node ID collision: %d", n.ID())) } g.nodes[n.ID()] = n g.ids.Use(n.ID()) } // AddStatement adds s to the graph. It panics if Term UIDs in the statement // are not consistent with existing terms in the graph. Statements must not // be altered while being held by the graph. If the UID fields of the terms // in s are zero, they will be set to values consistent with the rest of the // graph on return, mutating the parameter, otherwise the UIDs must match terms // that already exist in the graph. The statement must be a valid RDF statement // otherwise AddStatement will panic. func (g *Graph) AddStatement(s *Statement) { _, _, kind, err := s.Predicate.Parts() if err != nil { panic(fmt.Errorf("rdf: error extracting predicate: %w", err)) } if kind != IRI { panic(fmt.Errorf("rdf: predicate is not an IRI: %s", s.Predicate.Value)) } _, _, kind, err = s.Subject.Parts() if err != nil { panic(fmt.Errorf("rdf: error extracting subject: %w", err)) } switch kind { case IRI, Blank: default: panic(fmt.Errorf("rdf: subject is not an IRI or blank node: %s", s.Subject.Value)) } _, _, kind, err = s.Object.Parts() if err != nil { panic(fmt.Errorf("rdf: error extracting object: %w", err)) } if kind == Invalid { panic(fmt.Errorf("rdf: object is not a valid term: %s", s.Object.Value)) } statements, ok := g.pred[s.Predicate.UID] if !ok { statements = make(map[*Statement]bool) g.pred[s.Predicate.UID] = statements } statements[s] = true g.addTerm(&s.Subject) g.addTerm(&s.Predicate) g.addTerm(&s.Object) g.setLine(s) } // addTerm adds t to the graph. It panics if the added node ID matches an existing node ID. func (g *Graph) addTerm(t *Term) { if t.UID == 0 { id, ok := g.termIDs[t.Value] if ok { t.UID = id return } id = g.ids.NewID() g.ids.Use(id) t.UID = id g.termIDs[t.Value] = id return } id, ok := g.termIDs[t.Value] if !ok { g.termIDs[t.Value] = t.UID } else if id != t.UID { panic(fmt.Sprintf("rdf: term ID collision: term:%s new ID:%d old ID:%d", t.Value, t.UID, id)) } } // AllStatements returns an iterator of the statements that make up the graph. func (g *Graph) AllStatements() *Statements { return &Statements{eit: g.Edges()} } // 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. // The returned graph.Edge is a multi.Edge if an edge exists. func (g *Graph) Edge(uid, vid int64) graph.Edge { l := g.Lines(uid, vid) if l == graph.Empty { return nil } return multi.Edge{F: g.Node(uid), T: g.Node(vid), Lines: l} } // Edges returns all the edges in the graph. Each edge in the returned slice // is a multi.Edge. func (g *Graph) Edges() graph.Edges { if len(g.nodes) == 0 { return graph.Empty } var edges []graph.Edge for _, u := range g.nodes { for _, e := range g.from[u.ID()] { var lines []graph.Line for _, l := range e { lines = append(lines, l) } if len(lines) != 0 { edges = append(edges, multi.Edge{ F: g.Node(u.ID()), T: g.Node(lines[0].To().ID()), Lines: iterator.NewOrderedLines(lines), }) } } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedEdges(edges) } // From returns all nodes in g that can be reached directly from n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *Graph) From(id int64) graph.Nodes { if len(g.from[id]) == 0 { return graph.Empty } return iterator.NewNodesByLines(g.nodes, g.from[id]) } // FromSubject returns all nodes in g that can be reached directly from an // RDF subject term. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *Graph) FromSubject(t Term) graph.Nodes { return g.From(t.UID) } // HasEdgeBetween returns whether an edge exists between nodes x and y without // considering direction. func (g *Graph) 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 *Graph) HasEdgeFromTo(uid, vid int64) bool { _, ok := g.from[uid][vid] return ok } // Lines returns the lines from u to v if such any such lines exists and nil otherwise. // The node v must be directly reachable from u as defined by the From method. func (g *Graph) Lines(uid, vid int64) graph.Lines { edge := g.from[uid][vid] if len(edge) == 0 { return graph.Empty } var lines []graph.Line for _, l := range edge { lines = append(lines, l) } return iterator.NewOrderedLines(lines) } // newLine returns a new Line from the source to the destination node. // The returned Line will have a graph-unique ID. // The Line's ID does not become valid in g until the Line is added to g. func (g *Graph) newLine(from, to graph.Node) graph.Line { return multi.Line{F: from, T: to, UID: g.ids.NewID()} } // 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 *Graph) newNode() graph.Node { if len(g.nodes) == 0 { return multi.Node(0) } if int64(len(g.nodes)) == uid.Max { panic("rdf: cannot allocate node: no slot") } return multi.Node(g.ids.NewID()) } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *Graph) Node(id int64) graph.Node { return g.nodes[id] } // TermFor returns the Term for the given text. The text must be // an exact match for the Term's Value field. func (g *Graph) TermFor(text string) (term Term, ok bool) { id, ok := g.termIDs[text] if !ok { return } n, ok := g.nodes[id] if !ok { var s map[*Statement]bool s, ok = g.pred[id] if !ok { return } for k := range s { return k.Predicate, true } } return n.(Term), true } // Nodes returns all the nodes in the graph. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *Graph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // Predicates returns a slice of all the predicates used in the graph. func (g *Graph) Predicates() []Term { p := make([]Term, len(g.pred)) i := 0 for _, statements := range g.pred { for s := range statements { p[i] = s.Predicate i++ break } } return p } // removeLine removes the line with the given end point and line IDs from // the graph, leaving the terminal nodes. If the line does not exist it is // a no-op. func (g *Graph) removeLine(fid, tid, id int64) { if _, ok := g.nodes[fid]; !ok { return } if _, ok := g.nodes[tid]; !ok { return } delete(g.from[fid][tid], id) if len(g.from[fid][tid]) == 0 { delete(g.from[fid], tid) } delete(g.to[tid][fid], id) if len(g.to[tid][fid]) == 0 { delete(g.to[tid], fid) } g.ids.Release(id) } // 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 *Graph) 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.ids.Release(id) } // RemoveStatement removes s from the graph, leaving the terminal nodes if they // are part of another statement. If the statement does not exist in g it is a no-op. func (g *Graph) RemoveStatement(s *Statement) { if !g.pred[s.Predicate.UID][s] { return } // Remove the connection. g.removeLine(s.Subject.UID, s.Object.UID, s.Predicate.UID) statements := g.pred[s.Predicate.UID] delete(statements, s) if len(statements) == 0 { delete(g.pred, s.Predicate.UID) if len(g.from[s.Predicate.UID]) == 0 { g.ids.Release(s.Predicate.UID) delete(g.termIDs, s.Predicate.Value) } } // Remove any orphan terms. if g.From(s.Subject.UID).Len() == 0 && g.To(s.Subject.UID).Len() == 0 { g.removeNode(s.Subject.UID) delete(g.termIDs, s.Subject.Value) } if g.From(s.Object.UID).Len() == 0 && g.To(s.Object.UID).Len() == 0 { g.removeNode(s.Object.UID) delete(g.termIDs, s.Object.Value) } } // RemoveTerm removes t and any statements referencing t from the graph. If // the term is a predicate, all statements with the predicate are removed. If // the term does not exist it is a no-op. func (g *Graph) RemoveTerm(t Term) { // Remove any predicates. if statements, ok := g.pred[t.UID]; ok { for s := range statements { g.RemoveStatement(s) } } // Quick return. _, nok := g.nodes[t.UID] _, fok := g.from[t.UID] _, tok := g.to[t.UID] if !nok && !fok && !tok { return } // Remove any statements that impinge on the term. to := g.From(t.UID) for to.Next() { lines := g.Lines(t.UID, to.Node().ID()) for lines.Next() { g.RemoveStatement(lines.Line().(*Statement)) } } from := g.To(t.UID) if from.Next() { lines := g.Lines(from.Node().ID(), t.UID) for lines.Next() { g.RemoveStatement(lines.Line().(*Statement)) } } // Remove the node. g.removeNode(t.UID) delete(g.termIDs, t.Value) } // setLine adds l, a line from one node to another. If the nodes do not exist, // they are added, and are set to the nodes of the line otherwise. func (g *Graph) setLine(l graph.Line) { var ( from = l.From() fid = from.ID() to = l.To() tid = to.ID() lid = l.ID() ) 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 } switch { case g.from[fid] == nil: g.from[fid] = map[int64]map[int64]graph.Line{tid: {lid: l}} case g.from[fid][tid] == nil: g.from[fid][tid] = map[int64]graph.Line{lid: l} default: g.from[fid][tid][lid] = l } switch { case g.to[tid] == nil: g.to[tid] = map[int64]map[int64]graph.Line{fid: {lid: l}} case g.to[tid][fid] == nil: g.to[tid][fid] = map[int64]graph.Line{lid: l} default: g.to[tid][fid][lid] = l } g.ids.Use(lid) } // Statements returns an iterator of the statements that connect the subject // term node u to the object term node v. func (g *Graph) Statements(uid, vid int64) *Statements { return &Statements{lit: g.Lines(uid, vid)} } // To returns all nodes in g that can reach directly to n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *Graph) To(id int64) graph.Nodes { if len(g.to[id]) == 0 { return graph.Empty } return iterator.NewNodesByLines(g.nodes, g.to[id]) } // ToObject returns all nodes in g that can reach directly to an RDF object // term. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *Graph) ToObject(t Term) graph.Nodes { return g.To(t.UID) } // Statements is an RDF statement iterator. type Statements struct { eit graph.Edges lit graph.Lines } // Next returns whether the iterator holds any additional statements. func (s *Statements) Next() bool { if s.lit != nil && s.lit.Next() { return true } if s.eit == nil || !s.eit.Next() { return false } s.lit = s.eit.Edge().(multi.Edge).Lines return s.lit.Next() } // Statement returns the current statement. func (s *Statements) Statement() *Statement { return s.lit.Line().(*Statement) } // ConnectedByAny is a helper function to for simplifying graph traversal // conditions. func ConnectedByAny(e graph.Edge, with func(*Statement) bool) bool { switch e := e.(type) { case *Statement: return with(e) case graph.Lines: it := e for it.Next() { s, ok := it.Line().(*Statement) if !ok { continue } ok = with(s) if ok { return true } } } return false } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/graph_example_test.go000066400000000000000000000222471450372207100253760ustar00rootroot00000000000000// Copyright ©2022 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 rdf_test import ( "fmt" "io" "log" "os" "strings" "gonum.org/v1/gonum/graph/formats/rdf" ) func ExampleGraph() { f, err := os.Open("path/to/graph.nq") if err != nil { log.Fatal(err) } dec := rdf.NewDecoder(f) var statements []*rdf.Statement for { s, err := dec.Unmarshal() if err != nil { if err != io.EOF { log.Fatalf("error during decoding: %v", err) } break } // Statements can be filtered at this point to exclude unwanted // or irrelevant parts of the graph. statements = append(statements, s) } f.Close() // Canonicalize blank nodes to reduce memory footprint. statements, err = rdf.URDNA2015(statements, statements) if err != nil { log.Fatal(err) } g := rdf.NewGraph() for _, s := range statements { g.AddStatement(s) } // Do something with the graph. } const gods = ` _:alcmene "human" . _:alcmene "Alcmene" . _:cerberus _:cerberushome . _:cerberus "monster" . _:cerberus "Cerberus" . _:cerberushome _:tartarus . _:cronos "titan" . _:cronos "Cronos" . _:hades _:hadeshome . _:hades _:poseidon . _:hades _:zeus . _:hades _:cerberus . _:hades "god" . _:hades "Hades" . _:hadeshome _:tartarus . _:hadeshome "it is peaceful" . _:heracles _:cerberus . _:heracles _:hydra . _:heracles _:nemean . _:heracles _:zeus . _:heracles _:alcmene . _:heracles "demigod" . _:heracles "Heracles" . _:hydra "monster" . _:hydra "Lernean Hydra" . _:nemean "monster" . _:nemean "Nemean Lion" . _:olympus "location" . _:olympus "Olympus" . _:poseidon _:poseidonhome . _:poseidon _:hades . _:poseidon _:zeus . _:poseidon "god" . _:poseidon "Poseidon" . _:poseidonhome _:sea . _:poseidonhome "it was given to him" . _:sea "location" . _:sea "Sea" . _:tartarus "location" . _:tartarus "Tartarus" . _:theseus _:cerberus . _:theseus _:poseidon . _:theseus "human" . _:theseus "Theseus" . _:zeus _:zeushome . _:zeus _:hades . _:zeus _:poseidon . _:zeus _:cronos . _:zeus "god" . _:zeus "Zeus" . _:zeushome _:olympus . _:zeushome "he can see everything" . ` func ExampleQuery() { g := rdf.NewGraph() dec := rdf.NewDecoder(strings.NewReader(gods)) for { s, err := dec.Unmarshal() if err != nil { if err != io.EOF { log.Fatalf("error during decoding: %v", err) } break } g.AddStatement(s) } it := g.Nodes() nodes := make([]rdf.Term, 0, it.Len()) for it.Next() { nodes = append(nodes, it.Node().(rdf.Term)) } // Construct a query start point. This can be reused. If a specific // node is already known it can be used to reduce the work required here. heracles := g.Query(nodes...).In(func(s *rdf.Statement) bool { // Traverse in from the name "Heracles". return s.Predicate.Value == "" && s.Object.Value == `"Heracles"` }) // father and name filter statements on their predicate values. These // are used in the queries that follow. father := func(s *rdf.Statement) bool { // Traverse across . return s.Predicate.Value == "" } name := func(s *rdf.Statement) bool { // Traverse across . return s.Predicate.Value == "" } // g.V().has('name', 'heracles').out('father').out('father').values('name') for _, r := range heracles. Out(father). // Traverse out across to get to Zeus. Out(father). // and again to get to Cronos. Out(name). // Retrieve the name by traversing the edges. Result() { fmt.Printf("Heracles' grandfather: %s\n", r.Value) } // g.V().has('name', 'heracles').repeat(out('father')).emit().values('name') var i int heracles.Repeat(func(q rdf.Query) (rdf.Query, bool) { q = q.Out(father) for _, r := range q.Out(name).Result() { fmt.Printf("Heracles' lineage %d: %s\n", i, r.Value) } i++ return q, true }) // parents and typ are helper filters for queries below. parents := func(s *rdf.Statement) bool { // Traverse across or return s.Predicate.Value == "" || s.Predicate.Value == "" } typ := func(s *rdf.Statement) bool { // Traverse across . return s.Predicate.Value == "" } // g.V(heracles).out('father', 'mother').label() for _, r := range heracles.Out(parents).Out(typ).Result() { fmt.Printf("Heracles' parents' types: %s\n", r.Value) } // battled is a helper filter for queries below. battled := func(s *rdf.Statement) bool { // Traverse across . return s.Predicate.Value == "" } // g.V(heracles).out('battled').label() for _, r := range heracles.Out(battled).Out(typ).Result() { fmt.Printf("Heracles' antagonists' types: %s\n", r.Value) } // g.V(heracles).out('battled').valueMap() for _, r := range heracles.Out(battled).Result() { m := make(map[string]string) g.Query(r).Out(func(s *rdf.Statement) bool { // Store any p: namespace in the map. if strings.HasPrefix(s.Predicate.Value, "") m[prop] = s.Object.Value } // But don't store the result into the query. return false }) fmt.Println(m) } // g.V(heracles).as('h').out('battled').in('battled').where(neq('h')).values('name') for _, r := range heracles.Out(battled).In(battled).Not(heracles).Out(name).Result() { fmt.Printf("Heracles' allies: %s\n", r.Value) } // Construct a query start point for Hades, this time using a restricted // starting set only including the name. It would also be possible to // start directly from a query with the term _:hades, but that depends // on the blank node identity, which may be altered, for example by // canonicalization. h, ok := g.TermFor(`"Hades"`) if !ok { log.Fatal("could not find term for Hades") } hades := g.Query(h).In(name) // g.V(hades).as('x').out('lives').in('lives').where(neq('x')).values('name') // // This is more complex with RDF since properties are encoded by // attachment to anonymous blank nodes, so we take two steps, the // first to the blank node for where Hades lives and then the second // to get the actual location. lives := func(s *rdf.Statement) bool { // Traverse across . return s.Predicate.Value == "" } location := func(s *rdf.Statement) bool { // Traverse across . return s.Predicate.Value == "" } for _, r := range hades.Out(lives).Out(location).In(location).In(lives).Not(hades).Out(name).Result() { fmt.Printf("Hades lives with: %s\n", r.Value) } // g.V(hades).out('brother').as('god').out('lives').as('place').select('god', 'place').by('name') brother := func(s *rdf.Statement) bool { // Traverse across . return s.Predicate.Value == "" } for _, r := range hades.Out(brother).Result() { m := make(map[string]string) as := func(key string) func(s *rdf.Statement) bool { return func(s *rdf.Statement) bool { // Store any objects in the map. if s.Predicate.Value == "" { m[key] = s.Object.Value } // But don't store the result into the query. return false } } sub := g.Query(r) sub.Out(as("god")) sub.Out(lives).Out(location).Out(as("place")) fmt.Println(m) } // The query above but with the reason for their choice. for _, r := range hades.Out(brother).Result() { m := make(map[string]string) // as stores the query result under the provided key // for m, and if cont is not nil, allows the chain // to continue. as := func(query, key string, cont func(s *rdf.Statement) bool) func(s *rdf.Statement) bool { return func(s *rdf.Statement) bool { // Store any objects matching the query in the map. if s.Predicate.Value == query { m[key] = s.Object.Value } // Continue with chain if cont is not nil and // the statement satisfies its condition. if cont == nil { return false } return cont(s) } } sub := g.Query(r) sub.Out(as("", "god", nil)) sub.Out(lives). Out(as("", "reason", location)). Out(as("", "place", nil)) fmt.Println(m) } // Unordered output: // // Heracles' grandfather: "Cronos" // Heracles' lineage 0: "Zeus" // Heracles' lineage 1: "Cronos" // Heracles' parents' types: "god" // Heracles' parents' types: "human" // Heracles' antagonists' types: "monster" // Heracles' antagonists' types: "monster" // Heracles' antagonists' types: "monster" // map[name:"Cerberus"] // map[name:"Lernean Hydra"] // map[name:"Nemean Lion"] // Heracles' allies: "Theseus" // Hades lives with: "Cerberus" // map[god:"Zeus" place:"Olympus"] // map[god:"Poseidon" place:"Sea"] // map[god:"Zeus" place:"Olympus" reason:"he can see everything"] // map[god:"Poseidon" place:"Sea" reason:"it was given to him"] } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/graph_export_test.go000066400000000000000000000033441450372207100252610ustar00rootroot00000000000000// Copyright ©2022 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 rdf import "gonum.org/v1/gonum/graph" var ( g *Graph _ graph.Graph = g _ graph.Directed = g _ graph.Multigraph = g _ graph.DirectedMultigraph = g _ graph.NodeAdder = g _ graph.NodeRemover = g _ graph.LineAdder = g _ graph.LineRemover = g ) // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. func (g *Graph) AddNode(n graph.Node) { g.addNode(n) } // NewLine returns a new Line from the source to the destination node. // The returned Line will have a graph-unique ID. // The Line's ID does not become valid in g until the Line is added to g. func (g *Graph) NewLine(from, to graph.Node) graph.Line { return g.newLine(from, 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 *Graph) NewNode() graph.Node { return g.newNode() } // RemoveLine removes the line with the given end point and line IDs from the graph, leaving // the terminal nodes. If the line does not exist it is a no-op. func (g *Graph) RemoveLine(fid, tid, id int64) { g.removeLine(fid, tid, id) } // 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 *Graph) RemoveNode(id int64) { g.removeNode(id) } // SetLine adds l, a line from one node to another. If the nodes do not exist, they are added // and are set to the nodes of the line otherwise. func (g *Graph) SetLine(l graph.Line) { g.setLine(l) } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/graph_test.go000066400000000000000000000167761450372207100236750ustar00rootroot00000000000000// Copyright ©2022 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 rdf_test import ( "io" "math" "sort" "strings" "testing" "golang.org/x/exp/rand" "github.com/google/go-cmp/cmp" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/formats/rdf" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/testgraph" ) func graphBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, _, _ float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() gg := rdf.NewGraph() for _, n := range nodes { seen.Add(n) gg.AddNode(n) } for _, edge := range edges { f := gg.Node(edge.From().ID()) if f == nil { f = edge.From() } t := gg.Node(edge.To().ID()) if t == nil { t = edge.To() } cl := multi.Line{F: f, T: t, UID: edge.ID()} seen.Add(cl.F) seen.Add(cl.T) e = append(e, cl) gg.SetLine(cl) } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return gg, n, e, math.NaN(), math.NaN(), true } const ( usesEmpty = true reversesEdges = false // Not tested since Graph is directed, but included for documentation. ) func TestGraph(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, graphBuilder, reversesEdges) }) t.Run("LineExistence", func(t *testing.T) { testgraph.LineExistence(t, graphBuilder, usesEmpty, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, graphBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, graphBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllLines", func(t *testing.T) { testgraph.ReturnAllLines(t, graphBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, graphBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, graphBuilder, usesEmpty) }) t.Run("RemoveNodes", func(t *testing.T) { g := multi.NewDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- g.SetLine(g.NewLine(u, v)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddLines", func(t *testing.T) { testgraph.AddLines(t, 100, multi.NewDirectedGraph(), func(id int64) graph.Node { return multi.Node(id) }, true, // Can update nodes. ) }) t.Run("RemoveLines", func(t *testing.T) { g := multi.NewDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() var lines []graph.Line rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- l := g.NewLine(u, v) g.SetLine(l) lines = append(lines, l) } } rnd.Shuffle(len(lines), func(i, j int) { lines[i], lines[j] = lines[j], lines[i] }) testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines)) }) } var removeStatementTests = []struct { name string triples string remove int want string }{ { name: "triangle", triples: ` . . . `, remove: 0, want: ` . . `, }, { name: "star", triples: ` . . . `, remove: 0, want: ` . . `, }, { name: "loop", triples: ` . . `, remove: 0, want: ` . `, }, { name: "parallel", triples: ` . . `, remove: 0, want: ` . `, }, { name: "dumbell", triples: ` . . . . . . . `, remove: 3, want: ` . . . . . . `, }, } func TestRemoveStatement(t *testing.T) { for _, test := range removeStatementTests { g, statements, err := graphFromReader(strings.NewReader(test.triples)) if err != nil { t.Errorf("unexpected error for %q: %v", test.name, err) } g.RemoveStatement(statements[test.remove]) var gotStatements []string it := g.AllStatements() for it.Next() { gotStatements = append(gotStatements, it.Statement().String()) } sort.Strings(gotStatements) got := strings.TrimSpace(strings.Join(gotStatements, "\n")) want := strings.TrimSpace(test.want) if got != want { t.Errorf("unexpected result for %q:\n%s", test.name, cmp.Diff(got, want)) } } } var removeTermTests = []struct { name string triples string remove string want string }{ { name: "triangle", triples: ` . . . `, remove: "", want: ` . `, }, { name: "star", triples: ` . . . `, remove: "", want: "", }, { name: "loop", triples: ` . . `, remove: "", want: "", }, { name: "parallel", triples: ` . . `, remove: "", want: "", }, { name: "dumbell_1", triples: ` . . . . . . . `, remove: "", want: ` . . . . . . `, }, { name: "dumbell_2", triples: ` . . . . . . . `, remove: "", want: ` . `, }, } func TestRemoveTerm(t *testing.T) { for _, test := range removeTermTests { g, _, err := graphFromReader(strings.NewReader(test.triples)) if err != nil { t.Errorf("unexpected error for %q: %v", test.name, err) } term, ok := g.TermFor(test.remove) if !ok { t.Errorf("couldn't find expected term for %q", test.name) continue } g.RemoveTerm(term) var gotStatements []string it := g.AllStatements() for it.Next() { gotStatements = append(gotStatements, it.Statement().String()) } sort.Strings(gotStatements) got := strings.TrimSpace(strings.Join(gotStatements, "\n")) want := strings.TrimSpace(test.want) if got != want { t.Errorf("unexpected result for %q:\n%s", test.name, cmp.Diff(got, want)) } } } func graphFromReader(r io.Reader) (*rdf.Graph, []*rdf.Statement, error) { g := rdf.NewGraph() var statements []*rdf.Statement dec := rdf.NewDecoder(r) for { s, err := dec.Unmarshal() if err != nil { if err == io.EOF { break } return nil, nil, err } statements = append(statements, s) g.AddStatement(s) } return g, statements, nil } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/iso_canonical.go000066400000000000000000000623261450372207100243260ustar00rootroot00000000000000// Copyright ©2020 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 rdf import ( "bytes" "errors" "fmt" "hash" "sort" ) // See "Canonical Forms for Isomorphic and Equivalent RDF Graphs: Algorithms // for Leaning and Labelling Blank Nodes" by Aiden Hogan for description of // the algorithm, https://doi.org/10.1145/3068333 and available free from // the author's web page http://aidanhogan.com/docs/rdf-canonicalisation.pdf. // // Aspects of implementation from discussion in v1.0 of the readme of the PoC // at https://doi.org/10.5281/zenodo.3154322 // Isomorphic returns whether the RDF graph datasets a and b are isomorphic, // where there is a bijective mapping between blank nodes in a and b using // the given hash function. If decomp is true, the graphs are decomposed // before canonicalization. func Isomorphic(a, b []*Statement, decomp bool, h hash.Hash) bool { if len(a) != len(b) { return false } zero := make([]byte, h.Size()) ah, _ := IsoCanonicalHashes(a, decomp, true, h, zero) bh, _ := IsoCanonicalHashes(b, decomp, true, h, zero) if len(ah) != len(bh) { return false } work := make([][]byte, 2*len(ah)) lexicalHashes(work[:len(ah)], ah) lexicalHashes(work[len(ah):], bh) for i := range work[:len(ah)] { if !bytes.Equal(work[i], work[i+len(ah)]) { return false } } return true } func lexicalHashes(dst [][]byte, hashes map[string][]byte) { i := 0 for _, s := range hashes { dst[i] = s i++ } sort.Sort(lexical(dst)) } // IsoCanonicalHashes returns a mapping between the nodes of the RDF graph // dataset described by the given statements using the provided hash // function. If decomp is true, the graphs are decomposed before hashing. // If dist is true the input graph is decomposed into identical splits, the // entire graph will be hashed to distinguish nodes. If decomp is false, // dist has no effect. // Blank node hashes are initially set to the value of zero. Hash values // are provided for literal and IRI nodes as well as for blank node. The // hash input for literal nodes includes the quotes and the input for IRI // nodes first removes the angle quotes around the IRI, although these are // included in the map keys. // // Note that hashes returned by IsoCanonicalHashes with decomp=true are not // comparable with hashes returned by IsoCanonicalHashes with decomp=false. // // See http://aidanhogan.com/docs/rdf-canonicalisation.pdf for details of // the hashing algorithm. func IsoCanonicalHashes(statements []*Statement, decomp, dist bool, h hash.Hash, zero []byte) (hashes map[string][]byte, terms map[string]map[string]bool) { if len(statements) == 0 { return nil, nil } if debug { debug.log(0, "Statements:") for _, s := range statements { debug.log(0, s) } debug.log(0) } hash, parts, ok := hashBNodesPerSplit(statements, decomp, h, zero) if debug { debug.log(0, "Blanks:") if len(hash.blanks) != 0 { for _, b := range hash.blanks { debug.log(0, b) } } else { debug.log(0, "none") } debug.log(0) debug.log(0, "Parts:") debug.logParts(0, parts) debug.logf(0, "Hashes from hashBNodesPerSplit (splitting=%t):\n", decomp) debug.logHashes(0, hash.hashOf, h.Size()) } if ok { return hash.hashOf, hash.termsFor } // TODO: remove the triviality exception in distinguish and return // the original hashes if this result is nil. Make the triviality // exception optional. hashes = distinguish(statements, dist, h, zero, hash, parts, nil, 0) if hashes == nil { // distinguish was given trivial parts and // we did not ask it to try to merge them. return hash.hashOf, hash.termsFor } if debug { debug.log(0, "Final resolved Hashes:") debug.logHashes(0, hashes, h.Size()) } terms = make(map[string]map[string]bool, len(hashes)) for k, h := range hashes { terms[string(h)] = map[string]bool{k: true} } return hashes, terms } // C14n performs a relabeling of the statements in src based on the terms // obtained from IsoCanonicalHashes, placing the results in dst and returning // them. The relabeling scheme is the same as for the Universal RDF Dataset // Normalization Algorithm, blank terms are ordered lexically by their hash // value and then given a blank label with the prefix "_:c14n" and an // identifier counter corresponding to the label's sort rank. // // If dst is nil, it is allocated, otherwise the length of dst must match the // length of src. func C14n(dst, src []*Statement, terms map[string]map[string]bool) ([]*Statement, error) { if dst == nil { dst = make([]*Statement, len(src)) } if len(dst) != len(src) { return dst, errors.New("rdf: slice length mismatch") } need := make(map[string]bool) for _, s := range src { for _, t := range []string{ s.Subject.Value, s.Object.Value, s.Label.Value, } { if !isBlank(t) { continue } need[t] = true } } blanks := make([]string, len(need)) i := 0 for h, m := range terms { var ok bool for t := range m { if isBlank(t) { ok = true break } } if !ok { continue } if i == len(blanks) { return dst, errors.New("rdf: too many blanks in terms") } blanks[i] = h i++ } sort.Strings(blanks) c14n := make(map[string]string) for i, b := range blanks { if len(terms[b]) == 0 { return nil, fmt.Errorf("rdf: no term for blank with hash %x", b) } for t := range terms[b] { if !isBlank(t) { continue } if _, exists := c14n[t]; exists { continue } delete(need, t) c14n[t] = fmt.Sprintf("_:c14n%d", i) } } if len(need) != 0 { return dst, fmt.Errorf("rdf: missing term hashes for %d terms", len(need)) } for i, s := range src { if dst[i] == nil { dst[i] = &Statement{} } n := dst[i] n.Subject = Term{Value: translate(s.Subject.Value, c14n)} n.Predicate = s.Predicate n.Object = Term{Value: translate(s.Object.Value, c14n)} n.Label = Term{Value: translate(s.Label.Value, c14n)} } sort.Sort(c14nStatements(dst)) return dst, nil } func translate(term string, mapping map[string]string) string { if term, ok := mapping[term]; ok { return term } return term } type c14nStatements []*Statement func (s c14nStatements) Len() int { return len(s) } func (s c14nStatements) Less(i, j int) bool { si := s[i] sj := s[j] switch { case si.Subject.Value < sj.Subject.Value: return true case si.Subject.Value > sj.Subject.Value: return false } switch { // Always IRI. case si.Predicate.Value < sj.Predicate.Value: return true case si.Predicate.Value > sj.Predicate.Value: return false } switch { case si.Object.Value < sj.Object.Value: return true case si.Object.Value > sj.Object.Value: return false } return si.Label.Value < sj.Label.Value } func (s c14nStatements) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // hashBNodes returns the hashed blank nodes of the graph described by statements // using the provided hash function. Hashes are initialised with zero. // // This is algorithm 1 in doi:10.1145/3068333. func hashBNodes(statements []*Statement, h hash.Hash, zero []byte, hash0 map[string][]byte) (hash *table, disjoint bool) { curr := newTable() for _, s := range statements { for i, t := range []string{ s.Subject.Value, s.Predicate.Value, s.Object.Value, s.Label.Value, } { switch { case i == 3 && t == "": continue case isBlank(t): if hash0 == nil { curr.set(t, zero) } else { curr.set(t, hash0[t]) } case isIRI(t): h.Reset() h.Write([]byte(t[1 : len(t)-1])) curr.set(t, h.Sum(nil)) default: h.Reset() h.Write([]byte(t)) curr.set(t, h.Sum(nil)) } } } bag := newHashBag(h, curr) last := curr.clone() for { curr, last = last, curr for _, s := range statements { if isBlank(s.Subject.Value) { var lab []byte if s.Label.Value != "" { lab = last.hashOf[s.Label.Value] } c := hashTuple(h, last.hashOf[s.Object.Value], last.hashOf[s.Predicate.Value], lab, []byte{'+'}) bag.add(s.Subject.Value, c) } if isBlank(s.Object.Value) { var lab []byte if s.Label.Value != "" { lab = last.hashOf[s.Label.Value] } c := hashTuple(h, last.hashOf[s.Subject.Value], last.hashOf[s.Predicate.Value], lab, []byte{'-'}) bag.add(s.Object.Value, c) } // This and the lab value above implement the label hashing // required for RDF dataset hashing as described in // https://doi.org/10.5281/zenodo.3154322 v1.0 // Readme.md#adaptation-of-the-algorithms-to-handle-datasets. if isBlank(s.Label.Value) { c := hashTuple(h, last.hashOf[s.Subject.Value], last.hashOf[s.Predicate.Value], last.hashOf[s.Object.Value], []byte{'.'}) bag.add(s.Label.Value, c) } } for t := range bag.hashesFor { curr.set(t, bag.sum(t)) } disjoint = curr.allUnique() if disjoint || !curr.changedFrom(last) { return curr, disjoint } } } // table is a collision aware hash collection for RDF terms. type table struct { // hashOf holds the hash for each term. hashOf map[string][]byte // termsFor holds the set of nodes in // the second key for terms that share // the hash in the first key. termsFor map[string]map[string]bool // isBlank and blanks are the set of blank // nodes. // isBlank is nil for cloned tables. isBlank map[string]bool // blanks is nil for tables created // with newTable. blanks []string } // newTable returns a new hash table. func newTable() *table { return &table{ hashOf: make(map[string][]byte), termsFor: make(map[string]map[string]bool), isBlank: make(map[string]bool), } } // wasCloned returns whether t is a parent or child of a cloning operation. func (t *table) wasCloned() bool { return t.isBlank == nil } // isNew returns whether t is a new table. func (t *table) isNew() bool { return t.blanks == nil } // clone returns a clone of the receiver. func (t *table) clone() *table { new := &table{ hashOf: make(map[string][]byte), termsFor: make(map[string]map[string]bool), } for term, hash := range t.hashOf { new.hashOf[term] = hash } for hash, coll := range t.termsFor { if len(coll) == 0 { continue } terms := make(map[string]bool) for term := range coll { terms[term] = true } new.termsFor[hash] = terms } if t.isNew() { t.blanks = make([]string, len(t.isBlank)) i := 0 for n := range t.isBlank { t.blanks[i] = n i++ } t.isBlank = nil } new.blanks = t.blanks return new } // TODO(kortschak): Make hash table in table.hashOf reuse the []byte on update. // This is not trivial since we need to check for changes, so we can't just get // the current hash buffer and write into it. So if this is done we probably // a pair of buffers, a current and a waiting. // set sets the hash of the term, removing any previously set hash. func (t *table) set(term string, hash []byte) { prev := t.hashOf[term] if bytes.Equal(prev, hash) { return } t.hashOf[term] = hash // Delete any existing hashes for this term. switch terms := t.termsFor[string(prev)]; { case len(terms) == 1: delete(t.termsFor, string(prev)) case len(terms) > 1: delete(terms, term) } terms, ok := t.termsFor[string(hash)] if ok { terms[term] = true } else { t.termsFor[string(hash)] = map[string]bool{term: true} } if !t.wasCloned() && isBlank(term) { // We are in the original table, so note // any blank node label that we see. t.isBlank[term] = true } } // allUnique returns whether every term has an unique hash. allUnique // can only be called on a table that was returned by clone. func (t *table) allUnique() bool { if t.isNew() { panic("checked hash bag from uncloned table") } for _, term := range t.blanks { if len(t.termsFor[string(t.hashOf[term])]) > 1 { return false } } return true } // changedFrom returns whether the receiver has been updated from last. // changedFrom can only be called on a table that was returned by clone. func (t *table) changedFrom(last *table) bool { if t.isNew() { panic("checked hash bag from uncloned table") } for i, x := range t.blanks { for _, y := range t.blanks[i+1:] { if bytes.Equal(t.hashOf[x], t.hashOf[y]) != bytes.Equal(last.hashOf[x], last.hashOf[y]) { return true } } } return false } // hashBag implements a commutative and associative hash. // See notes in https://doi.org/10.5281/zenodo.3154322 v1.0 // Readme.md#what-is-the-precise-specification-of-hashbag. type hashBag struct { hash hash.Hash hashesFor map[string][][]byte } // newHashBag returns a new hashBag using the provided hash function for // the given hash table. newHashBag can only take a table parameter that // was returned by newTable. func newHashBag(h hash.Hash, t *table) hashBag { if t.wasCloned() { panic("made hash bag from cloned table") } b := hashBag{hash: h, hashesFor: make(map[string][][]byte, len(t.isBlank))} for n := range t.isBlank { b.hashesFor[n] = [][]byte{t.hashOf[n]} } return b } // add adds the hash to the hash bag for the term. func (b hashBag) add(term string, hash []byte) { b.hashesFor[term] = append(b.hashesFor[term], hash) } // sum calculates the hash sum for the given term, updates the hash bag // state and returns the hash. func (b hashBag) sum(term string) []byte { p := b.hashesFor[term] sort.Sort(lexical(p)) h := hashTuple(b.hash, p...) b.hashesFor[term] = b.hashesFor[term][:1] b.hashesFor[term][0] = h return h } // lexical implements lexical sorting of [][]byte. type lexical [][]byte func (b lexical) Len() int { return len(b) } func (b lexical) Less(i, j int) bool { return string(b[i]) < string(b[j]) } func (b lexical) Swap(i, j int) { b[i], b[j] = b[j], b[i] } // hashTuple returns the h hash of the concatenation of t. func hashTuple(h hash.Hash, t ...[]byte) []byte { h.Reset() for _, b := range t { h.Write(b) } return h.Sum(nil) } // hashBNodesPerSplit returns the independently hashed blank nodes of the // graph described by statements using the provided hash function. Hashes // are initialised with zero. // // This is algorithm 2 in doi:10.1145/3068333. func hashBNodesPerSplit(statements []*Statement, decomp bool, h hash.Hash, zero []byte) (hash *table, parts byLengthHash, disjoint bool) { if !decomp { hash, ok := hashBNodes(statements, h, zero, nil) parts = appendOrdered(byLengthHash{}, hash.termsFor) sort.Sort(parts) return hash, parts, ok } splits := split(statements) // Avoid recombination work if there is only one split. if len(splits) == 1 { hash, ok := hashBNodes(statements, h, zero, nil) parts = appendOrdered(byLengthHash{}, hash.termsFor) sort.Sort(parts) return hash, parts, ok } hash = &table{hashOf: make(map[string][]byte)} disjoint = true for _, g := range splits { part, ok := hashBNodes(g, h, zero, nil) // Each split is guaranteed to be disjoint in its // set of blank nodes, so we can just append to our // collection of blanks. hash.blanks = append(hash.blanks, part.blanks...) if !ok { // Allow a short-circuit of the allUnique check. disjoint = false } for k, v := range part.hashOf { hash.hashOf[k] = v } parts = appendOrdered(parts, part.termsFor) } sort.Sort(parts) return hash, parts, disjoint && allUnique(hash.hashOf) } // appendOrdered adds parts (labels stored in the second key) for each // hash (stored in the first key) to parts. func appendOrdered(parts byLengthHash, partSets map[string]map[string]bool) byLengthHash { for h, s := range partSets { var p []string for e := range s { if isBlank(e) { p = append(p, e) } } if p != nil { parts.nodes = append(parts.nodes, p) parts.hashes = append(parts.hashes, h) } } return parts } // byLengthHash implements ascending length sort of a set of blank RDF // term partitions with ties broken by lexical ordering of the partitions' // hashes. type byLengthHash struct { // nodes holds the blank nodes of a part. nodes [][]string // hashes holds the hashes corresponding // to the nodes in the nodes field, using // the same index. hashes []string } func (s byLengthHash) Len() int { return len(s.nodes) } func (s byLengthHash) Less(i, j int) bool { switch { case len(s.nodes[i]) < len(s.nodes[j]): return true case len(s.nodes[i]) > len(s.nodes[j]): return false } return s.hashes[i] < s.hashes[j] } func (s byLengthHash) Swap(i, j int) { s.nodes[i], s.nodes[j] = s.nodes[j], s.nodes[i] s.hashes[i], s.hashes[j] = s.hashes[j], s.hashes[i] } // allUnique returns whether the []byte hash values in hashes are all unique. func allUnique(hashes map[string][]byte) bool { set := make(map[string]bool) for _, h := range hashes { if set[string(h)] { return false } set[string(h)] = true } return true } // split returns the statements forming connected components in the graph // described by statements. // // This is split in algorithm 2 in doi:10.1145/3068333. func split(statements []*Statement) [][]*Statement { ds := make(djSet) for _, s := range statements { ds.add(s.Subject.Value) ds.add(s.Object.Value) if isBlank(s.Subject.Value) && isBlank(s.Object.Value) { ds.union(ds.find(s.Subject.Value), ds.find(s.Object.Value)) } } var ( splits [][]*Statement ground []*Statement ) idxOf := make(map[*dsNode]int) for _, s := range statements { var t string switch { case isBlank(s.Subject.Value): t = s.Subject.Value case isBlank(s.Object.Value): t = s.Object.Value default: ground = append(ground, s) continue } r := ds.find(t) if r == nil { panic(fmt.Sprintf("term not found: %q", t)) } i, ok := idxOf[r] if !ok { i = len(splits) idxOf[r] = i splits = append(splits, []*Statement{s}) } else { splits[i] = append(splits[i], s) } } if ground != nil { splits = append(splits, ground) } if debug { debug.log(0, "Splits:") for i, s := range splits { for j, t := range s { if j == 0 { debug.logf(0, "%d.\t%s\n", i+1, t) } else { debug.logf(0, "\t%s\n", t) } } debug.log(0) } } return splits } // distinguish returns G⊥: smallest hash-labelled graph found thus far. // The graph is returned as a node to hash lookup. // // This is part of algorithm 3 in doi:10.1145/3068333. // // The correspondence between the parameters for the function in the paper // with the implementation here is as follows: // - G = statements // - hash = hash // - P = parts (already sorted by hashBNodesPerSplit) // - G⊥ = lowest // - B = hash.blanks // // The additional parameter dist specifies that distinguish should treat // coequal trivial parts as a coarse of intermediate part and distinguish // the nodes in that merged part. func distinguish(statements []*Statement, dist bool, h hash.Hash, zero []byte, hash *table, parts byLengthHash, lowest map[string][]byte, depth int) map[string][]byte { if debug { debug.log(depth, "Running Distinguish") } var small []string var k int for k, small = range parts.nodes { if len(small) > 1 { break } } if len(small) < 2 { if lowest != nil || !dist { if debug { debug.log(depth, "Return lowest (no non-trivial parts):") debug.logHashes(depth, lowest, h.Size()) } return lowest } // We have been given a set of fine parts, // but to reach here they must have been // non-uniquely labeled, so treat them // as a single coarse part. k, small = 0, parts.nodes[0] } if debug { debug.logf(depth, "Part: %v %x\n\n", small, parts.hashes[k]) debug.log(depth, "Orig hash:") debug.logHashes(depth, hash.hashOf, h.Size()) } smallHash := hash.hashOf[small[0]] for _, p := range parts.nodes[k:] { if !bytes.Equal(smallHash, hash.hashOf[p[0]]) { if debug { debug.logf(depth, "End of co-equal hashes: %x != %x\n\n", smallHash, hash.hashOf[p[0]]) } break } for i, b := range p { if debug { debug.logf(depth, "Iter: %d — B = %q\n\n", i, b) if depth == 0 { debug.log(depth, "Current lowest:\n") debug.logHashes(depth, lowest, h.Size()) } } hashP := hash.clone() hashP.set(b, hashTuple(h, hashP.hashOf[b], []byte{'@'})) hashPP, ok := hashBNodes(statements, h, zero, hashP.hashOf) if ok { if debug { debug.log(depth, "hashPP is trivial") debug.log(depth, "comparing hashPP\n") debug.logHashes(depth, hashPP.hashOf, h.Size()) debug.log(depth, "with previous\n") debug.logHashes(depth, lowest, h.Size()) } if lowest == nil || graphLess(statements, hashPP.hashOf, lowest) { lowest = hashPP.hashOf debug.log(depth, "choose hashPP\n") } } else { partsP := appendOrdered(byLengthHash{}, hashPP.termsFor) sort.Sort(partsP) if debug { debug.log(depth, "Parts':") debug.logParts(depth, partsP) debug.log(depth, "Recursive distinguish") debug.log(depth, "Called with current lowest:\n") debug.logHashes(depth, lowest, h.Size()) } lowest = distinguish(statements, dist, h, zero, hashPP, partsP, lowest, depth+1) } } } if debug { debug.log(depth, "Return lowest:") debug.logHashes(depth, lowest, h.Size()) } return lowest } // terms ordered syntactically, triples ordered lexicographically, and graphs // ordered such that G < H if and only if G ⊂ H or there exists a triple // t ∈ G \ H such that no triple t' ∈ H \ G exists where t' < t. // p9 https://doi.org/10.1145/3068333 func graphLess(statements []*Statement, a, b map[string][]byte) bool { g := newLexicalStatements(statements, a) sort.Sort(g) h := newLexicalStatements(statements, b) sort.Sort(h) gSubH := sub(g, h, len(g.statements)) if len(gSubH) == 0 { return true } hSubG := sub(h, g, 1) if len(hSubG) == 0 { return true } lowestH := relabeledStatement{hSubG[0], h.hashes} for _, s := range gSubH { rs := relabeledStatement{s, g.hashes} if rs.less(lowestH) { return true } } return false } // lexicalStatements is a sort implementation for Statements with blank // node labels replaced with their hash. type lexicalStatements struct { statements []*Statement hashes map[string][]byte } func newLexicalStatements(statements []*Statement, hash map[string][]byte) lexicalStatements { s := lexicalStatements{ statements: make([]*Statement, len(statements)), hashes: hash, } copy(s.statements, statements) return s } // sub returns the difference between a and b up to max elements long. func sub(a, b lexicalStatements, max int) []*Statement { var d []*Statement var i, j int for i < len(a.statements) && j < len(b.statements) && len(d) < max { ra := relabeledStatement{a.statements[i], a.hashes} rb := relabeledStatement{b.statements[j], b.hashes} switch { case ra.less(rb): d = append(d, a.statements[i]) i++ case rb.less(ra): j++ default: i++ } } if len(d) < max { d = append(d, a.statements[i:min(len(a.statements), i+max-len(d))]...) } return d } func min(a, b int) int { if a < b { return a } return b } func (s lexicalStatements) Len() int { return len(s.statements) } func (s lexicalStatements) Less(i, j int) bool { return relabeledStatement{s.statements[i], s.hashes}.less(relabeledStatement{s.statements[j], s.hashes}) } func (s lexicalStatements) Swap(i, j int) { s.statements[i], s.statements[j] = s.statements[j], s.statements[i] } // relabeledStatement is a statement that is orderable by its blank node // hash relabeling. type relabeledStatement struct { statement *Statement labels map[string][]byte } func (a relabeledStatement) less(b relabeledStatement) bool { switch { case relabeledTerm{a.statement.Subject, a.labels}.less(relabeledTerm{b.statement.Subject, b.labels}): return true case relabeledTerm{b.statement.Subject, b.labels}.less(relabeledTerm{a.statement.Subject, a.labels}): return false } switch { // Always IRI. case a.statement.Predicate.Value < b.statement.Predicate.Value: return true case a.statement.Predicate.Value > b.statement.Predicate.Value: return false } switch { case relabeledTerm{a.statement.Object, a.labels}.less(relabeledTerm{b.statement.Object, b.labels}): return true case relabeledTerm{b.statement.Object, b.labels}.less(relabeledTerm{a.statement.Object, a.labels}): return false } return relabeledTerm{a.statement.Label, a.labels}.less(relabeledTerm{b.statement.Label, b.labels}) } func (s relabeledStatement) String() string { subj := relabeledTerm{term: s.statement.Subject, labels: s.labels} obj := relabeledTerm{term: s.statement.Object, labels: s.labels} if s.statement.Label.Value == "" { return fmt.Sprintf("%s %s %s .", subj, s.statement.Predicate.Value, obj) } lab := relabeledTerm{term: s.statement.Label, labels: s.labels} return fmt.Sprintf("%s %s %s %s .", subj, s.statement.Predicate.Value, obj, lab) } // relabeledTerm is a term that is orderable by its blank node hash relabeling. type relabeledTerm struct { term Term labels map[string][]byte } func (a relabeledTerm) less(b relabeledTerm) bool { aIsBlank := isBlank(a.term.Value) bIsBlank := isBlank(b.term.Value) switch { case aIsBlank && bIsBlank: return bytes.Compare(a.labels[a.term.Value], b.labels[b.term.Value]) < 0 case aIsBlank: return blankPrefix < unquoteIRI(b.term.Value) case bIsBlank: return unquoteIRI(a.term.Value) < blankPrefix default: return unquoteIRI(a.term.Value) < unquoteIRI(b.term.Value) } } func unquoteIRI(s string) string { if len(s) > 1 && s[0] == '<' && s[len(s)-1] == '>' { s = s[1 : len(s)-1] } return s } func (t relabeledTerm) String() string { if !isBlank(t.term.Value) { return t.term.Value } h, ok := t.labels[t.term.Value] if !ok { return t.term.Value + "_missing_hash" } return fmt.Sprintf("_:%0x", h) } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/iso_canonical_example_test.go000066400000000000000000000123541450372207100270740ustar00rootroot00000000000000// Copyright ©2020 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 rdf_test import ( "crypto/md5" "fmt" "log" "os" "sort" "strings" "text/tabwriter" "gonum.org/v1/gonum/graph/formats/rdf" ) func ExampleIsoCanonicalHashes_isomorphisms() { for _, statements := range []string{ ` . . `, ` _:a . _:b . _:c _:a . _:d _:b . _:c _:d . `, ` _:a1 . _:b1 . _:c1 _:a1 . _:d1 _:b1 . _:c1 _:d1 . `, ` # G _:a . _:b . _:a . _:c . _:c _:b . # H _:d . _:e . _:f _:d . _:f _:g . _:g _:e . `, ` _:greet "hola"@es . `, } { // Decode the statement stream. dec := rdf.NewDecoder(strings.NewReader(statements)) var s []*rdf.Statement for { l, err := dec.Unmarshal() if err != nil { break } s = append(s, l) } // Get the node label to hash look-up table. hashes, _ := rdf.IsoCanonicalHashes(s, false, true, md5.New(), make([]byte, 16)) // Get all the blank nodes. var blanks []string for k := range hashes { if strings.HasPrefix(k, "_:") { blanks = append(blanks, k) } } sort.Strings(blanks) if len(blanks) == 0 { fmt.Println("No blank nodes.") } else { w := tabwriter.NewWriter(os.Stdout, 0, 4, 1, ' ', 0) fmt.Fprintln(w, "Node\tHash") for _, k := range blanks { fmt.Fprintf(w, "%s\t%032x\n", k, hashes[k]) } w.Flush() } fmt.Println() } // Output: // // No blank nodes. // // Node Hash // _:a d4db6df055d5611e9d8aa6ea621561d1 // _:b ad70e47f2b026064c7f0922060512b9a // _:c dafd81e6fa603d3e11c898d631e8673f // _:d 7e318557b09444e88791721becc2a8e7 // // Node Hash // _:a1 d4db6df055d5611e9d8aa6ea621561d1 // _:b1 ad70e47f2b026064c7f0922060512b9a // _:c1 dafd81e6fa603d3e11c898d631e8673f // _:d1 7e318557b09444e88791721becc2a8e7 // // Node Hash // _:a 44ad49b6df3aea91ddbcef932c93e3b4 // _:b ba3ffd8b271a8545b1a3a9042e75ce4b // _:c 34e1bd90b6758b4a766e000128caa6a6 // _:d eb2a47c1032f623647d0497a2ff74052 // _:e 1d9ed02f28d87e555feb904688bc2449 // _:f d3b00d36ea503dcc8d234e4405feab81 // _:g 55127e4624c0a4fe5990933a48840af8 // // Node Hash // _:greet 0d9ba18a037a3fa67e46fce821fe51b4 } func ExampleIsoCanonicalHashes_isomorphicParts() { for _, statements := range []string{ ` # Part 1 _:a . _:b . _:c _:a . _:d _:b . _:c _:d . # Part 2 _:a1 . _:b1 . _:c1 _:a1 . _:d1 _:b1 . _:c1 _:d1 . `, } { // Decode the statement stream. dec := rdf.NewDecoder(strings.NewReader(statements)) var s []*rdf.Statement for { l, err := dec.Unmarshal() if err != nil { break } s = append(s, l) } // Get the node label to hash look-up table. This time // we will decompose the dataset into splits and not // distinguish nodes. This will then group nodes from // the two isomorphic parts. Otherwise each node in // the complete dataset would get a unique hash. hashes, _ := rdf.IsoCanonicalHashes(s, true, false, md5.New(), make([]byte, 16)) // Get all the blank nodes. var blanks []string for k := range hashes { if strings.HasPrefix(k, "_:") { blanks = append(blanks, k) } } sort.Strings(blanks) if len(blanks) == 0 { fmt.Println("No blank nodes.") } else { w := tabwriter.NewWriter(os.Stdout, 0, 4, 1, ' ', 0) fmt.Fprintln(w, "Node\tHash") for _, k := range blanks { fmt.Fprintf(w, "%s\t%032x\n", k, hashes[k]) } w.Flush() } fmt.Println() } // Output: // // Node Hash // _:a d4db6df055d5611e9d8aa6ea621561d1 // _:a1 d4db6df055d5611e9d8aa6ea621561d1 // _:b ad70e47f2b026064c7f0922060512b9a // _:b1 ad70e47f2b026064c7f0922060512b9a // _:c dafd81e6fa603d3e11c898d631e8673f // _:c1 dafd81e6fa603d3e11c898d631e8673f // _:d 7e318557b09444e88791721becc2a8e7 // _:d1 7e318557b09444e88791721becc2a8e7 } func ExampleC14n() { for _, statements := range []string{ ` _:a . _:b . _:c _:a . _:d _:b . _:c _:d . `, ` _:c1 _:a1 . _:b1 . _:d1 _:b1 . _:a1 . _:c1 _:d1 . `, } { // Decode the statement stream. dec := rdf.NewDecoder(strings.NewReader(statements)) var s []*rdf.Statement for { l, err := dec.Unmarshal() if err != nil { break } s = append(s, l) } // Get the hash to term label look-up table. _, terms := rdf.IsoCanonicalHashes(s, false, true, md5.New(), make([]byte, 16)) relabeled, err := rdf.C14n(nil, s, terms) if err != nil { log.Fatal(err) } for _, s := range relabeled { fmt.Println(s) } fmt.Println() } // Output: // // _:c14n0 _:c14n1 . // _:c14n1 . // _:c14n2 . // _:c14n3 _:c14n2 . // _:c14n3 _:c14n0 . // // _:c14n0 _:c14n1 . // _:c14n1 . // _:c14n2 . // _:c14n3 _:c14n2 . // _:c14n3 _:c14n0 . } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/iso_canonical_test.go000066400000000000000000000342411450372207100253600ustar00rootroot00000000000000// Copyright ©2020 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 rdf import ( "crypto/md5" "flag" "fmt" "hash" "io" "os" "path/filepath" "reflect" "sort" "testing" "text/tabwriter" "time" "golang.org/x/exp/rand" ) var ( origSeed = flag.Int64("seed", 1, "specify random seed to use for each test (negative for Unix time)") tests = flag.String("test", "*-in.n[qt]", "specify test case in testdata") ) func TestIsoCanonicalHashes(t *testing.T) { seed := uint64(*origSeed) if *origSeed < 0 { seed = uint64(time.Now().UnixNano()) } defer func() { if t.Failed() && *origSeed < 0 { t.Logf("time based seed: %d", seed) } }() // Number of times to run IsoCanonicalHashes to check consistency. const retries = 5 // Share a global hash function to ensure that we // are resetting the function internally on each use. hash := md5.New() glob, err := filepath.Glob(filepath.Join("testdata", *tests)) if err != nil { t.Fatalf("Failed to open test suite: %v", err) } for _, path := range glob { name := filepath.Base(path) t.Run(name, func(t *testing.T) { src := rand.NewSource(seed) f, err := os.Open(path) if err != nil { t.Fatalf("Failed to open test suite in %q: %v", path, err) } var statements []*Statement dec := NewDecoder(f) for { s, err := dec.Unmarshal() if err != nil { if err == io.EOF { break } t.Fatalf("Unexpected error reading from %q: %v", path, err) } statements = append(statements, s) } f.Close() for _, decomp := range []bool{false, true} { t.Run(fmt.Sprintf("decomp=%t", decomp), func(t *testing.T) { var last map[string][]byte for i := 0; i < retries; i++ { curr, terms := IsoCanonicalHashes(statements, decomp, true, hash, make([]byte, 16)) if !hashesDisjoint(terms) { t.Errorf("IsoCanonicalHashes did not uniquely identify nodes %q with decomp=%t", name, decomp) } if last != nil { last := relabelStatements(statements, termsFor(last, hash)) sort.Sort(simpleLexicalStatements(last)) curr := relabelStatements(statements, termsFor(curr, hash)) sort.Sort(simpleLexicalStatements(curr)) if !reflect.DeepEqual(last, curr) { t.Errorf("IsoCanonicalHashes was not stable between runs on %q with decomp=%t", name, decomp) t.Log("Current run:") for _, s := range curr { t.Logf("\t%s", s) } t.Log("Previous run:") for _, s := range last { t.Logf("\t%s", s) } break } } last = curr } hashes := last ok := allUnique(hashes) if !ok { t.Errorf("Failed to get unique hashes for %q disjoint with decomp=%t", name, decomp) t.Logf("skipping %q decomp=%t", path, decomp) return } // Test that a graph is not isomorphic with one generated // by deleting the last statement. t.Run("isomorphic G != G-s", func(t *testing.T) { if len(statements) == 0 { return } if Isomorphic(statements, statements[:len(statements)-1], decomp, hash) { t.Error("Isomorphic(G, G-s)=true") } }) // Test that a graph is not isomorphic with one generated // by hashing the first grounded statement. t.Run("isomorphic G != Gμ(g)", func(t *testing.T) { mangled, mangTerms := mangleFirstIL(statements, hash) if mangTerms == nil { // All terms were blanks. return } if Isomorphic(statements, mangled, decomp, hash) { t.Error("Isomorphic(G, Gμ(g))=true") } }) // Test that a graph is not isomorphic with one generated // by merging the first two lexically sorted blank nodes // into one. t.Run("isomorphic G != G(b1∪b2)", func(t *testing.T) { mangled, mangTerms := mergeFirst2B(statements) if mangTerms == nil { // All terms were blanks. return } if Isomorphic(statements, mangled, decomp, hash) { t.Error("Isomorphic(G, G(b1∪b2))=true") } }) // Relabel a copy of the statements and then sort. orig := relabelStatements(statements, termsFor(hashes, hash)) sort.Sort(simpleLexicalStatements(orig)) for _, perm := range []struct { name string data func() ([]*Statement, map[string]string) }{ { name: "reverse statements", data: func() ([]*Statement, map[string]string) { return reverseStatements(statements) }, }, { name: "permute statements", data: func() ([]*Statement, map[string]string) { return permuteStatements(statements, src) }, }, { name: "permute blank labels", data: func() ([]*Statement, map[string]string) { return permuteBlanks(statements, src) }, }, { name: "hash blank labels", data: func() ([]*Statement, map[string]string) { return hashBlanks(statements, md5.New()) }, }, { name: "reverse statements and hash blank labels", data: func() ([]*Statement, map[string]string) { // Reordering must come first since it does not return // a non-nil terms map, but hashBlanks does. s, _ := reverseStatements(statements) return hashBlanks(s, md5.New()) }, }, { name: "permute statements and hash blank labels", data: func() ([]*Statement, map[string]string) { // Reordering must come first since it does not return // a non-nil terms map, but hashBlanks does. s, _ := permuteStatements(statements, src) return hashBlanks(s, md5.New()) }, }, } { t.Run(perm.name, func(t *testing.T) { if debug { fmt.Fprintf(os.Stderr, "\n%q %q decomp=%t:\n", path, perm.name, decomp) } altStatements, terms := perm.data() altHashes, altTerms := IsoCanonicalHashes(altStatements, decomp, true, hash, make([]byte, 16)) ok := allUnique(altHashes) && hashesDisjoint(altTerms) if !ok { t.Errorf("Failed to get unique hashes for %q alternative disjoint %q with decomp=%t", path, perm.name, decomp) } if debug { fmt.Fprintln(os.Stderr, "Name mappings from original dataset:") keys := make([]string, len(hashes)) var i int for k := range hashes { keys[i] = k i++ } sort.Strings(keys) w := tabwriter.NewWriter(os.Stderr, 0, 4, 8, ' ', 0) for _, k := range keys { fmt.Fprintf(w, "\t%s\t%s\n", k, translate(k, terms)) } w.Flush() fmt.Fprintln(os.Stderr) } // Relabel a copy of the alternative statements and then sort. alt := relabelStatements(altStatements, termsFor(altHashes, hash)) sort.Sort(simpleLexicalStatements(alt)) for i := range statements { if *orig[i] != *alt[i] { // Otherwise we have pointer inequality. t.Errorf("Unexpected statement in %q %q decomp=%t:\ngot: %#v\nwant:%#v", path, perm.name, decomp, orig[i], alt[i]) break } } if !Isomorphic(statements, altStatements, decomp, hash) { t.Errorf("Isomorphic(G, perm(G))=false in %q %q decomp=%t", path, perm.name, decomp) } }) } }) } }) } } func permuteStatements(s []*Statement, src rand.Source) ([]*Statement, map[string]string) { rnd := rand.New(src) m := make([]*Statement, len(s)) for x, y := range rnd.Perm(len(s)) { m[x] = s[y] } return m, nil } func reverseStatements(s []*Statement) ([]*Statement, map[string]string) { m := make([]*Statement, len(s)) for i, j := 0, len(s)-1; i < len(s); i, j = i+1, j-1 { m[j] = s[i] } return m, nil } func permuteBlanks(s []*Statement, src rand.Source) ([]*Statement, map[string]string) { rnd := rand.New(src) terms := make(map[string]string) for _, e := range s { for _, t := range []string{ e.Subject.Value, e.Predicate.Value, e.Object.Value, e.Label.Value, } { if t == "" { continue } terms[t] = t } } var blanks []string for t := range terms { if isBlank(t) { blanks = append(blanks, t) } } sort.Strings(blanks) for x, y := range rnd.Perm(len(blanks)) { terms[blanks[x]] = blanks[y] } m := relabelStatements(s, terms) return m, terms } func hashBlanks(s []*Statement, h hash.Hash) ([]*Statement, map[string]string) { terms := make(map[string]string) for _, e := range s { for _, t := range []string{ e.Subject.Value, e.Predicate.Value, e.Object.Value, e.Label.Value, } { if !isBlank(t) { continue } h.Reset() h.Write([]byte(t)) terms[t] = fmt.Sprintf("_:%0*x", 2*h.Size(), h.Sum(nil)) } } m := relabelStatements(s, terms) return m, terms } func mangleFirstIL(s []*Statement, h hash.Hash) ([]*Statement, map[string]string) { terms := make(map[string]string) for _, e := range s { for _, t := range []string{ e.Subject.Value, e.Predicate.Value, e.Object.Value, e.Label.Value, } { if isBlank(t) { continue } h.Reset() h.Write([]byte(t)) terms[t] = fmt.Sprintf(`"%0*x"`, 2*h.Size(), h.Sum(nil)) return relabelStatements(s, terms), terms } } m := relabelStatements(s, nil) return m, nil } func mergeFirst2B(s []*Statement) ([]*Statement, map[string]string) { terms := make(map[string]string) for _, e := range s { for _, t := range []string{ e.Subject.Value, e.Predicate.Value, e.Object.Value, e.Label.Value, } { if !isBlank(t) { continue } terms[t] = t } } if len(terms) < 2 { return relabelStatements(s, nil), nil } blanks := make([]string, len(terms)) i := 0 for _, b := range terms { blanks[i] = b i++ } sort.Strings(blanks) terms[blanks[1]] = terms[blanks[0]] m := relabelStatements(s, terms) return m, nil } func hashesDisjoint(terms map[string]map[string]bool) bool { for _, t := range terms { if len(t) != 1 { return false } } return true } func TestLexicalStatements(t *testing.T) { if *tests == "" { *tests = "*" } hash := md5.New() glob, err := filepath.Glob(filepath.Join("testdata", *tests)) if err != nil { t.Fatalf("Failed to open test suite: %v", err) } for _, path := range glob { f, err := os.Open(path) if err != nil { t.Fatalf("Failed to open test suite in %q: %v", path, err) } var statements []*Statement dec := NewDecoder(f) for { s, err := dec.Unmarshal() if err != nil { if err == io.EOF { break } t.Fatalf("Unexpected error reading from %q: %v", path, err) } statements = append(statements, s) } f.Close() for _, decomp := range []bool{false, true} { hashes, _ := IsoCanonicalHashes(statements, decomp, true, hash, make([]byte, 16)) terms := termsFor(hashes, hash) // Sort a copy of the statements based on hashes and then relabel. indirect := make([]*Statement, len(statements)) copy(indirect, statements) sort.Sort(lexicalStatements{indirect, hashes}) indirect = relabelStatements(indirect, terms) // Relabel a copy of the statements and then sort. direct := relabelStatements(statements, terms) sort.Sort(simpleLexicalStatements(direct)) for i := range statements { if *indirect[i] != *direct[i] { // Otherwise we have pointer inequality. t.Errorf("Unexpected ordering of indirect sort in %q:\ngot: %#v\nwant:%#v", path, indirect[i], direct[i]) } } } } } func termsFor(hashes map[string][]byte, hash hash.Hash) map[string]string { terms := make(map[string]string) for t, h := range hashes { if isBlank(t) { terms[t] = fmt.Sprintf("_:%0*x", 2*hash.Size(), h) } } return terms } // simpleLexicalStatements implements lexical statement sorting on the // literal values without interpolation. type simpleLexicalStatements []*Statement func (s simpleLexicalStatements) Len() int { return len(s) } func (s simpleLexicalStatements) Less(i, j int) bool { si := s[i] sj := s[j] switch { case unquoteIRI(si.Subject.Value) < unquoteIRI(sj.Subject.Value): return true case unquoteIRI(si.Subject.Value) > unquoteIRI(sj.Subject.Value): return false } switch { // Always IRI. case si.Predicate.Value < sj.Predicate.Value: return true case si.Predicate.Value > sj.Predicate.Value: return false } switch { case unquoteIRI(si.Object.Value) < unquoteIRI(sj.Object.Value): return true case unquoteIRI(si.Object.Value) > unquoteIRI(sj.Object.Value): return false } return unquoteIRI(si.Label.Value) < unquoteIRI(sj.Label.Value) } func (s simpleLexicalStatements) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func relabelStatements(s []*Statement, terms map[string]string) []*Statement { m := make([]*Statement, len(s)) for i, e := range s { n := *e n.Subject = Term{Value: translate(n.Subject.Value, terms)} n.Predicate = Term{Value: translate(n.Predicate.Value, terms)} n.Object = Term{Value: translate(n.Object.Value, terms)} n.Label = Term{Value: translate(n.Label.Value, terms)} m[i] = &n } return m } func BenchmarkIsoCanonicalHashes(b *testing.B) { hash := md5.New() benchmarks := []string{ "test019-in.nq", "test044-in.nq", } for _, name := range benchmarks { path := filepath.Join("testdata", name) b.Run(name, func(b *testing.B) { f, err := os.Open(path) if err != nil { b.Fatalf("Failed to open test suite in %q: %v", path, err) } var statements []*Statement dec := NewDecoder(f) for { s, err := dec.Unmarshal() if err != nil { if err == io.EOF { break } b.Fatalf("Unexpected error reading from %q: %v", path, err) } statements = append(statements, s) } f.Close() nodes := make(map[string]bool) for _, s := range statements { for _, t := range []string{ s.Subject.Value, s.Predicate.Value, s.Object.Value, s.Label.Value, } { if t != "" { nodes[t] = true } } } n := len(nodes) for _, decomp := range []bool{false, true} { b.Run(fmt.Sprintf("decomp=%t", decomp), func(b *testing.B) { for i := 0; i < b.N; i++ { hashes, _ := IsoCanonicalHashes(statements, decomp, true, hash, make([]byte, 16)) if len(hashes) != n { b.Fatalf("unexpected number of hashes: %d != %d", len(hashes), len(statements)) } } }) } }) } } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/kind_string.go000066400000000000000000000011551450372207100240310ustar00rootroot00000000000000// Code generated by "stringer -type=Kind"; DO NOT EDIT. package rdf import "strconv" func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[Invalid-0] _ = x[IRI-1] _ = x[Literal-2] _ = x[Blank-3] } const _Kind_name = "InvalidIRILiteralBlank" var _Kind_index = [...]uint8{0, 7, 10, 17, 22} func (i Kind) String() string { if i < 0 || i >= Kind(len(_Kind_index)-1) { return "Kind(" + strconv.FormatInt(int64(i), 10) + ")" } return _Kind_name[_Kind_index[i]:_Kind_index[i+1]] } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/nodebug.go000066400000000000000000000011001450372207100231270ustar00rootroot00000000000000// Copyright ©2020 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:build !debug // +build !debug package rdf type debugger bool const debug debugger = false func (d debugger) log(depth int, args ...interface{}) {} func (d debugger) logf(depth int, format string, args ...interface{}) {} func (d debugger) logHashes(depth int, hashes map[string][]byte, size int) {} func (d debugger) logParts(depth int, parts byLengthHash) {} golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/nquads.rl000066400000000000000000000047071450372207100230270ustar00rootroot00000000000000// Copyright ©2020 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. // Ragel grammar definition derived from http://www.w3.org/TR/n-quads/#sec-grammar. %%{ machine nquads; alphtype rune; PN_CHARS_BASE = [A-Za-z] | 0x00c0 .. 0x00d6 | 0x00d8 .. 0x00f6 | 0x00f8 .. 0x02ff | 0x0370 .. 0x037d | 0x037f .. 0x1fff | 0x200c .. 0x200d | 0x2070 .. 0x218f | 0x2c00 .. 0x2fef | 0x3001 .. 0xd7ff | 0xf900 .. 0xfdcf | 0xfdf0 .. 0xfffd | 0x10000 .. 0xeffff ; PN_CHARS_U = PN_CHARS_BASE | '_' | ':' ; PN_CHARS = PN_CHARS_U | '-' | [0-9] | 0xb7 | 0x0300 .. 0x036f | 0x203f .. 0x2040 ; BLANK_NODE_LABEL = (PN_CHARS_U | [0-9]) ((PN_CHARS | '.')* PN_CHARS)? ; BLANK_NODE = '_:' BLANK_NODE_LABEL ; ECHAR = ('\\' [tbnrf"'\\]) ; UCHAR = ('\\u' xdigit {4} | '\\U' xdigit {8}) ; STRING_LITERAL = ( 0x00 .. 0x09 | 0x0b .. 0x0c | 0x0e .. '!' | '#' .. '[' | ']' .. 0x10ffff | ECHAR | UCHAR)* ; STRING_LITERAL_QUOTE = '"' STRING_LITERAL '"' ; IRI = ( '!' .. ';' | '=' | '?' .. '[' | ']' | '_' | 'a' .. 'z' | '~' | 0x80 .. 0x10ffff | UCHAR)* ; IRIREF = '<' IRI >StartIRI %EndIRI '>' ; LANGTAG = '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* ; whitespace = [ \t] ; literal = STRING_LITERAL_QUOTE ('^^' IRIREF | LANGTAG)? ; subject = IRIREF | BLANK_NODE ; predicate = IRIREF ; object = IRIREF | BLANK_NODE | literal ; graphLabel = IRIREF | BLANK_NODE ; }%% golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/parse.go000066400000000000000000001632421450372207100226360ustar00rootroot00000000000000 //line parse.rl:1 // Code generated by go generate gonum.org/v1/gonum/graph/formats/rdf; DO NOT EDIT. // Copyright ©2020 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 rdf import ( "fmt" "net/url" "unicode" ) //line parse.go:19 const nquads_start int = 1 const nquads_first_final int = 87 const nquads_error int = 0 const nquads_en_statement int = 1 //line parse.rl:31 func parse(data []rune) (Statement, error) { var ( cs, p int pe = len(data) eof = pe subject = -1 predicate = -1 object = -1 label = -1 iri = -1 s Statement ) //line parse.go:46 { cs = nquads_start } //line parse.rl:49 //line parse.go:54 { if p == pe { goto _test_eof } switch cs { case 1: goto st_case_1 case 0: goto st_case_0 case 2: goto st_case_2 case 3: goto st_case_3 case 4: goto st_case_4 case 5: goto st_case_5 case 6: goto st_case_6 case 7: goto st_case_7 case 8: goto st_case_8 case 9: goto st_case_9 case 10: goto st_case_10 case 11: goto st_case_11 case 12: goto st_case_12 case 87: goto st_case_87 case 88: goto st_case_88 case 13: goto st_case_13 case 14: goto st_case_14 case 15: goto st_case_15 case 16: goto st_case_16 case 17: goto st_case_17 case 18: goto st_case_18 case 19: goto st_case_19 case 20: goto st_case_20 case 21: goto st_case_21 case 22: goto st_case_22 case 23: goto st_case_23 case 24: goto st_case_24 case 25: goto st_case_25 case 26: goto st_case_26 case 27: goto st_case_27 case 28: goto st_case_28 case 89: goto st_case_89 case 29: goto st_case_29 case 30: goto st_case_30 case 31: goto st_case_31 case 32: goto st_case_32 case 33: goto st_case_33 case 34: goto st_case_34 case 35: goto st_case_35 case 36: goto st_case_36 case 37: goto st_case_37 case 38: goto st_case_38 case 39: goto st_case_39 case 40: goto st_case_40 case 41: goto st_case_41 case 42: goto st_case_42 case 43: goto st_case_43 case 44: goto st_case_44 case 45: goto st_case_45 case 46: goto st_case_46 case 47: goto st_case_47 case 48: goto st_case_48 case 49: goto st_case_49 case 50: goto st_case_50 case 51: goto st_case_51 case 52: goto st_case_52 case 53: goto st_case_53 case 54: goto st_case_54 case 55: goto st_case_55 case 56: goto st_case_56 case 57: goto st_case_57 case 58: goto st_case_58 case 59: goto st_case_59 case 90: goto st_case_90 case 60: goto st_case_60 case 61: goto st_case_61 case 62: goto st_case_62 case 63: goto st_case_63 case 91: goto st_case_91 case 64: goto st_case_64 case 65: goto st_case_65 case 66: goto st_case_66 case 67: goto st_case_67 case 68: goto st_case_68 case 69: goto st_case_69 case 70: goto st_case_70 case 71: goto st_case_71 case 72: goto st_case_72 case 73: goto st_case_73 case 74: goto st_case_74 case 75: goto st_case_75 case 76: goto st_case_76 case 77: goto st_case_77 case 78: goto st_case_78 case 79: goto st_case_79 case 80: goto st_case_80 case 81: goto st_case_81 case 82: goto st_case_82 case 83: goto st_case_83 case 84: goto st_case_84 case 85: goto st_case_85 case 86: goto st_case_86 } goto st_out st1: if p++; p == pe { goto _test_eof1 } st_case_1: switch data[p] { case 9: goto st1 case 32: goto st1 case 60: goto tr2 case 95: goto tr3 } goto tr0 tr0: //line parse_actions.rl:75 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return s, fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalid, data[p], p) } else { return s, fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalid, data[p], p) } } return s, ErrIncomplete goto st0 //line parse.go:275 st_case_0: st0: cs = 0 goto _out tr2: //line parse_actions.rl:8 subject = p goto st2 st2: if p++; p == pe { goto _test_eof2 } st_case_2: //line parse.go:291 switch data[p] { case 62: goto tr5 case 92: goto tr6 case 95: goto tr4 case 126: goto tr4 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto tr4 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto tr4 } case data[p] >= 97: goto tr4 } default: goto tr4 } goto tr0 tr4: //line parse_actions.rl:24 iri = p goto st3 st3: if p++; p == pe { goto _test_eof3 } st_case_3: //line parse.go:331 switch data[p] { case 62: goto tr8 case 92: goto st74 case 95: goto st3 case 126: goto st3 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto st3 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto st3 } case data[p] >= 97: goto st3 } default: goto st3 } goto tr0 tr5: //line parse_actions.rl:24 iri = p //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st4 tr8: //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st4 st4: if p++; p == pe { goto _test_eof4 } st_case_4: //line parse.go:397 switch data[p] { case 9: goto tr10 case 32: goto tr10 case 60: goto tr11 } goto tr0 tr10: //line parse_actions.rl:28 if subject < 0 { panic("unexpected parser state: subject start not set") } s.Subject.Value = string(data[subject:p]) goto st5 st5: if p++; p == pe { goto _test_eof5 } st_case_5: //line parse.go:421 switch data[p] { case 9: goto st5 case 32: goto st5 case 60: goto tr13 } goto tr0 tr11: //line parse_actions.rl:28 if subject < 0 { panic("unexpected parser state: subject start not set") } s.Subject.Value = string(data[subject:p]) //line parse_actions.rl:12 predicate = p goto st6 tr13: //line parse_actions.rl:12 predicate = p goto st6 st6: if p++; p == pe { goto _test_eof6 } st_case_6: //line parse.go:455 switch data[p] { case 62: goto tr15 case 92: goto tr16 case 95: goto tr14 case 126: goto tr14 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto tr14 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto tr14 } case data[p] >= 97: goto tr14 } default: goto tr14 } goto tr0 tr14: //line parse_actions.rl:24 iri = p goto st7 st7: if p++; p == pe { goto _test_eof7 } st_case_7: //line parse.go:495 switch data[p] { case 62: goto tr18 case 92: goto st65 case 95: goto st7 case 126: goto st7 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto st7 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto st7 } case data[p] >= 97: goto st7 } default: goto st7 } goto tr0 tr15: //line parse_actions.rl:24 iri = p //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st8 tr18: //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st8 st8: if p++; p == pe { goto _test_eof8 } st_case_8: //line parse.go:561 switch data[p] { case 9: goto tr20 case 32: goto tr20 case 34: goto tr21 case 60: goto tr22 case 95: goto tr23 } goto tr0 tr20: //line parse_actions.rl:35 if predicate < 0 { panic("unexpected parser state: predicate start not set") } s.Predicate.Value = string(data[predicate:p]) goto st9 st9: if p++; p == pe { goto _test_eof9 } st_case_9: //line parse.go:589 switch data[p] { case 9: goto st9 case 32: goto st9 case 34: goto tr25 case 60: goto tr26 case 95: goto tr27 } goto tr0 tr21: //line parse_actions.rl:35 if predicate < 0 { panic("unexpected parser state: predicate start not set") } s.Predicate.Value = string(data[predicate:p]) //line parse_actions.rl:16 object = p goto st10 tr25: //line parse_actions.rl:16 object = p goto st10 st10: if p++; p == pe { goto _test_eof10 } st_case_10: //line parse.go:627 switch data[p] { case 34: goto st11 case 92: goto st48 } switch { case data[p] < 11: if 0 <= data[p] && data[p] <= 9 { goto st10 } case data[p] > 12: if 14 <= data[p] && data[p] <= 1114111 { goto st10 } default: goto st10 } goto tr0 st11: if p++; p == pe { goto _test_eof11 } st_case_11: switch data[p] { case 9: goto tr31 case 32: goto tr31 case 46: goto tr32 case 60: goto tr33 case 64: goto st30 case 94: goto st34 case 95: goto tr36 } goto tr0 tr31: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) goto st12 tr97: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) //line parse_actions.rl:49 if label < 0 { panic("unexpected parser state: label start not set") } s.Label.Value = string(data[label:p]) goto st12 st12: if p++; p == pe { goto _test_eof12 } st_case_12: //line parse.go:699 switch data[p] { case 9: goto st12 case 32: goto st12 case 46: goto st87 case 60: goto tr39 case 95: goto tr40 } goto tr0 tr32: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) goto st87 tr48: //line parse_actions.rl:49 if label < 0 { panic("unexpected parser state: label start not set") } s.Label.Value = string(data[label:p]) goto st87 st87: if p++; p == pe { goto _test_eof87 } st_case_87: //line parse.go:736 switch data[p] { case 9: goto st87 case 32: goto st87 case 35: goto tr120 } goto st0 tr120: //line parse_actions.rl:72 goto st88 st88: if p++; p == pe { goto _test_eof88 } st_case_88: //line parse.go:756 goto st88 tr33: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) //line parse_actions.rl:20 label = p goto st13 tr39: //line parse_actions.rl:20 label = p goto st13 st13: if p++; p == pe { goto _test_eof13 } st_case_13: //line parse.go:782 switch data[p] { case 62: goto tr42 case 92: goto tr43 case 95: goto tr41 case 126: goto tr41 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto tr41 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto tr41 } case data[p] >= 97: goto tr41 } default: goto tr41 } goto tr0 tr41: //line parse_actions.rl:24 iri = p goto st14 st14: if p++; p == pe { goto _test_eof14 } st_case_14: //line parse.go:822 switch data[p] { case 62: goto tr45 case 92: goto st17 case 95: goto st14 case 126: goto st14 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto st14 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto st14 } case data[p] >= 97: goto st14 } default: goto st14 } goto tr0 tr42: //line parse_actions.rl:24 iri = p //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st15 tr45: //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st15 st15: if p++; p == pe { goto _test_eof15 } st_case_15: //line parse.go:888 switch data[p] { case 9: goto tr47 case 32: goto tr47 case 46: goto tr48 } goto tr0 tr47: //line parse_actions.rl:49 if label < 0 { panic("unexpected parser state: label start not set") } s.Label.Value = string(data[label:p]) goto st16 st16: if p++; p == pe { goto _test_eof16 } st_case_16: //line parse.go:912 switch data[p] { case 9: goto st16 case 32: goto st16 case 46: goto st87 } goto tr0 tr43: //line parse_actions.rl:24 iri = p goto st17 st17: if p++; p == pe { goto _test_eof17 } st_case_17: //line parse.go:933 switch data[p] { case 85: goto st18 case 117: goto st22 } goto tr0 st18: if p++; p == pe { goto _test_eof18 } st_case_18: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st19 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st19 } default: goto st19 } goto tr0 st19: if p++; p == pe { goto _test_eof19 } st_case_19: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st20 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st20 } default: goto st20 } goto tr0 st20: if p++; p == pe { goto _test_eof20 } st_case_20: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st21 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st21 } default: goto st21 } goto tr0 st21: if p++; p == pe { goto _test_eof21 } st_case_21: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st22 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st22 } default: goto st22 } goto tr0 st22: if p++; p == pe { goto _test_eof22 } st_case_22: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st23 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st23 } default: goto st23 } goto tr0 st23: if p++; p == pe { goto _test_eof23 } st_case_23: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st24 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st24 } default: goto st24 } goto tr0 st24: if p++; p == pe { goto _test_eof24 } st_case_24: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st25 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st25 } default: goto st25 } goto tr0 st25: if p++; p == pe { goto _test_eof25 } st_case_25: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st14 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st14 } default: goto st14 } goto tr0 tr36: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) //line parse_actions.rl:20 label = p goto st26 tr40: //line parse_actions.rl:20 label = p goto st26 st26: if p++; p == pe { goto _test_eof26 } st_case_26: //line parse.go:1109 if data[p] == 58 { goto st27 } goto tr0 st27: if p++; p == pe { goto _test_eof27 } st_case_27: if data[p] == 95 { goto st28 } switch { case data[p] < 895: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st28 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st28 } default: goto st28 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st28 } case data[p] > 767: if 880 <= data[p] && data[p] <= 893 { goto st28 } default: goto st28 } default: goto st28 } case data[p] > 8191: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8204 <= data[p] && data[p] <= 8205 { goto st28 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st28 } default: goto st28 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st28 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st28 } default: goto st28 } default: goto st28 } default: goto st28 } goto tr0 st28: if p++; p == pe { goto _test_eof28 } st_case_28: switch data[p] { case 9: goto tr47 case 32: goto tr47 case 45: goto st28 case 46: goto tr60 case 95: goto st28 case 183: goto st28 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st28 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st28 } default: goto st28 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st28 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st28 } default: goto st28 } default: goto st28 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st28 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st28 } default: goto st28 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st28 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st28 } default: goto st28 } default: goto st28 } default: goto st28 } goto tr0 tr60: //line parse_actions.rl:49 if label < 0 { panic("unexpected parser state: label start not set") } s.Label.Value = string(data[label:p]) goto st89 st89: if p++; p == pe { goto _test_eof89 } st_case_89: //line parse.go:1289 switch data[p] { case 9: goto st87 case 32: goto st87 case 35: goto tr120 case 45: goto st28 case 46: goto st29 case 95: goto st28 case 183: goto st28 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st28 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st28 } default: goto st28 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st28 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st28 } default: goto st28 } default: goto st28 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st28 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st28 } default: goto st28 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st28 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st28 } default: goto st28 } default: goto st28 } default: goto st28 } goto st0 st29: if p++; p == pe { goto _test_eof29 } st_case_29: switch data[p] { case 45: goto st28 case 46: goto st29 case 95: goto st28 case 183: goto st28 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st28 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st28 } default: goto st28 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st28 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st28 } default: goto st28 } default: goto st28 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st28 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st28 } default: goto st28 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st28 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st28 } default: goto st28 } default: goto st28 } default: goto st28 } goto tr0 st30: if p++; p == pe { goto _test_eof30 } st_case_30: switch { case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st31 } case data[p] >= 65: goto st31 } goto tr0 st31: if p++; p == pe { goto _test_eof31 } st_case_31: switch data[p] { case 9: goto tr31 case 32: goto tr31 case 45: goto st32 case 46: goto tr32 case 60: goto tr33 case 95: goto tr36 } switch { case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st31 } case data[p] >= 65: goto st31 } goto tr0 st32: if p++; p == pe { goto _test_eof32 } st_case_32: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st33 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st33 } default: goto st33 } goto tr0 st33: if p++; p == pe { goto _test_eof33 } st_case_33: switch data[p] { case 9: goto tr31 case 32: goto tr31 case 45: goto st32 case 46: goto tr32 case 60: goto tr33 case 95: goto tr36 } switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st33 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st33 } default: goto st33 } goto tr0 st34: if p++; p == pe { goto _test_eof34 } st_case_34: if data[p] == 94 { goto st35 } goto tr0 st35: if p++; p == pe { goto _test_eof35 } st_case_35: if data[p] == 60 { goto st36 } goto tr0 tr22: //line parse_actions.rl:35 if predicate < 0 { panic("unexpected parser state: predicate start not set") } s.Predicate.Value = string(data[predicate:p]) //line parse_actions.rl:16 object = p goto st36 tr26: //line parse_actions.rl:16 object = p goto st36 st36: if p++; p == pe { goto _test_eof36 } st_case_36: //line parse.go:1589 switch data[p] { case 62: goto tr68 case 92: goto tr69 case 95: goto tr67 case 126: goto tr67 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto tr67 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto tr67 } case data[p] >= 97: goto tr67 } default: goto tr67 } goto tr0 tr67: //line parse_actions.rl:24 iri = p goto st37 st37: if p++; p == pe { goto _test_eof37 } st_case_37: //line parse.go:1629 switch data[p] { case 62: goto tr71 case 92: goto st39 case 95: goto st37 case 126: goto st37 } switch { case data[p] < 61: if 33 <= data[p] && data[p] <= 59 { goto st37 } case data[p] > 93: switch { case data[p] > 122: if 128 <= data[p] && data[p] <= 1114111 { goto st37 } case data[p] >= 97: goto st37 } default: goto st37 } goto tr0 tr68: //line parse_actions.rl:24 iri = p //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st38 tr71: //line parse_actions.rl:56 if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } goto st38 st38: if p++; p == pe { goto _test_eof38 } st_case_38: //line parse.go:1695 switch data[p] { case 9: goto tr31 case 32: goto tr31 case 46: goto tr32 case 60: goto tr33 case 95: goto tr36 } goto tr0 tr69: //line parse_actions.rl:24 iri = p goto st39 st39: if p++; p == pe { goto _test_eof39 } st_case_39: //line parse.go:1720 switch data[p] { case 85: goto st40 case 117: goto st44 } goto tr0 st40: if p++; p == pe { goto _test_eof40 } st_case_40: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st41 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st41 } default: goto st41 } goto tr0 st41: if p++; p == pe { goto _test_eof41 } st_case_41: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st42 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st42 } default: goto st42 } goto tr0 st42: if p++; p == pe { goto _test_eof42 } st_case_42: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st43 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st43 } default: goto st43 } goto tr0 st43: if p++; p == pe { goto _test_eof43 } st_case_43: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st44 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st44 } default: goto st44 } goto tr0 st44: if p++; p == pe { goto _test_eof44 } st_case_44: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st45 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st45 } default: goto st45 } goto tr0 st45: if p++; p == pe { goto _test_eof45 } st_case_45: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st46 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st46 } default: goto st46 } goto tr0 st46: if p++; p == pe { goto _test_eof46 } st_case_46: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st47 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st47 } default: goto st47 } goto tr0 st47: if p++; p == pe { goto _test_eof47 } st_case_47: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st37 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st37 } default: goto st37 } goto tr0 st48: if p++; p == pe { goto _test_eof48 } st_case_48: switch data[p] { case 34: goto st10 case 39: goto st10 case 85: goto st49 case 92: goto st10 case 98: goto st10 case 102: goto st10 case 110: goto st10 case 114: goto st10 case 116: goto st10 case 117: goto st53 } goto tr0 st49: if p++; p == pe { goto _test_eof49 } st_case_49: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st50 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st50 } default: goto st50 } goto tr0 st50: if p++; p == pe { goto _test_eof50 } st_case_50: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st51 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st51 } default: goto st51 } goto tr0 st51: if p++; p == pe { goto _test_eof51 } st_case_51: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st52 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st52 } default: goto st52 } goto tr0 st52: if p++; p == pe { goto _test_eof52 } st_case_52: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st53 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st53 } default: goto st53 } goto tr0 st53: if p++; p == pe { goto _test_eof53 } st_case_53: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st54 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st54 } default: goto st54 } goto tr0 st54: if p++; p == pe { goto _test_eof54 } st_case_54: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st55 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st55 } default: goto st55 } goto tr0 st55: if p++; p == pe { goto _test_eof55 } st_case_55: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st56 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st56 } default: goto st56 } goto tr0 st56: if p++; p == pe { goto _test_eof56 } st_case_56: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st10 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st10 } default: goto st10 } goto tr0 tr23: //line parse_actions.rl:35 if predicate < 0 { panic("unexpected parser state: predicate start not set") } s.Predicate.Value = string(data[predicate:p]) //line parse_actions.rl:16 object = p goto st57 tr27: //line parse_actions.rl:16 object = p goto st57 st57: if p++; p == pe { goto _test_eof57 } st_case_57: //line parse.go:2068 if data[p] == 58 { goto st58 } goto tr0 st58: if p++; p == pe { goto _test_eof58 } st_case_58: if data[p] == 95 { goto st59 } switch { case data[p] < 895: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st59 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st59 } default: goto st59 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st59 } case data[p] > 767: if 880 <= data[p] && data[p] <= 893 { goto st59 } default: goto st59 } default: goto st59 } case data[p] > 8191: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8204 <= data[p] && data[p] <= 8205 { goto st59 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st59 } default: goto st59 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st59 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st59 } default: goto st59 } default: goto st59 } default: goto st59 } goto tr0 st59: if p++; p == pe { goto _test_eof59 } st_case_59: switch data[p] { case 9: goto tr31 case 32: goto tr31 case 45: goto st59 case 46: goto tr91 case 60: goto tr33 case 95: goto tr92 case 183: goto st59 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st59 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st59 } default: goto st59 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st59 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st59 } default: goto st59 } default: goto st59 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st59 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st59 } default: goto st59 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st59 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st59 } default: goto st59 } default: goto st59 } default: goto st59 } goto tr0 tr91: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) goto st90 st90: if p++; p == pe { goto _test_eof90 } st_case_90: //line parse.go:2250 switch data[p] { case 9: goto st87 case 32: goto st87 case 35: goto tr120 case 45: goto st59 case 46: goto st60 case 95: goto st59 case 183: goto st59 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st59 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st59 } default: goto st59 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st59 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st59 } default: goto st59 } default: goto st59 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st59 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st59 } default: goto st59 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st59 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st59 } default: goto st59 } default: goto st59 } default: goto st59 } goto st0 st60: if p++; p == pe { goto _test_eof60 } st_case_60: switch data[p] { case 45: goto st59 case 46: goto st60 case 95: goto st59 case 183: goto st59 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st59 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st59 } default: goto st59 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st59 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st59 } default: goto st59 } default: goto st59 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st59 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st59 } default: goto st59 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st59 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st59 } default: goto st59 } default: goto st59 } default: goto st59 } goto tr0 tr92: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) //line parse_actions.rl:20 label = p goto st61 st61: if p++; p == pe { goto _test_eof61 } st_case_61: //line parse.go:2434 switch data[p] { case 9: goto tr31 case 32: goto tr31 case 45: goto st59 case 46: goto tr91 case 58: goto st62 case 60: goto tr33 case 95: goto tr92 case 183: goto st59 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st59 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st59 } default: goto st59 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st59 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st59 } default: goto st59 } default: goto st59 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st59 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st59 } default: goto st59 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st59 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st59 } default: goto st59 } default: goto st59 } default: goto st59 } goto tr0 st62: if p++; p == pe { goto _test_eof62 } st_case_62: switch data[p] { case 9: goto tr31 case 32: goto tr31 case 45: goto st59 case 46: goto tr91 case 60: goto tr33 case 95: goto tr96 case 183: goto st59 } switch { case data[p] < 895: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st63 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st63 } default: goto st63 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st63 } case data[p] > 767: switch { case data[p] > 879: if 880 <= data[p] && data[p] <= 893 { goto st63 } case data[p] >= 768: goto st59 } default: goto st63 } default: goto st63 } case data[p] > 8191: switch { case data[p] < 11264: switch { case data[p] < 8255: if 8204 <= data[p] && data[p] <= 8205 { goto st63 } case data[p] > 8256: if 8304 <= data[p] && data[p] <= 8591 { goto st63 } default: goto st59 } case data[p] > 12271: switch { case data[p] < 63744: if 12289 <= data[p] && data[p] <= 55295 { goto st63 } case data[p] > 64975: switch { case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st63 } case data[p] >= 65008: goto st63 } default: goto st63 } default: goto st63 } default: goto st63 } goto tr0 tr96: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) //line parse_actions.rl:20 label = p goto st63 st63: if p++; p == pe { goto _test_eof63 } st_case_63: //line parse.go:2636 switch data[p] { case 9: goto tr97 case 32: goto tr97 case 45: goto st63 case 46: goto tr98 case 60: goto tr33 case 95: goto tr96 case 183: goto st63 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st63 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st63 } default: goto st63 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st63 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st63 } default: goto st63 } default: goto st63 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st63 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st63 } default: goto st63 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st63 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st63 } default: goto st63 } default: goto st63 } default: goto st63 } goto tr0 tr98: //line parse_actions.rl:42 if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) //line parse_actions.rl:49 if label < 0 { panic("unexpected parser state: label start not set") } s.Label.Value = string(data[label:p]) goto st91 st91: if p++; p == pe { goto _test_eof91 } st_case_91: //line parse.go:2741 switch data[p] { case 9: goto st87 case 32: goto st87 case 35: goto tr120 case 45: goto st63 case 46: goto st64 case 95: goto st63 case 183: goto st63 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st63 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st63 } default: goto st63 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st63 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st63 } default: goto st63 } default: goto st63 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st63 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st63 } default: goto st63 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st63 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st63 } default: goto st63 } default: goto st63 } default: goto st63 } goto st0 st64: if p++; p == pe { goto _test_eof64 } st_case_64: switch data[p] { case 45: goto st63 case 46: goto st64 case 95: goto st63 case 183: goto st63 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st63 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st63 } default: goto st63 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st63 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st63 } default: goto st63 } default: goto st63 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st63 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st63 } default: goto st63 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st63 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st63 } default: goto st63 } default: goto st63 } default: goto st63 } goto tr0 tr16: //line parse_actions.rl:24 iri = p goto st65 st65: if p++; p == pe { goto _test_eof65 } st_case_65: //line parse.go:2918 switch data[p] { case 85: goto st66 case 117: goto st70 } goto tr0 st66: if p++; p == pe { goto _test_eof66 } st_case_66: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st67 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st67 } default: goto st67 } goto tr0 st67: if p++; p == pe { goto _test_eof67 } st_case_67: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st68 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st68 } default: goto st68 } goto tr0 st68: if p++; p == pe { goto _test_eof68 } st_case_68: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st69 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st69 } default: goto st69 } goto tr0 st69: if p++; p == pe { goto _test_eof69 } st_case_69: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st70 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st70 } default: goto st70 } goto tr0 st70: if p++; p == pe { goto _test_eof70 } st_case_70: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st71 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st71 } default: goto st71 } goto tr0 st71: if p++; p == pe { goto _test_eof71 } st_case_71: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st72 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st72 } default: goto st72 } goto tr0 st72: if p++; p == pe { goto _test_eof72 } st_case_72: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st73 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st73 } default: goto st73 } goto tr0 st73: if p++; p == pe { goto _test_eof73 } st_case_73: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st7 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st7 } default: goto st7 } goto tr0 tr6: //line parse_actions.rl:24 iri = p goto st74 st74: if p++; p == pe { goto _test_eof74 } st_case_74: //line parse.go:3081 switch data[p] { case 85: goto st75 case 117: goto st79 } goto tr0 st75: if p++; p == pe { goto _test_eof75 } st_case_75: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st76 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st76 } default: goto st76 } goto tr0 st76: if p++; p == pe { goto _test_eof76 } st_case_76: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st77 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st77 } default: goto st77 } goto tr0 st77: if p++; p == pe { goto _test_eof77 } st_case_77: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st78 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st78 } default: goto st78 } goto tr0 st78: if p++; p == pe { goto _test_eof78 } st_case_78: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st79 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st79 } default: goto st79 } goto tr0 st79: if p++; p == pe { goto _test_eof79 } st_case_79: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st80 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st80 } default: goto st80 } goto tr0 st80: if p++; p == pe { goto _test_eof80 } st_case_80: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st81 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st81 } default: goto st81 } goto tr0 st81: if p++; p == pe { goto _test_eof81 } st_case_81: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st82 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st82 } default: goto st82 } goto tr0 st82: if p++; p == pe { goto _test_eof82 } st_case_82: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 57 { goto st3 } case data[p] > 70: if 97 <= data[p] && data[p] <= 102 { goto st3 } default: goto st3 } goto tr0 tr3: //line parse_actions.rl:8 subject = p goto st83 st83: if p++; p == pe { goto _test_eof83 } st_case_83: //line parse.go:3244 if data[p] == 58 { goto st84 } goto tr0 st84: if p++; p == pe { goto _test_eof84 } st_case_84: if data[p] == 95 { goto st85 } switch { case data[p] < 895: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st85 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st85 } default: goto st85 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st85 } case data[p] > 767: if 880 <= data[p] && data[p] <= 893 { goto st85 } default: goto st85 } default: goto st85 } case data[p] > 8191: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8204 <= data[p] && data[p] <= 8205 { goto st85 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st85 } default: goto st85 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st85 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st85 } default: goto st85 } default: goto st85 } default: goto st85 } goto tr0 st85: if p++; p == pe { goto _test_eof85 } st_case_85: switch data[p] { case 9: goto tr10 case 32: goto tr10 case 45: goto st85 case 46: goto st86 case 60: goto tr11 case 95: goto st85 case 183: goto st85 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st85 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st85 } default: goto st85 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st85 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st85 } default: goto st85 } default: goto st85 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st85 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st85 } default: goto st85 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st85 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st85 } default: goto st85 } default: goto st85 } default: goto st85 } goto tr0 st86: if p++; p == pe { goto _test_eof86 } st_case_86: switch data[p] { case 45: goto st85 case 46: goto st86 case 95: goto st85 case 183: goto st85 } switch { case data[p] < 8204: switch { case data[p] < 192: switch { case data[p] < 65: if 48 <= data[p] && data[p] <= 58 { goto st85 } case data[p] > 90: if 97 <= data[p] && data[p] <= 122 { goto st85 } default: goto st85 } case data[p] > 214: switch { case data[p] < 248: if 216 <= data[p] && data[p] <= 246 { goto st85 } case data[p] > 893: if 895 <= data[p] && data[p] <= 8191 { goto st85 } default: goto st85 } default: goto st85 } case data[p] > 8205: switch { case data[p] < 12289: switch { case data[p] < 8304: if 8255 <= data[p] && data[p] <= 8256 { goto st85 } case data[p] > 8591: if 11264 <= data[p] && data[p] <= 12271 { goto st85 } default: goto st85 } case data[p] > 55295: switch { case data[p] < 65008: if 63744 <= data[p] && data[p] <= 64975 { goto st85 } case data[p] > 65533: if 65536 <= data[p] && data[p] <= 983039 { goto st85 } default: goto st85 } default: goto st85 } default: goto st85 } goto tr0 st_out: _test_eof1: cs = 1; goto _test_eof _test_eof2: cs = 2; goto _test_eof _test_eof3: cs = 3; goto _test_eof _test_eof4: cs = 4; goto _test_eof _test_eof5: cs = 5; goto _test_eof _test_eof6: cs = 6; goto _test_eof _test_eof7: cs = 7; goto _test_eof _test_eof8: cs = 8; goto _test_eof _test_eof9: cs = 9; goto _test_eof _test_eof10: cs = 10; goto _test_eof _test_eof11: cs = 11; goto _test_eof _test_eof12: cs = 12; goto _test_eof _test_eof87: cs = 87; goto _test_eof _test_eof88: cs = 88; goto _test_eof _test_eof13: cs = 13; goto _test_eof _test_eof14: cs = 14; goto _test_eof _test_eof15: cs = 15; goto _test_eof _test_eof16: cs = 16; goto _test_eof _test_eof17: cs = 17; goto _test_eof _test_eof18: cs = 18; goto _test_eof _test_eof19: cs = 19; goto _test_eof _test_eof20: cs = 20; goto _test_eof _test_eof21: cs = 21; goto _test_eof _test_eof22: cs = 22; goto _test_eof _test_eof23: cs = 23; goto _test_eof _test_eof24: cs = 24; goto _test_eof _test_eof25: cs = 25; goto _test_eof _test_eof26: cs = 26; goto _test_eof _test_eof27: cs = 27; goto _test_eof _test_eof28: cs = 28; goto _test_eof _test_eof89: cs = 89; goto _test_eof _test_eof29: cs = 29; goto _test_eof _test_eof30: cs = 30; goto _test_eof _test_eof31: cs = 31; goto _test_eof _test_eof32: cs = 32; goto _test_eof _test_eof33: cs = 33; goto _test_eof _test_eof34: cs = 34; goto _test_eof _test_eof35: cs = 35; goto _test_eof _test_eof36: cs = 36; goto _test_eof _test_eof37: cs = 37; goto _test_eof _test_eof38: cs = 38; goto _test_eof _test_eof39: cs = 39; goto _test_eof _test_eof40: cs = 40; goto _test_eof _test_eof41: cs = 41; goto _test_eof _test_eof42: cs = 42; goto _test_eof _test_eof43: cs = 43; goto _test_eof _test_eof44: cs = 44; goto _test_eof _test_eof45: cs = 45; goto _test_eof _test_eof46: cs = 46; goto _test_eof _test_eof47: cs = 47; goto _test_eof _test_eof48: cs = 48; goto _test_eof _test_eof49: cs = 49; goto _test_eof _test_eof50: cs = 50; goto _test_eof _test_eof51: cs = 51; goto _test_eof _test_eof52: cs = 52; goto _test_eof _test_eof53: cs = 53; goto _test_eof _test_eof54: cs = 54; goto _test_eof _test_eof55: cs = 55; goto _test_eof _test_eof56: cs = 56; goto _test_eof _test_eof57: cs = 57; goto _test_eof _test_eof58: cs = 58; goto _test_eof _test_eof59: cs = 59; goto _test_eof _test_eof90: cs = 90; goto _test_eof _test_eof60: cs = 60; goto _test_eof _test_eof61: cs = 61; goto _test_eof _test_eof62: cs = 62; goto _test_eof _test_eof63: cs = 63; goto _test_eof _test_eof91: cs = 91; goto _test_eof _test_eof64: cs = 64; goto _test_eof _test_eof65: cs = 65; goto _test_eof _test_eof66: cs = 66; goto _test_eof _test_eof67: cs = 67; goto _test_eof _test_eof68: cs = 68; goto _test_eof _test_eof69: cs = 69; goto _test_eof _test_eof70: cs = 70; goto _test_eof _test_eof71: cs = 71; goto _test_eof _test_eof72: cs = 72; goto _test_eof _test_eof73: cs = 73; goto _test_eof _test_eof74: cs = 74; goto _test_eof _test_eof75: cs = 75; goto _test_eof _test_eof76: cs = 76; goto _test_eof _test_eof77: cs = 77; goto _test_eof _test_eof78: cs = 78; goto _test_eof _test_eof79: cs = 79; goto _test_eof _test_eof80: cs = 80; goto _test_eof _test_eof81: cs = 81; goto _test_eof _test_eof82: cs = 82; goto _test_eof _test_eof83: cs = 83; goto _test_eof _test_eof84: cs = 84; goto _test_eof _test_eof85: cs = 85; goto _test_eof _test_eof86: cs = 86; goto _test_eof _test_eof: {} if p == eof { switch cs { case 88: //line parse_actions.rl:68 return s, nil case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86: //line parse_actions.rl:75 if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return s, fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalid, data[p], p) } else { return s, fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalid, data[p], p) } } return s, ErrIncomplete case 87, 89, 90, 91: //line parse_actions.rl:72 //line parse_actions.rl:68 return s, nil //line parse.go:3615 } } _out: {} } //line parse.rl:51 return Statement{}, ErrInvalid } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/parse.rl000066400000000000000000000020441450372207100226360ustar00rootroot00000000000000// Code generated by go generate gonum.org/v1/gonum/graph/formats/rdf; DO NOT EDIT. // Copyright ©2020 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 rdf import ( "fmt" "net/url" "unicode" ) %%{ machine nquads; include "parse_actions.rl"; include "nquads.rl"; statement := ( whitespace* subject >StartSubject %SetSubject whitespace* predicate >StartPredicate %SetPredicate whitespace* object >StartObject %SetObject (whitespace* graphLabel >StartLabel %SetLabel)? whitespace* '.' whitespace* ('#' any*)? >Comment ) %Return @!Error ; write data; }%% func parse(data []rune) (Statement, error) { var ( cs, p int pe = len(data) eof = pe subject = -1 predicate = -1 object = -1 label = -1 iri = -1 s Statement ) %%write init; %%write exec; return Statement{}, ErrInvalid } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/parse_actions.rl000066400000000000000000000031501450372207100243550ustar00rootroot00000000000000// Copyright ©2020 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. %%{ machine nquads; action StartSubject { subject = p } action StartPredicate { predicate = p } action StartObject { object = p } action StartLabel { label = p } action StartIRI { iri = p } action SetSubject { if subject < 0 { panic("unexpected parser state: subject start not set") } s.Subject.Value = string(data[subject:p]) } action SetPredicate { if predicate < 0 { panic("unexpected parser state: predicate start not set") } s.Predicate.Value = string(data[predicate:p]) } action SetObject { if object < 0 { panic("unexpected parser state: object start not set") } s.Object.Value = string(data[object:p]) } action SetLabel { if label < 0 { panic("unexpected parser state: label start not set") } s.Label.Value = string(data[label:p]) } action EndIRI { if iri < 0 { panic("unexpected parser state: iri start not set") } switch u, err := url.Parse(string(data[iri:p])); { case err != nil: return s, err case !u.IsAbs(): return s, fmt.Errorf("%w: relative IRI ref %q", ErrInvalid, string(data[iri:p])) } } action Return { return s, nil } action Comment { } action Error { if p < len(data) { if r := data[p]; r < unicode.MaxASCII { return s, fmt.Errorf("%w: unexpected rune %q at %d", ErrInvalid, data[p], p) } else { return s, fmt.Errorf("%w: unexpected rune %q (\\u%04[2]x) at %d", ErrInvalid, data[p], p) } } return s, ErrIncomplete } }%% golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/query.go000066400000000000000000000156461450372207100226750ustar00rootroot00000000000000// Copyright ©2022 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 rdf import ( "sort" "gonum.org/v1/gonum/graph" ) // Query represents a step in an RDF graph query. The methods on Query // provide a simple graph query language. type Query struct { g graph.Directed terms []Term } // NewQuery returns a query of g starting from the given nodes. // Queries may not be mixed between distinct graphs. The type of // g must be comparable. Query operations only consider edges that // are represented by a *Statement or is an edge with lines held // in a graph.Lines with at least one *Statement. func NewQuery(g graph.Directed, from ...Term) Query { return Query{g: g, terms: from} } // Query returns a query of the receiver starting from the given nodes. // Queries may not be mixed between distinct graphs. func (g *Graph) Query(from ...Term) Query { return Query{g: g, terms: from} } // Out returns a query holding nodes reachable out from the receiver's // starting nodes via statements that satisfy fn. func (q Query) Out(fn func(s *Statement) bool) Query { r := Query{g: q.g} for _, s := range q.terms { it := q.g.From(s.ID()) for it.Next() { if ConnectedByAny(q.g.Edge(s.ID(), it.Node().ID()), fn) { r.terms = append(r.terms, it.Node().(Term)) } } } return r } // In returns a query holding nodes reachable in from the receiver's // starting nodes via statements that satisfy fn. func (q Query) In(fn func(s *Statement) bool) Query { r := Query{g: q.g} for _, s := range q.terms { it := q.g.To(s.ID()) for it.Next() { if ConnectedByAny(q.g.Edge(it.Node().ID(), s.ID()), fn) { r.terms = append(r.terms, it.Node().(Term)) } } } return r } // HasAllOut returns a query holding nodes from the receiver's // initial set where all outgoing statements satisfy fn. The // query short circuits, so fn is not called after the first // failure to match. func (q Query) HasAllOut(fn func(s *Statement) bool) Query { r := Query{g: q.g} notFn := not(fn) loop: for _, s := range q.terms { it := q.g.From(s.ID()) for it.Next() { if ConnectedByAny(q.g.Edge(s.ID(), it.Node().ID()), notFn) { continue loop } } r.terms = append(r.terms, s) } return r } // HasAllIn returns a query holding nodes from the receiver's // initial set where all incoming statements satisfy fn. The // query short circuits, so fn is not called after the first // failure to match. func (q Query) HasAllIn(fn func(s *Statement) bool) Query { r := Query{g: q.g} notFn := not(fn) loop: for _, s := range q.terms { it := q.g.To(s.ID()) for it.Next() { if ConnectedByAny(q.g.Edge(it.Node().ID(), s.ID()), notFn) { continue loop } } r.terms = append(r.terms, s) } return r } // HasAnyOut returns a query holding nodes from the receiver's // initial set where any outgoing statements satisfies fn. The // query short circuits, so fn is not called after the first match. func (q Query) HasAnyOut(fn func(s *Statement) bool) Query { r := Query{g: q.g} for _, s := range q.terms { it := q.g.From(s.ID()) for it.Next() { if ConnectedByAny(q.g.Edge(s.ID(), it.Node().ID()), fn) { r.terms = append(r.terms, s) break } } } return r } // HasAnyIn returns a query holding nodes from the receiver's // initial set where any incoming statements satisfies fn. The // query short circuits, so fn is not called after the first match. func (q Query) HasAnyIn(fn func(s *Statement) bool) Query { r := Query{g: q.g} for _, s := range q.terms { it := q.g.To(s.ID()) for it.Next() { if ConnectedByAny(q.g.Edge(it.Node().ID(), s.ID()), fn) { r.terms = append(r.terms, s) break } } } return r } // not returns the negation of fn. func not(fn func(s *Statement) bool) func(s *Statement) bool { return func(s *Statement) bool { return !fn(s) } } // And returns a query that holds the conjunction of q and p. func (q Query) And(p Query) Query { if q.g != p.g { panic("rdf: binary query operation parameters from distinct graphs") } sortByID(q.terms) sortByID(p.terms) r := Query{g: q.g} var i, j int for i < len(q.terms) && j < len(p.terms) { qi := q.terms[i] pj := p.terms[j] switch { case qi.ID() < pj.ID(): i++ case pj.ID() < qi.ID(): j++ default: r.terms = append(r.terms, qi) i++ j++ } } return r } // Or returns a query that holds the disjunction of q and p. func (q Query) Or(p Query) Query { if q.g != p.g { panic("rdf: binary query operation parameters from distinct graphs") } sortByID(q.terms) sortByID(p.terms) r := Query{g: q.g} var i, j int for i < len(q.terms) && j < len(p.terms) { qi := q.terms[i] pj := p.terms[j] switch { case qi.ID() < pj.ID(): if len(r.terms) == 0 || r.terms[len(r.terms)-1].UID != qi.UID { r.terms = append(r.terms, qi) } i++ case pj.ID() < qi.ID(): if len(r.terms) == 0 || r.terms[len(r.terms)-1].UID != pj.UID { r.terms = append(r.terms, pj) } j++ default: if len(r.terms) == 0 || r.terms[len(r.terms)-1].UID != qi.UID { r.terms = append(r.terms, qi) } i++ j++ } } r.terms = append(r.terms, q.terms[i:]...) r.terms = append(r.terms, p.terms[j:]...) return r } // Not returns a query that holds q less p. func (q Query) Not(p Query) Query { if q.g != p.g { panic("rdf: binary query operation parameters from distinct graphs") } sortByID(q.terms) sortByID(p.terms) r := Query{g: q.g} var i, j int for i < len(q.terms) && j < len(p.terms) { qi := q.terms[i] pj := p.terms[j] switch { case qi.ID() < pj.ID(): r.terms = append(r.terms, qi) i++ case pj.ID() < qi.ID(): j++ default: i++ } } if len(r.terms) < len(q.terms) { r.terms = append(r.terms, q.terms[i:len(q.terms)+min(0, i-len(r.terms))]...) } return r } // Repeat repeatedly calls fn on q until the set of results is empty or // ok is false, and then returns the result. If the last non-empty result // is wanted, fn should return its input and false when the partial // traversal returns an empty result. // // result := start.Repeat(func(q rdf.Query) (rdf.Query, bool) { // r := q.Out(condition) // if r.Len() == 0 { // return q, false // } // return r, true // }).Result() func (q Query) Repeat(fn func(Query) (q Query, ok bool)) Query { for { var ok bool q, ok = fn(q) if !ok || len(q.terms) == 0 { return q } } } // Unique returns a copy of the receiver that contains only one instance // of each term. func (q Query) Unique() Query { sortByID(q.terms) r := Query{g: q.g} for i, t := range q.terms { if i == 0 || t.UID != q.terms[i-1].UID { r.terms = append(r.terms, t) } } return r } // Len returns the number of terms held by the query. func (q Query) Len() int { return len(q.terms) } // Result returns the terms held by the query. func (q Query) Result() []Term { return q.terms } func sortByID(terms []Term) { sort.Slice(terms, func(i, j int) bool { return terms[i].ID() < terms[j].ID() }) } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/query_test.go000066400000000000000000000504431450372207100237260ustar00rootroot00000000000000// Copyright ©2022 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 rdf import ( "io" "reflect" "strings" "testing" "golang.org/x/exp/rand" ) var andTests = []struct { name string a, b []Term want []Term }{ { name: "identical", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "identical with excess a", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "identical with excess b", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "b less", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}}, }, { name: "a less", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 3}}, }, } func TestQueryAnd(t *testing.T) { src := rand.NewSource(1) for _, test := range andTests { for i := 0; i < 10; i++ { a := Query{terms: permutedTerms(test.a, src)} b := Query{terms: permutedTerms(test.b, src)} got := a.And(b).Result() sortByID(got) sortByID(test.want) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) } } } } var orTests = []struct { name string a, b []Term want []Term }{ { name: "identical", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "identical with excess a", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "identical with excess b", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "b less", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "a less", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, } func TestQueryOr(t *testing.T) { src := rand.NewSource(1) for _, test := range orTests { for i := 0; i < 10; i++ { a := Query{terms: permutedTerms(test.a, src)} b := Query{terms: permutedTerms(test.b, src)} got := a.Or(b).Result() sortByID(got) sortByID(test.want) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) } } } } var notTests = []struct { name string a, b []Term want []Term }{ { name: "identical", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: nil, }, { name: "identical with excess a", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: nil, }, { name: "identical with excess b", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: nil, }, { name: "b less", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}}, want: []Term{{Value: "", UID: 3}}, }, { name: "a less", a: []Term{{Value: "", UID: 1}, {Value: "", UID: 3}}, b: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: nil, }, } func TestQueryNot(t *testing.T) { src := rand.NewSource(1) for _, test := range notTests { for i := 0; i < 10; i++ { a := Query{terms: permutedTerms(test.a, src)} b := Query{terms: permutedTerms(test.b, src)} got := a.Not(b).Result() sortByID(got) sortByID(test.want) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) } } } } func TestQueryRepeat(t *testing.T) { const filterTestGraph = ` . . . . . . . . . . ` want := []string{"", "", "", "", "", ""} g, err := graphFromStatements(filterTestGraph) if err != nil { t.Fatalf("unexpected error constructing graph: %v", err) } start, ok := g.TermFor("") if !ok { t.Fatal("could not get start term") } for _, limit := range []int{0, 1, 2, 5, 100} { got := []string{} var i int result := g.Query(start).Repeat(func(q Query) (Query, bool) { if i >= limit { return q, false } i++ q = q.Out(func(s *Statement) bool { ok := s.Predicate.Value == "" if ok { got = append(got, s.Object.Value) } return ok }) return q, true }).Unique().Result() n := limit if n >= len(want) { n = len(want) - 1 } if !reflect.DeepEqual(got, want[1:n+1]) { t.Errorf("unexpected capture for limit=%d: got:%v want:%v", limit, got, want[:n]) } switch { case limit < len(want): if len(result) == 0 || result[0].Value != want[i] { t.Errorf("unexpected result for limit=%d: got:%v want:%v", limit, result[0], want[i]) } default: if len(result) != 0 { t.Errorf("unexpected result for limit=%d: got: %v want:none", limit, result[0]) } } } } var uniqueTests = []struct { name string in []Term want []Term }{ { name: "excess a", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "excess b", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 2}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, { name: "excess c", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}, {Value: "", UID: 3}}, want: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, }, } func TestQueryUnique(t *testing.T) { src := rand.NewSource(1) for _, test := range uniqueTests { for i := 0; i < 10; i++ { a := Query{terms: permutedTerms(test.in, src)} got := a.Unique().Result() sortByID(got) sortByID(test.want) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) } } } } // filterTestGraph is used to test Has*Out and Has*In. It has a symmetry // that means that the in an out tests have the same form, just with opposite // directions. const filterTestGraph = ` . . . . . # symmetry line. . . . . . ` var hasOutTests = []struct { name string in []Term fn func(*Statement) bool cons func(q Query) Query wantAll []Term wantAny []Term }{ { name: "all", in: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, fn: func(s *Statement) bool { return true }, cons: func(q Query) Query { cond := func(s *Statement) bool { return true } return q.Out(cond).In(cond).Unique() }, wantAll: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, wantAny: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, }, { name: "none", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return false }, cons: func(q Query) Query { cond := func(s *Statement) bool { return false } return q.Out(cond).In(cond).Unique() }, wantAll: nil, wantAny: nil, }, { name: ". .", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value == "" }, cons: func(q Query) Query { cond1 := func(s *Statement) bool { return s.Predicate.Value == "" } cond2 := func(s *Statement) bool { return s.Predicate.Value != "" } return q.Out(cond1).In(cond1).Not(q.Out(cond2).In(cond2)).Unique() }, wantAll: nil, wantAny: []Term{{Value: ""}}, }, { name: "!(. .)", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" }, cons: func(q Query) Query { cond1 := func(s *Statement) bool { return s.Predicate.Value != "" } cond2 := func(s *Statement) bool { return s.Predicate.Value == "" } return q.Out(cond1).In(cond1).Not(q.Out(cond2).In(cond2)).Unique() }, wantAll: []Term{{Value: ""}, {Value: ""}}, wantAny: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, }, { name: "!(. .)", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" }, cons: func(q Query) Query { cond1 := func(s *Statement) bool { return s.Predicate.Value != "" } cond2 := func(s *Statement) bool { return s.Predicate.Value == "" } return q.Out(cond1).In(cond1).Not(q.Out(cond2).In(cond2)).Unique() }, wantAll: nil, wantAny: []Term{{Value: ""}}, }, { name: "!(. )", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" || (s.Predicate.Value == "" && s.Object.Value != "") }, cons: func(q Query) Query { cond := func(s *Statement) bool { return s.Predicate.Value == "" && s.Object.Value != "" } return q.Out(cond).In(cond).Unique() }, wantAll: []Term{{Value: ""}, {Value: ""}}, wantAny: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, }, { name: "!(. !)", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" || (s.Predicate.Value == "" && s.Object.Value == "") }, cons: func(q Query) Query { cond := func(s *Statement) bool { return s.Predicate.Value == "" && s.Object.Value == "" } return q.Out(cond).In(cond).Unique() }, wantAll: []Term{{Value: ""}}, wantAny: []Term{{Value: ""}}, }, } func TestQueryHasAllOut(t *testing.T) { g, err := graphFromStatements(filterTestGraph) if err != nil { t.Fatalf("unexpected error constructing graph: %v", err) } for _, test := range hasOutTests { ids := make(map[string]int64) for i, v := range test.in { term, ok := g.TermFor(v.Value) if !ok { t.Fatalf("unexpected error constructing graph: could not get UID for term: %v", v.Value) } test.in[i].UID = term.UID ids[term.Value] = term.UID } for i, v := range test.wantAll { test.wantAll[i].UID = ids[v.Value] } a := Query{g: g, terms: test.in} got := a.HasAllOut(test.fn).Result() sortByID(got) sortByID(test.wantAll) if !reflect.DeepEqual(got, test.wantAll) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.wantAll) } cons := test.cons(a).Result() sortByID(cons) if !reflect.DeepEqual(got, cons) { t.Errorf("unexpected construction result for test %q:\ngot: %v\nwant:%v", test.name, got, cons) } } } func TestQueryHasAnyOut(t *testing.T) { g, err := graphFromStatements(filterTestGraph) if err != nil { t.Fatalf("unexpected error constructing graph: %v", err) } for _, test := range hasOutTests { ids := make(map[string]int64) for i, v := range test.in { term, ok := g.TermFor(v.Value) if !ok { t.Fatalf("unexpected error constructing graph: could not get UID for term: %v", v.Value) } test.in[i].UID = term.UID ids[term.Value] = term.UID } for i, v := range test.wantAny { test.wantAny[i].UID = ids[v.Value] } a := Query{g: g, terms: test.in} got := a.HasAnyOut(test.fn).Result() sortByID(got) sortByID(test.wantAny) if !reflect.DeepEqual(got, test.wantAny) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.wantAny) } } } var hasInTests = []struct { name string in []Term fn func(*Statement) bool cons func(q Query) Query wantAll []Term wantAny []Term }{ { name: "all", in: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, fn: func(s *Statement) bool { return true }, cons: func(q Query) Query { cond := func(s *Statement) bool { return true } return q.In(cond).Out(cond).Unique() }, wantAll: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, wantAny: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, }, { name: "none", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return false }, cons: func(q Query) Query { cond := func(s *Statement) bool { return false } return q.In(cond).Out(cond).Unique() }, wantAll: nil, wantAny: nil, }, { name: ". .", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value == "" }, cons: func(q Query) Query { cond1 := func(s *Statement) bool { return s.Predicate.Value == "" } cond2 := func(s *Statement) bool { return s.Predicate.Value != "" } return q.In(cond1).Out(cond1).Not(q.In(cond2).Out(cond2)).Unique() }, wantAll: nil, wantAny: []Term{{Value: ""}}, }, { name: "!(. .)", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" }, cons: func(q Query) Query { cond1 := func(s *Statement) bool { return s.Predicate.Value != "" } cond2 := func(s *Statement) bool { return s.Predicate.Value == "" } return q.In(cond1).Out(cond1).Not(q.In(cond2).Out(cond2)).Unique() }, wantAll: []Term{{Value: ""}, {Value: ""}}, wantAny: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, }, { name: "!(. .)", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" }, cons: func(q Query) Query { cond1 := func(s *Statement) bool { return s.Predicate.Value != "" } cond2 := func(s *Statement) bool { return s.Predicate.Value == "" } return q.In(cond1).Out(cond1).Not(q.In(cond2).Out(cond2)).Unique() }, wantAll: nil, wantAny: []Term{{Value: ""}}, }, { name: "!( .)", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" || (s.Predicate.Value == "" && s.Subject.Value != "") }, cons: func(q Query) Query { cond := func(s *Statement) bool { return s.Predicate.Value == "" && s.Subject.Value != "" } return q.In(cond).Out(cond).Unique() }, wantAll: []Term{{Value: ""}, {Value: ""}}, wantAny: []Term{{Value: ""}, {Value: ""}, {Value: ""}}, }, { name: "!(! .)", in: []Term{{Value: "", UID: 1}, {Value: "", UID: 2}, {Value: "", UID: 3}}, fn: func(s *Statement) bool { return s.Predicate.Value != "" || (s.Predicate.Value == "" && s.Subject.Value == "") }, cons: func(q Query) Query { cond := func(s *Statement) bool { return s.Predicate.Value == "" && s.Subject.Value == "" } return q.In(cond).Out(cond).Unique() }, wantAll: []Term{{Value: ""}}, wantAny: []Term{{Value: ""}}, }, } func TestQueryHasAllIn(t *testing.T) { g, err := graphFromStatements(filterTestGraph) if err != nil { t.Fatalf("unexpected error constructing graph: %v", err) } for _, test := range hasInTests { ids := make(map[string]int64) for i, v := range test.in { term, ok := g.TermFor(v.Value) if !ok { t.Fatalf("unexpected error constructing graph: could not get UID for term: %v", v.Value) } test.in[i].UID = term.UID ids[term.Value] = term.UID } for i, v := range test.wantAll { test.wantAll[i].UID = ids[v.Value] } a := Query{g: g, terms: test.in} got := a.HasAllIn(test.fn).Result() sortByID(got) sortByID(test.wantAll) if !reflect.DeepEqual(got, test.wantAll) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.wantAll) } cons := test.cons(a).Result() sortByID(cons) if !reflect.DeepEqual(got, cons) { t.Errorf("unexpected construction result for test %q:\ngot: %v\nwant:%v", test.name, got, cons) } } } func TestQueryHasAnyIn(t *testing.T) { g, err := graphFromStatements(filterTestGraph) if err != nil { t.Fatalf("unexpected error constructing graph: %v", err) } for _, test := range hasInTests { ids := make(map[string]int64) for i, v := range test.in { term, ok := g.TermFor(v.Value) if !ok { t.Fatalf("unexpected error constructing graph: could not get UID for term: %v", v.Value) } test.in[i].UID = term.UID ids[term.Value] = term.UID } for i, v := range test.wantAny { test.wantAny[i].UID = ids[v.Value] } a := Query{g: g, terms: test.in} got := a.HasAnyIn(test.fn).Result() sortByID(got) sortByID(test.wantAny) if !reflect.DeepEqual(got, test.wantAny) { t.Errorf("unexpected result for test %q:\ngot: %v\nwant:%v", test.name, got, test.wantAny) } } } func graphFromStatements(s string) (*Graph, error) { g := NewGraph() dec := NewDecoder(strings.NewReader(s)) for { s, err := dec.Unmarshal() if err != nil { if err != io.EOF { return nil, err } break } g.AddStatement(s) } return g, nil } func permutedTerms(t []Term, src rand.Source) []Term { rnd := rand.New(src) p := make([]Term, len(t)) for i, j := range rnd.Perm(len(t)) { p[i] = t[j] } return p } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/rdf.go000066400000000000000000000234531450372207100222760ustar00rootroot00000000000000// Copyright ©2020 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 ragel -Z -G2 parse.rl //go:generate ragel -Z -G2 extract.rl //go:generate ragel -Z -G2 check.rl //go:generate stringer -type=Kind package rdf import ( "bufio" "bytes" "errors" "fmt" "io" "net/url" "strconv" "strings" "unicode" "unicode/utf8" "gonum.org/v1/gonum/graph" ) var ( _ graph.Node = Term{} _ graph.Edge = (*Statement)(nil) _ graph.Line = (*Statement)(nil) ) var ( ErrInvalid = errors.New("invalid N-Quad") ErrIncomplete = errors.New("incomplete N-Quad") ErrInvalidTerm = errors.New("invalid term") ErrIncompleteTerm = errors.New("incomplete term") ) // Kind represents the kind of an RDF term. type Kind int const ( // Invalid is an invalid RDF term. Invalid Kind = iota // IRI is the kind of an IRI term. // https://www.w3.org/TR/n-quads/#sec-iri IRI // Literal is the kind of an RDF literal. // https://www.w3.org/TR/n-quads/#sec-literals Literal // Blank is the kind of an RDF blank node term. // https://www.w3.org/TR/n-quads/#BNodes Blank ) // Term is an RDF term. It implements the graph.Node interface. type Term struct { // Value is the text value of term. Value string // UID is the unique ID for the term // in a collection of RDF terms. UID int64 } // NewBlankTerm returns a Term based on the provided RDF blank node // label. The label should not include the "_:" prefix. The returned // Term will not have the UID set. func NewBlankTerm(label string) (Term, error) { err := checkLabelText([]rune(label)) if err != nil { return Term{}, err } return Term{Value: blankPrefix + label}, nil } const blankPrefix = "_:" func isBlank(s string) bool { return strings.HasPrefix(s, blankPrefix) } // NewIRITerm returns a Term based on the provided IRI which must // be valid and include a scheme. The returned Term will not have // the UID set. func NewIRITerm(iri string) (Term, error) { err := checkIRIText(iri) if err != nil { return Term{}, err } return Term{Value: escape("<", iri, ">")}, nil } func isIRI(s string) bool { return strings.HasPrefix(s, "<") && strings.HasSuffix(s, ">") } // NewLiteralTerm returns a Term based on the literal text and an // optional qualifier which may either be a "@"-prefixed language // tag or a valid IRI. The text will be escaped if necessary and quoted, // and if an IRI is given it will be escaped if necessary. The returned // Term will not have the UID set. func NewLiteralTerm(text, qual string) (Term, error) { text = escape(`"`, text, `"`) if qual == "" { return Term{Value: text}, nil } if strings.HasPrefix(qual, "@") { err := checkLangText([]byte(qual)) if err != nil { return Term{}, err } return Term{Value: text + qual}, nil } err := checkIRIText(qual) if err != nil { return Term{}, err } return Term{Value: text + escape("^^<", qual, ">")}, nil } func checkIRIText(iri string) error { switch u, err := url.Parse(iri); { case err != nil: return err case u.Scheme == "": return fmt.Errorf("rdf: %w: relative IRI ref %q", ErrInvalidTerm, iri) default: return nil } } func isLiteral(s string) bool { return strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) } // Parts returns the parts of the term and the kind of the term. // IRI node text is returned as a valid IRI with the quoting angle // brackets removed and escape sequences interpreted, and blank // nodes are stripped of the "_:" prefix. // When the term is a literal, qual will either be empty, an unescaped // IRI, or an RDF language tag prefixed with an @ symbol. The literal // text is returned unquoted and unescaped. func (t Term) Parts() (text, qual string, kind Kind, err error) { return extract([]rune(t.Value)) } // ID returns the value of the Term's UID field. func (t Term) ID() int64 { return t.UID } // Statement is an RDF statement. It implements the graph.Edge and graph.Line // interfaces. type Statement struct { Subject Term Predicate Term Object Term Label Term } // String returns the RDF 1.1 N-Quad formatted statement. func (s *Statement) String() string { if s.Label.Value == "" { return fmt.Sprintf("%s %s %s .", s.Subject.Value, s.Predicate.Value, s.Object.Value) } return fmt.Sprintf("%s %s %s %s .", s.Subject.Value, s.Predicate.Value, s.Object.Value, s.Label.Value) } // From returns the subject of the statement. func (s *Statement) From() graph.Node { return s.Subject } // To returns the object of the statement. func (s *Statement) To() graph.Node { return s.Object } // ID returns the UID of the Predicate field. func (s *Statement) ID() int64 { return s.Predicate.UID } // ReversedEdge returns the receiver unaltered. If there is a semantically // valid edge reversal operation for the data, the user should implement // this by wrapping Statement in a type performing that operation. // See the ReversedLine example for details. func (s *Statement) ReversedEdge() graph.Edge { return s } // ReversedLine returns the receiver unaltered. If there is a semantically // valid line reversal operation for the data, the user should implement // this by wrapping Statement in a type performing that operation. func (s *Statement) ReversedLine() graph.Line { return s } // ParseNQuad parses the statement and returns the corresponding Statement. // All Term UID fields are zero on return. func ParseNQuad(statement string) (*Statement, error) { s, err := parse([]rune(statement)) if err != nil { return nil, err } return &s, err } // Decoder is an RDF stream decoder. Statements returned by calls to the // Unmarshal method have their Terms' UID fields set so that unique terms // will have unique IDs and so can be used directly in a graph.Multi, or // in a graph.Graph if all predicate terms are identical. IDs created by // the decoder all exist within a single namespace and so Terms can be // uniquely identified by their UID. Term UIDs are based from 1 to allow // RDF-aware client graphs to assign ID if no ID has been assigned. type Decoder struct { scanner *bufio.Scanner strings store ids map[string]int64 } // NewDecoder returns a new Decoder that takes input from r. func NewDecoder(r io.Reader) *Decoder { return &Decoder{ scanner: bufio.NewScanner(r), strings: make(store), ids: make(map[string]int64), } } // Reset resets the decoder to use the provided io.Reader, retaining // the existing Term ID mapping. func (dec *Decoder) Reset(r io.Reader) { dec.scanner = bufio.NewScanner(r) dec.strings = make(store) if dec.ids == nil { dec.ids = make(map[string]int64) } } // Unmarshal returns the next statement from the input stream. func (dec *Decoder) Unmarshal() (*Statement, error) { for dec.scanner.Scan() { data := bytes.TrimSpace(dec.scanner.Bytes()) if len(data) == 0 || data[0] == '#' { continue } s, err := ParseNQuad(string(data)) if err != nil { return nil, fmt.Errorf("rdf: failed to parse %q: %w", data, err) } if s == nil { continue } s.Subject.Value = dec.strings.intern(s.Subject.Value) s.Predicate.Value = dec.strings.intern(s.Predicate.Value) s.Object.Value = dec.strings.intern(s.Object.Value) s.Subject.UID = dec.idFor(s.Subject.Value) s.Object.UID = dec.idFor(s.Object.Value) s.Predicate.UID = dec.idFor(s.Predicate.Value) if s.Label.Value != "" { s.Label.Value = dec.strings.intern(s.Label.Value) s.Label.UID = dec.idFor(s.Label.Value) } return s, nil } dec.strings = nil err := dec.scanner.Err() if err != nil { return nil, err } return nil, io.EOF } func (dec *Decoder) idFor(s string) int64 { id, ok := dec.ids[s] if ok { return id } id = int64(len(dec.ids)) + 1 dec.ids[s] = id return id } // Terms returns the mapping between terms and graph node IDs constructed // during decoding the RDF statement stream. func (dec *Decoder) Terms() map[string]int64 { return dec.ids } // store is a string internment implementation. type store map[string]string // intern returns an interned version of the parameter. func (is store) intern(s string) string { if s == "" { return "" } if len(s) < 2 || len(s) > 512 { // Not enough benefit on average with real data. return s } t, ok := is[s] if ok { return t } is[s] = s return s } func escape(lq, s, rq string) string { var buf strings.Builder if lq != "" { buf.WriteString(lq) } for _, r := range s { var c byte switch r { case '\n': c = 'n' case '\r': c = 'r' case '"', '\\': c = byte(r) default: const hex = "0123456789abcdef" switch { case r <= unicode.MaxASCII || strconv.IsPrint(r): buf.WriteRune(r) case r > utf8.MaxRune: r = 0xFFFD fallthrough case r < 0x10000: buf.WriteString("\\u") for s := 12; s >= 0; s -= 4 { buf.WriteByte(hex[r>>uint(s)&0xf]) } default: buf.WriteString("\\U") for s := 28; s >= 0; s -= 4 { buf.WriteByte(hex[r>>uint(s)&0xf]) } } continue } buf.Write([]byte{'\\', c}) } if rq != "" { buf.WriteString(rq) } return buf.String() } func unEscape(r []rune) string { var buf strings.Builder for i := 0; i < len(r); { switch r[i] { case '\\': i++ var c byte switch r[i] { case 't': c = '\t' case 'b': c = '\b' case 'n': c = '\n' case 'r': c = '\r' case 'f': c = '\f' case '"': c = '"' case '\\': c = '\\' case '\'': c = '\'' case 'u': rc, err := strconv.ParseInt(string(r[i+1:i+5]), 16, 32) if err != nil { panic(fmt.Errorf("internal parser error: %w", err)) } buf.WriteRune(rune(rc)) i += 5 continue case 'U': rc, err := strconv.ParseInt(string(r[i+1:i+9]), 16, 32) if err != nil { panic(fmt.Errorf("internal parser error: %w", err)) } buf.WriteRune(rune(rc)) i += 9 continue } buf.WriteByte(c) default: buf.WriteRune(r[i]) } i++ } return buf.String() } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/rdf_example_test.go000066400000000000000000000064651450372207100250540ustar00rootroot00000000000000// Copyright ©2020 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 rdf_test import ( "fmt" "log" "os" "strings" "text/tabwriter" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/formats/rdf" "gonum.org/v1/gonum/graph/multi" ) // dotNode implements graph.Node and dot.Node to allow the // RDF term value to be given to the DOT encoder. type dotNode struct { rdf.Term } func (n dotNode) DOTID() string { return n.Term.Value } // dotLine implements graph.Line and encoding.Attributer to // allow the line's RDF term value to be given to the DOT // encoder and for the nodes to be shimmed to the dotNode // type. // // Because the graph here is directed and we are not performing // any line reversals, it is safe not to implement the // ReversedLine method on dotLine; it will never be called. type dotLine struct { *rdf.Statement } func (l dotLine) From() graph.Node { return dotNode{l.Subject} } func (l dotLine) To() graph.Node { return dotNode{l.Object} } func (l dotLine) Attributes() []encoding.Attribute { return []encoding.Attribute{{Key: "label", Value: l.Predicate.Value}} } func Example_graph() { const statements = ` _:alice _:bob . _:alice "Alice" . _:alice "Smith" . _:bob _:alice . _:bob "Bob" . _:bob "Smith" . ` // Decode the statement stream and insert the lines into a multigraph. g := multi.NewDirectedGraph() dec := rdf.NewDecoder(strings.NewReader(statements)) for { l, err := dec.Unmarshal() if err != nil { break } // Wrap the line with a shim type to allow the RDF values // to be passed to the DOT marshaling routine. g.SetLine(dotLine{l}) } // Marshal the graph into DOT. b, err := dot.MarshalMulti(g, "smiths", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n\n", b) // Get the ID look-up table. w := tabwriter.NewWriter(os.Stdout, 0, 4, 1, ' ', 0) fmt.Fprintln(w, "Term\tID") for t, id := range dec.Terms() { fmt.Fprintf(w, "%s\t%d\n", t, id) } w.Flush() // Unordered output: // // digraph smiths { // // Node definitions. // "_:alice"; // "_:bob"; // "Alice"; // "Smith"; // "Bob"; // // // Edge definitions. // "_:alice" -> "_:bob" [label=]; // "_:alice" -> "Alice" [label=]; // "_:alice" -> "Smith" [label=]; // "_:bob" -> "_:alice" [label=]; // "_:bob" -> "Smith" [label=]; // "_:bob" -> "Bob" [label=]; // } // // Term ID // _:alice 1 // _:bob 2 // 3 // "Alice" 4 // 5 // "Smith" 6 // 7 // "Bob" 8 } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/rdf_line_example_test.go000066400000000000000000000124211450372207100260500ustar00rootroot00000000000000// Copyright ©2020 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 rdf_test import ( "fmt" "log" "strings" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/formats/rdf" "gonum.org/v1/gonum/graph/multi" ) // foodNode implements graph.Node, dot.Node and encoding.Attributer // to allow the RDF term value to be given to the DOT encoder. type foodNode struct { rdf.Term } func (n foodNode) DOTID() string { text, _, kind, err := n.Term.Parts() if err != nil { return fmt.Sprintf("error:%s", n.Term.Value) } switch kind { case rdf.Blank: return n.Term.Value case rdf.IRI: return text case rdf.Literal: return fmt.Sprintf("%q", text) default: return fmt.Sprintf("invalid:%s", n.Term.Value) } } func (n foodNode) Attributes() []encoding.Attribute { _, qual, _, err := n.Term.Parts() if err != nil { return []encoding.Attribute{{Key: "error", Value: err.Error()}} } if qual == "" { return nil } parts := strings.Split(qual, ":") return []encoding.Attribute{{Key: parts[0], Value: parts[1]}} } // foodLine implements graph.Line and encoding.Attributer to // allow the line's RDF term value to be given to the DOT // encoder and for the nodes to be shimmed to the foodNode // type. // // It also implements line reversal for the semantics of // a food web with some taxonomic information. type foodLine struct { *rdf.Statement } func (l foodLine) From() graph.Node { return foodNode{l.Subject} } func (l foodLine) To() graph.Node { return foodNode{l.Object} } func (l foodLine) ReversedLine() graph.Line { if l.Predicate.Value == "" { // This should remain unreversed, so return as is. return l } s := *l.Statement // Reverse the line end points. s.Subject, s.Object = s.Object, s.Subject // Invert the semantics of the predicate. switch s.Predicate.Value { case "": s.Predicate.Value = "" case "": s.Predicate.Value = "" case "": s.Predicate.Value = "" case "": s.Predicate.Value = "" default: panic("invalid predicate") } // All IDs returned by the RDF parser are positive, so // sign reverse the edge ID to avoid any collisions. s.Predicate.UID *= -1 return foodLine{&s} } func (l foodLine) Attributes() []encoding.Attribute { text, _, _, err := l.Predicate.Parts() if err != nil { return []encoding.Attribute{{Key: "error", Value: err.Error()}} } parts := strings.Split(text, ":") return []encoding.Attribute{{Key: parts[0], Value: parts[1]}} } // expand copies src into dst, adding the reversal of each line if it is // distinct. func expand(dst, src *multi.DirectedGraph) { it := src.Edges() for it.Next() { lit := it.Edge().(multi.Edge) for lit.Next() { l := lit.Line() r := l.ReversedLine() dst.SetLine(l) if l == r { continue } dst.SetLine(r) } } } func ExampleStatement_ReversedLine() { const statements = ` _:wolf _:animal . _:wolf "Wolf"^^ . _:wolf "Canis lupus"^^ . _:wolf _:sheep . _:sheep _:animal . _:sheep "Sheep"^^ . _:sheep "Ovis aries"^^ . _:sheep _:grass . _:grass _:plant . _:grass "Grass"^^ . _:grass "Lolium perenne"^^ . _:grass "Festuca rubra"^^ . _:grass "Poa pratensis"^^ . ` // Decode the statement stream and insert the lines into a multigraph. g := multi.NewDirectedGraph() dec := rdf.NewDecoder(strings.NewReader(statements)) for { l, err := dec.Unmarshal() if err != nil { break } // Wrap the line with a shim type to allow the RDF values // to be passed to the DOT marshaling routine. g.SetLine(foodLine{l}) } h := multi.NewDirectedGraph() expand(h, g) // Marshal the graph into DOT. b, err := dot.MarshalMulti(h, "food web", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n\n", b) // Output: // // digraph "food web" { // // Node definitions. // "_:wolf"; // "_:animal"; // "Wolf" [tax=common]; // "Canis lupus" [tax=binomial]; // "_:sheep"; // "Sheep" [tax=common]; // "Ovis aries" [tax=binomial]; // "_:grass"; // "_:plant"; // "Grass" [tax=common]; // "Lolium perenne" [tax=binomial]; // "Festuca rubra" [tax=binomial]; // "Poa pratensis" [tax=binomial]; // // // Edge definitions. // "_:wolf" -> "_:animal" [tax="is-a"]; // "_:wolf" -> "Wolf" [tax=is]; // "_:wolf" -> "Canis lupus" [tax=is]; // "_:wolf" -> "_:sheep" [eco=eats]; // "_:animal" -> "_:wolf" [tax=includes]; // "_:animal" -> "_:sheep" [tax=includes]; // "_:sheep" -> "_:wolf" [eco="eaten-by"]; // "_:sheep" -> "_:animal" [tax="is-a"]; // "_:sheep" -> "Sheep" [tax=is]; // "_:sheep" -> "Ovis aries" [tax=is]; // "_:sheep" -> "_:grass" [eco=eats]; // "_:grass" -> "_:sheep" [eco="eaten-by"]; // "_:grass" -> "_:plant" [tax="is-a"]; // "_:grass" -> "Grass" [tax=is]; // "_:grass" -> "Lolium perenne" [tax=is]; // "_:grass" -> "Festuca rubra" [tax=is]; // "_:grass" -> "Poa pratensis" [tax=is]; // "_:plant" -> "_:grass" [tax=includes]; // } } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/rdf_test.go000066400000000000000000000133771450372207100233410ustar00rootroot00000000000000// Copyright ©2020 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 rdf import ( "archive/tar" "compress/gzip" "fmt" "io" "os" "path/filepath" "reflect" "strings" "testing" ) func TestRDFWorkingGroupSuite(t *testing.T) { for _, file := range []string{ "ntriple_tests.tar.gz", "nquad_tests.tar.gz", } { suite, err := os.Open(filepath.Join("testdata", file)) if err != nil { t.Fatalf("Failed to open test suite in %q: %v", file, err) } defer suite.Close() r, err := gzip.NewReader(suite) if err != nil { t.Fatalf("Failed to uncompress test suite in %q: %v", file, err) } tr := tar.NewReader(r) for { h, err := tr.Next() if err != nil { if err == io.EOF { break } t.Fatalf("Unexpected error while reading suite archive: %v", err) } h.Name = filepath.Base(h.Name) if filepath.Ext(h.Name) != ".nt" && filepath.Ext(h.Name) != ".nq" { continue } if _, ok := testSuite[h.Name]; !ok { t.Errorf("Missing test suite item %q", h.Name) continue } isBad := strings.Contains(h.Name, "bad") var got []statement dec := NewDecoder(tr) for i := 0; ; i++ { s, err := dec.Unmarshal() if err == io.EOF { break } gotBad := err != nil if gotBad != isBad { t.Errorf("Unexpected error return for test suite item %q, got: %v", h.Name, err) } var subj, pred, obj, lab term if s != nil { subj.text, subj.qual, subj.kind, _ = s.Subject.Parts() pred.text, pred.qual, pred.kind, _ = s.Predicate.Parts() obj.text, obj.qual, obj.kind, _ = s.Object.Parts() lab.text, lab.qual, lab.kind, _ = s.Label.Parts() if lab.text == "" { lab = term{} } got = append(got, statement{testSuite[h.Name][i].input, subj, pred, obj, lab}) } if !gotBad { _, err = ParseNQuad(s.String()) if err != nil { t.Errorf("Unexpected error return for valid statement in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) } st, err := termFor(subj.text, subj.qual, subj.kind) if err != nil { t.Errorf("Unexpected error return for valid subject in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) } pt, err := termFor(pred.text, pred.qual, pred.kind) if err != nil { t.Errorf("Unexpected error return for valid predicate in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) } ot, err := termFor(obj.text, obj.qual, obj.kind) if err != nil { t.Errorf("Unexpected error return for valid object in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) } lt, err := termFor(lab.text, lab.qual, lab.kind) if err != nil { t.Errorf("Unexpected error return for valid label in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) } // We can't check that we recreate the original from the test suite // due to escaping, but we can check for a second pass through the // round-trip. c := &Statement{Subject: st, Predicate: pt, Object: ot, Label: lt} pc, err := ParseNQuad(c.String()) if err != nil { t.Errorf("Unexpected error return for reconstructed statement in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) } if !reflect.DeepEqual(c, pc) { t.Errorf("Unexpected reconstruction:\norig: %#v\ncons: %#v\nparsed:%#v", s, c, pc) } } } if !reflect.DeepEqual(testSuite[h.Name], got) { t.Errorf("Unexpected result for test suite item %q", h.Name) } } } } func termFor(text, qual string, kind Kind) (Term, error) { switch kind { case Invalid: return Term{}, nil case Blank: return NewBlankTerm(text) case IRI: return NewIRITerm(text) case Literal: return NewLiteralTerm(text, qual) default: panic(fmt.Sprintf("bad test kind=%d", kind)) } } var escapeSequenceTests = []struct { escaped string unEscaped string canRoundTrip bool }{ {escaped: `plain text!`, unEscaped: "plain text!", canRoundTrip: true}, {escaped: `\t`, unEscaped: "\t", canRoundTrip: false}, {escaped: `\b`, unEscaped: "\b", canRoundTrip: false}, {escaped: `\n`, unEscaped: "\n", canRoundTrip: true}, {escaped: `\r`, unEscaped: "\r", canRoundTrip: true}, {escaped: `\f`, unEscaped: "\f", canRoundTrip: false}, {escaped: `\\`, unEscaped: "\\", canRoundTrip: true}, {escaped: `\u0080`, unEscaped: "\u0080", canRoundTrip: true}, {escaped: `\U00000080`, unEscaped: "\u0080", canRoundTrip: false}, {escaped: `\t\b\n\r\f\"'\\`, unEscaped: "\t\b\n\r\f\"'\\", canRoundTrip: false}, {escaped: `\t\u0080`, unEscaped: "\t\u0080", canRoundTrip: false}, {escaped: `\b\U00000080`, unEscaped: "\b\u0080", canRoundTrip: false}, {escaped: `\u0080\n`, unEscaped: "\u0080\n", canRoundTrip: true}, {escaped: `\U00000080\r`, unEscaped: "\u0080\r", canRoundTrip: false}, {escaped: `\u00b7\f\U000000b7`, unEscaped: "·\f·", canRoundTrip: false}, {escaped: `\U000000b7\\\u00b7`, unEscaped: "·\\·", canRoundTrip: false}, {escaped: `\U00010105\\\U00010106`, unEscaped: "\U00010105\\\U00010106", canRoundTrip: true}, } func TestUnescape(t *testing.T) { for _, test := range escapeSequenceTests { got := unEscape([]rune(test.escaped)) if got != test.unEscaped { t.Errorf("Failed to properly unescape %q, got:%q want:%q", test.escaped, got, test.unEscaped) } if test.canRoundTrip { got = escape("", test.unEscaped, "") if got != test.escaped { t.Errorf("Failed to properly escape %q, got:%q want:%q", test.unEscaped, got, test.escaped) } got = escape(`"`, test.unEscaped, `"`) if got != `"`+test.escaped+`"` { t.Errorf("Failed to properly escape %q quoted, got:%q want:%q", test.unEscaped, got, `"`+test.escaped+`"`) } } } } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/test_suite_test.go000066400000000000000000001570531450372207100247560ustar00rootroot00000000000000// Copyright ©2020 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 © 2008 World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang) // and others. All Rights Reserved. // http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html // Used under https://www.w3.org/Consortium/Legal/2008/03-bsd-license. package rdf type statement struct { input string subject, predicate, object, label term } type term struct { text string qual string kind Kind } // Test suite values were extracted from the test case archives in this directory. // The archives were obtained from https://w3c.github.io/rdf-tests/ntriples/ and // https://w3c.github.io/rdf-tests/nquads/. var testSuite = map[string][]statement{ "comment_following_triple.nq": { { input: " . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, { input: " _:o . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Blank}, }, { input: " \"o\" . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Literal}, }, { input: " \"o\"^^ . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "http://example/dt", kind: Literal}, }, { input: " \"o\"@en . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "@en", kind: Literal}, }, }, "comment_following_triple.nt": { { input: " . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, { input: " _:o . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Blank}, }, { input: " \"o\" . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Literal}, }, { input: " \"o\"^^ . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "http://example/dt", kind: Literal}, }, { input: " \"o\"@en . # comment", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "@en", kind: Literal}, }, }, "langtagged_string.nq": { { input: " \"chat\"@en .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "chat", qual: "@en", kind: Literal}, }, }, "langtagged_string.nt": { { input: " \"chat\"@en .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "chat", qual: "@en", kind: Literal}, }, }, "lantag_with_subtag.nq": { { input: " \"Cheers\"@en-UK .", subject: term{text: "http://example.org/ex#a", kind: IRI}, predicate: term{text: "http://example.org/ex#b", kind: IRI}, object: term{text: "Cheers", qual: "@en-UK", kind: Literal}, }, }, "lantag_with_subtag.nt": { { input: " \"Cheers\"@en-UK .", subject: term{text: "http://example.org/ex#a", kind: IRI}, predicate: term{text: "http://example.org/ex#b", kind: IRI}, object: term{text: "Cheers", qual: "@en-UK", kind: Literal}, }, }, "literal.nq": { { input: " \"x\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x", kind: Literal}, }, }, "literal.nt": { { input: " \"x\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x", kind: Literal}, }, }, "literal_all_controls.nq": { { input: " \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\t\\u000B\\u000C\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\v\f\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", kind: Literal}, }, }, "literal_all_controls.nt": { { input: " \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\t\\u000B\\u000C\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\v\f\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", kind: Literal}, }, }, "literal_all_punctuation.nq": { { input: " \" !\\\"#$%&():;<=>?@[]^_`{|}~\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: " !\"#$%&():;<=>?@[]^_`{|}~", kind: Literal}, }, }, "literal_all_punctuation.nt": { { input: " \" !\\\"#$%&():;<=>?@[]^_`{|}~\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: " !\"#$%&():;<=>?@[]^_`{|}~", kind: Literal}, }, }, "literal_ascii_boundaries.nq": { { input: " \"\x00\t\v\f\x0e&([]\u007f\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\x00\t\v\f\x0e&([]\u007f", kind: Literal}, }, }, "literal_ascii_boundaries.nt": { { input: " \"\x00\t\v\f\x0e&([]\u007f\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\x00\t\v\f\x0e&([]\u007f", kind: Literal}, }, }, "literal_false.nq": { { input: " \"false\"^^ .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "false", qual: "http://www.w3.org/2001/XMLSchema#boolean", kind: Literal}, }, }, "literal_false.nt": { { input: " \"false\"^^ .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "false", qual: "http://www.w3.org/2001/XMLSchema#boolean", kind: Literal}, }, }, "literal_true.nq": { { input: " \"true\"^^ .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "true", qual: "http://www.w3.org/2001/XMLSchema#boolean", kind: Literal}, }, }, "literal_true.nt": { { input: " \"true\"^^ .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "true", qual: "http://www.w3.org/2001/XMLSchema#boolean", kind: Literal}, }, }, "literal_with_2_dquotes.nq": { { input: " \"x\\\"\\\"y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x\"\"y", kind: Literal}, }, }, "literal_with_2_dquotes.nt": { { input: " \"x\\\"\\\"y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x\"\"y", kind: Literal}, }, }, "literal_with_2_squotes.nt": { { input: " \"x''y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x''y", kind: Literal}, }, }, "literal_with_2_squotes.nq": { { input: " \"x''y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x''y", kind: Literal}, }, }, "literal_with_BACKSPACE.nq": { { input: " \"\\b\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\b", kind: Literal}, }, }, "literal_with_BACKSPACE.nt": { { input: " \"\\b\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\b", kind: Literal}, }, }, "literal_with_CARRIAGE_RETURN.nq": { { input: " \"\\r\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\r", kind: Literal}, }, }, "literal_with_CARRIAGE_RETURN.nt": { { input: " \"\\r\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\r", kind: Literal}, }, }, "literal_with_CHARACTER_TABULATION.nq": { { input: " \"\\t\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\t", kind: Literal}, }, }, "literal_with_CHARACTER_TABULATION.nt": { { input: " \"\\t\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\t", kind: Literal}, }, }, "literal_with_FORM_FEED.nq": { { input: " \"\\f\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\f", kind: Literal}, }, }, "literal_with_FORM_FEED.nt": { { input: " \"\\f\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\f", kind: Literal}, }, }, "literal_with_LINE_FEED.nq": { { input: " \"\\n\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\n", kind: Literal}, }, }, "literal_with_LINE_FEED.nt": { { input: " \"\\n\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\n", kind: Literal}, }, }, "literal_with_REVERSE_SOLIDUS.nq": { { input: " \"\\\\\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\\", kind: Literal}, }, }, "literal_with_REVERSE_SOLIDUS.nt": { { input: " \"\\\\\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\\", kind: Literal}, }, }, "literal_with_REVERSE_SOLIDUS2.nq": { { input: " \"test-\\\\\" .", subject: term{text: "http://example.org/ns#s", kind: IRI}, predicate: term{text: "http://example.org/ns#p1", kind: IRI}, object: term{text: "test-\\", kind: Literal}, }, }, "literal_with_REVERSE_SOLIDUS2.nt": { { input: " \"test-\\\\\" .", subject: term{text: "http://example.org/ns#s", kind: IRI}, predicate: term{text: "http://example.org/ns#p1", kind: IRI}, object: term{text: "test-\\", kind: Literal}, }, }, "literal_with_UTF8_boundaries.nq": { { input: " \"\u0080߿ࠀ\u0fffက쿿퀀\ud7ff\ue000�𐀀\U0003fffd\U00040000\U000ffffd\U00100000\U0010fffd\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\u0080߿ࠀ\u0fffက쿿퀀\ud7ff\ue000�𐀀\U0003fffd\U00040000\U000ffffd\U00100000\U0010fffd", kind: Literal}, }, }, "literal_with_UTF8_boundaries.nt": { { input: " \"\u0080߿ࠀ\u0fffက쿿퀀\ud7ff\ue000�𐀀\U0003fffd\U00040000\U000ffffd\U00100000\U0010fffd\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "\u0080߿ࠀ\u0fffက쿿퀀\ud7ff\ue000�𐀀\U0003fffd\U00040000\U000ffffd\U00100000\U0010fffd", kind: Literal}, }, }, "literal_with_dquote.nq": { { input: " \"x\\\"y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x\"y", kind: Literal}, }, }, "literal_with_dquote.nt": { { input: " \"x\\\"y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x\"y", kind: Literal}, }, }, "literal_with_numeric_escape4.nq": { { input: " \"\\u006F\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "o", kind: Literal}, }, }, "literal_with_numeric_escape4.nt": { { input: " \"\\u006F\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "o", kind: Literal}, }, }, "literal_with_numeric_escape8.nq": { { input: " \"\\U0000006F\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "o", kind: Literal}, }, }, "literal_with_numeric_escape8.nt": { { input: " \"\\U0000006F\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "o", kind: Literal}, }, }, "literal_with_squote.nq": { { input: " \"x'y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x'y", kind: Literal}, }, }, "literal_with_squote.nt": { { input: " \"x'y\" .", subject: term{text: "http://a.example/s", kind: IRI}, predicate: term{text: "http://a.example/p", kind: IRI}, object: term{text: "x'y", kind: Literal}, }, }, "minimal_whitespace.nq": { { input: ".", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, { input: "\"Alice\".", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "Alice", kind: Literal}, }, { input: "_:o.", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Blank}, }, { input: "_:s.", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, { input: "_:s\"Alice\".", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "Alice", kind: Literal}, }, { input: "_:s_:bnode1.", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "bnode1", kind: Blank}, }, }, "minimal_whitespace.nt": { { input: ".", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, { input: "\"Alice\".", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "Alice", kind: Literal}, }, { input: "_:o.", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Blank}, }, { input: "_:s.", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, { input: "_:s\"Alice\".", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "Alice", kind: Literal}, }, { input: "_:s_:bnode1.", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "bnode1", kind: Blank}, }, }, "nq-syntax-bnode-01.nq": { { input: " _:g .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, label: term{text: "g", kind: Blank}, }, }, "nq-syntax-bnode-02.nq": { { input: "_:s _:g .", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, label: term{text: "g", kind: Blank}, }, }, "nq-syntax-bnode-03.nq": { { input: " _:o _:g .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Blank}, label: term{text: "g", kind: Blank}, }, }, "nq-syntax-bnode-04.nq": { { input: " \"o\" _:g .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Literal}, label: term{text: "g", kind: Blank}, }, }, "nq-syntax-bnode-05.nq": { { input: " \"o\"@en _:g .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "@en", kind: Literal}, label: term{text: "g", kind: Blank}, }, }, "nq-syntax-bnode-06.nq": { { input: " \"o\"^^ _:g .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "http://www.w3.org/2001/XMLSchema#string", kind: Literal}, label: term{text: "g", kind: Blank}, }, }, "nq-syntax-uri-01.nq": { { input: " .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, label: term{text: "http://example/g", kind: IRI}, }, }, "nq-syntax-uri-02.nq": { { input: "_:s .", subject: term{text: "s", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, label: term{text: "http://example/g", kind: IRI}, }, }, "nq-syntax-uri-03.nq": { { input: " _:o .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Blank}, label: term{text: "http://example/g", kind: IRI}, }, }, "nq-syntax-uri-04.nq": { { input: " \"o\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", kind: Literal}, label: term{text: "http://example/g", kind: IRI}, }, }, "nq-syntax-uri-05.nq": { { input: " \"o\"@en .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "@en", kind: Literal}, label: term{text: "http://example/g", kind: IRI}, }, }, "nq-syntax-uri-06.nq": { { input: " \"o\"^^ .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "o", qual: "http://www.w3.org/2001/XMLSchema#string", kind: Literal}, label: term{text: "http://example/g", kind: IRI}, }, }, "nt-syntax-bnode-01.nq": { { input: "_:a .", subject: term{text: "a", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-bnode-01.nt": { { input: "_:a .", subject: term{text: "a", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-bnode-02.nq": { { input: " _:a .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a", kind: Blank}, }, { input: "_:a .", subject: term{text: "a", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-bnode-02.nt": { { input: " _:a .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a", kind: Blank}, }, { input: "_:a .", subject: term{text: "a", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-bnode-03.nq": { { input: " _:1a .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "1a", kind: Blank}, }, { input: "_:1a .", subject: term{text: "1a", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-bnode-03.nt": { { input: " _:1a .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "1a", kind: Blank}, }, { input: "_:1a .", subject: term{text: "1a", kind: Blank}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-datatypes-01.nq": { { input: " \"123\"^^ .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "123", qual: "http://www.w3.org/2001/XMLSchema#byte", kind: Literal}, }, }, "nt-syntax-datatypes-01.nt": { { input: " \"123\"^^ .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "123", qual: "http://www.w3.org/2001/XMLSchema#byte", kind: Literal}, }, }, "nt-syntax-datatypes-02.nq": { { input: " \"123\"^^ .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "123", qual: "http://www.w3.org/2001/XMLSchema#string", kind: Literal}, }, }, "nt-syntax-datatypes-02.nt": { { input: " \"123\"^^ .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "123", qual: "http://www.w3.org/2001/XMLSchema#string", kind: Literal}, }, }, "nt-syntax-str-esc-01.nq": { { input: " \"a\\n\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a\n", kind: Literal}, }, }, "nt-syntax-str-esc-01.nt": { { input: " \"a\\n\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a\n", kind: Literal}, }, }, "nt-syntax-str-esc-02.nq": { { input: " \"a\\u0020b\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a b", kind: Literal}, }, }, "nt-syntax-str-esc-02.nt": { { input: " \"a\\u0020b\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a b", kind: Literal}, }, }, "nt-syntax-str-esc-03.nq": { { input: " \"a\\U00000020b\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a b", kind: Literal}, }, }, "nt-syntax-str-esc-03.nt": { { input: " \"a\\U00000020b\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "a b", kind: Literal}, }, }, "nt-syntax-string-01.nq": { { input: " \"string\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "string", kind: Literal}, }, }, "nt-syntax-string-01.nt": { { input: " \"string\" .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "string", kind: Literal}, }, }, "nt-syntax-string-02.nq": { { input: " \"string\"@en .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "string", qual: "@en", kind: Literal}, }, }, "nt-syntax-string-02.nt": { { input: " \"string\"@en .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "string", qual: "@en", kind: Literal}, }, }, "nt-syntax-string-03.nq": { { input: " \"string\"@en-uk .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "string", qual: "@en-uk", kind: Literal}, }, }, "nt-syntax-string-03.nt": { { input: " \"string\"@en-uk .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "string", qual: "@en-uk", kind: Literal}, }, }, "nt-syntax-subm-01.nq": { { input: " .", subject: term{text: "http://example.org/resource1", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: "_:anon .", subject: term{text: "anon", kind: Blank}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " _:anon .", subject: term{text: "http://example.org/resource2", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "anon", kind: Blank}, }, { input: " \t \t \t.", subject: term{text: "http://example.org/resource3", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " .", subject: term{text: "http://example.org/resource4", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " .", subject: term{text: "http://example.org/resource5", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " .", subject: term{text: "http://example.org/resource6", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " \"simple literal\" .", subject: term{text: "http://example.org/resource7", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "simple literal", kind: Literal}, }, { input: " \"backslash:\\\\\" .", subject: term{text: "http://example.org/resource8", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "backslash:\\", kind: Literal}, }, { input: " \"dquote:\\\"\" .", subject: term{text: "http://example.org/resource9", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "dquote:\"", kind: Literal}, }, { input: " \"newline:\\n\" .", subject: term{text: "http://example.org/resource10", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "newline:\n", kind: Literal}, }, { input: " \"return\\r\" .", subject: term{text: "http://example.org/resource11", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "return\r", kind: Literal}, }, { input: " \"tab:\\t\" .", subject: term{text: "http://example.org/resource12", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "tab:\t", kind: Literal}, }, { input: " .", subject: term{text: "http://example.org/resource13", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " \"x\".", subject: term{text: "http://example.org/resource14", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "x", kind: Literal}, }, { input: " _:anon.", subject: term{text: "http://example.org/resource15", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "anon", kind: Blank}, }, { input: " \"\\u00E9\" .", subject: term{text: "http://example.org/resource16", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "é", kind: Literal}, }, { input: " \"\\u20AC\" .", subject: term{text: "http://example.org/resource17", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "€", kind: Literal}, }, { input: " \"\"^^ .", subject: term{text: "http://example.org/resource21", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \" \"^^ .", subject: term{text: "http://example.org/resource22", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: " ", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"x\"^^ .", subject: term{text: "http://example.org/resource23", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "x", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"\\\"\"^^ .", subject: term{text: "http://example.org/resource23", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "\"", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"\"^^ .", subject: term{text: "http://example.org/resource24", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"a \"^^ .", subject: term{text: "http://example.org/resource25", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "a ", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"a c\"^^ .", subject: term{text: "http://example.org/resource26", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "a c", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"a\\n\\nc\"^^ .", subject: term{text: "http://example.org/resource26", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "a\n\nc", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"chat\"^^ .", subject: term{text: "http://example.org/resource27", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "chat", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"chat\"@fr .", subject: term{text: "http://example.org/resource30", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "chat", qual: "@fr", kind: Literal}, }, { input: " \"chat\"@en .", subject: term{text: "http://example.org/resource31", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "chat", qual: "@en", kind: Literal}, }, { input: " \"abc\"^^ .", subject: term{text: "http://example.org/resource32", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "abc", qual: "http://example.org/datatype1", kind: Literal}, }, }, "nt-syntax-subm-01.nt": { { input: " .", subject: term{text: "http://example.org/resource1", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: "_:anon .", subject: term{text: "anon", kind: Blank}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " _:anon .", subject: term{text: "http://example.org/resource2", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "anon", kind: Blank}, }, { input: " \t \t \t.", subject: term{text: "http://example.org/resource3", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " .", subject: term{text: "http://example.org/resource4", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " .", subject: term{text: "http://example.org/resource5", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " .", subject: term{text: "http://example.org/resource6", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " \"simple literal\" .", subject: term{text: "http://example.org/resource7", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "simple literal", kind: Literal}, }, { input: " \"backslash:\\\\\" .", subject: term{text: "http://example.org/resource8", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "backslash:\\", kind: Literal}, }, { input: " \"dquote:\\\"\" .", subject: term{text: "http://example.org/resource9", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "dquote:\"", kind: Literal}, }, { input: " \"newline:\\n\" .", subject: term{text: "http://example.org/resource10", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "newline:\n", kind: Literal}, }, { input: " \"return\\r\" .", subject: term{text: "http://example.org/resource11", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "return\r", kind: Literal}, }, { input: " \"tab:\\t\" .", subject: term{text: "http://example.org/resource12", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "tab:\t", kind: Literal}, }, { input: " .", subject: term{text: "http://example.org/resource13", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "http://example.org/resource2", kind: IRI}, }, { input: " \"x\".", subject: term{text: "http://example.org/resource14", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "x", kind: Literal}, }, { input: " _:anon.", subject: term{text: "http://example.org/resource15", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "anon", kind: Blank}, }, { input: " \"\\u00E9\" .", subject: term{text: "http://example.org/resource16", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "é", kind: Literal}, }, { input: " \"\\u20AC\" .", subject: term{text: "http://example.org/resource17", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "€", kind: Literal}, }, { input: " \"\"^^ .", subject: term{text: "http://example.org/resource21", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \" \"^^ .", subject: term{text: "http://example.org/resource22", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: " ", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"x\"^^ .", subject: term{text: "http://example.org/resource23", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "x", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"\\\"\"^^ .", subject: term{text: "http://example.org/resource23", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "\"", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"\"^^ .", subject: term{text: "http://example.org/resource24", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"a \"^^ .", subject: term{text: "http://example.org/resource25", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "a ", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"a c\"^^ .", subject: term{text: "http://example.org/resource26", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "a c", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"a\\n\\nc\"^^ .", subject: term{text: "http://example.org/resource26", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "a\n\nc", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"chat\"^^ .", subject: term{text: "http://example.org/resource27", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "chat", qual: "http://www.w3.org/2000/01/rdf-schema#XMLLiteral", kind: Literal}, }, { input: " \"chat\"@fr .", subject: term{text: "http://example.org/resource30", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "chat", qual: "@fr", kind: Literal}, }, { input: " \"chat\"@en .", subject: term{text: "http://example.org/resource31", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "chat", qual: "@en", kind: Literal}, }, { input: " \"abc\"^^ .", subject: term{text: "http://example.org/resource32", kind: IRI}, predicate: term{text: "http://example.org/property", kind: IRI}, object: term{text: "abc", qual: "http://example.org/datatype1", kind: Literal}, }, }, "nt-syntax-uri-01.nq": { { input: " .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-uri-01.nt": { { input: " .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-uri-02.nq": { { input: " .", subject: term{text: "http://example/S", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-uri-02.nt": { { input: " .", subject: term{text: "http://example/S", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-uri-03.nq": { { input: " .", subject: term{text: "http://example/S", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-uri-03.nt": { { input: " .", subject: term{text: "http://example/S", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "http://example/o", kind: IRI}, }, }, "nt-syntax-uri-04.nq": { { input: " .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "scheme:!$%25&'()*+,-./0123456789:/@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~?#", kind: IRI}, }, }, "nt-syntax-uri-04.nt": { { input: " .", subject: term{text: "http://example/s", kind: IRI}, predicate: term{text: "http://example/p", kind: IRI}, object: term{text: "scheme:!$%25&'()*+,-./0123456789:/@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~?#", kind: IRI}, }, }, // Empty valid syntax. "nt-syntax-file-01.nq": nil, "nt-syntax-file-01.nt": nil, "nt-syntax-file-02.nq": nil, "nt-syntax-file-02.nt": nil, "nt-syntax-file-03.nq": nil, "nt-syntax-file-03.nt": nil, // Invalid syntax. "nq-syntax-bad-literal-01.nq": nil, "nq-syntax-bad-literal-02.nq": nil, "nq-syntax-bad-literal-03.nq": nil, "nq-syntax-bad-quint-01.nq": nil, "nq-syntax-bad-uri-01.nq": nil, "nt-syntax-bad-base-01.nq": nil, "nt-syntax-bad-base-01.nt": nil, "nt-syntax-bad-esc-01.nq": nil, "nt-syntax-bad-esc-01.nt": nil, "nt-syntax-bad-esc-02.nq": nil, "nt-syntax-bad-esc-02.nt": nil, "nt-syntax-bad-esc-03.nq": nil, "nt-syntax-bad-esc-03.nt": nil, "nt-syntax-bad-lang-01.nq": nil, "nt-syntax-bad-lang-01.nt": nil, "nt-syntax-bad-num-01.nq": nil, "nt-syntax-bad-num-01.nt": nil, "nt-syntax-bad-num-02.nq": nil, "nt-syntax-bad-num-02.nt": nil, "nt-syntax-bad-num-03.nq": nil, "nt-syntax-bad-num-03.nt": nil, "nt-syntax-bad-prefix-01.nq": nil, "nt-syntax-bad-prefix-01.nt": nil, "nt-syntax-bad-string-01.nq": nil, "nt-syntax-bad-string-01.nt": nil, "nt-syntax-bad-string-02.nq": nil, "nt-syntax-bad-string-02.nt": nil, "nt-syntax-bad-string-03.nq": nil, "nt-syntax-bad-string-03.nt": nil, "nt-syntax-bad-string-04.nq": nil, "nt-syntax-bad-string-04.nt": nil, "nt-syntax-bad-string-05.nq": nil, "nt-syntax-bad-string-05.nt": nil, "nt-syntax-bad-string-06.nq": nil, "nt-syntax-bad-string-06.nt": nil, "nt-syntax-bad-string-07.nq": nil, "nt-syntax-bad-string-07.nt": nil, "nt-syntax-bad-struct-01.nq": nil, "nt-syntax-bad-struct-01.nt": nil, "nt-syntax-bad-struct-02.nq": nil, "nt-syntax-bad-struct-02.nt": nil, "nt-syntax-bad-uri-01.nq": nil, "nt-syntax-bad-uri-01.nt": nil, "nt-syntax-bad-uri-02.nq": nil, "nt-syntax-bad-uri-02.nt": nil, "nt-syntax-bad-uri-03.nq": nil, "nt-syntax-bad-uri-03.nt": nil, "nt-syntax-bad-uri-04.nq": nil, "nt-syntax-bad-uri-04.nt": nil, "nt-syntax-bad-uri-05.nq": nil, "nt-syntax-bad-uri-05.nt": nil, "nt-syntax-bad-uri-06.nq": nil, "nt-syntax-bad-uri-06.nt": nil, "nt-syntax-bad-uri-07.nq": nil, "nt-syntax-bad-uri-07.nt": nil, "nt-syntax-bad-uri-08.nq": nil, "nt-syntax-bad-uri-08.nt": nil, "nt-syntax-bad-uri-09.nq": nil, "nt-syntax-bad-uri-09.nt": nil, } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/000077500000000000000000000000001450372207100227765ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/LICENSE.md000066400000000000000000000013501450372207100244010ustar00rootroot00000000000000Test suite license This document refers to nquad_tests.tar.gz, ntriple_tests.tar.gz and normalization tests in this directory. The original files can be obtained here: - [nquad_tests.tar.gz](https://w3c.github.io/rdf-tests/nquads/TESTS.tar.gz) - [ntriple_tests.tar.gz](https://w3c.github.io/rdf-tests/ntriples/TESTS.tar.gz) - [normalization tests](https://json-ld.github.io/rdf-dataset-canonicalization/). Distributed under both the [W3C Test Suite License](https://www.w3.org/Consortium/Legal/2008/04-testsuite-license) and the [W3C 3-clause BSD License](https://www.w3.org/Consortium/Legal/2008/03-bsd-license). To contribute to a W3C Test Suite, see the [policies and contribution forms](href="https://www.w3.org/2004/10/27-testcases"). golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/hogan17_2.9_g-in.nq000066400000000000000000000000421450372207100261000ustar00rootroot00000000000000_:a _:b . _:b _:a . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/hogan17_2.9_h-in.nq000066400000000000000000000000631450372207100261040ustar00rootroot00000000000000_:c _:d . _:d _:e . _:e _:c . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/hogan17_3.25_h-in.nq000066400000000000000000000001041450372207100261570ustar00rootroot00000000000000_:f _:i . _:f _:g . _:h _:i . _:h _:g . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/hogan17_3.25_i-in.nq000066400000000000000000000000631450372207100261640ustar00rootroot00000000000000_:j _:k . _:j _:l . _:j _:X . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/hogan17_4.16-in.nq000066400000000000000000000002301450372207100256510ustar00rootroot00000000000000_:d . _:e _:d . _:e . _:e _:f . _:f . _:g . _:h _:g . _:h . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/hogan17_4.5_g-in.nq000066400000000000000000000001411450372207100260760ustar00rootroot00000000000000 _:a . _:b . _:a . _:c . _:c _:b . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/hogan17_4.5_h-in.nq000066400000000000000000000001331450372207100261000ustar00rootroot00000000000000 _:d . _:e . _:f _:d . _:f _:g . _:g _:e . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/index.html000066400000000000000000003712261450372207100250060ustar00rootroot00000000000000 RDF Dataset Normalization Test Cases

W3C

RDF Dataset Normalization Test Cases

Includes manifests for different application profiles.

This page describes RDF Dataset Normalization tests for URGNA2012 and URDNA2015 profiles. These tests are also described in JSON-LD and Turtle formats for convenience. The manifest vocabulary is described in the RDF Dataset Normalization Test Vocabulary (JSON-LD, Turtle) and is based on the RDF Test Vocabulary.

General instructions for running the RDF Dataset Normalization Test suites

FIXME

Contributing Tests

The test manifests and entries are built automatically from manifest.csv using mk_manifest.rb, where each row defines a combination of RDF, JSON and Validation tests for the same action and implicit files. Tests may be contributed via pull request to https://github.com/json-ld/normalization with suitable changes to the manifest.csv and necessary action and result files. Tests will also be considered if a contribution is sent to public-credentials@w3.org.

Distribution

Distributed under both the W3C Test Suite License and the W3C 3-clause BSD License. To contribute to a W3C Test Suite, see the policies and contribution forms.

Disclaimer

UNDER BOTH MUTUALLY EXCLUSIVE LICENSES, THIS DOCUMENT AND ALL DOCUMENTS, TESTS AND SOFTWARE THAT LINK THIS STATEMENT ARE PROVIDED “AS IS,” AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF.

Contents

  1. RDF Graph Normalization (URGNA2012) – 59 entries
  2. RDF Dataset Normalization (URDNA2015) – 62 entries

RDF Graph Normalization (URGNA2012) (59 entries)

Tests the 2012 version of RDF Graph Normalization.

Instructions specific to running URGNA2012 tests.

manifest-urgna2012#test001: simple id
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test001-in.nq
result
test001-urgna2012.nq
manifest-urgna2012#test002: duplicate property iri values
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test002-in.nq
result
test002-urgna2012.nq
manifest-urgna2012#test003: bnode
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test003-in.nq
result
test003-urgna2012.nq
manifest-urgna2012#test004: bnode plus embed w/subject
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test004-in.nq
result
test004-urgna2012.nq
manifest-urgna2012#test005: bnode embed
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test005-in.nq
result
test005-urgna2012.nq
manifest-urgna2012#test006: multiple rdf types
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test006-in.nq
result
test006-urgna2012.nq
manifest-urgna2012#test007: coerce CURIE value
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test007-in.nq
result
test007-urgna2012.nq
manifest-urgna2012#test008: single subject complex
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test008-in.nq
result
test008-urgna2012.nq
manifest-urgna2012#test009: multiple subjects - complex
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test009-in.nq
result
test009-urgna2012.nq
manifest-urgna2012#test010: type
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test010-in.nq
result
test010-urgna2012.nq
manifest-urgna2012#test011: type-coerced type
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test011-in.nq
result
test011-urgna2012.nq
manifest-urgna2012#test012: type-coerced type, remove duplicate reference
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test012-in.nq
result
test012-urgna2012.nq
manifest-urgna2012#test013: type-coerced type, cycle
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test013-in.nq
result
test013-urgna2012.nq
manifest-urgna2012#test014: check types
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test014-in.nq
result
test014-urgna2012.nq
manifest-urgna2012#test015: top level context
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test015-in.nq
result
test015-urgna2012.nq
manifest-urgna2012#test016: blank node - dual link - embed
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test016-in.nq
result
test016-urgna2012.nq
manifest-urgna2012#test017: blank node - dual link - non-embed
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test017-in.nq
result
test017-urgna2012.nq
manifest-urgna2012#test018: blank node - self link
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test018-in.nq
result
test018-urgna2012.nq
manifest-urgna2012#test019: blank node - disjoint self links
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test019-in.nq
result
test019-urgna2012.nq
manifest-urgna2012#test020: blank node - diamond
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test020-in.nq
result
test020-urgna2012.nq
manifest-urgna2012#test021: blank node - circle of 2
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test021-in.nq
result
test021-urgna2012.nq
manifest-urgna2012#test022: blank node - double circle of 2
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test022-in.nq
result
test022-urgna2012.nq
manifest-urgna2012#test023: blank node - circle of 3
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test023-in.nq
result
test023-urgna2012.nq
manifest-urgna2012#test024: blank node - double circle of 3 (1-2-3)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test024-in.nq
result
test024-urgna2012.nq
manifest-urgna2012#test025: blank node - double circle of 3 (1-3-2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test025-in.nq
result
test025-urgna2012.nq
manifest-urgna2012#test026: blank node - double circle of 3 (2-1-3)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test026-in.nq
result
test026-urgna2012.nq
manifest-urgna2012#test027: blank node - double circle of 3 (2-3-1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test027-in.nq
result
test027-urgna2012.nq
manifest-urgna2012#test028: blank node - double circle of 3 (3-2-1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test028-in.nq
result
test028-urgna2012.nq
manifest-urgna2012#test029: blank node - double circle of 3 (3-1-2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test029-in.nq
result
test029-urgna2012.nq
manifest-urgna2012#test030: blank node - point at circle of 3
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test030-in.nq
result
test030-urgna2012.nq
manifest-urgna2012#test031: bnode (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test031-in.nq
result
test031-urgna2012.nq
manifest-urgna2012#test032: bnode (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test032-in.nq
result
test032-urgna2012.nq
manifest-urgna2012#test033: disjoint identical subgraphs (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test033-in.nq
result
test033-urgna2012.nq
manifest-urgna2012#test034: disjoint identical subgraphs (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test034-in.nq
result
test034-urgna2012.nq
manifest-urgna2012#test035: reordered w/strings (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test035-in.nq
result
test035-urgna2012.nq
manifest-urgna2012#test036: reordered w/strings (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test036-in.nq
result
test036-urgna2012.nq
manifest-urgna2012#test037: reordered w/strings (3)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test037-in.nq
result
test037-urgna2012.nq
manifest-urgna2012#test038: reordered 4 bnodes, reordered 2 properties (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test038-in.nq
result
test038-urgna2012.nq
manifest-urgna2012#test039: reordered 4 bnodes, reordered 2 properties (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test039-in.nq
result
test039-urgna2012.nq
manifest-urgna2012#test040: reordered 6 bnodes (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test040-in.nq
result
test040-urgna2012.nq
manifest-urgna2012#test041: reordered 6 bnodes (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test041-in.nq
result
test041-urgna2012.nq
manifest-urgna2012#test042: reordered 6 bnodes (3)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test042-in.nq
result
test042-urgna2012.nq
manifest-urgna2012#test043: literal with language
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test043-in.nq
result
test043-urgna2012.nq
manifest-urgna2012#test044: evil (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test044-in.nq
result
test044-urgna2012.nq
manifest-urgna2012#test045: evil (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test045-in.nq
result
test045-urgna2012.nq
manifest-urgna2012#test046: evil (3)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test046-in.nq
result
test046-urgna2012.nq
manifest-urgna2012#test047: deep diff (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test047-in.nq
result
test047-urgna2012.nq
manifest-urgna2012#test048: deep diff (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test048-in.nq
result
test048-urgna2012.nq
manifest-urgna2012#test049: remove null
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test049-in.nq
result
test049-urgna2012.nq
manifest-urgna2012#test050: nulls
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test050-in.nq
result
test050-urgna2012.nq
manifest-urgna2012#test051: merging subjects
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test051-in.nq
result
test051-urgna2012.nq
manifest-urgna2012#test052: alias keywords
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test052-in.nq
result
test052-urgna2012.nq
manifest-urgna2012#test053: @list
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test053-in.nq
result
test053-urgna2012.nq
manifest-urgna2012#test054: t-graph
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test054-in.nq
result
test054-urgna2012.nq
manifest-urgna2012#test055: simple reorder (1)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test055-in.nq
result
test055-urgna2012.nq
manifest-urgna2012#test056: simple reorder (2)
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test056-in.nq
result
test056-urgna2012.nq
manifest-urgna2012#test060: n-quads escaping
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test060-in.nq
result
test060-urgna2012.nq
manifest-urgna2012#test061: same literal value with multiple languages
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test061-in.nq
result
test061-urgna2012.nq
manifest-urgna2012#test062: same literal value with multiple datatypes
type
rdfn:Urgna2012EvalTest
approval
rdft:Proposed
action
test062-in.nq
result
test062-urgna2012.nq

RDF Dataset Normalization (URDNA2015) (62 entries)

Tests the 2015 version of RDF Dataset Normalization.

manifest-urdna2015#test001: simple id
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test001-in.nq
result
test001-urdna2015.nq
manifest-urdna2015#test002: duplicate property iri values
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test002-in.nq
result
test002-urdna2015.nq
manifest-urdna2015#test003: bnode
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test003-in.nq
result
test003-urdna2015.nq
manifest-urdna2015#test004: bnode plus embed w/subject
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test004-in.nq
result
test004-urdna2015.nq
manifest-urdna2015#test005: bnode embed
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test005-in.nq
result
test005-urdna2015.nq
manifest-urdna2015#test006: multiple rdf types
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test006-in.nq
result
test006-urdna2015.nq
manifest-urdna2015#test007: coerce CURIE value
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test007-in.nq
result
test007-urdna2015.nq
manifest-urdna2015#test008: single subject complex
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test008-in.nq
result
test008-urdna2015.nq
manifest-urdna2015#test009: multiple subjects - complex
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test009-in.nq
result
test009-urdna2015.nq
manifest-urdna2015#test010: type
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test010-in.nq
result
test010-urdna2015.nq
manifest-urdna2015#test011: type-coerced type
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test011-in.nq
result
test011-urdna2015.nq
manifest-urdna2015#test012: type-coerced type, remove duplicate reference
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test012-in.nq
result
test012-urdna2015.nq
manifest-urdna2015#test013: type-coerced type, cycle
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test013-in.nq
result
test013-urdna2015.nq
manifest-urdna2015#test014: check types
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test014-in.nq
result
test014-urdna2015.nq
manifest-urdna2015#test015: top level context
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test015-in.nq
result
test015-urdna2015.nq
manifest-urdna2015#test016: blank node - dual link - embed
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test016-in.nq
result
test016-urdna2015.nq
manifest-urdna2015#test017: blank node - dual link - non-embed
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test017-in.nq
result
test017-urdna2015.nq
manifest-urdna2015#test018: blank node - self link
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test018-in.nq
result
test018-urdna2015.nq
manifest-urdna2015#test019: blank node - disjoint self links
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test019-in.nq
result
test019-urdna2015.nq
manifest-urdna2015#test020: blank node - diamond
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test020-in.nq
result
test020-urdna2015.nq
manifest-urdna2015#test021: blank node - circle of 2
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test021-in.nq
result
test021-urdna2015.nq
manifest-urdna2015#test022: blank node - double circle of 2
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test022-in.nq
result
test022-urdna2015.nq
manifest-urdna2015#test023: blank node - circle of 3
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test023-in.nq
result
test023-urdna2015.nq
manifest-urdna2015#test024: blank node - double circle of 3 (1-2-3)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test024-in.nq
result
test024-urdna2015.nq
manifest-urdna2015#test025: blank node - double circle of 3 (1-3-2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test025-in.nq
result
test025-urdna2015.nq
manifest-urdna2015#test026: blank node - double circle of 3 (2-1-3)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test026-in.nq
result
test026-urdna2015.nq
manifest-urdna2015#test027: blank node - double circle of 3 (2-3-1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test027-in.nq
result
test027-urdna2015.nq
manifest-urdna2015#test028: blank node - double circle of 3 (3-2-1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test028-in.nq
result
test028-urdna2015.nq
manifest-urdna2015#test029: blank node - double circle of 3 (3-1-2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test029-in.nq
result
test029-urdna2015.nq
manifest-urdna2015#test030: blank node - point at circle of 3
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test030-in.nq
result
test030-urdna2015.nq
manifest-urdna2015#test031: bnode (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test031-in.nq
result
test031-urdna2015.nq
manifest-urdna2015#test032: bnode (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test032-in.nq
result
test032-urdna2015.nq
manifest-urdna2015#test033: disjoint identical subgraphs (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test033-in.nq
result
test033-urdna2015.nq
manifest-urdna2015#test034: disjoint identical subgraphs (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test034-in.nq
result
test034-urdna2015.nq
manifest-urdna2015#test035: reordered w/strings (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test035-in.nq
result
test035-urdna2015.nq
manifest-urdna2015#test036: reordered w/strings (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test036-in.nq
result
test036-urdna2015.nq
manifest-urdna2015#test037: reordered w/strings (3)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test037-in.nq
result
test037-urdna2015.nq
manifest-urdna2015#test038: reordered 4 bnodes, reordered 2 properties (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test038-in.nq
result
test038-urdna2015.nq
manifest-urdna2015#test039: reordered 4 bnodes, reordered 2 properties (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test039-in.nq
result
test039-urdna2015.nq
manifest-urdna2015#test040: reordered 6 bnodes (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test040-in.nq
result
test040-urdna2015.nq
manifest-urdna2015#test041: reordered 6 bnodes (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test041-in.nq
result
test041-urdna2015.nq
manifest-urdna2015#test042: reordered 6 bnodes (3)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test042-in.nq
result
test042-urdna2015.nq
manifest-urdna2015#test043: literal with language
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test043-in.nq
result
test043-urdna2015.nq
manifest-urdna2015#test044: evil (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test044-in.nq
result
test044-urdna2015.nq
manifest-urdna2015#test045: evil (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test045-in.nq
result
test045-urdna2015.nq
manifest-urdna2015#test046: evil (3)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test046-in.nq
result
test046-urdna2015.nq
manifest-urdna2015#test047: deep diff (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test047-in.nq
result
test047-urdna2015.nq
manifest-urdna2015#test048: deep diff (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test048-in.nq
result
test048-urdna2015.nq
manifest-urdna2015#test049: remove null
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test049-in.nq
result
test049-urdna2015.nq
manifest-urdna2015#test050: nulls
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test050-in.nq
result
test050-urdna2015.nq
manifest-urdna2015#test051: merging subjects
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test051-in.nq
result
test051-urdna2015.nq
manifest-urdna2015#test052: alias keywords
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test052-in.nq
result
test052-urdna2015.nq
manifest-urdna2015#test053: @list
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test053-in.nq
result
test053-urdna2015.nq
manifest-urdna2015#test054: t-graph
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test054-in.nq
result
test054-urdna2015.nq
manifest-urdna2015#test055: simple reorder (1)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test055-in.nq
result
test055-urdna2015.nq
manifest-urdna2015#test056: simple reorder (2)
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test056-in.nq
result
test056-urdna2015.nq
manifest-urdna2015#test057: unnamed graph
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test057-in.nq
result
test057-urdna2015.nq
manifest-urdna2015#test058: unnamed graph with blank node objects
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test058-in.nq
result
test058-urdna2015.nq
manifest-urdna2015#test059: n-quads parsing
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test059-in.nq
result
test059-urdna2015.nq
manifest-urdna2015#test060: n-quads escaping
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test060-in.nq
result
test060-urdna2015.nq
manifest-urdna2015#test061: same literal value with multiple languages
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test061-in.nq
result
test061-urdna2015.nq
manifest-urdna2015#test062: same literal value with multiple datatypes
type
rdfn:Urdna2015EvalTest
approval
rdft:Proposed
action
test062-in.nq
result
test062-urdna2015.nq
golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/manifest-urdna2015.jsonld000066400000000000000000000421051450372207100274400ustar00rootroot00000000000000{ "@context": { "xsd": "http://www.w3.org/2001/XMLSchema#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "mq": "http://www.w3.org/2001/sw/DataAccess/tests/test-query#", "rdfn": "http://json-ld.github.io/normalization/test-vocab#", "rdft": "http://www.w3.org/ns/rdftest#", "id": "@id", "type": "@type", "action": { "@id": "mf:action", "@type": "@id" }, "approval": { "@id": "rdft:approval", "@type": "@id" }, "comment": "rdfs:comment", "entries": { "@id": "mf:entries", "@type": "@id", "@container": "@list" }, "label": "rdfs:label", "name": "mf:name", "result": { "@id": "mf:result", "@type": "@id" } }, "id": "manifest-urdna2015", "type": "mf:Manifest", "label": "RDF Dataset Normalization (URDNA2015)", "comment": "Tests the 2015 version of RDF Dataset Normalization.", "entries": [ { "id": "manifest-urdna2015#test001", "type": "rdfn:Urdna2015EvalTest", "name": "simple id", "comment": null, "approval": "rdft:Proposed", "action": "test001-in.nq", "result": "test001-urdna2015.nq" }, { "id": "manifest-urdna2015#test002", "type": "rdfn:Urdna2015EvalTest", "name": "duplicate property iri values", "comment": null, "approval": "rdft:Proposed", "action": "test002-in.nq", "result": "test002-urdna2015.nq" }, { "id": "manifest-urdna2015#test003", "type": "rdfn:Urdna2015EvalTest", "name": "bnode", "comment": null, "approval": "rdft:Proposed", "action": "test003-in.nq", "result": "test003-urdna2015.nq" }, { "id": "manifest-urdna2015#test004", "type": "rdfn:Urdna2015EvalTest", "name": "bnode plus embed w/subject", "comment": null, "approval": "rdft:Proposed", "action": "test004-in.nq", "result": "test004-urdna2015.nq" }, { "id": "manifest-urdna2015#test005", "type": "rdfn:Urdna2015EvalTest", "name": "bnode embed", "comment": null, "approval": "rdft:Proposed", "action": "test005-in.nq", "result": "test005-urdna2015.nq" }, { "id": "manifest-urdna2015#test006", "type": "rdfn:Urdna2015EvalTest", "name": "multiple rdf types", "comment": null, "approval": "rdft:Proposed", "action": "test006-in.nq", "result": "test006-urdna2015.nq" }, { "id": "manifest-urdna2015#test007", "type": "rdfn:Urdna2015EvalTest", "name": "coerce CURIE value", "comment": null, "approval": "rdft:Proposed", "action": "test007-in.nq", "result": "test007-urdna2015.nq" }, { "id": "manifest-urdna2015#test008", "type": "rdfn:Urdna2015EvalTest", "name": "single subject complex", "comment": null, "approval": "rdft:Proposed", "action": "test008-in.nq", "result": "test008-urdna2015.nq" }, { "id": "manifest-urdna2015#test009", "type": "rdfn:Urdna2015EvalTest", "name": "multiple subjects - complex", "comment": null, "approval": "rdft:Proposed", "action": "test009-in.nq", "result": "test009-urdna2015.nq" }, { "id": "manifest-urdna2015#test010", "type": "rdfn:Urdna2015EvalTest", "name": "type", "comment": null, "approval": "rdft:Proposed", "action": "test010-in.nq", "result": "test010-urdna2015.nq" }, { "id": "manifest-urdna2015#test011", "type": "rdfn:Urdna2015EvalTest", "name": "type-coerced type", "comment": null, "approval": "rdft:Proposed", "action": "test011-in.nq", "result": "test011-urdna2015.nq" }, { "id": "manifest-urdna2015#test012", "type": "rdfn:Urdna2015EvalTest", "name": "type-coerced type, remove duplicate reference", "comment": null, "approval": "rdft:Proposed", "action": "test012-in.nq", "result": "test012-urdna2015.nq" }, { "id": "manifest-urdna2015#test013", "type": "rdfn:Urdna2015EvalTest", "name": "type-coerced type, cycle", "comment": null, "approval": "rdft:Proposed", "action": "test013-in.nq", "result": "test013-urdna2015.nq" }, { "id": "manifest-urdna2015#test014", "type": "rdfn:Urdna2015EvalTest", "name": "check types", "comment": null, "approval": "rdft:Proposed", "action": "test014-in.nq", "result": "test014-urdna2015.nq" }, { "id": "manifest-urdna2015#test015", "type": "rdfn:Urdna2015EvalTest", "name": "top level context", "comment": null, "approval": "rdft:Proposed", "action": "test015-in.nq", "result": "test015-urdna2015.nq" }, { "id": "manifest-urdna2015#test016", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - dual link - embed", "comment": null, "approval": "rdft:Proposed", "action": "test016-in.nq", "result": "test016-urdna2015.nq" }, { "id": "manifest-urdna2015#test017", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - dual link - non-embed", "comment": null, "approval": "rdft:Proposed", "action": "test017-in.nq", "result": "test017-urdna2015.nq" }, { "id": "manifest-urdna2015#test018", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - self link", "comment": null, "approval": "rdft:Proposed", "action": "test018-in.nq", "result": "test018-urdna2015.nq" }, { "id": "manifest-urdna2015#test019", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - disjoint self links", "comment": null, "approval": "rdft:Proposed", "action": "test019-in.nq", "result": "test019-urdna2015.nq" }, { "id": "manifest-urdna2015#test020", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - diamond", "comment": null, "approval": "rdft:Proposed", "action": "test020-in.nq", "result": "test020-urdna2015.nq" }, { "id": "manifest-urdna2015#test021", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - circle of 2", "comment": null, "approval": "rdft:Proposed", "action": "test021-in.nq", "result": "test021-urdna2015.nq" }, { "id": "manifest-urdna2015#test022", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - double circle of 2", "comment": null, "approval": "rdft:Proposed", "action": "test022-in.nq", "result": "test022-urdna2015.nq" }, { "id": "manifest-urdna2015#test023", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - circle of 3", "comment": null, "approval": "rdft:Proposed", "action": "test023-in.nq", "result": "test023-urdna2015.nq" }, { "id": "manifest-urdna2015#test024", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - double circle of 3 (1-2-3)", "comment": null, "approval": "rdft:Proposed", "action": "test024-in.nq", "result": "test024-urdna2015.nq" }, { "id": "manifest-urdna2015#test025", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - double circle of 3 (1-3-2)", "comment": null, "approval": "rdft:Proposed", "action": "test025-in.nq", "result": "test025-urdna2015.nq" }, { "id": "manifest-urdna2015#test026", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - double circle of 3 (2-1-3)", "comment": null, "approval": "rdft:Proposed", "action": "test026-in.nq", "result": "test026-urdna2015.nq" }, { "id": "manifest-urdna2015#test027", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - double circle of 3 (2-3-1)", "comment": null, "approval": "rdft:Proposed", "action": "test027-in.nq", "result": "test027-urdna2015.nq" }, { "id": "manifest-urdna2015#test028", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - double circle of 3 (3-2-1)", "comment": null, "approval": "rdft:Proposed", "action": "test028-in.nq", "result": "test028-urdna2015.nq" }, { "id": "manifest-urdna2015#test029", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - double circle of 3 (3-1-2)", "comment": null, "approval": "rdft:Proposed", "action": "test029-in.nq", "result": "test029-urdna2015.nq" }, { "id": "manifest-urdna2015#test030", "type": "rdfn:Urdna2015EvalTest", "name": "blank node - point at circle of 3", "comment": null, "approval": "rdft:Proposed", "action": "test030-in.nq", "result": "test030-urdna2015.nq" }, { "id": "manifest-urdna2015#test031", "type": "rdfn:Urdna2015EvalTest", "name": "bnode (1)", "comment": null, "approval": "rdft:Proposed", "action": "test031-in.nq", "result": "test031-urdna2015.nq" }, { "id": "manifest-urdna2015#test032", "type": "rdfn:Urdna2015EvalTest", "name": "bnode (2)", "comment": null, "approval": "rdft:Proposed", "action": "test032-in.nq", "result": "test032-urdna2015.nq" }, { "id": "manifest-urdna2015#test033", "type": "rdfn:Urdna2015EvalTest", "name": "disjoint identical subgraphs (1)", "comment": null, "approval": "rdft:Proposed", "action": "test033-in.nq", "result": "test033-urdna2015.nq" }, { "id": "manifest-urdna2015#test034", "type": "rdfn:Urdna2015EvalTest", "name": "disjoint identical subgraphs (2)", "comment": null, "approval": "rdft:Proposed", "action": "test034-in.nq", "result": "test034-urdna2015.nq" }, { "id": "manifest-urdna2015#test035", "type": "rdfn:Urdna2015EvalTest", "name": "reordered w/strings (1)", "comment": null, "approval": "rdft:Proposed", "action": "test035-in.nq", "result": "test035-urdna2015.nq" }, { "id": "manifest-urdna2015#test036", "type": "rdfn:Urdna2015EvalTest", "name": "reordered w/strings (2)", "comment": null, "approval": "rdft:Proposed", "action": "test036-in.nq", "result": "test036-urdna2015.nq" }, { "id": "manifest-urdna2015#test037", "type": "rdfn:Urdna2015EvalTest", "name": "reordered w/strings (3)", "comment": null, "approval": "rdft:Proposed", "action": "test037-in.nq", "result": "test037-urdna2015.nq" }, { "id": "manifest-urdna2015#test038", "type": "rdfn:Urdna2015EvalTest", "name": "reordered 4 bnodes, reordered 2 properties (1)", "comment": null, "approval": "rdft:Proposed", "action": "test038-in.nq", "result": "test038-urdna2015.nq" }, { "id": "manifest-urdna2015#test039", "type": "rdfn:Urdna2015EvalTest", "name": "reordered 4 bnodes, reordered 2 properties (2)", "comment": null, "approval": "rdft:Proposed", "action": "test039-in.nq", "result": "test039-urdna2015.nq" }, { "id": "manifest-urdna2015#test040", "type": "rdfn:Urdna2015EvalTest", "name": "reordered 6 bnodes (1)", "comment": null, "approval": "rdft:Proposed", "action": "test040-in.nq", "result": "test040-urdna2015.nq" }, { "id": "manifest-urdna2015#test041", "type": "rdfn:Urdna2015EvalTest", "name": "reordered 6 bnodes (2)", "comment": null, "approval": "rdft:Proposed", "action": "test041-in.nq", "result": "test041-urdna2015.nq" }, { "id": "manifest-urdna2015#test042", "type": "rdfn:Urdna2015EvalTest", "name": "reordered 6 bnodes (3)", "comment": null, "approval": "rdft:Proposed", "action": "test042-in.nq", "result": "test042-urdna2015.nq" }, { "id": "manifest-urdna2015#test043", "type": "rdfn:Urdna2015EvalTest", "name": "literal with language", "comment": null, "approval": "rdft:Proposed", "action": "test043-in.nq", "result": "test043-urdna2015.nq" }, { "id": "manifest-urdna2015#test044", "type": "rdfn:Urdna2015EvalTest", "name": "evil (1)", "comment": null, "approval": "rdft:Proposed", "action": "test044-in.nq", "result": "test044-urdna2015.nq" }, { "id": "manifest-urdna2015#test045", "type": "rdfn:Urdna2015EvalTest", "name": "evil (2)", "comment": null, "approval": "rdft:Proposed", "action": "test045-in.nq", "result": "test045-urdna2015.nq" }, { "id": "manifest-urdna2015#test046", "type": "rdfn:Urdna2015EvalTest", "name": "evil (3)", "comment": null, "approval": "rdft:Proposed", "action": "test046-in.nq", "result": "test046-urdna2015.nq" }, { "id": "manifest-urdna2015#test047", "type": "rdfn:Urdna2015EvalTest", "name": "deep diff (1)", "comment": null, "approval": "rdft:Proposed", "action": "test047-in.nq", "result": "test047-urdna2015.nq" }, { "id": "manifest-urdna2015#test048", "type": "rdfn:Urdna2015EvalTest", "name": "deep diff (2)", "comment": null, "approval": "rdft:Proposed", "action": "test048-in.nq", "result": "test048-urdna2015.nq" }, { "id": "manifest-urdna2015#test049", "type": "rdfn:Urdna2015EvalTest", "name": "remove null", "comment": null, "approval": "rdft:Proposed", "action": "test049-in.nq", "result": "test049-urdna2015.nq" }, { "id": "manifest-urdna2015#test050", "type": "rdfn:Urdna2015EvalTest", "name": "nulls", "comment": null, "approval": "rdft:Proposed", "action": "test050-in.nq", "result": "test050-urdna2015.nq" }, { "id": "manifest-urdna2015#test051", "type": "rdfn:Urdna2015EvalTest", "name": "merging subjects", "comment": null, "approval": "rdft:Proposed", "action": "test051-in.nq", "result": "test051-urdna2015.nq" }, { "id": "manifest-urdna2015#test052", "type": "rdfn:Urdna2015EvalTest", "name": "alias keywords", "comment": null, "approval": "rdft:Proposed", "action": "test052-in.nq", "result": "test052-urdna2015.nq" }, { "id": "manifest-urdna2015#test053", "type": "rdfn:Urdna2015EvalTest", "name": "@list", "comment": null, "approval": "rdft:Proposed", "action": "test053-in.nq", "result": "test053-urdna2015.nq" }, { "id": "manifest-urdna2015#test054", "type": "rdfn:Urdna2015EvalTest", "name": "t-graph", "comment": null, "approval": "rdft:Proposed", "action": "test054-in.nq", "result": "test054-urdna2015.nq" }, { "id": "manifest-urdna2015#test055", "type": "rdfn:Urdna2015EvalTest", "name": "simple reorder (1)", "comment": null, "approval": "rdft:Proposed", "action": "test055-in.nq", "result": "test055-urdna2015.nq" }, { "id": "manifest-urdna2015#test056", "type": "rdfn:Urdna2015EvalTest", "name": "simple reorder (2)", "comment": null, "approval": "rdft:Proposed", "action": "test056-in.nq", "result": "test056-urdna2015.nq" }, { "id": "manifest-urdna2015#test057", "type": "rdfn:Urdna2015EvalTest", "name": "unnamed graph", "comment": null, "approval": "rdft:Proposed", "action": "test057-in.nq", "result": "test057-urdna2015.nq" }, { "id": "manifest-urdna2015#test058", "type": "rdfn:Urdna2015EvalTest", "name": "unnamed graph with blank node objects", "comment": null, "approval": "rdft:Proposed", "action": "test058-in.nq", "result": "test058-urdna2015.nq" }, { "id": "manifest-urdna2015#test059", "type": "rdfn:Urdna2015EvalTest", "name": "n-quads parsing", "comment": null, "approval": "rdft:Proposed", "action": "test059-in.nq", "result": "test059-urdna2015.nq" }, { "id": "manifest-urdna2015#test060", "type": "rdfn:Urdna2015EvalTest", "name": "n-quads escaping", "comment": null, "approval": "rdft:Proposed", "action": "test060-in.nq", "result": "test060-urdna2015.nq" }, { "id": "manifest-urdna2015#test061", "type": "rdfn:Urdna2015EvalTest", "name": "same literal value with multiple languages", "comment": null, "approval": "rdft:Proposed", "action": "test061-in.nq", "result": "test061-urdna2015.nq" }, { "id": "manifest-urdna2015#test062", "type": "rdfn:Urdna2015EvalTest", "name": "same literal value with multiple datatypes", "comment": null, "approval": "rdft:Proposed", "action": "test062-in.nq", "result": "test062-urdna2015.nq" } ] } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/manifest-urdna2015.ttl000066400000000000000000000301011450372207100267430ustar00rootroot00000000000000## RDF Dataset Normalization tests ## Distributed under both the W3C Test Suite License[1] and the W3C 3- ## clause BSD License[2]. To contribute to a W3C Test Suite, see the ## policies and contribution forms [3] ## ## 1. http://www.w3.org/Consortium/Legal/2008/04-testsuite-license ## 2. http://www.w3.org/Consortium/Legal/2008/03-bsd-license ## 3. http://www.w3.org/2004/10/27-testcases ## ## Test types ## * rdfn:Urgna2012EvalTest - Normalization using URGNA2012 ## * rdfn:Urdna2015EvalTest - Normalization using URDNA2015 @prefix : . @prefix rdf: . @prefix rdfs: . @prefix mf: . @prefix rdft: . @prefix rdfn: . a mf:Manifest ; rdfs:label "RDF Dataset Normalization (URDNA2015)"; rdfs:comment "Tests the 2015 version of RDF Dataset Normalization."; mf:entries ( :test001 :test002 :test003 :test004 :test005 :test006 :test007 :test008 :test009 :test010 :test011 :test012 :test013 :test014 :test015 :test016 :test017 :test018 :test019 :test020 :test021 :test022 :test023 :test024 :test025 :test026 :test027 :test028 :test029 :test030 :test031 :test032 :test033 :test034 :test035 :test036 :test037 :test038 :test039 :test040 :test041 :test042 :test043 :test044 :test045 :test046 :test047 :test048 :test049 :test050 :test051 :test052 :test053 :test054 :test055 :test056 :test057 :test058 :test059 :test060 :test061 :test062 ) . :test001 a rdfn:Urdna2015EvalTest; mf:name "simple id"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test002 a rdfn:Urdna2015EvalTest; mf:name "duplicate property iri values"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test003 a rdfn:Urdna2015EvalTest; mf:name "bnode"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test004 a rdfn:Urdna2015EvalTest; mf:name "bnode plus embed w/subject"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test005 a rdfn:Urdna2015EvalTest; mf:name "bnode embed"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test006 a rdfn:Urdna2015EvalTest; mf:name "multiple rdf types"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test007 a rdfn:Urdna2015EvalTest; mf:name "coerce CURIE value"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test008 a rdfn:Urdna2015EvalTest; mf:name "single subject complex"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test009 a rdfn:Urdna2015EvalTest; mf:name "multiple subjects - complex"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test010 a rdfn:Urdna2015EvalTest; mf:name "type"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test011 a rdfn:Urdna2015EvalTest; mf:name "type-coerced type"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test012 a rdfn:Urdna2015EvalTest; mf:name "type-coerced type, remove duplicate reference"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test013 a rdfn:Urdna2015EvalTest; mf:name "type-coerced type, cycle"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test014 a rdfn:Urdna2015EvalTest; mf:name "check types"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test015 a rdfn:Urdna2015EvalTest; mf:name "top level context"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test016 a rdfn:Urdna2015EvalTest; mf:name "blank node - dual link - embed"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test017 a rdfn:Urdna2015EvalTest; mf:name "blank node - dual link - non-embed"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test018 a rdfn:Urdna2015EvalTest; mf:name "blank node - self link"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test019 a rdfn:Urdna2015EvalTest; mf:name "blank node - disjoint self links"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test020 a rdfn:Urdna2015EvalTest; mf:name "blank node - diamond"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test021 a rdfn:Urdna2015EvalTest; mf:name "blank node - circle of 2"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test022 a rdfn:Urdna2015EvalTest; mf:name "blank node - double circle of 2"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test023 a rdfn:Urdna2015EvalTest; mf:name "blank node - circle of 3"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test024 a rdfn:Urdna2015EvalTest; mf:name "blank node - double circle of 3 (1-2-3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test025 a rdfn:Urdna2015EvalTest; mf:name "blank node - double circle of 3 (1-3-2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test026 a rdfn:Urdna2015EvalTest; mf:name "blank node - double circle of 3 (2-1-3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test027 a rdfn:Urdna2015EvalTest; mf:name "blank node - double circle of 3 (2-3-1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test028 a rdfn:Urdna2015EvalTest; mf:name "blank node - double circle of 3 (3-2-1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test029 a rdfn:Urdna2015EvalTest; mf:name "blank node - double circle of 3 (3-1-2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test030 a rdfn:Urdna2015EvalTest; mf:name "blank node - point at circle of 3"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test031 a rdfn:Urdna2015EvalTest; mf:name "bnode (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test032 a rdfn:Urdna2015EvalTest; mf:name "bnode (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test033 a rdfn:Urdna2015EvalTest; mf:name "disjoint identical subgraphs (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test034 a rdfn:Urdna2015EvalTest; mf:name "disjoint identical subgraphs (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test035 a rdfn:Urdna2015EvalTest; mf:name "reordered w/strings (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test036 a rdfn:Urdna2015EvalTest; mf:name "reordered w/strings (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test037 a rdfn:Urdna2015EvalTest; mf:name "reordered w/strings (3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test038 a rdfn:Urdna2015EvalTest; mf:name "reordered 4 bnodes, reordered 2 properties (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test039 a rdfn:Urdna2015EvalTest; mf:name "reordered 4 bnodes, reordered 2 properties (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test040 a rdfn:Urdna2015EvalTest; mf:name "reordered 6 bnodes (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test041 a rdfn:Urdna2015EvalTest; mf:name "reordered 6 bnodes (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test042 a rdfn:Urdna2015EvalTest; mf:name "reordered 6 bnodes (3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test043 a rdfn:Urdna2015EvalTest; mf:name "literal with language"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test044 a rdfn:Urdna2015EvalTest; mf:name "evil (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test045 a rdfn:Urdna2015EvalTest; mf:name "evil (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test046 a rdfn:Urdna2015EvalTest; mf:name "evil (3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test047 a rdfn:Urdna2015EvalTest; mf:name "deep diff (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test048 a rdfn:Urdna2015EvalTest; mf:name "deep diff (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test049 a rdfn:Urdna2015EvalTest; mf:name "remove null"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test050 a rdfn:Urdna2015EvalTest; mf:name "nulls"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test051 a rdfn:Urdna2015EvalTest; mf:name "merging subjects"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test052 a rdfn:Urdna2015EvalTest; mf:name "alias keywords"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test053 a rdfn:Urdna2015EvalTest; mf:name "@list"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test054 a rdfn:Urdna2015EvalTest; mf:name "t-graph"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test055 a rdfn:Urdna2015EvalTest; mf:name "simple reorder (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test056 a rdfn:Urdna2015EvalTest; mf:name "simple reorder (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test057 a rdfn:Urdna2015EvalTest; mf:name "unnamed graph"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test058 a rdfn:Urdna2015EvalTest; mf:name "unnamed graph with blank node objects"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test059 a rdfn:Urdna2015EvalTest; mf:name "n-quads parsing"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test060 a rdfn:Urdna2015EvalTest; mf:name "n-quads escaping"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test061 a rdfn:Urdna2015EvalTest; mf:name "same literal value with multiple languages"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test062 a rdfn:Urdna2015EvalTest; mf:name "same literal value with multiple datatypes"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/manifest-urgna2012.jsonld000066400000000000000000000404471450372207100274470ustar00rootroot00000000000000{ "@context": { "xsd": "http://www.w3.org/2001/XMLSchema#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "mq": "http://www.w3.org/2001/sw/DataAccess/tests/test-query#", "rdfn": "http://json-ld.github.io/normalization/test-vocab#", "rdft": "http://www.w3.org/ns/rdftest#", "id": "@id", "type": "@type", "action": { "@id": "mf:action", "@type": "@id" }, "approval": { "@id": "rdft:approval", "@type": "@id" }, "comment": "rdfs:comment", "entries": { "@id": "mf:entries", "@type": "@id", "@container": "@list" }, "label": "rdfs:label", "name": "mf:name", "result": { "@id": "mf:result", "@type": "@id" } }, "id": "manifest-urgna2012", "type": "mf:Manifest", "label": "RDF Graph Normalization (URGNA2012)", "comment": "Tests the 2012 version of RDF Graph Normalization.", "entries": [ { "id": "manifest-urgna2012#test001", "type": "rdfn:Urgna2012EvalTest", "name": "simple id", "comment": null, "approval": "rdft:Proposed", "action": "test001-in.nq", "result": "test001-urgna2012.nq" }, { "id": "manifest-urgna2012#test002", "type": "rdfn:Urgna2012EvalTest", "name": "duplicate property iri values", "comment": null, "approval": "rdft:Proposed", "action": "test002-in.nq", "result": "test002-urgna2012.nq" }, { "id": "manifest-urgna2012#test003", "type": "rdfn:Urgna2012EvalTest", "name": "bnode", "comment": null, "approval": "rdft:Proposed", "action": "test003-in.nq", "result": "test003-urgna2012.nq" }, { "id": "manifest-urgna2012#test004", "type": "rdfn:Urgna2012EvalTest", "name": "bnode plus embed w/subject", "comment": null, "approval": "rdft:Proposed", "action": "test004-in.nq", "result": "test004-urgna2012.nq" }, { "id": "manifest-urgna2012#test005", "type": "rdfn:Urgna2012EvalTest", "name": "bnode embed", "comment": null, "approval": "rdft:Proposed", "action": "test005-in.nq", "result": "test005-urgna2012.nq" }, { "id": "manifest-urgna2012#test006", "type": "rdfn:Urgna2012EvalTest", "name": "multiple rdf types", "comment": null, "approval": "rdft:Proposed", "action": "test006-in.nq", "result": "test006-urgna2012.nq" }, { "id": "manifest-urgna2012#test007", "type": "rdfn:Urgna2012EvalTest", "name": "coerce CURIE value", "comment": null, "approval": "rdft:Proposed", "action": "test007-in.nq", "result": "test007-urgna2012.nq" }, { "id": "manifest-urgna2012#test008", "type": "rdfn:Urgna2012EvalTest", "name": "single subject complex", "comment": null, "approval": "rdft:Proposed", "action": "test008-in.nq", "result": "test008-urgna2012.nq" }, { "id": "manifest-urgna2012#test009", "type": "rdfn:Urgna2012EvalTest", "name": "multiple subjects - complex", "comment": null, "approval": "rdft:Proposed", "action": "test009-in.nq", "result": "test009-urgna2012.nq" }, { "id": "manifest-urgna2012#test010", "type": "rdfn:Urgna2012EvalTest", "name": "type", "comment": null, "approval": "rdft:Proposed", "action": "test010-in.nq", "result": "test010-urgna2012.nq" }, { "id": "manifest-urgna2012#test011", "type": "rdfn:Urgna2012EvalTest", "name": "type-coerced type", "comment": null, "approval": "rdft:Proposed", "action": "test011-in.nq", "result": "test011-urgna2012.nq" }, { "id": "manifest-urgna2012#test012", "type": "rdfn:Urgna2012EvalTest", "name": "type-coerced type, remove duplicate reference", "comment": null, "approval": "rdft:Proposed", "action": "test012-in.nq", "result": "test012-urgna2012.nq" }, { "id": "manifest-urgna2012#test013", "type": "rdfn:Urgna2012EvalTest", "name": "type-coerced type, cycle", "comment": null, "approval": "rdft:Proposed", "action": "test013-in.nq", "result": "test013-urgna2012.nq" }, { "id": "manifest-urgna2012#test014", "type": "rdfn:Urgna2012EvalTest", "name": "check types", "comment": null, "approval": "rdft:Proposed", "action": "test014-in.nq", "result": "test014-urgna2012.nq" }, { "id": "manifest-urgna2012#test015", "type": "rdfn:Urgna2012EvalTest", "name": "top level context", "comment": null, "approval": "rdft:Proposed", "action": "test015-in.nq", "result": "test015-urgna2012.nq" }, { "id": "manifest-urgna2012#test016", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - dual link - embed", "comment": null, "approval": "rdft:Proposed", "action": "test016-in.nq", "result": "test016-urgna2012.nq" }, { "id": "manifest-urgna2012#test017", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - dual link - non-embed", "comment": null, "approval": "rdft:Proposed", "action": "test017-in.nq", "result": "test017-urgna2012.nq" }, { "id": "manifest-urgna2012#test018", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - self link", "comment": null, "approval": "rdft:Proposed", "action": "test018-in.nq", "result": "test018-urgna2012.nq" }, { "id": "manifest-urgna2012#test019", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - disjoint self links", "comment": null, "approval": "rdft:Proposed", "action": "test019-in.nq", "result": "test019-urgna2012.nq" }, { "id": "manifest-urgna2012#test020", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - diamond", "comment": null, "approval": "rdft:Proposed", "action": "test020-in.nq", "result": "test020-urgna2012.nq" }, { "id": "manifest-urgna2012#test021", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - circle of 2", "comment": null, "approval": "rdft:Proposed", "action": "test021-in.nq", "result": "test021-urgna2012.nq" }, { "id": "manifest-urgna2012#test022", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - double circle of 2", "comment": null, "approval": "rdft:Proposed", "action": "test022-in.nq", "result": "test022-urgna2012.nq" }, { "id": "manifest-urgna2012#test023", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - circle of 3", "comment": null, "approval": "rdft:Proposed", "action": "test023-in.nq", "result": "test023-urgna2012.nq" }, { "id": "manifest-urgna2012#test024", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - double circle of 3 (1-2-3)", "comment": null, "approval": "rdft:Proposed", "action": "test024-in.nq", "result": "test024-urgna2012.nq" }, { "id": "manifest-urgna2012#test025", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - double circle of 3 (1-3-2)", "comment": null, "approval": "rdft:Proposed", "action": "test025-in.nq", "result": "test025-urgna2012.nq" }, { "id": "manifest-urgna2012#test026", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - double circle of 3 (2-1-3)", "comment": null, "approval": "rdft:Proposed", "action": "test026-in.nq", "result": "test026-urgna2012.nq" }, { "id": "manifest-urgna2012#test027", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - double circle of 3 (2-3-1)", "comment": null, "approval": "rdft:Proposed", "action": "test027-in.nq", "result": "test027-urgna2012.nq" }, { "id": "manifest-urgna2012#test028", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - double circle of 3 (3-2-1)", "comment": null, "approval": "rdft:Proposed", "action": "test028-in.nq", "result": "test028-urgna2012.nq" }, { "id": "manifest-urgna2012#test029", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - double circle of 3 (3-1-2)", "comment": null, "approval": "rdft:Proposed", "action": "test029-in.nq", "result": "test029-urgna2012.nq" }, { "id": "manifest-urgna2012#test030", "type": "rdfn:Urgna2012EvalTest", "name": "blank node - point at circle of 3", "comment": null, "approval": "rdft:Proposed", "action": "test030-in.nq", "result": "test030-urgna2012.nq" }, { "id": "manifest-urgna2012#test031", "type": "rdfn:Urgna2012EvalTest", "name": "bnode (1)", "comment": null, "approval": "rdft:Proposed", "action": "test031-in.nq", "result": "test031-urgna2012.nq" }, { "id": "manifest-urgna2012#test032", "type": "rdfn:Urgna2012EvalTest", "name": "bnode (2)", "comment": null, "approval": "rdft:Proposed", "action": "test032-in.nq", "result": "test032-urgna2012.nq" }, { "id": "manifest-urgna2012#test033", "type": "rdfn:Urgna2012EvalTest", "name": "disjoint identical subgraphs (1)", "comment": null, "approval": "rdft:Proposed", "action": "test033-in.nq", "result": "test033-urgna2012.nq" }, { "id": "manifest-urgna2012#test034", "type": "rdfn:Urgna2012EvalTest", "name": "disjoint identical subgraphs (2)", "comment": null, "approval": "rdft:Proposed", "action": "test034-in.nq", "result": "test034-urgna2012.nq" }, { "id": "manifest-urgna2012#test035", "type": "rdfn:Urgna2012EvalTest", "name": "reordered w/strings (1)", "comment": null, "approval": "rdft:Proposed", "action": "test035-in.nq", "result": "test035-urgna2012.nq" }, { "id": "manifest-urgna2012#test036", "type": "rdfn:Urgna2012EvalTest", "name": "reordered w/strings (2)", "comment": null, "approval": "rdft:Proposed", "action": "test036-in.nq", "result": "test036-urgna2012.nq" }, { "id": "manifest-urgna2012#test037", "type": "rdfn:Urgna2012EvalTest", "name": "reordered w/strings (3)", "comment": null, "approval": "rdft:Proposed", "action": "test037-in.nq", "result": "test037-urgna2012.nq" }, { "id": "manifest-urgna2012#test038", "type": "rdfn:Urgna2012EvalTest", "name": "reordered 4 bnodes, reordered 2 properties (1)", "comment": null, "approval": "rdft:Proposed", "action": "test038-in.nq", "result": "test038-urgna2012.nq" }, { "id": "manifest-urgna2012#test039", "type": "rdfn:Urgna2012EvalTest", "name": "reordered 4 bnodes, reordered 2 properties (2)", "comment": null, "approval": "rdft:Proposed", "action": "test039-in.nq", "result": "test039-urgna2012.nq" }, { "id": "manifest-urgna2012#test040", "type": "rdfn:Urgna2012EvalTest", "name": "reordered 6 bnodes (1)", "comment": null, "approval": "rdft:Proposed", "action": "test040-in.nq", "result": "test040-urgna2012.nq" }, { "id": "manifest-urgna2012#test041", "type": "rdfn:Urgna2012EvalTest", "name": "reordered 6 bnodes (2)", "comment": null, "approval": "rdft:Proposed", "action": "test041-in.nq", "result": "test041-urgna2012.nq" }, { "id": "manifest-urgna2012#test042", "type": "rdfn:Urgna2012EvalTest", "name": "reordered 6 bnodes (3)", "comment": null, "approval": "rdft:Proposed", "action": "test042-in.nq", "result": "test042-urgna2012.nq" }, { "id": "manifest-urgna2012#test043", "type": "rdfn:Urgna2012EvalTest", "name": "literal with language", "comment": null, "approval": "rdft:Proposed", "action": "test043-in.nq", "result": "test043-urgna2012.nq" }, { "id": "manifest-urgna2012#test044", "type": "rdfn:Urgna2012EvalTest", "name": "evil (1)", "comment": null, "approval": "rdft:Proposed", "action": "test044-in.nq", "result": "test044-urgna2012.nq" }, { "id": "manifest-urgna2012#test045", "type": "rdfn:Urgna2012EvalTest", "name": "evil (2)", "comment": null, "approval": "rdft:Proposed", "action": "test045-in.nq", "result": "test045-urgna2012.nq" }, { "id": "manifest-urgna2012#test046", "type": "rdfn:Urgna2012EvalTest", "name": "evil (3)", "comment": null, "approval": "rdft:Proposed", "action": "test046-in.nq", "result": "test046-urgna2012.nq" }, { "id": "manifest-urgna2012#test047", "type": "rdfn:Urgna2012EvalTest", "name": "deep diff (1)", "comment": null, "approval": "rdft:Proposed", "action": "test047-in.nq", "result": "test047-urgna2012.nq" }, { "id": "manifest-urgna2012#test048", "type": "rdfn:Urgna2012EvalTest", "name": "deep diff (2)", "comment": null, "approval": "rdft:Proposed", "action": "test048-in.nq", "result": "test048-urgna2012.nq" }, { "id": "manifest-urgna2012#test049", "type": "rdfn:Urgna2012EvalTest", "name": "remove null", "comment": null, "approval": "rdft:Proposed", "action": "test049-in.nq", "result": "test049-urgna2012.nq" }, { "id": "manifest-urgna2012#test050", "type": "rdfn:Urgna2012EvalTest", "name": "nulls", "comment": null, "approval": "rdft:Proposed", "action": "test050-in.nq", "result": "test050-urgna2012.nq" }, { "id": "manifest-urgna2012#test051", "type": "rdfn:Urgna2012EvalTest", "name": "merging subjects", "comment": null, "approval": "rdft:Proposed", "action": "test051-in.nq", "result": "test051-urgna2012.nq" }, { "id": "manifest-urgna2012#test052", "type": "rdfn:Urgna2012EvalTest", "name": "alias keywords", "comment": null, "approval": "rdft:Proposed", "action": "test052-in.nq", "result": "test052-urgna2012.nq" }, { "id": "manifest-urgna2012#test053", "type": "rdfn:Urgna2012EvalTest", "name": "@list", "comment": null, "approval": "rdft:Proposed", "action": "test053-in.nq", "result": "test053-urgna2012.nq" }, { "id": "manifest-urgna2012#test054", "type": "rdfn:Urgna2012EvalTest", "name": "t-graph", "comment": null, "approval": "rdft:Proposed", "action": "test054-in.nq", "result": "test054-urgna2012.nq" }, { "id": "manifest-urgna2012#test055", "type": "rdfn:Urgna2012EvalTest", "name": "simple reorder (1)", "comment": null, "approval": "rdft:Proposed", "action": "test055-in.nq", "result": "test055-urgna2012.nq" }, { "id": "manifest-urgna2012#test056", "type": "rdfn:Urgna2012EvalTest", "name": "simple reorder (2)", "comment": null, "approval": "rdft:Proposed", "action": "test056-in.nq", "result": "test056-urgna2012.nq" }, { "id": "manifest-urgna2012#test060", "type": "rdfn:Urgna2012EvalTest", "name": "n-quads escaping", "comment": null, "approval": "rdft:Proposed", "action": "test060-in.nq", "result": "test060-urgna2012.nq" }, { "id": "manifest-urgna2012#test061", "type": "rdfn:Urgna2012EvalTest", "name": "same literal value with multiple languages", "comment": null, "approval": "rdft:Proposed", "action": "test061-in.nq", "result": "test061-urgna2012.nq" }, { "id": "manifest-urgna2012#test062", "type": "rdfn:Urgna2012EvalTest", "name": "same literal value with multiple datatypes", "comment": null, "approval": "rdft:Proposed", "action": "test062-in.nq", "result": "test062-urgna2012.nq" } ] } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/manifest-urgna2012.ttl000066400000000000000000000270331450372207100267550ustar00rootroot00000000000000## RDF Dataset Normalization tests ## Distributed under both the W3C Test Suite License[1] and the W3C 3- ## clause BSD License[2]. To contribute to a W3C Test Suite, see the ## policies and contribution forms [3] ## ## 1. http://www.w3.org/Consortium/Legal/2008/04-testsuite-license ## 2. http://www.w3.org/Consortium/Legal/2008/03-bsd-license ## 3. http://www.w3.org/2004/10/27-testcases ## ## Test types ## * rdfn:Urgna2012EvalTest - Normalization using URGNA2012 ## * rdfn:Urdna2015EvalTest - Normalization using URDNA2015 @prefix : . @prefix rdf: . @prefix rdfs: . @prefix mf: . @prefix rdft: . @prefix rdfn: . a mf:Manifest ; rdfs:label "RDF Graph Normalization (URGNA2012)"; rdfs:comment "Tests the 2012 version of RDF Graph Normalization."; mf:entries ( :test001 :test002 :test003 :test004 :test005 :test006 :test007 :test008 :test009 :test010 :test011 :test012 :test013 :test014 :test015 :test016 :test017 :test018 :test019 :test020 :test021 :test022 :test023 :test024 :test025 :test026 :test027 :test028 :test029 :test030 :test031 :test032 :test033 :test034 :test035 :test036 :test037 :test038 :test039 :test040 :test041 :test042 :test043 :test044 :test045 :test046 :test047 :test048 :test049 :test050 :test051 :test052 :test053 :test054 :test055 :test056 :test060 :test061 :test062 ) . :test001 a rdfn:Urgna2012EvalTest; mf:name "simple id"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test002 a rdfn:Urgna2012EvalTest; mf:name "duplicate property iri values"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test003 a rdfn:Urgna2012EvalTest; mf:name "bnode"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test004 a rdfn:Urgna2012EvalTest; mf:name "bnode plus embed w/subject"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test005 a rdfn:Urgna2012EvalTest; mf:name "bnode embed"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test006 a rdfn:Urgna2012EvalTest; mf:name "multiple rdf types"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test007 a rdfn:Urgna2012EvalTest; mf:name "coerce CURIE value"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test008 a rdfn:Urgna2012EvalTest; mf:name "single subject complex"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test009 a rdfn:Urgna2012EvalTest; mf:name "multiple subjects - complex"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test010 a rdfn:Urgna2012EvalTest; mf:name "type"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test011 a rdfn:Urgna2012EvalTest; mf:name "type-coerced type"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test012 a rdfn:Urgna2012EvalTest; mf:name "type-coerced type, remove duplicate reference"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test013 a rdfn:Urgna2012EvalTest; mf:name "type-coerced type, cycle"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test014 a rdfn:Urgna2012EvalTest; mf:name "check types"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test015 a rdfn:Urgna2012EvalTest; mf:name "top level context"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test016 a rdfn:Urgna2012EvalTest; mf:name "blank node - dual link - embed"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test017 a rdfn:Urgna2012EvalTest; mf:name "blank node - dual link - non-embed"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test018 a rdfn:Urgna2012EvalTest; mf:name "blank node - self link"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test019 a rdfn:Urgna2012EvalTest; mf:name "blank node - disjoint self links"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test020 a rdfn:Urgna2012EvalTest; mf:name "blank node - diamond"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test021 a rdfn:Urgna2012EvalTest; mf:name "blank node - circle of 2"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test022 a rdfn:Urgna2012EvalTest; mf:name "blank node - double circle of 2"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test023 a rdfn:Urgna2012EvalTest; mf:name "blank node - circle of 3"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test024 a rdfn:Urgna2012EvalTest; mf:name "blank node - double circle of 3 (1-2-3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test025 a rdfn:Urgna2012EvalTest; mf:name "blank node - double circle of 3 (1-3-2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test026 a rdfn:Urgna2012EvalTest; mf:name "blank node - double circle of 3 (2-1-3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test027 a rdfn:Urgna2012EvalTest; mf:name "blank node - double circle of 3 (2-3-1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test028 a rdfn:Urgna2012EvalTest; mf:name "blank node - double circle of 3 (3-2-1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test029 a rdfn:Urgna2012EvalTest; mf:name "blank node - double circle of 3 (3-1-2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test030 a rdfn:Urgna2012EvalTest; mf:name "blank node - point at circle of 3"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test031 a rdfn:Urgna2012EvalTest; mf:name "bnode (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test032 a rdfn:Urgna2012EvalTest; mf:name "bnode (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test033 a rdfn:Urgna2012EvalTest; mf:name "disjoint identical subgraphs (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test034 a rdfn:Urgna2012EvalTest; mf:name "disjoint identical subgraphs (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test035 a rdfn:Urgna2012EvalTest; mf:name "reordered w/strings (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test036 a rdfn:Urgna2012EvalTest; mf:name "reordered w/strings (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test037 a rdfn:Urgna2012EvalTest; mf:name "reordered w/strings (3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test038 a rdfn:Urgna2012EvalTest; mf:name "reordered 4 bnodes, reordered 2 properties (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test039 a rdfn:Urgna2012EvalTest; mf:name "reordered 4 bnodes, reordered 2 properties (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test040 a rdfn:Urgna2012EvalTest; mf:name "reordered 6 bnodes (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test041 a rdfn:Urgna2012EvalTest; mf:name "reordered 6 bnodes (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test042 a rdfn:Urgna2012EvalTest; mf:name "reordered 6 bnodes (3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test043 a rdfn:Urgna2012EvalTest; mf:name "literal with language"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test044 a rdfn:Urgna2012EvalTest; mf:name "evil (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test045 a rdfn:Urgna2012EvalTest; mf:name "evil (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test046 a rdfn:Urgna2012EvalTest; mf:name "evil (3)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test047 a rdfn:Urgna2012EvalTest; mf:name "deep diff (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test048 a rdfn:Urgna2012EvalTest; mf:name "deep diff (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test049 a rdfn:Urgna2012EvalTest; mf:name "remove null"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test050 a rdfn:Urgna2012EvalTest; mf:name "nulls"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test051 a rdfn:Urgna2012EvalTest; mf:name "merging subjects"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test052 a rdfn:Urgna2012EvalTest; mf:name "alias keywords"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test053 a rdfn:Urgna2012EvalTest; mf:name "@list"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test054 a rdfn:Urgna2012EvalTest; mf:name "t-graph"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test055 a rdfn:Urgna2012EvalTest; mf:name "simple reorder (1)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test056 a rdfn:Urgna2012EvalTest; mf:name "simple reorder (2)"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test060 a rdfn:Urgna2012EvalTest; mf:name "n-quads escaping"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test061 a rdfn:Urgna2012EvalTest; mf:name "same literal value with multiple languages"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . :test062 a rdfn:Urgna2012EvalTest; mf:name "same literal value with multiple datatypes"; rdft:approval rdft:Proposed; mf:action ; mf:result ; . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/manifest.csv000066400000000000000000000053161450372207100253260ustar00rootroot00000000000000test,name,comment,approval,urgna2012,urdna2015 test001,simple id,,,TRUE,TRUE test002,duplicate property iri values,,,TRUE,TRUE test003,bnode,,,TRUE,TRUE test004,bnode plus embed w/subject,,,TRUE,TRUE test005,bnode embed,,,TRUE,TRUE test006,multiple rdf types,,,TRUE,TRUE test007,coerce CURIE value,,,TRUE,TRUE test008,single subject complex,,,TRUE,TRUE test009,multiple subjects - complex,,,TRUE,TRUE test010,type,,,TRUE,TRUE test011,type-coerced type,,,TRUE,TRUE test012,"type-coerced type, remove duplicate reference",,,TRUE,TRUE test013,"type-coerced type, cycle",,,TRUE,TRUE test014,check types,,,TRUE,TRUE test015,top level context,,,TRUE,TRUE test016,blank node - dual link - embed,,,TRUE,TRUE test017,blank node - dual link - non-embed,,,TRUE,TRUE test018,blank node - self link,,,TRUE,TRUE test019,blank node - disjoint self links,,,TRUE,TRUE test020,blank node - diamond,,,TRUE,TRUE test021,blank node - circle of 2,,,TRUE,TRUE test022,blank node - double circle of 2,,,TRUE,TRUE test023,blank node - circle of 3,,,TRUE,TRUE test024,blank node - double circle of 3 (1-2-3),,,TRUE,TRUE test025,blank node - double circle of 3 (1-3-2),,,TRUE,TRUE test026,blank node - double circle of 3 (2-1-3),,,TRUE,TRUE test027,blank node - double circle of 3 (2-3-1),,,TRUE,TRUE test028,blank node - double circle of 3 (3-2-1),,,TRUE,TRUE test029,blank node - double circle of 3 (3-1-2),,,TRUE,TRUE test030,blank node - point at circle of 3,,,TRUE,TRUE test031,bnode (1),,,TRUE,TRUE test032,bnode (2),,,TRUE,TRUE test033,disjoint identical subgraphs (1),,,TRUE,TRUE test034,disjoint identical subgraphs (2),,,TRUE,TRUE test035,reordered w/strings (1),,,TRUE,TRUE test036,reordered w/strings (2),,,TRUE,TRUE test037,reordered w/strings (3),,,TRUE,TRUE test038,"reordered 4 bnodes, reordered 2 properties (1)",,,TRUE,TRUE test039,"reordered 4 bnodes, reordered 2 properties (2)",,,TRUE,TRUE test040,reordered 6 bnodes (1),,,TRUE,TRUE test041,reordered 6 bnodes (2),,,TRUE,TRUE test042,reordered 6 bnodes (3),,,TRUE,TRUE test043,literal with language,,,TRUE,TRUE test044,evil (1),,,TRUE,TRUE test045,evil (2),,,TRUE,TRUE test046,evil (3),,,TRUE,TRUE test047,deep diff (1),,,TRUE,TRUE test048,deep diff (2),,,TRUE,TRUE test049,remove null,,,TRUE,TRUE test050,nulls,,,TRUE,TRUE test051,merging subjects,,,TRUE,TRUE test052,alias keywords,,,TRUE,TRUE test053,@list,,,TRUE,TRUE test054,t-graph,,,TRUE,TRUE test055,simple reorder (1),,,TRUE,TRUE test056,simple reorder (2),,,TRUE,TRUE test057,unnamed graph,,,FALSE,TRUE test058,unnamed graph with blank node objects,,,FALSE,TRUE test059,n-quads parsing,,,FALSE,TRUE test060,n-quads escaping,,,TRUE,TRUE test061,same literal value with multiple languages,,,TRUE,TRUE test062,same literal value with multiple datatypes,,,TRUE,TRUE golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/manifest.jsonld000066400000000000000000000011121450372207100260120ustar00rootroot00000000000000{ "@context": { "xsd": "http://www.w3.org/2001/XMLSchema#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "id": "@id", "type": "@type", "comment": "rdfs:comment", "include": {"@id": "mf:include", "@type": "@id", "@container": "@list"}, "label": "rdfs:label" }, "id": "", "type": "mf:Manifest", "label": "RDF Dataset Normalization Test Cases", "comment": "Includes manifests for different application profiles.", "include": ["manifest-urgna2012", "manifest-urdna2015"] } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/manifest.ttl000066400000000000000000000016671450372207100253430ustar00rootroot00000000000000## RDF Dataset Normalization tests ## Distributed under both the W3C Test Suite License[1] and the W3C 3- ## clause BSD License[2]. To contribute to a W3C Test Suite, see the ## policies and contribution forms [3] ## ## 1. http://www.w3.org/Consortium/Legal/2008/04-testsuite-license ## 2. http://www.w3.org/Consortium/Legal/2008/03-bsd-license ## 3. http://www.w3.org/2004/10/27-testcases ## ## Test types ## * rdfn:Urgna2012EvalTest - Normalization using URGNA2012 ## * rdfn:Urdna2015EvalTest - Normalization using URDNA2015 @prefix : <#> . @prefix rdf: . @prefix rdfs: . @prefix mf: . <> a mf:Manifest ; rdfs:label "RDF Dataset Normalization Test Cases" ; rdfs:comment "Includes manifests for different application profiles." mf:include ( ). golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/mk_manifest.rb000077500000000000000000000171621450372207100256320ustar00rootroot00000000000000#! /usr/bin/env ruby # Parse test manifest to create driver and area-specific test manifests require 'getoptlong' require 'csv' require 'json' require 'haml' require 'fileutils' class Manifest JSON_STATE = JSON::State.new( :indent => " ", :space => " ", :space_before => "", :object_nl => "\n", :array_nl => "\n" ) TITLE = { urgna2012: "RDF Graph Normalization (URGNA2012)", urdna2015: "RDF Dataset Normalization (URDNA2015)", } DESCRIPTION = { urgna2012: "Tests the 2012 version of RDF Graph Normalization.", urdna2015: "Tests the 2015 version of RDF Dataset Normalization." } Test = Struct.new(:id, :name, :comment, :approval, :action, :urgna2012, :urdna2015) attr_accessor :tests def initialize csv = CSV.new(File.open(File.expand_path("../manifest.csv", __FILE__))) columns = [] csv.shift.each_with_index {|c, i| columns[i] = c.to_sym if c} @tests = csv.map do |line| entry = {} # Create entry as object indexed by symbolized column name line.each_with_index {|v, i| entry[columns[i]] = v ? v.gsub("\r", "\n").gsub("\\", "\\\\") : nil} urgna2012 = "#{entry[:test]}-urgna2012.nq" if entry[:urgna2012] == "TRUE" urdna2015 = "#{entry[:test]}-urdna2015.nq" if entry[:urdna2015] == "TRUE" Test.new(entry[:test], entry[:name], entry[:comment], entry[:approval], "#{entry[:test]}-in.nq", urgna2012, urdna2015) end end # Create files referenced in the manifest def create_files tests.each do |test| files = [test.action, test.urgna2012, test.urdna2015].compact files.compact.select {|f| !File.exist?(f)}.each do |f| File.open(f, "w") {|io| io.puts( f.end_with?('.json') ? "{}" : "")} end end end def test_class(test, variant) case variant.to_sym when :urgna2012 then "rdfn:Urgna2012EvalTest" when :urdna2015 then "rdfn:Urdna2015EvalTest" end end def to_jsonld(variant) context = ::JSON.parse %({ "xsd": "http://www.w3.org/2001/XMLSchema#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "mq": "http://www.w3.org/2001/sw/DataAccess/tests/test-query#", "rdfn": "http://json-ld.github.io/normalization/test-vocab#", "rdft": "http://www.w3.org/ns/rdftest#", "id": "@id", "type": "@type", "action": {"@id": "mf:action", "@type": "@id"}, "approval": {"@id": "rdft:approval", "@type": "@id"}, "comment": "rdfs:comment", "entries": {"@id": "mf:entries", "@type": "@id", "@container": "@list"}, "label": "rdfs:label", "name": "mf:name", "result": {"@id": "mf:result", "@type": "@id"} }) manifest = { "@context" => context, "id" => "manifest-#{variant}", "type" => "mf:Manifest", "label" => TITLE[variant], "comment" => DESCRIPTION[variant], "entries" => [] } tests.each do |test| next unless test.send(variant) manifest["entries"] << { "id" => "manifest-#{variant}##{test.id}", "type" => test_class(test, variant), "name" => test.name, "comment" => test.comment, "approval" => (test.approval ? "rdft:#{test.approval}" : "rdft:Proposed"), "action" => test.action, "result" => test.send(variant) } end manifest.to_json(JSON_STATE) end def to_html # Create vocab.html using vocab_template.haml and compacted vocabulary template = File.read("template.haml") manifests = TITLE.keys.inject({}) do |memo, v| memo["manifest-#{v}"] = ::JSON.load(File.read("manifest-#{v}.jsonld")) memo end Haml::Engine.new(template, :format => :html5).render(self, man: ::JSON.load(File.read("manifest.jsonld")), manifests: manifests ) end def to_ttl(variant) output = [] output << %(## RDF Dataset Normalization tests ## Distributed under both the W3C Test Suite License[1] and the W3C 3- ## clause BSD License[2]. To contribute to a W3C Test Suite, see the ## policies and contribution forms [3] ## ## 1. http://www.w3.org/Consortium/Legal/2008/04-testsuite-license ## 2. http://www.w3.org/Consortium/Legal/2008/03-bsd-license ## 3. http://www.w3.org/2004/10/27-testcases ## ## Test types ## * rdfn:Urgna2012EvalTest - Normalization using URGNA2012 ## * rdfn:Urdna2015EvalTest - Normalization using URDNA2015 @prefix : . @prefix rdf: . @prefix rdfs: . @prefix mf: . @prefix rdft: . @prefix rdfn: . a mf:Manifest ; ) output << %( rdfs:label "#{TITLE[variant]}";) output << %( rdfs:comment "#{DESCRIPTION[variant]}";) output << %( mf:entries \() tests.select {|t| t.send(variant)}.map {|t| ":#{t.id}"}.each_slice(10) do |entries| output << %( #{entries.join(' ')}) end output << %( \) .) tests.select {|t| t.send(variant)}.each do |test| output << "" # separator output << ":#{test.id} a #{test_class(test, variant)};" output << %( mf:name "#{test.name}";) output << %( rdfs:comment "#{test.comment}";) if test.comment output << %( rdft:approval #{(test.approval ? "rdft:#{test.approval}" : "rdft:Proposed")};) output << %( mf:action <#{test.action}>;) output << %( mf:result <#{test.send(variant)}>;) output << %( .) end output.join("\n") end end options = { output: $stdout } OPT_ARGS = [ ["--format", "-f", GetoptLong::REQUIRED_ARGUMENT,"Output format, default #{options[:format].inspect}"], ["--output", "-o", GetoptLong::REQUIRED_ARGUMENT,"Output to the specified file path"], ["--quiet", GetoptLong::NO_ARGUMENT, "Supress most output other than progress indicators"], ["--touch", GetoptLong::NO_ARGUMENT, "Create referenced files and directories if missing"], ["--variant", GetoptLong::REQUIRED_ARGUMENT,"Test variant, 'rdf' or 'json'"], ["--help", "-?", GetoptLong::NO_ARGUMENT, "This message"] ] def usage STDERR.puts %{Usage: #{$0} [options] URL ...} width = OPT_ARGS.map do |o| l = o.first.length l += o[1].length + 2 if o[1].is_a?(String) l end.max OPT_ARGS.each do |o| s = " %-*s " % [width, (o[1].is_a?(String) ? "#{o[0,2].join(', ')}" : o[0])] s += o.last STDERR.puts s end exit(1) end opts = GetoptLong.new(*OPT_ARGS.map {|o| o[0..-2]}) opts.each do |opt, arg| case opt when '--format' then options[:format] = arg.to_sym when '--output' then options[:output] = File.open(arg, "w") when '--quiet' then options[:quiet] = true when '--touch' then options[:touch] = true when '--variant' then options[:variant] = arg.to_sym when '--help' then usage end end vocab = Manifest.new vocab.create_files if options[:touch] if options[:format] || options[:variant] case options[:format] when :jsonld then options[:output].puts(vocab.to_jsonld(options[:variant])) when :ttl then options[:output].puts(vocab.to_ttl(options[:variant])) when :html then options[:output].puts(vocab.to_html) else STDERR.puts "Unknown format #{options[:format].inspect}" end else Manifest::TITLE.keys.each do |variant| %w(jsonld ttl).each do |format| File.open("manifest-#{variant}.#{format}", "w") do |output| output.puts(vocab.send("to_#{format}".to_sym, variant)) end end end File.open("index.html", "w") do |output| output.puts(vocab.to_html) end end golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/mk_vocab.rb000077500000000000000000000027341450372207100251150ustar00rootroot00000000000000#!/usr/bin/env ruby # Generate vocab.jsonld and vocab.html from vocab.ttl and vocab_template. # # Generating vocab.jsonld is equivalent to running the following: # # jsonld --compact --context vocab_context.jsonld --input-format ttl vocab.ttl -o vocab.jsonld require 'linkeddata' require 'haml' require 'active_support' File.open("vocab.jsonld", "w") do |f| r = RDF::Repository.load("vocab.ttl") JSON::LD::API.fromRDF(r, useNativeTypes: true) do |expanded| # Remove leading/trailing and multiple whitespace from rdf:comments expanded.each do |o| c = o[RDF::RDFS.comment.to_s].first['@value'] o[RDF::RDFS.comment.to_s].first['@value'] = c.strip.gsub(/\s+/m, ' ') end JSON::LD::API.compact(expanded, File.open("vocab_context.jsonld")) do |compacted| # Create vocab.jsonld f.write(compacted.to_json(JSON::LD::JSON_STATE)) # Create vocab.html using vocab_template.haml and compacted vocabulary template = File.read("vocab_template.haml") html = Haml::Engine.new(template, :format => :html5).render(self, ontology: compacted['@graph'].detect {|o| o['@id'] == "http://json-ld.github.io/normalization/tests/vocab#"}, classes: compacted['@graph'].select {|o| o['@type'] == "rdfs:Class"}.sort_by {|o| o['rdfs:label']}, properties: compacted['@graph'].select {|o| o['@type'] == "rdf:Property"}.sort_by {|o| o['rdfs:label']} ) File.open("vocab.html", "w") {|fh| fh.write html} end end end golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/nquad_tests.tar.gz000066400000000000000000000157771450372207100265000ustar00rootroot00000000000000R]vyyiFDVx=3?*%A3!>rHnP$A%BZgvi _^|U6Z4@~Ϛ~6 j돀=z4|EIp8x=6dz~>T=g<8\Ă8P~Fok6F}@SȿOZ*1WC5IrA산i9kUrJw}d#Qϡ}4T-p1#~k㿦4 Q`~72 Dkui*F*B t=l W_Jso5,$E`$ucXVؾX_cތ_WߞbU!W\ W\urm~'??'cr=!חy y y y + r%\2'SO tl&W8'+]=~:__$,LuvpMȱ l7o'+'_%߷s 8f߈H 'daXr]'~A}7_]Fplvǂ}(st3g?ohJC_V?. [9鿛:>|Oo4e_VKҭlo85E`IobˋO?52ו:|t~~zIXMAX!_w.>zutyXzM`[a55)/d7;/ON^s_?1XHobuzv}?zP_V-uߞk:K%`?\U] 'uUZki1s鋫{Sjr!*?"{l mMnLz~Yڃ-@ O V+1_]oC Vۇ?>|wwuw~ӇE?{i0TdžmP{f濦jߨr삳ϧFoܴvvO\80ox-@_[֔*zKR/ 8UIZJ㒤w>IM{KD-*DQdVŏbyvx& x'ݱ1(Hy(}\{?]]#9\f)))z~v000006_(.ҹNK- O8ԴP? PɀX?@ۺS(DAPPz4A]dF(D)9o'УJ\IMdX{40癅iazFX3#l?#TP 0)"H}7R =iX NO|(8G)ޞS"a)*0EigDɍ,-laDplwx)^Fl+54. e Ԡ[jlv546w'3gbcyQyz gg,)BƦmM^҂K6P4/Q4߾r<7ðLZqQ6H8$(]kLF?J̟[d: +.DxaM+Vj>?C-@(f+V/X=b?z5ȣgb EFfZqʹ܄ܒ hE߁#=.s# yl9* _A\UĿ5ՉdFf\U7uCG}JWׅn0R)p|&˴9},Ȑtz~Un:C5@KnLNC.J>1 ,nB3F[A2RPFh2BU&-POԩfR:FJ'|^tJ% !J2/i0]PPLhX>5Jk j(&|-<lU PLnU7P3SokBUWXOo )}LDRXa"C, -D?(nM^ĥ3E]DU뷺~Q+5<+^/B3"^b>np \zRa k)㣮+ɡ, 7qF85Eaƽᢴ"*n2qBlJ@. _}ga |2@&D͑eAf6*͉$jfDGb` g)́h:vQC9tq`\tS|yQgR"EG2؀YrALJy0 Ɍq|hVrXN)'dtoZ9O\nu~υ5\4M4=4'F]X+cE3hA3{?hv?gl,[e!,RR '+K5~9[KH2B5UFb+zDWN[DL%&QHTeqoυ'-:Eϯ()/]3,;X͔Gͅ!> tǝAp-S3eM@.#D,T8fS][㙬,5[ Vs&&~,?GؾM:|_XD/'!KvRbkˋ+V9f,V?&~B8C$#̙a>M,# Q\qςvik:!6!tsDI;\LLv((fꕧkQTl]I1T}84=A&>yMs4P;UΠ(`.}oR~q_ vS;ߙ$8<,|wZNeEO}p5"+ibQf)OM=~S]? A/I SNDQяg!(9&#uגd_d@/%q/-&^o.~>J=e&oه@ W8=gi8؄6`x( n\XMyNk(s`_kJ:-O#=|Ho%(o|/J@>~mpj An~i)%E 7Wv``_bo4e_ xK?<$2 "/ HM_% s9W% se_VKuHrO6v?=~q0?.B'\ A|`l.Hs_h[acl"P[i4<#Tڀ8g]S' 1Kp$G\9i k A>Ko+iTԤJP/_4U 7ۈ8'.7|L/σZrG8ώ`']=B `?\#q#<]kr!cۈ4\b?|==62/!<ڐA~6"|Ǖ6i,+j-Gi*g <<_H'SQxx^Vh A71zX{.d'K "O=վVQ2P/z: /K e_.Bp xv|`Xs ~Aۖg"J?xP &r32|=v ʗ<} $C<'8>=J)=ԼQĨX"pѭ>%QqDi^\МY>.2{6Y<ߍZ3u[2QfI;`J뿛:>lK,QJ)ˆ׸qLaLQr?u$y KA<IXv!Pe?Ջ2t&kK7%&G=%}5+<@ux2U{eݎ;eyE&ؽ9ݣ42Z ėa>^PҒ Ui _? él!|jCM_ .9'pZ9lR[?'J?hU}~?=ٗ^W_~A> GoZcۙs=ɮ4%Fz~r&`_њj\t$ErVq K5^^+;D961mtm3 x-D(gSTp*;_`堟ψ!yNo{5U_|/!!!!!!!!!!!!!!!!1a[golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/ntriple_tests.tar.gz000066400000000000000000000142641450372207100270330ustar00rootroot00000000000000R]vyy4$ek]g<?2*%Aw(RCBc;mSA{}sz#Mi\@h$( 5xv ^ϋoZ{pfП6-5hi@C2rh{3=ŸZߙLCDzKukN-X0pzFz7KM]Q[8qMy'cZ ^5_MP (:tN*NW~?@EE=?v Dft=|{$xzͦR/oT,X$< Saӿ{iqכ J=^7u)_b^qGM#Q]z!t=b v.>D5,hje`"v5,wl:'iuU)Xь>TS}6S}v>>B)TB)TB)TB)TK{yHTB%+OWIs?}43M(q_9XG?G/goLfP`oߪ7_)X>?|777 ?~^8aCܞ"dMoz3._6˝sz޻ήmd\Ҹ66O]84;c߯W5Uv<$4*NZ]ѯO'8e~z^ƙ>wwFayifн Qi YGTA7M?t=DA$6mL ,]YC>7m4Oir⠦9hIk2% A}F83## ~Dߍ-wc΀ C^6%ǔqeI5Ye}nȞЭg2v3n>R^J>aGó>:9?۴M-p~|ҘuNsJϝSr}s甼gT[JԍY/*0Ⓓ{бyS[ Ąs숴#R\ p%59퇱я$)\t 1]c Hre D2=yz:Isi"v{S6U@[4^;0hіQI Z pT'St J(BMc{GfU1V1~e[VrYYg-%pm? Mv˴%BP ''' *#,flID>nv߄|zi K".+[=*4j`j +wiiFwP3Ҿ+ ?'(nP3&:+¾h. ?'#HP2%g2_I\ i)˴WI\ Viy$Up@VsiL#m`8 [PKˈDӋQ8"2"2zĸdsdT) VT"S+o]#BˣBTôA ϯKF)[ehrPҠm@{Hx,'3g Η>c`i*#2AR-h]fubVfBpq1|a$ |o`_+J/&mFh1K`n"A`fMUKA>K+/_o&֥XK0_rd?`(Qap_槍OqGj_ [!/r`?._dFER/io=>'e!H`K io~d7R_!#)fH^j?_/$io}lR_G0^.$* S ?yv*W ??(HzSQ?NZ`?qGSR\A<  L}/_'Й|( /Q //|K f`_y?9_ |+_n /{0/rσ`$=Ahr_)/B˿Mہ7.o$`_/.&w"g4$)+{9W 2tʷ OGڒ6`_BT]/wb%ȵV% /( ׬{|_W g^Q5ҿ\.//ZqG5g_c816{J#_h`R D?4"KA2_I*\U 6'St HK "?|kߊ*W6}g26R`66";ǍwMK?vly:Փu Y'Փ?[rH\U r/kEߥ`9?4kEi+/KgV-zғ?_9G5Gc85oo`;؞"s6_g3"C&!!qc۱v^tlX)]?M{nFq8CNn|M\{z&~T =,pJ"aytߓck  3qU2pOpdXKÅ1X4s!\\h pMq:|?`nJz])Z]JT|*8"%t3vƐv96qdCg[gMgibQ0@F|hLDž3s0y(u:@mc*![z\`Suf3C Yh)€ Ls\st ^>ώNNmL+ EpQ0_ @x8r8Er<諫3 F#8q/3/Ԋgs\y=ֳ otxfN'Jse?/)k=*.D3\Q\W0T 90=Lq͇+( L[qsY[pDp9<5wck{xeɠV퓖w=9 S{]@6x`H{q2⋯P|‘ϛ؉k2N䀩ydƲj~\DXG _.I\,I3# 'sZjab,jX.ͷf w|=#a~BffxbIǮ`kL+񻟢,} 6_@T,ܧv1}Umgc {Tgolang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/template.haml000066400000000000000000000142431450372207100254600ustar00rootroot00000000000000!!! 5 %html{lang: :en, prefix: "rdfn: http://json-ld.github.io/normalization/test-vocab# mf: http://www.w3.org/2001/sw/DataAccess/tests/test-manifest# rdft: http://www.w3.org/ns/rdftest#"} %head %meta{"http-equiv" => "Content-Type", content: "text/html;charset=utf-8"} %meta{name: "viewport", content: "width=device-width, initial-scale=1.0"} %link{rel: "stylesheet", type: "text/css", href: "https://www.w3.org/StyleSheets/TR/base"} :css body: {bacground-image: none;} dl.test-detail, dl.test-options { padding: 0.5em; } dl.test-detail>dt, dl.test-options>dt { float: left; clear: left; text-align: right; font-weight: bold; color: green; } dl.test-detail>dt:after, dl.test-options>dt:after {content: ": "} dl.test-detail>dd, dl.test-options>dd { margin: 0 0 0 110px; padding: 0 0 0.5em 0; } dl.test-description>dt {margin-top: 2em;} dd {margin-left: 0;} dd code {display: inline;} footer {text-align: center;} %title = man['label'] :css em.rfc2119 { text-transform: lowercase; font-variant: small-caps; font-style: normal; color: #900; } a.testlink { color: inherit; text-decoration: none; } a.testlink:hover { text-decoration: underline; } %body{resource: man['id'], typeof: man['type']} %p %a{href: "http://www.w3.org/"} %img{src: "http://www.w3.org/Icons/w3c_home", alt: "W3C", height: 48, width: 72} %h1{property: "rdfs:label"}<= man['label'] %p{property: "rdfs:comment"}<= man['comment'] :markdown This page describes RDF Dataset Normalization tests for URGNA2012 and URDNA2015 profiles. These tests are also described in [JSON-LD](manifest.jsonld) and [Turtle](manifest.ttl) formats for convenience. The manifest vocabulary is described in the [RDF Dataset Normalization Test Vocabulary](vocab.html) ([JSON-LD](vocab.jsonld), [Turtle](vocab.ttl)) and is based on the [RDF Test Vocabulary](http://www.w3.org/TR/2014/NOTE-rdf11-testcases-20140225/). ## General instructions for running the RDF Dataset Normalization Test suites FIXME ## Contributing Tests The test manifests and entries are built automatically from [manifest.csv](manifest.csv) using [mk_manifest.rb](mk_manifest.rb), where each row defines a combination of RDF, JSON and Validation tests for the same _action_ and implicit files. Tests may be contributed via pull request to [https://github.com/json-ld/normalization](https://github.com/json-ld/normalization) with suitable changes to the [manifest.csv](manifest.csv) and necessary _action_ and _result_ files. Tests will also be considered if a contribution is sent to [public-credentials@w3.org](mailto:public-credentials@w3.org). ## Distribution Distributed under both the [W3C Test Suite License](http://www.w3.org/Consortium/Legal/2008/04-testsuite-license) and the [W3C 3-clause BSD License](http://www.w3.org/Consortium/Legal/2008/03-bsd-license). To contribute to a W3C Test Suite, see the [policies and contribution forms](http://www.w3.org/2004/10/27-testcases). ## Disclaimer UNDER BOTH MUTUALLY EXCLUSIVE LICENSES, THIS DOCUMENT AND ALL DOCUMENTS, TESTS AND SOFTWARE THAT LINK THIS STATEMENT ARE PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF. %section.contents %h2="Contents" %ol - manifests.each do |id, man| %li %a{href: "##{id}"}<=man['label'] = "– #{man['entries'].count} entries" - manifests.each do |id, man| %section{id: id, property: "mf:entry", inlist: true, resource: id, typeof: man['type']} %h2<= "#{man['label']} (#{man['entries'].count} entries)" %p{property: "rdfs:comment"}<= man['comment'] %p - if id =~/urgna2012/ Instructions specific to running URGNA2012 tests. - elsif id =~ /urdna2016/ Instructions specific to running URDNA2015 tests. %dl.test-description - man['entries'].each do |test| %dt{id: test['id']} %a.testlink{href: "##{test['id']}"} = "#{test['id']}:" %span{about: test['id'], property: "mf:name"}<~test['name'] %dd{property: "mf:entry", inlist: true, resource: test['id'], typeof: test['type']} %div{property: "rdfs:comment"} :markdown #{test['comment'].to_s.gsub(/(MUST|MUST NOT|SHOULD|SHOULD NOT|MAY)/, '\\1')} %dl.test-detail %dt="type" %dd<~test['type'] %dt="approval" %dd{property: "mf:approval", resource: test['approval']}<~test['approval'] - if test['action'] %dt="action" %dd %a{property: "mf:action", href: test['action']}<~test['action'] - if test['result'] %dt="result" %dd %a{property: "mf:result", href: test['result']}<~test['result'] %footer :markdown [Copyright ©](http://www.w3.org/Consortium/Legal/ipr-notice#Copyright) 2015 [W3C](http://www.w3.org/)® ([MIT](http://www.csail.mit.edu/), [ERCIM](http://www.ercim.org/), [Keio](http://www.keio.ac.jp/), [Beihang](http://ev.buaa.edu.cn/)). W3C® [liability](http://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer), [trademark](http://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks) and [document use](http://www.w3.org/Consortium/Legal/copyright-documents) rules apply. golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test001-in.nq000066400000000000000000000000001450372207100251300ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test001-urdna2015.nq000066400000000000000000000000001450372207100261430ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test001-urgna2012.nq000066400000000000000000000000001450372207100261430ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test002-in.nq000066400000000000000000000001451450372207100251430ustar00rootroot00000000000000 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test002-urdna2015.nq000066400000000000000000000001451450372207100261560ustar00rootroot00000000000000 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test002-urgna2012.nq000066400000000000000000000001451450372207100261560ustar00rootroot00000000000000 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test003-in.nq000066400000000000000000000001301450372207100251360ustar00rootroot00000000000000_:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test003-urdna2015.nq000066400000000000000000000001331450372207100261540ustar00rootroot00000000000000_:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test003-urgna2012.nq000066400000000000000000000001331450372207100261540ustar00rootroot00000000000000_:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test004-in.nq000066400000000000000000000002421450372207100251430ustar00rootroot00000000000000_:b0 . _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test004-urdna2015.nq000066400000000000000000000002501450372207100261550ustar00rootroot00000000000000_:c14n0 . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test004-urgna2012.nq000066400000000000000000000002501450372207100261550ustar00rootroot00000000000000_:c14n0 . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test005-in.nq000066400000000000000000000004271450372207100251510ustar00rootroot00000000000000 . _:b0 . _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test005-urdna2015.nq000066400000000000000000000004351450372207100261630ustar00rootroot00000000000000 _:c14n0 . . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test005-urgna2012.nq000066400000000000000000000004351450372207100261630ustar00rootroot00000000000000 _:c14n0 . . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test006-in.nq000066400000000000000000000003521450372207100251470ustar00rootroot00000000000000 . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test006-urdna2015.nq000066400000000000000000000003521450372207100261620ustar00rootroot00000000000000 . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test006-urgna2012.nq000066400000000000000000000003521450372207100261620ustar00rootroot00000000000000 . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test007-in.nq000066400000000000000000000003271450372207100251520ustar00rootroot00000000000000 . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test007-urdna2015.nq000066400000000000000000000003271450372207100261650ustar00rootroot00000000000000 . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test007-urgna2012.nq000066400000000000000000000003271450372207100261650ustar00rootroot00000000000000 . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test008-in.nq000066400000000000000000000010531450372207100251500ustar00rootroot00000000000000 . . "Writer" . "My Book" . "Fun" . "Chapter One" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test008-urdna2015.nq000066400000000000000000000010531450372207100261630ustar00rootroot00000000000000 . "Writer" . "My Book" . "Fun" . "Chapter One" . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test008-urgna2012.nq000066400000000000000000000010531450372207100261630ustar00rootroot00000000000000 . "Writer" . "My Book" . "Fun" . "Chapter One" . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test009-in.nq000066400000000000000000000014441450372207100251550ustar00rootroot00000000000000 "Fun" . "Chapter One" . . "Jane" . "John" . . . "Writer" . "My Book" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test009-urdna2015.nq000066400000000000000000000014441450372207100261700ustar00rootroot00000000000000 . "Writer" . "My Book" . "Fun" . "Chapter One" . . "Jane" . "John" . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test009-urgna2012.nq000066400000000000000000000014441450372207100261700ustar00rootroot00000000000000 . "Writer" . "My Book" . "Fun" . "Chapter One" . . "Jane" . "John" . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test010-in.nq000066400000000000000000000002221450372207100251360ustar00rootroot00000000000000 "2011-01-25T00:00:00+00:00"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test010-urdna2015.nq000066400000000000000000000002221450372207100261510ustar00rootroot00000000000000 "2011-01-25T00:00:00+00:00"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test010-urgna2012.nq000066400000000000000000000002221450372207100261510ustar00rootroot00000000000000 "2011-01-25T00:00:00+00:00"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test011-in.nq000066400000000000000000000002151450372207100251410ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test011-urdna2015.nq000066400000000000000000000002151450372207100261540ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test011-urgna2012.nq000066400000000000000000000002151450372207100261540ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test012-in.nq000066400000000000000000000002101450372207100251350ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test012-urdna2015.nq000066400000000000000000000002101450372207100261500ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test012-urgna2012.nq000066400000000000000000000002101450372207100261500ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test013-in.nq000066400000000000000000000005341450372207100251470ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test013-urdna2015.nq000066400000000000000000000005341450372207100261620ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test013-urgna2012.nq000066400000000000000000000005341450372207100261620ustar00rootroot00000000000000 "2011-01-25T00:00:00Z"^^ . . . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test014-in.nq000066400000000000000000000005161450372207100251500ustar00rootroot00000000000000 "true"^^ . "1.23E0"^^ . "123"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test014-urdna2015.nq000066400000000000000000000005161450372207100261630ustar00rootroot00000000000000 "true"^^ . "1.23E0"^^ . "123"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test014-urgna2012.nq000066400000000000000000000005161450372207100261630ustar00rootroot00000000000000 "true"^^ . "1.23E0"^^ . "123"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test015-in.nq000066400000000000000000000000001450372207100251350ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test015-urdna2015.nq000066400000000000000000000000001450372207100261500ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test015-urgna2012.nq000066400000000000000000000000001450372207100261500ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test016-in.nq000066400000000000000000000002761450372207100251550ustar00rootroot00000000000000 _:b0 . _:b0 . _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test016-urdna2015.nq000066400000000000000000000003071450372207100261630ustar00rootroot00000000000000 _:c14n0 . _:c14n0 . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test016-urgna2012.nq000066400000000000000000000003071450372207100261630ustar00rootroot00000000000000 _:c14n0 . _:c14n0 . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test017-in.nq000066400000000000000000000001741450372207100251530ustar00rootroot00000000000000 _:b0 . _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test017-urdna2015.nq000066400000000000000000000002021450372207100261560ustar00rootroot00000000000000 _:c14n0 . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test017-urgna2012.nq000066400000000000000000000002021450372207100261560ustar00rootroot00000000000000 _:c14n0 . _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test018-in.nq000066400000000000000000000000541450372207100251510ustar00rootroot00000000000000_:b0 _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test018-urdna2015.nq000066400000000000000000000000621450372207100261630ustar00rootroot00000000000000_:c14n0 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test018-urgna2012.nq000066400000000000000000000000621450372207100261630ustar00rootroot00000000000000_:c14n0 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test019-in.nq000066400000000000000000000001301450372207100251450ustar00rootroot00000000000000_:b0 _:b0 . _:b1 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test019-urdna2015.nq000066400000000000000000000001441450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n0 . _:c14n1 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test019-urgna2012.nq000066400000000000000000000001441450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n0 . _:c14n1 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test020-in.nq000066400000000000000000000003401450372207100251400ustar00rootroot00000000000000 _:b0 . _:b1 . _:b0 _:b2 . _:b1 _:b2 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test020-urdna2015.nq000066400000000000000000000003621450372207100261570ustar00rootroot00000000000000 _:c14n2 . _:c14n0 . _:c14n0 _:c14n1 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test020-urgna2012.nq000066400000000000000000000003621450372207100261570ustar00rootroot00000000000000 _:c14n2 . _:c14n1 . _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test021-in.nq000066400000000000000000000001301450372207100251360ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test021-urdna2015.nq000066400000000000000000000001441450372207100261560ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test021-urgna2012.nq000066400000000000000000000001441450372207100261560ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test022-in.nq000066400000000000000000000002601450372207100251430ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b1 . _:b1 _:b0 . _:b1 _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test022-urdna2015.nq000066400000000000000000000003101450372207100261520ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test022-urgna2012.nq000066400000000000000000000003101450372207100261520ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test023-in.nq000066400000000000000000000002041450372207100251420ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b2 . _:b2 _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test023-urdna2015.nq000066400000000000000000000002261450372207100261610ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 _:c14n2 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test023-urgna2012.nq000066400000000000000000000002261450372207100261610ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n1 _:c14n0 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test024-in.nq000066400000000000000000000004101450372207100251420ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b1 _:b2 . _:b1 _:b0 . _:b2 _:b0 . _:b2 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test024-urdna2015.nq000066400000000000000000000004541450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n2 . _:c14n2 _:c14n1 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test024-urgna2012.nq000066400000000000000000000004541450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n2 . _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test025-in.nq000066400000000000000000000004101450372207100251430ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b1 _:b2 . _:b1 _:b0 . _:b2 _:b0 . _:b2 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test025-urdna2015.nq000066400000000000000000000004541450372207100261660ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n2 . _:c14n2 _:c14n1 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test025-urgna2012.nq000066400000000000000000000004541450372207100261660ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n2 . _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test026-in.nq000066400000000000000000000004101450372207100251440ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b1 _:b2 . _:b1 _:b0 . _:b2 _:b0 . _:b2 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test026-urdna2015.nq000066400000000000000000000004541450372207100261670ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n2 . _:c14n2 _:c14n1 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test026-urgna2012.nq000066400000000000000000000004541450372207100261670ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n2 . _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test027-in.nq000066400000000000000000000004101450372207100251450ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b1 _:b2 . _:b1 _:b0 . _:b2 _:b0 . _:b2 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test027-urdna2015.nq000066400000000000000000000004541450372207100261700ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n2 . _:c14n2 _:c14n1 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test027-urgna2012.nq000066400000000000000000000004541450372207100261700ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n2 . _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test028-in.nq000066400000000000000000000004101450372207100251460ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b1 _:b2 . _:b1 _:b0 . _:b2 _:b0 . _:b2 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test028-urdna2015.nq000066400000000000000000000004541450372207100261710ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n2 . _:c14n2 _:c14n1 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test028-urgna2012.nq000066400000000000000000000004541450372207100261710ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n2 . _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test029-in.nq000066400000000000000000000004101450372207100251470ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b1 _:b2 . _:b1 _:b0 . _:b2 _:b0 . _:b2 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test029-urdna2015.nq000066400000000000000000000004541450372207100261720ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n0 _:c14n1 . _:c14n1 _:c14n0 . _:c14n1 _:c14n2 . _:c14n2 _:c14n1 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test029-urgna2012.nq000066400000000000000000000004541450372207100261720ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n2 . _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . _:c14n2 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test030-in.nq000066400000000000000000000005201450372207100251410ustar00rootroot00000000000000 _:b0 . _:b1 . _:b2 . _:b0 _:b1 . _:b1 _:b2 . _:b2 _:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test030-urdna2015.nq000066400000000000000000000005531450372207100261620ustar00rootroot00000000000000 _:c14n0 . _:c14n1 . _:c14n2 . _:c14n0 _:c14n1 . _:c14n1 _:c14n2 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test030-urgna2012.nq000066400000000000000000000005531450372207100261620ustar00rootroot00000000000000 _:c14n1 . _:c14n2 . _:c14n0 . _:c14n0 _:c14n1 . _:c14n1 _:c14n2 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test031-in.nq000066400000000000000000000001301450372207100251370ustar00rootroot00000000000000_:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test031-urdna2015.nq000066400000000000000000000001331450372207100261550ustar00rootroot00000000000000_:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test031-urgna2012.nq000066400000000000000000000001331450372207100261550ustar00rootroot00000000000000_:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test032-in.nq000066400000000000000000000001301450372207100251400ustar00rootroot00000000000000_:b0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test032-urdna2015.nq000066400000000000000000000001331450372207100261560ustar00rootroot00000000000000_:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test032-urgna2012.nq000066400000000000000000000001331450372207100261560ustar00rootroot00000000000000_:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test033-in.nq000066400000000000000000000001301450372207100251410ustar00rootroot00000000000000_:b0 _:b1 . _:b2 _:b3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test033-urdna2015.nq000066400000000000000000000001441450372207100261610ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n2 _:c14n3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test033-urgna2012.nq000066400000000000000000000001441450372207100261610ustar00rootroot00000000000000_:c14n1 _:c14n0 . _:c14n3 _:c14n2 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test034-in.nq000066400000000000000000000001301450372207100251420ustar00rootroot00000000000000_:b0 _:b1 . _:b2 _:b3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test034-urdna2015.nq000066400000000000000000000001441450372207100261620ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n2 _:c14n3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test034-urgna2012.nq000066400000000000000000000001441450372207100261620ustar00rootroot00000000000000_:c14n1 _:c14n0 . _:c14n3 _:c14n2 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test035-in.nq000066400000000000000000000002521450372207100251500ustar00rootroot00000000000000_:b0 _:b1 . _:b1 "Foo" . _:b2 _:b3 . _:b3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test035-urdna2015.nq000066400000000000000000000002741450372207100261670ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 "Foo" . _:c14n2 _:c14n3 . _:c14n3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test035-urgna2012.nq000066400000000000000000000002741450372207100261670ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 "Foo" . _:c14n2 _:c14n3 . _:c14n3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test036-in.nq000066400000000000000000000002521450372207100251510ustar00rootroot00000000000000_:b0 _:b1 . _:b1 "Foo" . _:b2 _:b3 . _:b3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test036-urdna2015.nq000066400000000000000000000002741450372207100261700ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 "Foo" . _:c14n2 _:c14n3 . _:c14n3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test036-urgna2012.nq000066400000000000000000000002741450372207100261700ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 "Foo" . _:c14n2 _:c14n3 . _:c14n3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test037-in.nq000066400000000000000000000002521450372207100251520ustar00rootroot00000000000000_:b0 _:b1 . _:b1 "Foo" . _:b2 _:b3 . _:b3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test037-urdna2015.nq000066400000000000000000000002741450372207100261710ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 "Foo" . _:c14n2 _:c14n3 . _:c14n3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test037-urgna2012.nq000066400000000000000000000002741450372207100261710ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 "Foo" . _:c14n2 _:c14n3 . _:c14n3 "Foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test038-in.nq000066400000000000000000000001761450372207100251600ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b1 _:b3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test038-urdna2015.nq000066400000000000000000000002201450372207100261610ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n1 _:c14n0 . _:c14n1 _:c14n3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test038-urgna2012.nq000066400000000000000000000002201450372207100261610ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test039-in.nq000066400000000000000000000001761450372207100251610ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b2 _:b3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test039-urdna2015.nq000066400000000000000000000002201450372207100261620ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n1 _:c14n0 . _:c14n1 _:c14n3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test039-urgna2012.nq000066400000000000000000000002201450372207100261620ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n1 _:c14n3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test040-in.nq000066400000000000000000000002501450372207100251420ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b2 . _:b3 _:b4 . _:b4 _:b5 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test040-urdna2015.nq000066400000000000000000000003001450372207100261510ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 _:c14n2 . _:c14n3 _:c14n4 . _:c14n4 _:c14n5 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test040-urgna2012.nq000066400000000000000000000003001450372207100261510ustar00rootroot00000000000000_:c14n1 _:c14n0 . _:c14n2 _:c14n1 . _:c14n4 _:c14n3 . _:c14n5 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test041-in.nq000066400000000000000000000002501450372207100251430ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b2 . _:b3 _:b4 . _:b4 _:b5 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test041-urdna2015.nq000066400000000000000000000003001450372207100261520ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 _:c14n2 . _:c14n3 _:c14n4 . _:c14n4 _:c14n5 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test041-urgna2012.nq000066400000000000000000000003001450372207100261520ustar00rootroot00000000000000_:c14n1 _:c14n0 . _:c14n2 _:c14n1 . _:c14n4 _:c14n3 . _:c14n5 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test042-in.nq000066400000000000000000000002501450372207100251440ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b2 . _:b3 _:b4 . _:b4 _:b5 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test042-urdna2015.nq000066400000000000000000000003001450372207100261530ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n1 _:c14n2 . _:c14n3 _:c14n4 . _:c14n4 _:c14n5 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test042-urgna2012.nq000066400000000000000000000003001450372207100261530ustar00rootroot00000000000000_:c14n1 _:c14n0 . _:c14n2 _:c14n1 . _:c14n4 _:c14n3 . _:c14n5 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test043-in.nq000066400000000000000000000001061450372207100251450ustar00rootroot00000000000000 "test"@en . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test043-urdna2015.nq000066400000000000000000000001061450372207100261600ustar00rootroot00000000000000 "test"@en . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test043-urgna2012.nq000066400000000000000000000001061450372207100261600ustar00rootroot00000000000000 "test"@en . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test044-in.nq000066400000000000000000000027201450372207100251520ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b0 _:b3 . _:b1 _:b0 . _:b1 _:b3 . _:b1 _:b4 . _:b2 _:b0 . _:b2 _:b4 . _:b2 _:b5 . _:b3 _:b0 . _:b3 _:b1 . _:b3 _:b5 . _:b4 _:b1 . _:b4 _:b2 . _:b4 _:b5 . _:b5 _:b3 . _:b5 _:b2 . _:b5 _:b4 . _:b6 _:b7 . _:b6 _:b8 . _:b6 _:b9 . _:b7 _:b6 . _:b7 _:b10 . _:b7 _:b11 . _:b8 _:b6 . _:b8 _:b10 . _:b8 _:b11 . _:b9 _:b6 . _:b9 _:b10 . _:b9 _:b11 . _:b10 _:b7 . _:b10 _:b8 . _:b10 _:b9 . _:b11 _:b7 . _:b11 _:b8 . _:b11 _:b9 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test044-urdna2015.nq000066400000000000000000000032501450372207100261640ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n0 _:c14n3 . _:c14n1 _:c14n0 . _:c14n1 _:c14n4 . _:c14n1 _:c14n5 . _:c14n10 _:c14n7 . _:c14n10 _:c14n8 . _:c14n10 _:c14n9 . _:c14n11 _:c14n7 . _:c14n11 _:c14n8 . _:c14n11 _:c14n9 . _:c14n2 _:c14n0 . _:c14n2 _:c14n3 . _:c14n2 _:c14n5 . _:c14n3 _:c14n0 . _:c14n3 _:c14n2 . _:c14n3 _:c14n4 . _:c14n4 _:c14n1 . _:c14n4 _:c14n3 . _:c14n4 _:c14n5 . _:c14n5 _:c14n1 . _:c14n5 _:c14n2 . _:c14n5 _:c14n4 . _:c14n6 _:c14n7 . _:c14n6 _:c14n8 . _:c14n6 _:c14n9 . _:c14n7 _:c14n10 . _:c14n7 _:c14n11 . _:c14n7 _:c14n6 . _:c14n8 _:c14n10 . _:c14n8 _:c14n11 . _:c14n8 _:c14n6 . _:c14n9 _:c14n10 . _:c14n9 _:c14n11 . _:c14n9 _:c14n6 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test044-urgna2012.nq000066400000000000000000000032501450372207100261640ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n0 _:c14n3 . _:c14n1 _:c14n0 . _:c14n1 _:c14n4 . _:c14n1 _:c14n5 . _:c14n10 _:c14n11 . _:c14n10 _:c14n7 . _:c14n10 _:c14n9 . _:c14n11 _:c14n10 . _:c14n11 _:c14n8 . _:c14n11 _:c14n9 . _:c14n2 _:c14n0 . _:c14n2 _:c14n4 . _:c14n2 _:c14n5 . _:c14n3 _:c14n0 . _:c14n3 _:c14n4 . _:c14n3 _:c14n5 . _:c14n4 _:c14n1 . _:c14n4 _:c14n2 . _:c14n4 _:c14n3 . _:c14n5 _:c14n1 . _:c14n5 _:c14n2 . _:c14n5 _:c14n3 . _:c14n6 _:c14n7 . _:c14n6 _:c14n8 . _:c14n6 _:c14n9 . _:c14n7 _:c14n10 . _:c14n7 _:c14n6 . _:c14n7 _:c14n8 . _:c14n8 _:c14n11 . _:c14n8 _:c14n6 . _:c14n8 _:c14n7 . _:c14n9 _:c14n10 . _:c14n9 _:c14n11 . _:c14n9 _:c14n6 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test045-in.nq000066400000000000000000000027201450372207100251530ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b0 _:b3 . _:b1 _:b0 . _:b1 _:b4 . _:b1 _:b5 . _:b2 _:b0 . _:b2 _:b4 . _:b2 _:b5 . _:b3 _:b0 . _:b3 _:b4 . _:b3 _:b5 . _:b4 _:b1 . _:b4 _:b2 . _:b4 _:b3 . _:b5 _:b1 . _:b5 _:b2 . _:b5 _:b3 . _:b6 _:b7 . _:b6 _:b8 . _:b6 _:b9 . _:b7 _:b6 . _:b7 _:b9 . _:b7 _:b10 . _:b8 _:b6 . _:b8 _:b10 . _:b8 _:b11 . _:b9 _:b6 . _:b9 _:b7 . _:b9 _:b11 . _:b10 _:b7 . _:b10 _:b8 . _:b10 _:b11 . _:b11 _:b9 . _:b11 _:b8 . _:b11 _:b10 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test045-urdna2015.nq000066400000000000000000000032501450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n0 _:c14n3 . _:c14n1 _:c14n0 . _:c14n1 _:c14n4 . _:c14n1 _:c14n5 . _:c14n10 _:c14n7 . _:c14n10 _:c14n8 . _:c14n10 _:c14n9 . _:c14n11 _:c14n7 . _:c14n11 _:c14n8 . _:c14n11 _:c14n9 . _:c14n2 _:c14n0 . _:c14n2 _:c14n3 . _:c14n2 _:c14n5 . _:c14n3 _:c14n0 . _:c14n3 _:c14n2 . _:c14n3 _:c14n4 . _:c14n4 _:c14n1 . _:c14n4 _:c14n3 . _:c14n4 _:c14n5 . _:c14n5 _:c14n1 . _:c14n5 _:c14n2 . _:c14n5 _:c14n4 . _:c14n6 _:c14n7 . _:c14n6 _:c14n8 . _:c14n6 _:c14n9 . _:c14n7 _:c14n10 . _:c14n7 _:c14n11 . _:c14n7 _:c14n6 . _:c14n8 _:c14n10 . _:c14n8 _:c14n11 . _:c14n8 _:c14n6 . _:c14n9 _:c14n10 . _:c14n9 _:c14n11 . _:c14n9 _:c14n6 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test045-urgna2012.nq000066400000000000000000000032501450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n0 _:c14n3 . _:c14n1 _:c14n0 . _:c14n1 _:c14n4 . _:c14n1 _:c14n5 . _:c14n10 _:c14n11 . _:c14n10 _:c14n7 . _:c14n10 _:c14n9 . _:c14n11 _:c14n10 . _:c14n11 _:c14n8 . _:c14n11 _:c14n9 . _:c14n2 _:c14n0 . _:c14n2 _:c14n4 . _:c14n2 _:c14n5 . _:c14n3 _:c14n0 . _:c14n3 _:c14n4 . _:c14n3 _:c14n5 . _:c14n4 _:c14n1 . _:c14n4 _:c14n2 . _:c14n4 _:c14n3 . _:c14n5 _:c14n1 . _:c14n5 _:c14n2 . _:c14n5 _:c14n3 . _:c14n6 _:c14n7 . _:c14n6 _:c14n8 . _:c14n6 _:c14n9 . _:c14n7 _:c14n10 . _:c14n7 _:c14n6 . _:c14n7 _:c14n8 . _:c14n8 _:c14n11 . _:c14n8 _:c14n6 . _:c14n8 _:c14n7 . _:c14n9 _:c14n10 . _:c14n9 _:c14n11 . _:c14n9 _:c14n6 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test046-in.nq000066400000000000000000000027201450372207100251540ustar00rootroot00000000000000_:b0 _:b1 . _:b0 _:b2 . _:b0 _:b3 . _:b1 _:b0 . _:b1 _:b9 . _:b1 _:b8 . _:b2 _:b3 . _:b2 _:b8 . _:b2 _:b0 . _:b3 _:b0 . _:b3 _:b2 . _:b3 _:b9 . _:b4 _:b5 . _:b4 _:b6 . _:b4 _:b7 . _:b5 _:b10 . _:b5 _:b4 . _:b5 _:b11 . _:b6 _:b4 . _:b6 _:b11 . _:b6 _:b10 . _:b7 _:b10 . _:b7 _:b11 . _:b7 _:b4 . _:b8 _:b1 . _:b8 _:b2 . _:b8 _:b9 . _:b9 _:b8 . _:b9 _:b3 . _:b9 _:b1 . _:b10 _:b6 . _:b10 _:b7 . _:b10 _:b5 . _:b11 _:b5 . _:b11 _:b6 . _:b11 _:b7 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test046-urdna2015.nq000066400000000000000000000032501450372207100261660ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n0 _:c14n3 . _:c14n1 _:c14n0 . _:c14n1 _:c14n4 . _:c14n1 _:c14n5 . _:c14n10 _:c14n7 . _:c14n10 _:c14n8 . _:c14n10 _:c14n9 . _:c14n11 _:c14n7 . _:c14n11 _:c14n8 . _:c14n11 _:c14n9 . _:c14n2 _:c14n0 . _:c14n2 _:c14n3 . _:c14n2 _:c14n5 . _:c14n3 _:c14n0 . _:c14n3 _:c14n2 . _:c14n3 _:c14n4 . _:c14n4 _:c14n1 . _:c14n4 _:c14n3 . _:c14n4 _:c14n5 . _:c14n5 _:c14n1 . _:c14n5 _:c14n2 . _:c14n5 _:c14n4 . _:c14n6 _:c14n7 . _:c14n6 _:c14n8 . _:c14n6 _:c14n9 . _:c14n7 _:c14n10 . _:c14n7 _:c14n11 . _:c14n7 _:c14n6 . _:c14n8 _:c14n10 . _:c14n8 _:c14n11 . _:c14n8 _:c14n6 . _:c14n9 _:c14n10 . _:c14n9 _:c14n11 . _:c14n9 _:c14n6 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test046-urgna2012.nq000066400000000000000000000032501450372207100261660ustar00rootroot00000000000000_:c14n0 _:c14n1 . _:c14n0 _:c14n2 . _:c14n0 _:c14n3 . _:c14n1 _:c14n0 . _:c14n1 _:c14n4 . _:c14n1 _:c14n5 . _:c14n10 _:c14n11 . _:c14n10 _:c14n7 . _:c14n10 _:c14n9 . _:c14n11 _:c14n10 . _:c14n11 _:c14n8 . _:c14n11 _:c14n9 . _:c14n2 _:c14n0 . _:c14n2 _:c14n4 . _:c14n2 _:c14n5 . _:c14n3 _:c14n0 . _:c14n3 _:c14n4 . _:c14n3 _:c14n5 . _:c14n4 _:c14n1 . _:c14n4 _:c14n2 . _:c14n4 _:c14n3 . _:c14n5 _:c14n1 . _:c14n5 _:c14n2 . _:c14n5 _:c14n3 . _:c14n6 _:c14n7 . _:c14n6 _:c14n8 . _:c14n6 _:c14n9 . _:c14n7 _:c14n10 . _:c14n7 _:c14n6 . _:c14n7 _:c14n8 . _:c14n8 _:c14n11 . _:c14n8 _:c14n6 . _:c14n8 _:c14n7 . _:c14n9 _:c14n10 . _:c14n9 _:c14n11 . _:c14n9 _:c14n6 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test047-in.nq000066400000000000000000000005201450372207100251510ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b2 . _:b2 "foo1" . _:b2 "foo2" . _:b3 _:b4 . _:b4 _:b5 . _:b5 "bar1" . _:b5 "bar2" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test047-urdna2015.nq000066400000000000000000000005641450372207100261740ustar00rootroot00000000000000_:c14n0 "bar1" . _:c14n0 "bar2" . _:c14n1 "foo1" . _:c14n1 "foo2" . _:c14n2 _:c14n0 . _:c14n3 _:c14n2 . _:c14n4 _:c14n1 . _:c14n5 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test047-urgna2012.nq000066400000000000000000000005641450372207100261740ustar00rootroot00000000000000_:c14n0 "bar1" . _:c14n0 "bar2" . _:c14n1 "foo1" . _:c14n1 "foo2" . _:c14n2 _:c14n0 . _:c14n3 _:c14n2 . _:c14n4 _:c14n1 . _:c14n5 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test048-in.nq000066400000000000000000000005201450372207100251520ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b2 . _:b2 "bar1" . _:b2 "bar2" . _:b3 _:b4 . _:b4 _:b5 . _:b5 "foo1" . _:b5 "foo2" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test048-urdna2015.nq000066400000000000000000000005641450372207100261750ustar00rootroot00000000000000_:c14n0 "bar1" . _:c14n0 "bar2" . _:c14n1 "foo1" . _:c14n1 "foo2" . _:c14n2 _:c14n0 . _:c14n3 _:c14n2 . _:c14n4 _:c14n1 . _:c14n5 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test048-urgna2012.nq000066400000000000000000000005641450372207100261750ustar00rootroot00000000000000_:c14n0 "bar1" . _:c14n0 "bar2" . _:c14n1 "foo1" . _:c14n1 "foo2" . _:c14n2 _:c14n0 . _:c14n3 _:c14n2 . _:c14n4 _:c14n1 . _:c14n5 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test049-in.nq000066400000000000000000000000001450372207100251440ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test049-urdna2015.nq000066400000000000000000000000001450372207100261570ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test049-urgna2012.nq000066400000000000000000000000001450372207100261570ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test050-in.nq000066400000000000000000000002471450372207100251510ustar00rootroot00000000000000_:b0 "value" . _:b0 "Test 'null' in various locations" . _:b0 _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test050-urdna2015.nq000066400000000000000000000002631450372207100261620ustar00rootroot00000000000000_:c14n0 "value" . _:c14n0 "Test 'null' in various locations" . _:c14n0 _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test050-urgna2012.nq000066400000000000000000000002631450372207100261620ustar00rootroot00000000000000_:c14n1 "value" . _:c14n1 "Test 'null' in various locations" . _:c14n1 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test051-in.nq000066400000000000000000000003631450372207100251510ustar00rootroot00000000000000 "object1" . "object2" . "object3" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test051-urdna2015.nq000066400000000000000000000003631450372207100261640ustar00rootroot00000000000000 "object1" . "object2" . "object3" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test051-urgna2012.nq000066400000000000000000000003631450372207100261640ustar00rootroot00000000000000 "object1" . "object2" . "object3" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test052-in.nq000066400000000000000000000006231450372207100251510ustar00rootroot00000000000000 . . . "foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test052-urdna2015.nq000066400000000000000000000006231450372207100261640ustar00rootroot00000000000000 . . . "foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test052-urgna2012.nq000066400000000000000000000006231450372207100261640ustar00rootroot00000000000000 . . . "foo" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test053-in.nq000066400000000000000000000016401450372207100251520ustar00rootroot00000000000000_:b1 "1" . _:b1 _:b2 . _:b2 "2" . _:b2 _:b3 . _:b3 "3" . _:b3 . _:b0 _:b1 . _:b4 "4" . _:b4 _:b5 . _:b5 "5" . _:b5 _:b6 . _:b6 "6" . _:b6 . _:b0 _:b4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test053-urdna2015.nq000066400000000000000000000017341450372207100261710ustar00rootroot00000000000000_:c14n0 "3" . _:c14n0 . _:c14n1 "6" . _:c14n1 . _:c14n2 "1" . _:c14n2 _:c14n5 . _:c14n3 _:c14n2 . _:c14n3 _:c14n6 . _:c14n4 "5" . _:c14n4 _:c14n1 . _:c14n5 "2" . _:c14n5 _:c14n0 . _:c14n6 "4" . _:c14n6 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test053-urgna2012.nq000066400000000000000000000017341450372207100261710ustar00rootroot00000000000000_:c14n0 _:c14n2 . _:c14n0 _:c14n3 . _:c14n1 "2" . _:c14n1 _:c14n5 . _:c14n2 "1" . _:c14n2 _:c14n1 . _:c14n3 "4" . _:c14n3 _:c14n6 . _:c14n4 "6" . _:c14n4 . _:c14n5 "3" . _:c14n5 . _:c14n6 "5" . _:c14n6 _:c14n4 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test054-in.nq000066400000000000000000000011621450372207100251520ustar00rootroot00000000000000_:b0 _:b1 . _:b1 _:b2 . _:b2 _:b3 . _:b2 _:b4 . _:b3 _:b5 . _:b4 _:b10 . _:b5 _:b6 . _:b6 _:b7 . _:b7 _:b8 . _:b8 _:b9 . _:b10 _:b11 . _:b11 _:b12 . _:b12 _:b13 . _:b13 _:b14 . _:b14 _:b15 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test054-urdna2015.nq000066400000000000000000000013151450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n14 . _:c14n0 _:c14n7 . _:c14n1 _:c14n15 . _:c14n10 _:c14n9 . _:c14n11 _:c14n10 . _:c14n12 _:c14n11 . _:c14n13 _:c14n12 . _:c14n14 _:c14n13 . _:c14n15 _:c14n0 . _:c14n3 _:c14n2 . _:c14n4 _:c14n3 . _:c14n5 _:c14n4 . _:c14n6 _:c14n5 . _:c14n7 _:c14n6 . _:c14n9 _:c14n8 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test054-urgna2012.nq000066400000000000000000000013151450372207100261650ustar00rootroot00000000000000_:c14n0 _:c14n14 . _:c14n0 _:c14n7 . _:c14n1 _:c14n15 . _:c14n10 _:c14n9 . _:c14n11 _:c14n10 . _:c14n12 _:c14n11 . _:c14n13 _:c14n12 . _:c14n14 _:c14n13 . _:c14n15 _:c14n0 . _:c14n3 _:c14n2 . _:c14n4 _:c14n3 . _:c14n5 _:c14n4 . _:c14n6 _:c14n5 . _:c14n7 _:c14n6 . _:c14n9 _:c14n8 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test055-in.nq000066400000000000000000000002331450372207100251510ustar00rootroot00000000000000_:b0 _:b1 . _:b0 . _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test055-urdna2015.nq000066400000000000000000000002471450372207100261710ustar00rootroot00000000000000_:c14n0 . _:c14n0 _:c14n1 . _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test055-urgna2012.nq000066400000000000000000000002471450372207100261710ustar00rootroot00000000000000_:c14n0 . _:c14n0 _:c14n1 . _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test056-in.nq000066400000000000000000000002331450372207100251520ustar00rootroot00000000000000_:b0 . _:b1 _:b0 . _:b1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test056-urdna2015.nq000066400000000000000000000002471450372207100261720ustar00rootroot00000000000000_:c14n0 . _:c14n0 _:c14n1 . _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test056-urgna2012.nq000066400000000000000000000002471450372207100261720ustar00rootroot00000000000000_:c14n0 . _:c14n0 _:c14n1 . _:c14n1 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test057-in.nq000066400000000000000000000002041450372207100251510ustar00rootroot00000000000000_:b1 _:g . _:b1 "Manu Sporny" _:g . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test057-urdna2015.nq000066400000000000000000000002221450372207100261640ustar00rootroot00000000000000_:c14n1 _:c14n0 . _:c14n1 "Manu Sporny" _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test057-urgna2012.nq000066400000000000000000000002221450372207100261640ustar00rootroot00000000000000_:c14n1 _:c14n0 . _:c14n1 "Manu Sporny" _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test058-in.nq000066400000000000000000000001701450372207100251540ustar00rootroot00000000000000 _:b0 _:b3 . _:b1 _:b3 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test058-urdna2015.nq000066400000000000000000000002041450372207100261650ustar00rootroot00000000000000 _:c14n1 _:c14n0 . _:c14n2 _:c14n0 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test059-in.nq000066400000000000000000000004001450372207100251510ustar00rootroot00000000000000 . _:s _:o _:g . _:s_ _:o_ _:g_ . _:s_s _:o_o _:g_g . _:s0 _:o0 _:g0 . _:0s _:0o _:0g . _:s-0 _:o-0 _:g-0 . _:_ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test059-urdna2015.nq000066400000000000000000000005001450372207100261650ustar00rootroot00000000000000 . _:c14n0 . _:c14n1 _:c14n3 _:c14n2 . _:c14n10 _:c14n12 _:c14n11 . _:c14n13 _:c14n15 _:c14n14 . _:c14n16 _:c14n18 _:c14n17 . _:c14n4 _:c14n6 _:c14n5 . _:c14n7 _:c14n9 _:c14n8 . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test060-in.nq000066400000000000000000000011711450372207100251470ustar00rootroot00000000000000 "" . "simple" . "\"" . "\\" . "\n" . "\r" . "\"\\\n\r" . "\u0022\u005c" . "\t\b\n\r\f\"\'\\" . "\\u0039" . "\\n" . "\\\\" . "\"\"" . "\\\\\\" . "\"\"\"" . "\u221e" . "∞" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test060-urdna2015.nq000066400000000000000000000011521450372207100261610ustar00rootroot00000000000000 "" . "simple" . "\"" . "\\" . "\n" . "\r" . "\"\\\n\r" . "\"\\" . " \n\r \"'\\" . "\\u0039" . "\\n" . "\\\\" . "\"\"" . "\\\\\\" . "\"\"\"" . "∞" . "∞" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test060-urgna2012.nq000066400000000000000000000011521450372207100261610ustar00rootroot00000000000000 "" . "simple" . "\"" . "\\" . "\n" . "\r" . "\"\\\n\r" . "\"\\" . " \n\r \"'\\" . "\\u0039" . "\\n" . "\\\\" . "\"\"" . "\\\\\\" . "\"\"\"" . "∞" . "∞" . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test061-in.nq000066400000000000000000000001701450372207100251460ustar00rootroot00000000000000 "test"@en . "test"@fr . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test061-urdna2015.nq000066400000000000000000000001701450372207100261610ustar00rootroot00000000000000 "test"@en . "test"@fr . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test061-urgna2012.nq000066400000000000000000000001701450372207100261610ustar00rootroot00000000000000 "test"@en . "test"@fr . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test062-in.nq000066400000000000000000000002441450372207100251510ustar00rootroot00000000000000 "test"^^ . "test"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test062-urdna2015.nq000066400000000000000000000002441450372207100261640ustar00rootroot00000000000000 "test"^^ . "test"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/test062-urgna2012.nq000066400000000000000000000002441450372207100261640ustar00rootroot00000000000000 "test"^^ . "test"^^ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/vocab.html000066400000000000000000000111451450372207100247600ustar00rootroot00000000000000 RDF Dataset Normalization Test Vocabulary

W3C

RDF Dataset Normalization Test Vocabulary

This is a vocabulary document used to define classes and properties used in RDF Dataset Normalization Test Cases and associated test manifests.

This vocabulary extends the RDF Test Vocabulary and Test Manifest Vocabulary with Normalization-specific tests. The URI of the vocabulary is http://json-ld.github.io/normalization/tests/vocab# (abbreviated by rdfn in this document). Turtle and JSON-LD versions of the vocabular are also available. The vocabulary is published by the W3C Credentials Community Group.

Vocabulary Terms

The vocabulary terms below constitute the complete RDF Dataset Normalization Test vocabulary

Classes

rdfn:Test
Superclass of all RDF Dataset Normalization tests

All RDF Dataset Normalization tests have an input file referenced using mf:action and a result file referenced using mf:result. Results are compared as text where the result of running the test is serialized to canonical N-Quads, lexicographically-sorted.

subClassOf:
  • mf:ManifestEntry
  • rdft:Test
rdfn:Urdna2015EvalTest
URDNA2015 Evaluation Test

Normalization performed using the URDNA2015 algorithm.

subClassOf: rdfn:Test
rdfn:Urgna2012EvalTest
URGNA2012 Evaluation Test

Normalization performed using the URGNA2012 algorithm.

subClassOf: rdfn:Test

Properties

W3C Credentials Community Group
golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/vocab.jsonld000066400000000000000000000045771450372207100253200ustar00rootroot00000000000000{ "@context": { "dc": "http://purl.org/dc/elements/1.1/", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdfn": "http://json-ld.github.io/normalization/tests/vocab#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "rdft": "http://www.w3.org/ns/rdftest#", "xsd": "http://www.w3.org/2001/XMLSchema#", "dc:identifier": { "@type": "@id" }, "rdfs:subClassOf": { "@type": "@id" }, "rdfs:domain": { "@type": "@id" }, "rdfs:range": { "@type": "@id" } }, "@graph": [ { "@id": "http://json-ld.github.io/normalization/tests/vocab#", "dc:creator": "Gregg Kellogg", "dc:date": "2015-05-19", "dc:description": "\n This is a vocabulary document used to define classes and properties used in\n [RDF Dataset Normalization Test Cases](http://json-ld.github.io/normalization/tests/) and associated test manifests.\n ", "dc:identifier": "http://json-ld.github.io/normalization/tests/vocab#", "dc:publisher": "W3C Credentials Community Group", "dc:title": "RDF Dataset Normalization Test Vocabulary", "rdfs:comment": "This is a vocabulary document used to define classes and properties used in [RDF Dataset Normalization Test Cases](http://json-ld.github.io/normalization/tests/) and associated test manifests." }, { "@id": "rdfn:Test", "@type": "rdfs:Class", "rdfs:comment": "All RDF Dataset Normalization tests have an input file referenced using `mf:action` and a result file referenced using `mf:result`. Results are compared as text where the result of running the test is serialized to canonical N-Quads, lexicographically-sorted.", "rdfs:label": "Superclass of all RDF Dataset Normalization tests", "rdfs:subClassOf": [ "mf:ManifestEntry", "rdft:Test" ] }, { "@id": "rdfn:Urdna2015EvalTest", "@type": "rdfs:Class", "rdfs:comment": "Normalization performed using the URDNA2015 algorithm.", "rdfs:label": "URDNA2015 Evaluation Test", "rdfs:subClassOf": "rdfn:Test" }, { "@id": "rdfn:Urgna2012EvalTest", "@type": "rdfs:Class", "rdfs:comment": "Normalization performed using the URGNA2012 algorithm.", "rdfs:label": "URGNA2012 Evaluation Test", "rdfs:subClassOf": "rdfn:Test" } ] }golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/vocab.ttl000066400000000000000000000042761450372207100246260ustar00rootroot00000000000000# W3C RDF Dataset Normalization Test Vocabulary # This vocabulary defines classes an properties which extend # the test-manifest vocabulary at . @prefix : . @prefix dc: . @prefix mf: . @prefix rdf: . @prefix rdfn: . @prefix rdfs: . @prefix rdft: . @prefix xsd: . : dc:title "RDF Dataset Normalization Test Vocabulary"; dc:creator "Gregg Kellogg"; dc:publisher "W3C Credentials Community Group"; dc:description """ This is a vocabulary document used to define classes and properties used in [RDF Dataset Normalization Test Cases](http://json-ld.github.io/normalization/tests/) and associated test manifests. """; rdfs:comment """ This is a vocabulary document used to define classes and properties used in [RDF Dataset Normalization Test Cases](http://json-ld.github.io/normalization/tests/) and associated test manifests. """; dc:date "2015-05-19"; dc:identifier rdfn: . ## ---- Test Case Classes --- :Test a rdfs:Class; rdfs:subClassOf mf:ManifestEntry; rdfs:label "Superclass of all RDF Dataset Normalization tests"; rdfs:subClassOf rdft:Test; rdfs:comment """ All RDF Dataset Normalization tests have an input file referenced using `mf:action` and a result file referenced using `mf:result`. Results are compared as text where the result of running the test is serialized to canonical N-Quads, lexicographically-sorted. """ . :Urgna2012EvalTest a rdfs:Class; rdfs:label "URGNA2012 Evaluation Test"; rdfs:subClassOf :Test; rdfs:comment """ Normalization performed using the URGNA2012 algorithm. """ . :Urdna2015EvalTest a rdfs:Class; rdfs:label "URDNA2015 Evaluation Test"; rdfs:subClassOf :Test; rdfs:comment """ Normalization performed using the URDNA2015 algorithm. """ . golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/vocab_context.jsonld000066400000000000000000000010641450372207100270500ustar00rootroot00000000000000{ "@context": { "dc": "http://purl.org/dc/elements/1.1/", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdfn": "http://json-ld.github.io/normalization/tests/vocab#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "rdft": "http://www.w3.org/ns/rdftest#", "xsd": "http://www.w3.org/2001/XMLSchema#", "dc:identifier": {"@type": "@id"}, "rdfs:subClassOf": {"@type": "@id"}, "rdfs:domain": {"@type": "@id"}, "rdfs:range": {"@type": "@id"} } }golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/testdata/vocab_template.haml000066400000000000000000000103001450372207100266200ustar00rootroot00000000000000!!! 5 %html{lang: :en, prefix: "rdfn: http://json-ld.github.io/normalization/tests/vocab# mf: http://www.w3.org/2001/sw/DataAccess/tests/test-manifest# rdft: http://www.w3.org/ns/rdftest#"} %head %meta{"http-equiv" => "Content-Type", content: "text/html;charset=utf-8"} %meta{name: "viewport", content: "width=device-width, initial-scale=1.0"} %link{rel: "stylesheet", type: "text/css", href: "https://www.w3.org/StyleSheets/TR/base"} :css body: {bacground-image: none;} dt {margin-top: 2em;} dd code {display: inline;} footer {text-align: center;} %title = ontology['dc:title'] %body{resource: ontology['@id'], typeof: "owl:Ontology"} %meta{property: "dc:creator", value: ontology["dc:creator"]} %link{property: "dc:identifier", href: ontology["@id"]} %p %a{href: "http://www.w3.org/"} %img{src: "http://www.w3.org/Icons/w3c_home", alt: "W3C", height: 48, width: 72} %h1{property: "dc:title rdfs:label"}<= ontology["dc:title"] %span{property: "dc:description rdfs:comment"} :markdown #{ontology["dc:description"].gsub(/^\s+/, '')} This vocabulary extends the [RDF Test Vocabulary](http://www.w3.org/ns/rdftest#) and [Test Manifest Vocabulary](http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#) with Normalization-specific tests. The URI of the vocabulary is `http://json-ld.github.io/normalization/tests/vocab#` (abbreviated by `rdfn` in this document). [Turtle](vocab.ttl) and [JSON-LD](vocab.jsonld) versions of the vocabular are also available. The vocabulary is published by the [W3C Credentials Community Group](https://www.w3.org/community/credentials/). %section %h2="Vocabulary Terms" %p="The vocabulary terms below constitute the complete RDF Dataset Normalization Test vocabulary" %section %h3#classes="Classes" %dl - classes.sort_by {|c| c['@id']}.each do |cls| %dt{about: cls['@id'], typeof: cls['@type'], property: "rdfs:label"}<~cls["@id"] %dd{about: cls['@id']} %em{property: "rdfs:label"}<~cls["rdfs:label"] %span{property: "rdfs:comment"}< :markdown #{cls["rdfs:comment"].to_s.gsub(/^\s+/, '')} - if cls["rdfs:subClassOf"] %div %strong subClassOf: - if cls["rdfs:subClassOf"].is_a?(Array) %ul - cls["rdfs:subClassOf"].each do |e| %li %code{property: "rdfs:subClassOf", resource: e}=e - else %code{property: "rdfs:subClassOf", resource: cls["rdfs:subClassOf"]}=cls["rdfs:subClassOf"] %section %h3#properties="Properties" %dl - properties.sort_by {|c| c['@id']}.each do |prop| %dt{about: prop['@id'], typeof: prop['@type'], property: "rdfs:label"}<~prop["@id"] %dd{about: prop['@id']} %em{property: "rdfs:label"}<~prop["rdfs:label"] %span{property: "rdfs:comment"}< :markdown #{prop["rdfs:comment"].to_s.gsub(/^\s+/, '')} - if prop["rdfs:domain"] %div %strong domain: - if prop["rdfs:domain"].is_a?(Array) %ul - prop["rdfs:domain"].each do |e| %li %code{property: "rdfs:domain", resource: e}=e - else %code{property: "rdfs:domain", resource: prop["rdfs:domain"]}=prop["rdfs:domain"] - if prop["rdfs:range"] %div %strong range: - if prop["rdfs:range"].is_a?(Array) %ul - prop["rdfs:range"].each do |e| %li %code{property: "rdfs:range", resource: e}=e - else %code{property: "rdfs:range", resource: prop["rdfs:range"]}=prop["rdfs:range"] %footer %span{property: "dc:publisher"}<= ontology["dc:publisher"] golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/urna.go000066400000000000000000000373761450372207100225010ustar00rootroot00000000000000// Copyright ©2020 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 rdf import ( "bytes" "crypto/sha1" "crypto/sha256" "errors" "fmt" "hash" "sort" "gonum.org/v1/gonum/stat/combin" ) // Deduplicate removes duplicate statements in s, working in place, and returns // the deduplicated slice with statements sorted in lexical order. Term UID // fields are not considered and their values may be lost during deduplication. func Deduplicate(s []*Statement) []*Statement { if len(s) < 2 { return s } sort.Sort(c14nStatements(s)) curr := 0 for i, e := range s { if isSameStatement(e, s[curr]) { continue } curr++ if curr < i { s[curr], s[i] = s[i], nil } } return s[:curr+1] } func isSameStatement(a, b *Statement) bool { if a == b { return true } return a.Subject.Value == b.Subject.Value && a.Predicate.Value == b.Predicate.Value && a.Object.Value == b.Object.Value && a.Label.Value == b.Label.Value } // Note on implementation details: The comment numbering in the code relates the // implementation to the steps of the algorithm described in the specification. // URGNA2012 applies the Universal RDF Graph Normalization Algorithm 2012 // to the statements in src, placing the result in dst and returning it. // If dst is nil a slice of statements will be allocated. If dst is not // nil and not the same length as src, URGNA2012 will return an error. // // See https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html for details. func URGNA2012(dst, src []*Statement) ([]*Statement, error) { if dst == nil { dst = make([]*Statement, len(src)) } else if len(dst) != len(src) { return dst, errors.New("rdf: slice length mismatch") } // 1. https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#algorithm u := &urna{ canon: newIssuer("_:c14n"), hashes: make(map[string]string), statementsFor: make(map[string][]*Statement), hash: sha1.New(), label: "_:g", } u.hashToRelated = u.hashToRelatedURGNA2012 return u.relabel(dst, src) } // URDNA2015 applies the Universal RDF Dataset Normalization Algorithm 2015 // to the statements in src, placing the result in dst and returning it. // If dst is nil a slice of statements will be allocated. If dst is not // nil and not the same length as src, URDNA2015 will return an error. // // See https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html for details. func URDNA2015(dst, src []*Statement) ([]*Statement, error) { if dst == nil { dst = make([]*Statement, len(src)) } else if len(dst) != len(src) { return dst, errors.New("rdf: slice length mismatch") } // 1. https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#algorithm u := &urna{ canon: newIssuer("_:c14n"), hashes: make(map[string]string), statementsFor: make(map[string][]*Statement), hash: sha256.New(), } u.hashToRelated = u.hashToRelatedURDNA2015 return u.relabel(dst, src) } // urna is the canonicalization state for the URGNA2012 and URDNA2015 // algorithms. The urna type implements both algorithms through the state // of the label and hashToRelated fields. // // See https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#canonicalization-state // for details. type urna struct { // canon is the canonical issuer. canon *issuer // hashes holds already calculated hashes // for hashing first degree quads. hashes map[string]string // statementsFor is the blank node to quads map. statementsFor map[string][]*Statement // hash is the hash function used by the // canonicalization function. hash hash.Hash // hashToRelated holds URGNA2012 and URDNA2015- // specific hashing routines. hashToRelated relatedHashCreator // label holds "_:g" when running URGNA2012. // Otherwise it is empty. label string } // relabel is the algorithm described in section 4.4.2 of the spec at // https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#algorithm. func (u *urna) relabel(dst, src []*Statement) ([]*Statement, error) { // termsFor is the hash to blank nodes map. // It is not held in the urna struct, but is // part of the canonicalization state. // // https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#dfn-hash-to-blank-nodes-map var termsFor map[string][]string // 1. for _, s := range src { // 2. terms: for _, t := range []string{ s.Subject.Value, s.Object.Value, s.Label.Value, } { if !isBlank(t) { continue } for _, e := range u.statementsFor[t] { if e == s { continue terms } } u.statementsFor[t] = append(u.statementsFor[t], s) } } // todo is the list of non-normalized blank node identifiers. todo := make(map[string]bool) // 3. for b := range u.statementsFor { todo[b] = true } simple := true // 4. for simple { // 5. simple = false // 5.1 termsFor = make(map[string][]string) // 5.2 for b := range todo { // 5.3 hash := u.hashFirstDegreeQuads(b) // 5.3.1 termsFor[hash] = append(termsFor[hash], b) // 5.3.2 } for _, h := range lexicallySortedTermHashes(termsFor) { // 5.4 terms := termsFor[h] if len(terms) > 1 { // 5.4.1 continue } u.canon.issueFor(terms[0]) // 5.4.2 delete(todo, terms[0]) // 5.4.3 delete(termsFor, h) // 5.4.4 simple = true // 5.4.5 } } for _, hash := range lexicallySortedTermHashes(termsFor) { // 6. paths := make(map[string][]*issuer) // 6.1 for _, b := range termsFor[hash] { // 6.2 if u.canon.has(b) { // 6.2.1 continue } names := newIssuer("_:b") // 6.2.2 names.issueFor(b) // 6.2.3 // 6.2.4 hash, issuer := u.hashNDegreeQuads(b, names) paths[string(hash)] = append(paths[string(hash)], issuer) } for _, hash := range lexicallySortedPathHashes(paths) { // 6.3 for _, i := range paths[hash] { for _, existing := range i.ordered { // 6.3.1 u.canon.issueFor(existing) } } } } // 7. for i, s := range src { if dst[i] == nil { dst[i] = &Statement{} } n := dst[i] n.Subject = Term{Value: translateURNA(s.Subject.Value, u.canon.issued), UID: s.Subject.UID} n.Predicate = s.Predicate n.Object = Term{Value: translateURNA(s.Object.Value, u.canon.issued), UID: s.Object.UID} n.Label = Term{Value: translateURNA(s.Label.Value, u.canon.issued), UID: s.Label.UID} } sort.Sort(c14nStatements(dst)) return dst, nil } // lexicallySortedPathHashes returns the lexically sorted hashes of paths. func lexicallySortedPathHashes(paths map[string][]*issuer) []string { lexicalHashPaths := make([]string, len(paths)) i := 0 for h := range paths { lexicalHashPaths[i] = h i++ } sort.Strings(lexicalHashPaths) return lexicalHashPaths } func translateURNA(term string, mapping map[string]string) string { term = translate(term, mapping) if term == "" { return "" } text, qual, kind, err := extract([]rune(term)) var t Term switch kind { case Blank: return term case IRI: t, err = NewIRITerm(text) case Literal: t, err = NewLiteralTerm(text, qual) } if err != nil { panic(fmt.Errorf("rdf: invalid term %q: %w", term, err)) } return t.Value } // hashFirstDegreeQuads is the algorithm described in section 4.6 of the spec // at https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#algorithm-1. func (u *urna) hashFirstDegreeQuads(b string) string { if h, ok := u.hashes[b]; ok { return h } var statements []*Statement // 1. for _, s := range u.statementsFor[b] { // 2. and 3. var n Statement n.Subject.Value = replaceBlank(s.Subject.Value, b, "") n.Predicate.Value = s.Predicate.Value n.Object.Value = replaceBlank(s.Object.Value, b, "") n.Label.Value = replaceBlank(s.Label.Value, b, u.label) statements = append(statements, &n) } sort.Sort(c14nStatements(statements)) // 4. // 5. u.hash.Reset() for _, s := range statements { fmt.Fprintln(u.hash, s) } u.hashes[b] = string(hex(u.hash.Sum(nil))) return u.hashes[b] } // replaceBlank implements 3.1 of the algorithm described at // https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#algorithm-1. func replaceBlank(b, matching, label string) string { if !isBlank(b) { // 3.1 return b } if label != "" { // URGNA2012 modification. // When running in URGNA2012 mode, label is "_:g" for Label fields. // // If any blank node was used in the graph name position in the quad, // then the value was serialized using the special blank node identifier, // "_:g", instead of "_:z". // https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#urgna2012 return label } // 3.1.1.1 if b == matching { return "_:a" } return "_:z" } // hashNDegreeQuads is the algorithm described in section 4.8 of the spec // at https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#hash-n-degree-quads. func (u *urna) hashNDegreeQuads(b string, names *issuer) ([]byte, *issuer) { // termsFor is the hash to related blank nodes map. termsFor := u.hashToRelated(b, names) // 1., 2. and 3. var final []byte // 4. for _, hash := range lexicallySortedTermHashes(termsFor) { // 5. terms := termsFor[hash] final = append(final, hash...) // 5.1 var chosenPath []byte // 5.2 var chosenIssuer *issuer // 5.3 p := newPermutations(terms) // 5.4 permutations: for p.next() { namesCopy := names.clone() // 5.4.1 var path []byte // 5.4.2 var work []string // 5.4.3 for _, b := range p.permutation() { // 5.4.4 if u.canon.has(b) { // 5.4.4.1 path = append(path, u.canon.issueFor(b)...) } else { // 5.4.4.1 if !namesCopy.has(b) { work = append(work, b) } path = append(path, namesCopy.issueFor(b)...) // 5.4.4.2.2 } // 5.4.4.3 if len(chosenPath) != 0 && len(path) >= len(chosenPath) && bytes.Compare(path, chosenPath) > 0 { continue permutations } } for _, b := range work { // 5.4.5 hash, issuer := u.hashNDegreeQuads(b, namesCopy) // 5.4.5.1 path = append(path, namesCopy.issueFor(b)...) // 5.4.5.2 // 5.4.5.3 path = append(path, '<') path = append(path, hash...) path = append(path, '>') namesCopy = issuer // 5.4.5.4 // 5.4.5.5 if len(chosenPath) != 0 && len(path) >= len(chosenPath) && bytes.Compare(path, chosenPath) > 0 { continue permutations } } if len(chosenPath) == 0 || bytes.Compare(path, chosenPath) < 0 { // 5.4.6 chosenPath = path chosenIssuer = namesCopy } } // 5.5 final = append(final, chosenPath...) u.hash.Reset() u.hash.Write(final) names = chosenIssuer // 5.6 } return hex(u.hash.Sum(nil)), names } // lexicallySortedTermHashes returns the lexically sorted hashes of termsFor. func lexicallySortedTermHashes(termsFor map[string][]string) []string { lexicalHashes := make([]string, len(termsFor)) i := 0 for h := range termsFor { lexicalHashes[i] = h i++ } sort.Strings(lexicalHashes) return lexicalHashes } type relatedHashCreator func(b string, names *issuer) map[string][]string // hashToRelatedURDNA2015 is the section 1. 2. and 3. of 4.8.2 of the spec // at https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#hash-n-degree-quads. func (u *urna) hashToRelatedURDNA2015(b string, names *issuer) map[string][]string { // termsFor is the hash to related blank nodes map. termsFor := make(map[string][]string) // 1. for _, s := range u.statementsFor[b] { // 2. and 3. for i, term := range []string{ // 3.1 s.Subject.Value, s.Object.Value, s.Label.Value, } { if !isBlank(term) || term == b { continue } // 3.1.1 const position = "sog" hash := u.hashRelatedBlank(term, s, names, position[i]) // 3.1.2 termsFor[string(hash)] = append(termsFor[string(hash)], term) } } return termsFor } // hashToRelatedURGNA2012 is the section 1., 2. and 3. of 4.8.2 of the spec // at https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#hash-n-degree-quads // with changes made for URGNA2012 shown in the appendix for 4.8 at // https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#urgna2012. // The numbering of steps here corresponds to the spec's numbering in the // appendix. func (u *urna) hashToRelatedURGNA2012(b string, names *issuer) map[string][]string { // termsFor is the hash to related blank nodes map. termsFor := make(map[string][]string) for _, s := range u.statementsFor[b] { // 1. var ( term string pos byte ) switch { case isBlank(s.Subject.Value) && s.Subject.Value != b: // 1.1 term = s.Subject.Value pos = 'p' case isBlank(s.Object.Value) && s.Object.Value != b: // 1.2 term = s.Object.Value pos = 'r' default: continue // 1.3 } // 1.4 hash := u.hashRelatedBlank(term, s, names, pos) termsFor[string(hash)] = append(termsFor[string(hash)], term) } return termsFor } // hashNDegreeQuads is the algorithm described in section 4.7 of the spec // https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#hash-related-blank-node. func (u *urna) hashRelatedBlank(term string, s *Statement, names *issuer, pos byte) []byte { // 1. var b string switch { case u.canon.has(term): b = u.canon.issueFor(term) case names.has(term): b = names.issueFor(term) default: b = u.hashFirstDegreeQuads(term) } // 2. u.hash.Reset() u.hash.Write([]byte{pos}) if pos != 'g' { // 3. if u.label == "" { // URDNA2015: Term.Value retained the angle quotes // so we don't need to add them. u.hash.Write([]byte(s.Predicate.Value)) } else { // URGNA2012 does not delimit predicate by < and >. // https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#urgna2012 // with reference to 4.7. u.hash.Write([]byte(unquoteIRI(s.Predicate.Value))) } } // 4. and 5. u.hash.Write([]byte(b)) return hex(u.hash.Sum(nil)) } // issuer is an identifier issuer. type issuer struct { prefix string issued map[string]string ordered []string } // newIssuer returns a new identifier issuer with the given prefix. func newIssuer(prefix string) *issuer { return &issuer{prefix: prefix, issued: make(map[string]string)} } // issueFor implements the issue identifier algorithm. // // See https://json-ld.github.io/rdf-dataset-canonicalization/spec/index.html#issue-identifier-algorithm func (i *issuer) issueFor(b string) string { c, ok := i.issued[b] if ok { return c } c = fmt.Sprintf("%s%d", i.prefix, len(i.issued)) i.issued[b] = c i.ordered = append(i.ordered, b) return c } func (i *issuer) has(id string) bool { _, ok := i.issued[id] return ok } func (i *issuer) clone() *issuer { new := issuer{ prefix: i.prefix, issued: make(map[string]string, len(i.issued)), ordered: make([]string, len(i.ordered)), } copy(new.ordered, i.ordered) for k, v := range i.issued { new.issued[k] = v } return &new } func hex(data []byte) []byte { const digit = "0123456789abcdef" buf := make([]byte, 0, len(data)*2) for _, b := range data { buf = append(buf, digit[b>>4], digit[b&0xf]) } return buf } // permutations is a string permutation generator. type permutations struct { src []string dst []string idx []int perm *combin.PermutationGenerator } // newPermutation returns a new permutations. func newPermutations(src []string) *permutations { return &permutations{ src: src, dst: make([]string, len(src)), perm: combin.NewPermutationGenerator(len(src), len(src)), idx: make([]int, len(src)), } } // next returns whether there is another permutation available. func (p *permutations) next() bool { return p.perm.Next() } // permutation returns the permutation. The caller may not retain the // returned slice between iterations. func (p *permutations) permutation() []string { p.perm.Permutation(p.idx) for i, j := range p.idx { p.dst[j] = p.src[i] } return p.dst } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/urna_example_test.go000066400000000000000000000041541450372207100252370ustar00rootroot00000000000000// Copyright ©2020 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 rdf_test import ( "fmt" "log" "strings" "gonum.org/v1/gonum/graph/formats/rdf" ) func ExampleURDNA2015() { for _, statements := range []string{ ` _:a . _:b . _:c _:a . _:d _:b . _:c _:d . `, ` _:c1 _:a1 . _:b1 . _:d1 _:b1 . _:a1 . _:c1 _:d1 . `, } { // Decode the statement stream. dec := rdf.NewDecoder(strings.NewReader(statements)) var s []*rdf.Statement for { l, err := dec.Unmarshal() if err != nil { break } s = append(s, l) } relabeled, err := rdf.URDNA2015(nil, s) if err != nil { log.Fatal(err) } for _, s := range relabeled { fmt.Println(s) } fmt.Println() } // Output: // // _:c14n0 _:c14n2 . // _:c14n1 _:c14n3 . // _:c14n1 _:c14n0 . // _:c14n2 . // _:c14n3 . // // _:c14n0 _:c14n2 . // _:c14n1 _:c14n3 . // _:c14n1 _:c14n0 . // _:c14n2 . // _:c14n3 . } func ExampleURGNA2012() { for _, statements := range []string{ ` _:a . _:b . _:c _:a . _:d _:b . _:c _:d . `, ` _:c1 _:a1 . _:b1 . _:d1 _:b1 . _:a1 . _:c1 _:d1 . `, } { // Decode the statement stream. dec := rdf.NewDecoder(strings.NewReader(statements)) var s []*rdf.Statement for { l, err := dec.Unmarshal() if err != nil { break } s = append(s, l) } relabeled, err := rdf.URGNA2012(nil, s) if err != nil { log.Fatal(err) } for _, s := range relabeled { fmt.Println(s) } fmt.Println() } // Output: // // _:c14n0 _:c14n3 . // _:c14n0 _:c14n1 . // _:c14n1 _:c14n2 . // _:c14n2 . // _:c14n3 . // // _:c14n0 _:c14n3 . // _:c14n0 _:c14n1 . // _:c14n1 _:c14n2 . // _:c14n2 . // _:c14n3 . } golang-gonum-v1-gonum-0.14.0/graph/formats/rdf/urna_test.go000066400000000000000000000100751450372207100235230ustar00rootroot00000000000000// Copyright ©2020 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 rdf import ( "bytes" "fmt" "io" "os" "path/filepath" "strings" "testing" "github.com/google/go-cmp/cmp" ) var deduplicateTests = []struct { statements string want string }{ {}, { statements: ` _:1 _:2 . `, want: `_:1 _:2 . `, }, { statements: ` _:1 _:2 . _:1 _:2 . `, want: `_:1 _:2 . `, }, { statements: ` _:1 _:2 . _:2 _:1 . _:1 _:2 . `, want: `_:1 _:2 . _:2 _:1 . `, }, { statements: ` _:1 _:2 . _:2 _:1 . _:1 _:2 . _:1 _:2 . `, want: `_:1 _:2 . _:2 _:1 . `, }, } func TestDeduplicate(t *testing.T) { tests: for i, test := range deduplicateTests { var statements []*Statement dec := NewDecoder(strings.NewReader(test.statements)) for { s, err := dec.Unmarshal() if err != nil { if err != io.EOF { t.Errorf("error during decoding: %v", err) continue tests } break } statements = append(statements, s) } var buf strings.Builder for _, s := range Deduplicate(statements) { fmt.Fprintln(&buf, s) } got := buf.String() if got != test.want { t.Errorf("unexpected result for test %d:\n%s", i, cmp.Diff(got, test.want)) } } } func TestURNA(t *testing.T) { glob, err := filepath.Glob(filepath.Join("testdata", *tests)) if err != nil { t.Fatalf("Failed to open test suite: %v", err) } for _, test := range []struct { name string fn func(dst, src []*Statement) ([]*Statement, error) truth string }{ { name: "URDNA2015", fn: URDNA2015, truth: "-urdna2015.nq", }, { name: "URGNA2012", fn: URGNA2012, truth: "-urgna2012.nq", }, } { t.Run(test.name, func(t *testing.T) { for _, path := range glob { name := filepath.Base(path) golden := strings.TrimSuffix(path, "-in.nq") + test.truth want, err := os.ReadFile(golden) if err != nil { if !os.IsNotExist(err) { t.Errorf("Failed to read golden data: %v", err) } continue } t.Run(name, func(t *testing.T) { f, err := os.Open(path) if err != nil { t.Fatalf("Failed to open test suite in %q: %v", path, err) } var statements []*Statement dec := NewDecoder(f) for { s, err := dec.Unmarshal() if err != nil { if err == io.EOF { break } t.Fatalf("Unexpected error reading from %q: %v", path, err) } statements = append(statements, s) } f.Close() relabeled, _ := test.fn(nil, statements) var buf bytes.Buffer for _, s := range relabeled { fmt.Fprintln(&buf, s) } got := buf.Bytes() if !bytes.Equal(got, want) { t.Errorf("Unexpected result for %s %s:\ngot:\n%s\nwant:\n%s", test.name, path, got, want) } }) } }) } } func BenchmarkURNA(b *testing.B) { benchmarks := []string{ "test019-in.nq", "test044-in.nq", } for _, name := range benchmarks { path := filepath.Join("testdata", name) b.Run(name, func(b *testing.B) { f, err := os.Open(path) if err != nil { b.Fatalf("Failed to open test suite in %q: %v", path, err) } var statements []*Statement dec := NewDecoder(f) for { s, err := dec.Unmarshal() if err != nil { if err == io.EOF { break } b.Fatalf("Unexpected error reading from %q: %v", path, err) } statements = append(statements, s) } f.Close() for _, bench := range []struct { name string fn func(dst, src []*Statement) ([]*Statement, error) }{ { name: "URDNA2015", fn: URDNA2015, }, { name: "URGNA2012", fn: URGNA2012, }, } { b.Run(bench.name, func(b *testing.B) { for i := 0; i < b.N; i++ { relabeled, _ := bench.fn(nil, statements) if len(relabeled) != len(statements) { b.Fatalf("unexpected number of relabeled statements: %d != %d", len(relabeled), len(statements)) } } }) } }) } } golang-gonum-v1-gonum-0.14.0/graph/formats/sigmajs/000077500000000000000000000000001450372207100220475ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/sigmajs/sigmajs.go000066400000000000000000000055431450372207100240420ustar00rootroot00000000000000// 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 sigmajs implements marshaling and unmarshaling of Sigma.js JSON documents. // // See http://sigmajs.org/ for Sigma.js documentation. package sigmajs // import "gonum.org/v1/gonum/graph/formats/sigmajs" import ( "encoding/json" "errors" "fmt" ) // Graph is a Sigma.js graph. type Graph struct { Nodes []Node `json:"nodes"` Edges []Edge `json:"edges"` } // Node is a Sigma.js node. type Node struct { ID string Attributes map[string]interface{} } var ( _ json.Marshaler = (*Node)(nil) _ json.Unmarshaler = (*Node)(nil) ) // MarshalJSON implements the json.Marshaler interface. func (n *Node) MarshalJSON() ([]byte, error) { if n.Attributes == nil { type node struct { ID string `json:"id"` } return json.Marshal(node{ID: n.ID}) } n.Attributes["id"] = n.ID b, err := json.Marshal(n.Attributes) delete(n.Attributes, "id") return b, err } // UnmarshalJSON implements the json.Unmarshaler interface. func (n *Node) UnmarshalJSON(data []byte) error { var attrs map[string]interface{} err := json.Unmarshal(data, &attrs) if err != nil { return err } id, ok := attrs["id"] if !ok { return errors.New("sigmajs: no ID") } n.ID = fmt.Sprint(id) delete(attrs, "id") if len(attrs) != 0 { n.Attributes = attrs } return nil } // Edge is a Sigma.js edge. type Edge struct { ID string Source string Target string Attributes map[string]interface{} } var ( _ json.Marshaler = (*Edge)(nil) _ json.Unmarshaler = (*Edge)(nil) ) // MarshalJSON implements the json.Marshaler interface. func (e *Edge) MarshalJSON() ([]byte, error) { if e.Attributes == nil { type edge struct { ID string `json:"id"` Source string `json:"source"` Target string `json:"target"` } return json.Marshal(edge{ID: e.ID, Source: e.Source, Target: e.Target}) } e.Attributes["id"] = e.ID e.Attributes["source"] = e.Source e.Attributes["target"] = e.Target b, err := json.Marshal(e.Attributes) delete(e.Attributes, "id") delete(e.Attributes, "source") delete(e.Attributes, "target") return b, err } // UnmarshalJSON implements the json.Unmarshaler interface. func (e *Edge) UnmarshalJSON(data []byte) error { var attrs map[string]interface{} err := json.Unmarshal(data, &attrs) if err != nil { return err } id, ok := attrs["id"] if !ok { return errors.New("sigmajs: no ID") } source, ok := attrs["source"] if !ok { return errors.New("sigmajs: no source") } target, ok := attrs["target"] if !ok { return errors.New("sigmajs: no target") } e.ID = fmt.Sprint(id) e.Source = fmt.Sprint(source) e.Target = fmt.Sprint(target) delete(attrs, "id") delete(attrs, "source") delete(attrs, "target") if len(attrs) != 0 { e.Attributes = attrs } return nil } golang-gonum-v1-gonum-0.14.0/graph/formats/sigmajs/sigmajs_test.go000066400000000000000000000205141450372207100250740ustar00rootroot00000000000000// 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 sigmajs import ( "encoding/json" "os" "path/filepath" "reflect" "testing" ) var sigmajsExampleTests = []struct { path string wantNodes int wantEdges int wantGraph *Graph wantAttributes map[string]bool }{ { path: "geolocalized.json", wantNodes: 17, wantEdges: 35, wantGraph: &Graph{ Nodes: []Node{ { ID: "n1", Attributes: map[string]interface{}{ "label": "n1", "longitude": 2.48, "latitude": 50.93, "size": "5.5", "color": "rgb(1,179,255)", }, }, { ID: "n2", Attributes: map[string]interface{}{ "label": "n2", "latitude": 50.88, "longitude": 2.0, "size": "5.0", "color": "rgb(1,179,255)", }, }, { ID: "n4", Attributes: map[string]interface{}{ "label": "n4", "latitude": 49.4, "longitude": 0.19, "size": "6.0", "color": "rgb(1,179,255)", }, }, { ID: "n5", Attributes: map[string]interface{}{ "label": "n5", "latitude": 48.49, "longitude": -1.92, "size": "6.0", "color": "rgb(1,179,255)", }, }, { ID: "n6", Attributes: map[string]interface{}{ "label": "n6", "latitude": 48.26, "longitude": -4.38, "size": "4.5", "color": "rgb(1,179,255)", }, }, { ID: "n7", Attributes: map[string]interface{}{ "label": "n7", "latitude": 47.15, "longitude": -2.09, "size": "6.5", "color": "rgb(1,179,255)", }, }, { ID: "n8", Attributes: map[string]interface{}{ "label": "n8", "latitude": 46.02, "longitude": -1.04, "size": "6.5", "color": "rgb(1,179,255)", }, }, { ID: "n9", Attributes: map[string]interface{}{ "label": "n9", "latitude": 43.22, "longitude": -1.85, "size": "5.0", "color": "rgb(1,179,255)", }, }, { ID: "n10", Attributes: map[string]interface{}{ "label": "n10", "latitude": 42.38, "longitude": 3.18, "color": "rgb(1,179,255)", "size": "4.0", }, }, { ID: "n11", Attributes: map[string]interface{}{ "label": "n11", "latitude": 43.47, "longitude": 4.04, "size": "5.5", "color": "rgb(1,179,255)", }, }, { ID: "n12", Attributes: map[string]interface{}{ "label": "n12", "latitude": 42.9, "longitude": 6.59, "size": "5.0", "color": "rgb(1,179,255)", }, }, { ID: "n13", Attributes: map[string]interface{}{ "label": "n13", "latitude": 43.62, "longitude": 7.66, "size": "6.0", "color": "rgb(1,179,255)", }, }, { ID: "n14", Attributes: map[string]interface{}{ "label": "n14", "latitude": 46.05, "longitude": 6.19, "size": "6.5", "color": "rgb(1,179,255)", }, }, { ID: "n15", Attributes: map[string]interface{}{ "label": "n15", "latitude": 47.43, "longitude": 7.65, "size": "6.0", "color": "rgb(1,179,255)", }, }, { ID: "n16", Attributes: map[string]interface{}{ "label": "n16", "latitude": 48.9, "longitude": 8.32, "size": "5.5", "color": "rgb(1,179,255)", }, }, { ID: "n17", Attributes: map[string]interface{}{ "label": "n17", "latitude": 49.83, "longitude": 4.94, "size": "6.5", "color": "rgb(1,179,255)", }, }, { ID: "Paris", Attributes: map[string]interface{}{ "label": "Paris", "latitude": 48.72, "longitude": 2.46, "size": "9.0", "color": "rgb(1,179,255)", }, }, }, Edges: []Edge{ {ID: "8", Source: "n1", Target: "Paris"}, {ID: "7", Source: "n2", Target: "n4"}, {ID: "28", Source: "n4", Target: "n1"}, {ID: "30", Source: "n4", Target: "n7"}, {ID: "26", Source: "n5", Target: "n1"}, {ID: "27", Source: "n5", Target: "n2"}, {ID: "0", Source: "n6", Target: "n5"}, {ID: "29", Source: "n7", Target: "n5"}, {ID: "1", Source: "n7", Target: "n8"}, {ID: "17", Source: "n7", Target: "Paris"}, {ID: "10", Source: "n8", Target: "n13"}, {ID: "18", Source: "n8", Target: "Paris"}, {ID: "15", Source: "n9", Target: "n8"}, {ID: "34", Source: "n10", Target: "n9"}, {ID: "31", Source: "n10", Target: "n11"}, {ID: "11", Source: "n11", Target: "n13"}, {ID: "13", Source: "n11", Target: "n14"}, {ID: "32", Source: "n12", Target: "n10"}, {ID: "12", Source: "n12", Target: "n11"}, {ID: "23", Source: "n12", Target: "n13"}, {ID: "33", Source: "n13", Target: "n10"}, {ID: "25", Source: "n13", Target: "n14"}, {ID: "14", Source: "n14", Target: "n9"}, {ID: "5", Source: "n14", Target: "n17"}, {ID: "19", Source: "n14", Target: "Paris"}, {ID: "6", Source: "n15", Target: "n8"}, {ID: "22", Source: "n15", Target: "n16"}, {ID: "20", Source: "n15", Target: "Paris"}, {ID: "4", Source: "n16", Target: "n15"}, {ID: "24", Source: "n16", Target: "Paris"}, {ID: "9", Source: "n17", Target: "n7"}, {ID: "21", Source: "n17", Target: "n17"}, {ID: "2", Source: "Paris", Target: "n4"}, {ID: "3", Source: "Paris", Target: "n17"}, {ID: "16", Source: "Paris", Target: "Paris"}, }, }, }, { path: "arctic.json", wantNodes: 1715, wantEdges: 6676, wantAttributes: map[string]bool{ "label": true, "x": true, "y": true, "color": true, "size": true, "attributes": true, "attributes.nodedef": true, }, }, } func TestUnmarshal(t *testing.T) { for _, test := range sigmajsExampleTests { data, err := os.ReadFile(filepath.Join("testdata", test.path)) if err != nil { t.Errorf("failed to read %q: %v", test.path, err) continue } var got Graph err = json.Unmarshal(data, &got) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } if len(got.Nodes) != test.wantNodes { t.Errorf("unexpected result for order of %q: got:%d want:%d", test.path, len(got.Nodes), test.wantNodes) } if len(got.Edges) != test.wantEdges { t.Errorf("unexpected result for size of %q: got:%d want:%d", test.path, len(got.Edges), test.wantEdges) } if test.wantGraph != nil && !reflect.DeepEqual(&got, test.wantGraph) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, test.wantGraph) } if test.wantAttributes != nil { var paths []string for _, n := range got.Nodes { paths = attrPaths(paths, "", n.Attributes) } gotAttrs := make(map[string]bool) for _, p := range paths { gotAttrs[p] = true } if !reflect.DeepEqual(gotAttrs, test.wantAttributes) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, gotAttrs, test.wantAttributes) } } } } func attrPaths(dst []string, prefix string, m map[string]interface{}) []string { for k, v := range m { path := prefix if path != "" { path += "." } if v, ok := v.(map[string]interface{}); ok { dst = attrPaths(dst, path+k, v) } dst = append(dst, path+k) } return dst } func TestMarshal(t *testing.T) { for _, test := range sigmajsExampleTests { data, err := os.ReadFile(filepath.Join("testdata", test.path)) if err != nil { t.Errorf("failed to read %q: %v", test.path, err) continue } var want Graph err = json.Unmarshal(data, &want) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } marshaled, err := json.Marshal(want) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } var got Graph err = json.Unmarshal(marshaled, &got) if err != nil { t.Errorf("failed to unmarshal %q: %v", test.path, err) continue } if !reflect.DeepEqual(got, want) { t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, want) } } } golang-gonum-v1-gonum-0.14.0/graph/formats/sigmajs/testdata/000077500000000000000000000000001450372207100236605ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/formats/sigmajs/testdata/LICENSE.txt000066400000000000000000000020731450372207100255050ustar00rootroot00000000000000Copyright (C) 2013-2014, Alexis Jacomy, http://sigmajs.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-gonum-v1-gonum-0.14.0/graph/formats/sigmajs/testdata/arctic.json000066400000000000000000020027371450372207100260330ustar00rootroot00000000000000{"edges":[{"source":"473","target":"313","id":"6432"},{"source":"285","target":"50","id":"357"},{"source":"441","target":"1394","id":"4376"},{"source":"51","target":"50","id":"5581"},{"source":"1051","target":"428","id":"2763"},{"source":"1712","target":"377","id":"6595"},{"source":"1197","target":"79","id":"3431"},{"source":"515","target":"608","id":"1171"},{"source":"397","target":"396","id":"3911"},{"source":"499","target":"49","id":"829"},{"source":"362","target":"177","id":"6459"},{"source":"634","target":"281","id":"1234"},{"source":"1070","target":"436","id":"2819"},{"source":"1672","target":"816","id":"6296"},{"source":"279","target":"335","id":"504"},{"source":"424","target":"130","id":"4942"},{"source":"744","target":"65","id":"1559"},{"source":"1176","target":"1177","id":"3296"},{"source":"957","target":"958","id":"2426"},{"source":"1631","target":"206","id":"6038"},{"source":"631","target":"53","id":"1216"},{"source":"1594","target":"76","id":"5762"},{"source":"832","target":"237","id":"1880"},{"source":"494","target":"128","id":"4201"},{"source":"1034","target":"209","id":"2675"},{"source":"451","target":"452","id":"739"},{"source":"573","target":"279","id":"1044"},{"source":"1540","target":"335","id":"5303"},{"source":"631","target":"632","id":"1218"},{"source":"1563","target":"1564","id":"5497"},{"source":"778","target":"645","id":"1682"},{"source":"765","target":"747","id":"4823"},{"source":"1249","target":"1409","id":"5912"},{"source":"1650","target":"484","id":"6159"},{"source":"630","target":"240","id":"1211"},{"source":"1524","target":"1138","id":"5262"},{"source":"308","target":"368","id":"566"},{"source":"1718","target":"1717","id":"6626"},{"source":"730","target":"51","id":"1522"},{"source":"1513","target":"68","id":"5214"},{"source":"42","target":"281","id":"344"},{"source":"1453","target":"1","id":"4761"},{"source":"64","target":"67","id":"1828"},{"source":"868","target":"82","id":"2021"},{"source":"408","target":"50","id":"875"},{"source":"982","target":"250","id":"2513"},{"source":"115","target":"364","id":"2320"},{"source":"271","target":"38","id":"4327"},{"source":"117","target":"120","id":"124"},{"source":"1052","target":"208","id":"2769"},{"source":"1378","target":"293","id":"4282"},{"source":"496","target":"403","id":"822"},{"source":"1696","target":"53","id":"6426"},{"source":"761","target":"82","id":"1615"},{"source":"252","target":"250","id":"758"},{"source":"1353","target":"281","id":"4174"},{"source":"186","target":"188","id":"208"},{"source":"1179","target":"284","id":"3309"},{"source":"453","target":"76","id":"1617"},{"source":"451","target":"53","id":"740"},{"source":"1177","target":"427","id":"5363"},{"source":"1000","target":"567","id":"3291"},{"source":"1590","target":"567","id":"5716"},{"source":"716","target":"711","id":"1449"},{"source":"199","target":"201","id":"3322"},{"source":"1273","target":"1229","id":"3764"},{"source":"1372","target":"216","id":"4258"},{"source":"434","target":"433","id":"940"},{"source":"660","target":"662","id":"4041"},{"source":"1575","target":"281","id":"5603"},{"source":"1629","target":"177","id":"6026"},{"source":"611","target":"53","id":"1176"},{"source":"794","target":"102","id":"1736"},{"source":"687","target":"53","id":"1381"},{"source":"1054","target":"1","id":"2777"},{"source":"1214","target":"82","id":"3488"},{"source":"61","target":"408","id":"862"},{"source":"42","target":"282","id":"345"},{"source":"452","target":"50","id":"2279"},{"source":"225","target":"211","id":"6087"},{"source":"1715","target":"182","id":"6613"},{"source":"1253","target":"377","id":"6559"},{"source":"385","target":"303","id":"3685"},{"source":"1480","target":"919","id":"4981"},{"source":"1253","target":"182","id":"6561"},{"source":"1709","target":"1062","id":"6547"},{"source":"1583","target":"241","id":"5667"},{"source":"1604","target":"1126","id":"5852"},{"source":"456","target":"30","id":"5812"},{"source":"333","target":"50","id":"493"},{"source":"574","target":"573","id":"1062"},{"source":"1420","target":"344","id":"4557"},{"source":"878","target":"645","id":"2076"},{"source":"1109","target":"177","id":"3001"},{"source":"1349","target":"628","id":"4140"},{"source":"504","target":"568","id":"1638"},{"source":"138","target":"133","id":"6170"},{"source":"971","target":"311","id":"2472"},{"source":"245","target":"53","id":"1735"},{"source":"1536","target":"104","id":"5287"},{"source":"1558","target":"79","id":"5446"},{"source":"1091","target":"119","id":"2914"},{"source":"714","target":"870","id":"6655"},{"source":"1601","target":"965","id":"5798"},{"source":"450","target":"272","id":"4689"},{"source":"535","target":"537","id":"2466"},{"source":"1253","target":"185","id":"6562"},{"source":"1457","target":"166","id":"4781"},{"source":"1162","target":"379","id":"3222"},{"source":"1179","target":"282","id":"3307"},{"source":"570","target":"571","id":"1039"},{"source":"1571","target":"1572","id":"5541"},{"source":"49","target":"182","id":"5183"},{"source":"865","target":"511","id":"2290"},{"source":"1082","target":"1083","id":"6574"},{"source":"484","target":"411","id":"5588"},{"source":"755","target":"211","id":"1591"},{"source":"988","target":"316","id":"2523"},{"source":"0","target":"1","id":"1"},{"source":"1261","target":"298","id":"3690"},{"source":"256","target":"296","id":"5165"},{"source":"787","target":"322","id":"6469"},{"source":"1164","target":"424","id":"3989"},{"source":"1222","target":"185","id":"3537"},{"source":"1263","target":"570","id":"3708"},{"source":"1560","target":"1561","id":"5481"},{"source":"462","target":"79","id":"772"},{"source":"578","target":"580","id":"5679"},{"source":"987","target":"335","id":"3049"},{"source":"311","target":"79","id":"468"},{"source":"758","target":"403","id":"5833"},{"source":"95","target":"82","id":"103"},{"source":"895","target":"64","id":"2138"},{"source":"944","target":"53","id":"2362"},{"source":"1660","target":"48","id":"6226"},{"source":"45","target":"46","id":"3235"},{"source":"808","target":"280","id":"1788"},{"source":"969","target":"970","id":"2470"},{"source":"1628","target":"405","id":"6019"},{"source":"1685","target":"1","id":"6395"},{"source":"100","target":"68","id":"1842"},{"source":"1219","target":"685","id":"3518"},{"source":"717","target":"713","id":"1459"},{"source":"901","target":"872","id":"2166"},{"source":"1050","target":"1402","id":"4443"},{"source":"1290","target":"325","id":"3835"},{"source":"492","target":"121","id":"814"},{"source":"754","target":"312","id":"5439"},{"source":"1411","target":"537","id":"4513"},{"source":"779","target":"84","id":"1687"},{"source":"180","target":"79","id":"201"},{"source":"1355","target":"296","id":"4176"},{"source":"469","target":"974","id":"3191"},{"source":"1001","target":"460","id":"2547"},{"source":"1454","target":"1","id":"5916"},{"source":"119","target":"114","id":"3176"},{"source":"910","target":"177","id":"2224"},{"source":"53","target":"68","id":"1110"},{"source":"1374","target":"406","id":"4269"},{"source":"1483","target":"648","id":"4992"},{"source":"1349","target":"177","id":"4141"},{"source":"998","target":"993","id":"2545"},{"source":"44","target":"46","id":"42"},{"source":"36","target":"40","id":"441"},{"source":"279","target":"61","id":"503"},{"source":"833","target":"715","id":"1888"},{"source":"752","target":"847","id":"1941"},{"source":"1604","target":"495","id":"5849"},{"source":"1191","target":"1025","id":"3399"},{"source":"1427","target":"1155","id":"4611"},{"source":"510","target":"262","id":"6333"},{"source":"1152","target":"996","id":"4495"},{"source":"1337","target":"48","id":"4072"},{"source":"730","target":"731","id":"1520"},{"source":"410","target":"280","id":"671"},{"source":"577","target":"581","id":"4393"},{"source":"1293","target":"113","id":"3843"},{"source":"681","target":"53","id":"1368"},{"source":"1346","target":"872","id":"4122"},{"source":"750","target":"312","id":"1585"},{"source":"871","target":"68","id":"2040"},{"source":"1405","target":"638","id":"4454"},{"source":"1426","target":"323","id":"4595"},{"source":"1713","target":"37","id":"6603"},{"source":"45","target":"852","id":"3234"},{"source":"1606","target":"1579","id":"5860"},{"source":"482","target":"334","id":"3839"},{"source":"587","target":"590","id":"1108"},{"source":"49","target":"281","id":"5190"},{"source":"65","target":"118","id":"2130"},{"source":"1362","target":"105","id":"4226"},{"source":"1512","target":"1","id":"5213"},{"source":"1269","target":"49","id":"3750"},{"source":"305","target":"309","id":"400"},{"source":"677","target":"53","id":"1361"},{"source":"1545","target":"772","id":"5353"},{"source":"73","target":"70","id":"1709"},{"source":"1146","target":"613","id":"3658"},{"source":"1168","target":"185","id":"3261"},{"source":"1178","target":"170","id":"3298"},{"source":"1571","target":"329","id":"5537"},{"source":"1230","target":"230","id":"3581"},{"source":"1577","target":"712","id":"5619"},{"source":"1397","target":"378","id":"4411"},{"source":"1344","target":"498","id":"4115"},{"source":"590","target":"267","id":"5169"},{"source":"1291","target":"1292","id":"5644"},{"source":"568","target":"708","id":"1644"},{"source":"1188","target":"76","id":"3382"},{"source":"853","target":"313","id":"1969"},{"source":"716","target":"109","id":"1454"},{"source":"1025","target":"65","id":"4625"},{"source":"1290","target":"826","id":"3836"},{"source":"1046","target":"1138","id":"6339"},{"source":"1632","target":"806","id":"6051"},{"source":"930","target":"150","id":"6080"},{"source":"1361","target":"217","id":"4203"},{"source":"639","target":"53","id":"1257"},{"source":"862","target":"772","id":"2628"},{"source":"1150","target":"976","id":"3134"},{"source":"1333","target":"623","id":"4047"},{"source":"273","target":"37","id":"5565"},{"source":"1457","target":"49","id":"4789"},{"source":"243","target":"247","id":"282"},{"source":"330","target":"294","id":"482"},{"source":"1657","target":"65","id":"6208"},{"source":"75","target":"76","id":"69"},{"source":"1223","target":"292","id":"3563"},{"source":"310","target":"45","id":"405"},{"source":"687","target":"96","id":"1383"},{"source":"187","target":"190","id":"218"},{"source":"109","target":"150","id":"5723"},{"source":"644","target":"743","id":"1554"},{"source":"374","target":"119","id":"5177"},{"source":"1248","target":"1607","id":"5899"},{"source":"1388","target":"974","id":"4358"},{"source":"1163","target":"422","id":"3217"},{"source":"1017","target":"277","id":"3978"},{"source":"1292","target":"1582","id":"5659"},{"source":"871","target":"61","id":"2041"},{"source":"1359","target":"1360","id":"4198"},{"source":"660","target":"888","id":"4043"},{"source":"424","target":"654","id":"4945"},{"source":"86","target":"87","id":"79"},{"source":"274","target":"40","id":"323"},{"source":"363","target":"364","id":"555"},{"source":"693","target":"97","id":"1399"},{"source":"1074","target":"262","id":"2845"},{"source":"597","target":"598","id":"1143"},{"source":"538","target":"51","id":"4661"},{"source":"408","target":"49","id":"873"},{"source":"114","target":"598","id":"2214"},{"source":"538","target":"50","id":"4660"},{"source":"1707","target":"1049","id":"6536"},{"source":"1606","target":"1282","id":"5861"},{"source":"1080","target":"301","id":"2849"},{"source":"1485","target":"498","id":"5003"},{"source":"169","target":"171","id":"191"},{"source":"1684","target":"281","id":"6389"},{"source":"1131","target":"1132","id":"3067"},{"source":"547","target":"463","id":"949"},{"source":"799","target":"405","id":"1758"},{"source":"931","target":"147","id":"2315"},{"source":"982","target":"439","id":"2512"},{"source":"266","target":"444","id":"3992"},{"source":"1401","target":"53","id":"4418"},{"source":"807","target":"198","id":"6517"},{"source":"634","target":"335","id":"1233"},{"source":"47","target":"48","id":"4429"},{"source":"949","target":"1","id":"2397"},{"source":"939","target":"53","id":"2348"},{"source":"833","target":"281","id":"1890"},{"source":"725","target":"65","id":"1498"},{"source":"1421","target":"723","id":"4569"},{"source":"761","target":"175","id":"1614"},{"source":"1464","target":"883","id":"4827"},{"source":"430","target":"37","id":"4834"},{"source":"1386","target":"974","id":"4343"},{"source":"118","target":"65","id":"1297"},{"source":"1315","target":"296","id":"4483"},{"source":"778","target":"96","id":"1675"},{"source":"1670","target":"561","id":"6288"},{"source":"1341","target":"1015","id":"4089"},{"source":"171","target":"567","id":"5259"},{"source":"631","target":"49","id":"1213"},{"source":"778","target":"53","id":"1680"},{"source":"983","target":"216","id":"4693"},{"source":"1408","target":"224","id":"6201"},{"source":"1230","target":"170","id":"3583"},{"source":"1246","target":"99","id":"6104"},{"source":"526","target":"524","id":"3544"},{"source":"833","target":"280","id":"1886"},{"source":"538","target":"200","id":"4658"},{"source":"328","target":"46","id":"476"},{"source":"1647","target":"85","id":"6136"},{"source":"1523","target":"1123","id":"5254"},{"source":"272","target":"209","id":"4682"},{"source":"754","target":"137","id":"5441"},{"source":"1324","target":"79","id":"4646"},{"source":"199","target":"200","id":"3321"},{"source":"786","target":"323","id":"3949"},{"source":"1151","target":"1152","id":"3139"},{"source":"723","target":"724","id":"1482"},{"source":"481","target":"281","id":"800"},{"source":"1209","target":"431","id":"3473"},{"source":"96","target":"95","id":"1808"},{"source":"370","target":"334","id":"4583"},{"source":"351","target":"1","id":"4447"},{"source":"47","target":"281","id":"4426"},{"source":"876","target":"1150","id":"3129"},{"source":"1278","target":"1279","id":"3798"},{"source":"1365","target":"494","id":"4244"},{"source":"1705","target":"68","id":"6504"},{"source":"1661","target":"76","id":"6235"},{"source":"1436","target":"1","id":"4706"},{"source":"1631","target":"1033","id":"6044"},{"source":"335","target":"533","id":"1057"},{"source":"1103","target":"79","id":"2967"},{"source":"119","target":"289","id":"3172"},{"source":"1468","target":"67","id":"4863"},{"source":"837","target":"444","id":"1905"},{"source":"541","target":"540","id":"2742"},{"source":"370","target":"533","id":"4585"},{"source":"1190","target":"96","id":"5058"},{"source":"1646","target":"313","id":"6133"},{"source":"336","target":"281","id":"3146"},{"source":"1197","target":"852","id":"3429"},{"source":"1434","target":"429","id":"4950"},{"source":"356","target":"508","id":"851"},{"source":"1608","target":"79","id":"5879"},{"source":"1408","target":"79","id":"6200"},{"source":"1558","target":"82","id":"5448"},{"source":"1631","target":"1403","id":"6039"},{"source":"134","target":"139","id":"150"},{"source":"1296","target":"484","id":"3858"},{"source":"587","target":"513","id":"1103"},{"source":"891","target":"325","id":"2112"},{"source":"1285","target":"49","id":"3816"},{"source":"1249","target":"1607","id":"5909"},{"source":"740","target":"50","id":"1538"},{"source":"708","target":"568","id":"2874"},{"source":"716","target":"713","id":"1455"},{"source":"1140","target":"426","id":"3088"},{"source":"993","target":"292","id":"4526"},{"source":"1360","target":"513","id":"6660"},{"source":"1589","target":"53","id":"5707"},{"source":"1324","target":"318","id":"4645"},{"source":"992","target":"313","id":"2533"},{"source":"569","target":"65","id":"2200"},{"source":"472","target":"177","id":"786"},{"source":"410","target":"48","id":"677"},{"source":"829","target":"556","id":"1867"},{"source":"927","target":"150","id":"2297"},{"source":"1108","target":"74","id":"2994"},{"source":"811","target":"175","id":"1803"},{"source":"629","target":"628","id":"2682"},{"source":"315","target":"296","id":"3508"},{"source":"1144","target":"296","id":"3101"},{"source":"1663","target":"287","id":"6242"},{"source":"1552","target":"128","id":"5395"},{"source":"120","target":"582","id":"4022"},{"source":"725","target":"610","id":"1503"},{"source":"801","target":"51","id":"4218"},{"source":"1231","target":"230","id":"5530"},{"source":"1554","target":"53","id":"5418"},{"source":"595","target":"65","id":"1132"},{"source":"1683","target":"20","id":"6380"},{"source":"1661","target":"1662","id":"6234"},{"source":"759","target":"695","id":"5775"},{"source":"264","target":"403","id":"1569"},{"source":"789","target":"798","id":"3028"},{"source":"124","target":"125","id":"132"},{"source":"1374","target":"983","id":"4268"},{"source":"66","target":"53","id":"2607"},{"source":"301","target":"182","id":"387"},{"source":"859","target":"817","id":"1998"},{"source":"714","target":"502","id":"6648"},{"source":"1144","target":"381","id":"3103"},{"source":"730","target":"48","id":"1519"},{"source":"412","target":"1","id":"2645"},{"source":"1242","target":"569","id":"3607"},{"source":"1431","target":"607","id":"4666"},{"source":"901","target":"111","id":"2171"},{"source":"1575","target":"801","id":"5604"},{"source":"1365","target":"757","id":"4239"},{"source":"11","target":"12","id":"13"},{"source":"896","target":"128","id":"4819"},{"source":"30","target":"24","id":"5045"},{"source":"466","target":"1","id":"777"},{"source":"1341","target":"65","id":"4094"},{"source":"1594","target":"172","id":"5759"},{"source":"198","target":"203","id":"232"},{"source":"252","target":"53","id":"761"},{"source":"633","target":"50","id":"1229"},{"source":"463","target":"177","id":"2634"},{"source":"1008","target":"344","id":"5692"},{"source":"684","target":"1","id":"1375"},{"source":"904","target":"567","id":"2206"},{"source":"1404","target":"272","id":"4536"},{"source":"366","target":"65","id":"5457"},{"source":"1015","target":"1","id":"3680"},{"source":"535","target":"533","id":"2467"},{"source":"249","target":"252","id":"290"},{"source":"393","target":"201","id":"643"},{"source":"1597","target":"409","id":"5784"},{"source":"268","target":"271","id":"315"},{"source":"722","target":"96","id":"1477"},{"source":"50","target":"105","id":"5477"},{"source":"53","target":"79","id":"1112"},{"source":"918","target":"919","id":"2261"},{"source":"195","target":"272","id":"5389"},{"source":"691","target":"692","id":"1394"},{"source":"1082","target":"367","id":"6572"},{"source":"484","target":"119","id":"5590"},{"source":"317","target":"325","id":"4545"},{"source":"146","target":"161","id":"1540"},{"source":"978","target":"979","id":"2504"},{"source":"1626","target":"79","id":"6010"},{"source":"1536","target":"708","id":"5288"},{"source":"421","target":"191","id":"3689"},{"source":"279","target":"49","id":"500"},{"source":"720","target":"79","id":"3511"},{"source":"359","target":"79","id":"554"},{"source":"1228","target":"1229","id":"3579"},{"source":"1661","target":"453","id":"6230"},{"source":"66","target":"61","id":"2606"},{"source":"943","target":"498","id":"2359"},{"source":"349","target":"133","id":"6279"},{"source":"370","target":"281","id":"4582"},{"source":"665","target":"666","id":"1329"},{"source":"1503","target":"1","id":"5105"},{"source":"459","target":"53","id":"764"},{"source":"1485","target":"120","id":"5004"},{"source":"980","target":"365","id":"2507"},{"source":"631","target":"50","id":"1214"},{"source":"438","target":"264","id":"1564"},{"source":"1620","target":"76","id":"5966"},{"source":"1500","target":"705","id":"5098"},{"source":"26","target":"253","id":"2881"},{"source":"707","target":"769","id":"1630"},{"source":"319","target":"182","id":"3897"},{"source":"944","target":"607","id":"2364"},{"source":"640","target":"1140","id":"5319"},{"source":"355","target":"712","id":"4008"},{"source":"902","target":"65","id":"3166"},{"source":"643","target":"68","id":"1267"},{"source":"1051","target":"96","id":"2759"},{"source":"1136","target":"600","id":"4389"},{"source":"744","target":"67","id":"1562"},{"source":"1677","target":"374","id":"6358"},{"source":"1296","target":"48","id":"3863"},{"source":"1509","target":"374","id":"5198"},{"source":"433","target":"434","id":"711"},{"source":"460","target":"515","id":"1162"},{"source":"542","target":"1","id":"933"},{"source":"357","target":"356","id":"918"},{"source":"625","target":"177","id":"1207"},{"source":"121","target":"122","id":"128"},{"source":"50","target":"66","id":"5474"},{"source":"1443","target":"68","id":"4720"},{"source":"1415","target":"979","id":"4535"},{"source":"517","target":"323","id":"3056"},{"source":"1084","target":"259","id":"2869"},{"source":"1142","target":"1718","id":"6621"},{"source":"1703","target":"1103","id":"6494"},{"source":"275","target":"270","id":"4322"},{"source":"178","target":"549","id":"1243"},{"source":"716","target":"502","id":"1453"},{"source":"264","target":"266","id":"1572"},{"source":"1264","target":"647","id":"3713"},{"source":"1435","target":"344","id":"4698"},{"source":"881","target":"498","id":"2090"},{"source":"1048","target":"539","id":"2744"},{"source":"1717","target":"203","id":"6622"},{"source":"773","target":"708","id":"1649"},{"source":"809","target":"61","id":"1800"},{"source":"1469","target":"510","id":"4870"},{"source":"1374","target":"53","id":"4265"},{"source":"492","target":"217","id":"817"},{"source":"543","target":"537","id":"939"},{"source":"165","target":"167","id":"187"},{"source":"1011","target":"1013","id":"2586"},{"source":"1320","target":"1322","id":"3996"},{"source":"495","target":"82","id":"6521"},{"source":"797","target":"397","id":"1749"},{"source":"281","target":"335","id":"3079"},{"source":"35","target":"273","id":"418"},{"source":"1298","target":"411","id":"3871"},{"source":"724","target":"79","id":"2831"},{"source":"852","target":"185","id":"3254"},{"source":"775","target":"1","id":"1674"},{"source":"914","target":"104","id":"2247"},{"source":"957","target":"961","id":"2429"},{"source":"1650","target":"532","id":"6162"},{"source":"779","target":"120","id":"1689"},{"source":"501","target":"50","id":"833"},{"source":"888","target":"889","id":"4032"},{"source":"54","target":"57","id":"52"},{"source":"277","target":"185","id":"339"},{"source":"912","target":"367","id":"2861"},{"source":"45","target":"311","id":"3231"},{"source":"1336","target":"53","id":"4062"},{"source":"1245","target":"690","id":"3625"},{"source":"193","target":"37","id":"222"},{"source":"1656","target":"1160","id":"6199"},{"source":"65","target":"67","id":"2125"},{"source":"53","target":"592","id":"1117"},{"source":"799","target":"370","id":"1761"},{"source":"750","target":"753","id":"1586"},{"source":"105","target":"64","id":"5381"},{"source":"1368","target":"1096","id":"4252"},{"source":"319","target":"79","id":"3895"},{"source":"1702","target":"1704","id":"6486"},{"source":"482","target":"600","id":"3842"},{"source":"1362","target":"591","id":"4222"},{"source":"779","target":"175","id":"1685"},{"source":"1119","target":"53","id":"6252"},{"source":"1332","target":"53","id":"4046"},{"source":"1352","target":"76","id":"4163"},{"source":"634","target":"636","id":"1235"},{"source":"181","target":"325","id":"3524"},{"source":"1280","target":"494","id":"3801"},{"source":"397","target":"51","id":"3910"},{"source":"837","target":"781","id":"1906"},{"source":"1285","target":"51","id":"3818"},{"source":"465","target":"368","id":"953"},{"source":"1353","target":"749","id":"4169"},{"source":"1694","target":"966","id":"6422"},{"source":"532","target":"49","id":"927"},{"source":"348","target":"1429","id":"4623"},{"source":"327","target":"306","id":"459"},{"source":"183","target":"79","id":"5118"},{"source":"1561","target":"119","id":"6509"},{"source":"1107","target":"62","id":"2983"},{"source":"487","target":"198","id":"812"},{"source":"1670","target":"74","id":"6282"},{"source":"153","target":"379","id":"2229"},{"source":"1279","target":"1249","id":"5631"},{"source":"68","target":"109","id":"108"},{"source":"135","target":"572","id":"1040"},{"source":"1481","target":"440","id":"4983"},{"source":"1701","target":"68","id":"6477"},{"source":"330","target":"181","id":"485"},{"source":"266","target":"403","id":"3994"},{"source":"483","target":"1308","id":"3923"},{"source":"622","target":"182","id":"4460"},{"source":"1706","target":"33","id":"6524"},{"source":"156","target":"82","id":"178"},{"source":"872","target":"150","id":"2052"},{"source":"263","target":"264","id":"307"},{"source":"383","target":"259","id":"634"},{"source":"664","target":"663","id":"3704"},{"source":"1091","target":"408","id":"2909"},{"source":"626","target":"177","id":"3225"},{"source":"1145","target":"20","id":"3111"},{"source":"795","target":"796","id":"1746"},{"source":"481","target":"484","id":"804"},{"source":"885","target":"79","id":"4004"},{"source":"1550","target":"915","id":"5373"},{"source":"689","target":"53","id":"6108"},{"source":"551","target":"167","id":"969"},{"source":"1570","target":"97","id":"5528"},{"source":"1082","target":"911","id":"6568"},{"source":"1339","target":"975","id":"4077"},{"source":"1294","target":"61","id":"3847"},{"source":"409","target":"200","id":"4651"},{"source":"716","target":"128","id":"1457"},{"source":"319","target":"296","id":"3893"},{"source":"1468","target":"65","id":"4862"},{"source":"199","target":"411","id":"3319"},{"source":"492","target":"128","id":"815"},{"source":"296","target":"319","id":"430"},{"source":"937","target":"698","id":"2341"},{"source":"976","target":"876","id":"3131"},{"source":"1594","target":"109","id":"5758"},{"source":"544","target":"1233","id":"6112"},{"source":"594","target":"53","id":"4875"},{"source":"927","target":"650","id":"2296"},{"source":"1452","target":"412","id":"4752"},{"source":"335","target":"574","id":"1053"},{"source":"1212","target":"82","id":"3481"},{"source":"1041","target":"598","id":"2706"},{"source":"26","target":"25","id":"2882"},{"source":"747","target":"20","id":"3776"},{"source":"869","target":"232","id":"2023"},{"source":"1656","target":"65","id":"6196"},{"source":"145","target":"82","id":"1000"},{"source":"1383","target":"185","id":"4317"},{"source":"1401","target":"695","id":"4420"},{"source":"294","target":"377","id":"903"},{"source":"69","target":"74","id":"68"},{"source":"44","target":"52","id":"48"},{"source":"643","target":"53","id":"1268"},{"source":"369","target":"47","id":"574"},{"source":"901","target":"68","id":"2173"},{"source":"322","target":"1311","id":"3942"},{"source":"725","target":"608","id":"1504"},{"source":"388","target":"537","id":"2392"},{"source":"1636","target":"1036","id":"6067"},{"source":"1070","target":"732","id":"2821"},{"source":"58","target":"59","id":"53"},{"source":"808","target":"409","id":"1793"},{"source":"550","target":"65","id":"963"},{"source":"884","target":"468","id":"2095"},{"source":"778","target":"84","id":"1681"},{"source":"694","target":"695","id":"1406"},{"source":"1288","target":"219","id":"3826"},{"source":"214","target":"215","id":"242"},{"source":"288","target":"68","id":"364"},{"source":"658","target":"659","id":"1319"},{"source":"785","target":"322","id":"1713"},{"source":"1643","target":"863","id":"6115"},{"source":"533","target":"1122","id":"6085"},{"source":"567","target":"428","id":"2722"},{"source":"1334","target":"401","id":"4054"},{"source":"1327","target":"567","id":"5873"},{"source":"905","target":"907","id":"2217"},{"source":"245","target":"131","id":"1729"},{"source":"750","target":"79","id":"1581"},{"source":"1040","target":"1034","id":"2696"},{"source":"431","target":"50","id":"708"},{"source":"1540","target":"344","id":"5308"},{"source":"72","target":"73","id":"1021"},{"source":"1397","target":"68","id":"4407"},{"source":"860","target":"348","id":"6118"},{"source":"1519","target":"607","id":"5243"},{"source":"387","target":"48","id":"637"},{"source":"676","target":"567","id":"1359"},{"source":"415","target":"416","id":"3642"},{"source":"295","target":"79","id":"3181"},{"source":"1616","target":"1130","id":"5947"},{"source":"262","target":"25","id":"5977"},{"source":"928","target":"150","id":"6079"},{"source":"1643","target":"861","id":"6116"},{"source":"830","target":"556","id":"1877"},{"source":"753","target":"185","id":"5133"},{"source":"688","target":"25","id":"1655"},{"source":"1432","target":"444","id":"4679"},{"source":"1198","target":"498","id":"3436"},{"source":"912","target":"307","id":"2858"},{"source":"290","target":"50","id":"1856"},{"source":"1456","target":"607","id":"4775"},{"source":"1632","target":"168","id":"6052"},{"source":"603","target":"166","id":"1427"},{"source":"1558","target":"1","id":"5447"},{"source":"1318","target":"1133","id":"3970"},{"source":"183","target":"325","id":"5121"},{"source":"1222","target":"79","id":"3533"},{"source":"577","target":"519","id":"4397"},{"source":"993","target":"995","id":"4527"},{"source":"294","target":"185","id":"904"},{"source":"1122","target":"335","id":"3043"},{"source":"182","target":"79","id":"4469"},{"source":"1161","target":"65","id":"3196"},{"source":"939","target":"167","id":"2350"},{"source":"569","target":"427","id":"2197"},{"source":"333","target":"279","id":"494"},{"source":"381","target":"185","id":"614"},{"source":"944","target":"49","id":"2368"},{"source":"965","target":"109","id":"2444"},{"source":"891","target":"51","id":"2114"},{"source":"843","target":"85","id":"1925"},{"source":"1179","target":"336","id":"3306"},{"source":"1705","target":"624","id":"6501"},{"source":"425","target":"427","id":"698"},{"source":"437","target":"423","id":"1314"},{"source":"1123","target":"1137","id":"3084"},{"source":"1620","target":"1111","id":"5963"},{"source":"1250","target":"301","id":"3634"},{"source":"1405","target":"1098","id":"4453"},{"source":"1250","target":"1253","id":"3640"},{"source":"1091","target":"65","id":"2912"},{"source":"753","target":"852","id":"5132"},{"source":"1696","target":"924","id":"6430"},{"source":"611","target":"287","id":"1180"},{"source":"382","target":"282","id":"622"},{"source":"285","target":"63","id":"352"},{"source":"1250","target":"1252","id":"3639"},{"source":"1298","target":"280","id":"3868"},{"source":"395","target":"76","id":"647"},{"source":"510","target":"555","id":"6332"},{"source":"797","target":"49","id":"1753"},{"source":"1349","target":"79","id":"4142"},{"source":"719","target":"721","id":"1470"},{"source":"1644","target":"963","id":"6123"},{"source":"1114","target":"1115","id":"3059"},{"source":"868","target":"498","id":"2019"},{"source":"1402","target":"206","id":"5838"},{"source":"472","target":"474","id":"784"},{"source":"589","target":"267","id":"1662"},{"source":"869","target":"132","id":"2024"},{"source":"268","target":"40","id":"317"},{"source":"1327","target":"422","id":"5868"},{"source":"1330","target":"662","id":"4036"},{"source":"971","target":"185","id":"2475"},{"source":"375","target":"363","id":"596"},{"source":"902","target":"131","id":"3168"},{"source":"142","target":"147","id":"167"},{"source":"1170","target":"988","id":"3270"},{"source":"1592","target":"101","id":"5745"},{"source":"1159","target":"238","id":"3185"},{"source":"1479","target":"391","id":"4975"},{"source":"904","target":"104","id":"2205"},{"source":"838","target":"281","id":"2454"},{"source":"208","target":"204","id":"5842"},{"source":"363","target":"64","id":"558"},{"source":"1457","target":"370","id":"4787"},{"source":"1657","target":"667","id":"6203"},{"source":"1681","target":"1682","id":"6379"},{"source":"855","target":"296","id":"1973"},{"source":"1404","target":"37","id":"4539"},{"source":"1216","target":"1217","id":"3494"},{"source":"1620","target":"849","id":"5967"},{"source":"1712","target":"302","id":"6598"},{"source":"104","target":"597","id":"2210"},{"source":"1712","target":"303","id":"6591"},{"source":"702","target":"541","id":"3884"},{"source":"1052","target":"206","id":"2766"},{"source":"1543","target":"109","id":"5340"},{"source":"258","target":"570","id":"1306"},{"source":"118","target":"131","id":"1299"},{"source":"192","target":"188","id":"213"},{"source":"1567","target":"571","id":"5503"},{"source":"1608","target":"148","id":"5878"},{"source":"1172","target":"455","id":"3275"},{"source":"223","target":"225","id":"255"},{"source":"411","target":"48","id":"1785"},{"source":"301","target":"302","id":"388"},{"source":"1652","target":"497","id":"6181"},{"source":"886","target":"883","id":"2103"},{"source":"1500","target":"958","id":"5099"},{"source":"887","target":"889","id":"2108"},{"source":"23","target":"25","id":"5803"},{"source":"1184","target":"1185","id":"3347"},{"source":"366","target":"560","id":"5455"},{"source":"770","target":"707","id":"5552"},{"source":"438","target":"202","id":"1567"},{"source":"1629","target":"547","id":"6025"},{"source":"846","target":"883","id":"5689"},{"source":"1189","target":"76","id":"3392"},{"source":"364","target":"316","id":"583"},{"source":"1484","target":"663","id":"4993"},{"source":"1223","target":"617","id":"3556"},{"source":"843","target":"711","id":"1923"},{"source":"249","target":"104","id":"286"},{"source":"143","target":"378","id":"609"},{"source":"1016","target":"66","id":"2592"},{"source":"1577","target":"1135","id":"5620"},{"source":"1314","target":"297","id":"4448"},{"source":"864","target":"53","id":"2008"},{"source":"1411","target":"1124","id":"4509"},{"source":"1571","target":"310","id":"5532"},{"source":"1665","target":"1666","id":"6272"},{"source":"65","target":"64","id":"2131"},{"source":"439","target":"441","id":"718"},{"source":"1066","target":"1062","id":"2804"},{"source":"519","target":"577","id":"1071"},{"source":"1175","target":"284","id":"3325"},{"source":"479","target":"1066","id":"4297"},{"source":"105","target":"592","id":"5384"},{"source":"1098","target":"1094","id":"2944"},{"source":"1459","target":"352","id":"4801"},{"source":"789","target":"49","id":"3037"},{"source":"1495","target":"806","id":"5080"},{"source":"458","target":"697","id":"5372"},{"source":"1372","target":"579","id":"4261"},{"source":"852","target":"46","id":"3252"},{"source":"1610","target":"5","id":"5887"},{"source":"1120","target":"1121","id":"3038"},{"source":"130","target":"131","id":"141"},{"source":"1530","target":"236","id":"5276"},{"source":"1672","target":"434","id":"6294"},{"source":"1621","target":"1386","id":"5982"},{"source":"206","target":"272","id":"2688"},{"source":"1044","target":"1046","id":"2728"},{"source":"243","target":"244","id":"279"},{"source":"1277","target":"335","id":"3793"},{"source":"895","target":"242","id":"2141"},{"source":"585","target":"110","id":"5577"},{"source":"727","target":"50","id":"1513"},{"source":"1672","target":"897","id":"6292"},{"source":"333","target":"335","id":"497"},{"source":"1615","target":"1282","id":"5925"},{"source":"1506","target":"1","id":"5835"},{"source":"1426","target":"517","id":"4593"},{"source":"1250","target":"294","id":"3635"},{"source":"650","target":"443","id":"1283"},{"source":"1267","target":"532","id":"3739"},{"source":"1689","target":"380","id":"6403"},{"source":"1593","target":"437","id":"5750"},{"source":"260","target":"261","id":"303"},{"source":"1329","target":"128","id":"5601"},{"source":"268","target":"273","id":"318"},{"source":"486","target":"313","id":"2502"},{"source":"65","target":"93","id":"2132"},{"source":"333","target":"334","id":"491"},{"source":"640","target":"642","id":"5322"},{"source":"262","target":"211","id":"5978"},{"source":"873","target":"65","id":"2055"},{"source":"677","target":"582","id":"1364"},{"source":"500","target":"228","id":"5795"},{"source":"947","target":"155","id":"2402"},{"source":"375","target":"51","id":"602"},{"source":"651","target":"570","id":"1303"},{"source":"1341","target":"1340","id":"4087"},{"source":"523","target":"294","id":"909"},{"source":"1209","target":"667","id":"3470"},{"source":"1351","target":"1138","id":"4160"},{"source":"1214","target":"94","id":"3484"},{"source":"961","target":"962","id":"4578"},{"source":"60","target":"61","id":"54"},{"source":"1134","target":"166","id":"3072"},{"source":"1582","target":"1580","id":"5648"},{"source":"1509","target":"1293","id":"5193"},{"source":"970","target":"82","id":"3096"},{"source":"592","target":"105","id":"4817"},{"source":"535","target":"543","id":"2463"},{"source":"328","target":"182","id":"477"},{"source":"1663","target":"667","id":"6241"},{"source":"156","target":"109","id":"177"},{"source":"1376","target":"1377","id":"4278"},{"source":"1658","target":"979","id":"6217"},{"source":"1070","target":"262","id":"2822"},{"source":"1363","target":"53","id":"4236"},{"source":"267","target":"113","id":"4437"},{"source":"1011","target":"1014","id":"2587"},{"source":"1071","target":"262","id":"2838"},{"source":"1597","target":"634","id":"5780"},{"source":"375","target":"113","id":"598"},{"source":"509","target":"61","id":"853"},{"source":"535","target":"364","id":"2461"},{"source":"75","target":"77","id":"70"},{"source":"410","target":"53","id":"673"},{"source":"608","target":"50","id":"1496"},{"source":"1038","target":"1037","id":"5030"},{"source":"1156","target":"68","id":"3156"},{"source":"326","target":"306","id":"465"},{"source":"1201","target":"1003","id":"4996"},{"source":"1543","target":"65","id":"5336"},{"source":"1152","target":"1314","id":"4497"},{"source":"459","target":"366","id":"770"},{"source":"117","target":"119","id":"123"},{"source":"668","target":"378","id":"1334"},{"source":"463","target":"1","id":"2638"},{"source":"1595","target":"1394","id":"5772"},{"source":"497","target":"109","id":"2625"},{"source":"944","target":"339","id":"2365"},{"source":"268","target":"36","id":"313"},{"source":"1161","target":"50","id":"3201"},{"source":"320","target":"322","id":"437"},{"source":"1652","target":"53","id":"6188"},{"source":"1629","target":"549","id":"6029"},{"source":"815","target":"607","id":"1820"},{"source":"252","target":"131","id":"756"},{"source":"1372","target":"167","id":"4259"},{"source":"781","target":"50","id":"2787"},{"source":"1109","target":"463","id":"3003"},{"source":"1230","target":"1181","id":"3582"},{"source":"581","target":"883","id":"4183"},{"source":"93","target":"64","id":"2158"},{"source":"550","target":"93","id":"964"},{"source":"1258","target":"1259","id":"3669"},{"source":"1705","target":"53","id":"6506"},{"source":"172","target":"101","id":"5735"},{"source":"69","target":"71","id":"65"},{"source":"421","target":"292","id":"3686"},{"source":"760","target":"53","id":"1608"},{"source":"931","target":"170","id":"2313"},{"source":"592","target":"96","id":"4815"},{"source":"874","target":"104","id":"2065"},{"source":"1674","target":"53","id":"6309"},{"source":"300","target":"299","id":"3008"},{"source":"1326","target":"424","id":"4029"},{"source":"483","target":"801","id":"3926"},{"source":"1047","target":"463","id":"4330"},{"source":"1716","target":"1718","id":"6618"},{"source":"1327","target":"654","id":"5874"},{"source":"573","target":"335","id":"1045"},{"source":"1705","target":"1022","id":"6502"},{"source":"96","target":"812","id":"1809"},{"source":"1530","target":"1018","id":"5277"},{"source":"625","target":"463","id":"1209"},{"source":"402","target":"82","id":"653"},{"source":"88","target":"79","id":"80"},{"source":"925","target":"119","id":"2286"},{"source":"778","target":"175","id":"1678"},{"source":"860","target":"113","id":"6120"},{"source":"352","target":"353","id":"536"},{"source":"966","target":"256","id":"5823"},{"source":"1205","target":"571","id":"3457"},{"source":"224","target":"225","id":"2828"},{"source":"729","target":"229","id":"1514"},{"source":"859","target":"860","id":"1995"},{"source":"1421","target":"311","id":"4567"},{"source":"9","target":"1","id":"10"},{"source":"547","target":"177","id":"945"},{"source":"339","target":"53","id":"4209"},{"source":"1555","target":"644","id":"5425"},{"source":"328","target":"185","id":"478"},{"source":"1156","target":"65","id":"3162"},{"source":"694","target":"49","id":"1407"},{"source":"552","target":"287","id":"4895"},{"source":"502","target":"444","id":"5075"},{"source":"1302","target":"1300","id":"6400"},{"source":"1589","target":"118","id":"5708"},{"source":"1577","target":"715","id":"5617"},{"source":"1140","target":"82","id":"3090"},{"source":"675","target":"280","id":"6633"},{"source":"1401","target":"49","id":"4421"},{"source":"924","target":"1542","id":"5328"},{"source":"468","target":"159","id":"778"},{"source":"1169","target":"824","id":"3262"},{"source":"38","target":"275","id":"1287"},{"source":"1493","target":"262","id":"5056"},{"source":"1180","target":"411","id":"3315"},{"source":"1552","target":"217","id":"5397"},{"source":"1428","target":"196","id":"4617"},{"source":"1246","target":"53","id":"6105"},{"source":"1480","target":"1316","id":"4979"},{"source":"34","target":"38","id":"36"},{"source":"1012","target":"53","id":"5569"},{"source":"363","target":"67","id":"560"},{"source":"134","target":"140","id":"154"},{"source":"1652","target":"236","id":"6179"},{"source":"1294","target":"868","id":"3849"},{"source":"161","target":"435","id":"5310"},{"source":"375","target":"116","id":"603"},{"source":"1224","target":"215","id":"3565"},{"source":"903","target":"93","id":"2179"},{"source":"139","target":"135","id":"157"},{"source":"359","target":"177","id":"553"},{"source":"1532","target":"94","id":"5279"},{"source":"1135","target":"857","id":"3077"},{"source":"1683","target":"109","id":"6382"},{"source":"801","target":"48","id":"4215"},{"source":"857","target":"858","id":"2017"},{"source":"497","target":"166","id":"2626"},{"source":"1625","target":"934","id":"6006"},{"source":"1582","target":"1292","id":"5646"},{"source":"1343","target":"200","id":"4111"},{"source":"170","target":"915","id":"4792"},{"source":"1292","target":"1580","id":"5660"},{"source":"1469","target":"698","id":"4871"},{"source":"925","target":"552","id":"2288"},{"source":"1163","target":"424","id":"3215"},{"source":"747","target":"170","id":"3782"},{"source":"133","target":"138","id":"148"},{"source":"1455","target":"65","id":"4764"},{"source":"1397","target":"155","id":"4406"},{"source":"742","target":"989","id":"5147"},{"source":"532","target":"538","id":"926"},{"source":"935","target":"109","id":"4797"},{"source":"671","target":"131","id":"1348"},{"source":"1604","target":"82","id":"5848"},{"source":"125","target":"123","id":"133"},{"source":"1368","target":"1097","id":"4253"},{"source":"165","target":"168","id":"188"},{"source":"1525","target":"1526","id":"5263"},{"source":"1573","target":"48","id":"5543"},{"source":"703","target":"704","id":"3889"},{"source":"1688","target":"1","id":"6472"},{"source":"1713","target":"272","id":"6601"},{"source":"944","target":"715","id":"2363"},{"source":"1276","target":"281","id":"3773"},{"source":"595","target":"109","id":"1137"},{"source":"1182","target":"200","id":"3335"},{"source":"1086","target":"105","id":"2896"},{"source":"1472","target":"156","id":"4920"},{"source":"1625","target":"164","id":"6008"},{"source":"1004","target":"444","id":"2568"},{"source":"1624","target":"159","id":"5990"},{"source":"1588","target":"498","id":"5699"},{"source":"1608","target":"803","id":"5881"},{"source":"1650","target":"1292","id":"6160"},{"source":"93","target":"82","id":"2164"},{"source":"288","target":"51","id":"363"},{"source":"1083","target":"1082","id":"5931"},{"source":"1097","target":"312","id":"2954"},{"source":"1202","target":"648","id":"5000"},{"source":"52","target":"68","id":"5765"},{"source":"63","target":"65","id":"995"},{"source":"318","target":"296","id":"531"},{"source":"628","target":"629","id":"4153"},{"source":"1675","target":"68","id":"6323"},{"source":"1345","target":"182","id":"4119"},{"source":"1350","target":"906","id":"4147"},{"source":"1592","target":"567","id":"5744"},{"source":"1276","target":"335","id":"3771"},{"source":"393","target":"394","id":"644"},{"source":"24","target":"947","id":"5815"},{"source":"1652","target":"284","id":"6185"},{"source":"242","target":"153","id":"2226"},{"source":"273","target":"274","id":"5563"},{"source":"901","target":"451","id":"2165"},{"source":"1180","target":"406","id":"3312"},{"source":"1670","target":"72","id":"6287"},{"source":"788","target":"48","id":"1720"},{"source":"1051","target":"949","id":"2760"},{"source":"816","target":"498","id":"1992"},{"source":"299","target":"361","id":"1248"},{"source":"908","target":"907","id":"3514"},{"source":"1052","target":"209","id":"2772"},{"source":"472","target":"79","id":"787"},{"source":"334","target":"1451","id":"4742"},{"source":"1537","target":"458","id":"5298"},{"source":"741","target":"280","id":"1543"},{"source":"589","target":"513","id":"1666"},{"source":"39","target":"313","id":"4305"},{"source":"825","target":"490","id":"5853"},{"source":"1017","target":"457","id":"3979"},{"source":"369","target":"267","id":"575"},{"source":"1663","target":"455","id":"6239"},{"source":"1118","target":"166","id":"3023"},{"source":"295","target":"292","id":"3178"},{"source":"252","target":"104","id":"757"},{"source":"1167","target":"1157","id":"3255"},{"source":"1224","target":"495","id":"3567"},{"source":"1713","target":"209","id":"6604"},{"source":"1420","target":"280","id":"4558"},{"source":"1381","target":"1152","id":"4291"},{"source":"695","target":"731","id":"4955"},{"source":"1226","target":"1197","id":"3573"},{"source":"745","target":"746","id":"1575"},{"source":"250","target":"252","id":"3363"},{"source":"1499","target":"606","id":"5092"},{"source":"1618","target":"281","id":"5955"},{"source":"598","target":"597","id":"1982"},{"source":"182","target":"296","id":"4468"},{"source":"640","target":"174","id":"5317"},{"source":"407","target":"216","id":"664"},{"source":"637","target":"79","id":"1251"},{"source":"132","target":"1442","id":"5346"},{"source":"315","target":"298","id":"3507"},{"source":"778","target":"65","id":"1676"},{"source":"1477","target":"424","id":"4938"},{"source":"780","target":"174","id":"1691"},{"source":"201","target":"391","id":"4758"},{"source":"755","target":"368","id":"1592"},{"source":"1455","target":"62","id":"4769"},{"source":"904","target":"131","id":"2203"},{"source":"918","target":"65","id":"2257"},{"source":"361","target":"211","id":"1958"},{"source":"1487","target":"1488","id":"5016"},{"source":"6","target":"5","id":"8"},{"source":"1307","target":"167","id":"3919"},{"source":"461","target":"118","id":"2620"},{"source":"1312","target":"296","id":"3931"},{"source":"1334","target":"1126","id":"4052"},{"source":"609","target":"161","id":"3066"},{"source":"775","target":"777","id":"1673"},{"source":"528","target":"526","id":"3553"},{"source":"322","target":"785","id":"3941"},{"source":"283","target":"281","id":"6350"},{"source":"1056","target":"1057","id":"2778"},{"source":"118","target":"567","id":"1292"},{"source":"1478","target":"456","id":"4966"},{"source":"1556","target":"1557","id":"5433"},{"source":"1034","target":"272","id":"2677"},{"source":"1264","target":"1","id":"3714"},{"source":"633","target":"104","id":"1227"},{"source":"580","target":"577","id":"1075"},{"source":"303","target":"182","id":"391"},{"source":"950","target":"79","id":"2398"},{"source":"1347","target":"1208","id":"4131"},{"source":"92","target":"65","id":"86"},{"source":"893","target":"181","id":"2559"},{"source":"298","target":"300","id":"381"},{"source":"1588","target":"1379","id":"5701"},{"source":"1025","target":"258","id":"4629"},{"source":"1119","target":"49","id":"6258"},{"source":"793","target":"53","id":"2964"},{"source":"279","target":"336","id":"507"},{"source":"1060","target":"1114","id":"3016"},{"source":"866","target":"1018","id":"2612"},{"source":"583","target":"577","id":"1088"},{"source":"526","target":"528","id":"3543"},{"source":"67","target":"68","id":"2709"},{"source":"1102","target":"638","id":"3500"},{"source":"1363","target":"48","id":"4230"},{"source":"1633","target":"435","id":"6060"},{"source":"326","target":"315","id":"462"},{"source":"794","target":"50","id":"1741"},{"source":"745","target":"747","id":"1576"},{"source":"837","target":"839","id":"1907"},{"source":"681","target":"106","id":"1370"},{"source":"1585","target":"1","id":"5673"},{"source":"496","target":"166","id":"821"},{"source":"912","target":"653","id":"2859"},{"source":"176","target":"177","id":"196"},{"source":"1266","target":"806","id":"3730"},{"source":"1231","target":"354","id":"5531"},{"source":"510","target":"436","id":"6334"},{"source":"1434","target":"272","id":"4949"},{"source":"1471","target":"65","id":"4909"},{"source":"881","target":"883","id":"2085"},{"source":"463","target":"906","id":"2637"},{"source":"973","target":"1","id":"2479"},{"source":"267","target":"119","id":"4439"},{"source":"272","target":"1434","id":"4684"},{"source":"828","target":"65","id":"1862"},{"source":"1116","target":"1115","id":"5935"},{"source":"1323","target":"885","id":"5958"},{"source":"192","target":"191","id":"215"},{"source":"1478","target":"582","id":"4964"},{"source":"633","target":"635","id":"1228"},{"source":"1032","target":"82","id":"2665"},{"source":"745","target":"749","id":"1579"},{"source":"823","target":"82","id":"1845"},{"source":"1498","target":"781","id":"5083"},{"source":"727","target":"728","id":"1512"},{"source":"1065","target":"1063","id":"2801"},{"source":"728","target":"114","id":"5453"},{"source":"1226","target":"613","id":"3571"},{"source":"868","target":"109","id":"2020"},{"source":"1636","target":"1297","id":"6068"},{"source":"889","target":"888","id":"4403"},{"source":"884","target":"53","id":"2096"},{"source":"1244","target":"49","id":"3616"},{"source":"1483","target":"1003","id":"4989"},{"source":"641","target":"642","id":"5324"},{"source":"808","target":"48","id":"1792"},{"source":"1319","target":"68","id":"3980"},{"source":"216","target":"1","id":"543"},{"source":"1198","target":"281","id":"3437"},{"source":"1169","target":"238","id":"3263"},{"source":"269","target":"37","id":"333"},{"source":"990","target":"950","id":"2531"},{"source":"256","target":"182","id":"5161"},{"source":"1470","target":"65","id":"4902"},{"source":"809","target":"279","id":"1798"},{"source":"35","target":"38","id":"415"},{"source":"938","target":"975","id":"2483"},{"source":"955","target":"335","id":"2423"},{"source":"607","target":"65","id":"1485"},{"source":"1396","target":"211","id":"4384"},{"source":"1210","target":"290","id":"6444"},{"source":"1571","target":"367","id":"5539"},{"source":"299","target":"177","id":"1246"},{"source":"1710","target":"122","id":"6555"},{"source":"1692","target":"1693","id":"6420"},{"source":"547","target":"548","id":"946"},{"source":"248","target":"1","id":"5349"},{"source":"671","target":"105","id":"1351"},{"source":"1477","target":"422","id":"4931"},{"source":"553","target":"68","id":"982"},{"source":"1626","target":"50","id":"6015"},{"source":"580","target":"379","id":"1082"},{"source":"393","target":"216","id":"645"},{"source":"461","target":"65","id":"2622"},{"source":"652","target":"653","id":"1309"},{"source":"900","target":"652","id":"2153"},{"source":"460","target":"608","id":"1164"},{"source":"1472","target":"158","id":"4921"},{"source":"1066","target":"79","id":"2802"},{"source":"833","target":"48","id":"1892"},{"source":"951","target":"287","id":"2409"},{"source":"1664","target":"618","id":"6248"},{"source":"865","target":"926","id":"2292"},{"source":"1258","target":"524","id":"3670"},{"source":"576","target":"582","id":"2375"},{"source":"619","target":"298","id":"6032"},{"source":"1236","target":"622","id":"3594"},{"source":"687","target":"65","id":"1384"},{"source":"1418","target":"758","id":"4556"},{"source":"249","target":"250","id":"287"},{"source":"520","target":"521","id":"897"},{"source":"368","target":"177","id":"3004"},{"source":"1011","target":"408","id":"2583"},{"source":"1359","target":"696","id":"4193"},{"source":"534","target":"532","id":"6540"},{"source":"615","target":"1039","id":"4335"},{"source":"1427","target":"65","id":"4609"},{"source":"514","target":"498","id":"890"},{"source":"1611","target":"1614","id":"5920"},{"source":"873","target":"874","id":"2054"},{"source":"1210","target":"1077","id":"6445"},{"source":"442","target":"445","id":"721"},{"source":"1117","target":"177","id":"3020"},{"source":"1658","target":"295","id":"6218"},{"source":"60","target":"68","id":"63"},{"source":"1492","target":"53","id":"5049"},{"source":"625","target":"626","id":"1204"},{"source":"36","target":"122","id":"445"},{"source":"296","target":"292","id":"433"},{"source":"441","target":"129","id":"4374"},{"source":"1278","target":"227","id":"3796"},{"source":"675","target":"512","id":"6634"},{"source":"1708","target":"49","id":"6542"},{"source":"1110","target":"1111","id":"3012"},{"source":"1341","target":"444","id":"4096"},{"source":"1663","target":"262","id":"6243"},{"source":"830","target":"237","id":"1874"},{"source":"1174","target":"1126","id":"3290"},{"source":"1104","target":"177","id":"2975"},{"source":"802","target":"79","id":"1767"},{"source":"957","target":"502","id":"2431"},{"source":"717","target":"502","id":"1458"},{"source":"367","target":"309","id":"4319"},{"source":"1495","target":"1474","id":"5081"},{"source":"1401","target":"279","id":"4417"},{"source":"1047","target":"207","id":"4332"},{"source":"1016","target":"1017","id":"2594"},{"source":"321","target":"296","id":"731"},{"source":"754","target":"185","id":"5440"},{"source":"397","target":"49","id":"3908"},{"source":"750","target":"754","id":"1587"},{"source":"383","target":"385","id":"628"},{"source":"929","target":"53","id":"2303"},{"source":"939","target":"466","id":"2347"},{"source":"48","target":"405","id":"4639"},{"source":"676","target":"674","id":"1360"},{"source":"904","target":"427","id":"2207"},{"source":"1673","target":"597","id":"6299"},{"source":"1664","target":"485","id":"6246"},{"source":"1163","target":"428","id":"3214"},{"source":"607","target":"515","id":"1488"},{"source":"1257","target":"1","id":"3661"},{"source":"965","target":"964","id":"2443"},{"source":"590","target":"116","id":"5174"},{"source":"82","target":"128","id":"6438"},{"source":"1083","target":"367","id":"5929"},{"source":"1122","target":"388","id":"3044"},{"source":"851","target":"312","id":"1962"},{"source":"1460","target":"1461","id":"4807"},{"source":"79","target":"638","id":"1256"},{"source":"1432","target":"1395","id":"4680"},{"source":"1097","target":"324","id":"2952"},{"source":"593","target":"82","id":"1128"},{"source":"509","target":"365","id":"856"},{"source":"310","target":"46","id":"407"},{"source":"470","target":"471","id":"780"},{"source":"1705","target":"174","id":"6499"},{"source":"1498","target":"567","id":"5086"},{"source":"672","target":"118","id":"5403"},{"source":"1129","target":"323","id":"4598"},{"source":"167","target":"698","id":"2340"},{"source":"1574","target":"65","id":"5560"},{"source":"335","target":"532","id":"1058"},{"source":"1571","target":"46","id":"5538"},{"source":"495","target":"493","id":"6519"},{"source":"377","target":"295","id":"2151"},{"source":"920","target":"646","id":"2263"},{"source":"881","target":"53","id":"2088"},{"source":"801","target":"956","id":"4211"},{"source":"411","target":"807","id":"1779"},{"source":"1084","target":"397","id":"2870"},{"source":"1203","target":"238","id":"3453"},{"source":"409","target":"405","id":"4649"},{"source":"1184","target":"133","id":"3349"},{"source":"568","target":"504","id":"1642"},{"source":"1124","target":"896","id":"4846"},{"source":"1663","target":"457","id":"6244"},{"source":"550","target":"53","id":"967"},{"source":"714","target":"444","id":"6654"},{"source":"1706","target":"493","id":"6523"},{"source":"1458","target":"170","id":"4796"},{"source":"504","target":"708","id":"1640"},{"source":"716","target":"714","id":"1456"},{"source":"1115","target":"1116","id":"3062"},{"source":"1718","target":"1121","id":"6629"},{"source":"1026","target":"1","id":"2649"},{"source":"342","target":"310","id":"519"},{"source":"549","target":"463","id":"1277"},{"source":"829","target":"101","id":"1873"},{"source":"1650","target":"535","id":"6163"},{"source":"373","target":"364","id":"589"},{"source":"400","target":"136","id":"2389"},{"source":"1589","target":"104","id":"5712"},{"source":"1591","target":"109","id":"5733"},{"source":"841","target":"48","id":"2446"},{"source":"22","target":"25","id":"25"},{"source":"971","target":"972","id":"2474"},{"source":"768","target":"504","id":"6392"},{"source":"1605","target":"567","id":"5857"},{"source":"48","target":"49","id":"4633"},{"source":"129","target":"82","id":"139"},{"source":"142","target":"51","id":"166"},{"source":"1455","target":"50","id":"4765"},{"source":"760","target":"65","id":"1609"},{"source":"939","target":"68","id":"2346"},{"source":"1455","target":"53","id":"4771"},{"source":"545","target":"1","id":"943"},{"source":"537","target":"533","id":"3334"},{"source":"520","target":"1","id":"898"},{"source":"1212","target":"175","id":"3483"},{"source":"1721","target":"166","id":"6669"},{"source":"795","target":"50","id":"1745"},{"source":"437","target":"655","id":"1316"},{"source":"1054","target":"79","id":"2773"},{"source":"490","target":"491","id":"813"},{"source":"308","target":"162","id":"567"},{"source":"302","target":"301","id":"5113"},{"source":"1048","target":"702","id":"2747"},{"source":"224","target":"223","id":"2825"},{"source":"527","target":"525","id":"3547"},{"source":"1702","target":"1646","id":"6484"},{"source":"750","target":"752","id":"1583"},{"source":"1428","target":"752","id":"4619"},{"source":"1457","target":"267","id":"4785"},{"source":"310","target":"185","id":"408"},{"source":"388","target":"533","id":"2394"},{"source":"986","target":"985","id":"2521"},{"source":"994","target":"166","id":"2539"},{"source":"250","target":"451","id":"3370"},{"source":"553","target":"67","id":"989"},{"source":"906","target":"177","id":"2219"},{"source":"321","target":"194","id":"734"},{"source":"669","target":"65","id":"1335"},{"source":"314","target":"317","id":"426"},{"source":"699","target":"700","id":"1416"},{"source":"912","target":"1082","id":"2862"},{"source":"838","target":"49","id":"2456"},{"source":"222","target":"97","id":"249"},{"source":"1573","target":"51","id":"5547"},{"source":"342","target":"182","id":"521"},{"source":"1249","target":"618","id":"5910"},{"source":"30","target":"25","id":"5042"},{"source":"1540","target":"1466","id":"5306"},{"source":"257","target":"238","id":"299"},{"source":"1409","target":"1248","id":"4503"},{"source":"862","target":"118","id":"2629"},{"source":"274","target":"269","id":"325"},{"source":"673","target":"541","id":"1354"},{"source":"1317","target":"391","id":"6497"},{"source":"1011","target":"53","id":"2584"},{"source":"1105","target":"53","id":"2979"},{"source":"929","target":"25","id":"2302"},{"source":"1720","target":"144","id":"6665"},{"source":"1120","target":"5","id":"3040"},{"source":"1543","target":"99","id":"5334"},{"source":"1325","target":"1113","id":"4011"},{"source":"1428","target":"137","id":"4616"},{"source":"1312","target":"786","id":"3936"},{"source":"510","target":"554","id":"6336"},{"source":"1420","target":"568","id":"4560"},{"source":"413","target":"418","id":"684"},{"source":"85","target":"128","id":"1930"},{"source":"161","target":"641","id":"5311"},{"source":"735","target":"120","id":"1531"},{"source":"1191","target":"408","id":"3403"},{"source":"939","target":"467","id":"2352"},{"source":"68","target":"65","id":"110"},{"source":"1573","target":"484","id":"5548"},{"source":"273","target":"38","id":"5566"},{"source":"977","target":"82","id":"2496"},{"source":"461","target":"591","id":"2619"},{"source":"1673","target":"498","id":"6302"},{"source":"1226","target":"296","id":"3574"},{"source":"105","target":"50","id":"5385"},{"source":"1397","target":"379","id":"4412"},{"source":"1536","target":"1165","id":"5290"},{"source":"411","target":"409","id":"1777"},{"source":"864","target":"66","id":"2011"},{"source":"250","target":"65","id":"3366"},{"source":"1290","target":"626","id":"3834"},{"source":"220","target":"221","id":"247"},{"source":"682","target":"640","id":"6168"},{"source":"453","target":"249","id":"1616"},{"source":"1076","target":"1078","id":"3697"},{"source":"1360","target":"119","id":"6658"},{"source":"92","target":"53","id":"84"},{"source":"483","target":"397","id":"3925"},{"source":"719","target":"141","id":"1472"},{"source":"334","target":"50","id":"4743"},{"source":"1025","target":"120","id":"4626"},{"source":"1599","target":"1526","id":"5792"},{"source":"1201","target":"159","id":"4998"},{"source":"205","target":"900","id":"2678"},{"source":"882","target":"253","id":"2884"},{"source":"268","target":"34","id":"319"},{"source":"245","target":"50","id":"1732"},{"source":"1186","target":"53","id":"3354"},{"source":"235","target":"53","id":"269"},{"source":"1342","target":"50","id":"4097"},{"source":"499","target":"500","id":"830"},{"source":"1644","target":"502","id":"6129"},{"source":"1618","target":"896","id":"5951"},{"source":"141","target":"79","id":"6211"},{"source":"118","target":"93","id":"1298"},{"source":"429","target":"207","id":"4691"},{"source":"515","target":"607","id":"1170"},{"source":"957","target":"960","id":"2428"},{"source":"1145","target":"61","id":"3113"},{"source":"1152","target":"417","id":"4498"},{"source":"723","target":"309","id":"1483"},{"source":"714","target":"85","id":"6652"},{"source":"279","target":"282","id":"498"},{"source":"1674","target":"104","id":"6314"},{"source":"398","target":"50","id":"5160"},{"source":"1122","target":"82","id":"3041"},{"source":"1660","target":"959","id":"6222"},{"source":"957","target":"962","id":"2432"},{"source":"1167","target":"852","id":"3256"},{"source":"1629","target":"463","id":"6024"},{"source":"187","target":"192","id":"216"},{"source":"1638","target":"367","id":"6563"},{"source":"1658","target":"1659","id":"6219"},{"source":"1672","target":"598","id":"6295"},{"source":"311","target":"224","id":"469"},{"source":"1082","target":"309","id":"6571"},{"source":"1672","target":"87","id":"6293"},{"source":"1082","target":"913","id":"6573"},{"source":"1637","target":"1638","id":"6077"},{"source":"373","target":"116","id":"587"},{"source":"1537","target":"109","id":"5299"},{"source":"1156","target":"515","id":"3161"},{"source":"891","target":"181","id":"2118"},{"source":"1278","target":"313","id":"3797"},{"source":"1689","target":"113","id":"6406"},{"source":"815","target":"403","id":"1819"},{"source":"346","target":"646","id":"1272"},{"source":"1165","target":"65","id":"5230"},{"source":"1665","target":"239","id":"6270"},{"source":"1690","target":"314","id":"6415"},{"source":"793","target":"170","id":"2966"},{"source":"574","target":"281","id":"1064"},{"source":"285","target":"286","id":"355"},{"source":"1301","target":"531","id":"6399"},{"source":"1515","target":"163","id":"6565"},{"source":"1341","target":"806","id":"4091"},{"source":"1536","target":"96","id":"5285"},{"source":"1134","target":"281","id":"3074"},{"source":"1071","target":"1075","id":"2836"},{"source":"1280","target":"759","id":"3804"},{"source":"977","target":"48","id":"2495"},{"source":"1104","target":"626","id":"2971"},{"source":"892","target":"185","id":"5145"},{"source":"219","target":"324","id":"449"},{"source":"437","target":"654","id":"1315"},{"source":"773","target":"768","id":"1651"},{"source":"1049","target":"567","id":"2755"},{"source":"1397","target":"1165","id":"4405"},{"source":"153","target":"120","id":"2228"},{"source":"61","target":"133","id":"870"},{"source":"819","target":"79","id":"1835"},{"source":"173","target":"95","id":"194"},{"source":"1336","target":"279","id":"4060"},{"source":"1084","target":"51","id":"2867"},{"source":"64","target":"65","id":"1826"},{"source":"329","target":"79","id":"3241"},{"source":"1254","target":"42","id":"3646"},{"source":"578","target":"68","id":"5677"},{"source":"671","target":"672","id":"1352"},{"source":"143","target":"120","id":"610"},{"source":"845","target":"707","id":"1935"},{"source":"786","target":"322","id":"3948"},{"source":"42","target":"283","id":"348"},{"source":"1360","target":"51","id":"6661"},{"source":"598","target":"104","id":"1984"},{"source":"843","target":"502","id":"1921"},{"source":"1429","target":"693","id":"4967"},{"source":"68","target":"53","id":"109"},{"source":"1016","target":"53","id":"2590"},{"source":"1316","target":"391","id":"4969"},{"source":"291","target":"295","id":"372"},{"source":"716","target":"444","id":"1452"},{"source":"823","target":"824","id":"1847"},{"source":"756","target":"53","id":"1601"},{"source":"49","target":"280","id":"5187"},{"source":"1637","target":"313","id":"6075"},{"source":"1513","target":"65","id":"5216"},{"source":"1479","target":"68","id":"4972"},{"source":"1615","target":"421","id":"5923"},{"source":"1148","target":"351","id":"3123"},{"source":"792","target":"61","id":"1725"},{"source":"394","target":"391","id":"4930"},{"source":"502","target":"870","id":"5077"},{"source":"42","target":"280","id":"342"},{"source":"1459","target":"50","id":"4798"},{"source":"937","target":"469","id":"2344"},{"source":"1594","target":"68","id":"5761"},{"source":"1313","target":"292","id":"3955"},{"source":"732","target":"1386","id":"5970"},{"source":"1087","target":"79","id":"5443"},{"source":"603","target":"411","id":"1424"},{"source":"513","target":"335","id":"5207"},{"source":"797","target":"405","id":"1748"},{"source":"1162","target":"120","id":"3221"},{"source":"326","target":"79","id":"466"},{"source":"1286","target":"1287","id":"3825"},{"source":"1696","target":"179","id":"6429"},{"source":"472","target":"464","id":"781"},{"source":"639","target":"554","id":"1258"},{"source":"329","target":"45","id":"3243"},{"source":"1273","target":"1","id":"3765"},{"source":"654","target":"656","id":"3421"},{"source":"1438","target":"1440","id":"4709"},{"source":"1707","target":"656","id":"6538"},{"source":"690","target":"163","id":"1388"},{"source":"689","target":"104","id":"6110"},{"source":"837","target":"495","id":"1910"},{"source":"1247","target":"1152","id":"3630"},{"source":"92","target":"67","id":"88"},{"source":"836","target":"490","id":"1900"},{"source":"345","target":"349","id":"528"},{"source":"425","target":"104","id":"699"},{"source":"197","target":"198","id":"226"},{"source":"1304","target":"444","id":"3899"},{"source":"714","target":"713","id":"6649"},{"source":"219","target":"79","id":"448"},{"source":"554","target":"510","id":"2050"},{"source":"426","target":"104","id":"1031"},{"source":"644","target":"645","id":"1551"},{"source":"1616","target":"1617","id":"5948"},{"source":"877","target":"107","id":"2071"},{"source":"922","target":"91","id":"2273"},{"source":"311","target":"46","id":"471"},{"source":"869","target":"85","id":"2028"},{"source":"244","target":"645","id":"1667"},{"source":"1276","target":"20","id":"3768"},{"source":"1626","target":"1627","id":"6014"},{"source":"914","target":"251","id":"2249"},{"source":"2","target":"3","id":"3"},{"source":"763","target":"764","id":"3441"},{"source":"422","target":"1","id":"694"},{"source":"118","target":"82","id":"1293"},{"source":"352","target":"166","id":"535"},{"source":"1421","target":"1422","id":"4571"},{"source":"133","target":"137","id":"147"},{"source":"741","target":"535","id":"1544"},{"source":"1658","target":"302","id":"6212"},{"source":"725","target":"104","id":"1500"},{"source":"1506","target":"296","id":"5834"},{"source":"1194","target":"607","id":"3410"},{"source":"233","target":"447","id":"1007"},{"source":"781","target":"131","id":"2784"},{"source":"1086","target":"132","id":"2895"},{"source":"51","target":"281","id":"5585"},{"source":"1263","target":"65","id":"3709"},{"source":"281","target":"1125","id":"3083"},{"source":"1492","target":"1493","id":"5051"},{"source":"1345","target":"370","id":"4120"},{"source":"337","target":"182","id":"515"},{"source":"814","target":"97","id":"1816"},{"source":"574","target":"409","id":"1066"},{"source":"1540","target":"409","id":"5305"},{"source":"54","target":"56","id":"51"},{"source":"1432","target":"607","id":"4677"},{"source":"1574","target":"68","id":"5557"},{"source":"1456","target":"53","id":"4774"},{"source":"1327","target":"109","id":"5876"},{"source":"117","target":"65","id":"121"},{"source":"1188","target":"250","id":"3384"},{"source":"514","target":"65","id":"881"},{"source":"1478","target":"68","id":"4960"},{"source":"260","target":"262","id":"305"},{"source":"289","target":"62","id":"3723"},{"source":"1593","target":"567","id":"5751"},{"source":"213","target":"87","id":"240"},{"source":"1584","target":"1219","id":"5671"},{"source":"925","target":"65","id":"2285"},{"source":"1236","target":"852","id":"3592"},{"source":"319","target":"311","id":"3894"},{"source":"1050","target":"206","id":"4442"},{"source":"1285","target":"979","id":"3815"},{"source":"1283","target":"401","id":"5949"},{"source":"269","target":"276","id":"330"},{"source":"211","target":"225","id":"1947"},{"source":"834","target":"202","id":"5070"},{"source":"310","target":"312","id":"406"},{"source":"869","target":"82","id":"2026"},{"source":"1402","target":"401","id":"5841"},{"source":"954","target":"647","id":"3694"},{"source":"1645","target":"505","id":"6131"},{"source":"625","target":"629","id":"1210"},{"source":"397","target":"50","id":"3909"},{"source":"1303","target":"888","id":"4034"},{"source":"1419","target":"645","id":"5355"},{"source":"197","target":"199","id":"228"},{"source":"1035","target":"209","id":"2683"},{"source":"1014","target":"177","id":"3596"},{"source":"619","target":"526","id":"6036"},{"source":"1425","target":"524","id":"6436"},{"source":"1572","target":"1408","id":"6322"},{"source":"485","target":"79","id":"905"},{"source":"1001","target":"1002","id":"2551"},{"source":"1330","target":"262","id":"4038"},{"source":"1441","target":"1442","id":"4712"},{"source":"1432","target":"262","id":"4675"},{"source":"815","target":"817","id":"1818"},{"source":"898","target":"899","id":"2149"},{"source":"1359","target":"513","id":"4196"},{"source":"1590","target":"93","id":"5715"},{"source":"783","target":"1","id":"1699"},{"source":"192","target":"190","id":"214"},{"source":"822","target":"50","id":"6268"},{"source":"583","target":"585","id":"1090"},{"source":"1123","target":"1138","id":"3085"},{"source":"406","target":"53","id":"4736"},{"source":"811","target":"109","id":"1807"},{"source":"1189","target":"82","id":"3390"},{"source":"1433","target":"79","id":"4681"},{"source":"1591","target":"114","id":"5730"},{"source":"463","target":"79","id":"2635"},{"source":"936","target":"469","id":"2331"},{"source":"348","target":"76","id":"4621"},{"source":"1267","target":"405","id":"3733"},{"source":"697","target":"883","id":"5686"},{"source":"249","target":"76","id":"289"},{"source":"712","target":"868","id":"2036"},{"source":"779","target":"157","id":"1684"},{"source":"1574","target":"174","id":"5559"},{"source":"333","target":"53","id":"488"},{"source":"568","target":"427","id":"1641"},{"source":"1156","target":"408","id":"3159"},{"source":"1156","target":"364","id":"3158"},{"source":"1647","target":"175","id":"6135"},{"source":"771","target":"770","id":"6410"},{"source":"210","target":"211","id":"238"},{"source":"92","target":"93","id":"87"},{"source":"481","target":"482","id":"801"},{"source":"281","target":"600","id":"3080"},{"source":"499","target":"370","id":"828"},{"source":"223","target":"5","id":"254"},{"source":"606","target":"657","id":"3117"},{"source":"744","target":"241","id":"1560"},{"source":"94","target":"95","id":"90"},{"source":"1187","target":"65","id":"3371"},{"source":"327","target":"315","id":"461"},{"source":"756","target":"339","id":"1603"},{"source":"871","target":"65","id":"2046"},{"source":"48","target":"334","id":"4642"},{"source":"808","target":"50","id":"1786"},{"source":"866","target":"53","id":"2609"},{"source":"533","target":"956","id":"6084"},{"source":"274","target":"37","id":"328"},{"source":"657","target":"128","id":"5995"},{"source":"69","target":"73","id":"67"},{"source":"676","target":"646","id":"1358"},{"source":"15","target":"16","id":"18"},{"source":"411","target":"806","id":"1778"},{"source":"913","target":"1130","id":"5134"},{"source":"1361","target":"492","id":"4202"},{"source":"1457","target":"455","id":"4783"},{"source":"528","target":"617","id":"3552"},{"source":"1545","target":"1546","id":"5351"},{"source":"1081","target":"79","id":"2855"},{"source":"999","target":"1000","id":"2546"},{"source":"914","target":"915","id":"2248"},{"source":"677","target":"51","id":"1366"},{"source":"97","target":"94","id":"5266"},{"source":"1163","target":"567","id":"3210"},{"source":"89","target":"141","id":"2235"},{"source":"665","target":"431","id":"1325"},{"source":"93","target":"50","id":"2163"},{"source":"1144","target":"185","id":"3107"},{"source":"253","target":"76","id":"805"},{"source":"784","target":"65","id":"1706"},{"source":"1369","target":"1370","id":"4255"},{"source":"832","target":"65","id":"1884"},{"source":"1701","target":"53","id":"6479"},{"source":"98","target":"100","id":"94"},{"source":"664","target":"660","id":"3706"},{"source":"1480","target":"1317","id":"4982"},{"source":"896","target":"765","id":"4821"},{"source":"1203","target":"570","id":"3451"},{"source":"1554","target":"65","id":"5419"},{"source":"1327","target":"53","id":"5869"},{"source":"1104","target":"224","id":"2969"},{"source":"1267","target":"747","id":"3735"},{"source":"1148","target":"79","id":"3122"},{"source":"577","target":"585","id":"4394"},{"source":"1156","target":"53","id":"3160"},{"source":"1622","target":"1484","id":"5976"},{"source":"851","target":"79","id":"1961"},{"source":"760","target":"68","id":"1606"},{"source":"397","target":"801","id":"3914"},{"source":"1298","target":"335","id":"3869"},{"source":"271","target":"36","id":"4325"},{"source":"1568","target":"772","id":"5508"},{"source":"1045","target":"65","id":"2733"},{"source":"1315","target":"323","id":"4487"},{"source":"1074","target":"1076","id":"2844"},{"source":"1359","target":"335","id":"4200"},{"source":"1126","target":"33","id":"4813"},{"source":"366","target":"598","id":"5456"},{"source":"1001","target":"361","id":"2549"},{"source":"298","target":"219","id":"378"},{"source":"1701","target":"460","id":"6480"},{"source":"407","target":"146","id":"667"},{"source":"691","target":"217","id":"1392"},{"source":"1290","target":"79","id":"3832"},{"source":"477","target":"368","id":"3517"},{"source":"549","target":"79","id":"1276"},{"source":"570","target":"159","id":"1038"},{"source":"65","target":"50","id":"2127"},{"source":"728","target":"104","id":"5452"},{"source":"322","target":"296","id":"3945"},{"source":"1626","target":"513","id":"6013"},{"source":"955","target":"48","id":"2418"},{"source":"1363","target":"49","id":"4232"},{"source":"1592","target":"109","id":"5747"},{"source":"41","target":"43","id":"40"},{"source":"1607","target":"1409","id":"5903"},{"source":"1471","target":"53","id":"4907"},{"source":"813","target":"645","id":"1810"},{"source":"161","target":"1541","id":"5313"},{"source":"945","target":"1","id":"2371"},{"source":"901","target":"109","id":"2172"},{"source":"61","target":"66","id":"866"},{"source":"1295","target":"544","id":"3857"},{"source":"296","target":"79","id":"429"},{"source":"1709","target":"479","id":"6548"},{"source":"1489","target":"1038","id":"5021"},{"source":"1022","target":"250","id":"3359"},{"source":"1677","target":"370","id":"6357"},{"source":"958","target":"959","id":"2811"},{"source":"1539","target":"1","id":"5300"},{"source":"465","target":"462","id":"954"},{"source":"379","target":"68","id":"4126"},{"source":"713","target":"714","id":"6647"},{"source":"708","target":"769","id":"2872"},{"source":"18","target":"981","id":"2511"},{"source":"275","target":"36","id":"4323"},{"source":"1709","target":"183","id":"6551"},{"source":"1339","target":"724","id":"4079"},{"source":"1573","target":"66","id":"5542"},{"source":"884","target":"515","id":"2097"},{"source":"167","target":"53","id":"2336"},{"source":"1107","target":"513","id":"2988"},{"source":"1443","target":"53","id":"4721"},{"source":"1569","target":"772","id":"5515"},{"source":"333","target":"48","id":"490"},{"source":"705","target":"568","id":"1423"},{"source":"1294","target":"970","id":"3851"},{"source":"1589","target":"114","id":"5704"},{"source":"967","target":"1027","id":"2653"},{"source":"195","target":"194","id":"5388"},{"source":"1227","target":"294","id":"3576"},{"source":"1000","target":"1175","id":"3292"},{"source":"1471","target":"1015","id":"4911"},{"source":"1709","target":"303","id":"6544"},{"source":"659","target":"661","id":"3882"},{"source":"404","target":"48","id":"656"},{"source":"70","target":"73","id":"2492"},{"source":"1652","target":"48","id":"6182"},{"source":"1518","target":"163","id":"5234"},{"source":"1383","target":"79","id":"4313"},{"source":"1019","target":"1021","id":"2615"},{"source":"711","target":"712","id":"1436"},{"source":"1022","target":"65","id":"3356"},{"source":"714","target":"712","id":"6653"},{"source":"355","target":"505","id":"4010"},{"source":"1590","target":"430","id":"5718"},{"source":"275","target":"276","id":"4321"},{"source":"270","target":"38","id":"410"},{"source":"515","target":"216","id":"1172"},{"source":"509","target":"511","id":"859"},{"source":"1226","target":"79","id":"3569"},{"source":"365","target":"264","id":"1339"},{"source":"894","target":"177","id":"2119"},{"source":"1712","target":"1227","id":"6596"},{"source":"628","target":"177","id":"4149"},{"source":"532","target":"537","id":"925"},{"source":"30","target":"456","id":"5044"},{"source":"1070","target":"109","id":"2820"},{"source":"1472","target":"736","id":"4918"},{"source":"1041","target":"1043","id":"2705"},{"source":"1078","target":"1079","id":"3643"},{"source":"1591","target":"104","id":"5729"},{"source":"1639","target":"456","id":"6095"},{"source":"50","target":"64","id":"5471"},{"source":"528","target":"523","id":"3551"},{"source":"856","target":"321","id":"1977"},{"source":"414","target":"420","id":"690"},{"source":"657","target":"1593","id":"6001"},{"source":"249","target":"65","id":"285"},{"source":"779","target":"68","id":"1683"},{"source":"482","target":"483","id":"3838"},{"source":"1409","target":"1249","id":"4504"},{"source":"184","target":"325","id":"5125"},{"source":"1215","target":"238","id":"3492"},{"source":"471","target":"485","id":"807"},{"source":"1194","target":"732","id":"3408"},{"source":"741","target":"364","id":"1542"},{"source":"717","target":"441","id":"1465"},{"source":"1312","target":"321","id":"3932"},{"source":"1187","target":"68","id":"3374"},{"source":"391","target":"983","id":"3965"},{"source":"14","target":"5","id":"17"},{"source":"1519","target":"51","id":"5237"},{"source":"1160","target":"177","id":"3193"},{"source":"1081","target":"368","id":"2857"},{"source":"1395","target":"571","id":"4382"},{"source":"959","target":"163","id":"3163"},{"source":"579","target":"253","id":"6003"},{"source":"78","target":"79","id":"72"},{"source":"1188","target":"53","id":"3383"},{"source":"1639","target":"27","id":"6091"},{"source":"274","target":"38","id":"329"},{"source":"378","target":"120","id":"3207"},{"source":"1313","target":"1152","id":"3954"},{"source":"1165","target":"53","id":"5227"},{"source":"589","target":"113","id":"1660"},{"source":"171","target":"1046","id":"5261"},{"source":"864","target":"480","id":"2006"},{"source":"506","target":"50","id":"847"},{"source":"1269","target":"1268","id":"3749"},{"source":"1499","target":"424","id":"5093"},{"source":"292","target":"219","id":"374"},{"source":"1187","target":"82","id":"3373"},{"source":"625","target":"300","id":"1203"},{"source":"1509","target":"370","id":"5197"},{"source":"1637","target":"998","id":"6073"},{"source":"1063","target":"1069","id":"4301"},{"source":"363","target":"365","id":"557"},{"source":"1690","target":"1152","id":"6418"},{"source":"537","target":"335","id":"3331"},{"source":"152","target":"154","id":"172"},{"source":"292","target":"297","id":"375"},{"source":"1708","target":"508","id":"6541"},{"source":"1576","target":"68","id":"5608"},{"source":"784","target":"53","id":"1704"},{"source":"460","target":"119","id":"1167"},{"source":"1319","target":"53","id":"3981"},{"source":"1579","target":"79","id":"5635"},{"source":"1597","target":"66","id":"5781"},{"source":"873","target":"109","id":"2061"},{"source":"151","target":"150","id":"170"},{"source":"595","target":"591","id":"1130"},{"source":"257","target":"50","id":"297"},{"source":"354","target":"1","id":"1147"},{"source":"1510","target":"1236","id":"5201"},{"source":"1249","target":"1248","id":"5915"},{"source":"1490","target":"494","id":"5032"},{"source":"730","target":"702","id":"1518"},{"source":"179","target":"1117","id":"3398"},{"source":"330","target":"296","id":"479"},{"source":"1099","target":"1094","id":"2949"},{"source":"1271","target":"746","id":"3755"},{"source":"837","target":"280","id":"1904"},{"source":"73","target":"561","id":"1708"},{"source":"1188","target":"109","id":"3385"},{"source":"794","target":"65","id":"1739"},{"source":"206","target":"209","id":"2691"},{"source":"955","target":"279","id":"2421"},{"source":"1124","target":"543","id":"4848"},{"source":"561","target":"70","id":"1025"},{"source":"979","target":"488","id":"2657"},{"source":"1211","target":"159","id":"3474"},{"source":"1517","target":"1515","id":"5233"},{"source":"645","target":"95","id":"1555"},{"source":"67","target":"93","id":"2714"},{"source":"1006","target":"82","id":"2574"},{"source":"1091","target":"66","id":"2913"},{"source":"894","target":"79","id":"2120"},{"source":"1699","target":"159","id":"6453"},{"source":"856","target":"295","id":"1980"},{"source":"1281","target":"1200","id":"3809"},{"source":"362","target":"56","id":"6461"},{"source":"1108","target":"177","id":"2997"},{"source":"580","target":"582","id":"1076"},{"source":"382","target":"284","id":"625"},{"source":"26","target":"947","id":"2883"},{"source":"498","target":"80","id":"1987"},{"source":"108","target":"65","id":"5491"},{"source":"1455","target":"591","id":"4763"},{"source":"1678","target":"619","id":"6371"},{"source":"1432","target":"608","id":"4678"},{"source":"1720","target":"265","id":"6663"},{"source":"1259","target":"524","id":"3963"},{"source":"864","target":"498","id":"2009"},{"source":"1248","target":"618","id":"5894"},{"source":"1359","target":"53","id":"4192"},{"source":"264","target":"202","id":"1573"},{"source":"1679","target":"1196","id":"6377"},{"source":"630","target":"120","id":"1212"},{"source":"929","target":"154","id":"2305"},{"source":"336","target":"284","id":"3142"},{"source":"1687","target":"1688","id":"6398"},{"source":"591","target":"1","id":"1239"},{"source":"1050","target":"208","id":"4444"},{"source":"505","target":"232","id":"4001"},{"source":"180","target":"185","id":"206"},{"source":"553","target":"554","id":"987"},{"source":"1376","target":"525","id":"4280"},{"source":"1628","target":"535","id":"6018"},{"source":"1188","target":"239","id":"3386"},{"source":"312","target":"638","id":"3246"},{"source":"608","target":"216","id":"1490"},{"source":"64","target":"349","id":"1831"},{"source":"1129","target":"517","id":"4597"},{"source":"1720","target":"438","id":"6668"},{"source":"1651","target":"1404","id":"6174"},{"source":"451","target":"453","id":"742"},{"source":"48","target":"53","id":"4637"},{"source":"325","target":"79","id":"5138"},{"source":"703","target":"540","id":"3892"},{"source":"1440","target":"111","id":"6177"},{"source":"1572","target":"79","id":"6318"},{"source":"1086","target":"68","id":"2891"},{"source":"1427","target":"400","id":"4610"},{"source":"1134","target":"170","id":"3075"},{"source":"1510","target":"113","id":"5199"},{"source":"589","target":"49","id":"1665"},{"source":"505","target":"493","id":"4000"},{"source":"909","target":"906","id":"6081"},{"source":"1486","target":"79","id":"5011"},{"source":"1543","target":"82","id":"5333"},{"source":"695","target":"111","id":"4954"},{"source":"1711","target":"79","id":"6583"},{"source":"837","target":"48","id":"1908"},{"source":"133","target":"136","id":"146"},{"source":"322","target":"1312","id":"3943"},{"source":"1459","target":"279","id":"4800"},{"source":"1022","target":"93","id":"3357"},{"source":"1571","target":"79","id":"5534"},{"source":"1086","target":"65","id":"2893"},{"source":"730","target":"607","id":"1517"},{"source":"921","target":"498","id":"2269"},{"source":"108","target":"50","id":"5492"},{"source":"929","target":"68","id":"2301"},{"source":"1426","target":"1129","id":"4596"},{"source":"726","target":"607","id":"2190"},{"source":"722","target":"239","id":"1475"},{"source":"1513","target":"366","id":"5218"},{"source":"376","target":"294","id":"608"},{"source":"712","target":"869","id":"2037"},{"source":"1242","target":"568","id":"3606"},{"source":"26","target":"76","id":"2880"},{"source":"719","target":"720","id":"1469"},{"source":"1247","target":"1248","id":"3631"},{"source":"1470","target":"552","id":"4904"},{"source":"289","target":"286","id":"3722"},{"source":"1547","target":"159","id":"5522"},{"source":"877","target":"740","id":"2069"},{"source":"822","target":"397","id":"6263"},{"source":"528","target":"524","id":"3554"},{"source":"1363","target":"52","id":"4234"},{"source":"452","target":"53","id":"2281"},{"source":"1256","target":"65","id":"3651"},{"source":"1049","target":"1050","id":"2756"},{"source":"539","target":"541","id":"929"},{"source":"1577","target":"129","id":"5616"},{"source":"1466","target":"335","id":"4836"},{"source":"1024","target":"121","id":"2644"},{"source":"265","target":"834","id":"1895"},{"source":"977","target":"46","id":"2494"},{"source":"487","target":"489","id":"811"},{"source":"841","target":"51","id":"2449"},{"source":"153","target":"152","id":"2232"},{"source":"1053","target":"209","id":"4601"},{"source":"410","target":"49","id":"678"},{"source":"398","target":"1244","id":"5155"},{"source":"64","target":"53","id":"1824"},{"source":"197","target":"166","id":"227"},{"source":"1507","target":"79","id":"5148"},{"source":"1678","target":"185","id":"6370"},{"source":"191","target":"190","id":"5885"},{"source":"1183","target":"1","id":"3345"},{"source":"1303","target":"663","id":"4033"},{"source":"1548","target":"5","id":"5357"},{"source":"747","target":"600","id":"3779"},{"source":"1292","target":"1291","id":"5658"},{"source":"397","target":"1206","id":"3913"},{"source":"145","target":"436","id":"1002"},{"source":"371","target":"372","id":"578"},{"source":"1573","target":"53","id":"5550"},{"source":"938","target":"53","id":"2481"},{"source":"797","target":"370","id":"1750"},{"source":"250","target":"53","id":"3364"},{"source":"537","target":"532","id":"3329"},{"source":"1605","target":"175","id":"5856"},{"source":"1594","target":"53","id":"5763"},{"source":"64","target":"50","id":"1830"},{"source":"434","target":"161","id":"941"},{"source":"1362","target":"65","id":"4224"},{"source":"1716","target":"1120","id":"6615"},{"source":"1063","target":"1066","id":"4300"},{"source":"1689","target":"399","id":"6404"},{"source":"1489","target":"1037","id":"5020"},{"source":"760","target":"624","id":"1610"},{"source":"1432","target":"515","id":"4676"},{"source":"1452","target":"66","id":"4751"},{"source":"1721","target":"53","id":"6670"},{"source":"569","target":"568","id":"2199"},{"source":"943","target":"120","id":"2361"},{"source":"1362","target":"68","id":"4219"},{"source":"650","target":"324","id":"1284"},{"source":"81","target":"82","id":"74"},{"source":"1298","target":"397","id":"3873"},{"source":"285","target":"61","id":"350"},{"source":"1038","target":"206","id":"5028"},{"source":"53","target":"64","id":"1113"},{"source":"613","target":"313","id":"1966"},{"source":"1343","target":"393","id":"4107"},{"source":"925","target":"287","id":"2287"},{"source":"1268","target":"63","id":"3743"},{"source":"1667","target":"1668","id":"6274"},{"source":"613","target":"292","id":"1963"},{"source":"833","target":"109","id":"1894"},{"source":"1611","target":"600","id":"5918"},{"source":"459","target":"460","id":"765"},{"source":"1257","target":"5","id":"3662"},{"source":"261","target":"238","id":"5960"},{"source":"85","target":"82","id":"1932"},{"source":"1458","target":"497","id":"4794"},{"source":"832","target":"53","id":"1882"},{"source":"1639","target":"552","id":"6094"},{"source":"408","target":"61","id":"877"},{"source":"1373","target":"698","id":"6367"},{"source":"805","target":"166","id":"1771"},{"source":"39","target":"270","id":"4304"},{"source":"1427","target":"53","id":"4607"},{"source":"1286","target":"53","id":"3823"},{"source":"1624","target":"648","id":"5989"},{"source":"225","target":"224","id":"6089"},{"source":"740","target":"53","id":"1535"},{"source":"358","target":"360","id":"548"},{"source":"1092","target":"409","id":"2919"},{"source":"1606","target":"421","id":"5865"},{"source":"310","target":"79","id":"404"},{"source":"1245","target":"141","id":"3628"},{"source":"142","target":"145","id":"163"},{"source":"1345","target":"267","id":"4118"},{"source":"1548","target":"1","id":"5356"},{"source":"684","target":"5","id":"1376"},{"source":"304","target":"966","id":"4506"},{"source":"1242","target":"427","id":"3609"},{"source":"606","target":"437","id":"3115"},{"source":"269","target":"273","id":"338"},{"source":"849","target":"79","id":"1950"},{"source":"50","target":"111","id":"5476"},{"source":"398","target":"48","id":"5157"},{"source":"47","target":"49","id":"4431"},{"source":"730","target":"732","id":"1524"},{"source":"726","target":"53","id":"2195"},{"source":"642","target":"641","id":"6165"},{"source":"426","target":"427","id":"1030"},{"source":"1337","target":"200","id":"4073"},{"source":"274","target":"36","id":"327"},{"source":"1568","target":"1569","id":"5513"},{"source":"820","target":"167","id":"1836"},{"source":"1393","target":"233","id":"4371"},{"source":"1223","target":"528","id":"3561"},{"source":"574","target":"334","id":"1067"},{"source":"1341","target":"784","id":"4093"},{"source":"513","target":"50","id":"5209"},{"source":"216","target":"214","id":"545"},{"source":"1673","target":"512","id":"6300"},{"source":"330","target":"219","id":"480"},{"source":"1033","target":"177","id":"2671"},{"source":"363","target":"161","id":"561"},{"source":"204","target":"207","id":"235"},{"source":"703","target":"702","id":"3886"},{"source":"100","target":"248","id":"1844"},{"source":"385","target":"294","id":"3683"},{"source":"87","target":"380","id":"6289"},{"source":"1175","target":"33","id":"3326"},{"source":"726","target":"65","id":"2191"},{"source":"394","target":"390","id":"4928"},{"source":"759","target":"284","id":"5777"},{"source":"1099","target":"312","id":"2950"},{"source":"713","target":"715","id":"6641"},{"source":"951","target":"65","id":"2408"},{"source":"153","target":"242","id":"2233"},{"source":"375","target":"115","id":"599"},{"source":"1014","target":"463","id":"3598"},{"source":"63","target":"62","id":"993"},{"source":"729","target":"402","id":"1515"},{"source":"1674","target":"131","id":"6313"},{"source":"995","target":"993","id":"2541"},{"source":"654","target":"437","id":"3418"},{"source":"24","target":"23","id":"5817"},{"source":"1624","target":"1547","id":"5991"},{"source":"1046","target":"567","id":"6338"},{"source":"482","target":"1292","id":"3841"},{"source":"533","target":"532","id":"6082"},{"source":"1475","target":"900","id":"4925"},{"source":"831","target":"1085","id":"2876"},{"source":"296","target":"185","id":"432"},{"source":"298","target":"299","id":"379"},{"source":"1513","target":"897","id":"5219"},{"source":"378","target":"668","id":"3205"},{"source":"457","target":"1017","id":"6343"},{"source":"246","target":"915","id":"2641"},{"source":"1350","target":"79","id":"4146"},{"source":"374","target":"267","id":"5179"},{"source":"881","target":"68","id":"2087"},{"source":"808","target":"406","id":"1794"},{"source":"113","target":"267","id":"1097"},{"source":"1357","target":"367","id":"5314"},{"source":"405","target":"51","id":"2926"},{"source":"780","target":"175","id":"1698"},{"source":"239","target":"648","id":"6451"},{"source":"1318","target":"1316","id":"3973"},{"source":"1359","target":"49","id":"4195"},{"source":"1451","target":"185","id":"5109"},{"source":"321","target":"294","id":"732"},{"source":"1174","target":"388","id":"3289"},{"source":"1187","target":"103","id":"3375"},{"source":"1500","target":"961","id":"5096"},{"source":"946","target":"76","id":"2377"},{"source":"768","target":"708","id":"6393"},{"source":"788","target":"114","id":"1717"},{"source":"509","target":"408","id":"854"},{"source":"633","target":"634","id":"1223"},{"source":"696","target":"697","id":"1411"},{"source":"665","target":"287","id":"1331"},{"source":"1107","target":"1015","id":"2987"},{"source":"878","target":"68","id":"2074"},{"source":"68","target":"108","id":"107"},{"source":"743","target":"644","id":"1549"},{"source":"315","target":"306","id":"3504"},{"source":"611","target":"119","id":"1179"},{"source":"891","target":"893","id":"2117"},{"source":"1169","target":"82","id":"3264"},{"source":"1208","target":"211","id":"3462"},{"source":"1490","target":"833","id":"5038"},{"source":"777","target":"16","id":"3464"},{"source":"1387","target":"974","id":"4350"},{"source":"1712","target":"182","id":"6597"},{"source":"673","target":"675","id":"1356"},{"source":"980","target":"916","id":"2509"},{"source":"251","target":"453","id":"3974"},{"source":"1163","target":"656","id":"3216"},{"source":"804","target":"1","id":"1770"},{"source":"237","target":"238","id":"272"},{"source":"174","target":"423","id":"1525"},{"source":"402","target":"403","id":"652"},{"source":"1033","target":"209","id":"2672"},{"source":"769","target":"768","id":"1635"},{"source":"1146","target":"381","id":"3660"},{"source":"594","target":"510","id":"4879"},{"source":"211","target":"361","id":"1946"},{"source":"1636","target":"420","id":"6070"},{"source":"621","target":"372","id":"3958"},{"source":"1416","target":"296","id":"4547"},{"source":"1182","target":"411","id":"3338"},{"source":"580","target":"576","id":"1080"},{"source":"288","target":"289","id":"361"},{"source":"725","target":"726","id":"1499"},{"source":"404","target":"405","id":"654"},{"source":"1279","target":"79","id":"5626"},{"source":"459","target":"65","id":"767"},{"source":"750","target":"137","id":"1589"},{"source":"1071","target":"1074","id":"2835"},{"source":"1540","target":"427","id":"5302"},{"source":"1183","target":"1155","id":"3343"},{"source":"1720","target":"263","id":"6664"},{"source":"954","target":"436","id":"3692"},{"source":"1260","target":"1","id":"3677"},{"source":"509","target":"65","id":"857"},{"source":"1071","target":"1073","id":"2834"},{"source":"431","target":"53","id":"709"},{"source":"481","target":"334","id":"803"},{"source":"1250","target":"500","id":"3638"},{"source":"1421","target":"310","id":"4566"},{"source":"502","target":"85","id":"5073"},{"source":"1716","target":"1717","id":"6617"},{"source":"1273","target":"1274","id":"3761"},{"source":"552","target":"53","id":"4891"},{"source":"651","target":"53","id":"1304"},{"source":"883","target":"915","id":"4188"},{"source":"1652","target":"498","id":"6180"},{"source":"1035","target":"1034","id":"2684"},{"source":"1378","target":"291","id":"4283"},{"source":"188","target":"190","id":"224"},{"source":"828","target":"53","id":"1860"},{"source":"711","target":"714","id":"1441"},{"source":"312","target":"852","id":"3247"},{"source":"476","target":"473","id":"793"},{"source":"103","target":"234","id":"264"},{"source":"1211","target":"96","id":"3475"},{"source":"245","target":"68","id":"1734"},{"source":"304","target":"185","id":"4507"},{"source":"1222","target":"892","id":"3536"},{"source":"610","target":"53","id":"1183"},{"source":"1005","target":"885","id":"3269"},{"source":"1124","target":"82","id":"4847"},{"source":"1501","target":"48","id":"5102"},{"source":"750","target":"311","id":"1580"},{"source":"681","target":"682","id":"1367"},{"source":"369","target":"254","id":"572"},{"source":"1649","target":"85","id":"6147"},{"source":"979","target":"978","id":"2656"},{"source":"1101","target":"1100","id":"2958"},{"source":"288","target":"53","id":"366"},{"source":"824","target":"823","id":"3265"},{"source":"965","target":"82","id":"2445"},{"source":"267","target":"374","id":"4433"},{"source":"949","target":"204","id":"2396"},{"source":"1223","target":"523","id":"3555"},{"source":"604","target":"428","id":"1152"},{"source":"1254","target":"279","id":"3647"},{"source":"1576","target":"1117","id":"5610"},{"source":"133","target":"135","id":"145"},{"source":"1053","target":"208","id":"4599"},{"source":"806","target":"111","id":"6054"},{"source":"732","target":"238","id":"5973"},{"source":"202","target":"265","id":"6638"},{"source":"918","target":"781","id":"2260"},{"source":"1063","target":"1064","id":"4299"},{"source":"1119","target":"409","id":"6257"},{"source":"842","target":"85","id":"1919"},{"source":"1315","target":"79","id":"4485"},{"source":"404","target":"50","id":"660"},{"source":"874","target":"114","id":"2066"},{"source":"279","target":"42","id":"501"},{"source":"757","target":"344","id":"5830"},{"source":"547","target":"79","id":"947"},{"source":"683","target":"21","id":"1444"},{"source":"242","target":"241","id":"2225"},{"source":"914","target":"50","id":"2250"},{"source":"1227","target":"377","id":"3577"},{"source":"548","target":"463","id":"962"},{"source":"1092","target":"66","id":"2924"},{"source":"1674","target":"65","id":"6312"},{"source":"498","target":"857","id":"1986"},{"source":"1637","target":"57","id":"6074"},{"source":"1325","target":"408","id":"4015"},{"source":"276","target":"313","id":"6590"},{"source":"1700","target":"150","id":"6464"},{"source":"540","target":"541","id":"2189"},{"source":"1267","target":"364","id":"3738"},{"source":"1504","target":"50","id":"5106"},{"source":"1650","target":"334","id":"6157"},{"source":"383","target":"61","id":"632"},{"source":"1027","target":"967","id":"5435"},{"source":"1405","target":"312","id":"4456"},{"source":"1551","target":"439","id":"5387"},{"source":"937","target":"458","id":"2345"},{"source":"1625","target":"1324","id":"6007"},{"source":"131","target":"567","id":"2186"},{"source":"457","target":"259","id":"6342"},{"source":"276","target":"38","id":"6589"},{"source":"48","target":"409","id":"4641"},{"source":"336","target":"50","id":"3148"},{"source":"337","target":"53","id":"509"},{"source":"23","target":"28","id":"5805"},{"source":"975","target":"510","id":"2489"},{"source":"1042","target":"209","id":"2716"},{"source":"400","target":"133","id":"2387"},{"source":"799","target":"48","id":"1762"},{"source":"1049","target":"495","id":"2752"},{"source":"643","target":"645","id":"1270"},{"source":"1421","target":"79","id":"4568"},{"source":"1230","target":"1231","id":"3584"},{"source":"524","target":"1259","id":"4501"},{"source":"36","target":"275","id":"440"},{"source":"126","target":"127","id":"135"},{"source":"1595","target":"97","id":"5773"},{"source":"1104","target":"638","id":"2970"},{"source":"51","target":"408","id":"5583"},{"source":"1455","target":"262","id":"4766"},{"source":"145","target":"166","id":"1001"},{"source":"864","target":"50","id":"2005"},{"source":"1616","target":"1083","id":"5946"},{"source":"642","target":"161","id":"6164"},{"source":"1705","target":"120","id":"6503"},{"source":"587","target":"589","id":"1105"},{"source":"1066","target":"1065","id":"2803"},{"source":"474","target":"473","id":"6608"},{"source":"273","target":"40","id":"5568"},{"source":"918","target":"104","id":"2258"},{"source":"525","target":"293","id":"930"},{"source":"884","target":"216","id":"2094"},{"source":"918","target":"458","id":"2262"},{"source":"266","target":"264","id":"3991"},{"source":"841","target":"49","id":"2447"},{"source":"595","target":"592","id":"1134"},{"source":"556","target":"830","id":"3424"},{"source":"87","target":"544","id":"6291"},{"source":"1373","target":"82","id":"6366"},{"source":"748","target":"364","id":"3788"},{"source":"1339","target":"1015","id":"4081"},{"source":"1007","target":"1009","id":"2578"},{"source":"1638","target":"899","id":"6564"},{"source":"414","target":"219","id":"688"},{"source":"1570","target":"570","id":"5526"},{"source":"770","target":"769","id":"5553"},{"source":"285","target":"51","id":"358"},{"source":"829","target":"76","id":"1869"},{"source":"1339","target":"223","id":"4085"},{"source":"944","target":"484","id":"2369"},{"source":"1269","target":"61","id":"3754"},{"source":"1125","target":"533","id":"4522"},{"source":"347","target":"348","id":"4031"},{"source":"268","target":"38","id":"314"},{"source":"866","target":"66","id":"2611"},{"source":"769","target":"708","id":"1633"},{"source":"484","target":"166","id":"5587"},{"source":"216","target":"351","id":"544"},{"source":"1354","target":"479","id":"4175"},{"source":"644","target":"96","id":"1552"},{"source":"574","target":"49","id":"1059"},{"source":"461","target":"64","id":"2621"},{"source":"21","target":"20","id":"1310"},{"source":"321","target":"322","id":"733"},{"source":"610","target":"216","id":"1182"},{"source":"1486","target":"591","id":"5010"},{"source":"207","target":"1","id":"2695"},{"source":"524","target":"1258","id":"4500"},{"source":"1025","target":"53","id":"4628"},{"source":"1368","target":"312","id":"4254"},{"source":"856","target":"310","id":"1974"},{"source":"1125","target":"335","id":"4518"},{"source":"1214","target":"96","id":"3487"},{"source":"543","target":"532","id":"935"},{"source":"417","target":"1152","id":"4467"},{"source":"346","target":"647","id":"1273"},{"source":"263","target":"266","id":"309"},{"source":"1187","target":"53","id":"3378"},{"source":"687","target":"82","id":"1378"},{"source":"1501","target":"49","id":"5103"},{"source":"902","target":"93","id":"3167"},{"source":"97","target":"82","id":"5267"},{"source":"613","target":"296","id":"1964"},{"source":"363","target":"68","id":"563"},{"source":"1390","target":"365","id":"4362"},{"source":"381","target":"296","id":"613"},{"source":"115","target":"113","id":"2322"},{"source":"437","target":"657","id":"1318"},{"source":"336","target":"51","id":"3141"},{"source":"594","target":"61","id":"4874"},{"source":"1179","target":"516","id":"3305"},{"source":"1674","target":"118","id":"6310"},{"source":"1443","target":"82","id":"4719"},{"source":"1279","target":"1282","id":"5629"},{"source":"418","target":"219","id":"4564"},{"source":"53","target":"65","id":"1114"},{"source":"1201","target":"1077","id":"4995"},{"source":"443","target":"79","id":"1288"},{"source":"1606","target":"1249","id":"5863"},{"source":"183","target":"296","id":"5117"},{"source":"1226","target":"819","id":"3570"},{"source":"261","target":"732","id":"5961"},{"source":"361","target":"299","id":"1956"},{"source":"328","target":"45","id":"474"},{"source":"1636","target":"1152","id":"6069"},{"source":"538","target":"280","id":"4662"},{"source":"118","target":"64","id":"1295"},{"source":"991","target":"272","id":"4947"},{"source":"597","target":"65","id":"1144"},{"source":"786","target":"787","id":"3950"},{"source":"770","target":"771","id":"5556"},{"source":"463","target":"549","id":"2636"},{"source":"330","target":"79","id":"484"},{"source":"903","target":"901","id":"2180"},{"source":"1579","target":"1279","id":"5632"},{"source":"1483","target":"1202","id":"4991"},{"source":"488","target":"150","id":"2524"},{"source":"202","target":"403","id":"6635"},{"source":"1456","target":"759","id":"4779"},{"source":"51","target":"1015","id":"5578"},{"source":"67","target":"50","id":"2715"},{"source":"22","target":"24","id":"24"},{"source":"952","target":"348","id":"2410"},{"source":"1670","target":"71","id":"6284"},{"source":"1006","target":"834","id":"2573"},{"source":"1628","target":"537","id":"6020"},{"source":"1256","target":"170","id":"3653"},{"source":"929","target":"736","id":"2300"},{"source":"1414","target":"1200","id":"4534"},{"source":"1673","target":"598","id":"6301"},{"source":"658","target":"660","id":"1320"},{"source":"1268","target":"61","id":"3741"},{"source":"184","target":"892","id":"5126"},{"source":"1320","target":"1321","id":"3995"},{"source":"397","target":"956","id":"3912"},{"source":"535","target":"536","id":"2465"},{"source":"23","target":"24","id":"5807"},{"source":"267","target":"589","id":"4438"},{"source":"1198","target":"312","id":"3439"},{"source":"1486","target":"651","id":"5012"},{"source":"1553","target":"1384","id":"5410"},{"source":"383","target":"335","id":"633"},{"source":"1650","target":"49","id":"6158"},{"source":"852","target":"79","id":"3249"},{"source":"320","target":"292","id":"434"},{"source":"1313","target":"417","id":"3953"},{"source":"459","target":"68","id":"763"},{"source":"658","target":"663","id":"1323"},{"source":"1598","target":"354","id":"5786"},{"source":"244","target":"111","id":"1669"},{"source":"1585","target":"122","id":"5672"},{"source":"102","target":"50","id":"101"},{"source":"1650","target":"533","id":"6161"},{"source":"573","target":"66","id":"1047"},{"source":"1079","target":"1078","id":"6456"},{"source":"833","target":"444","id":"1889"},{"source":"1312","target":"1311","id":"3934"},{"source":"637","target":"299","id":"1250"},{"source":"119","target":"636","id":"3171"},{"source":"1412","target":"1199","id":"4524"},{"source":"1452","target":"50","id":"4747"},{"source":"857","target":"80","id":"2015"},{"source":"1048","target":"701","id":"2745"},{"source":"752","target":"137","id":"1942"},{"source":"1588","target":"68","id":"5703"},{"source":"1623","target":"1619","id":"5985"},{"source":"451","target":"104","id":"747"},{"source":"1601","target":"712","id":"5797"},{"source":"301","target":"296","id":"384"},{"source":"827","target":"1","id":"1857"},{"source":"1065","target":"1062","id":"2799"},{"source":"708","target":"768","id":"2875"},{"source":"65","target":"105","id":"2126"},{"source":"1262","target":"1078","id":"4631"},{"source":"1593","target":"118","id":"5749"},{"source":"243","target":"245","id":"280"},{"source":"1714","target":"79","id":"6609"},{"source":"639","target":"640","id":"1261"},{"source":"246","target":"1023","id":"2643"},{"source":"142","target":"143","id":"161"},{"source":"1044","target":"118","id":"2731"},{"source":"1343","target":"344","id":"4106"},{"source":"449","target":"5","id":"729"},{"source":"1093","target":"79","id":"2935"},{"source":"717","target":"128","id":"1461"},{"source":"1216","target":"128","id":"3493"},{"source":"1720","target":"264","id":"6662"},{"source":"592","target":"53","id":"4814"},{"source":"1560","target":"1001","id":"5484"},{"source":"577","target":"580","id":"4398"},{"source":"1105","target":"468","id":"2978"},{"source":"1459","target":"166","id":"4799"},{"source":"1026","target":"967","id":"2648"},{"source":"845","target":"379","id":"1936"},{"source":"1479","target":"167","id":"4974"},{"source":"891","target":"53","id":"2115"},{"source":"1035","target":"1036","id":"2686"},{"source":"1041","target":"104","id":"2701"},{"source":"1579","target":"1282","id":"5633"},{"source":"1611","target":"1612","id":"5917"},{"source":"472","target":"473","id":"783"},{"source":"789","target":"405","id":"3033"},{"source":"131","target":"104","id":"2184"},{"source":"298","target":"296","id":"377"},{"source":"1380","target":"1379","id":"4289"},{"source":"668","target":"669","id":"1333"},{"source":"937","target":"167","id":"2342"},{"source":"201","target":"519","id":"4756"},{"source":"569","target":"130","id":"2196"},{"source":"433","target":"435","id":"712"},{"source":"1330","target":"664","id":"4037"},{"source":"1173","target":"532","id":"3276"},{"source":"215","target":"1","id":"5993"},{"source":"640","target":"641","id":"5321"},{"source":"456","target":"28","id":"5811"},{"source":"869","target":"172","id":"2025"},{"source":"1597","target":"519","id":"5779"},{"source":"593","target":"61","id":"1120"},{"source":"1468","target":"53","id":"4859"},{"source":"42","target":"48","id":"346"},{"source":"1137","target":"1123","id":"5255"},{"source":"315","target":"219","id":"3503"},{"source":"741","target":"536","id":"1545"},{"source":"1554","target":"901","id":"5420"},{"source":"1712","target":"79","id":"6593"},{"source":"170","target":"109","id":"4791"},{"source":"560","target":"366","id":"1019"},{"source":"139","target":"138","id":"158"},{"source":"785","target":"787","id":"1716"},{"source":"391","target":"1317","id":"3967"},{"source":"893","target":"53","id":"2556"},{"source":"784","target":"50","id":"1702"},{"source":"236","target":"235","id":"1231"},{"source":"1517","target":"163","id":"5232"},{"source":"538","target":"49","id":"4659"},{"source":"1705","target":"157","id":"6505"},{"source":"457","target":"513","id":"6344"},{"source":"1360","target":"49","id":"6659"},{"source":"688","target":"53","id":"1656"},{"source":"1004","target":"519","id":"2567"},{"source":"656","target":"82","id":"5332"},{"source":"1051","target":"344","id":"2757"},{"source":"282","target":"293","id":"3284"},{"source":"1343","target":"201","id":"4112"},{"source":"768","target":"769","id":"6391"},{"source":"1276","target":"364","id":"3769"},{"source":"1616","target":"652","id":"5941"},{"source":"717","target":"710","id":"1462"},{"source":"6","target":"7","id":"7"},{"source":"1256","target":"53","id":"3649"},{"source":"656","target":"654","id":"5330"},{"source":"1014","target":"1013","id":"3599"},{"source":"1221","target":"183","id":"3528"},{"source":"1660","target":"961","id":"6225"},{"source":"28","target":"30","id":"5039"},{"source":"1052","target":"205","id":"2765"},{"source":"1583","target":"551","id":"5664"},{"source":"408","target":"119","id":"871"},{"source":"274","target":"270","id":"326"},{"source":"1334","target":"987","id":"4057"},{"source":"873","target":"458","id":"2059"},{"source":"848","target":"79","id":"1943"},{"source":"454","target":"455","id":"751"},{"source":"687","target":"98","id":"1379"},{"source":"312","target":"79","id":"3245"},{"source":"1237","target":"1238","id":"3601"},{"source":"102","target":"65","id":"98"},{"source":"789","target":"397","id":"3034"},{"source":"1342","target":"200","id":"4105"},{"source":"1302","target":"1301","id":"6401"},{"source":"1250","target":"182","id":"3636"},{"source":"67","target":"65","id":"2713"},{"source":"167","target":"50","id":"2339"},{"source":"1086","target":"635","id":"2894"},{"source":"779","target":"53","id":"1686"},{"source":"1559","target":"124","id":"5465"},{"source":"459","target":"461","id":"769"},{"source":"1456","target":"757","id":"4780"},{"source":"1353","target":"170","id":"4170"},{"source":"911","target":"309","id":"2241"},{"source":"635","target":"50","id":"4402"},{"source":"448","target":"195","id":"726"},{"source":"283","target":"282","id":"6351"},{"source":"1558","target":"128","id":"5445"},{"source":"371","target":"316","id":"579"},{"source":"933","target":"650","id":"2316"},{"source":"913","target":"900","id":"5136"},{"source":"871","target":"64","id":"2045"},{"source":"969","target":"85","id":"2468"},{"source":"589","target":"233","id":"1659"},{"source":"578","target":"577","id":"5683"},{"source":"172","target":"439","id":"5741"},{"source":"92","target":"68","id":"83"},{"source":"61","target":"48","id":"867"},{"source":"1277","target":"731","id":"3795"},{"source":"19","target":"20","id":"21"},{"source":"416","target":"418","id":"3666"},{"source":"131","target":"53","id":"2181"},{"source":"1337","target":"807","id":"4076"},{"source":"1306","target":"18","id":"3907"},{"source":"10","target":"1","id":"11"},{"source":"1547","target":"238","id":"5520"},{"source":"671","target":"67","id":"1349"},{"source":"929","target":"27","id":"2306"},{"source":"971","target":"224","id":"2473"},{"source":"1443","target":"67","id":"4716"},{"source":"1571","target":"185","id":"5540"},{"source":"446","target":"309","id":"907"},{"source":"377","target":"852","id":"2152"},{"source":"264","target":"438","id":"1570"},{"source":"48","target":"280","id":"4635"},{"source":"727","target":"390","id":"1507"},{"source":"52","target":"554","id":"5767"},{"source":"943","target":"857","id":"2360"},{"source":"1054","target":"1055","id":"2775"},{"source":"926","target":"76","id":"2386"},{"source":"945","target":"170","id":"2372"},{"source":"1107","target":"65","id":"2985"},{"source":"884","target":"885","id":"2100"},{"source":"1667","target":"579","id":"6277"},{"source":"532","target":"535","id":"923"},{"source":"1256","target":"215","id":"3654"},{"source":"805","target":"411","id":"1774"},{"source":"1012","target":"334","id":"5574"},{"source":"1077","target":"1201","id":"3448"},{"source":"1520","target":"560","id":"5246"},{"source":"921","target":"152","id":"2268"},{"source":"165","target":"68","id":"185"},{"source":"41","target":"42","id":"39"},{"source":"931","target":"287","id":"2314"},{"source":"504","target":"569","id":"1639"},{"source":"268","target":"274","id":"320"},{"source":"1095","target":"313","id":"2939"},{"source":"187","target":"188","id":"217"},{"source":"1081","target":"465","id":"2854"},{"source":"63","target":"53","id":"994"},{"source":"593","target":"591","id":"1121"},{"source":"1178","target":"42","id":"3300"},{"source":"944","target":"109","id":"2370"},{"source":"712","target":"870","id":"2038"},{"source":"717","target":"85","id":"1463"},{"source":"1389","target":"313","id":"4365"},{"source":"335","target":"281","id":"1054"},{"source":"857","target":"581","id":"2016"},{"source":"312","target":"185","id":"3248"},{"source":"244","target":"109","id":"1670"},{"source":"370","target":"364","id":"4579"},{"source":"47","target":"374","id":"4430"},{"source":"747","target":"281","id":"3780"},{"source":"595","target":"104","id":"1133"},{"source":"1201","target":"569","id":"4994"},{"source":"177","target":"79","id":"956"},{"source":"805","target":"48","id":"1776"},{"source":"1387","target":"1388","id":"4353"},{"source":"460","target":"53","id":"1161"},{"source":"1226","target":"381","id":"3568"},{"source":"878","target":"877","id":"2077"},{"source":"803","target":"148","id":"3757"},{"source":"1041","target":"1042","id":"2703"},{"source":"731","target":"234","id":"4959"},{"source":"259","target":"457","id":"2155"},{"source":"1673","target":"544","id":"6305"},{"source":"511","target":"68","id":"6474"},{"source":"422","target":"423","id":"693"},{"source":"1468","target":"1161","id":"4865"},{"source":"538","target":"66","id":"4655"},{"source":"811","target":"173","id":"1802"},{"source":"727","target":"200","id":"1511"},{"source":"314","target":"182","id":"424"},{"source":"701","target":"539","id":"1417"},{"source":"202","target":"835","id":"6640"},{"source":"1592","target":"964","id":"5743"},{"source":"1485","target":"519","id":"5001"},{"source":"621","target":"182","id":"3960"},{"source":"915","target":"935","id":"2326"},{"source":"697","target":"846","id":"5688"},{"source":"1569","target":"159","id":"5516"},{"source":"336","target":"279","id":"3143"},{"source":"368","target":"361","id":"3006"},{"source":"1220","target":"1","id":"3520"},{"source":"612","target":"615","id":"1192"},{"source":"1345","target":"181","id":"4117"},{"source":"1509","target":"113","id":"5192"},{"source":"1365","target":"51","id":"4246"},{"source":"1006","target":"1003","id":"2572"},{"source":"724","target":"224","id":"2829"},{"source":"1244","target":"398","id":"3615"},{"source":"590","target":"51","id":"5173"},{"source":"958","target":"961","id":"2813"},{"source":"1268","target":"62","id":"3742"},{"source":"1562","target":"159","id":"5494"},{"source":"1298","target":"48","id":"3874"},{"source":"364","target":"113","id":"581"},{"source":"346","target":"648","id":"1274"},{"source":"837","target":"49","id":"1909"},{"source":"711","target":"85","id":"1435"},{"source":"332","target":"521","id":"4386"},{"source":"322","target":"320","id":"3939"},{"source":"293","target":"292","id":"615"},{"source":"574","target":"48","id":"1065"},{"source":"833","target":"403","id":"1887"},{"source":"1087","target":"53","id":"5442"},{"source":"953","target":"661","id":"2416"},{"source":"1180","target":"983","id":"3311"},{"source":"1644","target":"833","id":"6122"},{"source":"36","target":"270","id":"444"},{"source":"1253","target":"296","id":"6557"},{"source":"216","target":"166","id":"546"},{"source":"257","target":"258","id":"301"},{"source":"1194","target":"634","id":"3409"},{"source":"1452","target":"53","id":"4750"},{"source":"499","target":"267","id":"826"},{"source":"103","target":"65","id":"265"},{"source":"144","target":"436","id":"713"},{"source":"45","target":"310","id":"3230"},{"source":"1364","target":"113","id":"6516"},{"source":"1702","target":"853","id":"6489"},{"source":"940","target":"1","id":"2355"},{"source":"1555","target":"53","id":"5424"},{"source":"274","target":"272","id":"322"},{"source":"840","target":"48","id":"1916"},{"source":"305","target":"185","id":"401"},{"source":"1105","target":"51","id":"2981"},{"source":"1280","target":"607","id":"3799"},{"source":"1369","target":"1","id":"4256"},{"source":"1715","target":"652","id":"6611"},{"source":"908","target":"79","id":"3513"},{"source":"172","target":"712","id":"5734"},{"source":"1334","target":"82","id":"4053"},{"source":"792","target":"793","id":"1727"},{"source":"283","target":"293","id":"6347"},{"source":"112","target":"113","id":"112"},{"source":"992","target":"994","id":"2535"},{"source":"181","target":"79","id":"3521"},{"source":"1573","target":"334","id":"5544"},{"source":"1104","target":"62","id":"2976"},{"source":"1410","target":"304","id":"6578"},{"source":"31","target":"33","id":"32"},{"source":"530","target":"529","id":"2506"},{"source":"50","target":"591","id":"5470"},{"source":"709","target":"85","id":"1434"},{"source":"797","target":"48","id":"1751"},{"source":"576","target":"120","id":"2374"},{"source":"498","target":"816","id":"1990"},{"source":"897","target":"90","id":"5461"},{"source":"435","target":"598","id":"3149"},{"source":"305","target":"79","id":"399"},{"source":"181","target":"892","id":"3525"},{"source":"1435","target":"567","id":"4702"},{"source":"177","target":"549","id":"957"},{"source":"134","target":"136","id":"153"},{"source":"62","target":"68","id":"975"},{"source":"303","target":"304","id":"392"},{"source":"1279","target":"1579","id":"5628"},{"source":"946","target":"883","id":"2382"},{"source":"308","target":"211","id":"565"},{"source":"1436","target":"1437","id":"4707"},{"source":"526","target":"79","id":"3542"},{"source":"1583","target":"744","id":"5665"},{"source":"695","target":"618","id":"4953"},{"source":"322","target":"323","id":"3944"},{"source":"1016","target":"65","id":"2591"},{"source":"451","target":"65","id":"744"},{"source":"883","target":"109","id":"4191"},{"source":"707","target":"708","id":"1626"},{"source":"1448","target":"377","id":"4733"},{"source":"1033","target":"37","id":"2670"},{"source":"1373","target":"84","id":"6364"},{"source":"101","target":"109","id":"2878"},{"source":"877","target":"65","id":"2070"},{"source":"506","target":"409","id":"845"},{"source":"987","target":"1122","id":"3051"},{"source":"543","target":"405","id":"938"},{"source":"1588","target":"53","id":"5697"},{"source":"916","target":"96","id":"2253"},{"source":"74","target":"70","id":"1712"},{"source":"134","target":"135","id":"151"},{"source":"966","target":"183","id":"5822"},{"source":"1472","target":"1474","id":"4919"},{"source":"217","target":"495","id":"3121"},{"source":"131","target":"118","id":"2182"},{"source":"445","target":"225","id":"2824"},{"source":"892","target":"306","id":"5140"},{"source":"611","target":"166","id":"1174"},{"source":"1663","target":"515","id":"6238"},{"source":"593","target":"68","id":"1119"},{"source":"1262","target":"262","id":"4632"},{"source":"344","target":"82","id":"523"},{"source":"723","target":"307","id":"1480"},{"source":"1500","target":"960","id":"5095"},{"source":"52","target":"1429","id":"5771"},{"source":"391","target":"883","id":"3964"},{"source":"1236","target":"621","id":"3593"},{"source":"1083","target":"899","id":"5932"},{"source":"187","target":"191","id":"219"},{"source":"821","target":"109","id":"1840"},{"source":"382","target":"281","id":"621"},{"source":"1536","target":"109","id":"5283"},{"source":"773","target":"769","id":"1646"},{"source":"708","target":"504","id":"2873"},{"source":"245","target":"65","id":"1728"},{"source":"895","target":"131","id":"2140"},{"source":"1575","target":"457","id":"5607"},{"source":"577","target":"120","id":"4400"},{"source":"929","target":"120","id":"2307"},{"source":"1347","target":"79","id":"4130"},{"source":"824","target":"82","id":"3268"},{"source":"408","target":"48","id":"872"},{"source":"696","target":"100","id":"1414"},{"source":"596","target":"76","id":"1139"},{"source":"61","target":"65","id":"865"},{"source":"47","target":"513","id":"4432"},{"source":"1709","target":"301","id":"6543"},{"source":"617","target":"219","id":"1194"},{"source":"622","target":"372","id":"4458"},{"source":"49","target":"513","id":"5185"},{"source":"1014","target":"79","id":"3597"},{"source":"667","target":"1","id":"3595"},{"source":"1468","target":"68","id":"4858"},{"source":"981","target":"18","id":"3906"},{"source":"755","target":"299","id":"1597"},{"source":"1097","target":"1094","id":"2953"},{"source":"25","target":"456","id":"1014"},{"source":"1061","target":"1062","id":"2793"},{"source":"511","target":"50","id":"6473"},{"source":"1709","target":"296","id":"6545"},{"source":"49","target":"66","id":"5189"},{"source":"1629","target":"548","id":"6027"},{"source":"710","target":"83","id":"1466"},{"source":"15","target":"1","id":"19"},{"source":"1651","target":"209","id":"6172"},{"source":"1162","target":"1165","id":"3223"},{"source":"1245","target":"99","id":"3624"},{"source":"1125","target":"535","id":"4519"},{"source":"1376","target":"293","id":"4277"},{"source":"1299","target":"1302","id":"3880"},{"source":"1362","target":"64","id":"4223"},{"source":"746","target":"20","id":"4856"},{"source":"287","target":"286","id":"4883"},{"source":"459","target":"64","id":"766"},{"source":"802","target":"637","id":"1766"},{"source":"592","target":"82","id":"4818"},{"source":"754","target":"136","id":"5437"},{"source":"1675","target":"119","id":"6329"},{"source":"606","target":"422","id":"3114"},{"source":"93","target":"105","id":"2162"},{"source":"1090","target":"292","id":"3237"},{"source":"958","target":"962","id":"2815"},{"source":"1365","target":"607","id":"4242"},{"source":"1035","target":"272","id":"2687"},{"source":"626","target":"638","id":"3228"},{"source":"173","target":"174","id":"193"},{"source":"1509","target":"267","id":"5195"},{"source":"808","target":"411","id":"1789"},{"source":"398","target":"396","id":"5153"},{"source":"1595","target":"759","id":"5774"},{"source":"479","target":"1064","id":"4296"},{"source":"345","target":"159","id":"524"},{"source":"1282","target":"618","id":"5892"},{"source":"1469","target":"926","id":"4872"},{"source":"1083","target":"653","id":"5928"},{"source":"1615","target":"988","id":"5921"},{"source":"1365","target":"339","id":"4245"},{"source":"836","target":"266","id":"1903"},{"source":"774","target":"82","id":"1653"},{"source":"1258","target":"1235","id":"3668"},{"source":"374","target":"49","id":"5181"},{"source":"1138","target":"1123","id":"5251"},{"source":"1012","target":"709","id":"5570"},{"source":"1116","target":"1060","id":"5933"},{"source":"1703","target":"313","id":"6495"},{"source":"1286","target":"48","id":"3820"},{"source":"389","target":"167","id":"639"},{"source":"964","target":"175","id":"2436"},{"source":"1051","target":"567","id":"2762"},{"source":"980","target":"65","id":"2508"},{"source":"1087","target":"635","id":"5444"},{"source":"10","target":"5","id":"12"},{"source":"301","target":"292","id":"383"},{"source":"1292","target":"218","id":"5654"},{"source":"633","target":"53","id":"1222"},{"source":"437","target":"422","id":"1312"},{"source":"848","target":"752","id":"1944"},{"source":"745","target":"170","id":"1574"},{"source":"474","target":"475","id":"6606"},{"source":"1446","target":"982","id":"4730"},{"source":"495","target":"825","id":"6520"},{"source":"362","target":"372","id":"6462"},{"source":"1190","target":"101","id":"5059"},{"source":"1675","target":"64","id":"6327"},{"source":"106","target":"53","id":"2252"},{"source":"239","target":"149","id":"6452"},{"source":"745","target":"748","id":"1577"},{"source":"1291","target":"1580","id":"5643"},{"source":"528","target":"293","id":"3549"},{"source":"1607","target":"1248","id":"5906"},{"source":"653","target":"1083","id":"2865"},{"source":"1051","target":"437","id":"2758"},{"source":"200","target":"607","id":"4664"},{"source":"854","target":"1","id":"1970"},{"source":"1397","target":"65","id":"4410"},{"source":"1086","target":"1087","id":"2889"},{"source":"1471","target":"66","id":"4910"},{"source":"1707","target":"270","id":"6532"},{"source":"815","target":"438","id":"1821"},{"source":"951","target":"457","id":"2403"},{"source":"1037","target":"1434","id":"5027"},{"source":"1636","target":"1035","id":"6066"},{"source":"532","target":"534","id":"921"},{"source":"1325","target":"66","id":"4019"},{"source":"1540","target":"747","id":"5304"},{"source":"1382","target":"463","id":"4292"},{"source":"687","target":"99","id":"1380"},{"source":"182","target":"621","id":"4470"},{"source":"287","target":"62","id":"4885"},{"source":"1363","target":"47","id":"4229"},{"source":"1319","target":"79","id":"3982"},{"source":"616","target":"177","id":"6581"},{"source":"987","target":"388","id":"3050"},{"source":"1091","target":"61","id":"2908"},{"source":"1339","target":"784","id":"4086"},{"source":"273","target":"36","id":"5564"},{"source":"463","target":"430","id":"2639"},{"source":"846","target":"935","id":"5690"},{"source":"1575","target":"49","id":"5605"},{"source":"871","target":"408","id":"2042"},{"source":"1043","target":"567","id":"5676"},{"source":"1044","target":"166","id":"2729"},{"source":"509","target":"68","id":"852"},{"source":"687","target":"109","id":"1385"},{"source":"1512","target":"128","id":"5212"},{"source":"1337","target":"201","id":"4074"},{"source":"337","target":"296","id":"508"},{"source":"882","target":"109","id":"2888"},{"source":"1650","target":"370","id":"6155"},{"source":"1707","target":"144","id":"6534"},{"source":"204","target":"205","id":"233"},{"source":"80","target":"109","id":"3097"},{"source":"893","target":"571","id":"2561"},{"source":"815","target":"816","id":"1817"},{"source":"1593","target":"422","id":"5748"},{"source":"578","target":"519","id":"5678"},{"source":"1086","target":"50","id":"2890"},{"source":"1204","target":"238","id":"3454"},{"source":"1677","target":"254","id":"6360"},{"source":"256","target":"302","id":"5162"},{"source":"1452","target":"48","id":"4755"},{"source":"501","target":"51","id":"834"},{"source":"1327","target":"497","id":"5872"},{"source":"724","target":"5","id":"2830"},{"source":"1145","target":"1146","id":"3109"},{"source":"1183","target":"133","id":"3341"},{"source":"704","target":"91","id":"6531"},{"source":"46","target":"185","id":"4308"},{"source":"1670","target":"1671","id":"6285"},{"source":"915","target":"458","id":"2327"},{"source":"454","target":"431","id":"748"},{"source":"1286","target":"279","id":"3822"},{"source":"1096","target":"148","id":"2940"},{"source":"266","target":"502","id":"3993"},{"source":"1016","target":"49","id":"2596"},{"source":"1362","target":"119","id":"4225"},{"source":"1468","target":"119","id":"4864"},{"source":"1255","target":"1231","id":"3648"},{"source":"1266","target":"498","id":"3727"},{"source":"1004","target":"76","id":"2565"},{"source":"1092","target":"50","id":"2921"},{"source":"1326","target":"1329","id":"4030"},{"source":"63","target":"67","id":"996"},{"source":"1037","target":"1","id":"5026"},{"source":"1359","target":"88","id":"4199"},{"source":"786","target":"1312","id":"3947"},{"source":"398","target":"409","id":"5158"},{"source":"320","target":"296","id":"435"},{"source":"1391","target":"1115","id":"4368"},{"source":"47","target":"113","id":"4424"},{"source":"1125","target":"364","id":"4515"},{"source":"1652","target":"166","id":"6186"},{"source":"1402","target":"208","id":"5840"},{"source":"404","target":"65","id":"662"},{"source":"356","target":"357","id":"850"},{"source":"760","target":"519","id":"1607"},{"source":"1248","target":"1409","id":"5896"},{"source":"702","target":"161","id":"3885"},{"source":"1091","target":"51","id":"2916"},{"source":"711","target":"444","id":"1437"},{"source":"1336","target":"166","id":"4059"},{"source":"1086","target":"53","id":"2892"},{"source":"247","target":"175","id":"4604"},{"source":"53","target":"82","id":"1109"},{"source":"180","target":"181","id":"202"},{"source":"694","target":"334","id":"1405"},{"source":"459","target":"114","id":"768"},{"source":"1597","target":"1396","id":"5783"},{"source":"511","target":"65","id":"6476"},{"source":"208","target":"207","id":"5846"},{"source":"873","target":"50","id":"2060"},{"source":"1455","target":"511","id":"4767"},{"source":"869","target":"53","id":"2027"},{"source":"1209","target":"408","id":"3466"},{"source":"1297","target":"1036","id":"3866"},{"source":"1172","target":"666","id":"3273"},{"source":"727","target":"307","id":"1506"},{"source":"1198","target":"61","id":"3432"},{"source":"752","target":"136","id":"1940"},{"source":"1077","target":"647","id":"3446"},{"source":"306","target":"325","id":"452"},{"source":"1342","target":"194","id":"4103"},{"source":"948","target":"24","id":"3444"},{"source":"4","target":"5","id":"5"},{"source":"84","target":"82","id":"1301"},{"source":"1590","target":"64","id":"5714"},{"source":"1462","target":"1463","id":"4808"},{"source":"514","target":"62","id":"887"},{"source":"525","target":"517","id":"931"},{"source":"1579","target":"1249","id":"5634"},{"source":"1462","target":"1260","id":"4809"},{"source":"822","target":"48","id":"6264"},{"source":"727","target":"65","id":"1509"},{"source":"639","target":"65","id":"1259"},{"source":"62","target":"67","id":"971"},{"source":"358","target":"79","id":"550"},{"source":"756","target":"758","id":"1599"},{"source":"334","target":"65","id":"4745"},{"source":"438","target":"265","id":"1565"},{"source":"1178","target":"284","id":"3299"},{"source":"1690","target":"297","id":"6416"},{"source":"1102","target":"626","id":"3501"},{"source":"1486","target":"53","id":"5009"},{"source":"1326","target":"606","id":"4027"},{"source":"768","target":"771","id":"6394"},{"source":"1282","target":"1248","id":"5889"},{"source":"1648","target":"50","id":"6138"},{"source":"291","target":"219","id":"369"},{"source":"670","target":"159","id":"1343"},{"source":"411","target":"805","id":"1783"},{"source":"1189","target":"109","id":"3389"},{"source":"1362","target":"53","id":"4220"},{"source":"33","target":"344","id":"6440"},{"source":"1222","target":"325","id":"3535"},{"source":"1654","target":"1261","id":"6191"},{"source":"263","target":"113","id":"306"},{"source":"455","target":"621","id":"1200"},{"source":"288","target":"290","id":"367"},{"source":"283","target":"334","id":"6352"},{"source":"113","target":"116","id":"1100"},{"source":"302","target":"256","id":"5116"},{"source":"94","target":"96","id":"91"},{"source":"1458","target":"976","id":"4795"},{"source":"1334","target":"1122","id":"4056"},{"source":"65","target":"104","id":"2124"},{"source":"964","target":"95","id":"2435"},{"source":"878","target":"53","id":"2075"},{"source":"417","target":"1314","id":"4466"},{"source":"1593","target":"109","id":"5755"},{"source":"778","target":"109","id":"1677"},{"source":"649","target":"547","id":"1278"},{"source":"829","target":"109","id":"1868"},{"source":"1407","target":"185","id":"4490"},{"source":"190","target":"187","id":"2526"},{"source":"1684","target":"1141","id":"6390"},{"source":"1493","target":"698","id":"5057"},{"source":"453","target":"65","id":"1618"},{"source":"526","target":"619","id":"3538"},{"source":"1038","target":"1039","id":"5029"},{"source":"1559","target":"123","id":"5464"},{"source":"461","target":"53","id":"2618"},{"source":"1629","target":"907","id":"6023"},{"source":"169","target":"68","id":"189"},{"source":"897","target":"91","id":"5463"},{"source":"1184","target":"1082","id":"3348"},{"source":"694","target":"111","id":"1403"},{"source":"1448","target":"979","id":"4734"},{"source":"800","target":"498","id":"2030"},{"source":"610","target":"515","id":"1184"},{"source":"528","target":"294","id":"3550"},{"source":"1336","target":"321","id":"4061"},{"source":"631","target":"397","id":"1220"},{"source":"773","target":"771","id":"1652"},{"source":"506","target":"133","id":"840"},{"source":"174","target":"1","id":"1526"},{"source":"484","target":"281","id":"5589"},{"source":"1470","target":"64","id":"4901"},{"source":"592","target":"65","id":"4816"},{"source":"417","target":"371","id":"4464"},{"source":"317","target":"79","id":"4543"},{"source":"1347","target":"1263","id":"4132"},{"source":"1713","target":"429","id":"6602"},{"source":"393","target":"391","id":"642"},{"source":"22","target":"23","id":"23"},{"source":"68","target":"50","id":"106"},{"source":"1329","target":"437","id":"5596"},{"source":"451","target":"118","id":"741"},{"source":"1209","target":"62","id":"3467"},{"source":"1712","target":"183","id":"6599"},{"source":"417","target":"292","id":"4462"},{"source":"240","target":"242","id":"276"},{"source":"593","target":"300","id":"1124"},{"source":"1022","target":"451","id":"3355"},{"source":"1039","target":"206","id":"2698"},{"source":"645","target":"96","id":"1556"},{"source":"1663","target":"408","id":"6237"},{"source":"194","target":"195","id":"4481"},{"source":"752","target":"211","id":"1939"},{"source":"131","target":"114","id":"2185"},{"source":"404","target":"66","id":"663"},{"source":"1586","target":"1","id":"6554"},{"source":"142","target":"146","id":"164"},{"source":"1326","target":"422","id":"4025"},{"source":"689","target":"99","id":"6107"},{"source":"631","target":"48","id":"1221"},{"source":"781","target":"109","id":"2788"},{"source":"905","target":"906","id":"2216"},{"source":"50","target":"53","id":"5469"},{"source":"1202","target":"647","id":"4999"},{"source":"538","target":"48","id":"4657"},{"source":"1537","target":"823","id":"5293"},{"source":"235","target":"160","id":"268"},{"source":"771","target":"769","id":"6413"},{"source":"397","target":"398","id":"3916"},{"source":"1170","target":"1090","id":"3271"},{"source":"1648","target":"280","id":"6142"},{"source":"1599","target":"659","id":"5791"},{"source":"206","target":"1","id":"2693"},{"source":"984","target":"985","id":"2516"},{"source":"1175","target":"598","id":"3328"},{"source":"856","target":"294","id":"1978"},{"source":"1218","target":"1","id":"3510"},{"source":"608","target":"515","id":"1492"},{"source":"79","target":"300","id":"1255"},{"source":"329","target":"311","id":"3240"},{"source":"1577","target":"441","id":"5621"},{"source":"1191","target":"52","id":"3400"},{"source":"792","target":"159","id":"1726"},{"source":"1405","target":"1197","id":"4457"},{"source":"835","target":"264","id":"5066"},{"source":"1621","target":"1547","id":"5983"},{"source":"1446","target":"1447","id":"4729"},{"source":"574","target":"292","id":"1061"},{"source":"797","target":"798","id":"1754"},{"source":"1221","target":"182","id":"3532"},{"source":"19","target":"21","id":"22"},{"source":"1519","target":"732","id":"5241"},{"source":"67","target":"118","id":"2711"},{"source":"244","target":"643","id":"1671"},{"source":"742","target":"203","id":"5146"},{"source":"864","target":"865","id":"2010"},{"source":"715","target":"1","id":"1448"},{"source":"52","target":"114","id":"5769"},{"source":"392","target":"1133","id":"4273"},{"source":"838","target":"51","id":"2458"},{"source":"1329","target":"422","id":"5595"},{"source":"994","target":"170","id":"2540"},{"source":"1501","target":"513","id":"5104"},{"source":"913","target":"137","id":"5135"},{"source":"1198","target":"408","id":"3433"},{"source":"1180","target":"334","id":"3313"},{"source":"1348","target":"433","id":"4137"},{"source":"1004","target":"439","id":"2566"},{"source":"992","target":"993","id":"2534"},{"source":"843","target":"444","id":"1920"},{"source":"1094","target":"312","id":"2937"},{"source":"656","target":"424","id":"5331"},{"source":"834","target":"403","id":"5071"},{"source":"1014","target":"1","id":"3600"},{"source":"1631","target":"420","id":"6042"},{"source":"904","target":"118","id":"2208"},{"source":"46","target":"723","id":"4309"},{"source":"1107","target":"50","id":"2989"},{"source":"1390","target":"90","id":"4360"},{"source":"1125","target":"532","id":"4516"},{"source":"1644","target":"48","id":"6128"},{"source":"1319","target":"50","id":"3984"},{"source":"327","target":"219","id":"458"},{"source":"597","target":"104","id":"1141"},{"source":"1597","target":"405","id":"5782"},{"source":"727","target":"229","id":"1505"},{"source":"1376","target":"516","id":"4279"},{"source":"658","target":"662","id":"1322"},{"source":"1091","target":"53","id":"2910"},{"source":"975","target":"167","id":"2487"},{"source":"703","target":"161","id":"3887"},{"source":"1631","target":"209","id":"6043"},{"source":"112","target":"114","id":"115"},{"source":"327","target":"298","id":"456"},{"source":"1304","target":"1305","id":"3901"},{"source":"67","target":"64","id":"2712"},{"source":"1080","target":"294","id":"2850"},{"source":"200","target":"444","id":"4665"},{"source":"321","target":"185","id":"730"},{"source":"82","target":"84","id":"6437"},{"source":"1689","target":"159","id":"6405"},{"source":"437","target":"656","id":"1317"},{"source":"1050","target":"401","id":"4441"},{"source":"1660","target":"502","id":"6227"},{"source":"35","target":"36","id":"414"},{"source":"607","target":"216","id":"1486"},{"source":"1471","target":"48","id":"4912"},{"source":"285","target":"65","id":"354"},{"source":"1334","target":"1123","id":"4049"},{"source":"616","target":"79","id":"6582"},{"source":"31","target":"32","id":"31"},{"source":"1404","target":"429","id":"4538"},{"source":"664","target":"646","id":"3702"},{"source":"1011","target":"1012","id":"2581"},{"source":"336","target":"335","id":"3144"},{"source":"876","target":"976","id":"3128"},{"source":"635","target":"53","id":"4401"},{"source":"1248","target":"1249","id":"5900"},{"source":"378","target":"68","id":"3204"},{"source":"991","target":"429","id":"4948"},{"source":"1325","target":"53","id":"4016"},{"source":"441","target":"82","id":"4378"},{"source":"1307","target":"1308","id":"3918"},{"source":"862","target":"554","id":"2632"},{"source":"1591","target":"118","id":"5725"},{"source":"279","target":"53","id":"505"},{"source":"931","target":"61","id":"2310"},{"source":"333","target":"61","id":"496"},{"source":"391","target":"1133","id":"3969"},{"source":"214","target":"217","id":"245"},{"source":"1707","target":"109","id":"6539"},{"source":"167","target":"334","id":"2338"},{"source":"651","target":"132","id":"1305"},{"source":"1423","target":"1424","id":"4586"},{"source":"208","target":"209","id":"5843"},{"source":"276","target":"1384","id":"6588"},{"source":"896","target":"388","id":"4820"},{"source":"1374","target":"334","id":"4270"},{"source":"499","target":"181","id":"825"},{"source":"621","target":"1315","id":"3961"},{"source":"647","target":"1003","id":"3711"},{"source":"144","target":"437","id":"715"},{"source":"953","target":"76","id":"2412"},{"source":"1423","target":"1258","id":"4589"},{"source":"375","target":"112","id":"595"},{"source":"409","target":"49","id":"4652"},{"source":"304","target":"1410","id":"4508"},{"source":"926","target":"436","id":"2383"},{"source":"532","target":"536","id":"924"},{"source":"425","target":"250","id":"700"},{"source":"1637","target":"993","id":"6076"},{"source":"1294","target":"833","id":"3848"},{"source":"204","target":"209","id":"237"},{"source":"24","target":"68","id":"5814"},{"source":"322","target":"321","id":"3940"},{"source":"748","target":"281","id":"3784"},{"source":"659","target":"1303","id":"3881"},{"source":"993","target":"998","id":"4530"},{"source":"894","target":"463","id":"2122"},{"source":"1654","target":"1","id":"6192"},{"source":"305","target":"308","id":"398"},{"source":"1107","target":"66","id":"2986"},{"source":"1483","target":"1077","id":"4986"},{"source":"1152","target":"316","id":"4499"},{"source":"285","target":"53","id":"353"},{"source":"1215","target":"159","id":"3490"},{"source":"462","target":"177","id":"771"},{"source":"1470","target":"62","id":"4898"},{"source":"619","target":"617","id":"6034"},{"source":"1468","target":"50","id":"4866"},{"source":"712","target":"713","id":"2033"},{"source":"1152","target":"292","id":"4493"},{"source":"1336","target":"839","id":"4064"},{"source":"436","target":"266","id":"1006"},{"source":"1256","target":"100","id":"3650"},{"source":"432","target":"1","id":"710"},{"source":"115","target":"112","id":"2324"},{"source":"1500","target":"959","id":"5100"},{"source":"413","target":"419","id":"685"},{"source":"645","target":"82","id":"1557"},{"source":"1188","target":"103","id":"3380"},{"source":"684","target":"685","id":"1374"},{"source":"1591","target":"53","id":"5724"},{"source":"364","target":"116","id":"585"},{"source":"1099","target":"313","id":"2951"},{"source":"978","target":"310","id":"2503"},{"source":"1543","target":"251","id":"5339"},{"source":"1707","target":"567","id":"6535"},{"source":"1522","target":"1","id":"5249"},{"source":"748","target":"335","id":"3789"},{"source":"1194","target":"833","id":"3411"},{"source":"1126","target":"896","id":"4811"},{"source":"1065","target":"751","id":"2797"},{"source":"1083","target":"913","id":"5930"},{"source":"1246","target":"688","id":"6106"},{"source":"541","target":"539","id":"2740"},{"source":"288","target":"65","id":"360"},{"source":"1214","target":"128","id":"3485"},{"source":"397","target":"48","id":"3915"},{"source":"756","target":"757","id":"1598"},{"source":"98","target":"99","id":"93"},{"source":"587","target":"267","id":"1107"},{"source":"443","target":"150","id":"1290"},{"source":"890","target":"790","id":"2109"},{"source":"253","target":"84","id":"806"},{"source":"183","target":"966","id":"5122"},{"source":"452","target":"451","id":"2280"},{"source":"502","target":"109","id":"5078"},{"source":"163","target":"162","id":"2236"},{"source":"1467","target":"444","id":"4852"},{"source":"1505","target":"500","id":"5110"},{"source":"1696","target":"50","id":"6431"},{"source":"943","target":"169","id":"2358"},{"source":"858","target":"584","id":"5063"},{"source":"357","target":"216","id":"917"},{"source":"1519","target":"757","id":"5240"},{"source":"1353","target":"335","id":"4173"},{"source":"182","target":"185","id":"4472"},{"source":"1368","target":"1095","id":"4251"},{"source":"713","target":"82","id":"6646"},{"source":"780","target":"782","id":"1695"},{"source":"1194","target":"484","id":"3416"},{"source":"1411","target":"230","id":"4511"},{"source":"48","target":"50","id":"4634"},{"source":"287","target":"53","id":"4886"},{"source":"707","target":"82","id":"1628"},{"source":"799","target":"280","id":"1765"},{"source":"1683","target":"814","id":"6381"},{"source":"1580","target":"1291","id":"5649"},{"source":"829","target":"453","id":"1870"},{"source":"681","target":"640","id":"1372"},{"source":"501","target":"504","id":"836"},{"source":"1182","target":"166","id":"3337"},{"source":"392","target":"585","id":"4275"},{"source":"109","target":"101","id":"5722"},{"source":"1333","target":"624","id":"4048"},{"source":"49","target":"50","id":"5186"},{"source":"1165","target":"64","id":"5229"},{"source":"1158","target":"122","id":"3182"},{"source":"583","target":"580","id":"1084"},{"source":"1004","target":"95","id":"2563"},{"source":"1120","target":"1","id":"3039"},{"source":"838","target":"513","id":"2457"},{"source":"612","target":"37","id":"1189"},{"source":"186","target":"189","id":"209"},{"source":"128","target":"85","id":"137"},{"source":"637","target":"300","id":"1252"},{"source":"698","target":"696","id":"6439"},{"source":"1383","target":"311","id":"4312"},{"source":"1554","target":"938","id":"5422"},{"source":"1435","target":"656","id":"4705"},{"source":"1607","target":"618","id":"5908"},{"source":"840","target":"502","id":"1917"},{"source":"741","target":"20","id":"1541"},{"source":"1633","target":"1513","id":"6061"},{"source":"859","target":"87","id":"1997"},{"source":"569","target":"504","id":"2198"},{"source":"462","target":"463","id":"773"},{"source":"1145","target":"381","id":"3112"},{"source":"104","target":"598","id":"2211"},{"source":"665","target":"455","id":"1328"},{"source":"293","target":"294","id":"617"},{"source":"1475","target":"1476","id":"4926"},{"source":"748","target":"600","id":"3790"},{"source":"1001","target":"433","id":"2552"},{"source":"701","target":"91","id":"1421"},{"source":"1173","target":"334","id":"3282"},{"source":"222","target":"166","id":"250"},{"source":"1719","target":"53","id":"6630"},{"source":"1702","target":"1703","id":"6485"},{"source":"373","target":"51","id":"594"},{"source":"1674","target":"61","id":"6308"},{"source":"1675","target":"53","id":"6325"},{"source":"186","target":"190","id":"210"},{"source":"983","target":"937","id":"4694"},{"source":"924","target":"1379","id":"5325"},{"source":"1178","target":"282","id":"3301"},{"source":"98","target":"101","id":"95"},{"source":"921","target":"120","id":"2271"},{"source":"135","target":"133","id":"1043"},{"source":"1141","target":"1136","id":"3093"},{"source":"298","target":"79","id":"380"},{"source":"492","target":"494","id":"818"},{"source":"552","target":"68","id":"4888"},{"source":"456","target":"24","id":"5808"},{"source":"24","target":"456","id":"5818"},{"source":"263","target":"265","id":"308"},{"source":"317","target":"181","id":"4544"},{"source":"1023","target":"581","id":"4356"},{"source":"1353","target":"748","id":"4167"},{"source":"1425","target":"1235","id":"6435"},{"source":"1296","target":"352","id":"3859"},{"source":"797","target":"50","id":"1755"},{"source":"60","target":"67","id":"61"},{"source":"454","target":"457","id":"755"},{"source":"34","target":"35","id":"33"},{"source":"1208","target":"16","id":"3463"},{"source":"1490","target":"758","id":"5035"},{"source":"385","target":"1","id":"3684"},{"source":"811","target":"65","id":"1805"},{"source":"296","target":"182","id":"431"},{"source":"750","target":"185","id":"1588"},{"source":"1519","target":"1015","id":"5244"},{"source":"117","target":"67","id":"122"},{"source":"209","target":"272","id":"2669"},{"source":"541","target":"703","id":"2738"},{"source":"670","target":"504","id":"1346"},{"source":"364","target":"371","id":"586"},{"source":"64","target":"68","id":"1823"},{"source":"583","target":"114","id":"1085"},{"source":"168","target":"165","id":"6368"},{"source":"1507","target":"325","id":"5151"},{"source":"117","target":"53","id":"118"},{"source":"1709","target":"1557","id":"6552"},{"source":"1194","target":"51","id":"3415"},{"source":"301","target":"295","id":"386"},{"source":"1721","target":"114","id":"6672"},{"source":"178","target":"1","id":"1240"},{"source":"824","target":"1159","id":"3266"},{"source":"398","target":"405","id":"5154"},{"source":"1088","target":"1090","id":"2906"},{"source":"1286","target":"339","id":"3824"},{"source":"1088","target":"146","id":"2905"},{"source":"124","target":"123","id":"131"},{"source":"604","target":"495","id":"1154"},{"source":"914","target":"79","id":"2245"},{"source":"99","target":"89","id":"159"},{"source":"1189","target":"159","id":"3393"},{"source":"660","target":"1330","id":"4040"},{"source":"1362","target":"108","id":"4228"},{"source":"1124","target":"335","id":"4843"},{"source":"251","target":"708","id":"3975"},{"source":"1665","target":"159","id":"6271"},{"source":"1402","target":"1050","id":"5839"},{"source":"1033","target":"1034","id":"2673"},{"source":"1259","target":"1235","id":"3962"},{"source":"1568","target":"97","id":"5511"},{"source":"695","target":"234","id":"4952"},{"source":"1353","target":"747","id":"4166"},{"source":"509","target":"62","id":"855"},{"source":"1608","target":"89","id":"5880"},{"source":"311","target":"45","id":"470"},{"source":"1483","target":"1201","id":"4990"},{"source":"257","target":"51","id":"298"},{"source":"465","target":"177","id":"950"},{"source":"464","target":"1","id":"3865"},{"source":"984","target":"127","id":"2515"},{"source":"1420","target":"49","id":"4562"},{"source":"266","target":"438","id":"3990"},{"source":"1164","target":"426","id":"3986"},{"source":"44","target":"50","id":"46"},{"source":"475","target":"473","id":"795"},{"source":"1673","target":"816","id":"6303"},{"source":"711","target":"715","id":"1442"},{"source":"1355","target":"1356","id":"4177"},{"source":"314","target":"292","id":"420"},{"source":"1161","target":"120","id":"3199"},{"source":"873","target":"131","id":"2056"},{"source":"249","target":"53","id":"284"},{"source":"413","target":"416","id":"682"},{"source":"1134","target":"284","id":"3076"},{"source":"1293","target":"49","id":"3844"},{"source":"1346","target":"903","id":"4123"},{"source":"1004","target":"216","id":"2564"},{"source":"258","target":"571","id":"1308"},{"source":"1580","target":"1581","id":"5652"},{"source":"988","target":"292","id":"2522"},{"source":"195","target":"450","id":"5390"},{"source":"1027","target":"966","id":"5436"},{"source":"1678","target":"50","id":"6375"},{"source":"628","target":"906","id":"4151"},{"source":"519","target":"120","id":"1070"},{"source":"1391","target":"1060","id":"4366"},{"source":"893","target":"65","id":"2557"},{"source":"1051","target":"82","id":"2764"},{"source":"270","target":"40","id":"412"},{"source":"1712","target":"894","id":"6594"},{"source":"1131","target":"512","id":"3068"},{"source":"1366","target":"82","id":"4250"},{"source":"1499","target":"437","id":"5090"},{"source":"1605","target":"109","id":"5859"},{"source":"131","target":"65","id":"2183"},{"source":"583","target":"584","id":"1089"},{"source":"131","target":"50","id":"2188"},{"source":"413","target":"420","id":"687"},{"source":"1096","target":"1097","id":"2943"},{"source":"373","target":"113","id":"590"},{"source":"548","target":"547","id":"959"},{"source":"617","target":"79","id":"1195"},{"source":"184","target":"79","id":"5123"},{"source":"201","target":"200","id":"4760"},{"source":"607","target":"608","id":"1489"},{"source":"1232","target":"1233","id":"3588"},{"source":"907","target":"906","id":"2221"},{"source":"134","target":"138","id":"155"},{"source":"245","target":"102","id":"1733"},{"source":"1011","target":"1015","id":"2588"},{"source":"606","target":"104","id":"3116"},{"source":"1357","target":"185","id":"5315"},{"source":"753","target":"79","id":"5128"},{"source":"1689","target":"1079","id":"6408"},{"source":"903","target":"53","id":"2177"},{"source":"1189","target":"1190","id":"3388"},{"source":"136","target":"752","id":"2400"},{"source":"1642","target":"1407","id":"6100"},{"source":"1325","target":"513","id":"4012"},{"source":"1060","target":"1116","id":"3018"},{"source":"1536","target":"65","id":"5286"},{"source":"1304","target":"311","id":"3904"},{"source":"1470","target":"63","id":"4899"},{"source":"410","target":"61","id":"672"},{"source":"334","target":"53","id":"4744"},{"source":"1578","target":"105","id":"5624"},{"source":"805","target":"281","id":"1775"},{"source":"1553","target":"167","id":"5411"},{"source":"1537","target":"68","id":"5291"},{"source":"1591","target":"50","id":"5732"},{"source":"1216","target":"214","id":"3495"},{"source":"514","target":"68","id":"885"},{"source":"483","target":"279","id":"3922"},{"source":"240","target":"152","id":"274"},{"source":"93","target":"53","id":"2156"},{"source":"868","target":"531","id":"2022"},{"source":"1342","target":"335","id":"4100"},{"source":"1658","target":"296","id":"6214"},{"source":"658","target":"664","id":"1324"},{"source":"1046","target":"1042","id":"6337"},{"source":"1675","target":"216","id":"6324"},{"source":"607","target":"53","id":"1487"},{"source":"873","target":"114","id":"2058"},{"source":"1714","target":"1711","id":"6610"},{"source":"339","target":"65","id":"4210"},{"source":"251","target":"97","id":"3977"},{"source":"1133","target":"391","id":"3071"},{"source":"102","target":"103","id":"96"},{"source":"1657","target":"666","id":"6210"},{"source":"573","target":"281","id":"1048"},{"source":"895","target":"67","id":"2142"},{"source":"569","target":"82","id":"2201"},{"source":"1107","target":"61","id":"2991"},{"source":"1499","target":"422","id":"5087"},{"source":"773","target":"568","id":"1648"},{"source":"283","target":"61","id":"6348"},{"source":"1702","target":"79","id":"6488"},{"source":"1520","target":"659","id":"5247"},{"source":"1480","target":"391","id":"4978"},{"source":"598","target":"816","id":"1983"},{"source":"47","target":"267","id":"4428"},{"source":"1601","target":"84","id":"5801"},{"source":"1177","target":"493","id":"5364"},{"source":"801","target":"397","id":"4213"},{"source":"593","target":"131","id":"1123"},{"source":"85","target":"709","id":"1931"},{"source":"1004","target":"1005","id":"2569"},{"source":"268","target":"270","id":"312"},{"source":"410","target":"45","id":"676"},{"source":"1405","target":"613","id":"4452"},{"source":"180","target":"184","id":"205"},{"source":"1296","target":"498","id":"3862"},{"source":"1230","target":"216","id":"3586"},{"source":"1189","target":"101","id":"3387"},{"source":"518","target":"519","id":"895"},{"source":"881","target":"109","id":"2086"},{"source":"1687","target":"1158","id":"6397"},{"source":"47","target":"589","id":"4425"},{"source":"1221","target":"255","id":"3531"},{"source":"1314","target":"292","id":"4449"},{"source":"1280","target":"732","id":"3807"},{"source":"789","target":"50","id":"3029"},{"source":"224","target":"724","id":"2827"},{"source":"176","target":"79","id":"198"},{"source":"1443","target":"248","id":"4717"},{"source":"1108","target":"73","id":"2999"},{"source":"373","target":"115","id":"591"},{"source":"682","target":"161","id":"6167"},{"source":"1292","target":"983","id":"5655"},{"source":"314","target":"315","id":"423"},{"source":"580","target":"578","id":"1077"},{"source":"895","target":"50","id":"2134"},{"source":"1125","target":"281","id":"4520"},{"source":"1122","target":"987","id":"3045"},{"source":"741","target":"742","id":"1547"},{"source":"1244","target":"50","id":"3617"},{"source":"39","target":"275","id":"4306"},{"source":"1694","target":"1695","id":"6423"},{"source":"1039","target":"1037","id":"2700"},{"source":"398","target":"397","id":"5156"},{"source":"720","target":"141","id":"3512"},{"source":"504","target":"427","id":"1637"},{"source":"1048","target":"703","id":"2748"},{"source":"808","target":"405","id":"1791"},{"source":"1466","target":"505","id":"4842"},{"source":"1510","target":"513","id":"5205"},{"source":"250","target":"109","id":"3368"},{"source":"749","target":"1449","id":"4739"},{"source":"1407","target":"1408","id":"4491"},{"source":"1037","target":"1039","id":"5025"},{"source":"561","target":"72","id":"1023"},{"source":"1537","target":"1538","id":"5294"},{"source":"1408","target":"185","id":"6202"},{"source":"108","target":"118","id":"5489"},{"source":"1156","target":"51","id":"3154"},{"source":"653","target":"1082","id":"2866"},{"source":"1319","target":"108","id":"3985"},{"source":"834","target":"835","id":"5072"},{"source":"1247","target":"1249","id":"3632"},{"source":"915","target":"697","id":"2328"},{"source":"629","target":"177","id":"2679"},{"source":"249","target":"251","id":"288"},{"source":"859","target":"863","id":"2000"},{"source":"871","target":"513","id":"2049"},{"source":"694","target":"53","id":"1401"},{"source":"290","target":"53","id":"1852"},{"source":"850","target":"718","id":"1954"},{"source":"881","target":"167","id":"2092"},{"source":"1490","target":"235","id":"5036"},{"source":"197","target":"202","id":"231"},{"source":"1651","target":"37","id":"6171"},{"source":"529","target":"353","id":"914"},{"source":"830","target":"831","id":"1876"},{"source":"1519","target":"759","id":"5239"},{"source":"93","target":"84","id":"2157"},{"source":"1590","target":"606","id":"5717"},{"source":"883","target":"68","id":"4185"},{"source":"926","target":"262","id":"2384"},{"source":"1401","target":"284","id":"4423"},{"source":"100","target":"53","id":"1843"},{"source":"703","target":"539","id":"3890"},{"source":"379","target":"118","id":"4127"},{"source":"1012","target":"50","id":"5575"},{"source":"1420","target":"335","id":"4559"},{"source":"348","target":"347","id":"4622"},{"source":"1109","target":"465","id":"3000"},{"source":"69","target":"70","id":"64"},{"source":"514","target":"515","id":"889"},{"source":"60","target":"63","id":"56"},{"source":"1657","target":"457","id":"6205"},{"source":"1201","target":"427","id":"4997"},{"source":"184","target":"181","id":"5124"},{"source":"127","target":"812","id":"2354"},{"source":"851","target":"852","id":"1960"},{"source":"1556","target":"182","id":"5432"},{"source":"954","target":"159","id":"3693"},{"source":"1041","target":"567","id":"2704"},{"source":"1413","target":"1200","id":"4531"},{"source":"329","target":"626","id":"3242"},{"source":"984","target":"987","id":"2518"},{"source":"382","target":"53","id":"620"},{"source":"1472","target":"241","id":"4923"},{"source":"605","target":"204","id":"2898"},{"source":"6","target":"1","id":"6"},{"source":"1334","target":"1174","id":"4050"},{"source":"413","target":"417","id":"683"},{"source":"196","target":"136","id":"225"},{"source":"1701","target":"515","id":"6481"},{"source":"722","target":"234","id":"1478"},{"source":"821","target":"822","id":"1841"},{"source":"822","target":"181","id":"6262"},{"source":"1130","target":"653","id":"5938"},{"source":"376","target":"377","id":"604"},{"source":"1012","target":"103","id":"5576"},{"source":"590","target":"113","id":"5166"},{"source":"1235","target":"524","id":"3591"},{"source":"738","target":"1289","id":"3830"},{"source":"857","target":"816","id":"2014"},{"source":"717","target":"712","id":"1464"},{"source":"250","target":"249","id":"3369"},{"source":"670","target":"53","id":"1344"},{"source":"514","target":"50","id":"884"},{"source":"1594","target":"498","id":"5764"},{"source":"436","target":"556","id":"1005"},{"source":"1146","target":"318","id":"3659"},{"source":"609","target":"433","id":"3064"},{"source":"627","target":"861","id":"3856"},{"source":"283","target":"279","id":"6353"},{"source":"681","target":"641","id":"1373"},{"source":"455","target":"301","id":"1199"},{"source":"553","target":"61","id":"983"},{"source":"713","target":"502","id":"6645"},{"source":"1456","target":"279","id":"4773"},{"source":"112","target":"65","id":"113"},{"source":"1588","target":"109","id":"5702"},{"source":"946","target":"95","id":"2376"},{"source":"1185","target":"1083","id":"5940"},{"source":"951","target":"455","id":"2407"},{"source":"72","target":"70","id":"1022"},{"source":"1618","target":"388","id":"5954"},{"source":"835","target":"265","id":"5067"},{"source":"405","target":"411","id":"2929"},{"source":"829","target":"830","id":"1871"},{"source":"292","target":"296","id":"373"},{"source":"622","target":"1315","id":"4461"},{"source":"142","target":"144","id":"162"},{"source":"51","target":"119","id":"5586"},{"source":"567","target":"1044","id":"2720"},{"source":"1037","target":"206","id":"5024"},{"source":"407","target":"61","id":"665"},{"source":"427","target":"504","id":"1034"},{"source":"1117","target":"79","id":"3021"},{"source":"1168","target":"1166","id":"3257"},{"source":"1337","target":"411","id":"4070"},{"source":"26","target":"23","id":"2879"},{"source":"1500","target":"962","id":"5097"},{"source":"951","target":"431","id":"2404"},{"source":"543","target":"335","id":"936"},{"source":"1513","target":"668","id":"5215"},{"source":"1305","target":"415","id":"4576"},{"source":"562","target":"559","id":"1026"},{"source":"1182","target":"201","id":"3336"},{"source":"199","target":"166","id":"3317"},{"source":"880","target":"53","id":"2081"},{"source":"624","target":"896","id":"2145"},{"source":"881","target":"882","id":"2084"},{"source":"565","target":"1430","id":"4644"},{"source":"1491","target":"1","id":"5046"},{"source":"472","target":"475","id":"785"},{"source":"1325","target":"50","id":"4013"},{"source":"1563","target":"1566","id":"5501"},{"source":"1337","target":"805","id":"4069"},{"source":"1168","target":"312","id":"3258"},{"source":"237","target":"239","id":"273"},{"source":"1606","target":"1409","id":"5866"},{"source":"1162","target":"519","id":"3219"},{"source":"1081","target":"361","id":"2856"},{"source":"1193","target":"1","id":"3407"},{"source":"583","target":"120","id":"1087"},{"source":"1583","target":"936","id":"5668"},{"source":"1660","target":"505","id":"6224"},{"source":"691","target":"128","id":"1390"},{"source":"628","target":"1324","id":"4148"},{"source":"45","target":"185","id":"3236"},{"source":"1254","target":"280","id":"3644"},{"source":"1568","target":"258","id":"5510"},{"source":"364","target":"115","id":"582"},{"source":"1101","target":"1102","id":"2960"},{"source":"1632","target":"335","id":"6047"},{"source":"1365","target":"147","id":"4241"},{"source":"1356","target":"57","id":"4284"},{"source":"977","target":"432","id":"2498"},{"source":"740","target":"65","id":"1537"},{"source":"691","target":"215","id":"1395"},{"source":"1056","target":"479","id":"2779"},{"source":"1280","target":"51","id":"3803"},{"source":"1316","target":"201","id":"4970"},{"source":"44","target":"49","id":"45"},{"source":"1525","target":"1527","id":"5264"},{"source":"967","target":"1026","id":"2654"},{"source":"1349","target":"463","id":"4144"},{"source":"732","target":"1621","id":"5974"},{"source":"1570","target":"96","id":"5527"},{"source":"1456","target":"758","id":"4772"},{"source":"1563","target":"1565","id":"5498"},{"source":"1501","target":"1502","id":"5101"},{"source":"1644","target":"444","id":"6124"},{"source":"291","target":"293","id":"370"},{"source":"786","target":"206","id":"3946"},{"source":"1530","target":"53","id":"5275"},{"source":"1296","target":"788","id":"3861"},{"source":"1048","target":"704","id":"2750"},{"source":"314","target":"296","id":"421"},{"source":"379","target":"155","id":"4129"},{"source":"1576","target":"1401","id":"5612"},{"source":"1599","target":"661","id":"5794"},{"source":"938","target":"976","id":"2484"},{"source":"1329","target":"1","id":"5599"},{"source":"260","target":"238","id":"304"},{"source":"334","target":"406","id":"4741"},{"source":"1553","target":"166","id":"5408"},{"source":"341","target":"1","id":"518"},{"source":"1309","target":"114","id":"3928"},{"source":"293","target":"381","id":"616"},{"source":"969","target":"48","id":"2471"},{"source":"1121","target":"313","id":"3682"},{"source":"1351","target":"104","id":"4157"},{"source":"1232","target":"86","id":"3587"},{"source":"1349","target":"1350","id":"4139"},{"source":"1418","target":"95","id":"4552"},{"source":"1276","target":"370","id":"3766"},{"source":"1281","target":"618","id":"3808"},{"source":"1383","target":"723","id":"4314"},{"source":"663","target":"888","id":"2791"},{"source":"565","target":"777","id":"4643"},{"source":"828","target":"76","id":"1859"},{"source":"649","target":"177","id":"1279"},{"source":"1244","target":"956","id":"3620"},{"source":"555","target":"510","id":"3190"},{"source":"405","target":"66","id":"2930"},{"source":"64","target":"93","id":"1827"},{"source":"1621","target":"261","id":"5984"},{"source":"670","target":"65","id":"1347"},{"source":"807","target":"411","id":"6518"},{"source":"362","target":"360","id":"6458"},{"source":"862","target":"504","id":"2630"},{"source":"376","target":"296","id":"606"},{"source":"1336","target":"281","id":"4063"},{"source":"595","target":"53","id":"1129"},{"source":"51","target":"49","id":"5579"},{"source":"1107","target":"53","id":"2984"},{"source":"1269","target":"62","id":"3747"},{"source":"342","target":"183","id":"522"},{"source":"665","target":"457","id":"1332"},{"source":"1209","target":"666","id":"3469"},{"source":"64","target":"118","id":"1825"},{"source":"787","target":"786","id":"6470"},{"source":"703","target":"91","id":"3888"},{"source":"936","target":"498","id":"2329"},{"source":"1471","target":"607","id":"4908"},{"source":"252","target":"95","id":"760"},{"source":"984","target":"986","id":"2517"},{"source":"841","target":"967","id":"2452"},{"source":"1152","target":"371","id":"4494"},{"source":"1567","target":"238","id":"5504"},{"source":"656","target":"423","id":"5329"},{"source":"1197","target":"626","id":"3427"},{"source":"1101","target":"1094","id":"2956"},{"source":"357","target":"1","id":"919"},{"source":"544","target":"87","id":"6114"},{"source":"696","target":"167","id":"1415"},{"source":"1512","target":"82","id":"5211"},{"source":"244","target":"104","id":"1668"},{"source":"903","target":"104","id":"2174"},{"source":"1320","target":"232","id":"3997"},{"source":"841","target":"259","id":"2451"},{"source":"1577","target":"172","id":"5622"},{"source":"555","target":"436","id":"3186"},{"source":"903","target":"65","id":"2178"},{"source":"938","target":"165","id":"2480"},{"source":"616","target":"296","id":"6580"},{"source":"686","target":"685","id":"6278"},{"source":"1623","target":"1547","id":"5986"},{"source":"512","target":"784","id":"1701"},{"source":"318","target":"1","id":"532"},{"source":"553","target":"287","id":"981"},{"source":"290","target":"826","id":"1855"},{"source":"351","target":"79","id":"4446"},{"source":"731","target":"111","id":"4956"},{"source":"1143","target":"1","id":"3098"},{"source":"605","target":"428","id":"2901"},{"source":"1694","target":"303","id":"6424"},{"source":"643","target":"109","id":"1266"},{"source":"105","target":"53","id":"5380"},{"source":"997","target":"313","id":"2543"},{"source":"1418","target":"1419","id":"4555"},{"source":"1684","target":"1136","id":"6385"},{"source":"917","target":"76","id":"2254"},{"source":"269","target":"275","id":"335"},{"source":"1358","target":"1379","id":"4288"},{"source":"163","target":"164","id":"2238"},{"source":"387","target":"388","id":"636"},{"source":"1054","target":"908","id":"2776"},{"source":"161","target":"434","id":"5309"},{"source":"1707","target":"423","id":"6537"},{"source":"1631","target":"204","id":"6041"},{"source":"478","target":"479","id":"796"},{"source":"541","target":"704","id":"2739"},{"source":"1628","target":"532","id":"6016"},{"source":"54","target":"55","id":"50"},{"source":"826","target":"626","id":"5360"},{"source":"1584","target":"1060","id":"5670"},{"source":"442","target":"443","id":"719"},{"source":"1076","target":"1262","id":"3698"},{"source":"425","target":"426","id":"697"},{"source":"1562","target":"596","id":"5495"},{"source":"181","target":"312","id":"3522"},{"source":"337","target":"48","id":"516"},{"source":"958","target":"48","id":"2814"},{"source":"821","target":"88","id":"1837"},{"source":"1653","target":"351","id":"6189"},{"source":"374","target":"113","id":"5175"},{"source":"979","target":"415","id":"2659"},{"source":"1230","target":"533","id":"3585"},{"source":"110","target":"111","id":"111"},{"source":"405","target":"48","id":"2932"},{"source":"882","target":"101","id":"2887"},{"source":"92","target":"64","id":"85"},{"source":"614","target":"324","id":"2816"},{"source":"186","target":"192","id":"212"},{"source":"113","target":"374","id":"1098"},{"source":"1104","target":"286","id":"2972"},{"source":"134","target":"82","id":"156"},{"source":"172","target":"441","id":"5737"},{"source":"1093","target":"312","id":"2936"},{"source":"137","target":"861","id":"6151"},{"source":"1376","target":"291","id":"4276"},{"source":"1441","target":"132","id":"4711"},{"source":"1180","target":"405","id":"3316"},{"source":"537","target":"543","id":"3330"},{"source":"787","target":"321","id":"6465"},{"source":"947","target":"26","id":"2401"},{"source":"987","target":"896","id":"3054"},{"source":"1269","target":"408","id":"3746"},{"source":"1276","target":"533","id":"3767"},{"source":"84","target":"53","id":"1300"},{"source":"375","target":"374","id":"601"},{"source":"113","target":"372","id":"1096"},{"source":"264","target":"265","id":"1571"},{"source":"66","target":"498","id":"2598"},{"source":"232","target":"353","id":"4372"},{"source":"856","target":"219","id":"1975"},{"source":"805","target":"344","id":"1772"},{"source":"481","target":"166","id":"798"},{"source":"582","target":"897","id":"4714"},{"source":"675","target":"69","id":"6632"},{"source":"964","target":"882","id":"2439"},{"source":"352","target":"128","id":"534"},{"source":"951","target":"53","id":"2406"},{"source":"1210","target":"1079","id":"6448"},{"source":"853","target":"292","id":"1968"},{"source":"1144","target":"318","id":"3102"},{"source":"1343","target":"505","id":"4110"},{"source":"1560","target":"636","id":"5480"},{"source":"1552","target":"970","id":"5396"},{"source":"977","target":"279","id":"2497"},{"source":"567","target":"424","id":"2723"},{"source":"161","target":"642","id":"5312"},{"source":"670","target":"591","id":"1345"},{"source":"558","target":"556","id":"1012"},{"source":"1675","target":"512","id":"6326"},{"source":"1194","target":"339","id":"3413"},{"source":"1554","target":"132","id":"5423"},{"source":"1451","target":"79","id":"5108"},{"source":"311","target":"296","id":"467"},{"source":"223","target":"79","id":"251"},{"source":"1144","target":"79","id":"3104"},{"source":"800","target":"581","id":"2031"},{"source":"970","target":"217","id":"3095"},{"source":"1109","target":"79","id":"3002"},{"source":"713","target":"712","id":"6644"},{"source":"660","target":"1303","id":"4039"},{"source":"975","target":"696","id":"2486"},{"source":"103","target":"82","id":"267"},{"source":"108","target":"68","id":"5485"},{"source":"1523","target":"96","id":"5253"},{"source":"1664","target":"471","id":"6245"},{"source":"1022","target":"109","id":"3362"},{"source":"1456","target":"494","id":"4776"},{"source":"498","target":"858","id":"1989"},{"source":"247","target":"215","id":"4605"},{"source":"689","target":"82","id":"6111"},{"source":"305","target":"219","id":"395"},{"source":"1315","target":"292","id":"4482"},{"source":"1125","target":"537","id":"4521"},{"source":"1606","target":"1279","id":"5867"},{"source":"1237","target":"1241","id":"3605"},{"source":"52","target":"67","id":"5770"},{"source":"1420","target":"48","id":"4561"},{"source":"1602","target":"1603","id":"5847"},{"source":"1358","target":"428","id":"4287"},{"source":"1272","target":"1181","id":"3760"},{"source":"984","target":"82","id":"2520"},{"source":"1292","target":"1581","id":"5653"},{"source":"424","target":"567","id":"4944"},{"source":"1543","target":"708","id":"5337"},{"source":"102","target":"104","id":"99"},{"source":"1581","target":"585","id":"5662"},{"source":"1498","target":"655","id":"5084"},{"source":"1397","target":"668","id":"4408"},{"source":"553","target":"460","id":"985"},{"source":"880","target":"68","id":"2079"},{"source":"1507","target":"212","id":"5150"},{"source":"224","target":"445","id":"2826"},{"source":"609","target":"119","id":"3065"},{"source":"1112","target":"136","id":"3013"},{"source":"352","target":"1","id":"540"},{"source":"830","target":"76","id":"1875"},{"source":"1582","target":"1581","id":"5647"},{"source":"622","target":"621","id":"4459"},{"source":"607","target":"598","id":"1484"},{"source":"501","target":"49","id":"832"},{"source":"461","target":"68","id":"2616"},{"source":"1054","target":"718","id":"2774"},{"source":"587","target":"374","id":"1101"},{"source":"904","target":"569","id":"2204"},{"source":"48","target":"61","id":"4636"},{"source":"555","target":"554","id":"3188"},{"source":"1568","target":"570","id":"5509"},{"source":"1678","target":"79","id":"6372"},{"source":"23","target":"26","id":"5804"},{"source":"1126","target":"82","id":"4812"},{"source":"1597","target":"1458","id":"5785"},{"source":"179","target":"300","id":"3397"},{"source":"554","target":"348","id":"2051"},{"source":"452","target":"79","id":"2282"},{"source":"171","target":"65","id":"5257"},{"source":"1513","target":"1165","id":"5217"},{"source":"519","target":"578","id":"1072"},{"source":"394","target":"167","id":"4929"},{"source":"612","target":"292","id":"1188"},{"source":"1387","target":"1385","id":"4352"},{"source":"1543","target":"453","id":"5335"},{"source":"1573","target":"61","id":"5549"},{"source":"324","target":"150","id":"2818"},{"source":"730","target":"49","id":"1521"},{"source":"327","target":"79","id":"460"},{"source":"1406","target":"181","id":"4473"},{"source":"1606","target":"1607","id":"5862"},{"source":"638","target":"626","id":"3100"},{"source":"1013","target":"1014","id":"3026"},{"source":"539","target":"540","id":"928"},{"source":"78","target":"80","id":"73"},{"source":"1696","target":"1057","id":"6428"},{"source":"1625","target":"324","id":"6005"},{"source":"1341","target":"223","id":"4092"},{"source":"231","target":"233","id":"262"},{"source":"1039","target":"1040","id":"2699"},{"source":"1211","target":"82","id":"3477"},{"source":"195","target":"429","id":"5391"},{"source":"1610","target":"1","id":"5886"},{"source":"818","target":"221","id":"1832"},{"source":"740","target":"174","id":"1536"},{"source":"22","target":"27","id":"27"},{"source":"771","target":"708","id":"6414"},{"source":"747","target":"748","id":"3781"},{"source":"438","target":"403","id":"1568"},{"source":"284","target":"323","id":"6355"},{"source":"207","target":"37","id":"2694"},{"source":"382","target":"42","id":"627"},{"source":"1499","target":"657","id":"5094"},{"source":"725","target":"216","id":"1501"},{"source":"42","target":"279","id":"341"},{"source":"408","target":"53","id":"878"},{"source":"1226","target":"1144","id":"3572"},{"source":"693","target":"258","id":"1398"},{"source":"1490","target":"607","id":"5037"},{"source":"1387","target":"150","id":"4351"},{"source":"1073","target":"1074","id":"2840"},{"source":"1294","target":"48","id":"3846"},{"source":"1044","target":"171","id":"2727"},{"source":"1519","target":"53","id":"5242"},{"source":"628","target":"463","id":"4152"},{"source":"295","target":"294","id":"3180"},{"source":"1313","target":"296","id":"3956"},{"source":"572","target":"135","id":"2668"},{"source":"1407","target":"79","id":"4488"},{"source":"152","target":"153","id":"171"},{"source":"39","target":"34","id":"4303"},{"source":"298","target":"185","id":"382"},{"source":"152","target":"155","id":"173"},{"source":"411","target":"166","id":"1780"},{"source":"1444","target":"351","id":"4726"},{"source":"1184","target":"1183","id":"3352"},{"source":"1383","target":"312","id":"4315"},{"source":"1626","target":"1255","id":"6012"},{"source":"1194","target":"731","id":"3414"},{"source":"410","target":"412","id":"675"},{"source":"1674","target":"50","id":"6315"},{"source":"194","target":"270","id":"4480"},{"source":"305","target":"306","id":"396"},{"source":"1173","target":"335","id":"3277"},{"source":"236","target":"403","id":"1232"},{"source":"741","target":"370","id":"1546"},{"source":"955","target":"502","id":"2419"},{"source":"1684","target":"1142","id":"6386"},{"source":"1660","target":"960","id":"6223"},{"source":"1357","target":"899","id":"5316"},{"source":"762","target":"765","id":"1622"},{"source":"858","target":"581","id":"5062"},{"source":"1010","target":"1","id":"2580"},{"source":"1485","target":"1","id":"5005"},{"source":"68","target":"106","id":"104"},{"source":"1421","target":"46","id":"4573"},{"source":"1182","target":"391","id":"3340"},{"source":"1242","target":"504","id":"3610"},{"source":"1047","target":"1036","id":"4333"},{"source":"1499","target":"515","id":"5089"},{"source":"563","target":"566","id":"1029"},{"source":"93","target":"104","id":"2160"},{"source":"1715","target":"415","id":"6612"},{"source":"1618","target":"765","id":"5952"},{"source":"416","target":"420","id":"3664"},{"source":"1499","target":"280","id":"5088"},{"source":"475","target":"313","id":"794"},{"source":"1294","target":"412","id":"3850"},{"source":"1336","target":"48","id":"4065"},{"source":"480","target":"170","id":"797"},{"source":"1052","target":"207","id":"2767"},{"source":"272","target":"429","id":"4683"},{"source":"815","target":"598","id":"1822"},{"source":"1279","target":"1248","id":"5630"},{"source":"294","target":"219","id":"900"},{"source":"1481","target":"1196","id":"4984"},{"source":"1137","target":"1138","id":"5256"},{"source":"1221","target":"181","id":"3530"},{"source":"303","target":"219","id":"390"},{"source":"1519","target":"484","id":"5238"},{"source":"197","target":"200","id":"229"},{"source":"1315","target":"294","id":"4484"},{"source":"71","target":"72","id":"3672"},{"source":"1139","target":"76","id":"3086"},{"source":"1715","target":"1279","id":"6614"},{"source":"795","target":"234","id":"1743"},{"source":"604","target":"82","id":"1153"},{"source":"243","target":"248","id":"283"},{"source":"413","target":"415","id":"681"},{"source":"181","target":"185","id":"3526"},{"source":"704","target":"541","id":"6530"},{"source":"461","target":"50","id":"2623"},{"source":"968","target":"272","id":"2459"},{"source":"1007","target":"1008","id":"2577"},{"source":"603","target":"200","id":"1426"},{"source":"71","target":"561","id":"3673"},{"source":"771","target":"768","id":"6412"},{"source":"416","target":"185","id":"3667"},{"source":"287","target":"119","id":"4882"},{"source":"64","target":"105","id":"1829"},{"source":"1466","target":"504","id":"4837"},{"source":"1647","target":"128","id":"6134"},{"source":"1367","target":"1328","id":"4829"},{"source":"1571","target":"723","id":"5535"},{"source":"666","target":"1003","id":"3465"},{"source":"1593","target":"175","id":"5756"},{"source":"563","target":"565","id":"1028"},{"source":"1470","target":"61","id":"4897"},{"source":"735","target":"154","id":"1530"},{"source":"375","target":"119","id":"600"},{"source":"199","target":"402","id":"3318"},{"source":"345","target":"348","id":"527"},{"source":"1362","target":"460","id":"4221"},{"source":"1213","target":"761","id":"5343"},{"source":"1246","target":"98","id":"6103"},{"source":"672","target":"93","id":"5406"},{"source":"1101","target":"79","id":"2961"},{"source":"1667","target":"1","id":"6275"},{"source":"493","target":"495","id":"1850"},{"source":"1176","target":"49","id":"3295"},{"source":"176","target":"1","id":"200"},{"source":"1457","target":"409","id":"4788"},{"source":"882","target":"708","id":"2886"},{"source":"454","target":"456","id":"754"},{"source":"95","target":"96","id":"102"},{"source":"850","target":"99","id":"1951"},{"source":"279","target":"280","id":"502"},{"source":"977","target":"937","id":"2501"},{"source":"1065","target":"479","id":"2800"},{"source":"439","target":"440","id":"717"},{"source":"195","target":"448","id":"5393"},{"source":"238","target":"261","id":"5968"},{"source":"1119","target":"48","id":"6256"},{"source":"90","target":"91","id":"82"},{"source":"382","target":"166","id":"626"},{"source":"1016","target":"45","id":"2593"},{"source":"1075","target":"211","id":"3460"},{"source":"1130","target":"652","id":"5936"},{"source":"1601","target":"439","id":"5800"},{"source":"703","target":"701","id":"3891"},{"source":"426","target":"114","id":"1032"},{"source":"365","target":"120","id":"1341"},{"source":"1372","target":"489","id":"4260"},{"source":"765","target":"388","id":"4822"},{"source":"892","target":"181","id":"5143"},{"source":"1098","target":"626","id":"2945"},{"source":"1380","target":"1358","id":"4290"},{"source":"525","target":"323","id":"932"},{"source":"1404","target":"209","id":"4540"},{"source":"1489","target":"206","id":"5022"},{"source":"1618","target":"533","id":"5953"},{"source":"734","target":"733","id":"1528"},{"source":"176","target":"179","id":"199"},{"source":"42","target":"49","id":"347"},{"source":"1537","target":"883","id":"5297"},{"source":"1374","target":"489","id":"4266"},{"source":"958","target":"960","id":"2812"},{"source":"1545","target":"1547","id":"5352"},{"source":"1510","target":"279","id":"5206"},{"source":"62","target":"552","id":"973"},{"source":"1675","target":"50","id":"6331"},{"source":"1607","target":"1279","id":"5904"},{"source":"727","target":"119","id":"1510"},{"source":"765","target":"82","id":"4826"},{"source":"93","target":"67","id":"2161"},{"source":"1317","target":"1316","id":"6498"},{"source":"835","target":"403","id":"5064"},{"source":"279","target":"48","id":"499"},{"source":"887","target":"608","id":"2105"},{"source":"1411","target":"536","id":"4512"},{"source":"901","target":"93","id":"2168"},{"source":"1574","target":"461","id":"5562"},{"source":"899","target":"367","id":"6575"},{"source":"835","target":"438","id":"5065"},{"source":"654","target":"567","id":"3419"},{"source":"308","target":"360","id":"569"},{"source":"1115","target":"1130","id":"3063"},{"source":"117","target":"50","id":"126"},{"source":"1018","target":"146","id":"4383"},{"source":"548","target":"177","id":"960"},{"source":"282","target":"525","id":"3285"},{"source":"833","target":"50","id":"1893"},{"source":"996","target":"993","id":"2542"},{"source":"158","target":"159","id":"180"},{"source":"1507","target":"1508","id":"5149"},{"source":"1296","target":"607","id":"3860"},{"source":"1576","target":"201","id":"5613"},{"source":"1339","target":"502","id":"4083"},{"source":"108","target":"61","id":"5486"},{"source":"1556","target":"1","id":"5431"},{"source":"281","target":"1136","id":"3082"},{"source":"1720","target":"146","id":"6667"},{"source":"578","target":"576","id":"5681"},{"source":"1472","target":"779","id":"4922"},{"source":"859","target":"862","id":"1999"},{"source":"1631","target":"1034","id":"6037"},{"source":"276","target":"275","id":"6585"},{"source":"1560","target":"1002","id":"5482"},{"source":"1426","target":"295","id":"4594"},{"source":"771","target":"109","id":"6411"},{"source":"118","target":"104","id":"1291"},{"source":"289","target":"65","id":"3720"},{"source":"444","target":"82","id":"2554"},{"source":"1263","target":"262","id":"3707"},{"source":"917","target":"453","id":"2255"},{"source":"1244","target":"801","id":"3622"},{"source":"24","target":"26","id":"5816"},{"source":"1198","target":"403","id":"3434"},{"source":"1540","target":"364","id":"5301"},{"source":"1498","target":"437","id":"5085"},{"source":"1645","target":"1177","id":"6132"},{"source":"1339","target":"1340","id":"4078"},{"source":"49","target":"48","id":"5184"},{"source":"809","target":"48","id":"1801"},{"source":"286","target":"238","id":"3717"},{"source":"501","target":"48","id":"839"},{"source":"255","target":"254","id":"3864"},{"source":"172","target":"579","id":"5739"},{"source":"1365","target":"759","id":"4247"},{"source":"1559","target":"125","id":"5466"},{"source":"237","target":"76","id":"271"},{"source":"1101","target":"1093","id":"2962"},{"source":"756","target":"51","id":"1604"},{"source":"1440","target":"1","id":"6178"},{"source":"125","target":"124","id":"134"},{"source":"427","target":"569","id":"1036"},{"source":"1469","target":"1218","id":"4868"},{"source":"340","target":"163","id":"4341"},{"source":"1184","target":"1112","id":"3350"},{"source":"1423","target":"1259","id":"4590"},{"source":"120","target":"930","id":"4023"},{"source":"360","target":"79","id":"571"},{"source":"644","target":"592","id":"1553"},{"source":"519","target":"114","id":"1068"},{"source":"845","target":"846","id":"1933"},{"source":"527","target":"528","id":"3548"},{"source":"507","target":"160","id":"848"},{"source":"1022","target":"50","id":"3361"},{"source":"1173","target":"53","id":"3278"},{"source":"479","target":"1062","id":"4293"},{"source":"1064","target":"1063","id":"2796"},{"source":"1162","target":"668","id":"3220"},{"source":"497","target":"53","id":"2627"},{"source":"1136","target":"1141","id":"4391"},{"source":"1064","target":"1062","id":"2795"},{"source":"1700","target":"324","id":"6463"},{"source":"1661","target":"1352","id":"6232"},{"source":"836","target":"837","id":"1901"},{"source":"2","target":"1","id":"2"},{"source":"1013","target":"79","id":"3025"},{"source":"803","target":"79","id":"3758"},{"source":"1362","target":"50","id":"4227"},{"source":"626","target":"300","id":"3227"},{"source":"951","target":"408","id":"2405"},{"source":"728","target":"597","id":"5451"},{"source":"605","target":"606","id":"2900"},{"source":"1184","target":"1155","id":"3351"},{"source":"927","target":"79","id":"2295"},{"source":"929","target":"930","id":"2299"},{"source":"173","target":"175","id":"195"},{"source":"256","target":"183","id":"5163"},{"source":"1292","target":"334","id":"5656"},{"source":"506","target":"48","id":"844"},{"source":"639","target":"642","id":"1264"},{"source":"202","target":"264","id":"6637"},{"source":"1490","target":"759","id":"5033"},{"source":"1607","target":"421","id":"5902"},{"source":"1543","target":"250","id":"5338"},{"source":"929","target":"109","id":"2308"},{"source":"1223","target":"619","id":"3562"},{"source":"1349","target":"906","id":"4143"},{"source":"784","target":"68","id":"1703"},{"source":"1053","target":"204","id":"4600"},{"source":"753","target":"312","id":"5131"},{"source":"697","target":"915","id":"5685"},{"source":"1639","target":"287","id":"6093"},{"source":"711","target":"502","id":"1438"},{"source":"955","target":"956","id":"2424"},{"source":"1247","target":"618","id":"3629"},{"source":"119","target":"511","id":"3174"},{"source":"753","target":"45","id":"5130"},{"source":"1575","target":"259","id":"5602"},{"source":"895","target":"567","id":"2133"},{"source":"799","target":"631","id":"1756"},{"source":"53","target":"93","id":"1115"},{"source":"1312","target":"1034","id":"3933"},{"source":"1263","target":"348","id":"3710"},{"source":"492","target":"495","id":"819"},{"source":"522","target":"471","id":"899"},{"source":"878","target":"781","id":"2073"},{"source":"1491","target":"79","id":"5047"},{"source":"408","target":"51","id":"876"},{"source":"1525","target":"1528","id":"5265"},{"source":"746","target":"281","id":"4857"},{"source":"665","target":"408","id":"1326"},{"source":"25","target":"27","id":"1013"},{"source":"552","target":"65","id":"4893"},{"source":"785","target":"323","id":"1715"},{"source":"657","target":"437","id":"5996"},{"source":"649","target":"79","id":"1281"},{"source":"739","target":"313","id":"1534"},{"source":"1191","target":"65","id":"3404"},{"source":"821","target":"53","id":"1838"},{"source":"1242","target":"1","id":"3608"},{"source":"1601","target":"697","id":"5799"},{"source":"367","target":"307","id":"4318"},{"source":"625","target":"628","id":"1206"},{"source":"493","target":"82","id":"1849"},{"source":"1095","target":"312","id":"2938"},{"source":"1639","target":"1640","id":"6097"},{"source":"1407","target":"182","id":"4489"},{"source":"383","target":"387","id":"631"},{"source":"875","target":"576","id":"2064"},{"source":"1515","target":"1518","id":"6566"},{"source":"518","target":"436","id":"894"},{"source":"405","target":"335","id":"2928"},{"source":"880","target":"167","id":"2082"},{"source":"587","target":"49","id":"1102"},{"source":"319","target":"185","id":"3898"},{"source":"1326","target":"1327","id":"4024"},{"source":"765","target":"896","id":"4824"},{"source":"1026","target":"182","id":"2650"},{"source":"34","target":"36","id":"34"},{"source":"1261","target":"401","id":"3691"},{"source":"975","target":"68","id":"2490"},{"source":"694","target":"484","id":"1409"},{"source":"1571","target":"311","id":"5533"},{"source":"334","target":"66","id":"4740"},{"source":"179","target":"178","id":"3395"},{"source":"570","target":"76","id":"1037"},{"source":"505","target":"495","id":"4003"},{"source":"1076","target":"1079","id":"3700"},{"source":"914","target":"65","id":"2246"},{"source":"946","target":"948","id":"2381"},{"source":"793","target":"863","id":"2965"},{"source":"519","target":"579","id":"1073"},{"source":"107","target":"50","id":"2334"},{"source":"1224","target":"33","id":"3566"},{"source":"62","target":"64","id":"979"},{"source":"1510","target":"590","id":"5203"},{"source":"1577","target":"1373","id":"5614"},{"source":"1650","target":"406","id":"6156"},{"source":"684","target":"686","id":"1377"},{"source":"1567","target":"174","id":"5506"},{"source":"462","target":"464","id":"774"},{"source":"441","target":"439","id":"4375"},{"source":"1279","target":"618","id":"5627"},{"source":"435","target":"816","id":"3150"},{"source":"1248","target":"1282","id":"5898"},{"source":"1176","target":"280","id":"3294"},{"source":"1102","target":"312","id":"3502"},{"source":"479","target":"1","id":"4295"},{"source":"1653","target":"1430","id":"6190"},{"source":"523","target":"526","id":"911"},{"source":"621","target":"622","id":"3959"},{"source":"445","target":"911","id":"2823"},{"source":"914","target":"53","id":"2244"},{"source":"672","target":"105","id":"5399"},{"source":"472","target":"361","id":"788"},{"source":"1453","target":"1454","id":"4762"},{"source":"787","target":"1037","id":"6471"},{"source":"1519","target":"339","id":"5236"},{"source":"1341","target":"502","id":"4090"},{"source":"379","target":"668","id":"4128"},{"source":"1701","target":"408","id":"6478"},{"source":"561","target":"73","id":"1024"},{"source":"61","target":"53","id":"863"},{"source":"1580","target":"1582","id":"5650"},{"source":"814","target":"95","id":"1814"},{"source":"348","target":"661","id":"4624"},{"source":"895","target":"118","id":"2137"},{"source":"365","target":"624","id":"1340"},{"source":"835","target":"202","id":"5069"},{"source":"1573","target":"65","id":"5551"},{"source":"714","target":"129","id":"6650"},{"source":"417","target":"314","id":"4463"},{"source":"79","target":"299","id":"1254"},{"source":"1505","target":"1506","id":"5111"},{"source":"1385","target":"1","id":"4346"},{"source":"701","target":"704","id":"1422"},{"source":"797","target":"53","id":"1747"},{"source":"1677","target":"47","id":"6363"},{"source":"430","target":"463","id":"4831"},{"source":"1591","target":"904","id":"5728"},{"source":"1684","target":"981","id":"6383"},{"source":"458","target":"167","id":"5370"},{"source":"1325","target":"498","id":"4017"},{"source":"1459","target":"280","id":"4802"},{"source":"430","target":"908","id":"4832"},{"source":"633","target":"511","id":"1230"},{"source":"1431","target":"262","id":"4673"},{"source":"711","target":"82","id":"1439"},{"source":"604","target":"606","id":"1158"},{"source":"1702","target":"313","id":"6491"},{"source":"1658","target":"377","id":"6216"},{"source":"664","target":"888","id":"3705"},{"source":"1282","target":"1200","id":"5893"},{"source":"610","target":"79","id":"1185"},{"source":"476","target":"477","id":"792"},{"source":"1375","target":"21","id":"4271"},{"source":"1343","target":"1000","id":"4108"},{"source":"1166","target":"351","id":"3238"},{"source":"368","target":"300","id":"3007"},{"source":"1457","target":"280","id":"4782"},{"source":"287","target":"552","id":"4884"},{"source":"911","target":"307","id":"2239"},{"source":"1012","target":"111","id":"5573"},{"source":"1406","target":"256","id":"4475"},{"source":"1577","target":"710","id":"5618"},{"source":"1107","target":"108","id":"2990"},{"source":"1443","target":"50","id":"4718"},{"source":"1326","target":"1328","id":"4026"},{"source":"68","target":"107","id":"105"},{"source":"166","target":"20","id":"259"},{"source":"809","target":"810","id":"1796"},{"source":"1455","target":"76","id":"4768"},{"source":"1140","target":"76","id":"3087"},{"source":"1567","target":"159","id":"5505"},{"source":"214","target":"82","id":"244"},{"source":"1077","target":"1003","id":"3447"},{"source":"1125","target":"543","id":"4517"},{"source":"836","target":"838","id":"1902"},{"source":"965","target":"96","id":"2442"},{"source":"1312","target":"323","id":"3937"},{"source":"502","target":"555","id":"5076"},{"source":"891","target":"892","id":"2113"},{"source":"1165","target":"668","id":"5228"},{"source":"92","target":"50","id":"89"},{"source":"907","target":"908","id":"2222"},{"source":"330","target":"185","id":"487"},{"source":"713","target":"85","id":"6643"},{"source":"506","target":"53","id":"841"},{"source":"940","target":"941","id":"2356"},{"source":"1514","target":"1516","id":"5223"},{"source":"413","target":"414","id":"680"},{"source":"1307","target":"166","id":"3917"},{"source":"483","target":"482","id":"3924"},{"source":"895","target":"93","id":"2139"},{"source":"1098","target":"312","id":"2946"},{"source":"370","target":"634","id":"4581"},{"source":"392","target":"391","id":"4274"},{"source":"817","target":"498","id":"2004"},{"source":"52","target":"65","id":"5768"},{"source":"1514","target":"164","id":"5226"},{"source":"977","target":"570","id":"2500"},{"source":"852","target":"312","id":"3251"},{"source":"1084","target":"53","id":"2868"},{"source":"1276","target":"747","id":"3774"},{"source":"1401","target":"281","id":"4419"},{"source":"1161","target":"444","id":"3197"},{"source":"94","target":"97","id":"92"},{"source":"62","target":"63","id":"977"},{"source":"1081","target":"476","id":"2853"},{"source":"1363","target":"334","id":"4231"},{"source":"169","target":"170","id":"190"},{"source":"1506","target":"182","id":"5836"},{"source":"162","target":"164","id":"184"},{"source":"1179","target":"42","id":"3303"},{"source":"1487","target":"626","id":"5017"},{"source":"294","target":"376","id":"901"},{"source":"532","target":"335","id":"922"},{"source":"1599","target":"888","id":"5793"},{"source":"923","target":"924","id":"2276"},{"source":"598","target":"114","id":"1985"},{"source":"1311","target":"322","id":"3930"},{"source":"1373","target":"167","id":"6365"},{"source":"1346","target":"1160","id":"4125"},{"source":"535","target":"335","id":"2464"},{"source":"911","target":"913","id":"2242"},{"source":"140","target":"136","id":"6152"},{"source":"658","target":"661","id":"1321"},{"source":"254","target":"183","id":"295"},{"source":"688","target":"99","id":"1654"},{"source":"1157","target":"1","id":"3164"},{"source":"1616","target":"912","id":"5943"},{"source":"1187","target":"550","id":"3377"},{"source":"567","target":"1042","id":"2719"},{"source":"1173","target":"49","id":"3283"},{"source":"821","target":"498","id":"1839"},{"source":"1008","target":"121","id":"5691"},{"source":"453","target":"250","id":"1619"},{"source":"904","target":"65","id":"2209"},{"source":"1383","target":"852","id":"4316"},{"source":"190","target":"188","id":"2527"},{"source":"792","target":"68","id":"1724"},{"source":"619","target":"523","id":"6033"},{"source":"780","target":"740","id":"1692"},{"source":"861","target":"137","id":"6153"},{"source":"895","target":"68","id":"2135"},{"source":"769","target":"707","id":"1632"},{"source":"653","target":"911","id":"2864"},{"source":"1486","target":"68","id":"5007"},{"source":"180","target":"182","id":"203"},{"source":"406","target":"334","id":"4737"},{"source":"127","target":"111","id":"2353"},{"source":"1405","target":"819","id":"4451"},{"source":"452","target":"65","id":"2277"},{"source":"964","target":"101","id":"2438"},{"source":"1483","target":"1484","id":"4988"},{"source":"825","target":"493","id":"5854"},{"source":"712","target":"128","id":"2034"},{"source":"1221","target":"302","id":"3527"},{"source":"375","target":"373","id":"597"},{"source":"481","target":"483","id":"802"},{"source":"1161","target":"502","id":"3200"},{"source":"713","target":"96","id":"6642"},{"source":"263","target":"267","id":"310"},{"source":"799","target":"397","id":"1759"},{"source":"1559","target":"1","id":"5467"},{"source":"1304","target":"328","id":"3905"},{"source":"514","target":"287","id":"883"},{"source":"1421","target":"185","id":"4574"},{"source":"1466","target":"1266","id":"4840"},{"source":"1467","target":"502","id":"4853"},{"source":"1365","target":"27","id":"4243"},{"source":"212","target":"885","id":"3999"},{"source":"1477","target":"437","id":"4932"},{"source":"170","target":"313","id":"4793"},{"source":"1337","target":"806","id":"4075"},{"source":"987","target":"1125","id":"3052"},{"source":"577","target":"576","id":"4399"},{"source":"270","target":"36","id":"409"},{"source":"1404","target":"450","id":"4537"},{"source":"1510","target":"589","id":"5200"},{"source":"208","target":"206","id":"5845"},{"source":"190","target":"192","id":"2525"},{"source":"1466","target":"281","id":"4839"},{"source":"1008","target":"437","id":"5694"},{"source":"410","target":"50","id":"679"},{"source":"63","target":"511","id":"999"},{"source":"1588","target":"96","id":"5698"},{"source":"306","target":"79","id":"455"},{"source":"270","target":"313","id":"411"},{"source":"1631","target":"208","id":"6040"},{"source":"529","target":"530","id":"915"},{"source":"1071","target":"1072","id":"2833"},{"source":"1155","target":"440","id":"3152"},{"source":"552","target":"512","id":"4892"},{"source":"1108","target":"300","id":"2996"},{"source":"481","target":"279","id":"799"},{"source":"881","target":"65","id":"2091"},{"source":"903","target":"109","id":"2175"},{"source":"631","target":"280","id":"1215"},{"source":"681","target":"683","id":"1369"},{"source":"1007","target":"502","id":"2575"},{"source":"600","target":"497","id":"1148"},{"source":"44","target":"45","id":"41"},{"source":"1427","target":"82","id":"4612"},{"source":"1560","target":"609","id":"5478"},{"source":"726","target":"426","id":"2194"},{"source":"186","target":"191","id":"211"},{"source":"963","target":"571","id":"2433"},{"source":"1332","target":"128","id":"4045"},{"source":"30","target":"23","id":"5043"},{"source":"1618","target":"537","id":"5950"},{"source":"103","target":"53","id":"263"},{"source":"178","target":"79","id":"1242"},{"source":"132","target":"53","id":"5345"},{"source":"828","target":"109","id":"1863"},{"source":"726","target":"104","id":"2192"},{"source":"577","target":"578","id":"4395"},{"source":"706","target":"82","id":"1432"},{"source":"217","target":"33","id":"3120"},{"source":"744","target":"120","id":"1563"},{"source":"519","target":"576","id":"1069"},{"source":"116","target":"115","id":"6513"},{"source":"53","target":"104","id":"1116"},{"source":"1281","target":"1283","id":"3811"},{"source":"1292","target":"585","id":"5657"},{"source":"1557","target":"183","id":"5828"},{"source":"34","target":"39","id":"37"},{"source":"356","target":"216","id":"849"},{"source":"1363","target":"51","id":"4233"},{"source":"893","target":"50","id":"2560"},{"source":"287","target":"460","id":"4880"},{"source":"35","target":"39","id":"416"},{"source":"890","target":"1","id":"2110"},{"source":"573","target":"48","id":"1049"},{"source":"34","target":"40","id":"38"},{"source":"1670","target":"69","id":"6286"},{"source":"377","target":"294","id":"2150"},{"source":"214","target":"216","id":"243"},{"source":"1218","target":"721","id":"3509"},{"source":"103","target":"97","id":"266"},{"source":"882","target":"96","id":"2885"},{"source":"1105","target":"511","id":"2982"},{"source":"1616","target":"911","id":"5942"},{"source":"286","target":"159","id":"3715"},{"source":"1269","target":"1222","id":"3748"},{"source":"1051","target":"1042","id":"2761"},{"source":"1237","target":"1240","id":"3604"},{"source":"1647","target":"82","id":"6137"},{"source":"181","target":"184","id":"3523"},{"source":"1674","target":"363","id":"6317"},{"source":"408","target":"66","id":"879"},{"source":"178","target":"177","id":"1241"},{"source":"328","target":"311","id":"473"},{"source":"383","target":"386","id":"629"},{"source":"653","target":"652","id":"2863"},{"source":"832","target":"571","id":"1885"},{"source":"953","target":"954","id":"2414"},{"source":"1036","target":"207","id":"3853"},{"source":"1260","target":"377","id":"3676"},{"source":"1644","target":"839","id":"6127"},{"source":"274","target":"275","id":"321"},{"source":"1015","target":"166","id":"3678"},{"source":"974","target":"313","id":"4337"},{"source":"1620","target":"1493","id":"5962"},{"source":"426","target":"567","id":"1033"},{"source":"946","target":"96","id":"2378"},{"source":"423","target":"656","id":"3140"},{"source":"1626","target":"1243","id":"6011"},{"source":"931","target":"480","id":"2309"},{"source":"477","target":"476","id":"3515"},{"source":"339","target":"280","id":"4208"},{"source":"541","target":"701","id":"2741"},{"source":"326","target":"298","id":"463"},{"source":"564","target":"446","id":"3224"},{"source":"1421","target":"312","id":"4572"},{"source":"809","target":"42","id":"1797"},{"source":"560","target":"104","id":"1017"},{"source":"1353","target":"1124","id":"4171"},{"source":"877","target":"111","id":"2072"},{"source":"251","target":"250","id":"3976"},{"source":"1170","target":"1171","id":"3272"},{"source":"1197","target":"638","id":"3426"},{"source":"1573","target":"50","id":"5546"},{"source":"694","target":"128","id":"1400"},{"source":"17","target":"18","id":"20"},{"source":"1545","target":"159","id":"5354"},{"source":"551","target":"497","id":"970"},{"source":"1345","target":"587","id":"4116"},{"source":"1134","target":"497","id":"3073"},{"source":"1276","target":"600","id":"3772"},{"source":"133","target":"134","id":"144"},{"source":"172","target":"82","id":"5740"},{"source":"1303","target":"660","id":"4035"},{"source":"191","target":"188","id":"5884"},{"source":"409","target":"335","id":"4648"},{"source":"1191","target":"114","id":"3406"},{"source":"983","target":"444","id":"4695"},{"source":"460","target":"607","id":"1163"},{"source":"183","target":"182","id":"5119"},{"source":"722","target":"82","id":"1474"},{"source":"921","target":"153","id":"2270"},{"source":"382","target":"48","id":"623"},{"source":"1622","target":"1106","id":"5975"},{"source":"46","target":"45","id":"4310"},{"source":"1398","target":"1400","id":"4415"},{"source":"1571","target":"45","id":"5536"},{"source":"960","target":"1284","id":"3813"},{"source":"883","target":"498","id":"4187"},{"source":"1435","target":"354","id":"4700"},{"source":"517","target":"1129","id":"3057"},{"source":"249","target":"253","id":"291"},{"source":"789","target":"1119","id":"3030"},{"source":"1554","target":"903","id":"5421"},{"source":"1347","target":"640","id":"4135"},{"source":"421","target":"486","id":"3688"},{"source":"413","target":"296","id":"686"},{"source":"1598","target":"76","id":"5787"},{"source":"1327","target":"65","id":"5871"},{"source":"696","target":"458","id":"1410"},{"source":"1678","target":"315","id":"6373"},{"source":"780","target":"109","id":"1696"},{"source":"781","target":"53","id":"2782"},{"source":"1235","target":"149","id":"3590"},{"source":"404","target":"53","id":"661"},{"source":"1428","target":"810","id":"4618"},{"source":"1260","target":"381","id":"3675"},{"source":"366","target":"728","id":"5460"},{"source":"812","target":"96","id":"5413"},{"source":"1227","target":"974","id":"3578"},{"source":"780","target":"234","id":"1693"},{"source":"553","target":"286","id":"990"},{"source":"760","target":"262","id":"1613"},{"source":"756","target":"279","id":"1600"},{"source":"401","target":"79","id":"651"},{"source":"1615","target":"1607","id":"5926"},{"source":"612","target":"616","id":"1193"},{"source":"40","target":"272","id":"4685"},{"source":"809","target":"382","id":"1799"},{"source":"130","target":"104","id":"142"},{"source":"550","target":"104","id":"966"},{"source":"1446","target":"391","id":"4728"},{"source":"1416","target":"79","id":"4548"},{"source":"826","target":"79","id":"5359"},{"source":"418","target":"961","id":"4563"},{"source":"252","target":"65","id":"762"},{"source":"1464","target":"935","id":"4828"},{"source":"388","target":"20","id":"2391"},{"source":"1669","target":"1","id":"6280"},{"source":"65","target":"68","id":"2128"},{"source":"706","target":"708","id":"1430"},{"source":"108","target":"53","id":"5487"},{"source":"4","target":"1","id":"4"},{"source":"744","target":"53","id":"1558"},{"source":"1607","target":"1249","id":"5907"},{"source":"281","target":"111","id":"3081"},{"source":"955","target":"324","id":"2417"},{"source":"936","target":"167","id":"2330"},{"source":"672","target":"50","id":"5400"},{"source":"265","target":"202","id":"1896"},{"source":"37","target":"430","id":"706"},{"source":"1006","target":"233","id":"2571"},{"source":"832","target":"76","id":"1881"},{"source":"1664","target":"1407","id":"6249"},{"source":"538","target":"335","id":"4653"},{"source":"1388","target":"1385","id":"4359"},{"source":"410","target":"42","id":"670"},{"source":"1282","target":"1283","id":"5891"},{"source":"627","target":"73","id":"3854"},{"source":"350","target":"318","id":"529"},{"source":"1611","target":"1613","id":"5919"},{"source":"657","target":"654","id":"5999"},{"source":"1679","target":"556","id":"6376"},{"source":"509","target":"510","id":"858"},{"source":"276","target":"36","id":"6587"},{"source":"1150","target":"101","id":"3137"},{"source":"736","target":"154","id":"6346"},{"source":"438","target":"266","id":"1566"},{"source":"543","target":"535","id":"937"},{"source":"1176","target":"759","id":"3297"},{"source":"799","target":"49","id":"1764"},{"source":"1191","target":"511","id":"3402"},{"source":"1060","target":"1115","id":"3017"},{"source":"1105","target":"68","id":"2977"},{"source":"673","target":"113","id":"1353"},{"source":"1560","target":"433","id":"5483"},{"source":"911","target":"912","id":"2240"},{"source":"991","target":"908","id":"4946"},{"source":"1418","target":"1","id":"4554"},{"source":"267","target":"513","id":"4435"},{"source":"587","target":"47","id":"1106"},{"source":"1363","target":"1364","id":"4235"},{"source":"63","target":"287","id":"997"},{"source":"1697","target":"85","id":"6441"},{"source":"755","target":"300","id":"1593"},{"source":"1183","target":"556","id":"3344"},{"source":"330","target":"332","id":"486"},{"source":"1577","target":"82","id":"5615"},{"source":"1048","target":"91","id":"2749"},{"source":"1575","target":"513","id":"5606"},{"source":"871","target":"53","id":"2044"},{"source":"1082","target":"912","id":"6569"},{"source":"300","target":"463","id":"3009"},{"source":"732","target":"261","id":"5972"},{"source":"1337","target":"1338","id":"4068"},{"source":"788","target":"632","id":"1718"},{"source":"1146","target":"79","id":"3657"},{"source":"1718","target":"1120","id":"6628"},{"source":"901","target":"65","id":"2167"},{"source":"1620","target":"260","id":"5965"},{"source":"342","target":"343","id":"520"},{"source":"1168","target":"852","id":"3259"},{"source":"1048","target":"540","id":"2746"},{"source":"1563","target":"1084","id":"5500"},{"source":"380","target":"87","id":"612"},{"source":"892","target":"312","id":"5142"},{"source":"1351","target":"65","id":"4156"},{"source":"1385","target":"150","id":"4345"},{"source":"1520","target":"213","id":"5245"},{"source":"762","target":"764","id":"1621"},{"source":"1345","target":"254","id":"4121"},{"source":"715","target":"85","id":"1447"},{"source":"158","target":"53","id":"181"},{"source":"526","target":"523","id":"3540"},{"source":"404","target":"406","id":"657"},{"source":"822","target":"53","id":"6260"},{"source":"672","target":"67","id":"5398"},{"source":"799","target":"800","id":"1757"},{"source":"382","target":"280","id":"619"},{"source":"649","target":"549","id":"1282"},{"source":"608","target":"498","id":"1494"},{"source":"743","target":"174","id":"1548"},{"source":"568","target":"569","id":"1643"},{"source":"856","target":"293","id":"1976"},{"source":"649","target":"548","id":"1280"},{"source":"822","target":"1119","id":"6269"},{"source":"913","target":"136","id":"5137"},{"source":"1203","target":"68","id":"3450"},{"source":"1472","target":"109","id":"4917"},{"source":"469","target":"732","id":"3192"},{"source":"116","target":"113","id":"6512"},{"source":"1053","target":"1034","id":"4602"},{"source":"1310","target":"522","id":"3929"},{"source":"876","target":"104","id":"3127"},{"source":"1016","target":"48","id":"2595"},{"source":"1325","target":"61","id":"4014"},{"source":"1365","target":"758","id":"4240"},{"source":"620","target":"170","id":"1198"},{"source":"723","target":"223","id":"1479"},{"source":"1599","target":"662","id":"5790"},{"source":"998","target":"996","id":"2544"},{"source":"248","target":"247","id":"5350"},{"source":"465","target":"463","id":"952"},{"source":"860","target":"116","id":"6119"},{"source":"1716","target":"1121","id":"6616"},{"source":"134","target":"84","id":"152"},{"source":"1590","target":"82","id":"5719"},{"source":"865","target":"262","id":"2294"},{"source":"966","target":"1410","id":"5824"},{"source":"1444","target":"82","id":"4727"},{"source":"1435","target":"424","id":"4704"},{"source":"329","target":"185","id":"3244"},{"source":"1011","target":"66","id":"2585"},{"source":"208","target":"205","id":"5844"},{"source":"332","target":"331","id":"4385"},{"source":"79","target":"177","id":"1253"},{"source":"1187","target":"453","id":"3379"},{"source":"1648","target":"49","id":"6145"},{"source":"574","target":"405","id":"1063"},{"source":"1431","target":"1206","id":"4669"},{"source":"1482","target":"211","id":"4985"},{"source":"1364","target":"1293","id":"6515"},{"source":"1312","target":"787","id":"3938"},{"source":"1576","target":"216","id":"5609"},{"source":"1537","target":"469","id":"5295"},{"source":"396","target":"398","id":"649"},{"source":"762","target":"763","id":"1620"},{"source":"11","target":"1","id":"14"},{"source":"676","target":"673","id":"1357"},{"source":"1562","target":"76","id":"5493"},{"source":"318","target":"351","id":"533"},{"source":"814","target":"96","id":"1815"},{"source":"921","target":"883","id":"2265"},{"source":"202","target":"438","id":"6636"},{"source":"1452","target":"1401","id":"4754"},{"source":"240","target":"241","id":"275"},{"source":"1467","target":"411","id":"4850"},{"source":"990","target":"991","id":"2532"},{"source":"177","target":"463","id":"958"},{"source":"724","target":"211","id":"2832"},{"source":"484","target":"1401","id":"5591"},{"source":"1478","target":"65","id":"4962"},{"source":"336","target":"53","id":"3145"},{"source":"891","target":"184","id":"2111"},{"source":"479","target":"1068","id":"4298"},{"source":"1722","target":"82","id":"6676"},{"source":"886","target":"170","id":"2104"},{"source":"692","target":"1","id":"5720"},{"source":"1211","target":"215","id":"3476"},{"source":"954","target":"262","id":"3695"},{"source":"589","target":"374","id":"1664"},{"source":"369","target":"181","id":"573"},{"source":"593","target":"105","id":"1126"},{"source":"278","target":"238","id":"340"},{"source":"745","target":"111","id":"1578"},{"source":"83","target":"84","id":"76"},{"source":"794","target":"25","id":"1737"},{"source":"1563","target":"513","id":"5502"},{"source":"1151","target":"417","id":"3138"},{"source":"234","target":"85","id":"1927"},{"source":"1456","target":"339","id":"4777"},{"source":"897","target":"64","id":"5462"},{"source":"1629","target":"79","id":"6028"},{"source":"91","target":"541","id":"5415"},{"source":"1616","target":"653","id":"5944"},{"source":"1421","target":"45","id":"4570"},{"source":"1657","target":"455","id":"6207"},{"source":"1601","target":"96","id":"5802"},{"source":"573","target":"49","id":"1050"},{"source":"1654","target":"1124","id":"6193"},{"source":"808","target":"65","id":"1790"},{"source":"1478","target":"120","id":"4963"},{"source":"980","target":"67","id":"2510"},{"source":"1677","target":"513","id":"6359"},{"source":"454","target":"62","id":"749"},{"source":"219","target":"182","id":"450"},{"source":"404","target":"397","id":"655"},{"source":"1280","target":"758","id":"3806"},{"source":"1135","target":"167","id":"3078"},{"source":"537","target":"405","id":"3333"},{"source":"1456","target":"484","id":"4778"},{"source":"1658","target":"376","id":"6215"},{"source":"862","target":"568","id":"2631"},{"source":"829","target":"831","id":"1872"},{"source":"1506","target":"302","id":"5837"},{"source":"849","target":"324","id":"1949"},{"source":"1237","target":"1239","id":"3603"},{"source":"1244","target":"1206","id":"3621"},{"source":"553","target":"53","id":"984"},{"source":"885","target":"1323","id":"4006"},{"source":"339","target":"50","id":"4207"},{"source":"657","target":"567","id":"5997"},{"source":"1477","target":"423","id":"4935"},{"source":"1140","target":"53","id":"3089"},{"source":"1704","target":"1238","id":"6527"},{"source":"1141","target":"1142","id":"3094"},{"source":"374","target":"589","id":"5176"},{"source":"571","target":"159","id":"5523"},{"source":"137","target":"136","id":"6150"},{"source":"850","target":"690","id":"1953"},{"source":"183","target":"302","id":"5120"},{"source":"71","target":"70","id":"3674"},{"source":"854","target":"429","id":"1972"},{"source":"1245","target":"1246","id":"3627"},{"source":"430","target":"79","id":"4830"},{"source":"628","target":"1350","id":"4155"},{"source":"1004","target":"392","id":"2570"},{"source":"1067","target":"1063","id":"2807"},{"source":"191","target":"192","id":"5883"},{"source":"669","target":"155","id":"1337"},{"source":"750","target":"136","id":"1584"},{"source":"1234","target":"277","id":"3589"},{"source":"297","target":"292","id":"4165"},{"source":"595","target":"50","id":"1136"},{"source":"325","target":"181","id":"5139"},{"source":"967","target":"182","id":"2652"},{"source":"1008","target":"1","id":"5695"},{"source":"1709","target":"1","id":"6549"},{"source":"1012","target":"104","id":"5572"},{"source":"1044","target":"424","id":"2726"},{"source":"1130","target":"913","id":"5939"},{"source":"1444","target":"1445","id":"4724"},{"source":"1347","target":"1348","id":"4133"},{"source":"1451","target":"310","id":"5107"},{"source":"435","target":"155","id":"3151"},{"source":"317","target":"296","id":"4542"},{"source":"964","target":"96","id":"2437"},{"source":"327","target":"296","id":"457"},{"source":"593","target":"65","id":"1122"},{"source":"589","target":"47","id":"1661"},{"source":"1341","target":"724","id":"4088"},{"source":"382","target":"381","id":"618"},{"source":"1632","target":"573","id":"6046"},{"source":"1150","target":"104","id":"3136"},{"source":"364","target":"373","id":"580"},{"source":"411","target":"1","id":"1784"},{"source":"1092","target":"224","id":"2917"},{"source":"623","target":"624","id":"1202"},{"source":"363","target":"366","id":"562"},{"source":"1673","target":"239","id":"6307"},{"source":"740","target":"109","id":"1539"},{"source":"1036","target":"209","id":"3852"},{"source":"287","target":"515","id":"4881"},{"source":"262","target":"1493","id":"5980"},{"source":"1269","target":"513","id":"3751"},{"source":"1557","target":"818","id":"5825"},{"source":"376","target":"306","id":"607"},{"source":"590","target":"513","id":"5172"},{"source":"156","target":"152","id":"174"},{"source":"1325","target":"65","id":"4018"},{"source":"626","target":"79","id":"3226"},{"source":"883","target":"1358","id":"4190"},{"source":"1656","target":"872","id":"6195"},{"source":"1174","target":"230","id":"3288"},{"source":"217","target":"128","id":"3118"},{"source":"725","target":"498","id":"1497"},{"source":"1487","target":"1315","id":"5018"},{"source":"639","target":"50","id":"1263"},{"source":"1648","target":"53","id":"6143"},{"source":"1660","target":"958","id":"6221"},{"source":"119","target":"61","id":"3175"},{"source":"201","target":"212","id":"4759"},{"source":"268","target":"272","id":"316"},{"source":"799","target":"801","id":"1760"},{"source":"1285","target":"841","id":"3814"},{"source":"780","target":"68","id":"1697"},{"source":"310","target":"311","id":"403"},{"source":"828","target":"237","id":"1858"},{"source":"1374","target":"519","id":"4264"},{"source":"116","target":"363","id":"6510"},{"source":"1243","target":"79","id":"3612"},{"source":"67","target":"53","id":"2710"},{"source":"203","target":"296","id":"736"},{"source":"1529","target":"1225","id":"5270"},{"source":"743","target":"645","id":"1550"},{"source":"254","target":"1","id":"293"},{"source":"1179","target":"279","id":"3304"},{"source":"391","target":"68","id":"3968"},{"source":"268","target":"269","id":"311"},{"source":"414","target":"421","id":"691"},{"source":"717","target":"714","id":"1460"},{"source":"1385","target":"79","id":"4347"},{"source":"1061","target":"1063","id":"2794"},{"source":"1210","target":"1078","id":"6446"},{"source":"1073","target":"662","id":"2839"},{"source":"330","target":"331","id":"483"},{"source":"1537","target":"156","id":"5292"},{"source":"1015","target":"127","id":"3679"},{"source":"747","target":"335","id":"3778"},{"source":"707","target":"706","id":"1629"},{"source":"974","target":"150","id":"4338"},{"source":"580","target":"498","id":"1079"},{"source":"1069","target":"1063","id":"2810"},{"source":"1329","target":"567","id":"5597"},{"source":"1266","target":"495","id":"3731"},{"source":"1268","target":"53","id":"3744"},{"source":"1452","target":"281","id":"4753"},{"source":"1267","target":"409","id":"3736"},{"source":"828","target":"511","id":"1865"},{"source":"664","target":"662","id":"3703"},{"source":"1674","target":"64","id":"6311"},{"source":"583","target":"578","id":"1091"},{"source":"758","target":"344","id":"5832"},{"source":"306","target":"315","id":"451"},{"source":"1209","target":"457","id":"3471"},{"source":"1676","target":"281","id":"6354"},{"source":"482","target":"1291","id":"3840"},{"source":"1111","target":"238","id":"5956"},{"source":"1241","target":"1238","id":"6526"},{"source":"672","target":"451","id":"5401"},{"source":"1067","target":"1062","id":"2806"},{"source":"1267","target":"600","id":"3732"},{"source":"1510","target":"47","id":"5202"},{"source":"838","target":"48","id":"2455"},{"source":"583","target":"576","id":"1086"},{"source":"803","target":"928","id":"3759"},{"source":"728","target":"113","id":"5450"},{"source":"661","target":"888","id":"6057"},{"source":"451","target":"64","id":"743"},{"source":"1342","target":"411","id":"4101"},{"source":"1675","target":"65","id":"6328"},{"source":"1033","target":"206","id":"2674"},{"source":"707","target":"768","id":"1627"},{"source":"302","target":"182","id":"5115"},{"source":"390","target":"391","id":"640"},{"source":"448","target":"192","id":"724"},{"source":"305","target":"307","id":"397"},{"source":"1586","target":"122","id":"6553"},{"source":"1008","target":"422","id":"5693"},{"source":"1632","target":"1266","id":"6050"},{"source":"795","target":"65","id":"1744"},{"source":"22","target":"26","id":"26"},{"source":"1673","target":"87","id":"6306"},{"source":"1607","target":"1282","id":"5905"},{"source":"294","target":"79","id":"902"},{"source":"199","target":"391","id":"3320"},{"source":"924","target":"53","id":"5327"},{"source":"186","target":"187","id":"207"},{"source":"165","target":"166","id":"186"},{"source":"1529","target":"1242","id":"5269"},{"source":"1630","target":"313","id":"6031"},{"source":"801","target":"49","id":"4216"},{"source":"1315","target":"486","id":"4486"},{"source":"613","target":"79","id":"1965"},{"source":"706","target":"707","id":"1428"},{"source":"671","target":"120","id":"1350"},{"source":"450","target":"908","id":"4688"},{"source":"53","target":"591","id":"1111"},{"source":"1459","target":"48","id":"4805"},{"source":"514","target":"53","id":"888"},{"source":"1417","target":"917","id":"4551"},{"source":"1082","target":"653","id":"6570"},{"source":"1555","target":"428","id":"5427"},{"source":"416","target":"855","id":"3665"},{"source":"1214","target":"84","id":"3486"},{"source":"267","target":"116","id":"4436"},{"source":"368","target":"79","id":"3005"},{"source":"414","target":"401","id":"689"},{"source":"533","target":"335","id":"6083"},{"source":"1224","target":"1225","id":"3564"},{"source":"1016","target":"277","id":"2589"},{"source":"990","target":"905","id":"2530"},{"source":"234","target":"82","id":"1929"},{"source":"880","target":"519","id":"2080"},{"source":"468","target":"469","id":"779"},{"source":"775","target":"776","id":"1672"},{"source":"599","target":"128","id":"1145"},{"source":"537","target":"535","id":"3332"},{"source":"1652","target":"496","id":"6187"},{"source":"1644","target":"49","id":"6130"},{"source":"1076","target":"1074","id":"3701"},{"source":"105","target":"82","id":"5386"},{"source":"1644","target":"280","id":"6121"},{"source":"1478","target":"50","id":"4965"},{"source":"1152","target":"297","id":"4496"},{"source":"1471","target":"50","id":"4913"},{"source":"1163","target":"437","id":"3218"},{"source":"1670","target":"70","id":"6283"},{"source":"1452","target":"280","id":"4748"},{"source":"1339","target":"48","id":"4082"},{"source":"1675","target":"592","id":"6330"},{"source":"933","target":"607","id":"2317"},{"source":"112","target":"116","id":"117"},{"source":"819","target":"292","id":"1834"},{"source":"333","target":"280","id":"495"},{"source":"1341","target":"975","id":"4095"},{"source":"604","target":"204","id":"1155"},{"source":"471","target":"79","id":"808"},{"source":"412","target":"429","id":"2647"},{"source":"411","target":"603","id":"1782"},{"source":"1267","target":"335","id":"3740"},{"source":"75","target":"1","id":"71"},{"source":"1177","target":"569","id":"5365"},{"source":"48","target":"66","id":"4638"},{"source":"1360","target":"600","id":"6657"},{"source":"826","target":"177","id":"5358"},{"source":"1625","target":"163","id":"6004"},{"source":"25","target":"53","id":"1015"},{"source":"1486","target":"130","id":"5008"},{"source":"404","target":"334","id":"658"},{"source":"1448","target":"294","id":"4732"},{"source":"1550","target":"883","id":"5374"},{"source":"828","target":"682","id":"1864"},{"source":"639","target":"641","id":"1262"},{"source":"176","target":"178","id":"197"},{"source":"47","target":"119","id":"4427"},{"source":"543","target":"409","id":"934"},{"source":"117","target":"64","id":"120"},{"source":"1428","target":"848","id":"4613"},{"source":"1560","target":"1131","id":"5479"},{"source":"964","target":"109","id":"2440"},{"source":"115","target":"373","id":"2321"},{"source":"1104","target":"408","id":"2974"},{"source":"1717","target":"1718","id":"6625"},{"source":"1461","target":"1","id":"5877"},{"source":"1569","target":"1567","id":"5517"},{"source":"1011","target":"459","id":"2582"},{"source":"405","target":"280","id":"2927"},{"source":"966","target":"304","id":"5819"},{"source":"691","target":"82","id":"1396"},{"source":"1225","target":"215","id":"3827"},{"source":"1163","target":"65","id":"3209"},{"source":"1188","target":"175","id":"3381"},{"source":"1476","target":"900","id":"5048"},{"source":"326","target":"219","id":"464"},{"source":"292","target":"182","id":"376"},{"source":"840","target":"715","id":"1913"},{"source":"350","target":"296","id":"530"},{"source":"1291","target":"334","id":"5641"},{"source":"581","target":"858","id":"4184"},{"source":"1077","target":"1202","id":"3449"},{"source":"62","target":"289","id":"972"},{"source":"102","target":"53","id":"97"},{"source":"36","target":"273","id":"442"},{"source":"1266","target":"857","id":"3728"},{"source":"866","target":"61","id":"2608"},{"source":"1639","target":"68","id":"6096"},{"source":"790","target":"791","id":"1723"},{"source":"732","target":"1547","id":"5971"},{"source":"1156","target":"636","id":"3153"},{"source":"1455","target":"159","id":"4770"},{"source":"314","target":"316","id":"425"},{"source":"801","target":"50","id":"4217"},{"source":"1198","target":"79","id":"3435"},{"source":"634","target":"51","id":"1236"},{"source":"1298","target":"502","id":"3875"},{"source":"627","target":"863","id":"3855"},{"source":"1670","target":"73","id":"6281"},{"source":"514","target":"66","id":"882"},{"source":"551","target":"166","id":"968"},{"source":"3","target":"1","id":"2663"},{"source":"1718","target":"149","id":"6627"},{"source":"63","target":"50","id":"998"},{"source":"544","target":"1295","id":"6113"},{"source":"1161","target":"53","id":"3202"},{"source":"590","target":"49","id":"5171"},{"source":"898","target":"367","id":"2147"},{"source":"1699","target":"155","id":"6455"},{"source":"1529","target":"215","id":"5271"},{"source":"1636","target":"209","id":"6071"},{"source":"955","target":"444","id":"2425"},{"source":"1052","target":"1053","id":"2768"},{"source":"552","target":"119","id":"4894"},{"source":"1049","target":"128","id":"2753"},{"source":"1716","target":"149","id":"6619"},{"source":"1112","target":"137","id":"3014"},{"source":"1651","target":"429","id":"6176"},{"source":"922","target":"90","id":"2272"},{"source":"752","target":"79","id":"1938"},{"source":"407","target":"370","id":"668"},{"source":"269","target":"274","id":"331"},{"source":"1044","target":"428","id":"2725"},{"source":"1553","target":"165","id":"5407"},{"source":"378","target":"1162","id":"3206"},{"source":"1344","target":"408","id":"4113"},{"source":"45","target":"79","id":"3232"},{"source":"611","target":"608","id":"1177"},{"source":"1180","target":"409","id":"3310"},{"source":"225","target":"361","id":"6088"},{"source":"833","target":"505","id":"1891"},{"source":"382","target":"49","id":"624"},{"source":"1469","target":"119","id":"4873"},{"source":"1034","target":"206","id":"2676"},{"source":"731","target":"695","id":"4957"},{"source":"1092","target":"61","id":"2922"},{"source":"718","target":"89","id":"1468"},{"source":"591","target":"300","id":"1238"},{"source":"1299","target":"1300","id":"3878"},{"source":"1104","target":"262","id":"2973"},{"source":"1703","target":"1646","id":"6496"},{"source":"373","target":"119","id":"592"},{"source":"1245","target":"850","id":"3626"},{"source":"1069","target":"1062","id":"2809"},{"source":"1633","target":"669","id":"6059"},{"source":"1142","target":"1120","id":"6620"},{"source":"1173","target":"281","id":"3279"},{"source":"674","target":"1265","id":"3726"},{"source":"1483","target":"647","id":"4987"},{"source":"887","target":"888","id":"2107"},{"source":"1615","target":"618","id":"5922"},{"source":"1164","target":"437","id":"3987"},{"source":"1203","target":"571","id":"3452"},{"source":"1390","target":"433","id":"4361"},{"source":"1651","target":"1034","id":"6173"},{"source":"764","target":"763","id":"3442"},{"source":"1479","target":"696","id":"4973"},{"source":"573","target":"484","id":"1052"},{"source":"524","target":"1235","id":"4502"},{"source":"822","target":"49","id":"6266"},{"source":"71","target":"69","id":"3671"},{"source":"823","target":"84","id":"1846"},{"source":"425","target":"175","id":"696"},{"source":"902","target":"109","id":"3170"},{"source":"1493","target":"53","id":"5054"},{"source":"1291","target":"166","id":"5638"},{"source":"1467","target":"82","id":"4854"},{"source":"709","target":"710","id":"1433"},{"source":"677","target":"680","id":"1365"},{"source":"1105","target":"1106","id":"2980"},{"source":"449","target":"195","id":"728"},{"source":"37","target":"207","id":"702"},{"source":"691","target":"85","id":"1391"},{"source":"1628","target":"335","id":"6017"},{"source":"315","target":"326","id":"3505"},{"source":"1431","target":"885","id":"4670"},{"source":"256","target":"966","id":"5164"},{"source":"1529","target":"1224","id":"5268"},{"source":"50","target":"68","id":"5468"},{"source":"118","target":"598","id":"1296"},{"source":"265","target":"438","id":"1897"},{"source":"983","target":"391","id":"4696"},{"source":"1657","target":"431","id":"6206"},{"source":"319","target":"150","id":"3896"},{"source":"195","target":"193","id":"5392"},{"source":"1677","target":"181","id":"6361"},{"source":"1663","target":"431","id":"6236"},{"source":"341","target":"121","id":"517"},{"source":"1570","target":"159","id":"5525"},{"source":"884","target":"68","id":"2093"},{"source":"939","target":"937","id":"2351"},{"source":"957","target":"48","id":"2430"},{"source":"493","target":"825","id":"1848"},{"source":"334","target":"167","id":"4746"},{"source":"755","target":"185","id":"1596"},{"source":"1249","target":"1279","id":"5913"},{"source":"1267","target":"533","id":"3737"},{"source":"1721","target":"1289","id":"6674"},{"source":"538","target":"397","id":"4656"},{"source":"362","target":"224","id":"6460"},{"source":"852","target":"45","id":"3250"},{"source":"1290","target":"210","id":"3831"},{"source":"1092","target":"48","id":"2918"},{"source":"1589","target":"569","id":"5710"},{"source":"862","target":"708","id":"2633"},{"source":"267","target":"49","id":"4434"},{"source":"261","target":"68","id":"5959"},{"source":"1398","target":"1399","id":"4414"},{"source":"1115","target":"1060","id":"3060"},{"source":"1342","target":"48","id":"4104"},{"source":"617","target":"619","id":"1197"},{"source":"444","target":"1003","id":"2553"},{"source":"1523","target":"95","id":"5252"},{"source":"1065","target":"1064","id":"2798"},{"source":"150","target":"163","id":"4340"},{"source":"339","target":"334","id":"4206"},{"source":"144","target":"403","id":"714"},{"source":"337","target":"319","id":"512"},{"source":"22","target":"30","id":"30"},{"source":"1136","target":"281","id":"4390"},{"source":"275","target":"313","id":"4320"},{"source":"610","target":"498","id":"1187"},{"source":"660","target":"664","id":"4042"},{"source":"337","target":"339","id":"513"},{"source":"501","target":"281","id":"837"},{"source":"396","target":"397","id":"648"},{"source":"320","target":"323","id":"438"},{"source":"871","target":"62","id":"2043"},{"source":"893","target":"51","id":"2562"},{"source":"715","target":"710","id":"1446"},{"source":"813","target":"132","id":"1813"},{"source":"840","target":"713","id":"1918"},{"source":"941","target":"1","id":"6576"},{"source":"66","target":"119","id":"2600"},{"source":"246","target":"1022","id":"2642"},{"source":"683","target":"82","id":"1445"},{"source":"866","target":"50","id":"2613"},{"source":"904","target":"93","id":"2202"},{"source":"716","target":"85","id":"1451"},{"source":"1355","target":"1357","id":"4179"},{"source":"727","target":"53","id":"1508"},{"source":"1353","target":"746","id":"4172"},{"source":"657","target":"656","id":"6000"},{"source":"753","target":"310","id":"5127"},{"source":"757","target":"238","id":"5831"},{"source":"1136","target":"1142","id":"4392"},{"source":"750","target":"751","id":"1582"},{"source":"442","target":"444","id":"720"},{"source":"302","target":"296","id":"5114"},{"source":"1213","target":"82","id":"5344"},{"source":"257","target":"259","id":"302"},{"source":"46","target":"309","id":"4307"},{"source":"70","target":"74","id":"2493"},{"source":"1126","target":"128","id":"4810"},{"source":"121","target":"1","id":"129"},{"source":"1130","target":"900","id":"5937"},{"source":"1637","target":"996","id":"6072"},{"source":"1076","target":"262","id":"3699"},{"source":"1477","target":"131","id":"4933"},{"source":"42","target":"53","id":"343"},{"source":"345","target":"346","id":"525"},{"source":"466","target":"467","id":"776"},{"source":"1495","target":"1496","id":"5079"},{"source":"506","target":"397","id":"843"},{"source":"376","target":"295","id":"605"},{"source":"398","target":"49","id":"5159"},{"source":"1117","target":"300","id":"3019"},{"source":"931","target":"403","id":"2311"},{"source":"1131","target":"609","id":"3070"},{"source":"1486","target":"92","id":"5014"},{"source":"460","target":"609","id":"1166"},{"source":"1319","target":"65","id":"3983"},{"source":"556","target":"76","id":"3423"},{"source":"1459","target":"66","id":"4803"},{"source":"386","target":"239","id":"6457"},{"source":"1282","target":"1249","id":"5890"},{"source":"924","target":"82","id":"5326"},{"source":"711","target":"710","id":"1443"},{"source":"1327","target":"437","id":"5870"},{"source":"1507","target":"210","id":"5152"},{"source":"1176","target":"279","id":"3293"},{"source":"1237","target":"1144","id":"3602"},{"source":"1696","target":"65","id":"6427"},{"source":"987","target":"1126","id":"3053"},{"source":"242","target":"120","id":"2227"},{"source":"506","target":"49","id":"846"},{"source":"1246","target":"689","id":"6102"},{"source":"1435","target":"1","id":"4703"},{"source":"374","target":"590","id":"5180"},{"source":"840","target":"280","id":"1911"},{"source":"854","target":"272","id":"1971"},{"source":"66","target":"49","id":"2602"},{"source":"1363","target":"45","id":"4237"},{"source":"817","target":"598","id":"2003"},{"source":"1243","target":"53","id":"3611"},{"source":"1219","target":"1","id":"3519"},{"source":"883","target":"976","id":"4189"},{"source":"1082","target":"307","id":"6567"},{"source":"722","target":"128","id":"1476"},{"source":"38","target":"270","id":"1286"},{"source":"1583","target":"875","id":"5666"},{"source":"1673","target":"817","id":"6304"},{"source":"113","target":"587","id":"1094"},{"source":"1080","target":"1","id":"2851"},{"source":"133","target":"82","id":"149"},{"source":"1031","target":"104","id":"2662"},{"source":"162","target":"163","id":"183"},{"source":"1045","target":"1042","id":"2736"},{"source":"1200","target":"1413","id":"4532"},{"source":"474","target":"313","id":"6607"},{"source":"770","target":"768","id":"5555"},{"source":"1091","target":"68","id":"2907"},{"source":"1353","target":"111","id":"4168"},{"source":"61","target":"279","id":"861"},{"source":"366","target":"114","id":"5459"},{"source":"164","target":"162","id":"5367"},{"source":"1148","target":"350","id":"3124"},{"source":"299","target":"79","id":"1247"},{"source":"734","target":"592","id":"1529"},{"source":"1344","target":"562","id":"4114"},{"source":"785","target":"786","id":"1714"},{"source":"879","target":"648","id":"2078"},{"source":"450","target":"37","id":"4687"},{"source":"66","target":"132","id":"2603"},{"source":"328","target":"329","id":"475"},{"source":"1390","target":"897","id":"4364"},{"source":"123","target":"124","id":"130"},{"source":"1243","target":"513","id":"3613"},{"source":"864","target":"866","id":"2012"},{"source":"650","target":"79","id":"1285"},{"source":"1655","target":"1015","id":"6194"},{"source":"828","target":"591","id":"1861"},{"source":"283","target":"525","id":"6349"},{"source":"369","target":"182","id":"576"},{"source":"594","target":"287","id":"4877"},{"source":"548","target":"79","id":"961"},{"source":"477","target":"79","id":"3516"},{"source":"816","target":"858","id":"1994"},{"source":"875","target":"760","id":"2063"},{"source":"373","target":"374","id":"593"},{"source":"171","target":"1138","id":"5260"},{"source":"87","target":"512","id":"6290"},{"source":"1282","target":"1279","id":"5888"},{"source":"1200","target":"1414","id":"4533"},{"source":"61","target":"49","id":"868"},{"source":"1042","target":"567","id":"2717"},{"source":"1537","target":"1256","id":"5296"},{"source":"250","target":"453","id":"3365"},{"source":"580","target":"120","id":"1081"},{"source":"1304","target":"319","id":"3900"},{"source":"689","target":"65","id":"6109"},{"source":"104","target":"114","id":"2212"},{"source":"455","target":"622","id":"1201"},{"source":"640","target":"106","id":"5318"},{"source":"576","target":"107","id":"2373"},{"source":"1557","target":"303","id":"5829"},{"source":"738","target":"440","id":"3829"},{"source":"1119","target":"66","id":"6253"},{"source":"1722","target":"166","id":"6675"},{"source":"866","target":"65","id":"2610"},{"source":"1031","target":"76","id":"2661"},{"source":"1342","target":"166","id":"4099"},{"source":"1459","target":"281","id":"4804"},{"source":"1570","target":"82","id":"5529"},{"source":"88","target":"89","id":"81"},{"source":"850","target":"79","id":"1952"},{"source":"1663","target":"666","id":"6240"},{"source":"789","target":"53","id":"3031"},{"source":"1052","target":"204","id":"2771"},{"source":"1398","target":"281","id":"4413"},{"source":"1685","target":"1686","id":"6396"},{"source":"1323","target":"1619","id":"5957"},{"source":"756","target":"759","id":"1605"},{"source":"1266","target":"48","id":"3729"},{"source":"1514","target":"1517","id":"5224"},{"source":"1395","target":"444","id":"4380"},{"source":"471","target":"486","id":"809"},{"source":"1435","target":"82","id":"4697"},{"source":"460","target":"160","id":"1159"},{"source":"657","target":"606","id":"5998"},{"source":"1113","target":"79","id":"3015"},{"source":"704","target":"64","id":"6529"},{"source":"171","target":"1042","id":"5258"},{"source":"639","target":"112","id":"1265"},{"source":"907","target":"909","id":"2223"},{"source":"168","target":"167","id":"6369"},{"source":"779","target":"174","id":"1688"},{"source":"513","target":"49","id":"5208"},{"source":"492","target":"493","id":"816"},{"source":"118","target":"53","id":"1294"},{"source":"1374","target":"487","id":"4263"},{"source":"1707","target":"1002","id":"6533"},{"source":"291","target":"294","id":"371"},{"source":"1092","target":"53","id":"2923"},{"source":"590","target":"374","id":"5170"},{"source":"578","target":"120","id":"5682"},{"source":"893","target":"104","id":"2558"},{"source":"1557","target":"182","id":"5827"},{"source":"518","target":"444","id":"896"},{"source":"1401","target":"109","id":"4422"},{"source":"142","target":"27","id":"165"},{"source":"393","target":"390","id":"646"},{"source":"1587","target":"18","id":"5675"},{"source":"1395","target":"839","id":"4381"},{"source":"712","target":"82","id":"2032"},{"source":"783","target":"50","id":"1700"},{"source":"66","target":"65","id":"2599"},{"source":"1074","target":"1079","id":"2846"},{"source":"843","target":"715","id":"1924"},{"source":"1547","target":"571","id":"5519"},{"source":"1594","target":"101","id":"5757"},{"source":"172","target":"109","id":"5738"},{"source":"816","target":"435","id":"1993"},{"source":"1108","target":"79","id":"2998"},{"source":"1195","target":"618","id":"3417"},{"source":"282","target":"283","id":"3286"},{"source":"1246","target":"100","id":"6101"},{"source":"117","target":"105","id":"125"},{"source":"262","target":"1262","id":"5979"},{"source":"993","target":"997","id":"4529"},{"source":"197","target":"201","id":"230"},{"source":"526","target":"617","id":"3541"},{"source":"832","target":"82","id":"1878"},{"source":"212","target":"79","id":"3998"},{"source":"83","target":"53","id":"75"},{"source":"1149","target":"170","id":"3126"},{"source":"290","target":"65","id":"1853"},{"source":"1150","target":"876","id":"3133"},{"source":"269","target":"38","id":"334"},{"source":"787","target":"785","id":"6466"},{"source":"219","target":"296","id":"447"},{"source":"1572","target":"1108","id":"6319"},{"source":"1145","target":"638","id":"3108"},{"source":"1628","target":"533","id":"6022"},{"source":"966","target":"317","id":"5821"},{"source":"1644","target":"324","id":"6125"},{"source":"944","target":"502","id":"2367"},{"source":"194","target":"193","id":"4479"},{"source":"363","target":"113","id":"556"},{"source":"1276","target":"230","id":"3770"},{"source":"532","target":"533","id":"920"},{"source":"202","target":"266","id":"6639"},{"source":"903","target":"451","id":"2176"},{"source":"1001","target":"160","id":"2550"},{"source":"1013","target":"1","id":"3027"},{"source":"612","target":"613","id":"1190"},{"source":"235","target":"236","id":"270"},{"source":"1589","target":"567","id":"5705"},{"source":"1290","target":"851","id":"3833"},{"source":"484","target":"51","id":"5594"},{"source":"1183","target":"82","id":"3346"},{"source":"1698","target":"646","id":"6449"},{"source":"1467","target":"925","id":"4851"},{"source":"669","target":"378","id":"1336"},{"source":"1253","target":"852","id":"6560"},{"source":"805","target":"603","id":"1773"},{"source":"920","target":"777","id":"2264"},{"source":"483","target":"166","id":"3921"},{"source":"65","target":"131","id":"2123"},{"source":"710","target":"85","id":"1467"},{"source":"1032","target":"215","id":"2664"},{"source":"808","target":"216","id":"1787"},{"source":"1660","target":"962","id":"6229"},{"source":"1406","target":"294","id":"4478"},{"source":"60","target":"66","id":"60"},{"source":"1372","target":"1373","id":"4262"},{"source":"203","target":"198","id":"735"},{"source":"1629","target":"649","id":"6030"},{"source":"626","target":"312","id":"3229"},{"source":"1108","target":"463","id":"2995"},{"source":"172","target":"84","id":"5742"},{"source":"303","target":"185","id":"393"},{"source":"1022","target":"901","id":"3358"},{"source":"1641","target":"920","id":"6099"},{"source":"1648","target":"1009","id":"6139"},{"source":"458","target":"883","id":"5371"},{"source":"1639","target":"862","id":"6090"},{"source":"361","target":"79","id":"1957"},{"source":"1492","target":"1494","id":"5052"},{"source":"840","target":"335","id":"1912"},{"source":"901","target":"902","id":"2169"},{"source":"1041","target":"67","id":"2702"},{"source":"69","target":"72","id":"66"},{"source":"1556","target":"219","id":"5429"},{"source":"677","target":"678","id":"1362"},{"source":"893","target":"180","id":"2555"},{"source":"701","target":"540","id":"1418"},{"source":"1248","target":"421","id":"5895"},{"source":"631","target":"66","id":"1219"},{"source":"773","target":"504","id":"1647"},{"source":"1215","target":"648","id":"3489"},{"source":"1651","target":"272","id":"6175"},{"source":"1574","target":"114","id":"5561"},{"source":"523","target":"524","id":"908"},{"source":"1390","target":"155","id":"4363"},{"source":"651","target":"216","id":"1302"},{"source":"773","target":"770","id":"1650"},{"source":"422","target":"130","id":"692"},{"source":"610","target":"608","id":"1186"},{"source":"1620","target":"262","id":"5964"},{"source":"1406","target":"302","id":"4474"},{"source":"1267","target":"281","id":"3734"},{"source":"405","target":"397","id":"2931"},{"source":"1141","target":"600","id":"3091"},{"source":"1713","target":"207","id":"6605"},{"source":"514","target":"408","id":"886"},{"source":"884","target":"498","id":"2098"},{"source":"1045","target":"1047","id":"2737"},{"source":"390","target":"392","id":"641"},{"source":"849","target":"361","id":"1948"},{"source":"34","target":"37","id":"35"},{"source":"288","target":"50","id":"362"},{"source":"595","target":"68","id":"1138"},{"source":"28","target":"24","id":"5041"},{"source":"1096","target":"324","id":"2941"},{"source":"748","target":"170","id":"3786"},{"source":"556","target":"1196","id":"3425"},{"source":"63","target":"68","id":"991"},{"source":"1429","target":"1","id":"4968"},{"source":"852","target":"1083","id":"3253"},{"source":"587","target":"116","id":"1104"},{"source":"1624","target":"238","id":"5988"},{"source":"258","target":"53","id":"1307"},{"source":"257","target":"53","id":"300"},{"source":"505","target":"1177","id":"4002"},{"source":"389","target":"166","id":"638"},{"source":"873","target":"53","id":"2053"},{"source":"918","target":"53","id":"2256"},{"source":"591","target":"177","id":"1237"},{"source":"1518","target":"959","id":"5235"},{"source":"1530","target":"235","id":"5274"},{"source":"372","target":"621","id":"3957"},{"source":"1514","target":"162","id":"5221"},{"source":"1092","target":"49","id":"2920"},{"source":"801","target":"1244","id":"4212"},{"source":"72","target":"561","id":"1020"},{"source":"787","target":"1312","id":"6468"},{"source":"179","target":"177","id":"3394"},{"source":"160","target":"161","id":"182"},{"source":"289","target":"53","id":"3724"},{"source":"555","target":"403","id":"3187"},{"source":"458","target":"915","id":"5369"},{"source":"1045","target":"104","id":"2735"},{"source":"784","target":"512","id":"1705"},{"source":"456","target":"25","id":"5809"},{"source":"1205","target":"16","id":"3456"},{"source":"340","target":"150","id":"4342"},{"source":"179","target":"79","id":"3396"},{"source":"1719","target":"50","id":"6631"},{"source":"1425","target":"293","id":"6434"},{"source":"1314","target":"296","id":"4450"},{"source":"1254","target":"838","id":"3645"},{"source":"1276","target":"748","id":"3775"},{"source":"53","target":"50","id":"1118"},{"source":"452","target":"549","id":"2283"},{"source":"383","target":"20","id":"630"},{"source":"992","target":"995","id":"2536"},{"source":"1567","target":"97","id":"5507"},{"source":"358","target":"361","id":"551"},{"source":"1452","target":"61","id":"4749"},{"source":"1690","target":"316","id":"6417"},{"source":"1223","target":"486","id":"3558"},{"source":"74","target":"72","id":"1710"},{"source":"499","target":"182","id":"827"},{"source":"979","target":"1029","id":"2658"},{"source":"1189","target":"344","id":"3391"},{"source":"1581","target":"166","id":"5661"},{"source":"1490","target":"757","id":"5034"},{"source":"563","target":"564","id":"1027"},{"source":"1298","target":"66","id":"3872"},{"source":"8","target":"1","id":"9"},{"source":"1550","target":"707","id":"5376"},{"source":"113","target":"588","id":"1095"},{"source":"1280","target":"757","id":"3805"},{"source":"1632","target":"344","id":"6045"},{"source":"66","target":"48","id":"2601"},{"source":"496","target":"497","id":"820"},{"source":"1490","target":"27","id":"5031"},{"source":"765","target":"1124","id":"4825"},{"source":"114","target":"597","id":"2213"},{"source":"240","target":"120","id":"277"},{"source":"1248","target":"1279","id":"5897"},{"source":"1469","target":"594","id":"4869"},{"source":"1008","target":"424","id":"5696"},{"source":"902","target":"68","id":"3165"},{"source":"977","target":"61","id":"2499"},{"source":"333","target":"66","id":"489"},{"source":"1633","target":"1634","id":"6058"},{"source":"588","target":"116","id":"2144"},{"source":"113","target":"49","id":"1099"},{"source":"547","target":"549","id":"948"},{"source":"167","target":"65","id":"2337"},{"source":"83","target":"85","id":"77"},{"source":"44","target":"51","id":"47"},{"source":"1438","target":"1439","id":"4708"},{"source":"1342","target":"806","id":"4098"},{"source":"285","target":"62","id":"351"},{"source":"370","target":"335","id":"4580"},{"source":"163","target":"79","id":"2237"},{"source":"1553","target":"389","id":"5409"},{"source":"1144","target":"613","id":"3105"},{"source":"131","target":"111","id":"2187"},{"source":"1544","target":"76","id":"5341"},{"source":"1692","target":"791","id":"6421"},{"source":"502","target":"1284","id":"5074"},{"source":"1364","target":"631","id":"6514"},{"source":"523","target":"528","id":"913"},{"source":"832","target":"68","id":"1879"},{"source":"1049","target":"82","id":"2751"},{"source":"50","target":"65","id":"5472"},{"source":"693","target":"571","id":"1397"},{"source":"769","target":"770","id":"1634"},{"source":"330","target":"306","id":"481"},{"source":"682","target":"642","id":"6166"},{"source":"825","target":"495","id":"5855"},{"source":"35","target":"34","id":"419"},{"source":"1336","target":"50","id":"4066"},{"source":"1418","target":"602","id":"4553"},{"source":"770","target":"708","id":"5554"},{"source":"925","target":"50","id":"2289"},{"source":"1684","target":"111","id":"6384"},{"source":"789","target":"48","id":"3035"},{"source":"747","target":"364","id":"3777"},{"source":"1342","target":"1180","id":"4102"},{"source":"427","target":"568","id":"1035"},{"source":"922","target":"897","id":"2274"},{"source":"1423","target":"524","id":"4591"},{"source":"1366","target":"166","id":"4248"},{"source":"40","target":"429","id":"4686"},{"source":"1066","target":"479","id":"2805"},{"source":"286","target":"262","id":"3718"},{"source":"44","target":"47","id":"43"},{"source":"728","target":"116","id":"5454"},{"source":"797","target":"409","id":"1752"},{"source":"1334","target":"817","id":"4055"},{"source":"1359","target":"51","id":"4197"},{"source":"1487","target":"79","id":"5015"},{"source":"462","target":"465","id":"775"},{"source":"794","target":"109","id":"1742"},{"source":"841","target":"966","id":"2450"},{"source":"1144","target":"351","id":"3106"},{"source":"1709","target":"182","id":"6550"},{"source":"906","target":"463","id":"2220"},{"source":"1598","target":"1132","id":"5788"},{"source":"271","target":"1384","id":"4326"},{"source":"732","target":"469","id":"5969"},{"source":"1585","target":"1586","id":"5674"},{"source":"1717","target":"1120","id":"6623"},{"source":"755","target":"79","id":"1590"},{"source":"706","target":"132","id":"1431"},{"source":"1212","target":"761","id":"3478"},{"source":"411","target":"532","id":"1781"},{"source":"1145","target":"1147","id":"3110"},{"source":"1599","target":"890","id":"5789"},{"source":"1444","target":"216","id":"4725"},{"source":"182","target":"256","id":"4471"},{"source":"802","target":"150","id":"1769"},{"source":"681","target":"161","id":"1371"},{"source":"83","target":"82","id":"78"},{"source":"1119","target":"51","id":"6251"},{"source":"560","target":"114","id":"1018"},{"source":"780","target":"781","id":"1694"},{"source":"515","target":"610","id":"1169"},{"source":"1441","target":"1","id":"4710"},{"source":"120","target":"668","id":"4020"},{"source":"1045","target":"93","id":"2734"},{"source":"1509","target":"47","id":"5194"},{"source":"794","target":"53","id":"1738"},{"source":"1347","target":"1265","id":"4134"},{"source":"1209","target":"1210","id":"3472"},{"source":"1336","target":"284","id":"4058"},{"source":"1316","target":"216","id":"4971"},{"source":"605","target":"1046","id":"2903"},{"source":"1331","target":"1","id":"4044"},{"source":"1044","target":"426","id":"2730"},{"source":"328","target":"296","id":"472"},{"source":"926","target":"698","id":"2385"},{"source":"1684","target":"600","id":"6387"},{"source":"1351","target":"567","id":"4159"},{"source":"934","target":"1324","id":"4007"},{"source":"555","target":"469","id":"3189"},{"source":"553","target":"65","id":"988"},{"source":"767","target":"1","id":"1625"},{"source":"1291","target":"218","id":"5637"},{"source":"641","target":"640","id":"5323"},{"source":"568","target":"772","id":"1645"},{"source":"1022","target":"924","id":"3360"},{"source":"89","target":"79","id":"2234"},{"source":"694","target":"48","id":"1404"},{"source":"408","target":"67","id":"880"},{"source":"295","target":"293","id":"3179"},{"source":"835","target":"559","id":"5068"},{"source":"1661","target":"68","id":"6233"},{"source":"1227","target":"293","id":"3575"},{"source":"874","target":"876","id":"2067"},{"source":"957","target":"959","id":"2427"},{"source":"1472","target":"120","id":"4924"},{"source":"662","target":"663","id":"2789"},{"source":"400","target":"570","id":"2388"},{"source":"374","target":"513","id":"5182"},{"source":"1187","target":"76","id":"3376"},{"source":"1573","target":"49","id":"5545"},{"source":"1562","target":"571","id":"5496"},{"source":"404","target":"49","id":"659"},{"source":"1510","target":"374","id":"5204"},{"source":"1479","target":"983","id":"4976"},{"source":"437","target":"606","id":"1313"},{"source":"938","target":"167","id":"2482"},{"source":"156","target":"154","id":"176"},{"source":"593","target":"50","id":"1127"},{"source":"215","target":"128","id":"5992"},{"source":"1536","target":"250","id":"5289"},{"source":"588","target":"113","id":"2143"},{"source":"1369","target":"1371","id":"4257"},{"source":"611","target":"216","id":"1175"},{"source":"860","target":"347","id":"6117"},{"source":"1457","target":"405","id":"4784"},{"source":"1163","target":"1162","id":"3212"},{"source":"338","target":"1284","id":"3812"},{"source":"1391","target":"1392","id":"4369"},{"source":"115","target":"116","id":"2323"},{"source":"722","target":"720","id":"1473"},{"source":"1249","target":"421","id":"5911"},{"source":"157","target":"152","id":"179"},{"source":"1298","target":"53","id":"3870"},{"source":"527","target":"294","id":"3545"},{"source":"358","target":"359","id":"547"},{"source":"545","target":"546","id":"944"},{"source":"799","target":"409","id":"1763"},{"source":"1633","target":"366","id":"6063"},{"source":"245","target":"104","id":"1730"},{"source":"928","target":"148","id":"6078"},{"source":"454","target":"53","id":"750"},{"source":"1101","target":"312","id":"2959"},{"source":"1443","target":"591","id":"4722"},{"source":"285","target":"68","id":"359"},{"source":"1428","target":"136","id":"4614"},{"source":"454","target":"170","id":"752"},{"source":"448","target":"313","id":"725"},{"source":"1163","target":"1164","id":"3213"},{"source":"615","target":"206","id":"4334"},{"source":"291","target":"292","id":"368"},{"source":"1677","target":"1293","id":"6362"},{"source":"864","target":"61","id":"2007"},{"source":"1210","target":"1262","id":"6447"},{"source":"1471","target":"279","id":"4914"},{"source":"1544","target":"82","id":"5342"},{"source":"458","target":"696","id":"5368"},{"source":"1632","target":"999","id":"6048"},{"source":"1589","target":"427","id":"5706"},{"source":"832","target":"693","id":"1883"},{"source":"929","target":"779","id":"2304"},{"source":"1305","target":"296","id":"4575"},{"source":"333","target":"49","id":"492"},{"source":"307","target":"367","id":"564"},{"source":"979","target":"1030","id":"2660"},{"source":"1273","target":"1228","id":"3763"},{"source":"974","target":"1385","id":"4339"},{"source":"1550","target":"106","id":"5378"},{"source":"421","target":"420","id":"3687"},{"source":"901","target":"250","id":"2170"},{"source":"27","target":"428","id":"2993"},{"source":"1547","target":"258","id":"5518"},{"source":"1679","target":"1680","id":"6378"},{"source":"976","target":"1150","id":"3132"},{"source":"1046","target":"1524","id":"6341"},{"source":"580","target":"519","id":"1078"},{"source":"51","target":"61","id":"5582"},{"source":"912","target":"309","id":"2860"},{"source":"259","target":"841","id":"2154"},{"source":"1448","target":"416","id":"4735"},{"source":"308","target":"79","id":"570"},{"source":"1376","target":"295","id":"4281"},{"source":"1650","target":"281","id":"6154"},{"source":"1110","target":"500","id":"3011"},{"source":"1555","target":"498","id":"5426"},{"source":"1114","target":"1060","id":"3058"},{"source":"1248","target":"1283","id":"5901"},{"source":"949","target":"208","id":"2395"},{"source":"944","target":"48","id":"2366"},{"source":"1098","target":"79","id":"2947"},{"source":"1431","target":"608","id":"4667"},{"source":"271","target":"275","id":"4328"},{"source":"1071","target":"1076","id":"2837"},{"source":"690","target":"685","id":"1389"},{"source":"1183","target":"76","id":"3342"},{"source":"1514","target":"163","id":"5222"},{"source":"601","target":"600","id":"1150"},{"source":"755","target":"45","id":"1594"},{"source":"619","target":"79","id":"6035"},{"source":"352","target":"232","id":"539"},{"source":"1472","target":"1473","id":"4916"},{"source":"1720","target":"62","id":"6666"},{"source":"1431","target":"515","id":"4674"},{"source":"227","target":"1","id":"257"},{"source":"746","target":"170","id":"4855"},{"source":"744","target":"131","id":"1561"},{"source":"845","target":"706","id":"1934"},{"source":"143","target":"379","id":"611"},{"source":"1486","target":"1109","id":"5013"},{"source":"60","target":"65","id":"59"},{"source":"1204","target":"239","id":"3455"},{"source":"608","target":"65","id":"1495"},{"source":"1291","target":"279","id":"5639"},{"source":"1387","target":"1","id":"4355"},{"source":"1658","target":"303","id":"6213"},{"source":"572","target":"196","id":"2667"},{"source":"711","target":"713","id":"1440"},{"source":"1023","target":"858","id":"4357"},{"source":"942","target":"76","id":"2357"},{"source":"1101","target":"1098","id":"2957"},{"source":"567","target":"131","id":"2718"},{"source":"339","target":"1243","id":"4205"},{"source":"883","target":"693","id":"4186"},{"source":"424","target":"422","id":"4943"},{"source":"1044","target":"1042","id":"2732"},{"source":"429","target":"1","id":"4692"},{"source":"989","target":"192","id":"2529"},{"source":"1477","target":"130","id":"4939"},{"source":"1550","target":"68","id":"5375"},{"source":"1046","target":"171","id":"6340"},{"source":"1702","target":"1103","id":"6490"},{"source":"1678","target":"334","id":"6374"},{"source":"460","target":"433","id":"1160"},{"source":"992","target":"996","id":"2537"},{"source":"117","target":"118","id":"119"},{"source":"1221","target":"254","id":"3529"},{"source":"1626","target":"53","id":"6009"},{"source":"978","target":"182","id":"2505"},{"source":"483","target":"51","id":"3920"},{"source":"42","target":"284","id":"349"},{"source":"604","target":"605","id":"1157"},{"source":"1470","target":"511","id":"4905"},{"source":"578","target":"241","id":"5680"},{"source":"430","target":"429","id":"4833"},{"source":"374","target":"47","id":"5178"},{"source":"443","target":"309","id":"1289"},{"source":"1187","target":"708","id":"3372"},{"source":"1556","target":"1410","id":"5434"},{"source":"887","target":"598","id":"2106"},{"source":"788","target":"789","id":"1719"},{"source":"1457","target":"182","id":"4786"},{"source":"28","target":"456","id":"5040"},{"source":"93","target":"65","id":"2159"},{"source":"1337","target":"199","id":"4071"},{"source":"612","target":"614","id":"1191"},{"source":"45","target":"626","id":"3233"},{"source":"788","target":"498","id":"1722"},{"source":"726","target":"114","id":"2193"},{"source":"643","target":"644","id":"1269"},{"source":"407","target":"409","id":"669"},{"source":"968","target":"37","id":"2460"},{"source":"558","target":"76","id":"1011"},{"source":"216","target":"357","id":"542"},{"source":"1068","target":"1064","id":"2808"},{"source":"1534","target":"82","id":"5281"},{"source":"447","target":"233","id":"1009"},{"source":"868","target":"84","id":"2018"},{"source":"885","target":"212","id":"4005"},{"source":"611","target":"66","id":"1178"},{"source":"234","target":"215","id":"1928"},{"source":"373","target":"112","id":"588"},{"source":"529","target":"531","id":"916"},{"source":"654","target":"657","id":"3422"},{"source":"1122","target":"1015","id":"3047"},{"source":"108","target":"64","id":"5490"},{"source":"728","target":"363","id":"5449"},{"source":"581","target":"519","id":"4181"},{"source":"429","target":"37","id":"4690"},{"source":"894","target":"74","id":"2121"},{"source":"1493","target":"166","id":"5053"},{"source":"754","target":"638","id":"5438"},{"source":"1250","target":"1251","id":"3633"},{"source":"696","target":"698","id":"1413"},{"source":"589","target":"590","id":"1663"},{"source":"969","target":"444","id":"2469"},{"source":"245","target":"105","id":"1731"},{"source":"1379","target":"1358","id":"4286"},{"source":"952","target":"349","id":"2411"},{"source":"580","target":"581","id":"1074"},{"source":"691","target":"248","id":"1393"},{"source":"801","target":"483","id":"4214"},{"source":"436","target":"555","id":"1004"},{"source":"1583","target":"409","id":"5669"},{"source":"37","target":"272","id":"704"},{"source":"573","target":"50","id":"1051"},{"source":"1198","target":"119","id":"3438"},{"source":"1374","target":"391","id":"4267"},{"source":"766","target":"163","id":"1623"},{"source":"352","target":"354","id":"537"},{"source":"538","target":"53","id":"4654"},{"source":"992","target":"997","id":"2538"},{"source":"1479","target":"170","id":"4977"},{"source":"21","target":"1","id":"1311"},{"source":"61","target":"512","id":"864"},{"source":"1664","target":"855","id":"6247"},{"source":"889","target":"661","id":"4404"},{"source":"476","target":"79","id":"790"},{"source":"1658","target":"1448","id":"6220"},{"source":"405","target":"200","id":"2933"},{"source":"794","target":"104","id":"1740"},{"source":"57","target":"313","id":"3184"},{"source":"223","target":"224","id":"253"},{"source":"1209","target":"455","id":"3468"},{"source":"479","target":"1063","id":"4294"},{"source":"178","target":"463","id":"1244"},{"source":"567","target":"82","id":"2724"},{"source":"1514","target":"1518","id":"5225"},{"source":"625","target":"627","id":"1205"},{"source":"1148","target":"318","id":"3125"},{"source":"1179","target":"170","id":"3308"},{"source":"1286","target":"166","id":"3821"},{"source":"1468","target":"484","id":"4867"},{"source":"254","target":"255","id":"292"},{"source":"1160","target":"1","id":"3195"},{"source":"781","target":"104","id":"2785"},{"source":"1427","target":"128","id":"4606"},{"source":"781","target":"68","id":"2781"},{"source":"457","target":"51","id":"6345"},{"source":"66","target":"50","id":"2604"},{"source":"822","target":"405","id":"6261"},{"source":"613","target":"351","id":"1967"},{"source":"365","target":"155","id":"1342"},{"source":"1156","target":"239","id":"3155"},{"source":"1457","target":"513","id":"4790"},{"source":"363","target":"65","id":"559"},{"source":"282","target":"284","id":"3287"},{"source":"766","target":"1","id":"1624"},{"source":"921","target":"155","id":"2267"},{"source":"628","target":"934","id":"4154"},{"source":"193","target":"194","id":"220"},{"source":"73","target":"72","id":"1707"},{"source":"1016","target":"50","id":"2597"},{"source":"1164","target":"606","id":"3988"},{"source":"1411","target":"532","id":"4510"},{"source":"441","target":"172","id":"4377"},{"source":"62","target":"53","id":"978"},{"source":"449","target":"450","id":"727"},{"source":"1291","target":"983","id":"5640"},{"source":"1412","target":"996","id":"4523"},{"source":"1074","target":"1073","id":"2848"},{"source":"66","target":"88","id":"2605"},{"source":"1007","target":"50","id":"2576"},{"source":"1318","target":"111","id":"3971"},{"source":"608","target":"607","id":"1493"},{"source":"1672","target":"702","id":"6298"},{"source":"476","target":"475","id":"789"},{"source":"409","target":"48","id":"4650"},{"source":"1431","target":"1432","id":"4672"},{"source":"1387","target":"79","id":"4349"},{"source":"714","target":"715","id":"6651"},{"source":"701","target":"702","id":"1419"},{"source":"633","target":"65","id":"1225"},{"source":"1268","target":"513","id":"3745"},{"source":"267","target":"47","id":"4440"},{"source":"180","target":"183","id":"204"},{"source":"600","target":"281","id":"1149"},{"source":"946","target":"250","id":"2380"},{"source":"1466","target":"747","id":"4841"},{"source":"378","target":"424","id":"3208"},{"source":"818","target":"313","id":"1833"},{"source":"1702","target":"1238","id":"6487"},{"source":"248","target":"175","id":"5347"},{"source":"1604","target":"128","id":"5850"},{"source":"1096","target":"1094","id":"2942"},{"source":"933","target":"934","id":"2318"},{"source":"608","target":"53","id":"1491"},{"source":"881","target":"100","id":"2089"},{"source":"254","target":"182","id":"294"},{"source":"120","target":"576","id":"4021"},{"source":"787","target":"206","id":"6467"},{"source":"1181","target":"216","id":"3323"},{"source":"672","target":"53","id":"5402"},{"source":"508","target":"137","id":"3656"},{"source":"496","target":"498","id":"823"},{"source":"1492","target":"104","id":"5050"},{"source":"436","target":"264","id":"1003"},{"source":"1489","target":"1434","id":"5019"},{"source":"172","target":"882","id":"5736"},{"source":"1223","target":"526","id":"3559"},{"source":"148","target":"150","id":"169"},{"source":"44","target":"48","id":"44"},{"source":"231","target":"232","id":"261"},{"source":"65","target":"53","id":"2129"},{"source":"1621","target":"469","id":"5981"},{"source":"169","target":"172","id":"192"},{"source":"52","target":"53","id":"5766"},{"source":"1102","target":"1098","id":"3499"},{"source":"1689","target":"133","id":"6402"},{"source":"1363","target":"46","id":"4238"},{"source":"702","target":"160","id":"3883"},{"source":"931","target":"932","id":"2312"},{"source":"1158","target":"1","id":"3183"},{"source":"228","target":"1","id":"258"},{"source":"1180","target":"166","id":"3314"},{"source":"643","target":"65","id":"1271"},{"source":"67","target":"92","id":"2708"},{"source":"1104","target":"79","id":"2968"},{"source":"1256","target":"469","id":"3652"},{"source":"1161","target":"567","id":"3198"},{"source":"1593","target":"654","id":"5753"},{"source":"1383","target":"310","id":"4311"},{"source":"1636","target":"1034","id":"6065"},{"source":"1568","target":"571","id":"5514"},{"source":"206","target":"1037","id":"2689"},{"source":"482","target":"281","id":"3837"},{"source":"806","target":"1266","id":"6053"},{"source":"1703","target":"853","id":"6493"},{"source":"636","target":"119","id":"3177"},{"source":"232","target":"128","id":"4373"},{"source":"1184","target":"1083","id":"3353"},{"source":"148","target":"149","id":"168"},{"source":"1583","target":"166","id":"5663"},{"source":"1212","target":"81","id":"3482"},{"source":"1269","target":"1270","id":"3753"},{"source":"1633","target":"1165","id":"6062"},{"source":"1592","target":"150","id":"5746"},{"source":"984","target":"765","id":"2519"},{"source":"265","target":"835","id":"1899"},{"source":"1007","target":"833","id":"2579"},{"source":"1250","target":"302","id":"3637"},{"source":"1119","target":"405","id":"6254"},{"source":"1073","target":"262","id":"2841"},{"source":"1339","target":"806","id":"4084"},{"source":"687","target":"689","id":"1386"},{"source":"473","target":"474","id":"6433"},{"source":"405","target":"50","id":"2925"},{"source":"1471","target":"61","id":"4915"},{"source":"778","target":"25","id":"1679"},{"source":"1355","target":"182","id":"4178"},{"source":"976","target":"104","id":"3130"},{"source":"126","target":"82","id":"136"},{"source":"1404","target":"1403","id":"4541"},{"source":"628","target":"79","id":"4150"},{"source":"1150","target":"65","id":"3135"},{"source":"590","target":"589","id":"5167"},{"source":"1053","target":"206","id":"4603"},{"source":"1326","target":"423","id":"4028"},{"source":"1652","target":"695","id":"6183"},{"source":"1194","target":"1182","id":"3412"},{"source":"604","target":"567","id":"1156"},{"source":"286","target":"647","id":"3716"},{"source":"523","target":"525","id":"910"},{"source":"1615","target":"1279","id":"5924"},{"source":"923","target":"110","id":"2275"},{"source":"690","target":"79","id":"1387"},{"source":"573","target":"53","id":"1046"},{"source":"1480","target":"1479","id":"4980"},{"source":"1091","target":"50","id":"2915"},{"source":"1641","target":"630","id":"6098"},{"source":"1591","target":"65","id":"5726"},{"source":"725","target":"515","id":"1502"},{"source":"1074","target":"224","id":"2847"},{"source":"595","target":"79","id":"1131"},{"source":"22","target":"28","id":"28"},{"source":"285","target":"287","id":"356"},{"source":"1197","target":"312","id":"3428"},{"source":"1635","target":"1","id":"6064"},{"source":"788","target":"411","id":"1721"},{"source":"1124","target":"388","id":"4844"},{"source":"279","target":"281","id":"506"},{"source":"20","target":"21","id":"140"},{"source":"694","target":"50","id":"1408"},{"source":"36","target":"276","id":"443"},{"source":"1574","target":"53","id":"5558"},{"source":"1244","target":"48","id":"3623"},{"source":"1604","target":"344","id":"5851"},{"source":"1485","target":"50","id":"5006"},{"source":"751","target":"479","id":"1937"},{"source":"484","target":"49","id":"5593"},{"source":"1285","target":"966","id":"3819"},{"source":"605","target":"495","id":"2904"},{"source":"1401","target":"166","id":"4416"},{"source":"1649","target":"217","id":"6148"},{"source":"950","target":"208","id":"2399"},{"source":"410","target":"411","id":"674"},{"source":"215","target":"82","id":"5994"},{"source":"1249","target":"1282","id":"5914"},{"source":"688","target":"83","id":"1658"},{"source":"982","target":"983","id":"2514"},{"source":"336","target":"334","id":"3147"},{"source":"1411","target":"765","id":"4514"},{"source":"511","target":"53","id":"6475"},{"source":"483","target":"334","id":"3927"},{"source":"461","target":"459","id":"2617"},{"source":"1699","target":"1","id":"6454"},{"source":"1281","target":"1282","id":"3810"},{"source":"1091","target":"498","id":"2911"},{"source":"1032","target":"128","id":"2666"},{"source":"811","target":"592","id":"1806"},{"source":"1572","target":"626","id":"6320"},{"source":"217","target":"82","id":"3119"},{"source":"886","target":"600","id":"2102"},{"source":"602","target":"603","id":"1151"},{"source":"594","target":"262","id":"4878"},{"source":"1578","target":"82","id":"5625"},{"source":"51","target":"53","id":"5584"},{"source":"760","target":"120","id":"1612"},{"source":"1721","target":"119","id":"6673"},{"source":"320","target":"321","id":"436"},{"source":"813","target":"127","id":"1812"},{"source":"335","target":"575","id":"1055"},{"source":"948","target":"668","id":"3443"},{"source":"1517","target":"162","id":"5231"},{"source":"1660","target":"49","id":"6228"},{"source":"1280","target":"339","id":"3802"},{"source":"871","target":"289","id":"2047"},{"source":"1656","target":"903","id":"6197"},{"source":"665","target":"515","id":"1327"},{"source":"49","target":"61","id":"5188"},{"source":"1175","target":"200","id":"3324"},{"source":"22","target":"29","id":"29"},{"source":"156","target":"53","id":"175"},{"source":"526","target":"219","id":"3539"},{"source":"1327","target":"424","id":"5875"},{"source":"388","target":"896","id":"2393"},{"source":"1555","target":"1379","id":"5428"},{"source":"1593","target":"101","id":"5752"},{"source":"902","target":"111","id":"3169"},{"source":"60","target":"53","id":"57"},{"source":"1223","target":"527","id":"3560"},{"source":"1554","target":"68","id":"5417"},{"source":"1244","target":"396","id":"3619"},{"source":"135","target":"137","id":"1042"},{"source":"1291","target":"1581","id":"5645"},{"source":"60","target":"64","id":"58"},{"source":"226","target":"79","id":"256"},{"source":"1243","target":"239","id":"3614"},{"source":"476","target":"368","id":"791"},{"source":"105","target":"65","id":"5382"},{"source":"603","target":"1","id":"1425"},{"source":"535","target":"532","id":"2462"},{"source":"697","target":"170","id":"5687"},{"source":"25","target":"559","id":"1016"},{"source":"1117","target":"894","id":"3022"},{"source":"425","target":"428","id":"701"},{"source":"1705","target":"779","id":"6500"},{"source":"590","target":"47","id":"5168"},{"source":"748","target":"1122","id":"3783"},{"source":"1713","target":"1","id":"6600"},{"source":"962","target":"961","id":"6356"},{"source":"296","target":"219","id":"427"},{"source":"1385","target":"974","id":"4348"},{"source":"61","target":"50","id":"869"},{"source":"1138","target":"1137","id":"5250"},{"source":"1648","target":"281","id":"6144"},{"source":"595","target":"105","id":"1135"},{"source":"1594","target":"95","id":"5760"},{"source":"633","target":"93","id":"1226"},{"source":"925","target":"53","id":"2284"},{"source":"1304","target":"325","id":"3902"},{"source":"583","target":"68","id":"1083"},{"source":"250","target":"50","id":"3367"},{"source":"48","target":"281","id":"4640"},{"source":"1509","target":"254","id":"5191"},{"source":"14","target":"1","id":"16"},{"source":"1563","target":"258","id":"5499"},{"source":"37","target":"429","id":"705"},{"source":"1379","target":"428","id":"4285"},{"source":"1177","target":"505","id":"5362"},{"source":"1579","target":"618","id":"5636"},{"source":"1049","target":"599","id":"2754"},{"source":"1313","target":"297","id":"3951"},{"source":"915","target":"883","id":"2325"},{"source":"1530","target":"641","id":"5273"},{"source":"631","target":"65","id":"1217"},{"source":"200","target":"229","id":"4663"},{"source":"1025","target":"76","id":"4627"},{"source":"1721","target":"816","id":"6671"},{"source":"673","target":"674","id":"1355"},{"source":"1298","target":"50","id":"3867"},{"source":"1467","target":"166","id":"4849"},{"source":"74","target":"73","id":"1711"},{"source":"1649","target":"128","id":"6146"},{"source":"1710","target":"1","id":"6556"},{"source":"1648","target":"279","id":"6141"},{"source":"633","target":"79","id":"1224"},{"source":"516","target":"517","id":"891"},{"source":"806","target":"48","id":"6055"},{"source":"1572","target":"1407","id":"6321"},{"source":"1329","target":"424","id":"5600"},{"source":"1557","target":"967","id":"5826"},{"source":"115","target":"363","id":"2319"},{"source":"206","target":"1038","id":"2690"},{"source":"594","target":"865","id":"4876"},{"source":"677","target":"679","id":"1363"},{"source":"1318","target":"983","id":"3972"},{"source":"206","target":"1039","id":"2692"},{"source":"177","target":"465","id":"955"},{"source":"243","target":"118","id":"278"},{"source":"1608","target":"1609","id":"5882"},{"source":"828","target":"68","id":"1866"},{"source":"850","target":"141","id":"1955"},{"source":"552","target":"61","id":"4889"},{"source":"808","target":"49","id":"1795"},{"source":"201","target":"607","id":"4757"},{"source":"712","target":"232","id":"2039"},{"source":"1471","target":"408","id":"4906"},{"source":"840","target":"444","id":"1915"},{"source":"1197","target":"298","id":"3430"},{"source":"361","target":"368","id":"1959"},{"source":"27","target":"25","id":"2992"},{"source":"456","target":"27","id":"5810"},{"source":"1561","target":"609","id":"6508"},{"source":"1074","target":"1077","id":"2842"},{"source":"1122","target":"1124","id":"3048"},{"source":"1161","target":"64","id":"3203"},{"source":"1549","target":"1073","id":"5366"},{"source":"869","target":"712","id":"2029"},{"source":"1160","target":"79","id":"3194"},{"source":"1694","target":"182","id":"6425"},{"source":"1329","target":"654","id":"5598"},{"source":"1689","target":"647","id":"6407"},{"source":"301","target":"294","id":"385"},{"source":"948","target":"768","id":"3445"},{"source":"859","target":"161","id":"2002"},{"source":"1511","target":"82","id":"5210"},{"source":"1628","target":"409","id":"6021"},{"source":"446","target":"149","id":"906"},{"source":"605","target":"1050","id":"2902"},{"source":"1175","target":"128","id":"3327"},{"source":"252","target":"458","id":"759"},{"source":"973","target":"79","id":"2477"},{"source":"114","target":"104","id":"2215"},{"source":"898","target":"1","id":"2148"},{"source":"701","target":"703","id":"1420"},{"source":"62","target":"50","id":"974"},{"source":"1339","target":"1161","id":"4080"},{"source":"1443","target":"65","id":"4715"},{"source":"1717","target":"1121","id":"6624"},{"source":"306","target":"326","id":"454"},{"source":"552","target":"63","id":"4890"},{"source":"23","target":"456","id":"5806"},{"source":"431","target":"1","id":"707"},{"source":"324","target":"211","id":"2817"},{"source":"1588","target":"65","id":"5700"},{"source":"62","target":"61","id":"976"},{"source":"782","target":"175","id":"2897"},{"source":"392","target":"498","id":"4272"},{"source":"1351","target":"1042","id":"4158"},{"source":"1596","target":"759","id":"5778"},{"source":"1470","target":"68","id":"4896"},{"source":"779","target":"736","id":"1690"},{"source":"663","target":"662","id":"2790"},{"source":"1324","target":"628","id":"4647"},{"source":"408","target":"513","id":"874"},{"source":"1536","target":"97","id":"5282"},{"source":"501","target":"503","id":"835"},{"source":"498","target":"581","id":"1988"},{"source":"335","target":"51","id":"1056"},{"source":"1489","target":"1039","id":"5023"},{"source":"733","target":"174","id":"1527"},{"source":"290","target":"67","id":"1854"},{"source":"696","target":"109","id":"1412"},{"source":"37","target":"1","id":"703"},{"source":"299","target":"300","id":"1249"},{"source":"975","target":"53","id":"2485"},{"source":"1244","target":"51","id":"3618"},{"source":"856","target":"185","id":"1981"},{"source":"731","target":"109","id":"4958"},{"source":"501","target":"502","id":"831"},{"source":"109","target":"964","id":"5721"},{"source":"387","target":"216","id":"635"},{"source":"1277","target":"1275","id":"3792"},{"source":"1661","target":"901","id":"6231"},{"source":"1426","target":"293","id":"4592"},{"source":"1337","target":"166","id":"4067"},{"source":"719","target":"1","id":"1471"},{"source":"629","target":"79","id":"2680"},{"source":"1355","target":"500","id":"4180"},{"source":"1477","target":"430","id":"4937"},{"source":"523","target":"527","id":"912"},{"source":"195","target":"449","id":"5394"},{"source":"135","target":"494","id":"1041"},{"source":"1047","target":"209","id":"4331"},{"source":"1547","target":"648","id":"5521"},{"source":"1657","target":"559","id":"6209"},{"source":"596","target":"159","id":"1140"},{"source":"695","target":"166","id":"4951"},{"source":"113","target":"112","id":"1093"},{"source":"843","target":"714","id":"1922"},{"source":"1709","target":"967","id":"6546"},{"source":"1477","target":"567","id":"4934"},{"source":"501","target":"505","id":"838"},{"source":"50","target":"67","id":"5475"},{"source":"749","target":"166","id":"4738"},{"source":"816","target":"598","id":"1991"},{"source":"987","target":"82","id":"3055"},{"source":"1025","target":"760","id":"4630"},{"source":"611","target":"552","id":"1181"},{"source":"274","target":"276","id":"324"},{"source":"223","target":"211","id":"252"},{"source":"1102","target":"177","id":"3497"},{"source":"1416","target":"317","id":"4549"},{"source":"927","target":"928","id":"2298"},{"source":"472","target":"313","id":"782"},{"source":"1615","target":"1249","id":"5927"},{"source":"856","target":"79","id":"1979"},{"source":"518","target":"166","id":"893"},{"source":"316","target":"1","id":"4492"},{"source":"921","target":"858","id":"2266"},{"source":"204","target":"206","id":"234"},{"source":"1568","target":"1567","id":"5512"},{"source":"310","target":"296","id":"402"},{"source":"730","target":"484","id":"1523"},{"source":"1216","target":"82","id":"3496"},{"source":"153","target":"584","id":"2230"},{"source":"243","target":"246","id":"281"},{"source":"117","target":"95","id":"127"},{"source":"1593","target":"1329","id":"5754"},{"source":"288","target":"62","id":"365"},{"source":"210","target":"212","id":"239"},{"source":"418","target":"416","id":"4565"},{"source":"1701","target":"287","id":"6483"},{"source":"1191","target":"259","id":"3405"},{"source":"1431","target":"760","id":"4668"},{"source":"1350","target":"177","id":"4145"},{"source":"1334","target":"1335","id":"4051"},{"source":"647","target":"1202","id":"3712"},{"source":"289","target":"79","id":"3725"},{"source":"892","target":"325","id":"5144"},{"source":"936","target":"883","id":"2332"},{"source":"355","target":"217","id":"4009"},{"source":"638","target":"79","id":"3099"},{"source":"451","target":"131","id":"746"},{"source":"593","target":"594","id":"1125"},{"source":"605","target":"567","id":"2899"},{"source":"370","target":"51","id":"4584"},{"source":"1253","target":"79","id":"6558"},{"source":"1590","target":"422","id":"5713"},{"source":"461","target":"108","id":"2624"},{"source":"102","target":"105","id":"100"},{"source":"315","target":"79","id":"3506"},{"source":"617","target":"618","id":"1196"},{"source":"776","target":"1060","id":"2792"},{"source":"1173","target":"406","id":"3281"},{"source":"317","target":"185","id":"4546"},{"source":"859","target":"861","id":"1996"},{"source":"1605","target":"1","id":"5858"},{"source":"1485","target":"64","id":"5002"},{"source":"144","target":"438","id":"716"},{"source":"567","target":"1045","id":"2721"},{"source":"874","target":"50","id":"2068"},{"source":"1163","target":"378","id":"3211"},{"source":"112","target":"104","id":"114"},{"source":"918","target":"915","id":"2259"},{"source":"577","target":"68","id":"4396"},{"source":"108","target":"591","id":"5488"},{"source":"1701","target":"65","id":"6482"},{"source":"1343","target":"1175","id":"4109"},{"source":"953","target":"1","id":"2415"},{"source":"687","target":"688","id":"1382"},{"source":"44","target":"53","id":"49"},{"source":"337","target":"340","id":"514"},{"source":"1299","target":"76","id":"3877"},{"source":"499","target":"254","id":"824"},{"source":"1347","target":"641","id":"4136"},{"source":"1212","target":"1213","id":"3480"},{"source":"578","target":"585","id":"5684"},{"source":"203","target":"79","id":"737"},{"source":"967","target":"1","id":"2651"},{"source":"1606","target":"618","id":"5864"},{"source":"304","target":"294","id":"4505"},{"source":"107","target":"53","id":"2333"},{"source":"1444","target":"214","id":"4723"},{"source":"939","target":"107","id":"2349"},{"source":"391","target":"1316","id":"3966"},{"source":"122","target":"1","id":"860"},{"source":"500","target":"1600","id":"5796"},{"source":"188","target":"192","id":"223"},{"source":"1173","target":"48","id":"3280"},{"source":"615","target":"209","id":"4336"},{"source":"1616","target":"913","id":"5945"},{"source":"1589","target":"904","id":"5711"},{"source":"859","target":"513","id":"2001"},{"source":"571","target":"570","id":"5524"},{"source":"487","target":"488","id":"810"},{"source":"735","target":"736","id":"1532"},{"source":"730","target":"634","id":"1516"},{"source":"1040","target":"1039","id":"2697"},{"source":"1468","target":"79","id":"4860"},{"source":"154","target":"152","id":"2434"},{"source":"1442","target":"79","id":"6442"},{"source":"91","target":"704","id":"5416"},{"source":"303","target":"301","id":"394"},{"source":"442","target":"446","id":"722"},{"source":"456","target":"23","id":"5813"},{"source":"1386","target":"1323","id":"4344"},{"source":"1119","target":"397","id":"6255"},{"source":"1223","target":"79","id":"3557"},{"source":"167","target":"68","id":"2335"},{"source":"239","target":"1698","id":"6450"},{"source":"1076","target":"1077","id":"3696"},{"source":"1298","target":"49","id":"3876"},{"source":"1273","target":"1275","id":"3762"},{"source":"1711","target":"150","id":"6584"},{"source":"1531","target":"662","id":"5278"},{"source":"841","target":"513","id":"2448"},{"source":"216","target":"356","id":"541"},{"source":"1206","target":"397","id":"3458"},{"source":"871","target":"287","id":"2048"},{"source":"884","target":"82","id":"2101"},{"source":"1115","target":"1114","id":"3061"},{"source":"130","target":"132","id":"143"},{"source":"1116","target":"1114","id":"5934"},{"source":"1712","target":"293","id":"6592"},{"source":"153","target":"155","id":"2231"},{"source":"1012","target":"65","id":"5571"},{"source":"434","target":"544","id":"942"},{"source":"1561","target":"433","id":"6507"},{"source":"793","target":"61","id":"2963"},{"source":"707","target":"568","id":"1631"},{"source":"1387","target":"1389","id":"4354"},{"source":"506","target":"405","id":"842"},{"source":"1406","target":"301","id":"4477"},{"source":"1001","target":"607","id":"2548"},{"source":"781","target":"65","id":"2783"},{"source":"422","target":"424","id":"695"},{"source":"254","target":"256","id":"296"},{"source":"193","target":"195","id":"221"},{"source":"276","target":"270","id":"6586"},{"source":"665","target":"667","id":"1330"},{"source":"515","target":"53","id":"1168"},{"source":"1081","target":"477","id":"2852"},{"source":"574","target":"51","id":"1060"},{"source":"271","target":"276","id":"4329"},{"source":"366","target":"104","id":"5458"},{"source":"891","target":"79","id":"2116"},{"source":"858","target":"76","id":"5060"},{"source":"1466","target":"568","id":"4838"},{"source":"748","target":"533","id":"3787"},{"source":"789","target":"632","id":"3032"},{"source":"1225","target":"33","id":"3828"},{"source":"1299","target":"1301","id":"3879"},{"source":"557","target":"76","id":"1008"},{"source":"1099","target":"79","id":"2948"},{"source":"1652","target":"109","id":"6184"},{"source":"864","target":"867","id":"2013"},{"source":"611","target":"222","id":"1173"},{"source":"219","target":"292","id":"446"},{"source":"811","target":"53","id":"1804"},{"source":"858","target":"498","id":"5061"},{"source":"1442","target":"1","id":"6443"},{"source":"270","target":"273","id":"413"},{"source":"1459","target":"49","id":"4806"},{"source":"412","target":"1025","id":"2646"},{"source":"1351","target":"171","id":"4161"},{"source":"941","target":"12","id":"6577"},{"source":"1478","target":"25","id":"4961"},{"source":"337","target":"119","id":"510"},{"source":"286","target":"648","id":"3719"},{"source":"1656","target":"246","id":"6198"},{"source":"1644","target":"1266","id":"6126"},{"source":"639","target":"106","id":"1260"},{"source":"1215","target":"596","id":"3491"},{"source":"812","target":"110","id":"5412"},{"source":"112","target":"115","id":"116"},{"source":"271","target":"270","id":"4324"},{"source":"128","target":"82","id":"138"},{"source":"873","target":"104","id":"2057"},{"source":"1019","target":"1020","id":"2614"},{"source":"1269","target":"1079","id":"3752"},{"source":"533","target":"537","id":"6086"},{"source":"723","target":"361","id":"1481"},{"source":"1182","target":"199","id":"3339"},{"source":"1540","target":"1124","id":"5307"},{"source":"1589","target":"65","id":"5709"},{"source":"1351","target":"1046","id":"4162"},{"source":"451","target":"93","id":"745"},{"source":"1131","target":"541","id":"3069"},{"source":"708","target":"707","id":"2871"},{"source":"1423","target":"1235","id":"4588"},{"source":"1623","target":"238","id":"5987"},{"source":"552","target":"50","id":"4887"},{"source":"119","target":"50","id":"3173"},{"source":"966","target":"1415","id":"5820"},{"source":"1063","target":"1","id":"4302"},{"source":"204","target":"208","id":"236"},{"source":"265","target":"264","id":"1898"},{"source":"222","target":"1","id":"248"},{"source":"802","target":"803","id":"1768"},{"source":"1013","target":"177","id":"3024"},{"source":"510","target":"53","id":"6335"},{"source":"1578","target":"53","id":"5623"},{"source":"550","target":"131","id":"965"},{"source":"60","target":"62","id":"55"},{"source":"1428","target":"847","id":"4615"},{"source":"586","target":"1","id":"1092"},{"source":"706","target":"85","id":"1429"},{"source":"246","target":"68","id":"2640"},{"source":"399","target":"400","id":"650"},{"source":"1532","target":"1533","id":"5280"},{"source":"769","target":"771","id":"1636"},{"source":"824","target":"1169","id":"3267"},{"source":"296","target":"318","id":"428"},{"source":"1391","target":"1116","id":"4370"},{"source":"1465","target":"498","id":"4835"},{"source":"549","target":"177","id":"1275"},{"source":"955","target":"49","id":"2420"},{"source":"1122","target":"1123","id":"3046"},{"source":"1468","target":"784","id":"4861"},{"source":"442","target":"447","id":"723"},{"source":"60","target":"50","id":"62"},{"source":"1122","target":"280","id":"3042"},{"source":"1313","target":"1314","id":"3952"},{"source":"105","target":"93","id":"5383"},{"source":"454","target":"287","id":"753"},{"source":"1410","target":"1556","id":"6579"},{"source":"831","target":"76","id":"2877"},{"source":"748","target":"747","id":"3785"},{"source":"1178","target":"1179","id":"3302"},{"source":"51","target":"513","id":"5580"},{"source":"1403","target":"1404","id":"4445"},{"source":"289","target":"119","id":"3721"},{"source":"1212","target":"774","id":"3479"},{"source":"62","target":"65","id":"980"},{"source":"865","target":"436","id":"2291"},{"source":"1550","target":"65","id":"5377"},{"source":"1550","target":"918","id":"5379"},{"source":"1427","target":"752","id":"4608"},{"source":"116","target":"373","id":"6511"},{"source":"214","target":"128","id":"241"},{"source":"269","target":"194","id":"336"},{"source":"306","target":"219","id":"453"},{"source":"1228","target":"5","id":"3580"},{"source":"229","target":"230","id":"260"},{"source":"337","target":"338","id":"511"},{"source":"203","target":"185","id":"738"},{"source":"884","target":"444","id":"2099"},{"source":"415","target":"979","id":"3641"},{"source":"36","target":"38","id":"439"},{"source":"1100","target":"1093","id":"2955"},{"source":"1406","target":"1357","id":"4476"},{"source":"971","target":"296","id":"2476"},{"source":"1580","target":"1292","id":"5651"},{"source":"1690","target":"1691","id":"6419"},{"source":"625","target":"79","id":"1208"},{"source":"358","target":"177","id":"549"},{"source":"1287","target":"348","id":"4620"},{"source":"1493","target":"50","id":"5055"},{"source":"1505","target":"254","id":"5112"},{"source":"1277","target":"748","id":"3794"},{"source":"314","target":"295","id":"422"},{"source":"937","target":"938","id":"2343"},{"source":"748","target":"536","id":"3791"},{"source":"1304","target":"310","id":"3903"},{"source":"407","target":"408","id":"666"},{"source":"822","target":"409","id":"6265"},{"source":"1648","target":"166","id":"6140"},{"source":"1222","target":"312","id":"3534"},{"source":"759","target":"109","id":"5776"},{"source":"840","target":"841","id":"1914"},{"source":"813","target":"96","id":"1811"},{"source":"1674","target":"68","id":"6316"},{"source":"447","target":"498","id":"1010"},{"source":"1312","target":"322","id":"3935"},{"source":"1207","target":"732","id":"3459"},{"source":"1168","target":"351","id":"3260"},{"source":"1075","target":"724","id":"3461"},{"source":"1556","target":"967","id":"5430"},{"source":"1591","target":"567","id":"5731"},{"source":"416","target":"296","id":"3663"},{"source":"308","target":"359","id":"568"},{"source":"844","target":"154","id":"1926"},{"source":"541","target":"702","id":"2743"},{"source":"737","target":"738","id":"1533"},{"source":"789","target":"409","id":"3036"},{"source":"460","target":"65","id":"1165"},{"source":"273","target":"271","id":"5567"},{"source":"597","target":"114","id":"1142"},{"source":"682","target":"641","id":"6169"},{"source":"290","target":"62","id":"1851"},{"source":"1423","target":"1425","id":"4587"},{"source":"716","target":"710","id":"1450"},{"source":"1509","target":"182","id":"5196"},{"source":"1041","target":"65","id":"2707"},{"source":"218","target":"219","id":"246"},{"source":"1141","target":"281","id":"3092"},{"source":"452","target":"93","id":"2278"},{"source":"1689","target":"675","id":"6409"},{"source":"1667","target":"215","id":"6276"},{"source":"1514","target":"1515","id":"5220"},{"source":"760","target":"576","id":"1611"},{"source":"1470","target":"53","id":"4900"},{"source":"905","target":"79","id":"2218"},{"source":"332","target":"149","id":"4387"},{"source":"527","target":"523","id":"3546"},{"source":"838","target":"259","id":"2453"},{"source":"1285","target":"513","id":"3817"},{"source":"63","target":"61","id":"992"},{"source":"848","target":"211","id":"1945"},{"source":"1191","target":"1192","id":"3401"},{"source":"822","target":"798","id":"6267"},{"source":"880","target":"576","id":"2083"},{"source":"672","target":"64","id":"5404"},{"source":"812","target":"111","id":"5414"},{"source":"993","target":"996","id":"4528"},{"source":"781","target":"924","id":"2786"},{"source":"1359","target":"259","id":"4194"},{"source":"1470","target":"287","id":"4903"},{"source":"300","target":"177","id":"3010"},{"source":"1405","target":"626","id":"4455"},{"source":"629","target":"324","id":"2681"},{"source":"1346","target":"246","id":"4124"},{"source":"1706","target":"495","id":"6525"},{"source":"1657","target":"287","id":"6204"},{"source":"1435","target":"175","id":"4699"},{"source":"417","target":"297","id":"4465"},{"source":"1172","target":"431","id":"3274"},{"source":"756","target":"607","id":"1602"},{"source":"1256","target":"82","id":"3655"},{"source":"1280","target":"833","id":"3800"},{"source":"973","target":"974","id":"2478"},{"source":"1477","target":"1","id":"4936"},{"source":"875","target":"858","id":"2062"},{"source":"1672","target":"1295","id":"6297"},{"source":"694","target":"281","id":"1402"},{"source":"190","target":"191","id":"2528"},{"source":"495","target":"1706","id":"6522"},{"source":"345","target":"347","id":"526"},{"source":"1293","target":"513","id":"3845"},{"source":"582","target":"576","id":"4713"},{"source":"365","target":"438","id":"1338"},{"source":"1124","target":"1272","id":"4845"},{"source":"1416","target":"325","id":"4550"},{"source":"1052","target":"491","id":"2770"},{"source":"339","target":"1056","id":"4204"},{"source":"1348","target":"161","id":"4138"},{"source":"13","target":"1","id":"15"},{"source":"352","target":"355","id":"538"},{"source":"70","target":"72","id":"2491"},{"source":"826","target":"312","id":"5361"},{"source":"1499","target":"174","id":"5091"},{"source":"806","target":"600","id":"6056"},{"source":"1156","target":"216","id":"3157"},{"source":"753","target":"638","id":"5129"},{"source":"394","target":"216","id":"4927"},{"source":"1366","target":"1367","id":"4249"},{"source":"1352","target":"453","id":"4164"},{"source":"1632","target":"281","id":"6049"},{"source":"424","target":"656","id":"4941"},{"source":"1649","target":"82","id":"6149"},{"source":"303","target":"296","id":"389"},{"source":"624","target":"897","id":"2146"},{"source":"581","target":"498","id":"4182"},{"source":"755","target":"312","id":"1595"},{"source":"1412","target":"1404","id":"4525"},{"source":"553","target":"64","id":"986"},{"source":"50","target":"104","id":"5473"},{"source":"12","target":"1","id":"4388"},{"source":"400","target":"137","id":"2390"},{"source":"1102","target":"79","id":"3498"},{"source":"1199","target":"1200","id":"3440"},{"source":"640","target":"161","id":"5320"},{"source":"1446","target":"976","id":"4731"},{"source":"269","target":"270","id":"332"},{"source":"35","target":"40","id":"417"},{"source":"654","target":"606","id":"3420"},{"source":"579","target":"82","id":"6002"},{"source":"269","target":"40","id":"337"},{"source":"672","target":"65","id":"5405"},{"source":"895","target":"53","id":"2136"},{"source":"1667","target":"76","id":"6273"},{"source":"865","target":"287","id":"2293"},{"source":"329","target":"310","id":"3239"},{"source":"1015","target":"736","id":"3681"},{"source":"1497","target":"76","id":"5082"},{"source":"712","target":"85","id":"2035"},{"source":"1058","target":"1059","id":"2780"},{"source":"914","target":"109","id":"2251"},{"source":"1435","target":"437","id":"4701"},{"source":"441","target":"713","id":"4379"},{"source":"405","target":"49","id":"2934"},{"source":"946","target":"947","id":"2379"},{"source":"516","target":"323","id":"892"},{"source":"892","target":"79","id":"5141"},{"source":"1684","target":"886","id":"6388"},{"source":"1035","target":"206","id":"2685"},{"source":"1520","target":"1521","id":"5248"},{"source":"1397","target":"710","id":"4409"},{"source":"965","target":"95","id":"2441"},{"source":"369","target":"370","id":"577"},{"source":"1591","target":"131","id":"5727"},{"source":"955","target":"280","id":"2422"},{"source":"979","target":"1028","id":"2655"},{"source":"1704","target":"313","id":"6528"},{"source":"1305","target":"182","id":"4577"},{"source":"1360","target":"408","id":"6656"},{"source":"99","target":"141","id":"160"},{"source":"178","target":"300","id":"1245"},{"source":"424","target":"1","id":"4940"},{"source":"465","target":"79","id":"951"},{"source":"914","target":"253","id":"2243"},{"source":"1271","target":"484","id":"3756"},{"source":"248","target":"53","id":"5348"},{"source":"1119","target":"50","id":"6259"},{"source":"975","target":"938","id":"2488"},{"source":"1391","target":"1114","id":"4367"},{"source":"953","target":"952","id":"2413"},{"source":"364","target":"49","id":"584"},{"source":"1431","target":"1395","id":"4671"},{"source":"1529","target":"33","id":"5272"},{"source":"1536","target":"53","id":"5284"},{"source":"1664","target":"470","id":"6250"},{"source":"1703","target":"79","id":"6492"},{"source":"354","target":"166","id":"1146"},{"source":"688","target":"693","id":"1657"},{"source":"1291","target":"585","id":"5642"},{"source":"484","target":"334","id":"5592"},{"source":"358","target":"362","id":"552"},{"source":"1639","target":"1379","id":"6092"},{"source":"1074","target":"1078","id":"2843"},{"source":"1576","target":"1319","id":"5611"}],"nodes":[{"label":"Sciences De La Terre","x":1412.2230224609375,"y":-2.055976390838623,"id":"262","color":"rgb(255,204,102)","size":8.540210723876953},{"label":"Champ","x":-933.5524291992188,"y":239.07545471191406,"id":"586","color":"rgb(255,51,51)","size":4.0},{"label":"Chaîne Trophique","x":1256.1710205078125,"y":-1671.3907470703125,"id":"580","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"Kilometre Carre","x":173.3579559326172,"y":-567.8416137695312,"id":"1015","color":"rgb(102,255,102)","size":5.103478908538818},{"label":"Catastrophe Naturelle","x":1467.9786376953125,"y":-1406.437744140625,"id":"25","color":"rgb(102,102,0)","size":5.6738481521606445},{"label":"Planet In Peril","x":-675.910400390625,"y":744.3154296875,"id":"1491","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Glacial Period","x":-271.1141662597656,"y":1832.915283203125,"id":"1098","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Gaz Parfait","x":2628.283447265625,"y":-645.1771240234375,"id":"541","color":"rgb(255,255,51)","size":5.103478908538818},{"label":"Sable Bitumineux","x":-52.610496520996094,"y":-1401.718994140625,"id":"1327","color":"rgb(0,153,0)","size":4.6399359703063965},{"label":"Anwr Drilling","x":-2627.632080078125,"y":915.7081298828125,"id":"274","color":"rgb(102,0,102)","size":4.936610698699951},{"label":"Science Center","x":785.2101440429688,"y":399.9143371582031,"id":"1323","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Polycristal","x":2375.138671875,"y":-291.7706298828125,"id":"1520","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Droit","x":-345.1713562011719,"y":-1826.0067138671875,"id":"842","color":"rgb(153,0,0)","size":4.0},{"label":"Mammifères Marins","x":-273.3992614746094,"y":-1182.143798828125,"id":"1318","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Energie Marine","x":761.4014892578125,"y":-970.1514892578125,"id":"726","color":"rgb(0,153,0)","size":4.293514728546143},{"label":"Vent Geostrophique","x":1671.5755615234375,"y":-254.51400756835938,"id":"1561","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Organisme Vivant","x":1507.45263671875,"y":-1434.38671875,"id":"582","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Polluant Secondaire","x":1457.781982421875,"y":-1268.886474609375,"id":"1513","color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Limite Des 200 Miles Marins","x":-33.31745529174805,"y":-699.0526123046875,"id":"1294","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Pollution Prevention","x":-1377.6392822265625,"y":713.9226684570312,"id":"1518","color":"rgb(102,102,0)","size":4.075808525085449},{"label":"Satellite Orbit","x":231.1543426513672,"y":2578.50390625,"id":"1130","color":"rgb(255,153,153)","size":4.293514728546143},{"label":"Oil Field","x":-2092.7724609375,"y":969.78466796875,"id":"450","color":"rgb(102,0,102)","size":4.206028938293457},{"label":"Océan Arctique","x":28.159622192382812,"y":-147.4086151123047,"id":"48","color":"rgb(0,204,204)","size":32.935298919677734},{"label":"Mesures Conservatoires Et Compensatoires","x":201.2974395751953,"y":-654.922607421875,"id":"1346","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Oiseau Marin","x":-78.5789566040039,"y":-1023.541015625,"id":"983","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"Banquise Permanente","x":46.569725036621094,"y":10.34594440460205,"id":"410","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Installations Classées","x":1222.58544921875,"y":-2058.860107421875,"id":"948","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"Acide Éthanoïque","x":2378.265625,"y":-1083.8045654296875,"id":"90","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Situation Anticyclonique","x":1643.440185546875,"y":-1384.404052734375,"id":"1633","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Judd Gregg","x":-1378.9903564453125,"y":1433.5750732421875,"id":"1463","color":"rgb(0,204,204)","size":4.0},{"label":"Pole Airship","x":213.51223754882812,"y":28.755355834960938,"id":"398","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Estuaires","x":917.8259887695312,"y":-1474.0455322265625,"id":"943","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Norwegian Oil","x":-2236.421142578125,"y":960.3920288085938,"id":"1404","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Yukon River","x":-1329.87548828125,"y":869.7622680664062,"id":"1717","color":"rgb(153,0,0)","size":4.206028938293457},{"label":"Technologie Gmbh","x":1799.05419921875,"y":-276.313232421875,"id":"1666","color":"rgb(255,255,51)","size":4.0},{"label":"Air Quality","x":-1209.4488525390625,"y":1061.2088623046875,"id":"162","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Nord Géographique","x":456.9866027832031,"y":508.9895935058594,"id":"47","color":"rgb(153,255,255)","size":6.584775924682617},{"label":"Gaz Parfaits","x":2766.4443359375,"y":-772.1646728515625,"id":"1048","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Glaciers Of Iceland","x":-1106.13330078125,"y":1600.585693359375,"id":"1103","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Equivalent Co2","x":350.8734436035156,"y":-349.5634765625,"id":"452","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Fonds Côtiers","x":408.5318603515625,"y":-1242.9537353515625,"id":"1004","color":"rgb(0,153,0)","size":4.39528751373291},{"label":"Groupe Pétrolier","x":-405.83056640625,"y":-1606.5108642578125,"id":"606","color":"rgb(102,0,102)","size":5.103478908538818},{"label":"Arctic National Wildlife Refuge","x":-2764.014404296875,"y":976.0181884765625,"id":"35","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Port Ouest","x":-511.3980407714844,"y":-1958.8724365234375,"id":"1524","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Gaz Carbonique","x":1104.385498046875,"y":-792.3753051757812,"id":"67","color":"rgb(102,255,102)","size":9.501245498657227},{"label":"Ice Records","x":-147.54861450195312,"y":1719.7235107421875,"id":"329","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Chauffage Solaire","x":1274.2322998046875,"y":-937.2332763671875,"id":"597","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Bouclier Canadien","x":309.83795166015625,"y":-842.7721557617188,"id":"496","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Aperture Radar","x":411.4226379394531,"y":864.9448852539062,"id":"810","color":"rgb(153,255,255)","size":4.0086140632629395},{"label":"Hydrate De Méthane","x":503.4374694824219,"y":-844.715576171875,"id":"1161","color":"rgb(0,153,0)","size":4.6399359703063965},{"label":"Sibérie","x":-367.50750732421875,"y":-766.07080078125,"id":"1632","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Refuge To Oil","x":-2698.738037109375,"y":874.7493286132812,"id":"273","color":"rgb(102,0,102)","size":4.781970500946045},{"label":"Ressources Vivantes","x":774.3036499023438,"y":-1410.3544921875,"id":"1594","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Unique Plateau Continental","x":-320.9755859375,"y":-1846.307861328125,"id":"1697","color":"rgb(153,0,0)","size":4.0},{"label":"Oil Companies","x":-2245.361328125,"y":813.8052978515625,"id":"272","color":"rgb(102,0,102)","size":6.584775924682617},{"label":"Crépuscule Nautique","x":1977.38623046875,"y":-1353.287353515625,"id":"737","color":"rgb(255,255,51)","size":4.0},{"label":"Ice News","x":42.22573471069336,"y":1851.931884765625,"id":"1422","color":"rgb(153,255,255)","size":4.0},{"label":"Admiral Scheer","x":-1439.79736328125,"y":2020.9342041015625,"id":"419","color":"rgb(0,204,204)","size":4.0},{"label":"Ligne De Champ","x":446.68719482421875,"y":556.0613403320312,"id":"1293","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Systeme Meteo","x":2142.0986328125,"y":-530.1538696289062,"id":"1541","color":"rgb(255,204,102)","size":4.0},{"label":"Identité Collective","x":957.6539306640625,"y":-1371.41162109375,"id":"1169","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Highest Mountain","x":-1436.0623779296875,"y":2075.27001953125,"id":"57","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Acidification Des Océans","x":949.3548583984375,"y":-771.9315185546875,"id":"92","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Cape Dorset","x":-1116.916748046875,"y":1553.179931640625,"id":"525","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Quantités D\u0027Eau,1","x":561.6199951171875,"y":-1561.1962890625,"id":"1555","attributes":{"nodedef":"n1555"},"color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Wally Herbert","x":-971.27978515625,"y":1483.9224853515625,"id":"1709","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Aleutian Island","x":-599.6304931640625,"y":307.56365966796875,"id":"198","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Science De La Nature","x":1429.4813232421875,"y":-375.6391906738281,"id":"261","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"King Haakon","x":-664.6025390625,"y":2235.445556640625,"id":"1030","color":"rgb(0,204,204)","size":4.0},{"label":"Oao Gazprom","x":-2060.773681640625,"y":549.4484252929688,"id":"1053","color":"rgb(102,0,102)","size":4.206028938293457},{"label":"Calotte Glaciaire","x":591.7031860351562,"y":-123.89764404296875,"id":"61","color":"rgb(153,255,255)","size":19.1311092376709},{"label":"Rétroaction Positive","x":987.7084350585938,"y":-480.2536315917969,"id":"52","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Parc National","x":-282.4018249511719,"y":-606.8483276367188,"id":"170","color":"rgb(153,255,0)","size":8.235326766967773},{"label":"Lynx","x":-1016.044921875,"y":2644.493896484375,"id":"1310","color":"rgb(0,204,204)","size":4.0},{"label":"Nanisivik Mine","x":-1148.0731201171875,"y":1985.365234375,"id":"1378","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Courants Marins Chauds","x":341.8601379394531,"y":-261.7185974121094,"id":"727","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Discover North","x":-1485.690673828125,"y":1784.274658203125,"id":"818","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Sous-Marins","x":-590.5049438476562,"y":-1314.688720703125,"id":"1645","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Science \u0026 Vie","x":1182.782958984375,"y":280.2792053222656,"id":"1111","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Genetic Resources","x":783.1207885742188,"y":-1739.42529296875,"id":"1538","color":"rgb(153,255,0)","size":4.0},{"label":"Fjords Tours","x":-1812.889892578125,"y":1720.9605712890625,"id":"997","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Satellite Image","x":301.9154357910156,"y":2138.177978515625,"id":"1083","color":"rgb(255,153,153)","size":4.781970500946045},{"label":"Grand Nord","x":-362.91522216796875,"y":-256.2770080566406,"id":"281","color":"rgb(0,204,204)","size":18.676555633544922},{"label":"Yves Delorme","x":-3590.7666015625,"y":-1715.421875,"id":"1682","color":"rgb(51,153,255)","size":4.0},{"label":"Russie Unie","x":-901.9271850585938,"y":-1313.946533203125,"id":"825","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Gaz Naturel","x":29.68891716003418,"y":-1422.890625,"id":"567","color":"rgb(0,153,0)","size":13.54262924194336},{"label":"Intérêts Économiques","x":136.60568237304688,"y":-1761.73779296875,"id":"1214","color":"rgb(153,0,0)","size":4.133297443389893},{"label":"Île Aux Ours","x":-216.5255584716797,"y":-281.82208251953125,"id":"1173","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Russian Mig","x":-3845.65625,"y":-1035.047607421875,"id":"1602","color":"rgb(255,51,51)","size":4.0},{"label":"Physique Des Particules","x":1444.818359375,"y":-100.17031860351562,"id":"1003","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Loup Arctique","x":-200.24407958984375,"y":-220.78904724121094,"id":"483","color":"rgb(153,255,0)","size":4.781970500946045},{"label":"1831","x":-1042.585693359375,"y":278.2547302246094,"id":"0","color":"rgb(255,51,51)","size":4.0},{"label":"Carbon Dioxide","x":-509.6867370605469,"y":1153.4713134765625,"id":"177","color":"rgb(102,255,102)","size":14.764718055725098},{"label":"Sheila Watt","x":-922.7695922851562,"y":1962.31884765625,"id":"619","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Agriculture Durable","x":891.6155395507812,"y":-1680.5008544921875,"id":"156","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Agence Spatiale","x":938.8359985351562,"y":420.05511474609375,"id":"133","color":"rgb(255,153,153)","size":5.472443103790283},{"label":"Wildlife Fund","x":-428.5501403808594,"y":976.4503173828125,"id":"1711","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Bilan Carbone","x":755.95556640625,"y":-1098.6580810546875,"id":"451","color":"rgb(102,255,102)","size":5.472443103790283},{"label":"Planetary Orbit","x":-131.3832550048828,"y":2532.2919921875,"id":"1476","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Reserve Petroliere","x":-578.7444458007812,"y":-1032.4029541015625,"id":"1008","color":"rgb(102,0,102)","size":4.293514728546143},{"label":"Commission Européenne","x":401.4253845214844,"y":-1512.4029541015625,"id":"84","color":"rgb(255,51,51)","size":5.472443103790283},{"label":"Institut Camille Jordan","x":1339.658447265625,"y":381.1823425292969,"id":"1566","color":"rgb(255,255,51)","size":4.0},{"label":"Passage International","x":-1377.7752685546875,"y":155.49526977539062,"id":"1460","color":"rgb(255,51,51)","size":4.0},{"label":"Institutes Of Technology","x":1001.623779296875,"y":1100.98046875,"id":"777","color":"rgb(255,153,153)","size":4.075808525085449},{"label":"Générations Futures","x":451.8046875,"y":-1203.6495361328125,"id":"781","color":"rgb(102,255,102)","size":5.103478908538818},{"label":"Nunavik","x":-1306.2196044921875,"y":2811.482666015625,"id":"1423","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Coopération Internationale","x":115.85001373291016,"y":-1025.172119140625,"id":"722","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Bulles De Gaz Emprisonnées","x":1125.7774658203125,"y":-525.71630859375,"id":"509","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Universite De Montreal","x":1673.3009033203125,"y":47.932456970214844,"id":"1698","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Cambridge Bay","x":-1225.4501953125,"y":1317.5401611328125,"id":"516","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Circumpolar Conference","x":-1056.1627197265625,"y":2054.598388671875,"id":"617","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Lacs Sous-Glaciaires","x":758.4376220703125,"y":347.21270751953125,"id":"1269","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Bilan Environnemental","x":824.1160888671875,"y":-1392.2030029296875,"id":"252","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Durablement Pollué","x":748.7852783203125,"y":-2095.647216796875,"id":"845","color":"rgb(102,102,0)","size":4.075808525085449},{"label":"Écosystèmes","x":600.8551635742188,"y":-1271.76513671875,"id":"881","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Metre Cube","x":177.89779663085938,"y":-1657.566162109375,"id":"428","color":"rgb(102,0,102)","size":4.781970500946045},{"label":"Global Surveyor","x":1119.8714599609375,"y":647.7386474609375,"id":"863","color":"rgb(255,153,153)","size":4.075808525085449},{"label":"Archives Du Climat","x":939.9533081054688,"y":-416.38031005859375,"id":"288","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Protection De La Nature","x":646.8939819335938,"y":-1496.78466796875,"id":"458","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"Europe Du Nord","x":-820.3291015625,"y":-818.375732421875,"id":"388","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Plan De Prévention Des Risques","x":1789.16943359375,"y":-1745.5433349609375,"id":"30","color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Détroit De Nares","x":69.19367980957031,"y":211.30694580078125,"id":"809","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Bateau De Pêche","x":410.1282653808594,"y":-1891.766845703125,"id":"439","color":"rgb(153,0,0)","size":4.39528751373291},{"label":"Developpement Humain","x":235.37948608398438,"y":-1622.2196044921875,"id":"813","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Perte De Glace","x":430.07354736328125,"y":-328.2873229980469,"id":"1471","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Magnetic Field","x":-23.518125534057617,"y":1376.1861572265625,"id":"372","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Coûts Supplémentaires","x":713.3629150390625,"y":-1702.53173828125,"id":"734","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Régions Polaires","x":291.6045227050781,"y":183.0286865234375,"id":"1575","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Condensat De Bose-Einstein","x":1717.8370361328125,"y":83.28048706054688,"id":"673","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Commission Océanographique Intergouvernementale","x":443.1557922363281,"y":-590.3914184570312,"id":"651","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"American Geophysical","x":13.97448444366455,"y":896.5333862304688,"id":"223","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Richard Weber","x":-271.6991882324219,"y":1477.3450927734375,"id":"500","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Degree Fahrenheit","x":792.5369262695312,"y":2364.6083984375,"id":"74","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Earth System","x":-33.12626266479492,"y":1281.72265625,"id":"361","color":"rgb(255,255,51)","size":5.282204627990723},{"label":"Arctique Canadien","x":-34.037384033203125,"y":-42.725345611572266,"id":"279","color":"rgb(0,204,204)","size":10.882965087890625},{"label":"Déchets","x":591.4802856445312,"y":-2255.109375,"id":"773","color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Yukon Quest","x":-1212.327392578125,"y":21.756004333496094,"id":"1142","color":"rgb(153,0,0)","size":4.133297443389893},{"label":"Constante Des Gaz Parfaits","x":2765.376220703125,"y":-746.6752319335938,"id":"701","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Absolute Zero","x":1101.5811767578125,"y":2339.88916015625,"id":"69","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Grand Port","x":-558.8419799804688,"y":-1775.0401611328125,"id":"1123","color":"rgb(153,0,0)","size":4.293514728546143},{"label":"Voyages Et Aventures Du Capitaine Hatteras","x":223.48948669433594,"y":467.0993347167969,"id":"1708","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Midnight Sun","x":-1395.9552001953125,"y":2051.304931640625,"id":"297","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Mer D\u0027Okhotsk,1","x":-401.33245849609375,"y":-1031.172607421875,"id":"1343","attributes":{"nodedef":"n1343"},"color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Lost Planet","x":1539.6019287109375,"y":-854.0687866210938,"id":"678","color":"rgb(255,204,102)","size":4.0},{"label":"Dérèglements Climatiques","x":1019.9054565429688,"y":-1099.6612548828125,"id":"794","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Reseau Trophique","x":1108.49365234375,"y":-1649.361083984375,"id":"578","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"Communaute Scientifique","x":1391.388427734375,"y":-517.110595703125,"id":"258","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Longue Distance","x":-1891.9310302734375,"y":-955.7990112304688,"id":"981","color":"rgb(204,204,255)","size":4.0340681076049805},{"label":"Igloos","x":-1043.2408447265625,"y":2237.484130859375,"id":"1170","color":"rgb(204,204,255)","size":4.0340681076049805},{"label":"Navigation Company","x":245.43983459472656,"y":3486.531005859375,"id":"1392","color":"rgb(255,255,51)","size":4.0},{"label":"Helge Sander","x":-371.4839172363281,"y":2118.072265625,"id":"343","color":"rgb(0,204,204)","size":4.0},{"label":"Station Météorologique","x":1818.5457763671875,"y":-736.021240234375,"id":"682","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Croisiere Arctique","x":-612.6448364257812,"y":42.875667572021484,"id":"741","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Territoire Arctique Canadien","x":-549.2730712890625,"y":-191.093994140625,"id":"1676","color":"rgb(0,204,204)","size":4.0},{"label":"Geophysique Appliquee","x":1942.337890625,"y":539.9500732421875,"id":"1073","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Richesses Maritimes","x":291.574951171875,"y":-1910.2333984375,"id":"1601","color":"rgb(153,0,0)","size":4.206028938293457},{"label":"Plante Aquatique","x":1285.7686767578125,"y":-1453.8092041015625,"id":"858","color":"rgb(153,255,0)","size":4.781970500946045},{"label":"Network Of Centres Of Excellence","x":-875.6000366210938,"y":1464.3062744140625,"id":"332","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"International Arctic","x":-707.1710205078125,"y":1718.787353515625,"id":"315","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Bay Alaska","x":-2304.918701171875,"y":1538.0584716796875,"id":"448","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Combustible Fossile","x":815.3712768554688,"y":-1225.1680908203125,"id":"118","color":"rgb(0,153,0)","size":8.852968215942383},{"label":"Ferdinand De Lesseps","x":-239.18646240234375,"y":-2538.10498046875,"id":"530","color":"rgb(204,0,0)","size":4.0086140632629395},{"label":"Pingos","x":-436.329345703125,"y":1763.2047119140625,"id":"1487","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"South Iceland","x":-1511.5205078125,"y":1666.0196533203125,"id":"1646","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Fisheries Research","x":-505.2409362792969,"y":896.1464233398438,"id":"488","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Gaz De France","x":-273.7169189453125,"y":-1318.034423828125,"id":"1042","color":"rgb(102,0,102)","size":4.6399359703063965},{"label":"European Energy","x":-1345.869384765625,"y":931.9912719726562,"id":"950","color":"rgb(0,153,0)","size":4.0340681076049805},{"label":"Energie Nucléaire","x":263.9258117675781,"y":-1404.858154296875,"id":"569","color":"rgb(0,153,0)","size":5.282204627990723},{"label":"Navire De Pêche","x":111.64442443847656,"y":-1903.831787109375,"id":"441","color":"rgb(153,0,0)","size":4.6399359703063965},{"label":"Union Internationale","x":569.4212036132812,"y":-953.427490234375,"id":"698","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Air Humide","x":1812.0146484375,"y":-450.9634094238281,"id":"160","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Space Agency","x":827.9591064453125,"y":867.1500854492188,"id":"140","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Recherche","x":1645.1668701171875,"y":-853.490478515625,"id":"1562","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Circum-Arctic Resource Appraisal","x":-1417.8199462890625,"y":1346.6717529296875,"id":"612","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Voyage Au Cap","x":-850.92626953125,"y":-287.2585144042969,"id":"534","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"National Weather","x":49.27556228637695,"y":2100.6494140625,"id":"367","color":"rgb(255,255,51)","size":4.781970500946045},{"label":"National Oceanic","x":155.75376892089844,"y":1900.197998046875,"id":"309","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Fonte Annuelle","x":364.8657531738281,"y":-123.84783935546875,"id":"1011","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Indigènes Inuit","x":225.49862670898438,"y":-419.7015686035156,"id":"1194","color":"rgb(204,204,255)","size":4.510906219482422},{"label":"Fusee Ariane","x":944.4932861328125,"y":925.226318359375,"id":"572","color":"rgb(255,153,153)","size":4.0340681076049805},{"label":"Commission For Refugees","x":-626.1370239257812,"y":2209.29736328125,"id":"1028","color":"rgb(0,204,204)","size":4.0},{"label":"Mayen Islands","x":-1624.634521484375,"y":2166.725830078125,"id":"1239","color":"rgb(0,204,204)","size":4.0},{"label":"Maree Noire","x":-99.39531707763672,"y":-1763.42578125,"id":"1164","color":"rgb(102,0,102)","size":4.133297443389893},{"label":"Condensats","x":1507.54150390625,"y":-204.82220458984375,"id":"676","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Physical Oceanography","x":402.76641845703125,"y":1244.8629150390625,"id":"1482","color":"rgb(255,204,102)","size":4.0},{"label":"Nunavut","x":-1353.854248046875,"y":1785.6558837890625,"id":"1426","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Intérêt Stratégique","x":364.9102783203125,"y":-1361.624755859375,"id":"1211","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Solstices","x":-400.19305419921875,"y":2067.84814453125,"id":"1642","color":"rgb(0,204,204)","size":4.0},{"label":"Environnement Canada","x":1323.092041015625,"y":-917.3856201171875,"id":"106","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Convention Des Nations","x":-272.1719970703125,"y":-1238.3597412109375,"id":"715","color":"rgb(255,51,51)","size":4.781970500946045},{"label":"Securite Alimentaire","x":379.0228576660156,"y":-1565.291259765625,"id":"579","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Filet De Pêche","x":292.838623046875,"y":-1705.7376708984375,"id":"982","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"Sami Language","x":-1942.499267578125,"y":2512.8349609375,"id":"1248","color":"rgb(204,204,255)","size":5.282204627990723},{"label":"Une Vérité Qui Dérange","x":269.528076171875,"y":-395.56805419921875,"id":"1696","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Niveau Trophique","x":1112.0208740234375,"y":-1626.6505126953125,"id":"577","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"August Peterman","x":47.598548889160156,"y":969.8030395507812,"id":"369","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Recherche Fondamentale","x":1382.326416015625,"y":-1028.606689453125,"id":"1567","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Samoyèdes","x":-1532.1046142578125,"y":-832.3033447265625,"id":"1611","color":"rgb(204,204,255)","size":4.075808525085449},{"label":"Cryosphère","x":-141.69094848632812,"y":1432.79052734375,"id":"755","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Arctic Explorer","x":-793.9893188476562,"y":1843.285400390625,"id":"303","color":"rgb(0,204,204)","size":4.936610698699951},{"label":"Satellite Navigation","x":234.13194274902344,"y":3367.627197265625,"id":"1116","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Instrument Scientifique","x":1140.2447509765625,"y":245.36618041992188,"id":"666","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Océan Glacial Arctique","x":75.3579330444336,"y":-222.08584594726562,"id":"538","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Recherche Française","x":1463.2591552734375,"y":-942.5368041992188,"id":"1568","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Plan De Prevention","x":1853.248291015625,"y":-1832.4892578125,"id":"28","color":"rgb(102,102,0)","size":4.206028938293457},{"label":"Institut Des Sciences","x":1449.68994140625,"y":-269.876708984375,"id":"1204","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Submersible Mir","x":51.21259307861328,"y":1336.3157958984375,"id":"1653","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Lemming","x":-974.2824096679688,"y":1868.3739013671875,"id":"1288","color":"rgb(0,204,204)","size":4.0},{"label":"Lumière Solaire","x":1415.5977783203125,"y":-1074.5252685546875,"id":"1309","color":"rgb(255,255,51)","size":4.0},{"label":"Baleine Bleue","x":30.028717041015625,"y":-1047.228759765625,"id":"390","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Aire Marine Protégée","x":291.7319641113281,"y":-1383.3349609375,"id":"169","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Sommet De La Terre","x":279.6936950683594,"y":-981.5819702148438,"id":"689","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Archipel Arctique","x":-255.59234619140625,"y":73.05978393554688,"id":"42","color":"rgb(0,204,204)","size":5.886096477508545},{"label":"Global Average Temperature","x":49.35322189331055,"y":1719.8236083984375,"id":"1108","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"High Altitude","x":-772.4302978515625,"y":2072.1865234375,"id":"56","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Érosion Des Sols","x":1110.46728515625,"y":-1435.0150146484375,"id":"929","color":"rgb(153,255,0)","size":4.6399359703063965},{"label":"Lappland","x":-1614.2547607421875,"y":1686.1014404296875,"id":"1278","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Capelan","x":-967.8992309570312,"y":324.8018798828125,"id":"542","color":"rgb(255,51,51)","size":4.0},{"label":"National Institute","x":885.5368041992188,"y":763.1171264648438,"id":"16","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Fibre Optique","x":-2214.43505859375,"y":-1087.89404296875,"id":"18","color":"rgb(204,204,255)","size":4.133297443389893},{"label":"Institut De Recherche Agronomique","x":1479.1070556640625,"y":-675.8849487304688,"id":"1203","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Polar Bear","x":-248.04136657714844,"y":1112.631103515625,"id":"1451","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Esperance De Vie","x":-203.37042236328125,"y":-1382.83740234375,"id":"127","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Glace Pérenne","x":331.8544921875,"y":6.469234466552734,"id":"1092","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Préoccupations Environnementales","x":913.7150268554688,"y":-1516.5771484375,"id":"1536","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Théorie Erronée De La Mer Polaire Libre De Glace","x":265.0186767578125,"y":744.8469848632812,"id":"1677","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"1927","x":-1194.3721923828125,"y":423.0043029785156,"id":"6","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Organisation Nations Unies","x":-482.8285217285156,"y":-142.87576293945312,"id":"1441","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Geostationary Operational","x":284.5367126464844,"y":2251.43701171875,"id":"912","color":"rgb(255,153,153)","size":4.39528751373291},{"label":"Très Basses Températures","x":1497.54736328125,"y":285.4104309082031,"id":"1689","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Arctic Region","x":-918.8540649414062,"y":1732.8306884765625,"id":"219","color":"rgb(0,204,204)","size":7.9385457038879395},{"label":"Gas Condensate","x":-1892.72509765625,"y":856.7564086914062,"id":"1033","color":"rgb(102,0,102)","size":4.206028938293457},{"label":"Courant Marin","x":597.963623046875,"y":-437.8042297363281,"id":"607","color":"rgb(255,204,102)","size":8.852968215942383},{"label":"North Cape","x":-1306.5689697265625,"y":2003.2337646484375,"id":"1314","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Sciences Santé","x":1610.7698974609375,"y":-138.92054748535156,"id":"1623","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Tonje Folkestad","x":-297.1965026855469,"y":995.9053344726562,"id":"1678","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Coastal Zone","x":-57.49678421020508,"y":1147.275634765625,"id":"443","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Interactions Air-Neige","x":1003.8515014648438,"y":267.47943115234375,"id":"1209","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Eaux Intérieures","x":254.67762756347656,"y":-1601.257568359375,"id":"868","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Earth Observation","x":476.53277587890625,"y":1206.121337890625,"id":"752","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Activité Solaire","x":1019.194091796875,"y":-65.51429748535156,"id":"112","color":"rgb(255,255,51)","size":4.781970500946045},{"label":"Arctic Ocean","x":-858.7642211914062,"y":1760.1708984375,"id":"296","color":"rgb(0,204,204)","size":18.676555633544922},{"label":"1958","x":-923.1117553710938,"y":300.51910400390625,"id":"9","color":"rgb(255,51,51)","size":4.0},{"label":"Energy Technology","x":-1174.175537109375,"y":1211.6539306640625,"id":"907","color":"rgb(0,153,0)","size":4.206028938293457},{"label":"Mare Island","x":-1608.9420166015625,"y":172.58163452148438,"id":"1229","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Pergélisol","x":611.0936279296875,"y":-347.7278747558594,"id":"1468","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Prévision Météorologique","x":1674.5135498046875,"y":-759.5797119140625,"id":"640","color":"rgb(255,204,102)","size":4.781970500946045},{"label":"Volume Molaire","x":2573.265625,"y":-778.6514282226562,"id":"704","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Canadian Hydrographic","x":185.7216339111328,"y":1505.6448974609375,"id":"446","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Dépôts Rocheux","x":1134.8359375,"y":-416.6546325683594,"id":"792","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Nature Bassin","x":1054.341552734375,"y":-1553.7513427734375,"id":"1023","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Ressource Naturelle","x":372.7302551269531,"y":-1337.694580078125,"id":"109","color":"rgb(0,153,0)","size":23.853513717651367},{"label":"Affaires Étrangères","x":-416.64178466796875,"y":-1388.5225830078125,"id":"128","color":"rgb(255,51,51)","size":11.244990348815918},{"label":"Test Ban","x":-1156.66259765625,"y":-132.11866760253906,"id":"962","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Pêche Lac","x":1041.0244140625,"y":-1170.6361083984375,"id":"1465","color":"rgb(153,255,0)","size":4.0},{"label":"Genie Mecanique","x":2703.232666015625,"y":428.4504699707031,"id":"663","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Observatoire De Greenwich","x":1127.2589111328125,"y":-137.82998657226562,"id":"1287","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Boreogadus Saida","x":-415.00299072265625,"y":0.7784530520439148,"id":"487","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Perte De Sol","x":990.3416748046875,"y":-1785.65185546875,"id":"1472","color":"rgb(102,102,0)","size":4.510906219482422},{"label":"Engrais Chimique","x":1442.54638671875,"y":-1840.012939453125,"id":"153","color":"rgb(102,102,0)","size":4.510906219482422},{"label":"Creation De Valeur","x":-144.18275451660156,"y":-1219.799072265625,"id":"1668","color":"rgb(153,255,0)","size":4.0},{"label":"Prise De Conscience","x":391.77239990234375,"y":-1272.17529296875,"id":"924","color":"rgb(0,153,0)","size":4.39528751373291},{"label":"Urss","x":-1082.490478515625,"y":-1814.544189453125,"id":"31","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Eaux De Fonte","x":775.5789794921875,"y":-394.23291015625,"id":"864","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Reaction Chimique","x":1998.379638671875,"y":-1139.310546875,"id":"897","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Brent Boddy","x":-57.53631591796875,"y":991.5533447265625,"id":"499","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Bruno Peyron","x":-96.83160400390625,"y":-66.97936248779297,"id":"356","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Bris De Glace","x":-51.48553466796875,"y":-200.6317138671875,"id":"280","color":"rgb(0,204,204)","size":9.501245498657227},{"label":"Gestion Des Risques","x":1580.8740234375,"y":-1767.4342041015625,"id":"26","color":"rgb(102,102,0)","size":4.510906219482422},{"label":"Frappes Nucléaires","x":-1311.4027099609375,"y":-464.2800598144531,"id":"1024","color":"rgb(255,51,51)","size":4.0},{"label":"Northern Norway","x":-1513.88427734375,"y":1940.5718994140625,"id":"1152","color":"rgb(0,204,204)","size":5.282204627990723},{"label":"Ocean Engineering","x":863.1543579101562,"y":1605.9718017578125,"id":"565","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Bas Niveau","x":-377.101806640625,"y":94.28236389160156,"id":"432","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Fjord Du Saguenay","x":-808.0360717773438,"y":63.18717575073242,"id":"994","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Natural Sciences","x":785.9993286132812,"y":268.3930358886719,"id":"1386","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Laboratoire De Géologie","x":1599.014892578125,"y":-225.34234619140625,"id":"954","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Souveraineté Limitée","x":-436.36474609375,"y":-1584.6697998046875,"id":"1649","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Eau Salée","x":1287.019775390625,"y":-803.0387573242188,"id":"817","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"1978","x":-1086.7376708984375,"y":282.59967041015625,"id":"11","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Cercle Polaire Arctique","x":-257.4226989746094,"y":114.5979995727539,"id":"574","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Hazardous Waste","x":-1165.3197021484375,"y":117.11734771728516,"id":"959","color":"rgb(102,102,0)","size":4.206028938293457},{"label":"Dechet Dangereux","x":573.1505126953125,"y":-2150.138916015625,"id":"707","color":"rgb(102,102,0)","size":4.936610698699951},{"label":"Nature Photography","x":-1234.7947998046875,"y":1187.2357177734375,"id":"1389","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Effect Of Global Warming","x":-253.63299560546875,"y":1540.568359375,"id":"894","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"United Nations","x":-440.61810302734375,"y":156.68453979492188,"id":"1442","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Ecole Polytechnique","x":2021.11474609375,"y":174.77450561523438,"id":"646","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Regime Alimentaire","x":198.74391174316406,"y":-1272.209228515625,"id":"585","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Biosphere Programme","x":-750.0748291015625,"y":1525.2879638671875,"id":"476","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Prévisions Météo","x":1819.6859130859375,"y":-586.1161499023438,"id":"641","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Aléoutiennes","x":-82.33863067626953,"y":-485.130859375,"id":"197","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Chien De Traineau","x":-721.9819946289062,"y":-527.147216796875,"id":"600","color":"rgb(204,204,255)","size":5.6738481521606445},{"label":"Norvège Du Nord","x":-686.24169921875,"y":-355.7278747558594,"id":"1125","color":"rgb(153,0,0)","size":4.6399359703063965},{"label":"Intérêts Stratégiques","x":-436.1466369628906,"y":-1513.074462890625,"id":"1216","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Wood Mackenzie","x":-1887.30224609375,"y":604.39013671875,"id":"1713","color":"rgb(102,0,102)","size":4.206028938293457},{"label":"Alexei Miller","x":-1747.8853759765625,"y":243.88377380371094,"id":"204","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Environmental Protection","x":-1113.230712890625,"y":872.4547119140625,"id":"163","color":"rgb(102,255,102)","size":5.282204627990723},{"label":"National Maladies Rares","x":1955.45361328125,"y":-838.8698120117188,"id":"1546","color":"rgb(255,204,102)","size":4.0},{"label":"Solar Energy","x":-1137.634521484375,"y":1279.6405029296875,"id":"909","color":"rgb(0,153,0)","size":4.0086140632629395},{"label":"Pollution","x":-1426.6656494140625,"y":951.9179077148438,"id":"1514","color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Plate-Formes Offshore","x":-85.44915008544922,"y":-1274.136962890625,"id":"1499","color":"rgb(102,0,102)","size":4.39528751373291},{"label":"Atmosphere Composition","x":-530.412841796875,"y":1407.7283935546875,"id":"359","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Missile Balistique","x":71.72400665283203,"y":-676.071533203125,"id":"494","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Union Européenne","x":77.16728973388672,"y":-1303.923583984375,"id":"82","color":"rgb(255,51,51)","size":44.51482391357422},{"label":"Glacial Outwash","x":-459.3403015136719,"y":1557.467529296875,"id":"1096","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Flux Zonal","x":1283.772705078125,"y":-80.11326599121094,"id":"1001","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Boreal Forest","x":-945.212158203125,"y":2200.774169921875,"id":"471","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Nouvelle-Zemble","x":-201.8921661376953,"y":-571.7731323242188,"id":"1420","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Plantes Vertes","x":1396.9930419921875,"y":-1724.7591552734375,"id":"584","color":"rgb(102,102,0)","size":4.0340681076049805},{"label":"Pays Balte","x":-659.1566772460938,"y":-1289.7989501953125,"id":"1126","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Soil Salinity","x":-605.7926025390625,"y":1008.748291015625,"id":"1609","color":"rgb(255,204,102)","size":4.0},{"label":"Mammifere Marin","x":-95.50175476074219,"y":-1201.1683349609375,"id":"391","color":"rgb(153,255,0)","size":6.837328910827637},{"label":"Masse Glaciaire","x":649.7149658203125,"y":-186.74403381347656,"id":"1325","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Global Concern Expedition","x":519.5447998046875,"y":990.1395263671875,"id":"1110","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Global Exploration","x":797.335205078125,"y":1284.910400390625,"id":"1112","color":"rgb(255,153,153)","size":4.0340681076049805},{"label":"Geographic Traveler","x":-1745.7501220703125,"y":1280.5291748046875,"id":"1067","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Living Organism","x":-918.6689453125,"y":959.650390625,"id":"464","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Anomalie Magnétique","x":1387.6629638671875,"y":-146.3898162841797,"id":"263","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"-4200 M","x":-1213.0836181640625,"y":2295.2705078125,"id":"54","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Anwr Oil","x":-2581.248291015625,"y":955.8977661132812,"id":"269","color":"rgb(102,0,102)","size":4.781970500946045},{"label":"Ours Polaire","x":-157.55242919921875,"y":-308.56231689453125,"id":"334","color":"rgb(153,255,0)","size":10.178449630737305},{"label":"Pole Magnetique","x":679.227294921875,"y":556.8468627929688,"id":"374","color":"rgb(153,255,255)","size":6.341859817504883},{"label":"Gabriel Wackermann","x":-87.75955963134766,"y":-1859.6141357421875,"id":"1496","color":"rgb(153,0,0)","size":4.0},{"label":"Aptenodytes Forsteri","x":289.0431823730469,"y":919.851318359375,"id":"277","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Periode Interglaciaire","x":1033.8819580078125,"y":-503.2251281738281,"id":"552","color":"rgb(255,255,51)","size":5.472443103790283},{"label":"Nature Chimique","x":2002.038818359375,"y":-1090.4591064453125,"id":"1390","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Températures Globales","x":1006.1412963867188,"y":-671.974365234375,"id":"1675","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Diversite Culturelle","x":605.7864379882812,"y":-1663.8399658203125,"id":"823","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Giec","x":722.7131958007812,"y":-586.2316284179688,"id":"1086","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Vatnajokull Glacier","x":-1299.3758544921875,"y":1628.77099609375,"id":"1703","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Transformations","x":-1208.724853515625,"y":282.80255126953125,"id":"1685","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Recit De Voyage","x":-683.7840576171875,"y":-572.9569091796875,"id":"1231","color":"rgb(204,204,255)","size":4.075808525085449},{"label":"Carte Marine","x":812.1536865234375,"y":13.741379737854004,"id":"233","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Composition Chimique","x":1572.0687255859375,"y":-1048.61572265625,"id":"365","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Degre Celsius","x":1432.5145263671875,"y":-311.01776123046875,"id":"512","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Grand Dauphin","x":-79.85520935058594,"y":-1255.1279296875,"id":"1133","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Degree Celsius","x":960.0056762695312,"y":2435.82666015625,"id":"73","color":"rgb(255,255,51)","size":4.781970500946045},{"label":"Courants Marins Froids","x":-207.296875,"y":-879.0455932617188,"id":"729","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Convention De Varsovie","x":180.90830993652344,"y":-913.2974853515625,"id":"683","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Fjord Horse","x":-1878.0020751953125,"y":1849.91552734375,"id":"995","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Glaciation","x":-235.29949951171875,"y":1871.2613525390625,"id":"1101","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"National Wildlife Refuge","x":-2618.724853515625,"y":814.0955200195312,"id":"271","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Chiens","x":-889.0441284179688,"y":-568.3861694335938,"id":"601","color":"rgb(204,204,255)","size":4.0},{"label":"Liquide De Refroidissement","x":2370.32861328125,"y":-649.3900756835938,"id":"1295","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Bœuf Musqué","x":-256.10687255859375,"y":-330.9064636230469,"id":"481","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Television Show","x":-941.4266967773438,"y":282.9108581542969,"id":"1669","color":"rgb(255,51,51)","size":4.0},{"label":"Adverse Event","x":-2619.889404296875,"y":-152.8070068359375,"id":"124","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Objectifs Du Millénaire","x":117.25886535644531,"y":-1529.2181396484375,"id":"247","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Alliage Métallique","x":2378.687744140625,"y":-330.806884765625,"id":"213","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Active Volcano","x":-1640.16650390625,"y":2000.4835205078125,"id":"1238","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Grandes Rousses","x":885.4703369140625,"y":-186.6187744140625,"id":"932","color":"rgb(255,204,102)","size":4.0},{"label":"Golfe De Finlande","x":-689.8905029296875,"y":-991.0733642578125,"id":"987","color":"rgb(255,51,51)","size":4.6399359703063965},{"label":"Geographic Video","x":-1619.5887451171875,"y":1215.6246337890625,"id":"1068","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Secteur Pétrolier","x":-364.1715393066406,"y":-1760.04833984375,"id":"657","color":"rgb(102,0,102)","size":4.781970500946045},{"label":"Ratification","x":-507.1439514160156,"y":-315.71282958984375,"id":"1558","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Péninsule Scandinave","x":-769.4072875976562,"y":-756.4035034179688,"id":"1124","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Gazprom","x":-1937.9300537109375,"y":468.28424072265625,"id":"1052","color":"rgb(102,0,102)","size":4.39528751373291},{"label":"Écologisme","x":721.4150390625,"y":-1248.9193115234375,"id":"878","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Periode Geologique","x":1184.9498291015625,"y":-223.36912536621094,"id":"594","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Ocean Pacifique","x":-188.73233032226562,"y":-531.0193481445312,"id":"200","color":"rgb(255,51,51)","size":5.6738481521606445},{"label":"Weather Services","x":-132.76998901367188,"y":2149.054443359375,"id":"899","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Plateau Continental En Arctique","x":-45.741153717041016,"y":-1658.357666015625,"id":"1495","color":"rgb(102,0,102)","size":4.0340681076049805},{"label":"Symboliquement Planté","x":-807.3521728515625,"y":-263.1263732910156,"id":"1660","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Insel Seeland","x":-1842.103271484375,"y":-1701.308349609375,"id":"764","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Souveraineté","x":-172.32069396972656,"y":-1680.070556640625,"id":"1647","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Base De Donnée","x":1301.830322265625,"y":-1226.973876953125,"id":"76","color":"rgb(255,255,51)","size":14.764718055725098},{"label":"Kalaallit Nunaat","x":-749.01806640625,"y":1343.0867919921875,"id":"1146","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Subarctique","x":184.04832458496094,"y":-753.6328125,"id":"1652","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Hydrocarbure Aromatique","x":1017.660400390625,"y":-1741.5787353515625,"id":"378","color":"rgb(102,102,0)","size":4.6399359703063965},{"label":"Planification Strategique","x":613.8388061523438,"y":-1836.17822265625,"id":"1190","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Mbep/J","x":-463.3499450683594,"y":-1650.888427734375,"id":"1326","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Pack","x":-1091.357666015625,"y":216.81724548339844,"id":"1453","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Classification Périodique","x":1661.9716796875,"y":-1525.0955810546875,"id":"623","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Mission Arctique","x":307.9113464355469,"y":-306.6958923339844,"id":"339","color":"rgb(153,255,255)","size":5.6738481521606445},{"label":"Temperature Record","x":-120.6404037475586,"y":1793.9925537109375,"id":"1572","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Courant Océanique","x":835.2644653320312,"y":-451.4788513183594,"id":"608","color":"rgb(255,204,102)","size":5.6738481521606445},{"label":"Yamal","x":-776.9039916992188,"y":2286.57568359375,"id":"1715","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Russian Jet","x":-3853.128662109375,"y":-1009.4136352539062,"id":"1603","color":"rgb(255,51,51)","size":4.0},{"label":"Conflits","x":-460.0719299316406,"y":-1356.5899658203125,"id":"691","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Bilan De Masse Glaciaire","x":794.037841796875,"y":-204.70335388183594,"id":"454","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Aire De Répartition","x":88.43418884277344,"y":-981.20361328125,"id":"165","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Engrais Azoté","x":1342.5379638671875,"y":-1752.6905517578125,"id":"242","color":"rgb(102,102,0)","size":4.206028938293457},{"label":"Natural Resources Commission","x":-1613.603515625,"y":98.33975982666016,"id":"1370","color":"rgb(0,153,0)","size":4.0},{"label":"Déformations","x":194.17935180664062,"y":1320.2796630859375,"id":"775","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Climat Polaire","x":235.52413940429688,"y":-184.31378173828125,"id":"634","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Dechet Radioactif","x":325.6799011230469,"y":-1643.284912109375,"id":"568","color":"rgb(102,102,0)","size":5.6738481521606445},{"label":"Programme Des Nations Unies","x":85.97142028808594,"y":-1140.53759765625,"id":"248","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Érosion Glaciaire","x":742.3344116210938,"y":-350.19073486328125,"id":"931","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Évolution Des Galaxies","x":1633.125244140625,"y":-54.933509826660156,"id":"952","color":"rgb(255,153,153)","size":4.0340681076049805},{"label":"Drapeau De La Russie","x":-15.412890434265137,"y":-559.6062622070312,"id":"837","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Analyse De Sol","x":1482.62353515625,"y":-1745.756591796875,"id":"240","color":"rgb(102,102,0)","size":4.133297443389893},{"label":"Rayon Solaire","x":1197.6590576171875,"y":-457.2544860839844,"id":"728","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Law Of The Sea","x":-1015.6412353515625,"y":-235.204833984375,"id":"960","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Indices","x":-935.016845703125,"y":261.6860046386719,"id":"1193","color":"rgb(255,51,51)","size":4.0},{"label":"Climate Change","x":574.4462280273438,"y":-244.7993621826172,"id":"591","color":"rgb(102,255,102)","size":5.472443103790283},{"label":"Dioxyde De Carbone","x":1076.9239501953125,"y":-838.5778198242188,"id":"64","color":"rgb(102,255,102)","size":12.75397777557373},{"label":"Carottes De Glace","x":1182.79248046875,"y":-605.17724609375,"id":"553","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Wentworth Higginson","x":-1183.2293701171875,"y":240.41905212402344,"id":"941","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Produit Chimique","x":1520.8070068359375,"y":-1546.7008056640625,"id":"155","color":"rgb(102,102,0)","size":4.781970500946045},{"label":"Iles Pribilof","x":-198.6033172607422,"y":-740.008056640625,"id":"1182","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Photographies","x":1839.8797607421875,"y":-1381.5904541015625,"id":"1481","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Planète","x":1200.0296630859375,"y":-768.0518798828125,"id":"1492","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Cooperative Institute For Research","x":97.84896850585938,"y":1591.988037109375,"id":"723","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Natural Histories","x":-456.4294738769531,"y":770.5518798828125,"id":"974","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Compréhension Du Système Climatique","x":801.6995849609375,"y":-861.987060546875,"id":"670","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Alaska Halibut","x":-3062.091064453125,"y":2551.033447265625,"id":"187","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Température Ambiante","x":2132.640380859375,"y":-386.3600158691406,"id":"87","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"International Airports","x":-1742.007568359375,"y":1980.4854736328125,"id":"221","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Polar Foundation","x":-108.2223892211914,"y":1356.49560546875,"id":"184","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"New York","x":-752.0060424804688,"y":236.44363403320312,"id":"1","color":"rgb(255,51,51)","size":64.35166931152344},{"label":"Empreinte Génétique","x":476.001220703125,"y":-2566.525634765625,"id":"1533","color":"rgb(102,102,0)","size":4.0},{"label":"Norwegian Ministry","x":-2301.88037109375,"y":2535.718017578125,"id":"1200","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Tara Arctic","x":236.50755310058594,"y":-119.65736389160156,"id":"1119","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Action Climat","x":754.18310546875,"y":-991.233154296875,"id":"102","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Basse Pression","x":1899.7237548828125,"y":-507.6459655761719,"id":"433","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Changement Climatique Global","x":604.3817138671875,"y":-524.1521606445312,"id":"593","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Recherche Sciences","x":1627.426025390625,"y":-399.2071838378906,"id":"1547","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Gps Navigation","x":194.82525634765625,"y":3389.077392578125,"id":"1114","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Port Maritime","x":-610.5924072265625,"y":-1976.65283203125,"id":"1137","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"1002 Area","x":-2678.666748046875,"y":995.836181640625,"id":"34","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Exploration Well","x":-2312.6064453125,"y":836.2626953125,"id":"968","color":"rgb(102,0,102)","size":4.0086140632629395},{"label":"Pression Atmosphérique","x":1988.022705078125,"y":-564.9814453125,"id":"161","color":"rgb(255,204,102)","size":6.108868598937988},{"label":"Mendeleïev","x":1611.185546875,"y":-1567.342529296875,"id":"1333","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Safe Passage","x":-1208.8505859375,"y":156.23768615722656,"id":"1461","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Fjords Of Norway","x":-1889.8212890625,"y":1917.4227294921875,"id":"996","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Leonid Brejnev","x":-732.2546997070312,"y":-1650.6351318359375,"id":"1225","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"James Forbes","x":636.195068359375,"y":258.57037353515625,"id":"667","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Recherche Aux Pôles","x":1176.76513671875,"y":222.73812866210938,"id":"1563","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Iles Lofoten","x":-813.2720947265625,"y":-402.7174377441406,"id":"537","color":"rgb(0,204,204)","size":5.472443103790283},{"label":"Glouton","x":-295.9211730957031,"y":-747.9576416015625,"id":"1118","color":"rgb(153,255,0)","size":4.0},{"label":"Geographic World","x":-1738.5836181640625,"y":1237.1822509765625,"id":"1069","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Magnetic Pole","x":-61.151405334472656,"y":1537.1751708984375,"id":"621","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"1937","x":-922.0673828125,"y":217.56393432617188,"id":"8","color":"rgb(255,51,51)","size":4.0},{"label":"Polar Research","x":-226.88523864746094,"y":1496.3126220703125,"id":"325","color":"rgb(153,255,255)","size":5.282204627990723},{"label":"Record Minimum","x":-48.43122100830078,"y":1773.6942138671875,"id":"1571","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Information Géographique","x":1652.8824462890625,"y":-1207.1824951171875,"id":"556","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"East Siberian","x":-1020.4994506835938,"y":2079.242431640625,"id":"855","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Carotte De Glace","x":1005.4568481445312,"y":-244.7089080810547,"id":"62","color":"rgb(153,255,255)","size":9.173389434814453},{"label":"Migrations","x":-1498.015380859375,"y":1193.9449462890625,"id":"1354","color":"rgb(153,255,0)","size":4.0},{"label":"Upper Atmosphere","x":-290.42523193359375,"y":1562.1124267578125,"id":"362","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Agence Internationale","x":101.9319076538086,"y":-1183.8203125,"id":"130","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Transport Logistique","x":1128.3056640625,"y":-2616.636474609375,"id":"1302","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Océanographie","x":928.886474609375,"y":-164.4426727294922,"id":"1431","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Will Steger","x":-630.0276489257812,"y":1798.4930419921875,"id":"1712","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Bleriot Xi","x":-598.3441772460938,"y":282.5133361816406,"id":"43","color":"rgb(0,204,204)","size":4.0},{"label":"Geodetic Surveying","x":212.71829223632812,"y":2365.78125,"id":"776","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Décennie","x":-988.4039916992188,"y":118.36727142333984,"id":"767","color":"rgb(255,51,51)","size":4.0},{"label":"American Scientist","x":-1284.3760986328125,"y":988.1171264648438,"id":"227","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Champ Magnetique Terrestre","x":617.023681640625,"y":604.7554321289062,"id":"587","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Cambrien Moyen","x":503.5157775878906,"y":-911.0304565429688,"id":"518","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Systèmes Glaciaires","x":985.3449096679688,"y":154.50323486328125,"id":"1663","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Iceberg","x":-545.5053100585938,"y":1385.1671142578125,"id":"1167","color":"rgb(153,255,255)","size":4.0086140632629395},{"label":"Intérêts Défensifs","x":-12.911566734313965,"y":-1922.81103515625,"id":"1212","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Mode De Vie","x":-115.59657287597656,"y":-940.325927734375,"id":"111","color":"rgb(153,255,0)","size":6.584775924682617},{"label":"Zone Économique Exclusive","x":-199.3349609375,"y":-1561.9595947265625,"id":"714","color":"rgb(153,0,0)","size":5.103478908538818},{"label":"Dmitri Medvedev","x":-749.7711791992188,"y":-1404.799560546875,"id":"493","color":"rgb(255,51,51)","size":4.510906219482422},{"label":"Océans","x":-448.6255798339844,"y":1364.870849609375,"id":"1433","color":"rgb(102,255,102)","size":4.0},{"label":"Périodes Interglaciaires","x":978.1617431640625,"y":-603.2879638671875,"id":"1470","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Observation Satellite","x":633.9613647460938,"y":1304.4700927734375,"id":"1428","color":"rgb(255,153,153)","size":4.293514728546143},{"label":"Cellule Photovoltaïque","x":1573.73876953125,"y":-920.066650390625,"id":"560","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Glacial Moraine","x":-745.0570068359375,"y":1737.6048583984375,"id":"1095","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Natural World","x":-595.7034912109375,"y":788.1918334960938,"id":"1385","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Hemisphere Nord","x":822.0599975585938,"y":-116.0876235961914,"id":"119","color":"rgb(255,204,102)","size":11.244990348815918},{"label":"Droit Humain","x":59.45440673828125,"y":-1219.3333740234375,"id":"234","color":"rgb(255,51,51)","size":4.510906219482422},{"label":"American University","x":-607.4078979492188,"y":865.6720581054688,"id":"228","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Exploitation Des Richesses","x":311.64801025390625,"y":-1837.4033203125,"id":"965","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Gisement De Chtokman","x":-769.5961303710938,"y":-1157.606689453125,"id":"605","color":"rgb(102,0,102)","size":4.39528751373291},{"label":"Innovation Norway","x":-2335.32470703125,"y":2176.70068359375,"id":"1199","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Deh Cho","x":-1856.7294921875,"y":1537.44580078125,"id":"785","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Environnement","x":453.2809753417969,"y":-992.4443969726562,"id":"914","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Mecanique Des Roches","x":2446.5673828125,"y":373.1225280761719,"id":"1330","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Arctic Refuge","x":-2631.31884765625,"y":850.3453979492188,"id":"36","color":"rgb(153,255,0)","size":5.6738481521606445},{"label":"Grande Odyssée","x":-984.5294189453125,"y":-365.6311340332031,"id":"1141","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Polar Ice","x":-110.7434310913086,"y":1699.8232421875,"id":"753","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Bathymétrie","x":324.61383056640625,"y":767.0276489257812,"id":"442","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Fondation Polaire Internationale","x":551.2457275390625,"y":51.95774841308594,"id":"893","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Recherche Scientifique","x":1442.5101318359375,"y":-540.7030029296875,"id":"571","color":"rgb(255,204,102)","size":5.472443103790283},{"label":"Géophysique","x":1632.0228271484375,"y":628.3880615234375,"id":"1071","color":"rgb(255,204,51)","size":4.206028938293457},{"label":"Gravures","x":-1026.744873046875,"y":137.02943420410156,"id":"1143","color":"rgb(255,51,51)","size":4.0},{"label":"Déchet Industriel","x":657.5604248046875,"y":-2385.392578125,"id":"769","color":"rgb(102,102,0)","size":4.781970500946045},{"label":"Ice Hotel","x":-593.0064697265625,"y":1885.76708984375,"id":"1090","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Île De Gotland","x":-846.1076049804688,"y":-999.18359375,"id":"1174","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Geologic Province","x":-994.019775390625,"y":1189.9840087890625,"id":"614","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Séracs","x":-1662.7349853515625,"y":1545.182373046875,"id":"1630","color":"rgb(0,204,204)","size":4.0},{"label":"1969","x":-1062.8043212890625,"y":419.4639892578125,"id":"10","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Propulsion Nucléaire","x":-385.1502380371094,"y":-1260.037353515625,"id":"1177","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Norwegian Navy","x":-569.5661010742188,"y":2063.767822265625,"id":"1415","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Sammy Davis","x":-1078.1158447265625,"y":156.47669982910156,"id":"1454","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Institut Océanographique","x":463.5839538574219,"y":81.99915313720703,"id":"1206","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Hausse Des Prix","x":-333.2700500488281,"y":-1539.107666015625,"id":"423","color":"rgb(153,0,0)","size":4.39528751373291},{"label":"Technologies Modernes","x":-32.22397232055664,"y":-1066.8753662109375,"id":"1667","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Haute Pression","x":1766.5191650390625,"y":-1061.0745849609375,"id":"435","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Film Documentaire","x":-155.1978302001953,"y":52.95424270629883,"id":"1057","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Onu","x":-1233.36279296875,"y":135.1965789794922,"id":"1436","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Polar Star","x":-1302.835205078125,"y":952.3133544921875,"id":"742","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Superficie","x":49.51503372192383,"y":-587.6513061523438,"id":"1655","color":"rgb(255,51,51)","size":4.0},{"label":"Reserve Naturelle","x":434.63714599609375,"y":-1621.7032470703125,"id":"697","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Eau Froide","x":1541.7825927734375,"y":-1092.912109375,"id":"816","color":"rgb(255,204,102)","size":4.936610698699951},{"label":"Delta De La Léna","x":289.7749938964844,"y":-542.6483154296875,"id":"788","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Netherlands Institute","x":278.0394592285156,"y":488.0981140136719,"id":"1396","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Pcgr Du Canada","x":-597.6290893554688,"y":-1740.4219970703125,"id":"1367","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Lomonosov Ridge","x":-466.1482849121094,"y":1429.583984375,"id":"319","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Expédition Arctique","x":-198.63258361816406,"y":-88.86698913574219,"id":"955","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Renne Caribou","x":458.2775573730469,"y":-1139.828125,"id":"1583","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Polar Bridge","x":-403.4349670410156,"y":1495.7833251953125,"id":"1505","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Arcticnet","x":-643.3875122070312,"y":1682.5628662109375,"id":"330","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Alaska","x":-3098.02685546875,"y":2507.338134765625,"id":"186","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Climate Variation","x":-198.80438232421875,"y":1270.0087890625,"id":"637","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Aurora Borealis","x":-896.8470458984375,"y":1434.7862548828125,"id":"371","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Puits De Carbone","x":949.2518310546875,"y":-967.28125,"id":"672","color":"rgb(0,153,0)","size":4.6399359703063965},{"label":"Gas Pipeline","x":-2079.5126953125,"y":693.8248291015625,"id":"206","color":"rgb(102,0,102)","size":7.370260715484619},{"label":"Gel","x":-3475.97705078125,"y":-1943.2325439453125,"id":"1058","color":"rgb(51,153,255)","size":4.0},{"label":"Sciences Naturelles","x":1289.0399169921875,"y":-203.2497100830078,"id":"1621","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Aurore Boréale","x":-38.54255294799805,"y":154.39012145996094,"id":"364","color":"rgb(0,204,204)","size":6.584775924682617},{"label":"Marine Canadienne","x":-901.2643432617188,"y":-2052.479248046875,"id":"1320","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Inconvenient Truth","x":-316.84161376953125,"y":893.7084350585938,"id":"179","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Croissance Démographique","x":656.6221313476562,"y":-1804.153076171875,"id":"644","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Écosystème","x":971.4881591796875,"y":-1275.459716796875,"id":"880","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Geographic Adventure","x":-1713.5594482421875,"y":1303.010986328125,"id":"1061","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Achim Steiner","x":75.6333999633789,"y":264.43115234375,"id":"88","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Erosion Marine","x":-82.82237243652344,"y":629.181884765625,"id":"933","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"1893","x":-1061.2469482421875,"y":260.2148132324219,"id":"2","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Élément Nutritif","x":1147.1973876953125,"y":-1708.31396484375,"id":"241","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Ice Sheet","x":-148.8400115966797,"y":1680.135009765625,"id":"312","color":"rgb(153,255,255)","size":9.836332321166992},{"label":"Cryosat 2","x":55.193878173828125,"y":1549.1031494140625,"id":"750","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Natural Gas Liquids","x":-2024.284423828125,"y":879.7984008789062,"id":"615","color":"rgb(102,0,102)","size":4.075808525085449},{"label":"Iouri Andropov","x":-750.6943359375,"y":-1591.2652587890625,"id":"1224","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Risques Naturels","x":1759.55419921875,"y":-1789.48095703125,"id":"22","color":"rgb(102,102,0)","size":4.39528751373291},{"label":"Séquestration Co2","x":-801.0259399414062,"y":1199.588134765625,"id":"1629","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"North Slope","x":-2024.936767578125,"y":924.9051513671875,"id":"194","color":"rgb(102,0,102)","size":4.39528751373291},{"label":"Polar Science","x":-132.6469268798828,"y":1475.8482666015625,"id":"892","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Fonte Des Glaces","x":459.58941650390625,"y":-200.27076721191406,"id":"66","color":"rgb(102,255,102)","size":13.145594596862793},{"label":"Global Warning","x":-243.81764221191406,"y":967.8666381835938,"id":"1117","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Ile Victoria","x":-490.3682861328125,"y":177.11434936523438,"id":"1179","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Centre Spatial","x":876.1445922851562,"y":616.9332275390625,"id":"135","color":"rgb(255,153,153)","size":4.39528751373291},{"label":"Physique Theorique","x":1881.3311767578125,"y":108.39909362792969,"id":"1202","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Politique","x":-5.994494438171387,"y":-1563.6400146484375,"id":"1511","color":"rgb(255,51,51)","size":4.0},{"label":"Essai Historique","x":-1157.0037841796875,"y":177.75860595703125,"id":"940","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Groenland","x":-331.8370056152344,"y":792.9080200195312,"id":"1145","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Droit International","x":-258.4610595703125,"y":-1630.45166015625,"id":"85","color":"rgb(255,51,51)","size":7.9385457038879395},{"label":"Science Physique","x":2234.972412109375,"y":52.56838607788086,"id":"1622","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Institute Of Meteorology","x":954.8125610351562,"y":784.3052368164062,"id":"1208","color":"rgb(255,204,102)","size":4.0340681076049805},{"label":"Faible Superficie","x":261.7717590332031,"y":-143.9561309814453,"id":"977","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Glacial Erosion","x":-193.4502410888672,"y":1852.1458740234375,"id":"1093","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Milieu Aquatique","x":1167.759765625,"y":-1534.117919921875,"id":"581","color":"rgb(153,255,0)","size":4.781970500946045},{"label":"Degre Centigrade","x":849.8101806640625,"y":-506.2597961425781,"id":"784","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"International Energy","x":-1331.1221923828125,"y":1015.0953979492188,"id":"908","color":"rgb(0,153,0)","size":4.293514728546143},{"label":"East Oil","x":-1742.295654296875,"y":576.974609375,"id":"854","color":"rgb(102,0,102)","size":4.0340681076049805},{"label":"Chaîne Logistique","x":1199.179931640625,"y":-2594.193359375,"id":"1300","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Conseil De L\u0027Arctique,1","x":-84.26390075683594,"y":-507.35498046875,"id":"694","attributes":{"nodedef":"n694"},"color":"rgb(255,51,51)","size":4.6399359703063965},{"label":"Scandinavian Peninsula","x":-1889.73388671875,"y":2102.25634765625,"id":"1283","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Alaska Salmon","x":-3059.961669921875,"y":2481.27099609375,"id":"188","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Universités Canadiennes","x":526.4083251953125,"y":102.38640594482422,"id":"386","color":"rgb(153,255,255)","size":4.0086140632629395},{"label":"National Geographic Society","x":-1637.8243408203125,"y":1171.7003173828125,"id":"1063","color":"rgb(153,255,0)","size":4.6399359703063965},{"label":"Center For Coastal And Ocean Mapping","x":852.3263549804688,"y":1872.09228515625,"id":"563","color":"rgb(255,153,153)","size":4.0340681076049805},{"label":"Transport De Marchandises","x":900.6026000976562,"y":-2553.81201171875,"id":"1301","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Terminal Méthanier","x":-392.3746643066406,"y":-1739.4954833984375,"id":"1046","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Glace Continentale","x":770.9066162109375,"y":-432.2124328613281,"id":"1091","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Gas Giants","x":-1531.8878173828125,"y":905.6224365234375,"id":"205","color":"rgb(102,0,102)","size":4.075808525085449},{"label":"Dégradation De L\u0027Environnement,1","x":722.3955078125,"y":-1539.0269775390625,"id":"778","attributes":{"nodedef":"n778"},"color":"rgb(102,102,0)","size":4.39528751373291},{"label":"Convention De Genève","x":-24.439672470092773,"y":-1609.70947265625,"id":"709","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Revendications","x":85.95450592041016,"y":-849.3680419921875,"id":"1596","color":"rgb(255,51,51)","size":4.0},{"label":"Chaînes Alimentaires","x":1151.4473876953125,"y":-1582.9261474609375,"id":"583","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Health Science","x":1327.412109375,"y":241.00694274902344,"id":"1619","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Mer Des Tchouktches","x":-448.9115295410156,"y":-286.3415832519531,"id":"1342","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Cartes Shom","x":774.489501953125,"y":44.53413391113281,"id":"447","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Technology Conference","x":-1174.6954345703125,"y":758.0120849609375,"id":"686","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Pmrc","x":-971.127197265625,"y":301.84942626953125,"id":"1503","color":"rgb(255,51,51)","size":4.0},{"label":"North Atlantic","x":-592.1644897460938,"y":960.2535400390625,"id":"351","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Conservation De La Nature","x":341.7538757324219,"y":-1182.1884765625,"id":"696","color":"rgb(153,255,0)","size":4.781970500946045},{"label":"Institut De Physique","x":1748.0091552734375,"y":133.39999389648438,"id":"1077","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"International Polar Expedition","x":-403.2984619140625,"y":1634.9942626953125,"id":"1221","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"High Arctic","x":-997.6122436523438,"y":1941.9306640625,"id":"295","color":"rgb(0,204,204)","size":5.103478908538818},{"label":"Valley Winter","x":-1254.2745361328125,"y":201.01535034179688,"id":"1688","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Mer De Béring","x":-416.0766906738281,"y":-581.99462890625,"id":"1337","color":"rgb(255,51,51)","size":4.6399359703063965},{"label":"Advanced Science","x":862.8711547851562,"y":533.5106201171875,"id":"1270","color":"rgb(255,153,153)","size":4.0},{"label":"Developpement Local","x":327.0224914550781,"y":-1726.369384765625,"id":"814","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"Yukon","x":-1277.1168212890625,"y":912.0397338867188,"id":"1716","color":"rgb(153,0,0)","size":4.133297443389893},{"label":"Jacques Nougier","x":369.62542724609375,"y":1031.9442138671875,"id":"1234","color":"rgb(255,255,51)","size":4.0},{"label":"Adrian Flanagan","x":-598.8163452148438,"y":2167.505859375,"id":"1251","color":"rgb(0,204,204)","size":4.0},{"label":"Zones Géographiques","x":-218.76654052734375,"y":-1089.88232421875,"id":"1722","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Etude D\u0027Impact,2","x":989.4458618164062,"y":-1832.7940673828125,"id":"946","attributes":{"nodedef":"n946"},"color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Nomadic Tribe","x":-1678.7099609375,"y":-860.518310546875,"id":"1613","color":"rgb(204,204,255)","size":4.0},{"label":"25% Inférieure","x":378.7664489746094,"y":256.8262939453125,"id":"44","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Experience Scientifique","x":780.1193237304688,"y":-305.1599426269531,"id":"963","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Lgge","x":-72.10955810546875,"y":1455.18896484375,"id":"1290","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Hemisphere Sud","x":1008.4192504882812,"y":-105.01465606689453,"id":"636","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Analyse Qualitative Globale Simplifiée Des Impacts","x":344.9957275390625,"y":-1426.785400390625,"id":"243","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Adverse Effect","x":-2590.093017578125,"y":-133.97509765625,"id":"123","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Rayonnement Ultraviolet","x":1545.1719970703125,"y":-874.0010375976562,"id":"680","color":"rgb(255,204,102)","size":4.0},{"label":"Biologie Marine","x":1135.73681640625,"y":-625.051513671875,"id":"468","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Eau Douce","x":905.9652709960938,"y":-1031.2620849609375,"id":"498","color":"rgb(102,255,102)","size":13.944929122924805},{"label":"Reserve Naturelle Regionale","x":694.9480590820312,"y":-1956.704833984375,"id":"846","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Otan","x":-403.6894836425781,"y":-605.4341430664062,"id":"1444","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Norwegian Polar","x":-518.056396484375,"y":1673.6336669921875,"id":"317","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Canis Lupus","x":-332.4640197753906,"y":-551.8473510742188,"id":"1308","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Water Pollution","x":-1417.96337890625,"y":887.7281494140625,"id":"1515","color":"rgb(102,102,0)","size":4.075808525085449},{"label":"Cycle De Doha","x":84.66776275634766,"y":-1861.4490966796875,"id":"761","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"Explorateur Polaire","x":49.932064056396484,"y":445.4388122558594,"id":"841","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Ressources Naturelles","x":231.35784912109375,"y":-1204.1434326171875,"id":"1592","color":"rgb(0,153,0)","size":4.133297443389893},{"label":"Kara","x":-1029.7344970703125,"y":437.6309814453125,"id":"1257","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Template Matching","x":-1361.560302734375,"y":302.0841369628906,"id":"1686","color":"rgb(255,51,51)","size":4.0},{"label":"Ifremer Brest","x":511.7898864746094,"y":-372.69976806640625,"id":"1005","color":"rgb(153,255,255)","size":4.0086140632629395},{"label":"Risque Majeur","x":1767.0731201171875,"y":-1811.623779296875,"id":"23","color":"rgb(102,102,0)","size":4.6399359703063965},{"label":"Canadian Inuit","x":-1131.8297119140625,"y":2217.159423828125,"id":"523","color":"rgb(204,204,255)","size":4.781970500946045},{"label":"Board Of Trustees","x":-919.033935546875,"y":897.6107177734375,"id":"1693","color":"rgb(102,255,102)","size":4.0},{"label":"Agenda 21","x":79.4177017211914,"y":-499.4136047363281,"id":"99","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Nature","x":-706.6260375976562,"y":836.9927978515625,"id":"1387","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Cape Cross","x":212.16981506347656,"y":-2052.8818359375,"id":"1447","color":"rgb(153,0,0)","size":4.0},{"label":"Science Des Materiaux","x":2504.886474609375,"y":-260.5295104980469,"id":"1521","color":"rgb(255,255,51)","size":4.0},{"label":"Canada","x":-1005.2640380859375,"y":680.813232421875,"id":"520","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Convention On Climate","x":-614.9793701171875,"y":647.582275390625,"id":"718","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Astronomie De Lyon","x":1325.966552734375,"y":337.0829772949219,"id":"1564","color":"rgb(255,153,153)","size":4.0},{"label":"Accessibles","x":150.030517578125,"y":-543.5947875976562,"id":"75","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Carbon Cycle","x":-557.7491455078125,"y":1300.622802734375,"id":"465","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Accumulateur De Froid","x":2515.8671875,"y":-386.56671142578125,"id":"86","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Universite De Reading","x":733.7023315429688,"y":-634.2902221679688,"id":"1699","color":"rgb(255,204,102)","size":4.0340681076049805},{"label":"Otto Neumann Sverdrup","x":-899.0653686523438,"y":2098.9833984375,"id":"1448","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Azote Liquide","x":2053.978515625,"y":-126.75948333740234,"id":"380","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Variation Climatique","x":1092.8575439453125,"y":-579.475341796875,"id":"511","color":"rgb(255,204,102)","size":5.282204627990723},{"label":"Ligne De Base","x":-266.4502258300781,"y":-1518.729248046875,"id":"870","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Snohvit","x":-2041.626220703125,"y":1151.53125,"id":"1636","color":"rgb(102,0,102)","size":4.293514728546143},{"label":"Earth Summit","x":-434.10894775390625,"y":501.4352722167969,"id":"850","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Nord Stream","x":-1559.5074462890625,"y":35.28211212158203,"id":"1050","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Plusieurs Expéditions","x":224.90196228027344,"y":299.7099304199219,"id":"1501","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Sami Parliament","x":-1931.7279052734375,"y":2559.63525390625,"id":"1607","color":"rgb(204,204,255)","size":4.781970500946045},{"label":"Régions Subpolaires","x":113.39276885986328,"y":-350.522705078125,"id":"1576","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Makivik Corporation","x":-1267.5469970703125,"y":2790.955810546875,"id":"1259","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Toundra","x":-3601.925048828125,"y":-1691.172119140625,"id":"1681","color":"rgb(51,153,255)","size":4.0},{"label":"Express Côtier","x":-753.6414794921875,"y":-218.7122802734375,"id":"535","color":"rgb(0,204,204)","size":5.282204627990723},{"label":"Danemark","x":-1614.99658203125,"y":-1534.9354248046875,"id":"762","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Zero Absolu","x":1220.9068603515625,"y":520.4005737304688,"id":"675","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Geographie De La Russie","x":-1012.9732666015625,"y":-152.01487731933594,"id":"958","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Habitat Sain","x":816.5289916992188,"y":-1637.7469482421875,"id":"1150","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Nobel De La Paix","x":657.8598022460938,"y":-373.2637939453125,"id":"635","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Pressure Ridge","x":-300.82281494140625,"y":2095.478759765625,"id":"1357","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Période Du Quaternaire","x":1016.2114868164062,"y":-305.43133544921875,"id":"1469","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Science Naturelle","x":1218.244140625,"y":-309.01025390625,"id":"732","color":"rgb(255,204,102)","size":5.282204627990723},{"label":"Carbon Capture","x":-691.7048950195312,"y":1221.33251953125,"id":"547","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Asie Centrale","x":-319.7685546875,"y":-1110.31103515625,"id":"344","color":"rgb(255,51,51)","size":5.282204627990723},{"label":"Glacial Valley","x":-181.54881286621094,"y":2009.858154296875,"id":"1100","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Lomrog","x":-209.9856719970703,"y":1389.962646484375,"id":"1304","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Fonte Des Neiges","x":762.1256103515625,"y":-414.39501953125,"id":"866","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"1er Juillet 1909","x":-499.7980651855469,"y":233.0601806640625,"id":"41","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Geophysical Research","x":233.82315063476562,"y":1178.865966796875,"id":"224","color":"rgb(255,204,102)","size":5.282204627990723},{"label":"East Antarctica","x":-88.15560150146484,"y":1613.804931640625,"id":"851","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Espèce Humaine","x":758.9379272460938,"y":-1053.2381591796875,"id":"107","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Laboratoire De Physique","x":1664.2449951171875,"y":111.04265594482422,"id":"647","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Sápmi","x":-1812.7078857421875,"y":2444.205078125,"id":"1615","color":"rgb(204,204,255)","size":4.293514728546143},{"label":"Banquise Continentale","x":494.56414794921875,"y":-35.85556411743164,"id":"407","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Ressources Pétrolières","x":5.557656764984131,"y":-1679.0411376953125,"id":"1593","color":"rgb(102,0,102)","size":4.6399359703063965},{"label":"Calotte Polaire","x":716.3751831054688,"y":-65.0952377319336,"id":"408","color":"rgb(153,255,255)","size":10.178449630737305},{"label":"Club De Rome","x":633.6453857421875,"y":-1392.46533203125,"id":"643","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Action 21","x":300.5744934082031,"y":-1140.8724365234375,"id":"98","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Pacifique Nord","x":-69.47128295898438,"y":-741.9420166015625,"id":"201","color":"rgb(255,51,51)","size":5.103478908538818},{"label":"Lac Inari","x":-517.269287109375,"y":-265.3852233886719,"id":"1267","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Gazoduc Nord Stream","x":-615.8136596679688,"y":-1195.086669921875,"id":"1049","color":"rgb(102,0,102)","size":4.293514728546143},{"label":"Compose Organique Volatil","x":1425.1248779296875,"y":-1582.4134521484375,"id":"669","color":"rgb(102,102,0)","size":4.133297443389893},{"label":"Tromsø","x":-1374.7109375,"y":1913.8165283203125,"id":"1690","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Peninsule De Kola","x":-309.8347473144531,"y":-942.0747680664062,"id":"1466","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Équilibre Physique","x":124.99056243896484,"y":-1557.06103515625,"id":"923","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Conférence De Rio","x":390.2206115722656,"y":-1159.0963134765625,"id":"687","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Cristal De Glace","x":1232.4102783203125,"y":-102.79730987548828,"id":"146","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Colin Ware","x":926.259033203125,"y":1965.2078857421875,"id":"566","color":"rgb(255,255,51)","size":4.0},{"label":"Technologie","x":1581.9178466796875,"y":-336.73651123046875,"id":"1665","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Affaiblissement","x":-122.19145202636719,"y":-1517.307861328125,"id":"126","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Echelle De Temps","x":1488.7841796875,"y":-631.0740356445312,"id":"554","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Nuit Polaire","x":-99.41971588134766,"y":227.19300842285156,"id":"370","color":"rgb(0,204,204)","size":6.341859817504883},{"label":"Système Opérant","x":1278.6395263671875,"y":-1429.378662109375,"id":"1661","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Bilan Radiatif","x":1147.6866455078125,"y":-749.841552734375,"id":"459","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Accord International","x":200.89614868164062,"y":-1449.5303955078125,"id":"83","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Global Carbon","x":-402.25408935546875,"y":928.3751831054688,"id":"1109","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Pays Scandinave","x":-880.7955932617188,"y":-1050.10595703125,"id":"765","color":"rgb(255,51,51)","size":4.6399359703063965},{"label":"Same","x":-1110.919921875,"y":401.4477233886719,"id":"1610","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Gas Field","x":-2166.35986328125,"y":897.1481323242188,"id":"1034","color":"rgb(102,0,102)","size":4.781970500946045},{"label":"Reindeer Herding","x":-1707.0650634765625,"y":2392.613037109375,"id":"1279","color":"rgb(204,204,255)","size":5.472443103790283},{"label":"Agricultural Science","x":-384.6358947753906,"y":662.8099365234375,"id":"151","color":"rgb(102,255,102)","size":4.0},{"label":"Glissement De Terrain","x":1159.54150390625,"y":-1336.1181640625,"id":"27","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Dérive Arctique","x":141.0907745361328,"y":-99.68477630615234,"id":"797","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Law Of Sea","x":-454.2995910644531,"y":200.2239227294922,"id":"338","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Vitesse De Derive","x":543.1426391601562,"y":392.12109375,"id":"1364","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Far North","x":-1296.9681396484375,"y":2076.255126953125,"id":"486","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Importance Stratégique","x":666.7877197265625,"y":-1432.8302001953125,"id":"1189","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Global Climate","x":-197.5624237060547,"y":1134.3074951171875,"id":"300","color":"rgb(102,255,102)","size":5.886096477508545},{"label":"Rayon De Soleil","x":1629.82470703125,"y":-1112.863037109375,"id":"1289","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Pétrole","x":-376.43804931640625,"y":-1084.022705078125,"id":"1477","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Observation Satellitaire","x":506.5022277832031,"y":-307.2046813964844,"id":"1427","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Diversité Biologique","x":386.11077880859375,"y":-1118.481689453125,"id":"100","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Genie Civil","x":2628.016357421875,"y":490.0144348144531,"id":"662","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Territoires Du Nord","x":-403.6544494628906,"y":-31.657672882080078,"id":"284","color":"rgb(0,204,204)","size":5.103478908538818},{"label":"Dorsale Océanique","x":1771.7816162109375,"y":-541.5540161132812,"id":"265","color":"rgb(255,204,102)","size":4.781970500946045},{"label":"Cercle Arctique","x":-114.37723541259766,"y":-244.14686584472656,"id":"573","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Mackenzie Valley","x":-1897.8876953125,"y":1437.210693359375,"id":"786","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Barrel Of Oil","x":-2069.470703125,"y":796.83154296875,"id":"37","color":"rgb(102,0,102)","size":6.584775924682617},{"label":"Température","x":1094.9617919921875,"y":2582.613525390625,"id":"1670","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Alfred Wegener","x":140.85134887695312,"y":1208.193115234375,"id":"210","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Danger","x":-1045.3048095703125,"y":560.9677734375,"id":"766","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Gaz Naturel Pour Véhicules","x":34.037445068359375,"y":-960.7977905273438,"id":"1045","color":"rgb(0,153,0)","size":4.206028938293457},{"label":"International Commission","x":-170.1094207763672,"y":173.10662841796875,"id":"1218","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Archéologie","x":1697.4716796875,"y":-422.6084289550781,"id":"278","color":"rgb(255,255,51)","size":4.0},{"label":"Pygargue","x":-530.29248046875,"y":-718.80859375,"id":"1553","color":"rgb(204,204,255)","size":4.133297443389893},{"label":"Glaciologues","x":603.4629516601562,"y":-287.44390869140625,"id":"1107","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Nombre De Reynolds","x":2456.903076171875,"y":178.03688049316406,"id":"889","color":"rgb(255,255,0)","size":4.075808525085449},{"label":"Petit Rorqual","x":-97.76100158691406,"y":-1044.327392578125,"id":"394","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Parc National Wapusk","x":110.16836547851562,"y":-938.0703735351562,"id":"1458","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Impact Environnemental","x":900.10498046875,"y":-1452.6837158203125,"id":"250","color":"rgb(153,255,0)","size":6.584775924682617},{"label":"University Of Northern British","x":-1309.81298828125,"y":-512.9873046875,"id":"1400","color":"rgb(153,255,255)","size":4.0},{"label":"Etude Du Quaternaire","x":1390.19189453125,"y":-603.2861938476562,"id":"926","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Forêt Boréale","x":-7.181797981262207,"y":-917.6866455078125,"id":"497","color":"rgb(0,153,0)","size":4.6399359703063965},{"label":"Skaller","x":-1005.0679931640625,"y":254.76441955566406,"id":"1635","color":"rgb(255,51,51)","size":4.0},{"label":"Brise-Glace Russe","x":314.2594909667969,"y":-57.35684585571289,"id":"506","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Unesco Biosphere","x":-1305.965576171875,"y":1596.37890625,"id":"473","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Approche Systémique","x":1452.9090576171875,"y":-1503.2738037109375,"id":"1662","color":"rgb(255,255,51)","size":4.0},{"label":"62.809 Km²","x":-3687.156982421875,"y":-1498.2891845703125,"id":"58","color":"rgb(255,255,51)","size":4.0},{"label":"Pole Nord","x":142.79425048828125,"y":98.24790954589844,"id":"49","color":"rgb(0,204,204)","size":31.900625228881836},{"label":"Surfaces Englacées","x":1017.113037109375,"y":48.020137786865234,"id":"1657","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Observatoire Des Sciences","x":1681.810302734375,"y":327.4986267089844,"id":"1262","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Satellite Service","x":357.4742126464844,"y":2558.146728515625,"id":"1617","color":"rgb(255,153,153)","size":4.0},{"label":"Ours Brun","x":-546.7056274414062,"y":-570.5150756835938,"id":"749","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Baker Lake","x":-1292.3116455078125,"y":1876.362548828125,"id":"1377","color":"rgb(0,204,204)","size":4.0},{"label":"Cargo Ship","x":-1623.7650146484375,"y":56.645198822021484,"id":"1274","color":"rgb(255,51,51)","size":4.0},{"label":"Northern Hemisphere","x":-425.2862548828125,"y":1888.925537109375,"id":"1407","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Circulation Thermohaline","x":585.6029052734375,"y":-267.0980529785156,"id":"610","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Satellite Photo","x":591.8084106445312,"y":1738.074462890625,"id":"1185","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Institut Royal","x":1343.8946533203125,"y":-224.90185546875,"id":"1207","color":"rgb(255,255,51)","size":4.0},{"label":"Glacial Retreat","x":-633.63037109375,"y":1639.9283447265625,"id":"1099","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Institute Of Geophysics","x":746.8310546875,"y":968.5191040039062,"id":"1075","color":"rgb(255,204,102)","size":4.0340681076049805},{"label":"Réserves D\u0027Énergies Fossiles,1","x":568.9767456054688,"y":-1300.394287109375,"id":"1589","attributes":{"nodedef":"n1589"},"color":"rgb(0,153,0)","size":4.510906219482422},{"label":"Petroleum Congress","x":-1832.741943359375,"y":921.537109375,"id":"991","color":"rgb(102,0,102)","size":4.075808525085449},{"label":"International Polar","x":-80.96073913574219,"y":1307.7596435546875,"id":"181","color":"rgb(153,255,255)","size":6.837328910827637},{"label":"Amplitude Thermique","x":1254.463134765625,"y":-699.683837890625,"id":"235","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Lapons","x":-759.9954223632812,"y":-489.00518798828125,"id":"1277","color":"rgb(204,204,255)","size":4.075808525085449},{"label":"Inuit People","x":-1119.61962890625,"y":2266.22998046875,"id":"528","color":"rgb(204,204,255)","size":4.6399359703063965},{"label":"Spitzberg","x":-408.04937744140625,"y":-213.5766143798828,"id":"1650","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Carottes Glaciaires","x":969.6451416015625,"y":-432.83563232421875,"id":"63","color":"rgb(255,255,51)","size":5.472443103790283},{"label":"Robert Peary","x":-922.84228515625,"y":1658.168212890625,"id":"1557","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Hectares Globaux","x":562.0274658203125,"y":-1184.515869140625,"id":"902","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Element Chimique","x":1355.92431640625,"y":-1334.5970458984375,"id":"624","color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Norwegian National","x":-2346.080322265625,"y":2597.039794921875,"id":"1414","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Geographic Explorer","x":-1533.6759033203125,"y":1280.688232421875,"id":"1065","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Jean Lemire","x":411.0581359863281,"y":203.411865234375,"id":"1243","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Protection Animale","x":194.66322326660156,"y":-1489.9267578125,"id":"919","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Gazoducs","x":-246.90235900878906,"y":-1405.90234375,"id":"1051","color":"rgb(102,0,102)","size":4.39528751373291},{"label":"Loi De Newton","x":2768.0830078125,"y":739.8944702148438,"id":"1526","color":"rgb(255,255,0)","size":4.0086140632629395},{"label":"Terre Agricole","x":1055.7603759765625,"y":-1679.8907470703125,"id":"736","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Arctic Research","x":-595.9910888671875,"y":1777.158447265625,"id":"306","color":"rgb(153,255,255)","size":4.936610698699951},{"label":"Papanine","x":67.4764404296875,"y":321.97711181640625,"id":"1457","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Planck Institute","x":1722.83447265625,"y":184.09603881835938,"id":"1265","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Sedna Iv","x":240.6781768798828,"y":225.52828979492188,"id":"1626","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"1986","x":-967.396728515625,"y":216.6686248779297,"id":"13","color":"rgb(255,51,51)","size":4.0},{"label":"Resolution De Conflit","x":-802.1610107421875,"y":-614.1929321289062,"id":"692","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Nappe Phréatique","x":686.59765625,"y":-1779.1011962890625,"id":"1379","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Gérard Jugie","x":649.3414306640625,"y":24.25006103515625,"id":"1084","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Rayonnement Solaire","x":1429.1036376953125,"y":-987.4943237304688,"id":"366","color":"rgb(255,204,102)","size":4.781970500946045},{"label":"Chtokman","x":-587.8933715820312,"y":-1263.6697998046875,"id":"604","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Banque Mondiale","x":207.86805725097656,"y":-1685.1241455078125,"id":"175","color":"rgb(153,0,0)","size":5.886096477508545},{"label":"Habitat Écologique","x":879.9754638671875,"y":-1601.36962890625,"id":"876","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Aker Yards","x":-590.3784790039062,"y":-1667.7393798828125,"id":"1217","color":"rgb(255,51,51)","size":4.0},{"label":"Norwegian Fjords","x":-1819.7435302734375,"y":1941.7181396484375,"id":"993","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Courants Marins","x":740.0386352539062,"y":-772.4693603515625,"id":"725","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"World Biosphere","x":-1380.392822265625,"y":1572.7969970703125,"id":"474","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Glacial Arctique","x":-98.87494659423828,"y":-112.53652954101562,"id":"405","color":"rgb(0,204,204)","size":9.173389434814453},{"label":"Le Fram","x":1.6208196878433228,"y":820.0587768554688,"id":"1285","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Balises","x":1477.4683837890625,"y":-1345.0499267578125,"id":"395","color":"rgb(255,255,51)","size":4.0},{"label":"Méthane","x":-722.9597778320312,"y":1301.656005859375,"id":"1349","color":"rgb(0,153,0)","size":4.206028938293457},{"label":"Bénéfice Net","x":-632.4590454101562,"y":-1823.570068359375,"id":"1328","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"National Geographic","x":-1397.74169921875,"y":1131.574951171875,"id":"479","color":"rgb(153,255,0)","size":5.103478908538818},{"label":"Régions Arctiques","x":57.04184341430664,"y":-398.7633972167969,"id":"484","color":"rgb(0,204,204)","size":6.837328910827637},{"label":"Light Pollution","x":-1550.57373046875,"y":963.8270263671875,"id":"1516","color":"rgb(102,102,0)","size":4.0},{"label":"Recyclage Des Déchets","x":654.7275390625,"y":-2429.897705078125,"id":"770","color":"rgb(102,102,0)","size":4.39528751373291},{"label":"Igloo Building","x":-1083.1083984375,"y":2375.260009765625,"id":"1171","color":"rgb(204,204,255)","size":4.0},{"label":"Ile Wrangel","x":-254.5749969482422,"y":-439.13525390625,"id":"1180","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Pôle Nord Magnétique","x":492.461669921875,"y":627.1895141601562,"id":"1510","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Agence Nationale","x":1428.78466796875,"y":-1177.7340087890625,"id":"772","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Précipitations Faibles","x":1415.2930908203125,"y":-583.3818969726562,"id":"1530","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Dégradations Écologiques","x":431.67926025390625,"y":-1474.4056396484375,"id":"780","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Finnish Economy","x":-941.7028198242188,"y":-1652.6466064453125,"id":"986","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Norwegian Government","x":-2365.86767578125,"y":2572.55810546875,"id":"1413","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Analyses De Cycle De Vie","x":1009.1702880859375,"y":-1412.4342041015625,"id":"249","color":"rgb(153,255,0)","size":4.6399359703063965},{"label":"International Polar Year","x":-58.65946960449219,"y":1398.2398681640625,"id":"1222","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Nombreux Polluants","x":1069.2344970703125,"y":-1600.981201171875,"id":"1397","color":"rgb(102,102,0)","size":4.39528751373291},{"label":"Évolution De La Glace","x":855.4246826171875,"y":-23.298423767089844,"id":"951","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Ice Patrol","x":-550.0018310546875,"y":1364.3714599609375,"id":"1166","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Radio Association","x":-1379.472900390625,"y":268.6378479003906,"id":"546","color":"rgb(255,51,51)","size":4.0},{"label":"Fridtjof Nansen","x":-640.83935546875,"y":2040.8262939453125,"id":"979","color":"rgb(0,204,204)","size":4.936610698699951},{"label":"Risque Naturel","x":1649.328125,"y":-1627.618896484375,"id":"456","color":"rgb(102,102,0)","size":5.282204627990723},{"label":"Déclinaison Magnétique","x":626.72119140625,"y":533.5086669921875,"id":"589","color":"rgb(153,255,255)","size":5.282204627990723},{"label":"Eaux Territoriales","x":-189.23031616210938,"y":-1744.7435302734375,"id":"712","color":"rgb(153,0,0)","size":5.886096477508545},{"label":"Règlementer La Protection De L\u0027Environnement,1","x":319.12982177734375,"y":-1075.597900390625,"id":"1578","attributes":{"nodedef":"n1578"},"color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Variations Glaciaires","x":1004.5759887695312,"y":-546.2811279296875,"id":"1701","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Wildlife Refuge","x":-2488.70947265625,"y":935.2979125976562,"id":"276","color":"rgb(153,255,0)","size":4.781970500946045},{"label":"Gold Rush","x":-1305.9024658203125,"y":640.7337036132812,"id":"1120","color":"rgb(153,0,0)","size":4.293514728546143},{"label":"Telescope Spatial","x":1484.6490478515625,"y":-77.53192901611328,"id":"349","color":"rgb(255,153,153)","size":4.075808525085449},{"label":"Human Impact","x":-242.1216278076172,"y":320.5730285644531,"id":"1160","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Amis De La Terre","x":401.504150390625,"y":-1223.7393798828125,"id":"103","color":"rgb(0,153,0)","size":4.510906219482422},{"label":"Sonde Voyager","x":1429.6922607421875,"y":181.77130126953125,"id":"860","color":"rgb(255,153,153)","size":4.133297443389893},{"label":"Polar Orbit","x":390.5345153808594,"y":2202.097412109375,"id":"913","color":"rgb(255,153,153)","size":4.510906219482422},{"label":"Carnivorous Animals","x":-1647.055419921875,"y":-880.9697265625,"id":"1612","color":"rgb(204,204,255)","size":4.0},{"label":"Fjell","x":-1517.3455810546875,"y":1056.70654296875,"id":"990","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Mikhail Malakhov","x":-609.2708129882812,"y":1933.433349609375,"id":"1355","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Données Environnementales","x":1346.6571044921875,"y":-1474.193359375,"id":"829","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Baffin Bay","x":-730.2673950195312,"y":1399.5347900390625,"id":"381","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Point De Non-Retour","x":602.4612426757812,"y":-325.70556640625,"id":"1504","color":"rgb(255,204,102)","size":4.0},{"label":"Hydrostatic Pressure","x":-407.7259216308594,"y":1971.3367919921875,"id":"1488","color":"rgb(153,255,255)","size":4.0},{"label":"Vladimir Vladimirovitch","x":-858.2808227539062,"y":-1503.6971435546875,"id":"1706","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Transhumance","x":-1474.1590576171875,"y":181.26686096191406,"id":"1687","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Laponie Finlandaise","x":-628.8026733398438,"y":-549.0878295898438,"id":"747","color":"rgb(204,204,255)","size":5.472443103790283},{"label":"Salmon Fishing","x":-2913.92822265625,"y":2500.835205078125,"id":"191","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Ice Shelf","x":-190.6495361328125,"y":1773.7933349609375,"id":"852","color":"rgb(153,255,255)","size":5.886096477508545},{"label":"Physique Nucléaire","x":1447.166748046875,"y":-458.37335205078125,"id":"1201","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Eaux Libres","x":625.849853515625,"y":-937.6300048828125,"id":"800","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Tourisme De Masse","x":35.64778518676758,"y":-1237.3614501953125,"id":"1683","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Comportement Mécanique Du Matériau Glace","x":890.2638549804688,"y":178.80201721191406,"id":"665","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"1993","x":36.647705078125,"y":579.983154296875,"id":"15","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Température Moyenne Du Globe","x":850.3651123046875,"y":-792.5848999023438,"id":"1674","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Différence De Densité","x":1439.3902587890625,"y":-803.2998046875,"id":"815","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Cara","x":-1237.788330078125,"y":260.89483642578125,"id":"545","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Mackenzie River","x":-1691.715087890625,"y":1612.4267578125,"id":"322","color":"rgb(0,204,204)","size":5.282204627990723},{"label":"Claude Bourguignon","x":1691.6942138671875,"y":-1333.328369140625,"id":"630","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Nageoire Caudale","x":215.7217254638672,"y":-1250.8089599609375,"id":"392","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Droit De La Mer","x":-210.29884338378906,"y":-1344.11865234375,"id":"843","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Réserves Hydrocarbures","x":-132.05116271972656,"y":-1118.11962890625,"id":"1590","color":"rgb(102,0,102)","size":4.293514728546143},{"label":"Geophysical Union","x":77.1497802734375,"y":873.7490844726562,"id":"724","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Astrophysique","x":1783.648681640625,"y":-140.97059631347656,"id":"345","color":"rgb(255,153,153)","size":4.133297443389893},{"label":"Détroit De Behring","x":-438.4812927246094,"y":-528.7012329101562,"id":"805","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Norway","x":-2236.260009765625,"y":1732.703369140625,"id":"1412","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Geophysical Data","x":353.0085754394531,"y":1442.74609375,"id":"445","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Cyberdocumentaire","x":194.38003540039062,"y":-440.8644104003906,"id":"756","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Glaciologie Océanographie","x":1223.7781982421875,"y":-480.4251403808594,"id":"1105","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Geostationary Satellite","x":282.42694091796875,"y":2399.638916015625,"id":"653","color":"rgb(255,153,153)","size":4.6399359703063965},{"label":"Co2 Sequestration","x":-693.1399536132812,"y":1256.73974609375,"id":"649","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"6-Avr-09","x":-851.099365234375,"y":-454.1927795410156,"id":"19","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Zones De Fractures","x":1544.406494140625,"y":-418.4399719238281,"id":"1720","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Dégradations Sanitaires","x":-281.1681213378906,"y":-53.5842170715332,"id":"783","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Bonne Pratique","x":949.76171875,"y":-1626.8707275390625,"id":"253","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"National Wildlife","x":-2570.702392578125,"y":1014.2642211914062,"id":"275","color":"rgb(153,255,0)","size":4.781970500946045},{"label":"Pole Sud","x":526.24462890625,"y":302.62603759765625,"id":"513","color":"rgb(153,255,255)","size":10.527388572692871},{"label":"Croûte Océanique","x":1651.7996826171875,"y":-607.842041015625,"id":"264","color":"rgb(255,204,102)","size":5.282204627990723},{"label":"Arctic Climate","x":-653.6159057617188,"y":1591.3482666015625,"id":"298","color":"rgb(153,255,255)","size":4.936610698699951},{"label":"Milieu Naturel","x":685.8338012695312,"y":-1621.4942626953125,"id":"883","color":"rgb(153,255,0)","size":6.837328910827637},{"label":"Institut National De Recherche","x":1252.3394775390625,"y":204.79171752929688,"id":"1205","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Goddard Institute","x":-430.7890930175781,"y":684.432373046875,"id":"1013","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Liquefied Natural Gas","x":-1997.0789794921875,"y":776.1526489257812,"id":"1036","color":"rgb(102,0,102)","size":4.206028938293457},{"label":"Comportement Mécanique","x":2692.309814453125,"y":363.16912841796875,"id":"658","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"War Of Terror","x":-1307.4576416015625,"y":220.9207763671875,"id":"1710","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Pipkrakes","x":434.6990661621094,"y":-822.610107421875,"id":"1490","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Sustainable Development","x":-362.5677795410156,"y":419.285888671875,"id":"141","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Cycle De Vie","x":1149.1319580078125,"y":-1494.5059814453125,"id":"453","color":"rgb(153,255,0)","size":5.103478908538818},{"label":"Ouverture Du Passage Du Nord-Ouest","x":31.295948028564453,"y":-284.809814453125,"id":"1452","color":"rgb(153,0,0)","size":4.510906219482422},{"label":"Joseph-Elzéar Bernier (1852-1934)","x":-176.7270965576172,"y":32.511817932128906,"id":"1254","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Courbe Isotherme","x":586.0437622070312,"y":-222.40838623046875,"id":"730","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Extinction Des Espèces","x":399.3851623535156,"y":-1030.6234130859375,"id":"938","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Ice Cores","x":-151.26065063476562,"y":1561.3101806640625,"id":"626","color":"rgb(153,255,255)","size":6.108868598937988},{"label":"Université De Québec","x":1112.0452880859375,"y":-184.35299682617188,"id":"239","color":"rgb(255,255,51)","size":4.936610698699951},{"label":"Marine Sediment","x":-667.27099609375,"y":1089.9775390625,"id":"934","color":"rgb(0,153,0)","size":4.075808525085449},{"label":"Analyse De Données","x":1425.0694580078125,"y":-895.9777221679688,"id":"237","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Geophysique Interne","x":1671.1990966796875,"y":568.9614868164062,"id":"1074","color":"rgb(255,204,51)","size":4.6399359703063965},{"label":"Atlantic Drift","x":-915.51123046875,"y":1545.07080078125,"id":"350","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Navire Océanographique","x":822.8958740234375,"y":-327.39044189453125,"id":"1395","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Carte Géographie","x":603.58984375,"y":-973.70751953125,"id":"145","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Zone Économique","x":-231.34207153320312,"y":-1606.3955078125,"id":"713","color":"rgb(153,0,0)","size":5.282204627990723},{"label":"Amérique Du Sud","x":-356.3387451171875,"y":-652.8462524414062,"id":"229","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Océan Glacial","x":-159.73886108398438,"y":-180.17025756835938,"id":"409","color":"rgb(0,204,204)","size":8.235326766967773},{"label":"Eruption Volcanique","x":1564.9263916015625,"y":-654.048583984375,"id":"559","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"650 000 Ans","x":932.0712890625,"y":-565.0851440429688,"id":"60","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Plateforme Pétrolière","x":-260.26751708984375,"y":-1877.6268310546875,"id":"655","color":"rgb(102,0,102)","size":4.0086140632629395},{"label":"Histoire Géologique","x":1214.1163330078125,"y":-670.208251953125,"id":"555","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Northern Quebec","x":-1248.2911376953125,"y":2663.8232421875,"id":"524","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Region Polaire","x":472.4181823730469,"y":-83.093505859375,"id":"51","color":"rgb(0,204,204)","size":18.676555633544922},{"label":"Canal De Suez","x":-197.74679565429688,"y":-2417.987060546875,"id":"529","color":"rgb(204,0,0)","size":4.075808525085449},{"label":"Iles Feroe","x":-635.4229736328125,"y":-723.7227172851562,"id":"1181","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Najwa Nimri","x":-548.2072143554688,"y":-378.23529052734375,"id":"575","color":"rgb(0,204,204)","size":4.0},{"label":"Chef De Gouvernement","x":-647.8400268554688,"y":-1379.173095703125,"id":"599","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Réfugié Climatique","x":316.4598693847656,"y":-868.939697265625,"id":"1012","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Gilles Labarthe","x":317.49761962890625,"y":-1768.2515869140625,"id":"782","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Earth Science","x":306.0815734863281,"y":1127.4530029296875,"id":"211","color":"rgb(255,204,102)","size":5.886096477508545},{"label":"Circulation Océanique Mondiale","x":548.7537841796875,"y":-394.6384582519531,"id":"611","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Volcanic Islands","x":-1667.2989501953125,"y":2117.06884765625,"id":"1241","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Goélette Tara","x":248.9503936767578,"y":-164.35665893554688,"id":"789","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Gas Storage","x":-2368.42236328125,"y":790.8409423828125,"id":"1040","color":"rgb(102,0,102)","size":4.0340681076049805},{"label":"Annuaire Sciences","x":1520.93896484375,"y":-166.29861450195312,"id":"260","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Global Change","x":-328.3797912597656,"y":1407.6304931640625,"id":"368","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"East Iceland","x":-1432.9488525390625,"y":1744.767822265625,"id":"853","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Quantité De Ressources Nécessaires","x":655.5470581054688,"y":-1010.1531982421875,"id":"1554","color":"rgb(0,153,0)","size":4.293514728546143},{"label":"Boris Gryzlov","x":-968.377197265625,"y":-695.67138671875,"id":"490","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Adverse Reaction","x":-2583.47412109375,"y":-171.4156494140625,"id":"125","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Radio Commission","x":-1329.051513671875,"y":440.54400634765625,"id":"7","color":"rgb(255,51,51)","size":4.0},{"label":"Changements Climatiques","x":562.6347045898438,"y":-799.8172607421875,"id":"595","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Marine Research","x":112.32674407958984,"y":687.9962158203125,"id":"212","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Fonds Marins Du Pôle","x":-206.661865234375,"y":-829.8015747070312,"id":"1007","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Météorologie","x":1402.136474609375,"y":119.9842300415039,"id":"1347","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Observatoire De Paris","x":1645.601806640625,"y":-187.08619689941406,"id":"348","color":"rgb(255,255,51)","size":4.781970500946045},{"label":"Lac Vostok","x":835.7393188476562,"y":-45.74352264404297,"id":"1268","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Sonde Viking","x":1175.79736328125,"y":944.133056640625,"id":"1643","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Nappes","x":681.9324951171875,"y":-2016.6527099609375,"id":"1380","color":"rgb(102,102,0)","size":4.0086140632629395},{"label":"Bouclier Antimissile","x":-738.5277099609375,"y":-1235.395263671875,"id":"492","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Ocean Floor","x":-825.3276977539062,"y":1300.9876708984375,"id":"1324","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Détroit De Fram","x":-55.04530334472656,"y":-329.93707275390625,"id":"808","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Frontier In American History","x":-1133.305419921875,"y":303.24676513671875,"id":"3","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Epfl Lausanne","x":1752.3311767578125,"y":349.822998046875,"id":"920","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Science De La Terre","x":1194.40625,"y":-6.191011428833008,"id":"1620","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Crevasses","x":-1673.8072509765625,"y":1519.3421630859375,"id":"739","color":"rgb(0,204,204)","size":4.0},{"label":"Plan De Prévention De Risque Naturel","x":1859.6912841796875,"y":-1892.7198486328125,"id":"29","color":"rgb(102,102,0)","size":4.0},{"label":"Galveston Bay","x":-994.8403930664062,"y":810.9219360351562,"id":"1055","color":"rgb(102,255,102)","size":4.0},{"label":"Logistique","x":1180.882568359375,"y":-2362.267578125,"id":"1299","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"Septentrional De L\u0027Europe,1","x":-599.4520263671875,"y":-240.5999298095703,"id":"1628","attributes":{"nodedef":"n1628"},"color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Classe Dominante","x":330.9660949707031,"y":-1010.1752319335938,"id":"796","color":"rgb(153,255,0)","size":4.0},{"label":"Centrale Nucléaire","x":211.94808959960938,"y":-1468.9288330078125,"id":"427","color":"rgb(0,153,0)","size":5.282204627990723},{"label":"Elliptic Orbit","x":-174.8773956298828,"y":2327.053955078125,"id":"900","color":"rgb(255,153,153)","size":4.206028938293457},{"label":"Brume Légère","x":2014.856689453125,"y":-408.7442626953125,"id":"507","color":"rgb(255,204,102)","size":4.0},{"label":"Pollution Atmosphérique","x":1176.463134765625,"y":-1357.466064453125,"id":"1165","color":"rgb(102,102,0)","size":4.510906219482422},{"label":"Mackenzie Delta","x":-1785.2647705078125,"y":1501.4832763671875,"id":"1312","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Univers De Grenoble","x":1553.7344970703125,"y":344.835205078125,"id":"1210","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Inland Ice","x":-318.5847473144531,"y":1719.4364013671875,"id":"1197","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Baie Disko","x":-297.0066833496094,"y":-359.0252990722656,"id":"387","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Bald Eagle","x":-1986.3089599609375,"y":336.0643005371094,"id":"1384","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Prélèvement","x":482.5769348144531,"y":-2409.00390625,"id":"1532","color":"rgb(102,102,0)","size":4.0086140632629395},{"label":"Environnement De Basse","x":926.786865234375,"y":-1721.84619140625,"id":"916","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Renard Polaire","x":-566.1803588867188,"y":-770.5494384765625,"id":"1292","color":"rgb(153,255,0)","size":5.103478908538818},{"label":"Vallee Glaciaire","x":820.0235595703125,"y":-582.6707763671875,"id":"147","color":"rgb(255,204,102)","size":4.0340681076049805},{"label":"Physique Appliquée","x":2376.69384765625,"y":202.5380096435547,"id":"1484","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Team North","x":-535.7245483398438,"y":2188.06884765625,"id":"1252","color":"rgb(0,204,204)","size":4.0},{"label":"Rhéologie","x":2337.57958984375,"y":488.13970947265625,"id":"1599","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"European Space","x":679.074951171875,"y":1231.0482177734375,"id":"136","color":"rgb(255,153,153)","size":5.103478908538818},{"label":"Convention De Bâle","x":374.0647888183594,"y":-1949.95703125,"id":"706","color":"rgb(153,0,0)","size":4.293514728546143},{"label":"L\u0027Océan Glacial Arctique,1","x":48.046844482421875,"y":-310.00390625,"id":"1298","attributes":{"nodedef":"n1298"},"color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Icebergs","x":-401.4381103515625,"y":1591.3231201171875,"id":"1168","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Yukon Territories","x":-1300.5863037109375,"y":805.2991333007812,"id":"1718","color":"rgb(153,0,0)","size":4.293514728546143},{"label":"Conference On Environment","x":-733.2816772460938,"y":725.8975830078125,"id":"690","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Magerøya","x":-1317.69775390625,"y":2029.0751953125,"id":"1313","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Planète Terre","x":981.09326171875,"y":-350.93524169921875,"id":"1493","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Loi De Comportement","x":2595.855224609375,"y":256.8731384277344,"id":"659","color":"rgb(255,255,0)","size":4.133297443389893},{"label":"Geographical Society","x":-1606.1199951171875,"y":1324.9771728515625,"id":"1062","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Marine Russe","x":-537.8284912109375,"y":-1164.311767578125,"id":"505","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Bande Côtière","x":251.931396484375,"y":-960.4885864257812,"id":"402","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Exploitation Agricole","x":1264.929443359375,"y":-1911.810546875,"id":"154","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Peuple Autochtone","x":-238.15725708007812,"y":-465.5401611328125,"id":"695","color":"rgb(204,204,255)","size":4.6399359703063965},{"label":"Gas Price","x":-1848.1641845703125,"y":553.953125,"id":"207","color":"rgb(102,0,102)","size":4.6399359703063965},{"label":"Effet Dynamo","x":961.6566772460938,"y":513.2507934570312,"id":"588","color":"rgb(255,153,153)","size":4.0340681076049805},{"label":"Ignace Venetz","x":918.0681762695312,"y":469.9112854003906,"id":"1172","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"200 Metres","x":-146.15635681152344,"y":-719.9545288085938,"id":"503","color":"rgb(255,51,51)","size":4.0},{"label":"Loi De Mariotte","x":2331.056396484375,"y":-626.9660034179688,"id":"702","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Réchauffement Global","x":992.4798583984375,"y":-651.2942504882812,"id":"108","color":"rgb(255,204,102)","size":5.103478908538818},{"label":"Island Navy","x":-1509.423828125,"y":287.9374084472656,"id":"1228","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Solid Earth","x":255.05235290527344,"y":1264.2841796875,"id":"225","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Terre De Baffin","x":-421.7633361816406,"y":441.2944030761719,"id":"283","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Station Météo","x":1904.0716552734375,"y":-653.455322265625,"id":"642","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Données Géographiques","x":1658.4525146484375,"y":-1306.4632568359375,"id":"830","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Global Ocean","x":139.24534606933594,"y":600.2429809570312,"id":"1113","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Gestion Des Données","x":1647.5302734375,"y":-1473.1031494140625,"id":"831","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Arctic Haze","x":-328.0976867675781,"y":1800.9615478515625,"id":"305","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Coastal Erosion","x":-212.16925048828125,"y":1024.1375732421875,"id":"650","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Government Of Nunavut","x":-1442.6414794921875,"y":1648.6278076171875,"id":"517","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Al Gore","x":-573.0253295898438,"y":913.5389404296875,"id":"176","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Histoire Culturelle","x":1271.152099609375,"y":-1099.011962890625,"id":"1159","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Libre De Droit","x":1470.94482421875,"y":-1249.3375244140625,"id":"440","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Space Agencies","x":719.65869140625,"y":1200.9990234375,"id":"137","color":"rgb(255,153,153)","size":5.103478908538818},{"label":"Navigation Maritime","x":946.244873046875,"y":130.5264129638672,"id":"1393","color":"rgb(255,255,51)","size":4.0},{"label":"Topographie","x":2066.535888671875,"y":-1426.6158447265625,"id":"1679","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Norsk Hydro","x":-2283.26513671875,"y":937.6468505859375,"id":"1403","color":"rgb(102,0,102)","size":4.0340681076049805},{"label":"Progres Technique","x":11.202921867370605,"y":-1463.979248046875,"id":"1419","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Légendaire Passage","x":358.2781982421875,"y":-282.7051696777344,"id":"1286","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Habitat Naturel","x":716.3448486328125,"y":-1602.0145263671875,"id":"976","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Lapon","x":-1466.6243896484375,"y":78.49531555175781,"id":"1273","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Grand Lac Des Esclaves","x":-347.9867858886719,"y":-486.2426452636719,"id":"1134","color":"rgb(204,204,255)","size":4.133297443389893},{"label":"Biological Invasions","x":-293.0665283203125,"y":-505.9958801269531,"id":"466","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Jan Mayen","x":-1543.442138671875,"y":2096.722412109375,"id":"1237","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Espece Disparue","x":567.878662109375,"y":-1223.2427978515625,"id":"936","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Palses","x":283.32855224609375,"y":-564.1228637695312,"id":"1456","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Menacer","x":56.30271530151367,"y":-1117.4920654296875,"id":"1332","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Energie Solaire","x":1242.6446533203125,"y":-964.1528930664062,"id":"114","color":"rgb(0,153,0)","size":8.540210723876953},{"label":"Mission Banquise","x":94.93065643310547,"y":-12.493345260620117,"id":"801","color":"rgb(153,255,255)","size":5.103478908538818},{"label":"Mer Baltique","x":-582.2013549804688,"y":-959.6834716796875,"id":"1334","color":"rgb(255,51,51)","size":4.510906219482422},{"label":"Brown Bear","x":-761.362548828125,"y":-631.6953125,"id":"1449","color":"rgb(153,255,0)","size":4.0},{"label":"Hydrocarbures Aromatiques Polycycliques","x":1065.962646484375,"y":-1764.6729736328125,"id":"1162","color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Baffin Island","x":-1026.7235107421875,"y":1774.6162109375,"id":"293","color":"rgb(0,204,204)","size":5.6738481521606445},{"label":"Calottes Glaciaires","x":811.1303100585938,"y":-547.6314697265625,"id":"514","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Parc Naturel","x":648.4389038085938,"y":-1895.759521484375,"id":"935","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"1926","x":-1055.7027587890625,"y":454.9776916503906,"id":"4","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Morses","x":-1462.1083984375,"y":135.85678100585938,"id":"1369","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Plongée Inédite","x":-1133.52197265625,"y":-255.4286651611328,"id":"1500","color":"rgb(204,204,255)","size":4.206028938293457},{"label":"Water Level","x":-546.029296875,"y":2229.371337890625,"id":"1638","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Vatnajökull","x":-1385.9775390625,"y":1713.69580078125,"id":"1702","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Taïga","x":-1005.849853515625,"y":2259.279052734375,"id":"1664","color":"rgb(204,204,255)","size":4.206028938293457},{"label":"Nuclear Test","x":-1154.5859375,"y":51.68592834472656,"id":"961","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Morue Polaire","x":94.72049713134766,"y":-789.96630859375,"id":"1374","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Atlantique Au Pacifique","x":-439.2219543457031,"y":-982.3482666015625,"id":"352","color":"rgb(153,0,0)","size":4.510906219482422},{"label":"Circulation Atmosphérique","x":1365.9012451171875,"y":-398.28692626953125,"id":"460","color":"rgb(255,255,51)","size":5.472443103790283},{"label":"Conditions Extrêmes","x":1417.91015625,"y":-823.0306396484375,"id":"677","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"University Institute Of Technology","x":-3697.0966796875,"y":-1473.5218505859375,"id":"59","color":"rgb(255,255,51)","size":4.0},{"label":"Canada Lynx","x":-1001.9783325195312,"y":2532.795166015625,"id":"522","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"James Hansen","x":-478.28204345703125,"y":734.7833251953125,"id":"1014","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Peak Oil","x":-1167.2392578125,"y":524.763427734375,"id":"430","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Croissance Economique","x":481.40350341796875,"y":-1703.0057373046875,"id":"645","color":"rgb(153,0,0)","size":4.781970500946045},{"label":"Nature Center","x":-635.1229248046875,"y":819.4346313476562,"id":"1388","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Frederick Albert","x":-824.1995849609375,"y":1089.054931640625,"id":"1026","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Amirauté Britannique","x":122.9698715209961,"y":-869.6787109375,"id":"231","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Remote Operated Vehicle","x":531.0745239257812,"y":1574.986572265625,"id":"1430","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Banquise","x":234.07656860351562,"y":-241.07652282714844,"id":"404","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Islande","x":-635.1261596679688,"y":-631.5878295898438,"id":"1230","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Phytoplancton","x":565.5634765625,"y":-889.5340576171875,"id":"1485","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Revendications Territoriales En Arctique","x":236.14395141601562,"y":-373.0220642089844,"id":"1597","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Uiuc","x":-757.5460815429688,"y":900.6135864257812,"id":"1692","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Perturbation","x":-162.2955322265625,"y":2552.986572265625,"id":"1475","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Baie De Baffin","x":-173.62672424316406,"y":93.36151123046875,"id":"382","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Arktika 2007","x":-125.97048950195312,"y":542.8394165039062,"id":"337","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Passage Du Nord-Ouest","x":-103.84112548828125,"y":-353.5108947753906,"id":"1459","color":"rgb(153,0,0)","size":4.510906219482422},{"label":"Co2 Emission","x":-571.61376953125,"y":1040.9888916015625,"id":"549","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Cout De Production","x":729.2435913085938,"y":-1758.0506591796875,"id":"733","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Energy Source","x":-949.5540771484375,"y":1256.624755859375,"id":"906","color":"rgb(0,153,0)","size":4.510906219482422},{"label":"Barents Region","x":-1531.8826904296875,"y":1764.85791015625,"id":"414","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Pays Industrialise","x":573.6298217773438,"y":-1248.1722412109375,"id":"592","color":"rgb(0,153,0)","size":4.936610698699951},{"label":"Nanisivik","x":-1202.904296875,"y":1798.4354248046875,"id":"1376","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Froid","x":1200.5894775390625,"y":-1286.499755859375,"id":"1031","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Ère Glaciaire","x":836.2801513671875,"y":-528.111083984375,"id":"925","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Carrefour Internet","x":-1480.3045654296875,"y":-671.3770141601562,"id":"1439","color":"rgb(153,0,0)","size":4.0},{"label":"Earth Observing","x":331.4771728515625,"y":1300.4405517578125,"id":"848","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Statoilhydro","x":-2194.32373046875,"y":788.8901977539062,"id":"1651","color":"rgb(102,0,102)","size":4.206028938293457},{"label":"Style De Vie","x":-894.8253784179688,"y":-493.0680847167969,"id":"1440","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Union Soviétique","x":-763.6751708984375,"y":-1542.8663330078125,"id":"33","color":"rgb(255,51,51)","size":4.510906219482422},{"label":"Carburant Fossile","x":831.7618408203125,"y":-1143.6112060546875,"id":"550","color":"rgb(0,153,0)","size":4.206028938293457},{"label":"Archives Climatiques","x":951.119384765625,"y":-398.11865234375,"id":"285","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Emile Victor","x":491.4800720214844,"y":178.28729248046875,"id":"259","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Exploitation Des Ressources Naturelles","x":442.4892272949219,"y":-1748.2611083984375,"id":"964","color":"rgb(153,0,0)","size":4.510906219482422},{"label":"Forage Research","x":2844.0498046875,"y":3273.77978515625,"id":"1020","color":"rgb(102,102,0)","size":4.0},{"label":"Gradient De Pression","x":1744.927734375,"y":-345.5768127441406,"id":"609","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Réserves D\u0027Eau Potable,1","x":748.7661743164062,"y":-1352.6942138671875,"id":"1588","attributes":{"nodedef":"n1588"},"color":"rgb(0,153,0)","size":4.293514728546143},{"label":"Compagnie Aérienne","x":-736.46435546875,"y":-424.6734619140625,"id":"21","color":"rgb(153,0,0)","size":4.206028938293457},{"label":"Developpement Economique","x":354.28936767578125,"y":-1812.65283203125,"id":"96","color":"rgb(153,0,0)","size":8.852968215942383},{"label":"Disko Bay","x":-706.180908203125,"y":1659.318359375,"id":"819","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Soleil De Minuit","x":-747.2490234375,"y":-382.99755859375,"id":"533","color":"rgb(0,204,204)","size":6.341859817504883},{"label":"Satellites","x":310.328125,"y":2452.65283203125,"id":"1616","color":"rgb(255,153,153)","size":4.39528751373291},{"label":"German Research","x":132.76564025878906,"y":1355.157470703125,"id":"1508","color":"rgb(255,255,51)","size":4.0},{"label":"Cone De Dejection","x":1378.17236328125,"y":-1311.23779296875,"id":"1640","color":"rgb(102,102,0)","size":4.0},{"label":"Île Hans","x":-107.25237274169922,"y":-442.64801025390625,"id":"1176","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Drapeau Russe En Titane","x":-242.6774444580078,"y":-629.63525390625,"id":"840","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Calcul Des Variations","x":1703.5733642578125,"y":-715.7037353515625,"id":"1132","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Agriculture Biologique","x":1389.9615478515625,"y":-1890.01220703125,"id":"152","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Station Spatiale","x":1019.3164672851562,"y":553.3150634765625,"id":"138","color":"rgb(255,153,153)","size":4.075808525085449},{"label":"Invasive Species","x":-38.249080657958984,"y":-809.7889404296875,"id":"467","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Agroalimentaire Canada","x":1231.261962890625,"y":-1122.6280517578125,"id":"158","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Brise Thermique","x":1796.84521484375,"y":-1453.11962890625,"id":"1634","color":"rgb(255,255,51)","size":4.0},{"label":"Natural Resource","x":-338.9927062988281,"y":600.8294677734375,"id":"150","color":"rgb(0,153,0)","size":6.584775924682617},{"label":"Mackenzie Basin","x":-1819.001708984375,"y":1630.96533203125,"id":"1311","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Atmospheric Administration","x":212.73204040527344,"y":1831.9705810546875,"id":"307","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Brise-Glace Nucléaire","x":-14.00204849243164,"y":-612.0587158203125,"id":"501","color":"rgb(255,51,51)","size":4.510906219482422},{"label":"Liquid Water","x":775.841552734375,"y":1468.2659912109375,"id":"627","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Arctic Circle","x":-1167.511474609375,"y":1866.387451171875,"id":"292","color":"rgb(0,204,204)","size":8.852968215942383},{"label":"British Columbia","x":-680.8260498046875,"y":1174.98583984375,"id":"149","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Prudhoe Bay","x":-2199.666748046875,"y":1069.3577880859375,"id":"195","color":"rgb(102,0,102)","size":4.781970500946045},{"label":"Axel Heiberg","x":-875.6810302734375,"y":2022.853271484375,"id":"376","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Êtres Vivants","x":1280.424560546875,"y":-1506.078369140625,"id":"576","color":"rgb(153,255,0)","size":5.103478908538818},{"label":"Nord","x":-1128.7164306640625,"y":-480.7825622558594,"id":"1398","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Grand Migrateur","x":413.6694641113281,"y":-1600.87353515625,"id":"1135","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Voie Navigable","x":303.36151123046875,"y":-2323.163818359375,"id":"531","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Petrole Brut","x":-304.07794189453125,"y":-1465.567626953125,"id":"424","color":"rgb(102,0,102)","size":6.584775924682617},{"label":"Steve Morse","x":-1578.6285400390625,"y":125.89031982421875,"id":"1371","color":"rgb(153,255,0)","size":4.0},{"label":"Opportunité","x":-1325.32763671875,"y":-624.910888671875,"id":"1438","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Morue De L\u0027Atlantique,1","x":1.2945709228515625,"y":-1095.300048828125,"id":"1372","attributes":{"nodedef":"n1372"},"color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Modèles Climatiques Informatiques","x":322.5306091308594,"y":324.6382751464844,"id":"1363","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Guerre Froide","x":-629.8975219726562,"y":-1472.99658203125,"id":"217","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Polarstern","x":34.676597595214844,"y":1259.896484375,"id":"1507","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Northwest Passage","x":-690.6357421875,"y":1953.7867431640625,"id":"304","color":"rgb(153,0,0)","size":4.293514728546143},{"label":"Oil Drill","x":-2590.5537109375,"y":882.829345703125,"id":"40","color":"rgb(102,0,102)","size":4.6399359703063965},{"label":"Arctic National","x":-2465.8466796875,"y":850.1004028320312,"id":"270","color":"rgb(153,255,0)","size":5.6738481521606445},{"label":"High Place","x":-1380.56591796875,"y":200.6070556640625,"id":"1158","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Nord Magnétique","x":557.978515625,"y":581.586669921875,"id":"267","color":"rgb(153,255,255)","size":6.584775924682617},{"label":"Espace Naturel","x":568.6636352539062,"y":-1583.75244140625,"id":"915","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"Lisière De La Glace","x":184.7472686767578,"y":-611.1664428710938,"id":"1296","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Coast Guards","x":-534.0105590820312,"y":-614.1861572265625,"id":"1338","color":"rgb(255,51,51)","size":4.0},{"label":"Migration Des Rennes","x":-593.470458984375,"y":-594.5366821289062,"id":"1353","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Ecologie Profonde","x":595.971435546875,"y":-1096.5831298828125,"id":"877","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Capacité Calorifique","x":2820.78125,"y":-687.0199584960938,"id":"539","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Laboratoire De Mécanique","x":2629.334228515625,"y":406.2079772949219,"id":"664","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Lávvu","x":-2022.188720703125,"y":2395.55615234375,"id":"1281","color":"rgb(204,204,255)","size":4.075808525085449},{"label":"Dorsale De Lomonossov","x":29.32948875427246,"y":-721.5557861328125,"id":"833","color":"rgb(255,51,51)","size":5.472443103790283},{"label":"Climat Continental","x":1238.1683349609375,"y":-723.8411865234375,"id":"236","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Peuple Indigène","x":-120.85368347167969,"y":-765.8795776367188,"id":"731","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Champ Magnétique","x":837.4072265625,"y":444.8371276855469,"id":"113","color":"rgb(255,255,51)","size":9.501245498657227},{"label":"Fonte Banquise","x":404.0470275878906,"y":138.27108764648438,"id":"1016","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Gas Transmission","x":-2304.46142578125,"y":765.5785522460938,"id":"1039","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Valley Pipeline","x":-1920.1005859375,"y":1382.6810302734375,"id":"787","color":"rgb(102,0,102)","size":4.6399359703063965},{"label":"Intérêts Scientifiques","x":1755.324951171875,"y":-487.8387451171875,"id":"1215","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"University Of Tromsø","x":-1464.7073974609375,"y":2000.673583984375,"id":"1691","color":"rgb(0,204,204)","size":4.0},{"label":"Moraines","x":-426.2164001464844,"y":1818.9564208984375,"id":"1368","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Lever De Soleil","x":1821.1827392578125,"y":-1282.8504638671875,"id":"738","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Compagnie Pétrolière","x":-312.8392028808594,"y":-1654.1334228515625,"id":"437","color":"rgb(102,0,102)","size":7.099246978759766},{"label":"Images Satellites","x":741.8519897460938,"y":1143.925048828125,"id":"1184","color":"rgb(255,153,153)","size":4.293514728546143},{"label":"Qualite De Vie","x":53.828861236572266,"y":-1637.9798583984375,"id":"812","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Plaque Continentale","x":1758.8013916015625,"y":-631.8386840820312,"id":"835","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Energy Technology Laboratory","x":-533.006591796875,"y":1278.4935302734375,"id":"910","color":"rgb(102,255,102)","size":4.0},{"label":"Équilibre Chimique","x":2451.575439453125,"y":-1055.55615234375,"id":"922","color":"rgb(255,204,102)","size":4.0340681076049805},{"label":"Kelvin Scale","x":1147.1556396484375,"y":2560.599853515625,"id":"71","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Arctic Expedition","x":-698.1810302734375,"y":1821.115478515625,"id":"301","color":"rgb(0,204,204)","size":5.103478908538818},{"label":"Cendre Volcanique","x":1609.515625,"y":-563.578125,"id":"562","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Ann Bancroft","x":-205.17994689941406,"y":1289.1558837890625,"id":"254","color":"rgb(255,255,51)","size":5.103478908538818},{"label":"National Energy Technology","x":-885.4706420898438,"y":1109.333251953125,"id":"1382","color":"rgb(102,255,102)","size":4.0},{"label":"Convention Des Nations Unies Sur Le Droit De La Mer","x":-161.36451721191406,"y":-1443.8486328125,"id":"716","color":"rgb(153,0,0)","size":4.510906219482422},{"label":"Natural Gas","x":-1409.1258544921875,"y":423.159423828125,"id":"1047","color":"rgb(0,153,0)","size":4.133297443389893},{"label":"Journée Mondiale De La Biodiversité","x":311.27545166015625,"y":-1096.246337890625,"id":"1256","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Contamination Radioactive","x":-548.1245727539062,"y":-1011.6006469726562,"id":"705","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Méthode Merise","x":1445.80322265625,"y":-1454.8597412109375,"id":"1352","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"San Francisco","x":-1114.530029296875,"y":581.2503051757812,"id":"5","color":"rgb(255,51,51)","size":5.103478908538818},{"label":"Frédéric Lasserre","x":-379.4819030761719,"y":-104.75343322753906,"id":"412","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Environmental Studies","x":311.84100341796875,"y":-220.78436279296875,"id":"632","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Temperature Sensor","x":1153.5224609375,"y":2657.78515625,"id":"1671","color":"rgb(255,255,51)","size":4.0},{"label":"Sverdrup","x":-815.9874267578125,"y":2120.587158203125,"id":"1658","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Inuit Circumpolar","x":-1038.5679931640625,"y":2173.03125,"id":"526","color":"rgb(204,204,255)","size":4.781970500946045},{"label":"Jaures Medvedev","x":-109.4727554321289,"y":-1361.7779541015625,"id":"1242","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Naomi Uemura","x":-1082.544677734375,"y":2133.81494140625,"id":"1356","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Roger Brunet","x":360.7059020996094,"y":-632.6066284179688,"id":"757","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Crise Ecologique","x":565.8154296875,"y":-1118.103271484375,"id":"740","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Europe Via","x":-1288.2213134765625,"y":-133.4451446533203,"id":"949","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Proue Surélevée","x":401.95635986328125,"y":-2106.44091796875,"id":"1551","color":"rgb(153,0,0)","size":4.0},{"label":"Biosphère","x":-1003.8191528320312,"y":1405.8773193359375,"id":"472","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Nicolas Vanier","x":-923.4484252929688,"y":-344.1199951171875,"id":"1136","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Energie Renouvelable","x":817.0204467773438,"y":-1168.9273681640625,"id":"104","color":"rgb(0,153,0)","size":19.1311092376709},{"label":"North Norway","x":-1367.631591796875,"y":1979.0384521484375,"id":"417","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"National Snow","x":71.34999084472656,"y":1415.9742431640625,"id":"46","color":"rgb(153,255,255)","size":5.282204627990723},{"label":"Quebec Government","x":-1329.685546875,"y":2897.574462890625,"id":"1424","color":"rgb(0,204,204)","size":4.0},{"label":"Pressure Treat","x":-335.1393737792969,"y":840.61328125,"id":"1147","color":"rgb(102,255,102)","size":4.0},{"label":"Jacobs Engineering","x":-847.073486328125,"y":2264.95849609375,"id":"1659","color":"rgb(0,204,204)","size":4.0},{"label":"Oil Price","x":-1909.205322265625,"y":688.3704833984375,"id":"429","color":"rgb(102,0,102)","size":5.472443103790283},{"label":"Baltic Sea","x":-1349.2330322265625,"y":782.0280151367188,"id":"401","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Finnish Lapland","x":-1341.6407470703125,"y":2100.314697265625,"id":"988","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"North Greenland","x":-376.8964538574219,"y":1782.964599609375,"id":"1405","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Azote Kjeldahl","x":1249.180908203125,"y":-1604.6259765625,"id":"143","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Dérive Transpolaire","x":90.34806060791016,"y":-77.55829620361328,"id":"799","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Etats Arctiques","x":220.3595428466797,"y":-632.3721923828125,"id":"944","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Gaz","x":511.72564697265625,"y":-1272.9373779296875,"id":"1041","color":"rgb(0,153,0)","size":4.293514728546143},{"label":"Île De Sakhaline","x":-421.34039306640625,"y":-1212.58935546875,"id":"1000","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Eruption Solaire","x":813.0960083007812,"y":220.2419891357422,"id":"115","color":"rgb(255,255,51)","size":4.781970500946045},{"label":"Arctic Science","x":-678.52099609375,"y":1757.73486328125,"id":"326","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Flam Railway","x":-1862.12841796875,"y":2014.658935546875,"id":"998","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Scandinavie","x":-844.7327270507812,"y":-715.8115234375,"id":"1618","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Oléoducs","x":-301.7325134277344,"y":-1280.14111328125,"id":"1435","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Formation Géologique","x":1130.813720703125,"y":-1306.9691162109375,"id":"862","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Balbuzard Pêcheur","x":-261.09759521484375,"y":-860.1210327148438,"id":"389","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Langue Scandinave","x":-879.9846801757812,"y":-795.6299438476562,"id":"1272","color":"rgb(204,204,255)","size":4.0086140632629395},{"label":"University Of Natural","x":-261.92498779296875,"y":1613.1439208984375,"id":"1600","color":"rgb(153,255,255)","size":4.0},{"label":"Pole Expedition","x":-536.613037109375,"y":1839.82470703125,"id":"256","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Beaufort Sea","x":-1314.319091796875,"y":1486.2528076171875,"id":"321","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Earth Sciences","x":140.06918334960938,"y":949.2770385742188,"id":"849","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Laponie Suédoise","x":-676.6172485351562,"y":-447.30023193359375,"id":"748","color":"rgb(204,204,255)","size":5.282204627990723},{"label":"Écosystèmes Marins","x":541.1787109375,"y":-776.7356567382812,"id":"884","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Global positioning","x":169.76914978027344,"y":3209.15771484375,"id":"1060","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Energie Fossile","x":567.6663208007812,"y":-1162.6912841796875,"id":"131","color":"rgb(0,153,0)","size":8.540210723876953},{"label":"Répercussions","x":-1328.6962890625,"y":178.18540954589844,"id":"1585","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Climatic Change","x":-308.025146484375,"y":1221.129638671875,"id":"79","color":"rgb(102,255,102)","size":79.5716781616211},{"label":"Council Of Canada","x":-1029.6468505859375,"y":1089.7691650390625,"id":"521","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Sayan Mountains","x":-1673.0694580078125,"y":-901.0927124023438,"id":"1614","color":"rgb(204,204,255)","size":4.0},{"label":"Chaine Alimentaire","x":1030.9202880859375,"y":-1390.243896484375,"id":"519","color":"rgb(153,255,0)","size":6.341859817504883},{"label":"Sognefjorden","x":-1595.1903076171875,"y":2023.157470703125,"id":"1637","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Circulation Océanique","x":881.097900390625,"y":-373.423095703125,"id":"515","color":"rgb(255,255,51)","size":6.584775924682617},{"label":"Pouvoir Public","x":746.6023559570312,"y":-1559.674072265625,"id":"97","color":"rgb(153,255,0)","size":5.103478908538818},{"label":"Communique De Presse","x":187.27760314941406,"y":-1929.7447509765625,"id":"1394","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Celsius Temperature","x":1085.2469482421875,"y":2629.656494140625,"id":"561","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Suède","x":-1009.474365234375,"y":84.77333068847656,"id":"1654","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Economie Gestion","x":1995.5655517578125,"y":-56.462928771972656,"id":"879","color":"rgb(255,255,51)","size":4.0},{"label":"Île Melville","x":-466.9360656738281,"y":57.297176361083984,"id":"1178","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Programme Pluriannuel De Recherche","x":1765.3302001953125,"y":-807.9656982421875,"id":"1545","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Profil Environnemental","x":663.1678466796875,"y":-1452.0347900390625,"id":"1543","color":"rgb(0,153,0)","size":4.39528751373291},{"label":"Technique De Randonnée","x":2199.39501953125,"y":-1483.310302734375,"id":"1680","color":"rgb(255,255,51)","size":4.0},{"label":"Empreinte Écologique","x":758.0026245117188,"y":-1200.9490966796875,"id":"901","color":"rgb(102,255,102)","size":5.103478908538818},{"label":"Northwest Territories","x":-1446.688232421875,"y":1508.540283203125,"id":"323","color":"rgb(0,204,204)","size":4.936610698699951},{"label":"Données Climatiques","x":1194.1854248046875,"y":-894.2398681640625,"id":"828","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Lagopède","x":-378.12152099609375,"y":-444.1365051269531,"id":"1271","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Umberto Nobile","x":-583.5703735351562,"y":1976.1595458984375,"id":"1694","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Claude Gascard","x":395.4162902832031,"y":-179.3833770751953,"id":"631","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Mer Polaire Ouverte","x":92.1793441772461,"y":1011.4505004882812,"id":"1345","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Droit De Passage","x":1362.7652587890625,"y":-2079.392578125,"id":"844","color":"rgb(153,0,0)","size":4.0},{"label":"Nord Du Canada","x":-149.541259765625,"y":-413.6909484863281,"id":"1401","color":"rgb(255,51,51)","size":4.781970500946045},{"label":"Activité Humaine","x":1020.486083984375,"y":-997.356689453125,"id":"68","color":"rgb(102,255,102)","size":39.22166061401367},{"label":"Emissions De Co2","x":700.1669311523438,"y":-1030.9810791015625,"id":"93","color":"rgb(102,255,102)","size":9.173389434814453},{"label":"Interglacial Period","x":-285.3956604003906,"y":1658.77197265625,"id":"1102","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Declaration De Doha","x":22.64794158935547,"y":-1824.061279296875,"id":"774","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Grands Lacs","x":360.0180358886719,"y":-912.3419189453125,"id":"80","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Laboratoire Kastler","x":1787.1490478515625,"y":65.69087982177734,"id":"674","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Baie De Disko","x":-122.5660171508789,"y":135.06480407714844,"id":"383","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Ajustement Structurel","x":577.732421875,"y":-1725.208740234375,"id":"173","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"Indigenous Population","x":-1743.23681640625,"y":2319.311767578125,"id":"1195","color":"rgb(204,204,255)","size":4.0},{"label":"Konungariket Sverige","x":-1090.12109375,"y":833.55322265625,"id":"1261","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Finnish Companies","x":-957.6561889648438,"y":-1628.5633544921875,"id":"985","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Sols","x":1887.2938232421875,"y":-459.31365966796875,"id":"1641","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Longues Distances","x":-2320.859375,"y":-1128.3441162109375,"id":"1306","color":"rgb(204,204,255)","size":4.0},{"label":"Armée Américaine","x":-1105.5269775390625,"y":-114.18011474609375,"id":"341","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Iles Kouriles","x":-282.15093994140625,"y":-1069.7958984375,"id":"1175","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Photographie Aerienne","x":1980.08544921875,"y":-1403.850341796875,"id":"1196","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Natural Repair","x":1594.8365478515625,"y":-897.4264526367188,"id":"679","color":"rgb(255,204,102)","size":4.0},{"label":"Phoque Gris","x":-215.6255645751953,"y":-1140.5015869140625,"id":"1316","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Alaska State","x":-3147.713623046875,"y":2533.282470703125,"id":"189","color":"rgb(0,204,204)","size":4.0},{"label":"Tigre De Siberie","x":-72.00604248046875,"y":-1002.9564208984375,"id":"168","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Capteur De Pression","x":2150.798583984375,"y":-587.2140502929688,"id":"434","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Écologie Pratique","x":1065.259033203125,"y":-1147.25,"id":"874","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"New values","x":-154.02786254882812,"y":1974.202392578125,"id":"972","color":"rgb(0,204,204)","size":4.0},{"label":"Indicateur Climatique","x":1028.111328125,"y":-458.3717956542969,"id":"1191","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Aeronautical Engineering","x":-566.309814453125,"y":2136.8984375,"id":"1695","color":"rgb(153,255,255)","size":4.0},{"label":"Écologie Des Populations","x":1250.4727783203125,"y":-1381.619384765625,"id":"875","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Plateformes","x":1534.6314697265625,"y":-1326.825927734375,"id":"1497","color":"rgb(255,255,51)","size":4.0},{"label":"Réchauffement Différentiel","x":1635.4635009765625,"y":-296.90118408203125,"id":"1560","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Marine Royale","x":-1010.1068725585938,"y":-2144.4228515625,"id":"1322","color":"rgb(255,51,51)","size":4.0},{"label":"Phénomène Naturel","x":1266.3018798828125,"y":-1267.392333984375,"id":"1478","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Renard Gris","x":-711.9309692382812,"y":-865.7280883789062,"id":"1580","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Fonte","x":-954.379638671875,"y":155.9615020751953,"id":"1010","color":"rgb(0,204,204)","size":4.0},{"label":"Conditions Météorologiques","x":1496.9547119140625,"y":-782.289794921875,"id":"681","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Biogeochemical Cycle","x":-720.203369140625,"y":1154.4080810546875,"id":"462","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Glace","x":467.92193603515625,"y":1068.4384765625,"id":"1088","color":"rgb(153,255,255)","size":4.0086140632629395},{"label":"Plateformes De Forage","x":-32.178138732910156,"y":-1701.26904296875,"id":"1498","color":"rgb(102,0,102)","size":4.075808525085449},{"label":"Convention Internationale","x":27.588159561157227,"y":-1738.7987060546875,"id":"710","color":"rgb(153,0,0)","size":4.510906219482422},{"label":"Carte Géologique","x":1361.2398681640625,"y":-744.355224609375,"id":"436","color":"rgb(255,204,102)","size":5.103478908538818},{"label":"Dérèglement Climatique","x":818.4898071289062,"y":-1077.4920654296875,"id":"245","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Menace","x":-1735.708984375,"y":23.019989013671875,"id":"1331","color":"rgb(255,51,51)","size":4.0},{"label":"Polar Explorer","x":-540.6795043945312,"y":1721.8673095703125,"id":"183","color":"rgb(153,255,255)","size":5.472443103790283},{"label":"Energie Interne","x":2853.764892578125,"y":-711.9080810546875,"id":"540","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Fishing Ship","x":-2195.95947265625,"y":1698.998291015625,"id":"989","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Farthest North","x":-489.3768005371094,"y":1994.6044921875,"id":"978","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Agriculture Intensive","x":1194.085693359375,"y":-1809.0849609375,"id":"157","color":"rgb(102,102,0)","size":4.0340681076049805},{"label":"Ellesmere Island","x":-791.665771484375,"y":1980.0880126953125,"id":"377","color":"rgb(0,204,204)","size":4.781970500946045},{"label":"Connaissance Scientifique","x":1104.625732421875,"y":-1029.750732421875,"id":"693","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Produit Derive","x":1291.8006591796875,"y":-784.8773193359375,"id":"1494","color":"rgb(255,204,102)","size":4.0},{"label":"Perdrix Des Neiges","x":-556.744873046875,"y":-505.8311767578125,"id":"746","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Alain Hubert","x":-147.12803649902344,"y":1327.6324462890625,"id":"180","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Bay Oil","x":-1974.5218505859375,"y":957.7298583984375,"id":"449","color":"rgb(102,0,102)","size":4.075808525085449},{"label":"Mecanique Des Fluides","x":2573.458984375,"y":312.06390380859375,"id":"888","color":"rgb(255,255,0)","size":4.510906219482422},{"label":"Energy Conference","x":-1079.1385498046875,"y":1234.311279296875,"id":"905","color":"rgb(0,153,0)","size":4.075808525085449},{"label":"Revendication","x":265.2763366699219,"y":-1583.3365478515625,"id":"1595","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Management Environnemental","x":843.4338989257812,"y":-1657.6605224609375,"id":"251","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Bering Sea","x":-856.4624633789062,"y":1048.4078369140625,"id":"203","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Protocole De Kyoto","x":804.7012939453125,"y":-946.403076171875,"id":"105","color":"rgb(102,255,102)","size":7.099246978759766},{"label":"Northern University","x":-1368.3258056640625,"y":116.15547180175781,"id":"1437","color":"rgb(255,255,51)","size":4.0},{"label":"Impacts Environnementaux","x":916.9364624023438,"y":-1329.6590576171875,"id":"1187","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Eaux Internationales","x":-45.005516052246094,"y":-1584.10498046875,"id":"869","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Department Of Physics","x":114.74959564208984,"y":793.4013671875,"id":"790","color":"rgb(153,255,255)","size":4.0086140632629395},{"label":"Phoque Moine","x":174.09072875976562,"y":-1117.7325439453125,"id":"1479","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Jules Verne","x":292.7366027832031,"y":628.7774047851562,"id":"508","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Marcel Leroux","x":493.2509765625,"y":-352.26470947265625,"id":"1319","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Écotourisme Québec","x":-421.915771484375,"y":-885.8495483398438,"id":"886","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Afge Local","x":-3463.37109375,"y":-1966.770751953125,"id":"1059","color":"rgb(51,153,255)","size":4.0},{"label":"Grande Puissance","x":-423.2604064941406,"y":-1298.2620849609375,"id":"970","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Américains Du Nord","x":45.0167121887207,"y":-631.6409301757812,"id":"222","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Port De Montreal","x":245.47291564941406,"y":385.5518798828125,"id":"1627","color":"rgb(0,204,204)","size":4.0},{"label":"Croyances Animistes Traditionnelles","x":-616.6427612304688,"y":-652.6201171875,"id":"745","color":"rgb(204,204,255)","size":4.206028938293457},{"label":"Programme De Doha","x":-21.686321258544922,"y":-1883.6951904296875,"id":"1213","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Centre De Gravité","x":3091.731689453125,"y":953.8211059570312,"id":"1528","color":"rgb(255,255,0)","size":4.0},{"label":"Croissance De La Population","x":635.1356201171875,"y":-1875.99609375,"id":"743","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Impact Activités Humaines","x":736.72216796875,"y":-612.231201171875,"id":"1186","color":"rgb(255,255,51)","size":4.0},{"label":"Mer Gelée","x":1194.6021728515625,"y":-504.497802734375,"id":"1344","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Changement Climatique","x":639.014892578125,"y":-703.6633911132812,"id":"53","color":"rgb(102,255,102)","size":99.99999237060547},{"label":"Extinction","x":-623.718505859375,"y":764.0315551757812,"id":"973","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Atacama Large","x":-1263.72509765625,"y":2407.256103515625,"id":"55","color":"rgb(0,204,204)","size":4.0},{"label":"International Conference","x":-1029.4451904296875,"y":853.9440307617188,"id":"685","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Joik","x":-1815.1776123046875,"y":2372.54052734375,"id":"1247","color":"rgb(204,204,255)","size":4.075808525085449},{"label":"Celsius Scale","x":1050.712646484375,"y":2602.3388671875,"id":"72","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Mer De Laptev","x":148.3580322265625,"y":-263.6416320800781,"id":"1339","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Isfjord","x":-731.637451171875,"y":1618.5643310546875,"id":"1226","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Iles Aleoutiennes","x":-252.2587432861328,"y":-786.9063720703125,"id":"199","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Université Joseph","x":1623.983154296875,"y":505.6729431152344,"id":"1079","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Gestion Des Ressources","x":540.045654296875,"y":-1682.798095703125,"id":"101","color":"rgb(0,153,0)","size":5.103478908538818},{"label":"Arctique","x":108.06491088867188,"y":-182.56524658203125,"id":"333","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Glacial Lake","x":-325.3822326660156,"y":1850.6939697265625,"id":"1094","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Mecanique Des Milieux Continus","x":2787.80224609375,"y":384.6292724609375,"id":"1303","color":"rgb(255,255,0)","size":4.133297443389893},{"label":"Sédiments","x":-930.0875854492188,"y":1070.3548583984375,"id":"1625","color":"rgb(0,153,0)","size":4.133297443389893},{"label":"Réversiblité","x":1091.1778564453125,"y":-961.290771484375,"id":"1598","color":"rgb(255,204,102)","size":4.0340681076049805},{"label":"Documentaires Reportages","x":-139.54441833496094,"y":-13.036221504211426,"id":"956","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Mourmansk","x":-950.3997192382812,"y":-471.90557861328125,"id":"1375","color":"rgb(0,204,204)","size":4.0},{"label":"Johannesburg 2002.","x":-308.7962341308594,"y":137.21817016601562,"id":"1245","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Extinction Massive","x":585.7884521484375,"y":-821.8596801757812,"id":"975","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Joseph Fourier","x":1753.0748291015625,"y":527.2044677734375,"id":"1078","color":"rgb(255,255,51)","size":4.206028938293457},{"label":"Puissances Militaires","x":-586.8568725585938,"y":-1493.1463623046875,"id":"1552","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Population","x":-936.8165283203125,"y":347.7954406738281,"id":"1522","color":"rgb(255,51,51)","size":4.0},{"label":"Canadian Navy","x":-987.0184936523438,"y":-2168.454345703125,"id":"1321","color":"rgb(255,51,51)","size":4.0},{"label":"Sami Culture","x":-1937.94482421875,"y":2468.69091796875,"id":"1282","color":"rgb(204,204,255)","size":5.282204627990723},{"label":"Repérage Satellite","x":-307.4222106933594,"y":2304.399658203125,"id":"1584","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Réchauffement Climatique","x":480.5789489746094,"y":-476.38458251953125,"id":"50","color":"rgb(102,255,102)","size":56.631980895996094},{"label":"Earth Explorer","x":-1058.8309326171875,"y":1358.3682861328125,"id":"751","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Simulation Numérique","x":2325.76318359375,"y":225.4872283935547,"id":"661","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Meteorological Station","x":-1598.993896484375,"y":2188.527587890625,"id":"1240","color":"rgb(0,204,204)","size":4.0},{"label":"Lng Carrier","x":-2107.6708984375,"y":1014.72021484375,"id":"1297","color":"rgb(102,0,102)","size":4.0086140632629395},{"label":"Barrage Hydroélectrique","x":548.54150390625,"y":-1642.50537109375,"id":"425","color":"rgb(0,153,0)","size":4.206028938293457},{"label":"Discipline Scientifique","x":1859.9405517578125,"y":-169.36407470703125,"id":"1106","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Yvon Le Maho","x":648.9661254882812,"y":-544.9031372070312,"id":"1719","color":"rgb(255,204,102)","size":4.0086140632629395},{"label":"Norwegian Polar Institute","x":-563.6276245117188,"y":1612.9364013671875,"id":"1416","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Polar Expedition","x":-636.3841552734375,"y":1911.3157958984375,"id":"302","color":"rgb(153,255,255)","size":5.103478908538818},{"label":"Laboratoire De Météorologie","x":1433.879150390625,"y":-248.84622192382812,"id":"1263","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Ecological Footprint","x":174.93313598632812,"y":-522.507080078125,"id":"872","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Prospection Electromagnetique","x":2055.60400390625,"y":625.3250122070312,"id":"1549","color":"rgb(255,255,51)","size":4.0},{"label":"Agricultural Land","x":-503.6853332519531,"y":1084.8663330078125,"id":"148","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Forcage Radiatif","x":854.035400390625,"y":-816.6619873046875,"id":"461","color":"rgb(255,204,102)","size":4.781970500946045},{"label":"Russian Gas","x":-1841.2296142578125,"y":488.3793640136719,"id":"208","color":"rgb(102,0,102)","size":5.103478908538818},{"label":"Canadian Arctic","x":-870.5809936523438,"y":1920.4820556640625,"id":"294","color":"rgb(255,51,51)","size":7.9385457038879395},{"label":"Latitude 66° 33\u0027N,1","x":362.4998779296875,"y":-522.8916015625,"id":"1280","attributes":{"nodedef":"n1280"},"color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Josef Land","x":-881.2371826171875,"y":2143.9130859375,"id":"415","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Climatologie","x":1387.076904296875,"y":-654.1448974609375,"id":"639","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Arctic Sea","x":-90.56189727783203,"y":1657.809814453125,"id":"311","color":"rgb(153,255,255)","size":5.6738481521606445},{"label":"Science Nord","x":-1296.1273193359375,"y":-539.59521484375,"id":"1399","color":"rgb(153,255,255)","size":4.0},{"label":"Bloc Erratique","x":448.885009765625,"y":-417.5223693847656,"id":"480","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Energie Primaire","x":536.199462890625,"y":-1360.2603759765625,"id":"904","color":"rgb(0,153,0)","size":4.6399359703063965},{"label":"Soil Science","x":662.3010864257812,"y":-840.2737426757812,"id":"930","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Environment Programme","x":-306.8843994140625,"y":557.0643920898438,"id":"89","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Extent Minimum","x":-193.59140014648438,"y":1815.1783447265625,"id":"971","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Glaciologie","x":436.9810791015625,"y":789.4720458984375,"id":"1104","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Pôle Nord Géomagnétique","x":310.8309020996094,"y":815.92431640625,"id":"1509","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Frontière Terrestre","x":-394.6021728515625,"y":-1488.3306884765625,"id":"1032","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Arctic Ice","x":-255.33016967773438,"y":1737.73486328125,"id":"310","color":"rgb(0,204,204)","size":6.108868598937988},{"label":"Thon Rouge","x":206.93438720703125,"y":-1359.9771728515625,"id":"1373","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Petroleum Product","x":-2264.662841796875,"y":747.086669921875,"id":"1434","color":"rgb(102,0,102)","size":4.133297443389893},{"label":"Végétation Locale","x":1114.59375,"y":-1471.4329833984375,"id":"1705","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Navire De Recherche","x":70.53507232666016,"y":-244.04432678222656,"id":"839","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Atmosphère Terrestre","x":1137.197509765625,"y":-371.8663635253906,"id":"363","color":"rgb(255,255,0)","size":5.282204627990723},{"label":"Coopération","x":-558.1478271484375,"y":376.72161865234375,"id":"719","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Hydrographic Survey","x":586.7369384765625,"y":1790.6697998046875,"id":"564","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Biomes Of The World","x":-1001.8667602539062,"y":2355.270263671875,"id":"470","color":"rgb(204,204,255)","size":4.0086140632629395},{"label":"Méthanier","x":104.27997589111328,"y":-1588.522216796875,"id":"1351","color":"rgb(102,0,102)","size":4.293514728546143},{"label":"Carbon Sequestration","x":-788.3623046875,"y":1279.9970703125,"id":"548","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Observatoire De Recherche","x":1151.910888671875,"y":-865.9721069335938,"id":"1025","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Observation System","x":631.1531982421875,"y":1363.797607421875,"id":"847","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Empreinte Energetique","x":566.9852294921875,"y":-1052.157470703125,"id":"903","color":"rgb(0,153,0)","size":4.6399359703063965},{"label":"Cap Lizard","x":-314.93060302734375,"y":-164.61312866210938,"id":"357","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Sciences Sociales","x":1755.0657958984375,"y":-379.21099853515625,"id":"1624","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Matiere Organique","x":1244.5677490234375,"y":-1558.487548828125,"id":"120","color":"rgb(153,255,0)","size":10.527388572692871},{"label":"Coastal Plain","x":-2725.831298828125,"y":941.7975463867188,"id":"38","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"Déclaration De Rio","x":612.9371948242188,"y":-1074.5045166015625,"id":"688","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Gas Company","x":-2017.2681884765625,"y":624.8248291015625,"id":"209","color":"rgb(102,0,102)","size":6.341859817504883},{"label":"North Magnetic","x":-10.140995025634766,"y":1495.694580078125,"id":"622","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Island Expedition","x":-829.6738891601562,"y":1681.056640625,"id":"1227","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Sonde De Temperature","x":2307.5634765625,"y":-551.9292602539062,"id":"544","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Clark Ross","x":568.3779296875,"y":671.209228515625,"id":"455","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Volcanic Plateau","x":-1624.3095703125,"y":1801.562744140625,"id":"1704","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Space Science","x":1044.7261962890625,"y":1038.4227294921875,"id":"861","color":"rgb(255,153,153)","size":4.133297443389893},{"label":"Oceanographie Physique","x":966.4908447265625,"y":-283.2160339355469,"id":"1432","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Sommet De Johannesburg","x":258.27178955078125,"y":-813.4686889648438,"id":"1246","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Ice Data","x":-11.349913597106934,"y":1434.9552001953125,"id":"45","color":"rgb(153,255,255)","size":6.837328910827637},{"label":"Couverture Végétale","x":1250.3302001953125,"y":-1848.6412353515625,"id":"735","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Missiles Balistiques","x":-828.7572631835938,"y":-1458.7127685546875,"id":"1361","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Nouvel Environnement","x":1604.5255126953125,"y":-1706.1563720703125,"id":"1417","color":"rgb(102,255,102)","size":4.0},{"label":"Soil Erosion","x":-455.86676025390625,"y":946.5283813476562,"id":"928","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Dorsales Lomonossov","x":39.05314254760742,"y":-421.98748779296875,"id":"836","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Cnrs Umr","x":1952.6683349609375,"y":55.34114456176758,"id":"346","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"James Bay","x":-1204.0933837890625,"y":2584.969482421875,"id":"1235","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Economic Zone","x":-629.4299926757812,"y":-285.3661804199219,"id":"1284","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Nuclear Icebreaker","x":-642.9785766601562,"y":1862.987548828125,"id":"1305","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Température Constante","x":2101.514892578125,"y":-803.8215942382812,"id":"1672","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Educapoles","x":105.24282836914062,"y":835.7413330078125,"id":"891","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Barents","x":-1320.2484130859375,"y":1932.0987548828125,"id":"413","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Sea Of Ice","x":-402.9502258300781,"y":1698.795654296875,"id":"185","color":"rgb(153,255,255)","size":14.352338790893555},{"label":"Pole Geographique","x":653.4030151367188,"y":484.79840087890625,"id":"590","color":"rgb(153,255,255)","size":5.103478908538818},{"label":"Etudes Spatiales","x":1028.2242431640625,"y":491.39324951171875,"id":"400","color":"rgb(255,153,153)","size":4.206028938293457},{"label":"Rajendra Pachauri","x":491.4423522949219,"y":14.165596961975098,"id":"1087","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Solifluxion","x":1204.88037109375,"y":-1249.0697021484375,"id":"1639","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Greenland Ice","x":-126.77063751220703,"y":1516.032958984375,"id":"638","color":"rgb(153,255,255)","size":4.936610698699951},{"label":"Eastern Arctic","x":-843.3505249023438,"y":1801.095458984375,"id":"856","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Caribou Des Bois","x":133.42225646972656,"y":-1002.9473876953125,"id":"551","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Échantillons De Glace","x":1049.4072265625,"y":-330.250732421875,"id":"871","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Port Autonome","x":-482.2939453125,"y":-1922.71484375,"id":"1138","color":"rgb(153,0,0)","size":4.39528751373291},{"label":"Sibérie Orientale","x":-269.6578063964844,"y":-701.846435546875,"id":"806","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Rythme D\u0027Exploitation,1","x":-91.83535766601562,"y":-1162.8453369140625,"id":"1605","attributes":{"nodedef":"n1605"},"color":"rgb(102,0,102)","size":4.075808525085449},{"label":"Canadian Boreal","x":-796.159423828125,"y":2042.5194091796875,"id":"485","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Convention De Montego","x":-184.02239990234375,"y":-1494.572265625,"id":"711","color":"rgb(153,0,0)","size":4.781970500946045},{"label":"Kara Sea","x":-1109.3558349609375,"y":1923.9544677734375,"id":"416","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Castors Lapons","x":-1256.1171875,"y":-228.22557067871094,"id":"1275","color":"rgb(204,204,255)","size":4.0086140632629395},{"label":"American Physical Society","x":-382.6901550292969,"y":1385.4027099609375,"id":"226","color":"rgb(102,255,102)","size":4.0},{"label":"Haut Arctique","x":-196.34776306152344,"y":-157.2665252685547,"id":"336","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Profondeur","x":829.1661376953125,"y":-1430.9351806640625,"id":"1544","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Communication Satellite","x":43.59181213378906,"y":2506.35546875,"id":"652","color":"rgb(255,153,153)","size":4.206028938293457},{"label":"Russie","x":-522.8524780273438,"y":-1415.021484375,"id":"1604","color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Impact Écologique","x":822.514892578125,"y":-1276.9775390625,"id":"1022","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Climate Crisis","x":-559.0671997070312,"y":979.5825805664062,"id":"178","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Élévation Température","x":-248.6700897216797,"y":1585.9635009765625,"id":"898","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Régions Pétrolières","x":-464.6183166503906,"y":-1464.7113037109375,"id":"1329","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Aurore Polaire","x":714.0791625976562,"y":311.250732421875,"id":"373","color":"rgb(153,255,255)","size":4.936610698699951},{"label":"Marine Science","x":434.7555847167969,"y":370.1911315917969,"id":"885","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Route Commerciale","x":281.8993225097656,"y":-792.7899169921875,"id":"758","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Passage Kennedy","x":-1272.6044921875,"y":1398.203125,"id":"1462","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Evaluation Des Risques","x":1577.1671142578125,"y":-1862.7254638671875,"id":"947","color":"rgb(102,102,0)","size":4.133297443389893},{"label":"Renard Arctique","x":-482.01922607421875,"y":-749.9813842773438,"id":"1291","color":"rgb(153,255,0)","size":4.936610698699951},{"label":"Erosion","x":-355.6134338378906,"y":958.4852294921875,"id":"927","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Forage Seed","x":2815.6865234375,"y":3295.669189453125,"id":"1021","color":"rgb(102,102,0)","size":4.0},{"label":"Température De L\u0027Eau,1","x":1581.2574462890625,"y":-736.5062255859375,"id":"1673","attributes":{"nodedef":"n1673"},"color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Ungava Bay","x":-1236.7750244140625,"y":2544.859130859375,"id":"1425","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Environnement Protection","x":742.9298706054688,"y":-1374.4422607421875,"id":"918","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Protection De L\u0027Environnement,1","x":924.9998779296875,"y":-1493.4639892578125,"id":"1550","attributes":{"nodedef":"n1550"},"color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Phoques","x":-176.49501037597656,"y":-1298.3714599609375,"id":"1480","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Health Wealth","x":-769.10888671875,"y":813.8422241210938,"id":"1157","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Modèles Climatiques","x":960.2445068359375,"y":-632.1519775390625,"id":"1362","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Concentration Atmosphérique En Gaz À Effet De Serre","x":1109.8857421875,"y":-1201.5419921875,"id":"671","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Cycle Biogéochimique","x":1231.748779296875,"y":-1076.531982421875,"id":"760","color":"rgb(255,255,51)","size":4.781970500946045},{"label":"Écoulement","x":1946.003662109375,"y":-204.98585510253906,"id":"887","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Liv Arnesen","x":-211.08746337890625,"y":1457.8192138671875,"id":"255","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Activités Humaines","x":939.146484375,"y":-1054.251220703125,"id":"117","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Effet De Serre Anthropique","x":869.8401489257812,"y":-1122.5921630859375,"id":"895","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Salinisation","x":-492.9778747558594,"y":998.083251953125,"id":"1608","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Reseau De Distribution","x":164.8856964111328,"y":-1508.1824951171875,"id":"1043","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Canal De Panama","x":-467.1565856933594,"y":-1797.8077392578125,"id":"353","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Kennedy Channel","x":-990.4541015625,"y":1290.1942138671875,"id":"1260","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Fond Marin","x":161.1836395263672,"y":-697.8049926757812,"id":"444","color":"rgb(255,51,51)","size":8.235326766967773},{"label":"Saami","x":-1866.03271484375,"y":2491.896484375,"id":"1606","color":"rgb(204,204,255)","size":4.39528751373291},{"label":"Administration Bush","x":-1136.2672119140625,"y":-428.8100891113281,"id":"121","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Nunavut Land","x":-1509.091796875,"y":1711.5626220703125,"id":"1129","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Ecologie","x":695.2794799804688,"y":-1120.096435546875,"id":"873","color":"rgb(0,204,51)","size":4.510906219482422},{"label":"Mer De Sibérie Orientale","x":210.74697875976562,"y":-328.9768981933594,"id":"1341","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Court Terme","x":501.63348388671875,"y":-1379.796875,"id":"174","color":"rgb(0,153,0)","size":5.103478908538818},{"label":"Laboratoire Des Sciences Du Climat","x":895.5632934570312,"y":-84.9769515991211,"id":"289","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Etats-Unis","x":-664.49609375,"y":-157.40467834472656,"id":"945","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"International Journal Of Theoretical","x":-969.3994750976562,"y":198.23516845703125,"id":"1220","color":"rgb(255,51,51)","size":4.0},{"label":"Réseau De Communications","x":-2286.451416015625,"y":-1148.6153564453125,"id":"1587","color":"rgb(204,204,255)","size":4.0},{"label":"Reindeer Husbandry","x":-1639.425537109375,"y":2342.082763671875,"id":"1579","color":"rgb(204,204,255)","size":4.293514728546143},{"label":"Northern Light","x":-1084.892578125,"y":1428.5267333984375,"id":"316","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Geographic Magazine","x":-1408.0269775390625,"y":1253.908203125,"id":"1066","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Pollutions Localisées","x":409.26171875,"y":-437.8915100097656,"id":"1519","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Marine Soviétique","x":-557.7352294921875,"y":-1440.10791015625,"id":"355","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Données Scientifiques","x":1144.4649658203125,"y":-1053.2713623046875,"id":"832","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Arctic Bay","x":-1102.2261962890625,"y":1965.6678466796875,"id":"291","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Gas Hydrates","x":-526.14404296875,"y":1344.7689208984375,"id":"629","color":"rgb(0,153,0)","size":4.206028938293457},{"label":"Affaires Maritimes","x":-70.12700653076172,"y":-1806.66552734375,"id":"129","color":"rgb(153,0,0)","size":4.075808525085449},{"label":"Lac Glaciaire","x":1025.576171875,"y":-203.9110870361328,"id":"867","color":"rgb(153,255,255)","size":4.0},{"label":"Gulf-Stream","x":-762.6338500976562,"y":1361.40185546875,"id":"1148","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Norvège","x":-934.0388793945312,"y":-634.4059448242188,"id":"1411","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"National Parks","x":-1568.43505859375,"y":1488.180908203125,"id":"313","color":"rgb(153,255,0)","size":9.501245498657227},{"label":"Géologie","x":1237.4952392578125,"y":-582.6567993164062,"id":"1070","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Président Carter","x":-894.6444091796875,"y":174.04171752929688,"id":"1539","color":"rgb(255,51,51)","size":4.0},{"label":"Prélever","x":-138.2056427001953,"y":-1914.477294921875,"id":"1534","color":"rgb(153,0,0)","size":4.0},{"label":"Arctic Red","x":-1440.24658203125,"y":1692.1748046875,"id":"320","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"National Interest Lands","x":-2533.43408203125,"y":1090.193603515625,"id":"39","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Edp Sciences","x":620.9034423828125,"y":649.64892578125,"id":"890","color":"rgb(153,255,255)","size":4.0340681076049805},{"label":"Réactions","x":-2242.13916015625,"y":-81.64968872070312,"id":"1559","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"National Snow And Ice Data Center","x":-82.20970153808594,"y":1755.7330322265625,"id":"1383","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Zone De Subduction","x":1619.37841796875,"y":-586.6400146484375,"id":"202","color":"rgb(255,204,102)","size":4.936610698699951},{"label":"International Organization","x":-435.0935974121094,"y":328.05108642578125,"id":"721","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"West Passage","x":-738.1751098632812,"y":1883.2489013671875,"id":"1410","color":"rgb(153,0,0)","size":4.133297443389893},{"label":"Politique International","x":-499.8843688964844,"y":-908.3687133789062,"id":"1512","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Nouvelles Routes Commerciales","x":-253.4183349609375,"y":-961.7564086914062,"id":"1418","color":"rgb(153,0,0)","size":4.133297443389893},{"label":"Hydrocarbures","x":150.72735595703125,"y":-1719.0933837890625,"id":"1163","color":"rgb(102,0,102)","size":4.6399359703063965},{"label":"Knud Rasmussen","x":-722.918212890625,"y":1028.62451171875,"id":"385","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Otaries","x":245.4610137939453,"y":-1857.8228759765625,"id":"1446","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Laponie","x":-600.4788818359375,"y":-305.26251220703125,"id":"1276","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Novaya Zemlya","x":-1189.239990234375,"y":1574.789306640625,"id":"418","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Pont Alexandre","x":151.32626342773438,"y":-57.80909729003906,"id":"798","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Conférence","x":-1122.256103515625,"y":633.0912475585938,"id":"684","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Veau Marin","x":-208.42149353027344,"y":-1258.4281005859375,"id":"1317","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Atlantique Nord","x":-13.135313987731934,"y":-534.4340209960938,"id":"216","color":"rgb(255,51,51)","size":10.178449630737305},{"label":"Bruno Jacomy","x":1302.4163818359375,"y":361.8206787109375,"id":"1565","color":"rgb(255,255,51)","size":4.0},{"label":"Inlandsis","x":435.01898193359375,"y":159.8060302734375,"id":"1198","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Déchet Nucléaire","x":380.8000793457031,"y":-1663.5177001953125,"id":"504","color":"rgb(102,102,0)","size":5.472443103790283},{"label":"Philosophie De La Science","x":780.9424438476562,"y":-242.83270263671875,"id":"1429","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Convention Des Nations Unies Sur Le Droit De La Mer De 1982","x":-282.8759460449219,"y":-1720.91064453125,"id":"717","color":"rgb(153,0,0)","size":4.39528751373291},{"label":"North Pole","x":-513.2245483398438,"y":1585.4044189453125,"id":"182","color":"rgb(0,204,204)","size":14.764718055725098},{"label":"Cartes","x":1560.257080078125,"y":-1286.2509765625,"id":"557","color":"rgb(255,255,51)","size":4.0},{"label":"Temps Géologique","x":1447.703857421875,"y":-494.1518859863281,"id":"510","color":"rgb(255,204,102)","size":4.781970500946045},{"label":"Milieu Polaire","x":300.757568359375,"y":-101.02339172363281,"id":"1359","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Quantite De Matiere","x":2636.1533203125,"y":-881.0833740234375,"id":"91","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Physique","x":1883.59228515625,"y":24.318912506103516,"id":"1483","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Pays Nordique","x":-659.119140625,"y":-1094.1265869140625,"id":"896","color":"rgb(255,51,51)","size":4.6399359703063965},{"label":"Pigb","x":324.859130859375,"y":-200.34991455078125,"id":"1486","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Poussée D\u0027Archimède,1","x":3051.099853515625,"y":905.1744384765625,"id":"1525","attributes":{"nodedef":"n1525"},"color":"rgb(255,255,0)","size":4.0340681076049805},{"label":"Pollution Control","x":-1381.4327392578125,"y":969.9300537109375,"id":"1517","color":"rgb(102,102,0)","size":4.075808525085449},{"label":"Vladimir Putin","x":-1570.246826171875,"y":-132.1924285888672,"id":"491","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Préfabriqués","x":2714.468017578125,"y":551.2706909179688,"id":"1531","color":"rgb(255,255,51)","size":4.0},{"label":"Zone Polaire","x":354.72003173828125,"y":33.996063232421875,"id":"1360","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Clathrates","x":-273.6105651855469,"y":1365.593994140625,"id":"625","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Graduate Student","x":-371.85546875,"y":872.8204345703125,"id":"791","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Alliance Atlantique","x":-366.25677490234375,"y":-1161.8916015625,"id":"214","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Programme Des Nations","x":183.9048309326172,"y":-892.7618408203125,"id":"132","color":"rgb(102,255,102)","size":4.781970500946045},{"label":"Northern Sami","x":-1973.365478515625,"y":2609.33251953125,"id":"1409","color":"rgb(204,204,255)","size":4.206028938293457},{"label":"Recherches Prospectives","x":884.8547973632812,"y":-1303.6541748046875,"id":"1570","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Gbep","x":-897.9884643554688,"y":807.901123046875,"id":"1054","color":"rgb(0,153,0)","size":4.133297443389893},{"label":"War Of Iraq","x":-1343.6434326171875,"y":248.77804565429688,"id":"1586","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Atlantic Ocean","x":-893.0388793945312,"y":1363.2615966796875,"id":"318","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Præsidium Du Soviet Suprême De L\u0027Urss,1","x":-649.39306640625,"y":-1628.699462890625,"id":"1529","attributes":{"nodedef":"n1529"},"color":"rgb(255,51,51)","size":4.133297443389893},{"label":"Geological Survey","x":-382.74688720703125,"y":1018.3242797851562,"id":"324","color":"rgb(102,255,102)","size":5.103478908538818},{"label":"Espèce Rare","x":392.0811462402344,"y":-962.0516967773438,"id":"937","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Loup","x":-143.7703399658203,"y":-850.323486328125,"id":"1307","color":"rgb(153,255,0)","size":4.0340681076049805},{"label":"Natural Resources Ministry","x":-589.6399536132812,"y":704.2279052734375,"id":"340","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Isotherme","x":2666.44091796875,"y":-415.98529052734375,"id":"1232","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Amérique Du Nord","x":-141.58084106445312,"y":-656.83056640625,"id":"166","color":"rgb(255,51,51)","size":17.335289001464844},{"label":"Roald Amundsen","x":-523.8612060546875,"y":1742.4547119140625,"id":"966","color":"rgb(153,255,255)","size":5.103478908538818},{"label":"Radar Altimeter","x":199.72256469726562,"y":1572.3167724609375,"id":"754","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"East Greenland","x":-944.6824340820312,"y":1563.160400390625,"id":"613","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Ours Blanc","x":-94.96329498291016,"y":-394.123779296875,"id":"406","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Ressources Fossiles","x":636.2318725585938,"y":-1141.4078369140625,"id":"1591","color":"rgb(0,153,0)","size":4.6399359703063965},{"label":"Agence Spatiale Européenne","x":811.7756958007812,"y":289.67626953125,"id":"134","color":"rgb(255,153,153)","size":4.39528751373291},{"label":"Secretaire General","x":-380.1330871582031,"y":-1336.759033203125,"id":"215","color":"rgb(255,51,51)","size":5.282204627990723},{"label":"Activité Économique","x":495.2303161621094,"y":-1774.67724609375,"id":"95","color":"rgb(153,0,0)","size":5.6738481521606445},{"label":"Capitale De La Norvège","x":-714.158935546875,"y":-332.8415222167969,"id":"543","color":"rgb(153,0,0)","size":4.6399359703063965},{"label":"Forage","x":2852.77197265625,"y":3320.1611328125,"id":"1019","color":"rgb(102,102,0)","size":4.0086140632629395},{"label":"Glacial Till","x":-310.6843566894531,"y":1678.2410888671875,"id":"1097","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Arthur Chilingarov","x":-390.9749755859375,"y":1931.4237060546875,"id":"342","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Sami People","x":-1888.802734375,"y":2538.2783203125,"id":"1249","color":"rgb(204,204,255)","size":5.6738481521606445},{"label":"Progression","x":-1064.17529296875,"y":380.4419250488281,"id":"1548","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Universite De Paris","x":1826.4591064453125,"y":-120.52847290039062,"id":"648","color":"rgb(255,255,51)","size":4.510906219482422},{"label":"Atmospheric Research","x":-383.1943664550781,"y":1518.517333984375,"id":"360","color":"rgb(153,255,255)","size":4.075808525085449},{"label":"Wwf","x":-426.822265625,"y":1108.128662109375,"id":"1714","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Renard Roux","x":-501.80584716796875,"y":-930.3526611328125,"id":"1581","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Source Lumineuse","x":1338.2926025390625,"y":-355.2475280761719,"id":"1192","color":"rgb(255,255,51)","size":4.0},{"label":"Fermentation Bactérienne","x":1216.25146484375,"y":-1170.071533203125,"id":"980","color":"rgb(153,255,0)","size":4.075808525085449},{"label":"Neige Au Sol","x":1302.529052734375,"y":-289.34307861328125,"id":"1018","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"International Cooperation","x":-362.96234130859375,"y":298.28668212890625,"id":"720","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"International Geosphere","x":-609.56396484375,"y":1503.0321044921875,"id":"477","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Louis Etienne","x":262.0841064453125,"y":-13.704791069030762,"id":"397","color":"rgb(0,204,204)","size":8.235326766967773},{"label":"Mécanique Des Solides","x":2748.43115234375,"y":453.333984375,"id":"660","color":"rgb(255,255,0)","size":4.39528751373291},{"label":"Laboratoire De Géophysique","x":1749.293701171875,"y":467.0248107910156,"id":"1076","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Klavdij Sluban","x":-773.81005859375,"y":-1072.273681640625,"id":"1335","color":"rgb(255,51,51)","size":4.0},{"label":"Période Glaciaire","x":1182.68359375,"y":-265.6172180175781,"id":"287","color":"rgb(153,255,255)","size":8.235326766967773},{"label":"Croûte Continentale","x":1700.3018798828125,"y":-695.7825317382812,"id":"438","color":"rgb(255,204,102)","size":5.282204627990723},{"label":"Laboratoire De Physique Statistique","x":453.7958984375,"y":278.333740234375,"id":"1264","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Aurores Boréales","x":925.7900390625,"y":199.57559204101562,"id":"375","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Fahrenheit Scale","x":1027.1209716796875,"y":2542.7236328125,"id":"70","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Anwr","x":-2690.359619140625,"y":895.0036010742188,"id":"268","color":"rgb(153,255,0)","size":4.6399359703063965},{"label":"Traineau","x":-965.9135131835938,"y":-565.5975341796875,"id":"1684","color":"rgb(204,204,255)","size":4.39528751373291},{"label":"Biosphere Reserve","x":-1270.091552734375,"y":1550.5616455078125,"id":"475","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Bassin Sédimentaire","x":1087.60693359375,"y":-942.1962890625,"id":"144","color":"rgb(255,204,102)","size":4.293514728546143},{"label":"Institute Affiliate","x":-670.5057983398438,"y":2188.31787109375,"id":"1029","color":"rgb(0,204,204)","size":4.0},{"label":"Navigation","x":226.42288208007812,"y":3431.34326171875,"id":"1391","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"New England","x":-1147.896484375,"y":263.2210998535156,"id":"12","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Frederick Cook","x":-847.7138061523438,"y":1235.386962890625,"id":"967","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Plante Fourragère","x":1074.7864990234375,"y":-1960.4940185546875,"id":"1473","color":"rgb(153,255,0)","size":4.0},{"label":"Géosphère","x":-534.4583129882812,"y":1452.3653564453125,"id":"1081","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Surface Bioproductive","x":332.2822570800781,"y":-773.5977172851562,"id":"1656","color":"rgb(102,255,102)","size":4.133297443389893},{"label":"James Clark Ross","x":135.2253875732422,"y":1444.279541015625,"id":"1236","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Exploration Polaire","x":86.10325622558594,"y":51.03369903564453,"id":"838","color":"rgb(153,255,255)","size":4.39528751373291},{"label":"Gadus Morhua","x":-265.5268249511719,"y":-683.766357421875,"id":"489","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Compose Organique","x":1279.6739501953125,"y":-1786.3187255859375,"id":"668","color":"rgb(102,102,0)","size":4.6399359703063965},{"label":"Ile De Baffin","x":-542.6830444335938,"y":483.6591491699219,"id":"282","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Northern Canada","x":-766.9470825195312,"y":1782.7698974609375,"id":"1315","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Consommation","x":-3767.505126953125,"y":-1286.1236572265625,"id":"699","color":"rgb(204,0,0)","size":4.0},{"label":"Centre De Recherche","x":1475.1954345703125,"y":-714.0918579101562,"id":"159","color":"rgb(255,204,102)","size":7.9385457038879395},{"label":"Équilibre Biologique","x":1321.3497314453125,"y":-1695.903076171875,"id":"921","color":"rgb(102,102,0)","size":4.293514728546143},{"label":"Centre National","x":1352.81494140625,"y":-562.0387573242188,"id":"570","color":"rgb(255,204,102)","size":4.936610698699951},{"label":"Dominique Raynaud","x":897.6173706054688,"y":-141.02593994140625,"id":"290","color":"rgb(255,204,102)","size":4.39528751373291},{"label":"Journal De Bord","x":-291.7248229980469,"y":-123.4757080078125,"id":"1255","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Baril De Pétrole","x":-373.9239807128906,"y":-1424.874755859375,"id":"422","color":"rgb(102,0,102)","size":5.6738481521606445},{"label":"Fossil Fuel","x":-684.3709716796875,"y":1111.435546875,"id":"463","color":"rgb(0,153,0)","size":8.235326766967773},{"label":"Stephen Harper","x":-132.4368896484375,"y":-591.208251953125,"id":"1009","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Presqu\u0027Île De Kola,1","x":-388.2249450683594,"y":-725.830078125,"id":"1540","attributes":{"nodedef":"n1540"},"color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Alta","x":-1820.52587890625,"y":2058.934326171875,"id":"220","color":"rgb(0,204,204)","size":4.0},{"label":"Russia To Germany","x":-1770.2144775390625,"y":400.1640625,"id":"1402","color":"rgb(102,0,102)","size":4.133297443389893},{"label":"Environmental Satellite","x":318.142333984375,"y":2182.989501953125,"id":"911","color":"rgb(255,153,153)","size":4.39528751373291},{"label":"Ile Wake","x":249.35452270507812,"y":435.57574462890625,"id":"1502","color":"rgb(0,204,204)","size":4.0},{"label":"George Hubert Wilkins","x":-890.5496215820312,"y":1383.94775390625,"id":"1080","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Recul De La Banquise","x":387.477294921875,"y":-241.42066955566406,"id":"1573","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Eau Chaude","x":1326.6470947265625,"y":-1008.3419189453125,"id":"598","color":"rgb(255,204,102)","size":6.341859817504883},{"label":"Plateau Continental","x":-42.98124694824219,"y":-898.1126708984375,"id":"502","color":"rgb(102,255,102)","size":8.235326766967773},{"label":"Vitesse Limite","x":3108.7373046875,"y":928.3176879882812,"id":"1527","color":"rgb(255,255,0)","size":4.0},{"label":"Gps Satellite","x":220.57168579101562,"y":3309.154296875,"id":"1115","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Imagerie Satellite","x":755.4320068359375,"y":-166.0117645263672,"id":"1183","color":"rgb(255,153,153)","size":4.293514728546143},{"label":"Race To The Pole","x":-762.5220947265625,"y":1482.967529296875,"id":"1027","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Bush Administration","x":-1530.074462890625,"y":215.48060607910156,"id":"122","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Marge Continentale","x":1305.8900146484375,"y":-625.6681518554688,"id":"266","color":"rgb(255,204,102)","size":4.781970500946045},{"label":"Narvik","x":-1618.4957275390625,"y":2043.26513671875,"id":"1381","color":"rgb(0,204,204)","size":4.0},{"label":"Baleine Grise","x":-176.243896484375,"y":-979.921875,"id":"393","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Arctic Summer","x":-252.80731201171875,"y":1699.3084716796875,"id":"328","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Métaux Lourds","x":1217.7490234375,"y":-1729.1802978515625,"id":"379","color":"rgb(102,102,0)","size":4.6399359703063965},{"label":"Port En Eau Profonde","x":66.55622863769531,"y":-1956.13330078125,"id":"1523","color":"rgb(153,0,0)","size":4.0340681076049805},{"label":"Decroissance Soutenable","x":425.0431823730469,"y":-1451.91259765625,"id":"244","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Glacier Rocheux","x":714.1744384765625,"y":-146.1813201904297,"id":"793","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Fleuve Amour","x":-529.2616577148438,"y":-1068.8953857421875,"id":"999","color":"rgb(102,0,102)","size":4.0086140632629395},{"label":"Weather Satellite","x":353.239501953125,"y":2159.915283203125,"id":"1082","color":"rgb(255,153,153)","size":4.936610698699951},{"label":"Pipe Line","x":-2321.0849609375,"y":713.1168212890625,"id":"1489","color":"rgb(102,0,102)","size":4.133297443389893},{"label":"Agence Spatiale Russe","x":996.43310546875,"y":594.5779418945312,"id":"139","color":"rgb(255,153,153)","size":4.0340681076049805},{"label":"Chaîne De Montagnes","x":1214.927001953125,"y":-648.8825073242188,"id":"403","color":"rgb(255,204,102)","size":5.6738481521606445},{"label":"Accord Canada","x":14.053364753723145,"y":283.5315856933594,"id":"78","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Alaska Pipeline","x":-2189.193359375,"y":992.2608642578125,"id":"193","color":"rgb(102,0,102)","size":4.133297443389893},{"label":"Klondike Gold","x":-1461.8563232421875,"y":988.4777221679688,"id":"1121","color":"rgb(153,0,0)","size":4.133297443389893},{"label":"Acier Inoxydable","x":2597.7001953125,"y":-472.5513610839844,"id":"1233","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Kativik School","x":-1295.8642578125,"y":2771.06103515625,"id":"1258","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Arctic Norway","x":-1015.7074584960938,"y":1845.171142578125,"id":"314","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Péninsule Tchouktche","x":22.759498596191406,"y":-830.916748046875,"id":"1467","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Port Méthanier","x":-87.27054595947266,"y":-1629.2996826171875,"id":"171","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Produits Pétroliers","x":-328.5513916015625,"y":-1678.751220703125,"id":"656","color":"rgb(102,0,102)","size":4.936610698699951},{"label":"Expédition Polaire Russe","x":-910.3502197265625,"y":-196.7174072265625,"id":"957","color":"rgb(255,51,51)","size":4.293514728546143},{"label":"Nsidc","x":-39.78633499145508,"y":1692.2911376953125,"id":"1421","color":"rgb(153,255,255)","size":4.510906219482422},{"label":"Risque Technologique","x":1651.34423828125,"y":-1836.7208251953125,"id":"24","color":"rgb(102,102,0)","size":4.781970500946045},{"label":"Michael Llodra","x":296.3454895019531,"y":-1547.416259765625,"id":"1542","color":"rgb(255,51,51)","size":4.0},{"label":"Traitement Des Déchets","x":701.334716796875,"y":-2317.052734375,"id":"768","color":"rgb(102,102,0)","size":4.781970500946045},{"label":"Agent D\u0027Érosion,1","x":1293.1495361328125,"y":-845.2651977539062,"id":"142","attributes":{"nodedef":"n142"},"color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Insel Fünen","x":-1856.4827880859375,"y":-1676.109375,"id":"763","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Règlementer La Pêche","x":-24.56975555419922,"y":-1786.160400390625,"id":"1577","color":"rgb(153,0,0)","size":4.510906219482422},{"label":"Centre Technique Régional","x":-3758.538818359375,"y":-1311.2628173828125,"id":"700","color":"rgb(204,0,0)","size":4.0},{"label":"Gaz Naturel Liquéfié","x":-91.20169830322266,"y":-1537.076416015625,"id":"1044","color":"rgb(0,153,0)","size":4.510906219482422},{"label":"Inuit Eskimo","x":-1141.657470703125,"y":2152.69580078125,"id":"527","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Détroit De Béring","x":-323.8287353515625,"y":-395.40972900390625,"id":"411","color":"rgb(0,204,204)","size":7.650110721588135},{"label":"Protection Agency","x":-1255.6109619140625,"y":1038.06103515625,"id":"164","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Modifications Futures","x":-315.1140441894531,"y":-1362.1593017578125,"id":"1366","color":"rgb(255,51,51)","size":4.0340681076049805},{"label":"Geophysical Services","x":1747.908447265625,"y":736.555908203125,"id":"1072","color":"rgb(255,204,51)","size":4.0},{"label":"21-Avr-08","x":-2301.590576171875,"y":-1107.337646484375,"id":"17","color":"rgb(204,204,255)","size":4.0},{"label":"Accord De Marrakech","x":-23.58915138244629,"y":-1841.5423583984375,"id":"81","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Birds Of North","x":-1526.2667236328125,"y":1152.0509033203125,"id":"478","color":"rgb(153,255,0)","size":4.0},{"label":"Fjord","x":-1721.904541015625,"y":1539.12451171875,"id":"992","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Habitants Locaux","x":-450.0788269042969,"y":-632.4037475585938,"id":"1149","color":"rgb(204,204,255)","size":4.0},{"label":"Sous-Marin Mir","x":0.7903322577476501,"y":-263.9958190917969,"id":"1644","color":"rgb(255,51,51)","size":4.6399359703063965},{"label":"Impacts Sociaux","x":857.00830078125,"y":-1250.28759765625,"id":"1188","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Recherche Publique","x":1598.115234375,"y":-1009.1126708984375,"id":"1569","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Atmosphère","x":-327.4678955078125,"y":1451.6829833984375,"id":"358","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Paysages Naturels","x":759.217529296875,"y":-1915.464599609375,"id":"1464","color":"rgb(153,255,0)","size":4.0086140632629395},{"label":"Quest For The North","x":-836.8455810546875,"y":1504.2691650390625,"id":"1556","color":"rgb(153,0,0)","size":4.293514728546143},{"label":"Estimation Précise","x":1511.7779541015625,"y":-1364.507568359375,"id":"942","color":"rgb(255,255,51)","size":4.0},{"label":"Russia To Canada","x":-675.6696166992188,"y":1444.2498779296875,"id":"1506","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Année Polaire Internationale","x":953.1709594726562,"y":-222.62002563476562,"id":"257","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Dégradation Des Sols","x":940.4586181640625,"y":-1574.67333984375,"id":"779","color":"rgb(102,102,0)","size":4.781970500946045},{"label":"Croissance Végétale","x":1036.1978759765625,"y":-1246.32275390625,"id":"744","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Égalité De Droit","x":55.669151306152344,"y":-467.2328186035156,"id":"77","color":"rgb(102,255,102)","size":4.0},{"label":"Chemin De Fer","x":-327.4593811035156,"y":-804.969482421875,"id":"354","color":"rgb(153,0,0)","size":4.206028938293457},{"label":"1988","x":-1095.9884033203125,"y":437.6317443847656,"id":"14","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Gestion Des Déchets","x":641.9574584960938,"y":-2060.39013671875,"id":"708","color":"rgb(102,102,0)","size":6.584775924682617},{"label":"Barriere De Glace","x":751.5405883789062,"y":84.75260162353516,"id":"431","color":"rgb(153,255,255)","size":4.6399359703063965},{"label":"Disparition De La Banquise D\u0027Été,1","x":481.5081787109375,"y":-566.0498046875,"id":"821","attributes":{"nodedef":"n821"},"color":"rgb(102,255,102)","size":4.133297443389893},{"label":"Préservation Biodiversité","x":730.5175170898438,"y":-1473.8968505859375,"id":"1537","color":"rgb(102,102,0)","size":4.510906219482422},{"label":"Alopex Lagopus","x":-719.4835815429688,"y":84.6142578125,"id":"218","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Fjord Norvégien","x":-884.736328125,"y":-309.86322021484375,"id":"536","color":"rgb(0,204,204)","size":4.133297443389893},{"label":"Pipeline Company","x":-2126.298828125,"y":726.8614501953125,"id":"1037","color":"rgb(102,0,102)","size":4.510906219482422},{"label":"Golfe De Botnie","x":-574.8486328125,"y":-847.8629150390625,"id":"1122","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Plaque Tectonique","x":1617.9876708984375,"y":-518.2423706054688,"id":"834","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Ère Quaternaire","x":1294.13525390625,"y":-334.4315490722656,"id":"865","color":"rgb(255,255,51)","size":4.293514728546143},{"label":"Vent Solaire","x":904.5231323242188,"y":317.2509765625,"id":"116","color":"rgb(255,153,153)","size":5.6738481521606445},{"label":"Lac Baikal","x":-68.26935577392578,"y":-861.2033081054688,"id":"1266","color":"rgb(153,255,0)","size":4.510906219482422},{"label":"Atlantic Treaty Organization","x":-615.8858642578125,"y":-697.463134765625,"id":"1445","color":"rgb(255,51,51)","size":4.0},{"label":"Navire De Guerre","x":-466.7169494628906,"y":-1556.725341796875,"id":"232","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"International Journal Of Technology","x":-822.3903198242188,"y":1132.199462890625,"id":"1219","color":"rgb(102,255,102)","size":4.0340681076049805},{"label":"Agence De Voyages","x":-566.8865966796875,"y":-400.0716857910156,"id":"20","color":"rgb(0,204,204)","size":4.936610698699951},{"label":"Shtokman","x":-2037.73486328125,"y":832.659423828125,"id":"1631","color":"rgb(102,0,102)","size":4.39528751373291},{"label":"Disparition","x":246.64466857910156,"y":-1162.3238525390625,"id":"820","color":"rgb(153,255,0)","size":4.0},{"label":"Mer De Beaufort","x":-225.43960571289062,"y":-33.4792594909668,"id":"1336","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Environnement De Développement","x":1485.168212890625,"y":-1605.7059326171875,"id":"917","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Christophe Colomb","x":-492.0862731933594,"y":-791.3049926757812,"id":"602","color":"rgb(255,51,51)","size":4.0086140632629395},{"label":"Kola Peninsula","x":-1877.4124755859375,"y":2299.73876953125,"id":"421","color":"rgb(204,204,255)","size":4.6399359703063965},{"label":"Centre Of Excellence","x":-827.9765625,"y":1638.33740234375,"id":"331","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Usgs","x":-401.1330871582031,"y":821.0635375976562,"id":"1700","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Land Degradation","x":-478.3914794921875,"y":1062.0526123046875,"id":"803","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Geographic Channel","x":-1642.635498046875,"y":1258.9573974609375,"id":"1064","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Climate System","x":-284.0472717285156,"y":1345.24169921875,"id":"299","color":"rgb(102,255,102)","size":4.6399359703063965},{"label":"Extension De Sa Zee","x":-258.7265319824219,"y":-1052.287841796875,"id":"969","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Renard Des Sables","x":-736.22412109375,"y":-892.9422607421875,"id":"1582","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Terre Adelie","x":740.2885131835938,"y":240.6663818359375,"id":"457","color":"rgb(255,204,102)","size":5.103478908538818},{"label":"Alaska Fishing","x":-2920.301025390625,"y":2365.240966796875,"id":"192","color":"rgb(0,204,204)","size":4.6399359703063965},{"label":"Vladimir Poutine","x":-711.3236694335938,"y":-1351.60986328125,"id":"495","color":"rgb(255,51,51)","size":5.886096477508545},{"label":"Gradient Thermique Adiabatique","x":1962.834228515625,"y":-431.2511901855469,"id":"1131","color":"rgb(255,204,102)","size":4.133297443389893},{"label":"Jean-Louis Etienne","x":246.227783203125,"y":71.02962493896484,"id":"1244","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Revendication Territoriale","x":84.11878967285156,"y":-772.0419311523438,"id":"759","color":"rgb(255,51,51)","size":4.936610698699951},{"label":"Haute Résolution","x":972.8068237304688,"y":-44.521812438964844,"id":"1155","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Zones Froides","x":1170.614990234375,"y":-814.6840209960938,"id":"1721","color":"rgb(255,204,102)","size":4.206028938293457},{"label":"Mecanique Celeste","x":1754.9249267578125,"y":-24.008731842041016,"id":"347","color":"rgb(255,153,153)","size":4.075808525085449},{"label":"Centrale Electrique","x":460.12310791015625,"y":-1536.29052734375,"id":"426","color":"rgb(0,153,0)","size":4.510906219482422},{"label":"Tara Expéditions","x":162.76512145996094,"y":-37.0638427734375,"id":"822","color":"rgb(153,255,255)","size":4.781970500946045},{"label":"Grand Public","x":1464.771484375,"y":-1291.46240234375,"id":"1139","color":"rgb(255,255,51)","size":4.0},{"label":"Identité Culturelle","x":744.2086791992188,"y":-1578.896240234375,"id":"824","color":"rgb(153,255,0)","size":4.206028938293457},{"label":"Ward Hunt Island","x":-468.4326477050781,"y":1868.2164306640625,"id":"1253","color":"rgb(0,204,204)","size":4.293514728546143},{"label":"Ballon Stratosphérique","x":1370.3006591796875,"y":497.37359619140625,"id":"399","color":"rgb(255,153,153)","size":4.0086140632629395},{"label":"Carnet De Voyage","x":-815.7117309570312,"y":-674.12451171875,"id":"230","color":"rgb(204,204,255)","size":4.206028938293457},{"label":"Volumes D\u0027Hydrocarbures,1","x":-284.30419921875,"y":-1003.9923706054688,"id":"1707","attributes":{"nodedef":"n1707"},"color":"rgb(102,0,102)","size":4.39528751373291},{"label":"Réfléchissement","x":1013.8643798828125,"y":-1074.454833984375,"id":"1574","color":"rgb(102,255,102)","size":4.206028938293457},{"label":"Loi Des Gaz Parfaits","x":2679.76318359375,"y":-726.4705810546875,"id":"703","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Histoire Naturelle","x":732.302001953125,"y":-565.925048828125,"id":"469","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"Dette Écologique.","x":479.8210754394531,"y":-1402.3721923828125,"id":"811","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Effet De Serre","x":865.8285522460938,"y":-903.2288208007812,"id":"65","color":"rgb(102,255,102)","size":69.37736511230469},{"label":"Eau Liquide","x":1440.804443359375,"y":-54.767822265625,"id":"859","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Eaux Douces","x":935.943603515625,"y":-1351.420654296875,"id":"857","color":"rgb(255,255,51)","size":4.39528751373291},{"label":"Hammerfest","x":-1517.981201171875,"y":2044.6671142578125,"id":"1151","color":"rgb(0,204,204)","size":4.0086140632629395},{"label":"Arctic Resources","x":-753.0548095703125,"y":1701.157958984375,"id":"327","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Souveraineté Canadienne","x":-83.83868408203125,"y":-374.80377197265625,"id":"1648","color":"rgb(255,51,51)","size":4.39528751373291},{"label":"Barent Sea","x":-1725.133544921875,"y":1701.3858642578125,"id":"420","color":"rgb(0,204,204)","size":4.206028938293457},{"label":"Gas Liquefaction","x":-2165.393310546875,"y":858.1279296875,"id":"1035","color":"rgb(102,0,102)","size":4.206028938293457},{"label":"Methane Hydrate","x":-674.2474365234375,"y":1322.800537109375,"id":"628","color":"rgb(102,255,102)","size":4.936610698699951},{"label":"Union Pour La Republique","x":-1195.4715576171875,"y":-1906.215576171875,"id":"32","color":"rgb(255,51,51)","size":4.0},{"label":"Meteorologie Aeronautique","x":1906.800048828125,"y":-298.53631591796875,"id":"1348","color":"rgb(255,204,102)","size":4.0340681076049805},{"label":"Origine Humaine","x":530.5454711914062,"y":-867.5733032226562,"id":"1443","color":"rgb(102,255,102)","size":4.39528751373291},{"label":"Activité Physique","x":19.17449951171875,"y":-1487.5723876953125,"id":"110","color":"rgb(255,51,51)","size":4.075808525085449},{"label":"Climat","x":634.1971435546875,"y":-416.56427001953125,"id":"633","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Cirque Glaciaire","x":-414.3337707519531,"y":-675.9893798828125,"id":"620","color":"rgb(204,204,255)","size":4.0},{"label":"Destruction","x":-1023.5889282226562,"y":235.55380249023438,"id":"804","color":"rgb(255,51,51)","size":4.0},{"label":"Bass Temperature","x":1143.0743408203125,"y":-394.33685302734375,"id":"1002","color":"rgb(255,255,51)","size":4.0340681076049805},{"label":"Laboratoire Des Sciences","x":1369.251708984375,"y":-120.38371276855469,"id":"286","color":"rgb(255,255,51)","size":4.6399359703063965},{"label":"Ressources Halieutiques","x":208.87730407714844,"y":-1788.5084228515625,"id":"172","color":"rgb(0,153,0)","size":5.282204627990723},{"label":"Finlande","x":-699.87255859375,"y":-1438.7354736328125,"id":"984","color":"rgb(255,51,51)","size":4.206028938293457},{"label":"Modelés Glaciaires","x":518.2478637695312,"y":-613.6041259765625,"id":"1365","color":"rgb(102,255,102)","size":4.510906219482422},{"label":"Methane Gas","x":-695.7578735351562,"y":1379.359375,"id":"1350","color":"rgb(0,153,0)","size":4.133297443389893},{"label":"North Pole Dash","x":-518.3096313476562,"y":1951.0364990234375,"id":"1406","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Science Humaine","x":1481.983154296875,"y":-437.10595703125,"id":"238","color":"rgb(255,255,51)","size":6.341859817504883},{"label":"Surface Temperature","x":-158.56500244140625,"y":1636.7862548828125,"id":"1408","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Josée Auclair","x":-585.8860473632812,"y":2012.5086669921875,"id":"1250","color":"rgb(0,204,204)","size":4.39528751373291},{"label":"Atmospheric Chemistry","x":-458.1257629394531,"y":1473.9342041015625,"id":"308","color":"rgb(153,255,255)","size":4.293514728546143},{"label":"Vitus Bering","x":-514.814208984375,"y":-218.38807678222656,"id":"807","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Inuits","x":-1086.007568359375,"y":2101.54638671875,"id":"1223","color":"rgb(204,204,255)","size":4.510906219482422},{"label":"Désertification","x":-346.1569519042969,"y":1042.04052734375,"id":"802","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Gestion Durable","x":535.494140625,"y":-1856.2032470703125,"id":"882","color":"rgb(153,0,0)","size":4.39528751373291},{"label":"Évolution Dynamique","x":1323.7410888671875,"y":-173.46302795410156,"id":"953","color":"rgb(255,255,51)","size":4.133297443389893},{"label":"Manchot Empereur","x":589.0419921875,"y":461.8739929199219,"id":"1017","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Terre Arable","x":529.2310791015625,"y":-1912.7171630859375,"id":"1474","color":"rgb(153,0,0)","size":4.0086140632629395},{"label":"Espece Menacee","x":189.9256591796875,"y":-1050.06298828125,"id":"167","color":"rgb(153,255,0)","size":8.852968215942383},{"label":"Greenland Sea","x":-837.241943359375,"y":1581.582763671875,"id":"1144","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Project For Ice","x":7.382100582122803,"y":1167.9910888671875,"id":"826","color":"rgb(153,255,255)","size":4.206028938293457},{"label":"Acteur Économique","x":488.945556640625,"y":-1980.610595703125,"id":"94","color":"rgb(153,0,0)","size":4.206028938293457},{"label":"Cartographier","x":1643.154052734375,"y":-1261.8980712890625,"id":"558","color":"rgb(255,255,51)","size":4.0086140632629395},{"label":"Nappe Souterraine","x":579.6406860351562,"y":-1934.3416748046875,"id":"1358","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Domm","x":-1004.6201171875,"y":179.20132446289062,"id":"827","color":"rgb(255,51,51)","size":4.0},{"label":"Lièvre Arctique","x":-455.9764099121094,"y":-421.9842224121094,"id":"482","color":"rgb(153,255,0)","size":4.39528751373291},{"label":"Gédéon Programmes","x":-504.4151611328125,"y":353.18511962890625,"id":"1056","color":"rgb(0,204,204)","size":4.0340681076049805},{"label":"Indigenous Peoples","x":-1673.6878662109375,"y":2261.001220703125,"id":"618","color":"rgb(204,204,255)","size":5.282204627990723},{"label":"Grande Echelle","x":1003.61083984375,"y":-1225.32958984375,"id":"1140","color":"rgb(153,255,0)","size":4.133297443389893},{"label":"Tri Selectif","x":644.0982666015625,"y":-2335.362548828125,"id":"771","color":"rgb(102,102,0)","size":4.510906219482422},{"label":"Accès De Base","x":1810.5634765625,"y":-1565.491455078125,"id":"1085","color":"rgb(255,255,51)","size":4.0},{"label":"Fragmentation Écologique","x":657.0732421875,"y":-1327.8116455078125,"id":"246","color":"rgb(102,255,102)","size":4.293514728546143},{"label":"Gaz Sur Surface","x":219.41163635253906,"y":-202.6012725830078,"id":"1340","color":"rgb(102,255,102)","size":4.0086140632629395},{"label":"Pipeline Safety","x":-2272.401611328125,"y":690.718994140625,"id":"1038","color":"rgb(102,0,102)","size":4.133297443389893},{"label":"Hautes Latitudes","x":790.7667236328125,"y":-263.09051513671875,"id":"1156","color":"rgb(255,204,102)","size":4.6399359703063965},{"label":"West Siberian","x":-857.8103637695312,"y":1416.4312744140625,"id":"616","color":"rgb(0,204,204)","size":4.075808525085449},{"label":"Continent Américain","x":-518.6719360351562,"y":-467.7585754394531,"id":"603","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Charge De Recherche","x":1697.37646484375,"y":-832.8470458984375,"id":"596","color":"rgb(255,204,102)","size":4.075808525085449},{"label":"Paleoclimatologie","x":1190.7630615234375,"y":-548.8214111328125,"id":"1455","color":"rgb(255,204,102)","size":4.510906219482422},{"label":"Cercle Polaire","x":-441.5832824707031,"y":-338.2845458984375,"id":"335","color":"rgb(0,204,204)","size":14.764718055725098},{"label":"Alenia Space","x":836.8038940429688,"y":1245.3642578125,"id":"196","color":"rgb(255,153,153)","size":4.0340681076049805},{"label":"Fonds Marins","x":1276.6959228515625,"y":-437.3470458984375,"id":"1006","color":"rgb(255,255,51)","size":4.075808525085449},{"label":"Dérèglements Écologiques","x":344.27490234375,"y":-935.0296630859375,"id":"795","color":"rgb(102,255,102)","size":4.075808525085449},{"label":"Espèces","x":378.1238708496094,"y":-891.1968383789062,"id":"939","color":"rgb(153,255,0)","size":4.293514728546143},{"label":"Industrie Pétrolière","x":-323.57122802734375,"y":-1779.236083984375,"id":"654","color":"rgb(102,0,102)","size":4.936610698699951},{"label":"Ballon Dirigeable","x":245.244384765625,"y":127.29121398925781,"id":"396","color":"rgb(153,255,255)","size":4.133297443389893},{"label":"Fishing Alaska","x":-3016.6982421875,"y":2527.25244140625,"id":"190","color":"rgb(0,204,204)","size":4.510906219482422},{"label":"Cap Nord","x":-693.8167724609375,"y":-305.88018798828125,"id":"532","color":"rgb(0,204,204)","size":6.837328910827637}]} golang-gonum-v1-gonum-0.14.0/graph/formats/sigmajs/testdata/geolocalized.json000066400000000000000000000135111450372207100272150ustar00rootroot00000000000000{ "nodes":[ { "id":"n1", "label":"n1", "latitude":50.93, "longitude":2.48, "size":"5.5", "color":"rgb(1,179,255)" }, { "id":"n2", "label":"n2", "latitude":50.88, "longitude":2.0, "size":"5.0", "color":"rgb(1,179,255)" }, { "id":"n4", "label":"n4", "latitude":49.4, "longitude":0.19, "size":"6.0", "color":"rgb(1,179,255)" }, { "id":"n5", "label":"n5", "latitude":48.49, "longitude":-1.92, "size":"6.0", "color":"rgb(1,179,255)" }, { "id":"n6", "label":"n6", "latitude":48.26, "longitude":-4.38, "size":"4.5", "color":"rgb(1,179,255)" }, { "id":"n7", "label":"n7", "latitude":47.15, "longitude":-2.09, "size":"6.5", "color":"rgb(1,179,255)" }, { "id":"n8", "label":"n8", "latitude":46.02, "longitude":-1.04, "size":"6.5", "color":"rgb(1,179,255)" }, { "id":"n9", "label":"n9", "latitude":43.22, "longitude":-1.85, "size":"5.0", "color":"rgb(1,179,255)" }, { "id":"n10", "label":"n10", "latitude":42.38, "longitude":3.18, "size":"4.0", "color":"rgb(1,179,255)" }, { "id":"n11", "label":"n11", "latitude":43.47, "longitude":4.04, "size":"5.5", "color":"rgb(1,179,255)" }, { "id":"n12", "label":"n12", "latitude":42.9, "longitude":6.59, "size":"5.0", "color":"rgb(1,179,255)" }, { "id":"n13", "label":"n13", "latitude":43.62, "longitude":7.66, "size":"6.0", "color":"rgb(1,179,255)" }, { "id":"n14", "label":"n14", "latitude":46.05, "longitude":6.19, "size":"6.5", "color":"rgb(1,179,255)" }, { "id":"n15", "label":"n15", "latitude":47.43, "longitude":7.65, "size":"6.0", "color":"rgb(1,179,255)" }, { "id":"n16", "label":"n16", "latitude":48.9, "longitude":8.32, "size":"5.5", "color":"rgb(1,179,255)" }, { "id":"n17", "label":"n17", "latitude":49.83, "longitude":4.94, "size":"6.5", "color":"rgb(1,179,255)" }, { "id":"Paris", "label":"Paris", "latitude":48.72, "longitude":2.46, "size":"9.0", "color":"rgb(1,179,255)" } ], "edges":[ { "id":"8", "source":"n1", "target":"Paris" }, { "id":"7", "source":"n2", "target":"n4" }, { "id":"28", "source":"n4", "target":"n1" }, { "id":"30", "source":"n4", "target":"n7" }, { "id":"26", "source":"n5", "target":"n1" }, { "id":"27", "source":"n5", "target":"n2" }, { "id":"0", "source":"n6", "target":"n5" }, { "id":"29", "source":"n7", "target":"n5" }, { "id":"1", "source":"n7", "target":"n8" }, { "id":"17", "source":"n7", "target":"Paris" }, { "id":"10", "source":"n8", "target":"n13" }, { "id":"18", "source":"n8", "target":"Paris" }, { "id":"15", "source":"n9", "target":"n8" }, { "id":"34", "source":"n10", "target":"n9" }, { "id":"31", "source":"n10", "target":"n11" }, { "id":"11", "source":"n11", "target":"n13" }, { "id":"13", "source":"n11", "target":"n14" }, { "id":"32", "source":"n12", "target":"n10" }, { "id":"12", "source":"n12", "target":"n11" }, { "id":"23", "source":"n12", "target":"n13" }, { "id":"33", "source":"n13", "target":"n10" }, { "id":"25", "source":"n13", "target":"n14" }, { "id":"14", "source":"n14", "target":"n9" }, { "id":"5", "source":"n14", "target":"n17" }, { "id":"19", "source":"n14", "target":"Paris" }, { "id":"6", "source":"n15", "target":"n8" }, { "id":"22", "source":"n15", "target":"n16" }, { "id":"20", "source":"n15", "target":"Paris" }, { "id":"4", "source":"n16", "target":"n15" }, { "id":"24", "source":"n16", "target":"Paris" }, { "id":"9", "source":"n17", "target":"n7" }, { "id":"21", "source":"n17", "target":"n17" }, { "id":"2", "source":"Paris", "target":"n4" }, { "id":"3", "source":"Paris", "target":"n17" }, { "id":"16", "source":"Paris", "target":"Paris" } ] }golang-gonum-v1-gonum-0.14.0/graph/graph.go000066400000000000000000000212201450372207100203640ustar00rootroot00000000000000// 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 the edge reversal of the receiver // if a reversal is valid for the data type. // When a reversal is valid an edge of the same type as // the receiver with nodes of the receiver swapped should // be returned, otherwise the receiver should be returned // unaltered. 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) } // NodeWithIDer is a graph that can return potentially new nodes with // a defined ID. type NodeWithIDer interface { // NodeWithID returns a Node with the given ID if possible. // A nil Node will be returned if no Node exists or // can be created. // If a non-nil Node is returned that is not already in the // graph NodeWithID will return true for new and the Node // must be added to the graph before use. NodeWithID(id int64) (n Node, new bool) } // 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())) } } } golang-gonum-v1-gonum-0.14.0/graph/graph_test.go000066400000000000000000000170761450372207100214410ustar00rootroot00000000000000// 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 graph_test import ( "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) type graphBuilder interface { graph.Graph graph.Builder } func TestCopy(t *testing.T) { copyTests := []struct { desc string src graph.Graph dst graphBuilder // If want is nil, compare to src. want graph.Graph }{ { desc: "undirected to undirected", src: func() graph.Graph { g := simple.NewUndirectedGraph() g.AddNode(simple.Node(-1)) for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, } { g.SetEdge(e) } return g }(), dst: simple.NewUndirectedGraph(), }, { desc: "undirected to directed", src: func() graph.Graph { g := simple.NewUndirectedGraph() g.AddNode(simple.Node(-1)) for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, } { g.SetEdge(e) } return g }(), dst: simple.NewDirectedGraph(), want: func() graph.Graph { g := simple.NewDirectedGraph() g.AddNode(simple.Node(-1)) for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, } { // want is a directed graph copied from // an undirected graph so we need to have // all edges in both directions. g.SetEdge(e) e.T, e.F = e.F, e.T g.SetEdge(e) } return g }(), }, { desc: "directed to undirected", src: func() graph.Graph { g := simple.NewDirectedGraph() g.AddNode(simple.Node(-1)) for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, } { g.SetEdge(e) } return g }(), dst: simple.NewUndirectedGraph(), want: func() graph.Graph { g := simple.NewUndirectedGraph() g.AddNode(simple.Node(-1)) for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, } { g.SetEdge(e) } return g }(), }, { desc: "directed to directed", src: func() graph.Graph { g := simple.NewDirectedGraph() g.AddNode(simple.Node(-1)) for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, } { g.SetEdge(e) } return g }(), dst: simple.NewDirectedGraph(), }, } for _, test := range copyTests { graph.Copy(test.dst, test.src) want := test.want if want == nil { want = test.src } if !same(test.dst, want) { t.Errorf("unexpected copy result for %s", test.desc) } } } type graphWeightedBuilder interface { graph.Graph graph.WeightedBuilder } func TestCopyWeighted(t *testing.T) { copyWeightedTests := []struct { desc string src graph.Weighted dst graphWeightedBuilder // If want is nil, compare to src. want graph.Graph }{ { desc: "undirected to undirected", src: func() graph.Weighted { g := simple.NewWeightedUndirectedGraph(0, 0) g.AddNode(simple.Node(-1)) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, } { g.SetWeightedEdge(e) } return g }(), dst: simple.NewWeightedUndirectedGraph(0, 0), }, { desc: "undirected to directed", src: func() graph.Weighted { g := simple.NewWeightedUndirectedGraph(0, 0) g.AddNode(simple.Node(-1)) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, } { g.SetWeightedEdge(e) } return g }(), dst: simple.NewWeightedDirectedGraph(0, 0), want: func() graph.Graph { g := simple.NewWeightedDirectedGraph(0, 0) g.AddNode(simple.Node(-1)) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, } { // want is a directed graph copied from // an undirected graph so we need to have // all edges in both directions. g.SetWeightedEdge(e) e.T, e.F = e.F, e.T g.SetWeightedEdge(e) } return g }(), }, { desc: "directed to undirected", src: func() graph.Weighted { g := simple.NewWeightedDirectedGraph(0, 0) g.AddNode(simple.Node(-1)) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, } { g.SetWeightedEdge(e) } return g }(), dst: simple.NewWeightedUndirectedGraph(0, 0), want: func() graph.Weighted { g := simple.NewWeightedUndirectedGraph(0, 0) g.AddNode(simple.Node(-1)) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, } { g.SetWeightedEdge(e) } return g }(), }, { desc: "directed to directed", src: func() graph.Weighted { g := simple.NewWeightedDirectedGraph(0, 0) g.AddNode(simple.Node(-1)) for _, e := range []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, } { g.SetWeightedEdge(e) } return g }(), dst: simple.NewWeightedDirectedGraph(0, 0), }, } for _, test := range copyWeightedTests { graph.CopyWeighted(test.dst, test.src) want := test.want if want == nil { want = test.src } if !same(test.dst, want) { t.Errorf("unexpected copy result for %s", test.desc) } } } func same(a, b graph.Graph) bool { aNodes := graph.NodesOf(a.Nodes()) bNodes := graph.NodesOf(b.Nodes()) ordered.ByID(aNodes) ordered.ByID(bNodes) for i, na := range aNodes { nb := bNodes[i] if na != nb { return false } } for _, u := range graph.NodesOf(a.Nodes()) { aFromU := graph.NodesOf(a.From(u.ID())) bFromU := graph.NodesOf(b.From(u.ID())) if len(aFromU) != len(bFromU) { return false } ordered.ByID(aFromU) ordered.ByID(bFromU) for i, va := range aFromU { vb := bFromU[i] if va != vb { return false } aW, aWok := a.(graph.Weighted) bW, bWok := b.(graph.Weighted) if aWok && bWok { if aW.WeightedEdge(u.ID(), va.ID()).Weight() != bW.WeightedEdge(u.ID(), vb.ID()).Weight() { return false } } } } type edger interface { Edges() graph.Edges } type weightedEdger interface { WeightedEdges() graph.WeightedEdges } var sizeA, sizeB int switch a := a.(type) { case edger: sizeA = len(graph.EdgesOf(a.Edges())) case weightedEdger: sizeA = len(graph.WeightedEdgesOf(a.WeightedEdges())) } switch b := b.(type) { case edger: sizeB = len(graph.EdgesOf(b.Edges())) case weightedEdger: sizeB = len(graph.WeightedEdgesOf(b.WeightedEdges())) } return sizeA == sizeB } golang-gonum-v1-gonum-0.14.0/graph/graphs/000077500000000000000000000000001450372207100202235ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/000077500000000000000000000000001450372207100207745ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/batagelj_brandes.go000066400000000000000000000227011450372207100245740ustar00rootroot00000000000000// 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. // The functions in this file are random graph generators from the paper // by Batagelj and Brandes http://algo.uni-konstanz.de/publications/bb-eglrn-05.pdf package gen import ( "fmt" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" ) // Gnp constructs a Gilbert’s model subgraph in the destination, dst, of order n. Edges // between nodes are formed with the probability, p. If src is not nil it is used // as the random source, otherwise rand.Float64 is used. The graph is constructed // in O(n+m) time where m is the number of edges added. func Gnp(dst graph.Builder, n int, p float64, src rand.Source) error { if p == 0 { for i := 0; i < n; i++ { dst.AddNode(dst.NewNode()) } return nil } if p < 0 || p > 1 { return fmt.Errorf("gen: bad probability: p=%v", p) } var r func() float64 if src == nil { r = rand.Float64 } else { r = rand.New(src).Float64 } nodes := make([]graph.Node, n) for i := range nodes { u := dst.NewNode() dst.AddNode(u) nodes[i] = u } lp := math.Log(1 - p) // Add forward edges for all graphs. for v, w := 1, -1; v < n; { w += 1 + int(math.Log(1-r())/lp) for w >= v && v < n { w -= v v++ } if v < n { dst.SetEdge(dst.NewEdge(nodes[w], nodes[v])) } } // Add backward edges for directed graphs. if _, ok := dst.(graph.Directed); !ok { return nil } for v, w := 1, -1; v < n; { w += 1 + int(math.Log(1-r())/lp) for w >= v && v < n { w -= v v++ } if v < n { dst.SetEdge(dst.NewEdge(nodes[v], nodes[w])) } } return nil } // Gnm constructs a Erdős-Rényi model subgraph in the destination, dst, of // order n and size m. If src is not nil it is used as the random source, // otherwise rand.Intn is used. The graph is constructed in O(m) expected // time for m ≤ (n choose 2)/2. func Gnm(dst GraphBuilder, n, m int, src rand.Source) error { if m == 0 { for i := 0; i < n; i++ { dst.AddNode(dst.NewNode()) } return nil } hasEdge := dst.HasEdgeBetween d, isDirected := dst.(graph.Directed) if isDirected { m /= 2 hasEdge = d.HasEdgeFromTo } nChoose2 := (n - 1) * n / 2 if m < 0 || m > nChoose2 { return fmt.Errorf("gen: bad size: m=%d", m) } var rnd func(int) int if src == nil { rnd = rand.Intn } else { rnd = rand.New(src).Intn } nodes := make([]graph.Node, n) for i := range nodes { u := dst.NewNode() dst.AddNode(u) nodes[i] = u } // Add forward edges for all graphs. for i := 0; i < m; i++ { for { v, w := edgeNodesFor(rnd(nChoose2), nodes) if !hasEdge(w.ID(), v.ID()) { dst.SetEdge(dst.NewEdge(w, v)) break } } } // Add backward edges for directed graphs. if !isDirected { return nil } for i := 0; i < m; i++ { for { v, w := edgeNodesFor(rnd(nChoose2), nodes) if !hasEdge(v.ID(), w.ID()) { dst.SetEdge(dst.NewEdge(v, w)) break } } } return nil } // SmallWorldsBB constructs a small worlds subgraph of order n in the destination, dst. // Node degree is specified by d and edge replacement by the probability, p. // If src is not nil it is used as the random source, otherwise rand.Float64 is used. // The graph is constructed in O(nd) time. // // The algorithm used is described in http://algo.uni-konstanz.de/publications/bb-eglrn-05.pdf func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src rand.Source) error { if d < 1 || d > (n-1)/2 { return fmt.Errorf("gen: bad degree: d=%d", d) } if p == 0 { for i := 0; i < n; i++ { dst.AddNode(dst.NewNode()) } return nil } if p < 0 || p >= 1 { return fmt.Errorf("gen: bad replacement: p=%v", p) } var ( rnd func() float64 rndN func(int) int ) if src == nil { rnd = rand.Float64 rndN = rand.Intn } else { r := rand.New(src) rnd = r.Float64 rndN = r.Intn } hasEdge := dst.HasEdgeBetween dg, isDirected := dst.(graph.Directed) if isDirected { hasEdge = dg.HasEdgeFromTo } nodes := make([]graph.Node, n) for i := range nodes { u := dst.NewNode() dst.AddNode(u) nodes[i] = u } nChoose2 := (n - 1) * n / 2 lp := math.Log(1 - p) // Add forward edges for all graphs. k := int(math.Log(1-rnd()) / lp) m := 0 replace := make(map[int]int) for v := 0; v < n; v++ { for i := 1; i <= d; i++ { if k > 0 { j := v*(v-1)/2 + (v+i)%n if v, u := edgeNodesFor(j, nodes); !hasEdge(u.ID(), v.ID()) { dst.SetEdge(dst.NewEdge(u, v)) } k-- m++ // For small graphs, m may be an // edge that has an end that is // not in the subgraph. if m >= nChoose2 { // Since m is monotonically // increasing, no m edges from // here on are valid, so don't // add them to replace. continue } if v, u := edgeNodesFor(m, nodes); !hasEdge(u.ID(), v.ID()) { replace[j] = m } else { replace[j] = replace[m] } } else { k = int(math.Log(1-rnd()) / lp) } } } for i := m + 1; i <= n*d && i < nChoose2; i++ { r := rndN(nChoose2-i) + i if v, u := edgeNodesFor(r, nodes); !hasEdge(u.ID(), v.ID()) { dst.SetEdge(dst.NewEdge(u, v)) } else if v, u = edgeNodesFor(replace[r], nodes); !hasEdge(u.ID(), v.ID()) { dst.SetEdge(dst.NewEdge(u, v)) } if v, u := edgeNodesFor(i, nodes); !hasEdge(u.ID(), v.ID()) { replace[r] = i } else { replace[r] = replace[i] } } // Add backward edges for directed graphs. if !isDirected { return nil } k = int(math.Log(1-rnd()) / lp) m = 0 replace = make(map[int]int) for v := 0; v < n; v++ { for i := 1; i <= d; i++ { if k > 0 { j := v*(v-1)/2 + (v+i)%n if u, v := edgeNodesFor(j, nodes); !hasEdge(u.ID(), v.ID()) { dst.SetEdge(dst.NewEdge(u, v)) } k-- m++ // For small graphs, m may be an // edge that has an end that is // not in the subgraph. if m >= nChoose2 { // Since m is monotonically // increasing, no m edges from // here on are valid, so don't // add them to replace. continue } if u, v := edgeNodesFor(m, nodes); !hasEdge(u.ID(), v.ID()) { replace[j] = m } else { replace[j] = replace[m] } } else { k = int(math.Log(1-rnd()) / lp) } } } for i := m + 1; i <= n*d && i < nChoose2; i++ { r := rndN(nChoose2-i) + i if u, v := edgeNodesFor(r, nodes); !hasEdge(u.ID(), v.ID()) { dst.SetEdge(dst.NewEdge(u, v)) } else if u, v = edgeNodesFor(replace[r], nodes); !hasEdge(u.ID(), v.ID()) { dst.SetEdge(dst.NewEdge(u, v)) } if u, v := edgeNodesFor(i, nodes); !hasEdge(u.ID(), v.ID()) { replace[r] = i } else { replace[r] = replace[i] } } return nil } // edgeNodesFor returns the pair of nodes for the ith edge in a simple // undirected graph. The pair is returned such that the index of w in // nodes is less than the index of v in nodes. func edgeNodesFor(i int, nodes []graph.Node) (v, w graph.Node) { // This is an algebraic simplification of the expressions described // on p3 of http://algo.uni-konstanz.de/publications/bb-eglrn-05.pdf vi := int(0.5 + math.Sqrt(float64(1+8*i))/2) wi := i - vi*(vi-1)/2 return nodes[vi], nodes[wi] } // Multigraph generators. // PowerLaw constructs a power-law degree graph by preferential attachment in dst // with n nodes and minimum degree d. PowerLaw does not consider nodes in dst prior // to the call. If src is not nil it is used as the random source, otherwise rand.Intn // is used. // The graph is constructed in O(nd) — O(n+m) — time. // // The algorithm used is described in http://algo.uni-konstanz.de/publications/bb-eglrn-05.pdf func PowerLaw(dst graph.MultigraphBuilder, n, d int, src rand.Source) error { if d < 1 { return fmt.Errorf("gen: bad minimum degree: d=%d", d) } var rnd func(int) int if src == nil { rnd = rand.Intn } else { rnd = rand.New(src).Intn } m := make([]graph.Node, 2*n*d) for v := 0; v < n; v++ { x := dst.NewNode() dst.AddNode(x) for i := 0; i < d; i++ { m[2*(v*d+i)] = x m[2*(v*d+i)+1] = m[rnd(2*v*d+i+1)] } } for i := 0; i < n*d; i++ { dst.SetLine(dst.NewLine(m[2*i], m[2*i+1])) } return nil } // BipartitePowerLaw constructs a bipartite power-law degree graph by preferential attachment // in dst with 2×n nodes and minimum degree d. BipartitePowerLaw does not consider nodes in // dst prior to the call. The two partitions are returned in p1 and p2. If src is not nil it is // used as the random source, otherwise rand.Intn is used. // The graph is constructed in O(nd) — O(n+m) — time. // // The algorithm used is described in http://algo.uni-konstanz.de/publications/bb-eglrn-05.pdf func BipartitePowerLaw(dst graph.MultigraphBuilder, n, d int, src rand.Source) (p1, p2 []graph.Node, err error) { if d < 1 { return nil, nil, fmt.Errorf("gen: bad minimum degree: d=%d", d) } var rnd func(int) int if src == nil { rnd = rand.Intn } else { rnd = rand.New(src).Intn } p := make([]graph.Node, 2*n) for i := range p { u := dst.NewNode() dst.AddNode(u) p[i] = u } m1 := make([]graph.Node, 2*n*d) m2 := make([]graph.Node, 2*n*d) for v := 0; v < n; v++ { for i := 0; i < d; i++ { m1[2*(v*d+i)] = p[v] m2[2*(v*d+i)] = p[n+v] if r := rnd(2*v*d + i + 1); r&0x1 == 0 { m1[2*(v*d+i)+1] = m2[r] } else { m1[2*(v*d+i)+1] = m1[r] } if r := rnd(2*v*d + i + 1); r&0x1 == 0 { m2[2*(v*d+i)+1] = m1[r] } else { m2[2*(v*d+i)+1] = m2[r] } } } for i := 0; i < n*d; i++ { dst.SetLine(dst.NewLine(m1[2*i], m1[2*i+1])) dst.SetLine(dst.NewLine(m2[2*i], m2[2*i+1])) } return p[:n], p[n:], nil } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/batagelj_brandes_test.go000066400000000000000000000224431450372207100256360ustar00rootroot00000000000000// 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 gen import ( "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/simple" ) type gnUndirected struct { graph.UndirectedBuilder addBackwards bool addSelfLoop bool addMultipleEdge bool } func (g *gnUndirected) SetEdge(e graph.Edge) { switch { case e.From().ID() == e.To().ID(): g.addSelfLoop = true return case e.From().ID() > e.To().ID(): g.addBackwards = true case g.UndirectedBuilder.HasEdgeBetween(e.From().ID(), e.To().ID()): g.addMultipleEdge = true } g.UndirectedBuilder.SetEdge(e) } type gnDirected struct { graph.DirectedBuilder addSelfLoop bool addMultipleEdge bool } func (g *gnDirected) SetEdge(e graph.Edge) { switch { case e.From().ID() == e.To().ID(): g.addSelfLoop = true return case g.DirectedBuilder.HasEdgeFromTo(e.From().ID(), e.To().ID()): g.addMultipleEdge = true } g.DirectedBuilder.SetEdge(e) } func TestGnpUndirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for p := 0.; p <= 1; p += 0.1 { g := &gnUndirected{UndirectedBuilder: simple.NewUndirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := Gnp(g, n, p, nil) if err != nil { t.Fatalf("unexpected error: n=%d, p=%v: %v", n, p, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: n=%d, p=%v", n, p) } if g.addBackwards { t.Errorf("edge added with From.ID > To.ID: n=%d, p=%v", n, p) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, p=%v", n, p) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, p=%v", n, p) } } } } func TestGnpDirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for p := 0.; p <= 1; p += 0.1 { g := &gnDirected{DirectedBuilder: simple.NewDirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := Gnp(g, n, p, nil) if err != nil { t.Fatalf("unexpected error: n=%d, p=%v: %v", n, p, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: n=%d, p=%v", n, p) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, p=%v", n, p) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, p=%v", n, p) } } } } func TestGnmUndirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { nChoose2 := (n - 1) * n / 2 for m := 0; m <= nChoose2; m++ { g := &gnUndirected{UndirectedBuilder: simple.NewUndirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := Gnm(g, n, m, nil) if err != nil { t.Fatalf("unexpected error: n=%d, m=%d: %v", n, m, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: n=%d, m=%d", n, m) } if g.addBackwards { t.Errorf("edge added with From.ID > To.ID: n=%d, m=%d", n, m) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, m=%d", n, m) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, m=%d", n, m) } } } } func TestGnmDirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { nChoose2 := (n - 1) * n / 2 for m := 0; m <= nChoose2*2; m++ { g := &gnDirected{DirectedBuilder: simple.NewDirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := Gnm(g, n, m, nil) if err != nil { t.Fatalf("unexpected error: n=%d, m=%d: %v", n, m, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: n=%d, m=%d", n, m) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, m=%d", n, m) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, m=%d", n, m) } } } } func TestSmallWorldsBBUndirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for d := 1; d <= (n-1)/2; d++ { for p := 0.; p < 1; p += 0.1 { g := &gnUndirected{UndirectedBuilder: simple.NewUndirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := SmallWorldsBB(g, n, d, p, nil) if err != nil { t.Fatalf("unexpected error: n=%d, d=%d, p=%v: %v", n, d, p, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: n=%d, d=%d, p=%v", n, d, p) } if g.addBackwards { t.Errorf("edge added with From.ID > To.ID: n=%d, d=%d, p=%v", n, d, p) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, d=%d, p=%v", n, d, p) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, d=%d, p=%v", n, d, p) } } } } } func TestSmallWorldsBBDirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for d := 1; d <= (n-1)/2; d++ { for p := 0.; p < 1; p += 0.1 { g := &gnDirected{DirectedBuilder: simple.NewDirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := SmallWorldsBB(g, n, d, p, nil) if err != nil { t.Fatalf("unexpected error: n=%d, d=%d, p=%v: %v", n, d, p, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: n=%d, d=%d, p=%v", n, d, p) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, d=%d, p=%v", n, d, p) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, d=%d, p=%v", n, d, p) } } } } } func TestPowerLawUndirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for d := 1; d <= 5; d++ { g := multi.NewUndirectedGraph() err := PowerLaw(g, n, d, nil) if err != nil { t.Fatalf("unexpected error: n=%d, d=%d: %v", n, d, err) } nodes := graph.NodesOf(g.Nodes()) if len(nodes) != n { t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes)) } for _, u := range nodes { uid := u.ID() var lines int for _, v := range graph.NodesOf(g.From(uid)) { lines += len(graph.LinesOf(g.Lines(uid, v.ID()))) } if lines < d { t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) break } } } } } func TestPowerLawDirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for d := 1; d <= 5; d++ { g := multi.NewDirectedGraph() err := PowerLaw(g, n, d, nil) if err != nil { t.Fatalf("unexpected error: n=%d, d=%d: %v", n, d, err) } nodes := graph.NodesOf(g.Nodes()) if len(nodes) != n { t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes)) } for _, u := range nodes { uid := u.ID() var lines int for _, v := range graph.NodesOf(g.From(uid)) { lines += len(graph.LinesOf(g.Lines(uid, v.ID()))) } if lines < d { t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) break } } } } } func TestBipartitePowerLawUndirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for d := 1; d <= 5; d++ { g := multi.NewUndirectedGraph() p1, p2, err := BipartitePowerLaw(g, n, d, nil) if err != nil { t.Fatalf("unexpected error: n=%d, d=%d: %v", n, d, err) } nodes := graph.NodesOf(g.Nodes()) if len(nodes) != 2*n { t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes)) } if len(p1) != n { t.Errorf("unexpected number of nodes in p1: n=%d, d=%d: got:%d", n, d, len(p1)) } if len(p2) != n { t.Errorf("unexpected number of nodes in p2: n=%d, d=%d: got:%d", n, d, len(p2)) } p1s := set.NewNodes() for _, u := range p1 { p1s.Add(u) } p2s := set.NewNodes() for _, u := range p2 { p2s.Add(u) } o := set.IntersectionOfNodes(p1s, p2s) if len(o) != 0 { t.Errorf("unexpected overlap in partition membership: n=%d, d=%d: got:%d", n, d, len(o)) } for _, u := range nodes { uid := u.ID() var lines int for _, v := range graph.NodesOf(g.From(uid)) { lines += len(graph.LinesOf(g.Lines(uid, v.ID()))) } if lines < d { t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) break } } } } } func TestBipartitePowerLawDirected(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for d := 1; d <= 5; d++ { g := multi.NewDirectedGraph() p1, p2, err := BipartitePowerLaw(g, n, d, nil) if err != nil { t.Fatalf("unexpected error: n=%d, d=%d: %v", n, d, err) } nodes := graph.NodesOf(g.Nodes()) if len(nodes) != 2*n { t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes)) } if len(p1) != n { t.Errorf("unexpected number of nodes in p1: n=%d, d=%d: got:%d", n, d, len(p1)) } if len(p2) != n { t.Errorf("unexpected number of nodes in p2: n=%d, d=%d: got:%d", n, d, len(p2)) } p1s := set.NewNodes() for _, u := range p1 { p1s.Add(u) } p2s := set.NewNodes() for _, u := range p2 { p2s.Add(u) } o := set.IntersectionOfNodes(p1s, p2s) if len(o) != 0 { t.Errorf("unexpected overlap in partition membership: n=%d, d=%d: got:%d", n, d, len(o)) } for _, u := range nodes { uid := u.ID() var lines int for _, v := range graph.NodesOf(g.From(uid)) { lines += len(graph.LinesOf(g.Lines(uid, v.ID()))) } if lines < d { t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) break } } } } } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/doc.go000066400000000000000000000004341450372207100220710ustar00rootroot00000000000000// 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 gen provides random graph generation functions. package gen // import "gonum.org/v1/gonum/graph/graphs/gen" golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/duplication.go000066400000000000000000000062141450372207100236410ustar00rootroot00000000000000// 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 gen import ( "fmt" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" ) // UndirectedMutator is an undirected graph builder that can remove edges. type UndirectedMutator interface { graph.UndirectedBuilder graph.EdgeRemover } // Duplication constructs a graph in the destination, dst, of order n. New nodes // are created by duplicating an existing node and all its edges. Each new edge is // deleted with probability delta. Additional edges are added between the new node // and existing nodes with probability alpha/|V|. An exception to this addition // rule is made for the parent node when sigma is not NaN; in this case an edge is // created with probability sigma. With the exception of the sigma parameter, this // corresponds to the completely correlated case in doi:10.1016/S0022-5193(03)00028-6. // If src is not nil it is used as the random source, otherwise rand.Float64 is used. func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src rand.Source) error { // As described in doi:10.1016/S0022-5193(03)00028-6 but // also clarified in doi:10.1186/gb-2007-8-4-r51. if delta < 0 || delta > 1 { return fmt.Errorf("gen: bad delta: delta=%v", delta) } if alpha <= 0 || alpha > 1 { return fmt.Errorf("gen: bad alpha: alpha=%v", alpha) } if sigma < 0 || sigma > 1 { return fmt.Errorf("gen: bad sigma: sigma=%v", sigma) } var ( rnd func() float64 rndN func(int) int ) if src == nil { rnd = rand.Float64 rndN = rand.Intn } else { r := rand.New(src) rnd = r.Float64 rndN = r.Intn } nodes := graph.NodesOf(dst.Nodes()) ordered.ByID(nodes) if len(nodes) == 0 { n-- u := dst.NewNode() dst.AddNode(u) nodes = append(nodes, u) } for i := 0; i < n; i++ { u := nodes[rndN(len(nodes))] d := dst.NewNode() did := d.ID() // Add the duplicate node. dst.AddNode(d) // Loop until we have connectivity // into the rest of the graph. for { // Add edges to parent's neighbours. to := graph.NodesOf(dst.From(u.ID())) ordered.ByID(to) for _, v := range to { vid := v.ID() if rnd() < delta || dst.HasEdgeBetween(vid, did) { continue } if vid < did { dst.SetEdge(dst.NewEdge(v, d)) } else { dst.SetEdge(dst.NewEdge(d, v)) } } // Add edges to old nodes. scaledAlpha := alpha / float64(len(nodes)) for _, v := range nodes { uid := u.ID() vid := v.ID() switch vid { case uid: if !math.IsNaN(sigma) { if i == 0 || rnd() < sigma { if vid < did { dst.SetEdge(dst.NewEdge(v, d)) } else { dst.SetEdge(dst.NewEdge(d, v)) } } continue } fallthrough default: if rnd() < scaledAlpha && !dst.HasEdgeBetween(vid, did) { if vid < did { dst.SetEdge(dst.NewEdge(v, d)) } else { dst.SetEdge(dst.NewEdge(d, v)) } } } } if dst.From(did).Len() != 0 { break } } nodes = append(nodes, d) } return nil } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/duplication_test.go000066400000000000000000000031041450372207100246730ustar00rootroot00000000000000// 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 gen import ( "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) type duplication struct { UndirectedMutator addBackwards bool addSelfLoop bool addMultipleEdge bool } func (g *duplication) SetEdge(e graph.Edge) { switch { case e.From().ID() == e.To().ID(): g.addSelfLoop = true return case e.From().ID() > e.To().ID(): g.addBackwards = true case g.UndirectedMutator.HasEdgeBetween(e.From().ID(), e.To().ID()): g.addMultipleEdge = true } g.UndirectedMutator.SetEdge(e) } func TestDuplication(t *testing.T) { t.Parallel() for n := 2; n <= 50; n++ { for alpha := 0.1; alpha <= 1; alpha += 0.1 { for delta := 0.; delta <= 1; delta += 0.2 { for sigma := 0.; sigma <= 1; sigma += 0.2 { g := &duplication{UndirectedMutator: simple.NewUndirectedGraph()} err := Duplication(g, n, delta, alpha, sigma, nil) if err != nil { t.Fatalf("unexpected error: n=%d, alpha=%v, delta=%v sigma=%v: %v", n, alpha, delta, sigma, err) } if g.addBackwards { t.Errorf("edge added with From.ID > To.ID: n=%d, alpha=%v, delta=%v sigma=%v", n, alpha, delta, sigma) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, alpha=%v, delta=%v sigma=%v", n, alpha, delta, sigma) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, alpha=%v, delta=%v sigma=%v", n, alpha, delta, sigma) } } } } } } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/gen.go000066400000000000000000000143221450372207100220760ustar00rootroot00000000000000// 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 gen import ( "fmt" "gonum.org/v1/gonum/graph" ) // GraphBuilder is a graph that can have nodes and edges added. type GraphBuilder interface { HasEdgeBetween(xid, yid int64) bool graph.Builder } func abs(a int) int { if a < 0 { return -a } return a } // NodeIDGraphBuild is a graph that can create new nodes with // specified IDs. type NodeIDGraphBuilder interface { graph.Builder graph.NodeWithIDer } // IDer is a mapping from an index to a node ID. type IDer interface { // Len returns the length of the set of node IDs. Len() int // ID returns the ID of the indexed node. // ID must be a bijective function. No check // is made for this property. ID(int) int64 } // IDRange is an IDer that provides a set of IDs in [First, Last]. type IDRange struct{ First, Last int64 } func (r IDRange) Len() int { return int(r.Last - r.First + 1) } func (r IDRange) ID(i int) int64 { return r.First + int64(i) } // IDSet is an IDer providing an explicit set of IDs. type IDSet []int64 func (s IDSet) Len() int { return len(s) } func (s IDSet) ID(i int) int64 { return s[i] } // Complete constructs a complete graph in dst using nodes with the given IDs. // If any ID appears twice in ids, Complete will panic. func Complete(dst NodeIDGraphBuilder, ids IDer) { switch ids.Len() { case 0: return case 1: u, new := dst.NodeWithID(ids.ID(0)) if new { dst.AddNode(u) } return } for i := 0; i < ids.Len(); i++ { uid := ids.ID(i) u, _ := dst.NodeWithID(uid) for j := i + 1; j < ids.Len(); j++ { vid := ids.ID(j) if uid == vid { panic(fmt.Errorf("gen: node ID collision i=%d j=%d: id=%d", i, j, uid)) } v, _ := dst.NodeWithID(vid) dst.SetEdge(dst.NewEdge(u, v)) } } } // Cycle constructs a cycle in dst using the node IDs in cycle. // If dst is a directed graph, edges are directed from earlier nodes to later // nodes in cycle. If any ID appears twice in cycle, Cycle will panic. func Cycle(dst NodeIDGraphBuilder, cycle IDer) { switch cycle.Len() { case 0: return case 1: u, new := dst.NodeWithID(cycle.ID(0)) if new { dst.AddNode(u) } return } err := check(cycle) if err != nil { panic(err) } cycleNoCheck(dst, cycle) } func cycleNoCheck(dst NodeIDGraphBuilder, cycle IDer) { for i := 0; i < cycle.Len(); i++ { uid := cycle.ID(i) vid := cycle.ID((i + 1) % cycle.Len()) u, _ := dst.NodeWithID(uid) v, _ := dst.NodeWithID(vid) dst.SetEdge(dst.NewEdge(u, v)) } } // Path constructs a path graph in dst with // If dst is a directed graph, edges are directed from earlier nodes to later // nodes in path. If any ID appears twice in path, Path will panic. func Path(dst NodeIDGraphBuilder, path IDer) { switch path.Len() { case 0: return case 1: u, new := dst.NodeWithID(path.ID(0)) if new { dst.AddNode(u) } return } err := check(path) if err != nil { panic(err) } for i := 0; i < path.Len()-1; i++ { uid := path.ID(i) vid := path.ID(i + 1) u, _ := dst.NodeWithID(uid) v, _ := dst.NodeWithID(vid) dst.SetEdge(dst.NewEdge(u, v)) } } // Star constructs a star graph in dst with edges between the center node ID to // node with IDs specified in leaves. // If dst is a directed graph, edges are directed from the center node to the // leaves. If any ID appears twice in leaves and center, Star will panic. func Star(dst NodeIDGraphBuilder, center int64, leaves IDer) { c, new := dst.NodeWithID(center) if new { dst.AddNode(c) } if leaves.Len() == 0 { return } err := check(leaves, center) if err != nil { panic(err) } for i := 0; i < leaves.Len(); i++ { id := leaves.ID(i) n, _ := dst.NodeWithID(id) dst.SetEdge(dst.NewEdge(c, n)) } } // Wheel constructs a wheel graph in dst with edges from the center // node ID to node with IDs specified in cycle and between nodes with IDs // adjacent in the cycle. // If dst is a directed graph, edges are directed from the center node to the // cycle and from earlier nodes to later nodes in cycle. If any ID appears // twice in cycle and center, Wheel will panic. func Wheel(dst NodeIDGraphBuilder, center int64, cycle IDer) { Star(dst, center, cycle) if cycle.Len() <= 1 { return } cycleNoCheck(dst, cycle) } // Tree constructs an n-ary tree breadth-first in dst with the given fan-out, n. // If the number of nodes does not equal \sum_{i=0}^h n^i, where h is an integer // indicating the height of the tree, a partial tree will be constructed with not // all nodes having zero or n children, and not all leaves being h from the root. // If the number of nodes is greater than one, n must be non-zero and // less than the number of nodes, otherwise Tree will panic. // If dst is a directed graph, edges are directed from the root to the leaves. // If any ID appears more than once in nodes, Tree will panic. func Tree(dst NodeIDGraphBuilder, n int, nodes IDer) { switch nodes.Len() { case 0: return case 1: if u, new := dst.NodeWithID(nodes.ID(0)); new { dst.AddNode(u) } return } if n < 1 || nodes.Len() <= n { panic("gen: invalid fan-out") } err := check(nodes) if err != nil { panic(err) } j := 0 for i := 0; j < nodes.Len(); i++ { u, _ := dst.NodeWithID(nodes.ID(i)) for j = n*i + 1; j <= n*i+n && j < nodes.Len(); j++ { v, _ := dst.NodeWithID(nodes.ID(j)) dst.SetEdge(dst.NewEdge(u, v)) } } } // check confirms that no node ID exists more than once in ids and extra. func check(ids IDer, extra ...int64) error { seen := make(map[int64]int, ids.Len()+len(extra)) for j := 0; j < ids.Len(); j++ { uid := ids.ID(j) if prev, exists := seen[uid]; exists { return fmt.Errorf("gen: node ID collision i=%d j=%d: id=%d", prev, j, uid) } seen[uid] = j } lenIDs := ids.Len() for j, uid := range extra { if prev, exists := seen[uid]; exists { if prev < lenIDs { if len(extra) == 1 { return fmt.Errorf("gen: node ID collision i=%d with extra: id=%d", prev, uid) } return fmt.Errorf("gen: node ID collision i=%d with extra j=%d: id=%d", prev, j, uid) } prev -= lenIDs return fmt.Errorf("gen: extra node ID collision i=%d j=%d: id=%d", prev, j, uid) } seen[uid] = j + lenIDs } return nil } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/gen_example_test.go000066400000000000000000000077701450372207100246610ustar00rootroot00000000000000// Copyright ©2021 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 gen_test import ( "fmt" "log" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/simple" ) func ExampleStar_undirectedRange() { dst := simple.NewUndirectedGraph() gen.Star(dst, 0, gen.IDRange{First: 1, Last: 6}) b, err := dot.Marshal(dst, "star", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", b) // Output: // strict graph star { // // Node definitions. // 0; // 1; // 2; // 3; // 4; // 5; // 6; // // // Edge definitions. // 0 -- 1; // 0 -- 2; // 0 -- 3; // 0 -- 4; // 0 -- 5; // 0 -- 6; // } } func ExampleWheel_directedRange() { dst := simple.NewDirectedGraph() gen.Wheel(dst, 0, gen.IDRange{First: 1, Last: 6}) b, err := dot.Marshal(dst, "wheel", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", b) // Output: // strict digraph wheel { // // Node definitions. // 0; // 1; // 2; // 3; // 4; // 5; // 6; // // // Edge definitions. // 0 -> 1; // 0 -> 2; // 0 -> 3; // 0 -> 4; // 0 -> 5; // 0 -> 6; // 1 -> 2; // 2 -> 3; // 3 -> 4; // 4 -> 5; // 5 -> 6; // 6 -> 1; // } } func ExamplePath_directedSet() { dst := simple.NewDirectedGraph() gen.Path(dst, gen.IDSet{2, 4, 5, 9}) b, err := dot.Marshal(dst, "path", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", b) // Output: // strict digraph path { // // Node definitions. // 2; // 4; // 5; // 9; // // // Edge definitions. // 2 -> 4; // 4 -> 5; // 5 -> 9; // } } func ExampleComplete_directedSet() { dst := simple.NewDirectedGraph() gen.Complete(dst, gen.IDSet{2, 4, 5, 9}) b, err := dot.Marshal(dst, "complete", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", b) // Output: // strict digraph complete { // // Node definitions. // 2; // 4; // 5; // 9; // // // Edge definitions. // 2 -> 4; // 2 -> 5; // 2 -> 9; // 4 -> 5; // 4 -> 9; // 5 -> 9; // } } // Bidirected allows bidirectional directed graph construction. type Bidirected struct { *simple.DirectedGraph } func (g Bidirected) SetEdge(e graph.Edge) { g.DirectedGraph.SetEdge(e) g.DirectedGraph.SetEdge(e.ReversedEdge()) } func ExampleComplete_biDirectedSet() { dst := simple.NewDirectedGraph() gen.Complete(Bidirected{dst}, gen.IDSet{2, 4, 5, 9}) b, err := dot.Marshal(dst, "complete", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", b) // Output: // strict digraph complete { // // Node definitions. // 2; // 4; // 5; // 9; // // // Edge definitions. // 2 -> 4; // 2 -> 5; // 2 -> 9; // 4 -> 2; // 4 -> 5; // 4 -> 9; // 5 -> 2; // 5 -> 4; // 5 -> 9; // 9 -> 2; // 9 -> 4; // 9 -> 5; // } } func ExampleComplete_undirectedSet() { dst := simple.NewUndirectedGraph() gen.Complete(dst, gen.IDSet{2, 4, 5, 9}) b, err := dot.Marshal(dst, "complete", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", b) // Output: // strict graph complete { // // Node definitions. // 2; // 4; // 5; // 9; // // // Edge definitions. // 2 -- 4; // 2 -- 5; // 2 -- 9; // 4 -- 5; // 4 -- 9; // 5 -- 9; // } } func ExampleTree_undirectedRange() { dst := simple.NewUndirectedGraph() gen.Tree(dst, 2, gen.IDRange{First: 0, Last: 14}) b, err := dot.Marshal(dst, "full_binary_tree_undirected", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", b) // Output: // strict graph full_binary_tree_undirected { // // Node definitions. // 0; // 1; // 2; // 3; // 4; // 5; // 6; // 7; // 8; // 9; // 10; // 11; // 12; // 13; // 14; // // // Edge definitions. // 0 -- 1; // 0 -- 2; // 1 -- 3; // 1 -- 4; // 2 -- 5; // 2 -- 6; // 3 -- 7; // 3 -- 8; // 4 -- 9; // 4 -- 10; // 5 -- 11; // 5 -- 12; // 6 -- 13; // 6 -- 14; // } } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/gen_test.go000066400000000000000000000355401450372207100231420ustar00rootroot00000000000000// Copyright ©2021 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 gen import ( "bytes" "fmt" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/simple" ) type nodeIDGraphBuilder interface { graph.Graph NodeIDGraphBuilder } func undirected() nodeIDGraphBuilder { return simple.NewUndirectedGraph() } func directed() nodeIDGraphBuilder { return simple.NewDirectedGraph() } type empty struct{} func (r empty) Len() int { return 0 } func (r empty) ID(i int) int64 { panic("called ID on empty IDer") } func panics(fn func()) (panicked bool, msg string) { defer func() { r := recover() if r != nil { panicked = true msg = fmt.Sprint(r) } }() fn() return } func TestComplete(t *testing.T) { tests := []struct { name string ids IDer dst func() nodeIDGraphBuilder want string panics string }{ { name: "empty", ids: empty{}, dst: undirected, want: `strict graph empty { }`, }, { name: "single", ids: IDRange{First: 1, Last: 1}, dst: undirected, want: `strict graph single { // Node definitions. 1; }`, }, { name: "pair_undirected", ids: IDRange{First: 1, Last: 2}, dst: undirected, want: `strict graph pair_undirected { // Node definitions. 1; 2; // Edge definitions. 1 -- 2; }`, }, { name: "pair_directed", ids: IDRange{First: 1, Last: 2}, dst: directed, want: `strict digraph pair_directed { // Node definitions. 1; 2; // Edge definitions. 1 -> 2; }`, }, { name: "quad_undirected", ids: IDRange{First: 1, Last: 4}, dst: undirected, want: `strict graph quad_undirected { // Node definitions. 1; 2; 3; 4; // Edge definitions. 1 -- 2; 1 -- 3; 1 -- 4; 2 -- 3; 2 -- 4; 3 -- 4; }`, }, { name: "quad_directed", ids: IDRange{First: 1, Last: 4}, dst: directed, want: `strict digraph quad_directed { // Node definitions. 1; 2; 3; 4; // Edge definitions. 1 -> 2; 1 -> 3; 1 -> 4; 2 -> 3; 2 -> 4; 3 -> 4; }`, }, { name: "collision", ids: IDSet{1, 2, 3, 2}, dst: undirected, panics: "gen: node ID collision i=1 j=3: id=2", }, } for _, test := range tests { dst := test.dst() panicked, msg := panics(func() { Complete(dst, test.ids) }) if msg != test.panics { t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics) } if panicked { continue } got, err := dot.Marshal(dst, test.name, "", " ") if err != nil { t.Errorf("unexpected marshaling graph error: %v", err) } if !bytes.Equal(got, []byte(test.want)) { t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want) } } } func TestCycle(t *testing.T) { tests := []struct { name string ids IDer dst func() nodeIDGraphBuilder want string panics string }{ { name: "empty", ids: empty{}, dst: undirected, want: `strict graph empty { }`, }, { name: "single", ids: IDRange{First: 1, Last: 1}, dst: undirected, want: `strict graph single { // Node definitions. 1; }`, }, { name: "pair_undirected", ids: IDRange{First: 1, Last: 2}, dst: undirected, want: `strict graph pair_undirected { // Node definitions. 1; 2; // Edge definitions. 1 -- 2; }`, }, { name: "pair_directed", ids: IDRange{First: 1, Last: 2}, dst: directed, want: `strict digraph pair_directed { // Node definitions. 1; 2; // Edge definitions. 1 -> 2; 2 -> 1; }`, }, { name: "quad_undirected", ids: IDRange{First: 1, Last: 4}, dst: undirected, want: `strict graph quad_undirected { // Node definitions. 1; 2; 3; 4; // Edge definitions. 1 -- 2; 1 -- 4; 2 -- 3; 3 -- 4; }`, }, { name: "quad_directed", ids: IDRange{First: 1, Last: 4}, dst: directed, want: `strict digraph quad_directed { // Node definitions. 1; 2; 3; 4; // Edge definitions. 1 -> 2; 2 -> 3; 3 -> 4; 4 -> 1; }`, }, { name: "collision", ids: IDSet{1, 2, 3, 2}, dst: undirected, panics: "gen: node ID collision i=1 j=3: id=2", }, } for _, test := range tests { dst := test.dst() panicked, msg := panics(func() { Cycle(dst, test.ids) }) if msg != test.panics { t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics) } if panicked { continue } got, err := dot.Marshal(dst, test.name, "", " ") if err != nil { t.Errorf("unexpected error marshaling graph: %v", err) } if !bytes.Equal(got, []byte(test.want)) { t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want) } } } func TestPath(t *testing.T) { tests := []struct { name string ids IDer dst func() nodeIDGraphBuilder want string panics string }{ { name: "empty", ids: empty{}, dst: undirected, want: `strict graph empty { }`, }, { name: "single", ids: IDRange{First: 1, Last: 1}, dst: undirected, want: `strict graph single { // Node definitions. 1; }`, }, { name: "pair_undirected", ids: IDRange{First: 1, Last: 2}, dst: undirected, want: `strict graph pair_undirected { // Node definitions. 1; 2; // Edge definitions. 1 -- 2; }`, }, { name: "pair_directed", ids: IDRange{First: 1, Last: 2}, dst: directed, want: `strict digraph pair_directed { // Node definitions. 1; 2; // Edge definitions. 1 -> 2; }`, }, { name: "quad_undirected", ids: IDRange{First: 1, Last: 4}, dst: undirected, want: `strict graph quad_undirected { // Node definitions. 1; 2; 3; 4; // Edge definitions. 1 -- 2; 2 -- 3; 3 -- 4; }`, }, { name: "quad_directed", ids: IDRange{First: 1, Last: 4}, dst: directed, want: `strict digraph quad_directed { // Node definitions. 1; 2; 3; 4; // Edge definitions. 1 -> 2; 2 -> 3; 3 -> 4; }`, }, { name: "collision", ids: IDSet{1, 2, 3, 2}, dst: undirected, panics: "gen: node ID collision i=1 j=3: id=2", }, } for _, test := range tests { dst := test.dst() panicked, msg := panics(func() { Path(dst, test.ids) }) if msg != test.panics { t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics) } if panicked { continue } got, err := dot.Marshal(dst, test.name, "", " ") if err != nil { t.Errorf("unexpected error marshaling graph: %v", err) } if !bytes.Equal(got, []byte(test.want)) { t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want) } } } func TestStar(t *testing.T) { tests := []struct { name string center int64 leaves IDer dst func() nodeIDGraphBuilder want string panics string }{ { name: "empty_leaves", center: 0, leaves: empty{}, dst: undirected, want: `strict graph empty_leaves { // Node definitions. 0; }`, }, { name: "single", center: 0, leaves: IDRange{First: 1, Last: 1}, dst: undirected, want: `strict graph single { // Node definitions. 0; 1; // Edge definitions. 0 -- 1; }`, }, { name: "pair_undirected", center: 0, leaves: IDRange{First: 1, Last: 2}, dst: undirected, want: `strict graph pair_undirected { // Node definitions. 0; 1; 2; // Edge definitions. 0 -- 1; 0 -- 2; }`, }, { name: "pair_directed", center: 0, leaves: IDRange{First: 1, Last: 2}, dst: directed, want: `strict digraph pair_directed { // Node definitions. 0; 1; 2; // Edge definitions. 0 -> 1; 0 -> 2; }`, }, { name: "quad_undirected", center: 0, leaves: IDRange{First: 1, Last: 4}, dst: undirected, want: `strict graph quad_undirected { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 3; 0 -- 4; }`, }, { name: "quad_directed", center: 0, leaves: IDRange{First: 1, Last: 4}, dst: directed, want: `strict digraph quad_directed { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2; 0 -> 3; 0 -> 4; }`, }, { name: "center collision", center: 1, leaves: IDRange{First: 1, Last: 4}, dst: undirected, panics: "gen: node ID collision i=0 with extra: id=1", }, { name: "leaf collision", center: 0, leaves: IDSet{1, 2, 3, 2}, dst: undirected, panics: "gen: node ID collision i=1 j=3: id=2", }, } for _, test := range tests { dst := test.dst() panicked, msg := panics(func() { Star(dst, test.center, test.leaves) }) if msg != test.panics { t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics) } if panicked { continue } got, err := dot.Marshal(dst, test.name, "", " ") if err != nil { t.Errorf("unexpected error marshaling graph: %v", err) } if !bytes.Equal(got, []byte(test.want)) { t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want) } } } func TestWheel(t *testing.T) { tests := []struct { name string center int64 cycle IDer dst func() nodeIDGraphBuilder want string panics string }{ { name: "empty_cycle", center: 0, cycle: empty{}, dst: undirected, want: `strict graph empty_cycle { // Node definitions. 0; }`, }, { name: "single", cycle: IDRange{First: 1, Last: 1}, dst: undirected, want: `strict graph single { // Node definitions. 0; 1; // Edge definitions. 0 -- 1; }`, }, { name: "pair_undirected", center: 0, cycle: IDRange{First: 1, Last: 2}, dst: undirected, want: `strict graph pair_undirected { // Node definitions. 0; 1; 2; // Edge definitions. 0 -- 1; 0 -- 2; 1 -- 2; }`, }, { name: "pair_directed", center: 0, cycle: IDRange{First: 1, Last: 2}, dst: directed, want: `strict digraph pair_directed { // Node definitions. 0; 1; 2; // Edge definitions. 0 -> 1; 0 -> 2; 1 -> 2; 2 -> 1; }`, }, { name: "quad_undirected", center: 0, cycle: IDRange{First: 1, Last: 4}, dst: undirected, want: `strict graph quad_undirected { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 3; 0 -- 4; 1 -- 2; 1 -- 4; 2 -- 3; 3 -- 4; }`, }, { name: "quad_directed", center: 0, cycle: IDRange{First: 1, Last: 4}, dst: directed, want: `strict digraph quad_directed { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -> 1; 0 -> 2; 0 -> 3; 0 -> 4; 1 -> 2; 2 -> 3; 3 -> 4; 4 -> 1; }`, }, { name: "center collision", center: 1, cycle: IDRange{First: 1, Last: 4}, dst: undirected, panics: "gen: node ID collision i=0 with extra: id=1", }, { name: "cycle collision", center: 0, cycle: IDSet{1, 2, 3, 2}, dst: undirected, panics: "gen: node ID collision i=1 j=3: id=2", }, } for _, test := range tests { dst := test.dst() panicked, msg := panics(func() { Wheel(dst, test.center, test.cycle) }) if msg != test.panics { t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics) } if panicked { continue } got, err := dot.Marshal(dst, test.name, "", " ") if err != nil { t.Errorf("unexpected error marshaling graph: %v", err) } if !bytes.Equal(got, []byte(test.want)) { t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want) } } } func TestCheck(t *testing.T) { tests := []struct { ids IDer extra []int64 want string }{ { ids: IDSet{1, 2, 3, 4}, extra: []int64{1}, want: "gen: node ID collision i=0 with extra: id=1", }, { ids: IDSet{1, 2, 3, 4}, extra: []int64{5, 2}, want: "gen: node ID collision i=1 with extra j=1: id=2", }, { ids: IDSet{}, extra: []int64{1, 2, 1}, want: "gen: extra node ID collision i=0 j=2: id=1", }, } for _, test := range tests { msg := fmt.Sprint(check(test.ids, test.extra...)) if msg != test.want { t.Errorf("unexpected check panic for ids=%#v extra=%v: got:%q want:%q", test.ids, test.extra, msg, test.want) } } } func TestTree(t *testing.T) { tests := []struct { name string dst func() nodeIDGraphBuilder nodes IDer fanout int want string panics string }{ { name: "empty_tree", dst: undirected, nodes: empty{}, fanout: 2, want: `strict graph empty_tree { }`, }, { name: "singleton_tree", dst: undirected, nodes: IDSet{0}, fanout: 0, want: `strict graph singleton_tree { // Node definitions. 0; }`, }, { name: "full_binary_tree_undirected", dst: undirected, nodes: IDRange{First: 0, Last: 14}, fanout: 2, want: `strict graph full_binary_tree_undirected { // Node definitions. 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; // Edge definitions. 0 -- 1; 0 -- 2; 1 -- 3; 1 -- 4; 2 -- 5; 2 -- 6; 3 -- 7; 3 -- 8; 4 -- 9; 4 -- 10; 5 -- 11; 5 -- 12; 6 -- 13; 6 -- 14; }`, }, { name: "partial_ternary_tree_undirected", dst: undirected, nodes: IDRange{First: 0, Last: 17}, fanout: 3, want: `strict graph partial_ternary_tree_undirected { // Node definitions. 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; // Edge definitions. 0 -- 1; 0 -- 2; 0 -- 3; 1 -- 4; 1 -- 5; 1 -- 6; 2 -- 7; 2 -- 8; 2 -- 9; 3 -- 10; 3 -- 11; 3 -- 12; 4 -- 13; 4 -- 14; 4 -- 15; 5 -- 16; 5 -- 17; }`, }, { name: "linear_graph_undirected", dst: undirected, nodes: IDRange{First: 0, Last: 4}, fanout: 1, want: `strict graph linear_graph_undirected { // Node definitions. 0; 1; 2; 3; 4; // Edge definitions. 0 -- 1; 1 -- 2; 2 -- 3; 3 -- 4; }`, }, { name: "full_ternary_tree_directed", dst: directed, nodes: IDRange{First: 0, Last: 12}, fanout: 3, want: `strict digraph full_ternary_tree_directed { // Node definitions. 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; // Edge definitions. 0 -> 1; 0 -> 2; 0 -> 3; 1 -> 4; 1 -> 5; 1 -> 6; 2 -> 7; 2 -> 8; 2 -> 9; 3 -> 10; 3 -> 11; 3 -> 12; }`, }, { name: "bad_fanout", dst: undirected, nodes: IDSet{0, 1, 2, 3}, fanout: -1, panics: "gen: invalid fan-out", }, { name: "collision", dst: undirected, nodes: IDSet{0, 1, 2, 3, 2}, fanout: 2, panics: "gen: node ID collision i=2 j=4: id=2", }, } for _, test := range tests { dst := test.dst() panicked, msg := panics(func() { Tree(dst, test.fanout, test.nodes) }) if msg != test.panics { t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics) } if panicked { continue } got, err := dot.Marshal(dst, test.name, "", " ") if err != nil { t.Errorf("unexpected error marshaling graph: %v", err) } if !bytes.Equal(got, []byte(test.want)) { t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/holme_kim.go000066400000000000000000000104621450372207100232720ustar00rootroot00000000000000// 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 gen import ( "errors" "fmt" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/stat/sampleuv" ) // TunableClusteringScaleFree constructs a subgraph in the destination, dst, of order n. // The graph is constructed successively starting from an m order graph with one node // having degree m-1. At each iteration of graph addition, one node is added with m // additional edges joining existing nodes with probability proportional to the nodes' // degrees. The edges are formed as a triad with probability, p. // If src is not nil it is used as the random source, otherwise rand.Float64 and // rand.Intn are used for the random number generators. // // The algorithm is essentially as described in http://arxiv.org/abs/cond-mat/0110452. func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64, src rand.Source) error { if p < 0 || p > 1 { return fmt.Errorf("gen: bad probability: p=%v", p) } if n <= m { return fmt.Errorf("gen: n <= m: n=%v m=%d", n, m) } var ( rnd func() float64 rndN func(int) int ) if src == nil { rnd = rand.Float64 rndN = rand.Intn } else { r := rand.New(src) rnd = r.Float64 rndN = r.Intn } // Initial condition. wt := make([]float64, n) id := make([]int64, n) for u := 0; u < m; u++ { un := dst.NewNode() dst.AddNode(un) id[u] = un.ID() // We need to give equal probability for // adding the first generation of edges. wt[u] = 1 } ws := sampleuv.NewWeighted(wt, src) for i := range wt { // These weights will organically grow // after the first growth iteration. wt[i] = 0 } // Growth. for v := m; v < n; v++ { vn := dst.NewNode() dst.AddNode(vn) id[v] = vn.ID() var u int pa: for i := 0; i < m; i++ { // Triad formation. if i != 0 && rnd() < p { // TODO(kortschak): Decide whether the node // order in this input to permute should be // sorted first to allow repeatable runs. for _, w := range permute(graph.NodesOf(dst.From(id[u])), rndN) { wid := w.ID() if wid == id[v] || dst.HasEdgeBetween(wid, id[v]) { continue } dst.SetEdge(dst.NewEdge(w, vn)) wt[wid]++ wt[v]++ continue pa } } // Preferential attachment. for { var ok bool u, ok = ws.Take() if !ok { return errors.New("gen: depleted distribution") } if u == v || dst.HasEdgeBetween(id[u], id[v]) { continue } dst.SetEdge(dst.NewEdge(dst.Node(id[u]), vn)) wt[u]++ wt[v]++ break } } ws.ReweightAll(wt) } return nil } func permute(n []graph.Node, rnd func(int) int) []graph.Node { for i := range n[:len(n)-1] { j := rnd(len(n)-i) + i n[i], n[j] = n[j], n[i] } return n } // PreferentialAttachment constructs a graph in the destination, dst, of order n. // The graph is constructed successively starting from an m order graph with one // node having degree m-1. At each iteration of graph addition, one node is added // with m additional edges joining existing nodes with probability proportional // to the nodes' degrees. If src is not nil it is used as the random source, // otherwise rand.Float64 is used for the random number generator. // // The algorithm is essentially as described in http://arxiv.org/abs/cond-mat/0110452 // after 10.1126/science.286.5439.509. func PreferentialAttachment(dst graph.UndirectedBuilder, n, m int, src rand.Source) error { if n <= m { return fmt.Errorf("gen: n <= m: n=%v m=%d", n, m) } // Initial condition. wt := make([]float64, n) for u := 0; u < m; u++ { if dst.Node(int64(u)) == nil { dst.AddNode(simple.Node(u)) } // We need to give equal probability for // adding the first generation of edges. wt[u] = 1 } ws := sampleuv.NewWeighted(wt, src) for i := range wt { // These weights will organically grow // after the first growth iteration. wt[i] = 0 } // Growth. for v := m; v < n; v++ { for i := 0; i < m; i++ { // Preferential attachment. u, ok := ws.Take() if !ok { return errors.New("gen: depleted distribution") } dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) wt[u]++ wt[v]++ } ws.ReweightAll(wt) } return nil } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/holme_kim_test.go000066400000000000000000000032371450372207100243330ustar00rootroot00000000000000// 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 gen import ( "testing" "gonum.org/v1/gonum/graph/simple" ) func TestTunableClusteringScaleFree(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for m := 0; m < n; m++ { for p := 0.; p <= 1; p += 0.1 { g := &gnUndirected{UndirectedBuilder: simple.NewUndirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := TunableClusteringScaleFree(g, n, m, p, nil) if err != nil { t.Fatalf("unexpected error: n=%d, m=%d, p=%v: %v", n, m, p, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: n=%d, m=%d, p=%v", n, m, p) } if g.addBackwards { t.Errorf("edge added with From.ID > To.ID: n=%d, m=%d, p=%v", n, m, p) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, m=%d, p=%v", n, m, p) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, m=%d, p=%v", n, m, p) } } } } } func TestPreferentialAttachment(t *testing.T) { t.Parallel() for n := 2; n <= 20; n++ { for m := 0; m < n; m++ { g := &gnUndirected{UndirectedBuilder: simple.NewUndirectedGraph()} err := PreferentialAttachment(g, n, m, nil) if err != nil { t.Fatalf("unexpected error: n=%d, m=%d: %v", n, m, err) } if g.addBackwards { t.Errorf("edge added with From.ID > To.ID: n=%d, m=%d", n, m) } if g.addSelfLoop { t.Errorf("unexpected self edge: n=%d, m=%d", n, m) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: n=%d, m=%d", n, m) } } } } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/small_world.go000066400000000000000000000112401450372207100236400ustar00rootroot00000000000000// 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 gen import ( "errors" "fmt" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/stat/sampleuv" ) // NavigableSmallWorld constructs an N-dimensional grid with guaranteed local connectivity // and random long-range connectivity as a subgraph in the destination, dst. // The dims parameters specifies the length of each of the N dimensions, p defines the // Manhattan distance between local nodes, and q defines the number of out-going long-range // connections from each node. Long-range connections are made with a probability // proportional to |d(u,v)|^-r where d is the Manhattan distance between non-local nodes. // // The algorithm is essentially as described on p4 of http://www.cs.cornell.edu/home/kleinber/swn.pdf. func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src rand.Source) (err error) { if p < 1 { return fmt.Errorf("gen: bad local distance: p=%v", p) } if q < 0 { return fmt.Errorf("gen: bad distant link count: q=%v", q) } if r < 0 { return fmt.Errorf("gen: bad decay constant: r=%v", r) } n := 1 for _, d := range dims { n *= d } nodes := make([]graph.Node, n) for i := range nodes { u := dst.NewNode() dst.AddNode(u) nodes[i] = u } hasEdge := dst.HasEdgeBetween d, isDirected := dst.(graph.Directed) if isDirected { hasEdge = d.HasEdgeFromTo } locality := make([]int, len(dims)) for i := range locality { locality[i] = p*2 + 1 } iterateOver(dims, func(u []int) { un := nodes[idxFrom(u, dims)] iterateOver(locality, func(delta []int) { d := manhattanDelta(u, delta, dims, -p) if d == 0 || d > p { return } vn := nodes[idxFromDelta(u, delta, dims, -p)] if un.ID() > vn.ID() { un, vn = vn, un } if !hasEdge(un.ID(), vn.ID()) { dst.SetEdge(dst.NewEdge(un, vn)) } if !isDirected { return } un, vn = vn, un if !hasEdge(un.ID(), vn.ID()) { dst.SetEdge(dst.NewEdge(un, vn)) } }) }) defer func() { r := recover() if r != nil { if r != "depleted distribution" { panic(r) } err = errors.New("depleted distribution") } }() w := make([]float64, n) ws := sampleuv.NewWeighted(w, src) iterateOver(dims, func(u []int) { un := nodes[idxFrom(u, dims)] iterateOver(dims, func(v []int) { d := manhattanBetween(u, v) if d <= p { return } w[idxFrom(v, dims)] = math.Pow(float64(d), -r) }) ws.ReweightAll(w) for i := 0; i < q; i++ { vidx, ok := ws.Take() if !ok { panic("depleted distribution") } vn := nodes[vidx] if !isDirected && un.ID() > vn.ID() { un, vn = vn, un } if !hasEdge(un.ID(), vn.ID()) { dst.SetEdge(dst.NewEdge(un, vn)) } } for i := range w { w[i] = 0 } }) return nil } // iterateOver performs an iteration over all dimensions of dims, calling fn // for each state. The elements of state must not be mutated by fn. func iterateOver(dims []int, fn func(state []int)) { iterator(0, dims, make([]int, len(dims)), fn) } func iterator(d int, dims, state []int, fn func(state []int)) { if d >= len(dims) { fn(state) return } for i := 0; i < dims[d]; i++ { state[d] = i iterator(d+1, dims, state, fn) } } // manhattanBetween returns the Manhattan distance between a and b. func manhattanBetween(a, b []int) int { if len(a) != len(b) { panic("gen: unexpected dimension") } var d int for i, v := range a { d += abs(v - b[i]) } return d } // manhattanDelta returns the Manhattan norm of delta+translate. If a // translated by delta+translate is out of the range given by dims, // zero is returned. func manhattanDelta(a, delta, dims []int, translate int) int { if len(a) != len(dims) { panic("gen: unexpected dimension") } if len(delta) != len(dims) { panic("gen: unexpected dimension") } var d int for i, v := range delta { v += translate t := a[i] + v if t < 0 || t >= dims[i] { return 0 } d += abs(v) } return d } // idxFrom returns a node index for the slice n over the given dimensions. func idxFrom(n, dims []int) int { s := 1 var id int for d, m := range dims { p := n[d] if p < 0 || p >= m { panic("gen: element out of range") } id += p * s s *= m } return id } // idxFromDelta returns a node index for the slice base plus the delta over the given // dimensions and applying the translation. func idxFromDelta(base, delta, dims []int, translate int) int { s := 1 var id int for d, m := range dims { n := base[d] + delta[d] + translate if n < 0 || n >= m { panic("gen: element out of range") } id += n * s s *= m } return id } golang-gonum-v1-gonum-0.14.0/graph/graphs/gen/small_world_test.go000066400000000000000000000042521450372207100247040ustar00rootroot00000000000000// 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 gen import ( "testing" "gonum.org/v1/gonum/graph/simple" ) var smallWorldDimensionParameters = [][]int{ {50}, {10, 10}, {6, 5, 4}, } func TestNavigableSmallWorldUndirected(t *testing.T) { t.Parallel() for p := 1; p < 5; p++ { for q := 0; q < 10; q++ { for r := 0.5; r < 10; r++ { for _, dims := range smallWorldDimensionParameters { g := &gnUndirected{UndirectedBuilder: simple.NewUndirectedGraph()} orig := g.NewNode() g.AddNode(orig) err := NavigableSmallWorld(g, dims, p, q, r, nil) n := 1 for _, d := range dims { n *= d } if err != nil { t.Fatalf("unexpected error: dims=%v n=%d, p=%d, q=%d, r=%v: %v", dims, n, p, q, r, err) } if g.From(orig.ID()).Len() != 0 { t.Errorf("edge added from already existing node: dims=%v n=%d, p=%d, q=%d, r=%v", dims, n, p, q, r) } if g.addBackwards { t.Errorf("edge added with From.ID > To.ID: dims=%v n=%d, p=%d, q=%d, r=%v", dims, n, p, q, r) } if g.addSelfLoop { t.Errorf("unexpected self edge: dims=%v n=%d, p=%d, q=%d, r=%v", dims, n, p, q, r) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: dims=%v n=%d, p=%d, q=%d, r=%v", dims, n, p, q, r) } } } } } } func TestNavigableSmallWorldDirected(t *testing.T) { t.Parallel() for p := 1; p < 5; p++ { for q := 0; q < 10; q++ { for r := 0.5; r < 10; r++ { for _, dims := range smallWorldDimensionParameters { g := &gnDirected{DirectedBuilder: simple.NewDirectedGraph()} err := NavigableSmallWorld(g, dims, p, q, r, nil) n := 1 for _, d := range dims { n *= d } if err != nil { t.Fatalf("unexpected error: dims=%v n=%d, p=%d, q=%d, r=%v: %v", dims, n, p, q, r, err) } if g.addSelfLoop { t.Errorf("unexpected self edge: dims=%v n=%d, p=%d, q=%d, r=%v", dims, n, p, q, r) } if g.addMultipleEdge { t.Errorf("unexpected multiple edge: dims=%v n=%d, p=%d, q=%d, r=%v", dims, n, p, q, r) } } } } } } golang-gonum-v1-gonum-0.14.0/graph/implicit_example_test.go000066400000000000000000000165321450372207100236610ustar00rootroot00000000000000// 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_test import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" ) // GraphNode is a node in an implicit graph. type GraphNode struct { id int64 neighbors []graph.Node roots []*GraphNode } // NewGraphNode returns a new GraphNode. func NewGraphNode(id int64) *GraphNode { return &GraphNode{id: id} } // Node allows GraphNode to satisfy the graph.Graph interface. func (g *GraphNode) Node(id int64) graph.Node { if id == g.id { return g } seen := map[int64]struct{}{g.id: {}} for _, root := range g.roots { if root.ID() == id { return root } if root.has(seen, id) { return root } } for _, n := range g.neighbors { if n.ID() == id { return n } if gn, ok := n.(*GraphNode); ok { if gn.has(seen, id) { return gn } } } return nil } func (g *GraphNode) has(seen map[int64]struct{}, id int64) bool { for _, root := range g.roots { if _, ok := seen[root.ID()]; ok { continue } seen[root.ID()] = struct{}{} if root.ID() == id { return true } if root.has(seen, id) { return true } } for _, n := range g.neighbors { if _, ok := seen[n.ID()]; ok { continue } seen[n.ID()] = struct{}{} if n.ID() == id { return true } if gn, ok := n.(*GraphNode); ok { if gn.has(seen, id) { return true } } } return false } // Nodes allows GraphNode to satisfy the graph.Graph interface. func (g *GraphNode) Nodes() graph.Nodes { nodes := []graph.Node{g} seen := map[int64]struct{}{g.id: {}} for _, root := range g.roots { nodes = append(nodes, root) seen[root.ID()] = struct{}{} nodes = root.nodes(nodes, seen) } for _, n := range g.neighbors { nodes = append(nodes, n) seen[n.ID()] = struct{}{} if gn, ok := n.(*GraphNode); ok { nodes = gn.nodes(nodes, seen) } } return iterator.NewOrderedNodes(nodes) } func (g *GraphNode) nodes(dst []graph.Node, seen map[int64]struct{}) []graph.Node { for _, root := range g.roots { if _, ok := seen[root.ID()]; ok { continue } seen[root.ID()] = struct{}{} dst = append(dst, graph.Node(root)) dst = root.nodes(dst, seen) } for _, n := range g.neighbors { if _, ok := seen[n.ID()]; ok { continue } dst = append(dst, n) if gn, ok := n.(*GraphNode); ok { dst = gn.nodes(dst, seen) } } return dst } // From allows GraphNode to satisfy the graph.Graph interface. func (g *GraphNode) From(id int64) graph.Nodes { if id == g.ID() { return iterator.NewOrderedNodes(g.neighbors) } seen := map[int64]struct{}{g.id: {}} for _, root := range g.roots { seen[root.ID()] = struct{}{} if result := root.findNeighbors(id, seen); result != nil { return iterator.NewOrderedNodes(result) } } for _, n := range g.neighbors { seen[n.ID()] = struct{}{} if gn, ok := n.(*GraphNode); ok { if result := gn.findNeighbors(id, seen); result != nil { return iterator.NewOrderedNodes(result) } } } return nil } func (g *GraphNode) findNeighbors(id int64, seen map[int64]struct{}) []graph.Node { if id == g.ID() { return g.neighbors } for _, root := range g.roots { if _, ok := seen[root.ID()]; ok { continue } seen[root.ID()] = struct{}{} if result := root.findNeighbors(id, seen); result != nil { return result } } for _, n := range g.neighbors { if _, ok := seen[n.ID()]; ok { continue } seen[n.ID()] = struct{}{} if gn, ok := n.(*GraphNode); ok { if result := gn.findNeighbors(id, seen); result != nil { return result } } } return nil } // HasEdgeBetween allows GraphNode to satisfy the graph.Graph interface. func (g *GraphNode) HasEdgeBetween(uid, vid int64) bool { return g.EdgeBetween(uid, vid) != nil } // Edge allows GraphNode to satisfy the graph.Graph interface. func (g *GraphNode) Edge(uid, vid int64) graph.Edge { return g.EdgeBetween(uid, vid) } // EdgeBetween allows GraphNode to satisfy the graph.Graph interface. func (g *GraphNode) EdgeBetween(uid, vid int64) graph.Edge { if uid == g.id || vid == g.id { for _, n := range g.neighbors { if n.ID() == uid || n.ID() == vid { return simple.Edge{F: g, T: n} } } return nil } seen := map[int64]struct{}{g.id: {}} for _, root := range g.roots { seen[root.ID()] = struct{}{} if result := root.edgeBetween(uid, vid, seen); result != nil { return result } } for _, n := range g.neighbors { seen[n.ID()] = struct{}{} if gn, ok := n.(*GraphNode); ok { if result := gn.edgeBetween(uid, vid, seen); result != nil { return result } } } return nil } func (g *GraphNode) edgeBetween(uid, vid int64, seen map[int64]struct{}) graph.Edge { if uid == g.id || vid == g.id { for _, n := range g.neighbors { if n.ID() == uid || n.ID() == vid { return simple.Edge{F: g, T: n} } } return nil } for _, root := range g.roots { if _, ok := seen[root.ID()]; ok { continue } seen[root.ID()] = struct{}{} if result := root.edgeBetween(uid, vid, seen); result != nil { return result } } for _, n := range g.neighbors { if _, ok := seen[n.ID()]; ok { continue } seen[n.ID()] = struct{}{} if gn, ok := n.(*GraphNode); ok { if result := gn.edgeBetween(uid, vid, seen); result != nil { return result } } } return nil } // ID allows GraphNode to satisfy the graph.Node interface. func (g *GraphNode) ID() int64 { return g.id } // AddMeighbor adds an edge between g and n. func (g *GraphNode) AddNeighbor(n *GraphNode) { g.neighbors = append(g.neighbors, graph.Node(n)) } // AddRoot adds provides an entrance into the graph g from n. func (g *GraphNode) AddRoot(n *GraphNode) { g.roots = append(g.roots, n) } func Example_implicit() { // This example shows the construction of the following graph // using the implicit graph type above. // // The visual representation of the graph can be seen at // https://graphviz.gitlab.io/_pages/Gallery/undirected/fdpclust.html // // graph G { // e // subgraph clusterA { // a -- b // subgraph clusterC { // C -- D // } // } // subgraph clusterB { // d -- f // } // d -- D // e -- clusterB // clusterC -- clusterB // } // graph G { G := NewGraphNode(0) // e e := NewGraphNode(1) // subgraph clusterA { clusterA := NewGraphNode(2) // a -- b a := NewGraphNode(3) b := NewGraphNode(4) a.AddNeighbor(b) b.AddNeighbor(a) clusterA.AddRoot(a) clusterA.AddRoot(b) // subgraph clusterC { clusterC := NewGraphNode(5) // C -- D C := NewGraphNode(6) D := NewGraphNode(7) C.AddNeighbor(D) D.AddNeighbor(C) clusterC.AddRoot(C) clusterC.AddRoot(D) // } clusterA.AddRoot(clusterC) // } // subgraph clusterB { clusterB := NewGraphNode(8) // d -- f d := NewGraphNode(9) f := NewGraphNode(10) d.AddNeighbor(f) f.AddNeighbor(d) clusterB.AddRoot(d) clusterB.AddRoot(f) // } // d -- D d.AddNeighbor(D) D.AddNeighbor(d) // e -- clusterB e.AddNeighbor(clusterB) clusterB.AddNeighbor(e) // clusterC -- clusterB clusterC.AddNeighbor(clusterB) clusterB.AddNeighbor(clusterC) G.AddRoot(e) G.AddRoot(clusterA) G.AddRoot(clusterB) // } if topo.IsPathIn(G, []graph.Node{C, D, d, f}) { fmt.Println("C--D--d--f is a path in G.") } // Output: // // C--D--d--f is a path in G. } golang-gonum-v1-gonum-0.14.0/graph/internal/000077500000000000000000000000001450372207100205535ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/internal/linear/000077500000000000000000000000001450372207100220255ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/internal/linear/doc.go000066400000000000000000000004431450372207100231220ustar00rootroot00000000000000// 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 linear provides common linear data structures. package linear // import "gonum.org/v1/gonum/graph/internal/linear" golang-gonum-v1-gonum-0.14.0/graph/internal/linear/linear.go000066400000000000000000000031521450372207100236270ustar00rootroot00000000000000// 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 linear import ( "gonum.org/v1/gonum/graph" ) // NodeStack implements a LIFO stack of graph.Node. type NodeStack []graph.Node // Len returns the number of graph.Nodes on the stack. func (s *NodeStack) Len() int { return len(*s) } // Pop returns the last graph.Node on the stack and removes it // from the stack. func (s *NodeStack) Pop() graph.Node { v := *s v, n := v[:len(v)-1], v[len(v)-1] *s = v return n } // Push adds the node n to the stack at the last position. func (s *NodeStack) Push(n graph.Node) { *s = append(*s, n) } // NodeQueue implements a FIFO queue. type NodeQueue struct { head int data []graph.Node } // Len returns the number of graph.Nodes in the queue. func (q *NodeQueue) Len() int { return len(q.data) - q.head } // Enqueue adds the node n to the back of the queue. func (q *NodeQueue) Enqueue(n graph.Node) { if len(q.data) == cap(q.data) && q.head > 0 { l := q.Len() copy(q.data, q.data[q.head:]) q.head = 0 q.data = append(q.data[:l], n) } else { q.data = append(q.data, n) } } // Dequeue returns the graph.Node at the front of the queue and // removes it from the queue. func (q *NodeQueue) Dequeue() graph.Node { if q.Len() == 0 { panic("queue: empty queue") } var n graph.Node n, q.data[q.head] = q.data[q.head], nil q.head++ if q.Len() == 0 { q.head = 0 q.data = q.data[:0] } return n } // Reset clears the queue for reuse. func (q *NodeQueue) Reset() { q.head = 0 q.data = q.data[:0] } golang-gonum-v1-gonum-0.14.0/graph/internal/ordered/000077500000000000000000000000001450372207100221775ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/internal/ordered/doc.go000066400000000000000000000004431450372207100232740ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/internal/ordered/sort.go000066400000000000000000000034621450372207100235220ustar00rootroot00000000000000// 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 ( "sort" "gonum.org/v1/gonum/graph" ) // ByID sorts a slice of graph.Node by ID. func ByID(n []graph.Node) { sort.Slice(n, func(i, j int) bool { return n[i].ID() < n[j].ID() }) } // BySliceValues sorts a slice of []int64 lexically by the values of the // []int64. func BySliceValues(c [][]int64) { sort.Slice(c, func(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) }) } // BySliceIDs sorts a slice of []graph.Node lexically by the IDs of the // []graph.Node. func BySliceIDs(c [][]graph.Node) { sort.Slice(c, func(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) }) } // Int64s sorts a slice of int64. func Int64s(s []int64) { sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) } // LinesByIDs sort a slice of graph.LinesByIDs lexically by the From IDs, // then by the To IDs, finally by the Line IDs. func LinesByIDs(n []graph.Line) { sort.Slice(n, func(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() }) } // 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] } } golang-gonum-v1-gonum-0.14.0/graph/internal/set/000077500000000000000000000000001450372207100213465ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/internal/set/doc.go000066400000000000000000000004301450372207100224370ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/internal/set/same.go000066400000000000000000000030241450372207100226210ustar00rootroot00000000000000// 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. //go:build !safe // +build !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)) } golang-gonum-v1-gonum-0.14.0/graph/internal/set/same_appengine.go000066400000000000000000000030041450372207100246450ustar00rootroot00000000000000// 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. //go:build safe // +build 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() } golang-gonum-v1-gonum-0.14.0/graph/internal/set/set.go000066400000000000000000000110721450372207100224710ustar00rootroot00000000000000// 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 } golang-gonum-v1-gonum-0.14.0/graph/internal/set/set_test.go000066400000000000000000000323731450372207100235370ustar00rootroot00000000000000// 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 ( "reflect" "testing" ) type node int64 func (n node) ID() int64 { return int64(n) } // TestSame tests the assumption that pointer equality via unsafe conversion // of a map[int]struct{} to uintptr is a valid test for perfect identity between // set values. If any of the tests in TestSame fail, the package is broken and same // must be reimplemented to conform to the runtime map implementation. The relevant // code to look at (at least for gc) is the hmap type in runtime/map.go. func TestSameInt64s(t *testing.T) { var ( a = make(Int64s) b = make(Int64s) c = a ) if int64sSame(a, b) { t.Error("Independently created sets test as same") } if !int64sSame(a, c) { t.Error("Set copy and original test as not same.") } a.Add(1) if !int64sSame(a, c) { t.Error("Set copy and original test as not same after addition.") } if !int64sSame(nil, nil) { t.Error("nil sets test as not same.") } if int64sSame(b, nil) { t.Error("nil and empty sets test as same.") } } func TestAddInt64s(t *testing.T) { s := make(Int64s) if s.Count() != 0 { t.Error("Set somehow contains new elements upon creation") } s.Add(1) s.Add(3) s.Add(5) if s.Count() != 3 { t.Error("Incorrect number of set elements after adding") } if !s.Has(1) || !s.Has(3) || !s.Has(5) { t.Error("Set doesn't contain element that was added") } s.Add(1) if s.Count() > 3 { t.Error("Set double-adds element (element not unique)") } else if s.Count() < 3 { t.Error("Set double-add lowered len") } if !s.Has(1) { t.Error("Set doesn't contain double-added element") } if !s.Has(3) || !s.Has(5) { t.Error("Set removes element on double-add") } } func TestRemoveInt64s(t *testing.T) { s := make(Int64s) s.Add(1) s.Add(3) s.Add(5) s.Remove(1) if s.Count() != 2 { t.Error("Incorrect number of set elements after removing an element") } if s.Has(1) { t.Error("Element present after removal") } if !s.Has(3) || !s.Has(5) { t.Error("Set remove removed wrong element") } s.Remove(1) if s.Count() != 2 || s.Has(1) { t.Error("Double set remove does something strange") } s.Add(1) if s.Count() != 3 || !s.Has(1) { t.Error("Cannot add element after removal") } } func TestSelfEqualInt64s(t *testing.T) { s := make(Int64s) if !Int64sEqual(s, s) { t.Error("Set is not equal to itself") } s.Add(1) if !Int64sEqual(s, s) { t.Error("Set ceases self equality after adding element") } } func TestEqualInt64s(t *testing.T) { a := make(Int64s) b := make(Int64s) if !Int64sEqual(a, b) { t.Error("Two different empty sets not equal") } a.Add(1) if Int64sEqual(a, b) { t.Error("Two different sets with different sizes equal") } b.Add(1) if !Int64sEqual(a, b) { t.Error("Two sets with same element not equal") } b.Remove(1) b.Add(2) if Int64sEqual(a, b) { t.Error("Two different sets with different elements equal") } } func TestSameInts(t *testing.T) { var ( a = make(Ints) b = make(Ints) c = a ) if intsSame(a, b) { t.Error("Independently created sets test as same") } if !intsSame(a, c) { t.Error("Set copy and original test as not same.") } a.Add(1) if !intsSame(a, c) { t.Error("Set copy and original test as not same after addition.") } if !intsSame(nil, nil) { t.Error("nil sets test as not same.") } if intsSame(b, nil) { t.Error("nil and empty sets test as same.") } } func TestAddInts(t *testing.T) { s := make(Ints) if s.Count() != 0 { t.Error("Set somehow contains new elements upon creation") } s.Add(1) s.Add(3) s.Add(5) if s.Count() != 3 { t.Error("Incorrect number of set elements after adding") } if !s.Has(1) || !s.Has(3) || !s.Has(5) { t.Error("Set doesn't contain element that was added") } s.Add(1) if s.Count() > 3 { t.Error("Set double-adds element (element not unique)") } else if s.Count() < 3 { t.Error("Set double-add lowered len") } if !s.Has(1) { t.Error("Set doesn't contain double-added element") } if !s.Has(3) || !s.Has(5) { t.Error("Set removes element on double-add") } } func TestRemoveInts(t *testing.T) { s := make(Ints) s.Add(1) s.Add(3) s.Add(5) s.Remove(1) if s.Count() != 2 { t.Error("Incorrect number of set elements after removing an element") } if s.Has(1) { t.Error("Element present after removal") } if !s.Has(3) || !s.Has(5) { t.Error("Set remove removed wrong element") } s.Remove(1) if s.Count() != 2 || s.Has(1) { t.Error("Double set remove does something strange") } s.Add(1) if s.Count() != 3 || !s.Has(1) { t.Error("Cannot add element after removal") } } func TestSelfEqualInts(t *testing.T) { s := make(Ints) if !IntsEqual(s, s) { t.Error("Set is not equal to itself") } s.Add(1) if !IntsEqual(s, s) { t.Error("Set ceases self equality after adding element") } } func TestEqualInts(t *testing.T) { a := make(Ints) b := make(Ints) if !IntsEqual(a, b) { t.Error("Two different empty sets not equal") } a.Add(1) if IntsEqual(a, b) { t.Error("Two different sets with different sizes equal") } b.Add(1) if !IntsEqual(a, b) { t.Error("Two sets with same element not equal") } b.Remove(1) b.Add(2) if IntsEqual(a, b) { t.Error("Two different sets with different elements equal") } } func TestSameNodes(t *testing.T) { var ( a = NewNodes() b = NewNodes() c = a ) if same(a, b) { t.Error("Independently created sets test as same") } if !same(a, c) { t.Error("Set copy and original test as not same.") } a.Add(node(1)) if !same(a, c) { t.Error("Set copy and original test as not same after addition.") } if !same(nil, nil) { t.Error("nil sets test as not same.") } if same(b, nil) { t.Error("nil and empty sets test as same.") } } func TestAddNodes(t *testing.T) { s := NewNodes() if s == nil { t.Fatal("Set cannot be created successfully") } if s.Count() != 0 { t.Error("Set somehow contains new elements upon creation") } s.Add(node(1)) s.Add(node(3)) s.Add(node(5)) if s.Count() != 3 { t.Error("Incorrect number of set elements after adding") } if !s.Has(node(1)) || !s.Has(node(3)) || !s.Has(node(5)) { t.Error("Set doesn't contain element that was added") } s.Add(node(1)) if s.Count() > 3 { t.Error("Set double-adds element (element not unique)") } else if s.Count() < 3 { t.Error("Set double-add lowered len") } if !s.Has(node(1)) { t.Error("Set doesn't contain double-added element") } if !s.Has(node(3)) || !s.Has(node(5)) { t.Error("Set removes element on double-add") } for e, n := range s { if e != n.ID() { t.Errorf("Element ID did not match key: %d != %d", e, n.ID()) } } } func TestRemoveNodes(t *testing.T) { s := NewNodes() s.Add(node(1)) s.Add(node(3)) s.Add(node(5)) s.Remove(node(1)) if s.Count() != 2 { t.Error("Incorrect number of set elements after removing an element") } if s.Has(node(1)) { t.Error("Element present after removal") } if !s.Has(node(3)) || !s.Has(node(5)) { t.Error("Set remove removed wrong element") } s.Remove(node(1)) if s.Count() != 2 || s.Has(node(1)) { t.Error("Double set remove does something strange") } s.Add(node(1)) if s.Count() != 3 || !s.Has(node(1)) { t.Error("Cannot add element after removal") } } func TestSelfEqualNodes(t *testing.T) { s := NewNodes() if !Equal(s, s) { t.Error("Set is not equal to itself") } s.Add(node(1)) if !Equal(s, s) { t.Error("Set ceases self equality after adding element") } } func TestEqualNodes(t *testing.T) { a := NewNodes() b := NewNodes() if !Equal(a, b) { t.Error("Two different empty sets not equal") } a.Add(node(1)) if Equal(a, b) { t.Error("Two different sets with different sizes equal") } b.Add(node(1)) if !Equal(a, b) { t.Error("Two sets with same element not equal") } b.Remove(node(1)) b.Add(node(2)) if Equal(a, b) { t.Error("Two different sets with different elements equal") } } func TestCopyNodes(t *testing.T) { a := NewNodes() a.Add(node(1)) a.Add(node(2)) a.Add(node(3)) b := CloneNodes(a) if !Equal(a, b) { t.Fatalf("Two sets not equal after copy: %v != %v", a, b) } b.Remove(node(1)) if Equal(a, b) { t.Errorf("Mutating one set mutated another after copy: %v == %v", a, b) } } func TestUnionSameNodes(t *testing.T) { a := NewNodes() b := NewNodes() a.Add(node(1)) a.Add(node(2)) b.Add(node(1)) b.Add(node(2)) c := UnionOfNodes(a, b) if c.Count() != 2 { t.Error("Union of same sets yields set with wrong len") } if !c.Has(node(1)) || !c.Has(node(2)) { t.Error("Union of same sets yields wrong elements") } for i, s := range []Nodes{a, b, c} { for e, n := range s { if e != n.ID() { t.Errorf("Element ID did not match key in s%d: %d != %d", i+1, e, n.ID()) } } } } func TestUnionDiffNodes(t *testing.T) { a := NewNodes() b := NewNodes() a.Add(node(1)) a.Add(node(2)) b.Add(node(3)) c := UnionOfNodes(a, b) if c.Count() != 3 { t.Error("Union of different sets yields set with wrong len") } if !c.Has(node(1)) || !c.Has(node(2)) || !c.Has(node(3)) { t.Error("Union of different sets yields set with wrong elements") } if a.Has(node(3)) || !a.Has(node(2)) || !a.Has(node(1)) || a.Count() != 2 { t.Error("Union of sets mutates non-destination set (argument 1)") } if !b.Has(node(3)) || b.Has(node(1)) || b.Has(node(2)) || b.Count() != 1 { t.Error("Union of sets mutates non-destination set (argument 2)") } for i, s := range []Nodes{a, b, c} { for e, n := range s { if e != n.ID() { t.Errorf("Element ID did not match key in s%d: %d != %d", i+1, e, n.ID()) } } } c = UnionOfNodes(a, a) if !reflect.DeepEqual(c, a) { t.Errorf("Union of equal sets not equal to sets: %v != %v", c, a) } } func TestUnionOverlappingNodes(t *testing.T) { a := NewNodes() b := NewNodes() a.Add(node(1)) a.Add(node(2)) b.Add(node(2)) b.Add(node(3)) c := UnionOfNodes(a, b) if c.Count() != 3 { t.Error("Union of overlapping sets yields set with wrong len") } if !c.Has(node(1)) || !c.Has(node(2)) || !c.Has(node(3)) { t.Error("Union of overlapping sets yields set with wrong elements") } if a.Has(node(3)) || !a.Has(node(2)) || !a.Has(node(1)) || a.Count() != 2 { t.Error("Union of sets mutates non-destination set (argument 1)") } if !b.Has(node(3)) || b.Has(node(1)) || !b.Has(node(2)) || b.Count() != 2 { t.Error("Union of sets mutates non-destination set (argument 2)") } for i, s := range []Nodes{a, b, c} { for e, n := range s { if e != n.ID() { t.Errorf("Element ID did not match key in s%d: %d != %d", i+1, e, n.ID()) } } } c = IntersectionOfNodes(a, a) if !reflect.DeepEqual(c, a) { t.Errorf("Intersection of equal sets not equal to sets: %v != %v", c, a) } } func TestIntersectSameNodes(t *testing.T) { a := NewNodes() b := NewNodes() a.Add(node(2)) a.Add(node(3)) b.Add(node(2)) b.Add(node(3)) c := IntersectionOfNodes(a, b) if card := c.Count(); card != 2 { t.Errorf("Intersection of identical sets yields set of wrong len %d", card) } if !c.Has(node(2)) || !c.Has(node(3)) { t.Error("Intersection of identical sets yields set of wrong elements") } for i, s := range []Nodes{a, b, c} { for e, n := range s { if e != n.ID() { t.Errorf("Element ID did not match key in s%d: %d != %d", i+1, e, n.ID()) } } } } func TestIntersectDiffNodes(t *testing.T) { a := NewNodes() b := NewNodes() a.Add(node(2)) a.Add(node(3)) b.Add(node(1)) b.Add(node(4)) c := IntersectionOfNodes(a, b) if card := c.Count(); card != 0 { t.Errorf("Intersection of different yields non-empty set %d", card) } if !a.Has(node(2)) || !a.Has(node(3)) || a.Has(node(1)) || a.Has(node(4)) || a.Count() != 2 { t.Error("Intersection of sets mutates non-destination set (argument 1)") } if b.Has(node(2)) || b.Has(node(3)) || !b.Has(node(1)) || !b.Has(node(4)) || b.Count() != 2 { t.Error("Intersection of sets mutates non-destination set (argument 1)") } for i, s := range []Nodes{a, b, c} { for e, n := range s { if e != n.ID() { t.Errorf("Element ID did not match key in s%d: %d != %d", i+1, e, n.ID()) } } } } func TestIntersectOverlappingNodes(t *testing.T) { a := NewNodes() b := NewNodes() a.Add(node(2)) a.Add(node(3)) b.Add(node(3)) b.Add(node(4)) c := IntersectionOfNodes(a, b) if card := c.Count(); card != 1 { t.Errorf("Intersection of overlapping sets yields set of incorrect len %d", card) } if !c.Has(node(3)) { t.Errorf("Intersection of overlapping sets yields set with wrong element") } if !a.Has(node(2)) || !a.Has(node(3)) || a.Has(node(4)) || a.Count() != 2 { t.Error("Intersection of sets mutates non-destination set (argument 1)") } if b.Has(node(2)) || !b.Has(node(3)) || !b.Has(node(4)) || b.Count() != 2 { t.Error("Intersection of sets mutates non-destination set (argument 1)") } for i, s := range []Nodes{a, b, c} { for e, n := range s { if e != n.ID() { t.Errorf("Element ID did not match key in s%d: %d != %d", i+1, e, n.ID()) } } } c = IntersectionOfNodes(c, a) want := Nodes{3: node(3)} if !reflect.DeepEqual(c, want) { t.Errorf("Intersection of sets with dst equal to a not equal: %v != %v", c, want) } c = IntersectionOfNodes(a, c) if !reflect.DeepEqual(c, want) { t.Errorf("Intersection of sets with dst equal to a not equal: %v != %v", c, want) } } golang-gonum-v1-gonum-0.14.0/graph/iterator/000077500000000000000000000000001450372207100205705ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/iterator/doc.go000066400000000000000000000005231450372207100216640ustar00rootroot00000000000000// 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 golang-gonum-v1-gonum-0.14.0/graph/iterator/edges.go000066400000000000000000000063511450372207100222130ustar00rootroot00000000000000// 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 } golang-gonum-v1-gonum-0.14.0/graph/iterator/edges_test.go000066400000000000000000000070311450372207100232460ustar00rootroot00000000000000// 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_test import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) type edge struct{ f, t int } func (e edge) From() graph.Node { return simple.Node(e.f) } func (e edge) To() graph.Node { return simple.Node(e.t) } func (e edge) ReversedEdge() graph.Edge { return edge{f: e.t, t: e.f} } var orderedEdgesTests = []struct { edges []graph.Edge }{ {edges: nil}, {edges: []graph.Edge{edge{f: 1, t: 2}}}, {edges: []graph.Edge{edge{f: 1, t: 2}, edge{f: 2, t: 3}, edge{f: 3, t: 4}, edge{f: 4, t: 5}}}, {edges: []graph.Edge{edge{f: 5, t: 4}, edge{f: 4, t: 3}, edge{f: 3, t: 2}, edge{f: 2, t: 1}}}, } func TestOrderedEdgesIterate(t *testing.T) { for _, test := range orderedEdgesTests { it := iterator.NewOrderedEdges(test.edges) for i := 0; i < 2; i++ { if it.Len() != len(test.edges) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.edges)) } var got []graph.Edge for it.Next() { got = append(got, it.Edge()) } want := test.edges if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } func TestOrderedEdgesSlice(t *testing.T) { for _, test := range orderedEdgesTests { it := iterator.NewOrderedEdges(test.edges) for i := 0; i < 2; i++ { got := it.EdgeSlice() want := test.edges if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } type weightedEdge struct { f, t int w float64 } func (e weightedEdge) From() graph.Node { return simple.Node(e.f) } func (e weightedEdge) To() graph.Node { return simple.Node(e.t) } func (e weightedEdge) ReversedEdge() graph.Edge { e.f, e.t = e.t, e.f; return e } func (e weightedEdge) Weight() float64 { return e.w } var orderedWeightedEdgesTests = []struct { edges []graph.WeightedEdge }{ {edges: nil}, {edges: []graph.WeightedEdge{weightedEdge{f: 1, t: 2, w: 1}}}, {edges: []graph.WeightedEdge{weightedEdge{f: 1, t: 2, w: 1}, weightedEdge{f: 2, t: 3, w: 2}, weightedEdge{f: 3, t: 4, w: 3}, weightedEdge{f: 4, t: 5, w: 4}}}, {edges: []graph.WeightedEdge{weightedEdge{f: 5, t: 4, w: 4}, weightedEdge{f: 4, t: 3, w: 3}, weightedEdge{f: 3, t: 2, w: 2}, weightedEdge{f: 2, t: 1, w: 1}}}, } func TestOrderedWeightedEdgesIterate(t *testing.T) { for _, test := range orderedWeightedEdgesTests { it := iterator.NewOrderedWeightedEdges(test.edges) for i := 0; i < 2; i++ { if it.Len() != len(test.edges) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.edges)) } var got []graph.WeightedEdge for it.Next() { got = append(got, it.WeightedEdge()) } want := test.edges if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } func TestOrderedWeightedEdgesSlice(t *testing.T) { for _, test := range orderedWeightedEdgesTests { it := iterator.NewOrderedWeightedEdges(test.edges) for i := 0; i < 2; i++ { got := it.WeightedEdgeSlice() want := test.edges if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } golang-gonum-v1-gonum-0.14.0/graph/iterator/lines.go000066400000000000000000000063511450372207100222360ustar00rootroot00000000000000// 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 } golang-gonum-v1-gonum-0.14.0/graph/iterator/lines_map.go000066400000000000000000000071311450372207100230700ustar00rootroot00000000000000// Copyright ©2021 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:build !safe // +build !safe package iterator import "gonum.org/v1/gonum/graph" // Lines implements the graph.Lines interfaces. // The iteration order of Lines is randomized. type Lines struct { lines int iter *mapIter pos int curr graph.Line } // NewLines returns a Lines initialized with the provided lines, a // map of line IDs to graph.Lines. No check is made that the keys // match the graph.Line IDs, and the map keys are not used. // // Behavior of the Lines is unspecified if lines is mutated after // the call to NewLines. func NewLines(lines map[int64]graph.Line) *Lines { return &Lines{lines: len(lines), iter: newMapIterLines(lines)} } // Len returns the remaining number of lines to be iterated over. func (l *Lines) Len() int { return l.lines - l.pos } // Next returns whether the next call of Line will return a valid line. func (l *Lines) Next() bool { if l.pos >= l.lines { return false } ok := l.iter.next() if ok { l.pos++ l.curr = l.iter.line() } return ok } // Line returns the current line of the iterator. Next must have been // called prior to a call to Line. func (l *Lines) Line() graph.Line { return l.curr } // Reset returns the iterator to its initial state. func (l *Lines) Reset() { l.curr = nil l.pos = 0 l.iter.hiter = hiter{} } // LineSlice returns all the remaining lines in the iterator and advances // the iterator. The order of lines within the returned slice is not // specified. func (l *Lines) LineSlice() []graph.Line { if l.Len() == 0 { return nil } lines := make([]graph.Line, 0, l.Len()) for l.iter.next() { lines = append(lines, l.iter.line()) } l.pos = l.lines return lines } // WeightedLines implements the graph.WeightedLines interfaces. // The iteration order of WeightedLines is randomized. type WeightedLines struct { lines int iter *mapIter pos int curr graph.WeightedLine } // NewWeightedLines returns a WeightedLines initialized with the provided lines, a // map of line IDs to graph.WeightedLines. No check is made that the keys // match the graph.WeightedLine IDs, and the map keys are not used. // // Behavior of the WeightedLines is unspecified if lines is mutated after // the call to NewWeightedLines. func NewWeightedLines(lines map[int64]graph.WeightedLine) *WeightedLines { return &WeightedLines{lines: len(lines), iter: newMapIterWeightedLines(lines)} } // Len returns the remaining number of lines to be iterated over. func (l *WeightedLines) Len() int { return l.lines - l.pos } // Next returns whether the next call of Line will return a valid line. func (l *WeightedLines) Next() bool { if l.pos >= l.lines { return false } ok := l.iter.next() if ok { l.pos++ l.curr = l.iter.weightedLine() } return ok } // WeightedLine returns the current line of the iterator. Next must have been // called prior to a call to WeightedLine. func (l *WeightedLines) WeightedLine() graph.WeightedLine { return l.curr } // Reset returns the iterator to its initial state. func (l *WeightedLines) Reset() { l.curr = nil l.pos = 0 l.iter.hiter = hiter{} } // WeightedLineSlice returns all the remaining lines in the iterator and advances // the iterator. The order of lines within the returned slice is not // specified. func (l *WeightedLines) WeightedLineSlice() []graph.WeightedLine { if l.Len() == 0 { return nil } lines := make([]graph.WeightedLine, 0, l.Len()) for l.iter.next() { lines = append(lines, l.iter.weightedLine()) } l.pos = l.lines return lines } golang-gonum-v1-gonum-0.14.0/graph/iterator/lines_map_safe.go000066400000000000000000000074741450372207100241000ustar00rootroot00000000000000// Copyright ©2021 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:build safe // +build safe package iterator import ( "reflect" "gonum.org/v1/gonum/graph" ) // Lines implements the graph.Lines interfaces. // The iteration order of Lines is randomized. type Lines struct { lines reflect.Value iter *reflect.MapIter pos int curr graph.Line } // NewLines returns a Lines initialized with the provided lines, a // map of line IDs to graph.Lines. No check is made that the keys // match the graph.Line IDs, and the map keys are not used. // // Behavior of the Lines is unspecified if lines is mutated after // the call to NewLines. func NewLines(lines map[int64]graph.Line) *Lines { rv := reflect.ValueOf(lines) return &Lines{lines: rv, iter: rv.MapRange()} } // Len returns the remaining number of lines to be iterated over. func (l *Lines) Len() int { return l.lines.Len() - l.pos } // Next returns whether the next call of Line will return a valid line. func (l *Lines) Next() bool { if l.pos >= l.lines.Len() { return false } ok := l.iter.Next() if ok { l.pos++ l.curr = l.iter.Value().Interface().(graph.Line) } return ok } // Line returns the current line of the iterator. Next must have been // called prior to a call to Line. func (l *Lines) Line() graph.Line { return l.curr } // Reset returns the iterator to its initial state. func (l *Lines) Reset() { l.curr = nil l.pos = 0 l.iter = l.lines.MapRange() } // LineSlice returns all the remaining lines in the iterator and advances // the iterator. The order of lines within the returned slice is not // specified. func (l *Lines) LineSlice() []graph.Line { if l.Len() == 0 { return nil } lines := make([]graph.Line, 0, l.Len()) for l.iter.Next() { lines = append(lines, l.iter.Value().Interface().(graph.Line)) } l.pos = l.lines.Len() return lines } // WeightedLines implements the graph.WeightedLines interfaces. // The iteration order of WeightedLines is randomized. type WeightedLines struct { lines reflect.Value iter *reflect.MapIter pos int curr graph.WeightedLine } // NewWeightedLines returns a WeightedLines initialized with the provided lines, a // map of line IDs to graph.WeightedLines. No check is made that the keys // match the graph.WeightedLine IDs, and the map keys are not used. // // Behavior of the WeightedLines is unspecified if lines is mutated after // the call to NewWeightedLines. func NewWeightedLines(lines map[int64]graph.WeightedLine) *WeightedLines { rv := reflect.ValueOf(lines) return &WeightedLines{lines: rv, iter: rv.MapRange()} } // Len returns the remaining number of lines to be iterated over. func (l *WeightedLines) Len() int { return l.lines.Len() - l.pos } // Next returns whether the next call of WeightedLine will return a valid line. func (l *WeightedLines) Next() bool { if l.pos >= l.lines.Len() { return false } ok := l.iter.Next() if ok { l.pos++ l.curr = l.iter.Value().Interface().(graph.WeightedLine) } return ok } // WeightedLine returns the current line of the iterator. Next must have been // called prior to a call to WeightedLine. func (l *WeightedLines) WeightedLine() graph.WeightedLine { return l.curr } // Reset returns the iterator to its initial state. func (l *WeightedLines) Reset() { l.curr = nil l.pos = 0 l.iter = l.lines.MapRange() } // WeightedLineSlice returns all the remaining lines in the iterator and advances // the iterator. The order of lines within the returned slice is not // specified. func (l *WeightedLines) WeightedLineSlice() []graph.WeightedLine { if l.Len() == 0 { return nil } lines := make([]graph.WeightedLine, 0, l.Len()) for l.iter.Next() { lines = append(lines, l.iter.Value().Interface().(graph.WeightedLine)) } l.pos = l.lines.Len() return lines } golang-gonum-v1-gonum-0.14.0/graph/iterator/lines_test.go000066400000000000000000000160671450372207100233020ustar00rootroot00000000000000// 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_test import ( "reflect" "sort" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) type line struct{ f, t, id int64 } func (l line) From() graph.Node { return simple.Node(l.f) } func (l line) To() graph.Node { return simple.Node(l.t) } func (l line) ReversedLine() graph.Line { l.f, l.t = l.t, l.f; return l } func (l line) ID() int64 { return l.id } var linesTests = []struct { lines map[int64]graph.Line }{ {lines: nil}, {lines: map[int64]graph.Line{1: line{f: 1, t: 2, id: 1}}}, {lines: map[int64]graph.Line{1: line{f: 1, t: 2, id: 1}, 2: line{f: 2, t: 3, id: 2}, 3: line{f: 3, t: 4, id: 3}, 4: line{f: 4, t: 5, id: 4}}}, {lines: map[int64]graph.Line{4: line{f: 5, t: 4, id: 4}, 3: line{f: 4, t: 3, id: 3}, 2: line{f: 3, t: 2, id: 2}, 1: line{f: 2, t: 1, id: 1}}}, } func TestLinesIterate(t *testing.T) { for _, test := range linesTests { it := iterator.NewLines(test.lines) for i := 0; i < 2; i++ { if it.Len() != len(test.lines) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.lines)) } var got map[int64]graph.Line if it.Len() != 0 { got = make(map[int64]graph.Line) } for it.Next() { got[it.Line().ID()] = it.Line() } want := test.lines if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } func TestLinesSlice(t *testing.T) { for _, test := range linesTests { it := iterator.NewLines(test.lines) for i := 0; i < 2; i++ { got := it.LineSlice() var want []graph.Line for _, l := range test.lines { want = append(want, l) } sort.Slice(got, func(i, j int) bool { return got[i].ID() < got[j].ID() }) sort.Slice(want, func(i, j int) bool { return want[i].ID() < want[j].ID() }) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } var orderedLinesTests = []struct { lines []graph.Line }{ {lines: nil}, {lines: []graph.Line{line{f: 1, t: 2}}}, {lines: []graph.Line{line{f: 1, t: 2}, line{f: 2, t: 3}, line{f: 3, t: 4}, line{f: 4, t: 5}}}, {lines: []graph.Line{line{f: 5, t: 4}, line{f: 4, t: 3}, line{f: 3, t: 2}, line{f: 2, t: 1}}}, } func TestOrderedLinesIterate(t *testing.T) { for _, test := range orderedLinesTests { it := iterator.NewOrderedLines(test.lines) for i := 0; i < 2; i++ { if it.Len() != len(test.lines) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.lines)) } var got []graph.Line for it.Next() { got = append(got, it.Line()) } want := test.lines if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } func TestOrderedLinesSlice(t *testing.T) { for _, test := range orderedLinesTests { it := iterator.NewOrderedLines(test.lines) for i := 0; i < 2; i++ { got := it.LineSlice() want := test.lines if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } type weightedLine struct { f, t, id int64 w float64 } func (l weightedLine) From() graph.Node { return simple.Node(l.f) } func (l weightedLine) To() graph.Node { return simple.Node(l.t) } func (l weightedLine) ReversedLine() graph.Line { l.f, l.t = l.t, l.f; return l } func (l weightedLine) Weight() float64 { return l.w } func (l weightedLine) ID() int64 { return l.id } var weightedLinesTests = []struct { lines map[int64]graph.WeightedLine }{ {lines: nil}, {lines: map[int64]graph.WeightedLine{2: weightedLine{f: 1, t: 2, w: 1, id: 2}}}, {lines: map[int64]graph.WeightedLine{2: weightedLine{f: 1, t: 2, w: 1, id: 2}, 4: weightedLine{f: 2, t: 3, w: 2, id: 4}, 6: weightedLine{f: 3, t: 4, w: 3, id: 6}, 8: weightedLine{f: 4, t: 5, w: 4, id: 8}}}, {lines: map[int64]graph.WeightedLine{8: weightedLine{f: 5, t: 4, w: 4, id: 8}, 6: weightedLine{f: 4, t: 3, w: 3, id: 6}, 4: weightedLine{f: 3, t: 2, w: 2, id: 4}, 2: weightedLine{f: 2, t: 1, w: 1, id: 2}}}, } func TestWeightedLinesIterate(t *testing.T) { for _, test := range weightedLinesTests { it := iterator.NewWeightedLines(test.lines) for i := 0; i < 2; i++ { if it.Len() != len(test.lines) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.lines)) } var got map[int64]graph.WeightedLine if it.Len() != 0 { got = make(map[int64]graph.WeightedLine) } for it.Next() { got[it.WeightedLine().ID()] = it.WeightedLine() } want := test.lines if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } func TestWeightedLinesSlice(t *testing.T) { for _, test := range weightedLinesTests { it := iterator.NewWeightedLines(test.lines) for i := 0; i < 2; i++ { got := it.WeightedLineSlice() var want []graph.WeightedLine for _, l := range test.lines { want = append(want, l) } sort.Slice(got, func(i, j int) bool { return got[i].ID() < got[j].ID() }) sort.Slice(want, func(i, j int) bool { return want[i].ID() < want[j].ID() }) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } var orderedWeightedLinesTests = []struct { lines []graph.WeightedLine }{ {lines: nil}, {lines: []graph.WeightedLine{weightedLine{f: 1, t: 2, w: 1}}}, {lines: []graph.WeightedLine{weightedLine{f: 1, t: 2, w: 1}, weightedLine{f: 2, t: 3, w: 2}, weightedLine{f: 3, t: 4, w: 3}, weightedLine{f: 4, t: 5, w: 4}}}, {lines: []graph.WeightedLine{weightedLine{f: 5, t: 4, w: 4}, weightedLine{f: 4, t: 3, w: 3}, weightedLine{f: 3, t: 2, w: 2}, weightedLine{f: 2, t: 1, w: 1}}}, } func TestOrderedWeightedLinesIterate(t *testing.T) { for _, test := range orderedWeightedLinesTests { it := iterator.NewOrderedWeightedLines(test.lines) for i := 0; i < 2; i++ { if it.Len() != len(test.lines) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.lines)) } var got []graph.WeightedLine for it.Next() { got = append(got, it.WeightedLine()) } want := test.lines if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } func TestOrderedWeightedLinesSlice(t *testing.T) { for _, test := range orderedWeightedLinesTests { it := iterator.NewOrderedWeightedLines(test.lines) for i := 0; i < 2; i++ { got := it.WeightedLineSlice() want := test.lines if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } golang-gonum-v1-gonum-0.14.0/graph/iterator/map.go000066400000000000000000000123501450372207100216750ustar00rootroot00000000000000// Copyright ©2020 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 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !safe // +build !safe package iterator import ( "unsafe" "gonum.org/v1/gonum/graph" ) // A mapIter is an iterator for ranging over a map. type mapIter struct { m *emptyInterface hiter hiter } type emptyInterface struct { typ, word unsafe.Pointer } // hiter's structure matches runtime.hiter's structure. // Having a clone here allows us to embed a map iterator // inside type mapIter so that mapIters can be re-used // without doing any allocations. // //lint:ignore U1000 This is a verbatim copy of the runtime type. type hiter struct { key unsafe.Pointer elem unsafe.Pointer t unsafe.Pointer h unsafe.Pointer buckets unsafe.Pointer bptr unsafe.Pointer overflow *[]unsafe.Pointer oldoverflow *[]unsafe.Pointer startBucket uintptr offset uint8 wrapped bool B uint8 i uint8 bucket uintptr checkBucket uintptr } func (h *hiter) initialized() bool { return h.t != nil } // newMapIterNodes returns a range iterator for a map of nodes. // The returned mapIter must not have its line or weightedLine methods called. func newMapIterNodes(m map[int64]graph.Node) *mapIter { return &mapIter{m: eface(m)} } // newMapIterEdges returns a range iterator for a map of edges. // The returned mapIter must not have its node, line or weightedLine methods called. func newMapIterEdges(m map[int64]graph.Edge) *mapIter { return &mapIter{m: eface(m)} } // newMapIterLines returns a range iterator for a map of line. // The returned mapIter must not have its node or weightedLine method called. func newMapIterLines(m map[int64]graph.Line) *mapIter { return &mapIter{m: eface(m)} } // newMapIterWeightedLines returns a range iterator for a map of line. // The returned mapIter must not have its node, line or weightedLine methods called. func newMapIterWeightedLines(m map[int64]graph.WeightedLine) *mapIter { return &mapIter{m: eface(m)} } // newMapIterByWeightedEdges returns a range iterator for a map of edges. // The returned mapIter must not have its node, line or weightedLine methods called. func newMapIterByWeightedEdges(m map[int64]graph.WeightedEdge) *mapIter { return &mapIter{m: eface(m)} } // newMapIterByLines returns a range iterator for a map of edges. // The returned mapIter must not have its node, line or weightedLine methods called. func newMapIterByLines(m map[int64]map[int64]graph.Line) *mapIter { return &mapIter{m: eface(m)} } // newMapIterByWeightedLines returns a range iterator for a map of edges. // The returned mapIter must not have its node, line or weightedLine methods called. func newMapIterByWeightedLines(m map[int64]map[int64]graph.WeightedLine) *mapIter { return &mapIter{m: eface(m)} } func eface(i interface{}) *emptyInterface { return (*emptyInterface)(unsafe.Pointer(&i)) } // id returns the key of the iterator's current map entry. func (it *mapIter) id() int64 { if !it.hiter.initialized() { panic("mapIter.id called before Next") } if mapiterkey(&it.hiter) == nil { panic("mapIter.id called on exhausted iterator") } return *(*int64)(mapiterkey(&it.hiter)) } // node returns the value of the iterator's current map entry. func (it *mapIter) node() graph.Node { if !it.hiter.initialized() { panic("mapIter.node called before next") } if mapiterkey(&it.hiter) == nil { panic("mapIter.node called on exhausted iterator") } return *(*graph.Node)(mapiterelem(&it.hiter)) } // line returns the value of the iterator's current map entry. func (it *mapIter) line() graph.Line { if !it.hiter.initialized() { panic("mapIter.line called before next") } if mapiterkey(&it.hiter) == nil { panic("mapIter.line called on exhausted iterator") } return *(*graph.Line)(mapiterelem(&it.hiter)) } // weightedLine returns the value of the iterator's current map entry. func (it *mapIter) weightedLine() graph.WeightedLine { if !it.hiter.initialized() { panic("mapIter.weightedLine called before next") } if mapiterkey(&it.hiter) == nil { panic("mapIter.weightedLine called on exhausted iterator") } return *(*graph.WeightedLine)(mapiterelem(&it.hiter)) } // next advances the map iterator and reports whether there is another // entry. It returns false when the iterator is exhausted; subsequent // calls to Key, Value, or next will panic. func (it *mapIter) next() bool { if !it.hiter.initialized() { mapiterinit(it.m.typ, it.m.word, &it.hiter) } else { if mapiterkey(&it.hiter) == nil { panic("mapIter.next called on exhausted iterator") } mapiternext(&it.hiter) } return mapiterkey(&it.hiter) != nil } //go:linkname mapiterinit runtime.mapiterinit //go:noescape func mapiterinit(t, m unsafe.Pointer, it *hiter) //go:linkname mapiterkey reflect.mapiterkey //go:noescape func mapiterkey(it *hiter) (key unsafe.Pointer) //go:linkname mapiterelem reflect.mapiterelem //go:noescape func mapiterelem(it *hiter) (elem unsafe.Pointer) //go:linkname mapiternext reflect.mapiternext //go:noescape func mapiternext(it *hiter) golang-gonum-v1-gonum-0.14.0/graph/iterator/map.s000066400000000000000000000003521450372207100215310ustar00rootroot00000000000000// Copyright ©2020 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. // Empty .s file to allow //go:linkname directives in map.go to work.golang-gonum-v1-gonum-0.14.0/graph/iterator/nodes.go000066400000000000000000000276041450372207100222400ustar00rootroot00000000000000// 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" // 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 } return len(n.nodes[n.idx+1:]) } // 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 + 1 n.idx = len(n.nodes) return n.nodes[idx:] } // Reset returns the iterator to its initial state. func (n *OrderedNodes) Reset() { n.idx = -1 } // LazyOrderedNodes implements the graph.Nodes and graph.NodeSlicer interfaces. // The iteration order of LazyOrderedNodes is not determined until the first // call to Next or NodeSlice. After that, the iteration order is fixed. type LazyOrderedNodes struct { iter OrderedNodes nodes map[int64]graph.Node } // NewLazyOrderedNodes returns a LazyOrderedNodes initialized with the provided nodes. func NewLazyOrderedNodes(nodes map[int64]graph.Node) *LazyOrderedNodes { return &LazyOrderedNodes{nodes: nodes} } // Len returns the remaining number of nodes to be iterated over. func (n *LazyOrderedNodes) Len() int { if n.iter.nodes == nil { return len(n.nodes) } return n.iter.Len() } // Next returns whether the next call of Node will return a valid node. func (n *LazyOrderedNodes) Next() bool { if n.iter.nodes == nil { n.fillSlice() } return n.iter.Next() } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *LazyOrderedNodes) Node() graph.Node { return n.iter.Node() } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. func (n *LazyOrderedNodes) NodeSlice() []graph.Node { if n.iter.nodes == nil { n.fillSlice() } return n.iter.NodeSlice() } // Reset returns the iterator to its initial state. func (n *LazyOrderedNodes) Reset() { n.iter.Reset() } func (n *LazyOrderedNodes) fillSlice() { n.iter = OrderedNodes{idx: -1, nodes: make([]graph.Node, len(n.nodes))} i := 0 for _, u := range n.nodes { n.iter.nodes[i] = u i++ } n.nodes = nil } // LazyOrderedNodesByEdge implements the graph.Nodes and graph.NodeSlicer interfaces. // The iteration order of LazyOrderedNodesByEdge is not determined until the first // call to Next or NodeSlice. After that, the iteration order is fixed. type LazyOrderedNodesByEdge struct { iter OrderedNodes nodes map[int64]graph.Node edges map[int64]graph.Edge } // NewLazyOrderedNodesByEdge returns a LazyOrderedNodesByEdge initialized with the // provided nodes. func NewLazyOrderedNodesByEdge(nodes map[int64]graph.Node, edges map[int64]graph.Edge) *LazyOrderedNodesByEdge { return &LazyOrderedNodesByEdge{nodes: nodes, edges: edges} } // Len returns the remaining number of nodes to be iterated over. func (n *LazyOrderedNodesByEdge) Len() int { if n.iter.nodes == nil { return len(n.edges) } return n.iter.Len() } // Next returns whether the next call of Node will return a valid node. func (n *LazyOrderedNodesByEdge) Next() bool { if n.iter.nodes == nil { n.fillSlice() } return n.iter.Next() } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *LazyOrderedNodesByEdge) Node() graph.Node { return n.iter.Node() } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. func (n *LazyOrderedNodesByEdge) NodeSlice() []graph.Node { if n.iter.nodes == nil { n.fillSlice() } return n.iter.NodeSlice() } // Reset returns the iterator to its initial state. func (n *LazyOrderedNodesByEdge) Reset() { n.iter.Reset() } func (n *LazyOrderedNodesByEdge) fillSlice() { n.iter = OrderedNodes{idx: -1, nodes: make([]graph.Node, len(n.edges))} i := 0 for id := range n.edges { n.iter.nodes[i] = n.nodes[id] i++ } n.nodes = nil n.edges = nil } // LazyOrderedNodesByWeightedEdge implements the graph.Nodes and graph.NodeSlicer interfaces. // The iteration order of LazyOrderedNodesByEeightedEdge is not determined until the first // call to Next or NodeSlice. After that, the iteration order is fixed. type LazyOrderedNodesByWeightedEdge struct { iter OrderedNodes nodes map[int64]graph.Node edges map[int64]graph.WeightedEdge } // NewLazyOrderedNodesByWeightedEdge returns a LazyOrderedNodesByEdge initialized with the // provided nodes. func NewLazyOrderedNodesByWeightedEdge(nodes map[int64]graph.Node, edges map[int64]graph.WeightedEdge) *LazyOrderedNodesByWeightedEdge { return &LazyOrderedNodesByWeightedEdge{nodes: nodes, edges: edges} } // Len returns the remaining number of nodes to be iterated over. func (n *LazyOrderedNodesByWeightedEdge) Len() int { if n.iter.nodes == nil { return len(n.edges) } return n.iter.Len() } // Next returns whether the next call of Node will return a valid node. func (n *LazyOrderedNodesByWeightedEdge) Next() bool { if n.iter.nodes == nil { n.fillSlice() } return n.iter.Next() } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *LazyOrderedNodesByWeightedEdge) Node() graph.Node { return n.iter.Node() } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. func (n *LazyOrderedNodesByWeightedEdge) NodeSlice() []graph.Node { if n.iter.nodes == nil { n.fillSlice() } return n.iter.NodeSlice() } // Reset returns the iterator to its initial state. func (n *LazyOrderedNodesByWeightedEdge) Reset() { n.iter.Reset() } func (n *LazyOrderedNodesByWeightedEdge) fillSlice() { n.iter = OrderedNodes{idx: -1, nodes: make([]graph.Node, len(n.edges))} i := 0 for id := range n.edges { n.iter.nodes[i] = n.nodes[id] i++ } n.nodes = nil n.edges = nil } // LazyOrderedNodesByLines implements the graph.Nodes and graph.NodeSlicer interfaces. // The iteration order of LazyOrderedNodesByLines is not determined until the first // call to Next or NodeSlice. After that, the iteration order is fixed. type LazyOrderedNodesByLines struct { iter OrderedNodes nodes map[int64]graph.Node edges map[int64]map[int64]graph.Line } // NewLazyOrderedNodesByLine returns a LazyOrderedNodesByLines initialized with the // provided nodes. func NewLazyOrderedNodesByLines(nodes map[int64]graph.Node, edges map[int64]map[int64]graph.Line) *LazyOrderedNodesByLines { return &LazyOrderedNodesByLines{nodes: nodes, edges: edges} } // Len returns the remaining number of nodes to be iterated over. func (n *LazyOrderedNodesByLines) Len() int { if n.iter.nodes == nil { return len(n.edges) } return n.iter.Len() } // Next returns whether the next call of Node will return a valid node. func (n *LazyOrderedNodesByLines) Next() bool { if n.iter.nodes == nil { n.fillSlice() } return n.iter.Next() } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *LazyOrderedNodesByLines) Node() graph.Node { return n.iter.Node() } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. func (n *LazyOrderedNodesByLines) NodeSlice() []graph.Node { if n.iter.nodes == nil { n.fillSlice() } return n.iter.NodeSlice() } // Reset returns the iterator to its initial state. func (n *LazyOrderedNodesByLines) Reset() { n.iter.Reset() } func (n *LazyOrderedNodesByLines) fillSlice() { n.iter = OrderedNodes{idx: -1, nodes: make([]graph.Node, len(n.edges))} i := 0 for id := range n.edges { n.iter.nodes[i] = n.nodes[id] i++ } n.nodes = nil n.edges = nil } // LazyOrderedNodesByWeightedLines implements the graph.Nodes and graph.NodeSlicer interfaces. // The iteration order of LazyOrderedNodesByEeightedLine is not determined until the first // call to Next or NodeSlice. After that, the iteration order is fixed. type LazyOrderedNodesByWeightedLines struct { iter OrderedNodes nodes map[int64]graph.Node edges map[int64]map[int64]graph.WeightedLine } // NewLazyOrderedNodesByWeightedLines returns a LazyOrderedNodesByLines initialized with the // provided nodes. func NewLazyOrderedNodesByWeightedLines(nodes map[int64]graph.Node, edges map[int64]map[int64]graph.WeightedLine) *LazyOrderedNodesByWeightedLines { return &LazyOrderedNodesByWeightedLines{nodes: nodes, edges: edges} } // Len returns the remaining number of nodes to be iterated over. func (n *LazyOrderedNodesByWeightedLines) Len() int { if n.iter.nodes == nil { return len(n.edges) } return n.iter.Len() } // Next returns whether the next call of Node will return a valid node. func (n *LazyOrderedNodesByWeightedLines) Next() bool { if n.iter.nodes == nil { n.fillSlice() } return n.iter.Next() } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *LazyOrderedNodesByWeightedLines) Node() graph.Node { return n.iter.Node() } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. func (n *LazyOrderedNodesByWeightedLines) NodeSlice() []graph.Node { if n.iter.nodes == nil { n.fillSlice() } return n.iter.NodeSlice() } // Reset returns the iterator to its initial state. func (n *LazyOrderedNodesByWeightedLines) Reset() { n.iter.Reset() } func (n *LazyOrderedNodesByWeightedLines) fillSlice() { n.iter = OrderedNodes{idx: -1, nodes: make([]graph.Node, len(n.edges))} i := 0 for id := range n.edges { n.iter.nodes[i] = n.nodes[id] i++ } n.nodes = nil n.edges = nil } // 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 { if n.end <= n.curr { return 0 } 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 { if n.Len() == 0 { return nil } 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 } golang-gonum-v1-gonum-0.14.0/graph/iterator/nodes_map.go000066400000000000000000000132261450372207100230700ustar00rootroot00000000000000// 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. //go:build !safe // +build !safe package iterator import "gonum.org/v1/gonum/graph" // Nodes implements the graph.Nodes interfaces. // The iteration order of Nodes is randomized. type Nodes struct { nodes int iter *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 to NewNodes. func NewNodes(nodes map[int64]graph.Node) *Nodes { return &Nodes{nodes: len(nodes), iter: newMapIterNodes(nodes)} } // Len returns the remaining number of nodes to be iterated over. func (n *Nodes) Len() int { return n.nodes - 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 { return false } ok := n.iter.next() if ok { n.pos++ n.curr = n.iter.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.hiter = hiter{} } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. The order of nodes within the returned slice is not // specified. func (n *Nodes) NodeSlice() []graph.Node { if n.Len() == 0 { return nil } nodes := make([]graph.Node, 0, n.Len()) for n.iter.next() { nodes = append(nodes, n.iter.node()) } n.pos = n.nodes return nodes } // NodesByEdge implements the graph.Nodes interfaces. // The iteration order of Nodes is randomized. type NodesByEdge struct { nodes map[int64]graph.Node edges int iter *mapIter pos int curr graph.Node } // NewNodesByEdge returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of edges, a map of to-node IDs to graph.Edge, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or edges // is mutated after the call to NewNodes. func NewNodesByEdge(nodes map[int64]graph.Node, edges map[int64]graph.Edge) *NodesByEdge { return &NodesByEdge{nodes: nodes, edges: len(edges), iter: newMapIterEdges(edges)} } // NewNodesByWeightedEdge returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of edges, a map of to-node IDs to graph.WeightedEdge, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or edges // is mutated after the call to NewNodes. func NewNodesByWeightedEdge(nodes map[int64]graph.Node, edges map[int64]graph.WeightedEdge) *NodesByEdge { return &NodesByEdge{nodes: nodes, edges: len(edges), iter: newMapIterByWeightedEdges(edges)} } // NewNodesByLines returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of lines, a map to-node IDs to map of graph.Line, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or lines // is mutated after the call to NewNodes. func NewNodesByLines(nodes map[int64]graph.Node, lines map[int64]map[int64]graph.Line) *NodesByEdge { return &NodesByEdge{nodes: nodes, edges: len(lines), iter: newMapIterByLines(lines)} } // NewNodesByWeightedLines returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of lines, a map to-node IDs to map of graph.WeightedLine, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or lines // is mutated after the call to NewNodes. func NewNodesByWeightedLines(nodes map[int64]graph.Node, lines map[int64]map[int64]graph.WeightedLine) *NodesByEdge { return &NodesByEdge{nodes: nodes, edges: len(lines), iter: newMapIterByWeightedLines(lines)} } // Len returns the remaining number of nodes to be iterated over. func (n *NodesByEdge) Len() int { return n.edges - n.pos } // Next returns whether the next call of Node will return a valid node. func (n *NodesByEdge) Next() bool { if n.pos >= n.edges { return false } ok := n.iter.next() if ok { n.pos++ n.curr = n.nodes[n.iter.id()] } return ok } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *NodesByEdge) Node() graph.Node { return n.curr } // Reset returns the iterator to its initial state. func (n *NodesByEdge) Reset() { n.curr = nil n.pos = 0 n.iter.hiter = hiter{} } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. The order of nodes within the returned slice is not // specified. func (n *NodesByEdge) NodeSlice() []graph.Node { if n.Len() == 0 { return nil } nodes := make([]graph.Node, 0, n.Len()) for n.iter.next() { nodes = append(nodes, n.nodes[n.iter.id()]) } n.pos = n.edges return nodes } golang-gonum-v1-gonum-0.14.0/graph/iterator/nodes_map_safe.go000066400000000000000000000135361450372207100240720ustar00rootroot00000000000000// 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. //go:build safe // +build safe package iterator import ( "reflect" "gonum.org/v1/gonum/graph" ) // 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 to 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.Reset(n.nodes) } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. The order of nodes within the returned slice is not // specified. func (n *Nodes) NodeSlice() []graph.Node { if n.Len() == 0 { return nil } nodes := make([]graph.Node, 0, n.Len()) for n.iter.Next() { nodes = append(nodes, n.iter.Value().Interface().(graph.Node)) } n.pos = n.nodes.Len() return nodes } // NodesByEdge implements the graph.Nodes interfaces. // The iteration order of Nodes is randomized. type NodesByEdge struct { nodes map[int64]graph.Node edges reflect.Value iter *reflect.MapIter pos int curr graph.Node } // NewNodesByEdge returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of edges, a map of to-node IDs to graph.Edge, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or edges // is mutated after the call to NewNodes. func NewNodesByEdge(nodes map[int64]graph.Node, edges map[int64]graph.Edge) *NodesByEdge { rv := reflect.ValueOf(edges) return &NodesByEdge{nodes: nodes, edges: rv, iter: rv.MapRange()} } // NewNodesByWeightedEdge returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of edges, a map of to-node IDs to graph.WeightedEdge, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or edges // is mutated after the call to NewNodes. func NewNodesByWeightedEdge(nodes map[int64]graph.Node, edges map[int64]graph.WeightedEdge) *NodesByEdge { rv := reflect.ValueOf(edges) return &NodesByEdge{nodes: nodes, edges: rv, iter: rv.MapRange()} } // NewNodesByLines returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of lines, a map to-node IDs to map of graph.Line, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or lines // is mutated after the call to NewNodes. func NewNodesByLines(nodes map[int64]graph.Node, lines map[int64]map[int64]graph.Line) *NodesByEdge { rv := reflect.ValueOf(lines) return &NodesByEdge{nodes: nodes, edges: rv, iter: rv.MapRange()} } // NewNodesByWeightedLines returns a NodesByEdge initialized with the // provided nodes, a map of node IDs to graph.Nodes, and the set // of lines, a map to-node IDs to map of graph.WeightedLine, that can be // traversed to reach the nodes that the NodesByEdge will iterate // over. No check is made that the keys match the graph.Node IDs, // and the map keys are not used. // // Behavior of the NodesByEdge is unspecified if nodes or lines // is mutated after the call to NewNodes. func NewNodesByWeightedLines(nodes map[int64]graph.Node, lines map[int64]map[int64]graph.WeightedLine) *NodesByEdge { rv := reflect.ValueOf(lines) return &NodesByEdge{nodes: nodes, edges: rv, iter: rv.MapRange()} } // Len returns the remaining number of nodes to be iterated over. func (n *NodesByEdge) Len() int { return n.edges.Len() - n.pos } // Next returns whether the next call of Node will return a valid node. func (n *NodesByEdge) Next() bool { if n.pos >= n.edges.Len() { return false } ok := n.iter.Next() if ok { n.pos++ n.curr = n.nodes[n.iter.Key().Int()] } return ok } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *NodesByEdge) Node() graph.Node { return n.curr } // Reset returns the iterator to its initial state. func (n *NodesByEdge) Reset() { n.curr = nil n.pos = 0 n.iter = n.edges.MapRange() } // NodeSlice returns all the remaining nodes in the iterator and advances // the iterator. The order of nodes within the returned slice is not // specified. func (n *NodesByEdge) NodeSlice() []graph.Node { if n.Len() == 0 { return nil } nodes := make([]graph.Node, 0, n.Len()) for n.iter.Next() { nodes = append(nodes, n.nodes[n.iter.Key().Int()]) } n.pos = n.edges.Len() return nodes } golang-gonum-v1-gonum-0.14.0/graph/iterator/nodes_test.go000066400000000000000000000554071450372207100233010ustar00rootroot00000000000000// 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_test import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) var orderedNodesTests = []struct { nodes []graph.Node }{ {nodes: nil}, {nodes: []graph.Node{simple.Node(1)}}, {nodes: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}}, {nodes: []graph.Node{simple.Node(5), simple.Node(3), simple.Node(2), simple.Node(1)}}, } func TestOrderedNodesIterate(t *testing.T) { for _, test := range orderedNodesTests { it := iterator.NewOrderedNodes(test.nodes) for i := 0; i < 2; i++ { if it.Len() != len(test.nodes) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.nodes)) } var got []graph.Node for it.Next() { got = append(got, it.Node()) if len(got)+it.Len() != len(test.nodes) { t.Errorf("unexpected iterator length during iteration for round %d: got:%d want:%d", i, it.Len(), len(test.nodes)-len(got)) } } want := test.nodes if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } func TestOrderedNodesSlice(t *testing.T) { for _, test := range orderedNodesTests { it := iterator.NewOrderedNodes(test.nodes) for i := 0; i < 2; i++ { got := it.NodeSlice() want := test.nodes if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } it.Reset() } } } var implicitNodesTests = []struct { beg, end int new func(int) graph.Node want []graph.Node }{ { beg: 1, end: 1, want: nil, }, { beg: 1, end: 2, new: newSimpleNode, want: []graph.Node{simple.Node(1)}, }, { beg: 1, end: 5, new: newSimpleNode, want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4)}, }, } func newSimpleNode(id int) graph.Node { return simple.Node(id) } func TestImplicitNodesIterate(t *testing.T) { for _, test := range implicitNodesTests { it := iterator.NewImplicitNodes(test.beg, test.end, test.new) for i := 0; i < 2; i++ { if it.Len() != len(test.want) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.want)) } var got []graph.Node for it.Next() { got = append(got, it.Node()) if len(got)+it.Len() != test.end-test.beg { t.Errorf("unexpected iterator length during iteration for round %d: got:%d want:%d", i, it.Len(), (test.end-test.beg)-len(got)) } } if it.Len() != 0 { t.Errorf("unexpected depleted iterator length for round %d: got:%d want:0", i, it.Len()) } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, test.want) } it.Reset() } } } var nodesTests = []struct { nodes map[int64]graph.Node }{ {nodes: nil}, {nodes: make(map[int64]graph.Node)}, {nodes: map[int64]graph.Node{1: simple.Node(1)}}, {nodes: map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 5: simple.Node(5)}}, {nodes: map[int64]graph.Node{5: simple.Node(5), 3: simple.Node(3), 2: simple.Node(2), 1: simple.Node(1)}}, } func TestIterateNodes(t *testing.T) { for _, typ := range []struct { name string new func(map[int64]graph.Node) graph.Nodes }{ {name: "Nodes", new: func(n map[int64]graph.Node) graph.Nodes { return iterator.NewNodes(n) }}, {name: "LazyOrderedNodes", new: func(n map[int64]graph.Node) graph.Nodes { return iterator.NewLazyOrderedNodes(n) }}, } { t.Run(typ.name, func(t *testing.T) { for _, test := range nodesTests { it := typ.new(test.nodes) for i := 0; i < 2; i++ { if it.Len() != len(test.nodes) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.nodes)) } var got map[int64]graph.Node if test.nodes != nil { got = make(map[int64]graph.Node) } for it.Next() { n := it.Node() got[n.ID()] = n if len(got)+it.Len() != len(test.nodes) { t.Errorf("unexpected iterator length during iteration for round %d: got:%d want:%d", i, it.Len(), len(test.nodes)) } } want := test.nodes if !reflect.DeepEqual(got, want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want) } func() { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() it.Next() }() it.Reset() } } }) } } var nodesByEdgeTests = []struct { n int64 edges map[int64]graph.Edge want map[int64]graph.Node }{ // The actual values of the edge stored in the edge // map leading to each node are not used, so they are // filled with nil values. { n: 6, edges: nil, want: nil, }, { n: 6, edges: make(map[int64]graph.Edge), want: make(map[int64]graph.Node), }, { n: 6, edges: map[int64]graph.Edge{1: nil}, want: map[int64]graph.Node{1: simple.Node(1)}, }, { n: 6, edges: map[int64]graph.Edge{1: nil, 2: nil, 3: nil, 5: nil}, want: map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 5: simple.Node(5)}, }, { n: 6, edges: map[int64]graph.Edge{5: nil, 3: nil, 2: nil, 1: nil}, want: map[int64]graph.Node{5: simple.Node(5), 3: simple.Node(3), 2: simple.Node(2), 1: simple.Node(1)}, }, } func TestNodesByEdgeIterate(t *testing.T) { for _, typ := range []struct { name string new func(map[int64]graph.Node, map[int64]graph.Edge) graph.Nodes }{ { name: "NodesByEdge", new: func(n map[int64]graph.Node, e map[int64]graph.Edge) graph.Nodes { return iterator.NewNodesByEdge(n, e) }}, { name: "LazyOrderedNodesByEdge", new: func(n map[int64]graph.Node, e map[int64]graph.Edge) graph.Nodes { return iterator.NewLazyOrderedNodesByEdge(n, e) }, }, } { t.Run(typ.name, func(t *testing.T) { for _, test := range nodesByEdgeTests { nodes := make(map[int64]graph.Node) for i := int64(0); i < test.n; i++ { nodes[i] = simple.Node(i) } it := typ.new(nodes, test.edges) for i := 0; i < 2; i++ { if it.Len() != len(test.edges) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } var got map[int64]graph.Node if test.edges != nil { got = make(map[int64]graph.Node) } for it.Next() { n := it.Node() got[n.ID()] = n if len(got)+it.Len() != len(test.edges) { t.Errorf("unexpected iterator length during iteration for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, test.want) } func() { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() it.Next() }() it.Reset() } } }) } } var nodesByWeightedEdgeTests = []struct { n int64 edges map[int64]graph.WeightedEdge want map[int64]graph.Node }{ // The actual values of the edges stored in the edge // map leading to each node are not used, so they are // filled with nil values. { n: 6, edges: nil, want: nil, }, { n: 6, edges: make(map[int64]graph.WeightedEdge), want: make(map[int64]graph.Node), }, { n: 6, edges: map[int64]graph.WeightedEdge{1: nil}, want: map[int64]graph.Node{1: simple.Node(1)}, }, { n: 6, edges: map[int64]graph.WeightedEdge{1: nil, 2: nil, 3: nil, 5: nil}, want: map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 5: simple.Node(5)}, }, { n: 6, edges: map[int64]graph.WeightedEdge{5: nil, 3: nil, 2: nil, 1: nil}, want: map[int64]graph.Node{5: simple.Node(5), 3: simple.Node(3), 2: simple.Node(2), 1: simple.Node(1)}, }, } func TestNodesByWeightedEdgeIterate(t *testing.T) { for _, typ := range []struct { name string new func(map[int64]graph.Node, map[int64]graph.WeightedEdge) graph.Nodes }{ { name: "NodesByWeightedEdge", new: func(n map[int64]graph.Node, e map[int64]graph.WeightedEdge) graph.Nodes { return iterator.NewNodesByWeightedEdge(n, e) }}, { name: "LazyOrderedNodesByWeightedEdge", new: func(n map[int64]graph.Node, e map[int64]graph.WeightedEdge) graph.Nodes { return iterator.NewLazyOrderedNodesByWeightedEdge(n, e) }, }, } { t.Run(typ.name, func(t *testing.T) { for _, test := range nodesByWeightedEdgeTests { nodes := make(map[int64]graph.Node) for i := int64(0); i < test.n; i++ { nodes[i] = simple.Node(i) } it := typ.new(nodes, test.edges) for i := 0; i < 2; i++ { if it.Len() != len(test.edges) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } var got map[int64]graph.Node if test.edges != nil { got = make(map[int64]graph.Node) } for it.Next() { n := it.Node() got[n.ID()] = n if len(got)+it.Len() != len(test.edges) { t.Errorf("unexpected iterator length during iteration for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, test.want) } func() { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() it.Next() }() it.Reset() } } }) } } var nodesByLinesTests = []struct { n int64 lines map[int64]map[int64]graph.Line want map[int64]graph.Node }{ // The actual values of the lines stored in the line // collection leading to each node are not used, so // they are filled with nil. { n: 6, lines: nil, want: nil, }, { n: 6, lines: make(map[int64]map[int64]graph.Line), want: make(map[int64]graph.Node), }, { n: 6, lines: map[int64]map[int64]graph.Line{1: nil}, want: map[int64]graph.Node{1: simple.Node(1)}, }, { n: 6, lines: map[int64]map[int64]graph.Line{1: nil, 2: nil, 3: nil, 5: nil}, want: map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 5: simple.Node(5)}, }, { n: 6, lines: map[int64]map[int64]graph.Line{5: nil, 3: nil, 2: nil, 1: nil}, want: map[int64]graph.Node{5: simple.Node(5), 3: simple.Node(3), 2: simple.Node(2), 1: simple.Node(1)}, }, } func TestNodesByLinesIterate(t *testing.T) { for _, typ := range []struct { name string new func(map[int64]graph.Node, map[int64]map[int64]graph.Line) graph.Nodes }{ { name: "NodesByLines", new: func(n map[int64]graph.Node, e map[int64]map[int64]graph.Line) graph.Nodes { return iterator.NewNodesByLines(n, e) }}, { name: "LazyOrderedNodesByLines", new: func(n map[int64]graph.Node, e map[int64]map[int64]graph.Line) graph.Nodes { return iterator.NewLazyOrderedNodesByLines(n, e) }, }, } { t.Run(typ.name, func(t *testing.T) { for _, test := range nodesByLinesTests { nodes := make(map[int64]graph.Node) for i := int64(0); i < test.n; i++ { nodes[i] = simple.Node(i) } it := typ.new(nodes, test.lines) for i := 0; i < 2; i++ { if it.Len() != len(test.lines) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } var got map[int64]graph.Node if test.lines != nil { got = make(map[int64]graph.Node) } for it.Next() { n := it.Node() got[n.ID()] = n if len(got)+it.Len() != len(test.lines) { t.Errorf("unexpected iterator length during iteration for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, test.want) } func() { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() it.Next() }() it.Reset() } } }) } } var nodesByWeightedLinesTests = []struct { n int64 lines map[int64]map[int64]graph.WeightedLine want map[int64]graph.Node }{ // The actual values of the lines stored in the line // collection leading to each node are not used, so // they are filled with nil. { n: 6, lines: nil, want: nil, }, { n: 6, lines: make(map[int64]map[int64]graph.WeightedLine), want: make(map[int64]graph.Node), }, { n: 6, lines: map[int64]map[int64]graph.WeightedLine{1: nil}, want: map[int64]graph.Node{1: simple.Node(1)}, }, { n: 6, lines: map[int64]map[int64]graph.WeightedLine{1: nil, 2: nil, 3: nil, 5: nil}, want: map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 5: simple.Node(5)}, }, { n: 6, lines: map[int64]map[int64]graph.WeightedLine{5: nil, 3: nil, 2: nil, 1: nil}, want: map[int64]graph.Node{5: simple.Node(5), 3: simple.Node(3), 2: simple.Node(2), 1: simple.Node(1)}, }, } func TestNodesByWeightedLinesIterate(t *testing.T) { for _, typ := range []struct { name string new func(map[int64]graph.Node, map[int64]map[int64]graph.WeightedLine) graph.Nodes }{ { name: "NodesByWeightedLines", new: func(n map[int64]graph.Node, e map[int64]map[int64]graph.WeightedLine) graph.Nodes { return iterator.NewNodesByWeightedLines(n, e) }}, { name: "LazyOrderedNodesByWeightedLines", new: func(n map[int64]graph.Node, e map[int64]map[int64]graph.WeightedLine) graph.Nodes { return iterator.NewLazyOrderedNodesByWeightedLines(n, e) }, }, } { t.Run(typ.name, func(t *testing.T) { for _, test := range nodesByWeightedLinesTests { nodes := make(map[int64]graph.Node) for i := int64(0); i < test.n; i++ { nodes[i] = simple.Node(i) } it := typ.new(nodes, test.lines) for i := 0; i < 2; i++ { if it.Len() != len(test.lines) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } var got map[int64]graph.Node if test.lines != nil { got = make(map[int64]graph.Node) } for it.Next() { n := it.Node() got[n.ID()] = n if len(got)+it.Len() != len(test.lines) { t.Errorf("unexpected iterator length during iteration for round %d: got:%d want:%d", i, it.Len(), len(nodes)) } } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, test.want) } func() { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() it.Next() }() it.Reset() } } }) } } type nodeSlicer interface { graph.Nodes graph.NodeSlicer } var nodeSlicerTests = []struct { nodes nodeSlicer want []graph.Node }{ { nodes: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewOrderedNodes([]graph.Node{simple.Node(1), simple.Node(2), simple.Node(3)}), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3)}, }, { nodes: iterator.NewImplicitNodes(1, 2, func(id int) graph.Node { return simple.Node(id) }), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewImplicitNodes(1, 4, func(id int) graph.Node { return simple.Node(id) }), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3)}, }, { nodes: iterator.NewNodes(map[int64]graph.Node{1: simple.Node(1)}), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewNodes(map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3)}), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3)}, }, { nodes: iterator.NewNodes(map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5)}, }, { nodes: iterator.NewNodes(map[int64]graph.Node{5: simple.Node(5), 3: simple.Node(3), 2: simple.Node(2), 1: simple.Node(1)}), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodes(map[int64]graph.Node{1: simple.Node(1)}), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewLazyOrderedNodes(map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3)}), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3)}, }, { nodes: iterator.NewLazyOrderedNodes(map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodes(map[int64]graph.Node{5: simple.Node(5), 3: simple.Node(3), 2: simple.Node(2), 1: simple.Node(1)}), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, // The actual values of the edges stored in the edge // map leading to each node are not used, so they are // filled with nil values. // // The three other constructors for NodesByEdge are not // tested for this behaviour since they have already // been tested above. { nodes: iterator.NewNodesByEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.Edge{1: nil}, ), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewNodesByEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.Edge{1: nil, 2: nil, 3: nil, 5: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewNodesByEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.Edge{5: nil, 3: nil, 2: nil, 1: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.Edge{1: nil}, ), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewLazyOrderedNodesByEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.Edge{1: nil, 2: nil, 3: nil, 5: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.Edge{5: nil, 3: nil, 2: nil, 1: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByWeightedEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.WeightedEdge{1: nil}, ), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewLazyOrderedNodesByWeightedEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.WeightedEdge{1: nil, 2: nil, 3: nil, 5: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByWeightedEdge( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]graph.WeightedEdge{5: nil, 3: nil, 2: nil, 1: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByLines( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]map[int64]graph.Line{1: nil}, ), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewLazyOrderedNodesByLines( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]map[int64]graph.Line{1: nil, 2: nil, 3: nil, 5: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByLines( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]map[int64]graph.Line{5: nil, 3: nil, 2: nil, 1: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByWeightedLines( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]map[int64]graph.WeightedLine{1: nil}, ), want: []graph.Node{simple.Node(1)}, }, { nodes: iterator.NewLazyOrderedNodesByWeightedLines( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]map[int64]graph.WeightedLine{1: nil, 2: nil, 3: nil, 5: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, { nodes: iterator.NewLazyOrderedNodesByWeightedLines( map[int64]graph.Node{1: simple.Node(1), 2: simple.Node(2), 3: simple.Node(3), 4: simple.Node(4), 5: simple.Node(5)}, map[int64]map[int64]graph.WeightedLine{5: nil, 3: nil, 2: nil, 1: nil}, ), want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}, }, } func TestNodeSlicers(t *testing.T) { for k, test := range nodeSlicerTests { wantLen := test.nodes.Len() for i := 0; i < wantLen; i++ { var gotIter []graph.Node for n := 0; n < i; n++ { ok := test.nodes.Next() if !ok { t.Errorf("test %d: unexpected failed Next call at position %d of len %d", k, n, wantLen) } gotIter = append(gotIter, test.nodes.Node()) } gotSlice := test.nodes.NodeSlice() if test.nodes.Next() { t.Errorf("test %d: expected no further iteration possible after NodeSlice with %d pre-iterations of %d", k, i, wantLen) } if gotLen := len(gotIter) + len(gotSlice); gotLen != wantLen { t.Errorf("test %d: unexpected total node count: got:%d want:%d", k, gotLen, wantLen) } got := append(gotIter, gotSlice...) ordered.ByID(got) if !reflect.DeepEqual(got, test.want) { t.Errorf("test %d: unexpected node slice:\ngot: %v\nwant:%v", k, got, test.want) } test.nodes.Reset() } } } golang-gonum-v1-gonum-0.14.0/graph/layout/000077500000000000000000000000001450372207100202545ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/layout/doc.go000066400000000000000000000004411450372207100213470ustar00rootroot00000000000000// Copyright ©2019 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 layout defines functions for performing graph layout. package layout // import "gonum.org/v1/gonum/graph/layout" golang-gonum-v1-gonum-0.14.0/graph/layout/eades.go000066400000000000000000000102061450372207100216630ustar00rootroot00000000000000// Copyright ©2019 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 layout import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/spatial/barneshut" "gonum.org/v1/gonum/spatial/r2" ) // EadesR2 implements the graph layout algorithm essentially as // described in "A heuristic for graph drawing", Congressus // numerantium 42:149-160. // The implementation here uses the Barnes-Hut approximation for // global repulsion calculation, and edge weights are considered // when calculating adjacent node attraction. type EadesR2 struct { // Updates is the number of updates to perform. Updates int // Repulsion is the strength of the global // repulsive force between nodes in the // layout. It corresponds to C3 in the paper. Repulsion float64 // Rate is the gradient descent rate. It // corresponds to C4 in the paper. Rate float64 // Theta is the Barnes-Hut theta constant. Theta float64 // Src is the source of randomness used // to initialize the nodes' locations. If // Src is nil, the global random number // generator is used. Src rand.Source nodes graph.Nodes indexOf map[int64]int particles []barneshut.Particle2 forces []r2.Vec } // Update is the EadesR2 spatial graph update function. func (u *EadesR2) Update(g graph.Graph, layout LayoutR2) bool { if u.Updates <= 0 { return false } u.Updates-- if !layout.IsInitialized() { var rnd func() float64 if u.Src == nil { rnd = rand.Float64 } else { rnd = rand.New(u.Src).Float64 } u.nodes = g.Nodes() u.indexOf = make(map[int64]int, u.nodes.Len()) if u.nodes.Len() >= 0 { u.particles = make([]barneshut.Particle2, 0, u.nodes.Len()) } for u.nodes.Next() { id := u.nodes.Node().ID() u.indexOf[id] = len(u.particles) u.particles = append(u.particles, eadesR2Node{id: id, pos: r2.Vec{X: rnd(), Y: rnd()}}) } u.forces = make([]r2.Vec, len(u.particles)) } u.nodes.Reset() // Apply global repulsion. plane, err := barneshut.NewPlane(u.particles) if err != nil { return false } var updated bool for i, p := range u.particles { f := r2.Scale(-u.Repulsion, plane.ForceOn(p, u.Theta, barneshut.Gravity2)) // Prevent marginal updates that can be caused by // floating point error when nodes are very far apart. if math.Hypot(f.X, f.Y) > 1e-12 { updated = true } u.forces[i] = f } // Handle edge weighting for attraction. var weight func(uid, vid int64) float64 if wg, ok := g.(graph.Weighted); ok { if _, ok := g.(graph.Directed); ok { weight = func(xid, yid int64) float64 { var w float64 f, ok := wg.Weight(xid, yid) if ok { w += f } r, ok := wg.Weight(yid, xid) if ok { w += r } return w } } else { weight = func(xid, yid int64) float64 { w, ok := wg.Weight(xid, yid) if ok { return w } return 0 } } } else { // This is only called when the adjacency is known so just return unit. weight = func(_, _ int64) float64 { return 1 } } seen := make(map[[2]int64]bool) for u.nodes.Next() { xid := u.nodes.Node().ID() xidx := u.indexOf[xid] to := g.From(xid) for to.Next() { yid := to.Node().ID() if seen[[2]int64{xid, yid}] { continue } seen[[2]int64{yid, xid}] = true yidx := u.indexOf[yid] // Apply adjacent node attraction. v := r2.Sub(u.particles[yidx].Coord2(), u.particles[xidx].Coord2()) f := r2.Scale(weight(xid, yid)*math.Log(math.Hypot(v.X, v.Y)), v) if math.IsInf(f.X, 0) || math.IsInf(f.Y, 0) { return false } if math.Hypot(f.X, f.Y) > 1e-12 { updated = true } u.forces[xidx] = r2.Add(u.forces[xidx], f) u.forces[yidx] = r2.Sub(u.forces[yidx], f) } } if !updated { return false } rate := u.Rate if rate == 0 { rate = 0.1 } for i, f := range u.forces { n := u.particles[i].(eadesR2Node) n.pos = r2.Add(n.pos, r2.Scale(rate, f)) u.particles[i] = n layout.SetCoord2(n.id, n.pos) } return true } type eadesR2Node struct { id int64 pos r2.Vec } func (p eadesR2Node) Coord2() r2.Vec { return p.pos } func (p eadesR2Node) Mass() float64 { return 1 } golang-gonum-v1-gonum-0.14.0/graph/layout/eades_example_test.go000066400000000000000000000100121450372207100244300ustar00rootroot00000000000000// Copyright ©2019 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 layout_test import ( "fmt" "image/color" "log" "math" "gonum.org/v1/gonum/graph/layout" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/plot" "gonum.org/v1/plot/font" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" "gonum.org/v1/plot/vg/draw" ) func ExampleEadesR2() { // Make a simple graph and render it as a PNG // with the EadesR2 force-directed layout. g := simple.NewUndirectedGraph() const n = 6 for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { g.SetEdge(g.NewEdge(simple.Node(i), simple.Node(j))) } } // Use the Eades layout algorithm with reasonable defaults. eades := layout.EadesR2{Repulsion: 1, Rate: 0.05, Updates: 30, Theta: 0.2} // Make a layout optimizer with the target graph and update function. optimizer := layout.NewOptimizerR2(g, eades.Update) // Perform layout optimization. for optimizer.Update() { } p := plot.New() // Add to plot. p.Add(render{optimizer}) p.HideAxes() // Render graph on save. err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "k6_eades.png") if err != nil { log.Fatal(err) } } const radius = vg.Length(15) // render implements the plot.Plotter interface for graphs. type render struct { layout.GraphR2 } func (p render) Plot(c draw.Canvas, plt *plot.Plot) { nodes := p.GraphR2.Nodes() if nodes.Len() == 0 { return } var ( xys plotter.XYs ids []string ) if nodes.Len() >= 0 { xys = make(plotter.XYs, 0, nodes.Len()) ids = make([]string, 0, nodes.Len()) } for nodes.Next() { u := nodes.Node() uid := u.ID() ur2 := p.GraphR2.LayoutNodeR2(uid) xys = append(xys, plotter.XY(ur2.Coord2)) ids = append(ids, fmt.Sprint(uid)) to := p.GraphR2.From(uid) for to.Next() { v := to.Node() vid := v.ID() vr2 := p.GraphR2.LayoutNodeR2(vid) l, err := plotter.NewLine(plotter.XYs{plotter.XY(ur2.Coord2), plotter.XY(vr2.Coord2)}) if err != nil { panic(err) } l.Plot(c, plt) if err != nil { panic(err) } } } n, err := plotter.NewScatter(xys) if err != nil { panic(err) } n.GlyphStyle.Shape = nodeGlyph{} n.GlyphStyle.Radius = radius n.Plot(c, plt) l, err := plotter.NewLabels(plotter.XYLabels{XYs: xys, Labels: ids}) if err != nil { panic(err) } fnt := font.From(plot.DefaultFont, 18) for i := range l.TextStyle { l.TextStyle[i] = draw.TextStyle{ Font: fnt, Handler: plot.DefaultTextHandler, XAlign: draw.XCenter, YAlign: -0.4, } } l.Plot(c, plt) } // DataRange returns the minimum and maximum X and Y values. func (p render) DataRange() (xmin, xmax, ymin, ymax float64) { nodes := p.GraphR2.Nodes() if nodes.Len() == 0 { return } var xys plotter.XYs if nodes.Len() >= 0 { xys = make(plotter.XYs, 0, nodes.Len()) } for nodes.Next() { u := nodes.Node() uid := u.ID() ur2 := p.GraphR2.LayoutNodeR2(uid) xys = append(xys, plotter.XY(ur2.Coord2)) } return plotter.XYRange(xys) } // GlyphBoxes returns a slice of plot.GlyphBoxes, implementing the // plot.GlyphBoxer interface. func (p render) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox { nodes := p.GraphR2.Nodes() if nodes.Len() == 0 { return nil } var b []plot.GlyphBox if nodes.Len() >= 0 { b = make([]plot.GlyphBox, 0, nodes.Len()) } for i := 0; nodes.Next(); i++ { u := nodes.Node() uid := u.ID() ur2 := p.GraphR2.LayoutNodeR2(uid) b = append(b, plot.GlyphBox{}) b[i].X = plt.X.Norm(ur2.Coord2.X) b[i].Y = plt.Y.Norm(ur2.Coord2.Y) r := radius b[i].Rectangle = vg.Rectangle{ Min: vg.Point{X: -r, Y: -r}, Max: vg.Point{X: +r, Y: +r}, } } return b } // nodeGlyph is a glyph that draws a filled circle. type nodeGlyph struct{} // DrawGlyph implements the GlyphDrawer interface. func (nodeGlyph) DrawGlyph(c *draw.Canvas, sty draw.GlyphStyle, pt vg.Point) { var p vg.Path c.Push() c.SetColor(color.White) p.Move(vg.Point{X: pt.X + sty.Radius, Y: pt.Y}) p.Arc(pt, sty.Radius, 0, 2*math.Pi) p.Close() c.Fill(p) c.Pop() c.Stroke(p) } golang-gonum-v1-gonum-0.14.0/graph/layout/eades_test.go000066400000000000000000000154211450372207100227260ustar00rootroot00000000000000// Copyright ©2019 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 layout_test import ( "path/filepath" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/spatial/r2" "gonum.org/v1/plot" "gonum.org/v1/plot/vg" . "gonum.org/v1/gonum/graph/layout" ) func TestEadesR2(t *testing.T) { eadesR2Tests := []struct { name string g graph.Graph param EadesR2 wantIters int }{ { name: "line", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, wantIters: 100, }, { name: "square", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(3)}, {F: simple.Node(2), T: simple.Node(3)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, wantIters: 100, }, { name: "tetrahedron", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(2)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(3)}, {F: simple.Node(2), T: simple.Node(3)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, wantIters: 100, }, { name: "sheet", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(4)}, {F: simple.Node(2), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(3), T: simple.Node(6)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(7)}, {F: simple.Node(5), T: simple.Node(8)}, {F: simple.Node(6), T: simple.Node(7)}, {F: simple.Node(7), T: simple.Node(8)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, wantIters: 100, }, { name: "tube", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(2)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(4)}, {F: simple.Node(2), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(3), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(6)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(7)}, {F: simple.Node(5), T: simple.Node(8)}, {F: simple.Node(6), T: simple.Node(7)}, {F: simple.Node(6), T: simple.Node(8)}, {F: simple.Node(7), T: simple.Node(8)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, wantIters: 100, }, { // This test does not produce a good layout, but is here to // ensure that Update does not panic with steep decent rates. name: "tube-steep", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(2)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(4)}, {F: simple.Node(2), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(3), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(6)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(7)}, {F: simple.Node(5), T: simple.Node(8)}, {F: simple.Node(6), T: simple.Node(7)}, {F: simple.Node(6), T: simple.Node(8)}, {F: simple.Node(7), T: simple.Node(8)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), param: EadesR2{Repulsion: 1, Rate: 1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, wantIters: 99, }, { name: "wp_page", // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.jpg g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(4)}, {F: simple.Node(1), T: simple.Node(5)}, {F: simple.Node(1), T: simple.Node(6)}, {F: simple.Node(1), T: simple.Node(7)}, {F: simple.Node(1), T: simple.Node(8)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(6)}, {F: simple.Node(4), T: simple.Node(7)}, {F: simple.Node(4), T: simple.Node(8)}, {F: simple.Node(4), T: simple.Node(9)}, {F: simple.Node(4), T: simple.Node(10)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, wantIters: 100, }, } for _, test := range eadesR2Tests { eades := test.param o := NewOptimizerR2(test.g, eades.Update) var n int for o.Update() { n++ } if n != test.wantIters { t.Errorf("unexpected number of iterations for %q: got:%d want:%d", test.name, n, test.wantIters) } p := plot.New() p.Add(render{o}) p.HideAxes() path := filepath.Join("testdata", test.name+".png") err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, path) if err != nil { t.Errorf("unexpected error: %v", err) continue } ok := checkRenderedLayout(t, path) if !ok { got := make(map[int64]r2.Vec) nodes := test.g.Nodes() for nodes.Next() { id := nodes.Node().ID() got[id] = o.Coord2(id) } t.Logf("got node positions: %#v", got) } } } golang-gonum-v1-gonum-0.14.0/graph/layout/isomap.go000066400000000000000000000034231450372207100220750ustar00rootroot00000000000000// Copyright ©2019 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 layout import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/path" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/spatial/r2" "gonum.org/v1/gonum/stat/mds" ) // IsomapR2 implements a graph layout algorithm based on the Isomap // non-linear dimensionality reduction method. Coordinates of nodes // are computed by finding a Torgerson multidimensional scaling of // the shortest path distances between all pairs of node in the graph. // The all pair shortest path distances are calculated using the // Floyd-Warshall algorithm and so IsomapR2 will not scale to large // graphs. Graphs with more than one connected component cannot be // laid out by IsomapR2. type IsomapR2 struct{} // Update is the IsomapR2 spatial graph update function. func (IsomapR2) Update(g graph.Graph, layout LayoutR2) bool { nodes := graph.NodesOf(g.Nodes()) v := isomap(g, nodes, 2) if v == nil { return false } // FIXME(kortschak): The Layout types do not have the capacity to // be cleared in the current API. Is this a problem? I don't know // at this stage. It might be if the layout is reused between graphs. // Someone may do this. for i, n := range nodes { layout.SetCoord2(n.ID(), r2.Vec{X: v.At(i, 0), Y: v.At(i, 1)}) } return false } func isomap(g graph.Graph, nodes []graph.Node, dims int) *mat.Dense { p, ok := path.FloydWarshall(g) if !ok { return nil } dist := mat.NewSymDense(len(nodes), nil) for i, u := range nodes { for j, v := range nodes { dist.SetSym(i, j, p.Weight(u.ID(), v.ID())) } } var v mat.Dense k, _ := mds.TorgersonScaling(&v, nil, dist) if k < dims { return nil } return &v } golang-gonum-v1-gonum-0.14.0/graph/layout/isomap_386_test.go000066400000000000000000000004611450372207100235330ustar00rootroot00000000000000// Copyright ©2020 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:build 386 // +build 386 package layout_test // Change the testdata path for calculations done on 386. func init() { arch = "_386" } golang-gonum-v1-gonum-0.14.0/graph/layout/isomap_arm64_test.go000066400000000000000000000004711450372207100241450ustar00rootroot00000000000000// Copyright ©2020 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:build arm64 // +build arm64 package layout_test // Change the testdata path for calculations done on arm64. func init() { arch = "_arm64" } golang-gonum-v1-gonum-0.14.0/graph/layout/isomap_noasm_test.go000066400000000000000000000005441450372207100243320ustar00rootroot00000000000000// Copyright ©2019 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:build noasm || gccgo || safe // +build noasm gccgo safe package layout_test // Change the testdata path for calculations done without assembly kernels. func init() { tag = "_noasm" } golang-gonum-v1-gonum-0.14.0/graph/layout/isomap_test.go000066400000000000000000000121701450372207100231330ustar00rootroot00000000000000// Copyright ©2019 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 layout_test import ( "path/filepath" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/spatial/r2" "gonum.org/v1/plot" "gonum.org/v1/plot/vg" . "gonum.org/v1/gonum/graph/layout" ) var ( // tag is modified in isomap_noasm_test.go to "_noasm" when any // build tag prevents use of the assembly numerical kernels. tag string // arch is modified in isomap_arm64_test.go to "_arm64" on arm64 // and "_386" on 386 to allow differences in numerical precision // to be allowed for. arch string ) func TestIsomapR2(t *testing.T) { isomapR2Tests := []struct { name string g graph.Graph }{ { name: "line_isomap", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), }, { name: "square_isomap", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(3)}, {F: simple.Node(2), T: simple.Node(3)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), }, { name: "tetrahedron_isomap", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(2)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(3)}, {F: simple.Node(2), T: simple.Node(3)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), }, { name: "sheet_isomap", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(4)}, {F: simple.Node(2), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(3), T: simple.Node(6)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(7)}, {F: simple.Node(5), T: simple.Node(8)}, {F: simple.Node(6), T: simple.Node(7)}, {F: simple.Node(7), T: simple.Node(8)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), }, { name: "tube_isomap", g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(1)}, {F: simple.Node(0), T: simple.Node(2)}, {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(4)}, {F: simple.Node(2), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(3), T: simple.Node(5)}, {F: simple.Node(3), T: simple.Node(6)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(7)}, {F: simple.Node(5), T: simple.Node(8)}, {F: simple.Node(6), T: simple.Node(7)}, {F: simple.Node(6), T: simple.Node(8)}, {F: simple.Node(7), T: simple.Node(8)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), }, { name: "wp_page_isomap", // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.jpg g: func() graph.Graph { edges := []simple.Edge{ {F: simple.Node(0), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(1), T: simple.Node(3)}, {F: simple.Node(1), T: simple.Node(4)}, {F: simple.Node(1), T: simple.Node(5)}, {F: simple.Node(1), T: simple.Node(6)}, {F: simple.Node(1), T: simple.Node(7)}, {F: simple.Node(1), T: simple.Node(8)}, {F: simple.Node(3), T: simple.Node(4)}, {F: simple.Node(4), T: simple.Node(5)}, {F: simple.Node(4), T: simple.Node(6)}, {F: simple.Node(4), T: simple.Node(7)}, {F: simple.Node(4), T: simple.Node(8)}, {F: simple.Node(4), T: simple.Node(9)}, {F: simple.Node(4), T: simple.Node(10)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return orderedGraph{g} }(), }, } for _, test := range isomapR2Tests { o := NewOptimizerR2(test.g, IsomapR2{}.Update) var n int for o.Update() { n++ } p := plot.New() p.Add(render{o}) p.HideAxes() path := filepath.Join("testdata", test.name+tag+arch+".png") err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, path) if err != nil { t.Errorf("unexpected error: %v", err) continue } ok := checkRenderedLayout(t, path) if !ok { got := make(map[int64]r2.Vec) nodes := test.g.Nodes() for nodes.Next() { id := nodes.Node().ID() got[id] = o.Coord2(id) } t.Logf("got node positions: %#v", got) } } } golang-gonum-v1-gonum-0.14.0/graph/layout/layout.go000066400000000000000000000011141450372207100221150ustar00rootroot00000000000000// Copyright ©2019 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 layout import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/spatial/r2" ) // GraphR2 is a graph with planar spatial representation of node positions. type GraphR2 interface { graph.Graph LayoutNodeR2(id int64) NodeR2 } // NodeR2 is a graph node with planar spatial representation of its position. // A NodeR2 is only valid when the graph.Node is not nil. type NodeR2 struct { graph.Node Coord2 r2.Vec } golang-gonum-v1-gonum-0.14.0/graph/layout/layout_test.go000066400000000000000000000051771450372207100231710ustar00rootroot00000000000000// Copyright ©2019 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 layout_test import ( "bytes" "encoding/base64" "image" "image/png" "os" "path/filepath" "strings" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/plot/cmpimg" ) // orderedGraph wraps a graph.Graph ensuring consistent ordering of nodes // in graph queries. Removal of this causes to tests to fail due to changes // in node iteration order, but the produced graph layouts are still good. type orderedGraph struct { graph.Graph } func (g orderedGraph) Nodes() graph.Nodes { n := graph.NodesOf(g.Graph.Nodes()) ordered.ByID(n) return iterator.NewOrderedNodes(n) } func (g orderedGraph) From(id int64) graph.Nodes { n := graph.NodesOf(g.Graph.From(id)) ordered.ByID(n) return iterator.NewOrderedNodes(n) } func goldenPath(path string) string { ext := filepath.Ext(path) noext := strings.TrimSuffix(path, ext) return noext + "_golden" + ext } func checkRenderedLayout(t *testing.T, path string) (ok bool) { if *cmpimg.GenerateTestData { // Recreate Golden image and exit. golden := goldenPath(path) _ = os.Remove(golden) if err := os.Rename(path, golden); err != nil { t.Fatal(err) } return true } // Read the images we've just generated and check them against the // Golden Images. got, err := os.ReadFile(path) if err != nil { t.Errorf("failed to read %s: %v", path, err) return true } golden := goldenPath(path) want, err := os.ReadFile(golden) if err != nil { t.Errorf("failed to read golden file %s: %v", golden, err) return true } typ := filepath.Ext(path)[1:] // remove the dot in ".png" ok, err = cmpimg.Equal(typ, got, want) if err != nil { t.Errorf("failed to compare image for %s: %v", path, err) return true } if !ok { t.Errorf("image mismatch for %s\n", path) v1, _, err := image.Decode(bytes.NewReader(got)) if err != nil { t.Errorf("failed to decode %s: %v", path, err) return false } v2, _, err := image.Decode(bytes.NewReader(want)) if err != nil { t.Errorf("failed to decode %s: %v", golden, err) return false } dst := image.NewRGBA64(v1.Bounds().Union(v2.Bounds())) rect := cmpimg.Diff(dst, v1, v2) t.Logf("image bounds union:%+v diff bounds intersection:%+v", dst.Bounds(), rect) var buf bytes.Buffer err = png.Encode(&buf, dst) if err != nil { t.Errorf("failed to encode difference png: %v", err) return false } t.Log("IMAGE:" + base64.StdEncoding.EncodeToString(buf.Bytes())) } return ok } golang-gonum-v1-gonum-0.14.0/graph/layout/optimizer.go000066400000000000000000000065631450372207100226370ustar00rootroot00000000000000// Copyright ©2019 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 layout import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/spatial/r2" ) // LayoutR2 implements graph layout updates and representations. type LayoutR2 interface { // IsInitialized returns whether the Layout is initialized. IsInitialized() bool // SetCoord2 sets the coordinates of the node with the given // id to coords. SetCoord2(id int64, coords r2.Vec) // Coord2 returns the coordinated of the node with the given // id in the graph layout. Coord2(id int64) r2.Vec } // NewOptimizerR2 returns a new layout optimizer. If g implements LayoutR2 the layout // will be updated into g, otherwise the OptimizerR2 will hold the graph layout. A nil // value for update is a valid no-op layout update function. func NewOptimizerR2(g graph.Graph, update func(graph.Graph, LayoutR2) bool) OptimizerR2 { l, ok := g.(LayoutR2) if !ok { l = make(coordinatesR2) } return OptimizerR2{ g: g, layout: l, Updater: update, } } // coordinatesR2 is the default layout store for R2. type coordinatesR2 map[int64]r2.Vec func (c coordinatesR2) IsInitialized() bool { return len(c) != 0 } func (c coordinatesR2) SetCoord2(id int64, pos r2.Vec) { c[id] = pos } func (c coordinatesR2) Coord2(id int64) r2.Vec { return c[id] } // OptimizerR2 is a helper type that holds a graph and layout // optimization state. type OptimizerR2 struct { g graph.Graph layout LayoutR2 // Updater is the function called for each call to Update. // It updates the OptimizerR2's spatial distribution of the // nodes in the backing graph. Updater func(graph.Graph, LayoutR2) bool } // Coord2 returns the location of the node with the given // ID. The returned value is only valid if the node exists // in the graph. func (g OptimizerR2) Coord2(id int64) r2.Vec { return g.layout.Coord2(id) } // Update updates the locations of the nodes in the graph // according to the provided update function. It returns whether // the update function is able to further refine the graph's // node locations. func (g OptimizerR2) Update() bool { if g.Updater == nil { return false } return g.Updater(g.g, g.layout) } // LayoutNodeR2 implements the GraphR2 interface. func (g OptimizerR2) LayoutNodeR2(id int64) NodeR2 { n := g.g.Node(id) if n == nil { return NodeR2{} } return NodeR2{Node: n, Coord2: g.Coord2(id)} } // Node returns the node with the given ID if it exists // in the graph, and nil otherwise. func (g OptimizerR2) Node(id int64) graph.Node { return g.g.Node(id) } // Nodes returns all the nodes in the graph. func (g OptimizerR2) Nodes() graph.Nodes { return g.g.Nodes() } // From returns all nodes that can be reached directly // from the node with the given ID. func (g OptimizerR2) From(id int64) graph.Nodes { return g.g.From(id) } // HasEdgeBetween returns whether an edge exists between // nodes with IDs xid and yid without considering direction. func (g OptimizerR2) HasEdgeBetween(xid, yid int64) bool { return g.g.HasEdgeBetween(xid, yid) } // 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. func (g OptimizerR2) Edge(uid, vid int64) graph.Edge { return g.g.Edge(uid, vid) } golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/000077500000000000000000000000001450372207100220655ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/.gitignore000066400000000000000000000000241450372207100240510ustar00rootroot00000000000000*.png !*_golden.png golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/line_golden.png000066400000000000000000000127241450372207100250600ustar00rootroot00000000000000PNG  IHDRzzIDATxmpTY$![$``XG*ڎӑCEb զR@&̐"I$y! M"kb7M6Ұ}{9ǻ{wQǻ{ȑk׮y\n݆ LB7| 9x/ޛ7oޞ={G+Lx}vͦsT__ߡC̙3z^xǫEAon~X,{Ňιs^tɇ͢ڍf{Gz뭇~؟ 6o[f?Sn,Y288'MӦLqƵk׾;~@ <ֶbŊ,iZ~ԀL lxx ccc+ë4M;uMnΞ=iZmm) 4M{饗nl?iSO=}̟??ӧg̘}߿%---&&nhh9ʕ+?;ܔ,\P7o_lYɓ'usg: 7)//OJJ9gCJJJt3sLQ]]sqs_~iZdd-WpfpnGEEبiZDDĐtttgܸqyRBsŢsp{ٹ';v<k &蜧K4c$&7SL/tw֓NMD#sHMnfΜYQQsi,˭߯q]$3gy*++t@8nrs}?iҤKvvv̙3};9OYYٳ9$&7˖-+//z)~iMӎ;vc˕+W***,X0{l?~<--MD&7/9ϟuV׷f3$%%} < \n?/}ƏrB? ]2XRRsΞKNN?M6UUUEFFR@t:?~W_}K'N|ȑg} 'O[[[\r徾3f[g5kp$&&vvv,_ܿ5&cnn*..pBMMMsssooj?~iӒ/^ D?; rCq+7rCqY17IsCq77sCq=78 $ Ln( :rCq KP@PB"578X "|n( rCq!H<8Il8iI8 I̹8H8I(*8@)Z8@)8@H(OP`JFR=70 (` r_6r5r3ܸAq` 7Q Ͱ(X܌Ant8ȍ^AnCqQ7En|GqP@?r/Dnz8MP3rHCnn8MP`rD .@n. 7ơ81Łȍ(TFnFq,rj"7Aq r2!7Dqrb 7Gqrc * 7fAq =rc"r#7Bq 1rc:"7fDq %rcR!7Eq rcj2!7fGq r#91PH@tF$B#78Łȍ(DDnDEq r#0Q@FB 780?r##7R803r#"780'r#'"7Ң80r#3S!780r#? 7J80r #7 8-r"7ʡ8r" 780QŁȍ(DnTGq`rh 7/`#7AP!7 H ܠ8r(`XEn A P FFqP@/?xޡ8(|Cn [8 _(#7ŁN@qA`P `(<#7$ `8GqAPP܊ X( 7" AGqBn`rP(PGeF8"7&rР8 "7rP8J!71rУ8 70r8#70#7rs8#70#+r38R"70)#r8!705#r8 7ő( AqDGn #4rPq@HGD8!7 (@ GqDAn #rIP#719rP3#7 1-r Qs"71!riQ!71rQ 71 r%P3 7P 9rP"7P !rPP!7P rEQ@iH8!714c r 6r| r EqnP` 7{' 0,XF@q#8An]( @qAnPk7|DqEnQ/G?rDn8z 0(Έ 03rFqCn8n ((έ ,grŹ@n8.0!7q(xq `(Cn)[r!7@h(Xrj!7@()Ur:!7@)Rr !7YH_r!7H\r!7IYr|!7yIVrL!7ISr@@ 8!7`-#hq $CnQ WrL@l8!7$_r!7T\rƴ!7YrɄ!7VrT!7Sr$ű jmFjiiILL,((X|׮]|rcccWWiƍ1cFDDWo _'NXSSvNE|VSO-Y7ވyΊ7VUU䤥 yrbWڽ{+9M6=rȺun~K/9;Aǎ{Wmk޼y… gΜy%nu9s&--mΝ<==ųgvm!7ۓ.]z`?00bŊsvmk˖-᯿zZlvrmPѹsRRR{5kuqqqPի{{{ ]tΛ7oѢEٜLϏ;añ?\[o(/'nܸQ/^ܼyskkkooˍ={^nn.G7ZkjjB|񬬬ϻAիWptn{y\tѢE}}}jÍ\tԩ&L 7Z_7..jioo0art(g```Ԩ\ZPKDDDww@-'Nljj2~ݦ&r%>>ENgmm-o}wGGVVVr2('%%%,,죏>2rӧOGGG@-QQQ-5rwyGn۷/##իbȑ#uuu6ѣW^]b… cbbRSS͛7p6}G@9ӧO߳gOzz o>cƌgdd曵P?oWUUEDDu{gΝ[l [{{m۶?~ӦM<Pĉ_~ݻw[OSVV)@Q>hMMMqqqttt篫KIIYj_r9%%eڴi:?ҩ555u~ፙ95qĂ˗/Ynjڦ˗www\1r(-11ɓK, n}<@ooӧcbbn~KJJ***;v_{5/8{.Zh]w5tA۱cGxxߟ؁o~cƌ~t: o~sUV{YYY_|Q555fz'RRR***lbX'St>֖`3gqNnWVVL2eÆ %7s8EEEN:w\UUUcccWWWXXرccbbf͚lٲ/,Ly`0`r A _H[ {IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/line_isomap_386_golden.png000066400000000000000000000105161450372207100270250ustar00rootroot00000000000000PNG  IHDRzzIDATxkPT"" *`CelB˘)ktFk,4j/5Ycie`X(JeX`*Wggatf~ף<9FáBn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7{rj/(((..xbinn6 !!!111)))111;aBۋժ(dLJJJOO0a? 97ȑ#[n=xfK 6ҥK%%%OnhhHKK[xyX -[ܹvÇOLL2L2&&f޼y/Rttt7s.:|I&رƍ]l_|fWW lƌz~~lzϯ]6>>h4.\]MMMMVVN={p8֭[Q>^n6mhsL'9z^:u/~!!!t/n/_\4i$"6Z'O~… KKK233uhVV֑#G裂 55500P㠯ZQI&ulHII)...**9r!Ǐ߸qও'OlѣGk?Dc^~ɫTSO>ݷo_M EQ 5IMM׸?߿O>&&&9ɍl0`)W\Q%22aaa={V㜄uipKbDDDhRSS(ʽ Vƍ+Z,pKMss&IQ&sE>>N~Ǐ_WWWTTqz8P__dɒ}jp8:~>W:tHrt2dkW˗/t7oطo_XXXrr'?8u1EQ\}vIIIokk:}tZZ(ׯ/))~і>C{?uUVVj?_^x1&&fܸq+V83wK.8q•\pSIIIrrr~~qxbw1cƳ>} /PQQ<7_fͲe˴ˇ {ӧ{{-'xny{!֠۷ojyPŢ{f̘IzI }W[nΟ?߫~;^]{x%CCCW\t;wzT^d/Ѕ~y%f{;nS4W^WXXSy#RSS_h4~ꫯ_[ɍn5kV>}yJSSccc\\m6N'xvUF:o&75+++((ȍ!;UUU5bĈ2 7otW;6mmmK, Flҥz~ժU---=9ԊAvsL mذ?ohh3fLff ޟ֭[eeeG^^ީS"##.]+7)wrX,?c^^+b4ՙ#G0aSRR[5777''ѣ:ꝅ''';'4 t?7Ԙfb0BBB7o^pjh 3nq%r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@[BzIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/line_isomap_arm64_golden.png000066400000000000000000000105161450372207100274360ustar00rootroot00000000000000PNG  IHDRzzIDATxkPT"" *`CelB˘)ktFk,4j/5Ycie`X(JeX`*Wggatf~ף<9FáBn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7{rj/(((..xbinn6 !!!111)))111;aBۋժ(dLJJJOO0a? 97ȑ#[n=xfK 6ҥK%%%OnhhHKK[xyX -[ܹvÇOLL2L2&&f޼y/Rttt7s.:|I&رƍ]l_|fWW lƌz~~lzϯ]6>>h4.\]MMMMVVN={p8֭[Q>^n6mhsL'9z^:u/~!!!t/n/_\4i$"6Z'O~… KKK233uhVV֑#G裂 55500P㠯ZQI&ulHII)...**9r!Ǐ߸qও'OlѣGk?Dc^~ɫTSO>ݷo_M EQ 5IMM׸?߿O>&&&9ɍl0`)W\Q%22aaa={V㜄uipKbDDDhRSS(ʽ Vƍ+Z,pKMss&IQ&sE>>N~Ǐ_WWWTTqz8P__dɒ}jp8:~>W:tHrt2dkW˗/t7oطo_XXXrr'?8u1EQ\}vIIIokk:}tZZ(ׯ/))~і>C{?uUVVj?_^x1&&fܸq+V83wK.8q•\pSIIIrrr~~qxbw1cƳ>} /PQQ<7_fͲe˴ˇ {ӧ{{-'xny{!֠۷ojyPŢ{f̘IzI }W[nΟ?߫~;^]{x%CCCW\t;wzT^d/Ѕ~y%f{;nS4W^WXXSy#RSS_h4~ꫯ_[ɍn5kV>}yJSSccc\\m6N'xvUF:o&75+++((ȍ!;UUU5bĈ2 7otW;6mmmK, Flҥz~ժU---=9ԊAvsL mذ?ohh3fLff ޟ֭[eeeG^^ީS"##.]+7)wrX,?c^^+b4ՙ#G0aSRR[5777''ѣ:ꝅ''';'4 t?7Ԙfb0BBB7o^pjh 3nq%r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@[BzIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/line_isomap_golden.png000066400000000000000000000105161450372207100264250ustar00rootroot00000000000000PNG  IHDRzzIDATxkPT"" *`CelB˘)ktFk,4j/5Ycie`X(JeX`*Wggatf~ף<9FáBn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7{rj/(((..xbinn6 !!!111)))111;aBۋժ(dLJJJOO0a? 97ȑ#[n=xfK 6ҥK%%%OnhhHKK[xyX -[ܹvÇOLL2L2&&f޼y/Rttt7s.:|I&رƍ]l_|fWW lƌz~~lzϯ]6>>h4.\]MMMMVVN={p8֭[Q>^n6mhsL'9z^:u/~!!!t/n/_\4i$"6Z'O~… KKK233uhVV֑#G裂 55500P㠯ZQI&ulHII)...**9r!Ǐ߸qও'OlѣGk?Dc^~ɫTSO>ݷo_M EQ 5IMM׸?߿O>&&&9ɍl0`)W\Q%22aaa={V㜄uipKbDDDhRSS(ʽ Vƍ+Z,pKMss&IQ&sE>>N~Ǐ_WWWTTqz8P__dɒ}jp8:~>W:tHrt2dkW˗/t7oطo_XXXrr'?8u1EQ\}vIIIokk:}tZZ(ׯ/))~і>C{?uUVVj?_^x1&&fܸq+V83wK.8q•\pSIIIrrr~~qxbw1cƳ>} /PQQ<7_fͲe˴ˇ {ӧ{{-'xny{!֠۷ojyPŢ{f̘IzI }W[nΟ?߫~;^]{x%CCCW\t;wzT^d/Ѕ~y%f{;nS4W^WXXSy#RSS_h4~ꫯ_[ɍn5kV>}yJSSccc\\m6N'xvUF:o&75+++((ȍ!;UUU5bĈ2 7otW;6mmmK, Flҥz~ժU---=9ԊAvsL mذ?ohh3fLff ޟ֭[eeeG^^ީS"##.]+7)wrX,?c^^+b4ՙ#G0aSRR[5777''ѣ:ꝅ''';'4 t?7Ԙfb0BBB7o^pjh 3nq%r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@[BzIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/line_isomap_noasm_arm64_golden.png000066400000000000000000000105161450372207100306330ustar00rootroot00000000000000PNG  IHDRzzIDATxkPT"" *`CelB˘)ktFk,4j/5Ycie`X(JeX`*Wggatf~ף<9FáBn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7{rj/(((..xbinn6 !!!111)))111;aBۋժ(dLJJJOO0a? 97ȑ#[n=xfK 6ҥK%%%OnhhHKK[xyX -[ܹvÇOLL2L2&&f޼y/Rttt7s.:|I&رƍ]l_|fWW lƌz~~lzϯ]6>>h4.\]MMMMVVN={p8֭[Q>^n6mhsL'9z^:u/~!!!t/n/_\4i$"6Z'O~… KKK233uhVV֑#G裂 55500P㠯ZQI&ulHII)...**9r!Ǐ߸qও'OlѣGk?Dc^~ɫTSO>ݷo_M EQ 5IMM׸?߿O>&&&9ɍl0`)W\Q%22aaa={V㜄uipKbDDDhRSS(ʽ Vƍ+Z,pKMss&IQ&sE>>N~Ǐ_WWWTTqz8P__dɒ}jp8:~>W:tHrt2dkW˗/t7oطo_XXXrr'?8u1EQ\}vIIIokk:}tZZ(ׯ/))~і>C{?uUVVj?_^x1&&fܸq+V83wK.8q•\pSIIIrrr~~qxbw1cƳ>} /PQQ<7_fͲe˴ˇ {ӧ{{-'xny{!֠۷ojyPŢ{f̘IzI }W[nΟ?߫~;^]{x%CCCW\t;wzT^d/Ѕ~y%f{;nS4W^WXXSy#RSS_h4~ꫯ_[ɍn5kV>}yJSSccc\\m6N'xvUF:o&75+++((ȍ!;UUU5bĈ2 7otW;6mmmK, Flҥz~ժU---=9ԊAvsL mذ?ohh3fLff ޟ֭[eeeG^^ީS"##.]+7)wrX,?c^^+b4ՙ#G0aSRR[5777''ѣ:ꝅ''';'4 t?7Ԙfb0BBB7o^pjh 3nq%r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@[BzIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/line_isomap_noasm_golden.png000066400000000000000000000105161450372207100276220ustar00rootroot00000000000000PNG  IHDRzzIDATxkPT"" *`CelB˘)ktFk,4j/5Ycie`X(JeX`*Wggatf~ף<9FáBn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7{rj/(((..xbinn6 !!!111)))111;aBۋժ(dLJJJOO0a? 97ȑ#[n=xfK 6ҥK%%%OnhhHKK[xyX -[ܹvÇOLL2L2&&f޼y/Rttt7s.:|I&رƍ]l_|fWW lƌz~~lzϯ]6>>h4.\]MMMMVVN={p8֭[Q>^n6mhsL'9z^:u/~!!!t/n/_\4i$"6Z'O~… KKK233uhVV֑#G裂 55500P㠯ZQI&ulHII)...**9r!Ǐ߸qও'OlѣGk?Dc^~ɫTSO>ݷo_M EQ 5IMM׸?߿O>&&&9ɍl0`)W\Q%22aaa={V㜄uipKbDDDhRSS(ʽ Vƍ+Z,pKMss&IQ&sE>>N~Ǐ_WWWTTqz8P__dɒ}jp8:~>W:tHrt2dkW˗/t7oطo_XXXrr'?8u1EQ\}vIIIokk:}tZZ(ׯ/))~і>C{?uUVVj?_^x1&&fܸq+V83wK.8q•\pSIIIrrr~~qxbw1cƳ>} /PQQ<7_fͲe˴ˇ {ӧ{{-'xny{!֠۷ojyPŢ{f̘IzI }W[nΟ?߫~;^]{x%CCCW\t;wzT^d/Ѕ~y%f{;nS4W^WXXSy#RSS_h4~ꫯ_[ɍn5kV>}yJSSccc\\m6N'xvUF:o&75+++((ȍ!;UUU5bĈ2 7otW;6mmmK, Flҥz~ժU---=9ԊAvsL mذ?ohh3fLff ޟ֭[eeeG^^ީS"##.]+7)wrX,?c^^+b4ՙ#G0aSRR[5777''ѣ:ꝅ''';'4 t?7Ԙfb0BBB7o^pjh 3nq%r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@ Bn!7B !r@[BzIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/sheet_golden.png000066400000000000000000000564131450372207100252440ustar00rootroot00000000000000PNG  IHDRzz\IDATxw\Sg8 ){/e*bAADPԖXw[onJ:(j2TeBv~͛2Nsrbz=^}5B%uuuׯ_ann0oљ1cƲeI$@LD_߿_x?Oф޽{w֐kk/r\`$,}֭#&MzC`uu۩Tubb"i MVV{ċظl2;6v͛7׬Y|QFIѣGaaaƍ{葄c7.]Zrݻ%/sʪh(jpܻwoŧNںu+a|||455SRRT*>&??7n<~8&O<}7oPnX,y\\@/^L6ʕ++W">baرcMMMW\@4uԭ[nٲ&{7MMMG>qDDD 1L;;Г'ObIws)==pR{pj퍊ڲeG׭[```u]ͭZJEEʕ+ Zn=zbԸ~~~/޻w/Ǖ-[vu R5RY|9N1$%%̟?H"dddxxxTVVZXXH8(jŋ3f@榦S.] AЙ3g>> E@f|RZZd2!444suu?~n8wwwbp8|TWW߻woss3 /_N$}}}lTMWW˗?mbbbjj榠f͚Nr\ccChmmsNDDqu@d2YOOoĉaaaQQQ5554YcwիW$??ݝB7HZoޞ#㕖Vĭ[̋o߾ 55>&O龾ڱG%H۷oGއ>><6** C9θq|||~WL>111;;DP0gggOOӧ'uttuvv>yt?~hѢK^|[W-[cÇ0me𷰍7z{{nrϗᕤX,ǘ1cPs ct¡tuu/^&5!a555;;[غu봴JKKM ޽Ep8PN&O|xܹ۷/%%E:<<APZZ R[v̙۷gϞp˗//^`ll^2$99իW߿ioo trr2e? H0L33v($)..N m» ccc?.^[EuuugN?|p۶mH$΄ ,Yr٢"Ir劲2}/JJJ i@/7Ba|t:ĉ7n2-LCC︲’\.°˖-)oN6 n:++KgEz A2Qn`9:::t<owK.UVV+'VEEETTԚ5k\]]̅))){xx]֭[4ퟏwvv yk׮|F(nݺuҤI>n)??ի~~~ϟ?߳gO}}}gg'WVVյrvvvuubaG ~:999;;Ǐ |hss*1Š]n<==h;OT円;#"8/VWW'''=zT}ࣹJKKAI&466׬Yc[766>_2Zn8|E/ SڠHEEW(rB4o<xY,7=vs;`SLQTTLHHf͛7{qqqikkuֲe˔&Lnݺľ e~O>%֘2BYYy[tµ@Ԋr/F/>O>|0334??ҥKASSkѢE...& `G71dɒ:}},-Z pH$nڴ)00p}) `ZZZe -k:2~RQQǺB TUU?~|ƌFFF}P(˗ߺuKK1\ڵkaaa`﯌p8Ǐwttc`8::N>=** yyyOII).. HUUu͛>}z_U߿/))innz؈_ z7В%KY#KMM%f``0)_JNNpvvLSSmǎX' Μ93}t* |dhhhcccmmW ٳg_x!2Wn촴@?J}ϝ;G$>+W)++åH$EFFVTTH9%)+,, %_}խ[9N^vmٲe e͚5GrCR@ϛ7OGGݻwFqH{Pi4ڥKϟoaaW2lnnrܹVsDMkkkXX@pss?0}ܸq 6mz*7===m޼Dz{{Q ꧟~"yzuuS 9[[[/Yrյ| 7oul[nA$3 ?K;<y$%%eƍr;mݺu!x@=a=d2[\Noii!&L Yrm7Smm{ |>>>K,5ɓMMM1S__2TnGw")Jyy9މȉ:9L0#^+kgg[ǘB˕9s攗Jx ޹hRRRag󛚚!g%%%333ggٳgϟ?cڵk_~Ǐ9rd՞999O5jT\\D|󍬌@C`0 ڳgމ[۷KWWocxxxLL ;` e֭NZ~Q$mUUUo =zAмyM@]yyYCڴiJEһ͛mmm/_A˗ a =,!QҥKO>Ů7o.\M\n>~hllo8Br.ZjҥX_nݮ]<<#,Nrll,H񩭭E+Njnn9毿{t8`׊X9 BWW755UYY˗2embbx4EEEsPRR>#/^+Vǫ|觻P(oooDkkk?d"N?~~ѣGC Mkk+keX_|މ"[reIIҥKwiddnݺgϞqܡfbbr-[ ~VD 0-:q޽{__tIYY~̘1`֖x<g.]t9qȑ#{mhh044%#{=r;ijjJII9rȻwܺDݤIVnSRR ys6w"j<==߾}-an@F.F9SWW-yMssqjNcc#-%gh4*)7|>/Aoo/3L& )7߇u;iiix'M frJ&%ARx'&== 777CSn r)77WAAAAٔ y(|MSS.M#*S(**"JJJ¡x~.7yyyt?555OM}}7 500D4MFl]X.eggd? YݍER-7=vs̑ft|9-PijIJJ"l-dMCC3,8`Zn޼yeȫ0(grrr 2e ZZnjkkV)' ===N@Saa!HD镛.ɥf͚w"ѽ,LzѣGKE@jI$މhjhh@w7Mbb"@mR{{Wnrss^ayU__?, E+7555`X^uwwi)9SRRAЄ P)r5@v B(dīWН^! Ns4%&&R͛7;ŘR*7O< ܾ 233I$*wHXQQHDDHdggkhh: #޿?j(PV]]܎WWW)Nݘ(7] m`0ƍw 7JA4{l)HB!s3l6;N,rAЌ3 e`ZJ.{'NnXiW^d)HYVVHK -G(7h]Țwށ)򧠠H$~1 777pQWWOii)JE=,&)) 3gb.0-%8xr ^W%%%B,q?4LUUUEEEޛɴA=,:EץMMML& MMMCCb,$ 233D"3BpG؛7o&&&vvvjhhX[[LWZZjbbzɓ'<߫t0* ùx񢅅D |rYY٠ro߾=~ 3ʼn( k455@ٮ] rGܤSԭ[ ͛7|FD%K@YHHL"hC|>~;vǏO>mjj/Ν;999NNN7n7Ȋr@Oee%VߑW@55;wHXx<޾}Ž;$ }DcPqwww@@@uuuZZ5D"8p`ܸq+V`0.\0 }R_]䏨xԼxYυ ͙3GKKhݻw`ZJx<cooEpDc7;wʊG}E``###э `?yyy9;;c|rx̙k׮a5&44t۶m_u]]t[J'`tb[nŊâyؑ#GLLL6mڄ]X) FPn.\vi,O?=x˗6%!! PGeeeWnX,։'l٢Q}|}}g̘qPA N@Ymm-v Wn 6 zjggg##I&Nm߾=!! #^޽{wZ[[prsƍ~iӦԼ|Ν;S>}[QMM 6S.`w%ܐ妧'%%eѢE ŋZj3gμz*A~@ @ _·2|?C???\\\^MH,%%%n644D~FII$X{%@ ݻw$ ;`CfI׭[GP.]$҅vb HAaa*Y+//7;da0bt3䓷o߆AUUWviRrAOO(```pÇ޽;--m)|Yjoo; }t:K )j83f{׮]'O^`ALLLpp0===`,kiiM^8bX~ ٻ100hhh$4JݶmA'ODTMMHc=Ł~kbrcgg _wݽk._t:]LLRt|r3iҤ*0޽{bkk+Aa!'O?^IIolٲQF)**L6mΝ`|/***xg lu1TTT{.C[ZZAжmY~ɓo߾3fS(̩TuHHHdd7o6HHOO,͘1CII &BpJXOKKUVm߾W^]vmvv6C|>tÆ ?0oc2o޼hpO@ hhh;::zzz" FϯxJJJ˗/;;eMMM51\}իkkkLWMMMT*JUUuڵ[lAxv||ٳDqzzzaaauuugg'CH$+++ggӧϟ?NNN.++gd2jkkp8D"/ \dرcN@ǨQ,,,0B4\p8aaa"]FьE]8m4UU՘T^^^BBBVVVqqq}}=Ʉ_P(6663gg_bΞ=[YY9y䠠 wwcuuu>عs'"sk;wNUUotB011*"8~Ɏ;|}}~|UUU;; ;w? w555USS۾};/_ %SLgۇi+#6mccxbL`2FuVxxĉD--'ߺuNK-%h9sĈ61"H?<%''Ci+#_S|J 6mҒBjΝ[p] ƾ;vx 1Iԕ=z̘1r劊ʬYQǏS0mvRQQy5\v@ |Okjj:99-_ҥKѐ+)) f(rwwE1,5777555[ATn???}}\ھy󦂂EҥK˗/wrr }#7nx Ãb\GGgʕGcbbbaau+HˍP(dX ,RW\U6c"xQ Cɔ7oDFFX[[_HP8 (LLL -$ƍPGRnEr# Db```IIxM;VCC#::Z xooo##ҟOHH O>Ŵ}ijjbWt5k`݊h+ÇLII9s&A_~e]]M 5k8;;quu'Xx˗/(~eeen:$%y97n7nASL9sLAAk.Lfzz={g̘.q򣤤ٳ0G} Djkk lnɩ7oތmjjP(VVV]]]555<6$$dժU`AFFFBBBvvvIIIss3łHEE~pɓmll_.^zgϞ?u7xijj*^4] _%^t;VGGG *0\#Q LMMEEEo߾n+M޽#ҹ 8\[FmF z$X,'SRRT x aofѢE}7ijkk%DAлM$>҇***^pE@APuu5II͊Gvqq6mZ@@X%#ڤ %%%sfee/Q(ooo~ESS$'''-- 3ް dZ[[K-PnE<==SSS$>>~cƌ 7o\` JJJzY^^^yyyjjjRRґ#GA pH[[@ pttNs.+  VC'O B $xjEEE\\\LL?@ LMMMbOׯ_2L_x]TT驡iw#Gu2޽{۶mb<nD>{l2#jnnE~~~UUN\ldd$RWWuruuu'''kkk###*󻺺JKKʊ!YzEYC}; bǎGglw{ F[;w.44tر7H$]]ݾS3|Wd2tݯ_C`<|pJJJ?xI~]ؼy3(72B\xQ m-\N) FFF^^^7ok0;vLYYΝ;"]mܼk.*nbׅzX-wgϞ1m| f͚eeeOÔ8Uf555y{{S3gΈ}rmmmHHDD17Mxx8(7j5iii)K ___VVVf͒{xPT\\lnnnoo_\\,y˗/+**X~ ퟀ$^|I&Ϝ9Ep>bffFѰ/6wj}vvv?u*PqQ\\Cъ>|;J_n/_N"P &oF=TjNNQ|pWWW]]ݡ.b,.)jjj277a2FVSS[v/7d2C&]V@l..b? o[mmm;y{{;88`tCY\\H\P `aΝwԞ~86S`r^z$ \~xϢ DzɓvvDο'}]+}w1dff?ކ JP&N(<}||8T_nx<(7Nßx'3.f@ bܤٙq"&^=#"I+RNBAAL& șN M4UGl7oi4H'f z7Hzzz/T61LnR,ᄈRTT,//;vɓ''=" _''*0T B5@vH$xBSL)--Jaa9s駟6S(y扗-P5իW𢨨w" 8ʕ+=u[HK,Ax?b`|>_]],)**޽ܹsuuuX?o߾]`@ oM ~ņ 0m{_nB!(7rfԨQx IAA!**QQQ5V\9zhI6wFr#: ,GDD}޽{ngwȍfNݻCCCCBBrrrP|{Y[[K n'gʕ+ӧO󋏏G% [vӧ㏀ 0Pn>d2ݻ˖- >x Ǔ$Zuu۷ !*Dx˗O81iҤt1p8ӧO;::vuuү 0܀k>/aaafff^^^Ƀmmm?wޝ-xMwC@')Dciiѣ'OΝ;¢B✜dUU[Jf(0|l3L&)0ȟ^~лf555qinBjrZZZ4 0prXe(75 ^rp@Pn |. 0$p :&, ^Ê 266ƥuлa? xvz7p '?^!C OZZZpZ`HCp<|L\.9ݰ.5 򧽽;1`0pw&'!iw l3===8`~\)-7L&3L&SMM )`HFw b[_ q(7l68XxtPn w-kooARqLnpYijj 8怴wbgϞ]QQq R԰ߟ}`X aX@a7#Luvv+**>{ QQQjjj .LNN2e *atq8pP<0wWpF(X+++ Μ9C̙O3p@|2??yÇXN WX! QHލ<}妮nwvvƨmEEk׮edd\v & UUUPCar~SSǍiӦ={b *p닜JJJ0x:$r?0˗/c */PՅʆ/^haa_"_WWWkii߿G7ߜ;wnƍd`Fr#gp?fލ@ qƚ5k\m6oo˗/ڵD"E_]^^KQ20O⻝@}qMNNNSSӢEG;wnQQѳg<<bAZ.OR׭[A&?|pر 6 -JV5 r>H"|_5x5RDDDMMMQQQ~~; ~#򤶶/7 }/NNN}A---#""mp|};"Y766"|vu;::BTRR0"\1 ܷ(}{yRQQ:>OOO8p;w<}4pa'Y\w![YY! KPonff`jj:{lP}p #'4M`ԩEEE5H_G1?? ///A׬Y>~+ WGVVV" b~X"&b444~gǬ\[nTWWN#y@ JJJ"##LLL{dcc3fDFF!@,x{{❅pkgggQ\ݻUTTƍー9rΊSN͚5!HFFF3f8|pqq1򴁡:99 &09NNNϞ=EQb2%%%,,*<<}SRR \.\}NpB{{{Qcǎ;cƌr1x (((C gМ:uСCoyHuppY`$1oߖ577www=zr߾}`sghhY\\oC;99]|y5___k׮ݻw yzz.\ v?#UUU7oތɁ^022RSSc2 fS(9s,YԴ9ahܹSSS /r`̙cǎe5_CCùsΝkeeqM$)!#gϞM 6l0=|>۫W5jʕ+HYY,*I&}X~ E\tiVVV}pk׮]$sBM =V@#rg|w" yYUUUKK_Uќ@u&V`ܺukvvvT*hjjnܸɓ'Gd/HǏcԩS$so> HE(7NYYY[[{ڵO<jފ9r>/##e]_;>'Nf)**P(ǎîUVߧ8< D0"v۷o1cƌ=ZOOOYY㵷WUU}d|_}տvA￟f,+ʾխ\]]fΜqҥK޺ѣy=Y@lڴܹsKG\}sssG(?-** 066wDt{x<Fp8'O<~իW}gԫ=zĉ3g Fg299Ǐ#9擡t׮]#Rcbbˊ 33)000554gxr111&L₩:::EGG.aٲe>>>ڿPCDbeex<ё#GD̹ihhPb</)))66633 ~]EE5 `Μ9 E hii;vlڵH"-,,3d_6n2Cȏ(71@ի2boUVVVTTXZZ" W__ݺu_lnnJOO/;wnGGX? sssw"fee*((tvv"|Xj}aaaBB ---SN=}+zzzx'2gH$}"VMMm+mmm/^EDOOOKKbg,466KǏ)cccWpFwȭ. ooo?[D}PSSo\.WKK , Pn@ dٳg̓D}@ mruuuG pFCCC|F>QԾʢ?fd2 x{jZ&LB Іd`0Q D?RPU* SیDq؇ڠ9 KBhGBxgwrJ69{ׯ8P(7nLKK{g)WLy_։NdbLfllDXvƍׯdddxpl6NSTJڵkF133 !! }.QRR'xɓN7~p[NX|ovbb‰uuu%%%agyF&!iEk6/^ʂ -+L`Yq]"*:==E&2ZŋQQQ$im\9bI$;Zp))),p8k֬7ijj _tiA&''dӵ"""?`0d;wQٹ,K |~nnS_#ݻwO(9sf1lb<sϹx,PHRkjj)))9vАs_q8g-tfjmm{9{D SB6mr+VMMM5 W\\---֭|+p***D$ưW_}?vr ᴵq\'IR544򾾾~M xcǎSN;i x>#28n"MMMd۷]J`l޼yY׬Ye2K{ۂOf0LfVV\E߿/ M&SSS ;f9SB$N/?駟kʾ}N> xK.m߾v˖-.T*ϗ111.)H yyy=㎔Pbb"s{D"8L&6.JQϗBXjkAnZTTw^'w)!Jj'''L EGG%%%3%ܼiӦ7ZջvRTAAA 3L`llbOO͛SSSkjjcZ1, W, N .#o.\T*333a2;v8z"<nVQ@`d2"8DofEm˄SBMMM݃sd2NꩧPI ]&;;jz֭Zߏhoo/++d?8zT*U(g\N@P?[UUm*޳%''3 0ˋB e2`@8sEE@@O G_ * ~RFx>B ܬ ᥗ^bosUV9rdff5zFoD,H$g8& Ο??<<$/bff&+L&Fq#_97+΅ )JYY$f=XdddCC+&''ᯄbu(ʜ_ %''啗#oAcA Ee{ԅp:tH$+W^?zW_}EӥRbqzWRVVϯ_>((._piN |=Ǐh uV"?w߭>w\zz:kbh4???>11Vo߾ AիBaeeX,v݆nՉyL&{駑WH$>_b0wyz4n_L7SFߺucppPUV@6r7lذs[:::㇆*--ݿZZZhhB:tЁpM@Qn D_B9vE@RD"F `0 /WG 7jnٲ>#ؕ+W2224 >& 8W,h୒###?|OOOVVtOzzz||իW322p{4Fnpjdb06@&;n`Ib111JrA~gR( ? 6 bX fhhw`0l6$vqxK? ޽KdNe6!rȒ\.d* 888X*ڵk ? 20<<`0>*۷JR H@~ÇBˉ'9zw7lLMMEEE*]n ꊎ`,R(|=R8p@PruSlcǎٳG}'O>}sC|[oy{{#/T*bǏGq·pO~~>+++[TVU"`'NT1,KD"III/BBBggϞݶmk|ol6z~Aju^^tCΒnΝᵵΝkhhpς,{&ϏFGGd<o6u:JR*%99977W,X ns ݼyYTj^oX|||drHHxIII ,npnpnpnpnp,`3$TIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/sheet_isomap_386_golden.png000066400000000000000000000544331450372207100272140ustar00rootroot00000000000000PNG  IHDRzzXIDATxy\i8>Kg;m'J{D )-$N0f&3vص`JB)uZ}yO=|֬Y'N;vlRRRSSSg\7ob|||N:aJiҥ8({nڵd2&99Ya իPYY \xٳcǎ-((sӧO{yyH:L@`8tw믿J×/_N4N߻wOSSS"} e=#G\RVTT;޽{$I= mkk)d@At|||\uرo"twwoذm߾o\\СC o (#84 ѣ'Nhbbrcǎ\p@(,X~ NGGGiiiGGP5Ϝ9zriWdH7Jh/^v.kkS>|XzHNZZZ=<kkkϝ;m (##Fy{{c ЗݍHNN7ng,A#??Ĉ ˷c@Q \.WGGFAV*ƞ8qb3gӕxR SLikkd'@wʕcǎa ݍtҜ9sfffYYY#F:@@QpXһfCCC<bTUU"0<<<8455l3ֱҍ"srrBBB${dĹ.YX)S b&&&o޼:T&Lp@ceffV^^^ZZ`0@`ddTWW+ $n8I~I[%4}tðTZzuBBBqq1 N.D"1))I=7664ť[+|ݻcX,*z>K;ȑ#AAA迴~F oh.zjTT/_lp>Ru3fڴiRҥK8.##C(_>,,[nEӧO!#jeA&ߎ;VQQq]2{`G@Ç3f@$00󤃾ɍ7lmmTZ*B ]~=X{vvvBBR0>6l.&F𨷷DW!DGGף555_j``כ[[[߿GxPGGNj/HEFO@Yi),,KyhoV\9~ UR_,--[[[kjj xh ZYYY{Eȑ|x3gia``pՐ!URți###666Da n jP^?~+duႂ&L dʋfCtMCR8`"hllgϞv444 F"EDT1ZO<(_??{dΝddd!UjBM\͛7MMML&n7n1c%i|=JZϟ?<))ի(;ioo J*SSSqzصk9&Ȉ⌫<`UUUbAгgP^(] LԤ#r󒒒+?҂aIqeQQAT]]" Agݻw{zz {n/0wPWHBINNΈ# 7AhH.2 .6@WJk̘1Ϟ=kmmEy]|G>|eΝ|='90UְaEhfmm-֧|:֪ eժUnnnϞ=|璓ZZZPu[ZZΜ9eBVZW^ hlljyEeeٹsDߟ_ (۷=Ж-[?d2i4RX/k!..NVV255Ec]]]jjj'N{) W\(%%%d2ȑ#REz-4%gΜo}صk׺ VbIi._UDwx<]]] 7jԨٳg2dKgg4_r¢F(n  p>+)) YGc)bӧs8c<ӳ~<O =*QH7¹z*ʒ(\.wСf͒( !!@ L8Q_!6n܈㣢>|XZZ,Vpvvnkk@ yyy 6L@ܹSUUTzC(zuuu<O?yƌ$˟aL&K{Z~t#gϞe˖I gͦx<>55bT*u\.W\bhhhll/], H7Bشicի."H1ytUVV\Bhii-[֭[_jp8!!!&&&8n鹹c}*rxߍB.;zh>X=q[|DRõkh4w}`0h AW544:t/ oo%K,X`ʔ)VQQAٴiӛ7oD&`0ğ6R |ۻwt:Ak֬K7orpp(((5k0n:dqtt4RA R5bǎh.nllLHHؽ{ҥKg̘wM6m7otREEDDDpm۶ߛ\B Db|||M0@ XRλO8ahhwt .ll[@G}}СC!:,t5+V HWWosss"8gΜo++,,ܼy!B{D^QQԢ"pBfBCCq8H|H\\\LMM( kll,---,,(++366^p+runnKOOr쌤Kű~Θ1ʕ+XEL&y+'7`dQ~~: ۷oyEEEddҥKutt>{DP,,,|}}óފT*@HII!em6ցj*TꇗO)ζ* B4|pBff&r̙3j5 H7Yell{ct:Hc!ȆlGmmmL# &ӧcKl6rCE&ܸqȄ U/tӃLRT ltԑP(>:UXXH&DǏ?ڻw}_|AЬY>,ޛ3g/nVÆ CNz:t02n:z(--hx<Ν;Ȝߖ-[p8\@@8+}SRR Ǐ/_.˚LGx<… J7|>?++3f|}}lْ(zPGikk0ϙ3L&GEEm[[@ KP]]K{Q__"*~ӧ/]TWWgdddgggffKPx<^ccciiiaa˗/xׂ Mt2i$\RѴZZZ^UU511qw3fHO@LVJJJz%H@ׯߴiw7Ϟ=Cfo߾7o|昘3fDSSH@w ðZ^^[bLȐx?Dz{UWWG&ϝ;۷o'&&$ؽ{7N"ݴXù 5^EEEpp0Htvv2g>6l@"Ο?ᤴR 1 sׯ5@a0UTT.^6ݼxR___eEEEƍP(gϞKH QYYqF fff6{l b ٳMww? ?iӦM:Uڄ +@k.^~H$[X[[K{Urr2At̾ijjpIII(߳g޽{?b!2Tչs444nH$… %(..D"[y H[[%@˃a811stt상^ݺu á+WSSɇB())Y"//F-ZSºuH߿?A...rr 9r*,,a+ 355lx9&J~-477N4ܗ={ ita&O,KWW}9s6 OOOqzxAT*U0dW^]\xza-\piii---@ yEj2o޼f6" :.N2C~n"##O:ydǎ†";;;7wa$b~gcii)¸vvvyyy"4Ĥ ZK.>>>¶=;v٢RAA3T}~4p$d" _577_xh㚙!C}P/^\bŵkDhݻ^LHHsΏ?h>F"x%#?@$Ǥ$###0Hvv6r"TN2X@bccD>lhh(ؕ< =~O:ebٳf͢R/I7sL0|4ܹ#L$ 9} FDD1pDnlԨQ\.7''}-[;v#FmЌ D iii_H>|fݺufܸqNB= )x< dɒ%s?~8 2}ƍ...h_bիW믲}%}}}+++4 n={&+W ={6&>|8lnn{ws|>ECC'O,++|666k]xqh2ӧy<RZ ,8w7{z={zI7o߾E AԄܕyl.vd|`@TVVfkk͋+++ׯ_?cƌ}} yõ{nl2dh-Z(,,,11 `@뗜 wy>?w^fs#""P= 2nݺm۶Emܸ1>>^$۷jd{322r\OOϥK; 3g@\.l͚5===LwvvRT4I 5D5**C__&Mr(P(RB GC LTTrԗ&>r[>}466V=zfƍPy!rCI>CV"{@f+_z@~7sss"ȃ[rT9y]?rw܌2uBKhѢh #$͛7Ϟ=cbb g#۳g |o;wMHHI/w0!??م,y-~`#F>|Ek5g`>111K,m8@R̙S__޽ 6Hs@p’˗/#q^ӧ_BJdzw\xB"[XVQQ雧0mmmPC555ȯy]zo/YB|rB/СCFG|2Mlb8q"Nnj~P@xԩSzzzׯ/((@yvvvPPL611z]M]]B9~8TQQ!l @z޽{ghh&ٌNRx|nnЈ!D"ڵkhgهB%Y[[Z̙3iii޽{}mm7oO8l2SSS3g|s%i6l`hh&w' XZZJ@x<~Ĉz~I( @HIIHAAA튊 afddlٲ͍F}[KKk(;bijjEv:HOJJ 9]!u-[6x`CC;w[WW/ppp0ǫp`x`C h(gQ) 㼼ZZX' a633(zϋ/FqhqnܸaeeF:0x|]CCb}X;T%ttt̚5L&>|X 3^VV{} A?7"##pܢ\z566ƍ"u#ϟ/B[ciii =zX,`߾}***999"T__vZ<+:x]p1LӧO hԩX`h"7ЦDAA ӦM{;wޅ3 ߿7oP=xt7g/\ GW4 \"J)8]}ׯoߎB122G> jIII" ]pD"0i&C>Q\\L"TL-wBΤu!u$-XիWL&kjj2!Cs---ƍɱHMMOeV]]maa ȑ#k֬A^p@̥>uCkx<@ Ļkhh 2[#::a:.#Oy9Yn& `at:+7np8uuuz֓EEEZZZ`() ~Gd5+WEp0,#SRRJ-**:Yq<u,"tUAjM<@ 4 Gӊyyy$IEEiҥ9KX":L7XIP`vb2J^"f< OOOy*歪*G0,ڱcցbiii)m555 N7D=ω`|R\E@A"`:>ÇE2> """TTTp81dslDeݿ?ֱY#!2I7PT͗ΝP*ȶrmll ڼy3ֱHW}}בDhh(#'O:,ڵK!7="+V^u ҒL&e-}M9zh:c)Gw!|ᾷsNdvͷ0 VZ0Jy&ֱhd4YfAu 7Æ Sߑ n3gT{q Cvkٲe`TVV"u$E9 47(_iiiH%PA\.~:H$(+5O7 UEZD:ʲ!44y[,ws?򻰤XRd%ѣ!0`: c22X.o_!X"u$\\\eI7Ǐ#GݻX$ZUUUEEEi7O0{cAEHL Y-6tPX؈RmӉx<^MMX!::ZHL b֭j@ކ٩ݻu,{HP(/_:/Z`OHLI rCkhhAPGD.kll kװEV#%r>}u,jkkVBRtXx1A4ݻX"022@d R"_vv* Xǂ% tPpp0ֱȜZ3flژ]\\\[[ގj```mmhee%Z<uH$ҽ{F%Z' |'|ԩS!ׯ_nn.|rڟoGKK> gΜ ))~ׯ_F1eʔsR(d%((Hґ*SSSӯT$@82 뱎勐B %ZR:;;2_*Ξ=kmm ð#Gz=?|޽H VGGoP__/oHt?ڐW&&&2J(2_/:L&}}?sss+u$?.wh@ÇՀTmmmnݺ[n={Lɓ'K*$%Aˑ?;vp)SGE&O8Wo߮u$DM磌RD~x+Wa,# omllVXqͯdG* )5///䡦חB={V>|~XX_z=|> Q:"k6n0DassΝ; avqqٶm[BB›7o::: ޾}{֭;vp8}}[666~-VBߖ23gAIpU΍7TyAyy.A+VT o(,,CNAZZZt:}۶m('*++wܩp>|)&&y!e0MMM555%ÇT*uHXH@Ae޼y[|ׯ_>\UUu׮]"KwttݻF [`600 c˖-T*5++K?0 h4+6 Y ݠCuuu{͛4ݻw TVV6~xUUp<#_dRx,**JzClݺJ*It#L:x/EGGkJ䑇0 dy) \A|}}: spp8qTGw ŋ$ M6!\|IX0|yvlN8AR+**=ӧO!s玴_ ݈ 33D2/Hc~M67 dxÆ }3%A ݈Hќ3g4117~:aǏ]]]mAX% ݈e…t:2ҿ?DJO)--Ga޾}[mllfJۋ.^~u!:tԩS/^( ݾ}{l߾oĈònݺ%Z[Ňucsupp蛱FxK2w+ԓԇ&L&55Ẻ:a*N^UVV^lӧOX,100D֡_6mZyy \dff"ƣl!+D7m44Ǐ?>>>JeddnҤIE\E.'2fhhX\\pw#+W̞=ǣ3))L3k֬Xp8??+Wl޼YKmm-q Fmmmߏ+ݍ(;׫3O&MDӫ?ɓ'?NxT[[ZߏK:;;~\nDA:::ח#߿gX(;9r$ HYe@f!{BQ0 {@*xA~rJya(-ߗϞ= 9"H7 "zP(O+((8qD\\Mff&\.Dv\eoo~Ν4))ښNQO̅aaaB[[['M1Ns>8*5@`iivھnʔ)}3<w7h(_z :srr2J0raxƍ'N 7nlݺU/nDA Q^OR>|'ѱwFիWUTTW͛7jժURXCNz핼x񢊊J}}==== /|r]]\xp***Lh222x3g7ĦMh4ȇ+ '׬YiӦo^VVVV^^^VVV[[k``0p@nU^QQA&Ŏ]޽{׮]5j;pܹs%޹B:ɱPmm&iJӷo.@ ϗlIII$IJGq(nDޮ~ziB[ZZ=bz葤#H˖-T \t ǧIo -!Gww9sH$ѣGn޼YB)>n`090`Yѹr0 7C!taeff۫_B/u --ɓ'KJ[[ԩSUUUO>-ٞ٫W>|haa:dȐ%K -Q̜9s:) ccc'''hjjruu522zzzzH$RSS@ :t(AF:p@^^^+222vakk A+8\4EdTTTxyyA[QQ7@>8EϟuŏX?|0::֭[555$i CMM緵UTTxNqttTJ'NLLLF0dff9qDcgϦ9;;c 4P>~~~XHxRF'N{nttt`` ֱNՁQ %ehhXWW+ cȑ#333srr찎{CI={ Ǐ9`˧믧OYnRi9##Xf X ;•Egg˗lԩppphll:@ÔRۻwo޼u,oٳXSʎ3La$/_2dȰarss1 n͛7ֺu644lhhQ {ׯx#L0  ۷ok7l Hk@`3?2L/:;;ggg755(O.KҧO9sL&s8GGxLKJJJesss`` L޻woMMBSSS D"߿H$___L0qtt466 44433kux<^JJJWW~cZ; 6S7drMM w-**^B籷={VTlE0Y`u~C*(r]\\ Ϗ H+ccc cٲe555T*USe߾}d2߿obb@f ,HPDGGc45\.秤h,s7`AΝkiiyS3]\\|J 6S@=H뛟a퍒t޽n@mL&CTAU7`1orJo!XgzzZ* K n<^GX̅zoʆ^% gڵ -^}8p`׮]|lޞF}VJJ-xҍIKK^tٳgxqq#F#7H7dZYY)**z@KOƌs%OOOA:F\_߾}yr A666^U]]-.F7bZWWw޽7ohGmmm3g<}@;D݈ӧOȬYFIHHٳ 9 _GGիWׯ_OR?۷k׎=zРA'N\bųg[lPHFō=?ܽ{75jfhhΖDq߾}X555 7p I&x,~l@!^ݫWXԴqFYQQTSSÇv@ ݈-[HII]655ܹs<Fbbbf̘Q^^奩ɿ0hժU&&&/VHssG5rHmmcǎ;R_q7qĈ644***JJJ7njjj$)==]! nƍ+++}||>~bƎ;hРX ޭMUUYYYiy4-!!akk놆~i&Qvv\ˍ7%$$ I$RKKKyyyNNNqq1L_= tttrssaҍ8/(((--UTTOyyy>}JMM-**gX֒|ܹۿ~Z? ~Ç!:r䈀 hj]`t#^*++Դsrrˈ#>}l2n˰aÒrrrtuu *))\Gh3Sb֭[ ֭ho"%%PXX(оF7⢵`199ҒNP(f`t#.O~ÇHҍXxW̙߅}5k־}RRR\\\_@8)c hfΜw^ۉq}}l~~~ 0x+++|;::kkkSb SQQ|=4TPP`0 x³7_p\jnnfַo OOϑ#GFFFb «WXtڵk.]u,@N:}ܹs}||Ο?u,@/S8TSS3`--_b/ŋֱ444:_jllTWWokkKOO:?)w^LL̪U9@$##eee҂u8@\ikkc0XǂJPPԩS 80Yf>{ @К}u, $%% :۷X½ ` zuu0,Qll# ^D޶mJJJd7[QQaccu,эhQ ))`ccЀu8t#x ֱht#222 ԰EHWTT:`t#Ԑe!!!X"߼yfnnfH7QQQfffX"F]ZZ:j(c^TGG,ц Ξ=x7ob K`t#\]][ZZg7Μ9p֭X_aagg7mڴOb(ۋ/~7![JKK0,H7HQQL&c(illhmmMMM544=uuu/^xulllFFF[[[?daÆO8TH7BgŊޏ?vqq:ѓmjj*%%U\\cGDDą >}J Fmmmmll)''pccciiiVVV\\ܻwVZ5m4|s.@0}:8kbpt[SSXD^MMͤILLL={ F իWf̘cddįx^cc2XSNȈ{L&s„ uuu>}%s nf'%%ddd466X,)))eee~lȑRRR=oտ+))“'O͛ s|'_.))9jԨZ[j Ë/niiwbd2?[nRWW߿??b`tñM6;w۷oqޛ7o͛_TAAAAhn~ufϞzVV֧Otzlݺ588855ېNİKJJJ>}_mVTTMqb^ϛ7'OBȇ *--$R gm&!!f+**LLL,--۲@~IKKCyJJ۷o{\@>d/O<9qĭ[۲RhhhIIɊ+۲HNNRDy]Xd F(QRR/PVQQ֭[| MM͇;;;ϟ?_]X~~/>Szzz\w*n7 DcǮ_~ƍuuujjjx~ٳgrRMM /nP~)@;ڿ?@8q@{v*㩩۷oAd2W܀tʑ#G;ٱcǥKP(v?x𠳳9}D_$oyyyϟ?ߺu+ Tرco޼oҥK|}}yZ0 x1ZUUU1 C WMM E%%%?^fMrrrSSӛ7oPvG\\\n߾[E[[;??Crwo^^6)gEȑ#׬Y樨(ﯴ0ߣl$88a7zHM0fee/^piGGJq#dF7}hmm0aշl $7nDzEFFr#G͑[9ݰH455p1c444 p׮]=.%%i@$%%W\yV4;w7:4sL===O Ջ/޹sʕ+ q---M6 zbݻ~Aw7XO ӧOkiiȦMPZz=/R(/_J䘇9sX,u?`tRK#^^^477|N@?c̘1sillD,MAAa> :%n`bbd2~K# R]]]߾}CHff /'޽[WW7gΜNnݺ#GM4iMWŽdhwㅅ=."%444i@ p/IIIt:}ƌmmm|lvd29(( Ś7oR̉fCu1M,Y߹sEdz#2%XPPH併ST5&&Ybiiɗ ;wN^^IOOOO,+00PEEENN'knnf0D"QWWWCC%Q̔#""zmÆ D"9rp UVVR(S7nܰեHEڵko]YYIR߿[bM__%K@βիW~sss MEsrr @AeC aaXeeeg55NȞW\naaA$]\\^xd2{ofGFF.[LBBBGG޽{pqի! Tm 8BII̙3g^! 6n:~= ...ǎILL >s挛Dnذa7n.WUUY[[CͧNt֚5kTUUkjjܹs ]]]G hʔ)SPPpҥsN]]}ԩ'OLMM=;wHHH GAA H7Ԝ3gຸ> ï_\8#d􏴶秦|Ug 8::B$++ x0 =zTQ]v q܋!***}~DhhAXnJMMF]Ƒב;EEE4 X~b-\ *?`6@A% H$R(Ǐ0| ~5GEE &9sayy~5{H DB@8TUU!(++:M> A|^^rʕ+$ͭ/_,!!ꊔH$*'~Ď%6X///@$8u, >̙3Y555MM'OprzzD:~=4@ pݲFT!GdffbN?旘L&r´i~zCMM ˆ#LHHXhH1bDBB7TVV"kp?g*!'O@n~DYY;w~gJJd+={V^^m>|ؿ9A~~~)AɏoД؈j PII)** p ()--=qѣd2rnj3n8+++uuuh(2e Avvv<48E{$Afι|ۈnݺAR߿?l0NojjJHH())illdXRRRÆ Cf%8iӦӧO'''KIIq8Ǝ1BYYD"aߴ͚5+88XZZwXG$X;yfЕ c/ rH",,N#'yo#n)6-`\Jlx0B|2ֱH7d``AТE(p-11QMM A`tӕ#''S3f ۛ7o8z˗/'OF,>|}vISSS0o߾r3>͕+W`h|R( %6G rvvFղcǎ$iԨQ&)6hnn.!!q_mtj*X0&FpL3 |A/wZ[[7np]ggӧ%%%ׇtlS0f!" ?AJlݻw HA`]]ݏ7 2$5^ 8ǵ5I7v L&={JJJ|\\YYieeSTTutdܹsX"ptO127n+jkk-"ͳgH$L: WPP7+{%a۶m?}]aa[O7K! wC%%% $Io޼a{nT͂ ?'A0:p;ZrfKK&9dXDyyyׯ__tӶmۂW(6mnkktGrrrȹ"ܼ|֭'N:1lذ/_xzz^voݺuD:ncccjjZ^^g2i$N;"==ᰰ0777qޡO/_>tHa03AwMR zTj* 7n0GfϞzjOOjAFPD"Go޼}!Xxdeedɒ5k kk˖-:::m@Ǐ?s9vF۽{zG$Y,GxzzΛ7~l(:uf#Bgg\eٹsٳ#F?~999:bQ흟aA`0Oѣ{ իW>~{97xUBB;w8jׯ7={˗/s盛ysQQɓ!*++;|0Jݲe ~,\ݻ 8x𠬬͛͛oܸٳsO̘1cĉ8;;h4EEEϟs1Fɔ@ltttdt:e= ɴ ɩիaͽR{{ŋTIhMccA455:;;'NHPЗrS(w/[[ף)oFvKLLDNggϱ+//WQQ h֭ƏK㩩Æ c0__n) ƕ+Wz^RRaGh"|{nb"ם>}SSSͥ=nuuu;wR'}7#F )6x`8qBGG}#{t|r|q= !!:::N<)++;`i6;;{۶mt:]YYի$L0K5]^^˗CtzǜC?笇_Ν;w۶m(ﯯ|2wAiSVVsǻ0Mъz ,DNB˗/4M[[脅EFF5/mN0aĉEEE...'NK@l6.??_8YuEeeeslnnnt_a 0 ?sժU;!KSmmm^^^0 [ ł!QSS^X~'&--S AAAu!rl&;qH\9e5cڮ\u,ƛ7oFʚ5kr]HHȀЗ#妥.cWBCCMLL(ǯ*{hii& .,..mׯ ;6 ;c͉';w7N[[v׮]Ռ.ZhĈ!22@ 8鴳ݻ~W{nbbbMM r,**zݹs\\\T… {0 +((*%h RK0tSSS#--}~ׯd2Ç+T*F!Tbb={Ǝ]DΞ=ۻFz !H,z AH 3JϫWfgg fIII#=jnnhjjJNNF3oٙ[\\\WWb$$$=--ںѣGVVV)))3f:t~4448˅455c0 8 ŋJ `1WTT޽X89S0 ?yD@}:H$۷ #G  0AއT*H|ֱpS4nJ/DssYsssIIAjjjIII| FrLLJ@ HII)}5c EEE{Т訡}Ar .@Klظq#I}P# rrr/_Keee#FPUUЦ9يN?/%6L=A666Ǹt`A$ߣ(S_VUU555GtvvFޯJl ^CCA/:J7k׮h4 orSaaŋahjjf&̉JJJa M0HMMhAp"!33SFF XxAAv9s&1@ϟWX!!!add(dںESSN'H"dL#<2aqn3g$nnn׮]~TkkkZZǏ7oތݸqիa&8üĆSA:p@+$ֱĆ ,q3Rbs58ѝ /((@=|0ֱ\CCCrrrHͶm۰={V&߼yCPDb@@ֱđ#GH$rֱ7fƌXүDhŋ0 KKK8gAʥJĪ )2dց`@T&W\][[u, qM)DJlpSb)! gX75;;;6 r#A!!!X#(H!ZZZ\X0t ޞ>ERbC&333E(>AYXX䢢"^#0 _xFp@\ 2]p!AT*:~BJlb% ` ljlT*uСׯ9G xsDBB*RYVVu8| >%6B?AʒHqܹ999999QQQ^^^#G$ cÆ yyy}pa܌{bn7o&D"СCXq+Teeeȶ/^DsJiiOP֬Y>= kD~ 馫+77 PD7gN2A~-999}}'OleXJJJ~~~=}M6?7 N<^X8#%6qd.[H$ܹm'֯_͛%())AsN>8!馫Yu8N}?A2ydyyy~}})F;wnGGGtt@H7ϝ;w$%%!5k7 JlL+((|-2 kkk%%%ŧ# Okk3ABpLJJM&i4ZEE$$$H$Ҍ3ƍ҂uP= <>$$XD mll|}}[ZZ8>^x/JpႧ'_KDDDJJJAAAuuu[[Ba0ڃalmm?~x5~$VLMMWZu!jժt999"@ɓ'XXX"S\HOO~QIIT*ɬKNNPVV5kֲeˆc;-sζmێ;'<<<޿c0555.XԩSETa6'켼plllI 255=|pjjj/7gee:u I4ƍ_A mo ooo |ԬH7}366 H[[;==# ˖-aݻwuL̝;w?055EY˗AyLػw/Q H7h>}L&0| 亻p###55K.ʢ_tҟ ܹse {R9;;GEE)((<{lԨQ?0 &ܾ}N]ss߿OPJKKyiM=}ťLAAyyy#FqM Ȟّ#G*d:߉w"3f1'7n㟵}0| ~5(֮];vX/]ɓ|NH7ܠP(O>}5L5kmvv̙3̙sQwe˖5k̟??;;(ܼ533s?w*@ួ}mm{ddA^*N:effh"6-.𪼼MGGӫ~ D7o|M**^H$()HMM ܟ^z_\\ޮebbddk555***GO`t+uOOÇ nܸqϞ=gLFȔ)SF5tիW طoNHHFL&WQߪEdraa!vttptMMϩtd) /$''D%%%4""##Z3`të .̞=[CCVZ^K8Q!/542x`ߣ|~q|#N200|2GwwԤ$N[RRR<Jo߾ t9' ƍCyffoVQQqz:t.G à JIIAygggyyכ8,A $""֖H$_SS'N ۷\?.lmm/)h"Kd{ʂ q޽$L'C A斖<6"V&Lӧ247KII%&&"cn?rrrB}ׯ!^WWׯ_OCC꺺: &߻woӦM}LX,ѣ]]] oݺx =޽{W__ʊqwtt G'NJ nPP(/t|󕐐xe\\\QQQFFF322 C]{{7Ф6q ӥ_A(Ȇ .\pEyq˗[ZZ-[u xp;d6eS++Vؽ{Oר9xM@͏,ddd jhh~{۷oܾ}@{YnNh/" IIIs0 b0׮]pǏԅn޼)%%%.DH7<166Ft ~Lu%KDGGW^Ycƌ{ OcccO>sq)SL4 }aaa3gtww߶mnx2nܸ(cJhoo sppq@ ܽ{wԩ&L[˗ na$]544HJJro9BʂUTTjkk9zӧD"Hfܹa:۩7oH>>hN'O yK޾}[NNmvttN!n޾}}}/_C_W]]M"455o.%%w>eee8/)SxOM4ǏELƦWTT\t)**2665j"JmooMII\r% d@{y ELܽ{իWfGFF>@Q*--2d ѾXikkc0bjkk;::T*NG+ GggCEEEdd$---vvvQQQw'O5vuuM<-Μ9<00ޅϚ5 F7TPP`ggG9=*++'MTXX;ccc~(;;;kkkI$J~ Æ {EEEYZZ&%%uuu\ nL]]ǏӧOwrr@?nk֬gVVV"EJJ͛7nj3}tcWXOVppu!m&###!Zx ?uuu ؈u Fރlll= SN;@ hii9s{5WwuekSuuu}Çaaa_~ N+++SԎꪪ*\]]Z⡯۷/^D8gbbck ϟ?ԴS(iaa*&+?6>߯_FF&..ʪOQgΜ8p5:@m EEE p設hs@˔h6loee%8讛Gmm͛7A6 ݈y޽;))iܹXǂ=dѣ]\\ LԩS?~ݻwc 455+**Aյ 411?ݻΞ= rphkkSWWOJJ233:V\\} 3npBtWfff}^pESS344XեKRSSwr0zʕ+nju,QQQQYYXހ Xbʕ߿_r%ֱɓ'3̐ >]|y̘1W^tֱV@@,Y"_Ex3c@ttt0 RSSu,@ϒi4ڤIE \]]@<:th[[YDDijgϦLboou,*e >}:c cctc'EEŶ6[ M>SN:YbEuu5X-ZF\̞=;w<|0ֱ*##tĈXp12dȐϟ?.XXxSRRRYY)''u,˔SVV^hQ||<ֱpoNFэx)--Ӄa8??_II p8V^^nhhbnċ۷o;;;cNNN]]]/_: ݈#Gb g]-[hjjb 2%l_-Z֭[Xǂ [QQX.э:uꔣ۷ocAYu F~Xқ3gX )nZsszsssjj\gg>Ç755a͝; ,nĝ~pppccpno }x̙37ntpp :CII`tdž <<<7mڄu,f͚*kn1bħO_tRc'clfiiFm0F x@ $''KII?H9{1kn---勋1h,'ssWUUYYYa;44 WWݻw̞=F}oܸQWW L4}gϞ۷o޽cSSXK 4hPZZړ'Of͚ݍ?۷Y Lg0s勠z7o,Xr ^ ЇB2\PP`0 ͦD"@ ASS3<<ܜf 766>zW\r>|f6WXXXWWbTOvtt{H7ZWt钧k~zCVV_xxOw!c"551c899͜9Nw?R___[[+!!/? .@s}fBܺu+..buuumHSostfV.E$؃4%fPk e m؋d=Q]92 VIRJ΅:rF\ qO]w˵]۹FZ>qDBB%ϟ1 p Z6|:hgg==='66ԩSFVX\\ljjڳgOLLLQQ ' qr׭[gZr9"j(K:NPꂰRq෉͛7?|зC!TWW+ʊ{Tt{e˖o۶m-kjj8P\\<33o߾eggtG=vXkk+* " ٷoJwwM[d29r:A.]k{{{A@p  ۻ~N'E*vwwmذ!x]@X@B0 r4Mϟ?Y,BzjPЃ7SNg6JeQ˗/߹sr1BB!N H;44422bRSS Faa!c%vB慃jL&\Nd_x<۷=Śx"lii!.!!̙3Zvmv7_MMM]]iii\^^p8DL&P˗۷m 3(*%b߿?Nߺukgg'qp`600w^T߿8 f#XElbAD8].^Kݎ Hff&)l6b)474 c-E&&&xħ0 m*@Ntq6K|JQX]]EB!Bzc\111ple nn7mmm*5o 1ju8 j@L&ӯ3tttbFC"k|IL HJJhfٯYϞ=+--}EII ###v"7D&ʮC븰088 D x4:'7n܈;B&ׯn`0`vAK~ 9δ4F#Hpk4 3ue2złqdCCC#-' UAAE 6-##CZ,P7;wA>RӧOn27(Lf2FGG}_ >E"Q𺀰D}}ǎeee**H-n7e2^ R FpJMM{n.c(//GCCCpҎPUUUO>}Y\ GRDǏ!en޼x'&&(777 %nTZ[[Lo(VeXeeeo޼~JJ RgϞ}_|ohNsuu5>>>99d޽;ߒ½R7!q@@B" qJ?IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/sheet_isomap_golden.png000066400000000000000000000547661450372207100266250ustar00rootroot00000000000000PNG  IHDRzzYIDATxwX3]z[tE@P@A,رD؍b=F% J)*` EHgu;"lcfy73gy˽wޥKbcc+++;8e„ ~~~ݺu!i$cZ[[=jaa1n8gddp\w***޽zss3fdff>DJ G߿oiif͚ϟ?㼊f߸qɉD"-]VaBR EJJJh]|Y__<99Y1Bc7P*++}}}Ο??fQbXͻ{N*!@&:Hڕ{zz&''[XXؚVxxo6cƌF1 n4441&&&鉥MAvܩ9a4 I?n?5__b̙ɽzotc7={vD<o%%%iiiT*U]@RλW^^jժ@ s '. n-_<22233FIn޼ӧO:::"QVVvԩ-[H:/^qIwgΜИ1cK8ٳgGmkk>mڴN/h˗/믿 4nv\xq֬Y 555#ojjgϞf<ϙ36**J!inz왒#F>x`С_dffiaذaݺu;{QC2@m=|P[[o߾8Ͽ~ttϷ$$$,$K`ky>vK@=DH߾}?~qHtٳgO'x8(ZYY>| J#W+++cXnݺ׿y&//OGG^__$Xب! V]]]@EEſUVhkkho߶lذa֭8AQ`4448$7d*bŊ/^<{Ǐ=zضm۵k,jKEESssdd2WX8tv|~cc#N6jHt'(jkk=nggNii){ Hteee L644}{\MM Ԅ,@=0@m9;;xXauW*KKKxHÝjkȐ!o߾y… y_| 4hF,x,j8Ϸ\zu||"Gزe jjjbbbF%BԐ jǬY.\pgϞ{^^^FFFɺx. RF܃+¡v_reҤIbyyyuuuVVVgr8#G9rDx! Ծ9s$''~L3g,]4'' HF)};v?OO86l_aQlܸ1%%' &Mzś7o%$=`~5*;;&!((h͉boBa !ABCCI$ҨQڬQ]pp ?sꈖփJKKZZZ*f>4o,,ҥKIIIl6а{ VWWegg777L0߿w_/ٳ055%cAĀ~mΝ˖-`5SSSSJJJZZǏ+**I$mͿظ[n>}L7Pbbb 䔖&;tҕ+W߿_CR%%%%%%T*UB1nxҥK]D,0!CX[[{:p8ZZZJ eB]@bFܕ䈈:__߮z0@Ғ̰xzzΜ93::,Sꅇ/\.tfϞFt,h޽֭#:HÔ:wQ^z-ѱ@bӍ"zm>} }zzzEEED |R8 EBlBCC#88 #O`Q8 %:̜9+887tX/^ŋ͛7lw直= $0(k׮8qb2Jֶ)(8T(>}deeU\\5?_~ ӍBp8?~466&:x<&XQQ`0,}AB4hPeee.oEccc L7oݺuϞ=[bŸq㈎EH˖-{ى'|sQQQcƌׯ?Ct,255-***,,#:H0ȳ/_XXXKn.ӧ=zXYYue)eH`lll_z%3pTRRr `Ȑ!D ȭaÆĄN>Xĩw߿":H0pX>111 ,\xD:t(с@F=|p'O$:믿|h"cMEE1B)))Iq JJJ\\\ ycff/_ݛX$YGGJVTT֚ EOreܸq'O\PRR 8q"ѱ@xt#?<9eʔc F?~[)=0%'RRR\]]wEt,]贴TVV*)) xw#jkk=== Fjj*ѱt)Eݻ4bc:Ӎ?,,N{xx>0%lvAA|,MvvǏMMMj|U݃Ǐ#2x`ӍL?Wn ˾|d=z4??D>LɞWN63>>XQ0Ș]]B4]L&SYYX^eIkk+iii0ʕ+W***NJt,dРA,֭[D"ƍ7f̘k׮EGG ÔXf;}֮]{ncGGGX,9؅B>t#"""ƏScIII򊍍%:t#{衦VRRB&G;wӦM#: X,Vff%CCCURRAt,~UJKOOONN,**r dv޽o߾nnn0.++ F8vvv/_$:ELIP||v߾}7nܘF&MMM{衮wqooo C9sM 6mz%K&OLЇy':LJ${;v,77GgX7oΜ9`hiim߾6Ѕ-KKKTPP@t 1{D3g_X]]chhVZZJ՛$(,,$ɖD`3gtww7oBuuҥKa0(fdd;FuQի;=*?*++y<^D`믿(sN.+bkeeeb 7gggA^zxUUՕ+W@PlllfΜE˗/_zuرbi3??Ĉ(>zVZ&^ZZIJJ:rHDD ׯ: uuuYYY?Zt/ DDtJJJmɩ^-+0Y҆ :t˗HKK˝;w&NH"z Y~t#ׯ#r5I4^PP?c I4=RRR<;;ّVVVblY5SB˻sΚ5kg???;;;MMMfllL )55ի=ԧO",C !ɏ?<^v;ݶm;]0^~fpomb;M{ꕚ:aU\+ WVVfgg觖&AdƍӦM?uC0)''NwMlׯQ8p :}/22b͝;1114p¬Y:n᧟~;w͛Vt#R}}}UWW]xǎ/400xp*k׮0Lmfee?xߢ(:mڴk׮t.nQ__*ąSQQG $ jŏ+1c,\ge۷D___x*p#;rI---UV}_oVUU\[`A/^[bF\\\( ]Fjjj555B\ػwoWZu3g༼*4gϞ8Ϸ̙VJZYYOݍ0\(]pن[t̰7yUTT"??_NL7°a?~===?}>؈ҩBaX"Bܱc?lnn.U,K~L7իrjj*SXX`uuuKK xrqq<^Bф<##֭͛B25BFd2=&&^zQK!x J};Feoo/n.n`?>##OwΝ+V1,, 㧥UQQ!ܵׯ__~VTThii ׯ|FHӦMkhhs8ʢE&O٣G<-TTTܾ}{"@LMM󅛲{xx qm^^dCQ6{l=r%%%Bݼyakk*2lkVVfeeH ikk+FP|YӍ?˗/K"UUCI#9pϟ?/sqttϟcՄ\)cѢEkUUD;ZrޢE$ڋ!HnK. B iee%]yFtaYYYd2yĉʕ+Z h$;wn=y㙛oܸQkҶm۬+**֬YgI6w 6xzzJ}7a .}HI&ݿӼ>}dffܕ+WborrrD:z(L&H#:p\ A_Nt,R-$$A]]]lwx<^DD' ړ&M yfJJʇrrr^|yCa.{9@nݺEPdիWdL7ggglvMKK111D">mЀǏO:Km|}}ݛ!h$?6XdPE(zz*FCdD"MMMLt,Rg˖->M322޼yzr [&[inldzpVZZLR.] pvv&:~7HrCAM||сt&7+3d2ݔ`xQTTLd6mDB7obEHÉE$nΞ=KPPݾ};ѱ8:XSTÊ,[X'K馡VVG]]]_tR"\.ɩp!3&22N#KL+d2ͶlڴXѺuD"01>~ӧfalllccCElk„ ZZZwqqMEO4$''H_z466Z[[ǎrݜeЉ`޽^^^X_NRSSö HNNN+WLJJgϞijj&NKpp06Nt RWWA/+..622̙3X LIJJ=z4Vr޼y.\HOO bkkkNNNDDƍ={믿׉f0w"N{쑪̅jjj(޾}XdVFV& nrrrF p8xzݲe eDDK=x`euׯ>|`0d2ѣGD"cvڅ LL ;vN;;; pT\\|Çeyy|ͷO}A}}}yGA`<}XIYrFmllBCC_ ]SSS]]}…=x:źp႗ 111077.55UEEAݻwK[۷oKTJyy9qL76mll W暚wtwaB&M*//G1;;;8JB/QFa544 h111H]]]E6oތ$ }:++K]]]ӚO?PhG,̬+$'bW^ njsm1 uܹsd29** {! /^deeTUU h$TYYvAˣP(W\邾Nq8ѣG+++ j*O\Bxddd#e.޼yҲwwwwssUSSd77]v}O ]]]޼yrʱc_rv֬Y...χ$gҥ***ϟ?{+V D555akg,)) 8tժU>PGFF.YD__Eщ'v:QtceezjqE,Yr޽;w2#F_!S@i8P׻tZ&Oldd$`$ELfAAϟ0a%&&MÉpwwGdl'dddoQN"fϞӧׯ755ݶm!+,,TWW_n亨%ԁׯd OCCCUUU^vm }cn;lSG8juu5F/^`CJmZ <-- +e򲲲F@D\K bEHtKܸq]]cǎl4!!mSLNee%8χĨJ^|YKJJLK<== sDBݡѝ:u AGڙYWWWģ8Zg;χƍ4 {%!2.5kVDDDCCp=BbѣG*}v___Ixٳgh'p\Yߟ%`SD !66vȑgqdA7n\kkkbb=BqFu~]]˗cN鍍89! T*%&&zxxqaFFƶmێ9"腚{ƞ!Bܺuɓ'ǎ62vW?R}Mߪ&>l{(ÒԕJJJJKKYiii>}zPP:88 q!$۶m6m;:tO789b&8XZZ<\@pݻwv%5ӱpqƤI;eʔh׮[ݻ}z gC&&&666uuuqnff ln@W\~>.===k]pݽW^8ϟ>}ɓCBBTUUGf{{{_xoߦP(K:bپ}V]]M" O9r .s5**%FFFbG5rEUUU.Ă:tX!C|=r{ ȷk :v޽{sw3h Aܹ3u͙3dnڴ{krÇH$<- 6 gH$.+%͛6mS0<OЏ{?$@AQj< ͛vҍq6Y]]rСI&lի4mܸq8χHCCtԩ;w/&[A],99YMM .ۦ8o~… }||޾}kgg-WW̸O>9rd̙ۭ4??wޝ\XXbŊ~i޽_~{õsNzj|0f̘/uc444~n:uy楧c $aڵl6{ǎjcȐ!W^=tPg*++۷1{ 555"6CB(M 6$$$,XãQQQ'NߏoTVV?^]|`I4U_ !^ϟ?o߾uhʔ)'O]v ŋ3`NvLNN˖-(Nqqq4 '+GGy wǏN55'N$˗{xx?_WW* v;>EP.]*=޽KӱlussJq *$$JwA_vjhh肾=zu3T-,,p777 V`;NNNboo"۷{쩡,--UQQR߿k0 ɓ %==OiO7 `&333={itt Jycxҥ~(:s/_|QnnN_澑H{NuTǩ$))D"u ] + ȷOfffYYY(%%EWWwذamsL`[Uhjj~Xd[NN2LZ6Ço~@8166fق +槵C־{}]tIYYyXpQTJt,*==FQTasU @qǫb[Ea; ϟ'N onK7S!1ѱȞGdA?׌0V2QMMǝiffuV׾|faccd2`;`{DQT]]Fڴiˋ@Л7o uSwޭ4u7n|}'𽲲S(cc'Ovt, +c.\@DWW?tRID^A%%%+퍽 077>|ܹs/_lٲ9sxyy|}}_gN5S#!!K'O  :uС+V{`9sfhh/cyC ׯ_\\(566>}4555;;EQeeekk~AR6'T.妦)SžYlllMLkw^D&9Bt,퐇t?~<6X ү_?鄫&7C6, 'C!`0?Nt,=JV*: ŋT*A) W+ ȁx˻S^ Apc MMMƦt?O[V`UnjCt,Dׯ`D"&===Ehs .rn03gKWcֲ[JCCL&) } 1ICCɓ'Dǂܦ>(F_Y444`"|`0dGE=z(ljj":"ܹEQ2|Ic>idd$ѱYrr2Jh_ʓHALMMvJDUVVb=k n|~vv`ڵD"6$IYY977X$ؿ7jgϞP((n߾X@ ,&ߖ(jjj^كJt ]anݺx(\\-ӿӧO#_SSCt,]a2 CQQQ ۟XIA ϿuB!W^%:aaHj u…,CP\.[l%[*nJ,YBt,~L"3x왦&`ĉrUt}xzzd6a ! .`0ܹCt,oեMO?W|lx^UVV`'n+66F(zc!FϏ@ ŋD"[(JPE`ƙ3gK[\.o߾_~X666FD"Rla M[cǎX[[`|c544(Ht,9y$LFQ4((X z1vO!o&$$~:??bPT---SSS{{{>} zkk/_Xa[, ڻwo\CC?cjjCsss#:0ݴӧ---ZlΫ޿ԩ"mmm{{{KKK]]]RQQ벲2&9qĀGGfXv|beer߿/z#""MܼlٲÇN#JzUUUYXX`E:=9%%eȑ[[۝;wv+++k߾}X2dȏ69-((PUU%Hs(>PTeee]fnjeW*0tTfffVYY xzzن[ϟ?Nfݻwt:B$%% Ejj*LԔ%iӦ `QߏGr$..mγgϨTқ7oD]Ƣ(/W\\wޕx<1F5k,rttE0 Ȯ]y&N}#3fP(GGGH$<W8ׯ_GܼEnZlY߾}ڌ00 +W޹sY`޿o``jii ^X#,אH+Vp۶m*---@B\iVV֢EdA֮]{ҥO>eff&&&?~ժU(jiiB7"BBCCL7;w.@GGF[NݻAׯe|ߟD";vv8`iiIR.]6 ---NNN"|yӍ9B"$7|r555ቈ֬Y .[ZZ޸qCR.{%ccc]]N>>&+1v$`+W(ϟ͗aX,ʱcDŽ ̟?_CCC3%%ǫJg)Ӎ 0c A*--]`.[W^^a._f]v '5 ^X477޽[MM [!h/^|R bMMMIWg08ߎC|>%hew!CpaÆUVV^pAͣ\mذA[[{***X0ѣAH$cLvmoo/tzq/WL/^ RHMMm֭gYYD;diiiZ; :::ܹSv{ՐTFFϟ?ާOlSΝcǎǏoݺU` OsHk׮ qmNNpc7|>޽{Z!ULjjjaS-[tMbq\<_wX^^m:FJN^^^os#̙3ms777A"UD0PQQ~MMM]ܯ슋swwɈ#V^-tݻwSplvq<߿$z*ᑔŝ"w ,S[[VWW޼yŝ"npQSSSVVnD}D"1.WF677uqfff%%%]ܯ́c7xY[[;} ?誘/_̙3 #}t߾} BQСC|>…g 544>ۢ{VԴb[P߻w|{B 6GTLP.] ^w#)eee,Jjii{Ivvu^^~ʭGyzz͛o>uuuک_vڵfqwزe  Kyyjxx<~xkk@4558p@SSÇ Vt#uI$R^^сSSSE_z֭[`0 lقgP۷֭QSS۾}{SSSD-Ô)++3LI5pX,Pӧϟ?v؈cӍKJJ8pWll,ѱHW^999 R >LI;_qqqW\!:8p@*Bt,`hhbJJJ444E988~:>>~Ȑ!D RCzj֭0H9֭[Ꜯnss7TUU݉G\zuÆ gϞ%:aJXYY~ؘXBNNnaa![uiӍ,)))166611}}9j``P__g``@t8P,?tPnnUxdXn݂FV⒖|jժ]vDӍ쩭e2ꥥDBǻ=}X )٣RVV6{lc!@~~ɓ U#FW8<beff~0*$SYYIP :Çaaa'O&:H`aJV䈈:___c"6mz%K`QF]tI⼽^|It,`yzzz555eeer\DIIDIIp !)Et Էo_SkdL72nժU'ѱHѣ O>mkkKt,HÔ077/,,,(({]v̙3CBBL7r"???>|@t,bS={X 1n䄆˗9СCG C>|xw#W_z[9水KIIqrr":HRRZyBhKKЄpO|0{+}[9EBƲcǎ=~dFFF3LAWTTK SH6bEA$Vk SH0,7yHLLd0beիWI$Nh޽D t$ƍ%%%;}wqq677wzz`0(;.w "|7{9snQՇ&eee୨+//lkkkΝۻwoWWW@&1Svw}WXX9^˗y@M  ~^x_^ҥKj:555(q.tы/~r8q+>Pq022g CffG}tڵ QQ===yyyRYYYQQa0(JP q䶶`r:,2ص@Ao&FFF;v7AFcx>W v@ ^S*&O̰쯿(@䃸Ah<|peeeYYYP ]pajjjtt* gzz:xUڤRimm-d mnn ­-Bz=/**v2@ L&r$VǙLL&#D/XL!Nd^z}D$I*Bր[ nPwwwT܀RI$ROO#7r].WVVVKK\7o>"c: nn{X,.,,wVZ[[WWW9rY,VRRҾ}0 s8fYﳳt:W^)-- n]\.JP(FFFzj]__#HIII';;[$eeep7 D D n!q@@B,aMIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/sheet_isomap_noasm_arm64_golden.png000066400000000000000000000537601450372207100310240ustar00rootroot00000000000000PNG  IHDRzzWIDATxg\8!H "EDżİqYw ]LeA* YH90*$z/ý졺T ^IIɝ;wߘ^nSPP0a¼y&OL"1@X`,33s…ڧOJKK;|pmmYϟ?ގuH ֭#O}8p`׮]|lޞF}VJJ-xҍIKK^tٳgxqq#F#7H7dZYY)**z@KOƌs%OOOA:F\_߾}yr A666^U]]-.F7bZWWw޽7ohGmmm3g<}@;D݈ӧOȬYFIHHٳ 9 _GGիWׯ_OR?۷k׎=zРA'N\bųg[lPHFō=?ܽ{75jfhhΖDq߾}X555 7p I&x,~l@!^ݫWXԴqFYQQTSSÇv@ ݈-[HII]655ܹs<Fbbbf̘Q^^奩ɿ0hժU&&&/VHssG5rHmmcǎ;R_q7qĈ644***JJJ7njjj$)==]! nƍ+++}||>~bƎ;hРX ޭMUUYYYiy4-!!akk놆~i&Qvv\ˍ7%$$ I$RKKKyyyNNNqq1L_= tttrssaҍ8/(((--UTTOyyy>}JMM-**gX֒|ܹۿ~Z? ~Ç!:r䈀 hj]`t#^*++Դsrrˈ#>}l2n˰aÒrrrtuu *))\Gh3Sb֭[ ֭ho"%%PXX(оF7⢵`199ҒNP(f`t#.O~ÇHҍXxW̙߅}5k־}RRR\\\_@8)c hfΜw^ۉq}}l~~~ 0x+++|;::kkkSb SQQ|=4TPP`0 x³7_p\jnnfַo OOϑ#GFFFb «WXtڵk.]u,@N:}ܹs}||Ο?u,@/S8TSS3`--_b/ŋֱ444:_jllTWWokkKOO:?)w^LL̪U9@$##eee҂u8@\ikkc0XǂJPPԩS 80Yf>{ @К}u, $%% :۷X½ ` zuu0,Qll# ^D޶mJJJd7[QQaccu,эhQ ))`ccЀu8t#x ֱht#222 ԰EHWTT:`t#Ԑe!!!X"߼yfnnfH7QQQfffX"F]ZZ:j(c^TGG,ц Ξ=x7ob K`t#\]][ZZg7Μ9p֭X_aagg7mڴOb(ۋ/~7![JKK0,H7HQQL&c(illhmmMMM544=uuu/^xulllFFF[[[?daÆO8TH7BgŊޏ?vqq:ѓmjj*%%U\\cGDDą >}J Fmmmmll)''pccciiiVVV\\ܻwVZ5m4|s.@0}:8kbpt[SSXD^MMͤILLL={ F իWf̘cddįx^cc2XSNȈ{L&s„ uuu>}%s nf'%%ddd466X,)))eee~lȑRRR=oտ+))“'O͛ s|'_.))9jԨZ[j Ë/niiwbd2?[nRWW߿??b`tñM6;w۷oqޛ7o͛_TAAAAhn~ufϞzVV֧Otzlݺ588855ېNİKJJJ>}_mVTTMqb^ϛ7'OBȇ *--$R gm&!!f+**LLL,--۲@~IKKCyJJ۷o{\@>d/O<9qĭ[۲RhhhIIɊ+۲HNNRDy]Xd F(QRR/PVQQ֭[| MM͇;;;ϟ?_]X~~/>Szzz\w*n7 DcǮ_~ƍuuujjjx~ٳgrRMM /nP~)@;ڿ?@8q@{v*㩩۷oAd2W܀tʑ#G;ٱcǥKP(v?x𠳳9}D_$oyyyϟ?ߺu+ Tرco޼oҥK|}}yZ0 x1ZUUU1 C WMM E%%%?^fMrrrSSӛ7oPvG\\\n߾[E[[;??Crwo^^6)gEȑ#׬Y樨(ﯴ0ߣl$88a7zHM0fee/^piGGJq#dF7}hmm0aշl $7nDzEFFr#G͑[9ݰH455p1c444 p׮]=.%%i@$%%W\yV4;w7:4sL===O Ջ/޹sʕ+ q---M6 zbݻ~Aw7XO ӧOkiiȦMPZz=/R(/_J䘇9sX,u?`tRK#^^^477|N@?c̘1sillD,MAAa> :%n`bbd2~K# R]]]߾}CHff /'޽[WW7gΜNnݺ#GM4iMWŽdhwㅅ=."%444i@ p/IIIt:}ƌmmm|lvd29(( Ś7oR̉fCu1M,Y߹sEdz#2%XPPH併ST5&&Ybiiɗ ;wN^^IOOOO,+00PEEENN'knnf0D"QWWWCC%Q̔#""zmÆ D"9rp UVVR(S7nܰեHEڵko]YYIR߿[bM__%K@βիW~sss MEsrr @AeC aaXeeeg55NȞW\naaA$]\\^xd2{ofGFF.[LBBBGG޽{pqի! Tm 8BII̙3g^! 6n:~= ...ǎILL >s挛Dnذa7n.WUUY[[CͧNt֚5kTUUkjjܹs ]]]G hʔ)SPPpҥsN]]}ԩ'OLMM=;wHHH GAA H7Ԝ3gຸ> ï_\8#d􏴶秦|Ug 8::B$++ x0 =zTQ]v q܋!***}~DhhAXnJMMF]Ƒב;EEE4 X~b-\ *?`6@A% H$R(Ǐ0| ~5GEE &9sayy~5{H DB@8TUU!(++:M> A|^^rʕ+$ͭ/_,!!ꊔH$*'~Ď%6X///@$8u, >̙3Y555MM'OprzzD:~=4@ pݲFT!GdffbN?旘L&r´i~zCMM ˆ#LHHXhH1bDBB7TVV"kp?g*!'O@n~DYY;w~gJJd+={V^^m>|ؿ9A~~~)AɏoД؈j PII)** p ()--=qѣd2rnj3n8+++uuuh(2e Avvv<48E{$Afι|ۈnݺAR߿?l0NojjJHH())illdXRRRÆ Cf%8iӦӧO'''KIIq8Ǝ1BYYD"aߴ͚5+88XZZwXG$X;yfЕ c/ rH",,N#'yo#n)6-`\Jlx0B|2ֱH7d``AТE(p-11QMM A`tӕ#''S3f ۛ7o8z˗/'OF,>|}vISSS0o߾r3>͕+W`h|R( %6G rvvFղcǎ$iԨQ&)6hnn.!!q_mtj*X0&FpL3 |A/wZ[[7np]ggӧ%%%ׇtlS0f!" ?AJlݻw HA`]]ݏ7 2$5^ 8ǵ5I7v L&={JJJ|\\YYieeSTTutdܹsX"ptO127n+jkk-"ͳgH$L: WPP7+{%a۶m?}]aa[O7K! wC%%% $Io޼a{nT͂ ?'A0:p;ZrfKK&9dXDyyyׯ__tӶmۂW(6mnkktGrrrȹ"ܼ|֭'N:1lذ/_xzz^voݺuD:ncccjjZ^^g2i$N;"==ᰰ0777qޡO/_>tHa03AwMR zTj* 7n0GfϞzjOOjAFPD"Go޼}!Xxdeedɒ5k kk˖-:::m@Ǐ?s9vF۽{zG$Y,GxzzΛ7~l(:uf#Bgg\eٹsٳ#F?~999:bQ흟aA`0Oѣ{ իW>~{97xUBB;w8jׯ7={˗/s盛ysQQɓ!*++;|0Jݲe ~,\ݻ 8x𠬬͛͛oܸٳsO̘1cĉ8;;h4EEEϟs1Fɔ@ltttdt:e= ɴ ɩիaͽR{{ŋTIhMccA455:;;'NHPЗrS(w/[[ף)oFvKLLDNggϱ+//WQQ h֭ƏK㩩Æ c0__n) ƕ+Wz^RRaGh"|{nb"ם>}SSSͥ=nuuu;wR'}7#F )6x`8qBGG}#{t|r|q= !!:::N<)++;`i6;;{۶mt:]YYի$L0K5]^^˗CtzǜC?笇_Ν;w۶m(ﯯ|2wAiSVVsǻ0Mъz ,DNB˗/4M[[脅EFF5/mN0aĉEEE...'NK@l6.??_8YuEeeeslnnnt_a 0 ?sժU;!KSmmm^^^0 [ ł!QSS^X~'&--S AAAu!rl&;qH\9e5cڮ\u,ƛ7oFʚ5kr]HHȀЗ#妥.cWBCCMLL(ǯ*{hii& .,..mׯ ;6 ;c͉';w7N[[v׮]Ռ.ZhĈ!22@ 8鴳ݻ~W{nbbbMM r,**zݹs\\\T… {0 +((*%h RK0tSSS#--}~ׯd2Ç+T*F!Tbb={Ǝ]DΞ=ۻFz !H,z AH 3JϫWfgg fIII#=jnnhjjJNNF3oٙ[\\\WWb$$$=--ںѣGVVV)))3f:t~4448˅455c0 8 ŋJ `1WTT޽X89S0 ?yD@}:H$۷ #G  0AއT*H|ֱpS4nJ/DssYsssIIAjjjIII| FrLLJ@ HII)}5c EEE{Т訡}Ar .@Klظq#I}P# rrr/_Keee#FPUUЦ9يN?/%6L=A666Ǹt`A$ߣ(S_VUU555GtvvFޯJl ^CCA/:J7k׮h4 orSaaŋahjjf&̉JJJa M0HMMhAp"!33SFF XxAAv9s&1@ϟWX!!!add(dںESSN'H"dL#<2aqn3g$nnn׮]~TkkkZZǏ7oތݸqիa&8üĆSA:p@+$ֱĆ ,q3Rbs58ѝ /((@=|0ֱ\CCCrrrHͶm۰={V&߼yCPDb@@ֱđ#GH$rֱ7fƌXүDhŋ0 KKK8gAʥJĪ )2dց`@T&W\][[u, qM)DJlpSb)! gX75;;;6 r#A!!!X#(H!ZZZ\X0t ޞ>ERbC&333E(>AYXX䢢"^#0 _xFp@\ 2]p!AT*:~BJlb% ` ljlT*uСׯ9G xsDBB*RYVVu8| >%6B?AʒHqܹ999999QQQ^^^#G$ cÆ yyy}pa܌{bn7o&D"СCXq+Teeeȶ/^DsJiiOP֬Y>= kD~ 馫+77 PD7gN2A~-999}}'OleXJJJ~~~=}M6?7 N<^X8#%6qd.[H$ܹm'֯_͛%())AsN>8!馫Yu8N}?A2ydyyy~}})F;wnGGGtt@H7ϝ;w$%%!5k7 JlL+((|-2 kkk%%%ŧ# Okk3ABpLJJM&i4ZEE$$$H$Ҍ3ƍ҂uP= <>$$XD mll|}}[ZZ8>^x/JpႧ'_KDDDJJJAAAuuu[[Ba0ڃalmm?~x5~$VLMMWZu!jժt999"@ɓ'XXX"S\HOO~QIIT*ɬKNNPVV5kֲeˆc;-sζmێ;'<<<޿c0555.XԩSETa6'켼plllI 255=|pjjj/7gee:u I4ƍ_A mo ooo |ԬH7}366 H[[;==# ˖-aݻwuL̝;w?055EY˗AyLػw/Q H7h>}L&0| 亻p###55K.ʢ_tҟ ܹse {R9;;GEE)((<{lԨQ?0 &ܾ}N]ss߿OPJKKyiM=}ťLAAyyy#FqM Ȟّ#G*d:߉w"3f1'7n㟵}0| ~5(֮];vX/]ɓ|NH7ܠP(O>}5L5kmvv̙3̙sQwe˖5k̟??;;(ܼ533s?w*@ួ}mm{ddA^*N:effh"6-.𪼼MGGӫ~ D7o|M**^H$()HMM ܟ^z_\\ޮebbddk555***GO`t+uOOÇ nܸqϞ=gLFȔ)SF5tիW طoNHHFL&WQߪEdraa!vttptMMϩtd) /$''D%%%4""##Z3`të .̞=[CCVZ^K8Q!/542x`ߣ|~q|#N200|2GwwԤ$N[RRR<Jo߾ t9' ƍCyffoVQQqz:t.G à JIIAygggyyכ8,A $""֖H$_SS'N ۷\?.lmm/)h"Kd{ʂ q޽$L'C A斖<6"V&Lӧ247KII%&&"cn?rrrB}ׯ!^WWׯ_OCC꺺: &߻woӦM}LX,ѣ]]] oݺx =޽{W__ʊqwtt G'NJ nPP(/t|󕐐xe\\\QQQFFF322 C]{{7Ф6q ӥ_A(Ȇ .\pEyq˗[ZZ-[u xp;d6eS++Vؽ{Oר9xM@͏,ddd jhh~{۷oܾ}@{YnNh/" IIIs0 b0׮]pǏԅn޼)%%%.DH7<166Ft ~Lu%KDGGW^Ycƌ{ OcccO>sq)SL4 }aaa3gtww߶mnx2nܸ(cJhoo sppq@ ܽ{wԩ&L[˗ na$]544HJJro9BʂUTTjkk9zӧD"Hfܹa:۩7oH>>hN'O yK޾}[NNmvttN!n޾}}}/_C_W]]M"455o.%%w>eee8/)SxOM4ǏELƦWTT\t)**2665j"JmooMII\r% d@{y ELܽ{իWfGFF>@Q*--2d ѾXikkc0bjkk;::T*NG+ GggCEEEdd$---vvvQQQw'O5vuuM<-Μ9<00ޅϚ5 F7TPP`ggG9=*++'MTXX;ccc~(;;;kkkI$J~ Æ {EEEYZZ&%%uuu\ nL]]ǏӧOwrr@?nk֬gVVV"EJJ͛7nj3}tcWXOVppu!m&###!Zx ?uuu ؈u Fރlll= SN;@ hii9s{5WwuekSuuu}Çaaa_~ N+++SԎꪪ*\]]Z⡯۷/^D8gbbck ϟ?ԴS(iaa*&+?6>߯_FF&..ʪOQgΜ8p5:@m EEE p設hs@˔h6loee%8讛Gmm͛7A6 ݈y޽;))iܹXǂ=dѣ]\\ LԩS?~ݻwc 455+**Aյ 411?ݻΞ= rphkkSWWOJJ233:V\\} 3npBtWfff}^pESS344XեKRSSwr0zʕ+nju,QQQQYYXހ Xbʕ߿_r%ֱɓ'3̐ >]|y̘1W^tֱV@@,Y"_Ex3c@ttt0 RSSu,@ϒi4ڤIE \]]@<:th[[YDDijgϦLboou,*e >}:c cctc'EEŶ6[ M>SN:YbEuu5X-ZF\̞=;w<|0ֱ*##tĈXp12dȐϟ?.XXxSRRRYY)''u,˔SVV^hQ||<ֱpoNFэx)--Ӄa8??_II p8V^^nhhbnċ۷o;;;cNNN]]]/_: ݈#Gb g]-[hjjb 2%l_-Z֭[Xǂ [QQX.э:uꔣ۷ocAYu F~Xқ3gX )nZsszsssjj\gg>Ç755a͝; ,nĝ~pppccpno }x̙37ntpp :CII`tdž <<<7mڄu,f͚*kn1bħO_tRc'clfiiFm0F x@ $''KII?H9{1kn---勋1h,'ssWUUYYYa;44 WWݻw̞=F}oܸQWW L4}gϞ۷o޽cSSXK 4hPZZړ'Of͚ݍ?۷Y Lg0s勠z7o,Xr ^ ЇB2\PP`0 ͦD"@ ASS3<<ܜf 766>zW\r>|f6WXXXWWbTOvtt{H7ZWt钧k~zCVV_xxOw!c"551c899͜9Nw?R___[[+!!/? .@s}fBܺu+..buuumHSostfV.E$؃4%fPk e m؋d=Q]92 VIRJ΅:rF\ qO]w˵]۹FZ>qDBB%ϟ1 p Z6|:hgg==='66ԩSFVX\\ljjڳgOLLLQQ ' qr׭[gZr9"j(K:NPꂰRq෉͛7?|зC!TWW+ʊ{Tt{e˖o۶m-kjj8P\\<33o߾eggtG=vXkk+* " ٷoJwwM[d29r:A.]k{{{A@p  ۻ~N'E*vwwmذ!x]@X@B0 r4Mϟ?Y,BzjPЃ7SNg6JeQ˗/߹sr1BB!N H;44422bRSS Faa!c%vB慃jL&\Nd_x<۷=Śx"lii!.!!̙3Zvmv7_MMM]]iii\^^p8DL&P˗۷m 3(*%b߿?Nߺukgg'qp`600w^T߿8 f#XElbAD8].^Kݎ Hff&)l6b)474 c-E&&&xħ0 m*@Ntq6K|JQX]]EB!Bzc\111ple nn7mmm*5o 1ju8 j@L&ӯ3tttbFC"k|IL HJJhfٯYϞ=+--}EII ###v"7D&ʮC븰088 D x4:'7n܈;B&ׯn`0`vAK~ 9δ4F#Hpk4 3ue2złqdCCC#-' UAAE 6-##CZ,P7;wA>RӧOn27(Lf2FGG}_ >E"Q𺀰D}}ǎeee**H-n7e2^ R FpJMM{n.c(//GCCCpҎPUUUO>}Y\ GRDǏ!en޼x'&&(777 %nTZ[[Lo(VeXeeeo޼~JJ RgϞ}_|ohNsuu5>>>99d޽;ߒ½R7!q@@B" qJ?IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/sheet_isomap_noasm_golden.png000066400000000000000000000544331450372207100300110ustar00rootroot00000000000000PNG  IHDRzzXIDATxy\i8>Kg;m'J{D )-$N0f&3vص`JB)uZ}yO=|֬Y'N;vlRRRSSSg\7ob|||N:aJiҥ8({nڵd2&99Ya իPYY \xٳcǎ-((sӧO{yyH:L@`8tw믿J×/_N4N߻wOSSS"} e=#G\RVTT;޽{$I= mkk)d@At|||\uرo"twwoذm߾o\\СC o (#84 ѣ'Nhbbrcǎ\p@(,X~ NGGGiiiGGP5Ϝ9zriWdH7Jh/^v.kkS>|XzHNZZZ=<kkkϝ;m (##Fy{{c ЗݍHNN7ng,A#??Ĉ ˷c@Q \.WGGFAV*ƞ8qb3gӕxR SLikkd'@wʕcǎa ݍtҜ9sfffYYY#F:@@QpXһfCCC<bTUU"0<<<8455l3ֱҍ"srrBBB${dĹ.YX)S b&&&o޼:T&Lp@ceffV^^^ZZ`0@`ddTWW+ $n8I~I[%4}tðTZzuBBBqq1 N.D"1))I=7664ť[+|ݻcX,*z>K;ȑ#AAA迴~F oh.zjTT/_lp>Ru3fڴiRҥK8.##C(_>,,[nEӧO!#jeA&ߎ;VQQq]2{`G@Ç3f@$00󤃾ɍ7lmmTZ*B ]~=X{vvvBBR0>6l.&F𨷷DW!DGGף555_j``כ[[[߿GxPGGNj/HEFO@Yi),,KyhoV\9~ UR_,--[[[kjj xh ZYYY{Eȑ|x3gia``pՐ!URți###666Da n jP^?~+duႂ&L dʋfCtMCR8`"hllgϞv444 F"EDT1ZO<(_??{dΝddd!UjBM\͛7MMML&n7n1c%i|=JZϟ?<))ի(;ioo J*SSSqzصk9&Ȉ⌫<`UUUbAгgP^(] LԤ#r󒒒+?҂aIqeQQAT]]" Agݻw{zz {n/0wPWHBINNΈ# 7AhH.2 .6@WJk̘1Ϟ=kmmEy]|G>|eΝ|='90UְaEhfmm-֧|:֪ eժUnnnϞ=|璓ZZZPu[ZZΜ9eBVZW^ hlljyEeeٹsDߟ_ (۷=Ж-[?d2i4RX/k!..NVV255Ec]]]jjj'N{) W\(%%%d2ȑ#REz-4%gΜo}صk׺ VbIi._UDwx<]]] 7jԨٳg2dKgg4_r¢F(n  p>+)) YGc)bӧs8c<ӳ~<O =*QH7¹z*ʒ(\.wСf͒( !!@ L8Q_!6n܈㣢>|XZZ,Vpvvnkk@ yyy 6L@ܹSUUTzC(zuuu<O?yƌ$˟aL&K{Z~t#gϞe˖I gͦx<>55bT*u\.W\bhhhll/], H7Bشicի."H1ytUVV\Bhii-[֭[_jp8!!!&&&8n鹹c}*rxߍB.;zh>X=q[|DRõkh4w}`0h AW544:t/ oo%K,X`ʔ)VQQAٴiӛ7oD&`0ğ6R |ۻwt:Ak֬K7orpp(((5k0n:dqtt4RA R5bǎh.nllLHHؽ{ҥKg̘wM6m7otREEDDDpm۶ߛ\B Db|||M0@ XRλO8ahhwt .ll[@G}}СC!:,t5+V HWWosss"8gΜo++,,ܼy!B{D^QQԢ"pBfBCCq8H|H\\\LMM( kll,---,,(++366^p+runnKOOr쌤Kű~Θ1ʕ+XEL&y+'7`dQ~~: ۷oyEEEddҥKutt>{DP,,,|}}óފT*@HII!em6ցj*TꇗO)ζ* B4|pBff&r̙3j5 H7Yell{ct:Hc!ȆlGmmmL# &ӧcKl6rCE&ܸqȄ U/tӃLRT ltԑP(>:UXXH&DǏ?ڻw}_|AЬY>,ޛ3g/nVÆ CNz:t02n:z(--hx<Ν;Ȝߖ-[p8\@@8+}SRR Ǐ/_.˚LGx<… J7|>?++3f|}}lْ(zPGikk0ϙ3L&GEEm[[@ KP]]K{Q__"*~ӧ/]TWWgdddgggffKPx<^ccciiiaa˗/xׂ Mt2i$\RѴZZZ^UU511qw3fHO@LVJJJz%H@ׯߴiw7Ϟ=Cfo߾7o|昘3fDSSH@w ðZ^^[bLȐx?Dz{UWWG&ϝ;۷o'&&$ؽ{7N"ݴXù 5^EEEpp0Htvv2g>6l@"Ο?ᤴR 1 sׯ5@a0UTT.^6ݼxR___eEEEƍP(gϞKH QYYqF fff6{l b ٳMww? ?iӦM:Uڄ +@k.^~H$[X[[K{Urr2At̾ijjpIII(߳g޽{?b!2Tչs444nH$… %(..D"[y H[[%@˃a811stt상^ݺu á+WSSɇB())Y"//F-ZSºuH߿?A...rr 9r*,,a+ 355lx9&J~-477N4ܗ={ ita&O,KWW}9s6 OOOqzxAT*U0dW^]\xza-\piii---@ yEj2o޼f6" :.N2C~n"##O:ydǎ†";;;7wa$b~gcii)¸vvvyyy"4Ĥ ZK.>>>¶=;v٢RAA3T}~4p$d" _577_xh㚙!C}P/^\bŵkDhݻ^LHHsΏ?h>F"x%#?@$Ǥ$###0Hvv6r"TN2X@bccD>lhh(ؕ< =~O:ebٳf͢R/I7sL0|4ܹ#L$ 9} FDD1pDnlԨQ\.7''}-[;v#FmЌ D iii_H>|fݺufܸqNB= )x< dɒ%s?~8 2}ƍ...h_bիW믲}%}}}+++4 n={&+W ={6&>|8lnn{ws|>ECC'O,++|666k]xqh2ӧy<RZ ,8w7{z={zI7o߾E AԄܕyl.vd|`@TVVfkk͋+++ׯ_?cƌ}} yõ{nl2dh-Z(,,,11 `@뗜 wy>?w^fs#""P= 2nݺm۶Emܸ1>>^$۷jd{322r\OOϥK; 3g@\.l͚5===LwvvRT4I 5D5**C__&Mr(P(RB GC LTTrԗ&>r[>}466V=zfƍPy!rCI>CV"{@f+_z@~7sss"ȃ[rT9y]?rw܌2uBKhѢh #$͛7Ϟ=cbb g#۳g |o;wMHHI/w0!??م,y-~`#F>|Ek5g`>111K,m8@R̙S__޽ 6Hs@p’˗/#q^ӧ_BJdzw\xB"[XVQQ雧0mmmPC555ȯy]zo/YB|rB/СCFG|2Mlb8q"Nnj~P@xԩSzzzׯ/((@yvvvPPL611z]M]]B9~8TQQ!l @z޽{ghh&ٌNRx|nnЈ!D"ڵkhgهB%Y[[Z̙3iii޽{}mm7oO8l2SSS3g|s%i6l`hh&w' XZZJ@x<~Ĉz~I( @HIIHAAA튊 afddlٲ͍F}[KKk(;bijjEv:HOJJ 9]!u-[6x`CC;w[WW/ppp0ǫp`x`C h(gQ) 㼼ZZX' a633(zϋ/FqhqnܸaeeF:0x|]CCb}X;T%ttt̚5L&>|X 3^VV{} A?7"##pܢ\z566ƍ"u#ϟ/B[ciii =zX,`߾}***999"T__vZ<+:x]p1LӧO hԩX`h"7ЦDAA ӦM{;wޅ3 ߿7oP=xt7g/\ GW4 \"J)8]}ׯoߎB122G> jIII" ]pD"0i&C>Q\\L"TL-wBΤu!u$-XիWL&kjj2!Cs---ƍɱHMMOeV]]maa ȑ#k֬A^p@̥>uCkx<@ Ļkhh 2[#::a:.#Oy9Yn& `at:+7np8uuuz֓EEEZZZ`() ~Gd5+WEp0,#SRRJ-**:Yq<u,"tUAjM<@ 4 Gӊyyy$IEEiҥ9KX":L7XIP`vb2J^"f< OOOy*歪*G0,ڱcցbiii)m555 N7D=ω`|R\E@A"`:>ÇE2> """TTTp81dslDeݿ?ֱY#!2I7PT͗ΝP*ȶrmll ڼy3ֱHW}}בDhh(#'O:,ڵK!7="+V^u ҒL&e-}M9zh:c)Gw!|ᾷsNdvͷ0 VZ0Jy&ֱhd4YfAu 7Æ Sߑ n3gT{q Cvkٲe`TVV"u$E9 47(_iiiH%PA\.~:H$(+5O7 UEZD:ʲ!44y[,ws?򻰤XRd%ѣ!0`: c22X.o_!X"u$\\\eI7Ǐ#GݻX$ZUUUEEEi7O0{cAEHL Y-6tPX؈RmӉx<^MMX!::ZHL b֭j@ކ٩ݻu,{HP(/_:/Z`OHLI rCkhhAPGD.kll kװEV#%r>}u,jkkVBRtXx1A4ݻX"022@d R"_vv* Xǂ% tPpp0ֱȜZ3flژ]\\\[[ގj```mmhee%Z<uH$ҽ{F%Z' |'|ԩS!ׯ_nn.|rڟoGKK> gΜ ))~ׯ_F1eʔsR(d%((Hґ*SSSӯT$@82 뱎勐B %ZR:;;2_*Ξ=kmm ð#Gz=?|޽H VGGoP__/oHt?ڐW&&&2J(2_/:L&}}?sss+u$?.wh@ÇՀTmmmnݺ[n={Lɓ'K*$%Aˑ?;vp)SGE&O8Wo߮u$DM磌RD~x+Wa,# omllVXqͯdG* )5///䡦חB={V>|~XX_z=|> Q:"k6n0DassΝ; avqqٶm[BB›7o::: ޾}{֭;vp8}}[666~-VBߖ23gAIpU΍7TyAyy.A+VT o(,,CNAZZZt:}۶m('*++wܩp>|)&&y!e0MMM555%ÇT*uHXH@Ae޼y[|ׯ_>\UUu׮]"KwttݻF [`600 c˖-T*5++K?0 h4+6 Y ݠCuuu{͛4ݻw TVV6~xUUp<#_dRx,**JzClݺJ*It#L:x/EGGkJ䑇0 dy) \A|}}: spp8qTGw ŋ$ M6!\|IX0|yvlN8AR+**=ӧO!s玴_ ݈ 33D2/Hc~M67 dxÆ }3%A ݈Hќ3g4117~:aǏ]]]mAX% ݈e…t:2ҿ?DJO)--Ga޾}[mllfJۋ.^~u!:tԩS/^( ݾ}{l߾oĈònݺ%Z[Ňucsupp蛱FxK2w+ԓԇ&L&55Ẻ:a*N^UVV^lӧOX,100D֡_6mZyy \dff"ƣl!+D7m44Ǐ?>>>JeddnҤIE\E.'2fhhX\\pw#+W̞=ǣ3))L3k֬Xp8??+Wl޼YKmm-q Fmmmߏ+ݍ(;׫3O&MDӫ?ɓ'?NxT[[ZߏK:;;~\nDA:::ח#߿gX(;9r$ HYe@f!{BQ0 {@*xA~rJya(-ߗϞ= 9"H7 "zP(O+((8qD\\Mff&\.Dv\eoo~Ν4))ښNQO̅aaaB[[['M1Ns>8*5@`iivھnʔ)}3<w7h(_z :srr2J0raxƍ'N 7nlݺU/nDA Q^OR>|'ѱwFիWUTTW͛7jժURXCNz핼x񢊊J}}==== /|r]]\xp***Lh222x3g7ĦMh4ȇ+ '׬YiӦo^VVVV^^^VVV[[k``0p@nU^QQA&Ŏ]޽{׮]5j;pܹs%޹B:ɱPmm&iJӷo.@ ϗlIII$IJGq(nDޮ~ziB[ZZ=bz葤#H˖-T \t ǧIo -!Gww9sH$ѣGn޼YB)>n`090`Yѹr0 7C!taeff۫_B/u --ɓ'KJ[[ԩSUUUO>-ٞ٫W>|haa:dȐ%K -Q̜9s:) ccc'''hjjruu522zzzzH$RSS@ :t(AF:p@^^^+222vakk A+8\4EdTTTxyyA[QQ7@>8EϟuŏX?|0::֭[555$i CMM緵UTTxNqttTJ'NLLLF0dff9qDcgϦ9;;c 4P>~~~XHxRF'N{nttt`` ֱNՁQ %ehhXWW+ cȑ#333srr찎{CI={ Ǐ9`˧믧OYnRi9##Xf X ;•Egg˗lԩppphll:@ÔRۻwo޼u,oٳXSʎ3La$/_2dȰarss1 n͛7ֺu644lhhQ {ׯx#L0  ۷ok7l Hk@`3?2L/:;;ggg755(O.KҧO9sL&s8GGxLKJJJesss`` L޻woMMBSSS D"߿H$___L0qtt466 44433kux<^JJJWW~cZ; 6S7drMM w-**^B籷={VTlE0Y`u~C*(r]\\ Ϗ H+ccc cٲe555T*USe߾}d2߿obb@f ,HPDGGc45\.秤h,s7`AΝkiiyS3]\\|J 6S@=H뛟a퍒t޽n@mL&CTAU7`1orJo!XgzzZ* K n<^GX̅zoʆ^% gڵ -^sor9R駟/^w\rԨQJ i@wﶶD555bX򂖖sM4? a٨@/7,==lĈڤ|c@P7/p544>!  :dllt=dL(͠=zos8y g+Wfdd,^X~ fs)))f`fffv…Kfff)#W7koo={Q.\`hh(Ǒ7mtС .̟?_@P7!<<<_>rH.Hrss-,,;8u֭[ن ES@X>ݻw+k0 >zSRR4W7---UuǶmێ;VWWЉ ݽ{~h%l߾oQD ɓ'R_$%%%͞={̘1NNN[ly1bG}_#/$9CB1bD|| NOOp˜1c>}*Y,aW^jd7DR~0l^0lڵO:y;vN4iرR]o=rcǎI9Gaa@JP7y󦋋o222|"B7o@ (((r2H4oX,<|p``׭1 +))rx<ߴHðS᯴H9~q$ ;L,IǏ?:^7Rc``o(c^ w?' ?:*8 ?{]]ݞ)?zh|s#1Bq\.azzz2n~3f̘&M'Oٳɓ+Wdds/aر<O#ڵJ={vǗ)&u3;w5j…]]]rP,رCCC#%%E.;i$|qו+W8ru3wZZZN0Ν;OKK+--MN':4}t| wwLM@ݼTkkE?s>?A~'sssKKׯ;??aٳ?x5W񆆆VVV }}}0;;{޼y!!!)ə3gutt3f̀-kmm 722ϝ;~;lmm);S^^hR'O޻wo?\@\|yAAH$=zP(| ~իkB]v-666//K%>-[@9nd`mm-jjj_^YYY__ɓ~*jlllmm4k,333I_d^pB7۶mƨUu#-cddraYL&۱clFZQQQ Z߀VSS駟=nj;DDDg P7Ҳp8NRR~?J9 PgQo߾'NJ$##EرCxԍTLfDD|~||ѣG߿/tm6|@Heĉ---nBaRRґ#G*++E"ٳ7o޼d9@ݼP(=y$,DzС--3g|Q[^bbX,޶m jժ7nٳgߺu>h ȑ# \ݼs]]􇈫_zJ:99Z*44@ݼ%KΞ=:9P(+WR uW_Ν: TTT޽;77 _*bŊp|n^`TUUBb555w>|{{&&&y ~ATGbbbΜ9܌aOTTJ /_^ԩSB0,, uaiiW_555kkk'%%YYYX,b̟ͫ?u5RiӦU <ǎƗJ[nn^*;;[ tuuwq޽x;; -Z(++ u@ puR/@DMGy @ KM<u:u@SSsׯ_j\@6p35"~zAo|}} ݫV^_ BTfp? T"//K%s1A ֶu111Tfj\.wڵכ6mZzzzggguuUzzze f'OĿDȌf޽;33_*affK%Ĉ#LMM߿:ݻw>}0o)z F ט1clvWWWddcGxm\<?b`` %%e?uꀪ nb6ПJhiӦR sssMMMxlΝ;wk׮x<*:y5k֬_&C[[[ssQ-]ҥK}}}yyyjkk7lؠ=qD&Q$+CXX؁`n𜒒؋/K%lllan`mm-ZZZPu=&с;}QFFp3;: ';v>$$߾}&&&1l \.***::VK%222ޑ8N[[ {ĉzDbll1eш7|>_OO/((CޠK%v1k, Ɍ#,@uT|֭[=<׍. _*1fwBCC8@``AnnLKKڰas{hjjzxxNklڴѣG^v#]ƍ,--;wE òP@ZO<پ};c~HQ@@۷6_yyOPN>yiiiNP| Gܹw^Ņܲeqcc#j6(,,D{nܹsn[oSdΜ9t:ŋ6000sLӧOc_VVa騃 "СC3fTY`AFFƠo>y򤦦ُ{uxA@~ J$)S0d% .\P߫]]]WWW)PLwwwHXMMӧ:tŋ b:ZMMϩ]rwUM_~0,%%uҥK^^^㝝aaa4 ð:tX*Je([o?s7n<ÇΝ+H&M4{L5<''')@@WWtSeee\\&]xTr.vZA@͛ߏb8\\\ ~zA@b5rAԱnrssgZZZndiivubQ|K%300Pa2 %,, uY)Rl'NQU7l6=00u3f ̛իnvލaXxx8 coo_]]Iԫn233 Q3fttt444(sҊ HFuܼ|rA@it:=//O^|yܸqjT7L&ðA@ ߟ9Wi222hkkk@҂:9skhh033>liicǎ}7Ǝ;ӦMqㆺ 122 9|0, & mmmcccyooh4--~>-..Vn"##1 khh@BHHHkjjRDUUU?mjggpP&Orq"H.\(b>ÿo@4-9997ˁnܸ7"]vaM }} E G㟽7S'NliiDbDK.}vaa᳓9墼wMMM}L jA *?̟?Ν;h…,u(mۆ:D3m4777x𠵵sYf)S44NFnN:痕 +KKKX$1UjiiA e˖wXUb:oLcu-BCCQ|N8abbbnn.aUn455Pdx<^}}GVٺ)**>}:ρrY5릨_uѣvvvrY5&66JZ uHF TWW{zz*bpլ<''') g{{˝ Myy9]v- Ojjɓ1 MLL B/nX,Rܺ\NJJX,}ϨZݰX`A $==Yf)h|U&IPP|7Mvv LZZPa큁@> =DftT˕*t L+++CCCA s 7*tթ˗mjjjbb:$SPP֭[Tn8NCC ޽{͞={0 Br劂d>GE&==uH֭[\.w͚5JK?|x`LrvPPH$[ t҄ *ͱcnjQdX,VwwvP }j.@UEGGS( 6(g:MbbX,޶m ONNvP }9rNɰ쎎+V(mF͝;w.\:k. 6oެ]7"HΞ=kmm]7sEi???eNJ)++` ԩSBvA`222̔ZZZvYuww766.[Ln Oll,a_Cֺ@>'N011177Wd8MM̀A W__Z7EEEJZsDdWoRMQQSG)jRMllrV@jOOO$n򜜜P|$Idd$W7\.wڵ@>E䫛 _ +X\UU*&77A9[JRRRb1]IV7,Ki[Jf͚*dR(X ! @ζQ֪4Pv/:2 noo DIHHF{f (<<uȧm2Mff2V@5;wN lܸm M[[[ssQ|8ՐcggG^7G...@2l6cŊusΝ Nڵ ð͛7BMjjH$B!$uYkkkB@ILL՝;w. L2ߋhnN:% at ##̌h;(n<kUwwwccePyq릸`NbFu?l@:s sssAGк @xި uSTTDU H$bMĺ)**x١r9z bdkUE TWW{zz28"M^^OBBD"Ddpr.vZA Tl"MLL B/nX,rwwGW7ZIII|b "֪HRRެYPy)b ɤP(,!(++sssCUU7666ZHKK ߋ@ufQ| ~f (<<uȧu PdffZYYjkUHܹs`ƍQꦭy娃@>hQdbFeܵkHQӦDZ+((x֭CQ7ug޽dAug âP|\B5!DݤXZZܺuYu>C8!`2dA}I$"/c.]4a저n;fll:$bI _1EGGS( 6"-u(vp:cggG͑#Gt Xb 2@\7wYp! Ѯ]0 ۼy3 2@Y7"@LgϞ& (&11QWWwܹ3@F:lPMYYt CEGXͩSB!dddndusA---X-[:̐Mqq1@5;al@dvHĉ&&&樃 Mijj xި )**"֪́$ IwFP7EEE<,;t@(G566Cd(Mll,YVPAuu' Cn򜜜?/d H"##Q"eMyy9]v@e#)nbbb( |qbqUU; Cupp ֪GJJX,&}(nX,VWWV8f͚:)nL&Be AYYâԺζ!֪DZZP($^tʫ6P d?DyuoP%%%S &33ʊ\[@Ν7nDdT7mmm˗/Wth4___AKIud21 #2Vкvj젠9})Vn:A@up|||0*f޽*2fϞ=EEE)a.T̕+WȻ&9ʨtKKK%*u]f >^&2;(gevKKK}}}GGϧRƖT*5..N"z+\ti„ *9997nhmm_a3gμw2X,Vww*=>2@33p]]ݝ;w~PUQQ8cƌoc|> c+V@D$P~z*%Socƌ:u*8 úQ'D"yu _|9==k;<~8//~zLMMutt~WA57Sdʕyyyr -Z,1P%:n;w.++kƌrN;wnK,xrEm6AU7S/^<~jiiqvv~w> )KKKXԄ:ꦯ{PP;vlrrrRRRaat-[:nbcc\:ҥK}}}7noP亟o>_NP[[;a„~0[[۞6Ao5SɚRn Û7oX:nee>a)۷W__ih#GI3ڵk׭[0bĈt''?_)u]vbɒtDJ2'oܸ!哂 ,8y䳿K.DrXlaa-PUƨS( W7W\111 -###/)G}3* eɒ%/_$@P]]: R7ׯ_wuuP(RqY++?bjjaد*s̹y&PYBBD"DDQ;wL8q8l Ə!'r\[!LRSS Tf# RMMMg̙Q@JbunF9Asrr455e:k8@^)))bX%{fDي￿zjDDLnjRTg! %%%͚5 untttJ}֭/;|?-- ٕNXͨQ Nӧ={FY|QF a^.--M(nݺunllljkkeex:|jY? HHH@Dgg犊 F;w˿ۡ}SQQaii9̯ %Af޼yRQ^^oFFF?rK.͝;wΝ;'d%ـkk?3fL07|SLy ===#G +Vزe, HlѢEut%4k.^O8! ɺϾ*޼ys{{K ]]]:2 VvvǏzIII3~}7+LfffǏc-[affq 7|3%%EUAKH,;;;J(SNQ^M,,,&&&WUB$ۛJN$/=E3++B)tq{:;;###Fnllpm@9t3JC{}s\MڤysOO_|oa``su@JKK1 GDI^U7>s BNR:u*Dž E@DI^U7PKKkrHOOo۶mD$%''jkkϛ7/##C~1P ##I&N<D?Ras b<~ȓF1y ݿðAu#HNCP8^Ԝ>}_+WR(:HU7]رc <Ǐ555L^^^N0LCCcҤI111j]@dFGBc___ }/ ]&{ay󦯯~ꃽΝ;9c -Ν;QQ*3}t [ovvvB}/ܽ{wʕ֝[[[?ya$BBBӱQQ1V~~CSNuvv=zP(|鯿zݒvڕ+WJy,޽ٳ^RȱcǢԂ=2ĺqܢvttSTcccssɓ'ϙ3g…r,O?hll0lK,E ,͛7ݻuVݨOƞ,Q뽽QAn/((И0aի?8dFDDh(&LNAЀw޽;++ӧR۷1u4@ OOOG ݽ{˗/߾};,PO }ɓQgAFsi|Ę1c###Ǎ:Pggr8AQ'Oٳɓڼ#GzzzFDDR 'i4ٳgQgA |ehhcрB9rg͚: 2P7 /2%%bX__ ,@ sNoo/ (AT"))R$̞=;,,lҥ9h.\@%x(444ܺuK(?~|ڴiEEE>>>sIKKC ]ZZP(ܺu+ ;w...|>_SSsʔ)!!!}~ s疖|A!ܸ^*:q?J6(,,D1IrrW^]t)޲eg}ׇ: x)|K7\ݐUeeeLLLnnӧO)?, E AЃ!]v*R;v~7eʔ7nLݷ~*Hǎkjjf x<޺uP!QAR~#GzyyEFF:::v.]- Q!UK%300+//GfJJXZZ9sfƌK,e֭[\.w͚5\ݨPtȑ?/ؼy%KPGSA~~~gΜDnױc*1spXܹsu)*1{[nJ̜9N>: CNN^GRVZJPG#ǏBP7`EEE=== aʕaaazzzɈ#jjjP!;wٳg9NyykkkTTNݱcGWWDf;::VX: ʃL~~~&&&?񏤤nCCCYѣG111gΜinn0'**u41557W_}deeebbbPDP!pw |ѢEyDXX؁N9P7@n|~||ѣGS%tou磎Tb u) 7:::w^`ޢEPTe˖BDpuH,=zСCeeeR :DEEEGG766B8P7@IN:_JL>=$$d*vmOO"x P6|DQQ×J]vdY6[WWӃhcjjjggWZߢIDP7|D^^ŗJpH$|ݻ_P(Iӯ^ZSScoo:2AS%(ʸqVXNGrĖx3g?\__ðfURRO?ݽ{:44tݺu¨^zU,,,6mֆ$MLL>S6-ͧ"##G9jԨ/R(*>)i@"jhh 533{4$$Ai޽쬯+ǻwܩ`0|n=~xӦMVVVxX,NzySSS3k,##l#1@]]]^YY'JIIR׿D"G hHGnP7dv5a:s5 ~q gg}yYK:P7NGnny󦖖VTT\cnӦMzzz,p@zRIJ2P/ظqL:uڴiNRPHooﺺr݃u O0FH[XXtuu).[[[ۨQnݪ),]]]ߩS ۷okhhddd(:UJJ F7RCp3T\~~\r544[*|򶶶"E'55Us P%%%/^ėJ۟?뵃WVV 333GGG///ח744D2P7@ܻw/&&&;;?U'z^-999$$d#F{njjرcO>=}tifزe֭[!ws 믿hiiKofҥ~Y[[ )Y~==/F?K.#+˖-344dݓroon# PkT*UC#^ —?~XA̙#n޼)cX҃jjܸqC#ZZZ0 ?~166633$uڣGxpι+V7NOjx2 9v@AF)x<^rrrGGǭ[*++#"">SF9rdWW Pk"F)PXYYY__ojjJu^nZ5j0τb09 SrKFP7@7n̚5 _$!3uuu666ÜtnZsvv~8ׯ_EH# Y5--_~EG/>w]7??7o<|ݓ4tuu JWW_|AR )9s… be +VlܸHshʕ+SSSLbdd믿:u~?4ӵ?~\I6ZZZFEEm޼op8l6f,X@w>Ӥ$6pVncsܸq -[DhEOe``+z"b366-))Q,Kbb}wNUUUqq1|=~x̙nnnr,n]WW1bĥKtGvww0P# L;ccƷ~[Ctttxxxtww5P7oQPP4gΜXUU`0eڡB%A7n011qqqbDd0vvv7nܰwRB}D$ ?3--iӦ2}V,>}IGGgbXa1InJ}];;;ooo''}544S111~~~ӦMcXaaajk/SҞ>}:~xǛFu֭:+W~jkA PxƍҚ֞|#QSSS3g.XUCnuPa@$P7%(ܮ 㥑WtIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/square_isomap_386_golden.png000066400000000000000000000227231450372207100274010ustar00rootroot00000000000000PNG  IHDRzz%IDATxw\wYXqAJl(1TlɥIKrQ(ƆFsQ"$C"Kg}^Ƀf-S￞f~߽ٝd2` ?x`BB•+W444422rƌ|>_  .\_>}Z(zH$yyyy]]K/4r۷bM/nHo6;vXGG+**֬Ychh윜ec 7зlWWWkkCIRF&bʕ*X#0 @oGzg80lذ rI@5/oyA iӦ]rvҤIJZ#0nON>={ 6]VVWWO>?l۶ݻSQk \fի=z)pvsrrzcccU:X,>}U:n Om oz"==>(.. o_:dlhh:*22r׮]r.ٳ555111H$qqq6mk:%K˿R`6q 9|XXb3FDD)v80r?J}Ç+6UFFbC!7\WWWWTT4n8xzzc` pwwWnnn'Bn<VpAnP[[[577yR,%' 7\ghhܬ߲ :T͓f!7\gee%H>|y+**<)hrunnn]OSAA'BnbĈj7;;_͓f!7@L<955U3WVVN4I!7@̜9~Qیǎ3ff:㵀hkkz-*ٳرc<(++DC qtt/<\*͝;?W1{ww&r矨.x:99)X`* [lYjJ'3fرcg7;oׯWmVRR't'Z[[G흘)n߾=nܸ?x* Ǯ]G)ڠ gϪ2@g|M/hϞ=QQQVVVK.Uȍ=T*OLLLd2ٲe˶nݪ1'Mt֭ve c'O={֭[W^:1\޽{JZ/0 ~Ggii ӭRSS)66V[[{Μ9"H&rvvPn I(FFFA}[Z[[[XX۷P.Cnt| ~ڵ> .400055zp: "##'믿۷/!!TOOܜ練TWWUTT?>y9L\\ʕ+||= QlMweeeYYYkeee}}D"~~~ pr] FPbŊ]vݽ{ߎsrEth s Э5$#gkH( 7\A֐PCn8!8ܰSZCBqX a9frfLl a%䆵> ;15$ebGkH( 7læ֐P@nX}!8ܰ[[CBqXa v0r\h a4\xV1:uj֬Y 3r`O 377/**໷QSq5b"䆑, 5ݡ8 0 Z 5O0rhMPCnš9P:CnC[ 5Aq /f0PBnh ⸹kz9hZD~uuu5NCnhQ{.]8\L Z 111{)--uwwU!74֨C ]5hrC hz8hZN(!7֨)ȍ&5hr1hf8hZC(!7Nȍ5t rVh =8ܨZCg( 7jjȍ:5Lrrh 8ܨZD( 7*0 ȍ5L(rh ;8ʅ(Z&(!7Jְ,ȍ25l(r4h 8(Z( -Jp̙3f5wr* iӦ5(SBԴ\U)Q\Wk4P+Gȍ@q(#Fnh tPP95$( Uh rC ZT8Cnu(N?5 /I5O50(NoM<h ( rZʅtAnU@qHch <ր8 րp8 Zjp=7h gܠ5),wsրfq8 Ztp17h ù5@C1bDAA̭ܠ5@[K,+**bkq8t1EEE߿ŅWU\ Zp"7h 0ܠ5,,.s8l Z67h 0ܠ5,+ s8l ZÚ*7h ;ÞL5bL]Krjll\\\18ljMaa!Z*{k sܠ5M -s18L Z027h Ya^nT)aRn'aDq/3rPA0 7h ut.sȋšunг8 Z04,Ms ݊Cܠ5B.7h rѧ8 Z 4)r3Gddd\t)77D(ikkM4v5.]ȸvZAAAUUUSSAFFF666'N7n6wu X=z#GZZZ2999́111 .2dH5jC8no9R__1vXwwÇdׯYZZ.X^9rs?3ݻW(sGGGZZҥK ,--mc4mmm33e9pdz=tΝٳg1z_URRi&777mm~v#7B022 \d?ի]];wNѤRibbСCl"J܍jn윜]Gw:::[lAk4{q***wX cӦM$%%ϙ3Autc>?}t---@X[[޽{wc޸qӳǟMRR뭷n^ozhƍ| r2A9ro 7zzzo%##C__?T@ѣGCBBZZZ;rMM_sssrѣÇϝ;W5?xIII'JCCCe˭/^ܵDDD9QK!T_޸qCuSx?>17gϞ%oSRd2YSS+YGlذAX޾ţd2τ sD"ƍ_{5TTTTUUuvvPNĺu_ZZMxxԩS|>@ pttԩS#""MRRs;wqȑ-xO=L>}ѢEňD"mmm۷o{8Ȯ]x/gddDlA ][lllFuk׮Qgpŝ@aW\JǏYVZ}5Awܡ8ĉMNNΘ1c(RUUefffnn}{pp0Y.R`bbBq#FH>gҒ nnn}䦸Ņ(A >v nܸAqrƻwRSRR2s/466=ݝ!ZZZNNN}|% GÇA~L1AVB!@1rB( ^n://#GhisKK>r6tPCTWWc;OCCq`i=8F^|ȥӳ͙3'66VJ'mmNCH$=wttGqrnPwojjjkk>|x``K/D~CD"ȈEAbv g(TO-FM>t|Ν[nxlmmmg7eee sSWWc;@@qr9rۗr@>r3jԨ~So/**:OKK+..:%%ͭyyyg{w~ꩧ~Cϛ7|8 aÆmݺl޼yӦM}CMd2w}gϞ{{I&];/.((t`0ܹ啞>eʔw>~ʄBҥKɷRqСKVTT#F|o]s]C5>}X,NOOWD788o}Cׯ_/D"4͛7W"z"rU'c{n==Udoo|r.At-::QZyuߋ_RSSy<XYYQ(Q]]\Kgg)S|||b1eh:իJ_JssqFEtutt>U ꫯuyH$p@u477O2ȨToNĶm۔;lll,ONNqܐOB5k>aya@@Al! x<￯se˖u1ܹ`ff x)冴{nQF) 7uЈ!ܼygKKDk=޽ɑ2A]8K.DqIRSSakkkG8qΝ;:RT$ݺuk֬!e˖eV$7z٦|>аgV:::AAA֭p4@ lM3gμ]@x_cǾ.\s߿WYYݻwBX,655>|;gvԩ˗ ~ICMMkCCٳgzKKKKqqqUUUSSȑ#{eAqTD(Q'OΜ9s+VZ؃]nPIk@P ZAqnunPѰ5t zAqB0#7(Etn cr aRnP~п5 'FyAqz`Jk Zܠ8k s15 0>7(pC[Æܠ8)m KrG05 ְ*7( Zöܠ8Jh s˰5 ְ67(Zܠ8hk sC5 p"7(0[Õܠ8n rͱ5Ad2נVaaaN޻w.[g7'OΚ5k߾}111^ p17A8q"<<:Nk8 Q8NAq@N `k4AnԌAnzp5c([  7=8 h Bk 7}@q@YК80xhM80hMoMPP Z'f( yf`(P*К!7T8?f@ȍPx F>(P ŁE8@Bk(F^ȍP.Ck Mhb8pUxquqqOMMEk䂳%9wչק5BnႺ:H /hz9̃( nh!7ʄZȍ8( r|(5Jܨhr!70Ztȍ 8̅֨rZ(5*ܨ,h 70ZRȍ8֨r>(5jܨCOhz 7 Z6ȍ8֨r(5jh Yh!7h Zȍ8h ry(:5hf!7tZq 8rC/(*54Ekz-n(11qΜ9Z 䆦?>w\g0Anѣ(Bnh Q ZCO ݡ8Bkh a:ΐf@q@kha h !7L< Z à85L0Z #8$YBqAnAka6na(V6NqFCnX AkavaUZa_q@nXMAka'va䆵^}6cnqVBnXAk a?fa1RݐqCn8AkzsV;.OqNAn8Ak=z4""AS?P*޻wO$I$}}}@daaA}N8 /_njj"7jiiIR0aԩS_|E~Bk8J7w\ -Z_Rǃ {W8p5P(Hd2X,w!C/^8//kkk͵Ξ=f@/ )NFFرc###/^(J~~~ZZZ/~a5\zW^!"<<@\]]̎9BnAk8ǺSQQgaa4[[[W^y睚x'EDD;vɓ399yD,9s srRYY{CCCe {)Sx~]]]Giii[QAnN___*+vxbb?_uX,pru jp¢Evk{luu595pruNNNr}%%%_ܻw!gtvvV@`.,,,lmmsss:K,IJJ7ob޸qc̘1 1anݶmۺuΟ??qDfljj Qp`(ESZ`w[o|w'P199Y&M|bŊ7hczxx$%%h 3|_$''h˗D;wh|9|EFF^z_NKK Tk׮=vعs笭;20nO⋰Prڵ7nW@`DKK+>>~ƌ??`KK… lr+cT|C<<0IPjjj֭['|}}?H@TqFKKKD=/X]~ȑ#*JJKKCBB!k׮ew;v,88xݻww:uTppO8!uF`ܻ>/['Nfk!3gμ|rEEŔ)StF`%}=|PsHcc[oEӨ;wfff޿}&L?GXX֭[v`IJJ*// sYY֭["""lR\\;МtʕQQQ[5nY&77ܹstv.((xgݻײn>Kg[n1"++ۻ  g_ogϞ'O& !dᎎiii/X cѱW 5G 7|C4hPw%=!^^^Kw&AnÇo߾ "HY8 7|W]]mii) !>>^&ZJVVV555ZO lZ[WWo?""BëҲFVk+Tkkkի3{=zűgϞ>|JRGGG-& yyyQO9;;?JRiiiDysss===8 g7|קO_~! AAAw駟k !cƌX`)ԩSiP(fϞ- lmm1''dʔ),) sYtiyy9[.55׷O{Ew Ǐ۷ȑ#]2rdܹ~ܹz U?Q?eJ\|yw>6/Wntttnni{~ FGG/Y$//]+!7@2xxxDDDkziȑFnxW_l٢7ڵ?,L8Ս1'66VOSdee;v֭6ld ի|n_IwuuMJJ߻ea̘1vtt >JOllljUvܩ1ʦLr톆] N81|;wnذ!$$c^|yܸq߿?hР&F ~A 888TUUT'''//dT(Bp…r\Vݻب 7nL& "jΝNNN}􉌌l'ϐ5-ӟ{9BW644t8L&Yl_8_ӧO|++?GFF 8^$֖KRSSӉ'i۷oڵ999"> h⌌ɓ'bϏ#AQBnK7 {{.> 䆏 + 05?~aZk((O 7@nɭ8[CAq >prqj * I g5{nb{k(( 7čPP.AnK8p ZCAqprn a;  j 5bvKHH7oX,.((CkZ9lܰɓ'Νkoowo8)ykpUF +5]AkZCqXa=-6Aka5КΡ8̇ܰZCp 58L0Z)FCk0r\hMw8 0Z}-jhh0r?d$FիW5q;x`XXctbFBCC8PTT4h \Ur h8L0Zo(!7c\ȍ5rcdh8ƂZc,(Q 7Fcxȍq5Lrch s8Z4( 70cȍ5Lrc h 8Z(^!7zְ ?ȍ~5l rGh {8 Zv(!7zp[ȍ5\rch 8ZU(N 7:p}ȍn5|tޢO={6Zx'֐JNN9s]AAZ(vp1-TklmmUv&??Bqh GSȍ68An4@k(}ȍfhš ZOЁЅ@P.!75@9kh ЇtZBq ZAq:<Z݁ⴇt Cq@n:ր8!7m5[(N OAq?5o(rC0Ak\mqxon0.Ak V>Uqx^СC!!![+**jʕ...\-.`௿Z*8WU| Z"7h ܠ5..sq8\ Zp67h ܠ5 +sp8\ ZÙp*7h p7ÝL5al]Grhmm]PP8\jiM^^Z*ukzm{ܠ5O,-s8l Z27h ]a_nXTh-aSnaEqXs/;r 7h }L.shatn08 Z ,Cstӊܠ5¨0.7h n18 Z )rӭG֦]x133P& B[[[D2l0)S۷ˡ /^LKKzjnnniiB XYY9;;!dĈKJJ:pǎ^^^B0885ȍL& ",X 33j߷rJv(a˖-ƍ;sFTX^zEDDTw wwwMњT*]`iDDZ`\#JǏommŢK̙3+**@+7qqq .n}"h֬Y&&&h Qqrrrqq>|ݻw?͛7܆ "JʼnD~[浗lo.&M JiiΩT@//t߽{VXѲ,ZhX 7Ÿ0/G7o))) &&OMRRu>-EV+ WWW^yE@?ٶm'ZfD",7G^xV;Hg~ L&Μ95d_~AAAX,D4RÆ 4iҗ_~I.К\.wqqپ}믿NTZZZԷo_ggg !7o믋:>Y`3޽{fͲ>}X,vssKHH},,,t9t?iQ'{{{{P=~޽{؄+ =|P$t\ޣGoX>>>4cƌ=zɓ'=zohJsݻw34!!! 3Θ1cѢE&..Ԕƞ={!Gm@0zh5kڑBݻ{6#BHii)Akgg.\keeE믿&<-[zڵWgi Z|J8q"͛kbccDsA&O\YYAnnܸ1rHfdd۷>~x\4w^EE@;6664߿KshennAn HsBH~lӧ!͛4ǡf{.@;]?S.\1bĠAhbbbY2~=zDi>kkkBjFLFsЎF[P dW\ټyѣGML4xعCի!!mS~hCzC#RtȐ!555`…})Dq MMM42f{cc#!̌8nH$ ƍ{;84577wpvceeE"ёT*lk?5#W[[[Z1z={\]]wI؊n$Iqq1!TVVNF,-g-DRTTA,YBHQQQ:t/BsWWW )|NGvv@;Æ ˣnwhpnѣn/]Ds^z-\!++e#>@'##˱@kJTڷ9HFFF=:ԩSʮ]Fs QQQ-[N:U^^Bb*11q4wI$DWWW_~ƃB 'O;vlǿrL0Yf)T}O<|WO}x-[b\.}ŋ>Y@+WvbB!HV^ץ0t~2551jee.rܼ`XuL6ʪHvMٵkn D7vIͳG7‚{C Lfgg'LLL{=[TZ̬- u vZPm۶,%99ۻpΜ9(P )))zzݻם1ܹ3n8;;_K+7[XX :4%%Eu/]R_jPhj˭[ fiiVrM&L@}ݞh"BH@@rùs׮] 3332dӧ0444|֎۶mynkkwN4 ի-DAAA|r_Hegg;vlݺu^^^#G>|QyZkZo۶I ?>s J%o߾qF-nnn]~ʬMn(_|mmmo+D"KK˖Yo޼]@ix7xǧkjj:jԨ41w)M߽{W&)JPhkkۯ_AV1!dܹ W޷o_m{zzVUU%%%iڂRBabbbaa<`Z+FWP=Ѻ5:kb ĉsٿ5k`Bk@&!洆AqtQannPnbZk@k l shaAnP05 @[Úܠ8]bxkؔo rta_nP6Vhְ57(Zܠ8sk so5 FߐAq 1ƠPfBk 14iAnaƐ@q10hPBk 1&X@n 1qqqnÆ w)//GkxNkrE?~ĉc&&&.YYT>}y ?)))2dO>miia/]4m4??T@a]5?C}}ܹs=<>~޼yeҥYYY B}s̘1D23<<|ƍzS؛7oرC7n߾Js 7𫈈ŋ{zzjz \kB"##5 NU%KL8~@++˗}훙iyo޼9rHO ƅ4iP(nܸ`I 3fHJJ1،jzԩ"˝Lgk׮]pÇ.]:{ /A:KgD^; rZr[_NgͧO999C IHH5kVBnP6lXLL=ҥKnܸ7 r[rezz['ԆݣG f͚۷iQF <8..NOS)O>$11QOS^Z.ٳGOÉ`+W)))~~~|ӦMǏ?s挓nG '|2w@ݾrӦM۷o_  .\_>}Z(zH$yyyy]]K/4r۷bM/nHo6;vXGG+**֬Ychh윜ec 7зlWWWkkCIRF&bʕ*X#0 @oGzg80lذ rI@5/oyA iӦ]rvҤIJZ#0nON>={ 6]VVWWO>?l۶ݻSQk \fի=z)pvsrrzcccU:X,>}U:n Om oz"==>(.. o_:dlhh:*22r׮]r.ٳ555111H$qqq6mk:%K˿R`6q 9|XXb3FDD)v80r?J}Ç+6UFFbC!7\WWWWTT4n8xzzc` pwwWnnn'Bn<VpAnP[[[577yR,%' 7\ghhܬ߲ :T͓f!7\gee%H>|y+**<)hrunnn]OSAA'BnbĈj7;;_͓f!7@L<955U3WVVN4I!7@̜9~Qیǎ3ff:㵀hkkz-*ٳرc<(++DC qtt/<\*͝;?W1{ww&r矨.x:99)X`* [lYjJ'3fرcg7;oׯWmVRR't'Z[[G흘)n߾=nܸ?x* Ǯ]G)ڠ gϪ2@g|M/hϞ=QQQVVVK.Uȍ=T*OLLLd2ٲe˶nݪ1'Mt֭ve c'O={֭[W^:1\޽{JZ/0 ~Ggii ӭRSS)66V[[{Μ9"H&rvvPn I(FFFA}[Z[[[XX۷P.Cnt| ~ڵ> .400055zp: "##'믿۷/!!TOOܜ練TWWUTT?>y9L\\ʕ+||= QlMweeeYYYkeee}}D"~~~ pr] FPbŊ]vݽ{ߎsrEth s Э5$#gkH( 7\A֐PCn8!8ܰSZCBqX a9frfLl a%䆵> ;15$ebGkH( 7læ֐P@nX}!8ܰ[[CBqXa v0r\h a4\xV1:uj֬Y 3r`O 377/**໷QSq5b"䆑, 5ݡ8 0 Z 5O0rhMPCnš9P:CnC[ 5Aq /f0PBnh ⸹kz9hZD~uuu5NCnhQ{.]8\L Z 111{)--uwwU!74֨C ]5hrC hz8hZN(!7֨)ȍ&5hr1hf8hZC(!7Nȍ5t rVh =8ܨZCg( 7jjȍ:5Lrrh 8ܨZD( 7*0 ȍ5L(rh ;8ʅ(Z&(!7Jְ,ȍ25l(r4h 8(Z( -Jp̙3f5wr* iӦ5(SBԴ\U)Q\Wk4P+Gȍ@q(#Fnh tPP95$( Uh rC ZT8Cnu(N?5 /I5O50(NoM<h ( rZʅtAnU@qHch <ր8 րp8 Zjp=7h gܠ5),wsրfq8 Ztp17h ù5@C1bDAA̭ܠ5@[K,+**bkq8t1EEE߿ŅWU\ Zp"7h 0ܠ5,,.s8l Z67h 0ܠ5,+ s8l ZÚ*7h ;ÞL5bL]Krjll\\\18ljMaa!Z*{k sܠ5M -s18L Z027h Ya^nT)aRn'aDq/3rPA0 7h ut.sȋšunг8 Z04,Ms ݊Cܠ5B.7h rѧ8 Z 4)r3Gddd\t)77D(ikkM4v5.]ȸvZAAAUUUSSAFFF666'N7n6wu X=z#GZZZ2999́111 .2dH5jC8no9R__1vXwwÇdׯYZZ.X^9rs?3ݻW(sGGGZZҥK ,--mc4mmm33e9pdz=tΝٳg1z_URRi&777mm~v#7B022 \d?ի]];wNѤRibbСCl"J܍jn윜]Gw:::[lAk4{q***wX cӦM$%%ϙ3Autc>?}t---@X[[޽{wc޸qӳǟMRR뭷n^ozhƍ| r2A9ro 7zzzo%##C__?T@ѣGCBBZZZ;rMM_sssrѣÇϝ;W5?xIII'JCCCe˭/^ܵDDD9QK!T_޸qCuSx?>17gϞ%oSRd2YSS+YGlذAX޾ţd2τ sD"ƍ_{5TTTTUUuvvPNĺu_ZZMxxԩS|>@ pttԩS#""MRRs;wqȑ-xO=L>}ѢEňD"mmm۷o{8Ȯ]x/gddDlA ][lllFuk׮Qgpŝ@aW\JǏYVZ}5Awܡ8ĉMNNΘ1c(RUUefffnn}{pp0Y.R`bbBq#FH>gҒ nnn}䦸Ņ(A >v nܸAqrƻwRSRR2s/466=ݝ!ZZZNNN}|% GÇA~L1AVB!@1rB( ^n://#GhisKK>r6tPCTWWc;OCCq`i=8F^|ȥӳ͙3'66VJ'mmNCH$=wttGqrnPwojjjkk>|x``K/D~CD"ȈEAbv g(TO-FM>t|Ν[nxlmmmg7eee sSWWc;@@qr9rۗr@>r3jԨ~So/**:OKK+..:%%ͭyyyg{w~ꩧ~Cϛ7|8 aÆmݺl޼yӦM}CMd2w}gϞ{{I&];/.((t`0ܹ啞>eʔw>~ʄBҥKɷRqСKVTT#F|o]s]C5>}X,NOOWD788o}Cׯ_/D"4͛7W"z"rU'c{n==Udoo|r.At-::QZyuߋ_RSSy<XYYQ(Q]]\Kgg)S|||b1eh:իJ_JssqFEtutt>U ꫯuyH$p@u477O2ȨToNĶm۔;lll,ONNqܐOB5k>aya@@Al! x<￯se˖u1ܹ`ff x)冴{nQF) 7uЈ!ܼygKKDk=޽ɑ2A]8K.DqIRSSakkkG8qΝ;:RT$ݺuk֬!e˖eV$7z٦|>аgV:::AAA֭p4@ lM3gμ]@x_cǾ.\s߿WYYݻwBX,655>|;gvԩ˗ ~ICMMkCCٳgzKKKKqqqUUUSSȑ#{eAqTD(Q'OΜ9s+VZ؃]nPIk@P ZAqnunPѰ5t zAqB0#7(Etn cr aRnP~п5 'FyAqz`Jk Zܠ8k s15 0>7(pC[Æܠ8)m KrG05 ְ*7( Zöܠ8Jh s˰5 ְ67(Zܠ8hk sC5 p"7(0[Õܠ8n rͱ5Ad2נVaaaN޻w.[g7'OΚ5k߾}111^ p17A8q"<<:Nk8 Q8NAq@N `k4AnԌAnzp5c([  7=8 h Bk 7}@q@YК80xhM80hMoMPP Z'f( yf`(P*К!7T8?f@ȍPx F>(P ŁE8@Bk(F^ȍP.Ck Mhb8pUxquqqOMMEk䂳%9wչק5BnႺ:H /hz9̃( nh!7ʄZȍ8( r|(5Jܨhr!70Ztȍ 8̅֨rZ(5*ܨ,h 70ZRȍ8֨r>(5jܨCOhz 7 Z6ȍ8֨r(5jh Yh!7h Zȍ8h ry(:5hf!7tZq 8rC/(*54Ekz-n(11qΜ9Z 䆦?>w\g0Anѣ(Bnh Q ZCO ݡ8Bkh a:ΐf@q@kha h !7L< Z à85L0Z #8$YBqAnAka6na(V6NqFCnX AkavaUZa_q@nXMAka'va䆵^}6cnqVBnXAk a?fa1RݐqCn8AkzsV;.OqNAn8Ak=z4""AS?P*޻wO$I$}}}@daaA}N8 /_njj"7jiiIR0aԩS_|E~Bk8J7w\ -Z_Rǃ {W8p5P(Hd2X,w!C/^8//kkk͵Ξ=f@/ )NFFرc###/^(J~~~ZZZ/~a5\zW^!"<<@\]]̎9BnAk8ǺSQQgaa4[[[W^y睚x'EDD;vɓ399yD,9s srRYY{CCCe {)Sx~]]]Giii[QAnN___*+vxbb?_uX,pru jp¢Evk{luu595pruNNNr}%%%_ܻw!gtvvV@`.,,,lmmsss:K,IJJ7ob޸qc̘1 1anݶmۺuΟ??qDfljj Qp`(ESZ`w[o|w'P199Y&M|bŊ7hczxx$%%h 3|_$''h˗D;wh|9|EFF^z_NKK Tk׮=vعs笭;20nO⋰Prڵ7nW@`DKK+>>~ƌ??`KK… lr+cT|C<<0IPjjj֭['|}}?H@TqFKKKD=/X]~ȑ#*JJKKCBB!k׮ew;v,88xݻww:uTppO8!uF`ܻ>/['Nfk!3gμ|rEEŔ)StF`%}=|PsHcc[oEӨ;wfff޿}&L?GXX֭[v`IJJ*// sYY֭["""lR\\;МtʕQQQ[5nY&77ܹstv.((xgݻײn>Kg[n1"++ۻ  g_ogϞ'O& !dᎎiii/X cѱW 5G 7|C4hPw%=!^^^Kw&AnÇo߾ "HY8 7|W]]mii) !>>^&ZJVVV555ZO lZ[WWo?""BëҲFVk+Tkkkի3{=zűgϞ>|JRGGG-& yyyQO9;;?JRiiiDysss===8 g7|קO_~! AAAw駟k !cƌX`)ԩSiP(fϞ- lmm1''dʔ),) sYtiyy9[.55׷O{Ew Ǐ۷ȑ#]2rdܹ~ܹz U?Q?eJ\|yw>6/Wntttnni{~ FGG/Y$//]+!7@2xxxDDDkziȑFnxW_l٢7ڵ?,L8Ս1'66VOSdee;v֭6ld ի|n_IwuuMJJ߻ea̘1vtt >JOllljUvܩ1ʦLr톆] N81|;wnذ!$$c^|yܸq߿?hР&F ~A 888TUUT'''//dT(Bp…r\Vݻب 7nL& "jΝNNN}􉌌l'ϐ5-ӟ{9BW644t8L&Yl_8_ӧO|++?GFF 8^$֖KRSSӉ'i۷oڵ999"> h⌌ɓ'bϏ#AQBnK7 {{.> 䆏 + 05?~aZk((O 7@nɭ8[CAq >prqj * I g5{nb{k(( 7čPP.AnK8p ZCAqprn a;  j 5bvKHH7oX,.((CkZ9lܰɓ'Νkoowo8)ykpUF +5]AkZCqXa=-6Aka5КΡ8̇ܰZCp 58L0Z)FCk0r\hMw8 0Z}-jhh0r?d$FիW5q;x`XXctbFBCC8PTT4h \Ur h8L0Zo(!7c\ȍ5rcdh8ƂZc,(Q 7Fcxȍq5Lrch s8Z4( 70cȍ5Lrc h 8Z(^!7zְ ?ȍ~5l rGh {8 Zv(!7zp[ȍ5\rch 8ZU(N 7:p}ȍn5|tޢO={6Zx'֐JNN9s]AAZ(vp1-TklmmUv&??Bqh GSȍ68An4@k(}ȍfhš ZOЁЅ@P.!75@9kh ЇtZBq ZAq:<Z݁ⴇt Cq@n:ր8!7m5[(N OAq?5o(rC0Ak\mqxon0.Ak V>Uqx^СC!!![+**jʕ...\-.`௿Z*8WU| Z"7h ܠ5..sq8\ Zp67h ܠ5 +sp8\ ZÙp*7h p7ÝL5al]Grhmm]PP8\jiM^^Z*ukzm{ܠ5O,-s8l Z27h ]a_nXTh-aSnaEqXs/;r 7h }L.shatn08 Z ,Cstӊܠ5¨0.7h n18 Z )rӭG֦]x133P& B[[[D2l0)S۷ˡ /^LKKzjnnniiB XYY9;;!dĈKJJ:pǎ^^^B0885ȍL& ",X 33j߷rJv(a˖-ƍ;sFTX^zEDDTw wwwMњT*]`iDDZ`\#JǏommŢK̙3+**@+7qqq .n}"h֬Y&&&h Qqrrrqq>|ݻw?͛7܆ "JʼnD~[浗lo.&M JiiΩT@//t߽{VXѲ,ZhX 7Ÿ0/G7o))) &&OMRRu>-EV+ WWW^yE@?ٶm'ZfD",7G^xV;Hg~ L&Μ95d_~AAAX,D4RÆ 4iҗ_~I.К\.wqqپ}믿NTZZZԷo_ggg !7o믋:>Y`3޽{fͲ>}X,vssKHH},,,t9t?iQ'{{{{P=~޽{؄+ =|P$t\ޣGoX>>>4cƌ=zɓ'=zohJsݻw34!!! 3Θ1cѢE&..Ԕƞ={!Gm@0zh5kڑBݻ{6#BHii)Akgg.\keeE믿&<-[zڵWgi Z|J8q"͛kbccDsA&O\YYAnnܸ1rHfdd۷>~x\4w^EE@;6664߿KshennAn HsBH~lӧ!͛4ǡf{.@;]?S.\1bĠAhbbbY2~=zDi>kkkBjFLFsЎF[P dW\ټyѣGML4xعCի!!mS~hCzC#RtȐ!555`…})Dq MMM42f{cc#!̌8nH$ ƍ{;84577wpvceeE"ёT*lk?5#W[[[Z1z={\]]wI؊n$Iqq1!TVVNF,-g-DRTTA,YBHQQQ:t/BsWWW )|NGvv@;Æ ˣnwhpnѣn/]Ds^z-\!++e#>@'##˱@kJTڷ9HFFF=:ԩSʮ]Fs QQQ-[N:U^^Bb*11q4wI$DWWW_~ƃB 'O;vlǿrL0Yf)T}O<|WO}x-[b\.}ŋ>Y@+WvbB!HV^ץ0t~2551jee.rܼ`XuL6ʪHvMٵkn D7vIͳG7‚{C Lfgg'LLL{=[TZ̬- u vZPm۶,%99ۻpΜ9(P )))zzݻם1ܹ3n8;;_K+7[XX :4%%Eu/]R_jPhj˭[ fiiVrM&L@}ݞh"BH@@rùs׮] 3332dӧ0444|֎۶mynkkwN4 ի-DAAA|r_Hegg;vlݺu^^^#G>|QyZkZo۶I ?>s J%o߾qF-nnn]~ʬMn(_|mmmo+D"KK˖Yo޼]@ix7xǧkjj:jԨ41w)M߽{W&)JPhkkۯ_AV1!dܹ W޷o_m{zzVUU%%%iڂRBabbbaa<`Z+FWP=Ѻ5:kb ĉsٿ5k`Bk@&!洆AqtQannPnbZk@k l shaAnP05 @[Úܠ8]bxkؔo rta_nP6Vhְ57(Zܠ8sk so5 FߐAq 1ƠPfBk 14iAnaƐ@q10hPBk 1&X@n 1qqqnÆ w)//GkxNkrE?~ĉc&&&.YYT>}y ?)))2dO>miia/]4m4??T@a]5?C}}ܹs=<>~޼yeҥYYY B}s̘1D23<<|ƍzS؛7oرC7n߾Js 7𫈈ŋ{zzjz \kB"##5 NU%KL8~@++˗}훙iyo޼9rHO ƅ4iP(nܸ`I 3fHJJ1،jzԩ"˝Lgk׮]pÇ.]:{ /A:KgD^; rZr[_NgͧO999C IHH5kVBnP6lXLL=ҥKnܸ7 r[rezz['ԆݣG f͚۷iQF <8..NOS)O>$11QOS^Z.ٳGOÉ`+W)))~~~|ӦMǏ?s挓nG '|2w@ݾrӦM۷o_  .\_>}Z(zH$yyyy]]K/4r۷bM/nHo6;vXGG+**֬Ychh윜ec 7зlWWWkkCIRF&bʕ*X#0 @oGzg80lذ rI@5/oyA iӦ]rvҤIJZ#0nON>={ 6]VVWWO>?l۶ݻSQk \fի=z)pvsrrzcccU:X,>}U:n Om oz"==>(.. o_:dlhh:*22r׮]r.ٳ555111H$qqq6mk:%K˿R`6q 9|XXb3FDD)v80r?J}Ç+6UFFbC!7\WWWWTT4n8xzzc` pwwWnnn'Bn<VpAnP[[[577yR,%' 7\ghhܬ߲ :T͓f!7\gee%H>|y+**<)hrunnn]OSAA'BnbĈj7;;_͓f!7@L<955U3WVVN4I!7@̜9~Qیǎ3ff:㵀hkkz-*ٳرc<(++DC qtt/<\*͝;?W1{ww&r矨.x:99)X`* [lYjJ'3fرcg7;oׯWmVRR't'Z[[G흘)n߾=nܸ?x* Ǯ]G)ڠ gϪ2@g|M/hϞ=QQQVVVK.Uȍ=T*OLLLd2ٲe˶nݪ1'Mt֭ve c'O={֭[W^:1\޽{JZ/0 ~Ggii ӭRSS)66V[[{Μ9"H&rvvPn I(FFFA}[Z[[[XX۷P.Cnt| ~ڵ> .400055zp: "##'믿۷/!!TOOܜ練TWWUTT?>y9L\\ʕ+||= QlMweeeYYYkeee}}D"~~~ pr] FPbŊ]vݽ{ߎsrEth s Э5$#gkH( 7\A֐PCn8!8ܰSZCBqX a9frfLl a%䆵> ;15$ebGkH( 7læ֐P@nX}!8ܰ[[CBqXa v0r\h a4\xV1:uj֬Y 3r`O 377/**໷QSq5b"䆑, 5ݡ8 0 Z 5O0rhMPCnš9P:CnC[ 5Aq /f0PBnh ⸹kz9hZD~uuu5NCnhQ{.]8\L Z 111{)--uwwU!74֨C ]5hrC hz8hZN(!7֨)ȍ&5hr1hf8hZC(!7Nȍ5t rVh =8ܨZCg( 7jjȍ:5Lrrh 8ܨZD( 7*0 ȍ5L(rh ;8ʅ(Z&(!7Jְ,ȍ25l(r4h 8(Z( -Jp̙3f5wr* iӦ5(SBԴ\U)Q\Wk4P+Gȍ@q(#Fnh tPP95$( Uh rC ZT8Cnu(N?5 /I5O50(NoM<h ( rZʅtAnU@qHch <ր8 րp8 Zjp=7h gܠ5),wsրfq8 Ztp17h ù5@C1bDAA̭ܠ5@[K,+**bkq8t1EEE߿ŅWU\ Zp"7h 0ܠ5,,.s8l Z67h 0ܠ5,+ s8l ZÚ*7h ;ÞL5bL]Krjll\\\18ljMaa!Z*{k sܠ5M -s18L Z027h Ya^nT)aRn'aDq/3rPA0 7h ut.sȋšunг8 Z04,Ms ݊Cܠ5B.7h rѧ8 Z 4)r3Gddd\t)77D(ikkM4v5.]ȸvZAAAUUUSSAFFF666'N7n6wu X=z#GZZZ2999́111 .2dH5jC8no9R__1vXwwÇdׯYZZ.X^9rs?3ݻW(sGGGZZҥK ,--mc4mmm33e9pdz=tΝٳg1z_URRi&777mm~v#7B022 \d?ի]];wNѤRibbСCl"J܍jn윜]Gw:::[lAk4{q***wX cӦM$%%ϙ3Autc>?}t---@X[[޽{wc޸qӳǟMRR뭷n^ozhƍ| r2A9ro 7zzzo%##C__?T@ѣGCBBZZZ;rMM_sssrѣÇϝ;W5?xIII'JCCCe˭/^ܵDDD9QK!T_޸qCuSx?>17gϞ%oSRd2YSS+YGlذAX޾ţd2τ sD"ƍ_{5TTTTUUuvvPNĺu_ZZMxxԩS|>@ pttԩS#""MRRs;wqȑ-xO=L>}ѢEňD"mmm۷o{8Ȯ]x/gddDlA ][lllFuk׮Qgpŝ@aW\JǏYVZ}5Awܡ8ĉMNNΘ1c(RUUefffnn}{pp0Y.R`bbBq#FH>gҒ nnn}䦸Ņ(A >v nܸAqrƻwRSRR2s/466=ݝ!ZZZNNN}|% GÇA~L1AVB!@1rB( ^n://#GhisKK>r6tPCTWWc;OCCq`i=8F^|ȥӳ͙3'66VJ'mmNCH$=wttGqrnPwojjjkk>|x``K/D~CD"ȈEAbv g(TO-FM>t|Ν[nxlmmmg7eee sSWWc;@@qr9rۗr@>r3jԨ~So/**:OKK+..:%%ͭyyyg{w~ꩧ~Cϛ7|8 aÆmݺl޼yӦM}CMd2w}gϞ{{I&];/.((t`0ܹ啞>eʔw>~ʄBҥKɷRqСKVTT#F|o]s]C5>}X,NOOWD788o}Cׯ_/D"4͛7W"z"rU'c{n==Udoo|r.At-::QZyuߋ_RSSy<XYYQ(Q]]\Kgg)S|||b1eh:իJ_JssqFEtutt>U ꫯuyH$p@u477O2ȨToNĶm۔;lll,ONNqܐOB5k>aya@@Al! x<￯se˖u1ܹ`ff x)冴{nQF) 7uЈ!ܼygKKDk=޽ɑ2A]8K.DqIRSSakkkG8qΝ;:RT$ݺuk֬!e˖eV$7z٦|>аgV:::AAA֭p4@ lM3gμ]@x_cǾ.\s߿WYYݻwBX,655>|;gvԩ˗ ~ICMMkCCٳgzKKKKqqqUUUSSȑ#{eAqTD(Q'OΜ9s+VZ؃]nPIk@P ZAqnunPѰ5t zAqB0#7(Etn cr aRnP~п5 'FyAqz`Jk Zܠ8k s15 0>7(pC[Æܠ8)m KrG05 ְ*7( Zöܠ8Jh s˰5 ְ67(Zܠ8hk sC5 p"7(0[Õܠ8n rͱ5Ad2נVaaaN޻w.[g7'OΚ5k߾}111^ p17A8q"<<:Nk8 Q8NAq@N `k4AnԌAnzp5c([  7=8 h Bk 7}@q@YК80xhM80hMoMPP Z'f( yf`(P*К!7T8?f@ȍPx F>(P ŁE8@Bk(F^ȍP.Ck Mhb8pUxquqqOMMEk䂳%9wչק5BnႺ:H /hz9̃( nh!7ʄZȍ8( r|(5Jܨhr!70Ztȍ 8̅֨rZ(5*ܨ,h 70ZRȍ8֨r>(5jܨCOhz 7 Z6ȍ8֨r(5jh Yh!7h Zȍ8h ry(:5hf!7tZq 8rC/(*54Ekz-n(11qΜ9Z 䆦?>w\g0Anѣ(Bnh Q ZCO ݡ8Bkh a:ΐf@q@kha h !7L< Z à85L0Z #8$YBqAnAka6na(V6NqFCnX AkavaUZa_q@nXMAka'va䆵^}6cnqVBnXAk a?fa1RݐqCn8AkzsV;.OqNAn8Ak=z4""AS?P*޻wO$I$}}}@daaA}N8 /_njj"7jiiIR0aԩS_|E~Bk8J7w\ -Z_Rǃ {W8p5P(Hd2X,w!C/^8//kkk͵Ξ=f@/ )NFFرc###/^(J~~~ZZZ/~a5\zW^!"<<@\]]̎9BnAk8ǺSQQgaa4[[[W^y睚x'EDD;vɓ399yD,9s srRYY{CCCe {)Sx~]]]Giii[QAnN___*+vxbb?_uX,pru jp¢Evk{luu595pruNNNr}%%%_ܻw!gtvvV@`.,,,lmmsss:K,IJJ7ob޸qc̘1 1anݶmۺuΟ??qDfljj Qp`(ESZ`w[o|w'P199Y&M|bŊ7hczxx$%%h 3|_$''h˗D;wh|9|EFF^z_NKK Tk׮=vعs笭;20nO⋰Prڵ7nW@`DKK+>>~ƌ??`KK… lr+cT|C<<}L&(((,Y+"H)6V^^oݺUPPD4K駟ۗkaaGFFp8\ff&@E"M}}~{AիW ϝ;ǣ.D؉fݺuw߿_~!<Anjjj_~A>ڵf/A藛_UOOoʕ^f#"",Xnffgmvi6="`3-qa?yf 4---v?^SSHKKldY"^nrrr^}~p9s? "No?~ohh899ihh666r؈˓'O&AD9spxqooobb_h"&a;g~"(rSZZ:c />};_r؎HUU"rܬ---yyw}]N`yaDĉxP(^ zX%''`Xq"^n8+GFFƽzA!?d2Ë kAQQvz{{222 "NˍZSS{`0o2G5 ;Dqx&!픗x E'ֶËUTT ;/{SPP@&/^?"D|'o޼ihhu߿?ڲ2SSSsNoo;dee-[ve&9?ث(xkddDII駟~~kkkUUշobJ}'ԄܹSTTc" <==B!&ftt/+WJJJ:::R3fdffr^MMmdd_| tuuw8NKK/%%e"n_ii̙3SSS'tLBGGGmm'ippP__ӦM}+W233@uvv޺u }!rlnn~S&ѣVRR,+>>>**ٳgmmm؆dž;DD^Ciią xK}}ܑ#G&فp*HIIYYY۷aN< }}}^f]]][ZZI$Th/^LHH(**&(ʚ\2$$[!Ka2===YYYJڻw?cnnf[ZZΟ?\RR200P(666ׯG$!{x?MMMӧO_xq__w[駟x7;*++wmaa16zRVVvssz;/D0Q⨩988tuuqpgrANn߾;é{yy%$$3Lxr===##/^L ˗/s)d`zxv```zz:TwbWnFGGۗ-[&!!6000F޽=mڴOr;%%%L6 {O BBB^[dı܌_Jjii:u>| {W˘722ruwwwAD233۹s' wittt_~}RR gggFFF8oޯ=={ilU)))0lf3:u՜Qmmm}}}555iii&UWWWQQ1<}_?RRRbnn⒚ /555?Ν;_Pٳg[[#r';;|έ\2)))77SYYم z( H${xx==7fggÎ4Þ={~ǎN6;MMͮ.:>řf'%%]v-++uttH$뻸pw"PìY8?'>>>7nv4A4<<сM1cƧ~(Tn ))ioo>>'O~{G.>z{{#""n޼ @.iii33+VTn˗/---O:_Lbhh&.\}Wdիy"d`3oSlgH.n>44;݀3ftuuO)%%a:&՛7oΟ?RYY922PUU7o%F`;DWs 88+`}}3p455׬Ys= Rիk׮Jg.,,J",55O>mjjqrrڼyt{ٸq˗κF<4(lvBBµkײ[[[D"pҥ[n9s&w{lnnb6mxbRR? QQQ111yyy]]]4O?4$$Mj^nªU&ͦP($͊!qҥ[nddd=<p4sAPΜ9&pn,Y>`0JJJ:::|wC SVV}(++ϝ;M*jff۷ͺ/fqt*sΣG_UUվ>:F.]hhh`x<~鎎-N8c9vخ]ˍÇ.]t~p]rrrdddVVVss36G__cee;577?{.''abb2gΜ $f…z޼yUUUzzz:&yƍ蜜lYdddlٲCCC'ʕ+ݫZZZrrrt:۷8n̙AAAmKn2lccV`ii wϞ=DP.)))0lfHNNXXX|wYYY㾞c0lgg'++999Ǐ3 (--qѧOb+ī܄m/^\]]aAR}}}&((( Sl6lӦM d*7FFFʰS ;"^~jjj*!!UUUw&pIl͛իWt;222^rC `GOO. 8~~~)))j/NsD鑂)##b22ӧO΂燇WUUX___@LL+@qg}ykgΜqtt\oo;w&((1LAK]]]JJjddvDdXx'''۱e˖Mnt%+F l` Yx<ߟJNhoyMٳgp8q)7 ,C-Z`}:S|L&O6M,Mrr2^v- qm<;"ʚŢDFF+VJJJo޼Y===c 򓜜XӧNG*((lٲvDa?ߩ;""" ƶm`ADL}}}_nbccGGG7n;V\ieeuVY~DDGG!V\ ;"@}}藛}}})&fk׮III5촨fxooowvvd"""dees"ԬdrZZ?;MKKrse0gΜo`gAD H\ti||ϯ:''GWwvvv ;Ȕxzzp"VN>M"xQaa!}?Lt҂ۛE ({{{iii)?~vD=\GG0mڴ3gGz KQ.7d2v ԔVu~,~H'"[n;^^^ B~=bkhhTTTpϟ"[n---p"'?~ 000(**}}}dddP(//wrcccC&anhAfooy\)''=~w^6m"[n,X;ݻ[;"vA p8\`` 'X í^~r-YH$;vl Dܔc[U}ʲR c,,,'ٌ 333ii ͛7KHH̝;}fٹs'F}<AFGGkkks(J\\9w.@Xlŋ?0̙3-̜93&&fq\`nn ;O̙3'??NXvDExfoذ!228ydX߿rJBBRUU522"l6KAA=(({ftppuFNVVV  jjjjNST{{^</++abb2gKK A5 ~?(^a[j`!b:NEEѣG\o[e@"XnEўbd 5aaavԩ9ssq].ޘ @Ӣ;C;wĦ S[[[/:::L&ʩ]P S(* ; }w 255MLL466[222VVV;)6;Hcǎ9rv݇###_~ZSQQ100m\M,w C" "X,Vpp0mٲ8lPWWwraI Sueemcc#fff ͊TVV6̞=Ν;/_3f_^RRyyyTTTpY)7L& v8%$$Kqa4<D266hmmm\oYtnrssձ,66v```Æ `0,Y2o޼G666 NTWWhA O_^SS; 2+))yzzh4앳2 ߞAql+ 𵶶 Awa_PP&>>D"͚5 vTUUo^\\; 򧶶y-]ŋC/##CCC@ qyTLPtttЬ1T*[F ;mvѵk^xQ//7nqQtvv2O?vNӿKAڍ7(ٳgg͚U[[{5l6{ڵwh|va@UU NjұBf޼yvNz(nn߾---ނ#99ytttժU___##;wvww Tשּׁ,&$ իWfffSǏ".Ξ=KPbccϟ҂d ,e@BMCCC__ߊ+`D222B==m۶Q(Leeeء&&::ztttƍB *yHt$n {zzZ[[a&4MYYװ+WVUU)++_vv"ޒ311ËK!7oBJyڵkUVՅ|ijj2 >x!%%v ;PRTT$PNd?#v̮طo?kpfr9]lJmm\qʊL&/a}v3}FA˗/544`gF^ǒ؉MZZzٙ|K(ݰ즦 "Ēgt![Ŀ=3.쌁{"܂߇w***b'F~vhe@4? ԪUX, fS(IIɎYd2_~6`̙N(ouuuazx<ӝ_},f7mڤLż`ˀ̙ÿ3⢡!@pp0 "ؘH$vww[ׯ_Î#rss |QF7QQQM6""R34 H$&%%!- _|+lJ$a)^^^v.pD"qݰUUU~(|TUU߼y;Rʢ4ɓ{tttu +"|۷oG!FJJ~hjj:v,\jߥX,ϡԝ:u [ ;Ғ = D"9rve@B6y󦤤̙3aAqqqCCC~~~Lҁ>|ݽw^؉ړ'OMM%"P\\ ;o"qpk֬s4d0|QUlݺuH$ K񶶶y-^ܹsf͂J$$$[MÇ]`e'|܎;3XE >W^ٽzvO`M6tKK˄===؉tMM W^N!₦n֬Y>>>{BTk&jxxɉ] MYeܹ{;m`J2 ;.߿M^v[<oee;ȟ.\ ##X`A{{;8 2 ܿ_^^{߉𚆆Ɩ-[ &y򥁁͛dG233FvyyyPrSZZjmm ;_7l+@+,--8ڊM B2 (7^.#|sk.w};wvuu?Hr 7Q;v"vLMM ?<}T]]Ϸ~ń$ޅct;IJJbٞ|諫kѢE4Cbŋ&&&zrU7+++##ڵKUU533s͚5t:OOVqi"iddDZZZ]]G'&&*((LMMy "ˀ`tsEB?"xіCqFkkkOOϑׯ_q n߾-##+200kiiD555h4lag\rz~o"dYNNBw\WWgoo;uȚ5kԕ+W#""lmmWTk2 AkNMMeX;kkkWW;wxbҍΘ1cRRRjLΟ?ؼy3qϏ;"鑐՝gD"q޽y&l 2_uBZ$ҥK0wTE_~P(qqq .lmm III ߥKp8ܪU`ŢE`ApժU걱-¶ikkkhh覰⎪;z{{-[fmmÇ777co <ԩSyz Wchmm۷v{H|O|HLL %%v? b6D=~;T__WbӋ8A[$7SIIIӧOD|ϟ?ɩٳUUU>#---//1xĝNMqq9/x왟`LL D}@# HMuuʕ+aG,N9sfeeeTTH҇?qc"~:`ӦM컹w޽;xNMMMIIIAXHHHN_nts}yyy%%%A^n^IItg}6ↆde@Wn>Tp99WΝ;۷Ob񥥥\ʈL`.ra///AD_II͛edd\zvQICxݻJJJǎ366.--qDg 6<<99"%%% HM}} `sqww|1$ϟ'֭һxe@Rn߿fl)bٛ6m*((زe Nǟ;w{Ϟ=csBBB`AM'-**j֭ԴJ"f͚U__O`lgffjiiZ39ؑ$))))//Opj 6Ϙbyzz"lll`@xc;mpnxx>ݻS`1cwFFƓ'O`gq2 u?`s&<<\wT߼yPOOv(.|g7 .Ap0̠<zQ؉xh޼yUUUWL$uuu|MQQ̙3fϟP(oiiZWZ;(`X͂ fimmuwwA`K[n%ɿ[ff2P<RTT;>y8eM=p8S();@`nd@mO½{ܺ`'ŋt:/DNNZZbX>}-((2 ;޴qF7؎Rgg… h4?\SSD}6.r @8U]]],~~~h_a67A3D#ݘ766 措\w 6tww%$$N$XL&B!ɭMMW^qn***vGU.d2111^BDɓ'ھ;Y Nh˖-3PT3g@?X,VPP!!!, v"A/!!;08;G`wTYYY]ss38ŋWWWAs3&;Nׯ 7l %%gϞa1rwwOII)((Eh 2 8妺zܹPUV۷v(!K"`MMMµ B`XwSDggCN$dddjkkO> ;(7 ‹uEFF>w Ϟ=njjҺqㆽ=DBOCCFt;@={vyyyOO 3ZC/^looqرTk"..npp0((vAk )&BihhU9W_0Ht`vIӣb999<>>uuu+V(..P( Aфn1L~K.2`;Bd2JJJvAP^CCC8dꢣE°Ln---|.\l.ln6F$a<~LQ˗VVUU  ~YY,|(j~L~ҒXbeCCÁZ[[Q%v*//ǦAçrѣGyј~+°gÙ3gEEEL ?wT})vdvnn.zD z`Æ DbJxܼh4OOό ))/iw3gN~~~]]NEJ~% g7givRVV~䉏NGF|$%%p8Ax[駟2%-7Q;رcƥ7n@. -[bsn ;Ȕfj֭ϟ+V_500#BD^^H$vuuC{e? Sr^SS188H Tuuu F[[7foٲ%""̙۬3\1sΣG+d22 .C .xyyM6md`ll\RR­'ۗ/_&[[Fn5;SSS;O8;TMܼ|2 @RRRVVɓ CCC,W\ ̝;766fO:7o߿?vTQQ`}Z[[a7gΜׯskDKKI2544A$;я#bۻ7##v &Pn(ɝ;w&See7?188᧎?.)) pvvDRWWDcQa2_|߳gb\666 ٳg؍>N1M?|0 aႏaoooYYYnZ`mm=}q/؊JIII~.BDDkBCCt:v.Haپ ٳg\`,ZHWW v#?pwwkLMM`0))Lw`0mlljJjj Ȩ="b;wHHHN*7iiix<ڵk<껩IUUu۶mo߾;w.@FFŋ<===pAnn.vl& rקo߾ ٻ``*kyE 駟˕y:y%%%:::<+jjj=== C144imm;_mDӏ=_N8188 ^w؁ Av޼ySpǏ[p!__ߦON0<|… J}}}Yȫ&&0-\t)((ZX~ƍutt/_-\]F .] ;7S8;`=644L_Wrrʕ+alћ6NhSi4%%H$NhHѦ/KGGgڵ999iiipdxx v.ܰXLČܳgτ"kI !##;G6m)7RRRkc׮]aaa @BBbr"ȇ'O߿v!43NQRRQ-4mҥ=^{LJ5ڴiÇ{{{agvd;O4NHHpbrQQYd GUU#&&bMAW?Dֆ$%%aqVh4UUׯs6k֬h#***{innNKKeX8nڴi .\nݧ~qD{SN}C^^^__vXrNќ4r%iii6Gjkkck)x 9^ӦM}(;Q=qnܹrR##WgϞwmllzGKl6;))ڵkH444\t֭[gΜd\>>>7n܀||MmmM)ݰl @>[n7o|ʡWWױIϒ{CTD8::p8Niܹ222S{FONNp>`Æ `OOϩS^f̝;СCmmm n"hbb;ab ~uk.4~a;;N:%J)"\{n@dd$ fءrܬʻ[$d۷RRR+=Td̺ػw/<v^)zٲ;wzc^|cjjj@w-[`<|NVV!Ǐqc"{6?@}YYYMQPPpqq ݻ9%2UΝKIIm7oHNUTTԬg͚U__9vCDJVVVpp>Vep85kݻ;:t?O$ɉ zO655''M6͛7v:.kL[pE%-tdllak`iF3VL <*& $  rQ@`1 < ""HJTmLKRGKO&dq?z~Is^bM&Ko䎎^{͛ D7v.HZmHHrJVVVIIA7b' _ټjse###cbb\R]]a6Z7VH$J{{{!!!D"A@PZZzEw5iiikkk5l6?jOex<@ 1}v@yxPLfX%%% U4 AXtԬ,6d2 .d2jR)JGFFVVV.]TYYY\\|< s9#FTTkkk3ݣTVV:NjUkkk555O<FBQ=?pT*Ummmrr2HtD|~ooo#Y,Djii]`0D"垅 "7 *Ah@ppD"=3hBuֹs禦<׻@qN\pA(NLL3555v,KQQ@D 8`P\\,|zooohhhgggqϖ 7tl"(77xzzXXXbb믿T* onnF񲲲ȕo;aL&3 =p)++BVz>)))33>Df|V+Ɏ FcooЯj2BBB"""X,s=WZZz9b\~n?qFEE;&߷WxP(O?c2:RÍz vC>w7lS*=pT*yB'[fgg[,)owE7nGn˗ n%˻'''U*fp4@(>x%dbXTTzo@$i4/vwwF#]FDbZZڃG^|Ű0RR0ΖH$ _|+L{"t:]q\,길T (pwsKKKL&$YcXz=z*K.\v綷OREW_}ե5I (., ƖW__ΎT*]]]mhhsiCQԥV`ڢf`0DGGcpǷqss**駟:=;;'`pxxF,xwsT*UӝSO=[oUWWcJӝ%1K.mnnc3(z˗/qs7oTT,H$DQ?9Ӧ jy+= h78w'1K/9vzcXD,GGG_v.P(ox>H{^oii!  gffN o~eoo2Y,?W_uJJ j?22≾ 3&qqq---NO6w֖^MHHxԈD`qVՃ^|ggMMMUUU^m X֚L{ QԒo7c7`ER~7wo4a ܿ?++KH$ j:%%yA^qހ G"|:ua Pԉ BsppੲZ6##be@U.}G_8jviw$&&.,,DDD잞_JwIJJtOZo6p8.]_~ LnooǾ!w7/,,~ii`<ɭNWhnnvP(LMMU*47)q@|{!vwIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tetrahedron_isomap_386_golden.png000066400000000000000000000474301450372207100304220ustar00rootroot00000000000000PNG  IHDRzzNIDATxwX׻8𳍺qiJ& Q5h4Cb4jh0v] b@A(/,}/s._2;sΛ<:{fR9۷oDDD qE|||G00ýf8p@KK?gWNNNOOg;wݻWSS/,,,@ LCy󦺺ܶm˹ҥK&&&bbb[nmkk֤b6ݰX+VHu֎`O4͛7# Hܬݔϙ3ŋ3fTeeϯ\2w -^)--uttp8ɣ5!ee刈+Wzyyr4q}}YbbbƍǓ))ʑ#Gdee###y2,@ e#77ŋ<{7nxꕎ͟djjʏ;;;dӧOa?l߾~SAhsΥi ͪURRR( _# .,,D| ~wҥ~߹!qq~Oȑ#zzz ,r3g888py_z 2ե~_\z5FpB}}}LL^uu5!=z3HILLDr9Ddd$B?OXqM? r2'jkksyt{^zA< I7III\^bnݺ%!!d26mZWWW||@ n MCCq())q;;;< rI7\^_QQw;} ,asy>@ n丼!$!!8nGFF!4>6{7$;;;=6%\^mx>pAAAqX,B AҍﹼK7555!"{d Aҍ~NN׫H`&&&\K&< rI7'ONIIzEEE''~={rssr###2 nM.XjBGrrr$**Ņ˓htcgg'''w .ܲe Lgg/B9y$#>s8D FLL\!))y];;;ӧ+))?zJ3gHIIM4i8D~,**Օjjj444U]]!daa_M6b&M4amy`0&O<܇AAA===yyyYYYΪ )i4کSEqq1No]v1 ;_ss3_P=·o.++ϧ]]]MMM;::}tmLvvvS *tvvۛ655c[JII J޽{mϮwU~ yƌ3ZZZx;)JXX'd7n>  H7"S]]fC"0R%%% N7'77WGGdre˖;wnd#$%%a[^FGG2$`pn8Nuuٳi4/fG6ٝ;w444={6zխ\R\\!o߾Q7n 9v옼zPPڇN>D"544(۷OII Qpʕ<CH7~IFFFVV/oxGGGbbۙL&D|/bDDD)xn"Ojll|rHHHbbbWWdWWW]]]vvvqqqwwĉ-Zkhhȇ 6vw0aihh,\8@Rm&!!|:C`c166nkkC]~ צMcccBBB ԩS_zw\Ӎ}OOBy&f zjZZZq@d|L7؊/7h-[466|wMTmQVV}pl߾=??B=zTWW >``VO>D<ݻLGGǨ(===cctЀr _'I&744Ν;WQQ;4DӍ%RPPD<'++f<=8\|ymm-ޡ nMpttt:c΍CBBmmm?w\B[[[qq1_+yYYق RRRO8w\A:;;B/^\=8 lmm]v-N_n]kk+ޡ n= %%%###=`P]v]~]MM222yyyxP{ׯ\x✜,8}}}p@H=ڶ744m]##Ƶkזzyy)((~nR еk=^tcZ[[9"%%sN KVUU‚ !TRRBPoɓ'׮]SQQILL;.ߚ)qeeewwwii)7nuVgg?7 Vx]PP0u>`:ᡢֆ\~4<8c ҍi]]… {zz=z$ LޱcGmm۷555{%t3i$Ѫy}677-..pĉ^>As""""}_~wh V9BZM7o^VVֻwܞ>}jjj:qP`n$ŋ˗oKOOyeee7o, <1R[Wssspp͛7jЀ\166vcPWW%yRRͽ{455bbb O\ꪪϚ5KYYyϞ=xe/M޼y#ف|?Ċ+9 bVV j5=8444x񢂂ԩS_zw\nLfEE5kVZZZii ^z5yd--g ,A[[۶ &@?aaa[lillͬY _t4mϞ= /_VVV g.((;4@N7...hԩSw233􌍍߿w\ndtJJ Bj5֤I ΝaN7!555a$ j5lpp0>x Jݶmkkk $ҍ)J?z* ?Xcc㐐EEES qCqttRj Բ ٩8q︀!̟?g looZMf[[[׮]K׭[ڊwh@ntuudӧO{_ZMCRwUWWwu55Ǐȸ^8e8V0jbQx✜,8}}}O)++d2** ׮][ZZ奠믿ƒs>ʊba]\\yǎkmm=r䈔Ν;%$$.]5t ZMBoʞ!LޱcG]]ݍ7{ҍauu5g;-Z=8744ׇcn޾j5 k׾~ѢEƍۺukWWޡ>-̙3!t]UcԱcZZZeee+))pBpK7666$ {233Z1ϯ811:<<|„ nTӱ?ϙ3j5ǸS>;++YUUСCxxtݛ_V` ˗l]{))b-<Ӎicc#g!-- C&o߾}i99ӧCyH3L>ᤦb?B_M0мy󲲲ܞ>}jbb2qP#g7oBwӧ755˦`'FDDX7VTT,[L^^<ӍJMHH~Ėo.1 }p{C\3`8j.aΓlllbbb |FOOo&j.$$$֮\277UYYyx> t3eʔa?`Xƍwܹ}!6o,))jժCn 6p8pW F 2""d?^AA1##9̘1exo&sww(**;wutt.^w\nTtz jҺsNkkMjkkWX!++?vttژsڤhffGFLLLMMMgϞ?~!--=o޼CO7uuu?Ι3Z0%%޽{ZZZfff>;1tcggݯV… xӧuuu؃Yf)++ٳ 2؏P J^^YBBbŊ\O7L&L&?yj~GFF^xQAAaԩ^;."? 233{tqqijjM̚5+--t^>ϯpܹ{m8.H7t:]\\e8j!++fe--ӧOht fjᤦf_}<8熰l;w5.>Jbί\=85kaI7SN2e? e˖feeM6-&&F__^HX BHFF]o&DQlll}}5k_tUTTj#++{ĉ#GHIIܹSBBbҥ}YBn{[c\]]Voɓ'׮]SQQILL;.< Qqtt2!b ХKp sttLNN.//Տ=w\tշaҤIT*ݻh/ׯ^nX/DFUUopfJJ ~A3d2yǎuuu7nPWW?~kNNޡ iTop jYhQNNNvvK\\X/\d~Kr8(/ ׮]E7n֭]]]x/•n ZM@`RRRǎkii ݻw… yS/\+ejLf0Ϟ=5.ϯ811:<<|„ Rtӯe8j51uϟWUUy{{gee9;;:txp677|7ne2@ٳСC555؞^邌۷/_ͭ޹QUU5441c ]oll=R__k.\Cwټy۷odѣG:ϟ?heee``&##prrr^z`bbrJ??b\P(JKKB!//ݝB ^ʏY˿k11155955uEEEii退!tsPiii߃VVV`7nFmٲ'#>|XFFFOO… f;vl„ ΝiBn#G=jnn/.Kpp&˗WYYhFkhhߵkW{{inn)xХC&-[?_P$[[[=Í &MMOO}H?VVVvpp0##~TN ԪBR*^SXXoff/ݓ)Mvvvsss߃zzz|^ٳgϟYSSuaYY!onnhqqqrrrJHWWf 3 .E;m(>n8.166tYXXU&QPP0qь8qDCCC./P(›n-c9FaoFZEEer8Hooo55/CqCEEExӍ3wj0l6[JJjWPϙ3ÇABBBxӍ'Bh`p;;;`(Jwwplll,..~L4i;::oQSSP(ϟ?wj0222)A555CCC=syCCe8__X_+WMCCd|}hSTT$fĉZc}5>}SP6cc| {怜kjj:ذ-18h:u*c<==RATP-1P 驫B~~~zzzj߷t6h)j0 .z*'KJJn߾=&&5++ᄏx񢻻m۸ƍ .tCR%%%ZMF*###11׮]gGG &,Y͛Τt횚+Vc'&Nb***[`h!!![n-..P(nnn<F__B}w211x|ƌ, \ڹsq/_^[[c~}v$ڷoW.577cUK}eMd27{}}= 2CѠ&SRRA&M$|!))yƍ@N433Ieeeyyy,L&KKKf"n8 R`` B~GSLxUUUyyya+׮]%>+W $aMٳ @& {{{ee[nY[['%%gC\ӳtR777 # |-P ݻL&[ ?~YY7W%%%a/yyy LVVV~@a k֬iii5k֐H$II۷o9Ftcdd0GL&j5(jooF)((޽k߾}mmmg<#k7kxPP]]ҥK:xڭ[rymیkkkϞ=/))xy|ǭ#G ޼y3#Vxdee999H$la]^VVgaa1&t5ڷoVHCCC5GqqpG?):pb/I7[#ɓ***؋~~~q!{w"v Y[[ <"յyf5kִر588{{gΜQVV ə0aB30III +;^}}7F mjǽZNN4QimmB.\#.W^^ތ3BBBLLL={VTT3 FBBڵk`a'Pt:}ʔ) kbbxNOOOe$'QJ7l6!zx9u"&&8ў* <.++zjfYYb ''˗/4^!w]]ݏ+|2~яm>1XRj5a)MMMy2?D ɀIݻB>|SssslCr^=?ٍ?"Jk7!l{D5#j;SVVO]]]ll,OKڵd:u*!!aݰHc@uwwر{HDӷlū{?lKTn>2VSh7jW\\!4aST 2 nհ{nЏdRbbQZZz_nnn<i̙/_֎OnBCl`d^xamm͛,暐%%W^c-׈dqqqp8ϟ?wvvfee <. ^=uԌe˖UWW?~ؘSttt._\NN.--?osÆu_ ! ٽ{qBқ6m,#A[)nh'OlD@YFBB!ħBϞ=,"D$ZcV|LYY֚޽{+11uO#zk7!&YQQOV bkk)S}ÃO}Wvvvw ÊHlٲ!7ZM!r ]]]J]xqee%_{ Ņfu.#&>>!tʕ@:úJJJnܸQe[l!H.]\H$Mww7Bh͚5;j526~zӛ`z<RS?***o޼پ}{NNB w [)++ 6( Pv۔\~ X,[[[´QM7X4MAAhoo 6nݺ%))I"6n(Ee>=~8$ŋSTtwwG?˗D8())1̏}mRĐٻ 6X[[X7o޻wF >Bj䰖6m yyyP)Bjkk-[Jkii[vHD Ñprr℡7B۷NNNJ;Qd2F:u HF:15ac 6}L&8qBGGx***sssMMMƏc0#k7!cc㚚!NpttZM!6s|__(|sÇ544ݛe&A޲e U܎;acz "!,N7CC"|||\ccBH]]̙3xG?.\ &&F"6oތw,'醛l+@yyy...~=;fBXa7h`7C/[YY0"v`P"n8a]]]WSΟ?1mڴlhl{M,\pܹ4-!!!88 oFחD" qj Rwww``,Va( +}%$$`/^,lȧ3g 8GFFJAE;PǏ;A\kw,cȧjЎ;8jUaalbbwDTVVF͜9S`D~``8j5$!!BGG'::);;3g;~'lsK.EGGcw<5 Ps/_ZS.[WTTjll;NnC GM8QLLΝ; v9nܸ˗+W+++ JNNw<0tp"5kHHH`/ Jp*###!D={6B+ҹsʞk;!p8:>eʔρZM]vMWW[ ^x5I$2ϙ0aj~ݻBRRR"Jo'!`v255B[[ۺu$%%grAE%66VAA!22ǧZ0$899q'jT^^`:~q o︸tҙ3gHG]pp}{C ŹRRRL٥0$%%a/xzzvvv AZH&/^xsdeeVᄇc{AP(ŋWTT]D"IJJ޼yX0'(**}"FPTTDIJJ_f檩A'ElS}kKKK}}6lo7_ N>S\jQ;BCUUU^^^ ׮];(++þYXX!⤛0aN_L;;;5)Sh|PFF K INN477A5 qqq&M葫k~~~ZZrݻ'NÇG>rq2VIPaٳbbbXYY211Mv-p819/_P(ʺFLLLOOo…gZZ` z<f%ǏST2,/=#C,jjjbbb?;~ӧ &Llnn`0۫333KJJ իWkSSCCC;::v_c"|X,WW/^hii %$$dX۷o銊[n}'IIIƍw޶6YPP憽`bbbJhh(XnQ{jii)((:theX{'&&>'Oc~L>sLRzz:0DGG#_-رL&/_fc{yyhCx˗/coh4%"##W\w,@X0 ;s OF P(===Êgǎ!:e˖.#,Y{!Btpmll :Ño߾-!!O?qsrss8Bh„ Ǐa$))) Ek`4nx>۷)Ç8[ 622yBh͚5X۷o FL7K.iJ&$$ VVVJٌ۷!ggVB馡A^^/, .400[|---J]lYuu5_$ILLٳx? r{r8ݻw7!$--iӦӲU]]aGt{qqӧO `={HHH`+c[?) J`L!Z͛CCC?$??aZ~))3g` ...iiiqqq&L;" "w`0!33E9::M2bK?HI󏘘L ; bn"""H$<_ZZÇ?fddHIIq8)-- !2xELKK OMMVtt ...?~rsss]]ݨ+J FBBڵkBgϞarɓ' Pff&899=yd8ayyyyIJJxرcxGDMFFVlͥD"TTT<==EӧO ݻwkkk ⤛]] /ﻺF3pZb)::xDq:1`7&#իWbbb-*p~IĐ6k֬jww۷o ݴ#FԩS+}7ى￷jnn \x8w7{}#RSSSya]wuUPPRRRbggfedX,ѽ{=$KV3%vd2O:qni4Zaaݰ.lhhTVV  lSSXwDswCPLMM_~=˧MfffvׯMMMGp8r䈆F^^ݻ322 ! Bhԩ/^w޹^z˖-#ٳg .8jjj9s˗/U "ƍޕܬddd͝;w?upp ?vrri cE[btɓ'9yϞ=Cof~MUUUO/2%--=zt՟+o޼?lc1 YbBvv6G~Ny>2omٲD"BL{{9srsscbb=x"55u֬YӧOz~+)..1cFAAɓD̵۷ ?~̓1߿loo%5+))9tPrr2 D⯶62s4lkk  H֭&X<c >P(FFF===ׯ_ӓEӧOh42}vc`pc""I$3g?yU}}'MDPr;l,?Gإ~(ŋor8ӧO4I[[`WWWdff&$$\DXA< Ppvv555ڄݍ}gggCCC $ >{Ȁ\` Yf!ܹxssPw744XZZnܸQSS3??=ZBkoSN%Hqqq /8\xQYY9==}j-X𕌌LjjjPmُ=RUU666;"xl lii} ѣG~~~>|\ilss~lN Ν;F%$$@9@`c+8::r8~ߧq'11`ܺukŵvvv`t3 l6[RRRZ޾#""Bt ~[KŪT*5!!g~յr̙4Ee0YYY}ttt槟~233khhtRtt40vLNN{S0[O>h1111nL#I7+++ JNN\Ơ1nRk666޲e ,))o7l̥l#===k5y)Ν;߾}ʧ~cnJJII]p8|XTT3gL<ŋVVV.\DǏ𡏏Ouu5W}}w}G9R__U_}ݻwkɒ%!YYG.j&22RUUUMMýtժU$iٲe Cm9 ,¦L&555fX---&7 k׮%H7oD1ͷ~Kтy2Z]]bJJJ㹹jjj!0O<m YYYؑ۷d113gp"hO,d2 DH7l6[󶷷h4 "Ba0UUU`x^DҍN~~'-((@ x^DҍEZZ'MOO000."'' rǏD "B?~|XXf 5kf3BYd{nomm )͛TUU===)n)//y>cA6HKKwvvl6;66vЏUTT>9ܹs;;;F,cA BhNNN2eJLĽ3=DBtbccsڵEo`TZz jkk7ˡC҂7DEl[?kkk&y >}:cƌ|pP!ke˖}۷/]Y__?޽`aaqhe0 f͚ٳEx7<L~;sLZZڋ/8r_lـhx"СCvvv~~~(--J7_xq|СCWXQQQ:>\oZKMM:t;p%Ϟ=榣e˖cmFsttt\dYIR',,,~}2Ƅ{7ͫ=u{ァP ˗/yfbb|@\Fލ&xɓbq^^`ŋk֬Ϟ=KPFZZZf͚ehhx5sssBdXx}ٳ h9x3Eo2w޵"|kמ;w޽{Æ #|pmۑ#G޽Ndԩ===YYYl6){74&Tk6O?|$M\ի8rٳƤN4\Uuuɓ'wMva0l6;..쉀f NNN.//g7JJJB!˵?~s'OВT*޴iSHHϟ_]])ɮ]prrrg;;t- <^&,Znnn۶m۸q+W`kkuy(7@ipaLK7o޴uppyɓ'M+ӧOg0'={vFFIZ3f ヂ+jURR٩HR冖JKKG<`0O>|xoo/l冖ꬭ>f׮]֐!Ch9(7fbbYW^5kQ̙SXXtCCC&ѡ`]1LEO>|U JKKGI冖x<^[[g l]RRKz'H$J  LѕճgTyٲemmm8OԪ Z>|xYY8::bp_^^d2@c<ĉo.  RÇ722R$)rCKSLyӧOյw7_ux}r Yd冖뗔`ʫW\ӳwޛ7oΛ7>3Hmm۷}Ղ+ꫯvuuuM0ɓ':::2g֭6lV3Ӿ}bbb ]=zҥKsyJ{{;겱?WwwêUvڥl^_\:|pXXXUUBE ۷o߃?N,Ϟ= ߶m"ݻw8pdy]]]2 455ݹsGEcǎ޽{wԨQ 76}ܹ___7:r_ 0 -->(Lzͱ| Qc-o4Deeٳ /P֭;{cVZE\FFC 6,''{ǎ]]]ʍse77WBĂr9...166V222f̘1wSh#(7f͚5?,--WX{:===999ߝ|||tuugΜР ֿh ssA\ .H$C חH$BB,ϟ??99Y,,Zrs[ŚiȐ!EMGGG\\֭[Νkll,l]]]'LAAAGٴih{;6444""{ݻ[[[qn5x`Pލ p8/_p87KLLD+W$-#FpuiMLL̙sŗ/18ǏɩyټՍپ}T*=rȫ/>\Ѫd2ϟOt@h'O:::6۝g˗/Ͽ|2rQΜ9ڞ{|>_*;V -[FhFhpڢʫW2iӦ):Ŋnllܽ{71r9***?~|^b2nnnJvZ{D"bFsX^bxҥ*kXl``0qě7oVTT(=ʰ>(n4DXXXooÇP(Tq'dŁhǏ[[[VWWX,PepSSM6 \Pn4 ZZZױ*Nq!5k֨8fPn4AHHܷoV)?Ҳm6Շ rZXXrq6Stttkk-6od2:$fffD͕"HVzJϟ𰰰{@]]kg>HKK'jL=[dddOO7|XٷD.pBZ XZZN>]We273VUU ̬̙3g;Ν;---R)#Ƃ\nHH{.>|8S:ucݺu 4jnneCGg􌏏WhCRUPPL&'O 8)))2 Rٳg]\\1BwRCeeeݸq)rCKǎڷo_tvvJ$7m觟~Oɛh(7o>SSS__>.:r{=x y~|_|a>['O&5L``ABCCb1 ~6ofaD-[bbbww+ȞlJ3"pƌW\H:58qbvv6}ٶmۛM2媯QK(Fjj*f흜ydGGZB1CM7(7t5 {2l„ jx<}rC'ᆆxnʦ8,+&&Zn>@ I%Kbvj*{{Nu  m39ȈPKJJyI9xND__Ν;x277^7k֬9R*zH$oMwTZRRY`AAř}066 ,--=w˗Ba`` ]FHLEFFsU6Pnh`AAA8T̾Ƿ  =P[!rdz  B1@:I&ER/UVV˝:JRh ^rCu)))}4ɔ֖P888|JrCi}4ɔ͍P 矡&x EGG$Sl2sᅵqqqPWvvvmmƍ: ۢLJ\ZnnٲE"rC]:::;vP,lqf aԩS1k(K=<<[ZZH1cܿٳg @ W7uVLo@ 4h9*`!rCQOvrrRbÚ#FJyC Yd rPnرc( {{{ǎKN.8qB__Znj3(7To>cc?X ԩSɥ-7dZJsͷ(7mܸZnj-(7yfo>%-,,c/twwC©k9uTlEd2>OB4L2%33uV3BBBp6ɔQbࡸrC- 666Jwtqq!:,,, . $%%(w:eѣFFFxMB׮] #:);P0@kPn痖.^XX,]%-]122u&Pn⫯b2JPZZjbbBh(r%''K$E %HK.?TA5:o޼K. %DDD($S/^899JΝ;p`t-=I\uuuR3?~|)Yܠ؈I\c)v5 Pr^ppBM2{.".Ƿ)+3(7555|G*-$(a-7&Y  bbbTBZnj(7%%%[YY8NCCApppX`7rÇE"QddHRHNP.4N> -758`nn>{lǡ&~8酇CM IuT ko@ř}ؾ}TPn p8f͉ȅXbb"Ty(X̹s^xQќ@D4|=; \)<<\">|쉄B=ٳNrr2͆Hqqq֞ե͋3`jjiӦ_u \|Y(= Ɣ)SȞ:dbbBR5 (7 ۴i̾?~ZnRbb$)((rj&A!$СCj\ WJJ ܤ (7dzxxXXXaz5LD_NNN|AZZZ~~>,OPn5o3]GGz梯D.pBA &&rj [9a5EkUUU?,࿠ܨ*33^m]ְř)mtsNKKKT: `@!@PPΎ;3ݻwL&|SNutt[urܹs$S.Xٳg{zz.TF%AAA2ȑ#jɓ'Tt 55U&TF%gϞ9r:K BF!C YdIVV֍7PgvPnwرH*H^yN8駟(o߾}5ɔڵk8S '**h5(7J***j^y`0&OI5ƍ*Qg^PnyfRdu}]]].I5ƙ3gaBy2D"!M26lXww@ P礚kYQQ\Bn"J3U܄EQr{{{'''53U,,,p,ʍ’Z[[5X|||kkk@@ Z .ϟ?/,,裏PgmR`XP:_\6oތ5xAR==PjjT*jwww+++TlmmQͮ,X:rn$MnnnhӧOBMAyh ٳg Յ qqqh2(7][[i& oVVV[lH$h,(7&rX ̠ N: !Kkk+k_FV ƌs'O <u W7}ٺud3kkkrRM_~g'''[̼x:gr3''  [hc`3=<<XM$;i<(7ogcc?m4XNX(Y4 =zTUUE C7qFkk;wBMbAoӦM,k߾}0 `q/rp \IԩS]: QQ:SL̄rj)WCC(99bCqA#!!uT*Dh# /Zn&!!!0>1rG522R CMuaaak׮Eܺu gw B4KKK/^:lsssAҥK###Qg=(7k:N풓%ɢEP=(7J.]255E,Du޼y.]***Bޠ)""B"'Ny&,Y[[TWW~zYY#,ԥW7aaaF䭚 rsP6Ǐ[[[{zz"X,=z4 @6m*))IJJB\pRkeG-N211Yf ԥu&$$D__ӦMvG [ZZmۆ:EiW%%%i)W~~>122B()::u*ҮryfJ5ɔr:RɥEF*?RM2媫:t(@I#G7o^ZZZ~~>,E&22RM2joowvvF(kpBA(GMLL de27 @yXͪ~ujіrY__:;`3M:P r_*B!Rn\.Pfee1Lx3N8M~_妹977חŢ Quww?-7_!($S.>Oz@i)))rUZQn]\\hP(tpp@ZnkIֺb 0?h~255Eݮ_`0L: ݻw/hxdҥ8kACM /7l6{Ϟ=RTTrQKLLD+WD1M{(k) iP.Z>_ZZdAT-0` 櫯b2@DU=řIIIdѢE~¥Rם;wPgQ>|:.fII3,MDDD"ojnn1bҰ]*Ay{{*P;vXAjFM˗/755B41uTAEFFi@M۷B|-7Tn&} (,,ӣ醧@,XBtY߼y3AGFjjT*cOTnRRRݭP!Fcc6,X:hSn<(###Q!LWWt 9}.}[nҦDGGϞ=ub`4q>P'==p>:2Qnkkk5WFF,Jؾ}Ֆ-[$ , G p8ᨃ&//g$&&vvvc84X3jjj:w܋/BQF Z?y{{=yd(W7[ndI X[[N*550 A矝4l/^}S/_:^n~ǎ6ɔN*Lx}}}zm2GrgZ7ɔի c騃cXQQQ4Frѣ*Z7ɔݻ  u@oXpH: ..7,FN4/".]:.}. L5$666糖M,++sttD{uK&r544L@&-oR?~F1JRH:_~eqq1[nR$''B<ѣFFFHrvZA3;ܤbd.^uRlsssAFYt#[nR`M2Q!EYY@%''S&ʍT*t钗),ř ͻtRQQ,Q`M2<:YF:LΝѡ+7G4i g3ux<^ppǏO::*7鍍[9eAƊׯ߆ PZ&88n۶ u`řT'Nhkk۸q# Pijj*((ƒS 755?( 4I\5559AJJT**7IIInnnYQMMMÆ Ch>;;;??[na)*&66V$8puѣGO?GOQDEEiRLnݺ`04?.{n@@.&(7$S7o23f֭[)r& @Údu}cdd:""hʕ0(yh{{ɜ9s4I\MMM 흛[SS3tPI_l߾]*j&nRSSLQ@9y򤣣6<ř f~~+W&A\nΜ9޾k.1ԀKqơQ||e@\nv>1[ ,+::yMѣG˗/GAmL @K]mMk0|8 ȑѡWnsss5I\<u Znד=~󃂂4I\O<8p UJJL&SB*gϺhf8Pr3++ƍN!dꦦ&HfMMM bkk}ӱcǺ$2 P(x(..uX;x 8r{zz.]~zgg?L&O5=zt@@@FFT*32k=|0**ܹsL&sӦM=zarRisssMMMIIIvv={pWjW8p --ߟ4i9͖H$UUUn{yy, Nooٳmmm?N%%%fffk׮%|dAׯ722zW*77n`X'O$# bÆ $O4u9M֟| IK$WWחo-7vvvK.%) &%%d޺uYTC.ߓ:Kppp~IV\iggFϟ?ׯ_hh(Znkff?p̘1ܣ"ܹs'NH,]]]gȞLd2zӇo-7---&&&QQQdGllM*ݾ}`ܾ}[ s>}ZGGG'1w\5Lz.b8tО={>}>---mjjxC6mBI-^ٳgX7㏛];w\pٳgC]x+Rken=rvvNOOQĞiӦ9YO^z@ EBB²ebŊUVUUUΫWřfԣ… ׯ Ƽy󪪪bVZ?g'G5ϟwqqY~}UUB'>}ZΛ)>;;ԩS_}"J08GJ޷o&!!T?2Ç|+LOO9I{_XX3zhw|֬Y3i$9W7ׯ_7n^m3d2 ?dΛ7[F)ׯ_1c. ˗cq`gg7rH ~+xiUUvMӕ+Wbbb PJl#1o޼9&;;{رwlll^}+'fggSMDvv6ѣwzxxZ<==]& q3q;w(wuwwʖ-[߂kbXN)..vqqQeh>`0^SSʼD?{.xlBNNq\\\ .Ŏ:::trӧOmmmU`(6gTXz. l#~:kR 7PʱWqKKp8a3\T 2ϟ?g0ojll`0^xssssL6fxUee￯y@򃞘:fgl$hmme0o^b8طPd2\er~i˖-3fعsB'D"qҥs*75ኊ+Qbױ$WmطHҿDrXXX444(1\KKˬY.\hfPb^`a+ ƛUqtuu( 9N75ӧOjc3+z"y[Ϋ|bՇJ;;;r*JrѣqP]]=iҤ/'OT|5joY,kOJJJqsѣG+\F? Dyy7S&L8QTT4eʔ[FDD(&##cԩJN &_8:x3g|1++K,Ϝ9_oo[(cܸq,+33S޼yLέ3gJK.-\TTTL2eȑO<ٱck_]h;iooOKK;v"aΜ9Gyiiiv:tV;¸\pΘ8k,ՂV&&&ǏONNVhRRRfΜ)ʫ>HLL3HBB~KK˾H'---###ra== ~&LׯߛaƍS*,x=zĤgΜٿ?֡{֬Y!!!G),,szmm-NNNo:::]UOOW;%<<<<==>۷9s=)>ʕz''iӦ& rѕ+Wwhii2d7l؀xO웯;881❧yS\zd܉rSWW׿R?d⼝VFF"-Upp0#0xHٳg;::t󭬬/_wtѼ~61244 "|dDFFr8 .>~d2PF;;I&J(72ٳ,oQn޼ibb駟Rԛ+]]T}~z3y䊊 2Xue?l``p, ŋFbX;{l̥R۷7md}cE;`իW_zU"qH$:qpp8sףGϟ`0Fua@񕕕wttd+VE }d;dzxx6D(ԔFZ2J$>}:>>ݻFFFƍsuuׯNwwwcccUUUaa{bӿ⋏?!j*));sLss#<==nmmRi[[ӧOݻWUUeeet 6s&eK7nܸ}l&L0m4'OܸqΝ;@(b==~ :cҤISL߿?ӓ}ƍǏ׷X,CCÁ:997nʔ)cǎIrm;*rP(75rP(75x(+,<IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tetrahedron_isomap_golden.png000066400000000000000000000474301450372207100300220ustar00rootroot00000000000000PNG  IHDRzzNIDATxwX׻8𳍺qiJ& Q5h4Cb4jh0v] b@A(/,}/s._2;sΛ<:{fR9۷oDDD qE|||G00ýf8p@KK?gWNNNOOg;wݻWSS/,,,@ LCy󦺺ܶm˹ҥK&&&bbb[nmkk֤b6ݰX+VHu֎`O4͛7# Hܬݔϙ3ŋ3fTeeϯ\2w -^)--uttp8ɣ5!ee刈+Wzyyr4q}}YbbbƍǓ))ʑ#Gdee###y2,@ e#77ŋ<{7nxꕎ͟djjʏ;;;dӧOa?l߾~SAhsΥi ͪURRR( _# .,,D| ~wҥ~߹!qq~Oȑ#zzz ,r3g888py_z 2ե~_\z5FpB}}}LL^uu5!=z3HILLDr9Ddd$B?OXqM? r2'jkksyt{^zA< I7III\^bnݺ%!!d26mZWWW||@ n MCCq())q;;;< rI7\^_QQw;} ,asy>@ n丼!$!!8nGFF!4>6{7$;;;=6%\^mx>pAAAqX,B AҍﹼK7555!"{d Aҍ~NN׫H`&&&\K&< rI7'ONIIzEEE''~={rssr###2 nM.XjBGrrr$**Ņ˓htcgg'''w .ܲe Lgg/B9y$#>s8D FLL\!))y];;;ӧ+))?zJ3gHIIM4i8D~,**Օjjj444U]]!daa_M6b&M4amy`0&O<܇AAA===yyyYYYΪ )i4کSEqq1No]v1 ;_ss3_P=·o.++ϧ]]]MMM;::}tmLvvvS *tvvۛ655c[JII J޽{mϮwU~ yƌ3ZZZx;)JXX'd7n>  H7"S]]fC"0R%%% N7'77WGGdre˖;wnd#$%%a[^FGG2$`pn8Nuuٳi4/fG6ٝ;w444={6zխ\R\\!o߾Q7n 9v옼zPPڇN>D"544(۷OII Qpʕ<CH7~IFFFVV/oxGGGbbۙL&D|/bDDD)xn"Ojll|rHHHbbbWWdWWW]]]vvvqqqwwĉ-Zkhhȇ 6vw0aihh,\8@Rm&!!|:C`c166nkkC]~ צMcccBBB ԩS_zw\Ӎ}OOBy&f zjZZZq@d|L7؊/7h-[466|wMTmQVV}pl߾=??B=zTWW >``VO>D<ݻLGGǨ(===cctЀr _'I&744Ν;WQQ;4DӍ%RPPD<'++f<=8\|ymm-ޡ nMpttt:c΍CBBmmm?w\B[[[qq1_+yYYق RRRO8w\A:;;B/^\=8 lmm]v-N_n]kk+ޡ n= %%%###=`P]v]~]MM222yyyxP{ׯ\x✜,8}}}p@H=ڶ744m]##Ƶkזzyy)((~nR еk=^tcZ[[9"%%sN KVUU‚ !TRRBPoɓ'׮]SQQILL;.ߚ)qeeewwwii)7nuVgg?7 Vx]PP0u>`:ᡢֆ\~4<8c ҍi]]… {zz=z$ LޱcGmm۷555{%t3i$Ѫy}677-..pĉ^>As""""}_~wh V9BZM7o^VVֻwܞ>}jjj:qP`n$ŋ˗oKOOyeee7o, <1R[Wssspp͛7jЀ\166vcPWW%yRRͽ{455bbb O\ꪪϚ5KYYyϞ=xe/M޼y#ف|?Ċ+9 bVV j5=8444x񢂂ԩS_zw\nLfEE5kVZZZii ^z5yd--g ,A[[۶ &@?aaa[lillͬY _t4mϞ= /_VVV g.((;4@N7...hԩSw233􌍍߿w\ndtJJ Bj5֤I ΝaN7!555a$ j5lpp0>x Jݶmkkk $ҍ)J?z* ?Xcc㐐EEES qCqttRj Բ ٩8q︀!̟?g looZMf[[[׮]K׭[ڊwh@ntuudӧO{_ZMCRwUWWwu55Ǐȸ^8e8V0jbQx✜,8}}}O)++d2** ׮][ZZ奠믿ƒs>ʊba]\\yǎkmm=r䈔Ν;%$$.]5t ZMBoʞ!LޱcG]]ݍ7{ҍauu5g;-Z=8744ׇcn޾j5 k׾~ѢEƍۺukWWޡ>-̙3!t]UcԱcZZZeee+))pBpK7666$ {233Z1ϯ811:<<|„ nTӱ?ϙ3j5ǸS>;++YUUСCxxtݛ_V` ˗l]{))b-<Ӎicc#g!-- C&o߾}i99ӧCyH3L>ᤦb?B_M0мy󲲲ܞ>}jbb2qP#g7oBwӧ755˦`'FDDX7VTT,[L^^<ӍJMHH~Ėo.1 }p{C\3`8j.aΓlllbbb |FOOo&j.$$$֮\277UYYyx> t3eʔa?`Xƍwܹ}!6o,))jժCn 6p8pW F 2""d?^AA1##9̘1exo&sww(**;wutt.^w\nTtz jҺsNkkMjkkWX!++?vttژsڤhffGFLLLMMMgϞ?~!--=o޼CO7uuu?Ι3Z0%%޽{ZZZfff>;1tcggݯV… xӧuuu؃Yf)++ٳ 2؏P J^^YBBbŊ\O7L&L&?yj~GFF^xQAAaԩ^;."? 233{tqqijjM̚5+--t^>ϯpܹ{m8.H7t:]\\e8j!++fe--ӧOht fjᤦf_}<8熰l;w5.>Jbί\=85kaI7SN2e? e˖feeM6-&&F__^HX BHFF]o&DQlll}}5k_tUTTj#++{ĉ#GHIIܹSBBbҥ}YBn{[c\]]Voɓ'׮]SQQILL;.< Qqtt2!b ХKp sttLNN.//Տ=w\tշaҤIT*ݻh/ׯ^nX/DFUUopfJJ ~A3d2yǎuuu7nPWW?~kNNޡ iTop jYhQNNNvvK\\X/\d~Kr8(/ ׮]E7n֭]]]x/•n ZM@`RRRǎkii ݻw… yS/\+ejLf0Ϟ=5.ϯ811:<<|„ Rtӯe8j51uϟWUUy{{gee9;;:txp677|7ne2@ٳСC555؞^邌۷/_ͭ޹QUU5441c ]oll=R__k.\Cwټy۷odѣG:ϟ?heee``&##prrr^z`bbrJ??b\P(JKKB!//ݝB ^ʏY˿k11155955uEEEii退!tsPiii߃VVV`7nFmٲ'#>|XFFFOO… f;vl„ ΝiBn#G=jnn/.Kpp&˗WYYhFkhhߵkW{{inn)xХC&-[?_P$[[[=Í &MMOO}H?VVVvpp0##~TN ԪBR*^SXXoff/ݓ)Mvvvsss߃zzz|^ٳgϟYSSuaYY!onnhqqqrrrJHWWf 3 .E;m(>n8.166tYXXU&QPP0qь8qDCCC./P(›n-c9FaoFZEEer8Hooo55/CqCEEExӍ3wj0l6[JJjWPϙ3ÇABBBxӍ'Bh`p;;;`(Jwwplll,..~L4i;::oQSSP(ϟ?wj0222)A555CCC=syCCe8__X_+WMCCd|}hSTT$fĉZc}5>}SP6cc| {怜kjj:ذ-18h:u*c<==RATP-1P 驫B~~~zzzj߷t6h)j0 .z*'KJJn߾=&&5++ᄏx񢻻m۸ƍ .tCR%%%ZMF*###11׮]gGG &,Y͛Τt횚+Vc'&Nb***[`h!!![n-..P(nnn<F__B}w211x|ƌ, \ڹsq/_^[[c~}v$ڷoW.577cUK}eMd27{}}= 2CѠ&SRRA&M$|!))yƍ@N433Ieeeyyy,L&KKKf"n8 R`` B~GSLxUUUyyya+׮]%>+W $aMٳ @& {{{ee[nY[['%%gC\ӳtR777 # |-P ݻL&[ ?~YY7W%%%a/yyy LVVV~@a k֬iii5k֐H$II۷o9Ftcdd0GL&j5(jooF)((޽k߾}mmmg<#k7kxPP]]ҥK:xڭ[rymیkkkϞ=/))xy|ǭ#G ޼y3#Vxdee999H$la]^VVgaa1&t5ڷoVHCCC5GqqpG?):pb/I7[#ɓ***؋~~~q!{w"v Y[[ <"յyf5kִر588{{gΜQVV ə0aB30III +;^}}7F mjǽZNN4QimmB.\#.W^^ތ3BBBLLL={VTT3 FBBڵk`a'Pt:}ʔ) kbbxNOOOe$'QJ7l6!zx9u"&&8ў* <.++zjfYYb ''˗/4^!w]]ݏ+|2~яm>1XRj5a)MMMy2?D ɀIݻB>|SssslCr^=?ٍ?"Jk7!l{D5#j;SVVO]]]ll,OKڵd:u*!!aݰHc@uwwر{HDӷlū{?lKTn>2VSh7jW\\!4aST 2 nհ{nЏdRbbQZZz_nnn<i̙/_֎OnBCl`d^xamm͛,暐%%W^c-׈dqqqp8ϟ?wvvfee <. ^=uԌe˖UWW?~ؘSttt._\NN.--?osÆu_ ! ٽ{qBқ6m,#A[)nh'OlD@YFBB!ħBϞ=,"D$ZcV|LYY֚޽{+11uO#zk7!&YQQOV bkk)S}ÃO}Wvvvw ÊHlٲ!7ZM!r ]]]J]xqee%_{ Ņfu.#&>>!tʕ@:úJJJnܸQe[l!H.]\H$Mww7Bh͚5;j526~zӛ`z<RS?***o޼پ}{NNB w [)++ 6( Pv۔\~ X,[[[´QM7X4MAAhoo 6nݺ%))I"6n(Ee>=~8$ŋSTtwwG?˗D8())1̏}mRĐٻ 6X[[X7o޻wF >Bj䰖6m yyyP)Bjkk-[Jkii[vHD Ñprr℡7B۷NNNJ;Qd2F:u HF:15ac 6}L&8qBGGx***sssMMMƏc0#k7!cc㚚!NpttZM!6s|__(|sÇ544ݛe&A޲e U܎;acz "!,N7CC"|||\ccBH]]̙3xG?.\ &&F"6oތw,'醛l+@yyy...~=;fBXa7h`7C/[YY0"v`P"n8a]]]WSΟ?1mڴlhl{M,\pܹ4-!!!88 oFחD" qj Rwww``,Va( +}%$$`/^,lȧ3g 8GFFJAE;PǏ;A\kw,cȧjЎ;8jUaalbbwDTVVF͜9S`D~``8j5$!!BGG'::);;3g;~'lsK.EGGcw<5 Ps/_ZS.[WTTjll;NnC GM8QLLΝ; v9nܸ˗+W+++ JNNw<0tp"5kHHH`/ Jp*###!D={6B+ҹsʞk;!p8:>eʔρZM]vMWW[ ^x5I$2ϙ0aj~ݻBRRR"Jo'!`v255B[[ۺu$%%grAE%66VAA!22ǧZ0$899q'jT^^`:~q o︸tҙ3gHG]pp}{C ŹRRRL٥0$%%a/xzzvvv AZH&/^xsdeeVᄇc{AP(ŋWTT]D"IJJ޼yX0'(**}"FPTTDIJJ_f檩A'ElS}kKKK}}6lo7_ N>S\jQ;BCUUU^^^ ׮];(++þYXX!⤛0aN_L;;;5)Sh|PFF K INN477A5 qqq&M葫k~~~ZZrݻ'NÇG>rq2VIPaٳbbbXYY211Mv-p819/_P(ʺFLLLOOo…gZZ` z<f%ǏST2,/=#C,jjjbbb?;~ӧ &Llnn`0۫333KJJ իWkSSCCC;::v_c"|X,WW/^hii %$$dX۷o銊[n}'IIIƍw޶6YPP憽`bbbJhh(XnQ{jii)((:theX{'&&>'Oc~L>sLRzz:0DGG#_-رL&/_fc{yyhCx˗/coh4%"##W\w,@X0 ;s OF P(===Êgǎ!:e˖.#,Y{!Btpmll :Ño߾-!!O?qsrss8Bh„ Ǐa$))) Ek`4nx>۷)Ç8[ 622yBh͚5X۷o FL7K.iJ&$$ VVVJٌ۷!ggVB馡A^^/, .400[|---J]lYuu5_$ILLٳx? r{r8ݻw7!$--iӦӲU]]aGt{qqӧO `={HHH`+c[?) J`L!Z͛CCC?$??aZ~))3g` ...iiiqqq&L;" "w`0!33E9::M2bK?HI󏘘L ; bn"""H$<_ZZÇ?fddHIIq8)-- !2xELKK OMMVtt ...?~rsss]]ݨ+J FBBڵkBgϞarɓ' Pff&899=yd8ayyyyIJJxرcxGDMFFVlͥD"TTT<==EӧO ݻwkkk ⤛]] /ﻺF3pZb)::xDq:1`7&#իWbbb-*p~IĐ6k֬jww۷o ݴ#FԩS+}7ى￷jnn \x8w7{}#RSSSya]wuUPPRRRbggfedX,ѽ{=$KV3%vd2O:qni4Zaaݰ.lhhTVV  lSSXwDswCPLMM_~=˧MfffvׯMMMGp8r䈆F^^ݻ322 ! Bhԩ/^w޹^z˖-#ٳg .8jjj9s˗/U "ƍޕܬddd͝;w?upp ?vrri cE[btɓ'9yϞ=Cof~MUUUO/2%--=zt՟+o޼?lc1 YbBvv6G~Ny>2omٲD"BL{{9srsscbb=x"55u֬YӧOz~+)..1cFAAɓD̵۷ ?~̓1߿loo%5+))9tPrr2 D⯶62s4lkk  H֭&X<c >P(FFF===ׯ_ӓEӧOh42}vc`pc""I$3g?yU}}'MDPr;l,?Gإ~(ŋor8ӧO4I[[`WWWdff&$$\DXA< Ppvv555ڄݍ}gggCCC $ >{Ȁ\` Yf!ܹxssPw744XZZnܸQSS3??=ZBkoSN%Hqqq /8\xQYY9==}j-X𕌌LjjjPmُ=RUU666;"xl lii} ѣG~~~>|\ilss~lN Ν;F%$$@9@`c+8::r8~ߧq'11`ܺukŵvvv`t3 l6[RRRZ޾#""Bt ~[KŪT*5!!g~յr̙4Ee0YYY}ttt槟~233khhtRtt40vLNN{S0[O>h1111nL#I7+++ JNN\Ơ1nRk666޲e ,))o7l̥l#===k5y)Ν;߾}ʧ~cnJJII]p8|XTT3gL<ŋVVV.\DǏ𡏏Ouu5W}}w}G9R__U_}ݻwkɒ%!YYG.j&22RUUUMMýtժU$iٲe Cm9 ,¦L&555fX---&7 k׮%H7oD1ͷ~Kтy2Z]]bJJJ㹹jjj!0O<m YYYؑ۷d113gp"hO,d2 DH7l6[󶷷h4 "Ba0UUU`x^DҍN~~'-((@ x^DҍEZZ'MOO000."'' rǏD "B?~|XXf 5kf3BYd{nomm )͛TUU===)n)//y>cA6HKKwvvl6;66vЏUTT>9ܹs;;;F,cA BhNNN2eJLĽ3=DBtbccsڵEo`TZz jkk7ˡC҂7DEl[?kkk&y >}:cƌ|pP!ke˖}۷/]Y__?޽`aaqhe0 f͚ٳEx7<L~;sLZZڋ/8r_lـhx"СCvvv~~~(--J7_xq|СCWXQQQ:>\oZKMM:t;p%Ϟ=榣e˖cmFsttt\dYIR',,,~}2Ƅ{7ͫ=u{ァP ˗/yfbb|@\Fލ&xɓbq^^`ŋk֬Ϟ=KPFZZZf͚ehhx5sssBdXx}ٳ h9x3Eo2w޵"|kמ;w޽{Æ #|pmۑ#G޽Ndԩ===YYYl6){74&Tk6O?|$M\ի8rٳƤN4\Uuuɓ'wMva0l6;..쉀f NNN.//g7JJJB!˵?~s'OВT*޴iSHHϟ_]])ɮ]prrrg;;t- <^&,Znnn۶m۸q+W`kkuy(7@ipaLK7o޴uppyɓ'M+ӧOg0'={vFFIZ3f ヂ+jURR٩HR冖JKKG<`0O>|xoo/l冖ꬭ>f׮]֐!Ch9(7fbbYW^5kQ̙SXXtCCC&ѡ`]1LEO>|U JKKGI冖x<^[[g l]RRKz'H$J  LѕճgTyٲemmm8OԪ Z>|xYY8::bp_^^d2@c<ĉo.  RÇ722R$)rCKSLyӧOյw7_ux}r Yd冖뗔`ʫW\ӳwޛ7oΛ7>3Hmm۷}Ղ+ꫯvuuuM0ɓ':::2g֭6lV3Ӿ}bbb ]=zҥKsyJ{{;겱?WwwêUvڥl^_\:|pXXXUUBE ۷o߃?N,Ϟ= ߶m"ݻw8pdy]]]2 455ݹsGEcǎ޽{wԨQ 76}ܹ___7:r_ 0 -->(Lzͱ| Qc-o4Deeٳ /P֭;{cVZE\FFC 6,''{ǎ]]]ʍse77WBĂr9...166V222f̘1wSh#(7f͚5?,--WX{:===999ߝ|||tuugΜР ֿh ssA\ .H$C חH$BB,ϟ??99Y,,Zrs[ŚiȐ!EMGGG\\֭[Νkll,l]]]'LAAAGٴih{;6444""{ݻ[[[qn5x`Pލ p8/_p87KLLD+W$-#FpuiMLL̙sŗ/18ǏɩyټՍپ}T*=rȫ/>\Ѫd2ϟOt@h'O:::6۝g˗/Ͽ|2rQΜ9ڞ{|>_*;V -[FhFhpڢʫW2iӦ):Ŋnllܽ{71r9***?~|^b2nnnJvZ{D"bFsX^bxҥ*kXl``0qě7oVTT(=ʰ>(n4DXXXooÇP(Tq'dŁhǏ[[[VWWX,PepSSM6 \Pn4 ZZZױ*Nq!5k֨8fPn4AHHܷoV)?Ҳm6Շ rZXXrq6Stttkk-6od2:$fffD͕"HVzJϟ𰰰{@]]kg>HKK'jL=[dddOO7|XٷD.pBZ XZZN>]We273VUU ̬̙3g;Ν;---R)#Ƃ\nHH{.>|8S:ucݺu 4jnneCGg􌏏WhCRUPPL&'O 8)))2 Rٳg]\\1BwRCeeeݸq)rCKǎڷo_tvvJ$7m觟~Oɛh(7o>SSS__>.:r{=x y~|_|a>['O&5L``ABCCb1 ~6ofaD-[bbbww+ȞlJ3"pƌW\H:58qbvv6}ٶmۛM2媯QK(Fjj*f흜ydGGZB1CM7(7t5 {2l„ jx<}rC'ᆆxnʦ8,+&&Zn>@ I%Kbvj*{{Nu  m39ȈPKJJyI9xND__Ν;x277^7k֬9R*zH$oMwTZRRY`AAř}066 ,--=w˗Ba`` ]FHLEFFsU6Pnh`AAA8T̾Ƿ  =P[!rdz  B1@:I&ER/UVV˝:JRh ^rCu)))}4ɔ֖P888|JrCi}4ɔ͍P 矡&x EGG$Sl2sᅵqqqPWvvvmmƍ: ۢLJ\ZnnٲE"rC]:::;vP,lqf aԩS1k(K=<<[ZZH1cܿٳg @ W7uVLo@ 4h9*`!rCQOvrrRbÚ#FJyC Yd rPnرc( {{{ǎKN.8qB__Znj3(7To>cc?X ԩSɥ-7dZJsͷ(7mܸZnj-(7yfo>%-,,c/twwC©k9uTlEd2>OB4L2%33uV3BBBp6ɔQbࡸrC- 666Jwtqq!:,,, . $%%(w:eѣFFFxMB׮] #:);P0@kPn痖.^XX,]%-]122u&Pn⫯b2JPZZjbbBh(r%''K$E %HK.?TA5:o޼K. %DDD($S/^899JΝ;p`t-=I\uuuR3?~|)Yܠ؈I\c)v5 Pr^ppBM2{.".Ƿ)+3(7555|G*-$(a-7&Y  bbbTBZnj(7%%%[YY8NCCApppX`7rÇE"QddHRHNP.4N> -758`nn>{lǡ&~8酇CM IuT ko@ř}ؾ}TPn p8f͉ȅXbb"Ty(X̹s^xQќ@D4|=; \)<<\">|쉄B=ٳNrr2͆Hqqq֞ե͋3`jjiӦ_u \|Y(= Ɣ)SȞ:dbbBR5 (7 ۴i̾?~ZnRbb$)((rj&A!$СCj\ WJJ ܤ (7dzxxXXXaz5LD_NNN|AZZZ~~>,OPn5o3]GGz梯D.pBA &&rj [9a5EkUUU?,࿠ܨ*33^m]ְř)mtsNKKKT: `@!@PPΎ;3ݻwL&|SNutt[urܹs$S.Xٳg{zz.TF%AAA2ȑ#jɓ'Tt 55U&TF%gϞ9r:K BF!C YdIVV֍7PgvPnwرH*H^yN8駟(o߾}5ɔڵk8S '**h5(7J***j^y`0&OI5ƍ*Qg^PnyfRdu}]]].I5ƙ3gaBy2D"!M26lXww@ P礚kYQQ\Bn"J3U܄EQr{{{'''53U,,,p,ʍ’Z[[5X|||kkk@@ Z .ϟ?/,,裏PgmR`XP:_\6oތ5xAR==PjjT*jwww+++TlmmQͮ,X:rn$MnnnhӧOBMAyh ٳg Յ qqqh2(7][[i& oVVV[lH$h,(7&rX ̠ N: !Kkk+k_FV ƌs'O <u W7}ٺud3kkkrRM_~g'''[̼x:gr3''  [hc`3=<<XM$;i<(7ogcc?m4XNX(Y4 =zTUUE C7qFkk;wBMbAoӦM,k߾}0 `q/rp \IԩS]: QQ:SL̄rj)WCC(99bCqA#!!uT*Dh# /Zn&!!!0>1rG522R CMuaaak׮Eܺu gw B4KKK/^:lsssAҥK###Qg=(7k:N풓%ɢEP=(7J.]255E,Du޼y.]***Bޠ)""B"'Ny&,Y[[TWW~zYY#,ԥW7aaaF䭚 rsP6Ǐ[[[{zz"X,=z4 @6m*))IJJB\pRkeG-N211Yf ԥu&$$D__ӦMvG [ZZmۆ:EiW%%%i)W~~>122B()::u*ҮryfJ5ɔr:RɥEF*?RM2媫:t(@I#G7o^ZZZ~~>,E&22RM2joowvvF(kpBA(GMLL de27 @yXͪ~ujіrY__:;`3M:P r_*B!Rn\.Pfee1Lx3N8M~_妹977חŢ Quww?-7_!($S.>Oz@i)))rUZQn]\\hP(tpp@ZnkIֺb 0?h~255Eݮ_`0L: ݻw/hxdҥ8kACM /7l6{Ϟ=RTTrQKLLD+WD1M{(k) iP.Z>_ZZdAT-0` 櫯b2@DU=řIIIdѢE~¥Rם;wPgQ>|:.fII3,MDDD"ojnn1bҰ]*Ay{{*P;vXAjFM˗/755B41uTAEFFi@M۷B|-7Tn&} (,,ӣ醧@,XBtY߼y3AGFjjT*cOTnRRRݭP!Fcc6,X:hSn<(###Q!LWWt 9}.}[nҦDGGϞ=ub`4q>P'==p>:2Qnkkk5WFF,Jؾ}Ֆ-[$ , G p8ᨃ&//g$&&vvvc84X3jjj:w܋/BQF Z?y{{=yd(W7[ndI X[[N*550 A矝4l/^}S/_:^n~ǎ6ɔN*Lx}}}zm2GrgZ7ɔի c騃cXQQQ4Frѣ*Z7ɔݻ  u@oXpH: ..7,FN4/".]:.}. L5$666糖M,++sttD{uK&r544L@&-oR?~F1JRH:_~eqq1[nR$''B<ѣFFFHrvZA3;ܤbd.^uRlsssAFYt#[nR`M2Q!EYY@%''S&ʍT*t钗),ř ͻtRQQ,Q`M2<:YF:LΝѡ+7G4i g3ux<^ppǏO::*7鍍[9eAƊׯ߆ PZ&88n۶ u`řT'Nhkk۸q# Pijj*((ƒS 755?( 4I\5559AJJT**7IIInnnYQMMMÆ Ch>;;;??[na)*&66V$8puѣGO?GOQDEEiRLnݺ`04?.{n@@.&(7$S7o23f֭[)r& @Údu}cdd:""hʕ0(yh{{ɜ9s4I\MMM 흛[SS3tPI_l߾]*j&nRSSLQ@9y򤣣6<ř f~~+W&A\nΜ9޾k.1ԀKqơQ||e@\nv>1[ ,+::yMѣG˗/GAmL @K]mMk0|8 ȑѡWnsss5I\<u Znד=~󃂂4I\O<8p UJJL&SB*gϺhf8Pr3++ƍN!dꦦ&HfMMM bkk}ӱcǺ$2 P(x(..uX;x 8r{zz.]~zgg?L&O5=zt@@@FFT*32k=|0**ܹsL&sӦM=zarRisssMMMIIIvv={pWjW8p --ߟ4i9͖H$UUUn{yy, Nooٳmmm?N%%%fffk׮%|dAׯ722zW*77n`X'O$# bÆ $O4u9M֟| IK$WWחo-7vvvK.%) &%%d޺uYTC.ߓ:Kppp~IV\iggFϟ?ׯ_hh(Znkff?p̘1ܣ"ܹs'NH,]]]gȞLd2zӇo-7---&&&QQQdGllM*ݾ}`ܾ}[ s>}ZGGG'1w\5Lz.b8tО={>}>---mjjxC6mBI-^ٳgX7㏛];w\pٳgC]x+Rken=rvvNOOQĞiӦ9YO^z@ EBB²ebŊUVUUUΫWřfԣ… ׯ Ƽy󪪪bVZ?g'G5ϟwqqY~}UUB'>}ZΛ)>;;ԩS_}"J08GJ޷o&!!T?2Ç|+LOO9I{_XX3zhw|֬Y3i$9W7ׯ_7n^m3d2 ?dΛ7[F)ׯ_1c. ˗cq`gg7rH ~+xiUUvMӕ+Wbbb PJl#1o޼9&;;{رwlll^}+'fggSMDvv6ѣwzxxZ<==]& q3q;w(wuwwʖ-[߂kbXN)..vqqQeh>`0^SSʼD?{.xlBNNq\\\ .Ŏ:::trӧOmmmU`(6gTXz. l#~:kR 7PʱWqKKp8a3\T 2ϟ?g0ojll`0^xssssL6fxUee￯y@򃞘:fgl$hmme0o^b8طPd2\er~i˖-3fعsB'D"qҥs*75ኊ+Qbױ$WmطHҿDrXXX444(1\KKˬY.\hfPb^`a+ ƛUqtuu( 9N75ӧOjc3+z"y[Ϋ|bՇJ;;;r*JrѣqP]]=iҤ/'OT|5joY,kOJJJqsѣG+\F? Dyy7S&L8QTT4eʔ[FDD(&##cԩJN &_8:x3g|1++K,Ϝ9_oo[(cܸq,+33S޼yLέ3gJK.-\TTTL2eȑO<ٱck_]h;iooOKK;v"aΜ9Gyiiiv:tV;¸\pΘ8k,ՂV&&&ǏONNVhRRRfΜ)ʫ>HLL3HBB~KK˾H'---###ra== ~&LׯߛaƍS*,x=zĤgΜٿ?֡{֬Y!!!G),,szmm-NNNo:::]UOOW;%<<<<==>۷9s=)>ʕz''iӦ& rѕ+Wwhii2d7l؀xO웯;881❧yS\zd܉rSWW׿R?d⼝VFF"-Upp0#0xHٳg;::t󭬬/_wtѼ~61244 "|dDFFr8 .>~d2PF;;I&J(72ٳ,oQn޼ibb駟Rԛ+]]T}~z3y䊊 2Xue?l``p, ŋFbX;{l̥R۷7md}cE;`իW_zU"qH$:qpp8sףGϟ`0Fua@񕕕wttd+VE }d;dzxx6D(ԔFZ2J$>}:>>ݻFFFƍsuuׯNwwwcccUUUaa{bӿ⋏?!j*));sLss#<==nmmRi[[ӧOݻWUUeeet 6s&eK7nܸ}l&L0m4'OܸqΝ;@(b==~ :cҤISL߿?ӓ}ƍǏ׷X,CCÁ:997nʔ)cǎIrm;*rP(75rP(75x(+,<IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tetrahedron_isomap_noasm_golden.png000066400000000000000000000474301450372207100312170ustar00rootroot00000000000000PNG  IHDRzzNIDATxwX׻8𳍺qiJ& Q5h4Cb4jh0v] b@A(/,}/s._2;sΛ<:{fR9۷oDDD qE|||G00ýf8p@KK?gWNNNOOg;wݻWSS/,,,@ LCy󦺺ܶm˹ҥK&&&bbb[nmkk֤b6ݰX+VHu֎`O4͛7# Hܬݔϙ3ŋ3fTeeϯ\2w -^)--uttp8ɣ5!ee刈+Wzyyr4q}}YbbbƍǓ))ʑ#Gdee###y2,@ e#77ŋ<{7nxꕎ͟djjʏ;;;dӧOa?l߾~SAhsΥi ͪURRR( _# .,,D| ~wҥ~߹!qq~Oȑ#zzz ,r3g888py_z 2ե~_\z5FpB}}}LL^uu5!=z3HILLDr9Ddd$B?OXqM? r2'jkksyt{^zA< I7III\^bnݺ%!!d26mZWWW||@ n MCCq())q;;;< rI7\^_QQw;} ,asy>@ n丼!$!!8nGFF!4>6{7$;;;=6%\^mx>pAAAqX,B AҍﹼK7555!"{d Aҍ~NN׫H`&&&\K&< rI7'ONIIzEEE''~={rssr###2 nM.XjBGrrr$**Ņ˓htcgg'''w .ܲe Lgg/B9y$#>s8D FLL\!))y];;;ӧ+))?zJ3gHIIM4i8D~,**Օjjj444U]]!daa_M6b&M4amy`0&O<܇AAA===yyyYYYΪ )i4کSEqq1No]v1 ;_ss3_P=·o.++ϧ]]]MMM;::}tmLvvvS *tvvۛ655c[JII J޽{mϮwU~ yƌ3ZZZx;)JXX'd7n>  H7"S]]fC"0R%%% N7'77WGGdre˖;wnd#$%%a[^FGG2$`pn8Nuuٳi4/fG6ٝ;w444={6zխ\R\\!o߾Q7n 9v옼zPPڇN>D"544(۷OII Qpʕ<CH7~IFFFVV/oxGGGbbۙL&D|/bDDD)xn"Ojll|rHHHbbbWWdWWW]]]vvvqqqwwĉ-Zkhhȇ 6vw0aihh,\8@Rm&!!|:C`c166nkkC]~ צMcccBBB ԩS_zw\Ӎ}OOBy&f zjZZZq@d|L7؊/7h-[466|wMTmQVV}pl߾=??B=zTWW >``VO>D<ݻLGGǨ(===cctЀr _'I&744Ν;WQQ;4DӍ%RPPD<'++f<=8\|ymm-ޡ nMpttt:c΍CBBmmm?w\B[[[qq1_+yYYق RRRO8w\A:;;B/^\=8 lmm]v-N_n]kk+ޡ n= %%%###=`P]v]~]MM222yyyxP{ׯ\x✜,8}}}p@H=ڶ744m]##Ƶkזzyy)((~nR еk=^tcZ[[9"%%sN KVUU‚ !TRRBPoɓ'׮]SQQILL;.ߚ)qeeewwwii)7nuVgg?7 Vx]PP0u>`:ᡢֆ\~4<8c ҍi]]… {zz=z$ LޱcGmm۷555{%t3i$Ѫy}677-..pĉ^>As""""}_~wh V9BZM7o^VVֻwܞ>}jjj:qP`n$ŋ˗oKOOyeee7o, <1R[Wssspp͛7jЀ\166vcPWW%yRRͽ{455bbb O\ꪪϚ5KYYyϞ=xe/M޼y#ف|?Ċ+9 bVV j5=8444x񢂂ԩS_zw\nLfEE5kVZZZii ^z5yd--g ,A[[۶ &@?aaa[lillͬY _t4mϞ= /_VVV g.((;4@N7...hԩSw233􌍍߿w\ndtJJ Bj5֤I ΝaN7!555a$ j5lpp0>x Jݶmkkk $ҍ)J?z* ?Xcc㐐EEES qCqttRj Բ ٩8q︀!̟?g looZMf[[[׮]K׭[ڊwh@ntuudӧO{_ZMCRwUWWwu55Ǐȸ^8e8V0jbQx✜,8}}}O)++d2** ׮][ZZ奠믿ƒs>ʊba]\\yǎkmm=r䈔Ν;%$$.]5t ZMBoʞ!LޱcG]]ݍ7{ҍauu5g;-Z=8744ׇcn޾j5 k׾~ѢEƍۺukWWޡ>-̙3!t]UcԱcZZZeee+))pBpK7666$ {233Z1ϯ811:<<|„ nTӱ?ϙ3j5ǸS>;++YUUСCxxtݛ_V` ˗l]{))b-<Ӎicc#g!-- C&o߾}i99ӧCyH3L>ᤦb?B_M0мy󲲲ܞ>}jbb2qP#g7oBwӧ755˦`'FDDX7VTT,[L^^<ӍJMHH~Ėo.1 }p{C\3`8j.aΓlllbbb |FOOo&j.$$$֮\277UYYyx> t3eʔa?`Xƍwܹ}!6o,))jժCn 6p8pW F 2""d?^AA1##9̘1exo&sww(**;wutt.^w\nTtz jҺsNkkMjkkWX!++?vttژsڤhffGFLLLMMMgϞ?~!--=o޼CO7uuu?Ι3Z0%%޽{ZZZfff>;1tcggݯV… xӧuuu؃Yf)++ٳ 2؏P J^^YBBbŊ\O7L&L&?yj~GFF^xQAAaԩ^;."? 233{tqqijjM̚5+--t^>ϯpܹ{m8.H7t:]\\e8j!++fe--ӧOht fjᤦf_}<8熰l;w5.>Jbί\=85kaI7SN2e? e˖feeM6-&&F__^HX BHFF]o&DQlll}}5k_tUTTj#++{ĉ#GHIIܹSBBbҥ}YBn{[c\]]Voɓ'׮]SQQILL;.< Qqtt2!b ХKp sttLNN.//Տ=w\tշaҤIT*ݻh/ׯ^nX/DFUUopfJJ ~A3d2yǎuuu7nPWW?~kNNޡ iTop jYhQNNNvvK\\X/\d~Kr8(/ ׮]E7n֭]]]x/•n ZM@`RRRǎkii ݻw… yS/\+ejLf0Ϟ=5.ϯ811:<<|„ Rtӯe8j51uϟWUUy{{gee9;;:txp677|7ne2@ٳСC555؞^邌۷/_ͭ޹QUU5441c ]oll=R__k.\Cwټy۷odѣG:ϟ?heee``&##prrr^z`bbrJ??b\P(JKKB!//ݝB ^ʏY˿k11155955uEEEii退!tsPiii߃VVV`7nFmٲ'#>|XFFFOO… f;vl„ ΝiBn#G=jnn/.Kpp&˗WYYhFkhhߵkW{{inn)xХC&-[?_P$[[[=Í &MMOO}H?VVVvpp0##~TN ԪBR*^SXXoff/ݓ)Mvvvsss߃zzz|^ٳgϟYSSuaYY!onnhqqqrrrJHWWf 3 .E;m(>n8.166tYXXU&QPP0qь8qDCCC./P(›n-c9FaoFZEEer8Hooo55/CqCEEExӍ3wj0l6[JJjWPϙ3ÇABBBxӍ'Bh`p;;;`(Jwwplll,..~L4i;::oQSSP(ϟ?wj0222)A555CCC=syCCe8__X_+WMCCd|}hSTT$fĉZc}5>}SP6cc| {怜kjj:ذ-18h:u*c<==RATP-1P 驫B~~~zzzj߷t6h)j0 .z*'KJJn߾=&&5++ᄏx񢻻m۸ƍ .tCR%%%ZMF*###11׮]gGG &,Y͛Τt횚+Vc'&Nb***[`h!!![n-..P(nnn<F__B}w211x|ƌ, \ڹsq/_^[[c~}v$ڷoW.577cUK}eMd27{}}= 2CѠ&SRRA&M$|!))yƍ@N433Ieeeyyy,L&KKKf"n8 R`` B~GSLxUUUyyya+׮]%>+W $aMٳ @& {{{ee[nY[['%%gC\ӳtR777 # |-P ݻL&[ ?~YY7W%%%a/yyy LVVV~@a k֬iii5k֐H$II۷o9Ftcdd0GL&j5(jooF)((޽k߾}mmmg<#k7kxPP]]ҥK:xڭ[rymیkkkϞ=/))xy|ǭ#G ޼y3#Vxdee999H$la]^VVgaa1&t5ڷoVHCCC5GqqpG?):pb/I7[#ɓ***؋~~~q!{w"v Y[[ <"յyf5kִر588{{gΜQVV ə0aB30III +;^}}7F mjǽZNN4QimmB.\#.W^^ތ3BBBLLL={VTT3 FBBڵk`a'Pt:}ʔ) kbbxNOOOe$'QJ7l6!zx9u"&&8ў* <.++zjfYYb ''˗/4^!w]]ݏ+|2~яm>1XRj5a)MMMy2?D ɀIݻB>|SssslCr^=?ٍ?"Jk7!l{D5#j;SVVO]]]ll,OKڵd:u*!!aݰHc@uwwر{HDӷlū{?lKTn>2VSh7jW\\!4aST 2 nհ{nЏdRbbQZZz_nnn<i̙/_֎OnBCl`d^xamm͛,暐%%W^c-׈dqqqp8ϟ?wvvfee <. ^=uԌe˖UWW?~ؘSttt._\NN.--?osÆu_ ! ٽ{qBқ6m,#A[)nh'OlD@YFBB!ħBϞ=,"D$ZcV|LYY֚޽{+11uO#zk7!&YQQOV bkk)S}ÃO}Wvvvw ÊHlٲ!7ZM!r ]]]J]xqee%_{ Ņfu.#&>>!tʕ@:úJJJnܸQe[l!H.]\H$Mww7Bh͚5;j526~zӛ`z<RS?***o޼پ}{NNB w [)++ 6( Pv۔\~ X,[[[´QM7X4MAAhoo 6nݺ%))I"6n(Ee>=~8$ŋSTtwwG?˗D8())1̏}mRĐٻ 6X[[X7o޻wF >Bj䰖6m yyyP)Bjkk-[Jkii[vHD Ñprr℡7B۷NNNJ;Qd2F:u HF:15ac 6}L&8qBGGx***sssMMMƏc0#k7!cc㚚!NpttZM!6s|__(|sÇ544ݛe&A޲e U܎;acz "!,N7CC"|||\ccBH]]̙3xG?.\ &&F"6oތw,'醛l+@yyy...~=;fBXa7h`7C/[YY0"v`P"n8a]]]WSΟ?1mڴlhl{M,\pܹ4-!!!88 oFחD" qj Rwww``,Va( +}%$$`/^,lȧ3g 8GFFJAE;PǏ;A\kw,cȧjЎ;8jUaalbbwDTVVF͜9S`D~``8j5$!!BGG'::);;3g;~'lsK.EGGcw<5 Ps/_ZS.[WTTjll;NnC GM8QLLΝ; v9nܸ˗+W+++ JNNw<0tp"5kHHH`/ Jp*###!D={6B+ҹsʞk;!p8:>eʔρZM]vMWW[ ^x5I$2ϙ0aj~ݻBRRR"Jo'!`v255B[[ۺu$%%grAE%66VAA!22ǧZ0$899q'jT^^`:~q o︸tҙ3gHG]pp}{C ŹRRRL٥0$%%a/xzzvvv AZH&/^xsdeeVᄇc{AP(ŋWTT]D"IJJ޼yX0'(**}"FPTTDIJJ_f檩A'ElS}kKKK}}6lo7_ N>S\jQ;BCUUU^^^ ׮];(++þYXX!⤛0aN_L;;;5)Sh|PFF K INN477A5 qqq&M葫k~~~ZZrݻ'NÇG>rq2VIPaٳbbbXYY211Mv-p819/_P(ʺFLLLOOo…gZZ` z<f%ǏST2,/=#C,jjjbbb?;~ӧ &Llnn`0۫333KJJ իWkSSCCC;::v_c"|X,WW/^hii %$$dX۷o銊[n}'IIIƍw޶6YPP憽`bbbJhh(XnQ{jii)((:theX{'&&>'Oc~L>sLRzz:0DGG#_-رL&/_fc{yyhCx˗/coh4%"##W\w,@X0 ;s OF P(===Êgǎ!:e˖.#,Y{!Btpmll :Ño߾-!!O?qsrss8Bh„ Ǐa$))) Ek`4nx>۷)Ç8[ 622yBh͚5X۷o FL7K.iJ&$$ VVVJٌ۷!ggVB馡A^^/, .400[|---J]lYuu5_$ILLٳx? r{r8ݻw7!$--iӦӲU]]aGt{qqӧO `={HHH`+c[?) J`L!Z͛CCC?$??aZ~))3g` ...iiiqqq&L;" "w`0!33E9::M2bK?HI󏘘L ; bn"""H$<_ZZÇ?fddHIIq8)-- !2xELKK OMMVtt ...?~rsss]]ݨ+J FBBڵkBgϞarɓ' Pff&899=yd8ayyyyIJJxرcxGDMFFVlͥD"TTT<==EӧO ݻwkkk ⤛]] /ﻺF3pZb)::xDq:1`7&#իWbbb-*p~IĐ6k֬jww۷o ݴ#FԩS+}7ى￷jnn \x8w7{}#RSSSya]wuUPPRRRbggfedX,ѽ{=$KV3%vd2O:qni4Zaaݰ.lhhTVV  lSSXwDswCPLMM_~=˧MfffvׯMMMGp8r䈆F^^ݻ322 ! Bhԩ/^w޹^z˖-#ٳg .8jjj9s˗/U "ƍޕܬddd͝;w?upp ?vrri cE[btɓ'9yϞ=Cof~MUUUO/2%--=zt՟+o޼?lc1 YbBvv6G~Ny>2omٲD"BL{{9srsscbb=x"55u֬YӧOz~+)..1cFAAɓD̵۷ ?~̓1߿loo%5+))9tPrr2 D⯶62s4lkk  H֭&X<c >P(FFF===ׯ_ӓEӧOh42}vc`pc""I$3g?yU}}'MDPr;l,?Gإ~(ŋor8ӧO4I[[`WWWdff&$$\DXA< Ppvv555ڄݍ}gggCCC $ >{Ȁ\` Yf!ܹxssPw744XZZnܸQSS3??=ZBkoSN%Hqqq /8\xQYY9==}j-X𕌌LjjjPmُ=RUU666;"xl lii} ѣG~~~>|\ilss~lN Ν;F%$$@9@`c+8::r8~ߧq'11`ܺukŵvvv`t3 l6[RRRZ޾#""Bt ~[KŪT*5!!g~յr̙4Ee0YYY}ttt槟~233khhtRtt40vLNN{S0[O>h1111nL#I7+++ JNN\Ơ1nRk666޲e ,))o7l̥l#===k5y)Ν;߾}ʧ~cnJJII]p8|XTT3gL<ŋVVV.\DǏ𡏏Ouu5W}}w}G9R__U_}ݻwkɒ%!YYG.j&22RUUUMMýtժU$iٲe Cm9 ,¦L&555fX---&7 k׮%H7oD1ͷ~Kтy2Z]]bJJJ㹹jjj!0O<m YYYؑ۷d113gp"hO,d2 DH7l6[󶷷h4 "Ba0UUU`x^DҍN~~'-((@ x^DҍEZZ'MOO000."'' rǏD "B?~|XXf 5kf3BYd{nomm )͛TUU===)n)//y>cA6HKKwvvl6;66vЏUTT>9ܹs;;;F,cA BhNNN2eJLĽ3=DBtbccsڵEo`TZz jkk7ˡC҂7DEl[?kkk&y >}:cƌ|pP!ke˖}۷/]Y__?޽`aaqhe0 f͚ٳ?qk׮y{{`lٲGl)B={v\\\lll>}Ȋ9a==m۶B}ٳgӧ/_L@ر=йB=INNܽ{E(JzT$7"C]>}X[[GDDBM9{lJJJzz:Y Ɓ ?x`4A P|ԨQ˖-#4..m#No.\ Ϥ.\Er@ӧOqFAA|%%%%''O>m#j֭۸qv)EwX qwrrr?~f7AW\y&88h4Zrܹkע+bggL] @ X`A jGmmСC xDDqP)ؽ{gBCC"A ԈK__?...00jݺusybbbV^{n''>8,8;;͟>} 677gddѣG\.kngʕ֯^Zj{8ӧ/2))tn6lr% @(O<155~)MM͓'OʘN o c̙|>O Iccѣl6ȑ#j \U_0<2~ۛ`om6@r@ gΜ >u}[>gɒ%ׯ;!A T޽{ ܹf6Ml޼?ҥ F믿޾}f@:h ?Ā@7o޴iSss ߿Ç?722χ׮];~7 ,--AUUU~~~VVVeeȑ#;onn~ӧO߼yS\\\]]㸦DzMinn 0`ٳGLK///U;w@kGSDg&:::((ӧOnW_}Y]]G555<`P:Z@tJFy=(-544ZkKKKOTiG Rs16 455`X5x9!o@)B),,IMM555 b[^h1@(+WJOO_jUQQq3fLZe˖9k *F gϞ}ڵk37nܥKLfMMM{Z񌌌lll5QP |{> &00ҥK CIdc~pŒ3jjj~e#QI&]p`֊њ脄3gۓ1jA)B|.\ꫯ$0iҤgy{OzzzB@)Bal۶ɓ'+++Bk&O|Y:ޡ̞=ߊ4A CFFϻwuvڵܰ3uSN*x<=====z$èen"OTXX{Lf2h!q͉'x|K5]n֭[1 ჱD}yNB $bĈ?Ӌ&7Hk޿/l߾=//WNh1@g۶mt:ðyQ~`VXX(iߊ ѵkW*Fhv@tLFFƈ#rssvM?i&8133WM(Zeg̙1_~7o󚼼<)P LV1."7\zA;ؾ}5k0 {yN(jkkÇ777GDDܿ"_dggK5sU9Q=B P jnn.QHH\CH!++ ð}=4J@)yOffeTTT=˵sðׯ_wM ݻw)..V1~@ȋ~.;;{j͞={dך̵kv AĿرcKKK{%:INOOOI< f7˫ɓTk@zzZ?~|CCCdd$Eo! ɓa˗IHH&oh-HqqOrrQxxx ,Ĥ1LH9h1P;֯_oaaŋ%KGkfʕ%%%\ZErr]fcc#w}GYYY999x 4A`ҤIeeeaaa/_=zjMRRZ ׮]#itEћG\|B;5Hرc-))IhO,^)B2"7,]]:Tُ?>c Ǐ===euuu9Nii)I7h1PYvibbɓYfUTTYkN:ENZSSs2F =B իW]tt5##C5LIIQfs Af0NS%sAIHH +5ɔ P7a„?R% .L0j Y'z={H (V1B :~رc2˗/wnXr saqc* $7NL^^#‚-R#Қ|yN$7ʒ%KphׯWHD.jP(r *Ft>=z4jԨwwh)2ȵk֐{z_xxDz@H@CC8qB^~EGGsy p) 7,P5BNY ͛T@llaW\1b㏌ 6ts(Zظq#Fq|ɒ%>W\!=xmm-277'=A4ܢ">goofIϒ[PP g7,{{{C  =><'=Q!: 999 ,ppprߕp8++߸qC\AAA11|r_穈I= .1 :۷o/((6F.**|Y\\\EE˝0a!E+WL6;<<\y. =x`PkƏOE SSO>u:s(ZJٳg ^^^gΜ^ ܿo,kxYWWڵkdpiRZ p1+$7ׯa葤?|pB tٵk0l֬YR B>|Hh4ggg+Hnm)_ϟ;::ݻwiٵkW@.]eH?ZkBaϞ=qˣ.Ar[nXnݺegg~ʔ)g-rڱcH'11j kS{ x۷/#15k0 [n]ˇn݂ؾˊ ӑERRYKKJS\\'҃/[ ǏÍ!xtEKK… ":tDAAA2Y$7k׮FFFT,k kĉMMMT䒝dh <2dY$7zj[KLLLO>.B9pչlllL&I% TVVX,9|2:ԤMkvسgՉtʕ+FFFT߿vvvqq1ՉիWNNNPkϟOi.yneeMi"]D>h"&==="""++‚Fuq֭_uxxѣe8dffBٻw/Z]{|~TTՉEOg۶m}`{>?qD:㸥%͆[7o&]!Off&aPkzO:U$7}>}_h|R(ynܸ`m۶1 iK>" OF===U<'X.#d ///00`㚚0ѣGa;;x<1GnjjKQ,999ݻw !!!˗/CWTT;vLu< hC(xx5ݻwlvKhIhkk+R"''Gy)tJ+pŅ`{XoG- YzHLL899=\!ƻwv wpz|)HnԝW^q\mmm߽{jPOOP]]O0}II%/j <(up@ A/՝2hE*/'NxbVVV}}} FSS#(ljj e"??Mk,YbnnqFdT6ܨ; xwZYY͜9(??Æ MMMpC0N&"ٰa׫91ܨ;L&x{8 駟D{ٽ{w@cc#8|>_!'ڋ5}T@{7ꎑQyy9\.PQQ!S\\ ʓ>XXXµkSkcǎp8ϟgReɍPUU'gyFۥ%%%"ٲe/^ '--MJOII@ Xb$$$y̫ Qw<<QT5eee"_Tȑ#EE3D(nݺIth"<M0Ž;t|n » )1=.\(Jpl_^^wpuu 0,{!ÐRQQ@O Alʕ+wihhX|U~v x޽ #bF< oƌfKJJkTgxPkIKK0LM< !^L&sܹT'C쪪*+M.]9A 垞 ޽K]JSSS;;;RԚ9sPH |ΝrFٺu+4o<[[[##>P֙b2999Tć(TVV2.](jJ %55zAJEEEãtVq"=eP8x` ^z1('Hnԑ`  gEL];$1gA1cuY:͛jyN$7jGTT`ƲlGGǼ<544̞=0]]]xS PArFTUU <)err˕/zA~P/Iihh5"2e %e޼y9RIAr.ݻdbLooeea^^^O<4]qqEp׿wy߾}zSS_D(bֻwoCArlll҈wn{Ϟ=[SS#@ xٳ ɜ7o^ki3,(4662 ePHsTFYp!at:xK,_b Po>KKK;tПܹs O>ܽ{wPP>ܠ1cFUUU{}||6fĉR! X{kڵRFe744[?hjj|͛yEg,lԨQDR;@***$ʄʦ5uuul6TQvܨ pS"45y?c޽cJJ͛7H'ɍ{h|ejj*_Zyx{ 9/׵\nhjj$ALMM9tʮn Q֮]KpRcll,6?Ȓ5+V%ʦ5V>|X <}zw ^111+K6LJJj V*)..hHM')00?eļ.**HdlL8 ?ZCEjݻ7\PtVΟ?>|xg͚%۷o=]۷*NLLLp[CQ^^ܾ}PWWGJ69rT+W'PkJ]RIAҁ䦓m6a544> ΧH&Νsi%gS0D 4zK. ׯI _EtqAbWV6V@:Hn:-ݰvMn&H[| طo|2yK eƍd݀^$@HHH-7|CZWmPq O>\j(/-ݰ"""HNͬY~ #i x"99*7کy%%44ޓ:u*uNܗ}nݺa@^~ /^⁞Fɍ!ròNII.4!~H$nyN.Dȍ#G:::^v ,˗u0֒5CCr777A>)Ҫquu}E{m>~tO>1Lww=zh>z*11Nl߾5jTDDģG|(ZԈnXaaa@ppsYPy[TYY`0X,Vppy_~ڵ+b׮]\ȉ˗/Æ # KR:<ܿ J !5Եkזwf9ƍ?~(Qׯc#)!Kg=d۷oFcA^^^@ Gr\MM͖5ZDnXsQ0Xp#0LLL|wfddԥKq)cՋ`b:*Zaedd(v0zNK kuZh$ b f͚ݰ~E忞3f̐:4e pѭ[7Yt1ǓY@rC27oޤ KR'ɔ:|!u 9h͔)Sphw]KKjҨA.^b֯_/]w5ϒ[nh-[P"??_KKK%RxܐChh( R_= nfee%oz)r $Fh YsppH5<kKZ>Z=xDҒD Xx14MuU/P2f'DarsscbbݻWVV&Qh%&ɍ<|-ٳܰ$z i/BnZC>aYYY=zX,`2-Ar#1-ݰN8ᴍDbx׬XXXȘ wm>} eꦦû+n۶`(]'ɍdinn>Ç'իWy؉@rC2_\ p #Oq!ѣA|oIdì;qD 6lܸŋK,)))8pG.˗/-??:ӽ{7oޘA C x^ϟK8XHIII9r%);v쨬²S[[K!33̬ya{yyikkzӧO(upp@r#hv.`k `͚5,r\.񉉮nxx8 JHHxŖ-[ ֭[533kllv ݴMxxxpppUUwxx8tRr\]]Bˉ}k$iKccbRJDMM ܹ'ΠAΝm۶7o2Lx#lϞ=pØ , V@H7_¿ tÒ<0e@DDD{ >I%b„ 766ihh={155Fjkk?}x_~j5K(2B(/_$1&|ӧG)**"'55N镂 K ti>79%=]kBBBzr?g87h &B0 <o߾ϡPUUutÒÇy./L!Rn~I~~ܹsmmma̖0 KKˉ'~kooI0 離 ^G(srr5?.&N(Qe~eCFs1co'}!]kbccGall oN0LCCiժUg7n0HaÆ7'(yD&//+ 00uT*5" /tttwb M6ivaÆ9::s8&ciiE🱸`̟?_A" %7˖-fQVRXd˗2z "I5-tѣ߿/P M5?#THT@]F. 2=(͡3IHH=zY~e{t9*{`RrnX=ϝ(}:ԚOGG"ɾ8'RZZ|||444(͢¨ܜ:u T槄,s1ݻ^DLkJKK{{7D#y~31 rڿ?aG(:r#r244Tf7,)( '5.b"F"7778h3:>zh*l=cbbp' QQMٸq#FqގQ%"""(=GC^BBB~tN4tCh3g8weٔV7WTMn^xaii pttUpȇ,sǏ[Ӄ#Fv)H n|sNO֪ŋ V"477ad2߯P<1b'Nhiiڒfr jTt:!55Ut˗/wĨϩ&DFFB/!Cرc Q#_ ~3@aaaaOJJ200h+W"klmmtH5uttjO:ͮZcժUNNNۥhpq^85l6{۷SHȈ^br-˴֮]GWCC{ y G|N疛]vï]f_~=OMMmoqd2⋹sL F(zxx3gऌdJt177={~ze˖7n{֧O>a3gԚ*7Z.]ZPUTIHSSmӦM*ee)5_Q6ydI;;;h4円[I㸖 ccqɸC9s`FӷnݪPK]]ݦMhC=cPkD;88tiXj~@{rssVX/X`ǎoVٱ֭[ o߾eee~z666-G666ӧO'ѐxر0r˷Д 'kҝclhhp8&&&!+2y߿޽{o߾-++VVV_~!Cijj;w.00P@xxxhhy<^ss9\٥577|\bq.]`0jjjDEsrs/** `ookL8.66!@:wԩS0 sqq:u BCC9رc޼y^^^9R__/(:t.(;i+8rss[-m.fΜ IEgf:tbt,=z%utҐXnݻ_Lzyy%%%b744\~},44TR(((Ō%$dee8a>;pSQ+ԭF(vMDsssE-MHUVVI_ZZf#VXN1tPxƬwDNIDPPԚ֟tfl8ro߾1<.4:JLLҥץN;{n-{X8>}F͜9s l6{ҥ'{.˖‹*w!=AQnqD*͌3:*İ\.W #Z#Nn---ǎK⼦%N0ʕ+6m5X.\HE"1^|?yDCHi4ZK3xo":$''nܸAnX #e=ϟgYYY%⨥bŊzϙ3BErK7sa%u+7111wRdԥndQ=%OpʾpBOmllLQ]2 GEp+7zn˰%gΜo޼!% yNֽyI5Pnu&{nXԩݻ;v(>tږ7obF* ϯk y$yҖ r=qӊӧOZ. {xxJ UUUL&ښi[nFC0A[#矚7@$Lŋ%P8tP,A/^;bL&SR0ŋfAKrL&c444Њ{PYYd2O:#1#,QFriH(.YD  FFFRjjjߗ &H8o߆N 6~"##L&R O8Ν;)yɲeˠ֔JڗNKwt+ufPOڐ+VHO믟ݙV:j=e4DNk>Zmr7kR$TA"mk%%%ʡ FCC>},^VP~Wgccfʕ+EEEvĻ5 no%)wwwEr=l09p5xA}YYYYfHkD$b޽*;b>O._ 僯/aׯ_[F!7eee}EDD/߿go3I. .]z8֭۾};aRk X4R<ݻw 6͛ҥǏX;ZiCE1`ffxԩ<wEoooWW;w_<566yAJJ ÁդcÆ [n0Rk *_ݻw8)gill?1,蔴a2<{LCCC__`>aH/RhƍpV:ާ-ݰ/_.c..HSHv)!7FFF2Ɲ>}:`˖-ۗ{ Zɑ\5ъG5nXS肤hc1emm/ATEyyyGNƼG8C"lٲeƍ{NTmRj>|h]Xٳgl6ĉ8 :lv{EiǏR !]kBS[[kff͜9R=c988,[`ÇGGG{.**W^,#$$$y.ҚLrG8Q%)xb _544$",,l̘1666C YxD(Kl-yó9ThM5 È㧚fmmmyJ-7?~ҒO^vv68{r)= &={]\\H. ,%F&֭322 ĉ]]],qJRyܷoEZse?u .#RkiWn---[J_v Gi#e9Z ^X!18) sDYtt4a.\(wqq[[[)< "rѡ582E.,,'H/;0bBv Ӂ477=А^555C a0Ϟ=#1r%$$Қ$8lmm[#Pdeooo@JJ g:::7o$%g``㸖)7 )<Ϗ9BAɣh-?3/灁-[?h|-333'';wh4MM\Yb*-EEEz;v\qrr[ X,KMHѣGcƌhzzzӦM;tГ'OE ^|ye˖AG7INNNfwFY"Қܰ;>2f$WWWI)"PZHݻwȑL%r`b0}]jՓ'O:K6`0>|(X9gҥD;wIJJ8>|H:ܱ"~+I;`ݻw999eee 4MWW¢{ =zhllu9IILLp86pB`` ԚKo߾O< 믿.\~Ncc.-..V0@z?iiihEEzK.th ݰ !C޾}+ujR7nDQv'''iG*%, s5DyM&ٓDي $`.槢{O&M䆥AubCsKKK9E(RnB`ر Ǐך*###~ {rHx@\}D碳ʍP(?~<W!١繏ODZsر̚5 6633fatʥ#s5ˍP(6mBdh#G8q;_j4655=vXk/_BٻwoqRܰH_!<ssnPEMMM˗/g2\.w˖-ė3 &&fP5z!b&::Nt7dϛ2e Չ95*(7B|I(bxb/^~ښd޽z=6*ш#djζpy#>C50Ν;rL6 05bn ?r2f$9ڼy3a)y>hB] ÿ́ tzrr2u)ҖtݻΨKԨܤM6QbNi"B?|@Q|h<s_*Keeevv6ɤ4-ZسgOJ8333*#T>}?~|ԩT666Ϟ=: l>OEp{{oS( YXtI4^~۷绸vd_.=N_re>~f$kIhh7onݪEX5kl 0Ǐi4gwĕ@Iz䚚<W('::a„  OOA:uuu=z'}W2k.1cH[RR[^ǴǾ},YDi"Y0R S8j}?:gϞ---ݺu+YV^Z)={veeS dBѫ92e FKLL(@ >|8Q]Px! ?yð/q!Phaaall{*_gRD 4=N///'u\uDÇZZZݻw/--%7}[,s3 VW^,66K.ܴiӆ ^0 @,EZ}}}CCCr\!sttLLL,))qssqㆌѪƏqYfݻ7''ήR_F իd (zz%***ˣٳgKt钙??`ffVUUExI{9\Bn 6l`Xl6{o*477GDD Ε>x>~8aFFF~jt}544F Fr# y<ޘ1cX,C=tPff@ hݲ266vҥYZZ^x͘Ν0L__@2<==v\lĉԌ VqϧO.**jnnfVVVڍtoII @CCO>[l8pGr_x"K^EEE/^lhuDFϿ|7233pr}4iRny󦯯FFF9' "mNj/UQk!xooo6nccx[J__x3gLtؒ[[[geeeh5n(*33SSSsr蘘ٳ'~~~|>?::q!$7bff 7>{̟?Ö ӦM ZLgoo_VVvĉS!۷o|suԉ'^bC!74x<ڵko9N"Z̅ѣ<-AY,͛7].י3g`.\P2Z[[bqBBPGV>~8эujukkk{ nc >}Z^^>䉉>x׮]hȏUYlY{ի$YޮhFcVVD"2ݻwZ-;}vl `#<33o߾[n=e˖{vs\nUUUgg'y1 EN޹s'|SZZȁ?~844DXd׮]&) 2/3|nذpCIKK=ettȦM7o El6L&KKK[p?zTTJdŊYYY6mM!n(2<<,HbDjkk*D˗XbF11krr}||b|A5662` qCH$b1B!nP(999b} HFFƏ?W\ٳgzd2r `p1P{?$7YzOb,RRRO8?\ qCB144oe6F"__z}(R(Lv TD8_NNNcpB"===BP&1,cdgg 翎xӧOlNGX޽{;v`Yy]߯ZZZ222杼x={TVV/Yt޽{7''STs\>߻[r <8䉉 _nyyyߣ9v`Wo 79rNhs=O466|'QCCH$Mt#YuqƥK} 7L(n۶m||l6xwJrz> RGR=z('}|ҥOxYIT*lN3_V*hdB!n~zp _;gn޼yƍ/^ )^(jjjbX*h42Z;::d2Yff˗GlZE"ZV(/^U'O\fV-++s88L ~/|2ym[[۝;w\./**JbE"o߾ ;gHTSSS__jժ߽q͟izzl6zj```ll-Dr,M@@ $ qI$A@/@RIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tube_golden.png000066400000000000000000000674071450372207100251000ustar00rootroot00000000000000PNG  IHDRzznIDATxw\SO !콑%SDHѪUV(jqU{a⤴" =d!՞Ï$$9'.(W\IHHD3###+W P8Z 899eddyfhhhh4ګW-Zt} ϟC]k #9899P+V˗/}||FH.666h4://ի*ssׯS@Ȋ+0O?b&N߱cؽ{7'hFЌ,\ŋIII ?~rժUgΜL1# 99ӧּߟB|rrrUbv#Y7nܸ{.ҥKy&o{!++!<<<00O!m[MMM>]`X,Rbb"t۷o/O`$³g5 =w\\\ܫWHG702661c`vGGG:E DʐN_,((/^~[!!!III圆o`===uuu500pʔ)ߧh>}Ε+W8W*v#0D???_9uꔧ… ݻŻb l70O^^^oo=zTQQ3gu'==]^^^[[WT*HP*:::9N n`ğ###P(%%%+v#455ihh>fSS -?}}} Eqdr -H\:( F!H}}}ߏWhFQVVnhh|zeeeZ` KKK@qn`*(Ƞ999T*UAn`*J$466VQQdP!1ʕ+NNN111{ p$))رct:}VUUt5kϾ䔟l70bEFF>@$}||RSSyۛD"L+uI4_3/^`0,#l70ׯgΜ fl`0nnn `0vL箓iӦaEEED"D޹swzn` `$  ER'>`/^ĐLdh4!??mnnC gϞdh^b,ٳL&SJt x<={oV]]і,,<<33k׮X6h`ݻw 1?qׯ777mֻɓ'{{{$```F&Lf___]]]yyyooܜ9sV\nY,JYreTT>  |rMM xdfٲewZ̘1ɓ'}}}D"ddffh4$)%%jlllgggjjQ9s$$$xxx  544?/Q(B^sss(l70|!22 <2CPKJJqoON|Hܹs!I$}}}333(EDD YYYJN`ϟ?p`XpjQlq .\ pCPP0 n`'''g޼ycGfcccD"Q߼ybhӧOWc޽{|r .077p$Gf&Huu5k׮p܊ D"EΝ'l70ahh0Ժ@>t{{; |t3ܹSKK <9sNH~Ey*`ѻ-[@Avq=RPPPKK ԺxݻHOOV=/V`O󑲲䌌ցdddΧ#jb]B%##w1Db]]B ܾ}իWPk/ƈ YYYkkk Db2uuu%%%ÎVZ|9@VkN:`0H$޽{L*>_>}zƍPk79s8//B-o@=+֮]`444vܙ_ׅʃV^M";688(Xp8///^^155PG@EE j-d2OZ,X@ ۡh4\D244466ɱ۷osvbԴvZ#3aaa###< !*0L cgg$77ǣP( ul7\MMťW}檪N>}SWWtttKxT$9p/_ZȧP(~Z /{:::&M۞KJJ,XO088xa===eTTT[[[y+RDQTTTVVZ˄>|j-<.aXzzz|Zkd2O>=VMVV6 @\̧ 366N܊:;; `0={@-7TUU9sj9 gdee_֭[ l]]]`=@IIVGGgƍvZ7@0TVV̀f?rrr޽\/ y_~j! QJZ84w8qBNNj!%22ro߾եhPO` 2fceeeo㟃YYY㶵UUU~`$##oZ طo߯Р ghjjֲ٘L&ޛ7g&t555$I"'Nmll)@}p l70::@ wϸtSҒ8#sqq {FP<<<>|۞Em۶)++ɱJӧO?YVVGƶnnn(pIqq͞={tb͞=>;;pRTT_\\\SSL^^^CCC__Ύ6l8{lqq1O?8XL&kkkeZZڹsnݺ522BRd2Xr4###77D"-^8883 ^a"##H۷ypp0H|-?:/_XQKKD"hYYYCCC//H6KH$}}}Qh4eff~Avvl5ꖖsM2:2l7pHdSS͛7w9o|1H\v֭[Zu֓'O|~/ &&Ekkk{{{ 3,ã=55D"V?| QRR6ccczݻRRR`!5kĬ_ٳlF;w. 7,]?|w~سgϑ#Gmmm/jjjҲjjj{zz>:#777>1鑗OHH1c;BCCǞ477YG%**テX,<?y\HrrrRRRuuuP 4,+///5532EEEMMI&=xۛgcc#hvww?~>Y nNٻwȈ@-HxYeeeCCCFFFrrQUUeKMM'###> C&MD  P(d2j!Yee%|RRRLLL^zuo%%%&&&D"wEOcffn&ʕ+Wz{{O8ɢpŊP  <7,`2-EEExt3Qttt:::"Y,\۝uo@UTT߸{}hhԴ:̚5 LԚ0bݻw.@c555wk`2" !lذF9rj!ÇGFFN< DVVwo޼y+WpnGGl7А=w\!'ޜ9sFEEj!":wW_7ܼyߟkjj`#6f'OcaaQVV6>;?~ӦM>b\&섳q rttZaeeV!€'6RSSef[np8x%[ne2dsss ]PWW744wpp` nܸKYYNݻosJee%B$%K\~0k׮k׮UTTSFݍx+WFEE}AUUÇãn Z7ek&ի?AAAe7lbbbtҥK 7p'NرcӧOݡ"̟?`0&O}P q&11B888N,SSS^]O>j-`|||BB‹/?x!--mkk;uTkkkvb|͛7C-Dضm3g"Y5668FTÁgggO\ HIIiiiC-D1cƓ'Oh4@myԔ{xÇ"Y0gϞk/ܹ`:::رcvzٴix9l7NKIIY[[yj-E~~fFCCc``ÓOc'$<(СCP ,޾}аrJ>n>DRTTZXZ^^ns@&UUUJbh4 CJfzaoo/DGF믿B-D{nBBBrrr]]j$D"h4ox#))bb=y֖O^n>PWWBD'NDEEtOOӧ)++6LfCCxD5)))99Dr999K`*Gyzz+[?SUN}vg``pٮ.vjnn>v옲thh(NRАkn>)x"***FFF2 N_H)SL0% ;+|G(--`ŊP U"""0̂ 'OUU+L:@ @ üǑ#Gıcxذa?x!̇0L CRA"P I~$y%vo> na@HJJw n' 2H$̙3|˖-D"1//K8ZZZ EbD^QQZD&ssE6񩬬!! ⠓,MA,\hpp!Z[[$80@ < j!"Ƌ/MŋS5PTTڵkHrbYYY_?nܸٹ{n/5cccǎ;?*,}4JP(ssGrT~`0y$SW"##v2$n *;w냋2x<5::sspH$N:=RRRP0 00j!PRXXb %%%p$##3o޼/^L箮.CCC{{{Wojjw͛pxŊP 0qvvFPP ę3g-hhh{Q444\\\xx~ܼLdŋr"Ivގ@ "8FFFΞ=kggb@"&&&_Ъ*+555GGNӧHLKKx711ZŨd d:::vmhh^pΗ.]eiӦİ0]';v@K,yo===]JJ @9sGŖK.Ź2*Av322FG֬Y3"B>~1 D"qׯ_醇#""455~.^wCCC"!)v}v{>}C&AQSS[fMii)ԺfժUH$R]]^Xm۶-[ ``` "GCC˗/Z j!b]t .NӑHEl"lN WVVF  T*@MML&3̶̾6+W[Y˖-[L$J,]?lllTUUZ?@wFEEA-dݻw  aw --b:ujٲevvv򊊊:::ϟ/))"DJJ @@".\'aP АZTTT]v X()) j]l!''(; @tt4B/^sNp˗/͛7%OEE% ۷PDA^;h4DfۍZDGG;;;p8ݻ?h*XZZp8AF E d29//OqF!뉼 677744tvv~F$J>lbb.`0*zYrijj <D"###ZxX|9P g7ߺueo4m``x3gΔz{{#U@ P?D9sfBBԺxxYڴXj D"j#J?slll?J333ҒAPɭ666)))Pk)))?ӧOPRR5kֶm̠Kp8Inn.T̙`jj>V"իW-[vҥUVA@wlQUUxbaiiyܹ^6c2ɫW`0/_\111nnnx<\߾};$@XX}zxxXb*FS8B Ֆ0 zPMooܹsq8ǹ7::Z\\lkk++++e`p)))8DTv ZZnZΊ+ZG^ikkVWWI>@ ݊t??lNhPm1L///,--G Vqn,--xkҡH$cccH"l{Gh ۷L`($WXyNll,B{@fddd::: <ȑ# ɓ'gpp0,, F2VVVaaa(~"],>C,B^ cjjVڵL&o+aՊ܍>x#7oLQE `V Vݤ#˗//ࠑ%'',%X N^!{80Lwwwf0 @U ݰX,{{3g;xoѣGn1VoDZٳ!S? HPe7wAPƛD&ʂZAAA j-f Bd7[laqUU{g̘8>Ja>*&ʝ;w۷oCH$*>[axx833ɉw}lv8y䬬,¼O|||ww78:iΝ[^^.++;m۶A--n߾MBBBynJJJFFFl`RV1D ƍœ Ԋ>Xynjkk.=tww?zD"IDWW0.Yj!<Fl޼955U]]]˓uvv{{{C--n:::QTTs999޿_MMו:;;9 3͛7#~ j!<ԩSn믿qQQ 8~XfͦMhm؟E bݻgkk+l;y^da?љȴ@`X~oݺUUUz ccgϞ:tpGhhɓ'/tuu92uT#>>テZ@5?OX)544|eϞ=AAA.(*APPX\Px2YYYaXUpMvv6O5'lh"X,VIIwΝT%|GB-D@ƢP(,n lGϞ=c ~att4::z3g411?B D"Q]]III"w9a؏~#ĕpj߾}*  Z!DuO~qv{yy}JIIWHޫxQ`0233޾}[QQQWW?6G"$IQQQCCX%//?7oBE 9;;ggg{xx<~* EVVVq*{شݜ>},Ȏ׀05@󮮮삂ʦt0P(&&&...}&!!! B  x񢆆FVV5$$$8p@q'n233mmmL8uW_}쬢ҒxOOϛ7odv"Ξ=@ ܾ}枞:>ɩ6DR]]]Et H$}j!Z F_ mccSPP0GK$"`ʔ)T*_l˪W^S(]]YfM:XFFFߟ={ ZPPP^^^[[JјL&DDuuuCCC $1ŋݻS(**rrr=|]WFFfΜ9+nbbb˖|eժUYYY`>-C޼yPSSSGGXlFdɓ!Q:::===%5 ghhή`̙<@ 6={Pxp Ų055v_Pԛ7o~| iiiMMMc p81J:u[ZZn߾=44T`A(MMͬ,~/ddd(JMM _p{wSaoo/++ ԴWUUU mllb{e<<.]믱XlRR񴵵466vvv2 '//ciiH"]\\h4S__uƍ$F߽{WSSBjkkE>АYWW;@" :::8GRx;UPP055 a͛(..Ih4 -...^d RSS۲eӧOhWWW|||@@Hb6mjnn|"v3::بgkknH$x3iiiS -˗/3up͛Q(m\\`]]]&ZGnFGGkjj yRrb߿@9rĊgϮ]M___ZZzXDdﶿjj(V,$8@ |X#//HEEBt:=44,O$#N6FldSSŋ?O=SF<,d2 "'`8EII 444;PYYٛ7okkk[ZZz{{&...8 @ B-_eee744tvvg9cs111eeelYp3V^s f%%ׯϝ;͠CF7<ЀF w-0ƇɆ?sѣ8By\]]ws/// ȉTvP(T*599iooommk'N͜9j!2{^VVSZZZSSS[[[XXx9MKK[rddd8(;݀,8YYYwZpaVpxx8##c|B3 ;.wܺu , b˖-h4zP p8?cmmQWmmm L&SKK,KG  #h4ׯg̘1u <+b|󍦦?ѡ')))588ȕj>"?I[lZsNui<mQI__߷~}wޝ?PU4noo'Z2.̇wMd`hhHYYؘWnݺxb:O!77jիWi4ȕ6TUUhllH'x< <6_illTRR6 y!N_f B$H$QQQP(%%%f,)vD"")TTT XBR?SSSsL < 9(Dn^xahh(#CqeӦMH$ĉP OfUWW)**ذIgggVVb-Zj!x𡳳'|||;w-//_lHDDBa8,;} P'K ?i| qVVBKKuֱӲD))3gfff񫯾^>", j!ڻw/|ICB EP|B e"dĤj!Ass˯\1ۻ6##OuLx1~nX,ZDdɒׯ*((@E iii2e˵kx~Օ@ |R Mtt4ڸq#B$)S^'ݻa gl?qvvbPx)BĜ$b ^GooowvvVQQ%NLxKKˏf9###P ?>|cck׮ijjNŋ#I&N#ԋ/k;!--qÆ P MAϜ93v#h4Ν;EkL͛7@@-D"ptt`0L&j!N?x ߆|344T~w>1B:y٤I}K,MKK={6| V`0999_߻w㏅ 8q"((B$MUUΝ;ذnݺjmmmH#&&ƍt:]^^^WWWAAF {D"M:uɒ% .~#v^p]%aH$fqq1B$={9r֭[{800UPPPWW`0p8?x_FSSNרDEEܼysPk t:LVSSZ@:F5kB$CIKK^#`֯_O% l۶mP ߽{a{eee^ :::x<^o @B4ؼy3?yaii5\ҋw^@ X9$$j!"C0ymCC <9 Pa`TB#>%:)//s).\S:::mmmP jLMM-Zt>x;w|}}B $ +,wkkk"섄ʞEinnNHHXd ZlUh5$??ҥ('Ǐ@y~`` ÚI6lpS3nz-leh9 .|k.%ƶXYY)1pj-5;`\03g ]C!<сH/͛7+#;5^SBqa͛7cE{ŋ)T )JQQDKTo޼Ν)Ⱦ}ccc`vDH$gdd`]Xx1<{,!O>~ʕ"DS Dbhh֢`1/ɶlقIt]իR+ի ,^[J~ k!Z&]vx<&u @qF:lK_v u)J/ Rttt0답l6к‰'F25...Nz뭷Ν_~Аf4AAAa-Dn*** :rCk?\.wٲeD" :#G}[A">>{r$$$*+VaO?d7 æ"Hj CvG&5Q(VCtdBr`mm{G"fϞ}?JII&&&mmmQ wLX =4j7$_5ɩS\\\&V\(gg<8A3gμp㍍A.JМ$%%A즖rH$Jr>C.g!!!K.eH z;襤<)㍌?~_Bٹs'AwZN˗/OLLJU,111B.J̙cbblHa-DOP𴴴3gI$6o2 LÒ_~exxX$={vƍAqƍ~"lٲoF/_NNN,/++K.{zzO]ݻwo-Zo$JSSSi4'Ck&F rrr֢2FX +&`7"9r'4m֬Y׉^{ 5OKK N'XkQ HTh&77)%%E`---!!!D"1::ZI䀵@`ddҰ2YZnnݺEP|ɇH322(D;njj ðdډM{{իU͕+Wp8<˘ƍAX033a8!!k-7xk!f͚5L&O}?CssgennsuLA.NPwίacݍ8_TdeeFjvvZ (? Bmm- 9``pX& M&99UVVNtVBf9%}}}8իXkyqqqEDD`-DnBBB^} Mh",--d3Px8qV2BCCe2˗0xzB̄ nCBtR[d2trAQQQ.p8h4IYO@5!Cv:Q΃DLLLLOOk) l6{޽t½r劆NeL>xkkkR)H= uF9 taoo1w\ NpYYٳ+߯!!!nݫQ700prr<}9 aK4TVVz@uݑH$suuE0OOψLv ݰatbFnϟ [nOFۍP(FCnnܹsC˘666feexǏ'&&@PLLLlo@@-J\.7<<?t: (M6A>loo/#򲲲ӧOo߾}ɒ%(Rvvv~~~6l8rHRR蛣"ejL&RZfSnnn{A?Kll,7\H$駟H$Rpp0H[#%]Pffw}hhh8:ðs```xxw}/4Ԕwڵq \vMg;;LPP###KJJbʕ+Q}wjjjrrrP]]]=/@  -,,X,ٳ͛VUݿ~7bccSSS0 + /X`ٲeVBZZZ➞o7]]]_5rZihhpss֮]Xښ]XXX]]d2a֬Y ,;jܿ?~ݻwM/XaڴiA&744eff&&& ;;;GEE:u R)ͳ=VjݺuNx;wX,33щ!dWw͚5믿@KmAΝ;hnnieei/^d2 ZvAD"Yvmzz7/^T(5 ũ1455ݻڵkvZb~svv&L.H$х/3D =T Ϛ5kҥH =z͛T*__h433C^|>";;;!!kϞ=ȩ5T ={zzR  MLL0Q7 XW\ٸqc]]cMeׯ'''#UBdF/HYdɪU̙j JJJ JKKy<^KKH$ 0 ST$?f}||^z%Xn]kkkFFr+WJKKݼyBBBP.c+VjPnF $ 7119s&LVHUTT>zsppp#q~̙imm믿_`ҥpqq)((8v옷wRRmh@C5v:ttt g.DccI.^ti(K@/_~WYyrر}m޼ٳhfhjjrppwr TCcc#ߣrE2lbbbmmp1<<\(޾}MhTJѤRiooHpMM̙3Z[[Q g^bW_}}DvP##eeeUUU( ׭[wa4Q HnH*ʢ۷֎ P-*T esDRPPPXXʂAl6ekkkΑQ@܀;qʗJQ`L^`ݻϝ;{{{r9Rw^QF$AG9s 9J5gnZ?u +33O>ݻNNNeee_~ݻODwx hHϘމϧ-##FY[[#'u ;Jmmm(߿vZiiipp@4{@ `uhc*u0 qSHma^^yztxzzNhӇ2.5 gff| 49χ eocB6P.[M+뎎6=00P__?r*0L.UVVւ x<K>\nggcǎ> 7oxwjkkcbbf̘ &L|Rݻwmll\\\Q}O~-[LZ8h)mmmNNN|c8p 6b`0>?C?~!5nߟ b}}}B.^xSN)ġC .]Fh5'22r׮]qqq*oΝ;7k,O/^L"_9O> pdd <`7`߾}0 =ztSIҽ{phUH:Ù3gv/={V*++7mTYYyիWZ#y @gضm[nnn[[ŊG>COOO"X\\ F^^^EEE/^ KMMa\o߾~z'';w\p!##cƌT @'H$/_>{lNNܹs=< s)//nX`|'aڵ!rO:>a„<* e/_BJJ=FtR;`7o>|Pqz{{S۷oY l6{ժUd2СC^;44@ |7}:xTTTVUU3n:k׮I @dl6{…JJJ>>t:|НΝ;ݻn O<2eJNNN?'SGKKŋӧOG { VTT HbbPYdƝD*++Rj۶mV__8h ի׮]I/& HPPPMK. 466R!002}csssUr۷oD䫯ӬYDk .77y̙؛Lw߯':tbQ(1Ks3337}7ϞXA988?MAAرc1VKKK6]RRs6Fwzn?v܉J3fL?qSSSD]/_:99M|X[[{ѢE"'n,-- Et:@?qQܹs?yKK˯}v^QBuvvVVVs2)hđI&C TUUǎ;mڴ {{{oNOOuggGBU;zeDIvv6睩P]]-{|۞"L[_2/.]RNNF$=== Eˍ^fJ|UUUݷoߞfT3gڪzAgSS~b;vLMEE@{n 'O 055E@ )))Ho(666Rf^'jjjz:;;ћVVV}oⰎ~RRHx8pB 7l6ƦMCٹsBNN4c邂>xgy)))*,,LQQ1==]ddd?.uPo޼qssud_h:r֭[Ya`MMMW\/X]]][[[//ŋ .[]]r444LMM{6%&&޸qӧF%%%ssswww3f y<ނ ?(Y={6sŋuЈ*((֞2eo3޽@ Hh޼yU:cc|~~~$_enn_<~x;4BCC'M4W0LOOO-- I|!F u{zt:ŋb-((HVVbN=/~ nٲF)((,Zٳ}rhmm}}&N uDDsIIɞ={x` d2Νx1Kx#G+W`>[2wuvv6[n$''VaefffOR~7^z矓d$)WUUU?k0c #),,1cL>rH;`4N81bӧO'~iKK ÜϏ%%%Ί-C ¶mۆIFMMMI#sJJJߴiP_}LvqqHA544l۶F)))X͛ݝfaaA $xr8 v{ϷzXǫYJJJ# =anQ!6H$SNo:Gӏ?>uTAƏ ^t)222%%iii˳Xnss \JF7ozH$??'111 . :uL`~~ÇUUU%1FIp87oLMM-//G'9 [2zp߻w}a\___QQ1V559s,[lƌI*b0gϞeee644\rEYYy…zzz666/0<ܸq#&&&##vmmmkkkoo`t9ɓ3gZ,[UU5m4MMxNCÇׯ_OII)..nkkC7'OpiӦ .ŋK.!d]]]+++kkk37NNNAʪp81c١#tvpp򊌌eee}ѿ/V"---***))=G񛚚͞=[pHAYfX(..rJ|||NNN}}=C8::,ZlI󽼼ZZZRRR,$ɓ'NZ|4TXX'$$z۷Rcccggٳg/Xq#!$ٚv(CAAA/YYYiSsNUUU_h-jd-a@ dћɓW>}Ni4y󼽽\tժU?Fݿq͝;رcbjnn߿Q]]f[:::3g ՕG7˽w_|vȷ<ϽgR(za[XXE=cƌ}a= nF;7qACCsƍ355 f\. :ܺuBCCޓܾ};::=oQ7nԩЂZ[[Ϟ=daaAPb4f̘3g۷Y=z >… YYY^__?Ppt3 "Z˗/?}h]fkii!H>ܯH0J@ctܹq:+`LU7m۶=zH L&. 6p25ڡ(`p,YyfSSӎb2(1 `A"##AwxNrrrTJss3~t:5= nF;UUU33/^x{{ҥK{mlllUUU3gKΙ8zx +VyFFPOWVV&%%M'}Tq*++7mڴy &H0lA܀R.]vڡCQd.\~F}0ݏ=a]]ݐ VfفϞ=L F?֭[W__l2&zjloo JMM766HM0A܀vޭf͚Y0h-Zۄ[[[ \\\lǏ7mdhhbŊI&ܹS $'';w덍ZZZƍ322RSS쬫+))yŲ ^|PHoC!x씔SjhhO:UGGg  {{l~pFN n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8DfFgϞVWWWTT f SSS{{{4c ׮]{722ruuP(UUU%%%JJJ^^^!!!ϗQ ~544-Z~WWWwϲk׮hjjn޼y C1j0,% A'''Cmƍ$1**fclXWW{n}}()@ dK2n8  JZZ x<׮]K ۥ0F+">N+D4555KJJ*++knnFظ{yy9::Jh ƍ>>>OVSSǏCBBbcc%7F u=JHHHOOo߾rhhkk[YYM8sڴi KAQDEE4LKKK^^455奦\rڵ"_\EDDZjH___#R_zf;;;;::;VOOF֪´,*q & RWáH3332b?77744TGGGAAaΝmmm|DGGH{JlKKرc$[HVff34iҙ3gYp!N`g!⦴t$/ސwuuZZZ:::7o- Nh_~4כ̙3G3 UL&󫯾"O>eeewWk(++;99eee ;V_rE=l:u*ÑRrrrǎR} r[[[MM˗/\c //?k֬8Iimm}5La`` z3GQQ{EEŶnDښ`_t100P0Yn߾Ȃ v'''쟿_u=xߏ[kkkKKK;mmmL&`tndnaXwl6rl6r8mz(dw%HOHUUղw޼y7`btttzn!dޑ%wQPP{Gt JURRhFeeeUUUA9%%iA#SLinn'n0VAƦt-555Y mMMM}}q7)74Fx_222o&TTT|3dee)Jo&JUTT,))X,HK֬YHGGFۻw/@;::Lfww7vf;;;9/Á 6999 _=Mwmeee+))aݳFXXX7X_8;;cobnnv=nhkkCSo0LC7X,vdA S@hF~UTTh4(33~655YQQQnn)S4622ZnȝnhmmE?L&d2Fkfwuu4Č6@Ahh} `Lyy9u((( -l6;11QFFf…SS~⦱QSSh@dѢE؛=J#H$XP(h qPVVVTTR҈s}}fu^' Kjj̉'4b[J>ӧO _.Z-[Hc H\{{ɂ Ś4i`AVd%>&+++iiiɓcbb([ZZ~gMMM--).--BرCyxp8իW SQQ,9oÑH$333//͟? HNN>:w>ˍx"LްaGL&388XAA/p႒ҤIfy޽{׭[ ˷lrd. ޽{NS'33]"&55O Ϗ׏3foF"! :PHN8q\hh7l@"߼y>}V6l@&-,,;e!:6}Ν9siӦeff # n>0ĉ***۶m+((*++k /^`_bXyy/1u)Sٙiiis8򼼼ﷴ|G[l/0ggg??^ZZ:a„3f8::ZZZST^YYI322߿_TTdmmq+V (q쌍KNNrv3f{-R> 70٫Dt^;())M8qԩ~~~Xj7=uww~2**JOOOMMM`8%x<^uuu]]ĉI$ҳgtv*#%X [7 ,<@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7 Hf?[]]]ZZ*++ᡡajjjoo?uTSSӡ& n&><}[ ]\\ddd:;;N>`0CBBV^m``0ԣ _qrrlM0nܸaooO O~ɚrvi`` ##lٲR| @ dC܀*..&|I~~>\.7**ƆB|,K3nR1mooҒaee-H  i 7 ꫯRSSE+B$׭[K"ܲ%=L0@܀vwEDDٳD"Y0!!uڴiiii# n8z###,Y"QQQ3f̘={vIIʂ'OlݺL".]dii%`޾tҠ 6H>B F}0A܀ؽ{wwwǥŘ1c~Çeщ>,#rSzzkTTTXXX+Vv_SNhwܑvG@DLww%=0":tO>={h78{M 433TPP khhԩSO8!qhe7ttt/_|Ϟ=^^^vVXqe6-q3f`ٙkhh|WP)S?c-jnn~x# @<==1,//^y%"zzzVVVBl7]SSSyy)ҥK{mx(((`1##Cf+..FR"̜9{ k0zl~]}}= :::"7_?a uuuѮq31Lwm6KK˫W.\P h'SDr"4ߒn޼xb___B_0rhGѸ\.B/z6kkk;o<77TS䴴h4QG F$8޾} Hee8E_xIuu5L_0RSSˊvcNJSYOO/_,//3f D0778q׬YDFYww{(nzWjjj:;;/IƏ߳_={0ܘa``P\\$==}ĉ=x~a\\\ZZZqqqcc#A?Ts81'uF戈+W۫nhkkO4iӦM111.󔐐 Ncbb:::|~WWWll\JJ Ƒo۶rݪN<lmm${zzر#!!bIufxIIIw}NGߨ&4vڴi~~~zzzBU?;?~_xbzyyb췻p|PD_MII鵵, NRmllL2o<###a+,rssG~weeejjj[uwwda9uƍ+++Յ`0wyQVVViiiSSHTWW755uvv={AOuuuf"HrrrB=nZZZnܸqݤ$2!VPJzyyyc4`2饥oYT{433[dɁ$^'&9v_~E ܹS]]сn?~ٳ'N(?$oNHH(((@?=L0s޼yӦM[G˗/Xȑ# 5.А~kעW^x"}x?>k,##%R>\TTxΞ=+++K7ߨ755I6۷O6m̘1d2KF/?-]ԩSgDhlluttDIoݺEѫu|>իWׯ_oEV8`0,\,_H$:88?~|>L"?~,TSN-]FIIIL&3fڴi۷oAX[[ >UC"K>uuugϞ]l]:::SLٲe˽{btwwOJJJ:::?CUUV%%%;wTUU{L<`~۷oȯ577K>0aqd2MLL.]*_N p>ܷow"p.++믿fdd,UWWk.kkkAI+ŊٴiSw*W\yن}ZPPPWW'7^QQQOOf711Hw,Ç6gkkvԩ?Cee"Ƣ.\(..И9sPk,^:)) {7o>y;2{ q :5ZfffYYޡ?| {֫WdCCC###wwϿO? &|W؏.\ ++dɒm۶~؏ÜAd0/_^fHtuu]~}TTTOGŇyÔB͚5+<<C[n/899۷חH$޽{K[/7t:X8^z%++h"t ~c?QJJw}7sL### "+RVVVǎ+.. .cOOO==o*))Y[[͛7=go{ fo}Ϟ=;쎥"e;;; )Jo߾qHl?qjժٳgcfI$R7h?#A19{rʈFE=|ṘcA.\(H~Y!''gڴi %@M0=4w\,u\֭[-[fccwl{mjj| ޽{uQ/55~&466XA@7D6,͛Y͝;wܸqBͮsA?2 B166'nZZZOX[[[oڎkmmXG9O>ҢhT*=®.hmmm^b2n$,/ҕ+Wx񢽽ɓ'222˗/?!Hč%4BvؗC~> P_pw|ٲe^^^zzzT*رca?D'n4441@_;zGUUcG D#A1cЁ\__r¢111)))X NO`_] GDWWAƞ) ^n~x<^YYY?qcooq(uuuPiiiB<3_~6 ӧO{nxYCCC,Etz'Sc˖-C x@d...D"ɓ'_bݻw{nr:::/<~XUUx111GrJpn cx`ܿ QT)++]v _~eAAzyޓڽ{7"ׯ_p??sbBѣG 3gˏiq~7eeeruQ(C|7~ DvZܾ}{ӫ֭[eee&M277ؐ;888::9sc8ZZZ ߿~ztzbbbmm+p =|YYYG7<F]F"q ڲe>K544()):thoݺE zN+! L&lʕR۷oåњ5k \hᗹsZYYF[nUUU^~?~\VV6++Kz]xH2tRD3gez7 %%%W2667n\uuua>.۔,8޾}B"/Auu5hɓ'E>駟fϞXr}:NMMMLLLOO/**c0D"QQQQWWeԩ΂&Vv2 q '7@pIH2#@IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tube_isomap_arm64_golden.png000066400000000000000000000441111450372207100274440ustar00rootroot00000000000000PNG  IHDRzzHIDATxw\]veq齃t0 vQ,!KF#֋`LL41$*( +#tX.w/Wmsog̜Gf#""޽9Ě&MZxʕ+544h0"RSScccˇXgvvv$ ډPo֭[vvvGm@7n=}xgggbblli>˫tؕ###׷СCCWHLLs0ק~qvMUAG @83f#Gޖ#d2 OKKm۶E3--ottt[n-¹ LHˍGdٲeoXr! ~~~oߖz?655YA}vsssA6oތohΜ9m ---7qwwڵk)))8+xzzTggg]Q~ |{'N핖`***&&&8߱cǛ ?>}tq3a„L!z#L2G)**:::nڴ)!!n?.ZАB߾}RR~իFNNsÇQ>~ݞBL[iӦ~gNNN؉*lxN{xx۷@.0p8kZ[[CI$9sBCC~ʶhPzbll'nz{{UTT„(*\TVV(z݁ \|r333ޥRRRgΜiiiܹ͍Fv(]]]o<ċ/;w@Mh4&)\6mz,TRRxb777mV'N\h{8=tHzԩSs5 b8; `qy&L7nܾ}mFFv7EQ޽{8m;;;8 H333w܉~f T QwFl֭[o'#]\\}..."> #G(++`6ZYYʾy*8#kLE?Zvv6DyPqOPΝ;'ѮTTT(((_cͦg.\@J?1RT˗_t[ .!!!ӧOWWW]`oo'sؗՒ%KXMgҤIӦM~/{URR*))\Wf͚ekkb$D˗/80uT55/g}#d?~ɒ%~ɵt%5KZZ#6TܰI&ڶK+v풓͕D믿6nࠠAUSS:ue'666((vYjOOcǎUTTٟ{Kh3>>^JJ̙3%𭏵)((:u͛7Dqൟ~iݺub)(UUUWnnn}}=5228q ͛wcS<tccR{,khhtҽ{rrr8 222...=yݹsI,5߿pB//OPeeey˖-R"۷Fܹ3''g;H("##TGHHF',ʕ+eddL >k\7|CP߼W744xyyQ(} }f֭[zzzIIIU)l6;***00ʊ~"H:::s=u>JJWWשS P8q#G7om}*--}I tPL yC- … mmm#Gc?!L:\r Ϝ93eAƏʕ/ ~˗/GDD$''뛘X,SSŋZZZ л(!!!22299;nmm=s+Vt ooo`^ rvرt .Q\_TZZ͜v3g\lHwΝ;qqq S\.MUUu޼yW9ss 7<O>.--mll?/^ckkFCF[neddTWWX,\exWO>vsszX;::FEEa#""^|#dnndA7pӋ ˗ Ҳtqq`c!,ޚ$ǎ{;Ϟ=SVV^lxv}||tuuyheddxnpPP(o. (:;;?XJJJdd'O ڰ F6m innvvv655so\\={6y>ɓ<7oFGG`g555==== Dv҅!샽FFF^r:::ص Ò%KLLL$w-7PP}ԭ[fJ,n nF!~?$)))-;ƍm;驩;J^vh8Jg1!''?|F4Y,/^nfftAQtwwGFFĤWUU9tRScy 3g;vZК?1F)** q ߻էOR\\,뱱iii555l6} ;wҥK==~3g>}Z>8q'88zzzk^t/_ljjޫfff/:up?JJJk&=Pdd$ 7Ommm\33˗YC`(; w۷WZUUUи)..xy̙sԩW^ 1 p0y۷SSS+++yWPM6?~\ЂfRPPvpp¿ =YEEb=`J̗rLFFfk؏uuuW\wqq'z{{>-І(XbbB][l={<++㩩MMMBnkkvy!( sFD___WXq)ޣSehhXWW'ܶq31L2,[nurr ]610vXpgjnݺuΝlQEQ1X'++bpanOOY`N]]Agu։>T]]4;`f311AHGGgؕ322޽wa%h4eer<cMf:::YYYӦMveyy7Wc2oVffE2xWUY|yww7<##c„ ]U`0ݻ7sL#Bīa C#qu1>qK(otR835@DII) {Ъ[YY_t iii)))6l-N`,--#""$ݖwoo%;b`jjnݺ۷wuuI#GH0:A܀8|poo_~)&>㠠 WWWɵF-?ٳg7IWPP D}0e~࿼GiiiyzzrPPӧOLt@ػc|… cbbUoڵW\q! ٳׯ_`SD}ƍ3f]qCQ444;w5kVIIХ^jkk[UU!nw oO>mmm޲e˫WSL xӭ$S΀o?ܼypɒ%зV͘1CYY9###,, Ɔ*p8ׯ_ǿf``*%%`0JJJrrr^zlٲ?FyD=)))99555yyyl6̌N;88xxx :1xW@܀3pq  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q HwcSSS?^SSSUU Ȇ ta?K]]ovte``DRJKK;::h4̙3WX1|))xwo0C]rEEEeɒ%8qʠ=ztu???--͛7oذANNn:F~BY5Ha27o&NNN¹ammUTTtuu]&n(JP𗙙ibbs\!*455_EUVuttHh" >]6i$+++W(*DUU>!!᯿rww@O vO?"V>}zZZ𨩩S; Ŏɓ첲Ɯiiiggg===[[[777**ɺ}… W_lKKˌ3X,VRRқ`ԪQzzzaa!HOOGQt„ ZZZԩSBMiis"""***h4=v/++\^^WVVvYf  RQQUΜ9#'N?~[;:iooxbxxxjjb[[[uuuAAA^^Xzeee+`ϋ/.]J"ۗ=8bmmgΜ lG__ɑo$TeǎJJJAAA}ʝnZzN?|pggm۶III{111(**d3JKKo*///WѣrrrUUUmҥKjjjZZZO:8iii9r䈪~LLV7vvvvuuUTTzp477:tH X,++@I7ٹj*uV&)\Ƶkע(g7W7III4m555oΝ(߿_R@k ЄJIIUVV~„ ?Ztt[ 7O<_lp ڻw QX,MM̓YwvvvFFF&LXhѕ+Wp8##]vk Ǐ,//W\ɓ'Jaŋ˗/p8 ڵkd2̙3- C"ڊ HPPKKKSRRVX 7uuuE5nWWWss:V...=4T0L ӧYF Oņ qҢ00Y8-v} "/^@$++KYnZYY$gff۷d555$̊+ bacc(sqFA>3>^rMH$ǷMJJ QQQ vΝ;% BGGDu(En݊ ȦMoxbQ%6̇R;v̞={…bqUUՐoիWmMQQ˵Hnn. 'NĿEAA(Quvv9rD }7.]BvU Hjj@1fKKK/h+ .tuu ]Gd֬YO455n[]]믿bNAOR'VVV\.;Ď-,,(ӧOo~Iݍ .W^n/rҤIjjjϟexx8v .##ԄiiiM81##϶$$$<3***,, Z`˗/sssZ[[f͚hggªUmxbv]]]uuuMMM-6773̶ή-\ѱLzBPT%%%MM͞/^JKK ɯ!{{GGGܼBXXXtwwvttwH$k.999K[JJJXlhqijj{{{=z믿dӦMiiiǖ{g_aɒ%'N3Ş={bbbp5kVBBB]]oEaaϭ9rȅ wB__onnn---;::] Loo/n= ljBHII }MQQq^kt: PSSvLgg璒cccQL&+gϞ۷ogggfgg'[[[utt`kcټ5K?DxqWa_SRRhؿZMMMUUukFRbbǠrssf.r7"YYYNNN|n233qvʃ^XXco>GGv%%%M 鵁V, yG===`XW.v@wUTTK{Z)čѳg pⅅx֔7~MaX,VCCCkKb2귶b/=K.[o333pf ˖-\?gwA555? g33Ir#&썂M`o !̱bFao999%%1c1A%322-###Ay;|JyM:\.{677744 V&v}c566X,ǿmRPPw#NǎǍ̷xqq)ŽWWB1447ZZZ8a?c;)MMM8`-Κ5D"b +;zbBVVX@`'4++1Ƨ7HHHƳrk⦸VQQOiӦ D"u؈6r'b}~{{;/}mGRL9swA]]2 bmmtRMWW A7[UTTĎ\pFddd^WRR  5o޼K׫իW?}}}lIYYٚ5kw&L6uX,ŋ&l «;hc;v쐕577WVV8rȡCbbbp֑7d2,AP.۷Y7 ܹsi4Zxxmۆ]Ĥc 'N|ԩS4]tO*-Z$Х`sڵѣ7pb{{;_3h9Vb`D`T*5(((,,wؕ-ZˎӧO߾}d>zg STTa;!AmmmoB议.uZ[[č6v7o4aJ矷~7鎎fff|q8={iT \]^ZZNee%z%T*jrZ u ;wܿ[*E ?HB{B{䉎wttرL&/XE"EQ4--M ݺu EQlOqРm6v&HD[inn DQtڴiOSfIv nϟ={vnnpEdeeOq;}tPPÇE?蘚^TT$>w /_޼yw}}vqTUU755d0* 97rrr֮]{ 6۷8xw 3gHҍ7:$`q񺺺sI SSӣG>|XrQ [}}c8%ц֯_omm{nF'o'O7n'|"H$]VRR"hLb?~ΝT*֭~snee5?ChhP*ĴYo.ij9|S?N"/6@bccL[nyḠ pn`0҄2x'A3g$Eccc(q7c]{{{QQ:99D%c XWTToaaApp XCcv@[UWWz EQ}}}uuuE O57c]GGJh+CCCmmϟرc|gKNNK.w @@611q---WkqsXf@~W2|F[1LxfXq3#R]]-Jqƙr8Lȋ/-"MLL|_ϙ/\䤪ʻEQ{{+W={rRw!HUUUxMMMp8ؒ4kkk ]$''8p`ܹJN>}qqql6g@">gJ<{7 eee311 ~_q舋{AfffiiiSSS__.:::Ǐwss?~9'|o߾aWZtiNNLmhh@3$$111YrX&$$ieee,--]]]gϞ=qDA,..f0s!w255tSimmqݻw|r %%ecc3}t__ߩS⹬\yǯ^9sM`bbNR\nKKKyyy^^^JJJtttMMͤInݺh"A/u \'OݻZTT`0x'ddd444]\\<=='O]fmmm=<<$7)r}}}\\\bbbvvvYYYss38SsssXX؏?X__6{l''' ۈdVWWݽ{733pƍׯZ*jkk׬YC";::,-_L&;;;?~XÇ |y(ǖ-[թS䊋%ʡCjjj$ gϞ]r ;L&oDjbXǎSRR}t]]݁ϝ;#S18{,DڵkZnJvڠ_ 7\._YY955U~𴷷O:АcxFGGoٲC[[Bނfff鞊d2y˖-C b^KW_AArɒ%/_ _~AQTGv풒2L8p@FF&11Q]yԎp8{zz @FF388ÇX7nܐ3gT\\ ԻѢҥKAAA...jjj˩yWZ._`{V %$$D7lؠ ޒѣG$)<<\]tƍ%T_P8O8zɱ7n܅ nhhXv- k׮%,H{ 7rx…鿵._\Bf̘accۥxktuu\RB]DEE(N <7qʕ6Jtuum߾B]x~hUUݻ o޼)nj8OṦD{$nܸq؏oCh4bxb«WΟ?? #kVx]VZZZUU?{Mvs̙3gH$ov) )0;KKKCQT\p9ii鲲3f``m۶kkȅ f{{۷=zuzzz666'OqҥKׯ_OIIaƍ300PUUf0===t:}+Vsk8KJJ®)/,,d0===د$zܹs{{{X/.kgg7qSNaƦ!N m/߁cǎQ(W87'O7,8kM:ի\yꫯpVr:::G۷0tۋ9u8Ox8z)D vvv>rww7?y ͛⬀f֬YحU~~~C0|W.NÞid28+߿A/b˗#rYET* RRR&Lۃhii!RVVrqΰ5i$F^HO2[CCg_OyK޽gϞ%''9s boorEE &7nWxL8bܩS2Dgmmp͛7g(87RDDDxЌywf9w`ۣwGZ &l8H|W^chƖTTTtA;Nڼy3M[[[Ei0,A?ZZZiii666g퍉x뤇`2CeDDDbb;oSho㺺:]]]RZZ*P2̧U_Μ9ϜaWR?GzuOؒ^//Eݻw8oOO:uٶn8Xt:]v ߻wo-[xKwfګ7FFF%%%` ӱ8"NX8@r3L_CCÁ˱Yreee|!''go0eee (;;[WW;6<+dE-qSXX`-33OA={6eʔm۶ PDxJJJS./++Cu?h|g͚rcccR\\EfGd2y…!!!&Mޱc^zE&_۷o/X ??٧SRR['''lOlNNNkĢUOOѣ7nĹIqqqjjjyy9J5004iGoq\[[[IOT~:L~;m֭بtĉ*uDebb(V444(++8p@ c6ԃ_ϟoii)Gv|4"F3gPl5_(8T֪K*::EQrs133knnD 5k ͇R(cb(99Y^^~֭b Y*lllV&n\B"v-Ʈ<~XYYyŊ~`hӦMkooWM`bb2MDDBYrX"_~R~p|===;;ѫeggZYY eRRhhhXbL>xEbWSS榤tY9X,ֱcddd>o`#Ǿ(X3xۏ=bll 30 X{R({ݻmp]6~x99'N-LLLD;w+W&%%}*9rˊB{Eo^ѣfffd2>be71 Ν;?;wPutt711QWWknn.//KOOojj5EEEA///~|rKKe2UUU+WܸqeG%%%egg666d[[[77iӦ `씔G1$//eii2eʔ &B>vDq  7@_IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tube_isomap_golden.png000066400000000000000000000437011450372207100264370ustar00rootroot00000000000000PNG  IHDRzzGIDATxw\?m,^HW*A;Ē1^I4vn&1QLT( XPTE ]z鰰+.GqyL;CxX,V\\o޼=ȚSL7o^HH FDFFFTT+**Ym„ ˗/&IN0.^`=zoggw^UV|Rr劋GBCC?~ݝxׯ{zz޻wooW˗z[1̳ghm۶ :`绻He˖egg0---88AYfUTTk5q(nݺׯ_9y򤪪ĉEcǎIIIM6ٳgUHOOwpp?wpM]];wD_CC\BB0KĂbZJO?~)//M,--+q ˗/qJLLD_FMl2x};}d2,YryMMÇoTN.''ى6ۧx ***8tuu!"##s}hN OhA~lGwwԬY:::QVVY_ 9UUUAB+++d2+++q֩p0eaaQTT.XX$YA{{{555I&yyyxaKII˫A dlgggOO" Zm~wﶲyNw_]J/((Yd׮]:::ϷNٳ'++  Fll \]]gEI$˼y Y0&&L&V OYqhmm-%Kmƍ?X-[L>]GGB0E/_~ԩfM^ڳgO@@IkIJ?|p1Y,\vp,KGGG]],1-u8ٳD@)))EFF,訡QWWŞ'LY Ehhh8ydHH:Jںukrr2L ogΜYrGP(ZZZ቉,k"  H$ŋ z{{PXƍO@n:{{{ >}҄ RSSo#T^~~~RRRPZhQdd$#INN޺uFlmmCBBN< T٫Wd4x+WXXXjkkӧ`8lss8pV<X,YR^^wU>P__Zc###-Zdee%''JIIEDDt7iƍrrr={͛7KII=|PŢ;&&O?uqqQSS?jD&544>8?ٱcD;wgf̘AR9"pqǕ"##ƾ}'WnkkÿXP]]]! mjjM"$Q.X@WWw9tKK DFFt7 bcc#--&Ta/sqqH477W |իW&csssExp8v555:uJ3/:::ӧO߲eːϼHBMM֭[%Dgg… %Ļz {^QQglْ4ObFFFd2y̙'O|+\nqqcǰ9!;o\{{sΟ?f LMM544+**JKKLټyV\iii)BCAvv>|XPPۋ-յ6mZppDlٲ\>䑜um˽wޭ[?~\RRĿSQQ+ @CCCr8΍7;;;UUUdee\nWWWuuuiii{{ʬY/_>cƌ!@1n?~S^^|EEEyao~ܺu+)))33_$IUUGs:::^~}̙. .R <*++cccVt:]KK {`% `o/8NvvvfffIIIccso&mmmKKK9 7n{s/iffkԼZTbܗ-[V^^@¡ }U(((8qݻw===Emoo͛7& 8n`H$Bϭ%,f߿#ٳg)kӧO/Ydȕ'MT\\nhhTUUw[SS8o < 433Yfq# 5a=v yyyx0ԕ+WH$ dq)iiw] R@PRoғ'Onܸ o摓׷:ujpp , HmmmΞ=;!!_~%" 3gr)))7oְ/OEg`` c 3:::44T=leXoߪW_!f]8qwBܹs4 9 st#-=#'' k׮655988,EP,ĮsK7>:upNr8;w(Q'sss'O.s n;"RRRrѪ_~eҤI7ĚxKϲ7gΜ$쵫\JJJ3`lp0dl:naݾ}fm޼9,,V##.+YhNIIᴷ+** -L6yc…gDKKH]cn;]]]왣qwwѩ¹Iee%4? n;333:^PP0: 8Ǟf`l(ʤI=zs166UUUؤ'xp87xzz^v \.ݻƶ;99M0OϘ1C΂1  s---?$ .߿?##&;;+W444?1hggg-0~#?!|K*++䌍׬Ys}}}}; w^zuII #{߿Zb 3n` ǒ%KLMMI7ի}m޼fvÇϞ=(ц>3 >䓕+W666J/??JPPu1JII ݹs3lBBBMMѣG ,عs˂%%%xK\GUkXN> Og7` ++899ݺuk8իW?B5 ǏgΜ=%{{~ܹsGa/𞁸YYYW9{8{kppɓ/^,1`0~a^^?sA333??)SX[[*++colll,++}͛7Y,ւ N3uݽ{Ek׮I iӦ^ݽ{7Dڿ8zfܹ'NUŶ6== 6`|g|ZZZ &$$GI&UTTӧI$O?$ƚ`8ݻݲ+醢drAA;㦹YVVtWx<^ee%F;{,mqٳgUVVhLL+L>=00&Md'ȑ#t:}[={f9993fizժUyyyO< ڵ+--Ql믿fggH>);;Çnnn87ȸpBYYD233[b5m/_pJss-[.OOO--̙3'N D$((gGa;.=F?~\rMl777.+V>3;;;(XΝ;׮]#G9y)ZӧOtR%-B$<<ggdd} v>>>nB\8;;R(|E6l"dMMM'''#%]]N˗/GҥK8+ 2{;w_׽{:$醬BCCwr%& oFˋDJJӓf''',%`zGଂ ٳg,QWWGO'Or82i .?I𬜗r<m۶~3gH#iii[[["!GGxlqSPP2!rA,--qf t8MTUUݺu+!!֭KKK{{'O^``oq3" ,--[ZZ,L0gUUUuuuqS]]m``@؀&FFF_ x/^TUUodll<`&CBB/^Ң"LO^/^ܹs'6[hAA͛7.\0p ͛o(p$Ν;BƮ])2y$((ݽnnngΜs  'Offf۷{ 'kΜ9 D"a%T*ҏ :NѤސ!+++---##W^^^ 999EEE E ¿7x<ÇWgϞ} ׯ RRR-[v>B /C}nd2BKRoh}Ccى?#,,,<<ؒ;w}p uukhh1c-kȑ#/K___gtuu"}DL&+Y_>"Xb NFF9,tVPPbNQQQVVRee% kbb]aŃfwNlw}l&)= iaVlw*''feNq|wH/ڵk㦡A@ܘ j 00СC"k"~/____[[[w?o|X,Vww7aBQT˗/'''ա(j``4oV{{ɩYMMmȕ_rr L( SRRF??O>d8h.]D"ӹsO$***Q |l\ %"FAd29>>gh}zzzwYLh❪wڵ8WNLL\bŀ}}} MMMx0 ))Gصk:tS$vCWW?h+`p{~T #yu2+; ģ]CCc͒nhҥ&L1؋_/_ndd$y]V[[ErM!(zm<+geeaӗ?~QQQ!!!(|=[`z ܹsd29--MrM\|Eѻwb|hccsUI܃ԩ5kܸqCg$&rJVVV}}}GGϔ)Sp```p  `X.] /,,tss[z5!ޢ%++n:۷Tݻ^͛(/^3tvv:88r]]G"7F_=W^][ҭh?S jjj'M4?/_477pdF"fI.w^$d2ɓkḻF' 6i>+nx<^NN˗EGIID.DsNYYϟK;dddF))ݻwߎ/L&Ck׮EQtƌB6,,F999sfԈxTT+rLLLN>ːzzz;>ȯXdddb9rj.]`NSN6 ®•ѯ~ݺu4MGGg֭O>ȗᤥnݺuS΃]DVV֯zVSSS iii6RQQrWZ5|sLhnn9sfCCC\\g;};vDDD@N<UZZhaa'''r;;; /_jժ!'1n0,ӧ)//onnP(溺SL>}p&Z#sҥIII{ٴiw]Յ޾}^v $޽{%%%&&&ږ'O^xGb^ ..{!:'//oee5((JyQ:_7q(nڴ)??>8u7n۶;qvv&`r(sV-0V:tŋmʔ)ֆ*** `466>x𠰰$44O??G21L6xuvv޼y3999==O}||> \./_TUUNfi @ `|S@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@Qtwwuww#UUUpFS`tQ__^YY_ Fuwwh#Y0A܀%''>>7n644TQQP( 4'''55522REEeժUaaa#w0 oM0rrr9s+Wܤ~222[l (RT7s7@06m6#33ƍxG>}Ν;tv7@3f8q?wvvF(T*544?z 奤t-eee\rNpp0KM0&9w\ (?ǏcY0@܀o TTT^<88x޽aaab/z-r(윙)ƚӦMp%ʬYjjjdZB"( qsqI</5kDAǏomN7?㳲~'I7d``ٳGoH0vA܀ؿG}dii)扉1118W޼ysKK˅ Dk ]7)**JMMݰah?y$00ǹO<)Zs`삸HLLiDض{ҥl6[-[(B`삸ݻwE/v3ftxj\nFF^t)99СCnH&O&B`삇ƻҮ' amm(Q>E'N| F7]]] Bm/_qFцEX555m (񮥥D" UUUmiiys0xf=駟222 Lz`t3IIIX,.s}tÇ ]& ӧ77㝪*{5Ý-[6vԆY-p05ijj"RVV>ǏwvvKtvvbW[VV&)uq30k׮eddTTTtwwS(gϞ}Cn`0/N0EEE%Hjjj/z<C`MJJKOO/))#DSL055=sh>}:i$ltuu[{ g__vXSSk^6n`t~+W>|X\\ֆ-355uuu _:zݻED%Ew 544\x1)))77799| BҲ^d1DnnŋqMLLd?P^^>}1,ׯxB888lڴ޽{\.OMQ&??Ŋt:]ZZzΜ9GINNv̨u"2eʔK.Xe777eee~ۇűX`_b}d2~G$.222((АJw*CCàƑ#^~k.---4uԈnlo A##wuu ^Y_bDrtt:r)))K,!<1!77w| a9X,Vhh(D/2<UAA!>>^$Bii?뫣ßهF̟?ĉ#G1c2SPPpe+++۶m 7ΝSRR277r Q]~}ooF~aƌq&N777_hѩSFbpYUUUSN ;"(GiiH//tKٳٳgvoNO2]lڴD"mٲe_ԱjjjNNND^,R0رcMMM#Gx.%%e``{gXo h7Q=%YEE?YreLL vna|ouup(++߽{7L&srrr _UUQYYX JׯFFF8PYY9}$N]]7|]0aʕ+…7n>}zǎgƞc6m=OQWrrrXXd 0'H$ҶmrvdYF]ti.xbEEEޞ1}t##Z1NBK#pvﯯb[[ۏ?WA,[ ]\\’G(zQݶmB0F"n"""tzjjx%Hfee5ns\nGGGkk;N0!VC555쓖3R}KMMR{Db>DDW*55 6Hl6{gΜdM}jzzzK,P}6=qDqcll"`bccQ]ɟXC^x.vJBM\ظSBy<^CC۱?3n{eeW^I+`gggq8իW1L4$TUU r 422R\@55C ݔXXXfkkkOO;::z{{^Y^^r{zzO LZZzK;/< F7'O޼y3+-&##.;vL8q8Μ9#V***UWW MZ%]ƛN"K,j+###q֦2ވk sgX?W_}%+n8a-4 s?s XjdqC ȽMoo/v7 0 gg?CXXz{{čZSSh֢4ٳׯaۦ&qcll\VV&ZoDhbbBp7"_~rܗ/_ \z3999zzz xPYY.aaa"4Z\\,`-++["wHTr{Yj>x@YYY@p\*MWW۷?CZ`RTT._,V/^,--ݼyhb()rҥ7N8==o<2kkkiff&rb=zt̒Ʈ.$++mii1i$CV~2 @A n qkt\IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tube_isomap_noasm_arm64_golden.png000066400000000000000000000441111450372207100306410ustar00rootroot00000000000000PNG  IHDRzzHIDATxw\]veq齃t0 vQ,!KF#֋`LL41$*( +#tX.w/Wmsog̜Gf#""޽9Ě&MZxʕ+544h0"RSScccˇXgvvv$ ډPo֭[vvvGm@7n=}xgggbblli>˫tؕ###׷СCCWHLLs0ק~qvMUAG @83f#Gޖ#d2 OKKm۶E3--ottt[n-¹ LHˍGdٲeoXr! ~~~oߖz?655YA}vsssA6oތohΜ9m ---7qwwڵk)))8+xzzTggg]Q~ |{'N핖`***&&&8߱cǛ ?>}tq3a„L!z#L2G)**:::nڴ)!!n?.ZАB߾}RR~իFNNsÇQ>~ݞBL[iӦ~gNNN؉*lxN{xx۷@.0p8kZ[[CI$9sBCC~ʶhPzbll'nz{{UTT„(*\TVV(z݁ \|r333ޥRRRgΜiiiܹ͍Fv(]]]o<ċ/;w@Mh4&)\6mz,TRRxb777mV'N\h{8=tHzԩSs5 b8; `qy&L7nܾ}mFFv7EQ޽{8m;;;8 H333w܉~f T QwFl֭[o'#]\\}..."> #G(++`6ZYYʾy*8#kLE?Zvv6DyPqOPΝ;'ѮTTT(((_cͦg.\@J?1RT˗_t[ .!!!ӧOWWW]`oo'sؗՒ%KXMgҤIӦM~/{URR*))\Wf͚ekkb$D˗/80uT55/g}#d?~ɒ%~ɵt%5KZZ#6TܰI&ڶK+v풓͕D믿6nࠠAUSS:ue'666((vYjOOcǎUTTٟ{Kh3>>^JJ̙3%𭏵)((:u͛7Dqൟ~iݺub)(UUUWnnn}}=5228q ͛wcS<tccR{,khhtҽ{rrr8 222...=yݹsI,5߿pB//OPeeey˖-R"۷Fܹ3''g;H("##TGHHF',ʕ+eddL >k\7|CP߼W744xyyQ(} }f֭[zzzIIIU)l6;***00ʊ~"H:::s=u>JJWWשS P8q#G7om}*--}I tPL yC- … mmm#Gc?!L:\r Ϝ93eAƏʕ/ ~˗/GDD$''뛘X,SSŋZZZ л(!!!22299;nmm=s+Vt ooo`^ rvرt .Q\_TZZ͜v3g\lHwΝ;qqq S\.MUUu޼yW9ss 7<O>.--mll?/^ckkFCF[neddTWWX,\exWO>vsszX;::FEEa#""^|#dnndA7pӋ ˗ Ҳtqq`c!,ޚ$ǎ{;Ϟ=SVV^lxv}||tuuyheddxnpPP(o. (:;;?XJJJdd'O ڰ F6m innvvv655so\\={6y>ɓ<7oFGG`g555==== Dv҅!샽FFF^r:::ص Ò%KLLL$w-7PP}ԭ[fJ,n nF!~?$)))-;ƍm;驩;J^vh8Jg1!''?|F4Y,/^nfftAQtwwGFFĤWUU9tRScy 3g;vZК?1F)** q ߻էOR\\,뱱iii555l6} ;wҥK==~3g>}Z>8q'88zzzk^t/_ljjޫfff/:up?JJJk&=Pdd$ 7Ommm\33˗YC`(; w۷WZUUUи)..xy̙sԩW^ 1 p0y۷SSS+++yWPM6?~\ЂfRPPvpp¿ =YEEb=`J̗rLFFfk؏uuuW\wqq'z{{>-І(XbbB][l={<++㩩MMMBnkkvy!( sFD___WXq)ޣSehhXWW'ܶq31L2,[nurr ]610vXpgjnݺuΝlQEQ1X'++bpanOOY`N]]Agu։>T]]4;`f311AHGGgؕ322޽wa%h4eer<cMf:::YYYӦMveyy7Wc2oVffE2xWUY|yww7<##c„ ]U`0ݻ7sL#Bīa C#qu1>qK(otR835@DII) {Ъ[YY_t iii)))6l-N`,--#""$ݖwoo%;b`jjnݺ۷wuuI#GH0:A܀8|poo_~)&>㠠 WWWɵF-?ٳg7IWPP D}0e~࿼GiiiyzzrPPӧOLt@ػc|… cbbUoڵW\q! ٳׯ_`SD}ƍ3f]qCQ444;w5kVIIХ^jkk[UU!nw oO>mmm޲e˫WSL xӭ$S΀o?ܼypɒ%зV͘1CYY9###,, Ɔ*p8ׯ_ǿf``*%%`0JJJrrr^zlٲ?FyD=)))99555yyyl6̌N;88xxx :1xW@܀3pq  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q  7@q HwcSSS?^SSSUU Ȇ ta?K]]ovte``DRJKK;::h4̙3WX1|))xwo0C]rEEEeɒ%8qʠ=ztu???--͛7oذANNn:F~BY5Ha27o&NNN¹ammUTTtuu]&n(JP𗙙ibbs\!*455_EUVuttHh" >]6i$+++W(*DUU>!!᯿rww@O vO?"V>}zZZ𨩩S; Ŏɓ첲Ɯiiiggg===[[[777**ɺ}… W_lKKˌ3X,VRRқ`ԪQzzzaa!HOOGQt„ ZZZԩSBMiis"""***h4=v/++\^^WVVvYf  RQQUΜ9#'N?~[;:iooxbxxxjjb[[[uuuAAA^^Xzeee+`ϋ/.]J"ۗ=8bmmgΜ lG__ɑo$TeǎJJJAAA}ʝnZzN?|pggm۶III{111(**d3JKKo*///WѣrrrUUUmҥKjjjZZZO:8iii9r䈪~LLV7vvvvuuUTTzp477:tH X,++@I7ٹj*uV&)\Ƶkע(g7W7III4m555oΝ(߿_R@k ЄJIIUVV~„ ?Ztt[ 7O<_lp ڻw QX,MM̓YwvvvFFF&LXhѕ+Wp8##]vk Ǐ,//W\ɓ'Jaŋ˗/p8 ڵkd2̙3- C"ڊ HPPKKKSRRVX 7uuuE5nWWWss:V...=4T0L ӧYF Oņ qҢ00Y8-v} "/^@$++KYnZYY$gff۷d555$̊+ bacc(sqFA>3>^rMH$ǷMJJ QQQ vΝ;% BGGDu(En݊ ȦMoxbQ%6̇R;v̞={…bqUUՐoիWmMQQ˵Hnn. 'NĿEAA(Quvv9rD }7.]BvU Hjj@1fKKK/h+ .tuu ]Gd֬YO455n[]]믿bNAOR'VVV\.;Ď-,,(ӧOo~Iݍ .W^n/rҤIjjjϟexx8v .##ԄiiiM81##϶$$$<3***,, Z`˗/sssZ[[f͚hggªUmxbv]]]uuuMMM-6773̶ή-\ѱLzBPT%%%MM͞/^JKK ɯ!{{GGGܼBXXXtwwvttwH$k.999K[JJJXlhqijj{{{=z믿dӦMiiiǖ{g_aɒ%'N3Ş={bbbp5kVBBB]]oEaaϭ9rȅ wB__onnn---;::] Loo/n= ljBHII }MQQq^kt: PSSvLgg璒cccQL&+gϞ۷ogggfgg'[[[utt`kcټ5K?DxqWa_SRRhؿZMMMUUukFRbbǠrssf.r7"YYYNNN|n233qvʃ^XXco>GGv%%%M 鵁V, yG===`XW.v@wUTTK{Z)čѳg pⅅx֔7~MaX,VCCCkKb2귶b/=K.[o333pf ˖-\?gwA555? g33Ir#&썂M`o !̱bFao999%%1c1A%322-###Ay;|JyM:\.{677744 V&v}c566X,ǿmRPPw#NǎǍ̷xqq)ŽWWB1447ZZZ8a?c;)MMM8`-Κ5D"b +;zbBVVX@`'4++1Ƨ7HHHƳrk⦸VQQOiӦ D"u؈6r'b}~{{;/}mGRL9swA]]2 bmmtRMWW A7[UTTĎ\pFddd^WRR  5o޼K׫իW?}}}lIYYٚ5kw&L6uX,ŋ&l «;hc;v쐕577WVV8rȡCbbbp֑7d2,AP.۷Y7 ܹsi4Zxxmۆ]Ĥc 'N|ԩS4]tO*-Z$Х`sڵѣ7pb{{;_3h9Vb`D`T*5(((,,wؕ-ZˎӧO߾}d>zg STTa;!AmmmoB议.uZ[[č6v7o4aJ矷~7鎎fff|q8={iT \]^ZZNee%z%T*jrZ u ;wܿ[*E ?HB{B{䉎wttرL&/XE"EQ4--M ݺu EQlOqРm6v&HD[inn DQtڴiOSfIv nϟ={vnnpEdeeOq;}tPPÇE?蘚^TT$>w /_޼yw}}vqTUU755d0* 97rrr֮]{ 6۷8xw 3gHҍ7:$`q񺺺sI SSӣG>|XrQ [}}c8%ц֯_omm{nF'o'O7n'|"H$]VRR"hLb?~ΝT*֭~snee5?ChhP*ĴYo.ij9|S?N"/6@bccL[nyḠ pn`0҄2x'A3g$Eccc(q7c]{{{QQ:99D%c XWTToaaApp XCcv@[UWWz EQ}}}uuuE O57c]GGJh+CCCmmϟرc|gKNNK.w @@611q---WkqsXf@~W2|F[1LxfXq3#R]]-Jqƙr8Lȋ/-"MLL|_ϙ/\䤪ʻEQ{{+W={rRw!HUUUxMMMp8ؒ4kkk ]$''8p`ܹJN>}qqql6g@">gJ<{7 eee311 ~_q舋{AfffiiiSSS__.:::Ǐwss?~9'|o߾aWZtiNNLmhh@3$$111YrX&$$ieee,--]]]gϞ=qDA,..f0s!w255tSimmqݻw|r %%ecc3}t__ߩS⹬\yǯ^9sM`bbNR\nKKKyyy^^^JJJtttMMͤInݺh"A/u \'OݻZTT`0x'ddd444]\\<=='O]fmmm=<<$7)r}}}\\\bbbvvvYYYss38SsssXX؏?X__6{l''' ۈdVWWݽ{733pƍׯZ*jkk׬YC";::,-_L&;;;?~XÇ |y(ǖ-[թS䊋%ʡCjjj$ gϞ]r ;L&oDjbXǎSRR}t]]݁ϝ;#S18{,DڵkZnJvڠ_ 7\._YY955U~𴷷O:АcxFGGoٲC[[Bނfff鞊d2y˖-C b^KW_AArɒ%/_ _~AQTGv풒2L8p@FF&11Q]yԎp8{zz @FF388ÇX7nܐ3gT\\ ԻѢҥKAAA...jjj˩yWZ._`{V %$$D7lؠ ޒѣG$)<<\]tƍ%T_P8O8zɱ7n܅ nhhXv- k׮%,H{ 7rx…鿵._\Bf̘accۥxktuu\RB]DEE(N <7qʕ6Jtuum߾B]x~hUUݻ o޼)nj8OṦD{$nܸq؏oCh4bxb«WΟ?? #kVx]VZZZUU?{Mvs̙3gH$ov) )0;KKKCQT\p9ii鲲3f``m۶kkȅ f{{۷=zuzzz666'OqҥKׯ_OIIaƍ300PUUf0===t:}+Vsk8KJJ®)/,,d0===د$zܹs{{{X/.kgg7qSNaƦ!N m/߁cǎQ(W87'O7,8kM:ի\yꫯpVr:::G۷0tۋ9u8Ox8z)D vvv>rww7?y ͛⬀f֬YحU~~~C0|W.NÞid28+߿A/b˗#rYET* RRR&Lۃhii!RVVrqΰ5i$F^HO2[CCg_OyK޽gϞ%''9s boorEE &7nWxL8bܩS2Dgmmp͛7g(87RDDDxЌywf9w`ۣwGZ &l8H|W^chƖTTTtA;Nڼy3M[[[Ei0,A?ZZZiii666g퍉x뤇`2CeDDDbb;oSho㺺:]]]RZZ*P2̧U_Μ9ϜaWR?GzuOؒ^//Eݻw8oOO:uٶn8Xt:]v ߻wo-[xKwfګ7FFF%%%` ӱ8"NX8@r3L_CCÁ˱Yreee|!''go0eee (;;[WW;6<+dE-qSXX`-33OA={6eʔm۶ PDxJJJS./++Cu?h|g͚rcccR\\EfGd2y…!!!&Mޱc^zE&_۷o/X ??٧SRR['''lOlNNNkĢUOOѣ7nĹIqqqjjjyy9J5004iGoq\[[[IOT~:L~;m֭بtĉ*uDebb(V444(++8p@ c6ԃ_ϟoii)Gv|4"F3gPl5_(8T֪K*::EQrs133knnD 5k ͇R(cb(99Y^^~֭b Y*lllV&n\B"v-Ʈ<~XYYyŊ~`hӦMkooWM`bb2MDDBYrX"_~R~p|===;;ѫeggZYY eRRhhhXbL>xEbWSS榤tY9X,ֱcddd>o`#Ǿ(X3xۏ=bll 30 X{R({ݻmp]6~x99'N-LLLD;w+W&%%}*9rˊB{Eo^ѣfffd2>be71 Ν;?;wPutt711QWWknn.//KOOojj5EEEA///~|rKKe2UUU+WܸqeG%%%egg666d[[[77iӦ `씔G1$//eii2eʔ &B>vDq  7@_IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/tube_isomap_noasm_golden.png000066400000000000000000000437241450372207100276410ustar00rootroot00000000000000PNG  IHDRzzGIDATxw\7]ҫ*tYAX cFD$DKb4b"6TP,A@`RHgYX=ܻ?. ̶+sDw?L=G#cёw`O .]T[[[Cϟ)//`c-[vКDayA##ŋwvv=zu떭 WZUVV&lwݸq555u͚5Ϟ=xŋcbbO?HUp5}}}ee]v`l}EkkkYYٝ;w;t˛2e H\dɋ/7LNN?> s)//nX`|'aڵ!rO:>a„<* e/_BJJ=FtR;`7o>|Pqz{{S۷oY l6{ժUd2СC^;44@ |7}:xTTTVUU3n:k׮I @dl6{…JJJ>>t:|НΝ;ݻn O<2eJNNN?'SGKKŋӧOG { VTT HbbPYdƝD*++Rj۶mV__8h ի׮]I/& HPPPMK. 466R!002}csssUr۷oD䫯ӬYDk .77y̙؛Lw߯':tbQ(1Ks3337}7ϞXA988?MAAرc1VKKK6]RRs6Fwzn?v܉J3fL?qSSSD]/_:99M|X[[{ѢE"'n,-- Et:@?qQܹs?yKK˯}v^QBuvvVVVs2)hđI&C TUUǎ;mڴ {{{oNOOuggGBU;zeDIvv6睩P]]-{|۞"L[_2/.]RNNF$=== Eˍ^fJ|UUUݷoߞfT3gڪzAgSS~b;vLMEE@{n 'O 055E@ )))Ho(666Rf^'jjjz:;;ћVVV}oⰎ~RRHx8pB 7l6ƦMCٹsBNN4c邂>xgy)))*,,LQQ1==]ddd?.uPo޼qssud_h:r֭[Ya`MMMW\/X]]][[[//ŋ .[]]r444LMM{6%&&޸qӧF%%%ssswww3f y<ނ ?(Y={6sŋuЈ*((֞2eo3޽@ Hh޼yU:cc|~~~$_enn_<~x;4BCC'M4W0LOOO-- I|!F u{zt:ŋb-((HVVbN=/~ nٲF)((,Zٳ}rhmm}}&N uDDsIIɞ={x` d2Νx1Kx#G+W`>[2wuvv6[n$''VaefffOR~7^z矓d$)WUUU?k0c #),,1cL>rH;`4N81bӧO'~iKK ÜϏ%%%Ί-C ¶mۆIFMMMI#sJJJߴiP_}LvqqHA544l۶F)))X͛ݝfaaA $xr8 v{ϷzXǫYJJJ# =anQ!6H$SNo:Gӏ?>uTAƏ ^t)222%%iii˳Xnss \JF7ozH$??'111 . :uL`~~ÇUUU%1FIp87oLMM-//G'9 [2zp߻w}a\___QQ1V559s,[lƌI*b0gϞeee644\rEYYy…zzz666/0<ܸq#&&&##vmmmkkkoo`t9ɓ3gZ,[UU5m4MMxNCÇׯ_OII)..nkkC7'OpiӦ .ŋK.!d]]]+++kkk37NNNAʪp81c١#tvpp򊌌eee}ѿ/V"---***))=G񛚚͞=[pHAYfX(..rJ|||NNN}}=C8::,ZlI󽼼ZZZRRR,$ɓ'NZ|4TXX'$$z۷Rcccggٳg/Xq#!$ٚv(CAAA/YYYiSsNUUU_h-jd-a@ dћɓW>}Ni4y󼽽\tժU?Fݿq͝;رcbjnn߿Q]]f[:::3g ՕG7˽w_|vȷ<ϽgR(za[XXE=cƌ}a= nF;7qACCsƍ355 f\. :ܺuBCCޓܾ};::=oQ7nԩЂZ[[Ϟ=daaAPb4f̘3g۷Y=z >… YYY^__?Ppt3 "Z˗/?}h]fkii!H>ܯH0J@ctܹq:+`LU7m۶=zH L&. 6p25ڡ(`p,YyfSSӎb2(1 `A"##AwxNrrrTJss3~t:5= nF;UUU33/^x{{ҥK{mlllUUU3gKΙ8zx +VyFFPOWVV&%%M'}Tq*++7mڴy &H0lA܀R.]vڡCQd.\~F}0ݏ=a]]ݐ VfفϞ=L F?֭[W__l2&zjloo JMM766HM0A܀vޭf͚Y0h-Zۄ[[[ \\\lǏ7mdhhbŊI&ܹS $'';w덍ZZZƍ322RSS쬫+))yŲ ^|PHoC!x씔SjhhO:UGGg  {{l~pFN n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8N n8DfFgϞVWWWTT f SSS{{{4c ׮]{722ruuP(UUU%%%JJJ^^^!!!ϗQ ~544-Z~WWWwϲk׮hjjn޼y C1j0,% A'''Cmƍ$1**fclXWW{n}}()@ dK2n8  JZZ x<׮]K ۥ0F+">N+D4555KJJ*++knnFظ{yy9::Jh ƍ>>>OVSSǏCBBbcc%7F u=JHHHOOo߾rhhkk[YYM8sڴi KAQDEE4LKKK^^455奦\rڵ"_\EDDZjH___#R_zf;;;;::;VOOF֪´,*q & RWáH3332b?77744TGGGAAaΝmmm|DGGH{JlKKرc$[HVff34iҙ3gYp!N`g!⦴t$/ސwuuZZZ:::7o- Nh_~4כ̙3G3 UL&󫯾"O>eeewWk(++;99eee ;V_rE=l:u*ÑRrrrǎR} r[[[MM˗/\c //?k֬8Iimm}5La`` z3GQQ{EEŶnDښ`_t100P0Yn߾Ȃ v'''쟿_u=xߏ[kkkKKK;mmmL&`tndnaXwl6rl6r8mz(dw%HOHUUղw޼y7`btttzn!dޑ%wQPP{Gt JURRhFeeeUUUA9%%iA#SLinn'n0VAƦt-555Y mMMM}}q7)74Fx_222o&TTT|3dee)Jo&JUTT,))X,HK֬YHGGFۻw/@;::Lfww7vf;;;9/Á 6999 _=Mwmeee+))aݳFXXX7X_8;;cobnnv=nhkkCSo0LC7X,vdA S@hF~UTTh4(33~655YQQQnn)S4622ZnȝnhmmE?L&d2Fkfwuu4Č6@Ahh} `Lyy9u((( -l6;11QFFf…SS~⦱QSSh@dѢE؛=J#H$XP(h qPVVVTTR҈s}}fu^' Kjj̉'4b[J>ӧO _.Z-[Hc H\{{ɂ Ś4i`AVd%>&+++iiiɓcbb([ZZ~gMMM--).--BرCyxp8իW SQQ,9oÑH$333//͟? HNN>:w>ˍx"LްaGL&388XAA/p႒ҤIfy޽{׭[ ˷lrd. ޽{NS'33]"&55O Ϗ׏3foF"! :PHN8q\hh7l@"߼y>}V6l@&-,,;e!:6}Ν9siӦeff # n>0ĉ***۶m+((*++k /^`_bXyy/1u)Sٙiiis8򼼼ﷴ|G[l/0ggg??^ZZ:a„3f8::ZZZST^YYI322߿_TTdmmq+V (q쌍KNNrv3f{-R> 70٫Dt^;())M8qԩ~~~Xj7=uww~2**JOOOMMM`8%x<^uuu]]ĉI$ҳgtv*#%X [7 ,<@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7@pq '7 Hf?[]]]ZZ*++ᡡajjjoo?uTSSӡ& n&><}[ ]\\ddd:;;N>`0CBBV^m``0ԣ _qrrlM0nܸaooO O~ɚrvi`` ##lٲR| @ dC܀*..&|I~~>\.7**ƆB|,K3nR1mooҒaee-H  i 7 ꫯRSSE+B$׭[K"ܲ%=L0@܀vwEDDٳD"Y0!!uڴiiii# n8z###,Y"QQQ3f̘={vIIʂ'OlݺL".]dii%`޾tҠ 6H>B F}0A܀ؽ{wwwǥŘ1c~Çeщ>,#rSzzkTTTXXX+Vv_SNhwܑvG@DLww%=0":tO>={h78{M 433TPP khhԩSO8!qhe7ttt/_|Ϟ=^^^vVXqe6-q3f`ٙkhh|WP)S?c-jnn~x# @<==1,//^y%"zzzVVVBl7]SSSyy)ҥK{mx(((`1##Cf+..FR"̜9{ k0zl~]}}= :::"7_?a uuuѮq31Lwm6KK˫W.\P h'SDr"4ߒn޼xb___B_0rhGѸ\.B/z6kkk;o<77TS䴴h4QG F$8޾} Hee8E_xIuu5L_0RSSˊvcNJSYOO/_,//3f D0778q׬YDFYww{(nzWjjj:;;/IƏ߳_={0ܘa``P\\$==}ĉ=x~a\\\ZZZqqqcc#A?Ts81'uF戈+W۫nhkkO4iӦM111.󔐐 Ncbb:::|~WWWll\JJ Ƒo۶rݪN<lmm${zzر#!!bIufxIIIw}NGߨ&4vڴi~~~zzzBU?;?~_xbzyyb췻p|PD_MII鵵, NRmllL2o<###a+,rssG~weeejjj[uwwda9uƍ+++Յ`0wyQVVViiiSSHTWW755uvv={AOuuuf"HrrrB=nZZZnܸqݤ$2!VPJzyyyc4`2饥oYT{433[dɁ$^'&9v_~E ܹS]]сn?~ٳ'N(?$oNHH(((@?=L0s޼yӦM[G˗/Xȑ# 5.А~kעW^x"}x?>k,##%R>\TTxΞ=+++K7ߨ755I6۷O6m̘1d2KF/?-]ԩSgDhlluttDIoݺEѫu|>իWׯ_oEV8`0,\,_H$:88?~|>L"?~,TSN-]FIIIL&3fڴi۷oAX[[ >UC"K>uuugϞ]l]:::SLٲe˽{btwwOJJJ:::?CUUV%%%;wTUU{L<`~۷oȯ577K>0aqd2MLL.]*_N p>ܷow"p.++믿fdd,UWWk.kkkAI+ŊٴiSw*W\yن}ZPPPWW'7^QQQOOf711Hw,Ç6gkkvԩ?Cee"Ƣ.\(..И9sPk,^:)) {7o>y;2{ q :5ZfffYYޡ?| {֫WdCCC###wwϿO? &|W؏.\ ++dɒm۶~؏ÜAd0/_^fHtuu]~}TTTOGŇyÔB͚5+<<C[n/899۷חH$޽{K[/7t:X8^z%++h"t ~c?QJJw}7sL### "+RVVVǎ+.. .cOOO==o*))Y[[͛7=go{ fo}Ϟ=;쎥"e;;; )Jo߾qHl?qjժٳgcfI$R7h?#A19{rʈFE=|ṘcA.\(H~Y!''gڴi %@M0=4w\,u\֭[-[fccwl{mjj| ޽{uQ/55~&466XA@7D6,͛Y͝;wܸqBͮsA?2 B166'nZZZOX[[[oڎkmmXG9O>ҢhT*=®.hmmm^b2n$,/ҕ+Wx񢽽ɓ'222˗/?!Hč%4BvؗC~> P_pw|ٲe^^^zzzT*رca?D'n4441@_;zGUUcG D#A1cЁ\__r¢111)))X NO`_] GDWWAƞ) ^n~x<^YYY?qcooq(uuuPiiiB<3_~6 ӧO{nxYCCC,Etz'Sc˖-C x@d...D"ɓ'_bݻw{nr:::/<~XUUx111GrJpn cx`ܿ QT)++]v _~eAAzyޓڽ{7"ׯ_p??sbBѣG 3gˏiq~7eeeruQ(C|7~ DvZܾ}{ӫ֭[eee&M277ؐ;888::9sc8ZZZ ߿~ztzbbbmm+p =|YYYG7<F]F"q ڲe>K544()):thoݺE zN+! L&lʕR۷oåњ5k \hᗹsZYYF[nUUU^~?~\VV6++Kz]xH2tRD3gez7 %%%W2667n\uuua>.۔,8޾}B"/Auu5hɓ'E>駟fϞXr}:NMMMLLLOO/**c0D"QQQQWWeԩ΂&Vv2 q '7@pIH2#@IENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/wp_page_golden.png000066400000000000000000000646231450372207100255600ustar00rootroot00000000000000PNG  IHDRzziZIDATxw\8}YzMA(H1XPQ#1cD%Vb Q(bD H^ŗ".W{P8ޙ[ @+**z/LWWkܹ$IB!133;s挷;w>ٙjժ|777 ӧOx<Ç |{}ǏnnnnBcAAҥKi4ѣ322ݠuƍ#G>y$%%%55Ç?|p~~q6o 9`Dt ;v HB6uq???ᛂ Buc'OGb0iL7?BCCO>JaaիW) -C؂n`k97nHKK_m|ѧOF}18|``[pL7_dɒ۷orrr2gΜ̗/_tz qŋ'NPUUաCpm%%%"+22رc4MAQ>|tիի盚踻߸q+V(X0̙3(3fL}}}bbbzzçLH]]766V!H>L8,&&cƌCaa"?ɓ'EEEhZp?HMo(FrgJ&Ϟ=ݻe#l6ÇF Avן>}`ii &nݺ%%C>yx!Hbt[AA444Dy}aa!@__FFFf혚/I nzA^ee%@AAK*WTT/I nzkjj~ ǏL& EVVЀyy> IM:Tfy r\)BHtӛ\SS555vuu!CYpHtӛfyy9_z=577#ǃ*++l i L7^OOI=?DO7EEEÆ ?^0feeERP^?snȂ=ǧ777/I nzcXoFyVJJJ ͹slΝ;݋!HZtӇS^|em o'׮];|@@'/^kIKAoߒHׯêÆ =z4N kooGyo}}=:q℠Bd;ޞ63|pھ};޿k In蘚C ĵ#"L7_4k֬/^dgg3 z>_QtttEEźu͛޳g5`G7ü_}Ց#G0oL7Xv]^aκ>ASزeˢEO~e,,,?~RRR5Aٰa1;ƕ+Wvuu9;;#'K,))gذa)))|AnPپ}_sNGGG۩z^hѴi̙ s 4tsrrǎ;gΜϟ_:thZZZrraEphaÆOxyyU^^~޽K.]vD"˗/KA =zɓW^355URRP(>|xuUUŚ4iMTT͛׮]KtDnUPP_QQX,СCmmmmllSx!00݈O?%%%y{{ ё111yс@1̔̚5+//@ pt#:***׮]#:"L7"5~VÔH߿z-85##݈ںuΟ?Ot $jptCyyyMMׯ_oy \ 6ptCv99 & 3!h0I& L7ؿ? %:0EÇomm=x с@ ޿Ot $ ptCಲ'Oؤ nDR}||233kjjp Bt ;0EL}q8XVpt#^ G7_~|2с@Fa nNPPPQQL7*//ꚚJt,%8;,ݻDAXFݻㅇa >LC~@ 3pt#n|q эRRRRTT,--%:݈e˖{ٳgDA؀b)ɳ~.f эD266mll$:HM6555:u@ pt#TUU߾}Kt x<^YYYwCyyymmm]]]Dth$Kڵ疖Da,===99޽{YYY*''gkkkmmMPI?~{F[[۱c8PXXhnnikkkjj'//PVVVXXׯ[ZZXb4Q$Lnhh :HX\.ȑ#ZZZ Vz;##3g``ŋ$q1O>{{ee?@P>|O؀SmĈo߾ea$͛7LMM/333Ξ?~MMMBB#1bNK;w۷@ A?믿~00z'O8;;WTTTtuuە+W(͛1lㅄ0{a,V`xćgϞ1̰0<_pWh\ݍxL&ɓ'555wyannnIIImmmGGJUVVյ7nܤIzPkjj5jԕ+WXf'MҒ!V0HK.?t:DMMdr8⼼z%K,X@FF+VǿxBEE.޿?rȰuԅ ^A: LrJ[[[?sܴe˖ɩڵCB]yyy ܹsxwgU^^wGt#JKK)ʷ~[RR׽uuu6l333-F;;;tfMLLVX!PFR%%%))) ȇ+itPJJJ(իW]xϯ/k׮r_j,K8F"аVVV>oTUU}b~q*3wE"b*//2d0-|C%%%Wtא!C޿/LXF2e˖9׎6o|A1&uuu'@b 獪uuu!n$׳Z Ս(R80#z?tzY,c(UF2>|8 Ђ BBB,X;jԨϣB'O.j0voWVVFsvvv[Cm!n$ȸy)Sʕ+nnnbX,r :::ʮ^zС oGz6l]C_2{_u޽}-uֻw***^| }捶m˗<==ۆ#G=z_~i-`wl+:٩nݺK2 #=‡)l͝;7"""66vٲeJ##:;;ga~^^޹s?.++{A___2ǔeeӧM[YϿ[kkkoݺbۇFdʶː`V\ihh(3[UTTlقwGw7`0LdTTTSSSUTTBBBQވǁ0f͚O>޽ FHHӍ5/YYYooo[Y FCCcÆ 7n,,,į={l߾]NN^ӍdAjUUtttL2㏶x_]]={l__yѾ`(/~)rS/Ȕ6 =7n?aBh!_jkk81'N`۲`'N|MAAt[z}XUU,++49Λ7o~i)$<ǏϚ5K}466N6ƍb  `kkk``p94X͛^;{ 9qE47nhnn:vFu݇:99UTT`qqq޼ys]1$ ,+֯_oX򹥥޽+--}622Zb'Oh׮]"v?k׮ݶmk? 1b˗#DCTVV2#G/=ݻwE Sdbb?I&=~Fn߾@R׮]f0H0--F;rqqnyyy&YWW3wwwK_VUU DÔhhh055 ػw/~}477b͚5kŊb{`D;$)11 ׮]SP0M_mjjJLL suuM׬Ys6.80!!!'O|棏Z]]۷o:.֭[<==T2PtӍp8_}ӧOSSSGU'Onmm\[iUSS`0D#RpݍR.\vrr}6&mzjܸq---n݂ovvviii-t#LիW+//7 >..VSS:::؅ ao߾ݽ{ļ/ =zTVVvȑ!..0uT! H%K[XXx{{;88}bO<ƍmmmNNNȲw}z!Ǐ2ӳɓw۞7&&&]yxxΝ;Gt F:}1##L&\v<K#gMܿ_a ;w,Z@L^l١C]EEdG* ؘ 4RPP@s%=7|$۷odOOONvu֢E.9Ht#ZZZ/iӦcYzaOcwpGrwwqKKM >%%%X&=Z[[lvEE5 8ZЄ/LZ&p&_`ZXUA_n]QQ1iP:MSRkX5hllrMMMڔ\V„`fFFF ͛7X5SSӑ#G>6%`) 0%:::  O1lVMFjuvv`Ν;uuuWZn18MFjl r<A* Bp0`Zba#-[ybn|U,tKh YUUGbVH-.+++S7n`كx dS`L7RK^^ƭ曌X+&̠ٳgS'?555 EIIIWWwԨQL%&H$RDD՛kkkxI$>`%L`Fttt\|̙3iiiMMM&&&222eee$rƌ .400 :jq8~L ))aԩõ#JX"H477oݺUCC`̘1#66+oݺrJ 'xRVV8p.^wGD3f I@`I7ΝVUUݼysMM ʻ8Ε+Wlmm)?؈sAURRbXx%zaaaҟnd+kٳZZZO<:@\ O7)))"ݻ///%J7oD+tSVV6j(]]ݴ4!>}:ɼpF(!!)NjkkLb[[ѱHiT'O&L dk*** ?ٳO:QxȔ.^(//)6vX sRnjkk=<<ݻI$߰aâE]I8qR.\hii9shz󋋋w 7ab.\Iuu5XBNN1%ܩS"{8E/U8t}v/^>qqqĩ !\R馳SVVVAA劸kPT---NR0ݻoڴiȑ8uAPN<ի={ԅ0)2/vF ]`%L4j(wG[nURRû#PTBF >! 9ٳD"-ݔP(ڪ%`0麭MFFFYYsN@PPсH3iۢ+4屑_*R\7n}뫨x}c,*TTT|{WWצM~G3!] /i'%%}UVVaU& S* |+WJJJ/_]222$I~SM;,]z߾}D&LBHUҦM;'Dc2 JMMP(S%O?"^$Bxqڵ|~$#>!رݻwk֬!:y ct*hjj vƍ.\H'''Gtgʕ۷o-aMĒtcjjZXX(ׯ_FWaa!L:t$ IX XRn>}*7n 2dfeeQb6TҍvTTԛ7o6mDH&^ ׯ͛$u設=#F͗/_Nvvmۈ &&& ݻw"7;;L&6LB=IՎp+Iggg%%%ӻzOSSөS\]SSkll?Bĉ>>>ȟ3B1227o-X_!j\t vZlmmųfii-[\\\ nȹC 144/%$$II[)..&׮]A_mmm֭26}ܹ3g"d]]]K.q/rRvu322P(" A_=zhڴid2YKKkٲeϟU#(?~NP4557n(piFq mZmee%ӹo߮0411100YH"|}}cccl6&]t yIkxx5L#1܄Y\\<}t{rr2Sn+**6oެw^ =|^ Mqq1ܳg{N^^~֭4h")2rVSS򊉉iiicǎJJJ o}ׅVNsI&YXX`Xfffb)))DGG;~F31>KjkkqjȐ!d29''p[*i&!/((UQQ P3p8I&~ WZbh+''gʕGd;99mݺǏގ)6 H$t͛ؽ{7󫳳sƌ)))4>w\uuL LUUCcc#-o߾0qDl1cưX,$FFF~iJHHD`?>vXxx x_0J</00PUUqrXؑJ;͈ vZ2lccY6oloo߽dZYYt_h"2,AӻUp8fB(**N6mΜ9SN@Yl٣Gz5(n07ld2?Sx݉L&#377700xMt:]]]?`DTWWo۶ٹׂ搐j wf9bllL&===9'77wǎȂ;;\.WSSJɛ{Xoooqrr*)O7H9s&B mjj]]]}}Fmݺ`llLG]]޽{TTTp6l` ʕ+KKKߛ={l2+T11l0!Paa!씔4t/hOHHwKKl\\Mq8דHPX֦믿F55-[/a thkk;}ԩS׍ӧO={_=i$dDX~۷ol3##N3L|9rf\nBBB@@ 쬭xbՠN8!##עK.}~~~|=T_^[[GjG8_:;;>}S\\\SSNPtuuG0ƛ7oڒ&Og:t(.--۷o>x𠴴"w̘13f̘?~;~\irssҰ=,55gʕ;ԩSh.r޷oߎD[~}^^ٳgдP^^n``-t!:I*UUUtIb#`dA)FC~*]]]{zj999^xD"¸L&'%%~Ϟ=ŋwRVVFӕѯ)0a’%KWD`RKKG[ihh1;;;$$dȑ /hF)55D"]p?!//Otx||}ݹs|,_D;wTM__秥sA3BA?6Aիq@\.0111::zʕ c_D[[ۈ#ddd^xcǎML7JRq=`'@dd:B{A32lŋoAꈡ(SCCǏccc/^5f###&侞T&Z|9^i4u߾} .DN{{;DJLL*Aӧwurr¯d ~]L&gΝWSS㷅˗_vѣkcc4iR/D"t```oll<|psssUUۢ"lCC^_&&&v޼yDyt#"VVVEEEF0a˗e]x@fC{苏"SSS~xAAA!!!vvvEEŐdSccckkkgg'yJe2111155:th_wsD|2`ݲX,Q^/z0݈>r׌3}zܹUUUx<{{{//y닦wd"2>>>00.yɼy/_.?OaKERܹ3۶m#$嫯rttTWWG:qNQUUtReee+BxBLII!H?%%ӧ{D?ܹ(|PF+))~Mh4 >%%KgϖQRR3rm۶M &MM_Ҳ䘘7)`;J={RKK?LѬ/\ى͆={(++] YMOR6AAAeee_=t NRSSxwRii¡CN6Jn߾qӍ8bK_33355'O /Z[[###i4U˃uT*ťϧNsss'n7ݺu ׾쌌d0VVV/_+TTTȌ9R|r(_`_  eee===cjjjll_pm=imbb/ÇdS0 O?ݻUUUuǗׯ_ϛ7BGFFsSS˗t~LLd=@ӍXGR=V?g>}rqqee`6l&/%HW^EAAA$B~aOk֬100@ 4iҥK###-[[XXPq1; nĝDjkkD%%%q4ѣG|P^^e555%%%O8LNNhׯ7o***[˗/>wyzzZ[[>|Ĉ3fXn]RRBbVZZ2w\<onn;v,zzzC9_ߋ/633^`0UTT233>ٳgtF1qqqHP7nsqq3f V۩>WRR>)`ee{!L7,++FYv-Ϸoߦx8q"B;wp}\{Obb2DD# 0FFF"?L,+88X/^?~ BKKڵkT)Sjjj?߷oDRUU>!MX%Ȳ͛7 BCC) D Dp-`؇fΜIիWh4kkgϢlllܽ{ʑ#G> >>L&X,ĥl 'pU]]tqL7NmÇq ,hZZZ˗/OIIR>\xqΜ9,KQQq͚5TNOOg0T*֭[„$'''*%RSSՑ-"L7FĢX=~A[8;;O2嫯񱷷G Bxxx?~WD" oŋ/kkkJLjH̙3qZ@ nԴxb]55͛72KRWWk׮+W2LEEo&,,>GӧOHq7I~~>DrttFFMa!'0Ll Ӎ \\\mssD#խlf#5#nddD =1ߨ)"kA0&&&H}~///q+\lkkISoٲsϗ 5cccE٩(m޼vimm%:at ͎@VʆT0|oFoUUJ6lV]}"Ԅ,,۷o':t32???흁cLj?rrrZܰa@GGlmmI$Rqq1]bD߯eff +ӉG@0|QjjrV}ff& ¶ͣGH$>/,_~Q222%k۵k566`öm444k```uu5d2Ny)))T*`|PCFFF]]NQrssc0D.zmmm~~~&!`?uuuAAAL&Bm6#Nimnn B5 oMBCCR\dBKKKvtӅ999!']YXXܸqDRpjÇ***${1HZZRHHH荚ˆA}9;;Xk! ts)###dbK'$BA_}Ar*į544HFM쀀DR#""pꥵŋo߾;w yP|hht,Gmµ .2l0ٳgq ب)|557ob&ùyfHH%BfF ># ])--AlD I} HMM #J%ȉ'X,޾Jv6mڤɮ[.!!˗ <~/^\z%4::z#Q~ȑ#m'',#`ʕ"hذaȫaÆZQQ ޵kQ[(,, STT:zh?#O7=K81E})ێ;[nEC]]صҷQSȒ1%%+W+//JVVv˖-XWWAӝ9,sN# ** .h4Ν#rrrQHk~̝?y;immOիWeee'MTZZ*L/_UQQIKKGٳg۶m;w555{E|||Sɑd H$$WYY٘1c /^տD"޽Nh4{~(HIHHGjDDD$''z?TWWhwww e<*"BBBz̊m)S}6-''jjjƖ^(!!XXXt?x>|Noذ-[s _yB={vFFʻ***TUU544q-"dbܹs6.Y q=e̙~L;::=N1|ɐ!CFMat~ ן5kN}'ZZZv/jCn8κu(˗/軡!<y$[ ٨.MIl_r͗-[6pikksrr266r63|EEE)ѣGyqH w@ǏclII L\^^mHkllDFFݑt(,,$H)))|FDDlڴ)997'N`0EQxyy h4 #.]`9̌B-11B`T_ICZJرcŊcƌA]EE?/ݜ={L&7@mhh6l?RKKKpp0LYY922N%66^ `0(ޙG5ym@B  P@dpe,VDWeKRC+uPz{AiYWQъ"2(R)Af ɓ 8|83쳿CJ0pGGGB. 3!]a&Z,,,lѢEv! 8>$.VWW{yyA qc0 7oP(p\:.8' WSS)0fX,9s&aC=@m 2j022˾7nd/^DWuu]O1Nݻ,,,x<ޒ%Kz{{!ؼys__ܹsCG /So߾MKKh8r7Z[[ hy:"Ơ[SSrX,~?;>)++0 NېuIzqoW_}5X"~w <<<jd8~;;;q4pB NI֯_?>33@ 0 .pϟgff>v>>޽p ֬YwaG G JHYlJ#ٽ{sZZZX,،&)~zBR%噚_b)tSTTo%>>dLx dN`ܔNK}jjjtڵk% t$7F] =zwPg_o䢋0:uN f2Gٴi~ff&2>‡$^^^+WLNNt\nZz֭젠y!. HOO믋AzbtBCCE"dxLL/`^'O»;}%KI+-o޼I PPYprr9s/)N S`0^z֛7odyLLL .\tС<.Mmfdd4?:D%GH7w3gD Lfrr1:t\'h,cape">hWIIL&[[[\r׮]qqq'O\|9a$hK'oG6m244 ͛7D"|7nʸaY, 촵%zɓ'EnAIOaa!B!ɣI͈[XXdEx<^||<pqqQUvZq) "W \Ndt3c JJJvvvA#QPPcD"NZ2bccd2%zb)))uww-(x*@.sWWW2.i#R Âql4ޖ]]]ԤzwOF/=aijjuXXXH$a؉'tttbvw/\c-ggg@~(NIZ[[Y,;:;;mmmzzz=9݀:4(f ۷K fY,V4)Ό|>Uq};w B-}vŊT*UNZj///%znQH&N||8hLyX,͆looO$nxxx]f2YXcIGUU9seVQQfg͚4K" 'IwtttȻ4A__r4K'AyaΝJJJ[,xN'&&J/ ccci4ŋGd4V7͛7鵶JqZ0LhaM8d2966VNCCCL˗/d_عs'LvrrTI,_zuG-anzzz,--=<<Cq 2 B[[Frҥ۔+}}}ruammtR<~\駟>($x1+++":vk|)N z~5$p{]zUEE>QV{uuu<)**"r2)(++ 9s&@YzϞ={ҥĽ{XXX~]5554ֶ***90 JJJvt㾾q CD @[[?8,-->ܹw^___ :N"խ~Bu.,,rss}e+ wE <(INNHZnݙ3g [ZZW x d2>+**]xq >)jhh \\6p8R/TUU!S^^ z]~#秧S]q 7B5~crJH\~ނDjmx$ ݱcL?k$J:֭#HϞ=*P(&ɮC{-H]bH433.//cWD"ApRrYDX WIضmۂ &$$Ɀ_MMm--,;/^ILLLJJf0vvv:::4M(vvv644|H$n۶'33SUUHE^^|m\RNNN[zxdl\]]WVVVWWI$ٳqQyӳ".{zz쬬, *** JaK,ٰa,~rrr=z$p$ )ğ ZիW8 LLLnݺ~9-΋/ٯYBB8;Țnrѣw)((ݸyzz6 $Ͷ7nhnnDFFFVVV@ ]]nPH&?<^!??w>|xΜ9rr7|W귎'@S"`~-))o155 H1QYYK5bt&z1mr" sY>|ð?tO(ǎE r$fWSS0[#zzzo.--|Bh4Y"ҍI#G|111iiiJ+V`ٲs CCC ø\,FhW>#Y"FW\ٲe +o޼YxqUU1۱cI0H _ Q ]]ǏhǪ*kkk"ҍbD@DK.ͽvZJJJDDď? 1((3//Oڐ勣cqq1/rs0?#GGGID@ҍbq]777zlٲŗ!-&k+7oD0D˗<,**1rܤ1((;aؐr{ yfx#@{CO;;;z ۳gOeeeoooss VX YB}---cG B$=}~___3uusƦR +>>f-[rrr|}}5kBbqbbիI$̱#&% 0.MMMIwuu钾;l۶mٲe?p8chOץKGB(>_'N̛7F13g677e,o>>>QQQvwbkzҍ6D~ð55_EEE]r, c'7n ƗÇwtt߿_^5]֌?TA;>>>CJ$}= *(&;[ne0\.WNH$ٍ!ǃ n D)6}ƓcǎX,??܍Ywwt@hjjZ7EGGǐ`NmmPԫWvwwhz{{7a555/;޾} eeet#555<...L&3++KYY@F]r!+))mذapp֭[?7mmmamRDknn^PP |ג2884w۷o/yrssr|ssqGGxޮnhhٮPiE4!\jteeed2y߾}H3s@FD=+l6|Ϟ={eٖrT[l6މ͛VVVT*o[EE+b8777 @ ?LğȪĀxPS bee ehh#Q A$((&&&ݻw'''90y+ŗ.])//$ICCL&~zppB,\;88|㝦tDGG:uiˉ:I:.PHR %B;(("}}}giiirr!>gIIW \hΝKOOb>LIIA1nt,Z(../vϞ=o߾$uɘ1XDEEQ(˗/h3!!H$=zG ((:l!oN bbbpU< HLLܺuۙ3gHNN^|91"L6lPRRfeeܼuVC$wkJ7ٳgť[.;;[( 611qٳgLMM1j@I?|BBBAAڂ 8Jmmmuuu=www߸qс7bAfŋwTVV666vvv PTMMM5gggg&9ё"1N1Nt@ n8 'PA  UIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/wp_page_isomap_386_golden.png000066400000000000000000000426211450372207100275220ustar00rootroot00000000000000PNG  IHDRzzEXIDATxw\S8# KXZmJ^QTl! !@a$Qě&7!/9"{ d˳g޸q3nj֭^zumm-+\4w:x𠉉 ڱcyUkkkttnTTP(sJ {ɓLW_}*E]v6B9*# <@"&Mb0qqq%Tqqܹs+**QI$ɓtk B1%%eȑƍKII!(Gw7UYY?`khhV$]p!%%ÃJ | [nikk\(Θ1#'''33ؘ:S_TWW^kB4ĉ #<<nx __SNȯw9ҥKAAAkDPnxchk׮ɻŋ?|0''J=(7CJJʈ#,˝N8!(@BBB^xqM<'F\hhhYYY|/477>|x޼yxwrrrtttݻw{{{߽{WKK O۷o5ٳg2d Rr8wtt}ܹsB9B⧟~oggGvJ hkkDd'Ԡ@l3(7 ;;!4h QjPn ӧOBd'Ԡ@Av x9{'(7ؘ,bBA|>֖,d%Bى(;(7*''!Fv" 8Dd߿?ى(;(7ȪNS?Mv* 722"; Y566?< +[Yuvvۗ,TdRRRoqrLB^^^d' 'Ob "*Iv"* 2)//"; jrLB5@@&}!; tttۓjrB#;eff" @v" Ey{{jr􊊊(ى(7H l}}}PPn^CC)Y (7H:~A@z0?(7HŅDTIv"* Rz1,*(7H!;L)2LP%PnRUU.Y(7HĄ,T laaAv RvvvdgJ 6HLv" xBݝDT 4hى(7Hӧ!Q%PnFII ; i<\GG,T QWWgllLv* hjjə*>;;dx<&Y[[ E?JWW9n߾}̙7o"544۫_|;vlppqT. ڵkWaa3===_Ԕs޽T;;>,<<\CCܕ[W^uvvO p^URRvZ]]];;s9GU>B,^JuuuXyq\9ڠ3Ü:ujeeѣG'L K;w\ro߾*++Gw%M:͛3 f``d``@TX7eʔⴴ>}VAjM ֦>JhTx]2221#AOO/!!lWEpwW~~מ={-[&Vbcc{ʯӧ֦Q(64iҤֻwʵ,oo[n5Jmegg4cƌw[ PS/.,,LKKׯ={6::Z&OLR/^(is <*={6<<\ N$iW\ PG׮]9s&󛛛?3fH=fĉ:::.] PG7n:t!kJעѣwr%z-/c<1JrQ~~uqq)..Tp P;---<O{ Bu~Z .vGEX P;B!D.H$Rp P;V-vvi4VpXfff nWy@jJ:88<{LX,===<u흙FI nT@hȑ3cINN1b"[T6Pn:8qbCC"deeȸǃ(>|c?f3#FXcӦM:::駟^~ɓ'D䮪5uԩ%KZSSGdkk}i 5%?n8Iʒ† >\\\ Q[Pn7oރ¨]$x|mX,PT>/c P;؎[n}kggwe߼y"993srrĻwJݢ r˭[L&FKR("O6 !R[[NjV^ P#P(999=v} xzz~=\RR?`oݺ%EbL&8FFFR\*` P˗/y1?~|ZsssOOO333 /^effxt~N\f O>dϞ=RRZPn@'RSSGyMl`,)))=*//ollloog2vvv7nhnn&juϟcoȾ@BfxGGGSyРAF& ǏmllGx|777qybcD"sVVBILL$0>3z-l&F믿ԊKSSS]]yyy[nUXVVVݓw+"h̙< ʻQbAg &L Ν>}"3gN||tK[[#ttt@ DE8p`̘1L&ѣG 5Yf ”Ç#x<BYx1!aǎJe0 F1 :ndd4gΜ& PyN \GGFxxঝGYdɉ'D"BROOZYYZZZUH gBaðBLOJӕQ...^l2l??ƞϯBt:z*NT`` $1!;b---lн{$jN$;99QTى*(7@%eggP(b+I ]XXHnX@ihh|;tall ;w2 KјL۷_!qF:u6'$$si4l->z‚FrA*oATTTmڴ6f= d:___?B۷/v0&&FM4 i4ZYY΁rTÛ{'(춫Dǒ%K}~Nx=sk1b@ xm/P(7@Y(l¦)]vDSPP`oo|mu~^=ma3B9qī0s-[xxxTWWؐ&OLPN>Mv"x---L&Jb"'///88X J577))D"Q>}ퟗ$B{챲rw7Ld W>>>`hkk< J^\\(VZcjkk6 MrrSsss||W_}Ev:5k@ v(?p=r1cJmkk;w.v;::^;ܽj`?By2J^u\?ԩSBO>}MCC_I|ɓ'xNŪRbb-[Mj`jj'ν{T*dmFEFFȿh4ڶmpƆ7 =]~`J/ KKKmmDyȑ#TP(h 6m277oiia08q˗/ۿ$%i( rOvZv-BsrjjҥKL&JhzzzӦMù~EWW޽{i4Zffka5? _3gΌPE/rd炰1c$%%ɻ[[[.MxtUA-^!E͞=ڵkׯ_wC{uw=1rQYY9pƭ[a2dZZZ b777}}}lkNT߾}g Bܹs˖-SٳgDnOr֋g'Hjuuu+ԩS'Lp;v\$o}\%Cn iccp΅|؃gϒOݻBpҥT*uܹ=CENwȷ~zle x)SPԉ'|&@FkkkPDDٹ(kkk;;;ƀT1c*++eD>w Jf'Hj4,`0|խXJ2<@2hL&d碌q7iiid' 魑J566޲e ;+Wjhhh4777-¸ M6mٲ$++K3 e˖/d? @ pwwͽqƜ9sZ[[ɓ]\\,--BaSSSuuuAA ejj*։Kڌ3=Eߟ,ǒ%Kojj b2ݮ-&]pw$N߾}DU\wwnO=x`VVVSSF355 q  {\P͞F)i(7Vii7߿_]]rBQ Srr Bs|0~MMMFFF7n$;Go2 Mopbbb9cdd4x`WWW;;;}}}f={Y\\lnn|T+VIKK}˕NnTvvHhgO|_~URRRz[RRk.ݴiӞ!ʍkoo)ʧ~"]HtaCCC2q@l]vVḱĶZZZƌchh({X,@,MMѣG:=Y `ܨ0>`ccGTLdhhnllLJӫV"!? H4k,KKbb#wttL8F rwZs]7XOU}wW^MLLtpp 628{l~\]]_H-44[jKjjj"F%=zh?A_GGŋ999!T]]-׆F477ggg=...;w|BquuE=ygwJ/xݴiAVVشiB(!!A~MH ʍ*yQWWqoll/_"LMMqR& `ѣG_GG!bN*&dF陛K)##CGGG^6HWWOV"QQQyėU %Ņ5557n~?~۶' )o,,,G/!tyy'UֆtqAll,g ~JJ4i'|G\ErJh4@ ږ &L>}ԨQö֗]&lÇs߾}<[0CDOOH}͛۷oῖH.xVbb"1AϜ9C`Lyr2RRR޽[[[+c{9rƍFTTTH7+Q~rrr&066 !*e?JKK_xֆ-dcc S^^VGa``d2;::l1K n?>**UM)nTKK BI|>'Oƞ\bKjO4i֬YӦM>|5BRޑDOUx<ٳg#""{=333VsT*;t'N444_98<d2_xpWWÇgggoڴISSt bAAA, [BX777㌬ΜY,,~wY:(ksssHHJ]ztD"Y, 6=z~766ƹcэ7֬Y{Y[[{yy͘1ȑ#gsEEET*իo;A(^|9,,ۤs_>??W^( oěꘘB/\妢&%%E^xu9C)ov„ og̘񶞑t6nhiiĥKD"w |U%IIIJ]=700 :/zw)++&SτBg}FN:EH@7o>֛~Fnݺ$<=#444|wr/Cccc߿>Wtt4%:_CRΝ+Ņ'OTn999{w7o`0m7Ͽ3P(FFF2O?iiiɯ P@TEڸq\emmmgg'Ņؿ/"䫧D"Q```ee{pАȊ+;Dxp_ryyy555mmmqmm>}6lʔ)nnn$&) s+6o޼k׮~<77رc7o|)6db{!Ǐ'E%4mڴ 6<}fs\c7>~rjxoV ww͛7,WnXb8yyy!}v׮]GoGRCHK xzzN>|666*l6M^]/ZRW@k֬yf}}= f0bZZZFFFÇ߲eD[V`?^XX{ne߾}n(ݔ.ZЫ#0Xinn{M@tٳO>]ZZUVeffnڴVKKcopǎ~3766^z?*ɺћsv'gvnɘ2駟=z˚]vc#HGElll̙s1W%''\Rֳ444֮]+V455;wNo===w7+glZxʀba}ӧOhEa}۷?~wttdǏ9ܰX*c[Vc_͎ǿl֢t`L&sܹO.++iii+W{_~ieebcc̙#]k֬)//ٳgߺuK"EnʍKAA ^|V]]F9::<r޽sUUUر\.wܸqRx+W>SI/=zt[[ÇhT)787115jXjj*B(00gzxx:5Uaeenݺ7oL&]555ǎb@KKK I/TnM@@@AAqXx1B=|}}/wڵQF<T\\ܷo_f>ÇK׮36PuSnp;w!Cˊ P[[ŋ o3BYYكL"I(:)kݻlڴIv-,,ꤾ\a)7t:ߏBSSҥKcǎurr333kmm�pF3f$t^|)R999[n=~DR_0+V_^:qDZVVfmm-Q/WA7@h4P DEEɸ;,]]]̙qFH?Ϻ~GP!U(!I7HX~}~G|D"%m۶yxxDGGkᅬ?meee8{ӧO>~ril{w*++?L=LܲeNAA #G4H~NHV8oݺuk?gG hkk=zT宧}رcҤNk֬>|(P<cjjg_^^v/󪄄SNM2e8n?~UXX,C s5>|8l߾N6ys\l߾M;vXYYIݢ"i_UZZX__OT۰aƍI&%1cƌ8O̙3߻_9::޽{>x@f͚?BH/tuu555}׆'Nxۆ<ƍWRg!"gݒ%KhyggOPP \O/{Ο?d>onnhnn%5`9s愆W}AQcc>,&_577V@%HYn:::=zTRRŋvfhhاOOOOl&q2nݺk׮UV-e@r}{@o>*zab&$$0ذ w@"""x<|ŋ5kȑ#~᧟~eB*^.&&N/XQ8</<iʝ ,>|'O͛ 08舍={qƏ/<==埲\ SZZ}cǎ1)SL0aȐ!NNNL&S|@ ())̼vڅ ZZZ7n܈m𠫫8|rRi@@8N\\\BB;w\.F333ӣRuuuZZZÆ 2eʼy666`"FIPn H$z6D".rvvvwwg0^_744(R-Ytɓ'w޽rJB2 ^[[{}&{1P([#eh4ڥKGQ1j_~ӧO?s< ѣGgffl===x3rqqrj3%%L=ZTT-ZbX?@X,wʻ!HB jҥKuuuN΃55///55PGG{ʔ)|>Ï?P(>>>/f2oR7o^xq~~>v|}}KKK{8'!!?/**JHH~njTQQq!pd2o߾miif33ѣGËpԎ͛ivv1chkk A͘1C|BBBrEcc#vѣGÆ {[̥Kb'O]{,l'O"n*>ASSgŎxyyM0!55֭[Ɯ2eJKK ˙3gtN=<< I|.^(>8rHٳgþ}2 cw4Czzzk,,,tuu^lDp8N_kjj?TTT# X,[YYDK./%"> +7\.m/̠^ 6T*uٲe'N(--Ɩ a20Bӹ\.}||RRR֯_|rrĀh8PnP/]ml1022jjjB:Vo RSS)K߾}KJJ{%~3dG!dgg" eĈl6Yƍ(>3fLvvvB@`+c+BqڵW=͜9S|mM: wܡPnP/666o7nIP:;;+++III6ӧ-,,`F8jgܹ.]~SNUTT츸j  2_zBDEEܹ!44*fk׮r)//wttܽ{wDDě&%% _? Hdkkۯ_3+W 4hذaoknƍvp8PnPGC (//u2<444X[[?… utĉ(y7wX52gΜ-[dgg˯7nCg 5%,,,_QQ1p@"TjJJJMMͤI^|IlZ$ qqqtRVVք $ٳTSSSq(7q]pC z.իXRRPnPw'Nw_~5x`@?hРNr@ >>//S$aoЙLٳ.\HZ @A @A @A @A_o 7dܞIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/wp_page_isomap_arm64_golden.png000066400000000000000000000426211450372207100301330ustar00rootroot00000000000000PNG  IHDRzzEXIDATxw\S8# KXZmJ^QTl! !@a$Qě&7!/9"{ d˳g޸q3nj֭^zumm-+\4w:x𠉉 ڱcyUkkkttnTTP(sJ {ɓLW_}*E]v6B9*# <@"&Mb0qqq%Tqqܹs+**QI$ɓtk B1%%eȑƍKII!(Gw7UYY?`khhV$]p!%%ÃJ | [nikk\(Θ1#'''33ؘ:S_TWW^kB4ĉ #<<nx __SNȯw9ҥKAAAkDPnxchk׮ɻŋ?|0''J=(7CJJʈ#,˝N8!(@BBB^xqM<'F\hhhYYY|/477>|x޼yxwrrrtttݻw{{{߽{WKK O۷o5ٳg2d Rr8wtt}ܹsB9B⧟~oggGvJ hkkDd'Ԡ@l3(7 ;;!4h QjPn ӧOBd'Ԡ@Av x9{'(7ؘ,bBA|>֖,d%Bى(;(7*''!Fv" 8Dd߿?ى(;(7ȪNS?Mv* 722"; Y566?< +[Yuvvۗ,TdRRRoqrLB^^^d' 'Ob "*Iv"* 2)//"; jrLB5@@&}!; tttۓjrB#;eff" @v" Ey{{jr􊊊(ى(7H l}}}PPn^CC)Y (7H:~A@z0?(7HŅDTIv"* Rz1,*(7H!;L)2LP%PnRUU.Y(7HĄ,T laaAv RvvvdgJ 6HLv" xBݝDT 4hى(7Hӧ!Q%PnFII ; i<\GG,T QWWgllLv* hjjə*>;;dx<&Y[[ E?JWW9n߾}̙7o"544۫_|;vlppqT. ڵkWaa3===_Ԕs޽T;;>,<<\CCܕ[W^uvvO p^URRvZ]]];;s9GU>B,^JuuuXyq\9ڠ3Ü:ujeeѣG'L K;w\ro߾*++Gw%M:͛3 f``d``@TX7eʔⴴ>}VAjM ֦>JhTx]2221#AOO/!!lWEpwW~~מ={-[&Vbcc{ʯӧ֦Q(64iҤֻwʵ,oo[n5Jmegg4cƌw[ PS/.,,LKKׯ={6::Z&OLR/^(is <*={6<<\ N$iW\ PG׮]9s&󛛛?3fH=fĉ:::.] PG7n:t!kJעѣwr%z-/c<1JrQ~~uqq)..Tp P;---<O{ Bu~Z .vGEX P;B!D.H$Rp P;V-vvi4VpXfff nWy@jJ:88<{LX,===<u흙FI nT@hȑ3cINN1b"[T6Pn:8qbCC"deeȸǃ(>|c?f3#FXcӦM:::駟^~ɓ'D䮪5uԩ%KZSSGdkk}i 5%?n8Iʒ† >\\\ Q[Pn7oރ¨]$x|mX,PT>/c P;؎[n}kggwe߼y"993srrĻwJݢ r˭[L&FKR("O6 !R[[NjV^ P#P(999=v} xzz~=\RR?`oݺ%EbL&8FFFR\*` P˗/y1?~|ZsssOOO333 /^effxt~N\f O>dϞ=RRZPn@'RSSGyMl`,)))=*//ollloog2vvv7nhnn&juϟcoȾ@BfxGGGSyРAF& ǏmllGx|777qybcD"sVVBILL$0>3z-l&F믿ԊKSSS]]yyy[nUXVVVݓw+"h̙< ʻQbAg &L Ν>}"3gN||tK[[#ttt@ DE8p`̘1L&ѣG 5Yf ”Ç#x<BYx1!aǎJe0 F1 :ndd4gΜ& PyN \GGFxxঝGYdɉ'D"BROOZYYZZZUH gBaðBLOJӕQ...^l2l??ƞϯBt:z*NT`` $1!;b---lн{$jN$;99QTى*(7@%eggP(b+I ]XXHnX@ihh|;tall ;w2 KјL۷_!qF:u6'$$si4l->z‚FrA*oATTTmڴ6f= d:___?B۷/v0&&FM4 i4ZYY΁rTÛ{'(춫Dǒ%K}~Nx=sk1b@ xm/P(7@Y(l¦)]vDSPP`oo|mu~^=ma3B9qī0s-[xxxTWWؐ&OLPN>Mv"x---L&Jb"'///88X J577))D"Q>}ퟗ$B{챲rw7Ld W>>>`hkk< J^\\(VZcjkk6 MrrSsss||W_}Ev:5k@ v(?p=r1cJmkk;w.v;::^;ܽj`?By2J^u\?ԩSBO>}MCC_I|ɓ'xNŪRbb-[Mj`jj'ν{T*dmFEFFȿh4ڶmpƆ7 =]~`J/ KKKmmDyȑ#TP(h 6m277oiia08q˗/ۿ$%i( rOvZv-BsrjjҥKL&JhzzzӦMù~EWW޽{i4Zffka5? _3gΌPE/rd炰1c$%%ɻ[[[.MxtUA-^!E͞=ڵkׯ_wC{uw=1rQYY9pƭ[a2dZZZ b777}}}lkNT߾}g Bܹs˖-SٳgDnOr֋g'Hjuuu+ԩS'Lp;v\$o}\%Cn iccp΅|؃gϒOݻBpҥT*uܹ=CENwȷ~zle x)SPԉ'|&@FkkkPDDٹ(kkk;;;ƀT1c*++eD>w Jf'Hj4,`0|խXJ2<@2hL&d碌q7iiid' 魑J566޲e ;+Wjhhh4777-¸ M6mٲ$++K3 e˖/d? @ pwwͽqƜ9sZ[[ɓ]\\,--BaSSSuuuAA ejj*։Kڌ3=Eߟ,ǒ%Kojj b2ݮ-&]pw$N߾}DU\wwnO=x`VVVSSF355 q  {\P͞F)i(7Vii7߿_]]rBQ Srr Bs|0~MMMFFF7n$;Go2 Mopbbb9cdd4x`WWW;;;}}}f={Y\\lnn|T+VIKK}˕NnTvvHhgO|_~URRRz[RRk.ݴiӞ!ʍkoo)ʧ~"]HtaCCC2q@l]vVḱĶZZZƌchh({X,@,MMѣG:=Y `ܨ0>`ccGTLdhhnllLJӫV"!? H4k,KKbb#wttL8F rwZs]7XOU}wW^MLLtpp 628{l~\]]_H-44[jKjjj"F%=zh?A_GGŋ999!T]]-׆F477ggg=...;w|BquuE=ygwJ/xݴiAVVشiB(!!A~MH ʍ*yQWWqoll/_"LMMqR& `ѣG_GG!bN*&dF陛K)##CGGG^6HWWOV"QQQyėU %Ņ5557n~?~۶' )o,,,G/!tyy'UֆtqAll,g ~JJ4i'|G\ErJh4@ ږ &L>}ԨQö֗]&lÇs߾}<[0CDOOH}͛۷oῖH.xVbb"1AϜ9C`Lyr2RRR޽[[[+c{9rƍFTTTH7+Q~rrr&066 !*e?JKK_xֆ-dcc S^^VGa``d2;::l1K n?>**UM)nTKK BI|>'Oƞ\bKjO4i֬YӦM>|5BRޑDOUx<ٳg#""{=333VsT*;t'N444_98<d2_xpWWÇgggoڴISSt bAAA, [BX777㌬ΜY,,~wY:(ksssHHJ]ztD"Y, 6=z~766ƹcэ7֬Y{Y[[{yy͘1ȑ#gsEEET*իo;A(^|9,,ۤs_>??W^( oěꘘB/\妢&%%E^xu9C)ov„ og̘񶞑t6nhiiĥKD"w |U%IIIJ]=700 :/zw)++&SτBg}FN:EH@7o>֛~Fnݺ$<=#444|wr/Cccc߿>Wtt4%:_CRΝ+Ņ'OTn999{w7o`0m7Ͽ3P(FFF2O?iiiɯ P@TEڸq\emmmgg'Ņؿ/"䫧D"Q```ee{pАȊ+;Dxp_ryyy555mmmqmm>}6lʔ)nnn$&) s+6o޼k׮~<77رc7o|)6db{!Ǐ'E%4mڴ 6<}fs\c7>~rjxoV ww͛7,WnXb8yyy!}v׮]GoGRCHK xzzN>|666*l6M^]/ZRW@k֬yf}}= f0bZZZFFFÇ߲eD[V`?^XX{ne߾}n(ݔ.ZЫ#0Xinn{M@tٳO>]ZZUVeffnڴVKKcopǎ~3766^z?*ɺћsv'gvnɘ2駟=z˚]vc#HGElll̙s1W%''\Rֳ444֮]+V455;wNo===w7+glZxʀba}ӧOhEa}۷?~wttdǏ9ܰX*c[Vc_͎ǿl֢t`L&sܹO.++iii+W{_~ieebcc̙#]k֬)//ٳgߺuK"EnʍKAA ^|V]]F9::<r޽sUUUر\.wܸqRx+W>SI/=zt[[ÇhT)787115jXjj*B(00gzxx:5Uaeenݺ7oL&]555ǎb@KKK I/TnM@@@AAqXx1B=|}}/wڵQF<T\\ܷo_f>ÇK׮36PuSnp;w!Cˊ P[[ŋ o3BYYكL"I(:)kݻlڴIv-,,ꤾ\a)7t:ߏBSSҥKcǎurr333kmm�pF3f$t^|)R999[n=~DR_0+V_^:qDZVVfmm-Q/WA7@h4P DEEɸ;,]]]̙qFH?Ϻ~GP!U(!I7HX~}~G|D"%m۶yxxDGGkᅬ?meee8{ӧO>~ril{w*++?L=LܲeNAA #G4H~NHV8oݺuk?gG hkk=zT宧}رcҤNk֬>|(P<cjjg_^^v/󪄄SNM2e8n?~UXX,C s5>|8l߾N6ys\l߾M;vXYYIݢ"i_UZZX__OT۰aƍI&%1cƌ8O̙3߻_9::޽{>x@f͚?BH/tuu555}׆'Nxۆ<ƍWRg!"gݒ%KhyggOPP \O/{Ο?d>onnhnn%5`9s愆W}AQcc>,&_577V@%HYn:::=zTRRŋvfhhاOOOOl&q2nݺk׮UV-e@r}{@o>*zab&$$0ذ w@"""x<|ŋ5kȑ#~᧟~eB*^.&&N/XQ8</<iʝ ,>|'O͛ 08舍={qƏ/<==埲\ SZZ}cǎ1)SL0aȐ!NNNL&S|@ ())̼vڅ ZZZ7n܈m𠫫8|rRi@@8N\\\BB;w\.F333ӣRuuuZZZÆ 2eʼy666`"FIPn H$z6D".rvvvwwg0^_744(R-Ytɓ'w޽rJB2 ^[[{}&{1P([#eh4ڥKGQ1j_~ӧO?s< ѣGgffl===x3rqqrj3%%L=ZTT-ZbX?@X,wʻ!HB jҥKuuuN΃55///55PGG{ʔ)|>Ï?P(>>>/f2oR7o^xq~~>v|}}KKK{8'!!?/**JHH~njTQQq!pd2o߾miif33ѣGËpԎ͛ivv1chkk A͘1C|BBBrEcc#vѣGÆ {[̥Kb'O]{,l'O"n*>ASSgŎxyyM0!55֭[Ɯ2eJKK ˙3gtN=<< I|.^(>8rHٳgþ}2 cw4Czzzk,,,tuu^lDp8N_kjj?TTT# X,[YYDK./%"> +7\.m/̠^ 6T*uٲe'N(--Ɩ a20Bӹ\.}||RRR֯_|rrĀh8PnP/]ml1022jjjB:Vo RSS)K߾}KJJ{%~3dG!dgg" eĈl6Yƍ(>3fLvvvB@`+c+BqڵW=͜9S|mM: wܡPnP/666o7nIP:;;+++III6ӧ-,,`F8jgܹ.]~SNUTT츸j  2_zBDEEܹ!44*fk׮r)//wttܽ{wDDě&%% _? Hdkkۯ_3+W 4hذaoknƍvp8PnPGC (//u2<444X[[?… utĉ(y7wX52gΜ-[dgg˯7nCg 5%,,,_QQ1p@"TjJJJMMͤI^|IlZ$ qqqtRVVք $ٳTSSSq(7q]pC z.իXRRPnPw'Nw_~5x`@?hРNr@ >>//S$aoЙLٳ.\HZ @A @A @A @A_o 7dܞIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/wp_page_isomap_golden.png000066400000000000000000000426211450372207100271220ustar00rootroot00000000000000PNG  IHDRzzEXIDATxw\S8# KXZmJ^QTl! !@a$Qě&7!/9"{ d˳g޸q3nj֭^zumm-+\4w:x𠉉 ڱcyUkkkttnTTP(sJ {ɓLW_}*E]v6B9*# <@"&Mb0qqq%Tqqܹs+**QI$ɓtk B1%%eȑƍKII!(Gw7UYY?`khhV$]p!%%ÃJ | [nikk\(Θ1#'''33ؘ:S_TWW^kB4ĉ #<<nx __SNȯw9ҥKAAAkDPnxchk׮ɻŋ?|0''J=(7CJJʈ#,˝N8!(@BBB^xqM<'F\hhhYYY|/477>|x޼yxwrrrtttݻw{{{߽{WKK O۷o5ٳg2d Rr8wtt}ܹsB9B⧟~oggGvJ hkkDd'Ԡ@l3(7 ;;!4h QjPn ӧOBd'Ԡ@Av x9{'(7ؘ,bBA|>֖,d%Bى(;(7*''!Fv" 8Dd߿?ى(;(7ȪNS?Mv* 722"; Y566?< +[Yuvvۗ,TdRRRoqrLB^^^d' 'Ob "*Iv"* 2)//"; jrLB5@@&}!; tttۓjrB#;eff" @v" Ey{{jr􊊊(ى(7H l}}}PPn^CC)Y (7H:~A@z0?(7HŅDTIv"* Rz1,*(7H!;L)2LP%PnRUU.Y(7HĄ,T laaAv RvvvdgJ 6HLv" xBݝDT 4hى(7Hӧ!Q%PnFII ; i<\GG,T QWWgllLv* hjjə*>;;dx<&Y[[ E?JWW9n߾}̙7o"544۫_|;vlppqT. ڵkWaa3===_Ԕs޽T;;>,<<\CCܕ[W^uvvO p^URRvZ]]];;s9GU>B,^JuuuXyq\9ڠ3Ü:ujeeѣG'L K;w\ro߾*++Gw%M:͛3 f``d``@TX7eʔⴴ>}VAjM ֦>JhTx]2221#AOO/!!lWEpwW~~מ={-[&Vbcc{ʯӧ֦Q(64iҤֻwʵ,oo[n5Jmegg4cƌw[ PS/.,,LKKׯ={6::Z&OLR/^(is <*={6<<\ N$iW\ PG׮]9s&󛛛?3fH=fĉ:::.] PG7n:t!kJעѣwr%z-/c<1JrQ~~uqq)..Tp P;---<O{ Bu~Z .vGEX P;B!D.H$Rp P;V-vvi4VpXfff nWy@jJ:88<{LX,===<u흙FI nT@hȑ3cINN1b"[T6Pn:8qbCC"deeȸǃ(>|c?f3#FXcӦM:::駟^~ɓ'D䮪5uԩ%KZSSGdkk}i 5%?n8Iʒ† >\\\ Q[Pn7oރ¨]$x|mX,PT>/c P;؎[n}kggwe߼y"993srrĻwJݢ r˭[L&FKR("O6 !R[[NjV^ P#P(999=v} xzz~=\RR?`oݺ%EbL&8FFFR\*` P˗/y1?~|ZsssOOO333 /^effxt~N\f O>dϞ=RRZPn@'RSSGyMl`,)))=*//ollloog2vvv7nhnn&juϟcoȾ@BfxGGGSyРAF& ǏmllGx|777qybcD"sVVBILL$0>3z-l&F믿ԊKSSS]]yyy[nUXVVVݓw+"h̙< ʻQbAg &L Ν>}"3gN||tK[[#ttt@ DE8p`̘1L&ѣG 5Yf ”Ç#x<BYx1!aǎJe0 F1 :ndd4gΜ& PyN \GGFxxঝGYdɉ'D"BROOZYYZZZUH gBaðBLOJӕQ...^l2l??ƞϯBt:z*NT`` $1!;b---lн{$jN$;99QTى*(7@%eggP(b+I ]XXHnX@ihh|;tall ;w2 KјL۷_!qF:u6'$$si4l->z‚FrA*oATTTmڴ6f= d:___?B۷/v0&&FM4 i4ZYY΁rTÛ{'(춫Dǒ%K}~Nx=sk1b@ xm/P(7@Y(l¦)]vDSPP`oo|mu~^=ma3B9qī0s-[xxxTWWؐ&OLPN>Mv"x---L&Jb"'///88X J577))D"Q>}ퟗ$B{챲rw7Ld W>>>`hkk< J^\\(VZcjkk6 MrrSsss||W_}Ev:5k@ v(?p=r1cJmkk;w.v;::^;ܽj`?By2J^u\?ԩSBO>}MCC_I|ɓ'xNŪRbb-[Mj`jj'ν{T*dmFEFFȿh4ڶmpƆ7 =]~`J/ KKKmmDyȑ#TP(h 6m277oiia08q˗/ۿ$%i( rOvZv-BsrjjҥKL&JhzzzӦMù~EWW޽{i4Zffka5? _3gΌPE/rd炰1c$%%ɻ[[[.MxtUA-^!E͞=ڵkׯ_wC{uw=1rQYY9pƭ[a2dZZZ b777}}}lkNT߾}g Bܹs˖-SٳgDnOr֋g'Hjuuu+ԩS'Lp;v\$o}\%Cn iccp΅|؃gϒOݻBpҥT*uܹ=CENwȷ~zle x)SPԉ'|&@FkkkPDDٹ(kkk;;;ƀT1c*++eD>w Jf'Hj4,`0|խXJ2<@2hL&d碌q7iiid' 魑J566޲e ;+Wjhhh4777-¸ M6mٲ$++K3 e˖/d? @ pwwͽqƜ9sZ[[ɓ]\\,--BaSSSuuuAA ejj*։Kڌ3=Eߟ,ǒ%Kojj b2ݮ-&]pw$N߾}DU\wwnO=x`VVVSSF355 q  {\P͞F)i(7Vii7߿_]]rBQ Srr Bs|0~MMMFFF7n$;Go2 Mopbbb9cdd4x`WWW;;;}}}f={Y\\lnn|T+VIKK}˕NnTvvHhgO|_~URRRz[RRk.ݴiӞ!ʍkoo)ʧ~"]HtaCCC2q@l]vVḱĶZZZƌchh({X,@,MMѣG:=Y `ܨ0>`ccGTLdhhnllLJӫV"!? H4k,KKbb#wttL8F rwZs]7XOU}wW^MLLtpp 628{l~\]]_H-44[jKjjj"F%=zh?A_GGŋ999!T]]-׆F477ggg=...;w|BquuE=ygwJ/xݴiAVVشiB(!!A~MH ʍ*yQWWqoll/_"LMMqR& `ѣG_GG!bN*&dF陛K)##CGGG^6HWWOV"QQQyėU %Ņ5557n~?~۶' )o,,,G/!tyy'UֆtqAll,g ~JJ4i'|G\ErJh4@ ږ &L>}ԨQö֗]&lÇs߾}<[0CDOOH}͛۷oῖH.xVbb"1AϜ9C`Lyr2RRR޽[[[+c{9rƍFTTTH7+Q~rrr&066 !*e?JKK_xֆ-dcc S^^VGa``d2;::l1K n?>**UM)nTKK BI|>'Oƞ\bKjO4i֬YӦM>|5BRޑDOUx<ٳg#""{=333VsT*;t'N444_98<d2_xpWWÇgggoڴISSt bAAA, [BX777㌬ΜY,,~wY:(ksssHHJ]ztD"Y, 6=z~766ƹcэ7֬Y{Y[[{yy͘1ȑ#gsEEET*իo;A(^|9,,ۤs_>??W^( oěꘘB/\妢&%%E^xu9C)ov„ og̘񶞑t6nhiiĥKD"w |U%IIIJ]=700 :/zw)++&SτBg}FN:EH@7o>֛~Fnݺ$<=#444|wr/Cccc߿>Wtt4%:_CRΝ+Ņ'OTn999{w7o`0m7Ͽ3P(FFF2O?iiiɯ P@TEڸq\emmmgg'Ņؿ/"䫧D"Q```ee{pАȊ+;Dxp_ryyy555mmmqmm>}6lʔ)nnn$&) s+6o޼k׮~<77رc7o|)6db{!Ǐ'E%4mڴ 6<}fs\c7>~rjxoV ww͛7,WnXb8yyy!}v׮]GoGRCHK xzzN>|666*l6M^]/ZRW@k֬yf}}= f0bZZZFFFÇ߲eD[V`?^XX{ne߾}n(ݔ.ZЫ#0Xinn{M@tٳO>]ZZUVeffnڴVKKcopǎ~3766^z?*ɺћsv'gvnɘ2駟=z˚]vc#HGElll̙s1W%''\Rֳ444֮]+V455;wNo===w7+glZxʀba}ӧOhEa}۷?~wttdǏ9ܰX*c[Vc_͎ǿl֢t`L&sܹO.++iii+W{_~ieebcc̙#]k֬)//ٳgߺuK"EnʍKAA ^|V]]F9::<r޽sUUUر\.wܸqRx+W>SI/=zt[[ÇhT)787115jXjj*B(00gzxx:5Uaeenݺ7oL&]555ǎb@KKK I/TnM@@@AAqXx1B=|}}/wڵQF<T\\ܷo_f>ÇK׮36PuSnp;w!Cˊ P[[ŋ o3BYYكL"I(:)kݻlڴIv-,,ꤾ\a)7t:ߏBSSҥKcǎurr333kmm�pF3f$t^|)R999[n=~DR_0+V_^:qDZVVfmm-Q/WA7@h4P DEEɸ;,]]]̙qFH?Ϻ~GP!U(!I7HX~}~G|D"%m۶yxxDGGkᅬ?meee8{ӧO>~ril{w*++?L=LܲeNAA #G4H~NHV8oݺuk?gG hkk=zT宧}رcҤNk֬>|(P<cjjg_^^v/󪄄SNM2e8n?~UXX,C s5>|8l߾N6ys\l߾M;vXYYIݢ"i_UZZX__OT۰aƍI&%1cƌ8O̙3߻_9::޽{>x@f͚?BH/tuu555}׆'Nxۆ<ƍWRg!"gݒ%KhyggOPP \O/{Ο?d>onnhnn%5`9s愆W}AQcc>,&_577V@%HYn:::=zTRRŋvfhhاOOOOl&q2nݺk׮UV-e@r}{@o>*zab&$$0ذ w@"""x<|ŋ5kȑ#~᧟~eB*^.&&N/XQ8</<iʝ ,>|'O͛ 08舍={qƏ/<==埲\ SZZ}cǎ1)SL0aȐ!NNNL&S|@ ())̼vڅ ZZZ7n܈m𠫫8|rRi@@8N\\\BB;w\.F333ӣRuuuZZZÆ 2eʼy666`"FIPn H$z6D".rvvvwwg0^_744(R-Ytɓ'w޽rJB2 ^[[{}&{1P([#eh4ڥKGQ1j_~ӧO?s< ѣGgffl===x3rqqrj3%%L=ZTT-ZbX?@X,wʻ!HB jҥKuuuN΃55///55PGG{ʔ)|>Ï?P(>>>/f2oR7o^xq~~>v|}}KKK{8'!!?/**JHH~njTQQq!pd2o߾miif33ѣGËpԎ͛ivv1chkk A͘1C|BBBrEcc#vѣGÆ {[̥Kb'O]{,l'O"n*>ASSgŎxyyM0!55֭[Ɯ2eJKK ˙3gtN=<< I|.^(>8rHٳgþ}2 cw4Czzzk,,,tuu^lDp8N_kjj?TTT# X,[YYDK./%"> +7\.m/̠^ 6T*uٲe'N(--Ɩ a20Bӹ\.}||RRR֯_|rrĀh8PnP/]ml1022jjjB:Vo RSS)K߾}KJJ{%~3dG!dgg" eĈl6Yƍ(>3fLvvvB@`+c+BqڵW=͜9S|mM: wܡPnP/666o7nIP:;;+++III6ӧ-,,`F8jgܹ.]~SNUTT츸j  2_zBDEEܹ!44*fk׮r)//wttܽ{wDDě&%% _? Hdkkۯ_3+W 4hذaoknƍvp8PnPGC (//u2<444X[[?… utĉ(y7wX52gΜ-[dgg˯7nCg 5%,,,_QQ1p@"TjJJJMMͤI^|IlZ$ qqqtRVVք $ٳTSSSq(7q]pC z.իXRRPnPw'Nw_~5x`@?hРNr@ >>//S$aoЙLٳ.\HZ @A @A @A @A_o 7dܞIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/wp_page_isomap_noasm_arm64_golden.png000066400000000000000000000426211450372207100313300ustar00rootroot00000000000000PNG  IHDRzzEXIDATxw\S8# KXZmJ^QTl! !@a$Qě&7!/9"{ d˳g޸q3nj֭^zumm-+\4w:x𠉉 ڱcyUkkkttnTTP(sJ {ɓLW_}*E]v6B9*# <@"&Mb0qqq%Tqqܹs+**QI$ɓtk B1%%eȑƍKII!(Gw7UYY?`khhV$]p!%%ÃJ | [nikk\(Θ1#'''33ؘ:S_TWW^kB4ĉ #<<nx __SNȯw9ҥKAAAkDPnxchk׮ɻŋ?|0''J=(7CJJʈ#,˝N8!(@BBB^xqM<'F\hhhYYY|/477>|x޼yxwrrrtttݻw{{{߽{WKK O۷o5ٳg2d Rr8wtt}ܹsB9B⧟~oggGvJ hkkDd'Ԡ@l3(7 ;;!4h QjPn ӧOBd'Ԡ@Av x9{'(7ؘ,bBA|>֖,d%Bى(;(7*''!Fv" 8Dd߿?ى(;(7ȪNS?Mv* 722"; Y566?< +[Yuvvۗ,TdRRRoqrLB^^^d' 'Ob "*Iv"* 2)//"; jrLB5@@&}!; tttۓjrB#;eff" @v" Ey{{jr􊊊(ى(7H l}}}PPn^CC)Y (7H:~A@z0?(7HŅDTIv"* Rz1,*(7H!;L)2LP%PnRUU.Y(7HĄ,T laaAv RvvvdgJ 6HLv" xBݝDT 4hى(7Hӧ!Q%PnFII ; i<\GG,T QWWgllLv* hjjə*>;;dx<&Y[[ E?JWW9n߾}̙7o"544۫_|;vlppqT. ڵkWaa3===_Ԕs޽T;;>,<<\CCܕ[W^uvvO p^URRvZ]]];;s9GU>B,^JuuuXyq\9ڠ3Ü:ujeeѣG'L K;w\ro߾*++Gw%M:͛3 f``d``@TX7eʔⴴ>}VAjM ֦>JhTx]2221#AOO/!!lWEpwW~~מ={-[&Vbcc{ʯӧ֦Q(64iҤֻwʵ,oo[n5Jmegg4cƌw[ PS/.,,LKKׯ={6::Z&OLR/^(is <*={6<<\ N$iW\ PG׮]9s&󛛛?3fH=fĉ:::.] PG7n:t!kJעѣwr%z-/c<1JrQ~~uqq)..Tp P;---<O{ Bu~Z .vGEX P;B!D.H$Rp P;V-vvi4VpXfff nWy@jJ:88<{LX,===<u흙FI nT@hȑ3cINN1b"[T6Pn:8qbCC"deeȸǃ(>|c?f3#FXcӦM:::駟^~ɓ'D䮪5uԩ%KZSSGdkk}i 5%?n8Iʒ† >\\\ Q[Pn7oރ¨]$x|mX,PT>/c P;؎[n}kggwe߼y"993srrĻwJݢ r˭[L&FKR("O6 !R[[NjV^ P#P(999=v} xzz~=\RR?`oݺ%EbL&8FFFR\*` P˗/y1?~|ZsssOOO333 /^effxt~N\f O>dϞ=RRZPn@'RSSGyMl`,)))=*//ollloog2vvv7nhnn&juϟcoȾ@BfxGGGSyРAF& ǏmllGx|777qybcD"sVVBILL$0>3z-l&F믿ԊKSSS]]yyy[nUXVVVݓw+"h̙< ʻQbAg &L Ν>}"3gN||tK[[#ttt@ DE8p`̘1L&ѣG 5Yf ”Ç#x<BYx1!aǎJe0 F1 :ndd4gΜ& PyN \GGFxxঝGYdɉ'D"BROOZYYZZZUH gBaðBLOJӕQ...^l2l??ƞϯBt:z*NT`` $1!;b---lн{$jN$;99QTى*(7@%eggP(b+I ]XXHnX@ihh|;tall ;w2 KјL۷_!qF:u6'$$si4l->z‚FrA*oATTTmڴ6f= d:___?B۷/v0&&FM4 i4ZYY΁rTÛ{'(춫Dǒ%K}~Nx=sk1b@ xm/P(7@Y(l¦)]vDSPP`oo|mu~^=ma3B9qī0s-[xxxTWWؐ&OLPN>Mv"x---L&Jb"'///88X J577))D"Q>}ퟗ$B{챲rw7Ld W>>>`hkk< J^\\(VZcjkk6 MrrSsss||W_}Ev:5k@ v(?p=r1cJmkk;w.v;::^;ܽj`?By2J^u\?ԩSBO>}MCC_I|ɓ'xNŪRbb-[Mj`jj'ν{T*dmFEFFȿh4ڶmpƆ7 =]~`J/ KKKmmDyȑ#TP(h 6m277oiia08q˗/ۿ$%i( rOvZv-BsrjjҥKL&JhzzzӦMù~EWW޽{i4Zffka5? _3gΌPE/rd炰1c$%%ɻ[[[.MxtUA-^!E͞=ڵkׯ_wC{uw=1rQYY9pƭ[a2dZZZ b777}}}lkNT߾}g Bܹs˖-SٳgDnOr֋g'Hjuuu+ԩS'Lp;v\$o}\%Cn iccp΅|؃gϒOݻBpҥT*uܹ=CENwȷ~zle x)SPԉ'|&@FkkkPDDٹ(kkk;;;ƀT1c*++eD>w Jf'Hj4,`0|խXJ2<@2hL&d碌q7iiid' 魑J566޲e ;+Wjhhh4777-¸ M6mٲ$++K3 e˖/d? @ pwwͽqƜ9sZ[[ɓ]\\,--BaSSSuuuAA ejj*։Kڌ3=Eߟ,ǒ%Kojj b2ݮ-&]pw$N߾}DU\wwnO=x`VVVSSF355 q  {\P͞F)i(7Vii7߿_]]rBQ Srr Bs|0~MMMFFF7n$;Go2 Mopbbb9cdd4x`WWW;;;}}}f={Y\\lnn|T+VIKK}˕NnTvvHhgO|_~URRRz[RRk.ݴiӞ!ʍkoo)ʧ~"]HtaCCC2q@l]vVḱĶZZZƌchh({X,@,MMѣG:=Y `ܨ0>`ccGTLdhhnllLJӫV"!? H4k,KKbb#wttL8F rwZs]7XOU}wW^MLLtpp 628{l~\]]_H-44[jKjjj"F%=zh?A_GGŋ999!T]]-׆F477ggg=...;w|BquuE=ygwJ/xݴiAVVشiB(!!A~MH ʍ*yQWWqoll/_"LMMqR& `ѣG_GG!bN*&dF陛K)##CGGG^6HWWOV"QQQyėU %Ņ5557n~?~۶' )o,,,G/!tyy'UֆtqAll,g ~JJ4i'|G\ErJh4@ ږ &L>}ԨQö֗]&lÇs߾}<[0CDOOH}͛۷oῖH.xVbb"1AϜ9C`Lyr2RRR޽[[[+c{9rƍFTTTH7+Q~rrr&066 !*e?JKK_xֆ-dcc S^^VGa``d2;::l1K n?>**UM)nTKK BI|>'Oƞ\bKjO4i֬YӦM>|5BRޑDOUx<ٳg#""{=333VsT*;t'N444_98<d2_xpWWÇgggoڴISSt bAAA, [BX777㌬ΜY,,~wY:(ksssHHJ]ztD"Y, 6=z~766ƹcэ7֬Y{Y[[{yy͘1ȑ#gsEEET*իo;A(^|9,,ۤs_>??W^( oěꘘB/\妢&%%E^xu9C)ov„ og̘񶞑t6nhiiĥKD"w |U%IIIJ]=700 :/zw)++&SτBg}FN:EH@7o>֛~Fnݺ$<=#444|wr/Cccc߿>Wtt4%:_CRΝ+Ņ'OTn999{w7o`0m7Ͽ3P(FFF2O?iiiɯ P@TEڸq\emmmgg'Ņؿ/"䫧D"Q```ee{pАȊ+;Dxp_ryyy555mmmqmm>}6lʔ)nnn$&) s+6o޼k׮~<77رc7o|)6db{!Ǐ'E%4mڴ 6<}fs\c7>~rjxoV ww͛7,WnXb8yyy!}v׮]GoGRCHK xzzN>|666*l6M^]/ZRW@k֬yf}}= f0bZZZFFFÇ߲eD[V`?^XX{ne߾}n(ݔ.ZЫ#0Xinn{M@tٳO>]ZZUVeffnڴVKKcopǎ~3766^z?*ɺћsv'gvnɘ2駟=z˚]vc#HGElll̙s1W%''\Rֳ444֮]+V455;wNo===w7+glZxʀba}ӧOhEa}۷?~wttdǏ9ܰX*c[Vc_͎ǿl֢t`L&sܹO.++iii+W{_~ieebcc̙#]k֬)//ٳgߺuK"EnʍKAA ^|V]]F9::<r޽sUUUر\.wܸqRx+W>SI/=zt[[ÇhT)787115jXjj*B(00gzxx:5Uaeenݺ7oL&]555ǎb@KKK I/TnM@@@AAqXx1B=|}}/wڵQF<T\\ܷo_f>ÇK׮36PuSnp;w!Cˊ P[[ŋ o3BYYكL"I(:)kݻlڴIv-,,ꤾ\a)7t:ߏBSSҥKcǎurr333kmm�pF3f$t^|)R999[n=~DR_0+V_^:qDZVVfmm-Q/WA7@h4P DEEɸ;,]]]̙qFH?Ϻ~GP!U(!I7HX~}~G|D"%m۶yxxDGGkᅬ?meee8{ӧO>~ril{w*++?L=LܲeNAA #G4H~NHV8oݺuk?gG hkk=zT宧}رcҤNk֬>|(P<cjjg_^^v/󪄄SNM2e8n?~UXX,C s5>|8l߾N6ys\l߾M;vXYYIݢ"i_UZZX__OT۰aƍI&%1cƌ8O̙3߻_9::޽{>x@f͚?BH/tuu555}׆'Nxۆ<ƍWRg!"gݒ%KhyggOPP \O/{Ο?d>onnhnn%5`9s愆W}AQcc>,&_577V@%HYn:::=zTRRŋvfhhاOOOOl&q2nݺk׮UV-e@r}{@o>*zab&$$0ذ w@"""x<|ŋ5kȑ#~᧟~eB*^.&&N/XQ8</<iʝ ,>|'O͛ 08舍={qƏ/<==埲\ SZZ}cǎ1)SL0aȐ!NNNL&S|@ ())̼vڅ ZZZ7n܈m𠫫8|rRi@@8N\\\BB;w\.F333ӣRuuuZZZÆ 2eʼy666`"FIPn H$z6D".rvvvwwg0^_744(R-Ytɓ'w޽rJB2 ^[[{}&{1P([#eh4ڥKGQ1j_~ӧO?s< ѣGgffl===x3rqqrj3%%L=ZTT-ZbX?@X,wʻ!HB jҥKuuuN΃55///55PGG{ʔ)|>Ï?P(>>>/f2oR7o^xq~~>v|}}KKK{8'!!?/**JHH~njTQQq!pd2o߾miif33ѣGËpԎ͛ivv1chkk A͘1C|BBBrEcc#vѣGÆ {[̥Kb'O]{,l'O"n*>ASSgŎxyyM0!55֭[Ɯ2eJKK ˙3gtN=<< I|.^(>8rHٳgþ}2 cw4Czzzk,,,tuu^lDp8N_kjj?TTT# X,[YYDK./%"> +7\.m/̠^ 6T*uٲe'N(--Ɩ a20Bӹ\.}||RRR֯_|rrĀh8PnP/]ml1022jjjB:Vo RSS)K߾}KJJ{%~3dG!dgg" eĈl6Yƍ(>3fLvvvB@`+c+BqڵW=͜9S|mM: wܡPnP/666o7nIP:;;+++III6ӧ-,,`F8jgܹ.]~SNUTT츸j  2_zBDEEܹ!44*fk׮r)//wttܽ{wDDě&%% _? Hdkkۯ_3+W 4hذaoknƍvp8PnPGC (//u2<444X[[?… utĉ(y7wX52gΜ-[dgg˯7nCg 5%,,,_QQ1p@"TjJJJMMͤI^|IlZ$ qqqtRVVք $ٳTSSSq(7q]pC z.իXRRPnPw'Nw_~5x`@?hРNr@ >>//S$aoЙLٳ.\HZ @A @A @A @A_o 7dܞIENDB`golang-gonum-v1-gonum-0.14.0/graph/layout/testdata/wp_page_isomap_noasm_golden.png000066400000000000000000000426211450372207100303170ustar00rootroot00000000000000PNG  IHDRzzEXIDATxw\S8# KXZmJ^QTl! !@a$Qě&7!/9"{ d˳g޸q3nj֭^zumm-+\4w:x𠉉 ڱcyUkkkttnTTP(sJ {ɓLW_}*E]v6B9*# <@"&Mb0qqq%Tqqܹs+**QI$ɓtk B1%%eȑƍKII!(Gw7UYY?`khhV$]p!%%ÃJ | [nikk\(Θ1#'''33ؘ:S_TWW^kB4ĉ #<<nx __SNȯw9ҥKAAAkDPnxchk׮ɻŋ?|0''J=(7CJJʈ#,˝N8!(@BBB^xqM<'F\hhhYYY|/477>|x޼yxwrrrtttݻw{{{߽{WKK O۷o5ٳg2d Rr8wtt}ܹsB9B⧟~oggGvJ hkkDd'Ԡ@l3(7 ;;!4h QjPn ӧOBd'Ԡ@Av x9{'(7ؘ,bBA|>֖,d%Bى(;(7*''!Fv" 8Dd߿?ى(;(7ȪNS?Mv* 722"; Y566?< +[Yuvvۗ,TdRRRoqrLB^^^d' 'Ob "*Iv"* 2)//"; jrLB5@@&}!; tttۓjrB#;eff" @v" Ey{{jr􊊊(ى(7H l}}}PPn^CC)Y (7H:~A@z0?(7HŅDTIv"* Rz1,*(7H!;L)2LP%PnRUU.Y(7HĄ,T laaAv RvvvdgJ 6HLv" xBݝDT 4hى(7Hӧ!Q%PnFII ; i<\GG,T QWWgllLv* hjjə*>;;dx<&Y[[ E?JWW9n߾}̙7o"544۫_|;vlppqT. ڵkWaa3===_Ԕs޽T;;>,<<\CCܕ[W^uvvO p^URRvZ]]];;s9GU>B,^JuuuXyq\9ڠ3Ü:ujeeѣG'L K;w\ro߾*++Gw%M:͛3 f``d``@TX7eʔⴴ>}VAjM ֦>JhTx]2221#AOO/!!lWEpwW~~מ={-[&Vbcc{ʯӧ֦Q(64iҤֻwʵ,oo[n5Jmegg4cƌw[ PS/.,,LKKׯ={6::Z&OLR/^(is <*={6<<\ N$iW\ PG׮]9s&󛛛?3fH=fĉ:::.] PG7n:t!kJעѣwr%z-/c<1JrQ~~uqq)..Tp P;---<O{ Bu~Z .vGEX P;B!D.H$Rp P;V-vvi4VpXfff nWy@jJ:88<{LX,===<u흙FI nT@hȑ3cINN1b"[T6Pn:8qbCC"deeȸǃ(>|c?f3#FXcӦM:::駟^~ɓ'D䮪5uԩ%KZSSGdkk}i 5%?n8Iʒ† >\\\ Q[Pn7oރ¨]$x|mX,PT>/c P;؎[n}kggwe߼y"993srrĻwJݢ r˭[L&FKR("O6 !R[[NjV^ P#P(999=v} xzz~=\RR?`oݺ%EbL&8FFFR\*` P˗/y1?~|ZsssOOO333 /^effxt~N\f O>dϞ=RRZPn@'RSSGyMl`,)))=*//ollloog2vvv7nhnn&juϟcoȾ@BfxGGGSyРAF& ǏmllGx|777qybcD"sVVBILL$0>3z-l&F믿ԊKSSS]]yyy[nUXVVVݓw+"h̙< ʻQbAg &L Ν>}"3gN||tK[[#ttt@ DE8p`̘1L&ѣG 5Yf ”Ç#x<BYx1!aǎJe0 F1 :ndd4gΜ& PyN \GGFxxঝGYdɉ'D"BROOZYYZZZUH gBaðBLOJӕQ...^l2l??ƞϯBt:z*NT`` $1!;b---lн{$jN$;99QTى*(7@%eggP(b+I ]XXHnX@ihh|;tall ;w2 KјL۷_!qF:u6'$$si4l->z‚FrA*oATTTmڴ6f= d:___?B۷/v0&&FM4 i4ZYY΁rTÛ{'(춫Dǒ%K}~Nx=sk1b@ xm/P(7@Y(l¦)]vDSPP`oo|mu~^=ma3B9qī0s-[xxxTWWؐ&OLPN>Mv"x---L&Jb"'///88X J577))D"Q>}ퟗ$B{챲rw7Ld W>>>`hkk< J^\\(VZcjkk6 MrrSsss||W_}Ev:5k@ v(?p=r1cJmkk;w.v;::^;ܽj`?By2J^u\?ԩSBO>}MCC_I|ɓ'xNŪRbb-[Mj`jj'ν{T*dmFEFFȿh4ڶmpƆ7 =]~`J/ KKKmmDyȑ#TP(h 6m277oiia08q˗/ۿ$%i( rOvZv-BsrjjҥKL&JhzzzӦMù~EWW޽{i4Zffka5? _3gΌPE/rd炰1c$%%ɻ[[[.MxtUA-^!E͞=ڵkׯ_wC{uw=1rQYY9pƭ[a2dZZZ b777}}}lkNT߾}g Bܹs˖-SٳgDnOr֋g'Hjuuu+ԩS'Lp;v\$o}\%Cn iccp΅|؃gϒOݻBpҥT*uܹ=CENwȷ~zle x)SPԉ'|&@FkkkPDDٹ(kkk;;;ƀT1c*++eD>w Jf'Hj4,`0|խXJ2<@2hL&d碌q7iiid' 魑J566޲e ;+Wjhhh4777-¸ M6mٲ$++K3 e˖/d? @ pwwͽqƜ9sZ[[ɓ]\\,--BaSSSuuuAA ejj*։Kڌ3=Eߟ,ǒ%Kojj b2ݮ-&]pw$N߾}DU\wwnO=x`VVVSSF355 q  {\P͞F)i(7Vii7߿_]]rBQ Srr Bs|0~MMMFFF7n$;Go2 Mopbbb9cdd4x`WWW;;;}}}f={Y\\lnn|T+VIKK}˕NnTvvHhgO|_~URRRz[RRk.ݴiӞ!ʍkoo)ʧ~"]HtaCCC2q@l]vVḱĶZZZƌchh({X,@,MMѣG:=Y `ܨ0>`ccGTLdhhnllLJӫV"!? H4k,KKbb#wttL8F rwZs]7XOU}wW^MLLtpp 628{l~\]]_H-44[jKjjj"F%=zh?A_GGŋ999!T]]-׆F477ggg=...;w|BquuE=ygwJ/xݴiAVVشiB(!!A~MH ʍ*yQWWqoll/_"LMMqR& `ѣG_GG!bN*&dF陛K)##CGGG^6HWWOV"QQQyėU %Ņ5557n~?~۶' )o,,,G/!tyy'UֆtqAll,g ~JJ4i'|G\ErJh4@ ږ &L>}ԨQö֗]&lÇs߾}<[0CDOOH}͛۷oῖH.xVbb"1AϜ9C`Lyr2RRR޽[[[+c{9rƍFTTTH7+Q~rrr&066 !*e?JKK_xֆ-dcc S^^VGa``d2;::l1K n?>**UM)nTKK BI|>'Oƞ\bKjO4i֬YӦM>|5BRޑDOUx<ٳg#""{=333VsT*;t'N444_98<d2_xpWWÇgggoڴISSt bAAA, [BX777㌬ΜY,,~wY:(ksssHHJ]ztD"Y, 6=z~766ƹcэ7֬Y{Y[[{yy͘1ȑ#gsEEET*իo;A(^|9,,ۤs_>??W^( oěꘘB/\妢&%%E^xu9C)ov„ og̘񶞑t6nhiiĥKD"w |U%IIIJ]=700 :/zw)++&SτBg}FN:EH@7o>֛~Fnݺ$<=#444|wr/Cccc߿>Wtt4%:_CRΝ+Ņ'OTn999{w7o`0m7Ͽ3P(FFF2O?iiiɯ P@TEڸq\emmmgg'Ņؿ/"䫧D"Q```ee{pАȊ+;Dxp_ryyy555mmmqmm>}6lʔ)nnn$&) s+6o޼k׮~<77رc7o|)6db{!Ǐ'E%4mڴ 6<}fs\c7>~rjxoV ww͛7,WnXb8yyy!}v׮]GoGRCHK xzzN>|666*l6M^]/ZRW@k֬yf}}= f0bZZZFFFÇ߲eD[V`?^XX{ne߾}n(ݔ.ZЫ#0Xinn{M@tٳO>]ZZUVeffnڴVKKcopǎ~3766^z?*ɺћsv'gvnɘ2駟=z˚]vc#HGElll̙s1W%''\Rֳ444֮]+V455;wNo===w7+glZxʀba}ӧOhEa}۷?~wttdǏ9ܰX*c[Vc_͎ǿl֢t`L&sܹO.++iii+W{_~ieebcc̙#]k֬)//ٳgߺuK"EnʍKAA ^|V]]F9::<r޽sUUUر\.wܸqRx+W>SI/=zt[[ÇhT)787115jXjj*B(00gzxx:5Uaeenݺ7oL&]555ǎb@KKK I/TnM@@@AAqXx1B=|}}/wڵQF<T\\ܷo_f>ÇK׮36PuSnp;w!Cˊ P[[ŋ o3BYYكL"I(:)kݻlڴIv-,,ꤾ\a)7t:ߏBSSҥKcǎurr333kmm�pF3f$t^|)R999[n=~DR_0+V_^:qDZVVfmm-Q/WA7@h4P DEEɸ;,]]]̙qFH?Ϻ~GP!U(!I7HX~}~G|D"%m۶yxxDGGkᅬ?meee8{ӧO>~ril{w*++?L=LܲeNAA #G4H~NHV8oݺuk?gG hkk=zT宧}رcҤNk֬>|(P<cjjg_^^v/󪄄SNM2e8n?~UXX,C s5>|8l߾N6ys\l߾M;vXYYIݢ"i_UZZX__OT۰aƍI&%1cƌ8O̙3߻_9::޽{>x@f͚?BH/tuu555}׆'Nxۆ<ƍWRg!"gݒ%KhyggOPP \O/{Ο?d>onnhnn%5`9s愆W}AQcc>,&_577V@%HYn:::=zTRRŋvfhhاOOOOl&q2nݺk׮UV-e@r}{@o>*zab&$$0ذ w@"""x<|ŋ5kȑ#~᧟~eB*^.&&N/XQ8</<iʝ ,>|'O͛ 08舍={qƏ/<==埲\ SZZ}cǎ1)SL0aȐ!NNNL&S|@ ())̼vڅ ZZZ7n܈m𠫫8|rRi@@8N\\\BB;w\.F333ӣRuuuZZZÆ 2eʼy666`"FIPn H$z6D".rvvvwwg0^_744(R-Ytɓ'w޽rJB2 ^[[{}&{1P([#eh4ڥKGQ1j_~ӧO?s< ѣGgffl===x3rqqrj3%%L=ZTT-ZbX?@X,wʻ!HB jҥKuuuN΃55///55PGG{ʔ)|>Ï?P(>>>/f2oR7o^xq~~>v|}}KKK{8'!!?/**JHH~njTQQq!pd2o߾miif33ѣGËpԎ͛ivv1chkk A͘1C|BBBrEcc#vѣGÆ {[̥Kb'O]{,l'O"n*>ASSgŎxyyM0!55֭[Ɯ2eJKK ˙3gtN=<< I|.^(>8rHٳgþ}2 cw4Czzzk,,,tuu^lDp8N_kjj?TTT# X,[YYDK./%"> +7\.m/̠^ 6T*uٲe'N(--Ɩ a20Bӹ\.}||RRR֯_|rrĀh8PnP/]ml1022jjjB:Vo RSS)K߾}KJJ{%~3dG!dgg" eĈl6Yƍ(>3fLvvvB@`+c+BqڵW=͜9S|mM: wܡPnP/666o7nIP:;;+++III6ӧ-,,`F8jgܹ.]~SNUTT츸j  2_zBDEEܹ!44*fk׮r)//wttܽ{wDDě&%% _? Hdkkۯ_3+W 4hذaoknƍvp8PnPGC (//u2<444X[[?… utĉ(y7wX52gΜ-[dgg˯7nCg 5%,,,_QQ1p@"TjJJJMMͤI^|IlZ$ qqqtRVVք $ٳTSSSq(7q]pC z.իXRRPnPw'Nw_~5x`@?hРNr@ >>//S$aoЙLٳ.\HZ @A @A @A @A_o 7dܞIENDB`golang-gonum-v1-gonum-0.14.0/graph/multi/000077500000000000000000000000001450372207100200715ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/multi/directed.go000066400000000000000000000173461450372207100222160ustar00rootroot00000000000000// 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 multi import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/set/uid" ) var ( dg *DirectedGraph _ graph.Graph = dg _ graph.Directed = dg _ graph.Multigraph = dg _ graph.DirectedMultigraph = dg _ graph.NodeAdder = dg _ graph.NodeRemover = dg _ graph.LineAdder = dg _ graph.LineRemover = dg ) // DirectedGraph implements a generalized directed graph. type DirectedGraph struct { nodes map[int64]graph.Node from map[int64]map[int64]map[int64]graph.Line to map[int64]map[int64]map[int64]graph.Line nodeIDs *uid.Set lineIDs map[int64]map[int64]*uid.Set } // NewDirectedGraph returns a DirectedGraph. func NewDirectedGraph() *DirectedGraph { return &DirectedGraph{ nodes: make(map[int64]graph.Node), from: make(map[int64]map[int64]map[int64]graph.Line), to: make(map[int64]map[int64]map[int64]graph.Line), nodeIDs: uid.NewSet(), lineIDs: make(map[int64]map[int64]*uid.Set), } } // 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. // The returned graph.Edge is a multi.Edge if an edge exists. func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge { l := g.Lines(uid, vid) if l == graph.Empty { return nil } return Edge{F: g.Node(uid), T: g.Node(vid), Lines: l} } // Edges returns all the edges in the graph. Each edge in the returned slice // is a multi.Edge. // // The returned graph.Edges is only valid until the next mutation of // the receiver. func (g *DirectedGraph) Edges() graph.Edges { if len(g.nodes) == 0 { return graph.Empty } var edges []graph.Edge for uid, u := range g.nodes { for vid, lines := range g.from[u.ID()] { if len(lines) == 0 { continue } edges = append(edges, Edge{ F: g.Node(uid), T: g.Node(vid), Lines: iterator.NewLines(lines), }) } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedEdges(edges) } // From returns all nodes in g that can be reached directly from n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *DirectedGraph) From(id int64) graph.Nodes { if len(g.from[id]) == 0 { return graph.Empty } return iterator.NewNodesByLines(g.nodes, g.from[id]) } // 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 { _, ok := g.from[uid][vid] return ok } // Lines returns the lines from u to v if such any such lines exists and nil otherwise. // The node v must be directly reachable from u as defined by the From method. func (g *DirectedGraph) Lines(uid, vid int64) graph.Lines { edge := g.from[uid][vid] if len(edge) == 0 { return graph.Empty } var lines []graph.Line for _, l := range edge { lines = append(lines, l) } return iterator.NewOrderedLines(lines) } // NewLine returns a new Line from the source to the destination node. // The returned Line will have a graph-unique ID. // The Line's ID does not become valid in g until the Line is added to g. func (g *DirectedGraph) NewLine(from, to graph.Node) graph.Line { fid := from.ID() tid := to.ID() var lineID int64 switch { case g.lineIDs[fid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[fid] = map[int64]*uid.Set{tid: uids} case g.lineIDs[fid][tid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[fid][tid] = uids default: lineID = g.lineIDs[fid][tid].NewID() } return Line{F: from, T: to, UID: lineID} } // 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. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *DirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *DirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // RemoveLine removes the line with the given end point and line IDs from the graph, leaving // the terminal nodes. If the line does not exist it is a no-op. func (g *DirectedGraph) RemoveLine(fid, tid, id int64) { if _, ok := g.nodes[fid]; !ok { return } if _, ok := g.nodes[tid]; !ok { return } delete(g.from[fid][tid], id) if len(g.from[fid][tid]) == 0 { delete(g.from[fid], tid) } delete(g.to[tid][fid], id) if len(g.to[tid][fid]) == 0 { delete(g.to[tid], fid) } g.lineIDs[fid][tid].Release(id) } // 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) } // SetLine adds l, a line from one node to another. If the nodes do not exist, they are added // and are set to the nodes of the line otherwise. func (g *DirectedGraph) SetLine(l graph.Line) { var ( from = l.From() fid = from.ID() to = l.To() tid = to.ID() lid = l.ID() ) 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 } switch { case g.from[fid] == nil: g.from[fid] = map[int64]map[int64]graph.Line{tid: {lid: l}} case g.from[fid][tid] == nil: g.from[fid][tid] = map[int64]graph.Line{lid: l} default: g.from[fid][tid][lid] = l } switch { case g.to[tid] == nil: g.to[tid] = map[int64]map[int64]graph.Line{fid: {lid: l}} case g.to[tid][fid] == nil: g.to[tid][fid] = map[int64]graph.Line{lid: l} default: g.to[tid][fid][lid] = l } switch { case g.lineIDs[fid] == nil: uids := uid.NewSet() g.lineIDs[fid] = map[int64]*uid.Set{tid: uids} case g.lineIDs[fid][tid] == nil: uids := uid.NewSet() g.lineIDs[fid][tid] = uids } g.lineIDs[fid][tid].Use(lid) } // To returns all nodes in g that can reach directly to n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *DirectedGraph) To(id int64) graph.Nodes { if len(g.to[id]) == 0 { return graph.Empty } return iterator.NewNodesByLines(g.nodes, g.to[id]) } golang-gonum-v1-gonum-0.14.0/graph/multi/directed_test.go000066400000000000000000000107371450372207100232520ustar00rootroot00000000000000// 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 multi_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/testgraph" ) func directedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, _, _ float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() dg := multi.NewDirectedGraph() for _, n := range nodes { seen.Add(n) dg.AddNode(n) } for _, edge := range edges { f := dg.Node(edge.From().ID()) if f == nil { f = edge.From() } t := dg.Node(edge.To().ID()) if t == nil { t = edge.To() } cl := multi.Line{F: f, T: t, UID: edge.ID()} seen.Add(cl.F) seen.Add(cl.T) e = append(e, cl) dg.SetLine(cl) } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return dg, n, e, math.NaN(), math.NaN(), true } func TestDirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, directedBuilder, reversesEdges) }) t.Run("LineExistence", func(t *testing.T) { testgraph.LineExistence(t, directedBuilder, usesEmpty, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, directedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, directedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllLines", func(t *testing.T) { testgraph.ReturnAllLines(t, directedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, directedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, directedBuilder, usesEmpty) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, multi.NewDirectedGraph(), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, multi.NewDirectedGraph(), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }), ) }) t.Run("RemoveNodes", func(t *testing.T) { g := multi.NewDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- g.SetLine(g.NewLine(u, v)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddLines", func(t *testing.T) { testgraph.AddLines(t, 100, multi.NewDirectedGraph(), func(id int64) graph.Node { return multi.Node(id) }, true, // Can update nodes. ) }) t.Run("RemoveLines", func(t *testing.T) { g := multi.NewDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() var lines []graph.Line rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- l := g.NewLine(u, v) g.SetLine(l) lines = append(lines, l) } } rnd.Shuffle(len(lines), func(i, j int) { lines[i], lines[j] = lines[j], lines[i] }) testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines)) }) } // Tests Issue #27 func TestEdgeOvercounting(t *testing.T) { g := generateDummyGraph() if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 { t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh)) } } func generateDummyGraph() *multi.DirectedGraph { nodes := [4]struct{ srcID, targetID int }{ {2, 1}, {1, 0}, {2, 0}, {0, 2}, } g := multi.NewDirectedGraph() for i, n := range nodes { g.SetLine(multi.Line{F: multi.Node(n.srcID), T: multi.Node(n.targetID), UID: int64(i)}) } return g } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123DirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := multi.NewDirectedGraph() n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/multi/doc.go000066400000000000000000000006231450372207100211660ustar00rootroot00000000000000// 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 multi provides a suite of multigraph implementations satisfying // the gonum/graph interfaces. // // All types in multi return the graph.Empty value for empty iterators. package multi // import "gonum.org/v1/gonum/graph/multi" golang-gonum-v1-gonum-0.14.0/graph/multi/multi.go000066400000000000000000000070271450372207100215600ustar00rootroot00000000000000// 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 multi import "gonum.org/v1/gonum/graph" // Node here is a duplication of simple.Node // to avoid needing to import both packages. // 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) } // Edge is a collection of multigraph edges sharing end points. type Edge struct { F, T graph.Node graph.Lines } // 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 } // ReversedEdge 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} } // Line is a multigraph edge. type Line struct { F, T graph.Node UID int64 } // From returns the from-node of the line. func (l Line) From() graph.Node { return l.F } // To returns the to-node of the line. func (l Line) To() graph.Node { return l.T } // ReversedLine returns a new Line with the F and T fields // swapped. The UID of the new Line is the same as the // UID of the receiver. The Lines within the Edge are // not altered. func (l Line) ReversedLine() graph.Line { l.F, l.T = l.T, l.F; return l } // ID returns the ID of the line. func (l Line) ID() int64 { return l.UID } // WeightedEdge is a collection of weighted multigraph edges sharing end points. type WeightedEdge struct { F, T graph.Node graph.WeightedLines // WeightFunc calculates the aggregate // weight of the lines in Lines. If // WeightFunc is nil, the sum of weights // is used as the edge weight. // The graph.WeightedLines can be expected // to be positioned at the first line of // the iterator on entry and must be // Reset before exit. // WeightFunc must accept a nil input. WeightFunc func(graph.WeightedLines) 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 } // ReversedEdge returns a new Edge with the F and T fields // swapped. The Lines within the WeightedEdge are not // altered. func (e WeightedEdge) ReversedEdge() graph.Edge { e.F, e.T = e.T, e.F; return e } // Weight returns the weight of the edge. Weight uses WeightFunc // field to calculate the weight, so the WeightedLines field is // expected to be positioned at the first line and is reset before // Weight returns. func (e WeightedEdge) Weight() float64 { if e.WeightFunc != nil { return e.WeightFunc(e.WeightedLines) } if e.WeightedLines == nil { return 0 } var w float64 for e.Next() { w += e.WeightedLine().Weight() } e.WeightedLines.Reset() return w } // WeightedLine is a weighted multigraph edge. type WeightedLine struct { F, T graph.Node W float64 UID int64 } // From returns the from-node of the line. func (l WeightedLine) From() graph.Node { return l.F } // To returns the to-node of the line. func (l WeightedLine) To() graph.Node { return l.T } // ReversedLine returns a new Line with the F and T fields // swapped. The UID and W of the new Line are the same as the // UID and W of the receiver. func (l WeightedLine) ReversedLine() graph.Line { l.F, l.T = l.T, l.F; return l } // ID returns the ID of the line. func (l WeightedLine) ID() int64 { return l.UID } // Weight returns the weight of the edge. func (l WeightedLine) Weight() float64 { return l.W } golang-gonum-v1-gonum-0.14.0/graph/multi/undirected.go000066400000000000000000000174171450372207100225600ustar00rootroot00000000000000// 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 multi import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/set/uid" ) var ( ug *UndirectedGraph _ graph.Graph = ug _ graph.Undirected = ug _ graph.Multigraph = ug _ graph.UndirectedMultigraph = ug _ graph.NodeAdder = ug _ graph.NodeRemover = ug _ graph.LineAdder = ug _ graph.LineRemover = ug ) // UndirectedGraph implements a generalized undirected graph. type UndirectedGraph struct { nodes map[int64]graph.Node lines map[int64]map[int64]map[int64]graph.Line nodeIDs *uid.Set lineIDs map[int64]map[int64]*uid.Set } // NewUndirectedGraph returns an UndirectedGraph. func NewUndirectedGraph() *UndirectedGraph { return &UndirectedGraph{ nodes: make(map[int64]graph.Node), lines: make(map[int64]map[int64]map[int64]graph.Line), nodeIDs: uid.NewSet(), lineIDs: make(map[int64]map[int64]*uid.Set), } } // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. func (g *UndirectedGraph) 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. // The returned graph.Edge is a multi.Edge if an edge exists. func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge { l := g.LinesBetween(uid, vid) if l == graph.Empty { return nil } return Edge{F: g.Node(uid), T: g.Node(vid), Lines: l} } // EdgeBetween returns the edge between nodes x and y. func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge { return g.Edge(xid, yid) } // Edges returns all the edges in the graph. Each edge in the returned slice // is a multi.Edge. // // The returned graph.Edges is only valid until the next mutation of // the receiver. func (g *UndirectedGraph) Edges() graph.Edges { if len(g.lines) == 0 { return graph.Empty } var edges []graph.Edge for xid, u := range g.lines { for yid, lines := range u { if yid < xid { // Do not consider lines when the To node ID is // before the From node ID. Both orientations // are stored. continue } if len(lines) == 0 { continue } edges = append(edges, Edge{ F: g.Node(xid), T: g.Node(yid), Lines: iterator.NewLines(lines), }) } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedEdges(edges) } // From returns all nodes in g that can be reached directly from n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *UndirectedGraph) From(id int64) graph.Nodes { if len(g.lines[id]) == 0 { return graph.Empty } return iterator.NewNodesByLines(g.nodes, g.lines[id]) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool { _, ok := g.lines[xid][yid] return ok } // Lines returns the lines 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 *UndirectedGraph) Lines(uid, vid int64) graph.Lines { return g.LinesBetween(uid, vid) } // LinesBetween returns the lines between nodes x and y. func (g *UndirectedGraph) LinesBetween(xid, yid int64) graph.Lines { if !g.HasEdgeBetween(xid, yid) { return graph.Empty } var lines []graph.Line for _, l := range g.lines[xid][yid] { if l.From().ID() != xid { l = l.ReversedLine() } lines = append(lines, l) } return iterator.NewOrderedLines(lines) } // NewLine returns a new Line from the source to the destination node. // The returned Line will have a graph-unique ID. // The Line's ID does not become valid in g until the Line is added to g. func (g *UndirectedGraph) NewLine(from, to graph.Node) graph.Line { xid := from.ID() yid := to.ID() if yid < xid { xid, yid = yid, xid } var lineID int64 switch { case g.lineIDs[xid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[xid] = map[int64]*uid.Set{yid: uids} case g.lineIDs[xid][yid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[xid][yid] = uids default: lineID = g.lineIDs[xid][yid].NewID() } return Line{F: from, T: to, UID: lineID} } // 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 *UndirectedGraph) 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 *UndirectedGraph) Node(id int64) graph.Node { return g.nodes[id] } // Nodes returns all the nodes in the graph. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *UndirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *UndirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // RemoveLine removes the line with the given end point and line Ids from the graph, leaving // the terminal nodes. If the line does not exist it is a no-op. func (g *UndirectedGraph) RemoveLine(fid, tid, id int64) { if _, ok := g.nodes[fid]; !ok { return } if _, ok := g.nodes[tid]; !ok { return } delete(g.lines[fid][tid], id) if len(g.lines[fid][tid]) == 0 { delete(g.lines[fid], tid) } delete(g.lines[tid][fid], id) if len(g.lines[tid][fid]) == 0 { delete(g.lines[tid], fid) } xid := fid yid := tid if yid < xid { xid, yid = yid, xid } g.lineIDs[xid][yid].Release(id) } // 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 *UndirectedGraph) RemoveNode(id int64) { if _, ok := g.nodes[id]; !ok { return } delete(g.nodes, id) for from := range g.lines[id] { delete(g.lines[from], id) } delete(g.lines, id) g.nodeIDs.Release(id) } // SetLine adds l, a line from one node to another. If the nodes do not exist, they are added // and are set to the nodes of the line otherwise. func (g *UndirectedGraph) SetLine(l graph.Line) { var ( from = l.From() fid = from.ID() to = l.To() tid = to.ID() lid = l.ID() ) 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 } switch { case g.lines[fid] == nil: g.lines[fid] = map[int64]map[int64]graph.Line{tid: {lid: l}} case g.lines[fid][tid] == nil: g.lines[fid][tid] = map[int64]graph.Line{lid: l} default: g.lines[fid][tid][lid] = l } switch { case g.lines[tid] == nil: g.lines[tid] = map[int64]map[int64]graph.Line{fid: {lid: l}} case g.lines[tid][fid] == nil: g.lines[tid][fid] = map[int64]graph.Line{lid: l} default: g.lines[tid][fid][lid] = l } xid := fid yid := tid if yid < xid { xid, yid = yid, xid } switch { case g.lineIDs[xid] == nil: uids := uid.NewSet() g.lineIDs[xid] = map[int64]*uid.Set{yid: uids} case g.lineIDs[xid][yid] == nil: uids := uid.NewSet() g.lineIDs[xid][yid] = uids } g.lineIDs[xid][yid].Use(lid) } golang-gonum-v1-gonum-0.14.0/graph/multi/undirected_test.go000066400000000000000000000107401450372207100236070ustar00rootroot00000000000000// 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 multi_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/testgraph" ) const ( usesEmpty = true reversesEdges = true ) func undirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, _, _ float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() ug := multi.NewUndirectedGraph() for _, n := range nodes { seen.Add(n) ug.AddNode(n) } for _, edge := range edges { f := ug.Node(edge.From().ID()) if f == nil { f = edge.From() } t := ug.Node(edge.To().ID()) if t == nil { t = edge.To() } ce := multi.Line{F: f, T: t, UID: edge.ID()} seen.Add(ce.F) seen.Add(ce.T) e = append(e, ce) ug.SetLine(ce) } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return ug, n, e, math.NaN(), math.NaN(), true } func TestUndirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, undirectedBuilder, reversesEdges) }) t.Run("LineExistence", func(t *testing.T) { testgraph.LineExistence(t, undirectedBuilder, usesEmpty, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, undirectedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, undirectedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllLines", func(t *testing.T) { testgraph.ReturnAllLines(t, undirectedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, undirectedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, undirectedBuilder, usesEmpty) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, multi.NewUndirectedGraph(), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, multi.NewUndirectedGraph(), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }), ) }) t.Run("RemoveNodes", func(t *testing.T) { g := multi.NewUndirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- g.SetLine(g.NewLine(u, v)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddLines", func(t *testing.T) { testgraph.AddLines(t, 100, multi.NewUndirectedGraph(), func(id int64) graph.Node { return multi.Node(id) }, true, // Can update nodes. ) }) t.Run("RemoveLines", func(t *testing.T) { g := multi.NewUndirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() var lines []graph.Line rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- l := g.NewLine(u, v) g.SetLine(l) lines = append(lines, l) } } rnd.Shuffle(len(lines), func(i, j int) { lines[i], lines[j] = lines[j], lines[i] }) testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines)) }) } func TestMaxID(t *testing.T) { g := multi.NewUndirectedGraph() nodes := make(map[graph.Node]struct{}) for i := multi.Node(0); i < 3; i++ { g.AddNode(i) nodes[i] = struct{}{} } g.RemoveNode(int64(0)) delete(nodes, multi.Node(0)) g.RemoveNode(int64(2)) delete(nodes, multi.Node(2)) n := g.NewNode() g.AddNode(n) if g.Node(n.ID()) == nil { t.Error("added node does not exist in graph") } if _, exists := nodes[n]; exists { t.Errorf("Created already existing node id: %v", n.ID()) } } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123UndirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := multi.NewUndirectedGraph() n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/multi/weighted_directed.go000066400000000000000000000252461450372207100240740ustar00rootroot00000000000000// 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 multi import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/set/uid" ) var ( wdg *WeightedDirectedGraph _ graph.Graph = wdg _ graph.Weighted = wdg _ graph.Directed = wdg _ graph.WeightedDirected = wdg _ graph.Multigraph = wdg _ graph.DirectedMultigraph = wdg _ graph.WeightedDirectedMultigraph = wdg _ graph.NodeAdder = wdg _ graph.NodeRemover = wdg _ graph.WeightedLineAdder = wdg _ graph.LineRemover = wdg ) // WeightedDirectedGraph implements a generalized directed graph. type WeightedDirectedGraph struct { // EdgeWeightFunc is used to provide // the WeightFunc function for WeightedEdge // values returned by the graph. // WeightFunc must accept a nil input. EdgeWeightFunc func(graph.WeightedLines) float64 nodes map[int64]graph.Node from map[int64]map[int64]map[int64]graph.WeightedLine to map[int64]map[int64]map[int64]graph.WeightedLine nodeIDs *uid.Set lineIDs map[int64]map[int64]*uid.Set } // NewWeightedDirectedGraph returns a WeightedDirectedGraph. func NewWeightedDirectedGraph() *WeightedDirectedGraph { return &WeightedDirectedGraph{ nodes: make(map[int64]graph.Node), from: make(map[int64]map[int64]map[int64]graph.WeightedLine), to: make(map[int64]map[int64]map[int64]graph.WeightedLine), nodeIDs: uid.NewSet(), lineIDs: make(map[int64]map[int64]*uid.Set), } } // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. func (g *WeightedDirectedGraph) 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. // The returned graph.Edge is a multi.WeightedEdge if an edge exists. func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge { return g.WeightedEdge(uid, vid) } // Edges returns all the edges in the graph. Each edge in the returned slice // is a multi.WeightedEdge. // // The returned graph.Edges is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) Edges() graph.Edges { if len(g.nodes) == 0 { return graph.Empty } var edges []graph.Edge for uid, u := range g.nodes { for vid, lines := range g.from[u.ID()] { if len(lines) == 0 { continue } edges = append(edges, WeightedEdge{ F: g.Node(uid), T: g.Node(vid), WeightedLines: iterator.NewWeightedLines(lines), WeightFunc: g.EdgeWeightFunc, }) } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedEdges(edges) } // From returns all nodes in g that can be reached directly from n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) From(id int64) graph.Nodes { if len(g.from[id]) == 0 { return graph.Empty } return iterator.NewNodesByWeightedLines(g.nodes, g.from[id]) } // HasEdgeBetween returns whether an edge exists between nodes x and y without // considering direction. func (g *WeightedDirectedGraph) 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 *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool { if _, ok := g.from[uid][vid]; !ok { return false } return true } // Lines returns the lines from u to v if such any such lines exists and nil otherwise. // The node v must be directly reachable from u as defined by the From method. func (g *WeightedDirectedGraph) Lines(uid, vid int64) graph.Lines { edge := g.from[uid][vid] if len(edge) == 0 { return graph.Empty } var lines []graph.Line for _, l := range edge { lines = append(lines, l) } return iterator.NewOrderedLines(lines) } // 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 *WeightedDirectedGraph) 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()) } // NewWeightedLine returns a new WeightedLine from the source to the destination node. // The returned WeightedLine will have a graph-unique ID. // The Line's ID does not become valid in g until the Line is added to g. func (g *WeightedDirectedGraph) NewWeightedLine(from, to graph.Node, weight float64) graph.WeightedLine { fid := from.ID() tid := to.ID() var lineID int64 switch { case g.lineIDs[fid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[fid] = map[int64]*uid.Set{tid: uids} case g.lineIDs[fid][tid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[fid][tid] = uids default: lineID = g.lineIDs[fid][tid].NewID() } return WeightedLine{F: from, T: to, W: weight, UID: lineID} } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *WeightedDirectedGraph) Node(id int64) graph.Node { return g.nodes[id] } // Nodes returns all the nodes in the graph. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *WeightedDirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // RemoveLine removes the line with the given end point and line IDs from the graph, // leaving the terminal nodes. If the line does not exist it is a no-op. func (g *WeightedDirectedGraph) RemoveLine(fid, tid, id int64) { if _, ok := g.nodes[fid]; !ok { return } if _, ok := g.nodes[tid]; !ok { return } delete(g.from[fid][tid], id) if len(g.from[fid][tid]) == 0 { delete(g.from[fid], tid) } delete(g.to[tid][fid], id) if len(g.to[tid][fid]) == 0 { delete(g.to[tid], fid) } g.lineIDs[fid][tid].Release(id) } // 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 *WeightedDirectedGraph) 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) } // SetWeightedLine adds l, a line from one node to another. If the nodes do not exist, they are added // and are set to the nodes of the line otherwise. func (g *WeightedDirectedGraph) SetWeightedLine(l graph.WeightedLine) { var ( from = l.From() fid = from.ID() to = l.To() tid = to.ID() lid = l.ID() ) 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 } switch { case g.from[fid] == nil: g.from[fid] = map[int64]map[int64]graph.WeightedLine{tid: {lid: l}} case g.from[fid][tid] == nil: g.from[fid][tid] = map[int64]graph.WeightedLine{lid: l} default: g.from[fid][tid][lid] = l } switch { case g.to[tid] == nil: g.to[tid] = map[int64]map[int64]graph.WeightedLine{fid: {lid: l}} case g.to[tid][fid] == nil: g.to[tid][fid] = map[int64]graph.WeightedLine{lid: l} default: g.to[tid][fid][lid] = l } switch { case g.lineIDs[fid] == nil: uids := uid.NewSet() g.lineIDs[fid] = map[int64]*uid.Set{tid: uids} case g.lineIDs[fid][tid] == nil: uids := uid.NewSet() g.lineIDs[fid][tid] = uids } g.lineIDs[fid][tid].Use(lid) } // To returns all nodes in g that can reach directly to n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) To(id int64) graph.Nodes { if len(g.to[id]) == 0 { return graph.Empty } return iterator.NewNodesByWeightedLines(g.nodes, g.to[id]) } // Weight returns the weight for the lines between x and y summarised by the receiver's // EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise. func (g *WeightedDirectedGraph) Weight(uid, vid int64) (w float64, ok bool) { lines := g.WeightedLines(uid, vid) return WeightedEdge{WeightedLines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), lines != graph.Empty } // 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. // The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists. func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge { lines := g.WeightedLines(uid, vid) if lines == graph.Empty { return nil } return WeightedEdge{ F: g.Node(uid), T: g.Node(vid), WeightedLines: lines, WeightFunc: g.EdgeWeightFunc, } } // WeightedEdges returns all the edges in the graph. Each edge in the returned slice // is a multi.WeightedEdge. // // The returned graph.WeightedEdges is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges { if len(g.nodes) == 0 { return graph.Empty } var edges []graph.WeightedEdge for uid, u := range g.nodes { for vid, lines := range g.from[u.ID()] { if len(lines) == 0 { continue } edges = append(edges, WeightedEdge{ F: g.Node(uid), T: g.Node(vid), WeightedLines: iterator.NewWeightedLines(lines), WeightFunc: g.EdgeWeightFunc, }) } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedWeightedEdges(edges) } // WeightedLines returns the weighted lines from u to v if such any such lines exists // and nil otherwise. The node v must be directly reachable from u as defined by the From method. func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) graph.WeightedLines { edge := g.from[uid][vid] if len(edge) == 0 { return graph.Empty } var lines []graph.WeightedLine for _, l := range edge { lines = append(lines, l) } return iterator.NewOrderedWeightedLines(lines) } golang-gonum-v1-gonum-0.14.0/graph/multi/weighted_directed_test.go000066400000000000000000000122251450372207100251240ustar00rootroot00000000000000// 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 multi_test import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/testgraph" ) func weightedDirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() dg := multi.NewWeightedDirectedGraph() dg.EdgeWeightFunc = func(l graph.WeightedLines) float64 { if l.Len() == 0 { return absent } var w float64 for l.Next() { w += l.WeightedLine().Weight() } l.Reset() return w } for _, n := range nodes { seen.Add(n) dg.AddNode(n) } for _, edge := range edges { f := dg.Node(edge.From().ID()) if f == nil { f = edge.From() } t := dg.Node(edge.To().ID()) if t == nil { t = edge.To() } cl := multi.WeightedLine{F: f, T: t, UID: edge.ID(), W: edge.Weight()} seen.Add(cl.F) seen.Add(cl.T) e = append(e, cl) dg.SetWeightedLine(cl) } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return dg, n, e, self, absent, true } func TestWeightedDirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, weightedDirectedBuilder, reversesEdges) }) t.Run("LineExistence", func(t *testing.T) { testgraph.LineExistence(t, directedBuilder, usesEmpty, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, weightedDirectedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, weightedDirectedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllLines", func(t *testing.T) { testgraph.ReturnAllLines(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnAllWeightedLines", func(t *testing.T) { testgraph.ReturnAllWeightedLines(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, weightedDirectedBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, weightedDirectedBuilder) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, multi.NewWeightedDirectedGraph(), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, multi.NewWeightedDirectedGraph(), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }), ) }) t.Run("RemoveNodes", func(t *testing.T) { g := multi.NewWeightedDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- g.SetWeightedLine(g.NewWeightedLine(u, v, 1)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddWeightedLines", func(t *testing.T) { testgraph.AddWeightedLines(t, 100, multi.NewWeightedDirectedGraph(), 0.5, func(id int64) graph.Node { return multi.Node(id) }, true, // Can update nodes. ) }) t.Run("RemoveLines", func(t *testing.T) { g := multi.NewWeightedDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() var lines []graph.Line rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- l := g.NewWeightedLine(u, v, 1) g.SetWeightedLine(l) lines = append(lines, l) } } rnd.Shuffle(len(lines), func(i, j int) { lines[i], lines[j] = lines[j], lines[i] }) testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines)) }) } // Tests Issue #27 func TestWeightedEdgeOvercounting(t *testing.T) { g := generateDummyWeightedGraph() if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 { t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh)) } } func generateDummyWeightedGraph() *multi.WeightedDirectedGraph { nodes := [4]struct{ srcID, targetID int }{ {2, 1}, {1, 0}, {2, 0}, {0, 2}, } g := multi.NewWeightedDirectedGraph() for i, n := range nodes { g.SetWeightedLine(multi.WeightedLine{F: multi.Node(n.srcID), T: multi.Node(n.targetID), W: 1, UID: int64(i)}) } return g } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123WeightedDirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := multi.NewWeightedDirectedGraph() n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/multi/weighted_undirected.go000066400000000000000000000264331450372207100244360ustar00rootroot00000000000000// 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 multi import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/set/uid" ) var ( wug *WeightedUndirectedGraph _ graph.Graph = wug _ graph.Weighted = wug _ graph.Undirected = wug _ graph.WeightedUndirected = wug _ graph.Multigraph = wug _ graph.UndirectedMultigraph = wug _ graph.WeightedUndirectedMultigraph = wug _ graph.NodeAdder = wug _ graph.NodeRemover = wug _ graph.WeightedLineAdder = wug _ graph.LineRemover = wug ) // WeightedUndirectedGraph implements a generalized undirected graph. type WeightedUndirectedGraph struct { // EdgeWeightFunc is used to provide // the WeightFunc function for WeightedEdge // values returned by the graph. // WeightFunc must accept a nil input. EdgeWeightFunc func(graph.WeightedLines) float64 nodes map[int64]graph.Node lines map[int64]map[int64]map[int64]graph.WeightedLine nodeIDs *uid.Set lineIDs map[int64]map[int64]*uid.Set } // NewWeightedUndirectedGraph returns an WeightedUndirectedGraph. func NewWeightedUndirectedGraph() *WeightedUndirectedGraph { return &WeightedUndirectedGraph{ nodes: make(map[int64]graph.Node), lines: make(map[int64]map[int64]map[int64]graph.WeightedLine), nodeIDs: uid.NewSet(), lineIDs: make(map[int64]map[int64]*uid.Set), } } // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. func (g *WeightedUndirectedGraph) 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. // The returned graph.Edge is a multi.WeightedEdge if an edge exists. func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge { return g.WeightedEdge(uid, vid) } // EdgeBetween returns the edge between nodes x and y. func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge { return g.WeightedEdge(xid, yid) } // Edges returns all the edges in the graph. Each edge in the returned slice // is a multi.WeightedEdge. // // The returned graph.Edges is only valid until the next mutation of // the receiver. func (g *WeightedUndirectedGraph) Edges() graph.Edges { if len(g.lines) == 0 { return graph.Empty } var edges []graph.Edge for xid, u := range g.lines { for yid, lines := range u { if yid < xid { // Do not consider lines when the To node ID is // before the From node ID. Both orientations // are stored. continue } if len(lines) == 0 { continue } edges = append(edges, WeightedEdge{ F: g.Node(xid), T: g.Node(yid), WeightedLines: iterator.NewWeightedLines(lines), WeightFunc: g.EdgeWeightFunc, }) } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedEdges(edges) } // From returns all nodes in g that can be reached directly from n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes { if len(g.lines[id]) == 0 { return graph.Empty } return iterator.NewNodesByWeightedLines(g.nodes, g.lines[id]) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool { _, ok := g.lines[xid][yid] return ok } // Lines returns the lines 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 *WeightedUndirectedGraph) Lines(uid, vid int64) graph.Lines { return g.LinesBetween(uid, vid) } // LinesBetween returns the lines between nodes x and y. func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) graph.Lines { if !g.HasEdgeBetween(xid, yid) { return graph.Empty } var lines []graph.Line for _, l := range g.lines[xid][yid] { if l.From().ID() != xid { l = l.ReversedLine().(graph.WeightedLine) } lines = append(lines, l) } return iterator.NewOrderedLines(lines) } // 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 *WeightedUndirectedGraph) 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()) } // NewWeightedLine returns a new WeightedLine from the source to the destination node. // The returned WeightedLine will have a graph-unique ID. // The Line's ID does not become valid in g until the Line is added to g. func (g *WeightedUndirectedGraph) NewWeightedLine(from, to graph.Node, weight float64) graph.WeightedLine { xid := from.ID() yid := to.ID() if yid < xid { xid, yid = yid, xid } var lineID int64 switch { case g.lineIDs[xid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[xid] = map[int64]*uid.Set{yid: uids} case g.lineIDs[xid][yid] == nil: uids := uid.NewSet() lineID = uids.NewID() g.lineIDs[xid][yid] = uids default: lineID = g.lineIDs[xid][yid].NewID() } return WeightedLine{F: from, T: to, W: weight, UID: lineID} } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *WeightedUndirectedGraph) Node(id int64) graph.Node { return g.nodes[id] } // Nodes returns all the nodes in the graph. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedUndirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *WeightedUndirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // RemoveLine removes the line with the given end point and line IDs from the graph, // leaving the terminal nodes. If the line does not exist it is a no-op. func (g *WeightedUndirectedGraph) RemoveLine(fid, tid, id int64) { if _, ok := g.nodes[fid]; !ok { return } if _, ok := g.nodes[tid]; !ok { return } delete(g.lines[fid][tid], id) if len(g.lines[fid][tid]) == 0 { delete(g.lines[fid], tid) } delete(g.lines[tid][fid], id) if len(g.lines[tid][fid]) == 0 { delete(g.lines[tid], fid) } xid := fid yid := tid if yid < xid { xid, yid = yid, xid } g.lineIDs[xid][yid].Release(id) } // 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 *WeightedUndirectedGraph) RemoveNode(id int64) { if _, ok := g.nodes[id]; !ok { return } delete(g.nodes, id) for from := range g.lines[id] { delete(g.lines[from], id) } delete(g.lines, id) g.nodeIDs.Release(id) } // SetWeightedLine adds l, a line from one node to another. If the nodes do not exist, they are added // and are set to the nodes of the line otherwise. func (g *WeightedUndirectedGraph) SetWeightedLine(l graph.WeightedLine) { var ( from = l.From() fid = from.ID() to = l.To() tid = to.ID() lid = l.ID() ) 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 } switch { case g.lines[fid] == nil: g.lines[fid] = map[int64]map[int64]graph.WeightedLine{tid: {lid: l}} case g.lines[fid][tid] == nil: g.lines[fid][tid] = map[int64]graph.WeightedLine{lid: l} default: g.lines[fid][tid][lid] = l } switch { case g.lines[tid] == nil: g.lines[tid] = map[int64]map[int64]graph.WeightedLine{fid: {lid: l}} case g.lines[tid][fid] == nil: g.lines[tid][fid] = map[int64]graph.WeightedLine{lid: l} default: g.lines[tid][fid][lid] = l } xid := fid yid := tid if yid < xid { xid, yid = yid, xid } switch { case g.lineIDs[xid] == nil: uids := uid.NewSet() g.lineIDs[xid] = map[int64]*uid.Set{yid: uids} case g.lineIDs[xid][yid] == nil: uids := uid.NewSet() g.lineIDs[xid][yid] = uids } g.lineIDs[xid][yid].Use(lid) } // Weight returns the weight for the lines between x and y summarised by the receiver's // EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise. func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) { lines := g.WeightedLines(xid, yid) return WeightedEdge{WeightedLines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), lines != graph.Empty } // 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. // The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists. func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge { lines := g.WeightedLines(uid, vid) if lines == graph.Empty { return nil } return WeightedEdge{ F: g.Node(uid), T: g.Node(vid), WeightedLines: lines, WeightFunc: g.EdgeWeightFunc, } } // WeightedEdgeBetween returns the weighted edge between nodes x and y. func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge { return g.WeightedEdge(xid, yid) } // WeightedEdges returns all the edges in the graph. Each edge in the returned slice // is a multi.WeightedEdge. // // The returned graph.WeightedEdges is only valid until the next mutation of // the receiver. func (g *WeightedUndirectedGraph) WeightedEdges() graph.WeightedEdges { if len(g.lines) == 0 { return graph.Empty } var edges []graph.WeightedEdge for xid, u := range g.lines { for yid, lines := range u { if yid < xid { // Do not consider lines when the To node ID is // before the From node ID. Both orientations // are stored. continue } if len(lines) == 0 { continue } edges = append(edges, WeightedEdge{ F: g.Node(xid), T: g.Node(yid), WeightedLines: iterator.NewWeightedLines(lines), WeightFunc: g.EdgeWeightFunc, }) } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedWeightedEdges(edges) } // WeightedLines returns the lines 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 *WeightedUndirectedGraph) WeightedLines(uid, vid int64) graph.WeightedLines { return g.WeightedLinesBetween(uid, vid) } // WeightedLinesBetween returns the lines between nodes x and y. func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) graph.WeightedLines { if !g.HasEdgeBetween(xid, yid) { return graph.Empty } var lines []graph.WeightedLine for _, l := range g.lines[xid][yid] { if l.From().ID() != xid { l = l.ReversedLine().(graph.WeightedLine) } lines = append(lines, l) } return iterator.NewOrderedWeightedLines(lines) } golang-gonum-v1-gonum-0.14.0/graph/multi/weighted_undirected_test.go000066400000000000000000000120751450372207100254720ustar00rootroot00000000000000// 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 multi_test import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/testgraph" ) func weightedUndirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() ug := multi.NewWeightedUndirectedGraph() ug.EdgeWeightFunc = func(l graph.WeightedLines) float64 { if l.Len() == 0 { return absent } var w float64 for l.Next() { w += l.WeightedLine().Weight() } l.Reset() return w } for _, n := range nodes { seen.Add(n) ug.AddNode(n) } for _, edge := range edges { f := ug.Node(edge.From().ID()) if f == nil { f = edge.From() } t := ug.Node(edge.To().ID()) if t == nil { t = edge.To() } cl := multi.WeightedLine{F: f, T: t, UID: edge.ID(), W: edge.Weight()} seen.Add(cl.F) seen.Add(cl.T) e = append(e, cl) ug.SetWeightedLine(cl) } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return ug, n, e, self, absent, true } func TestWeightedUndirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, weightedUndirectedBuilder, reversesEdges) }) t.Run("LineExistence", func(t *testing.T) { testgraph.LineExistence(t, weightedUndirectedBuilder, usesEmpty, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, weightedUndirectedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, weightedUndirectedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllLines", func(t *testing.T) { testgraph.ReturnAllLines(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnAllWeightedLines", func(t *testing.T) { testgraph.ReturnAllWeightedLines(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, weightedUndirectedBuilder) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, multi.NewWeightedUndirectedGraph(), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, multi.NewWeightedUndirectedGraph(), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }), ) }) t.Run("RemoveNodes", func(t *testing.T) { g := multi.NewWeightedUndirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- g.SetWeightedLine(g.NewWeightedLine(u, v, 1)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddWeightedLines", func(t *testing.T) { testgraph.AddWeightedLines(t, 100, multi.NewWeightedUndirectedGraph(), 0.5, func(id int64) graph.Node { return multi.Node(id) }, true, // Can update nodes. ) }) t.Run("RemoveLines", func(t *testing.T) { g := multi.NewWeightedUndirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() var lines []graph.Line rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() d-- l := g.NewWeightedLine(u, v, 1) g.SetWeightedLine(l) lines = append(lines, l) } } rnd.Shuffle(len(lines), func(i, j int) { lines[i], lines[j] = lines[j], lines[i] }) testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines)) }) } func TestWeightedMaxID(t *testing.T) { g := multi.NewWeightedUndirectedGraph() nodes := make(map[graph.Node]struct{}) for i := multi.Node(0); i < 3; i++ { g.AddNode(i) nodes[i] = struct{}{} } g.RemoveNode(int64(0)) delete(nodes, multi.Node(0)) g.RemoveNode(int64(2)) delete(nodes, multi.Node(2)) n := g.NewNode() g.AddNode(n) if g.Node(n.ID()) == nil { t.Error("added node does not exist in graph") } if _, exists := nodes[n]; exists { t.Errorf("Created already existing node id: %v", n.ID()) } } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123WeightedUndirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := multi.NewWeightedUndirectedGraph() n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/multigraph.go000066400000000000000000000134101450372207100214410ustar00rootroot00000000000000// 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 the edge reversal of the receiver // if a reversal is valid for the data type. // When a reversal is valid an edge of the same type as // the receiver with nodes of the receiver swapped should // be returned, otherwise the receiver should be returned // unaltered. 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 } // UndirectedMultigraphBuilder 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 } golang-gonum-v1-gonum-0.14.0/graph/network/000077500000000000000000000000001450372207100204305ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/network/betweenness.go000066400000000000000000000162311450372207100233040ustar00rootroot00000000000000// 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 network import ( "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/linear" "gonum.org/v1/gonum/graph/path" ) // Betweenness returns the non-zero betweenness centrality for nodes in the unweighted graph g. // // C_B(v) = \sum_{s ≠ v ≠ t ∈ V} (\sigma_{st}(v) / \sigma_{st}) // // where \sigma_{st} and \sigma_{st}(v) are the number of shortest paths from s to t, // and the subset of those paths containing v respectively. func Betweenness(g graph.Graph) map[int64]float64 { // Brandes' algorithm for finding betweenness centrality for nodes in // and unweighted graph: // // http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf // TODO(kortschak): Consider using the parallel algorithm when // GOMAXPROCS != 1. // // http://htor.inf.ethz.ch/publications/img/edmonds-hoefler-lumsdaine-bc.pdf // Also note special case for sparse networks: // http://wwwold.iit.cnr.it/staff/marco.pellegrini/papiri/asonam-final.pdf cb := make(map[int64]float64) brandes(g, func(s graph.Node, stack linear.NodeStack, p map[int64][]graph.Node, delta, sigma map[int64]float64) { for stack.Len() != 0 { w := stack.Pop() for _, v := range p[w.ID()] { delta[v.ID()] += sigma[v.ID()] / sigma[w.ID()] * (1 + delta[w.ID()]) } if w.ID() != s.ID() { if d := delta[w.ID()]; d != 0 { cb[w.ID()] += d } } } }) return cb } // EdgeBetweenness returns the non-zero betweenness centrality for edges in the // unweighted graph g. For an edge e the centrality C_B is computed as // // C_B(e) = \sum_{s ≠ t ∈ V} (\sigma_{st}(e) / \sigma_{st}), // // where \sigma_{st} and \sigma_{st}(e) are the number of shortest paths from s // to t, and the subset of those paths containing e, respectively. // // If g is undirected, edges are retained such that u.ID < v.ID where u and v are // the nodes of e. func EdgeBetweenness(g graph.Graph) map[[2]int64]float64 { // Modified from Brandes' original algorithm as described in Algorithm 7 // with the exception that node betweenness is not calculated: // // http://algo.uni-konstanz.de/publications/b-vspbc-08.pdf _, isUndirected := g.(graph.Undirected) cb := make(map[[2]int64]float64) brandes(g, func(s graph.Node, stack linear.NodeStack, p map[int64][]graph.Node, delta, sigma map[int64]float64) { for stack.Len() != 0 { w := stack.Pop() for _, v := range p[w.ID()] { c := sigma[v.ID()] / sigma[w.ID()] * (1 + delta[w.ID()]) vid := v.ID() wid := w.ID() if isUndirected && wid < vid { vid, wid = wid, vid } cb[[2]int64{vid, wid}] += c delta[v.ID()] += c } } }) return cb } // brandes is the common code for Betweenness and EdgeBetweenness. It corresponds // to algorithm 1 in http://algo.uni-konstanz.de/publications/b-vspbc-08.pdf with // the accumulation loop provided by the accumulate closure. func brandes(g graph.Graph, accumulate func(s graph.Node, stack linear.NodeStack, p map[int64][]graph.Node, delta, sigma map[int64]float64)) { var ( nodes = graph.NodesOf(g.Nodes()) stack linear.NodeStack p = make(map[int64][]graph.Node, len(nodes)) sigma = make(map[int64]float64, len(nodes)) d = make(map[int64]int, len(nodes)) delta = make(map[int64]float64, len(nodes)) queue linear.NodeQueue ) for _, s := range nodes { stack = stack[:0] for _, w := range nodes { p[w.ID()] = p[w.ID()][:0] } for _, t := range nodes { sigma[t.ID()] = 0 d[t.ID()] = -1 } sigma[s.ID()] = 1 d[s.ID()] = 0 queue.Enqueue(s) for queue.Len() != 0 { v := queue.Dequeue() vid := v.ID() stack.Push(v) to := g.From(vid) for to.Next() { w := to.Node() wid := w.ID() // w found for the first time? if d[wid] < 0 { queue.Enqueue(w) d[wid] = d[vid] + 1 } // shortest path to w via v? if d[wid] == d[vid]+1 { sigma[wid] += sigma[vid] p[wid] = append(p[wid], v) } } } for _, v := range nodes { delta[v.ID()] = 0 } // S returns vertices in order of non-increasing distance from s accumulate(s, stack, p, delta, sigma) } } // BetweennessWeighted returns the non-zero betweenness centrality for nodes in the weighted // graph g used to construct the given shortest paths. // // C_B(v) = \sum_{s ≠ v ≠ t ∈ V} (\sigma_{st}(v) / \sigma_{st}) // // where \sigma_{st} and \sigma_{st}(v) are the number of shortest paths from s to t, // and the subset of those paths containing v respectively. func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64 { cb := make(map[int64]float64) nodes := graph.NodesOf(g.Nodes()) for i, s := range nodes { sid := s.ID() for j, t := range nodes { if i == j { continue } tid := t.ID() d := p.Weight(sid, tid) if math.IsInf(d, 0) { continue } // If we have a unique path, don't do the // extra work needed to get all paths. path, _, unique := p.Between(sid, tid) if unique { for _, v := range path[1 : len(path)-1] { // For undirected graphs we double count // passage though nodes. This is consistent // with Brandes' algorithm's behaviour. cb[v.ID()]++ } continue } // Otherwise iterate over all paths. paths, _ := p.AllBetween(sid, tid) stFrac := 1 / float64(len(paths)) for _, path := range paths { for _, v := range path[1 : len(path)-1] { cb[v.ID()] += stFrac } } } } return cb } // EdgeBetweennessWeighted returns the non-zero betweenness centrality for edges in // the weighted graph g. For an edge e the centrality C_B is computed as // // C_B(e) = \sum_{s ≠ t ∈ V} (\sigma_{st}(e) / \sigma_{st}), // // where \sigma_{st} and \sigma_{st}(e) are the number of shortest paths from s // to t, and the subset of those paths containing e, respectively. // // If g is undirected, edges are retained such that u.ID < v.ID where u and v are // the nodes of e. func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]float64 { cb := make(map[[2]int64]float64) _, isUndirected := g.(graph.Undirected) nodes := graph.NodesOf(g.Nodes()) for i, s := range nodes { sid := s.ID() for j, t := range nodes { if i == j { continue } tid := t.ID() d := p.Weight(sid, tid) if math.IsInf(d, 0) { continue } // If we have a unique path, don't do the // extra work needed to get all paths. path, _, unique := p.Between(sid, tid) if unique { for k, v := range path[1:] { // For undirected graphs we double count // passage though edges. This is consistent // with Brandes' algorithm's behaviour. uid := path[k].ID() vid := v.ID() if isUndirected && vid < uid { uid, vid = vid, uid } cb[[2]int64{uid, vid}]++ } continue } // Otherwise iterate over all paths. paths, _ := p.AllBetween(sid, tid) stFrac := 1 / float64(len(paths)) for _, path := range paths { for k, v := range path[1:] { uid := path[k].ID() vid := v.ID() if isUndirected && vid < uid { uid, vid = vid, uid } cb[[2]int64{uid, vid}] += stFrac } } } } return cb } golang-gonum-v1-gonum-0.14.0/graph/network/betweenness_test.go000066400000000000000000000167661450372207100243600ustar00rootroot00000000000000// 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 network import ( "fmt" "math" "sort" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph/path" "gonum.org/v1/gonum/graph/simple" ) var betweennessTests = []struct { g []set wantTol float64 want map[int64]float64 wantEdges map[[2]int64]float64 }{ { // Example graph from http://en.wikipedia.org/wiki/File:PageRanks-Example.svg 16:17, 8 July 2009 g: []set{ A: nil, B: linksTo(C), C: linksTo(B), D: linksTo(A, B), E: linksTo(D, B, F), F: linksTo(B, E), G: linksTo(B, E), H: linksTo(B, E), I: linksTo(B, E), J: linksTo(E), K: linksTo(E), }, wantTol: 1e-1, want: map[int64]float64{ B: 32, D: 18, E: 48, }, wantEdges: map[[2]int64]float64{ {A, D}: 20, {B, C}: 20, {B, D}: 16, {B, E}: 12, {B, F}: 9, {B, G}: 9, {B, H}: 9, {B, I}: 9, {D, E}: 20, {E, F}: 11, {E, G}: 11, {E, H}: 11, {E, I}: 11, {E, J}: 20, {E, K}: 20, }, }, { // Example graph from http://en.wikipedia.org/w/index.php?title=PageRank&oldid=659286279#Power_Method g: []set{ A: linksTo(B, C), B: linksTo(D), C: linksTo(D, E), D: linksTo(E), E: linksTo(A), }, wantTol: 1e-3, want: map[int64]float64{ A: 2, B: 0.6667, C: 0.6667, D: 2, E: 0.6667, }, wantEdges: map[[2]int64]float64{ {A, B}: 2 + 2/3. + 4/2., {A, C}: 2 + 2/3. + 2/2., {A, E}: 2 + 2/3. + 2/2., {B, D}: 2 + 2/3. + 4/2., {C, D}: 2 + 2/3. + 2/2., {C, E}: 2, {D, E}: 2 + 2/3. + 2/2., }, }, { g: []set{ A: linksTo(B), B: linksTo(C), C: nil, }, wantTol: 1e-3, want: map[int64]float64{ B: 2, }, wantEdges: map[[2]int64]float64{ {A, B}: 4, {B, C}: 4, }, }, { g: []set{ A: linksTo(B), B: linksTo(C), C: linksTo(D), D: linksTo(E), E: nil, }, wantTol: 1e-3, want: map[int64]float64{ B: 6, C: 8, D: 6, }, wantEdges: map[[2]int64]float64{ {A, B}: 8, {B, C}: 12, {C, D}: 12, {D, E}: 8, }, }, { g: []set{ A: linksTo(C), B: linksTo(C), C: nil, D: linksTo(C), E: linksTo(C), }, wantTol: 1e-3, want: map[int64]float64{ C: 12, }, wantEdges: map[[2]int64]float64{ {A, C}: 8, {B, C}: 8, {C, D}: 8, {C, E}: 8, }, }, { g: []set{ A: linksTo(B, C, D, E), B: linksTo(C, D, E), C: linksTo(D, E), D: linksTo(E), E: nil, }, wantTol: 1e-3, want: map[int64]float64{}, wantEdges: map[[2]int64]float64{ {A, B}: 2, {A, C}: 2, {A, D}: 2, {A, E}: 2, {B, C}: 2, {B, D}: 2, {B, E}: 2, {C, D}: 2, {C, E}: 2, {D, E}: 2, }, }, } func TestBetweenness(t *testing.T) { for i, test := range betweennessTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := Betweenness(g) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { wantN, gotOK := got[int64(n)] gotN, wantOK := test.want[int64(n)] if gotOK != wantOK { t.Errorf("unexpected betweenness result for test %d, node %c", i, n+'A') } if !scalar.EqualWithinAbsOrRel(gotN, wantN, test.wantTol, test.wantTol) { t.Errorf("unexpected betweenness result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } } func TestEdgeBetweenness(t *testing.T) { for i, test := range betweennessTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := EdgeBetweenness(g) prec := 1 - int(math.Log10(test.wantTol)) outer: for u := range test.g { for v := range test.g { wantQ, gotOK := got[[2]int64{int64(u), int64(v)}] gotQ, wantOK := test.wantEdges[[2]int64{int64(u), int64(v)}] if gotOK != wantOK { t.Errorf("unexpected betweenness result for test %d, edge (%c,%c)", i, u+'A', v+'A') } if !scalar.EqualWithinAbsOrRel(gotQ, wantQ, test.wantTol, test.wantTol) { t.Errorf("unexpected betweenness result for test %d:\ngot: %v\nwant:%v", i, orderedPairFloats(got, prec), orderedPairFloats(test.wantEdges, prec)) break outer } } } } } func TestBetweennessWeighted(t *testing.T) { for i, test := range betweennessTests { g := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } p, ok := path.FloydWarshall(g) if !ok { t.Errorf("unexpected negative cycle in test %d", i) continue } got := BetweennessWeighted(g, p) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { gotN, gotOK := got[int64(n)] wantN, wantOK := test.want[int64(n)] if gotOK != wantOK { t.Errorf("unexpected betweenness existence for test %d, node %c", i, n+'A') } if !scalar.EqualWithinAbsOrRel(gotN, wantN, test.wantTol, test.wantTol) { t.Errorf("unexpected betweenness result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } } func TestEdgeBetweennessWeighted(t *testing.T) { for i, test := range betweennessTests { g := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } p, ok := path.FloydWarshall(g) if !ok { t.Errorf("unexpected negative cycle in test %d", i) continue } got := EdgeBetweennessWeighted(g, p) prec := 1 - int(math.Log10(test.wantTol)) outer: for u := range test.g { for v := range test.g { wantQ, gotOK := got[[2]int64{int64(u), int64(v)}] gotQ, wantOK := test.wantEdges[[2]int64{int64(u), int64(v)}] if gotOK != wantOK { t.Errorf("unexpected betweenness result for test %d, edge (%c,%c)", i, u+'A', v+'A') } if !scalar.EqualWithinAbsOrRel(gotQ, wantQ, test.wantTol, test.wantTol) { t.Errorf("unexpected betweenness result for test %d:\ngot: %v\nwant:%v", i, orderedPairFloats(got, prec), orderedPairFloats(test.wantEdges, prec)) break outer } } } } } func orderedPairFloats(w map[[2]int64]float64, prec int) []pairKeyFloatVal { o := make(orderedPairFloatsMap, 0, len(w)) for k, v := range w { o = append(o, pairKeyFloatVal{prec: prec, key: k, val: v}) } sort.Sort(o) return o } type pairKeyFloatVal struct { prec int key [2]int64 val float64 } func (kv pairKeyFloatVal) String() string { return fmt.Sprintf("(%c,%c):%.*f", kv.key[0]+'A', kv.key[1]+'A', kv.prec, kv.val) } type orderedPairFloatsMap []pairKeyFloatVal func (o orderedPairFloatsMap) Len() int { return len(o) } func (o orderedPairFloatsMap) Less(i, j int) bool { return o[i].key[0] < o[j].key[0] || (o[i].key[0] == o[j].key[0] && o[i].key[1] < o[j].key[1]) } func (o orderedPairFloatsMap) Swap(i, j int) { o[i], o[j] = o[j], o[i] } golang-gonum-v1-gonum-0.14.0/graph/network/diffusion.go000066400000000000000000000054661450372207100227600ustar00rootroot00000000000000// 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 network import ( "gonum.org/v1/gonum/graph/spectral" "gonum.org/v1/gonum/mat" ) // Diffuse performs a heat diffusion across nodes of the undirected // graph described by the given Laplacian using the initial heat distribution, // h, according to the Laplacian with a diffusion time of t. // The resulting heat distribution is returned, written into the map dst and // returned, // // d = exp(-Lt)×h // // where L is the graph Laplacian. Indexing into h and dst is defined by the // Laplacian Index field. If dst is nil, a new map is created. // // Nodes without corresponding entries in h are given an initial heat of zero, // and entries in h without a corresponding node in the original graph are // not altered when written to dst. func Diffuse(dst, h map[int64]float64, by spectral.Laplacian, t float64) map[int64]float64 { heat := make([]float64, len(by.Index)) for id, i := range by.Index { heat[i] = h[id] } v := mat.NewVecDense(len(heat), heat) var m, tl mat.Dense tl.Scale(-t, by) m.Exp(&tl) v.MulVec(&m, v) if dst == nil { dst = make(map[int64]float64) } for i, n := range heat { dst[by.Nodes[i].ID()] = n } return dst } // DiffuseToEquilibrium performs a heat diffusion across nodes of the // graph described by the given Laplacian using the initial heat // distribution, h, according to the Laplacian until the update function // // h_{n+1} = h_n - L×h_n // // results in a 2-norm update difference within tol, or iters updates have // been made. // The resulting heat distribution is returned as eq, written into the map dst, // and a boolean indicating whether the equilibrium converged to within tol. // Indexing into h and dst is defined by the Laplacian Index field. If dst // is nil, a new map is created. // // Nodes without corresponding entries in h are given an initial heat of zero, // and entries in h without a corresponding node in the original graph are // not altered when written to dst. func DiffuseToEquilibrium(dst, h map[int64]float64, by spectral.Laplacian, tol float64, iters int) (eq map[int64]float64, ok bool) { heat := make([]float64, len(by.Index)) for id, i := range by.Index { heat[i] = h[id] } v := mat.NewVecDense(len(heat), heat) last := make([]float64, len(by.Index)) for id, i := range by.Index { last[i] = h[id] } lastV := mat.NewVecDense(len(last), last) var tmp mat.VecDense for { iters-- if iters < 0 { break } lastV, v = v, lastV tmp.MulVec(by.Matrix, lastV) v.SubVec(lastV, &tmp) if normDiff(heat, last) < tol { ok = true break } } if dst == nil { dst = make(map[int64]float64) } for i, n := range v.RawVector().Data { dst[by.Nodes[i].ID()] = n } return dst, ok } golang-gonum-v1-gonum-0.14.0/graph/network/diffusion_test.go000066400000000000000000000260521450372207100240110ustar00rootroot00000000000000// 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 network import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/spectral" ) var diffuseTests = []struct { g []set h map[int64]float64 t float64 wantTol float64 want map[bool]map[int64]float64 }{ { g: grid(5), h: map[int64]float64{0: 1}, t: 0.1, wantTol: 1e-9, want: map[bool]map[int64]float64{ false: { A: 0.826684055, B: 0.078548060, C: 0.003858840, D: 0.000127487, E: 0.000003233, F: 0.078548060, G: 0.007463308, H: 0.000366651, I: 0.000012113, J: 0.000000307, K: 0.003858840, L: 0.000366651, M: 0.000018012, N: 0.000000595, O: 0.000000015, P: 0.000127487, Q: 0.000012113, R: 0.000000595, S: 0.000000020, T: 0.000000000, U: 0.000003233, V: 0.000000307, W: 0.000000015, X: 0.000000000, Y: 0.000000000, }, true: { A: 0.9063462486, B: 0.0369774705, C: 0.0006161414, D: 0.0000068453, E: 0.0000000699, F: 0.0369774705, G: 0.0010670895, H: 0.0000148186, I: 0.0000001420, J: 0.0000000014, K: 0.0006161414, L: 0.0000148186, M: 0.0000001852, N: 0.0000000016, O: 0.0000000000, P: 0.0000068453, Q: 0.0000001420, R: 0.0000000016, S: 0.0000000000, T: 0.0000000000, U: 0.0000000699, V: 0.0000000014, W: 0.0000000000, X: 0.0000000000, Y: 0.0000000000, }, }, }, { g: grid(5), h: map[int64]float64{0: 1}, t: 1, wantTol: 1e-9, want: map[bool]map[int64]float64{ false: { A: 0.2743435076, B: 0.1615920872, C: 0.0639346641, D: 0.0188054933, E: 0.0051023569, F: 0.1615920872, G: 0.0951799548, H: 0.0376583937, I: 0.0110766934, J: 0.0030053582, K: 0.0639346641, L: 0.0376583937, M: 0.0148997194, N: 0.0043825455, O: 0.0011890840, P: 0.0188054933, Q: 0.0110766934, R: 0.0043825455, S: 0.0012890649, T: 0.0003497525, U: 0.0051023569, V: 0.0030053582, W: 0.0011890840, X: 0.0003497525, Y: 0.0000948958, }, true: { A: 0.4323917545, B: 0.1660487336, C: 0.0270298904, D: 0.0029720194, E: 0.0003007247, F: 0.1660487336, G: 0.0463974679, H: 0.0063556078, I: 0.0006056850, J: 0.0000589574, K: 0.0270298904, L: 0.0063556078, M: 0.0007860810, N: 0.0000691647, O: 0.0000065586, P: 0.0029720194, Q: 0.0006056850, R: 0.0000691647, S: 0.0000057466, T: 0.0000005475, U: 0.0003007247, V: 0.0000589574, W: 0.0000065586, X: 0.0000005475, Y: 0.0000000555, }, }, }, { g: grid(5), h: map[int64]float64{0: 1}, t: 10, wantTol: 1e-9, want: map[bool]map[int64]float64{ false: { A: 0.0432375924, B: 0.0426071834, C: 0.0415872351, D: 0.0405673794, E: 0.0399371202, F: 0.0426071834, G: 0.0419859658, H: 0.0409808885, I: 0.0399759024, J: 0.0393548325, K: 0.0415872351, L: 0.0409808885, M: 0.0399998711, N: 0.0390189428, O: 0.0384127403, P: 0.0405673794, Q: 0.0399759024, R: 0.0390189428, S: 0.0380620700, T: 0.0374707336, U: 0.0399371202, V: 0.0393548325, W: 0.0384127403, X: 0.0374707336, Y: 0.0368885843, }, true: { A: 0.0532814862, B: 0.0594280160, C: 0.0462076361, D: 0.0330529557, E: 0.0211688130, F: 0.0594280160, G: 0.0612529898, H: 0.0462850376, I: 0.0319891593, J: 0.0213123519, K: 0.0462076361, L: 0.0462850376, M: 0.0340410963, N: 0.0229646704, O: 0.0152763556, P: 0.0330529557, Q: 0.0319891593, R: 0.0229646704, S: 0.0153031853, T: 0.0103681461, U: 0.0211688130, V: 0.0213123519, W: 0.0152763556, X: 0.0103681461, Y: 0.0068893147, }, }, }, { g: grid(5), h: func() map[int64]float64 { m := make(map[int64]float64, 25) for i := int64(A); i <= Y; i++ { m[i] = 1 } return m }(), t: 1, // FIXME(kortschak): Low t used due to instability in mat.Exp. wantTol: 1e-1, // FIXME(kortschak): High tolerance used due to instability in mat.Exp. want: map[bool]map[int64]float64{ false: { A: 1, B: 1, C: 1, D: 1, E: 1, F: 1, G: 1, H: 1, I: 1, J: 1, K: 1, L: 1, M: 1, N: 1, O: 1, P: 1, Q: 1, R: 1, S: 1, T: 1, U: 1, V: 1, W: 1, X: 1, Y: 1, }, true: { // Output from the python implementation associated with doi:10.1371/journal.pcbi.1005598. A: 0.98264450473308107, B: 1.002568278028513, C: 0.9958911385307706, D: 1.002568278028513, E: 0.98264450473308107, F: 1.002568278028513, G: 1.0075291695232433, H: 1.0038067383118021, I: 1.0075291695232433, J: 1.002568278028513, K: 0.9958911385307706, L: 1.0038067383118021, M: 1.0001850837547184, N: 1.0038067383118021, O: 0.9958911385307706, P: 1.002568278028513, Q: 1.0075291695232433, R: 1.0038067383118021, S: 1.0075291695232433, T: 1.002568278028513, U: 0.98264450473308107, V: 1.002568278028513, W: 0.9958911385307706, X: 1.002568278028513, Y: 0.98264450473308107, }, }, }, { g: []set{ A: linksTo(B, C), B: linksTo(D), C: nil, D: nil, E: linksTo(F), F: nil, }, h: map[int64]float64{A: 1, E: 10}, t: 0.1, wantTol: 1e-9, want: map[bool]map[int64]float64{ false: { A: 0.8270754166, B: 0.0822899600, C: 0.0863904410, D: 0.0042441824, E: 9.0936537654, F: 0.9063462346, }, true: { A: 0.9082331512, B: 0.0453361743, C: 0.0640616812, D: 0.0016012085, E: 9.0936537654, F: 0.9063462346, }, }, }, } func TestDiffuse(t *testing.T) { for i, test := range diffuseTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } for j, lfn := range []func(g graph.Undirected) spectral.Laplacian{spectral.NewLaplacian, spectral.NewSymNormLaplacian} { normalize := j == 1 var wantTemp float64 for _, v := range test.h { wantTemp += v } got := Diffuse(nil, test.h, lfn(g), test.t) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.want[normalize][int64(n)], test.wantTol, test.wantTol) { t.Errorf("unexpected Diffuse result for test %d with normalize=%t:\ngot: %v\nwant:%v", i, normalize, orderedFloats(got, prec), orderedFloats(test.want[normalize], prec)) break } } if j == 1 { continue } var gotTemp float64 for _, v := range got { gotTemp += v } gotTemp /= float64(len(got)) wantTemp /= float64(len(got)) if !scalar.EqualWithinAbsOrRel(gotTemp, wantTemp, test.wantTol, test.wantTol) { t.Errorf("unexpected total heat for test %d with normalize=%t: got:%v want:%v", i, normalize, gotTemp, wantTemp) } } } } var diffuseToEquilibriumTests = []struct { g []set builder builder h map[int64]float64 damp float64 tol float64 iter int want map[int64]float64 wantOK bool }{ { g: grid(5), builder: simple.NewUndirectedGraph(), h: map[int64]float64{0: 1}, damp: 0.85, tol: 1e-6, iter: 1e4, want: map[int64]float64{ A: 0.025000, B: 0.037500, C: 0.037500, D: 0.037500, E: 0.025000, F: 0.037500, G: 0.050000, H: 0.050000, I: 0.050000, J: 0.037500, K: 0.037500, L: 0.050000, M: 0.050000, N: 0.050000, O: 0.037500, P: 0.037500, Q: 0.050000, R: 0.050000, S: 0.050000, T: 0.037500, U: 0.025000, V: 0.037500, W: 0.037500, X: 0.037500, Y: 0.025000, }, wantOK: true, }, { // Example graph from http://en.wikipedia.org/wiki/File:PageRanks-Example.svg 16:17, 8 July 2009 g: []set{ A: nil, B: linksTo(C), C: linksTo(B), D: linksTo(A, B), E: linksTo(D, B, F), F: linksTo(B, E), G: linksTo(B, E), H: linksTo(B, E), I: linksTo(B, E), J: linksTo(E), K: linksTo(E), }, builder: simple.NewDirectedGraph(), h: map[int64]float64{ A: 1. / 11., B: 1. / 11., C: 1. / 11., D: 1. / 11., E: 1. / 11., F: 1. / 11., G: 1. / 11., H: 1. / 11., I: 1. / 11., J: 1. / 11., K: 1. / 11., }, damp: 0.85, tol: 1e-6, iter: 1e4, // This does not look like Page Rank because we do not // do the random node hops. An alternative Laplacian // value that does do that would replicate PageRank. This // is left as an exercise for the reader. want: map[int64]float64{ A: 0.227273, B: 0.386364, C: 0.386364, D: 0.000000, E: 0.000000, F: 0.000000, G: 0.000000, H: 0.000000, I: 0.000000, J: 0.000000, K: 0.000000, }, wantOK: true, }, { g: []set{ A: linksTo(B, C), B: linksTo(D, C), C: nil, D: nil, E: linksTo(F), F: nil, }, builder: simple.NewDirectedGraph(), h: map[int64]float64{A: 1, E: -10}, tol: 1e-6, iter: 3, want: map[int64]float64{ A: 0, B: 0, C: 0.75, D: 0.25, E: 0, F: -10, }, wantOK: true, }, { g: []set{ A: linksTo(B, C), B: linksTo(D, C), C: nil, D: nil, E: linksTo(F), F: nil, }, builder: simple.NewUndirectedGraph(), h: map[int64]float64{A: 1, E: -10}, damp: 0.85, tol: 1e-6, iter: 1e4, want: map[int64]float64{ A: 0.25, B: 0.375, C: 0.25, D: 0.125, E: -5, F: -5, }, wantOK: true, }, { g: []set{ A: linksTo(B), B: linksTo(C), C: nil, }, builder: simple.NewUndirectedGraph(), h: map[int64]float64{B: 1}, iter: 1, tol: 1e-6, want: map[int64]float64{ A: 0.5, B: 0, C: 0.5, }, wantOK: false, }, { g: []set{ A: linksTo(B), B: linksTo(C), C: nil, }, builder: simple.NewUndirectedGraph(), h: map[int64]float64{B: 1}, iter: 2, tol: 1e-6, want: map[int64]float64{ A: 0, B: 1, C: 0, }, wantOK: false, }, } func TestDiffuseToEquilibrium(t *testing.T) { for i, test := range diffuseToEquilibriumTests { g := test.builder for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } var wantTemp float64 for _, v := range test.h { wantTemp += v } got, ok := DiffuseToEquilibrium(nil, test.h, spectral.NewRandomWalkLaplacian(g, test.damp), test.tol*test.tol, test.iter) if ok != test.wantOK { t.Errorf("unexpected success value for test %d: got:%t want:%t", i, ok, test.wantOK) } prec := -int(math.Log10(test.tol)) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.want[int64(n)], test.tol, test.tol) { t.Errorf("unexpected DiffuseToEquilibrium result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } var gotTemp float64 for _, v := range got { gotTemp += v } gotTemp /= float64(len(got)) wantTemp /= float64(len(got)) if !scalar.EqualWithinAbsOrRel(gotTemp, wantTemp, test.tol, test.tol) { t.Errorf("unexpected total heat for test %d: got:%v want:%v", i, gotTemp, wantTemp) } } } type builder interface { graph.Graph graph.Builder } func grid(d int) []set { dim := int64(d) s := make([]set, dim*dim) for i := range s { s[i] = make(set) } for i := int64(0); i < dim*dim; i++ { if i%dim != 0 { s[i][i-1] = struct{}{} } if i/dim != 0 { s[i][i-dim] = struct{}{} } } return s } golang-gonum-v1-gonum-0.14.0/graph/network/distance.go000066400000000000000000000063421450372207100225560ustar00rootroot00000000000000// 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 network import ( "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/path" ) // Closeness returns the closeness centrality for nodes in the graph g used to // construct the given shortest paths. // // C(v) = 1 / \sum_u d(u,v) // // For directed graphs the incoming paths are used. Infinite distances are // not considered. func Closeness(g graph.Graph, p path.AllShortest) map[int64]float64 { nodes := graph.NodesOf(g.Nodes()) c := make(map[int64]float64, len(nodes)) for _, u := range nodes { uid := u.ID() var sum float64 for _, v := range nodes { vid := v.ID() // The ordering here is not relevant for // undirected graphs, but we make sure we // are counting incoming paths. d := p.Weight(vid, uid) if math.IsInf(d, 0) { continue } sum += d } c[u.ID()] = 1 / sum } return c } // Farness returns the farness for nodes in the graph g used to construct // the given shortest paths. // // F(v) = \sum_u d(u,v) // // For directed graphs the incoming paths are used. Infinite distances are // not considered. func Farness(g graph.Graph, p path.AllShortest) map[int64]float64 { nodes := graph.NodesOf(g.Nodes()) f := make(map[int64]float64, len(nodes)) for _, u := range nodes { uid := u.ID() var sum float64 for _, v := range nodes { vid := v.ID() // The ordering here is not relevant for // undirected graphs, but we make sure we // are counting incoming paths. d := p.Weight(vid, uid) if math.IsInf(d, 0) { continue } sum += d } f[u.ID()] = sum } return f } // Harmonic returns the harmonic centrality for nodes in the graph g used to // construct the given shortest paths. // // H(v)= \sum_{u ≠ v} 1 / d(u,v) // // For directed graphs the incoming paths are used. Infinite distances are // not considered. func Harmonic(g graph.Graph, p path.AllShortest) map[int64]float64 { nodes := graph.NodesOf(g.Nodes()) h := make(map[int64]float64, len(nodes)) for i, u := range nodes { uid := u.ID() var sum float64 for j, v := range nodes { vid := v.ID() // The ordering here is not relevant for // undirected graphs, but we make sure we // are counting incoming paths. d := p.Weight(vid, uid) if math.IsInf(d, 0) { continue } if i != j { sum += 1 / d } } h[u.ID()] = sum } return h } // Residual returns the Dangalchev's residual closeness for nodes in the graph // g used to construct the given shortest paths. // // C(v)= \sum_{u ≠ v} 1 / 2^d(u,v) // // For directed graphs the incoming paths are used. Infinite distances are // not considered. func Residual(g graph.Graph, p path.AllShortest) map[int64]float64 { nodes := graph.NodesOf(g.Nodes()) r := make(map[int64]float64, len(nodes)) for i, u := range nodes { uid := u.ID() var sum float64 for j, v := range nodes { vid := v.ID() // The ordering here is not relevant for // undirected graphs, but we make sure we // are counting incoming paths. d := p.Weight(vid, uid) if math.IsInf(d, 0) { continue } if i != j { sum += math.Exp2(-d) } } r[u.ID()] = sum } return r } golang-gonum-v1-gonum-0.14.0/graph/network/distance_test.go000066400000000000000000000220641450372207100236140ustar00rootroot00000000000000// 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 network import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph/path" "gonum.org/v1/gonum/graph/simple" ) var undirectedCentralityTests = []struct { g []set farness map[int64]float64 harmonic map[int64]float64 residual map[int64]float64 }{ { g: []set{ A: linksTo(B), B: linksTo(C), C: nil, }, farness: map[int64]float64{ A: 1 + 2, B: 1 + 1, C: 2 + 1, }, harmonic: map[int64]float64{ A: 1 + 1.0/2.0, B: 1 + 1, C: 1.0/2.0 + 1, }, residual: map[int64]float64{ A: 1/math.Exp2(1) + 1/math.Exp2(2), B: 1/math.Exp2(1) + 1/math.Exp2(1), C: 1/math.Exp2(2) + 1/math.Exp2(1), }, }, { g: []set{ A: linksTo(B), B: linksTo(C), C: linksTo(D), D: linksTo(E), E: nil, }, farness: map[int64]float64{ A: 1 + 2 + 3 + 4, B: 1 + 1 + 2 + 3, C: 2 + 1 + 1 + 2, D: 3 + 2 + 1 + 1, E: 4 + 3 + 2 + 1, }, harmonic: map[int64]float64{ A: 1 + 1.0/2.0 + 1.0/3.0 + 1.0/4.0, B: 1 + 1 + 1.0/2.0 + 1.0/3.0, C: 1.0/2.0 + 1 + 1 + 1.0/2.0, D: 1.0/3.0 + 1.0/2.0 + 1 + 1, E: 1.0/4.0 + 1.0/3.0 + 1.0/2.0 + 1, }, residual: map[int64]float64{ A: 1/math.Exp2(1) + 1/math.Exp2(2) + 1/math.Exp2(3) + 1/math.Exp2(4), B: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(2) + 1/math.Exp2(3), C: 1/math.Exp2(2) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(2), D: 1/math.Exp2(3) + 1/math.Exp2(2) + 1/math.Exp2(1) + 1/math.Exp2(1), E: 1/math.Exp2(4) + 1/math.Exp2(3) + 1/math.Exp2(2) + 1/math.Exp2(1), }, }, { g: []set{ A: linksTo(C), B: linksTo(C), C: nil, D: linksTo(C), E: linksTo(C), }, farness: map[int64]float64{ A: 2 + 2 + 1 + 2, B: 2 + 1 + 2 + 2, C: 1 + 1 + 1 + 1, D: 2 + 1 + 2 + 2, E: 2 + 2 + 1 + 2, }, harmonic: map[int64]float64{ A: 1.0/2.0 + 1.0/2.0 + 1 + 1.0/2.0, B: 1.0/2.0 + 1 + 1.0/2.0 + 1.0/2.0, C: 1 + 1 + 1 + 1, D: 1.0/2.0 + 1 + 1.0/2.0 + 1.0/2.0, E: 1.0/2.0 + 1.0/2.0 + 1 + 1.0/2.0, }, residual: map[int64]float64{ A: 1/math.Exp2(2) + 1/math.Exp2(2) + 1/math.Exp2(1) + 1/math.Exp2(2), B: 1/math.Exp2(2) + 1/math.Exp2(1) + 1/math.Exp2(2) + 1/math.Exp2(2), C: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), D: 1/math.Exp2(2) + 1/math.Exp2(1) + 1/math.Exp2(2) + 1/math.Exp2(2), E: 1/math.Exp2(2) + 1/math.Exp2(2) + 1/math.Exp2(1) + 1/math.Exp2(2), }, }, { g: []set{ A: linksTo(B, C, D, E), B: linksTo(C, D, E), C: linksTo(D, E), D: linksTo(E), E: nil, }, farness: map[int64]float64{ A: 1 + 1 + 1 + 1, B: 1 + 1 + 1 + 1, C: 1 + 1 + 1 + 1, D: 1 + 1 + 1 + 1, E: 1 + 1 + 1 + 1, }, harmonic: map[int64]float64{ A: 1 + 1 + 1 + 1, B: 1 + 1 + 1 + 1, C: 1 + 1 + 1 + 1, D: 1 + 1 + 1 + 1, E: 1 + 1 + 1 + 1, }, residual: map[int64]float64{ A: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), B: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), C: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), D: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), E: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), }, }, } func TestDistanceCentralityUndirected(t *testing.T) { const tol = 1e-12 prec := 1 - int(math.Log10(tol)) for i, test := range undirectedCentralityTests { g := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } p, ok := path.FloydWarshall(g) if !ok { t.Errorf("unexpected negative cycle in test %d", i) continue } var got map[int64]float64 got = Closeness(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], 1/test.farness[int64(n)], tol, tol) { want := make(map[int64]float64) for n, v := range test.farness { want[n] = 1 / v } t.Errorf("unexpected closeness centrality for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(want, prec)) break } } got = Farness(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.farness[int64(n)], tol, tol) { t.Errorf("unexpected farness for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.farness, prec)) break } } got = Harmonic(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.harmonic[int64(n)], tol, tol) { t.Errorf("unexpected harmonic centrality for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.harmonic, prec)) break } } got = Residual(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.residual[int64(n)], tol, tol) { t.Errorf("unexpected residual closeness for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.residual, prec)) break } } } } var directedCentralityTests = []struct { g []set farness map[int64]float64 harmonic map[int64]float64 residual map[int64]float64 }{ { g: []set{ A: linksTo(B), B: linksTo(C), C: nil, }, farness: map[int64]float64{ A: 0, B: 1, C: 2 + 1, }, harmonic: map[int64]float64{ A: 0, B: 1, C: 1.0/2.0 + 1, }, residual: map[int64]float64{ A: 0, B: 1 / math.Exp2(1), C: 1/math.Exp2(2) + 1/math.Exp2(1), }, }, { g: []set{ A: linksTo(B), B: linksTo(C), C: linksTo(D), D: linksTo(E), E: nil, }, farness: map[int64]float64{ A: 0, B: 1, C: 2 + 1, D: 3 + 2 + 1, E: 4 + 3 + 2 + 1, }, harmonic: map[int64]float64{ A: 0, B: 1, C: 1.0/2.0 + 1, D: 1.0/3.0 + 1.0/2.0 + 1, E: 1.0/4.0 + 1.0/3.0 + 1.0/2.0 + 1, }, residual: map[int64]float64{ A: 0, B: 1 / math.Exp2(1), C: 1/math.Exp2(2) + 1/math.Exp2(1), D: 1/math.Exp2(3) + 1/math.Exp2(2) + 1/math.Exp2(1), E: 1/math.Exp2(4) + 1/math.Exp2(3) + 1/math.Exp2(2) + 1/math.Exp2(1), }, }, { g: []set{ A: linksTo(C), B: linksTo(C), C: nil, D: linksTo(C), E: linksTo(C), }, farness: map[int64]float64{ A: 0, B: 0, C: 1 + 1 + 1 + 1, D: 0, E: 0, }, harmonic: map[int64]float64{ A: 0, B: 0, C: 1 + 1 + 1 + 1, D: 0, E: 0, }, residual: map[int64]float64{ A: 0, B: 0, C: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), D: 0, E: 0, }, }, { g: []set{ A: linksTo(B, C, D, E), B: linksTo(C, D, E), C: linksTo(D, E), D: linksTo(E), E: nil, }, farness: map[int64]float64{ A: 0, B: 1, C: 1 + 1, D: 1 + 1 + 1, E: 1 + 1 + 1 + 1, }, harmonic: map[int64]float64{ A: 0, B: 1, C: 1 + 1, D: 1 + 1 + 1, E: 1 + 1 + 1 + 1, }, residual: map[int64]float64{ A: 0, B: 1 / math.Exp2(1), C: 1/math.Exp2(1) + 1/math.Exp2(1), D: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), E: 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1) + 1/math.Exp2(1), }, }, } func TestDistanceCentralityDirected(t *testing.T) { const tol = 1e-12 prec := 1 - int(math.Log10(tol)) for i, test := range directedCentralityTests { g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1}) } } p, ok := path.FloydWarshall(g) if !ok { t.Errorf("unexpected negative cycle in test %d", i) continue } var got map[int64]float64 got = Closeness(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], 1/test.farness[int64(n)], tol, tol) { want := make(map[int64]float64) for n, v := range test.farness { want[n] = 1 / v } t.Errorf("unexpected closeness centrality for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(want, prec)) break } } got = Farness(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.farness[int64(n)], tol, tol) { t.Errorf("unexpected farness for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.farness, prec)) break } } got = Harmonic(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.harmonic[int64(n)], tol, tol) { t.Errorf("unexpected harmonic centrality for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.harmonic, prec)) break } } got = Residual(g, p) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.residual[int64(n)], tol, tol) { t.Errorf("unexpected residual closeness for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.residual, prec)) break } } } } golang-gonum-v1-gonum-0.14.0/graph/network/doc.go000066400000000000000000000004321450372207100215230ustar00rootroot00000000000000// 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 network provides network analysis functions. package network // import "gonum.org/v1/gonum/graph/network" golang-gonum-v1-gonum-0.14.0/graph/network/hits.go000066400000000000000000000044771450372207100217420ustar00rootroot00000000000000// 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 network import ( "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/graph" ) // HubAuthority is a Hyperlink-Induced Topic Search hub-authority score pair. type HubAuthority struct { Hub float64 Authority float64 } // HITS returns the Hyperlink-Induced Topic Search hub-authority scores for // nodes of the directed graph g. HITS terminates when the 2-norm of the // vector difference between iterations is below tol. The returned map is // keyed on the graph node IDs. func HITS(g graph.Directed, tol float64) map[int64]HubAuthority { nodes := graph.NodesOf(g.Nodes()) // Make a topological copy of g with dense node IDs. indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { indexOf[n.ID()] = i } nodesLinkingTo := make([][]int, len(nodes)) nodesLinkedFrom := make([][]int, len(nodes)) for i, n := range nodes { id := n.ID() from := g.To(id) for from.Next() { u := from.Node() nodesLinkingTo[i] = append(nodesLinkingTo[i], indexOf[u.ID()]) } to := g.From(id) for to.Next() { v := to.Node() nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()]) } } w := make([]float64, 4*len(nodes)) auth := w[:len(nodes)] hub := w[len(nodes) : 2*len(nodes)] for i := range nodes { auth[i] = 1 hub[i] = 1 } deltaAuth := w[2*len(nodes) : 3*len(nodes)] deltaHub := w[3*len(nodes):] var norm float64 for { norm = 0 for v := range nodes { var a float64 for _, u := range nodesLinkingTo[v] { a += hub[u] } deltaAuth[v] = auth[v] auth[v] = a norm += a * a } norm = math.Sqrt(norm) for i := range auth { auth[i] /= norm deltaAuth[i] -= auth[i] } norm = 0 for u := range nodes { var h float64 for _, v := range nodesLinkedFrom[u] { h += auth[v] } deltaHub[u] = hub[u] hub[u] = h norm += h * h } norm = math.Sqrt(norm) for i := range hub { hub[i] /= norm deltaHub[i] -= hub[i] } if floats.Norm(deltaAuth, 2) < tol && floats.Norm(deltaHub, 2) < tol { break } } hubAuth := make(map[int64]HubAuthority, len(nodes)) for i, n := range nodes { hubAuth[n.ID()] = HubAuthority{Hub: hub[i], Authority: auth[i]} } return hubAuth } golang-gonum-v1-gonum-0.14.0/graph/network/hits_test.go000066400000000000000000000047071450372207100227750ustar00rootroot00000000000000// 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 network import ( "fmt" "math" "sort" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph/simple" ) var hitsTests = []struct { g []set tol float64 wantTol float64 want map[int64]HubAuthority }{ { // Example graph from http://www.cis.hut.fi/Opinnot/T-61.6020/2008/pagerank_hits.pdf page 8. g: []set{ A: linksTo(B, C, D), B: linksTo(C, D), C: linksTo(B), D: nil, }, tol: 1e-4, wantTol: 1e-4, want: map[int64]HubAuthority{ A: {Hub: 0.7887, Authority: 0}, B: {Hub: 0.5774, Authority: 0.4597}, C: {Hub: 0.2113, Authority: 0.6280}, D: {Hub: 0, Authority: 0.6280}, }, }, } func TestHITS(t *testing.T) { for i, test := range hitsTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := HITS(g, test.tol) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)].Hub, test.want[int64(n)].Hub, test.wantTol, test.wantTol) { t.Errorf("unexpected HITS result for test %d:\ngot: %v\nwant:%v", i, orderedHubAuth(got, prec), orderedHubAuth(test.want, prec)) break } if !scalar.EqualWithinAbsOrRel(got[int64(n)].Authority, test.want[int64(n)].Authority, test.wantTol, test.wantTol) { t.Errorf("unexpected HITS result for test %d:\ngot: %v\nwant:%v", i, orderedHubAuth(got, prec), orderedHubAuth(test.want, prec)) break } } } } func orderedHubAuth(w map[int64]HubAuthority, prec int) []keyHubAuthVal { o := make(orderedHubAuthMap, 0, len(w)) for k, v := range w { o = append(o, keyHubAuthVal{prec: prec, key: k, val: v}) } sort.Sort(o) return o } type keyHubAuthVal struct { prec int key int64 val HubAuthority } func (kv keyHubAuthVal) String() string { return fmt.Sprintf("%d:{H:%.*f, A:%.*f}", kv.key, kv.prec, kv.val.Hub, kv.prec, kv.val.Authority, ) } type orderedHubAuthMap []keyHubAuthVal func (o orderedHubAuthMap) Len() int { return len(o) } func (o orderedHubAuthMap) Less(i, j int) bool { return o[i].key < o[j].key } func (o orderedHubAuthMap) Swap(i, j int) { o[i], o[j] = o[j], o[i] } golang-gonum-v1-gonum-0.14.0/graph/network/network.go000066400000000000000000000007701450372207100224540ustar00rootroot00000000000000// 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. // TODO(kortschak): Implement: // * edge-weighted PageRank and HITS // * PersonalizedPageRank: // http://infolab.stanford.edu/~backrub/google.html 2.1.2 Intuitive Justification // http://ilpubs.stanford.edu:8090/596/1/2003-35.pdf // http://www.vldb.org/pvldb/vol7/p1023-maehara.pdf // * other centrality measures package network golang-gonum-v1-gonum-0.14.0/graph/network/network_test.go000066400000000000000000000007301450372207100235070ustar00rootroot00000000000000// 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 network const ( A = iota B C D E F G H I J K L M N O P Q R S T U V W X Y Z ) // set is an integer set. type set map[int64]struct{} func linksTo(i ...int64) set { if len(i) == 0 { return nil } s := make(set) for _, v := range i { s[v] = struct{}{} } return s } golang-gonum-v1-gonum-0.14.0/graph/network/page.go000066400000000000000000000256531450372207100217060ustar00rootroot00000000000000// 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 network import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/mat" ) // PageRank returns the PageRank weights for nodes of the directed graph g // using the given damping factor and terminating when the 2-norm of the // vector difference between iterations is below tol. The returned map is // keyed on the graph node IDs. // If g is a graph.WeightedDirected, an edge-weighted PageRank is calculated. func PageRank(g graph.Directed, damp, tol float64) map[int64]float64 { if g, ok := g.(graph.WeightedDirected); ok { return edgeWeightedPageRank(g, damp, tol) } return pageRank(g, damp, tol) } // PageRankSparse returns the PageRank weights for nodes of the sparse directed // graph g using the given damping factor and terminating when the 2-norm of the // vector difference between iterations is below tol. The returned map is // keyed on the graph node IDs. // If g is a graph.WeightedDirected, an edge-weighted PageRank is calculated. func PageRankSparse(g graph.Directed, damp, tol float64) map[int64]float64 { if g, ok := g.(graph.WeightedDirected); ok { return edgeWeightedPageRankSparse(g, damp, tol) } return pageRankSparse(g, damp, tol) } // edgeWeightedPageRank returns the PageRank weights for nodes of the weighted directed graph g // using the given damping factor and terminating when the 2-norm of the // vector difference between iterations is below tol. The returned map is // keyed on the graph node IDs. func edgeWeightedPageRank(g graph.WeightedDirected, damp, tol float64) map[int64]float64 { // edgeWeightedPageRank is implemented according to "How Google Finds Your Needle // in the Web's Haystack" with the modification that // the columns of hyperlink matrix H are calculated with edge weights. // // G.I^k = alpha.H.I^k + alpha.A.I^k + (1-alpha).1/n.1.I^k // // http://www.ams.org/samplings/feature-column/fcarc-pagerank nodes := graph.NodesOf(g.Nodes()) indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { indexOf[n.ID()] = i } m := mat.NewDense(len(nodes), len(nodes), nil) dangling := damp / float64(len(nodes)) for j, u := range nodes { to := graph.NodesOf(g.From(u.ID())) var z float64 for _, v := range to { if w, ok := g.Weight(u.ID(), v.ID()); ok { z += w } } if z != 0 { for _, v := range to { if w, ok := g.Weight(u.ID(), v.ID()); ok { m.Set(indexOf[v.ID()], j, (w*damp)/z) } } } else { for i := range nodes { m.Set(i, j, dangling) } } } matrix := m.RawMatrix().Data dt := (1 - damp) / float64(len(nodes)) for i := range matrix { matrix[i] += dt } last := make([]float64, len(nodes)) for i := range last { last[i] = 1 } lastV := mat.NewVecDense(len(nodes), last) vec := make([]float64, len(nodes)) var sum float64 for i := range vec { r := rand.NormFloat64() sum += r vec[i] = r } f := 1 / sum for i := range vec { vec[i] *= f } v := mat.NewVecDense(len(nodes), vec) for { lastV, v = v, lastV v.MulVec(m, lastV) if normDiff(vec, last) < tol { break } } ranks := make(map[int64]float64, len(nodes)) for i, r := range v.RawVector().Data { ranks[nodes[i].ID()] = r } return ranks } // edgeWeightedPageRankSparse returns the PageRank weights for nodes of the sparse weighted directed // graph g using the given damping factor and terminating when the 2-norm of the // vector difference between iterations is below tol. The returned map is // keyed on the graph node IDs. func edgeWeightedPageRankSparse(g graph.WeightedDirected, damp, tol float64) map[int64]float64 { // edgeWeightedPageRankSparse is implemented according to "How Google Finds Your Needle // in the Web's Haystack" with the modification that // the columns of hyperlink matrix H are calculated with edge weights. // // G.I^k = alpha.H.I^k + alpha.A.I^k + (1-alpha).1/n.1.I^k // // http://www.ams.org/samplings/feature-column/fcarc-pagerank nodes := graph.NodesOf(g.Nodes()) indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { indexOf[n.ID()] = i } m := make(rowCompressedMatrix, len(nodes)) var dangling compressedRow df := damp / float64(len(nodes)) for j, u := range nodes { to := graph.NodesOf(g.From(u.ID())) var z float64 for _, v := range to { if w, ok := g.Weight(u.ID(), v.ID()); ok { z += w } } if z != 0 { for _, v := range to { if w, ok := g.Weight(u.ID(), v.ID()); ok { m.addTo(indexOf[v.ID()], j, (w*damp)/z) } } } else { dangling.addTo(j, df) } } last := make([]float64, len(nodes)) for i := range last { last[i] = 1 } lastV := mat.NewVecDense(len(nodes), last) vec := make([]float64, len(nodes)) var sum float64 for i := range vec { r := rand.NormFloat64() sum += r vec[i] = r } f := 1 / sum for i := range vec { vec[i] *= f } v := mat.NewVecDense(len(nodes), vec) dt := (1 - damp) / float64(len(nodes)) for { lastV, v = v, lastV m.mulVecUnitary(v, lastV) // First term of the G matrix equation; with := dangling.dotUnitary(lastV) // Second term; away := onesDotUnitary(dt, lastV) // Last term. floats.AddConst(with+away, v.RawVector().Data) if normDiff(vec, last) < tol { break } } ranks := make(map[int64]float64, len(nodes)) for i, r := range v.RawVector().Data { ranks[nodes[i].ID()] = r } return ranks } // pageRank returns the PageRank weights for nodes of the directed graph g // using the given damping factor and terminating when the 2-norm of the // vector difference between iterations is below tol. The returned map is // keyed on the graph node IDs. func pageRank(g graph.Directed, damp, tol float64) map[int64]float64 { // pageRank is implemented according to "How Google Finds Your Needle // in the Web's Haystack". // // G.I^k = alpha.S.I^k + (1-alpha).1/n.1.I^k // // http://www.ams.org/samplings/feature-column/fcarc-pagerank nodes := graph.NodesOf(g.Nodes()) indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { indexOf[n.ID()] = i } m := mat.NewDense(len(nodes), len(nodes), nil) dangling := damp / float64(len(nodes)) for j, u := range nodes { to := graph.NodesOf(g.From(u.ID())) f := damp / float64(len(to)) for _, v := range to { m.Set(indexOf[v.ID()], j, f) } if len(to) == 0 { for i := range nodes { m.Set(i, j, dangling) } } } matrix := m.RawMatrix().Data dt := (1 - damp) / float64(len(nodes)) for i := range matrix { matrix[i] += dt } last := make([]float64, len(nodes)) for i := range last { last[i] = 1 } lastV := mat.NewVecDense(len(nodes), last) vec := make([]float64, len(nodes)) var sum float64 for i := range vec { r := rand.NormFloat64() sum += r vec[i] = r } f := 1 / sum for i := range vec { vec[i] *= f } v := mat.NewVecDense(len(nodes), vec) for { lastV, v = v, lastV v.MulVec(m, lastV) if normDiff(vec, last) < tol { break } } ranks := make(map[int64]float64, len(nodes)) for i, r := range v.RawVector().Data { ranks[nodes[i].ID()] = r } return ranks } // pageRankSparse returns the PageRank weights for nodes of the sparse directed // graph g using the given damping factor and terminating when the 2-norm of the // vector difference between iterations is below tol. The returned map is // keyed on the graph node IDs. func pageRankSparse(g graph.Directed, damp, tol float64) map[int64]float64 { // pageRankSparse is implemented according to "How Google Finds Your Needle // in the Web's Haystack". // // G.I^k = alpha.H.I^k + alpha.A.I^k + (1-alpha).1/n.1.I^k // // http://www.ams.org/samplings/feature-column/fcarc-pagerank nodes := graph.NodesOf(g.Nodes()) indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { indexOf[n.ID()] = i } m := make(rowCompressedMatrix, len(nodes)) var dangling compressedRow df := damp / float64(len(nodes)) for j, u := range nodes { to := graph.NodesOf(g.From(u.ID())) f := damp / float64(len(to)) for _, v := range to { m.addTo(indexOf[v.ID()], j, f) } if len(to) == 0 { dangling.addTo(j, df) } } last := make([]float64, len(nodes)) for i := range last { last[i] = 1 } lastV := mat.NewVecDense(len(nodes), last) vec := make([]float64, len(nodes)) var sum float64 for i := range vec { r := rand.NormFloat64() sum += r vec[i] = r } f := 1 / sum for i := range vec { vec[i] *= f } v := mat.NewVecDense(len(nodes), vec) dt := (1 - damp) / float64(len(nodes)) for { lastV, v = v, lastV m.mulVecUnitary(v, lastV) // First term of the G matrix equation; with := dangling.dotUnitary(lastV) // Second term; away := onesDotUnitary(dt, lastV) // Last term. floats.AddConst(with+away, v.RawVector().Data) if normDiff(vec, last) < tol { break } } ranks := make(map[int64]float64, len(nodes)) for i, r := range v.RawVector().Data { ranks[nodes[i].ID()] = r } return ranks } // rowCompressedMatrix implements row-compressed // matrix/vector multiplication. type rowCompressedMatrix []compressedRow // addTo adds the value v to the matrix element at (i,j). Repeated // calls to addTo with the same column index will result in // non-unique element representation. func (m rowCompressedMatrix) addTo(i, j int, v float64) { m[i].addTo(j, v) } // mulVecUnitary multiplies the receiver by the src vector, storing // the result in dst. It assumes src and dst are the same length as m // and that both have unitary vector increments. func (m rowCompressedMatrix) mulVecUnitary(dst, src *mat.VecDense) { dMat := dst.RawVector().Data for i, r := range m { dMat[i] = r.dotUnitary(src) } } // compressedRow implements a simplified scatter-based Ddot. type compressedRow []sparseElement // addTo adds the value v to the vector element at j. Repeated // calls to addTo with the same vector index will result in // non-unique element representation. func (r *compressedRow) addTo(j int, v float64) { *r = append(*r, sparseElement{index: j, value: v}) } // dotUnitary performs a simplified scatter-based Ddot operations on // v and the receiver. v must have a unitary vector increment. func (r compressedRow) dotUnitary(v *mat.VecDense) float64 { var sum float64 vec := v.RawVector().Data for _, e := range r { sum += vec[e.index] * e.value } return sum } // sparseElement is a sparse vector or matrix element. type sparseElement struct { index int value float64 } // onesDotUnitary performs the equivalent of a Ddot of v with // a ones vector of equal length. v must have a unitary vector // increment. func onesDotUnitary(alpha float64, v *mat.VecDense) float64 { var sum float64 for _, f := range v.RawVector().Data { sum += alpha * f } return sum } // normDiff returns the 2-norm of the difference between x and y. // This is a cut down version of gonum/floats.Distance. func normDiff(x, y []float64) float64 { var sum float64 for i, v := range x { d := v - y[i] sum += d * d } return math.Sqrt(sum) } golang-gonum-v1-gonum-0.14.0/graph/network/page_test.go000066400000000000000000000146661450372207100227470ustar00rootroot00000000000000// 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 network import ( "fmt" "math" "sort" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph/simple" ) var pageRankTests = []struct { g []set damp float64 tol float64 wantTol float64 want map[int64]float64 }{ { // Example graph from http://en.wikipedia.org/wiki/File:PageRanks-Example.svg 16:17, 8 July 2009 g: []set{ A: nil, B: linksTo(C), C: linksTo(B), D: linksTo(A, B), E: linksTo(D, B, F), F: linksTo(B, E), G: linksTo(B, E), H: linksTo(B, E), I: linksTo(B, E), J: linksTo(E), K: linksTo(E), }, damp: 0.85, tol: 1e-8, wantTol: 1e-8, want: map[int64]float64{ A: 0.03278149, B: 0.38440095, C: 0.34291029, D: 0.03908709, E: 0.08088569, F: 0.03908709, G: 0.01616948, H: 0.01616948, I: 0.01616948, J: 0.01616948, K: 0.01616948, }, }, { // Example graph from http://en.wikipedia.org/w/index.php?title=PageRank&oldid=659286279#Power_Method // Expected result calculated with the given MATLAB code. g: []set{ A: linksTo(B, C), B: linksTo(D), C: linksTo(D, E), D: linksTo(E), E: linksTo(A), }, damp: 0.80, tol: 1e-3, wantTol: 1e-3, want: map[int64]float64{ A: 0.250, B: 0.140, C: 0.140, D: 0.208, E: 0.262, }, }, } func TestPageRank(t *testing.T) { for i, test := range pageRankTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := pageRank(g, test.damp, test.tol) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.want[int64(n)], test.wantTol, test.wantTol) { t.Errorf("unexpected PageRank result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } } func TestPageRankSparse(t *testing.T) { for i, test := range pageRankTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := pageRankSparse(g, test.damp, test.tol) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.want[int64(n)], test.wantTol, test.wantTol) { t.Errorf("unexpected PageRank result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } } var edgeWeightedPageRankTests = []struct { g []set self, absent float64 edges map[int]map[int64]float64 damp float64 tol float64 wantTol float64 want map[int64]float64 }{ { // This test case is created according to the result with the following python code // on python 3.6.4 (using "networkx" of version 2.1) // // >>> import networkx as nx // >>> D = nx.DiGraph() // >>> D.add_weighted_edges_from([('A', 'B', 0.3), ('A','C', 1.2), ('B', 'A', 0.4), ('C', 'B', 0.3), ('D', 'A', 0.3), ('D', 'B', 2.1)]) // >>> nx.pagerank(D, alpha=0.85, tol=1e-10) // {'A': 0.3409109390701202, 'B': 0.3522682754411842, 'C': 0.2693207854886954, 'D': 0.037500000000000006} g: []set{ A: linksTo(B, C), B: linksTo(A), C: linksTo(B), D: linksTo(A, B), }, edges: map[int]map[int64]float64{ A: { B: 0.3, C: 1.2, }, B: { A: 0.4, }, C: { B: 0.3, }, D: { A: 0.3, B: 2.1, }, }, damp: 0.85, tol: 1e-10, wantTol: 1e-8, want: map[int64]float64{ A: 0.3409120160955594, B: 0.3522678129306601, C: 0.2693201709737804, D: 0.037500000000000006, }, }, } func TestEdgeWeightedPageRank(t *testing.T) { for i, test := range edgeWeightedPageRankTests { g := simple.NewWeightedDirectedGraph(test.self, test.absent) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } ws, ok := test.edges[u] if !ok { t.Errorf("edges not found for %v", u) } for v := range e { if w, ok := ws[v]; ok { g.SetWeightedEdge(g.NewWeightedEdge(simple.Node(u), simple.Node(v), w)) } } } got := edgeWeightedPageRank(g, test.damp, test.tol) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.want[int64(n)], test.wantTol, test.wantTol) { t.Errorf("unexpected PageRank result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } } func TestEdgeWeightedPageRankSparse(t *testing.T) { for i, test := range edgeWeightedPageRankTests { g := simple.NewWeightedDirectedGraph(test.self, test.absent) for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } ws, ok := test.edges[u] if !ok { t.Errorf("edges not found for %v", u) } for v := range e { if w, ok := ws[v]; ok { g.SetWeightedEdge(g.NewWeightedEdge(simple.Node(u), simple.Node(v), w)) } } } got := edgeWeightedPageRankSparse(g, test.damp, test.tol) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !scalar.EqualWithinAbsOrRel(got[int64(n)], test.want[int64(n)], test.wantTol, test.wantTol) { t.Errorf("unexpected PageRank result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } } func orderedFloats(w map[int64]float64, prec int) []keyFloatVal { o := make(orderedFloatsMap, 0, len(w)) for k, v := range w { o = append(o, keyFloatVal{prec: prec, key: k, val: v}) } sort.Sort(o) return o } type keyFloatVal struct { prec int key int64 val float64 } func (kv keyFloatVal) String() string { return fmt.Sprintf("%c:%.*f", kv.key+'A', kv.prec, kv.val) } type orderedFloatsMap []keyFloatVal func (o orderedFloatsMap) Len() int { return len(o) } func (o orderedFloatsMap) Less(i, j int) bool { return o[i].key < o[j].key } func (o orderedFloatsMap) Swap(i, j int) { o[i], o[j] = o[j], o[i] } golang-gonum-v1-gonum-0.14.0/graph/nodes_edges.go000066400000000000000000000174001450372207100215470ustar00rootroot00000000000000// 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. func NodesOf(it Nodes) []Node { if it == nil { return nil } n := it.Len() switch { case n == 0: return nil case n < 0: n = 0 } switch it := it.(type) { case NodeSlicer: return it.NodeSlice() } nodes := make([]Node, 0, n) for it.Next() { nodes = append(nodes, it.Node()) } if len(nodes) == 0 { return nil } return nodes } // 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. func EdgesOf(it Edges) []Edge { if it == nil { return nil } n := it.Len() switch { case n == 0: return nil case n < 0: n = 0 } switch it := it.(type) { case EdgeSlicer: return it.EdgeSlice() } edges := make([]Edge, 0, n) for it.Next() { edges = append(edges, it.Edge()) } if len(edges) == 0 { return nil } return edges } // 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. func WeightedEdgesOf(it WeightedEdges) []WeightedEdge { if it == nil { return nil } n := it.Len() switch { case n == 0: return nil case n < 0: n = 0 } switch it := it.(type) { case WeightedEdgeSlicer: return it.WeightedEdgeSlice() } edges := make([]WeightedEdge, 0, n) for it.Next() { edges = append(edges, it.WeightedEdge()) } if len(edges) == 0 { return nil } return edges } // 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. func LinesOf(it Lines) []Line { if it == nil { return nil } n := it.Len() switch { case n == 0: return nil case n < 0: n = 0 } switch it := it.(type) { case LineSlicer: return it.LineSlice() } lines := make([]Line, 0, n) for it.Next() { lines = append(lines, it.Line()) } if len(lines) == 0 { return nil } return lines } // 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. func WeightedLinesOf(it WeightedLines) []WeightedLine { if it == nil { return nil } n := it.Len() switch { case n == 0: return nil case n < 0: n = 0 } switch it := it.(type) { case WeightedLineSlicer: return it.WeightedLineSlice() } lines := make([]WeightedLine, 0, n) for it.Next() { lines = append(lines, it.WeightedLine()) } if len(lines) == 0 { return nil } return lines } // 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(0) type empty int 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 } func (empty) String() string { return "" } func (empty) GoString() string { return "graph.Empty" } golang-gonum-v1-gonum-0.14.0/graph/nodes_edges_test.go000066400000000000000000000205171450372207100226110ustar00rootroot00000000000000// Copyright ©2019 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_test import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/multi" "gonum.org/v1/gonum/graph/simple" ) // nodes // edges // weightededges // lines // weightedlines // empty type basicNodes struct { graph.Nodes } func TestNodesOf(t *testing.T) { nodesOfTests := []struct { name string nodes graph.Nodes want []graph.Node }{ { name: "nil", nodes: nil, want: nil, }, { name: "empty", nodes: graph.Empty, want: nil, }, { name: "no nodes", nodes: iterator.NewOrderedNodes(nil), want: nil, }, { name: "implicit nodes", nodes: iterator.NewImplicitNodes(-1, 4, func(id int) graph.Node { return simple.Node(id) }), want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, }, { name: "no slice method", nodes: basicNodes{iterator.NewOrderedNodes([]graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)})}, want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, }, { name: "explicit nodes", nodes: iterator.NewOrderedNodes([]graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}), want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, }, } for _, test := range nodesOfTests { got := graph.NodesOf(test.nodes) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %q: got:%v want:%v", test.name, got, test.want) } } } type basicEdges struct { graph.Edges } func TestEdgesOf(t *testing.T) { edgesOfTests := []struct { name string edges graph.Edges want []graph.Edge }{ { name: "nil", edges: nil, want: nil, }, { name: "empty", edges: graph.Empty, want: nil, }, { name: "no edges", edges: iterator.NewOrderedEdges(nil), want: nil, }, { name: "no slice method", edges: basicEdges{iterator.NewOrderedEdges([]graph.Edge{ simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(3), T: simple.Node(4)}, })}, want: []graph.Edge{ simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(3), T: simple.Node(4)}, }, }, { name: "explicit edges", edges: iterator.NewOrderedEdges([]graph.Edge{ simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(3), T: simple.Node(4)}, }), want: []graph.Edge{ simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(3), T: simple.Node(4)}, }, }, } for _, test := range edgesOfTests { got := graph.EdgesOf(test.edges) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %q: got:%v want:%v", test.name, got, test.want) } } } type basicWeightedEdges struct { graph.WeightedEdges } func TestWeightedEdgesOf(t *testing.T) { weightedEdgesOfTests := []struct { name string edges graph.WeightedEdges want []graph.WeightedEdge }{ { name: "nil", edges: nil, want: nil, }, { name: "empty", edges: graph.Empty, want: nil, }, { name: "no edges", edges: iterator.NewOrderedWeightedEdges(nil), want: nil, }, { name: "no slice method", edges: basicWeightedEdges{iterator.NewOrderedWeightedEdges([]graph.WeightedEdge{ simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, })}, want: []graph.WeightedEdge{ simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, }, }, { name: "explicit edges", edges: iterator.NewOrderedWeightedEdges([]graph.WeightedEdge{ simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, }), want: []graph.WeightedEdge{ simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, }, }, } for _, test := range weightedEdgesOfTests { got := graph.WeightedEdgesOf(test.edges) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %q: got:%v want:%v", test.name, got, test.want) } } } type basicLines struct { graph.Lines } func TestLinesOf(t *testing.T) { linesOfTests := []struct { name string lines graph.Lines want []graph.Line }{ { name: "nil", lines: nil, want: nil, }, { name: "empty", lines: graph.Empty, want: nil, }, { name: "no edges", lines: iterator.NewOrderedLines(nil), want: nil, }, { name: "no slice method", lines: basicLines{iterator.NewOrderedLines([]graph.Line{ multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, })}, want: []graph.Line{ multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, }, }, { name: "explicit edges", lines: iterator.NewOrderedLines([]graph.Line{ multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, }), want: []graph.Line{ multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, }, }, } for _, test := range linesOfTests { got := graph.LinesOf(test.lines) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %q: got:%v want:%v", test.name, got, test.want) } } } type basicWeightedLines struct { graph.WeightedLines } func TestWeightedLinesOf(t *testing.T) { weightedLinesOfTests := []struct { name string lines graph.WeightedLines want []graph.WeightedLine }{ { name: "nil", lines: nil, want: nil, }, { name: "empty", lines: graph.Empty, want: nil, }, { name: "no edges", lines: iterator.NewOrderedWeightedLines(nil), want: nil, }, { name: "no slice method", lines: basicWeightedLines{iterator.NewOrderedWeightedLines([]graph.WeightedLine{ multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, })}, want: []graph.WeightedLine{ multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, }, }, { name: "explicit edges", lines: iterator.NewOrderedWeightedLines([]graph.WeightedLine{ multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, }), want: []graph.WeightedLine{ multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, }, }, } for _, test := range weightedLinesOfTests { got := graph.WeightedLinesOf(test.lines) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %q: got:%v want:%v", test.name, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/graph/path/000077500000000000000000000000001450372207100176735ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/path/a_star.go000066400000000000000000000074641450372207100215060ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "container/heap" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/traverse" ) // AStar finds the A*-shortest path from s to t in g using the heuristic h. The path and // its cost are returned in a Shortest along with paths and costs to all nodes explored // during the search. The number of expanded nodes is also returned. This value may help // with heuristic tuning. // // The path will be the shortest path if the heuristic is admissible. A heuristic is // admissible if for any node, n, in the graph, the heuristic estimate of the cost of // the path from n to t is less than or equal to the true cost of that path. // // If h is nil, AStar will use the g.HeuristicCost method if g implements HeuristicCoster, // falling back to NullHeuristic otherwise. If the graph does not implement Weighted, // UniformCost is used. AStar will panic if g has an A*-reachable negative edge weight. func AStar(s, t graph.Node, g traverse.Graph, h Heuristic) (path Shortest, expanded int) { if g, ok := g.(graph.Graph); ok { if g.Node(s.ID()) == nil || g.Node(t.ID()) == nil { return Shortest{from: s}, 0 } } var weight Weighting if wg, ok := g.(Weighted); ok { weight = wg.Weight } else { weight = UniformCost(g) } if h == nil { if g, ok := g.(HeuristicCoster); ok { h = g.HeuristicCost } else { h = NullHeuristic } } path = newShortestFrom(s, []graph.Node{s, t}) tid := t.ID() visited := make(set.Int64s) open := &aStarQueue{indexOf: make(map[int64]int)} heap.Push(open, aStarNode{node: s, gscore: 0, fscore: h(s, t)}) for open.Len() != 0 { u := heap.Pop(open).(aStarNode) uid := u.node.ID() i := path.indexOf[uid] expanded++ if uid == tid { break } visited.Add(uid) to := g.From(u.node.ID()) for to.Next() { v := to.Node() vid := v.ID() if visited.Has(vid) { continue } j, ok := path.indexOf[vid] if !ok { j = path.add(v) } w, ok := weight(u.node.ID(), vid) if !ok { panic("path: A* unexpected invalid weight") } if w < 0 { panic("path: A* negative edge weight") } g := u.gscore + w if n, ok := open.node(vid); !ok { path.set(j, g, i) heap.Push(open, aStarNode{node: v, gscore: g, fscore: g + h(v, t)}) } else if g < n.gscore { path.set(j, g, i) open.update(vid, g, g+h(v, t)) } } } return path, expanded } // NullHeuristic is an admissible, consistent heuristic that will not speed up computation. func NullHeuristic(_, _ graph.Node) float64 { return 0 } // aStarNode adds A* accounting to a graph.Node. type aStarNode struct { node graph.Node gscore float64 fscore float64 } // aStarQueue is an A* priority queue. type aStarQueue struct { indexOf map[int64]int nodes []aStarNode } func (q *aStarQueue) Less(i, j int) bool { return q.nodes[i].fscore < q.nodes[j].fscore } func (q *aStarQueue) Swap(i, j int) { q.indexOf[q.nodes[i].node.ID()] = j q.indexOf[q.nodes[j].node.ID()] = i q.nodes[i], q.nodes[j] = q.nodes[j], q.nodes[i] } func (q *aStarQueue) Len() int { return len(q.nodes) } func (q *aStarQueue) Push(x interface{}) { n := x.(aStarNode) q.indexOf[n.node.ID()] = len(q.nodes) q.nodes = append(q.nodes, n) } func (q *aStarQueue) Pop() interface{} { n := q.nodes[len(q.nodes)-1] q.nodes = q.nodes[:len(q.nodes)-1] delete(q.indexOf, n.node.ID()) return n } func (q *aStarQueue) update(id int64, g, f float64) { i, ok := q.indexOf[id] if !ok { return } q.nodes[i].gscore = g q.nodes[i].fscore = f heap.Fix(q, i) } func (q *aStarQueue) node(id int64) (aStarNode, bool) { loc, ok := q.indexOf[id] if ok { return q.nodes[loc], true } return aStarNode{}, false } golang-gonum-v1-gonum-0.14.0/graph/path/a_star_test.go000066400000000000000000000166171450372207100225450ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/path/internal/testgraphs" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" ) var aStarTests = []struct { name string g graph.Graph s, t int64 heuristic Heuristic wantPath []int64 }{ { name: "simple path", g: func() graph.Graph { return testgraphs.NewGridFrom( "*..*", "**.*", "**.*", "**.*", ) }(), s: 1, t: 14, wantPath: []int64{1, 2, 6, 10, 14}, }, { name: "small open graph", g: testgraphs.NewGrid(3, 3, true), s: 0, t: 8, }, { name: "large open graph", g: testgraphs.NewGrid(1000, 1000, true), s: 0, t: 999*1000 + 999, }, { name: "no path", g: func() graph.Graph { tg := testgraphs.NewGrid(5, 5, true) // Create a complete "wall" across the middle row. tg.Set(2, 0, false) tg.Set(2, 1, false) tg.Set(2, 2, false) tg.Set(2, 3, false) tg.Set(2, 4, false) return tg }(), s: 2, t: 22, }, { name: "partially obstructed", g: func() graph.Graph { tg := testgraphs.NewGrid(10, 10, true) // Create a partial "wall" across the middle // row with a gap at the left-hand end. tg.Set(4, 1, false) tg.Set(4, 2, false) tg.Set(4, 3, false) tg.Set(4, 4, false) tg.Set(4, 5, false) tg.Set(4, 6, false) tg.Set(4, 7, false) tg.Set(4, 8, false) tg.Set(4, 9, false) return tg }(), s: 5, t: 9*10 + 9, }, { name: "partially obstructed with heuristic", g: func() graph.Graph { tg := testgraphs.NewGrid(10, 10, true) // Create a partial "wall" across the middle // row with a gap at the left-hand end. tg.Set(4, 1, false) tg.Set(4, 2, false) tg.Set(4, 3, false) tg.Set(4, 4, false) tg.Set(4, 5, false) tg.Set(4, 6, false) tg.Set(4, 7, false) tg.Set(4, 8, false) tg.Set(4, 9, false) return tg }(), s: 5, t: 9*10 + 9, // Manhattan Heuristic heuristic: func(u, v graph.Node) float64 { uid := u.ID() cu := (uid % 10) ru := (uid - cu) / 10 vid := v.ID() cv := (vid % 10) rv := (vid - cv) / 10 return math.Abs(float64(ru-rv)) + math.Abs(float64(cu-cv)) }, }, } func TestAStar(t *testing.T) { t.Parallel() for _, test := range aStarTests { pt, _ := AStar(simple.Node(test.s), simple.Node(test.t), test.g, test.heuristic) p, cost := pt.To(test.t) if !topo.IsPathIn(test.g, p) { t.Errorf("got path that is not path in input graph for %q", test.name) } bfp, ok := BellmanFordFrom(simple.Node(test.s), test.g) if !ok { t.Fatalf("unexpected negative cycle in %q", test.name) } if want := bfp.WeightTo(test.t); cost != want { t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want) } var got = make([]int64, 0, len(p)) for _, n := range p { got = append(got, n.ID()) } if test.wantPath != nil && !reflect.DeepEqual(got, test.wantPath) { t.Errorf("unexpected result for %q:\ngot: %v\nwant:%v", test.name, got, test.wantPath) } } } func TestExhaustiveAStar(t *testing.T) { t.Parallel() g := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) nodes := []locatedNode{ {id: 1, x: 0, y: 6}, {id: 2, x: 1, y: 0}, {id: 3, x: 8, y: 7}, {id: 4, x: 16, y: 0}, {id: 5, x: 17, y: 6}, {id: 6, x: 9, y: 8}, } for _, n := range nodes { g.AddNode(n) } edges := []weightedEdge{ {from: g.Node(1), to: g.Node(2), cost: 7}, {from: g.Node(1), to: g.Node(3), cost: 9}, {from: g.Node(1), to: g.Node(6), cost: 14}, {from: g.Node(2), to: g.Node(3), cost: 10}, {from: g.Node(2), to: g.Node(4), cost: 15}, {from: g.Node(3), to: g.Node(4), cost: 11}, {from: g.Node(3), to: g.Node(6), cost: 2}, {from: g.Node(4), to: g.Node(5), cost: 7}, {from: g.Node(5), to: g.Node(6), cost: 9}, } for _, e := range edges { g.SetWeightedEdge(e) } heuristic := func(u, v graph.Node) float64 { lu := u.(locatedNode) lv := v.(locatedNode) return math.Hypot(lu.x-lv.x, lu.y-lv.y) } if ok, edge, goal := isMonotonic(g, heuristic); !ok { t.Fatalf("non-monotonic heuristic at edge:%v for goal:%v", edge, goal) } ps := DijkstraAllPaths(g) ends := graph.NodesOf(g.Nodes()) for _, start := range ends { for _, goal := range ends { pt, _ := AStar(start, goal, g, heuristic) gotPath, gotWeight := pt.To(goal.ID()) wantPath, wantWeight, _ := ps.Between(start.ID(), goal.ID()) if gotWeight != wantWeight { t.Errorf("unexpected path weight from %v to %v result: got:%f want:%f", start, goal, gotWeight, wantWeight) } if !reflect.DeepEqual(gotPath, wantPath) { t.Errorf("unexpected path from %v to %v result:\ngot: %v\nwant:%v", start, goal, gotPath, wantPath) } } } } type locatedNode struct { id int64 x, y float64 } func (n locatedNode) ID() int64 { return n.id } type weightedEdge struct { from, to graph.Node cost float64 } func (e weightedEdge) From() graph.Node { return e.from } func (e weightedEdge) To() graph.Node { return e.to } func (e weightedEdge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from; return e } func (e weightedEdge) Weight() float64 { return e.cost } func isMonotonic(g UndirectedWeightLister, h Heuristic) (ok bool, at graph.Edge, goal graph.Node) { for _, goal := range graph.NodesOf(g.Nodes()) { for _, edge := range graph.WeightedEdgesOf(g.WeightedEdges()) { from := edge.From() to := edge.To() w, ok := g.Weight(from.ID(), to.ID()) if !ok { panic("A*: unexpected invalid weight") } if h(from, goal) > w+h(to, goal) { return false, edge, goal } } } return true, nil, nil } func TestAStarNullHeuristic(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } var ( pt Shortest panicked bool ) func() { defer func() { panicked = recover() != nil }() pt, _ = AStar(test.Query.From(), test.Query.To(), g.(graph.Graph), nil) }() if panicked || test.HasNegativeWeight { if !test.HasNegativeWeight { t.Errorf("%q: unexpected panic", test.Name) } if !panicked { t.Errorf("%q: expected panic for negative edge weight", test.Name) } continue } if pt.From().ID() != test.Query.From().ID() { t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID()) } p, weight := pt.To(test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from To: got:%f want:%f", test.Name, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight { t.Errorf("%q: unexpected weight from Weight: got:%f want:%f", test.Name, weight, test.Weight) } var got []int64 for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, p, test.WantPaths) } np, weight := pt.To(test.NoPathFor.To().ID()) if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) { t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path= weight=+Inf", test.Name, np, weight) } } } golang-gonum-v1-gonum-0.14.0/graph/path/bellman_ford_moore.go000066400000000000000000000144651450372207100240610ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/linear" "gonum.org/v1/gonum/graph/traverse" ) // BellmanFordFrom returns a shortest-path tree for a shortest path from u to all nodes in // the graph g, or false indicating that a negative cycle exists in the graph. If the graph // does not implement Weighted, UniformCost is used. // // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path // tree, otherwise only nodes reachable from u will be stored. // // The time complexity of BellmanFordFrom is O(|V|.|E|). func BellmanFordFrom(u graph.Node, g traverse.Graph) (path Shortest, ok bool) { if h, ok := g.(graph.Graph); ok { if h.Node(u.ID()) == nil { return Shortest{from: u}, true } path = newShortestFrom(u, graph.NodesOf(h.Nodes())) } else { if g.From(u.ID()) == graph.Empty { return Shortest{from: u}, true } path = newShortestFrom(u, []graph.Node{u}) } path.dist[path.indexOf[u.ID()]] = 0 path.negCosts = make(map[negEdge]float64) var weight Weighting if wg, ok := g.(Weighted); ok { weight = wg.Weight } else { weight = UniformCost(g) } // Queue to keep track which nodes need to be relaxed. // Only nodes whose vertex distance changed in the previous iterations // need to be relaxed again. queue := newBellmanFordQueue(path.indexOf) queue.enqueue(u) // TODO(kortschak): Consider adding further optimisations // from http://arxiv.org/abs/1111.5414. var loops int64 for queue.len() != 0 { u := queue.dequeue() uid := u.ID() j := path.indexOf[uid] to := g.From(uid) for to.Next() { v := to.Node() vid := v.ID() k, ok := path.indexOf[vid] if !ok { k = path.add(v) } w, ok := weight(uid, vid) if !ok { panic("bellman-ford: unexpected invalid weight") } joint := path.dist[j] + w if joint < path.dist[k] { path.set(k, joint, j) if !queue.has(vid) { queue.enqueue(v) } } } // The maximum number of edges in the relaxed subgraph is |V_r| * (|V_r|-1). // If the queue-loop has more iterations than the maximum number of edges // it indicates that we have a negative cycle. maxEdges := int64(len(path.nodes)) * int64(len(path.nodes)-1) if loops > maxEdges { path.hasNegativeCycle = true return path, false } loops++ } return path, true } // BellmanFordAllFrom returns a shortest-path tree for shortest paths from u to all nodes in // the graph g, or false indicating that a negative cycle exists in the graph. If the graph // does not implement Weighted, UniformCost is used. // // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path // tree, otherwise only nodes reachable from u will be stored. // // The time complexity of BellmanFordAllFrom is O(|V|.|E|). func BellmanFordAllFrom(u graph.Node, g traverse.Graph) (path ShortestAlts, ok bool) { if h, ok := g.(graph.Graph); ok { if h.Node(u.ID()) == nil { return ShortestAlts{from: u}, true } path = newShortestAltsFrom(u, graph.NodesOf(h.Nodes())) } else { if g.From(u.ID()) == graph.Empty { return ShortestAlts{from: u}, true } path = newShortestAltsFrom(u, []graph.Node{u}) } path.dist[path.indexOf[u.ID()]] = 0 path.negCosts = make(map[negEdge]float64) var weight Weighting if wg, ok := g.(Weighted); ok { weight = wg.Weight } else { weight = UniformCost(g) } // Queue to keep track which nodes need to be relaxed. // Only nodes whose vertex distance changed in the previous iterations // need to be relaxed again. queue := newBellmanFordQueue(path.indexOf) queue.enqueue(u) // TODO(kortschak): Consider adding further optimisations // from http://arxiv.org/abs/1111.5414. var loops int64 for queue.len() != 0 { u := queue.dequeue() uid := u.ID() j := path.indexOf[uid] for _, v := range graph.NodesOf(g.From(uid)) { vid := v.ID() k, ok := path.indexOf[vid] if !ok { k = path.add(v) } w, ok := weight(uid, vid) if !ok { panic("bellman-ford: unexpected invalid weight") } joint := path.dist[j] + w if joint < path.dist[k] { path.set(k, joint, j) if !queue.has(vid) { queue.enqueue(v) } } else if joint == path.dist[k] { path.addPath(k, j) } } // The maximum number of edges in the relaxed subgraph is |V_r| * (|V_r|-1). // If the queue-loop has more iterations than the maximum number of edges // it indicates that we have a negative cycle. maxEdges := int64(len(path.nodes)) * int64(len(path.nodes)-1) if loops > maxEdges { path.hasNegativeCycle = true return path, false } loops++ } return path, true } // bellmanFordQueue is a queue for the Queue-based Bellman-Ford algorithm. type bellmanFordQueue struct { // queue holds the nodes which need to be relaxed. queue linear.NodeQueue // onQueue keeps track whether a node is on the queue or not. onQueue []bool // indexOf contains a mapping holding the id of a node with its index in the onQueue array. indexOf map[int64]int } // enqueue adds a node to the bellmanFordQueue. func (q *bellmanFordQueue) enqueue(n graph.Node) { i, ok := q.indexOf[n.ID()] switch { case !ok: panic("bellman-ford: unknown node") case i < len(q.onQueue): if q.onQueue[i] { panic("bellman-ford: already queued") } case i == len(q.onQueue): q.onQueue = append(q.onQueue, false) case i < cap(q.onQueue): q.onQueue = q.onQueue[:i+1] default: q.onQueue = append(q.onQueue, make([]bool, i-len(q.onQueue)+1)...) } q.onQueue[i] = true q.queue.Enqueue(n) } // dequeue returns the first value of the bellmanFordQueue. func (q *bellmanFordQueue) dequeue() graph.Node { n := q.queue.Dequeue() q.onQueue[q.indexOf[n.ID()]] = false return n } // len returns the number of nodes in the bellmanFordQueue. func (q *bellmanFordQueue) len() int { return q.queue.Len() } // has returns whether a node with the given id is in the queue. func (q bellmanFordQueue) has(id int64) bool { idx, ok := q.indexOf[id] if !ok || idx >= len(q.onQueue) { return false } return q.onQueue[idx] } // newBellmanFordQueue creates a new bellmanFordQueue. func newBellmanFordQueue(indexOf map[int64]int) bellmanFordQueue { return bellmanFordQueue{ onQueue: make([]bool, len(indexOf)), indexOf: indexOf, } } golang-gonum-v1-gonum-0.14.0/graph/path/bellman_ford_moore_test.go000066400000000000000000000146421450372207100251150ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/path/internal/testgraphs" "gonum.org/v1/gonum/graph/traverse" ) func TestBellmanFordFrom(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } for _, tg := range []struct { typ string g traverse.Graph }{ {"complete", g.(graph.Graph)}, {"incremental", incremental{g.(graph.Weighted)}}, } { pt, ok := BellmanFordFrom(test.Query.From(), tg.g) if test.HasNegativeCycle { if ok { t.Errorf("%q %s: expected negative cycle", test.Name, tg.typ) } } else if !ok { t.Fatalf("%q %s: unexpected negative cycle", test.Name, tg.typ) } if pt.From().ID() != test.Query.From().ID() { t.Fatalf("%q %s: unexpected from node ID: got:%d want:%d", test.Name, tg.typ, pt.From().ID(), test.Query.From().ID()) } p, weight := pt.To(test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q %s: unexpected weight from To: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight { t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } var got []int64 for _, n := range p { got = append(got, n.ID()) } ok = len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q %s: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, tg.typ, p, test.WantPaths) } np, weight := pt.To(test.NoPathFor.To().ID()) if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) { t.Errorf("%q %s: unexpected path:\ngot: path=%v weight=%f\nwant:path= weight=+Inf", test.Name, tg.typ, np, weight) } } } } func TestBellmanFordAllFrom(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } for _, tg := range []struct { typ string g traverse.Graph }{ {"complete", g.(graph.Graph)}, {"incremental", incremental{g.(graph.Weighted)}}, } { pt, ok := BellmanFordAllFrom(test.Query.From(), tg.g) if test.HasNegativeCycle { if ok { t.Errorf("%q %s: expected negative cycle", test.Name, tg.typ) } } else if !ok { t.Fatalf("%q %s: unexpected negative cycle", test.Name, tg.typ) } if pt.From().ID() != test.Query.From().ID() { t.Fatalf("%q %s: unexpected from node ID: got:%d want:%d", test.Name, tg.typ, pt.From().ID(), test.Query.From().ID()) } // Test single path results. p, weight, unique := pt.To(test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q %s: unexpected weight from To: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight { t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } var gotPath []int64 for _, n := range p { gotPath = append(gotPath, n.ID()) } ok = len(gotPath) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(gotPath, sp) { ok = true break } } if !ok { t.Errorf("%q %s: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, tg.typ, p, test.WantPaths) } if unique != test.HasUniquePath { t.Errorf("%q %s: unexpected uniqueness from To: got:%t want:%t (%d paths)", test.Name, tg.typ, unique, test.HasUniquePath, len(test.WantPaths)) } // Test multiple path results. paths, weight := pt.AllTo(test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q %s: unexpected weight from AllTo: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight { t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } var gotPaths [][]int64 if len(paths) != 0 { gotPaths = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { gotPaths[i] = append(gotPaths[i], v.ID()) } } if test.HasNegativeCycleInPath { if gotPaths != nil { t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant: []", test.Name, tg.typ, gotPaths) } } else { ordered.BySliceValues(gotPaths) if !reflect.DeepEqual(gotPaths, test.WantPaths) { t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, tg.typ, gotPaths, test.WantPaths) } } paths = paths[:0] pt.AllToFunc(test.Query.To().ID(), func(path []graph.Node) { paths = append(paths, append([]graph.Node(nil), path...)) }) if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight { t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } gotPaths = nil if len(paths) != 0 { gotPaths = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { gotPaths[i] = append(gotPaths[i], v.ID()) } } if test.HasNegativeCycleInPath { if gotPaths != nil { t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant: []", test.Name, tg.typ, gotPaths) } } else { ordered.BySliceValues(gotPaths) if !reflect.DeepEqual(gotPaths, test.WantPaths) { t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, tg.typ, gotPaths, test.WantPaths) } } // Test absent paths. np, weight, unique := pt.To(test.NoPathFor.To().ID()) if pt.From().ID() == test.NoPathFor.From().ID() && !(np == nil && math.IsInf(weight, 1) && !unique) { t.Errorf("%q %s: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path= weight=+Inf unique=false", test.Name, tg.typ, np, weight, unique) } } } } golang-gonum-v1-gonum-0.14.0/graph/path/bench_test.go000066400000000000000000000123661450372207100223500ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "fmt" "sync" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/traverse" ) var ( gnpUndirected_10_tenth = gnpUndirected(10, 0.1) gnpUndirected_100_tenth = gnpUndirected(100, 0.1) gnpUndirected_1000_tenth = gnpUndirected(1000, 0.1) gnpUndirected_10_half = gnpUndirected(10, 0.5) gnpUndirected_100_half = gnpUndirected(100, 0.5) gnpUndirected_1000_half = gnpUndirected(1000, 0.5) nswUndirected_10_2_2_2 = navigableSmallWorldUndirected(10, 2, 2, 2) nswUndirected_10_2_5_2 = navigableSmallWorldUndirected(10, 2, 5, 2) nswUndirected_100_5_10_2 = navigableSmallWorldUndirected(100, 5, 10, 2) nswUndirected_100_5_20_2 = navigableSmallWorldUndirected(100, 5, 20, 2) ) func gnpUndirected(n int, p float64) func() graph.Undirected { var once sync.Once var cache graph.Undirected return func() graph.Undirected { once.Do(func() { g := simple.NewUndirectedGraph() err := gen.Gnp(g, n, p, nil) if err != nil { panic(fmt.Sprintf("path: bad test: %v", err)) } cache = g }) return cache } } func navigableSmallWorldUndirected(n, p, q int, r float64) func() graph.Undirected { var once sync.Once var cache graph.Undirected return func() graph.Undirected { once.Do(func() { g := simple.NewUndirectedGraph() err := gen.NavigableSmallWorld(g, []int{n, n}, p, q, r, nil) if err != nil { panic(fmt.Sprintf("path: bad test: %v", err)) } cache = g }) return cache } } func manhattan(size int) func(x, y graph.Node) float64 { return func(x, y graph.Node) float64 { return manhattanBetween(coordinatesForID(x, size, size), coordinatesForID(y, size, size)) } } func coordinatesForID(n graph.Node, c, r int) [2]int { id := n.ID() if id >= int64(c*r) { panic("out of range") } return [2]int{int(id) / r, int(id) % r} } // manhattanBetween returns the Manhattan distance between a and b. func manhattanBetween(a, b [2]int) float64 { var d int for i, v := range a { d += abs(v - b[i]) } return float64(d) } func abs(a int) int { if a < 0 { return -a } return a } func BenchmarkAStarUndirected(b *testing.B) { benchmarks := []struct { name string graph graph.Undirected h Heuristic }{ {"GNP Undirected 10 tenth", gnpUndirected_10_tenth(), nil}, {"GNP Undirected 100 tenth", gnpUndirected_100_tenth(), nil}, {"GNP Undirected 1000 tenth", gnpUndirected_1000_tenth(), nil}, {"GNP Undirected 10 half", gnpUndirected_10_half(), nil}, {"GNP Undirected 100 half", gnpUndirected_100_half(), nil}, {"GNP Undirected 1000 half", gnpUndirected_1000_half(), nil}, {"NSW Undirected 10 2 2 2", nswUndirected_10_2_2_2(), nil}, {"NSW Undirected 10 2 2 2 heuristic", nswUndirected_10_2_2_2(), manhattan(10)}, {"NSW Undirected 10 2 5 2", nswUndirected_10_2_5_2(), nil}, {"NSW Undirected 10 2 5 2 heuristic", nswUndirected_10_2_5_2(), manhattan(10)}, {"NSW Undirected 100 5 10 2", nswUndirected_100_5_10_2(), nil}, {"NSW Undirected 100 5 10 2 heuristic", nswUndirected_100_5_10_2(), manhattan(100)}, {"NSW Undirected 100 5 20 2", nswUndirected_100_5_20_2(), nil}, {"NSW Undirected 100 5 20 2 heuristic", nswUndirected_100_5_20_2(), manhattan(100)}, } for _, bm := range benchmarks { b.Run(bm.name, func(b *testing.B) { var expanded int for i := 0; i < b.N; i++ { _, expanded = AStar(simple.Node(0), simple.Node(1), bm.graph, bm.h) } if expanded == 0 { b.Fatal("unexpected number of expanded nodes") } }) } } var ( gnpDirected_500_tenth = gnpDirected(500, 0.1) gnpDirected_1000_tenth = gnpDirected(1000, 0.1) gnpDirected_2000_tenth = gnpDirected(2000, 0.1) gnpDirected_500_half = gnpDirected(500, 0.5) gnpDirected_1000_half = gnpDirected(1000, 0.5) gnpDirected_2000_half = gnpDirected(2000, 0.5) gnpDirected_500_full = gnpDirected(500, 1) gnpDirected_1000_full = gnpDirected(1000, 1) gnpDirected_2000_full = gnpDirected(2000, 1) ) func gnpDirected(n int, p float64) func() graph.Directed { var once sync.Once var cache graph.Directed return func() graph.Directed { once.Do(func() { g := simple.NewDirectedGraph() err := gen.Gnp(g, n, p, nil) if err != nil { panic(fmt.Sprintf("path: bad test: %v", err)) } cache = g }) return cache } } func BenchmarkBellmanFordFrom(b *testing.B) { benchmarks := []struct { name string graph graph.Directed }{ {"500 tenth", gnpDirected_500_tenth()}, {"1000 tenth", gnpDirected_1000_tenth()}, {"2000 tenth", gnpDirected_2000_tenth()}, {"500 half", gnpDirected_500_half()}, {"1000 half", gnpDirected_1000_half()}, {"2000 half", gnpDirected_2000_half()}, {"500 full", gnpDirected_500_full()}, {"1000 full", gnpDirected_1000_full()}, {"2000 full", gnpDirected_2000_full()}, } type incremental struct { traverse.Graph } for _, bm := range benchmarks { for _, tg := range []struct { typ string g traverse.Graph }{ {g: bm.graph}, {typ: " incremental", g: incremental{bm.graph}}, } { b.Run(bm.name+tg.typ, func(b *testing.B) { for i := 0; i < b.N; i++ { BellmanFordFrom(bm.graph.Node(0), tg.g) } }) } } } golang-gonum-v1-gonum-0.14.0/graph/path/dijkstra.go000066400000000000000000000156351450372207100220470ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "container/heap" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/traverse" ) // DijkstraFrom returns a shortest-path tree for a shortest path from u to all nodes in // the graph g. If the graph does not implement Weighted, UniformCost is used. // DijkstraFrom will panic if g has a u-reachable negative edge weight. // // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path // tree, otherwise only nodes reachable from u will be stored. // // The time complexity of DijkstraFrom is O(|E|.log|V|). func DijkstraFrom(u graph.Node, g traverse.Graph) Shortest { var path Shortest if h, ok := g.(graph.Graph); ok { if h.Node(u.ID()) == nil { return Shortest{from: u} } path = newShortestFrom(u, graph.NodesOf(h.Nodes())) } else { if g.From(u.ID()) == graph.Empty { return Shortest{from: u} } path = newShortestFrom(u, []graph.Node{u}) } var weight Weighting if wg, ok := g.(Weighted); ok { weight = wg.Weight } else { weight = UniformCost(g) } // Dijkstra's algorithm here is implemented essentially as // described in Function B.2 in figure 6 of UTCS Technical // Report TR-07-54. // // This implementation deviates from the report as follows: // - the value of path.dist for the start vertex u is initialized to 0; // - outdated elements from the priority queue (i.e. with respect to the dist value) // are skipped. // // http://www.cs.utexas.edu/ftp/techreports/tr07-54.pdf Q := priorityQueue{{node: u, dist: 0}} for Q.Len() != 0 { mid := heap.Pop(&Q).(distanceNode) k := path.indexOf[mid.node.ID()] if mid.dist > path.dist[k] { continue } mnid := mid.node.ID() to := g.From(mnid) for to.Next() { v := to.Node() vid := v.ID() j, ok := path.indexOf[vid] if !ok { j = path.add(v) } w, ok := weight(mnid, vid) if !ok { panic("dijkstra: unexpected invalid weight") } if w < 0 { panic("dijkstra: negative edge weight") } joint := path.dist[k] + w if joint < path.dist[j] { heap.Push(&Q, distanceNode{node: v, dist: joint}) path.set(j, joint, k) } } } return path } // DijkstraAllFrom returns a shortest-path tree for shortest paths from u to all nodes in // the graph g. If the graph does not implement Weighted, UniformCost is used. // DijkstraAllFrom will panic if g has a u-reachable negative edge weight. // // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path // tree, otherwise only nodes reachable from u will be stored. // // The time complexity of DijkstraAllFrom is O(|E|.log|V|). func DijkstraAllFrom(u graph.Node, g traverse.Graph) ShortestAlts { var path ShortestAlts if h, ok := g.(graph.Graph); ok { if h.Node(u.ID()) == nil { return ShortestAlts{from: u} } path = newShortestAltsFrom(u, graph.NodesOf(h.Nodes())) } else { if g.From(u.ID()) == graph.Empty { return ShortestAlts{from: u} } path = newShortestAltsFrom(u, []graph.Node{u}) } var weight Weighting if wg, ok := g.(Weighted); ok { weight = wg.Weight } else { weight = UniformCost(g) } // Dijkstra's algorithm here is implemented essentially as // described in Function B.2 in figure 6 of UTCS Technical // Report TR-07-54. // // This implementation deviates from the report as follows: // - the value of path.dist for the start vertex u is initialized to 0; // - outdated elements from the priority queue (i.e. with respect to the dist value) // are skipped. // // http://www.cs.utexas.edu/ftp/techreports/tr07-54.pdf Q := priorityQueue{{node: u, dist: 0}} for Q.Len() != 0 { mid := heap.Pop(&Q).(distanceNode) k := path.indexOf[mid.node.ID()] if mid.dist > path.dist[k] { continue } mnid := mid.node.ID() for _, v := range graph.NodesOf(g.From(mnid)) { vid := v.ID() j, ok := path.indexOf[vid] if !ok { j = path.add(v) } w, ok := weight(mnid, vid) if !ok { panic("dijkstra: unexpected invalid weight") } if w < 0 { panic("dijkstra: negative edge weight") } joint := path.dist[k] + w if joint < path.dist[j] { heap.Push(&Q, distanceNode{node: v, dist: joint}) path.set(j, joint, k) } else if joint == path.dist[j] { path.addPath(j, k) } } } return path } // DijkstraAllPaths returns a shortest-path tree for shortest paths in the graph g. // If the graph does not implement graph.Weighter, UniformCost is used. // DijkstraAllPaths will panic if g has a negative edge weight. // // The time complexity of DijkstraAllPaths is O(|V|.|E|+|V|^2.log|V|). func DijkstraAllPaths(g graph.Graph) (paths AllShortest) { paths = newAllShortest(graph.NodesOf(g.Nodes()), false) dijkstraAllPaths(g, paths) return paths } // dijkstraAllPaths is the all-paths implementation of Dijkstra. It is shared // between DijkstraAllPaths and JohnsonAllPaths to avoid repeated allocation // of the nodes slice and the indexOf map. It returns nothing, but stores the // result of the work in the paths parameter which is a reference type. func dijkstraAllPaths(g graph.Graph, paths AllShortest) { var weight Weighting if wg, ok := g.(graph.Weighted); ok { weight = wg.Weight } else { weight = UniformCost(g) } var Q priorityQueue for i, u := range paths.nodes { // Dijkstra's algorithm here is implemented essentially as // described in Function B.2 in figure 6 of UTCS Technical // Report TR-07-54 with the addition of handling multiple // co-equal paths. // // http://www.cs.utexas.edu/ftp/techreports/tr07-54.pdf // Q must be empty at this point. heap.Push(&Q, distanceNode{node: u, dist: 0}) for Q.Len() != 0 { mid := heap.Pop(&Q).(distanceNode) k := paths.indexOf[mid.node.ID()] if mid.dist < paths.dist.At(i, k) { paths.dist.Set(i, k, mid.dist) } mnid := mid.node.ID() to := g.From(mnid) for to.Next() { v := to.Node() vid := v.ID() j := paths.indexOf[vid] w, ok := weight(mnid, vid) if !ok { panic("dijkstra: unexpected invalid weight") } if w < 0 { panic("dijkstra: negative edge weight") } joint := paths.dist.At(i, k) + w if joint < paths.dist.At(i, j) { heap.Push(&Q, distanceNode{node: v, dist: joint}) paths.set(i, j, joint, k) } else if joint == paths.dist.At(i, j) { paths.add(i, j, k) } } } } } type distanceNode struct { node graph.Node dist float64 } // priorityQueue implements a no-dec priority queue. type priorityQueue []distanceNode func (q priorityQueue) Len() int { return len(q) } func (q priorityQueue) Less(i, j int) bool { return q[i].dist < q[j].dist } func (q priorityQueue) Swap(i, j int) { q[i], q[j] = q[j], q[i] } func (q *priorityQueue) Push(n interface{}) { *q = append(*q, n.(distanceNode)) } func (q *priorityQueue) Pop() interface{} { t := *q var n interface{} n, *q = t[len(t)-1], t[:len(t)-1] return n } golang-gonum-v1-gonum-0.14.0/graph/path/dijkstra_test.go000066400000000000000000000254551450372207100231070ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/path/internal/testgraphs" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/traverse" ) func TestDijkstraFrom(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } for _, tg := range []struct { typ string g traverse.Graph }{ {"complete", g.(graph.Graph)}, {"incremental", incremental{g.(graph.Weighted)}}, } { var ( pt Shortest panicked bool ) func() { defer func() { panicked = recover() != nil }() pt = DijkstraFrom(test.Query.From(), tg.g) }() if panicked || test.HasNegativeWeight { if !test.HasNegativeWeight { t.Errorf("%q %s: unexpected panic", test.Name, tg.typ) } if !panicked { t.Errorf("%q %s: expected panic for negative edge weight", test.Name, tg.typ) } continue } if pt.From().ID() != test.Query.From().ID() { t.Fatalf("%q %s: unexpected from node ID: got:%d want:%d", test.Name, tg.typ, pt.From().ID(), test.Query.From().ID()) } p, weight := pt.To(test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q %s: unexpected weight from To: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight { t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } var got []int64 for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q %s: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, tg.typ, p, test.WantPaths) } np, weight := pt.To(test.NoPathFor.To().ID()) if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) { t.Errorf("%q %s: unexpected path:\ngot: path=%v weight=%f\nwant:path= weight=+Inf", test.Name, tg.typ, np, weight) } } } } func TestDijkstraAllFrom(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } for _, tg := range []struct { typ string g traverse.Graph }{ {"complete", g.(graph.Graph)}, {"incremental", incremental{g.(graph.Weighted)}}, } { var ( pt ShortestAlts panicked bool ) func() { defer func() { panicked = recover() != nil }() pt = DijkstraAllFrom(test.Query.From(), tg.g) }() if panicked || test.HasNegativeWeight { if !test.HasNegativeWeight { t.Errorf("%q %s: unexpected panic", test.Name, tg.typ) } if !panicked { t.Errorf("%q %s: expected panic for negative edge weight", test.Name, tg.typ) } continue } if pt.From().ID() != test.Query.From().ID() { t.Fatalf("%q %s: unexpected from node ID: got:%d want:%d", test.Name, tg.typ, pt.From().ID(), test.Query.From().ID()) } // Test single path results. p, weight, unique := pt.To(test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q %s: unexpected weight from To: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight { t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } var gotPath []int64 for _, n := range p { gotPath = append(gotPath, n.ID()) } ok := len(gotPath) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(gotPath, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, p, test.WantPaths) } if unique != test.HasUniquePath { t.Errorf("%q: unexpected uniqueness from To: got:%t want:%t (%d paths)", test.Name, unique, test.HasUniquePath, len(test.WantPaths)) } // Test multiple path results. paths, weight := pt.AllTo(test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from AllTo: got:%f want:%f", test.Name, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight { t.Errorf("%q: unexpected weight from Weight: got:%f want:%f", test.Name, weight, test.Weight) } var gotPaths [][]int64 if len(paths) != 0 { gotPaths = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { gotPaths[i] = append(gotPaths[i], v.ID()) } } ordered.BySliceValues(gotPaths) if !reflect.DeepEqual(gotPaths, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, gotPaths, test.WantPaths) } paths = paths[:0] pt.AllToFunc(test.Query.To().ID(), func(path []graph.Node) { paths = append(paths, append([]graph.Node(nil), path...)) }) if weight != test.Weight { t.Errorf("%q %s: unexpected weight from AllTo: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight { t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f", test.Name, tg.typ, weight, test.Weight) } gotPaths = nil if len(paths) != 0 { gotPaths = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { gotPaths[i] = append(gotPaths[i], v.ID()) } } ordered.BySliceValues(gotPaths) if !reflect.DeepEqual(gotPaths, test.WantPaths) { t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, tg.typ, gotPaths, test.WantPaths) } // Test absent paths. np, weight, unique := pt.To(test.NoPathFor.To().ID()) if pt.From().ID() == test.NoPathFor.From().ID() && !(np == nil && math.IsInf(weight, 1) && !unique) { t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path= weight=+Inf unique=false", test.Name, np, weight, unique) } } } } type weightedTraverseGraph interface { traverse.Graph Weighted } type incremental struct { weightedTraverseGraph } func TestDijkstraAllPaths(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } var ( pt AllShortest panicked bool ) func() { defer func() { panicked = recover() != nil }() pt = DijkstraAllPaths(g.(graph.Graph)) }() if panicked || test.HasNegativeWeight { if !test.HasNegativeWeight { t.Errorf("%q: unexpected panic", test.Name) } if !panicked { t.Errorf("%q: expected panic for negative edge weight", test.Name) } continue } // Check all random paths returned are OK. for i := 0; i < 10; i++ { p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight { t.Errorf("%q: unexpected weight from Weight: got:%f want:%f", test.Name, weight, test.Weight) } if unique != test.HasUniquePath { t.Errorf("%q: unexpected number of paths: got: unique=%t want: unique=%t", test.Name, unique, test.HasUniquePath) } var got []int64 for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, p, test.WantPaths) } } np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID()) if np != nil || !math.IsInf(weight, 1) || unique { t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path= weight=+Inf unique=false", test.Name, np, weight, unique) } paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } var got [][]int64 if len(paths) != 0 { got = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, got, test.WantPaths) } paths = paths[:0] pt.AllBetweenFunc(test.Query.From().ID(), test.Query.To().ID(), func(path []graph.Node) { paths = append(paths, append([]graph.Node(nil), path...)) }) got = nil if len(paths) != 0 { got = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, got, test.WantPaths) } nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID()) if nps != nil || !math.IsInf(weight, 1) { t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path= weight=+Inf", test.Name, nps, weight) } } } func TestAllShortestAbsentNode(t *testing.T) { t.Parallel() g := simple.NewUndirectedGraph() g.SetEdge(simple.Edge{F: simple.Node(1), T: simple.Node(2)}) paths := DijkstraAllPaths(g) // Confirm we have a good paths tree. if _, cost := paths.AllBetween(1, 2); cost != 1 { t.Errorf("unexpected cost between existing nodes: got:%v want:1", cost) } gotPath, cost, unique := paths.Between(0, 0) if cost != 0 { t.Errorf("unexpected cost from absent node to itself: got:%v want:0", cost) } if !unique { t.Error("unexpected non-unique path from absent node to itself") } wantPath := []graph.Node{node(0)} if !reflect.DeepEqual(gotPath, wantPath) { t.Errorf("unexpected path from absent node to itself: got:%#v want:%#v", gotPath, wantPath) } gotPaths, cost := paths.AllBetween(0, 0) if cost != 0 { t.Errorf("unexpected cost from absent node to itself: got:%v want:0", cost) } wantPaths := [][]graph.Node{{node(0)}} if !reflect.DeepEqual(gotPaths, wantPaths) { t.Errorf("unexpected paths from absent node to itself: got:%#v want:%#v", gotPaths, wantPaths) } } golang-gonum-v1-gonum-0.14.0/graph/path/disjoint.go000066400000000000000000000021361450372207100220470ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path // djSet implements a disjoint set finder using the union-find algorithm. type djSet map[int64]*dsNode // add adds e to the collection of sets held by the disjoint set. func (s djSet) add(e int64) { if _, ok := s[e]; ok { return } s[e] = &dsNode{} } // union joins two sets a and b within the collection of sets held by // the disjoint set. func (djSet) union(a, b *dsNode) { ra := find(a) rb := find(b) if ra == rb { return } if ra.rank < rb.rank { ra.parent = rb return } rb.parent = ra if ra.rank == rb.rank { ra.rank++ } } // find returns the root of the set containing e. func (s djSet) find(e int64) *dsNode { n, ok := s[e] if !ok { return nil } return find(n) } // find returns the root of the set containing the set node, n. func find(n *dsNode) *dsNode { for ; n.parent != nil; n = n.parent { } return n } // dsNode is a disjoint set element. type dsNode struct { parent *dsNode rank int } golang-gonum-v1-gonum-0.14.0/graph/path/disjoint_test.go000066400000000000000000000022221450372207100231020ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "testing" ) func TestDisjointSetMakeSet(t *testing.T) { t.Parallel() ds := make(djSet) ds.add(3) if len(ds) != 1 { t.Error("Disjoint set master map of wrong size") } node, ok := ds[3] if !ok { t.Error("Make set did not successfully add element") } else { if node == nil { t.Fatal("Disjoint set node from add is nil") } if node.rank != 0 { t.Error("Node rank set incorrectly") } if node.parent != nil { t.Error("Node parent set incorrectly") } } } func TestDisjointSetFind(t *testing.T) { t.Parallel() ds := make(djSet) ds.add(3) ds.add(4) ds.add(5) ds.union(ds.find(3), ds.find(4)) if ds.find(3) == ds.find(5) { t.Error("Disjoint sets incorrectly found to be the same") } } func TestUnion(t *testing.T) { t.Parallel() ds := make(djSet) ds.add(3) ds.add(4) ds.add(5) ds.union(ds.find(3), ds.find(4)) ds.union(ds.find(4), ds.find(5)) if ds.find(3) != ds.find(5) { t.Error("Sets found to be disjoint after union") } } golang-gonum-v1-gonum-0.14.0/graph/path/doc.go000066400000000000000000000004231450372207100207660ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package path provides graph path finding functions. package path // import "gonum.org/v1/gonum/graph/path" golang-gonum-v1-gonum-0.14.0/graph/path/dynamic/000077500000000000000000000000001450372207100213175ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/path/dynamic/doc.go000066400000000000000000000004671450372207100224220ustar00rootroot00000000000000// Copyright ©2016 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 dynamic provides incremental heuristic graph path finding functions. package dynamic // import "gonum.org/v1/gonum/graph/path/dynamic" golang-gonum-v1-gonum-0.14.0/graph/path/dynamic/dstarlite.go000066400000000000000000000322631450372207100236470ustar00rootroot00000000000000// 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 dynamic import ( "container/heap" "fmt" "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/path" "gonum.org/v1/gonum/graph/simple" ) // DStarLite implements the D* Lite dynamic re-planning path search algorithm. // // doi:10.1109/tro.2004.838026 and ISBN:0-262-51129-0 pp476-483 type DStarLite struct { s, t *dStarLiteNode last *dStarLiteNode model WorldModel queue dStarLiteQueue keyModifier float64 weight path.Weighting heuristic path.Heuristic } // WorldModel is a mutable weighted directed graph that returns nodes identified // by id number. type WorldModel interface { graph.WeightedBuilder graph.WeightedDirected } // NewDStarLite returns a new DStarLite planner for the path from s to t in g using the // heuristic h. The world model, m, is used to store shortest path information during path // planning. The world model must be an empty graph when NewDStarLite is called. // // If h is nil, the DStarLite will use the g.HeuristicCost method if g implements // path.HeuristicCoster, falling back to path.NullHeuristic otherwise. If the graph does not // implement graph.Weighter, path.UniformCost is used. NewDStarLite will panic if g has // a negative edge weight. func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel) *DStarLite { /* procedure Initialize() {02”} U = ∅; {03”} k_m = 0; {04”} for all s ∈ S rhs(s) = g(s) = ∞; {05”} rhs(s_goal) = 0; {06”} U.Insert(s_goal, [h(s_start, s_goal); 0]); */ d := &DStarLite{ s: newDStarLiteNode(s), t: newDStarLiteNode(t), // badKey is overwritten below. model: m, heuristic: h, } d.t.rhs = 0 /* procedure Main() {29”} s_last = s_start; {30”} Initialize(); */ d.last = d.s if wg, ok := g.(graph.Weighted); ok { d.weight = wg.Weight } else { d.weight = path.UniformCost(g) } if d.heuristic == nil { if g, ok := g.(path.HeuristicCoster); ok { d.heuristic = g.HeuristicCost } else { d.heuristic = path.NullHeuristic } } d.queue.insert(d.t, key{d.heuristic(s, t), 0}) nodes := g.Nodes() for nodes.Next() { n := nodes.Node() switch n.ID() { case d.s.ID(): d.model.AddNode(d.s) case d.t.ID(): d.model.AddNode(d.t) default: d.model.AddNode(newDStarLiteNode(n)) } } model := d.model.Nodes() for model.Next() { u := model.Node() uid := u.ID() to := g.From(uid) for to.Next() { v := to.Node() vid := v.ID() w := edgeWeight(d.weight, uid, vid) if w < 0 { panic("D* Lite: negative edge weight") } d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: d.model.Node(vid), W: w}) } } /* procedure Main() {31”} ComputeShortestPath(); */ d.findShortestPath() return d } // edgeWeight is a helper function that returns the weight of the edge between // two connected nodes, u and v, using the provided weight function. It panics // if there is no edge between u and v. func edgeWeight(weight path.Weighting, uid, vid int64) float64 { w, ok := weight(uid, vid) if !ok { panic("D* Lite: unexpected invalid weight") } return w } // keyFor is the CalculateKey procedure in the D* Lite papers. func (d *DStarLite) keyFor(s *dStarLiteNode) key { /* procedure CalculateKey(s) {01”} return [min(g(s), rhs(s)) + h(s_start, s) + k_m; min(g(s), rhs(s))]; */ k := key{1: math.Min(s.g, s.rhs)} k[0] = k[1] + d.heuristic(d.s.Node, s.Node) + d.keyModifier return k } // update is the UpdateVertex procedure in the D* Lite papers. func (d *DStarLite) update(u *dStarLiteNode) { /* procedure UpdateVertex(u) {07”} if (g(u) != rhs(u) AND u ∈ U) U.Update(u,CalculateKey(u)); {08”} else if (g(u) != rhs(u) AND u /∈ U) U.Insert(u,CalculateKey(u)); {09”} else if (g(u) = rhs(u) AND u ∈ U) U.Remove(u); */ inQueue := u.inQueue() switch { case inQueue && u.g != u.rhs: d.queue.update(u, d.keyFor(u)) case !inQueue && u.g != u.rhs: d.queue.insert(u, d.keyFor(u)) case inQueue && u.g == u.rhs: d.queue.remove(u) } } // findShortestPath is the ComputeShortestPath procedure in the D* Lite papers. func (d *DStarLite) findShortestPath() { /* procedure ComputeShortestPath() {10”} while (U.TopKey() < CalculateKey(s_start) OR rhs(s_start) > g(s_start)) {11”} u = U.Top(); {12”} k_old = U.TopKey(); {13”} k_new = CalculateKey(u); {14”} if(k_old < k_new) {15”} U.Update(u, k_new); {16”} else if (g(u) > rhs(u)) {17”} g(u) = rhs(u); {18”} U.Remove(u); {19”} for all s ∈ Pred(u) {20”} if (s != s_goal) rhs(s) = min(rhs(s), c(s, u) + g(u)); {21”} UpdateVertex(s); {22”} else {23”} g_old = g(u); {24”} g(u) = ∞; {25”} for all s ∈ Pred(u) ∪ {u} {26”} if (rhs(s) = c(s, u) + g_old) {27”} if (s != s_goal) rhs(s) = min s'∈Succ(s)(c(s, s') + g(s')); {28”} UpdateVertex(s); */ for d.queue.Len() != 0 { // We use d.queue.Len since d.queue does not return an infinite key when empty. u := d.queue.top() if !u.key.less(d.keyFor(d.s)) && d.s.rhs <= d.s.g { break } uid := u.ID() switch kNew := d.keyFor(u); { case u.key.less(kNew): d.queue.update(u, kNew) case u.g > u.rhs: u.g = u.rhs d.queue.remove(u) from := d.model.To(uid) for from.Next() { s := from.Node().(*dStarLiteNode) sid := s.ID() if sid != d.t.ID() { s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, uid)+u.g) } d.update(s) } default: gOld := u.g u.g = math.Inf(1) for _, _s := range append(graph.NodesOf(d.model.To(uid)), u) { s := _s.(*dStarLiteNode) sid := s.ID() if s.rhs == edgeWeight(d.model.Weight, sid, uid)+gOld { if s.ID() != d.t.ID() { s.rhs = math.Inf(1) to := d.model.From(sid) for to.Next() { t := to.Node() tid := t.ID() s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, tid)+t.(*dStarLiteNode).g) } } } d.update(s) } } } } // Step performs one movement step along the best path towards the goal. // It returns false if no further progression toward the goal can be // achieved, either because the goal has been reached or because there // is no path. func (d *DStarLite) Step() bool { /* procedure Main() {32”} while (s_start != s_goal) {33”} // if (rhs(s_start) = ∞) then there is no known path {34”} s_start = argmin s'∈Succ(s_start)(c(s_start, s') + g(s')); */ if d.s.ID() == d.t.ID() { return false } if math.IsInf(d.s.rhs, 1) { return false } // We use rhs comparison to break ties // between coequally weighted nodes. rhs := math.Inf(1) min := math.Inf(1) var next *dStarLiteNode dsid := d.s.ID() to := d.model.From(dsid) for to.Next() { s := to.Node().(*dStarLiteNode) w := edgeWeight(d.model.Weight, dsid, s.ID()) + s.g if w < min || (w == min && s.rhs < rhs) { next = s min = w rhs = s.rhs } } d.s = next /* procedure Main() {35”} Move to s_start; */ return true } // MoveTo moves to n in the world graph. func (d *DStarLite) MoveTo(n graph.Node) { d.last = d.s d.s = d.model.Node(n.ID()).(*dStarLiteNode) d.keyModifier += d.heuristic(d.last, d.s) } // UpdateWorld updates or adds edges in the world graph. UpdateWorld will // panic if changes include a negative edge weight. func (d *DStarLite) UpdateWorld(changes []graph.Edge) { /* procedure Main() {36”} Scan graph for changed edge costs; {37”} if any edge costs changed {38”} k_m = k_m + h(s_last, s_start); {39”} s_last = s_start; {40”} for all directed edges (u, v) with changed edge costs {41”} c_old = c(u, v); {42”} Update the edge cost c(u, v); {43”} if (c_old > c(u, v)) {44”} if (u != s_goal) rhs(u) = min(rhs(u), c(u, v) + g(v)); {45”} else if (rhs(u) = c_old + g(v)) {46”} if (u != s_goal) rhs(u) = min s'∈Succ(u)(c(u, s') + g(s')); {47”} UpdateVertex(u); {48”} ComputeShortestPath() */ if len(changes) == 0 { return } d.keyModifier += d.heuristic(d.last, d.s) d.last = d.s for _, e := range changes { from := e.From() fid := from.ID() to := e.To() tid := to.ID() c, _ := d.weight(fid, tid) if c < 0 { panic("D* Lite: negative edge weight") } cOld, _ := d.model.Weight(fid, tid) u := d.worldNodeFor(from) v := d.worldNodeFor(to) d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: v, W: c}) uid := u.ID() if cOld > c { if uid != d.t.ID() { u.rhs = math.Min(u.rhs, c+v.g) } } else if u.rhs == cOld+v.g { if uid != d.t.ID() { u.rhs = math.Inf(1) to := d.model.From(uid) for to.Next() { t := to.Node() u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, uid, t.ID())+t.(*dStarLiteNode).g) } } } d.update(u) } d.findShortestPath() } func (d *DStarLite) worldNodeFor(n graph.Node) *dStarLiteNode { switch w := d.model.Node(n.ID()).(type) { case *dStarLiteNode: return w case graph.Node: panic(fmt.Sprintf("D* Lite: illegal world model node type: %T", w)) default: return newDStarLiteNode(n) } } // Here returns the current location. func (d *DStarLite) Here() graph.Node { return d.s.Node } // Path returns the path from the current location to the goal and the // weight of the path. func (d *DStarLite) Path() (p []graph.Node, weight float64) { u := d.s p = []graph.Node{u.Node} for u.ID() != d.t.ID() { if math.IsInf(u.rhs, 1) { return nil, math.Inf(1) } // We use stored rhs comparison to break // ties between calculated rhs-coequal nodes. rhsMin := math.Inf(1) min := math.Inf(1) var ( next *dStarLiteNode cost float64 ) uid := u.ID() to := d.model.From(uid) for to.Next() { v := to.Node().(*dStarLiteNode) vid := v.ID() w := edgeWeight(d.model.Weight, uid, vid) if rhs := w + v.g; rhs < min || (rhs == min && v.rhs < rhsMin) { next = v min = rhs rhsMin = v.rhs cost = w } } if next == nil { return nil, math.NaN() } u = next weight += cost p = append(p, u.Node) } return p, weight } /* The pseudocode uses the following functions to manage the priority queue: * U.Top() returns a vertex with the smallest priority of all vertices in priority queue U. * U.TopKey() returns the smallest priority of all vertices in priority queue U. (If is empty, then U.TopKey() returns [∞;∞].) * U.Pop() deletes the vertex with the smallest priority in priority queue U and returns the vertex. * U.Insert(s, k) inserts vertex s into priority queue with priority k. * U.Update(s, k) changes the priority of vertex s in priority queue U to k. (It does nothing if the current priority of vertex s already equals k.) * Finally, U.Remove(s) removes vertex s from priority queue U. */ // key is a D* Lite priority queue key. type key [2]float64 // badKey is a poisoned key. Testing for a bad key uses NaN inequality. var badKey = key{math.NaN(), math.NaN()} func (k key) isBadKey() bool { return k != k } // less returns whether k is less than other. From ISBN:0-262-51129-0 pp476-483: // // k ≤ k' iff k₁ < k'₁ OR (k₁ == k'₁ AND k₂ ≤ k'₂) func (k key) less(other key) bool { if k.isBadKey() || other.isBadKey() { panic("D* Lite: poisoned key") } return k[0] < other[0] || (k[0] == other[0] && k[1] < other[1]) } // dStarLiteNode adds D* Lite accounting to a graph.Node. type dStarLiteNode struct { graph.Node key key idx int rhs float64 g float64 } // newDStarLiteNode returns a dStarLite node that is in a legal state // for existence outside the DStarLite priority queue. func newDStarLiteNode(n graph.Node) *dStarLiteNode { return &dStarLiteNode{ Node: n, rhs: math.Inf(1), g: math.Inf(1), key: badKey, idx: -1, } } // inQueue returns whether the node is in the queue. func (q *dStarLiteNode) inQueue() bool { return q.idx >= 0 } // dStarLiteQueue is a D* Lite priority queue. type dStarLiteQueue []*dStarLiteNode func (q dStarLiteQueue) Less(i, j int) bool { return q[i].key.less(q[j].key) } func (q dStarLiteQueue) Swap(i, j int) { q[i], q[j] = q[j], q[i] q[i].idx = i q[j].idx = j } func (q dStarLiteQueue) Len() int { return len(q) } func (q *dStarLiteQueue) Push(x interface{}) { n := x.(*dStarLiteNode) n.idx = len(*q) *q = append(*q, n) } func (q *dStarLiteQueue) Pop() interface{} { n := (*q)[len(*q)-1] n.idx = -1 *q = (*q)[:len(*q)-1] return n } // top returns the top node in the queue. Note that instead of // returning a key [∞;∞] when q is empty, the caller checks for // an empty queue by calling q.Len. func (q dStarLiteQueue) top() *dStarLiteNode { return q[0] } // insert puts the node u into the queue with the key k. func (q *dStarLiteQueue) insert(u *dStarLiteNode, k key) { u.key = k heap.Push(q, u) } // update updates the node in the queue identified by id with the key k. func (q *dStarLiteQueue) update(n *dStarLiteNode, k key) { n.key = k heap.Fix(q, n.idx) } // remove removes the node identified by id from the queue. func (q *dStarLiteQueue) remove(n *dStarLiteNode) { heap.Remove(q, n.idx) n.key = badKey n.idx = -1 } golang-gonum-v1-gonum-0.14.0/graph/path/dynamic/dstarlite_test.go000066400000000000000000000360241450372207100247050ustar00rootroot00000000000000// 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 dynamic import ( "bytes" "flag" "fmt" "math" "reflect" "strings" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/path" "gonum.org/v1/gonum/graph/path/internal/testgraphs" "gonum.org/v1/gonum/graph/simple" ) var ( debug = flag.Bool("debug", false, "write path progress for failing dynamic case tests") vdebug = flag.Bool("vdebug", false, "write path progress for all dynamic case tests (requires test.v)") maxWide = flag.Int("maxwidth", 5, "maximum width grid to dump for debugging") ) func TestDStarLiteNullHeuristic(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { // Skip zero-weight cycles. if strings.HasPrefix(test.Name, "zero-weight") { continue } g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } var ( d *DStarLite panicked bool ) func() { defer func() { panicked = recover() != nil }() d = NewDStarLite(test.Query.From(), test.Query.To(), g.(graph.Graph), path.NullHeuristic, simple.NewWeightedDirectedGraph(0, math.Inf(1))) }() if panicked || test.HasNegativeWeight { if !test.HasNegativeWeight { t.Errorf("%q: unexpected panic", test.Name) } if !panicked { t.Errorf("%q: expected panic for negative edge weight", test.Name) } continue } p, weight := d.Path() if !math.IsInf(weight, 1) && p[0].ID() != test.Query.From().ID() { t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, p[0].ID(), test.Query.From().ID()) } if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } var got []int64 for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, p, test.WantPaths) } } } var dynamicDStarLiteTests = []struct { g *testgraphs.Grid radius float64 all bool diag, unit bool remember []bool modify func(*testgraphs.LimitedVisionGrid) heuristic func(dx, dy float64) float64 s, t graph.Node want []graph.Node weight float64 wantedPaths map[int64][]graph.Node }{ { // This is the example shown in figures 6 and 7 of doi:10.1109/tro.2004.838026. g: testgraphs.NewGridFrom( "...", ".*.", ".*.", ".*.", "...", ), radius: 1.5, all: true, diag: true, unit: true, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Max(math.Abs(dx), math.Abs(dy)) }, s: simple.Node(3), t: simple.Node(14), want: []graph.Node{ simple.Node(3), simple.Node(6), simple.Node(9), simple.Node(13), simple.Node(14), }, weight: 4, }, { // This is a small example that has the property that the first corner // may be taken incorrectly at 90° or correctly at 45° because the // calculated rhs values of 12 and 17 are tied when moving from node // 16, and the grid is small enough to examine by a dump. g: testgraphs.NewGridFrom( ".....", "...*.", "**.*.", "...*.", ), radius: 1.5, all: true, diag: true, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Max(math.Abs(dx), math.Abs(dy)) }, s: simple.Node(15), t: simple.Node(14), want: []graph.Node{ simple.Node(15), simple.Node(16), simple.Node(12), simple.Node(7), simple.Node(3), simple.Node(9), simple.Node(14), }, weight: 7.242640687119285, wantedPaths: map[int64][]graph.Node{ 12: {simple.Node(12), simple.Node(7), simple.Node(3), simple.Node(9), simple.Node(14)}, }, }, { // This is the example shown in figure 2 of doi:10.1109/tro.2004.838026 // with the exception that diagonal edge weights are calculated with the hypot // function instead of a step count and only allowing information to be known // from exploration. g: testgraphs.NewGridFrom( "..................", "..................", "..................", "..................", "..................", "..................", "....*.*...........", "*****.***.........", "......*...........", "......***.........", "......*...........", "......*...........", "......*...........", "*****.*...........", "......*...........", ), radius: 1.5, all: true, diag: true, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Max(math.Abs(dx), math.Abs(dy)) }, s: simple.Node(253), t: simple.Node(122), want: []graph.Node{ simple.Node(253), simple.Node(254), simple.Node(255), simple.Node(256), simple.Node(239), simple.Node(221), simple.Node(203), simple.Node(185), simple.Node(167), simple.Node(149), simple.Node(131), simple.Node(113), simple.Node(96), // The following section depends // on map iteration order. nil, nil, nil, nil, nil, nil, nil, simple.Node(122), }, weight: 21.242640687119287, }, { // This is the example shown in figure 2 of doi:10.1109/tro.2004.838026 // with the exception that diagonal edge weights are calculated with the hypot // function instead of a step count, not closing the exit and only allowing // information to be known from exploration. g: testgraphs.NewGridFrom( "..................", "..................", "..................", "..................", "..................", "..................", "....*.*...........", "*****.***.........", "..................", // Keep open. "......***.........", "......*...........", "......*...........", "......*...........", "*****.*...........", "......*...........", ), radius: 1.5, all: true, diag: true, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Max(math.Abs(dx), math.Abs(dy)) }, s: simple.Node(253), t: simple.Node(122), want: []graph.Node{ simple.Node(253), simple.Node(254), simple.Node(255), simple.Node(256), simple.Node(239), simple.Node(221), simple.Node(203), simple.Node(185), simple.Node(167), simple.Node(150), simple.Node(151), simple.Node(152), // The following section depends // on map iteration order. nil, nil, nil, nil, nil, simple.Node(122), }, weight: 18.656854249492383, }, { // This is the example shown in figure 2 of doi:10.1109/tro.2004.838026 // with the exception that diagonal edge weights are calculated with the hypot // function instead of a step count, the exit is closed at a distance and // information is allowed to be known from exploration. g: testgraphs.NewGridFrom( "..................", "..................", "..................", "..................", "..................", "..................", "....*.*...........", "*****.***.........", "........*.........", "......***.........", "......*...........", "......*...........", "......*...........", "*****.*...........", "......*...........", ), radius: 1.5, all: true, diag: true, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Max(math.Abs(dx), math.Abs(dy)) }, s: simple.Node(253), t: simple.Node(122), want: []graph.Node{ simple.Node(253), simple.Node(254), simple.Node(255), simple.Node(256), simple.Node(239), simple.Node(221), simple.Node(203), simple.Node(185), simple.Node(167), simple.Node(150), simple.Node(151), simple.Node(150), simple.Node(131), simple.Node(113), simple.Node(96), // The following section depends // on map iteration order. nil, nil, nil, nil, nil, nil, nil, simple.Node(122), }, weight: 24.07106781186548, }, { // This is the example shown in figure 2 of doi:10.1109/tro.2004.838026 // with the exception that diagonal edge weights are calculated with the hypot // function instead of a step count. g: testgraphs.NewGridFrom( "..................", "..................", "..................", "..................", "..................", "..................", "....*.*...........", "*****.***.........", "......*...........", // Forget this wall. "......***.........", "......*...........", "......*...........", "......*...........", "*****.*...........", "......*...........", ), radius: 1.5, all: true, diag: true, remember: []bool{true}, modify: func(l *testgraphs.LimitedVisionGrid) { all := l.Grid.AllVisible l.Grid.AllVisible = false for _, n := range graph.NodesOf(l.Nodes()) { id := n.ID() l.Known[id] = l.Grid.Node(id) == nil } l.Grid.AllVisible = all const ( wallRow = 8 wallCol = 6 ) l.Known[l.NodeAt(wallRow, wallCol).ID()] = false // Check we have a correctly modified representation. nodes := graph.NodesOf(l.Nodes()) for _, u := range nodes { uid := u.ID() for _, v := range nodes { vid := v.ID() if l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) { ur, uc := l.RowCol(uid) vr, vc := l.RowCol(vid) if (ur == wallRow && uc == wallCol) || (vr == wallRow && vc == wallCol) { if !l.HasEdgeBetween(uid, vid) { panic(fmt.Sprintf("expected to believe edge between %v (%d,%d) and %v (%d,%d) is passable", u, v, ur, uc, vr, vc)) } continue } panic(fmt.Sprintf("disagreement about edge between %v (%d,%d) and %v (%d,%d): got:%t want:%t", u, v, ur, uc, vr, vc, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid))) } } } }, heuristic: func(dx, dy float64) float64 { return math.Max(math.Abs(dx), math.Abs(dy)) }, s: simple.Node(253), t: simple.Node(122), want: []graph.Node{ simple.Node(253), simple.Node(254), simple.Node(255), simple.Node(256), simple.Node(239), simple.Node(221), simple.Node(203), simple.Node(185), simple.Node(167), simple.Node(149), simple.Node(131), simple.Node(113), simple.Node(96), // The following section depends // on map iteration order. nil, nil, nil, nil, nil, nil, nil, simple.Node(122), }, weight: 21.242640687119287, }, { g: testgraphs.NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1, all: true, diag: false, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Hypot(dx, dy) }, s: simple.Node(1), t: simple.Node(14), want: []graph.Node{ simple.Node(1), simple.Node(2), simple.Node(6), simple.Node(10), simple.Node(14), }, weight: 4, }, { g: testgraphs.NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1.5, all: true, diag: true, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Hypot(dx, dy) }, s: simple.Node(1), t: simple.Node(14), want: []graph.Node{ simple.Node(1), simple.Node(6), simple.Node(10), simple.Node(14), }, weight: math.Sqrt2 + 2, }, { g: testgraphs.NewGridFrom( "...", ".*.", ".*.", ".*.", ".*.", ), radius: 1, all: true, diag: false, remember: []bool{false, true}, heuristic: func(dx, dy float64) float64 { return math.Hypot(dx, dy) }, s: simple.Node(6), t: simple.Node(14), want: []graph.Node{ simple.Node(6), simple.Node(9), simple.Node(12), simple.Node(9), simple.Node(6), simple.Node(3), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(5), simple.Node(8), simple.Node(11), simple.Node(14), }, weight: 12, }, } func TestDStarLiteDynamic(t *testing.T) { t.Parallel() for i, test := range dynamicDStarLiteTests { for _, remember := range test.remember { l := &testgraphs.LimitedVisionGrid{ Grid: test.g, VisionRadius: test.radius, Location: test.s, } if remember { l.Known = make(map[int64]bool) } l.Grid.AllVisible = test.all l.Grid.AllowDiagonal = test.diag l.Grid.UnitEdgeWeight = test.unit if test.modify != nil { test.modify(l) } got := []graph.Node{test.s} l.MoveTo(test.s) heuristic := func(a, b graph.Node) float64 { ax, ay := l.XY(a.ID()) bx, by := l.XY(b.ID()) return test.heuristic(ax-bx, ay-by) } world := simple.NewWeightedDirectedGraph(0, math.Inf(1)) d := NewDStarLite(test.s, test.t, l, heuristic, world) var ( dp *dumper buf bytes.Buffer ) _, c := l.Grid.Dims() if c <= *maxWide && (*debug || *vdebug) { dp = &dumper{ w: &buf, dStarLite: d, grid: l, } } dp.dump(true) dp.printEdges("Initial world knowledge: %s\n\n", simpleWeightedEdgesOf(l, graph.EdgesOf(world.Edges()))) for d.Step() { changes, _ := l.MoveTo(d.Here()) got = append(got, l.Location) d.UpdateWorld(changes) dp.dump(true) if wantedPath, ok := test.wantedPaths[l.Location.ID()]; ok { gotPath, _ := d.Path() if !samePath(gotPath, wantedPath) { t.Errorf("unexpected intermediate path estimation for test %d %s memory:\ngot: %v\nwant:%v", i, memory(remember), gotPath, wantedPath) } } dp.printEdges("Edges changing after last step:\n%s\n\n", simpleWeightedEdgesOf(l, changes)) } if weight := weightOf(got, l.Grid); !samePath(got, test.want) || weight != test.weight { t.Errorf("unexpected path for test %d %s memory got weight:%v want weight:%v:\ngot: %v\nwant:%v", i, memory(remember), weight, test.weight, got, test.want) b, err := l.Render(got) t.Errorf("path taken (err:%v):\n%s", err, b) if c <= *maxWide && (*debug || *vdebug) { t.Error(buf.String()) } } else if c <= *maxWide && *vdebug { t.Logf("Test %d:\n%s", i, buf.String()) } } } } type memory bool func (m memory) String() string { if m { return "with" } return "without" } // samePath compares two paths for equality ignoring nodes that are nil. func samePath(a, b []graph.Node) bool { if len(a) != len(b) { return false } for i, e := range a { if e == nil || b[i] == nil { continue } if e.ID() != b[i].ID() { return false } } return true } // weightOf return the weight of the path in g. func weightOf(path []graph.Node, g graph.Weighted) float64 { var w float64 if len(path) > 1 { for p, n := range path[1:] { ew, ok := g.Weight(path[p].ID(), n.ID()) if !ok { return math.Inf(1) } w += ew } } return w } // simpleWeightedEdgesOf returns the weighted edges in g corresponding to the given edges. func simpleWeightedEdgesOf(g graph.Weighted, edges []graph.Edge) []simple.WeightedEdge { w := make([]simple.WeightedEdge, len(edges)) for i, e := range edges { w[i].F = e.From() w[i].T = e.To() ew, _ := g.Weight(e.From().ID(), e.To().ID()) w[i].W = ew } return w } golang-gonum-v1-gonum-0.14.0/graph/path/dynamic/dumper_test.go000066400000000000000000000076251450372207100242130ustar00rootroot00000000000000// 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 dynamic import ( "bytes" "fmt" "io" "sort" "text/tabwriter" "gonum.org/v1/gonum/graph/path/internal/testgraphs" "gonum.org/v1/gonum/graph/simple" ) // dumper implements a grid D* Lite statistics dump. type dumper struct { step int dStarLite *DStarLite grid *testgraphs.LimitedVisionGrid w io.Writer } // dump writes a single step of a D* Lite path search to the dumper's io.Writer. func (d *dumper) dump(withpath bool) { if d == nil { return } var pathStep map[int64]int if withpath { pathStep = make(map[int64]int) path, _ := d.dStarLite.Path() for i, n := range path { pathStep[n.ID()] = i } } fmt.Fprintf(d.w, "Step:%d kₘ=%v\n", d.step, d.dStarLite.keyModifier) d.step++ w := tabwriter.NewWriter(d.w, 0, 0, 0, ' ', tabwriter.Debug) rows, cols := d.grid.Grid.Dims() for r := 0; r < rows; r++ { if r == 0 { for c := 0; c < cols; c++ { if c != 0 { fmt.Fprint(w, "\t") } fmt.Fprint(w, "-------------------") } fmt.Fprintln(w) } for ln := 0; ln < 6; ln++ { for c := 0; c < cols; c++ { if c != 0 { fmt.Fprint(w, "\t") } n := d.dStarLite.model.Node(d.grid.NodeAt(r, c).ID()).(*dStarLiteNode) switch ln { case 0: if n.ID() == d.grid.Location.ID() { if d.grid.Grid.HasOpen(n.ID()) { fmt.Fprintf(w, "id:%2d >@<", n.ID()) } else { // Mark location as illegal. fmt.Fprintf(w, "id:%2d >!<", n.ID()) } } else if n.ID() == d.dStarLite.t.ID() { fmt.Fprintf(w, "id:%2d G", n.ID()) // Mark goal cell as illegal. if !d.grid.Grid.HasOpen(n.ID()) { fmt.Fprint(w, "!") } } else if pathStep[n.ID()] > 0 { fmt.Fprintf(w, "id:%2d %2d", n.ID(), pathStep[n.ID()]) // Mark path cells with an obstruction. if !d.grid.Grid.HasOpen(n.ID()) { fmt.Fprint(w, "!") } } else { fmt.Fprintf(w, "id:%2d", n.ID()) // Mark cells with an obstruction. if !d.grid.Grid.HasOpen(n.ID()) { fmt.Fprint(w, " *") } } case 1: fmt.Fprintf(w, "h: %.4v", d.dStarLite.heuristic(n, d.dStarLite.Here())) case 2: fmt.Fprintf(w, "g: %.4v", n.g) case 3: fmt.Fprintf(w, "rhs:%.4v", n.rhs) case 4: if n.g != n.rhs { fmt.Fprintf(w, "key:%.3f", n.key) } if !n.key.isBadKey() { // Mark keys for nodes in the priority queue. // We use NaN inequality for this check since all // keys not in the queue must have their key set // to badKey. // // This should always mark cells where key is // printed. fmt.Fprint(w, "*") } if n.g > n.rhs { fmt.Fprint(w, "^") } if n.g < n.rhs { fmt.Fprint(w, "v") } default: fmt.Fprint(w, "-------------------") } } fmt.Fprintln(w) } } w.Flush() fmt.Fprintln(d.w) } // printEdges pretty prints the given edges to the dumper's io.Writer using the provided // format string. The edges are first formatted to a string, so the format string must use // the %s verb to indicate where the edges are to be printed. func (d *dumper) printEdges(format string, edges []simple.WeightedEdge) { if d == nil { return } var buf bytes.Buffer sort.Sort(lexically(edges)) for i, e := range edges { if i != 0 { fmt.Fprint(&buf, ", ") } fmt.Fprintf(&buf, "%d->%d:%.4v", e.From().ID(), e.To().ID(), e.Weight()) } if len(edges) == 0 { fmt.Fprint(&buf, "none") } fmt.Fprintf(d.w, format, buf.Bytes()) } type lexically []simple.WeightedEdge func (l lexically) Len() int { return len(l) } func (l lexically) Less(i, j int) bool { return l[i].From().ID() < l[j].From().ID() || (l[i].From().ID() == l[j].From().ID() && l[i].To().ID() < l[j].To().ID()) } func (l lexically) Swap(i, j int) { l[i], l[j] = l[j], l[i] } golang-gonum-v1-gonum-0.14.0/graph/path/floydwarshall.go000066400000000000000000000041541450372207100231010ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "gonum.org/v1/gonum/graph" ) // FloydWarshall returns a shortest-path tree for the graph g or false indicating // that a negative cycle exists in the graph. If a negative cycle exists in the graph // the returned paths will be valid and edge weights on the negative cycle will be // set to -Inf. If the graph does not implement Weighted, UniformCost is used. // // The time complexity of FloydWarshall is O(|V|^3). func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) { var weight Weighting if wg, ok := g.(Weighted); ok { weight = wg.Weight } else { weight = UniformCost(g) } nodes := graph.NodesOf(g.Nodes()) paths = newAllShortest(nodes, true) for i, u := range nodes { paths.dist.Set(i, i, 0) uid := u.ID() to := g.From(uid) for to.Next() { vid := to.Node().ID() j := paths.indexOf[vid] w, ok := weight(uid, vid) if !ok { panic("floyd-warshall: unexpected invalid weight") } paths.set(i, j, w, j) } } for k := range nodes { for i := range nodes { for j := range nodes { ij := paths.dist.At(i, j) joint := paths.dist.At(i, k) + paths.dist.At(k, j) if ij > joint { paths.set(i, j, joint, paths.at(i, k)...) } else if ij-joint == 0 { paths.add(i, j, paths.at(i, k)...) } } } } ok = true for i := range nodes { if paths.dist.At(i, i) < 0 { ok = false break } } if !ok { // If we have a negative cycle, mark all // the edges in the cycles with NaN(0xdefaced) // weight. These weights are internal, being // returned as -Inf in user calls. d := paths.dist for i := range nodes { for j := range nodes { for k := range nodes { if math.IsInf(d.At(i, k), 1) || math.IsInf(d.At(k, j), 1) { continue } if d.At(k, k) < 0 { d.Set(k, k, defaced) d.Set(i, j, defaced) } else if math.Float64bits(d.At(k, k)) == defacedBits { d.Set(i, j, defaced) } } } } } return paths, ok } golang-gonum-v1-gonum-0.14.0/graph/path/floydwarshall_test.go000066400000000000000000000066241450372207100241440ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/path/internal/testgraphs" ) func TestFloydWarshall(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } pt, ok := FloydWarshall(g.(graph.Graph)) if test.HasNegativeCycle { if ok { t.Errorf("%q: expected negative cycle", test.Name) } continue } if !ok { t.Fatalf("%q: unexpected negative cycle", test.Name) } // Check all random paths returned are OK. for i := 0; i < 10; i++ { p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight { t.Errorf("%q: unexpected weight from Weight: got:%f want:%f", test.Name, weight, test.Weight) } if unique != test.HasUniquePath { t.Errorf("%q: unexpected number of paths: got: unique=%t want: unique=%t", test.Name, unique, test.HasUniquePath) } var got []int64 for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, p, test.WantPaths) } } np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID()) if np != nil || !math.IsInf(weight, 1) || unique { t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path= weight=+Inf unique=false", test.Name, np, weight, unique) } paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } var got [][]int64 if len(paths) != 0 { got = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, got, test.WantPaths) } paths = paths[:0] pt.AllBetweenFunc(test.Query.From().ID(), test.Query.To().ID(), func(path []graph.Node) { paths = append(paths, append([]graph.Node(nil), path...)) }) got = nil if len(paths) != 0 { got = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, got, test.WantPaths) } nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID()) if nps != nil || !math.IsInf(weight, 1) { t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path= weight=+Inf", test.Name, nps, weight) } } } golang-gonum-v1-gonum-0.14.0/graph/path/internal/000077500000000000000000000000001450372207100215075ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/000077500000000000000000000000001450372207100236735ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/doc.go000066400000000000000000000005551450372207100247740ustar00rootroot00000000000000// 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 testsgraphs provides a number of graphs used for testing // routines in the path and path/dynamic packages. package testgraphs // import "gonum.org/v1/gonum/graph/path/internal/testgraphs" golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/grid.go000066400000000000000000000166601450372207100251600ustar00rootroot00000000000000// 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 testgraphs import ( "errors" "fmt" "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) const ( Closed = '*' // Closed is the closed grid node representation. Open = '.' // Open is the open grid node representation. Unknown = '?' // Unknown is the unknown grid node representation. ) // Grid is a 2D grid planar undirected graph. type Grid struct { // AllowDiagonal specifies whether // diagonally adjacent nodes can // be connected by an edge. AllowDiagonal bool // UnitEdgeWeight specifies whether // finite edge weights are returned as // the unit length. Otherwise edge // weights are the Euclidean distance // between connected nodes. UnitEdgeWeight bool // AllVisible specifies whether // non-open nodes are visible // in calls to Nodes and HasNode. AllVisible bool open []bool r, c int } // NewGrid returns an r by c grid with all positions // set to the specified open state. func NewGrid(r, c int, open bool) *Grid { states := make([]bool, r*c) if open { for i := range states { states[i] = true } } return &Grid{ open: states, r: r, c: c, } } // NewGridFrom returns a grid specified by the rows strings. All rows must // be the same length and must only contain the Open or Closed characters, // NewGridFrom will panic otherwise. func NewGridFrom(rows ...string) *Grid { if len(rows) == 0 { return nil } for i, r := range rows[:len(rows)-1] { if len(r) != len(rows[i+1]) { panic("grid: unequal row lengths") } } states := make([]bool, 0, len(rows)*len(rows[0])) for _, r := range rows { for _, b := range r { switch b { case Closed: states = append(states, false) case Open: states = append(states, true) default: panic(fmt.Sprintf("grid: invalid state: %q", r)) } } } return &Grid{ open: states, r: len(rows), c: len(rows[0]), } } // Nodes returns all the open nodes in the grid if AllVisible is // false, otherwise all nodes are returned. func (g *Grid) Nodes() graph.Nodes { var nodes []graph.Node for id, ok := range g.open { if ok || g.AllVisible { nodes = append(nodes, simple.Node(id)) } } return iterator.NewOrderedNodes(nodes) } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *Grid) Node(id int64) graph.Node { if g.has(id) { return simple.Node(id) } return nil } // has returns whether id represents a node in the grid. The state of // the AllVisible field determines whether a non-open node is present. func (g *Grid) has(id int64) bool { return 0 <= id && id < int64(len(g.open)) && (g.AllVisible || g.open[id]) } // HasOpen returns whether n is an open node in the grid. func (g *Grid) HasOpen(id int64) bool { return 0 <= id && id < int64(len(g.open)) && g.open[id] } // Set sets the node at position (r, c) to the specified open state. func (g *Grid) Set(r, c int, open bool) { if r < 0 || r >= g.r { panic("grid: illegal row index") } if c < 0 || c >= g.c { panic("grid: illegal column index") } g.open[r*g.c+c] = open } // Dims returns the dimensions of the grid. func (g *Grid) Dims() (r, c int) { return g.r, g.c } // RowCol returns the row and column of the id. RowCol will panic if the // node id is outside the range of the grid. func (g *Grid) RowCol(id int64) (r, c int) { if id < 0 || int64(len(g.open)) <= id { panic("grid: illegal node id") } return int(id) / g.c, int(id) % g.c } // XY returns the cartesian coordinates of n. If n is not a node // in the grid, (NaN, NaN) is returned. func (g *Grid) XY(id int64) (x, y float64) { if !g.has(id) { return math.NaN(), math.NaN() } r, c := g.RowCol(id) return float64(c), float64(r) } // NodeAt returns the node at (r, c). The returned node may be open or closed. func (g *Grid) NodeAt(r, c int) graph.Node { if r < 0 || r >= g.r || c < 0 || c >= g.c { return nil } return simple.Node(r*g.c + c) } // From returns all the nodes reachable from u. Reachabilty requires that both // ends of an edge must be open. func (g *Grid) From(uid int64) graph.Nodes { if !g.HasOpen(uid) { return graph.Empty } nr, nc := g.RowCol(uid) var to []graph.Node for r := nr - 1; r <= nr+1; r++ { for c := nc - 1; c <= nc+1; c++ { if v := g.NodeAt(r, c); v != nil && g.HasEdgeBetween(uid, v.ID()) { to = append(to, v) } } } if len(to) == 0 { return graph.Empty } return iterator.NewOrderedNodes(to) } // HasEdgeBetween returns whether there is an edge between u and v. func (g *Grid) HasEdgeBetween(uid, vid int64) bool { if !g.HasOpen(uid) || !g.HasOpen(vid) || uid == vid { return false } ur, uc := g.RowCol(uid) vr, vc := g.RowCol(vid) if abs(ur-vr) > 1 || abs(uc-vc) > 1 { return false } return g.AllowDiagonal || ur == vr || uc == vc } func abs(i int) int { if i < 0 { return -i } return i } // Edge returns the edge between u and v. func (g *Grid) Edge(uid, vid int64) graph.Edge { return g.WeightedEdgeBetween(uid, vid) } // WeightedEdge returns the weighted edge between u and v. func (g *Grid) WeightedEdge(uid, vid int64) graph.WeightedEdge { return g.WeightedEdgeBetween(uid, vid) } // EdgeBetween returns the edge between u and v. func (g *Grid) EdgeBetween(uid, vid int64) graph.Edge { return g.WeightedEdgeBetween(uid, vid) } // WeightedEdgeBetween returns the weighted edge between u and v. func (g *Grid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge { if g.HasEdgeBetween(uid, vid) { if !g.AllowDiagonal || g.UnitEdgeWeight { return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1} } ux, uy := g.XY(uid) vx, vy := g.XY(vid) return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)} } return nil } // Weight returns the weight of the given edge. func (g *Grid) Weight(xid, yid int64) (w float64, ok bool) { if xid == yid { return 0, true } if !g.HasEdgeBetween(xid, yid) { return math.Inf(1), false } if e := g.EdgeBetween(xid, yid); e != nil { if !g.AllowDiagonal || g.UnitEdgeWeight { return 1, true } ux, uy := g.XY(e.From().ID()) vx, vy := g.XY(e.To().ID()) return math.Hypot(ux-vx, uy-vy), true } return math.Inf(1), true } // String returns a string representation of the grid. func (g *Grid) String() string { b, _ := g.Render(nil) return string(b) } // Render returns a text representation of the graph // with the given path included. If the path is not a path // in the grid Render returns a non-nil error and the // path up to that point. func (g *Grid) Render(path []graph.Node) ([]byte, error) { b := make([]byte, g.r*(g.c+1)-1) for r := 0; r < g.r; r++ { for c := 0; c < g.c; c++ { if g.open[r*g.c+c] { b[r*(g.c+1)+c] = Open } else { b[r*(g.c+1)+c] = Closed } } if r < g.r-1 { b[r*(g.c+1)+g.c] = '\n' } } // We don't use topo.IsPathIn at the outset because we // want to draw as much as possible before failing. for i, n := range path { id := n.ID() if !g.has(id) || (i != 0 && !g.HasEdgeBetween(path[i-1].ID(), id)) { if 0 <= id && id < int64(len(g.open)) { r, c := g.RowCol(id) b[r*(g.c+1)+c] = '!' } return b, errors.New("grid: not a path in graph") } r, c := g.RowCol(id) switch i { case len(path) - 1: b[r*(g.c+1)+c] = 'G' case 0: b[r*(g.c+1)+c] = 'S' default: b[r*(g.c+1)+c] = 'o' } } return b, nil } golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/grid_test.go000066400000000000000000000110421450372207100262040ustar00rootroot00000000000000// 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 testgraphs import ( "bytes" "errors" "reflect" "strings" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) var _ graph.Graph = (*Grid)(nil) func join(g ...string) string { return strings.Join(g, "\n") } type node int64 func (n node) ID() int64 { return int64(n) } func TestGrid(t *testing.T) { t.Parallel() g := NewGrid(4, 4, false) got := g.String() want := join( "****", "****", "****", "****", ) if got != want { t.Fatalf("unexpected grid rendering:\ngot: %q\nwant:%q", got, want) } var ops = []struct { r, c int state bool want string }{ { r: 0, c: 1, state: true, want: join( "*.**", "****", "****", "****", ), }, { r: 0, c: 1, state: false, want: join( "****", "****", "****", "****", ), }, { r: 0, c: 1, state: true, want: join( "*.**", "****", "****", "****", ), }, { r: 0, c: 2, state: true, want: join( "*..*", "****", "****", "****", ), }, { r: 1, c: 2, state: true, want: join( "*..*", "**.*", "****", "****", ), }, { r: 2, c: 2, state: true, want: join( "*..*", "**.*", "**.*", "****", ), }, { r: 3, c: 2, state: true, want: join( "*..*", "**.*", "**.*", "**.*", ), }, } for _, test := range ops { g.Set(test.r, test.c, test.state) got := g.String() if got != test.want { t.Fatalf("unexpected grid rendering after set (%d, %d) open state to %t:\ngot: %q\nwant:%q", test.r, test.c, test.state, got, test.want) } } // Match the last state from the loop against the // explicit description of the grid. got = NewGridFrom( "*..*", "**.*", "**.*", "**.*", ).String() want = g.String() if got != want { t.Fatalf("unexpected grid rendering from NewGridFrom:\ngot: %q\nwant:%q", got, want) } var paths = []struct { path []graph.Node diagonal bool want string }{ { path: nil, diagonal: false, want: join( "*..*", "**.*", "**.*", "**.*", ), }, { path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, diagonal: false, want: join( "*So*", "**o*", "**o*", "**G*", ), }, { path: []graph.Node{node(1), node(6), node(10), node(14)}, diagonal: false, want: join( "*S.*", "**!*", "**.*", "**.*", ), }, { path: []graph.Node{node(1), node(6), node(10), node(14)}, diagonal: true, want: join( "*S.*", "**o*", "**o*", "**G*", ), }, { path: []graph.Node{node(1), node(5), node(9)}, diagonal: false, want: join( "*S.*", "*!.*", "**.*", "**.*", ), }, } for _, test := range paths { g.AllowDiagonal = test.diagonal got, err := g.Render(test.path) errored := err != nil if bytes.Contains(got, []byte{'!'}) != errored { t.Fatalf("unexpected error return: got:%v want:%v", err, errors.New("grid: not a path in graph")) } if string(got) != test.want { t.Fatalf("unexpected grid path rendering for %v:\ngot: %q\nwant:%q", test.path, got, want) } } var coords = []struct { r, c int id int64 }{ {r: 0, c: 0, id: 0}, {r: 0, c: 3, id: 3}, {r: 3, c: 0, id: 12}, {r: 3, c: 3, id: 15}, } for _, test := range coords { if id := g.NodeAt(test.r, test.c).ID(); id != test.id { t.Fatalf("unexpected ID for node at (%d, %d):\ngot: %d\nwant:%d", test.r, test.c, id, test.id) } if r, c := g.RowCol(test.id); r != test.r || c != test.c { t.Fatalf("unexpected row/col for node %d:\ngot: (%d, %d)\nwant:(%d, %d)", test.id, r, c, test.r, test.c) } } var reach = []struct { from graph.Node diagonal bool to []graph.Node }{ { from: node(0), diagonal: false, to: nil, }, { from: node(2), diagonal: false, to: []graph.Node{simple.Node(1), simple.Node(6)}, }, { from: node(1), diagonal: false, to: []graph.Node{simple.Node(2)}, }, { from: node(1), diagonal: true, to: []graph.Node{simple.Node(2), simple.Node(6)}, }, } for _, test := range reach { g.AllowDiagonal = test.diagonal got := graph.NodesOf(g.From(test.from.ID())) if !reflect.DeepEqual(got, test.to) { t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v", test.from, test.diagonal, got, test.to) } } } golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/limited.go000066400000000000000000000202761450372207100256600ustar00rootroot00000000000000// 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 testgraphs import ( "errors" "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" ) // LimitedVisionGrid is a 2D grid planar undirected graph where the capacity // to determine the presence of edges is dependent on the current and past // positions on the grid. In the absence of information, the grid is // optimistic. type LimitedVisionGrid struct { Grid *Grid // Location is the current // location on the grid. Location graph.Node // VisionRadius specifies how far // away edges can be detected. VisionRadius float64 // Known holds a store of known // nodes, if not nil. Known map[int64]bool } // MoveTo moves to the node n on the grid and returns a slice of newly seen and // already known edges. MoveTo panics if n is nil. func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) { l.Location = n row, column := l.RowCol(n.ID()) x := float64(column) y := float64(row) seen := make(map[[2]int64]bool) bound := int(l.VisionRadius + 0.5) for r := row - bound; r <= row+bound; r++ { for c := column - bound; c <= column+bound; c++ { u := l.NodeAt(r, c) if u == nil { continue } uid := u.ID() ux, uy := l.XY(uid) if math.Hypot(x-ux, y-uy) > l.VisionRadius { continue } for _, v := range l.allPossibleFrom(uid) { vid := v.ID() if seen[[2]int64{uid, vid}] { continue } seen[[2]int64{uid, vid}] = true vx, vy := l.XY(vid) if !l.Known[vid] && math.Hypot(x-vx, y-vy) > l.VisionRadius { continue } e := simple.Edge{F: u, T: v} if !l.Known[uid] || !l.Known[vid] { new = append(new, e) } else { old = append(old, e) } } } } if l.Known != nil { for r := row - bound; r <= row+bound; r++ { for c := column - bound; c <= column+bound; c++ { u := l.NodeAt(r, c) if u == nil { continue } uid := u.ID() ux, uy := l.XY(uid) if math.Hypot(x-ux, y-uy) > l.VisionRadius { continue } for _, v := range l.allPossibleFrom(uid) { vid := v.ID() vx, vy := l.XY(vid) if math.Hypot(x-vx, y-vy) > l.VisionRadius { continue } l.Known[vid] = true } l.Known[uid] = true } } } return new, old } // allPossibleFrom returns all the nodes possibly reachable from u. func (l *LimitedVisionGrid) allPossibleFrom(uid int64) []graph.Node { if !l.has(uid) { return nil } nr, nc := l.RowCol(uid) var to []graph.Node for r := nr - 1; r <= nr+1; r++ { for c := nc - 1; c <= nc+1; c++ { v := l.NodeAt(r, c) if v == nil || uid == v.ID() { continue } ur, uc := l.RowCol(uid) vr, vc := l.RowCol(v.ID()) if abs(ur-vr) > 1 || abs(uc-vc) > 1 { continue } if !l.Grid.AllowDiagonal && ur != vr && uc != vc { continue } to = append(to, v) } } return to } // RowCol returns the row and column of the id. RowCol will panic if the // node id is outside the range of the grid. func (l *LimitedVisionGrid) RowCol(id int64) (r, c int) { return l.Grid.RowCol(id) } // XY returns the cartesian coordinates of n. If n is not a node // in the grid, (NaN, NaN) is returned. func (l *LimitedVisionGrid) XY(id int64) (x, y float64) { if !l.has(id) { return math.NaN(), math.NaN() } r, c := l.RowCol(id) return float64(c), float64(r) } // Nodes returns all the nodes in the grid. func (l *LimitedVisionGrid) Nodes() graph.Nodes { nodes := make([]graph.Node, 0, len(l.Grid.open)) for id := range l.Grid.open { nodes = append(nodes, simple.Node(id)) } return iterator.NewOrderedNodes(nodes) } // NodeAt returns the node at (r, c). The returned node may be open or closed. func (l *LimitedVisionGrid) NodeAt(r, c int) graph.Node { return l.Grid.NodeAt(r, c) } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (l *LimitedVisionGrid) Node(id int64) graph.Node { if l.has(id) { return simple.Node(id) } return nil } // has returns whether the node with the given ID is a node in the grid. func (l *LimitedVisionGrid) has(id int64) bool { return 0 <= id && id < int64(len(l.Grid.open)) } // From returns nodes that are optimistically reachable from u. func (l *LimitedVisionGrid) From(uid int64) graph.Nodes { if !l.has(uid) { return graph.Empty } nr, nc := l.RowCol(uid) var to []graph.Node for r := nr - 1; r <= nr+1; r++ { for c := nc - 1; c <= nc+1; c++ { if v := l.NodeAt(r, c); v != nil && l.HasEdgeBetween(uid, v.ID()) { to = append(to, v) } } } if len(to) == 0 { return graph.Empty } return iterator.NewOrderedNodes(to) } // HasEdgeBetween optimistically returns whether an edge is exists between u and v. func (l *LimitedVisionGrid) HasEdgeBetween(uid, vid int64) bool { if uid == vid { return false } ur, uc := l.RowCol(uid) vr, vc := l.RowCol(vid) if abs(ur-vr) > 1 || abs(uc-vc) > 1 { return false } if !l.Grid.AllowDiagonal && ur != vr && uc != vc { return false } x, y := l.XY(l.Location.ID()) ux, uy := l.XY(uid) vx, vy := l.XY(vid) uKnown := l.Known[uid] || math.Hypot(x-ux, y-uy) <= l.VisionRadius vKnown := l.Known[vid] || math.Hypot(x-vx, y-vy) <= l.VisionRadius switch { case uKnown && vKnown: return l.Grid.HasEdgeBetween(uid, vid) case uKnown: return l.Grid.HasOpen(uid) case vKnown: return l.Grid.HasOpen(vid) default: return true } } // Edge optimistically returns the edge from u to v. func (l *LimitedVisionGrid) Edge(uid, vid int64) graph.Edge { return l.WeightedEdgeBetween(uid, vid) } // Edge optimistically returns the weighted edge from u to v. func (l *LimitedVisionGrid) WeightedEdge(uid, vid int64) graph.WeightedEdge { return l.WeightedEdgeBetween(uid, vid) } // WeightedEdgeBetween optimistically returns the edge between u and v. func (l *LimitedVisionGrid) EdgeBetween(uid, vid int64) graph.Edge { return l.WeightedEdgeBetween(uid, vid) } // WeightedEdgeBetween optimistically returns the weighted edge between u and v. func (l *LimitedVisionGrid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge { if l.HasEdgeBetween(uid, vid) { if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight { return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1} } ux, uy := l.XY(uid) vx, vy := l.XY(vid) return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)} } return nil } // Weight returns the weight of the given edge. func (l *LimitedVisionGrid) Weight(xid, yid int64) (w float64, ok bool) { if xid == yid { return 0, true } if !l.HasEdgeBetween(xid, yid) { return math.Inf(1), false } if e := l.EdgeBetween(xid, yid); e != nil { if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight { return 1, true } ux, uy := l.XY(e.From().ID()) vx, vy := l.XY(e.To().ID()) return math.Hypot(ux-vx, uy-vy), true } return math.Inf(1), true } // String returns a string representation of the grid. func (l *LimitedVisionGrid) String() string { b, _ := l.Render(nil) return string(b) } // Render returns a text representation of the graph // with the given path included. If the path is not a path // in the grid Render returns a non-nil error and the // path up to that point. func (l *LimitedVisionGrid) Render(path []graph.Node) ([]byte, error) { rows, cols := l.Grid.Dims() b := make([]byte, rows*(cols+1)-1) for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { if !l.Known[int64(r*cols+c)] { b[r*(cols+1)+c] = Unknown } else if l.Grid.open[r*cols+c] { b[r*(cols+1)+c] = Open } else { b[r*(cols+1)+c] = Closed } } if r < rows-1 { b[r*(cols+1)+cols] = '\n' } } // We don't use topo.IsPathIn at the outset because we // want to draw as much as possible before failing. for i, n := range path { id := n.ID() if !l.has(id) || (i != 0 && !l.HasEdgeBetween(path[i-1].ID(), id)) { if 0 <= id && id < int64(len(l.Grid.open)) { r, c := l.RowCol(id) b[r*(cols+1)+c] = '!' } return b, errors.New("grid: not a path in graph") } r, c := l.RowCol(id) switch i { case len(path) - 1: b[r*(cols+1)+c] = 'G' case 0: b[r*(cols+1)+c] = 'S' default: b[r*(cols+1)+c] = 'o' } } return b, nil } golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/limited_test.go000066400000000000000000001472041450372207100267200ustar00rootroot00000000000000// 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 testgraphs import ( "math" "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) type changes struct { n graph.Node new, old []simple.WeightedEdge } var limitedVisionTests = []struct { g *Grid radius float64 diag bool remember bool path []graph.Node want []changes }{ { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1, diag: false, remember: false, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, }, old: nil, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, }, old: nil, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, }, old: nil, }, { n: node(14), new: []simple.WeightedEdge{ {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: nil, }, }, }, { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1.5, diag: false, remember: false, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(4), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(4), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, }, old: nil, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, }, old: nil, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: nil, }, { n: node(14), new: []simple.WeightedEdge{ {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: nil, }, }, }, { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1, diag: false, remember: true, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, }, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, }, old: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, }, old: []simple.WeightedEdge{ {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(10), T: simple.Node(6), W: 1}, }, }, { n: node(14), new: []simple.WeightedEdge{ {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(14), T: simple.Node(10), W: 1}, }, }, }, }, { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1.5, diag: false, remember: true, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(4), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(4), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, }, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, }, }, { n: node(14), new: nil, old: []simple.WeightedEdge{ {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, }, }, }, { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1, diag: true, remember: false, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, }, old: nil, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(2), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, }, old: nil, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(6), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(6), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(11), W: math.Inf(1)}, }, old: nil, }, { n: node(14), new: []simple.WeightedEdge{ {F: simple.Node(10), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(10), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: nil, }, }, }, { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1.5, diag: true, remember: false, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(4), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(4), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(4), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(2), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, }, old: nil, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(2), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(6), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, }, old: nil, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(6), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(10), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: nil, }, { n: node(14), new: []simple.WeightedEdge{ {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(10), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: nil, }, }, }, { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1, diag: true, remember: true, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, }, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(7), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(6), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(11), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(11), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, }, }, { n: node(14), new: []simple.WeightedEdge{ {F: simple.Node(10), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(14), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(11), W: math.Inf(1)}, }, }, }, }, { g: NewGridFrom( "*..*", "**.*", "**.*", "**.*", ), radius: 1.5, diag: true, remember: true, path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, want: []changes{ { n: node(1), new: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(0), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(4), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(4), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(4), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, old: nil, }, { n: node(2), new: []simple.WeightedEdge{ {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, }, }, { n: node(6), new: []simple.WeightedEdge{ {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(6), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(1), T: simple.Node(6), W: math.Sqrt2}, {F: simple.Node(2), T: simple.Node(1), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(2), T: simple.Node(6), W: 1}, {F: simple.Node(2), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(3), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, }, }, { n: node(10), new: []simple.WeightedEdge{ {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(10), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, old: []simple.WeightedEdge{ {F: simple.Node(5), T: simple.Node(0), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(1), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(5), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(1), W: math.Sqrt2}, {F: simple.Node(6), T: simple.Node(2), W: 1}, {F: simple.Node(6), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(6), T: simple.Node(10), W: 1}, {F: simple.Node(6), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(2), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(3), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(7), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, }, }, { n: node(14), new: nil, old: []simple.WeightedEdge{ {F: simple.Node(9), T: simple.Node(4), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(9), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(5), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(6), W: 1}, {F: simple.Node(10), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(10), T: simple.Node(14), W: 1}, {F: simple.Node(10), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(6), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(7), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(11), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(13), T: simple.Node(14), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(9), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(10), W: 1}, {F: simple.Node(14), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(13), W: math.Inf(1)}, {F: simple.Node(14), T: simple.Node(15), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(10), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(11), W: math.Inf(1)}, {F: simple.Node(15), T: simple.Node(14), W: math.Inf(1)}, }, }, }, }, } func TestLimitedVisionGrid(t *testing.T) { t.Parallel() for i, test := range limitedVisionTests { l := &LimitedVisionGrid{ Grid: test.g, VisionRadius: test.radius, Location: test.path[0], } if test.remember { l.Known = make(map[int64]bool) } l.Grid.AllowDiagonal = test.diag x, y := l.XY(test.path[0].ID()) nodes := graph.NodesOf(l.Nodes()) for _, u := range nodes { uid := u.ID() ux, uy := l.XY(uid) uNear := math.Hypot(x-ux, y-uy) <= test.radius for _, v := range nodes { vid := v.ID() vx, vy := l.XY(vid) vNear := math.Hypot(x-vx, y-vy) <= test.radius if u.ID() == v.ID() && l.HasEdgeBetween(uid, vid) { t.Errorf("unexpected self edge: %v -- %v", u, v) } if !uNear && !vNear && !l.HasEdgeBetween(uid, vid) && couldConnectIn(l, uid, vid) { t.Errorf("unexpected pessimism: no hope in distant edge between %v and %v for test %d", u, v, i) } if (uNear && vNear) && l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) { t.Errorf("unrealistic optimism: disagreement about edge between %v and %v for test %d: got:%t want:%t", u, v, i, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid)) } } } var got []changes for _, n := range test.path { new, old := l.MoveTo(n) got = append(got, changes{n: n, new: asConcreteEdges(new, l), old: asConcreteEdges(old, l)}) } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected walk for test %d:\ngot: %+v\nwant:%+v", i, got, test.want) } } } func asConcreteEdges(changes []graph.Edge, in graph.Weighted) []simple.WeightedEdge { if changes == nil { return nil } we := make([]simple.WeightedEdge, len(changes)) for i, e := range changes { we[i].F = e.From() we[i].T = e.To() w, ok := in.Weight(e.From().ID(), e.To().ID()) if !ok && !math.IsInf(w, 1) { panic("unexpected invalid finite weight") } we[i].W = w } return we } func couldConnectIn(l *LimitedVisionGrid, uid, vid int64) bool { if uid == vid { return false } ur, uc := l.RowCol(uid) vr, vc := l.RowCol(vid) if abs(ur-vr) > 1 || abs(uc-vc) > 1 { return false } if (ur != vr || uc != vc) && !l.Grid.AllowDiagonal { return false } if !l.Known[uid] && !l.Known[vid] { return true } if l.Known[uid] && !l.Grid.HasOpen(uid) { return false } if l.Known[vid] && !l.Grid.HasOpen(vid) { return false } return true } golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/shortest.go000066400000000000000000000547141450372207100261100ustar00rootroot00000000000000// 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 testgraphs import ( "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) // ShortestPathTests are graphs used to test the static shortest path routines in path: BellmanFord, // DijkstraAllPaths, DijkstraFrom, FloydWarshall and Johnson, and the static degenerate case for the // dynamic shortest path routine in path/dynamic: DStarLite. var ShortestPathTests = []struct { Name string Graph func() graph.WeightedEdgeAdder Edges []simple.WeightedEdge HasNegativeWeight bool HasNegativeCycle bool HasNegativeCycleInPath bool Query simple.Edge Weight float64 WantPaths [][]int64 HasUniquePath bool NoPathFor simple.Edge }{ // Positive weighted graphs. { Name: "empty directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, Weight: math.Inf(1), NoPathFor: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, }, { Name: "empty undirected", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, Weight: math.Inf(1), NoPathFor: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, }, { Name: "one edge directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, Weight: 1, WantPaths: [][]int64{ {0, 1}, }, HasUniquePath: true, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, }, { Name: "one edge self directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(0)}, Weight: 0, WantPaths: [][]int64{ {0}, }, HasUniquePath: true, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, }, { Name: "one edge undirected", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, Weight: 1, WantPaths: [][]int64{ {0, 1}, }, HasUniquePath: true, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, }, { Name: "two paths directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(2), W: 2}, {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(2)}, Weight: 2, WantPaths: [][]int64{ {0, 1, 2}, {0, 2}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(1)}, }, { Name: "two paths undirected", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(2), W: 2}, {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(2)}, Weight: 2, WantPaths: [][]int64{ {0, 1, 2}, {0, 2}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(4)}, }, { Name: "confounding paths directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->5 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(5), W: 1}, // Add direct edge to goal of weight 4 {F: simple.Node(0), T: simple.Node(5), W: 4}, // Add edge to a node that's still optimal {F: simple.Node(0), T: simple.Node(2), W: 2}, // Add edge to 3 that's overpriced {F: simple.Node(0), T: simple.Node(3), W: 4}, // Add very cheap edge to 4 which is a dead end {F: simple.Node(0), T: simple.Node(4), W: 0.25}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 5}, {0, 2, 3, 5}, {0, 5}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "confounding paths undirected", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->5 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(5), W: 1}, // Add direct edge to goal of weight 4 {F: simple.Node(0), T: simple.Node(5), W: 4}, // Add edge to a node that's still optimal {F: simple.Node(0), T: simple.Node(2), W: 2}, // Add edge to 3 that's overpriced {F: simple.Node(0), T: simple.Node(3), W: 4}, // Add very cheap edge to 4 which is a dead end {F: simple.Node(0), T: simple.Node(4), W: 0.25}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 5}, {0, 2, 3, 5}, {0, 5}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, }, { Name: "confounding paths directed 2-step", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->5 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(5), W: 1}, // Add two step path to goal of weight 4 {F: simple.Node(0), T: simple.Node(6), W: 2}, {F: simple.Node(6), T: simple.Node(5), W: 2}, // Add edge to a node that's still optimal {F: simple.Node(0), T: simple.Node(2), W: 2}, // Add edge to 3 that's overpriced {F: simple.Node(0), T: simple.Node(3), W: 4}, // Add very cheap edge to 4 which is a dead end {F: simple.Node(0), T: simple.Node(4), W: 0.25}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 5}, {0, 2, 3, 5}, {0, 6, 5}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "confounding paths undirected 2-step", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->5 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(5), W: 1}, // Add two step path to goal of weight 4 {F: simple.Node(0), T: simple.Node(6), W: 2}, {F: simple.Node(6), T: simple.Node(5), W: 2}, // Add edge to a node that's still optimal {F: simple.Node(0), T: simple.Node(2), W: 2}, // Add edge to 3 that's overpriced {F: simple.Node(0), T: simple.Node(3), W: 4}, // Add very cheap edge to 4 which is a dead end {F: simple.Node(0), T: simple.Node(4), W: 0.25}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 5}, {0, 2, 3, 5}, {0, 6, 5}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(7)}, }, { Name: "zero-weight cycle directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, // Add a zero-weight cycle. {F: simple.Node(1), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(1), W: 0}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight cycle^2 directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, // Add a zero-weight cycle. {F: simple.Node(1), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(1), W: 0}, // With its own zero-weight cycle. {F: simple.Node(5), T: simple.Node(6), W: 0}, {F: simple.Node(6), T: simple.Node(5), W: 0}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight cycle^2 confounding directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, // Add a zero-weight cycle. {F: simple.Node(1), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(1), W: 0}, // With its own zero-weight cycle. {F: simple.Node(5), T: simple.Node(6), W: 0}, {F: simple.Node(6), T: simple.Node(5), W: 0}, // But leading to the target. {F: simple.Node(5), T: simple.Node(4), W: 3}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, {0, 1, 5, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight cycle^3 directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, // Add a zero-weight cycle. {F: simple.Node(1), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(1), W: 0}, // With its own zero-weight cycle. {F: simple.Node(5), T: simple.Node(6), W: 0}, {F: simple.Node(6), T: simple.Node(5), W: 0}, // With its own zero-weight cycle. {F: simple.Node(6), T: simple.Node(7), W: 0}, {F: simple.Node(7), T: simple.Node(6), W: 0}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight 3·cycle^2 confounding directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, // Add a zero-weight cycle. {F: simple.Node(1), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(1), W: 0}, // With 3 of its own zero-weight cycles. {F: simple.Node(5), T: simple.Node(6), W: 0}, {F: simple.Node(6), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(7), W: 0}, {F: simple.Node(7), T: simple.Node(5), W: 0}, // Each leading to the target. {F: simple.Node(5), T: simple.Node(4), W: 3}, {F: simple.Node(6), T: simple.Node(4), W: 3}, {F: simple.Node(7), T: simple.Node(4), W: 3}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, {0, 1, 5, 4}, {0, 1, 5, 6, 4}, {0, 1, 5, 7, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight reversed 3·cycle^2 confounding directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, // Add a zero-weight cycle. {F: simple.Node(3), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(3), W: 0}, // With 3 of its own zero-weight cycles. {F: simple.Node(5), T: simple.Node(6), W: 0}, {F: simple.Node(6), T: simple.Node(5), W: 0}, {F: simple.Node(5), T: simple.Node(7), W: 0}, {F: simple.Node(7), T: simple.Node(5), W: 0}, // Each leading from the source. {F: simple.Node(0), T: simple.Node(5), W: 3}, {F: simple.Node(0), T: simple.Node(6), W: 3}, {F: simple.Node(0), T: simple.Node(7), W: 3}, }, Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, {0, 5, 3, 4}, {0, 6, 5, 3, 4}, {0, 7, 5, 3, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight |V|·cycle^(n/|V|) directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: func() []simple.WeightedEdge { e := []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, } next := len(e) + 1 // Add n zero-weight cycles. const n = 100 for i := 0; i < n; i++ { e = append(e, simple.WeightedEdge{F: simple.Node(next + i), T: simple.Node(i), W: 0}, simple.WeightedEdge{F: simple.Node(i), T: simple.Node(next + i), W: 0}, ) } return e }(), Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight n·cycle directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: func() []simple.WeightedEdge { e := []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, } next := len(e) + 1 // Add n zero-weight cycles. const n = 100 for i := 0; i < n; i++ { e = append(e, simple.WeightedEdge{F: simple.Node(next + i), T: simple.Node(1), W: 0}, simple.WeightedEdge{F: simple.Node(1), T: simple.Node(next + i), W: 0}, ) } return e }(), Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, { Name: "zero-weight bi-directional tree with single exit directed", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: func() []simple.WeightedEdge { e := []simple.WeightedEdge{ // Add a path from 0->4 of weight 4 {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 1}, {F: simple.Node(3), T: simple.Node(4), W: 1}, } // Make a bi-directional tree rooted at node 2 with // a single exit to node 4 and co-equal cost from // 2 to 4. const ( depth = 4 branching = 4 ) next := len(e) + 1 src := 2 var i, last int for l := 0; l < depth; l++ { for i = 0; i < branching; i++ { last = next + i e = append(e, simple.WeightedEdge{F: simple.Node(src), T: simple.Node(last), W: 0}) e = append(e, simple.WeightedEdge{F: simple.Node(last), T: simple.Node(src), W: 0}) } src = next + 1 next += branching } e = append(e, simple.WeightedEdge{F: simple.Node(last), T: simple.Node(4), W: 2}) return e }(), Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, Weight: 4, WantPaths: [][]int64{ {0, 1, 2, 3, 4}, {0, 1, 2, 6, 10, 14, 20, 4}, }, HasUniquePath: false, NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, }, // Negative weighted graphs. { Name: "one edge directed negative", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: -1}, }, HasNegativeWeight: true, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, Weight: -1, WantPaths: [][]int64{ {0, 1}, }, HasUniquePath: true, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, }, { Name: "one edge undirected negative", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: -1}, }, HasNegativeWeight: true, HasNegativeCycle: true, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, HasNegativeCycleInPath: true, Weight: math.Inf(-1), WantPaths: [][]int64{ {0, 1}, // One loop around negative cycle and no lead-in path. }, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, }, { Name: "two path directed negative cycle", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: -1}, {F: simple.Node(2), T: simple.Node(1), W: -1}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(0), T: simple.Node(4), W: 1}, }, HasNegativeWeight: true, HasNegativeCycle: true, Query: simple.Edge{F: simple.Node(0), T: simple.Node(3)}, HasNegativeCycleInPath: true, Weight: math.Inf(-1), WantPaths: [][]int64{ {1, 2, 1, 3}, // One loop around negative cycle and no lead-in path. }, NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, }, { Name: "two path directed off-path negative cycle", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: -1}, {F: simple.Node(2), T: simple.Node(1), W: -1}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(0), T: simple.Node(4), W: 10}, // Push search into negative cycle. }, HasNegativeWeight: true, HasNegativeCycle: true, Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, HasNegativeCycleInPath: false, Weight: 10, WantPaths: [][]int64{ {0, 4}, }, HasUniquePath: true, NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, }, { Name: "two path directed diamond negative cycle", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: -1}, {F: simple.Node(2), T: simple.Node(1), W: -1}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(0), T: simple.Node(3), W: 10}, // Push search into negative cycle. }, HasNegativeWeight: true, HasNegativeCycle: true, Query: simple.Edge{F: simple.Node(0), T: simple.Node(3)}, HasNegativeCycleInPath: true, Weight: math.Inf(-1), WantPaths: [][]int64{ {1, 2, 1, 3}, // One loop around negative cycle and no lead-in path. }, NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, }, { Name: "wp graph negative", // http://en.wikipedia.org/w/index.php?title=Johnson%27s_algorithm&oldid=564595231 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node('w'), T: simple.Node('z'), W: 2}, {F: simple.Node('x'), T: simple.Node('w'), W: 6}, {F: simple.Node('x'), T: simple.Node('y'), W: 3}, {F: simple.Node('y'), T: simple.Node('w'), W: 4}, {F: simple.Node('y'), T: simple.Node('z'), W: 5}, {F: simple.Node('z'), T: simple.Node('x'), W: -7}, {F: simple.Node('z'), T: simple.Node('y'), W: -3}, }, HasNegativeWeight: true, Query: simple.Edge{F: simple.Node('z'), T: simple.Node('y')}, Weight: -4, WantPaths: [][]int64{ {'z', 'x', 'y'}, }, HasUniquePath: true, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, }, { Name: "roughgarden negative", Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, Edges: []simple.WeightedEdge{ {F: simple.Node('a'), T: simple.Node('b'), W: -2}, {F: simple.Node('b'), T: simple.Node('c'), W: -1}, {F: simple.Node('c'), T: simple.Node('a'), W: 4}, {F: simple.Node('c'), T: simple.Node('x'), W: 2}, {F: simple.Node('c'), T: simple.Node('y'), W: -3}, {F: simple.Node('z'), T: simple.Node('x'), W: 1}, {F: simple.Node('z'), T: simple.Node('y'), W: -4}, }, HasNegativeWeight: true, Query: simple.Edge{F: simple.Node('a'), T: simple.Node('y')}, Weight: -6, WantPaths: [][]int64{ {'a', 'b', 'c', 'y'}, }, HasUniquePath: true, NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, }, } golang-gonum-v1-gonum-0.14.0/graph/path/internal/testgraphs/shortest_test.go000066400000000000000000000007101450372207100271320ustar00rootroot00000000000000// Copyright ©2020 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 testgraphs import "testing" func TestVerifyShortestPathTests(t *testing.T) { t.Parallel() for _, test := range ShortestPathTests { if len(test.WantPaths) != 1 && test.HasUniquePath { t.Fatalf("%q: bad shortest path test: non-unique paths marked unique", test.Name) } } } golang-gonum-v1-gonum-0.14.0/graph/path/johnson_apsp.go000066400000000000000000000104701450372207100227250ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) // JohnsonAllPaths returns a shortest-path tree for shortest paths in the graph g. // If the graph does not implement Weighted, UniformCost is used. If a negative cycle // exists in g, ok will be returned false and paths will not contain valid data. // // The time complexity of JohnsonAllPaths is O(|V|.|E|+|V|^2.log|V|). func JohnsonAllPaths(g graph.Graph) (paths AllShortest, ok bool) { adjusted := johnsonWeightAdjuster{Graph: g} if wg, ok := g.(Weighted); ok { adjusted.weight = wg.Weight } else { adjusted.weight = UniformCost(g) } paths = newAllShortest(graph.NodesOf(g.Nodes()), false) var q int64 sign := int64(-1) for { // Choose a random node ID until we find // one that is not in g. q = sign * rand.Int63() if _, exists := paths.indexOf[q]; !exists { break } sign *= -1 } adjusted.adjustBy, ok = BellmanFordFrom(johnsonGraphNode(q), johnsonReWeight{adjusted, q}) if !ok { return paths, false } dijkstraAllPaths(adjusted, paths) for i, u := range paths.nodes { hu := adjusted.adjustBy.WeightTo(u.ID()) for j, v := range paths.nodes { if i == j { continue } hv := adjusted.adjustBy.WeightTo(v.ID()) paths.dist.Set(i, j, paths.dist.At(i, j)-hu+hv) } } return paths, ok } // johnsonWeightAdjuster is an edge re-weighted graph constructed // by the first phase of the Johnson algorithm such that no negative // edge weights exist in the graph. type johnsonWeightAdjuster struct { graph.Graph weight Weighting adjustBy Shortest } var _ graph.Weighted = johnsonWeightAdjuster{} func (g johnsonWeightAdjuster) Node(id int64) graph.Node { panic("path: unintended use of johnsonWeightAdjuster") } func (g johnsonWeightAdjuster) WeightedEdge(_, _ int64) graph.WeightedEdge { panic("path: unintended use of johnsonWeightAdjuster") } func (g johnsonWeightAdjuster) Weight(xid, yid int64) (w float64, ok bool) { w, ok = g.weight(xid, yid) return w + g.adjustBy.WeightTo(xid) - g.adjustBy.WeightTo(yid), ok } func (johnsonWeightAdjuster) HasEdgeBetween(_, _ int64) bool { panic("path: unintended use of johnsonWeightAdjuster") } // johnsonReWeight provides a query node to allow edge re-weighting // using the Bellman-Ford algorithm for the first phase of the // Johnson algorithm. type johnsonReWeight struct { johnsonWeightAdjuster q int64 } func (g johnsonReWeight) Node(id int64) graph.Node { if id != g.q { panic("path: unintended use of johnsonReWeight") } return simple.Node(id) } func (g johnsonReWeight) Nodes() graph.Nodes { return newJohnsonNodeIterator(g.q, g.Graph.Nodes()) } func (g johnsonReWeight) From(id int64) graph.Nodes { if id == g.q { return g.Graph.Nodes() } return g.Graph.From(id) } func (g johnsonReWeight) Edge(uid, vid int64) graph.Edge { if uid == g.q && g.Graph.Node(vid) != nil { return simple.Edge{F: johnsonGraphNode(g.q), T: simple.Node(vid)} } return g.Graph.Edge(uid, vid) } func (g johnsonReWeight) Weight(xid, yid int64) (w float64, ok bool) { switch g.q { case xid: return 0, true case yid: return math.Inf(1), false default: return g.weight(xid, yid) } } type johnsonGraphNode int64 func (n johnsonGraphNode) ID() int64 { return int64(n) } func newJohnsonNodeIterator(q int64, nodes graph.Nodes) *johnsonNodeIterator { return &johnsonNodeIterator{q: q, nodes: nodes} } type johnsonNodeIterator struct { q int64 nodes graph.Nodes qUsed, qOK bool } func (it *johnsonNodeIterator) Len() int { var len int if it.nodes != nil { len = it.nodes.Len() if len < 0 { return len } } if !it.qUsed { len++ } return len } func (it *johnsonNodeIterator) Next() bool { if it.nodes != nil { ok := it.nodes.Next() if ok { return true } } if !it.qUsed { it.qOK = true it.qUsed = true return true } it.qOK = false return false } func (it *johnsonNodeIterator) Node() graph.Node { if it.qOK { return johnsonGraphNode(it.q) } if it.nodes == nil { return nil } return it.nodes.Node() } func (it *johnsonNodeIterator) Reset() { it.qOK = false it.qUsed = false if it.nodes == nil { return } it.nodes.Reset() } golang-gonum-v1-gonum-0.14.0/graph/path/johnson_apsp_test.go000066400000000000000000000066301450372207100237670ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/path/internal/testgraphs" ) func TestJohnsonAllPaths(t *testing.T) { t.Parallel() for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetWeightedEdge(e) } pt, ok := JohnsonAllPaths(g.(graph.Graph)) if test.HasNegativeCycle { if ok { t.Errorf("%q: expected negative cycle", test.Name) } continue } if !ok { t.Fatalf("%q: unexpected negative cycle", test.Name) } // Check all random paths returned are OK. for i := 0; i < 10; i++ { p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight { t.Errorf("%q: unexpected weight from Weight: got:%f want:%f", test.Name, weight, test.Weight) } if unique != test.HasUniquePath { t.Errorf("%q: unexpected number of paths: got: unique=%t want: unique=%t", test.Name, unique, test.HasUniquePath) } var got []int64 for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, p, test.WantPaths) } } np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID()) if np != nil || !math.IsInf(weight, 1) || unique { t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path= weight=+Inf unique=false", test.Name, np, weight, unique) } paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } var got [][]int64 if len(paths) != 0 { got = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, got, test.WantPaths) } paths = paths[:0] pt.AllBetweenFunc(test.Query.From().ID(), test.Query.To().ID(), func(path []graph.Node) { paths = append(paths, append([]graph.Node(nil), path...)) }) got = nil if len(paths) != 0 { got = make([][]int64, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, got, test.WantPaths) } nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID()) if nps != nil || !math.IsInf(weight, 1) { t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path= weight=+Inf", test.Name, nps, weight) } } } golang-gonum-v1-gonum-0.14.0/graph/path/negative_cycles_example_test.go000066400000000000000000000105021450372207100261360ustar00rootroot00000000000000// 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 path_test import ( "fmt" "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/path" "gonum.org/v1/gonum/graph/simple" ) func ExampleBellmanFordFrom_negativecycles() { // BellmanFordFrom can be used to find a non-exhaustive // set of negative cycles in a graph. // Construct a graph with a negative cycle. edges := []simple.WeightedEdge{ {F: simple.Node('a'), T: simple.Node('b'), W: -2}, {F: simple.Node('a'), T: simple.Node('f'), W: 2}, {F: simple.Node('b'), T: simple.Node('c'), W: 6}, {F: simple.Node('c'), T: simple.Node('a'), W: -5}, {F: simple.Node('d'), T: simple.Node('c'), W: -3}, {F: simple.Node('d'), T: simple.Node('e'), W: 8}, {F: simple.Node('e'), T: simple.Node('b'), W: 9}, {F: simple.Node('e'), T: simple.Node('c'), W: 2}, } g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) for _, e := range edges { g.SetWeightedEdge(e) } // Add a zero-cost path to all nodes from a new node Q. // Since the graph is being mutated, we get a range over // a slice of the graph's nodes rather than using the // graph.Nodes iterator directly. for _, n := range graph.NodesOf(g.Nodes()) { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node('Q'), T: n}) } // Find the shortest path to each node from Q. pt, ok := path.BellmanFordFrom(simple.Node('Q'), g) if ok { fmt.Println("no negative cycle present") return } for _, id := range []int64{'a', 'b', 'c', 'd', 'e', 'f'} { p, w := pt.To(id) if math.IsInf(w, -1) { fmt.Printf("negative cycle in path to %c path:%c\n", id, p) } } // Output: // negative cycle in path to a path:[a b c a] // negative cycle in path to b path:[b c a b] // negative cycle in path to c path:[c a b c] // negative cycle in path to f path:[a b c a f] } func ExampleFloydWarshall_negativecycles() { // FloydWarshall can be used to find an exhaustive // set of nodes in negative cycles in a graph. // Construct a graph with a negative cycle. edges := []simple.WeightedEdge{ {F: simple.Node('a'), T: simple.Node('f'), W: -1}, {F: simple.Node('b'), T: simple.Node('a'), W: 1}, {F: simple.Node('b'), T: simple.Node('c'), W: -1}, {F: simple.Node('b'), T: simple.Node('d'), W: 1}, {F: simple.Node('c'), T: simple.Node('b'), W: 0}, {F: simple.Node('e'), T: simple.Node('a'), W: 1}, {F: simple.Node('f'), T: simple.Node('e'), W: -1}, } g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) for _, e := range edges { g.SetWeightedEdge(e) } // Find the shortest path to each node from Q. pt, ok := path.FloydWarshall(g) if ok { fmt.Println("no negative cycle present") return } ids := []int64{'a', 'b', 'c', 'd', 'e', 'f'} for _, id := range ids { if math.IsInf(pt.Weight(id, id), -1) { fmt.Printf("%c is in a negative cycle\n", id) } } for _, uid := range ids { for _, vid := range ids { _, w, unique := pt.Between(uid, vid) if math.IsInf(w, -1) { fmt.Printf("negative cycle in path from %c to %c unique=%t\n", uid, vid, unique) } } } // Output: // a is in a negative cycle // b is in a negative cycle // c is in a negative cycle // e is in a negative cycle // f is in a negative cycle // negative cycle in path from a to a unique=false // negative cycle in path from a to e unique=false // negative cycle in path from a to f unique=false // negative cycle in path from b to a unique=false // negative cycle in path from b to b unique=false // negative cycle in path from b to c unique=false // negative cycle in path from b to d unique=false // negative cycle in path from b to e unique=false // negative cycle in path from b to f unique=false // negative cycle in path from c to a unique=false // negative cycle in path from c to b unique=false // negative cycle in path from c to c unique=false // negative cycle in path from c to d unique=false // negative cycle in path from c to e unique=false // negative cycle in path from c to f unique=false // negative cycle in path from e to a unique=false // negative cycle in path from e to e unique=false // negative cycle in path from e to f unique=false // negative cycle in path from f to a unique=false // negative cycle in path from f to e unique=false // negative cycle in path from f to f unique=false } golang-gonum-v1-gonum-0.14.0/graph/path/shortest.go000066400000000000000000000524601450372207100221040ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/mat" ) // Shortest is a shortest-path tree created by the BellmanFordFrom, DijkstraFrom // or AStar single-source shortest path functions. type Shortest struct { // from holds the source node given to // the function that returned the // Shortest value. from graph.Node // nodes hold the nodes of the analysed // graph. nodes []graph.Node // indexOf contains a mapping between // the id-dense representation of the // graph and the potentially id-sparse // nodes held in nodes. indexOf map[int64]int // dist and next represent the shortest // paths between nodes. // // Indices into dist and next are // mapped through indexOf. // // dist contains the distances // from the from node for each // node in the graph. dist []float64 // next contains the shortest-path // tree of the graph. The index is a // linear mapping of to-dense-id. next []int // hasNegativeCycle indicates // whether the Shortest includes // a negative cycle. This should // be set by the function that // returned the Shortest value. hasNegativeCycle bool // negCosts holds negative costs // between pairs of nodes to report // negative cycles. // negCosts must be initialised by // routines that can handle negative // edge weights. negCosts map[negEdge]float64 } // newShortestFrom returns a shortest path tree for paths from u // initialised with the given nodes. The nodes held by the returned // Shortest may be lazily added. func newShortestFrom(u graph.Node, nodes []graph.Node) Shortest { indexOf := make(map[int64]int, len(nodes)) uid := u.ID() for i, n := range nodes { indexOf[n.ID()] = i if n.ID() == uid { u = n } } p := Shortest{ from: u, nodes: nodes, indexOf: indexOf, dist: make([]float64, len(nodes)), next: make([]int, len(nodes)), } for i := range nodes { p.dist[i] = math.Inf(1) p.next[i] = -1 } p.dist[indexOf[uid]] = 0 return p } // add adds a node to the Shortest, initialising its stored index and returning, and // setting the distance and position as unconnected. add will panic if the node is // already present. func (p *Shortest) add(u graph.Node) int { uid := u.ID() if _, exists := p.indexOf[uid]; exists { panic("shortest: adding existing node") } idx := len(p.nodes) p.indexOf[uid] = idx p.nodes = append(p.nodes, u) p.dist = append(p.dist, math.Inf(1)) p.next = append(p.next, -1) return idx } // set sets the weight of the path from the node in p.nodes indexed by mid to the node // indexed by to. func (p Shortest) set(to int, weight float64, mid int) { p.dist[to] = weight p.next[to] = mid if weight < 0 { e := negEdge{from: mid, to: to} c, ok := p.negCosts[e] if !ok { p.negCosts[e] = weight } else if weight < c { // The only ways that we can have a new weight that is // lower than the previous weight is if either the edge // has already been traversed in a negative cycle, or // the edge is reachable from a negative cycle. // Either way the reported path is returned with a // negative infinite path weight. p.negCosts[e] = math.Inf(-1) } } } // From returns the starting node of the paths held by the Shortest. func (p Shortest) From() graph.Node { return p.from } // WeightTo returns the weight of the minimum path to v. If the path to v includes // a negative cycle, the returned weight will not reflect the true path weight. func (p Shortest) WeightTo(vid int64) float64 { to, toOK := p.indexOf[vid] if !toOK { return math.Inf(1) } return p.dist[to] } // To returns a shortest path to v and the weight of the path. If the path // to v includes a negative cycle, one pass through the cycle will be included // in path, but any path leading into the negative cycle will be lost, and // weight will be returned as -Inf. func (p Shortest) To(vid int64) (path []graph.Node, weight float64) { to, toOK := p.indexOf[vid] if !toOK || math.IsInf(p.dist[to], 1) { return nil, math.Inf(1) } from := p.indexOf[p.from.ID()] path = []graph.Node{p.nodes[to]} weight = math.Inf(1) if p.hasNegativeCycle { seen := make(set.Ints) seen.Add(from) for to != from { next := p.next[to] if math.IsInf(p.negCosts[negEdge{from: next, to: to}], -1) { weight = math.Inf(-1) } if seen.Has(to) { break } seen.Add(to) path = append(path, p.nodes[next]) to = next } } else { n := len(p.nodes) for to != from { to = p.next[to] path = append(path, p.nodes[to]) if n < 0 { panic("path: unexpected negative cycle") } n-- } } ordered.Reverse(path) return path, math.Min(weight, p.dist[p.indexOf[vid]]) } // ShortestAlts is a shortest-path tree created by the BellmanFordAllFrom or DijkstraAllFrom // single-source shortest path functions. type ShortestAlts struct { // from holds the source node given to // the function that returned the // ShortestAlts value. from graph.Node // nodes hold the nodes of the analysed // graph. nodes []graph.Node // indexOf contains a mapping between // the id-dense representation of the // graph and the potentially id-sparse // nodes held in nodes. indexOf map[int64]int // dist and next represent the shortest // paths between nodes. // // Indices into dist and next are // mapped through indexOf. // // dist contains the distances // from the from node for each // node in the graph. dist []float64 // next contains the shortest-path // tree of the graph. The index is a // linear mapping of to-dense-id. next [][]int // hasNegativeCycle indicates // whether the ShortestAlts includes // a negative cycle. This should // be set by the function that // returned the ShortestAlts value. hasNegativeCycle bool // negCosts holds negative costs // between pairs of nodes to report // negative cycles. // negCosts must be initialised by // routines that can handle negative // edge weights. negCosts map[negEdge]float64 } // newShortestAltsFrom returns a shortest path tree for all paths from u // initialised with the given nodes. The nodes held by the returned // Shortest may be lazily added. func newShortestAltsFrom(u graph.Node, nodes []graph.Node) ShortestAlts { indexOf := make(map[int64]int, len(nodes)) uid := u.ID() for i, n := range nodes { indexOf[n.ID()] = i if n.ID() == uid { u = n } } p := ShortestAlts{ from: u, nodes: nodes, indexOf: indexOf, dist: make([]float64, len(nodes)), next: make([][]int, len(nodes)), } for i := range nodes { p.dist[i] = math.Inf(1) p.next[i] = nil } p.dist[indexOf[uid]] = 0 return p } // add adds a node to the ShortestAlts, initialising its stored index and returning, and // setting the distance and position as unconnected. add will panic if the node is // already present. func (p *ShortestAlts) add(u graph.Node) int { uid := u.ID() if _, exists := p.indexOf[uid]; exists { panic("shortest: adding existing node") } idx := len(p.nodes) p.indexOf[uid] = idx p.nodes = append(p.nodes, u) p.dist = append(p.dist, math.Inf(1)) p.next = append(p.next, nil) return idx } // set sets the weight of the path from the node in p.nodes indexed by mid to the node // indexed by to. func (p ShortestAlts) set(to int, weight float64, mid int) { p.dist[to] = weight p.next[to] = []int{mid} if weight < 0 { e := negEdge{from: mid, to: to} c, ok := p.negCosts[e] if !ok { p.negCosts[e] = weight } else if weight < c { // The only ways that we can have a new weight that is // lower than the previous weight is if either the edge // has already been traversed in a negative cycle, or // the edge is reachable from a negative cycle. // Either way the reported path is returned with a // negative infinite path weight. p.negCosts[e] = math.Inf(-1) } } } // addPath adds a new path from the node in p.nodes indexed by mid to the node indexed // by to. The weight of the path is expected to be the same as already existing paths // between these nodes, but no check is made for this. func (p ShortestAlts) addPath(to, mid int) { // These are likely to be rare, so just loop over collisions. for _, v := range p.next[to] { if mid == v { return } } p.next[to] = append(p.next[to], mid) } // From returns the starting node of the paths held by the ShortestAlts. func (p ShortestAlts) From() graph.Node { return p.from } // WeightTo returns the weight of the minimum path to v. If the path to v includes // a negative cycle, the returned weight will not reflect the true path weight. func (p ShortestAlts) WeightTo(vid int64) float64 { to, toOK := p.indexOf[vid] if !toOK { return math.Inf(1) } return p.dist[to] } // To returns a shortest path to v and the weight of the path. If more than // one shortest path exists between u and v, a randomly chosen path will be // returned and unique is returned false. If a cycle with zero weight exists // in the path, it will not be included, but unique will be returned false. // If the path to v includes a negative cycle, one pass through the cycle will // be included in path, but any path leading into the negative cycle will be // lost, and weight will be returned as -Inf. func (p ShortestAlts) To(vid int64) (path []graph.Node, weight float64, unique bool) { to, toOK := p.indexOf[vid] if !toOK || math.IsInf(p.dist[to], 1) { return nil, math.Inf(1), false } from := p.indexOf[p.from.ID()] unique = true path = []graph.Node{p.nodes[to]} if p.hasNegativeCycle { weight = math.Inf(1) seen := make(set.Ints) seen.Add(from) for to != from { c := p.next[to] var next int if len(c) != 1 { unique = false next = c[rand.Intn(len(c))] } else { next = c[0] } if math.IsInf(p.negCosts[negEdge{from: next, to: to}], -1) { weight = math.Inf(-1) unique = false } if seen.Has(to) { break } seen.Add(to) path = append(path, p.nodes[next]) to = next } weight = math.Min(weight, p.dist[p.indexOf[vid]]) } else { seen := make([]int, len(p.nodes)) for i := range seen { seen[i] = -1 } seen[to] = 0 var next int for from != to { c := p.next[to] if len(c) != 1 { unique = false next = c[rand.Intn(len(c))] } else { next = c[0] } if seen[next] >= 0 { path = path[:seen[next]] } seen[next] = len(path) path = append(path, p.nodes[next]) to = next } weight = p.dist[p.indexOf[vid]] } ordered.Reverse(path) return path, weight, unique } // AllTo returns all shortest paths to v and the weight of the paths. Paths // containing zero-weight cycles are not returned. If a negative cycle exists between // u and v, paths is returned nil and weight is returned as -Inf. func (p ShortestAlts) AllTo(vid int64) (paths [][]graph.Node, weight float64) { from := p.indexOf[p.from.ID()] to, toOK := p.indexOf[vid] if !toOK || len(p.next[to]) == 0 { if p.from.ID() == vid { return [][]graph.Node{{p.nodes[from]}}, 0 } return nil, math.Inf(1) } _, weight, unique := p.To(vid) if math.IsInf(weight, -1) && !unique { return nil, math.Inf(-1) } seen := make([]bool, len(p.nodes)) p.allTo(from, to, seen, []graph.Node{p.nodes[to]}, func(path []graph.Node) { paths = append(paths, append([]graph.Node(nil), path...)) }) weight = p.dist[to] return paths, weight } // AllToFunc calls fn on all shortest paths to v. Paths containing zero-weight // cycles are not considered. If a negative cycle exists between u and v, no // path is considered. The fn closure must not retain the path parameter. func (p ShortestAlts) AllToFunc(vid int64, fn func(path []graph.Node)) { from := p.indexOf[p.from.ID()] to, toOK := p.indexOf[vid] if !toOK || len(p.next[to]) == 0 { if p.from.ID() == vid { fn([]graph.Node{p.nodes[from]}) } return } _, weight, unique := p.To(vid) if math.IsInf(weight, -1) && !unique { return } seen := make([]bool, len(p.nodes)) p.allTo(from, to, seen, []graph.Node{p.nodes[to]}, fn) } // allTo recursively constructs a slice of paths extending from the node // indexed into p.nodes by from to the node indexed by to. len(seen) must match // the number of nodes held by the receiver. The path parameter is the current // working path and the results passed to fn. func (p ShortestAlts) allTo(from, to int, seen []bool, path []graph.Node, fn func(path []graph.Node)) { seen[to] = true if from == to { if path == nil { return } ordered.Reverse(path) fn(path) ordered.Reverse(path) return } first := true var seenWork []bool for _, to := range p.next[to] { if seen[to] { continue } if first { p := make([]graph.Node, len(path), len(path)+1) copy(p, path) path = p seenWork = make([]bool, len(seen)) first = false } copy(seenWork, seen) p.allTo(from, to, seenWork, append(path, p.nodes[to]), fn) } } // negEdge is a key into the negative costs map used by Shortest and ShortestAlts. type negEdge struct{ from, to int } // AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall // or JohnsonAllPaths all-pairs shortest paths functions. type AllShortest struct { // nodes hold the nodes of the analysed // graph. nodes []graph.Node // indexOf contains a mapping between // the id-dense representation of the // graph and the potentially id-sparse // nodes held in nodes. indexOf map[int64]int // dist, next and forward represent // the shortest paths between nodes. // // Indices into dist and next are // mapped through indexOf. // // dist contains the pairwise // distances between nodes. // // Internally, edges on negative // cycles are given a special NaN // weight, NaN(0xdefaced). // This is returned to the user as // -Inf. This approach allows -Inf // weight edges on simple paths to be // distinguished from -Inf weight // paths that contain negative cycles. // The distinction is visible to the // user through whether then path // returned with a -Inf weight is // nil or contains a set of nodes. dist *mat.Dense // next contains the shortest-path // tree of the graph. The first index // is a linear mapping of from-dense-id // and to-dense-id, to-major with a // stride equal to len(nodes); the // slice indexed to is the list of // intermediates leading from the 'from' // node to the 'to' node represented // by dense id. // The interpretation of next is // dependent on the state of forward. next [][]int // forward indicates the direction of // path reconstruction. Forward // reconstruction is used for Floyd- // Warshall and reverse is used for // Dijkstra. forward bool } var ( // defaced is NaN(0xdefaced) used as a marker for -Inf weight edges // within paths containing negative cycles. Routines marking these // edges should use this value. defaced = scalar.NaNWith(0xdefaced) // defacedBits is the bit pattern we look for in AllShortest to // identify the edges. defacedBits = math.Float64bits(defaced) ) // newAllShortest returns an all-pairs shortest path forest for paths with the // given nodes. The forward flag indicates whether the path reconstruction is // performed in the forward (Floyd-Warshall) or reverse (Dijkstra/Johnson's) order. func newAllShortest(nodes []graph.Node, forward bool) AllShortest { if len(nodes) == 0 { return AllShortest{} } indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { indexOf[n.ID()] = i } dist := make([]float64, len(nodes)*len(nodes)) for i := range dist { dist[i] = math.Inf(1) } return AllShortest{ nodes: nodes, indexOf: indexOf, dist: mat.NewDense(len(nodes), len(nodes), dist), next: make([][]int, len(nodes)*len(nodes)), forward: forward, } } // at returns a slice of node indexes into p.nodes for nodes that are mid points // between nodes indexed by from and to. func (p AllShortest) at(from, to int) (mid []int) { return p.next[from+to*len(p.nodes)] } // set sets the weights of paths between node indexes into p.nodes for from and to // passing through the nodes indexed by mid. func (p AllShortest) set(from, to int, weight float64, mid ...int) { p.dist.Set(from, to, weight) p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)][:0], mid...) } // add adds paths between node indexed in p.nodes by from and to passing through // the nodes indexed by mid. func (p AllShortest) add(from, to int, mid ...int) { loop: // These are likely to be rare, so just loop over collisions. for _, k := range mid { for _, v := range p.next[from+to*len(p.nodes)] { if k == v { continue loop } } p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)], k) } } // Weight returns the weight of the minimum path between u and v. func (p AllShortest) Weight(uid, vid int64) float64 { from, fromOK := p.indexOf[uid] to, toOK := p.indexOf[vid] if !fromOK || !toOK { return math.Inf(1) } w := p.dist.At(from, to) if math.Float64bits(w) == defacedBits { return math.Inf(-1) } return w } // Between returns a shortest path from u to v and the weight of the path. If more than // one shortest path exists between u and v, a randomly chosen path will be returned and // unique is returned false. If a cycle with zero weight exists in the path, it will not // be included, but unique will be returned false. If a negative cycle exists on the path // from u to v, path will be returned nil, weight will be -Inf and unique will be false. func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) { from, fromOK := p.indexOf[uid] to, toOK := p.indexOf[vid] if !fromOK || !toOK || len(p.at(from, to)) == 0 { if uid == vid { if !fromOK { return []graph.Node{node(uid)}, 0, true } return []graph.Node{p.nodes[from]}, 0, true } return nil, math.Inf(1), false } weight = p.dist.At(from, to) if math.Float64bits(weight) == defacedBits { return nil, math.Inf(-1), false } seen := make([]int, len(p.nodes)) for i := range seen { seen[i] = -1 } var n graph.Node if p.forward { n = p.nodes[from] seen[from] = 0 } else { n = p.nodes[to] seen[to] = 0 } path = []graph.Node{n} unique = true var next int for from != to { c := p.at(from, to) if len(c) != 1 { unique = false next = c[rand.Intn(len(c))] } else { next = c[0] } if seen[next] >= 0 { path = path[:seen[next]] } seen[next] = len(path) path = append(path, p.nodes[next]) if p.forward { from = next } else { to = next } } if !p.forward { ordered.Reverse(path) } return path, weight, unique } // AllBetween returns all shortest paths from u to v and the weight of the paths. Paths // containing zero-weight cycles are not returned. If a negative cycle exists between // u and v, paths is returned nil and weight is returned as -Inf. func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) { from, fromOK := p.indexOf[uid] to, toOK := p.indexOf[vid] if !fromOK || !toOK || len(p.at(from, to)) == 0 { if uid == vid { if !fromOK { return [][]graph.Node{{node(uid)}}, 0 } return [][]graph.Node{{p.nodes[from]}}, 0 } return nil, math.Inf(1) } weight = p.dist.At(from, to) if math.Float64bits(weight) == defacedBits { return nil, math.Inf(-1) } var n graph.Node if p.forward { n = p.nodes[from] } else { n = p.nodes[to] } seen := make([]bool, len(p.nodes)) p.allBetween(from, to, seen, []graph.Node{n}, func(path []graph.Node) { paths = append(paths, append([]graph.Node(nil), path...)) }) return paths, weight } // AllBetweenFunc calls fn on all shortest paths from u to v. Paths containing // zero-weight cycles are not considered. If a negative cycle exists between u // and v, no path is considered. The fn closure must not retain the path // parameter. func (p AllShortest) AllBetweenFunc(uid, vid int64, fn func(path []graph.Node)) { from, fromOK := p.indexOf[uid] to, toOK := p.indexOf[vid] if !fromOK || !toOK || len(p.at(from, to)) == 0 { if uid == vid { if !fromOK { fn([]graph.Node{node(uid)}) return } fn([]graph.Node{p.nodes[from]}) return } return } if math.Float64bits(p.dist.At(from, to)) == defacedBits { return } var n graph.Node if p.forward { n = p.nodes[from] } else { n = p.nodes[to] } seen := make([]bool, len(p.nodes)) p.allBetween(from, to, seen, []graph.Node{n}, fn) } // allBetween recursively constructs a set of paths extending from the node // indexed into p.nodes by from to the node indexed by to. len(seen) must match // the number of nodes held by the receiver. The path parameter is the current // working path and the results passed to fn. func (p AllShortest) allBetween(from, to int, seen []bool, path []graph.Node, fn func([]graph.Node)) { if p.forward { seen[from] = true } else { seen[to] = true } if from == to { if path == nil { return } if !p.forward { ordered.Reverse(path) } fn(path) if !p.forward { ordered.Reverse(path) } return } first := true var seenWork []bool for _, n := range p.at(from, to) { if seen[n] { continue } if first { p := make([]graph.Node, len(path), len(path)+1) copy(p, path) path = p seenWork = make([]bool, len(seen)) first = false } if p.forward { from = n } else { to = n } copy(seenWork, seen) p.allBetween(from, to, seenWork, append(path, p.nodes[n]), fn) } } type node int64 func (n node) ID() int64 { return int64(n) } golang-gonum-v1-gonum-0.14.0/graph/path/shortest_test.go000066400000000000000000000201461450372207100231370ustar00rootroot00000000000000// Copyright ©2023 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "fmt" "math" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var shortestTests = []struct { n, d int p float64 seed uint64 }{ {n: 100, d: 2, p: 0.5, seed: 1}, {n: 200, d: 2, p: 0.5, seed: 1}, {n: 100, d: 4, p: 0.25, seed: 1}, {n: 200, d: 4, p: 0.25, seed: 1}, {n: 100, d: 16, p: 0.1, seed: 1}, {n: 200, d: 16, p: 0.1, seed: 1}, } func TestShortestAlts(t *testing.T) { for _, test := range shortestTests { t.Run(fmt.Sprintf("AllTo_%d×%d|%v", test.n, test.d, test.p), func(t *testing.T) { g := simple.NewDirectedGraph() gen.SmallWorldsBB(g, test.n, test.d, test.p, rand.New(rand.NewSource(test.seed))) all := allShortest(DijkstraAllPaths(g)) for uid := int64(0); uid < int64(test.n); uid++ { p := DijkstraAllFrom(g.Node(uid), g) for vid := int64(0); vid < int64(test.n); vid++ { got, gotW := p.AllTo(vid) want, wantW := all.AllBetween(uid, vid) if gotW != wantW { t.Errorf("mismatched weight: got:%f want:%f", gotW, wantW) continue } var gotPaths [][]int64 if len(got) != 0 { gotPaths = make([][]int64, len(got)) } for i, p := range got { for _, v := range p { gotPaths[i] = append(gotPaths[i], v.ID()) } } ordered.BySliceValues(gotPaths) var wantPaths [][]int64 if len(want) != 0 { wantPaths = make([][]int64, len(want)) } for i, p := range want { for _, v := range p { wantPaths[i] = append(wantPaths[i], v.ID()) } } ordered.BySliceValues(wantPaths) if !reflect.DeepEqual(gotPaths, wantPaths) { t.Errorf("unexpected shortest paths %d --> %d:\ngot: %v\nwant:%v", uid, vid, gotPaths, wantPaths) } } } }) } } func TestAllShortest(t *testing.T) { for _, test := range shortestTests { t.Run(fmt.Sprintf("AllBetween_%d×%d|%v", test.n, test.d, test.p), func(t *testing.T) { g := simple.NewDirectedGraph() gen.SmallWorldsBB(g, test.n, test.d, test.p, rand.New(rand.NewSource(test.seed))) p := DijkstraAllPaths(g) for uid := int64(0); uid < int64(test.n); uid++ { for vid := int64(0); vid < int64(test.n); vid++ { got, gotW := p.AllBetween(uid, vid) want, wantW := allShortest(p).AllBetween(uid, vid) // Compare to naive. if gotW != wantW { t.Errorf("mismatched weight: got:%f want:%f", gotW, wantW) continue } var gotPaths [][]int64 if len(got) != 0 { gotPaths = make([][]int64, len(got)) } for i, p := range got { for _, v := range p { gotPaths[i] = append(gotPaths[i], v.ID()) } } ordered.BySliceValues(gotPaths) var wantPaths [][]int64 if len(want) != 0 { wantPaths = make([][]int64, len(want)) } for i, p := range want { for _, v := range p { wantPaths[i] = append(wantPaths[i], v.ID()) } } ordered.BySliceValues(wantPaths) if !reflect.DeepEqual(gotPaths, wantPaths) { t.Errorf("unexpected shortest paths %d --> %d:\ngot: %v\nwant:%v", uid, vid, gotPaths, wantPaths) } } } }) } } // allShortest implements an allocation-naive AllBetween. type allShortest AllShortest // at returns a slice of node indexes into p.nodes for nodes that are mid points // between nodes indexed by from and to. func (p allShortest) at(from, to int) (mid []int) { return p.next[from+to*len(p.nodes)] } // AllBetween returns all shortest paths from u to v and the weight of the paths. Paths // containing zero-weight cycles are not returned. If a negative cycle exists between // u and v, paths is returned nil and weight is returned as -Inf. func (p allShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) { from, fromOK := p.indexOf[uid] to, toOK := p.indexOf[vid] if !fromOK || !toOK || len(p.at(from, to)) == 0 { if uid == vid { if !fromOK { return [][]graph.Node{{node(uid)}}, 0 } return [][]graph.Node{{p.nodes[from]}}, 0 } return nil, math.Inf(1) } weight = p.dist.At(from, to) if math.Float64bits(weight) == defacedBits { return nil, math.Inf(-1) } var n graph.Node if p.forward { n = p.nodes[from] } else { n = p.nodes[to] } seen := make([]bool, len(p.nodes)) paths = p.allBetween(from, to, seen, []graph.Node{n}, nil) return paths, weight } // allBetween recursively constructs a slice of paths extending from the node // indexed into p.nodes by from to the node indexed by to. len(seen) must match // the number of nodes held by the receiver. The path parameter is the current // working path and the results are written into paths. func (p allShortest) allBetween(from, to int, seen []bool, path []graph.Node, paths [][]graph.Node) [][]graph.Node { if p.forward { seen[from] = true } else { seen[to] = true } if from == to { if path == nil { return paths } if !p.forward { ordered.Reverse(path) } return append(paths, path) } first := true for _, n := range p.at(from, to) { if seen[n] { continue } if first { path = append([]graph.Node(nil), path...) first = false } if p.forward { from = n } else { to = n } path = path[:len(path):len(path)] paths = p.allBetween(from, to, append([]bool(nil), seen...), append(path, p.nodes[n]), paths) } return paths } var shortestBenchmarks = []struct { n, d int p float64 seed uint64 }{ {n: 100, d: 2, p: 0.5, seed: 1}, {n: 1000, d: 2, p: 0.5, seed: 1}, {n: 100, d: 4, p: 0.25, seed: 1}, {n: 1000, d: 4, p: 0.25, seed: 1}, {n: 100, d: 16, p: 0.1, seed: 1}, {n: 1000, d: 16, p: 0.1, seed: 1}, } func BenchmarkShortestAlts(b *testing.B) { for _, bench := range shortestBenchmarks { g := simple.NewDirectedGraph() gen.SmallWorldsBB(g, bench.n, bench.d, bench.p, rand.New(rand.NewSource(bench.seed))) // Find the widest path set. var ( bestP ShortestAlts bestVid int64 n int ) for uid := int64(0); uid < int64(bench.n); uid++ { p := DijkstraAllFrom(g.Node(uid), g) for vid := int64(0); vid < int64(bench.n); vid++ { paths, _ := p.AllTo(vid) if len(paths) > n { n = len(paths) bestP = p bestVid = vid } } } b.Run(fmt.Sprintf("AllTo_%d×%d|%v(%d)", bench.n, bench.d, bench.p, n), func(b *testing.B) { for i := 0; i < b.N; i++ { paths, _ := bestP.AllTo(bestVid) if len(paths) != n { b.Errorf("unexpected number of paths: got:%d want:%d", len(paths), n) } } }) b.Run(fmt.Sprintf("AllToFunc_%d×%d|%v(%d)", bench.n, bench.d, bench.p, n), func(b *testing.B) { for i := 0; i < b.N; i++ { var paths int bestP.AllToFunc(bestVid, func(_ []graph.Node) { paths++ }) if paths != n { b.Errorf("unexpected number of paths: got:%d want:%d", paths, n) } } }) } } func BenchmarkAllShortest(b *testing.B) { for _, bench := range shortestBenchmarks { g := simple.NewDirectedGraph() gen.SmallWorldsBB(g, bench.n, bench.d, bench.p, rand.New(rand.NewSource(bench.seed))) p := DijkstraAllPaths(g) // Find the widest path set. var ( bestUid, bestVid int64 n int ) for uid := int64(0); uid < int64(bench.n); uid++ { for vid := int64(0); vid < int64(bench.n); vid++ { paths, _ := p.AllBetween(uid, vid) if len(paths) > n { n = len(paths) bestUid = uid bestVid = vid } } } b.Run(fmt.Sprintf("AllBetween_%d×%d|%v(%d)", bench.n, bench.d, bench.p, n), func(b *testing.B) { for i := 0; i < b.N; i++ { paths, _ := p.AllBetween(bestUid, bestVid) if len(paths) != n { b.Errorf("unexpected number of paths: got:%d want:%d", len(paths), n) } } }) b.Run(fmt.Sprintf("AllBetweenFunc_%d×%d|%v(%d)", bench.n, bench.d, bench.p, n), func(b *testing.B) { for i := 0; i < b.N; i++ { var paths int p.AllBetweenFunc(bestUid, bestVid, func(_ []graph.Node) { paths++ }) if paths != n { b.Errorf("unexpected number of paths: got:%d want:%d", paths, n) } } }) } } golang-gonum-v1-gonum-0.14.0/graph/path/spanning_tree.go000066400000000000000000000124661450372207100230670ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "container/heap" "math" "sort" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) // WeightedBuilder is a type that can add nodes and weighted edges. type WeightedBuilder interface { AddNode(graph.Node) SetWeightedEdge(graph.WeightedEdge) } // Prim generates a minimum spanning tree of g by greedy tree extension, placing // the result in the destination, dst. If the edge weights of g are distinct // it will be the unique minimum spanning tree of g. The destination is not cleared // first. The weight of the minimum spanning tree is returned. If g is not connected, // a minimum spanning forest will be constructed in dst and the sum of minimum // spanning tree weights will be returned. // // Nodes and Edges from g are used to construct dst, so if the Node and Edge // types used in g are pointer or reference-like, then the values will be shared // between the graphs. // // If dst has nodes that exist in g, Prim will panic. func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 { nodes := graph.NodesOf(g.Nodes()) if len(nodes) == 0 { return 0 } q := &primQueue{ indexOf: make(map[int64]int, len(nodes)-1), nodes: make([]simple.WeightedEdge, 0, len(nodes)-1), } dst.AddNode(nodes[0]) for _, u := range nodes[1:] { dst.AddNode(u) heap.Push(q, simple.WeightedEdge{F: u, W: math.Inf(1)}) } u := nodes[0] uid := u.ID() for _, v := range graph.NodesOf(g.From(uid)) { w, ok := g.Weight(uid, v.ID()) if !ok { panic("prim: unexpected invalid weight") } q.update(v, u, w) } var w float64 for q.Len() > 0 { e := heap.Pop(q).(simple.WeightedEdge) if e.To() != nil && g.HasEdgeBetween(e.From().ID(), e.To().ID()) { dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID())) w += e.Weight() } u = e.From() uid := u.ID() for _, n := range graph.NodesOf(g.From(uid)) { if key, ok := q.key(n); ok { w, ok := g.Weight(uid, n.ID()) if !ok { panic("prim: unexpected invalid weight") } if w < key { q.update(n, u, w) } } } } return w } // primQueue is a Prim's priority queue. The priority queue is a // queue of edge From nodes keyed on the minimum edge weight to // a node in the set of nodes already connected to the minimum // spanning forest. type primQueue struct { indexOf map[int64]int nodes []simple.WeightedEdge } func (q *primQueue) Less(i, j int) bool { return q.nodes[i].Weight() < q.nodes[j].Weight() } func (q *primQueue) Swap(i, j int) { q.indexOf[q.nodes[i].From().ID()] = j q.indexOf[q.nodes[j].From().ID()] = i q.nodes[i], q.nodes[j] = q.nodes[j], q.nodes[i] } func (q *primQueue) Len() int { return len(q.nodes) } func (q *primQueue) Push(x interface{}) { n := x.(simple.WeightedEdge) q.indexOf[n.From().ID()] = len(q.nodes) q.nodes = append(q.nodes, n) } func (q *primQueue) Pop() interface{} { n := q.nodes[len(q.nodes)-1] q.nodes = q.nodes[:len(q.nodes)-1] delete(q.indexOf, n.From().ID()) return n } // key returns the key for the node u and whether the node is // in the queue. If the node is not in the queue, key is returned // as +Inf. func (q *primQueue) key(u graph.Node) (key float64, ok bool) { i, ok := q.indexOf[u.ID()] if !ok { return math.Inf(1), false } return q.nodes[i].Weight(), ok } // update updates u's position in the queue with the new closest // MST-connected neighbour, v, and the key weight between u and v. func (q *primQueue) update(u, v graph.Node, key float64) { id := u.ID() i, ok := q.indexOf[id] if !ok { return } q.nodes[i].T = v q.nodes[i].W = key heap.Fix(q, i) } // UndirectedWeightLister is an undirected graph that returns edge weights and // the set of edges in the graph. type UndirectedWeightLister interface { graph.WeightedUndirected WeightedEdges() graph.WeightedEdges } // Kruskal generates a minimum spanning tree of g by greedy tree coalescence, placing // the result in the destination, dst. If the edge weights of g are distinct // it will be the unique minimum spanning tree of g. The destination is not cleared // first. The weight of the minimum spanning tree is returned. If g is not connected, // a minimum spanning forest will be constructed in dst and the sum of minimum // spanning tree weights will be returned. // // Nodes and Edges from g are used to construct dst, so if the Node and Edge // types used in g are pointer or reference-like, then the values will be shared // between the graphs. // // If dst has nodes that exist in g, Kruskal will panic. func Kruskal(dst WeightedBuilder, g UndirectedWeightLister) float64 { edges := graph.WeightedEdgesOf(g.WeightedEdges()) sort.Sort(byWeight(edges)) ds := make(djSet) it := g.Nodes() for it.Next() { n := it.Node() dst.AddNode(n) ds.add(n.ID()) } var w float64 for _, e := range edges { if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 { ds.union(s1, s2) dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID())) w += e.Weight() } } return w } type byWeight []graph.WeightedEdge func (e byWeight) Len() int { return len(e) } func (e byWeight) Less(i, j int) bool { return e[i].Weight() < e[j].Weight() } func (e byWeight) Swap(i, j int) { e[i], e[j] = e[j], e[i] } golang-gonum-v1-gonum-0.14.0/graph/path/spanning_tree_test.go000066400000000000000000000255611450372207100241260ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) func TestVerifySpanningTreeTests(t *testing.T) { t.Parallel() for _, test := range spanningTreeTests { var w float64 for _, e := range test.treeEdges { w += e.W } if w != test.want { t.Fatalf("bad test: %s weight mismatch: %v != %v", test.name, w, test.want) } } } type spanningGraph interface { graph.WeightedBuilder graph.WeightedUndirected WeightedEdges() graph.WeightedEdges } var spanningTreeTests = []struct { name string graph func() spanningGraph edges []simple.WeightedEdge want float64 treeEdges []simple.WeightedEdge }{ { name: "Empty", graph: func() spanningGraph { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, want: 0, }, { // https://upload.wikimedia.org/wikipedia/commons/f/f7/Prim%27s_algorithm.svg // Modified to make edge weights unique; A--B is increased to 2.5 otherwise // to prevent the alternative solution being found. name: "Prim WP figure 1", graph: func() spanningGraph { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('B'), W: 2.5}, {F: simple.Node('A'), T: simple.Node('D'), W: 1}, {F: simple.Node('B'), T: simple.Node('D'), W: 2}, {F: simple.Node('C'), T: simple.Node('D'), W: 3}, }, want: 6, treeEdges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('D'), W: 1}, {F: simple.Node('B'), T: simple.Node('D'), W: 2}, {F: simple.Node('C'), T: simple.Node('D'), W: 3}, }, }, { // https://upload.wikimedia.org/wikipedia/commons/5/5c/MST_kruskal_en.gif name: "Kruskal WP figure 1", graph: func() spanningGraph { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node('a'), T: simple.Node('b'), W: 3}, {F: simple.Node('a'), T: simple.Node('e'), W: 1}, {F: simple.Node('b'), T: simple.Node('c'), W: 5}, {F: simple.Node('b'), T: simple.Node('e'), W: 4}, {F: simple.Node('c'), T: simple.Node('d'), W: 2}, {F: simple.Node('c'), T: simple.Node('e'), W: 6}, {F: simple.Node('d'), T: simple.Node('e'), W: 7}, }, want: 11, treeEdges: []simple.WeightedEdge{ {F: simple.Node('a'), T: simple.Node('b'), W: 3}, {F: simple.Node('a'), T: simple.Node('e'), W: 1}, {F: simple.Node('b'), T: simple.Node('c'), W: 5}, {F: simple.Node('c'), T: simple.Node('d'), W: 2}, }, }, { // https://upload.wikimedia.org/wikipedia/commons/8/87/Kruskal_Algorithm_6.svg name: "Kruskal WP example", graph: func() spanningGraph { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('B'), W: 7}, {F: simple.Node('A'), T: simple.Node('D'), W: 5}, {F: simple.Node('B'), T: simple.Node('C'), W: 8}, {F: simple.Node('B'), T: simple.Node('D'), W: 9}, {F: simple.Node('B'), T: simple.Node('E'), W: 7}, {F: simple.Node('C'), T: simple.Node('E'), W: 5}, {F: simple.Node('D'), T: simple.Node('E'), W: 15}, {F: simple.Node('D'), T: simple.Node('F'), W: 6}, {F: simple.Node('E'), T: simple.Node('F'), W: 8}, {F: simple.Node('E'), T: simple.Node('G'), W: 9}, {F: simple.Node('F'), T: simple.Node('G'), W: 11}, }, want: 39, treeEdges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('B'), W: 7}, {F: simple.Node('A'), T: simple.Node('D'), W: 5}, {F: simple.Node('B'), T: simple.Node('E'), W: 7}, {F: simple.Node('C'), T: simple.Node('E'), W: 5}, {F: simple.Node('D'), T: simple.Node('F'), W: 6}, {F: simple.Node('E'), T: simple.Node('G'), W: 9}, }, }, { // https://upload.wikimedia.org/wikipedia/commons/2/2e/Boruvka%27s_algorithm_%28Sollin%27s_algorithm%29_Anim.gif name: "Borůvka WP example", graph: func() spanningGraph { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('B'), W: 13}, {F: simple.Node('A'), T: simple.Node('C'), W: 6}, {F: simple.Node('B'), T: simple.Node('C'), W: 7}, {F: simple.Node('B'), T: simple.Node('D'), W: 1}, {F: simple.Node('C'), T: simple.Node('D'), W: 14}, {F: simple.Node('C'), T: simple.Node('E'), W: 8}, {F: simple.Node('C'), T: simple.Node('H'), W: 20}, {F: simple.Node('D'), T: simple.Node('E'), W: 9}, {F: simple.Node('D'), T: simple.Node('F'), W: 3}, {F: simple.Node('E'), T: simple.Node('F'), W: 2}, {F: simple.Node('E'), T: simple.Node('J'), W: 18}, {F: simple.Node('G'), T: simple.Node('H'), W: 15}, {F: simple.Node('G'), T: simple.Node('I'), W: 5}, {F: simple.Node('G'), T: simple.Node('J'), W: 19}, {F: simple.Node('G'), T: simple.Node('K'), W: 10}, {F: simple.Node('H'), T: simple.Node('J'), W: 17}, {F: simple.Node('I'), T: simple.Node('K'), W: 11}, {F: simple.Node('J'), T: simple.Node('K'), W: 16}, {F: simple.Node('J'), T: simple.Node('L'), W: 4}, {F: simple.Node('K'), T: simple.Node('L'), W: 12}, }, want: 83, treeEdges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('C'), W: 6}, {F: simple.Node('B'), T: simple.Node('C'), W: 7}, {F: simple.Node('B'), T: simple.Node('D'), W: 1}, {F: simple.Node('D'), T: simple.Node('F'), W: 3}, {F: simple.Node('E'), T: simple.Node('F'), W: 2}, {F: simple.Node('E'), T: simple.Node('J'), W: 18}, {F: simple.Node('G'), T: simple.Node('H'), W: 15}, {F: simple.Node('G'), T: simple.Node('I'), W: 5}, {F: simple.Node('G'), T: simple.Node('K'), W: 10}, {F: simple.Node('J'), T: simple.Node('L'), W: 4}, {F: simple.Node('K'), T: simple.Node('L'), W: 12}, }, }, { // https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg // Nodes labelled row major. name: "Minimum Spanning Tree WP figure 1", graph: func() spanningGraph { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 4}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(4), W: 4}, {F: simple.Node(2), T: simple.Node(3), W: 5}, {F: simple.Node(2), T: simple.Node(5), W: 9}, {F: simple.Node(2), T: simple.Node(6), W: 9}, {F: simple.Node(2), T: simple.Node(8), W: 7}, {F: simple.Node(3), T: simple.Node(4), W: 3}, {F: simple.Node(3), T: simple.Node(8), W: 9}, {F: simple.Node(4), T: simple.Node(8), W: 10}, {F: simple.Node(4), T: simple.Node(10), W: 18}, {F: simple.Node(5), T: simple.Node(6), W: 2}, {F: simple.Node(5), T: simple.Node(7), W: 4}, {F: simple.Node(5), T: simple.Node(9), W: 6}, {F: simple.Node(6), T: simple.Node(7), W: 2}, {F: simple.Node(6), T: simple.Node(8), W: 8}, {F: simple.Node(7), T: simple.Node(8), W: 9}, {F: simple.Node(7), T: simple.Node(9), W: 3}, {F: simple.Node(7), T: simple.Node(10), W: 9}, {F: simple.Node(8), T: simple.Node(10), W: 8}, {F: simple.Node(9), T: simple.Node(10), W: 9}, }, want: 38, treeEdges: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 4}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(2), T: simple.Node(8), W: 7}, {F: simple.Node(3), T: simple.Node(4), W: 3}, {F: simple.Node(5), T: simple.Node(6), W: 2}, {F: simple.Node(6), T: simple.Node(7), W: 2}, {F: simple.Node(6), T: simple.Node(8), W: 8}, {F: simple.Node(7), T: simple.Node(9), W: 3}, {F: simple.Node(8), T: simple.Node(10), W: 8}, }, }, { // https://upload.wikimedia.org/wikipedia/commons/2/2e/Boruvka%27s_algorithm_%28Sollin%27s_algorithm%29_Anim.gif // but with C--H and E--J cut. name: "Borůvka WP example cut", graph: func() spanningGraph { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('B'), W: 13}, {F: simple.Node('A'), T: simple.Node('C'), W: 6}, {F: simple.Node('B'), T: simple.Node('C'), W: 7}, {F: simple.Node('B'), T: simple.Node('D'), W: 1}, {F: simple.Node('C'), T: simple.Node('D'), W: 14}, {F: simple.Node('C'), T: simple.Node('E'), W: 8}, {F: simple.Node('D'), T: simple.Node('E'), W: 9}, {F: simple.Node('D'), T: simple.Node('F'), W: 3}, {F: simple.Node('E'), T: simple.Node('F'), W: 2}, {F: simple.Node('G'), T: simple.Node('H'), W: 15}, {F: simple.Node('G'), T: simple.Node('I'), W: 5}, {F: simple.Node('G'), T: simple.Node('J'), W: 19}, {F: simple.Node('G'), T: simple.Node('K'), W: 10}, {F: simple.Node('H'), T: simple.Node('J'), W: 17}, {F: simple.Node('I'), T: simple.Node('K'), W: 11}, {F: simple.Node('J'), T: simple.Node('K'), W: 16}, {F: simple.Node('J'), T: simple.Node('L'), W: 4}, {F: simple.Node('K'), T: simple.Node('L'), W: 12}, }, want: 65, treeEdges: []simple.WeightedEdge{ {F: simple.Node('A'), T: simple.Node('C'), W: 6}, {F: simple.Node('B'), T: simple.Node('C'), W: 7}, {F: simple.Node('B'), T: simple.Node('D'), W: 1}, {F: simple.Node('D'), T: simple.Node('F'), W: 3}, {F: simple.Node('E'), T: simple.Node('F'), W: 2}, {F: simple.Node('G'), T: simple.Node('H'), W: 15}, {F: simple.Node('G'), T: simple.Node('I'), W: 5}, {F: simple.Node('G'), T: simple.Node('K'), W: 10}, {F: simple.Node('J'), T: simple.Node('L'), W: 4}, {F: simple.Node('K'), T: simple.Node('L'), W: 12}, }, }, } func testMinimumSpanning(mst func(dst WeightedBuilder, g spanningGraph) float64, t *testing.T) { for _, test := range spanningTreeTests { g := test.graph() for _, e := range test.edges { g.SetWeightedEdge(e) } dst := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) w := mst(dst, g) if w != test.want { t.Errorf("unexpected minimum spanning tree weight for %q: got: %f want: %f", test.name, w, test.want) } var got float64 for _, e := range graph.WeightedEdgesOf(dst.WeightedEdges()) { got += e.Weight() } if got != test.want { t.Errorf("unexpected minimum spanning tree edge weight sum for %q: got: %f want: %f", test.name, got, test.want) } gotEdges := graph.EdgesOf(dst.Edges()) if len(gotEdges) != len(test.treeEdges) { t.Errorf("unexpected number of spanning tree edges for %q: got: %d want: %d", test.name, len(gotEdges), len(test.treeEdges)) } for _, e := range test.treeEdges { w, ok := dst.Weight(e.From().ID(), e.To().ID()) if !ok { t.Errorf("spanning tree edge not found in graph for %q: %+v", test.name, e) } if w != e.Weight() { t.Errorf("unexpected spanning tree edge weight for %q: got: %f want: %f", test.name, w, e.Weight()) } } } } func TestKruskal(t *testing.T) { t.Parallel() testMinimumSpanning(func(dst WeightedBuilder, g spanningGraph) float64 { return Kruskal(dst, g) }, t) } func TestPrim(t *testing.T) { t.Parallel() testMinimumSpanning(func(dst WeightedBuilder, g spanningGraph) float64 { return Prim(dst, g) }, t) } golang-gonum-v1-gonum-0.14.0/graph/path/testdata/000077500000000000000000000000001450372207100215045ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/000077500000000000000000000000001450372207100224535ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/README000066400000000000000000000003761450372207100233410ustar00rootroot00000000000000DOT files placed in this directory will be used to run benchmarks on the path.Dominators function. The DOT files included should contain one node that has the label "entry" or "root". This node will be used as the control flow entry point to the graph. golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n1024.dot000066400000000000000000002523351450372207100257610ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 6150; 14; 6149; 19; 6148; 24; 6147; 29; 6146; 34; 6145; 39; 6144; 44; 6143; 49; 6142; 54; 6141; 59; 6140; 64; 6139; 69; 6138; 74; 6137; 79; 6136; 84; 6135; 89; 6134; 94; 6133; 99; 6132; 104; 6131; 109; 6130; 114; 6129; 119; 6128; 124; 6127; 129; 6126; 134; 6125; 139; 6124; 144; 6123; 149; 6122; 154; 6121; 159; 6120; 164; 6119; 169; 6118; 174; 6117; 179; 6116; 184; 6115; 189; 6114; 194; 6113; 199; 6112; 204; 6111; 209; 6110; 214; 6109; 219; 6108; 224; 6107; 229; 6106; 234; 6105; 239; 6104; 244; 6103; 249; 6102; 254; 6101; 259; 6100; 264; 6099; 269; 6098; 274; 6097; 279; 6096; 284; 6095; 289; 6094; 294; 6093; 299; 6092; 304; 6091; 309; 6090; 314; 6089; 319; 6088; 324; 6087; 329; 6086; 334; 6085; 339; 6084; 344; 6083; 349; 6082; 354; 6081; 359; 6080; 364; 6079; 369; 6078; 374; 6077; 379; 6076; 384; 6075; 389; 6074; 394; 6073; 399; 6072; 404; 6071; 409; 6070; 414; 6069; 419; 6068; 424; 6067; 429; 6066; 434; 6065; 439; 6064; 444; 6063; 449; 6062; 454; 6061; 459; 6060; 464; 6059; 469; 6058; 474; 6057; 479; 6056; 484; 6055; 489; 6054; 494; 6053; 499; 6052; 504; 6051; 509; 6050; 514; 6049; 519; 6048; 524; 6047; 529; 6046; 534; 6045; 539; 6044; 544; 6043; 549; 6042; 554; 6041; 559; 6040; 564; 6039; 569; 6038; 574; 6037; 579; 6036; 584; 6035; 589; 6034; 594; 6033; 599; 6032; 604; 6031; 609; 6030; 614; 6029; 619; 6028; 624; 6027; 629; 6026; 634; 6025; 639; 6024; 644; 6023; 649; 6022; 654; 6021; 659; 6020; 664; 6019; 669; 6018; 674; 6017; 679; 6016; 684; 6015; 689; 6014; 694; 6013; 699; 6012; 704; 6011; 709; 6010; 714; 6009; 719; 6008; 724; 6007; 729; 6006; 734; 6005; 739; 6004; 744; 6003; 749; 6002; 754; 6001; 759; 6000; 764; 5999; 769; 5998; 774; 5997; 779; 5996; 784; 5995; 789; 5994; 794; 5993; 799; 5992; 804; 5991; 809; 5990; 814; 5989; 819; 5988; 824; 5987; 829; 5986; 834; 5985; 839; 5984; 844; 5983; 849; 5982; 854; 5981; 859; 5980; 864; 5979; 869; 5978; 874; 5977; 879; 5976; 884; 5975; 889; 5974; 894; 5973; 899; 5972; 904; 5971; 909; 5970; 914; 5969; 919; 5968; 924; 5967; 929; 5966; 934; 5965; 939; 5964; 944; 5963; 949; 5962; 954; 5961; 959; 5960; 964; 5959; 969; 5958; 974; 5957; 979; 5956; 984; 5955; 989; 5954; 994; 5953; 999; 5952; 1004; 5951; 1009; 5950; 1014; 5949; 1019; 5948; 1024; 5947; 1029; 5946; 1034; 5945; 1039; 5944; 1044; 5943; 1049; 5942; 1054; 5941; 1059; 5940; 1064; 5939; 1069; 5938; 1074; 5937; 1079; 5936; 1084; 5935; 1089; 5934; 1094; 5933; 1099; 5932; 1104; 5931; 1109; 5930; 1114; 5929; 1119; 5928; 1124; 5927; 1129; 5926; 1134; 5925; 1139; 5924; 1144; 5923; 1149; 5922; 1154; 5921; 1159; 5920; 1164; 5919; 1169; 5918; 1174; 5917; 1179; 5916; 1184; 5915; 1189; 5914; 1194; 5913; 1199; 5912; 1204; 5911; 1209; 5910; 1214; 5909; 1219; 5908; 1224; 5907; 1229; 5906; 1234; 5905; 1239; 5904; 1244; 5903; 1249; 5902; 1254; 5901; 1259; 5900; 1264; 5899; 1269; 5898; 1274; 5897; 1279; 5896; 1284; 5895; 1289; 5894; 1294; 5893; 1299; 5892; 1304; 5891; 1309; 5890; 1314; 5889; 1319; 5888; 1324; 5887; 1329; 5886; 1334; 5885; 1339; 5884; 1344; 5883; 1349; 5882; 1354; 5881; 1359; 5880; 1364; 5879; 1369; 5878; 1374; 5877; 1379; 5876; 1384; 5875; 1389; 5874; 1394; 5873; 1399; 5872; 1404; 5871; 1409; 5870; 1414; 5869; 1419; 5868; 1424; 5867; 1429; 5866; 1434; 5865; 1439; 5864; 1444; 5863; 1449; 5862; 1454; 5861; 1459; 5860; 1464; 5859; 1469; 5858; 1474; 5857; 1479; 5856; 1484; 5855; 1489; 5854; 1494; 5853; 1499; 5852; 1504; 5851; 1509; 5850; 1514; 5849; 1519; 5848; 1524; 5847; 1529; 5846; 1534; 5845; 1539; 5844; 1544; 5843; 1549; 5842; 1554; 5841; 1559; 5840; 1564; 5839; 1569; 5838; 1574; 5837; 1579; 5836; 1584; 5835; 1589; 5834; 1594; 5833; 1599; 5832; 1604; 5831; 1609; 5830; 1614; 5829; 1619; 5828; 1624; 5827; 1629; 5826; 1634; 5825; 1639; 5824; 1644; 5823; 1649; 5822; 1654; 5821; 1659; 5820; 1664; 5819; 1669; 5818; 1674; 5817; 1679; 5816; 1684; 5815; 1689; 5814; 1694; 5813; 1699; 5812; 1704; 5811; 1709; 5810; 1714; 5809; 1719; 5808; 1724; 5807; 1729; 5806; 1734; 5805; 1739; 5804; 1744; 5803; 1749; 5802; 1754; 5801; 1759; 5800; 1764; 5799; 1769; 5798; 1774; 5797; 1779; 5796; 1784; 5795; 1789; 5794; 1794; 5793; 1799; 5792; 1804; 5791; 1809; 5790; 1814; 5789; 1819; 5788; 1824; 5787; 1829; 5786; 1834; 5785; 1839; 5784; 1844; 5783; 1849; 5782; 1854; 5781; 1859; 5780; 1864; 5779; 1869; 5778; 1874; 5777; 1879; 5776; 1884; 5775; 1889; 5774; 1894; 5773; 1899; 5772; 1904; 5771; 1909; 5770; 1914; 5769; 1919; 5768; 1924; 5767; 1929; 5766; 1934; 5765; 1939; 5764; 1944; 5763; 1949; 5762; 1954; 5761; 1959; 5760; 1964; 5759; 1969; 5758; 1974; 5757; 1979; 5756; 1984; 5755; 1989; 5754; 1994; 5753; 1999; 5752; 2004; 5751; 2009; 5750; 2014; 5749; 2019; 5748; 2024; 5747; 2029; 5746; 2034; 5745; 2039; 5744; 2044; 5743; 2049; 5742; 2054; 5741; 2059; 5740; 2064; 5739; 2069; 5738; 2074; 5737; 2079; 5736; 2084; 5735; 2089; 5734; 2094; 5733; 2099; 5732; 2104; 5731; 2109; 5730; 2114; 5729; 2119; 5728; 2124; 5727; 2129; 5726; 2134; 5725; 2139; 5724; 2144; 5723; 2149; 5722; 2154; 5721; 2159; 5720; 2164; 5719; 2169; 5718; 2174; 5717; 2179; 5716; 2184; 5715; 2189; 5714; 2194; 5713; 2199; 5712; 2204; 5711; 2209; 5710; 2214; 5709; 2219; 5708; 2224; 5707; 2229; 5706; 2234; 5705; 2239; 5704; 2244; 5703; 2249; 5702; 2254; 5701; 2259; 5700; 2264; 5699; 2269; 5698; 2274; 5697; 2279; 5696; 2284; 5695; 2289; 5694; 2294; 5693; 2299; 5692; 2304; 5691; 2309; 5690; 2314; 5689; 2319; 5688; 2324; 5687; 2329; 5686; 2334; 5685; 2339; 5684; 2344; 5683; 2349; 5682; 2354; 5681; 2359; 5680; 2364; 5679; 2369; 5678; 2374; 5677; 2379; 5676; 2384; 5675; 2389; 5674; 2394; 5673; 2399; 5672; 2404; 5671; 2409; 5670; 2414; 5669; 2419; 5668; 2424; 5667; 2429; 5666; 2434; 5665; 2439; 5664; 2444; 5663; 2449; 5662; 2454; 5661; 2459; 5660; 2464; 5659; 2469; 5658; 2474; 5657; 2479; 5656; 2484; 5655; 2489; 5654; 2494; 5653; 2499; 5652; 2504; 5651; 2509; 5650; 2514; 5649; 2519; 5648; 2524; 5647; 2529; 5646; 2534; 5645; 2539; 5644; 2544; 5643; 2549; 5642; 2554; 5641; 2559; 5640; 2564; 5639; 2569; 5638; 2574; 5637; 2579; 5636; 2584; 5635; 2589; 5634; 2594; 5633; 2599; 5632; 2604; 5631; 2609; 5630; 2614; 5629; 2619; 5628; 2624; 5627; 2629; 5626; 2634; 5625; 2639; 5624; 2644; 5623; 2649; 5622; 2654; 5621; 2659; 5620; 2664; 5619; 2669; 5618; 2674; 5617; 2679; 5616; 2684; 5615; 2689; 5614; 2694; 5613; 2699; 5612; 2704; 5611; 2709; 5610; 2714; 5609; 2719; 5608; 2724; 5607; 2729; 5606; 2734; 5605; 2739; 5604; 2744; 5603; 2749; 5602; 2754; 5601; 2759; 5600; 2764; 5599; 2769; 5598; 2774; 5597; 2779; 5596; 2784; 5595; 2789; 5594; 2794; 5593; 2799; 5592; 2804; 5591; 2809; 5590; 2814; 5589; 2819; 5588; 2824; 5587; 2829; 5586; 2834; 5585; 2839; 5584; 2844; 5583; 2849; 5582; 2854; 5581; 2859; 5580; 2864; 5579; 2869; 5578; 2874; 5577; 2879; 5576; 2884; 5575; 2889; 5574; 2894; 5573; 2899; 5572; 2904; 5571; 2909; 5570; 2914; 5569; 2919; 5568; 2924; 5567; 2929; 5566; 2934; 5565; 2939; 5564; 2944; 5563; 2949; 5562; 2954; 5561; 2959; 5560; 2964; 5559; 2969; 5558; 2974; 5557; 2979; 5556; 2984; 5555; 2989; 5554; 2994; 5553; 2999; 5552; 3004; 5551; 3009; 5550; 3014; 5549; 3019; 5548; 3024; 5547; 3029; 5546; 3034; 5545; 3039; 5544; 3044; 5543; 3049; 5542; 3054; 5541; 3059; 5540; 3064; 5539; 3069; 5538; 3074; 5537; 3079; 5536; 3084; 5535; 3089; 5534; 3094; 5533; 3099; 5532; 3104; 5531; 3109; 5530; 3114; 5529; 3119; 5528; 3124; 5527; 3129; 5526; 3134; 5525; 3139; 5524; 3144; 5523; 3149; 5522; 3154; 5521; 3159; 5520; 3164; 5519; 3169; 5518; 3174; 5517; 3179; 5516; 3184; 5515; 3189; 5514; 3194; 5513; 3199; 5512; 3204; 5511; 3209; 5510; 3214; 5509; 3219; 5508; 3224; 5507; 3229; 5506; 3234; 5505; 3239; 5504; 3244; 5503; 3249; 5502; 3254; 5501; 3259; 5500; 3264; 5499; 3269; 5498; 3274; 5497; 3279; 5496; 3284; 5495; 3289; 5494; 3294; 5493; 3299; 5492; 3304; 5491; 3309; 5490; 3314; 5489; 3319; 5488; 3324; 5487; 3329; 5486; 3334; 5485; 3339; 5484; 3344; 5483; 3349; 5482; 3354; 5481; 3359; 5480; 3364; 5479; 3369; 5478; 3374; 5477; 3379; 5476; 3384; 5475; 3389; 5474; 3394; 5473; 3399; 5472; 3404; 5471; 3409; 5470; 3414; 5469; 3419; 5468; 3424; 5467; 3429; 5466; 3434; 5465; 3439; 5464; 3444; 5463; 3449; 5462; 3454; 5461; 3459; 5460; 3464; 5459; 3469; 5458; 3474; 5457; 3479; 5456; 3484; 5455; 3489; 5454; 3494; 5453; 3499; 5452; 3504; 5451; 3509; 5450; 3514; 5449; 3519; 5448; 3524; 5447; 3529; 5446; 3534; 5445; 3539; 5444; 3544; 5443; 3549; 5442; 3554; 5441; 3559; 5440; 3564; 5439; 3569; 5438; 3574; 5437; 3579; 5436; 3584; 5435; 3589; 5434; 3594; 5433; 3599; 5432; 3604; 5431; 3609; 5430; 3614; 5429; 3619; 5428; 3624; 5427; 3629; 5426; 3634; 5425; 3639; 5424; 3644; 5423; 3649; 5422; 3654; 5421; 3659; 5420; 3664; 5419; 3669; 5418; 3674; 5417; 3679; 5416; 3684; 5415; 3689; 5414; 3694; 5413; 3699; 5412; 3704; 5411; 3709; 5410; 3714; 5409; 3719; 5408; 3724; 5407; 3729; 5406; 3734; 5405; 3739; 5404; 3744; 5403; 3749; 5402; 3754; 5401; 3759; 5400; 3764; 5399; 3769; 5398; 3774; 5397; 3779; 5396; 3784; 5395; 3789; 5394; 3794; 5393; 3799; 5392; 3804; 5391; 3809; 5390; 3814; 5389; 3819; 5388; 3824; 5387; 3829; 5386; 3834; 5385; 3839; 5384; 3844; 5383; 3849; 5382; 3854; 5381; 3859; 5380; 3864; 5379; 3869; 5378; 3874; 5377; 3879; 5376; 3884; 5375; 3889; 5374; 3894; 5373; 3899; 5372; 3904; 5371; 3909; 5370; 3914; 5369; 3919; 5368; 3924; 5367; 3929; 5366; 3934; 5365; 3939; 5364; 3944; 5363; 3949; 5362; 3954; 5361; 3959; 5360; 3964; 5359; 3969; 5358; 3974; 5357; 3979; 5356; 3984; 5355; 3989; 5354; 3994; 5353; 3999; 5352; 4004; 5351; 4009; 5350; 4014; 5349; 4019; 5348; 4024; 5347; 4029; 5346; 4034; 5345; 4039; 5344; 4044; 5343; 4049; 5342; 4054; 5341; 4059; 5340; 4064; 5339; 4069; 5338; 4074; 5337; 4079; 5336; 4084; 5335; 4089; 5334; 4094; 5333; 4099; 5332; 4104; 5331; 4109; 5330; 4114; 5329; 4119; 5328; 4124; 5327; 4129; 5326; 4134; 5325; 4139; 5324; 4144; 5323; 4149; 5322; 4154; 5321; 4159; 5320; 4164; 5319; 4169; 5318; 4174; 5317; 4179; 5316; 4184; 5315; 4189; 5314; 4194; 5313; 4199; 5312; 4204; 5311; 4209; 5310; 4214; 5309; 4219; 5308; 4224; 5307; 4229; 5306; 4234; 5305; 4239; 5304; 4244; 5303; 4249; 5302; 4254; 5301; 4259; 5300; 4264; 5299; 4269; 5298; 4274; 5297; 4279; 5296; 4284; 5295; 4289; 5294; 4294; 5293; 4299; 5292; 4304; 5291; 4309; 5290; 4314; 5289; 4319; 5288; 4324; 5287; 4329; 5286; 4334; 5285; 4339; 5284; 4344; 5283; 4349; 5282; 4354; 5281; 4359; 5280; 4364; 5279; 4369; 5278; 4374; 5277; 4379; 5276; 4384; 5275; 4389; 5274; 4394; 5273; 4399; 5272; 4404; 5271; 4409; 5270; 4414; 5269; 4419; 5268; 4424; 5267; 4429; 5266; 4434; 5265; 4439; 5264; 4444; 5263; 4449; 5262; 4454; 5261; 4459; 5260; 4464; 5259; 4469; 5258; 4474; 5257; 4479; 5256; 4484; 5255; 4489; 5254; 4494; 5253; 4499; 5252; 4504; 5251; 4509; 5250; 4514; 5249; 4519; 5248; 4524; 5247; 4529; 5246; 4534; 5245; 4539; 5244; 4544; 5243; 4549; 5242; 4554; 5241; 4559; 5240; 4564; 5239; 4569; 5238; 4574; 5237; 4579; 5236; 4584; 5235; 4589; 5234; 4594; 5233; 4599; 5232; 4604; 5231; 4609; 5230; 4614; 5229; 4619; 5228; 4624; 5227; 4629; 5226; 4634; 5225; 4639; 5224; 4644; 5223; 4649; 5222; 4654; 5221; 4659; 5220; 4664; 5219; 4669; 5218; 4674; 5217; 4679; 5216; 4684; 5215; 4689; 5214; 4694; 5213; 4699; 5212; 4704; 5211; 4709; 5210; 4714; 5209; 4719; 5208; 4724; 5207; 4729; 5206; 4734; 5205; 4739; 5204; 4744; 5203; 4749; 5202; 4754; 5201; 4759; 5200; 4764; 5199; 4769; 5198; 4774; 5197; 4779; 5196; 4784; 5195; 4789; 5194; 4794; 5193; 4799; 5192; 4804; 5191; 4809; 5190; 4814; 5189; 4819; 5188; 4824; 5187; 4829; 5186; 4834; 5185; 4839; 5184; 4844; 5183; 4849; 5182; 4854; 5181; 4859; 5180; 4864; 5179; 4869; 5178; 4874; 5177; 4879; 5176; 4884; 5175; 4889; 5174; 4894; 5173; 4899; 5172; 4904; 5171; 4909; 5170; 4914; 5169; 4919; 5168; 4924; 5167; 4929; 5166; 4934; 5165; 4939; 5164; 4944; 5163; 4949; 5162; 4954; 5161; 4959; 5160; 4964; 5159; 4969; 5158; 4974; 5157; 4979; 5156; 4984; 5155; 4989; 5154; 4994; 5153; 4999; 5152; 5004; 5151; 5009; 5150; 5014; 5149; 5019; 5148; 5024; 5147; 5029; 5146; 5034; 5145; 5039; 5144; 5044; 5143; 5049; 5142; 5054; 5141; 5059; 5140; 5064; 5139; 5069; 5138; 5074; 5137; 5079; 5136; 5084; 5135; 5089; 5134; 5094; 5133; 5099; 5132; 5104; 5131; 5109; 5130; 5114; 5129; 5119; 5128; 5124; 5127; // Edge definitions. 2 -> 9 [label=true]; 2 -> 6150 [label=false]; 9 -> 14 [label=true]; 9 -> 6149 [label=false]; 14 -> 19 [label=true]; 14 -> 6148 [label=false]; 6149 -> 6150; 19 -> 24 [label=true]; 19 -> 6147 [label=false]; 6148 -> 6149; 24 -> 29 [label=true]; 24 -> 6146 [label=false]; 6147 -> 6148; 29 -> 34 [label=true]; 29 -> 6145 [label=false]; 6146 -> 6147; 34 -> 39 [label=true]; 34 -> 6144 [label=false]; 6145 -> 6146; 39 -> 44 [label=true]; 39 -> 6143 [label=false]; 6144 -> 6145; 44 -> 49 [label=true]; 44 -> 6142 [label=false]; 6143 -> 6144; 49 -> 54 [label=true]; 49 -> 6141 [label=false]; 6142 -> 6143; 54 -> 59 [label=true]; 54 -> 6140 [label=false]; 6141 -> 6142; 59 -> 64 [label=true]; 59 -> 6139 [label=false]; 6140 -> 6141; 64 -> 69 [label=true]; 64 -> 6138 [label=false]; 6139 -> 6140; 69 -> 74 [label=true]; 69 -> 6137 [label=false]; 6138 -> 6139; 74 -> 79 [label=true]; 74 -> 6136 [label=false]; 6137 -> 6138; 79 -> 84 [label=true]; 79 -> 6135 [label=false]; 6136 -> 6137; 84 -> 89 [label=true]; 84 -> 6134 [label=false]; 6135 -> 6136; 89 -> 94 [label=true]; 89 -> 6133 [label=false]; 6134 -> 6135; 94 -> 99 [label=true]; 94 -> 6132 [label=false]; 6133 -> 6134; 99 -> 104 [label=true]; 99 -> 6131 [label=false]; 6132 -> 6133; 104 -> 109 [label=true]; 104 -> 6130 [label=false]; 6131 -> 6132; 109 -> 114 [label=true]; 109 -> 6129 [label=false]; 6130 -> 6131; 114 -> 119 [label=true]; 114 -> 6128 [label=false]; 6129 -> 6130; 119 -> 124 [label=true]; 119 -> 6127 [label=false]; 6128 -> 6129; 124 -> 129 [label=true]; 124 -> 6126 [label=false]; 6127 -> 6128; 129 -> 134 [label=true]; 129 -> 6125 [label=false]; 6126 -> 6127; 134 -> 139 [label=true]; 134 -> 6124 [label=false]; 6125 -> 6126; 139 -> 144 [label=true]; 139 -> 6123 [label=false]; 6124 -> 6125; 144 -> 149 [label=true]; 144 -> 6122 [label=false]; 6123 -> 6124; 149 -> 154 [label=true]; 149 -> 6121 [label=false]; 6122 -> 6123; 154 -> 159 [label=true]; 154 -> 6120 [label=false]; 6121 -> 6122; 159 -> 164 [label=true]; 159 -> 6119 [label=false]; 6120 -> 6121; 164 -> 169 [label=true]; 164 -> 6118 [label=false]; 6119 -> 6120; 169 -> 174 [label=true]; 169 -> 6117 [label=false]; 6118 -> 6119; 174 -> 179 [label=true]; 174 -> 6116 [label=false]; 6117 -> 6118; 179 -> 184 [label=true]; 179 -> 6115 [label=false]; 6116 -> 6117; 184 -> 189 [label=true]; 184 -> 6114 [label=false]; 6115 -> 6116; 189 -> 194 [label=true]; 189 -> 6113 [label=false]; 6114 -> 6115; 194 -> 199 [label=true]; 194 -> 6112 [label=false]; 6113 -> 6114; 199 -> 204 [label=true]; 199 -> 6111 [label=false]; 6112 -> 6113; 204 -> 209 [label=true]; 204 -> 6110 [label=false]; 6111 -> 6112; 209 -> 214 [label=true]; 209 -> 6109 [label=false]; 6110 -> 6111; 214 -> 219 [label=true]; 214 -> 6108 [label=false]; 6109 -> 6110; 219 -> 224 [label=true]; 219 -> 6107 [label=false]; 6108 -> 6109; 224 -> 229 [label=true]; 224 -> 6106 [label=false]; 6107 -> 6108; 229 -> 234 [label=true]; 229 -> 6105 [label=false]; 6106 -> 6107; 234 -> 239 [label=true]; 234 -> 6104 [label=false]; 6105 -> 6106; 239 -> 244 [label=true]; 239 -> 6103 [label=false]; 6104 -> 6105; 244 -> 249 [label=true]; 244 -> 6102 [label=false]; 6103 -> 6104; 249 -> 254 [label=true]; 249 -> 6101 [label=false]; 6102 -> 6103; 254 -> 259 [label=true]; 254 -> 6100 [label=false]; 6101 -> 6102; 259 -> 264 [label=true]; 259 -> 6099 [label=false]; 6100 -> 6101; 264 -> 269 [label=true]; 264 -> 6098 [label=false]; 6099 -> 6100; 269 -> 274 [label=true]; 269 -> 6097 [label=false]; 6098 -> 6099; 274 -> 279 [label=true]; 274 -> 6096 [label=false]; 6097 -> 6098; 279 -> 284 [label=true]; 279 -> 6095 [label=false]; 6096 -> 6097; 284 -> 289 [label=true]; 284 -> 6094 [label=false]; 6095 -> 6096; 289 -> 294 [label=true]; 289 -> 6093 [label=false]; 6094 -> 6095; 294 -> 299 [label=true]; 294 -> 6092 [label=false]; 6093 -> 6094; 299 -> 304 [label=true]; 299 -> 6091 [label=false]; 6092 -> 6093; 304 -> 309 [label=true]; 304 -> 6090 [label=false]; 6091 -> 6092; 309 -> 314 [label=true]; 309 -> 6089 [label=false]; 6090 -> 6091; 314 -> 319 [label=true]; 314 -> 6088 [label=false]; 6089 -> 6090; 319 -> 324 [label=true]; 319 -> 6087 [label=false]; 6088 -> 6089; 324 -> 329 [label=true]; 324 -> 6086 [label=false]; 6087 -> 6088; 329 -> 334 [label=true]; 329 -> 6085 [label=false]; 6086 -> 6087; 334 -> 339 [label=true]; 334 -> 6084 [label=false]; 6085 -> 6086; 339 -> 344 [label=true]; 339 -> 6083 [label=false]; 6084 -> 6085; 344 -> 349 [label=true]; 344 -> 6082 [label=false]; 6083 -> 6084; 349 -> 354 [label=true]; 349 -> 6081 [label=false]; 6082 -> 6083; 354 -> 359 [label=true]; 354 -> 6080 [label=false]; 6081 -> 6082; 359 -> 364 [label=true]; 359 -> 6079 [label=false]; 6080 -> 6081; 364 -> 369 [label=true]; 364 -> 6078 [label=false]; 6079 -> 6080; 369 -> 374 [label=true]; 369 -> 6077 [label=false]; 6078 -> 6079; 374 -> 379 [label=true]; 374 -> 6076 [label=false]; 6077 -> 6078; 379 -> 384 [label=true]; 379 -> 6075 [label=false]; 6076 -> 6077; 384 -> 389 [label=true]; 384 -> 6074 [label=false]; 6075 -> 6076; 389 -> 394 [label=true]; 389 -> 6073 [label=false]; 6074 -> 6075; 394 -> 399 [label=true]; 394 -> 6072 [label=false]; 6073 -> 6074; 399 -> 404 [label=true]; 399 -> 6071 [label=false]; 6072 -> 6073; 404 -> 409 [label=true]; 404 -> 6070 [label=false]; 6071 -> 6072; 409 -> 414 [label=true]; 409 -> 6069 [label=false]; 6070 -> 6071; 414 -> 419 [label=true]; 414 -> 6068 [label=false]; 6069 -> 6070; 419 -> 424 [label=true]; 419 -> 6067 [label=false]; 6068 -> 6069; 424 -> 429 [label=true]; 424 -> 6066 [label=false]; 6067 -> 6068; 429 -> 434 [label=true]; 429 -> 6065 [label=false]; 6066 -> 6067; 434 -> 439 [label=true]; 434 -> 6064 [label=false]; 6065 -> 6066; 439 -> 444 [label=true]; 439 -> 6063 [label=false]; 6064 -> 6065; 444 -> 449 [label=true]; 444 -> 6062 [label=false]; 6063 -> 6064; 449 -> 454 [label=true]; 449 -> 6061 [label=false]; 6062 -> 6063; 454 -> 459 [label=true]; 454 -> 6060 [label=false]; 6061 -> 6062; 459 -> 464 [label=true]; 459 -> 6059 [label=false]; 6060 -> 6061; 464 -> 469 [label=true]; 464 -> 6058 [label=false]; 6059 -> 6060; 469 -> 474 [label=true]; 469 -> 6057 [label=false]; 6058 -> 6059; 474 -> 479 [label=true]; 474 -> 6056 [label=false]; 6057 -> 6058; 479 -> 484 [label=true]; 479 -> 6055 [label=false]; 6056 -> 6057; 484 -> 489 [label=true]; 484 -> 6054 [label=false]; 6055 -> 6056; 489 -> 494 [label=true]; 489 -> 6053 [label=false]; 6054 -> 6055; 494 -> 499 [label=true]; 494 -> 6052 [label=false]; 6053 -> 6054; 499 -> 504 [label=true]; 499 -> 6051 [label=false]; 6052 -> 6053; 504 -> 509 [label=true]; 504 -> 6050 [label=false]; 6051 -> 6052; 509 -> 514 [label=true]; 509 -> 6049 [label=false]; 6050 -> 6051; 514 -> 519 [label=true]; 514 -> 6048 [label=false]; 6049 -> 6050; 519 -> 524 [label=true]; 519 -> 6047 [label=false]; 6048 -> 6049; 524 -> 529 [label=true]; 524 -> 6046 [label=false]; 6047 -> 6048; 529 -> 534 [label=true]; 529 -> 6045 [label=false]; 6046 -> 6047; 534 -> 539 [label=true]; 534 -> 6044 [label=false]; 6045 -> 6046; 539 -> 544 [label=true]; 539 -> 6043 [label=false]; 6044 -> 6045; 544 -> 549 [label=true]; 544 -> 6042 [label=false]; 6043 -> 6044; 549 -> 554 [label=true]; 549 -> 6041 [label=false]; 6042 -> 6043; 554 -> 559 [label=true]; 554 -> 6040 [label=false]; 6041 -> 6042; 559 -> 564 [label=true]; 559 -> 6039 [label=false]; 6040 -> 6041; 564 -> 569 [label=true]; 564 -> 6038 [label=false]; 6039 -> 6040; 569 -> 574 [label=true]; 569 -> 6037 [label=false]; 6038 -> 6039; 574 -> 579 [label=true]; 574 -> 6036 [label=false]; 6037 -> 6038; 579 -> 584 [label=true]; 579 -> 6035 [label=false]; 6036 -> 6037; 584 -> 589 [label=true]; 584 -> 6034 [label=false]; 6035 -> 6036; 589 -> 594 [label=true]; 589 -> 6033 [label=false]; 6034 -> 6035; 594 -> 599 [label=true]; 594 -> 6032 [label=false]; 6033 -> 6034; 599 -> 604 [label=true]; 599 -> 6031 [label=false]; 6032 -> 6033; 604 -> 609 [label=true]; 604 -> 6030 [label=false]; 6031 -> 6032; 609 -> 614 [label=true]; 609 -> 6029 [label=false]; 6030 -> 6031; 614 -> 619 [label=true]; 614 -> 6028 [label=false]; 6029 -> 6030; 619 -> 624 [label=true]; 619 -> 6027 [label=false]; 6028 -> 6029; 624 -> 629 [label=true]; 624 -> 6026 [label=false]; 6027 -> 6028; 629 -> 634 [label=true]; 629 -> 6025 [label=false]; 6026 -> 6027; 634 -> 639 [label=true]; 634 -> 6024 [label=false]; 6025 -> 6026; 639 -> 644 [label=true]; 639 -> 6023 [label=false]; 6024 -> 6025; 644 -> 649 [label=true]; 644 -> 6022 [label=false]; 6023 -> 6024; 649 -> 654 [label=true]; 649 -> 6021 [label=false]; 6022 -> 6023; 654 -> 659 [label=true]; 654 -> 6020 [label=false]; 6021 -> 6022; 659 -> 664 [label=true]; 659 -> 6019 [label=false]; 6020 -> 6021; 664 -> 669 [label=true]; 664 -> 6018 [label=false]; 6019 -> 6020; 669 -> 674 [label=true]; 669 -> 6017 [label=false]; 6018 -> 6019; 674 -> 679 [label=true]; 674 -> 6016 [label=false]; 6017 -> 6018; 679 -> 684 [label=true]; 679 -> 6015 [label=false]; 6016 -> 6017; 684 -> 689 [label=true]; 684 -> 6014 [label=false]; 6015 -> 6016; 689 -> 694 [label=true]; 689 -> 6013 [label=false]; 6014 -> 6015; 694 -> 699 [label=true]; 694 -> 6012 [label=false]; 6013 -> 6014; 699 -> 704 [label=true]; 699 -> 6011 [label=false]; 6012 -> 6013; 704 -> 709 [label=true]; 704 -> 6010 [label=false]; 6011 -> 6012; 709 -> 714 [label=true]; 709 -> 6009 [label=false]; 6010 -> 6011; 714 -> 719 [label=true]; 714 -> 6008 [label=false]; 6009 -> 6010; 719 -> 724 [label=true]; 719 -> 6007 [label=false]; 6008 -> 6009; 724 -> 729 [label=true]; 724 -> 6006 [label=false]; 6007 -> 6008; 729 -> 734 [label=true]; 729 -> 6005 [label=false]; 6006 -> 6007; 734 -> 739 [label=true]; 734 -> 6004 [label=false]; 6005 -> 6006; 739 -> 744 [label=true]; 739 -> 6003 [label=false]; 6004 -> 6005; 744 -> 749 [label=true]; 744 -> 6002 [label=false]; 6003 -> 6004; 749 -> 754 [label=true]; 749 -> 6001 [label=false]; 6002 -> 6003; 754 -> 759 [label=true]; 754 -> 6000 [label=false]; 6001 -> 6002; 759 -> 764 [label=true]; 759 -> 5999 [label=false]; 6000 -> 6001; 764 -> 769 [label=true]; 764 -> 5998 [label=false]; 5999 -> 6000; 769 -> 774 [label=true]; 769 -> 5997 [label=false]; 5998 -> 5999; 774 -> 779 [label=true]; 774 -> 5996 [label=false]; 5997 -> 5998; 779 -> 784 [label=true]; 779 -> 5995 [label=false]; 5996 -> 5997; 784 -> 789 [label=true]; 784 -> 5994 [label=false]; 5995 -> 5996; 789 -> 794 [label=true]; 789 -> 5993 [label=false]; 5994 -> 5995; 794 -> 799 [label=true]; 794 -> 5992 [label=false]; 5993 -> 5994; 799 -> 804 [label=true]; 799 -> 5991 [label=false]; 5992 -> 5993; 804 -> 809 [label=true]; 804 -> 5990 [label=false]; 5991 -> 5992; 809 -> 814 [label=true]; 809 -> 5989 [label=false]; 5990 -> 5991; 814 -> 819 [label=true]; 814 -> 5988 [label=false]; 5989 -> 5990; 819 -> 824 [label=true]; 819 -> 5987 [label=false]; 5988 -> 5989; 824 -> 829 [label=true]; 824 -> 5986 [label=false]; 5987 -> 5988; 829 -> 834 [label=true]; 829 -> 5985 [label=false]; 5986 -> 5987; 834 -> 839 [label=true]; 834 -> 5984 [label=false]; 5985 -> 5986; 839 -> 844 [label=true]; 839 -> 5983 [label=false]; 5984 -> 5985; 844 -> 849 [label=true]; 844 -> 5982 [label=false]; 5983 -> 5984; 849 -> 854 [label=true]; 849 -> 5981 [label=false]; 5982 -> 5983; 854 -> 859 [label=true]; 854 -> 5980 [label=false]; 5981 -> 5982; 859 -> 864 [label=true]; 859 -> 5979 [label=false]; 5980 -> 5981; 864 -> 869 [label=true]; 864 -> 5978 [label=false]; 5979 -> 5980; 869 -> 874 [label=true]; 869 -> 5977 [label=false]; 5978 -> 5979; 874 -> 879 [label=true]; 874 -> 5976 [label=false]; 5977 -> 5978; 879 -> 884 [label=true]; 879 -> 5975 [label=false]; 5976 -> 5977; 884 -> 889 [label=true]; 884 -> 5974 [label=false]; 5975 -> 5976; 889 -> 894 [label=true]; 889 -> 5973 [label=false]; 5974 -> 5975; 894 -> 899 [label=true]; 894 -> 5972 [label=false]; 5973 -> 5974; 899 -> 904 [label=true]; 899 -> 5971 [label=false]; 5972 -> 5973; 904 -> 909 [label=true]; 904 -> 5970 [label=false]; 5971 -> 5972; 909 -> 914 [label=true]; 909 -> 5969 [label=false]; 5970 -> 5971; 914 -> 919 [label=true]; 914 -> 5968 [label=false]; 5969 -> 5970; 919 -> 924 [label=true]; 919 -> 5967 [label=false]; 5968 -> 5969; 924 -> 929 [label=true]; 924 -> 5966 [label=false]; 5967 -> 5968; 929 -> 934 [label=true]; 929 -> 5965 [label=false]; 5966 -> 5967; 934 -> 939 [label=true]; 934 -> 5964 [label=false]; 5965 -> 5966; 939 -> 944 [label=true]; 939 -> 5963 [label=false]; 5964 -> 5965; 944 -> 949 [label=true]; 944 -> 5962 [label=false]; 5963 -> 5964; 949 -> 954 [label=true]; 949 -> 5961 [label=false]; 5962 -> 5963; 954 -> 959 [label=true]; 954 -> 5960 [label=false]; 5961 -> 5962; 959 -> 964 [label=true]; 959 -> 5959 [label=false]; 5960 -> 5961; 964 -> 969 [label=true]; 964 -> 5958 [label=false]; 5959 -> 5960; 969 -> 974 [label=true]; 969 -> 5957 [label=false]; 5958 -> 5959; 974 -> 979 [label=true]; 974 -> 5956 [label=false]; 5957 -> 5958; 979 -> 984 [label=true]; 979 -> 5955 [label=false]; 5956 -> 5957; 984 -> 989 [label=true]; 984 -> 5954 [label=false]; 5955 -> 5956; 989 -> 994 [label=true]; 989 -> 5953 [label=false]; 5954 -> 5955; 994 -> 999 [label=true]; 994 -> 5952 [label=false]; 5953 -> 5954; 999 -> 1004 [label=true]; 999 -> 5951 [label=false]; 5952 -> 5953; 1004 -> 1009 [label=true]; 1004 -> 5950 [label=false]; 5951 -> 5952; 1009 -> 1014 [label=true]; 1009 -> 5949 [label=false]; 5950 -> 5951; 1014 -> 1019 [label=true]; 1014 -> 5948 [label=false]; 5949 -> 5950; 1019 -> 1024 [label=true]; 1019 -> 5947 [label=false]; 5948 -> 5949; 1024 -> 1029 [label=true]; 1024 -> 5946 [label=false]; 5947 -> 5948; 1029 -> 1034 [label=true]; 1029 -> 5945 [label=false]; 5946 -> 5947; 1034 -> 1039 [label=true]; 1034 -> 5944 [label=false]; 5945 -> 5946; 1039 -> 1044 [label=true]; 1039 -> 5943 [label=false]; 5944 -> 5945; 1044 -> 1049 [label=true]; 1044 -> 5942 [label=false]; 5943 -> 5944; 1049 -> 1054 [label=true]; 1049 -> 5941 [label=false]; 5942 -> 5943; 1054 -> 1059 [label=true]; 1054 -> 5940 [label=false]; 5941 -> 5942; 1059 -> 1064 [label=true]; 1059 -> 5939 [label=false]; 5940 -> 5941; 1064 -> 1069 [label=true]; 1064 -> 5938 [label=false]; 5939 -> 5940; 1069 -> 1074 [label=true]; 1069 -> 5937 [label=false]; 5938 -> 5939; 1074 -> 1079 [label=true]; 1074 -> 5936 [label=false]; 5937 -> 5938; 1079 -> 1084 [label=true]; 1079 -> 5935 [label=false]; 5936 -> 5937; 1084 -> 1089 [label=true]; 1084 -> 5934 [label=false]; 5935 -> 5936; 1089 -> 1094 [label=true]; 1089 -> 5933 [label=false]; 5934 -> 5935; 1094 -> 1099 [label=true]; 1094 -> 5932 [label=false]; 5933 -> 5934; 1099 -> 1104 [label=true]; 1099 -> 5931 [label=false]; 5932 -> 5933; 1104 -> 1109 [label=true]; 1104 -> 5930 [label=false]; 5931 -> 5932; 1109 -> 1114 [label=true]; 1109 -> 5929 [label=false]; 5930 -> 5931; 1114 -> 1119 [label=true]; 1114 -> 5928 [label=false]; 5929 -> 5930; 1119 -> 1124 [label=true]; 1119 -> 5927 [label=false]; 5928 -> 5929; 1124 -> 1129 [label=true]; 1124 -> 5926 [label=false]; 5927 -> 5928; 1129 -> 1134 [label=true]; 1129 -> 5925 [label=false]; 5926 -> 5927; 1134 -> 1139 [label=true]; 1134 -> 5924 [label=false]; 5925 -> 5926; 1139 -> 1144 [label=true]; 1139 -> 5923 [label=false]; 5924 -> 5925; 1144 -> 1149 [label=true]; 1144 -> 5922 [label=false]; 5923 -> 5924; 1149 -> 1154 [label=true]; 1149 -> 5921 [label=false]; 5922 -> 5923; 1154 -> 1159 [label=true]; 1154 -> 5920 [label=false]; 5921 -> 5922; 1159 -> 1164 [label=true]; 1159 -> 5919 [label=false]; 5920 -> 5921; 1164 -> 1169 [label=true]; 1164 -> 5918 [label=false]; 5919 -> 5920; 1169 -> 1174 [label=true]; 1169 -> 5917 [label=false]; 5918 -> 5919; 1174 -> 1179 [label=true]; 1174 -> 5916 [label=false]; 5917 -> 5918; 1179 -> 1184 [label=true]; 1179 -> 5915 [label=false]; 5916 -> 5917; 1184 -> 1189 [label=true]; 1184 -> 5914 [label=false]; 5915 -> 5916; 1189 -> 1194 [label=true]; 1189 -> 5913 [label=false]; 5914 -> 5915; 1194 -> 1199 [label=true]; 1194 -> 5912 [label=false]; 5913 -> 5914; 1199 -> 1204 [label=true]; 1199 -> 5911 [label=false]; 5912 -> 5913; 1204 -> 1209 [label=true]; 1204 -> 5910 [label=false]; 5911 -> 5912; 1209 -> 1214 [label=true]; 1209 -> 5909 [label=false]; 5910 -> 5911; 1214 -> 1219 [label=true]; 1214 -> 5908 [label=false]; 5909 -> 5910; 1219 -> 1224 [label=true]; 1219 -> 5907 [label=false]; 5908 -> 5909; 1224 -> 1229 [label=true]; 1224 -> 5906 [label=false]; 5907 -> 5908; 1229 -> 1234 [label=true]; 1229 -> 5905 [label=false]; 5906 -> 5907; 1234 -> 1239 [label=true]; 1234 -> 5904 [label=false]; 5905 -> 5906; 1239 -> 1244 [label=true]; 1239 -> 5903 [label=false]; 5904 -> 5905; 1244 -> 1249 [label=true]; 1244 -> 5902 [label=false]; 5903 -> 5904; 1249 -> 1254 [label=true]; 1249 -> 5901 [label=false]; 5902 -> 5903; 1254 -> 1259 [label=true]; 1254 -> 5900 [label=false]; 5901 -> 5902; 1259 -> 1264 [label=true]; 1259 -> 5899 [label=false]; 5900 -> 5901; 1264 -> 1269 [label=true]; 1264 -> 5898 [label=false]; 5899 -> 5900; 1269 -> 1274 [label=true]; 1269 -> 5897 [label=false]; 5898 -> 5899; 1274 -> 1279 [label=true]; 1274 -> 5896 [label=false]; 5897 -> 5898; 1279 -> 1284 [label=true]; 1279 -> 5895 [label=false]; 5896 -> 5897; 1284 -> 1289 [label=true]; 1284 -> 5894 [label=false]; 5895 -> 5896; 1289 -> 1294 [label=true]; 1289 -> 5893 [label=false]; 5894 -> 5895; 1294 -> 1299 [label=true]; 1294 -> 5892 [label=false]; 5893 -> 5894; 1299 -> 1304 [label=true]; 1299 -> 5891 [label=false]; 5892 -> 5893; 1304 -> 1309 [label=true]; 1304 -> 5890 [label=false]; 5891 -> 5892; 1309 -> 1314 [label=true]; 1309 -> 5889 [label=false]; 5890 -> 5891; 1314 -> 1319 [label=true]; 1314 -> 5888 [label=false]; 5889 -> 5890; 1319 -> 1324 [label=true]; 1319 -> 5887 [label=false]; 5888 -> 5889; 1324 -> 1329 [label=true]; 1324 -> 5886 [label=false]; 5887 -> 5888; 1329 -> 1334 [label=true]; 1329 -> 5885 [label=false]; 5886 -> 5887; 1334 -> 1339 [label=true]; 1334 -> 5884 [label=false]; 5885 -> 5886; 1339 -> 1344 [label=true]; 1339 -> 5883 [label=false]; 5884 -> 5885; 1344 -> 1349 [label=true]; 1344 -> 5882 [label=false]; 5883 -> 5884; 1349 -> 1354 [label=true]; 1349 -> 5881 [label=false]; 5882 -> 5883; 1354 -> 1359 [label=true]; 1354 -> 5880 [label=false]; 5881 -> 5882; 1359 -> 1364 [label=true]; 1359 -> 5879 [label=false]; 5880 -> 5881; 1364 -> 1369 [label=true]; 1364 -> 5878 [label=false]; 5879 -> 5880; 1369 -> 1374 [label=true]; 1369 -> 5877 [label=false]; 5878 -> 5879; 1374 -> 1379 [label=true]; 1374 -> 5876 [label=false]; 5877 -> 5878; 1379 -> 1384 [label=true]; 1379 -> 5875 [label=false]; 5876 -> 5877; 1384 -> 1389 [label=true]; 1384 -> 5874 [label=false]; 5875 -> 5876; 1389 -> 1394 [label=true]; 1389 -> 5873 [label=false]; 5874 -> 5875; 1394 -> 1399 [label=true]; 1394 -> 5872 [label=false]; 5873 -> 5874; 1399 -> 1404 [label=true]; 1399 -> 5871 [label=false]; 5872 -> 5873; 1404 -> 1409 [label=true]; 1404 -> 5870 [label=false]; 5871 -> 5872; 1409 -> 1414 [label=true]; 1409 -> 5869 [label=false]; 5870 -> 5871; 1414 -> 1419 [label=true]; 1414 -> 5868 [label=false]; 5869 -> 5870; 1419 -> 1424 [label=true]; 1419 -> 5867 [label=false]; 5868 -> 5869; 1424 -> 1429 [label=true]; 1424 -> 5866 [label=false]; 5867 -> 5868; 1429 -> 1434 [label=true]; 1429 -> 5865 [label=false]; 5866 -> 5867; 1434 -> 1439 [label=true]; 1434 -> 5864 [label=false]; 5865 -> 5866; 1439 -> 1444 [label=true]; 1439 -> 5863 [label=false]; 5864 -> 5865; 1444 -> 1449 [label=true]; 1444 -> 5862 [label=false]; 5863 -> 5864; 1449 -> 1454 [label=true]; 1449 -> 5861 [label=false]; 5862 -> 5863; 1454 -> 1459 [label=true]; 1454 -> 5860 [label=false]; 5861 -> 5862; 1459 -> 1464 [label=true]; 1459 -> 5859 [label=false]; 5860 -> 5861; 1464 -> 1469 [label=true]; 1464 -> 5858 [label=false]; 5859 -> 5860; 1469 -> 1474 [label=true]; 1469 -> 5857 [label=false]; 5858 -> 5859; 1474 -> 1479 [label=true]; 1474 -> 5856 [label=false]; 5857 -> 5858; 1479 -> 1484 [label=true]; 1479 -> 5855 [label=false]; 5856 -> 5857; 1484 -> 1489 [label=true]; 1484 -> 5854 [label=false]; 5855 -> 5856; 1489 -> 1494 [label=true]; 1489 -> 5853 [label=false]; 5854 -> 5855; 1494 -> 1499 [label=true]; 1494 -> 5852 [label=false]; 5853 -> 5854; 1499 -> 1504 [label=true]; 1499 -> 5851 [label=false]; 5852 -> 5853; 1504 -> 1509 [label=true]; 1504 -> 5850 [label=false]; 5851 -> 5852; 1509 -> 1514 [label=true]; 1509 -> 5849 [label=false]; 5850 -> 5851; 1514 -> 1519 [label=true]; 1514 -> 5848 [label=false]; 5849 -> 5850; 1519 -> 1524 [label=true]; 1519 -> 5847 [label=false]; 5848 -> 5849; 1524 -> 1529 [label=true]; 1524 -> 5846 [label=false]; 5847 -> 5848; 1529 -> 1534 [label=true]; 1529 -> 5845 [label=false]; 5846 -> 5847; 1534 -> 1539 [label=true]; 1534 -> 5844 [label=false]; 5845 -> 5846; 1539 -> 1544 [label=true]; 1539 -> 5843 [label=false]; 5844 -> 5845; 1544 -> 1549 [label=true]; 1544 -> 5842 [label=false]; 5843 -> 5844; 1549 -> 1554 [label=true]; 1549 -> 5841 [label=false]; 5842 -> 5843; 1554 -> 1559 [label=true]; 1554 -> 5840 [label=false]; 5841 -> 5842; 1559 -> 1564 [label=true]; 1559 -> 5839 [label=false]; 5840 -> 5841; 1564 -> 1569 [label=true]; 1564 -> 5838 [label=false]; 5839 -> 5840; 1569 -> 1574 [label=true]; 1569 -> 5837 [label=false]; 5838 -> 5839; 1574 -> 1579 [label=true]; 1574 -> 5836 [label=false]; 5837 -> 5838; 1579 -> 1584 [label=true]; 1579 -> 5835 [label=false]; 5836 -> 5837; 1584 -> 1589 [label=true]; 1584 -> 5834 [label=false]; 5835 -> 5836; 1589 -> 1594 [label=true]; 1589 -> 5833 [label=false]; 5834 -> 5835; 1594 -> 1599 [label=true]; 1594 -> 5832 [label=false]; 5833 -> 5834; 1599 -> 1604 [label=true]; 1599 -> 5831 [label=false]; 5832 -> 5833; 1604 -> 1609 [label=true]; 1604 -> 5830 [label=false]; 5831 -> 5832; 1609 -> 1614 [label=true]; 1609 -> 5829 [label=false]; 5830 -> 5831; 1614 -> 1619 [label=true]; 1614 -> 5828 [label=false]; 5829 -> 5830; 1619 -> 1624 [label=true]; 1619 -> 5827 [label=false]; 5828 -> 5829; 1624 -> 1629 [label=true]; 1624 -> 5826 [label=false]; 5827 -> 5828; 1629 -> 1634 [label=true]; 1629 -> 5825 [label=false]; 5826 -> 5827; 1634 -> 1639 [label=true]; 1634 -> 5824 [label=false]; 5825 -> 5826; 1639 -> 1644 [label=true]; 1639 -> 5823 [label=false]; 5824 -> 5825; 1644 -> 1649 [label=true]; 1644 -> 5822 [label=false]; 5823 -> 5824; 1649 -> 1654 [label=true]; 1649 -> 5821 [label=false]; 5822 -> 5823; 1654 -> 1659 [label=true]; 1654 -> 5820 [label=false]; 5821 -> 5822; 1659 -> 1664 [label=true]; 1659 -> 5819 [label=false]; 5820 -> 5821; 1664 -> 1669 [label=true]; 1664 -> 5818 [label=false]; 5819 -> 5820; 1669 -> 1674 [label=true]; 1669 -> 5817 [label=false]; 5818 -> 5819; 1674 -> 1679 [label=true]; 1674 -> 5816 [label=false]; 5817 -> 5818; 1679 -> 1684 [label=true]; 1679 -> 5815 [label=false]; 5816 -> 5817; 1684 -> 1689 [label=true]; 1684 -> 5814 [label=false]; 5815 -> 5816; 1689 -> 1694 [label=true]; 1689 -> 5813 [label=false]; 5814 -> 5815; 1694 -> 1699 [label=true]; 1694 -> 5812 [label=false]; 5813 -> 5814; 1699 -> 1704 [label=true]; 1699 -> 5811 [label=false]; 5812 -> 5813; 1704 -> 1709 [label=true]; 1704 -> 5810 [label=false]; 5811 -> 5812; 1709 -> 1714 [label=true]; 1709 -> 5809 [label=false]; 5810 -> 5811; 1714 -> 1719 [label=true]; 1714 -> 5808 [label=false]; 5809 -> 5810; 1719 -> 1724 [label=true]; 1719 -> 5807 [label=false]; 5808 -> 5809; 1724 -> 1729 [label=true]; 1724 -> 5806 [label=false]; 5807 -> 5808; 1729 -> 1734 [label=true]; 1729 -> 5805 [label=false]; 5806 -> 5807; 1734 -> 1739 [label=true]; 1734 -> 5804 [label=false]; 5805 -> 5806; 1739 -> 1744 [label=true]; 1739 -> 5803 [label=false]; 5804 -> 5805; 1744 -> 1749 [label=true]; 1744 -> 5802 [label=false]; 5803 -> 5804; 1749 -> 1754 [label=true]; 1749 -> 5801 [label=false]; 5802 -> 5803; 1754 -> 1759 [label=true]; 1754 -> 5800 [label=false]; 5801 -> 5802; 1759 -> 1764 [label=true]; 1759 -> 5799 [label=false]; 5800 -> 5801; 1764 -> 1769 [label=true]; 1764 -> 5798 [label=false]; 5799 -> 5800; 1769 -> 1774 [label=true]; 1769 -> 5797 [label=false]; 5798 -> 5799; 1774 -> 1779 [label=true]; 1774 -> 5796 [label=false]; 5797 -> 5798; 1779 -> 1784 [label=true]; 1779 -> 5795 [label=false]; 5796 -> 5797; 1784 -> 1789 [label=true]; 1784 -> 5794 [label=false]; 5795 -> 5796; 1789 -> 1794 [label=true]; 1789 -> 5793 [label=false]; 5794 -> 5795; 1794 -> 1799 [label=true]; 1794 -> 5792 [label=false]; 5793 -> 5794; 1799 -> 1804 [label=true]; 1799 -> 5791 [label=false]; 5792 -> 5793; 1804 -> 1809 [label=true]; 1804 -> 5790 [label=false]; 5791 -> 5792; 1809 -> 1814 [label=true]; 1809 -> 5789 [label=false]; 5790 -> 5791; 1814 -> 1819 [label=true]; 1814 -> 5788 [label=false]; 5789 -> 5790; 1819 -> 1824 [label=true]; 1819 -> 5787 [label=false]; 5788 -> 5789; 1824 -> 1829 [label=true]; 1824 -> 5786 [label=false]; 5787 -> 5788; 1829 -> 1834 [label=true]; 1829 -> 5785 [label=false]; 5786 -> 5787; 1834 -> 1839 [label=true]; 1834 -> 5784 [label=false]; 5785 -> 5786; 1839 -> 1844 [label=true]; 1839 -> 5783 [label=false]; 5784 -> 5785; 1844 -> 1849 [label=true]; 1844 -> 5782 [label=false]; 5783 -> 5784; 1849 -> 1854 [label=true]; 1849 -> 5781 [label=false]; 5782 -> 5783; 1854 -> 1859 [label=true]; 1854 -> 5780 [label=false]; 5781 -> 5782; 1859 -> 1864 [label=true]; 1859 -> 5779 [label=false]; 5780 -> 5781; 1864 -> 1869 [label=true]; 1864 -> 5778 [label=false]; 5779 -> 5780; 1869 -> 1874 [label=true]; 1869 -> 5777 [label=false]; 5778 -> 5779; 1874 -> 1879 [label=true]; 1874 -> 5776 [label=false]; 5777 -> 5778; 1879 -> 1884 [label=true]; 1879 -> 5775 [label=false]; 5776 -> 5777; 1884 -> 1889 [label=true]; 1884 -> 5774 [label=false]; 5775 -> 5776; 1889 -> 1894 [label=true]; 1889 -> 5773 [label=false]; 5774 -> 5775; 1894 -> 1899 [label=true]; 1894 -> 5772 [label=false]; 5773 -> 5774; 1899 -> 1904 [label=true]; 1899 -> 5771 [label=false]; 5772 -> 5773; 1904 -> 1909 [label=true]; 1904 -> 5770 [label=false]; 5771 -> 5772; 1909 -> 1914 [label=true]; 1909 -> 5769 [label=false]; 5770 -> 5771; 1914 -> 1919 [label=true]; 1914 -> 5768 [label=false]; 5769 -> 5770; 1919 -> 1924 [label=true]; 1919 -> 5767 [label=false]; 5768 -> 5769; 1924 -> 1929 [label=true]; 1924 -> 5766 [label=false]; 5767 -> 5768; 1929 -> 1934 [label=true]; 1929 -> 5765 [label=false]; 5766 -> 5767; 1934 -> 1939 [label=true]; 1934 -> 5764 [label=false]; 5765 -> 5766; 1939 -> 1944 [label=true]; 1939 -> 5763 [label=false]; 5764 -> 5765; 1944 -> 1949 [label=true]; 1944 -> 5762 [label=false]; 5763 -> 5764; 1949 -> 1954 [label=true]; 1949 -> 5761 [label=false]; 5762 -> 5763; 1954 -> 1959 [label=true]; 1954 -> 5760 [label=false]; 5761 -> 5762; 1959 -> 1964 [label=true]; 1959 -> 5759 [label=false]; 5760 -> 5761; 1964 -> 1969 [label=true]; 1964 -> 5758 [label=false]; 5759 -> 5760; 1969 -> 1974 [label=true]; 1969 -> 5757 [label=false]; 5758 -> 5759; 1974 -> 1979 [label=true]; 1974 -> 5756 [label=false]; 5757 -> 5758; 1979 -> 1984 [label=true]; 1979 -> 5755 [label=false]; 5756 -> 5757; 1984 -> 1989 [label=true]; 1984 -> 5754 [label=false]; 5755 -> 5756; 1989 -> 1994 [label=true]; 1989 -> 5753 [label=false]; 5754 -> 5755; 1994 -> 1999 [label=true]; 1994 -> 5752 [label=false]; 5753 -> 5754; 1999 -> 2004 [label=true]; 1999 -> 5751 [label=false]; 5752 -> 5753; 2004 -> 2009 [label=true]; 2004 -> 5750 [label=false]; 5751 -> 5752; 2009 -> 2014 [label=true]; 2009 -> 5749 [label=false]; 5750 -> 5751; 2014 -> 2019 [label=true]; 2014 -> 5748 [label=false]; 5749 -> 5750; 2019 -> 2024 [label=true]; 2019 -> 5747 [label=false]; 5748 -> 5749; 2024 -> 2029 [label=true]; 2024 -> 5746 [label=false]; 5747 -> 5748; 2029 -> 2034 [label=true]; 2029 -> 5745 [label=false]; 5746 -> 5747; 2034 -> 2039 [label=true]; 2034 -> 5744 [label=false]; 5745 -> 5746; 2039 -> 2044 [label=true]; 2039 -> 5743 [label=false]; 5744 -> 5745; 2044 -> 2049 [label=true]; 2044 -> 5742 [label=false]; 5743 -> 5744; 2049 -> 2054 [label=true]; 2049 -> 5741 [label=false]; 5742 -> 5743; 2054 -> 2059 [label=true]; 2054 -> 5740 [label=false]; 5741 -> 5742; 2059 -> 2064 [label=true]; 2059 -> 5739 [label=false]; 5740 -> 5741; 2064 -> 2069 [label=true]; 2064 -> 5738 [label=false]; 5739 -> 5740; 2069 -> 2074 [label=true]; 2069 -> 5737 [label=false]; 5738 -> 5739; 2074 -> 2079 [label=true]; 2074 -> 5736 [label=false]; 5737 -> 5738; 2079 -> 2084 [label=true]; 2079 -> 5735 [label=false]; 5736 -> 5737; 2084 -> 2089 [label=true]; 2084 -> 5734 [label=false]; 5735 -> 5736; 2089 -> 2094 [label=true]; 2089 -> 5733 [label=false]; 5734 -> 5735; 2094 -> 2099 [label=true]; 2094 -> 5732 [label=false]; 5733 -> 5734; 2099 -> 2104 [label=true]; 2099 -> 5731 [label=false]; 5732 -> 5733; 2104 -> 2109 [label=true]; 2104 -> 5730 [label=false]; 5731 -> 5732; 2109 -> 2114 [label=true]; 2109 -> 5729 [label=false]; 5730 -> 5731; 2114 -> 2119 [label=true]; 2114 -> 5728 [label=false]; 5729 -> 5730; 2119 -> 2124 [label=true]; 2119 -> 5727 [label=false]; 5728 -> 5729; 2124 -> 2129 [label=true]; 2124 -> 5726 [label=false]; 5727 -> 5728; 2129 -> 2134 [label=true]; 2129 -> 5725 [label=false]; 5726 -> 5727; 2134 -> 2139 [label=true]; 2134 -> 5724 [label=false]; 5725 -> 5726; 2139 -> 2144 [label=true]; 2139 -> 5723 [label=false]; 5724 -> 5725; 2144 -> 2149 [label=true]; 2144 -> 5722 [label=false]; 5723 -> 5724; 2149 -> 2154 [label=true]; 2149 -> 5721 [label=false]; 5722 -> 5723; 2154 -> 2159 [label=true]; 2154 -> 5720 [label=false]; 5721 -> 5722; 2159 -> 2164 [label=true]; 2159 -> 5719 [label=false]; 5720 -> 5721; 2164 -> 2169 [label=true]; 2164 -> 5718 [label=false]; 5719 -> 5720; 2169 -> 2174 [label=true]; 2169 -> 5717 [label=false]; 5718 -> 5719; 2174 -> 2179 [label=true]; 2174 -> 5716 [label=false]; 5717 -> 5718; 2179 -> 2184 [label=true]; 2179 -> 5715 [label=false]; 5716 -> 5717; 2184 -> 2189 [label=true]; 2184 -> 5714 [label=false]; 5715 -> 5716; 2189 -> 2194 [label=true]; 2189 -> 5713 [label=false]; 5714 -> 5715; 2194 -> 2199 [label=true]; 2194 -> 5712 [label=false]; 5713 -> 5714; 2199 -> 2204 [label=true]; 2199 -> 5711 [label=false]; 5712 -> 5713; 2204 -> 2209 [label=true]; 2204 -> 5710 [label=false]; 5711 -> 5712; 2209 -> 2214 [label=true]; 2209 -> 5709 [label=false]; 5710 -> 5711; 2214 -> 2219 [label=true]; 2214 -> 5708 [label=false]; 5709 -> 5710; 2219 -> 2224 [label=true]; 2219 -> 5707 [label=false]; 5708 -> 5709; 2224 -> 2229 [label=true]; 2224 -> 5706 [label=false]; 5707 -> 5708; 2229 -> 2234 [label=true]; 2229 -> 5705 [label=false]; 5706 -> 5707; 2234 -> 2239 [label=true]; 2234 -> 5704 [label=false]; 5705 -> 5706; 2239 -> 2244 [label=true]; 2239 -> 5703 [label=false]; 5704 -> 5705; 2244 -> 2249 [label=true]; 2244 -> 5702 [label=false]; 5703 -> 5704; 2249 -> 2254 [label=true]; 2249 -> 5701 [label=false]; 5702 -> 5703; 2254 -> 2259 [label=true]; 2254 -> 5700 [label=false]; 5701 -> 5702; 2259 -> 2264 [label=true]; 2259 -> 5699 [label=false]; 5700 -> 5701; 2264 -> 2269 [label=true]; 2264 -> 5698 [label=false]; 5699 -> 5700; 2269 -> 2274 [label=true]; 2269 -> 5697 [label=false]; 5698 -> 5699; 2274 -> 2279 [label=true]; 2274 -> 5696 [label=false]; 5697 -> 5698; 2279 -> 2284 [label=true]; 2279 -> 5695 [label=false]; 5696 -> 5697; 2284 -> 2289 [label=true]; 2284 -> 5694 [label=false]; 5695 -> 5696; 2289 -> 2294 [label=true]; 2289 -> 5693 [label=false]; 5694 -> 5695; 2294 -> 2299 [label=true]; 2294 -> 5692 [label=false]; 5693 -> 5694; 2299 -> 2304 [label=true]; 2299 -> 5691 [label=false]; 5692 -> 5693; 2304 -> 2309 [label=true]; 2304 -> 5690 [label=false]; 5691 -> 5692; 2309 -> 2314 [label=true]; 2309 -> 5689 [label=false]; 5690 -> 5691; 2314 -> 2319 [label=true]; 2314 -> 5688 [label=false]; 5689 -> 5690; 2319 -> 2324 [label=true]; 2319 -> 5687 [label=false]; 5688 -> 5689; 2324 -> 2329 [label=true]; 2324 -> 5686 [label=false]; 5687 -> 5688; 2329 -> 2334 [label=true]; 2329 -> 5685 [label=false]; 5686 -> 5687; 2334 -> 2339 [label=true]; 2334 -> 5684 [label=false]; 5685 -> 5686; 2339 -> 2344 [label=true]; 2339 -> 5683 [label=false]; 5684 -> 5685; 2344 -> 2349 [label=true]; 2344 -> 5682 [label=false]; 5683 -> 5684; 2349 -> 2354 [label=true]; 2349 -> 5681 [label=false]; 5682 -> 5683; 2354 -> 2359 [label=true]; 2354 -> 5680 [label=false]; 5681 -> 5682; 2359 -> 2364 [label=true]; 2359 -> 5679 [label=false]; 5680 -> 5681; 2364 -> 2369 [label=true]; 2364 -> 5678 [label=false]; 5679 -> 5680; 2369 -> 2374 [label=true]; 2369 -> 5677 [label=false]; 5678 -> 5679; 2374 -> 2379 [label=true]; 2374 -> 5676 [label=false]; 5677 -> 5678; 2379 -> 2384 [label=true]; 2379 -> 5675 [label=false]; 5676 -> 5677; 2384 -> 2389 [label=true]; 2384 -> 5674 [label=false]; 5675 -> 5676; 2389 -> 2394 [label=true]; 2389 -> 5673 [label=false]; 5674 -> 5675; 2394 -> 2399 [label=true]; 2394 -> 5672 [label=false]; 5673 -> 5674; 2399 -> 2404 [label=true]; 2399 -> 5671 [label=false]; 5672 -> 5673; 2404 -> 2409 [label=true]; 2404 -> 5670 [label=false]; 5671 -> 5672; 2409 -> 2414 [label=true]; 2409 -> 5669 [label=false]; 5670 -> 5671; 2414 -> 2419 [label=true]; 2414 -> 5668 [label=false]; 5669 -> 5670; 2419 -> 2424 [label=true]; 2419 -> 5667 [label=false]; 5668 -> 5669; 2424 -> 2429 [label=true]; 2424 -> 5666 [label=false]; 5667 -> 5668; 2429 -> 2434 [label=true]; 2429 -> 5665 [label=false]; 5666 -> 5667; 2434 -> 2439 [label=true]; 2434 -> 5664 [label=false]; 5665 -> 5666; 2439 -> 2444 [label=true]; 2439 -> 5663 [label=false]; 5664 -> 5665; 2444 -> 2449 [label=true]; 2444 -> 5662 [label=false]; 5663 -> 5664; 2449 -> 2454 [label=true]; 2449 -> 5661 [label=false]; 5662 -> 5663; 2454 -> 2459 [label=true]; 2454 -> 5660 [label=false]; 5661 -> 5662; 2459 -> 2464 [label=true]; 2459 -> 5659 [label=false]; 5660 -> 5661; 2464 -> 2469 [label=true]; 2464 -> 5658 [label=false]; 5659 -> 5660; 2469 -> 2474 [label=true]; 2469 -> 5657 [label=false]; 5658 -> 5659; 2474 -> 2479 [label=true]; 2474 -> 5656 [label=false]; 5657 -> 5658; 2479 -> 2484 [label=true]; 2479 -> 5655 [label=false]; 5656 -> 5657; 2484 -> 2489 [label=true]; 2484 -> 5654 [label=false]; 5655 -> 5656; 2489 -> 2494 [label=true]; 2489 -> 5653 [label=false]; 5654 -> 5655; 2494 -> 2499 [label=true]; 2494 -> 5652 [label=false]; 5653 -> 5654; 2499 -> 2504 [label=true]; 2499 -> 5651 [label=false]; 5652 -> 5653; 2504 -> 2509 [label=true]; 2504 -> 5650 [label=false]; 5651 -> 5652; 2509 -> 2514 [label=true]; 2509 -> 5649 [label=false]; 5650 -> 5651; 2514 -> 2519 [label=true]; 2514 -> 5648 [label=false]; 5649 -> 5650; 2519 -> 2524 [label=true]; 2519 -> 5647 [label=false]; 5648 -> 5649; 2524 -> 2529 [label=true]; 2524 -> 5646 [label=false]; 5647 -> 5648; 2529 -> 2534 [label=true]; 2529 -> 5645 [label=false]; 5646 -> 5647; 2534 -> 2539 [label=true]; 2534 -> 5644 [label=false]; 5645 -> 5646; 2539 -> 2544 [label=true]; 2539 -> 5643 [label=false]; 5644 -> 5645; 2544 -> 2549 [label=true]; 2544 -> 5642 [label=false]; 5643 -> 5644; 2549 -> 2554 [label=true]; 2549 -> 5641 [label=false]; 5642 -> 5643; 2554 -> 2559 [label=true]; 2554 -> 5640 [label=false]; 5641 -> 5642; 2559 -> 2564 [label=true]; 2559 -> 5639 [label=false]; 5640 -> 5641; 2564 -> 2569 [label=true]; 2564 -> 5638 [label=false]; 5639 -> 5640; 2569 -> 2574 [label=true]; 2569 -> 5637 [label=false]; 5638 -> 5639; 2574 -> 2579 [label=true]; 2574 -> 5636 [label=false]; 5637 -> 5638; 2579 -> 2584 [label=true]; 2579 -> 5635 [label=false]; 5636 -> 5637; 2584 -> 2589 [label=true]; 2584 -> 5634 [label=false]; 5635 -> 5636; 2589 -> 2594 [label=true]; 2589 -> 5633 [label=false]; 5634 -> 5635; 2594 -> 2599 [label=true]; 2594 -> 5632 [label=false]; 5633 -> 5634; 2599 -> 2604 [label=true]; 2599 -> 5631 [label=false]; 5632 -> 5633; 2604 -> 2609 [label=true]; 2604 -> 5630 [label=false]; 5631 -> 5632; 2609 -> 2614 [label=true]; 2609 -> 5629 [label=false]; 5630 -> 5631; 2614 -> 2619 [label=true]; 2614 -> 5628 [label=false]; 5629 -> 5630; 2619 -> 2624 [label=true]; 2619 -> 5627 [label=false]; 5628 -> 5629; 2624 -> 2629 [label=true]; 2624 -> 5626 [label=false]; 5627 -> 5628; 2629 -> 2634 [label=true]; 2629 -> 5625 [label=false]; 5626 -> 5627; 2634 -> 2639 [label=true]; 2634 -> 5624 [label=false]; 5625 -> 5626; 2639 -> 2644 [label=true]; 2639 -> 5623 [label=false]; 5624 -> 5625; 2644 -> 2649 [label=true]; 2644 -> 5622 [label=false]; 5623 -> 5624; 2649 -> 2654 [label=true]; 2649 -> 5621 [label=false]; 5622 -> 5623; 2654 -> 2659 [label=true]; 2654 -> 5620 [label=false]; 5621 -> 5622; 2659 -> 2664 [label=true]; 2659 -> 5619 [label=false]; 5620 -> 5621; 2664 -> 2669 [label=true]; 2664 -> 5618 [label=false]; 5619 -> 5620; 2669 -> 2674 [label=true]; 2669 -> 5617 [label=false]; 5618 -> 5619; 2674 -> 2679 [label=true]; 2674 -> 5616 [label=false]; 5617 -> 5618; 2679 -> 2684 [label=true]; 2679 -> 5615 [label=false]; 5616 -> 5617; 2684 -> 2689 [label=true]; 2684 -> 5614 [label=false]; 5615 -> 5616; 2689 -> 2694 [label=true]; 2689 -> 5613 [label=false]; 5614 -> 5615; 2694 -> 2699 [label=true]; 2694 -> 5612 [label=false]; 5613 -> 5614; 2699 -> 2704 [label=true]; 2699 -> 5611 [label=false]; 5612 -> 5613; 2704 -> 2709 [label=true]; 2704 -> 5610 [label=false]; 5611 -> 5612; 2709 -> 2714 [label=true]; 2709 -> 5609 [label=false]; 5610 -> 5611; 2714 -> 2719 [label=true]; 2714 -> 5608 [label=false]; 5609 -> 5610; 2719 -> 2724 [label=true]; 2719 -> 5607 [label=false]; 5608 -> 5609; 2724 -> 2729 [label=true]; 2724 -> 5606 [label=false]; 5607 -> 5608; 2729 -> 2734 [label=true]; 2729 -> 5605 [label=false]; 5606 -> 5607; 2734 -> 2739 [label=true]; 2734 -> 5604 [label=false]; 5605 -> 5606; 2739 -> 2744 [label=true]; 2739 -> 5603 [label=false]; 5604 -> 5605; 2744 -> 2749 [label=true]; 2744 -> 5602 [label=false]; 5603 -> 5604; 2749 -> 2754 [label=true]; 2749 -> 5601 [label=false]; 5602 -> 5603; 2754 -> 2759 [label=true]; 2754 -> 5600 [label=false]; 5601 -> 5602; 2759 -> 2764 [label=true]; 2759 -> 5599 [label=false]; 5600 -> 5601; 2764 -> 2769 [label=true]; 2764 -> 5598 [label=false]; 5599 -> 5600; 2769 -> 2774 [label=true]; 2769 -> 5597 [label=false]; 5598 -> 5599; 2774 -> 2779 [label=true]; 2774 -> 5596 [label=false]; 5597 -> 5598; 2779 -> 2784 [label=true]; 2779 -> 5595 [label=false]; 5596 -> 5597; 2784 -> 2789 [label=true]; 2784 -> 5594 [label=false]; 5595 -> 5596; 2789 -> 2794 [label=true]; 2789 -> 5593 [label=false]; 5594 -> 5595; 2794 -> 2799 [label=true]; 2794 -> 5592 [label=false]; 5593 -> 5594; 2799 -> 2804 [label=true]; 2799 -> 5591 [label=false]; 5592 -> 5593; 2804 -> 2809 [label=true]; 2804 -> 5590 [label=false]; 5591 -> 5592; 2809 -> 2814 [label=true]; 2809 -> 5589 [label=false]; 5590 -> 5591; 2814 -> 2819 [label=true]; 2814 -> 5588 [label=false]; 5589 -> 5590; 2819 -> 2824 [label=true]; 2819 -> 5587 [label=false]; 5588 -> 5589; 2824 -> 2829 [label=true]; 2824 -> 5586 [label=false]; 5587 -> 5588; 2829 -> 2834 [label=true]; 2829 -> 5585 [label=false]; 5586 -> 5587; 2834 -> 2839 [label=true]; 2834 -> 5584 [label=false]; 5585 -> 5586; 2839 -> 2844 [label=true]; 2839 -> 5583 [label=false]; 5584 -> 5585; 2844 -> 2849 [label=true]; 2844 -> 5582 [label=false]; 5583 -> 5584; 2849 -> 2854 [label=true]; 2849 -> 5581 [label=false]; 5582 -> 5583; 2854 -> 2859 [label=true]; 2854 -> 5580 [label=false]; 5581 -> 5582; 2859 -> 2864 [label=true]; 2859 -> 5579 [label=false]; 5580 -> 5581; 2864 -> 2869 [label=true]; 2864 -> 5578 [label=false]; 5579 -> 5580; 2869 -> 2874 [label=true]; 2869 -> 5577 [label=false]; 5578 -> 5579; 2874 -> 2879 [label=true]; 2874 -> 5576 [label=false]; 5577 -> 5578; 2879 -> 2884 [label=true]; 2879 -> 5575 [label=false]; 5576 -> 5577; 2884 -> 2889 [label=true]; 2884 -> 5574 [label=false]; 5575 -> 5576; 2889 -> 2894 [label=true]; 2889 -> 5573 [label=false]; 5574 -> 5575; 2894 -> 2899 [label=true]; 2894 -> 5572 [label=false]; 5573 -> 5574; 2899 -> 2904 [label=true]; 2899 -> 5571 [label=false]; 5572 -> 5573; 2904 -> 2909 [label=true]; 2904 -> 5570 [label=false]; 5571 -> 5572; 2909 -> 2914 [label=true]; 2909 -> 5569 [label=false]; 5570 -> 5571; 2914 -> 2919 [label=true]; 2914 -> 5568 [label=false]; 5569 -> 5570; 2919 -> 2924 [label=true]; 2919 -> 5567 [label=false]; 5568 -> 5569; 2924 -> 2929 [label=true]; 2924 -> 5566 [label=false]; 5567 -> 5568; 2929 -> 2934 [label=true]; 2929 -> 5565 [label=false]; 5566 -> 5567; 2934 -> 2939 [label=true]; 2934 -> 5564 [label=false]; 5565 -> 5566; 2939 -> 2944 [label=true]; 2939 -> 5563 [label=false]; 5564 -> 5565; 2944 -> 2949 [label=true]; 2944 -> 5562 [label=false]; 5563 -> 5564; 2949 -> 2954 [label=true]; 2949 -> 5561 [label=false]; 5562 -> 5563; 2954 -> 2959 [label=true]; 2954 -> 5560 [label=false]; 5561 -> 5562; 2959 -> 2964 [label=true]; 2959 -> 5559 [label=false]; 5560 -> 5561; 2964 -> 2969 [label=true]; 2964 -> 5558 [label=false]; 5559 -> 5560; 2969 -> 2974 [label=true]; 2969 -> 5557 [label=false]; 5558 -> 5559; 2974 -> 2979 [label=true]; 2974 -> 5556 [label=false]; 5557 -> 5558; 2979 -> 2984 [label=true]; 2979 -> 5555 [label=false]; 5556 -> 5557; 2984 -> 2989 [label=true]; 2984 -> 5554 [label=false]; 5555 -> 5556; 2989 -> 2994 [label=true]; 2989 -> 5553 [label=false]; 5554 -> 5555; 2994 -> 2999 [label=true]; 2994 -> 5552 [label=false]; 5553 -> 5554; 2999 -> 3004 [label=true]; 2999 -> 5551 [label=false]; 5552 -> 5553; 3004 -> 3009 [label=true]; 3004 -> 5550 [label=false]; 5551 -> 5552; 3009 -> 3014 [label=true]; 3009 -> 5549 [label=false]; 5550 -> 5551; 3014 -> 3019 [label=true]; 3014 -> 5548 [label=false]; 5549 -> 5550; 3019 -> 3024 [label=true]; 3019 -> 5547 [label=false]; 5548 -> 5549; 3024 -> 3029 [label=true]; 3024 -> 5546 [label=false]; 5547 -> 5548; 3029 -> 3034 [label=true]; 3029 -> 5545 [label=false]; 5546 -> 5547; 3034 -> 3039 [label=true]; 3034 -> 5544 [label=false]; 5545 -> 5546; 3039 -> 3044 [label=true]; 3039 -> 5543 [label=false]; 5544 -> 5545; 3044 -> 3049 [label=true]; 3044 -> 5542 [label=false]; 5543 -> 5544; 3049 -> 3054 [label=true]; 3049 -> 5541 [label=false]; 5542 -> 5543; 3054 -> 3059 [label=true]; 3054 -> 5540 [label=false]; 5541 -> 5542; 3059 -> 3064 [label=true]; 3059 -> 5539 [label=false]; 5540 -> 5541; 3064 -> 3069 [label=true]; 3064 -> 5538 [label=false]; 5539 -> 5540; 3069 -> 3074 [label=true]; 3069 -> 5537 [label=false]; 5538 -> 5539; 3074 -> 3079 [label=true]; 3074 -> 5536 [label=false]; 5537 -> 5538; 3079 -> 3084 [label=true]; 3079 -> 5535 [label=false]; 5536 -> 5537; 3084 -> 3089 [label=true]; 3084 -> 5534 [label=false]; 5535 -> 5536; 3089 -> 3094 [label=true]; 3089 -> 5533 [label=false]; 5534 -> 5535; 3094 -> 3099 [label=true]; 3094 -> 5532 [label=false]; 5533 -> 5534; 3099 -> 3104 [label=true]; 3099 -> 5531 [label=false]; 5532 -> 5533; 3104 -> 3109 [label=true]; 3104 -> 5530 [label=false]; 5531 -> 5532; 3109 -> 3114 [label=true]; 3109 -> 5529 [label=false]; 5530 -> 5531; 3114 -> 3119 [label=true]; 3114 -> 5528 [label=false]; 5529 -> 5530; 3119 -> 3124 [label=true]; 3119 -> 5527 [label=false]; 5528 -> 5529; 3124 -> 3129 [label=true]; 3124 -> 5526 [label=false]; 5527 -> 5528; 3129 -> 3134 [label=true]; 3129 -> 5525 [label=false]; 5526 -> 5527; 3134 -> 3139 [label=true]; 3134 -> 5524 [label=false]; 5525 -> 5526; 3139 -> 3144 [label=true]; 3139 -> 5523 [label=false]; 5524 -> 5525; 3144 -> 3149 [label=true]; 3144 -> 5522 [label=false]; 5523 -> 5524; 3149 -> 3154 [label=true]; 3149 -> 5521 [label=false]; 5522 -> 5523; 3154 -> 3159 [label=true]; 3154 -> 5520 [label=false]; 5521 -> 5522; 3159 -> 3164 [label=true]; 3159 -> 5519 [label=false]; 5520 -> 5521; 3164 -> 3169 [label=true]; 3164 -> 5518 [label=false]; 5519 -> 5520; 3169 -> 3174 [label=true]; 3169 -> 5517 [label=false]; 5518 -> 5519; 3174 -> 3179 [label=true]; 3174 -> 5516 [label=false]; 5517 -> 5518; 3179 -> 3184 [label=true]; 3179 -> 5515 [label=false]; 5516 -> 5517; 3184 -> 3189 [label=true]; 3184 -> 5514 [label=false]; 5515 -> 5516; 3189 -> 3194 [label=true]; 3189 -> 5513 [label=false]; 5514 -> 5515; 3194 -> 3199 [label=true]; 3194 -> 5512 [label=false]; 5513 -> 5514; 3199 -> 3204 [label=true]; 3199 -> 5511 [label=false]; 5512 -> 5513; 3204 -> 3209 [label=true]; 3204 -> 5510 [label=false]; 5511 -> 5512; 3209 -> 3214 [label=true]; 3209 -> 5509 [label=false]; 5510 -> 5511; 3214 -> 3219 [label=true]; 3214 -> 5508 [label=false]; 5509 -> 5510; 3219 -> 3224 [label=true]; 3219 -> 5507 [label=false]; 5508 -> 5509; 3224 -> 3229 [label=true]; 3224 -> 5506 [label=false]; 5507 -> 5508; 3229 -> 3234 [label=true]; 3229 -> 5505 [label=false]; 5506 -> 5507; 3234 -> 3239 [label=true]; 3234 -> 5504 [label=false]; 5505 -> 5506; 3239 -> 3244 [label=true]; 3239 -> 5503 [label=false]; 5504 -> 5505; 3244 -> 3249 [label=true]; 3244 -> 5502 [label=false]; 5503 -> 5504; 3249 -> 3254 [label=true]; 3249 -> 5501 [label=false]; 5502 -> 5503; 3254 -> 3259 [label=true]; 3254 -> 5500 [label=false]; 5501 -> 5502; 3259 -> 3264 [label=true]; 3259 -> 5499 [label=false]; 5500 -> 5501; 3264 -> 3269 [label=true]; 3264 -> 5498 [label=false]; 5499 -> 5500; 3269 -> 3274 [label=true]; 3269 -> 5497 [label=false]; 5498 -> 5499; 3274 -> 3279 [label=true]; 3274 -> 5496 [label=false]; 5497 -> 5498; 3279 -> 3284 [label=true]; 3279 -> 5495 [label=false]; 5496 -> 5497; 3284 -> 3289 [label=true]; 3284 -> 5494 [label=false]; 5495 -> 5496; 3289 -> 3294 [label=true]; 3289 -> 5493 [label=false]; 5494 -> 5495; 3294 -> 3299 [label=true]; 3294 -> 5492 [label=false]; 5493 -> 5494; 3299 -> 3304 [label=true]; 3299 -> 5491 [label=false]; 5492 -> 5493; 3304 -> 3309 [label=true]; 3304 -> 5490 [label=false]; 5491 -> 5492; 3309 -> 3314 [label=true]; 3309 -> 5489 [label=false]; 5490 -> 5491; 3314 -> 3319 [label=true]; 3314 -> 5488 [label=false]; 5489 -> 5490; 3319 -> 3324 [label=true]; 3319 -> 5487 [label=false]; 5488 -> 5489; 3324 -> 3329 [label=true]; 3324 -> 5486 [label=false]; 5487 -> 5488; 3329 -> 3334 [label=true]; 3329 -> 5485 [label=false]; 5486 -> 5487; 3334 -> 3339 [label=true]; 3334 -> 5484 [label=false]; 5485 -> 5486; 3339 -> 3344 [label=true]; 3339 -> 5483 [label=false]; 5484 -> 5485; 3344 -> 3349 [label=true]; 3344 -> 5482 [label=false]; 5483 -> 5484; 3349 -> 3354 [label=true]; 3349 -> 5481 [label=false]; 5482 -> 5483; 3354 -> 3359 [label=true]; 3354 -> 5480 [label=false]; 5481 -> 5482; 3359 -> 3364 [label=true]; 3359 -> 5479 [label=false]; 5480 -> 5481; 3364 -> 3369 [label=true]; 3364 -> 5478 [label=false]; 5479 -> 5480; 3369 -> 3374 [label=true]; 3369 -> 5477 [label=false]; 5478 -> 5479; 3374 -> 3379 [label=true]; 3374 -> 5476 [label=false]; 5477 -> 5478; 3379 -> 3384 [label=true]; 3379 -> 5475 [label=false]; 5476 -> 5477; 3384 -> 3389 [label=true]; 3384 -> 5474 [label=false]; 5475 -> 5476; 3389 -> 3394 [label=true]; 3389 -> 5473 [label=false]; 5474 -> 5475; 3394 -> 3399 [label=true]; 3394 -> 5472 [label=false]; 5473 -> 5474; 3399 -> 3404 [label=true]; 3399 -> 5471 [label=false]; 5472 -> 5473; 3404 -> 3409 [label=true]; 3404 -> 5470 [label=false]; 5471 -> 5472; 3409 -> 3414 [label=true]; 3409 -> 5469 [label=false]; 5470 -> 5471; 3414 -> 3419 [label=true]; 3414 -> 5468 [label=false]; 5469 -> 5470; 3419 -> 3424 [label=true]; 3419 -> 5467 [label=false]; 5468 -> 5469; 3424 -> 3429 [label=true]; 3424 -> 5466 [label=false]; 5467 -> 5468; 3429 -> 3434 [label=true]; 3429 -> 5465 [label=false]; 5466 -> 5467; 3434 -> 3439 [label=true]; 3434 -> 5464 [label=false]; 5465 -> 5466; 3439 -> 3444 [label=true]; 3439 -> 5463 [label=false]; 5464 -> 5465; 3444 -> 3449 [label=true]; 3444 -> 5462 [label=false]; 5463 -> 5464; 3449 -> 3454 [label=true]; 3449 -> 5461 [label=false]; 5462 -> 5463; 3454 -> 3459 [label=true]; 3454 -> 5460 [label=false]; 5461 -> 5462; 3459 -> 3464 [label=true]; 3459 -> 5459 [label=false]; 5460 -> 5461; 3464 -> 3469 [label=true]; 3464 -> 5458 [label=false]; 5459 -> 5460; 3469 -> 3474 [label=true]; 3469 -> 5457 [label=false]; 5458 -> 5459; 3474 -> 3479 [label=true]; 3474 -> 5456 [label=false]; 5457 -> 5458; 3479 -> 3484 [label=true]; 3479 -> 5455 [label=false]; 5456 -> 5457; 3484 -> 3489 [label=true]; 3484 -> 5454 [label=false]; 5455 -> 5456; 3489 -> 3494 [label=true]; 3489 -> 5453 [label=false]; 5454 -> 5455; 3494 -> 3499 [label=true]; 3494 -> 5452 [label=false]; 5453 -> 5454; 3499 -> 3504 [label=true]; 3499 -> 5451 [label=false]; 5452 -> 5453; 3504 -> 3509 [label=true]; 3504 -> 5450 [label=false]; 5451 -> 5452; 3509 -> 3514 [label=true]; 3509 -> 5449 [label=false]; 5450 -> 5451; 3514 -> 3519 [label=true]; 3514 -> 5448 [label=false]; 5449 -> 5450; 3519 -> 3524 [label=true]; 3519 -> 5447 [label=false]; 5448 -> 5449; 3524 -> 3529 [label=true]; 3524 -> 5446 [label=false]; 5447 -> 5448; 3529 -> 3534 [label=true]; 3529 -> 5445 [label=false]; 5446 -> 5447; 3534 -> 3539 [label=true]; 3534 -> 5444 [label=false]; 5445 -> 5446; 3539 -> 3544 [label=true]; 3539 -> 5443 [label=false]; 5444 -> 5445; 3544 -> 3549 [label=true]; 3544 -> 5442 [label=false]; 5443 -> 5444; 3549 -> 3554 [label=true]; 3549 -> 5441 [label=false]; 5442 -> 5443; 3554 -> 3559 [label=true]; 3554 -> 5440 [label=false]; 5441 -> 5442; 3559 -> 3564 [label=true]; 3559 -> 5439 [label=false]; 5440 -> 5441; 3564 -> 3569 [label=true]; 3564 -> 5438 [label=false]; 5439 -> 5440; 3569 -> 3574 [label=true]; 3569 -> 5437 [label=false]; 5438 -> 5439; 3574 -> 3579 [label=true]; 3574 -> 5436 [label=false]; 5437 -> 5438; 3579 -> 3584 [label=true]; 3579 -> 5435 [label=false]; 5436 -> 5437; 3584 -> 3589 [label=true]; 3584 -> 5434 [label=false]; 5435 -> 5436; 3589 -> 3594 [label=true]; 3589 -> 5433 [label=false]; 5434 -> 5435; 3594 -> 3599 [label=true]; 3594 -> 5432 [label=false]; 5433 -> 5434; 3599 -> 3604 [label=true]; 3599 -> 5431 [label=false]; 5432 -> 5433; 3604 -> 3609 [label=true]; 3604 -> 5430 [label=false]; 5431 -> 5432; 3609 -> 3614 [label=true]; 3609 -> 5429 [label=false]; 5430 -> 5431; 3614 -> 3619 [label=true]; 3614 -> 5428 [label=false]; 5429 -> 5430; 3619 -> 3624 [label=true]; 3619 -> 5427 [label=false]; 5428 -> 5429; 3624 -> 3629 [label=true]; 3624 -> 5426 [label=false]; 5427 -> 5428; 3629 -> 3634 [label=true]; 3629 -> 5425 [label=false]; 5426 -> 5427; 3634 -> 3639 [label=true]; 3634 -> 5424 [label=false]; 5425 -> 5426; 3639 -> 3644 [label=true]; 3639 -> 5423 [label=false]; 5424 -> 5425; 3644 -> 3649 [label=true]; 3644 -> 5422 [label=false]; 5423 -> 5424; 3649 -> 3654 [label=true]; 3649 -> 5421 [label=false]; 5422 -> 5423; 3654 -> 3659 [label=true]; 3654 -> 5420 [label=false]; 5421 -> 5422; 3659 -> 3664 [label=true]; 3659 -> 5419 [label=false]; 5420 -> 5421; 3664 -> 3669 [label=true]; 3664 -> 5418 [label=false]; 5419 -> 5420; 3669 -> 3674 [label=true]; 3669 -> 5417 [label=false]; 5418 -> 5419; 3674 -> 3679 [label=true]; 3674 -> 5416 [label=false]; 5417 -> 5418; 3679 -> 3684 [label=true]; 3679 -> 5415 [label=false]; 5416 -> 5417; 3684 -> 3689 [label=true]; 3684 -> 5414 [label=false]; 5415 -> 5416; 3689 -> 3694 [label=true]; 3689 -> 5413 [label=false]; 5414 -> 5415; 3694 -> 3699 [label=true]; 3694 -> 5412 [label=false]; 5413 -> 5414; 3699 -> 3704 [label=true]; 3699 -> 5411 [label=false]; 5412 -> 5413; 3704 -> 3709 [label=true]; 3704 -> 5410 [label=false]; 5411 -> 5412; 3709 -> 3714 [label=true]; 3709 -> 5409 [label=false]; 5410 -> 5411; 3714 -> 3719 [label=true]; 3714 -> 5408 [label=false]; 5409 -> 5410; 3719 -> 3724 [label=true]; 3719 -> 5407 [label=false]; 5408 -> 5409; 3724 -> 3729 [label=true]; 3724 -> 5406 [label=false]; 5407 -> 5408; 3729 -> 3734 [label=true]; 3729 -> 5405 [label=false]; 5406 -> 5407; 3734 -> 3739 [label=true]; 3734 -> 5404 [label=false]; 5405 -> 5406; 3739 -> 3744 [label=true]; 3739 -> 5403 [label=false]; 5404 -> 5405; 3744 -> 3749 [label=true]; 3744 -> 5402 [label=false]; 5403 -> 5404; 3749 -> 3754 [label=true]; 3749 -> 5401 [label=false]; 5402 -> 5403; 3754 -> 3759 [label=true]; 3754 -> 5400 [label=false]; 5401 -> 5402; 3759 -> 3764 [label=true]; 3759 -> 5399 [label=false]; 5400 -> 5401; 3764 -> 3769 [label=true]; 3764 -> 5398 [label=false]; 5399 -> 5400; 3769 -> 3774 [label=true]; 3769 -> 5397 [label=false]; 5398 -> 5399; 3774 -> 3779 [label=true]; 3774 -> 5396 [label=false]; 5397 -> 5398; 3779 -> 3784 [label=true]; 3779 -> 5395 [label=false]; 5396 -> 5397; 3784 -> 3789 [label=true]; 3784 -> 5394 [label=false]; 5395 -> 5396; 3789 -> 3794 [label=true]; 3789 -> 5393 [label=false]; 5394 -> 5395; 3794 -> 3799 [label=true]; 3794 -> 5392 [label=false]; 5393 -> 5394; 3799 -> 3804 [label=true]; 3799 -> 5391 [label=false]; 5392 -> 5393; 3804 -> 3809 [label=true]; 3804 -> 5390 [label=false]; 5391 -> 5392; 3809 -> 3814 [label=true]; 3809 -> 5389 [label=false]; 5390 -> 5391; 3814 -> 3819 [label=true]; 3814 -> 5388 [label=false]; 5389 -> 5390; 3819 -> 3824 [label=true]; 3819 -> 5387 [label=false]; 5388 -> 5389; 3824 -> 3829 [label=true]; 3824 -> 5386 [label=false]; 5387 -> 5388; 3829 -> 3834 [label=true]; 3829 -> 5385 [label=false]; 5386 -> 5387; 3834 -> 3839 [label=true]; 3834 -> 5384 [label=false]; 5385 -> 5386; 3839 -> 3844 [label=true]; 3839 -> 5383 [label=false]; 5384 -> 5385; 3844 -> 3849 [label=true]; 3844 -> 5382 [label=false]; 5383 -> 5384; 3849 -> 3854 [label=true]; 3849 -> 5381 [label=false]; 5382 -> 5383; 3854 -> 3859 [label=true]; 3854 -> 5380 [label=false]; 5381 -> 5382; 3859 -> 3864 [label=true]; 3859 -> 5379 [label=false]; 5380 -> 5381; 3864 -> 3869 [label=true]; 3864 -> 5378 [label=false]; 5379 -> 5380; 3869 -> 3874 [label=true]; 3869 -> 5377 [label=false]; 5378 -> 5379; 3874 -> 3879 [label=true]; 3874 -> 5376 [label=false]; 5377 -> 5378; 3879 -> 3884 [label=true]; 3879 -> 5375 [label=false]; 5376 -> 5377; 3884 -> 3889 [label=true]; 3884 -> 5374 [label=false]; 5375 -> 5376; 3889 -> 3894 [label=true]; 3889 -> 5373 [label=false]; 5374 -> 5375; 3894 -> 3899 [label=true]; 3894 -> 5372 [label=false]; 5373 -> 5374; 3899 -> 3904 [label=true]; 3899 -> 5371 [label=false]; 5372 -> 5373; 3904 -> 3909 [label=true]; 3904 -> 5370 [label=false]; 5371 -> 5372; 3909 -> 3914 [label=true]; 3909 -> 5369 [label=false]; 5370 -> 5371; 3914 -> 3919 [label=true]; 3914 -> 5368 [label=false]; 5369 -> 5370; 3919 -> 3924 [label=true]; 3919 -> 5367 [label=false]; 5368 -> 5369; 3924 -> 3929 [label=true]; 3924 -> 5366 [label=false]; 5367 -> 5368; 3929 -> 3934 [label=true]; 3929 -> 5365 [label=false]; 5366 -> 5367; 3934 -> 3939 [label=true]; 3934 -> 5364 [label=false]; 5365 -> 5366; 3939 -> 3944 [label=true]; 3939 -> 5363 [label=false]; 5364 -> 5365; 3944 -> 3949 [label=true]; 3944 -> 5362 [label=false]; 5363 -> 5364; 3949 -> 3954 [label=true]; 3949 -> 5361 [label=false]; 5362 -> 5363; 3954 -> 3959 [label=true]; 3954 -> 5360 [label=false]; 5361 -> 5362; 3959 -> 3964 [label=true]; 3959 -> 5359 [label=false]; 5360 -> 5361; 3964 -> 3969 [label=true]; 3964 -> 5358 [label=false]; 5359 -> 5360; 3969 -> 3974 [label=true]; 3969 -> 5357 [label=false]; 5358 -> 5359; 3974 -> 3979 [label=true]; 3974 -> 5356 [label=false]; 5357 -> 5358; 3979 -> 3984 [label=true]; 3979 -> 5355 [label=false]; 5356 -> 5357; 3984 -> 3989 [label=true]; 3984 -> 5354 [label=false]; 5355 -> 5356; 3989 -> 3994 [label=true]; 3989 -> 5353 [label=false]; 5354 -> 5355; 3994 -> 3999 [label=true]; 3994 -> 5352 [label=false]; 5353 -> 5354; 3999 -> 4004 [label=true]; 3999 -> 5351 [label=false]; 5352 -> 5353; 4004 -> 4009 [label=true]; 4004 -> 5350 [label=false]; 5351 -> 5352; 4009 -> 4014 [label=true]; 4009 -> 5349 [label=false]; 5350 -> 5351; 4014 -> 4019 [label=true]; 4014 -> 5348 [label=false]; 5349 -> 5350; 4019 -> 4024 [label=true]; 4019 -> 5347 [label=false]; 5348 -> 5349; 4024 -> 4029 [label=true]; 4024 -> 5346 [label=false]; 5347 -> 5348; 4029 -> 4034 [label=true]; 4029 -> 5345 [label=false]; 5346 -> 5347; 4034 -> 4039 [label=true]; 4034 -> 5344 [label=false]; 5345 -> 5346; 4039 -> 4044 [label=true]; 4039 -> 5343 [label=false]; 5344 -> 5345; 4044 -> 4049 [label=true]; 4044 -> 5342 [label=false]; 5343 -> 5344; 4049 -> 4054 [label=true]; 4049 -> 5341 [label=false]; 5342 -> 5343; 4054 -> 4059 [label=true]; 4054 -> 5340 [label=false]; 5341 -> 5342; 4059 -> 4064 [label=true]; 4059 -> 5339 [label=false]; 5340 -> 5341; 4064 -> 4069 [label=true]; 4064 -> 5338 [label=false]; 5339 -> 5340; 4069 -> 4074 [label=true]; 4069 -> 5337 [label=false]; 5338 -> 5339; 4074 -> 4079 [label=true]; 4074 -> 5336 [label=false]; 5337 -> 5338; 4079 -> 4084 [label=true]; 4079 -> 5335 [label=false]; 5336 -> 5337; 4084 -> 4089 [label=true]; 4084 -> 5334 [label=false]; 5335 -> 5336; 4089 -> 4094 [label=true]; 4089 -> 5333 [label=false]; 5334 -> 5335; 4094 -> 4099 [label=true]; 4094 -> 5332 [label=false]; 5333 -> 5334; 4099 -> 4104 [label=true]; 4099 -> 5331 [label=false]; 5332 -> 5333; 4104 -> 4109 [label=true]; 4104 -> 5330 [label=false]; 5331 -> 5332; 4109 -> 4114 [label=true]; 4109 -> 5329 [label=false]; 5330 -> 5331; 4114 -> 4119 [label=true]; 4114 -> 5328 [label=false]; 5329 -> 5330; 4119 -> 4124 [label=true]; 4119 -> 5327 [label=false]; 5328 -> 5329; 4124 -> 4129 [label=true]; 4124 -> 5326 [label=false]; 5327 -> 5328; 4129 -> 4134 [label=true]; 4129 -> 5325 [label=false]; 5326 -> 5327; 4134 -> 4139 [label=true]; 4134 -> 5324 [label=false]; 5325 -> 5326; 4139 -> 4144 [label=true]; 4139 -> 5323 [label=false]; 5324 -> 5325; 4144 -> 4149 [label=true]; 4144 -> 5322 [label=false]; 5323 -> 5324; 4149 -> 4154 [label=true]; 4149 -> 5321 [label=false]; 5322 -> 5323; 4154 -> 4159 [label=true]; 4154 -> 5320 [label=false]; 5321 -> 5322; 4159 -> 4164 [label=true]; 4159 -> 5319 [label=false]; 5320 -> 5321; 4164 -> 4169 [label=true]; 4164 -> 5318 [label=false]; 5319 -> 5320; 4169 -> 4174 [label=true]; 4169 -> 5317 [label=false]; 5318 -> 5319; 4174 -> 4179 [label=true]; 4174 -> 5316 [label=false]; 5317 -> 5318; 4179 -> 4184 [label=true]; 4179 -> 5315 [label=false]; 5316 -> 5317; 4184 -> 4189 [label=true]; 4184 -> 5314 [label=false]; 5315 -> 5316; 4189 -> 4194 [label=true]; 4189 -> 5313 [label=false]; 5314 -> 5315; 4194 -> 4199 [label=true]; 4194 -> 5312 [label=false]; 5313 -> 5314; 4199 -> 4204 [label=true]; 4199 -> 5311 [label=false]; 5312 -> 5313; 4204 -> 4209 [label=true]; 4204 -> 5310 [label=false]; 5311 -> 5312; 4209 -> 4214 [label=true]; 4209 -> 5309 [label=false]; 5310 -> 5311; 4214 -> 4219 [label=true]; 4214 -> 5308 [label=false]; 5309 -> 5310; 4219 -> 4224 [label=true]; 4219 -> 5307 [label=false]; 5308 -> 5309; 4224 -> 4229 [label=true]; 4224 -> 5306 [label=false]; 5307 -> 5308; 4229 -> 4234 [label=true]; 4229 -> 5305 [label=false]; 5306 -> 5307; 4234 -> 4239 [label=true]; 4234 -> 5304 [label=false]; 5305 -> 5306; 4239 -> 4244 [label=true]; 4239 -> 5303 [label=false]; 5304 -> 5305; 4244 -> 4249 [label=true]; 4244 -> 5302 [label=false]; 5303 -> 5304; 4249 -> 4254 [label=true]; 4249 -> 5301 [label=false]; 5302 -> 5303; 4254 -> 4259 [label=true]; 4254 -> 5300 [label=false]; 5301 -> 5302; 4259 -> 4264 [label=true]; 4259 -> 5299 [label=false]; 5300 -> 5301; 4264 -> 4269 [label=true]; 4264 -> 5298 [label=false]; 5299 -> 5300; 4269 -> 4274 [label=true]; 4269 -> 5297 [label=false]; 5298 -> 5299; 4274 -> 4279 [label=true]; 4274 -> 5296 [label=false]; 5297 -> 5298; 4279 -> 4284 [label=true]; 4279 -> 5295 [label=false]; 5296 -> 5297; 4284 -> 4289 [label=true]; 4284 -> 5294 [label=false]; 5295 -> 5296; 4289 -> 4294 [label=true]; 4289 -> 5293 [label=false]; 5294 -> 5295; 4294 -> 4299 [label=true]; 4294 -> 5292 [label=false]; 5293 -> 5294; 4299 -> 4304 [label=true]; 4299 -> 5291 [label=false]; 5292 -> 5293; 4304 -> 4309 [label=true]; 4304 -> 5290 [label=false]; 5291 -> 5292; 4309 -> 4314 [label=true]; 4309 -> 5289 [label=false]; 5290 -> 5291; 4314 -> 4319 [label=true]; 4314 -> 5288 [label=false]; 5289 -> 5290; 4319 -> 4324 [label=true]; 4319 -> 5287 [label=false]; 5288 -> 5289; 4324 -> 4329 [label=true]; 4324 -> 5286 [label=false]; 5287 -> 5288; 4329 -> 4334 [label=true]; 4329 -> 5285 [label=false]; 5286 -> 5287; 4334 -> 4339 [label=true]; 4334 -> 5284 [label=false]; 5285 -> 5286; 4339 -> 4344 [label=true]; 4339 -> 5283 [label=false]; 5284 -> 5285; 4344 -> 4349 [label=true]; 4344 -> 5282 [label=false]; 5283 -> 5284; 4349 -> 4354 [label=true]; 4349 -> 5281 [label=false]; 5282 -> 5283; 4354 -> 4359 [label=true]; 4354 -> 5280 [label=false]; 5281 -> 5282; 4359 -> 4364 [label=true]; 4359 -> 5279 [label=false]; 5280 -> 5281; 4364 -> 4369 [label=true]; 4364 -> 5278 [label=false]; 5279 -> 5280; 4369 -> 4374 [label=true]; 4369 -> 5277 [label=false]; 5278 -> 5279; 4374 -> 4379 [label=true]; 4374 -> 5276 [label=false]; 5277 -> 5278; 4379 -> 4384 [label=true]; 4379 -> 5275 [label=false]; 5276 -> 5277; 4384 -> 4389 [label=true]; 4384 -> 5274 [label=false]; 5275 -> 5276; 4389 -> 4394 [label=true]; 4389 -> 5273 [label=false]; 5274 -> 5275; 4394 -> 4399 [label=true]; 4394 -> 5272 [label=false]; 5273 -> 5274; 4399 -> 4404 [label=true]; 4399 -> 5271 [label=false]; 5272 -> 5273; 4404 -> 4409 [label=true]; 4404 -> 5270 [label=false]; 5271 -> 5272; 4409 -> 4414 [label=true]; 4409 -> 5269 [label=false]; 5270 -> 5271; 4414 -> 4419 [label=true]; 4414 -> 5268 [label=false]; 5269 -> 5270; 4419 -> 4424 [label=true]; 4419 -> 5267 [label=false]; 5268 -> 5269; 4424 -> 4429 [label=true]; 4424 -> 5266 [label=false]; 5267 -> 5268; 4429 -> 4434 [label=true]; 4429 -> 5265 [label=false]; 5266 -> 5267; 4434 -> 4439 [label=true]; 4434 -> 5264 [label=false]; 5265 -> 5266; 4439 -> 4444 [label=true]; 4439 -> 5263 [label=false]; 5264 -> 5265; 4444 -> 4449 [label=true]; 4444 -> 5262 [label=false]; 5263 -> 5264; 4449 -> 4454 [label=true]; 4449 -> 5261 [label=false]; 5262 -> 5263; 4454 -> 4459 [label=true]; 4454 -> 5260 [label=false]; 5261 -> 5262; 4459 -> 4464 [label=true]; 4459 -> 5259 [label=false]; 5260 -> 5261; 4464 -> 4469 [label=true]; 4464 -> 5258 [label=false]; 5259 -> 5260; 4469 -> 4474 [label=true]; 4469 -> 5257 [label=false]; 5258 -> 5259; 4474 -> 4479 [label=true]; 4474 -> 5256 [label=false]; 5257 -> 5258; 4479 -> 4484 [label=true]; 4479 -> 5255 [label=false]; 5256 -> 5257; 4484 -> 4489 [label=true]; 4484 -> 5254 [label=false]; 5255 -> 5256; 4489 -> 4494 [label=true]; 4489 -> 5253 [label=false]; 5254 -> 5255; 4494 -> 4499 [label=true]; 4494 -> 5252 [label=false]; 5253 -> 5254; 4499 -> 4504 [label=true]; 4499 -> 5251 [label=false]; 5252 -> 5253; 4504 -> 4509 [label=true]; 4504 -> 5250 [label=false]; 5251 -> 5252; 4509 -> 4514 [label=true]; 4509 -> 5249 [label=false]; 5250 -> 5251; 4514 -> 4519 [label=true]; 4514 -> 5248 [label=false]; 5249 -> 5250; 4519 -> 4524 [label=true]; 4519 -> 5247 [label=false]; 5248 -> 5249; 4524 -> 4529 [label=true]; 4524 -> 5246 [label=false]; 5247 -> 5248; 4529 -> 4534 [label=true]; 4529 -> 5245 [label=false]; 5246 -> 5247; 4534 -> 4539 [label=true]; 4534 -> 5244 [label=false]; 5245 -> 5246; 4539 -> 4544 [label=true]; 4539 -> 5243 [label=false]; 5244 -> 5245; 4544 -> 4549 [label=true]; 4544 -> 5242 [label=false]; 5243 -> 5244; 4549 -> 4554 [label=true]; 4549 -> 5241 [label=false]; 5242 -> 5243; 4554 -> 4559 [label=true]; 4554 -> 5240 [label=false]; 5241 -> 5242; 4559 -> 4564 [label=true]; 4559 -> 5239 [label=false]; 5240 -> 5241; 4564 -> 4569 [label=true]; 4564 -> 5238 [label=false]; 5239 -> 5240; 4569 -> 4574 [label=true]; 4569 -> 5237 [label=false]; 5238 -> 5239; 4574 -> 4579 [label=true]; 4574 -> 5236 [label=false]; 5237 -> 5238; 4579 -> 4584 [label=true]; 4579 -> 5235 [label=false]; 5236 -> 5237; 4584 -> 4589 [label=true]; 4584 -> 5234 [label=false]; 5235 -> 5236; 4589 -> 4594 [label=true]; 4589 -> 5233 [label=false]; 5234 -> 5235; 4594 -> 4599 [label=true]; 4594 -> 5232 [label=false]; 5233 -> 5234; 4599 -> 4604 [label=true]; 4599 -> 5231 [label=false]; 5232 -> 5233; 4604 -> 4609 [label=true]; 4604 -> 5230 [label=false]; 5231 -> 5232; 4609 -> 4614 [label=true]; 4609 -> 5229 [label=false]; 5230 -> 5231; 4614 -> 4619 [label=true]; 4614 -> 5228 [label=false]; 5229 -> 5230; 4619 -> 4624 [label=true]; 4619 -> 5227 [label=false]; 5228 -> 5229; 4624 -> 4629 [label=true]; 4624 -> 5226 [label=false]; 5227 -> 5228; 4629 -> 4634 [label=true]; 4629 -> 5225 [label=false]; 5226 -> 5227; 4634 -> 4639 [label=true]; 4634 -> 5224 [label=false]; 5225 -> 5226; 4639 -> 4644 [label=true]; 4639 -> 5223 [label=false]; 5224 -> 5225; 4644 -> 4649 [label=true]; 4644 -> 5222 [label=false]; 5223 -> 5224; 4649 -> 4654 [label=true]; 4649 -> 5221 [label=false]; 5222 -> 5223; 4654 -> 4659 [label=true]; 4654 -> 5220 [label=false]; 5221 -> 5222; 4659 -> 4664 [label=true]; 4659 -> 5219 [label=false]; 5220 -> 5221; 4664 -> 4669 [label=true]; 4664 -> 5218 [label=false]; 5219 -> 5220; 4669 -> 4674 [label=true]; 4669 -> 5217 [label=false]; 5218 -> 5219; 4674 -> 4679 [label=true]; 4674 -> 5216 [label=false]; 5217 -> 5218; 4679 -> 4684 [label=true]; 4679 -> 5215 [label=false]; 5216 -> 5217; 4684 -> 4689 [label=true]; 4684 -> 5214 [label=false]; 5215 -> 5216; 4689 -> 4694 [label=true]; 4689 -> 5213 [label=false]; 5214 -> 5215; 4694 -> 4699 [label=true]; 4694 -> 5212 [label=false]; 5213 -> 5214; 4699 -> 4704 [label=true]; 4699 -> 5211 [label=false]; 5212 -> 5213; 4704 -> 4709 [label=true]; 4704 -> 5210 [label=false]; 5211 -> 5212; 4709 -> 4714 [label=true]; 4709 -> 5209 [label=false]; 5210 -> 5211; 4714 -> 4719 [label=true]; 4714 -> 5208 [label=false]; 5209 -> 5210; 4719 -> 4724 [label=true]; 4719 -> 5207 [label=false]; 5208 -> 5209; 4724 -> 4729 [label=true]; 4724 -> 5206 [label=false]; 5207 -> 5208; 4729 -> 4734 [label=true]; 4729 -> 5205 [label=false]; 5206 -> 5207; 4734 -> 4739 [label=true]; 4734 -> 5204 [label=false]; 5205 -> 5206; 4739 -> 4744 [label=true]; 4739 -> 5203 [label=false]; 5204 -> 5205; 4744 -> 4749 [label=true]; 4744 -> 5202 [label=false]; 5203 -> 5204; 4749 -> 4754 [label=true]; 4749 -> 5201 [label=false]; 5202 -> 5203; 4754 -> 4759 [label=true]; 4754 -> 5200 [label=false]; 5201 -> 5202; 4759 -> 4764 [label=true]; 4759 -> 5199 [label=false]; 5200 -> 5201; 4764 -> 4769 [label=true]; 4764 -> 5198 [label=false]; 5199 -> 5200; 4769 -> 4774 [label=true]; 4769 -> 5197 [label=false]; 5198 -> 5199; 4774 -> 4779 [label=true]; 4774 -> 5196 [label=false]; 5197 -> 5198; 4779 -> 4784 [label=true]; 4779 -> 5195 [label=false]; 5196 -> 5197; 4784 -> 4789 [label=true]; 4784 -> 5194 [label=false]; 5195 -> 5196; 4789 -> 4794 [label=true]; 4789 -> 5193 [label=false]; 5194 -> 5195; 4794 -> 4799 [label=true]; 4794 -> 5192 [label=false]; 5193 -> 5194; 4799 -> 4804 [label=true]; 4799 -> 5191 [label=false]; 5192 -> 5193; 4804 -> 4809 [label=true]; 4804 -> 5190 [label=false]; 5191 -> 5192; 4809 -> 4814 [label=true]; 4809 -> 5189 [label=false]; 5190 -> 5191; 4814 -> 4819 [label=true]; 4814 -> 5188 [label=false]; 5189 -> 5190; 4819 -> 4824 [label=true]; 4819 -> 5187 [label=false]; 5188 -> 5189; 4824 -> 4829 [label=true]; 4824 -> 5186 [label=false]; 5187 -> 5188; 4829 -> 4834 [label=true]; 4829 -> 5185 [label=false]; 5186 -> 5187; 4834 -> 4839 [label=true]; 4834 -> 5184 [label=false]; 5185 -> 5186; 4839 -> 4844 [label=true]; 4839 -> 5183 [label=false]; 5184 -> 5185; 4844 -> 4849 [label=true]; 4844 -> 5182 [label=false]; 5183 -> 5184; 4849 -> 4854 [label=true]; 4849 -> 5181 [label=false]; 5182 -> 5183; 4854 -> 4859 [label=true]; 4854 -> 5180 [label=false]; 5181 -> 5182; 4859 -> 4864 [label=true]; 4859 -> 5179 [label=false]; 5180 -> 5181; 4864 -> 4869 [label=true]; 4864 -> 5178 [label=false]; 5179 -> 5180; 4869 -> 4874 [label=true]; 4869 -> 5177 [label=false]; 5178 -> 5179; 4874 -> 4879 [label=true]; 4874 -> 5176 [label=false]; 5177 -> 5178; 4879 -> 4884 [label=true]; 4879 -> 5175 [label=false]; 5176 -> 5177; 4884 -> 4889 [label=true]; 4884 -> 5174 [label=false]; 5175 -> 5176; 4889 -> 4894 [label=true]; 4889 -> 5173 [label=false]; 5174 -> 5175; 4894 -> 4899 [label=true]; 4894 -> 5172 [label=false]; 5173 -> 5174; 4899 -> 4904 [label=true]; 4899 -> 5171 [label=false]; 5172 -> 5173; 4904 -> 4909 [label=true]; 4904 -> 5170 [label=false]; 5171 -> 5172; 4909 -> 4914 [label=true]; 4909 -> 5169 [label=false]; 5170 -> 5171; 4914 -> 4919 [label=true]; 4914 -> 5168 [label=false]; 5169 -> 5170; 4919 -> 4924 [label=true]; 4919 -> 5167 [label=false]; 5168 -> 5169; 4924 -> 4929 [label=true]; 4924 -> 5166 [label=false]; 5167 -> 5168; 4929 -> 4934 [label=true]; 4929 -> 5165 [label=false]; 5166 -> 5167; 4934 -> 4939 [label=true]; 4934 -> 5164 [label=false]; 5165 -> 5166; 4939 -> 4944 [label=true]; 4939 -> 5163 [label=false]; 5164 -> 5165; 4944 -> 4949 [label=true]; 4944 -> 5162 [label=false]; 5163 -> 5164; 4949 -> 4954 [label=true]; 4949 -> 5161 [label=false]; 5162 -> 5163; 4954 -> 4959 [label=true]; 4954 -> 5160 [label=false]; 5161 -> 5162; 4959 -> 4964 [label=true]; 4959 -> 5159 [label=false]; 5160 -> 5161; 4964 -> 4969 [label=true]; 4964 -> 5158 [label=false]; 5159 -> 5160; 4969 -> 4974 [label=true]; 4969 -> 5157 [label=false]; 5158 -> 5159; 4974 -> 4979 [label=true]; 4974 -> 5156 [label=false]; 5157 -> 5158; 4979 -> 4984 [label=true]; 4979 -> 5155 [label=false]; 5156 -> 5157; 4984 -> 4989 [label=true]; 4984 -> 5154 [label=false]; 5155 -> 5156; 4989 -> 4994 [label=true]; 4989 -> 5153 [label=false]; 5154 -> 5155; 4994 -> 4999 [label=true]; 4994 -> 5152 [label=false]; 5153 -> 5154; 4999 -> 5004 [label=true]; 4999 -> 5151 [label=false]; 5152 -> 5153; 5004 -> 5009 [label=true]; 5004 -> 5150 [label=false]; 5151 -> 5152; 5009 -> 5014 [label=true]; 5009 -> 5149 [label=false]; 5150 -> 5151; 5014 -> 5019 [label=true]; 5014 -> 5148 [label=false]; 5149 -> 5150; 5019 -> 5024 [label=true]; 5019 -> 5147 [label=false]; 5148 -> 5149; 5024 -> 5029 [label=true]; 5024 -> 5146 [label=false]; 5147 -> 5148; 5029 -> 5034 [label=true]; 5029 -> 5145 [label=false]; 5146 -> 5147; 5034 -> 5039 [label=true]; 5034 -> 5144 [label=false]; 5145 -> 5146; 5039 -> 5044 [label=true]; 5039 -> 5143 [label=false]; 5144 -> 5145; 5044 -> 5049 [label=true]; 5044 -> 5142 [label=false]; 5143 -> 5144; 5049 -> 5054 [label=true]; 5049 -> 5141 [label=false]; 5142 -> 5143; 5054 -> 5059 [label=true]; 5054 -> 5140 [label=false]; 5141 -> 5142; 5059 -> 5064 [label=true]; 5059 -> 5139 [label=false]; 5140 -> 5141; 5064 -> 5069 [label=true]; 5064 -> 5138 [label=false]; 5139 -> 5140; 5069 -> 5074 [label=true]; 5069 -> 5137 [label=false]; 5138 -> 5139; 5074 -> 5079 [label=true]; 5074 -> 5136 [label=false]; 5137 -> 5138; 5079 -> 5084 [label=true]; 5079 -> 5135 [label=false]; 5136 -> 5137; 5084 -> 5089 [label=true]; 5084 -> 5134 [label=false]; 5135 -> 5136; 5089 -> 5094 [label=true]; 5089 -> 5133 [label=false]; 5134 -> 5135; 5094 -> 5099 [label=true]; 5094 -> 5132 [label=false]; 5133 -> 5134; 5099 -> 5104 [label=true]; 5099 -> 5131 [label=false]; 5132 -> 5133; 5104 -> 5109 [label=true]; 5104 -> 5130 [label=false]; 5131 -> 5132; 5109 -> 5114 [label=true]; 5109 -> 5129 [label=false]; 5130 -> 5131; 5114 -> 5119 [label=true]; 5114 -> 5128 [label=false]; 5129 -> 5130; 5119 -> 5124 [label=true]; 5119 -> 5127 [label=false]; 5128 -> 5129; 5124 -> 5127; 5127 -> 5128; }golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n128.dot000066400000000000000000000233731450372207100257030ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 774; 14; 773; 19; 772; 24; 771; 29; 770; 34; 769; 39; 768; 44; 767; 49; 766; 54; 765; 59; 764; 64; 763; 69; 762; 74; 761; 79; 760; 84; 759; 89; 758; 94; 757; 99; 756; 104; 755; 109; 754; 114; 753; 119; 752; 124; 751; 129; 750; 134; 749; 139; 748; 144; 747; 149; 746; 154; 745; 159; 744; 164; 743; 169; 742; 174; 741; 179; 740; 184; 739; 189; 738; 194; 737; 199; 736; 204; 735; 209; 734; 214; 733; 219; 732; 224; 731; 229; 730; 234; 729; 239; 728; 244; 727; 249; 726; 254; 725; 259; 724; 264; 723; 269; 722; 274; 721; 279; 720; 284; 719; 289; 718; 294; 717; 299; 716; 304; 715; 309; 714; 314; 713; 319; 712; 324; 711; 329; 710; 334; 709; 339; 708; 344; 707; 349; 706; 354; 705; 359; 704; 364; 703; 369; 702; 374; 701; 379; 700; 384; 699; 389; 698; 394; 697; 399; 696; 404; 695; 409; 694; 414; 693; 419; 692; 424; 691; 429; 690; 434; 689; 439; 688; 444; 687; 449; 686; 454; 685; 459; 684; 464; 683; 469; 682; 474; 681; 479; 680; 484; 679; 489; 678; 494; 677; 499; 676; 504; 675; 509; 674; 514; 673; 519; 672; 524; 671; 529; 670; 534; 669; 539; 668; 544; 667; 549; 666; 554; 665; 559; 664; 564; 663; 569; 662; 574; 661; 579; 660; 584; 659; 589; 658; 594; 657; 599; 656; 604; 655; 609; 654; 614; 653; 619; 652; 624; 651; 629; 650; 634; 649; 639; 648; 644; 647; // Edge definitions. 2 -> 9 [label=true]; 2 -> 774 [label=false]; 9 -> 14 [label=true]; 9 -> 773 [label=false]; 14 -> 19 [label=true]; 14 -> 772 [label=false]; 773 -> 774; 19 -> 24 [label=true]; 19 -> 771 [label=false]; 772 -> 773; 24 -> 29 [label=true]; 24 -> 770 [label=false]; 771 -> 772; 29 -> 34 [label=true]; 29 -> 769 [label=false]; 770 -> 771; 34 -> 39 [label=true]; 34 -> 768 [label=false]; 769 -> 770; 39 -> 44 [label=true]; 39 -> 767 [label=false]; 768 -> 769; 44 -> 49 [label=true]; 44 -> 766 [label=false]; 767 -> 768; 49 -> 54 [label=true]; 49 -> 765 [label=false]; 766 -> 767; 54 -> 59 [label=true]; 54 -> 764 [label=false]; 765 -> 766; 59 -> 64 [label=true]; 59 -> 763 [label=false]; 764 -> 765; 64 -> 69 [label=true]; 64 -> 762 [label=false]; 763 -> 764; 69 -> 74 [label=true]; 69 -> 761 [label=false]; 762 -> 763; 74 -> 79 [label=true]; 74 -> 760 [label=false]; 761 -> 762; 79 -> 84 [label=true]; 79 -> 759 [label=false]; 760 -> 761; 84 -> 89 [label=true]; 84 -> 758 [label=false]; 759 -> 760; 89 -> 94 [label=true]; 89 -> 757 [label=false]; 758 -> 759; 94 -> 99 [label=true]; 94 -> 756 [label=false]; 757 -> 758; 99 -> 104 [label=true]; 99 -> 755 [label=false]; 756 -> 757; 104 -> 109 [label=true]; 104 -> 754 [label=false]; 755 -> 756; 109 -> 114 [label=true]; 109 -> 753 [label=false]; 754 -> 755; 114 -> 119 [label=true]; 114 -> 752 [label=false]; 753 -> 754; 119 -> 124 [label=true]; 119 -> 751 [label=false]; 752 -> 753; 124 -> 129 [label=true]; 124 -> 750 [label=false]; 751 -> 752; 129 -> 134 [label=true]; 129 -> 749 [label=false]; 750 -> 751; 134 -> 139 [label=true]; 134 -> 748 [label=false]; 749 -> 750; 139 -> 144 [label=true]; 139 -> 747 [label=false]; 748 -> 749; 144 -> 149 [label=true]; 144 -> 746 [label=false]; 747 -> 748; 149 -> 154 [label=true]; 149 -> 745 [label=false]; 746 -> 747; 154 -> 159 [label=true]; 154 -> 744 [label=false]; 745 -> 746; 159 -> 164 [label=true]; 159 -> 743 [label=false]; 744 -> 745; 164 -> 169 [label=true]; 164 -> 742 [label=false]; 743 -> 744; 169 -> 174 [label=true]; 169 -> 741 [label=false]; 742 -> 743; 174 -> 179 [label=true]; 174 -> 740 [label=false]; 741 -> 742; 179 -> 184 [label=true]; 179 -> 739 [label=false]; 740 -> 741; 184 -> 189 [label=true]; 184 -> 738 [label=false]; 739 -> 740; 189 -> 194 [label=true]; 189 -> 737 [label=false]; 738 -> 739; 194 -> 199 [label=true]; 194 -> 736 [label=false]; 737 -> 738; 199 -> 204 [label=true]; 199 -> 735 [label=false]; 736 -> 737; 204 -> 209 [label=true]; 204 -> 734 [label=false]; 735 -> 736; 209 -> 214 [label=true]; 209 -> 733 [label=false]; 734 -> 735; 214 -> 219 [label=true]; 214 -> 732 [label=false]; 733 -> 734; 219 -> 224 [label=true]; 219 -> 731 [label=false]; 732 -> 733; 224 -> 229 [label=true]; 224 -> 730 [label=false]; 731 -> 732; 229 -> 234 [label=true]; 229 -> 729 [label=false]; 730 -> 731; 234 -> 239 [label=true]; 234 -> 728 [label=false]; 729 -> 730; 239 -> 244 [label=true]; 239 -> 727 [label=false]; 728 -> 729; 244 -> 249 [label=true]; 244 -> 726 [label=false]; 727 -> 728; 249 -> 254 [label=true]; 249 -> 725 [label=false]; 726 -> 727; 254 -> 259 [label=true]; 254 -> 724 [label=false]; 725 -> 726; 259 -> 264 [label=true]; 259 -> 723 [label=false]; 724 -> 725; 264 -> 269 [label=true]; 264 -> 722 [label=false]; 723 -> 724; 269 -> 274 [label=true]; 269 -> 721 [label=false]; 722 -> 723; 274 -> 279 [label=true]; 274 -> 720 [label=false]; 721 -> 722; 279 -> 284 [label=true]; 279 -> 719 [label=false]; 720 -> 721; 284 -> 289 [label=true]; 284 -> 718 [label=false]; 719 -> 720; 289 -> 294 [label=true]; 289 -> 717 [label=false]; 718 -> 719; 294 -> 299 [label=true]; 294 -> 716 [label=false]; 717 -> 718; 299 -> 304 [label=true]; 299 -> 715 [label=false]; 716 -> 717; 304 -> 309 [label=true]; 304 -> 714 [label=false]; 715 -> 716; 309 -> 314 [label=true]; 309 -> 713 [label=false]; 714 -> 715; 314 -> 319 [label=true]; 314 -> 712 [label=false]; 713 -> 714; 319 -> 324 [label=true]; 319 -> 711 [label=false]; 712 -> 713; 324 -> 329 [label=true]; 324 -> 710 [label=false]; 711 -> 712; 329 -> 334 [label=true]; 329 -> 709 [label=false]; 710 -> 711; 334 -> 339 [label=true]; 334 -> 708 [label=false]; 709 -> 710; 339 -> 344 [label=true]; 339 -> 707 [label=false]; 708 -> 709; 344 -> 349 [label=true]; 344 -> 706 [label=false]; 707 -> 708; 349 -> 354 [label=true]; 349 -> 705 [label=false]; 706 -> 707; 354 -> 359 [label=true]; 354 -> 704 [label=false]; 705 -> 706; 359 -> 364 [label=true]; 359 -> 703 [label=false]; 704 -> 705; 364 -> 369 [label=true]; 364 -> 702 [label=false]; 703 -> 704; 369 -> 374 [label=true]; 369 -> 701 [label=false]; 702 -> 703; 374 -> 379 [label=true]; 374 -> 700 [label=false]; 701 -> 702; 379 -> 384 [label=true]; 379 -> 699 [label=false]; 700 -> 701; 384 -> 389 [label=true]; 384 -> 698 [label=false]; 699 -> 700; 389 -> 394 [label=true]; 389 -> 697 [label=false]; 698 -> 699; 394 -> 399 [label=true]; 394 -> 696 [label=false]; 697 -> 698; 399 -> 404 [label=true]; 399 -> 695 [label=false]; 696 -> 697; 404 -> 409 [label=true]; 404 -> 694 [label=false]; 695 -> 696; 409 -> 414 [label=true]; 409 -> 693 [label=false]; 694 -> 695; 414 -> 419 [label=true]; 414 -> 692 [label=false]; 693 -> 694; 419 -> 424 [label=true]; 419 -> 691 [label=false]; 692 -> 693; 424 -> 429 [label=true]; 424 -> 690 [label=false]; 691 -> 692; 429 -> 434 [label=true]; 429 -> 689 [label=false]; 690 -> 691; 434 -> 439 [label=true]; 434 -> 688 [label=false]; 689 -> 690; 439 -> 444 [label=true]; 439 -> 687 [label=false]; 688 -> 689; 444 -> 449 [label=true]; 444 -> 686 [label=false]; 687 -> 688; 449 -> 454 [label=true]; 449 -> 685 [label=false]; 686 -> 687; 454 -> 459 [label=true]; 454 -> 684 [label=false]; 685 -> 686; 459 -> 464 [label=true]; 459 -> 683 [label=false]; 684 -> 685; 464 -> 469 [label=true]; 464 -> 682 [label=false]; 683 -> 684; 469 -> 474 [label=true]; 469 -> 681 [label=false]; 682 -> 683; 474 -> 479 [label=true]; 474 -> 680 [label=false]; 681 -> 682; 479 -> 484 [label=true]; 479 -> 679 [label=false]; 680 -> 681; 484 -> 489 [label=true]; 484 -> 678 [label=false]; 679 -> 680; 489 -> 494 [label=true]; 489 -> 677 [label=false]; 678 -> 679; 494 -> 499 [label=true]; 494 -> 676 [label=false]; 677 -> 678; 499 -> 504 [label=true]; 499 -> 675 [label=false]; 676 -> 677; 504 -> 509 [label=true]; 504 -> 674 [label=false]; 675 -> 676; 509 -> 514 [label=true]; 509 -> 673 [label=false]; 674 -> 675; 514 -> 519 [label=true]; 514 -> 672 [label=false]; 673 -> 674; 519 -> 524 [label=true]; 519 -> 671 [label=false]; 672 -> 673; 524 -> 529 [label=true]; 524 -> 670 [label=false]; 671 -> 672; 529 -> 534 [label=true]; 529 -> 669 [label=false]; 670 -> 671; 534 -> 539 [label=true]; 534 -> 668 [label=false]; 669 -> 670; 539 -> 544 [label=true]; 539 -> 667 [label=false]; 668 -> 669; 544 -> 549 [label=true]; 544 -> 666 [label=false]; 667 -> 668; 549 -> 554 [label=true]; 549 -> 665 [label=false]; 666 -> 667; 554 -> 559 [label=true]; 554 -> 664 [label=false]; 665 -> 666; 559 -> 564 [label=true]; 559 -> 663 [label=false]; 664 -> 665; 564 -> 569 [label=true]; 564 -> 662 [label=false]; 663 -> 664; 569 -> 574 [label=true]; 569 -> 661 [label=false]; 662 -> 663; 574 -> 579 [label=true]; 574 -> 660 [label=false]; 661 -> 662; 579 -> 584 [label=true]; 579 -> 659 [label=false]; 660 -> 661; 584 -> 589 [label=true]; 584 -> 658 [label=false]; 659 -> 660; 589 -> 594 [label=true]; 589 -> 657 [label=false]; 658 -> 659; 594 -> 599 [label=true]; 594 -> 656 [label=false]; 657 -> 658; 599 -> 604 [label=true]; 599 -> 655 [label=false]; 656 -> 657; 604 -> 609 [label=true]; 604 -> 654 [label=false]; 655 -> 656; 609 -> 614 [label=true]; 609 -> 653 [label=false]; 654 -> 655; 614 -> 619 [label=true]; 614 -> 652 [label=false]; 653 -> 654; 619 -> 624 [label=true]; 619 -> 651 [label=false]; 652 -> 653; 624 -> 629 [label=true]; 624 -> 650 [label=false]; 651 -> 652; 629 -> 634 [label=true]; 629 -> 649 [label=false]; 650 -> 651; 634 -> 639 [label=true]; 634 -> 648 [label=false]; 649 -> 650; 639 -> 644 [label=true]; 639 -> 647 [label=false]; 648 -> 649; 644 -> 647; 647 -> 648; }golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n16.dot000066400000000000000000000022641450372207100256130ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 102; 14; 101; 19; 100; 24; 99; 29; 98; 34; 97; 39; 96; 44; 95; 49; 94; 54; 93; 59; 92; 64; 91; 69; 90; 74; 89; 79; 88; 84; 87; // Edge definitions. 2 -> 9 [label=true]; 2 -> 102 [label=false]; 9 -> 14 [label=true]; 9 -> 101 [label=false]; 14 -> 19 [label=true]; 14 -> 100 [label=false]; 101 -> 102; 19 -> 24 [label=true]; 19 -> 99 [label=false]; 100 -> 101; 24 -> 29 [label=true]; 24 -> 98 [label=false]; 99 -> 100; 29 -> 34 [label=true]; 29 -> 97 [label=false]; 98 -> 99; 34 -> 39 [label=true]; 34 -> 96 [label=false]; 97 -> 98; 39 -> 44 [label=true]; 39 -> 95 [label=false]; 96 -> 97; 44 -> 49 [label=true]; 44 -> 94 [label=false]; 95 -> 96; 49 -> 54 [label=true]; 49 -> 93 [label=false]; 94 -> 95; 54 -> 59 [label=true]; 54 -> 92 [label=false]; 93 -> 94; 59 -> 64 [label=true]; 59 -> 91 [label=false]; 92 -> 93; 64 -> 69 [label=true]; 64 -> 90 [label=false]; 91 -> 92; 69 -> 74 [label=true]; 69 -> 89 [label=false]; 90 -> 91; 74 -> 79 [label=true]; 74 -> 88 [label=false]; 89 -> 90; 79 -> 84 [label=true]; 79 -> 87 [label=false]; 88 -> 89; 84 -> 87; 87 -> 88; }golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n2048.dot000066400000000000000000005466371450372207100260030ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 12294; 14; 12293; 19; 12292; 24; 12291; 29; 12290; 34; 12289; 39; 12288; 44; 12287; 49; 12286; 54; 12285; 59; 12284; 64; 12283; 69; 12282; 74; 12281; 79; 12280; 84; 12279; 89; 12278; 94; 12277; 99; 12276; 104; 12275; 109; 12274; 114; 12273; 119; 12272; 124; 12271; 129; 12270; 134; 12269; 139; 12268; 144; 12267; 149; 12266; 154; 12265; 159; 12264; 164; 12263; 169; 12262; 174; 12261; 179; 12260; 184; 12259; 189; 12258; 194; 12257; 199; 12256; 204; 12255; 209; 12254; 214; 12253; 219; 12252; 224; 12251; 229; 12250; 234; 12249; 239; 12248; 244; 12247; 249; 12246; 254; 12245; 259; 12244; 264; 12243; 269; 12242; 274; 12241; 279; 12240; 284; 12239; 289; 12238; 294; 12237; 299; 12236; 304; 12235; 309; 12234; 314; 12233; 319; 12232; 324; 12231; 329; 12230; 334; 12229; 339; 12228; 344; 12227; 349; 12226; 354; 12225; 359; 12224; 364; 12223; 369; 12222; 374; 12221; 379; 12220; 384; 12219; 389; 12218; 394; 12217; 399; 12216; 404; 12215; 409; 12214; 414; 12213; 419; 12212; 424; 12211; 429; 12210; 434; 12209; 439; 12208; 444; 12207; 449; 12206; 454; 12205; 459; 12204; 464; 12203; 469; 12202; 474; 12201; 479; 12200; 484; 12199; 489; 12198; 494; 12197; 499; 12196; 504; 12195; 509; 12194; 514; 12193; 519; 12192; 524; 12191; 529; 12190; 534; 12189; 539; 12188; 544; 12187; 549; 12186; 554; 12185; 559; 12184; 564; 12183; 569; 12182; 574; 12181; 579; 12180; 584; 12179; 589; 12178; 594; 12177; 599; 12176; 604; 12175; 609; 12174; 614; 12173; 619; 12172; 624; 12171; 629; 12170; 634; 12169; 639; 12168; 644; 12167; 649; 12166; 654; 12165; 659; 12164; 664; 12163; 669; 12162; 674; 12161; 679; 12160; 684; 12159; 689; 12158; 694; 12157; 699; 12156; 704; 12155; 709; 12154; 714; 12153; 719; 12152; 724; 12151; 729; 12150; 734; 12149; 739; 12148; 744; 12147; 749; 12146; 754; 12145; 759; 12144; 764; 12143; 769; 12142; 774; 12141; 779; 12140; 784; 12139; 789; 12138; 794; 12137; 799; 12136; 804; 12135; 809; 12134; 814; 12133; 819; 12132; 824; 12131; 829; 12130; 834; 12129; 839; 12128; 844; 12127; 849; 12126; 854; 12125; 859; 12124; 864; 12123; 869; 12122; 874; 12121; 879; 12120; 884; 12119; 889; 12118; 894; 12117; 899; 12116; 904; 12115; 909; 12114; 914; 12113; 919; 12112; 924; 12111; 929; 12110; 934; 12109; 939; 12108; 944; 12107; 949; 12106; 954; 12105; 959; 12104; 964; 12103; 969; 12102; 974; 12101; 979; 12100; 984; 12099; 989; 12098; 994; 12097; 999; 12096; 1004; 12095; 1009; 12094; 1014; 12093; 1019; 12092; 1024; 12091; 1029; 12090; 1034; 12089; 1039; 12088; 1044; 12087; 1049; 12086; 1054; 12085; 1059; 12084; 1064; 12083; 1069; 12082; 1074; 12081; 1079; 12080; 1084; 12079; 1089; 12078; 1094; 12077; 1099; 12076; 1104; 12075; 1109; 12074; 1114; 12073; 1119; 12072; 1124; 12071; 1129; 12070; 1134; 12069; 1139; 12068; 1144; 12067; 1149; 12066; 1154; 12065; 1159; 12064; 1164; 12063; 1169; 12062; 1174; 12061; 1179; 12060; 1184; 12059; 1189; 12058; 1194; 12057; 1199; 12056; 1204; 12055; 1209; 12054; 1214; 12053; 1219; 12052; 1224; 12051; 1229; 12050; 1234; 12049; 1239; 12048; 1244; 12047; 1249; 12046; 1254; 12045; 1259; 12044; 1264; 12043; 1269; 12042; 1274; 12041; 1279; 12040; 1284; 12039; 1289; 12038; 1294; 12037; 1299; 12036; 1304; 12035; 1309; 12034; 1314; 12033; 1319; 12032; 1324; 12031; 1329; 12030; 1334; 12029; 1339; 12028; 1344; 12027; 1349; 12026; 1354; 12025; 1359; 12024; 1364; 12023; 1369; 12022; 1374; 12021; 1379; 12020; 1384; 12019; 1389; 12018; 1394; 12017; 1399; 12016; 1404; 12015; 1409; 12014; 1414; 12013; 1419; 12012; 1424; 12011; 1429; 12010; 1434; 12009; 1439; 12008; 1444; 12007; 1449; 12006; 1454; 12005; 1459; 12004; 1464; 12003; 1469; 12002; 1474; 12001; 1479; 12000; 1484; 11999; 1489; 11998; 1494; 11997; 1499; 11996; 1504; 11995; 1509; 11994; 1514; 11993; 1519; 11992; 1524; 11991; 1529; 11990; 1534; 11989; 1539; 11988; 1544; 11987; 1549; 11986; 1554; 11985; 1559; 11984; 1564; 11983; 1569; 11982; 1574; 11981; 1579; 11980; 1584; 11979; 1589; 11978; 1594; 11977; 1599; 11976; 1604; 11975; 1609; 11974; 1614; 11973; 1619; 11972; 1624; 11971; 1629; 11970; 1634; 11969; 1639; 11968; 1644; 11967; 1649; 11966; 1654; 11965; 1659; 11964; 1664; 11963; 1669; 11962; 1674; 11961; 1679; 11960; 1684; 11959; 1689; 11958; 1694; 11957; 1699; 11956; 1704; 11955; 1709; 11954; 1714; 11953; 1719; 11952; 1724; 11951; 1729; 11950; 1734; 11949; 1739; 11948; 1744; 11947; 1749; 11946; 1754; 11945; 1759; 11944; 1764; 11943; 1769; 11942; 1774; 11941; 1779; 11940; 1784; 11939; 1789; 11938; 1794; 11937; 1799; 11936; 1804; 11935; 1809; 11934; 1814; 11933; 1819; 11932; 1824; 11931; 1829; 11930; 1834; 11929; 1839; 11928; 1844; 11927; 1849; 11926; 1854; 11925; 1859; 11924; 1864; 11923; 1869; 11922; 1874; 11921; 1879; 11920; 1884; 11919; 1889; 11918; 1894; 11917; 1899; 11916; 1904; 11915; 1909; 11914; 1914; 11913; 1919; 11912; 1924; 11911; 1929; 11910; 1934; 11909; 1939; 11908; 1944; 11907; 1949; 11906; 1954; 11905; 1959; 11904; 1964; 11903; 1969; 11902; 1974; 11901; 1979; 11900; 1984; 11899; 1989; 11898; 1994; 11897; 1999; 11896; 2004; 11895; 2009; 11894; 2014; 11893; 2019; 11892; 2024; 11891; 2029; 11890; 2034; 11889; 2039; 11888; 2044; 11887; 2049; 11886; 2054; 11885; 2059; 11884; 2064; 11883; 2069; 11882; 2074; 11881; 2079; 11880; 2084; 11879; 2089; 11878; 2094; 11877; 2099; 11876; 2104; 11875; 2109; 11874; 2114; 11873; 2119; 11872; 2124; 11871; 2129; 11870; 2134; 11869; 2139; 11868; 2144; 11867; 2149; 11866; 2154; 11865; 2159; 11864; 2164; 11863; 2169; 11862; 2174; 11861; 2179; 11860; 2184; 11859; 2189; 11858; 2194; 11857; 2199; 11856; 2204; 11855; 2209; 11854; 2214; 11853; 2219; 11852; 2224; 11851; 2229; 11850; 2234; 11849; 2239; 11848; 2244; 11847; 2249; 11846; 2254; 11845; 2259; 11844; 2264; 11843; 2269; 11842; 2274; 11841; 2279; 11840; 2284; 11839; 2289; 11838; 2294; 11837; 2299; 11836; 2304; 11835; 2309; 11834; 2314; 11833; 2319; 11832; 2324; 11831; 2329; 11830; 2334; 11829; 2339; 11828; 2344; 11827; 2349; 11826; 2354; 11825; 2359; 11824; 2364; 11823; 2369; 11822; 2374; 11821; 2379; 11820; 2384; 11819; 2389; 11818; 2394; 11817; 2399; 11816; 2404; 11815; 2409; 11814; 2414; 11813; 2419; 11812; 2424; 11811; 2429; 11810; 2434; 11809; 2439; 11808; 2444; 11807; 2449; 11806; 2454; 11805; 2459; 11804; 2464; 11803; 2469; 11802; 2474; 11801; 2479; 11800; 2484; 11799; 2489; 11798; 2494; 11797; 2499; 11796; 2504; 11795; 2509; 11794; 2514; 11793; 2519; 11792; 2524; 11791; 2529; 11790; 2534; 11789; 2539; 11788; 2544; 11787; 2549; 11786; 2554; 11785; 2559; 11784; 2564; 11783; 2569; 11782; 2574; 11781; 2579; 11780; 2584; 11779; 2589; 11778; 2594; 11777; 2599; 11776; 2604; 11775; 2609; 11774; 2614; 11773; 2619; 11772; 2624; 11771; 2629; 11770; 2634; 11769; 2639; 11768; 2644; 11767; 2649; 11766; 2654; 11765; 2659; 11764; 2664; 11763; 2669; 11762; 2674; 11761; 2679; 11760; 2684; 11759; 2689; 11758; 2694; 11757; 2699; 11756; 2704; 11755; 2709; 11754; 2714; 11753; 2719; 11752; 2724; 11751; 2729; 11750; 2734; 11749; 2739; 11748; 2744; 11747; 2749; 11746; 2754; 11745; 2759; 11744; 2764; 11743; 2769; 11742; 2774; 11741; 2779; 11740; 2784; 11739; 2789; 11738; 2794; 11737; 2799; 11736; 2804; 11735; 2809; 11734; 2814; 11733; 2819; 11732; 2824; 11731; 2829; 11730; 2834; 11729; 2839; 11728; 2844; 11727; 2849; 11726; 2854; 11725; 2859; 11724; 2864; 11723; 2869; 11722; 2874; 11721; 2879; 11720; 2884; 11719; 2889; 11718; 2894; 11717; 2899; 11716; 2904; 11715; 2909; 11714; 2914; 11713; 2919; 11712; 2924; 11711; 2929; 11710; 2934; 11709; 2939; 11708; 2944; 11707; 2949; 11706; 2954; 11705; 2959; 11704; 2964; 11703; 2969; 11702; 2974; 11701; 2979; 11700; 2984; 11699; 2989; 11698; 2994; 11697; 2999; 11696; 3004; 11695; 3009; 11694; 3014; 11693; 3019; 11692; 3024; 11691; 3029; 11690; 3034; 11689; 3039; 11688; 3044; 11687; 3049; 11686; 3054; 11685; 3059; 11684; 3064; 11683; 3069; 11682; 3074; 11681; 3079; 11680; 3084; 11679; 3089; 11678; 3094; 11677; 3099; 11676; 3104; 11675; 3109; 11674; 3114; 11673; 3119; 11672; 3124; 11671; 3129; 11670; 3134; 11669; 3139; 11668; 3144; 11667; 3149; 11666; 3154; 11665; 3159; 11664; 3164; 11663; 3169; 11662; 3174; 11661; 3179; 11660; 3184; 11659; 3189; 11658; 3194; 11657; 3199; 11656; 3204; 11655; 3209; 11654; 3214; 11653; 3219; 11652; 3224; 11651; 3229; 11650; 3234; 11649; 3239; 11648; 3244; 11647; 3249; 11646; 3254; 11645; 3259; 11644; 3264; 11643; 3269; 11642; 3274; 11641; 3279; 11640; 3284; 11639; 3289; 11638; 3294; 11637; 3299; 11636; 3304; 11635; 3309; 11634; 3314; 11633; 3319; 11632; 3324; 11631; 3329; 11630; 3334; 11629; 3339; 11628; 3344; 11627; 3349; 11626; 3354; 11625; 3359; 11624; 3364; 11623; 3369; 11622; 3374; 11621; 3379; 11620; 3384; 11619; 3389; 11618; 3394; 11617; 3399; 11616; 3404; 11615; 3409; 11614; 3414; 11613; 3419; 11612; 3424; 11611; 3429; 11610; 3434; 11609; 3439; 11608; 3444; 11607; 3449; 11606; 3454; 11605; 3459; 11604; 3464; 11603; 3469; 11602; 3474; 11601; 3479; 11600; 3484; 11599; 3489; 11598; 3494; 11597; 3499; 11596; 3504; 11595; 3509; 11594; 3514; 11593; 3519; 11592; 3524; 11591; 3529; 11590; 3534; 11589; 3539; 11588; 3544; 11587; 3549; 11586; 3554; 11585; 3559; 11584; 3564; 11583; 3569; 11582; 3574; 11581; 3579; 11580; 3584; 11579; 3589; 11578; 3594; 11577; 3599; 11576; 3604; 11575; 3609; 11574; 3614; 11573; 3619; 11572; 3624; 11571; 3629; 11570; 3634; 11569; 3639; 11568; 3644; 11567; 3649; 11566; 3654; 11565; 3659; 11564; 3664; 11563; 3669; 11562; 3674; 11561; 3679; 11560; 3684; 11559; 3689; 11558; 3694; 11557; 3699; 11556; 3704; 11555; 3709; 11554; 3714; 11553; 3719; 11552; 3724; 11551; 3729; 11550; 3734; 11549; 3739; 11548; 3744; 11547; 3749; 11546; 3754; 11545; 3759; 11544; 3764; 11543; 3769; 11542; 3774; 11541; 3779; 11540; 3784; 11539; 3789; 11538; 3794; 11537; 3799; 11536; 3804; 11535; 3809; 11534; 3814; 11533; 3819; 11532; 3824; 11531; 3829; 11530; 3834; 11529; 3839; 11528; 3844; 11527; 3849; 11526; 3854; 11525; 3859; 11524; 3864; 11523; 3869; 11522; 3874; 11521; 3879; 11520; 3884; 11519; 3889; 11518; 3894; 11517; 3899; 11516; 3904; 11515; 3909; 11514; 3914; 11513; 3919; 11512; 3924; 11511; 3929; 11510; 3934; 11509; 3939; 11508; 3944; 11507; 3949; 11506; 3954; 11505; 3959; 11504; 3964; 11503; 3969; 11502; 3974; 11501; 3979; 11500; 3984; 11499; 3989; 11498; 3994; 11497; 3999; 11496; 4004; 11495; 4009; 11494; 4014; 11493; 4019; 11492; 4024; 11491; 4029; 11490; 4034; 11489; 4039; 11488; 4044; 11487; 4049; 11486; 4054; 11485; 4059; 11484; 4064; 11483; 4069; 11482; 4074; 11481; 4079; 11480; 4084; 11479; 4089; 11478; 4094; 11477; 4099; 11476; 4104; 11475; 4109; 11474; 4114; 11473; 4119; 11472; 4124; 11471; 4129; 11470; 4134; 11469; 4139; 11468; 4144; 11467; 4149; 11466; 4154; 11465; 4159; 11464; 4164; 11463; 4169; 11462; 4174; 11461; 4179; 11460; 4184; 11459; 4189; 11458; 4194; 11457; 4199; 11456; 4204; 11455; 4209; 11454; 4214; 11453; 4219; 11452; 4224; 11451; 4229; 11450; 4234; 11449; 4239; 11448; 4244; 11447; 4249; 11446; 4254; 11445; 4259; 11444; 4264; 11443; 4269; 11442; 4274; 11441; 4279; 11440; 4284; 11439; 4289; 11438; 4294; 11437; 4299; 11436; 4304; 11435; 4309; 11434; 4314; 11433; 4319; 11432; 4324; 11431; 4329; 11430; 4334; 11429; 4339; 11428; 4344; 11427; 4349; 11426; 4354; 11425; 4359; 11424; 4364; 11423; 4369; 11422; 4374; 11421; 4379; 11420; 4384; 11419; 4389; 11418; 4394; 11417; 4399; 11416; 4404; 11415; 4409; 11414; 4414; 11413; 4419; 11412; 4424; 11411; 4429; 11410; 4434; 11409; 4439; 11408; 4444; 11407; 4449; 11406; 4454; 11405; 4459; 11404; 4464; 11403; 4469; 11402; 4474; 11401; 4479; 11400; 4484; 11399; 4489; 11398; 4494; 11397; 4499; 11396; 4504; 11395; 4509; 11394; 4514; 11393; 4519; 11392; 4524; 11391; 4529; 11390; 4534; 11389; 4539; 11388; 4544; 11387; 4549; 11386; 4554; 11385; 4559; 11384; 4564; 11383; 4569; 11382; 4574; 11381; 4579; 11380; 4584; 11379; 4589; 11378; 4594; 11377; 4599; 11376; 4604; 11375; 4609; 11374; 4614; 11373; 4619; 11372; 4624; 11371; 4629; 11370; 4634; 11369; 4639; 11368; 4644; 11367; 4649; 11366; 4654; 11365; 4659; 11364; 4664; 11363; 4669; 11362; 4674; 11361; 4679; 11360; 4684; 11359; 4689; 11358; 4694; 11357; 4699; 11356; 4704; 11355; 4709; 11354; 4714; 11353; 4719; 11352; 4724; 11351; 4729; 11350; 4734; 11349; 4739; 11348; 4744; 11347; 4749; 11346; 4754; 11345; 4759; 11344; 4764; 11343; 4769; 11342; 4774; 11341; 4779; 11340; 4784; 11339; 4789; 11338; 4794; 11337; 4799; 11336; 4804; 11335; 4809; 11334; 4814; 11333; 4819; 11332; 4824; 11331; 4829; 11330; 4834; 11329; 4839; 11328; 4844; 11327; 4849; 11326; 4854; 11325; 4859; 11324; 4864; 11323; 4869; 11322; 4874; 11321; 4879; 11320; 4884; 11319; 4889; 11318; 4894; 11317; 4899; 11316; 4904; 11315; 4909; 11314; 4914; 11313; 4919; 11312; 4924; 11311; 4929; 11310; 4934; 11309; 4939; 11308; 4944; 11307; 4949; 11306; 4954; 11305; 4959; 11304; 4964; 11303; 4969; 11302; 4974; 11301; 4979; 11300; 4984; 11299; 4989; 11298; 4994; 11297; 4999; 11296; 5004; 11295; 5009; 11294; 5014; 11293; 5019; 11292; 5024; 11291; 5029; 11290; 5034; 11289; 5039; 11288; 5044; 11287; 5049; 11286; 5054; 11285; 5059; 11284; 5064; 11283; 5069; 11282; 5074; 11281; 5079; 11280; 5084; 11279; 5089; 11278; 5094; 11277; 5099; 11276; 5104; 11275; 5109; 11274; 5114; 11273; 5119; 11272; 5124; 11271; 5129; 11270; 5134; 11269; 5139; 11268; 5144; 11267; 5149; 11266; 5154; 11265; 5159; 11264; 5164; 11263; 5169; 11262; 5174; 11261; 5179; 11260; 5184; 11259; 5189; 11258; 5194; 11257; 5199; 11256; 5204; 11255; 5209; 11254; 5214; 11253; 5219; 11252; 5224; 11251; 5229; 11250; 5234; 11249; 5239; 11248; 5244; 11247; 5249; 11246; 5254; 11245; 5259; 11244; 5264; 11243; 5269; 11242; 5274; 11241; 5279; 11240; 5284; 11239; 5289; 11238; 5294; 11237; 5299; 11236; 5304; 11235; 5309; 11234; 5314; 11233; 5319; 11232; 5324; 11231; 5329; 11230; 5334; 11229; 5339; 11228; 5344; 11227; 5349; 11226; 5354; 11225; 5359; 11224; 5364; 11223; 5369; 11222; 5374; 11221; 5379; 11220; 5384; 11219; 5389; 11218; 5394; 11217; 5399; 11216; 5404; 11215; 5409; 11214; 5414; 11213; 5419; 11212; 5424; 11211; 5429; 11210; 5434; 11209; 5439; 11208; 5444; 11207; 5449; 11206; 5454; 11205; 5459; 11204; 5464; 11203; 5469; 11202; 5474; 11201; 5479; 11200; 5484; 11199; 5489; 11198; 5494; 11197; 5499; 11196; 5504; 11195; 5509; 11194; 5514; 11193; 5519; 11192; 5524; 11191; 5529; 11190; 5534; 11189; 5539; 11188; 5544; 11187; 5549; 11186; 5554; 11185; 5559; 11184; 5564; 11183; 5569; 11182; 5574; 11181; 5579; 11180; 5584; 11179; 5589; 11178; 5594; 11177; 5599; 11176; 5604; 11175; 5609; 11174; 5614; 11173; 5619; 11172; 5624; 11171; 5629; 11170; 5634; 11169; 5639; 11168; 5644; 11167; 5649; 11166; 5654; 11165; 5659; 11164; 5664; 11163; 5669; 11162; 5674; 11161; 5679; 11160; 5684; 11159; 5689; 11158; 5694; 11157; 5699; 11156; 5704; 11155; 5709; 11154; 5714; 11153; 5719; 11152; 5724; 11151; 5729; 11150; 5734; 11149; 5739; 11148; 5744; 11147; 5749; 11146; 5754; 11145; 5759; 11144; 5764; 11143; 5769; 11142; 5774; 11141; 5779; 11140; 5784; 11139; 5789; 11138; 5794; 11137; 5799; 11136; 5804; 11135; 5809; 11134; 5814; 11133; 5819; 11132; 5824; 11131; 5829; 11130; 5834; 11129; 5839; 11128; 5844; 11127; 5849; 11126; 5854; 11125; 5859; 11124; 5864; 11123; 5869; 11122; 5874; 11121; 5879; 11120; 5884; 11119; 5889; 11118; 5894; 11117; 5899; 11116; 5904; 11115; 5909; 11114; 5914; 11113; 5919; 11112; 5924; 11111; 5929; 11110; 5934; 11109; 5939; 11108; 5944; 11107; 5949; 11106; 5954; 11105; 5959; 11104; 5964; 11103; 5969; 11102; 5974; 11101; 5979; 11100; 5984; 11099; 5989; 11098; 5994; 11097; 5999; 11096; 6004; 11095; 6009; 11094; 6014; 11093; 6019; 11092; 6024; 11091; 6029; 11090; 6034; 11089; 6039; 11088; 6044; 11087; 6049; 11086; 6054; 11085; 6059; 11084; 6064; 11083; 6069; 11082; 6074; 11081; 6079; 11080; 6084; 11079; 6089; 11078; 6094; 11077; 6099; 11076; 6104; 11075; 6109; 11074; 6114; 11073; 6119; 11072; 6124; 11071; 6129; 11070; 6134; 11069; 6139; 11068; 6144; 11067; 6149; 11066; 6154; 11065; 6159; 11064; 6164; 11063; 6169; 11062; 6174; 11061; 6179; 11060; 6184; 11059; 6189; 11058; 6194; 11057; 6199; 11056; 6204; 11055; 6209; 11054; 6214; 11053; 6219; 11052; 6224; 11051; 6229; 11050; 6234; 11049; 6239; 11048; 6244; 11047; 6249; 11046; 6254; 11045; 6259; 11044; 6264; 11043; 6269; 11042; 6274; 11041; 6279; 11040; 6284; 11039; 6289; 11038; 6294; 11037; 6299; 11036; 6304; 11035; 6309; 11034; 6314; 11033; 6319; 11032; 6324; 11031; 6329; 11030; 6334; 11029; 6339; 11028; 6344; 11027; 6349; 11026; 6354; 11025; 6359; 11024; 6364; 11023; 6369; 11022; 6374; 11021; 6379; 11020; 6384; 11019; 6389; 11018; 6394; 11017; 6399; 11016; 6404; 11015; 6409; 11014; 6414; 11013; 6419; 11012; 6424; 11011; 6429; 11010; 6434; 11009; 6439; 11008; 6444; 11007; 6449; 11006; 6454; 11005; 6459; 11004; 6464; 11003; 6469; 11002; 6474; 11001; 6479; 11000; 6484; 10999; 6489; 10998; 6494; 10997; 6499; 10996; 6504; 10995; 6509; 10994; 6514; 10993; 6519; 10992; 6524; 10991; 6529; 10990; 6534; 10989; 6539; 10988; 6544; 10987; 6549; 10986; 6554; 10985; 6559; 10984; 6564; 10983; 6569; 10982; 6574; 10981; 6579; 10980; 6584; 10979; 6589; 10978; 6594; 10977; 6599; 10976; 6604; 10975; 6609; 10974; 6614; 10973; 6619; 10972; 6624; 10971; 6629; 10970; 6634; 10969; 6639; 10968; 6644; 10967; 6649; 10966; 6654; 10965; 6659; 10964; 6664; 10963; 6669; 10962; 6674; 10961; 6679; 10960; 6684; 10959; 6689; 10958; 6694; 10957; 6699; 10956; 6704; 10955; 6709; 10954; 6714; 10953; 6719; 10952; 6724; 10951; 6729; 10950; 6734; 10949; 6739; 10948; 6744; 10947; 6749; 10946; 6754; 10945; 6759; 10944; 6764; 10943; 6769; 10942; 6774; 10941; 6779; 10940; 6784; 10939; 6789; 10938; 6794; 10937; 6799; 10936; 6804; 10935; 6809; 10934; 6814; 10933; 6819; 10932; 6824; 10931; 6829; 10930; 6834; 10929; 6839; 10928; 6844; 10927; 6849; 10926; 6854; 10925; 6859; 10924; 6864; 10923; 6869; 10922; 6874; 10921; 6879; 10920; 6884; 10919; 6889; 10918; 6894; 10917; 6899; 10916; 6904; 10915; 6909; 10914; 6914; 10913; 6919; 10912; 6924; 10911; 6929; 10910; 6934; 10909; 6939; 10908; 6944; 10907; 6949; 10906; 6954; 10905; 6959; 10904; 6964; 10903; 6969; 10902; 6974; 10901; 6979; 10900; 6984; 10899; 6989; 10898; 6994; 10897; 6999; 10896; 7004; 10895; 7009; 10894; 7014; 10893; 7019; 10892; 7024; 10891; 7029; 10890; 7034; 10889; 7039; 10888; 7044; 10887; 7049; 10886; 7054; 10885; 7059; 10884; 7064; 10883; 7069; 10882; 7074; 10881; 7079; 10880; 7084; 10879; 7089; 10878; 7094; 10877; 7099; 10876; 7104; 10875; 7109; 10874; 7114; 10873; 7119; 10872; 7124; 10871; 7129; 10870; 7134; 10869; 7139; 10868; 7144; 10867; 7149; 10866; 7154; 10865; 7159; 10864; 7164; 10863; 7169; 10862; 7174; 10861; 7179; 10860; 7184; 10859; 7189; 10858; 7194; 10857; 7199; 10856; 7204; 10855; 7209; 10854; 7214; 10853; 7219; 10852; 7224; 10851; 7229; 10850; 7234; 10849; 7239; 10848; 7244; 10847; 7249; 10846; 7254; 10845; 7259; 10844; 7264; 10843; 7269; 10842; 7274; 10841; 7279; 10840; 7284; 10839; 7289; 10838; 7294; 10837; 7299; 10836; 7304; 10835; 7309; 10834; 7314; 10833; 7319; 10832; 7324; 10831; 7329; 10830; 7334; 10829; 7339; 10828; 7344; 10827; 7349; 10826; 7354; 10825; 7359; 10824; 7364; 10823; 7369; 10822; 7374; 10821; 7379; 10820; 7384; 10819; 7389; 10818; 7394; 10817; 7399; 10816; 7404; 10815; 7409; 10814; 7414; 10813; 7419; 10812; 7424; 10811; 7429; 10810; 7434; 10809; 7439; 10808; 7444; 10807; 7449; 10806; 7454; 10805; 7459; 10804; 7464; 10803; 7469; 10802; 7474; 10801; 7479; 10800; 7484; 10799; 7489; 10798; 7494; 10797; 7499; 10796; 7504; 10795; 7509; 10794; 7514; 10793; 7519; 10792; 7524; 10791; 7529; 10790; 7534; 10789; 7539; 10788; 7544; 10787; 7549; 10786; 7554; 10785; 7559; 10784; 7564; 10783; 7569; 10782; 7574; 10781; 7579; 10780; 7584; 10779; 7589; 10778; 7594; 10777; 7599; 10776; 7604; 10775; 7609; 10774; 7614; 10773; 7619; 10772; 7624; 10771; 7629; 10770; 7634; 10769; 7639; 10768; 7644; 10767; 7649; 10766; 7654; 10765; 7659; 10764; 7664; 10763; 7669; 10762; 7674; 10761; 7679; 10760; 7684; 10759; 7689; 10758; 7694; 10757; 7699; 10756; 7704; 10755; 7709; 10754; 7714; 10753; 7719; 10752; 7724; 10751; 7729; 10750; 7734; 10749; 7739; 10748; 7744; 10747; 7749; 10746; 7754; 10745; 7759; 10744; 7764; 10743; 7769; 10742; 7774; 10741; 7779; 10740; 7784; 10739; 7789; 10738; 7794; 10737; 7799; 10736; 7804; 10735; 7809; 10734; 7814; 10733; 7819; 10732; 7824; 10731; 7829; 10730; 7834; 10729; 7839; 10728; 7844; 10727; 7849; 10726; 7854; 10725; 7859; 10724; 7864; 10723; 7869; 10722; 7874; 10721; 7879; 10720; 7884; 10719; 7889; 10718; 7894; 10717; 7899; 10716; 7904; 10715; 7909; 10714; 7914; 10713; 7919; 10712; 7924; 10711; 7929; 10710; 7934; 10709; 7939; 10708; 7944; 10707; 7949; 10706; 7954; 10705; 7959; 10704; 7964; 10703; 7969; 10702; 7974; 10701; 7979; 10700; 7984; 10699; 7989; 10698; 7994; 10697; 7999; 10696; 8004; 10695; 8009; 10694; 8014; 10693; 8019; 10692; 8024; 10691; 8029; 10690; 8034; 10689; 8039; 10688; 8044; 10687; 8049; 10686; 8054; 10685; 8059; 10684; 8064; 10683; 8069; 10682; 8074; 10681; 8079; 10680; 8084; 10679; 8089; 10678; 8094; 10677; 8099; 10676; 8104; 10675; 8109; 10674; 8114; 10673; 8119; 10672; 8124; 10671; 8129; 10670; 8134; 10669; 8139; 10668; 8144; 10667; 8149; 10666; 8154; 10665; 8159; 10664; 8164; 10663; 8169; 10662; 8174; 10661; 8179; 10660; 8184; 10659; 8189; 10658; 8194; 10657; 8199; 10656; 8204; 10655; 8209; 10654; 8214; 10653; 8219; 10652; 8224; 10651; 8229; 10650; 8234; 10649; 8239; 10648; 8244; 10647; 8249; 10646; 8254; 10645; 8259; 10644; 8264; 10643; 8269; 10642; 8274; 10641; 8279; 10640; 8284; 10639; 8289; 10638; 8294; 10637; 8299; 10636; 8304; 10635; 8309; 10634; 8314; 10633; 8319; 10632; 8324; 10631; 8329; 10630; 8334; 10629; 8339; 10628; 8344; 10627; 8349; 10626; 8354; 10625; 8359; 10624; 8364; 10623; 8369; 10622; 8374; 10621; 8379; 10620; 8384; 10619; 8389; 10618; 8394; 10617; 8399; 10616; 8404; 10615; 8409; 10614; 8414; 10613; 8419; 10612; 8424; 10611; 8429; 10610; 8434; 10609; 8439; 10608; 8444; 10607; 8449; 10606; 8454; 10605; 8459; 10604; 8464; 10603; 8469; 10602; 8474; 10601; 8479; 10600; 8484; 10599; 8489; 10598; 8494; 10597; 8499; 10596; 8504; 10595; 8509; 10594; 8514; 10593; 8519; 10592; 8524; 10591; 8529; 10590; 8534; 10589; 8539; 10588; 8544; 10587; 8549; 10586; 8554; 10585; 8559; 10584; 8564; 10583; 8569; 10582; 8574; 10581; 8579; 10580; 8584; 10579; 8589; 10578; 8594; 10577; 8599; 10576; 8604; 10575; 8609; 10574; 8614; 10573; 8619; 10572; 8624; 10571; 8629; 10570; 8634; 10569; 8639; 10568; 8644; 10567; 8649; 10566; 8654; 10565; 8659; 10564; 8664; 10563; 8669; 10562; 8674; 10561; 8679; 10560; 8684; 10559; 8689; 10558; 8694; 10557; 8699; 10556; 8704; 10555; 8709; 10554; 8714; 10553; 8719; 10552; 8724; 10551; 8729; 10550; 8734; 10549; 8739; 10548; 8744; 10547; 8749; 10546; 8754; 10545; 8759; 10544; 8764; 10543; 8769; 10542; 8774; 10541; 8779; 10540; 8784; 10539; 8789; 10538; 8794; 10537; 8799; 10536; 8804; 10535; 8809; 10534; 8814; 10533; 8819; 10532; 8824; 10531; 8829; 10530; 8834; 10529; 8839; 10528; 8844; 10527; 8849; 10526; 8854; 10525; 8859; 10524; 8864; 10523; 8869; 10522; 8874; 10521; 8879; 10520; 8884; 10519; 8889; 10518; 8894; 10517; 8899; 10516; 8904; 10515; 8909; 10514; 8914; 10513; 8919; 10512; 8924; 10511; 8929; 10510; 8934; 10509; 8939; 10508; 8944; 10507; 8949; 10506; 8954; 10505; 8959; 10504; 8964; 10503; 8969; 10502; 8974; 10501; 8979; 10500; 8984; 10499; 8989; 10498; 8994; 10497; 8999; 10496; 9004; 10495; 9009; 10494; 9014; 10493; 9019; 10492; 9024; 10491; 9029; 10490; 9034; 10489; 9039; 10488; 9044; 10487; 9049; 10486; 9054; 10485; 9059; 10484; 9064; 10483; 9069; 10482; 9074; 10481; 9079; 10480; 9084; 10479; 9089; 10478; 9094; 10477; 9099; 10476; 9104; 10475; 9109; 10474; 9114; 10473; 9119; 10472; 9124; 10471; 9129; 10470; 9134; 10469; 9139; 10468; 9144; 10467; 9149; 10466; 9154; 10465; 9159; 10464; 9164; 10463; 9169; 10462; 9174; 10461; 9179; 10460; 9184; 10459; 9189; 10458; 9194; 10457; 9199; 10456; 9204; 10455; 9209; 10454; 9214; 10453; 9219; 10452; 9224; 10451; 9229; 10450; 9234; 10449; 9239; 10448; 9244; 10447; 9249; 10446; 9254; 10445; 9259; 10444; 9264; 10443; 9269; 10442; 9274; 10441; 9279; 10440; 9284; 10439; 9289; 10438; 9294; 10437; 9299; 10436; 9304; 10435; 9309; 10434; 9314; 10433; 9319; 10432; 9324; 10431; 9329; 10430; 9334; 10429; 9339; 10428; 9344; 10427; 9349; 10426; 9354; 10425; 9359; 10424; 9364; 10423; 9369; 10422; 9374; 10421; 9379; 10420; 9384; 10419; 9389; 10418; 9394; 10417; 9399; 10416; 9404; 10415; 9409; 10414; 9414; 10413; 9419; 10412; 9424; 10411; 9429; 10410; 9434; 10409; 9439; 10408; 9444; 10407; 9449; 10406; 9454; 10405; 9459; 10404; 9464; 10403; 9469; 10402; 9474; 10401; 9479; 10400; 9484; 10399; 9489; 10398; 9494; 10397; 9499; 10396; 9504; 10395; 9509; 10394; 9514; 10393; 9519; 10392; 9524; 10391; 9529; 10390; 9534; 10389; 9539; 10388; 9544; 10387; 9549; 10386; 9554; 10385; 9559; 10384; 9564; 10383; 9569; 10382; 9574; 10381; 9579; 10380; 9584; 10379; 9589; 10378; 9594; 10377; 9599; 10376; 9604; 10375; 9609; 10374; 9614; 10373; 9619; 10372; 9624; 10371; 9629; 10370; 9634; 10369; 9639; 10368; 9644; 10367; 9649; 10366; 9654; 10365; 9659; 10364; 9664; 10363; 9669; 10362; 9674; 10361; 9679; 10360; 9684; 10359; 9689; 10358; 9694; 10357; 9699; 10356; 9704; 10355; 9709; 10354; 9714; 10353; 9719; 10352; 9724; 10351; 9729; 10350; 9734; 10349; 9739; 10348; 9744; 10347; 9749; 10346; 9754; 10345; 9759; 10344; 9764; 10343; 9769; 10342; 9774; 10341; 9779; 10340; 9784; 10339; 9789; 10338; 9794; 10337; 9799; 10336; 9804; 10335; 9809; 10334; 9814; 10333; 9819; 10332; 9824; 10331; 9829; 10330; 9834; 10329; 9839; 10328; 9844; 10327; 9849; 10326; 9854; 10325; 9859; 10324; 9864; 10323; 9869; 10322; 9874; 10321; 9879; 10320; 9884; 10319; 9889; 10318; 9894; 10317; 9899; 10316; 9904; 10315; 9909; 10314; 9914; 10313; 9919; 10312; 9924; 10311; 9929; 10310; 9934; 10309; 9939; 10308; 9944; 10307; 9949; 10306; 9954; 10305; 9959; 10304; 9964; 10303; 9969; 10302; 9974; 10301; 9979; 10300; 9984; 10299; 9989; 10298; 9994; 10297; 9999; 10296; 10004; 10295; 10009; 10294; 10014; 10293; 10019; 10292; 10024; 10291; 10029; 10290; 10034; 10289; 10039; 10288; 10044; 10287; 10049; 10286; 10054; 10285; 10059; 10284; 10064; 10283; 10069; 10282; 10074; 10281; 10079; 10280; 10084; 10279; 10089; 10278; 10094; 10277; 10099; 10276; 10104; 10275; 10109; 10274; 10114; 10273; 10119; 10272; 10124; 10271; 10129; 10270; 10134; 10269; 10139; 10268; 10144; 10267; 10149; 10266; 10154; 10265; 10159; 10264; 10164; 10263; 10169; 10262; 10174; 10261; 10179; 10260; 10184; 10259; 10189; 10258; 10194; 10257; 10199; 10256; 10204; 10255; 10209; 10254; 10214; 10253; 10219; 10252; 10224; 10251; 10229; 10250; 10234; 10249; 10239; 10248; 10244; 10247; // Edge definitions. 2 -> 9 [label=true]; 2 -> 12294 [label=false]; 9 -> 14 [label=true]; 9 -> 12293 [label=false]; 14 -> 19 [label=true]; 14 -> 12292 [label=false]; 12293 -> 12294; 19 -> 24 [label=true]; 19 -> 12291 [label=false]; 12292 -> 12293; 24 -> 29 [label=true]; 24 -> 12290 [label=false]; 12291 -> 12292; 29 -> 34 [label=true]; 29 -> 12289 [label=false]; 12290 -> 12291; 34 -> 39 [label=true]; 34 -> 12288 [label=false]; 12289 -> 12290; 39 -> 44 [label=true]; 39 -> 12287 [label=false]; 12288 -> 12289; 44 -> 49 [label=true]; 44 -> 12286 [label=false]; 12287 -> 12288; 49 -> 54 [label=true]; 49 -> 12285 [label=false]; 12286 -> 12287; 54 -> 59 [label=true]; 54 -> 12284 [label=false]; 12285 -> 12286; 59 -> 64 [label=true]; 59 -> 12283 [label=false]; 12284 -> 12285; 64 -> 69 [label=true]; 64 -> 12282 [label=false]; 12283 -> 12284; 69 -> 74 [label=true]; 69 -> 12281 [label=false]; 12282 -> 12283; 74 -> 79 [label=true]; 74 -> 12280 [label=false]; 12281 -> 12282; 79 -> 84 [label=true]; 79 -> 12279 [label=false]; 12280 -> 12281; 84 -> 89 [label=true]; 84 -> 12278 [label=false]; 12279 -> 12280; 89 -> 94 [label=true]; 89 -> 12277 [label=false]; 12278 -> 12279; 94 -> 99 [label=true]; 94 -> 12276 [label=false]; 12277 -> 12278; 99 -> 104 [label=true]; 99 -> 12275 [label=false]; 12276 -> 12277; 104 -> 109 [label=true]; 104 -> 12274 [label=false]; 12275 -> 12276; 109 -> 114 [label=true]; 109 -> 12273 [label=false]; 12274 -> 12275; 114 -> 119 [label=true]; 114 -> 12272 [label=false]; 12273 -> 12274; 119 -> 124 [label=true]; 119 -> 12271 [label=false]; 12272 -> 12273; 124 -> 129 [label=true]; 124 -> 12270 [label=false]; 12271 -> 12272; 129 -> 134 [label=true]; 129 -> 12269 [label=false]; 12270 -> 12271; 134 -> 139 [label=true]; 134 -> 12268 [label=false]; 12269 -> 12270; 139 -> 144 [label=true]; 139 -> 12267 [label=false]; 12268 -> 12269; 144 -> 149 [label=true]; 144 -> 12266 [label=false]; 12267 -> 12268; 149 -> 154 [label=true]; 149 -> 12265 [label=false]; 12266 -> 12267; 154 -> 159 [label=true]; 154 -> 12264 [label=false]; 12265 -> 12266; 159 -> 164 [label=true]; 159 -> 12263 [label=false]; 12264 -> 12265; 164 -> 169 [label=true]; 164 -> 12262 [label=false]; 12263 -> 12264; 169 -> 174 [label=true]; 169 -> 12261 [label=false]; 12262 -> 12263; 174 -> 179 [label=true]; 174 -> 12260 [label=false]; 12261 -> 12262; 179 -> 184 [label=true]; 179 -> 12259 [label=false]; 12260 -> 12261; 184 -> 189 [label=true]; 184 -> 12258 [label=false]; 12259 -> 12260; 189 -> 194 [label=true]; 189 -> 12257 [label=false]; 12258 -> 12259; 194 -> 199 [label=true]; 194 -> 12256 [label=false]; 12257 -> 12258; 199 -> 204 [label=true]; 199 -> 12255 [label=false]; 12256 -> 12257; 204 -> 209 [label=true]; 204 -> 12254 [label=false]; 12255 -> 12256; 209 -> 214 [label=true]; 209 -> 12253 [label=false]; 12254 -> 12255; 214 -> 219 [label=true]; 214 -> 12252 [label=false]; 12253 -> 12254; 219 -> 224 [label=true]; 219 -> 12251 [label=false]; 12252 -> 12253; 224 -> 229 [label=true]; 224 -> 12250 [label=false]; 12251 -> 12252; 229 -> 234 [label=true]; 229 -> 12249 [label=false]; 12250 -> 12251; 234 -> 239 [label=true]; 234 -> 12248 [label=false]; 12249 -> 12250; 239 -> 244 [label=true]; 239 -> 12247 [label=false]; 12248 -> 12249; 244 -> 249 [label=true]; 244 -> 12246 [label=false]; 12247 -> 12248; 249 -> 254 [label=true]; 249 -> 12245 [label=false]; 12246 -> 12247; 254 -> 259 [label=true]; 254 -> 12244 [label=false]; 12245 -> 12246; 259 -> 264 [label=true]; 259 -> 12243 [label=false]; 12244 -> 12245; 264 -> 269 [label=true]; 264 -> 12242 [label=false]; 12243 -> 12244; 269 -> 274 [label=true]; 269 -> 12241 [label=false]; 12242 -> 12243; 274 -> 279 [label=true]; 274 -> 12240 [label=false]; 12241 -> 12242; 279 -> 284 [label=true]; 279 -> 12239 [label=false]; 12240 -> 12241; 284 -> 289 [label=true]; 284 -> 12238 [label=false]; 12239 -> 12240; 289 -> 294 [label=true]; 289 -> 12237 [label=false]; 12238 -> 12239; 294 -> 299 [label=true]; 294 -> 12236 [label=false]; 12237 -> 12238; 299 -> 304 [label=true]; 299 -> 12235 [label=false]; 12236 -> 12237; 304 -> 309 [label=true]; 304 -> 12234 [label=false]; 12235 -> 12236; 309 -> 314 [label=true]; 309 -> 12233 [label=false]; 12234 -> 12235; 314 -> 319 [label=true]; 314 -> 12232 [label=false]; 12233 -> 12234; 319 -> 324 [label=true]; 319 -> 12231 [label=false]; 12232 -> 12233; 324 -> 329 [label=true]; 324 -> 12230 [label=false]; 12231 -> 12232; 329 -> 334 [label=true]; 329 -> 12229 [label=false]; 12230 -> 12231; 334 -> 339 [label=true]; 334 -> 12228 [label=false]; 12229 -> 12230; 339 -> 344 [label=true]; 339 -> 12227 [label=false]; 12228 -> 12229; 344 -> 349 [label=true]; 344 -> 12226 [label=false]; 12227 -> 12228; 349 -> 354 [label=true]; 349 -> 12225 [label=false]; 12226 -> 12227; 354 -> 359 [label=true]; 354 -> 12224 [label=false]; 12225 -> 12226; 359 -> 364 [label=true]; 359 -> 12223 [label=false]; 12224 -> 12225; 364 -> 369 [label=true]; 364 -> 12222 [label=false]; 12223 -> 12224; 369 -> 374 [label=true]; 369 -> 12221 [label=false]; 12222 -> 12223; 374 -> 379 [label=true]; 374 -> 12220 [label=false]; 12221 -> 12222; 379 -> 384 [label=true]; 379 -> 12219 [label=false]; 12220 -> 12221; 384 -> 389 [label=true]; 384 -> 12218 [label=false]; 12219 -> 12220; 389 -> 394 [label=true]; 389 -> 12217 [label=false]; 12218 -> 12219; 394 -> 399 [label=true]; 394 -> 12216 [label=false]; 12217 -> 12218; 399 -> 404 [label=true]; 399 -> 12215 [label=false]; 12216 -> 12217; 404 -> 409 [label=true]; 404 -> 12214 [label=false]; 12215 -> 12216; 409 -> 414 [label=true]; 409 -> 12213 [label=false]; 12214 -> 12215; 414 -> 419 [label=true]; 414 -> 12212 [label=false]; 12213 -> 12214; 419 -> 424 [label=true]; 419 -> 12211 [label=false]; 12212 -> 12213; 424 -> 429 [label=true]; 424 -> 12210 [label=false]; 12211 -> 12212; 429 -> 434 [label=true]; 429 -> 12209 [label=false]; 12210 -> 12211; 434 -> 439 [label=true]; 434 -> 12208 [label=false]; 12209 -> 12210; 439 -> 444 [label=true]; 439 -> 12207 [label=false]; 12208 -> 12209; 444 -> 449 [label=true]; 444 -> 12206 [label=false]; 12207 -> 12208; 449 -> 454 [label=true]; 449 -> 12205 [label=false]; 12206 -> 12207; 454 -> 459 [label=true]; 454 -> 12204 [label=false]; 12205 -> 12206; 459 -> 464 [label=true]; 459 -> 12203 [label=false]; 12204 -> 12205; 464 -> 469 [label=true]; 464 -> 12202 [label=false]; 12203 -> 12204; 469 -> 474 [label=true]; 469 -> 12201 [label=false]; 12202 -> 12203; 474 -> 479 [label=true]; 474 -> 12200 [label=false]; 12201 -> 12202; 479 -> 484 [label=true]; 479 -> 12199 [label=false]; 12200 -> 12201; 484 -> 489 [label=true]; 484 -> 12198 [label=false]; 12199 -> 12200; 489 -> 494 [label=true]; 489 -> 12197 [label=false]; 12198 -> 12199; 494 -> 499 [label=true]; 494 -> 12196 [label=false]; 12197 -> 12198; 499 -> 504 [label=true]; 499 -> 12195 [label=false]; 12196 -> 12197; 504 -> 509 [label=true]; 504 -> 12194 [label=false]; 12195 -> 12196; 509 -> 514 [label=true]; 509 -> 12193 [label=false]; 12194 -> 12195; 514 -> 519 [label=true]; 514 -> 12192 [label=false]; 12193 -> 12194; 519 -> 524 [label=true]; 519 -> 12191 [label=false]; 12192 -> 12193; 524 -> 529 [label=true]; 524 -> 12190 [label=false]; 12191 -> 12192; 529 -> 534 [label=true]; 529 -> 12189 [label=false]; 12190 -> 12191; 534 -> 539 [label=true]; 534 -> 12188 [label=false]; 12189 -> 12190; 539 -> 544 [label=true]; 539 -> 12187 [label=false]; 12188 -> 12189; 544 -> 549 [label=true]; 544 -> 12186 [label=false]; 12187 -> 12188; 549 -> 554 [label=true]; 549 -> 12185 [label=false]; 12186 -> 12187; 554 -> 559 [label=true]; 554 -> 12184 [label=false]; 12185 -> 12186; 559 -> 564 [label=true]; 559 -> 12183 [label=false]; 12184 -> 12185; 564 -> 569 [label=true]; 564 -> 12182 [label=false]; 12183 -> 12184; 569 -> 574 [label=true]; 569 -> 12181 [label=false]; 12182 -> 12183; 574 -> 579 [label=true]; 574 -> 12180 [label=false]; 12181 -> 12182; 579 -> 584 [label=true]; 579 -> 12179 [label=false]; 12180 -> 12181; 584 -> 589 [label=true]; 584 -> 12178 [label=false]; 12179 -> 12180; 589 -> 594 [label=true]; 589 -> 12177 [label=false]; 12178 -> 12179; 594 -> 599 [label=true]; 594 -> 12176 [label=false]; 12177 -> 12178; 599 -> 604 [label=true]; 599 -> 12175 [label=false]; 12176 -> 12177; 604 -> 609 [label=true]; 604 -> 12174 [label=false]; 12175 -> 12176; 609 -> 614 [label=true]; 609 -> 12173 [label=false]; 12174 -> 12175; 614 -> 619 [label=true]; 614 -> 12172 [label=false]; 12173 -> 12174; 619 -> 624 [label=true]; 619 -> 12171 [label=false]; 12172 -> 12173; 624 -> 629 [label=true]; 624 -> 12170 [label=false]; 12171 -> 12172; 629 -> 634 [label=true]; 629 -> 12169 [label=false]; 12170 -> 12171; 634 -> 639 [label=true]; 634 -> 12168 [label=false]; 12169 -> 12170; 639 -> 644 [label=true]; 639 -> 12167 [label=false]; 12168 -> 12169; 644 -> 649 [label=true]; 644 -> 12166 [label=false]; 12167 -> 12168; 649 -> 654 [label=true]; 649 -> 12165 [label=false]; 12166 -> 12167; 654 -> 659 [label=true]; 654 -> 12164 [label=false]; 12165 -> 12166; 659 -> 664 [label=true]; 659 -> 12163 [label=false]; 12164 -> 12165; 664 -> 669 [label=true]; 664 -> 12162 [label=false]; 12163 -> 12164; 669 -> 674 [label=true]; 669 -> 12161 [label=false]; 12162 -> 12163; 674 -> 679 [label=true]; 674 -> 12160 [label=false]; 12161 -> 12162; 679 -> 684 [label=true]; 679 -> 12159 [label=false]; 12160 -> 12161; 684 -> 689 [label=true]; 684 -> 12158 [label=false]; 12159 -> 12160; 689 -> 694 [label=true]; 689 -> 12157 [label=false]; 12158 -> 12159; 694 -> 699 [label=true]; 694 -> 12156 [label=false]; 12157 -> 12158; 699 -> 704 [label=true]; 699 -> 12155 [label=false]; 12156 -> 12157; 704 -> 709 [label=true]; 704 -> 12154 [label=false]; 12155 -> 12156; 709 -> 714 [label=true]; 709 -> 12153 [label=false]; 12154 -> 12155; 714 -> 719 [label=true]; 714 -> 12152 [label=false]; 12153 -> 12154; 719 -> 724 [label=true]; 719 -> 12151 [label=false]; 12152 -> 12153; 724 -> 729 [label=true]; 724 -> 12150 [label=false]; 12151 -> 12152; 729 -> 734 [label=true]; 729 -> 12149 [label=false]; 12150 -> 12151; 734 -> 739 [label=true]; 734 -> 12148 [label=false]; 12149 -> 12150; 739 -> 744 [label=true]; 739 -> 12147 [label=false]; 12148 -> 12149; 744 -> 749 [label=true]; 744 -> 12146 [label=false]; 12147 -> 12148; 749 -> 754 [label=true]; 749 -> 12145 [label=false]; 12146 -> 12147; 754 -> 759 [label=true]; 754 -> 12144 [label=false]; 12145 -> 12146; 759 -> 764 [label=true]; 759 -> 12143 [label=false]; 12144 -> 12145; 764 -> 769 [label=true]; 764 -> 12142 [label=false]; 12143 -> 12144; 769 -> 774 [label=true]; 769 -> 12141 [label=false]; 12142 -> 12143; 774 -> 779 [label=true]; 774 -> 12140 [label=false]; 12141 -> 12142; 779 -> 784 [label=true]; 779 -> 12139 [label=false]; 12140 -> 12141; 784 -> 789 [label=true]; 784 -> 12138 [label=false]; 12139 -> 12140; 789 -> 794 [label=true]; 789 -> 12137 [label=false]; 12138 -> 12139; 794 -> 799 [label=true]; 794 -> 12136 [label=false]; 12137 -> 12138; 799 -> 804 [label=true]; 799 -> 12135 [label=false]; 12136 -> 12137; 804 -> 809 [label=true]; 804 -> 12134 [label=false]; 12135 -> 12136; 809 -> 814 [label=true]; 809 -> 12133 [label=false]; 12134 -> 12135; 814 -> 819 [label=true]; 814 -> 12132 [label=false]; 12133 -> 12134; 819 -> 824 [label=true]; 819 -> 12131 [label=false]; 12132 -> 12133; 824 -> 829 [label=true]; 824 -> 12130 [label=false]; 12131 -> 12132; 829 -> 834 [label=true]; 829 -> 12129 [label=false]; 12130 -> 12131; 834 -> 839 [label=true]; 834 -> 12128 [label=false]; 12129 -> 12130; 839 -> 844 [label=true]; 839 -> 12127 [label=false]; 12128 -> 12129; 844 -> 849 [label=true]; 844 -> 12126 [label=false]; 12127 -> 12128; 849 -> 854 [label=true]; 849 -> 12125 [label=false]; 12126 -> 12127; 854 -> 859 [label=true]; 854 -> 12124 [label=false]; 12125 -> 12126; 859 -> 864 [label=true]; 859 -> 12123 [label=false]; 12124 -> 12125; 864 -> 869 [label=true]; 864 -> 12122 [label=false]; 12123 -> 12124; 869 -> 874 [label=true]; 869 -> 12121 [label=false]; 12122 -> 12123; 874 -> 879 [label=true]; 874 -> 12120 [label=false]; 12121 -> 12122; 879 -> 884 [label=true]; 879 -> 12119 [label=false]; 12120 -> 12121; 884 -> 889 [label=true]; 884 -> 12118 [label=false]; 12119 -> 12120; 889 -> 894 [label=true]; 889 -> 12117 [label=false]; 12118 -> 12119; 894 -> 899 [label=true]; 894 -> 12116 [label=false]; 12117 -> 12118; 899 -> 904 [label=true]; 899 -> 12115 [label=false]; 12116 -> 12117; 904 -> 909 [label=true]; 904 -> 12114 [label=false]; 12115 -> 12116; 909 -> 914 [label=true]; 909 -> 12113 [label=false]; 12114 -> 12115; 914 -> 919 [label=true]; 914 -> 12112 [label=false]; 12113 -> 12114; 919 -> 924 [label=true]; 919 -> 12111 [label=false]; 12112 -> 12113; 924 -> 929 [label=true]; 924 -> 12110 [label=false]; 12111 -> 12112; 929 -> 934 [label=true]; 929 -> 12109 [label=false]; 12110 -> 12111; 934 -> 939 [label=true]; 934 -> 12108 [label=false]; 12109 -> 12110; 939 -> 944 [label=true]; 939 -> 12107 [label=false]; 12108 -> 12109; 944 -> 949 [label=true]; 944 -> 12106 [label=false]; 12107 -> 12108; 949 -> 954 [label=true]; 949 -> 12105 [label=false]; 12106 -> 12107; 954 -> 959 [label=true]; 954 -> 12104 [label=false]; 12105 -> 12106; 959 -> 964 [label=true]; 959 -> 12103 [label=false]; 12104 -> 12105; 964 -> 969 [label=true]; 964 -> 12102 [label=false]; 12103 -> 12104; 969 -> 974 [label=true]; 969 -> 12101 [label=false]; 12102 -> 12103; 974 -> 979 [label=true]; 974 -> 12100 [label=false]; 12101 -> 12102; 979 -> 984 [label=true]; 979 -> 12099 [label=false]; 12100 -> 12101; 984 -> 989 [label=true]; 984 -> 12098 [label=false]; 12099 -> 12100; 989 -> 994 [label=true]; 989 -> 12097 [label=false]; 12098 -> 12099; 994 -> 999 [label=true]; 994 -> 12096 [label=false]; 12097 -> 12098; 999 -> 1004 [label=true]; 999 -> 12095 [label=false]; 12096 -> 12097; 1004 -> 1009 [label=true]; 1004 -> 12094 [label=false]; 12095 -> 12096; 1009 -> 1014 [label=true]; 1009 -> 12093 [label=false]; 12094 -> 12095; 1014 -> 1019 [label=true]; 1014 -> 12092 [label=false]; 12093 -> 12094; 1019 -> 1024 [label=true]; 1019 -> 12091 [label=false]; 12092 -> 12093; 1024 -> 1029 [label=true]; 1024 -> 12090 [label=false]; 12091 -> 12092; 1029 -> 1034 [label=true]; 1029 -> 12089 [label=false]; 12090 -> 12091; 1034 -> 1039 [label=true]; 1034 -> 12088 [label=false]; 12089 -> 12090; 1039 -> 1044 [label=true]; 1039 -> 12087 [label=false]; 12088 -> 12089; 1044 -> 1049 [label=true]; 1044 -> 12086 [label=false]; 12087 -> 12088; 1049 -> 1054 [label=true]; 1049 -> 12085 [label=false]; 12086 -> 12087; 1054 -> 1059 [label=true]; 1054 -> 12084 [label=false]; 12085 -> 12086; 1059 -> 1064 [label=true]; 1059 -> 12083 [label=false]; 12084 -> 12085; 1064 -> 1069 [label=true]; 1064 -> 12082 [label=false]; 12083 -> 12084; 1069 -> 1074 [label=true]; 1069 -> 12081 [label=false]; 12082 -> 12083; 1074 -> 1079 [label=true]; 1074 -> 12080 [label=false]; 12081 -> 12082; 1079 -> 1084 [label=true]; 1079 -> 12079 [label=false]; 12080 -> 12081; 1084 -> 1089 [label=true]; 1084 -> 12078 [label=false]; 12079 -> 12080; 1089 -> 1094 [label=true]; 1089 -> 12077 [label=false]; 12078 -> 12079; 1094 -> 1099 [label=true]; 1094 -> 12076 [label=false]; 12077 -> 12078; 1099 -> 1104 [label=true]; 1099 -> 12075 [label=false]; 12076 -> 12077; 1104 -> 1109 [label=true]; 1104 -> 12074 [label=false]; 12075 -> 12076; 1109 -> 1114 [label=true]; 1109 -> 12073 [label=false]; 12074 -> 12075; 1114 -> 1119 [label=true]; 1114 -> 12072 [label=false]; 12073 -> 12074; 1119 -> 1124 [label=true]; 1119 -> 12071 [label=false]; 12072 -> 12073; 1124 -> 1129 [label=true]; 1124 -> 12070 [label=false]; 12071 -> 12072; 1129 -> 1134 [label=true]; 1129 -> 12069 [label=false]; 12070 -> 12071; 1134 -> 1139 [label=true]; 1134 -> 12068 [label=false]; 12069 -> 12070; 1139 -> 1144 [label=true]; 1139 -> 12067 [label=false]; 12068 -> 12069; 1144 -> 1149 [label=true]; 1144 -> 12066 [label=false]; 12067 -> 12068; 1149 -> 1154 [label=true]; 1149 -> 12065 [label=false]; 12066 -> 12067; 1154 -> 1159 [label=true]; 1154 -> 12064 [label=false]; 12065 -> 12066; 1159 -> 1164 [label=true]; 1159 -> 12063 [label=false]; 12064 -> 12065; 1164 -> 1169 [label=true]; 1164 -> 12062 [label=false]; 12063 -> 12064; 1169 -> 1174 [label=true]; 1169 -> 12061 [label=false]; 12062 -> 12063; 1174 -> 1179 [label=true]; 1174 -> 12060 [label=false]; 12061 -> 12062; 1179 -> 1184 [label=true]; 1179 -> 12059 [label=false]; 12060 -> 12061; 1184 -> 1189 [label=true]; 1184 -> 12058 [label=false]; 12059 -> 12060; 1189 -> 1194 [label=true]; 1189 -> 12057 [label=false]; 12058 -> 12059; 1194 -> 1199 [label=true]; 1194 -> 12056 [label=false]; 12057 -> 12058; 1199 -> 1204 [label=true]; 1199 -> 12055 [label=false]; 12056 -> 12057; 1204 -> 1209 [label=true]; 1204 -> 12054 [label=false]; 12055 -> 12056; 1209 -> 1214 [label=true]; 1209 -> 12053 [label=false]; 12054 -> 12055; 1214 -> 1219 [label=true]; 1214 -> 12052 [label=false]; 12053 -> 12054; 1219 -> 1224 [label=true]; 1219 -> 12051 [label=false]; 12052 -> 12053; 1224 -> 1229 [label=true]; 1224 -> 12050 [label=false]; 12051 -> 12052; 1229 -> 1234 [label=true]; 1229 -> 12049 [label=false]; 12050 -> 12051; 1234 -> 1239 [label=true]; 1234 -> 12048 [label=false]; 12049 -> 12050; 1239 -> 1244 [label=true]; 1239 -> 12047 [label=false]; 12048 -> 12049; 1244 -> 1249 [label=true]; 1244 -> 12046 [label=false]; 12047 -> 12048; 1249 -> 1254 [label=true]; 1249 -> 12045 [label=false]; 12046 -> 12047; 1254 -> 1259 [label=true]; 1254 -> 12044 [label=false]; 12045 -> 12046; 1259 -> 1264 [label=true]; 1259 -> 12043 [label=false]; 12044 -> 12045; 1264 -> 1269 [label=true]; 1264 -> 12042 [label=false]; 12043 -> 12044; 1269 -> 1274 [label=true]; 1269 -> 12041 [label=false]; 12042 -> 12043; 1274 -> 1279 [label=true]; 1274 -> 12040 [label=false]; 12041 -> 12042; 1279 -> 1284 [label=true]; 1279 -> 12039 [label=false]; 12040 -> 12041; 1284 -> 1289 [label=true]; 1284 -> 12038 [label=false]; 12039 -> 12040; 1289 -> 1294 [label=true]; 1289 -> 12037 [label=false]; 12038 -> 12039; 1294 -> 1299 [label=true]; 1294 -> 12036 [label=false]; 12037 -> 12038; 1299 -> 1304 [label=true]; 1299 -> 12035 [label=false]; 12036 -> 12037; 1304 -> 1309 [label=true]; 1304 -> 12034 [label=false]; 12035 -> 12036; 1309 -> 1314 [label=true]; 1309 -> 12033 [label=false]; 12034 -> 12035; 1314 -> 1319 [label=true]; 1314 -> 12032 [label=false]; 12033 -> 12034; 1319 -> 1324 [label=true]; 1319 -> 12031 [label=false]; 12032 -> 12033; 1324 -> 1329 [label=true]; 1324 -> 12030 [label=false]; 12031 -> 12032; 1329 -> 1334 [label=true]; 1329 -> 12029 [label=false]; 12030 -> 12031; 1334 -> 1339 [label=true]; 1334 -> 12028 [label=false]; 12029 -> 12030; 1339 -> 1344 [label=true]; 1339 -> 12027 [label=false]; 12028 -> 12029; 1344 -> 1349 [label=true]; 1344 -> 12026 [label=false]; 12027 -> 12028; 1349 -> 1354 [label=true]; 1349 -> 12025 [label=false]; 12026 -> 12027; 1354 -> 1359 [label=true]; 1354 -> 12024 [label=false]; 12025 -> 12026; 1359 -> 1364 [label=true]; 1359 -> 12023 [label=false]; 12024 -> 12025; 1364 -> 1369 [label=true]; 1364 -> 12022 [label=false]; 12023 -> 12024; 1369 -> 1374 [label=true]; 1369 -> 12021 [label=false]; 12022 -> 12023; 1374 -> 1379 [label=true]; 1374 -> 12020 [label=false]; 12021 -> 12022; 1379 -> 1384 [label=true]; 1379 -> 12019 [label=false]; 12020 -> 12021; 1384 -> 1389 [label=true]; 1384 -> 12018 [label=false]; 12019 -> 12020; 1389 -> 1394 [label=true]; 1389 -> 12017 [label=false]; 12018 -> 12019; 1394 -> 1399 [label=true]; 1394 -> 12016 [label=false]; 12017 -> 12018; 1399 -> 1404 [label=true]; 1399 -> 12015 [label=false]; 12016 -> 12017; 1404 -> 1409 [label=true]; 1404 -> 12014 [label=false]; 12015 -> 12016; 1409 -> 1414 [label=true]; 1409 -> 12013 [label=false]; 12014 -> 12015; 1414 -> 1419 [label=true]; 1414 -> 12012 [label=false]; 12013 -> 12014; 1419 -> 1424 [label=true]; 1419 -> 12011 [label=false]; 12012 -> 12013; 1424 -> 1429 [label=true]; 1424 -> 12010 [label=false]; 12011 -> 12012; 1429 -> 1434 [label=true]; 1429 -> 12009 [label=false]; 12010 -> 12011; 1434 -> 1439 [label=true]; 1434 -> 12008 [label=false]; 12009 -> 12010; 1439 -> 1444 [label=true]; 1439 -> 12007 [label=false]; 12008 -> 12009; 1444 -> 1449 [label=true]; 1444 -> 12006 [label=false]; 12007 -> 12008; 1449 -> 1454 [label=true]; 1449 -> 12005 [label=false]; 12006 -> 12007; 1454 -> 1459 [label=true]; 1454 -> 12004 [label=false]; 12005 -> 12006; 1459 -> 1464 [label=true]; 1459 -> 12003 [label=false]; 12004 -> 12005; 1464 -> 1469 [label=true]; 1464 -> 12002 [label=false]; 12003 -> 12004; 1469 -> 1474 [label=true]; 1469 -> 12001 [label=false]; 12002 -> 12003; 1474 -> 1479 [label=true]; 1474 -> 12000 [label=false]; 12001 -> 12002; 1479 -> 1484 [label=true]; 1479 -> 11999 [label=false]; 12000 -> 12001; 1484 -> 1489 [label=true]; 1484 -> 11998 [label=false]; 11999 -> 12000; 1489 -> 1494 [label=true]; 1489 -> 11997 [label=false]; 11998 -> 11999; 1494 -> 1499 [label=true]; 1494 -> 11996 [label=false]; 11997 -> 11998; 1499 -> 1504 [label=true]; 1499 -> 11995 [label=false]; 11996 -> 11997; 1504 -> 1509 [label=true]; 1504 -> 11994 [label=false]; 11995 -> 11996; 1509 -> 1514 [label=true]; 1509 -> 11993 [label=false]; 11994 -> 11995; 1514 -> 1519 [label=true]; 1514 -> 11992 [label=false]; 11993 -> 11994; 1519 -> 1524 [label=true]; 1519 -> 11991 [label=false]; 11992 -> 11993; 1524 -> 1529 [label=true]; 1524 -> 11990 [label=false]; 11991 -> 11992; 1529 -> 1534 [label=true]; 1529 -> 11989 [label=false]; 11990 -> 11991; 1534 -> 1539 [label=true]; 1534 -> 11988 [label=false]; 11989 -> 11990; 1539 -> 1544 [label=true]; 1539 -> 11987 [label=false]; 11988 -> 11989; 1544 -> 1549 [label=true]; 1544 -> 11986 [label=false]; 11987 -> 11988; 1549 -> 1554 [label=true]; 1549 -> 11985 [label=false]; 11986 -> 11987; 1554 -> 1559 [label=true]; 1554 -> 11984 [label=false]; 11985 -> 11986; 1559 -> 1564 [label=true]; 1559 -> 11983 [label=false]; 11984 -> 11985; 1564 -> 1569 [label=true]; 1564 -> 11982 [label=false]; 11983 -> 11984; 1569 -> 1574 [label=true]; 1569 -> 11981 [label=false]; 11982 -> 11983; 1574 -> 1579 [label=true]; 1574 -> 11980 [label=false]; 11981 -> 11982; 1579 -> 1584 [label=true]; 1579 -> 11979 [label=false]; 11980 -> 11981; 1584 -> 1589 [label=true]; 1584 -> 11978 [label=false]; 11979 -> 11980; 1589 -> 1594 [label=true]; 1589 -> 11977 [label=false]; 11978 -> 11979; 1594 -> 1599 [label=true]; 1594 -> 11976 [label=false]; 11977 -> 11978; 1599 -> 1604 [label=true]; 1599 -> 11975 [label=false]; 11976 -> 11977; 1604 -> 1609 [label=true]; 1604 -> 11974 [label=false]; 11975 -> 11976; 1609 -> 1614 [label=true]; 1609 -> 11973 [label=false]; 11974 -> 11975; 1614 -> 1619 [label=true]; 1614 -> 11972 [label=false]; 11973 -> 11974; 1619 -> 1624 [label=true]; 1619 -> 11971 [label=false]; 11972 -> 11973; 1624 -> 1629 [label=true]; 1624 -> 11970 [label=false]; 11971 -> 11972; 1629 -> 1634 [label=true]; 1629 -> 11969 [label=false]; 11970 -> 11971; 1634 -> 1639 [label=true]; 1634 -> 11968 [label=false]; 11969 -> 11970; 1639 -> 1644 [label=true]; 1639 -> 11967 [label=false]; 11968 -> 11969; 1644 -> 1649 [label=true]; 1644 -> 11966 [label=false]; 11967 -> 11968; 1649 -> 1654 [label=true]; 1649 -> 11965 [label=false]; 11966 -> 11967; 1654 -> 1659 [label=true]; 1654 -> 11964 [label=false]; 11965 -> 11966; 1659 -> 1664 [label=true]; 1659 -> 11963 [label=false]; 11964 -> 11965; 1664 -> 1669 [label=true]; 1664 -> 11962 [label=false]; 11963 -> 11964; 1669 -> 1674 [label=true]; 1669 -> 11961 [label=false]; 11962 -> 11963; 1674 -> 1679 [label=true]; 1674 -> 11960 [label=false]; 11961 -> 11962; 1679 -> 1684 [label=true]; 1679 -> 11959 [label=false]; 11960 -> 11961; 1684 -> 1689 [label=true]; 1684 -> 11958 [label=false]; 11959 -> 11960; 1689 -> 1694 [label=true]; 1689 -> 11957 [label=false]; 11958 -> 11959; 1694 -> 1699 [label=true]; 1694 -> 11956 [label=false]; 11957 -> 11958; 1699 -> 1704 [label=true]; 1699 -> 11955 [label=false]; 11956 -> 11957; 1704 -> 1709 [label=true]; 1704 -> 11954 [label=false]; 11955 -> 11956; 1709 -> 1714 [label=true]; 1709 -> 11953 [label=false]; 11954 -> 11955; 1714 -> 1719 [label=true]; 1714 -> 11952 [label=false]; 11953 -> 11954; 1719 -> 1724 [label=true]; 1719 -> 11951 [label=false]; 11952 -> 11953; 1724 -> 1729 [label=true]; 1724 -> 11950 [label=false]; 11951 -> 11952; 1729 -> 1734 [label=true]; 1729 -> 11949 [label=false]; 11950 -> 11951; 1734 -> 1739 [label=true]; 1734 -> 11948 [label=false]; 11949 -> 11950; 1739 -> 1744 [label=true]; 1739 -> 11947 [label=false]; 11948 -> 11949; 1744 -> 1749 [label=true]; 1744 -> 11946 [label=false]; 11947 -> 11948; 1749 -> 1754 [label=true]; 1749 -> 11945 [label=false]; 11946 -> 11947; 1754 -> 1759 [label=true]; 1754 -> 11944 [label=false]; 11945 -> 11946; 1759 -> 1764 [label=true]; 1759 -> 11943 [label=false]; 11944 -> 11945; 1764 -> 1769 [label=true]; 1764 -> 11942 [label=false]; 11943 -> 11944; 1769 -> 1774 [label=true]; 1769 -> 11941 [label=false]; 11942 -> 11943; 1774 -> 1779 [label=true]; 1774 -> 11940 [label=false]; 11941 -> 11942; 1779 -> 1784 [label=true]; 1779 -> 11939 [label=false]; 11940 -> 11941; 1784 -> 1789 [label=true]; 1784 -> 11938 [label=false]; 11939 -> 11940; 1789 -> 1794 [label=true]; 1789 -> 11937 [label=false]; 11938 -> 11939; 1794 -> 1799 [label=true]; 1794 -> 11936 [label=false]; 11937 -> 11938; 1799 -> 1804 [label=true]; 1799 -> 11935 [label=false]; 11936 -> 11937; 1804 -> 1809 [label=true]; 1804 -> 11934 [label=false]; 11935 -> 11936; 1809 -> 1814 [label=true]; 1809 -> 11933 [label=false]; 11934 -> 11935; 1814 -> 1819 [label=true]; 1814 -> 11932 [label=false]; 11933 -> 11934; 1819 -> 1824 [label=true]; 1819 -> 11931 [label=false]; 11932 -> 11933; 1824 -> 1829 [label=true]; 1824 -> 11930 [label=false]; 11931 -> 11932; 1829 -> 1834 [label=true]; 1829 -> 11929 [label=false]; 11930 -> 11931; 1834 -> 1839 [label=true]; 1834 -> 11928 [label=false]; 11929 -> 11930; 1839 -> 1844 [label=true]; 1839 -> 11927 [label=false]; 11928 -> 11929; 1844 -> 1849 [label=true]; 1844 -> 11926 [label=false]; 11927 -> 11928; 1849 -> 1854 [label=true]; 1849 -> 11925 [label=false]; 11926 -> 11927; 1854 -> 1859 [label=true]; 1854 -> 11924 [label=false]; 11925 -> 11926; 1859 -> 1864 [label=true]; 1859 -> 11923 [label=false]; 11924 -> 11925; 1864 -> 1869 [label=true]; 1864 -> 11922 [label=false]; 11923 -> 11924; 1869 -> 1874 [label=true]; 1869 -> 11921 [label=false]; 11922 -> 11923; 1874 -> 1879 [label=true]; 1874 -> 11920 [label=false]; 11921 -> 11922; 1879 -> 1884 [label=true]; 1879 -> 11919 [label=false]; 11920 -> 11921; 1884 -> 1889 [label=true]; 1884 -> 11918 [label=false]; 11919 -> 11920; 1889 -> 1894 [label=true]; 1889 -> 11917 [label=false]; 11918 -> 11919; 1894 -> 1899 [label=true]; 1894 -> 11916 [label=false]; 11917 -> 11918; 1899 -> 1904 [label=true]; 1899 -> 11915 [label=false]; 11916 -> 11917; 1904 -> 1909 [label=true]; 1904 -> 11914 [label=false]; 11915 -> 11916; 1909 -> 1914 [label=true]; 1909 -> 11913 [label=false]; 11914 -> 11915; 1914 -> 1919 [label=true]; 1914 -> 11912 [label=false]; 11913 -> 11914; 1919 -> 1924 [label=true]; 1919 -> 11911 [label=false]; 11912 -> 11913; 1924 -> 1929 [label=true]; 1924 -> 11910 [label=false]; 11911 -> 11912; 1929 -> 1934 [label=true]; 1929 -> 11909 [label=false]; 11910 -> 11911; 1934 -> 1939 [label=true]; 1934 -> 11908 [label=false]; 11909 -> 11910; 1939 -> 1944 [label=true]; 1939 -> 11907 [label=false]; 11908 -> 11909; 1944 -> 1949 [label=true]; 1944 -> 11906 [label=false]; 11907 -> 11908; 1949 -> 1954 [label=true]; 1949 -> 11905 [label=false]; 11906 -> 11907; 1954 -> 1959 [label=true]; 1954 -> 11904 [label=false]; 11905 -> 11906; 1959 -> 1964 [label=true]; 1959 -> 11903 [label=false]; 11904 -> 11905; 1964 -> 1969 [label=true]; 1964 -> 11902 [label=false]; 11903 -> 11904; 1969 -> 1974 [label=true]; 1969 -> 11901 [label=false]; 11902 -> 11903; 1974 -> 1979 [label=true]; 1974 -> 11900 [label=false]; 11901 -> 11902; 1979 -> 1984 [label=true]; 1979 -> 11899 [label=false]; 11900 -> 11901; 1984 -> 1989 [label=true]; 1984 -> 11898 [label=false]; 11899 -> 11900; 1989 -> 1994 [label=true]; 1989 -> 11897 [label=false]; 11898 -> 11899; 1994 -> 1999 [label=true]; 1994 -> 11896 [label=false]; 11897 -> 11898; 1999 -> 2004 [label=true]; 1999 -> 11895 [label=false]; 11896 -> 11897; 2004 -> 2009 [label=true]; 2004 -> 11894 [label=false]; 11895 -> 11896; 2009 -> 2014 [label=true]; 2009 -> 11893 [label=false]; 11894 -> 11895; 2014 -> 2019 [label=true]; 2014 -> 11892 [label=false]; 11893 -> 11894; 2019 -> 2024 [label=true]; 2019 -> 11891 [label=false]; 11892 -> 11893; 2024 -> 2029 [label=true]; 2024 -> 11890 [label=false]; 11891 -> 11892; 2029 -> 2034 [label=true]; 2029 -> 11889 [label=false]; 11890 -> 11891; 2034 -> 2039 [label=true]; 2034 -> 11888 [label=false]; 11889 -> 11890; 2039 -> 2044 [label=true]; 2039 -> 11887 [label=false]; 11888 -> 11889; 2044 -> 2049 [label=true]; 2044 -> 11886 [label=false]; 11887 -> 11888; 2049 -> 2054 [label=true]; 2049 -> 11885 [label=false]; 11886 -> 11887; 2054 -> 2059 [label=true]; 2054 -> 11884 [label=false]; 11885 -> 11886; 2059 -> 2064 [label=true]; 2059 -> 11883 [label=false]; 11884 -> 11885; 2064 -> 2069 [label=true]; 2064 -> 11882 [label=false]; 11883 -> 11884; 2069 -> 2074 [label=true]; 2069 -> 11881 [label=false]; 11882 -> 11883; 2074 -> 2079 [label=true]; 2074 -> 11880 [label=false]; 11881 -> 11882; 2079 -> 2084 [label=true]; 2079 -> 11879 [label=false]; 11880 -> 11881; 2084 -> 2089 [label=true]; 2084 -> 11878 [label=false]; 11879 -> 11880; 2089 -> 2094 [label=true]; 2089 -> 11877 [label=false]; 11878 -> 11879; 2094 -> 2099 [label=true]; 2094 -> 11876 [label=false]; 11877 -> 11878; 2099 -> 2104 [label=true]; 2099 -> 11875 [label=false]; 11876 -> 11877; 2104 -> 2109 [label=true]; 2104 -> 11874 [label=false]; 11875 -> 11876; 2109 -> 2114 [label=true]; 2109 -> 11873 [label=false]; 11874 -> 11875; 2114 -> 2119 [label=true]; 2114 -> 11872 [label=false]; 11873 -> 11874; 2119 -> 2124 [label=true]; 2119 -> 11871 [label=false]; 11872 -> 11873; 2124 -> 2129 [label=true]; 2124 -> 11870 [label=false]; 11871 -> 11872; 2129 -> 2134 [label=true]; 2129 -> 11869 [label=false]; 11870 -> 11871; 2134 -> 2139 [label=true]; 2134 -> 11868 [label=false]; 11869 -> 11870; 2139 -> 2144 [label=true]; 2139 -> 11867 [label=false]; 11868 -> 11869; 2144 -> 2149 [label=true]; 2144 -> 11866 [label=false]; 11867 -> 11868; 2149 -> 2154 [label=true]; 2149 -> 11865 [label=false]; 11866 -> 11867; 2154 -> 2159 [label=true]; 2154 -> 11864 [label=false]; 11865 -> 11866; 2159 -> 2164 [label=true]; 2159 -> 11863 [label=false]; 11864 -> 11865; 2164 -> 2169 [label=true]; 2164 -> 11862 [label=false]; 11863 -> 11864; 2169 -> 2174 [label=true]; 2169 -> 11861 [label=false]; 11862 -> 11863; 2174 -> 2179 [label=true]; 2174 -> 11860 [label=false]; 11861 -> 11862; 2179 -> 2184 [label=true]; 2179 -> 11859 [label=false]; 11860 -> 11861; 2184 -> 2189 [label=true]; 2184 -> 11858 [label=false]; 11859 -> 11860; 2189 -> 2194 [label=true]; 2189 -> 11857 [label=false]; 11858 -> 11859; 2194 -> 2199 [label=true]; 2194 -> 11856 [label=false]; 11857 -> 11858; 2199 -> 2204 [label=true]; 2199 -> 11855 [label=false]; 11856 -> 11857; 2204 -> 2209 [label=true]; 2204 -> 11854 [label=false]; 11855 -> 11856; 2209 -> 2214 [label=true]; 2209 -> 11853 [label=false]; 11854 -> 11855; 2214 -> 2219 [label=true]; 2214 -> 11852 [label=false]; 11853 -> 11854; 2219 -> 2224 [label=true]; 2219 -> 11851 [label=false]; 11852 -> 11853; 2224 -> 2229 [label=true]; 2224 -> 11850 [label=false]; 11851 -> 11852; 2229 -> 2234 [label=true]; 2229 -> 11849 [label=false]; 11850 -> 11851; 2234 -> 2239 [label=true]; 2234 -> 11848 [label=false]; 11849 -> 11850; 2239 -> 2244 [label=true]; 2239 -> 11847 [label=false]; 11848 -> 11849; 2244 -> 2249 [label=true]; 2244 -> 11846 [label=false]; 11847 -> 11848; 2249 -> 2254 [label=true]; 2249 -> 11845 [label=false]; 11846 -> 11847; 2254 -> 2259 [label=true]; 2254 -> 11844 [label=false]; 11845 -> 11846; 2259 -> 2264 [label=true]; 2259 -> 11843 [label=false]; 11844 -> 11845; 2264 -> 2269 [label=true]; 2264 -> 11842 [label=false]; 11843 -> 11844; 2269 -> 2274 [label=true]; 2269 -> 11841 [label=false]; 11842 -> 11843; 2274 -> 2279 [label=true]; 2274 -> 11840 [label=false]; 11841 -> 11842; 2279 -> 2284 [label=true]; 2279 -> 11839 [label=false]; 11840 -> 11841; 2284 -> 2289 [label=true]; 2284 -> 11838 [label=false]; 11839 -> 11840; 2289 -> 2294 [label=true]; 2289 -> 11837 [label=false]; 11838 -> 11839; 2294 -> 2299 [label=true]; 2294 -> 11836 [label=false]; 11837 -> 11838; 2299 -> 2304 [label=true]; 2299 -> 11835 [label=false]; 11836 -> 11837; 2304 -> 2309 [label=true]; 2304 -> 11834 [label=false]; 11835 -> 11836; 2309 -> 2314 [label=true]; 2309 -> 11833 [label=false]; 11834 -> 11835; 2314 -> 2319 [label=true]; 2314 -> 11832 [label=false]; 11833 -> 11834; 2319 -> 2324 [label=true]; 2319 -> 11831 [label=false]; 11832 -> 11833; 2324 -> 2329 [label=true]; 2324 -> 11830 [label=false]; 11831 -> 11832; 2329 -> 2334 [label=true]; 2329 -> 11829 [label=false]; 11830 -> 11831; 2334 -> 2339 [label=true]; 2334 -> 11828 [label=false]; 11829 -> 11830; 2339 -> 2344 [label=true]; 2339 -> 11827 [label=false]; 11828 -> 11829; 2344 -> 2349 [label=true]; 2344 -> 11826 [label=false]; 11827 -> 11828; 2349 -> 2354 [label=true]; 2349 -> 11825 [label=false]; 11826 -> 11827; 2354 -> 2359 [label=true]; 2354 -> 11824 [label=false]; 11825 -> 11826; 2359 -> 2364 [label=true]; 2359 -> 11823 [label=false]; 11824 -> 11825; 2364 -> 2369 [label=true]; 2364 -> 11822 [label=false]; 11823 -> 11824; 2369 -> 2374 [label=true]; 2369 -> 11821 [label=false]; 11822 -> 11823; 2374 -> 2379 [label=true]; 2374 -> 11820 [label=false]; 11821 -> 11822; 2379 -> 2384 [label=true]; 2379 -> 11819 [label=false]; 11820 -> 11821; 2384 -> 2389 [label=true]; 2384 -> 11818 [label=false]; 11819 -> 11820; 2389 -> 2394 [label=true]; 2389 -> 11817 [label=false]; 11818 -> 11819; 2394 -> 2399 [label=true]; 2394 -> 11816 [label=false]; 11817 -> 11818; 2399 -> 2404 [label=true]; 2399 -> 11815 [label=false]; 11816 -> 11817; 2404 -> 2409 [label=true]; 2404 -> 11814 [label=false]; 11815 -> 11816; 2409 -> 2414 [label=true]; 2409 -> 11813 [label=false]; 11814 -> 11815; 2414 -> 2419 [label=true]; 2414 -> 11812 [label=false]; 11813 -> 11814; 2419 -> 2424 [label=true]; 2419 -> 11811 [label=false]; 11812 -> 11813; 2424 -> 2429 [label=true]; 2424 -> 11810 [label=false]; 11811 -> 11812; 2429 -> 2434 [label=true]; 2429 -> 11809 [label=false]; 11810 -> 11811; 2434 -> 2439 [label=true]; 2434 -> 11808 [label=false]; 11809 -> 11810; 2439 -> 2444 [label=true]; 2439 -> 11807 [label=false]; 11808 -> 11809; 2444 -> 2449 [label=true]; 2444 -> 11806 [label=false]; 11807 -> 11808; 2449 -> 2454 [label=true]; 2449 -> 11805 [label=false]; 11806 -> 11807; 2454 -> 2459 [label=true]; 2454 -> 11804 [label=false]; 11805 -> 11806; 2459 -> 2464 [label=true]; 2459 -> 11803 [label=false]; 11804 -> 11805; 2464 -> 2469 [label=true]; 2464 -> 11802 [label=false]; 11803 -> 11804; 2469 -> 2474 [label=true]; 2469 -> 11801 [label=false]; 11802 -> 11803; 2474 -> 2479 [label=true]; 2474 -> 11800 [label=false]; 11801 -> 11802; 2479 -> 2484 [label=true]; 2479 -> 11799 [label=false]; 11800 -> 11801; 2484 -> 2489 [label=true]; 2484 -> 11798 [label=false]; 11799 -> 11800; 2489 -> 2494 [label=true]; 2489 -> 11797 [label=false]; 11798 -> 11799; 2494 -> 2499 [label=true]; 2494 -> 11796 [label=false]; 11797 -> 11798; 2499 -> 2504 [label=true]; 2499 -> 11795 [label=false]; 11796 -> 11797; 2504 -> 2509 [label=true]; 2504 -> 11794 [label=false]; 11795 -> 11796; 2509 -> 2514 [label=true]; 2509 -> 11793 [label=false]; 11794 -> 11795; 2514 -> 2519 [label=true]; 2514 -> 11792 [label=false]; 11793 -> 11794; 2519 -> 2524 [label=true]; 2519 -> 11791 [label=false]; 11792 -> 11793; 2524 -> 2529 [label=true]; 2524 -> 11790 [label=false]; 11791 -> 11792; 2529 -> 2534 [label=true]; 2529 -> 11789 [label=false]; 11790 -> 11791; 2534 -> 2539 [label=true]; 2534 -> 11788 [label=false]; 11789 -> 11790; 2539 -> 2544 [label=true]; 2539 -> 11787 [label=false]; 11788 -> 11789; 2544 -> 2549 [label=true]; 2544 -> 11786 [label=false]; 11787 -> 11788; 2549 -> 2554 [label=true]; 2549 -> 11785 [label=false]; 11786 -> 11787; 2554 -> 2559 [label=true]; 2554 -> 11784 [label=false]; 11785 -> 11786; 2559 -> 2564 [label=true]; 2559 -> 11783 [label=false]; 11784 -> 11785; 2564 -> 2569 [label=true]; 2564 -> 11782 [label=false]; 11783 -> 11784; 2569 -> 2574 [label=true]; 2569 -> 11781 [label=false]; 11782 -> 11783; 2574 -> 2579 [label=true]; 2574 -> 11780 [label=false]; 11781 -> 11782; 2579 -> 2584 [label=true]; 2579 -> 11779 [label=false]; 11780 -> 11781; 2584 -> 2589 [label=true]; 2584 -> 11778 [label=false]; 11779 -> 11780; 2589 -> 2594 [label=true]; 2589 -> 11777 [label=false]; 11778 -> 11779; 2594 -> 2599 [label=true]; 2594 -> 11776 [label=false]; 11777 -> 11778; 2599 -> 2604 [label=true]; 2599 -> 11775 [label=false]; 11776 -> 11777; 2604 -> 2609 [label=true]; 2604 -> 11774 [label=false]; 11775 -> 11776; 2609 -> 2614 [label=true]; 2609 -> 11773 [label=false]; 11774 -> 11775; 2614 -> 2619 [label=true]; 2614 -> 11772 [label=false]; 11773 -> 11774; 2619 -> 2624 [label=true]; 2619 -> 11771 [label=false]; 11772 -> 11773; 2624 -> 2629 [label=true]; 2624 -> 11770 [label=false]; 11771 -> 11772; 2629 -> 2634 [label=true]; 2629 -> 11769 [label=false]; 11770 -> 11771; 2634 -> 2639 [label=true]; 2634 -> 11768 [label=false]; 11769 -> 11770; 2639 -> 2644 [label=true]; 2639 -> 11767 [label=false]; 11768 -> 11769; 2644 -> 2649 [label=true]; 2644 -> 11766 [label=false]; 11767 -> 11768; 2649 -> 2654 [label=true]; 2649 -> 11765 [label=false]; 11766 -> 11767; 2654 -> 2659 [label=true]; 2654 -> 11764 [label=false]; 11765 -> 11766; 2659 -> 2664 [label=true]; 2659 -> 11763 [label=false]; 11764 -> 11765; 2664 -> 2669 [label=true]; 2664 -> 11762 [label=false]; 11763 -> 11764; 2669 -> 2674 [label=true]; 2669 -> 11761 [label=false]; 11762 -> 11763; 2674 -> 2679 [label=true]; 2674 -> 11760 [label=false]; 11761 -> 11762; 2679 -> 2684 [label=true]; 2679 -> 11759 [label=false]; 11760 -> 11761; 2684 -> 2689 [label=true]; 2684 -> 11758 [label=false]; 11759 -> 11760; 2689 -> 2694 [label=true]; 2689 -> 11757 [label=false]; 11758 -> 11759; 2694 -> 2699 [label=true]; 2694 -> 11756 [label=false]; 11757 -> 11758; 2699 -> 2704 [label=true]; 2699 -> 11755 [label=false]; 11756 -> 11757; 2704 -> 2709 [label=true]; 2704 -> 11754 [label=false]; 11755 -> 11756; 2709 -> 2714 [label=true]; 2709 -> 11753 [label=false]; 11754 -> 11755; 2714 -> 2719 [label=true]; 2714 -> 11752 [label=false]; 11753 -> 11754; 2719 -> 2724 [label=true]; 2719 -> 11751 [label=false]; 11752 -> 11753; 2724 -> 2729 [label=true]; 2724 -> 11750 [label=false]; 11751 -> 11752; 2729 -> 2734 [label=true]; 2729 -> 11749 [label=false]; 11750 -> 11751; 2734 -> 2739 [label=true]; 2734 -> 11748 [label=false]; 11749 -> 11750; 2739 -> 2744 [label=true]; 2739 -> 11747 [label=false]; 11748 -> 11749; 2744 -> 2749 [label=true]; 2744 -> 11746 [label=false]; 11747 -> 11748; 2749 -> 2754 [label=true]; 2749 -> 11745 [label=false]; 11746 -> 11747; 2754 -> 2759 [label=true]; 2754 -> 11744 [label=false]; 11745 -> 11746; 2759 -> 2764 [label=true]; 2759 -> 11743 [label=false]; 11744 -> 11745; 2764 -> 2769 [label=true]; 2764 -> 11742 [label=false]; 11743 -> 11744; 2769 -> 2774 [label=true]; 2769 -> 11741 [label=false]; 11742 -> 11743; 2774 -> 2779 [label=true]; 2774 -> 11740 [label=false]; 11741 -> 11742; 2779 -> 2784 [label=true]; 2779 -> 11739 [label=false]; 11740 -> 11741; 2784 -> 2789 [label=true]; 2784 -> 11738 [label=false]; 11739 -> 11740; 2789 -> 2794 [label=true]; 2789 -> 11737 [label=false]; 11738 -> 11739; 2794 -> 2799 [label=true]; 2794 -> 11736 [label=false]; 11737 -> 11738; 2799 -> 2804 [label=true]; 2799 -> 11735 [label=false]; 11736 -> 11737; 2804 -> 2809 [label=true]; 2804 -> 11734 [label=false]; 11735 -> 11736; 2809 -> 2814 [label=true]; 2809 -> 11733 [label=false]; 11734 -> 11735; 2814 -> 2819 [label=true]; 2814 -> 11732 [label=false]; 11733 -> 11734; 2819 -> 2824 [label=true]; 2819 -> 11731 [label=false]; 11732 -> 11733; 2824 -> 2829 [label=true]; 2824 -> 11730 [label=false]; 11731 -> 11732; 2829 -> 2834 [label=true]; 2829 -> 11729 [label=false]; 11730 -> 11731; 2834 -> 2839 [label=true]; 2834 -> 11728 [label=false]; 11729 -> 11730; 2839 -> 2844 [label=true]; 2839 -> 11727 [label=false]; 11728 -> 11729; 2844 -> 2849 [label=true]; 2844 -> 11726 [label=false]; 11727 -> 11728; 2849 -> 2854 [label=true]; 2849 -> 11725 [label=false]; 11726 -> 11727; 2854 -> 2859 [label=true]; 2854 -> 11724 [label=false]; 11725 -> 11726; 2859 -> 2864 [label=true]; 2859 -> 11723 [label=false]; 11724 -> 11725; 2864 -> 2869 [label=true]; 2864 -> 11722 [label=false]; 11723 -> 11724; 2869 -> 2874 [label=true]; 2869 -> 11721 [label=false]; 11722 -> 11723; 2874 -> 2879 [label=true]; 2874 -> 11720 [label=false]; 11721 -> 11722; 2879 -> 2884 [label=true]; 2879 -> 11719 [label=false]; 11720 -> 11721; 2884 -> 2889 [label=true]; 2884 -> 11718 [label=false]; 11719 -> 11720; 2889 -> 2894 [label=true]; 2889 -> 11717 [label=false]; 11718 -> 11719; 2894 -> 2899 [label=true]; 2894 -> 11716 [label=false]; 11717 -> 11718; 2899 -> 2904 [label=true]; 2899 -> 11715 [label=false]; 11716 -> 11717; 2904 -> 2909 [label=true]; 2904 -> 11714 [label=false]; 11715 -> 11716; 2909 -> 2914 [label=true]; 2909 -> 11713 [label=false]; 11714 -> 11715; 2914 -> 2919 [label=true]; 2914 -> 11712 [label=false]; 11713 -> 11714; 2919 -> 2924 [label=true]; 2919 -> 11711 [label=false]; 11712 -> 11713; 2924 -> 2929 [label=true]; 2924 -> 11710 [label=false]; 11711 -> 11712; 2929 -> 2934 [label=true]; 2929 -> 11709 [label=false]; 11710 -> 11711; 2934 -> 2939 [label=true]; 2934 -> 11708 [label=false]; 11709 -> 11710; 2939 -> 2944 [label=true]; 2939 -> 11707 [label=false]; 11708 -> 11709; 2944 -> 2949 [label=true]; 2944 -> 11706 [label=false]; 11707 -> 11708; 2949 -> 2954 [label=true]; 2949 -> 11705 [label=false]; 11706 -> 11707; 2954 -> 2959 [label=true]; 2954 -> 11704 [label=false]; 11705 -> 11706; 2959 -> 2964 [label=true]; 2959 -> 11703 [label=false]; 11704 -> 11705; 2964 -> 2969 [label=true]; 2964 -> 11702 [label=false]; 11703 -> 11704; 2969 -> 2974 [label=true]; 2969 -> 11701 [label=false]; 11702 -> 11703; 2974 -> 2979 [label=true]; 2974 -> 11700 [label=false]; 11701 -> 11702; 2979 -> 2984 [label=true]; 2979 -> 11699 [label=false]; 11700 -> 11701; 2984 -> 2989 [label=true]; 2984 -> 11698 [label=false]; 11699 -> 11700; 2989 -> 2994 [label=true]; 2989 -> 11697 [label=false]; 11698 -> 11699; 2994 -> 2999 [label=true]; 2994 -> 11696 [label=false]; 11697 -> 11698; 2999 -> 3004 [label=true]; 2999 -> 11695 [label=false]; 11696 -> 11697; 3004 -> 3009 [label=true]; 3004 -> 11694 [label=false]; 11695 -> 11696; 3009 -> 3014 [label=true]; 3009 -> 11693 [label=false]; 11694 -> 11695; 3014 -> 3019 [label=true]; 3014 -> 11692 [label=false]; 11693 -> 11694; 3019 -> 3024 [label=true]; 3019 -> 11691 [label=false]; 11692 -> 11693; 3024 -> 3029 [label=true]; 3024 -> 11690 [label=false]; 11691 -> 11692; 3029 -> 3034 [label=true]; 3029 -> 11689 [label=false]; 11690 -> 11691; 3034 -> 3039 [label=true]; 3034 -> 11688 [label=false]; 11689 -> 11690; 3039 -> 3044 [label=true]; 3039 -> 11687 [label=false]; 11688 -> 11689; 3044 -> 3049 [label=true]; 3044 -> 11686 [label=false]; 11687 -> 11688; 3049 -> 3054 [label=true]; 3049 -> 11685 [label=false]; 11686 -> 11687; 3054 -> 3059 [label=true]; 3054 -> 11684 [label=false]; 11685 -> 11686; 3059 -> 3064 [label=true]; 3059 -> 11683 [label=false]; 11684 -> 11685; 3064 -> 3069 [label=true]; 3064 -> 11682 [label=false]; 11683 -> 11684; 3069 -> 3074 [label=true]; 3069 -> 11681 [label=false]; 11682 -> 11683; 3074 -> 3079 [label=true]; 3074 -> 11680 [label=false]; 11681 -> 11682; 3079 -> 3084 [label=true]; 3079 -> 11679 [label=false]; 11680 -> 11681; 3084 -> 3089 [label=true]; 3084 -> 11678 [label=false]; 11679 -> 11680; 3089 -> 3094 [label=true]; 3089 -> 11677 [label=false]; 11678 -> 11679; 3094 -> 3099 [label=true]; 3094 -> 11676 [label=false]; 11677 -> 11678; 3099 -> 3104 [label=true]; 3099 -> 11675 [label=false]; 11676 -> 11677; 3104 -> 3109 [label=true]; 3104 -> 11674 [label=false]; 11675 -> 11676; 3109 -> 3114 [label=true]; 3109 -> 11673 [label=false]; 11674 -> 11675; 3114 -> 3119 [label=true]; 3114 -> 11672 [label=false]; 11673 -> 11674; 3119 -> 3124 [label=true]; 3119 -> 11671 [label=false]; 11672 -> 11673; 3124 -> 3129 [label=true]; 3124 -> 11670 [label=false]; 11671 -> 11672; 3129 -> 3134 [label=true]; 3129 -> 11669 [label=false]; 11670 -> 11671; 3134 -> 3139 [label=true]; 3134 -> 11668 [label=false]; 11669 -> 11670; 3139 -> 3144 [label=true]; 3139 -> 11667 [label=false]; 11668 -> 11669; 3144 -> 3149 [label=true]; 3144 -> 11666 [label=false]; 11667 -> 11668; 3149 -> 3154 [label=true]; 3149 -> 11665 [label=false]; 11666 -> 11667; 3154 -> 3159 [label=true]; 3154 -> 11664 [label=false]; 11665 -> 11666; 3159 -> 3164 [label=true]; 3159 -> 11663 [label=false]; 11664 -> 11665; 3164 -> 3169 [label=true]; 3164 -> 11662 [label=false]; 11663 -> 11664; 3169 -> 3174 [label=true]; 3169 -> 11661 [label=false]; 11662 -> 11663; 3174 -> 3179 [label=true]; 3174 -> 11660 [label=false]; 11661 -> 11662; 3179 -> 3184 [label=true]; 3179 -> 11659 [label=false]; 11660 -> 11661; 3184 -> 3189 [label=true]; 3184 -> 11658 [label=false]; 11659 -> 11660; 3189 -> 3194 [label=true]; 3189 -> 11657 [label=false]; 11658 -> 11659; 3194 -> 3199 [label=true]; 3194 -> 11656 [label=false]; 11657 -> 11658; 3199 -> 3204 [label=true]; 3199 -> 11655 [label=false]; 11656 -> 11657; 3204 -> 3209 [label=true]; 3204 -> 11654 [label=false]; 11655 -> 11656; 3209 -> 3214 [label=true]; 3209 -> 11653 [label=false]; 11654 -> 11655; 3214 -> 3219 [label=true]; 3214 -> 11652 [label=false]; 11653 -> 11654; 3219 -> 3224 [label=true]; 3219 -> 11651 [label=false]; 11652 -> 11653; 3224 -> 3229 [label=true]; 3224 -> 11650 [label=false]; 11651 -> 11652; 3229 -> 3234 [label=true]; 3229 -> 11649 [label=false]; 11650 -> 11651; 3234 -> 3239 [label=true]; 3234 -> 11648 [label=false]; 11649 -> 11650; 3239 -> 3244 [label=true]; 3239 -> 11647 [label=false]; 11648 -> 11649; 3244 -> 3249 [label=true]; 3244 -> 11646 [label=false]; 11647 -> 11648; 3249 -> 3254 [label=true]; 3249 -> 11645 [label=false]; 11646 -> 11647; 3254 -> 3259 [label=true]; 3254 -> 11644 [label=false]; 11645 -> 11646; 3259 -> 3264 [label=true]; 3259 -> 11643 [label=false]; 11644 -> 11645; 3264 -> 3269 [label=true]; 3264 -> 11642 [label=false]; 11643 -> 11644; 3269 -> 3274 [label=true]; 3269 -> 11641 [label=false]; 11642 -> 11643; 3274 -> 3279 [label=true]; 3274 -> 11640 [label=false]; 11641 -> 11642; 3279 -> 3284 [label=true]; 3279 -> 11639 [label=false]; 11640 -> 11641; 3284 -> 3289 [label=true]; 3284 -> 11638 [label=false]; 11639 -> 11640; 3289 -> 3294 [label=true]; 3289 -> 11637 [label=false]; 11638 -> 11639; 3294 -> 3299 [label=true]; 3294 -> 11636 [label=false]; 11637 -> 11638; 3299 -> 3304 [label=true]; 3299 -> 11635 [label=false]; 11636 -> 11637; 3304 -> 3309 [label=true]; 3304 -> 11634 [label=false]; 11635 -> 11636; 3309 -> 3314 [label=true]; 3309 -> 11633 [label=false]; 11634 -> 11635; 3314 -> 3319 [label=true]; 3314 -> 11632 [label=false]; 11633 -> 11634; 3319 -> 3324 [label=true]; 3319 -> 11631 [label=false]; 11632 -> 11633; 3324 -> 3329 [label=true]; 3324 -> 11630 [label=false]; 11631 -> 11632; 3329 -> 3334 [label=true]; 3329 -> 11629 [label=false]; 11630 -> 11631; 3334 -> 3339 [label=true]; 3334 -> 11628 [label=false]; 11629 -> 11630; 3339 -> 3344 [label=true]; 3339 -> 11627 [label=false]; 11628 -> 11629; 3344 -> 3349 [label=true]; 3344 -> 11626 [label=false]; 11627 -> 11628; 3349 -> 3354 [label=true]; 3349 -> 11625 [label=false]; 11626 -> 11627; 3354 -> 3359 [label=true]; 3354 -> 11624 [label=false]; 11625 -> 11626; 3359 -> 3364 [label=true]; 3359 -> 11623 [label=false]; 11624 -> 11625; 3364 -> 3369 [label=true]; 3364 -> 11622 [label=false]; 11623 -> 11624; 3369 -> 3374 [label=true]; 3369 -> 11621 [label=false]; 11622 -> 11623; 3374 -> 3379 [label=true]; 3374 -> 11620 [label=false]; 11621 -> 11622; 3379 -> 3384 [label=true]; 3379 -> 11619 [label=false]; 11620 -> 11621; 3384 -> 3389 [label=true]; 3384 -> 11618 [label=false]; 11619 -> 11620; 3389 -> 3394 [label=true]; 3389 -> 11617 [label=false]; 11618 -> 11619; 3394 -> 3399 [label=true]; 3394 -> 11616 [label=false]; 11617 -> 11618; 3399 -> 3404 [label=true]; 3399 -> 11615 [label=false]; 11616 -> 11617; 3404 -> 3409 [label=true]; 3404 -> 11614 [label=false]; 11615 -> 11616; 3409 -> 3414 [label=true]; 3409 -> 11613 [label=false]; 11614 -> 11615; 3414 -> 3419 [label=true]; 3414 -> 11612 [label=false]; 11613 -> 11614; 3419 -> 3424 [label=true]; 3419 -> 11611 [label=false]; 11612 -> 11613; 3424 -> 3429 [label=true]; 3424 -> 11610 [label=false]; 11611 -> 11612; 3429 -> 3434 [label=true]; 3429 -> 11609 [label=false]; 11610 -> 11611; 3434 -> 3439 [label=true]; 3434 -> 11608 [label=false]; 11609 -> 11610; 3439 -> 3444 [label=true]; 3439 -> 11607 [label=false]; 11608 -> 11609; 3444 -> 3449 [label=true]; 3444 -> 11606 [label=false]; 11607 -> 11608; 3449 -> 3454 [label=true]; 3449 -> 11605 [label=false]; 11606 -> 11607; 3454 -> 3459 [label=true]; 3454 -> 11604 [label=false]; 11605 -> 11606; 3459 -> 3464 [label=true]; 3459 -> 11603 [label=false]; 11604 -> 11605; 3464 -> 3469 [label=true]; 3464 -> 11602 [label=false]; 11603 -> 11604; 3469 -> 3474 [label=true]; 3469 -> 11601 [label=false]; 11602 -> 11603; 3474 -> 3479 [label=true]; 3474 -> 11600 [label=false]; 11601 -> 11602; 3479 -> 3484 [label=true]; 3479 -> 11599 [label=false]; 11600 -> 11601; 3484 -> 3489 [label=true]; 3484 -> 11598 [label=false]; 11599 -> 11600; 3489 -> 3494 [label=true]; 3489 -> 11597 [label=false]; 11598 -> 11599; 3494 -> 3499 [label=true]; 3494 -> 11596 [label=false]; 11597 -> 11598; 3499 -> 3504 [label=true]; 3499 -> 11595 [label=false]; 11596 -> 11597; 3504 -> 3509 [label=true]; 3504 -> 11594 [label=false]; 11595 -> 11596; 3509 -> 3514 [label=true]; 3509 -> 11593 [label=false]; 11594 -> 11595; 3514 -> 3519 [label=true]; 3514 -> 11592 [label=false]; 11593 -> 11594; 3519 -> 3524 [label=true]; 3519 -> 11591 [label=false]; 11592 -> 11593; 3524 -> 3529 [label=true]; 3524 -> 11590 [label=false]; 11591 -> 11592; 3529 -> 3534 [label=true]; 3529 -> 11589 [label=false]; 11590 -> 11591; 3534 -> 3539 [label=true]; 3534 -> 11588 [label=false]; 11589 -> 11590; 3539 -> 3544 [label=true]; 3539 -> 11587 [label=false]; 11588 -> 11589; 3544 -> 3549 [label=true]; 3544 -> 11586 [label=false]; 11587 -> 11588; 3549 -> 3554 [label=true]; 3549 -> 11585 [label=false]; 11586 -> 11587; 3554 -> 3559 [label=true]; 3554 -> 11584 [label=false]; 11585 -> 11586; 3559 -> 3564 [label=true]; 3559 -> 11583 [label=false]; 11584 -> 11585; 3564 -> 3569 [label=true]; 3564 -> 11582 [label=false]; 11583 -> 11584; 3569 -> 3574 [label=true]; 3569 -> 11581 [label=false]; 11582 -> 11583; 3574 -> 3579 [label=true]; 3574 -> 11580 [label=false]; 11581 -> 11582; 3579 -> 3584 [label=true]; 3579 -> 11579 [label=false]; 11580 -> 11581; 3584 -> 3589 [label=true]; 3584 -> 11578 [label=false]; 11579 -> 11580; 3589 -> 3594 [label=true]; 3589 -> 11577 [label=false]; 11578 -> 11579; 3594 -> 3599 [label=true]; 3594 -> 11576 [label=false]; 11577 -> 11578; 3599 -> 3604 [label=true]; 3599 -> 11575 [label=false]; 11576 -> 11577; 3604 -> 3609 [label=true]; 3604 -> 11574 [label=false]; 11575 -> 11576; 3609 -> 3614 [label=true]; 3609 -> 11573 [label=false]; 11574 -> 11575; 3614 -> 3619 [label=true]; 3614 -> 11572 [label=false]; 11573 -> 11574; 3619 -> 3624 [label=true]; 3619 -> 11571 [label=false]; 11572 -> 11573; 3624 -> 3629 [label=true]; 3624 -> 11570 [label=false]; 11571 -> 11572; 3629 -> 3634 [label=true]; 3629 -> 11569 [label=false]; 11570 -> 11571; 3634 -> 3639 [label=true]; 3634 -> 11568 [label=false]; 11569 -> 11570; 3639 -> 3644 [label=true]; 3639 -> 11567 [label=false]; 11568 -> 11569; 3644 -> 3649 [label=true]; 3644 -> 11566 [label=false]; 11567 -> 11568; 3649 -> 3654 [label=true]; 3649 -> 11565 [label=false]; 11566 -> 11567; 3654 -> 3659 [label=true]; 3654 -> 11564 [label=false]; 11565 -> 11566; 3659 -> 3664 [label=true]; 3659 -> 11563 [label=false]; 11564 -> 11565; 3664 -> 3669 [label=true]; 3664 -> 11562 [label=false]; 11563 -> 11564; 3669 -> 3674 [label=true]; 3669 -> 11561 [label=false]; 11562 -> 11563; 3674 -> 3679 [label=true]; 3674 -> 11560 [label=false]; 11561 -> 11562; 3679 -> 3684 [label=true]; 3679 -> 11559 [label=false]; 11560 -> 11561; 3684 -> 3689 [label=true]; 3684 -> 11558 [label=false]; 11559 -> 11560; 3689 -> 3694 [label=true]; 3689 -> 11557 [label=false]; 11558 -> 11559; 3694 -> 3699 [label=true]; 3694 -> 11556 [label=false]; 11557 -> 11558; 3699 -> 3704 [label=true]; 3699 -> 11555 [label=false]; 11556 -> 11557; 3704 -> 3709 [label=true]; 3704 -> 11554 [label=false]; 11555 -> 11556; 3709 -> 3714 [label=true]; 3709 -> 11553 [label=false]; 11554 -> 11555; 3714 -> 3719 [label=true]; 3714 -> 11552 [label=false]; 11553 -> 11554; 3719 -> 3724 [label=true]; 3719 -> 11551 [label=false]; 11552 -> 11553; 3724 -> 3729 [label=true]; 3724 -> 11550 [label=false]; 11551 -> 11552; 3729 -> 3734 [label=true]; 3729 -> 11549 [label=false]; 11550 -> 11551; 3734 -> 3739 [label=true]; 3734 -> 11548 [label=false]; 11549 -> 11550; 3739 -> 3744 [label=true]; 3739 -> 11547 [label=false]; 11548 -> 11549; 3744 -> 3749 [label=true]; 3744 -> 11546 [label=false]; 11547 -> 11548; 3749 -> 3754 [label=true]; 3749 -> 11545 [label=false]; 11546 -> 11547; 3754 -> 3759 [label=true]; 3754 -> 11544 [label=false]; 11545 -> 11546; 3759 -> 3764 [label=true]; 3759 -> 11543 [label=false]; 11544 -> 11545; 3764 -> 3769 [label=true]; 3764 -> 11542 [label=false]; 11543 -> 11544; 3769 -> 3774 [label=true]; 3769 -> 11541 [label=false]; 11542 -> 11543; 3774 -> 3779 [label=true]; 3774 -> 11540 [label=false]; 11541 -> 11542; 3779 -> 3784 [label=true]; 3779 -> 11539 [label=false]; 11540 -> 11541; 3784 -> 3789 [label=true]; 3784 -> 11538 [label=false]; 11539 -> 11540; 3789 -> 3794 [label=true]; 3789 -> 11537 [label=false]; 11538 -> 11539; 3794 -> 3799 [label=true]; 3794 -> 11536 [label=false]; 11537 -> 11538; 3799 -> 3804 [label=true]; 3799 -> 11535 [label=false]; 11536 -> 11537; 3804 -> 3809 [label=true]; 3804 -> 11534 [label=false]; 11535 -> 11536; 3809 -> 3814 [label=true]; 3809 -> 11533 [label=false]; 11534 -> 11535; 3814 -> 3819 [label=true]; 3814 -> 11532 [label=false]; 11533 -> 11534; 3819 -> 3824 [label=true]; 3819 -> 11531 [label=false]; 11532 -> 11533; 3824 -> 3829 [label=true]; 3824 -> 11530 [label=false]; 11531 -> 11532; 3829 -> 3834 [label=true]; 3829 -> 11529 [label=false]; 11530 -> 11531; 3834 -> 3839 [label=true]; 3834 -> 11528 [label=false]; 11529 -> 11530; 3839 -> 3844 [label=true]; 3839 -> 11527 [label=false]; 11528 -> 11529; 3844 -> 3849 [label=true]; 3844 -> 11526 [label=false]; 11527 -> 11528; 3849 -> 3854 [label=true]; 3849 -> 11525 [label=false]; 11526 -> 11527; 3854 -> 3859 [label=true]; 3854 -> 11524 [label=false]; 11525 -> 11526; 3859 -> 3864 [label=true]; 3859 -> 11523 [label=false]; 11524 -> 11525; 3864 -> 3869 [label=true]; 3864 -> 11522 [label=false]; 11523 -> 11524; 3869 -> 3874 [label=true]; 3869 -> 11521 [label=false]; 11522 -> 11523; 3874 -> 3879 [label=true]; 3874 -> 11520 [label=false]; 11521 -> 11522; 3879 -> 3884 [label=true]; 3879 -> 11519 [label=false]; 11520 -> 11521; 3884 -> 3889 [label=true]; 3884 -> 11518 [label=false]; 11519 -> 11520; 3889 -> 3894 [label=true]; 3889 -> 11517 [label=false]; 11518 -> 11519; 3894 -> 3899 [label=true]; 3894 -> 11516 [label=false]; 11517 -> 11518; 3899 -> 3904 [label=true]; 3899 -> 11515 [label=false]; 11516 -> 11517; 3904 -> 3909 [label=true]; 3904 -> 11514 [label=false]; 11515 -> 11516; 3909 -> 3914 [label=true]; 3909 -> 11513 [label=false]; 11514 -> 11515; 3914 -> 3919 [label=true]; 3914 -> 11512 [label=false]; 11513 -> 11514; 3919 -> 3924 [label=true]; 3919 -> 11511 [label=false]; 11512 -> 11513; 3924 -> 3929 [label=true]; 3924 -> 11510 [label=false]; 11511 -> 11512; 3929 -> 3934 [label=true]; 3929 -> 11509 [label=false]; 11510 -> 11511; 3934 -> 3939 [label=true]; 3934 -> 11508 [label=false]; 11509 -> 11510; 3939 -> 3944 [label=true]; 3939 -> 11507 [label=false]; 11508 -> 11509; 3944 -> 3949 [label=true]; 3944 -> 11506 [label=false]; 11507 -> 11508; 3949 -> 3954 [label=true]; 3949 -> 11505 [label=false]; 11506 -> 11507; 3954 -> 3959 [label=true]; 3954 -> 11504 [label=false]; 11505 -> 11506; 3959 -> 3964 [label=true]; 3959 -> 11503 [label=false]; 11504 -> 11505; 3964 -> 3969 [label=true]; 3964 -> 11502 [label=false]; 11503 -> 11504; 3969 -> 3974 [label=true]; 3969 -> 11501 [label=false]; 11502 -> 11503; 3974 -> 3979 [label=true]; 3974 -> 11500 [label=false]; 11501 -> 11502; 3979 -> 3984 [label=true]; 3979 -> 11499 [label=false]; 11500 -> 11501; 3984 -> 3989 [label=true]; 3984 -> 11498 [label=false]; 11499 -> 11500; 3989 -> 3994 [label=true]; 3989 -> 11497 [label=false]; 11498 -> 11499; 3994 -> 3999 [label=true]; 3994 -> 11496 [label=false]; 11497 -> 11498; 3999 -> 4004 [label=true]; 3999 -> 11495 [label=false]; 11496 -> 11497; 4004 -> 4009 [label=true]; 4004 -> 11494 [label=false]; 11495 -> 11496; 4009 -> 4014 [label=true]; 4009 -> 11493 [label=false]; 11494 -> 11495; 4014 -> 4019 [label=true]; 4014 -> 11492 [label=false]; 11493 -> 11494; 4019 -> 4024 [label=true]; 4019 -> 11491 [label=false]; 11492 -> 11493; 4024 -> 4029 [label=true]; 4024 -> 11490 [label=false]; 11491 -> 11492; 4029 -> 4034 [label=true]; 4029 -> 11489 [label=false]; 11490 -> 11491; 4034 -> 4039 [label=true]; 4034 -> 11488 [label=false]; 11489 -> 11490; 4039 -> 4044 [label=true]; 4039 -> 11487 [label=false]; 11488 -> 11489; 4044 -> 4049 [label=true]; 4044 -> 11486 [label=false]; 11487 -> 11488; 4049 -> 4054 [label=true]; 4049 -> 11485 [label=false]; 11486 -> 11487; 4054 -> 4059 [label=true]; 4054 -> 11484 [label=false]; 11485 -> 11486; 4059 -> 4064 [label=true]; 4059 -> 11483 [label=false]; 11484 -> 11485; 4064 -> 4069 [label=true]; 4064 -> 11482 [label=false]; 11483 -> 11484; 4069 -> 4074 [label=true]; 4069 -> 11481 [label=false]; 11482 -> 11483; 4074 -> 4079 [label=true]; 4074 -> 11480 [label=false]; 11481 -> 11482; 4079 -> 4084 [label=true]; 4079 -> 11479 [label=false]; 11480 -> 11481; 4084 -> 4089 [label=true]; 4084 -> 11478 [label=false]; 11479 -> 11480; 4089 -> 4094 [label=true]; 4089 -> 11477 [label=false]; 11478 -> 11479; 4094 -> 4099 [label=true]; 4094 -> 11476 [label=false]; 11477 -> 11478; 4099 -> 4104 [label=true]; 4099 -> 11475 [label=false]; 11476 -> 11477; 4104 -> 4109 [label=true]; 4104 -> 11474 [label=false]; 11475 -> 11476; 4109 -> 4114 [label=true]; 4109 -> 11473 [label=false]; 11474 -> 11475; 4114 -> 4119 [label=true]; 4114 -> 11472 [label=false]; 11473 -> 11474; 4119 -> 4124 [label=true]; 4119 -> 11471 [label=false]; 11472 -> 11473; 4124 -> 4129 [label=true]; 4124 -> 11470 [label=false]; 11471 -> 11472; 4129 -> 4134 [label=true]; 4129 -> 11469 [label=false]; 11470 -> 11471; 4134 -> 4139 [label=true]; 4134 -> 11468 [label=false]; 11469 -> 11470; 4139 -> 4144 [label=true]; 4139 -> 11467 [label=false]; 11468 -> 11469; 4144 -> 4149 [label=true]; 4144 -> 11466 [label=false]; 11467 -> 11468; 4149 -> 4154 [label=true]; 4149 -> 11465 [label=false]; 11466 -> 11467; 4154 -> 4159 [label=true]; 4154 -> 11464 [label=false]; 11465 -> 11466; 4159 -> 4164 [label=true]; 4159 -> 11463 [label=false]; 11464 -> 11465; 4164 -> 4169 [label=true]; 4164 -> 11462 [label=false]; 11463 -> 11464; 4169 -> 4174 [label=true]; 4169 -> 11461 [label=false]; 11462 -> 11463; 4174 -> 4179 [label=true]; 4174 -> 11460 [label=false]; 11461 -> 11462; 4179 -> 4184 [label=true]; 4179 -> 11459 [label=false]; 11460 -> 11461; 4184 -> 4189 [label=true]; 4184 -> 11458 [label=false]; 11459 -> 11460; 4189 -> 4194 [label=true]; 4189 -> 11457 [label=false]; 11458 -> 11459; 4194 -> 4199 [label=true]; 4194 -> 11456 [label=false]; 11457 -> 11458; 4199 -> 4204 [label=true]; 4199 -> 11455 [label=false]; 11456 -> 11457; 4204 -> 4209 [label=true]; 4204 -> 11454 [label=false]; 11455 -> 11456; 4209 -> 4214 [label=true]; 4209 -> 11453 [label=false]; 11454 -> 11455; 4214 -> 4219 [label=true]; 4214 -> 11452 [label=false]; 11453 -> 11454; 4219 -> 4224 [label=true]; 4219 -> 11451 [label=false]; 11452 -> 11453; 4224 -> 4229 [label=true]; 4224 -> 11450 [label=false]; 11451 -> 11452; 4229 -> 4234 [label=true]; 4229 -> 11449 [label=false]; 11450 -> 11451; 4234 -> 4239 [label=true]; 4234 -> 11448 [label=false]; 11449 -> 11450; 4239 -> 4244 [label=true]; 4239 -> 11447 [label=false]; 11448 -> 11449; 4244 -> 4249 [label=true]; 4244 -> 11446 [label=false]; 11447 -> 11448; 4249 -> 4254 [label=true]; 4249 -> 11445 [label=false]; 11446 -> 11447; 4254 -> 4259 [label=true]; 4254 -> 11444 [label=false]; 11445 -> 11446; 4259 -> 4264 [label=true]; 4259 -> 11443 [label=false]; 11444 -> 11445; 4264 -> 4269 [label=true]; 4264 -> 11442 [label=false]; 11443 -> 11444; 4269 -> 4274 [label=true]; 4269 -> 11441 [label=false]; 11442 -> 11443; 4274 -> 4279 [label=true]; 4274 -> 11440 [label=false]; 11441 -> 11442; 4279 -> 4284 [label=true]; 4279 -> 11439 [label=false]; 11440 -> 11441; 4284 -> 4289 [label=true]; 4284 -> 11438 [label=false]; 11439 -> 11440; 4289 -> 4294 [label=true]; 4289 -> 11437 [label=false]; 11438 -> 11439; 4294 -> 4299 [label=true]; 4294 -> 11436 [label=false]; 11437 -> 11438; 4299 -> 4304 [label=true]; 4299 -> 11435 [label=false]; 11436 -> 11437; 4304 -> 4309 [label=true]; 4304 -> 11434 [label=false]; 11435 -> 11436; 4309 -> 4314 [label=true]; 4309 -> 11433 [label=false]; 11434 -> 11435; 4314 -> 4319 [label=true]; 4314 -> 11432 [label=false]; 11433 -> 11434; 4319 -> 4324 [label=true]; 4319 -> 11431 [label=false]; 11432 -> 11433; 4324 -> 4329 [label=true]; 4324 -> 11430 [label=false]; 11431 -> 11432; 4329 -> 4334 [label=true]; 4329 -> 11429 [label=false]; 11430 -> 11431; 4334 -> 4339 [label=true]; 4334 -> 11428 [label=false]; 11429 -> 11430; 4339 -> 4344 [label=true]; 4339 -> 11427 [label=false]; 11428 -> 11429; 4344 -> 4349 [label=true]; 4344 -> 11426 [label=false]; 11427 -> 11428; 4349 -> 4354 [label=true]; 4349 -> 11425 [label=false]; 11426 -> 11427; 4354 -> 4359 [label=true]; 4354 -> 11424 [label=false]; 11425 -> 11426; 4359 -> 4364 [label=true]; 4359 -> 11423 [label=false]; 11424 -> 11425; 4364 -> 4369 [label=true]; 4364 -> 11422 [label=false]; 11423 -> 11424; 4369 -> 4374 [label=true]; 4369 -> 11421 [label=false]; 11422 -> 11423; 4374 -> 4379 [label=true]; 4374 -> 11420 [label=false]; 11421 -> 11422; 4379 -> 4384 [label=true]; 4379 -> 11419 [label=false]; 11420 -> 11421; 4384 -> 4389 [label=true]; 4384 -> 11418 [label=false]; 11419 -> 11420; 4389 -> 4394 [label=true]; 4389 -> 11417 [label=false]; 11418 -> 11419; 4394 -> 4399 [label=true]; 4394 -> 11416 [label=false]; 11417 -> 11418; 4399 -> 4404 [label=true]; 4399 -> 11415 [label=false]; 11416 -> 11417; 4404 -> 4409 [label=true]; 4404 -> 11414 [label=false]; 11415 -> 11416; 4409 -> 4414 [label=true]; 4409 -> 11413 [label=false]; 11414 -> 11415; 4414 -> 4419 [label=true]; 4414 -> 11412 [label=false]; 11413 -> 11414; 4419 -> 4424 [label=true]; 4419 -> 11411 [label=false]; 11412 -> 11413; 4424 -> 4429 [label=true]; 4424 -> 11410 [label=false]; 11411 -> 11412; 4429 -> 4434 [label=true]; 4429 -> 11409 [label=false]; 11410 -> 11411; 4434 -> 4439 [label=true]; 4434 -> 11408 [label=false]; 11409 -> 11410; 4439 -> 4444 [label=true]; 4439 -> 11407 [label=false]; 11408 -> 11409; 4444 -> 4449 [label=true]; 4444 -> 11406 [label=false]; 11407 -> 11408; 4449 -> 4454 [label=true]; 4449 -> 11405 [label=false]; 11406 -> 11407; 4454 -> 4459 [label=true]; 4454 -> 11404 [label=false]; 11405 -> 11406; 4459 -> 4464 [label=true]; 4459 -> 11403 [label=false]; 11404 -> 11405; 4464 -> 4469 [label=true]; 4464 -> 11402 [label=false]; 11403 -> 11404; 4469 -> 4474 [label=true]; 4469 -> 11401 [label=false]; 11402 -> 11403; 4474 -> 4479 [label=true]; 4474 -> 11400 [label=false]; 11401 -> 11402; 4479 -> 4484 [label=true]; 4479 -> 11399 [label=false]; 11400 -> 11401; 4484 -> 4489 [label=true]; 4484 -> 11398 [label=false]; 11399 -> 11400; 4489 -> 4494 [label=true]; 4489 -> 11397 [label=false]; 11398 -> 11399; 4494 -> 4499 [label=true]; 4494 -> 11396 [label=false]; 11397 -> 11398; 4499 -> 4504 [label=true]; 4499 -> 11395 [label=false]; 11396 -> 11397; 4504 -> 4509 [label=true]; 4504 -> 11394 [label=false]; 11395 -> 11396; 4509 -> 4514 [label=true]; 4509 -> 11393 [label=false]; 11394 -> 11395; 4514 -> 4519 [label=true]; 4514 -> 11392 [label=false]; 11393 -> 11394; 4519 -> 4524 [label=true]; 4519 -> 11391 [label=false]; 11392 -> 11393; 4524 -> 4529 [label=true]; 4524 -> 11390 [label=false]; 11391 -> 11392; 4529 -> 4534 [label=true]; 4529 -> 11389 [label=false]; 11390 -> 11391; 4534 -> 4539 [label=true]; 4534 -> 11388 [label=false]; 11389 -> 11390; 4539 -> 4544 [label=true]; 4539 -> 11387 [label=false]; 11388 -> 11389; 4544 -> 4549 [label=true]; 4544 -> 11386 [label=false]; 11387 -> 11388; 4549 -> 4554 [label=true]; 4549 -> 11385 [label=false]; 11386 -> 11387; 4554 -> 4559 [label=true]; 4554 -> 11384 [label=false]; 11385 -> 11386; 4559 -> 4564 [label=true]; 4559 -> 11383 [label=false]; 11384 -> 11385; 4564 -> 4569 [label=true]; 4564 -> 11382 [label=false]; 11383 -> 11384; 4569 -> 4574 [label=true]; 4569 -> 11381 [label=false]; 11382 -> 11383; 4574 -> 4579 [label=true]; 4574 -> 11380 [label=false]; 11381 -> 11382; 4579 -> 4584 [label=true]; 4579 -> 11379 [label=false]; 11380 -> 11381; 4584 -> 4589 [label=true]; 4584 -> 11378 [label=false]; 11379 -> 11380; 4589 -> 4594 [label=true]; 4589 -> 11377 [label=false]; 11378 -> 11379; 4594 -> 4599 [label=true]; 4594 -> 11376 [label=false]; 11377 -> 11378; 4599 -> 4604 [label=true]; 4599 -> 11375 [label=false]; 11376 -> 11377; 4604 -> 4609 [label=true]; 4604 -> 11374 [label=false]; 11375 -> 11376; 4609 -> 4614 [label=true]; 4609 -> 11373 [label=false]; 11374 -> 11375; 4614 -> 4619 [label=true]; 4614 -> 11372 [label=false]; 11373 -> 11374; 4619 -> 4624 [label=true]; 4619 -> 11371 [label=false]; 11372 -> 11373; 4624 -> 4629 [label=true]; 4624 -> 11370 [label=false]; 11371 -> 11372; 4629 -> 4634 [label=true]; 4629 -> 11369 [label=false]; 11370 -> 11371; 4634 -> 4639 [label=true]; 4634 -> 11368 [label=false]; 11369 -> 11370; 4639 -> 4644 [label=true]; 4639 -> 11367 [label=false]; 11368 -> 11369; 4644 -> 4649 [label=true]; 4644 -> 11366 [label=false]; 11367 -> 11368; 4649 -> 4654 [label=true]; 4649 -> 11365 [label=false]; 11366 -> 11367; 4654 -> 4659 [label=true]; 4654 -> 11364 [label=false]; 11365 -> 11366; 4659 -> 4664 [label=true]; 4659 -> 11363 [label=false]; 11364 -> 11365; 4664 -> 4669 [label=true]; 4664 -> 11362 [label=false]; 11363 -> 11364; 4669 -> 4674 [label=true]; 4669 -> 11361 [label=false]; 11362 -> 11363; 4674 -> 4679 [label=true]; 4674 -> 11360 [label=false]; 11361 -> 11362; 4679 -> 4684 [label=true]; 4679 -> 11359 [label=false]; 11360 -> 11361; 4684 -> 4689 [label=true]; 4684 -> 11358 [label=false]; 11359 -> 11360; 4689 -> 4694 [label=true]; 4689 -> 11357 [label=false]; 11358 -> 11359; 4694 -> 4699 [label=true]; 4694 -> 11356 [label=false]; 11357 -> 11358; 4699 -> 4704 [label=true]; 4699 -> 11355 [label=false]; 11356 -> 11357; 4704 -> 4709 [label=true]; 4704 -> 11354 [label=false]; 11355 -> 11356; 4709 -> 4714 [label=true]; 4709 -> 11353 [label=false]; 11354 -> 11355; 4714 -> 4719 [label=true]; 4714 -> 11352 [label=false]; 11353 -> 11354; 4719 -> 4724 [label=true]; 4719 -> 11351 [label=false]; 11352 -> 11353; 4724 -> 4729 [label=true]; 4724 -> 11350 [label=false]; 11351 -> 11352; 4729 -> 4734 [label=true]; 4729 -> 11349 [label=false]; 11350 -> 11351; 4734 -> 4739 [label=true]; 4734 -> 11348 [label=false]; 11349 -> 11350; 4739 -> 4744 [label=true]; 4739 -> 11347 [label=false]; 11348 -> 11349; 4744 -> 4749 [label=true]; 4744 -> 11346 [label=false]; 11347 -> 11348; 4749 -> 4754 [label=true]; 4749 -> 11345 [label=false]; 11346 -> 11347; 4754 -> 4759 [label=true]; 4754 -> 11344 [label=false]; 11345 -> 11346; 4759 -> 4764 [label=true]; 4759 -> 11343 [label=false]; 11344 -> 11345; 4764 -> 4769 [label=true]; 4764 -> 11342 [label=false]; 11343 -> 11344; 4769 -> 4774 [label=true]; 4769 -> 11341 [label=false]; 11342 -> 11343; 4774 -> 4779 [label=true]; 4774 -> 11340 [label=false]; 11341 -> 11342; 4779 -> 4784 [label=true]; 4779 -> 11339 [label=false]; 11340 -> 11341; 4784 -> 4789 [label=true]; 4784 -> 11338 [label=false]; 11339 -> 11340; 4789 -> 4794 [label=true]; 4789 -> 11337 [label=false]; 11338 -> 11339; 4794 -> 4799 [label=true]; 4794 -> 11336 [label=false]; 11337 -> 11338; 4799 -> 4804 [label=true]; 4799 -> 11335 [label=false]; 11336 -> 11337; 4804 -> 4809 [label=true]; 4804 -> 11334 [label=false]; 11335 -> 11336; 4809 -> 4814 [label=true]; 4809 -> 11333 [label=false]; 11334 -> 11335; 4814 -> 4819 [label=true]; 4814 -> 11332 [label=false]; 11333 -> 11334; 4819 -> 4824 [label=true]; 4819 -> 11331 [label=false]; 11332 -> 11333; 4824 -> 4829 [label=true]; 4824 -> 11330 [label=false]; 11331 -> 11332; 4829 -> 4834 [label=true]; 4829 -> 11329 [label=false]; 11330 -> 11331; 4834 -> 4839 [label=true]; 4834 -> 11328 [label=false]; 11329 -> 11330; 4839 -> 4844 [label=true]; 4839 -> 11327 [label=false]; 11328 -> 11329; 4844 -> 4849 [label=true]; 4844 -> 11326 [label=false]; 11327 -> 11328; 4849 -> 4854 [label=true]; 4849 -> 11325 [label=false]; 11326 -> 11327; 4854 -> 4859 [label=true]; 4854 -> 11324 [label=false]; 11325 -> 11326; 4859 -> 4864 [label=true]; 4859 -> 11323 [label=false]; 11324 -> 11325; 4864 -> 4869 [label=true]; 4864 -> 11322 [label=false]; 11323 -> 11324; 4869 -> 4874 [label=true]; 4869 -> 11321 [label=false]; 11322 -> 11323; 4874 -> 4879 [label=true]; 4874 -> 11320 [label=false]; 11321 -> 11322; 4879 -> 4884 [label=true]; 4879 -> 11319 [label=false]; 11320 -> 11321; 4884 -> 4889 [label=true]; 4884 -> 11318 [label=false]; 11319 -> 11320; 4889 -> 4894 [label=true]; 4889 -> 11317 [label=false]; 11318 -> 11319; 4894 -> 4899 [label=true]; 4894 -> 11316 [label=false]; 11317 -> 11318; 4899 -> 4904 [label=true]; 4899 -> 11315 [label=false]; 11316 -> 11317; 4904 -> 4909 [label=true]; 4904 -> 11314 [label=false]; 11315 -> 11316; 4909 -> 4914 [label=true]; 4909 -> 11313 [label=false]; 11314 -> 11315; 4914 -> 4919 [label=true]; 4914 -> 11312 [label=false]; 11313 -> 11314; 4919 -> 4924 [label=true]; 4919 -> 11311 [label=false]; 11312 -> 11313; 4924 -> 4929 [label=true]; 4924 -> 11310 [label=false]; 11311 -> 11312; 4929 -> 4934 [label=true]; 4929 -> 11309 [label=false]; 11310 -> 11311; 4934 -> 4939 [label=true]; 4934 -> 11308 [label=false]; 11309 -> 11310; 4939 -> 4944 [label=true]; 4939 -> 11307 [label=false]; 11308 -> 11309; 4944 -> 4949 [label=true]; 4944 -> 11306 [label=false]; 11307 -> 11308; 4949 -> 4954 [label=true]; 4949 -> 11305 [label=false]; 11306 -> 11307; 4954 -> 4959 [label=true]; 4954 -> 11304 [label=false]; 11305 -> 11306; 4959 -> 4964 [label=true]; 4959 -> 11303 [label=false]; 11304 -> 11305; 4964 -> 4969 [label=true]; 4964 -> 11302 [label=false]; 11303 -> 11304; 4969 -> 4974 [label=true]; 4969 -> 11301 [label=false]; 11302 -> 11303; 4974 -> 4979 [label=true]; 4974 -> 11300 [label=false]; 11301 -> 11302; 4979 -> 4984 [label=true]; 4979 -> 11299 [label=false]; 11300 -> 11301; 4984 -> 4989 [label=true]; 4984 -> 11298 [label=false]; 11299 -> 11300; 4989 -> 4994 [label=true]; 4989 -> 11297 [label=false]; 11298 -> 11299; 4994 -> 4999 [label=true]; 4994 -> 11296 [label=false]; 11297 -> 11298; 4999 -> 5004 [label=true]; 4999 -> 11295 [label=false]; 11296 -> 11297; 5004 -> 5009 [label=true]; 5004 -> 11294 [label=false]; 11295 -> 11296; 5009 -> 5014 [label=true]; 5009 -> 11293 [label=false]; 11294 -> 11295; 5014 -> 5019 [label=true]; 5014 -> 11292 [label=false]; 11293 -> 11294; 5019 -> 5024 [label=true]; 5019 -> 11291 [label=false]; 11292 -> 11293; 5024 -> 5029 [label=true]; 5024 -> 11290 [label=false]; 11291 -> 11292; 5029 -> 5034 [label=true]; 5029 -> 11289 [label=false]; 11290 -> 11291; 5034 -> 5039 [label=true]; 5034 -> 11288 [label=false]; 11289 -> 11290; 5039 -> 5044 [label=true]; 5039 -> 11287 [label=false]; 11288 -> 11289; 5044 -> 5049 [label=true]; 5044 -> 11286 [label=false]; 11287 -> 11288; 5049 -> 5054 [label=true]; 5049 -> 11285 [label=false]; 11286 -> 11287; 5054 -> 5059 [label=true]; 5054 -> 11284 [label=false]; 11285 -> 11286; 5059 -> 5064 [label=true]; 5059 -> 11283 [label=false]; 11284 -> 11285; 5064 -> 5069 [label=true]; 5064 -> 11282 [label=false]; 11283 -> 11284; 5069 -> 5074 [label=true]; 5069 -> 11281 [label=false]; 11282 -> 11283; 5074 -> 5079 [label=true]; 5074 -> 11280 [label=false]; 11281 -> 11282; 5079 -> 5084 [label=true]; 5079 -> 11279 [label=false]; 11280 -> 11281; 5084 -> 5089 [label=true]; 5084 -> 11278 [label=false]; 11279 -> 11280; 5089 -> 5094 [label=true]; 5089 -> 11277 [label=false]; 11278 -> 11279; 5094 -> 5099 [label=true]; 5094 -> 11276 [label=false]; 11277 -> 11278; 5099 -> 5104 [label=true]; 5099 -> 11275 [label=false]; 11276 -> 11277; 5104 -> 5109 [label=true]; 5104 -> 11274 [label=false]; 11275 -> 11276; 5109 -> 5114 [label=true]; 5109 -> 11273 [label=false]; 11274 -> 11275; 5114 -> 5119 [label=true]; 5114 -> 11272 [label=false]; 11273 -> 11274; 5119 -> 5124 [label=true]; 5119 -> 11271 [label=false]; 11272 -> 11273; 5124 -> 5129 [label=true]; 5124 -> 11270 [label=false]; 11271 -> 11272; 5129 -> 5134 [label=true]; 5129 -> 11269 [label=false]; 11270 -> 11271; 5134 -> 5139 [label=true]; 5134 -> 11268 [label=false]; 11269 -> 11270; 5139 -> 5144 [label=true]; 5139 -> 11267 [label=false]; 11268 -> 11269; 5144 -> 5149 [label=true]; 5144 -> 11266 [label=false]; 11267 -> 11268; 5149 -> 5154 [label=true]; 5149 -> 11265 [label=false]; 11266 -> 11267; 5154 -> 5159 [label=true]; 5154 -> 11264 [label=false]; 11265 -> 11266; 5159 -> 5164 [label=true]; 5159 -> 11263 [label=false]; 11264 -> 11265; 5164 -> 5169 [label=true]; 5164 -> 11262 [label=false]; 11263 -> 11264; 5169 -> 5174 [label=true]; 5169 -> 11261 [label=false]; 11262 -> 11263; 5174 -> 5179 [label=true]; 5174 -> 11260 [label=false]; 11261 -> 11262; 5179 -> 5184 [label=true]; 5179 -> 11259 [label=false]; 11260 -> 11261; 5184 -> 5189 [label=true]; 5184 -> 11258 [label=false]; 11259 -> 11260; 5189 -> 5194 [label=true]; 5189 -> 11257 [label=false]; 11258 -> 11259; 5194 -> 5199 [label=true]; 5194 -> 11256 [label=false]; 11257 -> 11258; 5199 -> 5204 [label=true]; 5199 -> 11255 [label=false]; 11256 -> 11257; 5204 -> 5209 [label=true]; 5204 -> 11254 [label=false]; 11255 -> 11256; 5209 -> 5214 [label=true]; 5209 -> 11253 [label=false]; 11254 -> 11255; 5214 -> 5219 [label=true]; 5214 -> 11252 [label=false]; 11253 -> 11254; 5219 -> 5224 [label=true]; 5219 -> 11251 [label=false]; 11252 -> 11253; 5224 -> 5229 [label=true]; 5224 -> 11250 [label=false]; 11251 -> 11252; 5229 -> 5234 [label=true]; 5229 -> 11249 [label=false]; 11250 -> 11251; 5234 -> 5239 [label=true]; 5234 -> 11248 [label=false]; 11249 -> 11250; 5239 -> 5244 [label=true]; 5239 -> 11247 [label=false]; 11248 -> 11249; 5244 -> 5249 [label=true]; 5244 -> 11246 [label=false]; 11247 -> 11248; 5249 -> 5254 [label=true]; 5249 -> 11245 [label=false]; 11246 -> 11247; 5254 -> 5259 [label=true]; 5254 -> 11244 [label=false]; 11245 -> 11246; 5259 -> 5264 [label=true]; 5259 -> 11243 [label=false]; 11244 -> 11245; 5264 -> 5269 [label=true]; 5264 -> 11242 [label=false]; 11243 -> 11244; 5269 -> 5274 [label=true]; 5269 -> 11241 [label=false]; 11242 -> 11243; 5274 -> 5279 [label=true]; 5274 -> 11240 [label=false]; 11241 -> 11242; 5279 -> 5284 [label=true]; 5279 -> 11239 [label=false]; 11240 -> 11241; 5284 -> 5289 [label=true]; 5284 -> 11238 [label=false]; 11239 -> 11240; 5289 -> 5294 [label=true]; 5289 -> 11237 [label=false]; 11238 -> 11239; 5294 -> 5299 [label=true]; 5294 -> 11236 [label=false]; 11237 -> 11238; 5299 -> 5304 [label=true]; 5299 -> 11235 [label=false]; 11236 -> 11237; 5304 -> 5309 [label=true]; 5304 -> 11234 [label=false]; 11235 -> 11236; 5309 -> 5314 [label=true]; 5309 -> 11233 [label=false]; 11234 -> 11235; 5314 -> 5319 [label=true]; 5314 -> 11232 [label=false]; 11233 -> 11234; 5319 -> 5324 [label=true]; 5319 -> 11231 [label=false]; 11232 -> 11233; 5324 -> 5329 [label=true]; 5324 -> 11230 [label=false]; 11231 -> 11232; 5329 -> 5334 [label=true]; 5329 -> 11229 [label=false]; 11230 -> 11231; 5334 -> 5339 [label=true]; 5334 -> 11228 [label=false]; 11229 -> 11230; 5339 -> 5344 [label=true]; 5339 -> 11227 [label=false]; 11228 -> 11229; 5344 -> 5349 [label=true]; 5344 -> 11226 [label=false]; 11227 -> 11228; 5349 -> 5354 [label=true]; 5349 -> 11225 [label=false]; 11226 -> 11227; 5354 -> 5359 [label=true]; 5354 -> 11224 [label=false]; 11225 -> 11226; 5359 -> 5364 [label=true]; 5359 -> 11223 [label=false]; 11224 -> 11225; 5364 -> 5369 [label=true]; 5364 -> 11222 [label=false]; 11223 -> 11224; 5369 -> 5374 [label=true]; 5369 -> 11221 [label=false]; 11222 -> 11223; 5374 -> 5379 [label=true]; 5374 -> 11220 [label=false]; 11221 -> 11222; 5379 -> 5384 [label=true]; 5379 -> 11219 [label=false]; 11220 -> 11221; 5384 -> 5389 [label=true]; 5384 -> 11218 [label=false]; 11219 -> 11220; 5389 -> 5394 [label=true]; 5389 -> 11217 [label=false]; 11218 -> 11219; 5394 -> 5399 [label=true]; 5394 -> 11216 [label=false]; 11217 -> 11218; 5399 -> 5404 [label=true]; 5399 -> 11215 [label=false]; 11216 -> 11217; 5404 -> 5409 [label=true]; 5404 -> 11214 [label=false]; 11215 -> 11216; 5409 -> 5414 [label=true]; 5409 -> 11213 [label=false]; 11214 -> 11215; 5414 -> 5419 [label=true]; 5414 -> 11212 [label=false]; 11213 -> 11214; 5419 -> 5424 [label=true]; 5419 -> 11211 [label=false]; 11212 -> 11213; 5424 -> 5429 [label=true]; 5424 -> 11210 [label=false]; 11211 -> 11212; 5429 -> 5434 [label=true]; 5429 -> 11209 [label=false]; 11210 -> 11211; 5434 -> 5439 [label=true]; 5434 -> 11208 [label=false]; 11209 -> 11210; 5439 -> 5444 [label=true]; 5439 -> 11207 [label=false]; 11208 -> 11209; 5444 -> 5449 [label=true]; 5444 -> 11206 [label=false]; 11207 -> 11208; 5449 -> 5454 [label=true]; 5449 -> 11205 [label=false]; 11206 -> 11207; 5454 -> 5459 [label=true]; 5454 -> 11204 [label=false]; 11205 -> 11206; 5459 -> 5464 [label=true]; 5459 -> 11203 [label=false]; 11204 -> 11205; 5464 -> 5469 [label=true]; 5464 -> 11202 [label=false]; 11203 -> 11204; 5469 -> 5474 [label=true]; 5469 -> 11201 [label=false]; 11202 -> 11203; 5474 -> 5479 [label=true]; 5474 -> 11200 [label=false]; 11201 -> 11202; 5479 -> 5484 [label=true]; 5479 -> 11199 [label=false]; 11200 -> 11201; 5484 -> 5489 [label=true]; 5484 -> 11198 [label=false]; 11199 -> 11200; 5489 -> 5494 [label=true]; 5489 -> 11197 [label=false]; 11198 -> 11199; 5494 -> 5499 [label=true]; 5494 -> 11196 [label=false]; 11197 -> 11198; 5499 -> 5504 [label=true]; 5499 -> 11195 [label=false]; 11196 -> 11197; 5504 -> 5509 [label=true]; 5504 -> 11194 [label=false]; 11195 -> 11196; 5509 -> 5514 [label=true]; 5509 -> 11193 [label=false]; 11194 -> 11195; 5514 -> 5519 [label=true]; 5514 -> 11192 [label=false]; 11193 -> 11194; 5519 -> 5524 [label=true]; 5519 -> 11191 [label=false]; 11192 -> 11193; 5524 -> 5529 [label=true]; 5524 -> 11190 [label=false]; 11191 -> 11192; 5529 -> 5534 [label=true]; 5529 -> 11189 [label=false]; 11190 -> 11191; 5534 -> 5539 [label=true]; 5534 -> 11188 [label=false]; 11189 -> 11190; 5539 -> 5544 [label=true]; 5539 -> 11187 [label=false]; 11188 -> 11189; 5544 -> 5549 [label=true]; 5544 -> 11186 [label=false]; 11187 -> 11188; 5549 -> 5554 [label=true]; 5549 -> 11185 [label=false]; 11186 -> 11187; 5554 -> 5559 [label=true]; 5554 -> 11184 [label=false]; 11185 -> 11186; 5559 -> 5564 [label=true]; 5559 -> 11183 [label=false]; 11184 -> 11185; 5564 -> 5569 [label=true]; 5564 -> 11182 [label=false]; 11183 -> 11184; 5569 -> 5574 [label=true]; 5569 -> 11181 [label=false]; 11182 -> 11183; 5574 -> 5579 [label=true]; 5574 -> 11180 [label=false]; 11181 -> 11182; 5579 -> 5584 [label=true]; 5579 -> 11179 [label=false]; 11180 -> 11181; 5584 -> 5589 [label=true]; 5584 -> 11178 [label=false]; 11179 -> 11180; 5589 -> 5594 [label=true]; 5589 -> 11177 [label=false]; 11178 -> 11179; 5594 -> 5599 [label=true]; 5594 -> 11176 [label=false]; 11177 -> 11178; 5599 -> 5604 [label=true]; 5599 -> 11175 [label=false]; 11176 -> 11177; 5604 -> 5609 [label=true]; 5604 -> 11174 [label=false]; 11175 -> 11176; 5609 -> 5614 [label=true]; 5609 -> 11173 [label=false]; 11174 -> 11175; 5614 -> 5619 [label=true]; 5614 -> 11172 [label=false]; 11173 -> 11174; 5619 -> 5624 [label=true]; 5619 -> 11171 [label=false]; 11172 -> 11173; 5624 -> 5629 [label=true]; 5624 -> 11170 [label=false]; 11171 -> 11172; 5629 -> 5634 [label=true]; 5629 -> 11169 [label=false]; 11170 -> 11171; 5634 -> 5639 [label=true]; 5634 -> 11168 [label=false]; 11169 -> 11170; 5639 -> 5644 [label=true]; 5639 -> 11167 [label=false]; 11168 -> 11169; 5644 -> 5649 [label=true]; 5644 -> 11166 [label=false]; 11167 -> 11168; 5649 -> 5654 [label=true]; 5649 -> 11165 [label=false]; 11166 -> 11167; 5654 -> 5659 [label=true]; 5654 -> 11164 [label=false]; 11165 -> 11166; 5659 -> 5664 [label=true]; 5659 -> 11163 [label=false]; 11164 -> 11165; 5664 -> 5669 [label=true]; 5664 -> 11162 [label=false]; 11163 -> 11164; 5669 -> 5674 [label=true]; 5669 -> 11161 [label=false]; 11162 -> 11163; 5674 -> 5679 [label=true]; 5674 -> 11160 [label=false]; 11161 -> 11162; 5679 -> 5684 [label=true]; 5679 -> 11159 [label=false]; 11160 -> 11161; 5684 -> 5689 [label=true]; 5684 -> 11158 [label=false]; 11159 -> 11160; 5689 -> 5694 [label=true]; 5689 -> 11157 [label=false]; 11158 -> 11159; 5694 -> 5699 [label=true]; 5694 -> 11156 [label=false]; 11157 -> 11158; 5699 -> 5704 [label=true]; 5699 -> 11155 [label=false]; 11156 -> 11157; 5704 -> 5709 [label=true]; 5704 -> 11154 [label=false]; 11155 -> 11156; 5709 -> 5714 [label=true]; 5709 -> 11153 [label=false]; 11154 -> 11155; 5714 -> 5719 [label=true]; 5714 -> 11152 [label=false]; 11153 -> 11154; 5719 -> 5724 [label=true]; 5719 -> 11151 [label=false]; 11152 -> 11153; 5724 -> 5729 [label=true]; 5724 -> 11150 [label=false]; 11151 -> 11152; 5729 -> 5734 [label=true]; 5729 -> 11149 [label=false]; 11150 -> 11151; 5734 -> 5739 [label=true]; 5734 -> 11148 [label=false]; 11149 -> 11150; 5739 -> 5744 [label=true]; 5739 -> 11147 [label=false]; 11148 -> 11149; 5744 -> 5749 [label=true]; 5744 -> 11146 [label=false]; 11147 -> 11148; 5749 -> 5754 [label=true]; 5749 -> 11145 [label=false]; 11146 -> 11147; 5754 -> 5759 [label=true]; 5754 -> 11144 [label=false]; 11145 -> 11146; 5759 -> 5764 [label=true]; 5759 -> 11143 [label=false]; 11144 -> 11145; 5764 -> 5769 [label=true]; 5764 -> 11142 [label=false]; 11143 -> 11144; 5769 -> 5774 [label=true]; 5769 -> 11141 [label=false]; 11142 -> 11143; 5774 -> 5779 [label=true]; 5774 -> 11140 [label=false]; 11141 -> 11142; 5779 -> 5784 [label=true]; 5779 -> 11139 [label=false]; 11140 -> 11141; 5784 -> 5789 [label=true]; 5784 -> 11138 [label=false]; 11139 -> 11140; 5789 -> 5794 [label=true]; 5789 -> 11137 [label=false]; 11138 -> 11139; 5794 -> 5799 [label=true]; 5794 -> 11136 [label=false]; 11137 -> 11138; 5799 -> 5804 [label=true]; 5799 -> 11135 [label=false]; 11136 -> 11137; 5804 -> 5809 [label=true]; 5804 -> 11134 [label=false]; 11135 -> 11136; 5809 -> 5814 [label=true]; 5809 -> 11133 [label=false]; 11134 -> 11135; 5814 -> 5819 [label=true]; 5814 -> 11132 [label=false]; 11133 -> 11134; 5819 -> 5824 [label=true]; 5819 -> 11131 [label=false]; 11132 -> 11133; 5824 -> 5829 [label=true]; 5824 -> 11130 [label=false]; 11131 -> 11132; 5829 -> 5834 [label=true]; 5829 -> 11129 [label=false]; 11130 -> 11131; 5834 -> 5839 [label=true]; 5834 -> 11128 [label=false]; 11129 -> 11130; 5839 -> 5844 [label=true]; 5839 -> 11127 [label=false]; 11128 -> 11129; 5844 -> 5849 [label=true]; 5844 -> 11126 [label=false]; 11127 -> 11128; 5849 -> 5854 [label=true]; 5849 -> 11125 [label=false]; 11126 -> 11127; 5854 -> 5859 [label=true]; 5854 -> 11124 [label=false]; 11125 -> 11126; 5859 -> 5864 [label=true]; 5859 -> 11123 [label=false]; 11124 -> 11125; 5864 -> 5869 [label=true]; 5864 -> 11122 [label=false]; 11123 -> 11124; 5869 -> 5874 [label=true]; 5869 -> 11121 [label=false]; 11122 -> 11123; 5874 -> 5879 [label=true]; 5874 -> 11120 [label=false]; 11121 -> 11122; 5879 -> 5884 [label=true]; 5879 -> 11119 [label=false]; 11120 -> 11121; 5884 -> 5889 [label=true]; 5884 -> 11118 [label=false]; 11119 -> 11120; 5889 -> 5894 [label=true]; 5889 -> 11117 [label=false]; 11118 -> 11119; 5894 -> 5899 [label=true]; 5894 -> 11116 [label=false]; 11117 -> 11118; 5899 -> 5904 [label=true]; 5899 -> 11115 [label=false]; 11116 -> 11117; 5904 -> 5909 [label=true]; 5904 -> 11114 [label=false]; 11115 -> 11116; 5909 -> 5914 [label=true]; 5909 -> 11113 [label=false]; 11114 -> 11115; 5914 -> 5919 [label=true]; 5914 -> 11112 [label=false]; 11113 -> 11114; 5919 -> 5924 [label=true]; 5919 -> 11111 [label=false]; 11112 -> 11113; 5924 -> 5929 [label=true]; 5924 -> 11110 [label=false]; 11111 -> 11112; 5929 -> 5934 [label=true]; 5929 -> 11109 [label=false]; 11110 -> 11111; 5934 -> 5939 [label=true]; 5934 -> 11108 [label=false]; 11109 -> 11110; 5939 -> 5944 [label=true]; 5939 -> 11107 [label=false]; 11108 -> 11109; 5944 -> 5949 [label=true]; 5944 -> 11106 [label=false]; 11107 -> 11108; 5949 -> 5954 [label=true]; 5949 -> 11105 [label=false]; 11106 -> 11107; 5954 -> 5959 [label=true]; 5954 -> 11104 [label=false]; 11105 -> 11106; 5959 -> 5964 [label=true]; 5959 -> 11103 [label=false]; 11104 -> 11105; 5964 -> 5969 [label=true]; 5964 -> 11102 [label=false]; 11103 -> 11104; 5969 -> 5974 [label=true]; 5969 -> 11101 [label=false]; 11102 -> 11103; 5974 -> 5979 [label=true]; 5974 -> 11100 [label=false]; 11101 -> 11102; 5979 -> 5984 [label=true]; 5979 -> 11099 [label=false]; 11100 -> 11101; 5984 -> 5989 [label=true]; 5984 -> 11098 [label=false]; 11099 -> 11100; 5989 -> 5994 [label=true]; 5989 -> 11097 [label=false]; 11098 -> 11099; 5994 -> 5999 [label=true]; 5994 -> 11096 [label=false]; 11097 -> 11098; 5999 -> 6004 [label=true]; 5999 -> 11095 [label=false]; 11096 -> 11097; 6004 -> 6009 [label=true]; 6004 -> 11094 [label=false]; 11095 -> 11096; 6009 -> 6014 [label=true]; 6009 -> 11093 [label=false]; 11094 -> 11095; 6014 -> 6019 [label=true]; 6014 -> 11092 [label=false]; 11093 -> 11094; 6019 -> 6024 [label=true]; 6019 -> 11091 [label=false]; 11092 -> 11093; 6024 -> 6029 [label=true]; 6024 -> 11090 [label=false]; 11091 -> 11092; 6029 -> 6034 [label=true]; 6029 -> 11089 [label=false]; 11090 -> 11091; 6034 -> 6039 [label=true]; 6034 -> 11088 [label=false]; 11089 -> 11090; 6039 -> 6044 [label=true]; 6039 -> 11087 [label=false]; 11088 -> 11089; 6044 -> 6049 [label=true]; 6044 -> 11086 [label=false]; 11087 -> 11088; 6049 -> 6054 [label=true]; 6049 -> 11085 [label=false]; 11086 -> 11087; 6054 -> 6059 [label=true]; 6054 -> 11084 [label=false]; 11085 -> 11086; 6059 -> 6064 [label=true]; 6059 -> 11083 [label=false]; 11084 -> 11085; 6064 -> 6069 [label=true]; 6064 -> 11082 [label=false]; 11083 -> 11084; 6069 -> 6074 [label=true]; 6069 -> 11081 [label=false]; 11082 -> 11083; 6074 -> 6079 [label=true]; 6074 -> 11080 [label=false]; 11081 -> 11082; 6079 -> 6084 [label=true]; 6079 -> 11079 [label=false]; 11080 -> 11081; 6084 -> 6089 [label=true]; 6084 -> 11078 [label=false]; 11079 -> 11080; 6089 -> 6094 [label=true]; 6089 -> 11077 [label=false]; 11078 -> 11079; 6094 -> 6099 [label=true]; 6094 -> 11076 [label=false]; 11077 -> 11078; 6099 -> 6104 [label=true]; 6099 -> 11075 [label=false]; 11076 -> 11077; 6104 -> 6109 [label=true]; 6104 -> 11074 [label=false]; 11075 -> 11076; 6109 -> 6114 [label=true]; 6109 -> 11073 [label=false]; 11074 -> 11075; 6114 -> 6119 [label=true]; 6114 -> 11072 [label=false]; 11073 -> 11074; 6119 -> 6124 [label=true]; 6119 -> 11071 [label=false]; 11072 -> 11073; 6124 -> 6129 [label=true]; 6124 -> 11070 [label=false]; 11071 -> 11072; 6129 -> 6134 [label=true]; 6129 -> 11069 [label=false]; 11070 -> 11071; 6134 -> 6139 [label=true]; 6134 -> 11068 [label=false]; 11069 -> 11070; 6139 -> 6144 [label=true]; 6139 -> 11067 [label=false]; 11068 -> 11069; 6144 -> 6149 [label=true]; 6144 -> 11066 [label=false]; 11067 -> 11068; 6149 -> 6154 [label=true]; 6149 -> 11065 [label=false]; 11066 -> 11067; 6154 -> 6159 [label=true]; 6154 -> 11064 [label=false]; 11065 -> 11066; 6159 -> 6164 [label=true]; 6159 -> 11063 [label=false]; 11064 -> 11065; 6164 -> 6169 [label=true]; 6164 -> 11062 [label=false]; 11063 -> 11064; 6169 -> 6174 [label=true]; 6169 -> 11061 [label=false]; 11062 -> 11063; 6174 -> 6179 [label=true]; 6174 -> 11060 [label=false]; 11061 -> 11062; 6179 -> 6184 [label=true]; 6179 -> 11059 [label=false]; 11060 -> 11061; 6184 -> 6189 [label=true]; 6184 -> 11058 [label=false]; 11059 -> 11060; 6189 -> 6194 [label=true]; 6189 -> 11057 [label=false]; 11058 -> 11059; 6194 -> 6199 [label=true]; 6194 -> 11056 [label=false]; 11057 -> 11058; 6199 -> 6204 [label=true]; 6199 -> 11055 [label=false]; 11056 -> 11057; 6204 -> 6209 [label=true]; 6204 -> 11054 [label=false]; 11055 -> 11056; 6209 -> 6214 [label=true]; 6209 -> 11053 [label=false]; 11054 -> 11055; 6214 -> 6219 [label=true]; 6214 -> 11052 [label=false]; 11053 -> 11054; 6219 -> 6224 [label=true]; 6219 -> 11051 [label=false]; 11052 -> 11053; 6224 -> 6229 [label=true]; 6224 -> 11050 [label=false]; 11051 -> 11052; 6229 -> 6234 [label=true]; 6229 -> 11049 [label=false]; 11050 -> 11051; 6234 -> 6239 [label=true]; 6234 -> 11048 [label=false]; 11049 -> 11050; 6239 -> 6244 [label=true]; 6239 -> 11047 [label=false]; 11048 -> 11049; 6244 -> 6249 [label=true]; 6244 -> 11046 [label=false]; 11047 -> 11048; 6249 -> 6254 [label=true]; 6249 -> 11045 [label=false]; 11046 -> 11047; 6254 -> 6259 [label=true]; 6254 -> 11044 [label=false]; 11045 -> 11046; 6259 -> 6264 [label=true]; 6259 -> 11043 [label=false]; 11044 -> 11045; 6264 -> 6269 [label=true]; 6264 -> 11042 [label=false]; 11043 -> 11044; 6269 -> 6274 [label=true]; 6269 -> 11041 [label=false]; 11042 -> 11043; 6274 -> 6279 [label=true]; 6274 -> 11040 [label=false]; 11041 -> 11042; 6279 -> 6284 [label=true]; 6279 -> 11039 [label=false]; 11040 -> 11041; 6284 -> 6289 [label=true]; 6284 -> 11038 [label=false]; 11039 -> 11040; 6289 -> 6294 [label=true]; 6289 -> 11037 [label=false]; 11038 -> 11039; 6294 -> 6299 [label=true]; 6294 -> 11036 [label=false]; 11037 -> 11038; 6299 -> 6304 [label=true]; 6299 -> 11035 [label=false]; 11036 -> 11037; 6304 -> 6309 [label=true]; 6304 -> 11034 [label=false]; 11035 -> 11036; 6309 -> 6314 [label=true]; 6309 -> 11033 [label=false]; 11034 -> 11035; 6314 -> 6319 [label=true]; 6314 -> 11032 [label=false]; 11033 -> 11034; 6319 -> 6324 [label=true]; 6319 -> 11031 [label=false]; 11032 -> 11033; 6324 -> 6329 [label=true]; 6324 -> 11030 [label=false]; 11031 -> 11032; 6329 -> 6334 [label=true]; 6329 -> 11029 [label=false]; 11030 -> 11031; 6334 -> 6339 [label=true]; 6334 -> 11028 [label=false]; 11029 -> 11030; 6339 -> 6344 [label=true]; 6339 -> 11027 [label=false]; 11028 -> 11029; 6344 -> 6349 [label=true]; 6344 -> 11026 [label=false]; 11027 -> 11028; 6349 -> 6354 [label=true]; 6349 -> 11025 [label=false]; 11026 -> 11027; 6354 -> 6359 [label=true]; 6354 -> 11024 [label=false]; 11025 -> 11026; 6359 -> 6364 [label=true]; 6359 -> 11023 [label=false]; 11024 -> 11025; 6364 -> 6369 [label=true]; 6364 -> 11022 [label=false]; 11023 -> 11024; 6369 -> 6374 [label=true]; 6369 -> 11021 [label=false]; 11022 -> 11023; 6374 -> 6379 [label=true]; 6374 -> 11020 [label=false]; 11021 -> 11022; 6379 -> 6384 [label=true]; 6379 -> 11019 [label=false]; 11020 -> 11021; 6384 -> 6389 [label=true]; 6384 -> 11018 [label=false]; 11019 -> 11020; 6389 -> 6394 [label=true]; 6389 -> 11017 [label=false]; 11018 -> 11019; 6394 -> 6399 [label=true]; 6394 -> 11016 [label=false]; 11017 -> 11018; 6399 -> 6404 [label=true]; 6399 -> 11015 [label=false]; 11016 -> 11017; 6404 -> 6409 [label=true]; 6404 -> 11014 [label=false]; 11015 -> 11016; 6409 -> 6414 [label=true]; 6409 -> 11013 [label=false]; 11014 -> 11015; 6414 -> 6419 [label=true]; 6414 -> 11012 [label=false]; 11013 -> 11014; 6419 -> 6424 [label=true]; 6419 -> 11011 [label=false]; 11012 -> 11013; 6424 -> 6429 [label=true]; 6424 -> 11010 [label=false]; 11011 -> 11012; 6429 -> 6434 [label=true]; 6429 -> 11009 [label=false]; 11010 -> 11011; 6434 -> 6439 [label=true]; 6434 -> 11008 [label=false]; 11009 -> 11010; 6439 -> 6444 [label=true]; 6439 -> 11007 [label=false]; 11008 -> 11009; 6444 -> 6449 [label=true]; 6444 -> 11006 [label=false]; 11007 -> 11008; 6449 -> 6454 [label=true]; 6449 -> 11005 [label=false]; 11006 -> 11007; 6454 -> 6459 [label=true]; 6454 -> 11004 [label=false]; 11005 -> 11006; 6459 -> 6464 [label=true]; 6459 -> 11003 [label=false]; 11004 -> 11005; 6464 -> 6469 [label=true]; 6464 -> 11002 [label=false]; 11003 -> 11004; 6469 -> 6474 [label=true]; 6469 -> 11001 [label=false]; 11002 -> 11003; 6474 -> 6479 [label=true]; 6474 -> 11000 [label=false]; 11001 -> 11002; 6479 -> 6484 [label=true]; 6479 -> 10999 [label=false]; 11000 -> 11001; 6484 -> 6489 [label=true]; 6484 -> 10998 [label=false]; 10999 -> 11000; 6489 -> 6494 [label=true]; 6489 -> 10997 [label=false]; 10998 -> 10999; 6494 -> 6499 [label=true]; 6494 -> 10996 [label=false]; 10997 -> 10998; 6499 -> 6504 [label=true]; 6499 -> 10995 [label=false]; 10996 -> 10997; 6504 -> 6509 [label=true]; 6504 -> 10994 [label=false]; 10995 -> 10996; 6509 -> 6514 [label=true]; 6509 -> 10993 [label=false]; 10994 -> 10995; 6514 -> 6519 [label=true]; 6514 -> 10992 [label=false]; 10993 -> 10994; 6519 -> 6524 [label=true]; 6519 -> 10991 [label=false]; 10992 -> 10993; 6524 -> 6529 [label=true]; 6524 -> 10990 [label=false]; 10991 -> 10992; 6529 -> 6534 [label=true]; 6529 -> 10989 [label=false]; 10990 -> 10991; 6534 -> 6539 [label=true]; 6534 -> 10988 [label=false]; 10989 -> 10990; 6539 -> 6544 [label=true]; 6539 -> 10987 [label=false]; 10988 -> 10989; 6544 -> 6549 [label=true]; 6544 -> 10986 [label=false]; 10987 -> 10988; 6549 -> 6554 [label=true]; 6549 -> 10985 [label=false]; 10986 -> 10987; 6554 -> 6559 [label=true]; 6554 -> 10984 [label=false]; 10985 -> 10986; 6559 -> 6564 [label=true]; 6559 -> 10983 [label=false]; 10984 -> 10985; 6564 -> 6569 [label=true]; 6564 -> 10982 [label=false]; 10983 -> 10984; 6569 -> 6574 [label=true]; 6569 -> 10981 [label=false]; 10982 -> 10983; 6574 -> 6579 [label=true]; 6574 -> 10980 [label=false]; 10981 -> 10982; 6579 -> 6584 [label=true]; 6579 -> 10979 [label=false]; 10980 -> 10981; 6584 -> 6589 [label=true]; 6584 -> 10978 [label=false]; 10979 -> 10980; 6589 -> 6594 [label=true]; 6589 -> 10977 [label=false]; 10978 -> 10979; 6594 -> 6599 [label=true]; 6594 -> 10976 [label=false]; 10977 -> 10978; 6599 -> 6604 [label=true]; 6599 -> 10975 [label=false]; 10976 -> 10977; 6604 -> 6609 [label=true]; 6604 -> 10974 [label=false]; 10975 -> 10976; 6609 -> 6614 [label=true]; 6609 -> 10973 [label=false]; 10974 -> 10975; 6614 -> 6619 [label=true]; 6614 -> 10972 [label=false]; 10973 -> 10974; 6619 -> 6624 [label=true]; 6619 -> 10971 [label=false]; 10972 -> 10973; 6624 -> 6629 [label=true]; 6624 -> 10970 [label=false]; 10971 -> 10972; 6629 -> 6634 [label=true]; 6629 -> 10969 [label=false]; 10970 -> 10971; 6634 -> 6639 [label=true]; 6634 -> 10968 [label=false]; 10969 -> 10970; 6639 -> 6644 [label=true]; 6639 -> 10967 [label=false]; 10968 -> 10969; 6644 -> 6649 [label=true]; 6644 -> 10966 [label=false]; 10967 -> 10968; 6649 -> 6654 [label=true]; 6649 -> 10965 [label=false]; 10966 -> 10967; 6654 -> 6659 [label=true]; 6654 -> 10964 [label=false]; 10965 -> 10966; 6659 -> 6664 [label=true]; 6659 -> 10963 [label=false]; 10964 -> 10965; 6664 -> 6669 [label=true]; 6664 -> 10962 [label=false]; 10963 -> 10964; 6669 -> 6674 [label=true]; 6669 -> 10961 [label=false]; 10962 -> 10963; 6674 -> 6679 [label=true]; 6674 -> 10960 [label=false]; 10961 -> 10962; 6679 -> 6684 [label=true]; 6679 -> 10959 [label=false]; 10960 -> 10961; 6684 -> 6689 [label=true]; 6684 -> 10958 [label=false]; 10959 -> 10960; 6689 -> 6694 [label=true]; 6689 -> 10957 [label=false]; 10958 -> 10959; 6694 -> 6699 [label=true]; 6694 -> 10956 [label=false]; 10957 -> 10958; 6699 -> 6704 [label=true]; 6699 -> 10955 [label=false]; 10956 -> 10957; 6704 -> 6709 [label=true]; 6704 -> 10954 [label=false]; 10955 -> 10956; 6709 -> 6714 [label=true]; 6709 -> 10953 [label=false]; 10954 -> 10955; 6714 -> 6719 [label=true]; 6714 -> 10952 [label=false]; 10953 -> 10954; 6719 -> 6724 [label=true]; 6719 -> 10951 [label=false]; 10952 -> 10953; 6724 -> 6729 [label=true]; 6724 -> 10950 [label=false]; 10951 -> 10952; 6729 -> 6734 [label=true]; 6729 -> 10949 [label=false]; 10950 -> 10951; 6734 -> 6739 [label=true]; 6734 -> 10948 [label=false]; 10949 -> 10950; 6739 -> 6744 [label=true]; 6739 -> 10947 [label=false]; 10948 -> 10949; 6744 -> 6749 [label=true]; 6744 -> 10946 [label=false]; 10947 -> 10948; 6749 -> 6754 [label=true]; 6749 -> 10945 [label=false]; 10946 -> 10947; 6754 -> 6759 [label=true]; 6754 -> 10944 [label=false]; 10945 -> 10946; 6759 -> 6764 [label=true]; 6759 -> 10943 [label=false]; 10944 -> 10945; 6764 -> 6769 [label=true]; 6764 -> 10942 [label=false]; 10943 -> 10944; 6769 -> 6774 [label=true]; 6769 -> 10941 [label=false]; 10942 -> 10943; 6774 -> 6779 [label=true]; 6774 -> 10940 [label=false]; 10941 -> 10942; 6779 -> 6784 [label=true]; 6779 -> 10939 [label=false]; 10940 -> 10941; 6784 -> 6789 [label=true]; 6784 -> 10938 [label=false]; 10939 -> 10940; 6789 -> 6794 [label=true]; 6789 -> 10937 [label=false]; 10938 -> 10939; 6794 -> 6799 [label=true]; 6794 -> 10936 [label=false]; 10937 -> 10938; 6799 -> 6804 [label=true]; 6799 -> 10935 [label=false]; 10936 -> 10937; 6804 -> 6809 [label=true]; 6804 -> 10934 [label=false]; 10935 -> 10936; 6809 -> 6814 [label=true]; 6809 -> 10933 [label=false]; 10934 -> 10935; 6814 -> 6819 [label=true]; 6814 -> 10932 [label=false]; 10933 -> 10934; 6819 -> 6824 [label=true]; 6819 -> 10931 [label=false]; 10932 -> 10933; 6824 -> 6829 [label=true]; 6824 -> 10930 [label=false]; 10931 -> 10932; 6829 -> 6834 [label=true]; 6829 -> 10929 [label=false]; 10930 -> 10931; 6834 -> 6839 [label=true]; 6834 -> 10928 [label=false]; 10929 -> 10930; 6839 -> 6844 [label=true]; 6839 -> 10927 [label=false]; 10928 -> 10929; 6844 -> 6849 [label=true]; 6844 -> 10926 [label=false]; 10927 -> 10928; 6849 -> 6854 [label=true]; 6849 -> 10925 [label=false]; 10926 -> 10927; 6854 -> 6859 [label=true]; 6854 -> 10924 [label=false]; 10925 -> 10926; 6859 -> 6864 [label=true]; 6859 -> 10923 [label=false]; 10924 -> 10925; 6864 -> 6869 [label=true]; 6864 -> 10922 [label=false]; 10923 -> 10924; 6869 -> 6874 [label=true]; 6869 -> 10921 [label=false]; 10922 -> 10923; 6874 -> 6879 [label=true]; 6874 -> 10920 [label=false]; 10921 -> 10922; 6879 -> 6884 [label=true]; 6879 -> 10919 [label=false]; 10920 -> 10921; 6884 -> 6889 [label=true]; 6884 -> 10918 [label=false]; 10919 -> 10920; 6889 -> 6894 [label=true]; 6889 -> 10917 [label=false]; 10918 -> 10919; 6894 -> 6899 [label=true]; 6894 -> 10916 [label=false]; 10917 -> 10918; 6899 -> 6904 [label=true]; 6899 -> 10915 [label=false]; 10916 -> 10917; 6904 -> 6909 [label=true]; 6904 -> 10914 [label=false]; 10915 -> 10916; 6909 -> 6914 [label=true]; 6909 -> 10913 [label=false]; 10914 -> 10915; 6914 -> 6919 [label=true]; 6914 -> 10912 [label=false]; 10913 -> 10914; 6919 -> 6924 [label=true]; 6919 -> 10911 [label=false]; 10912 -> 10913; 6924 -> 6929 [label=true]; 6924 -> 10910 [label=false]; 10911 -> 10912; 6929 -> 6934 [label=true]; 6929 -> 10909 [label=false]; 10910 -> 10911; 6934 -> 6939 [label=true]; 6934 -> 10908 [label=false]; 10909 -> 10910; 6939 -> 6944 [label=true]; 6939 -> 10907 [label=false]; 10908 -> 10909; 6944 -> 6949 [label=true]; 6944 -> 10906 [label=false]; 10907 -> 10908; 6949 -> 6954 [label=true]; 6949 -> 10905 [label=false]; 10906 -> 10907; 6954 -> 6959 [label=true]; 6954 -> 10904 [label=false]; 10905 -> 10906; 6959 -> 6964 [label=true]; 6959 -> 10903 [label=false]; 10904 -> 10905; 6964 -> 6969 [label=true]; 6964 -> 10902 [label=false]; 10903 -> 10904; 6969 -> 6974 [label=true]; 6969 -> 10901 [label=false]; 10902 -> 10903; 6974 -> 6979 [label=true]; 6974 -> 10900 [label=false]; 10901 -> 10902; 6979 -> 6984 [label=true]; 6979 -> 10899 [label=false]; 10900 -> 10901; 6984 -> 6989 [label=true]; 6984 -> 10898 [label=false]; 10899 -> 10900; 6989 -> 6994 [label=true]; 6989 -> 10897 [label=false]; 10898 -> 10899; 6994 -> 6999 [label=true]; 6994 -> 10896 [label=false]; 10897 -> 10898; 6999 -> 7004 [label=true]; 6999 -> 10895 [label=false]; 10896 -> 10897; 7004 -> 7009 [label=true]; 7004 -> 10894 [label=false]; 10895 -> 10896; 7009 -> 7014 [label=true]; 7009 -> 10893 [label=false]; 10894 -> 10895; 7014 -> 7019 [label=true]; 7014 -> 10892 [label=false]; 10893 -> 10894; 7019 -> 7024 [label=true]; 7019 -> 10891 [label=false]; 10892 -> 10893; 7024 -> 7029 [label=true]; 7024 -> 10890 [label=false]; 10891 -> 10892; 7029 -> 7034 [label=true]; 7029 -> 10889 [label=false]; 10890 -> 10891; 7034 -> 7039 [label=true]; 7034 -> 10888 [label=false]; 10889 -> 10890; 7039 -> 7044 [label=true]; 7039 -> 10887 [label=false]; 10888 -> 10889; 7044 -> 7049 [label=true]; 7044 -> 10886 [label=false]; 10887 -> 10888; 7049 -> 7054 [label=true]; 7049 -> 10885 [label=false]; 10886 -> 10887; 7054 -> 7059 [label=true]; 7054 -> 10884 [label=false]; 10885 -> 10886; 7059 -> 7064 [label=true]; 7059 -> 10883 [label=false]; 10884 -> 10885; 7064 -> 7069 [label=true]; 7064 -> 10882 [label=false]; 10883 -> 10884; 7069 -> 7074 [label=true]; 7069 -> 10881 [label=false]; 10882 -> 10883; 7074 -> 7079 [label=true]; 7074 -> 10880 [label=false]; 10881 -> 10882; 7079 -> 7084 [label=true]; 7079 -> 10879 [label=false]; 10880 -> 10881; 7084 -> 7089 [label=true]; 7084 -> 10878 [label=false]; 10879 -> 10880; 7089 -> 7094 [label=true]; 7089 -> 10877 [label=false]; 10878 -> 10879; 7094 -> 7099 [label=true]; 7094 -> 10876 [label=false]; 10877 -> 10878; 7099 -> 7104 [label=true]; 7099 -> 10875 [label=false]; 10876 -> 10877; 7104 -> 7109 [label=true]; 7104 -> 10874 [label=false]; 10875 -> 10876; 7109 -> 7114 [label=true]; 7109 -> 10873 [label=false]; 10874 -> 10875; 7114 -> 7119 [label=true]; 7114 -> 10872 [label=false]; 10873 -> 10874; 7119 -> 7124 [label=true]; 7119 -> 10871 [label=false]; 10872 -> 10873; 7124 -> 7129 [label=true]; 7124 -> 10870 [label=false]; 10871 -> 10872; 7129 -> 7134 [label=true]; 7129 -> 10869 [label=false]; 10870 -> 10871; 7134 -> 7139 [label=true]; 7134 -> 10868 [label=false]; 10869 -> 10870; 7139 -> 7144 [label=true]; 7139 -> 10867 [label=false]; 10868 -> 10869; 7144 -> 7149 [label=true]; 7144 -> 10866 [label=false]; 10867 -> 10868; 7149 -> 7154 [label=true]; 7149 -> 10865 [label=false]; 10866 -> 10867; 7154 -> 7159 [label=true]; 7154 -> 10864 [label=false]; 10865 -> 10866; 7159 -> 7164 [label=true]; 7159 -> 10863 [label=false]; 10864 -> 10865; 7164 -> 7169 [label=true]; 7164 -> 10862 [label=false]; 10863 -> 10864; 7169 -> 7174 [label=true]; 7169 -> 10861 [label=false]; 10862 -> 10863; 7174 -> 7179 [label=true]; 7174 -> 10860 [label=false]; 10861 -> 10862; 7179 -> 7184 [label=true]; 7179 -> 10859 [label=false]; 10860 -> 10861; 7184 -> 7189 [label=true]; 7184 -> 10858 [label=false]; 10859 -> 10860; 7189 -> 7194 [label=true]; 7189 -> 10857 [label=false]; 10858 -> 10859; 7194 -> 7199 [label=true]; 7194 -> 10856 [label=false]; 10857 -> 10858; 7199 -> 7204 [label=true]; 7199 -> 10855 [label=false]; 10856 -> 10857; 7204 -> 7209 [label=true]; 7204 -> 10854 [label=false]; 10855 -> 10856; 7209 -> 7214 [label=true]; 7209 -> 10853 [label=false]; 10854 -> 10855; 7214 -> 7219 [label=true]; 7214 -> 10852 [label=false]; 10853 -> 10854; 7219 -> 7224 [label=true]; 7219 -> 10851 [label=false]; 10852 -> 10853; 7224 -> 7229 [label=true]; 7224 -> 10850 [label=false]; 10851 -> 10852; 7229 -> 7234 [label=true]; 7229 -> 10849 [label=false]; 10850 -> 10851; 7234 -> 7239 [label=true]; 7234 -> 10848 [label=false]; 10849 -> 10850; 7239 -> 7244 [label=true]; 7239 -> 10847 [label=false]; 10848 -> 10849; 7244 -> 7249 [label=true]; 7244 -> 10846 [label=false]; 10847 -> 10848; 7249 -> 7254 [label=true]; 7249 -> 10845 [label=false]; 10846 -> 10847; 7254 -> 7259 [label=true]; 7254 -> 10844 [label=false]; 10845 -> 10846; 7259 -> 7264 [label=true]; 7259 -> 10843 [label=false]; 10844 -> 10845; 7264 -> 7269 [label=true]; 7264 -> 10842 [label=false]; 10843 -> 10844; 7269 -> 7274 [label=true]; 7269 -> 10841 [label=false]; 10842 -> 10843; 7274 -> 7279 [label=true]; 7274 -> 10840 [label=false]; 10841 -> 10842; 7279 -> 7284 [label=true]; 7279 -> 10839 [label=false]; 10840 -> 10841; 7284 -> 7289 [label=true]; 7284 -> 10838 [label=false]; 10839 -> 10840; 7289 -> 7294 [label=true]; 7289 -> 10837 [label=false]; 10838 -> 10839; 7294 -> 7299 [label=true]; 7294 -> 10836 [label=false]; 10837 -> 10838; 7299 -> 7304 [label=true]; 7299 -> 10835 [label=false]; 10836 -> 10837; 7304 -> 7309 [label=true]; 7304 -> 10834 [label=false]; 10835 -> 10836; 7309 -> 7314 [label=true]; 7309 -> 10833 [label=false]; 10834 -> 10835; 7314 -> 7319 [label=true]; 7314 -> 10832 [label=false]; 10833 -> 10834; 7319 -> 7324 [label=true]; 7319 -> 10831 [label=false]; 10832 -> 10833; 7324 -> 7329 [label=true]; 7324 -> 10830 [label=false]; 10831 -> 10832; 7329 -> 7334 [label=true]; 7329 -> 10829 [label=false]; 10830 -> 10831; 7334 -> 7339 [label=true]; 7334 -> 10828 [label=false]; 10829 -> 10830; 7339 -> 7344 [label=true]; 7339 -> 10827 [label=false]; 10828 -> 10829; 7344 -> 7349 [label=true]; 7344 -> 10826 [label=false]; 10827 -> 10828; 7349 -> 7354 [label=true]; 7349 -> 10825 [label=false]; 10826 -> 10827; 7354 -> 7359 [label=true]; 7354 -> 10824 [label=false]; 10825 -> 10826; 7359 -> 7364 [label=true]; 7359 -> 10823 [label=false]; 10824 -> 10825; 7364 -> 7369 [label=true]; 7364 -> 10822 [label=false]; 10823 -> 10824; 7369 -> 7374 [label=true]; 7369 -> 10821 [label=false]; 10822 -> 10823; 7374 -> 7379 [label=true]; 7374 -> 10820 [label=false]; 10821 -> 10822; 7379 -> 7384 [label=true]; 7379 -> 10819 [label=false]; 10820 -> 10821; 7384 -> 7389 [label=true]; 7384 -> 10818 [label=false]; 10819 -> 10820; 7389 -> 7394 [label=true]; 7389 -> 10817 [label=false]; 10818 -> 10819; 7394 -> 7399 [label=true]; 7394 -> 10816 [label=false]; 10817 -> 10818; 7399 -> 7404 [label=true]; 7399 -> 10815 [label=false]; 10816 -> 10817; 7404 -> 7409 [label=true]; 7404 -> 10814 [label=false]; 10815 -> 10816; 7409 -> 7414 [label=true]; 7409 -> 10813 [label=false]; 10814 -> 10815; 7414 -> 7419 [label=true]; 7414 -> 10812 [label=false]; 10813 -> 10814; 7419 -> 7424 [label=true]; 7419 -> 10811 [label=false]; 10812 -> 10813; 7424 -> 7429 [label=true]; 7424 -> 10810 [label=false]; 10811 -> 10812; 7429 -> 7434 [label=true]; 7429 -> 10809 [label=false]; 10810 -> 10811; 7434 -> 7439 [label=true]; 7434 -> 10808 [label=false]; 10809 -> 10810; 7439 -> 7444 [label=true]; 7439 -> 10807 [label=false]; 10808 -> 10809; 7444 -> 7449 [label=true]; 7444 -> 10806 [label=false]; 10807 -> 10808; 7449 -> 7454 [label=true]; 7449 -> 10805 [label=false]; 10806 -> 10807; 7454 -> 7459 [label=true]; 7454 -> 10804 [label=false]; 10805 -> 10806; 7459 -> 7464 [label=true]; 7459 -> 10803 [label=false]; 10804 -> 10805; 7464 -> 7469 [label=true]; 7464 -> 10802 [label=false]; 10803 -> 10804; 7469 -> 7474 [label=true]; 7469 -> 10801 [label=false]; 10802 -> 10803; 7474 -> 7479 [label=true]; 7474 -> 10800 [label=false]; 10801 -> 10802; 7479 -> 7484 [label=true]; 7479 -> 10799 [label=false]; 10800 -> 10801; 7484 -> 7489 [label=true]; 7484 -> 10798 [label=false]; 10799 -> 10800; 7489 -> 7494 [label=true]; 7489 -> 10797 [label=false]; 10798 -> 10799; 7494 -> 7499 [label=true]; 7494 -> 10796 [label=false]; 10797 -> 10798; 7499 -> 7504 [label=true]; 7499 -> 10795 [label=false]; 10796 -> 10797; 7504 -> 7509 [label=true]; 7504 -> 10794 [label=false]; 10795 -> 10796; 7509 -> 7514 [label=true]; 7509 -> 10793 [label=false]; 10794 -> 10795; 7514 -> 7519 [label=true]; 7514 -> 10792 [label=false]; 10793 -> 10794; 7519 -> 7524 [label=true]; 7519 -> 10791 [label=false]; 10792 -> 10793; 7524 -> 7529 [label=true]; 7524 -> 10790 [label=false]; 10791 -> 10792; 7529 -> 7534 [label=true]; 7529 -> 10789 [label=false]; 10790 -> 10791; 7534 -> 7539 [label=true]; 7534 -> 10788 [label=false]; 10789 -> 10790; 7539 -> 7544 [label=true]; 7539 -> 10787 [label=false]; 10788 -> 10789; 7544 -> 7549 [label=true]; 7544 -> 10786 [label=false]; 10787 -> 10788; 7549 -> 7554 [label=true]; 7549 -> 10785 [label=false]; 10786 -> 10787; 7554 -> 7559 [label=true]; 7554 -> 10784 [label=false]; 10785 -> 10786; 7559 -> 7564 [label=true]; 7559 -> 10783 [label=false]; 10784 -> 10785; 7564 -> 7569 [label=true]; 7564 -> 10782 [label=false]; 10783 -> 10784; 7569 -> 7574 [label=true]; 7569 -> 10781 [label=false]; 10782 -> 10783; 7574 -> 7579 [label=true]; 7574 -> 10780 [label=false]; 10781 -> 10782; 7579 -> 7584 [label=true]; 7579 -> 10779 [label=false]; 10780 -> 10781; 7584 -> 7589 [label=true]; 7584 -> 10778 [label=false]; 10779 -> 10780; 7589 -> 7594 [label=true]; 7589 -> 10777 [label=false]; 10778 -> 10779; 7594 -> 7599 [label=true]; 7594 -> 10776 [label=false]; 10777 -> 10778; 7599 -> 7604 [label=true]; 7599 -> 10775 [label=false]; 10776 -> 10777; 7604 -> 7609 [label=true]; 7604 -> 10774 [label=false]; 10775 -> 10776; 7609 -> 7614 [label=true]; 7609 -> 10773 [label=false]; 10774 -> 10775; 7614 -> 7619 [label=true]; 7614 -> 10772 [label=false]; 10773 -> 10774; 7619 -> 7624 [label=true]; 7619 -> 10771 [label=false]; 10772 -> 10773; 7624 -> 7629 [label=true]; 7624 -> 10770 [label=false]; 10771 -> 10772; 7629 -> 7634 [label=true]; 7629 -> 10769 [label=false]; 10770 -> 10771; 7634 -> 7639 [label=true]; 7634 -> 10768 [label=false]; 10769 -> 10770; 7639 -> 7644 [label=true]; 7639 -> 10767 [label=false]; 10768 -> 10769; 7644 -> 7649 [label=true]; 7644 -> 10766 [label=false]; 10767 -> 10768; 7649 -> 7654 [label=true]; 7649 -> 10765 [label=false]; 10766 -> 10767; 7654 -> 7659 [label=true]; 7654 -> 10764 [label=false]; 10765 -> 10766; 7659 -> 7664 [label=true]; 7659 -> 10763 [label=false]; 10764 -> 10765; 7664 -> 7669 [label=true]; 7664 -> 10762 [label=false]; 10763 -> 10764; 7669 -> 7674 [label=true]; 7669 -> 10761 [label=false]; 10762 -> 10763; 7674 -> 7679 [label=true]; 7674 -> 10760 [label=false]; 10761 -> 10762; 7679 -> 7684 [label=true]; 7679 -> 10759 [label=false]; 10760 -> 10761; 7684 -> 7689 [label=true]; 7684 -> 10758 [label=false]; 10759 -> 10760; 7689 -> 7694 [label=true]; 7689 -> 10757 [label=false]; 10758 -> 10759; 7694 -> 7699 [label=true]; 7694 -> 10756 [label=false]; 10757 -> 10758; 7699 -> 7704 [label=true]; 7699 -> 10755 [label=false]; 10756 -> 10757; 7704 -> 7709 [label=true]; 7704 -> 10754 [label=false]; 10755 -> 10756; 7709 -> 7714 [label=true]; 7709 -> 10753 [label=false]; 10754 -> 10755; 7714 -> 7719 [label=true]; 7714 -> 10752 [label=false]; 10753 -> 10754; 7719 -> 7724 [label=true]; 7719 -> 10751 [label=false]; 10752 -> 10753; 7724 -> 7729 [label=true]; 7724 -> 10750 [label=false]; 10751 -> 10752; 7729 -> 7734 [label=true]; 7729 -> 10749 [label=false]; 10750 -> 10751; 7734 -> 7739 [label=true]; 7734 -> 10748 [label=false]; 10749 -> 10750; 7739 -> 7744 [label=true]; 7739 -> 10747 [label=false]; 10748 -> 10749; 7744 -> 7749 [label=true]; 7744 -> 10746 [label=false]; 10747 -> 10748; 7749 -> 7754 [label=true]; 7749 -> 10745 [label=false]; 10746 -> 10747; 7754 -> 7759 [label=true]; 7754 -> 10744 [label=false]; 10745 -> 10746; 7759 -> 7764 [label=true]; 7759 -> 10743 [label=false]; 10744 -> 10745; 7764 -> 7769 [label=true]; 7764 -> 10742 [label=false]; 10743 -> 10744; 7769 -> 7774 [label=true]; 7769 -> 10741 [label=false]; 10742 -> 10743; 7774 -> 7779 [label=true]; 7774 -> 10740 [label=false]; 10741 -> 10742; 7779 -> 7784 [label=true]; 7779 -> 10739 [label=false]; 10740 -> 10741; 7784 -> 7789 [label=true]; 7784 -> 10738 [label=false]; 10739 -> 10740; 7789 -> 7794 [label=true]; 7789 -> 10737 [label=false]; 10738 -> 10739; 7794 -> 7799 [label=true]; 7794 -> 10736 [label=false]; 10737 -> 10738; 7799 -> 7804 [label=true]; 7799 -> 10735 [label=false]; 10736 -> 10737; 7804 -> 7809 [label=true]; 7804 -> 10734 [label=false]; 10735 -> 10736; 7809 -> 7814 [label=true]; 7809 -> 10733 [label=false]; 10734 -> 10735; 7814 -> 7819 [label=true]; 7814 -> 10732 [label=false]; 10733 -> 10734; 7819 -> 7824 [label=true]; 7819 -> 10731 [label=false]; 10732 -> 10733; 7824 -> 7829 [label=true]; 7824 -> 10730 [label=false]; 10731 -> 10732; 7829 -> 7834 [label=true]; 7829 -> 10729 [label=false]; 10730 -> 10731; 7834 -> 7839 [label=true]; 7834 -> 10728 [label=false]; 10729 -> 10730; 7839 -> 7844 [label=true]; 7839 -> 10727 [label=false]; 10728 -> 10729; 7844 -> 7849 [label=true]; 7844 -> 10726 [label=false]; 10727 -> 10728; 7849 -> 7854 [label=true]; 7849 -> 10725 [label=false]; 10726 -> 10727; 7854 -> 7859 [label=true]; 7854 -> 10724 [label=false]; 10725 -> 10726; 7859 -> 7864 [label=true]; 7859 -> 10723 [label=false]; 10724 -> 10725; 7864 -> 7869 [label=true]; 7864 -> 10722 [label=false]; 10723 -> 10724; 7869 -> 7874 [label=true]; 7869 -> 10721 [label=false]; 10722 -> 10723; 7874 -> 7879 [label=true]; 7874 -> 10720 [label=false]; 10721 -> 10722; 7879 -> 7884 [label=true]; 7879 -> 10719 [label=false]; 10720 -> 10721; 7884 -> 7889 [label=true]; 7884 -> 10718 [label=false]; 10719 -> 10720; 7889 -> 7894 [label=true]; 7889 -> 10717 [label=false]; 10718 -> 10719; 7894 -> 7899 [label=true]; 7894 -> 10716 [label=false]; 10717 -> 10718; 7899 -> 7904 [label=true]; 7899 -> 10715 [label=false]; 10716 -> 10717; 7904 -> 7909 [label=true]; 7904 -> 10714 [label=false]; 10715 -> 10716; 7909 -> 7914 [label=true]; 7909 -> 10713 [label=false]; 10714 -> 10715; 7914 -> 7919 [label=true]; 7914 -> 10712 [label=false]; 10713 -> 10714; 7919 -> 7924 [label=true]; 7919 -> 10711 [label=false]; 10712 -> 10713; 7924 -> 7929 [label=true]; 7924 -> 10710 [label=false]; 10711 -> 10712; 7929 -> 7934 [label=true]; 7929 -> 10709 [label=false]; 10710 -> 10711; 7934 -> 7939 [label=true]; 7934 -> 10708 [label=false]; 10709 -> 10710; 7939 -> 7944 [label=true]; 7939 -> 10707 [label=false]; 10708 -> 10709; 7944 -> 7949 [label=true]; 7944 -> 10706 [label=false]; 10707 -> 10708; 7949 -> 7954 [label=true]; 7949 -> 10705 [label=false]; 10706 -> 10707; 7954 -> 7959 [label=true]; 7954 -> 10704 [label=false]; 10705 -> 10706; 7959 -> 7964 [label=true]; 7959 -> 10703 [label=false]; 10704 -> 10705; 7964 -> 7969 [label=true]; 7964 -> 10702 [label=false]; 10703 -> 10704; 7969 -> 7974 [label=true]; 7969 -> 10701 [label=false]; 10702 -> 10703; 7974 -> 7979 [label=true]; 7974 -> 10700 [label=false]; 10701 -> 10702; 7979 -> 7984 [label=true]; 7979 -> 10699 [label=false]; 10700 -> 10701; 7984 -> 7989 [label=true]; 7984 -> 10698 [label=false]; 10699 -> 10700; 7989 -> 7994 [label=true]; 7989 -> 10697 [label=false]; 10698 -> 10699; 7994 -> 7999 [label=true]; 7994 -> 10696 [label=false]; 10697 -> 10698; 7999 -> 8004 [label=true]; 7999 -> 10695 [label=false]; 10696 -> 10697; 8004 -> 8009 [label=true]; 8004 -> 10694 [label=false]; 10695 -> 10696; 8009 -> 8014 [label=true]; 8009 -> 10693 [label=false]; 10694 -> 10695; 8014 -> 8019 [label=true]; 8014 -> 10692 [label=false]; 10693 -> 10694; 8019 -> 8024 [label=true]; 8019 -> 10691 [label=false]; 10692 -> 10693; 8024 -> 8029 [label=true]; 8024 -> 10690 [label=false]; 10691 -> 10692; 8029 -> 8034 [label=true]; 8029 -> 10689 [label=false]; 10690 -> 10691; 8034 -> 8039 [label=true]; 8034 -> 10688 [label=false]; 10689 -> 10690; 8039 -> 8044 [label=true]; 8039 -> 10687 [label=false]; 10688 -> 10689; 8044 -> 8049 [label=true]; 8044 -> 10686 [label=false]; 10687 -> 10688; 8049 -> 8054 [label=true]; 8049 -> 10685 [label=false]; 10686 -> 10687; 8054 -> 8059 [label=true]; 8054 -> 10684 [label=false]; 10685 -> 10686; 8059 -> 8064 [label=true]; 8059 -> 10683 [label=false]; 10684 -> 10685; 8064 -> 8069 [label=true]; 8064 -> 10682 [label=false]; 10683 -> 10684; 8069 -> 8074 [label=true]; 8069 -> 10681 [label=false]; 10682 -> 10683; 8074 -> 8079 [label=true]; 8074 -> 10680 [label=false]; 10681 -> 10682; 8079 -> 8084 [label=true]; 8079 -> 10679 [label=false]; 10680 -> 10681; 8084 -> 8089 [label=true]; 8084 -> 10678 [label=false]; 10679 -> 10680; 8089 -> 8094 [label=true]; 8089 -> 10677 [label=false]; 10678 -> 10679; 8094 -> 8099 [label=true]; 8094 -> 10676 [label=false]; 10677 -> 10678; 8099 -> 8104 [label=true]; 8099 -> 10675 [label=false]; 10676 -> 10677; 8104 -> 8109 [label=true]; 8104 -> 10674 [label=false]; 10675 -> 10676; 8109 -> 8114 [label=true]; 8109 -> 10673 [label=false]; 10674 -> 10675; 8114 -> 8119 [label=true]; 8114 -> 10672 [label=false]; 10673 -> 10674; 8119 -> 8124 [label=true]; 8119 -> 10671 [label=false]; 10672 -> 10673; 8124 -> 8129 [label=true]; 8124 -> 10670 [label=false]; 10671 -> 10672; 8129 -> 8134 [label=true]; 8129 -> 10669 [label=false]; 10670 -> 10671; 8134 -> 8139 [label=true]; 8134 -> 10668 [label=false]; 10669 -> 10670; 8139 -> 8144 [label=true]; 8139 -> 10667 [label=false]; 10668 -> 10669; 8144 -> 8149 [label=true]; 8144 -> 10666 [label=false]; 10667 -> 10668; 8149 -> 8154 [label=true]; 8149 -> 10665 [label=false]; 10666 -> 10667; 8154 -> 8159 [label=true]; 8154 -> 10664 [label=false]; 10665 -> 10666; 8159 -> 8164 [label=true]; 8159 -> 10663 [label=false]; 10664 -> 10665; 8164 -> 8169 [label=true]; 8164 -> 10662 [label=false]; 10663 -> 10664; 8169 -> 8174 [label=true]; 8169 -> 10661 [label=false]; 10662 -> 10663; 8174 -> 8179 [label=true]; 8174 -> 10660 [label=false]; 10661 -> 10662; 8179 -> 8184 [label=true]; 8179 -> 10659 [label=false]; 10660 -> 10661; 8184 -> 8189 [label=true]; 8184 -> 10658 [label=false]; 10659 -> 10660; 8189 -> 8194 [label=true]; 8189 -> 10657 [label=false]; 10658 -> 10659; 8194 -> 8199 [label=true]; 8194 -> 10656 [label=false]; 10657 -> 10658; 8199 -> 8204 [label=true]; 8199 -> 10655 [label=false]; 10656 -> 10657; 8204 -> 8209 [label=true]; 8204 -> 10654 [label=false]; 10655 -> 10656; 8209 -> 8214 [label=true]; 8209 -> 10653 [label=false]; 10654 -> 10655; 8214 -> 8219 [label=true]; 8214 -> 10652 [label=false]; 10653 -> 10654; 8219 -> 8224 [label=true]; 8219 -> 10651 [label=false]; 10652 -> 10653; 8224 -> 8229 [label=true]; 8224 -> 10650 [label=false]; 10651 -> 10652; 8229 -> 8234 [label=true]; 8229 -> 10649 [label=false]; 10650 -> 10651; 8234 -> 8239 [label=true]; 8234 -> 10648 [label=false]; 10649 -> 10650; 8239 -> 8244 [label=true]; 8239 -> 10647 [label=false]; 10648 -> 10649; 8244 -> 8249 [label=true]; 8244 -> 10646 [label=false]; 10647 -> 10648; 8249 -> 8254 [label=true]; 8249 -> 10645 [label=false]; 10646 -> 10647; 8254 -> 8259 [label=true]; 8254 -> 10644 [label=false]; 10645 -> 10646; 8259 -> 8264 [label=true]; 8259 -> 10643 [label=false]; 10644 -> 10645; 8264 -> 8269 [label=true]; 8264 -> 10642 [label=false]; 10643 -> 10644; 8269 -> 8274 [label=true]; 8269 -> 10641 [label=false]; 10642 -> 10643; 8274 -> 8279 [label=true]; 8274 -> 10640 [label=false]; 10641 -> 10642; 8279 -> 8284 [label=true]; 8279 -> 10639 [label=false]; 10640 -> 10641; 8284 -> 8289 [label=true]; 8284 -> 10638 [label=false]; 10639 -> 10640; 8289 -> 8294 [label=true]; 8289 -> 10637 [label=false]; 10638 -> 10639; 8294 -> 8299 [label=true]; 8294 -> 10636 [label=false]; 10637 -> 10638; 8299 -> 8304 [label=true]; 8299 -> 10635 [label=false]; 10636 -> 10637; 8304 -> 8309 [label=true]; 8304 -> 10634 [label=false]; 10635 -> 10636; 8309 -> 8314 [label=true]; 8309 -> 10633 [label=false]; 10634 -> 10635; 8314 -> 8319 [label=true]; 8314 -> 10632 [label=false]; 10633 -> 10634; 8319 -> 8324 [label=true]; 8319 -> 10631 [label=false]; 10632 -> 10633; 8324 -> 8329 [label=true]; 8324 -> 10630 [label=false]; 10631 -> 10632; 8329 -> 8334 [label=true]; 8329 -> 10629 [label=false]; 10630 -> 10631; 8334 -> 8339 [label=true]; 8334 -> 10628 [label=false]; 10629 -> 10630; 8339 -> 8344 [label=true]; 8339 -> 10627 [label=false]; 10628 -> 10629; 8344 -> 8349 [label=true]; 8344 -> 10626 [label=false]; 10627 -> 10628; 8349 -> 8354 [label=true]; 8349 -> 10625 [label=false]; 10626 -> 10627; 8354 -> 8359 [label=true]; 8354 -> 10624 [label=false]; 10625 -> 10626; 8359 -> 8364 [label=true]; 8359 -> 10623 [label=false]; 10624 -> 10625; 8364 -> 8369 [label=true]; 8364 -> 10622 [label=false]; 10623 -> 10624; 8369 -> 8374 [label=true]; 8369 -> 10621 [label=false]; 10622 -> 10623; 8374 -> 8379 [label=true]; 8374 -> 10620 [label=false]; 10621 -> 10622; 8379 -> 8384 [label=true]; 8379 -> 10619 [label=false]; 10620 -> 10621; 8384 -> 8389 [label=true]; 8384 -> 10618 [label=false]; 10619 -> 10620; 8389 -> 8394 [label=true]; 8389 -> 10617 [label=false]; 10618 -> 10619; 8394 -> 8399 [label=true]; 8394 -> 10616 [label=false]; 10617 -> 10618; 8399 -> 8404 [label=true]; 8399 -> 10615 [label=false]; 10616 -> 10617; 8404 -> 8409 [label=true]; 8404 -> 10614 [label=false]; 10615 -> 10616; 8409 -> 8414 [label=true]; 8409 -> 10613 [label=false]; 10614 -> 10615; 8414 -> 8419 [label=true]; 8414 -> 10612 [label=false]; 10613 -> 10614; 8419 -> 8424 [label=true]; 8419 -> 10611 [label=false]; 10612 -> 10613; 8424 -> 8429 [label=true]; 8424 -> 10610 [label=false]; 10611 -> 10612; 8429 -> 8434 [label=true]; 8429 -> 10609 [label=false]; 10610 -> 10611; 8434 -> 8439 [label=true]; 8434 -> 10608 [label=false]; 10609 -> 10610; 8439 -> 8444 [label=true]; 8439 -> 10607 [label=false]; 10608 -> 10609; 8444 -> 8449 [label=true]; 8444 -> 10606 [label=false]; 10607 -> 10608; 8449 -> 8454 [label=true]; 8449 -> 10605 [label=false]; 10606 -> 10607; 8454 -> 8459 [label=true]; 8454 -> 10604 [label=false]; 10605 -> 10606; 8459 -> 8464 [label=true]; 8459 -> 10603 [label=false]; 10604 -> 10605; 8464 -> 8469 [label=true]; 8464 -> 10602 [label=false]; 10603 -> 10604; 8469 -> 8474 [label=true]; 8469 -> 10601 [label=false]; 10602 -> 10603; 8474 -> 8479 [label=true]; 8474 -> 10600 [label=false]; 10601 -> 10602; 8479 -> 8484 [label=true]; 8479 -> 10599 [label=false]; 10600 -> 10601; 8484 -> 8489 [label=true]; 8484 -> 10598 [label=false]; 10599 -> 10600; 8489 -> 8494 [label=true]; 8489 -> 10597 [label=false]; 10598 -> 10599; 8494 -> 8499 [label=true]; 8494 -> 10596 [label=false]; 10597 -> 10598; 8499 -> 8504 [label=true]; 8499 -> 10595 [label=false]; 10596 -> 10597; 8504 -> 8509 [label=true]; 8504 -> 10594 [label=false]; 10595 -> 10596; 8509 -> 8514 [label=true]; 8509 -> 10593 [label=false]; 10594 -> 10595; 8514 -> 8519 [label=true]; 8514 -> 10592 [label=false]; 10593 -> 10594; 8519 -> 8524 [label=true]; 8519 -> 10591 [label=false]; 10592 -> 10593; 8524 -> 8529 [label=true]; 8524 -> 10590 [label=false]; 10591 -> 10592; 8529 -> 8534 [label=true]; 8529 -> 10589 [label=false]; 10590 -> 10591; 8534 -> 8539 [label=true]; 8534 -> 10588 [label=false]; 10589 -> 10590; 8539 -> 8544 [label=true]; 8539 -> 10587 [label=false]; 10588 -> 10589; 8544 -> 8549 [label=true]; 8544 -> 10586 [label=false]; 10587 -> 10588; 8549 -> 8554 [label=true]; 8549 -> 10585 [label=false]; 10586 -> 10587; 8554 -> 8559 [label=true]; 8554 -> 10584 [label=false]; 10585 -> 10586; 8559 -> 8564 [label=true]; 8559 -> 10583 [label=false]; 10584 -> 10585; 8564 -> 8569 [label=true]; 8564 -> 10582 [label=false]; 10583 -> 10584; 8569 -> 8574 [label=true]; 8569 -> 10581 [label=false]; 10582 -> 10583; 8574 -> 8579 [label=true]; 8574 -> 10580 [label=false]; 10581 -> 10582; 8579 -> 8584 [label=true]; 8579 -> 10579 [label=false]; 10580 -> 10581; 8584 -> 8589 [label=true]; 8584 -> 10578 [label=false]; 10579 -> 10580; 8589 -> 8594 [label=true]; 8589 -> 10577 [label=false]; 10578 -> 10579; 8594 -> 8599 [label=true]; 8594 -> 10576 [label=false]; 10577 -> 10578; 8599 -> 8604 [label=true]; 8599 -> 10575 [label=false]; 10576 -> 10577; 8604 -> 8609 [label=true]; 8604 -> 10574 [label=false]; 10575 -> 10576; 8609 -> 8614 [label=true]; 8609 -> 10573 [label=false]; 10574 -> 10575; 8614 -> 8619 [label=true]; 8614 -> 10572 [label=false]; 10573 -> 10574; 8619 -> 8624 [label=true]; 8619 -> 10571 [label=false]; 10572 -> 10573; 8624 -> 8629 [label=true]; 8624 -> 10570 [label=false]; 10571 -> 10572; 8629 -> 8634 [label=true]; 8629 -> 10569 [label=false]; 10570 -> 10571; 8634 -> 8639 [label=true]; 8634 -> 10568 [label=false]; 10569 -> 10570; 8639 -> 8644 [label=true]; 8639 -> 10567 [label=false]; 10568 -> 10569; 8644 -> 8649 [label=true]; 8644 -> 10566 [label=false]; 10567 -> 10568; 8649 -> 8654 [label=true]; 8649 -> 10565 [label=false]; 10566 -> 10567; 8654 -> 8659 [label=true]; 8654 -> 10564 [label=false]; 10565 -> 10566; 8659 -> 8664 [label=true]; 8659 -> 10563 [label=false]; 10564 -> 10565; 8664 -> 8669 [label=true]; 8664 -> 10562 [label=false]; 10563 -> 10564; 8669 -> 8674 [label=true]; 8669 -> 10561 [label=false]; 10562 -> 10563; 8674 -> 8679 [label=true]; 8674 -> 10560 [label=false]; 10561 -> 10562; 8679 -> 8684 [label=true]; 8679 -> 10559 [label=false]; 10560 -> 10561; 8684 -> 8689 [label=true]; 8684 -> 10558 [label=false]; 10559 -> 10560; 8689 -> 8694 [label=true]; 8689 -> 10557 [label=false]; 10558 -> 10559; 8694 -> 8699 [label=true]; 8694 -> 10556 [label=false]; 10557 -> 10558; 8699 -> 8704 [label=true]; 8699 -> 10555 [label=false]; 10556 -> 10557; 8704 -> 8709 [label=true]; 8704 -> 10554 [label=false]; 10555 -> 10556; 8709 -> 8714 [label=true]; 8709 -> 10553 [label=false]; 10554 -> 10555; 8714 -> 8719 [label=true]; 8714 -> 10552 [label=false]; 10553 -> 10554; 8719 -> 8724 [label=true]; 8719 -> 10551 [label=false]; 10552 -> 10553; 8724 -> 8729 [label=true]; 8724 -> 10550 [label=false]; 10551 -> 10552; 8729 -> 8734 [label=true]; 8729 -> 10549 [label=false]; 10550 -> 10551; 8734 -> 8739 [label=true]; 8734 -> 10548 [label=false]; 10549 -> 10550; 8739 -> 8744 [label=true]; 8739 -> 10547 [label=false]; 10548 -> 10549; 8744 -> 8749 [label=true]; 8744 -> 10546 [label=false]; 10547 -> 10548; 8749 -> 8754 [label=true]; 8749 -> 10545 [label=false]; 10546 -> 10547; 8754 -> 8759 [label=true]; 8754 -> 10544 [label=false]; 10545 -> 10546; 8759 -> 8764 [label=true]; 8759 -> 10543 [label=false]; 10544 -> 10545; 8764 -> 8769 [label=true]; 8764 -> 10542 [label=false]; 10543 -> 10544; 8769 -> 8774 [label=true]; 8769 -> 10541 [label=false]; 10542 -> 10543; 8774 -> 8779 [label=true]; 8774 -> 10540 [label=false]; 10541 -> 10542; 8779 -> 8784 [label=true]; 8779 -> 10539 [label=false]; 10540 -> 10541; 8784 -> 8789 [label=true]; 8784 -> 10538 [label=false]; 10539 -> 10540; 8789 -> 8794 [label=true]; 8789 -> 10537 [label=false]; 10538 -> 10539; 8794 -> 8799 [label=true]; 8794 -> 10536 [label=false]; 10537 -> 10538; 8799 -> 8804 [label=true]; 8799 -> 10535 [label=false]; 10536 -> 10537; 8804 -> 8809 [label=true]; 8804 -> 10534 [label=false]; 10535 -> 10536; 8809 -> 8814 [label=true]; 8809 -> 10533 [label=false]; 10534 -> 10535; 8814 -> 8819 [label=true]; 8814 -> 10532 [label=false]; 10533 -> 10534; 8819 -> 8824 [label=true]; 8819 -> 10531 [label=false]; 10532 -> 10533; 8824 -> 8829 [label=true]; 8824 -> 10530 [label=false]; 10531 -> 10532; 8829 -> 8834 [label=true]; 8829 -> 10529 [label=false]; 10530 -> 10531; 8834 -> 8839 [label=true]; 8834 -> 10528 [label=false]; 10529 -> 10530; 8839 -> 8844 [label=true]; 8839 -> 10527 [label=false]; 10528 -> 10529; 8844 -> 8849 [label=true]; 8844 -> 10526 [label=false]; 10527 -> 10528; 8849 -> 8854 [label=true]; 8849 -> 10525 [label=false]; 10526 -> 10527; 8854 -> 8859 [label=true]; 8854 -> 10524 [label=false]; 10525 -> 10526; 8859 -> 8864 [label=true]; 8859 -> 10523 [label=false]; 10524 -> 10525; 8864 -> 8869 [label=true]; 8864 -> 10522 [label=false]; 10523 -> 10524; 8869 -> 8874 [label=true]; 8869 -> 10521 [label=false]; 10522 -> 10523; 8874 -> 8879 [label=true]; 8874 -> 10520 [label=false]; 10521 -> 10522; 8879 -> 8884 [label=true]; 8879 -> 10519 [label=false]; 10520 -> 10521; 8884 -> 8889 [label=true]; 8884 -> 10518 [label=false]; 10519 -> 10520; 8889 -> 8894 [label=true]; 8889 -> 10517 [label=false]; 10518 -> 10519; 8894 -> 8899 [label=true]; 8894 -> 10516 [label=false]; 10517 -> 10518; 8899 -> 8904 [label=true]; 8899 -> 10515 [label=false]; 10516 -> 10517; 8904 -> 8909 [label=true]; 8904 -> 10514 [label=false]; 10515 -> 10516; 8909 -> 8914 [label=true]; 8909 -> 10513 [label=false]; 10514 -> 10515; 8914 -> 8919 [label=true]; 8914 -> 10512 [label=false]; 10513 -> 10514; 8919 -> 8924 [label=true]; 8919 -> 10511 [label=false]; 10512 -> 10513; 8924 -> 8929 [label=true]; 8924 -> 10510 [label=false]; 10511 -> 10512; 8929 -> 8934 [label=true]; 8929 -> 10509 [label=false]; 10510 -> 10511; 8934 -> 8939 [label=true]; 8934 -> 10508 [label=false]; 10509 -> 10510; 8939 -> 8944 [label=true]; 8939 -> 10507 [label=false]; 10508 -> 10509; 8944 -> 8949 [label=true]; 8944 -> 10506 [label=false]; 10507 -> 10508; 8949 -> 8954 [label=true]; 8949 -> 10505 [label=false]; 10506 -> 10507; 8954 -> 8959 [label=true]; 8954 -> 10504 [label=false]; 10505 -> 10506; 8959 -> 8964 [label=true]; 8959 -> 10503 [label=false]; 10504 -> 10505; 8964 -> 8969 [label=true]; 8964 -> 10502 [label=false]; 10503 -> 10504; 8969 -> 8974 [label=true]; 8969 -> 10501 [label=false]; 10502 -> 10503; 8974 -> 8979 [label=true]; 8974 -> 10500 [label=false]; 10501 -> 10502; 8979 -> 8984 [label=true]; 8979 -> 10499 [label=false]; 10500 -> 10501; 8984 -> 8989 [label=true]; 8984 -> 10498 [label=false]; 10499 -> 10500; 8989 -> 8994 [label=true]; 8989 -> 10497 [label=false]; 10498 -> 10499; 8994 -> 8999 [label=true]; 8994 -> 10496 [label=false]; 10497 -> 10498; 8999 -> 9004 [label=true]; 8999 -> 10495 [label=false]; 10496 -> 10497; 9004 -> 9009 [label=true]; 9004 -> 10494 [label=false]; 10495 -> 10496; 9009 -> 9014 [label=true]; 9009 -> 10493 [label=false]; 10494 -> 10495; 9014 -> 9019 [label=true]; 9014 -> 10492 [label=false]; 10493 -> 10494; 9019 -> 9024 [label=true]; 9019 -> 10491 [label=false]; 10492 -> 10493; 9024 -> 9029 [label=true]; 9024 -> 10490 [label=false]; 10491 -> 10492; 9029 -> 9034 [label=true]; 9029 -> 10489 [label=false]; 10490 -> 10491; 9034 -> 9039 [label=true]; 9034 -> 10488 [label=false]; 10489 -> 10490; 9039 -> 9044 [label=true]; 9039 -> 10487 [label=false]; 10488 -> 10489; 9044 -> 9049 [label=true]; 9044 -> 10486 [label=false]; 10487 -> 10488; 9049 -> 9054 [label=true]; 9049 -> 10485 [label=false]; 10486 -> 10487; 9054 -> 9059 [label=true]; 9054 -> 10484 [label=false]; 10485 -> 10486; 9059 -> 9064 [label=true]; 9059 -> 10483 [label=false]; 10484 -> 10485; 9064 -> 9069 [label=true]; 9064 -> 10482 [label=false]; 10483 -> 10484; 9069 -> 9074 [label=true]; 9069 -> 10481 [label=false]; 10482 -> 10483; 9074 -> 9079 [label=true]; 9074 -> 10480 [label=false]; 10481 -> 10482; 9079 -> 9084 [label=true]; 9079 -> 10479 [label=false]; 10480 -> 10481; 9084 -> 9089 [label=true]; 9084 -> 10478 [label=false]; 10479 -> 10480; 9089 -> 9094 [label=true]; 9089 -> 10477 [label=false]; 10478 -> 10479; 9094 -> 9099 [label=true]; 9094 -> 10476 [label=false]; 10477 -> 10478; 9099 -> 9104 [label=true]; 9099 -> 10475 [label=false]; 10476 -> 10477; 9104 -> 9109 [label=true]; 9104 -> 10474 [label=false]; 10475 -> 10476; 9109 -> 9114 [label=true]; 9109 -> 10473 [label=false]; 10474 -> 10475; 9114 -> 9119 [label=true]; 9114 -> 10472 [label=false]; 10473 -> 10474; 9119 -> 9124 [label=true]; 9119 -> 10471 [label=false]; 10472 -> 10473; 9124 -> 9129 [label=true]; 9124 -> 10470 [label=false]; 10471 -> 10472; 9129 -> 9134 [label=true]; 9129 -> 10469 [label=false]; 10470 -> 10471; 9134 -> 9139 [label=true]; 9134 -> 10468 [label=false]; 10469 -> 10470; 9139 -> 9144 [label=true]; 9139 -> 10467 [label=false]; 10468 -> 10469; 9144 -> 9149 [label=true]; 9144 -> 10466 [label=false]; 10467 -> 10468; 9149 -> 9154 [label=true]; 9149 -> 10465 [label=false]; 10466 -> 10467; 9154 -> 9159 [label=true]; 9154 -> 10464 [label=false]; 10465 -> 10466; 9159 -> 9164 [label=true]; 9159 -> 10463 [label=false]; 10464 -> 10465; 9164 -> 9169 [label=true]; 9164 -> 10462 [label=false]; 10463 -> 10464; 9169 -> 9174 [label=true]; 9169 -> 10461 [label=false]; 10462 -> 10463; 9174 -> 9179 [label=true]; 9174 -> 10460 [label=false]; 10461 -> 10462; 9179 -> 9184 [label=true]; 9179 -> 10459 [label=false]; 10460 -> 10461; 9184 -> 9189 [label=true]; 9184 -> 10458 [label=false]; 10459 -> 10460; 9189 -> 9194 [label=true]; 9189 -> 10457 [label=false]; 10458 -> 10459; 9194 -> 9199 [label=true]; 9194 -> 10456 [label=false]; 10457 -> 10458; 9199 -> 9204 [label=true]; 9199 -> 10455 [label=false]; 10456 -> 10457; 9204 -> 9209 [label=true]; 9204 -> 10454 [label=false]; 10455 -> 10456; 9209 -> 9214 [label=true]; 9209 -> 10453 [label=false]; 10454 -> 10455; 9214 -> 9219 [label=true]; 9214 -> 10452 [label=false]; 10453 -> 10454; 9219 -> 9224 [label=true]; 9219 -> 10451 [label=false]; 10452 -> 10453; 9224 -> 9229 [label=true]; 9224 -> 10450 [label=false]; 10451 -> 10452; 9229 -> 9234 [label=true]; 9229 -> 10449 [label=false]; 10450 -> 10451; 9234 -> 9239 [label=true]; 9234 -> 10448 [label=false]; 10449 -> 10450; 9239 -> 9244 [label=true]; 9239 -> 10447 [label=false]; 10448 -> 10449; 9244 -> 9249 [label=true]; 9244 -> 10446 [label=false]; 10447 -> 10448; 9249 -> 9254 [label=true]; 9249 -> 10445 [label=false]; 10446 -> 10447; 9254 -> 9259 [label=true]; 9254 -> 10444 [label=false]; 10445 -> 10446; 9259 -> 9264 [label=true]; 9259 -> 10443 [label=false]; 10444 -> 10445; 9264 -> 9269 [label=true]; 9264 -> 10442 [label=false]; 10443 -> 10444; 9269 -> 9274 [label=true]; 9269 -> 10441 [label=false]; 10442 -> 10443; 9274 -> 9279 [label=true]; 9274 -> 10440 [label=false]; 10441 -> 10442; 9279 -> 9284 [label=true]; 9279 -> 10439 [label=false]; 10440 -> 10441; 9284 -> 9289 [label=true]; 9284 -> 10438 [label=false]; 10439 -> 10440; 9289 -> 9294 [label=true]; 9289 -> 10437 [label=false]; 10438 -> 10439; 9294 -> 9299 [label=true]; 9294 -> 10436 [label=false]; 10437 -> 10438; 9299 -> 9304 [label=true]; 9299 -> 10435 [label=false]; 10436 -> 10437; 9304 -> 9309 [label=true]; 9304 -> 10434 [label=false]; 10435 -> 10436; 9309 -> 9314 [label=true]; 9309 -> 10433 [label=false]; 10434 -> 10435; 9314 -> 9319 [label=true]; 9314 -> 10432 [label=false]; 10433 -> 10434; 9319 -> 9324 [label=true]; 9319 -> 10431 [label=false]; 10432 -> 10433; 9324 -> 9329 [label=true]; 9324 -> 10430 [label=false]; 10431 -> 10432; 9329 -> 9334 [label=true]; 9329 -> 10429 [label=false]; 10430 -> 10431; 9334 -> 9339 [label=true]; 9334 -> 10428 [label=false]; 10429 -> 10430; 9339 -> 9344 [label=true]; 9339 -> 10427 [label=false]; 10428 -> 10429; 9344 -> 9349 [label=true]; 9344 -> 10426 [label=false]; 10427 -> 10428; 9349 -> 9354 [label=true]; 9349 -> 10425 [label=false]; 10426 -> 10427; 9354 -> 9359 [label=true]; 9354 -> 10424 [label=false]; 10425 -> 10426; 9359 -> 9364 [label=true]; 9359 -> 10423 [label=false]; 10424 -> 10425; 9364 -> 9369 [label=true]; 9364 -> 10422 [label=false]; 10423 -> 10424; 9369 -> 9374 [label=true]; 9369 -> 10421 [label=false]; 10422 -> 10423; 9374 -> 9379 [label=true]; 9374 -> 10420 [label=false]; 10421 -> 10422; 9379 -> 9384 [label=true]; 9379 -> 10419 [label=false]; 10420 -> 10421; 9384 -> 9389 [label=true]; 9384 -> 10418 [label=false]; 10419 -> 10420; 9389 -> 9394 [label=true]; 9389 -> 10417 [label=false]; 10418 -> 10419; 9394 -> 9399 [label=true]; 9394 -> 10416 [label=false]; 10417 -> 10418; 9399 -> 9404 [label=true]; 9399 -> 10415 [label=false]; 10416 -> 10417; 9404 -> 9409 [label=true]; 9404 -> 10414 [label=false]; 10415 -> 10416; 9409 -> 9414 [label=true]; 9409 -> 10413 [label=false]; 10414 -> 10415; 9414 -> 9419 [label=true]; 9414 -> 10412 [label=false]; 10413 -> 10414; 9419 -> 9424 [label=true]; 9419 -> 10411 [label=false]; 10412 -> 10413; 9424 -> 9429 [label=true]; 9424 -> 10410 [label=false]; 10411 -> 10412; 9429 -> 9434 [label=true]; 9429 -> 10409 [label=false]; 10410 -> 10411; 9434 -> 9439 [label=true]; 9434 -> 10408 [label=false]; 10409 -> 10410; 9439 -> 9444 [label=true]; 9439 -> 10407 [label=false]; 10408 -> 10409; 9444 -> 9449 [label=true]; 9444 -> 10406 [label=false]; 10407 -> 10408; 9449 -> 9454 [label=true]; 9449 -> 10405 [label=false]; 10406 -> 10407; 9454 -> 9459 [label=true]; 9454 -> 10404 [label=false]; 10405 -> 10406; 9459 -> 9464 [label=true]; 9459 -> 10403 [label=false]; 10404 -> 10405; 9464 -> 9469 [label=true]; 9464 -> 10402 [label=false]; 10403 -> 10404; 9469 -> 9474 [label=true]; 9469 -> 10401 [label=false]; 10402 -> 10403; 9474 -> 9479 [label=true]; 9474 -> 10400 [label=false]; 10401 -> 10402; 9479 -> 9484 [label=true]; 9479 -> 10399 [label=false]; 10400 -> 10401; 9484 -> 9489 [label=true]; 9484 -> 10398 [label=false]; 10399 -> 10400; 9489 -> 9494 [label=true]; 9489 -> 10397 [label=false]; 10398 -> 10399; 9494 -> 9499 [label=true]; 9494 -> 10396 [label=false]; 10397 -> 10398; 9499 -> 9504 [label=true]; 9499 -> 10395 [label=false]; 10396 -> 10397; 9504 -> 9509 [label=true]; 9504 -> 10394 [label=false]; 10395 -> 10396; 9509 -> 9514 [label=true]; 9509 -> 10393 [label=false]; 10394 -> 10395; 9514 -> 9519 [label=true]; 9514 -> 10392 [label=false]; 10393 -> 10394; 9519 -> 9524 [label=true]; 9519 -> 10391 [label=false]; 10392 -> 10393; 9524 -> 9529 [label=true]; 9524 -> 10390 [label=false]; 10391 -> 10392; 9529 -> 9534 [label=true]; 9529 -> 10389 [label=false]; 10390 -> 10391; 9534 -> 9539 [label=true]; 9534 -> 10388 [label=false]; 10389 -> 10390; 9539 -> 9544 [label=true]; 9539 -> 10387 [label=false]; 10388 -> 10389; 9544 -> 9549 [label=true]; 9544 -> 10386 [label=false]; 10387 -> 10388; 9549 -> 9554 [label=true]; 9549 -> 10385 [label=false]; 10386 -> 10387; 9554 -> 9559 [label=true]; 9554 -> 10384 [label=false]; 10385 -> 10386; 9559 -> 9564 [label=true]; 9559 -> 10383 [label=false]; 10384 -> 10385; 9564 -> 9569 [label=true]; 9564 -> 10382 [label=false]; 10383 -> 10384; 9569 -> 9574 [label=true]; 9569 -> 10381 [label=false]; 10382 -> 10383; 9574 -> 9579 [label=true]; 9574 -> 10380 [label=false]; 10381 -> 10382; 9579 -> 9584 [label=true]; 9579 -> 10379 [label=false]; 10380 -> 10381; 9584 -> 9589 [label=true]; 9584 -> 10378 [label=false]; 10379 -> 10380; 9589 -> 9594 [label=true]; 9589 -> 10377 [label=false]; 10378 -> 10379; 9594 -> 9599 [label=true]; 9594 -> 10376 [label=false]; 10377 -> 10378; 9599 -> 9604 [label=true]; 9599 -> 10375 [label=false]; 10376 -> 10377; 9604 -> 9609 [label=true]; 9604 -> 10374 [label=false]; 10375 -> 10376; 9609 -> 9614 [label=true]; 9609 -> 10373 [label=false]; 10374 -> 10375; 9614 -> 9619 [label=true]; 9614 -> 10372 [label=false]; 10373 -> 10374; 9619 -> 9624 [label=true]; 9619 -> 10371 [label=false]; 10372 -> 10373; 9624 -> 9629 [label=true]; 9624 -> 10370 [label=false]; 10371 -> 10372; 9629 -> 9634 [label=true]; 9629 -> 10369 [label=false]; 10370 -> 10371; 9634 -> 9639 [label=true]; 9634 -> 10368 [label=false]; 10369 -> 10370; 9639 -> 9644 [label=true]; 9639 -> 10367 [label=false]; 10368 -> 10369; 9644 -> 9649 [label=true]; 9644 -> 10366 [label=false]; 10367 -> 10368; 9649 -> 9654 [label=true]; 9649 -> 10365 [label=false]; 10366 -> 10367; 9654 -> 9659 [label=true]; 9654 -> 10364 [label=false]; 10365 -> 10366; 9659 -> 9664 [label=true]; 9659 -> 10363 [label=false]; 10364 -> 10365; 9664 -> 9669 [label=true]; 9664 -> 10362 [label=false]; 10363 -> 10364; 9669 -> 9674 [label=true]; 9669 -> 10361 [label=false]; 10362 -> 10363; 9674 -> 9679 [label=true]; 9674 -> 10360 [label=false]; 10361 -> 10362; 9679 -> 9684 [label=true]; 9679 -> 10359 [label=false]; 10360 -> 10361; 9684 -> 9689 [label=true]; 9684 -> 10358 [label=false]; 10359 -> 10360; 9689 -> 9694 [label=true]; 9689 -> 10357 [label=false]; 10358 -> 10359; 9694 -> 9699 [label=true]; 9694 -> 10356 [label=false]; 10357 -> 10358; 9699 -> 9704 [label=true]; 9699 -> 10355 [label=false]; 10356 -> 10357; 9704 -> 9709 [label=true]; 9704 -> 10354 [label=false]; 10355 -> 10356; 9709 -> 9714 [label=true]; 9709 -> 10353 [label=false]; 10354 -> 10355; 9714 -> 9719 [label=true]; 9714 -> 10352 [label=false]; 10353 -> 10354; 9719 -> 9724 [label=true]; 9719 -> 10351 [label=false]; 10352 -> 10353; 9724 -> 9729 [label=true]; 9724 -> 10350 [label=false]; 10351 -> 10352; 9729 -> 9734 [label=true]; 9729 -> 10349 [label=false]; 10350 -> 10351; 9734 -> 9739 [label=true]; 9734 -> 10348 [label=false]; 10349 -> 10350; 9739 -> 9744 [label=true]; 9739 -> 10347 [label=false]; 10348 -> 10349; 9744 -> 9749 [label=true]; 9744 -> 10346 [label=false]; 10347 -> 10348; 9749 -> 9754 [label=true]; 9749 -> 10345 [label=false]; 10346 -> 10347; 9754 -> 9759 [label=true]; 9754 -> 10344 [label=false]; 10345 -> 10346; 9759 -> 9764 [label=true]; 9759 -> 10343 [label=false]; 10344 -> 10345; 9764 -> 9769 [label=true]; 9764 -> 10342 [label=false]; 10343 -> 10344; 9769 -> 9774 [label=true]; 9769 -> 10341 [label=false]; 10342 -> 10343; 9774 -> 9779 [label=true]; 9774 -> 10340 [label=false]; 10341 -> 10342; 9779 -> 9784 [label=true]; 9779 -> 10339 [label=false]; 10340 -> 10341; 9784 -> 9789 [label=true]; 9784 -> 10338 [label=false]; 10339 -> 10340; 9789 -> 9794 [label=true]; 9789 -> 10337 [label=false]; 10338 -> 10339; 9794 -> 9799 [label=true]; 9794 -> 10336 [label=false]; 10337 -> 10338; 9799 -> 9804 [label=true]; 9799 -> 10335 [label=false]; 10336 -> 10337; 9804 -> 9809 [label=true]; 9804 -> 10334 [label=false]; 10335 -> 10336; 9809 -> 9814 [label=true]; 9809 -> 10333 [label=false]; 10334 -> 10335; 9814 -> 9819 [label=true]; 9814 -> 10332 [label=false]; 10333 -> 10334; 9819 -> 9824 [label=true]; 9819 -> 10331 [label=false]; 10332 -> 10333; 9824 -> 9829 [label=true]; 9824 -> 10330 [label=false]; 10331 -> 10332; 9829 -> 9834 [label=true]; 9829 -> 10329 [label=false]; 10330 -> 10331; 9834 -> 9839 [label=true]; 9834 -> 10328 [label=false]; 10329 -> 10330; 9839 -> 9844 [label=true]; 9839 -> 10327 [label=false]; 10328 -> 10329; 9844 -> 9849 [label=true]; 9844 -> 10326 [label=false]; 10327 -> 10328; 9849 -> 9854 [label=true]; 9849 -> 10325 [label=false]; 10326 -> 10327; 9854 -> 9859 [label=true]; 9854 -> 10324 [label=false]; 10325 -> 10326; 9859 -> 9864 [label=true]; 9859 -> 10323 [label=false]; 10324 -> 10325; 9864 -> 9869 [label=true]; 9864 -> 10322 [label=false]; 10323 -> 10324; 9869 -> 9874 [label=true]; 9869 -> 10321 [label=false]; 10322 -> 10323; 9874 -> 9879 [label=true]; 9874 -> 10320 [label=false]; 10321 -> 10322; 9879 -> 9884 [label=true]; 9879 -> 10319 [label=false]; 10320 -> 10321; 9884 -> 9889 [label=true]; 9884 -> 10318 [label=false]; 10319 -> 10320; 9889 -> 9894 [label=true]; 9889 -> 10317 [label=false]; 10318 -> 10319; 9894 -> 9899 [label=true]; 9894 -> 10316 [label=false]; 10317 -> 10318; 9899 -> 9904 [label=true]; 9899 -> 10315 [label=false]; 10316 -> 10317; 9904 -> 9909 [label=true]; 9904 -> 10314 [label=false]; 10315 -> 10316; 9909 -> 9914 [label=true]; 9909 -> 10313 [label=false]; 10314 -> 10315; 9914 -> 9919 [label=true]; 9914 -> 10312 [label=false]; 10313 -> 10314; 9919 -> 9924 [label=true]; 9919 -> 10311 [label=false]; 10312 -> 10313; 9924 -> 9929 [label=true]; 9924 -> 10310 [label=false]; 10311 -> 10312; 9929 -> 9934 [label=true]; 9929 -> 10309 [label=false]; 10310 -> 10311; 9934 -> 9939 [label=true]; 9934 -> 10308 [label=false]; 10309 -> 10310; 9939 -> 9944 [label=true]; 9939 -> 10307 [label=false]; 10308 -> 10309; 9944 -> 9949 [label=true]; 9944 -> 10306 [label=false]; 10307 -> 10308; 9949 -> 9954 [label=true]; 9949 -> 10305 [label=false]; 10306 -> 10307; 9954 -> 9959 [label=true]; 9954 -> 10304 [label=false]; 10305 -> 10306; 9959 -> 9964 [label=true]; 9959 -> 10303 [label=false]; 10304 -> 10305; 9964 -> 9969 [label=true]; 9964 -> 10302 [label=false]; 10303 -> 10304; 9969 -> 9974 [label=true]; 9969 -> 10301 [label=false]; 10302 -> 10303; 9974 -> 9979 [label=true]; 9974 -> 10300 [label=false]; 10301 -> 10302; 9979 -> 9984 [label=true]; 9979 -> 10299 [label=false]; 10300 -> 10301; 9984 -> 9989 [label=true]; 9984 -> 10298 [label=false]; 10299 -> 10300; 9989 -> 9994 [label=true]; 9989 -> 10297 [label=false]; 10298 -> 10299; 9994 -> 9999 [label=true]; 9994 -> 10296 [label=false]; 10297 -> 10298; 9999 -> 10004 [label=true]; 9999 -> 10295 [label=false]; 10296 -> 10297; 10004 -> 10009 [label=true]; 10004 -> 10294 [label=false]; 10295 -> 10296; 10009 -> 10014 [label=true]; 10009 -> 10293 [label=false]; 10294 -> 10295; 10014 -> 10019 [label=true]; 10014 -> 10292 [label=false]; 10293 -> 10294; 10019 -> 10024 [label=true]; 10019 -> 10291 [label=false]; 10292 -> 10293; 10024 -> 10029 [label=true]; 10024 -> 10290 [label=false]; 10291 -> 10292; 10029 -> 10034 [label=true]; 10029 -> 10289 [label=false]; 10290 -> 10291; 10034 -> 10039 [label=true]; 10034 -> 10288 [label=false]; 10289 -> 10290; 10039 -> 10044 [label=true]; 10039 -> 10287 [label=false]; 10288 -> 10289; 10044 -> 10049 [label=true]; 10044 -> 10286 [label=false]; 10287 -> 10288; 10049 -> 10054 [label=true]; 10049 -> 10285 [label=false]; 10286 -> 10287; 10054 -> 10059 [label=true]; 10054 -> 10284 [label=false]; 10285 -> 10286; 10059 -> 10064 [label=true]; 10059 -> 10283 [label=false]; 10284 -> 10285; 10064 -> 10069 [label=true]; 10064 -> 10282 [label=false]; 10283 -> 10284; 10069 -> 10074 [label=true]; 10069 -> 10281 [label=false]; 10282 -> 10283; 10074 -> 10079 [label=true]; 10074 -> 10280 [label=false]; 10281 -> 10282; 10079 -> 10084 [label=true]; 10079 -> 10279 [label=false]; 10280 -> 10281; 10084 -> 10089 [label=true]; 10084 -> 10278 [label=false]; 10279 -> 10280; 10089 -> 10094 [label=true]; 10089 -> 10277 [label=false]; 10278 -> 10279; 10094 -> 10099 [label=true]; 10094 -> 10276 [label=false]; 10277 -> 10278; 10099 -> 10104 [label=true]; 10099 -> 10275 [label=false]; 10276 -> 10277; 10104 -> 10109 [label=true]; 10104 -> 10274 [label=false]; 10275 -> 10276; 10109 -> 10114 [label=true]; 10109 -> 10273 [label=false]; 10274 -> 10275; 10114 -> 10119 [label=true]; 10114 -> 10272 [label=false]; 10273 -> 10274; 10119 -> 10124 [label=true]; 10119 -> 10271 [label=false]; 10272 -> 10273; 10124 -> 10129 [label=true]; 10124 -> 10270 [label=false]; 10271 -> 10272; 10129 -> 10134 [label=true]; 10129 -> 10269 [label=false]; 10270 -> 10271; 10134 -> 10139 [label=true]; 10134 -> 10268 [label=false]; 10269 -> 10270; 10139 -> 10144 [label=true]; 10139 -> 10267 [label=false]; 10268 -> 10269; 10144 -> 10149 [label=true]; 10144 -> 10266 [label=false]; 10267 -> 10268; 10149 -> 10154 [label=true]; 10149 -> 10265 [label=false]; 10266 -> 10267; 10154 -> 10159 [label=true]; 10154 -> 10264 [label=false]; 10265 -> 10266; 10159 -> 10164 [label=true]; 10159 -> 10263 [label=false]; 10264 -> 10265; 10164 -> 10169 [label=true]; 10164 -> 10262 [label=false]; 10263 -> 10264; 10169 -> 10174 [label=true]; 10169 -> 10261 [label=false]; 10262 -> 10263; 10174 -> 10179 [label=true]; 10174 -> 10260 [label=false]; 10261 -> 10262; 10179 -> 10184 [label=true]; 10179 -> 10259 [label=false]; 10260 -> 10261; 10184 -> 10189 [label=true]; 10184 -> 10258 [label=false]; 10259 -> 10260; 10189 -> 10194 [label=true]; 10189 -> 10257 [label=false]; 10258 -> 10259; 10194 -> 10199 [label=true]; 10194 -> 10256 [label=false]; 10257 -> 10258; 10199 -> 10204 [label=true]; 10199 -> 10255 [label=false]; 10256 -> 10257; 10204 -> 10209 [label=true]; 10204 -> 10254 [label=false]; 10255 -> 10256; 10209 -> 10214 [label=true]; 10209 -> 10253 [label=false]; 10254 -> 10255; 10214 -> 10219 [label=true]; 10214 -> 10252 [label=false]; 10253 -> 10254; 10219 -> 10224 [label=true]; 10219 -> 10251 [label=false]; 10252 -> 10253; 10224 -> 10229 [label=true]; 10224 -> 10250 [label=false]; 10251 -> 10252; 10229 -> 10234 [label=true]; 10229 -> 10249 [label=false]; 10250 -> 10251; 10234 -> 10239 [label=true]; 10234 -> 10248 [label=false]; 10249 -> 10250; 10239 -> 10244 [label=true]; 10239 -> 10247 [label=false]; 10248 -> 10249; 10244 -> 10247; 10247 -> 10248; }golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n256.dot000066400000000000000000000513351450372207100257040ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 1542; 14; 1541; 19; 1540; 24; 1539; 29; 1538; 34; 1537; 39; 1536; 44; 1535; 49; 1534; 54; 1533; 59; 1532; 64; 1531; 69; 1530; 74; 1529; 79; 1528; 84; 1527; 89; 1526; 94; 1525; 99; 1524; 104; 1523; 109; 1522; 114; 1521; 119; 1520; 124; 1519; 129; 1518; 134; 1517; 139; 1516; 144; 1515; 149; 1514; 154; 1513; 159; 1512; 164; 1511; 169; 1510; 174; 1509; 179; 1508; 184; 1507; 189; 1506; 194; 1505; 199; 1504; 204; 1503; 209; 1502; 214; 1501; 219; 1500; 224; 1499; 229; 1498; 234; 1497; 239; 1496; 244; 1495; 249; 1494; 254; 1493; 259; 1492; 264; 1491; 269; 1490; 274; 1489; 279; 1488; 284; 1487; 289; 1486; 294; 1485; 299; 1484; 304; 1483; 309; 1482; 314; 1481; 319; 1480; 324; 1479; 329; 1478; 334; 1477; 339; 1476; 344; 1475; 349; 1474; 354; 1473; 359; 1472; 364; 1471; 369; 1470; 374; 1469; 379; 1468; 384; 1467; 389; 1466; 394; 1465; 399; 1464; 404; 1463; 409; 1462; 414; 1461; 419; 1460; 424; 1459; 429; 1458; 434; 1457; 439; 1456; 444; 1455; 449; 1454; 454; 1453; 459; 1452; 464; 1451; 469; 1450; 474; 1449; 479; 1448; 484; 1447; 489; 1446; 494; 1445; 499; 1444; 504; 1443; 509; 1442; 514; 1441; 519; 1440; 524; 1439; 529; 1438; 534; 1437; 539; 1436; 544; 1435; 549; 1434; 554; 1433; 559; 1432; 564; 1431; 569; 1430; 574; 1429; 579; 1428; 584; 1427; 589; 1426; 594; 1425; 599; 1424; 604; 1423; 609; 1422; 614; 1421; 619; 1420; 624; 1419; 629; 1418; 634; 1417; 639; 1416; 644; 1415; 649; 1414; 654; 1413; 659; 1412; 664; 1411; 669; 1410; 674; 1409; 679; 1408; 684; 1407; 689; 1406; 694; 1405; 699; 1404; 704; 1403; 709; 1402; 714; 1401; 719; 1400; 724; 1399; 729; 1398; 734; 1397; 739; 1396; 744; 1395; 749; 1394; 754; 1393; 759; 1392; 764; 1391; 769; 1390; 774; 1389; 779; 1388; 784; 1387; 789; 1386; 794; 1385; 799; 1384; 804; 1383; 809; 1382; 814; 1381; 819; 1380; 824; 1379; 829; 1378; 834; 1377; 839; 1376; 844; 1375; 849; 1374; 854; 1373; 859; 1372; 864; 1371; 869; 1370; 874; 1369; 879; 1368; 884; 1367; 889; 1366; 894; 1365; 899; 1364; 904; 1363; 909; 1362; 914; 1361; 919; 1360; 924; 1359; 929; 1358; 934; 1357; 939; 1356; 944; 1355; 949; 1354; 954; 1353; 959; 1352; 964; 1351; 969; 1350; 974; 1349; 979; 1348; 984; 1347; 989; 1346; 994; 1345; 999; 1344; 1004; 1343; 1009; 1342; 1014; 1341; 1019; 1340; 1024; 1339; 1029; 1338; 1034; 1337; 1039; 1336; 1044; 1335; 1049; 1334; 1054; 1333; 1059; 1332; 1064; 1331; 1069; 1330; 1074; 1329; 1079; 1328; 1084; 1327; 1089; 1326; 1094; 1325; 1099; 1324; 1104; 1323; 1109; 1322; 1114; 1321; 1119; 1320; 1124; 1319; 1129; 1318; 1134; 1317; 1139; 1316; 1144; 1315; 1149; 1314; 1154; 1313; 1159; 1312; 1164; 1311; 1169; 1310; 1174; 1309; 1179; 1308; 1184; 1307; 1189; 1306; 1194; 1305; 1199; 1304; 1204; 1303; 1209; 1302; 1214; 1301; 1219; 1300; 1224; 1299; 1229; 1298; 1234; 1297; 1239; 1296; 1244; 1295; 1249; 1294; 1254; 1293; 1259; 1292; 1264; 1291; 1269; 1290; 1274; 1289; 1279; 1288; 1284; 1287; // Edge definitions. 2 -> 9 [label=true]; 2 -> 1542 [label=false]; 9 -> 14 [label=true]; 9 -> 1541 [label=false]; 14 -> 19 [label=true]; 14 -> 1540 [label=false]; 1541 -> 1542; 19 -> 24 [label=true]; 19 -> 1539 [label=false]; 1540 -> 1541; 24 -> 29 [label=true]; 24 -> 1538 [label=false]; 1539 -> 1540; 29 -> 34 [label=true]; 29 -> 1537 [label=false]; 1538 -> 1539; 34 -> 39 [label=true]; 34 -> 1536 [label=false]; 1537 -> 1538; 39 -> 44 [label=true]; 39 -> 1535 [label=false]; 1536 -> 1537; 44 -> 49 [label=true]; 44 -> 1534 [label=false]; 1535 -> 1536; 49 -> 54 [label=true]; 49 -> 1533 [label=false]; 1534 -> 1535; 54 -> 59 [label=true]; 54 -> 1532 [label=false]; 1533 -> 1534; 59 -> 64 [label=true]; 59 -> 1531 [label=false]; 1532 -> 1533; 64 -> 69 [label=true]; 64 -> 1530 [label=false]; 1531 -> 1532; 69 -> 74 [label=true]; 69 -> 1529 [label=false]; 1530 -> 1531; 74 -> 79 [label=true]; 74 -> 1528 [label=false]; 1529 -> 1530; 79 -> 84 [label=true]; 79 -> 1527 [label=false]; 1528 -> 1529; 84 -> 89 [label=true]; 84 -> 1526 [label=false]; 1527 -> 1528; 89 -> 94 [label=true]; 89 -> 1525 [label=false]; 1526 -> 1527; 94 -> 99 [label=true]; 94 -> 1524 [label=false]; 1525 -> 1526; 99 -> 104 [label=true]; 99 -> 1523 [label=false]; 1524 -> 1525; 104 -> 109 [label=true]; 104 -> 1522 [label=false]; 1523 -> 1524; 109 -> 114 [label=true]; 109 -> 1521 [label=false]; 1522 -> 1523; 114 -> 119 [label=true]; 114 -> 1520 [label=false]; 1521 -> 1522; 119 -> 124 [label=true]; 119 -> 1519 [label=false]; 1520 -> 1521; 124 -> 129 [label=true]; 124 -> 1518 [label=false]; 1519 -> 1520; 129 -> 134 [label=true]; 129 -> 1517 [label=false]; 1518 -> 1519; 134 -> 139 [label=true]; 134 -> 1516 [label=false]; 1517 -> 1518; 139 -> 144 [label=true]; 139 -> 1515 [label=false]; 1516 -> 1517; 144 -> 149 [label=true]; 144 -> 1514 [label=false]; 1515 -> 1516; 149 -> 154 [label=true]; 149 -> 1513 [label=false]; 1514 -> 1515; 154 -> 159 [label=true]; 154 -> 1512 [label=false]; 1513 -> 1514; 159 -> 164 [label=true]; 159 -> 1511 [label=false]; 1512 -> 1513; 164 -> 169 [label=true]; 164 -> 1510 [label=false]; 1511 -> 1512; 169 -> 174 [label=true]; 169 -> 1509 [label=false]; 1510 -> 1511; 174 -> 179 [label=true]; 174 -> 1508 [label=false]; 1509 -> 1510; 179 -> 184 [label=true]; 179 -> 1507 [label=false]; 1508 -> 1509; 184 -> 189 [label=true]; 184 -> 1506 [label=false]; 1507 -> 1508; 189 -> 194 [label=true]; 189 -> 1505 [label=false]; 1506 -> 1507; 194 -> 199 [label=true]; 194 -> 1504 [label=false]; 1505 -> 1506; 199 -> 204 [label=true]; 199 -> 1503 [label=false]; 1504 -> 1505; 204 -> 209 [label=true]; 204 -> 1502 [label=false]; 1503 -> 1504; 209 -> 214 [label=true]; 209 -> 1501 [label=false]; 1502 -> 1503; 214 -> 219 [label=true]; 214 -> 1500 [label=false]; 1501 -> 1502; 219 -> 224 [label=true]; 219 -> 1499 [label=false]; 1500 -> 1501; 224 -> 229 [label=true]; 224 -> 1498 [label=false]; 1499 -> 1500; 229 -> 234 [label=true]; 229 -> 1497 [label=false]; 1498 -> 1499; 234 -> 239 [label=true]; 234 -> 1496 [label=false]; 1497 -> 1498; 239 -> 244 [label=true]; 239 -> 1495 [label=false]; 1496 -> 1497; 244 -> 249 [label=true]; 244 -> 1494 [label=false]; 1495 -> 1496; 249 -> 254 [label=true]; 249 -> 1493 [label=false]; 1494 -> 1495; 254 -> 259 [label=true]; 254 -> 1492 [label=false]; 1493 -> 1494; 259 -> 264 [label=true]; 259 -> 1491 [label=false]; 1492 -> 1493; 264 -> 269 [label=true]; 264 -> 1490 [label=false]; 1491 -> 1492; 269 -> 274 [label=true]; 269 -> 1489 [label=false]; 1490 -> 1491; 274 -> 279 [label=true]; 274 -> 1488 [label=false]; 1489 -> 1490; 279 -> 284 [label=true]; 279 -> 1487 [label=false]; 1488 -> 1489; 284 -> 289 [label=true]; 284 -> 1486 [label=false]; 1487 -> 1488; 289 -> 294 [label=true]; 289 -> 1485 [label=false]; 1486 -> 1487; 294 -> 299 [label=true]; 294 -> 1484 [label=false]; 1485 -> 1486; 299 -> 304 [label=true]; 299 -> 1483 [label=false]; 1484 -> 1485; 304 -> 309 [label=true]; 304 -> 1482 [label=false]; 1483 -> 1484; 309 -> 314 [label=true]; 309 -> 1481 [label=false]; 1482 -> 1483; 314 -> 319 [label=true]; 314 -> 1480 [label=false]; 1481 -> 1482; 319 -> 324 [label=true]; 319 -> 1479 [label=false]; 1480 -> 1481; 324 -> 329 [label=true]; 324 -> 1478 [label=false]; 1479 -> 1480; 329 -> 334 [label=true]; 329 -> 1477 [label=false]; 1478 -> 1479; 334 -> 339 [label=true]; 334 -> 1476 [label=false]; 1477 -> 1478; 339 -> 344 [label=true]; 339 -> 1475 [label=false]; 1476 -> 1477; 344 -> 349 [label=true]; 344 -> 1474 [label=false]; 1475 -> 1476; 349 -> 354 [label=true]; 349 -> 1473 [label=false]; 1474 -> 1475; 354 -> 359 [label=true]; 354 -> 1472 [label=false]; 1473 -> 1474; 359 -> 364 [label=true]; 359 -> 1471 [label=false]; 1472 -> 1473; 364 -> 369 [label=true]; 364 -> 1470 [label=false]; 1471 -> 1472; 369 -> 374 [label=true]; 369 -> 1469 [label=false]; 1470 -> 1471; 374 -> 379 [label=true]; 374 -> 1468 [label=false]; 1469 -> 1470; 379 -> 384 [label=true]; 379 -> 1467 [label=false]; 1468 -> 1469; 384 -> 389 [label=true]; 384 -> 1466 [label=false]; 1467 -> 1468; 389 -> 394 [label=true]; 389 -> 1465 [label=false]; 1466 -> 1467; 394 -> 399 [label=true]; 394 -> 1464 [label=false]; 1465 -> 1466; 399 -> 404 [label=true]; 399 -> 1463 [label=false]; 1464 -> 1465; 404 -> 409 [label=true]; 404 -> 1462 [label=false]; 1463 -> 1464; 409 -> 414 [label=true]; 409 -> 1461 [label=false]; 1462 -> 1463; 414 -> 419 [label=true]; 414 -> 1460 [label=false]; 1461 -> 1462; 419 -> 424 [label=true]; 419 -> 1459 [label=false]; 1460 -> 1461; 424 -> 429 [label=true]; 424 -> 1458 [label=false]; 1459 -> 1460; 429 -> 434 [label=true]; 429 -> 1457 [label=false]; 1458 -> 1459; 434 -> 439 [label=true]; 434 -> 1456 [label=false]; 1457 -> 1458; 439 -> 444 [label=true]; 439 -> 1455 [label=false]; 1456 -> 1457; 444 -> 449 [label=true]; 444 -> 1454 [label=false]; 1455 -> 1456; 449 -> 454 [label=true]; 449 -> 1453 [label=false]; 1454 -> 1455; 454 -> 459 [label=true]; 454 -> 1452 [label=false]; 1453 -> 1454; 459 -> 464 [label=true]; 459 -> 1451 [label=false]; 1452 -> 1453; 464 -> 469 [label=true]; 464 -> 1450 [label=false]; 1451 -> 1452; 469 -> 474 [label=true]; 469 -> 1449 [label=false]; 1450 -> 1451; 474 -> 479 [label=true]; 474 -> 1448 [label=false]; 1449 -> 1450; 479 -> 484 [label=true]; 479 -> 1447 [label=false]; 1448 -> 1449; 484 -> 489 [label=true]; 484 -> 1446 [label=false]; 1447 -> 1448; 489 -> 494 [label=true]; 489 -> 1445 [label=false]; 1446 -> 1447; 494 -> 499 [label=true]; 494 -> 1444 [label=false]; 1445 -> 1446; 499 -> 504 [label=true]; 499 -> 1443 [label=false]; 1444 -> 1445; 504 -> 509 [label=true]; 504 -> 1442 [label=false]; 1443 -> 1444; 509 -> 514 [label=true]; 509 -> 1441 [label=false]; 1442 -> 1443; 514 -> 519 [label=true]; 514 -> 1440 [label=false]; 1441 -> 1442; 519 -> 524 [label=true]; 519 -> 1439 [label=false]; 1440 -> 1441; 524 -> 529 [label=true]; 524 -> 1438 [label=false]; 1439 -> 1440; 529 -> 534 [label=true]; 529 -> 1437 [label=false]; 1438 -> 1439; 534 -> 539 [label=true]; 534 -> 1436 [label=false]; 1437 -> 1438; 539 -> 544 [label=true]; 539 -> 1435 [label=false]; 1436 -> 1437; 544 -> 549 [label=true]; 544 -> 1434 [label=false]; 1435 -> 1436; 549 -> 554 [label=true]; 549 -> 1433 [label=false]; 1434 -> 1435; 554 -> 559 [label=true]; 554 -> 1432 [label=false]; 1433 -> 1434; 559 -> 564 [label=true]; 559 -> 1431 [label=false]; 1432 -> 1433; 564 -> 569 [label=true]; 564 -> 1430 [label=false]; 1431 -> 1432; 569 -> 574 [label=true]; 569 -> 1429 [label=false]; 1430 -> 1431; 574 -> 579 [label=true]; 574 -> 1428 [label=false]; 1429 -> 1430; 579 -> 584 [label=true]; 579 -> 1427 [label=false]; 1428 -> 1429; 584 -> 589 [label=true]; 584 -> 1426 [label=false]; 1427 -> 1428; 589 -> 594 [label=true]; 589 -> 1425 [label=false]; 1426 -> 1427; 594 -> 599 [label=true]; 594 -> 1424 [label=false]; 1425 -> 1426; 599 -> 604 [label=true]; 599 -> 1423 [label=false]; 1424 -> 1425; 604 -> 609 [label=true]; 604 -> 1422 [label=false]; 1423 -> 1424; 609 -> 614 [label=true]; 609 -> 1421 [label=false]; 1422 -> 1423; 614 -> 619 [label=true]; 614 -> 1420 [label=false]; 1421 -> 1422; 619 -> 624 [label=true]; 619 -> 1419 [label=false]; 1420 -> 1421; 624 -> 629 [label=true]; 624 -> 1418 [label=false]; 1419 -> 1420; 629 -> 634 [label=true]; 629 -> 1417 [label=false]; 1418 -> 1419; 634 -> 639 [label=true]; 634 -> 1416 [label=false]; 1417 -> 1418; 639 -> 644 [label=true]; 639 -> 1415 [label=false]; 1416 -> 1417; 644 -> 649 [label=true]; 644 -> 1414 [label=false]; 1415 -> 1416; 649 -> 654 [label=true]; 649 -> 1413 [label=false]; 1414 -> 1415; 654 -> 659 [label=true]; 654 -> 1412 [label=false]; 1413 -> 1414; 659 -> 664 [label=true]; 659 -> 1411 [label=false]; 1412 -> 1413; 664 -> 669 [label=true]; 664 -> 1410 [label=false]; 1411 -> 1412; 669 -> 674 [label=true]; 669 -> 1409 [label=false]; 1410 -> 1411; 674 -> 679 [label=true]; 674 -> 1408 [label=false]; 1409 -> 1410; 679 -> 684 [label=true]; 679 -> 1407 [label=false]; 1408 -> 1409; 684 -> 689 [label=true]; 684 -> 1406 [label=false]; 1407 -> 1408; 689 -> 694 [label=true]; 689 -> 1405 [label=false]; 1406 -> 1407; 694 -> 699 [label=true]; 694 -> 1404 [label=false]; 1405 -> 1406; 699 -> 704 [label=true]; 699 -> 1403 [label=false]; 1404 -> 1405; 704 -> 709 [label=true]; 704 -> 1402 [label=false]; 1403 -> 1404; 709 -> 714 [label=true]; 709 -> 1401 [label=false]; 1402 -> 1403; 714 -> 719 [label=true]; 714 -> 1400 [label=false]; 1401 -> 1402; 719 -> 724 [label=true]; 719 -> 1399 [label=false]; 1400 -> 1401; 724 -> 729 [label=true]; 724 -> 1398 [label=false]; 1399 -> 1400; 729 -> 734 [label=true]; 729 -> 1397 [label=false]; 1398 -> 1399; 734 -> 739 [label=true]; 734 -> 1396 [label=false]; 1397 -> 1398; 739 -> 744 [label=true]; 739 -> 1395 [label=false]; 1396 -> 1397; 744 -> 749 [label=true]; 744 -> 1394 [label=false]; 1395 -> 1396; 749 -> 754 [label=true]; 749 -> 1393 [label=false]; 1394 -> 1395; 754 -> 759 [label=true]; 754 -> 1392 [label=false]; 1393 -> 1394; 759 -> 764 [label=true]; 759 -> 1391 [label=false]; 1392 -> 1393; 764 -> 769 [label=true]; 764 -> 1390 [label=false]; 1391 -> 1392; 769 -> 774 [label=true]; 769 -> 1389 [label=false]; 1390 -> 1391; 774 -> 779 [label=true]; 774 -> 1388 [label=false]; 1389 -> 1390; 779 -> 784 [label=true]; 779 -> 1387 [label=false]; 1388 -> 1389; 784 -> 789 [label=true]; 784 -> 1386 [label=false]; 1387 -> 1388; 789 -> 794 [label=true]; 789 -> 1385 [label=false]; 1386 -> 1387; 794 -> 799 [label=true]; 794 -> 1384 [label=false]; 1385 -> 1386; 799 -> 804 [label=true]; 799 -> 1383 [label=false]; 1384 -> 1385; 804 -> 809 [label=true]; 804 -> 1382 [label=false]; 1383 -> 1384; 809 -> 814 [label=true]; 809 -> 1381 [label=false]; 1382 -> 1383; 814 -> 819 [label=true]; 814 -> 1380 [label=false]; 1381 -> 1382; 819 -> 824 [label=true]; 819 -> 1379 [label=false]; 1380 -> 1381; 824 -> 829 [label=true]; 824 -> 1378 [label=false]; 1379 -> 1380; 829 -> 834 [label=true]; 829 -> 1377 [label=false]; 1378 -> 1379; 834 -> 839 [label=true]; 834 -> 1376 [label=false]; 1377 -> 1378; 839 -> 844 [label=true]; 839 -> 1375 [label=false]; 1376 -> 1377; 844 -> 849 [label=true]; 844 -> 1374 [label=false]; 1375 -> 1376; 849 -> 854 [label=true]; 849 -> 1373 [label=false]; 1374 -> 1375; 854 -> 859 [label=true]; 854 -> 1372 [label=false]; 1373 -> 1374; 859 -> 864 [label=true]; 859 -> 1371 [label=false]; 1372 -> 1373; 864 -> 869 [label=true]; 864 -> 1370 [label=false]; 1371 -> 1372; 869 -> 874 [label=true]; 869 -> 1369 [label=false]; 1370 -> 1371; 874 -> 879 [label=true]; 874 -> 1368 [label=false]; 1369 -> 1370; 879 -> 884 [label=true]; 879 -> 1367 [label=false]; 1368 -> 1369; 884 -> 889 [label=true]; 884 -> 1366 [label=false]; 1367 -> 1368; 889 -> 894 [label=true]; 889 -> 1365 [label=false]; 1366 -> 1367; 894 -> 899 [label=true]; 894 -> 1364 [label=false]; 1365 -> 1366; 899 -> 904 [label=true]; 899 -> 1363 [label=false]; 1364 -> 1365; 904 -> 909 [label=true]; 904 -> 1362 [label=false]; 1363 -> 1364; 909 -> 914 [label=true]; 909 -> 1361 [label=false]; 1362 -> 1363; 914 -> 919 [label=true]; 914 -> 1360 [label=false]; 1361 -> 1362; 919 -> 924 [label=true]; 919 -> 1359 [label=false]; 1360 -> 1361; 924 -> 929 [label=true]; 924 -> 1358 [label=false]; 1359 -> 1360; 929 -> 934 [label=true]; 929 -> 1357 [label=false]; 1358 -> 1359; 934 -> 939 [label=true]; 934 -> 1356 [label=false]; 1357 -> 1358; 939 -> 944 [label=true]; 939 -> 1355 [label=false]; 1356 -> 1357; 944 -> 949 [label=true]; 944 -> 1354 [label=false]; 1355 -> 1356; 949 -> 954 [label=true]; 949 -> 1353 [label=false]; 1354 -> 1355; 954 -> 959 [label=true]; 954 -> 1352 [label=false]; 1353 -> 1354; 959 -> 964 [label=true]; 959 -> 1351 [label=false]; 1352 -> 1353; 964 -> 969 [label=true]; 964 -> 1350 [label=false]; 1351 -> 1352; 969 -> 974 [label=true]; 969 -> 1349 [label=false]; 1350 -> 1351; 974 -> 979 [label=true]; 974 -> 1348 [label=false]; 1349 -> 1350; 979 -> 984 [label=true]; 979 -> 1347 [label=false]; 1348 -> 1349; 984 -> 989 [label=true]; 984 -> 1346 [label=false]; 1347 -> 1348; 989 -> 994 [label=true]; 989 -> 1345 [label=false]; 1346 -> 1347; 994 -> 999 [label=true]; 994 -> 1344 [label=false]; 1345 -> 1346; 999 -> 1004 [label=true]; 999 -> 1343 [label=false]; 1344 -> 1345; 1004 -> 1009 [label=true]; 1004 -> 1342 [label=false]; 1343 -> 1344; 1009 -> 1014 [label=true]; 1009 -> 1341 [label=false]; 1342 -> 1343; 1014 -> 1019 [label=true]; 1014 -> 1340 [label=false]; 1341 -> 1342; 1019 -> 1024 [label=true]; 1019 -> 1339 [label=false]; 1340 -> 1341; 1024 -> 1029 [label=true]; 1024 -> 1338 [label=false]; 1339 -> 1340; 1029 -> 1034 [label=true]; 1029 -> 1337 [label=false]; 1338 -> 1339; 1034 -> 1039 [label=true]; 1034 -> 1336 [label=false]; 1337 -> 1338; 1039 -> 1044 [label=true]; 1039 -> 1335 [label=false]; 1336 -> 1337; 1044 -> 1049 [label=true]; 1044 -> 1334 [label=false]; 1335 -> 1336; 1049 -> 1054 [label=true]; 1049 -> 1333 [label=false]; 1334 -> 1335; 1054 -> 1059 [label=true]; 1054 -> 1332 [label=false]; 1333 -> 1334; 1059 -> 1064 [label=true]; 1059 -> 1331 [label=false]; 1332 -> 1333; 1064 -> 1069 [label=true]; 1064 -> 1330 [label=false]; 1331 -> 1332; 1069 -> 1074 [label=true]; 1069 -> 1329 [label=false]; 1330 -> 1331; 1074 -> 1079 [label=true]; 1074 -> 1328 [label=false]; 1329 -> 1330; 1079 -> 1084 [label=true]; 1079 -> 1327 [label=false]; 1328 -> 1329; 1084 -> 1089 [label=true]; 1084 -> 1326 [label=false]; 1327 -> 1328; 1089 -> 1094 [label=true]; 1089 -> 1325 [label=false]; 1326 -> 1327; 1094 -> 1099 [label=true]; 1094 -> 1324 [label=false]; 1325 -> 1326; 1099 -> 1104 [label=true]; 1099 -> 1323 [label=false]; 1324 -> 1325; 1104 -> 1109 [label=true]; 1104 -> 1322 [label=false]; 1323 -> 1324; 1109 -> 1114 [label=true]; 1109 -> 1321 [label=false]; 1322 -> 1323; 1114 -> 1119 [label=true]; 1114 -> 1320 [label=false]; 1321 -> 1322; 1119 -> 1124 [label=true]; 1119 -> 1319 [label=false]; 1320 -> 1321; 1124 -> 1129 [label=true]; 1124 -> 1318 [label=false]; 1319 -> 1320; 1129 -> 1134 [label=true]; 1129 -> 1317 [label=false]; 1318 -> 1319; 1134 -> 1139 [label=true]; 1134 -> 1316 [label=false]; 1317 -> 1318; 1139 -> 1144 [label=true]; 1139 -> 1315 [label=false]; 1316 -> 1317; 1144 -> 1149 [label=true]; 1144 -> 1314 [label=false]; 1315 -> 1316; 1149 -> 1154 [label=true]; 1149 -> 1313 [label=false]; 1314 -> 1315; 1154 -> 1159 [label=true]; 1154 -> 1312 [label=false]; 1313 -> 1314; 1159 -> 1164 [label=true]; 1159 -> 1311 [label=false]; 1312 -> 1313; 1164 -> 1169 [label=true]; 1164 -> 1310 [label=false]; 1311 -> 1312; 1169 -> 1174 [label=true]; 1169 -> 1309 [label=false]; 1310 -> 1311; 1174 -> 1179 [label=true]; 1174 -> 1308 [label=false]; 1309 -> 1310; 1179 -> 1184 [label=true]; 1179 -> 1307 [label=false]; 1308 -> 1309; 1184 -> 1189 [label=true]; 1184 -> 1306 [label=false]; 1307 -> 1308; 1189 -> 1194 [label=true]; 1189 -> 1305 [label=false]; 1306 -> 1307; 1194 -> 1199 [label=true]; 1194 -> 1304 [label=false]; 1305 -> 1306; 1199 -> 1204 [label=true]; 1199 -> 1303 [label=false]; 1304 -> 1305; 1204 -> 1209 [label=true]; 1204 -> 1302 [label=false]; 1303 -> 1304; 1209 -> 1214 [label=true]; 1209 -> 1301 [label=false]; 1302 -> 1303; 1214 -> 1219 [label=true]; 1214 -> 1300 [label=false]; 1301 -> 1302; 1219 -> 1224 [label=true]; 1219 -> 1299 [label=false]; 1300 -> 1301; 1224 -> 1229 [label=true]; 1224 -> 1298 [label=false]; 1299 -> 1300; 1229 -> 1234 [label=true]; 1229 -> 1297 [label=false]; 1298 -> 1299; 1234 -> 1239 [label=true]; 1234 -> 1296 [label=false]; 1297 -> 1298; 1239 -> 1244 [label=true]; 1239 -> 1295 [label=false]; 1296 -> 1297; 1244 -> 1249 [label=true]; 1244 -> 1294 [label=false]; 1295 -> 1296; 1249 -> 1254 [label=true]; 1249 -> 1293 [label=false]; 1294 -> 1295; 1254 -> 1259 [label=true]; 1254 -> 1292 [label=false]; 1293 -> 1294; 1259 -> 1264 [label=true]; 1259 -> 1291 [label=false]; 1292 -> 1293; 1264 -> 1269 [label=true]; 1264 -> 1290 [label=false]; 1291 -> 1292; 1269 -> 1274 [label=true]; 1269 -> 1289 [label=false]; 1290 -> 1291; 1274 -> 1279 [label=true]; 1274 -> 1288 [label=false]; 1289 -> 1290; 1279 -> 1284 [label=true]; 1279 -> 1287 [label=false]; 1288 -> 1289; 1284 -> 1287; 1287 -> 1288; }golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n32.dot000066400000000000000000000046731450372207100256170ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 198; 14; 197; 19; 196; 24; 195; 29; 194; 34; 193; 39; 192; 44; 191; 49; 190; 54; 189; 59; 188; 64; 187; 69; 186; 74; 185; 79; 184; 84; 183; 89; 182; 94; 181; 99; 180; 104; 179; 109; 178; 114; 177; 119; 176; 124; 175; 129; 174; 134; 173; 139; 172; 144; 171; 149; 170; 154; 169; 159; 168; 164; 167; // Edge definitions. 2 -> 9 [label=true]; 2 -> 198 [label=false]; 9 -> 14 [label=true]; 9 -> 197 [label=false]; 14 -> 19 [label=true]; 14 -> 196 [label=false]; 197 -> 198; 19 -> 24 [label=true]; 19 -> 195 [label=false]; 196 -> 197; 24 -> 29 [label=true]; 24 -> 194 [label=false]; 195 -> 196; 29 -> 34 [label=true]; 29 -> 193 [label=false]; 194 -> 195; 34 -> 39 [label=true]; 34 -> 192 [label=false]; 193 -> 194; 39 -> 44 [label=true]; 39 -> 191 [label=false]; 192 -> 193; 44 -> 49 [label=true]; 44 -> 190 [label=false]; 191 -> 192; 49 -> 54 [label=true]; 49 -> 189 [label=false]; 190 -> 191; 54 -> 59 [label=true]; 54 -> 188 [label=false]; 189 -> 190; 59 -> 64 [label=true]; 59 -> 187 [label=false]; 188 -> 189; 64 -> 69 [label=true]; 64 -> 186 [label=false]; 187 -> 188; 69 -> 74 [label=true]; 69 -> 185 [label=false]; 186 -> 187; 74 -> 79 [label=true]; 74 -> 184 [label=false]; 185 -> 186; 79 -> 84 [label=true]; 79 -> 183 [label=false]; 184 -> 185; 84 -> 89 [label=true]; 84 -> 182 [label=false]; 183 -> 184; 89 -> 94 [label=true]; 89 -> 181 [label=false]; 182 -> 183; 94 -> 99 [label=true]; 94 -> 180 [label=false]; 181 -> 182; 99 -> 104 [label=true]; 99 -> 179 [label=false]; 180 -> 181; 104 -> 109 [label=true]; 104 -> 178 [label=false]; 179 -> 180; 109 -> 114 [label=true]; 109 -> 177 [label=false]; 178 -> 179; 114 -> 119 [label=true]; 114 -> 176 [label=false]; 177 -> 178; 119 -> 124 [label=true]; 119 -> 175 [label=false]; 176 -> 177; 124 -> 129 [label=true]; 124 -> 174 [label=false]; 175 -> 176; 129 -> 134 [label=true]; 129 -> 173 [label=false]; 174 -> 175; 134 -> 139 [label=true]; 134 -> 172 [label=false]; 173 -> 174; 139 -> 144 [label=true]; 139 -> 171 [label=false]; 172 -> 173; 144 -> 149 [label=true]; 144 -> 170 [label=false]; 171 -> 172; 149 -> 154 [label=true]; 149 -> 169 [label=false]; 170 -> 171; 154 -> 159 [label=true]; 154 -> 168 [label=false]; 169 -> 170; 159 -> 164 [label=true]; 159 -> 167 [label=false]; 168 -> 169; 164 -> 167; 167 -> 168; }golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n512.dot000066400000000000000000001243351450372207100257000ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 3078; 14; 3077; 19; 3076; 24; 3075; 29; 3074; 34; 3073; 39; 3072; 44; 3071; 49; 3070; 54; 3069; 59; 3068; 64; 3067; 69; 3066; 74; 3065; 79; 3064; 84; 3063; 89; 3062; 94; 3061; 99; 3060; 104; 3059; 109; 3058; 114; 3057; 119; 3056; 124; 3055; 129; 3054; 134; 3053; 139; 3052; 144; 3051; 149; 3050; 154; 3049; 159; 3048; 164; 3047; 169; 3046; 174; 3045; 179; 3044; 184; 3043; 189; 3042; 194; 3041; 199; 3040; 204; 3039; 209; 3038; 214; 3037; 219; 3036; 224; 3035; 229; 3034; 234; 3033; 239; 3032; 244; 3031; 249; 3030; 254; 3029; 259; 3028; 264; 3027; 269; 3026; 274; 3025; 279; 3024; 284; 3023; 289; 3022; 294; 3021; 299; 3020; 304; 3019; 309; 3018; 314; 3017; 319; 3016; 324; 3015; 329; 3014; 334; 3013; 339; 3012; 344; 3011; 349; 3010; 354; 3009; 359; 3008; 364; 3007; 369; 3006; 374; 3005; 379; 3004; 384; 3003; 389; 3002; 394; 3001; 399; 3000; 404; 2999; 409; 2998; 414; 2997; 419; 2996; 424; 2995; 429; 2994; 434; 2993; 439; 2992; 444; 2991; 449; 2990; 454; 2989; 459; 2988; 464; 2987; 469; 2986; 474; 2985; 479; 2984; 484; 2983; 489; 2982; 494; 2981; 499; 2980; 504; 2979; 509; 2978; 514; 2977; 519; 2976; 524; 2975; 529; 2974; 534; 2973; 539; 2972; 544; 2971; 549; 2970; 554; 2969; 559; 2968; 564; 2967; 569; 2966; 574; 2965; 579; 2964; 584; 2963; 589; 2962; 594; 2961; 599; 2960; 604; 2959; 609; 2958; 614; 2957; 619; 2956; 624; 2955; 629; 2954; 634; 2953; 639; 2952; 644; 2951; 649; 2950; 654; 2949; 659; 2948; 664; 2947; 669; 2946; 674; 2945; 679; 2944; 684; 2943; 689; 2942; 694; 2941; 699; 2940; 704; 2939; 709; 2938; 714; 2937; 719; 2936; 724; 2935; 729; 2934; 734; 2933; 739; 2932; 744; 2931; 749; 2930; 754; 2929; 759; 2928; 764; 2927; 769; 2926; 774; 2925; 779; 2924; 784; 2923; 789; 2922; 794; 2921; 799; 2920; 804; 2919; 809; 2918; 814; 2917; 819; 2916; 824; 2915; 829; 2914; 834; 2913; 839; 2912; 844; 2911; 849; 2910; 854; 2909; 859; 2908; 864; 2907; 869; 2906; 874; 2905; 879; 2904; 884; 2903; 889; 2902; 894; 2901; 899; 2900; 904; 2899; 909; 2898; 914; 2897; 919; 2896; 924; 2895; 929; 2894; 934; 2893; 939; 2892; 944; 2891; 949; 2890; 954; 2889; 959; 2888; 964; 2887; 969; 2886; 974; 2885; 979; 2884; 984; 2883; 989; 2882; 994; 2881; 999; 2880; 1004; 2879; 1009; 2878; 1014; 2877; 1019; 2876; 1024; 2875; 1029; 2874; 1034; 2873; 1039; 2872; 1044; 2871; 1049; 2870; 1054; 2869; 1059; 2868; 1064; 2867; 1069; 2866; 1074; 2865; 1079; 2864; 1084; 2863; 1089; 2862; 1094; 2861; 1099; 2860; 1104; 2859; 1109; 2858; 1114; 2857; 1119; 2856; 1124; 2855; 1129; 2854; 1134; 2853; 1139; 2852; 1144; 2851; 1149; 2850; 1154; 2849; 1159; 2848; 1164; 2847; 1169; 2846; 1174; 2845; 1179; 2844; 1184; 2843; 1189; 2842; 1194; 2841; 1199; 2840; 1204; 2839; 1209; 2838; 1214; 2837; 1219; 2836; 1224; 2835; 1229; 2834; 1234; 2833; 1239; 2832; 1244; 2831; 1249; 2830; 1254; 2829; 1259; 2828; 1264; 2827; 1269; 2826; 1274; 2825; 1279; 2824; 1284; 2823; 1289; 2822; 1294; 2821; 1299; 2820; 1304; 2819; 1309; 2818; 1314; 2817; 1319; 2816; 1324; 2815; 1329; 2814; 1334; 2813; 1339; 2812; 1344; 2811; 1349; 2810; 1354; 2809; 1359; 2808; 1364; 2807; 1369; 2806; 1374; 2805; 1379; 2804; 1384; 2803; 1389; 2802; 1394; 2801; 1399; 2800; 1404; 2799; 1409; 2798; 1414; 2797; 1419; 2796; 1424; 2795; 1429; 2794; 1434; 2793; 1439; 2792; 1444; 2791; 1449; 2790; 1454; 2789; 1459; 2788; 1464; 2787; 1469; 2786; 1474; 2785; 1479; 2784; 1484; 2783; 1489; 2782; 1494; 2781; 1499; 2780; 1504; 2779; 1509; 2778; 1514; 2777; 1519; 2776; 1524; 2775; 1529; 2774; 1534; 2773; 1539; 2772; 1544; 2771; 1549; 2770; 1554; 2769; 1559; 2768; 1564; 2767; 1569; 2766; 1574; 2765; 1579; 2764; 1584; 2763; 1589; 2762; 1594; 2761; 1599; 2760; 1604; 2759; 1609; 2758; 1614; 2757; 1619; 2756; 1624; 2755; 1629; 2754; 1634; 2753; 1639; 2752; 1644; 2751; 1649; 2750; 1654; 2749; 1659; 2748; 1664; 2747; 1669; 2746; 1674; 2745; 1679; 2744; 1684; 2743; 1689; 2742; 1694; 2741; 1699; 2740; 1704; 2739; 1709; 2738; 1714; 2737; 1719; 2736; 1724; 2735; 1729; 2734; 1734; 2733; 1739; 2732; 1744; 2731; 1749; 2730; 1754; 2729; 1759; 2728; 1764; 2727; 1769; 2726; 1774; 2725; 1779; 2724; 1784; 2723; 1789; 2722; 1794; 2721; 1799; 2720; 1804; 2719; 1809; 2718; 1814; 2717; 1819; 2716; 1824; 2715; 1829; 2714; 1834; 2713; 1839; 2712; 1844; 2711; 1849; 2710; 1854; 2709; 1859; 2708; 1864; 2707; 1869; 2706; 1874; 2705; 1879; 2704; 1884; 2703; 1889; 2702; 1894; 2701; 1899; 2700; 1904; 2699; 1909; 2698; 1914; 2697; 1919; 2696; 1924; 2695; 1929; 2694; 1934; 2693; 1939; 2692; 1944; 2691; 1949; 2690; 1954; 2689; 1959; 2688; 1964; 2687; 1969; 2686; 1974; 2685; 1979; 2684; 1984; 2683; 1989; 2682; 1994; 2681; 1999; 2680; 2004; 2679; 2009; 2678; 2014; 2677; 2019; 2676; 2024; 2675; 2029; 2674; 2034; 2673; 2039; 2672; 2044; 2671; 2049; 2670; 2054; 2669; 2059; 2668; 2064; 2667; 2069; 2666; 2074; 2665; 2079; 2664; 2084; 2663; 2089; 2662; 2094; 2661; 2099; 2660; 2104; 2659; 2109; 2658; 2114; 2657; 2119; 2656; 2124; 2655; 2129; 2654; 2134; 2653; 2139; 2652; 2144; 2651; 2149; 2650; 2154; 2649; 2159; 2648; 2164; 2647; 2169; 2646; 2174; 2645; 2179; 2644; 2184; 2643; 2189; 2642; 2194; 2641; 2199; 2640; 2204; 2639; 2209; 2638; 2214; 2637; 2219; 2636; 2224; 2635; 2229; 2634; 2234; 2633; 2239; 2632; 2244; 2631; 2249; 2630; 2254; 2629; 2259; 2628; 2264; 2627; 2269; 2626; 2274; 2625; 2279; 2624; 2284; 2623; 2289; 2622; 2294; 2621; 2299; 2620; 2304; 2619; 2309; 2618; 2314; 2617; 2319; 2616; 2324; 2615; 2329; 2614; 2334; 2613; 2339; 2612; 2344; 2611; 2349; 2610; 2354; 2609; 2359; 2608; 2364; 2607; 2369; 2606; 2374; 2605; 2379; 2604; 2384; 2603; 2389; 2602; 2394; 2601; 2399; 2600; 2404; 2599; 2409; 2598; 2414; 2597; 2419; 2596; 2424; 2595; 2429; 2594; 2434; 2593; 2439; 2592; 2444; 2591; 2449; 2590; 2454; 2589; 2459; 2588; 2464; 2587; 2469; 2586; 2474; 2585; 2479; 2584; 2484; 2583; 2489; 2582; 2494; 2581; 2499; 2580; 2504; 2579; 2509; 2578; 2514; 2577; 2519; 2576; 2524; 2575; 2529; 2574; 2534; 2573; 2539; 2572; 2544; 2571; 2549; 2570; 2554; 2569; 2559; 2568; 2564; 2567; // Edge definitions. 2 -> 9 [label=true]; 2 -> 3078 [label=false]; 9 -> 14 [label=true]; 9 -> 3077 [label=false]; 14 -> 19 [label=true]; 14 -> 3076 [label=false]; 3077 -> 3078; 19 -> 24 [label=true]; 19 -> 3075 [label=false]; 3076 -> 3077; 24 -> 29 [label=true]; 24 -> 3074 [label=false]; 3075 -> 3076; 29 -> 34 [label=true]; 29 -> 3073 [label=false]; 3074 -> 3075; 34 -> 39 [label=true]; 34 -> 3072 [label=false]; 3073 -> 3074; 39 -> 44 [label=true]; 39 -> 3071 [label=false]; 3072 -> 3073; 44 -> 49 [label=true]; 44 -> 3070 [label=false]; 3071 -> 3072; 49 -> 54 [label=true]; 49 -> 3069 [label=false]; 3070 -> 3071; 54 -> 59 [label=true]; 54 -> 3068 [label=false]; 3069 -> 3070; 59 -> 64 [label=true]; 59 -> 3067 [label=false]; 3068 -> 3069; 64 -> 69 [label=true]; 64 -> 3066 [label=false]; 3067 -> 3068; 69 -> 74 [label=true]; 69 -> 3065 [label=false]; 3066 -> 3067; 74 -> 79 [label=true]; 74 -> 3064 [label=false]; 3065 -> 3066; 79 -> 84 [label=true]; 79 -> 3063 [label=false]; 3064 -> 3065; 84 -> 89 [label=true]; 84 -> 3062 [label=false]; 3063 -> 3064; 89 -> 94 [label=true]; 89 -> 3061 [label=false]; 3062 -> 3063; 94 -> 99 [label=true]; 94 -> 3060 [label=false]; 3061 -> 3062; 99 -> 104 [label=true]; 99 -> 3059 [label=false]; 3060 -> 3061; 104 -> 109 [label=true]; 104 -> 3058 [label=false]; 3059 -> 3060; 109 -> 114 [label=true]; 109 -> 3057 [label=false]; 3058 -> 3059; 114 -> 119 [label=true]; 114 -> 3056 [label=false]; 3057 -> 3058; 119 -> 124 [label=true]; 119 -> 3055 [label=false]; 3056 -> 3057; 124 -> 129 [label=true]; 124 -> 3054 [label=false]; 3055 -> 3056; 129 -> 134 [label=true]; 129 -> 3053 [label=false]; 3054 -> 3055; 134 -> 139 [label=true]; 134 -> 3052 [label=false]; 3053 -> 3054; 139 -> 144 [label=true]; 139 -> 3051 [label=false]; 3052 -> 3053; 144 -> 149 [label=true]; 144 -> 3050 [label=false]; 3051 -> 3052; 149 -> 154 [label=true]; 149 -> 3049 [label=false]; 3050 -> 3051; 154 -> 159 [label=true]; 154 -> 3048 [label=false]; 3049 -> 3050; 159 -> 164 [label=true]; 159 -> 3047 [label=false]; 3048 -> 3049; 164 -> 169 [label=true]; 164 -> 3046 [label=false]; 3047 -> 3048; 169 -> 174 [label=true]; 169 -> 3045 [label=false]; 3046 -> 3047; 174 -> 179 [label=true]; 174 -> 3044 [label=false]; 3045 -> 3046; 179 -> 184 [label=true]; 179 -> 3043 [label=false]; 3044 -> 3045; 184 -> 189 [label=true]; 184 -> 3042 [label=false]; 3043 -> 3044; 189 -> 194 [label=true]; 189 -> 3041 [label=false]; 3042 -> 3043; 194 -> 199 [label=true]; 194 -> 3040 [label=false]; 3041 -> 3042; 199 -> 204 [label=true]; 199 -> 3039 [label=false]; 3040 -> 3041; 204 -> 209 [label=true]; 204 -> 3038 [label=false]; 3039 -> 3040; 209 -> 214 [label=true]; 209 -> 3037 [label=false]; 3038 -> 3039; 214 -> 219 [label=true]; 214 -> 3036 [label=false]; 3037 -> 3038; 219 -> 224 [label=true]; 219 -> 3035 [label=false]; 3036 -> 3037; 224 -> 229 [label=true]; 224 -> 3034 [label=false]; 3035 -> 3036; 229 -> 234 [label=true]; 229 -> 3033 [label=false]; 3034 -> 3035; 234 -> 239 [label=true]; 234 -> 3032 [label=false]; 3033 -> 3034; 239 -> 244 [label=true]; 239 -> 3031 [label=false]; 3032 -> 3033; 244 -> 249 [label=true]; 244 -> 3030 [label=false]; 3031 -> 3032; 249 -> 254 [label=true]; 249 -> 3029 [label=false]; 3030 -> 3031; 254 -> 259 [label=true]; 254 -> 3028 [label=false]; 3029 -> 3030; 259 -> 264 [label=true]; 259 -> 3027 [label=false]; 3028 -> 3029; 264 -> 269 [label=true]; 264 -> 3026 [label=false]; 3027 -> 3028; 269 -> 274 [label=true]; 269 -> 3025 [label=false]; 3026 -> 3027; 274 -> 279 [label=true]; 274 -> 3024 [label=false]; 3025 -> 3026; 279 -> 284 [label=true]; 279 -> 3023 [label=false]; 3024 -> 3025; 284 -> 289 [label=true]; 284 -> 3022 [label=false]; 3023 -> 3024; 289 -> 294 [label=true]; 289 -> 3021 [label=false]; 3022 -> 3023; 294 -> 299 [label=true]; 294 -> 3020 [label=false]; 3021 -> 3022; 299 -> 304 [label=true]; 299 -> 3019 [label=false]; 3020 -> 3021; 304 -> 309 [label=true]; 304 -> 3018 [label=false]; 3019 -> 3020; 309 -> 314 [label=true]; 309 -> 3017 [label=false]; 3018 -> 3019; 314 -> 319 [label=true]; 314 -> 3016 [label=false]; 3017 -> 3018; 319 -> 324 [label=true]; 319 -> 3015 [label=false]; 3016 -> 3017; 324 -> 329 [label=true]; 324 -> 3014 [label=false]; 3015 -> 3016; 329 -> 334 [label=true]; 329 -> 3013 [label=false]; 3014 -> 3015; 334 -> 339 [label=true]; 334 -> 3012 [label=false]; 3013 -> 3014; 339 -> 344 [label=true]; 339 -> 3011 [label=false]; 3012 -> 3013; 344 -> 349 [label=true]; 344 -> 3010 [label=false]; 3011 -> 3012; 349 -> 354 [label=true]; 349 -> 3009 [label=false]; 3010 -> 3011; 354 -> 359 [label=true]; 354 -> 3008 [label=false]; 3009 -> 3010; 359 -> 364 [label=true]; 359 -> 3007 [label=false]; 3008 -> 3009; 364 -> 369 [label=true]; 364 -> 3006 [label=false]; 3007 -> 3008; 369 -> 374 [label=true]; 369 -> 3005 [label=false]; 3006 -> 3007; 374 -> 379 [label=true]; 374 -> 3004 [label=false]; 3005 -> 3006; 379 -> 384 [label=true]; 379 -> 3003 [label=false]; 3004 -> 3005; 384 -> 389 [label=true]; 384 -> 3002 [label=false]; 3003 -> 3004; 389 -> 394 [label=true]; 389 -> 3001 [label=false]; 3002 -> 3003; 394 -> 399 [label=true]; 394 -> 3000 [label=false]; 3001 -> 3002; 399 -> 404 [label=true]; 399 -> 2999 [label=false]; 3000 -> 3001; 404 -> 409 [label=true]; 404 -> 2998 [label=false]; 2999 -> 3000; 409 -> 414 [label=true]; 409 -> 2997 [label=false]; 2998 -> 2999; 414 -> 419 [label=true]; 414 -> 2996 [label=false]; 2997 -> 2998; 419 -> 424 [label=true]; 419 -> 2995 [label=false]; 2996 -> 2997; 424 -> 429 [label=true]; 424 -> 2994 [label=false]; 2995 -> 2996; 429 -> 434 [label=true]; 429 -> 2993 [label=false]; 2994 -> 2995; 434 -> 439 [label=true]; 434 -> 2992 [label=false]; 2993 -> 2994; 439 -> 444 [label=true]; 439 -> 2991 [label=false]; 2992 -> 2993; 444 -> 449 [label=true]; 444 -> 2990 [label=false]; 2991 -> 2992; 449 -> 454 [label=true]; 449 -> 2989 [label=false]; 2990 -> 2991; 454 -> 459 [label=true]; 454 -> 2988 [label=false]; 2989 -> 2990; 459 -> 464 [label=true]; 459 -> 2987 [label=false]; 2988 -> 2989; 464 -> 469 [label=true]; 464 -> 2986 [label=false]; 2987 -> 2988; 469 -> 474 [label=true]; 469 -> 2985 [label=false]; 2986 -> 2987; 474 -> 479 [label=true]; 474 -> 2984 [label=false]; 2985 -> 2986; 479 -> 484 [label=true]; 479 -> 2983 [label=false]; 2984 -> 2985; 484 -> 489 [label=true]; 484 -> 2982 [label=false]; 2983 -> 2984; 489 -> 494 [label=true]; 489 -> 2981 [label=false]; 2982 -> 2983; 494 -> 499 [label=true]; 494 -> 2980 [label=false]; 2981 -> 2982; 499 -> 504 [label=true]; 499 -> 2979 [label=false]; 2980 -> 2981; 504 -> 509 [label=true]; 504 -> 2978 [label=false]; 2979 -> 2980; 509 -> 514 [label=true]; 509 -> 2977 [label=false]; 2978 -> 2979; 514 -> 519 [label=true]; 514 -> 2976 [label=false]; 2977 -> 2978; 519 -> 524 [label=true]; 519 -> 2975 [label=false]; 2976 -> 2977; 524 -> 529 [label=true]; 524 -> 2974 [label=false]; 2975 -> 2976; 529 -> 534 [label=true]; 529 -> 2973 [label=false]; 2974 -> 2975; 534 -> 539 [label=true]; 534 -> 2972 [label=false]; 2973 -> 2974; 539 -> 544 [label=true]; 539 -> 2971 [label=false]; 2972 -> 2973; 544 -> 549 [label=true]; 544 -> 2970 [label=false]; 2971 -> 2972; 549 -> 554 [label=true]; 549 -> 2969 [label=false]; 2970 -> 2971; 554 -> 559 [label=true]; 554 -> 2968 [label=false]; 2969 -> 2970; 559 -> 564 [label=true]; 559 -> 2967 [label=false]; 2968 -> 2969; 564 -> 569 [label=true]; 564 -> 2966 [label=false]; 2967 -> 2968; 569 -> 574 [label=true]; 569 -> 2965 [label=false]; 2966 -> 2967; 574 -> 579 [label=true]; 574 -> 2964 [label=false]; 2965 -> 2966; 579 -> 584 [label=true]; 579 -> 2963 [label=false]; 2964 -> 2965; 584 -> 589 [label=true]; 584 -> 2962 [label=false]; 2963 -> 2964; 589 -> 594 [label=true]; 589 -> 2961 [label=false]; 2962 -> 2963; 594 -> 599 [label=true]; 594 -> 2960 [label=false]; 2961 -> 2962; 599 -> 604 [label=true]; 599 -> 2959 [label=false]; 2960 -> 2961; 604 -> 609 [label=true]; 604 -> 2958 [label=false]; 2959 -> 2960; 609 -> 614 [label=true]; 609 -> 2957 [label=false]; 2958 -> 2959; 614 -> 619 [label=true]; 614 -> 2956 [label=false]; 2957 -> 2958; 619 -> 624 [label=true]; 619 -> 2955 [label=false]; 2956 -> 2957; 624 -> 629 [label=true]; 624 -> 2954 [label=false]; 2955 -> 2956; 629 -> 634 [label=true]; 629 -> 2953 [label=false]; 2954 -> 2955; 634 -> 639 [label=true]; 634 -> 2952 [label=false]; 2953 -> 2954; 639 -> 644 [label=true]; 639 -> 2951 [label=false]; 2952 -> 2953; 644 -> 649 [label=true]; 644 -> 2950 [label=false]; 2951 -> 2952; 649 -> 654 [label=true]; 649 -> 2949 [label=false]; 2950 -> 2951; 654 -> 659 [label=true]; 654 -> 2948 [label=false]; 2949 -> 2950; 659 -> 664 [label=true]; 659 -> 2947 [label=false]; 2948 -> 2949; 664 -> 669 [label=true]; 664 -> 2946 [label=false]; 2947 -> 2948; 669 -> 674 [label=true]; 669 -> 2945 [label=false]; 2946 -> 2947; 674 -> 679 [label=true]; 674 -> 2944 [label=false]; 2945 -> 2946; 679 -> 684 [label=true]; 679 -> 2943 [label=false]; 2944 -> 2945; 684 -> 689 [label=true]; 684 -> 2942 [label=false]; 2943 -> 2944; 689 -> 694 [label=true]; 689 -> 2941 [label=false]; 2942 -> 2943; 694 -> 699 [label=true]; 694 -> 2940 [label=false]; 2941 -> 2942; 699 -> 704 [label=true]; 699 -> 2939 [label=false]; 2940 -> 2941; 704 -> 709 [label=true]; 704 -> 2938 [label=false]; 2939 -> 2940; 709 -> 714 [label=true]; 709 -> 2937 [label=false]; 2938 -> 2939; 714 -> 719 [label=true]; 714 -> 2936 [label=false]; 2937 -> 2938; 719 -> 724 [label=true]; 719 -> 2935 [label=false]; 2936 -> 2937; 724 -> 729 [label=true]; 724 -> 2934 [label=false]; 2935 -> 2936; 729 -> 734 [label=true]; 729 -> 2933 [label=false]; 2934 -> 2935; 734 -> 739 [label=true]; 734 -> 2932 [label=false]; 2933 -> 2934; 739 -> 744 [label=true]; 739 -> 2931 [label=false]; 2932 -> 2933; 744 -> 749 [label=true]; 744 -> 2930 [label=false]; 2931 -> 2932; 749 -> 754 [label=true]; 749 -> 2929 [label=false]; 2930 -> 2931; 754 -> 759 [label=true]; 754 -> 2928 [label=false]; 2929 -> 2930; 759 -> 764 [label=true]; 759 -> 2927 [label=false]; 2928 -> 2929; 764 -> 769 [label=true]; 764 -> 2926 [label=false]; 2927 -> 2928; 769 -> 774 [label=true]; 769 -> 2925 [label=false]; 2926 -> 2927; 774 -> 779 [label=true]; 774 -> 2924 [label=false]; 2925 -> 2926; 779 -> 784 [label=true]; 779 -> 2923 [label=false]; 2924 -> 2925; 784 -> 789 [label=true]; 784 -> 2922 [label=false]; 2923 -> 2924; 789 -> 794 [label=true]; 789 -> 2921 [label=false]; 2922 -> 2923; 794 -> 799 [label=true]; 794 -> 2920 [label=false]; 2921 -> 2922; 799 -> 804 [label=true]; 799 -> 2919 [label=false]; 2920 -> 2921; 804 -> 809 [label=true]; 804 -> 2918 [label=false]; 2919 -> 2920; 809 -> 814 [label=true]; 809 -> 2917 [label=false]; 2918 -> 2919; 814 -> 819 [label=true]; 814 -> 2916 [label=false]; 2917 -> 2918; 819 -> 824 [label=true]; 819 -> 2915 [label=false]; 2916 -> 2917; 824 -> 829 [label=true]; 824 -> 2914 [label=false]; 2915 -> 2916; 829 -> 834 [label=true]; 829 -> 2913 [label=false]; 2914 -> 2915; 834 -> 839 [label=true]; 834 -> 2912 [label=false]; 2913 -> 2914; 839 -> 844 [label=true]; 839 -> 2911 [label=false]; 2912 -> 2913; 844 -> 849 [label=true]; 844 -> 2910 [label=false]; 2911 -> 2912; 849 -> 854 [label=true]; 849 -> 2909 [label=false]; 2910 -> 2911; 854 -> 859 [label=true]; 854 -> 2908 [label=false]; 2909 -> 2910; 859 -> 864 [label=true]; 859 -> 2907 [label=false]; 2908 -> 2909; 864 -> 869 [label=true]; 864 -> 2906 [label=false]; 2907 -> 2908; 869 -> 874 [label=true]; 869 -> 2905 [label=false]; 2906 -> 2907; 874 -> 879 [label=true]; 874 -> 2904 [label=false]; 2905 -> 2906; 879 -> 884 [label=true]; 879 -> 2903 [label=false]; 2904 -> 2905; 884 -> 889 [label=true]; 884 -> 2902 [label=false]; 2903 -> 2904; 889 -> 894 [label=true]; 889 -> 2901 [label=false]; 2902 -> 2903; 894 -> 899 [label=true]; 894 -> 2900 [label=false]; 2901 -> 2902; 899 -> 904 [label=true]; 899 -> 2899 [label=false]; 2900 -> 2901; 904 -> 909 [label=true]; 904 -> 2898 [label=false]; 2899 -> 2900; 909 -> 914 [label=true]; 909 -> 2897 [label=false]; 2898 -> 2899; 914 -> 919 [label=true]; 914 -> 2896 [label=false]; 2897 -> 2898; 919 -> 924 [label=true]; 919 -> 2895 [label=false]; 2896 -> 2897; 924 -> 929 [label=true]; 924 -> 2894 [label=false]; 2895 -> 2896; 929 -> 934 [label=true]; 929 -> 2893 [label=false]; 2894 -> 2895; 934 -> 939 [label=true]; 934 -> 2892 [label=false]; 2893 -> 2894; 939 -> 944 [label=true]; 939 -> 2891 [label=false]; 2892 -> 2893; 944 -> 949 [label=true]; 944 -> 2890 [label=false]; 2891 -> 2892; 949 -> 954 [label=true]; 949 -> 2889 [label=false]; 2890 -> 2891; 954 -> 959 [label=true]; 954 -> 2888 [label=false]; 2889 -> 2890; 959 -> 964 [label=true]; 959 -> 2887 [label=false]; 2888 -> 2889; 964 -> 969 [label=true]; 964 -> 2886 [label=false]; 2887 -> 2888; 969 -> 974 [label=true]; 969 -> 2885 [label=false]; 2886 -> 2887; 974 -> 979 [label=true]; 974 -> 2884 [label=false]; 2885 -> 2886; 979 -> 984 [label=true]; 979 -> 2883 [label=false]; 2884 -> 2885; 984 -> 989 [label=true]; 984 -> 2882 [label=false]; 2883 -> 2884; 989 -> 994 [label=true]; 989 -> 2881 [label=false]; 2882 -> 2883; 994 -> 999 [label=true]; 994 -> 2880 [label=false]; 2881 -> 2882; 999 -> 1004 [label=true]; 999 -> 2879 [label=false]; 2880 -> 2881; 1004 -> 1009 [label=true]; 1004 -> 2878 [label=false]; 2879 -> 2880; 1009 -> 1014 [label=true]; 1009 -> 2877 [label=false]; 2878 -> 2879; 1014 -> 1019 [label=true]; 1014 -> 2876 [label=false]; 2877 -> 2878; 1019 -> 1024 [label=true]; 1019 -> 2875 [label=false]; 2876 -> 2877; 1024 -> 1029 [label=true]; 1024 -> 2874 [label=false]; 2875 -> 2876; 1029 -> 1034 [label=true]; 1029 -> 2873 [label=false]; 2874 -> 2875; 1034 -> 1039 [label=true]; 1034 -> 2872 [label=false]; 2873 -> 2874; 1039 -> 1044 [label=true]; 1039 -> 2871 [label=false]; 2872 -> 2873; 1044 -> 1049 [label=true]; 1044 -> 2870 [label=false]; 2871 -> 2872; 1049 -> 1054 [label=true]; 1049 -> 2869 [label=false]; 2870 -> 2871; 1054 -> 1059 [label=true]; 1054 -> 2868 [label=false]; 2869 -> 2870; 1059 -> 1064 [label=true]; 1059 -> 2867 [label=false]; 2868 -> 2869; 1064 -> 1069 [label=true]; 1064 -> 2866 [label=false]; 2867 -> 2868; 1069 -> 1074 [label=true]; 1069 -> 2865 [label=false]; 2866 -> 2867; 1074 -> 1079 [label=true]; 1074 -> 2864 [label=false]; 2865 -> 2866; 1079 -> 1084 [label=true]; 1079 -> 2863 [label=false]; 2864 -> 2865; 1084 -> 1089 [label=true]; 1084 -> 2862 [label=false]; 2863 -> 2864; 1089 -> 1094 [label=true]; 1089 -> 2861 [label=false]; 2862 -> 2863; 1094 -> 1099 [label=true]; 1094 -> 2860 [label=false]; 2861 -> 2862; 1099 -> 1104 [label=true]; 1099 -> 2859 [label=false]; 2860 -> 2861; 1104 -> 1109 [label=true]; 1104 -> 2858 [label=false]; 2859 -> 2860; 1109 -> 1114 [label=true]; 1109 -> 2857 [label=false]; 2858 -> 2859; 1114 -> 1119 [label=true]; 1114 -> 2856 [label=false]; 2857 -> 2858; 1119 -> 1124 [label=true]; 1119 -> 2855 [label=false]; 2856 -> 2857; 1124 -> 1129 [label=true]; 1124 -> 2854 [label=false]; 2855 -> 2856; 1129 -> 1134 [label=true]; 1129 -> 2853 [label=false]; 2854 -> 2855; 1134 -> 1139 [label=true]; 1134 -> 2852 [label=false]; 2853 -> 2854; 1139 -> 1144 [label=true]; 1139 -> 2851 [label=false]; 2852 -> 2853; 1144 -> 1149 [label=true]; 1144 -> 2850 [label=false]; 2851 -> 2852; 1149 -> 1154 [label=true]; 1149 -> 2849 [label=false]; 2850 -> 2851; 1154 -> 1159 [label=true]; 1154 -> 2848 [label=false]; 2849 -> 2850; 1159 -> 1164 [label=true]; 1159 -> 2847 [label=false]; 2848 -> 2849; 1164 -> 1169 [label=true]; 1164 -> 2846 [label=false]; 2847 -> 2848; 1169 -> 1174 [label=true]; 1169 -> 2845 [label=false]; 2846 -> 2847; 1174 -> 1179 [label=true]; 1174 -> 2844 [label=false]; 2845 -> 2846; 1179 -> 1184 [label=true]; 1179 -> 2843 [label=false]; 2844 -> 2845; 1184 -> 1189 [label=true]; 1184 -> 2842 [label=false]; 2843 -> 2844; 1189 -> 1194 [label=true]; 1189 -> 2841 [label=false]; 2842 -> 2843; 1194 -> 1199 [label=true]; 1194 -> 2840 [label=false]; 2841 -> 2842; 1199 -> 1204 [label=true]; 1199 -> 2839 [label=false]; 2840 -> 2841; 1204 -> 1209 [label=true]; 1204 -> 2838 [label=false]; 2839 -> 2840; 1209 -> 1214 [label=true]; 1209 -> 2837 [label=false]; 2838 -> 2839; 1214 -> 1219 [label=true]; 1214 -> 2836 [label=false]; 2837 -> 2838; 1219 -> 1224 [label=true]; 1219 -> 2835 [label=false]; 2836 -> 2837; 1224 -> 1229 [label=true]; 1224 -> 2834 [label=false]; 2835 -> 2836; 1229 -> 1234 [label=true]; 1229 -> 2833 [label=false]; 2834 -> 2835; 1234 -> 1239 [label=true]; 1234 -> 2832 [label=false]; 2833 -> 2834; 1239 -> 1244 [label=true]; 1239 -> 2831 [label=false]; 2832 -> 2833; 1244 -> 1249 [label=true]; 1244 -> 2830 [label=false]; 2831 -> 2832; 1249 -> 1254 [label=true]; 1249 -> 2829 [label=false]; 2830 -> 2831; 1254 -> 1259 [label=true]; 1254 -> 2828 [label=false]; 2829 -> 2830; 1259 -> 1264 [label=true]; 1259 -> 2827 [label=false]; 2828 -> 2829; 1264 -> 1269 [label=true]; 1264 -> 2826 [label=false]; 2827 -> 2828; 1269 -> 1274 [label=true]; 1269 -> 2825 [label=false]; 2826 -> 2827; 1274 -> 1279 [label=true]; 1274 -> 2824 [label=false]; 2825 -> 2826; 1279 -> 1284 [label=true]; 1279 -> 2823 [label=false]; 2824 -> 2825; 1284 -> 1289 [label=true]; 1284 -> 2822 [label=false]; 2823 -> 2824; 1289 -> 1294 [label=true]; 1289 -> 2821 [label=false]; 2822 -> 2823; 1294 -> 1299 [label=true]; 1294 -> 2820 [label=false]; 2821 -> 2822; 1299 -> 1304 [label=true]; 1299 -> 2819 [label=false]; 2820 -> 2821; 1304 -> 1309 [label=true]; 1304 -> 2818 [label=false]; 2819 -> 2820; 1309 -> 1314 [label=true]; 1309 -> 2817 [label=false]; 2818 -> 2819; 1314 -> 1319 [label=true]; 1314 -> 2816 [label=false]; 2817 -> 2818; 1319 -> 1324 [label=true]; 1319 -> 2815 [label=false]; 2816 -> 2817; 1324 -> 1329 [label=true]; 1324 -> 2814 [label=false]; 2815 -> 2816; 1329 -> 1334 [label=true]; 1329 -> 2813 [label=false]; 2814 -> 2815; 1334 -> 1339 [label=true]; 1334 -> 2812 [label=false]; 2813 -> 2814; 1339 -> 1344 [label=true]; 1339 -> 2811 [label=false]; 2812 -> 2813; 1344 -> 1349 [label=true]; 1344 -> 2810 [label=false]; 2811 -> 2812; 1349 -> 1354 [label=true]; 1349 -> 2809 [label=false]; 2810 -> 2811; 1354 -> 1359 [label=true]; 1354 -> 2808 [label=false]; 2809 -> 2810; 1359 -> 1364 [label=true]; 1359 -> 2807 [label=false]; 2808 -> 2809; 1364 -> 1369 [label=true]; 1364 -> 2806 [label=false]; 2807 -> 2808; 1369 -> 1374 [label=true]; 1369 -> 2805 [label=false]; 2806 -> 2807; 1374 -> 1379 [label=true]; 1374 -> 2804 [label=false]; 2805 -> 2806; 1379 -> 1384 [label=true]; 1379 -> 2803 [label=false]; 2804 -> 2805; 1384 -> 1389 [label=true]; 1384 -> 2802 [label=false]; 2803 -> 2804; 1389 -> 1394 [label=true]; 1389 -> 2801 [label=false]; 2802 -> 2803; 1394 -> 1399 [label=true]; 1394 -> 2800 [label=false]; 2801 -> 2802; 1399 -> 1404 [label=true]; 1399 -> 2799 [label=false]; 2800 -> 2801; 1404 -> 1409 [label=true]; 1404 -> 2798 [label=false]; 2799 -> 2800; 1409 -> 1414 [label=true]; 1409 -> 2797 [label=false]; 2798 -> 2799; 1414 -> 1419 [label=true]; 1414 -> 2796 [label=false]; 2797 -> 2798; 1419 -> 1424 [label=true]; 1419 -> 2795 [label=false]; 2796 -> 2797; 1424 -> 1429 [label=true]; 1424 -> 2794 [label=false]; 2795 -> 2796; 1429 -> 1434 [label=true]; 1429 -> 2793 [label=false]; 2794 -> 2795; 1434 -> 1439 [label=true]; 1434 -> 2792 [label=false]; 2793 -> 2794; 1439 -> 1444 [label=true]; 1439 -> 2791 [label=false]; 2792 -> 2793; 1444 -> 1449 [label=true]; 1444 -> 2790 [label=false]; 2791 -> 2792; 1449 -> 1454 [label=true]; 1449 -> 2789 [label=false]; 2790 -> 2791; 1454 -> 1459 [label=true]; 1454 -> 2788 [label=false]; 2789 -> 2790; 1459 -> 1464 [label=true]; 1459 -> 2787 [label=false]; 2788 -> 2789; 1464 -> 1469 [label=true]; 1464 -> 2786 [label=false]; 2787 -> 2788; 1469 -> 1474 [label=true]; 1469 -> 2785 [label=false]; 2786 -> 2787; 1474 -> 1479 [label=true]; 1474 -> 2784 [label=false]; 2785 -> 2786; 1479 -> 1484 [label=true]; 1479 -> 2783 [label=false]; 2784 -> 2785; 1484 -> 1489 [label=true]; 1484 -> 2782 [label=false]; 2783 -> 2784; 1489 -> 1494 [label=true]; 1489 -> 2781 [label=false]; 2782 -> 2783; 1494 -> 1499 [label=true]; 1494 -> 2780 [label=false]; 2781 -> 2782; 1499 -> 1504 [label=true]; 1499 -> 2779 [label=false]; 2780 -> 2781; 1504 -> 1509 [label=true]; 1504 -> 2778 [label=false]; 2779 -> 2780; 1509 -> 1514 [label=true]; 1509 -> 2777 [label=false]; 2778 -> 2779; 1514 -> 1519 [label=true]; 1514 -> 2776 [label=false]; 2777 -> 2778; 1519 -> 1524 [label=true]; 1519 -> 2775 [label=false]; 2776 -> 2777; 1524 -> 1529 [label=true]; 1524 -> 2774 [label=false]; 2775 -> 2776; 1529 -> 1534 [label=true]; 1529 -> 2773 [label=false]; 2774 -> 2775; 1534 -> 1539 [label=true]; 1534 -> 2772 [label=false]; 2773 -> 2774; 1539 -> 1544 [label=true]; 1539 -> 2771 [label=false]; 2772 -> 2773; 1544 -> 1549 [label=true]; 1544 -> 2770 [label=false]; 2771 -> 2772; 1549 -> 1554 [label=true]; 1549 -> 2769 [label=false]; 2770 -> 2771; 1554 -> 1559 [label=true]; 1554 -> 2768 [label=false]; 2769 -> 2770; 1559 -> 1564 [label=true]; 1559 -> 2767 [label=false]; 2768 -> 2769; 1564 -> 1569 [label=true]; 1564 -> 2766 [label=false]; 2767 -> 2768; 1569 -> 1574 [label=true]; 1569 -> 2765 [label=false]; 2766 -> 2767; 1574 -> 1579 [label=true]; 1574 -> 2764 [label=false]; 2765 -> 2766; 1579 -> 1584 [label=true]; 1579 -> 2763 [label=false]; 2764 -> 2765; 1584 -> 1589 [label=true]; 1584 -> 2762 [label=false]; 2763 -> 2764; 1589 -> 1594 [label=true]; 1589 -> 2761 [label=false]; 2762 -> 2763; 1594 -> 1599 [label=true]; 1594 -> 2760 [label=false]; 2761 -> 2762; 1599 -> 1604 [label=true]; 1599 -> 2759 [label=false]; 2760 -> 2761; 1604 -> 1609 [label=true]; 1604 -> 2758 [label=false]; 2759 -> 2760; 1609 -> 1614 [label=true]; 1609 -> 2757 [label=false]; 2758 -> 2759; 1614 -> 1619 [label=true]; 1614 -> 2756 [label=false]; 2757 -> 2758; 1619 -> 1624 [label=true]; 1619 -> 2755 [label=false]; 2756 -> 2757; 1624 -> 1629 [label=true]; 1624 -> 2754 [label=false]; 2755 -> 2756; 1629 -> 1634 [label=true]; 1629 -> 2753 [label=false]; 2754 -> 2755; 1634 -> 1639 [label=true]; 1634 -> 2752 [label=false]; 2753 -> 2754; 1639 -> 1644 [label=true]; 1639 -> 2751 [label=false]; 2752 -> 2753; 1644 -> 1649 [label=true]; 1644 -> 2750 [label=false]; 2751 -> 2752; 1649 -> 1654 [label=true]; 1649 -> 2749 [label=false]; 2750 -> 2751; 1654 -> 1659 [label=true]; 1654 -> 2748 [label=false]; 2749 -> 2750; 1659 -> 1664 [label=true]; 1659 -> 2747 [label=false]; 2748 -> 2749; 1664 -> 1669 [label=true]; 1664 -> 2746 [label=false]; 2747 -> 2748; 1669 -> 1674 [label=true]; 1669 -> 2745 [label=false]; 2746 -> 2747; 1674 -> 1679 [label=true]; 1674 -> 2744 [label=false]; 2745 -> 2746; 1679 -> 1684 [label=true]; 1679 -> 2743 [label=false]; 2744 -> 2745; 1684 -> 1689 [label=true]; 1684 -> 2742 [label=false]; 2743 -> 2744; 1689 -> 1694 [label=true]; 1689 -> 2741 [label=false]; 2742 -> 2743; 1694 -> 1699 [label=true]; 1694 -> 2740 [label=false]; 2741 -> 2742; 1699 -> 1704 [label=true]; 1699 -> 2739 [label=false]; 2740 -> 2741; 1704 -> 1709 [label=true]; 1704 -> 2738 [label=false]; 2739 -> 2740; 1709 -> 1714 [label=true]; 1709 -> 2737 [label=false]; 2738 -> 2739; 1714 -> 1719 [label=true]; 1714 -> 2736 [label=false]; 2737 -> 2738; 1719 -> 1724 [label=true]; 1719 -> 2735 [label=false]; 2736 -> 2737; 1724 -> 1729 [label=true]; 1724 -> 2734 [label=false]; 2735 -> 2736; 1729 -> 1734 [label=true]; 1729 -> 2733 [label=false]; 2734 -> 2735; 1734 -> 1739 [label=true]; 1734 -> 2732 [label=false]; 2733 -> 2734; 1739 -> 1744 [label=true]; 1739 -> 2731 [label=false]; 2732 -> 2733; 1744 -> 1749 [label=true]; 1744 -> 2730 [label=false]; 2731 -> 2732; 1749 -> 1754 [label=true]; 1749 -> 2729 [label=false]; 2730 -> 2731; 1754 -> 1759 [label=true]; 1754 -> 2728 [label=false]; 2729 -> 2730; 1759 -> 1764 [label=true]; 1759 -> 2727 [label=false]; 2728 -> 2729; 1764 -> 1769 [label=true]; 1764 -> 2726 [label=false]; 2727 -> 2728; 1769 -> 1774 [label=true]; 1769 -> 2725 [label=false]; 2726 -> 2727; 1774 -> 1779 [label=true]; 1774 -> 2724 [label=false]; 2725 -> 2726; 1779 -> 1784 [label=true]; 1779 -> 2723 [label=false]; 2724 -> 2725; 1784 -> 1789 [label=true]; 1784 -> 2722 [label=false]; 2723 -> 2724; 1789 -> 1794 [label=true]; 1789 -> 2721 [label=false]; 2722 -> 2723; 1794 -> 1799 [label=true]; 1794 -> 2720 [label=false]; 2721 -> 2722; 1799 -> 1804 [label=true]; 1799 -> 2719 [label=false]; 2720 -> 2721; 1804 -> 1809 [label=true]; 1804 -> 2718 [label=false]; 2719 -> 2720; 1809 -> 1814 [label=true]; 1809 -> 2717 [label=false]; 2718 -> 2719; 1814 -> 1819 [label=true]; 1814 -> 2716 [label=false]; 2717 -> 2718; 1819 -> 1824 [label=true]; 1819 -> 2715 [label=false]; 2716 -> 2717; 1824 -> 1829 [label=true]; 1824 -> 2714 [label=false]; 2715 -> 2716; 1829 -> 1834 [label=true]; 1829 -> 2713 [label=false]; 2714 -> 2715; 1834 -> 1839 [label=true]; 1834 -> 2712 [label=false]; 2713 -> 2714; 1839 -> 1844 [label=true]; 1839 -> 2711 [label=false]; 2712 -> 2713; 1844 -> 1849 [label=true]; 1844 -> 2710 [label=false]; 2711 -> 2712; 1849 -> 1854 [label=true]; 1849 -> 2709 [label=false]; 2710 -> 2711; 1854 -> 1859 [label=true]; 1854 -> 2708 [label=false]; 2709 -> 2710; 1859 -> 1864 [label=true]; 1859 -> 2707 [label=false]; 2708 -> 2709; 1864 -> 1869 [label=true]; 1864 -> 2706 [label=false]; 2707 -> 2708; 1869 -> 1874 [label=true]; 1869 -> 2705 [label=false]; 2706 -> 2707; 1874 -> 1879 [label=true]; 1874 -> 2704 [label=false]; 2705 -> 2706; 1879 -> 1884 [label=true]; 1879 -> 2703 [label=false]; 2704 -> 2705; 1884 -> 1889 [label=true]; 1884 -> 2702 [label=false]; 2703 -> 2704; 1889 -> 1894 [label=true]; 1889 -> 2701 [label=false]; 2702 -> 2703; 1894 -> 1899 [label=true]; 1894 -> 2700 [label=false]; 2701 -> 2702; 1899 -> 1904 [label=true]; 1899 -> 2699 [label=false]; 2700 -> 2701; 1904 -> 1909 [label=true]; 1904 -> 2698 [label=false]; 2699 -> 2700; 1909 -> 1914 [label=true]; 1909 -> 2697 [label=false]; 2698 -> 2699; 1914 -> 1919 [label=true]; 1914 -> 2696 [label=false]; 2697 -> 2698; 1919 -> 1924 [label=true]; 1919 -> 2695 [label=false]; 2696 -> 2697; 1924 -> 1929 [label=true]; 1924 -> 2694 [label=false]; 2695 -> 2696; 1929 -> 1934 [label=true]; 1929 -> 2693 [label=false]; 2694 -> 2695; 1934 -> 1939 [label=true]; 1934 -> 2692 [label=false]; 2693 -> 2694; 1939 -> 1944 [label=true]; 1939 -> 2691 [label=false]; 2692 -> 2693; 1944 -> 1949 [label=true]; 1944 -> 2690 [label=false]; 2691 -> 2692; 1949 -> 1954 [label=true]; 1949 -> 2689 [label=false]; 2690 -> 2691; 1954 -> 1959 [label=true]; 1954 -> 2688 [label=false]; 2689 -> 2690; 1959 -> 1964 [label=true]; 1959 -> 2687 [label=false]; 2688 -> 2689; 1964 -> 1969 [label=true]; 1964 -> 2686 [label=false]; 2687 -> 2688; 1969 -> 1974 [label=true]; 1969 -> 2685 [label=false]; 2686 -> 2687; 1974 -> 1979 [label=true]; 1974 -> 2684 [label=false]; 2685 -> 2686; 1979 -> 1984 [label=true]; 1979 -> 2683 [label=false]; 2684 -> 2685; 1984 -> 1989 [label=true]; 1984 -> 2682 [label=false]; 2683 -> 2684; 1989 -> 1994 [label=true]; 1989 -> 2681 [label=false]; 2682 -> 2683; 1994 -> 1999 [label=true]; 1994 -> 2680 [label=false]; 2681 -> 2682; 1999 -> 2004 [label=true]; 1999 -> 2679 [label=false]; 2680 -> 2681; 2004 -> 2009 [label=true]; 2004 -> 2678 [label=false]; 2679 -> 2680; 2009 -> 2014 [label=true]; 2009 -> 2677 [label=false]; 2678 -> 2679; 2014 -> 2019 [label=true]; 2014 -> 2676 [label=false]; 2677 -> 2678; 2019 -> 2024 [label=true]; 2019 -> 2675 [label=false]; 2676 -> 2677; 2024 -> 2029 [label=true]; 2024 -> 2674 [label=false]; 2675 -> 2676; 2029 -> 2034 [label=true]; 2029 -> 2673 [label=false]; 2674 -> 2675; 2034 -> 2039 [label=true]; 2034 -> 2672 [label=false]; 2673 -> 2674; 2039 -> 2044 [label=true]; 2039 -> 2671 [label=false]; 2672 -> 2673; 2044 -> 2049 [label=true]; 2044 -> 2670 [label=false]; 2671 -> 2672; 2049 -> 2054 [label=true]; 2049 -> 2669 [label=false]; 2670 -> 2671; 2054 -> 2059 [label=true]; 2054 -> 2668 [label=false]; 2669 -> 2670; 2059 -> 2064 [label=true]; 2059 -> 2667 [label=false]; 2668 -> 2669; 2064 -> 2069 [label=true]; 2064 -> 2666 [label=false]; 2667 -> 2668; 2069 -> 2074 [label=true]; 2069 -> 2665 [label=false]; 2666 -> 2667; 2074 -> 2079 [label=true]; 2074 -> 2664 [label=false]; 2665 -> 2666; 2079 -> 2084 [label=true]; 2079 -> 2663 [label=false]; 2664 -> 2665; 2084 -> 2089 [label=true]; 2084 -> 2662 [label=false]; 2663 -> 2664; 2089 -> 2094 [label=true]; 2089 -> 2661 [label=false]; 2662 -> 2663; 2094 -> 2099 [label=true]; 2094 -> 2660 [label=false]; 2661 -> 2662; 2099 -> 2104 [label=true]; 2099 -> 2659 [label=false]; 2660 -> 2661; 2104 -> 2109 [label=true]; 2104 -> 2658 [label=false]; 2659 -> 2660; 2109 -> 2114 [label=true]; 2109 -> 2657 [label=false]; 2658 -> 2659; 2114 -> 2119 [label=true]; 2114 -> 2656 [label=false]; 2657 -> 2658; 2119 -> 2124 [label=true]; 2119 -> 2655 [label=false]; 2656 -> 2657; 2124 -> 2129 [label=true]; 2124 -> 2654 [label=false]; 2655 -> 2656; 2129 -> 2134 [label=true]; 2129 -> 2653 [label=false]; 2654 -> 2655; 2134 -> 2139 [label=true]; 2134 -> 2652 [label=false]; 2653 -> 2654; 2139 -> 2144 [label=true]; 2139 -> 2651 [label=false]; 2652 -> 2653; 2144 -> 2149 [label=true]; 2144 -> 2650 [label=false]; 2651 -> 2652; 2149 -> 2154 [label=true]; 2149 -> 2649 [label=false]; 2650 -> 2651; 2154 -> 2159 [label=true]; 2154 -> 2648 [label=false]; 2649 -> 2650; 2159 -> 2164 [label=true]; 2159 -> 2647 [label=false]; 2648 -> 2649; 2164 -> 2169 [label=true]; 2164 -> 2646 [label=false]; 2647 -> 2648; 2169 -> 2174 [label=true]; 2169 -> 2645 [label=false]; 2646 -> 2647; 2174 -> 2179 [label=true]; 2174 -> 2644 [label=false]; 2645 -> 2646; 2179 -> 2184 [label=true]; 2179 -> 2643 [label=false]; 2644 -> 2645; 2184 -> 2189 [label=true]; 2184 -> 2642 [label=false]; 2643 -> 2644; 2189 -> 2194 [label=true]; 2189 -> 2641 [label=false]; 2642 -> 2643; 2194 -> 2199 [label=true]; 2194 -> 2640 [label=false]; 2641 -> 2642; 2199 -> 2204 [label=true]; 2199 -> 2639 [label=false]; 2640 -> 2641; 2204 -> 2209 [label=true]; 2204 -> 2638 [label=false]; 2639 -> 2640; 2209 -> 2214 [label=true]; 2209 -> 2637 [label=false]; 2638 -> 2639; 2214 -> 2219 [label=true]; 2214 -> 2636 [label=false]; 2637 -> 2638; 2219 -> 2224 [label=true]; 2219 -> 2635 [label=false]; 2636 -> 2637; 2224 -> 2229 [label=true]; 2224 -> 2634 [label=false]; 2635 -> 2636; 2229 -> 2234 [label=true]; 2229 -> 2633 [label=false]; 2634 -> 2635; 2234 -> 2239 [label=true]; 2234 -> 2632 [label=false]; 2633 -> 2634; 2239 -> 2244 [label=true]; 2239 -> 2631 [label=false]; 2632 -> 2633; 2244 -> 2249 [label=true]; 2244 -> 2630 [label=false]; 2631 -> 2632; 2249 -> 2254 [label=true]; 2249 -> 2629 [label=false]; 2630 -> 2631; 2254 -> 2259 [label=true]; 2254 -> 2628 [label=false]; 2629 -> 2630; 2259 -> 2264 [label=true]; 2259 -> 2627 [label=false]; 2628 -> 2629; 2264 -> 2269 [label=true]; 2264 -> 2626 [label=false]; 2627 -> 2628; 2269 -> 2274 [label=true]; 2269 -> 2625 [label=false]; 2626 -> 2627; 2274 -> 2279 [label=true]; 2274 -> 2624 [label=false]; 2625 -> 2626; 2279 -> 2284 [label=true]; 2279 -> 2623 [label=false]; 2624 -> 2625; 2284 -> 2289 [label=true]; 2284 -> 2622 [label=false]; 2623 -> 2624; 2289 -> 2294 [label=true]; 2289 -> 2621 [label=false]; 2622 -> 2623; 2294 -> 2299 [label=true]; 2294 -> 2620 [label=false]; 2621 -> 2622; 2299 -> 2304 [label=true]; 2299 -> 2619 [label=false]; 2620 -> 2621; 2304 -> 2309 [label=true]; 2304 -> 2618 [label=false]; 2619 -> 2620; 2309 -> 2314 [label=true]; 2309 -> 2617 [label=false]; 2618 -> 2619; 2314 -> 2319 [label=true]; 2314 -> 2616 [label=false]; 2617 -> 2618; 2319 -> 2324 [label=true]; 2319 -> 2615 [label=false]; 2616 -> 2617; 2324 -> 2329 [label=true]; 2324 -> 2614 [label=false]; 2615 -> 2616; 2329 -> 2334 [label=true]; 2329 -> 2613 [label=false]; 2614 -> 2615; 2334 -> 2339 [label=true]; 2334 -> 2612 [label=false]; 2613 -> 2614; 2339 -> 2344 [label=true]; 2339 -> 2611 [label=false]; 2612 -> 2613; 2344 -> 2349 [label=true]; 2344 -> 2610 [label=false]; 2611 -> 2612; 2349 -> 2354 [label=true]; 2349 -> 2609 [label=false]; 2610 -> 2611; 2354 -> 2359 [label=true]; 2354 -> 2608 [label=false]; 2609 -> 2610; 2359 -> 2364 [label=true]; 2359 -> 2607 [label=false]; 2608 -> 2609; 2364 -> 2369 [label=true]; 2364 -> 2606 [label=false]; 2607 -> 2608; 2369 -> 2374 [label=true]; 2369 -> 2605 [label=false]; 2606 -> 2607; 2374 -> 2379 [label=true]; 2374 -> 2604 [label=false]; 2605 -> 2606; 2379 -> 2384 [label=true]; 2379 -> 2603 [label=false]; 2604 -> 2605; 2384 -> 2389 [label=true]; 2384 -> 2602 [label=false]; 2603 -> 2604; 2389 -> 2394 [label=true]; 2389 -> 2601 [label=false]; 2602 -> 2603; 2394 -> 2399 [label=true]; 2394 -> 2600 [label=false]; 2601 -> 2602; 2399 -> 2404 [label=true]; 2399 -> 2599 [label=false]; 2600 -> 2601; 2404 -> 2409 [label=true]; 2404 -> 2598 [label=false]; 2599 -> 2600; 2409 -> 2414 [label=true]; 2409 -> 2597 [label=false]; 2598 -> 2599; 2414 -> 2419 [label=true]; 2414 -> 2596 [label=false]; 2597 -> 2598; 2419 -> 2424 [label=true]; 2419 -> 2595 [label=false]; 2596 -> 2597; 2424 -> 2429 [label=true]; 2424 -> 2594 [label=false]; 2595 -> 2596; 2429 -> 2434 [label=true]; 2429 -> 2593 [label=false]; 2594 -> 2595; 2434 -> 2439 [label=true]; 2434 -> 2592 [label=false]; 2593 -> 2594; 2439 -> 2444 [label=true]; 2439 -> 2591 [label=false]; 2592 -> 2593; 2444 -> 2449 [label=true]; 2444 -> 2590 [label=false]; 2591 -> 2592; 2449 -> 2454 [label=true]; 2449 -> 2589 [label=false]; 2590 -> 2591; 2454 -> 2459 [label=true]; 2454 -> 2588 [label=false]; 2589 -> 2590; 2459 -> 2464 [label=true]; 2459 -> 2587 [label=false]; 2588 -> 2589; 2464 -> 2469 [label=true]; 2464 -> 2586 [label=false]; 2587 -> 2588; 2469 -> 2474 [label=true]; 2469 -> 2585 [label=false]; 2586 -> 2587; 2474 -> 2479 [label=true]; 2474 -> 2584 [label=false]; 2585 -> 2586; 2479 -> 2484 [label=true]; 2479 -> 2583 [label=false]; 2584 -> 2585; 2484 -> 2489 [label=true]; 2484 -> 2582 [label=false]; 2583 -> 2584; 2489 -> 2494 [label=true]; 2489 -> 2581 [label=false]; 2582 -> 2583; 2494 -> 2499 [label=true]; 2494 -> 2580 [label=false]; 2581 -> 2582; 2499 -> 2504 [label=true]; 2499 -> 2579 [label=false]; 2580 -> 2581; 2504 -> 2509 [label=true]; 2504 -> 2578 [label=false]; 2579 -> 2580; 2509 -> 2514 [label=true]; 2509 -> 2577 [label=false]; 2578 -> 2579; 2514 -> 2519 [label=true]; 2514 -> 2576 [label=false]; 2577 -> 2578; 2519 -> 2524 [label=true]; 2519 -> 2575 [label=false]; 2576 -> 2577; 2524 -> 2529 [label=true]; 2524 -> 2574 [label=false]; 2575 -> 2576; 2529 -> 2534 [label=true]; 2529 -> 2573 [label=false]; 2574 -> 2575; 2534 -> 2539 [label=true]; 2534 -> 2572 [label=false]; 2573 -> 2574; 2539 -> 2544 [label=true]; 2539 -> 2571 [label=false]; 2572 -> 2573; 2544 -> 2549 [label=true]; 2544 -> 2570 [label=false]; 2571 -> 2572; 2549 -> 2554 [label=true]; 2549 -> 2569 [label=false]; 2570 -> 2571; 2554 -> 2559 [label=true]; 2554 -> 2568 [label=false]; 2569 -> 2570; 2559 -> 2564 [label=true]; 2559 -> 2567 [label=false]; 2568 -> 2569; 2564 -> 2567; 2567 -> 2568; }golang-gonum-v1-gonum-0.14.0/graph/path/testdata/flow/nested_if_n64.dot000066400000000000000000000115731450372207100256210ustar00rootroot00000000000000digraph main { // Node definitions. 2 [label=entry]; 9; 390; 14; 389; 19; 388; 24; 387; 29; 386; 34; 385; 39; 384; 44; 383; 49; 382; 54; 381; 59; 380; 64; 379; 69; 378; 74; 377; 79; 376; 84; 375; 89; 374; 94; 373; 99; 372; 104; 371; 109; 370; 114; 369; 119; 368; 124; 367; 129; 366; 134; 365; 139; 364; 144; 363; 149; 362; 154; 361; 159; 360; 164; 359; 169; 358; 174; 357; 179; 356; 184; 355; 189; 354; 194; 353; 199; 352; 204; 351; 209; 350; 214; 349; 219; 348; 224; 347; 229; 346; 234; 345; 239; 344; 244; 343; 249; 342; 254; 341; 259; 340; 264; 339; 269; 338; 274; 337; 279; 336; 284; 335; 289; 334; 294; 333; 299; 332; 304; 331; 309; 330; 314; 329; 319; 328; 324; 327; // Edge definitions. 2 -> 9 [label=true]; 2 -> 390 [label=false]; 9 -> 14 [label=true]; 9 -> 389 [label=false]; 14 -> 19 [label=true]; 14 -> 388 [label=false]; 389 -> 390; 19 -> 24 [label=true]; 19 -> 387 [label=false]; 388 -> 389; 24 -> 29 [label=true]; 24 -> 386 [label=false]; 387 -> 388; 29 -> 34 [label=true]; 29 -> 385 [label=false]; 386 -> 387; 34 -> 39 [label=true]; 34 -> 384 [label=false]; 385 -> 386; 39 -> 44 [label=true]; 39 -> 383 [label=false]; 384 -> 385; 44 -> 49 [label=true]; 44 -> 382 [label=false]; 383 -> 384; 49 -> 54 [label=true]; 49 -> 381 [label=false]; 382 -> 383; 54 -> 59 [label=true]; 54 -> 380 [label=false]; 381 -> 382; 59 -> 64 [label=true]; 59 -> 379 [label=false]; 380 -> 381; 64 -> 69 [label=true]; 64 -> 378 [label=false]; 379 -> 380; 69 -> 74 [label=true]; 69 -> 377 [label=false]; 378 -> 379; 74 -> 79 [label=true]; 74 -> 376 [label=false]; 377 -> 378; 79 -> 84 [label=true]; 79 -> 375 [label=false]; 376 -> 377; 84 -> 89 [label=true]; 84 -> 374 [label=false]; 375 -> 376; 89 -> 94 [label=true]; 89 -> 373 [label=false]; 374 -> 375; 94 -> 99 [label=true]; 94 -> 372 [label=false]; 373 -> 374; 99 -> 104 [label=true]; 99 -> 371 [label=false]; 372 -> 373; 104 -> 109 [label=true]; 104 -> 370 [label=false]; 371 -> 372; 109 -> 114 [label=true]; 109 -> 369 [label=false]; 370 -> 371; 114 -> 119 [label=true]; 114 -> 368 [label=false]; 369 -> 370; 119 -> 124 [label=true]; 119 -> 367 [label=false]; 368 -> 369; 124 -> 129 [label=true]; 124 -> 366 [label=false]; 367 -> 368; 129 -> 134 [label=true]; 129 -> 365 [label=false]; 366 -> 367; 134 -> 139 [label=true]; 134 -> 364 [label=false]; 365 -> 366; 139 -> 144 [label=true]; 139 -> 363 [label=false]; 364 -> 365; 144 -> 149 [label=true]; 144 -> 362 [label=false]; 363 -> 364; 149 -> 154 [label=true]; 149 -> 361 [label=false]; 362 -> 363; 154 -> 159 [label=true]; 154 -> 360 [label=false]; 361 -> 362; 159 -> 164 [label=true]; 159 -> 359 [label=false]; 360 -> 361; 164 -> 169 [label=true]; 164 -> 358 [label=false]; 359 -> 360; 169 -> 174 [label=true]; 169 -> 357 [label=false]; 358 -> 359; 174 -> 179 [label=true]; 174 -> 356 [label=false]; 357 -> 358; 179 -> 184 [label=true]; 179 -> 355 [label=false]; 356 -> 357; 184 -> 189 [label=true]; 184 -> 354 [label=false]; 355 -> 356; 189 -> 194 [label=true]; 189 -> 353 [label=false]; 354 -> 355; 194 -> 199 [label=true]; 194 -> 352 [label=false]; 353 -> 354; 199 -> 204 [label=true]; 199 -> 351 [label=false]; 352 -> 353; 204 -> 209 [label=true]; 204 -> 350 [label=false]; 351 -> 352; 209 -> 214 [label=true]; 209 -> 349 [label=false]; 350 -> 351; 214 -> 219 [label=true]; 214 -> 348 [label=false]; 349 -> 350; 219 -> 224 [label=true]; 219 -> 347 [label=false]; 348 -> 349; 224 -> 229 [label=true]; 224 -> 346 [label=false]; 347 -> 348; 229 -> 234 [label=true]; 229 -> 345 [label=false]; 346 -> 347; 234 -> 239 [label=true]; 234 -> 344 [label=false]; 345 -> 346; 239 -> 244 [label=true]; 239 -> 343 [label=false]; 344 -> 345; 244 -> 249 [label=true]; 244 -> 342 [label=false]; 343 -> 344; 249 -> 254 [label=true]; 249 -> 341 [label=false]; 342 -> 343; 254 -> 259 [label=true]; 254 -> 340 [label=false]; 341 -> 342; 259 -> 264 [label=true]; 259 -> 339 [label=false]; 340 -> 341; 264 -> 269 [label=true]; 264 -> 338 [label=false]; 339 -> 340; 269 -> 274 [label=true]; 269 -> 337 [label=false]; 338 -> 339; 274 -> 279 [label=true]; 274 -> 336 [label=false]; 337 -> 338; 279 -> 284 [label=true]; 279 -> 335 [label=false]; 336 -> 337; 284 -> 289 [label=true]; 284 -> 334 [label=false]; 335 -> 336; 289 -> 294 [label=true]; 289 -> 333 [label=false]; 334 -> 335; 294 -> 299 [label=true]; 294 -> 332 [label=false]; 333 -> 334; 299 -> 304 [label=true]; 299 -> 331 [label=false]; 332 -> 333; 304 -> 309 [label=true]; 304 -> 330 [label=false]; 331 -> 332; 309 -> 314 [label=true]; 309 -> 329 [label=false]; 330 -> 331; 314 -> 319 [label=true]; 314 -> 328 [label=false]; 329 -> 330; 319 -> 324 [label=true]; 319 -> 327 [label=false]; 328 -> 329; 324 -> 327; 327 -> 328; }golang-gonum-v1-gonum-0.14.0/graph/path/weight.go000066400000000000000000000032361450372207100215150ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package path import ( "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/traverse" ) // Weighted is a weighted graph. It is a subset of graph.Weighted. type Weighted interface { // 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) } // Weighting is a mapping between a pair of nodes and a weight. It follows the // semantics of the Weighter interface. type Weighting func(xid, yid int64) (w float64, ok bool) // UniformCost returns a Weighting that returns an edge cost of 1 for existing // edges, zero for node identity and Inf for otherwise absent edges. func UniformCost(g traverse.Graph) Weighting { return func(xid, yid int64) (w float64, ok bool) { if xid == yid { return 0, true } if e := g.Edge(xid, yid); e != nil { return 1, true } return math.Inf(1), false } } // Heuristic returns an estimate of the cost of travelling between two nodes. type Heuristic func(x, y graph.Node) float64 // HeuristicCoster wraps the HeuristicCost method. A graph implementing the // interface provides a heuristic between any two given nodes. type HeuristicCoster interface { HeuristicCost(x, y graph.Node) float64 } golang-gonum-v1-gonum-0.14.0/graph/path/yen_ksp.go000066400000000000000000000105721450372207100216770ustar00rootroot00000000000000// 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 path import ( "math" "sort" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" ) // YenKShortestPaths returns the k-shortest loopless paths from s to t in g // with path costs no greater than cost beyond the shortest path. // If k is negative, only path cost will be used to limit the set of returned // paths. YenKShortestPaths will panic if g contains a negative edge weight. func YenKShortestPaths(g graph.Graph, k int, cost float64, s, t graph.Node) [][]graph.Node { // See https://en.wikipedia.org/wiki/Yen's_algorithm and // the paper at https://doi.org/10.1090%2Fqam%2F253822. _, isDirected := g.(graph.Directed) yk := yenKSPAdjuster{ Graph: g, isDirected: isDirected, } if wg, ok := g.(Weighted); ok { yk.weight = wg.Weight } else { yk.weight = UniformCost(g) } shortest, weight := DijkstraFrom(s, yk).To(t.ID()) cost += weight // Set cost to absolute cost limit. switch len(shortest) { case 0: return nil case 1: return [][]graph.Node{shortest} } paths := [][]graph.Node{shortest} var pot []yenShortest var root []graph.Node for i := int64(1); k < 0 || i < int64(k); i++ { // The spur node ranges from the first node to the next // to last node in the previous k-shortest path. for n := 0; n < len(paths[i-1])-1; n++ { yk.reset() spur := paths[i-1][n] root := append(root[:0], paths[i-1][:n+1]...) for _, path := range paths { if len(path) <= n { continue } ok := true for x := 0; x < len(root); x++ { if path[x].ID() != root[x].ID() { ok = false break } } if ok { yk.removeEdge(path[n].ID(), path[n+1].ID()) } } for _, u := range root[:len(root)-1] { yk.removeNode(u.ID()) } spath, weight := DijkstraFrom(spur, yk).To(t.ID()) if weight > cost || math.IsInf(weight, 1) { continue } if len(root) > 1 { var rootWeight float64 for x := 1; x < len(root); x++ { w, _ := yk.weight(root[x-1].ID(), root[x].ID()) rootWeight += w } spath = append(root[:len(root)-1], spath...) weight += rootWeight } pot = append(pot, yenShortest{spath, weight}) } if len(pot) == 0 { break } sort.Sort(byPathWeight(pot)) best := pot[0] if len(best.path) <= 1 || best.weight > cost { break } paths = append(paths, best.path) pot = pot[1:] } return paths } // yenShortest holds a path and its weight for sorting. type yenShortest struct { path []graph.Node weight float64 } type byPathWeight []yenShortest func (s byPathWeight) Len() int { return len(s) } func (s byPathWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byPathWeight) Less(i, j int) bool { return s[i].weight < s[j].weight } // yenKSPAdjuster allows walked edges to be omitted from a graph // without altering the embedded graph. type yenKSPAdjuster struct { graph.Graph isDirected bool // weight is the edge weight function // used for shortest path calculation. weight Weighting // visitedNodes holds the nodes that have // been removed by Yen's algorithm. visitedNodes map[int64]struct{} // visitedEdges holds the edges that have // been removed by Yen's algorithm. visitedEdges map[[2]int64]struct{} } func (g yenKSPAdjuster) From(id int64) graph.Nodes { if _, blocked := g.visitedNodes[id]; blocked { return graph.Empty } nodes := graph.NodesOf(g.Graph.From(id)) for i := 0; i < len(nodes); { if g.canWalk(id, nodes[i].ID()) { i++ continue } nodes[i] = nodes[len(nodes)-1] nodes = nodes[:len(nodes)-1] } if len(nodes) == 0 { return graph.Empty } return iterator.NewOrderedNodes(nodes) } func (g yenKSPAdjuster) canWalk(u, v int64) bool { if _, blocked := g.visitedNodes[v]; blocked { return false } _, blocked := g.visitedEdges[[2]int64{u, v}] return !blocked } func (g yenKSPAdjuster) removeNode(u int64) { g.visitedNodes[u] = struct{}{} } func (g yenKSPAdjuster) removeEdge(u, v int64) { g.visitedEdges[[2]int64{u, v}] = struct{}{} if !g.isDirected { g.visitedEdges[[2]int64{v, u}] = struct{}{} } } func (g *yenKSPAdjuster) reset() { g.visitedNodes = make(map[int64]struct{}) g.visitedEdges = make(map[[2]int64]struct{}) } func (g yenKSPAdjuster) Weight(xid, yid int64) (w float64, ok bool) { return g.weight(xid, yid) } golang-gonum-v1-gonum-0.14.0/graph/path/yen_ksp_test.go000066400000000000000000000263731450372207100227440ustar00rootroot00000000000000// 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 path import ( "math" "reflect" "sort" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var yenShortestPathTests = []struct { name string graph func() graph.WeightedEdgeAdder edges []simple.WeightedEdge query simple.Edge k int cost float64 wantPaths [][]int64 relaxed bool }{ { // https://en.wikipedia.org/w/index.php?title=Yen%27s_algorithm&oldid=841018784#Example name: "wikipedia example", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node('C'), T: simple.Node('D'), W: 3}, {F: simple.Node('C'), T: simple.Node('E'), W: 2}, {F: simple.Node('E'), T: simple.Node('D'), W: 1}, {F: simple.Node('D'), T: simple.Node('F'), W: 4}, {F: simple.Node('E'), T: simple.Node('F'), W: 2}, {F: simple.Node('E'), T: simple.Node('G'), W: 3}, {F: simple.Node('F'), T: simple.Node('G'), W: 2}, {F: simple.Node('F'), T: simple.Node('H'), W: 1}, {F: simple.Node('G'), T: simple.Node('H'), W: 2}, }, query: simple.Edge{F: simple.Node('C'), T: simple.Node('H')}, k: 3, cost: math.Inf(1), wantPaths: [][]int64{ {'C', 'E', 'F', 'H'}, {'C', 'E', 'G', 'H'}, {'C', 'D', 'F', 'H'}, }, }, { name: "1 edge graph", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 3}, }, query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, k: 10, cost: math.Inf(1), wantPaths: [][]int64{ {0, 1}, }, }, { name: "empty graph", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{}, query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, k: 1, wantPaths: nil, }, { name: "n-star graph", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 3}, {F: simple.Node(0), T: simple.Node(2), W: 3}, {F: simple.Node(0), T: simple.Node(3), W: 3}, }, query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, k: 1, cost: math.Inf(1), wantPaths: [][]int64{ {0, 1}, }, }, { name: "bipartite small", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: bipartite(5, 3, 0), query: simple.Edge{F: simple.Node(-1), T: simple.Node(1)}, k: 10, cost: math.Inf(1), wantPaths: [][]int64{ {-1, 2, 1}, {-1, 3, 1}, {-1, 4, 1}, {-1, 5, 1}, {-1, 6, 1}, }, }, { name: "bipartite parity", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: bipartite(5, 3, 0), query: simple.Edge{F: simple.Node(-1), T: simple.Node(1)}, k: 5, cost: math.Inf(1), wantPaths: [][]int64{ {-1, 2, 1}, {-1, 3, 1}, {-1, 4, 1}, {-1, 5, 1}, {-1, 6, 1}, }, }, { name: "bipartite large", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: bipartite(10, 3, 0), query: simple.Edge{F: simple.Node(-1), T: simple.Node(1)}, k: 5, cost: math.Inf(1), relaxed: true, }, { name: "bipartite inc", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: bipartite(5, 10, 1), query: simple.Edge{F: simple.Node(-1), T: simple.Node(1)}, k: 5, cost: math.Inf(1), wantPaths: [][]int64{ {-1, 2, 1}, {-1, 3, 1}, {-1, 4, 1}, {-1, 5, 1}, {-1, 6, 1}, }, }, { name: "bipartite dec", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: bipartite(5, 10, -1), query: simple.Edge{F: simple.Node(-1), T: simple.Node(1)}, k: 5, cost: math.Inf(1), wantPaths: [][]int64{ {-1, 6, 1}, {-1, 5, 1}, {-1, 4, 1}, {-1, 3, 1}, {-1, 2, 1}, }, }, { name: "waterfall", // This is the failing case in gonum/gonum#1700. graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: 1}, {F: simple.Node(2), T: simple.Node(4), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: 1}, {F: simple.Node(3), T: simple.Node(6), W: 1}, {F: simple.Node(4), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(6), W: 1}, }, query: simple.Edge{F: simple.Node(0), T: simple.Node(6)}, k: 4, cost: math.Inf(1), wantPaths: [][]int64{ {0, 1, 3, 6}, {0, 1, 5, 6}, {0, 1, 2, 4, 6}, {0, 1, 2, 5, 6}, }, }, { name: "waterfall_3", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(1), T: simple.Node(5), W: 1}, {F: simple.Node(2), T: simple.Node(4), W: 1}, {F: simple.Node(2), T: simple.Node(5), W: 1}, {F: simple.Node(3), T: simple.Node(6), W: 1}, {F: simple.Node(4), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(6), W: 1}, {F: simple.Node(5), T: simple.Node(6), W: 1}, }, query: simple.Edge{F: simple.Node(0), T: simple.Node(6)}, k: -1, cost: 0, // Find all paths equivalent to shortest. wantPaths: [][]int64{ {0, 1, 3, 6}, {0, 1, 5, 6}, }, }, { name: "clean_root", // This is the failing case in gonum/gonum#1778. graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 4}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 4}, }, query: simple.Edge{F: simple.Node(1), T: simple.Node(2)}, k: 3, cost: math.Inf(1), wantPaths: [][]int64{ {1, 2}, {1, 3, 2}, }, }, { name: "clean_root_4", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 4}, {F: simple.Node(1), T: simple.Node(3), W: 1}, {F: simple.Node(2), T: simple.Node(3), W: 4}, }, query: simple.Edge{F: simple.Node(1), T: simple.Node(2)}, k: -1, cost: 0, wantPaths: [][]int64{ {1, 2}, }, }, { name: "clean_root_1060", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 450}, {F: simple.Node(3), T: simple.Node(4), W: 450}, {F: simple.Node(3), T: simple.Node(1), W: 20}, {F: simple.Node(5), T: simple.Node(2), W: 450}, {F: simple.Node(2), T: simple.Node(4), W: 20}, {F: simple.Node(4), T: simple.Node(6), W: 610}, {F: simple.Node(5), T: simple.Node(7), W: 20}, {F: simple.Node(2), T: simple.Node(8), W: 610}, {F: simple.Node(7), T: simple.Node(3), W: 40}, {F: simple.Node(1), T: simple.Node(5), W: 40}, }, query: simple.Edge{F: simple.Node(8), T: simple.Node(5)}, k: -1, cost: 0, wantPaths: [][]int64{ {8, 2, 5}, }, }, { name: "clean_root_1100", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 450}, {F: simple.Node(3), T: simple.Node(4), W: 450}, {F: simple.Node(3), T: simple.Node(1), W: 20}, {F: simple.Node(5), T: simple.Node(2), W: 450}, {F: simple.Node(2), T: simple.Node(4), W: 20}, {F: simple.Node(4), T: simple.Node(6), W: 610}, {F: simple.Node(5), T: simple.Node(7), W: 20}, {F: simple.Node(2), T: simple.Node(8), W: 610}, {F: simple.Node(7), T: simple.Node(3), W: 40}, {F: simple.Node(1), T: simple.Node(5), W: 40}, }, query: simple.Edge{F: simple.Node(8), T: simple.Node(5)}, k: -1, cost: 40, wantPaths: [][]int64{ {8, 2, 5}, {8, 2, 1, 5}, }, }, { name: "clean_root_1140", graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, edges: []simple.WeightedEdge{ {F: simple.Node(1), T: simple.Node(2), W: 450}, {F: simple.Node(3), T: simple.Node(4), W: 450}, {F: simple.Node(3), T: simple.Node(1), W: 20}, {F: simple.Node(5), T: simple.Node(2), W: 450}, {F: simple.Node(2), T: simple.Node(4), W: 20}, {F: simple.Node(4), T: simple.Node(6), W: 610}, {F: simple.Node(5), T: simple.Node(7), W: 20}, {F: simple.Node(2), T: simple.Node(8), W: 610}, {F: simple.Node(7), T: simple.Node(3), W: 40}, {F: simple.Node(1), T: simple.Node(5), W: 40}, }, query: simple.Edge{F: simple.Node(8), T: simple.Node(5)}, k: -1, cost: 80, wantPaths: [][]int64{ {8, 2, 5}, {8, 2, 1, 5}, {8, 2, 1, 3, 7, 5}, {8, 2, 4, 3, 1, 5}, {8, 2, 4, 3, 7, 5}, }, }, } func bipartite(n int, weight, inc float64) []simple.WeightedEdge { var edges []simple.WeightedEdge for i := 2; i < n+2; i++ { edges = append(edges, simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(i), W: weight}, simple.WeightedEdge{F: simple.Node(i), T: simple.Node(1), W: weight}, ) weight += inc } return edges } func pathIDs(paths [][]graph.Node) [][]int64 { if paths == nil { return nil } ids := make([][]int64, len(paths)) for i, p := range paths { if p == nil { continue } ids[i] = make([]int64, len(p)) for j, n := range p { ids[i][j] = n.ID() } } return ids } func TestYenKSP(t *testing.T) { t.Parallel() for _, test := range yenShortestPathTests { g := test.graph() for _, e := range test.edges { g.SetWeightedEdge(e) } got := YenKShortestPaths(g.(graph.Graph), test.k, test.cost, test.query.From(), test.query.To()) gotIDs := pathIDs(got) paths := make(byPathWeight, len(gotIDs)) for i, p := range got { paths[i] = yenShortest{path: p, weight: pathWeight(p, g.(graph.Weighted))} } if !sort.IsSorted(paths) { t.Errorf("unexpected result for %q: got:%+v", test.name, paths) } if test.relaxed { continue } if len(gotIDs) != 0 { first := 0 last := pathWeight(got[0], g.(graph.Weighted)) for i := 1; i < len(got); i++ { w := pathWeight(got[i], g.(graph.Weighted)) if w == last { continue } ordered.BySliceValues(gotIDs[first:i]) first = i last = w } ordered.BySliceValues(gotIDs[first:]) } if !reflect.DeepEqual(test.wantPaths, gotIDs) { t.Errorf("unexpected result for %q:\ngot: %v\nwant:%v", test.name, gotIDs, test.wantPaths) } } } func pathWeight(path []graph.Node, g graph.Weighted) float64 { switch len(path) { case 0: return math.NaN() case 1: return 0 default: var w float64 for i, u := range path[:len(path)-1] { _w, _ := g.Weight(u.ID(), path[i+1].ID()) w += _w } return w } } golang-gonum-v1-gonum-0.14.0/graph/product/000077500000000000000000000000001450372207100204175ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/product/doc.go000066400000000000000000000014221450372207100215120ustar00rootroot00000000000000// Copyright ©2019 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 product implements graph product functions. // // All the graph products in this package are graphs with order // n₁n₂ where n₁ and n₂ are the orders of the input graphs. This is // the order of the set of the Cartesian product of the two input // graphs' nodes. // // The nodes of the product hold the original input graphs' nodes // in the A and B fields in product.Nodes. This allows a mapping // between the input graphs and their products. // // See https://en.wikipedia.org/wiki/Graph_product for more details // about graph products. package product // import "gonum.org/v1/gonum/graph/product" golang-gonum-v1-gonum-0.14.0/graph/product/product.go000066400000000000000000000236601450372207100224350ustar00rootroot00000000000000// Copyright ©2019 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 product import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/stat/combin" ) // Node is a product of two graph nodes. // All graph products return this type directly via relevant graph.Graph method // call, or indirectly via calls to graph.Edge methods from returned edges. type Node struct { UID int64 // A and B hold the nodes from graph a and b in a // graph product constructed by a product function. A, B graph.Node } // ID implements the graph.Node interface. func (n Node) ID() int64 { return n.UID } // Cartesian constructs the Cartesian product of a and b in dst. // // The Cartesian product of G₁ and G₂, G₁□G₂ has edges (u₁, u₂)~(v₁, v₂) when // (u₁=v₁ and u₂~v₂) or (u₁~v₁ and u₂=v₂). The Cartesian product has size m₂n₁+m₁n₂ // where m is the size of the input graphs and n is their order. func Cartesian(dst graph.Builder, a, b graph.Graph) { aNodes, bNodes, product := cartesianNodes(a, b) if len(product) == 0 { return } indexOfA := indexOf(aNodes) indexOfB := indexOf(bNodes) for _, p := range product { dst.AddNode(p) } dims := []int{len(aNodes), len(bNodes)} for i, uA := range aNodes { for j, uB := range bNodes { toB := b.From(uB.ID()) for toB.Next() { dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, j}, dims)], product[combin.IdxFor([]int{i, indexOfB[toB.Node().ID()]}, dims)], )) } toA := a.From(uA.ID()) for toA.Next() { dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, j}, dims)], product[combin.IdxFor([]int{indexOfA[toA.Node().ID()], j}, dims)], )) } } } } // Tensor constructs the Tensor product of a and b in dst. // // The Tensor product of G₁ and G₂, G₁⨯G₂ has edges (u₁, u₂)~(v₁, v₂) when // u₁~v₁ and u₂~v₂. The Tensor product has size 2m₁m₂ where m is the size // of the input graphs. func Tensor(dst graph.Builder, a, b graph.Graph) { aNodes, bNodes, product := cartesianNodes(a, b) if len(product) == 0 { return } indexOfA := indexOf(aNodes) indexOfB := indexOf(bNodes) for _, p := range product { dst.AddNode(p) } dims := []int{len(aNodes), len(bNodes)} for i, uA := range aNodes { toA := a.From(uA.ID()) for toA.Next() { j := indexOfA[toA.Node().ID()] for k, uB := range bNodes { toB := b.From(uB.ID()) for toB.Next() { dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, k}, dims)], product[combin.IdxFor([]int{j, indexOfB[toB.Node().ID()]}, dims)], )) } } } } } // Lexicographical constructs the Lexicographical product of a and b in dst. // // The Lexicographical product of G₁ and G₂, G₁·G₂ has edges (u₁, u₂)~(v₁, v₂) when // u₁~v₁ or (u₁=v₁ and u₂~v₂). The Lexicographical product has size m₂n₁+m₁n₂² // where m is the size of the input graphs and n is their order. func Lexicographical(dst graph.Builder, a, b graph.Graph) { aNodes, bNodes, product := cartesianNodes(a, b) if len(product) == 0 { return } indexOfA := indexOf(aNodes) indexOfB := indexOf(bNodes) for _, p := range product { dst.AddNode(p) } dims := []int{len(aNodes), len(bNodes)} p := make([]int, 2) for i, uA := range aNodes { toA := a.From(uA.ID()) for toA.Next() { j := indexOfA[toA.Node().ID()] gen := combin.NewCartesianGenerator([]int{len(bNodes), len(bNodes)}) for gen.Next() { p = gen.Product(p) dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, p[0]}, dims)], product[combin.IdxFor([]int{j, p[1]}, dims)], )) } } for j, uB := range bNodes { toB := b.From(uB.ID()) for toB.Next() { dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, j}, dims)], product[combin.IdxFor([]int{i, indexOfB[toB.Node().ID()]}, dims)], )) } } } } // Strong constructs the Strong product of a and b in dst. // // The Strong product of G₁ and G₂, G₁⊠G₂ has edges (u₁, u₂)~(v₁, v₂) when // (u₁=v₁ and u₂~v₂) or (u₁~v₁ and u₂=v₂) or (u₁~v₁ and u₂~v₂). The Strong // product has size n₁m₂+n₂m₁+2m₁m₂ where m is the size of the input graphs // and n is their order. func Strong(dst graph.Builder, a, b graph.Graph) { aNodes, bNodes, product := cartesianNodes(a, b) if len(product) == 0 { return } indexOfA := indexOf(aNodes) indexOfB := indexOf(bNodes) for _, p := range product { dst.AddNode(p) } dims := []int{len(aNodes), len(bNodes)} for i, uA := range aNodes { for j, uB := range bNodes { toB := b.From(uB.ID()) for toB.Next() { dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, j}, dims)], product[combin.IdxFor([]int{i, indexOfB[toB.Node().ID()]}, dims)], )) } toA := a.From(uA.ID()) for toA.Next() { dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, j}, dims)], product[combin.IdxFor([]int{indexOfA[toA.Node().ID()], j}, dims)], )) } } toA := a.From(uA.ID()) for toA.Next() { for j, uB := range bNodes { toB := b.From(uB.ID()) for toB.Next() { dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, j}, dims)], product[combin.IdxFor([]int{indexOfA[toA.Node().ID()], indexOfB[toB.Node().ID()]}, dims)], )) } } } } } // CoNormal constructs the Co-normal product of a and b in dst. // // The Co-normal product of G₁ and G₂, G₁*G₂ (or G₁[G₂]) has edges (u₁, u₂)~(v₁, v₂) // when u₁~v₁ or u₂~v₂. The Co-normal product is non-commutative. func CoNormal(dst graph.Builder, a, b graph.Graph) { aNodes, bNodes, product := cartesianNodes(a, b) if len(product) == 0 { return } indexOfA := indexOf(aNodes) indexOfB := indexOf(bNodes) for _, p := range product { dst.AddNode(p) } dims := []int{len(aNodes), len(bNodes)} p := make([]int, 2) for i, u := range aNodes { to := a.From(u.ID()) for to.Next() { j := indexOfA[to.Node().ID()] gen := combin.NewCartesianGenerator([]int{len(bNodes), len(bNodes)}) for gen.Next() { p = gen.Product(p) dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{i, p[0]}, dims)], product[combin.IdxFor([]int{j, p[1]}, dims)], )) } } } for i, u := range bNodes { to := b.From(u.ID()) for to.Next() { j := indexOfB[to.Node().ID()] gen := combin.NewCartesianGenerator([]int{len(aNodes), len(aNodes)}) for gen.Next() { p = gen.Product(p) dst.SetEdge(dst.NewEdge( product[combin.IdxFor([]int{p[0], i}, dims)], product[combin.IdxFor([]int{p[1], j}, dims)], )) } } } } // Modular constructs the Modular product of a and b in dst. // // The Modular product of G₁ and G₂, G₁◊G₂ has edges (u₁, u₂)~(v₁, v₂) // when (u₁~v₁ and u₂~v₂) or (u₁≁v₁ and u₂≁v₂), and (u₁≠v₁ and u₂≠v₂). // // Modular is O(n^2) time where n is the order of the Cartesian product // of a and b. func Modular(dst graph.Builder, a, b graph.Graph) { _, _, product := cartesianNodes(a, b) if len(product) == 0 { return } for _, p := range product { dst.AddNode(p) } _, aUndirected := a.(graph.Undirected) _, bUndirected := b.(graph.Undirected) _, dstUndirected := dst.(graph.Undirected) undirected := aUndirected && bUndirected && dstUndirected n := len(product) if undirected { n-- } for i, u := range product[:n] { var m int if undirected { m = i + 1 } for _, v := range product[m:] { if u.A.ID() == v.A.ID() || u.B.ID() == v.B.ID() { // No self-loops. continue } inA := a.Edge(u.A.ID(), v.A.ID()) != nil inB := b.Edge(u.B.ID(), v.B.ID()) != nil if inA == inB { dst.SetEdge(dst.NewEdge(u, v)) } } } } // ModularExt constructs the Modular product of a and b in dst with // additional control over assessing edge agreement. // // In addition to the modular product conditions, agree(u₁v₁, u₂v₂) must // return true when (u₁~v₁ and u₂~v₂) for an edge to be added between // (u₁, u₂) and (v₁, v₂) in dst. If agree is nil, Modular is called. // // ModularExt is O(n^2) time where n is the order of the Cartesian product // of a and b. func ModularExt(dst graph.Builder, a, b graph.Graph, agree func(eA, eB graph.Edge) bool) { if agree == nil { Modular(dst, a, b) return } _, _, product := cartesianNodes(a, b) if len(product) == 0 { return } for _, p := range product { dst.AddNode(p) } _, aUndirected := a.(graph.Undirected) _, bUndirected := b.(graph.Undirected) _, dstUndirected := dst.(graph.Undirected) undirected := aUndirected && bUndirected && dstUndirected n := len(product) if undirected { n-- } for i, u := range product[:n] { var m int if undirected { m = i + 1 } for _, v := range product[m:] { if u.A.ID() == v.A.ID() || u.B.ID() == v.B.ID() { // No self-loops. continue } eA := a.Edge(u.A.ID(), v.A.ID()) eB := b.Edge(u.B.ID(), v.B.ID()) inA := eA != nil inB := eB != nil if (inA && inB && agree(eA, eB)) || (!inA && !inB) { dst.SetEdge(dst.NewEdge(u, v)) } } } } // cartesianNodes returns the Cartesian product of the nodes in a and b. func cartesianNodes(a, b graph.Graph) (aNodes, bNodes []graph.Node, product []Node) { aNodes = lexicalNodes(a) bNodes = lexicalNodes(b) lens := []int{len(aNodes), len(bNodes)} product = make([]Node, combin.Card(lens)) gen := combin.NewCartesianGenerator(lens) p := make([]int, 2) for id := int64(0); gen.Next(); id++ { p = gen.Product(p) product[id] = Node{UID: id, A: aNodes[p[0]], B: bNodes[p[1]]} } return aNodes, bNodes, product } // lexicalNodes returns the nodes in g sorted lexically by node ID. func lexicalNodes(g graph.Graph) []graph.Node { nodes := graph.NodesOf(g.Nodes()) ordered.ByID(nodes) return nodes } func indexOf(nodes []graph.Node) map[int64]int { idx := make(map[int64]int, len(nodes)) for i, n := range nodes { idx[n.ID()] = i } return idx } golang-gonum-v1-gonum-0.14.0/graph/product/product_example_test.go000066400000000000000000000113621450372207100252030ustar00rootroot00000000000000// Copyright ©2019 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 product_test import ( "fmt" "os" "sort" "text/tabwriter" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/product" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" ) // atom is a graph.Node representing an atom in a molecule. type atom struct { name string // name is the name of the atom. pos int // pos is the position number of the atom. id int64 } // ID satisfies the graph.Node interface. func (n atom) ID() int64 { return n.id } func ExampleModular_subgraphIsomorphism() { // The modular product can be used to find subgraph isomorphisms. // See https://doi.org/10.1016/0020-0190(76)90049-1 and for a // theoretical perspective, https://doi.org/10.1145/990524.990529. // We can find the common structure between two organic molecules. // For example the purines adenine and guanine from nucleic acids. // Make a graph for adenine. adenine := simple.NewUndirectedGraph() for _, bond := range []simple.Edge{ // Purine nucleus. {F: atom{name: "N", pos: 1, id: 0}, T: atom{name: "C", pos: 2, id: 1}}, {F: atom{name: "N", pos: 1, id: 0}, T: atom{name: "C", pos: 6, id: 5}}, {F: atom{name: "C", pos: 2, id: 1}, T: atom{name: "N", pos: 3, id: 2}}, {F: atom{name: "N", pos: 3, id: 2}, T: atom{name: "C", pos: 4, id: 3}}, {F: atom{name: "C", pos: 4, id: 3}, T: atom{name: "C", pos: 5, id: 4}}, {F: atom{name: "C", pos: 4, id: 3}, T: atom{name: "N", pos: 9, id: 8}}, {F: atom{name: "C", pos: 5, id: 4}, T: atom{name: "C", pos: 6, id: 5}}, {F: atom{name: "C", pos: 5, id: 4}, T: atom{name: "N", pos: 7, id: 6}}, {F: atom{name: "N", pos: 7, id: 6}, T: atom{name: "C", pos: 8, id: 7}}, {F: atom{name: "C", pos: 8, id: 7}, T: atom{name: "N", pos: 9, id: 8}}, // Amino modification in adenine. // // Note that the position number of the N is non-standard. {F: atom{name: "C", pos: 6, id: 5}, T: atom{name: "N", pos: 10, id: 9}}, } { adenine.SetEdge(bond) } // Make a graph for guanine. // // Note that node IDs here have no intersection with // the adenine graph to show that they are not being // used to map between the graphs. guanine := simple.NewUndirectedGraph() for _, bond := range []simple.Edge{ // Purine nucleus. {F: atom{name: "N", pos: 1, id: 10}, T: atom{name: "C", pos: 2, id: 11}}, {F: atom{name: "N", pos: 1, id: 10}, T: atom{name: "C", pos: 6, id: 15}}, {F: atom{name: "C", pos: 2, id: 11}, T: atom{name: "N", pos: 3, id: 12}}, {F: atom{name: "N", pos: 3, id: 12}, T: atom{name: "C", pos: 4, id: 13}}, {F: atom{name: "C", pos: 4, id: 13}, T: atom{name: "C", pos: 5, id: 14}}, {F: atom{name: "C", pos: 4, id: 13}, T: atom{name: "N", pos: 9, id: 18}}, {F: atom{name: "C", pos: 5, id: 14}, T: atom{name: "C", pos: 6, id: 15}}, {F: atom{name: "C", pos: 5, id: 14}, T: atom{name: "N", pos: 7, id: 16}}, {F: atom{name: "N", pos: 7, id: 16}, T: atom{name: "C", pos: 8, id: 17}}, {F: atom{name: "C", pos: 8, id: 17}, T: atom{name: "N", pos: 9, id: 18}}, // Amino and keto modifications in guanine. // // Note that the position number of the N and O is non-standard. {F: atom{name: "C", pos: 2, id: 11}, T: atom{name: "N", pos: 11, id: 19}}, {F: atom{name: "C", pos: 6, id: 15}, T: atom{name: "O", pos: 10, id: 20}}, } { guanine.SetEdge(bond) } // Produce the modular product of the two graphs. p := simple.NewUndirectedGraph() product.Modular(p, adenine, guanine) // Find the maximal cliques in the modular product. mc := topo.BronKerbosch(p) // Report the largest. sort.Sort(byLength(mc)) max := len(mc[0]) w := tabwriter.NewWriter(os.Stdout, 5, 0, 0, ' ', tabwriter.AlignRight) fmt.Println(" Adenine Guanine") fmt.Fprintln(w, "Atom\tPos\tAtom\tPos\t") for _, c := range mc { if len(c) < max { break } for _, p := range c { // Extract the mapping between the // inputs from the product. p := p.(product.Node) adenine := p.A.(atom) guanine := p.B.(atom) fmt.Fprintf(w, "%s\t%d\t%s\t%d\t\n", adenine.name, adenine.pos, guanine.name, guanine.pos) } } w.Flush() // Unordered output: // Adenine Guanine // Atom Pos Atom Pos // N 3 N 3 // N 7 N 7 // N 10 O 10 // C 6 C 6 // C 2 C 2 // C 8 C 8 // C 5 C 5 // N 9 N 9 // N 1 N 1 // C 4 C 4 } // byLength implements the sort.Interface, sorting the slices // descending by length. type byLength [][]graph.Node func (n byLength) Len() int { return len(n) } func (n byLength) Less(i, j int) bool { return len(n[i]) > len(n[j]) } func (n byLength) Swap(i, j int) { n[i], n[j] = n[j], n[i] } golang-gonum-v1-gonum-0.14.0/graph/product/product_ext_example_test.go000066400000000000000000000103131450372207100260560ustar00rootroot00000000000000// Copyright ©2019 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 product_test import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/product" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" ) // person is a graph.Node representing a person. type person struct { name string // name is the name of the person. id int64 } // ID satisfies the graph.Node interface. func (n person) ID() int64 { return n.id } func ExampleModularExt_subgraphIsomorphism() { // Extended attributes of the graph can be used to refine // subgraph isomorphism identification. By filtering edge // agreement by weight we can identify social network // motifs within a larger graph. // // This example extracts sources of conflict from the // relationships of Julius Caesar, Mark Antony and // Cleopatra. // Make a graph describing people's relationships. // // Edge weight indicates love/animosity. people := simple.NewDirectedGraph() for _, relationship := range []simple.WeightedEdge{ {F: person{name: "Julius Caesar", id: 0}, T: person{name: "Cleopatra", id: 1}, W: 1}, {F: person{name: "Cleopatra", id: 1}, T: person{name: "Julius Caesar", id: 0}, W: 1}, {F: person{name: "Julius Caesar", id: 0}, T: person{name: "Cornelia", id: 3}, W: 1}, {F: person{name: "Cornelia", id: 3}, T: person{name: "Julius Caesar", id: 0}, W: 1}, {F: person{name: "Mark Antony", id: 2}, T: person{name: "Cleopatra", id: 1}, W: 1}, {F: person{name: "Cleopatra", id: 1}, T: person{name: "Mark Antony", id: 2}, W: 1}, {F: person{name: "Fulvia", id: 4}, T: person{name: "Mark Antony", id: 2}, W: 1}, {F: person{name: "Fulvia", id: 4}, T: person{name: "Cleopatra", id: 1}, W: -1}, {F: person{name: "Octavia", id: 5}, T: person{name: "Mark Antony", id: 2}, W: 1}, {F: person{name: "Octavia", id: 5}, T: person{name: "Cleopatra", id: 1}, W: -1}, } { people.SetEdge(relationship) } // Make a graph for the query pattern: a love triangle. pattern := simple.NewDirectedGraph() for _, relationsip := range []simple.WeightedEdge{ {F: person{name: "A", id: -1}, T: person{name: "B", id: -2}, W: 1}, {F: person{name: "B", id: -2}, T: person{name: "A", id: -1}, W: 1}, {F: person{name: "C", id: -3}, T: person{name: "A", id: -1}, W: -1}, {F: person{name: "C", id: -3}, T: person{name: "B", id: -2}, W: 1}, } { pattern.SetEdge(relationsip) } // Produce the modular product of the two graphs. p := simple.NewDirectedGraph() product.ModularExt(p, people, pattern, func(a, b graph.Edge) bool { return a.(simple.WeightedEdge).Weight() == b.(simple.WeightedEdge).Weight() }) // Find the maximal cliques in the undirected induction // of the modular product. mc := topo.BronKerbosch(undirected{p}) // Report the cliques that are identical in order to the pattern. fmt.Println("Person — Relationship position:") for _, c := range mc { if len(c) != pattern.Nodes().Len() { continue } for _, p := range c { // Extract the mapping between the // inputs from the product. p := p.(product.Node) people := p.A.(person) pattern := p.B.(person) fmt.Printf(" %s — %s\n", people.name, pattern.name) } fmt.Println() } // Unordered output: // Person — Relationship position: // Cleopatra — A // Mark Antony — B // Octavia — C // // Cleopatra — A // Mark Antony — B // Fulvia — C } // undirected converts a directed graph to an undirected graph // with edges between nodes only where directed edges exist in // both directions in the original graph. type undirected struct { graph.Directed } func (g undirected) From(uid int64) graph.Nodes { nodes := graph.NodesOf(g.Directed.From(uid)) for i := 0; i < len(nodes); { if g.Directed.Edge(nodes[i].ID(), uid) != nil { i++ } else { nodes[i], nodes = nodes[len(nodes)-1], nodes[:len(nodes)-1] } } return iterator.NewOrderedNodes(nodes) } func (g undirected) Edge(xid, yid int64) graph.Edge { e := g.Directed.Edge(xid, yid) if e != nil && g.Directed.Edge(yid, xid) != nil { return e } return nil } func (g undirected) EdgeBetween(xid, yid int64) graph.Edge { return g.Edge(xid, yid) } golang-gonum-v1-gonum-0.14.0/graph/product/product_test.go000066400000000000000000000257541450372207100235020ustar00rootroot00000000000000// Copyright ©2019 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 product import ( "bytes" "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/simple" ) func (n Node) DOTID() string { return fmt.Sprintf("(%d,%d)", n.A.ID(), n.B.ID()) } func left() *simple.UndirectedGraph { edges := []simple.Edge{ {F: simple.Node(-1), T: simple.Node(-2)}, {F: simple.Node(-2), T: simple.Node(-3)}, {F: simple.Node(-2), T: simple.Node(-4)}, {F: simple.Node(-3), T: simple.Node(-5)}, {F: simple.Node(-4), T: simple.Node(-5)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return g } func right() *simple.UndirectedGraph { edges := []simple.Edge{ {F: simple.Node(1), T: simple.Node(2)}, {F: simple.Node(2), T: simple.Node(3)}, {F: simple.Node(2), T: simple.Node(4)}, } g := simple.NewUndirectedGraph() for _, e := range edges { g.SetEdge(e) } return g } func path(m int) *simple.UndirectedGraph { sign := 1 if m < 0 { sign = -1 m = -m } g := simple.NewUndirectedGraph() if m == 0 { g.AddNode(simple.Node(0)) } for i := 1; i <= m; i++ { g.SetEdge(simple.Edge{F: simple.Node(sign * i), T: simple.Node(sign * (i + 1))}) } return g } var productTests = []struct { name string a, b *simple.UndirectedGraph }{ {name: "paths", a: path(-1), b: path(1)}, {name: "wp_mp", a: path(-2), b: path(2)}, {name: "wp_gp", a: left(), b: right()}, {name: "gnp_2×2", a: gnp(2, 0.5, rand.NewSource(1)), b: gnp(2, 0.5, rand.NewSource(2))}, {name: "gnp_2×3", a: gnp(2, 0.5, rand.NewSource(1)), b: gnp(3, 0.5, rand.NewSource(2))}, {name: "gnp_3×3", a: gnp(3, 0.5, rand.NewSource(1)), b: gnp(3, 0.5, rand.NewSource(2))}, {name: "gnp_4×4", a: gnp(4, 0.5, rand.NewSource(1)), b: gnp(4, 0.5, rand.NewSource(2))}, } func TestCartesian(t *testing.T) { for _, test := range productTests { got := simple.NewUndirectedGraph() Cartesian(got, test.a, test.b) gotBytes, _ := dot.Marshal(got, "", "", " ") want := simple.NewUndirectedGraph() naiveCartesian(want, test.a, test.b) wantBytes, _ := dot.Marshal(want, "", "", " ") gotEdgesLen := len(graph.EdgesOf(got.Edges())) nA := len(graph.NodesOf(test.a.Nodes())) mA := len(graph.EdgesOf(test.a.Edges())) nB := len(graph.NodesOf(test.b.Nodes())) mB := len(graph.EdgesOf(test.b.Edges())) wantEdgesLen := mB*nA + mA*nB if gotEdgesLen != wantEdgesLen { t.Errorf("unexpected number of edges for Cartesian product of %s: got:%d want:%d", test.name, gotEdgesLen, wantEdgesLen) } if !bytes.Equal(gotBytes, wantBytes) { t.Errorf("unexpected Cartesian product result for %s:\ngot:\n%s\nwant:\n%s", test.name, gotBytes, wantBytes) } } } // (u₁=v₁ and u₂~v₂) or (u₁~v₁ and u₂=v₂). func naiveCartesian(dst graph.Builder, a, b graph.Graph) { _, _, product := cartesianNodes(a, b) for _, p := range product { dst.AddNode(p) } for _, u := range product { for _, v := range product { edgeInA := a.Edge(u.A.ID(), v.A.ID()) != nil edgeInB := b.Edge(u.B.ID(), v.B.ID()) != nil if (u.A.ID() == v.A.ID() && edgeInB) || (edgeInA && u.B.ID() == v.B.ID()) { dst.SetEdge(dst.NewEdge(u, v)) } } } } func TestTensor(t *testing.T) { for _, test := range productTests { got := simple.NewUndirectedGraph() Tensor(got, test.a, test.b) gotBytes, _ := dot.Marshal(got, "", "", " ") want := simple.NewUndirectedGraph() naiveTensor(want, test.a, test.b) wantBytes, _ := dot.Marshal(want, "", "", " ") gotEdgesLen := len(graph.EdgesOf(got.Edges())) mA := len(graph.EdgesOf(test.a.Edges())) mB := len(graph.EdgesOf(test.b.Edges())) wantEdgesLen := 2 * mA * mB if gotEdgesLen != wantEdgesLen { t.Errorf("unexpected number of edges for Tensor product of %s: got:%d want:%d", test.name, gotEdgesLen, wantEdgesLen) } if !bytes.Equal(gotBytes, wantBytes) { t.Errorf("unexpected Tensor product result for %s:\ngot:\n%s\nwant:\n%s", test.name, gotBytes, wantBytes) } } } // u₁~v₁ and u₂~v₂. func naiveTensor(dst graph.Builder, a, b graph.Graph) { _, _, product := cartesianNodes(a, b) for _, p := range product { dst.AddNode(p) } for _, u := range product { for _, v := range product { edgeInA := a.Edge(u.A.ID(), v.A.ID()) != nil edgeInB := b.Edge(u.B.ID(), v.B.ID()) != nil if edgeInA && edgeInB { dst.SetEdge(dst.NewEdge(u, v)) } } } } func TestLexicographical(t *testing.T) { for _, test := range productTests { got := simple.NewUndirectedGraph() Lexicographical(got, test.a, test.b) gotBytes, _ := dot.Marshal(got, "", "", " ") want := simple.NewUndirectedGraph() naiveLexicographical(want, test.a, test.b) wantBytes, _ := dot.Marshal(want, "", "", " ") gotEdgesLen := len(graph.EdgesOf(got.Edges())) nA := len(graph.NodesOf(test.a.Nodes())) mA := len(graph.EdgesOf(test.a.Edges())) nB := len(graph.NodesOf(test.b.Nodes())) mB := len(graph.EdgesOf(test.b.Edges())) wantEdgesLen := mB*nA + mA*nB*nB if gotEdgesLen != wantEdgesLen { t.Errorf("unexpected number of edges for Lexicographical product of %s: got:%d want:%d", test.name, gotEdgesLen, wantEdgesLen) } if !bytes.Equal(gotBytes, wantBytes) { t.Errorf("unexpected Lexicographical product result for %s:\ngot:\n%s\nwant:\n%s", test.name, gotBytes, wantBytes) } } } // u₁~v₁ or (u₁=v₁ and u₂~v₂). func naiveLexicographical(dst graph.Builder, a, b graph.Graph) { _, _, product := cartesianNodes(a, b) for _, p := range product { dst.AddNode(p) } for _, u := range product { for _, v := range product { edgeInA := a.Edge(u.A.ID(), v.A.ID()) != nil edgeInB := b.Edge(u.B.ID(), v.B.ID()) != nil if edgeInA || (u.A.ID() == v.A.ID() && edgeInB) { dst.SetEdge(dst.NewEdge(u, v)) } } } } func TestStrong(t *testing.T) { for _, test := range productTests { got := simple.NewUndirectedGraph() Strong(got, test.a, test.b) gotBytes, _ := dot.Marshal(got, "", "", " ") want := simple.NewUndirectedGraph() naiveStrong(want, test.a, test.b) wantBytes, _ := dot.Marshal(want, "", "", " ") gotEdgesLen := len(graph.EdgesOf(got.Edges())) nA := len(graph.NodesOf(test.a.Nodes())) mA := len(graph.EdgesOf(test.a.Edges())) nB := len(graph.NodesOf(test.b.Nodes())) mB := len(graph.EdgesOf(test.b.Edges())) wantEdgesLen := nA*mB + nB*mA + 2*mA*mB if gotEdgesLen != wantEdgesLen { t.Errorf("unexpected number of edges for Strong product of %s: got:%d want:%d", test.name, gotEdgesLen, wantEdgesLen) } if !bytes.Equal(gotBytes, wantBytes) { t.Errorf("unexpected Strong product result for %s:\ngot:\n%s\nwant:\n%s", test.name, gotBytes, wantBytes) } } } // (u₁=v₁ and u₂~v₂) or (u₁~v₁ and u₂=v₂) or (u₁~v₁ and u₂~v₂). func naiveStrong(dst graph.Builder, a, b graph.Graph) { _, _, product := cartesianNodes(a, b) for _, p := range product { dst.AddNode(p) } for _, u := range product { for _, v := range product { edgeInA := a.Edge(u.A.ID(), v.A.ID()) != nil edgeInB := b.Edge(u.B.ID(), v.B.ID()) != nil if (u.A.ID() == v.A.ID() && edgeInB) || (edgeInA && u.B.ID() == v.B.ID()) || (edgeInA && edgeInB) { dst.SetEdge(dst.NewEdge(u, v)) } } } } func TestCoNormal(t *testing.T) { for _, test := range productTests { got := simple.NewUndirectedGraph() CoNormal(got, test.a, test.b) gotBytes, _ := dot.Marshal(got, "", "", " ") want := simple.NewUndirectedGraph() naiveCoNormal(want, test.a, test.b) wantBytes, _ := dot.Marshal(want, "", "", " ") if !bytes.Equal(gotBytes, wantBytes) { t.Errorf("unexpected Co-normal product result for %s:\ngot:\n%s\nwant:\n%s", test.name, gotBytes, wantBytes) } } } // u₁~v₁ or u₂~v₂. func naiveCoNormal(dst graph.Builder, a, b graph.Graph) { _, _, product := cartesianNodes(a, b) for _, p := range product { dst.AddNode(p) } for _, u := range product { for _, v := range product { edgeInA := a.Edge(u.A.ID(), v.A.ID()) != nil edgeInB := b.Edge(u.B.ID(), v.B.ID()) != nil if edgeInA || edgeInB { dst.SetEdge(dst.NewEdge(u, v)) } } } } func TestModular(t *testing.T) { for _, test := range productTests { got := simple.NewUndirectedGraph() Modular(got, test.a, test.b) gotBytes, _ := dot.Marshal(got, "", "", " ") want := simple.NewUndirectedGraph() naiveModular(want, test.a, test.b) wantBytes, _ := dot.Marshal(want, "", "", " ") if !bytes.Equal(gotBytes, wantBytes) { t.Errorf("unexpected Modular product result for %s:\ngot:\n%s\nwant:\n%s", test.name, gotBytes, wantBytes) } } } func TestModularExt(t *testing.T) { for _, test := range productTests { got := simple.NewUndirectedGraph() ModularExt(got, test.a, test.b, func(a, b graph.Edge) bool { return true }) gotBytes, _ := dot.Marshal(got, "", "", " ") want := simple.NewUndirectedGraph() naiveModular(want, test.a, test.b) wantBytes, _ := dot.Marshal(want, "", "", " ") if !bytes.Equal(gotBytes, wantBytes) { t.Errorf("unexpected ModularExt product result for %s:\ngot:\n%s\nwant:\n%s", test.name, gotBytes, wantBytes) } } } // (u₁~v₁ and u₂~v₂) or (u₁≁v₁ and u₂≁v₂). func naiveModular(dst graph.Builder, a, b graph.Graph) { _, _, product := cartesianNodes(a, b) for _, p := range product { dst.AddNode(p) } for i, u := range product { for j, v := range product { if i == j || u.A.ID() == v.A.ID() || u.B.ID() == v.B.ID() { // No self-edges. continue } edgeInA := a.Edge(u.A.ID(), v.A.ID()) != nil edgeInB := b.Edge(u.B.ID(), v.B.ID()) != nil if (edgeInA && edgeInB) || (!edgeInA && !edgeInB) { dst.SetEdge(dst.NewEdge(u, v)) } } } } func BenchmarkProduct(b *testing.B) { for seed, bench := range []struct { name string product func(dst graph.Builder, a, b graph.Graph) len []int }{ {"Cartesian", Cartesian, []int{50, 100}}, {"Cartesian naive", naiveCartesian, []int{50, 100}}, {"CoNormal", CoNormal, []int{50}}, {"CoNormal naive", naiveCoNormal, []int{50}}, {"Lexicographical", Lexicographical, []int{50}}, {"Lexicographical naive", naiveLexicographical, []int{50}}, {"Modular", Modular, []int{50}}, {"Modular naive", naiveModular, []int{50}}, {"Strong", Strong, []int{50}}, {"Strong naive", naiveStrong, []int{50}}, {"Tensor", Tensor, []int{50}}, {"Tensor naive", naiveTensor, []int{50}}, } { for _, p := range []float64{0.05, 0.25, 0.5, 0.75, 0.95} { for _, n := range bench.len { src := rand.NewSource(uint64(seed)) b.Run(fmt.Sprintf("%s %d-%.2f", bench.name, n, p), func(b *testing.B) { g1 := gnp(n, p, src) g2 := gnp(n, p, src) b.ResetTimer() for i := 0; i < b.N; i++ { dst := simple.NewDirectedGraph() bench.product(dst, g1, g2) } }) } } } } func gnp(n int, p float64, src rand.Source) *simple.UndirectedGraph { g := simple.NewUndirectedGraph() err := gen.Gnp(g, n, p, src) if err != nil { panic(fmt.Sprintf("gnp: bad test: %v", err)) } return g } golang-gonum-v1-gonum-0.14.0/graph/set/000077500000000000000000000000001450372207100175325ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/set/uid/000077500000000000000000000000001450372207100203135ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/set/uid/uid.go000066400000000000000000000022421450372207100214230ustar00rootroot00000000000000// 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 ( "math" "gonum.org/v1/gonum/graph/internal/set" ) // Max is the maximum ID value. const Max = math.MaxInt64 // Set implements available ID storage. type Set struct { maxID int64 used, free set.Int64s } // NewSet returns a new Set. 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 != math.MaxInt64 { return s.maxID + 1 } for id := int64(0); id <= s.maxID; 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) } golang-gonum-v1-gonum-0.14.0/graph/set/uid/uid_test.go000066400000000000000000000016461450372207100224710ustar00rootroot00000000000000// Copyright ©2020 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 ( "math" "testing" "golang.org/x/exp/rand" ) func TestSetChurn(t *testing.T) { rnd := rand.New(rand.NewSource(1)) set := NewSet() // Iterate over a number of ID allocations, // occasionally deleting IDs from the store. seen := make(map[int64]bool) for k := 0; k < 2; k++ { for i := 0; i < 1e4; i++ { id := set.NewID() if seen[id] { t.Fatalf("NewID returned already used ID") } set.Use(id) seen[id] = true if rnd.Float64() < 0.01 { j := rnd.Intn(10) for id := range seen { set.Release(id) delete(seen, id) j-- if j <= 0 { break } } } } // Kick the set into scavenging mode. set.Use(math.MaxInt64) } } golang-gonum-v1-gonum-0.14.0/graph/simple/000077500000000000000000000000001450372207100202305ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/simple/dense_directed_matrix.go000066400000000000000000000212341450372207100251060ustar00rootroot00000000000000// 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 ( "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 { 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) } golang-gonum-v1-gonum-0.14.0/graph/simple/dense_undirected_matrix.go000066400000000000000000000200161450372207100254460ustar00rootroot00000000000000// 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 ( "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 { 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.SymmetricDim() 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.SymmetricDim() // 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.SymmetricDim() return 0 <= id && id < int64(r) } golang-gonum-v1-gonum-0.14.0/graph/simple/densegraph_test.go000066400000000000000000000471741450372207100237530ustar00rootroot00000000000000// 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_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/testgraph" ) func isZeroContiguousSet(nodes []graph.Node) bool { t := make([]graph.Node, len(nodes)) copy(t, nodes) nodes = t ordered.ByID(nodes) for i, n := range nodes { if int64(i) != n.ID() { return false } } return true } func directedMatrixBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { if len(nodes) == 0 { return } if !isZeroContiguousSet(nodes) { return } seen := set.NewNodes() dg := simple.NewDirectedMatrix(len(nodes), absent, self, absent) for i := range nodes { seen.Add(simple.Node(i)) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } if !seen.Has(edge.From()) || !seen.Has(edge.To()) { continue } ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} e = append(e, ce) dg.SetWeightedEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } n = make([]graph.Node, 0, len(seen)) for _, sn := range seen { n = append(n, sn) } return dg, n, e, self, absent, true } func TestDirectedMatrix(t *testing.T) { t.Run("AdjacencyMatrix", func(t *testing.T) { testgraph.AdjacencyMatrix(t, directedMatrixBuilder) }) t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, directedMatrixBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, directedMatrixBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, directedMatrixBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, directedMatrixBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, directedMatrixBuilder, usesEmpty) }) t.Run("ReturnAllWeightedEdges", func(t *testing.T) { testgraph.ReturnAllWeightedEdges(t, directedMatrixBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, directedMatrixBuilder, usesEmpty) }) t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { testgraph.ReturnWeightedEdgeSlice(t, directedMatrixBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, directedMatrixBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, directedMatrixBuilder) }) t.Run("AddEdges", func(t *testing.T) { testgraph.AddEdges(t, 100, newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. false, // Cannot update nodes. ) }) t.Run("NoLoopAddEdges", func(t *testing.T) { testgraph.NoLoopAddEdges(t, 100, newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("AddWeightedEdges", func(t *testing.T) { testgraph.AddWeightedEdges(t, 100, newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, 0.5, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. false, // Cannot update nodes. ) }) t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { testgraph.NoLoopAddWeightedEdges(t, 100, newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, 0.5, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveEdges", func(t *testing.T) { g := newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)} rnd := rand.New(rand.NewSource(1)) it := g.Nodes() for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } func directedMatrixFromBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { if len(nodes) == 0 { return } if !isZeroContiguousSet(nodes) { return } seen := set.NewNodes() dg := simple.NewDirectedMatrixFrom(nodes, absent, self, absent) for _, n := range nodes { seen.Add(n) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } if !seen.Has(edge.From()) || !seen.Has(edge.To()) { continue } ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} e = append(e, ce) dg.SetWeightedEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } n = make([]graph.Node, 0, len(seen)) for _, sn := range seen { n = append(n, sn) } return dg, n, e, self, absent, true } func TestDirectedMatrixFrom(t *testing.T) { t.Run("AdjacencyMatrix", func(t *testing.T) { testgraph.AdjacencyMatrix(t, directedMatrixFromBuilder) }) t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, directedMatrixFromBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, directedMatrixFromBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, directedMatrixFromBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, directedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, directedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnAllWeightedEdges", func(t *testing.T) { testgraph.ReturnAllWeightedEdges(t, directedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, directedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { testgraph.ReturnWeightedEdgeSlice(t, directedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, directedMatrixFromBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, directedMatrixFromBuilder) }) const numNodes = 100 t.Run("AddEdges", func(t *testing.T) { testgraph.AddEdges(t, numNodes, newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddEdges", func(t *testing.T) { testgraph.NoLoopAddEdges(t, numNodes, newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("AddWeightedEdges", func(t *testing.T) { testgraph.AddWeightedEdges(t, numNodes, newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 1, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { testgraph.NoLoopAddWeightedEdges(t, numNodes, newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 1, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveEdges", func(t *testing.T) { g := newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)} rnd := rand.New(rand.NewSource(1)) it := g.Nodes() for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } type newEdgeShimDir struct { *simple.DirectedMatrix } func (g newEdgeShimDir) NewEdge(u, v graph.Node) graph.Edge { return simple.Edge{F: u, T: v} } func (g newEdgeShimDir) NewWeightedEdge(u, v graph.Node, w float64) graph.WeightedEdge { return simple.WeightedEdge{F: u, T: v, W: w} } func undirectedMatrixBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { if len(nodes) == 0 { return } if !isZeroContiguousSet(nodes) { return } seen := set.NewNodes() dg := simple.NewUndirectedMatrix(len(nodes), absent, self, absent) for i := range nodes { seen.Add(simple.Node(i)) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } if !seen.Has(edge.From()) || !seen.Has(edge.To()) { continue } ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} e = append(e, ce) dg.SetWeightedEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } n = make([]graph.Node, 0, len(seen)) for _, sn := range seen { n = append(n, sn) } return dg, n, e, self, absent, true } func TestUnirectedMatrix(t *testing.T) { t.Run("AdjacencyMatrix", func(t *testing.T) { testgraph.AdjacencyMatrix(t, undirectedMatrixBuilder) }) t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, undirectedMatrixBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, undirectedMatrixBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, undirectedMatrixBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, undirectedMatrixBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, undirectedMatrixBuilder, usesEmpty) }) t.Run("ReturnAllWeightedEdges", func(t *testing.T) { testgraph.ReturnAllWeightedEdges(t, undirectedMatrixBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, undirectedMatrixBuilder, usesEmpty) }) t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, undirectedMatrixBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, undirectedMatrixBuilder) }) t.Run("AddEdges", func(t *testing.T) { testgraph.AddEdges(t, 100, newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. false, // Cannot update nodes. ) }) t.Run("NoLoopAddEdges", func(t *testing.T) { testgraph.NoLoopAddEdges(t, 100, newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("AddWeightedEdges", func(t *testing.T) { testgraph.AddWeightedEdges(t, 100, newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, 1, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. false, // Cannot update nodes. ) }) t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { testgraph.NoLoopAddWeightedEdges(t, 100, newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, 1, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveEdges", func(t *testing.T) { g := newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)} rnd := rand.New(rand.NewSource(1)) it := g.Nodes() for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } func undirectedMatrixFromBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { if len(nodes) == 0 { return } if !isZeroContiguousSet(nodes) { return } seen := set.NewNodes() dg := simple.NewUndirectedMatrixFrom(nodes, absent, self, absent) for _, n := range nodes { seen.Add(n) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } if !seen.Has(edge.From()) || !seen.Has(edge.To()) { continue } ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} e = append(e, ce) dg.SetWeightedEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } n = make([]graph.Node, 0, len(seen)) for _, sn := range seen { n = append(n, sn) } return dg, n, e, self, absent, true } func TestUndirectedMatrixFrom(t *testing.T) { t.Run("AdjacencyMatrix", func(t *testing.T) { testgraph.AdjacencyMatrix(t, undirectedMatrixFromBuilder) }) t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, undirectedMatrixFromBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, undirectedMatrixFromBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, undirectedMatrixFromBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, undirectedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, undirectedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnAllWeightedEdges", func(t *testing.T) { testgraph.ReturnAllWeightedEdges(t, undirectedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, undirectedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixFromBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, undirectedMatrixFromBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, undirectedMatrixFromBuilder) }) const numNodes = 100 t.Run("AddEdges", func(t *testing.T) { testgraph.AddEdges(t, numNodes, newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddEdges", func(t *testing.T) { testgraph.NoLoopAddEdges(t, numNodes, newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("AddWeightedEdges", func(t *testing.T) { testgraph.AddWeightedEdges(t, numNodes, newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 1, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { testgraph.NoLoopAddWeightedEdges(t, numNodes, newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 1, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveEdges", func(t *testing.T) { g := newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)} rnd := rand.New(rand.NewSource(1)) it := g.Nodes() for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } type newEdgeShimUndir struct { *simple.UndirectedMatrix } func (g newEdgeShimUndir) NewEdge(u, v graph.Node) graph.Edge { return simple.Edge{F: u, T: v} } func (g newEdgeShimUndir) NewWeightedEdge(u, v graph.Node, w float64) graph.WeightedEdge { return simple.WeightedEdge{F: u, T: v, W: w} } func makeNodes(n int) []graph.Node { nodes := make([]graph.Node, n) for i := range nodes { nodes[i] = simple.Node(i) } return nodes } func TestBasicDenseImpassable(t *testing.T) { dg := simple.NewUndirectedMatrix(5, math.Inf(1), 0, math.Inf(1)) if dg == nil { t.Fatal("Directed graph could not be made") } for i := 0; i < 5; i++ { if dg.Node(int64(i)) == nil { t.Errorf("Node that should exist doesn't: %d", i) } if degree := dg.From(int64(i)).Len(); degree != 0 { t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree) } } for i := 5; i < 10; i++ { if dg.Node(int64(i)) != nil { t.Errorf("Node exists that shouldn't: %d", i) } } } func TestBasicDensePassable(t *testing.T) { dg := simple.NewUndirectedMatrix(5, 1, 0, math.Inf(1)) if dg == nil { t.Fatal("Directed graph could not be made") } for i := 0; i < 5; i++ { if dg.Node(int64(i)) == nil { t.Errorf("Node that should exist doesn't: %d", i) } if degree := dg.From(int64(i)).Len(); degree != 4 { t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree) } } for i := 5; i < 10; i++ { if dg.Node(int64(i)) != nil { t.Errorf("Node exists that shouldn't: %d", i) } } } func TestDirectedDenseAddRemove(t *testing.T) { dg := simple.NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1)) dg.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(0), T: simple.Node(2), W: 1}) if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 1 || neighbors[0].ID() != 2 || dg.Edge(int64(0), int64(2)) == nil { t.Errorf("Adding edge didn't create successor") } dg.RemoveEdge(int64(0), int64(2)) if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil { t.Errorf("Removing edge didn't properly remove successor") } if neighbors := graph.NodesOf(dg.To(int64(2))); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil { t.Errorf("Removing directed edge wrongly kept predecessor") } dg.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(0), T: simple.Node(2), W: 2}) // I figure we've torture tested From/To at this point // so we'll just use the bool functions now if dg.Edge(int64(0), int64(2)) == nil { t.Fatal("Adding directed edge didn't change successor back") } c1, _ := dg.Weight(int64(2), int64(0)) c2, _ := dg.Weight(int64(0), int64(2)) if c1 == c2 { t.Error("Adding directed edge affected cost in undirected manner") } } func TestUndirectedDenseAddRemove(t *testing.T) { dg := simple.NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1)) dg.SetEdge(simple.Edge{F: simple.Node(0), T: simple.Node(2)}) if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 1 || neighbors[0].ID() != 2 || dg.EdgeBetween(int64(0), int64(2)) == nil { t.Errorf("Couldn't add neighbor") } if neighbors := graph.NodesOf(dg.From(int64(2))); len(neighbors) != 1 || neighbors[0].ID() != 0 || dg.EdgeBetween(int64(2), int64(0)) == nil { t.Errorf("Adding an undirected neighbor didn't add it reciprocally") } } func TestDenseLists(t *testing.T) { dg := simple.NewDirectedMatrix(15, 1, 0, math.Inf(1)) nodes := graph.NodesOf(dg.Nodes()) if len(nodes) != 15 { t.Fatalf("Wrong number of nodes: got:%v want:%v", len(nodes), 15) } ordered.ByID(nodes) for i, node := range graph.NodesOf(dg.Nodes()) { if int64(i) != node.ID() { t.Errorf("Node list doesn't return properly id'd nodes") } } edges := graph.EdgesOf(dg.Edges()) if len(edges) != 15*14 { t.Errorf("Improper number of edges for passable dense graph") } dg.RemoveEdge(int64(12), int64(11)) edges = graph.EdgesOf(dg.Edges()) if len(edges) != (15*14)-1 { t.Errorf("Removing edge didn't affect edge listing properly") } } golang-gonum-v1-gonum-0.14.0/graph/simple/directed.go000066400000000000000000000133011450372207100223400ustar00rootroot00000000000000// 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/iterator" "gonum.org/v1/gonum/graph/set/uid" ) 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. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *DirectedGraph) From(id int64) graph.Nodes { if len(g.from[id]) == 0 { return graph.Empty } return iterator.NewNodesByEdge(g.nodes, g.from[id]) } // 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. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *DirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *DirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // 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. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *DirectedGraph) To(id int64) graph.Nodes { if len(g.to[id]) == 0 { return graph.Empty } return iterator.NewNodesByEdge(g.nodes, g.to[id]) } golang-gonum-v1-gonum-0.14.0/graph/simple/directed_test.go000066400000000000000000000112721450372207100234040ustar00rootroot00000000000000// 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_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/testgraph" ) func directedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, _, _ float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() dg := simple.NewDirectedGraph() for _, n := range nodes { seen.Add(n) dg.AddNode(n) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } f := dg.Node(edge.From().ID()) if f == nil { f = edge.From() } t := dg.Node(edge.To().ID()) if t == nil { t = edge.To() } ce := simple.Edge{F: f, T: t} seen.Add(ce.F) seen.Add(ce.T) e = append(e, ce) dg.SetEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return dg, n, e, math.NaN(), math.NaN(), true } func TestDirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, directedBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, directedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, directedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, directedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, directedBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, directedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, directedBuilder, usesEmpty) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, simple.NewDirectedGraph(), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, simple.NewDirectedGraph(), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }), ) }) t.Run("RemoveNodes", func(t *testing.T) { g := simple.NewDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddEdges", func(t *testing.T) { testgraph.AddEdges(t, 100, simple.NewDirectedGraph(), func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddEdges", func(t *testing.T) { testgraph.NoLoopAddEdges(t, 100, simple.NewDirectedGraph(), func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveEdges", func(t *testing.T) { g := simple.NewDirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } // Tests Issue #27 func TestEdgeOvercounting(t *testing.T) { g := generateDummyGraph() if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 { t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh)) } } func generateDummyGraph() *simple.DirectedGraph { nodes := [4]struct{ srcID, targetID int }{ {2, 1}, {1, 0}, {2, 0}, {0, 2}, } g := simple.NewDirectedGraph() for _, n := range nodes { g.SetEdge(simple.Edge{F: simple.Node(n.srcID), T: simple.Node(n.targetID)}) } return g } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123DirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := simple.NewDirectedGraph() n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/simple/doc.go000066400000000000000000000006311450372207100213240ustar00rootroot00000000000000// 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" golang-gonum-v1-gonum-0.14.0/graph/simple/simple.go000066400000000000000000000033511450372207100220520ustar00rootroot00000000000000// 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) } golang-gonum-v1-gonum-0.14.0/graph/simple/undirected.go000066400000000000000000000126521450372207100227130ustar00rootroot00000000000000// 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/iterator" "gonum.org/v1/gonum/graph/set/uid" ) var ( ug *UndirectedGraph _ graph.Graph = ug _ graph.Undirected = ug _ graph.NodeAdder = ug _ graph.NodeRemover = ug _ graph.EdgeAdder = ug _ graph.EdgeRemover = ug ) // UndirectedGraph implements a generalized undirected graph. type UndirectedGraph struct { nodes map[int64]graph.Node edges map[int64]map[int64]graph.Edge nodeIDs *uid.Set } // NewUndirectedGraph returns an UndirectedGraph. func NewUndirectedGraph() *UndirectedGraph { return &UndirectedGraph{ nodes: make(map[int64]graph.Node), edges: 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 *UndirectedGraph) 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 *UndirectedGraph) Edge(uid, vid int64) graph.Edge { return g.EdgeBetween(uid, vid) } // EdgeBetween returns the edge between nodes x and y. func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge { edge, ok := g.edges[xid][yid] if !ok { return nil } if edge.From().ID() == xid { return edge } return edge.ReversedEdge() } // Edges returns all the edges in the graph. func (g *UndirectedGraph) Edges() graph.Edges { if len(g.edges) == 0 { return graph.Empty } var edges []graph.Edge for xid, u := range g.edges { for yid, e := range u { if yid < xid { // Do not consider edges when the To node ID is // before the From node ID. Both orientations // are stored. continue } 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. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *UndirectedGraph) From(id int64) graph.Nodes { if len(g.edges[id]) == 0 { return graph.Empty } return iterator.NewNodesByEdge(g.nodes, g.edges[id]) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool { _, ok := g.edges[xid][yid] return ok } // NewEdge returns a new Edge from the source to the destination node. func (g *UndirectedGraph) 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 *UndirectedGraph) 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 *UndirectedGraph) Node(id int64) graph.Node { return g.nodes[id] } // Nodes returns all the nodes in the graph. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *UndirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *UndirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // RemoveEdge removes the edge with the given end IDs from the graph, leaving the terminal nodes. // If the edge does not exist it is a no-op. func (g *UndirectedGraph) RemoveEdge(fid, tid int64) { if _, ok := g.nodes[fid]; !ok { return } if _, ok := g.nodes[tid]; !ok { return } delete(g.edges[fid], tid) delete(g.edges[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 *UndirectedGraph) RemoveNode(id int64) { if _, ok := g.nodes[id]; !ok { return } delete(g.nodes, id) for from := range g.edges[id] { delete(g.edges[from], id) } delete(g.edges, 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 *UndirectedGraph) 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.edges[fid]; ok { fm[tid] = e } else { g.edges[fid] = map[int64]graph.Edge{tid: e} } if tm, ok := g.edges[tid]; ok { tm[fid] = e } else { g.edges[tid] = map[int64]graph.Edge{fid: e} } } golang-gonum-v1-gonum-0.14.0/graph/simple/undirected_test.go000066400000000000000000000116641450372207100237540ustar00rootroot00000000000000// 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_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/testgraph" ) const ( usesEmpty = true reversesEdges = true ) func undirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, _, _ float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() ug := simple.NewUndirectedGraph() for _, n := range nodes { seen.Add(n) ug.AddNode(n) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } f := ug.Node(edge.From().ID()) if f == nil { f = edge.From() } t := ug.Node(edge.To().ID()) if t == nil { t = edge.To() } ce := simple.Edge{F: f, T: t} seen.Add(ce.F) seen.Add(ce.T) e = append(e, ce) ug.SetEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return ug, n, e, math.NaN(), math.NaN(), true } func TestUndirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, undirectedBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, undirectedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, undirectedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, undirectedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, undirectedBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, undirectedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, undirectedBuilder, usesEmpty) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, simple.NewUndirectedGraph(), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, simple.NewUndirectedGraph(), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }), ) }) t.Run("RemoveNodes", func(t *testing.T) { g := simple.NewUndirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddEdges", func(t *testing.T) { testgraph.AddEdges(t, 100, simple.NewUndirectedGraph(), func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddEdges", func(t *testing.T) { testgraph.NoLoopAddEdges(t, 100, simple.NewUndirectedGraph(), func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveEdges", func(t *testing.T) { g := simple.NewUndirectedGraph() it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetEdge(g.NewEdge(u, v)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } func TestAssertMutableNotDirected(t *testing.T) { var g graph.UndirectedBuilder = simple.NewUndirectedGraph() if _, ok := g.(graph.Directed); ok { t.Fatal("Graph is directed, but a MutableGraph cannot safely be directed!") } } func TestMaxID(t *testing.T) { g := simple.NewUndirectedGraph() nodes := make(map[graph.Node]struct{}) for i := simple.Node(0); i < 3; i++ { g.AddNode(i) nodes[i] = struct{}{} } g.RemoveNode(int64(0)) delete(nodes, simple.Node(0)) g.RemoveNode(int64(2)) delete(nodes, simple.Node(2)) n := g.NewNode() g.AddNode(n) if g.Node(n.ID()) == nil { t.Error("added node does not exist in graph") } if _, exists := nodes[n]; exists { t.Errorf("Created already existing node id: %v", n.ID()) } } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123UndirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := simple.NewUndirectedGraph() n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/simple/weighted_directed.go000066400000000000000000000167741450372207100242410ustar00rootroot00000000000000// 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/iterator" "gonum.org/v1/gonum/graph/set/uid" ) var ( wdg *WeightedDirectedGraph _ graph.Graph = wdg _ graph.Weighted = wdg _ graph.Directed = wdg _ graph.WeightedDirected = wdg _ graph.NodeAdder = wdg _ graph.NodeRemover = wdg _ graph.WeightedEdgeAdder = wdg _ graph.EdgeRemover = wdg ) // WeightedDirectedGraph implements a generalized weighted directed graph. type WeightedDirectedGraph struct { nodes map[int64]graph.Node from map[int64]map[int64]graph.WeightedEdge to map[int64]map[int64]graph.WeightedEdge self, absent float64 nodeIDs *uid.Set } // NewWeightedDirectedGraph returns a WeightedDirectedGraph with the specified self and absent // edge weight values. func NewWeightedDirectedGraph(self, absent float64) *WeightedDirectedGraph { return &WeightedDirectedGraph{ nodes: make(map[int64]graph.Node), from: make(map[int64]map[int64]graph.WeightedEdge), to: make(map[int64]map[int64]graph.WeightedEdge), self: self, absent: absent, nodeIDs: uid.NewSet(), } } // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. func (g *WeightedDirectedGraph) 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 *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge { return g.WeightedEdge(uid, vid) } // Edges returns all the edges in the graph. func (g *WeightedDirectedGraph) 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. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) From(id int64) graph.Nodes { if len(g.from[id]) == 0 { return graph.Empty } return iterator.NewNodesByWeightedEdge(g.nodes, g.from[id]) } // HasEdgeBetween returns whether an edge exists between nodes x and y without // considering direction. func (g *WeightedDirectedGraph) 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 *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool { if _, ok := g.from[uid][vid]; !ok { return false } return true } // 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 *WeightedDirectedGraph) 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()) } // NewWeightedEdge returns a new weighted edge from the source to the destination node. func (g *WeightedDirectedGraph) NewWeightedEdge(from, to graph.Node, weight float64) graph.WeightedEdge { return WeightedEdge{F: from, T: to, W: weight} } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *WeightedDirectedGraph) Node(id int64) graph.Node { return g.nodes[id] } // Nodes returns all the nodes in the graph. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *WeightedDirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // 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 *WeightedDirectedGraph) 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 *WeightedDirectedGraph) 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) } // SetWeightedEdge adds a weighted 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 *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) { 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.WeightedEdge{tid: e} } if tm, ok := g.to[tid]; ok { tm[fid] = e } else { g.to[tid] = map[int64]graph.WeightedEdge{fid: e} } } // To returns all nodes in g that can reach directly to n. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedDirectedGraph) To(id int64) graph.Nodes { if len(g.to[id]) == 0 { return graph.Empty } return iterator.NewNodesByWeightedEdge(g.nodes, g.to[id]) } // 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 *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) { if xid == yid { return g.self, true } if to, ok := g.from[xid]; ok { if e, ok := to[yid]; ok { return e.Weight(), 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 *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge { edge, ok := g.from[uid][vid] if !ok { return nil } return edge } // WeightedEdges returns all the weighted edges in the graph. func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges { var edges []graph.WeightedEdge 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.NewOrderedWeightedEdges(edges) } golang-gonum-v1-gonum-0.14.0/graph/simple/weighted_directed_test.go000066400000000000000000000126411450372207100252650ustar00rootroot00000000000000// 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_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/testgraph" ) func weightedDirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() dg := simple.NewWeightedDirectedGraph(self, absent) for _, n := range nodes { seen.Add(n) dg.AddNode(n) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } f := dg.Node(edge.From().ID()) if f == nil { f = edge.From() } t := dg.Node(edge.To().ID()) if t == nil { t = edge.To() } ce := simple.WeightedEdge{F: f, T: t, W: edge.Weight()} seen.Add(ce.F) seen.Add(ce.T) e = append(e, ce) dg.SetWeightedEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return dg, n, e, self, absent, true } func TestWeightedDirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, weightedDirectedBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, weightedDirectedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, weightedDirectedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnAllWeightedEdges", func(t *testing.T) { testgraph.ReturnAllWeightedEdges(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { testgraph.ReturnWeightedEdgeSlice(t, weightedDirectedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, weightedDirectedBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, weightedDirectedBuilder) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, simple.NewWeightedDirectedGraph(1, 0), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, simple.NewWeightedDirectedGraph(1, 0), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }), ) }) t.Run("RemoveNodes", func(t *testing.T) { g := simple.NewWeightedDirectedGraph(1, 0) it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetWeightedEdge(g.NewWeightedEdge(u, v, 1)) } } testgraph.RemoveNodes(t, g) }) t.Run("AddWeightedEdges", func(t *testing.T) { testgraph.AddWeightedEdges(t, 100, simple.NewWeightedDirectedGraph(1, 0), 0.5, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { testgraph.NoLoopAddWeightedEdges(t, 100, simple.NewWeightedDirectedGraph(1, 0), 0.5, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveEdges", func(t *testing.T) { g := simple.NewWeightedDirectedGraph(1, 0) it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetWeightedEdge(g.NewWeightedEdge(u, v, 1)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } // Tests Issue #27 func TestWeightedEdgeOvercounting(t *testing.T) { g := generateDummyWeightedGraph() if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 { t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh)) } } func generateDummyWeightedGraph() *simple.WeightedDirectedGraph { nodes := [4]struct{ srcID, targetID int }{ {2, 1}, {1, 0}, {2, 0}, {0, 2}, } g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) for _, n := range nodes { g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(n.srcID), T: simple.Node(n.targetID), W: 1}) } return g } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123WeightedDirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/simple/weighted_undirected.go000066400000000000000000000170061450372207100245710ustar00rootroot00000000000000// 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/iterator" "gonum.org/v1/gonum/graph/set/uid" ) var ( wug *WeightedUndirectedGraph _ graph.Graph = wug _ graph.Weighted = wug _ graph.Undirected = wug _ graph.WeightedUndirected = wug _ graph.NodeAdder = wug _ graph.NodeRemover = wug _ graph.WeightedEdgeAdder = wug _ graph.EdgeRemover = wug ) // WeightedUndirectedGraph implements a generalized weighted undirected graph. type WeightedUndirectedGraph struct { nodes map[int64]graph.Node edges map[int64]map[int64]graph.WeightedEdge self, absent float64 nodeIDs *uid.Set } // NewWeightedUndirectedGraph returns an WeightedUndirectedGraph with the specified self and absent // edge weight values. func NewWeightedUndirectedGraph(self, absent float64) *WeightedUndirectedGraph { return &WeightedUndirectedGraph{ nodes: make(map[int64]graph.Node), edges: make(map[int64]map[int64]graph.WeightedEdge), self: self, absent: absent, nodeIDs: uid.NewSet(), } } // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. func (g *WeightedUndirectedGraph) 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 *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge { return g.WeightedEdgeBetween(uid, vid) } // EdgeBetween returns the edge between nodes x and y. func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge { return g.WeightedEdgeBetween(xid, yid) } // Edges returns all the edges in the graph. func (g *WeightedUndirectedGraph) Edges() graph.Edges { if len(g.edges) == 0 { return graph.Empty } var edges []graph.Edge for xid, u := range g.edges { for yid, e := range u { if yid < xid { // Do not consider edges when the To node ID is // before the From node ID. Both orientations // are stored. continue } 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 *WeightedUndirectedGraph) From(id int64) graph.Nodes { if len(g.edges[id]) == 0 { return graph.Empty } return iterator.NewNodesByWeightedEdge(g.nodes, g.edges[id]) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool { _, ok := g.edges[xid][yid] return ok } // 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 *WeightedUndirectedGraph) 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()) } // NewWeightedEdge returns a new weighted edge from the source to the destination node. func (g *WeightedUndirectedGraph) NewWeightedEdge(from, to graph.Node, weight float64) graph.WeightedEdge { return WeightedEdge{F: from, T: to, W: weight} } // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g *WeightedUndirectedGraph) Node(id int64) graph.Node { return g.nodes[id] } // Nodes returns all the nodes in the graph. // // The returned graph.Nodes is only valid until the next mutation of // the receiver. func (g *WeightedUndirectedGraph) Nodes() graph.Nodes { if len(g.nodes) == 0 { return graph.Empty } return iterator.NewNodes(g.nodes) } // NodeWithID returns a Node with the given ID if possible. If a graph.Node // is returned that is not already in the graph NodeWithID will return true // for new and the graph.Node must be added to the graph before use. func (g *WeightedUndirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { n, ok := g.nodes[id] if ok { return n, false } return Node(id), true } // 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 *WeightedUndirectedGraph) RemoveEdge(fid, tid int64) { if _, ok := g.nodes[fid]; !ok { return } if _, ok := g.nodes[tid]; !ok { return } delete(g.edges[fid], tid) delete(g.edges[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 *WeightedUndirectedGraph) RemoveNode(id int64) { if _, ok := g.nodes[id]; !ok { return } delete(g.nodes, id) for from := range g.edges[id] { delete(g.edges[from], id) } delete(g.edges, id) g.nodeIDs.Release(id) } // SetWeightedEdge adds a weighted 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 *WeightedUndirectedGraph) SetWeightedEdge(e graph.WeightedEdge) { 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.edges[fid]; ok { fm[tid] = e } else { g.edges[fid] = map[int64]graph.WeightedEdge{tid: e} } if tm, ok := g.edges[tid]; ok { tm[fid] = e } else { g.edges[tid] = map[int64]graph.WeightedEdge{fid: e} } } // 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 *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) { if xid == yid { return g.self, true } if n, ok := g.edges[xid]; ok { if e, ok := n[yid]; ok { return e.Weight(), 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 *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge { return g.WeightedEdgeBetween(uid, vid) } // WeightedEdgeBetween returns the weighted edge between nodes x and y. func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge { edge, ok := g.edges[xid][yid] if !ok { return nil } if edge.From().ID() == xid { return edge } return edge.ReversedEdge().(graph.WeightedEdge) } // WeightedEdges returns all the weighted edges in the graph. func (g *WeightedUndirectedGraph) WeightedEdges() graph.WeightedEdges { var edges []graph.WeightedEdge for xid, u := range g.edges { for yid, e := range u { if yid < xid { // Do not consider lines when the To node ID is // before the From node ID. Both orientations // are stored. continue } edges = append(edges, e) } } if len(edges) == 0 { return graph.Empty } return iterator.NewOrderedWeightedEdges(edges) } golang-gonum-v1-gonum-0.14.0/graph/simple/weighted_undirected_test.go000066400000000000000000000131421450372207100256250ustar00rootroot00000000000000// 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_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/testgraph" ) func weightedUndirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { seen := set.NewNodes() ug := simple.NewWeightedUndirectedGraph(self, absent) for _, n := range nodes { seen.Add(n) ug.AddNode(n) } for _, edge := range edges { if edge.From().ID() == edge.To().ID() { continue } f := ug.Node(edge.From().ID()) if f == nil { f = edge.From() } t := ug.Node(edge.To().ID()) if t == nil { t = edge.To() } ce := simple.WeightedEdge{F: f, T: t, W: edge.Weight()} seen.Add(ce.F) seen.Add(ce.T) e = append(e, ce) ug.SetWeightedEdge(ce) } if len(e) == 0 && len(edges) != 0 { return nil, nil, nil, math.NaN(), math.NaN(), false } if len(seen) != 0 { n = make([]graph.Node, 0, len(seen)) } for _, sn := range seen { n = append(n, sn) } return ug, n, e, self, absent, true } func TestWeightedUndirected(t *testing.T) { t.Run("EdgeExistence", func(t *testing.T) { testgraph.EdgeExistence(t, weightedUndirectedBuilder, reversesEdges) }) t.Run("NodeExistence", func(t *testing.T) { testgraph.NodeExistence(t, weightedUndirectedBuilder) }) t.Run("ReturnAdjacentNodes", func(t *testing.T) { testgraph.ReturnAdjacentNodes(t, weightedUndirectedBuilder, usesEmpty, reversesEdges) }) t.Run("ReturnAllEdges", func(t *testing.T) { testgraph.ReturnAllEdges(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnAllNodes", func(t *testing.T) { testgraph.ReturnAllNodes(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnAllWeightedEdges", func(t *testing.T) { testgraph.ReturnAllWeightedEdges(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnEdgeSlice", func(t *testing.T) { testgraph.ReturnEdgeSlice(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { testgraph.ReturnWeightedEdgeSlice(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("ReturnNodeSlice", func(t *testing.T) { testgraph.ReturnNodeSlice(t, weightedUndirectedBuilder, usesEmpty) }) t.Run("Weight", func(t *testing.T) { testgraph.Weight(t, weightedUndirectedBuilder) }) t.Run("AddNodes", func(t *testing.T) { testgraph.AddNodes(t, simple.NewWeightedUndirectedGraph(1, 0), 100) }) t.Run("AddArbitraryNodes", func(t *testing.T) { testgraph.AddArbitraryNodes(t, simple.NewWeightedUndirectedGraph(1, 0), testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }), ) }) t.Run("AddWeightedEdges", func(t *testing.T) { testgraph.AddWeightedEdges(t, 100, simple.NewWeightedUndirectedGraph(1, 0), 0.5, func(id int64) graph.Node { return simple.Node(id) }, false, // Cannot set self-loops. true, // Can update nodes. ) }) t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { testgraph.NoLoopAddWeightedEdges(t, 100, simple.NewWeightedUndirectedGraph(1, 0), 0.5, func(id int64) graph.Node { return simple.Node(id) }, ) }) t.Run("RemoveNodes", func(t *testing.T) { g := simple.NewWeightedUndirectedGraph(1, 0) it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetWeightedEdge(g.NewWeightedEdge(u, v, 1)) } } testgraph.RemoveNodes(t, g) }) t.Run("RemoveEdges", func(t *testing.T) { g := simple.NewWeightedUndirectedGraph(1, 0) it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) for it.Next() { g.AddNode(it.Node()) } it.Reset() rnd := rand.New(rand.NewSource(1)) for it.Next() { u := it.Node() d := rnd.Intn(5) vit := g.Nodes() for d >= 0 && vit.Next() { v := vit.Node() if v.ID() == u.ID() { continue } d-- g.SetWeightedEdge(g.NewWeightedEdge(u, v, 1)) } } testgraph.RemoveEdges(t, g, g.Edges()) }) } func TestAssertWeightedMutableNotDirected(t *testing.T) { var g graph.UndirectedWeightedBuilder = simple.NewWeightedUndirectedGraph(0, math.Inf(1)) if _, ok := g.(graph.Directed); ok { t.Fatal("Graph is directed, but a MutableGraph cannot safely be directed!") } } func TestWeightedMaxID(t *testing.T) { g := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) nodes := make(map[graph.Node]struct{}) for i := simple.Node(0); i < 3; i++ { g.AddNode(i) nodes[i] = struct{}{} } g.RemoveNode(int64(0)) delete(nodes, simple.Node(0)) g.RemoveNode(int64(2)) delete(nodes, simple.Node(2)) n := g.NewNode() g.AddNode(n) if g.Node(n.ID()) == nil { t.Error("added node does not exist in graph") } if _, exists := nodes[n]; exists { t.Errorf("Created already existing node id: %v", n.ID()) } } // Test for issue #123 https://github.com/gonum/graph/issues/123 func TestIssue123WeightedUndirectedGraph(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() g := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) n0 := g.NewNode() g.AddNode(n0) n1 := g.NewNode() g.AddNode(n1) g.RemoveNode(n0.ID()) n2 := g.NewNode() g.AddNode(n2) } golang-gonum-v1-gonum-0.14.0/graph/spectral/000077500000000000000000000000001450372207100205545ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/spectral/doc.go000066400000000000000000000004441450372207100216520ustar00rootroot00000000000000// Copyright ©2019 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 spectral provides graph spectral analysis functions. package spectral // import "gonum.org/v1/gonum/graph/spectral" golang-gonum-v1-gonum-0.14.0/graph/spectral/laplacian.go000066400000000000000000000067001450372207100230320ustar00rootroot00000000000000// 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 spectral import ( "math" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/mat" ) // Laplacian is a graph Laplacian matrix. type Laplacian struct { // Matrix holds the Laplacian matrix. mat.Matrix // Nodes holds the input graph nodes. Nodes []graph.Node // Index is a mapping from the graph // node IDs to row and column indices. Index map[int64]int } // NewLaplacian returns a Laplacian matrix for the simple undirected graph g. // The Laplacian is defined as D-A where D is a diagonal matrix holding the // degree of each node and A is the graph adjacency matrix of the input graph. // If g contains self edges, NewLaplacian will panic. func NewLaplacian(g graph.Undirected) Laplacian { nodes := graph.NodesOf(g.Nodes()) indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { id := n.ID() indexOf[id] = i } l := mat.NewSymDense(len(nodes), nil) for j, u := range nodes { uid := u.ID() to := graph.NodesOf(g.From(uid)) l.SetSym(j, j, float64(len(to))) for _, v := range to { vid := v.ID() if uid == vid { panic("network: self edge in graph") } if uid < vid { l.SetSym(indexOf[vid], j, -1) } } } return Laplacian{Matrix: l, Nodes: nodes, Index: indexOf} } // NewSymNormLaplacian returns a symmetric normalized Laplacian matrix for the // simple undirected graph g. // The normalized Laplacian is defined as I-D^(-1/2)AD^(-1/2) where D is a // diagonal matrix holding the degree of each node and A is the graph adjacency // matrix of the input graph. // If g contains self edges, NewSymNormLaplacian will panic. func NewSymNormLaplacian(g graph.Undirected) Laplacian { nodes := graph.NodesOf(g.Nodes()) indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { id := n.ID() indexOf[id] = i } l := mat.NewSymDense(len(nodes), nil) for j, u := range nodes { uid := u.ID() to := graph.NodesOf(g.From(uid)) if len(to) == 0 { continue } l.SetSym(j, j, 1) squdeg := math.Sqrt(float64(len(to))) for _, v := range to { vid := v.ID() if uid == vid { panic("network: self edge in graph") } if uid < vid { to := g.From(vid) k := to.Len() if k < 0 { k = len(graph.NodesOf(to)) } l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(k)))) } } } return Laplacian{Matrix: l, Nodes: nodes, Index: indexOf} } // NewRandomWalkLaplacian returns a damp-scaled random walk Laplacian matrix for // the simple graph g. // The random walk Laplacian is defined as I-D^(-1)A where D is a diagonal matrix // holding the degree of each node and A is the graph adjacency matrix of the input // graph. // If g contains self edges, NewRandomWalkLaplacian will panic. func NewRandomWalkLaplacian(g graph.Graph, damp float64) Laplacian { nodes := graph.NodesOf(g.Nodes()) indexOf := make(map[int64]int, len(nodes)) for i, n := range nodes { id := n.ID() indexOf[id] = i } l := mat.NewDense(len(nodes), len(nodes), nil) for j, u := range nodes { uid := u.ID() to := graph.NodesOf(g.From(uid)) if len(to) == 0 { continue } l.Set(j, j, 1-damp) rudeg := (damp - 1) / float64(len(to)) for _, v := range to { vid := v.ID() if uid == vid { panic("network: self edge in graph") } l.Set(indexOf[vid], j, rudeg) } } return Laplacian{Matrix: l, Nodes: nodes, Index: indexOf} } golang-gonum-v1-gonum-0.14.0/graph/spectral/laplacian_test.go000066400000000000000000000063121450372207100240700ustar00rootroot00000000000000// 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 spectral import ( "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/mat" ) var randomWalkLaplacianTests = []struct { g []set damp float64 want *mat.Dense }{ { g: []set{ A: linksTo(B, C), B: linksTo(C), C: nil, }, want: mat.NewDense(3, 3, []float64{ 1, 0, 0, -0.5, 1, 0, -0.5, -1, 0, }), }, { g: []set{ A: linksTo(B, C), B: linksTo(C), C: nil, }, damp: 0.85, want: mat.NewDense(3, 3, []float64{ 0.15, 0, 0, -0.075, 0.15, 0, -0.075, -0.15, 0, }), }, { g: []set{ A: linksTo(B), B: linksTo(C), C: linksTo(A), }, damp: 0.85, want: mat.NewDense(3, 3, []float64{ 0.15, 0, -0.15, -0.15, 0.15, 0, 0, -0.15, 0.15, }), }, { // Example graph from http://en.wikipedia.org/wiki/File:PageRanks-Example.svg 16:17, 8 July 2009 g: []set{ A: nil, B: linksTo(C), C: linksTo(B), D: linksTo(A, B), E: linksTo(D, B, F), F: linksTo(B, E), G: linksTo(B, E), H: linksTo(B, E), I: linksTo(B, E), J: linksTo(E), K: linksTo(E), }, want: mat.NewDense(11, 11, []float64{ 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -0.5, -1. / 3., -0.5, -0.5, -0.5, -0.5, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1. / 3., 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -0.5, -0.5, -0.5, -0.5, -1, -1, 0, 0, 0, 0, -1. / 3., 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, }), }, } func TestRandomWalkLaplacian(t *testing.T) { const tol = 1e-14 for i, test := range randomWalkLaplacianTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } l := NewRandomWalkLaplacian(g, test.damp) _, c := l.Dims() for j := 0; j < c; j++ { if got := mat.Sum(l.Matrix.(*mat.Dense).ColView(j)); !scalar.EqualWithinAbsOrRel(got, 0, tol, tol) { t.Errorf("unexpected column sum for test %d, column %d: got:%v want:0", i, j, got) } } l = NewRandomWalkLaplacian(sortedNodeGraph{g}, test.damp) if !mat.EqualApprox(l, test.want, tol) { t.Errorf("unexpected result for test %d:\ngot:\n% .2v\nwant:\n% .2v", i, mat.Formatted(l), mat.Formatted(test.want)) } } } type sortedNodeGraph struct { graph.Graph } func (g sortedNodeGraph) Nodes() graph.Nodes { n := graph.NodesOf(g.Graph.Nodes()) ordered.ByID(n) return iterator.NewOrderedNodes(n) } const ( A = iota B C D E F G H I J K L M N O P Q R S T U V W X Y Z ) // set is an integer set. type set map[int64]struct{} func linksTo(i ...int64) set { if len(i) == 0 { return nil } s := make(set) for _, v := range i { s[v] = struct{}{} } return s } golang-gonum-v1-gonum-0.14.0/graph/testgraph/000077500000000000000000000000001450372207100207405ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/testgraph/testcases.go000066400000000000000000000226231450372207100232720ustar00rootroot00000000000000// 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 testgraph import ( "math" "gonum.org/v1/gonum/graph" ) // node is a graph.Node implementation that is not exported // so that other packages will not be aware of its implementation. type node int64 func (n node) ID() int64 { return int64(n) } // line is an extended graph.Edge implementation that is not exported // so that other packages will not be aware of its implementation. It // covers all the edge types exported by graph. type line struct { F, T graph.Node UID int64 W float64 } func (e line) From() graph.Node { return e.F } func (e line) To() graph.Node { return e.T } func (e line) ReversedEdge() graph.Edge { e.F, e.T = e.T, e.F; return e } func (e line) ID() int64 { return e.UID } func (e line) Weight() float64 { return e.W } var testCases = []struct { // name is the name of the test. name string // nodes is the set of nodes that should be used // to construct the graph. nodes []graph.Node // edges is the set of edges that should be used // to construct the graph. edges []WeightedLine // nonexist is a set of nodes that should not be // found within the graph. nonexist []graph.Node // self is the weight value associated with // a self edge for simple graphs that do not // store individual self edges. self float64 // absent is the weight value associated // with absent edges. absent float64 }{ { name: "empty", nonexist: []graph.Node{node(-1), node(0), node(1)}, self: 0, absent: math.Inf(1), }, { name: "one - negative", nodes: []graph.Node{node(-1)}, nonexist: []graph.Node{node(0), node(1)}, self: 0, absent: math.Inf(1), }, { name: "one - zero", nodes: []graph.Node{node(0)}, nonexist: []graph.Node{node(-1), node(1)}, self: 0, absent: math.Inf(1), }, { name: "one - positive", nodes: []graph.Node{node(1)}, nonexist: []graph.Node{node(-1), node(0)}, self: 0, absent: math.Inf(1), }, { name: "one - self loop", nodes: []graph.Node{node(0)}, edges: []WeightedLine{line{F: node(0), T: node(0), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(-1), node(1)}, self: 0, absent: math.Inf(1), }, { name: "two - positive", nodes: []graph.Node{node(1), node(2)}, edges: []WeightedLine{line{F: node(1), T: node(2), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(-1), node(0)}, self: 0, absent: math.Inf(1), }, { name: "two - negative", nodes: []graph.Node{node(-1), node(-2)}, edges: []WeightedLine{line{F: node(-1), T: node(-2), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(0), node(-3)}, self: 0, absent: math.Inf(1), }, { name: "two - zero spanning", nodes: []graph.Node{node(-1), node(1)}, edges: []WeightedLine{line{F: node(-1), T: node(1), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(0), node(2)}, self: 0, absent: math.Inf(1), }, { name: "two - zero contiguous", nodes: []graph.Node{node(0), node(1)}, edges: []WeightedLine{line{F: node(0), T: node(1), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(-1), node(2)}, self: 0, absent: math.Inf(1), }, { name: "three - positive", nodes: []graph.Node{node(1), node(2), node(3)}, edges: []WeightedLine{line{F: node(1), T: node(2), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(-1), node(0)}, self: 0, absent: math.Inf(1), }, { name: "three - negative", nodes: []graph.Node{node(-1), node(-2), node(-3)}, edges: []WeightedLine{line{F: node(-1), T: node(-2), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(0), node(1)}, self: 0, absent: math.Inf(1), }, { name: "three - zero spanning", nodes: []graph.Node{node(-1), node(0), node(1)}, edges: []WeightedLine{line{F: node(-1), T: node(1), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(-2), node(2)}, self: 0, absent: math.Inf(1), }, { name: "three - zero contiguous", nodes: []graph.Node{node(0), node(1), node(2)}, edges: []WeightedLine{line{F: node(0), T: node(1), UID: 0, W: 0.5}}, nonexist: []graph.Node{node(-1), node(3)}, self: 0, absent: math.Inf(1), }, { name: "three in only", nodes: []graph.Node{node(0), node(1), node(2), node(3)}, edges: []WeightedLine{ line{F: node(1), T: node(0), UID: 0, W: 0.5}, line{F: node(2), T: node(0), UID: 1, W: 0.5}, line{F: node(3), T: node(0), UID: 2, W: 0.5}, }, nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "three out only", nodes: []graph.Node{node(0), node(1), node(2), node(3)}, edges: []WeightedLine{ line{F: node(0), T: node(1), UID: 0, W: 0.5}, line{F: node(0), T: node(2), UID: 1, W: 0.5}, line{F: node(0), T: node(3), UID: 2, W: 0.5}, }, nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique - single(non-prepared)", edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i + 1; j < 4; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique+ - single(non-prepared)", edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i; j < 4; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique - single(prepared)", nodes: func() []graph.Node { const n = 4 nodes := make([]graph.Node, n) for i := range nodes { nodes[i] = node(i) } return nodes }(), edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique+ - single(prepared)", nodes: func() []graph.Node { const n = 4 nodes := make([]graph.Node, n) for i := range nodes { nodes[i] = node(i) } return nodes }(), edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i; j < n; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique - double(non-prepared)", edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ edges = append(edges, line{F: node(j), T: node(i), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique+ - double(non-prepared)", edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i; j < n; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ edges = append(edges, line{F: node(j), T: node(i), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique - double(prepared)", nodes: func() []graph.Node { const n = 4 nodes := make([]graph.Node, n) for i := range nodes { nodes[i] = node(i) } return nodes }(), edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ edges = append(edges, line{F: node(j), T: node(i), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "4-clique+ - double(prepared)", nodes: func() []graph.Node { const n = 4 nodes := make([]graph.Node, n) for i := range nodes { nodes[i] = node(i) } return nodes }(), edges: func() []WeightedLine { const n = 4 var uid int64 var edges []WeightedLine for i := 0; i < n; i++ { for j := i; j < n; j++ { edges = append(edges, line{F: node(i), T: node(j), UID: uid, W: 0.5}) uid++ edges = append(edges, line{F: node(j), T: node(i), UID: uid, W: 0.5}) uid++ } } return edges }(), nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, { name: "issue 1686", nodes: []graph.Node{node(0), node(1), node(2)}, edges: []WeightedLine{ line{F: node(0), T: node(1), UID: 0, W: 0.5}, line{F: node(1), T: node(2), UID: 0, W: 0.5}, }, nonexist: []graph.Node{node(-1), node(4)}, self: 0, absent: math.Inf(1), }, } golang-gonum-v1-gonum-0.14.0/graph/testgraph/testgraph.go000066400000000000000000002062131450372207100232740ustar00rootroot00000000000000// 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 testgraph provides a set of testing helper functions // that test Gonum graph interface implementations. package testgraph // import "gonum.org/v1/gonum/graph/testgraph" import ( "fmt" "reflect" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/mat" ) // BUG(kortschak): Edge equality is tested in part with reflect.DeepEqual and // direct equality of weight values. This means that edges returned by graphs // must not contain NaN values. Weights returned by the Weight method are // compared with NaN-awareness, so they may be NaN when there is no edge // associated with the Weight call. func isValidIterator(it graph.Iterator) bool { return it != nil } func checkEmptyIterator(t *testing.T, it graph.Iterator, useEmpty bool) { t.Helper() if it.Len() != 0 { return } if it != graph.Empty { if useEmpty { t.Errorf("unexpected empty iterator: got:%T", it) return } // Only log this since we say that a graph should // return a graph.Empty when it is empty. t.Logf("unexpected empty iterator: got:%T", it) } } func hasEnds(x, y graph.Node, e Edge) bool { return (e.From().ID() == x.ID() && e.To().ID() == y.ID()) || (e.From().ID() == y.ID() && e.To().ID() == x.ID()) } // Edge supports basic edge operations. type Edge interface { // From returns the from node of the edge. From() graph.Node // To returns the to node of the edge. To() graph.Node } // WeightedLine is a generalized graph edge that supports all graph // edge operations except reversal. type WeightedLine interface { Edge // ID returns the unique ID for the Line. ID() int64 // Weight returns the weight of the edge. Weight() float64 } // A Builder function returns a graph constructed from the nodes, edges and // default weights passed in, potentially altering the nodes and edges to // conform to the requirements of the graph. The graph is returned along with // the nodes, edges and default weights used to construct the graph. // The returned edges may be any of graph.Edge, graph.WeightedEdge, graph.Line // or graph.WeightedLine depending on what the graph requires. // The client may skip a test case by returning ok=false when the input is not // a valid graph construction. type Builder func(nodes []graph.Node, edges []WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []Edge, s, a float64, ok bool) // edgeLister is a graph that can return all its edges. type edgeLister interface { // Edges returns all the edges of a graph. Edges() graph.Edges } // weightedEdgeLister is a graph that can return all its weighted edges. type weightedEdgeLister interface { // WeightedEdges returns all the weighted edges of a graph. WeightedEdges() graph.WeightedEdges } // matrixer is a graph that can return an adjacency matrix. type matrixer interface { // Matrix returns the graph's adjacency matrix. Matrix() mat.Matrix } // ReturnAllNodes tests the constructed graph for the ability to return all // the nodes it claims it has used in its construction. This is a check of // the Nodes method of graph.Graph and the iterator that is returned. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnAllNodes(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } it := g.Nodes() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) var got []graph.Node for it.Next() { got = append(got, it.Node()) } ordered.ByID(got) ordered.ByID(want) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected nodes result for test %q:\ngot: %v\nwant:%v", test.name, got, want) } } } // ReturnNodeSlice tests the constructed graph for the ability to return all // the nodes it claims it has used in its construction using the NodeSlicer // interface. This is a check of the Nodes method of graph.Graph and the // iterator that is returned. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnNodeSlice(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } it := g.Nodes() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) if it == nil { continue } s, ok := it.(graph.NodeSlicer) if !ok { t.Errorf("invalid type for test %q: %T cannot return node slicer", test.name, g) continue } got := s.NodeSlice() ordered.ByID(got) ordered.ByID(want) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected nodes result for test %q:\ngot: %v\nwant:%v", test.name, got, want) } } } // NodeExistence tests the constructed graph for the ability to correctly // return the existence of nodes within the graph. This is a check of the // Node method of graph.Graph. func NodeExistence(t *testing.T, b Builder) { for _, test := range testCases { g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } seen := set.NewNodes() for _, exist := range want { seen.Add(exist) if g.Node(exist.ID()) == nil { t.Errorf("missing node for test %q: %v", test.name, exist) } } for _, ghost := range test.nonexist { if g.Node(ghost.ID()) != nil { if seen.Has(ghost) { // Do not fail nodes that the graph builder says can exist // even if the test case input thinks they should not. t.Logf("builder has modified non-exist node set: %v is now allowed and present", ghost) continue } t.Errorf("unexpected node for test %q: %v", test.name, ghost) } } } } // ReturnAllEdges tests the constructed graph for the ability to return all // the edges it claims it has used in its construction. This is a check of // the Edges method of graph.Graph and the iterator that is returned. // ReturnAllEdges also checks that the edge end nodes exist within the graph, // checking the Node method of graph.Graph. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnAllEdges(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } var got []Edge switch eg := g.(type) { case edgeLister: it := eg.Edges() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for it.Next() { e := it.Edge() got = append(got, e) qe := g.Edge(e.From().ID(), e.To().ID()) if qe == nil { t.Errorf("missing edge for test %q: %v", test.name, e) } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, e.From().ID(), e.To().ID(), qe) } if g.Node(e.From().ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) } if g.Node(e.To().ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) } } default: t.Errorf("invalid type for test %q: %T cannot return edge iterator", test.name, g) continue } checkEdges(t, test.name, g, got, want) } } // ReturnEdgeSlice tests the constructed graph for the ability to return all // the edges it claims it has used in its construction using the EdgeSlicer // interface. This is a check of the Edges method of graph.Graph and the // iterator that is returned. ReturnEdgeSlice also checks that the edge end // nodes exist within the graph, checking the Node method of graph.Graph. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnEdgeSlice(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } var got []Edge switch eg := g.(type) { case edgeLister: it := eg.Edges() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) if it == nil { continue } s, ok := it.(graph.EdgeSlicer) if !ok { t.Errorf("invalid type for test %q: %T cannot return edge slicer", test.name, g) continue } gotNative := s.EdgeSlice() if len(gotNative) != 0 { got = make([]Edge, len(gotNative)) } for i, e := range gotNative { got[i] = e qe := g.Edge(e.From().ID(), e.To().ID()) if qe == nil { t.Errorf("missing edge for test %q: %v", test.name, e) } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, e.From().ID(), e.To().ID(), qe) } if g.Node(e.From().ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) } if g.Node(e.To().ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) } } default: t.Errorf("invalid type for test %T: cannot return edge iterator", g) continue } checkEdges(t, test.name, g, got, want) } } // ReturnAllLines tests the constructed graph for the ability to return all // the edges it claims it has used in its construction and then recover all // the lines that contribute to those edges. This is a check of the Edges // method of graph.Graph and the iterator that is returned and the graph.Lines // implementation of those edges. ReturnAllLines also checks that the edge // end nodes exist within the graph, checking the Node method of graph.Graph. // // The edges used within and returned by the Builder function should be // graph.Line. The edge parameter passed to b will contain only graph.Line. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnAllLines(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } var got []Edge switch eg := g.(type) { case edgeLister: it := eg.Edges() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for _, e := range graph.EdgesOf(it) { qe := g.Edge(e.From().ID(), e.To().ID()) if qe == nil { t.Errorf("missing edge for test %q: %v", test.name, e) } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, e.From().ID(), e.To().ID(), qe) } // FIXME(kortschak): This would not be necessary // if graph.WeightedLines (and by symmetry) // graph.WeightedEdges also were graph.Lines // and graph.Edges. switch lit := e.(type) { case graph.Lines: if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) for lit.Next() { got = append(got, lit.Line()) } case graph.WeightedLines: if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) for lit.Next() { got = append(got, lit.WeightedLine()) } default: continue } if g.Node(e.From().ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) } if g.Node(e.To().ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) } } default: t.Errorf("invalid type for test: %T cannot return edge iterator", g) continue } checkEdges(t, test.name, g, got, want) } } // ReturnAllWeightedEdges tests the constructed graph for the ability to return // all the edges it claims it has used in its construction. This is a check of // the Edges method of graph.Graph and the iterator that is returned. // ReturnAllWeightedEdges also checks that the edge end nodes exist within the // graph, checking the Node method of graph.Graph. // // The edges used within and returned by the Builder function should be // graph.WeightedEdge. The edge parameter passed to b will contain only // graph.WeightedEdge. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnAllWeightedEdges(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } var got []Edge switch eg := g.(type) { case weightedEdgeLister: it := eg.WeightedEdges() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for it.Next() { e := it.WeightedEdge() got = append(got, e) switch g := g.(type) { case graph.Weighted: qe := g.WeightedEdge(e.From().ID(), e.To().ID()) if qe == nil { t.Errorf("missing edge for test %q: %v", test.name, e) } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, e.From().ID(), e.To().ID(), qe) } default: t.Logf("weighted edge lister is not a weighted graph - are you sure?: %T", g) qe := g.Edge(e.From().ID(), e.To().ID()) if qe == nil { t.Errorf("missing edge for test %q: %v", test.name, e) } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, e.From().ID(), e.To().ID(), qe) } } if g.Node(e.From().ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) } if g.Node(e.To().ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) } } default: t.Errorf("invalid type for test: %T cannot return weighted edge iterator", g) continue } checkEdges(t, test.name, g, got, want) } } // ReturnWeightedEdgeSlice tests the constructed graph for the ability to // return all the edges it claims it has used in its construction using the // WeightedEdgeSlicer interface. This is a check of the Edges method of // graph.Graph and the iterator that is returned. ReturnWeightedEdgeSlice // also checks that the edge end nodes exist within the graph, checking // the Node method of graph.Graph. // // The edges used within and returned by the Builder function should be // graph.WeightedEdge. The edge parameter passed to b will contain only // graph.WeightedEdge. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnWeightedEdgeSlice(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } var got []Edge switch eg := g.(type) { case weightedEdgeLister: it := eg.WeightedEdges() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) s, ok := it.(graph.WeightedEdgeSlicer) if !ok { t.Errorf("invalid type for test %T: cannot return weighted edge slice", g) continue } for _, e := range s.WeightedEdgeSlice() { got = append(got, e) qe := g.Edge(e.From().ID(), e.To().ID()) if qe == nil { t.Errorf("missing edge for test %q: %v", test.name, e) } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, e.From().ID(), e.To().ID(), qe) } if g.Node(e.From().ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) } if g.Node(e.To().ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) } } default: t.Errorf("invalid type for test: %T cannot return weighted edge iterator", g) continue } checkEdges(t, test.name, g, got, want) } } // ReturnAllWeightedLines tests the constructed graph for the ability to return // all the edges it claims it has used in its construction and then recover all // the lines that contribute to those edges. This is a check of the Edges // method of graph.Graph and the iterator that is returned and the graph.Lines // implementation of those edges. ReturnAllWeightedLines also checks that the // edge end nodes exist within the graph, checking the Node method of // graph.Graph. // // The edges used within and returned by the Builder function should be // graph.WeightedLine. The edge parameter passed to b will contain only // graph.WeightedLine. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. func ReturnAllWeightedLines(t *testing.T, b Builder, useEmpty bool) { for _, test := range testCases { g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } var got []Edge switch eg := g.(type) { case weightedEdgeLister: it := eg.WeightedEdges() if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for _, e := range graph.WeightedEdgesOf(it) { qe := g.Edge(e.From().ID(), e.To().ID()) if qe == nil { t.Errorf("missing edge for test %q: %v", test.name, e) } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, e.From().ID(), e.To().ID(), qe) } // FIXME(kortschak): This would not be necessary // if graph.WeightedLines (and by symmetry) // graph.WeightedEdges also were graph.Lines // and graph.Edges. switch lit := e.(type) { case graph.Lines: if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) for lit.Next() { got = append(got, lit.Line()) } case graph.WeightedLines: if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) for lit.Next() { got = append(got, lit.WeightedLine()) } default: continue } if g.Node(e.From().ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) } if g.Node(e.To().ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) } } default: t.Errorf("invalid type for test: %T cannot return edge iterator", g) continue } checkEdges(t, test.name, g, got, want) } } // checkEdges compares got and want for the given graph type. func checkEdges(t *testing.T, name string, g graph.Graph, got, want []Edge) { t.Helper() switch g.(type) { case graph.Undirected: sort.Sort(lexicalUndirectedEdges(got)) sort.Sort(lexicalUndirectedEdges(want)) if !undirectedEdgeSetEqual(got, want) { t.Errorf("unexpected edges result for test %q:\ngot: %#v\nwant:%#v", name, got, want) } default: sort.Sort(lexicalEdges(got)) sort.Sort(lexicalEdges(want)) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected edges result for test %q:\ngot: %#v\nwant:%#v", name, got, want) } } } // EdgeExistence tests the constructed graph for the ability to correctly // return the existence of edges within the graph. This is a check of the // Edge methods of graph.Graph, the EdgeBetween method of graph.Undirected // and the EdgeFromTo method of graph.Directed. EdgeExistence also checks // that the nodes and traversed edges exist within the graph, checking the // Node, Edge, EdgeBetween and HasEdgeBetween methods of graph.Graph, the // EdgeBetween method of graph.Undirected and the HasEdgeFromTo method of // graph.Directed. If reversedEdge is true, edges will be checked to make // sure edges returned match the orientation of an Edge or WeightedEdge // call. func EdgeExistence(t *testing.T, b Builder, reversedEdge bool) { for _, test := range testCases { g, nodes, edges, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } want := make(map[edge]bool) for _, e := range edges { want[edge{f: e.From().ID(), t: e.To().ID()}] = true } for _, x := range nodes { for _, y := range nodes { between := want[edge{f: x.ID(), t: y.ID()}] || want[edge{f: y.ID(), t: x.ID()}] if has := g.HasEdgeBetween(x.ID(), y.ID()); has != between { if has { t.Errorf("unexpected edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } } else { if want[edge{f: x.ID(), t: y.ID()}] { e := g.Edge(x.ID(), y.ID()) if e == nil || !hasEnds(x, y, e) { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else if reversedEdge && (e.From().ID() != x.ID() || e.To().ID() != y.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, x.ID(), y.ID(), e) } } if between && !g.HasEdgeBetween(x.ID(), y.ID()) { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } if g.Node(x.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, x.ID()) } if g.Node(y.ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, y.ID()) } } switch g := g.(type) { case graph.Directed: u := x v := y if has := g.HasEdgeFromTo(u.ID(), v.ID()); has != want[edge{f: u.ID(), t: v.ID()}] { if has { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } else { t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } continue } // Edge has already been tested above. if g.Node(u.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, u.ID()) } if g.Node(v.ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, v.ID()) } case graph.Undirected: // HasEdgeBetween is already tested above. if between && g.Edge(x.ID(), y.ID()) == nil { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } if between && g.EdgeBetween(x.ID(), y.ID()) == nil { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } } switch g := g.(type) { case graph.WeightedDirected: u := x v := y if has := g.WeightedEdge(u.ID(), v.ID()) != nil; has != want[edge{f: u.ID(), t: v.ID()}] { if has { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } else { t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } continue } case graph.WeightedUndirected: // HasEdgeBetween is already tested above. if between && g.WeightedEdge(x.ID(), y.ID()) == nil { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } if between && g.WeightedEdgeBetween(x.ID(), y.ID()) == nil { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } } } } } } // LineExistence tests the constructed graph for the ability to correctly // return the existence of lines within the graph. This is a check of the // Line methods of graph.Multigraph, the EdgeBetween method of graph.Undirected // and the EdgeFromTo method of graph.Directed. LineExistence also checks // that the nodes and traversed edges exist within the graph, checking the // Node, Edge, EdgeBetween and HasEdgeBetween methods of graph.Graph, the // EdgeBetween method of graph.Undirected and the HasEdgeFromTo method of // graph.Directed. If reversedLine is true, lines will be checked to make // sure lines returned match the orientation of an Line or WeightedLine // call. func LineExistence(t *testing.T, b Builder, useEmpty, reversedLine bool) { for _, test := range testCases { g, nodes, edges, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } switch mg := g.(type) { case graph.Multigraph: want := make(map[edge]bool) for _, e := range edges { want[edge{f: e.From().ID(), t: e.To().ID()}] = true } for _, x := range nodes { for _, y := range nodes { between := want[edge{f: x.ID(), t: y.ID()}] || want[edge{f: y.ID(), t: x.ID()}] if has := g.HasEdgeBetween(x.ID(), y.ID()); has != between { if has { t.Errorf("unexpected edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } } else { if want[edge{f: x.ID(), t: y.ID()}] { lit := mg.Lines(x.ID(), y.ID()) if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) if lit.Len() == 0 { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else { for lit.Next() { l := lit.Line() if l == nil || !hasEnds(x, y, l) { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, x.ID(), y.ID(), l) } } } } if between && !g.HasEdgeBetween(x.ID(), y.ID()) { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } if g.Node(x.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, x.ID()) } if g.Node(y.ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, y.ID()) } } switch g := g.(type) { case graph.DirectedMultigraph: u := x v := y if has := g.HasEdgeFromTo(u.ID(), v.ID()); has != want[edge{f: u.ID(), t: v.ID()}] { if has { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } else { t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } continue } // Edge has already been tested above. if g.Node(u.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, u.ID()) } if g.Node(v.ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, v.ID()) } case graph.UndirectedMultigraph: // HasEdgeBetween is already tested above. lit := g.Lines(x.ID(), y.ID()) if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) if between && lit.Len() == 0 { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else { for lit.Next() { l := lit.Line() if l == nil || !hasEnds(x, y, l) { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, x.ID(), y.ID(), l) } } } lit = g.LinesBetween(x.ID(), y.ID()) if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) if between && lit.Len() == 0 { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else { for lit.Next() { l := lit.Line() if l == nil || !hasEnds(x, y, l) { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, x.ID(), y.ID(), l) } } } } switch g := g.(type) { case graph.WeightedDirectedMultigraph: u := x v := y lit := g.WeightedLines(u.ID(), v.ID()) if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) if has := lit != graph.Empty; has != want[edge{f: u.ID(), t: v.ID()}] { if has { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } else { t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } continue } for lit.Next() { l := lit.WeightedLine() if l.From().ID() != x.ID() || l.To().ID() != y.ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, x.ID(), y.ID(), l) } } // Edge has already been tested above. if g.Node(u.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, u.ID()) } if g.Node(v.ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, v.ID()) } case graph.WeightedUndirectedMultigraph: // HasEdgeBetween is already tested above. lit := g.WeightedLines(x.ID(), y.ID()) if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) if between && lit.Len() == 0 { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else { for lit.Next() { l := lit.WeightedLine() if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, x.ID(), y.ID(), l) } } } lit = g.WeightedLinesBetween(x.ID(), y.ID()) if !isValidIterator(lit) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) continue } checkEmptyIterator(t, lit, useEmpty) if between && lit.Len() == 0 { t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } else { for lit.Next() { l := lit.WeightedLine() if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, x.ID(), y.ID(), l) } } } } } } default: t.Errorf("invalid type for test: %T not a multigraph", g) continue } } } // ReturnAdjacentNodes tests the constructed graph for the ability to correctly // return the nodes reachable from each node within the graph. This is a check // of the From method of graph.Graph and the To method of graph.Directed. // ReturnAdjacentNodes also checks that the nodes and traversed edges exist // within the graph, checking the Node, Edge, EdgeBetween and HasEdgeBetween // methods of graph.Graph, the EdgeBetween method of graph.Undirected and the // HasEdgeFromTo method of graph.Directed. // If useEmpty is true, graph iterators will be checked for the use of // graph.Empty if they are empty. If reversedEdge is true, edges will be checked // to make sure edges returned match the orientation of an Edge or WeightedEdge // call. func ReturnAdjacentNodes(t *testing.T, b Builder, useEmpty, reversedEdge bool) { for _, test := range testCases { g, nodes, edges, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } want := make(map[edge]bool) for _, e := range edges { want[edge{f: e.From().ID(), t: e.To().ID()}] = true if g.From(e.From().ID()).Len() == 0 { t.Errorf("missing path from node %v with outbound edge %v", e.From().ID(), e) } } for _, x := range nodes { switch g := g.(type) { case graph.Directed: // Test forward. u := x it := g.From(u.ID()) if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for i := 0; it.Next(); i++ { v := it.Node() if i == 0 && g.Node(u.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, u.ID()) } if g.Node(v.ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, v.ID()) } qe := g.Edge(u.ID(), v.ID()) if qe == nil { t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } else if qe.From().ID() != u.ID() || qe.To().ID() != v.ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, u.ID(), v.ID(), qe) } if !g.HasEdgeBetween(u.ID(), v.ID()) { t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) } if !g.HasEdgeFromTo(u.ID(), v.ID()) { t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } if !want[edge{f: u.ID(), t: v.ID()}] { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } } // Test backward. v := x it = g.To(v.ID()) if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for i := 0; it.Next(); i++ { u := it.Node() if i == 0 && g.Node(v.ID()) == nil { t.Errorf("missing to node for test %q: %v", test.name, v.ID()) } if g.Node(u.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, u.ID()) } qe := g.Edge(u.ID(), v.ID()) if qe == nil { t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) continue } if qe.From().ID() != u.ID() || qe.To().ID() != v.ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, u.ID(), v.ID(), qe) } if !g.HasEdgeBetween(u.ID(), v.ID()) { t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) continue } if !g.HasEdgeFromTo(u.ID(), v.ID()) { t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) continue } if !want[edge{f: u.ID(), t: v.ID()}] { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } } for _, e := range edges { if g.To(e.To().ID()).Len() == 0 { t.Errorf("missing path to node %v with inbound edge %v", e.To().ID(), e) } } case graph.Undirected: u := x it := g.From(u.ID()) if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for i := 0; it.Next(); i++ { v := it.Node() if i == 0 && g.Node(u.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, u.ID()) } qe := g.Edge(u.ID(), v.ID()) if qe == nil || !hasEnds(u, v, qe) { t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) continue } if reversedEdge && (qe.From().ID() != u.ID() || qe.To().ID() != v.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, u.ID(), v.ID(), qe) } qe = g.EdgeBetween(u.ID(), v.ID()) if qe == nil || !hasEnds(u, v, qe) { t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) continue } if reversedEdge && (qe.From().ID() != u.ID() || qe.To().ID() != v.ID()) { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, u.ID(), v.ID(), qe) } if !g.HasEdgeBetween(u.ID(), v.ID()) { t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) continue } between := want[edge{f: u.ID(), t: v.ID()}] || want[edge{f: v.ID(), t: u.ID()}] if !between { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } } default: u := x it := g.From(u.ID()) if !isValidIterator(it) { t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) continue } checkEmptyIterator(t, it, useEmpty) for i := 0; it.Next(); i++ { v := it.Node() if i == 0 && g.Node(u.ID()) == nil { t.Errorf("missing from node for test %q: %v", test.name, u.ID()) } qe := g.Edge(u.ID(), v.ID()) if qe == nil { t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) continue } if qe.From().ID() != u.ID() || qe.To().ID() != v.ID() { t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", test.name, u.ID(), v.ID(), qe) } if !g.HasEdgeBetween(u.ID(), v.ID()) { t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) continue } between := want[edge{f: u.ID(), t: v.ID()}] || want[edge{f: v.ID(), t: u.ID()}] if !between { t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) } } } } } } // Weight tests the constructed graph for the ability to correctly return // the weight between to nodes, checking the Weight method of graph.Weighted. // // The self and absent values returned by the Builder should match the values // used by the Weight method. func Weight(t *testing.T, b Builder) { for _, test := range testCases { g, nodes, _, self, absent, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } wg, ok := g.(graph.Weighted) if !ok { t.Errorf("invalid graph type for test %q: %T is not graph.Weighted", test.name, g) } _, multi := g.(graph.Multigraph) for _, x := range nodes { for _, y := range nodes { w, ok := wg.Weight(x.ID(), y.ID()) e := wg.WeightedEdge(x.ID(), y.ID()) switch { case !ok: if e != nil { t.Errorf("missing edge weight for existing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) } if !scalar.Same(w, absent) { t.Errorf("unexpected absent weight for test %q: got:%v want:%v", test.name, w, absent) } case !multi && x.ID() == y.ID(): if !scalar.Same(w, self) { t.Errorf("unexpected self weight for test %q: got:%v want:%v", test.name, w, self) } case e == nil: t.Errorf("missing edge for existing non-self weight for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) case e.Weight() != w: t.Errorf("weight mismatch for test %q: edge=%v graph=%v", test.name, e.Weight(), w) } } } } } // AdjacencyMatrix tests the constructed graph for the ability to correctly // return an adjacency matrix that matches the weights returned by the graphs // Weight method. // // The self and absent values returned by the Builder should match the values // used by the Weight method. func AdjacencyMatrix(t *testing.T, b Builder) { for _, test := range testCases { g, nodes, _, self, absent, ok := b(test.nodes, test.edges, test.self, test.absent) if !ok { t.Logf("skipping test case: %q", test.name) continue } wg, ok := g.(graph.Weighted) if !ok { t.Errorf("invalid graph type for test %q: %T is not graph.Weighted", test.name, g) } mg, ok := g.(matrixer) if !ok { t.Errorf("invalid graph type for test %q: %T cannot return adjacency matrix", test.name, g) } m := mg.Matrix() r, c := m.Dims() if r != c || r != len(nodes) { t.Errorf("dimension mismatch for test %q: r=%d c=%d order=%d", test.name, r, c, len(nodes)) } for _, x := range nodes { i := int(x.ID()) for _, y := range nodes { j := int(y.ID()) w, ok := wg.Weight(x.ID(), y.ID()) switch { case !ok: if !scalar.Same(m.At(i, j), absent) { t.Errorf("weight mismatch for test %q: (%v)--(%v) matrix=%v graph=%v", test.name, x.ID(), y.ID(), m.At(i, j), w) } case x.ID() == y.ID(): if !scalar.Same(m.At(i, j), self) { t.Errorf("weight mismatch for test %q: (%v)--(%v) matrix=%v graph=%v", test.name, x.ID(), y.ID(), m.At(i, j), w) } default: if !scalar.Same(m.At(i, j), w) { t.Errorf("weight mismatch for test %q: (%v)--(%v) matrix=%v graph=%v", test.name, x.ID(), y.ID(), m.At(i, j), w) } } } } } } // lexicalEdges sorts a collection of edges lexically on the // keys: from.ID > to.ID > [line.ID] > [weight]. type lexicalEdges []Edge func (e lexicalEdges) Len() int { return len(e) } func (e lexicalEdges) Less(i, j int) bool { if e[i].From().ID() < e[j].From().ID() { return true } sf := e[i].From().ID() == e[j].From().ID() if sf && e[i].To().ID() < e[j].To().ID() { return true } st := e[i].To().ID() == e[j].To().ID() li, oki := e[i].(graph.Line) lj, okj := e[j].(graph.Line) if oki != okj { panic(fmt.Sprintf("testgraph: mismatched types %T != %T", e[i], e[j])) } if !oki { return sf && st && lessWeight(e[i], e[j]) } if sf && st && li.ID() < lj.ID() { return true } return sf && st && li.ID() == lj.ID() && lessWeight(e[i], e[j]) } func (e lexicalEdges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } // lexicalUndirectedEdges sorts a collection of edges lexically on the // keys: lo.ID > hi.ID > [line.ID] > [weight]. type lexicalUndirectedEdges []Edge func (e lexicalUndirectedEdges) Len() int { return len(e) } func (e lexicalUndirectedEdges) Less(i, j int) bool { lidi, hidi, _ := undirectedIDs(e[i]) lidj, hidj, _ := undirectedIDs(e[j]) if lidi < lidj { return true } sl := lidi == lidj if sl && hidi < hidj { return true } sh := hidi == hidj li, oki := e[i].(graph.Line) lj, okj := e[j].(graph.Line) if oki != okj { panic(fmt.Sprintf("testgraph: mismatched types %T != %T", e[i], e[j])) } if !oki { return sl && sh && lessWeight(e[i], e[j]) } if sl && sh && li.ID() < lj.ID() { return true } return sl && sh && li.ID() == lj.ID() && lessWeight(e[i], e[j]) } func (e lexicalUndirectedEdges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } func lessWeight(ei, ej Edge) bool { wei, oki := ei.(graph.WeightedEdge) wej, okj := ej.(graph.WeightedEdge) if oki != okj { panic(fmt.Sprintf("testgraph: mismatched types %T != %T", ei, ej)) } if !oki { return false } return wei.Weight() < wej.Weight() } // undirectedEdgeSetEqual returned whether a pair of undirected edge // slices sorted by lexicalUndirectedEdges are equal. func undirectedEdgeSetEqual(a, b []Edge) bool { if len(a) == 0 && len(b) == 0 { return true } if len(a) == 0 || len(b) == 0 { return false } if !undirectedEdgeEqual(a[0], b[0]) { return false } i, j := 0, 0 for { switch { case i == len(a)-1 && j == len(b)-1: return true case i < len(a)-1 && undirectedEdgeEqual(a[i+1], b[j]): i++ case j < len(b)-1 && undirectedEdgeEqual(a[i], b[j+1]): j++ case i < len(a)-1 && j < len(b)-1 && undirectedEdgeEqual(a[i+1], b[j+1]): i++ j++ default: return false } } } // undirectedEdgeEqual returns whether a pair of undirected edges are equal // after canonicalising from and to IDs by numerical sort order. func undirectedEdgeEqual(a, b Edge) bool { loa, hia, inva := undirectedIDs(a) lob, hib, invb := undirectedIDs(b) // Use reflect.DeepEqual if the edges are parallel // rather anti-parallel. if inva == invb { return reflect.DeepEqual(a, b) } if loa != lob || hia != hib { return false } la, oka := a.(graph.Line) lb, okb := b.(graph.Line) if !oka && !okb { return true } if la.ID() != lb.ID() { return false } wea, oka := a.(graph.WeightedEdge) web, okb := b.(graph.WeightedEdge) if !oka && !okb { return true } return wea.Weight() == web.Weight() } // NodeAdder is a graph.NodeAdder graph. type NodeAdder interface { graph.Graph graph.NodeAdder } // AddNodes tests whether g correctly implements the graph.NodeAdder interface. // AddNodes gets a new node from g and adds it to the graph, repeating this pair // of operations n times. The existence of added nodes is confirmed in the graph. // AddNodes also checks that re-adding each of the added nodes causes a panic. // If g satisfies NodeWithIDer, the NodeWithID method is tested for an additional // n rounds of node addition using NodeWithID to create new nodes as well as // confirming that NodeWithID returns existing nodes. func AddNodes(t *testing.T, g NodeAdder, n int) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() var addedNodes []graph.Node for i := 0; i < n; i++ { node := g.NewNode() prev := len(graph.NodesOf(g.Nodes())) if g.Node(node.ID()) != nil { curr := g.Nodes().Len() if curr != prev { t.Fatalf("NewNode mutated graph: prev graph order != curr graph order, %d != %d", prev, curr) } t.Fatalf("NewNode returned existing: %#v", node) } g.AddNode(node) addedNodes = append(addedNodes, node) curr := len(graph.NodesOf(g.Nodes())) if curr != prev+1 { t.Fatalf("AddNode failed to mutate graph: curr graph order != prev graph order+1, %d != %d", curr, prev+1) } if g.Node(node.ID()) == nil { t.Fatalf("AddNode failed to add node to graph trying to add %#v", node) } } ordered.ByID(addedNodes) graphNodes := graph.NodesOf(g.Nodes()) ordered.ByID(graphNodes) if !reflect.DeepEqual(addedNodes, graphNodes) { if n > 20 { t.Errorf("unexpected node set after node addition: got len:%v want len:%v", len(graphNodes), len(addedNodes)) } else { t.Errorf("unexpected node set after node addition: got:\n %v\nwant:\n%v", graphNodes, addedNodes) } } it := g.Nodes() for it.Next() { panicked := panics(func() { g.AddNode(it.Node()) }) if !panicked { t.Fatalf("expected panic adding existing node: %v", it.Node()) } } if gwi, ok := g.(graph.NodeWithIDer); ok { // Test existing nodes. it := g.Nodes() for it.Next() { id := it.Node().ID() n, new := gwi.NodeWithID(id) if n == nil { t.Errorf("unexpected nil node for existing node with ID=%d", id) } if new { t.Errorf("unexpected new node for existing node with ID=%d", id) } } // Run n rounds of ID-specified node addition. for i := 0; i < n; i++ { id := g.NewNode().ID() // Get a guaranteed non-existing node. n, new := gwi.NodeWithID(id) if n == nil { // Could not create a node, valid behaviour. continue } if !new { t.Errorf("unexpected old node for non-existing node with ID=%d", id) } g.AddNode(n) // Use the node to advance to a new non-existing node. } } } // AddArbitraryNodes tests whether g correctly implements the AddNode method. Not all // graph.NodeAdder graphs are expected to implement the semantics of this test. // AddArbitraryNodes iterates over add, adding each node to the graph. The existence // of each added node in the graph is confirmed. func AddArbitraryNodes(t *testing.T, g NodeAdder, add graph.Nodes) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() for add.Next() { node := add.Node() prev := len(graph.NodesOf(g.Nodes())) g.AddNode(node) curr := len(graph.NodesOf(g.Nodes())) if curr != prev+1 { t.Fatalf("AddNode failed to mutate graph: curr graph order != prev graph order+1, %d != %d", curr, prev+1) } if g.Node(node.ID()) == nil { t.Fatalf("AddNode failed to add node to graph trying to add %#v", node) } } add.Reset() addedNodes := graph.NodesOf(add) ordered.ByID(addedNodes) graphNodes := graph.NodesOf(g.Nodes()) ordered.ByID(graphNodes) if !reflect.DeepEqual(addedNodes, graphNodes) { t.Errorf("unexpected node set after node addition: got:\n %v\nwant:\n%v", graphNodes, addedNodes) } it := g.Nodes() for it.Next() { panicked := panics(func() { g.AddNode(it.Node()) }) if !panicked { t.Fatalf("expected panic adding existing node: %v", it.Node()) } } } // NodeRemover is a graph.NodeRemover graph. type NodeRemover interface { graph.Graph graph.NodeRemover } // RemoveNodes tests whether g correctly implements the graph.NodeRemover interface. // The input graph g must contain a set of nodes with some edges between them. func RemoveNodes(t *testing.T, g NodeRemover) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() it := g.Nodes() first := true for it.Next() { u := it.Node() seen := make(map[edge]struct{}) // Collect all incident edges. var incident []graph.Edge to := g.From(u.ID()) for to.Next() { v := to.Node() e := g.Edge(u.ID(), v.ID()) if e == nil { t.Fatalf("bad graph: neighbors not connected: u=%#v v=%#v", u, v) } if _, ok := g.(graph.Undirected); ok { seen[edge{f: e.To().ID(), t: e.From().ID()}] = struct{}{} } seen[edge{f: e.From().ID(), t: e.To().ID()}] = struct{}{} incident = append(incident, e) } // Collect all other edges. var others []graph.Edge currit := g.Nodes() for currit.Next() { u := currit.Node() to := g.From(u.ID()) for to.Next() { v := to.Node() e := g.Edge(u.ID(), v.ID()) if e == nil { t.Fatalf("bad graph: neighbors not connected: u=%#v v=%#v", u, v) } seen[edge{f: e.From().ID(), t: e.To().ID()}] = struct{}{} others = append(others, e) } } if first && len(seen) == 0 { t.Fatal("incomplete test: no edges in graph") } first = false prev := len(graph.NodesOf(g.Nodes())) g.RemoveNode(u.ID()) curr := len(graph.NodesOf(g.Nodes())) if curr != prev-1 { t.Fatalf("RemoveNode failed to mutate graph: curr graph order != prev graph order-1, %d != %d", curr, prev-1) } if g.Node(u.ID()) != nil { t.Fatalf("failed to remove node: %#v", u) } for _, e := range incident { if g.HasEdgeBetween(e.From().ID(), e.To().ID()) { t.Fatalf("RemoveNode failed to remove connected edge: %#v", e) } } for _, e := range others { if e.From().ID() == u.ID() || e.To().ID() == u.ID() { continue } if g.Edge(e.From().ID(), e.To().ID()) == nil { t.Fatalf("RemoveNode %v removed unconnected edge: %#v", u, e) } } } } // EdgeAdder is a graph.EdgeAdder graph. type EdgeAdder interface { graph.Graph graph.EdgeAdder } // AddEdges tests whether g correctly implements the graph.EdgeAdder interface. // AddEdges creates n pairs of nodes with random IDs in [0,n) and joins edges // each node in the pair using SetEdge. AddEdges confirms that the end point // nodes are added to the graph and that the edges are stored in the graph. // If canLoop is true, self edges may be created. If canSet is true, a second // call to SetEdge is made for each edge to confirm that the nodes corresponding // the end points are updated. func AddEdges(t *testing.T, n int, g EdgeAdder, newNode func(id int64) graph.Node, canLoop, canSetNode bool) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() type altNode struct { graph.Node } rnd := rand.New(rand.NewSource(1)) for i := 0; i < n; i++ { u := newNode(rnd.Int63n(int64(n))) var v graph.Node for { v = newNode(rnd.Int63n(int64(n))) if canLoop || u.ID() != v.ID() { break } } e := g.NewEdge(u, v) if g.Edge(u.ID(), v.ID()) != nil { t.Fatalf("NewEdge returned existing: %#v", e) } g.SetEdge(e) if g.Edge(u.ID(), v.ID()) == nil { t.Fatalf("SetEdge failed to add edge: %#v", e) } if g.Node(u.ID()) == nil { t.Fatalf("SetEdge failed to add from node: %#v", u) } if g.Node(v.ID()) == nil { t.Fatalf("SetEdge failed to add to node: %#v", v) } if !canSetNode { continue } g.SetEdge(g.NewEdge(altNode{u}, altNode{v})) if nu := g.Node(u.ID()); nu == u { t.Fatalf("SetEdge failed to update from node: u=%#v nu=%#v", u, nu) } if nv := g.Node(v.ID()); nv == v { t.Fatalf("SetEdge failed to update to node: v=%#v nv=%#v", v, nv) } } } // WeightedEdgeAdder is a graph.EdgeAdder graph. type WeightedEdgeAdder interface { graph.Graph graph.WeightedEdgeAdder } // AddWeightedEdges tests whether g correctly implements the graph.WeightedEdgeAdder // interface. AddWeightedEdges creates n pairs of nodes with random IDs in [0,n) and // joins edges each node in the pair using SetWeightedEdge with weight w. // AddWeightedEdges confirms that the end point nodes are added to the graph and that // the edges are stored in the graph. If canLoop is true, self edges may be created. // If canSet is true, a second call to SetWeightedEdge is made for each edge to // confirm that the nodes corresponding the end points are updated. func AddWeightedEdges(t *testing.T, n int, g WeightedEdgeAdder, w float64, newNode func(id int64) graph.Node, canLoop, canSetNode bool) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() type altNode struct { graph.Node } rnd := rand.New(rand.NewSource(1)) for i := 0; i < n; i++ { u := newNode(rnd.Int63n(int64(n))) var v graph.Node for { v = newNode(rnd.Int63n(int64(n))) if canLoop || u.ID() != v.ID() { break } } e := g.NewWeightedEdge(u, v, w) if g.Edge(u.ID(), v.ID()) != nil { t.Fatalf("NewEdge returned existing: %#v", e) } g.SetWeightedEdge(e) ne := g.Edge(u.ID(), v.ID()) if ne == nil { t.Fatalf("SetWeightedEdge failed to add edge: %#v", e) } we, ok := ne.(graph.WeightedEdge) if !ok { t.Fatalf("SetWeightedEdge failed to add weighted edge: %#v", e) } if we.Weight() != w { t.Fatalf("edge weight mismatch: got:%f want:%f", we.Weight(), w) } if g.Node(u.ID()) == nil { t.Fatalf("SetWeightedEdge failed to add from node: %#v", u) } if g.Node(v.ID()) == nil { t.Fatalf("SetWeightedEdge failed to add to node: %#v", v) } if !canSetNode { continue } g.SetWeightedEdge(g.NewWeightedEdge(altNode{u}, altNode{v}, w)) if nu := g.Node(u.ID()); nu == u { t.Fatalf("SetWeightedEdge failed to update from node: u=%#v nu=%#v", u, nu) } if nv := g.Node(v.ID()); nv == v { t.Fatalf("SetWeightedEdge failed to update to node: v=%#v nv=%#v", v, nv) } } } // NoLoopAddEdges tests whether g panics for self-loop addition. NoLoopAddEdges // adds n nodes with IDs in [0,n) and creates an edge from the graph with NewEdge. // NoLoopAddEdges confirms that this does not panic and then adds the edge to the // graph to ensure that SetEdge will panic when adding a self-loop. func NoLoopAddEdges(t *testing.T, n int, g EdgeAdder, newNode func(id int64) graph.Node) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() for id := 0; id < n; id++ { node := newNode(int64(id)) e := g.NewEdge(node, node) panicked := panics(func() { g.SetEdge(e) }) if !panicked { t.Errorf("expected panic for self-edge: %#v", e) } } } // NoLoopAddWeightedEdges tests whether g panics for self-loop addition. NoLoopAddWeightedEdges // adds n nodes with IDs in [0,n) and creates an edge from the graph with NewWeightedEdge. // NoLoopAddWeightedEdges confirms that this does not panic and then adds the edge to the // graph to ensure that SetWeightedEdge will panic when adding a self-loop. func NoLoopAddWeightedEdges(t *testing.T, n int, g WeightedEdgeAdder, w float64, newNode func(id int64) graph.Node) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() for id := 0; id < n; id++ { node := newNode(int64(id)) e := g.NewWeightedEdge(node, node, w) panicked := panics(func() { g.SetWeightedEdge(e) }) if !panicked { t.Errorf("expected panic for self-edge: %#v", e) } } } // LineAdder is a graph.LineAdder multigraph. type LineAdder interface { graph.Multigraph graph.LineAdder } // AddLines tests whether g correctly implements the graph.LineAdder interface. // AddLines creates n pairs of nodes with random IDs in [0,n) and joins edges // each node in the pair using SetLine. AddLines confirms that the end point // nodes are added to the graph and that the edges are stored in the graph. // If canSet is true, a second call to SetLine is made for each edge to confirm // that the nodes corresponding the end points are updated. func AddLines(t *testing.T, n int, g LineAdder, newNode func(id int64) graph.Node, canSetNode bool) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() type altNode struct { graph.Node } rnd := rand.New(rand.NewSource(1)) seen := make(tripleInt64s) for i := 0; i < n; i++ { u := newNode(rnd.Int63n(int64(n))) v := newNode(rnd.Int63n(int64(n))) prev := g.Lines(u.ID(), v.ID()) l := g.NewLine(u, v) if seen.has(u.ID(), v.ID(), l.ID()) { t.Fatalf("NewLine returned an existing line: %#v", l) } if g.Lines(u.ID(), v.ID()).Len() != prev.Len() { t.Fatalf("NewLine added a line: %#v", l) } g.SetLine(l) seen.add(u.ID(), v.ID(), l.ID()) if g.Lines(u.ID(), v.ID()).Len() != prev.Len()+1 { t.Fatalf("SetLine failed to add line: %#v", l) } if g.Node(u.ID()) == nil { t.Fatalf("SetLine failed to add from node: %#v", u) } if g.Node(v.ID()) == nil { t.Fatalf("SetLine failed to add to node: %#v", v) } if !canSetNode { continue } g.SetLine(g.NewLine(altNode{u}, altNode{v})) if nu := g.Node(u.ID()); nu == u { t.Fatalf("SetLine failed to update from node: u=%#v nu=%#v", u, nu) } if nv := g.Node(v.ID()); nv == v { t.Fatalf("SetLine failed to update to node: v=%#v nv=%#v", v, nv) } } } // WeightedLineAdder is a graph.WeightedLineAdder multigraph. type WeightedLineAdder interface { graph.Multigraph graph.WeightedLineAdder } // AddWeightedLines tests whether g correctly implements the graph.WeightedEdgeAdder // interface. AddWeightedLines creates n pairs of nodes with random IDs in [0,n) and // joins edges each node in the pair using SetWeightedLine with weight w. // AddWeightedLines confirms that the end point nodes are added to the graph and that // the edges are stored in the graph. If canSet is true, a second call to SetWeightedLine // is made for each edge to confirm that the nodes corresponding the end points are // updated. func AddWeightedLines(t *testing.T, n int, g WeightedLineAdder, w float64, newNode func(id int64) graph.Node, canSetNode bool) { defer func() { r := recover() if r != nil { t.Errorf("unexpected panic: %v", r) } }() type altNode struct { graph.Node } rnd := rand.New(rand.NewSource(1)) seen := make(tripleInt64s) for i := 0; i < n; i++ { u := newNode(rnd.Int63n(int64(n))) v := newNode(rnd.Int63n(int64(n))) prev := g.Lines(u.ID(), v.ID()) l := g.NewWeightedLine(u, v, w) if seen.has(u.ID(), v.ID(), l.ID()) { t.Fatalf("NewWeightedLine returned an existing line: %#v", l) } if g.Lines(u.ID(), v.ID()).Len() != prev.Len() { t.Fatalf("NewWeightedLine added a line: %#v", l) } g.SetWeightedLine(l) seen.add(u.ID(), v.ID(), l.ID()) curr := g.Lines(u.ID(), v.ID()) if curr.Len() != prev.Len()+1 { t.Fatalf("SetWeightedLine failed to add line: %#v", l) } var found bool for curr.Next() { if curr.Line().ID() == l.ID() { found = true wl, ok := curr.Line().(graph.WeightedLine) if !ok { t.Fatalf("SetWeightedLine failed to add weighted line: %#v", l) } if wl.Weight() != w { t.Fatalf("line weight mismatch: got:%f want:%f", wl.Weight(), w) } break } } if !found { t.Fatalf("SetWeightedLine failed to add line: %#v", l) } if g.Node(u.ID()) == nil { t.Fatalf("SetWeightedLine failed to add from node: %#v", u) } if g.Node(v.ID()) == nil { t.Fatalf("SetWeightedLine failed to add to node: %#v", v) } if !canSetNode { continue } g.SetWeightedLine(g.NewWeightedLine(altNode{u}, altNode{v}, w)) if nu := g.Node(u.ID()); nu == u { t.Fatalf("SetWeightedLine failed to update from node: u=%#v nu=%#v", u, nu) } if nv := g.Node(v.ID()); nv == v { t.Fatalf("SetWeightedLine failed to update to node: v=%#v nv=%#v", v, nv) } } } // EdgeRemover is a graph.EdgeRemover graph. type EdgeRemover interface { graph.Graph graph.EdgeRemover } // RemoveEdges tests whether g correctly implements the graph.EdgeRemover interface. // The input graph g must contain a set of nodes with some edges between them. // RemoveEdges iterates over remove, which must contain edges in g, removing each // edge. RemoveEdges confirms that the edge is removed, leaving its end-point nodes // and all other edges in the graph. func RemoveEdges(t *testing.T, g EdgeRemover, remove graph.Edges) { edges := make(map[edge]struct{}) nodes := g.Nodes() for nodes.Next() { u := nodes.Node() uid := u.ID() to := g.From(uid) for to.Next() { v := to.Node() edges[edge{f: u.ID(), t: v.ID()}] = struct{}{} } } for remove.Next() { e := remove.Edge() if g.Edge(e.From().ID(), e.To().ID()) == nil { t.Fatalf("bad tests: missing edge: %#v", e) } if g.Node(e.From().ID()) == nil { t.Fatalf("bad tests: missing from node: %#v", e.From()) } if g.Node(e.To().ID()) == nil { t.Fatalf("bad tests: missing to node: %#v", e.To()) } g.RemoveEdge(e.From().ID(), e.To().ID()) if _, ok := g.(graph.Undirected); ok { delete(edges, edge{f: e.To().ID(), t: e.From().ID()}) } delete(edges, edge{f: e.From().ID(), t: e.To().ID()}) for ge := range edges { if g.Edge(ge.f, ge.t) == nil { t.Fatalf("unexpected missing edge after removing edge %#v: %#v", e, ge) } } if ne := g.Edge(e.From().ID(), e.To().ID()); ne != nil { t.Fatalf("expected nil edge: got:%#v", ne) } if g.Node(e.From().ID()) == nil { t.Fatalf("unexpected deletion of from node: %#v", e.From()) } if g.Node(e.To().ID()) == nil { t.Fatalf("unexpected deletion to node: %#v", e.To()) } } } // LineRemover is a graph.EdgeRemove graph. type LineRemover interface { graph.Multigraph graph.LineRemover } // RemoveLines tests whether g correctly implements the graph.LineRemover interface. // The input graph g must contain a set of nodes with some lines between them. // RemoveLines iterates over remove, which must contain lines in g, removing each // line. RemoveLines confirms that the line is removed, leaving its end-point nodes // and all other lines in the graph. func RemoveLines(t *testing.T, g LineRemover, remove graph.Lines) { // lines is the set of lines in the graph. // The presence of a key indicates that the // line should exist in the graph. The value // for each key is used to indicate whether // it has been found during testing. lines := make(map[edge]bool) nodes := g.Nodes() for nodes.Next() { u := nodes.Node() uid := u.ID() to := g.From(uid) for to.Next() { v := to.Node() lit := g.Lines(u.ID(), v.ID()) for lit.Next() { lines[edge{f: u.ID(), t: v.ID(), id: lit.Line().ID()}] = true } } } for remove.Next() { l := remove.Line() if g.Lines(l.From().ID(), l.To().ID()) == graph.Empty { t.Fatalf("bad tests: missing line: %#v", l) } if g.Node(l.From().ID()) == nil { t.Fatalf("bad tests: missing from node: %#v", l.From()) } if g.Node(l.To().ID()) == nil { t.Fatalf("bad tests: missing to node: %#v", l.To()) } prev := g.Lines(l.From().ID(), l.To().ID()) g.RemoveLine(l.From().ID(), l.To().ID(), l.ID()) if _, ok := g.(graph.Undirected); ok { delete(lines, edge{f: l.To().ID(), t: l.From().ID(), id: l.ID()}) } delete(lines, edge{f: l.From().ID(), t: l.To().ID(), id: l.ID()}) // Mark all lines as not found. for gl := range lines { lines[gl] = false } // Mark found lines. This could be done far more efficiently. for gl := range lines { lit := g.Lines(gl.f, gl.t) for lit.Next() { lid := lit.Line().ID() if lid == gl.id { lines[gl] = true break } } } for gl, found := range lines { if !found { t.Fatalf("unexpected missing line after removing line %#v: %#v", l, gl) } } if curr := g.Lines(l.From().ID(), l.To().ID()); curr.Len() != prev.Len()-1 { t.Fatalf("RemoveLine failed to mutate graph: curr edge size != prev edge size-1, %d != %d", curr.Len(), prev.Len()-1) } if g.Node(l.From().ID()) == nil { t.Fatalf("unexpected deletion of from node: %#v", l.From()) } if g.Node(l.To().ID()) == nil { t.Fatalf("unexpected deletion to node: %#v", l.To()) } } } // undirectedIDs returns a numerical sort ordered canonicalisation of the // IDs of e. func undirectedIDs(e Edge) (lo, hi int64, inverted bool) { lid := e.From().ID() hid := e.To().ID() if hid < lid { inverted = true hid, lid = lid, hid } return lid, hid, inverted } type edge struct { f, t, id int64 } func panics(fn func()) (ok bool) { defer func() { ok = recover() != nil }() fn() return } // RandomNodes implements the graph.Nodes interface for a set of random nodes. type RandomNodes struct { n int seed uint64 newNode func(int64) graph.Node curr int64 state *rand.Rand seen set.Int64s count int } var _ graph.Nodes = (*RandomNodes)(nil) // NewRandomNodes returns a new implicit node iterator containing a set of n nodes // with IDs generated from a PRNG seeded by the given seed. // The provided new func maps the id to a graph.Node. func NewRandomNodes(n int, seed uint64, new func(id int64) graph.Node) *RandomNodes { return &RandomNodes{ n: n, seed: seed, newNode: new, state: rand.New(rand.NewSource(seed)), seen: make(set.Int64s), count: 0, } } // Len returns the remaining number of nodes to be iterated over. func (n *RandomNodes) Len() int { return n.n - n.count } // Next returns whether the next call of Node will return a valid node. func (n *RandomNodes) Next() bool { if n.count >= n.n { return false } n.count++ for { sign := int64(1) if n.state.Float64() < 0.5 { sign *= -1 } n.curr = sign * n.state.Int63() if !n.seen.Has(n.curr) { n.seen.Add(n.curr) return true } } } // Node returns the current node of the iterator. Next must have been // called prior to a call to Node. func (n *RandomNodes) Node() graph.Node { if n.Len() == -1 || n.count == 0 { return nil } return n.newNode(n.curr) } // Reset returns the iterator to its initial state. func (n *RandomNodes) Reset() { n.state = rand.New(rand.NewSource(n.seed)) n.seen = make(set.Int64s) n.count = 0 } // tripleInt64s is a set of [3]int64 identifiers. type tripleInt64s map[[3]int64]struct{} // add inserts an element into the set. func (s tripleInt64s) add(x, y, z int64) { s[[3]int64{x, y, z}] = struct{}{} } // has reports the existence of the element in the set. func (s tripleInt64s) has(x, y, z int64) bool { _, ok := s[[3]int64{x, y, z}] return ok } golang-gonum-v1-gonum-0.14.0/graph/testgraph/testgraph_test.go000066400000000000000000000032611450372207100243310ustar00rootroot00000000000000// Copyright ©2019 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 testgraph import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) var randomNodesTests = []struct { n int seed uint64 new func(int64) graph.Node want []graph.Node }{ { n: 0, want: nil, }, { n: 1, seed: 1, new: newSimpleNode, want: []graph.Node{simple.Node(-106976941678315313)}, }, { n: 1, seed: 2, new: newSimpleNode, want: []graph.Node{simple.Node(6816453162648937526)}, }, { n: 4, seed: 1, new: newSimpleNode, want: []graph.Node{ simple.Node(-106976941678315313), simple.Node(867649948573917593), simple.Node(-4246677790793934368), simple.Node(406519965772129914), }, }, { n: 4, seed: 2, new: newSimpleNode, want: []graph.Node{ simple.Node(6816453162648937526), simple.Node(-4921844272880608907), simple.Node(159088832891557680), simple.Node(-2611333848016927708), }, }, } func newSimpleNode(id int64) graph.Node { return simple.Node(id) } func TestRandomNodesIterate(t *testing.T) { for _, test := range randomNodesTests { for i := 0; i < 2; i++ { it := NewRandomNodes(test.n, test.seed, test.new) if it.Len() != len(test.want) { t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.want)) } var got []graph.Node for it.Next() { got = append(got, it.Node()) } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, test.want) } it.Reset() } } } golang-gonum-v1-gonum-0.14.0/graph/topo/000077500000000000000000000000001450372207100177205ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/topo/2sat_example_test.go000066400000000000000000000103111450372207100236660ustar00rootroot00000000000000// 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 topo_test import ( "bufio" "fmt" "io" "log" "sort" "strings" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" ) var systems = []string{ // Unsatisfiable system. `𝑥_a ∨ ¬𝑥_b ¬𝑥_b ∨ 𝑥_f 𝑥_h ∨ 𝑥_i 𝑥_a ∨ 𝑥_b 𝑥_k ∨ 𝑥_c ¬𝑥_f ∨ 𝑥_h 𝑥_c ∨ 𝑥_g 𝑥_f ∨ 𝑥_g 𝑥_h ∨ ¬𝑥_l ¬𝑥_h ∨ 𝑥_i 𝑥_i ∨ 𝑥_b ¬𝑥_i ∨ ¬𝑥_h 𝑥_i ∨ ¬𝑥_c 𝑥_l ∨ 𝑥_d ¬𝑥_j ∨ ¬𝑥_i ¬𝑥_a ∨ ¬𝑥_j ¬𝑥_a ∨ 𝑥_b ¬𝑥_d ∨ 𝑥_e ¬𝑥_k ∨ 𝑥_h 𝑥_l ∨ ¬𝑥_d 𝑥_l ∨ 𝑥_d 𝑥_l ∨ ¬𝑥_f 𝑥_b ∨ 𝑥_d 𝑥_b ∨ ¬𝑥_g 𝑥_d ∨ ¬𝑥_l ¬𝑥_l ∨ ¬𝑥_k `, // Satisfiable system. `𝑥_a ∨ ¬𝑥_b ¬𝑥_b ∨ 𝑥_f 𝑥_h ∨ 𝑥_i 𝑥_a ∨ 𝑥_b 𝑥_k ∨ 𝑥_c ¬𝑥_f ∨ 𝑥_h 𝑥_c ∨ 𝑥_g 𝑥_f ∨ 𝑥_g 𝑥_h ∨ ¬𝑥_l ¬𝑥_h ∨ 𝑥_i 𝑥_i ∨ 𝑥_b ¬𝑥_i ∨ 𝑥_e 𝑥_i ∨ ¬𝑥_c ¬𝑥_g ∨ ¬𝑥_a 𝑥_l ∨ 𝑥_f ¬𝑥_j ∨ ¬𝑥_i ¬𝑥_a ∨ ¬𝑥_j ¬𝑥_a ∨ 𝑥_b ¬𝑥_d ∨ 𝑥_e 𝑥_k ∨ ¬𝑥_a 𝑥_k ∨ 𝑥_h 𝑥_l ∨ ¬𝑥_d 𝑥_l ∨ 𝑥_e 𝑥_l ∨ ¬𝑥_f 𝑥_b ∨ 𝑥_d 𝑥_b ∨ ¬𝑥_g 𝑥_d ∨ ¬𝑥_l 𝑥_l ∨ 𝑥_e `, `fun ∨ ¬fun fun ∨ ¬Gonum Gonum ∨ Gonum `, } // twoSat returns whether the system described in the data read from r is // satisfiable and a set of states that satisfies the system. // The syntax used by twoSat is "𝑥 ∨ 𝑦" where 𝑥 and 𝑦 may be negated by // leading "¬" characters. twoSat uses the implication graph approach to // system analysis. func twoSat(r io.Reader) (state map[string]bool, ok bool) { g := simple.NewDirectedGraph() sc := bufio.NewScanner(r) nodes := make(map[string]node) for count := 1; sc.Scan(); count++ { line := sc.Text() fields := strings.Split(line, "∨") if len(fields) != 2 { log.Fatalf("failed to parse on line %d %q: invalid syntax", count, line) } var variables [2]node for i, f := range fields { f = strings.TrimSpace(f) var negate bool for strings.Index(f, "¬") == 0 { f = strings.TrimPrefix(f, "¬") negate = !negate } n, ok := nodes[f] if !ok { n = node{ id: int64(len(nodes) + 1), // id must not be zero. name: f, } nodes[f] = n } if negate { n = n.negated() } variables[i] = n } // Check for tautology. if variables[0].negated().ID() == variables[1].ID() { for _, v := range variables { if g.Node(v.ID()) == nil { g.AddNode(v) } } continue } // Add implications to the graph. g.SetEdge(simple.Edge{F: variables[0].negated(), T: variables[1]}) g.SetEdge(simple.Edge{F: variables[1].negated(), T: variables[0]}) } // Find implication inconsistencies. sccs := topo.TarjanSCC(g) for _, c := range sccs { set := make(map[int64]struct{}) for _, n := range c { id := n.ID() if _, ok := set[-id]; ok { return nil, false } set[id] = struct{}{} } } // Assign states. state = make(map[string]bool) unknown: for _, c := range sccs { for _, n := range c { if _, known := state[n.(node).name]; known { continue unknown } } for _, n := range c { n := n.(node) state[n.name] = n.id > 0 } } return state, true } type node struct { id int64 name string } func (n node) ID() int64 { return n.id } func (n node) negated() node { return node{-n.id, n.name} } func ExampleTarjanSCC_twoSAT() { for i, s := range systems { state, ok := twoSat(strings.NewReader(s)) if !ok { fmt.Printf("system %d is not satisfiable\n", i) continue } var ps []string for v, t := range state { ps = append(ps, fmt.Sprintf("%s:%t", v, t)) } sort.Strings(ps) fmt.Printf("system %d is satisfiable: %s\n", i, strings.Join(ps, " ")) } // Output: // system 0 is not satisfiable // system 1 is satisfiable: 𝑥_a:true 𝑥_b:true 𝑥_c:true 𝑥_d:true 𝑥_e:true 𝑥_f:true 𝑥_g:false 𝑥_h:true 𝑥_i:true 𝑥_j:false 𝑥_k:true 𝑥_l:true // system 2 is satisfiable: Gonum:true fun:true } golang-gonum-v1-gonum-0.14.0/graph/topo/bench_test.go000066400000000000000000000031211450372207100223620ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "fmt" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/simple" ) var ( gnpDirected_10_tenth = gnpDirected(10, 0.1) gnpDirected_100_tenth = gnpDirected(100, 0.1) gnpDirected_1000_tenth = gnpDirected(1000, 0.1) gnpDirected_10_half = gnpDirected(10, 0.5) gnpDirected_100_half = gnpDirected(100, 0.5) gnpDirected_1000_half = gnpDirected(1000, 0.5) ) func gnpDirected(n int, p float64) graph.Directed { g := simple.NewDirectedGraph() err := gen.Gnp(g, n, p, nil) if err != nil { panic(fmt.Sprintf("topo: bad test: %v", err)) } return g } func benchmarkTarjanSCC(b *testing.B, g graph.Directed) { var sccs [][]graph.Node for i := 0; i < b.N; i++ { sccs = TarjanSCC(g) } if len(sccs) == 0 { b.Fatal("unexpected number zero-sized SCC set") } } func BenchmarkTarjanSCCGnp_10_tenth(b *testing.B) { benchmarkTarjanSCC(b, gnpDirected_10_tenth) } func BenchmarkTarjanSCCGnp_100_tenth(b *testing.B) { benchmarkTarjanSCC(b, gnpDirected_100_tenth) } func BenchmarkTarjanSCCGnp_1000_tenth(b *testing.B) { benchmarkTarjanSCC(b, gnpDirected_1000_tenth) } func BenchmarkTarjanSCCGnp_10_half(b *testing.B) { benchmarkTarjanSCC(b, gnpDirected_10_half) } func BenchmarkTarjanSCCGnp_100_half(b *testing.B) { benchmarkTarjanSCC(b, gnpDirected_100_half) } func BenchmarkTarjanSCCGnp_1000_half(b *testing.B) { benchmarkTarjanSCC(b, gnpDirected_1000_half) } golang-gonum-v1-gonum-0.14.0/graph/topo/bron_kerbosch.go000066400000000000000000000136551450372207100231010ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" ) // DegeneracyOrdering returns the degeneracy ordering and the k-cores of // the undirected graph g. func DegeneracyOrdering(g graph.Undirected) (order []graph.Node, cores [][]graph.Node) { order, offsets := degeneracyOrdering(g) ordered.Reverse(order) cores = make([][]graph.Node, len(offsets)) offset := len(order) for i, n := range offsets { cores[i] = order[offset-n : offset] offset -= n } return order, cores } // KCore returns the k-core of the undirected graph g with nodes in an // optimal ordering for the coloring number. func KCore(k int, g graph.Undirected) []graph.Node { order, offsets := degeneracyOrdering(g) var offset int for _, n := range offsets[:k] { offset += n } core := make([]graph.Node, len(order)-offset) copy(core, order[offset:]) return core } // degeneracyOrdering is the common code for DegeneracyOrdering and KCore. It // returns l, the nodes of g in optimal ordering for coloring number and // s, a set of relative offsets into l for each k-core, where k is an index // into s. func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) { nodes := graph.NodesOf(g.Nodes()) // The algorithm used here is essentially as described at // http://en.wikipedia.org/w/index.php?title=Degeneracy_%28graph_theory%29&oldid=640308710 // Initialize an output list L in return parameters. // Compute a number d_v for each vertex v in G, // the number of neighbors of v that are not already in L. // Initially, these numbers are just the degrees of the vertices. dv := make(map[int64]int, len(nodes)) var ( maxDegree int neighbours = make(map[int64][]graph.Node) ) for _, n := range nodes { id := n.ID() adj := graph.NodesOf(g.From(id)) neighbours[id] = adj dv[id] = len(adj) if len(adj) > maxDegree { maxDegree = len(adj) } } // Initialize an array D such that D[i] contains a list of the // vertices v that are not already in L for which d_v = i. d := make([][]graph.Node, maxDegree+1) for _, n := range nodes { deg := dv[n.ID()] d[deg] = append(d[deg], n) } // Initialize k to 0. k := 0 // Repeat n times: s = []int{0} for range nodes { // Scan the array cells D[0], D[1], ... until // finding an i for which D[i] is nonempty. var ( i int di []graph.Node ) for i, di = range d { if len(di) != 0 { break } } // Set k to max(k,i). if i > k { k = i s = append(s, make([]int, k-len(s)+1)...) } // Select a vertex v from D[i]. Add v to the // beginning of L and remove it from D[i]. var v graph.Node v, d[i] = di[len(di)-1], di[:len(di)-1] l = append(l, v) s[k]++ delete(dv, v.ID()) // For each neighbor w of v not already in L, // subtract one from d_w and move w to the // cell of D corresponding to the new value of d_w. for _, w := range neighbours[v.ID()] { dw, ok := dv[w.ID()] if !ok { continue } for i, n := range d[dw] { if n.ID() == w.ID() { d[dw][i], d[dw] = d[dw][len(d[dw])-1], d[dw][:len(d[dw])-1] dw-- d[dw] = append(d[dw], w) break } } dv[w.ID()] = dw } } return l, s } // BronKerbosch returns the set of maximal cliques of the undirected graph g. func BronKerbosch(g graph.Undirected) [][]graph.Node { nodes := graph.NodesOf(g.Nodes()) // The algorithm used here is essentially BronKerbosch3 as described at // http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858 p := set.NewNodesSize(len(nodes)) for _, n := range nodes { p.Add(n) } x := set.NewNodes() var bk bronKerbosch order, _ := degeneracyOrdering(g) ordered.Reverse(order) for _, v := range order { neighbours := graph.NodesOf(g.From(v.ID())) nv := set.NewNodesSize(len(neighbours)) for _, n := range neighbours { nv.Add(n) } bk.maximalCliquePivot(g, []graph.Node{v}, set.IntersectionOfNodes(p, nv), set.IntersectionOfNodes(x, nv)) p.Remove(v) x.Add(v) } return bk } type bronKerbosch [][]graph.Node func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p, x set.Nodes) { if len(p) == 0 && len(x) == 0 { *bk = append(*bk, r) return } neighbours := bk.choosePivotFrom(g, p, x) nu := set.NewNodesSize(len(neighbours)) for _, n := range neighbours { nu.Add(n) } for _, v := range p { if nu.Has(v) { continue } vid := v.ID() neighbours := graph.NodesOf(g.From(vid)) nv := set.NewNodesSize(len(neighbours)) for _, n := range neighbours { nv.Add(n) } var found bool for _, n := range r { if n.ID() == vid { found = true break } } var sr []graph.Node if !found { sr = append(r[:len(r):len(r)], v) } bk.maximalCliquePivot(g, sr, set.IntersectionOfNodes(p, nv), set.IntersectionOfNodes(x, nv)) p.Remove(v) x.Add(v) } } func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighbors []graph.Node) { // TODO(kortschak): Investigate the impact of pivot choice that maximises // |p ⋂ neighbours(u)| as a function of input size. Until then, leave as // compile time option. if !tomitaTanakaTakahashi { for _, n := range p { return graph.NodesOf(g.From(n.ID())) } for _, n := range x { return graph.NodesOf(g.From(n.ID())) } panic("bronKerbosch: empty set") } var ( max = -1 pivot graph.Node ) maxNeighbors := func(s set.Nodes) { outer: for _, u := range s { nb := graph.NodesOf(g.From(u.ID())) c := len(nb) if c <= max { continue } for n := range nb { if _, ok := p[int64(n)]; ok { continue } c-- if c <= max { continue outer } } max = c pivot = u neighbors = nb } } maxNeighbors(p) maxNeighbors(x) if pivot == nil { panic("bronKerbosch: empty set") } return neighbors } golang-gonum-v1-gonum-0.14.0/graph/topo/bron_kerbosch_test.go000066400000000000000000000117141450372207100241320ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var vOrderTests = []struct { g []intset wantCore [][]int64 wantK int }{ { g: []intset{ 0: linksTo(1, 2, 4, 6), 1: linksTo(2, 4, 6), 2: linksTo(3, 6), 3: linksTo(4, 5), 4: linksTo(6), 5: nil, 6: nil, }, wantCore: [][]int64{ {}, {5}, {3}, {0, 1, 2, 4, 6}, }, wantK: 3, }, { g: batageljZaversnikGraph, wantCore: [][]int64{ {0}, {5, 9, 10, 16}, {1, 2, 3, 4, 11, 12, 13, 15}, {6, 7, 8, 14, 17, 18, 19, 20}, }, wantK: 3, }, } func TestDegeneracyOrdering(t *testing.T) { for i, test := range vOrderTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } order, core := DegeneracyOrdering(g) if len(core)-1 != test.wantK { t.Errorf("unexpected value of k for test %d: got: %d want: %d", i, len(core)-1, test.wantK) } var offset int for k, want := range test.wantCore { ordered.Int64s(want) got := make([]int64, len(want)) for j, n := range order[len(order)-len(want)-offset : len(order)-offset] { got[j] = n.ID() } ordered.Int64s(got) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want) } for j, n := range core[k] { got[j] = n.ID() } ordered.Int64s(got) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want) } offset += len(want) } } } func TestKCore(t *testing.T) { for i, test := range vOrderTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } for k := 0; k <= test.wantK+1; k++ { var want []int64 for _, c := range test.wantCore[k:] { want = append(want, c...) } core := KCore(k, g) if len(core) != len(want) { t.Errorf("unexpected %d-core length for test %d:\ngot: %v\nwant:%v", k, i, len(core), len(want)) continue } var got []int64 for _, n := range core { got = append(got, n.ID()) } ordered.Int64s(got) ordered.Int64s(want) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want) } } } } var bronKerboschTests = []struct { name string g []intset want [][]int64 }{ { // This is the example given in the Bron-Kerbosch article on wikipedia (renumbered). // http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858 name: "wikipedia example", g: []intset{ 0: linksTo(1, 4), 1: linksTo(2, 4), 2: linksTo(3), 3: linksTo(4, 5), 4: nil, 5: nil, }, want: [][]int64{ {0, 1, 4}, {1, 2}, {2, 3}, {3, 4}, {3, 5}, }, }, { name: "Batagelj-Zaversnik Graph", g: batageljZaversnikGraph, want: [][]int64{ {0}, {1, 2}, {1, 3}, {2, 4}, {3, 4}, {4, 5}, {6, 7, 8, 14}, {7, 11, 12}, {9, 11}, {10, 11}, {12, 18}, {13, 14, 15}, {14, 15, 17}, {15, 16}, {17, 18, 19, 20}, }, }, } func TestBronKerbosch(t *testing.T) { for _, test := range bronKerboschTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } cliques := BronKerbosch(g) got := make([][]int64, len(cliques)) for j, c := range cliques { ids := make([]int64, len(c)) for k, n := range c { ids[k] = n.ID() } ordered.Int64s(ids) got[j] = ids } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected cliques for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) } } } func BenchmarkBronKerbosch(b *testing.B) { for _, test := range bronKerboschTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } b.Run(test.name, func(b *testing.B) { var got [][]graph.Node for i := 0; i < b.N; i++ { got = BronKerbosch(g) } if len(got) != len(test.want) { b.Errorf("unexpected cliques for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) } }) } } golang-gonum-v1-gonum-0.14.0/graph/topo/clique_graph.go000066400000000000000000000060741450372207100227210ustar00rootroot00000000000000// 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 topo import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" ) // Builder is a pure topological graph construction type. type Builder interface { AddNode(graph.Node) SetEdge(graph.Edge) } // CliqueGraph builds the clique graph of g in dst using Clique and CliqueGraphEdge // nodes and edges. The nodes returned by calls to Nodes on the nodes and edges of // the constructed graph are the cliques and the common nodes between cliques // respectively. The dst graph is not cleared. func CliqueGraph(dst Builder, g graph.Undirected) { cliques := BronKerbosch(g) // Construct a consistent view of cliques in g. Sorting costs // us a little, but not as much as the cliques themselves. for _, c := range cliques { ordered.ByID(c) } ordered.BySliceIDs(cliques) cliqueNodes := make(cliqueNodeSets, len(cliques)) for id, c := range cliques { s := set.NewNodesSize(len(c)) for _, n := range c { s.Add(n) } ns := &nodeSet{Clique: Clique{id: int64(id), nodes: c}, nodes: s} dst.AddNode(ns.Clique) for _, n := range c { nid := n.ID() cliqueNodes[nid] = append(cliqueNodes[nid], ns) } } for _, cliques := range cliqueNodes { for i, uc := range cliques { for _, vc := range cliques[i+1:] { // Retain the nodes that contribute to the // edge between the cliques. var edgeNodes []graph.Node switch 1 { case len(uc.Clique.nodes): edgeNodes = []graph.Node{uc.Clique.nodes[0]} case len(vc.Clique.nodes): edgeNodes = []graph.Node{vc.Clique.nodes[0]} default: for _, n := range set.IntersectionOfNodes(uc.nodes, vc.nodes) { edgeNodes = append(edgeNodes, n) } ordered.ByID(edgeNodes) } dst.SetEdge(CliqueGraphEdge{from: uc.Clique, to: vc.Clique, nodes: edgeNodes}) } } } } type cliqueNodeSets map[int64][]*nodeSet type nodeSet struct { Clique nodes set.Nodes } // Clique is a node in a clique graph. type Clique struct { id int64 nodes []graph.Node } // ID returns the node ID. func (n Clique) ID() int64 { return n.id } // Nodes returns the nodes in the clique. func (n Clique) Nodes() []graph.Node { return n.nodes } // CliqueGraphEdge is an edge in a clique graph. type CliqueGraphEdge struct { from, to Clique nodes []graph.Node } // From returns the from node of the edge. func (e CliqueGraphEdge) From() graph.Node { return e.from } // To returns the to node of the edge. func (e CliqueGraphEdge) To() graph.Node { return e.to } // ReversedEdge returns a new CliqueGraphEdge with // the edge end points swapped. The nodes of the // new edge are shared with the receiver. func (e CliqueGraphEdge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from; return e } // Nodes returns the common nodes in the cliques of the underlying graph // corresponding to the from and to nodes in the clique graph. func (e CliqueGraphEdge) Nodes() []graph.Node { return e.nodes } golang-gonum-v1-gonum-0.14.0/graph/topo/clique_graph_test.go000066400000000000000000000064331450372207100237570ustar00rootroot00000000000000// 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 topo import ( "fmt" "testing" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/simple" ) var cliqueGraphTests = []struct { name string g []intset want string }{ { name: "simple", g: []intset{ 0: linksTo(1, 2, 4, 6), 1: linksTo(2, 4, 6), 2: linksTo(3, 6), 3: linksTo(4, 5), 4: linksTo(6), 5: nil, 6: nil, }, want: `strict graph { // Node definitions. 0 [nodes="[0 1 2 6]"]; 1 [nodes="[0 1 4 6]"]; 2 [nodes="[2 3]"]; 3 [nodes="[3 4]"]; 4 [nodes="[3 5]"]; // Edge definitions. 0 -- 1 [nodes="[0 1 6]"]; 0 -- 2 [nodes="[2]"]; 1 -- 3 [nodes="[4]"]; 2 -- 3 [nodes="[3]"]; 2 -- 4 [nodes="[3]"]; 3 -- 4 [nodes="[3]"]; }`, }, { name: "Batagelj-Zaversnik Graph", g: batageljZaversnikGraph, want: `strict graph { // Node definitions. 0 [nodes="[0]"]; 1 [nodes="[1 2]"]; 2 [nodes="[1 3]"]; 3 [nodes="[2 4]"]; 4 [nodes="[3 4]"]; 5 [nodes="[4 5]"]; 6 [nodes="[6 7 8 14]"]; 7 [nodes="[7 11 12]"]; 8 [nodes="[9 11]"]; 9 [nodes="[10 11]"]; 10 [nodes="[12 18]"]; 11 [nodes="[13 14 15]"]; 12 [nodes="[14 15 17]"]; 13 [nodes="[15 16]"]; 14 [nodes="[17 18 19 20]"]; // Edge definitions. 1 -- 2 [nodes="[1]"]; 1 -- 3 [nodes="[2]"]; 2 -- 4 [nodes="[3]"]; 3 -- 4 [nodes="[4]"]; 3 -- 5 [nodes="[4]"]; 4 -- 5 [nodes="[4]"]; 6 -- 7 [nodes="[7]"]; 6 -- 11 [nodes="[14]"]; 6 -- 12 [nodes="[14]"]; 7 -- 8 [nodes="[11]"]; 7 -- 9 [nodes="[11]"]; 7 -- 10 [nodes="[12]"]; 8 -- 9 [nodes="[11]"]; 10 -- 14 [nodes="[18]"]; 11 -- 12 [nodes="[14 15]"]; 11 -- 13 [nodes="[15]"]; 12 -- 13 [nodes="[15]"]; 12 -- 14 [nodes="[17]"]; }`, }, } func TestCliqueGraph(t *testing.T) { for _, test := range cliqueGraphTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } dst := simple.NewUndirectedGraph() CliqueGraph(dst, g) b, _ := dot.Marshal(dst, "", "", " ") got := string(b) if got != test.want { t.Errorf("unexpected clique graph result for %q: got:\n%s\nwant:\n%s", test.name, got, test.want) } } } func (n Clique) Attributes() []encoding.Attribute { return []encoding.Attribute{{Key: "nodes", Value: fmt.Sprintf(`"%v"`, n.Nodes())}} } func (e CliqueGraphEdge) Attributes() []encoding.Attribute { return []encoding.Attribute{{Key: "nodes", Value: fmt.Sprintf(`"%v"`, e.Nodes())}} } func BenchmarkCliqueGraph(b *testing.B) { for _, test := range cliqueGraphTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } b.Run(test.name, func(b *testing.B) { var dst *simple.UndirectedGraph for i := 0; i < b.N; i++ { b.StopTimer() dst = simple.NewUndirectedGraph() b.StartTimer() CliqueGraph(dst, g) } }) } } golang-gonum-v1-gonum-0.14.0/graph/topo/common_test.go000066400000000000000000000016161450372207100226020ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo // batageljZaversnikGraph is the example graph from // figure 1 of http://arxiv.org/abs/cs/0310049v1 var batageljZaversnikGraph = []intset{ 0: nil, 1: linksTo(2, 3), 2: linksTo(4), 3: linksTo(4), 4: linksTo(5), 5: nil, 6: linksTo(7, 8, 14), 7: linksTo(8, 11, 12, 14), 8: linksTo(14), 9: linksTo(11), 10: linksTo(11), 11: linksTo(12), 12: linksTo(18), 13: linksTo(14, 15), 14: linksTo(15, 17), 15: linksTo(16, 17), 16: nil, 17: linksTo(18, 19, 20), 18: linksTo(19, 20), 19: linksTo(20), 20: nil, } // intset is an integer set. type intset map[int64]struct{} func linksTo(i ...int64) intset { if len(i) == 0 { return nil } s := make(intset) for _, v := range i { s[v] = struct{}{} } return s } golang-gonum-v1-gonum-0.14.0/graph/topo/doc.go000066400000000000000000000004301450372207100210110ustar00rootroot00000000000000// 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 topo provides graph topology analysis functions. package topo // import "gonum.org/v1/gonum/graph/topo" golang-gonum-v1-gonum-0.14.0/graph/topo/johnson_cycles.go000066400000000000000000000150721450372207100232740ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" "gonum.org/v1/gonum/graph/iterator" ) // johnson implements Johnson's "Finding all the elementary // circuits of a directed graph" algorithm. SIAM J. Comput. 4(1):1975. // // Comments in the johnson methods are kept in sync with the comments // and labels from the paper. type johnson struct { adjacent johnsonGraph // SCC adjacency list. b []set.Ints // Johnson's "B-list". blocked []bool s int stack []graph.Node result [][]graph.Node } // DirectedCyclesIn returns the set of elementary cycles in the graph g. func DirectedCyclesIn(g graph.Directed) [][]graph.Node { jg := johnsonGraphFrom(g) j := johnson{ adjacent: jg, b: make([]set.Ints, len(jg.orig)), blocked: make([]bool, len(jg.orig)), } // len(j.nodes) is the order of g. for j.s < len(j.adjacent.orig)-1 { // We use the previous SCC adjacency to reduce the work needed. sccs := TarjanSCC(j.adjacent.subgraph(j.s)) // A_k = adjacency structure of strong component K with least // vertex in subgraph of G induced by {s, s+1, ... ,n}. j.adjacent = j.adjacent.sccSubGraph(sccs, 2) // Only allow SCCs with >= 2 vertices. if j.adjacent.order() == 0 { break } // s = least vertex in V_k if s := j.adjacent.leastVertexIndex(); s < j.s { j.s = s } for i, v := range j.adjacent.orig { if !j.adjacent.nodes.Has(v.ID()) { continue } if len(j.adjacent.succ[v.ID()]) > 0 { j.blocked[i] = false j.b[i] = make(set.Ints) } } //L3: _ = j.circuit(j.s) j.s++ } return j.result } // circuit is the CIRCUIT sub-procedure in the paper. func (j *johnson) circuit(v int) bool { f := false n := j.adjacent.orig[v] j.stack = append(j.stack, n) j.blocked[v] = true //L1: for w := range j.adjacent.succ[n.ID()] { w := j.adjacent.indexOf(w) if w == j.s { // Output circuit composed of stack followed by s. r := make([]graph.Node, len(j.stack)+1) copy(r, j.stack) r[len(r)-1] = j.adjacent.orig[j.s] j.result = append(j.result, r) f = true } else if !j.blocked[w] { if j.circuit(w) { f = true } } } //L2: if f { j.unblock(v) } else { for w := range j.adjacent.succ[n.ID()] { j.b[j.adjacent.indexOf(w)].Add(v) } } j.stack = j.stack[:len(j.stack)-1] return f } // unblock is the UNBLOCK sub-procedure in the paper. func (j *johnson) unblock(u int) { j.blocked[u] = false for w := range j.b[u] { j.b[u].Remove(w) if j.blocked[w] { j.unblock(w) } } } // johnsonGraph is an edge list representation of a graph with helpers // necessary for Johnson's algorithm type johnsonGraph struct { // Keep the original graph nodes and a // look-up to into the non-sparse // collection of potentially sparse IDs. orig []graph.Node index map[int64]int nodes set.Int64s succ map[int64]set.Int64s } // johnsonGraphFrom returns a deep copy of the graph g. func johnsonGraphFrom(g graph.Directed) johnsonGraph { nodes := graph.NodesOf(g.Nodes()) ordered.ByID(nodes) c := johnsonGraph{ orig: nodes, index: make(map[int64]int, len(nodes)), nodes: make(set.Int64s, len(nodes)), succ: make(map[int64]set.Int64s), } for i, u := range nodes { uid := u.ID() c.index[uid] = i to := g.From(uid) for to.Next() { v := to.Node() if c.succ[uid] == nil { c.succ[uid] = make(set.Int64s) c.nodes.Add(uid) } c.nodes.Add(v.ID()) c.succ[uid].Add(v.ID()) } } return c } // order returns the order of the graph. func (g johnsonGraph) order() int { return g.nodes.Count() } // indexOf returns the index of the retained node for the given node ID. func (g johnsonGraph) indexOf(id int64) int { return g.index[id] } // leastVertexIndex returns the index into orig of the least vertex. func (g johnsonGraph) leastVertexIndex() int { for _, v := range g.orig { if g.nodes.Has(v.ID()) { return g.indexOf(v.ID()) } } panic("johnsonCycles: empty set") } // subgraph returns a subgraph of g induced by {s, s+1, ... , n}. The // subgraph is destructively generated in g. func (g johnsonGraph) subgraph(s int) johnsonGraph { sn := g.orig[s].ID() for u, e := range g.succ { if u < sn { g.nodes.Remove(u) delete(g.succ, u) continue } for v := range e { if v < sn { g.succ[u].Remove(v) } } } return g } // sccSubGraph returns the graph of the tarjan's strongly connected // components with each SCC containing at least min vertices. // sccSubGraph returns nil if there is no SCC with at least min // members. func (g johnsonGraph) sccSubGraph(sccs [][]graph.Node, min int) johnsonGraph { if len(g.nodes) == 0 { g.nodes = nil g.succ = nil return g } sub := johnsonGraph{ orig: g.orig, index: g.index, nodes: make(set.Int64s), succ: make(map[int64]set.Int64s), } var n int for _, scc := range sccs { if len(scc) < min { continue } n++ for _, u := range scc { for _, v := range scc { if _, ok := g.succ[u.ID()][v.ID()]; ok { if sub.succ[u.ID()] == nil { sub.succ[u.ID()] = make(set.Int64s) sub.nodes.Add(u.ID()) } sub.nodes.Add(v.ID()) sub.succ[u.ID()].Add(v.ID()) } } } } if n == 0 { g.nodes = nil g.succ = nil return g } return sub } // Nodes is required to satisfy Tarjan. func (g johnsonGraph) Nodes() graph.Nodes { n := make([]graph.Node, 0, len(g.nodes)) for id := range g.nodes { n = append(n, johnsonGraphNode(id)) } return iterator.NewOrderedNodes(n) } // Successors is required to satisfy Tarjan. func (g johnsonGraph) From(id int64) graph.Nodes { adj := g.succ[id] if len(adj) == 0 { return graph.Empty } succ := make([]graph.Node, 0, len(adj)) for id := range adj { succ = append(succ, johnsonGraphNode(id)) } return iterator.NewOrderedNodes(succ) } func (johnsonGraph) Has(int64) bool { panic("topo: unintended use of johnsonGraph") } func (johnsonGraph) Node(int64) graph.Node { panic("topo: unintended use of johnsonGraph") } func (johnsonGraph) HasEdgeBetween(_, _ int64) bool { panic("topo: unintended use of johnsonGraph") } func (johnsonGraph) Edge(_, _ int64) graph.Edge { panic("topo: unintended use of johnsonGraph") } func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool { panic("topo: unintended use of johnsonGraph") } func (johnsonGraph) To(int64) graph.Nodes { panic("topo: unintended use of johnsonGraph") } type johnsonGraphNode int64 func (n johnsonGraphNode) ID() int64 { return int64(n) } golang-gonum-v1-gonum-0.14.0/graph/topo/johnson_cycles_test.go000066400000000000000000000041771450372207100243370ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "reflect" "testing" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var cyclesInTests = []struct { g []intset want [][]int64 }{ { g: []intset{ 0: linksTo(1), 1: linksTo(2, 7), 2: linksTo(3, 6), 3: linksTo(4), 4: linksTo(2, 5), 6: linksTo(3, 5), 7: linksTo(0, 6), }, want: [][]int64{ {0, 1, 7, 0}, {2, 3, 4, 2}, {2, 6, 3, 4, 2}, }, }, { g: []intset{ 0: linksTo(1, 2, 3), 1: linksTo(2), 2: linksTo(3), 3: linksTo(1), }, want: [][]int64{ {1, 2, 3, 1}, }, }, { g: []intset{ 0: linksTo(1), 1: linksTo(0, 2), 2: linksTo(1), }, want: [][]int64{ {0, 1, 0}, {1, 2, 1}, }, }, { g: []intset{ 0: linksTo(1), 1: linksTo(2, 3), 2: linksTo(4, 5), 3: linksTo(4, 5), 4: linksTo(6), 5: nil, 6: nil, }, want: nil, }, { g: []intset{ 0: linksTo(1), 1: linksTo(2, 3, 4), 2: linksTo(0, 3), 3: linksTo(4), 4: linksTo(3), }, want: [][]int64{ {0, 1, 2, 0}, {3, 4, 3}, }, }, } func TestDirectedCyclesIn(t *testing.T) { for i, test := range cyclesInTests { g := simple.NewDirectedGraph() g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs. for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } cycles := DirectedCyclesIn(g) var got [][]int64 if cycles != nil { got = make([][]int64, len(cycles)) } // johnson.circuit does range iteration over maps, // so sort to ensure consistent ordering. for j, c := range cycles { ids := make([]int64, len(c)) for k, n := range c { ids[k] = n.ID() } got[j] = ids } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected johnson result for %d:\n\tgot:%#v\n\twant:%#v", i, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/graph/topo/non_tomita_choice.go000066400000000000000000000003751450372207100237350ustar00rootroot00000000000000// 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:build !tomita // +build !tomita package topo const tomitaTanakaTakahashi = false golang-gonum-v1-gonum-0.14.0/graph/topo/paton_cycles.go000066400000000000000000000034121450372207100227320ustar00rootroot00000000000000// 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 topo import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/linear" "gonum.org/v1/gonum/graph/internal/set" ) // UndirectedCyclesIn returns a set of cycles that forms a cycle basis in the graph g. // Any cycle in g can be constructed as a symmetric difference of its elements. func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node { // From "An algorithm for finding a fundamental set of cycles of a graph" // https://doi.org/10.1145/363219.363232 var cycles [][]graph.Node done := make(set.Int64s) var tree linear.NodeStack nodes := g.Nodes() for nodes.Next() { n := nodes.Node() id := n.ID() if done.Has(id) { continue } done.Add(id) tree = tree[:0] tree.Push(n) from := sets{id: set.Int64s{}} to := map[int64]graph.Node{id: n} for tree.Len() != 0 { u := tree.Pop() uid := u.ID() adj := from[uid] it := g.From(uid) for it.Next() { v := it.Node() vid := v.ID() switch { case uid == vid: cycles = append(cycles, []graph.Node{u}) case !from.has(vid): done.Add(vid) to[vid] = u tree.Push(v) from.add(uid, vid) case !adj.Has(vid): c := []graph.Node{v, u} adj := from[vid] p := to[uid] for !adj.Has(p.ID()) { c = append(c, p) p = to[p.ID()] } c = append(c, p, c[0]) cycles = append(cycles, c) adj.Add(uid) } } } } return cycles } type sets map[int64]set.Int64s func (s sets) add(uid, vid int64) { e, ok := s[vid] if !ok { e = make(set.Int64s) s[vid] = e } e.Add(uid) } func (s sets) has(uid int64) bool { _, ok := s[uid] return ok } golang-gonum-v1-gonum-0.14.0/graph/topo/paton_cycles_test.go000066400000000000000000000055361450372207100240020ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var undirectedCyclesInTests = []struct { g []intset want [][][]int64 }{ { g: []intset{ 0: linksTo(1, 2), 1: linksTo(2, 4, 5, 9), 2: linksTo(4, 7, 9), 3: linksTo(5), 4: linksTo(8), 5: linksTo(7, 8), 6: nil, 7: nil, 8: nil, 9: nil, 10: linksTo(11, 12), 11: linksTo(12), 12: nil, }, want: [][][]int64{ { {0, 1, 2, 0}, {1, 2, 7, 5, 1}, {1, 2, 9, 1}, {1, 4, 8, 5, 1}, {2, 4, 8, 5, 7, 2}, {10, 11, 12, 10}, }, { {0, 1, 2, 0}, {1, 2, 4, 1}, {1, 2, 7, 5, 1}, {1, 2, 9, 1}, {1, 4, 8, 5, 1}, {10, 11, 12, 10}, }, { {0, 1, 2, 0}, {1, 2, 4, 1}, {1, 2, 9, 1}, {1, 4, 8, 5, 1}, {2, 4, 8, 5, 7, 2}, {10, 11, 12, 10}, }, { {0, 1, 2, 0}, {1, 2, 4, 1}, {1, 2, 7, 5, 1}, {1, 2, 9, 1}, {2, 4, 8, 5, 7, 2}, {10, 11, 12, 10}, }, }, }, } func TestUndirectedCyclesIn(t *testing.T) { for i, test := range undirectedCyclesInTests { g := simple.NewUndirectedGraph() g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs. for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } cycles := UndirectedCyclesIn(g) var got [][]int64 if cycles != nil { got = make([][]int64, len(cycles)) } // Canonicalise the cycles. for j, c := range cycles { ids := make([]int64, len(c)) for k, n := range canonicalise(c[:len(c)-1]) { ids[k] = n.ID() } ids[len(ids)-1] = ids[0] got[j] = ids } ordered.BySliceValues(got) var matched bool for _, want := range test.want { if reflect.DeepEqual(got, want) { matched = true break } } if !matched { t.Errorf("unexpected paton result for %d:\n\tgot:%#v\n\twant from:%#v", i, got, test.want) } } } // canonicalise returns the cycle path c cyclicly permuted such that // the first element has the lowest ID and then conditionally // reversed so that the second element has the lowest possible // neighbouring ID. // c lists each node only once - the final node must not be a // reiteration of the first node. func canonicalise(c []graph.Node) []graph.Node { if len(c) < 2 { return c } idx := 0 min := c[0].ID() for i, n := range c[1:] { if id := n.ID(); id < min { idx = i + 1 min = id } } if idx != 0 { c = append(c[idx:], c[:idx]...) } if c[len(c)-1].ID() < c[1].ID() { ordered.Reverse(c[1:]) } return c } golang-gonum-v1-gonum-0.14.0/graph/topo/tarjan.go000066400000000000000000000132161450372207100215310ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/internal/set" ) // Unorderable is an error containing sets of unorderable graph.Nodes. type Unorderable [][]graph.Node // Error satisfies the error interface. func (e Unorderable) Error() string { const maxNodes = 10 var n int for _, c := range e { n += len(c) } if n > maxNodes { // Don't return errors that are too long. return fmt.Sprintf("topo: no topological ordering: %d nodes in %d cyclic components", n, len(e)) } return fmt.Sprintf("topo: no topological ordering: cyclic components: %v", [][]graph.Node(e)) } func lexical(nodes []graph.Node) { ordered.ByID(nodes) } // Sort performs a topological sort of the directed graph g returning the 'from' to 'to' // sort order. If a topological ordering is not possible, an Unorderable error is returned // listing cyclic components in g with each cyclic component's members sorted by ID. When // an Unorderable error is returned, each cyclic component's topological position within // the sorted nodes is marked with a nil graph.Node. func Sort(g graph.Directed) (sorted []graph.Node, err error) { sccs := TarjanSCC(g) return sortedFrom(sccs, lexical) } // SortStabilized performs a topological sort of the directed graph g returning the 'from' // to 'to' sort order, or the order defined by the in place order sort function where there // is no unambiguous topological ordering. If a topological ordering is not possible, an // Unorderable error is returned listing cyclic components in g with each cyclic component's // members sorted by the provided order function. If order is nil, nodes are ordered lexically // by node ID. When an Unorderable error is returned, each cyclic component's topological // position within the sorted nodes is marked with a nil graph.Node. func SortStabilized(g graph.Directed, order func([]graph.Node)) (sorted []graph.Node, err error) { if order == nil { order = lexical } sccs := tarjanSCCstabilized(g, order) return sortedFrom(sccs, order) } func sortedFrom(sccs [][]graph.Node, order func([]graph.Node)) ([]graph.Node, error) { sorted := make([]graph.Node, 0, len(sccs)) var sc Unorderable for _, s := range sccs { if len(s) != 1 { order(s) sc = append(sc, s) sorted = append(sorted, nil) continue } sorted = append(sorted, s[0]) } var err error if sc != nil { for i, j := 0, len(sc)-1; i < j; i, j = i+1, j-1 { sc[i], sc[j] = sc[j], sc[i] } err = sc } ordered.Reverse(sorted) return sorted, err } // TarjanSCC returns the strongly connected components of the graph g using Tarjan's algorithm. // // A strongly connected component of a graph is a set of vertices where it's possible to reach any // vertex in the set from any other (meaning there's a cycle between them.) // // Generally speaking, a directed graph where the number of strongly connected components is equal // to the number of nodes is acyclic, unless you count reflexive edges as a cycle (which requires // only a little extra testing.) func TarjanSCC(g graph.Directed) [][]graph.Node { return tarjanSCCstabilized(g, nil) } func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node { nodes := graph.NodesOf(g.Nodes()) var succ func(id int64) []graph.Node if order == nil { succ = func(id int64) []graph.Node { return graph.NodesOf(g.From(id)) } } else { order(nodes) ordered.Reverse(nodes) succ = func(id int64) []graph.Node { to := graph.NodesOf(g.From(id)) order(to) ordered.Reverse(to) return to } } t := tarjan{ succ: succ, indexTable: make(map[int64]int, len(nodes)), lowLink: make(map[int64]int, len(nodes)), onStack: make(set.Int64s), } for _, v := range nodes { if t.indexTable[v.ID()] == 0 { t.strongconnect(v) } } return t.sccs } // tarjan implements Tarjan's strongly connected component finding // algorithm. The implementation is from the pseudocode at // // http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644 type tarjan struct { succ func(id int64) []graph.Node index int indexTable map[int64]int lowLink map[int64]int onStack set.Int64s stack []graph.Node sccs [][]graph.Node } // strongconnect is the strongconnect function described in the // wikipedia article. func (t *tarjan) strongconnect(v graph.Node) { vID := v.ID() // Set the depth index for v to the smallest unused index. t.index++ t.indexTable[vID] = t.index t.lowLink[vID] = t.index t.stack = append(t.stack, v) t.onStack.Add(vID) // Consider successors of v. for _, w := range t.succ(vID) { wID := w.ID() if t.indexTable[wID] == 0 { // Successor w has not yet been visited; recur on it. t.strongconnect(w) t.lowLink[vID] = min(t.lowLink[vID], t.lowLink[wID]) } else if t.onStack.Has(wID) { // Successor w is in stack s and hence in the current SCC. t.lowLink[vID] = min(t.lowLink[vID], t.indexTable[wID]) } } // If v is a root node, pop the stack and generate an SCC. if t.lowLink[vID] == t.indexTable[vID] { // Start a new strongly connected component. var ( scc []graph.Node w graph.Node ) for { w, t.stack = t.stack[len(t.stack)-1], t.stack[:len(t.stack)-1] t.onStack.Remove(w.ID()) // Add w to current strongly connected component. scc = append(scc, w) if w.ID() == vID { break } } // Output the current strongly connected component. t.sccs = append(t.sccs, scc) } } func min(a, b int) int { if a < b { return a } return b } golang-gonum-v1-gonum-0.14.0/graph/topo/tarjan_test.go000066400000000000000000000145331450372207100225730ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) type interval struct{ start, end int } var tarjanTests = []struct { g []intset ambiguousOrder []interval want [][]int64 sortedLength int unorderableLength int sortable bool }{ { g: []intset{ 0: linksTo(1), 1: linksTo(2, 7), 2: linksTo(3, 6), 3: linksTo(4), 4: linksTo(2, 5), 6: linksTo(3, 5), 7: linksTo(0, 6), }, want: [][]int64{ {5}, {2, 3, 4, 6}, {0, 1, 7}, }, sortedLength: 1, unorderableLength: 2, sortable: false, }, { g: []intset{ 0: linksTo(1, 2, 3), 1: linksTo(2), 2: linksTo(3), 3: linksTo(1), }, want: [][]int64{ {1, 2, 3}, {0}, }, sortedLength: 1, unorderableLength: 1, sortable: false, }, { g: []intset{ 0: linksTo(1), 1: linksTo(0, 2), 2: linksTo(1), }, want: [][]int64{ {0, 1, 2}, }, sortedLength: 0, unorderableLength: 1, sortable: false, }, { g: []intset{ 0: linksTo(1), 1: linksTo(2, 3), 2: linksTo(4, 5), 3: linksTo(4, 5), 4: linksTo(6), 5: nil, 6: nil, }, // Node pairs (2, 3) and (4, 5) are not // relatively orderable within each pair. ambiguousOrder: []interval{ {0, 3}, // This includes node 6 since it only needs to be before 4 in topo sort. {3, 5}, }, want: [][]int64{ {6}, {5}, {4}, {3}, {2}, {1}, {0}, }, sortedLength: 7, sortable: true, }, { g: []intset{ 0: linksTo(1), 1: linksTo(2, 3, 4), 2: linksTo(0, 3), 3: linksTo(4), 4: linksTo(3), }, // SCCs are not relatively ordable. ambiguousOrder: []interval{ {0, 2}, }, want: [][]int64{ {0, 1, 2}, {3, 4}, }, sortedLength: 0, unorderableLength: 2, sortable: false, }, } func TestSort(t *testing.T) { for i, test := range tarjanTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } sorted, err := Sort(g) var gotSortedLen int for _, n := range sorted { if n != nil { gotSortedLen++ } } if gotSortedLen != test.sortedLength { t.Errorf("unexpected number of sortable nodes for test %d: got:%d want:%d", i, gotSortedLen, test.sortedLength) } if err == nil != test.sortable { t.Errorf("unexpected sortability for test %d: got error: %v want: nil-error=%t", i, err, test.sortable) } if err != nil && len(err.(Unorderable)) != test.unorderableLength { t.Errorf("unexpected number of unorderable nodes for test %d: got:%d want:%d", i, len(err.(Unorderable)), test.unorderableLength) } } } func TestTarjanSCC(t *testing.T) { for i, test := range tarjanTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } gotSCCs := TarjanSCC(g) // tarjan.strongconnect does range iteration over maps, // so sort SCC members to ensure consistent ordering. gotIDs := make([][]int64, len(gotSCCs)) for i, scc := range gotSCCs { gotIDs[i] = make([]int64, len(scc)) for j, id := range scc { gotIDs[i][j] = id.ID() } ordered.Int64s(gotIDs[i]) } for _, iv := range test.ambiguousOrder { ordered.BySliceValues(test.want[iv.start:iv.end]) ordered.BySliceValues(gotIDs[iv.start:iv.end]) } if !reflect.DeepEqual(gotIDs, test.want) { t.Errorf("unexpected Tarjan scc result for %d:\n\tgot:%v\n\twant:%v", i, gotIDs, test.want) } } } var stabilizedSortTests = []struct { g []intset want []graph.Node err error }{ { g: []intset{ 0: linksTo(1), 1: linksTo(2, 7), 2: linksTo(3, 6), 3: linksTo(4), 4: linksTo(2, 5), 6: linksTo(3, 5), 7: linksTo(0, 6), }, want: []graph.Node{nil, nil, simple.Node(5)}, err: Unorderable{ {simple.Node(0), simple.Node(1), simple.Node(7)}, {simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(6)}, }, }, { g: []intset{ 0: linksTo(1, 2, 3), 1: linksTo(2), 2: linksTo(3), 3: linksTo(1), }, want: []graph.Node{simple.Node(0), nil}, err: Unorderable{ {simple.Node(1), simple.Node(2), simple.Node(3)}, }, }, { g: []intset{ 0: linksTo(1), 1: linksTo(0, 2), 2: linksTo(1), }, want: []graph.Node{nil}, err: Unorderable{ {simple.Node(0), simple.Node(1), simple.Node(2)}, }, }, { g: []intset{ 0: linksTo(1), 1: linksTo(2, 3), 2: linksTo(4, 5), 3: linksTo(4, 5), 4: linksTo(6), 5: nil, 6: nil, }, want: []graph.Node{simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6)}, err: nil, }, { g: []intset{ 0: linksTo(1), 1: linksTo(2, 3, 4), 2: linksTo(0, 3), 3: linksTo(4), 4: linksTo(3), }, want: []graph.Node{nil, nil}, err: Unorderable{ {simple.Node(0), simple.Node(1), simple.Node(2)}, {simple.Node(3), simple.Node(4)}, }, }, { g: []intset{ 0: linksTo(1, 2, 3, 4, 5, 6), 1: linksTo(7), 2: linksTo(7), 3: linksTo(7), 4: linksTo(7), 5: linksTo(7), 6: linksTo(7), 7: nil, }, want: []graph.Node{simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6), simple.Node(7)}, err: nil, }, } func TestSortStabilized(t *testing.T) { for i, test := range stabilizedSortTests { g := simple.NewDirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got, err := SortStabilized(g, nil) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected sort result for test %d: got:%d want:%d", i, got, test.want) } if !reflect.DeepEqual(err, test.err) { t.Errorf("unexpected sort error for test %d: got:%v want:%v", i, err, test.want) } } } golang-gonum-v1-gonum-0.14.0/graph/topo/tomita_choice.go000066400000000000000000000003721450372207100230600ustar00rootroot00000000000000// 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:build tomita // +build tomita package topo const tomitaTanakaTakahashi = true golang-gonum-v1-gonum-0.14.0/graph/topo/topo.go000066400000000000000000000051701450372207100212330ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/traverse" ) // IsPathIn returns whether path is a path in g. // // As special cases, IsPathIn returns true for a zero length path or for // a path of length 1 when the node in path exists in the graph. func IsPathIn(g graph.Graph, path []graph.Node) bool { switch len(path) { case 0: return true case 1: return g.Node(path[0].ID()) != nil default: var canReach func(uid, vid int64) bool switch g := g.(type) { case graph.Directed: canReach = g.HasEdgeFromTo default: canReach = g.HasEdgeBetween } for i, u := range path[:len(path)-1] { if !canReach(u.ID(), path[i+1].ID()) { return false } } return true } } // PathExistsIn returns whether there is a path in g starting at 'from' extending // to 'to'. // // PathExistsIn exists as a helper function. If many tests for path existence // are being performed, other approaches will be more efficient. func PathExistsIn(g graph.Graph, from, to graph.Node) bool { var t traverse.BreadthFirst return t.Walk(g, from, func(n graph.Node, _ int) bool { return n.ID() == to.ID() }) != nil } // ConnectedComponents returns the connected components of the undirected graph g. func ConnectedComponents(g graph.Undirected) [][]graph.Node { var ( w traverse.DepthFirst c []graph.Node cc [][]graph.Node ) during := func(n graph.Node) { c = append(c, n) } after := func() { cc = append(cc, []graph.Node(nil)) cc[len(cc)-1] = append(cc[len(cc)-1], c...) c = c[:0] } w.WalkAll(g, nil, after, during) return cc } // Equal returns whether two graphs are topologically equal. To be // considered topologically equal, a and b must have identical sets // of nodes and be identically traversable. func Equal(a, b graph.Graph) bool { aNodes := a.Nodes() bNodes := b.Nodes() if aNodes.Len() != bNodes.Len() { return false } aNodeSlice := graph.NodesOf(aNodes) bNodeSlice := graph.NodesOf(bNodes) ordered.ByID(aNodeSlice) ordered.ByID(bNodeSlice) for i, aU := range aNodeSlice { id := aU.ID() if id != bNodeSlice[i].ID() { return false } toA := a.From(id) toB := b.From(id) if toA.Len() != toB.Len() { return false } aAdjacent := graph.NodesOf(toA) bAdjacent := graph.NodesOf(toB) ordered.ByID(aAdjacent) ordered.ByID(bAdjacent) for i, aV := range aAdjacent { id := aV.ID() if id != bAdjacent[i].ID() { return false } } } return true } golang-gonum-v1-gonum-0.14.0/graph/topo/topo_test.go000066400000000000000000000231231450372207100222700ustar00rootroot00000000000000// Copyright ©2014 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package topo import ( "reflect" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) func TestIsPath(t *testing.T) { dg := simple.NewDirectedGraph() if !IsPathIn(dg, nil) { t.Error("IsPath returns false on nil path") } p := []graph.Node{simple.Node(0)} if IsPathIn(dg, p) { t.Error("IsPath returns true on nonexistent node") } dg.AddNode(p[0]) if !IsPathIn(dg, p) { t.Error("IsPath returns false on single-length path with existing node") } p = append(p, simple.Node(1)) dg.AddNode(p[1]) if IsPathIn(dg, p) { t.Error("IsPath returns true on bad path of length 2") } dg.SetEdge(simple.Edge{F: p[0], T: p[1]}) if !IsPathIn(dg, p) { t.Error("IsPath returns false on correct path of length 2") } p[0], p[1] = p[1], p[0] if IsPathIn(dg, p) { t.Error("IsPath erroneously returns true for a reverse path") } p = []graph.Node{p[1], p[0], simple.Node(2)} dg.SetEdge(simple.Edge{F: p[1], T: p[2]}) if !IsPathIn(dg, p) { t.Error("IsPath does not find a correct path for path > 2 nodes") } ug := simple.NewUndirectedGraph() ug.SetEdge(simple.Edge{F: p[1], T: p[0]}) ug.SetEdge(simple.Edge{F: p[1], T: p[2]}) if !IsPathIn(dg, p) { t.Error("IsPath does not correctly account for undirected behavior") } } var pathExistsInUndirectedTests = []struct { g []intset from, to int want bool }{ {g: batageljZaversnikGraph, from: 0, to: 0, want: true}, {g: batageljZaversnikGraph, from: 0, to: 1, want: false}, {g: batageljZaversnikGraph, from: 1, to: 2, want: true}, {g: batageljZaversnikGraph, from: 2, to: 1, want: true}, {g: batageljZaversnikGraph, from: 2, to: 12, want: false}, {g: batageljZaversnikGraph, from: 20, to: 6, want: true}, } func TestPathExistsInUndirected(t *testing.T) { for i, test := range pathExistsInUndirectedTests { g := simple.NewUndirectedGraph() for u, e := range test.g { if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { if g.Node(v) == nil { g.AddNode(simple.Node(v)) } g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to)) if got != test.want { t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want) } } } var pathExistsInDirectedTests = []struct { g []intset from, to int want bool }{ // The graph definition is such that from node IDs are // less than to node IDs. {g: batageljZaversnikGraph, from: 0, to: 0, want: true}, {g: batageljZaversnikGraph, from: 0, to: 1, want: false}, {g: batageljZaversnikGraph, from: 1, to: 2, want: true}, {g: batageljZaversnikGraph, from: 2, to: 1, want: false}, {g: batageljZaversnikGraph, from: 2, to: 12, want: false}, {g: batageljZaversnikGraph, from: 20, to: 6, want: false}, {g: batageljZaversnikGraph, from: 6, to: 20, want: true}, } func TestPathExistsInDirected(t *testing.T) { for i, test := range pathExistsInDirectedTests { g := simple.NewDirectedGraph() for u, e := range test.g { if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { if g.Node(v) == nil { g.AddNode(simple.Node(v)) } g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to)) if got != test.want { t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want) } } } var connectedComponentTests = []struct { g []intset want [][]int64 }{ { g: batageljZaversnikGraph, want: [][]int64{ {0}, {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, }, }, } func TestConnectedComponents(t *testing.T) { for i, test := range connectedComponentTests { g := simple.NewUndirectedGraph() for u, e := range test.g { if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { if g.Node(v) == nil { g.AddNode(simple.Node(v)) } g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } cc := ConnectedComponents(g) got := make([][]int64, len(cc)) for j, c := range cc { ids := make([]int64, len(c)) for k, n := range c { ids[k] = n.ID() } ordered.Int64s(ids) got[j] = ids } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected connected components for test %d %T:\ngot: %v\nwant:%v", i, g, got, test.want) } } } var equalTests = []struct { name string a, b graph.Graph want bool }{ {name: "empty g=g", a: simple.NewUndirectedGraph(), b: simple.NewUndirectedGraph(), want: true}, {name: "empty dg=dg", a: simple.NewDirectedGraph(), b: simple.NewDirectedGraph(), want: true}, {name: "empty g=dg", a: simple.NewUndirectedGraph(), b: simple.NewDirectedGraph(), want: true}, { name: "1 g=g", want: true, a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), }, { name: "1 dg=dg", want: true, a: addNodes(simple.NewDirectedGraph(), simple.Node(1)), b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), }, { name: "1 g=dg", want: true, a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), }, { name: "0/1 g≠g", want: false, a: simple.NewUndirectedGraph(), b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), }, { name: "0/1 dg≠dg", want: false, a: simple.NewDirectedGraph(), b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), }, { name: "0/1 g≠dg", want: false, a: simple.NewUndirectedGraph(), b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), }, { name: "0/1 g≠dg", want: false, a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), b: simple.NewDirectedGraph(), }, { name: "1 g≠g", want: false, a: addNodes(simple.NewUndirectedGraph(), simple.Node(0)), b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), }, { name: "1 dg≠dg", want: false, a: addNodes(simple.NewDirectedGraph(), simple.Node(0)), b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), }, { name: "1 g≠dg", want: false, a: addNodes(simple.NewUndirectedGraph(), simple.Node(0)), b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), }, { name: "box g=g", want: true, a: setEdges(simple.NewUndirectedGraph(), simple.Edge{F: simple.Node(0), T: simple.Node(1)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(2), T: simple.Node(3)}, simple.Edge{F: simple.Node(3), T: simple.Node(0)}, ), b: setEdges(simple.NewUndirectedGraph(), simple.Edge{F: simple.Node(3), T: simple.Node(0)}, simple.Edge{F: simple.Node(0), T: simple.Node(1)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(2), T: simple.Node(3)}, ), }, { name: "box dg=dg", want: true, a: setEdges(simple.NewDirectedGraph(), simple.Edge{F: simple.Node(0), T: simple.Node(1)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(2), T: simple.Node(3)}, simple.Edge{F: simple.Node(3), T: simple.Node(0)}, ), b: setEdges(simple.NewDirectedGraph(), simple.Edge{F: simple.Node(3), T: simple.Node(0)}, simple.Edge{F: simple.Node(0), T: simple.Node(1)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(2), T: simple.Node(3)}, ), }, { name: "box reversed dg≠dg", want: false, a: setEdges(simple.NewDirectedGraph(), simple.Edge{F: simple.Node(0), T: simple.Node(1)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(2), T: simple.Node(3)}, simple.Edge{F: simple.Node(3), T: simple.Node(0)}, ), b: setEdges(simple.NewDirectedGraph(), simple.Edge{F: simple.Node(1), T: simple.Node(0)}, simple.Edge{F: simple.Node(2), T: simple.Node(1)}, simple.Edge{F: simple.Node(3), T: simple.Node(2)}, simple.Edge{F: simple.Node(0), T: simple.Node(3)}, ), }, { name: "box g=dg", want: true, a: setEdges(simple.NewUndirectedGraph(), simple.Edge{F: simple.Node(0), T: simple.Node(1)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(2), T: simple.Node(3)}, simple.Edge{F: simple.Node(3), T: simple.Node(0)}, ), b: setEdges(simple.NewDirectedGraph(), simple.Edge{F: simple.Node(0), T: simple.Node(1)}, simple.Edge{F: simple.Node(1), T: simple.Node(0)}, simple.Edge{F: simple.Node(1), T: simple.Node(2)}, simple.Edge{F: simple.Node(2), T: simple.Node(3)}, simple.Edge{F: simple.Node(2), T: simple.Node(1)}, simple.Edge{F: simple.Node(3), T: simple.Node(2)}, simple.Edge{F: simple.Node(3), T: simple.Node(0)}, simple.Edge{F: simple.Node(0), T: simple.Node(3)}, ), }, } func TestEqual(t *testing.T) { for _, test := range equalTests { if got := Equal(test.a, test.b); got != test.want { t.Errorf("unexpected result for %q equality test: got:%t want:%t", test.name, got, test.want) } if got := Equal(plainGraph{test.a}, plainGraph{test.b}); got != test.want { t.Errorf("unexpected result for %q equality test with filtered method set: got:%t want:%t", test.name, got, test.want) } } } type plainGraph struct { graph.Graph } type builder interface { graph.Graph graph.Builder } func addNodes(dst builder, nodes ...graph.Node) builder { for _, n := range nodes { dst.AddNode(n) } return dst } func setEdges(dst builder, edges ...graph.Edge) builder { for _, e := range edges { dst.SetEdge(e) } return dst } golang-gonum-v1-gonum-0.14.0/graph/traverse/000077500000000000000000000000001450372207100205725ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/graph/traverse/doc.go000066400000000000000000000004431450372207100216670ustar00rootroot00000000000000// 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 traverse provides basic graph traversal primitives. package traverse // import "gonum.org/v1/gonum/graph/traverse" golang-gonum-v1-gonum-0.14.0/graph/traverse/traverse.go000066400000000000000000000136021450372207100227560ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package traverse import ( "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/internal/linear" "gonum.org/v1/gonum/graph/internal/set" ) var _ Graph = graph.Graph(nil) // Graph is the subset of graph.Graph necessary for graph traversal. type Graph interface { // From returns all nodes that can be reached directly // from the node with the given ID. From(id int64) graph.Nodes // 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) graph.Edge } // BreadthFirst implements stateful breadth-first graph traversal. type BreadthFirst struct { // Visit is called on all nodes on their first visit. Visit func(graph.Node) // Traverse is called on all edges that may be traversed // during the walk. This includes edges that would hop to // an already visited node. // // The value returned by Traverse determines whether // an edge can be traversed during the walk. Traverse func(graph.Edge) bool queue linear.NodeQueue visited set.Int64s } // Walk performs a breadth-first traversal of the graph g starting from the given node, // depending on the Traverse field and the until parameter if they are non-nil. // The traversal follows edges for which Traverse(edge) is true and returns the first node // for which until(node, depth) is true. During the traversal, if the Visit field is // non-nil, it is called with each node the first time it is visited. func (b *BreadthFirst) Walk(g Graph, from graph.Node, until func(n graph.Node, d int) bool) graph.Node { if b.visited == nil { b.visited = make(set.Int64s) } b.queue.Enqueue(from) if b.Visit != nil && !b.visited.Has(from.ID()) { b.Visit(from) } b.visited.Add(from.ID()) var ( depth int children int untilNext = 1 ) for b.queue.Len() > 0 { t := b.queue.Dequeue() if until != nil && until(t, depth) { return t } tid := t.ID() to := g.From(tid) for to.Next() { n := to.Node() nid := n.ID() if b.Traverse != nil && !b.Traverse(g.Edge(tid, nid)) { continue } if b.visited.Has(nid) { continue } if b.Visit != nil { b.Visit(n) } b.visited.Add(nid) children++ b.queue.Enqueue(n) } if untilNext--; untilNext == 0 { depth++ untilNext = children children = 0 } } return nil } // WalkAll calls Walk for each unvisited node of the graph g using edges independent // of their direction. The functions before and after are called prior to commencing // and after completing each walk if they are non-nil respectively. The function // during is called on each node as it is traversed. func (b *BreadthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) { b.Reset() nodes := g.Nodes() for nodes.Next() { from := nodes.Node() if b.Visited(from) { continue } if before != nil { before() } b.Walk(g, from, func(n graph.Node, _ int) bool { if during != nil { during(n) } return false }) if after != nil { after() } } } // Visited returned whether the node n was visited during a traverse. func (b *BreadthFirst) Visited(n graph.Node) bool { return b.visited.Has(n.ID()) } // Reset resets the state of the traverser for reuse. func (b *BreadthFirst) Reset() { b.queue.Reset() b.visited = nil } // DepthFirst implements stateful depth-first graph traversal. type DepthFirst struct { // Visit is called on all nodes on their first visit. Visit func(graph.Node) // Traverse is called on all edges that may be traversed // during the walk. This includes edges that would hop to // an already visited node. // // The value returned by Traverse determines whether an // edge can be traversed during the walk. Traverse func(graph.Edge) bool stack linear.NodeStack visited set.Int64s } // Walk performs a depth-first traversal of the graph g starting from the given node, // depending on the Traverse field and the until parameter if they are non-nil. // The traversal follows edges for which Traverse(edge) is true and returns the first node // for which until(node) is true. During the traversal, if the Visit field is non-nil, it // is called with each node the first time it is visited. func (d *DepthFirst) Walk(g Graph, from graph.Node, until func(graph.Node) bool) graph.Node { if d.visited == nil { d.visited = make(set.Int64s) } d.stack.Push(from) for d.stack.Len() != 0 { u := d.stack.Pop() uid := u.ID() if d.visited.Has(uid) { continue } d.visited.Add(uid) if d.Visit != nil { d.Visit(u) } if until != nil && until(u) { return u } to := g.From(uid) for to.Next() { v := to.Node() vid := v.ID() if d.Traverse != nil && !d.Traverse(g.Edge(uid, vid)) { continue } d.stack.Push(v) } } return nil } // WalkAll calls Walk for each unvisited node of the graph g using edges independent // of their direction. The functions before and after are called prior to commencing // and after completing each walk if they are non-nil respectively. The function // during is called on each node as it is traversed. func (d *DepthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) { d.Reset() nodes := g.Nodes() for nodes.Next() { from := nodes.Node() if d.Visited(from) { continue } if before != nil { before() } d.Walk(g, from, func(n graph.Node) bool { if during != nil { during(n) } return false }) if after != nil { after() } } } // Visited returned whether the node n was visited during a traverse. func (d *DepthFirst) Visited(n graph.Node) bool { return d.visited.Has(n.ID()) } // Reset resets the state of the traverser for reuse. func (d *DepthFirst) Reset() { d.stack = d.stack[:0] d.visited = nil } golang-gonum-v1-gonum-0.14.0/graph/traverse/traverse_test.go000066400000000000000000000261571450372207100240260ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package traverse import ( "fmt" "reflect" "strings" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/graphs/gen" "gonum.org/v1/gonum/graph/internal/ordered" "gonum.org/v1/gonum/graph/simple" ) var ( // batageljZaversnikGraph is the example graph from // figure 1 of http://arxiv.org/abs/cs/0310049v1 batageljZaversnikGraph = []intset{ 0: nil, 1: linksTo(2, 3), 2: linksTo(4), 3: linksTo(4), 4: linksTo(5), 5: nil, 6: linksTo(7, 8, 14), 7: linksTo(8, 11, 12, 14), 8: linksTo(14), 9: linksTo(11), 10: linksTo(11), 11: linksTo(12), 12: linksTo(18), 13: linksTo(14, 15), 14: linksTo(15, 17), 15: linksTo(16, 17), 16: nil, 17: linksTo(18, 19, 20), 18: linksTo(19, 20), 19: linksTo(20), 20: nil, } // wpBronKerboschGraph is the example given in the Bron-Kerbosch article on wikipedia (renumbered). // http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858 wpBronKerboschGraph = []intset{ 0: linksTo(1, 4), 1: linksTo(2, 4), 2: linksTo(3), 3: linksTo(4, 5), 4: nil, 5: nil, } // g1595 is the graph shown in https://github.com/gonum/gonum/issues/1595 with the addition // of an unconnected 0 node (due to limitations of intset). g1595 = []intset{ 0: nil, 1: linksTo(2, 4), 2: linksTo(3), 3: nil, 4: nil, } ) var breadthFirstTests = []struct { g []intset from graph.Node edge func(graph.Edge) bool until func(graph.Node, int) bool final map[graph.Node]bool want [][]int64 }{ { g: wpBronKerboschGraph, from: simple.Node(1), final: map[graph.Node]bool{nil: true}, want: [][]int64{ {1}, {0, 2, 4}, {3}, {5}, }, }, { g: wpBronKerboschGraph, edge: func(e graph.Edge) bool { // Do not traverse an edge between 3 and 5. return (e.From().ID() != 3 || e.To().ID() != 5) && (e.From().ID() != 5 || e.To().ID() != 3) }, from: simple.Node(1), final: map[graph.Node]bool{nil: true}, want: [][]int64{ {1}, {0, 2, 4}, {3}, }, }, { g: wpBronKerboschGraph, from: simple.Node(1), until: func(n graph.Node, _ int) bool { return n == simple.Node(3) }, final: map[graph.Node]bool{simple.Node(3): true}, want: [][]int64{ {1}, {0, 2, 4}, }, }, { g: batageljZaversnikGraph, from: simple.Node(13), final: map[graph.Node]bool{nil: true}, want: [][]int64{ {13}, {14, 15}, {6, 7, 8, 16, 17}, {11, 12, 18, 19, 20}, {9, 10}, }, }, { g: batageljZaversnikGraph, from: simple.Node(13), until: func(_ graph.Node, d int) bool { return d > 2 }, final: map[graph.Node]bool{ simple.Node(11): true, simple.Node(12): true, simple.Node(18): true, simple.Node(19): true, simple.Node(20): true, }, want: [][]int64{ {13}, {14, 15}, {6, 7, 8, 16, 17}, }, }, } func TestBreadthFirst(t *testing.T) { for i, test := range breadthFirstTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } w := BreadthFirst{ Traverse: test.edge, } var got [][]int64 final := w.Walk(g, test.from, func(n graph.Node, d int) bool { if test.until != nil && test.until(n, d) { return true } if d >= len(got) { got = append(got, []int64(nil)) } got[d] = append(got[d], n.ID()) return false }) if !test.final[final] { t.Errorf("unexpected final node for test %d:\ngot: %v\nwant: %v", i, final, test.final) } for _, l := range got { ordered.Int64s(l) } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected BFS level structure for test %d:\ngot: %v\nwant: %v", i, got, test.want) } } } var depthFirstTests = []struct { g []intset from graph.Node edge func(graph.Edge) bool until func(graph.Node) bool final map[graph.Node]bool want [][]int64 }{ { g: wpBronKerboschGraph, from: simple.Node(1), final: map[graph.Node]bool{nil: true}, want: [][]int64{ {1, 0, 4, 3, 5, 2}, {1, 0, 4, 3, 2, 5}, {1, 2, 3, 4, 0, 5}, {1, 2, 3, 5, 4, 0}, {1, 4, 0, 3, 5, 2}, {1, 4, 0, 3, 2, 5}, {1, 4, 3, 2, 5, 0}, {1, 4, 3, 5, 2, 0}, }, }, { g: wpBronKerboschGraph, edge: func(e graph.Edge) bool { // Do not traverse an edge between 3 and 5. return (e.From().ID() != 3 || e.To().ID() != 5) && (e.From().ID() != 5 || e.To().ID() != 3) }, from: simple.Node(1), final: map[graph.Node]bool{nil: true}, want: [][]int64{ {1, 0, 4, 3, 2}, {1, 2, 3, 4, 0}, {1, 4, 0, 3, 2}, {1, 4, 3, 2, 0}, }, }, { g: wpBronKerboschGraph, from: simple.Node(1), until: func(n graph.Node) bool { return n == simple.Node(3) }, final: map[graph.Node]bool{simple.Node(3): true}, }, { g: batageljZaversnikGraph, from: simple.Node(0), final: map[graph.Node]bool{nil: true}, want: [][]int64{{0}}, }, { g: batageljZaversnikGraph, from: simple.Node(3), final: map[graph.Node]bool{nil: true}, want: [][]int64{ {3, 1, 2, 4, 5}, {3, 4, 2, 1, 5}, {3, 4, 5, 2, 1}, }, }, { g: g1595, from: simple.Node(1), final: map[graph.Node]bool{nil: true}, want: [][]int64{ {1, 4, 2, 3}, {1, 2, 3, 4}, }, }, } func TestDepthFirst(t *testing.T) { for i, test := range depthFirstTests { g := simple.NewUndirectedGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } w := DepthFirst{ Traverse: test.edge, } var got []int64 final := w.Walk(g, test.from, func(n graph.Node) bool { if test.until != nil && test.until(n) { return true } got = append(got, n.ID()) return false }) if !test.final[final] { t.Errorf("unexpected final node for test %d:\ngot: %v\nwant: %v", i, final, test.final) } var ok bool for _, want := range test.want { if reflect.DeepEqual(got, want) { ok = true break } } if test.want != nil && !ok { var wanted strings.Builder for _, w := range test.want { fmt.Fprintf(&wanted, " %v\n", w) } t.Errorf("unexpected DFS traversed nodes for test %d:\ngot: %v\nwant one of:\n%s", i, got, &wanted) } } } var walkAllTests = []struct { g []intset edge func(graph.Edge) bool want [][]int64 }{ { g: batageljZaversnikGraph, want: [][]int64{ {0}, {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, }, }, { g: batageljZaversnikGraph, edge: func(e graph.Edge) bool { // Do not traverse an edge between 3 and 5. return (e.From().ID() != 4 || e.To().ID() != 5) && (e.From().ID() != 5 || e.To().ID() != 4) }, want: [][]int64{ {0}, {1, 2, 3, 4}, {5}, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, }, }, } func TestWalkAll(t *testing.T) { for i, test := range walkAllTests { g := simple.NewUndirectedGraph() for u, e := range test.g { if g.Node(int64(u)) == nil { g.AddNode(simple.Node(u)) } for v := range e { if g.Node(int64(v)) == nil { g.AddNode(simple.Node(v)) } g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } type walker interface { WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) } for _, w := range []walker{ &BreadthFirst{}, &DepthFirst{}, } { var ( c []graph.Node cc [][]graph.Node ) switch w := w.(type) { case *BreadthFirst: w.Traverse = test.edge case *DepthFirst: w.Traverse = test.edge default: panic(fmt.Sprintf("bad walker type: %T", w)) } during := func(n graph.Node) { c = append(c, n) } after := func() { cc = append(cc, []graph.Node(nil)) cc[len(cc)-1] = append(cc[len(cc)-1], c...) c = c[:0] } w.WalkAll(g, nil, after, during) got := make([][]int64, len(cc)) for j, c := range cc { ids := make([]int64, len(c)) for k, n := range c { ids[k] = n.ID() } ordered.Int64s(ids) got[j] = ids } ordered.BySliceValues(got) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected connected components for test %d using %T:\ngot: %v\nwant:%v", i, w, got, test.want) } } } } // intset is an integer set. type intset map[int]struct{} func linksTo(i ...int) intset { if len(i) == 0 { return nil } s := make(intset) for _, v := range i { s[v] = struct{}{} } return s } var ( gnpUndirected_10_tenth = gnpUndirected(10, 0.1) gnpUndirected_100_tenth = gnpUndirected(100, 0.1) gnpUndirected_1000_tenth = gnpUndirected(1000, 0.1) gnpUndirected_10_half = gnpUndirected(10, 0.5) gnpUndirected_100_half = gnpUndirected(100, 0.5) gnpUndirected_1000_half = gnpUndirected(1000, 0.5) ) func gnpUndirected(n int, p float64) graph.Undirected { g := simple.NewUndirectedGraph() err := gen.Gnp(g, n, p, nil) if err != nil { panic(fmt.Sprintf("traverse: bad test: %v", err)) } return g } func benchmarkWalkAllBreadthFirst(b *testing.B, g graph.Undirected) { n := g.Nodes().Len() b.ResetTimer() var bft BreadthFirst for i := 0; i < b.N; i++ { bft.WalkAll(g, nil, nil, nil) } if len(bft.visited) != n { b.Fatalf("unexpected number of nodes visited: want: %d got %d", n, len(bft.visited)) } } func BenchmarkWalkAllBreadthFirstGnp_10_tenth(b *testing.B) { benchmarkWalkAllBreadthFirst(b, gnpUndirected_10_tenth) } func BenchmarkWalkAllBreadthFirstGnp_100_tenth(b *testing.B) { benchmarkWalkAllBreadthFirst(b, gnpUndirected_100_tenth) } func BenchmarkWalkAllBreadthFirstGnp_1000_tenth(b *testing.B) { benchmarkWalkAllBreadthFirst(b, gnpUndirected_1000_tenth) } func BenchmarkWalkAllBreadthFirstGnp_10_half(b *testing.B) { benchmarkWalkAllBreadthFirst(b, gnpUndirected_10_half) } func BenchmarkWalkAllBreadthFirstGnp_100_half(b *testing.B) { benchmarkWalkAllBreadthFirst(b, gnpUndirected_100_half) } func BenchmarkWalkAllBreadthFirstGnp_1000_half(b *testing.B) { benchmarkWalkAllBreadthFirst(b, gnpUndirected_1000_half) } func benchmarkWalkAllDepthFirst(b *testing.B, g graph.Undirected) { n := g.Nodes().Len() b.ResetTimer() var dft DepthFirst for i := 0; i < b.N; i++ { dft.WalkAll(g, nil, nil, nil) } if len(dft.visited) != n { b.Fatalf("unexpected number of nodes visited: want: %d got %d", n, len(dft.visited)) } } func BenchmarkWalkAllDepthFirstGnp_10_tenth(b *testing.B) { benchmarkWalkAllDepthFirst(b, gnpUndirected_10_tenth) } func BenchmarkWalkAllDepthFirstGnp_100_tenth(b *testing.B) { benchmarkWalkAllDepthFirst(b, gnpUndirected_100_tenth) } func BenchmarkWalkAllDepthFirstGnp_1000_tenth(b *testing.B) { benchmarkWalkAllDepthFirst(b, gnpUndirected_1000_tenth) } func BenchmarkWalkAllDepthFirstGnp_10_half(b *testing.B) { benchmarkWalkAllDepthFirst(b, gnpUndirected_10_half) } func BenchmarkWalkAllDepthFirstGnp_100_half(b *testing.B) { benchmarkWalkAllDepthFirst(b, gnpUndirected_100_half) } func BenchmarkWalkAllDepthFirstGnp_1000_half(b *testing.B) { benchmarkWalkAllDepthFirst(b, gnpUndirected_1000_half) } golang-gonum-v1-gonum-0.14.0/graph/undirect.go000066400000000000000000000176661450372207100211230ustar00rootroot00000000000000// 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 graph // Undirect converts a directed graph to an undirected graph. type Undirect struct { G Directed } var _ Undirected = Undirect{} // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g Undirect) Node(id int64) Node { return g.G.Node(id) } // Nodes returns all the nodes in the graph. func (g Undirect) Nodes() Nodes { return g.G.Nodes() } // From returns all nodes in g that can be reached directly from u. func (g Undirect) From(uid int64) Nodes { if g.G.Node(uid) == nil { return Empty } return newNodeIteratorPair(g.G.From(uid), g.G.To(uid)) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g Undirect) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) } // 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. // If an edge exists, the Edge returned is an EdgePair. The weight of // the edge is determined by applying the Merge func to the weights of the // edges between u and v. func (g Undirect) Edge(uid, vid int64) Edge { return g.EdgeBetween(uid, vid) } // EdgeBetween returns the edge between nodes x and y. If an edge exists, the // Edge returned is an EdgePair. The weight of the edge is determined by // applying the Merge func to the weights of edges between x and y. func (g Undirect) EdgeBetween(xid, yid int64) Edge { fe := g.G.Edge(xid, yid) re := g.G.Edge(yid, xid) if fe == nil && re == nil { return nil } return EdgePair{fe, re} } // UndirectWeighted converts a directed weighted graph to an undirected weighted graph, // resolving edge weight conflicts. type UndirectWeighted struct { G WeightedDirected // Absent is the value used to // represent absent edge weights // passed to Merge if the reverse // edge is present. Absent float64 // Merge defines how discordant edge // weights in G are resolved. A merge // is performed if at least one edge // exists between the nodes being // considered. The edges corresponding // to the two weights are also passed, // in the same order. // The order of weight parameters // passed to Merge is not defined, so // the function should be commutative. // If Merge is nil, the arithmetic // mean is used to merge weights. Merge func(x, y float64, xe, ye Edge) float64 } var ( _ Undirected = UndirectWeighted{} _ WeightedUndirected = UndirectWeighted{} ) // Node returns the node with the given ID if it exists in the graph, // and nil otherwise. func (g UndirectWeighted) Node(id int64) Node { return g.G.Node(id) } // Nodes returns all the nodes in the graph. func (g UndirectWeighted) Nodes() Nodes { return g.G.Nodes() } // From returns all nodes in g that can be reached directly from u. func (g UndirectWeighted) From(uid int64) Nodes { if g.G.Node(uid) == nil { return Empty } return newNodeIteratorPair(g.G.From(uid), g.G.To(uid)) } // HasEdgeBetween returns whether an edge exists between nodes x and y. func (g UndirectWeighted) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) } // 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. // If an edge exists, the Edge returned is an EdgePair. The weight of // the edge is determined by applying the Merge func to the weights of the // edges between u and v. func (g UndirectWeighted) Edge(uid, vid int64) Edge { return g.WeightedEdgeBetween(uid, vid) } // 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. // If an edge exists, the Edge returned is an EdgePair. The weight of // the edge is determined by applying the Merge func to the weights of the // edges between u and v. func (g UndirectWeighted) WeightedEdge(uid, vid int64) WeightedEdge { return g.WeightedEdgeBetween(uid, vid) } // EdgeBetween returns the edge between nodes x and y. If an edge exists, the // Edge returned is an EdgePair. The weight of the edge is determined by // applying the Merge func to the weights of edges between x and y. func (g UndirectWeighted) EdgeBetween(xid, yid int64) Edge { return g.WeightedEdgeBetween(xid, yid) } // WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the // Edge returned is an EdgePair. The weight of the edge is determined by // applying the Merge func to the weights of edges between x and y. func (g UndirectWeighted) WeightedEdgeBetween(xid, yid int64) WeightedEdge { fe := g.G.Edge(xid, yid) re := g.G.Edge(yid, xid) if fe == nil && re == nil { return nil } f, ok := g.G.Weight(xid, yid) if !ok { f = g.Absent } r, ok := g.G.Weight(yid, xid) if !ok { r = g.Absent } var w float64 if g.Merge == nil { w = (f + r) / 2 } else { w = g.Merge(f, r, fe, re) } return WeightedEdgePair{EdgePair: [2]Edge{fe, re}, W: w} } // 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 the internal node weight is returned. If there is no joining // edge between the two nodes the weight value returned is zero. Weight returns true if an edge // exists between x and y or if x and y have the same ID, false otherwise. func (g UndirectWeighted) Weight(xid, yid int64) (w float64, ok bool) { fe := g.G.Edge(xid, yid) re := g.G.Edge(yid, xid) f, fOk := g.G.Weight(xid, yid) if !fOk { f = g.Absent } r, rOK := g.G.Weight(yid, xid) if !rOK { r = g.Absent } ok = fOk || rOK if g.Merge == nil { return (f + r) / 2, ok } return g.Merge(f, r, fe, re), ok } // EdgePair is an opposed pair of directed edges. type EdgePair [2]Edge // From returns the from node of the first non-nil edge, or nil. func (e EdgePair) From() Node { if e[0] != nil { return e[0].From() } else if e[1] != nil { return e[1].From() } return nil } // To returns the to node of the first non-nil edge, or nil. func (e EdgePair) To() Node { if e[0] != nil { return e[0].To() } else if e[1] != nil { return e[1].To() } return nil } // ReversedEdge returns a new Edge with the end point of the // edges in the pair swapped. func (e EdgePair) ReversedEdge() Edge { if e[0] != nil { e[0] = e[0].ReversedEdge() } if e[1] != nil { e[1] = e[1].ReversedEdge() } return e } // WeightedEdgePair is an opposed pair of directed edges. type WeightedEdgePair struct { EdgePair W float64 } // ReversedEdge returns a new Edge with the end point of the // edges in the pair swapped. func (e WeightedEdgePair) ReversedEdge() Edge { e.EdgePair = e.EdgePair.ReversedEdge().(EdgePair) return e } // Weight returns the merged edge weights of the two edges. func (e WeightedEdgePair) Weight() float64 { return e.W } // nodeIteratorPair combines two Nodes to produce a single stream of // unique nodes. type nodeIteratorPair struct { a, b Nodes curr Node idx, cnt int // unique indicates the node in b with the key ID is unique. unique map[int64]bool } func newNodeIteratorPair(a, b Nodes) *nodeIteratorPair { n := nodeIteratorPair{a: a, b: b, unique: make(map[int64]bool)} for n.b.Next() { n.unique[n.b.Node().ID()] = true n.cnt++ } n.b.Reset() for n.a.Next() { if _, ok := n.unique[n.a.Node().ID()]; !ok { n.cnt++ } n.unique[n.a.Node().ID()] = false } n.a.Reset() return &n } func (n *nodeIteratorPair) Len() int { return n.cnt - n.idx } func (n *nodeIteratorPair) Next() bool { if n.a.Next() { n.idx++ n.curr = n.a.Node() return true } for n.b.Next() { if n.unique[n.b.Node().ID()] { n.idx++ n.curr = n.b.Node() return true } } n.curr = nil return false } func (n *nodeIteratorPair) Node() Node { return n.curr } func (n *nodeIteratorPair) Reset() { n.idx = 0 n.curr = nil n.a.Reset() n.b.Reset() } golang-gonum-v1-gonum-0.14.0/graph/undirect_test.go000066400000000000000000000136411450372207100221470ustar00rootroot00000000000000// 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 graph_test import ( "math" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/iterator" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/mat" ) type weightedDirectedBuilder interface { graph.WeightedBuilder graph.WeightedDirected } var weightedDirectedGraphs = []struct { skipUnweighted bool g func() weightedDirectedBuilder edges []simple.WeightedEdge absent float64 merge func(x, y float64, xe, ye graph.Edge) float64 want mat.Matrix }{ { g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 2}, {F: simple.Node(1), T: simple.Node(0), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, }, want: mat.NewSymDense(3, []float64{ 0, (1. + 2.) / 2., 0, (1. + 2.) / 2., 0, 1. / 2., 0, 1. / 2., 0, }), }, { g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 2}, {F: simple.Node(1), T: simple.Node(0), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, }, absent: 1, merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Sqrt(x * y) }, want: mat.NewSymDense(3, []float64{ 0, math.Sqrt(1 * 2), 0, math.Sqrt(1 * 2), 0, math.Sqrt(1 * 1), 0, math.Sqrt(1 * 1), 0, }), }, { skipUnweighted: true, // The min merge function cannot be used in the unweighted case. g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 2}, {F: simple.Node(1), T: simple.Node(0), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, }, merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Min(x, y) }, want: mat.NewSymDense(3, []float64{ 0, math.Min(1, 2), 0, math.Min(1, 2), 0, math.Min(1, 0), 0, math.Min(1, 0), 0, }), }, { g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 2}, {F: simple.Node(1), T: simple.Node(0), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, }, merge: func(x, y float64, xe, ye graph.Edge) float64 { if xe == nil { return y } if ye == nil { return x } return math.Min(x, y) }, want: mat.NewSymDense(3, []float64{ 0, math.Min(1, 2), 0, math.Min(1, 2), 0, 1, 0, 1, 0, }), }, { g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, edges: []simple.WeightedEdge{ {F: simple.Node(0), T: simple.Node(1), W: 2}, {F: simple.Node(1), T: simple.Node(0), W: 1}, {F: simple.Node(1), T: simple.Node(2), W: 1}, }, merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Max(x, y) }, want: mat.NewSymDense(3, []float64{ 0, math.Max(1, 2), 0, math.Max(1, 2), 0, math.Max(1, 0), 0, math.Max(1, 0), 0, }), }, } func TestUndirect(t *testing.T) { for i, test := range weightedDirectedGraphs { if test.skipUnweighted { continue } g := test.g() for _, e := range test.edges { g.SetWeightedEdge(e) } src := graph.Undirect{G: g} nodes := graph.NodesOf(src.Nodes()) dst := simple.NewUndirectedMatrixFrom(nodes, 0, 0, 0) for _, u := range nodes { for _, v := range graph.NodesOf(src.From(u.ID())) { dst.SetEdge(src.Edge(u.ID(), v.ID())) } } want := unit{test.want} if !mat.Equal(dst.Matrix(), want) { t.Errorf("unexpected result for case %d:\ngot:\n%.4v\nwant:\n%.4v", i, mat.Formatted(dst.Matrix()), mat.Formatted(want), ) } } } func TestUndirectWeighted(t *testing.T) { for i, test := range weightedDirectedGraphs { g := test.g() for _, e := range test.edges { g.SetWeightedEdge(e) } src := graph.UndirectWeighted{G: g, Absent: test.absent, Merge: test.merge} nodes := graph.NodesOf(src.Nodes()) dst := simple.NewUndirectedMatrixFrom(nodes, 0, 0, 0) for _, u := range nodes { for _, v := range graph.NodesOf(src.From(u.ID())) { dst.SetWeightedEdge(src.WeightedEdge(u.ID(), v.ID())) } } if !mat.Equal(dst.Matrix(), test.want) { t.Errorf("unexpected result for case %d:\ngot:\n%.4v\nwant:\n%.4v", i, mat.Formatted(dst.Matrix()), mat.Formatted(test.want), ) } } } type unit struct { mat.Matrix } func (m unit) At(i, j int) float64 { v := m.Matrix.At(i, j) if v == 0 { return 0 } return 1 } var nodeIteratorPairTests = []struct { a, b graph.Nodes len int }{ {a: graph.Empty, b: graph.Empty, len: 0}, {a: iterator.NewOrderedNodes(nil), b: iterator.NewOrderedNodes(nil), len: 0}, {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), b: graph.Empty, len: 1}, {a: graph.Empty, b: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), len: 1}, {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), len: 1}, {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), len: 2}, {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0), simple.Node(1)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), len: 2}, {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(0), simple.Node(1)}), len: 2}, } func TestNodeIteratorPair(t *testing.T) { for _, test := range nodeIteratorPairTests { it := graph.NewNodeIteratorPair(test.a, test.b) for i := 0; i < 2; i++ { n := it.Len() if n != test.len { t.Errorf("unexpected length of iterator construction/reset: got:%d want:%d", n, test.len) } for it.Next() { n-- } if n != 0 { t.Errorf("unexpected remaining nodes after iterator completion: got:%d want:0", n) } it.Reset() } } } golang-gonum-v1-gonum-0.14.0/integrate/000077500000000000000000000000001450372207100176205ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/integrate/README.md000066400000000000000000000006141450372207100211000ustar00rootroot00000000000000# Gonum integrate [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/integrate)](https://pkg.go.dev/gonum.org/v1/gonum/integrate) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/integrate?status.svg)](https://godocs.io/gonum.org/v1/gonum/integrate) Package integrate provides numerical evaluation of definite integrals of single-variable functions for the Go programming language. golang-gonum-v1-gonum-0.14.0/integrate/doc.go000066400000000000000000000005101450372207100207100ustar00rootroot00000000000000// Copyright ©2016 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 integrate provides functions to compute an integral given a // specific list of evaluations. package integrate // import "gonum.org/v1/gonum/integrate" golang-gonum-v1-gonum-0.14.0/integrate/quad/000077500000000000000000000000001450372207100205525ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/integrate/quad/doc.go000066400000000000000000000005021450372207100216430ustar00rootroot00000000000000// 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 quad provides numerical evaluation of definite integrals of single-variable functions. package quad // import "gonum.org/v1/gonum/integrate/quad" golang-gonum-v1-gonum-0.14.0/integrate/quad/example_test.go000066400000000000000000000025271450372207100236010ustar00rootroot00000000000000// 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 quad_test import ( "fmt" "math" "runtime" "gonum.org/v1/gonum/integrate/quad" "gonum.org/v1/gonum/stat/distuv" ) func Example() { fmt.Println("Evaluate the expected value of x^2 + 3 under a Weibull distribution") f := func(x float64) float64 { d := distuv.Weibull{Lambda: 1, K: 1.5} return (x*x + 3) * d.Prob(x) } ev := quad.Fixed(f, 0, math.Inf(1), 10, nil, 0) fmt.Printf("EV with 10 points = %0.6v\n", ev) ev = quad.Fixed(f, 0, math.Inf(1), 30, nil, 0) fmt.Printf("EV with 30 points = %0.6v\n", ev) ev = quad.Fixed(f, 0, math.Inf(1), 100, nil, 0) fmt.Printf("EV with 100 points = %0.6v\n", ev) ev = quad.Fixed(f, 0, math.Inf(1), 10000, nil, 0) fmt.Printf("EV with 10000 points = %0.6v\n\n", ev) fmt.Println("Estimate using parallel evaluations of f.") concurrent := runtime.GOMAXPROCS(0) ev = quad.Fixed(f, 0, math.Inf(1), 100, nil, concurrent) fmt.Printf("EV = %0.6v\n", ev) // Output: // Evaluate the expected value of x^2 + 3 under a Weibull distribution // EV with 10 points = 4.20175 // EV with 30 points = 4.19066 // EV with 100 points = 4.19064 // EV with 10000 points = 4.19064 // // Estimate using parallel evaluations of f. // EV = 4.19064 } golang-gonum-v1-gonum-0.14.0/integrate/quad/hermite.go000066400000000000000000000236511450372207100225450ustar00rootroot00000000000000// Copyright ©2016 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 quad import ( "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mathext" ) // Hermite generates sample locations and weights for performing quadrature with // a squared-exponential weight // // int_-inf^inf e^(-x^2) f(x) dx . type Hermite struct{} func (h Hermite) FixedLocations(x, weight []float64, min, max float64) { // TODO(btracey): Implement the case where x > 20, x < 200 so that we don't // need to store all of that data. // Algorithm adapted from Chebfun http://www.chebfun.org/. // // References: // Algorithm: // G. H. Golub and J. A. Welsch, "Calculation of Gauss quadrature rules", // Math. Comp. 23:221-230, 1969. // A. Glaser, X. Liu and V. Rokhlin, "A fast algorithm for the // calculation of the roots of special functions", SIAM Journal // on Scientific Computing", 29(4):1420-1438:, 2007. // A. Townsend, T. Trogdon, and S.Olver, Fast computation of Gauss quadrature // nodes and weights on the whole real line, IMA J. Numer. Anal., 36: 337–358, // 2016. http://arxiv.org/abs/1410.5286 if len(x) != len(weight) { panic("hermite: slice length mismatch") } if min >= max { panic("hermite: min >= max") } if !math.IsInf(min, -1) || !math.IsInf(max, 1) { panic("hermite: non-infinite bound") } h.locations(x, weight) } func (h Hermite) locations(x, weights []float64) { n := len(x) switch { case 0 < n && n <= 200: copy(x, xCacheHermite[n-1]) copy(weights, wCacheHermite[n-1]) case n > 200: h.locationsAsy(x, weights) } } // Algorithm adapted from Chebfun http://www.chebfun.org/. Specific code // https://github.com/chebfun/chebfun/blob/development/hermpts.m. // Original Copyright Notice: /* Copyright (c) 2015, The Chancellor, Masters and Scholars of the University of Oxford, and the Chebfun Developers. 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 University of Oxford nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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. */ // locationAsy returns the node locations and weights of a Hermite quadrature rule // with len(x) points. func (h Hermite) locationsAsy(x, w []float64) { // A. Townsend, T. Trogdon, and S.Olver, Fast computation of Gauss quadrature // nodes and weights the whole real line, IMA J. Numer. Anal., // 36: 337–358, 2016. http://arxiv.org/abs/1410.5286 // Find the positive locations and weights. n := len(x) l := n / 2 xa := x[l:] wa := w[l:] for i := range xa { xa[i], wa[i] = h.locationsAsy0(i, n) } // Flip around zero -- copy the negative x locations with the corresponding // weights. if n%2 == 0 { l-- } for i, v := range xa { x[l-i] = -v } for i, v := range wa { w[l-i] = v } sumW := floats.Sum(w) c := math.SqrtPi / sumW floats.Scale(c, w) } // locationsAsy0 returns the location and weight for location i in an n-point // quadrature rule. The rule is symmetric, so i should be <= n/2 + n%2. func (h Hermite) locationsAsy0(i, n int) (x, w float64) { const convTol = 1e-16 const convIter = 20 theta0 := h.hermiteInitialGuess(i, n) t0 := theta0 / math.Sqrt(2*float64(n)+1) theta0 = math.Acos(t0) sqrt2np1 := math.Sqrt(2*float64(n) + 1) var vali, dvali float64 for k := 0; k < convIter; k++ { vali, dvali = h.hermpolyAsyAiry(i, n, theta0) dt := -vali / (math.Sqrt2 * sqrt2np1 * dvali * math.Sin(theta0)) theta0 -= dt if math.Abs(theta0) < convTol { break } } x = sqrt2np1 * math.Cos(theta0) ders := x*vali + math.Sqrt2*dvali w = math.Exp(-x*x) / (ders * ders) return x, w } // hermpolyAsyAiry evaluates the Hermite polynomials using the Airy asymptotic // formula in theta-space. func (h Hermite) hermpolyAsyAiry(i, n int, t float64) (valVec, dvalVec float64) { musq := 2*float64(n) + 1 cosT := math.Cos(t) sinT := math.Sin(t) sin2T := 2 * cosT * sinT eta := 0.5*t - 0.25*sin2T chi := -math.Pow(3*eta/2, 2.0/3) phi := math.Pow(-chi/(sinT*sinT), 1.0/4) cnst := 2 * math.SqrtPi * math.Pow(musq, 1.0/6) * phi airy0 := real(mathext.AiryAi(complex(math.Pow(musq, 2.0/3)*chi, 0))) airy1 := real(mathext.AiryAiDeriv(complex(math.Pow(musq, 2.0/3)*chi, 0))) // Terms in 12.10.43: const ( a1 = 15.0 / 144 b1 = -7.0 / 5 * a1 a2 = 5.0 * 7 * 9 * 11.0 / 2.0 / 144.0 / 144.0 b2 = -13.0 / 11 * a2 a3 = 7.0 * 9 * 11 * 13 * 15 * 17 / 6.0 / 144.0 / 144.0 / 144.0 b3 = -19.0 / 17 * a3 ) // Pre-compute terms. cos2T := cosT * cosT cos3T := cos2T * cosT cos4T := cos3T * cosT cos5T := cos4T * cosT cos7T := cos5T * cos2T cos9T := cos7T * cos2T chi2 := chi * chi chi3 := chi2 * chi chi4 := chi3 * chi chi5 := chi4 * chi phi6 := math.Pow(phi, 6) phi12 := phi6 * phi6 phi18 := phi12 * phi6 // u polynomials in 12.10.9. u1 := (cos3T - 6*cosT) / 24.0 u2 := (-9*cos4T + 249*cos2T + 145) / 1152.0 u3 := (-4042*cos9T + 18189*cos7T - 28287*cos5T - 151995*cos3T - 259290*cosT) / 414720.0 val := airy0 B0 := -(phi6*u1 + a1) / chi2 val += B0 * airy1 / math.Pow(musq, 4.0/3) A1 := (phi12*u2 + b1*phi6*u1 + b2) / chi3 val += A1 * airy0 / (musq * musq) B1 := -(phi18*u3 + a1*phi12*u2 + a2*phi6*u1 + a3) / chi5 val += B1 * airy1 / math.Pow(musq, 4.0/3+2) val *= cnst // Derivative. eta = 0.5*t - 0.25*sin2T chi = -math.Pow(3*eta/2, 2.0/3) phi = math.Pow(-chi/(sinT*sinT), 1.0/4) cnst = math.Sqrt2 * math.SqrtPi * math.Pow(musq, 1.0/3) / phi // v polynomials in 12.10.10. v1 := (cos3T + 6*cosT) / 24 v2 := (15*cos4T - 327*cos2T - 143) / 1152 v3 := (259290*cosT + 238425*cos3T - 36387*cos5T + 18189*cos7T - 4042*cos9T) / 414720 C0 := -(phi6*v1 + b1) / chi dval := C0 * airy0 / math.Pow(musq, 2.0/3) dval += airy1 C1 := -(phi18*v3 + b1*phi12*v2 + b2*phi6*v1 + b3) / chi4 dval += C1 * airy0 / math.Pow(musq, 2.0/3+2) D1 := (phi12*v2 + a1*phi6*v1 + a2) / chi3 dval += D1 * airy1 / (musq * musq) dval *= cnst return val, dval } // hermiteInitialGuess returns the initial guess for node i in an n-point Hermite // quadrature rule. The rule is symmetric, so i should be <= n/2 + n%2. func (h Hermite) hermiteInitialGuess(i, n int) float64 { // There are two different formulas for the initial guesses of the hermite // quadrature locations. The first uses the Gatteschi formula and is good // near x = sqrt(n+0.5) // [1] L. Gatteschi, Asymptotics and bounds for the zeros of Laguerre // polynomials: a survey, J. Comput. Appl. Math., 144 (2002), pp. 7-27. // The second is the Tricomi initial guesses, good near x = 0. This is // equation 2.1 in [1] and is originally from // [2] F. G. Tricomi, Sugli zeri delle funzioni di cui si conosce una // rappresentazione asintotica, Ann. Mat. Pura Appl. 26 (1947), pp. 283-300. // If the number of points is odd, there is a quadrature point at 1, which // has an initial guess of 0. if n%2 == 1 { if i == 0 { return 0 } i-- } m := n / 2 a := -0.5 if n%2 == 1 { a = 0.5 } nu := 4*float64(m) + 2*a + 2 // Find the split between Gatteschi guesses and Tricomi guesses. p := 0.4985 + math.SmallestNonzeroFloat64 pidx := int(math.Floor(p * float64(n))) // Use the Tricomi initial guesses in the first half where x is nearer to zero. // Note: zeros of besselj(+/-.5,x) are integer and half-integer multiples of pi. if i < pidx { rhs := math.Pi * (4*float64(m) - 4*(float64(i)+1) + 3) / nu tnk := math.Pi / 2 for k := 0; k < 7; k++ { val := tnk - math.Sin(tnk) - rhs dval := 1 - math.Cos(tnk) dTnk := val / dval tnk -= dTnk if math.Abs(dTnk) < 1e-14 { break } } vc := math.Cos(tnk / 2) t := vc * vc return math.Sqrt(nu*t - (5.0/(4.0*(1-t)*(1-t))-1.0/(1-t)-1+3*a*a)/3/nu) } // Use Gatteschi guesses in the second half where x is nearer to sqrt(n+0.5) i = m - (i + 1) var ar float64 if i < len(airyRtsExact) { ar = airyRtsExact[i] } else { t := 3.0 / 8 * math.Pi * (4*(float64(i)+1) - 1) ar = math.Pow(t, 2.0/3) * (1 + 5.0/48*math.Pow(t, -2) - 5.0/36*math.Pow(t, -4) + 77125.0/82944*math.Pow(t, -6) - 108056875.0/6967296*math.Pow(t, -8) + 162375596875.0/334430208*math.Pow(t, -10)) } r := nu + math.Pow(2, 2.0/3)*ar*math.Pow(nu, 1.0/3) + 0.2*math.Pow(2, 4.0/3)*ar*ar*math.Pow(nu, -1.0/3) + (11.0/35-a*a-12.0/175*ar*ar*ar)/nu + (16.0/1575*ar+92.0/7875*math.Pow(ar, 4))*math.Pow(2, 2.0/3)*math.Pow(nu, -5.0/3) - (15152.0/3031875*math.Pow(ar, 5)+1088.0/121275*ar*ar)*math.Pow(2, 1.0/3)*math.Pow(nu, -7.0/3) if r < 0 { ar = 0 } else { ar = math.Sqrt(r) } return ar } // airyRtsExact are the first airy roots. var airyRtsExact = []float64{ -2.338107410459762, -4.087949444130970, -5.520559828095555, -6.786708090071765, -7.944133587120863, -9.022650853340979, -10.040174341558084, -11.008524303733260, -11.936015563236262, -12.828776752865757, } golang-gonum-v1-gonum-0.14.0/integrate/quad/hermite_data.go000066400000000000000000035647721450372207100235570ustar00rootroot00000000000000// Copyright ©2016 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 quad // xCache computed from Chebfun. var xCacheHermite = [][]float64{ {0.0000000000000000e+00}, {-7.0710678118654757e-01, 7.0710678118654757e-01}, {-1.2247448713915887e+00, 0.0000000000000000e+00, 1.2247448713915887e+00}, {-1.6506801238857842e+00, -5.2464762327529035e-01, 5.2464762327529035e-01, 1.6506801238857842e+00}, {-2.0201828704560856e+00, -9.5857246461381873e-01, 0.0000000000000000e+00, 9.5857246461381873e-01, 2.0201828704560856e+00}, {-2.3506049736744914e+00, -1.3358490740136970e+00, -4.3607741192761657e-01, 4.3607741192761657e-01, 1.3358490740136970e+00, 2.3506049736744914e+00}, {-2.6519613568352316e+00, -1.6735516287674714e+00, -8.1628788285896481e-01, 0.0000000000000000e+00, 8.1628788285896481e-01, 1.6735516287674714e+00, 2.6519613568352316e+00}, {-2.9306374202572436e+00, -1.9816567566958443e+00, -1.1571937124467804e+00, -3.8118699020732216e-01, 3.8118699020732216e-01, 1.1571937124467804e+00, 1.9816567566958443e+00, 2.9306374202572436e+00}, {-3.1909932017815295e+00, -2.2665805845318427e+00, -1.4685532892166682e+00, -7.2355101875283767e-01, 0.0000000000000000e+00, 7.2355101875283767e-01, 1.4685532892166682e+00, 2.2665805845318427e+00, 3.1909932017815295e+00}, {-3.4361591188377378e+00, -2.5327316742327901e+00, -1.7566836492998816e+00, -1.0366108297895138e+00, -3.4290132722370481e-01, 3.4290132722370481e-01, 1.0366108297895138e+00, 1.7566836492998816e+00, 2.5327316742327901e+00, 3.4361591188377378e+00}, {-3.6684708465595812e+00, -2.7832900997816514e+00, -2.0259480158257550e+00, -1.3265570844949326e+00, -6.5680956688209979e-01, 0.0000000000000000e+00, 6.5680956688209979e-01, 1.3265570844949326e+00, 2.0259480158257550e+00, 2.7832900997816514e+00, 3.6684708465595812e+00}, {-3.8897248978697814e+00, -3.0206370251208896e+00, -2.2795070805010593e+00, -1.5976826351526043e+00, -9.4778839124016367e-01, -3.1424037625435908e-01, 3.1424037625435908e-01, 9.4778839124016367e-01, 1.5976826351526043e+00, 2.2795070805010593e+00, 3.0206370251208896e+00, 3.8897248978697814e+00}, {-4.1013375961786389e+00, -3.2466089783724090e+00, -2.5197356856782389e+00, -1.8531076516015121e+00, -1.2200550365907483e+00, -6.0576387917106034e-01, 0.0000000000000000e+00, 6.0576387917106034e-01, 1.2200550365907483e+00, 1.8531076516015121e+00, 2.5197356856782389e+00, 3.2466089783724090e+00, 4.1013375961786389e+00}, {-4.3044485704736335e+00, -3.4626569336022701e+00, -2.7484707249854017e+00, -2.0951832585077166e+00, -1.4766827311411406e+00, -8.7871378732939931e-01, -2.9174551067256199e-01, 2.9174551067256199e-01, 8.7871378732939931e-01, 1.4766827311411406e+00, 2.0951832585077166e+00, 2.7484707249854017e+00, 3.4626569336022701e+00, 4.3044485704736335e+00}, {-4.4999907073093910e+00, -3.6699503734044541e+00, -2.9671669279056028e+00, -2.3257324861738580e+00, -1.7199925751864888e+00, -1.1361155852109204e+00, -5.6506958325557588e-01, 0.0000000000000000e+00, 5.6506958325557588e-01, 1.1361155852109204e+00, 1.7199925751864888e+00, 2.3257324861738580e+00, 2.9671669279056028e+00, 3.6699503734044541e+00, 4.4999907073093910e+00}, {-4.6887389393058223e+00, -3.8694479048601238e+00, -3.1769991619799529e+00, -2.5462021578474796e+00, -1.9517879909162528e+00, -1.3802585391988815e+00, -8.2295144914465546e-01, -2.7348104613815244e-01, 2.7348104613815244e-01, 8.2295144914465546e-01, 1.3802585391988815e+00, 1.9517879909162528e+00, 2.5462021578474796e+00, 3.1769991619799529e+00, 3.8694479048601238e+00, 4.6887389393058223e+00}, {-4.8713451936744061e+00, -4.0619466758754772e+00, -3.3789320911414946e+00, -2.7577629157038897e+00, -2.1735028266666214e+00, -1.6129243142212311e+00, -1.0676487257434508e+00, -5.3163300134265479e-01, 0.0000000000000000e+00, 5.3163300134265479e-01, 1.0676487257434508e+00, 1.6129243142212311e+00, 2.1735028266666214e+00, 2.7577629157038897e+00, 3.3789320911414946e+00, 4.0619466758754772e+00, 4.8713451936744061e+00}, {-5.0483640088744668e+00, -4.2481178735681260e+00, -3.5737690684862655e+00, -2.9613775055316052e+00, -2.3862990891666858e+00, -1.8355316042616294e+00, -1.3009208583896172e+00, -7.7668291926741173e-01, -2.5826775051909689e-01, 2.5826775051909689e-01, 7.7668291926741173e-01, 1.3009208583896172e+00, 1.8355316042616294e+00, 2.3862990891666858e+00, 2.9613775055316052e+00, 3.5737690684862655e+00, 4.2481178735681260e+00, 5.0483640088744668e+00}, {-5.2202716905374844e+00, -4.4285328066037799e+00, -3.7621873519640201e+00, -3.1578488183476034e+00, -2.5911337897945423e+00, -2.0492317098506181e+00, -1.5241706193935327e+00, -1.0103683871343114e+00, -5.0352016342388828e-01, 0.0000000000000000e+00, 5.0352016342388828e-01, 1.0103683871343114e+00, 1.5241706193935327e+00, 2.0492317098506181e+00, 2.5911337897945423e+00, 3.1578488183476034e+00, 3.7621873519640201e+00, 4.4285328066037799e+00, 5.2202716905374844e+00}, {-5.3874808900112319e+00, -4.6036824495507451e+00, -3.9447640401156265e+00, -3.3478545673832172e+00, -2.7888060584281313e+00, -2.2549740020892761e+00, -1.7385377121165857e+00, -1.2340762153953231e+00, -7.3747372854539406e-01, -2.4534070830090132e-01, 2.4534070830090132e-01, 7.3747372854539406e-01, 1.2340762153953231e+00, 1.7385377121165857e+00, 2.2549740020892761e+00, 2.7888060584281313e+00, 3.3478545673832172e+00, 3.9447640401156265e+00, 4.6036824495507451e+00, 5.3874808900112319e+00}, {-5.5503518732646775e+00, -4.7739923434112193e+00, -4.1219955474918395e+00, -3.5319728771376777e+00, -2.9799912077045980e+00, -2.4535521245128376e+00, -1.9449629491862539e+00, -1.4489342506507319e+00, -9.6149963441836894e-01, -4.7945070707910747e-01, -0.0000000000000000e+00, 4.7945070707910747e-01, 9.6149963441836894e-01, 1.4489342506507319e+00, 1.9449629491862539e+00, 2.4535521245128376e+00, 2.9799912077045980e+00, 3.5319728771376777e+00, 4.1219955474918395e+00, 4.7739923434112193e+00, 5.5503518732646775e+00}, {-5.7092013532052626e+00, -4.9398341310601763e+00, -4.2943124805931614e+00, -3.7107015328778048e+00, -3.1652659092021374e+00, -2.6456374410581724e+00, -2.1442335927985341e+00, -1.6558743732864223e+00, -1.1767139584812445e+00, -7.0368609717000696e-01, -2.3417913993099065e-01, 2.3417913993099065e-01, 7.0368609717000696e-01, 1.1767139584812445e+00, 1.6558743732864223e+00, 2.1442335927985341e+00, 2.6456374410581724e+00, 3.1652659092021374e+00, 3.7107015328778048e+00, 4.2943124805931614e+00, 4.9398341310601763e+00, 5.7092013532052626e+00}, {-5.8643094989845714e+00, -5.1015346104766763e+00, -4.4620911737400064e+00, -3.8844727081061015e+00, -3.3451271599412244e+00, -2.8318037871261570e+00, -2.3370162114744559e+00, -1.8556770376713707e+00, -1.3840395856824952e+00, -9.1915146544256365e-01, -4.5853835006810478e-01, -0.0000000000000000e+00, 4.5853835006810478e-01, 9.1915146544256365e-01, 1.3840395856824952e+00, 1.8556770376713707e+00, 2.3370162114744559e+00, 2.8318037871261570e+00, 3.3451271599412244e+00, 3.8844727081061015e+00, 4.4620911737400064e+00, 5.1015346104766763e+00, 5.8643094989845714e+00}, {-6.0159255614257390e+00, -5.2593829276680442e+00, -4.6256627564237878e+00, -4.0536644024481490e+00, -3.5200068130345241e+00, -3.0125461375655647e+00, -2.5238810170114268e+00, -2.0490035736616985e+00, -1.5842500109616942e+00, -1.1267608176112451e+00, -6.7417110703721217e-01, -2.2441454747251557e-01, 2.2441454747251557e-01, 6.7417110703721217e-01, 1.1267608176112451e+00, 1.5842500109616942e+00, 2.0490035736616985e+00, 2.5238810170114268e+00, 3.0125461375655647e+00, 3.5200068130345241e+00, 4.0536644024481490e+00, 4.6256627564237878e+00, 5.2593829276680442e+00, 6.0159255614257390e+00}, {-6.1642724340524513e+00, -5.4136363552800333e+00, -4.7853203673522238e+00, -4.2186094443865612e+00, -3.6902828769983551e+00, -3.1882949244251044e+00, -2.7053202371730256e+00, -2.2364201302672808e+00, -1.7780011243371474e+00, -1.3272807020730839e+00, -8.8198275621382138e-01, -4.4014729864530827e-01, -0.0000000000000000e+00, 4.4014729864530827e-01, 8.8198275621382138e-01, 1.3272807020730839e+00, 1.7780011243371474e+00, 2.2364201302672808e+00, 2.7053202371730256e+00, 3.1882949244251044e+00, 3.6902828769983551e+00, 4.2186094443865612e+00, 4.7853203673522238e+00, 5.4136363552800333e+00, 6.1642724340524513e+00}, {-6.3095503856256920e+00, -5.5645249819501030e+00, -4.9413249572413793e+00, -4.3796026629833040e+00, -3.8562884199091489e+00, -3.3594271823508297e+00, -2.8817622195430865e+00, -2.4184157647737790e+00, -1.9658547856411364e+00, -1.5213615166519212e+00, -1.0827330110778832e+00, -6.4809521399344827e-01, -2.1577785624346338e-01, 2.1577785624346338e-01, 6.4809521399344827e-01, 1.0827330110778832e+00, 1.5213615166519212e+00, 1.9658547856411364e+00, 2.4184157647737790e+00, 2.8817622195430865e+00, 3.3594271823508297e+00, 3.8562884199091489e+00, 4.3796026629833040e+00, 4.9413249572413793e+00, 5.5645249819501030e+00, 6.3095503856256920e+00}, {-6.4519401407534707e+00, -5.7122555528165355e+00, -5.0939100031131836e+00, -4.5369066633724415e+00, -4.0183186704087381e+00, -3.5262753401343527e+00, -3.0535824198222552e+00, -2.5954163389108178e+00, -2.1482966453616275e+00, -1.7095607392603374e+00, -1.2770668173398578e+00, -8.4901134206010298e-01, -4.2380790054385303e-01, -0.0000000000000000e+00, 4.2380790054385303e-01, 8.4901134206010298e-01, 1.2770668173398578e+00, 1.7095607392603374e+00, 2.1482966453616275e+00, 2.5954163389108178e+00, 3.0535824198222552e+00, 3.5262753401343527e+00, 4.0183186704087381e+00, 4.5369066633724415e+00, 5.0939100031131836e+00, 5.7122555528165355e+00, 6.4519401407534707e+00}, {-6.5916054423677419e+00, -5.8570146413828503e+00, -5.2432853732029354e+00, -4.6907565239431177e+00, -4.1766367421292676e+00, -3.6891342384616794e+00, -3.2211120765614556e+00, -2.7677953529135935e+00, -2.3257498426564407e+00, -1.8923604968376853e+00, -1.4655372634574091e+00, -1.0435352737542081e+00, -6.2483671950520925e-01, -2.0806738269073688e-01, 2.0806738269073688e-01, 6.2483671950520925e-01, 1.0435352737542081e+00, 1.4655372634574091e+00, 1.8923604968376853e+00, 2.3257498426564407e+00, 2.7677953529135935e+00, 3.2211120765614556e+00, 3.6891342384616794e+00, 4.1766367421292676e+00, 4.6907565239431177e+00, 5.2432853732029354e+00, 5.8570146413828503e+00, 6.5916054423677419e+00}, {-6.7286951986088495e+00, -5.9989712894638192e+00, -5.3896405219667507e+00, -4.8413636510591642e+00, -4.3314782938191501e+00, -3.8482667922136202e+00, -3.3846451410922138e+00, -2.9358825042901264e+00, -2.4985856910194042e+00, -2.0701810760534278e+00, -1.6486229138923163e+00, -1.2322157550847530e+00, -8.1949868127091163e-01, -4.0916463639492873e-01, -0.0000000000000000e+00, 4.0916463639492873e-01, 8.1949868127091163e-01, 1.2322157550847530e+00, 1.6486229138923163e+00, 2.0701810760534278e+00, 2.4985856910194042e+00, 2.9358825042901264e+00, 3.3846451410922138e+00, 3.8482667922136202e+00, 4.3314782938191501e+00, 4.8413636510591642e+00, 5.3896405219667507e+00, 5.9989712894638192e+00, 6.7286951986088495e+00}, {-6.8633452935298900e+00, -6.1382792201239331e+00, -5.5331471515674950e+00, -4.9889189685899442e+00, -4.4830553570925176e+00, -4.0039086038612286e+00, -3.5444438731553496e+00, -3.0999705295864417e+00, -2.6671321245356170e+00, -2.2433914677615041e+00, -1.8267411436036880e+00, -1.4155278001981884e+00, -1.0083382710467235e+00, -6.0392105862555223e-01, -2.0112857654887151e-01, 2.0112857654887151e-01, 6.0392105862555223e-01, 1.0083382710467235e+00, 1.4155278001981884e+00, 1.8267411436036880e+00, 2.2433914677615041e+00, 2.6671321245356170e+00, 3.0999705295864417e+00, 3.5444438731553496e+00, 4.0039086038612286e+00, 4.4830553570925176e+00, 4.9889189685899442e+00, 5.5331471515674950e+00, 6.1382792201239331e+00, 6.8633452935298900e+00}, {-6.9956801237185395e+00, -6.2750787049428602e+00, -5.6739614446185875e+00, -5.1335955771123798e+00, -4.6315595063128594e+00, -4.1562717558181452e+00, -3.7007434032314697e+00, -3.2603207323135406e+00, -2.8316804533902054e+00, -2.4123177054804201e+00, -2.0002585489356388e+00, -1.5938858604721398e+00, -1.1918269983500462e+00, -7.9287697691530890e-01, -3.9594273647142297e-01, -0.0000000000000000e+00, 3.9594273647142297e-01, 7.9287697691530890e-01, 1.1918269983500462e+00, 1.5938858604721398e+00, 2.0002585489356388e+00, 2.4123177054804201e+00, 2.8316804533902054e+00, 3.2603207323135406e+00, 3.7007434032314697e+00, 4.1562717558181452e+00, 4.6315595063128594e+00, 5.1335955771123798e+00, 5.6739614446185875e+00, 6.2750787049428602e+00, 6.9956801237185395e+00}, {-7.1258139098307272e+00, -6.4094981492696599e+00, -5.8122259495159128e+00, -5.2755509865158796e+00, -4.7771645035025960e+00, -4.3055479533511987e+00, -3.8537554854714444e+00, -3.4171674928185705e+00, -2.9924908250023741e+00, -2.5772495377323170e+00, -2.1694991836061122e+00, -1.7676541094632017e+00, -1.3703764109528718e+00, -9.7650046358968279e-01, -5.8497876543593241e-01, -1.9484074156939934e-01, 1.9484074156939934e-01, 5.8497876543593241e-01, 9.7650046358968279e-01, 1.3703764109528718e+00, 1.7676541094632017e+00, 2.1694991836061122e+00, 2.5772495377323170e+00, 2.9924908250023741e+00, 3.4171674928185705e+00, 3.8537554854714444e+00, 4.3055479533511987e+00, 4.7771645035025960e+00, 5.2755509865158796e+00, 5.8122259495159128e+00, 6.4094981492696599e+00, 7.1258139098307272e+00}, {-7.2538518220151991e+00, -6.5416554457380762e+00, -5.9480711820871450e+00, -5.4149290026141923e+00, -4.9200285205950083e+00, -4.4519111488328269e+00, -4.0036716099569309e+00, -3.5707219802327179e+00, -3.1497966817038248e+00, -2.7384458243513548e+00, -2.3347511515295150e+00, -1.9371545818222065e+00, -1.5443482612431219e+00, -1.1552002041267895e+00, -7.6870137975886854e-01, -3.8392601450840907e-01, -0.0000000000000000e+00, 3.8392601450840907e-01, 7.6870137975886854e-01, 1.1552002041267895e+00, 1.5443482612431219e+00, 1.9371545818222065e+00, 2.3347511515295150e+00, 2.7384458243513548e+00, 3.1497966817038248e+00, 3.5707219802327179e+00, 4.0036716099569309e+00, 4.4519111488328269e+00, 4.9200285205950083e+00, 5.4149290026141923e+00, 5.9480711820871450e+00, 6.5416554457380762e+00, 7.2538518220151991e+00}, {-7.3798909504812453e+00, -6.6716591360701694e+00, -6.0816169939363158e+00, -5.5518613309887774e+00, -5.0602960186057615e+00, -4.5955197481081704e+00, -4.1506656029707809e+00, -3.7211752324761531e+00, -3.3038084315644154e+00, -2.8961389431744311e+00, -2.4962719408165470e+00, -2.1026736904673324e+00, -1.7140625533873379e+00, -1.3293355518847858e+00, -9.4751645803344731e-01, -5.6771726855487448e-01, -1.8910806052714246e-01, 1.8910806052714246e-01, 5.6771726855487448e-01, 9.4751645803344731e-01, 1.3293355518847858e+00, 1.7140625533873379e+00, 2.1026736904673324e+00, 2.4962719408165470e+00, 2.8961389431744311e+00, 3.3038084315644154e+00, 3.7211752324761531e+00, 4.1506656029707809e+00, 4.5955197481081704e+00, 5.0602960186057615e+00, 5.5518613309887774e+00, 6.0816169939363158e+00, 6.6716591360701694e+00, 7.3798909504812453e+00}, {-7.5040211464489355e+00, -6.7996094132841307e+00, -6.2129737476337166e+00, -5.6864689480904413e+00, -5.1980993461977523e+00, -4.7365184774132105e+00, -4.2948958144927625e+00, -3.8687007309691541e+00, -3.4547164957519905e+00, -3.0505384204304464e+00, -2.6542927811971722e+00, -2.2644675010425686e+00, -1.8798039887309170e+00, -1.4992244886117301e+00, -1.1217809907203027e+00, -7.4661763987986696e-01, -3.7294171704961682e-01, -0.0000000000000000e+00, 3.7294171704961682e-01, 7.4661763987986696e-01, 1.1217809907203027e+00, 1.4992244886117301e+00, 1.8798039887309170e+00, 2.2644675010425686e+00, 2.6542927811971722e+00, 3.0505384204304464e+00, 3.4547164957519905e+00, 3.8687007309691541e+00, 4.2948958144927625e+00, 4.7365184774132105e+00, 5.1980993461977523e+00, 5.6864689480904413e+00, 6.2129737476337166e+00, 6.7996094132841307e+00, 7.5040211464489355e+00}, {-7.6263257540038927e+00, -6.9255989902599406e+00, -6.3422433309944113e+00, -5.8188632795055772e+00, -5.3335601071130636e+00, -4.8750399724670830e+00, -4.4365069701928563e+00, -4.0134565677494702e+00, -3.6026938571484757e+00, -3.2018339457881582e+00, -2.8090222351311036e+00, -2.4227660420535617e+00, -2.0418271835544202e+00, -1.6651500018434142e+00, -1.2918109588209239e+00, -9.2098180157075304e-01, -5.5190143329042274e-01, -1.8385336710581282e-01, 1.8385336710581282e-01, 5.5190143329042274e-01, 9.2098180157075304e-01, 1.2918109588209239e+00, 1.6651500018434142e+00, 2.0418271835544202e+00, 2.4227660420535617e+00, 2.8090222351311036e+00, 3.2018339457881582e+00, 3.6026938571484757e+00, 4.0134565677494702e+00, 4.4365069701928563e+00, 4.8750399724670830e+00, 5.3335601071130636e+00, 5.8188632795055772e+00, 6.3422433309944113e+00, 6.9255989902599406e+00, 7.6263257540038927e+00}, {-7.7468822496494552e+00, -7.0497138557782293e+00, -6.4695200365240302e+00, -5.9491472174619711e+00, -5.4667903359685601e+00, -5.0112061385730726e+00, -4.5756317486673579e+00, -4.1555872811264782e+00, -3.7478982064754800e+00, -3.3501978949725357e+00, -2.9606491813032889e+00, -2.5777768581132716e+00, -2.2003609340092520e+00, -1.8273652487636047e+00, -1.4578876468742090e+00, -1.0911237649759331e+00, -7.2633961660512014e-01, -3.6284990505065795e-01, -0.0000000000000000e+00, 3.6284990505065795e-01, 7.2633961660512014e-01, 1.0911237649759331e+00, 1.4578876468742090e+00, 1.8273652487636047e+00, 2.2003609340092520e+00, 2.5777768581132716e+00, 2.9606491813032889e+00, 3.3501978949725357e+00, 3.7478982064754800e+00, 4.1555872811264782e+00, 4.5756317486673579e+00, 5.0112061385730726e+00, 5.4667903359685601e+00, 5.9491472174619711e+00, 6.4695200365240302e+00, 7.0497138557782293e+00, 7.7468822496494552e+00}, {-7.8657628033800400e+00, -7.1720339353200302e+00, -6.5948913272654934e+00, -6.0774160035375608e+00, -5.5978935141846780e+00, -5.1451293207408231e+00, -4.7123921320848874e+00, -4.2952254197496051e+00, -3.8904737609633409e+00, -3.4957874548356260e+00, -3.1093453117179419e+00, -2.7296879628883253e+00, -2.3556117330355080e+00, -1.9860977780390656e+00, -1.6202627556330140e+00, -1.2573231317007134e+00, -8.9656834619313597e-01, -5.3733981087098337e-01, -1.7901372329587750e-01, 1.7901372329587750e-01, 5.3733981087098337e-01, 8.9656834619313597e-01, 1.2573231317007134e+00, 1.6202627556330140e+00, 1.9860977780390656e+00, 2.3556117330355080e+00, 2.7296879628883253e+00, 3.1093453117179419e+00, 3.4957874548356260e+00, 3.8904737609633409e+00, 4.2952254197496051e+00, 4.7123921320848874e+00, 5.1451293207408231e+00, 5.5978935141846780e+00, 6.0774160035375608e+00, 6.5948913272654934e+00, 7.1720339353200302e+00, 7.8657628033800400e+00}, {-7.9830347727197806e+00, -7.2926336708657198e+00, -6.7184385064440910e+00, -6.2037579977281085e+00, -5.7269654517821049e+00, -5.2769133152304262e+00, -4.8469005687435258e+00, -4.4324928825930368e+00, -4.0305528146024674e+00, -3.6387464248745358e+00, -3.2552672359922297e+00, -2.8786703113749548e+00, -2.5077666938913192e+00, -2.1415530119868800e+00, -1.7791625828543136e+00, -1.4198301576857355e+00, -1.0628655672811786e+00, -7.0763327334857218e-01, -3.5353584699632934e-01, -0.0000000000000000e+00, 3.5353584699632934e-01, 7.0763327334857218e-01, 1.0628655672811786e+00, 1.4198301576857355e+00, 1.7791625828543136e+00, 2.1415530119868800e+00, 2.5077666938913192e+00, 2.8786703113749548e+00, 3.2552672359922297e+00, 3.6387464248745358e+00, 4.0305528146024674e+00, 4.4324928825930368e+00, 4.8469005687435258e+00, 5.2769133152304262e+00, 5.7269654517821049e+00, 6.2037579977281085e+00, 6.7184385064440910e+00, 7.2926336708657198e+00, 7.9830347727197806e+00}, {-8.0987611392508505e+00, -7.4115825314854691e+00, -6.8402373052493548e+00, -6.3282553512200810e+00, -5.8540950560303990e+00, -5.4066542479701267e+00, -4.9792609785452555e+00, -4.5675020728443938e+00, -4.1682570668324992e+00, -3.7792067534352229e+00, -3.3985582658596281e+00, -3.0248798839012840e+00, -2.6569959984428957e+00, -2.2939171418750832e+00, -1.9347914722822956e+00, -1.5788698949316138e+00, -1.2254801090462888e+00, -8.7400661235708799e-01, -5.2387471383227713e-01, -1.7453721459758240e-01, 1.7453721459758240e-01, 5.2387471383227713e-01, 8.7400661235708799e-01, 1.2254801090462888e+00, 1.5788698949316138e+00, 1.9347914722822956e+00, 2.2939171418750832e+00, 2.6569959984428957e+00, 3.0248798839012840e+00, 3.3985582658596281e+00, 3.7792067534352229e+00, 4.1682570668324992e+00, 4.5675020728443938e+00, 4.9792609785452555e+00, 5.4066542479701267e+00, 5.8540950560303990e+00, 6.3282553512200810e+00, 6.8402373052493548e+00, 7.4115825314854691e+00, 8.0987611392508505e+00}, {-8.2130008955982792e+00, -7.5289454645396203e+00, -6.9603584006367480e+00, -6.4509845971747524e+00, -5.9793650041651327e+00, -5.5344413406134461e+00, -5.1095696265331334e+00, -4.7003568963041156e+00, -4.3036987671546498e+00, -3.9172898548377817e+00, -3.5393499373637116e+00, -3.1684594539419857e+00, -2.8034549614843187e+00, -2.4433595531234111e+00, -2.0873346819187244e+00, -1.7346456088220295e+00, -1.3846357891600325e+00, -1.0367072529242058e+00, -6.9030505233020811e-01, -3.4490446301543276e-01, -0.0000000000000000e+00, 3.4490446301543276e-01, 6.9030505233020811e-01, 1.0367072529242058e+00, 1.3846357891600325e+00, 1.7346456088220295e+00, 2.0873346819187244e+00, 2.4433595531234111e+00, 2.8034549614843187e+00, 3.1684594539419857e+00, 3.5393499373637116e+00, 3.9172898548377817e+00, 4.3036987671546498e+00, 4.7003568963041156e+00, 5.1095696265331334e+00, 5.5344413406134461e+00, 5.9793650041651327e+00, 6.4509845971747524e+00, 6.9603584006367480e+00, 7.5289454645396203e+00, 8.2130008955982792e+00}, {-8.3258093895669294e+00, -7.6447832957047419e+00, -7.0788678730491084e+00, -6.5720171713874747e+00, -6.1028523343815264e+00, -5.6603575812830567e+00, -5.2379158850176495e+00, -4.8311536291282762e+00, -4.4369817058810304e+00, -4.0531077444247670e+00, -3.6777633163885568e+00, -3.3095400965109221e+00, -2.9472857823054786e+00, -2.5900348706171261e+00, -2.2369607870543176e+00, -1.8873416205434848e+00, -1.5405348009155460e+00, -1.1959577943778097e+00, -8.5307290916055367e-01, -5.1137491831546933e-01, -1.7038058556181696e-01, 1.7038058556181696e-01, 5.1137491831546933e-01, 8.5307290916055367e-01, 1.1959577943778097e+00, 1.5405348009155460e+00, 1.8873416205434848e+00, 2.2369607870543176e+00, 2.5900348706171261e+00, 2.9472857823054786e+00, 3.3095400965109221e+00, 3.6777633163885568e+00, 4.0531077444247670e+00, 4.4369817058810304e+00, 4.8311536291282762e+00, 5.2379158850176495e+00, 5.6603575812830567e+00, 6.1028523343815264e+00, 6.5720171713874747e+00, 7.0788678730491084e+00, 7.6447832957047419e+00, 8.3258093895669294e+00}, {-8.4372386310833765e+00, -7.7591530847325343e+00, -7.1958276123464335e+00, -6.6914198727121068e+00, -6.2246289668942199e+00, -5.7844803140775571e+00, -5.3643829011515560e+00, -4.9599816751949550e+00, -4.5682020755441552e+00, -4.1867640213660025e+00, -3.8139101240654272e+00, -3.4482424822200026e+00, -3.0886190396004185e+00, -2.7340846945379047e+00, -2.3838237072843595e+00, -2.0371256888641933e+00, -1.6933605309399098e+00, -1.3519593686708704e+00, -1.0123996845633196e+00, -6.7419327674231389e-01, -3.3687619662553298e-01, -0.0000000000000000e+00, 3.3687619662553298e-01, 6.7419327674231389e-01, 1.0123996845633196e+00, 1.3519593686708704e+00, 1.6933605309399098e+00, 2.0371256888641933e+00, 2.3838237072843595e+00, 2.7340846945379047e+00, 3.0886190396004185e+00, 3.4482424822200026e+00, 3.8139101240654272e+00, 4.1867640213660025e+00, 4.5682020755441552e+00, 4.9599816751949550e+00, 5.3643829011515560e+00, 5.7844803140775571e+00, 6.2246289668942199e+00, 6.6914198727121068e+00, 7.1958276123464335e+00, 7.7591530847325343e+00, 8.4372386310833765e+00}, {-8.5473375667355391e+00, -7.8721084427748513e+00, -7.3112956789163306e+00, -6.8092552715358323e+00, -6.3447621648968919e+00, -5.9068817590275451e+00, -5.4890481838807421e+00, -5.0869242297582531e+00, -4.6974492230014393e+00, -4.3183547234421118e+00, -3.9478937115246548e+00, -3.5846779931052279e+00, -3.2275749742774260e+00, -2.8756390821704421e+00, -2.5280644271476649e+00, -2.1841510195665261e+00, -1.8432799206176103e+00, -1.5048944344828714e+00, -1.1684854631902055e+00, -8.3357976100207332e-01, -4.9973020830067427e-01, -1.6650746707363237e-01, 1.6650746707363237e-01, 4.9973020830067427e-01, 8.3357976100207332e-01, 1.1684854631902055e+00, 1.5048944344828714e+00, 1.8432799206176103e+00, 2.1841510195665261e+00, 2.5280644271476649e+00, 2.8756390821704421e+00, 3.2275749742774260e+00, 3.5846779931052279e+00, 3.9478937115246548e+00, 4.3183547234421118e+00, 4.6974492230014393e+00, 5.0869242297582531e+00, 5.4890481838807421e+00, 5.9068817590275451e+00, 6.3447621648968919e+00, 6.8092552715358323e+00, 7.3112956789163306e+00, 7.8721084427748513e+00, 8.5473375667355391e+00}, {-8.6561523259903268e+00, -7.9836998162220016e+00, -7.4253266258561936e+00, -6.9255820732775950e+00, -6.4633149436642530e+00, -6.0276294722536941e+00, -5.6119841218396642e+00, -5.2120588631620075e+00, -4.8248063087032573e+00, -4.4479690736019313e+00, -4.0798099079253927e+00, -3.7189496893415628e+00, -3.3642645958565400e+00, -3.0148178197492252e+00, -2.6698124652513462e+00, -2.3285579714531894e+00, -1.9904454586466382e+00, -1.6549291191547923e+00, -1.3215117856392311e+00, -9.8973342486571125e-01, -6.5916168887413507e-01, -3.2938389969666915e-01, -0.0000000000000000e+00, 3.2938389969666915e-01, 6.5916168887413507e-01, 9.8973342486571125e-01, 1.3215117856392311e+00, 1.6549291191547923e+00, 1.9904454586466382e+00, 2.3285579714531894e+00, 2.6698124652513462e+00, 3.0148178197492252e+00, 3.3642645958565400e+00, 3.7189496893415628e+00, 4.0798099079253927e+00, 4.4479690736019313e+00, 4.8248063087032573e+00, 5.2120588631620075e+00, 5.6119841218396642e+00, 6.0276294722536941e+00, 6.4633149436642530e+00, 6.9255820732775950e+00, 7.4253266258561936e+00, 7.9836998162220016e+00, 8.6561523259903268e+00}, {-8.7637264425763934e+00, -8.0939747412671181e+00, -7.5379717872258256e+00, -7.0404554428052171e+00, -6.5803464347374083e+00, -6.1467867545054018e+00, -5.7332584418499435e+00, -5.3354580360572301e+00, -4.9503508867398853e+00, -4.5756901345704328e+00, -4.2097477613269749e+00, -3.8511531505025514e+00, -3.4987906412463645e+00, -3.1517315196384712e+00, -2.8091871354772668e+00, -2.4704755132281426e+00, -2.1349968729707256e+00, -1.8022151950574945e+00, -1.4716439717320722e+00, -1.1428349031264304e+00, -8.1536867934468149e-01, -4.8884723585117468e-01, -1.6288702795526222e-01, 1.6288702795526222e-01, 4.8884723585117468e-01, 8.1536867934468149e-01, 1.1428349031264304e+00, 1.4716439717320722e+00, 1.8022151950574945e+00, 2.1349968729707256e+00, 2.4704755132281426e+00, 2.8091871354772668e+00, 3.1517315196384712e+00, 3.4987906412463645e+00, 3.8511531505025514e+00, 4.2097477613269749e+00, 4.5756901345704328e+00, 4.9503508867398853e+00, 5.3354580360572301e+00, 5.7332584418499435e+00, 6.1467867545054018e+00, 6.5803464347374083e+00, 7.0404554428052171e+00, 7.5379717872258256e+00, 8.0939747412671181e+00, 8.7637264425763934e+00}, {-8.8701010540232534e+00, -8.2029780727977943e+00, -7.6492795366289874e+00, -7.1539272947757162e+00, -6.6959122110632512e+00, -6.2644130149704740e+00, -5.8529346161254212e+00, -5.4571895556816514e+00, -5.0741554169850653e+00, -4.7015953849679351e+00, -4.3377901884924199e+00, -3.9813772107064693e+00, -3.6312484092926161e+00, -3.2864825713246675e+00, -2.9462986351921705e+00, -2.6100224744061520e+00, -2.2770625758595000e+00, -1.9468917579991860e+00, -1.6190330813590508e+00, -1.2930487170109526e+00, -9.6853092273781483e-01, -6.4509452302768844e-01, -3.2237044915615060e-01, -0.0000000000000000e+00, 3.2237044915615060e-01, 6.4509452302768844e-01, 9.6853092273781483e-01, 1.2930487170109526e+00, 1.6190330813590508e+00, 1.9468917579991860e+00, 2.2770625758595000e+00, 2.6100224744061520e+00, 2.9462986351921705e+00, 3.2864825713246675e+00, 3.6312484092926161e+00, 3.9813772107064693e+00, 4.3377901884924199e+00, 4.7015953849679351e+00, 5.0741554169850653e+00, 5.4571895556816514e+00, 5.8529346161254212e+00, 6.2644130149704740e+00, 6.6959122110632512e+00, 7.1539272947757162e+00, 7.6492795366289874e+00, 8.2029780727977943e+00, 8.8701010540232534e+00}, {-8.9753150819316865e+00, -8.3107521907047843e+00, -7.7592955197657743e+00, -7.2660465541643502e+00, -6.8100645780741411e+00, -6.3805640961864096e+00, -5.9710722250135460e+00, -5.5773169812237278e+00, -5.1962877187923642e+00, -4.8257572281332095e+00, -4.4640145469344583e+00, -4.1097046035605898e+00, -3.7617264902283578e+00, -3.4191659693638847e+00, -3.0812489886451053e+00, -2.7473086248223830e+00, -2.4167609048732164e+00, -2.0890866609442762e+00, -1.7638175798953000e+00, -1.4405252201375651e+00, -1.1188121524021566e+00, -7.9830462777856215e-01, -4.7864633759449599e-01, -1.5949293584886245e-01, 1.5949293584886245e-01, 4.7864633759449599e-01, 7.9830462777856215e-01, 1.1188121524021566e+00, 1.4405252201375651e+00, 1.7638175798953000e+00, 2.0890866609442762e+00, 2.4167609048732164e+00, 2.7473086248223830e+00, 3.0812489886451053e+00, 3.4191659693638847e+00, 3.7617264902283578e+00, 4.1097046035605898e+00, 4.4640145469344583e+00, 4.8257572281332095e+00, 5.1962877187923642e+00, 5.5773169812237278e+00, 5.9710722250135460e+00, 6.3805640961864096e+00, 6.8100645780741411e+00, 7.2660465541643502e+00, 7.7592955197657743e+00, 8.3107521907047843e+00, 8.9753150819316865e+00}, {-9.0794053951994336e+00, -8.4173371862679787e+00, -7.8680628640816641e+00, -7.3768593906319282e+00, -6.9228528349597616e+00, -6.4952925650076585e+00, -6.0877272810547556e+00, -5.6958999850352088e+00, -5.3168113741835157e+00, -4.9482434430048912e+00, -4.5884931402744824e+00, -4.2362125300687872e+00, -3.8903074057661615e+00, -3.5498700372120946e+00, -3.2141328684568560e+00, -2.8824356106455995e+00, -2.5542011939519624e+00, -2.2289177453859468e+00, -1.9061247609883607e+00, -1.5854022514550468e+00, -1.2663620236873581e+00, -9.4864050761025742e-01, -6.3189269951096161e-01, -3.1578690052375491e-01, -0.0000000000000000e+00, 3.1578690052375491e-01, 6.3189269951096161e-01, 9.4864050761025742e-01, 1.2663620236873581e+00, 1.5854022514550468e+00, 1.9061247609883607e+00, 2.2289177453859468e+00, 2.5542011939519624e+00, 2.8824356106455995e+00, 3.2141328684568560e+00, 3.5498700372120946e+00, 3.8903074057661615e+00, 4.2362125300687872e+00, 4.5884931402744824e+00, 4.9482434430048912e+00, 5.3168113741835157e+00, 5.6958999850352088e+00, 6.0877272810547556e+00, 6.4952925650076585e+00, 6.9228528349597616e+00, 7.3768593906319282e+00, 7.8680628640816641e+00, 8.4173371862679787e+00, 9.0794053951994336e+00}, {-9.1824069581293166e+00, -8.5227710309178022e+00, -7.9756223682056362e+00, -7.4864094298641941e+00, -7.0343235097706103e+00, -6.6086479738553576e+00, -6.2029525192746719e+00, -5.8129946754204047e+00, -5.4357860872249475e+00, -5.0691175849172350e+00, -4.7112936661690421e+00, -4.3609731604545781e+00, -4.0170681728581341e+00, -3.6786770625152689e+00, -3.3450383139378910e+00, -3.0154977695745222e+00, -2.6894847022677451e+00, -2.3664939042986637e+00, -2.0460719686864088e+00, -1.7278065475158983e+00, -1.4113177548982998e+00, -1.0962511289576817e+00, -7.8227172955460689e-01, -4.6905905667823600e-01, -1.5630254688946871e-01, 1.5630254688946871e-01, 4.6905905667823600e-01, 7.8227172955460689e-01, 1.0962511289576817e+00, 1.4113177548982998e+00, 1.7278065475158983e+00, 2.0460719686864088e+00, 2.3664939042986637e+00, 2.6894847022677451e+00, 3.0154977695745222e+00, 3.3450383139378910e+00, 3.6786770625152689e+00, 4.0170681728581341e+00, 4.3609731604545781e+00, 4.7112936661690421e+00, 5.0691175849172350e+00, 5.4357860872249475e+00, 5.8129946754204047e+00, 6.2029525192746719e+00, 6.6086479738553576e+00, 7.0343235097706103e+00, 7.4864094298641941e+00, 7.9756223682056362e+00, 8.5227710309178022e+00, 9.1824069581293166e+00}, {-9.2843529650947954e+00, -8.6270897293636839e+00, -8.0820126735040123e+00, -7.5947379445835947e+00, -7.1445205714796174e+00, -6.7206770958687514e+00, -6.3167976579034049e+00, -5.9286538858731372e+00, -5.5532680052649175e+00, -5.1884393429381372e+00, -4.8324796145780748e+00, -4.4840540790573504e+00, -4.1420808019620621e+00, -3.8056638567519334e+00, -3.4740473616558587e+00, -3.1465828437716956e+00, -2.8227054233054294e+00, -2.5019160040577368e+00, -2.1837676525361926e+00, -1.8678549556995603e+00, -1.5538055294554218e+00, -1.2412730966236114e+00, -9.2993171560017596e-01, -6.1947084974715272e-01, -3.0959104093724038e-01, -0.0000000000000000e+00, 3.0959104093724038e-01, 6.1947084974715272e-01, 9.2993171560017596e-01, 1.2412730966236114e+00, 1.5538055294554218e+00, 1.8678549556995603e+00, 2.1837676525361926e+00, 2.5019160040577368e+00, 2.8227054233054294e+00, 3.1465828437716956e+00, 3.4740473616558587e+00, 3.8056638567519334e+00, 4.1420808019620621e+00, 4.4840540790573504e+00, 4.8324796145780748e+00, 5.1884393429381372e+00, 5.5532680052649175e+00, 5.9286538858731372e+00, 6.3167976579034049e+00, 6.7206770958687514e+00, 7.1445205714796174e+00, 7.5947379445835947e+00, 8.0820126735040123e+00, 8.6270897293636839e+00, 9.2843529650947954e+00}, {-9.3852749632231376e+00, -8.7303274588209110e+00, -8.1872704197671577e+00, -7.7018840275679166e+00, -7.2534856216969716e+00, -6.8314241370686029e+00, -6.4293096331149808e+00, -6.0429274349196920e+00, -5.6693100068563673e+00, -5.3062648593656414e+00, -4.9521106229353720e+00, -4.6055186799962122e+00, -4.2654127388779193e+00, -3.9309022499573141e+00, -3.6012366010181420e+00, -3.2757726058076915e+00, -2.9539507925538842e+00, -2.6352776875892849e+00, -2.3193122827994568e+00, -2.0056554817328660e+00, -1.6939417005414366e+00, -1.3838320462108629e+00, -1.0750086571198576e+00, -7.6716990012409136e-01, -4.6002619243746073e-01, -1.5329626692045756e-01, 1.5329626692045756e-01, 4.6002619243746073e-01, 7.6716990012409136e-01, 1.0750086571198576e+00, 1.3838320462108629e+00, 1.6939417005414366e+00, 2.0056554817328660e+00, 2.3193122827994568e+00, 2.6352776875892849e+00, 2.9539507925538842e+00, 3.2757726058076915e+00, 3.6012366010181420e+00, 3.9309022499573141e+00, 4.2654127388779193e+00, 4.6055186799962122e+00, 4.9521106229353720e+00, 5.3062648593656414e+00, 5.6693100068563673e+00, 6.0429274349196920e+00, 6.4293096331149808e+00, 6.8314241370686029e+00, 7.2534856216969716e+00, 7.7018840275679166e+00, 8.1872704197671577e+00, 8.7303274588209110e+00, 9.3852749632231376e+00}, {-9.4852029643727302e+00, -8.8325166958454133e+00, -8.2914303867830093e+00, -7.8078847487003955e+00, -7.3612580683690458e+00, -6.9409309282147520e+00, -6.5405328108757619e+00, -6.1558623601311924e+00, -5.7839619604859447e+00, -5.4226470161614522e+00, -5.0702427937817154e+00, -4.7254265200961152e+00, -4.3871272577720717e+00, -4.0544595295034727e+00, -3.7266776654942122e+00, -3.4031434102599176e+00, -3.0833023089391358e+00, -2.7666660769675384e+00, -2.4527991478588032e+00, -2.1413081984302371e+00, -1.8318338313140423e+00, -1.5240438405087577e+00, -1.2176276482547366e+00, -9.1229161088998856e-01, -6.0775496588729694e-01, -3.0374624334991529e-01, -0.0000000000000000e+00, 3.0374624334991529e-01, 6.0775496588729694e-01, 9.1229161088998856e-01, 1.2176276482547366e+00, 1.5240438405087577e+00, 1.8318338313140423e+00, 2.1413081984302371e+00, 2.4527991478588032e+00, 2.7666660769675384e+00, 3.0833023089391358e+00, 3.4031434102599176e+00, 3.7266776654942122e+00, 4.0544595295034727e+00, 4.3871272577720717e+00, 4.7254265200961152e+00, 5.0702427937817154e+00, 5.4226470161614522e+00, 5.7839619604859447e+00, 6.1558623601311924e+00, 6.5405328108757619e+00, 6.9409309282147520e+00, 7.3612580683690458e+00, 7.8078847487003955e+00, 8.2914303867830093e+00, 8.8325166958454133e+00, 9.4852029643727302e+00}, {-9.5841655475234688e+00, -8.9336883320961924e+00, -8.3945256233272012e+00, -7.9127752978124946e+00, -7.4678752834836200e+00, -7.0492370986783772e+00, -6.6505091785664918e+00, -6.2675031293697510e+00, -5.8972709576411209e+00, -5.5376356924033008e+00, -5.1869289795928895e+00, -4.8438336345819870e+00, -4.5072838118199003e+00, -4.1763988304784849e+00, -3.8504376683661063e+00, -3.5287666814910854e+00, -3.2108360825282936e+00, -2.8961623904571474e+00, -2.5843150518736273e+00, -2.2749060375416974e+00, -1.9675815973920669e+00, -1.6620156026589967e+00, -1.3579040662442226e+00, -1.0549605418738988e+00, -7.5291217747488703e-01, -4.5149624980624264e-01, -1.5045704292086298e-01, 1.5045704292086298e-01, 4.5149624980624264e-01, 7.5291217747488703e-01, 1.0549605418738988e+00, 1.3579040662442226e+00, 1.6620156026589967e+00, 1.9675815973920669e+00, 2.2749060375416974e+00, 2.5843150518736273e+00, 2.8961623904571474e+00, 3.2108360825282936e+00, 3.5287666814910854e+00, 3.8504376683661063e+00, 4.1763988304784849e+00, 4.5072838118199003e+00, 4.8438336345819870e+00, 5.1869289795928895e+00, 5.5376356924033008e+00, 5.8972709576411209e+00, 6.2675031293697510e+00, 6.6505091785664918e+00, 7.0492370986783772e+00, 7.4678752834836200e+00, 7.9127752978124946e+00, 8.3945256233272012e+00, 8.9336883320961924e+00, 9.5841655475234688e+00}, {-9.6821899525637249e+00, -9.0338717801824053e+00, -8.4965875649075624e+00, -8.0165891148558295e+00, -7.5733727465411995e+00, -7.1563802343429099e+00, -6.7592785186840851e+00, -6.3778918319127680e+00, -6.0092815232536667e+00, -5.6512779962558639e+00, -5.3022190388457897e+00, -4.9607928202275557e+00, -4.6259383469194120e+00, -4.2967794840336984e+00, -3.9725795904787460e+00, -3.6527093464132974e+00, -3.3366233189341656e+00, -3.0238424864191802e+00, -2.7139409275560999e+00, -2.4065354826206522e+00, -2.1012775733291407e+00, -1.7978466126036980e+00, -1.4959445977962444e+00, -1.1952915904152335e+00, -8.9562186046229086e-01, -5.9668052547571682e-01, -2.9822055049276669e-01, -0.0000000000000000e+00, 2.9822055049276669e-01, 5.9668052547571682e-01, 8.9562186046229086e-01, 1.1952915904152335e+00, 1.4959445977962444e+00, 1.7978466126036980e+00, 2.1012775733291407e+00, 2.4065354826206522e+00, 2.7139409275560999e+00, 3.0238424864191802e+00, 3.3366233189341656e+00, 3.6527093464132974e+00, 3.9725795904787460e+00, 4.2967794840336984e+00, 4.6259383469194120e+00, 4.9607928202275557e+00, 5.3022190388457897e+00, 5.6512779962558639e+00, 6.0092815232536667e+00, 6.3778918319127680e+00, 6.7592785186840851e+00, 7.1563802343429099e+00, 7.5733727465411995e+00, 8.0165891148558295e+00, 8.4965875649075624e+00, 9.0338717801824053e+00, 9.6821899525637249e+00}, {-9.7793021663403099e+00, -9.1330950706121001e+00, -8.5976461414362131e+00, -8.1193580087474686e+00, -7.6777841753281493e+00, -7.2623960212867891e+00, -6.8668785666252870e+00, -6.4870683517446244e+00, -6.1200358061419919e+00, -5.7636184744715768e+00, -5.4161600667900469e+00, -5.0763538899639924e+00, -4.7431435831181288e+00, -4.4156573291002159e+00, -4.0931626262997982e+00, -3.7750342196411242e+00, -3.4607307491477983e+00, -3.1497773444199684e+00, -2.8417523763809922e+00, -2.5362771776597737e+00, -2.2330079208452407e+00, -1.9316290883640068e+00, -1.6318481297059444e+00, -1.3333910111792098e+00, -1.0359984385570031e+00, -7.3942258523430104e-01, -4.4342419505035346e-01, -1.4776995439420115e-01, 1.4776995439420115e-01, 4.4342419505035346e-01, 7.3942258523430104e-01, 1.0359984385570031e+00, 1.3333910111792098e+00, 1.6318481297059444e+00, 1.9316290883640068e+00, 2.2330079208452407e+00, 2.5362771776597737e+00, 2.8417523763809922e+00, 3.1497773444199684e+00, 3.4607307491477983e+00, 3.7750342196411242e+00, 4.0931626262997982e+00, 4.4156573291002159e+00, 4.7431435831181288e+00, 5.0763538899639924e+00, 5.4161600667900469e+00, 5.7636184744715768e+00, 6.1200358061419919e+00, 6.4870683517446244e+00, 6.8668785666252870e+00, 7.2623960212867891e+00, 7.6777841753281493e+00, 8.1193580087474686e+00, 8.5976461414362131e+00, 9.1330950706121001e+00, 9.7793021663403099e+00}, {-9.8755270017367671e+00, -9.2313849407386552e+00, -8.6977298758606238e+00, -8.2211122660677169e+00, -7.7811416453357003e+00, -7.3673183767785728e+00, -6.9733451542956244e+00, -6.5950705250038864e+00, -6.2295737517233460e+00, -5.8746993020212539e+00, -5.5287966039093659e+00, -5.1905639023838361e+00, -4.8589492677211483e+00, -4.5330849920738157e+00, -4.2122424936406224e+00, -3.8958003472863840e+00, -3.5832210121368786e+00, -3.2740334921948340e+00, -2.9678201464818930e+00, -2.6642064637087906e+00, -2.3628529934485321e+00, -2.0634488697846303e+00, -1.7657065251132762e+00, -1.4693573011471874e+00, -1.1741477394031905e+00, -8.7983638589173074e-01, -5.8619098157190686e-01, -2.9298593604778866e-01, -0.0000000000000000e+00, 2.9298593604778866e-01, 5.8619098157190686e-01, 8.7983638589173074e-01, 1.1741477394031905e+00, 1.4693573011471874e+00, 1.7657065251132762e+00, 2.0634488697846303e+00, 2.3628529934485321e+00, 2.6642064637087906e+00, 2.9678201464818930e+00, 3.2740334921948340e+00, 3.5832210121368786e+00, 3.8958003472863840e+00, 4.2122424936406224e+00, 4.5330849920738157e+00, 4.8589492677211483e+00, 5.1905639023838361e+00, 5.5287966039093659e+00, 5.8746993020212539e+00, 6.2295737517233460e+00, 6.5950705250038864e+00, 6.9733451542956244e+00, 7.3673183767785728e+00, 7.7811416453357003e+00, 8.2211122660677169e+00, 8.6977298758606238e+00, 9.2313849407386552e+00, 9.8755270017367671e+00}, {-9.9708881704574601e+00, -9.3287669164964395e+00, -8.7968659746627651e+00, -8.3218807506473613e+00, -7.8834756990041477e+00, -7.4711795689242475e+00, -7.0787123410660744e+00, -6.7019342833176401e+00, -6.3379332589686221e+00, -5.9845604541065045e+00, -5.6401708246496867e+00, -5.3034673690975112e+00, -4.9734024034844930e+00, -4.6491121384000209e+00, -4.3298717115959429e+00, -4.0150633146984989e+00, -3.7041529964080997e+00, -3.3966733857420293e+00, -3.0922105568140124e+00, -2.7903938536440540e+00, -2.4908878695658663e+00, -2.1933860192661303e+00, -1.8976053029060733e+00, -1.6032819710214761e+00, -1.3101678741366003e+00, -1.0180273335786967e+00, -7.2663440704649163e-01, -4.3577044873391346e-01, -1.4522188229810670e-01, 1.4522188229810670e-01, 4.3577044873391346e-01, 7.2663440704649163e-01, 1.0180273335786967e+00, 1.3101678741366003e+00, 1.6032819710214761e+00, 1.8976053029060733e+00, 2.1933860192661303e+00, 2.4908878695658663e+00, 2.7903938536440540e+00, 3.0922105568140124e+00, 3.3966733857420293e+00, 3.7041529964080997e+00, 4.0150633146984989e+00, 4.3298717115959429e+00, 4.6491121384000209e+00, 4.9734024034844930e+00, 5.3034673690975112e+00, 5.6401708246496867e+00, 5.9845604541065045e+00, 6.3379332589686221e+00, 6.7019342833176401e+00, 7.0787123410660744e+00, 7.4711795689242475e+00, 7.8834756990041477e+00, 8.3218807506473613e+00, 8.7968659746627651e+00, 9.3287669164964395e+00, 9.9708881704574601e+00}, {-1.0065408350118513e+01, -9.4252653876263999e+00, -8.8950804110294346e+00, -8.4216909949586132e+00, -7.9848154458297120e+00, -7.5740103261427940e+00, -7.1830125334106762e+00, -6.8076937845356600e+00, -6.4451503233185363e+00, -6.0932398625106678e+00, -5.7503227086468636e+00, -5.4151064424967945e+00, -5.0865474548246592e+00, -4.7637856994329741e+00, -4.4460998505989417e+00, -4.1328755226679874e+00, -3.8235821457915500e+00, -3.5177557486926583e+00, -3.2149858747990203e+00, -2.9149054536014392e+00, -2.6171828242728932e+00, -2.3215153515122373e+00, -2.0276242346848043e+00, -1.7352502204281328e+00, -1.4441500040985724e+00, -1.1540931580511036e+00, -8.6485946196705754e-01, -5.7623653694114951e-01, -2.8801770388153508e-01, -0.0000000000000000e+00, 2.8801770388153508e-01, 5.7623653694114951e-01, 8.6485946196705754e-01, 1.1540931580511036e+00, 1.4441500040985724e+00, 1.7352502204281328e+00, 2.0276242346848043e+00, 2.3215153515122373e+00, 2.6171828242728932e+00, 2.9149054536014392e+00, 3.2149858747990203e+00, 3.5177557486926583e+00, 3.8235821457915500e+00, 4.1328755226679874e+00, 4.4460998505989417e+00, 4.7637856994329741e+00, 5.0865474548246592e+00, 5.4151064424967945e+00, 5.7503227086468636e+00, 6.0932398625106678e+00, 6.4451503233185363e+00, 6.8076937845356600e+00, 7.1830125334106762e+00, 7.5740103261427940e+00, 7.9848154458297120e+00, 8.4216909949586132e+00, 8.8950804110294346e+00, 9.4252653876263999e+00, 1.0065408350118513e+01}, {-1.0159109246180085e+01, -9.5209036770133171e+00, -8.9923980014049434e+00, -8.5205692841176308e+00, -8.0851886542490199e+00, -7.6758399375048869e+00, -7.2862765943955985e+00, -6.9123815321893174e+00, -6.5512591670629208e+00, -6.2007735579934371e+00, -5.8592901963942339e+00, -5.5255210861386832e+00, -5.1984265345762939e+00, -4.8771500774731509e+00, -4.5609737579358356e+00, -4.2492864359560061e+00, -3.9415607339261842e+00, -3.6373358761707317e+00, -3.3362046535475867e+00, -3.0378033382307490e+00, -2.7418037480696915e+00, -2.4479069023076856e+00, -2.1558378712292110e+00, -1.8653415312330315e+00, -1.5761790119750203e+00, -1.2881246748688935e+00, -1.0009634995607180e+00, -7.1448878167257845e-01, -4.2850006422062747e-01, -1.4280123870343886e-01, 1.4280123870343886e-01, 4.2850006422062747e-01, 7.1448878167257845e-01, 1.0009634995607180e+00, 1.2881246748688935e+00, 1.5761790119750203e+00, 1.8653415312330315e+00, 2.1558378712292110e+00, 2.4479069023076856e+00, 2.7418037480696915e+00, 3.0378033382307490e+00, 3.3362046535475867e+00, 3.6373358761707317e+00, 3.9415607339261842e+00, 4.2492864359560061e+00, 4.5609737579358356e+00, 4.8771500774731509e+00, 5.1984265345762939e+00, 5.5255210861386832e+00, 5.8592901963942339e+00, 6.2007735579934371e+00, 6.5512591670629208e+00, 6.9123815321893174e+00, 7.2862765943955985e+00, 7.6758399375048869e+00, 8.0851886542490199e+00, 8.5205692841176308e+00, 8.9923980014049434e+00, 9.5209036770133171e+00, 1.0159109246180085e+01}, {-1.0252011649196143e+01, -9.6157041046875609e+00, -9.0888424760573390e+00, -8.6185407332142496e+00, -8.1846218361099510e+00, -7.7766963448476236e+00, -7.3885339440499829e+00, -7.0160284848388690e+00, -6.6562923584988729e+00, -6.3071958002194259e+00, -5.9671093310413950e+00, -5.6347492296736759e+00, -5.3090795734924505e+00, -4.9892473314939929e+00, -4.6745377615999182e+00, -4.3643428074654231e+00, -4.0581381112767332e+00, -3.7554659075853780e+00, -3.4559220338316390e+00, -3.1591458858192856e+00, -2.8648125198053043e+00, -2.5726263447097191e+00, -2.2823160084101848e+00, -1.9936301908281084e+00, -1.7063340915790624e+00, -1.4202064526026656e+00, -1.1350369935815596e+00, -8.5062416477081448e-01, -5.6677314117022048e-01, -2.8329399584293824e-01, -0.0000000000000000e+00, 2.8329399584293824e-01, 5.6677314117022048e-01, 8.5062416477081448e-01, 1.1350369935815596e+00, 1.4202064526026656e+00, 1.7063340915790624e+00, 1.9936301908281084e+00, 2.2823160084101848e+00, 2.5726263447097191e+00, 2.8648125198053043e+00, 3.1591458858192856e+00, 3.4559220338316390e+00, 3.7554659075853780e+00, 4.0581381112767332e+00, 4.3643428074654231e+00, 4.6745377615999182e+00, 4.9892473314939929e+00, 5.3090795734924505e+00, 5.6347492296736759e+00, 5.9671093310413950e+00, 6.3071958002194259e+00, 6.6562923584988729e+00, 7.0160284848388690e+00, 7.3885339440499829e+00, 7.7766963448476236e+00, 8.1846218361099510e+00, 8.6185407332142496e+00, 9.0888424760573390e+00, 9.6157041046875609e+00, 1.0252011649196143e+01}, {-1.0344135487806895e+01, -9.7096880469839437e+00, -9.1844365442194498e+00, -8.7156293586041365e+00, -8.2831403244454158e+00, -7.8766062274725090e+00, -7.4898126515277026e+00, -7.1186641563335851e+00, -6.7602809210235622e+00, -6.4125391965266108e+00, -6.0738143878025932e+00, -5.7428269099958227e+00, -5.4185444743952305e+00, -5.1001173457332412e+00, -4.7868338549738239e+00, -4.4780888809091079e+00, -4.1733609279699495e+00, -3.8721950721542884e+00, -3.5741900152128512e+00, -3.2789880784162539e+00, -2.9862673397528621e+00, -2.6957353597041749e+00, -2.4071241008699498e+00, -2.1201857552620891e+00, -1.8346892680544815e+00, -1.5504173991942523e+00, -1.2671642017112603e+00, -9.8473282246759541e-01, -7.0293355055041085e-01, -4.2158205259642756e-01, -1.4049774444160384e-01, 1.4049774444160384e-01, 4.2158205259642756e-01, 7.0293355055041085e-01, 9.8473282246759541e-01, 1.2671642017112603e+00, 1.5504173991942523e+00, 1.8346892680544815e+00, 2.1201857552620891e+00, 2.4071241008699498e+00, 2.6957353597041749e+00, 2.9862673397528621e+00, 3.2789880784162539e+00, 3.5741900152128512e+00, 3.8721950721542884e+00, 4.1733609279699495e+00, 4.4780888809091079e+00, 4.7868338549738239e+00, 5.1001173457332412e+00, 5.4185444743952305e+00, 5.7428269099958227e+00, 6.0738143878025932e+00, 6.4125391965266108e+00, 6.7602809210235622e+00, 7.1186641563335851e+00, 7.4898126515277026e+00, 7.8766062274725090e+00, 8.2831403244454158e+00, 8.7156293586041365e+00, 9.1844365442194498e+00, 9.7096880469839437e+00, 1.0344135487806895e+01}, {-1.0435499877854168e+01, -9.8028759912974959e+00, -9.2792019543050390e+00, -8.8118581437284540e+00, -8.3807683451863202e+00, -7.9755950801420372e+00, -7.5901395198641071e+00, -7.2203167078889665e+00, -6.8632544331795353e+00, -6.5168348106821155e+00, -6.1794379922705955e+00, -5.8497884000810672e+00, -5.5268572526403030e+00, -5.2097979830408345e+00, -4.8979018644975740e+00, -4.5905665744435185e+00, -4.2872733352824408e+00, -3.9875699104197153e+00, -3.6910577000963465e+00, -3.3973817713303909e+00, -3.1062230279282566e+00, -2.8172919672837975e+00, -2.5303236304712007e+00, -2.2450734604812066e+00, -1.9613138583081484e+00, -1.6788312791720135e+00, -1.3974237486049623e+00, -1.1168987050996462e+00, -8.3707109558947612e-01, -5.5776166427908214e-01, -2.7879538567115225e-01, -0.0000000000000000e+00, 2.7879538567115225e-01, 5.5776166427908214e-01, 8.3707109558947612e-01, 1.1168987050996462e+00, 1.3974237486049623e+00, 1.6788312791720135e+00, 1.9613138583081484e+00, 2.2450734604812066e+00, 2.5303236304712007e+00, 2.8172919672837975e+00, 3.1062230279282566e+00, 3.3973817713303909e+00, 3.6910577000963465e+00, 3.9875699104197153e+00, 4.2872733352824408e+00, 4.5905665744435185e+00, 4.8979018644975740e+00, 5.2097979830408345e+00, 5.5268572526403030e+00, 5.8497884000810672e+00, 6.1794379922705955e+00, 6.5168348106821155e+00, 6.8632544331795353e+00, 7.2203167078889665e+00, 7.5901395198641071e+00, 7.9755950801420372e+00, 8.3807683451863202e+00, 8.8118581437284540e+00, 9.2792019543050390e+00, 9.8028759912974959e+00, 1.0435499877854168e+01}, {-1.0526123167960545e+01, -9.8952875868295376e+00, -9.3731595496467204e+00, -8.9072490999647691e+00, -8.4775290833798636e+00, -8.0736872850102248e+00, -7.6895401640404968e+00, -7.3210130327809484e+00, -6.9652411205511076e+00, -6.6201122626360274e+00, -6.2840112287748280e+00, -5.9556663267994852e+00, -5.6340521643499724e+00, -5.3183252246332708e+00, -5.0077796021987675e+00, -4.7018156474074990e+00, -4.3999171682281375e+00, -4.1016344745666560e+00, -3.8065715139453600e+00, -3.5143759357409059e+00, -3.2247312919920357e+00, -2.9373508230046212e+00, -2.6519724354306349e+00, -2.3683545886324011e+00, -2.0862728798817618e+00, -1.8055171714655447e+00, -1.5258891402098638e+00, -1.2472001569431179e+00, -9.6926942307117792e-01, -6.9192230581004455e-01, -4.1498882412107863e-01, -1.3830224498700971e-01, 1.3830224498700971e-01, 4.1498882412107863e-01, 6.9192230581004455e-01, 9.6926942307117792e-01, 1.2472001569431179e+00, 1.5258891402098638e+00, 1.8055171714655447e+00, 2.0862728798817618e+00, 2.3683545886324011e+00, 2.6519724354306349e+00, 2.9373508230046212e+00, 3.2247312919920357e+00, 3.5143759357409059e+00, 3.8065715139453600e+00, 4.1016344745666560e+00, 4.3999171682281375e+00, 4.7018156474074990e+00, 5.0077796021987675e+00, 5.3183252246332708e+00, 5.6340521643499724e+00, 5.9556663267994852e+00, 6.2840112287748280e+00, 6.6201122626360274e+00, 6.9652411205511076e+00, 7.3210130327809484e+00, 7.6895401640404968e+00, 8.0736872850102248e+00, 8.4775290833798636e+00, 8.9072490999647691e+00, 9.3731595496467204e+00, 9.8952875868295376e+00, 1.0526123167960545e+01}, {-1.0616022981878281e+01, -9.9869416916766838e+00, -9.4663293201553849e+00, -9.0018233229591331e+00, -8.5734447444179089e+00, -8.1709061780525847e+00, -7.7880390829895703e+00, -7.4207788343663230e+00, -7.0662679403068926e+00, -6.7223998201657338e+00, -6.3875637397870904e+00, -6.0604917788315049e+00, -5.7401618236902250e+00, -5.4257332976973487e+00, -5.1165030047214124e+00, -4.8118738520274640e+00, -4.5113321113682128e+00, -4.2144305099719546e+00, -3.9207754044447234e+00, -3.6300168776328952e+00, -3.3418409684468302e+00, -3.0559634843286707e+00, -2.7721250051570916e+00, -2.4900867953039354e+00, -2.2096274151691842e+00, -1.9305398759772254e+00, -1.6526292190403253e+00, -1.3757104277236682e+00, -1.0996066000569449e+00, -8.2414732440241278e-01, -5.4916721122159917e-01, -2.7450454175394473e-01, -0.0000000000000000e+00, 2.7450454175394473e-01, 5.4916721122159917e-01, 8.2414732440241278e-01, 1.0996066000569449e+00, 1.3757104277236682e+00, 1.6526292190403253e+00, 1.9305398759772254e+00, 2.2096274151691842e+00, 2.4900867953039354e+00, 2.7721250051570916e+00, 3.0559634843286707e+00, 3.3418409684468302e+00, 3.6300168776328952e+00, 3.9207754044447234e+00, 4.2144305099719546e+00, 4.5113321113682128e+00, 4.8118738520274640e+00, 5.1165030047214124e+00, 5.4257332976973487e+00, 5.7401618236902250e+00, 6.0604917788315049e+00, 6.3875637397870904e+00, 6.7223998201657338e+00, 7.0662679403068926e+00, 7.4207788343663230e+00, 7.7880390829895703e+00, 8.1709061780525847e+00, 8.5734447444179089e+00, 9.0018233229591331e+00, 9.4663293201553849e+00, 9.9869416916766838e+00, 1.0616022981878281e+01}, {-1.0705216257883158e+01, -1.0077856416579301e+01, -9.5587304502592971e+00, -9.0956010448419295e+00, -8.6685366107264805e+00, -8.2672741104998497e+00, -7.8856597261055059e+00, -7.5196386980596541e+00, -7.1663606590936650e+00, -6.8237244832006141e+00, -6.4901238172609474e+00, -6.1642944056838216e+00, -5.8452173103130356e+00, -5.5320547921086867e+00, -5.2241062602848638e+00, -4.9207770717124939e+00, -4.6215558496899147e+00, -4.3259976200905568e+00, -4.0337110220232306e+00, -3.7443484358240933e+00, -3.4575982403178411e+00, -3.1731786504386261e+00, -2.8908327450724003e+00, -2.6103244026894505e+00, -2.3314349368154352e+00, -2.0539602757725310e+00, -1.7777085685161123e+00, -1.5024981254275005e+00, -1.2281556226723449e+00, -9.5451451326831394e-01, -6.8141359873982055e-01, -4.0869572314721075e-01, -1.3620655703952730e-01, 1.3620655703952730e-01, 4.0869572314721075e-01, 6.8141359873982055e-01, 9.5451451326831394e-01, 1.2281556226723449e+00, 1.5024981254275005e+00, 1.7777085685161123e+00, 2.0539602757725310e+00, 2.3314349368154352e+00, 2.6103244026894505e+00, 2.8908327450724003e+00, 3.1731786504386261e+00, 3.4575982403178411e+00, 3.7443484358240933e+00, 4.0337110220232306e+00, 4.3259976200905568e+00, 4.6215558496899147e+00, 4.9207770717124939e+00, 5.2241062602848638e+00, 5.5320547921086867e+00, 5.8452173103130356e+00, 6.1642944056838216e+00, 6.4901238172609474e+00, 6.8237244832006141e+00, 7.1663606590936650e+00, 7.5196386980596541e+00, 7.8856597261055059e+00, 8.2672741104998497e+00, 8.6685366107264805e+00, 9.0956010448419295e+00, 9.5587304502592971e+00, 1.0077856416579301e+01, 1.0705216257883158e+01}, {-1.0793719285461286e+01, -1.0168049165614175e+01, -9.6503813634446356e+00, -9.1886016826884820e+00, -8.7628250943199557e+00, -8.3628125057261151e+00, -7.9824245547615575e+00, -7.6176161578278192e+00, -7.2655439249081999e+00, -6.9241120615277021e+00, -6.5917184866891132e+00, -6.2671025086846086e+00, -5.9492482679521004e+00, -5.6373207673775578e+00, -5.3306219248283462e+00, -5.0285594473595783e+00, -4.7306242061652037e+00, -4.4363734165111914e+00, -4.1454178838251625e+00, -3.8574121614750752e+00, -3.5720468340630473e+00, -3.2890423786892447e+00, -3.0081442150749433e+00, -2.7291186629245998e+00, -2.4517495992505411e+00, -2.1758356606878357e+00, -1.9011878731830645e+00, -1.6276276184711236e+00, -1.3549848665269235e+00, -1.0830966177633830e+00, -8.1180550955890352e-01, -5.4095854971511481e-01, -2.7040594535031914e-01, -0.0000000000000000e+00, 2.7040594535031914e-01, 5.4095854971511481e-01, 8.1180550955890352e-01, 1.0830966177633830e+00, 1.3549848665269235e+00, 1.6276276184711236e+00, 1.9011878731830645e+00, 2.1758356606878357e+00, 2.4517495992505411e+00, 2.7291186629245998e+00, 3.0081442150749433e+00, 3.2890423786892447e+00, 3.5720468340630473e+00, 3.8574121614750752e+00, 4.1454178838251625e+00, 4.4363734165111914e+00, 4.7306242061652037e+00, 5.0285594473595783e+00, 5.3306219248283462e+00, 5.6373207673775578e+00, 5.9492482679521004e+00, 6.2671025086846086e+00, 6.5917184866891132e+00, 6.9241120615277021e+00, 7.2655439249081999e+00, 7.6176161578278192e+00, 7.9824245547615575e+00, 8.3628125057261151e+00, 8.7628250943199557e+00, 9.1886016826884820e+00, 9.6503813634446356e+00, 1.0168049165614175e+01, 1.0793719285461286e+01}, {-1.0881547739512506e+01, -1.0257536674087854e+01, -9.7412997636867704e+00, -9.2808438835486236e+00, -8.8563297855819929e+00, -8.4575419119948716e+00, -8.0783550992846092e+00, -7.7147337577029216e+00, -7.3638413335052801e+00, -7.0235872465011688e+00, -6.6923735845747432e+00, -6.3689431247367301e+00, -6.0522829950450374e+00, -5.7415608508027303e+00, -5.4360810284450567e+00, -5.1352534929147948e+00, -4.8385712673985131e+00, -4.5455936557800598e+00, -4.2559335229494488e+00, -3.9692474811577245e+00, -3.6852281980879265e+00, -3.4035982804227491e+00, -3.1241053447888532e+00, -2.8465179952316144e+00, -2.5706225005795180e+00, -2.2962200172773377e+00, -2.0231242405790431e+00, -1.7511593940081669e+00, -1.4801584867781896e+00, -1.2099617834856000e+00, -9.4041544125892573e-01, -6.7137027764848267e-01, -4.0268063855845554e-01, -1.3420333993493833e-01, 1.3420333993493833e-01, 4.0268063855845554e-01, 6.7137027764848267e-01, 9.4041544125892573e-01, 1.2099617834856000e+00, 1.4801584867781896e+00, 1.7511593940081669e+00, 2.0231242405790431e+00, 2.2962200172773377e+00, 2.5706225005795180e+00, 2.8465179952316144e+00, 3.1241053447888532e+00, 3.4035982804227491e+00, 3.6852281980879265e+00, 3.9692474811577245e+00, 4.2559335229494488e+00, 4.5455936557800598e+00, 4.8385712673985131e+00, 5.1352534929147948e+00, 5.4360810284450567e+00, 5.7415608508027303e+00, 6.0522829950450374e+00, 6.3689431247367301e+00, 6.6923735845747432e+00, 7.0235872465011688e+00, 7.3638413335052801e+00, 7.7147337577029216e+00, 8.0783550992846092e+00, 8.4575419119948716e+00, 8.8563297855819929e+00, 9.2808438835486236e+00, 9.7412997636867704e+00, 1.0257536674087854e+01, 1.0881547739512506e+01}, {-1.0968716712272720e+01, -1.0346335043862190e+01, -9.8315026740330858e+00, -9.3723455663368824e+00, -8.9490694985983303e+00, -8.5514820514248040e+00, -8.1734720117891584e+00, -7.8110131087611858e+00, -7.4612754898399762e+00, -7.1221736773103954e+00, -6.7921138299353210e+00, -6.4698421035199560e+00, -6.1543485281550758e+00, -5.8448033276997977e+00, -5.5405131730790877e+00, -5.2408902012860343e+00, -4.9454294985999852e+00, -4.6536923643912962e+00, -4.3652936245432166e+00, -4.0798918452871904e+00, -3.7971816649246475e+00, -3.5168876985063164e+00, -3.2387596283073630e+00, -2.9625681999937008e+00, -2.6881019184401618e+00, -2.4151642892936240e+00, -2.1435714896364328e+00, -1.8731503781015579e+00, -1.6037367745786486e+00, -1.3351739542940309e+00, -1.0673113119622561e+00, -8.0000315987311321e-01, -5.3310762988307847e-01, -2.6648565380755118e-01, -0.0000000000000000e+00, 2.6648565380755118e-01, 5.3310762988307847e-01, 8.0000315987311321e-01, 1.0673113119622561e+00, 1.3351739542940309e+00, 1.6037367745786486e+00, 1.8731503781015579e+00, 2.1435714896364328e+00, 2.4151642892936240e+00, 2.6881019184401618e+00, 2.9625681999937008e+00, 3.2387596283073630e+00, 3.5168876985063164e+00, 3.7971816649246475e+00, 4.0798918452871904e+00, 4.3652936245432166e+00, 4.6536923643912962e+00, 4.9454294985999852e+00, 5.2408902012860343e+00, 5.5405131730790877e+00, 5.8448033276997977e+00, 6.1543485281550758e+00, 6.4698421035199560e+00, 6.7921138299353210e+00, 7.1221736773103954e+00, 7.4612754898399762e+00, 7.8110131087611858e+00, 8.1734720117891584e+00, 8.5514820514248040e+00, 8.9490694985983303e+00, 9.3723455663368824e+00, 9.8315026740330858e+00, 1.0346335043862190e+01, 1.0968716712272720e+01}, {-1.1055240743138121e+01, -1.0434459776321237e+01, -9.9210064725726337e+00, -9.4631239608462057e+00, -9.0410623133341144e+00, -8.6446518655005491e+00, -8.2677951152318059e+00, -7.9064749419687779e+00, -7.5578680649896128e+00, -7.2198940023018814e+00, -6.8909628903904032e+00, -6.5698241787566660e+00, -6.2554707188783159e+00, -5.9470752244713703e+00, -5.6439466223452381e+00, -5.3454991415732502e+00, -5.0512298489716008e+00, -4.7607019531713526e+00, -4.4735321501381859e+00, -4.1893808634925733e+00, -3.9079445988680890e+00, -3.6289498686372541e+00, -3.3521483007723556e+00, -3.0773126524497552e+00, -2.8042335229302870e+00, -2.5327166122907285e+00, -2.2625804097899467e+00, -1.9936542226231451e+00, -1.7257764756009522e+00, -1.4587932269483976e+00, -1.1925568563654070e+00, -9.2692488970661657e-01, -6.6175893081256654e-01, -3.9692367564298847e-01, -1.3228598727031571e-01, 1.3228598727031571e-01, 3.9692367564298847e-01, 6.6175893081256654e-01, 9.2692488970661657e-01, 1.1925568563654070e+00, 1.4587932269483976e+00, 1.7257764756009522e+00, 1.9936542226231451e+00, 2.2625804097899467e+00, 2.5327166122907285e+00, 2.8042335229302870e+00, 3.0773126524497552e+00, 3.3521483007723556e+00, 3.6289498686372541e+00, 3.9079445988680890e+00, 4.1893808634925733e+00, 4.4735321501381859e+00, 4.7607019531713526e+00, 5.0512298489716008e+00, 5.3454991415732502e+00, 5.6439466223452381e+00, 5.9470752244713703e+00, 6.2554707188783159e+00, 6.5698241787566660e+00, 6.8909628903904032e+00, 7.2198940023018814e+00, 7.5578680649896128e+00, 7.9064749419687779e+00, 8.2677951152318059e+00, 8.6446518655005491e+00, 9.0410623133341144e+00, 9.4631239608462057e+00, 9.9210064725726337e+00, 1.0434459776321237e+01, 1.1055240743138121e+01}, {-1.1141133846557336e+01, -1.0521925803168939e+01, -1.0009826926005323e+01, -9.5531956441224679e+00, -9.1323256149194787e+00, -8.7370695574210657e+00, -8.3613434490107519e+00, -8.0011391572542987e+00, -7.6536398489544064e+00, -7.3167699357978755e+00, -6.9889434433253230e+00, -6.6689130340885914e+00, -6.3556743048467315e+00, -6.0484023852002728e+00, -5.7464083842334572e+00, -5.4491085484699262e+00, -5.1560018484650616e+00, -4.8666533221367576e+00, -4.5806814514481742e+00, -4.2977484283048772e+00, -4.0175525306328757e+00, -3.7398220661958628e+00, -3.4643104988218911e+00, -3.1907924783359922e+00, -2.9190605692775651e+00, -2.6489225254318436e+00, -2.3801989943566357e+00, -2.1127215630246923e+00, -1.8463310754751214e+00, -1.5808761680325296e+00, -1.3162119786216788e+00, -1.0521989949595671e+00, -7.8870201263520334e-01, -5.2558917877833533e-01, -2.6273110051935877e-01, -0.0000000000000000e+00, 2.6273110051935877e-01, 5.2558917877833533e-01, 7.8870201263520334e-01, 1.0521989949595671e+00, 1.3162119786216788e+00, 1.5808761680325296e+00, 1.8463310754751214e+00, 2.1127215630246923e+00, 2.3801989943566357e+00, 2.6489225254318436e+00, 2.9190605692775651e+00, 3.1907924783359922e+00, 3.4643104988218911e+00, 3.7398220661958628e+00, 4.0175525306328757e+00, 4.2977484283048772e+00, 4.5806814514481742e+00, 4.8666533221367576e+00, 5.1560018484650616e+00, 5.4491085484699262e+00, 5.7464083842334572e+00, 6.0484023852002728e+00, 6.3556743048467315e+00, 6.6689130340885914e+00, 6.9889434433253230e+00, 7.3167699357978755e+00, 7.6536398489544064e+00, 8.0011391572542987e+00, 8.3613434490107519e+00, 8.7370695574210657e+00, 9.1323256149194787e+00, 9.5531956441224679e+00, 1.0009826926005323e+01, 1.0521925803168939e+01, 1.1141133846557336e+01}, {-1.1226409538142136e+01, -1.0608747515229252e+01, -1.0097979221003259e+01, -9.6425765744143064e+00, -9.2228761302815698e+00, -8.8287526315494791e+00, -8.4541353114024211e+00, -8.0950248691313433e+00, -7.7486107996948919e+00, -7.4128223108085409e+00, -7.0860772325710890e+00, -6.7671313640535109e+00, -6.4549829753707284e+00, -6.1488095423716089e+00, -5.8479242873741697e+00, -5.5517454045920136e+00, -5.2597736967589261e+00, -4.9715759567771789e+00, -4.6867723746994256e+00, -4.4050268283718435e+00, -4.1260392804003079e+00, -3.8495397401994360e+00, -3.5752834066737424e+00, -3.3030467134928974e+00, -3.0326240725636300e+00, -2.7638251631581228e+00, -2.4964726512514903e+00, -2.2304002505260021e+00, -1.9654510562578547e+00, -1.7014760979685193e+00, -1.4383330677067736e+00, -1.1758851891099782e+00, -9.1400019866369742e-01, -6.5254941532698807e-01, -3.9140687826621273e-01, -1.3044853509282020e-01, 1.3044853509282020e-01, 3.9140687826621273e-01, 6.5254941532698807e-01, 9.1400019866369742e-01, 1.1758851891099782e+00, 1.4383330677067736e+00, 1.7014760979685193e+00, 1.9654510562578547e+00, 2.2304002505260021e+00, 2.4964726512514903e+00, 2.7638251631581228e+00, 3.0326240725636300e+00, 3.3030467134928974e+00, 3.5752834066737424e+00, 3.8495397401994360e+00, 4.1260392804003079e+00, 4.4050268283718435e+00, 4.6867723746994256e+00, 4.9715759567771789e+00, 5.2597736967589261e+00, 5.5517454045920136e+00, 5.8479242873741697e+00, 6.1488095423716089e+00, 6.4549829753707284e+00, 6.7671313640535109e+00, 7.0860772325710890e+00, 7.4128223108085409e+00, 7.7486107996948919e+00, 8.0950248691313433e+00, 8.4541353114024211e+00, 8.8287526315494791e+00, 9.2228761302815698e+00, 9.6425765744143064e+00, 1.0097979221003259e+01, 1.0608747515229252e+01, 1.1226409538142136e+01}, {-1.1311080859133723e+01, -1.0694938789404631e+01, -1.0185477993538820e+01, -9.7312821228925461e+00, -9.3127299623383131e+00, -8.9197179302027116e+00, -8.5461882990986897e+00, -8.1881504491623041e+00, -7.8428000887281044e+00, -7.5080711279939001e+00, -7.1823851209949314e+00, -6.8645009305993021e+00, -6.5534194322069030e+00, -6.2483203822637563e+00, -5.9485190514660768e+00, -5.6534355164057573e+00, -5.3625723452058249e+00, -5.0754980166052253e+00, -4.7918343564389145e+00, -4.5112468522638922e+00, -4.2334370704564908e+00, -3.9581366357170062e+00, -3.6851023893880592e+00, -3.4141124491940373e+00, -3.1449629665080243e+00, -2.8774654290158654e+00, -2.6114443936789562e+00, -2.3467355617654575e+00, -2.0831841274592904e+00, -1.8206433462185645e+00, -1.5589732800480507e+00, -1.2980396851534748e+00, -1.0377130137484731e+00, -7.7786750657853077e-01, -5.1838035636125168e-01, -2.5913092507112634e-01, -0.0000000000000000e+00, 2.5913092507112634e-01, 5.1838035636125168e-01, 7.7786750657853077e-01, 1.0377130137484731e+00, 1.2980396851534748e+00, 1.5589732800480507e+00, 1.8206433462185645e+00, 2.0831841274592904e+00, 2.3467355617654575e+00, 2.6114443936789562e+00, 2.8774654290158654e+00, 3.1449629665080243e+00, 3.4141124491940373e+00, 3.6851023893880592e+00, 3.9581366357170062e+00, 4.2334370704564908e+00, 4.5112468522638922e+00, 4.7918343564389145e+00, 5.0754980166052253e+00, 5.3625723452058249e+00, 5.6534355164057573e+00, 5.9485190514660768e+00, 6.2483203822637563e+00, 6.5534194322069030e+00, 6.8645009305993021e+00, 7.1823851209949314e+00, 7.5080711279939001e+00, 7.8428000887281044e+00, 8.1881504491623041e+00, 8.5461882990986897e+00, 8.9197179302027116e+00, 9.3127299623383131e+00, 9.7312821228925461e+00, 1.0185477993538820e+01, 1.0694938789404631e+01, 1.1311080859133723e+01}, {-1.1395160399349303e+01, -1.0780513013934538e+01, -1.0272337356338001e+01, -9.8193271033153593e+00, -9.4019026219489774e+00, -9.0099816679963673e+00, -8.6375193440825591e+00, -8.2805335655260475e+00, -7.9362261435724362e+00, -7.6025356011958438e+00, -7.2778871393556734e+00, -6.9610426155273659e+00, -6.6510054458855254e+00, -6.3469576054906103e+00, -6.0482163524027337e+00, -5.7542035843517603e+00, -5.4644235724164387e+00, -5.1784464167185336e+00, -4.8958955116562031e+00, -4.6164378838097413e+00, -4.3397766284785542e+00, -4.0656449059380266e+00, -3.7938011146597774e+00, -3.5240249647298416e+00, -3.2561142480573673e+00, -2.9898821536352491e+00, -2.7251550130837989e+00, -2.4617703885377660e+00, -2.1995754346550642e+00, -1.9384254811801831e+00, -1.6781827934921525e+00, -1.4187154768845949e+00, -1.1598964966533338e+00, -9.0160279089609208e-01, -6.4371445661134197e-01, -3.8611399247334727e-01, -1.2868558374092035e-01, 1.2868558374092035e-01, 3.8611399247334727e-01, 6.4371445661134197e-01, 9.0160279089609208e-01, 1.1598964966533338e+00, 1.4187154768845949e+00, 1.6781827934921525e+00, 1.9384254811801831e+00, 2.1995754346550642e+00, 2.4617703885377660e+00, 2.7251550130837989e+00, 2.9898821536352491e+00, 3.2561142480573673e+00, 3.5240249647298416e+00, 3.7938011146597774e+00, 4.0656449059380266e+00, 4.3397766284785542e+00, 4.6164378838097413e+00, 4.8958955116562031e+00, 5.1784464167185336e+00, 5.4644235724164387e+00, 5.7542035843517603e+00, 6.0482163524027337e+00, 6.3469576054906103e+00, 6.6510054458855254e+00, 6.9610426155273659e+00, 7.2778871393556734e+00, 7.6025356011958438e+00, 7.9362261435724362e+00, 8.2805335655260475e+00, 8.6375193440825591e+00, 9.0099816679963673e+00, 9.4019026219489774e+00, 9.8193271033153593e+00, 1.0272337356338001e+01, 1.0780513013934538e+01, 1.1395160399349303e+01}, {-1.1478660318722643e+01, -1.0865483112083050e+01, -1.0358570924603207e+01, -9.9067257997991209e+00, -9.4904090577984004e+00, -9.0995594639401105e+00, -8.7281447480576215e+00, -8.3721912199266999e+00, -8.0289066873027544e+00, -7.6962341998287283e+00, -7.3726025317424613e+00, -7.0567764692174766e+00, -6.7477619079872566e+00, -6.4447429831267424e+00, -6.1470388825769424e+00, -5.8540732676978866e+00, -5.5653520540734327e+00, -5.2804469030361734e+00, -4.9989827149592099e+00, -4.7206279897915646e+00, -4.4450872824012313e+00, -4.1720952149448500e+00, -3.9014116643261456e+00, -3.6328178485882909e+00, -3.3661131093032384e+00, -3.1011122385952579e+00, -2.8376432363425028e+00, -2.5755454098889712e+00, -2.3146677482934548e+00, -2.0548675177858016e+00, -1.7960090360977110e+00, -1.5379625916624640e+00, -1.2806034800245349e+00, -1.0238111346569745e+00, -7.6746833310481610e-01, -5.1146046221189689e-01, -2.5567482833134803e-01, -0.0000000000000000e+00, 2.5567482833134803e-01, 5.1146046221189689e-01, 7.6746833310481610e-01, 1.0238111346569745e+00, 1.2806034800245349e+00, 1.5379625916624640e+00, 1.7960090360977110e+00, 2.0548675177858016e+00, 2.3146677482934548e+00, 2.5755454098889712e+00, 2.8376432363425028e+00, 3.1011122385952579e+00, 3.3661131093032384e+00, 3.6328178485882909e+00, 3.9014116643261456e+00, 4.1720952149448500e+00, 4.4450872824012313e+00, 4.7206279897915646e+00, 4.9989827149592099e+00, 5.2804469030361734e+00, 5.5653520540734327e+00, 5.8540732676978866e+00, 6.1470388825769424e+00, 6.4447429831267424e+00, 6.7477619079872566e+00, 7.0567764692174766e+00, 7.3726025317424613e+00, 7.6962341998287283e+00, 8.0289066873027544e+00, 8.3721912199266999e+00, 8.7281447480576215e+00, 9.0995594639401105e+00, 9.4904090577984004e+00, 9.9067257997991209e+00, 1.0358570924603207e+01, 1.0865483112083050e+01, 1.1478660318722643e+01}, {-1.1561592367542413e+01, -1.0949861564373141e+01, -1.0444191840136728e+01, -9.9934919928404522e+00, -9.5782636843755515e+00, -9.1884663714605921e+00, -8.8180802146261925e+00, -8.4631397820581817e+00, -8.1208587754520742e+00, -7.7891846883888824e+00, -7.4665497978837827e+00, -7.1517217559506374e+00, -6.8437088797189292e+00, -6.5416974088024276e+00, -6.2450084067917304e+00, -5.9530672445968058e+00, -5.6653814275042969e+00, -5.3815241217984982e+00, -5.1011216754614015e+00, -4.8238440007350292e+00, -4.5493970476880525e+00, -4.2775168321151087e+00, -4.0079646366324129e+00, -3.7405231094103377e+00, -3.4749930580623096e+00, -3.2111907876889831e+00, -2.9489458689195023e+00, -2.6880992485383528e+00, -2.4285016349547641e+00, -2.1700121054020434e+00, -1.9124968927478689e+00, -1.6558283181292228e+00, -1.3998838419857680e+00, -1.1445452109440197e+00, -8.8969768175512143e-01, -6.3522930636766928e-01, -3.8103026441027604e-01, -1.2699223100184112e-01, 1.2699223100184112e-01, 3.8103026441027604e-01, 6.3522930636766928e-01, 8.8969768175512143e-01, 1.1445452109440197e+00, 1.3998838419857680e+00, 1.6558283181292228e+00, 1.9124968927478689e+00, 2.1700121054020434e+00, 2.4285016349547641e+00, 2.6880992485383528e+00, 2.9489458689195023e+00, 3.2111907876889831e+00, 3.4749930580623096e+00, 3.7405231094103377e+00, 4.0079646366324129e+00, 4.2775168321151087e+00, 4.5493970476880525e+00, 4.8238440007350292e+00, 5.1011216754614015e+00, 5.3815241217984982e+00, 5.6653814275042969e+00, 5.9530672445968058e+00, 6.2450084067917304e+00, 6.5416974088024276e+00, 6.8437088797189292e+00, 7.1517217559506374e+00, 7.4665497978837827e+00, 7.7891846883888824e+00, 8.1208587754520742e+00, 8.4631397820581817e+00, 8.8180802146261925e+00, 9.1884663714605921e+00, 9.5782636843755515e+00, 9.9934919928404522e+00, 1.0444191840136728e+01, 1.0949861564373141e+01, 1.1561592367542413e+01}, {-1.1643967905483196e+01, -1.1033660429475029e+01, -1.0529212793984577e+01, -1.0079638983721908e+01, -9.6654804081925363e+00, -9.2767169065128172e+00, -8.9073408793931357e+00, -8.5533950218190302e+00, -8.2120988304736517e+00, -7.8814041633182299e+00, -7.5597467325857197e+00, -7.2458969961152926e+00, -6.9388656371030670e+00, -6.6378409471161133e+00, -6.3421458141623201e+00, -6.0512072677740329e+00, -5.7645343514856853e+00, -5.4817016838558219e+00, -5.2023370059655702e+00, -4.9261115854472983e+00, -4.6527327077376199e+00, -4.3819377189728366e+00, -4.1134892401757890e+00, -3.8471712777564733e+00, -3.5827860282892376e+00, -3.3201512269147213e+00, -3.0590979254933970e+00, -2.7994686133415088e+00, -2.5411156130214039e+00, -2.2838996982733861e+00, -2.0276888921639609e+00, -1.7723574118602183e+00, -1.5177847328096994e+00, -1.2638547500001409e+00, -1.0104550177477929e+00, -7.5747605237336058e-01, -5.0481068435860232e-01, -2.5235344827118406e-01, -0.0000000000000000e+00, 2.5235344827118406e-01, 5.0481068435860232e-01, 7.5747605237336058e-01, 1.0104550177477929e+00, 1.2638547500001409e+00, 1.5177847328096994e+00, 1.7723574118602183e+00, 2.0276888921639609e+00, 2.2838996982733861e+00, 2.5411156130214039e+00, 2.7994686133415088e+00, 3.0590979254933970e+00, 3.3201512269147213e+00, 3.5827860282892376e+00, 3.8471712777564733e+00, 4.1134892401757890e+00, 4.3819377189728366e+00, 4.6527327077376199e+00, 4.9261115854472983e+00, 5.2023370059655702e+00, 5.4817016838558219e+00, 5.7645343514856853e+00, 6.0512072677740329e+00, 6.3421458141623201e+00, 6.6378409471161133e+00, 6.9388656371030670e+00, 7.2458969961152926e+00, 7.5597467325857197e+00, 7.8814041633182299e+00, 8.2120988304736517e+00, 8.5533950218190302e+00, 8.9073408793931357e+00, 9.2767169065128172e+00, 9.6654804081925363e+00, 1.0079638983721908e+01, 1.0529212793984577e+01, 1.1033660429475029e+01, 1.1643967905483196e+01}, {-1.1725797919515925e+01, -1.1116891363846698e+01, -1.0613646047709890e+01, -1.0165179617422121e+01, -9.7520726523771355e+00, -9.3643250739262687e+00, -8.9959413381560331e+00, -8.6429721394539492e+00, -8.3026426739573083e+00, -7.9729090874349415e+00, -7.6522104625334553e+00, -7.3393200055543293e+00, -7.0332507130647253e+00, -6.7331928786770474e+00, -6.4384711663544172e+00, -6.1485142162283823e+00, -5.8628325617022545e+00, -5.5810022242153172e+00, -5.3026522869660511e+00, -5.0274553198842957e+00, -4.7551198880737857e+00, -4.4853846092140870e+00, -4.2180133803413131e+00, -3.9527914995987943e+00, -3.6895224813523542e+00, -3.4280254143563189e+00, -3.1681327493707792e+00, -2.9096884292910694e+00, -2.6525462944632925e+00, -2.3965687104578790e+00, -2.1416253765529731e+00, -1.8875922815137989e+00, -1.6343507796298868e+00, -1.3817867648795250e+00, -1.1297899248837724e+00, -8.7825305924819486e-01, -6.2707144915742807e-01, -3.7614226682388563e-01, -1.2536401469850444e-01, 1.2536401469850444e-01, 3.7614226682388563e-01, 6.2707144915742807e-01, 8.7825305924819486e-01, 1.1297899248837724e+00, 1.3817867648795250e+00, 1.6343507796298868e+00, 1.8875922815137989e+00, 2.1416253765529731e+00, 2.3965687104578790e+00, 2.6525462944632925e+00, 2.9096884292910694e+00, 3.1681327493707792e+00, 3.4280254143563189e+00, 3.6895224813523542e+00, 3.9527914995987943e+00, 4.2180133803413131e+00, 4.4853846092140870e+00, 4.7551198880737857e+00, 5.0274553198842957e+00, 5.3026522869660511e+00, 5.5810022242153172e+00, 5.8628325617022545e+00, 6.1485142162283823e+00, 6.4384711663544172e+00, 6.7331928786770474e+00, 7.0332507130647253e+00, 7.3393200055543293e+00, 7.6522104625334553e+00, 7.9729090874349415e+00, 8.3026426739573083e+00, 8.6429721394539492e+00, 8.9959413381560331e+00, 9.3643250739262687e+00, 9.7520726523771355e+00, 1.0165179617422121e+01, 1.0613646047709890e+01, 1.1116891363846698e+01, 1.1725797919515925e+01}, {-1.1807093040777294e+01, -1.1199565640216381e+01, -1.0697503453395814e+01, -1.0250126304140645e+01, -9.8380533797602858e+00, -9.4513043921191180e+00, -9.0838956733280174e+00, -8.7318857937825296e+00, -8.3925055567758680e+00, -8.0637153221240894e+00, -7.7439574806678753e+00, -7.4320079322856305e+00, -7.1268819366716176e+00, -6.8277717420599027e+00, -6.5340037424695643e+00, -6.2450081432878877e+00, -5.9602969222394462e+00, -5.6794474572664067e+00, -5.4020901259356995e+00, -5.1278987508656595e+00, -4.8565831248972122e+00, -4.5878830825516648e+00, -4.3215637389507622e+00, -4.0574116223471224e+00, -3.7952314990808915e+00, -3.5348437409765978e+00, -3.2760821218442313e+00, -3.0187919563650998e+00, -2.7628285142266278e+00, -2.5080556569501704e+00, -2.2543446558260460e+00, -2.0015731577016731e+00, -1.7496242717478425e+00, -1.4983857552446240e+00, -1.2477492802359769e+00, -9.9760976585826833e-01, -7.4786476344152575e-01, -4.9841388325234109e-01, -2.4915825309625725e-01, -0.0000000000000000e+00, 2.4915825309625725e-01, 4.9841388325234109e-01, 7.4786476344152575e-01, 9.9760976585826833e-01, 1.2477492802359769e+00, 1.4983857552446240e+00, 1.7496242717478425e+00, 2.0015731577016731e+00, 2.2543446558260460e+00, 2.5080556569501704e+00, 2.7628285142266278e+00, 3.0187919563650998e+00, 3.2760821218442313e+00, 3.5348437409765978e+00, 3.7952314990808915e+00, 4.0574116223471224e+00, 4.3215637389507622e+00, 4.5878830825516648e+00, 4.8565831248972122e+00, 5.1278987508656595e+00, 5.4020901259356995e+00, 5.6794474572664067e+00, 5.9602969222394462e+00, 6.2450081432878877e+00, 6.5340037424695643e+00, 6.8277717420599027e+00, 7.1268819366716176e+00, 7.4320079322856305e+00, 7.7439574806678753e+00, 8.0637153221240894e+00, 8.3925055567758680e+00, 8.7318857937825296e+00, 9.0838956733280174e+00, 9.4513043921191180e+00, 9.8380533797602858e+00, 1.0250126304140645e+01, 1.0697503453395814e+01, 1.1199565640216381e+01, 1.1807093040777294e+01}, {-1.1887863560471148e+01, -1.1281694164989270e+01, -1.0780796472469154e+01, -1.0334491039538371e+01, -9.9234351145692425e+00, -9.5376679163020608e+00, -9.1712174787264829e+00, -8.8201501286610533e+00, -8.4817021873215737e+00, -8.1538381574634560e+00, -7.8350036783292891e+00, -7.5239772908068669e+00, -7.2197764697589237e+00, -6.9215953729258182e+00, -6.6287620808575998e+00, -6.3407083213299842e+00, -6.0569474734510278e+00, -5.7770582280615690e+00, -5.5006722123151564e+00, -5.2274644551006757e+00, -4.9571459285134285e+00, -4.6894576329528137e+00, -4.4241658477651837e+00, -4.1610582741258364e+00, -3.8999408693873892e+00, -3.6406352232272088e+00, -3.3829763625124016e+00, -3.1268108983731295e+00, -2.8719954485287333e+00, -2.6183952824717842e+00, -2.3658831480742251e+00, -2.1143382465070100e+00, -1.8636453287449284e+00, -1.6136938918510606e+00, -1.3643774570540068e+00, -1.1155929146033490e+00, -8.6723992270397532e-01, -6.1922034962756711e-01, -3.7143774948304431e-01, -1.2379686317313206e-01, 1.2379686317313206e-01, 3.7143774948304431e-01, 6.1922034962756711e-01, 8.6723992270397532e-01, 1.1155929146033490e+00, 1.3643774570540068e+00, 1.6136938918510606e+00, 1.8636453287449284e+00, 2.1143382465070100e+00, 2.3658831480742251e+00, 2.6183952824717842e+00, 2.8719954485287333e+00, 3.1268108983731295e+00, 3.3829763625124016e+00, 3.6406352232272088e+00, 3.8999408693873892e+00, 4.1610582741258364e+00, 4.4241658477651837e+00, 4.6894576329528137e+00, 4.9571459285134285e+00, 5.2274644551006757e+00, 5.5006722123151564e+00, 5.7770582280615690e+00, 6.0569474734510278e+00, 6.3407083213299842e+00, 6.6287620808575998e+00, 6.9215953729258182e+00, 7.2197764697589237e+00, 7.5239772908068669e+00, 7.8350036783292891e+00, 8.1538381574634560e+00, 8.4817021873215737e+00, 8.8201501286610533e+00, 9.1712174787264829e+00, 9.5376679163020608e+00, 9.9234351145692425e+00, 1.0334491039538371e+01, 1.0780796472469154e+01, 1.1281694164989270e+01, 1.1887863560471148e+01}, {-1.1968119444868723e+01, -1.1363287494653905e+01, -1.0863536193428574e+01, -1.0418285423785731e+01, -1.0008229962827862e+01, -9.6234282602828909e+00, -9.2579198828492224e+00, -8.9077787978104048e+00, -8.5702467579780226e+00, -8.2432923404437446e+00, -7.9253643753426406e+00, -7.6152439941755770e+00, -7.3119508411483105e+00, -7.0146809405398773e+00, -6.7227640181091326e+00, -6.4356332834442265e+00, -6.1528034765082218e+00, -5.8738545599912273e+00, -5.5984193685789059e+00, -5.3261740939400637e+00, -5.0568308420977290e+00, -4.7901317317816865e+00, -4.5258441564113081e+00, -4.2637569369381021e+00, -4.0036771651776295e+00, -3.7454275882737633e+00, -3.4888444214602070e+00, -3.2337755028119282e+00, -2.9800787232025514e+00, -2.7276206792242430e+00, -2.4762755077735275e+00, -2.2259238693277426e+00, -1.9764520533164986e+00, -1.7277511839192137e+00, -1.4797165084468731e+00, -1.2322467534512360e+00, -9.8524353603723147e-01, -7.3861081967444187e-01, -4.9225440521533759e-01, -2.4608144890838049e-01, -0.0000000000000000e+00, 2.4608144890838049e-01, 4.9225440521533759e-01, 7.3861081967444187e-01, 9.8524353603723147e-01, 1.2322467534512360e+00, 1.4797165084468731e+00, 1.7277511839192137e+00, 1.9764520533164986e+00, 2.2259238693277426e+00, 2.4762755077735275e+00, 2.7276206792242430e+00, 2.9800787232025514e+00, 3.2337755028119282e+00, 3.4888444214602070e+00, 3.7454275882737633e+00, 4.0036771651776295e+00, 4.2637569369381021e+00, 4.5258441564113081e+00, 4.7901317317816865e+00, 5.0568308420977290e+00, 5.3261740939400637e+00, 5.5984193685789059e+00, 5.8738545599912273e+00, 6.1528034765082218e+00, 6.4356332834442265e+00, 6.7227640181091326e+00, 7.0146809405398773e+00, 7.3119508411483105e+00, 7.6152439941755770e+00, 7.9253643753426406e+00, 8.2432923404437446e+00, 8.5702467579780226e+00, 8.9077787978104048e+00, 9.2579198828492224e+00, 9.6234282602828909e+00, 1.0008229962827862e+01, 1.0418285423785731e+01, 1.0863536193428574e+01, 1.1363287494653905e+01, 1.1968119444868723e+01}, {-1.2047870349469452e+01, -1.1444355851257512e+01, -1.0945733348554121e+01, -1.0501520679503271e+01, -1.0092449631556644e+01, -9.7085976169732788e+00, -9.3440155707490522e+00, -8.9947849881314195e+00, -8.6581529699601738e+00, -8.3320921014281222e+00, -8.0150543482026926e+00, -7.7058233840379780e+00, -7.4034209786511349e+00, -7.1070449818933454e+00, -6.8160267254566378e+00, -6.5298008622888712e+00, -6.2478834549069706e+00, -5.9698556991575886e+00, -5.6953515977146445e+00, -5.4240484642257165e+00, -5.1556594962091573e+00, -4.8899278863041147e+00, -4.6266220952405250e+00, -4.3655320142842475e+00, -4.1064658171809416e+00, -3.8492473525444271e+00, -3.5937139640934332e+00, -3.3397146526239907e+00, -3.0871085130972600e+00, -2.8357633947424321e+00, -2.5855547430080739e+00, -2.3363645905095152e+00, -2.0880806704972801e+00, -1.8405956313004481e+00, -1.5938063340319311e+00, -1.3476132188376881e+00, -1.1019197273183625e+00, -8.5663177059026308e-01, -6.1165723388752291e-01, -3.6690550971654429e-01, -1.2228705241518351e-01, 1.2228705241518351e-01, 3.6690550971654429e-01, 6.1165723388752291e-01, 8.5663177059026308e-01, 1.1019197273183625e+00, 1.3476132188376881e+00, 1.5938063340319311e+00, 1.8405956313004481e+00, 2.0880806704972801e+00, 2.3363645905095152e+00, 2.5855547430080739e+00, 2.8357633947424321e+00, 3.0871085130972600e+00, 3.3397146526239907e+00, 3.5937139640934332e+00, 3.8492473525444271e+00, 4.1064658171809416e+00, 4.3655320142842475e+00, 4.6266220952405250e+00, 4.8899278863041147e+00, 5.1556594962091573e+00, 5.4240484642257165e+00, 5.6953515977146445e+00, 5.9698556991575886e+00, 6.2478834549069706e+00, 6.5298008622888712e+00, 6.8160267254566378e+00, 7.1070449818933454e+00, 7.4034209786511349e+00, 7.7058233840379780e+00, 8.0150543482026926e+00, 8.3320921014281222e+00, 8.6581529699601738e+00, 8.9947849881314195e+00, 9.3440155707490522e+00, 9.7085976169732788e+00, 1.0092449631556644e+01, 1.0501520679503271e+01, 1.0945733348554121e+01, 1.1444355851257512e+01, 1.2047870349469452e+01}, {-1.2127125632378913e+01, -1.1524909137013976e+01, -1.1027398329668573e+01, -1.0584207668672128e+01, -1.0176105446857637e+01, -9.7931877776907488e+00, -9.4295168046084115e+00, -9.0811814416185097e+00, -8.7454340566434574e+00, -8.4202511789832108e+00, -8.1040878565034831e+00, -7.7957302587642490e+00, -7.4942022390283798e+00, -7.1987034336195581e+00, -6.9085667427912707e+00, -6.6232282263685835e+00, -6.3422052331830958e+00, -6.0650801557222689e+00, -5.7914881274189227e+00, -5.5211075455728480e+00, -5.2536526594233770e+00, -4.9888676939643233e+00, -4.7265221335751297e+00, -4.4664068937399284e+00, -4.2083311812642945e+00, -3.9521198942311013e+00, -3.6976114493318364e+00, -3.4446559506485350e+00, -3.1931136334230796e+00, -2.9428535308492294e+00, -2.6937523228426583e+00, -2.4456933340503899e+00, -2.1985656547350549e+00, -1.9522633630987765e+00, -1.7066848314488341e+00, -1.4617321016098621e+00, -1.2173103173449662e+00, -9.7332720340140344e-01, -7.2969258225037825e-01, -4.8631792072343311e-01, -2.4311589961848629e-01, -0.0000000000000000e+00, 2.4311589961848629e-01, 4.8631792072343311e-01, 7.2969258225037825e-01, 9.7332720340140344e-01, 1.2173103173449662e+00, 1.4617321016098621e+00, 1.7066848314488341e+00, 1.9522633630987765e+00, 2.1985656547350549e+00, 2.4456933340503899e+00, 2.6937523228426583e+00, 2.9428535308492294e+00, 3.1931136334230796e+00, 3.4446559506485350e+00, 3.6976114493318364e+00, 3.9521198942311013e+00, 4.2083311812642945e+00, 4.4664068937399284e+00, 4.7265221335751297e+00, 4.9888676939643233e+00, 5.2536526594233770e+00, 5.5211075455728480e+00, 5.7914881274189227e+00, 6.0650801557222689e+00, 6.3422052331830958e+00, 6.6232282263685835e+00, 6.9085667427912707e+00, 7.1987034336195581e+00, 7.4942022390283798e+00, 7.7957302587642490e+00, 8.1040878565034831e+00, 8.4202511789832108e+00, 8.7454340566434574e+00, 9.0811814416185097e+00, 9.4295168046084115e+00, 9.7931877776907488e+00, 1.0176105446857637e+01, 1.0584207668672128e+01, 1.1027398329668573e+01, 1.1524909137013976e+01, 1.2127125632378913e+01}, {-1.2205894366956139e+01, -1.1604956948103077e+01, -1.1108541203015454e+01, -1.0666356908585685e+01, -1.0259208370962089e+01, -9.8772101503410621e+00, -9.5144354431069669e+00, -9.1669804759729860e+00, -8.8321028054925428e+00, -8.5077828432020937e+00, -8.1924786677436181e+00, -7.8849788998338592e+00, -7.5843094360641796e+00, -7.2896716618750510e+00, -7.0004000104832143e+00, -6.7159319139391096e+00, -6.4357859730612450e+00, -6.1595457424759266e+00, -5.8868474512821898e+00, -5.6173705443855964e+00, -5.3508302854168104e+00, -5.0869718928011789e+00, -4.8255658337490095e+00, -4.5664040049460510e+00, -4.3092966007328037e+00, -4.0540695203033383e+00, -3.8005622017862843e+00, -3.5486257974651720e+00, -3.2981216238257258e+00, -3.0489198345947157e+00, -2.8008982758405363e+00, -2.5539414905028606e+00, -2.3079398460883205e+00, -2.0627887641978626e+00, -1.8183880343913310e+00, -1.5746411979031998e+00, -1.3314549890897636e+00, -1.0887388243534069e+00, -8.4640432975900237e-01, -6.0436489970992124e-01, -3.6253527994578344e-01, -1.2083116880501313e-01, 1.2083116880501313e-01, 3.6253527994578344e-01, 6.0436489970992124e-01, 8.4640432975900237e-01, 1.0887388243534069e+00, 1.3314549890897636e+00, 1.5746411979031998e+00, 1.8183880343913310e+00, 2.0627887641978626e+00, 2.3079398460883205e+00, 2.5539414905028606e+00, 2.8008982758405363e+00, 3.0489198345947157e+00, 3.2981216238257258e+00, 3.5486257974651720e+00, 3.8005622017862843e+00, 4.0540695203033383e+00, 4.3092966007328037e+00, 4.5664040049460510e+00, 4.8255658337490095e+00, 5.0869718928011789e+00, 5.3508302854168104e+00, 5.6173705443855964e+00, 5.8868474512821898e+00, 6.1595457424759266e+00, 6.4357859730612450e+00, 6.7159319139391096e+00, 7.0004000104832143e+00, 7.2896716618750510e+00, 7.5843094360641796e+00, 7.8849788998338592e+00, 8.1924786677436181e+00, 8.5077828432020937e+00, 8.8321028054925428e+00, 9.1669804759729860e+00, 9.5144354431069669e+00, 9.8772101503410621e+00, 1.0259208370962089e+01, 1.0666356908585685e+01, 1.1108541203015454e+01, 1.1604956948103077e+01, 1.2205894366956139e+01}, {-1.2284185353778504e+01, -1.1684508587714936e+01, -1.1189171723313381e+01, -1.0747978586907845e+01, -1.0341769018312585e+01, -9.9606757765591638e+00, -9.5987829596674032e+00, -9.2521940040089010e+00, -8.9181715786909077e+00, -8.5946999176295051e+00, -8.2802400806274559e+00, -7.9735830966018995e+00, -7.6737568668958440e+00, -7.3799644903419361e+00, -7.0915418991761436e+00, -6.8079278647256025e+00, -6.5286422072422212e+00, -6.2532696108544226e+00, -5.9814473672099631e+00, -5.7128559348775809e+00, -5.4472115568012640e+00, -5.1842604083343016e+00, -4.9237739013081612e+00, -4.6655448734152234e+00, -4.4093844640660000e+00, -4.1551195285347458e+00, -3.9025904784769208e+00, -3.6516494632523195e+00, -3.4021588258868611e+00, -3.1539897819612150e+00, -2.9070212806051177e+00, -2.6611390150638674e+00, -2.4162345566678476e+00, -2.1722045909628105e+00, -1.9289502385999013e+00, -1.6863764465968691e+00, -1.4443914379551996e+00, -1.2029062094928866e+00, -9.6183406923470449e-01, -7.2109020587034223e-01, -4.8059128370529336e-01, -2.4025505723472676e-01, -0.0000000000000000e+00, 2.4025505723472676e-01, 4.8059128370529336e-01, 7.2109020587034223e-01, 9.6183406923470449e-01, 1.2029062094928866e+00, 1.4443914379551996e+00, 1.6863764465968691e+00, 1.9289502385999013e+00, 2.1722045909628105e+00, 2.4162345566678476e+00, 2.6611390150638674e+00, 2.9070212806051177e+00, 3.1539897819612150e+00, 3.4021588258868611e+00, 3.6516494632523195e+00, 3.9025904784769208e+00, 4.1551195285347458e+00, 4.4093844640660000e+00, 4.6655448734152234e+00, 4.9237739013081612e+00, 5.1842604083343016e+00, 5.4472115568012640e+00, 5.7128559348775809e+00, 5.9814473672099631e+00, 6.2532696108544226e+00, 6.5286422072422212e+00, 6.8079278647256025e+00, 7.0915418991761436e+00, 7.3799644903419361e+00, 7.6737568668958440e+00, 7.9735830966018995e+00, 8.2802400806274559e+00, 8.5946999176295051e+00, 8.9181715786909077e+00, 9.2521940040089010e+00, 9.5987829596674032e+00, 9.9606757765591638e+00, 1.0341769018312585e+01, 1.0747978586907845e+01, 1.1189171723313381e+01, 1.1684508587714936e+01, 1.2284185353778504e+01}, {-1.2362007131968511e+01, -1.1763573078389516e+01, -1.1269299347041693e+01, -1.0829082575898250e+01, -1.0423797670745445e+01, -1.0043595347880535e+01, -9.6825704596576454e+00, -9.3368335519365662e+00, -9.0036523325638047e+00, -8.6810147998900291e+00, -8.3673849469719066e+00, -8.0615561695659022e+00, -7.7625583367306144e+00, -7.4695962264936551e+00, -7.1820072377109705e+00, -6.8992314496242599e+00, -6.6207898710143054e+00, -6.3462682846048741e+00, -6.0753050133032716e+00, -5.8075814973426141e+00, -5.5428149259789015e+00, -5.2807523972174923e+00, -5.0211662316993868e+00, -4.7638501705179523e+00, -4.5086162584922675e+00, -4.2552922649886131e+00, -4.0037195305892794e+00, -3.7537511542142386e+00, -3.5052504546692158e+00, -3.2580896550268070e+00, -3.0121487491227401e+00, -2.7673145177270055e+00, -2.5234796683078762e+00, -2.2805420772311842e+00, -2.0384041170786049e+00, -1.7969720547840342e+00, -1.5561555086656726e+00, -1.3158669543141910e+00, -1.0760212707898533e+00, -8.3653531976321294e-01, -5.9732755116498426e-01, -3.5831762963623587e-01, -1.1942607662410318e-01, 1.1942607662410318e-01, 3.5831762963623587e-01, 5.9732755116498426e-01, 8.3653531976321294e-01, 1.0760212707898533e+00, 1.3158669543141910e+00, 1.5561555086656726e+00, 1.7969720547840342e+00, 2.0384041170786049e+00, 2.2805420772311842e+00, 2.5234796683078762e+00, 2.7673145177270055e+00, 3.0121487491227401e+00, 3.2580896550268070e+00, 3.5052504546692158e+00, 3.7537511542142386e+00, 4.0037195305892794e+00, 4.2552922649886131e+00, 4.5086162584922675e+00, 4.7638501705179523e+00, 5.0211662316993868e+00, 5.2807523972174923e+00, 5.5428149259789015e+00, 5.8075814973426141e+00, 6.0753050133032716e+00, 6.3462682846048741e+00, 6.6207898710143054e+00, 6.8992314496242599e+00, 7.1820072377109705e+00, 7.4695962264936551e+00, 7.7625583367306144e+00, 8.0615561695659022e+00, 8.3673849469719066e+00, 8.6810147998900291e+00, 9.0036523325638047e+00, 9.3368335519365662e+00, 9.6825704596576454e+00, 1.0043595347880535e+01, 1.0423797670745445e+01, 1.0829082575898250e+01, 1.1269299347041693e+01, 1.1763573078389516e+01, 1.2362007131968511e+01}, {-1.2439367989923680e+01, -1.1842159173697059e+01, -1.1348933245008068e+01, -1.0909678445859965e+01, -1.0505304291834085e+01, -1.0125979221008995e+01, -9.7658086966213720e+00, -9.4209102766018642e+00, -9.0885566358796162e+00, -8.7667394811116139e+00, -8.4539256923192720e+00, -8.1489109922424241e+00, -7.8507271820680931e+00, -7.5585806862536904e+00, -7.2718103393202060e+00, -6.9898574985414994e+00, -6.7122443318572111e+00, -6.4385576912861495e+00, -6.1684369014005451e+00, -5.9015643538974087e+00, -5.6376581532613121e+00, -5.3764662879277241e+00, -5.1177619537428889e+00, -4.8613397599750519e+00, -4.6070126197625800e+00, -4.3546091773629314e+00, -4.1039716607125998e+00, -3.8549540740709145e+00, -3.6074206648573135e+00, -3.3612446132027243e+00, -3.1163069035955786e+00, -2.8724953462701670e+00, -2.6297037223368069e+00, -2.3878310315742213e+00, -2.1467808256453083e+00, -1.9064606125144659e+00, -1.6667813202271460e+00, -1.4276568101012006e+00, -1.1890034308805355e+00, -9.5073960659419110e-01, -7.1278545180861597e-01, -4.7506240870319627e-01, -2.3749290097360490e-01, -0.0000000000000000e+00, 2.3749290097360490e-01, 4.7506240870319627e-01, 7.1278545180861597e-01, 9.5073960659419110e-01, 1.1890034308805355e+00, 1.4276568101012006e+00, 1.6667813202271460e+00, 1.9064606125144659e+00, 2.1467808256453083e+00, 2.3878310315742213e+00, 2.6297037223368069e+00, 2.8724953462701670e+00, 3.1163069035955786e+00, 3.3612446132027243e+00, 3.6074206648573135e+00, 3.8549540740709145e+00, 4.1039716607125998e+00, 4.3546091773629314e+00, 4.6070126197625800e+00, 4.8613397599750519e+00, 5.1177619537428889e+00, 5.3764662879277241e+00, 5.6376581532613121e+00, 5.9015643538974087e+00, 6.1684369014005451e+00, 6.4385576912861495e+00, 6.7122443318572111e+00, 6.9898574985414994e+00, 7.2718103393202060e+00, 7.5585806862536904e+00, 7.8507271820680931e+00, 8.1489109922424241e+00, 8.4539256923192720e+00, 8.7667394811116139e+00, 9.0885566358796162e+00, 9.4209102766018642e+00, 9.7658086966213720e+00, 1.0125979221008995e+01, 1.0505304291834085e+01, 1.0909678445859965e+01, 1.1348933245008068e+01, 1.1842159173697059e+01, 1.2439367989923680e+01}, {-1.2516275975487387e+01, -1.1920275369301974e+01, -1.1428082314244874e+01, -1.0989775477860821e+01, -1.0586298540449153e+01, -1.0207837432241758e+01, -9.8485080876029141e+00, -9.5044349817531568e+00, -9.1728956871075304e+00, -8.8518855642291054e+00, -8.5398743353481130e+00, -8.2356600117533336e+00, -7.9382762925370942e+00, -7.6469312171655428e+00, -7.3609650262218116e+00, -7.0798203265112649e+00, -6.8030204171920579e+00, -6.5301531917714213e+00, -6.2608589484644162e+00, -5.9948210018972574e+00, -5.7317583424731948e+00, -5.4714198187320084e+00, -5.2135794701554339e+00, -4.9580327411502472e+00, -4.7045933784481448e+00, -4.4530908645538636e+00, -4.2033682759582804e+00, -3.9552804810525908e+00, -3.7086926119853119e+00, -3.4634787590926437e+00, -3.2195208473769141e+00, -2.9767076627641722e+00, -2.7349340022167890e+00, -2.4940999266938628e+00, -2.2541100997915855e+00, -2.0148731979134999e+00, -1.7763013802059482e+00, -1.5383098083876734e+00, -1.3008162081103343e+00, -1.0637404646882309e+00, -8.2700424699148045e-01, -5.9053065405312266e-01, -3.5424387953214642e-01, -1.1806888962751633e-01, 1.1806888962751633e-01, 3.5424387953214642e-01, 5.9053065405312266e-01, 8.2700424699148045e-01, 1.0637404646882309e+00, 1.3008162081103343e+00, 1.5383098083876734e+00, 1.7763013802059482e+00, 2.0148731979134999e+00, 2.2541100997915855e+00, 2.4940999266938628e+00, 2.7349340022167890e+00, 2.9767076627641722e+00, 3.2195208473769141e+00, 3.4634787590926437e+00, 3.7086926119853119e+00, 3.9552804810525908e+00, 4.2033682759582804e+00, 4.4530908645538636e+00, 4.7045933784481448e+00, 4.9580327411502472e+00, 5.2135794701554339e+00, 5.4714198187320084e+00, 5.7317583424731948e+00, 5.9948210018972574e+00, 6.2608589484644162e+00, 6.5301531917714213e+00, 6.8030204171920579e+00, 7.0798203265112649e+00, 7.3609650262218116e+00, 7.6469312171655428e+00, 7.9382762925370942e+00, 8.2356600117533336e+00, 8.5398743353481130e+00, 8.8518855642291054e+00, 9.1728956871075304e+00, 9.5044349817531568e+00, 9.8485080876029141e+00, 1.0207837432241758e+01, 1.0586298540449153e+01, 1.0989775477860821e+01, 1.1428082314244874e+01, 1.1920275369301974e+01, 1.2516275975487387e+01}, {-1.2592738905595901e+01, -1.1997929913449418e+01, -1.1506755189277548e+01, -1.1069382675775751e+01, -1.0666789783587026e+01, -1.0289179711107796e+01, -9.9306787276273880e+00, -9.5874181334018580e+00, -9.2566803307032135e+00, -8.9364642812455379e+00, -8.6252425061665043e+00, -8.3218152682134434e+00, -8.0252181314463780e+00, -7.7346607201821760e+00, -7.4494846527302592e+00, -7.1691337582185994e+00, -6.8931324404171299e+00, -6.6210696079053228e+00, -6.3525865059800601e+00, -6.0873673452070678e+00, -5.8251319742404801e+00, -5.5656300731513921e+00, -5.3086364953650067e+00, -5.0539474894081309e+00, -4.8013776030542550e+00, -4.5507571227604720e+00, -4.3019299373155544e+00, -4.0547517407947415e+00, -3.8090885091914664e+00, -3.5648151994628399e+00, -3.3218146305539729e+00, -3.0799765142115443e+00, -2.8391966097343762e+00, -2.5993759817212956e+00, -2.3604203437138307e+00, -2.1222394736491395e+00, -1.8847466894257894e+00, -1.6478583747824140e+00, -1.4114935472024899e+00, -1.1755734607673940e+00, -9.4002123784514680e-01, -7.0476152427011995e-01, -4.6972016327466942e-01, -2.3482388390393241e-01, -0.0000000000000000e+00, 2.3482388390393241e-01, 4.6972016327466942e-01, 7.0476152427011995e-01, 9.4002123784514680e-01, 1.1755734607673940e+00, 1.4114935472024899e+00, 1.6478583747824140e+00, 1.8847466894257894e+00, 2.1222394736491395e+00, 2.3604203437138307e+00, 2.5993759817212956e+00, 2.8391966097343762e+00, 3.0799765142115443e+00, 3.3218146305539729e+00, 3.5648151994628399e+00, 3.8090885091914664e+00, 4.0547517407947415e+00, 4.3019299373155544e+00, 4.5507571227604720e+00, 4.8013776030542550e+00, 5.0539474894081309e+00, 5.3086364953650067e+00, 5.5656300731513921e+00, 5.8251319742404801e+00, 6.0873673452070678e+00, 6.3525865059800601e+00, 6.6210696079053228e+00, 6.8931324404171299e+00, 7.1691337582185994e+00, 7.4494846527302592e+00, 7.7346607201821760e+00, 8.0252181314463780e+00, 8.3218152682134434e+00, 8.6252425061665043e+00, 8.9364642812455379e+00, 9.2566803307032135e+00, 9.5874181334018580e+00, 9.9306787276273880e+00, 1.0289179711107796e+01, 1.0666789783587026e+01, 1.1069382675775751e+01, 1.1506755189277548e+01, 1.1997929913449418e+01, 1.2592738905595901e+01}, {-1.2668764375434174e+01, -1.2075130816910921e+01, -1.1584960252804917e+01, -1.1148508777693781e+01, -1.0746787108514194e+01, -1.0370015493271170e+01, -1.0012330403392184e+01, -9.6698698743374543e+00, -9.3399210724883908e+00, -9.0204865095226339e+00, -8.7100414635651475e+00, -8.4073884130034546e+00, -8.1115647551404777e+00, -7.8217816701739293e+00, -7.5373821269924042e+00, -7.2578111510465870e+00, -6.9825942253568725e+00, -6.7113212484546603e+00, -6.4436343875167896e+00, -6.1792187234934586e+00, -5.9177949371442047e+00, -5.6591135131207473e+00, -5.4029500908349490e+00, -5.1491016937770269e+00, -4.8973836402140369e+00, -4.6476269884213890e+00, -4.3996764055654278e+00, -4.1533883754886318e+00, -3.9086296798928606e+00, -3.6652761017603779e+00, -3.4232113106647768e+00, -3.1823258978578806e+00, -2.9425165353484215e+00, -2.7036852380958849e+00, -2.4657387122776617e+00, -2.2285877756048471e+00, -1.9921468380503871e+00, -1.7563334332534348e+00, -1.5210677923813427e+00, -1.2862724534455954e+00, -1.0518719000409926e+00, -8.1779222425489551e-01, -5.8396080911088377e-01, -3.5030602639582364e-01, -1.1675694609164179e-01, 1.1675694609164179e-01, 3.5030602639582364e-01, 5.8396080911088377e-01, 8.1779222425489551e-01, 1.0518719000409926e+00, 1.2862724534455954e+00, 1.5210677923813427e+00, 1.7563334332534348e+00, 1.9921468380503871e+00, 2.2285877756048471e+00, 2.4657387122776617e+00, 2.7036852380958849e+00, 2.9425165353484215e+00, 3.1823258978578806e+00, 3.4232113106647768e+00, 3.6652761017603779e+00, 3.9086296798928606e+00, 4.1533883754886318e+00, 4.3996764055654278e+00, 4.6476269884213890e+00, 4.8973836402140369e+00, 5.1491016937770269e+00, 5.4029500908349490e+00, 5.6591135131207473e+00, 5.9177949371442047e+00, 6.1792187234934586e+00, 6.4436343875167896e+00, 6.7113212484546603e+00, 6.9825942253568725e+00, 7.2578111510465870e+00, 7.5373821269924042e+00, 7.8217816701739293e+00, 8.1115647551404777e+00, 8.4073884130034546e+00, 8.7100414635651475e+00, 9.0204865095226339e+00, 9.3399210724883908e+00, 9.6698698743374543e+00, 1.0012330403392184e+01, 1.0370015493271170e+01, 1.0746787108514194e+01, 1.1148508777693781e+01, 1.1584960252804917e+01, 1.2075130816910921e+01, 1.2668764375434174e+01}, {-1.2744359767130547e+01, -1.2151885862422731e+01, -1.1662705645828531e+01, -1.1227162266730099e+01, -1.0826299334271541e+01, -1.0450353932747101e+01, -1.0093472606221523e+01, -9.7518000378530658e+00, -9.4226280941850682e+00, -9.1039627871662461e+00, -8.7942821113015697e+00, -8.4923907260054339e+00, -8.1973278312442819e+00, -7.9083061352456419e+00, -7.6246699314466770e+00, -7.3458654167536865e+00, -7.0714191292405717e+00, -6.8009219334794446e+00, -6.5340168945910211e+00, -6.2703899396887248e+00, -6.0097625569049269e+00, -5.7518860100246414e+00, -5.4965366980951300e+00, -5.2435123921335229e+00, -4.9926291522002995e+00, -4.7437187782456505e+00, -4.4966266840419751e+00, -4.2512101096067996e+00, -4.0073366067337117e+00, -3.7648827465709873e+00, -3.5237330089839838e+00, -3.2837788216598618e+00, -3.0449177232349895e+00, -2.8070526296277643e+00, -2.5700911865913141e+00, -2.3339451945166196e+00, -2.0985300939053997e+00, -1.8637645018342535e+00, -1.6295697912525116e+00, -1.3958697061759588e+00, -1.1625900068179993e+00, -9.2965813948535503e-01, -6.9700292669283159e-01, -4.6455427344836053e-01, -2.3224288604634152e-01, -0.0000000000000000e+00, 2.3224288604634152e-01, 4.6455427344836053e-01, 6.9700292669283159e-01, 9.2965813948535503e-01, 1.1625900068179993e+00, 1.3958697061759588e+00, 1.6295697912525116e+00, 1.8637645018342535e+00, 2.0985300939053997e+00, 2.3339451945166196e+00, 2.5700911865913141e+00, 2.8070526296277643e+00, 3.0449177232349895e+00, 3.2837788216598618e+00, 3.5237330089839838e+00, 3.7648827465709873e+00, 4.0073366067337117e+00, 4.2512101096067996e+00, 4.4966266840419751e+00, 4.7437187782456505e+00, 4.9926291522002995e+00, 5.2435123921335229e+00, 5.4965366980951300e+00, 5.7518860100246414e+00, 6.0097625569049269e+00, 6.2703899396887248e+00, 6.5340168945910211e+00, 6.8009219334794446e+00, 7.0714191292405717e+00, 7.3458654167536865e+00, 7.6246699314466770e+00, 7.9083061352456419e+00, 8.1973278312442819e+00, 8.4923907260054339e+00, 8.7942821113015697e+00, 9.1039627871662461e+00, 9.4226280941850682e+00, 9.7518000378530658e+00, 1.0093472606221523e+01, 1.0450353932747101e+01, 1.0826299334271541e+01, 1.1227162266730099e+01, 1.1662705645828531e+01, 1.2151885862422731e+01, 1.2744359767130547e+01}, {-1.2819532258018480e+01, -1.2228202613648115e+01, -1.1739999277265277e+01, -1.1305351381280618e+01, -1.0905335022579179e+01, -1.0530203913474873e+01, -1.0174114544331893e+01, -9.8332181607332707e+00, -9.5048112671603402e+00, -9.1869033275673413e+00, -8.8779750134809063e+00, -8.5768331318717053e+00, -8.2825186558731350e+00, -7.9942457949462566e+00, -7.7113601420959172e+00, -7.4333090418794825e+00, -7.1596200643171857e+00, -6.8898850172400419e+00, -6.6237478409567272e+00, -6.3608952857640544e+00, -6.1010496237476017e+00, -5.8439628737731484e+00, -5.5894121696594157e+00, -5.3371960041051256e+00, -5.0871311519710600e+00, -4.8390501265746098e+00, -4.5927990585018197e+00, -4.3482359124910070e+00, -4.1052289771248800e+00, -3.8636555763680760e+00, -3.6234009627673571e+00, -3.3843573603426855e+00, -3.1464231315109763e+00, -2.9095020472812747e+00, -2.6735026437884462e+00, -2.4383376512469250e+00, -2.2039234837948438e+00, -1.9701797806022634e+00, -1.7370289901408089e+00, -1.5043959907356530e+00, -1.2722077415053921e+00, -1.0403929585875988e+00, -8.0888181218354049e-01, -5.7760564046232032e-01, -3.4649667676368101e-01, -1.1548778684603313e-01, 1.1548778684603313e-01, 3.4649667676368101e-01, 5.7760564046232032e-01, 8.0888181218354049e-01, 1.0403929585875988e+00, 1.2722077415053921e+00, 1.5043959907356530e+00, 1.7370289901408089e+00, 1.9701797806022634e+00, 2.2039234837948438e+00, 2.4383376512469250e+00, 2.6735026437884462e+00, 2.9095020472812747e+00, 3.1464231315109763e+00, 3.3843573603426855e+00, 3.6234009627673571e+00, 3.8636555763680760e+00, 4.1052289771248800e+00, 4.3482359124910070e+00, 4.5927990585018197e+00, 4.8390501265746098e+00, 5.0871311519710600e+00, 5.3371960041051256e+00, 5.5894121696594157e+00, 5.8439628737731484e+00, 6.1010496237476017e+00, 6.3608952857640544e+00, 6.6237478409567272e+00, 6.8898850172400419e+00, 7.1596200643171857e+00, 7.4333090418794825e+00, 7.7113601420959172e+00, 7.9942457949462566e+00, 8.2825186558731350e+00, 8.5768331318717053e+00, 8.8779750134809063e+00, 9.1869033275673413e+00, 9.5048112671603402e+00, 9.8332181607332707e+00, 1.0174114544331893e+01, 1.0530203913474873e+01, 1.0905335022579179e+01, 1.1305351381280618e+01, 1.1739999277265277e+01, 1.2228202613648115e+01, 1.2819532258018480e+01}, {-1.2894288828491323e+01, -1.2304088423692580e+01, -1.1816848833075053e+01, -1.1383084124753704e+01, -1.0983902488179488e+01, -1.0609574060288383e+01, -1.0254265154452550e+01, -9.9141334955519440e+00, -9.5864801654334606e+00, -9.2693180331543115e+00, -8.9611304090936645e+00, -8.6607262153924776e+00, -8.3671481698791865e+00, -8.0796119574473497e+00, -7.7974644466766474e+00, -7.5201541069686444e+00, -7.2472095182038041e+00, -6.9782234097463292e+00, -6.7128405754384817e+00, -6.4507485669373850e+00, -6.1916704180836000e+00, -5.9353588800666905e+00, -5.6815917979923949e+00, -5.4301683618693133e+00, -5.1809060359441155e+00, -4.9336380202893313e+00, -4.6882111343374202e+00, -4.4444840380621056e+00, -4.2023257256606739e+00, -3.9616142408689083e+00, -3.7222355738045620e+00, -3.4840827074346534e+00, -3.2470547880671274e+00, -3.0110563991586603e+00, -2.7759969215550591e+00, -2.5417899662931847e+00, -2.3083528684815695e+00, -2.0756062326810416e+00, -1.8434735217321803e+00, -1.6118806822031735e+00, -1.3807558006205385e+00, -1.1500287854429532e+00, -9.1963107038107428e-01, -6.8949533518145145e-01, -4.5955524040186729e-01, -2.2974517302503578e-01, -0.0000000000000000e+00, 2.2974517302503578e-01, 4.5955524040186729e-01, 6.8949533518145145e-01, 9.1963107038107428e-01, 1.1500287854429532e+00, 1.3807558006205385e+00, 1.6118806822031735e+00, 1.8434735217321803e+00, 2.0756062326810416e+00, 2.3083528684815695e+00, 2.5417899662931847e+00, 2.7759969215550591e+00, 3.0110563991586603e+00, 3.2470547880671274e+00, 3.4840827074346534e+00, 3.7222355738045620e+00, 3.9616142408689083e+00, 4.2023257256606739e+00, 4.4444840380621056e+00, 4.6882111343374202e+00, 4.9336380202893313e+00, 5.1809060359441155e+00, 5.4301683618693133e+00, 5.6815917979923949e+00, 5.9353588800666905e+00, 6.1916704180836000e+00, 6.4507485669373850e+00, 6.7128405754384817e+00, 6.9782234097463292e+00, 7.2472095182038041e+00, 7.5201541069686444e+00, 7.7974644466766474e+00, 8.0796119574473497e+00, 8.3671481698791865e+00, 8.6607262153924776e+00, 8.9611304090936645e+00, 9.2693180331543115e+00, 9.5864801654334606e+00, 9.9141334955519440e+00, 1.0254265154452550e+01, 1.0609574060288383e+01, 1.0983902488179488e+01, 1.1383084124753704e+01, 1.1816848833075053e+01, 1.2304088423692580e+01, 1.2894288828491323e+01}, {-1.2968636269474320e+01, -1.2379550443198964e+01, -1.1893261784933093e+01, -1.1460368274811241e+01, -1.1062009808653285e+01, -1.0688472749322155e+01, -1.0333933112841928e+01, -9.9945550223243256e+00, -9.6676440779928683e+00, -9.3512165084081822e+00, -9.0437582257661120e+00, -8.7440802360223131e+00, -8.4512269741988870e+00, -8.1644155757609358e+00, -7.8829941618009407e+00, -7.6064123046955778e+00, -7.3341995730571172e+00, -7.0659495970458304e+00, -6.8013080034124762e+00, -6.5399631244304128e+00, -6.2816387346344911e+00, -6.0260882959858302e+00, -5.7730903426736297e+00, -5.5224447390110498e+00, -5.2739696146779718e+00, -5.0274988314577831e+00, -4.7828798713474461e+00, -4.5399720618862149e+00, -4.2986450736710040e+00, -4.0587776392825550e+00, -3.8202564535947250e+00, -3.5829752236268817e+00, -3.3468338423962911e+00, -3.1117376661126466e+00, -2.8775968778776946e+00, -2.6443259240630739e+00, -2.4118430119268002e+00, -2.1800696589332400e+00, -1.9489302857683151e+00, -1.7183518462708216e+00, -1.4882634884931585e+00, -1.2585962419071162e+00, -1.0292827264188049e+00, -8.0025687937913981e-01, -5.7145369719413508e-01, -3.4280898846921665e-01, -1.1425913587653955e-01, 1.1425913587653955e-01, 3.4280898846921665e-01, 5.7145369719413508e-01, 8.0025687937913981e-01, 1.0292827264188049e+00, 1.2585962419071162e+00, 1.4882634884931585e+00, 1.7183518462708216e+00, 1.9489302857683151e+00, 2.1800696589332400e+00, 2.4118430119268002e+00, 2.6443259240630739e+00, 2.8775968778776946e+00, 3.1117376661126466e+00, 3.3468338423962911e+00, 3.5829752236268817e+00, 3.8202564535947250e+00, 4.0587776392825550e+00, 4.2986450736710040e+00, 4.5399720618862149e+00, 4.7828798713474461e+00, 5.0274988314577831e+00, 5.2739696146779718e+00, 5.5224447390110498e+00, 5.7730903426736297e+00, 6.0260882959858302e+00, 6.2816387346344911e+00, 6.5399631244304128e+00, 6.8013080034124762e+00, 7.0659495970458304e+00, 7.3341995730571172e+00, 7.6064123046955778e+00, 7.8829941618009407e+00, 8.1644155757609358e+00, 8.4512269741988870e+00, 8.7440802360223131e+00, 9.0437582257661120e+00, 9.3512165084081822e+00, 9.6676440779928683e+00, 9.9945550223243256e+00, 1.0333933112841928e+01, 1.0688472749322155e+01, 1.1062009808653285e+01, 1.1460368274811241e+01, 1.1893261784933093e+01, 1.2379550443198964e+01, 1.2968636269474320e+01}, {-1.3042581189536424e+01, -1.2454595628047418e+01, -1.1969245398474266e+01, -1.1537211392148828e+01, -1.1139664833741461e+01, -1.0766908117887827e+01, -1.0413126845737839e+01, -1.0074491459554146e+01, -9.7483120204672815e+00, -9.4326080721882803e+00, -9.1258680927746667e+00, -8.8269051416209461e+00, -8.5347653443616345e+00, -8.2486672630612325e+00, -7.9679602491408312e+00, -7.6920949569654464e+00, -7.4206019236498832e+00, -7.1530756603397334e+00, -6.8891626070319019e+00, -6.6285518568795139e+00, -6.3709679051115460e+00, -6.1161649040299730e+00, -5.8639220558946130e+00, -5.6140398775862348e+00, -5.3663371416203249e+00, -5.1206483478982010e+00, -4.8768216162575175e+00, -4.6347169158093715e+00, -4.3942045661421210e+00, -4.1551639597063925e+00, -3.9174824654279452e+00, -3.6810544817710307e+00, -3.4457806137632216e+00, -3.2115669533719382e+00, -2.9783244464395575e+00, -2.7459683323916124e+00, -2.5144176453186349e+00, -2.2835947669364720e+00, -2.0534250234577174e+00, -1.8238363196378788e+00, -1.5947588042551295e+00, -1.3661245620886429e+00, -1.1378673281137517e+00, -9.0992222016050861e-01, -6.8222548670729899e-01, -4.5471426681985894e-01, -2.2732635951125563e-01, -0.0000000000000000e+00, 2.2732635951125563e-01, 4.5471426681985894e-01, 6.8222548670729899e-01, 9.0992222016050861e-01, 1.1378673281137517e+00, 1.3661245620886429e+00, 1.5947588042551295e+00, 1.8238363196378788e+00, 2.0534250234577174e+00, 2.2835947669364720e+00, 2.5144176453186349e+00, 2.7459683323916124e+00, 2.9783244464395575e+00, 3.2115669533719382e+00, 3.4457806137632216e+00, 3.6810544817710307e+00, 3.9174824654279452e+00, 4.1551639597063925e+00, 4.3942045661421210e+00, 4.6347169158093715e+00, 4.8768216162575175e+00, 5.1206483478982010e+00, 5.3663371416203249e+00, 5.6140398775862348e+00, 5.8639220558946130e+00, 6.1161649040299730e+00, 6.3709679051115460e+00, 6.6285518568795139e+00, 6.8891626070319019e+00, 7.1530756603397334e+00, 7.4206019236498832e+00, 7.6920949569654464e+00, 7.9679602491408312e+00, 8.2486672630612325e+00, 8.5347653443616345e+00, 8.8269051416209461e+00, 9.1258680927746667e+00, 9.4326080721882803e+00, 9.7483120204672815e+00, 1.0074491459554146e+01, 1.0413126845737839e+01, 1.0766908117887827e+01, 1.1139664833741461e+01, 1.1537211392148828e+01, 1.1969245398474266e+01, 1.2454595628047418e+01, 1.3042581189536424e+01}, {-1.3116130021662876e+01, -1.2529230746683540e+01, -1.2044806741134924e+01, -1.1613620828842913e+01, -1.1216875194202160e+01, -1.0844888073853586e+01, -1.0491854539276538e+01, -1.0153951274713688e+01, -9.8284927461917118e+00, -9.5135017694124251e+00, -9.2074693533717600e+00, -8.9092105814595968e+00, -8.6177732442147459e+00, -8.3323773071700593e+00, -8.0523733307197105e+00, -7.7772130310612386e+00, -7.5064278944277563e+00, -7.2396132940083531e+00, -6.9764164642851814e+00, -6.7165272404965179e+00, -6.4596708195551207e+00, -6.2056020247183090e+00, -5.9541007064117260e+00, -5.7049680135255354e+00, -5.4580233400707856e+00, -5.2131018018189597e+00, -4.9700521331667717e+00, -4.7287349203529301e+00, -4.4890211062169945e+00, -4.2507907159031859e+00, -4.0139317636282685e+00, -3.7783393087968626e+00, -3.5439146360273117e+00, -3.3105645385243054e+00, -3.0782006880468189e+00, -2.8467390777247825e+00, -2.6160995263623885e+00, -2.3862052347697795e+00, -2.1569823861931283e+00, -1.9283597841455022e+00, -1.7002685219383502e+00, -1.4726416790227095e+00, -1.2454140399065079e+00, -1.0185218319476799e+00, -7.9190247875401665e-01, -5.6549436626674887e-01, -3.3923661887888523e-01, -1.1306888315145193e-01, 1.1306888315145193e-01, 3.3923661887888523e-01, 5.6549436626674887e-01, 7.9190247875401665e-01, 1.0185218319476799e+00, 1.2454140399065079e+00, 1.4726416790227095e+00, 1.7002685219383502e+00, 1.9283597841455022e+00, 2.1569823861931283e+00, 2.3862052347697795e+00, 2.6160995263623885e+00, 2.8467390777247825e+00, 3.0782006880468189e+00, 3.3105645385243054e+00, 3.5439146360273117e+00, 3.7783393087968626e+00, 4.0139317636282685e+00, 4.2507907159031859e+00, 4.4890211062169945e+00, 4.7287349203529301e+00, 4.9700521331667717e+00, 5.2131018018189597e+00, 5.4580233400707856e+00, 5.7049680135255354e+00, 5.9541007064117260e+00, 6.2056020247183090e+00, 6.4596708195551207e+00, 6.7165272404965179e+00, 6.9764164642851814e+00, 7.2396132940083531e+00, 7.5064278944277563e+00, 7.7772130310612386e+00, 8.0523733307197105e+00, 8.3323773071700593e+00, 8.6177732442147459e+00, 8.9092105814595968e+00, 9.2074693533717600e+00, 9.5135017694124251e+00, 9.8284927461917118e+00, 1.0153951274713688e+01, 1.0491854539276538e+01, 1.0844888073853586e+01, 1.1216875194202160e+01, 1.1613620828842913e+01, 1.2044806741134924e+01, 1.2529230746683540e+01, 1.3116130021662876e+01}, {-1.3189289029708117e+01, -1.2603462387096409e+01, -1.2119952689615966e+01, -1.1689603736290559e+01, -1.1293648310231410e+01, -1.0922420304556775e+01, -1.0570124148913189e+01, -1.0232942694191875e+01, -9.9081947567061555e+00, -9.5939063821323529e+00, -9.2885710764670684e+00, -8.9910059185401376e+00, -8.7002603389157791e+00, -8.4155556842608696e+00, -8.1362437033700719e+00, -7.8617771549009925e+00, -7.5916884556157704e+00, -7.3255738226210259e+00, -7.0630812669681537e+00, -6.8039013480672903e+00, -6.5477599464293741e+00, -6.2944125378566032e+00, -6.0436396020679171e+00, -5.7952429005012469e+00, -5.5490424284915560e+00, -5.3048738966808706e+00, -5.0625866320797561e+00, -4.8220418150442850e+00, -4.5831109874666334e+00, -4.3456747816687633e+00, -4.1096218301890062e+00, -3.8748478248038931e+00, -3.6412546993987251e+00, -3.4087499161671784e+00, -3.1772458384281856e+00, -2.9466591763501873e+00, -2.7169104942556110e+00, -2.4879237700815029e+00, -2.2596259991006340e+00, -2.0319468352407690e+00, -1.8048182643389761e+00, -1.5781743044796297e+00, -1.3519507292254074e+00, -1.1260848100881036e+00, -9.0051507502248329e-01, -6.7518108007869271e-01, -4.5002319163025301e-01, -2.2498237681566594e-01, -0.0000000000000000e+00, 2.2498237681566594e-01, 4.5002319163025301e-01, 6.7518108007869271e-01, 9.0051507502248329e-01, 1.1260848100881036e+00, 1.3519507292254074e+00, 1.5781743044796297e+00, 1.8048182643389761e+00, 2.0319468352407690e+00, 2.2596259991006340e+00, 2.4879237700815029e+00, 2.7169104942556110e+00, 2.9466591763501873e+00, 3.1772458384281856e+00, 3.4087499161671784e+00, 3.6412546993987251e+00, 3.8748478248038931e+00, 4.1096218301890062e+00, 4.3456747816687633e+00, 4.5831109874666334e+00, 4.8220418150442850e+00, 5.0625866320797561e+00, 5.3048738966808706e+00, 5.5490424284915560e+00, 5.7952429005012469e+00, 6.0436396020679171e+00, 6.2944125378566032e+00, 6.5477599464293741e+00, 6.8039013480672903e+00, 7.0630812669681537e+00, 7.3255738226210259e+00, 7.5916884556157704e+00, 7.8617771549009925e+00, 8.1362437033700719e+00, 8.4155556842608696e+00, 8.7002603389157791e+00, 8.9910059185401376e+00, 9.2885710764670684e+00, 9.5939063821323529e+00, 9.9081947567061555e+00, 1.0232942694191875e+01, 1.0570124148913189e+01, 1.0922420304556775e+01, 1.1293648310231410e+01, 1.1689603736290559e+01, 1.2119952689615966e+01, 1.2603462387096409e+01, 1.3189289029708117e+01}, {-1.3262064314547260e+01, -1.2677296963466635e+01, -1.2194689936989255e+01, -1.1765167072765909e+01, -1.1369991399473138e+01, -1.0999512285277628e+01, -1.0647943408373985e+01, -1.0311473712742933e+01, -9.9874263117220838e+00, -9.6738304400421331e+00, -9.3691820677047506e+00, -9.0723002412708205e+00, -8.7822360072393444e+00, -8.4982120718321887e+00, -8.2195813524123764e+00, -7.9457976314642735e+00, -7.6763942384382915e+00, -7.4109682169993913e+00, -7.1491683376448565e+00, -6.8906858668688686e+00, -6.6352473515597925e+00, -6.3826089025647779e+00, -6.1325516109861775e+00, -5.8848778323693072e+00, -5.6394081442881152e+00, -5.3959788324149320e+00, -5.1544397956688064e+00, -4.9146527868415708e+00, -4.6764899241060425e+00, -4.4398324229806452e+00, -4.2045695090093798e+00, -3.9705974795569130e+00, -3.7378188893809927e+00, -3.5061418395049322e+00, -3.2754793527162449e+00, -3.0457488220163000e+00, -2.8168715207266257e+00, -2.5887721648595683e+00, -2.3613785198892869e+00, -2.1346210452930161e+00, -1.9084325712330619e+00, -1.6827480025638228e+00, -1.4575040460115227e+00, -1.2326389569154106e+00, -1.0080923023599291e+00, -7.8380473788493388e-01, -5.5971779524889242e-01, -3.3577367894853466e-01, -1.1191506937570589e-01, 1.1191506937570589e-01, 3.3577367894853466e-01, 5.5971779524889242e-01, 7.8380473788493388e-01, 1.0080923023599291e+00, 1.2326389569154106e+00, 1.4575040460115227e+00, 1.6827480025638228e+00, 1.9084325712330619e+00, 2.1346210452930161e+00, 2.3613785198892869e+00, 2.5887721648595683e+00, 2.8168715207266257e+00, 3.0457488220163000e+00, 3.2754793527162449e+00, 3.5061418395049322e+00, 3.7378188893809927e+00, 3.9705974795569130e+00, 4.2045695090093798e+00, 4.4398324229806452e+00, 4.6764899241060425e+00, 4.9146527868415708e+00, 5.1544397956688064e+00, 5.3959788324149320e+00, 5.6394081442881152e+00, 5.8848778323693072e+00, 6.1325516109861775e+00, 6.3826089025647779e+00, 6.6352473515597925e+00, 6.8906858668688686e+00, 7.1491683376448565e+00, 7.4109682169993913e+00, 7.6763942384382915e+00, 7.9457976314642735e+00, 8.2195813524123764e+00, 8.4982120718321887e+00, 8.7822360072393444e+00, 9.0723002412708205e+00, 9.3691820677047506e+00, 9.6738304400421331e+00, 9.9874263117220838e+00, 1.0311473712742933e+01, 1.0647943408373985e+01, 1.0999512285277628e+01, 1.1369991399473138e+01, 1.1765167072765909e+01, 1.2194689936989255e+01, 1.2677296963466635e+01, 1.3262064314547260e+01}, {-1.3334461819943153e+01, -1.2750740722503373e+01, -1.2269024999467902e+01, -1.1840317610615624e+01, -1.1445911484642805e+01, -1.1076171287300262e+01, -1.0725319838167971e+01, -1.0389552102465858e+01, -1.0066195438589224e+01, -9.7532822304545537e+00, -9.4493108799743251e+00, -9.1531023745391185e+00, -8.8637093532419815e+00, -8.5803558609974342e+00, -8.3023959646056102e+00, -8.0292844524423987e+00, -7.7605555495112331e+00, -7.4958071093975249e+00, -7.2346886456654547e+00, -6.9768921155793651e+00, -6.7221447159938794e+00, -6.4702031761523404e+00, -6.2208491815292408e+00, -5.9738856642890008e+00, -5.7291337661713966e+00, -5.4864303291169465e+00, -5.2456258043992712e+00, -5.0065824967968044e+00, -4.7691730793126910e+00, -4.5332793281004458e+00, -4.2987910379219327e+00, -4.0656050865933535e+00, -3.8336246231287601e+00, -3.6027583591447181e+00, -3.3729199468884627e+00, -3.1440274302474247e+00, -2.9160027574766345e+00, -2.6887713462813925e+00, -2.4622616934204693e+00, -2.2364050222293588e+00, -2.0111349624646375e+00, -1.7863872576859270e+00, -1.5620994960576213e+00, -1.3382108609965631e+00, -1.1146618985362737e+00, -8.9139429864040043e-01, -6.6835068799126329e-01, -4.4547443201433412e-01, -2.2270944408436802e-01, -0.0000000000000000e+00, 2.2270944408436802e-01, 4.4547443201433412e-01, 6.6835068799126329e-01, 8.9139429864040043e-01, 1.1146618985362737e+00, 1.3382108609965631e+00, 1.5620994960576213e+00, 1.7863872576859270e+00, 2.0111349624646375e+00, 2.2364050222293588e+00, 2.4622616934204693e+00, 2.6887713462813925e+00, 2.9160027574766345e+00, 3.1440274302474247e+00, 3.3729199468884627e+00, 3.6027583591447181e+00, 3.8336246231287601e+00, 4.0656050865933535e+00, 4.2987910379219327e+00, 4.5332793281004458e+00, 4.7691730793126910e+00, 5.0065824967968044e+00, 5.2456258043992712e+00, 5.4864303291169465e+00, 5.7291337661713966e+00, 5.9738856642890008e+00, 6.2208491815292408e+00, 6.4702031761523404e+00, 6.7221447159938794e+00, 6.9768921155793651e+00, 7.2346886456654547e+00, 7.4958071093975249e+00, 7.7605555495112331e+00, 8.0292844524423987e+00, 8.3023959646056102e+00, 8.5803558609974342e+00, 8.8637093532419815e+00, 9.1531023745391185e+00, 9.4493108799743251e+00, 9.7532822304545537e+00, 1.0066195438589224e+01, 1.0389552102465858e+01, 1.0725319838167971e+01, 1.1076171287300262e+01, 1.1445911484642805e+01, 1.1840317610615624e+01, 1.2269024999467902e+01, 1.2750740722503373e+01, 1.3334461819943153e+01}, {-1.3406487338144908e+01, -1.2823799749487808e+01, -1.2342964222859672e+01, -1.1915061943114164e+01, -1.1521415400787030e+01, -1.1152404385585125e+01, -1.0802260753684713e+01, -1.0467185421342810e+01, -1.0144509941292846e+01, -9.8322698077779673e+00, -9.5289658233901147e+00, -9.2334208902191612e+00, -8.9446892173254735e+00, -8.6619961681345181e+00, -8.3846969404162657e+00, -8.1122473111627915e+00, -7.8441823844608196e+00, -7.5801008078574874e+00, -7.3196528223045343e+00, -7.0625310602488653e+00, -6.8084633528587952e+00, -6.5572070319215392e+00, -6.3085443611121343e+00, -6.0622788326143020e+00, -5.8182321352035169e+00, -5.5762416493299236e+00, -5.3361583601383602e+00, -5.0978451050891360e+00, -4.8611750917912095e+00, -4.6260306357871555e+00, -4.3923020786826834e+00, -4.1598868551310302e+00, -3.9286886834276706e+00, -3.6986168593184914e+00, -3.4695856364185889e+00, -3.2415136796310131e+00, -3.0143235803311552e+00, -2.7879414239819891e+00, -2.5622964023726080e+00, -2.3373204639068783e+00, -2.1129479963711879e+00, -1.8891155374270083e+00, -1.6657615087415094e+00, -1.4428259702159327e+00, -1.2202503912189531e+00, -9.9797743609810530e-01, -7.7595076154014564e-01, -5.5411482359161690e-01, -3.3241469234223181e-01, -1.1079587242243949e-01, 1.1079587242243949e-01, 3.3241469234223181e-01, 5.5411482359161690e-01, 7.7595076154014564e-01, 9.9797743609810530e-01, 1.2202503912189531e+00, 1.4428259702159327e+00, 1.6657615087415094e+00, 1.8891155374270083e+00, 2.1129479963711879e+00, 2.3373204639068783e+00, 2.5622964023726080e+00, 2.7879414239819891e+00, 3.0143235803311552e+00, 3.2415136796310131e+00, 3.4695856364185889e+00, 3.6986168593184914e+00, 3.9286886834276706e+00, 4.1598868551310302e+00, 4.3923020786826834e+00, 4.6260306357871555e+00, 4.8611750917912095e+00, 5.0978451050891360e+00, 5.3361583601383602e+00, 5.5762416493299236e+00, 5.8182321352035169e+00, 6.0622788326143020e+00, 6.3085443611121343e+00, 6.5572070319215392e+00, 6.8084633528587952e+00, 7.0625310602488653e+00, 7.3196528223045343e+00, 7.5801008078574874e+00, 7.8441823844608196e+00, 8.1122473111627915e+00, 8.3846969404162657e+00, 8.6619961681345181e+00, 8.9446892173254735e+00, 9.2334208902191612e+00, 9.5289658233901147e+00, 9.8322698077779673e+00, 1.0144509941292846e+01, 1.0467185421342810e+01, 1.0802260753684713e+01, 1.1152404385585125e+01, 1.1521415400787030e+01, 1.1915061943114164e+01, 1.2342964222859672e+01, 1.2823799749487808e+01, 1.3406487338144908e+01}, {-1.3478146515232797e+01, -1.2896479974039561e+01, -1.2416513788721415e+01, -1.1989406490998284e+01, -1.1596509802200323e+01, -1.1228218466075560e+01, -1.0878773272902121e+01, -1.0544381021362536e+01, -1.0222377409009630e+01, -9.9108010025237636e+00, -9.6081549747716188e+00, -9.3132641171485986e+00, -9.0251841867360021e+00, -8.7431418459354120e+00, -8.4664934056489916e+00, -8.1946956148339627e+00, -7.9272844408189824e+00, -7.6638593097942502e+00, -7.4040711750779735e+00, -7.1476133293942068e+00, -6.8942142232839023e+00, -6.6436317759717189e+00, -6.3956488139470400e+00, -6.1500693736430252e+00, -5.9067156746204947e+00, -5.6654256190158065e+00, -5.4260507083580034e+00, -5.1884542945483902e+00, -4.9525101007153634e+00, -4.7181009617643239e+00, -4.4851177450803661e+00, -4.2534584199474237e+00, -4.0230272504840583e+00, -3.7937340917372753e+00, -3.5654937723650511e+00, -3.3382255503269591e+00, -3.1118526303762444e+00, -2.8863017340447339e+00, -2.6615027143383925e+00, -2.4373882085955381e+00, -2.2138933239623526e+00, -1.9909553507579980e+00, -1.7685134996706828e+00, -1.5465086592745161e+00, -1.3248831708071216e+00, -1.1035806175170297e+00, -8.8254562619156474e-01, -6.6172367872096116e-01, -4.4106093175132588e-01, -2.2050404263430215e-01, -0.0000000000000000e+00, 2.2050404263430215e-01, 4.4106093175132588e-01, 6.6172367872096116e-01, 8.8254562619156474e-01, 1.1035806175170297e+00, 1.3248831708071216e+00, 1.5465086592745161e+00, 1.7685134996706828e+00, 1.9909553507579980e+00, 2.2138933239623526e+00, 2.4373882085955381e+00, 2.6615027143383925e+00, 2.8863017340447339e+00, 3.1118526303762444e+00, 3.3382255503269591e+00, 3.5654937723650511e+00, 3.7937340917372753e+00, 4.0230272504840583e+00, 4.2534584199474237e+00, 4.4851177450803661e+00, 4.7181009617643239e+00, 4.9525101007153634e+00, 5.1884542945483902e+00, 5.4260507083580034e+00, 5.6654256190158065e+00, 5.9067156746204947e+00, 6.1500693736430252e+00, 6.3956488139470400e+00, 6.6436317759717189e+00, 6.8942142232839023e+00, 7.1476133293942068e+00, 7.4040711750779735e+00, 7.6638593097942502e+00, 7.9272844408189824e+00, 8.1946956148339627e+00, 8.4664934056489916e+00, 8.7431418459354120e+00, 9.0251841867360021e+00, 9.3132641171485986e+00, 9.6081549747716188e+00, 9.9108010025237636e+00, 1.0222377409009630e+01, 1.0544381021362536e+01, 1.0878773272902121e+01, 1.1228218466075560e+01, 1.1596509802200323e+01, 1.1989406490998284e+01, 1.2416513788721415e+01, 1.2896479974039561e+01, 1.3478146515232797e+01}, {-1.3549444856223355e+01, -1.2968787175621387e+01, -1.2489679720231214e+01, -1.2063357508698903e+01, -1.1671201169018351e+01, -1.1303620232659483e+01, -1.0954864323727046e+01, -1.0621146056253156e+01, -1.0299805224248269e+01, -9.9888834298724642e+00, -9.6868861866549612e+00, -9.3926401506071997e+00, -9.1052026055338082e+00, -8.8238014938930043e+00, -8.5477942224789647e+00, -8.2766384961541863e+00, -8.0098711302417200e+00, -7.7470923148599020e+00, -7.4879537012921364e+00, -7.2321492282755919e+00, -6.9794079514507139e+00, -6.7294883630724422e+00, -6.4821738377935736e+00, -6.2372689413028590e+00, -5.9945964085177108e+00, -5.7539946473095069e+00, -5.5153156590327264e+00, -5.2784232927787453e+00, -5.0431917691668700e+00, -4.8095044235715418e+00, -4.5772526293071110e+00, -4.3463348693861139e+00, -4.1166559316947993e+00, -3.8881262072644476e+00, -3.6606610751014688e+00, -3.4341803600244734e+00, -3.2086078523280142e+00, -2.9838708799890519e+00, -2.7598999256576846e+00, -2.5366282819075883e+00, -2.3139917392243752e+00, -2.0919283020285095e+00, -1.8703779286996216e+00, -1.6492822921192409e+00, -1.4285845577012724e+00, -1.2082291762513240e+00, -9.8816168930097070e-01, -7.6832854481204382e-01, -5.4867692134760149e-01, -3.2915455896704260e-01, -1.0970959522807897e-01, 1.0970959522807897e-01, 3.2915455896704260e-01, 5.4867692134760149e-01, 7.6832854481204382e-01, 9.8816168930097070e-01, 1.2082291762513240e+00, 1.4285845577012724e+00, 1.6492822921192409e+00, 1.8703779286996216e+00, 2.0919283020285095e+00, 2.3139917392243752e+00, 2.5366282819075883e+00, 2.7598999256576846e+00, 2.9838708799890519e+00, 3.2086078523280142e+00, 3.4341803600244734e+00, 3.6606610751014688e+00, 3.8881262072644476e+00, 4.1166559316947993e+00, 4.3463348693861139e+00, 4.5772526293071110e+00, 4.8095044235715418e+00, 5.0431917691668700e+00, 5.2784232927787453e+00, 5.5153156590327264e+00, 5.7539946473095069e+00, 5.9945964085177108e+00, 6.2372689413028590e+00, 6.4821738377935736e+00, 6.7294883630724422e+00, 6.9794079514507139e+00, 7.2321492282755919e+00, 7.4879537012921364e+00, 7.7470923148599020e+00, 8.0098711302417200e+00, 8.2766384961541863e+00, 8.5477942224789647e+00, 8.8238014938930043e+00, 9.1052026055338082e+00, 9.3926401506071997e+00, 9.6868861866549612e+00, 9.9888834298724642e+00, 1.0299805224248269e+01, 1.0621146056253156e+01, 1.0954864323727046e+01, 1.1303620232659483e+01, 1.1671201169018351e+01, 1.2063357508698903e+01, 1.2489679720231214e+01, 1.2968787175621387e+01, 1.3549444856223355e+01}, {-1.3620387729947742e+01, -1.3040726988796493e+01, -1.2562467887793943e+01, -1.2136921090287251e+01, -1.1745495813506075e+01, -1.1378616213805854e+01, -1.1030540650989794e+01, -1.0697487488847003e+01, -1.0376800570599057e+01, -1.0066524497824579e+01, -9.7651670958633421e+00, -9.4715568613271639e+00, -9.1847525840655759e+00, -8.9039834682597192e+00, -8.6286079999230569e+00, -8.3580848243237309e+00, -8.0919515900932844e+00, -7.8298092371332197e+00, -7.5713101008750368e+00, -7.3161487524084921e+00, -7.0640548388279587e+00, -6.8147874116676039e+00, -6.5681303797817083e+00, -6.3238888238470219e+00, -6.0818859794767741e+00, -5.8419607451405371e+00, -5.6039656063250805e+00, -5.3677648929830539e+00, -5.1332333061803963e+00, -4.9002546639192408e+00, -4.6687208267203344e+00, -4.4385307716320357e+00, -4.2095897895522105e+00, -3.9818087855776474e+00, -3.7551036658752275e+00, -3.5293947975507334e+00, -3.3046065303600929e+00, -3.0806667710024973e+00, -2.8575066022592246e+00, -2.6350599404753994e+00, -2.4132632258847226e+00, -2.1920551410961067e+00, -1.9713763537322730e+00, -1.7511692797619354e+00, -1.5313778645213059e+00, -1.3119473787947484e+00, -1.0928242276321787e+00, -8.7395576983320977e-01, -6.5529014623361903e-01, -4.3677611509527065e-01, -2.1836289303147782e-01, -0.0000000000000000e+00, 2.1836289303147782e-01, 4.3677611509527065e-01, 6.5529014623361903e-01, 8.7395576983320977e-01, 1.0928242276321787e+00, 1.3119473787947484e+00, 1.5313778645213059e+00, 1.7511692797619354e+00, 1.9713763537322730e+00, 2.1920551410961067e+00, 2.4132632258847226e+00, 2.6350599404753994e+00, 2.8575066022592246e+00, 3.0806667710024973e+00, 3.3046065303600929e+00, 3.5293947975507334e+00, 3.7551036658752275e+00, 3.9818087855776474e+00, 4.2095897895522105e+00, 4.4385307716320357e+00, 4.6687208267203344e+00, 4.9002546639192408e+00, 5.1332333061803963e+00, 5.3677648929830539e+00, 5.6039656063250805e+00, 5.8419607451405371e+00, 6.0818859794767741e+00, 6.3238888238470219e+00, 6.5681303797817083e+00, 6.8147874116676039e+00, 7.0640548388279587e+00, 7.3161487524084921e+00, 7.5713101008750368e+00, 7.8298092371332197e+00, 8.0919515900932844e+00, 8.3580848243237309e+00, 8.6286079999230569e+00, 8.9039834682597192e+00, 9.1847525840655759e+00, 9.4715568613271639e+00, 9.7651670958633421e+00, 1.0066524497824579e+01, 1.0376800570599057e+01, 1.0697487488847003e+01, 1.1030540650989794e+01, 1.1378616213805854e+01, 1.1745495813506075e+01, 1.2136921090287251e+01, 1.2562467887793943e+01, 1.3040726988796493e+01, 1.3620387729947742e+01}, {-1.3690980373715535e+01, -1.3112304908251922e+01, -1.2634884014394832e+01, -1.2210103175151124e+01, -1.1819399886057777e+01, -1.1453212768894272e+01, -1.1105808823112232e+01, -1.0773412098098593e+01, -1.0453370440115185e+01, -1.0143731414960465e+01, -9.8430051316625278e+00, -9.5500219040630885e+00, -9.2638420079694495e+00, -8.9836958915100507e+00, -8.7089431037842626e+00, -8.4390432154976232e+00, -8.1735346944358760e+00, -7.9120192166772831e+00, -7.6541497885353431e+00, -7.3996216003602537e+00, -7.1481648776449447e+00, -6.8995392180679298e+00, -6.6535290513692580e+00, -6.4099399596264091e+00, -6.1685956652061904e+00, -5.9293355428005707e+00, -5.6920125471434968e+00, -5.4564914735798906e+00, -5.2226474874947222e+00, -4.9903648726555803e+00, -4.7595359591142765e+00, -4.5300601993847316e+00, -4.3018433678250396e+00, -4.0747968629734785e+00, -3.8488370963629586e+00, -3.6238849543164635e+00, -3.3998653215923187e+00, -3.1767066576408891e+00, -2.9543406177575795e+00, -2.7327017126497148e+00, -2.5117270009375883e+00, -2.2913558099291085e+00, -2.0715294806793496e+00, -1.8521911338989445e+00, -1.6332854537309136e+00, -1.4147584867915231e+00, -1.1965574541809449e+00, -9.7863057442477308e-01, -7.6092689551645798e-01, -5.4339613440036172e-01, -3.2598852237076159e-01, -1.0865465496797615e-01, 1.0865465496797615e-01, 3.2598852237076159e-01, 5.4339613440036172e-01, 7.6092689551645798e-01, 9.7863057442477308e-01, 1.1965574541809449e+00, 1.4147584867915231e+00, 1.6332854537309136e+00, 1.8521911338989445e+00, 2.0715294806793496e+00, 2.2913558099291085e+00, 2.5117270009375883e+00, 2.7327017126497148e+00, 2.9543406177575795e+00, 3.1767066576408891e+00, 3.3998653215923187e+00, 3.6238849543164635e+00, 3.8488370963629586e+00, 4.0747968629734785e+00, 4.3018433678250396e+00, 4.5300601993847316e+00, 4.7595359591142765e+00, 4.9903648726555803e+00, 5.2226474874947222e+00, 5.4564914735798906e+00, 5.6920125471434968e+00, 5.9293355428005707e+00, 6.1685956652061904e+00, 6.4099399596264091e+00, 6.6535290513692580e+00, 6.8995392180679298e+00, 7.1481648776449447e+00, 7.3996216003602537e+00, 7.6541497885353431e+00, 7.9120192166772831e+00, 8.1735346944358760e+00, 8.4390432154976232e+00, 8.7089431037842626e+00, 8.9836958915100507e+00, 9.2638420079694495e+00, 9.5500219040630885e+00, 9.8430051316625278e+00, 1.0143731414960465e+01, 1.0453370440115185e+01, 1.0773412098098593e+01, 1.1105808823112232e+01, 1.1453212768894272e+01, 1.1819399886057777e+01, 1.2210103175151124e+01, 1.2634884014394832e+01, 1.3112304908251922e+01, 1.3690980373715535e+01}, {-1.3761227897775342e+01, -1.3183526293600599e+01, -1.2706933680714704e+01, -1.2282909553416038e+01, -1.1892919380924928e+01, -1.1527416094254811e+01, -1.1180675238467860e+01, -1.0848926485775479e+01, -1.0529521640346799e+01, -1.0220511197831829e+01, -9.9204075235256379e+00, -9.6280427257475036e+00, -9.3424785467404909e+00, -9.0629466613367704e+00, -8.7888076661013130e+00, -8.5195220427131719e+00, -8.2546290644616640e+00, -7.9937311305046359e+00, -7.7364819052916909e+00, -7.4825771858770791e+00, -7.2317477636524030e+00, -6.9837537698848138e+00, -6.7383801424910441e+00, -6.4954329519998799e+00, -6.2547363942623555e+00, -6.0161303065289111e+00, -5.7794680986505123e+00, -5.5446150166977928e+00, -5.3114466751017559e+00, -5.0798478074449882e+00, -4.8497111966094790e+00, -4.6209367530474879e+00, -4.3934307161440911e+00, -4.1671049584554103e+00, -3.9418763763764075e+00, -3.7176663537665213e+00, -3.4944002874250444e+00, -3.2720071651989722e+00, -3.0504191890280565e+00, -2.8295714364637563e+00, -2.6094015552011851e+00, -2.3898494859824693e+00, -2.1708572099022447e+00, -1.9523685166996116e+00, -1.7343287910777165e+00, -1.5166848144697649e+00, -1.2993845799825059e+00, -1.0823771185059250e+00, -8.6561233418988326e-01, -6.4904084766152925e-01, -4.3261384549707677e-01, -2.1628293457217421e-01, -0.0000000000000000e+00, 2.1628293457217421e-01, 4.3261384549707677e-01, 6.4904084766152925e-01, 8.6561233418988326e-01, 1.0823771185059250e+00, 1.2993845799825059e+00, 1.5166848144697649e+00, 1.7343287910777165e+00, 1.9523685166996116e+00, 2.1708572099022447e+00, 2.3898494859824693e+00, 2.6094015552011851e+00, 2.8295714364637563e+00, 3.0504191890280565e+00, 3.2720071651989722e+00, 3.4944002874250444e+00, 3.7176663537665213e+00, 3.9418763763764075e+00, 4.1671049584554103e+00, 4.3934307161440911e+00, 4.6209367530474879e+00, 4.8497111966094790e+00, 5.0798478074449882e+00, 5.3114466751017559e+00, 5.5446150166977928e+00, 5.7794680986505123e+00, 6.0161303065289111e+00, 6.2547363942623555e+00, 6.4954329519998799e+00, 6.7383801424910441e+00, 6.9837537698848138e+00, 7.2317477636524030e+00, 7.4825771858770791e+00, 7.7364819052916909e+00, 7.9937311305046359e+00, 8.2546290644616640e+00, 8.5195220427131719e+00, 8.7888076661013130e+00, 9.0629466613367704e+00, 9.3424785467404909e+00, 9.6280427257475036e+00, 9.9204075235256379e+00, 1.0220511197831829e+01, 1.0529521640346799e+01, 1.0848926485775479e+01, 1.1180675238467860e+01, 1.1527416094254811e+01, 1.1892919380924928e+01, 1.2282909553416038e+01, 1.2706933680714704e+01, 1.3183526293600599e+01, 1.3761227897775342e+01}, {-1.3831135289582965e+01, -1.3254396373973801e+01, -1.2778622330019754e+01, -1.2355345871125120e+01, -1.1966060141686793e+01, -1.1601232228934139e+01, -1.1255146131451047e+01, -1.0924037082840369e+01, -1.0605260801047601e+01, -1.0296870678005966e+01, -9.9973813085297891e+00, -9.7056265732561915e+00, -9.4206696618824566e+00, -9.1417434592085591e+00, -8.8682095941331820e+00, -8.5995294453241531e+00, -8.3352430784012270e+00, -8.0749536029866285e+00, -7.8183153294116643e+00, -7.5650246493836404e+00, -7.3148129082162541e+00, -7.0674407587544215e+00, -6.8226936349524259e+00, -6.5803780834395011e+00, -6.3403187609122504e+00, -6.1023559541821202e+00, -5.8663435147929848e+00, -5.6321471256242530e+00, -5.3996428356774224e+00, -5.1687158132495581e+00, -4.9392592782592839e+00, -4.7111735825401517e+00, -4.4843654131098756e+00, -4.2587470982328570e+00, -4.0342359998584794e+00, -3.8107539789883282e+00, -3.5882269228863879e+00, -3.3665843249351557e+00, -3.1457589094612213e+00, -2.9256862950849976e+00, -2.7063046911512725e+00, -2.4875546226165683e+00, -2.2693786794419482e+00, -2.0517212870941761e+00, -1.8345284952160181e+00, -1.6177477819054702e+00, -1.4013278713576325e+00, -1.1852185628827800e+00, -9.6937056952866862e-01, -7.5373536471122926e-01, -5.3826503540107018e-01, -3.2291214052800010e-01, -1.0762957335551564e-01, 1.0762957335551564e-01, 3.2291214052800010e-01, 5.3826503540107018e-01, 7.5373536471122926e-01, 9.6937056952866862e-01, 1.1852185628827800e+00, 1.4013278713576325e+00, 1.6177477819054702e+00, 1.8345284952160181e+00, 2.0517212870941761e+00, 2.2693786794419482e+00, 2.4875546226165683e+00, 2.7063046911512725e+00, 2.9256862950849976e+00, 3.1457589094612213e+00, 3.3665843249351557e+00, 3.5882269228863879e+00, 3.8107539789883282e+00, 4.0342359998584794e+00, 4.2587470982328570e+00, 4.4843654131098756e+00, 4.7111735825401517e+00, 4.9392592782592839e+00, 5.1687158132495581e+00, 5.3996428356774224e+00, 5.6321471256242530e+00, 5.8663435147929848e+00, 6.1023559541821202e+00, 6.3403187609122504e+00, 6.5803780834395011e+00, 6.8226936349524259e+00, 7.0674407587544215e+00, 7.3148129082162541e+00, 7.5650246493836404e+00, 7.8183153294116643e+00, 8.0749536029866285e+00, 8.3352430784012270e+00, 8.5995294453241531e+00, 8.8682095941331820e+00, 9.1417434592085591e+00, 9.4206696618824566e+00, 9.7056265732561915e+00, 9.9973813085297891e+00, 1.0296870678005966e+01, 1.0605260801047601e+01, 1.0924037082840369e+01, 1.1255146131451047e+01, 1.1601232228934139e+01, 1.1966060141686793e+01, 1.2355345871125120e+01, 1.2778622330019754e+01, 1.3254396373973801e+01, 1.3831135289582965e+01}, {-1.3900707417887173e+01, -1.3324920252415142e+01, -1.2849955272837832e+01, -1.2427417635190753e+01, -1.2038827866477725e+01, -1.1674667060202870e+01, -1.1329227578271460e+01, -1.0998750155541702e+01, -1.0680594380572309e+01, -1.0372816508782414e+01, -1.0073933338405658e+01, -9.7827805008057851e+00, -9.4984226146699928e+00, -9.2200937585148388e+00, -8.9471565789061032e+00, -8.6790733379711611e+00, -8.4153848809401453e+00, -8.1556950157409371e+00, -7.8996586867968652e+00, -7.6469728688944967e+00, -7.3973694497863685e+00, -7.1506095923972852e+00, -6.9064792151159047e+00, -6.6647853288831929e+00, -6.4253530391943388e+00, -6.1880230700488541e+00, -5.9526497019202820e+00, -5.7190990412807672e+00, -5.4872475579716511e+00, -5.2569808406969596e+00, -5.0281925314641187e+00, -4.8007834078342349e+00, -4.5746605880295625e+00, -4.3497368387482860e+00, -4.1259299692968714e+00, -3.9031622986173096e+00, -3.6813601841446331e+00, -3.4604536033170050e+00, -3.2403757800798094e+00, -3.0210628499554302e+00, -2.8024535582518539e+00, -2.5844889868023952e+00, -2.3671123053017529e+00, -2.1502685438583309e+00, -1.9339043838414955e+00, -1.7179679644825636e+00, -1.5024087030036999e+00, -1.2871771263105225e+00, -1.0722247125008730e+00, -8.5750374062088575e-01, -6.4296714724579429e-01, -4.2856838858126434e-01, -2.1426130687493608e-01, -0.0000000000000000e+00, 2.1426130687493608e-01, 4.2856838858126434e-01, 6.4296714724579429e-01, 8.5750374062088575e-01, 1.0722247125008730e+00, 1.2871771263105225e+00, 1.5024087030036999e+00, 1.7179679644825636e+00, 1.9339043838414955e+00, 2.1502685438583309e+00, 2.3671123053017529e+00, 2.5844889868023952e+00, 2.8024535582518539e+00, 3.0210628499554302e+00, 3.2403757800798094e+00, 3.4604536033170050e+00, 3.6813601841446331e+00, 3.9031622986173096e+00, 4.1259299692968714e+00, 4.3497368387482860e+00, 4.5746605880295625e+00, 4.8007834078342349e+00, 5.0281925314641187e+00, 5.2569808406969596e+00, 5.4872475579716511e+00, 5.7190990412807672e+00, 5.9526497019202820e+00, 6.1880230700488541e+00, 6.4253530391943388e+00, 6.6647853288831929e+00, 6.9064792151159047e+00, 7.1506095923972852e+00, 7.3973694497863685e+00, 7.6469728688944967e+00, 7.8996586867968652e+00, 8.1556950157409371e+00, 8.4153848809401453e+00, 8.6790733379711611e+00, 8.9471565789061032e+00, 9.2200937585148388e+00, 9.4984226146699928e+00, 9.7827805008057851e+00, 1.0073933338405658e+01, 1.0372816508782414e+01, 1.0680594380572309e+01, 1.0998750155541702e+01, 1.1329227578271460e+01, 1.1674667060202870e+01, 1.2038827866477725e+01, 1.2427417635190753e+01, 1.2849955272837832e+01, 1.3324920252415142e+01, 1.3900707417887173e+01}, {-1.3969949036642459e+01, -1.3395102910086411e+01, -1.2920937691432538e+01, -1.2499130218130038e+01, -1.2111228112984248e+01, -1.1747726328818176e+01, -1.1402925502488745e+01, -1.1073071811228770e+01, -1.0755528671982248e+01, -1.0448355171600436e+01, -1.0150070286259611e+01, -9.8595113770046634e+00, -9.5757444735437325e+00, -9.2980048323218245e+00, -9.0256561033487941e+00, -8.7581614191156962e+00, -8.4950623921731907e+00, -8.2359635170287859e+00, -7.9805203608479554e+00, -7.7284304703735840e+00, -7.4794262647792982e+00, -7.2332694060552951e+00, -6.9897462859257979e+00, -6.7486643683832410e+00, -6.5098491962299123e+00, -6.2731419188661652e+00, -6.0383972335511160e+00, -5.8054816577895725e+00, -5.5742720692284102e+00, -5.3446544634117208e+00, -5.1165228902768884e+00, -4.8897785383006882e+00, -4.6643289413814166e+00, -4.4400872883391642e+00, -4.2169718186716345e+00, -3.9949052911662122e+00, -3.7738145143243407e+00, -3.5536299294390266e+00, -3.3342852386840143e+00, -3.1157170718023619e+00, -2.8978646859830590e+00, -2.6806696943332091e+00, -2.4640758190263061e+00, -2.2480286657622290e+00, -2.0324755166339639e+00, -1.8173651388771286e+00, -1.6026476072949805e+00, -1.3882741384147259e+00, -1.1741969346494687e+00, -9.6036903692102105e-01, -7.4674418434770939e-01, -5.3327667972273107e-01, -3.1992125960608508e-01, -1.0663296792943616e-01, 1.0663296792943616e-01, 3.1992125960608508e-01, 5.3327667972273107e-01, 7.4674418434770939e-01, 9.6036903692102105e-01, 1.1741969346494687e+00, 1.3882741384147259e+00, 1.6026476072949805e+00, 1.8173651388771286e+00, 2.0324755166339639e+00, 2.2480286657622290e+00, 2.4640758190263061e+00, 2.6806696943332091e+00, 2.8978646859830590e+00, 3.1157170718023619e+00, 3.3342852386840143e+00, 3.5536299294390266e+00, 3.7738145143243407e+00, 3.9949052911662122e+00, 4.2169718186716345e+00, 4.4400872883391642e+00, 4.6643289413814166e+00, 4.8897785383006882e+00, 5.1165228902768884e+00, 5.3446544634117208e+00, 5.5742720692284102e+00, 5.8054816577895725e+00, 6.0383972335511160e+00, 6.2731419188661652e+00, 6.5098491962299123e+00, 6.7486643683832410e+00, 6.9897462859257979e+00, 7.2332694060552951e+00, 7.4794262647792982e+00, 7.7284304703735840e+00, 7.9805203608479554e+00, 8.2359635170287859e+00, 8.4950623921731907e+00, 8.7581614191156962e+00, 9.0256561033487941e+00, 9.2980048323218245e+00, 9.5757444735437325e+00, 9.8595113770046634e+00, 1.0150070286259611e+01, 1.0448355171600436e+01, 1.0755528671982248e+01, 1.1073071811228770e+01, 1.1402925502488745e+01, 1.1747726328818176e+01, 1.2111228112984248e+01, 1.2499130218130038e+01, 1.2920937691432538e+01, 1.3395102910086411e+01, 1.3969949036642459e+01}, {-1.4038864788757728e+01, -1.3464949210295044e+01, -1.2991574644085651e+01, -1.2570488862595592e+01, -1.2183266303224141e+01, -1.1820415634054809e+01, -1.1476245680301457e+01, -1.1147008003906418e+01, -1.0830069808875091e+01, -1.0523492982154455e+01, -1.0225798652986768e+01, -9.9358258915767603e+00, -9.6526421211592019e+00, -9.3754837607621955e+00, -9.1037154500398181e+00, -8.8368011791635279e+00, -8.5742833161234948e+00, -8.3157670306912532e+00, -8.0609085018410500e+00, -7.8094058375754942e+00, -7.5609919779111072e+00, -7.3154290733448306e+00, -7.0725039783127066e+00, -6.8320245990954787e+00, -6.5938169048330693e+00, -6.3577224590892367e+00, -6.1235963643451115e+00, -5.8913055371925065e+00, -5.6607272507011190e+00, -5.4317478943805018e+00, -5.2042619126759186e+00, -4.9781708909532618e+00, -4.7533827640966910e+00, -4.5298111276324908e+00, -4.3073746350430024e+00, -4.0859964678941409e+00, -3.8656038677524993e+00, -3.6461277207507310e+00, -3.4275021871760831e+00, -3.2096643696850733e+00, -2.9925540147475451e+00, -2.7761132427418982e+00, -2.5602863027962388e+00, -2.3450193490255717e+00, -2.1302602352750175e+00, -1.9159583258608970e+00, -1.7020643201191179e+00, -1.4885300888347839e+00, -1.2753085208470012e+00, -1.0623533783056693e+00, -8.4961915920820152e-01, -6.3706096596817285e-01, -4.2463437886846966e-01, -2.1229533333143397e-01, -0.0000000000000000e+00, 2.1229533333143397e-01, 4.2463437886846966e-01, 6.3706096596817285e-01, 8.4961915920820152e-01, 1.0623533783056693e+00, 1.2753085208470012e+00, 1.4885300888347839e+00, 1.7020643201191179e+00, 1.9159583258608970e+00, 2.1302602352750175e+00, 2.3450193490255717e+00, 2.5602863027962388e+00, 2.7761132427418982e+00, 2.9925540147475451e+00, 3.2096643696850733e+00, 3.4275021871760831e+00, 3.6461277207507310e+00, 3.8656038677524993e+00, 4.0859964678941409e+00, 4.3073746350430024e+00, 4.5298111276324908e+00, 4.7533827640966910e+00, 4.9781708909532618e+00, 5.2042619126759186e+00, 5.4317478943805018e+00, 5.6607272507011190e+00, 5.8913055371925065e+00, 6.1235963643451115e+00, 6.3577224590892367e+00, 6.5938169048330693e+00, 6.8320245990954787e+00, 7.0725039783127066e+00, 7.3154290733448306e+00, 7.5609919779111072e+00, 7.8094058375754942e+00, 8.0609085018410500e+00, 8.3157670306912532e+00, 8.5742833161234948e+00, 8.8368011791635279e+00, 9.1037154500398181e+00, 9.3754837607621955e+00, 9.6526421211592019e+00, 9.9358258915767603e+00, 1.0225798652986768e+01, 1.0523492982154455e+01, 1.0830069808875091e+01, 1.1147008003906418e+01, 1.1476245680301457e+01, 1.1820415634054809e+01, 1.2183266303224141e+01, 1.2570488862595592e+01, 1.2991574644085651e+01, 1.3464949210295044e+01, 1.4038864788757728e+01}, {-1.4107459209689143e+01, -1.3534463902352346e+01, -1.3061871069197858e+01, -1.2641498685712268e+01, -1.2254947728119026e+01, -1.1892740438516830e+01, -1.1549193745603484e+01, -1.1220564539543394e+01, -1.0904223770953831e+01, -1.0598236096233554e+01, -1.0301124773392132e+01, -1.0011730561776583e+01, -9.7291222611091452e+00, -9.4525374380792577e+00, -9.1813417085894020e+00, -8.9149999082012474e+00, -8.6530551488522143e+00, -8.3951132646519024e+00, -8.1408310358446965e+00, -7.8899071213998058e+00, -7.6420749720138357e+00, -7.3970972165620390e+00, -7.1547611620163289e+00, -6.9148751466506351e+00, -6.6772655554639746e+00, -6.4417743554625506e+00, -6.2082570433307618e+00, -5.9765809233777674e+00, -5.7466236523236125e+00, -5.5182720014163928e+00, -5.2914207968757996e+00, -5.0659720076635653e+00, -4.8418339557415173e+00, -4.6189206287614857e+00, -4.3971510788768189e+00, -4.1764488943211937e+00, -3.9567417327500811e+00, -3.7379609072207938e+00, -3.5200410172016268e+00, -3.3029196182276346e+00, -3.0865369248200669e+00, -2.8708355421046665e+00, -2.6557602222368328e+00, -2.4412576422971846e+00, -2.2272762007812905e+00, -2.0137658301898180e+00, -1.8006778235437944e+00, -1.5879646729152568e+00, -1.3755799182849759e+00, -1.1634780052233955e+00, -9.5161415004400396e-01, -7.3994421120471532e-01, -5.2842456583606134e-01, -3.1701199035803573e-01, -1.0566354421255454e-01, 1.0566354421255454e-01, 3.1701199035803573e-01, 5.2842456583606134e-01, 7.3994421120471532e-01, 9.5161415004400396e-01, 1.1634780052233955e+00, 1.3755799182849759e+00, 1.5879646729152568e+00, 1.8006778235437944e+00, 2.0137658301898180e+00, 2.2272762007812905e+00, 2.4412576422971846e+00, 2.6557602222368328e+00, 2.8708355421046665e+00, 3.0865369248200669e+00, 3.3029196182276346e+00, 3.5200410172016268e+00, 3.7379609072207938e+00, 3.9567417327500811e+00, 4.1764488943211937e+00, 4.3971510788768189e+00, 4.6189206287614857e+00, 4.8418339557415173e+00, 5.0659720076635653e+00, 5.2914207968757996e+00, 5.5182720014163928e+00, 5.7466236523236125e+00, 5.9765809233777674e+00, 6.2082570433307618e+00, 6.4417743554625506e+00, 6.6772655554639746e+00, 6.9148751466506351e+00, 7.1547611620163289e+00, 7.3970972165620390e+00, 7.6420749720138357e+00, 7.8899071213998058e+00, 8.1408310358446965e+00, 8.3951132646519024e+00, 8.6530551488522143e+00, 8.9149999082012474e+00, 9.1813417085894020e+00, 9.4525374380792577e+00, 9.7291222611091452e+00, 1.0011730561776583e+01, 1.0301124773392132e+01, 1.0598236096233554e+01, 1.0904223770953831e+01, 1.1220564539543394e+01, 1.1549193745603484e+01, 1.1892740438516830e+01, 1.2254947728119026e+01, 1.2641498685712268e+01, 1.3061871069197858e+01, 1.3534463902352346e+01, 1.4107459209689143e+01}, {-1.4175736730885069e+01, -1.3603651625271072e+01, -1.3131831789217085e+01, -1.2712164683229908e+01, -1.2326277551871243e+01, -1.1964706072741592e+01, -1.1621775194820279e+01, -1.1293747081147552e+01, -1.0977996389349029e+01, -1.0672590515300062e+01, -1.0376054822035842e+01, -1.0087231738512564e+01, -9.8051914243374672e+00, -9.5291725793451221e+00, -9.2585417826765291e+00, -8.9927647033681737e+00, -8.7313851861824325e+00, -8.4740097190111463e+00, -8.2202956732045873e+00, -7.9699422487875475e+00, -7.7226833973667368e+00, -7.4782822164736231e+00, -7.2365264558624682e+00, -6.9972248759462685e+00, -6.7602042675666434e+00, -6.5253069909368815e+00, -6.2923889264375843e+00, -6.0613177552660416e+00, -5.8319715065921489e+00, -5.6042373217821275e+00, -5.3780103967408355e+00, -5.1531930714178591e+00, -4.9296940416745816e+00, -4.7074276734866194e+00, -4.4863134031967471e+00, -4.2662752104856114e+00, -4.0472411530744239e+00, -3.8291429540521795e+00, -3.6119156342329615e+00, -3.3954971831747680e+00, -3.1798282634899460e+00, -2.9648519438950705e+00, -2.7505134571206762e+00, -2.5367599793568107e+00, -2.3235404283709329e+00, -2.1108052778175836e+00, -1.8985063855784825e+00, -1.6865968342381339e+00, -1.4750307820226600e+00, -1.2637633227153910e+00, -1.0527503532175146e+00, -8.4194844755040910e-01, -6.3131473620181966e-01, -4.2080678980376768e-01, -2.1038250619832910e-01, -0.0000000000000000e+00, 2.1038250619832910e-01, 4.2080678980376768e-01, 6.3131473620181966e-01, 8.4194844755040910e-01, 1.0527503532175146e+00, 1.2637633227153910e+00, 1.4750307820226600e+00, 1.6865968342381339e+00, 1.8985063855784825e+00, 2.1108052778175836e+00, 2.3235404283709329e+00, 2.5367599793568107e+00, 2.7505134571206762e+00, 2.9648519438950705e+00, 3.1798282634899460e+00, 3.3954971831747680e+00, 3.6119156342329615e+00, 3.8291429540521795e+00, 4.0472411530744239e+00, 4.2662752104856114e+00, 4.4863134031967471e+00, 4.7074276734866194e+00, 4.9296940416745816e+00, 5.1531930714178591e+00, 5.3780103967408355e+00, 5.6042373217821275e+00, 5.8319715065921489e+00, 6.0613177552660416e+00, 6.2923889264375843e+00, 6.5253069909368815e+00, 6.7602042675666434e+00, 6.9972248759462685e+00, 7.2365264558624682e+00, 7.4782822164736231e+00, 7.7226833973667368e+00, 7.9699422487875475e+00, 8.2202956732045873e+00, 8.4740097190111463e+00, 8.7313851861824325e+00, 8.9927647033681737e+00, 9.2585417826765291e+00, 9.5291725793451221e+00, 9.8051914243374672e+00, 1.0087231738512564e+01, 1.0376054822035842e+01, 1.0672590515300062e+01, 1.0977996389349029e+01, 1.1293747081147552e+01, 1.1621775194820279e+01, 1.1964706072741592e+01, 1.2326277551871243e+01, 1.2712164683229908e+01, 1.3131831789217085e+01, 1.3603651625271072e+01, 1.4175736730885069e+01}, {-1.4243701683090396e+01, -1.3672516911310485e+01, -1.3201461514403192e+01, -1.2782491733501539e+01, -1.2397260816155137e+01, -1.2036317739606817e+01, -1.1693995391536458e+01, -1.1366561153620273e+01, -1.1051393351707578e+01, -1.0746562091821255e+01, -1.0450594818817532e+01, -1.0162335612194752e+01, -9.8808559752619285e+00, -9.6053957268710537e+00, -9.3353223967607271e+00, -9.0701024758844149e+00, -8.8092805310594660e+00, -8.5524636937560086e+00, -8.2993099166213113e+00, -8.0495189311868405e+00, -7.8028251805712348e+00, -7.5589922216241447e+00, -7.3178082375274442e+00, -7.0790824013949303e+00, -6.8426419003295491e+00, -6.6083294779732258e+00, -6.3760013883766673e+00, -6.1455256793035486e+00, -5.9167807417097054e+00, -5.6896540760274723e+00, -5.4640412363607487e+00, -5.2398449216799987e+00, -5.0169741892502993e+00, -4.7953437702964461e+00, -4.5748734716450743e+00, -4.3554876500322477e+00, -4.1371147481089601e+00, -3.9196868830532363e+00, -3.7031394802088755e+00, -3.4874109453955420e+00, -3.2724423705327612e+00, -3.0581772680375412e+00, -2.8445613301276866e+00, -2.6315422097183796e+00, -2.4190693200603040e+00, -2.2070936506509247e+00, -1.9955675972702900e+00, -1.7844448042599628e+00, -1.5736800173872914e+00, -1.3632289458242499e+00, -1.1530481319262951e+00, -9.4309482762671593e-01, -7.3332687636947402e-01, -5.2370259959160714e-01, -3.1418068683720984e-01, -1.0472008864073033e-01, 1.0472008864073033e-01, 3.1418068683720984e-01, 5.2370259959160714e-01, 7.3332687636947402e-01, 9.4309482762671593e-01, 1.1530481319262951e+00, 1.3632289458242499e+00, 1.5736800173872914e+00, 1.7844448042599628e+00, 1.9955675972702900e+00, 2.2070936506509247e+00, 2.4190693200603040e+00, 2.6315422097183796e+00, 2.8445613301276866e+00, 3.0581772680375412e+00, 3.2724423705327612e+00, 3.4874109453955420e+00, 3.7031394802088755e+00, 3.9196868830532363e+00, 4.1371147481089601e+00, 4.3554876500322477e+00, 4.5748734716450743e+00, 4.7953437702964461e+00, 5.0169741892502993e+00, 5.2398449216799987e+00, 5.4640412363607487e+00, 5.6896540760274723e+00, 5.9167807417097054e+00, 6.1455256793035486e+00, 6.3760013883766673e+00, 6.6083294779732258e+00, 6.8426419003295491e+00, 7.0790824013949303e+00, 7.3178082375274442e+00, 7.5589922216241447e+00, 7.8028251805712348e+00, 8.0495189311868405e+00, 8.2993099166213113e+00, 8.5524636937560086e+00, 8.8092805310594660e+00, 9.0701024758844149e+00, 9.3353223967607271e+00, 9.6053957268710537e+00, 9.8808559752619285e+00, 1.0162335612194752e+01, 1.0450594818817532e+01, 1.0746562091821255e+01, 1.1051393351707578e+01, 1.1366561153620273e+01, 1.1693995391536458e+01, 1.2036317739606817e+01, 1.2397260816155137e+01, 1.2782491733501539e+01, 1.3201461514403192e+01, 1.3672516911310485e+01, 1.4243701683090396e+01}, {-1.4311358299517268e+01, -1.3741064189376445e+01, -1.3270764846437274e+01, -1.2852484601295865e+01, -1.2467902444132251e+01, -1.2107580518550922e+01, -1.1765859570925668e+01, -1.1439012148401694e+01, -1.1124420207060311e+01, -1.0820156534367447e+01, -1.0524750634313888e+01, -1.0237048218321810e+01, -9.9561221176215060e+00, -9.6812132563270588e+00, -9.4116901024866948e+00, -9.1470199577543809e+00, -8.8867481005681856e+00, -8.6304822961073278e+00, -8.3778810688446761e+00, -8.1286446726129125e+00, -7.8825080329965438e+00, -7.6392351571886659e+00, -7.3986146528207790e+00, -7.1604560966616368e+00, -6.9245870629045054e+00, -6.6908506692717395e+00, -6.4591035339104934e+00, -6.2292140613060107e+00, -6.0010609940399187e+00, -5.7745321810917920e+00, -5.5495235238436296e+00, -5.3259380689199052e+00, -5.1036852231316345e+00, -4.8826800705576368e+00, -4.6628427755272810e+00, -4.4440980582138394e+00, -4.2263747318887201e+00, -4.0096052927608685e+00, -3.7937255548353970e+00, -3.5786743234488534e+00, -3.3643931021355877e+00, -3.1508258282961985e+00, -2.9379186338110879e+00, -2.7256196272975335e+00, -2.5138786951694905e+00, -2.3026473190429599e+00, -2.0918784073499572e+00, -1.8815261392920377e+00, -1.6715458194887483e+00, -1.4618937418644296e+00, -1.2525270614742765e+00, -1.0434036731020315e+00, -8.3448209557097697e-01, -6.2572136079995633e-01, -4.1708090670945613e-01, -2.0852047314122538e-01, -0.0000000000000000e+00, 2.0852047314122538e-01, 4.1708090670945613e-01, 6.2572136079995633e-01, 8.3448209557097697e-01, 1.0434036731020315e+00, 1.2525270614742765e+00, 1.4618937418644296e+00, 1.6715458194887483e+00, 1.8815261392920377e+00, 2.0918784073499572e+00, 2.3026473190429599e+00, 2.5138786951694905e+00, 2.7256196272975335e+00, 2.9379186338110879e+00, 3.1508258282961985e+00, 3.3643931021355877e+00, 3.5786743234488534e+00, 3.7937255548353970e+00, 4.0096052927608685e+00, 4.2263747318887201e+00, 4.4440980582138394e+00, 4.6628427755272810e+00, 4.8826800705576368e+00, 5.1036852231316345e+00, 5.3259380689199052e+00, 5.5495235238436296e+00, 5.7745321810917920e+00, 6.0010609940399187e+00, 6.2292140613060107e+00, 6.4591035339104934e+00, 6.6908506692717395e+00, 6.9245870629045054e+00, 7.1604560966616368e+00, 7.3986146528207790e+00, 7.6392351571886659e+00, 7.8825080329965438e+00, 8.1286446726129125e+00, 8.3778810688446761e+00, 8.6304822961073278e+00, 8.8867481005681856e+00, 9.1470199577543809e+00, 9.4116901024866948e+00, 9.6812132563270588e+00, 9.9561221176215060e+00, 1.0237048218321810e+01, 1.0524750634313888e+01, 1.0820156534367447e+01, 1.1124420207060311e+01, 1.1439012148401694e+01, 1.1765859570925668e+01, 1.2107580518550922e+01, 1.2467902444132251e+01, 1.2852484601295865e+01, 1.3270764846437274e+01, 1.3741064189376445e+01, 1.4311358299517268e+01}, {-1.4378710718888687e+01, -1.3809297788283777e+01, -1.3339746281883333e+01, -1.2922147941452449e+01, -1.2538207244299381e+01, -1.2178499369616199e+01, -1.1837372843992933e+01, -1.1511105327917651e+01, -1.1197082370480098e+01, -1.0893379412488740e+01, -1.0598527994882549e+01, -1.0311375442821380e+01, -1.0030995900063404e+01, -9.7566313825866331e+00, -9.4876512847987584e+00, -9.2235237081638886e+00, -8.9637946326267190e+00, -8.7080724475249998e+00, -8.4560162400066048e+00, -8.2073267773259264e+00, -7.9617394588210120e+00, -7.7190187333975366e+00, -7.4789536245148378e+00, -7.2413541039213873e+00, -7.0060481241167620e+00, -6.7728791679610003e+00, -6.5417042085499943e+00, -6.3123919976942711e+00, -6.0848216199144423e+00, -5.8588812627189206e+00, -5.6344671643769209e+00, -5.4114827083623283e+00, -5.1898376397716799e+00, -4.9694473837781068e+00, -4.7502324499094550e+00, -4.5321179088799042e+00, -4.3150329310427544e+00, -4.0989103774038682e+00, -3.8836864356433058e+00, -3.6693002948148599e+00, -3.4556938533892665e+00, -3.2428114561228023e+00, -3.0305996559046307e+00, -2.8190069972914444e+00, -2.6079838188988345e+00, -2.3974820722025694e+00, -2.1874551546235876e+00, -1.9778577550389427e+00, -1.7686457100860522e+00, -1.5597758698165716e+00, -1.3512059714147289e+00, -1.1428945198277283e+00, -9.3480067426661317e-01, -7.2688413962779108e-01, -5.1910506196077233e-01, -3.1142392716846806e-01, -1.0380146217422165e-01, 1.0380146217422165e-01, 3.1142392716846806e-01, 5.1910506196077233e-01, 7.2688413962779108e-01, 9.3480067426661317e-01, 1.1428945198277283e+00, 1.3512059714147289e+00, 1.5597758698165716e+00, 1.7686457100860522e+00, 1.9778577550389427e+00, 2.1874551546235876e+00, 2.3974820722025694e+00, 2.6079838188988345e+00, 2.8190069972914444e+00, 3.0305996559046307e+00, 3.2428114561228023e+00, 3.4556938533892665e+00, 3.6693002948148599e+00, 3.8836864356433058e+00, 4.0989103774038682e+00, 4.3150329310427544e+00, 4.5321179088799042e+00, 4.7502324499094550e+00, 4.9694473837781068e+00, 5.1898376397716799e+00, 5.4114827083623283e+00, 5.6344671643769209e+00, 5.8588812627189206e+00, 6.0848216199144423e+00, 6.3123919976942711e+00, 6.5417042085499943e+00, 6.7728791679610003e+00, 7.0060481241167620e+00, 7.2413541039213873e+00, 7.4789536245148378e+00, 7.7190187333975366e+00, 7.9617394588210120e+00, 8.2073267773259264e+00, 8.4560162400066048e+00, 8.7080724475249998e+00, 8.9637946326267190e+00, 9.2235237081638886e+00, 9.4876512847987584e+00, 9.7566313825866331e+00, 1.0030995900063404e+01, 1.0311375442821380e+01, 1.0598527994882549e+01, 1.0893379412488740e+01, 1.1197082370480098e+01, 1.1511105327917651e+01, 1.1837372843992933e+01, 1.2178499369616199e+01, 1.2538207244299381e+01, 1.2922147941452449e+01, 1.3339746281883333e+01, 1.3809297788283777e+01, 1.4378710718888687e+01}, {-1.4445762988361196e+01, -1.3877221939887596e+01, -1.3408410215509624e+01, -1.2991486302387372e+01, -1.2608179914177892e+01, -1.2249079137323781e+01, -1.1908540201639026e+01, -1.1582845829838529e+01, -1.1269385127541279e+01, -1.0966236161382101e+01, -1.0671932487544689e+01, -1.0385323027156920e+01, -1.0105483221483672e+01, -9.8316561653115180e+00, -9.5632121677809998e+00, -9.2996201195877468e+00, -9.0404266923744707e+00, -8.7852408903904529e+00, -8.5337223546130900e+00, -8.2855723571485260e+00, -8.0405267626925543e+00, -7.7983504535582933e+00, -7.5588328607481419e+00, -7.3217843426652625e+00, -7.0870332216969052e+00, -6.8544233372804051e+00, -6.6238120087139674e+00, -6.3950683261592980e+00, -6.1680717068342963e+00, -5.9427106672279626e+00, -5.7188817726033569e+00, -5.4964887330064514e+00, -5.2754416211185129e+00, -5.0556561920420737e+00, -4.8370532888321796e+00, -4.6195583205220858e+00, -4.4031008017280051e+00, -4.1876139447872083e+00, -3.9730342968900869e+00, -3.7593014158877045e+00, -3.5463575794514748e+00, -3.3341475230768891e+00, -3.1226182030944165e+00, -2.9117185814056987e+00, -2.7013994291239474e+00, -2.4916131466813880e+00, -2.2823135982874576e+00, -2.0734559588903583e+00, -1.8649965720202712e+00, -1.6568928170822563e+00, -1.4491029848262951e+00, -1.2415861598558324e+00, -1.0343021091482230e+00, -8.2721117565385283e-01, -6.2027417611781133e-01, -4.1345230233083557e-01, -2.0670702506645103e-01, -0.0000000000000000e+00, 2.0670702506645103e-01, 4.1345230233083557e-01, 6.2027417611781133e-01, 8.2721117565385283e-01, 1.0343021091482230e+00, 1.2415861598558324e+00, 1.4491029848262951e+00, 1.6568928170822563e+00, 1.8649965720202712e+00, 2.0734559588903583e+00, 2.2823135982874576e+00, 2.4916131466813880e+00, 2.7013994291239474e+00, 2.9117185814056987e+00, 3.1226182030944165e+00, 3.3341475230768891e+00, 3.5463575794514748e+00, 3.7593014158877045e+00, 3.9730342968900869e+00, 4.1876139447872083e+00, 4.4031008017280051e+00, 4.6195583205220858e+00, 4.8370532888321796e+00, 5.0556561920420737e+00, 5.2754416211185129e+00, 5.4964887330064514e+00, 5.7188817726033569e+00, 5.9427106672279626e+00, 6.1680717068342963e+00, 6.3950683261592980e+00, 6.6238120087139674e+00, 6.8544233372804051e+00, 7.0870332216969052e+00, 7.3217843426652625e+00, 7.5588328607481419e+00, 7.7983504535582933e+00, 8.0405267626925543e+00, 8.2855723571485260e+00, 8.5337223546130900e+00, 8.7852408903904529e+00, 9.0404266923744707e+00, 9.2996201195877468e+00, 9.5632121677809998e+00, 9.8316561653115180e+00, 1.0105483221483672e+01, 1.0385323027156920e+01, 1.0671932487544689e+01, 1.0966236161382101e+01, 1.1269385127541279e+01, 1.1582845829838529e+01, 1.1908540201639026e+01, 1.2249079137323781e+01, 1.2608179914177892e+01, 1.2991486302387372e+01, 1.3408410215509624e+01, 1.3877221939887596e+01, 1.4445762988361196e+01}, {-1.4512519066332473e+01, -1.3944840782089997e+01, -1.3476760943476538e+01, -1.3060504129456817e+01, -1.2677825043852227e+01, -1.2319324554388889e+01, -1.1979366518555956e+01, -1.1654238671159664e+01, -1.1341333638590701e+01, -1.1038732086359635e+01, -1.0744969564657922e+01, -1.0458896573213373e+01, -1.0179589836134598e+01, -9.9062935142905033e+00, -9.6383788202379357e+00, -9.3753154236236274e+00, -9.1166506782713626e+00, -8.8619941943843266e+00, -8.6110061582143160e+00, -8.3633883384434800e+00, -8.1188770570299589e+00, -7.8772376216979518e+00, -7.6382598630271916e+00, -7.4017545180817317e+00, -7.1675502710629999e+00, -6.9354913097861042e+00, -6.7054352913834911e+00, -6.4772516357915970e+00, -6.2508200841027559e+00, -6.0260294726803698e+00, -5.8027766843552886e+00, -5.5809657459630806e+00, -5.3605070475936927e+00, -5.1413166636713479e+00, -4.9233157596994808e+00, -4.7064300714392884e+00, -4.4905894456231428e+00, -4.2757274331715260e+00, -4.0617809273868284e+00, -3.8486898408169177e+00, -3.6363968154755777e+00, -3.4248469619214639e+00, -3.2139876233679749e+00, -3.0037681615511667e+00, -2.7941397615435219e+00, -2.5850552530853812e+00, -2.3764689463269284e+00, -2.1683364801428588e+00, -1.9606146814080672e+00, -1.7532614338130410e+00, -1.5462355549578937e+00, -1.3394966805987920e+00, -1.1330051550337377e+00, -9.2672192670934395e-01, -7.2060844820888659e-01, -5.1462657984655003e-01, -3.0873849614504811e-01, -1.0290659451494534e-01, 1.0290659451494534e-01, 3.0873849614504811e-01, 5.1462657984655003e-01, 7.2060844820888659e-01, 9.2672192670934395e-01, 1.1330051550337377e+00, 1.3394966805987920e+00, 1.5462355549578937e+00, 1.7532614338130410e+00, 1.9606146814080672e+00, 2.1683364801428588e+00, 2.3764689463269284e+00, 2.5850552530853812e+00, 2.7941397615435219e+00, 3.0037681615511667e+00, 3.2139876233679749e+00, 3.4248469619214639e+00, 3.6363968154755777e+00, 3.8486898408169177e+00, 4.0617809273868284e+00, 4.2757274331715260e+00, 4.4905894456231428e+00, 4.7064300714392884e+00, 4.9233157596994808e+00, 5.1413166636713479e+00, 5.3605070475936927e+00, 5.5809657459630806e+00, 5.8027766843552886e+00, 6.0260294726803698e+00, 6.2508200841027559e+00, 6.4772516357915970e+00, 6.7054352913834911e+00, 6.9354913097861042e+00, 7.1675502710629999e+00, 7.4017545180817317e+00, 7.6382598630271916e+00, 7.8772376216979518e+00, 8.1188770570299589e+00, 8.3633883384434800e+00, 8.6110061582143160e+00, 8.8619941943843266e+00, 9.1166506782713626e+00, 9.3753154236236274e+00, 9.6383788202379357e+00, 9.9062935142905033e+00, 1.0179589836134598e+01, 1.0458896573213373e+01, 1.0744969564657922e+01, 1.1038732086359635e+01, 1.1341333638590701e+01, 1.1654238671159664e+01, 1.1979366518555956e+01, 1.2319324554388889e+01, 1.2677825043852227e+01, 1.3060504129456817e+01, 1.3476760943476538e+01, 1.3944840782089997e+01, 1.4512519066332473e+01}, {-1.4578982825139288e+01, -1.4012158361728110e+01, -1.3544802666397535e+01, -1.3129205768185479e+01, -1.2747147119365039e+01, -1.2389240245284292e+01, -1.2049856556961975e+01, -1.1725288752112307e+01, -1.1412932942839976e+01, -1.1110872367128264e+01, -1.0817644548390337e+01, -1.0532101547973223e+01, -1.0253321358511124e+01, -9.9805491945452847e+00, -9.7131571610296650e+00, -9.4506156965670485e+00, -9.1924728279240568e+00, -8.9383387625761230e+00, -8.6878742237708870e+00, -8.4407814687705134e+00, -8.1967972689854154e+00, -7.9556873498473575e+00, -7.7172419338499774e+00, -7.4812721290378645e+00, -7.2476069736794351e+00, -7.0160909961088489e+00, -6.7865821832816833e+00, -6.5589502767074928e+00, -6.3330753329246656e+00, -6.1088464994807214e+00, -5.8861609677875624e+00, -5.6649230721526251e+00, -5.4450435103908958e+00, -5.2264386661630065e+00, -5.0090300168969302e+00, -4.7927436140809663e+00, -4.5775096250454670e+00, -4.3632619272160529e+00, -4.1499377473239889e+00, -3.9374773392776570e+00, -3.7258236953922830e+00, -3.5149222864888690e+00, -3.3047208270435604e+00, -3.0951690621230776e+00, -2.8862185733023908e+00, -2.6778226011448112e+00, -2.4699358821459070e+00, -2.2625144983121754e+00, -2.0555157377720055e+00, -1.8488979650073754e+00, -1.6426204994556326e+00, -1.4366435013663816e+00, -1.2309278639126584e+00, -1.0254351106514223e+00, -8.2012729750837221e-01, -6.1496691852828633e-01, -4.0991681468614050e-01, -2.0494008509748737e-01, -0.0000000000000000e+00, 2.0494008509748737e-01, 4.0991681468614050e-01, 6.1496691852828633e-01, 8.2012729750837221e-01, 1.0254351106514223e+00, 1.2309278639126584e+00, 1.4366435013663816e+00, 1.6426204994556326e+00, 1.8488979650073754e+00, 2.0555157377720055e+00, 2.2625144983121754e+00, 2.4699358821459070e+00, 2.6778226011448112e+00, 2.8862185733023908e+00, 3.0951690621230776e+00, 3.3047208270435604e+00, 3.5149222864888690e+00, 3.7258236953922830e+00, 3.9374773392776570e+00, 4.1499377473239889e+00, 4.3632619272160529e+00, 4.5775096250454670e+00, 4.7927436140809663e+00, 5.0090300168969302e+00, 5.2264386661630065e+00, 5.4450435103908958e+00, 5.6649230721526251e+00, 5.8861609677875624e+00, 6.1088464994807214e+00, 6.3330753329246656e+00, 6.5589502767074928e+00, 6.7865821832816833e+00, 7.0160909961088489e+00, 7.2476069736794351e+00, 7.4812721290378645e+00, 7.7172419338499774e+00, 7.9556873498473575e+00, 8.1967972689854154e+00, 8.4407814687705134e+00, 8.6878742237708870e+00, 8.9383387625761230e+00, 9.1924728279240568e+00, 9.4506156965670485e+00, 9.7131571610296650e+00, 9.9805491945452847e+00, 1.0253321358511124e+01, 1.0532101547973223e+01, 1.0817644548390337e+01, 1.1110872367128264e+01, 1.1412932942839976e+01, 1.1725288752112307e+01, 1.2049856556961975e+01, 1.2389240245284292e+01, 1.2747147119365039e+01, 1.3129205768185479e+01, 1.3544802666397535e+01, 1.4012158361728110e+01, 1.4578982825139288e+01}, {-1.4645158053651027e+01, -1.4079178637349177e+01, -1.3612539492279215e+01, -1.3197595467366467e+01, -1.2816150525975972e+01, -1.2458830729659516e+01, -1.2120014970184142e+01, -1.1796000859913661e+01, -1.1484187962287965e+01, -1.1182662061890452e+01, -1.0889962635005938e+01, -1.0604943287993811e+01, -1.0326683268027864e+01, -1.0054428831215711e+01, -9.7875529641744929e+00, -9.5255268647413445e+00, -9.2678992236538775e+00, -9.0142808372415573e+00, -8.7643329577328277e+00, -8.5177583232401322e+00, -8.2742941470872093e+00, -8.0337065649878543e+00, -7.7957861839727647e+00, -7.5603444756835589e+00, -7.3272108250171302e+00, -7.0962300932900497e+00, -6.8672605896069676e+00, -6.6401723692025154e+00, -6.4148457960045002e+00, -6.1911703204459041e+00, -5.9690434339462293e+00, -5.7483697694039071e+00, -5.5290603231377613e+00, -5.3110317784497383e+00, -5.0942059146888043e+00, -4.8785090886224198e+00, -4.6638717772489988e+00, -4.4502281730478108e+00, -4.2375158241640083e+00, -4.0256753132434273e+00, -3.8146499696239737e+00, -3.6043856104035212e+00, -3.3948303065739314e+00, -3.1859341709648956e+00, -2.9776491652016608e+00, -2.7699289232646307e+00, -2.5627285895601974e+00, -2.3560046696818464e+00, -2.1497148922675668e+00, -1.9438180805509269e+00, -1.7382740323646890e+00, -1.5330434074921915e+00, -1.3280876213767709e+00, -1.1233687442963156e+00, -9.1884940519120828e-01, -7.1449269940145821e-01, -5.1026209962444491e-01, -3.0612136944972701e-01, -1.0203447886287802e-01, 1.0203447886287802e-01, 3.0612136944972701e-01, 5.1026209962444491e-01, 7.1449269940145821e-01, 9.1884940519120828e-01, 1.1233687442963156e+00, 1.3280876213767709e+00, 1.5330434074921915e+00, 1.7382740323646890e+00, 1.9438180805509269e+00, 2.1497148922675668e+00, 2.3560046696818464e+00, 2.5627285895601974e+00, 2.7699289232646307e+00, 2.9776491652016608e+00, 3.1859341709648956e+00, 3.3948303065739314e+00, 3.6043856104035212e+00, 3.8146499696239737e+00, 4.0256753132434273e+00, 4.2375158241640083e+00, 4.4502281730478108e+00, 4.6638717772489988e+00, 4.8785090886224198e+00, 5.0942059146888043e+00, 5.3110317784497383e+00, 5.5290603231377613e+00, 5.7483697694039071e+00, 5.9690434339462293e+00, 6.1911703204459041e+00, 6.4148457960045002e+00, 6.6401723692025154e+00, 6.8672605896069676e+00, 7.0962300932900497e+00, 7.3272108250171302e+00, 7.5603444756835589e+00, 7.7957861839727647e+00, 8.0337065649878543e+00, 8.2742941470872093e+00, 8.5177583232401322e+00, 8.7643329577328277e+00, 9.0142808372415573e+00, 9.2678992236538775e+00, 9.5255268647413445e+00, 9.7875529641744929e+00, 1.0054428831215711e+01, 1.0326683268027864e+01, 1.0604943287993811e+01, 1.0889962635005938e+01, 1.1182662061890452e+01, 1.1484187962287965e+01, 1.1796000859913661e+01, 1.2120014970184142e+01, 1.2458830729659516e+01, 1.2816150525975972e+01, 1.3197595467366467e+01, 1.3612539492279215e+01, 1.4079178637349177e+01, 1.4645158053651027e+01}, {-1.4711048459763671e+01, -1.4145905481877998e+01, -1.3679975439346320e+01, -1.3265677382038762e+01, -1.2884839551290751e+01, -1.2528100425622796e+01, -1.2189846306095971e+01, -1.1866379672363987e+01, -1.1555103505482034e+01, -1.1254106111274996e+01, -1.0961928898971054e+01, -1.0677427003696076e+01, -1.0399680913497548e+01, -1.0127937914235881e+01, -9.8615718637313439e+00, -9.6000547095956161e+00, -9.3429357978203189e+00, -9.0898265054222858e+00, -8.8403886058470427e+00, -8.5943253105810840e+00, -8.3513742675803542e+00, -8.1113020156791773e+00, -7.8738995393403330e+00, -7.6389786667002593e+00, -7.4063691221380390e+00, -7.1759160927206223e+00, -6.9474782023460993e+00, -6.7209258124599129e+00, -6.4961395866732436e+00, -6.2730092703749003e+00, -6.0514326468076227e+00, -5.8313146389908859e+00, -5.6125665329607717e+00, -5.3951053025257689e+00, -5.1788530194404441e+00, -4.9637363358218023e+00, -4.7496860279573854e+00, -4.5366365925149861e+00, -4.3245258876633645e+00, -4.1132948128290048e+00, -3.9028870218050722e+00, -3.6932486647410911e+00, -3.4843281552109961e+00, -3.2760759591109072e+00, -3.0684444025981263e+00, -2.8613874966667088e+00, -2.6548607762763461e+00, -2.4488211522211656e+00, -2.2432267741522884e+00, -2.0380369033597177e+00, -1.8332117940811192e+00, -1.6287125822420414e+00, -1.4245011806478818e+00, -1.2205401797456257e+00, -1.0167927531555376e+00, -8.1322256724173581e-01, -6.0979369404756556e-01, -4.0647052696828645e-01, -2.0321769857092067e-01, -0.0000000000000000e+00, 2.0321769857092067e-01, 4.0647052696828645e-01, 6.0979369404756556e-01, 8.1322256724173581e-01, 1.0167927531555376e+00, 1.2205401797456257e+00, 1.4245011806478818e+00, 1.6287125822420414e+00, 1.8332117940811192e+00, 2.0380369033597177e+00, 2.2432267741522884e+00, 2.4488211522211656e+00, 2.6548607762763461e+00, 2.8613874966667088e+00, 3.0684444025981263e+00, 3.2760759591109072e+00, 3.4843281552109961e+00, 3.6932486647410911e+00, 3.9028870218050722e+00, 4.1132948128290048e+00, 4.3245258876633645e+00, 4.5366365925149861e+00, 4.7496860279573854e+00, 4.9637363358218023e+00, 5.1788530194404441e+00, 5.3951053025257689e+00, 5.6125665329607717e+00, 5.8313146389908859e+00, 6.0514326468076227e+00, 6.2730092703749003e+00, 6.4961395866732436e+00, 6.7209258124599129e+00, 6.9474782023460993e+00, 7.1759160927206223e+00, 7.4063691221380390e+00, 7.6389786667002593e+00, 7.8738995393403330e+00, 8.1113020156791773e+00, 8.3513742675803542e+00, 8.5943253105810840e+00, 8.8403886058470427e+00, 9.0898265054222858e+00, 9.3429357978203189e+00, 9.6000547095956161e+00, 9.8615718637313439e+00, 1.0127937914235881e+01, 1.0399680913497548e+01, 1.0677427003696076e+01, 1.0961928898971054e+01, 1.1254106111274996e+01, 1.1555103505482034e+01, 1.1866379672363987e+01, 1.2189846306095971e+01, 1.2528100425622796e+01, 1.2884839551290751e+01, 1.3265677382038762e+01, 1.3679975439346320e+01, 1.4145905481877998e+01, 1.4711048459763671e+01}, {-1.4776657672798869e+01, -1.4212342685181815e+01, -1.3747114438757134e+01, -1.3333455576348189e+01, -1.2953218388266750e+01, -1.2597053652892484e+01, -1.2259355010417195e+01, -1.1936429761298314e+01, -1.1625684271126064e+01, -1.1325209342106415e+01, -1.1033548296890791e+01, -1.0749557783474378e+01, -1.0472319517421079e+01, -1.0201081802811933e+01, -9.9352193584733488e+00, -9.6742048725828571e+00, -9.4175883379130294e+00, -9.1649817042418142e+00, -8.9160472587078665e+00, -8.6704886789370494e+00, -8.4280440404817565e+00, -8.1884802783862387e+00, -7.9515887476984757e+00, -7.7171816262142663e+00, -7.4850889709254078e+00, -7.2551562877054536e+00, -7.0272425081913878e+00, -6.8012182928404501e+00, -6.5769645975720454e+00, -6.3543714551491233e+00, -6.1333369328198826e+00, -5.9137662356417078e+00, -5.6955709309901366e+00, -5.4786682744780215e+00, -5.2629806212085075e+00, -5.0484349092048060e+00, -4.8349622041811422e+00, -4.6224972966778903e+00, -4.4109783440817232e+00, -4.2003465512658975e+00, -3.9905458845758908e+00, -3.7815228146971922e+00, -3.5732260846105883e+00, -3.3656064993935964e+00, -3.1586167350865688e+00, -2.9522111642257620e+00, -2.7463456959669994e+00, -2.5409776289935784e+00, -2.3360655156294796e+00, -2.1315690357710211e+00, -1.9274488794124773e+00, -1.7236666366787170e+00, -1.5201846943942978e+00, -1.3169661383169375e+00, -1.1139746602463279e+00, -9.1117446928904511e-01, -7.0853020661847821e-01, -5.0600686311669596e-01, -3.0356969932406813e-01, -1.0118416715318335e-01, 1.0118416715318335e-01, 3.0356969932406813e-01, 5.0600686311669596e-01, 7.0853020661847821e-01, 9.1117446928904511e-01, 1.1139746602463279e+00, 1.3169661383169375e+00, 1.5201846943942978e+00, 1.7236666366787170e+00, 1.9274488794124773e+00, 2.1315690357710211e+00, 2.3360655156294796e+00, 2.5409776289935784e+00, 2.7463456959669994e+00, 2.9522111642257620e+00, 3.1586167350865688e+00, 3.3656064993935964e+00, 3.5732260846105883e+00, 3.7815228146971922e+00, 3.9905458845758908e+00, 4.2003465512658975e+00, 4.4109783440817232e+00, 4.6224972966778903e+00, 4.8349622041811422e+00, 5.0484349092048060e+00, 5.2629806212085075e+00, 5.4786682744780215e+00, 5.6955709309901366e+00, 5.9137662356417078e+00, 6.1333369328198826e+00, 6.3543714551491233e+00, 6.5769645975720454e+00, 6.8012182928404501e+00, 7.0272425081913878e+00, 7.2551562877054536e+00, 7.4850889709254078e+00, 7.7171816262142663e+00, 7.9515887476984757e+00, 8.1884802783862387e+00, 8.4280440404817565e+00, 8.6704886789370494e+00, 8.9160472587078665e+00, 9.1649817042418142e+00, 9.4175883379130294e+00, 9.6742048725828571e+00, 9.9352193584733488e+00, 1.0201081802811933e+01, 1.0472319517421079e+01, 1.0749557783474378e+01, 1.1033548296890791e+01, 1.1325209342106415e+01, 1.1625684271126064e+01, 1.1936429761298314e+01, 1.2259355010417195e+01, 1.2597053652892484e+01, 1.2953218388266750e+01, 1.3333455576348189e+01, 1.3747114438757134e+01, 1.4212342685181815e+01, 1.4776657672798869e+01}, {-1.4841989245812462e+01, -1.4278493956537387e+01, -1.3813960337214354e+01, -1.3400934026297357e+01, -1.3021291138101008e+01, -1.2665694635824183e+01, -1.2328545429882384e+01, -1.2006155595899877e+01, -1.1695934851542777e+01, -1.1395976471020912e+01, -1.1104825671283981e+01, -1.0821340597636343e+01, -1.0544604180098764e+01, -1.0273865729711682e+01, -1.0008500816363464e+01, -9.7479828598297100e+00, -9.4918624914245004e+00, -9.2397522259904878e+00, -8.9913148570644346e+00, -8.7462545214071792e+00, -8.5043097153654035e+00, -8.2652477635213177e+00, -8.0288603849063733e+00, -7.7949601003933706e+00, -7.5633772929797445e+00, -7.3339577806748517e+00, -7.1065607960848611e+00, -6.8810572917778128e+00, -6.6573285089186554e+00, -6.4352647603911377e+00, -6.2147643899767431e+00, -5.9957328770520153e+00, -5.7780820623389184e+00, -5.5617294749593142e+00, -5.3465977447386317e+00, -5.1326140866195260e+00, -4.9197098463649933e+00, -4.7078200985868248e+00, -4.4968832896314073e+00, -4.2868409190677941e+00, -4.0776372545120747e+00, -3.8692190753327944e+00, -3.6615354414501788e+00, -3.4545374839947667e+00, -3.2481782150506633e+00, -3.0424123540922232e+00, -2.8371961690442937e+00, -2.6324873301662031e+00, -2.4282447751872818e+00, -2.2244285843140195e+00, -2.0209998638917077e+00, -1.8179206376413908e+00, -1.6151537445099000e+00, -1.4126627422698670e+00, -1.2104118160904516e+00, -1.0083656913702024e+00, -8.0648955018269064e-01, -6.0474895073475177e-01, -4.0310974927746679e-01, -2.0153802394231832e-01, -0.0000000000000000e+00, 2.0153802394231832e-01, 4.0310974927746679e-01, 6.0474895073475177e-01, 8.0648955018269064e-01, 1.0083656913702024e+00, 1.2104118160904516e+00, 1.4126627422698670e+00, 1.6151537445099000e+00, 1.8179206376413908e+00, 2.0209998638917077e+00, 2.2244285843140195e+00, 2.4282447751872818e+00, 2.6324873301662031e+00, 2.8371961690442937e+00, 3.0424123540922232e+00, 3.2481782150506633e+00, 3.4545374839947667e+00, 3.6615354414501788e+00, 3.8692190753327944e+00, 4.0776372545120747e+00, 4.2868409190677941e+00, 4.4968832896314073e+00, 4.7078200985868248e+00, 4.9197098463649933e+00, 5.1326140866195260e+00, 5.3465977447386317e+00, 5.5617294749593142e+00, 5.7780820623389184e+00, 5.9957328770520153e+00, 6.2147643899767431e+00, 6.4352647603911377e+00, 6.6573285089186554e+00, 6.8810572917778128e+00, 7.1065607960848611e+00, 7.3339577806748517e+00, 7.5633772929797445e+00, 7.7949601003933706e+00, 8.0288603849063733e+00, 8.2652477635213177e+00, 8.5043097153654035e+00, 8.7462545214071792e+00, 8.9913148570644346e+00, 9.2397522259904878e+00, 9.4918624914245004e+00, 9.7479828598297100e+00, 1.0008500816363464e+01, 1.0273865729711682e+01, 1.0544604180098764e+01, 1.0821340597636343e+01, 1.1104825671283981e+01, 1.1395976471020912e+01, 1.1695934851542777e+01, 1.2006155595899877e+01, 1.2328545429882384e+01, 1.2665694635824183e+01, 1.3021291138101008e+01, 1.3400934026297357e+01, 1.3813960337214354e+01, 1.4278493956537387e+01, 1.4841989245812462e+01}, {-1.4907046657816622e+01, -1.4344362927004781e+01, -1.3880516899476401e+01, -1.3468116622389784e+01, -1.3089061813006204e+01, -1.2734027506319505e+01, -1.2397421815284703e+01, -1.2075561545881943e+01, -1.1765859735997486e+01, -1.1466412107936478e+01, -1.1175765754204676e+01, -1.0892780302181299e+01, -1.0616539883571752e+01, -1.0346294805375646e+01, -1.0081421478842227e+01, -9.8213940466086171e+00, -9.5657637705148062e+00, -9.3141437229916662e+00, -9.0661971968977273e+00, -8.8216287813440992e+00, -8.5801773868921547e+00, -8.3416107212171422e+00, -8.1057208609652847e+00, -7.8723206637443432e+00, -7.6412408321991903e+00, -7.4123274900628546e+00, -7.1854401644106494e+00, -6.9604500933022759e+00, -6.7372387963808658e+00, -6.5156968597076492e+00, -6.2957228964512764e+00, -6.0772226529322166e+00, -5.8601082355882221e+00, -5.6442974391377119e+00, -5.4297131599071493e+00, -5.2162828812008781e+00, -5.0039382199076590e+00, -4.7926145253924428e+00, -4.5822505232162971e+00, -4.3727879974390058e+00, -4.1641715062468725e+00, -3.9563481264582303e+00, -3.7492672231264832e+00, -3.5428802410129703e+00, -3.3371405151612126e+00, -3.1320030981875178e+00, -2.9274246022241841e+00, -2.7233630537216094e+00, -2.5197777595433375e+00, -2.3166291829805914e+00, -2.1138788284758951e+00, -1.9114891339837408e+00, -1.7094233700136701e+00, -1.5076455445008548e+00, -1.3061203127337706e+00, -1.1048128916400251e+00, -9.0368897779154544e-01, -7.0271466854059361e-01, -5.0185638573956481e-01, -3.0108080153124556e-01, -1.0035476572283220e-01, 1.0035476572283220e-01, 3.0108080153124556e-01, 5.0185638573956481e-01, 7.0271466854059361e-01, 9.0368897779154544e-01, 1.1048128916400251e+00, 1.3061203127337706e+00, 1.5076455445008548e+00, 1.7094233700136701e+00, 1.9114891339837408e+00, 2.1138788284758951e+00, 2.3166291829805914e+00, 2.5197777595433375e+00, 2.7233630537216094e+00, 2.9274246022241841e+00, 3.1320030981875178e+00, 3.3371405151612126e+00, 3.5428802410129703e+00, 3.7492672231264832e+00, 3.9563481264582303e+00, 4.1641715062468725e+00, 4.3727879974390058e+00, 4.5822505232162971e+00, 4.7926145253924428e+00, 5.0039382199076590e+00, 5.2162828812008781e+00, 5.4297131599071493e+00, 5.6442974391377119e+00, 5.8601082355882221e+00, 6.0772226529322166e+00, 6.2957228964512764e+00, 6.5156968597076492e+00, 6.7372387963808658e+00, 6.9604500933022759e+00, 7.1854401644106494e+00, 7.4123274900628546e+00, 7.6412408321991903e+00, 7.8723206637443432e+00, 8.1057208609652847e+00, 8.3416107212171422e+00, 8.5801773868921547e+00, 8.8216287813440992e+00, 9.0661971968977273e+00, 9.3141437229916662e+00, 9.5657637705148062e+00, 9.8213940466086171e+00, 1.0081421478842227e+01, 1.0346294805375646e+01, 1.0616539883571752e+01, 1.0892780302181299e+01, 1.1175765754204676e+01, 1.1466412107936478e+01, 1.1765859735997486e+01, 1.2075561545881943e+01, 1.2397421815284703e+01, 1.2734027506319505e+01, 1.3089061813006204e+01, 1.3468116622389784e+01, 1.3880516899476401e+01, 1.4344362927004781e+01, 1.4907046657816622e+01}, {-1.4971833315919479e+01, -1.4409953151712163e+01, -1.3946787810773682e+01, -1.3535007172173161e+01, -1.3156534338879860e+01, -1.2802056306622088e+01, -1.2465988324400744e+01, -1.2144651884544359e+01, -1.1835463313889939e+01, -1.1536520759384242e+01, -1.1246373170717687e+01, -1.0963881642425228e+01, -1.0688131495402112e+01, -1.0418374021858449e+01, -1.0153986464937166e+01, -9.8944436816224322e+00, -9.6392975564791730e+00, -9.3881617122605014e+00, -9.1406999342794091e+00, -8.8966172574222746e+00, -8.6556530000977201e+00, -8.4175752468453187e+00, -8.1821764257789713e+00, -7.9492697251276718e+00, -7.7186861610617425e+00, -7.4902721568710229e+00, -7.2638875278553732e+00, -7.0394037912138101e+00, -6.8167027385795480e+00, -6.5956752225409012e+00, -6.3762201188154259e+00, -6.1582434336162883e+00, -5.9416575318080138e+00, -5.7263804661537199e+00, -5.5123353916408391e+00, -5.2994500517810534e+00, -5.0876563260932981e+00, -4.8768898298307777e+00, -4.6670895585055892e+00, -4.4581975709748294e+00, -4.2501587058390200e+00, -4.0429203267128022e+00, -3.8364320925946052e+00, -3.6306457501139446e+00, -3.4255149448939752e+00, -3.2209950496501372e+00, -3.0170430069668734e+00, -2.8136171849644747e+00, -2.6106772442959039e+00, -2.4081840151061349e+00, -2.2060993827498390e+00, -2.0043861812019168e+00, -1.8030080932132322e+00, -1.6019295563640745e+00, -1.4011156742530042e+00, -1.2005321321308888e+00, -1.0001451163508825e+00, -7.9992123705629015e-01, -5.9982745357081801e-01, -3.9983100199064880e-01, -1.9989932450580150e-01, -0.0000000000000000e+00, 1.9989932450580150e-01, 3.9983100199064880e-01, 5.9982745357081801e-01, 7.9992123705629015e-01, 1.0001451163508825e+00, 1.2005321321308888e+00, 1.4011156742530042e+00, 1.6019295563640745e+00, 1.8030080932132322e+00, 2.0043861812019168e+00, 2.2060993827498390e+00, 2.4081840151061349e+00, 2.6106772442959039e+00, 2.8136171849644747e+00, 3.0170430069668734e+00, 3.2209950496501372e+00, 3.4255149448939752e+00, 3.6306457501139446e+00, 3.8364320925946052e+00, 4.0429203267128022e+00, 4.2501587058390200e+00, 4.4581975709748294e+00, 4.6670895585055892e+00, 4.8768898298307777e+00, 5.0876563260932981e+00, 5.2994500517810534e+00, 5.5123353916408391e+00, 5.7263804661537199e+00, 5.9416575318080138e+00, 6.1582434336162883e+00, 6.3762201188154259e+00, 6.5956752225409012e+00, 6.8167027385795480e+00, 7.0394037912138101e+00, 7.2638875278553732e+00, 7.4902721568710229e+00, 7.7186861610617425e+00, 7.9492697251276718e+00, 8.1821764257789713e+00, 8.4175752468453187e+00, 8.6556530000977201e+00, 8.8966172574222746e+00, 9.1406999342794091e+00, 9.3881617122605014e+00, 9.6392975564791730e+00, 9.8944436816224322e+00, 1.0153986464937166e+01, 1.0418374021858449e+01, 1.0688131495402112e+01, 1.0963881642425228e+01, 1.1246373170717687e+01, 1.1536520759384242e+01, 1.1835463313889939e+01, 1.2144651884544359e+01, 1.2465988324400744e+01, 1.2802056306622088e+01, 1.3156534338879860e+01, 1.3535007172173161e+01, 1.3946787810773682e+01, 1.4409953151712163e+01, 1.4971833315919479e+01}, {-1.5036352557386012e+01, -1.4475268112055591e+01, -1.4012776679134205e+01, -1.3601609402686369e+01, -1.3223712557871778e+01, -1.2869784992006130e+01, -1.2534249024802044e+01, -1.2213430791710801e+01, -1.1904749877820654e+01, -1.1606306831707778e+01, -1.1316652442235313e+01, -1.1034649256479808e+01, -1.0759383772299557e+01, -1.0490108256609062e+01, -1.0226200775202839e+01, -9.9671368911110161e+00, -9.7124691040283810e+00, -9.4618115799659321e+00, -9.2148285900237301e+00, -8.9712256084886892e+00, -8.7307423554516284e+00, -8.4931472862936879e+00, -8.2582331746602566e+00, -8.0258135335048770e+00, -7.7957196866256542e+00, -7.5677983509350675e+00, -7.3419096239550905e+00, -7.1179252959243602e+00, -6.8957274242423345e+00, -6.6752071216509830e+00, -6.4562635198693066e+00, -6.2388028782578386e+00, -6.0227378131410365e+00, -5.8079866281147483e+00, -5.5944727293462684e+00, -5.3821241127798674e+00, -5.1708729124709514e+00, -4.9606550011220074e+00, -4.7514096353844053e+00, -4.5430791396990857e+00, -4.3356086234350091e+00, -4.1289457268926073e+00, -3.9230403924055310e+00, -3.7178446573254824e+00, -3.5133124661335695e+00, -3.3093994993045657e+00, -3.1060630168714907e+00, -2.9032617149079720e+00, -2.7009555933736791e+00, -2.4991058339609178e+00, -2.2976746867440045e+00, -2.0966253645719419e+00, -1.8959219442631448e+00, -1.6955292737615766e+00, -1.4954128844992702e+00, -1.2955389082829973e+00, -1.0958739980844798e+00, -8.9638525216554721e-01, -6.9704014101314027e-01, -4.9780643659506446e-01, -2.9865214347665664e-01, -9.9545431361682174e-02, 9.9545431361682174e-02, 2.9865214347665664e-01, 4.9780643659506446e-01, 6.9704014101314027e-01, 8.9638525216554721e-01, 1.0958739980844798e+00, 1.2955389082829973e+00, 1.4954128844992702e+00, 1.6955292737615766e+00, 1.8959219442631448e+00, 2.0966253645719419e+00, 2.2976746867440045e+00, 2.4991058339609178e+00, 2.7009555933736791e+00, 2.9032617149079720e+00, 3.1060630168714907e+00, 3.3093994993045657e+00, 3.5133124661335695e+00, 3.7178446573254824e+00, 3.9230403924055310e+00, 4.1289457268926073e+00, 4.3356086234350091e+00, 4.5430791396990857e+00, 4.7514096353844053e+00, 4.9606550011220074e+00, 5.1708729124709514e+00, 5.3821241127798674e+00, 5.5944727293462684e+00, 5.8079866281147483e+00, 6.0227378131410365e+00, 6.2388028782578386e+00, 6.4562635198693066e+00, 6.6752071216509830e+00, 6.8957274242423345e+00, 7.1179252959243602e+00, 7.3419096239550905e+00, 7.5677983509350675e+00, 7.7957196866256542e+00, 8.0258135335048770e+00, 8.2582331746602566e+00, 8.4931472862936879e+00, 8.7307423554516284e+00, 8.9712256084886892e+00, 9.2148285900237301e+00, 9.4618115799659321e+00, 9.7124691040283810e+00, 9.9671368911110161e+00, 1.0226200775202839e+01, 1.0490108256609062e+01, 1.0759383772299557e+01, 1.1034649256479808e+01, 1.1316652442235313e+01, 1.1606306831707778e+01, 1.1904749877820654e+01, 1.2213430791710801e+01, 1.2534249024802044e+01, 1.2869784992006130e+01, 1.3223712557871778e+01, 1.3601609402686369e+01, 1.4012776679134205e+01, 1.4475268112055591e+01, 1.5036352557386012e+01}, {-1.5100607651623633e+01, -1.4540311217817694e+01, -1.4078487037622645e+01, -1.3667926962814708e+01, -1.3290600230854309e+01, -1.2937217433362431e+01, -1.2602207896558657e+01, -1.2281902356552338e+01, -1.1973723626537621e+01, -1.1675774634136665e+01, -1.1386607989721913e+01, -1.1105087678592627e+01, -1.0830301363602338e+01, -1.0561502276097833e+01, -1.0298069295499928e+01, -1.0039478682788769e+01, -9.7852835453915379e+00, -9.5350985857059971e+00, -9.2885885541431801e+00, -9.0454593582072000e+00, -8.8054511136991565e+00, -8.5683326410153491e+00, -8.3338970535972763e+00, -8.1019581834327870e+00, -7.8723476562632699e+00, -7.6449124769105978e+00, -7.4195130193460823e+00, -7.1960213409877323e+00, -6.9743197590276207e+00, -6.7542996402499806e+00, -6.5358603661027201e+00, -6.3189084426373174e+00, -6.1033567309754471e+00, -5.8891237786542385e+00, -5.6761332358780425e+00, -5.4643133436064266e+00, -5.2535964827157065e+00, -5.0439187753191463e+00, -4.8352197308201870e+00, -4.6274419304806678e+00, -4.4205307452707974e+00, -4.2144340825751483e+00, -4.0091021579943744e+00, -3.8044872890333408e+00, -3.6005437079246576e+00, -3.3972273912192827e+00, -3.1944959040967831e+00, -2.9923082576177755e+00, -2.7906247773689459e+00, -2.5894069821439305e+00, -2.3886174714670143e+00, -2.1882198209057537e+00, -1.9881784842371524e+00, -1.7884587016329878e+00, -1.5890264131159799e+00, -1.3898481766117783e+00, -1.1908910899840175e+00, -9.9212271649240336e-01, -7.9351101315811157e-01, -5.9502426155773702e-01, -3.9663100059735329e-01, -1.9829996084264417e-01, -0.0000000000000000e+00, 1.9829996084264417e-01, 3.9663100059735329e-01, 5.9502426155773702e-01, 7.9351101315811157e-01, 9.9212271649240336e-01, 1.1908910899840175e+00, 1.3898481766117783e+00, 1.5890264131159799e+00, 1.7884587016329878e+00, 1.9881784842371524e+00, 2.1882198209057537e+00, 2.3886174714670143e+00, 2.5894069821439305e+00, 2.7906247773689459e+00, 2.9923082576177755e+00, 3.1944959040967831e+00, 3.3972273912192827e+00, 3.6005437079246576e+00, 3.8044872890333408e+00, 4.0091021579943744e+00, 4.2144340825751483e+00, 4.4205307452707974e+00, 4.6274419304806678e+00, 4.8352197308201870e+00, 5.0439187753191463e+00, 5.2535964827157065e+00, 5.4643133436064266e+00, 5.6761332358780425e+00, 5.8891237786542385e+00, 6.1033567309754471e+00, 6.3189084426373174e+00, 6.5358603661027201e+00, 6.7542996402499806e+00, 6.9743197590276207e+00, 7.1960213409877323e+00, 7.4195130193460823e+00, 7.6449124769105978e+00, 7.8723476562632699e+00, 8.1019581834327870e+00, 8.3338970535972763e+00, 8.5683326410153491e+00, 8.8054511136991565e+00, 9.0454593582072000e+00, 9.2885885541431801e+00, 9.5350985857059971e+00, 9.7852835453915379e+00, 1.0039478682788769e+01, 1.0298069295499928e+01, 1.0561502276097833e+01, 1.0830301363602338e+01, 1.1105087678592627e+01, 1.1386607989721913e+01, 1.1675774634136665e+01, 1.1973723626537621e+01, 1.2281902356552338e+01, 1.2602207896558657e+01, 1.2937217433362431e+01, 1.3290600230854309e+01, 1.3667926962814708e+01, 1.4078487037622645e+01, 1.4540311217817694e+01, 1.5100607651623633e+01}, {-1.5164601802095889e+01, -1.4605085809208793e+01, -1.4143922346496764e+01, -1.3733963425557441e+01, -1.3357201039800040e+01, -1.3004357419686706e+01, -1.2669868834839699e+01, -1.2350070580302615e+01, -1.2042388667769094e+01, -1.1744928381740326e+01, -1.1456244136772701e+01, -1.1175201342355262e+01, -1.0900888814619361e+01, -1.0632560739297817e+01, -1.0369596800621338e+01, -1.0111473949621464e+01, -9.8577458942500833e+00, -9.6080278666058625e+00, -9.3619850901178872e+00, -9.1193238995071209e+00, -8.8797848004974700e+00, -8.6431369728612566e+00, -8.4091738642920379e+00, -8.1777096203182182e+00, -7.9485761631426497e+00, -7.7216207799931862e+00, -7.4967041157356897e+00, -7.2736984893343362e+00, -7.0524864720372555e+00, -6.8329596788076081e+00, -6.6150177348097277e+00, -6.3985673866027142e+00, -6.1835217337299566e+00, -5.9697995610809267e+00, -5.7573247560732410e+00, -5.5460257976013150e+00, -5.3358353060028794e+00, -5.1266896451402619e+00, -4.9185285691809160e+00, -4.7112949078678819e+00, -4.5049342850546665e+00, -4.2993948660856276e+00, -4.0946271302677770e+00, -3.8905836652304053e+00, -3.6872189804268034e+00, -3.4844893374148405e+00, -3.2823525948738599e+00, -3.0807680665852137e+00, -2.8796963908316315e+00, -2.6790994098635554e+00, -2.4789400582443553e+00, -2.2791822590257231e+00, -2.0797908268232597e+00, -1.8807313769636194e+00, -1.6819702399610155e+00, -1.4834743806546613e+00, -1.2852113214015310e+00, -1.0871490687721614e+00, -8.8925604324227414e-01, -6.9150101141075326e-01, -4.9385302030582290e-01, -2.9628133336672019e-01, -9.8755367708345074e-02, 9.8755367708345074e-02, 2.9628133336672019e-01, 4.9385302030582290e-01, 6.9150101141075326e-01, 8.8925604324227414e-01, 1.0871490687721614e+00, 1.2852113214015310e+00, 1.4834743806546613e+00, 1.6819702399610155e+00, 1.8807313769636194e+00, 2.0797908268232597e+00, 2.2791822590257231e+00, 2.4789400582443553e+00, 2.6790994098635554e+00, 2.8796963908316315e+00, 3.0807680665852137e+00, 3.2823525948738599e+00, 3.4844893374148405e+00, 3.6872189804268034e+00, 3.8905836652304053e+00, 4.0946271302677770e+00, 4.2993948660856276e+00, 4.5049342850546665e+00, 4.7112949078678819e+00, 4.9185285691809160e+00, 5.1266896451402619e+00, 5.3358353060028794e+00, 5.5460257976013150e+00, 5.7573247560732410e+00, 5.9697995610809267e+00, 6.1835217337299566e+00, 6.3985673866027142e+00, 6.6150177348097277e+00, 6.8329596788076081e+00, 7.0524864720372555e+00, 7.2736984893343362e+00, 7.4967041157356897e+00, 7.7216207799931862e+00, 7.9485761631426497e+00, 8.1777096203182182e+00, 8.4091738642920379e+00, 8.6431369728612566e+00, 8.8797848004974700e+00, 9.1193238995071209e+00, 9.3619850901178872e+00, 9.6080278666058625e+00, 9.8577458942500833e+00, 1.0111473949621464e+01, 1.0369596800621338e+01, 1.0632560739297817e+01, 1.0900888814619361e+01, 1.1175201342355262e+01, 1.1456244136772701e+01, 1.1744928381740326e+01, 1.2042388667769094e+01, 1.2350070580302615e+01, 1.2669868834839699e+01, 1.3004357419686706e+01, 1.3357201039800040e+01, 1.3733963425557441e+01, 1.4143922346496764e+01, 1.4605085809208793e+01, 1.5164601802095889e+01}, {-1.5228338148167351e+01, -1.4669595158833971e+01, -1.4209085995284871e+01, -1.3799722290211674e+01, -1.3423518590070948e+01, -1.3071208660474600e+01, -1.2737235652415684e+01, -1.2417939378869717e+01, -1.2110749020947747e+01, -1.1813772198267726e+01, -1.1525565112572695e+01, -1.1244994583785543e+01, -1.0971150569840248e+01, -1.0703288201027481e+01, -1.0440787957772772e+01, -1.0183127473450343e+01, -9.9298610495114250e+00, -9.6806044412474730e+00, -9.4350233389881648e+00, -9.1928244988460293e+00, -8.9537488108565402e+00, -8.7175658087076293e+00, -8.4840692689832480e+00, -8.2530736454457152e+00, -8.0244111514703373e+00, -7.7979293513870109e+00, -7.5734891556083452e+00, -7.3509631392269048e+00, -7.1302341220350698e+00, -6.9111939615465703e+00, -6.6937425208758290e+00, -6.4777867811645358e+00, -6.2632400742737344e+00, -6.0500214161419841e+00, -5.8380549248774187e+00, -5.6272693105464811e+00, -5.4175974259243240e+00, -5.2089758693153980e+00, -5.0013446320386352e+00, -4.7946467843764919e+00, -4.5888281947698371e+00, -4.3838372778464736e+00, -4.1796247675352030e+00, -3.9761435120673356e+00, -3.7733482881250526e+00, -3.5711956317782176e+00, -3.3696436841717392e+00, -3.1686520501953628e+00, -2.9681816685955908e+00, -2.7681946921824054e+00, -2.5686543769473498e+00, -2.3695249790490402e+00, -2.1707716587411507e+00, -1.9723603904195017e+00, -1.7742578780516791e+00, -1.5764314753267801e+00, -1.3788491099261777e+00, -1.1814792113700685e+00, -9.8429064194027271e-01, -7.8725263021825032e-01, -5.9033470680942102e-01, -3.9350664185130130e-01, -1.9673838392423251e-01, -0.0000000000000000e+00, 1.9673838392423251e-01, 3.9350664185130130e-01, 5.9033470680942102e-01, 7.8725263021825032e-01, 9.8429064194027271e-01, 1.1814792113700685e+00, 1.3788491099261777e+00, 1.5764314753267801e+00, 1.7742578780516791e+00, 1.9723603904195017e+00, 2.1707716587411507e+00, 2.3695249790490402e+00, 2.5686543769473498e+00, 2.7681946921824054e+00, 2.9681816685955908e+00, 3.1686520501953628e+00, 3.3696436841717392e+00, 3.5711956317782176e+00, 3.7733482881250526e+00, 3.9761435120673356e+00, 4.1796247675352030e+00, 4.3838372778464736e+00, 4.5888281947698371e+00, 4.7946467843764919e+00, 5.0013446320386352e+00, 5.2089758693153980e+00, 5.4175974259243240e+00, 5.6272693105464811e+00, 5.8380549248774187e+00, 6.0500214161419841e+00, 6.2632400742737344e+00, 6.4777867811645358e+00, 6.6937425208758290e+00, 6.9111939615465703e+00, 7.1302341220350698e+00, 7.3509631392269048e+00, 7.5734891556083452e+00, 7.7979293513870109e+00, 8.0244111514703373e+00, 8.2530736454457152e+00, 8.4840692689832480e+00, 8.7175658087076293e+00, 8.9537488108565402e+00, 9.1928244988460293e+00, 9.4350233389881648e+00, 9.6806044412474730e+00, 9.9298610495114250e+00, 1.0183127473450343e+01, 1.0440787957772772e+01, 1.0703288201027481e+01, 1.0971150569840248e+01, 1.1244994583785543e+01, 1.1525565112572695e+01, 1.1813772198267726e+01, 1.2110749020947747e+01, 1.2417939378869717e+01, 1.2737235652415684e+01, 1.3071208660474600e+01, 1.3423518590070948e+01, 1.3799722290211674e+01, 1.4209085995284871e+01, 1.4669595158833971e+01, 1.5228338148167351e+01}, {-1.5291819766882741e+01, -1.4733842473589300e+01, -1.4273981304787835e+01, -1.3865206984476242e+01, -1.3489556412623140e+01, -1.3137774788027649e+01, -1.2804312082067129e+01, -1.2485512585349447e+01, -1.2178808619831244e+01, -1.1882310118878310e+01, -1.1594575054741449e+01, -1.1314471644289977e+01, -1.1041090976019634e+01, -1.0773689115161440e+01, -1.0511647329914869e+01, -1.0254443928470931e+01, -1.0001633798930122e+01, -9.7528332134391675e+00, -9.5077083232790560e+00, -9.2659663002961761e+00, -9.0273484133947868e+00, -8.7916245448886858e+00, -8.5585887950645070e+00, -8.3280559207901454e+00, -8.0998584215078964e+00, -7.8738441335354343e+00, -7.6498742276810061e+00, -7.4278215299523005e+00, -7.2075691033873337e+00, -6.9890090426447742e+00, -6.7720414432559277e+00, -6.5565735152644828e+00, -6.3425188170017792e+00, -6.1297965894221624e+00, -5.9183311750858119e+00, -5.7080515087680856e+00, -5.4988906689739094e+00, -5.2907854814771786e+00, -5.0836761674893394e+00, -4.8775060302648141e+00, -4.6722211749326386e+00, -4.4677702571485822e+00, -4.2641042568255187e+00, -4.0611762737492727e+00, -3.8589413423442820e+00, -3.6573562632353078e+00, -3.4563794495717373e+00, -3.2559707863506588e+00, -3.0560915012026797e+00, -2.8567040452974051e+00, -2.6577719831894839e+00, -2.4592598905657392e+00, -2.2611332589730622e+00, -2.0633584067085660e+00, -1.8659023951405984e+00, -1.6687329498037236e+00, -1.4718183856744860e+00, -1.2751275360891583e+00, -1.0786296848109087e+00, -8.8229450079298133e-01, -6.8609197521733478e-01, -4.8999236041545891e-01, -2.9396611030029574e-01, -9.7983821955818992e-02, 9.7983821955818992e-02, 2.9396611030029574e-01, 4.8999236041545891e-01, 6.8609197521733478e-01, 8.8229450079298133e-01, 1.0786296848109087e+00, 1.2751275360891583e+00, 1.4718183856744860e+00, 1.6687329498037236e+00, 1.8659023951405984e+00, 2.0633584067085660e+00, 2.2611332589730622e+00, 2.4592598905657392e+00, 2.6577719831894839e+00, 2.8567040452974051e+00, 3.0560915012026797e+00, 3.2559707863506588e+00, 3.4563794495717373e+00, 3.6573562632353078e+00, 3.8589413423442820e+00, 4.0611762737492727e+00, 4.2641042568255187e+00, 4.4677702571485822e+00, 4.6722211749326386e+00, 4.8775060302648141e+00, 5.0836761674893394e+00, 5.2907854814771786e+00, 5.4988906689739094e+00, 5.7080515087680856e+00, 5.9183311750858119e+00, 6.1297965894221624e+00, 6.3425188170017792e+00, 6.5565735152644828e+00, 6.7720414432559277e+00, 6.9890090426447742e+00, 7.2075691033873337e+00, 7.4278215299523005e+00, 7.6498742276810061e+00, 7.8738441335354343e+00, 8.0998584215078964e+00, 8.3280559207901454e+00, 8.5585887950645070e+00, 8.7916245448886858e+00, 9.0273484133947868e+00, 9.2659663002961761e+00, 9.5077083232790560e+00, 9.7528332134391675e+00, 1.0001633798930122e+01, 1.0254443928470931e+01, 1.0511647329914869e+01, 1.0773689115161440e+01, 1.1041090976019634e+01, 1.1314471644289977e+01, 1.1594575054741449e+01, 1.1882310118878310e+01, 1.2178808619831244e+01, 1.2485512585349447e+01, 1.2804312082067129e+01, 1.3137774788027649e+01, 1.3489556412623140e+01, 1.3865206984476242e+01, 1.4273981304787835e+01, 1.4733842473589300e+01, 1.5291819766882741e+01}, {-1.5355049674683126e+01, -1.4797830896490307e+01, -1.4338611529008967e+01, -1.3930420866479178e+01, -1.3555317966130856e+01, -1.3204059359674192e+01, -1.2871101778903627e+01, -1.2552793952444540e+01, -1.2246571315023999e+01, -1.1950546092769182e+01, -1.1663278012068952e+01, -1.1383636673511937e+01, -1.1110714285141645e+01, -1.0843767837715543e+01, -1.0582179378973514e+01, -1.0325427884573593e+01, -1.0073068822584037e+01, -9.8247189758331519e+00, -9.5800449507652310e+00, -9.3387543294632973e+00, -9.1005887544187765e+00, -8.8653184514446028e+00, -8.6327378395084349e+00, -8.4026619736253494e+00, -8.1749236343739895e+00, -7.9493709251260496e+00, -7.7258652721212853e+00, -7.5042797472635216e+00, -7.2844976517401534e+00, -7.0664113121603904e+00, -6.8499210511601492e+00, -6.6349343022359886e+00, -6.4213648445851028e+00, -6.2091321383995863e+00, -5.9981607447217984e+00, -5.7883798168558824e+00, -5.5797226526273649e+00, -5.3721262986220681e+00, -5.1655311990180879e+00, -4.9598808828268046e+00, -4.7551216843394561e+00, -4.5512024923799270e+00, -4.3480745246271999e+00, -4.1456911238198586e+00, -3.9440075731117403e+00, -3.7429809282294269e+00, -3.5425698644023571e+00, -3.3427345363058465e+00, -3.1434364494849998e+00, -2.9446383419204585e+00, -2.7463040745609382e+00, -2.5483985297872240e+00, -2.3508875168916132e+00, -2.1537376837587945e+00, -1.9569164340215148e+00, -1.7603918490392145e+00, -1.5641326141118630e+00, -1.3681079483960505e+00, -1.1722875380371232e+00, -9.7664147207086760e-01, -7.8114018068176028e-01, -5.8575437543280562e-01, -3.9045499110504589e-01, -1.9521312880340755e-01, -0.0000000000000000e+00, 1.9521312880340755e-01, 3.9045499110504589e-01, 5.8575437543280562e-01, 7.8114018068176028e-01, 9.7664147207086760e-01, 1.1722875380371232e+00, 1.3681079483960505e+00, 1.5641326141118630e+00, 1.7603918490392145e+00, 1.9569164340215148e+00, 2.1537376837587945e+00, 2.3508875168916132e+00, 2.5483985297872240e+00, 2.7463040745609382e+00, 2.9446383419204585e+00, 3.1434364494849998e+00, 3.3427345363058465e+00, 3.5425698644023571e+00, 3.7429809282294269e+00, 3.9440075731117403e+00, 4.1456911238198586e+00, 4.3480745246271999e+00, 4.5512024923799270e+00, 4.7551216843394561e+00, 4.9598808828268046e+00, 5.1655311990180879e+00, 5.3721262986220681e+00, 5.5797226526273649e+00, 5.7883798168558824e+00, 5.9981607447217984e+00, 6.2091321383995863e+00, 6.4213648445851028e+00, 6.6349343022359886e+00, 6.8499210511601492e+00, 7.0664113121603904e+00, 7.2844976517401534e+00, 7.5042797472635216e+00, 7.7258652721212853e+00, 7.9493709251260496e+00, 8.1749236343739895e+00, 8.4026619736253494e+00, 8.6327378395084349e+00, 8.8653184514446028e+00, 9.1005887544187765e+00, 9.3387543294632973e+00, 9.5800449507652310e+00, 9.8247189758331519e+00, 1.0073068822584037e+01, 1.0325427884573593e+01, 1.0582179378973514e+01, 1.0843767837715543e+01, 1.1110714285141645e+01, 1.1383636673511937e+01, 1.1663278012068952e+01, 1.1950546092769182e+01, 1.2246571315023999e+01, 1.2552793952444540e+01, 1.2871101778903627e+01, 1.3204059359674192e+01, 1.3555317966130856e+01, 1.3930420866479178e+01, 1.4338611529008967e+01, 1.4797830896490307e+01, 1.5355049674683126e+01}, {-1.5418030829061875e+01, -1.4861563508435680e+01, -1.4402979857014893e+01, -1.3995367226732167e+01, -1.3620806639033354e+01, -1.3270065859909028e+01, -1.2937608322597471e+01, -1.2619787154794016e+01, -1.2314040876404606e+01, -1.2018483985703304e+01, -1.1731677947147649e+01, -1.1452493732070961e+01, -1.1180024657270208e+01, -1.0913528629812234e+01, -1.0652388468924656e+01, -1.0396083810552501e+01, -1.0144170696212489e+01, -9.8962664133982265e+00, -9.6520380180840490e+00, -9.4111934972461668e+00, -9.1734748618357518e+00, -8.9386526761940264e+00, -8.7065216731065060e+00, -8.4768972009392183e+00, -8.2496123166430966e+00, -8.0245153858819371e+00, -7.8014680855407574e+00, -7.5803437285851887e+00, -7.3610258494479153e+00, -7.1434070016947420e+00, -6.9273877299634155e+00, -6.7128756859735788e+00, -6.4997848644138259e+00, -6.2880349391774812e+00, -6.0775506840731746e+00, -5.8682614650210780e+00, -5.6601007930399492e+00, -5.4530059291673494e+00, -5.2469175339362204e+00, -5.0417793552319132e+00, -4.8375379493332744e+00, -4.6341424307446326e+00, -4.4315442470876985e+00, -4.2296969758707617e+00, -4.0285561404088908e+00, -3.8280790425501139e+00, -3.6282246101824178e+00, -3.4289532577657682e+00, -3.2302267583609394e+00, -3.0320081258198956e+00, -2.8342615059664689e+00, -2.6369520757359015e+00, -2.4400459493612159e+00, -2.2435100907965948e+00, -2.0473122316554950e+00, -1.8514207940163270e+00, -1.6558048175129170e+00, -1.4604338901821434e+00, -1.2652780825883267e+00, -1.0703078847841583e+00, -8.7549414570205153e-01, -6.8080801459844631e-01, -4.8622088419741660e-01, -2.9170433519935240e-01, -9.7230081835906187e-02, 9.7230081835906187e-02, 2.9170433519935240e-01, 4.8622088419741660e-01, 6.8080801459844631e-01, 8.7549414570205153e-01, 1.0703078847841583e+00, 1.2652780825883267e+00, 1.4604338901821434e+00, 1.6558048175129170e+00, 1.8514207940163270e+00, 2.0473122316554950e+00, 2.2435100907965948e+00, 2.4400459493612159e+00, 2.6369520757359015e+00, 2.8342615059664689e+00, 3.0320081258198956e+00, 3.2302267583609394e+00, 3.4289532577657682e+00, 3.6282246101824178e+00, 3.8280790425501139e+00, 4.0285561404088908e+00, 4.2296969758707617e+00, 4.4315442470876985e+00, 4.6341424307446326e+00, 4.8375379493332744e+00, 5.0417793552319132e+00, 5.2469175339362204e+00, 5.4530059291673494e+00, 5.6601007930399492e+00, 5.8682614650210780e+00, 6.0775506840731746e+00, 6.2880349391774812e+00, 6.4997848644138259e+00, 6.7128756859735788e+00, 6.9273877299634155e+00, 7.1434070016947420e+00, 7.3610258494479153e+00, 7.5803437285851887e+00, 7.8014680855407574e+00, 8.0245153858819371e+00, 8.2496123166430966e+00, 8.4768972009392183e+00, 8.7065216731065060e+00, 8.9386526761940264e+00, 9.1734748618357518e+00, 9.4111934972461668e+00, 9.6520380180840490e+00, 9.8962664133982265e+00, 1.0144170696212489e+01, 1.0396083810552501e+01, 1.0652388468924656e+01, 1.0913528629812234e+01, 1.1180024657270208e+01, 1.1452493732070961e+01, 1.1731677947147649e+01, 1.2018483985703304e+01, 1.2314040876404606e+01, 1.2619787154794016e+01, 1.2937608322597471e+01, 1.3270065859909028e+01, 1.3620806639033354e+01, 1.3995367226732167e+01, 1.4402979857014893e+01, 1.4861563508435680e+01, 1.5418030829061875e+01}, {-1.5480766130162912e+01, -1.4925043329908892e+01, -1.4467089414730456e+01, -1.4060049290015051e+01, -1.3686025751508065e+01, -1.3335797702455430e+01, -1.3003835219535608e+01, -1.2686495791216792e+01, -1.2381220995463224e+01, -1.2086127582443233e+01, -1.1799778738905447e+01, -1.1521046794198202e+01, -1.1249026163290472e+01, -1.0982975660531801e+01, -1.0722278868759513e+01, -1.0466416077189237e+01, -1.0214943894423017e+01, -9.9674801067548007e+00, -9.7236922142042346e+00, -9.4832886034446808e+00, -9.2460116489073236e+00, -9.0116322486398488e+00, -8.7799454445339524e+00, -8.5507668736650881e+00, -8.3239298647512676e+00, -8.0992830411501870e+00, -7.8766883257751701e+00, -7.6560192679949264e+00, -7.4371596307659544e+00, -7.2200021898070377e+00, -7.0044477068537327e+00, -6.7904040468269269e+00, -6.5777854147500525e+00, -6.3665116929098069e+00, -6.1565078624054426e+00, -5.9477034961131627e+00, -5.7400323123838195e+00, -5.5334317806272333e+00, -5.3278427714156580e+00, -5.1232092449384545e+00, -4.9194779726184912e+00, -4.7165982875032402e+00, -4.5145218597049430e+00, -4.3132024937121241e+00, -4.1125959448506144e+00, -3.9126597525531843e+00, -3.7133530884165373e+00, -3.5146366172935721e+00, -3.3164723698963634e+00, -3.1188236255781381e+00, -2.9216548041266144e+00, -2.7249313655408702e+00, -2.5286197168834539e+00, -2.3326871254017765e+00, -2.1371016372005704e+00, -1.9418320008225314e+00, -1.7468475951589244e+00, -1.5521183611674445e+00, -1.3576147369221905e+00, -1.1633075955612597e+00, -9.6916818573207730e-01, -7.7516807416380029e-01, -5.8127909002062172e-01, -3.8747327070995596e-01, -1.9372280883577261e-01, -0.0000000000000000e+00, 1.9372280883577261e-01, 3.8747327070995596e-01, 5.8127909002062172e-01, 7.7516807416380029e-01, 9.6916818573207730e-01, 1.1633075955612597e+00, 1.3576147369221905e+00, 1.5521183611674445e+00, 1.7468475951589244e+00, 1.9418320008225314e+00, 2.1371016372005704e+00, 2.3326871254017765e+00, 2.5286197168834539e+00, 2.7249313655408702e+00, 2.9216548041266144e+00, 3.1188236255781381e+00, 3.3164723698963634e+00, 3.5146366172935721e+00, 3.7133530884165373e+00, 3.9126597525531843e+00, 4.1125959448506144e+00, 4.3132024937121241e+00, 4.5145218597049430e+00, 4.7165982875032402e+00, 4.9194779726184912e+00, 5.1232092449384545e+00, 5.3278427714156580e+00, 5.5334317806272333e+00, 5.7400323123838195e+00, 5.9477034961131627e+00, 6.1565078624054426e+00, 6.3665116929098069e+00, 6.5777854147500525e+00, 6.7904040468269269e+00, 7.0044477068537327e+00, 7.2200021898070377e+00, 7.4371596307659544e+00, 7.6560192679949264e+00, 7.8766883257751701e+00, 8.0992830411501870e+00, 8.3239298647512676e+00, 8.5507668736650881e+00, 8.7799454445339524e+00, 9.0116322486398488e+00, 9.2460116489073236e+00, 9.4832886034446808e+00, 9.7236922142042346e+00, 9.9674801067548007e+00, 1.0214943894423017e+01, 1.0466416077189237e+01, 1.0722278868759513e+01, 1.0982975660531801e+01, 1.1249026163290472e+01, 1.1521046794198202e+01, 1.1799778738905447e+01, 1.2086127582443233e+01, 1.2381220995463224e+01, 1.2686495791216792e+01, 1.3003835219535608e+01, 1.3335797702455430e+01, 1.3686025751508065e+01, 1.4060049290015051e+01, 1.4467089414730456e+01, 1.4925043329908892e+01, 1.5480766130162912e+01}, {-1.5543258422323774e+01, -1.4988273322620483e+01, -1.4530943266670407e+01, -1.4124470217193569e+01, -1.3750978557373212e+01, -1.3401258232252896e+01, -1.3069785904893536e+01, -1.2752923386873304e+01, -1.2448115287552957e+01, -1.2153480589094658e+01, -1.1867584185044096e+01, -1.1589299750272769e+01, -1.1317722787546410e+01, -1.1052113009654860e+01, -1.0791854755335825e+01, -1.0536428960217005e+01, -1.0285392793773033e+01, -1.0038364535378761e+01, -9.7950121237570809e+00, -9.5550443402238834e+00, -9.3182039178520490e+00, -9.0842620837165757e+00, -8.8530141842483925e+00, -8.6242761407386386e+00, -8.3978815492187184e+00, -8.1736792862980483e+00, -7.9515315164625289e+00, -7.7313120209923101e+00, -7.5129047868198517e+00, -7.2962028071941081e+00, -7.0811070562331242e+00, -6.8675256072344579e+00, -6.6553728706063735e+00, -6.4445689319376820e+00, -6.2350389743700507e+00, -6.0267127723148342e+00, -5.8195242458455034e+00, -5.6134110669298432e+00, -5.4083143101435791e+00, -5.2041781417053947e+00, -5.0009495416506535e+00, -4.7985780547627241e+00, -4.5970155665415948e+00, -4.3962161010367922e+00, -4.1961356378270693e+00, -3.9967319458099735e+00, -3.7979644317837824e+00, -3.5997940020732910e+00, -3.4021829356783408e+00, -3.2050947676167678e+00, -3.0084941812975128e+00, -2.8123469088994537e+00, -2.6166196388511782e+00, -2.4212799296093106e+00, -2.2262961290209549e+00, -2.0316372986313107e+00, -1.8372731423624578e+00, -1.6431739390450815e+00, -1.4493104783328268e+00, -1.2556539995700138e+00, -1.0621761332184900e+00, -8.6884884447915023e-01, -6.7564437876870465e-01, -4.8253520873311562e-01, -2.8949398249614278e-01, -9.6493472854955881e-02, 9.6493472854955881e-02, 2.8949398249614278e-01, 4.8253520873311562e-01, 6.7564437876870465e-01, 8.6884884447915023e-01, 1.0621761332184900e+00, 1.2556539995700138e+00, 1.4493104783328268e+00, 1.6431739390450815e+00, 1.8372731423624578e+00, 2.0316372986313107e+00, 2.2262961290209549e+00, 2.4212799296093106e+00, 2.6166196388511782e+00, 2.8123469088994537e+00, 3.0084941812975128e+00, 3.2050947676167678e+00, 3.4021829356783408e+00, 3.5997940020732910e+00, 3.7979644317837824e+00, 3.9967319458099735e+00, 4.1961356378270693e+00, 4.3962161010367922e+00, 4.5970155665415948e+00, 4.7985780547627241e+00, 5.0009495416506535e+00, 5.2041781417053947e+00, 5.4083143101435791e+00, 5.6134110669298432e+00, 5.8195242458455034e+00, 6.0267127723148342e+00, 6.2350389743700507e+00, 6.4445689319376820e+00, 6.6553728706063735e+00, 6.8675256072344579e+00, 7.0811070562331242e+00, 7.2962028071941081e+00, 7.5129047868198517e+00, 7.7313120209923101e+00, 7.9515315164625289e+00, 8.1736792862980483e+00, 8.3978815492187184e+00, 8.6242761407386386e+00, 8.8530141842483925e+00, 9.0842620837165757e+00, 9.3182039178520490e+00, 9.5550443402238834e+00, 9.7950121237570809e+00, 1.0038364535378761e+01, 1.0285392793773033e+01, 1.0536428960217005e+01, 1.0791854755335825e+01, 1.1052113009654860e+01, 1.1317722787546410e+01, 1.1589299750272769e+01, 1.1867584185044096e+01, 1.2153480589094658e+01, 1.2448115287552957e+01, 1.2752923386873304e+01, 1.3069785904893536e+01, 1.3401258232252896e+01, 1.3750978557373212e+01, 1.4124470217193569e+01, 1.4530943266670407e+01, 1.4988273322620483e+01, 1.5543258422323774e+01}, {-1.5605510495565703e+01, -1.5051256391093448e+01, -1.4594544417610667e+01, -1.4188633106973045e+01, -1.3815668245922964e+01, -1.3466450727373902e+01, -1.3135463744634585e+01, -1.2819073395348772e+01, -1.2514727294059055e+01, -1.2220546635363748e+01, -1.1935098004387349e+01, -1.1657256409263454e+01, -1.1386118430379335e+01, -1.1120944670301025e+01, -1.0861120216120376e+01, -1.0606126643170979e+01, -1.0355521675732227e+01, -1.0108924080680463e+01, -9.8660022302368411e+00, -9.6264652954408270e+00, -9.3900563633043106e+00, -9.1565469853869601e+00, -8.9257328082304568e+00, -8.6974300329890397e+00, -8.4714725186984587e+00, -8.2477093909264614e+00, -8.0260030514294165e+00, -7.8062275090663409e+00, -7.5882669703629624e+00, -7.3720146416474837e+00, -7.1573717048843459e+00, -6.9442464371104355e+00, -6.7325534493647661e+00, -6.5222130256523068e+00, -6.3131505461243611e+00, -6.1052959815328816e+00, -5.8985834483025466e+00, -5.6929508153954593e+00, -5.4883393556191784e+00, -5.2846934352257779e+00, -5.0819602366259380e+00, -4.8800895098428096e+00, -4.6790333489905045e+00, -4.4787459906088296e+00, -4.2791836311409464e+00, -4.0803042612209337e+00, -3.8820675147573152e+00, -3.6844345310674940e+00, -3.4873678285452550e+00, -3.2908311885362425e+00, -3.0947895482603323e+00, -2.8992089017596818e+00, -2.7040562079709125e+00, -2.5092993051224148e+00, -2.3149068307458065e+00, -2.1208481466662792e+00, -1.9270932684016822e+00, -1.7336127984562590e+00, -1.5403778630431328e+00, -1.3473600518110582e+00, -1.1545313601863669e+00, -9.6186413397127435e-01, -7.6933101586525243e-01, -5.7690489359762542e-01, -3.8455884937721463e-01, -1.9226611037913860e-01, -0.0000000000000000e+00, 1.9226611037913860e-01, 3.8455884937721463e-01, 5.7690489359762542e-01, 7.6933101586525243e-01, 9.6186413397127435e-01, 1.1545313601863669e+00, 1.3473600518110582e+00, 1.5403778630431328e+00, 1.7336127984562590e+00, 1.9270932684016822e+00, 2.1208481466662792e+00, 2.3149068307458065e+00, 2.5092993051224148e+00, 2.7040562079709125e+00, 2.8992089017596818e+00, 3.0947895482603323e+00, 3.2908311885362425e+00, 3.4873678285452550e+00, 3.6844345310674940e+00, 3.8820675147573152e+00, 4.0803042612209337e+00, 4.2791836311409464e+00, 4.4787459906088296e+00, 4.6790333489905045e+00, 4.8800895098428096e+00, 5.0819602366259380e+00, 5.2846934352257779e+00, 5.4883393556191784e+00, 5.6929508153954593e+00, 5.8985834483025466e+00, 6.1052959815328816e+00, 6.3131505461243611e+00, 6.5222130256523068e+00, 6.7325534493647661e+00, 6.9442464371104355e+00, 7.1573717048843459e+00, 7.3720146416474837e+00, 7.5882669703629624e+00, 7.8062275090663409e+00, 8.0260030514294165e+00, 8.2477093909264614e+00, 8.4714725186984587e+00, 8.6974300329890397e+00, 8.9257328082304568e+00, 9.1565469853869601e+00, 9.3900563633043106e+00, 9.6264652954408270e+00, 9.8660022302368411e+00, 1.0108924080680463e+01, 1.0355521675732227e+01, 1.0606126643170979e+01, 1.0861120216120376e+01, 1.1120944670301025e+01, 1.1386118430379335e+01, 1.1657256409263454e+01, 1.1935098004387349e+01, 1.2220546635363748e+01, 1.2514727294059055e+01, 1.2819073395348772e+01, 1.3135463744634585e+01, 1.3466450727373902e+01, 1.3815668245922964e+01, 1.4188633106973045e+01, 1.4594544417610667e+01, 1.5051256391093448e+01, 1.5605510495565703e+01}, {-1.5667525087033042e+01, -1.5113995384194148e+01, -1.4657895814201638e+01, -1.4252540997590891e+01, -1.3880097943698006e+01, -1.3531378400872688e+01, -1.3200872037437804e+01, -1.2884949200661589e+01, -1.2581060484489544e+01, -1.2287329276732219e+01, -1.2002323839142806e+01, -1.1724920501080165e+01, -1.1454216910571811e+01, -1.1189474551468571e+01, -1.0930079251827893e+01, -1.0675513220130126e+01, -1.0425334729531320e+01, -1.0179163028964693e+01, -9.9366669190764370e+00, -9.6975559558409401e+00, -9.4615735756363968e+00, -9.2284916500953180e+00, -8.9981061215741249e+00, -8.7702334668725097e+00, -8.5447078038596302e+00, -8.3213785029101519e+00, -8.1001081988952368e+00, -7.8807711240717229e+00, -7.6632517003331104e+00, -7.4474433427993905e+00, -7.2332474369156490e+00, -7.0205724589985739e+00, -6.8093332161497848e+00, -6.5994501860991619e+00, -6.3908489411790317e+00, -6.1834596435017497e+00, -5.9772166006971021e+00, -5.7720578733949548e+00, -5.5679249271127809e+00, -5.3647623224033971e+00, -5.1625174380934791e+00, -4.9611402232433406e+00, -4.7605829741178525e+00, -4.5608001330046735e+00, -4.3617481061705252e+00, -4.1633850986262280e+00, -3.9656709636900676e+00, -3.7685670656076877e+00, -3.5720361537138379e+00, -3.3760422468139430e+00, -3.1805505266274205e+00, -2.9855272392745684e+00, -2.7909396039085173e+00, -2.5967557276963822e+00, -2.4029445264418832e+00, -2.2094756502175628e+00, -2.0163194134400269e+00, -1.8234467288779213e+00, -1.6308290451307998e+00, -1.4384382871587706e+00, -1.2462467994785644e+00, -1.0542272916723083e+00, -8.6235278588129705e-01, -6.7059656597901129e-01, -4.7893212813590247e-01, -2.8733313250340886e-01, -9.5773355756546857e-02, 9.5773355756546857e-02, 2.8733313250340886e-01, 4.7893212813590247e-01, 6.7059656597901129e-01, 8.6235278588129705e-01, 1.0542272916723083e+00, 1.2462467994785644e+00, 1.4384382871587706e+00, 1.6308290451307998e+00, 1.8234467288779213e+00, 2.0163194134400269e+00, 2.2094756502175628e+00, 2.4029445264418832e+00, 2.5967557276963822e+00, 2.7909396039085173e+00, 2.9855272392745684e+00, 3.1805505266274205e+00, 3.3760422468139430e+00, 3.5720361537138379e+00, 3.7685670656076877e+00, 3.9656709636900676e+00, 4.1633850986262280e+00, 4.3617481061705252e+00, 4.5608001330046735e+00, 4.7605829741178525e+00, 4.9611402232433406e+00, 5.1625174380934791e+00, 5.3647623224033971e+00, 5.5679249271127809e+00, 5.7720578733949548e+00, 5.9772166006971021e+00, 6.1834596435017497e+00, 6.3908489411790317e+00, 6.5994501860991619e+00, 6.8093332161497848e+00, 7.0205724589985739e+00, 7.2332474369156490e+00, 7.4474433427993905e+00, 7.6632517003331104e+00, 7.8807711240717229e+00, 8.1001081988952368e+00, 8.3213785029101519e+00, 8.5447078038596302e+00, 8.7702334668725097e+00, 8.9981061215741249e+00, 9.2284916500953180e+00, 9.4615735756363968e+00, 9.6975559558409401e+00, 9.9366669190764370e+00, 1.0179163028964693e+01, 1.0425334729531320e+01, 1.0675513220130126e+01, 1.0930079251827893e+01, 1.1189474551468571e+01, 1.1454216910571811e+01, 1.1724920501080165e+01, 1.2002323839142806e+01, 1.2287329276732219e+01, 1.2581060484489544e+01, 1.2884949200661589e+01, 1.3200872037437804e+01, 1.3531378400872688e+01, 1.3880097943698006e+01, 1.4252540997590891e+01, 1.4657895814201638e+01, 1.5113995384194148e+01, 1.5667525087033042e+01}, {-1.5729304882383959e+01, -1.5176493096610994e+01, -1.4721000346526051e+01, -1.4316196868450396e+01, -1.3944270716194302e+01, -1.3596044402569063e+01, -1.3266014016557564e+01, -1.2950554119200040e+01, -1.2647118258490758e+01, -1.2353831996553668e+01, -1.2069265257081389e+01, -1.1792295678839055e+01, -1.1522021967701262e+01, -1.1257706480479557e+01, -1.0998735778960949e+01, -1.0744592698355470e+01, -1.0494836054902457e+01, -1.0249085574277188e+01, -1.0007010480604432e+01, -9.7683207101299594e+00, -9.5327600441503151e+00, -9.3001006700843707e+00, -9.0701388219340853e+00, -8.8426912480559938e+00, -8.6175923211137029e+00, -8.3946916522729023e+00, -8.1738521055035420e+00, -7.9549481324236444e+00, -7.7378643662186803e+00, -7.5224944266685263e+00, -7.3087398984951246e+00, -7.0965094530044173e+00, -6.8857180889690319e+00, -6.6762864733372753e+00, -6.4681403659874999e+00, -6.2612101156154036e+00, -6.0554302161231597e+00, -5.8507389147062092e+00, -5.6470778643062038e+00, -5.4443918142929100e+00, -5.2426283342121209e+00, -5.0417375662357022e+00, -4.8416720026085907e+00, -4.6423862849333188e+00, -4.4438370225867869e+00, -4.2459826279436079e+00, -4.0487831663989748e+00, -3.8522002194524045e+00, -3.6561967593406961e+00, -3.4607370339009882e+00, -3.2657864605087177e+00, -3.0713115280751384e+00, -2.8772797062087854e+00, -2.6836593607479262e+00, -2.4904196749593304e+00, -2.2975305757745934e+00, -2.1049626645007851e+00, -1.9126871514986146e+00, -1.7206757943700177e+00, -1.5289008392390442e+00, -1.3373349647460135e+00, -1.1459512284058875e+00, -9.5472301500823675e-01, -7.6362398675858623e-01, -5.7262803487972669e-01, -3.8170923240711668e-01, -1.9084178792504236e-01, -0.0000000000000000e+00, 1.9084178792504236e-01, 3.8170923240711668e-01, 5.7262803487972669e-01, 7.6362398675858623e-01, 9.5472301500823675e-01, 1.1459512284058875e+00, 1.3373349647460135e+00, 1.5289008392390442e+00, 1.7206757943700177e+00, 1.9126871514986146e+00, 2.1049626645007851e+00, 2.2975305757745934e+00, 2.4904196749593304e+00, 2.6836593607479262e+00, 2.8772797062087854e+00, 3.0713115280751384e+00, 3.2657864605087177e+00, 3.4607370339009882e+00, 3.6561967593406961e+00, 3.8522002194524045e+00, 4.0487831663989748e+00, 4.2459826279436079e+00, 4.4438370225867869e+00, 4.6423862849333188e+00, 4.8416720026085907e+00, 5.0417375662357022e+00, 5.2426283342121209e+00, 5.4443918142929100e+00, 5.6470778643062038e+00, 5.8507389147062092e+00, 6.0554302161231597e+00, 6.2612101156154036e+00, 6.4681403659874999e+00, 6.6762864733372753e+00, 6.8857180889690319e+00, 7.0965094530044173e+00, 7.3087398984951246e+00, 7.5224944266685263e+00, 7.7378643662186803e+00, 7.9549481324236444e+00, 8.1738521055035420e+00, 8.3946916522729023e+00, 8.6175923211137029e+00, 8.8426912480559938e+00, 9.0701388219340853e+00, 9.3001006700843707e+00, 9.5327600441503151e+00, 9.7683207101299594e+00, 1.0007010480604432e+01, 1.0249085574277188e+01, 1.0494836054902457e+01, 1.0744592698355470e+01, 1.0998735778960949e+01, 1.1257706480479557e+01, 1.1522021967701262e+01, 1.1792295678839055e+01, 1.2069265257081389e+01, 1.2353831996553668e+01, 1.2647118258490758e+01, 1.2950554119200040e+01, 1.3266014016557564e+01, 1.3596044402569063e+01, 1.3944270716194302e+01, 1.4316196868450396e+01, 1.4721000346526051e+01, 1.5176493096610994e+01, 1.5729304882383959e+01}, {-1.5790852517134587e+01, -1.5238752270283085e+01, -1.4783860849603613e+01, -1.4379603641698345e+01, -1.4008189569512616e+01, -1.3660451820769911e+01, -1.3330892851617801e+01, -1.3015891401590464e+01, -1.2712903947791023e+01, -1.2420058208074661e+01, -1.2135925753638015e+01, -1.1859385521045176e+01, -1.1589537264407285e+01, -1.1325644205334678e+01, -1.1067093632255466e+01, -1.0813369000829548e+01, -1.0564029664716180e+01, -1.0318695821142974e+01, -1.0077037112888743e+01, -9.8387638519273803e+00, -9.6036201601455531e+00, -9.3713785365821725e+00, -9.1418355028369902e+00, -8.9148080748582679e+00, -8.6901308761912386e+00, -8.4676537549061486e+00, -8.2472398001890390e+00, -8.0287636791201553e+00, -7.8121102322437741e+00, -7.5971732800158449e+00, -7.3838546023854859e+00, -7.1720630615179752e+00, -6.9617138436331016e+00, -6.7527278005665341e+00, -6.5450308752913493e+00, -6.3385535985021413e+00, -6.1332306456429340e+00, -5.9290004455850367e+00, -5.7258048336320568e+00, -5.5235887427222501e+00, -5.3222999276716845e+00, -5.1218887180998118e+00, -4.9223077963371686e+00, -4.7235119971600676e+00, -4.5254581266508760e+00, -4.3281047978617426e+00, -4.1314122812779592e+00, -3.9353423683453870e+00, -3.7398582465531405e+00, -3.5449243847552383e+00, -3.3505064275787246e+00, -3.1565710979056170e+00, -2.9630861065357892e+00, -2.7700200682405702e+00, -2.5773424235052076e+00, -2.3850233653343853e+00, -2.1930337705606084e+00, -2.0013451351519014e+00, -1.8099295130641593e+00, -1.6187594582257014e+00, -1.4278079692779639e+00, -1.2370484367275345e+00, -1.0464545921915449e+00, -8.5600045944125114e-01, -6.6566030696788747e-01, -4.7540860181095812e-01, -2.8521996440226244e-01, -9.5069124189415724e-02, 9.5069124189415724e-02, 2.8521996440226244e-01, 4.7540860181095812e-01, 6.6566030696788747e-01, 8.5600045944125114e-01, 1.0464545921915449e+00, 1.2370484367275345e+00, 1.4278079692779639e+00, 1.6187594582257014e+00, 1.8099295130641593e+00, 2.0013451351519014e+00, 2.1930337705606084e+00, 2.3850233653343853e+00, 2.5773424235052076e+00, 2.7700200682405702e+00, 2.9630861065357892e+00, 3.1565710979056170e+00, 3.3505064275787246e+00, 3.5449243847552383e+00, 3.7398582465531405e+00, 3.9353423683453870e+00, 4.1314122812779592e+00, 4.3281047978617426e+00, 4.5254581266508760e+00, 4.7235119971600676e+00, 4.9223077963371686e+00, 5.1218887180998118e+00, 5.3222999276716845e+00, 5.5235887427222501e+00, 5.7258048336320568e+00, 5.9290004455850367e+00, 6.1332306456429340e+00, 6.3385535985021413e+00, 6.5450308752913493e+00, 6.7527278005665341e+00, 6.9617138436331016e+00, 7.1720630615179752e+00, 7.3838546023854859e+00, 7.5971732800158449e+00, 7.8121102322437741e+00, 8.0287636791201553e+00, 8.2472398001890390e+00, 8.4676537549061486e+00, 8.6901308761912386e+00, 8.9148080748582679e+00, 9.1418355028369902e+00, 9.3713785365821725e+00, 9.6036201601455531e+00, 9.8387638519273803e+00, 1.0077037112888743e+01, 1.0318695821142974e+01, 1.0564029664716180e+01, 1.0813369000829548e+01, 1.1067093632255466e+01, 1.1325644205334678e+01, 1.1589537264407285e+01, 1.1859385521045176e+01, 1.2135925753638015e+01, 1.2420058208074661e+01, 1.2712903947791023e+01, 1.3015891401590464e+01, 1.3330892851617801e+01, 1.3660451820769911e+01, 1.4008189569512616e+01, 1.4379603641698345e+01, 1.4783860849603613e+01, 1.5238752270283085e+01, 1.5790852517134587e+01}, {-1.5852170577958367e+01, -1.5300775595780827e+01, -1.4846480104844703e+01, -1.4442764183748782e+01, -1.4071857451951351e+01, -1.3724603683931077e+01, -1.3395511650343654e+01, -1.3080964234499790e+01, -1.2778420818075578e+01, -1.2486011256383852e+01, -1.2202308753936913e+01, -1.1926193533696322e+01, -1.1656766388576511e+01, -1.1393291396981837e+01, -1.1135156567035956e+01, -1.0881845968701494e+01, -1.0632919487519736e+01, -1.0387997787201458e+01, -1.0146750924472403e+01, -9.9088895826069283e+00, -9.6741582198685645e+00, -9.4423296428652392e+00, -9.2132006568631315e+00, -8.9865885415552977e+00, -8.7623281675764328e+00, -8.5402696161385645e+00, -8.3202761978883633e+00, -8.1022227916007061e+00, -7.8859944413814738e+00, -7.6714851645199493e+00, -7.4585969322894226e+00, -7.2472387937374041e+00, -7.0373261184664502e+00, -6.8287799390351633e+00, -6.6215263772344395e+00, -6.4154961413560549e+00, -6.2106240838470441e+00, -6.0068488105662023e+00, -5.8041123343284946e+00, -5.6023597666149243e+00, -5.4015390422975438e+00, -5.2016006730266913e+00, -5.0024975255849276e+00, -4.8041846220567344e+00, -4.6066189591163766e+00, -4.4097593441152032e+00, -4.2135662459677485e+00, -4.0180016591039696e+00, -3.8230289789816339e+00, -3.6286128878452084e+00, -3.4347192495813528e+00, -3.2413150126609418e+00, -3.0483681202772592e+00, -2.8558474268927547e+00, -2.6637226204951387e+00, -2.4719641499397405e+00, -2.2805431568207979e+00, -2.0894314113711125e+00, -1.8986012519385917e+00, -1.7080255276306118e+00, -1.5176775437537562e+00, -1.3275310097080575e+00, -1.1375599890219745e+00, -9.4773885123753698e-01, -7.5804222537475319e-01, -5.6844495472091694e-01, -3.7892205270411800e-01, -1.8944865962132065e-01, -0.0000000000000000e+00, 1.8944865962132065e-01, 3.7892205270411800e-01, 5.6844495472091694e-01, 7.5804222537475319e-01, 9.4773885123753698e-01, 1.1375599890219745e+00, 1.3275310097080575e+00, 1.5176775437537562e+00, 1.7080255276306118e+00, 1.8986012519385917e+00, 2.0894314113711125e+00, 2.2805431568207979e+00, 2.4719641499397405e+00, 2.6637226204951387e+00, 2.8558474268927547e+00, 3.0483681202772592e+00, 3.2413150126609418e+00, 3.4347192495813528e+00, 3.6286128878452084e+00, 3.8230289789816339e+00, 4.0180016591039696e+00, 4.2135662459677485e+00, 4.4097593441152032e+00, 4.6066189591163766e+00, 4.8041846220567344e+00, 5.0024975255849276e+00, 5.2016006730266913e+00, 5.4015390422975438e+00, 5.6023597666149243e+00, 5.8041123343284946e+00, 6.0068488105662023e+00, 6.2106240838470441e+00, 6.4154961413560549e+00, 6.6215263772344395e+00, 6.8287799390351633e+00, 7.0373261184664502e+00, 7.2472387937374041e+00, 7.4585969322894226e+00, 7.6714851645199493e+00, 7.8859944413814738e+00, 8.1022227916007061e+00, 8.3202761978883633e+00, 8.5402696161385645e+00, 8.7623281675764328e+00, 8.9865885415552977e+00, 9.2132006568631315e+00, 9.4423296428652392e+00, 9.6741582198685645e+00, 9.9088895826069283e+00, 1.0146750924472403e+01, 1.0387997787201458e+01, 1.0632919487519736e+01, 1.0881845968701494e+01, 1.1135156567035956e+01, 1.1393291396981837e+01, 1.1656766388576511e+01, 1.1926193533696322e+01, 1.2202308753936913e+01, 1.2486011256383852e+01, 1.2778420818075578e+01, 1.3080964234499790e+01, 1.3395511650343654e+01, 1.3724603683931077e+01, 1.4071857451951351e+01, 1.4442764183748782e+01, 1.4846480104844703e+01, 1.5300775595780827e+01, 1.5852170577958367e+01}, {-1.5913261603942480e+01, -1.5362565713640512e+01, -1.4908860841455180e+01, -1.4505681306755122e+01, -1.4135277255544954e+01, -1.3788502962262141e+01, -1.3459873460233181e+01, -1.3145775742375259e+01, -1.2843672070795714e+01, -1.2551694420292197e+01, -1.2268417614744900e+01, -1.1992723152311497e+01, -1.1723712855448614e+01, -1.1460651651502332e+01, -1.1202928261484638e+01, -1.0950027363642045e+01, -1.0701509369981165e+01, -1.0456995405743042e+01, -1.0216155937006269e+01, -9.9787020140292348e+00, -9.7443784273495506e+00, -9.5129582872037410e+00, -9.2842386787046287e+00, -9.0580371415563476e+00, -8.8341887898063280e+00, -8.6125439341638330e+00, -8.3929661031022729e+00, -8.1753303834489426e+00, -7.9595220192037859e+00, -7.7454352207811352e+00, -7.5329721470151476e+00, -7.3220420300038924e+00, -7.1125604188199452e+00, -6.9044485227388090e+00, -6.6976326382579296e+00, -6.4920436470380141e+00, -6.2876165741721222e+00, -6.0842901980089970e+00, -5.8820067042248958e+00, -5.6807113780286782e+00, -5.4803523293560428e+00, -5.2808802467053466e+00, -5.0822481759241382e+00, -4.8844113207996323e+00, -4.6873268627591953e+00, -4.4909537973654823e+00, -4.2952527856086178e+00, -4.1001860182656378e+00, -3.9057170918238593e+00, -3.7118108946570874e+00, -3.5184335023072513e+00, -3.3255520808638139e+00, -3.1331347975530193e+00, -2.9411507377518000e+00, -2.7495698277296028e+00, -2.5583627624976102e+00, -2.3675009382106698e+00, -2.1769563886241587e+00, -1.9867017251572272e+00, -1.7967100801564784e+00, -1.6069550529909824e+00, -1.4174106586413215e+00, -1.2280512784727862e+00, -1.0388516129063341e+00, -8.4978663572097946e-01, -6.6083154973822611e-01, -4.7196174365329491e-01, -2.8315274978949312e-01, -9.4380202561292328e-02, 9.4380202561292328e-02, 2.8315274978949312e-01, 4.7196174365329491e-01, 6.6083154973822611e-01, 8.4978663572097946e-01, 1.0388516129063341e+00, 1.2280512784727862e+00, 1.4174106586413215e+00, 1.6069550529909824e+00, 1.7967100801564784e+00, 1.9867017251572272e+00, 2.1769563886241587e+00, 2.3675009382106698e+00, 2.5583627624976102e+00, 2.7495698277296028e+00, 2.9411507377518000e+00, 3.1331347975530193e+00, 3.3255520808638139e+00, 3.5184335023072513e+00, 3.7118108946570874e+00, 3.9057170918238593e+00, 4.1001860182656378e+00, 4.2952527856086178e+00, 4.4909537973654823e+00, 4.6873268627591953e+00, 4.8844113207996323e+00, 5.0822481759241382e+00, 5.2808802467053466e+00, 5.4803523293560428e+00, 5.6807113780286782e+00, 5.8820067042248958e+00, 6.0842901980089970e+00, 6.2876165741721222e+00, 6.4920436470380141e+00, 6.6976326382579296e+00, 6.9044485227388090e+00, 7.1125604188199452e+00, 7.3220420300038924e+00, 7.5329721470151476e+00, 7.7454352207811352e+00, 7.9595220192037859e+00, 8.1753303834489426e+00, 8.3929661031022729e+00, 8.6125439341638330e+00, 8.8341887898063280e+00, 9.0580371415563476e+00, 9.2842386787046287e+00, 9.5129582872037410e+00, 9.7443784273495506e+00, 9.9787020140292348e+00, 1.0216155937006269e+01, 1.0456995405743042e+01, 1.0701509369981165e+01, 1.0950027363642045e+01, 1.1202928261484638e+01, 1.1460651651502332e+01, 1.1723712855448614e+01, 1.1992723152311497e+01, 1.2268417614744900e+01, 1.2551694420292197e+01, 1.2843672070795714e+01, 1.3145775742375259e+01, 1.3459873460233181e+01, 1.3788502962262141e+01, 1.4135277255544954e+01, 1.4505681306755122e+01, 1.4908860841455180e+01, 1.5362565713640512e+01, 1.5913261603942480e+01}, {-1.5974128087803059e+01, -1.5424125215654696e+01, -1.4971005737794270e+01, -1.4568357770032772e+01, -1.4198451817550286e+01, -1.3852152569276431e+01, -1.3523981270171619e+01, -1.3210328989123949e+01, -1.2908660844914866e+01, -1.2617110914147242e+01, -1.2334255626355663e+01, -1.2058977743887230e+01, -1.1790380109646946e+01, -1.1527728492218195e+01, -1.1270412318828130e+01, -1.1017916870112439e+01, -1.0769803079243415e+01, -1.0525692528151630e+01, -1.0285256087783404e+01, -1.0048205171171734e+01, -9.8142848971316887e+00, -9.5832686756941996e+00, -9.3549538681059694e+00, -9.1291582704569425e+00, -8.9057172366410864e+00, -8.6844813033334454e+00, -8.4653142133164536e+00, -8.2480912579473227e+00, -8.0326978775762718e+00, -7.8190284721625867e+00, -7.6069853844711011e+00, -7.3964780259572480e+00, -7.1874221213951852e+00, -6.9797390529218948e+00, -6.7733552877875338e+00, -6.5682018769582182e+00, -6.3642140139886543e+00, -6.1613306454010424e+00, -5.9594941252729363e+00, -5.7586499079259337e+00, -5.5587462735771860e+00, -5.3597340826114390e+00, -5.1615665547873322e+00, -4.9641990702352388e+00, -4.7675889895563337e+00, -4.5716954907107725e+00, -4.3764794207003801e+00, -4.1819031603187895e+00, -3.9879305004682921e+00, -3.7945265287347798e+00, -3.6016575250757095e+00, -3.4092908656157688e+00, -3.2173949336645937e+00, -3.0259390371736554e+00, -2.8348933319378968e+00, -2.6442287499240060e+00, -2.4539169321730845e+00, -2.2639301657825421e+00, -2.0742413245213673e+00, -1.8848238126757204e+00, -1.6956515117588089e+00, -1.5066987297510446e+00, -1.3179401525641421e+00, -1.1293507974466097e+00, -9.4090596806846227e-01, -7.5258121104029896e-01, -5.6435227363645946e-01, -3.7619506250401802e-01, -1.8808560314914807e-01, -0.0000000000000000e+00, 1.8808560314914807e-01, 3.7619506250401802e-01, 5.6435227363645946e-01, 7.5258121104029896e-01, 9.4090596806846227e-01, 1.1293507974466097e+00, 1.3179401525641421e+00, 1.5066987297510446e+00, 1.6956515117588089e+00, 1.8848238126757204e+00, 2.0742413245213673e+00, 2.2639301657825421e+00, 2.4539169321730845e+00, 2.6442287499240060e+00, 2.8348933319378968e+00, 3.0259390371736554e+00, 3.2173949336645937e+00, 3.4092908656157688e+00, 3.6016575250757095e+00, 3.7945265287347798e+00, 3.9879305004682921e+00, 4.1819031603187895e+00, 4.3764794207003801e+00, 4.5716954907107725e+00, 4.7675889895563337e+00, 4.9641990702352388e+00, 5.1615665547873322e+00, 5.3597340826114390e+00, 5.5587462735771860e+00, 5.7586499079259337e+00, 5.9594941252729363e+00, 6.1613306454010424e+00, 6.3642140139886543e+00, 6.5682018769582182e+00, 6.7733552877875338e+00, 6.9797390529218948e+00, 7.1874221213951852e+00, 7.3964780259572480e+00, 7.6069853844711011e+00, 7.8190284721625867e+00, 8.0326978775762718e+00, 8.2480912579473227e+00, 8.4653142133164536e+00, 8.6844813033334454e+00, 8.9057172366410864e+00, 9.1291582704569425e+00, 9.3549538681059694e+00, 9.5832686756941996e+00, 9.8142848971316887e+00, 1.0048205171171734e+01, 1.0285256087783404e+01, 1.0525692528151630e+01, 1.0769803079243415e+01, 1.1017916870112439e+01, 1.1270412318828130e+01, 1.1527728492218195e+01, 1.1790380109646946e+01, 1.2058977743887230e+01, 1.2334255626355663e+01, 1.2617110914147242e+01, 1.2908660844914866e+01, 1.3210328989123949e+01, 1.3523981270171619e+01, 1.3852152569276431e+01, 1.4198451817550286e+01, 1.4568357770032772e+01, 1.4971005737794270e+01, 1.5424125215654696e+01, 1.5974128087803059e+01}, {-1.6034772477060816e+01, -1.5485456646120181e+01, -1.5032917422687504e+01, -1.4630796281434252e+01, -1.4261383921882931e+01, -1.3915555363288536e+01, -1.3587838011990620e+01, -1.3274626979734647e+01, -1.2973390218594389e+01, -1.2682263889584272e+01, -1.2399826014408026e+01, -1.2124960608784908e+01, -1.1856771527137033e+01, -1.1594525371724179e+01, -1.1337612269445431e+01, -1.1085518097551031e+01, -1.0837804305192460e+01, -1.0594092926257336e+01, -1.0354055232179574e+01, -1.0117402994660386e+01, -9.8838816568977812e+00, -9.6532649249849332e+00, -9.4253504326923299e+00, -9.1999562289744645e+00, -8.9769179041114668e+00, -8.7560862173209468e+00, -8.5373251222877080e+00, -8.3205101114907762e+00, -8.1055268182049698e+00, -7.8922698284767430e+00, -7.6806416654983130e+00, -7.4705519165212015e+00, -7.2619164783901100e+00, -7.0546569023913719e+00, -6.8486998227236997e+00, -6.6439764557516492e+00, -6.4404221594710993e+00, -6.2379760444330401e+00, -6.0365806288366217e+00, -5.8361815316904240e+00, -5.6367271989099255e+00, -5.4381686580140975e+00, -5.2404592977393536e+00, -5.0435546694321367e+00, -4.8474123075333448e+00, -4.6519915668456937e+00, -4.4572534745922692e+00, -4.2631605955419172e+00, -4.0696769087032161e+00, -3.8767676942807565e+00, -3.6843994297509557e+00, -3.4925396940542712e+00, -3.3011570790203533e+00, -3.1102211072454056e+00, -2.9197021557295608e+00, -2.7295713846583514e+00, -2.5398006707783964e+00, -2.3503625448744949e+00, -2.1612301329048256e+00, -1.9723771003938499e+00, -1.7837775997197194e+00, -1.5954062199652144e+00, -1.4072379390291252e+00, -1.2192480777190431e+00, -1.0314122555671925e+00, -8.4370634812858625e-01, -6.5610644553571928e-01, -4.6858881209649367e-01, -2.8112984673230629e-01, -9.3706044061378571e-02, 9.3706044061378571e-02, 2.8112984673230629e-01, 4.6858881209649367e-01, 6.5610644553571928e-01, 8.4370634812858625e-01, 1.0314122555671925e+00, 1.2192480777190431e+00, 1.4072379390291252e+00, 1.5954062199652144e+00, 1.7837775997197194e+00, 1.9723771003938499e+00, 2.1612301329048256e+00, 2.3503625448744949e+00, 2.5398006707783964e+00, 2.7295713846583514e+00, 2.9197021557295608e+00, 3.1102211072454056e+00, 3.3011570790203533e+00, 3.4925396940542712e+00, 3.6843994297509557e+00, 3.8767676942807565e+00, 4.0696769087032161e+00, 4.2631605955419172e+00, 4.4572534745922692e+00, 4.6519915668456937e+00, 4.8474123075333448e+00, 5.0435546694321367e+00, 5.2404592977393536e+00, 5.4381686580140975e+00, 5.6367271989099255e+00, 5.8361815316904240e+00, 6.0365806288366217e+00, 6.2379760444330401e+00, 6.4404221594710993e+00, 6.6439764557516492e+00, 6.8486998227236997e+00, 7.0546569023913719e+00, 7.2619164783901100e+00, 7.4705519165212015e+00, 7.6806416654983130e+00, 7.8922698284767430e+00, 8.1055268182049698e+00, 8.3205101114907762e+00, 8.5373251222877080e+00, 8.7560862173209468e+00, 8.9769179041114668e+00, 9.1999562289744645e+00, 9.4253504326923299e+00, 9.6532649249849332e+00, 9.8838816568977812e+00, 1.0117402994660386e+01, 1.0354055232179574e+01, 1.0594092926257336e+01, 1.0837804305192460e+01, 1.1085518097551031e+01, 1.1337612269445431e+01, 1.1594525371724179e+01, 1.1856771527137033e+01, 1.2124960608784908e+01, 1.2399826014408026e+01, 1.2682263889584272e+01, 1.2973390218594389e+01, 1.3274626979734647e+01, 1.3587838011990620e+01, 1.3915555363288536e+01, 1.4261383921882931e+01, 1.4630796281434252e+01, 1.5032917422687504e+01, 1.5485456646120181e+01, 1.6034772477060816e+01}, {-1.6095197175178654e+01, -1.5546562503045239e+01, -1.5094598476696428e+01, -1.4692999498678725e+01, -1.4324076300505626e+01, -1.3978714148861499e+01, -1.3651446561974707e+01, -1.3338672661844436e+01, -1.3037863210821454e+01, -1.2747156437216972e+01, -1.2465131941640982e+01, -1.2190674982552025e+01, -1.1922890417116040e+01, -1.1661045673847648e+01, -1.1404531572900545e+01, -1.1152834582481235e+01, -1.0905516662643253e+01, -1.0662200294603309e+01, -1.0422557146004042e+01, -1.0186299343207718e+01, -9.9531726499989794e+00, -9.7229510648991155e+00, -9.4954324906908987e+00, -9.2704352257718199e+00, -9.0477950934492313e+00, -8.8273630721636813e+00, -8.6090033232019607e+00, -8.3925915368661208e+00, -8.1780135360427444e+00, -7.9651640895243876e+00, -7.7539458975483946e+00, -7.5442687197268468e+00, -7.3360486214748111e+00, -7.1292073196522763e+00, -6.9236716117447346e+00, -6.7193728757570428e+00, -6.5162466302615387e+00, -6.3142321458564812e+00, -6.1132721007540169e+00, -5.9133122744035465e+00, -5.7143012740244483e+00, -5.5161902897161745e+00, -5.3189328744684259e+00, -5.1224847459365774e+00, -4.9268036072990391e+00, -4.7318489848907346e+00, -4.5375820806238156e+00, -4.3439656374738016e+00, -4.1509638165353397e+00, -3.9585420843435810e+00, -3.7666671093205584e+00, -3.5753066663455639e+00, -3.3844295485681095e+00, -3.1940054856848250e+00, -3.0040050679901400e+00, -2.8143996755869578e+00, -2.6251614122095890e+00, -2.4362630431683869e+00, -2.2476779369751214e+00, -2.0593800102511661e+00, -1.8713436755579074e+00, -1.6835437918212028e+00, -1.4959556170497912e+00, -1.3085547630718375e+00, -1.1213171520347327e+00, -9.3421897443120272e-01, -7.4723664843005233e-01, -5.6034678030272367e-01, -3.7352612574750421e-01, -1.8675155192184525e-01, -0.0000000000000000e+00, 1.8675155192184525e-01, 3.7352612574750421e-01, 5.6034678030272367e-01, 7.4723664843005233e-01, 9.3421897443120272e-01, 1.1213171520347327e+00, 1.3085547630718375e+00, 1.4959556170497912e+00, 1.6835437918212028e+00, 1.8713436755579074e+00, 2.0593800102511661e+00, 2.2476779369751214e+00, 2.4362630431683869e+00, 2.6251614122095890e+00, 2.8143996755869578e+00, 3.0040050679901400e+00, 3.1940054856848250e+00, 3.3844295485681095e+00, 3.5753066663455639e+00, 3.7666671093205584e+00, 3.9585420843435810e+00, 4.1509638165353397e+00, 4.3439656374738016e+00, 4.5375820806238156e+00, 4.7318489848907346e+00, 4.9268036072990391e+00, 5.1224847459365774e+00, 5.3189328744684259e+00, 5.5161902897161745e+00, 5.7143012740244483e+00, 5.9133122744035465e+00, 6.1132721007540169e+00, 6.3142321458564812e+00, 6.5162466302615387e+00, 6.7193728757570428e+00, 6.9236716117447346e+00, 7.1292073196522763e+00, 7.3360486214748111e+00, 7.5442687197268468e+00, 7.7539458975483946e+00, 7.9651640895243876e+00, 8.1780135360427444e+00, 8.3925915368661208e+00, 8.6090033232019607e+00, 8.8273630721636813e+00, 9.0477950934492313e+00, 9.2704352257718199e+00, 9.4954324906908987e+00, 9.7229510648991155e+00, 9.9531726499989794e+00, 1.0186299343207718e+01, 1.0422557146004042e+01, 1.0662200294603309e+01, 1.0905516662643253e+01, 1.1152834582481235e+01, 1.1404531572900545e+01, 1.1661045673847648e+01, 1.1922890417116040e+01, 1.2190674982552025e+01, 1.2465131941640982e+01, 1.2747156437216972e+01, 1.3037863210821454e+01, 1.3338672661844436e+01, 1.3651446561974707e+01, 1.3978714148861499e+01, 1.4324076300505626e+01, 1.4692999498678725e+01, 1.5094598476696428e+01, 1.5546562503045239e+01, 1.6095197175178654e+01}, {-1.6155404542662776e+01, -1.5607445239317764e+01, -1.5156051433346871e+01, -1.4754970030637802e+01, -1.4386531634770627e+01, -1.4041631678205716e+01, -1.3714809742317117e+01, -1.3402468927252324e+01, -1.3102082782981558e+01, -1.2811791588270133e+01, -1.2530176509588186e+01, -1.2256124037680147e+01, -1.1988740023836153e+01, -1.1727292715539413e+01, -1.1471173619903071e+01, -1.1219869790544209e+01, -1.0972943693447091e+01, -1.0730018252630529e+01, -1.0490765527764685e+01, -1.0254897995961329e+01, -1.0022161737889968e+01, -9.7923310409601427e+00, -9.5652040735500723e+00, -9.3405993801743854e+00, -9.1183530139059350e+00, -8.8983161691878188e+00, -8.6803532117101110e+00, -8.4643400264036650e+00, -8.2501626225617972e+00, -8.0377159484935703e+00, -7.8269028782146863e+00, -7.6176333403821728e+00, -7.4098235656060059e+00, -7.2033954328740331e+00, -6.9982758994323033e+00, -6.7943965013094090e+00, -6.5916929139374751e+00, -6.3901045641355303e+00, -6.1895742861825749e+00, -5.9900480158931027e+00, -5.7914745175749145e+00, -5.5938051395422690e+00, -5.3969935945114758e+00, -5.2009957617479348e+00, -5.0057695082847111e+00, -4.8112745269098740e+00, -4.6174721889364516e+00, -4.4243254100357463e+00, -4.2317985276405068e+00, -4.0398571886161809e+00, -3.8484682460617101e+00, -3.6575996642408795e+00, -3.4672204307647947e+00, -3.2773004752487735e+00, -3.0878105937554641e+00, -2.8987223784123866e+00, -2.7100081516581653e+00, -2.5216409046290269e+00, -2.3335942392467470e+00, -2.1458423136124405e+00, -1.9583597903480086e+00, -1.7711217875596625e+00, -1.5841038321261636e+00, -1.3972818150389417e+00, -1.2106319485423875e+00, -1.0241307248408380e+00, -8.3775487615432709e-01, -6.5148133591837221e-01, -4.6528720093408932e-01, -2.7914969428399067e-01, -9.3046128836030015e-02, 9.3046128836030015e-02, 2.7914969428399067e-01, 4.6528720093408932e-01, 6.5148133591837221e-01, 8.3775487615432709e-01, 1.0241307248408380e+00, 1.2106319485423875e+00, 1.3972818150389417e+00, 1.5841038321261636e+00, 1.7711217875596625e+00, 1.9583597903480086e+00, 2.1458423136124405e+00, 2.3335942392467470e+00, 2.5216409046290269e+00, 2.7100081516581653e+00, 2.8987223784123866e+00, 3.0878105937554641e+00, 3.2773004752487735e+00, 3.4672204307647947e+00, 3.6575996642408795e+00, 3.8484682460617101e+00, 4.0398571886161809e+00, 4.2317985276405068e+00, 4.4243254100357463e+00, 4.6174721889364516e+00, 4.8112745269098740e+00, 5.0057695082847111e+00, 5.2009957617479348e+00, 5.3969935945114758e+00, 5.5938051395422690e+00, 5.7914745175749145e+00, 5.9900480158931027e+00, 6.1895742861825749e+00, 6.3901045641355303e+00, 6.5916929139374751e+00, 6.7943965013094090e+00, 6.9982758994323033e+00, 7.2033954328740331e+00, 7.4098235656060059e+00, 7.6176333403821728e+00, 7.8269028782146863e+00, 8.0377159484935703e+00, 8.2501626225617972e+00, 8.4643400264036650e+00, 8.6803532117101110e+00, 8.8983161691878188e+00, 9.1183530139059350e+00, 9.3405993801743854e+00, 9.5652040735500723e+00, 9.7923310409601427e+00, 1.0022161737889968e+01, 1.0254897995961329e+01, 1.0490765527764685e+01, 1.0730018252630529e+01, 1.0972943693447091e+01, 1.1219869790544209e+01, 1.1471173619903071e+01, 1.1727292715539413e+01, 1.1988740023836153e+01, 1.2256124037680147e+01, 1.2530176509588186e+01, 1.2811791588270133e+01, 1.3102082782981558e+01, 1.3402468927252324e+01, 1.3714809742317117e+01, 1.4041631678205716e+01, 1.4386531634770627e+01, 1.4754970030637802e+01, 1.5156051433346871e+01, 1.5607445239317764e+01, 1.6155404542662776e+01}, {-1.6215396898128663e+01, -1.5668107263835802e+01, -1.5217278780317361e+01, -1.4816710438579342e+01, -1.4448752556717958e+01, -1.4104310652531494e+01, -1.3777930322527094e+01, -1.3466018613382040e+01, -1.3166051840377859e+01, -1.2876172316156813e+01, -1.2594962760214381e+01, -1.2321310885302282e+01, -1.2054323528364668e+01, -1.1793269748698537e+01, -1.1537541734199792e+01, -1.1286627118459547e+01, -1.1040088868523824e+01, -1.0797550346784112e+01, -1.0558684000851162e+01, -1.0323202654766870e+01, -1.0090852702474850e+01, -9.8614087168236804e+00, -9.6346691284611641e+00, -9.4104527247850562e+00, -9.1885957854652229e+00, -8.9689497178220225e+00, -8.7513790888474610e+00, -8.5357599750069966e+00, -8.3219785688987216e+00, -8.1099299952250909e+00, -7.8995172986236630e+00, -7.6906505735952022e+00, -7.4832462126880364e+00, -7.2772262536958907e+00, -7.0725178102281943e+00, -6.8690525728554430e+00, -6.6667663702937121e+00, -6.4655987819036467e+00, -6.2654927942392939e+00, -6.0663944955663265e+00, -5.8682528032352996e+00, -5.6710192195879507e+00, -5.4746476127280044e+00, -5.2790940190292117e+00, -5.0843164647041039e+00, -4.8902748041336244e+00, -4.6969305729742112e+00, -4.5042468543255083e+00, -4.3121881564674842e+00, -4.1207203008672968e+00, -3.9298103193193850e+00, -3.7394263592217327e+00, -3.5495375961107607e+00, -3.3601141526799938e+00, -3.1711270235961577e+00, -2.9825480055027773e+00, -2.7943496316674543e+00, -2.6065051107863355e+00, -2.4189882695090272e+00, -2.2317734982904458e+00, -2.0448357002136932e+00, -1.8581502424607397e+00, -1.6716929101361060e+00, -1.4854398621734262e+00, -1.2993675890761167e+00, -1.1134528722618340e+00, -9.2767274479622841e-01, -7.4200445331498865e-01, -5.5642542094454162e-01, -3.7091321104119962e-01, -1.8544549157619233e-01, -0.0000000000000000e+00, 1.8544549157619233e-01, 3.7091321104119962e-01, 5.5642542094454162e-01, 7.4200445331498865e-01, 9.2767274479622841e-01, 1.1134528722618340e+00, 1.2993675890761167e+00, 1.4854398621734262e+00, 1.6716929101361060e+00, 1.8581502424607397e+00, 2.0448357002136932e+00, 2.2317734982904458e+00, 2.4189882695090272e+00, 2.6065051107863355e+00, 2.7943496316674543e+00, 2.9825480055027773e+00, 3.1711270235961577e+00, 3.3601141526799938e+00, 3.5495375961107607e+00, 3.7394263592217327e+00, 3.9298103193193850e+00, 4.1207203008672968e+00, 4.3121881564674842e+00, 4.5042468543255083e+00, 4.6969305729742112e+00, 4.8902748041336244e+00, 5.0843164647041039e+00, 5.2790940190292117e+00, 5.4746476127280044e+00, 5.6710192195879507e+00, 5.8682528032352996e+00, 6.0663944955663265e+00, 6.2654927942392939e+00, 6.4655987819036467e+00, 6.6667663702937121e+00, 6.8690525728554430e+00, 7.0725178102281943e+00, 7.2772262536958907e+00, 7.4832462126880364e+00, 7.6906505735952022e+00, 7.8995172986236630e+00, 8.1099299952250909e+00, 8.3219785688987216e+00, 8.5357599750069966e+00, 8.7513790888474610e+00, 8.9689497178220225e+00, 9.1885957854652229e+00, 9.4104527247850562e+00, 9.6346691284611641e+00, 9.8614087168236804e+00, 1.0090852702474850e+01, 1.0323202654766870e+01, 1.0558684000851162e+01, 1.0797550346784112e+01, 1.1040088868523824e+01, 1.1286627118459547e+01, 1.1537541734199792e+01, 1.1793269748698537e+01, 1.2054323528364668e+01, 1.2321310885302282e+01, 1.2594962760214381e+01, 1.2876172316156813e+01, 1.3166051840377859e+01, 1.3466018613382040e+01, 1.3777930322527094e+01, 1.4104310652531494e+01, 1.4448752556717958e+01, 1.4816710438579342e+01, 1.5217278780317361e+01, 1.5668107263835802e+01, 1.6215396898128663e+01}, {-1.6275176519333314e+01, -1.5728550942602004e+01, -1.5278282960589307e+01, -1.4878223237370916e+01, -1.4510741650331246e+01, -1.4166753723357122e+01, -1.3840811020790602e+01, -1.3529324504696065e+01, -1.3229773233699543e+01, -1.2940301538002238e+01, -1.2659493677496206e+01, -1.2386238576832154e+01, -1.2119644050283457e+01, -1.1858979961933818e+01, -1.1603639174400232e+01, -1.1353109895917042e+01, -1.1106955589822139e+01, -1.0864800052544570e+01, -1.0626316115639773e+01, -1.0391216946349248e+01, -1.0159249248367633e+01, -9.9301878766205718e+00, -9.7038315207870216e+00, -9.4799992080020576e+00, -9.2585274414535341e+00, -9.0392678383049354e+00, -8.8220851638421109e+00, -8.6068556830666605e+00, -8.3934657688780785e+00, -8.1818107193508762e+00, -7.9717937466932813e+00, -7.7633251081577797e+00, -7.5563213550879356e+00, -7.3507046808793666e+00, -7.1464023522306821e+00, -6.9433462109007360e+00, -6.7414722354477217e+00, -6.5407201542348838e+00, -6.3410331024462083e+00, -6.1423573170383490e+00, -5.9446418645201566e+00, -5.7478383972427567e+00, -5.5519009345358734e+00, -5.3567856655668686e+00, -5.1624507712492340e+00, -4.9688562629036443e+00, -4.7759638356907441e+00, -4.5837367351012581e+00, -4.3921396350144111e+00, -4.2011385260270222e+00, -4.0107006129187415e+00, -3.8207942202581950e+00, -3.6313887052743148e+00, -3.4424543772197556e+00, -3.2539624225418282e+00, -3.0658848352527657e+00, -2.8781943519573039e+00, -2.6908643910529264e+00, -2.5038689956679221e+00, -2.3171827799457509e+00, -2.1307808783218642e+00, -1.9446388974719979e+00, -1.7587328706394580e+00, -1.5730392140737939e+00, -1.3875346853347825e+00, -1.2021963432343084e+00, -1.0170015092047828e+00, -8.3192772989651476e-01, -6.4695274081809961e-01, -4.6205443084366904e-01, -2.7721080741886533e-01, -9.2399962303806829e-02, 9.2399962303806829e-02, 2.7721080741886533e-01, 4.6205443084366904e-01, 6.4695274081809961e-01, 8.3192772989651476e-01, 1.0170015092047828e+00, 1.2021963432343084e+00, 1.3875346853347825e+00, 1.5730392140737939e+00, 1.7587328706394580e+00, 1.9446388974719979e+00, 2.1307808783218642e+00, 2.3171827799457509e+00, 2.5038689956679221e+00, 2.6908643910529264e+00, 2.8781943519573039e+00, 3.0658848352527657e+00, 3.2539624225418282e+00, 3.4424543772197556e+00, 3.6313887052743148e+00, 3.8207942202581950e+00, 4.0107006129187415e+00, 4.2011385260270222e+00, 4.3921396350144111e+00, 4.5837367351012581e+00, 4.7759638356907441e+00, 4.9688562629036443e+00, 5.1624507712492340e+00, 5.3567856655668686e+00, 5.5519009345358734e+00, 5.7478383972427567e+00, 5.9446418645201566e+00, 6.1423573170383490e+00, 6.3410331024462083e+00, 6.5407201542348838e+00, 6.7414722354477217e+00, 6.9433462109007360e+00, 7.1464023522306821e+00, 7.3507046808793666e+00, 7.5563213550879356e+00, 7.7633251081577797e+00, 7.9717937466932813e+00, 8.1818107193508762e+00, 8.3934657688780785e+00, 8.6068556830666605e+00, 8.8220851638421109e+00, 9.0392678383049354e+00, 9.2585274414535341e+00, 9.4799992080020576e+00, 9.7038315207870216e+00, 9.9301878766205718e+00, 1.0159249248367633e+01, 1.0391216946349248e+01, 1.0626316115639773e+01, 1.0864800052544570e+01, 1.1106955589822139e+01, 1.1353109895917042e+01, 1.1603639174400232e+01, 1.1858979961933818e+01, 1.2119644050283457e+01, 1.2386238576832154e+01, 1.2659493677496206e+01, 1.2940301538002238e+01, 1.3229773233699543e+01, 1.3529324504696065e+01, 1.3840811020790602e+01, 1.4166753723357122e+01, 1.4510741650331246e+01, 1.4878223237370916e+01, 1.5278282960589307e+01, 1.5728550942602004e+01, 1.6275176519333314e+01}, {-1.6334745644175054e+01, -1.5788778599783345e+01, -1.5339066373560392e+01, -1.4939510896644496e+01, -1.4572501452752805e+01, -1.4228963493774261e+01, -1.3903454505286284e+01, -1.3592389334062910e+01, -1.3293249760441302e+01, -1.3004182116116599e+01, -1.2723772188949674e+01, -1.2450910105547806e+01, -1.2184704649330305e+01, -1.1924426482264677e+01, -1.1669469135738963e+01, -1.1419321387402469e+01, -1.1173547192211004e+01, -1.0931770776387262e+01, -1.0693665351523348e+01, -1.0458944424415622e+01, -1.0227355005071125e+01, -9.9986722272145627e+00, -9.7726950364017036e+00, -9.5492426964438799e+00, -9.3281519310537870e+00, -9.1092745642913098e+00, -8.8924755568174323e+00, -8.6776313592631116e+00, -8.4646285219201989e+00, -8.2533625133112452e+00, -8.0437367102645929e+00, -7.8356615297967140e+00, -7.6290536790115411e+00, -7.4238355038151660e+00, -7.2199344208383769e+00, -7.0172824197970574e+00, -6.8158156257772653e+00, -6.6154739127391755e+00, -6.4162005609911104e+00, -6.2179419525665987e+00, -6.0206472994014675e+00, -5.8242683999987914e+00, -5.6287594209215639e+00, -5.4340766999932706e+00, -5.2401785685362707e+00, -5.0470251903539998e+00, -4.8545784154787137e+00, -4.6628016469727172e+00, -4.4716597192961824e+00, -4.2811187869459504e+00, -4.0911462222326103e+00, -3.9017105212024688e+00, -3.7127812168303533e+00, -3.5243287987118928e+00, -3.3363246385723251e+00, -3.1487409209853521e+00, -2.9615505787617051e+00, -2.7747272325244832e+00, -2.5882451340382215e+00, -2.4020791129020052e+00, -2.2162045262547485e+00, -2.0305972111736730e+00, -1.8452334394757037e+00, -1.6600898746564745e+00, -1.4751435307233549e+00, -1.2903717326977489e+00, -1.1057520785781945e+00, -9.2126240256979075e-01, -7.3688073939740739e-01, -5.5258528953022001e-01, -3.6835438515345242e-01, -1.8416645673001250e-01, -0.0000000000000000e+00, 1.8416645673001250e-01, 3.6835438515345242e-01, 5.5258528953022001e-01, 7.3688073939740739e-01, 9.2126240256979075e-01, 1.1057520785781945e+00, 1.2903717326977489e+00, 1.4751435307233549e+00, 1.6600898746564745e+00, 1.8452334394757037e+00, 2.0305972111736730e+00, 2.2162045262547485e+00, 2.4020791129020052e+00, 2.5882451340382215e+00, 2.7747272325244832e+00, 2.9615505787617051e+00, 3.1487409209853521e+00, 3.3363246385723251e+00, 3.5243287987118928e+00, 3.7127812168303533e+00, 3.9017105212024688e+00, 4.0911462222326103e+00, 4.2811187869459504e+00, 4.4716597192961824e+00, 4.6628016469727172e+00, 4.8545784154787137e+00, 5.0470251903539998e+00, 5.2401785685362707e+00, 5.4340766999932706e+00, 5.6287594209215639e+00, 5.8242683999987914e+00, 6.0206472994014675e+00, 6.2179419525665987e+00, 6.4162005609911104e+00, 6.6154739127391755e+00, 6.8158156257772653e+00, 7.0172824197970574e+00, 7.2199344208383769e+00, 7.4238355038151660e+00, 7.6290536790115411e+00, 7.8356615297967140e+00, 8.0437367102645929e+00, 8.2533625133112452e+00, 8.4646285219201989e+00, 8.6776313592631116e+00, 8.8924755568174323e+00, 9.1092745642913098e+00, 9.3281519310537870e+00, 9.5492426964438799e+00, 9.7726950364017036e+00, 9.9986722272145627e+00, 1.0227355005071125e+01, 1.0458944424415622e+01, 1.0693665351523348e+01, 1.0931770776387262e+01, 1.1173547192211004e+01, 1.1419321387402469e+01, 1.1669469135738963e+01, 1.1924426482264677e+01, 1.2184704649330305e+01, 1.2450910105547806e+01, 1.2723772188949674e+01, 1.3004182116116599e+01, 1.3293249760441302e+01, 1.3592389334062910e+01, 1.3903454505286284e+01, 1.4228963493774261e+01, 1.4572501452752805e+01, 1.4939510896644496e+01, 1.5339066373560392e+01, 1.5788778599783345e+01, 1.6334745644175054e+01}, {-1.6394106471662131e+01, -1.5848792518737463e+01, -1.5399631376122628e+01, -1.5000575841923927e+01, -1.4634034455459645e+01, -1.4290942519672281e+01, -1.3965863395458523e+01, -1.3655215784079445e+01, -1.3356484166275854e+01, -1.3067816859418864e+01, -1.2787801167106462e+01, -1.2515328408121787e+01, -1.2249508326984577e+01, -1.1989612376763933e+01, -1.1735034751777302e+01, -1.1485264793960161e+01, -1.1239866945305195e+01, -1.0998465857673063e+01, -1.0760735118869476e+01, -1.0526388571683613e+01, -1.0295173529077774e+01, -1.0066865400378582e+01, -9.8412633839451633e+00, -9.6181869772854895e+00, -9.3974731217264083e+00, -9.1789738453613765e+00, -8.9625543013934692e+00, -8.7480911232640413e+00, -8.5354710358385653e+00, -8.3245896752567052e+00, -8.1153505801125796e+00, -7.9076643242985316e+00, -7.7014477677473518e+00, -7.4966234058915848e+00, -7.2931188022489746e+00, -7.0908660913775821e+00, -6.8898015416986063e+00, -6.6898651694904157e+00, -6.4910003968128018e+00, -6.2931537473009849e+00, -6.0962745747319902e+00, -5.9003148200559909e+00, -5.7052287932366612e+00, -5.5109729767842897e+00, -5.3175058483147666e+00, -5.1247877198432272e+00, -4.9327805918366323e+00, -4.7414480203154818e+00, -4.5507549955198634e+00, -4.3606678308461584e+00, -4.1711540609235342e+00, -3.9821823478385219e+00, -3.7937223946353149e+00, -3.6057448653220203e+00, -3.4182213107015205e+00, -3.2311240994220300e+00, -3.0444263537086158e+00, -2.8581018892943821e+00, -2.6721251591199171e+00, -2.4864712004130762e+00, -2.3011155847990197e+00, -2.1160343711234311e+00, -1.9312040607006651e+00, -1.7466015547236411e+00, -1.5622041135941906e+00, -1.3779893179515634e+00, -1.1939350311932622e+00, -1.0100193632965979e+00, -8.2622063576151961e-01, -6.4251734750563116e-01, -4.5888814155095509e-01, -2.7531177234913912e-01, -9.1767073597484664e-02, 9.1767073597484664e-02, 2.7531177234913912e-01, 4.5888814155095509e-01, 6.4251734750563116e-01, 8.2622063576151961e-01, 1.0100193632965979e+00, 1.1939350311932622e+00, 1.3779893179515634e+00, 1.5622041135941906e+00, 1.7466015547236411e+00, 1.9312040607006651e+00, 2.1160343711234311e+00, 2.3011155847990197e+00, 2.4864712004130762e+00, 2.6721251591199171e+00, 2.8581018892943821e+00, 3.0444263537086158e+00, 3.2311240994220300e+00, 3.4182213107015205e+00, 3.6057448653220203e+00, 3.7937223946353149e+00, 3.9821823478385219e+00, 4.1711540609235342e+00, 4.3606678308461584e+00, 4.5507549955198634e+00, 4.7414480203154818e+00, 4.9327805918366323e+00, 5.1247877198432272e+00, 5.3175058483147666e+00, 5.5109729767842897e+00, 5.7052287932366612e+00, 5.9003148200559909e+00, 6.0962745747319902e+00, 6.2931537473009849e+00, 6.4910003968128018e+00, 6.6898651694904157e+00, 6.8898015416986063e+00, 7.0908660913775821e+00, 7.2931188022489746e+00, 7.4966234058915848e+00, 7.7014477677473518e+00, 7.9076643242985316e+00, 8.1153505801125796e+00, 8.3245896752567052e+00, 8.5354710358385653e+00, 8.7480911232640413e+00, 8.9625543013934692e+00, 9.1789738453613765e+00, 9.3974731217264083e+00, 9.6181869772854895e+00, 9.8412633839451633e+00, 1.0066865400378582e+01, 1.0295173529077774e+01, 1.0526388571683613e+01, 1.0760735118869476e+01, 1.0998465857673063e+01, 1.1239866945305195e+01, 1.1485264793960161e+01, 1.1735034751777302e+01, 1.1989612376763933e+01, 1.2249508326984577e+01, 1.2515328408121787e+01, 1.2787801167106462e+01, 1.3067816859418864e+01, 1.3356484166275854e+01, 1.3655215784079445e+01, 1.3965863395458523e+01, 1.4290942519672281e+01, 1.4634034455459645e+01, 1.5000575841923927e+01, 1.5399631376122628e+01, 1.5848792518737463e+01, 1.6394106471662131e+01}, {-1.6453261162851238e+01, -1.5908594943006905e+01, -1.5459980283706434e+01, -1.5061420455716602e+01, -1.4695343105401838e+01, -1.4352693310923225e+01, -1.4028040263249208e+01, -1.3717806488350135e+01, -1.3419479146381439e+01, -1.3131208524813520e+01, -1.2851583430941135e+01, -1.2579496366100177e+01, -1.2314058027999442e+01, -1.2054540654144855e+01, -1.1800339096046955e+01, -1.1550943254895040e+01, -1.1305918055227691e+01, -1.1064888570473238e+01, -1.0827528760910019e+01, -1.0593552801837916e+01, -1.0362708305895856e+01, -1.0134770954893138e+01, -9.9095401969966606e+00, -9.6868357605097319e+00, -9.4664948015418702e+00, -9.2483695494377951e+00, -9.0323253471918115e+00, -8.8182390083208837e+00, -8.6059974295318415e+00, -8.3954964118396482e+00, -8.1866396528418637e+00, -7.9793378805138149e+00, -7.7735081047843622e+00, -7.5690729677310218e+00, -7.3659601768199030e+00, -7.1641020084474496e+00, -6.9634348712930993e+00, -6.7638989207955804e+00, -6.5654377175196297e+00, -6.3679979233591490e+00, -6.1715290304849564e+00, -5.9759831187344989e+00, -5.7813146377916294e+00, -5.5874802110437694e+00, -5.3944384584526848e+00, -5.2021498361504346e+00, -5.0105764907872219e+00, -4.8196821269235706e+00, -4.6294318859840997e+00, -4.4397922354810584e+00, -4.2507308673785191e+00, -4.0622166046072063e+00, -3.8742193148591682e+00, -3.6867098308940789e+00, -3.4996598766773372e+00, -3.3130419987465562e+00, -3.1268295022692216e+00, -2.9409963913117498e+00, -2.7555173128901118e+00, -2.5703675044157226e+00, -2.3855227441881959e+00, -2.2009593046196674e+00, -2.0166539079042916e+00, -1.8325836838717240e+00, -1.6487261297853975e+00, -1.4650590718655645e+00, -1.2815606283337120e+00, -1.0982091737893589e+00, -9.1498330474263811e-01, -7.3186180613665275e-01, -5.4882361870252716e-01, -3.6584780699750397e-01, -1.8291352798246857e-01, -0.0000000000000000e+00, 1.8291352798246857e-01, 3.6584780699750397e-01, 5.4882361870252716e-01, 7.3186180613665275e-01, 9.1498330474263811e-01, 1.0982091737893589e+00, 1.2815606283337120e+00, 1.4650590718655645e+00, 1.6487261297853975e+00, 1.8325836838717240e+00, 2.0166539079042916e+00, 2.2009593046196674e+00, 2.3855227441881959e+00, 2.5703675044157226e+00, 2.7555173128901118e+00, 2.9409963913117498e+00, 3.1268295022692216e+00, 3.3130419987465562e+00, 3.4996598766773372e+00, 3.6867098308940789e+00, 3.8742193148591682e+00, 4.0622166046072063e+00, 4.2507308673785191e+00, 4.4397922354810584e+00, 4.6294318859840997e+00, 4.8196821269235706e+00, 5.0105764907872219e+00, 5.2021498361504346e+00, 5.3944384584526848e+00, 5.5874802110437694e+00, 5.7813146377916294e+00, 5.9759831187344989e+00, 6.1715290304849564e+00, 6.3679979233591490e+00, 6.5654377175196297e+00, 6.7638989207955804e+00, 6.9634348712930993e+00, 7.1641020084474496e+00, 7.3659601768199030e+00, 7.5690729677310218e+00, 7.7735081047843622e+00, 7.9793378805138149e+00, 8.1866396528418637e+00, 8.3954964118396482e+00, 8.6059974295318415e+00, 8.8182390083208837e+00, 9.0323253471918115e+00, 9.2483695494377951e+00, 9.4664948015418702e+00, 9.6868357605097319e+00, 9.9095401969966606e+00, 1.0134770954893138e+01, 1.0362708305895856e+01, 1.0593552801837916e+01, 1.0827528760910019e+01, 1.1064888570473238e+01, 1.1305918055227691e+01, 1.1550943254895040e+01, 1.1800339096046955e+01, 1.2054540654144855e+01, 1.2314058027999442e+01, 1.2579496366100177e+01, 1.2851583430941135e+01, 1.3131208524813520e+01, 1.3419479146381439e+01, 1.3717806488350135e+01, 1.4028040263249208e+01, 1.4352693310923225e+01, 1.4695343105401838e+01, 1.5061420455716602e+01, 1.5459980283706434e+01, 1.5908594943006905e+01, 1.6453261162851238e+01}, {-1.6512211841757207e+01, -1.5968188077282482e+01, -1.5520115371292015e+01, -1.5122047078570679e+01, -1.4756429806104775e+01, -1.4414218332528858e+01, -1.4089987634289908e+01, -1.3780164032724846e+01, -1.3482237346726031e+01, -1.3194359818522189e+01, -1.2915121747251227e+01, -1.2643416807332409e+01, -1.2378356641882881e+01, -1.2119214266294843e+01, -1.1865385183637930e+01, -1.1616359849416588e+01, -1.1371703666311570e+01, -1.1131042125331231e+01, -1.0894049555564962e+01, -1.0660440461418377e+01, -1.0429962752004187e+01, -1.0202392378570206e+01, -9.9775290361704698e+00, -9.7551926810776539e+00, -9.5352206814286085e+00, -9.3174654651143189e+00, -9.1017925622483045e+00, -8.8880789637690558e+00, -8.6762117355753663e+00, -8.4660868409009815e+00, -8.2576081336726084e+00, -8.0506864932467330e+00, -7.8452390768098423e+00, -7.6411886703008571e+00, -7.4384631222974562e+00, -7.2369948481366277e+00, -7.0367203937895502e+00, -6.8375800508126918e+00, -6.6395175151495431e+00, -6.4424795837354694e+00, -6.2464158838193349e+00, -6.0512786307039113e+00, -5.8570224102572590e+00, -5.6636039830858733e+00, -5.4709821077089327e+00, -5.2791173804478735e+00, -5.0879720900604992e+00, -4.8975100854141935e+00, -4.7076966547174930e+00, -4.5184984150200371e+00, -4.3298832108534802e+00, -4.1418200210249481e+00, -3.9542788726937901e+00, -3.7672307619648824e+00, -3.5806475803201039e+00, -3.3945020462860152e+00, -3.2087676418019360e+00, -3.0234185528101056e+00, -2.8384296136395832e+00, -2.6537762547990797e+00, -2.4694344538319206e+00, -2.2853806889194859e+00, -2.1015918949484664e+00, -1.9180454217825835e+00, -1.7347189945015418e+00, -1.5515906753892701e+00, -1.3686388274702970e+00, -1.1858420794076876e+00, -1.0031792915885485e+00, -8.2062952323391314e-01, -6.3817200037899757e-01, -4.5578608457752007e-01, -2.7345124219010619e-01, -9.1147014121871414e-02, 9.1147014121871414e-02, 2.7345124219010619e-01, 4.5578608457752007e-01, 6.3817200037899757e-01, 8.2062952323391314e-01, 1.0031792915885485e+00, 1.1858420794076876e+00, 1.3686388274702970e+00, 1.5515906753892701e+00, 1.7347189945015418e+00, 1.9180454217825835e+00, 2.1015918949484664e+00, 2.2853806889194859e+00, 2.4694344538319206e+00, 2.6537762547990797e+00, 2.8384296136395832e+00, 3.0234185528101056e+00, 3.2087676418019360e+00, 3.3945020462860152e+00, 3.5806475803201039e+00, 3.7672307619648824e+00, 3.9542788726937901e+00, 4.1418200210249481e+00, 4.3298832108534802e+00, 4.5184984150200371e+00, 4.7076966547174930e+00, 4.8975100854141935e+00, 5.0879720900604992e+00, 5.2791173804478735e+00, 5.4709821077089327e+00, 5.6636039830858733e+00, 5.8570224102572590e+00, 6.0512786307039113e+00, 6.2464158838193349e+00, 6.4424795837354694e+00, 6.6395175151495431e+00, 6.8375800508126918e+00, 7.0367203937895502e+00, 7.2369948481366277e+00, 7.4384631222974562e+00, 7.6411886703008571e+00, 7.8452390768098423e+00, 8.0506864932467330e+00, 8.2576081336726084e+00, 8.4660868409009815e+00, 8.6762117355753663e+00, 8.8880789637690558e+00, 9.1017925622483045e+00, 9.3174654651143189e+00, 9.5352206814286085e+00, 9.7551926810776539e+00, 9.9775290361704698e+00, 1.0202392378570206e+01, 1.0429962752004187e+01, 1.0660440461418377e+01, 1.0894049555564962e+01, 1.1131042125331231e+01, 1.1371703666311570e+01, 1.1616359849416588e+01, 1.1865385183637930e+01, 1.2119214266294843e+01, 1.2378356641882881e+01, 1.2643416807332409e+01, 1.2915121747251227e+01, 1.3194359818522189e+01, 1.3482237346726031e+01, 1.3780164032724846e+01, 1.4089987634289908e+01, 1.4414218332528858e+01, 1.4756429806104775e+01, 1.5122047078570679e+01, 1.5520115371292015e+01, 1.5968188077282482e+01, 1.6512211841757207e+01}, {-1.6570960596234816e+01, -1.6027574088336884e+01, -1.5580038874389315e+01, -1.5182458010099252e+01, -1.4817296918736639e+01, -1.4475520005731354e+01, -1.4151707989055947e+01, -1.3842290956496822e+01, -1.3544761365310002e+01, -1.3257273397371849e+01, -1.2978418831992128e+01, -1.2707092507353986e+01, -1.2442407004329516e+01, -1.2183636109757821e+01, -1.1930175972733117e+01, -1.1681517598227204e+01, -1.1437226862743914e+01, -1.1196929670964046e+01, -1.0960300717203255e+01, -1.0727054831642461e+01, -1.0496940216738453e+01, -1.0269733090205794e+01, -1.0045233391137220e+01, -9.8232613010212955e+00, -9.6036543973400637e+00, -9.3862653039000534e+00, -9.1709597353376804e+00, -8.9576148574362815e+00, -8.7461179027166409e+00, -8.5363649940564841e+00, -8.3282601391216602e+00, -8.1217143660350786e+00, -7.9166449765926146e+00, -7.7129748979045933e+00, -7.5106321169206671e+00, -7.3095491851216430e+00, -7.1096627829092727e+00, -6.9109133350249667e+00, -6.7132446697794288e+00, -6.5166037160520816e+00, -6.3209402329793747e+00, -6.1262065680386195e+00, -5.9323574398835213e+00, -5.7393497428256754e+00, -5.5471423703043676e+00, -5.3556960550616148e+00, -5.1649732240539885e+00, -4.9749378663979575e+00, -4.7855554128699298e+00, -4.5967926256728040e+00, -4.4086174973432648e+00, -4.2209991578129564e+00, -4.0339077887557737e+00, -3.8473145444559340e+00, -3.6611914785198536e+00, -3.4755114758312047e+00, -3.2902481892147279e+00, -3.1053759803318370e+00, -2.9208698643810656e+00, -2.7367054582199937e+00, -2.5528589315633066e+00, -2.3693069609448871e+00, -2.1860266861608908e+00, -2.0029956689361597e+00, -1.8201918535785517e+00, -1.6375935294051731e+00, -1.4551792947414237e+00, -1.2729280223085093e+00, -1.0908188258278129e+00, -9.0883102768153856e-01, -7.2694412747841530e-01, -5.4513777138121788e-01, -3.6339172205944553e-01, -1.8168582913588810e-01, -0.0000000000000000e+00, 1.8168582913588810e-01, 3.6339172205944553e-01, 5.4513777138121788e-01, 7.2694412747841530e-01, 9.0883102768153856e-01, 1.0908188258278129e+00, 1.2729280223085093e+00, 1.4551792947414237e+00, 1.6375935294051731e+00, 1.8201918535785517e+00, 2.0029956689361597e+00, 2.1860266861608908e+00, 2.3693069609448871e+00, 2.5528589315633066e+00, 2.7367054582199937e+00, 2.9208698643810656e+00, 3.1053759803318370e+00, 3.2902481892147279e+00, 3.4755114758312047e+00, 3.6611914785198536e+00, 3.8473145444559340e+00, 4.0339077887557737e+00, 4.2209991578129564e+00, 4.4086174973432648e+00, 4.5967926256728040e+00, 4.7855554128699298e+00, 4.9749378663979575e+00, 5.1649732240539885e+00, 5.3556960550616148e+00, 5.5471423703043676e+00, 5.7393497428256754e+00, 5.9323574398835213e+00, 6.1262065680386195e+00, 6.3209402329793747e+00, 6.5166037160520816e+00, 6.7132446697794288e+00, 6.9109133350249667e+00, 7.1096627829092727e+00, 7.3095491851216430e+00, 7.5106321169206671e+00, 7.7129748979045933e+00, 7.9166449765926146e+00, 8.1217143660350786e+00, 8.3282601391216602e+00, 8.5363649940564841e+00, 8.7461179027166409e+00, 8.9576148574362815e+00, 9.1709597353376804e+00, 9.3862653039000534e+00, 9.6036543973400637e+00, 9.8232613010212955e+00, 1.0045233391137220e+01, 1.0269733090205794e+01, 1.0496940216738453e+01, 1.0727054831642461e+01, 1.0960300717203255e+01, 1.1196929670964046e+01, 1.1437226862743914e+01, 1.1681517598227204e+01, 1.1930175972733117e+01, 1.2183636109757821e+01, 1.2442407004329516e+01, 1.2707092507353986e+01, 1.2978418831992128e+01, 1.3257273397371849e+01, 1.3544761365310002e+01, 1.3842290956496822e+01, 1.4151707989055947e+01, 1.4475520005731354e+01, 1.4817296918736639e+01, 1.5182458010099252e+01, 1.5580038874389315e+01, 1.6027574088336884e+01, 1.6570960596234816e+01}, {-1.6629509478833860e+01, -1.6086755105929722e+01, -1.5639752989987683e+01, -1.5242655509972604e+01, -1.4877946763142496e+01, -1.4536600709088953e+01, -1.4213203763983850e+01, -1.3904189753562465e+01, -1.3607053753368865e+01, -1.3319951870041416e+01, -1.3041477351568494e+01, -1.2770526190723876e+01, -1.2506211898605262e+01, -1.2247809027167504e+01, -1.1994714366091593e+01, -1.1746419465057167e+01, -1.1502490670154140e+01, -1.1262554295905716e+01, -1.1026285398343321e+01, -1.0793399130164836e+01, -1.0563643984112028e+01, -1.0336796441464246e+01, -1.0112656682574075e+01, -9.8910451114622759e+00, -9.6717995123443519e+00, -9.4547727023830390e+00, -9.2398305782140078e+00, -9.0268504779630501e+00, -8.8157197982791242e+00, -8.6063348191874436e+00, -8.3985996995836860e+00, -8.1924256138258222e+00, -7.9877300057571530e+00, -7.7844359410588435e+00, -7.5824715424057798e+00, -7.3817694947224117e+00, -7.1822666100804051e+00, -6.9839034435780709e+00, -6.7866239529910715e+00, -6.5903751961596155e+00, -6.3951070610365948e+00, -6.2007720241079047e+00, -6.0073249335450427e+00, -5.8147228139876921e+00, -5.6229246903015975e+00, -5.4318914280313058e+00, -5.2415855885816516e+00, -5.0519712974268067e+00, -4.8630141238699967e+00, -4.6746809710674029e+00, -4.4869399751921195e+00, -4.2997604127527840e+00, -4.1131126152005661e+00, -3.9269678900605394e+00, -3.7412984479117779e+00, -3.5560773346168779e+00, -3.3712783682677476e+00, -3.1868760803720186e+00, -3.0028456608544345e+00, -2.8191629064911972e+00, -2.6358041724333074e+00, -2.4527463265082488e+00, -2.2699667060184630e+00, -2.0874430767805627e+00, -1.9051535941715365e+00, -1.7230767659677173e+00, -1.5411914167793415e+00, -1.3594766538983880e+00, -1.1779118343903046e+00, -9.9647653327140173e-01, -8.1515051262328730e-01, -6.3391369150388599e-01, -4.5274611652143021e-01, -2.7162793294346238e-01, -9.0539356217393022e-02, 9.0539356217393022e-02, 2.7162793294346238e-01, 4.5274611652143021e-01, 6.3391369150388599e-01, 8.1515051262328730e-01, 9.9647653327140173e-01, 1.1779118343903046e+00, 1.3594766538983880e+00, 1.5411914167793415e+00, 1.7230767659677173e+00, 1.9051535941715365e+00, 2.0874430767805627e+00, 2.2699667060184630e+00, 2.4527463265082488e+00, 2.6358041724333074e+00, 2.8191629064911972e+00, 3.0028456608544345e+00, 3.1868760803720186e+00, 3.3712783682677476e+00, 3.5560773346168779e+00, 3.7412984479117779e+00, 3.9269678900605394e+00, 4.1131126152005661e+00, 4.2997604127527840e+00, 4.4869399751921195e+00, 4.6746809710674029e+00, 4.8630141238699967e+00, 5.0519712974268067e+00, 5.2415855885816516e+00, 5.4318914280313058e+00, 5.6229246903015975e+00, 5.8147228139876921e+00, 6.0073249335450427e+00, 6.2007720241079047e+00, 6.3951070610365948e+00, 6.5903751961596155e+00, 6.7866239529910715e+00, 6.9839034435780709e+00, 7.1822666100804051e+00, 7.3817694947224117e+00, 7.5824715424057798e+00, 7.7844359410588435e+00, 7.9877300057571530e+00, 8.1924256138258222e+00, 8.3985996995836860e+00, 8.6063348191874436e+00, 8.8157197982791242e+00, 9.0268504779630501e+00, 9.2398305782140078e+00, 9.4547727023830390e+00, 9.6717995123443519e+00, 9.8910451114622759e+00, 1.0112656682574075e+01, 1.0336796441464246e+01, 1.0563643984112028e+01, 1.0793399130164836e+01, 1.1026285398343321e+01, 1.1262554295905716e+01, 1.1502490670154140e+01, 1.1746419465057167e+01, 1.1994714366091593e+01, 1.2247809027167504e+01, 1.2506211898605262e+01, 1.2770526190723876e+01, 1.3041477351568494e+01, 1.3319951870041416e+01, 1.3607053753368865e+01, 1.3904189753562465e+01, 1.4213203763983850e+01, 1.4536600709088953e+01, 1.4877946763142496e+01, 1.5242655509972604e+01, 1.5639752989987683e+01, 1.6086755105929722e+01, 1.6629509478833860e+01}, {-1.6687860507628386e+01, -1.6145733223684985e+01, -1.5699259877476434e+01, -1.5302641798879872e+01, -1.4938381618846188e+01, -1.4597462779517947e+01, -1.4274477352553639e+01, -1.3965862873544308e+01, -1.3669117016537621e+01, -1.3382397798268309e+01, -1.3104299924083964e+01, -1.2833720532318454e+01, -1.2569774056886668e+01, -1.2311735808633442e+01, -1.2059003212482786e+01, -1.1811068358148432e+01, -1.1567498057148995e+01, -1.1327919030095220e+01, -1.1092006691295751e+01, -1.0859476512776732e+01, -1.0630077274574017e+01, -1.0403585718697158e+01, -1.0179802264046788e+01, -9.9585475345593846e+00, -9.7396595186399217e+00, -9.5229912243166375e+00, -9.3084087277706491e+00, -9.0957895370391153e+00, -8.8850212104784116e+00, -8.6760001828398110e+00, -8.4686307618168346e+00, -8.2628242655509627e+00, -8.0584982774535074e+00, -7.8555759992614407e+00, -7.6539856868168998e+00, -7.4536601558800220e+00, -7.2545363475276838e+00, -7.0565549444870097e+00, -6.8596600312005922e+00, -6.6637987915949521e+00, -6.4689212394819462e+00, -6.2749799773089512e+00, -6.0819299796217976e+00, -5.8897283981415303e+00, -5.6983343858032613e+00, -5.5077089374792596e+00, -5.3178147454224645e+00, -5.1286160677313077e+00, -4.9400786083607757e+00, -4.7521694073949581e+00, -4.5648567404584961e+00, -4.3781100262830321e+00, -4.1918997415637014e+00, -4.0061973423430199e+00, -3.8209751912478049e+00, -3.6362064899810247e+00, -3.4518652165367119e+00, -3.2679260666634748e+00, -3.0843643991522391e+00, -2.9011561845674412e+00, -2.7182779570790365e+00, -2.5357067690860005e+00, -2.3534201483511836e+00, -2.1713960573929474e+00, -1.9896128549013927e+00, -1.8080492589666075e+00, -1.6266843119235277e+00, -1.4454973466329897e+00, -1.2644679540316108e+00, -1.0835759517944645e+00, -9.0280135396429395e-01, -7.2212434140935688e-01, -5.4152523297908439e-01, -3.6098445723261258e-01, -1.8048252462003789e-01, -0.0000000000000000e+00, 1.8048252462003789e-01, 3.6098445723261258e-01, 5.4152523297908439e-01, 7.2212434140935688e-01, 9.0280135396429395e-01, 1.0835759517944645e+00, 1.2644679540316108e+00, 1.4454973466329897e+00, 1.6266843119235277e+00, 1.8080492589666075e+00, 1.9896128549013927e+00, 2.1713960573929474e+00, 2.3534201483511836e+00, 2.5357067690860005e+00, 2.7182779570790365e+00, 2.9011561845674412e+00, 3.0843643991522391e+00, 3.2679260666634748e+00, 3.4518652165367119e+00, 3.6362064899810247e+00, 3.8209751912478049e+00, 4.0061973423430199e+00, 4.1918997415637014e+00, 4.3781100262830321e+00, 4.5648567404584961e+00, 4.7521694073949581e+00, 4.9400786083607757e+00, 5.1286160677313077e+00, 5.3178147454224645e+00, 5.5077089374792596e+00, 5.6983343858032613e+00, 5.8897283981415303e+00, 6.0819299796217976e+00, 6.2749799773089512e+00, 6.4689212394819462e+00, 6.6637987915949521e+00, 6.8596600312005922e+00, 7.0565549444870097e+00, 7.2545363475276838e+00, 7.4536601558800220e+00, 7.6539856868168998e+00, 7.8555759992614407e+00, 8.0584982774535074e+00, 8.2628242655509627e+00, 8.4686307618168346e+00, 8.6760001828398110e+00, 8.8850212104784116e+00, 9.0957895370391153e+00, 9.3084087277706491e+00, 9.5229912243166375e+00, 9.7396595186399217e+00, 9.9585475345593846e+00, 1.0179802264046788e+01, 1.0403585718697158e+01, 1.0630077274574017e+01, 1.0859476512776732e+01, 1.1092006691295751e+01, 1.1327919030095220e+01, 1.1567498057148995e+01, 1.1811068358148432e+01, 1.2059003212482786e+01, 1.2311735808633442e+01, 1.2569774056886668e+01, 1.2833720532318454e+01, 1.3104299924083964e+01, 1.3382397798268309e+01, 1.3669117016537621e+01, 1.3965862873544308e+01, 1.4274477352553639e+01, 1.4597462779517947e+01, 1.4938381618846188e+01, 1.5302641798879872e+01, 1.5699259877476434e+01, 1.6145733223684985e+01, 1.6687860507628386e+01}, {-1.6746015667021069e+01, -1.6204510499941978e+01, -1.5758561659537367e+01, -1.5362419059461168e+01, -1.4998603726021303e+01, -1.4658108513302281e+01, -1.4335531106337195e+01, -1.4027312722878635e+01, -1.3730953615978237e+01, -1.3444613698016527e+01, -1.3166889120550762e+01, -1.2896678158583638e+01, -1.2633096161556749e+01, -1.2375419193081754e+01, -1.2123045308073459e+01, -1.1875467131689264e+01, -1.1632251936796413e+01, -1.1393026846411182e+01, -1.1157467629750515e+01, -1.0925290075047540e+01, -1.0696243246707187e+01, -1.0470104144699656e+01, -1.0246673423826493e+01, -1.0025771925388167e+01, -9.8072378395003508e+00, -9.5909243626320890e+00, -9.3766977481232310e+00, -9.1644356715597066e+00, -8.9540258506546646e+00, -8.7453648725360029e+00, -8.5383571913371981e+00, -8.3329142666081459e+00, -8.1289538189277764e+00, -7.9263991836556649e+00, -7.7251787473280729e+00, -7.5252254540210100e+00, -7.3264763712435084e+00, -7.1288723067188302e+00, -6.9323574688579237e+00, -6.7368791649028887e+00, -6.5423875316754021e+00, -6.3488352946504518e+00, -6.1561775517231760e+00, -5.9643715785732399e+00, -5.7733766529779098e+00, -5.5831538957985396e+00, -5.3936661266788803e+00, -5.2048777327581446e+00, -5.0167545489255820e+00, -4.8292637483334380e+00, -4.6423737420472682e+00, -4.4560540868511129e+00, -4.2702754003439098e+00, -4.0850092825657862e+00, -3.9002282434810596e+00, -3.7159056357210827e+00, -3.5320155920561942e+00, -3.3485329671235227e+00, -3.1654332829874168e+00, -2.9826926781529521e+00, -2.8002878596910716e+00, -2.6181960581673263e+00, -2.4363949850953830e+00, -2.2548627926621019e+00, -2.0735780354934534e+00, -1.8925196342502328e+00, -1.7116668408598084e+00, -1.5309992052052144e+00, -1.3504965431061176e+00, -1.1701389054376192e+00, -9.8990654824282009e-01, -8.0977990370358899e-01, -6.2973955184126684e-01, -4.4976619282513375e-01, -2.6984061977151302e-01, -8.9943691920400901e-02, 8.9943691920400901e-02, 2.6984061977151302e-01, 4.4976619282513375e-01, 6.2973955184126684e-01, 8.0977990370358899e-01, 9.8990654824282009e-01, 1.1701389054376192e+00, 1.3504965431061176e+00, 1.5309992052052144e+00, 1.7116668408598084e+00, 1.8925196342502328e+00, 2.0735780354934534e+00, 2.2548627926621019e+00, 2.4363949850953830e+00, 2.6181960581673263e+00, 2.8002878596910716e+00, 2.9826926781529521e+00, 3.1654332829874168e+00, 3.3485329671235227e+00, 3.5320155920561942e+00, 3.7159056357210827e+00, 3.9002282434810596e+00, 4.0850092825657862e+00, 4.2702754003439098e+00, 4.4560540868511129e+00, 4.6423737420472682e+00, 4.8292637483334380e+00, 5.0167545489255820e+00, 5.2048777327581446e+00, 5.3936661266788803e+00, 5.5831538957985396e+00, 5.7733766529779098e+00, 5.9643715785732399e+00, 6.1561775517231760e+00, 6.3488352946504518e+00, 6.5423875316754021e+00, 6.7368791649028887e+00, 6.9323574688579237e+00, 7.1288723067188302e+00, 7.3264763712435084e+00, 7.5252254540210100e+00, 7.7251787473280729e+00, 7.9263991836556649e+00, 8.1289538189277764e+00, 8.3329142666081459e+00, 8.5383571913371981e+00, 8.7453648725360029e+00, 8.9540258506546646e+00, 9.1644356715597066e+00, 9.3766977481232310e+00, 9.5909243626320890e+00, 9.8072378395003508e+00, 1.0025771925388167e+01, 1.0246673423826493e+01, 1.0470104144699656e+01, 1.0696243246707187e+01, 1.0925290075047540e+01, 1.1157467629750515e+01, 1.1393026846411182e+01, 1.1632251936796413e+01, 1.1875467131689264e+01, 1.2123045308073459e+01, 1.2375419193081754e+01, 1.2633096161556749e+01, 1.2896678158583638e+01, 1.3166889120550762e+01, 1.3444613698016527e+01, 1.3730953615978237e+01, 1.4027312722878635e+01, 1.4335531106337195e+01, 1.4658108513302281e+01, 1.4998603726021303e+01, 1.5362419059461168e+01, 1.5758561659537367e+01, 1.6204510499941978e+01, 1.6746015667021069e+01}, {-1.6803976908523694e+01, -1.6263088958580713e+01, -1.5817660423010251e+01, -1.5421989437211316e+01, -1.5058615286432362e+01, -1.4718540167071973e+01, -1.4396367336014109e+01, -1.4088541665869107e+01, -1.3792565969471646e+01, -1.3506602040607744e+01, -1.3229247466060766e+01, -1.2959401648746917e+01, -1.2696180846459008e+01, -1.2438861869552357e+01, -1.2186843397769389e+01, -1.1939618587201746e+01, -1.1696755168060276e+01, -1.1457880662155430e+01, -1.1222671190311015e+01, -1.0990842853911044e+01, -1.0762144998868230e+01, -1.0536354880406639e+01, -1.0313273386643994e+01, -1.0092721573755421e+01, -9.8745378311513203e+00, -9.6585755413803565e+00, -9.4447011326189330e+00, -9.2327924457049324e+00, -9.0227373554249493e+00, -8.8144325990031405e+00, -8.6077827747261111e+00, -8.4026994812503251e+00, -8.1991005739976206e+00, -7.9969095195952864e+00, -7.7960548328817607e+00, -7.5964695838133709e+00, -7.3980909638458217e+00, -7.2008599031569602e+00, -7.0047207315224398e+00, -6.8096208768281805e+00, -6.6155105961598455e+00, -6.4223427351940696e+00, -6.2300725122630887e+00, -6.0386573240004857e+00, -5.8480565699220763e+00, -5.6582314936691613e+00, -5.4691450389548066e+00, -5.2807617185180318e+00, -5.0930474946144608e+00, -4.9059696697619373e+00, -4.7194967866215638e+00, -4.5335985360330326e+00, -4.3482456723419469e+00, -4.1634099352589846e+00, -3.9790639775789276e+00, -3.7951812981638180e+00, -3.6117361796606513e+00, -3.4287036304814422e+00, -3.2460593306235781e+00, -3.0637795809520179e+00, -2.8818412556030690e+00, -2.7002217572028795e+00, -2.5188989746230557e+00, -2.3378512430214919e+00, -2.1570573059390363e+00, -1.9764962792423748e+00, -1.7961476167208907e+00, -1.6159910771604287e+00, -1.4360066927302104e+00, -1.2561747385307371e+00, -1.0764757031605943e+00, -8.9689026016876394e-01, -7.1739924026651414e-01, -5.3798360417923241e-01, -3.5862441602383283e-01, -1.7930281710163956e-01, -0.0000000000000000e+00, 1.7930281710163956e-01, 3.5862441602383283e-01, 5.3798360417923241e-01, 7.1739924026651414e-01, 8.9689026016876394e-01, 1.0764757031605943e+00, 1.2561747385307371e+00, 1.4360066927302104e+00, 1.6159910771604287e+00, 1.7961476167208907e+00, 1.9764962792423748e+00, 2.1570573059390363e+00, 2.3378512430214919e+00, 2.5188989746230557e+00, 2.7002217572028795e+00, 2.8818412556030690e+00, 3.0637795809520179e+00, 3.2460593306235781e+00, 3.4287036304814422e+00, 3.6117361796606513e+00, 3.7951812981638180e+00, 3.9790639775789276e+00, 4.1634099352589846e+00, 4.3482456723419469e+00, 4.5335985360330326e+00, 4.7194967866215638e+00, 4.9059696697619373e+00, 5.0930474946144608e+00, 5.2807617185180318e+00, 5.4691450389548066e+00, 5.6582314936691613e+00, 5.8480565699220763e+00, 6.0386573240004857e+00, 6.2300725122630887e+00, 6.4223427351940696e+00, 6.6155105961598455e+00, 6.8096208768281805e+00, 7.0047207315224398e+00, 7.2008599031569602e+00, 7.3980909638458217e+00, 7.5964695838133709e+00, 7.7960548328817607e+00, 7.9969095195952864e+00, 8.1991005739976206e+00, 8.4026994812503251e+00, 8.6077827747261111e+00, 8.8144325990031405e+00, 9.0227373554249493e+00, 9.2327924457049324e+00, 9.4447011326189330e+00, 9.6585755413803565e+00, 9.8745378311513203e+00, 1.0092721573755421e+01, 1.0313273386643994e+01, 1.0536354880406639e+01, 1.0762144998868230e+01, 1.0990842853911044e+01, 1.1222671190311015e+01, 1.1457880662155430e+01, 1.1696755168060276e+01, 1.1939618587201746e+01, 1.2186843397769389e+01, 1.2438861869552357e+01, 1.2696180846459008e+01, 1.2959401648746917e+01, 1.3229247466060766e+01, 1.3506602040607744e+01, 1.3792565969471646e+01, 1.4088541665869107e+01, 1.4396367336014109e+01, 1.4718540167071973e+01, 1.5058615286432362e+01, 1.5421989437211316e+01, 1.5817660423010251e+01, 1.6263088958580713e+01, 1.6803976908523694e+01}, {-1.6861746151514453e+01, -1.6321470589822656e+01, -1.5876558219732326e+01, -1.5481355041356229e+01, -1.5118418464347313e+01, -1.4778759958751550e+01, -1.4456988312356128e+01, -1.4149552025707647e+01, -1.3853956452475600e+01, -1.3568365253816872e+01, -1.3291377440919536e+01, -1.3021893535990777e+01, -1.2759030698111300e+01, -1.2502066478454370e+01, -1.2250400176513523e+01, -1.2003525474883981e+01, -1.1761010557188053e+01, -1.1522483340487554e+01, -1.1287620293977072e+01, -1.1056137829198551e+01, -1.0827785570772761e+01, -1.0602341026531503e+01, -1.0379605315384135e+01, -1.0159399705951289e+01, -9.9415627845826098e+00, -9.7259481176063289e+00, -9.5124223057752690e+00, -9.3008633529456954e+00, -9.0911592887589681e+00, -8.8832069983214303e+00, -8.6769112218541409e+00, -8.4721836948885070e+00, -8.2689424054370715e+00, -8.0671109491149302e+00, -7.8666179667484384e+00, -7.6673966518192671e+00, -7.4693843173280303e+00, -7.2725220134526776e+00, -7.0767541888205505e+00, -6.8820283893841117e+00, -6.6882949898457129e+00, -6.4955069533605654e+00, -6.3036196158933109e+00, -6.1125904921391818e+00, -5.9223791003665953e+00, -5.7329468039109130e+00, -5.5442566673621716e+00, -5.3562733257536657e+00, -5.1689628652816504e+00, -4.9822927142762881e+00, -4.7962315433057050e+00, -4.6107491734334216e+00, -4.4258164917680798e+00, -4.2414053735465238e+00, -4.0574886100793801e+00, -3.8740398419645214e+00, -3.6910334970398750e+00, -3.5084447326044930e+00, -3.3262493814868481e+00, -3.1444239015829951e+00, -2.9629453285254086e+00, -2.7817912311767614e+00, -2.6009396696722078e+00, -2.4203691557594618e+00, -2.2400586152085502e+00, -2.0599873520829730e+00, -1.8801350146814075e+00, -1.7004815629744074e+00, -1.5210072373739318e+00, -1.3416925286852595e+00, -1.1625181491010375e+00, -9.8346500410607329e-01, -8.0451416516907071e-01, -6.2564684310401653e-01, -4.4684436198936728e-01, -2.6808813353769451e-01, -8.9359631812036308e-02, 8.9359631812036308e-02, 2.6808813353769451e-01, 4.4684436198936728e-01, 6.2564684310401653e-01, 8.0451416516907071e-01, 9.8346500410607329e-01, 1.1625181491010375e+00, 1.3416925286852595e+00, 1.5210072373739318e+00, 1.7004815629744074e+00, 1.8801350146814075e+00, 2.0599873520829730e+00, 2.2400586152085502e+00, 2.4203691557594618e+00, 2.6009396696722078e+00, 2.7817912311767614e+00, 2.9629453285254086e+00, 3.1444239015829951e+00, 3.3262493814868481e+00, 3.5084447326044930e+00, 3.6910334970398750e+00, 3.8740398419645214e+00, 4.0574886100793801e+00, 4.2414053735465238e+00, 4.4258164917680798e+00, 4.6107491734334216e+00, 4.7962315433057050e+00, 4.9822927142762881e+00, 5.1689628652816504e+00, 5.3562733257536657e+00, 5.5442566673621716e+00, 5.7329468039109130e+00, 5.9223791003665953e+00, 6.1125904921391818e+00, 6.3036196158933109e+00, 6.4955069533605654e+00, 6.6882949898457129e+00, 6.8820283893841117e+00, 7.0767541888205505e+00, 7.2725220134526776e+00, 7.4693843173280303e+00, 7.6673966518192671e+00, 7.8666179667484384e+00, 8.0671109491149302e+00, 8.2689424054370715e+00, 8.4721836948885070e+00, 8.6769112218541409e+00, 8.8832069983214303e+00, 9.0911592887589681e+00, 9.3008633529456954e+00, 9.5124223057752690e+00, 9.7259481176063289e+00, 9.9415627845826098e+00, 1.0159399705951289e+01, 1.0379605315384135e+01, 1.0602341026531503e+01, 1.0827785570772761e+01, 1.1056137829198551e+01, 1.1287620293977072e+01, 1.1522483340487554e+01, 1.1761010557188053e+01, 1.2003525474883981e+01, 1.2250400176513523e+01, 1.2502066478454370e+01, 1.2759030698111300e+01, 1.3021893535990777e+01, 1.3291377440919536e+01, 1.3568365253816872e+01, 1.3853956452475600e+01, 1.4149552025707647e+01, 1.4456988312356128e+01, 1.4778759958751550e+01, 1.5118418464347313e+01, 1.5481355041356229e+01, 1.5876558219732326e+01, 1.6321470589822656e+01, 1.6861746151514453e+01}, {-1.6919325283973091e+01, -1.6379657351007765e+01, -1.5935257067352701e+01, -1.5540517945702927e+01, -1.5178015387422422e+01, -1.4838770068479555e+01, -1.4517396267181470e+01, -1.4210346085463854e+01, -1.3915127399149720e+01, -1.3629905722933353e+01, -1.3353281481744700e+01, -1.3084156308589026e+01, -1.2821648256881092e+01, -1.2565035612781342e+01, -1.2313718290542331e+01, -1.2067190494908804e+01, -1.1825020859053186e+01, -1.1586837691812352e+01, -1.1352317807578974e+01, -1.1121177925121051e+01, -1.0893167945027271e+01, -1.0668065625149652e+01, -1.0445672312722746e+01, -1.0225809486441577e+01, -1.0008315927297842e+01, -9.7930453831581623e+00, -9.5798646251513500e+00, -9.3686518179792717e+00, -9.1592951439814989e+00, -8.9516916339961323e+00, -8.7457461680254056e+00, -8.5413706163114078e+00, -8.3384830972746489e+00, -8.1370073333099651e+00, -7.9368720889917341e+00, -7.7380106790491130e+00, -7.5403605357059194e+00, -7.3438628267689321e+00, -7.1484621172907721e+00, -6.9541060688033616e+00, -6.7607451710725037e+00, -6.5683325021070607e+00, -6.3768235128018915e+00, -6.1861758331287540e+00, -5.9963490972348117e+00, -5.8073047851809010e+00, -5.6190060793645857e+00, -5.4314177339367200e+00, -5.2445059557435734e+00, -5.0582382955161487e+00, -4.8725835481900202e+00, -4.6875116613772301e+00, -4.5029936511304234e+00, -4.3190015242413970e+00, -4.1355082064043351e+00, -3.9524874756501580e+00, -3.7699139005244779e+00, -3.5877627825391012e+00, -3.4060101024770435e+00, -3.2246324701747149e+00, -3.0436070774431303e+00, -2.8629116538234336e+00, -2.6825244249014188e+00, -2.5024240729314422e+00, -2.3225896995428044e+00, -2.1430007903215516e+00, -1.9636371810781683e+00, -1.7844790256269836e+00, -1.6055067649166126e+00, -1.4267010973625776e+00, -1.2480429502435568e+00, -1.0695134520316971e+00, -8.9109390553517087e-01, -7.1276576173782080e-01, -5.3451059422635872e-01, -3.5631007410029453e-01, -1.7814594526358507e-01, -0.0000000000000000e+00, 1.7814594526358507e-01, 3.5631007410029453e-01, 5.3451059422635872e-01, 7.1276576173782080e-01, 8.9109390553517087e-01, 1.0695134520316971e+00, 1.2480429502435568e+00, 1.4267010973625776e+00, 1.6055067649166126e+00, 1.7844790256269836e+00, 1.9636371810781683e+00, 2.1430007903215516e+00, 2.3225896995428044e+00, 2.5024240729314422e+00, 2.6825244249014188e+00, 2.8629116538234336e+00, 3.0436070774431303e+00, 3.2246324701747149e+00, 3.4060101024770435e+00, 3.5877627825391012e+00, 3.7699139005244779e+00, 3.9524874756501580e+00, 4.1355082064043351e+00, 4.3190015242413970e+00, 4.5029936511304234e+00, 4.6875116613772301e+00, 4.8725835481900202e+00, 5.0582382955161487e+00, 5.2445059557435734e+00, 5.4314177339367200e+00, 5.6190060793645857e+00, 5.8073047851809010e+00, 5.9963490972348117e+00, 6.1861758331287540e+00, 6.3768235128018915e+00, 6.5683325021070607e+00, 6.7607451710725037e+00, 6.9541060688033616e+00, 7.1484621172907721e+00, 7.3438628267689321e+00, 7.5403605357059194e+00, 7.7380106790491130e+00, 7.9368720889917341e+00, 8.1370073333099651e+00, 8.3384830972746489e+00, 8.5413706163114078e+00, 8.7457461680254056e+00, 8.9516916339961323e+00, 9.1592951439814989e+00, 9.3686518179792717e+00, 9.5798646251513500e+00, 9.7930453831581623e+00, 1.0008315927297842e+01, 1.0225809486441577e+01, 1.0445672312722746e+01, 1.0668065625149652e+01, 1.0893167945027271e+01, 1.1121177925121051e+01, 1.1352317807578974e+01, 1.1586837691812352e+01, 1.1825020859053186e+01, 1.2067190494908804e+01, 1.2313718290542331e+01, 1.2565035612781342e+01, 1.2821648256881092e+01, 1.3084156308589026e+01, 1.3353281481744700e+01, 1.3629905722933353e+01, 1.3915127399149720e+01, 1.4210346085463854e+01, 1.4517396267181470e+01, 1.4838770068479555e+01, 1.5178015387422422e+01, 1.5540517945702927e+01, 1.5935257067352701e+01, 1.6379657351007765e+01, 1.6919325283973091e+01}, {-1.6976716163194499e+01, -1.6437651167348605e+01, -1.5993758950122626e+01, -1.5599480189464179e+01, -1.5237408147560531e+01, -1.4898572639500255e+01, -1.4577593394280033e+01, -1.4270926089044083e+01, -1.3976081103348914e+01, -1.3691225791789593e+01, -1.3414961982530070e+01, -1.3146192411007465e+01, -1.2884036018123565e+01, -1.2627771819287853e+01, -1.2376800338602001e+01, -1.2130616298680719e+01, -1.1888788778454018e+01, -1.1650946475122105e+01, -1.1416766545164455e+01, -1.1185966011702471e+01, -1.0958295048610227e+01, -1.0733531661229089e+01, -1.0511477422708499e+01, -1.0291954019502739e+01, -1.0074800425004574e+01, -9.8598705664345285e+00, -9.6470313831544541e+00, -9.4361611985975138e+00, -9.2271483457046273e+00, -9.0198899989563817e+00, -8.8142911760456872e+00, -8.6102638798256326e+00, -8.4077263570086043e+00, -8.2066024546299392e+00, -8.0068210588433661e+00, -7.8083156034214856e+00, -7.6110236375661993e+00, -7.4148864444214286e+00, -7.2198487031214214e+00, -7.0258581883766524e+00, -6.8328655025529308e+00, -6.6408238359815064e+00, -6.4496887518830528e+00, -6.2594179928228799e+00, -6.0699713060598244e+00, -5.8813102855233703e+00, -5.6933982284661457e+00, -5.5062000051024196e+00, -5.3196819397663528e+00, -5.1338117023131167e+00, -4.9485582086476523e+00, -4.7638915294038444e+00, -4.5797828059155004e+00, -4.3962041727224284e+00, -4.2131286859429329e+00, -4.0305302569201968e+00, -3.8483835906160127e+00, -3.6666641282827874e+00, -3.4853479939947509e+00, -3.3044119446629794e+00, -3.1238333231970716e+00, -2.9435900145097715e+00, -2.7636604040902180e+00, -2.5840233388973028e+00, -2.4046580903472949e+00, -2.2255443191898578e+00, -2.0466620420841379e+00, -1.8679915997020398e+00, -1.6895136261993984e+00, -1.5112090199076367e+00, -1.3330589151089478e+00, -1.1550446547671134e+00, -9.7714776409397042e-01, -7.9934992483832146e-01, -6.2163295018989517e-01, -4.4397876019583243e-01, -2.6636935759120106e-01, -8.8786803948269877e-02, 8.8786803948269877e-02, 2.6636935759120106e-01, 4.4397876019583243e-01, 6.2163295018989517e-01, 7.9934992483832146e-01, 9.7714776409397042e-01, 1.1550446547671134e+00, 1.3330589151089478e+00, 1.5112090199076367e+00, 1.6895136261993984e+00, 1.8679915997020398e+00, 2.0466620420841379e+00, 2.2255443191898578e+00, 2.4046580903472949e+00, 2.5840233388973028e+00, 2.7636604040902180e+00, 2.9435900145097715e+00, 3.1238333231970716e+00, 3.3044119446629794e+00, 3.4853479939947509e+00, 3.6666641282827874e+00, 3.8483835906160127e+00, 4.0305302569201968e+00, 4.2131286859429329e+00, 4.3962041727224284e+00, 4.5797828059155004e+00, 4.7638915294038444e+00, 4.9485582086476523e+00, 5.1338117023131167e+00, 5.3196819397663528e+00, 5.5062000051024196e+00, 5.6933982284661457e+00, 5.8813102855233703e+00, 6.0699713060598244e+00, 6.2594179928228799e+00, 6.4496887518830528e+00, 6.6408238359815064e+00, 6.8328655025529308e+00, 7.0258581883766524e+00, 7.2198487031214214e+00, 7.4148864444214286e+00, 7.6110236375661993e+00, 7.8083156034214856e+00, 8.0068210588433661e+00, 8.2066024546299392e+00, 8.4077263570086043e+00, 8.6102638798256326e+00, 8.8142911760456872e+00, 9.0198899989563817e+00, 9.2271483457046273e+00, 9.4361611985975138e+00, 9.6470313831544541e+00, 9.8598705664345285e+00, 1.0074800425004574e+01, 1.0291954019502739e+01, 1.0511477422708499e+01, 1.0733531661229089e+01, 1.0958295048610227e+01, 1.1185966011702471e+01, 1.1416766545164455e+01, 1.1650946475122105e+01, 1.1888788778454018e+01, 1.2130616298680719e+01, 1.2376800338602001e+01, 1.2627771819287853e+01, 1.2884036018123565e+01, 1.3146192411007465e+01, 1.3414961982530070e+01, 1.3691225791789593e+01, 1.3976081103348914e+01, 1.4270926089044083e+01, 1.4577593394280033e+01, 1.4898572639500255e+01, 1.5237408147560531e+01, 1.5599480189464179e+01, 1.5993758950122626e+01, 1.6437651167348605e+01, 1.6976716163194499e+01}, {-1.7033920616481659e+01, -1.6495453932662432e+01, -1.6052065819662449e+01, -1.5658243778058655e+01, -1.5296598801743723e+01, -1.4958169779028550e+01, -1.4637581850310665e+01, -1.4331294242121345e+01, -1.4036819819586414e+01, -1.3752327763757672e+01, -1.3476421295676769e+01, -1.3208004244970210e+01, -1.2946196433284063e+01, -1.2690277599628986e+01, -1.2439648873125966e+01, -1.2193805490052643e+01, -1.1952316971370964e+01, -1.1714812399295406e+01, -1.1480969269340585e+01, -1.1250504906165974e+01, -1.1023169754304320e+01, -1.0798742064110225e+01, -1.0577023632291938e+01, -1.0357836350801911e+01, -1.0141019383247183e+01, -9.9264268340723447e+00, -9.7139258087846567e+00, -9.5033947874905458e+00, -9.2947222516928303e+00, -9.0878055174840568e+00, -8.8825497382175893e+00, -8.6788670473198550e+00, -8.4766758177429260e+00, -8.2759000190893772e+00, -8.0764686569918620e+00, -7.8783152821330633e+00, -7.6813775585211594e+00, -7.4855968824216461e+00, -7.2909180447858821e+00, -7.0972889311843357e+00, -6.9046602542051492e+00, -6.7129853140601305e+00, -6.5222197837846556e+00, -6.3323215159520476e+00, -6.1432503682675650e+00, -5.9549680457789771e+00, -5.7674379577529349e+00, -5.5806250875296657e+00, -5.3944958738913487e+00, -5.2090181026688498e+00, -5.0241608074728896e+00, -4.8398941785737106e+00, -4.6561894790717648e+00, -4.4730189676038190e+00, -4.2903558269168203e+00, -4.1081740977179662e+00, -3.9264486172753981e+00, -3.7451549623013909e+00, -3.5642693956998519e+00, -3.3837688168037010e+00, -3.2036307147658607e+00, -3.0238331248011101e+00, -2.8443545870054412e+00, -2.6651741075053921e+00, -2.4862711217125546e+00, -2.3076254594784578e+00, -2.1292173119626474e+00, -1.9510272000422848e+00, -1.7730359441052344e+00, -1.5952246350806079e+00, -1.4175746065712449e+00, -1.2400674079618077e+00, -1.0626847783841744e+00, -8.8540862142874210e-01, -7.0822098049619520e-01, -5.3110401468933777e-01, -3.5403997514879265e-01, -1.7701118173979521e-01, -0.0000000000000000e+00, 1.7701118173979521e-01, 3.5403997514879265e-01, 5.3110401468933777e-01, 7.0822098049619520e-01, 8.8540862142874210e-01, 1.0626847783841744e+00, 1.2400674079618077e+00, 1.4175746065712449e+00, 1.5952246350806079e+00, 1.7730359441052344e+00, 1.9510272000422848e+00, 2.1292173119626474e+00, 2.3076254594784578e+00, 2.4862711217125546e+00, 2.6651741075053921e+00, 2.8443545870054412e+00, 3.0238331248011101e+00, 3.2036307147658607e+00, 3.3837688168037010e+00, 3.5642693956998519e+00, 3.7451549623013909e+00, 3.9264486172753981e+00, 4.1081740977179662e+00, 4.2903558269168203e+00, 4.4730189676038190e+00, 4.6561894790717648e+00, 4.8398941785737106e+00, 5.0241608074728896e+00, 5.2090181026688498e+00, 5.3944958738913487e+00, 5.5806250875296657e+00, 5.7674379577529349e+00, 5.9549680457789771e+00, 6.1432503682675650e+00, 6.3323215159520476e+00, 6.5222197837846556e+00, 6.7129853140601305e+00, 6.9046602542051492e+00, 7.0972889311843357e+00, 7.2909180447858821e+00, 7.4855968824216461e+00, 7.6813775585211594e+00, 7.8783152821330633e+00, 8.0764686569918620e+00, 8.2759000190893772e+00, 8.4766758177429260e+00, 8.6788670473198550e+00, 8.8825497382175893e+00, 9.0878055174840568e+00, 9.2947222516928303e+00, 9.5033947874905458e+00, 9.7139258087846567e+00, 9.9264268340723447e+00, 1.0141019383247183e+01, 1.0357836350801911e+01, 1.0577023632291938e+01, 1.0798742064110225e+01, 1.1023169754304320e+01, 1.1250504906165974e+01, 1.1480969269340585e+01, 1.1714812399295406e+01, 1.1952316971370964e+01, 1.2193805490052643e+01, 1.2439648873125966e+01, 1.2690277599628986e+01, 1.2946196433284063e+01, 1.3208004244970210e+01, 1.3476421295676769e+01, 1.3752327763757672e+01, 1.4036819819586414e+01, 1.4331294242121345e+01, 1.4637581850310665e+01, 1.4958169779028550e+01, 1.5296598801743723e+01, 1.5658243778058655e+01, 1.6052065819662449e+01, 1.6495453932662432e+01, 1.7033920616481659e+01}, {-1.7090940441818589e+01, -1.6553067510081998e+01, -1.6110179595706111e+01, -1.5716810683887498e+01, -1.5355589372841228e+01, -1.5017563559089020e+01, -1.4697363755671436e+01, -1.4391452713037102e+01, -1.4097345763967498e+01, -1.3813213902715583e+01, -1.3537661732992635e+01, -1.3269594170493015e+01, -1.3008131910966144e+01, -1.2752555411464087e+01, -1.2502266401375357e+01, -1.2256760626504082e+01, -1.2015608046183521e+01, -1.1778438124354272e+01, -1.1544928692572215e+01, -1.1314797374275166e+01, -1.1087794882081830e+01, -1.0863699708936927e+01, -1.0642313872803815e+01, -1.0423459468924202e+01, -1.0206975848984905e+01, -9.9927172925773995e+00, -9.7805510693200404e+00, -9.5703558139886304e+00, -9.3620201546636572e+00, -9.1554415470755703e+00, -8.9505252782658893e+00, -8.7471836102562435e+00, -8.5453350402475099e+00, -8.3449036583995202e+00, -8.1458185877888383e+00, -7.9480134939425788e+00, -7.7514261535735791e+00, -7.5559980739261903e+00, -7.3616741555800598e+00, -7.1684023927258176e+00, -6.9761336058782426e+00, -6.7848212027732666e+00, -6.5944209638389415e+00, -6.4048908491640280e+00, -6.2161908243320640e+00, -6.0282827028602410e+00, -5.8411300032943645e+00, -5.6546978192742712e+00, -5.4689527011066783e+00, -5.2838625475716334e+00, -5.0993965068499545e+00, -4.9155248855969580e+00, -4.7322190653061282e+00, -4.5494514252081650e+00, -4.3671952710387769e+00, -4.1854247690845812e+00, -4.0041148849824761e+00, -3.8232413268052290e+00, -3.6427804920159894e+00, -3.4627094179181652e+00, -3.2830057352652728e+00, -3.1036476247289064e+00, -2.9246137759523689e+00, -2.7458833489433849e+00, -2.5674359375820566e+00, -2.3892515350402799e+00, -2.2113105009265008e+00, -2.0335935299852599e+00, -1.8560816221946776e+00, -1.6787560541171089e+00, -1.5015983513687976e+00, -1.3245902620836472e+00, -1.1477137312543411e+00, -9.7095087584109574e-01, -7.9428396054439432e-01, -6.1769537414325426e-01, -4.4116760630493546e-01, -2.6468322477561551e-01, -8.8224852864438347e-02, 8.8224852864438347e-02, 2.6468322477561551e-01, 4.4116760630493546e-01, 6.1769537414325426e-01, 7.9428396054439432e-01, 9.7095087584109574e-01, 1.1477137312543411e+00, 1.3245902620836472e+00, 1.5015983513687976e+00, 1.6787560541171089e+00, 1.8560816221946776e+00, 2.0335935299852599e+00, 2.2113105009265008e+00, 2.3892515350402799e+00, 2.5674359375820566e+00, 2.7458833489433849e+00, 2.9246137759523689e+00, 3.1036476247289064e+00, 3.2830057352652728e+00, 3.4627094179181652e+00, 3.6427804920159894e+00, 3.8232413268052290e+00, 4.0041148849824761e+00, 4.1854247690845812e+00, 4.3671952710387769e+00, 4.5494514252081650e+00, 4.7322190653061282e+00, 4.9155248855969580e+00, 5.0993965068499545e+00, 5.2838625475716334e+00, 5.4689527011066783e+00, 5.6546978192742712e+00, 5.8411300032943645e+00, 6.0282827028602410e+00, 6.2161908243320640e+00, 6.4048908491640280e+00, 6.5944209638389415e+00, 6.7848212027732666e+00, 6.9761336058782426e+00, 7.1684023927258176e+00, 7.3616741555800598e+00, 7.5559980739261903e+00, 7.7514261535735791e+00, 7.9480134939425788e+00, 8.1458185877888383e+00, 8.3449036583995202e+00, 8.5453350402475099e+00, 8.7471836102562435e+00, 8.9505252782658893e+00, 9.1554415470755703e+00, 9.3620201546636572e+00, 9.5703558139886304e+00, 9.7805510693200404e+00, 9.9927172925773995e+00, 1.0206975848984905e+01, 1.0423459468924202e+01, 1.0642313872803815e+01, 1.0863699708936927e+01, 1.1087794882081830e+01, 1.1314797374275166e+01, 1.1544928692572215e+01, 1.1778438124354272e+01, 1.2015608046183521e+01, 1.2256760626504082e+01, 1.2502266401375357e+01, 1.2752555411464087e+01, 1.3008131910966144e+01, 1.3269594170493015e+01, 1.3537661732992635e+01, 1.3813213902715583e+01, 1.4097345763967498e+01, 1.4391452713037102e+01, 1.4697363755671436e+01, 1.5017563559089020e+01, 1.5355589372841228e+01, 1.5716810683887498e+01, 1.6110179595706111e+01, 1.6553067510081998e+01, 1.7090940441818589e+01}, {-1.7147777408524032e+01, -1.6610493732745791e+01, -1.6168102166823996e+01, -1.5775182847088153e+01, -1.5414381850393539e+01, -1.5076756017330117e+01, -1.4756941195343936e+01, -1.4451403633675961e+01, -1.4157661115094985e+01, -1.3873886433984071e+01, -1.3598685566661047e+01, -1.3330964506884797e+01, -1.3069844817966612e+01, -1.2814607669526135e+01, -1.2564655386543684e+01, -1.2319484220282153e+01, -1.2078664564848737e+01, -1.1841826262681151e+01, -1.1608647478438799e+01, -1.1378846131631990e+01, -1.1152173200444981e+01, -1.0928407418040756e+01, -1.0707351021384738e+01, -1.0488826306849386e+01, -1.0272672812117237e+01, -1.0058744989900266e+01, -9.8469102719449655e+00, -9.6370474457447699e+00, -9.4290452840267438e+00, -9.2228013802394901e+00, -9.0182211531960341e+00, -8.8152169915922389e+00, -8.6137075149457782e+00, -8.4136169320244640e+00, -8.2148744813764658e+00, -8.0174139413725705e+00, -7.8211731993958935e+00, -7.6260938715966651e+00, -7.4321209660664360e+00, -7.2392025834514619e+00, -7.0472896499758120e+00, -6.8563356786247329e+00, -6.6662965548819884e+00, -6.4771303439479562e+00, -6.2887971168089667e+00, -6.1012587928995696e+00, -5.9144789974110621e+00, -5.7284229315624149e+00, -5.5430572543722416e+00, -5.3583499746593573e+00, -5.1742703521606801e+00, -4.9907888067929420e+00, -4.8078768352029666e+00, -4.6255069338529911e+00, -4.4436525279753418e+00, -4.2622879058067751e+00, -4.0813881575787159e+00, -3.9009291187969852e+00, -3.7208873173946002e+00, -3.5412399243848873e+00, -3.3619647076803778e+00, -3.1830399887764611e+00, -3.0044446020282125e+00, -2.8261578562746821e+00, -2.6481594985877317e+00, -2.4704296799425793e+00, -2.2929489226249280e+00, -2.1156980892051682e+00, -1.9386583529239170e+00, -1.7618111693452876e+00, -1.5851382491449768e+00, -1.4086215319096145e+00, -1.2322431608320461e+00, -1.0559854581943640e+00, -8.7983090153669952e-01, -7.0376210041511855e-01, -5.2776177365646371e-01, -3.5181272702177707e-01, -1.7589783119299077e-01, -0.0000000000000000e+00, 1.7589783119299077e-01, 3.5181272702177707e-01, 5.2776177365646371e-01, 7.0376210041511855e-01, 8.7983090153669952e-01, 1.0559854581943640e+00, 1.2322431608320461e+00, 1.4086215319096145e+00, 1.5851382491449768e+00, 1.7618111693452876e+00, 1.9386583529239170e+00, 2.1156980892051682e+00, 2.2929489226249280e+00, 2.4704296799425793e+00, 2.6481594985877317e+00, 2.8261578562746821e+00, 3.0044446020282125e+00, 3.1830399887764611e+00, 3.3619647076803778e+00, 3.5412399243848873e+00, 3.7208873173946002e+00, 3.9009291187969852e+00, 4.0813881575787159e+00, 4.2622879058067751e+00, 4.4436525279753418e+00, 4.6255069338529911e+00, 4.8078768352029666e+00, 4.9907888067929420e+00, 5.1742703521606801e+00, 5.3583499746593573e+00, 5.5430572543722416e+00, 5.7284229315624149e+00, 5.9144789974110621e+00, 6.1012587928995696e+00, 6.2887971168089667e+00, 6.4771303439479562e+00, 6.6662965548819884e+00, 6.8563356786247329e+00, 7.0472896499758120e+00, 7.2392025834514619e+00, 7.4321209660664360e+00, 7.6260938715966651e+00, 7.8211731993958935e+00, 8.0174139413725705e+00, 8.2148744813764658e+00, 8.4136169320244640e+00, 8.6137075149457782e+00, 8.8152169915922389e+00, 9.0182211531960341e+00, 9.2228013802394901e+00, 9.4290452840267438e+00, 9.6370474457447699e+00, 9.8469102719449655e+00, 1.0058744989900266e+01, 1.0272672812117237e+01, 1.0488826306849386e+01, 1.0707351021384738e+01, 1.0928407418040756e+01, 1.1152173200444981e+01, 1.1378846131631990e+01, 1.1608647478438799e+01, 1.1841826262681151e+01, 1.2078664564848737e+01, 1.2319484220282153e+01, 1.2564655386543684e+01, 1.2814607669526135e+01, 1.3069844817966612e+01, 1.3330964506884797e+01, 1.3598685566661047e+01, 1.3873886433984071e+01, 1.4157661115094985e+01, 1.4451403633675961e+01, 1.4756941195343936e+01, 1.5076756017330117e+01, 1.5414381850393539e+01, 1.5775182847088153e+01, 1.6168102166823996e+01, 1.6610493732745791e+01, 1.7147777408524032e+01}, {-1.7204433257886514e+01, -1.6667734404468501e+01, -1.6225835391124875e+01, -1.5833362176266244e+01, -1.5472978191373558e+01, -1.5135749157814335e+01, -1.4816316219712570e+01, -1.4511149100314286e+01, -1.4217768014947598e+01, -1.3934347545235219e+01, -1.3659495030180320e+01, -1.3392117533718560e+01, -1.3131337480278725e+01, -1.2876436746658081e+01, -1.2626818248827179e+01, -1.2381978739506893e+01, -1.2141489044042531e+01, -1.1904979380197393e+01, -1.1672128242851137e+01, -1.1442653844932979e+01, -1.1216307427723020e+01, -1.0992867962280265e+01, -1.0772137902368133e+01, -1.0553939743380022e+01, -1.0338113206958853e+01, -1.0124512916959700e+01, -9.9130064653237309e+00, -9.7034727903605109e+00, -9.4958008075637199e+00, -9.2898882462326107e+00, -9.0856406550885644e+00, -8.8829705476356562e+00, -8.6817966638328432e+00, -8.4820433291649113e+00, -8.2836398957394959e+00, -8.0865202528325053e+00, -7.8906223965273750e+00, -7.6958880498740347e+00, -7.5022623264288848e+00, -7.3096934312013273e+00, -7.1181323939823153e+00, -6.9275328308096045e+00, -6.7378507299670023e+00, -6.5490442594474336e+00, -6.3610735932529767e+00, -6.1739007542758424e+00, -5.9874894718156684e+00, -5.8018050520510185e+00, -5.6168142600053486e+00, -5.4324852117363971e+00, -5.2487872756390139e+00, -5.0656909818891060e+00, -4.8831679391745020e+00, -4.7011907579602283e+00, -4.5197329796234431e+00, -4.3387690108692292e+00, -4.1582740629043391e+00, -3.9782240949032923e+00, -3.7985957613512462e+00, -3.6193663628916424e+00, -3.4405138003449269e+00, -3.2620165315981051e+00, -3.0838535310943649e+00, -2.9060042516778903e+00, -2.7284485885718048e+00, -2.5511668452873062e+00, -2.3741397012797925e+00, -2.1973481811834414e+00, -2.0207736254695439e+00, -1.8443976623860776e+00, -1.6682021810467551e+00, -1.4921693055472409e+00, -1.3162813699945290e+00, -1.1405208943427161e+00, -9.6487056093471757e-01, -7.8931319165491054e-01, -6.1383172560234123e-01, -4.3840919719805421e-01, -2.6302871464332994e-01, -8.7673438648223800e-02, 8.7673438648223800e-02, 2.6302871464332994e-01, 4.3840919719805421e-01, 6.1383172560234123e-01, 7.8931319165491054e-01, 9.6487056093471757e-01, 1.1405208943427161e+00, 1.3162813699945290e+00, 1.4921693055472409e+00, 1.6682021810467551e+00, 1.8443976623860776e+00, 2.0207736254695439e+00, 2.1973481811834414e+00, 2.3741397012797925e+00, 2.5511668452873062e+00, 2.7284485885718048e+00, 2.9060042516778903e+00, 3.0838535310943649e+00, 3.2620165315981051e+00, 3.4405138003449269e+00, 3.6193663628916424e+00, 3.7985957613512462e+00, 3.9782240949032923e+00, 4.1582740629043391e+00, 4.3387690108692292e+00, 4.5197329796234431e+00, 4.7011907579602283e+00, 4.8831679391745020e+00, 5.0656909818891060e+00, 5.2487872756390139e+00, 5.4324852117363971e+00, 5.6168142600053486e+00, 5.8018050520510185e+00, 5.9874894718156684e+00, 6.1739007542758424e+00, 6.3610735932529767e+00, 6.5490442594474336e+00, 6.7378507299670023e+00, 6.9275328308096045e+00, 7.1181323939823153e+00, 7.3096934312013273e+00, 7.5022623264288848e+00, 7.6958880498740347e+00, 7.8906223965273750e+00, 8.0865202528325053e+00, 8.2836398957394959e+00, 8.4820433291649113e+00, 8.6817966638328432e+00, 8.8829705476356562e+00, 9.0856406550885644e+00, 9.2898882462326107e+00, 9.4958008075637199e+00, 9.7034727903605109e+00, 9.9130064653237309e+00, 1.0124512916959700e+01, 1.0338113206958853e+01, 1.0553939743380022e+01, 1.0772137902368133e+01, 1.0992867962280265e+01, 1.1216307427723020e+01, 1.1442653844932979e+01, 1.1672128242851137e+01, 1.1904979380197393e+01, 1.2141489044042531e+01, 1.2381978739506893e+01, 1.2626818248827179e+01, 1.2876436746658081e+01, 1.3131337480278725e+01, 1.3392117533718560e+01, 1.3659495030180320e+01, 1.3934347545235219e+01, 1.4217768014947598e+01, 1.4511149100314286e+01, 1.4816316219712570e+01, 1.5135749157814335e+01, 1.5472978191373558e+01, 1.5833362176266244e+01, 1.6225835391124875e+01, 1.6667734404468501e+01, 1.7204433257886514e+01}, {-1.7260909703781458e+01, -1.6724791300392337e+01, -1.6283381096937688e+01, -1.5891350549206285e+01, -1.5531380320925585e+01, -1.5194544951785256e+01, -1.4875490845359661e+01, -1.4570691174443654e+01, -1.4277668569732091e+01, -1.3994599387373768e+01, -1.3720092319274791e+01, -1.3453055491772846e+01, -1.3192612184064762e+01, -1.2938044974817329e+01, -1.2688757366462070e+01, -1.2444246609242258e+01, -1.2204083956265350e+01, -1.1967899997504619e+01, -1.1735373555229600e+01, -1.1506223133185523e+01, -1.1280200233327742e+01, -1.1057084062337088e+01, -1.0836677288618299e+01, -1.0618802604522946e+01, -1.0403299913666036e+01, -1.0190024009115621e+01, -9.9788426411218261e+00, -9.7696348969572284e+00, -9.5622898330514161e+00, -9.3567053127370503e+00, -9.1527870128321815e+00, -8.9504475698358625e+00, -8.7496058423271297e+00, -8.5501862706726577e+00, -8.3521183186851253e+00, -8.1553359846666886e+00, -7.9597773714928959e+00, -7.7653843071712023e+00, -7.5721020087422000e+00, -7.3798787835549238e+00, -7.1886657628964983e+00, -6.9984166637349920e+00, -6.8090875749762771e+00, -6.6206367651677347e+00, -6.4330245090246105e+00, -6.2462129305252470e+00, -6.0601658606325453e+00, -5.8748487079613687e+00, -5.6902283409336283e+00, -5.5062729801514685e+00, -5.3229520998798137e+00, -5.1402363376670781e+00, -4.9580974112509208e+00, -4.7765080419975057e+00, -4.5954418842104330e+00, -4.4148734597213917e+00, -4.2347780972404623e+00, -4.0551318760012771e+00, -3.8759115732862068e+00, -3.6970946154603719e+00, -3.5186590321815130e+00, -3.3405834134862555e+00, -3.1628468694827729e+00, -2.9854289924057533e+00, -2.8083098208124282e+00, -2.6314698057185479e+00, -2.4548897784909895e+00, -2.2785509203293697e+00, -2.1024347331829158e+00, -1.9265230119611116e+00, -1.7507978179074160e+00, -1.5752414530149108e+00, -1.3998364353710842e+00, -1.2245654753263127e+00, -1.0494114523869875e+00, -8.7435739273980528e-01, -6.9938644731849353e-01, -5.2448187032830795e-01, -3.4962699814701426e-01, -1.7480522852383426e-01, -0.0000000000000000e+00, 1.7480522852383426e-01, 3.4962699814701426e-01, 5.2448187032830795e-01, 6.9938644731849353e-01, 8.7435739273980528e-01, 1.0494114523869875e+00, 1.2245654753263127e+00, 1.3998364353710842e+00, 1.5752414530149108e+00, 1.7507978179074160e+00, 1.9265230119611116e+00, 2.1024347331829158e+00, 2.2785509203293697e+00, 2.4548897784909895e+00, 2.6314698057185479e+00, 2.8083098208124282e+00, 2.9854289924057533e+00, 3.1628468694827729e+00, 3.3405834134862555e+00, 3.5186590321815130e+00, 3.6970946154603719e+00, 3.8759115732862068e+00, 4.0551318760012771e+00, 4.2347780972404623e+00, 4.4148734597213917e+00, 4.5954418842104330e+00, 4.7765080419975057e+00, 4.9580974112509208e+00, 5.1402363376670781e+00, 5.3229520998798137e+00, 5.5062729801514685e+00, 5.6902283409336283e+00, 5.8748487079613687e+00, 6.0601658606325453e+00, 6.2462129305252470e+00, 6.4330245090246105e+00, 6.6206367651677347e+00, 6.8090875749762771e+00, 6.9984166637349920e+00, 7.1886657628964983e+00, 7.3798787835549238e+00, 7.5721020087422000e+00, 7.7653843071712023e+00, 7.9597773714928959e+00, 8.1553359846666886e+00, 8.3521183186851253e+00, 8.5501862706726577e+00, 8.7496058423271297e+00, 8.9504475698358625e+00, 9.1527870128321815e+00, 9.3567053127370503e+00, 9.5622898330514161e+00, 9.7696348969572284e+00, 9.9788426411218261e+00, 1.0190024009115621e+01, 1.0403299913666036e+01, 1.0618802604522946e+01, 1.0836677288618299e+01, 1.1057084062337088e+01, 1.1280200233327742e+01, 1.1506223133185523e+01, 1.1735373555229600e+01, 1.1967899997504619e+01, 1.2204083956265350e+01, 1.2444246609242258e+01, 1.2688757366462070e+01, 1.2938044974817329e+01, 1.3192612184064762e+01, 1.3453055491772846e+01, 1.3720092319274791e+01, 1.3994599387373768e+01, 1.4277668569732091e+01, 1.4570691174443654e+01, 1.4875490845359661e+01, 1.5194544951785256e+01, 1.5531380320925585e+01, 1.5891350549206285e+01, 1.6283381096937688e+01, 1.6724791300392337e+01, 1.7260909703781458e+01}, {-1.7317208433270949e+01, -1.6781666167619914e+01, -1.6340741083473855e+01, -1.5949149813561979e+01, -1.5589590133082927e+01, -1.5253145338412237e+01, -1.4934467055837311e+01, -1.4630031883570041e+01, -1.4337364850710150e+01, -1.4054644075392147e+01, -1.3780479592778537e+01, -1.3513780583944808e+01, -1.3253671176599115e+01, -1.2999434646049597e+01, -1.2750475076730016e+01, -1.2506290212533999e+01, -1.2266451730913499e+01, -1.2030590590990464e+01, -1.1798385939645330e+01, -1.1569556568885659e+01, -1.1343854238969067e+01, -1.1121058389970566e+01, -1.0900971902825360e+01, -1.0683417664825948e+01, -1.0468235759616565e+01, -1.0255281147593752e+01, -1.0044421735476904e+01, -9.8355367576951434e+00, -9.6285154098307064e+00, -9.4232556874808058e+00, -9.2196633937979797e+00, -9.0176512865137788e+00, -8.8171383410582820e+00, -8.6180491108986974e+00, -8.4203131697537437e+00, -8.2238646231301775e+00, -8.0286416788466841e+00, -7.8345862679873983e+00, -7.6416437091600784e+00, -7.4497624100959028e+00, -7.2588936015760819e+00, -7.0689910994481711e+00, -6.8800110911364190e+00, -6.6919119435819789e+00, -6.5046540299913760e+00, -6.3181995731417278e+00, -6.1325125033020340e+00, -5.9475583290919758e+00, -5.7633040198215193e+00, -5.5797178980431177e+00, -5.3967695412089913e+00, -5.2144296914634500e+00, -5.0326701727181335e+00, -4.8514638142596134e+00, -4.6707843802263858e+00, -4.4906065043681664e+00, -4.3109056295662098e+00, -4.1316579516506131e+00, -3.9528403671005403e+00, -3.7744304242568925e+00, -3.5964062777151744e+00, -3.4187466455998319e+00, -3.2414307694507918e+00, -3.0644383764788512e+00, -2.8877496439694483e+00, -2.7113451656344782e+00, -2.5352059197296661e+00, -2.3593132387707172e+00, -2.1836487806954117e+00, -2.0081945013310838e+00, -1.8329326280378133e+00, -1.6578456344072345e+00, -1.4829162159053173e+00, -1.3081272663548922e+00, -1.1334618551601847e+00, -9.5890320518127026e-01, -7.8443467117124477e-01, -6.1003971869307638e-01, -4.3570190343662574e-01, -2.6140485085923082e-01, -8.7132236075583736e-02, 8.7132236075583736e-02, 2.6140485085923082e-01, 4.3570190343662574e-01, 6.1003971869307638e-01, 7.8443467117124477e-01, 9.5890320518127026e-01, 1.1334618551601847e+00, 1.3081272663548922e+00, 1.4829162159053173e+00, 1.6578456344072345e+00, 1.8329326280378133e+00, 2.0081945013310838e+00, 2.1836487806954117e+00, 2.3593132387707172e+00, 2.5352059197296661e+00, 2.7113451656344782e+00, 2.8877496439694483e+00, 3.0644383764788512e+00, 3.2414307694507918e+00, 3.4187466455998319e+00, 3.5964062777151744e+00, 3.7744304242568925e+00, 3.9528403671005403e+00, 4.1316579516506131e+00, 4.3109056295662098e+00, 4.4906065043681664e+00, 4.6707843802263858e+00, 4.8514638142596134e+00, 5.0326701727181335e+00, 5.2144296914634500e+00, 5.3967695412089913e+00, 5.5797178980431177e+00, 5.7633040198215193e+00, 5.9475583290919758e+00, 6.1325125033020340e+00, 6.3181995731417278e+00, 6.5046540299913760e+00, 6.6919119435819789e+00, 6.8800110911364190e+00, 7.0689910994481711e+00, 7.2588936015760819e+00, 7.4497624100959028e+00, 7.6416437091600784e+00, 7.8345862679873983e+00, 8.0286416788466841e+00, 8.2238646231301775e+00, 8.4203131697537437e+00, 8.6180491108986974e+00, 8.8171383410582820e+00, 9.0176512865137788e+00, 9.2196633937979797e+00, 9.4232556874808058e+00, 9.6285154098307064e+00, 9.8355367576951434e+00, 1.0044421735476904e+01, 1.0255281147593752e+01, 1.0468235759616565e+01, 1.0683417664825948e+01, 1.0900971902825360e+01, 1.1121058389970566e+01, 1.1343854238969067e+01, 1.1569556568885659e+01, 1.1798385939645330e+01, 1.2030590590990464e+01, 1.2266451730913499e+01, 1.2506290212533999e+01, 1.2750475076730016e+01, 1.2999434646049597e+01, 1.3253671176599115e+01, 1.3513780583944808e+01, 1.3780479592778537e+01, 1.4054644075392147e+01, 1.4337364850710150e+01, 1.4630031883570041e+01, 1.4934467055837311e+01, 1.5253145338412237e+01, 1.5589590133082927e+01, 1.5949149813561979e+01, 1.6340741083473855e+01, 1.6781666167619914e+01, 1.7317208433270949e+01}, {-1.7373331107186754e+01, -1.6838360725829279e+01, -1.6397917121470808e+01, -1.6006761787526802e+01, -1.5647609491464893e+01, -1.5311552225513632e+01, -1.4993246802416799e+01, -1.4689173221989655e+01, -1.4396858895000966e+01, -1.4114483689200235e+01, -1.3840658973492838e+01, -1.3574294976135944e+01, -1.3314516667182943e+01, -1.3060608013433232e+01, -1.2811973676932878e+01, -1.2568111891415747e+01, -1.2328594755317379e+01, -1.2093053593899976e+01, -1.1861167875925814e+01, -1.1632656679158853e+01, -1.1407272019832192e+01, -1.1184793569232429e+01, -1.0965024418758787e+01, -1.0747787648671435e+01, -1.0532923520744902e+01, -1.0320287160863774e+01, -1.0109746630421466e+01, -9.9011813092421690e+00, -9.6944805303231938e+00, -9.4895424198040619e+00, -9.2862729054572402e+00, -9.0845848645331397e+00, -8.8843973875939959e+00, -8.6856351394777924e+00, -8.4882278020634931e+00, -8.2921095862957674e+00, -8.0972188031442496e+00, -7.9034974849477484e+00, -7.7108910500251024e+00, -7.5193480045954200e+00, -7.3288196769976075e+00, -7.1392599799761927e+00, -6.9506251974411839e+00, -6.7628737926408222e+00, -6.5759662351281483e+00, -6.3898648442721324e+00, -6.2045336473746264e+00, -6.0199382507162937e+00, -5.8360457220763333e+00, -5.6528244834591428e+00, -5.4702442129216378e+00, -5.2882757545322603e+00, -5.1068910356106052e+00, -4.9260629904980000e+00, -4.7457654901969706e+00, -4.5659732772932937e+00, -4.3866619056401390e+00, -4.2078076843410157e+00, -4.0293876256181580e+00, -3.8513793961965916e+00, -3.6737612718723360e+00, -3.4965120949666812e+00, -3.3196112343979944e+00, -3.1430385481283984e+00, -2.9667743477655746e+00, -2.7907993651201082e+00, -2.6150947205366424e+00, -2.4396418928328796e+00, -2.2644226906944231e+00, -2.0894192253858019e+00, -1.9146138846489213e+00, -1.7399893076698572e+00, -1.5655283610033905e+00, -1.3912141153521926e+00, -1.2170298231041317e+00, -1.0429588965369114e+00, -8.6898488660423323e-01, -6.9509146222196017e-01, -5.2126238997639096e-01, -3.4748151417981160e-01, -1.7373273720096005e-01, -0.0000000000000000e+00, 1.7373273720096005e-01, 3.4748151417981160e-01, 5.2126238997639096e-01, 6.9509146222196017e-01, 8.6898488660423323e-01, 1.0429588965369114e+00, 1.2170298231041317e+00, 1.3912141153521926e+00, 1.5655283610033905e+00, 1.7399893076698572e+00, 1.9146138846489213e+00, 2.0894192253858019e+00, 2.2644226906944231e+00, 2.4396418928328796e+00, 2.6150947205366424e+00, 2.7907993651201082e+00, 2.9667743477655746e+00, 3.1430385481283984e+00, 3.3196112343979944e+00, 3.4965120949666812e+00, 3.6737612718723360e+00, 3.8513793961965916e+00, 4.0293876256181580e+00, 4.2078076843410157e+00, 4.3866619056401390e+00, 4.5659732772932937e+00, 4.7457654901969706e+00, 4.9260629904980000e+00, 5.1068910356106052e+00, 5.2882757545322603e+00, 5.4702442129216378e+00, 5.6528244834591428e+00, 5.8360457220763333e+00, 6.0199382507162937e+00, 6.2045336473746264e+00, 6.3898648442721324e+00, 6.5759662351281483e+00, 6.7628737926408222e+00, 6.9506251974411839e+00, 7.1392599799761927e+00, 7.3288196769976075e+00, 7.5193480045954200e+00, 7.7108910500251024e+00, 7.9034974849477484e+00, 8.0972188031442496e+00, 8.2921095862957674e+00, 8.4882278020634931e+00, 8.6856351394777924e+00, 8.8843973875939959e+00, 9.0845848645331397e+00, 9.2862729054572402e+00, 9.4895424198040619e+00, 9.6944805303231938e+00, 9.9011813092421690e+00, 1.0109746630421466e+01, 1.0320287160863774e+01, 1.0532923520744902e+01, 1.0747787648671435e+01, 1.0965024418758787e+01, 1.1184793569232429e+01, 1.1407272019832192e+01, 1.1632656679158853e+01, 1.1861167875925814e+01, 1.2093053593899976e+01, 1.2328594755317379e+01, 1.2568111891415747e+01, 1.2811973676932878e+01, 1.3060608013433232e+01, 1.3314516667182943e+01, 1.3574294976135944e+01, 1.3840658973492838e+01, 1.4114483689200235e+01, 1.4396858895000966e+01, 1.4689173221989655e+01, 1.4993246802416799e+01, 1.5311552225513632e+01, 1.5647609491464893e+01, 1.6006761787526802e+01, 1.6397917121470808e+01, 1.6838360725829279e+01, 1.7373331107186754e+01}, {-1.7429279360697116e+01, -1.6894876667871738e+01, -1.6454910953817389e+01, -1.6064188260485547e+01, -1.5705440229953897e+01, -1.5369767490259161e+01, -1.5051832004816319e+01, -1.4748117151542182e+01, -1.4456152706360307e+01, -1.4174120274430678e+01, -1.3900632549018214e+01, -1.3634600798111430e+01, -1.3375150828031479e+01, -1.3121567291995134e+01, -1.2873255425338009e+01, -1.2629713947884454e+01, -1.2390515375747968e+01, -1.2155291397374004e+01, -1.1923721800726158e+01, -1.1695525946865237e+01, -1.1470456105717808e+01, -1.1248292177643179e+01, -1.1028837462481100e+01, -1.0811915231528733e+01, -1.0597365922834403e+01, -1.0385044825972880e+01, -1.0174820155259216e+01, -9.9665714341945719e+00, -9.7601881314978272e+00, -9.5555685021734451e+00, -9.3526185969451436e+00, -9.1512514109155187e+00, -8.9513861481082948e+00, -8.7529475830520980e+00, -8.5558655040914431e+00, -8.3600742258949641e+00, -8.1655121608455978e+00, -7.9721214407712111e+00, -7.7798475819041020e+00, -7.5886391871177059e+00, -7.3984476804351802e+00, -7.2092270695808969e+00, -7.0209337329860251e+00, -6.8335262281900011e+00, -6.6469651190213561e+00, -6.4612128193108518e+00, -6.2762334512001194e+00, -6.0919927163706555e+00, -5.9084577787394661e+00, -5.7255971573558835e+00, -5.5433806283944191e+00, -5.3617791352758264e+00, -5.1807647060662454e+00, -5.0003103774057065e+00, -4.8203901243047591e+00, -4.6409787952237167e+00, -4.4620520519147870e+00, -4.2835863135645020e+00, -4.1055587048237943e+00, -3.9279470073566172e+00, -3.7507296145762479e+00, -3.5738854892718694e+00, -3.3973941238575383e+00, -3.2212355030015671e+00, -3.0453900684172543e+00, -2.8698386856160685e+00, -2.6945626124422972e+00, -2.5195434692239367e+00, -2.3447632103886216e+00, -2.1702040974057377e+00, -1.9958486729268685e+00, -1.8216797360063830e+00, -1.6476803182925728e+00, -1.4738336610872771e+00, -1.3001231931786021e+00, -1.1265325093571319e+00, -9.5304534953113307e-01, -7.7964557836059989e-01, -6.0631716533377134e-01, -4.3304416521289407e-01, -2.5981069877863450e-01, -8.6600933804640304e-02, 8.6600933804640304e-02, 2.5981069877863450e-01, 4.3304416521289407e-01, 6.0631716533377134e-01, 7.7964557836059989e-01, 9.5304534953113307e-01, 1.1265325093571319e+00, 1.3001231931786021e+00, 1.4738336610872771e+00, 1.6476803182925728e+00, 1.8216797360063830e+00, 1.9958486729268685e+00, 2.1702040974057377e+00, 2.3447632103886216e+00, 2.5195434692239367e+00, 2.6945626124422972e+00, 2.8698386856160685e+00, 3.0453900684172543e+00, 3.2212355030015671e+00, 3.3973941238575383e+00, 3.5738854892718694e+00, 3.7507296145762479e+00, 3.9279470073566172e+00, 4.1055587048237943e+00, 4.2835863135645020e+00, 4.4620520519147870e+00, 4.6409787952237167e+00, 4.8203901243047591e+00, 5.0003103774057065e+00, 5.1807647060662454e+00, 5.3617791352758264e+00, 5.5433806283944191e+00, 5.7255971573558835e+00, 5.9084577787394661e+00, 6.0919927163706555e+00, 6.2762334512001194e+00, 6.4612128193108518e+00, 6.6469651190213561e+00, 6.8335262281900011e+00, 7.0209337329860251e+00, 7.2092270695808969e+00, 7.3984476804351802e+00, 7.5886391871177059e+00, 7.7798475819041020e+00, 7.9721214407712111e+00, 8.1655121608455978e+00, 8.3600742258949641e+00, 8.5558655040914431e+00, 8.7529475830520980e+00, 8.9513861481082948e+00, 9.1512514109155187e+00, 9.3526185969451436e+00, 9.5555685021734451e+00, 9.7601881314978272e+00, 9.9665714341945719e+00, 1.0174820155259216e+01, 1.0385044825972880e+01, 1.0597365922834403e+01, 1.0811915231528733e+01, 1.1028837462481100e+01, 1.1248292177643179e+01, 1.1470456105717808e+01, 1.1695525946865237e+01, 1.1923721800726158e+01, 1.2155291397374004e+01, 1.2390515375747968e+01, 1.2629713947884454e+01, 1.2873255425338009e+01, 1.3121567291995134e+01, 1.3375150828031479e+01, 1.3634600798111430e+01, 1.3900632549018214e+01, 1.4174120274430678e+01, 1.4456152706360307e+01, 1.4748117151542182e+01, 1.5051832004816319e+01, 1.5369767490259161e+01, 1.5705440229953897e+01, 1.6064188260485547e+01, 1.6454910953817389e+01, 1.6894876667871738e+01, 1.7429279360697116e+01}, {-1.7485054803857970e+01, -1.6951215660353082e+01, -1.6511724296161706e+01, -1.6121430993647511e+01, -1.5763084153353320e+01, -1.5427792979852288e+01, -1.5110224551907818e+01, -1.4806865602342286e+01, -1.4515248255936989e+01, -1.4233555843220696e+01, -1.3960402372562056e+01, -1.3694700144334103e+01, -1.3435575795134914e+01, -1.3182314659599264e+01, -1.2934322542095073e+01, -1.2691098644846306e+01, -1.2452215898392630e+01, -1.2217306351455802e+01, -1.1986050108567399e+01, -1.1758166811670554e+01, -1.1533408982146776e+01, -1.1311556747331544e+01, -1.1092413613523263e+01, -1.0875803041166620e+01, -1.0661565642768281e+01, -1.0449556869836458e+01, -1.0239645087896863e+01, -1.0031709962451384e+01, -9.8256410962894503e+00, -9.6213368716463528e+00, -9.4187034605725390e+00, -9.2176539744013386e+00, -9.0181077289936873e+00, -8.8199896069364012e+00, -8.6232295013939773e+00, -8.4277618290957275e+00, -8.2335251021525675e+00, -8.0404615501699581e+00, -7.8485167855520830e+00, -7.6576395060512166e+00, -7.4677812295616199e+00, -7.2788960569330223e+00, -7.0909404592182668e+00, -6.9038730862998348e+00, -6.7176545942812487e+00, -6.5322474893984905e+00, -6.3476159865165220e+00, -6.1637258805374548e+00, -5.9805444292681393e+00, -5.7980402464829925e+00, -5.6161832040781530e+00, -5.4349443423501533e+00, -5.2542957875499878e+00, -5.0742106759647410e+00, -4.8946630838663463e+00, -4.7156279627427748e+00, -4.5370810792926148e+00, -4.3589989597211884e+00, -4.1813588379261919e+00, -4.0041386072044292e+00, -3.8273167751493955e+00, -3.6508724214429682e+00, -3.4747851582739164e+00, -3.2990350931419172e+00, -3.1236027938286419e+00, -2.9484692553376957e+00, -2.7736158686231027e+00, -2.5990243909418167e+00, -2.4246769176797933e+00, -2.2505558555135576e+00, -2.0766438967802112e+00, -1.9029239949385686e+00, -1.7293793410127316e+00, -1.5559933409170248e+00, -1.3827495935679281e+00, -1.2096318696945301e+00, -1.0366240912641824e+00, -8.6371031144450516e-01, -6.9087469502674481e-01, -5.1810149923876170e-01, -3.4537505487866837e-01, -1.7267974770236652e-01, -0.0000000000000000e+00, 1.7267974770236652e-01, 3.4537505487866837e-01, 5.1810149923876170e-01, 6.9087469502674481e-01, 8.6371031144450516e-01, 1.0366240912641824e+00, 1.2096318696945301e+00, 1.3827495935679281e+00, 1.5559933409170248e+00, 1.7293793410127316e+00, 1.9029239949385686e+00, 2.0766438967802112e+00, 2.2505558555135576e+00, 2.4246769176797933e+00, 2.5990243909418167e+00, 2.7736158686231027e+00, 2.9484692553376957e+00, 3.1236027938286419e+00, 3.2990350931419172e+00, 3.4747851582739164e+00, 3.6508724214429682e+00, 3.8273167751493955e+00, 4.0041386072044292e+00, 4.1813588379261919e+00, 4.3589989597211884e+00, 4.5370810792926148e+00, 4.7156279627427748e+00, 4.8946630838663463e+00, 5.0742106759647410e+00, 5.2542957875499878e+00, 5.4349443423501533e+00, 5.6161832040781530e+00, 5.7980402464829925e+00, 5.9805444292681393e+00, 6.1637258805374548e+00, 6.3476159865165220e+00, 6.5322474893984905e+00, 6.7176545942812487e+00, 6.9038730862998348e+00, 7.0909404592182668e+00, 7.2788960569330223e+00, 7.4677812295616199e+00, 7.6576395060512166e+00, 7.8485167855520830e+00, 8.0404615501699581e+00, 8.2335251021525675e+00, 8.4277618290957275e+00, 8.6232295013939773e+00, 8.8199896069364012e+00, 9.0181077289936873e+00, 9.2176539744013386e+00, 9.4187034605725390e+00, 9.6213368716463528e+00, 9.8256410962894503e+00, 1.0031709962451384e+01, 1.0239645087896863e+01, 1.0449556869836458e+01, 1.0661565642768281e+01, 1.0875803041166620e+01, 1.1092413613523263e+01, 1.1311556747331544e+01, 1.1533408982146776e+01, 1.1758166811670554e+01, 1.1986050108567399e+01, 1.2217306351455802e+01, 1.2452215898392630e+01, 1.2691098644846306e+01, 1.2934322542095073e+01, 1.3182314659599264e+01, 1.3435575795134914e+01, 1.3694700144334103e+01, 1.3960402372562056e+01, 1.4233555843220696e+01, 1.4515248255936989e+01, 1.4806865602342286e+01, 1.5110224551907818e+01, 1.5427792979852288e+01, 1.5763084153353320e+01, 1.6121430993647511e+01, 1.6511724296161706e+01, 1.6951215660353082e+01, 1.7485054803857970e+01}, {-1.7540659022148994e+01, -1.7007379344198675e+01, -1.6568358837502078e+01, -1.6178491720661924e+01, -1.5820543038026845e+01, -1.5485630512193200e+01, -1.5168426302403656e+01, -1.4865420473490115e+01, -1.4574147483007465e+01, -1.4292792374971157e+01, -1.4019970463722631e+01, -1.3754595074773901e+01, -1.3495793669093878e+01, -1.3242852257808744e+01, -1.2995177210125478e+01, -1.2752268207034200e+01, -1.2513698590301434e+01, -1.2279100766067012e+01, -1.2048155152843032e+01, -1.1820581671084192e+01, -1.1596133091430600e+01, -1.1374589766138451e+01, -1.1155755406023257e+01, -1.0939453658827642e+01, -1.0725525309740862e+01, -1.0513825970487574e+01, -1.0304224156133158e+01, -1.0096599672544393e+01, -9.8908422549712061e+00, -9.6868504112873062e+00, -9.4845304332878886e+00, -9.2837955469590963e+00, -9.0845651784194441e+00, -8.8867643167273460e+00, -8.6903229582689274e+00, -8.4951756202195732e+00, -8.3012609127831123e+00, -8.1085211616830808e+00, -7.9169020738077709e+00, -7.7263524400685295e+00, -7.5368238704753843e+00, -7.3482705572089442e+00, -7.1606490621065957e+00, -6.9739181255105622e+00, -6.7880384938663552e+00, -6.6029727638288866e+00, -6.4186852409432520e+00, -6.2351418112283552e+00, -6.0523098242126343e+00, -5.8701579861589899e+00, -5.6886562623761669e+00, -5.5077757876508500e+00, -5.3274887839522851e+00, -5.1477684846624596e+00, -4.9685890646722539e+00, -4.7899255757595700e+00, -4.6117538867311527e+00, -4.4340506278668892e+00, -4.2567931392552376e+00, -4.0799594226519913e+00, -3.9035280965327215e+00, -3.7274783540427840e+00, -3.5517899235782049e+00, -3.3764430317567267e+00, -3.2014183685612045e+00, -3.0266970544577654e+00, -2.8522606093090528e+00, -2.6780909229187282e+00, -2.5041702270574335e+00, -2.3304810688329010e+00, -2.1570062852778933e+00, -1.9837289790394881e+00, -1.8106324950618549e+00, -1.6377003981623639e+00, -1.4649164514076216e+00, -1.2922645952019900e+00, -1.1197289270063837e+00, -9.4729368160967065e-01, -7.7494321187896786e-01, -6.0266196991848653e-01, -4.3043448856942984e-01, -2.5824536318581770e-01, -8.6079233622990678e-02, 8.6079233622990678e-02, 2.5824536318581770e-01, 4.3043448856942984e-01, 6.0266196991848653e-01, 7.7494321187896786e-01, 9.4729368160967065e-01, 1.1197289270063837e+00, 1.2922645952019900e+00, 1.4649164514076216e+00, 1.6377003981623639e+00, 1.8106324950618549e+00, 1.9837289790394881e+00, 2.1570062852778933e+00, 2.3304810688329010e+00, 2.5041702270574335e+00, 2.6780909229187282e+00, 2.8522606093090528e+00, 3.0266970544577654e+00, 3.2014183685612045e+00, 3.3764430317567267e+00, 3.5517899235782049e+00, 3.7274783540427840e+00, 3.9035280965327215e+00, 4.0799594226519913e+00, 4.2567931392552376e+00, 4.4340506278668892e+00, 4.6117538867311527e+00, 4.7899255757595700e+00, 4.9685890646722539e+00, 5.1477684846624596e+00, 5.3274887839522851e+00, 5.5077757876508500e+00, 5.6886562623761669e+00, 5.8701579861589899e+00, 6.0523098242126343e+00, 6.2351418112283552e+00, 6.4186852409432520e+00, 6.6029727638288866e+00, 6.7880384938663552e+00, 6.9739181255105622e+00, 7.1606490621065957e+00, 7.3482705572089442e+00, 7.5368238704753843e+00, 7.7263524400685295e+00, 7.9169020738077709e+00, 8.1085211616830808e+00, 8.3012609127831123e+00, 8.4951756202195732e+00, 8.6903229582689274e+00, 8.8867643167273460e+00, 9.0845651784194441e+00, 9.2837955469590963e+00, 9.4845304332878886e+00, 9.6868504112873062e+00, 9.8908422549712061e+00, 1.0096599672544393e+01, 1.0304224156133158e+01, 1.0513825970487574e+01, 1.0725525309740862e+01, 1.0939453658827642e+01, 1.1155755406023257e+01, 1.1374589766138451e+01, 1.1596133091430600e+01, 1.1820581671084192e+01, 1.2048155152843032e+01, 1.2279100766067012e+01, 1.2513698590301434e+01, 1.2752268207034200e+01, 1.2995177210125478e+01, 1.3242852257808744e+01, 1.3495793669093878e+01, 1.3754595074773901e+01, 1.4019970463722631e+01, 1.4292792374971157e+01, 1.4574147483007465e+01, 1.4865420473490115e+01, 1.5168426302403656e+01, 1.5485630512193200e+01, 1.5820543038026845e+01, 1.6178491720661924e+01, 1.6568358837502078e+01, 1.7007379344198675e+01, 1.7540659022148994e+01}, {-1.7596093576995067e+01, -1.7063369335203092e+01, -1.6624816240761632e+01, -1.6235372148216229e+01, -1.5877818632519856e+01, -1.5543281876523103e+01, -1.5226439085523806e+01, -1.4923783633761518e+01, -1.4632852295689380e+01, -1.4351831817083784e+01, -1.4079338809250348e+01, -1.3814287615693701e+01, -1.3555806515930390e+01, -1.3303182192722531e+01, -1.3055821575985398e+01, -1.2813224821897842e+01, -1.2574965680305057e+01, -1.2340676911954159e+01, -1.2110039246794949e+01, -1.1882772881465453e+01, -1.1658630833708994e+01, -1.1437393678686862e+01, -1.1218865329829219e+01, -1.1002869620365653e+01, -1.0789247506430682e+01, -1.0577854758286833e+01, -1.0368560038906804e+01, -1.0161243292925425e+01, -9.9557943864826086e+00, -9.7521119515382608e+00, -9.5501023980913669e+00, -9.3496790652448780e+00, -9.1507614878382224e+00, -8.9532747598589513e+00, -8.7571489793618653e+00, -8.5623187624005972e+00, -8.3687228156851035e+00, -8.1763035594473781e+00, -7.9850067934236462e+00, -7.7947814000180404e+00, -7.6055790796564340e+00, -7.4173541141133637e+00, -7.2300631542333695e+00, -7.0436650289972214e+00, -6.8581205733240118e+00, -6.6733924723685520e+00, -6.4894451203829293e+00, -6.3062444924720467e+00, -6.1237580277938539e+00, -5.9419545229426243e+00, -5.7608040344137255e+00, -5.5802777891851223e+00, -5.4003481025684028e+00, -5.2209883025831942e+00, -5.0421726601961838e+00, -4.8638763248414749e+00, -4.6860752647046970e+00, -4.5087462113102941e+00, -4.3318666080012935e+00, -4.1554145619443341e+00, -3.9793687993309228e+00, -3.8037086234793556e+00, -3.6284138755712148e+00, -3.4534648977822986e+00, -3.2788424985907505e+00, -3.1045279200654083e+00, -2.9305028069552952e+00, -2.7567491774170563e+00, -2.5832493952312059e+00, -2.4099861433705372e+00, -2.2369423987951111e+00, -2.0641014083580762e+00, -1.8914466657152740e+00, -1.7189618891393004e+00, -1.5466310001455315e+00, -1.3744381028436181e+00, -1.2023674639332740e+00, -1.0304034932677821e+00, -8.5853072491269411e-01, -6.8673379863064854e-01, -5.1499744172618944e-01, -3.4330645118694048e-01, -1.7164567605949776e-01, -0.0000000000000000e+00, 1.7164567605949776e-01, 3.4330645118694048e-01, 5.1499744172618944e-01, 6.8673379863064854e-01, 8.5853072491269411e-01, 1.0304034932677821e+00, 1.2023674639332740e+00, 1.3744381028436181e+00, 1.5466310001455315e+00, 1.7189618891393004e+00, 1.8914466657152740e+00, 2.0641014083580762e+00, 2.2369423987951111e+00, 2.4099861433705372e+00, 2.5832493952312059e+00, 2.7567491774170563e+00, 2.9305028069552952e+00, 3.1045279200654083e+00, 3.2788424985907505e+00, 3.4534648977822986e+00, 3.6284138755712148e+00, 3.8037086234793556e+00, 3.9793687993309228e+00, 4.1554145619443341e+00, 4.3318666080012935e+00, 4.5087462113102941e+00, 4.6860752647046970e+00, 4.8638763248414749e+00, 5.0421726601961838e+00, 5.2209883025831942e+00, 5.4003481025684028e+00, 5.5802777891851223e+00, 5.7608040344137255e+00, 5.9419545229426243e+00, 6.1237580277938539e+00, 6.3062444924720467e+00, 6.4894451203829293e+00, 6.6733924723685520e+00, 6.8581205733240118e+00, 7.0436650289972214e+00, 7.2300631542333695e+00, 7.4173541141133637e+00, 7.6055790796564340e+00, 7.7947814000180404e+00, 7.9850067934236462e+00, 8.1763035594473781e+00, 8.3687228156851035e+00, 8.5623187624005972e+00, 8.7571489793618653e+00, 8.9532747598589513e+00, 9.1507614878382224e+00, 9.3496790652448780e+00, 9.5501023980913669e+00, 9.7521119515382608e+00, 9.9557943864826086e+00, 1.0161243292925425e+01, 1.0368560038906804e+01, 1.0577854758286833e+01, 1.0789247506430682e+01, 1.1002869620365653e+01, 1.1218865329829219e+01, 1.1437393678686862e+01, 1.1658630833708994e+01, 1.1882772881465453e+01, 1.2110039246794949e+01, 1.2340676911954159e+01, 1.2574965680305057e+01, 1.2813224821897842e+01, 1.3055821575985398e+01, 1.3303182192722531e+01, 1.3555806515930390e+01, 1.3814287615693701e+01, 1.4079338809250348e+01, 1.4351831817083784e+01, 1.4632852295689380e+01, 1.4923783633761518e+01, 1.5226439085523806e+01, 1.5543281876523103e+01, 1.5877818632519856e+01, 1.6235372148216229e+01, 1.6624816240761632e+01, 1.7063369335203092e+01, 1.7596093576995067e+01}, {-1.7651360006273592e+01, -1.7119187224564673e+01, -1.6681098143347068e+01, -1.6292073956617820e+01, -1.5934912658163535e+01, -1.5600748834050473e+01, -1.5284264701644213e+01, -1.4981956922278711e+01, -1.4691364571634727e+01, -1.4410676085677181e+01, -1.4138509363787067e+01, -1.3873779760412367e+01, -1.3615616367875141e+01, -1.3363306535787522e+01, -1.3116257750703349e+01, -1.2873970640467419e+01, -1.2636019359905287e+01, -1.2402037021606754e+01, -1.2171704664459938e+01, -1.1944742758999288e+01, -1.1720904567955738e+01, -1.1499970887418726e+01, -1.1281745831568482e+01, -1.1066053417347991e+01, -1.0852734770136896e+01, -1.0641645817094179e+01, -1.0432655367504838e+01, -1.0225643503212597e+01, -1.0020500219714993e+01, -9.8171242715446922e+00, -9.6154221854030180e+00, -9.4153074120141333e+00, -9.2166995934430851e+00, -9.0195239271065724e+00, -8.8237106112187824e+00, -8.6291943591887517e+00, -8.4359139726921839e+00, -8.2438119649078239e+00, -8.0528342268332285e+00, -7.8629297307503139e+00, -7.6740502658540599e+00, -7.4861502018311290e+00, -7.2991862768130868e+00, -7.1131174066575413e+00, -6.9279045129506267e+00, -6.7435103674923891e+00, -6.5598994513357987e+00, -6.3770378267108159e+00, -6.1948930203856341e+00, -6.0134339172047717e+00, -5.8326306627035311e+00, -5.6524545738351115e+00, -5.4728780569640936e+00, -5.2938745323809906e+00, -5.1154183646798366e+00, -4.9374847984163193e+00, -4.7600498985294708e+00, -4.5830904950670517e+00, -4.4065841318044781e+00, -4.2305090183906966e+00, -4.0548439856925214e+00, -3.8795684440424409e+00, -3.7046623441243547e+00, -3.5301061402576419e+00, -3.3558807558629016e+00, -3.1819675509129310e+00, -3.0083482911904582e+00, -2.8350051191900167e+00, -2.6619205265154431e+00, -2.4890773276369966e+00, -2.3164586348831824e+00, -2.1440478345522327e+00, -1.9718285640369488e+00, -1.7997846898643619e+00, -1.6279002865585475e+00, -1.4561596162410049e+00, -1.2845471088883613e+00, -1.1130473431718593e+00, -9.4164502780718806e-01, -7.7032498334676469e-01, -5.9907212434961710e-01, -4.2787144186658727e-01, -2.5670798618070745e-01, -8.5566849744303619e-02, 8.5566849744303619e-02, 2.5670798618070745e-01, 4.2787144186658727e-01, 5.9907212434961710e-01, 7.7032498334676469e-01, 9.4164502780718806e-01, 1.1130473431718593e+00, 1.2845471088883613e+00, 1.4561596162410049e+00, 1.6279002865585475e+00, 1.7997846898643619e+00, 1.9718285640369488e+00, 2.1440478345522327e+00, 2.3164586348831824e+00, 2.4890773276369966e+00, 2.6619205265154431e+00, 2.8350051191900167e+00, 3.0083482911904582e+00, 3.1819675509129310e+00, 3.3558807558629016e+00, 3.5301061402576419e+00, 3.7046623441243547e+00, 3.8795684440424409e+00, 4.0548439856925214e+00, 4.2305090183906966e+00, 4.4065841318044781e+00, 4.5830904950670517e+00, 4.7600498985294708e+00, 4.9374847984163193e+00, 5.1154183646798366e+00, 5.2938745323809906e+00, 5.4728780569640936e+00, 5.6524545738351115e+00, 5.8326306627035311e+00, 6.0134339172047717e+00, 6.1948930203856341e+00, 6.3770378267108159e+00, 6.5598994513357987e+00, 6.7435103674923891e+00, 6.9279045129506267e+00, 7.1131174066575413e+00, 7.2991862768130868e+00, 7.4861502018311290e+00, 7.6740502658540599e+00, 7.8629297307503139e+00, 8.0528342268332285e+00, 8.2438119649078239e+00, 8.4359139726921839e+00, 8.6291943591887517e+00, 8.8237106112187824e+00, 9.0195239271065724e+00, 9.2166995934430851e+00, 9.4153074120141333e+00, 9.6154221854030180e+00, 9.8171242715446922e+00, 1.0020500219714993e+01, 1.0225643503212597e+01, 1.0432655367504838e+01, 1.0641645817094179e+01, 1.0852734770136896e+01, 1.1066053417347991e+01, 1.1281745831568482e+01, 1.1499970887418726e+01, 1.1720904567955738e+01, 1.1944742758999288e+01, 1.2171704664459938e+01, 1.2402037021606754e+01, 1.2636019359905287e+01, 1.2873970640467419e+01, 1.3116257750703349e+01, 1.3363306535787522e+01, 1.3615616367875141e+01, 1.3873779760412367e+01, 1.4138509363787067e+01, 1.4410676085677181e+01, 1.4691364571634727e+01, 1.4981956922278711e+01, 1.5284264701644213e+01, 1.5600748834050473e+01, 1.5934912658163535e+01, 1.6292073956617820e+01, 1.6681098143347068e+01, 1.7119187224564673e+01, 1.7651360006273592e+01}, {-1.7706459824808160e+01, -1.7174834579405605e+01, -1.6737206157692185e+01, -1.6348598800359760e+01, -1.5991826809662236e+01, -1.5658033118559841e+01, -1.5341904922927041e+01, -1.5039942149162044e+01, -1.4749686158703426e+01, -1.4469327066282485e+01, -1.4197484050584235e+01, -1.3933073470045795e+01, -1.3675225224131985e+01, -1.3423227324587016e+01, -1.3176487810593191e+01, -1.2934507778191829e+01, -1.2696861784139129e+01, -1.2463183290148008e+01, -1.2233153641587771e+01, -1.2006493580642585e+01, -1.1782956612954054e+01, -1.1562323753600294e+01, -1.1344399315683788e+01, -1.1129007498123606e+01, -1.0915989593880358e+01, -1.0705201685404040e+01, -1.0496512726733012e+01, -1.0289802935397134e+01, -1.0084962434756044e+01, -9.8818901004391417e+00, -9.6804925743867667e+00, -9.4806834174876062e+00, -9.2823823775768961e+00, -9.0855147540413785e+00, -8.8900108437873531e+00, -8.6958054560996842e+00, -8.5028374861240277e+00, -8.3110495384702450e+00, -8.1203875938581902e+00, -7.9308007128818385e+00, -7.7422407719095485e+00, -7.5546622269112049e+00, -7.3680219016401658e+00, -7.1822787971261874e+00, -6.9973939198751642e+00, -6.8133301265393582e+00, -6.6300519831306728e+00, -6.4475256371099929e+00, -6.2657187009061461e+00, -6.0846001456053820e+00, -5.9041402037120223e+00, -5.7243102800175727e+00, -5.5450828697328980e+00, -5.3664314831390003e+00, -5.1883305760991361e+00, -5.0107554858504457e+00, -4.8336823715588126e+00, -4.6570881591776718e+00, -4.4809504902012192e+00, -4.3052476739459955e+00, -4.1299586430328983e+00, -3.9550629117751774e+00, -3.7805405372073957e+00, -3.6063720825162893e+00, -3.4325385826573980e+00, -3.2590215119615689e+00, -3.0858027535533901e+00, -2.9128645704195151e+00, -2.7401895779789363e+00, -2.5677607180197990e+00, -2.3955612338784800e+00, -2.2235746467465418e+00, -2.0517847329999523e+00, -1.8801755024527722e+00, -1.7087311774444227e+00, -1.5374361726757684e+00, -1.3662750757146653e+00, -1.1952326280963763e+00, -1.0242937069484293e+00, -8.5344330707311145e-01, -6.8266652342392853e-01, -5.1194853391500583e-01, -3.4127458250465148e-01, -1.7062996249611376e-01, -0.0000000000000000e+00, 1.7062996249611376e-01, 3.4127458250465148e-01, 5.1194853391500583e-01, 6.8266652342392853e-01, 8.5344330707311145e-01, 1.0242937069484293e+00, 1.1952326280963763e+00, 1.3662750757146653e+00, 1.5374361726757684e+00, 1.7087311774444227e+00, 1.8801755024527722e+00, 2.0517847329999523e+00, 2.2235746467465418e+00, 2.3955612338784800e+00, 2.5677607180197990e+00, 2.7401895779789363e+00, 2.9128645704195151e+00, 3.0858027535533901e+00, 3.2590215119615689e+00, 3.4325385826573980e+00, 3.6063720825162893e+00, 3.7805405372073957e+00, 3.9550629117751774e+00, 4.1299586430328983e+00, 4.3052476739459955e+00, 4.4809504902012192e+00, 4.6570881591776718e+00, 4.8336823715588126e+00, 5.0107554858504457e+00, 5.1883305760991361e+00, 5.3664314831390003e+00, 5.5450828697328980e+00, 5.7243102800175727e+00, 5.9041402037120223e+00, 6.0846001456053820e+00, 6.2657187009061461e+00, 6.4475256371099929e+00, 6.6300519831306728e+00, 6.8133301265393582e+00, 6.9973939198751642e+00, 7.1822787971261874e+00, 7.3680219016401658e+00, 7.5546622269112049e+00, 7.7422407719095485e+00, 7.9308007128818385e+00, 8.1203875938581902e+00, 8.3110495384702450e+00, 8.5028374861240277e+00, 8.6958054560996842e+00, 8.8900108437873531e+00, 9.0855147540413785e+00, 9.2823823775768961e+00, 9.4806834174876062e+00, 9.6804925743867667e+00, 9.8818901004391417e+00, 1.0084962434756044e+01, 1.0289802935397134e+01, 1.0496512726733012e+01, 1.0705201685404040e+01, 1.0915989593880358e+01, 1.1129007498123606e+01, 1.1344399315683788e+01, 1.1562323753600294e+01, 1.1782956612954054e+01, 1.2006493580642585e+01, 1.2233153641587771e+01, 1.2463183290148008e+01, 1.2696861784139129e+01, 1.2934507778191829e+01, 1.3176487810593191e+01, 1.3423227324587016e+01, 1.3675225224131985e+01, 1.3933073470045795e+01, 1.4197484050584235e+01, 1.4469327066282485e+01, 1.4749686158703426e+01, 1.5039942149162044e+01, 1.5341904922927041e+01, 1.5658033118559841e+01, 1.5991826809662236e+01, 1.6348598800359760e+01, 1.6737206157692185e+01, 1.7174834579405605e+01, 1.7706459824808160e+01}, {-1.7761394524848996e+01, -1.7230312943277969e+01, -1.6793141871786613e+01, -1.6404948308671031e+01, -1.6048562755664683e+01, -1.5715136437003761e+01, -1.5399361493933315e+01, -1.5097741096163510e+01, -1.4807818875617881e+01, -1.4527786614519313e+01, -1.4256264762200541e+01, -1.3992170674226745e+01, -1.3734635051620387e+01, -1.3482946563606328e+01, -1.3236513798043475e+01, -1.2994838315752334e+01, -1.2757495072417459e+01, -1.2524117876199165e+01, -1.2294388376531968e+01, -1.2068027585042133e+01, -1.1844789248242524e+01, -1.1624454598296943e+01, -1.1406828145437910e+01, -1.1191734268858408e+01, -1.0979014427470727e+01, -1.0768524857445218e+01, -1.0560134656049588e+01, -1.0353724175012228e+01, -1.0149183664094940e+01, -9.9464121185839414e+00, -9.7453162942320208e+00, -9.5458098606732449e+00, -9.3478126700959958e+00, -9.1512501224373288e+00, -8.9560526118688415e+00, -8.7621550421132515e+00, -8.5694964003332892e+00, -8.3780193810985182e+00, -8.1876700533578219e+00, -7.9983975644987861e+00, -7.8101538765164022e+00, -7.6228935300856273e+00, -7.4365734329690358e+00, -7.2511526697184987e+00, -7.0665923300691791e+00, -6.8828553537915784e+00, -6.6999063900760145e+00, -6.5177116697841271e+00, -6.3362388891223835e+00, -6.1554571034797059e+00, -5.9753366303309603e+00, -5.7958489602446139e+00, -5.6169666751500360e+00, -5.4386633731207876e+00, -5.2609135990173996e+00, -5.0836927804084810e+00, -4.9069771682545298e+00, -4.7307437818957530e+00, -4.5549703579349439e+00, -4.3796353026499011e+00, -4.2047176476080219e+00, -4.0301970081890968e+00, -3.8560535447518163e+00, -3.6822679262054381e+00, -3.5088212957709741e+00, -3.3356952387365157e+00, -3.1628717520292895e+00, -2.9903332154429094e+00, -2.8180623643724516e+00, -2.6460422639225052e+00, -2.4742562842645146e+00, -2.3026880771296399e+00, -2.1313215533321839e+00, -1.9601408612264668e+00, -1.7891303660069930e+00, -1.6182746297679145e+00, -1.4475583922432660e+00, -1.2769665521542517e+00, -1.1064841490940971e+00, -9.3609634588467550e-01, -7.6578841134230902e-01, -5.9554570339290602e-01, -4.2535365247890039e-01, -2.5519774520239308e-01, -8.5063508150433453e-02, 8.5063508150433453e-02, 2.5519774520239308e-01, 4.2535365247890039e-01, 5.9554570339290602e-01, 7.6578841134230902e-01, 9.3609634588467550e-01, 1.1064841490940971e+00, 1.2769665521542517e+00, 1.4475583922432660e+00, 1.6182746297679145e+00, 1.7891303660069930e+00, 1.9601408612264668e+00, 2.1313215533321839e+00, 2.3026880771296399e+00, 2.4742562842645146e+00, 2.6460422639225052e+00, 2.8180623643724516e+00, 2.9903332154429094e+00, 3.1628717520292895e+00, 3.3356952387365157e+00, 3.5088212957709741e+00, 3.6822679262054381e+00, 3.8560535447518163e+00, 4.0301970081890968e+00, 4.2047176476080219e+00, 4.3796353026499011e+00, 4.5549703579349439e+00, 4.7307437818957530e+00, 4.9069771682545298e+00, 5.0836927804084810e+00, 5.2609135990173996e+00, 5.4386633731207876e+00, 5.6169666751500360e+00, 5.7958489602446139e+00, 5.9753366303309603e+00, 6.1554571034797059e+00, 6.3362388891223835e+00, 6.5177116697841271e+00, 6.6999063900760145e+00, 6.8828553537915784e+00, 7.0665923300691791e+00, 7.2511526697184987e+00, 7.4365734329690358e+00, 7.6228935300856273e+00, 7.8101538765164022e+00, 7.9983975644987861e+00, 8.1876700533578219e+00, 8.3780193810985182e+00, 8.5694964003332892e+00, 8.7621550421132515e+00, 8.9560526118688415e+00, 9.1512501224373288e+00, 9.3478126700959958e+00, 9.5458098606732449e+00, 9.7453162942320208e+00, 9.9464121185839414e+00, 1.0149183664094940e+01, 1.0353724175012228e+01, 1.0560134656049588e+01, 1.0768524857445218e+01, 1.0979014427470727e+01, 1.1191734268858408e+01, 1.1406828145437910e+01, 1.1624454598296943e+01, 1.1844789248242524e+01, 1.2068027585042133e+01, 1.2294388376531968e+01, 1.2524117876199165e+01, 1.2757495072417459e+01, 1.2994838315752334e+01, 1.3236513798043475e+01, 1.3482946563606328e+01, 1.3734635051620387e+01, 1.3992170674226745e+01, 1.4256264762200541e+01, 1.4527786614519313e+01, 1.4807818875617881e+01, 1.5097741096163510e+01, 1.5399361493933315e+01, 1.5715136437003761e+01, 1.6048562755664683e+01, 1.6404948308671031e+01, 1.6793141871786613e+01, 1.7230312943277969e+01, 1.7761394524848996e+01}, {-1.7816165576540595e+01, -1.7285623836656182e+01, -1.6848906849690259e+01, -1.6461124086051807e+01, -1.6105122139319558e+01, -1.5772060470078458e+01, -1.5456636132218662e+01, -1.5155355517282629e+01, -1.4865764512599243e+01, -1.4586056556752672e+01, -1.4314853361179868e+01, -1.4051073271804183e+01, -1.3793847785696649e+01, -1.3542466224976369e+01, -1.3296337722283933e+01, -1.3054964299852571e+01, -1.2817921309339152e+01, -1.2584842902718409e+01, -1.2355411031114167e+01, -1.2129346973425209e+01, -1.1906404715032753e+01, -1.1686365703318645e+01, -1.1469034643887829e+01, -1.1254236094539081e+01, -1.1041811678540856e+01, -1.0831617784246889e+01, -1.0623523650663971e+01, -1.0417409762265434e+01, -1.0213166493789654e+01, -1.0010692958774635e+01, -9.8098960253945080e+00, -9.6106894706457702e+00, -9.4129932496899222e+00, -9.2167328616325275e+00, -9.0218387965226103e+00, -8.8282460511228340e+00, -8.6358937032013543e+00, -8.4447245358586134e+00, -8.2546847048231751e+00, -8.0657234428032414e+00, -7.8777927959207110e+00, -7.6908473880261887e+00, -7.5048442093293950e+00, -7.3197424263067070e+00, -7.1355032102865055e+00, -6.9520895824801361e+00, -6.7694662735346460e+00, -6.5875995959434990e+00, -6.4064573278715784e+00, -6.2260086071378540e+00, -6.0462238342585293e+00, -5.8670745835899512e+00, -5.6885335217276216e+00, -5.5105743324184848e+00, -5.3331716473306852e+00, -5.1563009821003343e+00, -4.9799386771402681e+00, -4.8040618427527138e+00, -4.6286483081374303e+00, -4.4536765739303981e+00, -4.2791257679461268e+00, -4.1049756038301792e+00, -3.9312063423578660e+00, -3.7577987551410561e+00, -3.5847340905279546e+00, -3.4119940415009409e+00, -3.2395607153955579e+00, -3.0674166052796257e+00, -2.8955445628456173e+00, -2.7239277726819950e+00, -2.5525497278003657e+00, -2.3813942063052753e+00, -2.2104452491022966e+00, -2.0396871385479329e+00, -1.8691043779518630e+00, -1.6986816718482496e+00, -1.5284039069583553e+00, -1.3582561337715613e+00, -1.1882235486761765e+00, -1.0182914765751778e+00, -8.4844535392529652e-01, -6.7867071214067709e-01, -5.0895316130475177e-01, -3.3927837413597878e-01, -1.6963207015474091e-01, -0.0000000000000000e+00, 1.6963207015474091e-01, 3.3927837413597878e-01, 5.0895316130475177e-01, 6.7867071214067709e-01, 8.4844535392529652e-01, 1.0182914765751778e+00, 1.1882235486761765e+00, 1.3582561337715613e+00, 1.5284039069583553e+00, 1.6986816718482496e+00, 1.8691043779518630e+00, 2.0396871385479329e+00, 2.2104452491022966e+00, 2.3813942063052753e+00, 2.5525497278003657e+00, 2.7239277726819950e+00, 2.8955445628456173e+00, 3.0674166052796257e+00, 3.2395607153955579e+00, 3.4119940415009409e+00, 3.5847340905279546e+00, 3.7577987551410561e+00, 3.9312063423578660e+00, 4.1049756038301792e+00, 4.2791257679461268e+00, 4.4536765739303981e+00, 4.6286483081374303e+00, 4.8040618427527138e+00, 4.9799386771402681e+00, 5.1563009821003343e+00, 5.3331716473306852e+00, 5.5105743324184848e+00, 5.6885335217276216e+00, 5.8670745835899512e+00, 6.0462238342585293e+00, 6.2260086071378540e+00, 6.4064573278715784e+00, 6.5875995959434990e+00, 6.7694662735346460e+00, 6.9520895824801361e+00, 7.1355032102865055e+00, 7.3197424263067070e+00, 7.5048442093293950e+00, 7.6908473880261887e+00, 7.8777927959207110e+00, 8.0657234428032414e+00, 8.2546847048231751e+00, 8.4447245358586134e+00, 8.6358937032013543e+00, 8.8282460511228340e+00, 9.0218387965226103e+00, 9.2167328616325275e+00, 9.4129932496899222e+00, 9.6106894706457702e+00, 9.8098960253945080e+00, 1.0010692958774635e+01, 1.0213166493789654e+01, 1.0417409762265434e+01, 1.0623523650663971e+01, 1.0831617784246889e+01, 1.1041811678540856e+01, 1.1254236094539081e+01, 1.1469034643887829e+01, 1.1686365703318645e+01, 1.1906404715032753e+01, 1.2129346973425209e+01, 1.2355411031114167e+01, 1.2584842902718409e+01, 1.2817921309339152e+01, 1.3054964299852571e+01, 1.3296337722283933e+01, 1.3542466224976369e+01, 1.3793847785696649e+01, 1.4051073271804183e+01, 1.4314853361179868e+01, 1.4586056556752672e+01, 1.4865764512599243e+01, 1.5155355517282629e+01, 1.5456636132218662e+01, 1.5772060470078458e+01, 1.6105122139319558e+01, 1.6461124086051807e+01, 1.6848906849690259e+01, 1.7285623836656182e+01, 1.7816165576540595e+01}, {-1.7870774428377043e+01, -1.7340768757416335e+01, -1.6904502632033939e+01, -1.6517127712794291e+01, -1.6161506578815988e+01, -1.5828806872783744e+01, -1.5513730528912630e+01, -1.5212787139365300e+01, -1.4923524831985965e+01, -1.4644138690731507e+01, -1.4373251680710139e+01, -1.4109783131522859e+01, -1.3852865330854605e+01, -1.3601788249195971e+01, -1.3355961560129954e+01, -1.3114887743985697e+01, -1.2878142545481497e+01, -1.2645360457815213e+01, -1.2416223731463095e+01, -1.2190453910463864e+01, -1.1967805217099682e+01, -1.1748059312137153e+01, -1.1531021094829603e+01, -1.1316515299946504e+01, -1.1104383713549687e+01, -1.0894482874671912e+01, -1.0686682162601475e+01, -1.0480862193135913e+01, -1.0276913464597831e+01, -1.0074735207405618e+01, -9.8742344007979135e+00, -9.6753249277855886e+00, -9.4779268451589243e+00, -9.2819657498467407e+00, -9.0873722264251189e+00, -8.8940813633373228e+00, -8.7020323275849982e+00, -8.5111679894115486e+00, -8.3214345899181446e+00, -8.1327814457042589e+00, -7.9451606855641499e+00, -7.7585270150414196e+00, -7.5728375052793471e+00, -7.3880514031314979e+00, -7.2041299599356252e+00, -7.0210362767207544e+00, -6.8387351639253717e+00, -6.6571930139644744e+00, -6.4763776852031878e+00, -6.2962583960814955e+00, -6.1168056282939949e+00, -5.9379910380649177e+00, -5.7597873746756241e+00, -5.5821684055025109e+00, -5.4051088469102604e+00, -5.2285843004206338e+00, -5.0525711936423852e+00, -4.8770467255047967e+00, -4.7019888153869536e+00, -4.5273760557783174e+00, -4.3531876681442050e+00, -4.1794034617032088e+00, -4.0060037948530276e+00, -3.8329695390070744e+00, -3.6602820446272100e+00, -3.4879231092581433e+00, -3.3158749473870577e+00, -3.1441201619679244e+00, -2.9726417174641275e+00, -2.8014229142755962e+00, -2.6304473644278392e+00, -2.4596989684102435e+00, -2.2891618930598643e+00, -2.1188205503948270e+00, -1.9486595773085056e+00, -1.7786638160418760e+00, -1.6088182953569903e+00, -1.4391082123394401e+00, -1.2695189147619996e+00, -1.1000358839454638e+00, -9.3064471805601867e-01, -7.6133111578138291e-01, -5.9208086033042751e-01, -4.2287980370308703e-01, -2.5371385117911249e-01, -8.4568945975610571e-02, 8.4568945975610571e-02, 2.5371385117911249e-01, 4.2287980370308703e-01, 5.9208086033042751e-01, 7.6133111578138291e-01, 9.3064471805601867e-01, 1.1000358839454638e+00, 1.2695189147619996e+00, 1.4391082123394401e+00, 1.6088182953569903e+00, 1.7786638160418760e+00, 1.9486595773085056e+00, 2.1188205503948270e+00, 2.2891618930598643e+00, 2.4596989684102435e+00, 2.6304473644278392e+00, 2.8014229142755962e+00, 2.9726417174641275e+00, 3.1441201619679244e+00, 3.3158749473870577e+00, 3.4879231092581433e+00, 3.6602820446272100e+00, 3.8329695390070744e+00, 4.0060037948530276e+00, 4.1794034617032088e+00, 4.3531876681442050e+00, 4.5273760557783174e+00, 4.7019888153869536e+00, 4.8770467255047967e+00, 5.0525711936423852e+00, 5.2285843004206338e+00, 5.4051088469102604e+00, 5.5821684055025109e+00, 5.7597873746756241e+00, 5.9379910380649177e+00, 6.1168056282939949e+00, 6.2962583960814955e+00, 6.4763776852031878e+00, 6.6571930139644744e+00, 6.8387351639253717e+00, 7.0210362767207544e+00, 7.2041299599356252e+00, 7.3880514031314979e+00, 7.5728375052793471e+00, 7.7585270150414196e+00, 7.9451606855641499e+00, 8.1327814457042589e+00, 8.3214345899181446e+00, 8.5111679894115486e+00, 8.7020323275849982e+00, 8.8940813633373228e+00, 9.0873722264251189e+00, 9.2819657498467407e+00, 9.4779268451589243e+00, 9.6753249277855886e+00, 9.8742344007979135e+00, 1.0074735207405618e+01, 1.0276913464597831e+01, 1.0480862193135913e+01, 1.0686682162601475e+01, 1.0894482874671912e+01, 1.1104383713549687e+01, 1.1316515299946504e+01, 1.1531021094829603e+01, 1.1748059312137153e+01, 1.1967805217099682e+01, 1.2190453910463864e+01, 1.2416223731463095e+01, 1.2645360457815213e+01, 1.2878142545481497e+01, 1.3114887743985697e+01, 1.3355961560129954e+01, 1.3601788249195971e+01, 1.3852865330854605e+01, 1.4109783131522859e+01, 1.4373251680710139e+01, 1.4644138690731507e+01, 1.4923524831985965e+01, 1.5212787139365300e+01, 1.5513730528912630e+01, 1.5828806872783744e+01, 1.6161506578815988e+01, 1.6517127712794291e+01, 1.6904502632033939e+01, 1.7340768757416335e+01, 1.7870774428377043e+01}, {-1.7925222507645273e+01, -1.7395749181302794e+01, -1.6959930736506667e+01, -1.6572960745489535e+01, -1.6217717667909398e+01, -1.5885377274967727e+01, -1.5570646349282180e+01, -1.5270037662686175e+01, -1.4981101568835271e+01, -1.4702034786209495e+01, -1.4431461525263758e+01, -1.4168302092683751e+01, -1.3911689561406538e+01, -1.3660914545833675e+01, -1.3415387256705733e+01, -1.3174610629179487e+01, -1.2938160798167818e+01, -1.2705672595541055e+01, -1.2476828568829013e+01, -1.2251350525113802e+01, -1.2028992921645616e+01, -1.1809537630775932e+01, -1.1592789743714977e+01, -1.1378574170599888e+01, -1.1166732858754798e+01, -1.0957122496418719e+01, -1.0749612601735487e+01, -1.0544083920437931e+01, -1.0340427073072608e+01, -1.0138541405599460e+01, -9.9383340069978168e+00, -9.7397188649785829e+00, -9.5426161366508815e+00, -9.3469515154567748e+00, -9.1526556791851785e+00, -8.9596638066377352e+00, -8.7679151527158581e+00, -8.5773526734573888e+00, -8.3879226939696405e+00, -8.1995746133560008e+00, -8.0122606416719417e+00, -7.8259355647163380e+00, -7.6405565330989909e+00, -7.4560828725515957e+00, -7.2724759128875176e+00, -7.0896988333823048e+00, -6.9077165226546269e+00, -6.7264954513869304e+00, -6.5460035564448802e+00, -6.3662101351413103e+00, -6.1870857485496860e+00, -6.0086021329082362e+00, -5.8307321182728238e+00, -5.6534495536772900e+00, -5.4767292381468682e+00, -5.3005468569855445e+00, -5.1248789228235241e+00, -4.9497027209678768e+00, -4.7749962586489980e+00, -4.6007382177989511e+00, -4.4269079110357756e+00, -4.2534852405612638e+00, -4.0804506597091201e+00, -3.9077851369063397e+00, -3.7354701218335649e+00, -3.5634875135904314e+00, -3.3918196306899016e+00, -3.2204491827214987e+00, -3.0493592435375283e+00, -2.8785332258289715e+00, -2.7079548569689353e+00, -2.5376081560115265e+00, -2.3674774117429300e+00, -2.1975471616893691e+00, -2.0278021719937014e+00, -1.8582274180786869e+00, -1.6888080660205369e+00, -1.5195294545613143e+00, -1.3503770776931412e+00, -1.1813365677510279e+00, -1.0123936789545276e+00, -8.4353427134138192e-01, -6.7474429503886002e-01, -5.0600977482067722e-01, -3.3731679489919819e-01, -1.6865148390411927e-01, -0.0000000000000000e+00, 1.6865148390411927e-01, 3.3731679489919819e-01, 5.0600977482067722e-01, 6.7474429503886002e-01, 8.4353427134138192e-01, 1.0123936789545276e+00, 1.1813365677510279e+00, 1.3503770776931412e+00, 1.5195294545613143e+00, 1.6888080660205369e+00, 1.8582274180786869e+00, 2.0278021719937014e+00, 2.1975471616893691e+00, 2.3674774117429300e+00, 2.5376081560115265e+00, 2.7079548569689353e+00, 2.8785332258289715e+00, 3.0493592435375283e+00, 3.2204491827214987e+00, 3.3918196306899016e+00, 3.5634875135904314e+00, 3.7354701218335649e+00, 3.9077851369063397e+00, 4.0804506597091201e+00, 4.2534852405612638e+00, 4.4269079110357756e+00, 4.6007382177989511e+00, 4.7749962586489980e+00, 4.9497027209678768e+00, 5.1248789228235241e+00, 5.3005468569855445e+00, 5.4767292381468682e+00, 5.6534495536772900e+00, 5.8307321182728238e+00, 6.0086021329082362e+00, 6.1870857485496860e+00, 6.3662101351413103e+00, 6.5460035564448802e+00, 6.7264954513869304e+00, 6.9077165226546269e+00, 7.0896988333823048e+00, 7.2724759128875176e+00, 7.4560828725515957e+00, 7.6405565330989909e+00, 7.8259355647163380e+00, 8.0122606416719417e+00, 8.1995746133560008e+00, 8.3879226939696405e+00, 8.5773526734573888e+00, 8.7679151527158581e+00, 8.9596638066377352e+00, 9.1526556791851785e+00, 9.3469515154567748e+00, 9.5426161366508815e+00, 9.7397188649785829e+00, 9.9383340069978168e+00, 1.0138541405599460e+01, 1.0340427073072608e+01, 1.0544083920437931e+01, 1.0749612601735487e+01, 1.0957122496418719e+01, 1.1166732858754798e+01, 1.1378574170599888e+01, 1.1592789743714977e+01, 1.1809537630775932e+01, 1.2028992921645616e+01, 1.2251350525113802e+01, 1.2476828568829013e+01, 1.2705672595541055e+01, 1.2938160798167818e+01, 1.3174610629179487e+01, 1.3415387256705733e+01, 1.3660914545833675e+01, 1.3911689561406538e+01, 1.4168302092683751e+01, 1.4431461525263758e+01, 1.4702034786209495e+01, 1.4981101568835271e+01, 1.5270037662686175e+01, 1.5570646349282180e+01, 1.5885377274967727e+01, 1.6217717667909398e+01, 1.6572960745489535e+01, 1.6959930736506667e+01, 1.7395749181302794e+01, 1.7925222507645273e+01}, {-1.7979511220856821e+01, -1.7450566562382527e+01, -1.7015192658329994e+01, -1.6628624717520726e+01, -1.6273756976433262e+01, -1.5941773281856777e+01, -1.5627385233279865e+01, -1.5327108761515133e+01, -1.5038496431508072e+01, -1.4759746585548676e+01, -1.4489484671220278e+01, -1.4226631965786098e+01, -1.3970322322144929e+01, -1.3719846994209712e+01, -1.3474616726146943e+01, -1.3234134904720168e+01, -1.2997978052213019e+01, -1.2765781336657277e+01, -1.2537227600374516e+01, -1.2312038911428751e+01, -1.2089969960138866e+01, -1.1870802828673778e+01, -1.1654342798540783e+01, -1.1440414953672729e+01, -1.1228861401155735e+01, -1.1019538976992907e+01, -1.0812317336788272e+01, -1.0607077354851786e+01, -1.0403709772624749e+01, -1.0202114050301228e+01, -1.0002197385309380e+01, -9.8038738687782931e+00, -9.6070637568592137e+00, -9.4116928382313976e+00, -9.2176918826171956e+00, -9.0249961578901878e+00, -8.8335450055546225e+00, -8.6432814661321498e+00, -8.4541519474088638e+00, -8.2661059296450645e+00, -8.0790957027880133e+00, -7.8930761314972990e+00, -7.7080044444269156e+00, -7.5238400447339577e+00, -7.3405443392217018e+00, -7.1580805838909543e+00, -6.9764137439811300e+00, -6.7955103668419072e+00, -6.6153384661958059e+00, -6.4358674165386551e+00, -6.2570678565839728e+00, -6.0789116007933410e+00, -5.9013715581517205e+00, -5.7244216574471602e+00, -5.5480367784012250e+00, -5.3721926880716282e+00, -5.1968659820138337e+00, -5.0220340297452291e+00, -4.8476749241050427e+00, -4.6737674341465381e+00, -4.5002909612360460e+00, -4.3272254980667917e+00, -4.1545515903248518e+00, -3.9822503007705263e+00, -3.8103031755212977e+00, -3.6386922123428187e+00, -3.4673998307723486e+00, -3.2964088439149859e+00, -3.1257024317672348e+00, -2.9552641159350221e+00, -2.7850777356245309e+00, -2.6151274247942147e+00, -2.4453975903652418e+00, -2.2758728913956188e+00, -2.1065382191302762e+00, -1.9373786778457494e+00, -1.7683795664136901e+00, -1.5995263605124337e+00, -1.4308046954202789e+00, -1.2622003493280531e+00, -1.0936992271119663e+00, -9.2528734451076988e-01, -7.5695081265386188e-01, -5.8867582288920217e-01, -4.2044863186181980e-01, -2.5225554679525719e-01, -8.4082910929564950e-02, 8.4082910929564950e-02, 2.5225554679525719e-01, 4.2044863186181980e-01, 5.8867582288920217e-01, 7.5695081265386188e-01, 9.2528734451076988e-01, 1.0936992271119663e+00, 1.2622003493280531e+00, 1.4308046954202789e+00, 1.5995263605124337e+00, 1.7683795664136901e+00, 1.9373786778457494e+00, 2.1065382191302762e+00, 2.2758728913956188e+00, 2.4453975903652418e+00, 2.6151274247942147e+00, 2.7850777356245309e+00, 2.9552641159350221e+00, 3.1257024317672348e+00, 3.2964088439149859e+00, 3.4673998307723486e+00, 3.6386922123428187e+00, 3.8103031755212977e+00, 3.9822503007705263e+00, 4.1545515903248518e+00, 4.3272254980667917e+00, 4.5002909612360460e+00, 4.6737674341465381e+00, 4.8476749241050427e+00, 5.0220340297452291e+00, 5.1968659820138337e+00, 5.3721926880716282e+00, 5.5480367784012250e+00, 5.7244216574471602e+00, 5.9013715581517205e+00, 6.0789116007933410e+00, 6.2570678565839728e+00, 6.4358674165386551e+00, 6.6153384661958059e+00, 6.7955103668419072e+00, 6.9764137439811300e+00, 7.1580805838909543e+00, 7.3405443392217018e+00, 7.5238400447339577e+00, 7.7080044444269156e+00, 7.8930761314972990e+00, 8.0790957027880133e+00, 8.2661059296450645e+00, 8.4541519474088638e+00, 8.6432814661321498e+00, 8.8335450055546225e+00, 9.0249961578901878e+00, 9.2176918826171956e+00, 9.4116928382313976e+00, 9.6070637568592137e+00, 9.8038738687782931e+00, 1.0002197385309380e+01, 1.0202114050301228e+01, 1.0403709772624749e+01, 1.0607077354851786e+01, 1.0812317336788272e+01, 1.1019538976992907e+01, 1.1228861401155735e+01, 1.1440414953672729e+01, 1.1654342798540783e+01, 1.1870802828673778e+01, 1.2089969960138866e+01, 1.2312038911428751e+01, 1.2537227600374516e+01, 1.2765781336657277e+01, 1.2997978052213019e+01, 1.3234134904720168e+01, 1.3474616726146943e+01, 1.3719846994209712e+01, 1.3970322322144929e+01, 1.4226631965786098e+01, 1.4489484671220278e+01, 1.4759746585548676e+01, 1.5038496431508072e+01, 1.5327108761515133e+01, 1.5627385233279865e+01, 1.5941773281856777e+01, 1.6273756976433262e+01, 1.6628624717520726e+01, 1.7015192658329994e+01, 1.7450566562382527e+01, 1.7979511220856821e+01}, {-1.8033641954168267e+01, -1.7505222333487513e+01, -1.7070289870719815e+01, -1.6684121139543407e+01, -1.6329626050797177e+01, -1.5997996474571265e+01, -1.5683948796077209e+01, -1.5384002084668344e+01, -1.5095711102237930e+01, -1.4817275804306519e+01, -1.4547322867471838e+01, -1.4284774533151579e+01, -1.4028765428985777e+01, -1.3778587444058825e+01, -1.3533651852283532e+01, -1.3293462488855706e+01, -1.3057596260647884e+01, -1.2825688669380938e+01, -1.2597422849942523e+01, -1.2372521129351217e+01, -1.2150738429127935e+01, -1.1931857039523125e+01, -1.1715682430712077e+01, -1.1502039858881551e+01, -1.1290771589409180e+01, -1.1081734604649661e+01, -1.0874798696301507e+01, -1.0669844865923427e+01, -1.0466763974552268e+01, -1.0265455595339178e+01, -1.0065827032900119e+01, -9.8677924805319144e+00, -9.6712722921832484e+00, -9.4761923505272865e+00, -9.2824835159740040e+00, -9.0900811442169349e+00, -8.8989246621016740e+00, -8.7089571933595398e+00, -8.5201252271656553e+00, -8.3323783236290581e+00, -8.1456688512594901e+00, -7.9599517522241854e+00, -7.7751843318419356e+00, -7.5913260692870139e+00, -7.4083384469130396e+00, -7.2261847959726726e+00, -7.0448301568163600e+00, -6.8642411519124229e+00, -6.6843858702502548e+00, -6.5052337618746865e+00, -6.3267555414586063e+00, -6.1489230999568738e+00, -5.9717094235012285e+00, -5.7950885187964847e+00, -5.6190353443649403e+00, -5.4435257470611598e+00, -5.2685364033444513e+00, -5.0940447648531757e+00, -4.9200290078745663e+00, -4.7464679863470698e+00, -4.5733411880702048e+00, -4.4006286938303605e+00, -4.2283111391802617e+00, -4.0563696786358214e+00, -3.8847859520769483e+00, -3.7135420531591667e+00, -3.5426204995608663e+00, -3.3720042049069567e+00, -3.2016764522238601e+00, -3.0316208687934161e+00, -2.8618214022844848e+00, -2.6922622980510740e+00, -2.5229280774947309e+00, -2.3538035173969201e+00, -2.1848736301342204e+00, -2.0161236446955049e+00, -1.8475389884259239e+00, -1.6791052694275435e+00, -1.5108082595509420e+00, -1.3426338779160372e+00, -1.1745681749038943e+00, -1.0065973165643360e+00, -8.3870756938683533e-01, -6.7088528538449332e-01, -5.0311688744285843e-01, -3.3538885488700437e-01, -1.6768770922162865e-01, -0.0000000000000000e+00, 1.6768770922162865e-01, 3.3538885488700437e-01, 5.0311688744285843e-01, 6.7088528538449332e-01, 8.3870756938683533e-01, 1.0065973165643360e+00, 1.1745681749038943e+00, 1.3426338779160372e+00, 1.5108082595509420e+00, 1.6791052694275435e+00, 1.8475389884259239e+00, 2.0161236446955049e+00, 2.1848736301342204e+00, 2.3538035173969201e+00, 2.5229280774947309e+00, 2.6922622980510740e+00, 2.8618214022844848e+00, 3.0316208687934161e+00, 3.2016764522238601e+00, 3.3720042049069567e+00, 3.5426204995608663e+00, 3.7135420531591667e+00, 3.8847859520769483e+00, 4.0563696786358214e+00, 4.2283111391802617e+00, 4.4006286938303605e+00, 4.5733411880702048e+00, 4.7464679863470698e+00, 4.9200290078745663e+00, 5.0940447648531757e+00, 5.2685364033444513e+00, 5.4435257470611598e+00, 5.6190353443649403e+00, 5.7950885187964847e+00, 5.9717094235012285e+00, 6.1489230999568738e+00, 6.3267555414586063e+00, 6.5052337618746865e+00, 6.6843858702502548e+00, 6.8642411519124229e+00, 7.0448301568163600e+00, 7.2261847959726726e+00, 7.4083384469130396e+00, 7.5913260692870139e+00, 7.7751843318419356e+00, 7.9599517522241854e+00, 8.1456688512594901e+00, 8.3323783236290581e+00, 8.5201252271656553e+00, 8.7089571933595398e+00, 8.8989246621016740e+00, 9.0900811442169349e+00, 9.2824835159740040e+00, 9.4761923505272865e+00, 9.6712722921832484e+00, 9.8677924805319144e+00, 1.0065827032900119e+01, 1.0265455595339178e+01, 1.0466763974552268e+01, 1.0669844865923427e+01, 1.0874798696301507e+01, 1.1081734604649661e+01, 1.1290771589409180e+01, 1.1502039858881551e+01, 1.1715682430712077e+01, 1.1931857039523125e+01, 1.2150738429127935e+01, 1.2372521129351217e+01, 1.2597422849942523e+01, 1.2825688669380938e+01, 1.3057596260647884e+01, 1.3293462488855706e+01, 1.3533651852283532e+01, 1.3778587444058825e+01, 1.4028765428985777e+01, 1.4284774533151579e+01, 1.4547322867471838e+01, 1.4817275804306519e+01, 1.5095711102237930e+01, 1.5384002084668344e+01, 1.5683948796077209e+01, 1.5997996474571265e+01, 1.6329626050797177e+01, 1.6684121139543407e+01, 1.7070289870719815e+01, 1.7505222333487513e+01, 1.8033641954168267e+01}, {-1.8087616073790890e+01, -1.7559717906645613e+01, -1.7125223825336107e+01, -1.6739451499952981e+01, -1.6385326414471709e+01, -1.6054048410627541e+01, -1.5740338628583727e+01, -1.5440719256044483e+01, -1.5152747237684542e+01, -1.4874624131806939e+01, -1.4604977836012001e+01, -1.4342731549531273e+01, -1.4087020669594040e+01, -1.3837137716174603e+01, -1.3592494489303405e+01, -1.3352595269479263e+01, -1.3117017345422802e+01, -1.2885396550109379e+01, -1.2657416308802228e+01, -1.2432799205480446e+01, -1.2211300391032086e+01, -1.1992702362083911e+01, -1.1776810775879971e+01, -1.1563451059348457e+01, -1.1352465634716971e+01, -1.1143711629308052e+01, -1.0937058969577729e+01, -1.0732388783033896e+01, -1.0529592049038808e+01, -1.0328568452453034e+01, -1.0129225403849107e+01, -9.9314771974714695e+00, -9.7352442838524844e+00, -9.5404526384475599e+00, -9.3470332111408592e+00, -9.1549214442271172e+00, -8.9640568486659262e+00, -8.7743826301592698e+00, -8.5858453580177638e+00, -8.3983946709283614e+00, -8.2119830146725530e+00, -8.0265654076120381e+00, -7.8420992303922956e+00, -7.6585440368392881e+00, -7.4758613834617105e+00, -7.2940146753366397e+00, -7.1129690264635128e+00, -6.9326911329302607e+00, -6.7531491574546436e+00, -6.5743126240500311e+00, -6.3961523217237177e+00, -6.2186402162517354e+00, -6.0417493691907094e+00, -5.8654538633877182e+00, -5.6897287343358398e+00, -5.5145499067980914e+00, -5.3398941361876862e+00, -5.1657389542492513e+00, -4.9920626186351811e+00, -4.8188440660145870e+00, -4.6460628683903158e+00, -4.4736991923328295e+00, -4.3017337608691273e+00, -4.1301478177908013e+00, -3.9589230941681977e+00, -3.7880417768779360e+00, -3.6174864789689782e+00, -3.4472402117084235e+00, -3.2772863581623723e+00, -3.1076086481798137e+00, -2.9381911346587741e+00, -2.7690181709839532e+00, -2.6000743895340599e+00, -2.4313446811650303e+00, -2.2628141755824469e+00, -2.0944682225228455e+00, -1.9262923736692732e+00, -1.7582723652315242e+00, -1.5903941011259675e+00, -1.4226436366938928e+00, -1.2550071629008195e+00, -1.0874709909623226e+00, -9.2002153734466763e-01, -7.5264530909089167e-01, -5.8532888942501560e-01, -4.1805892358878166e-01, -2.5082210486674750e-01, -8.3605160756706529e-02, 8.3605160756706529e-02, 2.5082210486674750e-01, 4.1805892358878166e-01, 5.8532888942501560e-01, 7.5264530909089167e-01, 9.2002153734466763e-01, 1.0874709909623226e+00, 1.2550071629008195e+00, 1.4226436366938928e+00, 1.5903941011259675e+00, 1.7582723652315242e+00, 1.9262923736692732e+00, 2.0944682225228455e+00, 2.2628141755824469e+00, 2.4313446811650303e+00, 2.6000743895340599e+00, 2.7690181709839532e+00, 2.9381911346587741e+00, 3.1076086481798137e+00, 3.2772863581623723e+00, 3.4472402117084235e+00, 3.6174864789689782e+00, 3.7880417768779360e+00, 3.9589230941681977e+00, 4.1301478177908013e+00, 4.3017337608691273e+00, 4.4736991923328295e+00, 4.6460628683903158e+00, 4.8188440660145870e+00, 4.9920626186351811e+00, 5.1657389542492513e+00, 5.3398941361876862e+00, 5.5145499067980914e+00, 5.6897287343358398e+00, 5.8654538633877182e+00, 6.0417493691907094e+00, 6.2186402162517354e+00, 6.3961523217237177e+00, 6.5743126240500311e+00, 6.7531491574546436e+00, 6.9326911329302607e+00, 7.1129690264635128e+00, 7.2940146753366397e+00, 7.4758613834617105e+00, 7.6585440368392881e+00, 7.8420992303922956e+00, 8.0265654076120381e+00, 8.2119830146725530e+00, 8.3983946709283614e+00, 8.5858453580177638e+00, 8.7743826301592698e+00, 8.9640568486659262e+00, 9.1549214442271172e+00, 9.3470332111408592e+00, 9.5404526384475599e+00, 9.7352442838524844e+00, 9.9314771974714695e+00, 1.0129225403849107e+01, 1.0328568452453034e+01, 1.0529592049038808e+01, 1.0732388783033896e+01, 1.0937058969577729e+01, 1.1143711629308052e+01, 1.1352465634716971e+01, 1.1563451059348457e+01, 1.1776810775879971e+01, 1.1992702362083911e+01, 1.2211300391032086e+01, 1.2432799205480446e+01, 1.2657416308802228e+01, 1.2885396550109379e+01, 1.3117017345422802e+01, 1.3352595269479263e+01, 1.3592494489303405e+01, 1.3837137716174603e+01, 1.4087020669594040e+01, 1.4342731549531273e+01, 1.4604977836012001e+01, 1.4874624131806939e+01, 1.5152747237684542e+01, 1.5440719256044483e+01, 1.5740338628583727e+01, 1.6054048410627541e+01, 1.6385326414471709e+01, 1.6739451499952981e+01, 1.7125223825336107e+01, 1.7559717906645613e+01, 1.8087616073790890e+01}, {-1.8141434926389717e+01, -1.7614054673500309e+01, -1.7179995952720883e+01, -1.6794617265339959e+01, -1.6440859568460443e+01, -1.6109930624426557e+01, -1.5796556297952138e+01, -1.5497261875146510e+01, -1.5209606469472327e+01, -1.4931793231695860e+01, -1.4662451272508532e+01, -1.4400504742695974e+01, -1.4145089803991842e+01, -1.3895499603035967e+01, -1.3651146462397561e+01, -1.3411535104793492e+01, -1.3176243198091708e+01, -1.2944906904124267e+01, -1.2717209936373832e+01, -1.2492875133818373e+01, -1.2271657874909140e+01, -1.2053340860973840e+01, -1.1837729934755059e+01, -1.1624650692438404e+01, -1.1413945711687965e+01, -1.1205472263438262e+01, -1.0999100407593694e+01, -1.0794711396339702e+01, -1.0592196326121911e+01, -1.0391454992291058e+01, -1.0192394910173833e+01, -9.9949304737714737e+00, -9.7989822290161133e+00, -9.6044762429642674e+00, -9.4113435537920687e+00, -9.2195196892087417e+00, -9.0289442430934326e+00, -8.8395605019136383e+00, -8.6513151138967856e+00, -8.4641577950728877e+00, -8.2780410672415687e+00, -8.0929200236841812e+00, -7.9087521190744416e+00, -7.7254969805656009e+00, -7.5431162374687224e+00, -7.3615733673019719e+00, -7.1808335562975261e+00, -7.0008635727114159e+00, -6.8216316515006419e+00, -6.6431073891179739e+00, -6.4652616473335298e+00, -6.2880664651279838e+00, -6.1114949778187784e+00, -5.9355213426810298e+00, -5.7601206704114505e+00, -5.5852689618586204e+00, -5.4109430495080577e+00, -5.2371205432672880e+00, -5.0637797801455120e+00, -4.8908997774658411e+00, -4.7184601892859508e+00, -4.5464412657363820e+00, -4.3748238150150680e+00, -4.2035891678025479e+00, -4.0327191438852346e+00, -3.8621960207943373e+00, -3.6920025042860427e+00, -3.5221217005044698e+00, -3.3525370896831359e+00, -3.1832325012532876e+00, -3.0141920902387014e+00, -2.8454003148266174e+00, -2.6768419150134308e+00, -2.5085018922317608e+00, -2.3403654898726809e+00, -2.1724181746232882e+00, -2.0046456185454748e+00, -1.8370336818268698e+00, -1.6695683961394456e+00, -1.5022359485453094e+00, -1.3350226658927800e+00, -1.1679149996489939e+00, -1.0008995111180643e+00, -8.3396285699622974e-01, -6.6709177521751994e-01, -5.0027307104524965e-01, -3.3349360336615247e-01, -1.6674027114518436e-01, -0.0000000000000000e+00, 1.6674027114518436e-01, 3.3349360336615247e-01, 5.0027307104524965e-01, 6.6709177521751994e-01, 8.3396285699622974e-01, 1.0008995111180643e+00, 1.1679149996489939e+00, 1.3350226658927800e+00, 1.5022359485453094e+00, 1.6695683961394456e+00, 1.8370336818268698e+00, 2.0046456185454748e+00, 2.1724181746232882e+00, 2.3403654898726809e+00, 2.5085018922317608e+00, 2.6768419150134308e+00, 2.8454003148266174e+00, 3.0141920902387014e+00, 3.1832325012532876e+00, 3.3525370896831359e+00, 3.5221217005044698e+00, 3.6920025042860427e+00, 3.8621960207943373e+00, 4.0327191438852346e+00, 4.2035891678025479e+00, 4.3748238150150680e+00, 4.5464412657363820e+00, 4.7184601892859508e+00, 4.8908997774658411e+00, 5.0637797801455120e+00, 5.2371205432672880e+00, 5.4109430495080577e+00, 5.5852689618586204e+00, 5.7601206704114505e+00, 5.9355213426810298e+00, 6.1114949778187784e+00, 6.2880664651279838e+00, 6.4652616473335298e+00, 6.6431073891179739e+00, 6.8216316515006419e+00, 7.0008635727114159e+00, 7.1808335562975261e+00, 7.3615733673019719e+00, 7.5431162374687224e+00, 7.7254969805656009e+00, 7.9087521190744416e+00, 8.0929200236841812e+00, 8.2780410672415687e+00, 8.4641577950728877e+00, 8.6513151138967856e+00, 8.8395605019136383e+00, 9.0289442430934326e+00, 9.2195196892087417e+00, 9.4113435537920687e+00, 9.6044762429642674e+00, 9.7989822290161133e+00, 9.9949304737714737e+00, 1.0192394910173833e+01, 1.0391454992291058e+01, 1.0592196326121911e+01, 1.0794711396339702e+01, 1.0999100407593694e+01, 1.1205472263438262e+01, 1.1413945711687965e+01, 1.1624650692438404e+01, 1.1837729934755059e+01, 1.2053340860973840e+01, 1.2271657874909140e+01, 1.2492875133818373e+01, 1.2717209936373832e+01, 1.2944906904124267e+01, 1.3176243198091708e+01, 1.3411535104793492e+01, 1.3651146462397561e+01, 1.3895499603035967e+01, 1.4145089803991842e+01, 1.4400504742695974e+01, 1.4662451272508532e+01, 1.4931793231695860e+01, 1.5209606469472327e+01, 1.5497261875146510e+01, 1.5796556297952138e+01, 1.6109930624426557e+01, 1.6440859568460443e+01, 1.6794617265339959e+01, 1.7179995952720883e+01, 1.7614054673500309e+01, 1.8141434926389717e+01}, {-1.8195099839472430e+01, -1.7668234005719587e+01, -1.7234607662724841e+01, -1.6849619880933339e+01, -1.6496226991759631e+01, -1.6165644627729627e+01, -1.5852603348070128e+01, -1.5553631517589562e+01, -1.5266290404714507e+01, -1.4988784742481727e+01, -1.4719744846860621e+01, -1.4458095814010402e+01, -1.4202974565149994e+01, -1.3953674869416368e+01, -1.3709609568387386e+01, -1.3470283823956324e+01, -1.3235275680476827e+01, -1.3004221626275813e+01, -1.2776805660932723e+01, -1.2552750876494338e+01, -1.2331812877201305e+01, -1.2113774567435913e+01, -1.1898441973897304e+01, -1.1685640860572095e+01, -1.1475213959174649e+01, -1.1267018682922650e+01, -1.1060925223886697e+01, -1.0856814957685176e+01, -1.0654579096632252e+01, -1.0454117545377073e+01, -1.0255337922825921e+01, -1.0058154721574315e+01, -9.8624885817991093e+00, -9.6682656610062114e+00, -9.4754170845116796e+00, -9.2838784642833954e+00, -9.0935894759573372e+00, -8.9044934855939797e+00, -8.7165372191524781e+00, -8.5296704688056462e+00, -8.3438458311533719e+00, -8.1590184731587261e+00, -7.9751459222633976e+00, -7.7921878776629914e+00, -7.6101060401591205e+00, -7.4288639583701048e+00, -7.2484268893885622e+00, -7.0687616722327293e+00, -6.8898366126570973e+00, -6.7116213780739269e+00, -6.5340869014957565e+00, -6.3572052935446060e+00, -6.1809497616900950e+00, -6.0052945359788579e+00, -5.8302148006042280e+00, -5.6556866307401252e+00, -5.4816869341281516e+00, -5.3081933969635617e+00, -5.1351844336752253e+00, -4.9626391402379442e+00, -4.7905372506934265e+00, -4.6188590965895351e+00, -4.4475855690767556e+00, -4.2766980834267416e+00, -4.1061785457606526e+00, -3.9360093217952534e+00, -3.7661732074327352e+00, -3.5966534010361229e+00, -3.4274334772463870e+00, -3.2584973622099573e+00, -3.0898293100966461e+00, -2.9214138807980121e+00, -2.7532359187051947e+00, -2.5852805324732593e+00, -2.4175330756862730e+00, -2.2499791283437252e+00, -2.0826044790946652e+00, -1.9153951081510019e+00, -1.7483371708160103e+00, -1.5814169815681258e+00, -1.4146209986437335e+00, -1.2479358090658317e+00, -1.0813481140682928e+00, -9.1484471486787966e-01, -7.4841249873834059e-01, -5.8203842534274008e-01, -4.1570951328174155e-01, -2.4941282681685847e-01, -8.3135462728728945e-02, 8.3135462728728945e-02, 2.4941282681685847e-01, 4.1570951328174155e-01, 5.8203842534274008e-01, 7.4841249873834059e-01, 9.1484471486787966e-01, 1.0813481140682928e+00, 1.2479358090658317e+00, 1.4146209986437335e+00, 1.5814169815681258e+00, 1.7483371708160103e+00, 1.9153951081510019e+00, 2.0826044790946652e+00, 2.2499791283437252e+00, 2.4175330756862730e+00, 2.5852805324732593e+00, 2.7532359187051947e+00, 2.9214138807980121e+00, 3.0898293100966461e+00, 3.2584973622099573e+00, 3.4274334772463870e+00, 3.5966534010361229e+00, 3.7661732074327352e+00, 3.9360093217952534e+00, 4.1061785457606526e+00, 4.2766980834267416e+00, 4.4475855690767556e+00, 4.6188590965895351e+00, 4.7905372506934265e+00, 4.9626391402379442e+00, 5.1351844336752253e+00, 5.3081933969635617e+00, 5.4816869341281516e+00, 5.6556866307401252e+00, 5.8302148006042280e+00, 6.0052945359788579e+00, 6.1809497616900950e+00, 6.3572052935446060e+00, 6.5340869014957565e+00, 6.7116213780739269e+00, 6.8898366126570973e+00, 7.0687616722327293e+00, 7.2484268893885622e+00, 7.4288639583701048e+00, 7.6101060401591205e+00, 7.7921878776629914e+00, 7.9751459222633976e+00, 8.1590184731587261e+00, 8.3438458311533719e+00, 8.5296704688056462e+00, 8.7165372191524781e+00, 8.9044934855939797e+00, 9.0935894759573372e+00, 9.2838784642833954e+00, 9.4754170845116796e+00, 9.6682656610062114e+00, 9.8624885817991093e+00, 1.0058154721574315e+01, 1.0255337922825921e+01, 1.0454117545377073e+01, 1.0654579096632252e+01, 1.0856814957685176e+01, 1.1060925223886697e+01, 1.1267018682922650e+01, 1.1475213959174649e+01, 1.1685640860572095e+01, 1.1898441973897304e+01, 1.2113774567435913e+01, 1.2331812877201305e+01, 1.2552750876494338e+01, 1.2776805660932723e+01, 1.3004221626275813e+01, 1.3235275680476827e+01, 1.3470283823956324e+01, 1.3709609568387386e+01, 1.3953674869416368e+01, 1.4202974565149994e+01, 1.4458095814010402e+01, 1.4719744846860621e+01, 1.4988784742481727e+01, 1.5266290404714507e+01, 1.5553631517589562e+01, 1.5852603348070128e+01, 1.6165644627729627e+01, 1.6496226991759631e+01, 1.6849619880933339e+01, 1.7234607662724841e+01, 1.7668234005719587e+01, 1.8195099839472430e+01}, {-1.8248612121768343e+01, -1.7722257255394386e+01, -1.7289060344922966e+01, -1.6904460771032490e+01, -1.6551430141805881e+01, -1.6221191910121661e+01, -1.5908481300039147e+01, -1.5609829735595335e+01, -1.5322800626523263e+01, -1.5045600278061576e+01, -1.4776860203741105e+01, -1.4515506438991860e+01, -1.4260676659563400e+01, -1.4011665252976300e+01, -1.3767885576334674e+01, -1.3528843227708883e+01, -1.3294116625314924e+01, -1.3063342581647838e+01, -1.2836205380293851e+01, -1.2612428364469304e+01, -1.2391767362459763e+01, -1.2174005480084015e+01, -1.1958948926483190e+01, -1.1746423632015365e+01, -1.1536272481085435e+01, -1.1328353027891652e+01, -1.1122535595414808e+01, -1.0918701681487823e+01, -1.0716742613104932e+01, -1.0516558403048526e+01, -1.0318056772656865e+01, -1.0121152311984588e+01, -9.9257657543260880e+00, -9.7318233465134139e+00, -9.5392562998795718e+00, -9.3480003095250854e+00, -9.1579951317106332e+00, -8.9691842109485744e+00, -8.7815143497770496e+00, -8.5949354153447821e+00, -8.4094000778684173e+00, -8.2248635767903480e+00, -8.0412835110966494e+00, -7.8586196507783281e+00, -7.6768337668550366e+00, -7.4958894777450231e+00, -7.3157521100712737e+00, -7.1363885722521356e+00, -6.9577672394433048e+00, -6.7798578485838581e+00, -6.6026314024574280e+00, -6.4260600818151339e+00, -6.2501171647232399e+00, -6.0747769523986586e+00, -5.9000147008819077e+00, -5.7258065579720290e+00, -5.5521295049130304e+00, -5.3789613023779728e+00, -5.2062804403463288e+00, -5.0340660915133606e+00, -4.8622980679082559e+00, -4.6909567804310086e+00, -4.5200232010473753e+00, -4.3494788274071139e+00, -4.1793056496735739e+00, -4.0094861193729656e+00, -3.8400031200895830e+00, -3.6708399398492308e+00, -3.5019802450472732e+00, -3.3334080557903905e+00, -3.1651077225323845e+00, -2.9970639038944427e+00, -2.8292615455692673e+00, -2.6616858602164983e+00, -2.4943223082640649e+00, -2.3271565795365086e+00, -2.1601745756370865e+00, -1.9933623930155944e+00, -1.8267063066584319e+00, -1.6601927543415429e+00, -1.4938083213904756e+00, -1.3275397258950710e+00, -1.1613738043291120e+00, -9.9529749752779750e-01, -8.2929783697808435e-01, -6.6336193137884258e-01, -4.9747695342938458e-01, -3.3163012680628950e-01, -1.6580871328955671e-01, -0.0000000000000000e+00, 1.6580871328955671e-01, 3.3163012680628950e-01, 4.9747695342938458e-01, 6.6336193137884258e-01, 8.2929783697808435e-01, 9.9529749752779750e-01, 1.1613738043291120e+00, 1.3275397258950710e+00, 1.4938083213904756e+00, 1.6601927543415429e+00, 1.8267063066584319e+00, 1.9933623930155944e+00, 2.1601745756370865e+00, 2.3271565795365086e+00, 2.4943223082640649e+00, 2.6616858602164983e+00, 2.8292615455692673e+00, 2.9970639038944427e+00, 3.1651077225323845e+00, 3.3334080557903905e+00, 3.5019802450472732e+00, 3.6708399398492308e+00, 3.8400031200895830e+00, 4.0094861193729656e+00, 4.1793056496735739e+00, 4.3494788274071139e+00, 4.5200232010473753e+00, 4.6909567804310086e+00, 4.8622980679082559e+00, 5.0340660915133606e+00, 5.2062804403463288e+00, 5.3789613023779728e+00, 5.5521295049130304e+00, 5.7258065579720290e+00, 5.9000147008819077e+00, 6.0747769523986586e+00, 6.2501171647232399e+00, 6.4260600818151339e+00, 6.6026314024574280e+00, 6.7798578485838581e+00, 6.9577672394433048e+00, 7.1363885722521356e+00, 7.3157521100712737e+00, 7.4958894777450231e+00, 7.6768337668550366e+00, 7.8586196507783281e+00, 8.0412835110966494e+00, 8.2248635767903480e+00, 8.4094000778684173e+00, 8.5949354153447821e+00, 8.7815143497770496e+00, 8.9691842109485744e+00, 9.1579951317106332e+00, 9.3480003095250854e+00, 9.5392562998795718e+00, 9.7318233465134139e+00, 9.9257657543260880e+00, 1.0121152311984588e+01, 1.0318056772656865e+01, 1.0516558403048526e+01, 1.0716742613104932e+01, 1.0918701681487823e+01, 1.1122535595414808e+01, 1.1328353027891652e+01, 1.1536272481085435e+01, 1.1746423632015365e+01, 1.1958948926483190e+01, 1.2174005480084015e+01, 1.2391767362459763e+01, 1.2612428364469304e+01, 1.2836205380293851e+01, 1.3063342581647838e+01, 1.3294116625314924e+01, 1.3528843227708883e+01, 1.3767885576334674e+01, 1.4011665252976300e+01, 1.4260676659563400e+01, 1.4515506438991860e+01, 1.4776860203741105e+01, 1.5045600278061576e+01, 1.5322800626523263e+01, 1.5609829735595335e+01, 1.5908481300039147e+01, 1.6221191910121661e+01, 1.6551430141805881e+01, 1.6904460771032490e+01, 1.7289060344922966e+01, 1.7722257255394386e+01, 1.8248612121768343e+01}, {-1.8301973063597831e+01, -1.7776125755426882e+01, -1.7343355369019513e+01, -1.6959141339427859e+01, -1.6606470454912181e+01, -1.6276573939462359e+01, -1.5964191652640661e+01, -1.5665858058473457e+01, -1.5379138694506308e+01, -1.5102241428233055e+01, -1.4833798963124122e+01, -1.4572738267853815e+01, -1.4318197767810874e+01, -1.4069472464839684e+01, -1.3825976228134913e+01, -1.3587215088986124e+01, -1.3352767836885693e+01, -1.3122271606204340e+01, -1.2895410962476978e+01, -1.2671909498220252e+01, -1.2451523264048797e+01, -1.2234035565627281e+01, -1.2019252793050947e+01, -1.1807001041645883e+01, -1.1597123347173454e+01, -1.1389477403535365e+01, -1.1183933663391947e+01, -1.0980373745597644e+01, -1.0778689090663802e+01, -1.0578779818366641e+01, -1.0380553751354837e+01, -1.0183925576033463e+01, -9.9888161177141903e+00, -9.7951517114594342e+00, -9.6028636535242580e+00, -9.4118877210445753e+00, -9.2221637498031388e+00, -9.0336352616534104e+00, -8.8462491345909715e+00, -8.6599553096056603e+00, -8.4747065293805139e+00, -8.2904581046690247e+00, -8.1071677048133868e+00, -7.9247951693895704e+00, -7.7433023384005537e+00, -7.5626528988034316e+00, -7.3828122454620404e+00, -7.2037473548748121e+00, -7.0254266702460146e+00, -6.8478199966541871e+00, -6.6708984052298304e+00, -6.4946341453898597e+00, -6.3190005642925637e+00, -6.1439720327768708e+00, -5.9695238771362042e+00, -5.7956323161519689e+00, -5.6222744028767648e+00, -5.4494279707139679e+00, -5.2770715833897031e+00, -5.1051844884564179e+00, -4.9337465740051734e+00, -4.7627383282970204e+00, -4.5921408020531498e+00, -4.4219355731693852e+00, -4.2521047136434067e+00, -4.0826307585233783e+00, -3.9134966767045909e+00, -3.7446858434166801e+00, -3.5761820142581890e+00, -3.4079693006478804e+00, -3.2400321465734825e+00, -3.0723553065286380e+00, -2.9049238245378035e+00, -2.7377230141769160e+00, -2.5707384395048281e+00, -2.4039558968269845e+00, -2.2373613972185420e+00, -2.0709411497393346e+00, -1.9046815452776742e+00, -1.7385691409641026e+00, -1.5725906450998823e+00, -1.4067329025482804e+00, -1.2409828805395797e+00, -1.0753276548433179e+00, -9.0975439626347543e-01, -7.4425035741428780e-01, -5.7880285973602430e-01, -4.1339928071149723e-01, -2.4802704124523722e-01, -8.2673593168222662e-02, 8.2673593168222662e-02, 2.4802704124523722e-01, 4.1339928071149723e-01, 5.7880285973602430e-01, 7.4425035741428780e-01, 9.0975439626347543e-01, 1.0753276548433179e+00, 1.2409828805395797e+00, 1.4067329025482804e+00, 1.5725906450998823e+00, 1.7385691409641026e+00, 1.9046815452776742e+00, 2.0709411497393346e+00, 2.2373613972185420e+00, 2.4039558968269845e+00, 2.5707384395048281e+00, 2.7377230141769160e+00, 2.9049238245378035e+00, 3.0723553065286380e+00, 3.2400321465734825e+00, 3.4079693006478804e+00, 3.5761820142581890e+00, 3.7446858434166801e+00, 3.9134966767045909e+00, 4.0826307585233783e+00, 4.2521047136434067e+00, 4.4219355731693852e+00, 4.5921408020531498e+00, 4.7627383282970204e+00, 4.9337465740051734e+00, 5.1051844884564179e+00, 5.2770715833897031e+00, 5.4494279707139679e+00, 5.6222744028767648e+00, 5.7956323161519689e+00, 5.9695238771362042e+00, 6.1439720327768708e+00, 6.3190005642925637e+00, 6.4946341453898597e+00, 6.6708984052298304e+00, 6.8478199966541871e+00, 7.0254266702460146e+00, 7.2037473548748121e+00, 7.3828122454620404e+00, 7.5626528988034316e+00, 7.7433023384005537e+00, 7.9247951693895704e+00, 8.1071677048133868e+00, 8.2904581046690247e+00, 8.4747065293805139e+00, 8.6599553096056603e+00, 8.8462491345909715e+00, 9.0336352616534104e+00, 9.2221637498031388e+00, 9.4118877210445753e+00, 9.6028636535242580e+00, 9.7951517114594342e+00, 9.9888161177141903e+00, 1.0183925576033463e+01, 1.0380553751354837e+01, 1.0578779818366641e+01, 1.0778689090663802e+01, 1.0980373745597644e+01, 1.1183933663391947e+01, 1.1389477403535365e+01, 1.1597123347173454e+01, 1.1807001041645883e+01, 1.2019252793050947e+01, 1.2234035565627281e+01, 1.2451523264048797e+01, 1.2671909498220252e+01, 1.2895410962476978e+01, 1.3122271606204340e+01, 1.3352767836885693e+01, 1.3587215088986124e+01, 1.3825976228134913e+01, 1.4069472464839684e+01, 1.4318197767810874e+01, 1.4572738267853815e+01, 1.4833798963124122e+01, 1.5102241428233055e+01, 1.5379138694506308e+01, 1.5665858058473457e+01, 1.5964191652640661e+01, 1.6276573939462359e+01, 1.6606470454912181e+01, 1.6959141339427859e+01, 1.7343355369019513e+01, 1.7776125755426882e+01, 1.8301973063597831e+01}, {-1.8355183937232482e+01, -1.7829840819908938e+01, -1.7397494085242659e+01, -1.7013662969810934e+01, -1.6661349346692710e+01, -1.6331792162325648e+01, -1.6019735882790211e+01, -1.5721717993090206e+01, -1.5435306145250426e+01, -1.5158709759192869e+01, -1.4890562720798751e+01, -1.4629792926034948e+01, -1.4375539545099908e+01, -1.4127098190154650e+01, -1.3883883239094454e+01, -1.3645401153510734e+01, -1.3411231091622829e+01, -1.3181010507418183e+01, -1.2954424246353401e+01, -1.2731196148405482e+01, -1.2511082484830109e+01, -1.2293866759574003e+01, -1.2079355542224606e+01, -1.1867375091697919e+01, -1.1657768593802700e+01, -1.1450393880891689e+01, -1.1245121534098722e+01, -1.1041833292131351e+01, -1.0840420707879813e+01, -1.0640784006999668e+01, -1.0442831112353673e+01, -1.0246476805614231e+01, -1.0051642003036079e+01, -9.8582531268427509e+00, -9.6662415571436178e+00, -9.4755431520404851e+00, -9.2860978257640348e+00, -9.0978491764272782e+00, -8.9107441563917540e+00, -8.7247327793845830e+00, -8.5397678594367203e+00, -8.3558047774774487e+00, -8.1728012720508225e+00, -7.9907172511424713e+00, -7.8095146225403225e+00, -7.6291571405168730e+00, -7.4496102669262783e+00, -7.2708410450674368e+00, -7.0928179848824850e+00, -6.9155109582455818e+00, -6.7388911032550611e+00, -6.5629307365772949e+00, -6.3876032730067926e+00, -6.2128831515070333e+00, -6.0387457670829185e+00, -5.8651674079104827e+00, -5.6921251972144509e+00, -5.5195970394407690e+00, -5.3475615703205710e+00, -5.1759981104652155e+00, -5.0048866221698640e+00, -4.8342076691363776e+00, -4.6639423788555394e+00, -4.4940724074145217e+00, -4.3245799065183155e+00, -4.1554474925341225e+00, -3.9866582173856151e+00, -3.8181955411399695e+00, -3.6500433061447404e+00, -3.4821857125843008e+00, -3.3146072953368710e+00, -3.1472929020232101e+00, -2.9802276721470844e+00, -2.8133970172356633e+00, -2.6467866018952186e+00, -2.4803823257039688e+00, -2.3141703058696805e+00, -2.1481368605848363e+00, -1.9822684930168015e+00, -1.8165518758745727e+00, -1.6509738364973834e+00, -1.4855213424137426e+00, -1.3201814873224036e+00, -1.1549414774493456e+00, -9.8978861823713149e-01, -8.2471030132498657e-01, -6.5969399177967603e-01, -4.9472721553871407e-01, -3.2979754702868869e-01, -1.6489259692248556e-01, -0.0000000000000000e+00, 1.6489259692248556e-01, 3.2979754702868869e-01, 4.9472721553871407e-01, 6.5969399177967603e-01, 8.2471030132498657e-01, 9.8978861823713149e-01, 1.1549414774493456e+00, 1.3201814873224036e+00, 1.4855213424137426e+00, 1.6509738364973834e+00, 1.8165518758745727e+00, 1.9822684930168015e+00, 2.1481368605848363e+00, 2.3141703058696805e+00, 2.4803823257039688e+00, 2.6467866018952186e+00, 2.8133970172356633e+00, 2.9802276721470844e+00, 3.1472929020232101e+00, 3.3146072953368710e+00, 3.4821857125843008e+00, 3.6500433061447404e+00, 3.8181955411399695e+00, 3.9866582173856151e+00, 4.1554474925341225e+00, 4.3245799065183155e+00, 4.4940724074145217e+00, 4.6639423788555394e+00, 4.8342076691363776e+00, 5.0048866221698640e+00, 5.1759981104652155e+00, 5.3475615703205710e+00, 5.5195970394407690e+00, 5.6921251972144509e+00, 5.8651674079104827e+00, 6.0387457670829185e+00, 6.2128831515070333e+00, 6.3876032730067926e+00, 6.5629307365772949e+00, 6.7388911032550611e+00, 6.9155109582455818e+00, 7.0928179848824850e+00, 7.2708410450674368e+00, 7.4496102669262783e+00, 7.6291571405168730e+00, 7.8095146225403225e+00, 7.9907172511424713e+00, 8.1728012720508225e+00, 8.3558047774774487e+00, 8.5397678594367203e+00, 8.7247327793845830e+00, 8.9107441563917540e+00, 9.0978491764272782e+00, 9.2860978257640348e+00, 9.4755431520404851e+00, 9.6662415571436178e+00, 9.8582531268427509e+00, 1.0051642003036079e+01, 1.0246476805614231e+01, 1.0442831112353673e+01, 1.0640784006999668e+01, 1.0840420707879813e+01, 1.1041833292131351e+01, 1.1245121534098722e+01, 1.1450393880891689e+01, 1.1657768593802700e+01, 1.1867375091697919e+01, 1.2079355542224606e+01, 1.2293866759574003e+01, 1.2511082484830109e+01, 1.2731196148405482e+01, 1.2954424246353401e+01, 1.3181010507418183e+01, 1.3411231091622829e+01, 1.3645401153510734e+01, 1.3883883239094454e+01, 1.4127098190154650e+01, 1.4375539545099908e+01, 1.4629792926034948e+01, 1.4890562720798751e+01, 1.5158709759192869e+01, 1.5435306145250426e+01, 1.5721717993090206e+01, 1.6019735882790211e+01, 1.6331792162325648e+01, 1.6661349346692710e+01, 1.7013662969810934e+01, 1.7397494085242659e+01, 1.7829840819908938e+01, 1.8355183937232482e+01}, {-1.8408245997246180e+01, -1.7883403744491030e+01, -1.7451477824729114e+01, -1.7068027026173699e+01, -1.6716068212476749e+01, -1.6386848004427836e+01, -1.6075115445979726e+01, -1.5777411024325023e+01, -1.5491304492792262e+01, -1.5215006814022102e+01, -1.4947153048869007e+01, -1.4686672014714095e+01, -1.4432703621796808e+01, -1.4184544088639219e+01, -1.3941608298492062e+01, -1.3703403140370927e+01, -1.3469508138708429e+01, -1.3239561064882505e+01, -1.3013247042274847e+01, -1.2790290156511402e+01, -1.2570446897828043e+01, -1.2353500966915787e+01, -1.2139259111417608e+01, -1.1927547752486015e+01, -1.1718210224692305e+01, -1.1511104497611852e+01, -1.1306101279669830e+01, -1.1103082428282363e+01, -1.0901939607604296e+01, -1.0702573148080202e+01, -1.0504891071714988e+01, -1.0308808254390055e+01, -1.0114245702254145e+01, -9.9211299236483459e+00, -9.7293923814947600e+00, -9.5389690138184235e+00, -9.3497998122512573e+00, -9.1618284501124911e+00, -8.9750019530671192e+00, -8.7892704065055494e+00, -8.6045866947189253e+00, -8.4209062677087161e+00, -8.2381869320992998e+00, -8.0563886631444781e+00, -7.8754734352537348e+00, -7.6954050688277018e+00, -7.5161490914978035e+00, -7.3376726121226348e+00, -7.1599442061117617e+00, -6.9829338108329129e+00, -6.8066126300166054e+00, -6.6309530462073942e+00, -6.4559285404270428e+00, -6.2815136183148121e+00, -6.1076837420963281e+00, -5.9344152678072613e+00, -5.7616853872629088e+00, -5.5894720743212600e+00, -5.4177540350364595e+00, -5.2465106613426817e+00, -5.0757219879463076e+00, -4.9053686521374775e+00, -4.7354318562614344e+00, -4.5658933326158548e+00, -4.3967353105632334e+00, -4.2279404856676086e+00, -4.0594919906828633e+00, -3.8913733682357932e+00, -3.7235685450613194e+00, -3.5560618076598769e+00, -3.3888377792582984e+00, -3.2218813979656056e+00, -3.0551778960241212e+00, -2.8887127800643957e+00, -2.7224718122796761e+00, -2.5564409924420968e+00, -2.3906065406885992e+00, -2.2249548810097695e+00, -2.0594726253794451e+00, -1.8941465584671033e+00, -1.7289636228787715e+00, -1.5639109048755229e+00, -1.3989756205215691e+00, -1.2341451022165917e+00, -1.0694067855692595e+00, -9.0474819657091143e-01, -7.4015693903015356e-01, -5.7562068223063112e-01, -4.1112714877553319e-01, -2.4666410258345153e-01, -8.2219337001082138e-02, 8.2219337001082138e-02, 2.4666410258345153e-01, 4.1112714877553319e-01, 5.7562068223063112e-01, 7.4015693903015356e-01, 9.0474819657091143e-01, 1.0694067855692595e+00, 1.2341451022165917e+00, 1.3989756205215691e+00, 1.5639109048755229e+00, 1.7289636228787715e+00, 1.8941465584671033e+00, 2.0594726253794451e+00, 2.2249548810097695e+00, 2.3906065406885992e+00, 2.5564409924420968e+00, 2.7224718122796761e+00, 2.8887127800643957e+00, 3.0551778960241212e+00, 3.2218813979656056e+00, 3.3888377792582984e+00, 3.5560618076598769e+00, 3.7235685450613194e+00, 3.8913733682357932e+00, 4.0594919906828633e+00, 4.2279404856676086e+00, 4.3967353105632334e+00, 4.5658933326158548e+00, 4.7354318562614344e+00, 4.9053686521374775e+00, 5.0757219879463076e+00, 5.2465106613426817e+00, 5.4177540350364595e+00, 5.5894720743212600e+00, 5.7616853872629088e+00, 5.9344152678072613e+00, 6.1076837420963281e+00, 6.2815136183148121e+00, 6.4559285404270428e+00, 6.6309530462073942e+00, 6.8066126300166054e+00, 6.9829338108329129e+00, 7.1599442061117617e+00, 7.3376726121226348e+00, 7.5161490914978035e+00, 7.6954050688277018e+00, 7.8754734352537348e+00, 8.0563886631444781e+00, 8.2381869320992998e+00, 8.4209062677087161e+00, 8.6045866947189253e+00, 8.7892704065055494e+00, 8.9750019530671192e+00, 9.1618284501124911e+00, 9.3497998122512573e+00, 9.5389690138184235e+00, 9.7293923814947600e+00, 9.9211299236483459e+00, 1.0114245702254145e+01, 1.0308808254390055e+01, 1.0504891071714988e+01, 1.0702573148080202e+01, 1.0901939607604296e+01, 1.1103082428282363e+01, 1.1306101279669830e+01, 1.1511104497611852e+01, 1.1718210224692305e+01, 1.1927547752486015e+01, 1.2139259111417608e+01, 1.2353500966915787e+01, 1.2570446897828043e+01, 1.2790290156511402e+01, 1.3013247042274847e+01, 1.3239561064882505e+01, 1.3469508138708429e+01, 1.3703403140370927e+01, 1.3941608298492062e+01, 1.4184544088639219e+01, 1.4432703621796808e+01, 1.4686672014714095e+01, 1.4947153048869007e+01, 1.5215006814022102e+01, 1.5491304492792262e+01, 1.5777411024325023e+01, 1.6075115445979726e+01, 1.6386848004427836e+01, 1.6716068212476749e+01, 1.7068027026173699e+01, 1.7451477824729114e+01, 1.7883403744491030e+01, 1.8408245997246180e+01}, {-1.8461160480857558e+01, -1.7936815806741905e+01, -1.7505307899899091e+01, -1.7122234853198016e+01, -1.6770628427712005e+01, -1.6441742871044735e+01, -1.6130331776708392e+01, -1.5832938615515195e+01, -1.5547135229076916e+01, -1.5271134113158810e+01, -1.5003571496240674e+01, -1.4743377111311560e+01, -1.4489691603942756e+01, -1.4241811795112390e+01, -1.3999153070125370e+01, -1.3761222742582584e+01, -1.3527600700651213e+01, -1.3297925030905425e+01, -1.3071881132685062e+01, -1.2849193335481473e+01, -1.2629618346876333e+01, -1.2412940062792593e+01, -1.2198965407516690e+01, -1.1987520963108198e+01, -1.1778450211639703e+01, -1.1571611258704099e+01, -1.1366874938858906e+01, -1.1164123227107424e+01, -1.0963247897778071e+01, -1.0764149385037474e+01, -1.0566735808984420e+01, -1.0370922138674908e+01, -1.0176629469126997e+01, -9.9837843937805424e+00, -9.7923184573541491e+00, -9.6021676767792830e+00, -9.4132721200689708e+00, -9.2255755347225286e+00, -9.0390250186738808e+00, -8.8535707279314924e+00, -8.6691656159885877e+00, -8.4857652008457727e+00, -8.3033273561177268e+00, -8.1218121232175022e+00, -7.9411815420463903e+00, -7.7613994979807179e+00, -7.5824315832521663e+00, -7.4042449710755918e+00, -7.2268083010962609e+00, -7.0500915749135666e+00, -6.8740660605962152e+00, -6.6987042052389292e+00, -6.5239795547267194e+00, -6.3498666799725676e+00, -6.1763411089806590e+00, -6.0033792641618602e+00, -5.8309584043931153e+00, -5.6590565713687386e+00, -5.4876525398409859e+00, -5.3167257713902920e+00, -5.1462563714034442e+00, -4.9762250489711075e+00, -4.8066130794454613e+00, -4.6374022694244390e+00, -4.4685749239519819e+00, -4.3001138157438552e+00, -4.1320021562665863e+00, -3.9642235685129914e+00, -3.7967620613319606e+00, -3.6296020051828295e+00, -3.4627281091959579e+00, -3.2961253994312023e+00, -3.1297791982350316e+00, -2.9636751046050795e+00, -2.7977989754781833e+00, -2.6321369078644477e+00, -2.4666752217556631e+00, -2.3014004437416671e+00, -2.1362992912728620e+00, -1.9713586575113293e+00, -1.8065655967166996e+00, -1.6419073101163049e+00, -1.4773711322121057e+00, -1.3129445174795540e+00, -1.1486150274158851e+00, -9.8437031789740859e-01, -8.2019812680717263e-01, -6.5608626189593511e-01, -4.9202258884072003e-01, -3.2799501946636006e-01, -1.6399150009634114e-01, -0.0000000000000000e+00, 1.6399150009634114e-01, 3.2799501946636006e-01, 4.9202258884072003e-01, 6.5608626189593511e-01, 8.2019812680717263e-01, 9.8437031789740859e-01, 1.1486150274158851e+00, 1.3129445174795540e+00, 1.4773711322121057e+00, 1.6419073101163049e+00, 1.8065655967166996e+00, 1.9713586575113293e+00, 2.1362992912728620e+00, 2.3014004437416671e+00, 2.4666752217556631e+00, 2.6321369078644477e+00, 2.7977989754781833e+00, 2.9636751046050795e+00, 3.1297791982350316e+00, 3.2961253994312023e+00, 3.4627281091959579e+00, 3.6296020051828295e+00, 3.7967620613319606e+00, 3.9642235685129914e+00, 4.1320021562665863e+00, 4.3001138157438552e+00, 4.4685749239519819e+00, 4.6374022694244390e+00, 4.8066130794454613e+00, 4.9762250489711075e+00, 5.1462563714034442e+00, 5.3167257713902920e+00, 5.4876525398409859e+00, 5.6590565713687386e+00, 5.8309584043931153e+00, 6.0033792641618602e+00, 6.1763411089806590e+00, 6.3498666799725676e+00, 6.5239795547267194e+00, 6.6987042052389292e+00, 6.8740660605962152e+00, 7.0500915749135666e+00, 7.2268083010962609e+00, 7.4042449710755918e+00, 7.5824315832521663e+00, 7.7613994979807179e+00, 7.9411815420463903e+00, 8.1218121232175022e+00, 8.3033273561177268e+00, 8.4857652008457727e+00, 8.6691656159885877e+00, 8.8535707279314924e+00, 9.0390250186738808e+00, 9.2255755347225286e+00, 9.4132721200689708e+00, 9.6021676767792830e+00, 9.7923184573541491e+00, 9.9837843937805424e+00, 1.0176629469126997e+01, 1.0370922138674908e+01, 1.0566735808984420e+01, 1.0764149385037474e+01, 1.0963247897778071e+01, 1.1164123227107424e+01, 1.1366874938858906e+01, 1.1571611258704099e+01, 1.1778450211639703e+01, 1.1987520963108198e+01, 1.2198965407516690e+01, 1.2412940062792593e+01, 1.2629618346876333e+01, 1.2849193335481473e+01, 1.3071881132685062e+01, 1.3297925030905425e+01, 1.3527600700651213e+01, 1.3761222742582584e+01, 1.3999153070125370e+01, 1.4241811795112390e+01, 1.4489691603942756e+01, 1.4743377111311560e+01, 1.5003571496240674e+01, 1.5271134113158810e+01, 1.5547135229076916e+01, 1.5832938615515195e+01, 1.6130331776708392e+01, 1.6441742871044735e+01, 1.6770628427712005e+01, 1.7122234853198016e+01, 1.7505307899899091e+01, 1.7936815806741905e+01, 1.8461160480857558e+01}, {-1.8513928608263910e+01, -1.7990078266499342e+01, -1.7558985604821832e+01, -1.7176287776635139e+01, -1.6825031348357740e+01, -1.6496478147418177e+01, -1.6185386288902521e+01, -1.5888302208889046e+01, -1.5602799824404595e+01, -1.5327093154858311e+01, -1.5059819589095412e+01, -1.4799909769977225e+01, -1.4546505073756210e+01, -1.4298902920011114e+01, -1.4056519192842705e+01, -1.3818861627636300e+01, -1.3585510473849133e+01, -1.3356104131088610e+01, -1.3130328272714728e+01, -1.2907907470327904e+01, -1.2688598647247023e+01, -1.2472185893139361e+01, -1.2258476307546671e+01, -1.2047296632129509e+01, -1.1838490495223393e+01, -1.1631916137256281e+01, -1.1427444517781534e+01, -1.1224957728290695e+01, -1.1024347652217228e+01, -1.0825514826405534e+01, -1.0628367468022887e+01, -1.0432820638288694e+01, -1.0238795520089184e+01, -1.0046218790968188e+01, -9.8550220764490426e+00, -9.6651414713778827e+00, -9.4765171191542965e+00, -9.2890928404578474e+00, -9.1028158044838392e+00, -8.9176362368413074e+00, -8.7335071591960247e+00, -8.5503841565041103e+00, -8.3682251683108984e+00, -8.1869903011111198e+00, -8.0066416592005272e+00, -7.8271431918122021e+00, -7.6484605546357463e+00, -7.4705609840747460e+00, -7.2934131828156445e+00, -7.1169872154661693e+00, -6.9412544131792480e+00, -6.7661872863133015e+00, -6.5917594442957039e+00, -6.4179455219559527e+00, -6.2447211116812200e+00, -6.0720627008216166e+00, -5.8999476138372433e+00, -5.7283539587355410e+00, -5.5572605773966774e+00, -5.3866469994277919e+00, -5.2164933992246887e+00, -5.0467805559527736e+00, -4.8774898161882945e+00, -4.7086030589866992e+00, -4.5401026631678034e+00, -4.3719714766276327e+00, -4.2041927875047698e+00, -4.0367502970449332e+00, -3.8696280940217886e+00, -3.7028106305845436e+00, -3.5362826994142633e+00, -3.3700294120808700e+00, -3.2040361785018661e+00, -3.0382886874118746e+00, -2.8727728877593544e+00, -2.7074749709533479e+00, -2.5423813538889330e+00, -2.3774786626852964e+00, -2.2127537170750284e+00, -2.0481935153874455e+00, -1.8837852200725123e+00, -1.7195161437153161e+00, -1.5553737354940405e+00, -1.3913455680370777e+00, -1.2274193246372884e+00, -1.0635827867835286e+00, -8.9982382197139399e-01, -7.3613037175675000e-01, -5.7249044001699179e-01, -4.0889208138615224e-01, -2.4532338983095259e-01, -8.1772487335672980e-02, 8.1772487335672980e-02, 2.4532338983095259e-01, 4.0889208138615224e-01, 5.7249044001699179e-01, 7.3613037175675000e-01, 8.9982382197139399e-01, 1.0635827867835286e+00, 1.2274193246372884e+00, 1.3913455680370777e+00, 1.5553737354940405e+00, 1.7195161437153161e+00, 1.8837852200725123e+00, 2.0481935153874455e+00, 2.2127537170750284e+00, 2.3774786626852964e+00, 2.5423813538889330e+00, 2.7074749709533479e+00, 2.8727728877593544e+00, 3.0382886874118746e+00, 3.2040361785018661e+00, 3.3700294120808700e+00, 3.5362826994142633e+00, 3.7028106305845436e+00, 3.8696280940217886e+00, 4.0367502970449332e+00, 4.2041927875047698e+00, 4.3719714766276327e+00, 4.5401026631678034e+00, 4.7086030589866992e+00, 4.8774898161882945e+00, 5.0467805559527736e+00, 5.2164933992246887e+00, 5.3866469994277919e+00, 5.5572605773966774e+00, 5.7283539587355410e+00, 5.8999476138372433e+00, 6.0720627008216166e+00, 6.2447211116812200e+00, 6.4179455219559527e+00, 6.5917594442957039e+00, 6.7661872863133015e+00, 6.9412544131792480e+00, 7.1169872154661693e+00, 7.2934131828156445e+00, 7.4705609840747460e+00, 7.6484605546357463e+00, 7.8271431918122021e+00, 8.0066416592005272e+00, 8.1869903011111198e+00, 8.3682251683108984e+00, 8.5503841565041103e+00, 8.7335071591960247e+00, 8.9176362368413074e+00, 9.1028158044838392e+00, 9.2890928404578474e+00, 9.4765171191542965e+00, 9.6651414713778827e+00, 9.8550220764490426e+00, 1.0046218790968188e+01, 1.0238795520089184e+01, 1.0432820638288694e+01, 1.0628367468022887e+01, 1.0825514826405534e+01, 1.1024347652217228e+01, 1.1224957728290695e+01, 1.1427444517781534e+01, 1.1631916137256281e+01, 1.1838490495223393e+01, 1.2047296632129509e+01, 1.2258476307546671e+01, 1.2472185893139361e+01, 1.2688598647247023e+01, 1.2907907470327904e+01, 1.3130328272714728e+01, 1.3356104131088610e+01, 1.3585510473849133e+01, 1.3818861627636300e+01, 1.4056519192842705e+01, 1.4298902920011114e+01, 1.4546505073756210e+01, 1.4799909769977225e+01, 1.5059819589095412e+01, 1.5327093154858311e+01, 1.5602799824404595e+01, 1.5888302208889046e+01, 1.6185386288902521e+01, 1.6496478147418177e+01, 1.6825031348357740e+01, 1.7176287776635139e+01, 1.7558985604821832e+01, 1.7990078266499342e+01, 1.8513928608263910e+01}, {-1.8566551582966934e+01, -1.8043192366212146e+01, -1.7612512215572043e+01, -1.7230187103675732e+01, -1.6879278311267964e+01, -1.6551055199152213e+01, -1.6240280376324659e+01, -1.5943503225988053e+01, -1.5658299727865778e+01, -1.5382885415641553e+01, -1.5115898831352473e+01, -1.4856271522065896e+01, -1.4603145590122086e+01, -1.4355819049893570e+01, -1.4113708281060786e+01, -1.3876321438029819e+01, -1.3643239129136898e+01, -1.3414100064890203e+01, -1.3188590190760220e+01, -1.2966434318726625e+01, -1.2747389586262109e+01, -1.2531240275314762e+01, -1.2317793659316827e+01, -1.2106876638246456e+01, -1.1898332985486029e+01, -1.1692021075138110e+01, -1.1487811990637235e+01, -1.1285587938886058e+01, -1.1085240911376399e+01, -1.0886671546608126e+01, -1.0689788157813780e+01, -1.0494505897387436e+01, -1.0300746035105149e+01, -1.0108435331643134e+01, -9.9175054923613413e+00, -9.7278926890529842e+00, -9.5395371395344313e+00, -9.3523827366910055e+00, -9.1663767199978832e+00, -8.9814693836739572e+00, -8.7976138165555611e+00, -8.6147656695390857e+00, -8.4328829470701354e+00, -8.2519258196777496e+00, -8.0718564549859924e+00, -7.8926388649980117e+00, -7.7142387677523603e+00, -7.5366234617083592e+00, -7.3597617114348806e+00, -7.1836236433617389e+00, -7.0081806505105702e+00, -6.8334053052569255e+00, -6.6592712792911071e+00, -6.4857532700449330e+00, -6.3128269329377309e+00, -6.1404688188693868e+00, -5.9686563164530524e+00, -5.7973675985364332e+00, -5.6265815726098278e+00, -5.4562778347421155e+00, -5.2864366267236216e+00, -5.1170387961280301e+00, -4.9480657590346588e+00, -4.7794994651782767e+00, -4.6113223653163988e+00, -4.4435173806242290e+00, -4.2760678739453368e+00, -4.1089576227421016e+00, -3.9421707936041384e+00, -3.7756919181855801e+00, -3.6095058704533836e+00, -3.4435978451389198e+00, -3.2779533372941430e+00, -3.1125581228617367e+00, -2.9473982401758851e+00, -2.7824599723168095e+00, -2.6177298302480856e+00, -2.4531945366709622e+00, -2.2888410105346408e+00, -2.1246563521456703e+00, -1.9606278288234207e+00, -1.7967428610519807e+00, -1.6329890090818511e+00, -1.4693539599375276e+00, -1.3058255147894620e+00, -1.1423915766510224e+00, -9.7904013836295944e-01, -8.1575927082952060e-01, -6.5253711147178228e-01, -4.8936185286498823e-01, -3.2622173152770212e-01, -1.6310501683142664e-01, -0.0000000000000000e+00, 1.6310501683142664e-01, 3.2622173152770212e-01, 4.8936185286498823e-01, 6.5253711147178228e-01, 8.1575927082952060e-01, 9.7904013836295944e-01, 1.1423915766510224e+00, 1.3058255147894620e+00, 1.4693539599375276e+00, 1.6329890090818511e+00, 1.7967428610519807e+00, 1.9606278288234207e+00, 2.1246563521456703e+00, 2.2888410105346408e+00, 2.4531945366709622e+00, 2.6177298302480856e+00, 2.7824599723168095e+00, 2.9473982401758851e+00, 3.1125581228617367e+00, 3.2779533372941430e+00, 3.4435978451389198e+00, 3.6095058704533836e+00, 3.7756919181855801e+00, 3.9421707936041384e+00, 4.1089576227421016e+00, 4.2760678739453368e+00, 4.4435173806242290e+00, 4.6113223653163988e+00, 4.7794994651782767e+00, 4.9480657590346588e+00, 5.1170387961280301e+00, 5.2864366267236216e+00, 5.4562778347421155e+00, 5.6265815726098278e+00, 5.7973675985364332e+00, 5.9686563164530524e+00, 6.1404688188693868e+00, 6.3128269329377309e+00, 6.4857532700449330e+00, 6.6592712792911071e+00, 6.8334053052569255e+00, 7.0081806505105702e+00, 7.1836236433617389e+00, 7.3597617114348806e+00, 7.5366234617083592e+00, 7.7142387677523603e+00, 7.8926388649980117e+00, 8.0718564549859924e+00, 8.2519258196777496e+00, 8.4328829470701354e+00, 8.6147656695390857e+00, 8.7976138165555611e+00, 8.9814693836739572e+00, 9.1663767199978832e+00, 9.3523827366910055e+00, 9.5395371395344313e+00, 9.7278926890529842e+00, 9.9175054923613413e+00, 1.0108435331643134e+01, 1.0300746035105149e+01, 1.0494505897387436e+01, 1.0689788157813780e+01, 1.0886671546608126e+01, 1.1085240911376399e+01, 1.1285587938886058e+01, 1.1487811990637235e+01, 1.1692021075138110e+01, 1.1898332985486029e+01, 1.2106876638246456e+01, 1.2317793659316827e+01, 1.2531240275314762e+01, 1.2747389586262109e+01, 1.2966434318726625e+01, 1.3188590190760220e+01, 1.3414100064890203e+01, 1.3643239129136898e+01, 1.3876321438029819e+01, 1.4113708281060786e+01, 1.4355819049893570e+01, 1.4603145590122086e+01, 1.4856271522065896e+01, 1.5115898831352473e+01, 1.5382885415641553e+01, 1.5658299727865778e+01, 1.5943503225988053e+01, 1.6240280376324659e+01, 1.6551055199152213e+01, 1.6879278311267964e+01, 1.7230187103675732e+01, 1.7612512215572043e+01, 1.8043192366212146e+01, 1.8566551582966934e+01}, {-1.8619030592090468e+01, -1.8096159331273782e+01, -1.7665888990577489e+01, -1.7283934123310647e+01, -1.6933370634565016e+01, -1.6605475372599290e+01, -1.6295015412972358e+01, -1.5998543068078176e+01, -1.5713636367765231e+01, -1.5438512350731910e+01, -1.5171810705118517e+01, -1.4912463876600265e+01, -1.4659614689068135e+01, -1.4412561747929246e+01, -1.4170721925268760e+01, -1.3933603791786325e+01, -1.3700788312318828e+01, -1.3471914506172659e+01, -1.3246668589046763e+01, -1.3024775611596180e+01, -1.2805992923888546e+01, -1.2590104998712771e+01, -1.2376919282049462e+01, -1.2166262830933078e+01, -1.1957979562598471e+01, -1.1751927983683725e+01, -1.1547979300411118e+01, -1.1346015834038415e+01, -1.1145929683090303e+01, -1.0947621586721102e+01, -1.0750999953246895e+01, -1.0555980025269434e+01, -1.0362483158498314e+01, -1.0170436195792986e+01, -9.9797709214047838e+00, -9.7904235831297708e+00, -9.6023344722552224e+00, -9.4154475529222363e+00, -9.2297101339294976e+00, -9.0450725771408784e+00, -8.8614880375878489e+00, -8.6789122311192006e+00, -8.4973032260786319e+00, -8.3166212560112189e+00, -8.1368285508332487e+00, -7.9578891842622976e+00, -7.7797689356090070e+00, -7.6024351642886749e+00, -7.4258566956282692e+00, -7.2500037167290969e+00, -7.0748476813029546e+00, -6.9003612225343067e+00, -6.7265180731367256e+00, -6.5532929918714933e+00, -6.3806616958821749e+00, -6.2086007982735998e+00, -6.0370877504282516e+00, -5.8661007886095131e+00, -5.6956188844502709e+00, -5.5256216989684903e+00, -5.3560895397890276e+00, -5.1870033212841671e+00, -5.0183445273745217e+00, -4.8500951767577565e+00, -4.6822377903553614e+00, -4.5147553607879187e+00, -4.3476313237072048e+00, -4.1808495308294304e+00, -4.0143942245280941e+00, -3.8482500138575717e+00, -3.6824018518898707e+00, -3.5168350142570763e+00, -3.3515350788010423e+00, -3.1864879062399973e+00, -3.0216796217689894e+00, -2.8570965975176055e+00, -2.6927254357942609e+00, -2.5285529530516158e+00, -2.3645661645123681e+00, -2.2007522693989476e+00, -2.0370986367144122e+00, -1.8735927915252717e+00, -1.7102224017000158e+00, -1.5469752650598505e+00, -1.3838392969005895e+00, -1.2208025178467894e+00, -1.0578530420011503e+00, -8.9497906535386207e-01, -7.3216885441804769e-01, -5.6941073505871143e-01, -4.0669308148366978e-01, -2.4400430536582823e-01, -8.1332845066888051e-02, 8.1332845066888051e-02, 2.4400430536582823e-01, 4.0669308148366978e-01, 5.6941073505871143e-01, 7.3216885441804769e-01, 8.9497906535386207e-01, 1.0578530420011503e+00, 1.2208025178467894e+00, 1.3838392969005895e+00, 1.5469752650598505e+00, 1.7102224017000158e+00, 1.8735927915252717e+00, 2.0370986367144122e+00, 2.2007522693989476e+00, 2.3645661645123681e+00, 2.5285529530516158e+00, 2.6927254357942609e+00, 2.8570965975176055e+00, 3.0216796217689894e+00, 3.1864879062399973e+00, 3.3515350788010423e+00, 3.5168350142570763e+00, 3.6824018518898707e+00, 3.8482500138575717e+00, 4.0143942245280941e+00, 4.1808495308294304e+00, 4.3476313237072048e+00, 4.5147553607879187e+00, 4.6822377903553614e+00, 4.8500951767577565e+00, 5.0183445273745217e+00, 5.1870033212841671e+00, 5.3560895397890276e+00, 5.5256216989684903e+00, 5.6956188844502709e+00, 5.8661007886095131e+00, 6.0370877504282516e+00, 6.2086007982735998e+00, 6.3806616958821749e+00, 6.5532929918714933e+00, 6.7265180731367256e+00, 6.9003612225343067e+00, 7.0748476813029546e+00, 7.2500037167290969e+00, 7.4258566956282692e+00, 7.6024351642886749e+00, 7.7797689356090070e+00, 7.9578891842622976e+00, 8.1368285508332487e+00, 8.3166212560112189e+00, 8.4973032260786319e+00, 8.6789122311192006e+00, 8.8614880375878489e+00, 9.0450725771408784e+00, 9.2297101339294976e+00, 9.4154475529222363e+00, 9.6023344722552224e+00, 9.7904235831297708e+00, 9.9797709214047838e+00, 1.0170436195792986e+01, 1.0362483158498314e+01, 1.0555980025269434e+01, 1.0750999953246895e+01, 1.0947621586721102e+01, 1.1145929683090303e+01, 1.1346015834038415e+01, 1.1547979300411118e+01, 1.1751927983683725e+01, 1.1957979562598471e+01, 1.2166262830933078e+01, 1.2376919282049462e+01, 1.2590104998712771e+01, 1.2805992923888546e+01, 1.3024775611596180e+01, 1.3246668589046763e+01, 1.3471914506172659e+01, 1.3700788312318828e+01, 1.3933603791786325e+01, 1.4170721925268760e+01, 1.4412561747929246e+01, 1.4659614689068135e+01, 1.4912463876600265e+01, 1.5171810705118517e+01, 1.5438512350731910e+01, 1.5713636367765231e+01, 1.5998543068078176e+01, 1.6295015412972358e+01, 1.6605475372599290e+01, 1.6933370634565016e+01, 1.7283934123310647e+01, 1.7665888990577489e+01, 1.8096159331273782e+01, 1.8619030592090468e+01}, {-1.8671366806690571e+01, -1.8148980370347783e+01, -1.7719117170958008e+01, -1.7337530106682756e+01, -1.6987309618003824e+01, -1.6659739995236801e+01, -1.6349592753466883e+01, -1.6053423116550778e+01, -1.5768811152035209e+01, -1.5493975394480826e+01, -1.5227556671125813e+01, -1.4968488320721917e+01, -1.4715913884228952e+01, -1.4469132554376165e+01, -1.4227561692518973e+01, -1.3990710282959036e+01, -1.3758159644687614e+01, -1.3529549103735965e+01, -1.3304565144176481e+01, -1.3082933053660961e+01, -1.2864410393317099e+01, -1.2648781825357542e+01, -1.2435854966991251e+01, -1.2225457031069224e+01, -1.2017432077505465e+01, -1.1811638744355296e+01, -1.1607948359555895e+01, -1.1406243357684700e+01, -1.1206415943294315e+01, -1.1008366955213159e+01, -1.0812004895879960e+01, -1.0617245097158223e+01, -1.0424008999756163e+01, -1.0232223527789033e+01, -1.0041820543476462e+01, -9.8527363696957284e+00, -9.6649113702822387e+00, -9.4782895797065567e+00, -9.2928183751587881e+00, -9.1084481852078358e+00, -8.9251322301305365e+00, -8.7428262897666009e+00, -8.5614884953828341e+00, -8.3810791425501474e+00, -8.2015605224698938e+00, -8.0228967695483639e+00, -7.8450537233223443e+00, -7.6679988030953385e+00, -7.4917008938611840e+00, -7.3161302422763823e+00, -7.1412583615998901e+00, -6.9670579446537078e+00, -6.7935027839732776e+00, -6.6205676984161617e+00, -6.4482284655834805e+00, -6.2764617594829843e+00, -6.1052450929273041e+00, -5.9345567642172057e+00, -5.7643758077087970e+00, -5.5946819479066203e+00, -5.4254555567622882e+00, -5.2566776138914113e+00, -5.0883296694508156e+00, -4.9203938094437563e+00, -4.7528526232436477e+00, -4.5856891731470037e+00, -4.4188869657842096e+00, -4.2524299252326587e+00, -4.0863023676909851e+00, -3.9204889775857690e+00, -3.7549747849933839e+00, -3.5897451442697546e+00, -3.4247857137898574e+00, -3.2600824367068570e+00, -3.0956215226480941e+00, -2.9313894302716164e+00, -2.7673728506128410e+00, -2.6035586911561817e+00, -2.4399340605712174e+00, -2.2764862540572279e+00, -2.1132027392437367e+00, -1.9500711425981514e+00, -1.7870792362946351e+00, -1.6242149255011178e+00, -1.4614662360438109e+00, -1.2988213024107587e+00, -1.1362683560579210e+00, -9.7379571398297626e-01, -8.1139176753353270e-01, -6.4904497141773709e-01, -4.8674383288637452e-01, -3.2447690105649102e-01, -1.6223275634733261e-01, -0.0000000000000000e+00, 1.6223275634733261e-01, 3.2447690105649102e-01, 4.8674383288637452e-01, 6.4904497141773709e-01, 8.1139176753353270e-01, 9.7379571398297626e-01, 1.1362683560579210e+00, 1.2988213024107587e+00, 1.4614662360438109e+00, 1.6242149255011178e+00, 1.7870792362946351e+00, 1.9500711425981514e+00, 2.1132027392437367e+00, 2.2764862540572279e+00, 2.4399340605712174e+00, 2.6035586911561817e+00, 2.7673728506128410e+00, 2.9313894302716164e+00, 3.0956215226480941e+00, 3.2600824367068570e+00, 3.4247857137898574e+00, 3.5897451442697546e+00, 3.7549747849933839e+00, 3.9204889775857690e+00, 4.0863023676909851e+00, 4.2524299252326587e+00, 4.4188869657842096e+00, 4.5856891731470037e+00, 4.7528526232436477e+00, 4.9203938094437563e+00, 5.0883296694508156e+00, 5.2566776138914113e+00, 5.4254555567622882e+00, 5.5946819479066203e+00, 5.7643758077087970e+00, 5.9345567642172057e+00, 6.1052450929273041e+00, 6.2764617594829843e+00, 6.4482284655834805e+00, 6.6205676984161617e+00, 6.7935027839732776e+00, 6.9670579446537078e+00, 7.1412583615998901e+00, 7.3161302422763823e+00, 7.4917008938611840e+00, 7.6679988030953385e+00, 7.8450537233223443e+00, 8.0228967695483639e+00, 8.2015605224698938e+00, 8.3810791425501474e+00, 8.5614884953828341e+00, 8.7428262897666009e+00, 8.9251322301305365e+00, 9.1084481852078358e+00, 9.2928183751587881e+00, 9.4782895797065567e+00, 9.6649113702822387e+00, 9.8527363696957284e+00, 1.0041820543476462e+01, 1.0232223527789033e+01, 1.0424008999756163e+01, 1.0617245097158223e+01, 1.0812004895879960e+01, 1.1008366955213159e+01, 1.1206415943294315e+01, 1.1406243357684700e+01, 1.1607948359555895e+01, 1.1811638744355296e+01, 1.2017432077505465e+01, 1.2225457031069224e+01, 1.2435854966991251e+01, 1.2648781825357542e+01, 1.2864410393317099e+01, 1.3082933053660961e+01, 1.3304565144176481e+01, 1.3529549103735965e+01, 1.3758159644687614e+01, 1.3990710282959036e+01, 1.4227561692518973e+01, 1.4469132554376165e+01, 1.4715913884228952e+01, 1.4968488320721917e+01, 1.5227556671125813e+01, 1.5493975394480826e+01, 1.5768811152035209e+01, 1.6053423116550778e+01, 1.6349592753466883e+01, 1.6659739995236801e+01, 1.6987309618003824e+01, 1.7337530106682756e+01, 1.7719117170958008e+01, 1.8148980370347783e+01, 1.8671366806690571e+01}, {-1.8723561382058008e+01, -1.8201656675685278e+01, -1.7772197980856198e+01, -1.7390976307430105e+01, -1.7041096543327139e+01, -1.6713850376034177e+01, -1.6404013733432148e+01, -1.6108144733313441e+01, -1.5823825468638194e+01, -1.5549275960782586e+01, -1.5283138169159214e+01, -1.5024346320130698e+01, -1.4772044667297957e+01, -1.4525532987045759e+01, -1.4284229126904924e+01, -1.4047642482122557e+01, -1.3815354723529373e+01, -1.3587005481836711e+01, -1.3362281507661821e+01, -1.3140908323999378e+01, -1.2922643701525621e+01, -1.2707272490482195e+01, -1.2494602478007950e+01, -1.2284461031551617e+01, -1.2076692352553557e+01, -1.1871155209388238e+01, -1.1667721050654935e+01, -1.1466272423235269e+01, -1.1266701636724759e+01, -1.1068909628665612e+01, -1.0872804994678496e+01, -1.0678303154963148e+01, -1.0485325634312177e+01, -1.0293799437190248e+01, -1.0103656502883585e+01, -9.9148332284509078e+00, -9.7272700493753241e+00, -9.5409110695534167e+00, -9.3557037336580802e+00, -9.1715985360473766e+00, -8.9885487613184782e+00, -8.8065102523660030e+00, -8.6254412024311282e+00, -8.4453019681474064e+00, -8.2660549010220361e+00, -8.0876641951531028e+00, -7.9100957492873887e+00, -7.7333170415796193e+00, -7.5572970156311445e+00, -7.3820059765703627e+00, -7.2074154960945611e+00, -7.0334983255273515e+00, -6.8602283160613764e+00, -6.6875803454554488e+00, -6.5155302505411381e+00, -6.3440547649682282e+00, -6.1731314616830320e+00, -6.0027386996898384e+00, -5.8328555746948121e+00, -5.6634618732746507e+00, -5.4945380302499895e+00, -5.3260650889766197e+00, -5.1580246642968088e+00, -4.9903989079186992e+00, -4.8231704760145977e+00, -4.6563224988490806e+00, -4.4898385522658026e+00, -4.3237026308777766e+00, -4.1578991228200994e+00, -3.9924127859367369e+00, -3.8272287252842805e+00, -3.6623323718456740e+00, -3.4977094623559837e+00, -3.3333460201503651e+00, -3.1692283369516736e+00, -3.0053429555216815e+00, -2.8416766531057553e+00, -2.6782164256060947e+00, -2.5149494724234098e+00, -2.3518631819111540e+00, -2.1889451173902774e+00, -2.0261830036759103e+00, -1.8635647140704730e+00, -1.7010782577804868e+00, -1.5387117677168360e+00, -1.3764534886404416e+00, -1.2142917656172734e+00, -1.0522150327483684e+00, -8.9021180214204398e-01, -7.2827065309683536e-01, -5.6638022146482336e-01, -4.0452918916600705e-01, -2.4270627382517243e-01, -8.0900218503372048e-02, 8.0900218503372048e-02, 2.4270627382517243e-01, 4.0452918916600705e-01, 5.6638022146482336e-01, 7.2827065309683536e-01, 8.9021180214204398e-01, 1.0522150327483684e+00, 1.2142917656172734e+00, 1.3764534886404416e+00, 1.5387117677168360e+00, 1.7010782577804868e+00, 1.8635647140704730e+00, 2.0261830036759103e+00, 2.1889451173902774e+00, 2.3518631819111540e+00, 2.5149494724234098e+00, 2.6782164256060947e+00, 2.8416766531057553e+00, 3.0053429555216815e+00, 3.1692283369516736e+00, 3.3333460201503651e+00, 3.4977094623559837e+00, 3.6623323718456740e+00, 3.8272287252842805e+00, 3.9924127859367369e+00, 4.1578991228200994e+00, 4.3237026308777766e+00, 4.4898385522658026e+00, 4.6563224988490806e+00, 4.8231704760145977e+00, 4.9903989079186992e+00, 5.1580246642968088e+00, 5.3260650889766197e+00, 5.4945380302499895e+00, 5.6634618732746507e+00, 5.8328555746948121e+00, 6.0027386996898384e+00, 6.1731314616830320e+00, 6.3440547649682282e+00, 6.5155302505411381e+00, 6.6875803454554488e+00, 6.8602283160613764e+00, 7.0334983255273515e+00, 7.2074154960945611e+00, 7.3820059765703627e+00, 7.5572970156311445e+00, 7.7333170415796193e+00, 7.9100957492873887e+00, 8.0876641951531028e+00, 8.2660549010220361e+00, 8.4453019681474064e+00, 8.6254412024311282e+00, 8.8065102523660030e+00, 8.9885487613184782e+00, 9.1715985360473766e+00, 9.3557037336580802e+00, 9.5409110695534167e+00, 9.7272700493753241e+00, 9.9148332284509078e+00, 1.0103656502883585e+01, 1.0293799437190248e+01, 1.0485325634312177e+01, 1.0678303154963148e+01, 1.0872804994678496e+01, 1.1068909628665612e+01, 1.1266701636724759e+01, 1.1466272423235269e+01, 1.1667721050654935e+01, 1.1871155209388238e+01, 1.2076692352553557e+01, 1.2284461031551617e+01, 1.2494602478007950e+01, 1.2707272490482195e+01, 1.2922643701525621e+01, 1.3140908323999378e+01, 1.3362281507661821e+01, 1.3587005481836711e+01, 1.3815354723529373e+01, 1.4047642482122557e+01, 1.4284229126904924e+01, 1.4525532987045759e+01, 1.4772044667297957e+01, 1.5024346320130698e+01, 1.5283138169159214e+01, 1.5549275960782586e+01, 1.5823825468638194e+01, 1.6108144733313441e+01, 1.6404013733432148e+01, 1.6713850376034177e+01, 1.7041096543327139e+01, 1.7390976307430105e+01, 1.7772197980856198e+01, 1.8201656675685278e+01, 1.8723561382058008e+01}, {-1.8775615458013544e+01, -1.8254189423434781e+01, -1.7825132627760091e+01, -1.7444273962020645e+01, -1.7094732674611997e+01, -1.6767807805810907e+01, -1.6458279669864240e+01, -1.6162709261170946e+01, -1.5878680685959477e+01, -1.5604415443478599e+01, -1.5338556618472303e+01, -1.5080039319512867e+01, -1.4828008508467775e+01, -1.4581764541755678e+01, -1.4340725750026818e+01, -1.4104401936851414e+01, -1.3872375122615423e+01, -1.3644285240693469e+01, -1.3419819306444866e+01, -1.3198703076577427e+01, -1.2980694529827234e+01, -1.2765578703092004e+01, -1.2553163552163017e+01, -1.2343276597888334e+01, -1.2135762182101830e+01, -1.1930479202418702e+01, -1.1727299227066995e+01, -1.1526104914236369e+01, -1.1326788677599657e+01, -1.1129251552471963e+01, -1.0933402226734774e+01, -1.0739156208018326e+01, -1.0546435104305445e+01, -1.0355165999524157e+01, -1.0165280909146327e+01, -9.9767163035334772e+00, -9.7894126889375794e+00, -9.6033142377998999e+00, -9.4183684613901413e+00, -9.2345259189629125e+00, -9.0517399585345863e+00, -8.8699664851432551e+00, -8.6891637530810133e+00, -8.5092921791069820e+00, -8.3303141740818543e+00, -8.1521939908263850e+00, -7.9748975863098721e+00, -7.7983924965309503e+00, -7.6226477226697984e+00, -7.4476336272751640e+00, -7.2733218394067363e+00, -7.0996851677878805e+00, -6.9266975211391140e+00, -6.7543338349621100e+00, -6.5825700041298303e+00, -6.4113828207126948e+00, -6.2407499165352709e+00, -6.0706497100141474e+00, -5.9010613568767107e+00, -5.7319647044035085e+00, -5.5633402488744599e+00, -5.3951690959323528e+00, -5.2274329236061510e+00, -5.0601139477624058e+00, -4.8931948897757946e+00, -4.7266589462300219e+00, -4.5604897604781494e+00, -4.3946713959074097e+00, -4.2291883107676789e+00, -4.0640253344354704e+00, -3.8991676449965649e+00, -3.7346007480405388e+00, -3.5703104565694619e+00, -3.4062828719311762e+00, -3.2425043656948236e+00, -3.0789615623928461e+00, -2.9156413230595541e+00, -2.7525307295016344e+00, -2.5896170692407368e+00, -2.4268878210725524e+00, -2.2643306411906372e+00, -2.1019333498267070e+00, -1.9396839183622288e+00, -1.7775704568689277e+00, -1.6155812020383324e+00, -1.4537045054627018e+00, -1.2919288222316836e+00, -1.1302426998108011e+00, -9.6863476716944097e-01, -8.0709372412735814e-01, -6.4560833088991310e-01, -4.8416739774326256e-01, -3.2275977488157320e-01, -1.6137434233903589e-01, -0.0000000000000000e+00, 1.6137434233903589e-01, 3.2275977488157320e-01, 4.8416739774326256e-01, 6.4560833088991310e-01, 8.0709372412735814e-01, 9.6863476716944097e-01, 1.1302426998108011e+00, 1.2919288222316836e+00, 1.4537045054627018e+00, 1.6155812020383324e+00, 1.7775704568689277e+00, 1.9396839183622288e+00, 2.1019333498267070e+00, 2.2643306411906372e+00, 2.4268878210725524e+00, 2.5896170692407368e+00, 2.7525307295016344e+00, 2.9156413230595541e+00, 3.0789615623928461e+00, 3.2425043656948236e+00, 3.4062828719311762e+00, 3.5703104565694619e+00, 3.7346007480405388e+00, 3.8991676449965649e+00, 4.0640253344354704e+00, 4.2291883107676789e+00, 4.3946713959074097e+00, 4.5604897604781494e+00, 4.7266589462300219e+00, 4.8931948897757946e+00, 5.0601139477624058e+00, 5.2274329236061510e+00, 5.3951690959323528e+00, 5.5633402488744599e+00, 5.7319647044035085e+00, 5.9010613568767107e+00, 6.0706497100141474e+00, 6.2407499165352709e+00, 6.4113828207126948e+00, 6.5825700041298303e+00, 6.7543338349621100e+00, 6.9266975211391140e+00, 7.0996851677878805e+00, 7.2733218394067363e+00, 7.4476336272751640e+00, 7.6226477226697984e+00, 7.7983924965309503e+00, 7.9748975863098721e+00, 8.1521939908263850e+00, 8.3303141740818543e+00, 8.5092921791069820e+00, 8.6891637530810133e+00, 8.8699664851432551e+00, 9.0517399585345863e+00, 9.2345259189629125e+00, 9.4183684613901413e+00, 9.6033142377998999e+00, 9.7894126889375794e+00, 9.9767163035334772e+00, 1.0165280909146327e+01, 1.0355165999524157e+01, 1.0546435104305445e+01, 1.0739156208018326e+01, 1.0933402226734774e+01, 1.1129251552471963e+01, 1.1326788677599657e+01, 1.1526104914236369e+01, 1.1727299227066995e+01, 1.1930479202418702e+01, 1.2135762182101830e+01, 1.2343276597888334e+01, 1.2553163552163017e+01, 1.2765578703092004e+01, 1.2980694529827234e+01, 1.3198703076577427e+01, 1.3419819306444866e+01, 1.3644285240693469e+01, 1.3872375122615423e+01, 1.4104401936851414e+01, 1.4340725750026818e+01, 1.4581764541755678e+01, 1.4828008508467775e+01, 1.5080039319512867e+01, 1.5338556618472303e+01, 1.5604415443478599e+01, 1.5878680685959477e+01, 1.6162709261170946e+01, 1.6458279669864240e+01, 1.6767807805810907e+01, 1.7094732674611997e+01, 1.7444273962020645e+01, 1.7825132627760091e+01, 1.8254189423434781e+01, 1.8775615458013544e+01}, {-1.8827530159196098e+01, -1.8306579773944520e+01, -1.7877922302817918e+01, -1.7497424290078804e+01, -1.7148219258607661e+01, -1.6821613557585714e+01, -1.6512391861491736e+01, -1.6217118024196811e+01, -1.5933378153189908e+01, -1.5659395216751500e+01, -1.5393813418192966e+01, -1.5135568742958350e+01, -1.4883806856859362e+01, -1.4637828692771006e+01, -1.4397053061445078e+01, -1.4160990172186152e+01, -1.3929222392681286e+01, -1.3701389956978932e+01, -1.3477180143402940e+01, -1.3256318940768097e+01, -1.3038564534403923e+01, -1.2823702146512529e+01, -1.2611539900280661e+01, -1.2401905468777167e+01, -1.2194643333116042e+01, -1.1989612519093924e+01, -1.1786684713553210e+01, -1.1585742685014308e+01, -1.1386678950280542e+01, -1.1189394641517911e+01, -1.0993798537966583e+01, -1.0799806233800744e+01, -1.0607339419318674e+01, -1.0416325257045436e+01, -1.0226695837777637e+01, -1.0038387704321417e+01, -9.8513414328396713e+00, -9.6655012634583866e+00, -9.4808147731799934e+00, -9.2972325852854905e+00, -9.1147081103323924e+00, -8.9331973146145547e+00, -8.7526585125759730e+00, -8.5730521801893929e+00, -8.3943407867426210e+00, -8.2164886428367048e+00, -8.0394617627036364e+00, -7.8632277392072103e+00, -7.6877556301072998e+00, -7.5130158543520213e+00, -7.3389800973191823e+00, -7.1656212240628339e+00, -6.9929131997360230e+00, -6.8208310164601347e+00, -6.6493506259970188e+00, -6.4784488776542828e+00, -6.3081034609187254e+00, -6.1382928523689460e+00, -5.9689962664672880e+00, -5.8001936098740767e+00, -5.6318654389648133e+00, -5.4639929202639941e+00, -5.2965577935384172e+00, -5.1295423373184992e+00, -4.9629293366389069e+00, -4.7967020528099553e+00, -4.6308441950490966e+00, -4.4653398938177720e+00, -4.3001736757230296e+00, -4.1353304398559789e+00, -3.9707954354504480e+00, -3.8065542407552790e+00, -3.6425927430227989e+00, -3.4788971195240692e+00, -3.3154538195088263e+00, -3.1522495470345691e+00, -2.9892712445951148e+00, -2.8265060774842699e+00, -2.6639414188349808e+00, -2.5015648352786735e+00, -2.3393640731732996e+00, -2.1773270453521110e+00, -2.0154418183483078e+00, -1.8536966000534938e+00, -1.6920797277704067e+00, -1.5305796566226446e+00, -1.3691849482861076e+00, -1.2078842600086817e+00, -1.0466663338862598e+00, -8.8551998636459661e-01, -7.2443409793770541e-01, -5.6339760301455488e-01, -4.0239947992671032e-01, -2.4142874105030510e-01, -8.0474423016328678e-02, 8.0474423016328678e-02, 2.4142874105030510e-01, 4.0239947992671032e-01, 5.6339760301455488e-01, 7.2443409793770541e-01, 8.8551998636459661e-01, 1.0466663338862598e+00, 1.2078842600086817e+00, 1.3691849482861076e+00, 1.5305796566226446e+00, 1.6920797277704067e+00, 1.8536966000534938e+00, 2.0154418183483078e+00, 2.1773270453521110e+00, 2.3393640731732996e+00, 2.5015648352786735e+00, 2.6639414188349808e+00, 2.8265060774842699e+00, 2.9892712445951148e+00, 3.1522495470345691e+00, 3.3154538195088263e+00, 3.4788971195240692e+00, 3.6425927430227989e+00, 3.8065542407552790e+00, 3.9707954354504480e+00, 4.1353304398559789e+00, 4.3001736757230296e+00, 4.4653398938177720e+00, 4.6308441950490966e+00, 4.7967020528099553e+00, 4.9629293366389069e+00, 5.1295423373184992e+00, 5.2965577935384172e+00, 5.4639929202639941e+00, 5.6318654389648133e+00, 5.8001936098740767e+00, 5.9689962664672880e+00, 6.1382928523689460e+00, 6.3081034609187254e+00, 6.4784488776542828e+00, 6.6493506259970188e+00, 6.8208310164601347e+00, 6.9929131997360230e+00, 7.1656212240628339e+00, 7.3389800973191823e+00, 7.5130158543520213e+00, 7.6877556301072998e+00, 7.8632277392072103e+00, 8.0394617627036364e+00, 8.2164886428367048e+00, 8.3943407867426210e+00, 8.5730521801893929e+00, 8.7526585125759730e+00, 8.9331973146145547e+00, 9.1147081103323924e+00, 9.2972325852854905e+00, 9.4808147731799934e+00, 9.6655012634583866e+00, 9.8513414328396713e+00, 1.0038387704321417e+01, 1.0226695837777637e+01, 1.0416325257045436e+01, 1.0607339419318674e+01, 1.0799806233800744e+01, 1.0993798537966583e+01, 1.1189394641517911e+01, 1.1386678950280542e+01, 1.1585742685014308e+01, 1.1786684713553210e+01, 1.1989612519093924e+01, 1.2194643333116042e+01, 1.2401905468777167e+01, 1.2611539900280661e+01, 1.2823702146512529e+01, 1.3038564534403923e+01, 1.3256318940768097e+01, 1.3477180143402940e+01, 1.3701389956978932e+01, 1.3929222392681286e+01, 1.4160990172186152e+01, 1.4397053061445078e+01, 1.4637828692771006e+01, 1.4883806856859362e+01, 1.5135568742958350e+01, 1.5393813418192966e+01, 1.5659395216751500e+01, 1.5933378153189908e+01, 1.6217118024196811e+01, 1.6512391861491736e+01, 1.6821613557585714e+01, 1.7148219258607661e+01, 1.7497424290078804e+01, 1.7877922302817918e+01, 1.8306579773944520e+01, 1.8827530159196098e+01}, {-1.8879306595344101e+01, -1.8358828872057543e+01, -1.7930568181145354e+01, -1.7550428494704086e+01, -1.7201557525065336e+01, -1.6875268886917173e+01, -1.6566351589127169e+01, -1.6271372328095570e+01, -1.5987919200699100e+01, -1.5714216635509363e+01, -1.5448909947718773e+01, -1.5190935994367434e+01, -1.4939441140940190e+01, -1.4693726893234164e+01, -1.4453212539122219e+01, -1.4217408691087410e+01, -1.3985898061893202e+01, -1.3758321184299211e+01, -1.3534365597840969e+01, -1.3313757521857125e+01, -1.3096255346825995e+01, -1.2881644478923162e+01, -1.2669733207493820e+01, -1.2460349356668459e+01, -1.2253337545746717e+01, -1.2048556927665979e+01, -1.1845879306886999e+01, -1.1645187561301928e+01, -1.1446374309916036e+01, -1.1249340780842516e+01, -1.1053995843796514e+01, -1.0860255178628208e+01, -1.0668040557095399e+01, -1.0477279219472964e+01, -1.0287903331040779e+01, -1.0099849506211216e+01, -9.9130583902203586e+00, -9.7274742900396252e+00, -9.5430448475612568e+00, -9.3597207492442038e+00, -9.1774554673313418e+00, -8.9962050285074913e+00, -8.8159278064930948e+00, -8.6365843355868694e+00, -8.4581371426023590e+00, -8.2805505950043532e+00, -8.1037907633543647e+00, -7.9278252964301190e+00, -7.7526233076005129e+00, -7.5781552712214886e+00, -7.4043929279751541e+00, -7.2313091982087343e+00, -7.0588781024451404e+00, -6.8870746883362148e+00, -6.7158749634153345e+00, -6.5452558330803203e+00, -6.3751950433020319e+00, -6.2056711276101213e+00, -6.0366633579564608e+00, -5.8681516990995659e+00, -5.7001167661909662e+00, -5.5325397852775344e+00, -5.3654025564628540e+00, -5.1986874194964612e+00, -5.0323772215824860e+00, -4.8664552872193818e+00, -4.7009053899003126e+00, -4.5357117255196737e+00, -4.3708588873453733e+00, -4.2063318424291563e+00, -4.0421159093385528e+00, -3.8781967371040955e+00, -3.7145602852845432e+00, -3.5511928050609516e+00, -3.3880808212776983e+00, -3.2252111153551550e+00, -3.0625707090045471e+00, -2.9001468486808863e+00, -2.7379269907145933e+00, -2.5758987870667562e+00, -2.4140500716568205e+00, -2.2523688472150090e+00, -2.0908432726148978e+00, -1.9294616506444018e+00, -1.7682124161759520e+00, -1.6070841246989318e+00, -1.4460654411794531e+00, -1.2851451292143858e+00, -1.1243120404481430e+00, -9.6355510422216051e-01, -8.0286331742823902e-01, -6.4222573453801035e-01, -4.8163145778170013e-01, -3.2106962745015089e-01, -1.6052941229469772e-01, -0.0000000000000000e+00, 1.6052941229469772e-01, 3.2106962745015089e-01, 4.8163145778170013e-01, 6.4222573453801035e-01, 8.0286331742823902e-01, 9.6355510422216051e-01, 1.1243120404481430e+00, 1.2851451292143858e+00, 1.4460654411794531e+00, 1.6070841246989318e+00, 1.7682124161759520e+00, 1.9294616506444018e+00, 2.0908432726148978e+00, 2.2523688472150090e+00, 2.4140500716568205e+00, 2.5758987870667562e+00, 2.7379269907145933e+00, 2.9001468486808863e+00, 3.0625707090045471e+00, 3.2252111153551550e+00, 3.3880808212776983e+00, 3.5511928050609516e+00, 3.7145602852845432e+00, 3.8781967371040955e+00, 4.0421159093385528e+00, 4.2063318424291563e+00, 4.3708588873453733e+00, 4.5357117255196737e+00, 4.7009053899003126e+00, 4.8664552872193818e+00, 5.0323772215824860e+00, 5.1986874194964612e+00, 5.3654025564628540e+00, 5.5325397852775344e+00, 5.7001167661909662e+00, 5.8681516990995659e+00, 6.0366633579564608e+00, 6.2056711276101213e+00, 6.3751950433020319e+00, 6.5452558330803203e+00, 6.7158749634153345e+00, 6.8870746883362148e+00, 7.0588781024451404e+00, 7.2313091982087343e+00, 7.4043929279751541e+00, 7.5781552712214886e+00, 7.7526233076005129e+00, 7.9278252964301190e+00, 8.1037907633543647e+00, 8.2805505950043532e+00, 8.4581371426023590e+00, 8.6365843355868694e+00, 8.8159278064930948e+00, 8.9962050285074913e+00, 9.1774554673313418e+00, 9.3597207492442038e+00, 9.5430448475612568e+00, 9.7274742900396252e+00, 9.9130583902203586e+00, 1.0099849506211216e+01, 1.0287903331040779e+01, 1.0477279219472964e+01, 1.0668040557095399e+01, 1.0860255178628208e+01, 1.1053995843796514e+01, 1.1249340780842516e+01, 1.1446374309916036e+01, 1.1645187561301928e+01, 1.1845879306886999e+01, 1.2048556927665979e+01, 1.2253337545746717e+01, 1.2460349356668459e+01, 1.2669733207493820e+01, 1.2881644478923162e+01, 1.3096255346825995e+01, 1.3313757521857125e+01, 1.3534365597840969e+01, 1.3758321184299211e+01, 1.3985898061893202e+01, 1.4217408691087410e+01, 1.4453212539122219e+01, 1.4693726893234164e+01, 1.4939441140940190e+01, 1.5190935994367434e+01, 1.5448909947718773e+01, 1.5714216635509363e+01, 1.5987919200699100e+01, 1.6271372328095570e+01, 1.6566351589127169e+01, 1.6875268886917173e+01, 1.7201557525065336e+01, 1.7550428494704086e+01, 1.7930568181145354e+01, 1.8358828872057543e+01, 1.8879306595344101e+01}, {-1.8930945861570141e+01, -1.8410937847399730e+01, -1.7983071422125320e+01, -1.7603287762782053e+01, -1.7254748687059873e+01, -1.6928775032235986e+01, -1.6620160116009828e+01, -1.6325473460556140e+01, -1.6042305140399389e+01, -1.5768881035760351e+01, -1.5503847567102451e+01, -1.5246142457847222e+01, -1.4994912768931876e+01, -1.4749460575583919e+01, -1.4509205639853443e+01, -1.4273658974878348e+01, -1.4042403636302666e+01, -1.3815080453660714e+01, -1.3591377225971019e+01, -1.3371020401535507e+01, -1.3153768574557885e+01, -1.2939407333876543e+01, -1.2727745133777605e+01, -1.2518609948312903e+01, -1.2311846533891678e+01, -1.2107314169569506e+01, -1.1904884776447382e+01, -1.1704441340847984e+01, -1.1505876583067728e+01, -1.1309091826281094e+01, -1.1113996029812375e+01, -1.0920504958337819e+01, -1.0728540464237067e+01, -1.0538029864706095e+01, -1.0348905398685391e+01, -1.0161103751374336e+01, -9.9745656362640407e+00, -9.7892354263520396e+00, -9.6050608275979510e+00, -9.4219925888112019e+00, -9.2399842430857984e+00, -9.0589918766548454e+00, -8.8789739216625421e+00, -8.6998909698693474e+00, -8.5217056047373152e+00, -8.3443822497033171e+00, -8.1678870307509044e+00, -7.9921876516470487e+00, -7.8172532804264092e+00, -7.6430544458895735e+00, -7.4695629430384693e+00, -7.2967517465063425e+00, -7.1245949311547765e+00, -6.9530675991094046e+00, -6.7821458125915717e+00, -6.6118065319773942e+00, -6.4420275585800111e+00, -6.2727874817069420e+00, -6.1040656295934008e+00, -5.9358420238552689e+00, -5.7680973371429536e+00, -5.6008128537104387e+00, -5.4339704326429148e+00, -5.2675524735120289e+00, -5.1015418842505529e+00, -4.9359220510583919e+00, -4.7706768101697055e+00, -4.6057904213268381e+00, -4.4412475428209168e+00, -4.2770332079715754e+00, -4.1131328029295950e+00, -3.9495320456963339e+00, -3.7862169662628560e+00, -3.6231738877798154e+00, -3.4603894086764226e+00, -3.2978503856533741e+00, -3.1355439174805326e+00, -2.9734573295354325e+00, -2.8115781590234925e+00, -2.6498941408250944e+00, -2.4883931939185926e+00, -2.3270634083318020e+00, -2.1658930325776748e+00, -2.0048704615326960e+00, -1.8439842247190983e+00, -1.6832229749542722e+00, -1.5225754773327997e+00, -1.3620305985083838e+00, -1.2015772962445594e+00, -1.0412046092045326e+00, -8.8090164695175288e-01, -7.2065758013394154e-01, -5.6046163082425071e-01, -4.0030306299404111e-01, -2.4017117309244904e-01, -8.0055280708449292e-02, 8.0055280708449292e-02, 2.4017117309244904e-01, 4.0030306299404111e-01, 5.6046163082425071e-01, 7.2065758013394154e-01, 8.8090164695175288e-01, 1.0412046092045326e+00, 1.2015772962445594e+00, 1.3620305985083838e+00, 1.5225754773327997e+00, 1.6832229749542722e+00, 1.8439842247190983e+00, 2.0048704615326960e+00, 2.1658930325776748e+00, 2.3270634083318020e+00, 2.4883931939185926e+00, 2.6498941408250944e+00, 2.8115781590234925e+00, 2.9734573295354325e+00, 3.1355439174805326e+00, 3.2978503856533741e+00, 3.4603894086764226e+00, 3.6231738877798154e+00, 3.7862169662628560e+00, 3.9495320456963339e+00, 4.1131328029295950e+00, 4.2770332079715754e+00, 4.4412475428209168e+00, 4.6057904213268381e+00, 4.7706768101697055e+00, 4.9359220510583919e+00, 5.1015418842505529e+00, 5.2675524735120289e+00, 5.4339704326429148e+00, 5.6008128537104387e+00, 5.7680973371429536e+00, 5.9358420238552689e+00, 6.1040656295934008e+00, 6.2727874817069420e+00, 6.4420275585800111e+00, 6.6118065319773942e+00, 6.7821458125915717e+00, 6.9530675991094046e+00, 7.1245949311547765e+00, 7.2967517465063425e+00, 7.4695629430384693e+00, 7.6430544458895735e+00, 7.8172532804264092e+00, 7.9921876516470487e+00, 8.1678870307509044e+00, 8.3443822497033171e+00, 8.5217056047373152e+00, 8.6998909698693474e+00, 8.8789739216625421e+00, 9.0589918766548454e+00, 9.2399842430857984e+00, 9.4219925888112019e+00, 9.6050608275979510e+00, 9.7892354263520396e+00, 9.9745656362640407e+00, 1.0161103751374336e+01, 1.0348905398685391e+01, 1.0538029864706095e+01, 1.0728540464237067e+01, 1.0920504958337819e+01, 1.1113996029812375e+01, 1.1309091826281094e+01, 1.1505876583067728e+01, 1.1704441340847984e+01, 1.1904884776447382e+01, 1.2107314169569506e+01, 1.2311846533891678e+01, 1.2518609948312903e+01, 1.2727745133777605e+01, 1.2939407333876543e+01, 1.3153768574557885e+01, 1.3371020401535507e+01, 1.3591377225971019e+01, 1.3815080453660714e+01, 1.4042403636302666e+01, 1.4273658974878348e+01, 1.4509205639853443e+01, 1.4749460575583919e+01, 1.4994912768931876e+01, 1.5246142457847222e+01, 1.5503847567102451e+01, 1.5768881035760351e+01, 1.6042305140399389e+01, 1.6325473460556140e+01, 1.6620160116009828e+01, 1.6928775032235986e+01, 1.7254748687059873e+01, 1.7603287762782053e+01, 1.7983071422125320e+01, 1.8410937847399730e+01, 1.8930945861570141e+01}, {-1.8982449038629166e+01, -1.8462907814661030e+01, -1.8035433169700678e+01, -1.7656003265287762e+01, -1.7307793941303686e+01, -1.6982133215169227e+01, -1.6673818688140226e+01, -1.6379422691596499e+01, -1.6096537266100814e+01, -1.5823389734978102e+01, -1.5558627617427760e+01, -1.5301189498098173e+01, -1.5050223129207568e+01, -1.4805031151963790e+01, -1.4565033799686276e+01, -1.4329742483675762e+01, -1.4098740600289259e+01, -1.3871669273924994e+01, -1.3648216561379414e+01, -1.3428109138379162e+01, -1.3211105801450707e+01, -1.2996992320804354e+01, -1.2785577314468604e+01, -1.2576688905294764e+01, -1.2370171985743601e+01, -1.2165885959983921e+01, -1.1963702864796298e+01, -1.1763505794009992e+01, -1.1565187568319024e+01, -1.1368649605090505e+01, -1.1173800952409410e+01, -1.0980557458945643e+01, -1.0788841056880692e+01, -1.0598579139520853e+01, -1.0409704018662802e+01, -1.0222152449492267e+01, -1.0035865212956141e+01, -9.8507867472781321e+00, -9.6668648216825712e+00, -9.4840502465221892e+00, -9.3022966149286930e+00, -9.1215600718621754e+00, -8.9417991070598717e+00, -8.7629743689023787e+00, -8.5850484966463263e+00, -8.4079859688330369e+00, -8.2317529659853896e+00, -8.0563172459604981e+00, -7.8816480305419629e+00, -7.7077159020391406e+00, -7.5344927088175595e+00, -7.3619514788185860e+00, -7.1900663402415486e+00, -7.0188124486605776e+00, -6.8481659199339457e+00, -6.6781037683378583e+00, -6.5086038494209282e+00, -6.3396448071316529e+00, -6.1712060248201084e+00, -6.0032675797578730e+00, -5.8358102008577646e+00, -5.6688152293079357e+00, -5.5022645818639999e+00, -5.3361407165684911e+00, -5.1704266006896686e+00, -5.0051056806918259e+00, -4.8401618540670963e+00, -4.6755794428746595e+00, -4.5113431688473895e+00, -4.3474381299386442e+00, -4.1838497781931396e+00, -4.0205638988360004e+00, -3.8575665904830925e+00, -3.6948442463838789e+00, -3.5323835366153280e+00, -3.3701713911519686e+00, -3.2081949837430650e+00, -3.0464417165332232e+00, -2.8848992053675047e+00, -2.7235552657264601e+00, -2.5623978992403580e+00, -2.4014152807354292e+00, -2.2405957457680694e+00, -2.0799277786058252e+00, -1.9194000006165373e+00, -1.7590011590293138e+00, -1.5987201160331019e+00, -1.4385458381804410e+00, -1.2784673860656646e+00, -1.1184739042482656e+00, -9.5855461139344544e-01, -7.9869879060299465e-01, -6.3889577991065161e-01, -4.7913496291691687e-01, -3.1940575953902500e-01, -1.5969761685235179e-01, -0.0000000000000000e+00, 1.5969761685235179e-01, 3.1940575953902500e-01, 4.7913496291691687e-01, 6.3889577991065161e-01, 7.9869879060299465e-01, 9.5855461139344544e-01, 1.1184739042482656e+00, 1.2784673860656646e+00, 1.4385458381804410e+00, 1.5987201160331019e+00, 1.7590011590293138e+00, 1.9194000006165373e+00, 2.0799277786058252e+00, 2.2405957457680694e+00, 2.4014152807354292e+00, 2.5623978992403580e+00, 2.7235552657264601e+00, 2.8848992053675047e+00, 3.0464417165332232e+00, 3.2081949837430650e+00, 3.3701713911519686e+00, 3.5323835366153280e+00, 3.6948442463838789e+00, 3.8575665904830925e+00, 4.0205638988360004e+00, 4.1838497781931396e+00, 4.3474381299386442e+00, 4.5113431688473895e+00, 4.6755794428746595e+00, 4.8401618540670963e+00, 5.0051056806918259e+00, 5.1704266006896686e+00, 5.3361407165684911e+00, 5.5022645818639999e+00, 5.6688152293079357e+00, 5.8358102008577646e+00, 6.0032675797578730e+00, 6.1712060248201084e+00, 6.3396448071316529e+00, 6.5086038494209282e+00, 6.6781037683378583e+00, 6.8481659199339457e+00, 7.0188124486605776e+00, 7.1900663402415486e+00, 7.3619514788185860e+00, 7.5344927088175595e+00, 7.7077159020391406e+00, 7.8816480305419629e+00, 8.0563172459604981e+00, 8.2317529659853896e+00, 8.4079859688330369e+00, 8.5850484966463263e+00, 8.7629743689023787e+00, 8.9417991070598717e+00, 9.1215600718621754e+00, 9.3022966149286930e+00, 9.4840502465221892e+00, 9.6668648216825712e+00, 9.8507867472781321e+00, 1.0035865212956141e+01, 1.0222152449492267e+01, 1.0409704018662802e+01, 1.0598579139520853e+01, 1.0788841056880692e+01, 1.0980557458945643e+01, 1.1173800952409410e+01, 1.1368649605090505e+01, 1.1565187568319024e+01, 1.1763505794009992e+01, 1.1963702864796298e+01, 1.2165885959983921e+01, 1.2370171985743601e+01, 1.2576688905294764e+01, 1.2785577314468604e+01, 1.2996992320804354e+01, 1.3211105801450707e+01, 1.3428109138379162e+01, 1.3648216561379414e+01, 1.3871669273924994e+01, 1.4098740600289259e+01, 1.4329742483675762e+01, 1.4565033799686276e+01, 1.4805031151963790e+01, 1.5050223129207568e+01, 1.5301189498098173e+01, 1.5558627617427760e+01, 1.5823389734978102e+01, 1.6096537266100814e+01, 1.6379422691596499e+01, 1.6673818688140226e+01, 1.6982133215169227e+01, 1.7307793941303686e+01, 1.7656003265287762e+01, 1.8035433169700678e+01, 1.8462907814661030e+01, 1.8982449038629166e+01}, {-1.9033817193180372e+01, -1.8514739873870020e+01, -1.8087654552659949e+01, -1.7708576157582009e+01, -1.7360694468453165e+01, -1.7035344640856714e+01, -1.6727328534606457e+01, -1.6433221273899989e+01, -1.6150616853857390e+01, -1.5877744032458063e+01, -1.5613251421176075e+01, -1.5356078460791041e+01, -1.5105373590679383e+01, -1.4860440014620181e+01, -1.4620698434329638e+01, -1.4385660656810286e+01, -1.4154910416992225e+01, -1.3928089132251925e+01, -1.3704885115481808e+01, -1.3485025268316207e+01, -1.3268268588222005e+01, -1.3054401025509831e+01, -1.2843231360770561e+01, -1.2634587864551046e+01, -1.2428315564322974e+01, -1.2224273988380631e+01, -1.2022335288240422e+01, -1.1822382664331087e+01, -1.1624309036867450e+01, -1.1428015916557383e+01, -1.1233412439414929e+01, -1.1040414537288214e+01, -1.0848944221357737e+01, -1.0658928960246737e+01, -1.0470301137821307e+01, -1.0282997578470843e+01, -1.0096959129817110e+01, -9.9121302945287511e+00, -9.7284589043113154e+00, -9.5458958302732722e+00, -9.3643947247907189e+00, -9.1839117907500878e+00, -9.0044055746721732e+00, -8.8258367807379408e+00, -8.6481681031671602e+00, -8.4713640747611425e+00, -8.2953909297232951e+00, -8.1202164791264426e+00, -7.9458099976117715e+00, -7.7721421200878789e+00, -7.5991847473548857e+00, -7.4269109597125382e+00, -7.2552949377261493e+00, -7.0843118894232422e+00, -6.9139379832792587e+00, -6.7441502864247154e+00, -6.5749267075705307e+00, -6.4062459442041968e+00, -6.2380874336583796e+00, -6.0704313076963157e+00, -5.9032583502958440e+00, -5.7365499583469575e+00, -5.5702881050067488e+00, -5.4044553054813402e+00, -5.2390345850270315e+00, -5.0740094489830243e+00, -4.9093638546659628e+00, -4.7450821849723575e+00, -4.5811492235491675e+00, -4.4175501314054006e+00, -4.2542704248488947e+00, -4.0912959546425300e+00, -3.9286128862831946e+00, -3.7662076813149068e+00, -3.6040670795948389e+00, -3.4421780824374997e+00, -3.2805279365682800e+00, -3.1191041188228450e+00, -2.9578943215336770e+00, -2.7968864385493881e+00, -2.6360685518363063e+00, -2.4754289186153811e+00, -2.3149559589906059e+00, -2.1546382440280341e+00, -1.9944644842470249e+00, -1.8344235184876900e+00, -1.6745043031205911e+00, -1.5146959015666042e+00, -1.3549874740965486e+00, -1.1953682678816466e+00, -1.0358276072672234e+00, -8.7635488424319652e-01, -7.1693954908593016e-01, -5.5757110114689967e-01, -3.9823907976435802e-01, -2.3893305527481104e-01, -7.9642620101614783e-02, 7.9642620101614783e-02, 2.3893305527481104e-01, 3.9823907976435802e-01, 5.5757110114689967e-01, 7.1693954908593016e-01, 8.7635488424319652e-01, 1.0358276072672234e+00, 1.1953682678816466e+00, 1.3549874740965486e+00, 1.5146959015666042e+00, 1.6745043031205911e+00, 1.8344235184876900e+00, 1.9944644842470249e+00, 2.1546382440280341e+00, 2.3149559589906059e+00, 2.4754289186153811e+00, 2.6360685518363063e+00, 2.7968864385493881e+00, 2.9578943215336770e+00, 3.1191041188228450e+00, 3.2805279365682800e+00, 3.4421780824374997e+00, 3.6040670795948389e+00, 3.7662076813149068e+00, 3.9286128862831946e+00, 4.0912959546425300e+00, 4.2542704248488947e+00, 4.4175501314054006e+00, 4.5811492235491675e+00, 4.7450821849723575e+00, 4.9093638546659628e+00, 5.0740094489830243e+00, 5.2390345850270315e+00, 5.4044553054813402e+00, 5.5702881050067488e+00, 5.7365499583469575e+00, 5.9032583502958440e+00, 6.0704313076963157e+00, 6.2380874336583796e+00, 6.4062459442041968e+00, 6.5749267075705307e+00, 6.7441502864247154e+00, 6.9139379832792587e+00, 7.0843118894232422e+00, 7.2552949377261493e+00, 7.4269109597125382e+00, 7.5991847473548857e+00, 7.7721421200878789e+00, 7.9458099976117715e+00, 8.1202164791264426e+00, 8.2953909297232951e+00, 8.4713640747611425e+00, 8.6481681031671602e+00, 8.8258367807379408e+00, 9.0044055746721732e+00, 9.1839117907500878e+00, 9.3643947247907189e+00, 9.5458958302732722e+00, 9.7284589043113154e+00, 9.9121302945287511e+00, 1.0096959129817110e+01, 1.0282997578470843e+01, 1.0470301137821307e+01, 1.0658928960246737e+01, 1.0848944221357737e+01, 1.1040414537288214e+01, 1.1233412439414929e+01, 1.1428015916557383e+01, 1.1624309036867450e+01, 1.1822382664331087e+01, 1.2022335288240422e+01, 1.2224273988380631e+01, 1.2428315564322974e+01, 1.2634587864551046e+01, 1.2843231360770561e+01, 1.3054401025509831e+01, 1.3268268588222005e+01, 1.3485025268316207e+01, 1.3704885115481808e+01, 1.3928089132251925e+01, 1.4154910416992225e+01, 1.4385660656810286e+01, 1.4620698434329638e+01, 1.4860440014620181e+01, 1.5105373590679383e+01, 1.5356078460791041e+01, 1.5613251421176075e+01, 1.5877744032458063e+01, 1.6150616853857390e+01, 1.6433221273899989e+01, 1.6727328534606457e+01, 1.7035344640856714e+01, 1.7360694468453165e+01, 1.7708576157582009e+01, 1.8087654552659949e+01, 1.8514739873870020e+01, 1.9033817193180372e+01}, {-1.9085051378043033e+01, -1.8566435110662020e+01, -1.8139736684916269e+01, -1.7761007579700482e+01, -1.7413451433407719e+01, -1.7088410498259837e+01, -1.6780690867902603e+01, -1.6486870443143417e+01, -1.6204545162304957e+01, -1.5931945209665145e+01, -1.5667720282583909e+01, -1.5410810672934431e+01, -1.5160365503176191e+01, -1.4915688536290588e+01, -1.4676200939552615e+01, -1.4441414913235960e+01, -1.4210914528731067e+01, -1.3984341494531598e+01, -1.3761384377966619e+01, -1.3541770305082187e+01, -1.3325258472923085e+01, -1.3111635010647520e+01, -1.2900708860246835e+01, -1.2692308438876983e+01, -1.2486278907997042e+01, -1.2282479919055724e+01, -1.2080783737378024e+01, -1.1881073669101410e+01, -1.1683242733101009e+01, -1.1487192532589896e+01, -1.1292832290695909e+01, -1.1100078021646450e+01, -1.0908851814834854e+01, -1.0719081213424776e+01, -1.0530698672582092e+01, -1.0343641085134585e+01, -1.0157849364615741e+01, -9.9732680773760247e+00, -9.7898451168372347e+00, -9.6075314140949892e+00, -9.4262806799959176e+00, -9.2460491745721143e+00, -9.0667955003389675e+00, -8.8884804164791387e+00, -8.7110666713658151e+00, -8.5345188512382073e+00, -8.3588032431445285e+00, -8.1838877105226704e+00, -8.0097415800046274e+00, -7.8363355382140769e+00, -7.6636415374829738e+00, -7.4916327095468409e+00, -7.3202832863932787e+00, -7.1495685275371788e+00, -6.9794646530814948e+00, -6.8099487819964919e+00, -6.6409988751145752e+00, -6.4725936823937991e+00, -6.3047126940519806e+00, -6.1373360952161162e+00, -5.9704447237692317e+00, -5.8040200311098342e+00, -5.6380440455680922e+00, -5.4724993382485847e+00, -5.3073689910920496e+00, -5.1426365669687621e+00, -4.9782860816339154e+00, -4.8143019773913309e+00, -4.6506690983259311e+00, -4.4873726669780289e+00, -4.3243982623437809e+00, -4.1617317990962412e+00, -3.9993595079305000e+00, -3.8372679169445236e+00, -3.6754438339745814e+00, -3.5138743298107440e+00, -3.3525467222238068e+00, -3.1914485607403469e+00, -3.0305676121073946e+00, -2.8698918463925485e+00, -2.7094094236692574e+00, -2.5491086812405244e+00, -2.3889781213574715e+00, -2.2290063993920741e+00, -2.0691823124259607e+00, -1.9094947882195137e+00, -1.7499328745276050e+00, -1.5904857287301759e+00, -1.4311426077475764e+00, -1.2718928582120677e+00, -1.1127259068682478e+00, -9.5363125117633152e-01, -7.9459845009326358e-01, -6.3561711500753826e-01, -4.7667690080438158e-01, -3.1776749703859319e-01, -1.5887861919288843e-01, -0.0000000000000000e+00, 1.5887861919288843e-01, 3.1776749703859319e-01, 4.7667690080438158e-01, 6.3561711500753826e-01, 7.9459845009326358e-01, 9.5363125117633152e-01, 1.1127259068682478e+00, 1.2718928582120677e+00, 1.4311426077475764e+00, 1.5904857287301759e+00, 1.7499328745276050e+00, 1.9094947882195137e+00, 2.0691823124259607e+00, 2.2290063993920741e+00, 2.3889781213574715e+00, 2.5491086812405244e+00, 2.7094094236692574e+00, 2.8698918463925485e+00, 3.0305676121073946e+00, 3.1914485607403469e+00, 3.3525467222238068e+00, 3.5138743298107440e+00, 3.6754438339745814e+00, 3.8372679169445236e+00, 3.9993595079305000e+00, 4.1617317990962412e+00, 4.3243982623437809e+00, 4.4873726669780289e+00, 4.6506690983259311e+00, 4.8143019773913309e+00, 4.9782860816339154e+00, 5.1426365669687621e+00, 5.3073689910920496e+00, 5.4724993382485847e+00, 5.6380440455680922e+00, 5.8040200311098342e+00, 5.9704447237692317e+00, 6.1373360952161162e+00, 6.3047126940519806e+00, 6.4725936823937991e+00, 6.6409988751145752e+00, 6.8099487819964919e+00, 6.9794646530814948e+00, 7.1495685275371788e+00, 7.3202832863932787e+00, 7.4916327095468409e+00, 7.6636415374829738e+00, 7.8363355382140769e+00, 8.0097415800046274e+00, 8.1838877105226704e+00, 8.3588032431445285e+00, 8.5345188512382073e+00, 8.7110666713658151e+00, 8.8884804164791387e+00, 9.0667955003389675e+00, 9.2460491745721143e+00, 9.4262806799959176e+00, 9.6075314140949892e+00, 9.7898451168372347e+00, 9.9732680773760247e+00, 1.0157849364615741e+01, 1.0343641085134585e+01, 1.0530698672582092e+01, 1.0719081213424776e+01, 1.0908851814834854e+01, 1.1100078021646450e+01, 1.1292832290695909e+01, 1.1487192532589896e+01, 1.1683242733101009e+01, 1.1881073669101410e+01, 1.2080783737378024e+01, 1.2282479919055724e+01, 1.2486278907997042e+01, 1.2692308438876983e+01, 1.2900708860246835e+01, 1.3111635010647520e+01, 1.3325258472923085e+01, 1.3541770305082187e+01, 1.3761384377966619e+01, 1.3984341494531598e+01, 1.4210914528731067e+01, 1.4441414913235960e+01, 1.4676200939552615e+01, 1.4915688536290588e+01, 1.5160365503176191e+01, 1.5410810672934431e+01, 1.5667720282583909e+01, 1.5931945209665145e+01, 1.6204545162304957e+01, 1.6486870443143417e+01, 1.6780690867902603e+01, 1.7088410498259837e+01, 1.7413451433407719e+01, 1.7761007579700482e+01, 1.8139736684916269e+01, 1.8566435110662020e+01, 1.9085051378043033e+01}, {-1.9136152632446343e+01, -1.8617994596540964e+01, -1.8191680665779813e+01, -1.7813298656636132e+01, -1.7466065985601755e+01, -1.7141331960462935e+01, -1.6833906884239585e+01, -1.6540371418317267e+01, -1.6258323432990789e+01, -1.5985994530572864e+01, -1.5722035487991715e+01, -1.5465387443233377e+01, -1.5215200197812091e+01, -1.4970778070582133e+01, -1.4731542691573273e+01, -1.4497006651929539e+01, -1.4266754357415572e+01, -1.4040427805805265e+01, -1.3817715817227148e+01, -1.3598345740663659e+01, -1.3382076971394328e+01, -1.3168695816190608e+01, -1.2958011377300066e+01, -1.2749852217418379e+01, -1.2544063630985093e+01, -1.2340505391648597e+01, -1.2139049877631299e+01, -1.1939580499904540e+01, -1.1741990375159112e+01, -1.1546181198293549e+01, -1.1352062278750141e+01, -1.1159549712352600e+01, -1.0968565665937081e+01, -1.0779037756447492e+01, -1.0590898509596441e+01, -1.0404084885901707e+01, -1.0218537864062538e+01, -1.0034202073365652e+01, -9.8510254682020655e+00, -9.6689590389043136e+00, -9.4879565540345112e+00, -9.3079743300090456e+00, -9.1289710245687488e+00, -8.9509074511196953e+00, -8.7737464113997543e+00, -8.5974525442855416e+00, -8.4219921888566009e+00, -8.2473332600882276e+00, -8.0734451357601422e+00, -7.9002985533514174e+00, -7.7278655158483680e+00, -7.5561192055258362e+00, -7.3850339048770719e+00, -7.2145849239662976e+00, -7.0447485335633226e+00, -6.8755019034936238e+00, -6.7068230457014044e+00, -6.5386907615791259e+00, -6.3710845931658042e+00, -6.2039847778590458e+00, -6.0373722063233055e+00, -5.8712283833097523e+00, -5.7055353911321696e+00, -5.5402758555689235e+00, -5.3754329139836932e+00, -5.2109901854777609e+00, -5.0469317429044782e+00, -4.8832420865923929e+00, -4.7199061196376721e+00, -4.5569091246390609e+00, -4.3942367417598831e+00, -4.2318749480117184e+00, -4.0698100376633946e+00, -3.9080286036870948e+00, -3.7465175201606447e+00, -3.5852639255516232e+00, -3.4242552068148551e+00, -3.2634789842401504e+00, -3.1029230969919848e+00, -2.9425755892871246e+00, -2.7824246971601365e+00, -2.6224588357702330e+00, -2.4626665872061215e+00, -2.3030366887483824e+00, -2.1435580215515251e+00, -1.9842195997101939e+00, -1.8250105596761317e+00, -1.6659201499943919e+00, -1.5069377213289974e+00, -1.3480527167497827e+00, -1.1892546622534923e+00, -1.0305331574934382e+00, -8.7187786669305845e-01, -7.1327850971966389e-01, -5.5472485329544763e-01, -3.9620670232352440e-01, -2.3771389130732343e-01, -7.9236275842124657e-02, 7.9236275842124657e-02, 2.3771389130732343e-01, 3.9620670232352440e-01, 5.5472485329544763e-01, 7.1327850971966389e-01, 8.7187786669305845e-01, 1.0305331574934382e+00, 1.1892546622534923e+00, 1.3480527167497827e+00, 1.5069377213289974e+00, 1.6659201499943919e+00, 1.8250105596761317e+00, 1.9842195997101939e+00, 2.1435580215515251e+00, 2.3030366887483824e+00, 2.4626665872061215e+00, 2.6224588357702330e+00, 2.7824246971601365e+00, 2.9425755892871246e+00, 3.1029230969919848e+00, 3.2634789842401504e+00, 3.4242552068148551e+00, 3.5852639255516232e+00, 3.7465175201606447e+00, 3.9080286036870948e+00, 4.0698100376633946e+00, 4.2318749480117184e+00, 4.3942367417598831e+00, 4.5569091246390609e+00, 4.7199061196376721e+00, 4.8832420865923929e+00, 5.0469317429044782e+00, 5.2109901854777609e+00, 5.3754329139836932e+00, 5.5402758555689235e+00, 5.7055353911321696e+00, 5.8712283833097523e+00, 6.0373722063233055e+00, 6.2039847778590458e+00, 6.3710845931658042e+00, 6.5386907615791259e+00, 6.7068230457014044e+00, 6.8755019034936238e+00, 7.0447485335633226e+00, 7.2145849239662976e+00, 7.3850339048770719e+00, 7.5561192055258362e+00, 7.7278655158483680e+00, 7.9002985533514174e+00, 8.0734451357601422e+00, 8.2473332600882276e+00, 8.4219921888566009e+00, 8.5974525442855416e+00, 8.7737464113997543e+00, 8.9509074511196953e+00, 9.1289710245687488e+00, 9.3079743300090456e+00, 9.4879565540345112e+00, 9.6689590389043136e+00, 9.8510254682020655e+00, 1.0034202073365652e+01, 1.0218537864062538e+01, 1.0404084885901707e+01, 1.0590898509596441e+01, 1.0779037756447492e+01, 1.0968565665937081e+01, 1.1159549712352600e+01, 1.1352062278750141e+01, 1.1546181198293549e+01, 1.1741990375159112e+01, 1.1939580499904540e+01, 1.2139049877631299e+01, 1.2340505391648597e+01, 1.2544063630985093e+01, 1.2749852217418379e+01, 1.2958011377300066e+01, 1.3168695816190608e+01, 1.3382076971394328e+01, 1.3598345740663659e+01, 1.3817715817227148e+01, 1.4040427805805265e+01, 1.4266754357415572e+01, 1.4497006651929539e+01, 1.4731542691573273e+01, 1.4970778070582133e+01, 1.5215200197812091e+01, 1.5465387443233377e+01, 1.5722035487991715e+01, 1.5985994530572864e+01, 1.6258323432990789e+01, 1.6540371418317267e+01, 1.6833906884239585e+01, 1.7141331960462935e+01, 1.7466065985601755e+01, 1.7813298656636132e+01, 1.8191680665779813e+01, 1.8617994596540964e+01, 1.9136152632446343e+01}, {-1.9187121982273521e+01, -1.8669419389135154e+01, -1.8243487580223828e+01, -1.7865450498614848e+01, -1.7518539259289700e+01, -1.7194110184967560e+01, -1.6886977763848531e+01, -1.6593725402038196e+01, -1.6311952890695306e+01, -1.6039893241994275e+01, -1.5776198306184138e+01, -1.5519810062439074e+01, -1.5269878987345788e+01, -1.5025709952340740e+01, -1.4786725047437830e+01, -1.4552437252279828e+01, -1.4322431304945502e+01, -1.4096349490675653e+01, -1.3873880880782780e+01, -1.3654753045730484e+01, -1.3438725577708846e+01, -1.3225584959886243e+01, -1.3015140453639436e+01, -1.2807220766151111e+01, -1.2601671323850574e+01, -1.2398352021647000e+01, -1.2197135349764665e+01, -1.1997904823149442e+01, -1.1800553655478529e+01, -1.1604983632531599e+01, -1.1411104149281471e+01, -1.1218831382380758e+01, -1.1028087575354093e+01, -1.0838800418181339e+01, -1.0650902506384885e+01, -1.0464330867440474e+01, -1.0279026544483804e+01, -1.0094934229009290e+01, -9.9120019356474849e+00, -9.7301807132353808e+00, -9.5494243873137332e+00, -9.3696893299405168e+00, -9.1909342533320295e+00, -9.0131200243591802e+00, -8.8362094973560179e+00, -8.6601673630569582e+00, -8.4849600117808954e+00, -8.3105554092350147e+00, -8.1369229835265475e+00, -7.9640335221538869e+00, -7.7918590779046193e+00, -7.6203728827216537e+00, -7.4495492687133176e+00, -7.2793635955820948e+00, -7.1097921838319138e+00, -6.9408122531878398e+00, -6.7724018657261427e+00, -6.6045398732686005e+00, -6.4372058686436739e+00, -6.2703801404598503e+00, -6.1040436310739281e+00, -5.9381778974699042e+00, -5.7727650747931136e+00, -5.6077878423099152e+00, -5.4432293915858283e+00, -5.2790733966951038e+00, -5.1153039862925711e+00, -4.9519057173944132e+00, -4.7888635507286939e+00, -4.6261628275290461e+00, -4.4637892476562113e+00, -4.3017288489422221e+00, -4.1399679876610396e+00, -3.9784933200376109e+00, -3.8172917847145760e+00, -3.6563505861024530e+00, -3.4956571785450063e+00, -3.3351992512368578e+00, -3.1749647138352097e+00, -3.0149416827118620e+00, -2.8551184677956569e+00, -2.6954835599590137e+00, -2.5360256189054007e+00, -2.3767334615175160e+00, -2.2175960506285199e+00, -2.0586024841810624e+00, -1.8997419847409271e+00, -1.7410038893340725e+00, -1.5823776395775344e+00, -1.4238527720762202e+00, -1.2654189090589871e+00, -1.1070657492286282e+00, -9.4878305880147162e-01, -7.9056066271324643e-01, -6.3238843596870120e-01, -4.7425629511315831e-01, -3.1615418980479731e-01, -1.5807209446693934e-01, -0.0000000000000000e+00, 1.5807209446693934e-01, 3.1615418980479731e-01, 4.7425629511315831e-01, 6.3238843596870120e-01, 7.9056066271324643e-01, 9.4878305880147162e-01, 1.1070657492286282e+00, 1.2654189090589871e+00, 1.4238527720762202e+00, 1.5823776395775344e+00, 1.7410038893340725e+00, 1.8997419847409271e+00, 2.0586024841810624e+00, 2.2175960506285199e+00, 2.3767334615175160e+00, 2.5360256189054007e+00, 2.6954835599590137e+00, 2.8551184677956569e+00, 3.0149416827118620e+00, 3.1749647138352097e+00, 3.3351992512368578e+00, 3.4956571785450063e+00, 3.6563505861024530e+00, 3.8172917847145760e+00, 3.9784933200376109e+00, 4.1399679876610396e+00, 4.3017288489422221e+00, 4.4637892476562113e+00, 4.6261628275290461e+00, 4.7888635507286939e+00, 4.9519057173944132e+00, 5.1153039862925711e+00, 5.2790733966951038e+00, 5.4432293915858283e+00, 5.6077878423099152e+00, 5.7727650747931136e+00, 5.9381778974699042e+00, 6.1040436310739281e+00, 6.2703801404598503e+00, 6.4372058686436739e+00, 6.6045398732686005e+00, 6.7724018657261427e+00, 6.9408122531878398e+00, 7.1097921838319138e+00, 7.2793635955820948e+00, 7.4495492687133176e+00, 7.6203728827216537e+00, 7.7918590779046193e+00, 7.9640335221538869e+00, 8.1369229835265475e+00, 8.3105554092350147e+00, 8.4849600117808954e+00, 8.6601673630569582e+00, 8.8362094973560179e+00, 9.0131200243591802e+00, 9.1909342533320295e+00, 9.3696893299405168e+00, 9.5494243873137332e+00, 9.7301807132353808e+00, 9.9120019356474849e+00, 1.0094934229009290e+01, 1.0279026544483804e+01, 1.0464330867440474e+01, 1.0650902506384885e+01, 1.0838800418181339e+01, 1.1028087575354093e+01, 1.1218831382380758e+01, 1.1411104149281471e+01, 1.1604983632531599e+01, 1.1800553655478529e+01, 1.1997904823149442e+01, 1.2197135349764665e+01, 1.2398352021647000e+01, 1.2601671323850574e+01, 1.2807220766151111e+01, 1.3015140453639436e+01, 1.3225584959886243e+01, 1.3438725577708846e+01, 1.3654753045730484e+01, 1.3873880880782780e+01, 1.4096349490675653e+01, 1.4322431304945502e+01, 1.4552437252279828e+01, 1.4786725047437830e+01, 1.5025709952340740e+01, 1.5269878987345788e+01, 1.5519810062439074e+01, 1.5776198306184138e+01, 1.6039893241994275e+01, 1.6311952890695306e+01, 1.6593725402038196e+01, 1.6886977763848531e+01, 1.7194110184967560e+01, 1.7518539259289700e+01, 1.7865450498614848e+01, 1.8243487580223828e+01, 1.8669419389135154e+01, 1.9187121982273521e+01}, {-1.9237960440300323e+01, -1.8720710532447114e+01, -1.8295158499144485e+01, -1.7917464201364730e+01, -1.7570872373824393e+01, -1.7246746313979781e+01, -1.6939904671276931e+01, -1.6646933580854089e+01, -1.6365434743746000e+01, -1.6093642573904912e+01, -1.5830209988722080e+01, -1.5574079803690140e+01, -1.5324403166531194e+01, -1.5080485498011255e+01, -1.4841749345390438e+01, -1.4607708074467340e+01, -1.4377946753600369e+01, -1.4152107953707038e+01, -1.3929880995689542e+01, -1.3710993670057162e+01, -1.3495205764604879e+01, -1.3282303937699215e+01, -1.3072097608735946e+01, -1.2864415628348308e+01, -1.2659103553980440e+01, -1.2456021400878894e+01, -1.2255041770389502e+01, -1.2056048280588383e+01, -1.1858934241324912e+01, -1.1663601528470521e+01, -1.1469959621759649e+01, -1.1277924777921493e+01, -1.1087419316430047e+01, -1.0898370999572231e+01, -1.0710712491958864e+01, -1.0524380887307489e+01, -1.0339317292477098e+01, -1.0155466460457681e+01, -9.9727764654064881e+00, -9.7911984139496884e+00, -9.6106861878874543e+00, -9.4311962141946886e+00, -9.2526872588317186e+00, -9.0751202413947372e+00, -8.8984580680650804e+00, -8.7226654806754844e+00, -8.5477089200129779e+00, -8.3735564017325164e+00, -8.2001774034706933e+00, -8.0275427619319260e+00, -7.8556245788755001e+00, -7.6843961350654411e+00, -7.5138318113597080e+00, -7.3439070162139659e+00, -7.1745981189604136e+00, -7.0058823882959311e+00, -6.8377379354779668e+00, -6.6701436617824124e+00, -6.5030792098264039e+00, -6.3365249184017198e+00, -6.1704617805017721e+00, -6.0048714042581519e+00, -5.8397359765316308e+00, -5.6750382289281065e+00, -5.5107614060326373e+00, -5.3468892356747437e+00, -5.1834059010560054e+00, -5.0202960145867985e+00, -4.8575445932931558e+00, -4.6951370356673570e+00, -4.5330590998470743e+00, -4.3712968830180499e+00, -4.2098368019442765e+00, -4.0486655745377966e+00, -3.8877702023875300e+00, -3.7271379541730876e+00, -3.5667563498954848e+00, -3.4066131458619480e+00, -3.2466963203668557e+00, -3.0869940600152046e+00, -2.9274947466388688e+00, -2.7681869447595400e+00, -2.6090593895553744e+00, -2.4501009752913179e+00, -2.2913007441756847e+00, -2.1326478756079257e+00, -1.9741316757846794e+00, -1.8157415676330977e+00, -1.6574670810421992e+00, -1.4992978433645401e+00, -1.3412235701618946e+00, -1.1832340561698793e+00, -1.0253191664575543e+00, -8.6746882775900824e-01, -7.0967301995478616e-01, -5.5192176768174561e-01, -3.9420513205055796e-01, -2.3651320245058799e-01, -7.8836088422303746e-02, 7.8836088422303746e-02, 2.3651320245058799e-01, 3.9420513205055796e-01, 5.5192176768174561e-01, 7.0967301995478616e-01, 8.6746882775900824e-01, 1.0253191664575543e+00, 1.1832340561698793e+00, 1.3412235701618946e+00, 1.4992978433645401e+00, 1.6574670810421992e+00, 1.8157415676330977e+00, 1.9741316757846794e+00, 2.1326478756079257e+00, 2.2913007441756847e+00, 2.4501009752913179e+00, 2.6090593895553744e+00, 2.7681869447595400e+00, 2.9274947466388688e+00, 3.0869940600152046e+00, 3.2466963203668557e+00, 3.4066131458619480e+00, 3.5667563498954848e+00, 3.7271379541730876e+00, 3.8877702023875300e+00, 4.0486655745377966e+00, 4.2098368019442765e+00, 4.3712968830180499e+00, 4.5330590998470743e+00, 4.6951370356673570e+00, 4.8575445932931558e+00, 5.0202960145867985e+00, 5.1834059010560054e+00, 5.3468892356747437e+00, 5.5107614060326373e+00, 5.6750382289281065e+00, 5.8397359765316308e+00, 6.0048714042581519e+00, 6.1704617805017721e+00, 6.3365249184017198e+00, 6.5030792098264039e+00, 6.6701436617824124e+00, 6.8377379354779668e+00, 7.0058823882959311e+00, 7.1745981189604136e+00, 7.3439070162139659e+00, 7.5138318113597080e+00, 7.6843961350654411e+00, 7.8556245788755001e+00, 8.0275427619319260e+00, 8.2001774034706933e+00, 8.3735564017325164e+00, 8.5477089200129779e+00, 8.7226654806754844e+00, 8.8984580680650804e+00, 9.0751202413947372e+00, 9.2526872588317186e+00, 9.4311962141946886e+00, 9.6106861878874543e+00, 9.7911984139496884e+00, 9.9727764654064881e+00, 1.0155466460457681e+01, 1.0339317292477098e+01, 1.0524380887307489e+01, 1.0710712491958864e+01, 1.0898370999572231e+01, 1.1087419316430047e+01, 1.1277924777921493e+01, 1.1469959621759649e+01, 1.1663601528470521e+01, 1.1858934241324912e+01, 1.2056048280588383e+01, 1.2255041770389502e+01, 1.2456021400878894e+01, 1.2659103553980440e+01, 1.2864415628348308e+01, 1.3072097608735946e+01, 1.3282303937699215e+01, 1.3495205764604879e+01, 1.3710993670057162e+01, 1.3929880995689542e+01, 1.4152107953707038e+01, 1.4377946753600369e+01, 1.4607708074467340e+01, 1.4841749345390438e+01, 1.5080485498011255e+01, 1.5324403166531194e+01, 1.5574079803690140e+01, 1.5830209988722080e+01, 1.6093642573904912e+01, 1.6365434743746000e+01, 1.6646933580854089e+01, 1.6939904671276931e+01, 1.7246746313979781e+01, 1.7570872373824393e+01, 1.7917464201364730e+01, 1.8295158499144485e+01, 1.8720710532447114e+01, 1.9237960440300323e+01}, {-1.9288669006428073e+01, -1.8771869057097732e+01, -1.8346694479614712e+01, -1.7969340846379055e+01, -1.7623066433928877e+01, -1.7299241474690692e+01, -1.6992688755677822e+01, -1.6699997125541856e+01, -1.6418770184323929e+01, -1.6147243739757997e+01, -1.5884071770266710e+01, -1.5628197922845580e+01, -1.5378774012459481e+01, -1.5135106005988732e+01, -1.4896616905233879e+01, -1.4662820459834590e+01, -1.4433302066419493e+01, -1.4207704579815282e+01, -1.3985717568940393e+01, -1.3767069042933601e+01, -1.3551518983907220e+01, -1.3338854224244356e+01, -1.3128884340266051e+01, -1.2921438325035480e+01, -1.2716361866052114e+01, -1.2513515097991551e+01, -1.2312770732455700e+01, -1.2114012489821327e+01, -1.1917133775310306e+01, -1.1722036554111044e+01, -1.1528630389965276e+01, -1.1336831618941112e+01, -1.1146562635737574e+01, -1.0957751274234692e+01, -1.0770330267425512e+01, -1.0584236774568581e+01, -1.0399411965548676e+01, -1.0215800654155213e+01, -1.0033350973375560e+01, -9.8520140869264541e+00, -9.6717439321652883e+00, -9.4924969902767238e+00, -9.3142320802515925e+00, -9.1369101736902376e+00, -8.9604942278913082e+00, -8.7849490350458534e+00, -8.6102410856578757e+00, -8.4363384445666423e+00, -8.2632106381612598e+00, -8.0908285515608398e+00, -7.9191643346894995e+00, -7.7481913163088629e+00, -7.5778839251852919e+00, -7.4082176176676109e+00, -7.2391688110363521e+00, -7.0707148220592551e+00, -6.9028338102518392e+00, -6.7355047253976705e+00, -6.5687072589316280e+00, -6.4024217988321039e+00, -6.2366293877054586e+00, -6.0713116837789416e+00, -5.9064509245471877e+00, -5.7420298928430569e+00, -5.5780318851261201e+00, -5.4144406818022057e+00, -5.2512405194051937e+00, -5.0884160644880927e+00, -4.9259523890845678e+00, -4.7638349476146598e+00, -4.6020495551197111e+00, -4.4405823667216309e+00, -4.2794198582106002e+00, -4.1185488076735286e+00, -3.9579562780827859e+00, -3.7976296007713630e+00, -3.6375563597264895e+00, -3.4777243766391046e+00, -3.3181216966513536e+00, -3.1587365747486800e+00, -2.9995574627469606e+00, -2.8405729968287345e+00, -2.6817719855857511e+00, -2.5231433985279939e+00, -2.3646763550219534e+00, -2.2063601136233109e+00, -2.0481840617713236e+00, -1.8901377058141628e+00, -1.7322106613361827e+00, -1.5743926437596774e+00, -1.4166734591950965e+00, -1.2590429955149371e+00, -1.1014912136276596e+00, -9.4400813892896185e-01, -7.8658385290862076e-01, -6.2920848489186076e-01, -4.7187220389486334e-01, -3.1456521057457892e-01, -1.5727772925344838e-01, -0.0000000000000000e+00, 1.5727772925344838e-01, 3.1456521057457892e-01, 4.7187220389486334e-01, 6.2920848489186076e-01, 7.8658385290862076e-01, 9.4400813892896185e-01, 1.1014912136276596e+00, 1.2590429955149371e+00, 1.4166734591950965e+00, 1.5743926437596774e+00, 1.7322106613361827e+00, 1.8901377058141628e+00, 2.0481840617713236e+00, 2.2063601136233109e+00, 2.3646763550219534e+00, 2.5231433985279939e+00, 2.6817719855857511e+00, 2.8405729968287345e+00, 2.9995574627469606e+00, 3.1587365747486800e+00, 3.3181216966513536e+00, 3.4777243766391046e+00, 3.6375563597264895e+00, 3.7976296007713630e+00, 3.9579562780827859e+00, 4.1185488076735286e+00, 4.2794198582106002e+00, 4.4405823667216309e+00, 4.6020495551197111e+00, 4.7638349476146598e+00, 4.9259523890845678e+00, 5.0884160644880927e+00, 5.2512405194051937e+00, 5.4144406818022057e+00, 5.5780318851261201e+00, 5.7420298928430569e+00, 5.9064509245471877e+00, 6.0713116837789416e+00, 6.2366293877054586e+00, 6.4024217988321039e+00, 6.5687072589316280e+00, 6.7355047253976705e+00, 6.9028338102518392e+00, 7.0707148220592551e+00, 7.2391688110363521e+00, 7.4082176176676109e+00, 7.5778839251852919e+00, 7.7481913163088629e+00, 7.9191643346894995e+00, 8.0908285515608398e+00, 8.2632106381612598e+00, 8.4363384445666423e+00, 8.6102410856578757e+00, 8.7849490350458534e+00, 8.9604942278913082e+00, 9.1369101736902376e+00, 9.3142320802515925e+00, 9.4924969902767238e+00, 9.6717439321652883e+00, 9.8520140869264541e+00, 1.0033350973375560e+01, 1.0215800654155213e+01, 1.0399411965548676e+01, 1.0584236774568581e+01, 1.0770330267425512e+01, 1.0957751274234692e+01, 1.1146562635737574e+01, 1.1336831618941112e+01, 1.1528630389965276e+01, 1.1722036554111044e+01, 1.1917133775310306e+01, 1.2114012489821327e+01, 1.2312770732455700e+01, 1.2513515097991551e+01, 1.2716361866052114e+01, 1.2921438325035480e+01, 1.3128884340266051e+01, 1.3338854224244356e+01, 1.3551518983907220e+01, 1.3767069042933601e+01, 1.3985717568940393e+01, 1.4207704579815282e+01, 1.4433302066419493e+01, 1.4662820459834590e+01, 1.4896616905233879e+01, 1.5135106005988732e+01, 1.5378774012459481e+01, 1.5628197922845580e+01, 1.5884071770266710e+01, 1.6147243739757997e+01, 1.6418770184323929e+01, 1.6699997125541856e+01, 1.6992688755677822e+01, 1.7299241474690692e+01, 1.7623066433928877e+01, 1.7969340846379055e+01, 1.8346694479614712e+01, 1.8771869057097732e+01, 1.9288669006428073e+01}, {-1.9339248667911409e+01, -1.8822895980564734e+01, -1.8398096565132178e+01, -1.8021081501173168e+01, -1.7675122529961925e+01, -1.7351596779550405e+01, -1.7045331151092153e+01, -1.6752917191398179e+01, -1.6471960388762881e+01, -1.6200697936792103e+01, -1.5937784868895722e+01, -1.5682165658809755e+01, -1.5432992784892868e+01, -1.5189572756961194e+01, -1.4951329028681464e+01, -1.4717775731247299e+01, -1.4488498587572698e+01, -1.4263140734648266e+01, -1.4041391987855551e+01, -1.3822980573565543e+01, -1.3607666666938064e+01, -1.3395237273208020e+01, -1.3185502124544024e+01, -1.2978290355434069e+01, -1.2773447782488505e+01, -1.2570834658918320e+01, -1.2370323805730495e+01, -1.2171799044787127e+01, -1.1975153875897130e+01, -1.1780290352805242e+01, -1.1587118122520339e+01, -1.1395553599726039e+01, -1.1205519253636435e+01, -1.1016942989025184e+01, -1.0829757606576079e+01, -1.0643900330402785e+01, -1.0459312392733535e+01, -1.0275938667476471e+01, -1.0093727345768286e+01, -9.9126296477337945e+00, -9.7325995656019266e+00, -9.5535936340768206e+00, -9.3755707244836426e+00, -9.1984918597235552e+00, -9.0223200475008358e+00, -8.8470201296436706e+00, -8.6725586456412369e+00, -8.4989037087736055e+00, -8.3260248934261227e+00, -8.1538931323624819e+00, -7.9824806228866425e+00, -7.8117607409569434e+00, -7.6417079624302628e+00, -7.4722977907127222e+00, -7.3035066901782200e+00, -7.1353120247902524e+00, -6.9676920014260446e+00, -6.8006256174581203e+00, -6.6340926121968646e+00, -6.4680734218403675e+00, -6.3025491376151397e+00, -6.1375014668241503e+00, -5.9729126965475468e+00, -5.8087656597670589e+00, -5.6450437037075716e+00, -5.4817306602094709e+00, -5.3188108179631426e+00, -5.1562688964529020e+00, -4.9940900214715160e+00, -4.8322597020794342e+00, -4.6707638088937005e+00, -4.5095885536020024e+00, -4.3487204696060182e+00, -4.1881463937064671e+00, -4.0278534487497097e+00, -3.8678290271620543e+00, -3.7080607753039518e+00, -3.5485365785817580e+00, -3.3892445472592136e+00, -3.2301730029155085e+00, -3.0713104655004981e+00, -2.9126456409412849e+00, -2.7541674092575419e+00, -2.5958648131459636e+00, -2.4377270469968155e+00, -2.2797434463078550e+00, -2.1219034774632650e+00, -1.9641967278469044e+00, -1.8066128962612460e+00, -1.6491417836246915e+00, -1.4917732839215128e+00, -1.3344973753799896e+00, -1.1773041118552243e+00, -1.0201836143944896e+00, -8.6312606296338723e-01, -7.0612168831240074e-01, -5.4916076396359503e-01, -3.9223359829815591e-01, -2.3533052672581237e-01, -7.8441903917412792e-02, 7.8441903917412792e-02, 2.3533052672581237e-01, 3.9223359829815591e-01, 5.4916076396359503e-01, 7.0612168831240074e-01, 8.6312606296338723e-01, 1.0201836143944896e+00, 1.1773041118552243e+00, 1.3344973753799896e+00, 1.4917732839215128e+00, 1.6491417836246915e+00, 1.8066128962612460e+00, 1.9641967278469044e+00, 2.1219034774632650e+00, 2.2797434463078550e+00, 2.4377270469968155e+00, 2.5958648131459636e+00, 2.7541674092575419e+00, 2.9126456409412849e+00, 3.0713104655004981e+00, 3.2301730029155085e+00, 3.3892445472592136e+00, 3.5485365785817580e+00, 3.7080607753039518e+00, 3.8678290271620543e+00, 4.0278534487497097e+00, 4.1881463937064671e+00, 4.3487204696060182e+00, 4.5095885536020024e+00, 4.6707638088937005e+00, 4.8322597020794342e+00, 4.9940900214715160e+00, 5.1562688964529020e+00, 5.3188108179631426e+00, 5.4817306602094709e+00, 5.6450437037075716e+00, 5.8087656597670589e+00, 5.9729126965475468e+00, 6.1375014668241503e+00, 6.3025491376151397e+00, 6.4680734218403675e+00, 6.6340926121968646e+00, 6.8006256174581203e+00, 6.9676920014260446e+00, 7.1353120247902524e+00, 7.3035066901782200e+00, 7.4722977907127222e+00, 7.6417079624302628e+00, 7.8117607409569434e+00, 7.9824806228866425e+00, 8.1538931323624819e+00, 8.3260248934261227e+00, 8.4989037087736055e+00, 8.6725586456412369e+00, 8.8470201296436706e+00, 9.0223200475008358e+00, 9.1984918597235552e+00, 9.3755707244836426e+00, 9.5535936340768206e+00, 9.7325995656019266e+00, 9.9126296477337945e+00, 1.0093727345768286e+01, 1.0275938667476471e+01, 1.0459312392733535e+01, 1.0643900330402785e+01, 1.0829757606576079e+01, 1.1016942989025184e+01, 1.1205519253636435e+01, 1.1395553599726039e+01, 1.1587118122520339e+01, 1.1780290352805242e+01, 1.1975153875897130e+01, 1.2171799044787127e+01, 1.2370323805730495e+01, 1.2570834658918320e+01, 1.2773447782488505e+01, 1.2978290355434069e+01, 1.3185502124544024e+01, 1.3395237273208020e+01, 1.3607666666938064e+01, 1.3822980573565543e+01, 1.4041391987855551e+01, 1.4263140734648266e+01, 1.4488498587572698e+01, 1.4717775731247299e+01, 1.4951329028681464e+01, 1.5189572756961194e+01, 1.5432992784892868e+01, 1.5682165658809755e+01, 1.5937784868895722e+01, 1.6200697936792103e+01, 1.6471960388762881e+01, 1.6752917191398179e+01, 1.7045331151092153e+01, 1.7351596779550405e+01, 1.7675122529961925e+01, 1.8021081501173168e+01, 1.8398096565132178e+01, 1.8822895980564734e+01, 1.9339248667911409e+01}, } // wCache computed from Chebfun. var wCacheHermite = [][]float64{ {1.7724538509055159e+00}, {8.8622692545275794e-01, 8.8622692545275794e-01}, {2.9540897515091952e-01, 1.1816359006036770e+00, 2.9540897515091952e-01}, {8.1312835447245130e-02, 8.0491409000551273e-01, 8.0491409000551273e-01, 8.1312835447245130e-02}, {1.9953242059045879e-02, 3.9361932315224107e-01, 9.4530872048294201e-01, 3.9361932315224107e-01, 1.9953242059045879e-02}, {4.5300099055088682e-03, 1.5706732032285645e-01, 7.2462959522439263e-01, 7.2462959522439263e-01, 1.5706732032285645e-01, 4.5300099055088682e-03}, {9.7178124509951806e-04, 5.4515582819127072e-02, 4.2560725261012772e-01, 8.1026461755680723e-01, 4.2560725261012772e-01, 5.4515582819127072e-02, 9.7178124509951806e-04}, {1.9960407221136889e-04, 1.7077983007413408e-02, 2.0780232581489197e-01, 6.6114701255824115e-01, 6.6114701255824115e-01, 2.0780232581489197e-01, 1.7077983007413408e-02, 1.9960407221136889e-04}, {3.9606977263264351e-05, 4.9436242755369481e-03, 8.8474527394376584e-02, 4.3265155900255570e-01, 7.2023521560605097e-01, 4.3265155900255570e-01, 8.8474527394376584e-02, 4.9436242755369481e-03, 3.9606977263264351e-05}, {7.6404328552325936e-06, 1.3436457467812385e-03, 3.3874394455481120e-02, 2.4013861108231432e-01, 6.1086263373532612e-01, 6.1086263373532612e-01, 2.4013861108231432e-01, 3.3874394455481120e-02, 1.3436457467812385e-03, 7.6404328552325936e-06}, {1.4395603937142598e-06, 3.4681946632334550e-04, 1.1911395444911524e-02, 1.1722787516770818e-01, 4.2935975235612489e-01, 6.5475928691459262e-01, 4.2935975235612489e-01, 1.1722787516770818e-01, 1.1911395444911524e-02, 3.4681946632334550e-04, 1.4395603937142598e-06}, {2.6585516843563055e-07, 8.5736870435878019e-05, 3.9053905846290599e-03, 5.1607985615883964e-02, 2.6049231026416109e-01, 5.7013523626247942e-01, 5.7013523626247942e-01, 2.6049231026416109e-01, 5.1607985615883964e-02, 3.9053905846290599e-03, 8.5736870435878019e-05, 2.6585516843563055e-07}, {4.8257318500731284e-08, 2.0430360402707074e-05, 1.2074599927193832e-03, 2.0862775296169932e-02, 1.4032332068702327e-01, 4.2161629689854296e-01, 6.0439318792116203e-01, 4.2161629689854296e-01, 1.4032332068702327e-01, 2.0862775296169932e-02, 1.2074599927193832e-03, 2.0430360402707074e-05, 4.8257318500731284e-08}, {8.6285911681251554e-09, 4.7164843550189453e-06, 3.5509261355192302e-04, 7.8500547264579047e-03, 6.8505534223465281e-02, 2.7310560906424641e-01, 5.3640590971209023e-01, 5.3640590971209023e-01, 2.7310560906424641e-01, 6.8505534223465281e-02, 7.8500547264579047e-03, 3.5509261355192302e-04, 4.7164843550189453e-06, 8.6285911681251554e-09}, {1.5224758042535219e-09, 1.0591155477110612e-06, 1.0000444123249973e-04, 2.7780688429127598e-03, 3.0780033872546117e-02, 1.5848891579593580e-01, 4.1202868749889832e-01, 5.6410030872641814e-01, 4.1202868749889832e-01, 1.5848891579593580e-01, 3.0780033872546117e-02, 2.7780688429127598e-03, 1.0000444123249973e-04, 1.0591155477110612e-06, 1.5224758042535219e-09}, {2.6548074740111957e-10, 2.3209808448652080e-07, 2.7118600925378922e-05, 9.3228400862418201e-04, 1.2880311535509982e-02, 8.3810041398985943e-02, 2.8064745852853384e-01, 5.0792947901661334e-01, 5.0792947901661334e-01, 2.8064745852853384e-01, 8.3810041398985943e-02, 1.2880311535509982e-02, 9.3228400862418201e-04, 2.7118600925378922e-05, 2.3209808448652080e-07, 2.6548074740111957e-10}, {4.5805789307986523e-11, 4.9770789816307401e-08, 7.1122891400212805e-06, 2.9864328669775215e-04, 5.0673499576275429e-03, 4.0920034149756306e-02, 1.7264829767009740e-01, 4.0182646947041184e-01, 5.3091793762486328e-01, 4.0182646947041184e-01, 1.7264829767009740e-01, 4.0920034149756306e-02, 5.0673499576275429e-03, 2.9864328669775215e-04, 7.1122891400212805e-06, 4.9770789816307401e-08, 4.5805789307986523e-11}, {7.8281997721158175e-12, 1.0467205795791975e-08, 1.8106544810934246e-06, 9.1811268679294544e-05, 1.8885226302684155e-03, 1.8640042387544645e-02, 9.7301747641315411e-02, 2.8480728566997937e-01, 4.8349569472545578e-01, 4.8349569472545578e-01, 2.8480728566997937e-01, 9.7301747641315411e-02, 1.8640042387544645e-02, 1.8885226302684155e-03, 9.1811268679294544e-05, 1.8106544810934246e-06, 1.0467205795791975e-08, 7.8281997721158175e-12}, {1.3262970944985103e-12, 2.1630510098635541e-09, 4.4882431472231438e-07, 2.7209197763161644e-05, 6.7087752140718431e-04, 7.9888667777229892e-03, 5.0810386909052110e-02, 1.8363270130699696e-01, 3.9160898861302956e-01, 5.0297488827618764e-01, 3.9160898861302956e-01, 1.8363270130699696e-01, 5.0810386909052110e-02, 7.9888667777229892e-03, 6.7087752140718431e-04, 2.7209197763161644e-05, 4.4882431472231438e-07, 2.1630510098635541e-09, 1.3262970944985103e-12}, {2.2293936455341389e-13, 4.3993409922731442e-10, 1.0860693707692744e-07, 7.8025564785320785e-06, 2.2833863601635308e-04, 3.2437733422378532e-03, 2.4810520887463654e-02, 1.0901720602002316e-01, 2.8667550536283426e-01, 4.6224366960061009e-01, 4.6224366960061009e-01, 2.8667550536283426e-01, 1.0901720602002316e-01, 2.4810520887463654e-02, 3.2437733422378532e-03, 2.2833863601635308e-04, 7.8025564785320785e-06, 1.0860693707692744e-07, 4.3993409922731442e-10, 2.2293936455341389e-13}, {3.7203650688184023e-14, 8.8186112420499177e-11, 2.5712301800593246e-08, 2.1718848980566754e-06, 7.4783988673100723e-05, 1.2549820417264148e-03, 1.1414065837434373e-02, 6.0179646658912296e-02, 1.9212032406699767e-01, 3.8166907361350205e-01, 4.7902370312017756e-01, 3.8166907361350205e-01, 1.9212032406699767e-01, 6.0179646658912296e-02, 1.1414065837434373e-02, 1.2549820417264148e-03, 7.4783988673100723e-05, 2.1718848980566754e-06, 2.5712301800593246e-08, 8.8186112420499177e-11, 3.7203650688184023e-14}, {6.1671834244041516e-15, 1.7443390075479748e-11, 5.9669909860596536e-09, 5.8842875633009930e-07, 2.3655128552510423e-05, 4.6488505088425271e-04, 4.9783993350516510e-03, 3.1140370884423854e-02, 1.1910236095878249e-01, 2.8697143324690705e-01, 4.4354522643495936e-01, 4.4354522643495936e-01, 2.8697143324690705e-01, 1.1910236095878249e-01, 3.1140370884423854e-02, 4.9783993350516510e-03, 4.6488505088425271e-04, 2.3655128552510423e-05, 5.8842875633009930e-07, 5.9669909860596536e-09, 1.7443390075479748e-11, 6.1671834244041516e-15}, {1.0160384616453285e-15, 3.4083140980305419e-12, 1.3596296504028875e-09, 1.5553393291457709e-07, 7.2492959180022684e-06, 1.6556169914187465e-04, 2.0695678749606356e-03, 1.5207084004484164e-02, 6.8890289429087329e-02, 1.9864489857802253e-01, 3.7214382487756476e-01, 4.5819658559321297e-01, 3.7214382487756476e-01, 1.9864489857802253e-01, 6.8890289429087329e-02, 1.5207084004484164e-02, 2.0695678749606356e-03, 1.6556169914187465e-04, 7.2492959180022684e-06, 1.5553393291457709e-07, 1.3596296504028875e-09, 3.4083140980305419e-12, 1.0160384616453285e-15}, {1.6643684964891445e-16, 6.5846202430781003e-13, 3.0462542699875441e-10, 4.0189711749414533e-08, 2.1582457049023422e-06, 5.6886916364043827e-05, 8.2369248268841886e-04, 7.0483558100726791e-03, 3.7445470503230750e-02, 1.2773962178455914e-01, 2.8617953534644303e-01, 4.2693116386869923e-01, 4.2693116386869923e-01, 2.8617953534644303e-01, 1.2773962178455914e-01, 3.7445470503230750e-02, 7.0483558100726791e-03, 8.2369248268841886e-04, 5.6886916364043827e-05, 2.1582457049023422e-06, 4.0189711749414533e-08, 3.0462542699875441e-10, 6.5846202430781003e-13, 1.6643684964891445e-16}, {2.7119235127587269e-17, 1.2588149877465385e-13, 6.7196384177062396e-11, 1.0170382503018480e-08, 6.2570324996911171e-07, 1.8915972957340510e-05, 3.1508363874548464e-04, 3.1157087201256362e-03, 1.9243098965408916e-02, 7.6888995175808827e-02, 2.0362113667812395e-01, 3.6308898927589056e-01, 4.3986872216948475e-01, 3.6308898927589056e-01, 2.0362113667812395e-01, 7.6888995175808827e-02, 1.9243098965408916e-02, 3.1157087201256362e-03, 3.1508363874548464e-04, 1.8915972957340510e-05, 6.2570324996911171e-07, 1.0170382503018480e-08, 6.7196384177062396e-11, 1.2588149877465385e-13, 2.7119235127587269e-17}, {4.3969160947540168e-18, 2.3831486593721262e-14, 1.4609999339816088e-11, 2.5244940344905425e-09, 1.7701063373973562e-07, 6.1032917173960523e-06, 1.1622970160311058e-04, 1.3190647223238600e-03, 9.3979012911595897e-03, 4.3598227217250818e-02, 1.3511332791178782e-01, 2.8463224117678448e-01, 4.1204365059036946e-01, 4.1204365059036946e-01, 2.8463224117678448e-01, 1.3511332791178782e-01, 4.3598227217250818e-02, 9.3979012911595897e-03, 1.3190647223238600e-03, 1.1622970160311058e-04, 6.1032917173960523e-06, 1.7701063373973562e-07, 2.5244940344905425e-09, 1.4609999339816088e-11, 2.3831486593721262e-14, 4.3969160947540168e-18}, {7.0957792932592773e-19, 4.4707724573930981e-15, 3.1341176136230566e-12, 6.1550315782317765e-10, 4.8954004096995851e-08, 1.9152809005953010e-06, 4.1467580043841186e-05, 5.3676961568811289e-04, 4.3812798357925394e-03, 2.3415933625341907e-02, 8.4173081084051971e-02, 2.0737048075100944e-01, 3.5451730409975396e-01, 4.2357728801505945e-01, 3.5451730409975396e-01, 2.0737048075100944e-01, 8.4173081084051971e-02, 2.3415933625341907e-02, 4.3812798357925394e-03, 5.3676961568811289e-04, 4.1467580043841186e-05, 1.9152809005953010e-06, 4.8954004096995851e-08, 6.1550315782317765e-10, 3.1341176136230566e-12, 4.4707724573930981e-15, 7.0957792932592773e-19}, {1.1401393479036859e-19, 8.3159379512068002e-16, 6.6394367149096827e-13, 1.4758531682776914e-10, 1.3256825015417164e-08, 5.8577197209929782e-07, 1.4345504229714394e-05, 2.1061810002403312e-04, 1.9573312944089908e-03, 1.1968423214354838e-02, 4.9514889289898188e-02, 1.4139460978695487e-01, 2.8256139125938867e-01, 3.9860471782645146e-01, 3.9860471782645146e-01, 2.8256139125938867e-01, 1.4139460978695487e-01, 4.9514889289898188e-02, 1.1968423214354838e-02, 1.9573312944089908e-03, 2.1061810002403312e-04, 1.4345504229714394e-05, 5.8577197209929782e-07, 1.3256825015417164e-08, 1.4758531682776914e-10, 6.6394367149096827e-13, 8.3159379512068002e-16, 1.1401393479036859e-19}, {1.8244608516739659e-20, 1.5345004446053123e-16, 1.3901072714496111e-13, 3.4841301613084286e-11, 3.5203123276007155e-09, 1.7492291299499463e-07, 4.8230734976477891e-06, 7.9909203545218356e-05, 8.4079250614026418e-04, 5.8455035452715061e-03, 2.7639655592023655e-02, 9.0768842215578197e-02, 2.1014269444921063e-01, 3.4641893907167015e-01, 4.0897117463522970e-01, 3.4641893907167015e-01, 2.1014269444921063e-01, 9.0768842215578197e-02, 2.7639655592023655e-02, 5.8455035452715061e-03, 8.4079250614026418e-04, 7.9909203545218356e-05, 4.8230734976477891e-06, 1.7492291299499463e-07, 3.5203123276007155e-09, 3.4841301613084286e-11, 1.3901072714496111e-13, 1.5345004446053123e-16, 1.8244608516739659e-20}, {2.9082547001312504e-21, 2.8103336027509541e-17, 2.8786070805487377e-14, 8.1061862974630246e-12, 9.1785804243785856e-10, 5.1085224507759746e-08, 1.5790948873247135e-06, 2.9387252289229863e-05, 3.4831012431868588e-04, 2.7379224730676621e-03, 1.4703829704826692e-02, 5.5144176870234256e-02, 1.4673584754089000e-01, 2.8013093083921248e-01, 3.8639488954181417e-01, 3.8639488954181417e-01, 2.8013093083921248e-01, 1.4673584754089000e-01, 5.5144176870234256e-02, 1.4703829704826692e-02, 2.7379224730676621e-03, 3.4831012431868588e-04, 2.9387252289229863e-05, 1.5790948873247135e-06, 5.1085224507759746e-08, 9.1785804243785856e-10, 8.1061862974630246e-12, 2.8786070805487377e-14, 2.8103336027509541e-17, 2.9082547001312504e-21}, {4.6189683913871598e-22, 5.1106090079270951e-18, 5.8995564987539112e-15, 1.8603735214521663e-12, 2.3524920032086692e-10, 1.4611988344910622e-08, 5.0437125589397732e-07, 1.0498602757675620e-05, 1.3952090395047032e-04, 1.2336833073068893e-03, 7.4827999140352043e-03, 3.1847230731300323e-02, 9.6717948160870412e-02, 2.1213278866876470e-01, 3.3877265789410776e-01, 3.9577855609860946e-01, 3.3877265789410776e-01, 2.1213278866876470e-01, 9.6717948160870412e-02, 3.1847230731300323e-02, 7.4827999140352043e-03, 1.2336833073068893e-03, 1.3952090395047032e-04, 1.0498602757675620e-05, 5.0437125589397732e-07, 1.4611988344910622e-08, 2.3524920032086692e-10, 1.8603735214521663e-12, 5.8995564987539112e-15, 5.1106090079270951e-18, 4.6189683913871598e-22}, {7.3106764273841909e-23, 9.2317365365181365e-19, 1.1973440170928574e-15, 4.2150102113264756e-13, 5.9332914633966556e-11, 4.0988321647708776e-09, 1.5741677925455937e-07, 3.6505851295623875e-06, 5.4165840618199778e-05, 5.3626836552797335e-04, 3.6548903266544271e-03, 1.7553428831573435e-02, 6.0458130955912612e-02, 1.5126973407664251e-01, 2.7745814230252980e-01, 3.7523835259280258e-01, 3.7523835259280258e-01, 2.7745814230252980e-01, 1.5126973407664251e-01, 6.0458130955912612e-02, 1.7553428831573435e-02, 3.6548903266544271e-03, 5.3626836552797335e-04, 5.4165840618199778e-05, 3.6505851295623875e-06, 1.5741677925455937e-07, 4.0988321647708776e-09, 5.9332914633966556e-11, 4.2150102113264756e-13, 1.1973440170928574e-15, 9.2317365365181365e-19, 7.3106764273841909e-23}, {1.1533162176980265e-23, 1.6570947415336692e-19, 2.4077856795579959e-16, 9.4348141590150248e-14, 1.4739809370924901e-11, 1.1289222471083366e-09, 4.8077456763232087e-08, 1.2376933672012150e-06, 2.0423684051423809e-05, 2.2544277059632773e-04, 1.7184546377609299e-03, 9.2656899706852411e-03, 3.5987982318576993e-02, 1.0206907999554145e-01, 2.1349393115029186e-01, 3.3155200075074132e-01, 3.8378526651986389e-01, 3.3155200075074132e-01, 2.1349393115029186e-01, 1.0206907999554145e-01, 3.5987982318576993e-02, 9.2656899706852411e-03, 1.7184546377609299e-03, 2.2544277059632773e-04, 2.0423684051423809e-05, 1.2376933672012150e-06, 4.8077456763232087e-08, 1.1289222471083366e-09, 1.4739809370924901e-11, 9.4348141590150248e-14, 2.4077856795579959e-16, 1.6570947415336692e-19, 1.1533162176980265e-23}, {1.8138001119597749e-24, 2.9567089223605576e-20, 4.7999019978948293e-17, 2.0878403731160143e-14, 3.6098817474860888e-12, 3.0562520419155053e-10, 1.4387732912539959e-08, 4.0979740352245880e-07, 7.4934487833022770e-06, 9.1861189828724009e-05, 7.7981759962319987e-04, 4.6984636292665893e-03, 2.0473151727019457e-02, 6.5445134108752731e-02, 1.5511041662330927e-01, 2.7462771563513722e-01, 3.6499244699664513e-01, 3.6499244699664513e-01, 2.7462771563513722e-01, 1.5511041662330927e-01, 6.5445134108752731e-02, 2.0473151727019457e-02, 4.6984636292665893e-03, 7.7981759962319987e-04, 9.1861189828724009e-05, 7.4934487833022770e-06, 4.0979740352245880e-07, 1.4387732912539959e-08, 3.0562520419155053e-10, 3.6098817474860888e-12, 2.0878403731160143e-14, 4.7999019978948293e-17, 2.9567089223605576e-20, 1.8138001119597749e-24}, {2.8441134634327172e-25, 5.2456527291743166e-21, 9.4898848794730163e-18, 4.5704441904182093e-15, 8.7225260125370039e-13, 8.1406956866777238e-11, 4.2239761300094312e-09, 1.3269405173066746e-07, 2.6798156546135386e-06, 3.6352769174157649e-05, 3.4234009319960727e-04, 2.2950283295840954e-03, 1.1166806590265730e-02, 4.0024775133100314e-02, 1.0687290695546242e-01, 2.1434719059607343e-01, 3.2472872157456961e-01, 3.7281997319072468e-01, 3.2472872157456961e-01, 2.1434719059607343e-01, 1.0687290695546242e-01, 4.0024775133100314e-02, 1.1166806590265730e-02, 2.2950283295840954e-03, 3.4234009319960727e-04, 3.6352769174157649e-05, 2.6798156546135386e-06, 1.3269405173066746e-07, 4.2239761300094312e-09, 8.1406956866777238e-11, 8.7225260125370039e-13, 4.5704441904182093e-15, 9.4898848794730163e-18, 5.2456527291743166e-21, 2.8441134634327172e-25}, {4.4471534175756294e-26, 9.2564030835581952e-22, 1.8615979878080060e-18, 9.9029016869062119e-16, 2.0809126742868747e-13, 2.1353541817845700e-11, 1.2178678209557312e-09, 4.2074913231090725e-08, 9.3555700897732196e-07, 1.3997029220328986e-05, 1.4569615962636070e-04, 1.0825347566868020e-03, 5.8564259865595538e-03, 2.3425767509731743e-02, 7.0104750105177666e-02, 1.5835545375116650e-01, 2.7170124700952736e-01, 3.5554007427370893e-01, 3.5554007427370893e-01, 2.7170124700952736e-01, 1.5835545375116650e-01, 7.0104750105177666e-02, 2.3425767509731743e-02, 5.8564259865595538e-03, 1.0825347566868020e-03, 1.4569615962636070e-04, 1.3997029220328986e-05, 9.3555700897732196e-07, 4.2074913231090725e-08, 1.2178678209557312e-09, 2.1353541817845700e-11, 2.0809126742868747e-13, 9.9029016869062119e-16, 1.8615979878080060e-18, 9.2564030835581952e-22, 4.4471534175756294e-26}, {6.9350835444886530e-27, 1.6249853271916221e-22, 3.6247269512444368e-19, 2.1248851941314958e-16, 4.9047393641852124e-14, 5.5203972646374721e-12, 3.4519062272121333e-10, 1.3079698821802362e-08, 3.1928854810032377e-07, 5.2521435771200543e-06, 6.0226951652674167e-05, 4.9417150121469438e-04, 2.9608001846029054e-03, 1.3160179977211566e-02, 4.3931362299539353e-02, 1.1117916510719518e-01, 2.1478887596478388e-01, 3.1827467975443136e-01, 3.6274375769908357e-01, 3.1827467975443136e-01, 2.1478887596478388e-01, 1.1117916510719518e-01, 4.3931362299539353e-02, 1.3160179977211566e-02, 2.9608001846029054e-03, 4.9417150121469438e-04, 6.0226951652674167e-05, 5.2521435771200543e-06, 3.1928854810032377e-07, 1.3079698821802362e-08, 3.4519062272121333e-10, 5.5203972646374721e-12, 4.9047393641852124e-14, 2.1248851941314958e-16, 3.6247269512444368e-19, 1.6249853271916221e-22, 6.9350835444886530e-27}, {1.0787188820741241e-27, 2.8387387532094075e-23, 7.0078433305584917e-20, 4.5173712236048158e-17, 1.1428616750256895e-14, 1.4076333438452520e-12, 9.6270292926054501e-11, 3.9906528856889178e-09, 1.0665865704409148e-07, 1.9234656867323990e-06, 2.4223415120935207e-05, 2.1875759533939115e-04, 1.4463071215627061e-03, 7.1152368261340193e-03, 2.6380533520486894e-02, 7.4443983368238764e-02, 1.6108797149548099e-01, 2.6872376002892800e-01, 3.4678411786878038e-01, 3.4678411786878038e-01, 2.6872376002892800e-01, 1.6108797149548099e-01, 7.4443983368238764e-02, 2.6380533520486894e-02, 7.1152368261340193e-03, 1.4463071215627061e-03, 2.1875759533939115e-04, 2.4223415120935207e-05, 1.9234656867323990e-06, 1.0665865704409148e-07, 3.9906528856889178e-09, 9.6270292926054501e-11, 1.4076333438452520e-12, 1.1428616750256895e-14, 4.5173712236048158e-17, 7.0078433305584917e-20, 2.8387387532094075e-23, 1.0787188820741241e-27}, {1.6737892441539538e-28, 4.9359073375904207e-24, 1.3457268201343837e-20, 9.5193204821162674e-18, 2.6340961107224671e-15, 3.5426508019791487e-13, 2.6440048769930072e-11, 1.1961664237667613e-09, 3.4915088439108438e-08, 6.8844204093401453e-07, 9.4942995361418356e-06, 9.4077279467672325e-05, 6.8405759521855724e-04, 3.7112302317141572e-03, 1.5221980837289402e-02, 4.7690071331635359e-02, 1.1503504579976950e-01, 2.1489607677746486e-01, 3.1216284886717011e-01, 3.5344263570679940e-01, 3.1216284886717011e-01, 2.1489607677746486e-01, 1.1503504579976950e-01, 4.7690071331635359e-02, 1.5221980837289402e-02, 3.7112302317141572e-03, 6.8405759521855724e-04, 9.4077279467672325e-05, 9.4942995361418356e-06, 6.8844204093401453e-07, 3.4915088439108438e-08, 1.1961664237667613e-09, 2.6440048769930072e-11, 3.5426508019791487e-13, 2.6340961107224671e-15, 9.5193204821162674e-18, 1.3457268201343837e-20, 4.9359073375904207e-24, 1.6737892441539538e-28}, {2.5910437138470431e-29, 8.5440569637751720e-25, 2.5675933654117104e-21, 1.9891810121165382e-18, 6.0083587894908697e-16, 8.8057076452162173e-14, 7.1565280526903396e-12, 3.5256207913654460e-10, 1.1212360832275973e-08, 2.4111441636705294e-07, 3.6315761506930362e-06, 3.9369339810924932e-05, 3.1385359454133192e-04, 1.8714968295979542e-03, 8.4608880082581352e-03, 2.9312565536172355e-02, 7.8474605865404390e-02, 1.6337873271327136e-01, 2.6572825187737692e-01, 3.3864327742558936e-01, 3.3864327742558936e-01, 2.6572825187737692e-01, 1.6337873271327136e-01, 7.8474605865404390e-02, 2.9312565536172355e-02, 8.4608880082581352e-03, 1.8714968295979542e-03, 3.1385359454133192e-04, 3.9369339810924932e-05, 3.6315761506930362e-06, 2.4111441636705294e-07, 1.1212360832275973e-08, 3.5256207913654460e-10, 7.1565280526903396e-12, 8.8057076452162173e-14, 6.0083587894908697e-16, 1.9891810121165382e-18, 2.5675933654117104e-21, 8.5440569637751720e-25, 2.5910437138470431e-29}, {4.0019596605455888e-30, 1.4726537286520423e-25, 4.8687379360130589e-22, 4.1234085375315004e-19, 1.3569875295861202e-16, 2.1629872471750215e-14, 1.9103833646809321e-12, 1.0226798927782354e-10, 3.5356816483807076e-09, 8.2726584187498191e-08, 1.3573781404870848e-06, 1.6055965736677200e-05, 1.3993025659674152e-04, 9.1423425632870857e-04, 4.5403929873032720e-03, 1.7330881362116784e-02, 5.1289872397094663e-02, 1.1848439124684401e-01, 2.1473086449008444e-01, 3.0636781693785120e-01, 3.4482208361638955e-01, 3.0636781693785120e-01, 2.1473086449008444e-01, 1.1848439124684401e-01, 5.1289872397094663e-02, 1.7330881362116784e-02, 4.5403929873032720e-03, 9.1423425632870857e-04, 1.3993025659674152e-04, 1.6055965736677200e-05, 1.3573781404870848e-06, 8.2726584187498191e-08, 3.5356816483807076e-09, 1.0226798927782354e-10, 1.9103833646809321e-12, 2.1629872471750215e-14, 1.3569875295861202e-16, 4.1234085375315004e-19, 4.8687379360130589e-22, 1.4726537286520423e-25, 4.0019596605455888e-30}, {6.1678589258109773e-31, 2.5278698640534739e-26, 9.1778906956924963e-23, 8.4821520800863616e-20, 3.0358903478107461e-17, 5.2533377155686787e-15, 5.0327055821840466e-13, 2.9217288372333376e-11, 1.0958052288078504e-09, 2.7834715265490800e-08, 4.9636593935798231e-07, 6.3902459677354328e-06, 6.0719621077883790e-05, 4.3341227172125611e-04, 2.3571613945963252e-03, 9.8795240531885219e-03, 3.2202101288907867e-02, 8.2211269303293782e-02, 1.6528800127466756e-01, 2.6273890678229461e-01, 3.3104891389085667e-01, 3.3104891389085667e-01, 2.6273890678229461e-01, 1.6528800127466756e-01, 8.2211269303293782e-02, 3.2202101288907867e-02, 9.8795240531885219e-03, 2.3571613945963252e-03, 4.3341227172125611e-04, 6.0719621077883790e-05, 6.3902459677354328e-06, 4.9636593935798231e-07, 2.7834715265490800e-08, 1.0958052288078504e-09, 2.9217288372333376e-11, 5.0327055821840466e-13, 5.2533377155686787e-15, 3.0358903478107461e-17, 8.4821520800863616e-20, 9.1778906956924963e-23, 2.5278698640534739e-26, 6.1678589258109773e-31}, {9.4863063307486296e-32, 4.3221460599337345e-27, 1.7203368260282161e-23, 1.7320753790913467e-20, 6.7308117032428195e-18, 1.2622032209758195e-15, 1.3092104166584946e-13, 8.2271061208164963e-12, 3.3407179153175535e-10, 9.1931960675404414e-09, 1.7777830445479720e-07, 2.4851377424115403e-06, 2.5680573077056677e-05, 1.9972435671322962e-04, 1.1860700927674253e-03, 5.4414552932418097e-03, 1.9468160151101737e-02, 5.4724809081874805e-02, 1.2156737988638795e-01, 2.1434349700188368e-01, 3.0086599386765978e-01, 3.3680296539275278e-01, 3.0086599386765978e-01, 2.1434349700188368e-01, 1.2156737988638795e-01, 5.4724809081874805e-02, 1.9468160151101737e-02, 5.4414552932418097e-03, 1.1860700927674253e-03, 1.9972435671322962e-04, 2.5680573077056677e-05, 2.4851377424115403e-06, 1.7777830445479720e-07, 9.1931960675404414e-09, 3.3407179153175535e-10, 8.2271061208164963e-12, 1.3092104166584946e-13, 1.2622032209758195e-15, 6.7308117032428195e-18, 1.7320753790913467e-20, 1.7203368260282161e-23, 4.3221460599337345e-27, 9.4863063307486296e-32}, {1.4561153081762322e-32, 7.3621261042968285e-28, 3.2072216919050275e-24, 3.5121449558365656e-21, 1.4794099758171669e-18, 3.0015214029808191e-16, 3.3650356127923192e-14, 2.2848078971220373e-12, 1.0026000778909185e-10, 2.9831210190396358e-09, 6.2427245062815072e-08, 9.4545385422855902e-07, 1.0600171772517656e-05, 8.9597973640616782e-05, 5.7942043271566558e-04, 2.9012937752966299e-03, 1.1357866939069948e-02, 3.5033757109687119e-02, 8.5670187300246295e-02, 1.6686716582564590e-01, 2.5977339611588807e-01, 3.2394262884199604e-01, 3.2394262884199604e-01, 2.5977339611588807e-01, 1.6686716582564590e-01, 8.5670187300246295e-02, 3.5033757109687119e-02, 1.1357866939069948e-02, 2.9012937752966299e-03, 5.7942043271566558e-04, 8.9597973640616782e-05, 1.0600171772517656e-05, 9.4545385422855902e-07, 6.2427245062815072e-08, 2.9831210190396358e-09, 1.0026000778909185e-10, 2.2848078971220373e-12, 3.3650356127923192e-14, 3.0015214029808191e-16, 1.4794099758171669e-18, 3.5121449558365656e-21, 3.2072216919050275e-24, 7.3621261042968285e-28, 1.4561153081762322e-32}, {2.2308126593779868e-33, 1.2494829120559801e-28, 5.9481747159233458e-25, 7.0737246502696336e-22, 3.2248298707326610e-19, 7.0674619157542681e-17, 8.5500874663703821e-15, 6.2620383158353876e-13, 2.9642049893157670e-11, 9.5182669412336419e-10, 2.1512839074194501e-08, 3.5225192415065300e-07, 4.2754558863972689e-06, 3.9183295448819551e-05, 2.7524242709953090e-04, 1.5001278829297612e-03, 6.4070706562040147e-03, 2.1617644433765643e-02, 5.7992746631628803e-02, 1.2432050192893590e-01, 2.1377487850201790e-01, 2.9563565196662861e-01, 3.2931845505069163e-01, 2.9563565196662861e-01, 2.1377487850201790e-01, 1.2432050192893590e-01, 5.7992746631628803e-02, 2.1617644433765643e-02, 6.4070706562040147e-03, 1.5001278829297612e-03, 2.7524242709953090e-04, 3.9183295448819551e-05, 4.2754558863972689e-06, 3.5225192415065300e-07, 2.1512839074194501e-08, 9.5182669412336419e-10, 2.9642049893157670e-11, 6.2620383158353876e-13, 8.5500874663703821e-15, 7.0674619157542681e-17, 3.2248298707326610e-19, 7.0737246502696336e-22, 5.9481747159233458e-25, 1.2494829120559801e-28, 2.2308126593779868e-33}, {3.4113792299096508e-34, 2.1132014962696289e-29, 1.0976558019968051e-25, 1.4155042016755176e-22, 6.9737995966949200e-20, 1.6484447389507407e-17, 2.1486472823678717e-15, 1.6947076167749986e-13, 8.6391402914483532e-12, 2.9885455879923381e-10, 7.2816347565639946e-09, 1.2865324130563406e-07, 1.6869468397355139e-06, 1.6725935920653945e-05, 1.2731983755106949e-04, 7.5339673454313967e-04, 3.5010578505227864e-03, 1.2883487559777229e-02, 3.7795830992247079e-02, 8.8868227566005320e-02, 1.6816012736212269e-01, 2.5684454350651975e-01, 3.1727438491816684e-01, 3.1727438491816684e-01, 2.5684454350651975e-01, 1.6816012736212269e-01, 8.8868227566005320e-02, 3.7795830992247079e-02, 1.2883487559777229e-02, 3.5010578505227864e-03, 7.5339673454313967e-04, 1.2731983755106949e-04, 1.6725935920653945e-05, 1.6869468397355139e-06, 1.2865324130563406e-07, 7.2816347565639946e-09, 2.9885455879923381e-10, 8.6391402914483532e-12, 1.6947076167749986e-13, 2.1486472823678717e-15, 1.6484447389507407e-17, 6.9737995966949200e-20, 1.4155042016755176e-22, 1.0976558019968051e-25, 2.1132014962696289e-29, 3.4113792299096508e-34}, {5.2074550840354642e-35, 3.5619817807815819e-30, 2.0158558166547157e-26, 2.8149547423920401e-23, 1.4966299166256593e-20, 3.8101463479230325e-18, 5.3428423961486667e-16, 4.5312676467479057e-14, 2.4836135431247532e-12, 9.2402978883643831e-11, 2.4228134937243909e-09, 4.6104364856635215e-08, 6.5181055230401887e-07, 6.9771079617906096e-06, 5.7425938238321535e-05, 3.6806169587486260e-04, 1.8562527788732503e-03, 7.4296915378901547e-03, 2.3765555762406108e-02, 6.1094386221801737e-02, 1.2677670015500209e-01, 2.1305846026514422e-01, 2.9065687385124467e-01, 3.2231167941131522e-01, 2.9065687385124467e-01, 2.1305846026514422e-01, 1.2677670015500209e-01, 6.1094386221801737e-02, 2.3765555762406108e-02, 7.4296915378901547e-03, 1.8562527788732503e-03, 3.6806169587486260e-04, 5.7425938238321535e-05, 6.9771079617906096e-06, 6.5181055230401887e-07, 4.6104364856635215e-08, 2.4228134937243909e-09, 9.2402978883643831e-11, 2.4836135431247532e-12, 4.5312676467479057e-14, 5.3428423961486667e-16, 3.8101463479230325e-18, 1.4966299166256593e-20, 2.8149547423920401e-23, 2.0158558166547157e-26, 3.5619817807815819e-30, 5.2074550840354642e-35}, {7.9355514607740056e-36, 5.9846126933135906e-31, 3.6850360801506979e-27, 5.5645774689023294e-24, 3.1883873235051506e-21, 8.7301596011867662e-19, 1.3151596226583889e-16, 1.1975898654791956e-14, 7.0469325815459271e-13, 2.8152965378381835e-11, 7.9304674951654092e-10, 1.6225141358957786e-08, 2.4686589936697532e-07, 2.8472586917348417e-06, 2.5285990277484952e-05, 1.7515043180117349e-04, 9.5639231981941610e-04, 4.1530049119775534e-03, 1.4444961574981133e-02, 4.0479676984603939e-02, 9.1822297079285201e-02, 1.6920447194564109e-01, 2.5396154266475901e-01, 3.1100103037796278e-01, 3.1100103037796278e-01, 2.5396154266475901e-01, 1.6920447194564109e-01, 9.1822297079285201e-02, 4.0479676984603939e-02, 1.4444961574981133e-02, 4.1530049119775534e-03, 9.5639231981941610e-04, 1.7515043180117349e-04, 2.5285990277484952e-05, 2.8472586917348417e-06, 2.4686589936697532e-07, 1.6225141358957786e-08, 7.9304674951654092e-10, 2.8152965378381835e-11, 7.0469325815459271e-13, 1.1975898654791956e-14, 1.3151596226583889e-16, 8.7301596011867662e-19, 3.1883873235051506e-21, 5.5645774689023294e-24, 3.6850360801506979e-27, 5.9846126933135906e-31, 7.9355514607740056e-36}, {1.2072872864975299e-36, 1.0023613427435658e-31, 6.7063563353463921e-28, 1.0936809436127891e-24, 6.7446743456588804e-22, 1.9836416602794039e-19, 3.2059589524003601e-17, 3.1301391441242865e-15, 1.9744849360632020e-13, 8.4575241714312574e-12, 2.5554702439987741e-10, 5.6118428733874883e-09, 9.1729613211703643e-08, 1.1378411996774051e-06, 1.0881805485674181e-05, 8.1291046453153734e-05, 4.7952088600477827e-04, 2.2536737753387727e-03, 8.5018075629547680e-03, 2.5900304438342722e-02, 6.4032496212210105e-02, 1.2896559830848855e-01, 2.1222171925816707e-01, 2.8591145169466448e-01, 3.1573389003557428e-01, 2.8591145169466448e-01, 2.1222171925816707e-01, 1.2896559830848855e-01, 6.4032496212210105e-02, 2.5900304438342722e-02, 8.5018075629547680e-03, 2.2536737753387727e-03, 4.7952088600477827e-04, 8.1291046453153734e-05, 1.0881805485674181e-05, 1.1378411996774051e-06, 9.1729613211703643e-08, 5.6118428733874883e-09, 2.5554702439987741e-10, 8.4575241714312574e-12, 1.9744849360632020e-13, 3.1301391441242865e-15, 3.2059589524003601e-17, 1.9836416602794039e-19, 6.7446743456588804e-22, 1.0936809436127891e-24, 6.7063563353463921e-28, 1.0023613427435658e-31, 1.2072872864975299e-36}, {1.8337940485734247e-37, 1.6738016679078003e-32, 1.2152441234045103e-28, 2.1376583083600910e-25, 1.4170935995734126e-22, 4.4709843654079433e-20, 7.7423829570434533e-18, 8.0942618934651918e-16, 5.4659440318156410e-14, 2.5066555238996801e-12, 8.1118773649302876e-11, 1.9090405438119032e-09, 3.3467934040214541e-08, 4.4570299668178385e-07, 4.5816827079555368e-06, 3.6840190537807232e-05, 2.3426989210925618e-04, 1.1890117817496457e-03, 4.8532638261719538e-03, 1.6031941068412211e-02, 4.3079159156765599e-02, 9.4548935477086246e-02, 1.7003245567716402e-01, 2.5113085633200216e-01, 3.0508512920439906e-01, 3.0508512920439906e-01, 2.5113085633200216e-01, 1.7003245567716402e-01, 9.4548935477086246e-02, 4.3079159156765599e-02, 1.6031941068412211e-02, 4.8532638261719538e-03, 1.1890117817496457e-03, 2.3426989210925618e-04, 3.6840190537807232e-05, 4.5816827079555368e-06, 4.4570299668178385e-07, 3.3467934040214541e-08, 1.9090405438119032e-09, 8.1118773649302876e-11, 2.5066555238996801e-12, 5.4659440318156410e-14, 8.0942618934651918e-16, 7.7423829570434533e-18, 4.4709843654079433e-20, 1.4170935995734126e-22, 2.1376583083600910e-25, 1.2152441234045103e-28, 1.6738016679078003e-32, 1.8337940485734247e-37}, {2.7811222326645344e-38, 2.7868913296983680e-33, 2.1929968310380126e-29, 4.1558650081686601e-26, 2.9579544865762534e-23, 9.9993599745434670e-21, 1.8530303241143367e-18, 2.0717064275729557e-16, 1.4956863300607063e-14, 7.3335422940638437e-13, 2.5381498317560184e-11, 6.3917274853532610e-10, 1.1999326533873204e-08, 1.7127604128737511e-07, 1.8891833940946794e-06, 1.6319954290330701e-05, 1.1165708931911324e-04, 6.1070259874041984e-04, 2.6911086058640649e-03, 9.6161203333211508e-03, 2.8012262602063957e-02, 6.6811317318844293e-02, 1.3091376937688559e-01, 2.1128731588244376e-01, 2.8138276384359967e-01, 3.0954302944664125e-01, 2.8138276384359967e-01, 2.1128731588244376e-01, 1.3091376937688559e-01, 6.6811317318844293e-02, 2.8012262602063957e-02, 9.6161203333211508e-03, 2.6911086058640649e-03, 6.1070259874041984e-04, 1.1165708931911324e-04, 1.6319954290330701e-05, 1.8891833940946794e-06, 1.7127604128737511e-07, 1.1999326533873204e-08, 6.3917274853532610e-10, 2.5381498317560184e-11, 7.3335422940638437e-13, 1.4956863300607063e-14, 2.0717064275729557e-16, 1.8530303241143367e-18, 9.9993599745434670e-21, 2.9579544865762534e-23, 4.1558650081686601e-26, 2.1929968310380126e-29, 2.7868913296983680e-33, 2.7811222326645344e-38}, {4.2115420614105446e-39, 4.6271645012802355e-34, 3.9415951369162550e-30, 8.0378813038410338e-27, 6.1353803600426939e-24, 2.2196939309444735e-21, 4.3966970036273617e-19, 5.2503117409060339e-17, 4.0473768240447191e-15, 2.1189539626185899e-13, 7.8326447571213533e-12, 2.1076390184671402e-10, 4.2306685774284424e-09, 6.4623052172886120e-08, 7.6355680403038401e-07, 7.0741004987582161e-06, 5.1975998082926043e-05, 3.0574624681119092e-04, 1.4514479978625793e-03, 5.5977022679341544e-03, 1.7635166965733341e-02, 4.5590184103438805e-02, 9.7064055572858784e-02, 1.7067182934440731e-01, 2.4835688537420786e-01, 2.9949402485158516e-01, 2.9949402485158516e-01, 2.4835688537420786e-01, 1.7067182934440731e-01, 9.7064055572858784e-02, 4.5590184103438805e-02, 1.7635166965733341e-02, 5.5977022679341544e-03, 1.4514479978625793e-03, 3.0574624681119092e-04, 5.1975998082926043e-05, 7.0741004987582161e-06, 7.6355680403038401e-07, 6.4623052172886120e-08, 4.2306685774284424e-09, 2.1076390184671402e-10, 7.8326447571213533e-12, 2.1189539626185899e-13, 4.0473768240447191e-15, 5.2503117409060339e-17, 4.3966970036273617e-19, 2.2196939309444735e-21, 6.1353803600426939e-24, 8.0378813038410338e-27, 3.9415951369162550e-30, 4.6271645012802355e-34, 4.2115420614105446e-39}, {6.3684623301529066e-40, 7.6617679179706699e-35, 7.0570663748570958e-31, 1.5468771288046908e-27, 1.2648661239395541e-24, 4.8919455331107564e-22, 1.0345305017520525e-19, 1.3179732316466649e-17, 1.0835445640249948e-15, 6.0495805864229647e-14, 2.3852254108327101e-12, 6.8487736158296791e-11, 1.4678463337326563e-09, 2.3957838556591937e-08, 3.0275650879319551e-07, 3.0032131335980235e-06, 2.3654729185615187e-05, 1.4937604708377004e-04, 7.6242846753152228e-04, 3.1668653729621131e-03, 1.0765666029311394e-02, 3.0093535038790555e-02, 6.9436105549292540e-02, 1.3264501499247186e-01, 2.1027400626010295e-01, 2.7705564403537380e-01, 3.0370259492878027e-01, 2.7705564403537380e-01, 2.1027400626010295e-01, 1.3264501499247186e-01, 6.9436105549292540e-02, 3.0093535038790555e-02, 1.0765666029311394e-02, 3.1668653729621131e-03, 7.6242846753152228e-04, 1.4937604708377004e-04, 2.3654729185615187e-05, 3.0032131335980235e-06, 3.0275650879319551e-07, 2.3957838556591937e-08, 1.4678463337326563e-09, 6.8487736158296791e-11, 2.3852254108327101e-12, 6.0495805864229647e-14, 1.0835445640249948e-15, 1.3179732316466649e-17, 1.0345305017520525e-19, 4.8919455331107564e-22, 1.2648661239395541e-24, 1.5468771288046908e-27, 7.0570663748570958e-31, 7.6617679179706699e-35, 6.3684623301529066e-40}, {9.6165697698301258e-41, 1.2653200760168758e-35, 1.2587808691128722e-31, 2.9626275871495710e-28, 2.5923371557456032e-25, 1.0706490586422193e-22, 2.4146919999727056e-20, 3.2782519697898691e-18, 2.8709892632049820e-16, 1.7073406733468467e-14, 7.1713449978551876e-13, 2.1943984676811026e-11, 5.0147398704735039e-10, 8.7334448358337394e-09, 1.1786188465819090e-07, 1.2498100284112936e-06, 1.0535444441825744e-05, 7.1294347272485073e-05, 3.9051617266315898e-04, 1.7435254219654911e-03, 6.3820594170464536e-03, 1.9246441370539501e-02, 4.8010306161295493e-02, 9.9382787160472649e-02, 1.7114652799601413e-01, 2.4564247050424473e-01, 2.9419908452729160e-01, 2.9419908452729160e-01, 2.4564247050424473e-01, 1.7114652799601413e-01, 9.9382787160472649e-02, 4.8010306161295493e-02, 1.9246441370539501e-02, 6.3820594170464536e-03, 1.7435254219654911e-03, 3.9051617266315898e-04, 7.1294347272485073e-05, 1.0535444441825744e-05, 1.2498100284112936e-06, 1.1786188465819090e-07, 8.7334448358337394e-09, 5.0147398704735039e-10, 2.1943984676811026e-11, 7.1713449978551876e-13, 1.7073406733468467e-14, 2.8709892632049820e-16, 3.2782519697898691e-18, 2.4146919999727056e-20, 1.0706490586422193e-22, 2.5923371557456032e-25, 2.9626275871495710e-28, 1.2587808691128722e-31, 1.2653200760168758e-35, 9.6165697698301258e-41}, {1.4501627690036662e-41, 2.0843249634724133e-36, 2.2371881417054147e-32, 5.6477366517509067e-29, 5.2828491369827090e-26, 2.3275184070080019e-23, 5.5924703344128403e-21, 8.0822735455939761e-19, 7.5316452507313807e-17, 4.7652984604189149e-15, 2.1297535284773726e-13, 6.9364439628016448e-12, 1.6879993347401012e-10, 3.1324958261028878e-09, 4.5081881972300138e-08, 5.1027034733995817e-07, 4.5962183144073910e-06, 3.3274977701846682e-05, 1.9525422369452320e-04, 9.3526439804451304e-04, 3.6789367196008232e-03, 1.1943896271882769e-02, 3.2137739232619873e-02, 7.1912783366758826e-02, 1.3418063914176925e-01, 2.0919736551904625e-01, 2.7291625193942631e-01, 2.9818072956643887e-01, 2.7291625193942631e-01, 2.0919736551904625e-01, 1.3418063914176925e-01, 7.1912783366758826e-02, 3.2137739232619873e-02, 1.1943896271882769e-02, 3.6789367196008232e-03, 9.3526439804451304e-04, 1.9525422369452320e-04, 3.3274977701846682e-05, 4.5962183144073910e-06, 5.1027034733995817e-07, 4.5081881972300138e-08, 3.1324958261028878e-09, 1.6879993347401012e-10, 6.9364439628016448e-12, 2.1297535284773726e-13, 4.7652984604189149e-15, 7.5316452507313807e-17, 8.0822735455939761e-19, 5.5924703344128403e-21, 2.3275184070080019e-23, 5.2828491369827090e-26, 5.6477366517509067e-29, 2.2371881417054147e-32, 2.0843249634724133e-36, 1.4501627690036662e-41}, {2.1839473796203715e-42, 3.4249840843882790e-37, 3.9621540898960065e-33, 1.0717993883210793e-29, 1.0706713589643687e-26, 5.0270999187295385e-24, 1.2855363897049299e-21, 1.9756668115390835e-19, 1.9569261785647621e-17, 1.3158561251396991e-15, 6.2504456297525029e-14, 2.1641925885012134e-12, 5.6013978504685036e-11, 1.1062006976882208e-09, 1.6954324255991913e-08, 2.0454464536460739e-07, 1.9657534004009810e-06, 1.5201081492284489e-05, 9.5395991047773378e-05, 4.8937293565704996e-04, 2.0647475636031381e-03, 7.2020522320410518e-03, 2.0858574140157814e-02, 5.0338397424815960e-02, 1.0151939271798682e-01, 1.7147724762127156e-01, 2.4298927099272355e-01, 2.8917508433514816e-01, 2.8917508433514816e-01, 2.4298927099272355e-01, 1.7147724762127156e-01, 1.0151939271798682e-01, 5.0338397424815960e-02, 2.0858574140157814e-02, 7.2020522320410518e-03, 2.0647475636031381e-03, 4.8937293565704996e-04, 9.5395991047773378e-05, 1.5201081492284489e-05, 1.9657534004009810e-06, 2.0454464536460739e-07, 1.6954324255991913e-08, 1.1062006976882208e-09, 5.6013978504685036e-11, 2.1641925885012134e-12, 6.2504456297525029e-14, 1.3158561251396991e-15, 1.9569261785647621e-17, 1.9756668115390835e-19, 1.2855363897049299e-21, 5.0270999187295385e-24, 1.0706713589643687e-26, 1.0717993883210793e-29, 3.9621540898960065e-33, 3.4249840843882790e-37, 2.1839473796203715e-42}, {3.2848343922234264e-43, 5.6145192176094857e-38, 6.9933335612180924e-34, 2.0251468211785233e-30, 2.1584037474070782e-27, 1.0789794198158127e-24, 2.9336812927661561e-22, 4.7897086011228863e-20, 5.0376705984946099e-18, 3.5961584198415702e-16, 1.8135512160129682e-14, 6.6680503871104131e-13, 1.8333727853050702e-11, 3.8483200507286178e-10, 6.2732332422802088e-09, 8.0560041690845556e-08, 8.2486418628805857e-07, 6.8030638512964077e-06, 4.5587459694050582e-05, 2.5003668451320217e-04, 1.1295333257645079e-03, 4.2250842236442390e-03, 1.3144726459581649e-02, 3.4139801128400288e-02, 7.4247675370613914e-02, 1.3553970687329148e-01, 2.0807036460654699e-01, 2.6895194980711801e-01, 2.9294948869685189e-01, 2.6895194980711801e-01, 2.0807036460654699e-01, 1.3553970687329148e-01, 7.4247675370613914e-02, 3.4139801128400288e-02, 1.3144726459581649e-02, 4.2250842236442390e-03, 1.1295333257645079e-03, 2.5003668451320217e-04, 4.5587459694050582e-05, 6.8030638512964077e-06, 8.2486418628805857e-07, 8.0560041690845556e-08, 6.2732332422802088e-09, 3.8483200507286178e-10, 1.8333727853050702e-11, 6.6680503871104131e-13, 1.8135512160129682e-14, 3.5961584198415702e-16, 5.0376705984946099e-18, 4.7897086011228863e-20, 2.9336812927661561e-22, 1.0789794198158127e-24, 2.1584037474070782e-27, 2.0251468211785233e-30, 6.9933335612180924e-34, 5.6145192176094857e-38, 3.2848343922234264e-43}, {4.9345427975166703e-44, 9.1824526100660134e-39, 1.2302868650409080e-34, 3.8103303738430430e-31, 4.3288355988163862e-28, 2.3018029777481733e-25, 6.6480276615029978e-23, 1.1519651049881098e-20, 1.2852645022546249e-18, 9.7305218355116897e-17, 5.2042716465726346e-15, 2.0297402247949017e-13, 5.9217773854289703e-12, 1.3196011058824996e-10, 2.2850766766300011e-09, 3.1195246571716635e-08, 3.3984745324530809e-07, 2.9851306091787731e-06, 2.1327339454200749e-05, 1.2486893055641099e-04, 6.0296061313673489e-04, 2.4143454547297083e-03, 8.0534582747568747e-03, 2.2465314158278335e-02, 5.2574374089316610e-02, 1.0348723259331935e-01, 1.7168192789310016e-01, 2.4039805219536928e-01, 2.8439970531426456e-01, 2.8439970531426456e-01, 2.4039805219536928e-01, 1.7168192789310016e-01, 1.0348723259331935e-01, 5.2574374089316610e-02, 2.2465314158278335e-02, 8.0534582747568747e-03, 2.4143454547297083e-03, 6.0296061313673489e-04, 1.2486893055641099e-04, 2.1327339454200749e-05, 2.9851306091787731e-06, 3.3984745324530809e-07, 3.1195246571716635e-08, 2.2850766766300011e-09, 1.3196011058824996e-10, 5.9217773854289703e-12, 2.0297402247949017e-13, 5.2042716465726346e-15, 9.7305218355116897e-17, 1.2852645022546249e-18, 1.1519651049881098e-20, 6.6480276615029978e-23, 2.3018029777481733e-25, 4.3288355988163862e-28, 3.8103303738430430e-31, 1.2302868650409080e-34, 9.1824526100660134e-39, 4.9345427975166703e-44}, {7.4038563068673450e-45, 1.4983962534795572e-39, 2.1574506027269642e-35, 7.1398344998607888e-32, 8.6385560494218303e-29, 4.8816444464632883e-26, 1.4963121942445614e-23, 2.7492726789010400e-21, 3.2508143970587746e-19, 2.6076354448061946e-17, 1.4776310161414783e-15, 6.1066717751743867e-14, 1.8884472351365658e-12, 4.4624672633249920e-11, 8.1989628692240572e-10, 1.1884210228039399e-08, 1.3757431403862670e-07, 1.2852403270784334e-06, 9.7761956199732341e-06, 6.1008880084875632e-05, 3.1439538907451493e-04, 1.3453332060777454e-03, 4.8029120328152543e-03, 1.4362559357587188e-02, 3.6095769719147547e-02, 7.6447309674074940e-02, 1.3673928335964028e-01, 2.0690383287647826e-01, 2.6515118763397444e-01, 2.8798424312571891e-01, 2.6515118763397444e-01, 2.0690383287647826e-01, 1.3673928335964028e-01, 7.6447309674074940e-02, 3.6095769719147547e-02, 1.4362559357587188e-02, 4.8029120328152543e-03, 1.3453332060777454e-03, 3.1439538907451493e-04, 6.1008880084875632e-05, 9.7761956199732341e-06, 1.2852403270784334e-06, 1.3757431403862670e-07, 1.1884210228039399e-08, 8.1989628692240572e-10, 4.4624672633249920e-11, 1.8884472351365658e-12, 6.1066717751743867e-14, 1.4776310161414783e-15, 2.6076354448061946e-17, 3.2508143970587746e-19, 2.7492726789010400e-21, 1.4963121942445614e-23, 4.8816444464632883e-26, 8.6385560494218303e-29, 7.1398344998607888e-32, 2.1574506027269642e-35, 1.4983962534795572e-39, 7.4038563068673450e-45}, {1.1095872479683389e-45, 2.4397475881451687e-40, 3.7716267271207567e-36, 1.3325596117642357e-32, 1.7155731476717639e-29, 1.0294059971650915e-26, 3.3457569557525580e-24, 6.5125672574964802e-22, 8.1536404730238284e-20, 6.9232479095776861e-18, 4.1524441096940554e-16, 1.8166245762596555e-14, 5.9484305160561044e-13, 1.4889573490628030e-11, 2.8993590128077474e-10, 4.4568227752259551e-09, 5.4755546192766962e-08, 5.4335161342049202e-07, 4.3942869362670327e-06, 2.9187419041555301e-05, 1.6027733468184521e-04, 7.3177355696550823e-04, 2.7913248289530633e-03, 8.9321783603078207e-03, 2.4061272766109355e-02, 5.4718970932182816e-02, 1.0529876369778575e-01, 1.7177615691888495e-01, 2.3786890495865878e-01, 2.7985311752282899e-01, 2.7985311752282899e-01, 2.3786890495865878e-01, 1.7177615691888495e-01, 1.0529876369778575e-01, 5.4718970932182816e-02, 2.4061272766109355e-02, 8.9321783603078207e-03, 2.7913248289530633e-03, 7.3177355696550823e-04, 1.6027733468184521e-04, 2.9187419041555301e-05, 4.3942869362670327e-06, 5.4335161342049202e-07, 5.4755546192766962e-08, 4.4568227752259551e-09, 2.8993590128077474e-10, 1.4889573490628030e-11, 5.9484305160561044e-13, 1.8166245762596555e-14, 4.1524441096940554e-16, 6.9232479095776861e-18, 8.1536404730238284e-20, 6.5125672574964802e-22, 3.3457569557525580e-24, 1.0294059971650915e-26, 1.7155731476717639e-29, 1.3325596117642357e-32, 3.7716267271207567e-36, 2.4397475881451687e-40, 1.1095872479683389e-45}, {1.6610070486206728e-46, 3.9640620009950677e-41, 6.5736876067220763e-37, 2.4774746124224036e-33, 3.3910839755167296e-30, 2.1587655850502334e-27, 7.4335800238463694e-25, 1.5315980968945761e-22, 2.0285571447032586e-20, 1.8216160573946239e-18, 1.1553699025986796e-16, 5.3454835391987630e-15, 1.8515162945489592e-13, 4.9041814317738659e-12, 1.0110041892763622e-10, 1.6462612023799091e-09, 2.1440032177267756e-08, 2.2570860520414515e-07, 1.9382734960996544e-06, 1.3684069297535329e-05, 7.9958097609494878e-05, 3.8892085371592777e-04, 1.5825583090958971e-03, 5.4099296624677247e-03, 1.5592290312662006e-02, 3.8002651439240136e-02, 7.8518270158397185e-02, 1.3779465152760539e-01, 2.0570683105394089e-01, 2.6150339781427412e-01, 2.8326318995972372e-01, 2.6150339781427412e-01, 2.0570683105394089e-01, 1.3779465152760539e-01, 7.8518270158397185e-02, 3.8002651439240136e-02, 1.5592290312662006e-02, 5.4099296624677247e-03, 1.5825583090958971e-03, 3.8892085371592777e-04, 7.9958097609494878e-05, 1.3684069297535329e-05, 1.9382734960996544e-06, 2.2570860520414515e-07, 2.1440032177267756e-08, 1.6462612023799091e-09, 1.0110041892763622e-10, 4.9041814317738659e-12, 1.8515162945489592e-13, 5.3454835391987630e-15, 1.1553699025986796e-16, 1.8216160573946239e-18, 2.0285571447032586e-20, 1.5315980968945761e-22, 7.4335800238463694e-25, 2.1587655850502334e-27, 3.3910839755167296e-30, 2.4774746124224036e-33, 6.5736876067220763e-37, 3.9640620009950677e-41, 1.6610070486206728e-46}, {2.4837138180536654e-47, 6.4274569671736483e-42, 1.1424028966725505e-37, 4.5888574043976661e-34, 6.6725110959391675e-31, 4.5029239074522869e-28, 1.6414116353925588e-25, 3.5767852999576706e-23, 5.0073739324943669e-21, 4.7513038441234886e-19, 3.1838887747718650e-17, 1.5564176512276732e-15, 5.6970949884188746e-14, 1.5952148801760892e-12, 3.4779437587729222e-11, 5.9926928642653631e-10, 8.2638647618516911e-09, 9.2185737335790556e-08, 8.3956368818335782e-07, 6.2919256841286273e-06, 3.9066932688710276e-05, 2.0215217999457319e-04, 8.7616004129601344e-04, 3.1945104951283309e-03, 9.8342822671495106e-03, 2.5641844544669879e-02, 5.6773556441129344e-02, 1.0696556035928920e-01, 1.7177351127893237e-01, 2.3540141376649018e-01, 2.7551763457131306e-01, 2.7551763457131306e-01, 2.3540141376649018e-01, 1.7177351127893237e-01, 1.0696556035928920e-01, 5.6773556441129344e-02, 2.5641844544669879e-02, 9.8342822671495106e-03, 3.1945104951283309e-03, 8.7616004129601344e-04, 2.0215217999457319e-04, 3.9066932688710276e-05, 6.2919256841286273e-06, 8.3956368818335782e-07, 9.2185737335790556e-08, 8.2638647618516911e-09, 5.9926928642653631e-10, 3.4779437587729222e-11, 1.5952148801760892e-12, 5.6970949884188746e-14, 1.5564176512276732e-15, 3.1838887747718650e-17, 4.7513038441234886e-19, 5.0073739324943669e-21, 3.5767852999576706e-23, 1.6414116353925588e-25, 4.5029239074522869e-28, 6.6725110959391675e-31, 4.5888574043976661e-34, 1.1424028966725505e-37, 6.4274569671736483e-42, 2.4837138180536654e-47}, {3.7099206361930349e-48, 1.0400778615224128e-42, 1.9796804708319897e-38, 8.4687478191905945e-35, 1.3071305930820806e-31, 9.3437837175659029e-29, 3.6027426635285024e-26, 8.2963863116210883e-24, 1.2266629909143781e-21, 1.2288435628835336e-19, 8.6925536958459408e-18, 4.4857058689315790e-16, 1.7335817955789140e-14, 5.1265062385198317e-13, 1.1808921844569749e-11, 2.1508698297874976e-10, 3.1371929535383148e-09, 3.7041625984897139e-08, 3.5734732949990906e-07, 2.8393114498469317e-06, 1.8709113003788699e-05, 1.0284880800685653e-04, 4.7411702610320811e-04, 1.8409222622442125e-03, 6.0436044551375788e-03, 1.6829299199652096e-02, 3.9858264027817066e-02, 8.0467087994200825e-02, 1.3871950817658463e-01, 2.0448695346897386e-01, 2.5799889943138321e-01, 2.7876694884925185e-01, 2.5799889943138321e-01, 2.0448695346897386e-01, 1.3871950817658463e-01, 8.0467087994200825e-02, 3.9858264027817066e-02, 1.6829299199652096e-02, 6.0436044551375788e-03, 1.8409222622442125e-03, 4.7411702610320811e-04, 1.0284880800685653e-04, 1.8709113003788699e-05, 2.8393114498469317e-06, 3.5734732949990906e-07, 3.7041625984897139e-08, 3.1371929535383148e-09, 2.1508698297874976e-10, 1.1808921844569749e-11, 5.1265062385198317e-13, 1.7335817955789140e-14, 4.4857058689315790e-16, 8.6925536958459408e-18, 1.2288435628835336e-19, 1.2266629909143781e-21, 8.2963863116210883e-24, 3.6027426635285024e-26, 9.3437837175659029e-29, 1.3071305930820806e-31, 8.4687478191905945e-35, 1.9796804708319897e-38, 1.0400778615224128e-42, 3.7099206361930349e-48}, {5.5357065358570184e-49, 1.6797479901081275e-43, 3.4211380112558623e-39, 1.5573906246297621e-35, 2.5496608991129390e-32, 1.9291035954649827e-29, 7.8617977889259561e-27, 1.9117068833006383e-24, 2.9828627842798555e-22, 3.1522545665038165e-20, 2.3518847106758435e-18, 1.2800933913224359e-16, 5.2186237265908379e-15, 1.6283407307097284e-13, 3.9591777669477542e-12, 7.6152172501454727e-11, 1.1736167423215493e-09, 1.4651253164761138e-08, 1.4955329367272515e-07, 1.2583402510311900e-06, 8.7884992308503793e-06, 5.1259291357862856e-05, 2.5098369851306242e-04, 1.0363290995075809e-03, 3.6225869785344623e-03, 1.0756040509879146e-02, 2.7203128953688913e-02, 5.8739981964099283e-02, 1.0849834930618682e-01, 1.7168584234908363e-01, 2.3299478606267793e-01, 2.7137742494130401e-01, 2.7137742494130401e-01, 2.3299478606267793e-01, 1.7168584234908363e-01, 1.0849834930618682e-01, 5.8739981964099283e-02, 2.7203128953688913e-02, 1.0756040509879146e-02, 3.6225869785344623e-03, 1.0363290995075809e-03, 2.5098369851306242e-04, 5.1259291357862856e-05, 8.7884992308503793e-06, 1.2583402510311900e-06, 1.4955329367272515e-07, 1.4651253164761138e-08, 1.1736167423215493e-09, 7.6152172501454727e-11, 3.9591777669477542e-12, 1.6283407307097284e-13, 5.2186237265908379e-15, 1.2800933913224359e-16, 2.3518847106758435e-18, 3.1522545665038165e-20, 2.9828627842798555e-22, 1.9117068833006383e-24, 7.8617977889259561e-27, 1.9291035954649827e-29, 2.5496608991129390e-32, 1.5573906246297621e-35, 3.4211380112558623e-39, 1.6797479901081275e-43, 5.5357065358570184e-49}, {8.2516107962538437e-50, 2.7076758452831307e-44, 5.8962844659788279e-40, 2.8541849032786616e-36, 4.9525862550205175e-33, 3.9632869870747322e-30, 1.7059115810757949e-27, 4.3769741948718935e-25, 7.2016107891350715e-23, 8.0222187354240242e-21, 6.3078910455861518e-19, 3.6181996190429121e-17, 1.5546635722380968e-15, 5.1139174817165822e-14, 1.3112516106390246e-12, 2.6608653477929730e-11, 4.3286561534485417e-10, 5.7075829327787572e-09, 6.1577962214505752e-08, 5.4804560350180002e-07, 4.0522493910237441e-06, 2.5045342890495838e-05, 1.3008291629845118e-04, 5.7039896752377221e-04, 2.1199816320368434e-03, 6.7014045380057391e-03, 1.8069433112703592e-02, 4.1661108762478506e-02, 8.2300163369735294e-02, 1.3952613948284390e-01, 2.0325057415444170e-01, 2.5462881185279007e-01, 2.7447822655926341e-01, 2.5462881185279007e-01, 2.0325057415444170e-01, 1.3952613948284390e-01, 8.2300163369735294e-02, 4.1661108762478506e-02, 1.8069433112703592e-02, 6.7014045380057391e-03, 2.1199816320368434e-03, 5.7039896752377221e-04, 1.3008291629845118e-04, 2.5045342890495838e-05, 4.0522493910237441e-06, 5.4804560350180002e-07, 6.1577962214505752e-08, 5.7075829327787572e-09, 4.3286561534485417e-10, 2.6608653477929730e-11, 1.3112516106390246e-12, 5.1139174817165822e-14, 1.5546635722380968e-15, 3.6181996190429121e-17, 6.3078910455861518e-19, 8.0222187354240242e-21, 7.2016107891350715e-23, 4.3769741948718935e-25, 1.7059115810757949e-27, 3.9632869870747322e-30, 4.9525862550205175e-33, 2.8541849032786616e-36, 5.8962844659788279e-40, 2.7076758452831307e-44, 8.2516107962538437e-50}, {1.2287768797135238e-50, 4.3565748909654033e-45, 1.0135609150438053e-40, 5.2133092407201474e-37, 9.5811571508986169e-34, 8.1036840367508257e-31, 3.6813492354788247e-28, 9.9592645616067056e-26, 1.7266548206330479e-23, 2.0259038600763283e-21, 1.6775151863814584e-19, 1.0132362352411122e-17, 4.5848634437116816e-16, 1.5885532676287405e-14, 4.2916420558156765e-13, 9.1795670585092616e-12, 1.5747988216738595e-10, 2.1910095676436381e-09, 2.4958591861839229e-08, 2.3470996573719479e-07, 1.8351979221091958e-06, 1.2005278344250187e-05, 6.6061130219886947e-05, 3.0721561121964142e-04, 1.2123596600232957e-03, 4.0741349478589858e-03, 1.1693944851274627e-02, 2.8741855098732765e-02, 6.0620459149597836e-02, 1.0990705313380535e-01, 1.7152351798443127e-01, 2.3064795199119065e-01, 2.6741826939146512e-01, 2.6741826939146512e-01, 2.3064795199119065e-01, 1.7152351798443127e-01, 1.0990705313380535e-01, 6.0620459149597836e-02, 2.8741855098732765e-02, 1.1693944851274627e-02, 4.0741349478589858e-03, 1.2123596600232957e-03, 3.0721561121964142e-04, 6.6061130219886947e-05, 1.2005278344250187e-05, 1.8351979221091958e-06, 2.3470996573719479e-07, 2.4958591861839229e-08, 2.1910095676436381e-09, 1.5747988216738595e-10, 9.1795670585092616e-12, 4.2916420558156765e-13, 1.5885532676287405e-14, 4.5848634437116816e-16, 1.0132362352411122e-17, 1.6775151863814584e-19, 2.0259038600763283e-21, 1.7266548206330479e-23, 9.9592645616067056e-26, 3.6813492354788247e-28, 8.1036840367508257e-31, 9.5811571508986169e-34, 5.2133092407201474e-37, 1.0135609150438053e-40, 4.3565748909654033e-45, 1.2287768797135238e-50}, {1.8280449098224982e-51, 6.9969776104465074e-46, 1.7378601313821812e-41, 9.4914073654790101e-38, 1.8462398438517290e-34, 1.6492772853150654e-31, 7.9020561032723045e-29, 2.2524636987884908e-26, 4.1119507972824725e-24, 5.0779932729853307e-22, 4.4245805201641825e-20, 2.8120140377689001e-18, 1.3389362360428643e-16, 4.8824398317753951e-15, 1.3886060911907966e-13, 3.1279303248480510e-12, 5.6537332414960619e-11, 8.2920364429410743e-10, 9.9634336551576826e-09, 9.8898818048931736e-08, 8.1685444112022656e-07, 5.6493811974978918e-06, 3.2895750894750603e-05, 1.6204473635815332e-04, 6.7809290318947399e-04, 2.4191591440605796e-03, 7.3808332831545517e-03, 1.9308982903048826e-02, 4.3410259562275427e-02, 8.4023710374037747e-02, 1.4022557730554358e-01, 2.0200304815121278e-01, 2.5138497704677004e-01, 2.7038153661061759e-01, 2.5138497704677004e-01, 2.0200304815121278e-01, 1.4022557730554358e-01, 8.4023710374037747e-02, 4.3410259562275427e-02, 1.9308982903048826e-02, 7.3808332831545517e-03, 2.4191591440605796e-03, 6.7809290318947399e-04, 1.6204473635815332e-04, 3.2895750894750603e-05, 5.6493811974978918e-06, 8.1685444112022656e-07, 9.8898818048931736e-08, 9.9634336551576826e-09, 8.2920364429410743e-10, 5.6537332414960619e-11, 3.1279303248480510e-12, 1.3886060911907966e-13, 4.8824398317753951e-15, 1.3389362360428643e-16, 2.8120140377689001e-18, 4.4245805201641825e-20, 5.0779932729853307e-22, 4.1119507972824725e-24, 2.2524636987884908e-26, 7.9020561032723045e-29, 1.6492772853150654e-31, 1.8462398438517290e-34, 9.4914073654790101e-38, 1.7378601313821812e-41, 6.9969776104465074e-46, 1.8280449098224982e-51}, {2.7170067116730165e-52, 1.1217925177026293e-46, 2.9723642655668546e-42, 1.7225457466828413e-38, 3.5439568636689488e-35, 3.3415178524750795e-32, 1.6874060730443393e-29, 5.0645263679858964e-27, 9.7283658177698223e-25, 1.2635945997114491e-22, 1.1577247535043669e-20, 7.7362132775431355e-19, 3.8731516902515290e-17, 1.4852494321530914e-15, 4.4433093884802028e-14, 1.0531630647084200e-12, 2.0038587880644725e-11, 3.0952986928769617e-10, 3.9193048318854111e-09, 4.1023319776043747e-08, 3.5754993018691617e-07, 2.6114965376035973e-06, 1.6073154232928773e-05, 8.3767928571091071e-05, 3.7124104714178821e-04, 1.4042112162131032e-03, 4.5476632686124660e-03, 1.2644719871722365e-02, 3.0255311010248965e-02, 6.2417460794691487e-02, 1.1120083831262205e-01, 1.7129562704597320e-01, 2.2835964147332644e-01, 2.6362735600964210e-01, 2.6362735600964210e-01, 2.2835964147332644e-01, 1.7129562704597320e-01, 1.1120083831262205e-01, 6.2417460794691487e-02, 3.0255311010248965e-02, 1.2644719871722365e-02, 4.5476632686124660e-03, 1.4042112162131032e-03, 3.7124104714178821e-04, 8.3767928571091071e-05, 1.6073154232928773e-05, 2.6114965376035973e-06, 3.5754993018691617e-07, 4.1023319776043747e-08, 3.9193048318854111e-09, 3.0952986928769617e-10, 2.0038587880644725e-11, 1.0531630647084200e-12, 4.4433093884802028e-14, 1.4852494321530914e-15, 3.8731516902515290e-17, 7.7362132775431355e-19, 1.1577247535043669e-20, 1.2635945997114491e-22, 9.7283658177698223e-25, 5.0645263679858964e-27, 1.6874060730443393e-29, 3.3415178524750795e-32, 3.5439568636689488e-35, 1.7225457466828413e-38, 2.9723642655668546e-42, 1.1217925177026293e-46, 2.7170067116730165e-52}, {4.0345457983197185e-53, 1.7954384298058220e-47, 5.0715303590978945e-43, 3.1165183087668226e-39, 6.7773962594083074e-36, 6.7403932258482419e-33, 3.5851439372856567e-30, 1.1322450883416873e-27, 2.2869723112554000e-25, 3.1221586704548222e-23, 3.0058381695419005e-21, 2.1103468793130292e-19, 1.1100994988590987e-17, 4.4732478501982463e-16, 1.4065409569369246e-14, 3.5050786947688594e-13, 7.0144682351913210e-12, 1.1401392553489413e-10, 1.5199381740983112e-09, 1.6759992864221019e-08, 1.5399292502874990e-07, 1.1865872353918687e-06, 7.7110412769679424e-06, 4.2469576433922949e-05, 1.9909609055329152e-04, 7.9743820114063489e-04, 2.7377658998792736e-03, 8.0794563303749761e-03, 2.0544655922552182e-02, 4.5105267291699995e-02, 8.5643719556781017e-02, 1.4082773794401451e-01, 2.0074887688731419e-01, 2.4825988992112150e-01, 2.6646296361626087e-01, 2.4825988992112150e-01, 2.0074887688731419e-01, 1.4082773794401451e-01, 8.5643719556781017e-02, 4.5105267291699995e-02, 2.0544655922552182e-02, 8.0794563303749761e-03, 2.7377658998792736e-03, 7.9743820114063489e-04, 1.9909609055329152e-04, 4.2469576433922949e-05, 7.7110412769679424e-06, 1.1865872353918687e-06, 1.5399292502874990e-07, 1.6759992864221019e-08, 1.5199381740983112e-09, 1.1401392553489413e-10, 7.0144682351913210e-12, 3.5050786947688594e-13, 1.4065409569369246e-14, 4.4732478501982463e-16, 1.1100994988590987e-17, 2.1103468793130292e-19, 3.0058381695419005e-21, 3.1221586704548222e-23, 2.2869723112554000e-25, 1.1322450883416873e-27, 3.5851439372856567e-30, 6.7403932258482419e-33, 6.7773962594083074e-36, 3.1165183087668226e-39, 5.0715303590978945e-43, 1.7954384298058220e-47, 4.0345457983197185e-53}, {5.9856092466933942e-54, 2.8688168912332612e-48, 8.6328113687066931e-44, 5.6216222243961033e-40, 1.2913788025337670e-36, 1.3538428107777088e-33, 7.5798318604310986e-31, 2.5172693785018537e-28, 5.3430216209626571e-26, 7.6615923972613038e-24, 7.7454736745174986e-22, 5.7095124323046545e-20, 3.1533210598724162e-18, 1.3342434681247850e-16, 4.4061175397950322e-15, 1.1534952560183679e-13, 2.4259623022354819e-12, 4.1457910332486197e-11, 5.8137344484280929e-10, 6.7473312881324816e-09, 6.5292934189484169e-08, 5.3024856335051780e-07, 3.6344904047182492e-06, 2.1131233267306212e-05, 1.0466994285006789e-04, 4.4339999663332603e-04, 1.6117353953558448e-03, 5.0416367476379337e-03, 1.3605327560618538e-02, 3.1741278190050709e-02, 6.4133640985369098e-02, 1.1238816501981971e-01, 1.7101015293603891e-01, 2.2612844383734518e-01, 2.5999310620316046e-01, 2.5999310620316046e-01, 2.2612844383734518e-01, 1.7101015293603891e-01, 1.1238816501981971e-01, 6.4133640985369098e-02, 3.1741278190050709e-02, 1.3605327560618538e-02, 5.0416367476379337e-03, 1.6117353953558448e-03, 4.4339999663332603e-04, 1.0466994285006789e-04, 2.1131233267306212e-05, 3.6344904047182492e-06, 5.3024856335051780e-07, 6.5292934189484169e-08, 6.7473312881324816e-09, 5.8137344484280929e-10, 4.1457910332486197e-11, 2.4259623022354819e-12, 1.1534952560183679e-13, 4.4061175397950322e-15, 1.3342434681247850e-16, 3.1533210598724162e-18, 5.7095124323046545e-20, 7.7454736745174986e-22, 7.6615923972613038e-24, 5.3430216209626571e-26, 2.5172693785018537e-28, 7.5798318604310986e-31, 1.3538428107777088e-33, 1.2913788025337670e-36, 5.6216222243961033e-40, 8.6328113687066931e-44, 2.8688168912332612e-48, 5.9856092466933942e-54}, {8.8724008630942898e-55, 4.5764336789075590e-49, 1.4661118038718265e-44, 1.0110662325251453e-40, 2.4518913381167023e-37, 2.7079520650401302e-34, 1.5949041770861358e-31, 5.5663539164360154e-29, 1.2407683405472676e-26, 1.8675901831656063e-24, 1.9812686302523555e-22, 1.5323733317270031e-20, 8.8796168315044913e-19, 3.9423704233496054e-17, 1.3663145902821194e-15, 3.7548696680658361e-14, 8.2926419028182389e-13, 1.4887527478920644e-11, 2.1942330999743630e-10, 2.6779761171072075e-09, 2.7267833016134243e-08, 2.3316541347245123e-07, 1.6840172739131284e-06, 1.0325059077129107e-05, 5.3979561403797981e-05, 2.4157232920980263e-04, 9.2859086457657155e-04, 3.0750221611855083e-03, 8.7949222136699829e-03, 2.1773546737772456e-02, 4.6746077576099838e-02, 8.7165933915876653e-02, 1.4134154505606342e-01, 1.9949184460058894e-01, 2.4524663594920437e-01, 2.6270996412870795e-01, 2.4524663594920437e-01, 1.9949184460058894e-01, 1.4134154505606342e-01, 8.7165933915876653e-02, 4.6746077576099838e-02, 2.1773546737772456e-02, 8.7949222136699829e-03, 3.0750221611855083e-03, 9.2859086457657155e-04, 2.4157232920980263e-04, 5.3979561403797981e-05, 1.0325059077129107e-05, 1.6840172739131284e-06, 2.3316541347245123e-07, 2.7267833016134243e-08, 2.6779761171072075e-09, 2.1942330999743630e-10, 1.4887527478920644e-11, 8.2926419028182389e-13, 3.7548696680658361e-14, 1.3663145902821194e-15, 3.9423704233496054e-17, 8.8796168315044913e-19, 1.5323733317270031e-20, 1.9812686302523555e-22, 1.8675901831656063e-24, 1.2407683405472676e-26, 5.5663539164360154e-29, 1.5949041770861358e-31, 2.7079520650401302e-34, 2.4518913381167023e-37, 1.0110662325251453e-40, 1.4661118038718265e-44, 4.5764336789075590e-49, 8.8724008630942898e-55}, {1.3140200635759138e-55, 7.2888760600699374e-50, 2.4843223778452137e-45, 1.8132393982490279e-41, 4.6392142210443241e-38, 5.3944805170903356e-35, 3.3402996562304201e-32, 1.2244058147622891e-29, 2.8644542990100537e-27, 4.5229388132654362e-25, 5.0319775906458023e-23, 4.0808135693241622e-21, 2.4793963766166604e-19, 1.1542667556483506e-17, 4.1953024073558444e-16, 1.2094094650388391e-14, 2.8026693289669983e-13, 5.2816149659273362e-12, 8.1749589868013172e-11, 1.0483088420892190e-09, 1.1221758911496157e-08, 1.0094315168892042e-07, 7.6747273751899334e-07, 4.9572490208738044e-06, 2.7325285268221331e-05, 1.2904853700328517e-04, 5.2397811821303173e-04, 1.8346879155592502e-03, 5.5544997811365557e-03, 1.4572966566065007e-02, 3.3197971745097789e-02, 6.5771771087721614e-02, 1.1347683695023611e-01, 1.7067412122709255e-01, 2.2395285395671372e-01, 2.5650502626034899e-01, 2.5650502626034899e-01, 2.2395285395671372e-01, 1.7067412122709255e-01, 1.1347683695023611e-01, 6.5771771087721614e-02, 3.3197971745097789e-02, 1.4572966566065007e-02, 5.5544997811365557e-03, 1.8346879155592502e-03, 5.2397811821303173e-04, 1.2904853700328517e-04, 2.7325285268221331e-05, 4.9572490208738044e-06, 7.6747273751899334e-07, 1.0094315168892042e-07, 1.1221758911496157e-08, 1.0483088420892190e-09, 8.1749589868013172e-11, 5.2816149659273362e-12, 2.8026693289669983e-13, 1.2094094650388391e-14, 4.1953024073558444e-16, 1.1542667556483506e-17, 2.4793963766166604e-19, 4.0808135693241622e-21, 5.0319775906458023e-23, 4.5229388132654362e-25, 2.8644542990100537e-27, 1.2244058147622891e-29, 3.3402996562304201e-32, 5.3944805170903356e-35, 4.6392142210443241e-38, 1.8132393982490279e-41, 2.4843223778452137e-45, 7.2888760600699374e-50, 1.3140200635759138e-55}, {1.9444622230234342e-56, 1.1590959320007943e-50, 4.2004740254236363e-46, 3.2427888315124139e-42, 8.7482381269078278e-39, 1.0703814562172511e-35, 6.9640785632250250e-33, 2.6794918791965289e-30, 6.5751748013020018e-28, 1.0884570120961755e-25, 1.2691625603633038e-23, 1.0785433636173751e-21, 6.8663309606135431e-20, 3.3495959873429566e-18, 1.2758954586949696e-16, 3.8555242748433330e-15, 9.3683796134838034e-14, 1.8518064702871477e-12, 3.0076840393622017e-11, 4.0491316393465588e-10, 4.5529601729418187e-09, 4.3045713494096147e-08, 3.4420843484101099e-07, 2.3399997161498497e-06, 1.3586053874631190e-05, 6.7639272623934896e-05, 2.8977924888595573e-04, 1.0716281610696826e-03, 3.4300764387647066e-03, 9.5249775695009746e-03, 2.2993107110436964e-02, 4.8332960504809425e-02, 8.8595835021937436e-02, 1.4177503840549346e-01, 1.9823513131250983e-01, 2.4233883536068279e-01, 2.5911119749680783e-01, 2.4233883536068279e-01, 1.9823513131250983e-01, 1.4177503840549346e-01, 8.8595835021937436e-02, 4.8332960504809425e-02, 2.2993107110436964e-02, 9.5249775695009746e-03, 3.4300764387647066e-03, 1.0716281610696826e-03, 2.8977924888595573e-04, 6.7639272623934896e-05, 1.3586053874631190e-05, 2.3399997161498497e-06, 3.4420843484101099e-07, 4.3045713494096147e-08, 4.5529601729418187e-09, 4.0491316393465588e-10, 3.0076840393622017e-11, 1.8518064702871477e-12, 9.3683796134838034e-14, 3.8555242748433330e-15, 1.2758954586949696e-16, 3.3495959873429566e-18, 6.8663309606135431e-20, 1.0785433636173751e-21, 1.2691625603633038e-23, 1.0884570120961755e-25, 6.5751748013020018e-28, 2.6794918791965289e-30, 6.9640785632250250e-33, 1.0703814562172511e-35, 8.7482381269078278e-39, 3.2427888315124139e-42, 4.2004740254236363e-46, 1.1590959320007943e-50, 1.9444622230234342e-56}, {2.8750275727924455e-57, 1.8404303463880958e-51, 7.0869721836637015e-47, 5.7836152624626662e-43, 1.6442414677949876e-39, 2.1156822123723002e-36, 1.4455024437001548e-33, 5.8345675304162565e-31, 1.5008973228057372e-28, 2.6033049503053747e-26, 3.1794998286708481e-24, 2.8296018603048517e-22, 1.8863727782270500e-20, 9.6365678168475681e-19, 3.8443430855465295e-17, 1.2168900581339222e-15, 3.0981886195643928e-14, 6.4188571380482567e-13, 1.0931590521335809e-11, 1.5438256127811863e-10, 1.8219509376836273e-09, 1.8089441547445238e-08, 1.5199860776329110e-07, 1.0865550828327965e-06, 6.6384540614267379e-06, 3.4806103755504017e-05, 1.5717296348585755e-04, 6.1320670594855193e-04, 2.0727405318696742e-03, 6.0846962089377739e-03, 1.5545067446090813e-02, 3.4623986133714632e-02, 6.7334688728284187e-02, 1.1447404988622129e-01, 1.7029372558220210e-01, 2.2183130791546488e-01, 2.5315358016164968e-01, 2.5315358016164968e-01, 2.2183130791546488e-01, 1.7029372558220210e-01, 1.1447404988622129e-01, 6.7334688728284187e-02, 3.4623986133714632e-02, 1.5545067446090813e-02, 6.0846962089377739e-03, 2.0727405318696742e-03, 6.1320670594855193e-04, 1.5717296348585755e-04, 3.4806103755504017e-05, 6.6384540614267379e-06, 1.0865550828327965e-06, 1.5199860776329110e-07, 1.8089441547445238e-08, 1.8219509376836273e-09, 1.5438256127811863e-10, 1.0931590521335809e-11, 6.4188571380482567e-13, 3.0981886195643928e-14, 1.2168900581339222e-15, 3.8443430855465295e-17, 9.6365678168475681e-19, 1.8863727782270500e-20, 2.8296018603048517e-22, 3.1794998286708481e-24, 2.6033049503053747e-26, 1.5008973228057372e-28, 5.8345675304162565e-31, 1.4455024437001548e-33, 2.1156822123723002e-36, 1.6442414677949876e-39, 5.7836152624626662e-43, 7.0869721836637015e-47, 1.8404303463880958e-51, 2.8750275727924455e-57}, {4.2475403944235563e-58, 2.9179360026092975e-52, 1.1932102199256711e-47, 1.0287869477179010e-43, 3.0804483195558287e-40, 4.1660662393372492e-37, 2.9874354212480538e-34, 1.2642951712027768e-31, 3.4074887052468082e-29, 6.1891475308279466e-27, 7.9129760878551264e-25, 7.3704570195170156e-23, 5.1421792395941592e-21, 2.7491455795179009e-19, 1.1478770068871720e-17, 3.8036255791351365e-16, 1.0139883410013013e-14, 2.2003659842875677e-13, 3.9263803072919160e-12, 5.8125114501326569e-11, 7.1939577649798698e-10, 7.4947098368604126e-09, 6.6118669991811844e-08, 4.9655916977568413e-07, 3.1895150634568674e-06, 1.7594600636505465e-05, 8.3660559585237938e-05, 3.4399085887424382e-04, 1.2265540580803703e-03, 3.8020227522452721e-03, 1.0267477817470316e-02, 2.4201116175054306e-02, 4.9866450712457495e-02, 8.9938636734284719e-02, 1.4213547000895149e-01, 1.9698140672796691e-01, 2.3953059321276829e-01, 2.5565638153018372e-01, 2.3953059321276829e-01, 1.9698140672796691e-01, 1.4213547000895149e-01, 8.9938636734284719e-02, 4.9866450712457495e-02, 2.4201116175054306e-02, 1.0267477817470316e-02, 3.8020227522452721e-03, 1.2265540580803703e-03, 3.4399085887424382e-04, 8.3660559585237938e-05, 1.7594600636505465e-05, 3.1895150634568674e-06, 4.9655916977568413e-07, 6.6118669991811844e-08, 7.4947098368604126e-09, 7.1939577649798698e-10, 5.8125114501326569e-11, 3.9263803072919160e-12, 2.2003659842875677e-13, 1.0139883410013013e-14, 3.8036255791351365e-16, 1.1478770068871720e-17, 2.7491455795179009e-19, 5.1421792395941592e-21, 7.3704570195170156e-23, 7.9129760878551264e-25, 6.1891475308279466e-27, 3.4074887052468082e-29, 1.2642951712027768e-31, 2.9874354212480538e-34, 4.1660662393372492e-37, 3.0804483195558287e-40, 1.0287869477179010e-43, 1.1932102199256711e-47, 2.9179360026092975e-52, 4.2475403944235563e-58}, {6.2703784480694208e-59, 4.6195869591589206e-53, 2.0048780070281735e-48, 1.8252564480138844e-44, 5.7530583850395732e-41, 8.1734457929853433e-38, 6.1482072743115000e-35, 2.7266171296454801e-32, 7.6951427469170207e-30, 1.4628329302419815e-27, 1.9567429736662381e-25, 1.9064520843927174e-23, 1.3911463582850983e-21, 7.7788589853855015e-20, 3.3973551764091287e-18, 1.1777094633733961e-16, 3.2852244087268414e-15, 7.4617858659486148e-14, 1.3941377125806722e-12, 2.1618054623290873e-11, 2.8038686778996357e-10, 3.0626832246516170e-09, 2.8344707359971740e-08, 2.2345250981121576e-07, 1.5076264668245447e-06, 8.7420837008076225e-06, 4.3727831577546010e-05, 1.8929762178671690e-04, 7.1126362441827832e-04, 2.3254926708230895e-03, 6.6306857259903285e-03, 1.6519285009994170e-02, 3.6018246356681126e-02, 6.8825257394126579e-02, 1.1538643824874496e-01, 1.6987443543948361e-01, 2.1976221051624720e-01, 2.4993008013933904e-01, 2.4993008013933904e-01, 2.1976221051624720e-01, 1.6987443543948361e-01, 1.1538643824874496e-01, 6.8825257394126579e-02, 3.6018246356681126e-02, 1.6519285009994170e-02, 6.6306857259903285e-03, 2.3254926708230895e-03, 7.1126362441827832e-04, 1.8929762178671690e-04, 4.3727831577546010e-05, 8.7420837008076225e-06, 1.5076264668245447e-06, 2.2345250981121576e-07, 2.8344707359971740e-08, 3.0626832246516170e-09, 2.8038686778996357e-10, 2.1618054623290873e-11, 1.3941377125806722e-12, 7.4617858659486148e-14, 3.2852244087268414e-15, 1.1777094633733961e-16, 3.3973551764091287e-18, 7.7788589853855015e-20, 1.3911463582850983e-21, 1.9064520843927174e-23, 1.9567429736662381e-25, 1.4628329302419815e-27, 7.6951427469170207e-30, 2.7266171296454801e-32, 6.1482072743115000e-35, 8.1734457929853433e-38, 5.7530583850395732e-41, 1.8252564480138844e-44, 2.0048780070281735e-48, 4.6195869591589206e-53, 6.2703784480694208e-59}, {9.2494982219878178e-60, 7.3032412797370021e-54, 3.3619702764053515e-49, 3.2301359968277160e-45, 1.0711545066976377e-41, 1.5978109726748470e-38, 1.2601224816663446e-35, 5.8531004842511326e-33, 1.7288387765755684e-30, 3.4377966700873511e-28, 4.8085158087733593e-26, 4.8977600911363362e-24, 3.7358525784193159e-22, 2.1835856119475800e-20, 9.9692083309512582e-19, 3.6131260931106432e-17, 1.0539595203667931e-15, 2.5039803161790368e-14, 4.8951189293680036e-13, 7.9452485251106098e-12, 1.0791168663568375e-10, 1.2349280054594245e-09, 1.1980389793173491e-08, 9.9059473817560524e-08, 7.0144004582899757e-07, 4.2716344520701190e-06, 2.2456298833005965e-05, 1.0225119927510267e-04, 4.0444792546155510e-04, 1.3933051824601373e-03, 4.1899160223157692e-03, 1.1020394106207396e-02, 2.5395651463267135e-02, 5.1347296466210786e-02, 9.1199284542961764e-02, 1.4242938912607919e-01, 1.9573290855318265e-01, 2.3681645470932214e-01, 2.5233616878303844e-01, 2.3681645470932214e-01, 1.9573290855318265e-01, 1.4242938912607919e-01, 9.1199284542961764e-02, 5.1347296466210786e-02, 2.5395651463267135e-02, 1.1020394106207396e-02, 4.1899160223157692e-03, 1.3933051824601373e-03, 4.0444792546155510e-04, 1.0225119927510267e-04, 2.2456298833005965e-05, 4.2716344520701190e-06, 7.0144004582899757e-07, 9.9059473817560524e-08, 1.1980389793173491e-08, 1.2349280054594245e-09, 1.0791168663568375e-10, 7.9452485251106098e-12, 4.8951189293680036e-13, 2.5039803161790368e-14, 1.0539595203667931e-15, 3.6131260931106432e-17, 9.9692083309512582e-19, 2.1835856119475800e-20, 3.7358525784193159e-22, 4.8977600911363362e-24, 4.8085158087733593e-26, 3.4377966700873511e-28, 1.7288387765755684e-30, 5.8531004842511326e-33, 1.2601224816663446e-35, 1.5978109726748470e-38, 1.0711545066976377e-41, 3.2301359968277160e-45, 3.3619702764053515e-49, 7.3032412797370021e-54, 9.2494982219878178e-60}, {1.3633833300020003e-60, 1.1529935596394474e-54, 5.6267053619996539e-50, 5.7021852730627675e-46, 1.9884044482437607e-42, 3.1126000220972273e-39, 2.5723712996578709e-36, 1.2507839519363874e-33, 3.8645811266244288e-31, 8.0343028910788638e-29, 1.1744629608333255e-26, 1.2499248537371909e-24, 9.9604705585733289e-23, 6.0820538195831629e-21, 2.9010288549385599e-19, 1.0985973435650033e-17, 3.3490712214349002e-16, 8.3173189675616162e-15, 1.7001957813551391e-13, 2.8865604962002583e-12, 4.1025651516570179e-11, 4.9151895982232822e-10, 4.9945929385487262e-09, 4.3280820924798808e-08, 3.2138167253993492e-07, 2.0537028582318748e-06, 1.1336998395832870e-05, 5.4246298804851998e-05, 2.2565979982055683e-04, 8.1827502694065590e-04, 2.5924825356809312e-03, 7.1909572204228826e-03, 1.7493488621590211e-02, 3.7379964305875417e-02, 7.0246334697072893e-02, 1.1622011916471321e-01, 1.6942108833811217e-01, 2.1774395641632643e-01, 2.4682659213344721e-01, 2.4682659213344721e-01, 2.1774395641632643e-01, 1.6942108833811217e-01, 1.1622011916471321e-01, 7.0246334697072893e-02, 3.7379964305875417e-02, 1.7493488621590211e-02, 7.1909572204228826e-03, 2.5924825356809312e-03, 8.1827502694065590e-04, 2.2565979982055683e-04, 5.4246298804851998e-05, 1.1336998395832870e-05, 2.0537028582318748e-06, 3.2138167253993492e-07, 4.3280820924798808e-08, 4.9945929385487262e-09, 4.9151895982232822e-10, 4.1025651516570179e-11, 2.8865604962002583e-12, 1.7001957813551391e-13, 8.3173189675616162e-15, 3.3490712214349002e-16, 1.0985973435650033e-17, 2.9010288549385599e-19, 6.0820538195831629e-21, 9.9604705585733289e-23, 1.2499248537371909e-24, 1.1744629608333255e-26, 8.0343028910788638e-29, 3.8645811266244288e-31, 1.2507839519363874e-33, 2.5723712996578709e-36, 3.1126000220972273e-39, 1.9884044482437607e-42, 5.7021852730627675e-46, 5.6267053619996539e-50, 1.1529935596394474e-54, 1.3633833300020003e-60}, {2.0081683556012850e-61, 1.8178162551753148e-55, 9.3991295413480502e-51, 1.0041756149620635e-46, 3.6803258437880526e-43, 6.0427427569366402e-40, 5.2306055163095921e-37, 2.6610906118130193e-34, 8.5963278572927171e-32, 1.8674862726204788e-29, 2.8515675215544967e-27, 3.1692521338966959e-25, 2.6370712657175804e-23, 1.6812873372296920e-21, 8.3735311688359131e-20, 3.3113569430928055e-18, 1.0543294854998749e-16, 2.7353878696405856e-15, 5.8430667493651178e-14, 1.0369888470878425e-12, 1.5412284525394938e-11, 1.9317783962508064e-10, 2.0546146868576734e-09, 1.8645196384240901e-08, 1.4507140693109981e-07, 9.7197681673778427e-07, 5.6294099461087388e-06, 2.8280775482696968e-05, 1.2361276486093516e-04, 4.7135721157038344e-04, 1.5717570688376730e-03, 4.5927856260634522e-03, 1.1781817217642985e-02, 2.6575061210558436e-02, 5.2776416531222697e-02, 9.2382459021801644e-02, 1.4266271740044509e-01, 1.9449150803253865e-01, 2.3419136519193123e-01, 2.4914204006426580e-01, 2.3419136519193123e-01, 1.9449150803253865e-01, 1.4266271740044509e-01, 9.2382459021801644e-02, 5.2776416531222697e-02, 2.6575061210558436e-02, 1.1781817217642985e-02, 4.5927856260634522e-03, 1.5717570688376730e-03, 4.7135721157038344e-04, 1.2361276486093516e-04, 2.8280775482696968e-05, 5.6294099461087388e-06, 9.7197681673778427e-07, 1.4507140693109981e-07, 1.8645196384240901e-08, 2.0546146868576734e-09, 1.9317783962508064e-10, 1.5412284525394938e-11, 1.0369888470878425e-12, 5.8430667493651178e-14, 2.7353878696405856e-15, 1.0543294854998749e-16, 3.3113569430928055e-18, 8.3735311688359131e-20, 1.6812873372296920e-21, 2.6370712657175804e-23, 3.1692521338966959e-25, 2.8515675215544967e-27, 1.8674862726204788e-29, 8.5963278572927171e-32, 2.6610906118130193e-34, 5.2306055163095921e-37, 6.0427427569366402e-40, 3.6803258437880526e-43, 1.0041756149620635e-46, 9.3991295413480502e-51, 1.8178162551753148e-55, 2.0081683556012850e-61}, {2.9557746032980847e-62, 2.8621845857326094e-56, 1.5671564937749406e-51, 1.7642057043388989e-47, 6.7924330161546228e-44, 1.1692076998197370e-40, 1.0595146928277511e-37, 5.6371927794771982e-35, 1.9029906100319421e-32, 4.3178173430220290e-30, 6.8834570436337191e-28, 7.9851871981733358e-26, 6.9341198195289992e-24, 4.6134710745539610e-22, 2.3978402756179082e-20, 9.8965289896201795e-19, 3.2891620143645649e-17, 8.9094610406663587e-16, 1.9875208346984979e-14, 3.6848498201591518e-13, 5.7232797185020048e-12, 7.4997199146582833e-11, 8.3430559260867452e-10, 7.9229232891502669e-09, 6.4544629501196559e-08, 4.5305355658612973e-07, 2.7507246274012478e-06, 1.4496444191129691e-05, 6.6517412418153150e-05, 2.6647788669335111e-04, 9.3431768696117658e-04, 2.8731975330897244e-03, 7.7640394053996482e-03, 1.8465751154427907e-02, 3.8708599914838084e-02, 7.1600747691843394e-02, 1.1698073380429937e-01, 1.6893796927590174e-01, 2.1577494627433041e-01, 2.4383585380721171e-01, 2.4383585380721171e-01, 2.1577494627433041e-01, 1.6893796927590174e-01, 1.1698073380429937e-01, 7.1600747691843394e-02, 3.8708599914838084e-02, 1.8465751154427907e-02, 7.7640394053996482e-03, 2.8731975330897244e-03, 9.3431768696117658e-04, 2.6647788669335111e-04, 6.6517412418153150e-05, 1.4496444191129691e-05, 2.7507246274012478e-06, 4.5305355658612973e-07, 6.4544629501196559e-08, 7.9229232891502669e-09, 8.3430559260867452e-10, 7.4997199146582833e-11, 5.7232797185020048e-12, 3.6848498201591518e-13, 1.9875208346984979e-14, 8.9094610406663587e-16, 3.2891620143645649e-17, 9.8965289896201795e-19, 2.3978402756179082e-20, 4.6134710745539610e-22, 6.9341198195289992e-24, 7.9851871981733358e-26, 6.8834570436337191e-28, 4.3178173430220290e-30, 1.9029906100319421e-32, 5.6371927794771982e-35, 1.0595146928277511e-37, 1.1692076998197370e-40, 6.7924330161546228e-44, 1.7642057043388989e-47, 1.5671564937749406e-51, 2.8621845857326094e-56, 2.9557746032980847e-62}, {4.3474845662635656e-63, 4.5007211282481250e-57, 2.6082298377217237e-52, 3.0923065202135848e-48, 1.2501139575481106e-44, 2.2549072526181938e-41, 2.1381421402290456e-38, 1.1891459359657575e-35, 4.1929734266120318e-33, 9.9316879214599191e-31, 1.6522218331862429e-28, 1.9995631822582135e-26, 1.8111771920709664e-24, 1.2568606780858601e-22, 6.8135449122040696e-21, 2.9333425183931587e-19, 1.0170733571061197e-17, 2.8746837567251872e-16, 6.6931269313103119e-15, 1.2955204220510481e-13, 2.1014796586114549e-12, 2.8770619925838150e-11, 3.3453423873608581e-10, 3.3221419859886598e-09, 2.8316197051829986e-08, 2.0807020978532919e-07, 1.3232911149144323e-06, 7.3096953196703488e-06, 3.5180651840387621e-05, 1.4793874164100584e-04, 5.4489132381766836e-04, 1.7617305058156662e-03, 5.0096471937478518e-03, 1.2549959027149010e-02, 2.7737938219946516e-02, 5.4154863728585530e-02, 9.3492582227695284e-02, 1.4284081532237788e-01, 1.9325876496080116e-01, 2.3165063428423818e-01, 2.4606621240915144e-01, 2.3165063428423818e-01, 1.9325876496080116e-01, 1.4284081532237788e-01, 9.3492582227695284e-02, 5.4154863728585530e-02, 2.7737938219946516e-02, 1.2549959027149010e-02, 5.0096471937478518e-03, 1.7617305058156662e-03, 5.4489132381766836e-04, 1.4793874164100584e-04, 3.5180651840387621e-05, 7.3096953196703488e-06, 1.3232911149144323e-06, 2.0807020978532919e-07, 2.8316197051829986e-08, 3.3221419859886598e-09, 3.3453423873608581e-10, 2.8770619925838150e-11, 2.1014796586114549e-12, 1.2955204220510481e-13, 6.6931269313103119e-15, 2.8746837567251872e-16, 1.0170733571061197e-17, 2.9333425183931587e-19, 6.8135449122040696e-21, 1.2568606780858601e-22, 1.8111771920709664e-24, 1.9995631822582135e-26, 1.6522218331862429e-28, 9.9316879214599191e-31, 4.1929734266120318e-33, 1.1891459359657575e-35, 2.1381421402290456e-38, 2.2549072526181938e-41, 1.2501139575481106e-44, 3.0923065202135848e-48, 2.6082298377217237e-52, 4.5007211282481250e-57, 4.3474845662635656e-63}, {6.3900846179356680e-64, 7.0683040654635165e-58, 4.3331628156671634e-53, 5.4079341607686490e-49, 2.2944871434121997e-45, 4.3348761233697938e-42, 4.2990971075609177e-39, 2.4981476114804934e-36, 9.1963660505689469e-34, 2.2729303616459228e-31, 3.9439087540838148e-29, 4.9770348134757658e-27, 4.7000291498915663e-25, 3.4001352768447133e-23, 1.9215431432889354e-21, 8.6245303609378974e-20, 3.1179884254074804e-18, 9.1905096520186247e-17, 2.2320593837338383e-15, 4.5078424718756776e-14, 7.6319902510210860e-13, 1.0909613183044814e-11, 1.3250311215425566e-10, 1.3750709116496800e-09, 1.2253983047111421e-08, 9.4193245001969527e-08, 6.2702226836829128e-07, 3.6275480887435970e-06, 1.8297490531324017e-05, 8.0695629747031377e-05, 3.1195003282250721e-04, 1.0594217898549964e-03, 3.1670839271362595e-03, 8.3485090964466376e-03, 1.9434337138642246e-02, 4.0003826723007251e-02, 7.2891273924741068e-02, 1.1767348589341342e-01, 1.6842887908813681e-01, 2.1385359898330383e-01, 2.4095120319809515e-01, 2.4095120319809515e-01, 2.1385359898330383e-01, 1.6842887908813681e-01, 1.1767348589341342e-01, 7.2891273924741068e-02, 4.0003826723007251e-02, 1.9434337138642246e-02, 8.3485090964466376e-03, 3.1670839271362595e-03, 1.0594217898549964e-03, 3.1195003282250721e-04, 8.0695629747031377e-05, 1.8297490531324017e-05, 3.6275480887435970e-06, 6.2702226836829128e-07, 9.4193245001969527e-08, 1.2253983047111421e-08, 1.3750709116496800e-09, 1.3250311215425566e-10, 1.0909613183044814e-11, 7.6319902510210860e-13, 4.5078424718756776e-14, 2.2320593837338383e-15, 9.1905096520186247e-17, 3.1179884254074804e-18, 8.6245303609378974e-20, 1.9215431432889354e-21, 3.4001352768447133e-23, 4.7000291498915663e-25, 4.9770348134757658e-27, 3.9439087540838148e-29, 2.2729303616459228e-31, 9.1963660505689469e-34, 2.4981476114804934e-36, 4.2990971075609177e-39, 4.3348761233697938e-42, 2.2944871434121997e-45, 5.4079341607686490e-49, 4.3331628156671634e-53, 7.0683040654635165e-58, 6.3900846179356680e-64}, {9.3860543034002427e-65, 1.1086857074759456e-58, 7.1863132033979924e-54, 9.4366281490374702e-50, 4.2000954414179859e-46, 8.3074192361133957e-43, 8.6131947009295395e-40, 5.2269922366851146e-37, 2.0080025620200044e-34, 5.1761145427794598e-32, 9.3634938532685839e-30, 1.2315531785339706e-27, 1.2119297214386231e-25, 9.1354157424215784e-24, 5.3793647773372928e-22, 2.5158646274622071e-20, 9.4786222458398701e-19, 2.9120616998176371e-17, 7.3730974398680154e-16, 1.5527783781178122e-14, 2.7422533133249144e-13, 4.0903372275217891e-12, 5.1859074150534959e-11, 5.6202961151004291e-10, 5.2329996549801057e-09, 4.2048817138133669e-08, 2.9276307349429699e-07, 1.7725651070157471e-06, 9.3629045679147633e-06, 4.3270500380986358e-05, 1.7541290219541701e-04, 6.2518907824834233e-04, 1.9629978285824797e-03, 5.4395127563656737e-03, 1.3323152028369395e-02, 2.8883095437764291e-02, 5.5483794234023616e-02, 9.4533826153130718e-02, 1.4296854105472981e-01, 1.9203597399663150e-01, 2.2918990372570339e-01, 2.4310155924759538e-01, 2.2918990372570339e-01, 1.9203597399663150e-01, 1.4296854105472981e-01, 9.4533826153130718e-02, 5.5483794234023616e-02, 2.8883095437764291e-02, 1.3323152028369395e-02, 5.4395127563656737e-03, 1.9629978285824797e-03, 6.2518907824834233e-04, 1.7541290219541701e-04, 4.3270500380986358e-05, 9.3629045679147633e-06, 1.7725651070157471e-06, 2.9276307349429699e-07, 4.2048817138133669e-08, 5.2329996549801057e-09, 5.6202961151004291e-10, 5.1859074150534959e-11, 4.0903372275217891e-12, 2.7422533133249144e-13, 1.5527783781178122e-14, 7.3730974398680154e-16, 2.9120616998176371e-17, 9.4786222458398701e-19, 2.5158646274622071e-20, 5.3793647773372928e-22, 9.1354157424215784e-24, 1.2119297214386231e-25, 1.2315531785339706e-27, 9.3634938532685839e-30, 5.1761145427794598e-32, 2.0080025620200044e-34, 5.2269922366851146e-37, 8.6131947009295395e-40, 8.3074192361133957e-43, 4.2000954414179859e-46, 9.4366281490374702e-50, 7.1863132033979924e-54, 1.1086857074759456e-58, 9.3860543034002427e-65}, {1.3777591125358009e-65, 1.7368921661372738e-59, 1.1897755678170730e-54, 1.6430818957997274e-50, 7.6682284731962107e-47, 1.5871807417910754e-43, 1.7196165366502119e-40, 1.0893693911932259e-37, 4.3652562606795252e-35, 1.1730726684546622e-32, 2.2113391943206024e-30, 3.0299940661257904e-28, 3.1056775475544893e-26, 2.4381144772606556e-24, 1.4951761449964922e-22, 7.2828478980006098e-21, 2.8579464976920660e-19, 9.1468094747747248e-18, 2.4130464210357486e-16, 5.2963672903976192e-15, 9.7511119835367196e-14, 1.5167942114683800e-12, 2.0061976506906991e-11, 2.2691700569827051e-10, 2.2060316533485200e-09, 1.8517359090727501e-08, 1.3475150826592070e-07, 8.5321092475315403e-07, 4.7158906386790063e-06, 2.2820419642920848e-05, 9.6932540256516268e-05, 3.6225322463531061e-04, 1.1935740511675038e-03, 3.4735556703184827e-03, 8.9429974621500780e-03, 2.0397690515966099e-02, 4.1265501456996284e-02, 7.4120627126827321e-02, 1.1830317740926892e-01, 1.6789719350811264e-01, 2.1197836082996782e-01, 2.3816651641238701e-01, 2.3816651641238701e-01, 2.1197836082996782e-01, 1.6789719350811264e-01, 1.1830317740926892e-01, 7.4120627126827321e-02, 4.1265501456996284e-02, 2.0397690515966099e-02, 8.9429974621500780e-03, 3.4735556703184827e-03, 1.1935740511675038e-03, 3.6225322463531061e-04, 9.6932540256516268e-05, 2.2820419642920848e-05, 4.7158906386790063e-06, 8.5321092475315403e-07, 1.3475150826592070e-07, 1.8517359090727501e-08, 2.2060316533485200e-09, 2.2691700569827051e-10, 2.0061976506906991e-11, 1.5167942114683800e-12, 9.7511119835367196e-14, 5.2963672903976192e-15, 2.4130464210357486e-16, 9.1468094747747248e-18, 2.8579464976920660e-19, 7.2828478980006098e-21, 1.4951761449964922e-22, 2.4381144772606556e-24, 3.1056775475544893e-26, 3.0299940661257904e-28, 2.2113391943206024e-30, 1.1730726684546622e-32, 4.3652562606795252e-35, 1.0893693911932259e-37, 1.7196165366502119e-40, 1.5871807417910754e-43, 7.6682284731962107e-47, 1.6430818957997274e-50, 1.1897755678170730e-54, 1.7368921661372738e-59, 1.3777591125358009e-65}, {2.0210775781982523e-66, 2.7178104548553350e-60, 1.9665137729345701e-55, 2.8548162606098395e-51, 1.3964239783926081e-47, 3.0233321269411514e-44, 3.4214653414754691e-41, 2.2616501773134073e-38, 9.4491938966483701e-36, 2.6460383187052969e-33, 5.1955440071780227e-31, 7.4129920915228913e-29, 7.9104233673873923e-27, 6.4645977792616403e-25, 4.1267488231576369e-23, 2.0924604014548367e-21, 8.5484498659455372e-20, 2.8486537373202696e-18, 7.8262318929365957e-17, 1.7892942386135024e-15, 3.4323564970059177e-14, 5.5646126660265747e-13, 7.6736928514695270e-12, 9.0529279992180488e-11, 9.1835433159763121e-10, 8.0473976876877841e-09, 6.1165350599767583e-08, 4.0472265409701691e-07, 2.3390768958015489e-06, 1.1842716592385991e-05, 5.2665815424842040e-05, 2.0620794316657292e-04, 7.1235629871549161e-04, 2.1752890413369533e-03, 5.8813993717320096e-03, 1.4099847351552907e-02, 3.0009543309201085e-02, 5.6764441788522510e-02, 9.5510122550246740e-02, 1.4305030254196435e-01, 1.9082420376099704e-01, 2.2680511848210408e-01, 2.4024154090350588e-01, 2.2680511848210408e-01, 1.9082420376099704e-01, 1.4305030254196435e-01, 9.5510122550246740e-02, 5.6764441788522510e-02, 3.0009543309201085e-02, 1.4099847351552907e-02, 5.8813993717320096e-03, 2.1752890413369533e-03, 7.1235629871549161e-04, 2.0620794316657292e-04, 5.2665815424842040e-05, 1.1842716592385991e-05, 2.3390768958015489e-06, 4.0472265409701691e-07, 6.1165350599767583e-08, 8.0473976876877841e-09, 9.1835433159763121e-10, 9.0529279992180488e-11, 7.6736928514695270e-12, 5.5646126660265747e-13, 3.4323564970059177e-14, 1.7892942386135024e-15, 7.8262318929365957e-17, 2.8486537373202696e-18, 8.5484498659455372e-20, 2.0924604014548367e-21, 4.1267488231576369e-23, 6.4645977792616403e-25, 7.9104233673873923e-27, 7.4129920915228913e-29, 5.1955440071780227e-31, 2.6460383187052969e-33, 9.4491938966483701e-36, 2.2616501773134073e-38, 3.4214653414754691e-41, 3.0233321269411514e-44, 1.3964239783926081e-47, 2.8548162606098395e-51, 1.9665137729345701e-55, 2.7178104548553350e-60, 2.0210775781982523e-66}, {2.9629045151469795e-67, 4.2477382853725514e-61, 3.2450153429194443e-56, 4.9498576868697659e-52, 2.5365833564005594e-48, 5.7421164166187080e-45, 6.7848084979774069e-42, 4.6777688454197694e-39, 2.0368541188744583e-36, 5.9410439274149082e-34, 1.2145487671367711e-31, 1.8036964134319502e-29, 2.0029387907481775e-27, 1.7031624106751895e-25, 1.1312252871807839e-23, 5.9680464287706203e-22, 2.5370441167173625e-20, 8.7983250076979868e-19, 2.5159793892190254e-17, 5.9885746170489713e-16, 1.1962793877597350e-14, 2.0202353514446467e-13, 2.9029728072990475e-12, 3.5699318546714651e-11, 3.7765043235634349e-10, 3.4525199163835126e-09, 2.7390187380396967e-08, 1.8926893464082190e-07, 1.1429783024859512e-06, 6.0502321414091725e-06, 2.8148083952665619e-05, 1.1537557343902387e-04, 4.1754273548549582e-04, 1.3367210462102556e-03, 3.7920023944900709e-03, 9.5461945478795308e-03, 2.1354422319535372e-02, 4.2493637239894133e-02, 7.5291446661321912e-02, 1.1887424153508566e-01, 1.6734591429857545e-01, 2.1014771223832399e-01, 2.3547615304001107e-01, 2.3547615304001107e-01, 2.1014771223832399e-01, 1.6734591429857545e-01, 1.1887424153508566e-01, 7.5291446661321912e-02, 4.2493637239894133e-02, 2.1354422319535372e-02, 9.5461945478795308e-03, 3.7920023944900709e-03, 1.3367210462102556e-03, 4.1754273548549582e-04, 1.1537557343902387e-04, 2.8148083952665619e-05, 6.0502321414091725e-06, 1.1429783024859512e-06, 1.8926893464082190e-07, 2.7390187380396967e-08, 3.4525199163835126e-09, 3.7765043235634349e-10, 3.5699318546714651e-11, 2.9029728072990475e-12, 2.0202353514446467e-13, 1.1962793877597350e-14, 5.9885746170489713e-16, 2.5159793892190254e-17, 8.7983250076979868e-19, 2.5370441167173625e-20, 5.9680464287706203e-22, 1.1312252871807839e-23, 1.7031624106751895e-25, 2.0029387907481775e-27, 1.8036964134319502e-29, 1.2145487671367711e-31, 5.9410439274149082e-34, 2.0368541188744583e-36, 4.6777688454197694e-39, 6.7848084979774069e-42, 5.7421164166187080e-45, 2.5365833564005594e-48, 4.9498576868697659e-52, 3.2450153429194443e-56, 4.2477382853725514e-61, 2.9629045151469795e-67}, {4.3409286059314790e-68, 6.6312997992786490e-62, 5.3461191685641914e-57, 8.5648796438497824e-53, 4.5963493020491623e-49, 1.0874550734954457e-45, 1.3410304270363433e-42, 9.6394008578235831e-40, 4.3726474538903734e-37, 1.3279095802116780e-34, 2.8252406271755742e-32, 4.3652040547608271e-30, 5.0421784821017282e-28, 4.4592405404333692e-26, 3.0802364578690691e-24, 1.6900522980387141e-22, 7.4723281435460732e-21, 2.6954831586023608e-19, 8.0190167662890588e-18, 1.9861050466676079e-16, 4.1293419627929950e-15, 7.2600749267287114e-14, 1.0864518129258071e-12, 1.3919025655825987e-11, 1.5345768250281952e-10, 1.4627430245954727e-09, 1.2104826477830397e-08, 8.7294781098733113e-08, 5.5045426913594814e-07, 3.0442062696033981e-06, 1.4805735210956500e-05, 6.3482017172793501e-05, 2.4048437850905004e-04, 8.0646696699679095e-04, 2.3982976827574042e-03, 6.3343363657207474e-03, 1.4878611633370075e-02, 3.1116468918540825e-02, 5.7998096102851303e-02, 9.6425173608541109e-02, 1.4309010371318212e-01, 1.8962432993080802e-01, 2.2449250076685384e-01, 2.3748014388162669e-01, 2.2449250076685384e-01, 1.8962432993080802e-01, 1.4309010371318212e-01, 9.6425173608541109e-02, 5.7998096102851303e-02, 3.1116468918540825e-02, 1.4878611633370075e-02, 6.3343363657207474e-03, 2.3982976827574042e-03, 8.0646696699679095e-04, 2.4048437850905004e-04, 6.3482017172793501e-05, 1.4805735210956500e-05, 3.0442062696033981e-06, 5.5045426913594814e-07, 8.7294781098733113e-08, 1.2104826477830397e-08, 1.4627430245954727e-09, 1.5345768250281952e-10, 1.3919025655825987e-11, 1.0864518129258071e-12, 7.2600749267287114e-14, 4.1293419627929950e-15, 1.9861050466676079e-16, 8.0190167662890588e-18, 2.6954831586023608e-19, 7.4723281435460732e-21, 1.6900522980387141e-22, 3.0802364578690691e-24, 4.4592405404333692e-26, 5.0421784821017282e-28, 4.3652040547608271e-30, 2.8252406271755742e-32, 1.3279095802116780e-34, 4.3726474538903734e-37, 9.6394008578235831e-40, 1.3410304270363433e-42, 1.0874550734954457e-45, 4.5963493020491623e-49, 8.5648796438497824e-53, 5.3461191685641914e-57, 6.6312997992786490e-62, 4.3409286059314790e-68}, {6.3559888804815291e-69, 1.0340740401651512e-62, 8.7937979910383930e-58, 1.4790458246095511e-53, 8.3086543388025186e-50, 2.0536646110581859e-46, 2.6420736294829820e-43, 1.9792151722732658e-40, 9.3494545988123451e-38, 2.9549868117171349e-35, 6.5403217012580441e-33, 1.0509161650154305e-30, 1.2621393343519558e-28, 1.1604245678013870e-26, 8.3325690961981494e-25, 4.7526132981917159e-23, 2.1844800072999790e-21, 8.1927992139953961e-20, 2.5344499212676499e-18, 6.5284978547093747e-17, 1.4120140414140493e-15, 2.5832194339375668e-14, 4.0236781196418743e-13, 5.3673492268073417e-12, 6.1636566122784830e-11, 6.1219783545440359e-10, 5.2813629715600939e-09, 3.9723156884506070e-08, 2.6137484697367874e-07, 1.5091682442228327e-06, 7.6676762452478550e-06, 3.4365246906918278e-05, 1.3616684443587397e-04, 4.7795191142819410e-04, 1.4887726540954260e-03, 4.1217965699966519e-03, 1.0156852342094170e-02, 2.2303298514796874e-02, 4.3688380057289714e-02, 7.6406289996198792e-02, 1.1939077299329898e-01, 1.6677771361921795e-01, 2.0836017261496417e-01, 2.3287490818454673e-01, 2.3287490818454673e-01, 2.0836017261496417e-01, 1.6677771361921795e-01, 1.1939077299329898e-01, 7.6406289996198792e-02, 4.3688380057289714e-02, 2.2303298514796874e-02, 1.0156852342094170e-02, 4.1217965699966519e-03, 1.4887726540954260e-03, 4.7795191142819410e-04, 1.3616684443587397e-04, 3.4365246906918278e-05, 7.6676762452478550e-06, 1.5091682442228327e-06, 2.6137484697367874e-07, 3.9723156884506070e-08, 5.2813629715600939e-09, 6.1219783545440359e-10, 6.1636566122784830e-11, 5.3673492268073417e-12, 4.0236781196418743e-13, 2.5832194339375668e-14, 1.4120140414140493e-15, 6.5284978547093747e-17, 2.5344499212676499e-18, 8.1927992139953961e-20, 2.1844800072999790e-21, 4.7526132981917159e-23, 8.3325690961981494e-25, 1.1604245678013870e-26, 1.2621393343519558e-28, 1.0509161650154305e-30, 6.5403217012580441e-33, 2.9549868117171349e-35, 9.3494545988123451e-38, 1.9792151722732658e-40, 2.6420736294829820e-43, 2.0536646110581859e-46, 8.3086543388025186e-50, 1.4790458246095511e-53, 8.7937979910383930e-58, 1.0340740401651512e-62, 6.3559888804815291e-69}, {9.3008818390890492e-70, 1.6107424492415425e-63, 1.4442544724939497e-58, 2.5491245644508241e-54, 1.4983841626026885e-50, 3.8676878782479128e-47, 5.1890175350658309e-44, 4.0494895783343356e-41, 1.9912326515858821e-38, 6.5473365822875601e-36, 1.5069227943967880e-33, 2.5171173318424500e-31, 3.1418754018247846e-29, 3.0018077177700208e-27, 2.2397389074987337e-25, 1.3273883998725675e-23, 6.3398444713628853e-22, 2.4709662681137447e-20, 7.9447537335212530e-19, 2.1273958174343124e-17, 4.7841544346425597e-16, 9.1026391570176184e-15, 1.4750035153523922e-13, 2.0475389185298693e-12, 2.4477459246779186e-11, 2.5318768471063941e-10, 2.2756270244146732e-09, 1.7840153336747013e-08, 1.2241314031279016e-07, 7.3745467763804806e-07, 3.9114112665063118e-06, 1.8311113911126260e-05, 7.5833505293245319e-05, 2.7838967822704579e-04, 9.0756465037858196e-04, 2.6316863728237144e-03, 6.7973713273565750e-03, 1.5658123034423620e-02, 3.2203216875107243e-02, 5.9186084836389256e-02, 9.7282463095519897e-02, 1.4309158549116330e-01, 1.8843706331894564e-01, 2.2224852664936542e-01, 2.3481182765823758e-01, 2.2224852664936542e-01, 1.8843706331894564e-01, 1.4309158549116330e-01, 9.7282463095519897e-02, 5.9186084836389256e-02, 3.2203216875107243e-02, 1.5658123034423620e-02, 6.7973713273565750e-03, 2.6316863728237144e-03, 9.0756465037858196e-04, 2.7838967822704579e-04, 7.5833505293245319e-05, 1.8311113911126260e-05, 3.9114112665063118e-06, 7.3745467763804806e-07, 1.2241314031279016e-07, 1.7840153336747013e-08, 2.2756270244146732e-09, 2.5318768471063941e-10, 2.4477459246779186e-11, 2.0475389185298693e-12, 1.4750035153523922e-13, 9.1026391570176184e-15, 4.7841544346425597e-16, 2.1273958174343124e-17, 7.9447537335212530e-19, 2.4709662681137447e-20, 6.3398444713628853e-22, 1.3273883998725675e-23, 2.2397389074987337e-25, 3.0018077177700208e-27, 3.1418754018247846e-29, 2.5171173318424500e-31, 1.5069227943967880e-33, 6.5473365822875601e-36, 1.9912326515858821e-38, 4.0494895783343356e-41, 5.1890175350658309e-44, 3.8676878782479128e-47, 1.4983841626026885e-50, 2.5491245644508241e-54, 1.4442544724939497e-58, 1.6107424492415425e-63, 9.3008818390890492e-70}, {1.3602242492354518e-70, 2.5062893896000025e-64, 2.3683907001837810e-59, 4.3849662998245842e-55, 2.6959438737993594e-51, 7.2644220875022382e-48, 1.0159844536444225e-44, 8.2566412936940675e-42, 4.2246144598021515e-39, 1.4445590039286314e-36, 3.4560072588078828e-34, 5.9987185516144465e-32, 7.7788491872908368e-30, 7.7199678213751262e-28, 5.9827510138490597e-26, 3.6826729053156295e-24, 1.8269179382831153e-22, 7.3963423583597857e-21, 2.4705505922880106e-19, 6.8737797990960140e-18, 1.6064742942702627e-16, 3.1773129599637848e-15, 5.3533724861984214e-14, 7.7293031086018118e-13, 9.6137828691596686e-12, 1.0350233726240316e-10, 9.6863849248805751e-10, 7.9104166149104796e-09, 5.6567852900930044e-08, 3.5533045829496680e-07, 1.9661408494659142e-06, 9.6077760741794566e-06, 4.1557921102543606e-05, 1.5944214368480690e-04, 5.4359224952962480e-04, 1.6496055361812409e-03, 4.4622998595035017e-03, 1.0773786624642434e-02, 2.3243228173755130e-02, 4.4849988132390606e-02, 7.7467627605512762e-02, 1.1985655590239072e-01, 1.6619497260995916e-01, 2.0661430370392464e-01, 2.3035797018194470e-01, 2.3035797018194470e-01, 2.0661430370392464e-01, 1.6619497260995916e-01, 1.1985655590239072e-01, 7.7467627605512762e-02, 4.4849988132390606e-02, 2.3243228173755130e-02, 1.0773786624642434e-02, 4.4622998595035017e-03, 1.6496055361812409e-03, 5.4359224952962480e-04, 1.5944214368480690e-04, 4.1557921102543606e-05, 9.6077760741794566e-06, 1.9661408494659142e-06, 3.5533045829496680e-07, 5.6567852900930044e-08, 7.9104166149104796e-09, 9.6863849248805751e-10, 1.0350233726240316e-10, 9.6137828691596686e-12, 7.7293031086018118e-13, 5.3533724861984214e-14, 3.1773129599637848e-15, 1.6064742942702627e-16, 6.8737797990960140e-18, 2.4705505922880106e-19, 7.3963423583597857e-21, 1.8269179382831153e-22, 3.6826729053156295e-24, 5.9827510138490597e-26, 7.7199678213751262e-28, 7.7788491872908368e-30, 5.9987185516144465e-32, 3.4560072588078828e-34, 1.4445590039286314e-36, 4.2246144598021515e-39, 8.2566412936940675e-42, 1.0159844536444225e-44, 7.2644220875022382e-48, 2.6959438737993594e-51, 4.3849662998245842e-55, 2.3683907001837810e-59, 2.5062893896000025e-64, 1.3602242492354518e-70}, {1.9881401943823065e-71, 3.8956133082883524e-65, 3.8780907613890165e-60, 7.5287596024697438e-56, 4.8396443307633869e-52, 1.3608233728823463e-48, 1.9832504849666674e-45, 1.6777720088426207e-42, 8.9292665279968075e-40, 3.1739897948436054e-37, 7.8902747437194502e-35, 1.4225885948951900e-32, 1.9157413956045486e-30, 1.9741018729702676e-28, 1.5883597138828314e-26, 1.0150605078465530e-24, 5.2280336522983695e-23, 2.1976422794092572e-21, 7.6226000038011678e-20, 2.2026235762112506e-18, 5.3473142908729109e-17, 1.0988447789132501e-15, 1.9241100890740006e-14, 2.8879825636852583e-13, 3.7354214836948911e-12, 4.1834945759406555e-11, 4.0743696574618951e-10, 3.4640710439123456e-09, 2.5801094931709852e-08, 1.6888360171753998e-07, 9.7426112561417961e-07, 4.9661767693609960e-06, 2.2420154669404182e-05, 8.9832774694917811e-05, 3.2005763736769638e-04, 1.0156641399211783e-03, 2.8750919999992967e-03, 7.2695749936617917e-03, 1.6437166647437267e-02, 3.3269271876221002e-02, 6.0329758617287225e-02, 9.8085267668094472e-02, 1.4305806223178333e-01, 1.8726297375534309e-01, 2.2006990496442211e-01, 2.3223147790375134e-01, 2.2006990496442211e-01, 1.8726297375534309e-01, 1.4305806223178333e-01, 9.8085267668094472e-02, 6.0329758617287225e-02, 3.3269271876221002e-02, 1.6437166647437267e-02, 7.2695749936617917e-03, 2.8750919999992967e-03, 1.0156641399211783e-03, 3.2005763736769638e-04, 8.9832774694917811e-05, 2.2420154669404182e-05, 4.9661767693609960e-06, 9.7426112561417961e-07, 1.6888360171753998e-07, 2.5801094931709852e-08, 3.4640710439123456e-09, 4.0743696574618951e-10, 4.1834945759406555e-11, 3.7354214836948911e-12, 2.8879825636852583e-13, 1.9241100890740006e-14, 1.0988447789132501e-15, 5.3473142908729109e-17, 2.2026235762112506e-18, 7.6226000038011678e-20, 2.1976422794092572e-21, 5.2280336522983695e-23, 1.0150605078465530e-24, 1.5883597138828314e-26, 1.9741018729702676e-28, 1.9157413956045486e-30, 1.4225885948951900e-32, 7.8902747437194502e-35, 3.1739897948436054e-37, 8.9292665279968075e-40, 1.6777720088426207e-42, 1.9832504849666674e-45, 1.3608233728823463e-48, 4.8396443307633869e-52, 7.5287596024697438e-56, 3.8780907613890165e-60, 3.8956133082883524e-65, 1.9881401943823065e-71}, {2.9042780793285192e-72, 6.0487911085991875e-66, 6.3408840552698421e-61, 1.2902630736739495e-56, 8.6686227081665284e-53, 2.5425883339495936e-49, 3.8599589978240019e-46, 3.3979613434850632e-43, 1.8803612804682350e-40, 6.9456401083003465e-38, 1.7934288277345599e-35, 3.3574581848271432e-33, 4.6935588729781351e-31, 5.0199340944280284e-29, 4.1917802591871942e-27, 2.7800091791127284e-25, 1.4859465721519723e-23, 6.4827357579899811e-22, 2.3339160328683892e-20, 7.0010683610304173e-19, 1.7647313333962599e-17, 3.7660828360044482e-16, 6.8501492079314778e-15, 1.0683188551398555e-13, 1.4362003723050719e-12, 1.6723593784919510e-11, 1.6940433392992703e-10, 1.4986355561051177e-09, 1.1619214278627516e-08, 7.9204993538763526e-08, 4.7607676418369897e-07, 2.5297850142327841e-06, 1.1912329247318932e-05, 4.9812715968551620e-05, 1.8533007239769129e-04, 6.1455372697219728e-04, 1.8190665842030779e-03, 4.8128687057527163e-03, 1.1395877807434502e-02, 2.4173252104118973e-02, 4.5978813889354229e-02, 7.8477839811903538e-02, 1.2027508931592504e-01, 1.6559981501591434e-01, 2.0490871177338488e-01, 2.2792088322788109e-01, 2.2792088322788109e-01, 2.0490871177338488e-01, 1.6559981501591434e-01, 1.2027508931592504e-01, 7.8477839811903538e-02, 4.5978813889354229e-02, 2.4173252104118973e-02, 1.1395877807434502e-02, 4.8128687057527163e-03, 1.8190665842030779e-03, 6.1455372697219728e-04, 1.8533007239769129e-04, 4.9812715968551620e-05, 1.1912329247318932e-05, 2.5297850142327841e-06, 4.7607676418369897e-07, 7.9204993538763526e-08, 1.1619214278627516e-08, 1.4986355561051177e-09, 1.6940433392992703e-10, 1.6723593784919510e-11, 1.4362003723050719e-12, 1.0683188551398555e-13, 6.8501492079314778e-15, 3.7660828360044482e-16, 1.7647313333962599e-17, 7.0010683610304173e-19, 2.3339160328683892e-20, 6.4827357579899811e-22, 1.4859465721519723e-23, 2.7800091791127284e-25, 4.1917802591871942e-27, 5.0199340944280284e-29, 4.6935588729781351e-31, 3.3574581848271432e-33, 1.7934288277345599e-35, 6.9456401083003465e-38, 1.8803612804682350e-40, 3.3979613434850632e-43, 3.8599589978240019e-46, 2.5425883339495936e-49, 8.6686227081665284e-53, 1.2902630736739495e-56, 6.3408840552698421e-61, 6.0487911085991875e-66, 2.9042780793285192e-72}, {4.2402214052951246e-73, 9.3824834253827312e-67, 1.0352869434490524e-61, 2.2072219195734482e-57, 1.5493136809731731e-53, 4.7385536981365373e-50, 7.4907905142626159e-47, 6.8594377885386513e-44, 3.9454427601608861e-41, 1.5138792655234332e-38, 4.0587293642249081e-36, 7.8867039514681461e-34, 1.1440858552314813e-31, 1.2695564683626133e-29, 1.0997785424357608e-27, 7.5663389636387123e-26, 4.1954427268621758e-24, 1.8988470634740822e-22, 7.0927393378883720e-21, 2.2077343775414074e-19, 5.7754643743238307e-18, 1.2794126341282052e-16, 2.4162049041525693e-15, 3.9134647294064509e-14, 5.4654903154799270e-13, 6.6135809154494093e-12, 6.9642829049519196e-11, 6.4070330827294555e-10, 5.1680095336388813e-09, 3.6666857282366239e-08, 2.2949550926387024e-07, 1.2704896429597333e-06, 6.2359369667152816e-06, 2.7195889773576724e-05, 1.0558960284417518e-04, 3.6560795714255136e-04, 1.1307532404246092e-03, 3.1281305245610394e-03, 7.7500451541012766e-03, 1.7214629493700298e-02, 3.4314242859408567e-02, 6.1430478646654310e-02, 9.8836668138780004e-02, 1.4299255414069270e-01, 1.8610251044108347e-01, 2.1795355826999802e-01, 2.2973436523811983e-01, 2.1795355826999802e-01, 1.8610251044108347e-01, 1.4299255414069270e-01, 9.8836668138780004e-02, 6.1430478646654310e-02, 3.4314242859408567e-02, 1.7214629493700298e-02, 7.7500451541012766e-03, 3.1281305245610394e-03, 1.1307532404246092e-03, 3.6560795714255136e-04, 1.0558960284417518e-04, 2.7195889773576724e-05, 6.2359369667152816e-06, 1.2704896429597333e-06, 2.2949550926387024e-07, 3.6666857282366239e-08, 5.1680095336388813e-09, 6.4070330827294555e-10, 6.9642829049519196e-11, 6.6135809154494093e-12, 5.4654903154799270e-13, 3.9134647294064509e-14, 2.4162049041525693e-15, 1.2794126341282052e-16, 5.7754643743238307e-18, 2.2077343775414074e-19, 7.0927393378883720e-21, 1.8988470634740822e-22, 4.1954427268621758e-24, 7.5663389636387123e-26, 1.0997785424357608e-27, 1.2695564683626133e-29, 1.1440858552314813e-31, 7.8867039514681461e-34, 4.0587293642249081e-36, 1.5138792655234332e-38, 3.9454427601608861e-41, 6.8594377885386513e-44, 7.4907905142626159e-47, 4.7385536981365373e-50, 1.5493136809731731e-53, 2.2072219195734482e-57, 1.0352869434490524e-61, 9.3824834253827312e-67, 4.2402214052951246e-73}, {6.1873167292600330e-74, 1.4538901947049863e-67, 1.6879603995600424e-62, 3.7691324369200321e-58, 2.7631164912569130e-54, 8.8091139694466722e-51, 1.4495623366344723e-47, 1.3802919462863240e-44, 8.2491698349502409e-42, 3.2868281039958480e-39, 9.1463558192668670e-37, 1.8440635697521863e-34, 2.7749265480534503e-32, 3.1936039953280896e-30, 2.8689474946571079e-28, 2.0467667970915599e-26, 1.1768586219954579e-24, 5.5235547418541776e-23, 2.1397391826730893e-21, 6.9081875027574077e-20, 1.8747446593629021e-18, 4.3090894092529427e-17, 8.4454653993109795e-16, 1.4199548095965024e-14, 2.0591425994119171e-13, 2.5880423909347226e-12, 2.8316127909785268e-11, 2.7076622359247714e-10, 2.2709635043178179e-09, 1.6760660123885240e-08, 1.0917307724251056e-07, 6.2927723529831787e-07, 3.2175123782368650e-06, 1.4625147457368242e-05, 5.9216205461426278e-05, 2.1395132199714689e-04, 6.9090534092963924e-04, 1.9969762869401319e-03, 5.1728592008298650e-03, 1.2022070950665343e-02, 2.5092532015162070e-02, 4.7075288211797156e-02, 7.9439215172105435e-02, 1.2064961060726002e-01, 1.6499413655200360e-01, 2.0324204888941669e-01, 2.2555951425452636e-01, 2.2555951425452636e-01, 2.0324204888941669e-01, 1.6499413655200360e-01, 1.2064961060726002e-01, 7.9439215172105435e-02, 4.7075288211797156e-02, 2.5092532015162070e-02, 1.2022070950665343e-02, 5.1728592008298650e-03, 1.9969762869401319e-03, 6.9090534092963924e-04, 2.1395132199714689e-04, 5.9216205461426278e-05, 1.4625147457368242e-05, 3.2175123782368650e-06, 6.2927723529831787e-07, 1.0917307724251056e-07, 1.6760660123885240e-08, 2.2709635043178179e-09, 2.7076622359247714e-10, 2.8316127909785268e-11, 2.5880423909347226e-12, 2.0591425994119171e-13, 1.4199548095965024e-14, 8.4454653993109795e-16, 4.3090894092529427e-17, 1.8747446593629021e-18, 6.9081875027574077e-20, 2.1397391826730893e-21, 5.5235547418541776e-23, 1.1768586219954579e-24, 2.0467667970915599e-26, 2.8689474946571079e-28, 3.1936039953280896e-30, 2.7749265480534503e-32, 1.8440635697521863e-34, 9.1463558192668670e-37, 3.2868281039958480e-39, 8.2491698349502409e-42, 1.3802919462863240e-44, 1.4495623366344723e-47, 8.8091139694466722e-51, 2.7631164912569130e-54, 3.7691324369200321e-58, 1.6879603995600424e-62, 1.4538901947049863e-67, 6.1873167292600330e-74}, {9.0236831042710006e-75, 2.2507013266634397e-68, 2.7483088481763178e-63, 6.4250837772781210e-59, 4.9175305451785707e-55, 1.6336381889925197e-51, 2.7972683193869001e-48, 2.7688066162395138e-45, 1.7187588390664908e-42, 7.1089100355543671e-40, 2.0525562261562526e-37, 4.2923202100065188e-35, 6.6976892723501377e-33, 7.9915865248767542e-31, 7.4422174735850754e-29, 5.5036367600342068e-27, 3.2802180350829561e-25, 1.5959112775571386e-23, 6.4090652642750824e-22, 2.1453091893671746e-20, 6.0370235645633800e-19, 1.4391241588665120e-17, 2.9258946262067771e-16, 5.1042859875473367e-15, 7.6822356519145676e-14, 1.0023990331996466e-12, 1.1389647007504889e-11, 1.1314327929338598e-10, 9.8619913092006371e-10, 7.5672777489105014e-09, 5.1267694307391355e-08, 3.0750156860401326e-07, 1.6368618884967503e-06, 7.7499739996840847e-06, 3.2702654980222023e-05, 1.2321031502033358e-04, 4.1514601828721595e-04, 1.2527946608682095e-03, 3.3904013872216063e-03, 8.2379096963313674e-03, 1.7989495266934163e-02, 3.5337848644927512e-02, 6.2489606495141174e-02, 9.9539560539641095e-02, 1.4289781614596173e-01, 1.8495601933162914e-01, 2.1589660563060412e-01, 2.2731610876192898e-01, 2.1589660563060412e-01, 1.8495601933162914e-01, 1.4289781614596173e-01, 9.9539560539641095e-02, 6.2489606495141174e-02, 3.5337848644927512e-02, 1.7989495266934163e-02, 8.2379096963313674e-03, 3.3904013872216063e-03, 1.2527946608682095e-03, 4.1514601828721595e-04, 1.2321031502033358e-04, 3.2702654980222023e-05, 7.7499739996840847e-06, 1.6368618884967503e-06, 3.0750156860401326e-07, 5.1267694307391355e-08, 7.5672777489105014e-09, 9.8619913092006371e-10, 1.1314327929338598e-10, 1.1389647007504889e-11, 1.0023990331996466e-12, 7.6822356519145676e-14, 5.1042859875473367e-15, 2.9258946262067771e-16, 1.4391241588665120e-17, 6.0370235645633800e-19, 2.1453091893671746e-20, 6.4090652642750824e-22, 1.5959112775571386e-23, 3.2802180350829561e-25, 5.5036367600342068e-27, 7.4422174735850754e-29, 7.9915865248767542e-31, 6.6976892723501377e-33, 4.2923202100065188e-35, 2.0525562261562526e-37, 7.1089100355543671e-40, 1.7187588390664908e-42, 2.7688066162395138e-45, 2.7972683193869001e-48, 1.6336381889925197e-51, 4.9175305451785707e-55, 6.4250837772781210e-59, 2.7483088481763178e-63, 2.2507013266634397e-68, 9.0236831042710006e-75}, {1.3153371477011018e-75, 3.4808413877180985e-69, 4.4687024216810169e-64, 1.0933824737518103e-59, 8.7337328359193298e-56, 3.0222939315022155e-52, 5.3832225069701608e-49, 5.5370648197825761e-46, 3.5689385617810602e-43, 1.5317989647111863e-40, 4.5874016658583215e-38, 9.9468000592214207e-36, 1.6088732079384737e-33, 1.9895468942695488e-31, 1.9199707067949033e-29, 1.4712415549741861e-27, 9.0859656470487372e-26, 4.5806010985499422e-24, 1.9062601886875492e-22, 6.6129511764811165e-21, 1.9288793268371580e-19, 4.7668311711866824e-18, 1.0049051491574811e-16, 1.8181691304932292e-15, 2.8387673951693530e-14, 3.8436817248766534e-13, 4.5333033745839362e-12, 4.6760103859850812e-11, 4.2335937835110236e-10, 3.3755847311277282e-09, 2.3773662147574315e-08, 1.4829694050050112e-07, 8.2135445478328264e-07, 4.0482331787772522e-06, 1.7791805918220274e-05, 6.9854324445415533e-05, 2.4541809273052672e-04, 7.7269582168165273e-04, 2.1831319760967165e-03, 5.5416312894389780e-03, 1.2651375112800185e-02, 2.6000340271244451e-02, 4.8139906731089997e-02, 8.0353950080642028e-02, 1.2098311686251535e-01, 1.6437963059849708e-01, 2.0161301347923419e-01, 2.2327002349753469e-01, 2.2327002349753469e-01, 2.0161301347923419e-01, 1.6437963059849708e-01, 1.2098311686251535e-01, 8.0353950080642028e-02, 4.8139906731089997e-02, 2.6000340271244451e-02, 1.2651375112800185e-02, 5.5416312894389780e-03, 2.1831319760967165e-03, 7.7269582168165273e-04, 2.4541809273052672e-04, 6.9854324445415533e-05, 1.7791805918220274e-05, 4.0482331787772522e-06, 8.2135445478328264e-07, 1.4829694050050112e-07, 2.3773662147574315e-08, 3.3755847311277282e-09, 4.2335937835110236e-10, 4.6760103859850812e-11, 4.5333033745839362e-12, 3.8436817248766534e-13, 2.8387673951693530e-14, 1.8181691304932292e-15, 1.0049051491574811e-16, 4.7668311711866824e-18, 1.9288793268371580e-19, 6.6129511764811165e-21, 1.9062601886875492e-22, 4.5806010985499422e-24, 9.0859656470487372e-26, 1.4712415549741861e-27, 1.9199707067949033e-29, 1.9895468942695488e-31, 1.6088732079384737e-33, 9.9468000592214207e-36, 4.5874016658583215e-38, 1.5317989647111863e-40, 3.5689385617810602e-43, 5.5370648197825761e-46, 5.3832225069701608e-49, 3.0222939315022155e-52, 8.7337328359193298e-56, 1.0933824737518103e-59, 4.4687024216810169e-64, 3.4808413877180985e-69, 1.3153371477011018e-75}, {1.9163113126364858e-76, 5.3782147987051925e-70, 7.2563879227687952e-65, 1.8575257861979059e-60, 1.5480113585024239e-56, 5.5781996438680938e-53, 1.0331986095466757e-49, 1.1039698088171895e-46, 7.3860282667906572e-44, 3.2885519707581838e-41, 1.0211695752712912e-38, 2.2950262940501390e-36, 3.8466556677503065e-34, 4.9282126606183490e-32, 4.9266058774066898e-30, 3.9104187247799965e-28, 2.5014139383687256e-26, 1.3062311410367629e-24, 5.6310279110780034e-23, 2.0237140711644305e-21, 6.1159230112779824e-20, 1.5662392354042098e-18, 3.4222031640236014e-17, 6.4188994417848841e-16, 1.0392178377829332e-14, 1.4594559933116930e-13, 1.7858814626910534e-12, 1.9118156866346926e-11, 1.7970567599571068e-10, 1.4881403983681883e-09, 1.0889411432936255e-08, 7.0605103886976605e-08, 4.0665248009122635e-07, 2.0852201445349388e-06, 9.5392954689367993e-06, 3.9005661581998708e-05, 1.4279713128781597e-04, 4.6876282593032669e-04, 1.3817279615374414e-03, 3.6614915226082989e-03, 8.7323289056329013e-03, 1.8760838951499537e-02, 3.6339904964249992e-02, 6.3508495757082825e-02, 1.0019666687230201e-01, 1.4277636364566415e-01, 1.8382375801093334e-01, 2.1389634702935822e-01, 2.2497264372314615e-01, 2.1389634702935822e-01, 1.8382375801093334e-01, 1.4277636364566415e-01, 1.0019666687230201e-01, 6.3508495757082825e-02, 3.6339904964249992e-02, 1.8760838951499537e-02, 8.7323289056329013e-03, 3.6614915226082989e-03, 1.3817279615374414e-03, 4.6876282593032669e-04, 1.4279713128781597e-04, 3.9005661581998708e-05, 9.5392954689367993e-06, 2.0852201445349388e-06, 4.0665248009122635e-07, 7.0605103886976605e-08, 1.0889411432936255e-08, 1.4881403983681883e-09, 1.7970567599571068e-10, 1.9118156866346926e-11, 1.7858814626910534e-12, 1.4594559933116930e-13, 1.0392178377829332e-14, 6.4188994417848841e-16, 3.4222031640236014e-17, 1.5662392354042098e-18, 6.1159230112779824e-20, 2.0237140711644305e-21, 5.6310279110780034e-23, 1.3062311410367629e-24, 2.5014139383687256e-26, 3.9104187247799965e-28, 4.9266058774066898e-30, 4.9282126606183490e-32, 3.8466556677503065e-34, 2.2950262940501390e-36, 1.0211695752712912e-38, 3.2885519707581838e-41, 7.3860282667906572e-44, 1.1039698088171895e-46, 1.0331986095466757e-49, 5.5781996438680938e-53, 1.5480113585024239e-56, 1.8575257861979059e-60, 7.2563879227687952e-65, 5.3782147987051925e-70, 1.9163113126364858e-76}, {2.7904525118679737e-77, 8.3020782212471425e-71, 1.1767736856636937e-65, 3.1505048454950654e-61, 2.7383297861245024e-57, 1.0271804264134620e-53, 1.9777901946758928e-50, 2.1945724897613748e-47, 1.5235549200899557e-44, 7.0346474438870195e-42, 2.2642373940609524e-39, 5.2728051887223330e-37, 9.1548141716730934e-35, 1.2147369169275739e-32, 1.2575027798926635e-30, 1.0335182999889521e-28, 6.8454256421150675e-27, 3.7013456293648089e-25, 1.6522412624655730e-23, 6.1491894101104838e-22, 1.9247067870562822e-20, 5.1057396537975428e-19, 1.1557955215269003e-17, 2.2464616952811288e-16, 3.7697131696054083e-15, 5.4886703549372233e-14, 6.9650658814205409e-13, 7.7347769030963229e-12, 7.5445969018975008e-11, 6.4855152005816811e-10, 4.9282840753506927e-09, 3.3196572232173258e-08, 1.9871572271899896e-07, 1.0595200143943266e-06, 5.0423148877264742e-06, 2.1459377904439359e-05, 8.1811800690556602e-05, 2.7983364446273394e-04, 8.5995448443042602e-04, 2.3773109222215024e-03, 5.9185523609855805e-03, 1.3282862169963864e-02, 2.6896050260216100e-02, 4.9173217905643024e-02, 8.1224149327040002e-02, 1.2127838443962285e-01, 1.6375781072963536e-01, 2.0002035034474053e-01, 2.2104883827723254e-01, 2.2104883827723254e-01, 2.0002035034474053e-01, 1.6375781072963536e-01, 1.2127838443962285e-01, 8.1224149327040002e-02, 4.9173217905643024e-02, 2.6896050260216100e-02, 1.3282862169963864e-02, 5.9185523609855805e-03, 2.3773109222215024e-03, 8.5995448443042602e-04, 2.7983364446273394e-04, 8.1811800690556602e-05, 2.1459377904439359e-05, 5.0423148877264742e-06, 1.0595200143943266e-06, 1.9871572271899896e-07, 3.3196572232173258e-08, 4.9282840753506927e-09, 6.4855152005816811e-10, 7.5445969018975008e-11, 7.7347769030963229e-12, 6.9650658814205409e-13, 5.4886703549372233e-14, 3.7697131696054083e-15, 2.2464616952811288e-16, 1.1557955215269003e-17, 5.1057396537975428e-19, 1.9247067870562822e-20, 6.1491894101104838e-22, 1.6522412624655730e-23, 3.7013456293648089e-25, 6.8454256421150675e-27, 1.0335182999889521e-28, 1.2575027798926635e-30, 1.2147369169275739e-32, 9.1548141716730934e-35, 5.2728051887223330e-37, 2.2642373940609524e-39, 7.0346474438870195e-42, 1.5235549200899557e-44, 2.1945724897613748e-47, 1.9777901946758928e-50, 1.0271804264134620e-53, 2.7383297861245024e-57, 3.1505048454950654e-61, 1.1767736856636937e-65, 8.3020782212471425e-71, 2.7904525118679737e-77}, {4.0613138578260408e-78, 1.2803753168202646e-71, 1.9059379634157273e-66, 5.3348322229477923e-62, 4.8344851717020582e-58, 1.8871785659984032e-54, 3.7761789448607101e-51, 4.3499235924727088e-48, 3.1326162048099509e-45, 1.4994923130410846e-42, 5.0011700959096005e-40, 1.2063719426097628e-37, 2.1689987827926264e-35, 2.9797144315839396e-33, 3.1931805290733206e-31, 2.7165497805935431e-29, 1.8623802130980743e-27, 1.0423117478273709e-25, 4.8161473163605573e-24, 1.8555204994489541e-22, 6.0128622969968872e-21, 1.6515980171005252e-19, 3.8719360930637078e-18, 7.7952821069111630e-17, 1.3552585228326797e-15, 2.0448819688025393e-14, 2.6898645575023506e-13, 3.0973073233390342e-12, 3.1335844312742886e-11, 2.7949011969950757e-10, 2.2044098210910168e-09, 1.5418168139637173e-08, 9.5872357774191023e-08, 5.3122836336339743e-07, 2.6285303500427774e-06, 1.1636493707975660e-05, 4.6170574104968263e-05, 1.6444759671629532e-04, 5.2653510513586970e-04, 1.5174715210062894e-03, 3.9409789851024037e-03, 9.2324971205438137e-03, 1.9527821414966836e-02, 3.7320312768871315e-02, 6.4488485276268173e-02, 1.0081054546716739e-01, 1.4263049549711082e-01, 1.8270590844100287e-01, 2.1195024923496616e-01, 2.2270019277644792e-01, 2.1195024923496616e-01, 1.8270590844100287e-01, 1.4263049549711082e-01, 1.0081054546716739e-01, 6.4488485276268173e-02, 3.7320312768871315e-02, 1.9527821414966836e-02, 9.2324971205438137e-03, 3.9409789851024037e-03, 1.5174715210062894e-03, 5.2653510513586970e-04, 1.6444759671629532e-04, 4.6170574104968263e-05, 1.1636493707975660e-05, 2.6285303500427774e-06, 5.3122836336339743e-07, 9.5872357774191023e-08, 1.5418168139637173e-08, 2.2044098210910168e-09, 2.7949011969950757e-10, 3.1335844312742886e-11, 3.0973073233390342e-12, 2.6898645575023506e-13, 2.0448819688025393e-14, 1.3552585228326797e-15, 7.7952821069111630e-17, 3.8719360930637078e-18, 1.6515980171005252e-19, 6.0128622969968872e-21, 1.8555204994489541e-22, 4.8161473163605573e-24, 1.0423117478273709e-25, 1.8623802130980743e-27, 2.7165497805935431e-29, 3.1931805290733206e-31, 2.9797144315839396e-33, 2.1689987827926264e-35, 1.2063719426097628e-37, 5.0011700959096005e-40, 1.4994923130410846e-42, 3.1326162048099509e-45, 4.3499235924727088e-48, 3.7761789448607101e-51, 1.8871785659984032e-54, 4.8344851717020582e-58, 5.3348322229477923e-62, 1.9059379634157273e-66, 1.2803753168202646e-71, 4.0613138578260408e-78}, {5.9080678650312624e-79, 1.9728605748792453e-72, 3.0830289900033436e-67, 9.0192223036937046e-63, 8.5188830817618133e-59, 3.4594779364755318e-55, 7.1915294634635365e-52, 8.5975639548257647e-49, 6.4207252053484628e-46, 3.1852178778360094e-43, 1.1004706827142279e-40, 2.7487848843571218e-38, 5.1162326043852910e-36, 7.2745725968876294e-34, 8.0674342787094055e-32, 7.1018122263849361e-30, 5.0377911662132328e-28, 2.9173500726293596e-26, 1.3948415260687786e-24, 5.5610269616591533e-23, 1.8649976751302685e-21, 5.3023161831319081e-20, 1.2868329211211647e-18, 2.6824921647604057e-17, 4.8298353217030778e-16, 7.5488968779152708e-15, 1.0288749373509957e-13, 1.2278785144101270e-12, 1.2879038257315668e-11, 1.1913006349290762e-10, 9.7479212538717177e-10, 7.0758572838895756e-09, 4.5681275084849536e-08, 2.6290974837537234e-07, 1.3517971591103712e-06, 6.2215248177778678e-06, 2.5676159384549134e-05, 9.5171627785509925e-05, 3.1729197104330006e-04, 9.5269218854862072e-04, 2.5792732600590893e-03, 6.3030002856080628e-03, 1.3915665220231790e-02, 2.7779127385933564e-02, 5.0175812677428613e-02, 8.2051827391224449e-02, 1.2153798684410418e-01, 1.6313003050278282e-01, 1.9846285025418653e-01, 2.1889262958743932e-01, 2.1889262958743932e-01, 1.9846285025418653e-01, 1.6313003050278282e-01, 1.2153798684410418e-01, 8.2051827391224449e-02, 5.0175812677428613e-02, 2.7779127385933564e-02, 1.3915665220231790e-02, 6.3030002856080628e-03, 2.5792732600590893e-03, 9.5269218854862072e-04, 3.1729197104330006e-04, 9.5171627785509925e-05, 2.5676159384549134e-05, 6.2215248177778678e-06, 1.3517971591103712e-06, 2.6290974837537234e-07, 4.5681275084849536e-08, 7.0758572838895756e-09, 9.7479212538717177e-10, 1.1913006349290762e-10, 1.2879038257315668e-11, 1.2278785144101270e-12, 1.0288749373509957e-13, 7.5488968779152708e-15, 4.8298353217030778e-16, 2.6824921647604057e-17, 1.2868329211211647e-18, 5.3023161831319081e-20, 1.8649976751302685e-21, 5.5610269616591533e-23, 1.3948415260687786e-24, 2.9173500726293596e-26, 5.0377911662132328e-28, 7.1018122263849361e-30, 8.0674342787094055e-32, 7.2745725968876294e-34, 5.1162326043852910e-36, 2.7487848843571218e-38, 1.1004706827142279e-40, 3.1852178778360094e-43, 6.4207252053484628e-46, 8.5975639548257647e-49, 7.1915294634635365e-52, 3.4594779364755318e-55, 8.5188830817618133e-59, 9.0192223036937046e-63, 3.0830289900033436e-67, 1.9728605748792453e-72, 5.9080678650312624e-79}, {8.5904309894818364e-80, 3.0371816846686698e-73, 4.9809124279561082e-68, 1.5224294774877133e-63, 1.4982961830544962e-59, 6.3278572616256388e-56, 1.3661743924144741e-52, 1.6945475116309319e-49, 1.3119398711365523e-46, 6.7430272036894988e-44, 2.4125325785224105e-41, 6.2381218594744620e-39, 1.2015973481338649e-36, 1.7677477939830743e-34, 2.0280915379277212e-32, 1.8467949790116279e-30, 1.3550808933459723e-28, 8.1168066229507355e-27, 4.0142573977672800e-25, 1.6555633107937502e-23, 5.7440707561477782e-22, 1.6897039658922656e-20, 4.2436086794049572e-19, 9.1557867438886624e-18, 1.7065546359370669e-16, 2.7618433228960722e-15, 3.8986379094133088e-14, 4.8201156943039955e-13, 5.2391878407492571e-12, 5.0236198872007664e-11, 4.2625383198445261e-10, 3.2096074629923419e-09, 2.1502703382505708e-08, 1.2847504869574726e-07, 6.8606640833299067e-07, 3.2808733242412502e-06, 1.4075589850899586e-05, 5.4263099453546539e-05, 1.8825409449540776e-04, 5.8852552673756763e-04, 1.6599244925103198e-03, 4.2284362004214454e-03, 9.7376438372710882e-03, 2.0289684052787870e-02, 3.8279047715437671e-02, 6.5430893699439191e-02, 1.0138360090162955e-01, 1.4246231456883673e-01, 1.8160258790817957e-01, 2.1005593297000114e-01, 2.2049524037272045e-01, 2.1005593297000114e-01, 1.8160258790817957e-01, 1.4246231456883673e-01, 1.0138360090162955e-01, 6.5430893699439191e-02, 3.8279047715437671e-02, 2.0289684052787870e-02, 9.7376438372710882e-03, 4.2284362004214454e-03, 1.6599244925103198e-03, 5.8852552673756763e-04, 1.8825409449540776e-04, 5.4263099453546539e-05, 1.4075589850899586e-05, 3.2808733242412502e-06, 6.8606640833299067e-07, 1.2847504869574726e-07, 2.1502703382505708e-08, 3.2096074629923419e-09, 4.2625383198445261e-10, 5.0236198872007664e-11, 5.2391878407492571e-12, 4.8201156943039955e-13, 3.8986379094133088e-14, 2.7618433228960722e-15, 1.7065546359370669e-16, 9.1557867438886624e-18, 4.2436086794049572e-19, 1.6897039658922656e-20, 5.7440707561477782e-22, 1.6555633107937502e-23, 4.0142573977672800e-25, 8.1168066229507355e-27, 1.3550808933459723e-28, 1.8467949790116279e-30, 2.0280915379277212e-32, 1.7677477939830743e-34, 1.2015973481338649e-36, 6.2381218594744620e-39, 2.4125325785224105e-41, 6.7430272036894988e-44, 1.3119398711365523e-46, 1.6945475116309319e-49, 1.3661743924144741e-52, 6.3278572616256388e-56, 1.4982961830544962e-59, 1.5224294774877133e-63, 4.9809124279561082e-68, 3.0371816846686698e-73, 8.5904309894818364e-80}, {1.2484709934169793e-80, 4.6716134267455262e-74, 8.0373302337190505e-69, 2.5658825214250866e-64, 2.6303256479665557e-60, 1.1549629962198519e-56, 2.5889667003232748e-53, 3.3307225187898004e-50, 2.6725211308631837e-47, 1.4227172891228852e-44, 5.2696956176078606e-42, 1.4101103127648418e-39, 2.8100935042395224e-37, 4.2761357132188511e-35, 5.0736585413756089e-33, 4.7776103023740991e-31, 3.6248608340202214e-29, 2.2451158851842135e-27, 1.1481416337131872e-25, 4.8966201179064703e-24, 1.7569837815084929e-22, 5.3457088341630912e-21, 1.3887935290404047e-19, 3.1001141967930157e-18, 5.9794936879871788e-17, 1.0016087747850758e-15, 1.4637583603666311e-14, 1.8740601774404304e-13, 2.1099943426302045e-12, 2.0963143669741310e-11, 1.8436168972317116e-10, 1.4393514257953216e-09, 1.0001836240436016e-08, 6.2007747893151711e-08, 3.4372586316527799e-07, 1.7070358456037084e-06, 7.6089581259975007e-06, 3.0491388427439179e-05, 1.1001458276280751e-04, 3.5787758856259302e-04, 1.0509023763580526e-03, 2.7887647298672400e-03, 6.6943659482095498e-03, 1.4548976670515633e-02, 2.8649120680685196e-02, 5.1148315515202297e-02, 8.2838910302204208e-02, 1.2176431106358794e-01, 1.6249750087283824e-01, 1.9693934921359804e-01, 2.1679829114353039e-01, 2.1679829114353039e-01, 1.9693934921359804e-01, 1.6249750087283824e-01, 1.2176431106358794e-01, 8.2838910302204208e-02, 5.1148315515202297e-02, 2.8649120680685196e-02, 1.4548976670515633e-02, 6.6943659482095498e-03, 2.7887647298672400e-03, 1.0509023763580526e-03, 3.5787758856259302e-04, 1.1001458276280751e-04, 3.0491388427439179e-05, 7.6089581259975007e-06, 1.7070358456037084e-06, 3.4372586316527799e-07, 6.2007747893151711e-08, 1.0001836240436016e-08, 1.4393514257953216e-09, 1.8436168972317116e-10, 2.0963143669741310e-11, 2.1099943426302045e-12, 1.8740601774404304e-13, 1.4637583603666311e-14, 1.0016087747850758e-15, 5.9794936879871788e-17, 3.1001141967930157e-18, 1.3887935290404047e-19, 5.3457088341630912e-21, 1.7569837815084929e-22, 4.8966201179064703e-24, 1.1481416337131872e-25, 2.2451158851842135e-27, 3.6248608340202214e-29, 4.7776103023740991e-31, 5.0736585413756089e-33, 4.2761357132188511e-35, 2.8100935042395224e-37, 1.4101103127648418e-39, 5.2696956176078606e-42, 1.4227172891228852e-44, 2.6725211308631837e-47, 3.3307225187898004e-50, 2.5889667003232748e-53, 1.1549629962198519e-56, 2.6303256479665557e-60, 2.5658825214250866e-64, 8.0373302337190505e-69, 4.6716134267455262e-74, 1.2484709934169793e-80}, {1.8135909934565948e-81, 7.1794482518779405e-75, 1.2953741930788741e-69, 4.3179663130756179e-65, 4.6092689309993016e-61, 2.1035897073764635e-57, 4.8944169739176386e-54, 6.5290610509647759e-51, 5.4278702104818919e-48, 2.9919651066058538e-45, 1.1469498354442222e-42, 3.1751925459280292e-40, 6.5444038132328712e-38, 1.0297652702618718e-35, 1.2632131984833186e-33, 1.2296697906080111e-31, 9.6441699135755975e-30, 6.1744578340056585e-28, 3.2639881507273933e-26, 1.4390083206149803e-24, 5.3380455822882838e-23, 1.6792427517695717e-21, 4.5112507797362053e-20, 1.0414929706906582e-18, 2.0779783402868767e-17, 3.6013157967372950e-16, 5.4464951383584157e-15, 7.2181098533397167e-14, 8.4145383929577368e-13, 8.6584557144940455e-12, 7.8890516800983647e-11, 6.3831524130277722e-10, 4.5984942968861874e-09, 2.9567316716160832e-08, 1.7005133441347446e-07, 8.7658428229201604e-07, 4.0574245645905015e-06, 1.6891865749199694e-05, 6.3348592408607267e-05, 2.1430344005210969e-04, 6.5478304395432502e-04, 1.8089687249743006e-03, 4.5234328605134695e-03, 1.0247034345774014e-02, 2.1045743544451385e-02, 3.9216150726808105e-02, 6.6337015149646864e-02, 1.0191809344727074e-01, 1.4227374613665661e-01, 1.8051385843527265e-01, 2.0821116124461711e-01, 2.1835450988366478e-01, 2.0821116124461711e-01, 1.8051385843527265e-01, 1.4227374613665661e-01, 1.0191809344727074e-01, 6.6337015149646864e-02, 3.9216150726808105e-02, 2.1045743544451385e-02, 1.0247034345774014e-02, 4.5234328605134695e-03, 1.8089687249743006e-03, 6.5478304395432502e-04, 2.1430344005210969e-04, 6.3348592408607267e-05, 1.6891865749199694e-05, 4.0574245645905015e-06, 8.7658428229201604e-07, 1.7005133441347446e-07, 2.9567316716160832e-08, 4.5984942968861874e-09, 6.3831524130277722e-10, 7.8890516800983647e-11, 8.6584557144940455e-12, 8.4145383929577368e-13, 7.2181098533397167e-14, 5.4464951383584157e-15, 3.6013157967372950e-16, 2.0779783402868767e-17, 1.0414929706906582e-18, 4.5112507797362053e-20, 1.6792427517695717e-21, 5.3380455822882838e-23, 1.4390083206149803e-24, 3.2639881507273933e-26, 6.1744578340056585e-28, 9.6441699135755975e-30, 1.2296697906080111e-31, 1.2632131984833186e-33, 1.0297652702618718e-35, 6.5444038132328712e-38, 3.1751925459280292e-40, 1.1469498354442222e-42, 2.9919651066058538e-45, 5.4278702104818919e-48, 6.5290610509647759e-51, 4.8944169739176386e-54, 2.1035897073764635e-57, 4.6092689309993016e-61, 4.3179663130756179e-65, 1.2953741930788741e-69, 7.1794482518779405e-75, 1.8135909934565948e-81}, {2.6333035610382397e-82, 1.1024259296315383e-75, 2.0852967445741233e-70, 7.2556400241843898e-66, 8.0626671773555472e-62, 3.8234147683158063e-58, 9.2309809923115915e-55, 1.2764717039702522e-51, 1.0991625015027042e-48, 6.2718288470036324e-46, 2.4875851238977396e-43, 7.1225496037923785e-41, 1.5178899706379763e-38, 2.4689751624056617e-36, 3.1303492079755755e-34, 3.1491543092696820e-32, 2.5522940793940470e-30, 1.6885482670813982e-28, 9.2239272353929576e-27, 4.2024365472164892e-25, 1.6110964547970300e-23, 5.2383797573874037e-22, 1.4547178325694397e-20, 3.4721710760327322e-19, 7.1634722023972862e-18, 1.2840032078315100e-16, 2.0088075710888178e-15, 2.7546357750311648e-14, 3.3235533916670117e-13, 3.5405078866592410e-12, 3.3406627081403544e-11, 2.8000417787301215e-10, 2.0903260822482034e-09, 1.3932720755460754e-08, 8.3098897726797486e-08, 4.4440079875949290e-07, 2.1349200492771325e-06, 9.2289528191432300e-06, 3.5954963665620299e-05, 1.2641879089097217e-04, 4.0166542717281779e-04, 1.1545621668817155e-03, 3.0055192270927668e-03, 7.0920553324460628e-03, 1.5182046088138676e-02, 2.9505655023499801e-02, 5.2091376675144491e-02, 8.3587237918301055e-02, 1.2195957249370640e-01, 1.6186130554382056e-01, 1.9544872749879730e-01, 2.1476292059027455e-01, 2.1476292059027455e-01, 1.9544872749879730e-01, 1.6186130554382056e-01, 1.2195957249370640e-01, 8.3587237918301055e-02, 5.2091376675144491e-02, 2.9505655023499801e-02, 1.5182046088138676e-02, 7.0920553324460628e-03, 3.0055192270927668e-03, 1.1545621668817155e-03, 4.0166542717281779e-04, 1.2641879089097217e-04, 3.5954963665620299e-05, 9.2289528191432300e-06, 2.1349200492771325e-06, 4.4440079875949290e-07, 8.3098897726797486e-08, 1.3932720755460754e-08, 2.0903260822482034e-09, 2.8000417787301215e-10, 3.3406627081403544e-11, 3.5405078866592410e-12, 3.3235533916670117e-13, 2.7546357750311648e-14, 2.0088075710888178e-15, 1.2840032078315100e-16, 7.1634722023972862e-18, 3.4721710760327322e-19, 1.4547178325694397e-20, 5.2383797573874037e-22, 1.6110964547970300e-23, 4.2024365472164892e-25, 9.2239272353929576e-27, 1.6885482670813982e-28, 2.5522940793940470e-30, 3.1491543092696820e-32, 3.1303492079755755e-34, 2.4689751624056617e-36, 1.5178899706379763e-38, 7.1225496037923785e-41, 2.4875851238977396e-43, 6.2718288470036324e-46, 1.0991625015027042e-48, 1.2764717039702522e-51, 9.2309809923115915e-55, 3.8234147683158063e-58, 8.0626671773555472e-62, 7.2556400241843898e-66, 2.0852967445741233e-70, 1.1024259296315383e-75, 2.6333035610382397e-82}, {3.8217861138085193e-83, 1.6914062097101716e-76, 3.3530353599320843e-71, 1.2174103962049957e-66, 1.4078704255855603e-62, 6.9351300068921097e-59, 1.7369401373650657e-55, 2.4890859009540812e-52, 2.2194272123488213e-49, 1.3105586296104345e-46, 5.3766702664810952e-44, 1.5917657474423608e-41, 3.5064188455904165e-39, 5.8941611353204651e-37, 7.7216030296457281e-35, 8.0254188497506414e-33, 6.7194313102734894e-31, 4.5922904136653062e-29, 2.5914755539513213e-27, 1.2197280334801351e-25, 4.8310543796668917e-24, 1.6229893391874090e-22, 4.6574324658183078e-21, 1.1488922069252337e-19, 2.4500971300072567e-18, 4.5403372361053743e-17, 7.3453513452694623e-16, 1.0418125668654998e-14, 1.3004299981305270e-13, 1.4335908364459435e-12, 1.4002082648585132e-11, 1.2152299982982779e-10, 9.3968905695997315e-10, 6.4898261604097228e-09, 4.0121667112572270e-08, 2.2249156377389857e-07, 1.1087989233089753e-06, 4.9744232013977632e-06, 2.0121686738026826e-05, 7.3491681493347192e-05, 2.4267655305986469e-04, 7.2534332143885018e-04, 1.9644706290361147e-03, 4.8255384821498035e-03, 1.0759969971184533e-02, 2.1795386765479520e-02, 4.0131719533568026e-02, 6.7208115842432761e-02, 1.0241614803131452e-01, 1.4206655437043109e-01, 1.7943973488563147e-01, 2.0641382873539532e-01, 2.1627494312286819e-01, 2.0641382873539532e-01, 1.7943973488563147e-01, 1.4206655437043109e-01, 1.0241614803131452e-01, 6.7208115842432761e-02, 4.0131719533568026e-02, 2.1795386765479520e-02, 1.0759969971184533e-02, 4.8255384821498035e-03, 1.9644706290361147e-03, 7.2534332143885018e-04, 2.4267655305986469e-04, 7.3491681493347192e-05, 2.0121686738026826e-05, 4.9744232013977632e-06, 1.1087989233089753e-06, 2.2249156377389857e-07, 4.0121667112572270e-08, 6.4898261604097228e-09, 9.3968905695997315e-10, 1.2152299982982779e-10, 1.4002082648585132e-11, 1.4335908364459435e-12, 1.3004299981305270e-13, 1.0418125668654998e-14, 7.3453513452694623e-16, 4.5403372361053743e-17, 2.4500971300072567e-18, 1.1488922069252337e-19, 4.6574324658183078e-21, 1.6229893391874090e-22, 4.8310543796668917e-24, 1.2197280334801351e-25, 2.5914755539513213e-27, 4.5922904136653062e-29, 6.7194313102734894e-31, 8.0254188497506414e-33, 7.7216030296457281e-35, 5.8941611353204651e-37, 3.5064188455904165e-39, 1.5917657474423608e-41, 5.3766702664810952e-44, 1.3105586296104345e-46, 2.2194272123488213e-49, 2.4890859009540812e-52, 1.7369401373650657e-55, 6.9351300068921097e-59, 1.4078704255855603e-62, 1.2174103962049957e-66, 3.3530353599320843e-71, 1.6914062097101716e-76, 3.8217861138085193e-83}, {5.5441992722068482e-84, 2.5929395481292082e-77, 5.3853541853574509e-72, 2.0397343220146265e-67, 2.4541249535874453e-63, 1.2554100822781216e-59, 3.2608376921091931e-56, 4.8412365544964550e-53, 4.4687726007935870e-50, 2.7300300393618730e-47, 1.1581833176995228e-44, 3.5442966005156755e-42, 8.0681149793680242e-40, 1.4011614007496688e-37, 1.8960834059704929e-35, 2.0353977109818878e-33, 1.7599996574525402e-31, 1.2422004027168656e-29, 7.2392001895975213e-28, 3.5188457649983255e-26, 1.4394549700596331e-24, 4.9949088636257322e-23, 1.4806823585568918e-21, 3.7736012205435806e-20, 8.3155142767475590e-19, 1.5925756694175446e-17, 2.6632797443869722e-16, 3.9055385475699820e-15, 5.0416061378516563e-14, 5.7492300646009343e-13, 5.8103188163962404e-12, 5.2193608370012943e-11, 4.1786070059665728e-10, 2.9889202437814213e-09, 1.9144674266312151e-08, 1.1003547442210821e-07, 5.6858218763614167e-07, 2.6459673129317030e-06, 1.1106993480718368e-05, 4.2117165655971054e-05, 1.4445933891050312e-04, 4.4872081587300148e-04, 1.2636334832367285e-03, 3.2292611575356744e-03, 7.4954912038533066e-03, 1.5814177885623497e-02, 3.0348423943327270e-02, 5.3005665528953826e-02, 8.4298566514348958e-02, 1.2212582857840716e-01, 1.6122241452497918e-01, 1.9398990851223818e-01, 2.1278380261127008e-01, 2.1278380261127008e-01, 1.9398990851223818e-01, 1.6122241452497918e-01, 1.2212582857840716e-01, 8.4298566514348958e-02, 5.3005665528953826e-02, 3.0348423943327270e-02, 1.5814177885623497e-02, 7.4954912038533066e-03, 3.2292611575356744e-03, 1.2636334832367285e-03, 4.4872081587300148e-04, 1.4445933891050312e-04, 4.2117165655971054e-05, 1.1106993480718368e-05, 2.6459673129317030e-06, 5.6858218763614167e-07, 1.1003547442210821e-07, 1.9144674266312151e-08, 2.9889202437814213e-09, 4.1786070059665728e-10, 5.2193608370012943e-11, 5.8103188163962404e-12, 5.7492300646009343e-13, 5.0416061378516563e-14, 3.9055385475699820e-15, 2.6632797443869722e-16, 1.5925756694175446e-17, 8.3155142767475590e-19, 3.7736012205435806e-20, 1.4806823585568918e-21, 4.9949088636257322e-23, 1.4394549700596331e-24, 3.5188457649983255e-26, 7.2392001895975213e-28, 1.2422004027168656e-29, 1.7599996574525402e-31, 2.0353977109818878e-33, 1.8960834059704929e-35, 1.4011614007496688e-37, 8.0681149793680242e-40, 3.5442966005156755e-42, 1.1581833176995228e-44, 2.7300300393618730e-47, 4.4687726007935870e-50, 4.8412365544964550e-53, 3.2608376921091931e-56, 1.2554100822781216e-59, 2.4541249535874453e-63, 2.0397343220146265e-67, 5.3853541853574509e-72, 2.5929395481292082e-77, 5.5441992722068482e-84}, {8.0393570948066263e-85, 3.9718103441759187e-78, 8.6398120096864360e-73, 3.4126815525065270e-68, 4.2706414980124341e-64, 2.2680834264069969e-60, 6.1079802227760500e-57, 9.3924613692270336e-54, 8.9727413440350903e-51, 5.6695759907967620e-48, 2.4865399657656492e-45, 7.8635083915713631e-43, 1.8492505278934263e-40, 3.3170216420826621e-38, 4.6353055637591542e-36, 5.1377976964188761e-34, 4.5868230110636832e-32, 3.3422916829863083e-30, 2.0109122099933846e-28, 1.0091662170872907e-26, 4.2622901606926843e-25, 1.5271754441949008e-23, 4.6750298903216843e-22, 1.2305362144434042e-20, 2.8009656241231101e-19, 5.5420769366655970e-18, 9.5769111189688996e-17, 1.4514991221804437e-15, 1.9370075854564139e-14, 2.2840535977994185e-13, 2.3875175115445612e-12, 2.2189005868460593e-11, 1.8384761407124325e-10, 1.3614036372254147e-09, 9.0305672540467943e-09, 5.3771344014689486e-08, 2.8795698296534307e-07, 1.3893404522738127e-06, 6.0491308542217258e-06, 2.3802318133010187e-05, 8.4755918374596230e-05, 2.7344820329821672e-04, 8.0022923976588462e-04, 2.1262829728506513e-03, 5.1343246513282466e-03, 1.1275787985601648e-02, 2.2538065887400437e-02, 4.1025901106205930e-02, 6.8045431494172207e-02, 1.0287976270898229e-01, 1.4184235712795296e-01, 1.7838019194959490e-01, 2.0466195210272575e-01, 2.1425368197218711e-01, 2.0466195210272575e-01, 1.7838019194959490e-01, 1.4184235712795296e-01, 1.0287976270898229e-01, 6.8045431494172207e-02, 4.1025901106205930e-02, 2.2538065887400437e-02, 1.1275787985601648e-02, 5.1343246513282466e-03, 2.1262829728506513e-03, 8.0022923976588462e-04, 2.7344820329821672e-04, 8.4755918374596230e-05, 2.3802318133010187e-05, 6.0491308542217258e-06, 1.3893404522738127e-06, 2.8795698296534307e-07, 5.3771344014689486e-08, 9.0305672540467943e-09, 1.3614036372254147e-09, 1.8384761407124325e-10, 2.2189005868460593e-11, 2.3875175115445612e-12, 2.2840535977994185e-13, 1.9370075854564139e-14, 1.4514991221804437e-15, 9.5769111189688996e-17, 5.5420769366655970e-18, 2.8009656241231101e-19, 1.2305362144434042e-20, 4.6750298903216843e-22, 1.5271754441949008e-23, 4.2622901606926843e-25, 1.0091662170872907e-26, 2.0109122099933846e-28, 3.3422916829863083e-30, 4.5868230110636832e-32, 5.1377976964188761e-34, 4.6353055637591542e-36, 3.3170216420826621e-38, 1.8492505278934263e-40, 7.8635083915713631e-43, 2.4865399657656492e-45, 5.6695759907967620e-48, 8.9727413440350903e-51, 9.3924613692270336e-54, 6.1079802227760500e-57, 2.2680834264069969e-60, 4.2706414980124341e-64, 3.4126815525065270e-68, 8.6398120096864360e-73, 3.9718103441759187e-78, 8.0393570948066263e-85}, {1.1652438369940990e-85, 6.0791348825232945e-79, 1.3845734727539209e-73, 5.7018195541180805e-69, 7.4193203262024338e-65, 4.0896774498494807e-61, 1.1415803801508950e-57, 1.8177229307902597e-54, 1.7966861107994258e-51, 1.1738936354016808e-48, 5.3209955905676318e-46, 1.7384628972964638e-43, 4.2224503669018324e-41, 7.8205013430131660e-39, 1.1282489276123687e-36, 1.2908866148089198e-34, 1.1895168657985647e-32, 8.9460231384332668e-31, 5.5552056820850460e-29, 2.8773904696541066e-27, 1.2543771045577858e-25, 4.6393197457827112e-24, 1.4661278293822309e-22, 3.9843331940864138e-21, 9.3649180986702086e-20, 1.9137000334222806e-18, 3.4159437284687078e-17, 5.3490074750121478e-16, 7.3765684098315642e-15, 8.9908236810354557e-14, 9.7167575155334535e-13, 9.3392850013870488e-12, 8.0050126851044650e-11, 6.1341491782010079e-10, 4.2120058561600563e-09, 2.5970629339726590e-08, 1.4407085283844865e-07, 7.2034690286882965e-07, 3.2515206739898432e-06, 1.3269605500302639e-05, 4.9028384509802042e-05, 1.6420793698012457e-04, 4.9909954967131240e-04, 1.3780641953787555e-03, 3.4597075988944920e-03, 7.9041144380998778e-03, 1.6444728895483641e-02, 3.1177182981317560e-02, 5.3891864826823496e-02, 8.4974571583542949e-02, 1.2226499127815092e-01, 1.6058169612107806e-01, 1.9256185751562635e-01, 2.1085839371676188e-01, 2.1085839371676188e-01, 1.9256185751562635e-01, 1.6058169612107806e-01, 1.2226499127815092e-01, 8.4974571583542949e-02, 5.3891864826823496e-02, 3.1177182981317560e-02, 1.6444728895483641e-02, 7.9041144380998778e-03, 3.4597075988944920e-03, 1.3780641953787555e-03, 4.9909954967131240e-04, 1.6420793698012457e-04, 4.9028384509802042e-05, 1.3269605500302639e-05, 3.2515206739898432e-06, 7.2034690286882965e-07, 1.4407085283844865e-07, 2.5970629339726590e-08, 4.2120058561600563e-09, 6.1341491782010079e-10, 8.0050126851044650e-11, 9.3392850013870488e-12, 9.7167575155334535e-13, 8.9908236810354557e-14, 7.3765684098315642e-15, 5.3490074750121478e-16, 3.4159437284687078e-17, 1.9137000334222806e-18, 9.3649180986702086e-20, 3.9843331940864138e-21, 1.4661278293822309e-22, 4.6393197457827112e-24, 1.2543771045577858e-25, 2.8773904696541066e-27, 5.5552056820850460e-29, 8.9460231384332668e-31, 1.1895168657985647e-32, 1.2908866148089198e-34, 1.1282489276123687e-36, 7.8205013430131660e-39, 4.2224503669018324e-41, 1.7384628972964638e-43, 5.3209955905676318e-46, 1.1738936354016808e-48, 1.7966861107994258e-51, 1.8177229307902597e-54, 1.1415803801508950e-57, 4.0896774498494807e-61, 7.4193203262024338e-65, 5.7018195541180805e-69, 1.3845734727539209e-73, 6.0791348825232945e-79, 1.1652438369940990e-85}, {1.6882167305707454e-86, 9.2973163909464803e-80, 2.2164453269063499e-74, 9.5134149540243336e-70, 1.2868308966878782e-65, 7.3601988558208524e-62, 2.1289805828564999e-58, 3.5092885496818465e-55, 3.5879758763817130e-52, 2.4233946264708683e-49, 1.1349953099138248e-46, 3.8300452415564833e-44, 9.6052219657335494e-42, 1.8364466079421476e-39, 2.7344551836642605e-37, 3.2286335472886435e-35, 3.0699209573361954e-33, 2.3822649787982913e-31, 1.5263559111336781e-29, 8.1574699196788167e-28, 3.6694695554120368e-26, 1.4004790074896691e-24, 4.5675182897648129e-23, 1.2811473098169559e-21, 3.1084252235905216e-20, 6.5579821121285801e-19, 1.2087664560459120e-17, 1.9548969486564158e-16, 2.7849389834496225e-15, 3.5072844186621564e-14, 3.9175124016391924e-13, 3.8925586774167020e-12, 3.4501563168365539e-11, 2.7347438232977245e-10, 1.9430095134453053e-09, 1.2400464068693708e-08, 7.1228670517261927e-08, 3.6889724023685680e-07, 1.7254610364884881e-06, 7.2997812630457740e-06, 2.7971738168589429e-05, 9.7203453180453000e-05, 3.0668682564469456e-04, 8.7945145983116615e-04, 2.2942465962944290e-03, 5.4493669764638540e-03, 1.1793861247331682e-02, 2.3273293687959880e-02, 4.1898884894253120e-02, 6.8850165394430590e-02, 1.0331081665178690e-01, 1.4160263924602950e-01, 1.7733517017411166e-01, 2.0295366115211383e-01, 2.1228805186235042e-01, 2.0295366115211383e-01, 1.7733517017411166e-01, 1.4160263924602950e-01, 1.0331081665178690e-01, 6.8850165394430590e-02, 4.1898884894253120e-02, 2.3273293687959880e-02, 1.1793861247331682e-02, 5.4493669764638540e-03, 2.2942465962944290e-03, 8.7945145983116615e-04, 3.0668682564469456e-04, 9.7203453180453000e-05, 2.7971738168589429e-05, 7.2997812630457740e-06, 1.7254610364884881e-06, 3.6889724023685680e-07, 7.1228670517261927e-08, 1.2400464068693708e-08, 1.9430095134453053e-09, 2.7347438232977245e-10, 3.4501563168365539e-11, 3.8925586774167020e-12, 3.9175124016391924e-13, 3.5072844186621564e-14, 2.7849389834496225e-15, 1.9548969486564158e-16, 1.2087664560459120e-17, 6.5579821121285801e-19, 3.1084252235905216e-20, 1.2811473098169559e-21, 4.5675182897648129e-23, 1.4004790074896691e-24, 3.6694695554120368e-26, 8.1574699196788167e-28, 1.5263559111336781e-29, 2.3822649787982913e-31, 3.0699209573361954e-33, 3.2286335472886435e-35, 2.7344551836642605e-37, 1.8364466079421476e-39, 9.6052219657335494e-42, 3.8300452415564833e-44, 1.1349953099138248e-46, 2.4233946264708683e-49, 3.5879758763817130e-52, 3.5092885496818465e-55, 2.1289805828564999e-58, 7.3601988558208524e-62, 1.2868308966878782e-65, 9.5134149540243336e-70, 2.2164453269063499e-74, 9.2973163909464803e-80, 1.6882167305707454e-86}, {2.4448842535551943e-87, 1.4208271558885895e-80, 3.5443349838315051e-75, 1.5851638341206613e-70, 2.2283154783345243e-66, 1.3221294591344122e-62, 3.9619475088358356e-59, 6.7588233504303362e-56, 7.1462236088717712e-53, 4.9883667718148639e-50, 2.4133632044032138e-47, 8.4092583458821788e-45, 2.1769699583039015e-42, 4.2954616661119346e-40, 6.5994654800159303e-38, 8.0390389893761170e-36, 7.8853213936624651e-34, 6.3119668181308563e-32, 4.1716030615092882e-30, 2.2997378701939073e-28, 1.0671290531221681e-26, 4.2015271606281150e-25, 1.4137224274155160e-23, 4.0914965094167889e-22, 1.0244196283925887e-20, 2.2306211570300883e-19, 4.2441255956981095e-18, 7.0866359430444936e-17, 1.0425344386668410e-15, 1.3561256356020877e-14, 1.5649369927618164e-13, 1.6069042876497942e-12, 1.4722456305780643e-11, 1.2066201440627706e-10, 8.8669552925941743e-10, 5.8549609302492589e-09, 3.4807738736531026e-08, 1.8664547970988355e-07, 9.0421645542748592e-07, 3.9637332341743650e-06, 1.5744241598181718e-05, 5.6738856687547051e-05, 1.8573262875095809e-04, 5.5284802877925447e-04, 1.4977892627292288e-03, 3.6965702725171162e-03, 8.3173850369341346e-03, 1.7073105881727814e-02, 3.1991743583371472e-02, 5.4750665778331979e-02, 8.5616850779843184e-02, 1.2237883847025718e-01, 1.5993992755454783e-01, 1.9116358027866243e-01, 2.0898430851629271e-01, 2.0898430851629271e-01, 1.9116358027866243e-01, 1.5993992755454783e-01, 1.2237883847025718e-01, 8.5616850779843184e-02, 5.4750665778331979e-02, 3.1991743583371472e-02, 1.7073105881727814e-02, 8.3173850369341346e-03, 3.6965702725171162e-03, 1.4977892627292288e-03, 5.5284802877925447e-04, 1.8573262875095809e-04, 5.6738856687547051e-05, 1.5744241598181718e-05, 3.9637332341743650e-06, 9.0421645542748592e-07, 1.8664547970988355e-07, 3.4807738736531026e-08, 5.8549609302492589e-09, 8.8669552925941743e-10, 1.2066201440627706e-10, 1.4722456305780643e-11, 1.6069042876497942e-12, 1.5649369927618164e-13, 1.3561256356020877e-14, 1.0425344386668410e-15, 7.0866359430444936e-17, 4.2441255956981095e-18, 2.2306211570300883e-19, 1.0244196283925887e-20, 4.0914965094167889e-22, 1.4137224274155160e-23, 4.2015271606281150e-25, 1.0671290531221681e-26, 2.2997378701939073e-28, 4.1716030615092882e-30, 6.3119668181308563e-32, 7.8853213936624651e-34, 8.0390389893761170e-36, 6.5994654800159303e-38, 4.2954616661119346e-40, 2.1769699583039015e-42, 8.4092583458821788e-45, 2.4133632044032138e-47, 4.9883667718148639e-50, 7.1462236088717712e-53, 6.7588233504303362e-56, 3.9619475088358356e-59, 1.3221294591344122e-62, 2.2283154783345243e-66, 1.5851638341206613e-70, 3.5443349838315051e-75, 1.4208271558885895e-80, 2.4448842535551943e-87}, {3.5392388249213494e-88, 2.1696906628474067e-81, 5.6618251917679648e-76, 2.6377634936769698e-71, 3.8524845909450548e-67, 2.3705848077171715e-63, 7.3575399530382127e-60, 1.2986758900322505e-56, 1.4196212763395569e-53, 1.0238881258836751e-50, 5.1156622686963731e-48, 1.8401448448645002e-45, 4.9161713392811270e-43, 1.0008264983378071e-40, 1.5861732912787765e-38, 1.9928674928468924e-36, 2.0159688321556722e-34, 1.6641520867485548e-32, 1.1341833636634616e-30, 6.4478013617261386e-29, 3.0854328584335985e-27, 1.2528407416044293e-25, 4.3478662125855451e-24, 1.2979585113660281e-22, 3.3525506308968111e-21, 7.5318707919556725e-20, 1.4788148820660904e-18, 2.5485379935372649e-17, 3.8703599993584500e-16, 5.1983189715882119e-15, 6.1952864130014014e-14, 6.5714753453597697e-13, 6.2212201579575959e-12, 5.2699881035078001e-11, 4.0039253602146504e-10, 2.7342851107604089e-09, 1.6816952694545013e-08, 9.3323608375261539e-08, 4.6806643299789927e-07, 2.1250386338304275e-06, 8.7455216612331247e-06, 3.2668449881324752e-05, 1.1089473739894331e-04, 3.4245439902397305e-04, 9.6300903314221480e-04, 2.4681920354686017e-03, 5.7702467735466509e-03, 1.2313597617381173e-02, 2.4000639085914963e-02, 4.2750896794915914e-02, 6.9623487033404263e-02, 1.0371107766286002e-01, 1.4134876449586573e-01, 1.7630458117164949e-01, 2.0128719075538343e-01, 2.1037554689061755e-01, 2.0128719075538343e-01, 1.7630458117164949e-01, 1.4134876449586573e-01, 1.0371107766286002e-01, 6.9623487033404263e-02, 4.2750896794915914e-02, 2.4000639085914963e-02, 1.2313597617381173e-02, 5.7702467735466509e-03, 2.4681920354686017e-03, 9.6300903314221480e-04, 3.4245439902397305e-04, 1.1089473739894331e-04, 3.2668449881324752e-05, 8.7455216612331247e-06, 2.1250386338304275e-06, 4.6806643299789927e-07, 9.3323608375261539e-08, 1.6816952694545013e-08, 2.7342851107604089e-09, 4.0039253602146504e-10, 5.2699881035078001e-11, 6.2212201579575959e-12, 6.5714753453597697e-13, 6.1952864130014014e-14, 5.1983189715882119e-15, 3.8703599993584500e-16, 2.5485379935372649e-17, 1.4788148820660904e-18, 7.5318707919556725e-20, 3.3525506308968111e-21, 1.2979585113660281e-22, 4.3478662125855451e-24, 1.2528407416044293e-25, 3.0854328584335985e-27, 6.4478013617261386e-29, 1.1341833636634616e-30, 1.6641520867485548e-32, 2.0159688321556722e-34, 1.9928674928468924e-36, 1.5861732912787765e-38, 1.0008264983378071e-40, 4.9161713392811270e-43, 1.8401448448645002e-45, 5.1156622686963731e-48, 1.0238881258836751e-50, 1.4196212763395569e-53, 1.2986758900322505e-56, 7.3575399530382127e-60, 2.3705848077171715e-63, 3.8524845909450548e-67, 2.6377634936769698e-71, 5.6618251917679648e-76, 2.1696906628474067e-81, 3.5392388249213494e-88}, {5.1213633747657793e-89, 3.3107952448155878e-82, 9.0350209598558634e-77, 4.3835962164609016e-72, 6.6500528211701889e-68, 4.2427446781122925e-64, 1.3635093884813276e-60, 2.4895722182831332e-57, 2.8129093907478575e-54, 2.0956899110692340e-51, 1.0810706995222149e-48, 4.0133902027335798e-46, 1.1062614025677837e-43, 2.3230252252301317e-41, 3.7968846438904689e-39, 4.9189778171570439e-37, 5.1304565438169636e-35, 4.3662939232282773e-33, 3.0678714585911782e-31, 1.7980362370024124e-29, 8.8704657684441925e-28, 3.7135654602235681e-26, 1.3288244259482261e-24, 4.0906197763453875e-23, 1.0896574554298035e-21, 2.5250019651414982e-20, 5.1142598161040868e-19, 9.0937679770517361e-18, 1.4251779817419312e-16, 1.9757601287853092e-15, 2.4309836206138916e-14, 2.6627832873106297e-13, 2.6038192973897978e-12, 2.2788951363311533e-11, 1.7893870863289438e-10, 1.2632724994941663e-09, 8.0347791732044002e-09, 4.6125099246668157e-08, 2.3940078640211405e-07, 1.1251692413517793e-06, 4.7955457442441056e-06, 1.8559162409889888e-05, 6.5298413383660050e-05, 2.0909754829024987e-04, 6.1000345990479894e-04, 1.6227318637929411e-03, 3.9395573314086755e-03, 8.7347828708895063e-03, 1.7698763026162554e-02, 3.2791967492410569e-02, 5.5582763848207158e-02, 8.6226926941764842e-02, 1.2246902437683259e-01, 1.5929780439003277e-01, 1.8979412167575810e-01, 2.0715930730796278e-01, 2.0715930730796278e-01, 1.8979412167575810e-01, 1.5929780439003277e-01, 1.2246902437683259e-01, 8.6226926941764842e-02, 5.5582763848207158e-02, 3.2791967492410569e-02, 1.7698763026162554e-02, 8.7347828708895063e-03, 3.9395573314086755e-03, 1.6227318637929411e-03, 6.1000345990479894e-04, 2.0909754829024987e-04, 6.5298413383660050e-05, 1.8559162409889888e-05, 4.7955457442441056e-06, 1.1251692413517793e-06, 2.3940078640211405e-07, 4.6125099246668157e-08, 8.0347791732044002e-09, 1.2632724994941663e-09, 1.7893870863289438e-10, 2.2788951363311533e-11, 2.6038192973897978e-12, 2.6627832873106297e-13, 2.4309836206138916e-14, 1.9757601287853092e-15, 1.4251779817419312e-16, 9.0937679770517361e-18, 5.1142598161040868e-19, 2.5250019651414982e-20, 1.0896574554298035e-21, 4.0906197763453875e-23, 1.3288244259482261e-24, 3.7135654602235681e-26, 8.8704657684441925e-28, 1.7980362370024124e-29, 3.0678714585911782e-31, 4.3662939232282773e-33, 5.1304565438169636e-35, 4.9189778171570439e-37, 3.7968846438904689e-39, 2.3230252252301317e-41, 1.1062614025677837e-43, 4.0133902027335798e-46, 1.0810706995222149e-48, 2.0956899110692340e-51, 2.8129093907478575e-54, 2.4895722182831332e-57, 1.3635093884813276e-60, 4.2427446781122925e-64, 6.6500528211701889e-68, 4.3835962164609016e-72, 9.0350209598558634e-77, 3.3107952448155878e-82, 5.1213633747657793e-89}, {7.4077801156809802e-90, 5.0483520825696067e-83, 1.4403225795247276e-77, 7.2755698062212851e-73, 1.1461458182067259e-68, 7.5798509757209669e-65, 2.5217356180713449e-61, 4.7616681817655899e-58, 5.5596107723280791e-55, 4.2776169290546349e-52, 2.2777250019423805e-49, 8.7248851122544073e-47, 2.4806792113142151e-44, 5.3718421575826214e-42, 9.0525141699026487e-40, 1.2089985963915576e-37, 1.2997822407575913e-35, 1.1401487006660065e-33, 8.2566517430946983e-32, 4.9874725361855554e-30, 2.5360177279806859e-28, 1.0943086662261828e-26, 4.0363441926925487e-25, 1.2809131432068308e-23, 3.5178503719335083e-22, 8.4054498872392565e-21, 1.7557265568072654e-19, 3.2200557928719378e-18, 5.2060944517170957e-17, 7.4470753817100703e-16, 9.4565868275202180e-15, 1.0692722214257240e-13, 1.0796165415752499e-12, 9.7589319582302090e-12, 7.9162851028857836e-11, 5.7753749442476326e-10, 3.7971425911450754e-09, 2.2540365079384215e-08, 1.2101463098116854e-07, 5.8853747125042215e-07, 2.5965756360441134e-06, 1.0406346919868978e-05, 3.7931294208686378e-05, 1.2588825538260341e-04, 3.8080638386839771e-04, 1.0508900454889139e-03, 2.6479410521627993e-03, 6.0965525061442453e-03, 1.2834439196438882e-02, 2.4719722908456396e-02, 4.3582193779905874e-02, 7.0366531191907819e-02, 1.0408220923468044e-01, 1.4108198634981012e-01, 1.7528831212387214e-01, 1.9966087345702854e-01, 2.0851381638716077e-01, 1.9966087345702854e-01, 1.7528831212387214e-01, 1.4108198634981012e-01, 1.0408220923468044e-01, 7.0366531191907819e-02, 4.3582193779905874e-02, 2.4719722908456396e-02, 1.2834439196438882e-02, 6.0965525061442453e-03, 2.6479410521627993e-03, 1.0508900454889139e-03, 3.8080638386839771e-04, 1.2588825538260341e-04, 3.7931294208686378e-05, 1.0406346919868978e-05, 2.5965756360441134e-06, 5.8853747125042215e-07, 1.2101463098116854e-07, 2.2540365079384215e-08, 3.7971425911450754e-09, 5.7753749442476326e-10, 7.9162851028857836e-11, 9.7589319582302090e-12, 1.0796165415752499e-12, 1.0692722214257240e-13, 9.4565868275202180e-15, 7.4470753817100703e-16, 5.2060944517170957e-17, 3.2200557928719378e-18, 1.7557265568072654e-19, 8.4054498872392565e-21, 3.5178503719335083e-22, 1.2809131432068308e-23, 4.0363441926925487e-25, 1.0943086662261828e-26, 2.5360177279806859e-28, 4.9874725361855554e-30, 8.2566517430946983e-32, 1.1401487006660065e-33, 1.2997822407575913e-35, 1.2089985963915576e-37, 9.0525141699026487e-40, 5.3718421575826214e-42, 2.4806792113142151e-44, 8.7248851122544073e-47, 2.2777250019423805e-49, 4.2776169290546349e-52, 5.5596107723280791e-55, 4.7616681817655899e-58, 2.5217356180713449e-61, 7.5798509757209669e-65, 1.1461458182067259e-68, 7.2755698062212851e-73, 1.4403225795247276e-77, 5.0483520825696067e-83, 7.4077801156809802e-90}, {1.0710750710094196e-90, 7.6922700260785516e-84, 2.2937970374962485e-78, 1.2060181138762046e-73, 1.9724028846801179e-69, 1.3517892214658933e-65, 4.6544766331713673e-62, 9.0869836287455904e-59, 1.0961147706353286e-55, 8.7075616610856478e-53, 4.7848109229537450e-50, 1.8906897473607166e-47, 5.5435860303288234e-45, 1.2376390647546546e-42, 2.1498363403641766e-40, 2.9591207501866347e-38, 3.2783946198859832e-36, 2.9632924702764426e-34, 2.2111690104503776e-32, 1.3762537782433349e-30, 7.2106896606964717e-29, 3.2061793655442875e-27, 1.2186704300488311e-25, 3.9856906328389221e-24, 1.1282136742777468e-22, 2.7788009433178836e-21, 5.9840605797879746e-20, 1.1316516319423812e-18, 1.8868897366381483e-17, 2.7841156852775031e-16, 3.6474708837523359e-15, 4.2559572408720686e-14, 4.4353966285433845e-13, 4.1393133324428903e-12, 3.4675788374516700e-11, 2.6132836673568577e-10, 1.7753911292124313e-09, 1.0893439091005499e-08, 6.0471668709771245e-08, 3.0419237917584698e-07, 1.3886494911822552e-06, 5.7606576662754425e-06, 2.1743312833175104e-05, 7.4756242475529144e-05, 2.3436272202084139e-04, 6.7059411024834642e-04, 1.7528045021959946e-03, 4.1883749721869905e-03, 9.1558081843385875e-03, 1.8321199420242032e-02, 3.3577761609077682e-02, 5.6388855176296548e-02, 8.6806251150572486e-02, 1.2253708910746171e-01, 1.5865594890874077e-01, 1.8845256425575369e-01, 2.0538128483764440e-01, 2.0538128483764440e-01, 1.8845256425575369e-01, 1.5865594890874077e-01, 1.2253708910746171e-01, 8.6806251150572486e-02, 5.6388855176296548e-02, 3.3577761609077682e-02, 1.8321199420242032e-02, 9.1558081843385875e-03, 4.1883749721869905e-03, 1.7528045021959946e-03, 6.7059411024834642e-04, 2.3436272202084139e-04, 7.4756242475529144e-05, 2.1743312833175104e-05, 5.7606576662754425e-06, 1.3886494911822552e-06, 3.0419237917584698e-07, 6.0471668709771245e-08, 1.0893439091005499e-08, 1.7753911292124313e-09, 2.6132836673568577e-10, 3.4675788374516700e-11, 4.1393133324428903e-12, 4.4353966285433845e-13, 4.2559572408720686e-14, 3.6474708837523359e-15, 2.7841156852775031e-16, 1.8868897366381483e-17, 1.1316516319423812e-18, 5.9840605797879746e-20, 2.7788009433178836e-21, 1.1282136742777468e-22, 3.9856906328389221e-24, 1.2186704300488311e-25, 3.2061793655442875e-27, 7.2106896606964717e-29, 1.3762537782433349e-30, 2.2111690104503776e-32, 2.9632924702764426e-34, 3.2783946198859832e-36, 2.9591207501866347e-38, 2.1498363403641766e-40, 1.2376390647546546e-42, 5.5435860303288234e-45, 1.8906897473607166e-47, 4.7848109229537450e-50, 8.7075616610856478e-53, 1.0961147706353286e-55, 9.0869836287455904e-59, 4.6544766331713673e-62, 1.3517892214658933e-65, 1.9724028846801179e-69, 1.2060181138762046e-73, 2.2937970374962485e-78, 7.6922700260785516e-84, 1.0710750710094196e-90}, {1.5480449561254974e-91, 1.1712554562855694e-84, 3.6493992259071536e-79, 1.9966381452254604e-74, 3.3892412733092808e-70, 2.4065988574277261e-66, 8.5740429722944209e-63, 1.7303021840396506e-59, 2.1557967924444521e-56, 1.7677871947095523e-53, 1.0022253044363931e-50, 4.0842818848410062e-48, 1.2346472555075369e-45, 2.8411408701159342e-43, 5.0858613958959180e-41, 7.2130038186701857e-39, 8.2330481300630906e-37, 7.6663204905842568e-35, 5.8928891499709780e-33, 3.7782612371775474e-31, 2.0392097722330042e-29, 9.3406997569354054e-28, 3.6577061009128777e-26, 1.2325099622415151e-24, 3.5948795028461328e-23, 9.1244425221919135e-22, 2.0251548550899527e-20, 3.9477817506225531e-19, 6.7863601469508643e-18, 1.0325389659471167e-16, 1.3951643164647175e-15, 1.6793350772844097e-14, 1.8058345392733700e-13, 1.7393402348430495e-12, 1.5041987406688428e-11, 1.1705945482958366e-10, 8.2144797343634809e-10, 5.2077334277669068e-09, 2.9879393170121428e-08, 1.5539942997674910e-07, 7.3371456445731177e-07, 3.1491925110163785e-06, 1.2303027527173753e-05, 4.3799266325778880e-05, 1.4224028492262314e-04, 4.2179171252798944e-04, 1.1430722829481254e-03, 2.8333080652480614e-03, 6.4278810024544141e-03, 1.3355861419689084e-02, 2.5430213894352387e-02, 4.4393059115154253e-02, 7.1080397415348953e-02, 1.0442577716745464e-01, 1.4080345768904715e-01, 1.7428622967828752e-01, 1.9807313269914872e-01, 2.0670065276640287e-01, 1.9807313269914872e-01, 1.7428622967828752e-01, 1.4080345768904715e-01, 1.0442577716745464e-01, 7.1080397415348953e-02, 4.4393059115154253e-02, 2.5430213894352387e-02, 1.3355861419689084e-02, 6.4278810024544141e-03, 2.8333080652480614e-03, 1.1430722829481254e-03, 4.2179171252798944e-04, 1.4224028492262314e-04, 4.3799266325778880e-05, 1.2303027527173753e-05, 3.1491925110163785e-06, 7.3371456445731177e-07, 1.5539942997674910e-07, 2.9879393170121428e-08, 5.2077334277669068e-09, 8.2144797343634809e-10, 1.1705945482958366e-10, 1.5041987406688428e-11, 1.7393402348430495e-12, 1.8058345392733700e-13, 1.6793350772844097e-14, 1.3951643164647175e-15, 1.0325389659471167e-16, 6.7863601469508643e-18, 3.9477817506225531e-19, 2.0251548550899527e-20, 9.1244425221919135e-22, 3.5948795028461328e-23, 1.2325099622415151e-24, 3.6577061009128777e-26, 9.3406997569354054e-28, 2.0392097722330042e-29, 3.7782612371775474e-31, 5.8928891499709780e-33, 7.6663204905842568e-35, 8.2330481300630906e-37, 7.2130038186701857e-39, 5.0858613958959180e-41, 2.8411408701159342e-43, 1.2346472555075369e-45, 4.0842818848410062e-48, 1.0022253044363931e-50, 1.7677871947095523e-53, 2.1557967924444521e-56, 1.7303021840396506e-59, 8.5740429722944209e-63, 2.4065988574277261e-66, 3.3892412733092808e-70, 1.9966381452254604e-74, 3.6493992259071536e-79, 1.1712554562855694e-84, 1.5480449561254974e-91}, {2.2365648981246453e-92, 1.7821550800540237e-85, 5.8004986924644819e-80, 3.3015035960765624e-75, 5.8152759548633637e-71, 4.2771691981814217e-67, 1.5763666548556604e-63, 3.2876134769273718e-60, 4.2297673811987948e-57, 3.5794857851611975e-54, 2.0932606053442080e-51, 8.7956536234027020e-49, 2.7406328866050857e-46, 6.4989825715662458e-44, 1.1986003025152256e-41, 1.7511205172582050e-39, 2.0587364582129049e-37, 1.9743896190133811e-35, 1.5630006293499951e-33, 1.0320466636328443e-31, 5.7365178511704523e-30, 2.7061869712127610e-28, 1.0914439534101697e-26, 3.7881611827990218e-25, 1.1381700734483244e-23, 2.9761942889320718e-22, 6.8061278108013458e-21, 1.3672374402361970e-19, 2.4223988311307281e-18, 3.7993465086131341e-17, 5.2930247423722938e-16, 6.5702357143564891e-15, 7.2875563565483730e-14, 7.2418684802603713e-13, 6.4631097928536238e-12, 5.1919141781420298e-11, 3.7618946881237821e-10, 2.4632483182140787e-09, 1.4601515540917063e-08, 7.8484291703314789e-08, 3.8310233242483633e-07, 1.7005728326428347e-06, 6.8734922472265778e-06, 2.5326195751014174e-05, 8.5160665584721077e-05, 2.6158391341408045e-04, 7.3463960542667715e-04, 1.8879100806443562e-03, 4.4427288798279318e-03, 9.5799818951133077e-03, 1.8939956587000626e-02, 3.4349073289602634e-02, 5.7169633542064863e-02, 8.7356205785880797e-02, 1.2258446739609345e-01, 1.5801491756025524e-01, 1.8713802680418945e-01, 2.0364826010006534e-01, 2.0364826010006534e-01, 1.8713802680418945e-01, 1.5801491756025524e-01, 1.2258446739609345e-01, 8.7356205785880797e-02, 5.7169633542064863e-02, 3.4349073289602634e-02, 1.8939956587000626e-02, 9.5799818951133077e-03, 4.4427288798279318e-03, 1.8879100806443562e-03, 7.3463960542667715e-04, 2.6158391341408045e-04, 8.5160665584721077e-05, 2.5326195751014174e-05, 6.8734922472265778e-06, 1.7005728326428347e-06, 3.8310233242483633e-07, 7.8484291703314789e-08, 1.4601515540917063e-08, 2.4632483182140787e-09, 3.7618946881237821e-10, 5.1919141781420298e-11, 6.4631097928536238e-12, 7.2418684802603713e-13, 7.2875563565483730e-14, 6.5702357143564891e-15, 5.2930247423722938e-16, 3.7993465086131341e-17, 2.4223988311307281e-18, 1.3672374402361970e-19, 6.8061278108013458e-21, 2.9761942889320718e-22, 1.1381700734483244e-23, 3.7881611827990218e-25, 1.0914439534101697e-26, 2.7061869712127610e-28, 5.7365178511704523e-30, 1.0320466636328443e-31, 1.5630006293499951e-33, 1.9743896190133811e-35, 2.0587364582129049e-37, 1.7511205172582050e-39, 1.1986003025152256e-41, 6.4989825715662458e-44, 2.7406328866050857e-46, 8.7956536234027020e-49, 2.0932606053442080e-51, 3.5794857851611975e-54, 4.2297673811987948e-57, 3.2876134769273718e-60, 1.5763666548556604e-63, 4.2771691981814217e-67, 5.8152759548633637e-71, 3.3015035960765624e-75, 5.8004986924644819e-80, 1.7821550800540237e-85, 2.2365648981246453e-92}, {3.2301009543101099e-93, 2.7098206745663592e-86, 9.2107100141581600e-81, 5.4525421540759655e-76, 9.9634282798974572e-72, 7.5888934406190700e-68, 2.8926678180441972e-64, 6.2331956354059190e-61, 8.2793896913033925e-58, 7.2291385544928827e-55, 4.3597174343439006e-52, 1.8884218782951360e-49, 6.0637045694189279e-47, 1.4814159278355307e-44, 2.8142461042205111e-42, 4.2343947760097721e-40, 5.1264009327908215e-38, 5.0622696862483853e-36, 4.1261954854591773e-34, 2.8051622162519962e-32, 1.6053724151348174e-30, 7.7976718238941548e-29, 3.2382364130273421e-27, 1.1573493767550765e-25, 3.5810407352214098e-24, 9.6443805701337253e-23, 2.2718330011553644e-21, 4.7015694865721316e-20, 8.5828869554158906e-19, 1.3872615165495405e-17, 1.9920232649990639e-16, 2.5491665563098012e-15, 2.9155331883629833e-14, 2.9881593623355600e-13, 2.7511620846328702e-12, 2.2805223736764051e-11, 1.7055424914056455e-10, 1.1530186653890739e-09, 7.0587498965529012e-09, 3.9196764143747362e-08, 1.9772532357280954e-07, 9.0734367403526114e-07, 3.7926166158590859e-06, 1.4457032475544561e-05, 5.0311336988073622e-05, 1.6000468687262702e-04, 4.6545282707817341e-04, 1.2395239105761761e-03, 3.0241014828653783e-03, 6.7638384706753211e-03, 1.3877372041544333e-02, 2.6131824932046500e-02, 4.5183798113816530e-02, 7.1766149805041285e-02, 1.0474325576824089e-01, 1.4051423956652490e-01, 1.7329818332155345e-01, 1.9652247660560301e-01, 2.0493398052053613e-01, 1.9652247660560301e-01, 1.7329818332155345e-01, 1.4051423956652490e-01, 1.0474325576824089e-01, 7.1766149805041285e-02, 4.5183798113816530e-02, 2.6131824932046500e-02, 1.3877372041544333e-02, 6.7638384706753211e-03, 3.0241014828653783e-03, 1.2395239105761761e-03, 4.6545282707817341e-04, 1.6000468687262702e-04, 5.0311336988073622e-05, 1.4457032475544561e-05, 3.7926166158590859e-06, 9.0734367403526114e-07, 1.9772532357280954e-07, 3.9196764143747362e-08, 7.0587498965529012e-09, 1.1530186653890739e-09, 1.7055424914056455e-10, 2.2805223736764051e-11, 2.7511620846328702e-12, 2.9881593623355600e-13, 2.9155331883629833e-14, 2.5491665563098012e-15, 1.9920232649990639e-16, 1.3872615165495405e-17, 8.5828869554158906e-19, 4.7015694865721316e-20, 2.2718330011553644e-21, 9.6443805701337253e-23, 3.5810407352214098e-24, 1.1573493767550765e-25, 3.2382364130273421e-27, 7.7976718238941548e-29, 1.6053724151348174e-30, 2.8051622162519962e-32, 4.1261954854591773e-34, 5.0622696862483853e-36, 5.1264009327908215e-38, 4.2343947760097721e-40, 2.8142461042205111e-42, 1.4814159278355307e-44, 6.0637045694189279e-47, 1.8884218782951360e-49, 4.3597174343439006e-52, 7.2291385544928827e-55, 8.2793896913033925e-58, 6.2331956354059190e-61, 2.8926678180441972e-64, 7.5888934406190700e-68, 9.9634282798974572e-72, 5.4525421540759655e-76, 9.2107100141581600e-81, 2.7098206745663592e-86, 3.2301009543101099e-93}, {4.6632605618348153e-94, 4.1175713624143213e-87, 1.4612038470881841e-81, 8.9943320432041730e-77, 1.7046189545614933e-72, 1.3442523656293476e-68, 5.2981258920312120e-65, 1.1793052736766146e-61, 1.6168482075284075e-58, 1.4562812961539782e-55, 9.0550269871980438e-53, 4.0423080380262144e-50, 1.3372947653240557e-47, 3.3652104040755819e-45, 6.5834566491742290e-43, 1.0199300069374435e-40, 1.2712364015219454e-38, 1.2922794919134986e-36, 1.0842626381128112e-34, 7.5875981466261195e-33, 4.4697458344428785e-31, 2.2348156961076159e-29, 9.5537375722030760e-28, 3.5151519348961093e-26, 1.1197954114046576e-24, 3.1052469143218520e-23, 7.5325222776132763e-22, 1.6054837533511592e-20, 3.0189715471734914e-19, 5.0270892648593941e-18, 7.4380949511123831e-17, 9.8097342377809155e-16, 1.1565317290963977e-14, 1.2221338000525176e-13, 1.1603996128858022e-12, 9.9222265232533288e-12, 7.6565621148965857e-11, 5.3422379271962827e-10, 3.3764133497574799e-09, 1.9362011885244885e-08, 1.0089574633621321e-07, 4.7845042712908339e-07, 2.0673284334051564e-06, 8.1491561908568428e-06, 2.9337744635072858e-05, 9.6558931405380603e-05, 2.9081250785794189e-04, 8.0215126322350460e-04, 2.0279429361286859e-03, 4.7023255147965815e-03, 1.0006845717689308e-02, 1.9554616052364186e-02, 3.5105886050128668e-02, 5.7925787803644498e-02, 8.7878107549790321e-02, 1.2261249660444425e-01, 1.5737520760258733e-01, 1.8584966291329158e-01, 2.0195836706954076e-01, 2.0195836706954076e-01, 1.8584966291329158e-01, 1.5737520760258733e-01, 1.2261249660444425e-01, 8.7878107549790321e-02, 5.7925787803644498e-02, 3.5105886050128668e-02, 1.9554616052364186e-02, 1.0006845717689308e-02, 4.7023255147965815e-03, 2.0279429361286859e-03, 8.0215126322350460e-04, 2.9081250785794189e-04, 9.6558931405380603e-05, 2.9337744635072858e-05, 8.1491561908568428e-06, 2.0673284334051564e-06, 4.7845042712908339e-07, 1.0089574633621321e-07, 1.9362011885244885e-08, 3.3764133497574799e-09, 5.3422379271962827e-10, 7.6565621148965857e-11, 9.9222265232533288e-12, 1.1603996128858022e-12, 1.2221338000525176e-13, 1.1565317290963977e-14, 9.8097342377809155e-16, 7.4380949511123831e-17, 5.0270892648593941e-18, 3.0189715471734914e-19, 1.6054837533511592e-20, 7.5325222776132763e-22, 3.1052469143218520e-23, 1.1197954114046576e-24, 3.5151519348961093e-26, 9.5537375722030760e-28, 2.2348156961076159e-29, 4.4697458344428785e-31, 7.5875981466261195e-33, 1.0842626381128112e-34, 1.2922794919134986e-36, 1.2712364015219454e-38, 1.0199300069374435e-40, 6.5834566491742290e-43, 3.3652104040755819e-45, 1.3372947653240557e-47, 4.0423080380262144e-50, 9.0550269871980438e-53, 1.4562812961539782e-55, 1.6168482075284075e-58, 1.1793052736766146e-61, 5.2981258920312120e-65, 1.3442523656293476e-68, 1.7046189545614933e-72, 8.9943320432041730e-77, 1.4612038470881841e-81, 4.1175713624143213e-87, 4.6632605618348153e-94}, {6.7298368161176175e-95, 6.2524679295400819e-88, 2.3159244482213129e-82, 1.4819345628019795e-77, 2.9122929849292479e-73, 2.3772467547464570e-69, 9.6859162631794203e-66, 2.2265944526096699e-62, 3.1502482452041196e-59, 2.9262669926463904e-56, 1.8755830649756743e-53, 8.6273958082206037e-51, 2.9399528685004811e-48, 7.6185958106575033e-46, 1.5345315352659727e-43, 2.4472631035773749e-41, 3.1395792592468297e-39, 3.2847155364958309e-37, 2.8362637361915701e-35, 2.0425551530268673e-33, 1.2382461823632275e-31, 6.3712964630586884e-30, 2.8030942195831802e-28, 1.0614795301061955e-26, 3.4805041051243282e-25, 9.9351833121692472e-24, 2.4810981347002888e-22, 5.4448704650642035e-21, 1.0543376862850843e-19, 1.8081886383358570e-18, 2.7559344338025971e-17, 3.7447612695692442e-16, 4.5495653050067822e-15, 4.9552804559564594e-14, 4.8505588604403995e-13, 4.2769240959330674e-12, 3.4041116737305440e-11, 2.4505079134311513e-10, 1.5983528945271918e-09, 9.4619152361816427e-09, 5.0915075227638090e-08, 2.4939923966935258e-07, 1.1135208095853982e-06, 4.5371664146194656e-06, 1.6890448115948282e-05, 5.7506280394736890e-05, 1.7923272339346707e-04, 5.1182575908404512e-04, 1.3402041554580024e-03, 3.2201249358166924e-03, 7.1040413328426078e-03, 1.4398510037728523e-02, 2.6824309528990144e-02, 4.5954734368354178e-02, 7.2424817070363218e-02, 1.0503603365193327e-01, 1.4021530912606431e-01, 1.7232400830089628e-01, 1.9500749227238295e-01, 2.0321184623044758e-01, 1.9500749227238295e-01, 1.7232400830089628e-01, 1.4021530912606431e-01, 1.0503603365193327e-01, 7.2424817070363218e-02, 4.5954734368354178e-02, 2.6824309528990144e-02, 1.4398510037728523e-02, 7.1040413328426078e-03, 3.2201249358166924e-03, 1.3402041554580024e-03, 5.1182575908404512e-04, 1.7923272339346707e-04, 5.7506280394736890e-05, 1.6890448115948282e-05, 4.5371664146194656e-06, 1.1135208095853982e-06, 2.4939923966935258e-07, 5.0915075227638090e-08, 9.4619152361816427e-09, 1.5983528945271918e-09, 2.4505079134311513e-10, 3.4041116737305440e-11, 4.2769240959330674e-12, 4.8505588604403995e-13, 4.9552804559564594e-14, 4.5495653050067822e-15, 3.7447612695692442e-16, 2.7559344338025971e-17, 1.8081886383358570e-18, 1.0543376862850843e-19, 5.4448704650642035e-21, 2.4810981347002888e-22, 9.9351833121692472e-24, 3.4805041051243282e-25, 1.0614795301061955e-26, 2.8030942195831802e-28, 6.3712964630586884e-30, 1.2382461823632275e-31, 2.0425551530268673e-33, 2.8362637361915701e-35, 3.2847155364958309e-37, 3.1395792592468297e-39, 2.4472631035773749e-41, 1.5345315352659727e-43, 7.6185958106575033e-46, 2.9399528685004811e-48, 8.6273958082206037e-51, 1.8755830649756743e-53, 2.9262669926463904e-56, 3.1502482452041196e-59, 2.2265944526096699e-62, 9.6859162631794203e-66, 2.3772467547464570e-69, 2.9122929849292479e-73, 1.4819345628019795e-77, 2.3159244482213129e-82, 6.2524679295400819e-88, 6.7298368161176175e-95}, {9.7087403173561320e-96, 9.4880223969421335e-89, 3.6672428899258345e-83, 2.4388595277598848e-78, 4.9686800178709975e-74, 4.1972934212808472e-70, 1.7675264508544507e-66, 4.1953576796012743e-63, 6.1240687137526128e-60, 5.8655575443381544e-57, 3.8745058915294428e-54, 1.8359883902918249e-51, 6.4431660432386704e-49, 1.7190498209667764e-46, 3.5641227393846403e-44, 5.8499085615955162e-42, 7.7228330960795927e-40, 8.3138040908205878e-38, 7.3861592386371398e-36, 5.4726905931533611e-34, 3.4133817510443908e-32, 1.8070157219004075e-30, 8.1797979499699255e-29, 3.1872062136052619e-27, 1.0753877987999934e-25, 3.1590858369572161e-24, 8.1196497360506958e-23, 1.8341746417696775e-21, 3.6563781425498920e-20, 6.4565140315879466e-19, 1.0133911369582986e-17, 1.4182835695860085e-16, 1.7750978597330652e-15, 1.9921528797000957e-14, 2.0097524571107850e-13, 1.8267486127018911e-12, 1.4991784686824891e-11, 1.1130625000696823e-10, 7.4897520452156729e-10, 4.5753933756254367e-09, 2.5414386492665182e-08, 1.2854272339650551e-07, 5.9280419576037410e-07, 2.4957777427586521e-06, 9.6033945516455336e-06, 3.3808196410240332e-05, 1.0899702609675318e-04, 3.2209543490435076e-04, 8.7313245576434379e-04, 2.1727898312954579e-03, 4.9668732525919509e-03, 1.0435962135902662e-02, 2.0164796980741757e-02, 3.5848215647758121e-02, 5.8657999750043426e-02, 8.8373210437321048e-02, 1.2262242405763166e-01, 1.5673726302678062e-01, 1.8458665957131964e-01, 2.0030984626187961e-01, 2.0030984626187961e-01, 1.8458665957131964e-01, 1.5673726302678062e-01, 1.2262242405763166e-01, 8.8373210437321048e-02, 5.8657999750043426e-02, 3.5848215647758121e-02, 2.0164796980741757e-02, 1.0435962135902662e-02, 4.9668732525919509e-03, 2.1727898312954579e-03, 8.7313245576434379e-04, 3.2209543490435076e-04, 1.0899702609675318e-04, 3.3808196410240332e-05, 9.6033945516455336e-06, 2.4957777427586521e-06, 5.9280419576037410e-07, 1.2854272339650551e-07, 2.5414386492665182e-08, 4.5753933756254367e-09, 7.4897520452156729e-10, 1.1130625000696823e-10, 1.4991784686824891e-11, 1.8267486127018911e-12, 2.0097524571107850e-13, 1.9921528797000957e-14, 1.7750978597330652e-15, 1.4182835695860085e-16, 1.0133911369582986e-17, 6.4565140315879466e-19, 3.6563781425498920e-20, 1.8341746417696775e-21, 8.1196497360506958e-23, 3.1590858369572161e-24, 1.0753877987999934e-25, 3.1872062136052619e-27, 8.1797979499699255e-29, 1.8070157219004075e-30, 3.4133817510443908e-32, 5.4726905931533611e-34, 7.3861592386371398e-36, 8.3138040908205878e-38, 7.7228330960795927e-40, 5.8499085615955162e-42, 3.5641227393846403e-44, 1.7190498209667764e-46, 6.4431660432386704e-49, 1.8359883902918249e-51, 3.8745058915294428e-54, 5.8655575443381544e-57, 6.1240687137526128e-60, 4.1953576796012743e-63, 1.7675264508544507e-66, 4.1972934212808472e-70, 4.9686800178709975e-74, 2.4388595277598848e-78, 3.6672428899258345e-83, 9.4880223969421335e-89, 9.7087403173561320e-96}, {1.4001253071178789e-96, 1.4388577548096490e-89, 5.8017947700800046e-84, 4.0091236159545663e-79, 8.4655265882771739e-75, 7.3990554223004025e-71, 3.2196574821489126e-67, 7.8890210982671253e-64, 1.1878725902550843e-60, 1.1728639625604033e-57, 7.9826611475407281e-55, 3.8960048884898755e-52, 1.4077485752140258e-49, 3.8661220025482209e-47, 8.2491446524855651e-45, 1.3931625443392332e-42, 1.8922123418053773e-40, 2.0955223902923607e-38, 1.9150597358365338e-36, 1.4595508732329443e-34, 9.3637976764322119e-33, 5.0989613303209105e-31, 2.3742569610821154e-29, 9.5165969692199733e-28, 3.3033284608828233e-26, 9.9838789745986388e-25, 2.6403982498871405e-23, 6.1378568842560367e-22, 1.2592940912286238e-20, 2.2889503956241953e-19, 3.6986721862085567e-18, 5.3301125275267336e-17, 6.8703687643915730e-16, 7.9423755813393362e-15, 8.2552749332412685e-14, 7.7326044861505372e-13, 6.5412509847214547e-12, 5.0072069799282932e-11, 3.4747667141215967e-10, 2.1897184637878725e-09, 1.2550651872012550e-08, 6.5522732997355584e-08, 3.1199715417437437e-07, 1.3566980827714974e-06, 5.3937313862223019e-06, 1.9625894008346668e-05, 6.5422509840297027e-05, 1.9997290405207970e-04, 5.6094024606844449e-04, 1.4450639870005968e-03, 3.4211784137958604e-03, 7.4481168960531027e-03, 1.4918844448036933e-02, 2.7507458506267436e-02, 4.6706206412519734e-02, 7.3057392793912337e-02, 1.0530541916565815e-01, 1.3990756676688021e-01, 1.7136352815479530e-01, 1.9352684051681762e-01, 2.0153240948474130e-01, 1.9352684051681762e-01, 1.7136352815479530e-01, 1.3990756676688021e-01, 1.0530541916565815e-01, 7.3057392793912337e-02, 4.6706206412519734e-02, 2.7507458506267436e-02, 1.4918844448036933e-02, 7.4481168960531027e-03, 3.4211784137958604e-03, 1.4450639870005968e-03, 5.6094024606844449e-04, 1.9997290405207970e-04, 6.5422509840297027e-05, 1.9625894008346668e-05, 5.3937313862223019e-06, 1.3566980827714974e-06, 3.1199715417437437e-07, 6.5522732997355584e-08, 1.2550651872012550e-08, 2.1897184637878725e-09, 3.4747667141215967e-10, 5.0072069799282932e-11, 6.5412509847214547e-12, 7.7326044861505372e-13, 8.2552749332412685e-14, 7.9423755813393362e-15, 6.8703687643915730e-16, 5.3301125275267336e-17, 3.6986721862085567e-18, 2.2889503956241953e-19, 1.2592940912286238e-20, 6.1378568842560367e-22, 2.6403982498871405e-23, 9.9838789745986388e-25, 3.3033284608828233e-26, 9.5165969692199733e-28, 2.3742569610821154e-29, 5.0989613303209105e-31, 9.3637976764322119e-33, 1.4595508732329443e-34, 1.9150597358365338e-36, 2.0955223902923607e-38, 1.8922123418053773e-40, 1.3931625443392332e-42, 8.2491446524855651e-45, 3.8661220025482209e-47, 1.4077485752140258e-49, 3.8960048884898755e-52, 7.9826611475407281e-55, 1.1728639625604033e-57, 1.1878725902550843e-60, 7.8890210982671253e-64, 3.2196574821489126e-67, 7.3990554223004025e-71, 8.4655265882771739e-75, 4.0091236159545663e-79, 5.8017947700800046e-84, 1.4388577548096490e-89, 1.4001253071178789e-96}, {2.0184534275095049e-97, 2.1806296158265287e-90, 9.1706055028522197e-85, 6.5830036453656527e-80, 1.4403978976524620e-75, 1.3022823162971665e-71, 5.8544142858486073e-68, 1.4805274033207088e-64, 2.2990511219174665e-61, 2.3396177274687451e-58, 1.6403928051497794e-55, 8.2441788250067191e-53, 3.0664667336421114e-50, 8.6667923231989335e-48, 1.9026918231732264e-45, 3.3057067086043009e-43, 4.6182598989607685e-41, 5.2602254003426042e-39, 4.9438860107310490e-37, 3.8749094400485918e-35, 2.5564844139368277e-33, 1.4316070974387265e-31, 6.8553849798952103e-30, 2.8259664729965746e-28, 1.0088930738432750e-26, 3.1364243262134751e-25, 8.5327296120897214e-24, 2.0406372113926846e-22, 4.3078486936244584e-21, 8.0577481866273284e-20, 1.3400866628758495e-18, 1.9879461273563199e-17, 2.6381930823541892e-16, 3.1406382865933653e-15, 3.3622360761898003e-14, 3.2444814316722348e-13, 2.8281489919728500e-12, 2.2313290142958860e-11, 1.5963585528134907e-10, 1.0373981456665397e-09, 6.1333415530709063e-09, 3.3038743448338228e-08, 1.6237364967913452e-07, 7.2898765543366947e-07, 2.9932498983591025e-06, 1.1252541495603299e-05, 3.8767965827716168e-05, 1.2251950121646584e-04, 3.5547512496610876e-04, 9.4757899341760905e-04, 2.3223308982827312e-03, 5.2360833859067743e-03, 1.0866914248342787e-02, 2.0770153886127483e-02, 3.6576106509803016e-02, 5.9366942312670930e-02, 8.8842708636295842e-02, 1.2261541377174207e-01, 1.5610147984994696e-01, 1.8334823578007414e-01, 1.9870103704081624e-01, 1.9870103704081624e-01, 1.8334823578007414e-01, 1.5610147984994696e-01, 1.2261541377174207e-01, 8.8842708636295842e-02, 5.9366942312670930e-02, 3.6576106509803016e-02, 2.0770153886127483e-02, 1.0866914248342787e-02, 5.2360833859067743e-03, 2.3223308982827312e-03, 9.4757899341760905e-04, 3.5547512496610876e-04, 1.2251950121646584e-04, 3.8767965827716168e-05, 1.1252541495603299e-05, 2.9932498983591025e-06, 7.2898765543366947e-07, 1.6237364967913452e-07, 3.3038743448338228e-08, 6.1333415530709063e-09, 1.0373981456665397e-09, 1.5963585528134907e-10, 2.2313290142958860e-11, 2.8281489919728500e-12, 3.2444814316722348e-13, 3.3622360761898003e-14, 3.1406382865933653e-15, 2.6381930823541892e-16, 1.9879461273563199e-17, 1.3400866628758495e-18, 8.0577481866273284e-20, 4.3078486936244584e-21, 2.0406372113926846e-22, 8.5327296120897214e-24, 3.1364243262134751e-25, 1.0088930738432750e-26, 2.8259664729965746e-28, 6.8553849798952103e-30, 1.4316070974387265e-31, 2.5564844139368277e-33, 3.8749094400485918e-35, 4.9438860107310490e-37, 5.2602254003426042e-39, 4.6182598989607685e-41, 3.3057067086043009e-43, 1.9026918231732264e-45, 8.6667923231989335e-48, 3.0664667336421114e-50, 8.2441788250067191e-53, 1.6403928051497794e-55, 2.3396177274687451e-58, 2.2990511219174665e-61, 1.4805274033207088e-64, 5.8544142858486073e-68, 1.3022823162971665e-71, 1.4403978976524620e-75, 6.5830036453656527e-80, 9.1706055028522197e-85, 2.1806296158265287e-90, 2.0184534275095049e-97}, {2.9088440757674062e-98, 3.3027195553941757e-91, 1.4482784276490109e-85, 1.0797361898132115e-80, 2.4475687753038470e-76, 2.2885780042663531e-72, 1.0626701542492299e-68, 2.7730751722659017e-65, 4.4400764524986828e-62, 4.6560392499732150e-59, 3.3622797072552750e-56, 1.7396913258105826e-53, 6.6597646076210362e-51, 1.9366833085713306e-48, 4.3737554297590874e-46, 7.8155861441480535e-44, 1.1228680356492188e-41, 1.3151165218678305e-39, 1.2708875196505519e-37, 1.0241410150378061e-35, 6.9469156975836022e-34, 3.9996687161846431e-32, 1.9692128985290527e-30, 8.3465290951830949e-29, 3.0639885163656867e-27, 9.7951708742326283e-26, 2.7405597239380626e-24, 6.7411887298015296e-23, 1.4638683297363268e-21, 2.8169790254203712e-20, 4.8205257099851608e-19, 7.3591325007878809e-18, 1.0052255425278666e-16, 1.2319403285686423e-15, 1.3580008734485746e-14, 1.3496086984992707e-13, 1.2118575324056077e-12, 9.8514672314148016e-12, 7.2637761188053839e-11, 4.8661361388782973e-10, 2.9666085963352118e-09, 1.6482913905846427e-08, 8.3579939555984911e-08, 3.8727287415554441e-07, 1.6416874675897103e-06, 6.3737479499140128e-06, 2.2686436750985634e-05, 7.4097922186640899e-05, 2.2227085873416057e-04, 6.1281987967776825e-04, 1.5540467884754450e-03, 3.6270593070595858e-03, 7.7957038787030220e-03, 1.5437973179493971e-02, 2.8181096910943754e-02, 4.7438564768728979e-02, 7.3664835869183778e-02, 1.0555264545810959e-01, 1.3959184263252383e-01, 1.7041655690534233e-01, 1.9207925104318502e-01, 1.9989393461088162e-01, 1.9207925104318502e-01, 1.7041655690534233e-01, 1.3959184263252383e-01, 1.0555264545810959e-01, 7.3664835869183778e-02, 4.7438564768728979e-02, 2.8181096910943754e-02, 1.5437973179493971e-02, 7.7957038787030220e-03, 3.6270593070595858e-03, 1.5540467884754450e-03, 6.1281987967776825e-04, 2.2227085873416057e-04, 7.4097922186640899e-05, 2.2686436750985634e-05, 6.3737479499140128e-06, 1.6416874675897103e-06, 3.8727287415554441e-07, 8.3579939555984911e-08, 1.6482913905846427e-08, 2.9666085963352118e-09, 4.8661361388782973e-10, 7.2637761188053839e-11, 9.8514672314148016e-12, 1.2118575324056077e-12, 1.3496086984992707e-13, 1.3580008734485746e-14, 1.2319403285686423e-15, 1.0052255425278666e-16, 7.3591325007878809e-18, 4.8205257099851608e-19, 2.8169790254203712e-20, 1.4638683297363268e-21, 6.7411887298015296e-23, 2.7405597239380626e-24, 9.7951708742326283e-26, 3.0639885163656867e-27, 8.3465290951830949e-29, 1.9692128985290527e-30, 3.9996687161846431e-32, 6.9469156975836022e-34, 1.0241410150378061e-35, 1.2708875196505519e-37, 1.3151165218678305e-39, 1.1228680356492188e-41, 7.8155861441480535e-44, 4.3737554297590874e-46, 1.9366833085713306e-48, 6.6597646076210362e-51, 1.7396913258105826e-53, 3.3622797072552750e-56, 4.6560392499732150e-59, 4.4400764524986828e-62, 2.7730751722659017e-65, 1.0626701542492299e-68, 2.2885780042663531e-72, 2.4475687753038470e-76, 1.0797361898132115e-80, 1.4482784276490109e-85, 3.3027195553941757e-91, 2.9088440757674062e-98}, {4.1905794490628812e-99, 4.9990906972957580e-92, 2.2852295477811565e-86, 1.7690369566797577e-81, 4.1535499466158161e-77, 4.0157584892449402e-73, 1.9255984704437394e-69, 5.1840723409278860e-66, 8.5567547361303599e-63, 9.2443848020406234e-60, 6.8742017262988808e-57, 3.6611032011247543e-54, 1.4421371050636836e-51, 4.3141707603430363e-49, 1.0020507711410342e-46, 1.8412712525866596e-44, 2.7198617815524323e-42, 3.2749113002444449e-40, 3.2533264664077919e-38, 2.6949141835666013e-36, 1.8790207698162015e-34, 1.1120314056802636e-32, 5.6279071396682005e-31, 2.4520940513432773e-29, 9.2537661461189014e-28, 3.0414019572106789e-26, 8.7492009712123219e-25, 2.2129732702532020e-23, 4.9419868423536690e-22, 9.7813379414413797e-21, 1.7218091698469169e-19, 2.7043296085128987e-18, 3.8011128040478799e-17, 4.7943347392243567e-16, 5.4401721259012553e-15, 5.5664982903187763e-14, 5.1473099468312146e-13, 4.3100503800704298e-12, 3.2741601230785952e-11, 2.2604055819337785e-10, 1.4204990214913607e-09, 8.1379035349171669e-09, 4.2560154044109738e-08, 2.0345626953177357e-07, 8.9008863258739004e-07, 3.5675339063854564e-06, 1.3113467580430861e-05, 4.4247522456022853e-05, 1.3716931938884588e-04, 3.9098949747131122e-04, 1.0254795244170039e-03, 2.4764405325003970e-03, 5.5096709995779728e-03, 1.1299305506959472e-02, 2.1370374426895520e-02, 3.7289628484137964e-02, 6.0053278089003327e-02, 8.9287739344200062e-02, 1.2259255262751995e-01, 1.5546821084992313e-01, 1.8213364120711689e-01, 1.9713037059257607e-01, 1.9713037059257607e-01, 1.8213364120711689e-01, 1.5546821084992313e-01, 1.2259255262751995e-01, 8.9287739344200062e-02, 6.0053278089003327e-02, 3.7289628484137964e-02, 2.1370374426895520e-02, 1.1299305506959472e-02, 5.5096709995779728e-03, 2.4764405325003970e-03, 1.0254795244170039e-03, 3.9098949747131122e-04, 1.3716931938884588e-04, 4.4247522456022853e-05, 1.3113467580430861e-05, 3.5675339063854564e-06, 8.9008863258739004e-07, 2.0345626953177357e-07, 4.2560154044109738e-08, 8.1379035349171669e-09, 1.4204990214913607e-09, 2.2604055819337785e-10, 3.2741601230785952e-11, 4.3100503800704298e-12, 5.1473099468312146e-13, 5.5664982903187763e-14, 5.4401721259012553e-15, 4.7943347392243567e-16, 3.8011128040478799e-17, 2.7043296085128987e-18, 1.7218091698469169e-19, 9.7813379414413797e-21, 4.9419868423536690e-22, 2.2129732702532020e-23, 8.7492009712123219e-25, 3.0414019572106789e-26, 9.2537661461189014e-28, 2.4520940513432773e-29, 5.6279071396682005e-31, 1.1120314056802636e-32, 1.8790207698162015e-34, 2.6949141835666013e-36, 3.2533264664077919e-38, 3.2749113002444449e-40, 2.7198617815524323e-42, 1.8412712525866596e-44, 1.0020507711410342e-46, 4.3141707603430363e-49, 1.4421371050636836e-51, 3.6611032011247543e-54, 6.8742017262988808e-57, 9.2443848020406234e-60, 8.5567547361303599e-63, 5.1840723409278860e-66, 1.9255984704437394e-69, 4.0157584892449402e-73, 4.1535499466158161e-77, 1.7690369566797577e-81, 2.2852295477811565e-86, 4.9990906972957580e-92, 4.1905794490628812e-99}, {6.0350604964534262e-100, 7.5621198682031623e-93, 3.6027698446759891e-87, 2.8952659291406100e-82, 7.0395367135995835e-78, 7.0359072121742493e-74, 3.4833403833073089e-70, 9.6729013253984892e-67, 1.6455761362144333e-63, 1.8312341591411876e-60, 1.4019398864694188e-57, 7.6839475145600301e-55, 3.1138694261390015e-52, 9.5806542034971832e-50, 2.2882121049633724e-47, 4.3227155768633621e-45, 6.5638401618338331e-43, 8.1233879274180601e-41, 8.2938969771250512e-39, 7.0606944403026099e-37, 5.0593403396440372e-35, 3.0770662798790086e-33, 1.6004068212453668e-31, 7.1663558200524862e-30, 2.7795790004930404e-28, 9.3899224442264679e-27, 2.7766379169834465e-25, 7.2198960174204195e-24, 1.6577060031062816e-22, 3.3737146353721905e-21, 6.1074208727145320e-20, 9.8664119741289685e-19, 1.4266141735959953e-17, 1.8513770722928222e-16, 2.1618705462400890e-15, 2.2768505441090677e-14, 2.1674951892336612e-13, 1.8688765345567561e-12, 1.4622404081860438e-11, 1.0399946851470756e-10, 6.7347582712586187e-10, 3.9769084715886220e-09, 2.1444167115213114e-08, 1.0572466663977363e-07, 4.7716606625319424e-07, 1.9736622489528508e-06, 7.4891717673847164e-06, 2.6095502713919602e-05, 8.3569751965942746e-05, 2.4616923611611111e-04, 6.6748228082773623e-04, 1.6670890148279265e-03, 3.8375633568742918e-03, 8.1464528080591927e-03, 1.5955521786480558e-02, 2.8845081137418717e-02, 4.8152169340609514e-02, 7.4248071076568556e-02, 1.0577887521500248e-01, 1.3926890249425167e-01, 1.6948290095730328e-01, 1.9066351798670744e-01, 1.9829478313399460e-01, 1.9066351798670744e-01, 1.6948290095730328e-01, 1.3926890249425167e-01, 1.0577887521500248e-01, 7.4248071076568556e-02, 4.8152169340609514e-02, 2.8845081137418717e-02, 1.5955521786480558e-02, 8.1464528080591927e-03, 3.8375633568742918e-03, 1.6670890148279265e-03, 6.6748228082773623e-04, 2.4616923611611111e-04, 8.3569751965942746e-05, 2.6095502713919602e-05, 7.4891717673847164e-06, 1.9736622489528508e-06, 4.7716606625319424e-07, 1.0572466663977363e-07, 2.1444167115213114e-08, 3.9769084715886220e-09, 6.7347582712586187e-10, 1.0399946851470756e-10, 1.4622404081860438e-11, 1.8688765345567561e-12, 2.1674951892336612e-13, 2.2768505441090677e-14, 2.1618705462400890e-15, 1.8513770722928222e-16, 1.4266141735959953e-17, 9.8664119741289685e-19, 6.1074208727145320e-20, 3.3737146353721905e-21, 1.6577060031062816e-22, 7.2198960174204195e-24, 2.7766379169834465e-25, 9.3899224442264679e-27, 2.7795790004930404e-28, 7.1663558200524862e-30, 1.6004068212453668e-31, 3.0770662798790086e-33, 5.0593403396440372e-35, 7.0606944403026099e-37, 8.2938969771250512e-39, 8.1233879274180601e-41, 6.5638401618338331e-43, 4.3227155768633621e-45, 2.2882121049633724e-47, 9.5806542034971832e-50, 3.1138694261390015e-52, 7.6839475145600301e-55, 1.4019398864694188e-57, 1.8312341591411876e-60, 1.6455761362144333e-63, 9.6729013253984892e-67, 3.4833403833073089e-70, 7.0359072121742493e-74, 7.0395367135995835e-78, 2.8952659291406100e-82, 3.6027698446759891e-87, 7.5621198682031623e-93, 6.0350604964534262e-100}, {8.6885048841104336e-101, 1.1432282229672125e-93, 5.6751482819801390e-88, 4.7334609039691596e-83, 1.1915620124280458e-78, 1.2309273526337388e-74, 6.2907076772692688e-71, 1.8014846076367508e-67, 3.1581319803836728e-64, 3.6193344722347900e-61, 2.8521414298372380e-58, 1.6084468211903416e-55, 6.7043872367938317e-53, 2.1211541634033625e-50, 5.2082971293259102e-48, 1.0113496653683935e-45, 1.5782902465389378e-43, 2.0072591434893221e-41, 2.1058526230258254e-39, 1.8420302384806772e-37, 1.3561579038335388e-35, 8.4745466577882083e-34, 4.5287460314884707e-32, 2.0836578377129600e-30, 8.3043823092881025e-29, 2.8828182366037129e-27, 8.7606149843747518e-26, 2.3412386562212859e-24, 5.5254399484537480e-23, 1.1560142775887639e-21, 2.1516151218938123e-20, 3.5742061956149856e-19, 5.3150514071326065e-18, 7.0949360015714532e-17, 8.5234045323955501e-16, 9.2369780981720531e-15, 9.0500846874230352e-14, 8.0327883964150772e-13, 6.4713186612400961e-12, 4.7401870432354588e-11, 3.1621598261836951e-10, 1.9240529197354846e-09, 1.0693195796935537e-08, 5.4353072977389075e-08, 2.5298490233788676e-07, 1.0794646043238905e-06, 4.2268677400739964e-06, 1.5203524203072556e-05, 5.0277271260002348e-05, 1.5298771765756425e-04, 4.2867197747952282e-04, 1.1068159448702048e-03, 2.6349882348356921e-03, 5.7873557283189625e-03, 1.1732759367031630e-02, 2.1965177289949588e-02, 3.7988873885061170e-02, 6.0717658137057637e-02, 8.9709385493087268e-02, 1.2255485603934885e-01, 1.5483776980551858e-01, 1.8094215487742904e-01, 1.9559636350108756e-01, 1.9559636350108756e-01, 1.8094215487742904e-01, 1.5483776980551858e-01, 1.2255485603934885e-01, 8.9709385493087268e-02, 6.0717658137057637e-02, 3.7988873885061170e-02, 2.1965177289949588e-02, 1.1732759367031630e-02, 5.7873557283189625e-03, 2.6349882348356921e-03, 1.1068159448702048e-03, 4.2867197747952282e-04, 1.5298771765756425e-04, 5.0277271260002348e-05, 1.5203524203072556e-05, 4.2268677400739964e-06, 1.0794646043238905e-06, 2.5298490233788676e-07, 5.4353072977389075e-08, 1.0693195796935537e-08, 1.9240529197354846e-09, 3.1621598261836951e-10, 4.7401870432354588e-11, 6.4713186612400961e-12, 8.0327883964150772e-13, 9.0500846874230352e-14, 9.2369780981720531e-15, 8.5234045323955501e-16, 7.0949360015714532e-17, 5.3150514071326065e-18, 3.5742061956149856e-19, 2.1516151218938123e-20, 1.1560142775887639e-21, 5.5254399484537480e-23, 2.3412386562212859e-24, 8.7606149843747518e-26, 2.8828182366037129e-27, 8.3043823092881025e-29, 2.0836578377129600e-30, 4.5287460314884707e-32, 8.4745466577882083e-34, 1.3561579038335388e-35, 1.8420302384806772e-37, 2.1058526230258254e-39, 2.0072591434893221e-41, 1.5782902465389378e-43, 1.0113496653683935e-45, 5.2082971293259102e-48, 2.1211541634033625e-50, 6.7043872367938317e-53, 1.6084468211903416e-55, 2.8521414298372380e-58, 3.6193344722347900e-61, 3.1581319803836728e-64, 1.8014846076367508e-67, 6.2907076772692688e-71, 1.2309273526337388e-74, 1.1915620124280458e-78, 4.7334609039691596e-83, 5.6751482819801390e-88, 1.1432282229672125e-93, 8.6885048841104336e-101}, {1.2504497509175530e-101, 1.7272798059471284e-94, 8.9321681572258524e-89, 7.7306185241136030e-84, 2.0143957652711162e-79, 2.1503714733677984e-75, 1.1341924208630308e-71, 3.3489139011900278e-68, 6.0486548964206330e-65, 7.1375092946576251e-62, 5.7884563375067011e-59, 3.3581166223962448e-56, 1.4394641949298623e-53, 4.6821808383361703e-51, 1.1817054440721172e-48, 2.3581659156082481e-46, 3.7814427940915093e-44, 4.9411031115925398e-42, 5.3255303775590573e-40, 4.7854390680281889e-38, 3.6191883446065631e-36, 2.3232083386416384e-34, 1.2753331411048401e-32, 6.0277753850946330e-31, 2.4679773241853991e-29, 8.8019567691972675e-28, 2.7482489212126092e-26, 7.5468218903320873e-25, 1.8303134636337642e-23, 3.9355990860983814e-22, 7.5293161638815711e-21, 1.2857997786762843e-19, 1.9659326888507207e-18, 2.6986511907298130e-17, 3.3344414303302576e-16, 3.7173303125266623e-15, 3.7473954472956373e-14, 3.4230094493503872e-13, 2.8385303725081926e-12, 2.1406920290521382e-11, 1.4706331273477511e-10, 9.2173940967721533e-10, 5.2781663937137130e-09, 2.7650497045037171e-08, 1.3267855842580783e-07, 5.8380944276295039e-07, 2.3581561724849069e-06, 8.7524468034552877e-06, 2.9876790536001972e-05, 9.3874435720364848e-05, 2.7170762628015821e-04, 7.2493929742724068e-04, 1.7841208326818967e-03, 4.0524855186172149e-03, 8.5000263041808636e-03, 1.6471142241660967e-02, 2.9499296248305443e-02, 4.8847387114452009e-02, 7.4807989768816377e-02, 1.0598520508123921e-01, 1.3893945309094766e-01, 1.6856236074260383e-01, 1.8927849580179334e-01, 1.9673340688884505e-01, 1.8927849580179334e-01, 1.6856236074260383e-01, 1.3893945309094766e-01, 1.0598520508123921e-01, 7.4807989768816377e-02, 4.8847387114452009e-02, 2.9499296248305443e-02, 1.6471142241660967e-02, 8.5000263041808636e-03, 4.0524855186172149e-03, 1.7841208326818967e-03, 7.2493929742724068e-04, 2.7170762628015821e-04, 9.3874435720364848e-05, 2.9876790536001972e-05, 8.7524468034552877e-06, 2.3581561724849069e-06, 5.8380944276295039e-07, 1.3267855842580783e-07, 2.7650497045037171e-08, 5.2781663937137130e-09, 9.2173940967721533e-10, 1.4706331273477511e-10, 2.1406920290521382e-11, 2.8385303725081926e-12, 3.4230094493503872e-13, 3.7473954472956373e-14, 3.7173303125266623e-15, 3.3344414303302576e-16, 2.6986511907298130e-17, 1.9659326888507207e-18, 1.2857997786762843e-19, 7.5293161638815711e-21, 3.9355990860983814e-22, 1.8303134636337642e-23, 7.5468218903320873e-25, 2.7482489212126092e-26, 8.8019567691972675e-28, 2.4679773241853991e-29, 6.0277753850946330e-31, 1.2753331411048401e-32, 2.3232083386416384e-34, 3.6191883446065631e-36, 4.7854390680281889e-38, 5.3255303775590573e-40, 4.9411031115925398e-42, 3.7814427940915093e-44, 2.3581659156082481e-46, 1.1817054440721172e-48, 4.6821808383361703e-51, 1.4394641949298623e-53, 3.3581166223962448e-56, 5.7884563375067011e-59, 7.1375092946576251e-62, 6.0486548964206330e-65, 3.3489139011900278e-68, 1.1341924208630308e-71, 2.1503714733677984e-75, 2.0143957652711162e-79, 7.7306185241136030e-84, 8.9321681572258524e-89, 1.7272798059471284e-94, 1.2504497509175530e-101}, {1.7990659801093241e-102, 2.6081724024084728e-95, 1.4046897713151180e-89, 1.2612494833385409e-84, 3.4012300869368197e-80, 3.7512158688048432e-76, 2.0415857972441075e-72, 6.2142441618306433e-69, 1.1561551640964042e-65, 1.4044672577405165e-62, 1.1719785012130235e-59, 6.9930729240520693e-57, 3.0820773833392742e-54, 1.0304862520557101e-51, 2.6727437517360924e-49, 5.4802170289787664e-47, 9.0280401387865924e-45, 1.2117795341306277e-42, 1.3414974817643660e-40, 1.2380855579763670e-38, 9.6167080679676503e-37, 6.3399135263665769e-35, 3.5743788958794533e-33, 1.7351030202821157e-31, 7.2965450067684075e-30, 2.6729236200580738e-28, 8.5728304837693986e-27, 2.4184034596476935e-25, 6.0259840320064904e-24, 1.3313678590335932e-22, 2.6174575839348305e-21, 4.5940076773297253e-20, 7.2201073169282769e-19, 1.0189332304232922e-17, 1.2945481593393717e-16, 1.4842238375138792e-15, 1.5390497303535517e-14, 1.4463473211904274e-13, 1.2342144866005691e-12, 9.5803165087358731e-12, 6.7757804877745394e-11, 4.3731866598484108e-10, 2.5793972294264184e-09, 1.3921907152935201e-08, 6.8845811221543303e-08, 3.1228729861789030e-07, 1.3007470032382014e-06, 4.9799245325909927e-06, 1.7540485848093888e-05, 5.6887437600402582e-05, 1.7001408826280900e-04, 4.6855153780841227e-04, 1.1915638144571682e-03, 2.7978394016057863e-03, 6.0688624069258814e-03, 1.2166918864469335e-02, 2.2554310167824408e-02, 3.8673954810636818e-02, 6.1360721004490068e-02, 9.0108678376448870e-02, 1.2250327316413555e-01, 1.5421043529835440e-01, 1.7977308390779931e-01, 1.9409761186408808e-01, 1.9409761186408808e-01, 1.7977308390779931e-01, 1.5421043529835440e-01, 1.2250327316413555e-01, 9.0108678376448870e-02, 6.1360721004490068e-02, 3.8673954810636818e-02, 2.2554310167824408e-02, 1.2166918864469335e-02, 6.0688624069258814e-03, 2.7978394016057863e-03, 1.1915638144571682e-03, 4.6855153780841227e-04, 1.7001408826280900e-04, 5.6887437600402582e-05, 1.7540485848093888e-05, 4.9799245325909927e-06, 1.3007470032382014e-06, 3.1228729861789030e-07, 6.8845811221543303e-08, 1.3921907152935201e-08, 2.5793972294264184e-09, 4.3731866598484108e-10, 6.7757804877745394e-11, 9.5803165087358731e-12, 1.2342144866005691e-12, 1.4463473211904274e-13, 1.5390497303535517e-14, 1.4842238375138792e-15, 1.2945481593393717e-16, 1.0189332304232922e-17, 7.2201073169282769e-19, 4.5940076773297253e-20, 2.6174575839348305e-21, 1.3313678590335932e-22, 6.0259840320064904e-24, 2.4184034596476935e-25, 8.5728304837693986e-27, 2.6729236200580738e-28, 7.2965450067684075e-30, 1.7351030202821157e-31, 3.5743788958794533e-33, 6.3399135263665769e-35, 9.6167080679676503e-37, 1.2380855579763670e-38, 1.3414974817643660e-40, 1.2117795341306277e-42, 9.0280401387865924e-45, 5.4802170289787664e-47, 2.6727437517360924e-49, 1.0304862520557101e-51, 3.0820773833392742e-54, 6.9930729240520693e-57, 1.1719785012130235e-59, 1.4044672577405165e-62, 1.1561551640964042e-65, 6.2142441618306433e-69, 2.0415857972441075e-72, 3.7512158688048432e-76, 3.4012300869368197e-80, 1.2612494833385409e-84, 1.4046897713151180e-89, 2.6081724024084728e-95, 1.7990659801093241e-102}, {2.5875539364524082e-103, 3.9360184590802221e-96, 2.2072552957748285e-90, 2.0556308729779607e-85, 5.7358476340730861e-81, 6.5345649901409931e-77, 3.6690360645455800e-73, 1.1510510197511481e-69, 2.2055377414515242e-66, 2.7576366331120112e-63, 2.3673174707161052e-60, 1.4525786040323095e-57, 6.5811912152939833e-55, 2.2613773295130902e-52, 6.0264301132977530e-50, 1.2693840763809051e-47, 2.1479177879979361e-45, 2.9609218353788539e-43, 3.3661609053282785e-41, 3.1901478352848241e-39, 2.5443979671277979e-37, 1.7223946532210455e-35, 9.9710553873521448e-34, 4.9700994335207590e-32, 2.1462063060723877e-30, 8.0737792155578718e-29, 2.6593692402816157e-27, 7.7051505318327598e-26, 1.9720496638158951e-24, 4.4757971347544071e-23, 9.0403370335874384e-22, 1.6303640703529370e-20, 2.6332049182645191e-19, 3.8194419802784429e-18, 4.9883327330781313e-17, 5.8802277275507751e-16, 6.2702394771473180e-15, 6.0607257135908391e-14, 5.3204907075388442e-13, 4.2495506587750072e-12, 3.0933020393247358e-11, 2.0552435298786022e-10, 1.2482251818681576e-09, 6.9389671445373625e-09, 3.5351823460523453e-08, 1.6525270457753961e-07, 7.0953503060139187e-07, 2.8010603367707380e-06, 1.0176471541446871e-05, 3.4054184172402124e-05, 1.0504748699764762e-04, 2.9892250594151955e-04, 7.8519722061027154e-04, 1.9050667392793649e-03, 4.2716207417923171e-03, 8.8560992639436561e-03, 1.6984511709158091e-02, 3.0143653484891619e-02, 4.9524590136894565e-02, 7.5345450641660414e-02, 1.0617266978963312e-01, 1.3860414698078849e-01, 1.6765473214361890e-01, 1.8792309546385810e-01, 1.9520834171916421e-01, 1.8792309546385810e-01, 1.6765473214361890e-01, 1.3860414698078849e-01, 1.0617266978963312e-01, 7.5345450641660414e-02, 4.9524590136894565e-02, 3.0143653484891619e-02, 1.6984511709158091e-02, 8.8560992639436561e-03, 4.2716207417923171e-03, 1.9050667392793649e-03, 7.8519722061027154e-04, 2.9892250594151955e-04, 1.0504748699764762e-04, 3.4054184172402124e-05, 1.0176471541446871e-05, 2.8010603367707380e-06, 7.0953503060139187e-07, 1.6525270457753961e-07, 3.5351823460523453e-08, 6.9389671445373625e-09, 1.2482251818681576e-09, 2.0552435298786022e-10, 3.0933020393247358e-11, 4.2495506587750072e-12, 5.3204907075388442e-13, 6.0607257135908391e-14, 6.2702394771473180e-15, 5.8802277275507751e-16, 4.9883327330781313e-17, 3.8194419802784429e-18, 2.6332049182645191e-19, 1.6303640703529370e-20, 9.0403370335874384e-22, 4.4757971347544071e-23, 1.9720496638158951e-24, 7.7051505318327598e-26, 2.6593692402816157e-27, 8.0737792155578718e-29, 2.1462063060723877e-30, 4.9700994335207590e-32, 9.9710553873521448e-34, 1.7223946532210455e-35, 2.5443979671277979e-37, 3.1901478352848241e-39, 3.3661609053282785e-41, 2.9609218353788539e-43, 2.1479177879979361e-45, 1.2693840763809051e-47, 6.0264301132977530e-50, 2.2613773295130902e-52, 6.5811912152939833e-55, 1.4525786040323095e-57, 2.3673174707161052e-60, 2.7576366331120112e-63, 2.2055377414515242e-66, 1.1510510197511481e-69, 3.6690360645455800e-73, 6.5345649901409931e-77, 5.7358476340730861e-81, 2.0556308729779607e-85, 2.2072552957748285e-90, 3.9360184590802221e-96, 2.5875539364524082e-103}, {3.7204460108518457e-104, 5.9364731594787663e-97, 3.4655965116643281e-91, 3.3469757581791224e-86, 9.6613261772636215e-82, 1.1367258528662723e-77, 6.5833865033387550e-74, 2.1283034461639501e-70, 4.1991937638649886e-67, 5.4030149717578019e-64, 4.7707625290237234e-61, 3.0097211186016156e-58, 1.4015247946309535e-55, 4.9483338463613849e-53, 1.3546817753059001e-50, 2.9307665929739616e-48, 5.0927511908300209e-46, 7.2087130229885203e-44, 8.4144007328158726e-42, 8.1870801342500945e-40, 6.7037119216509246e-38, 4.6587143166611642e-36, 2.7687058280430152e-34, 1.4168038025321554e-32, 6.2811433857681812e-31, 2.4259782593432643e-29, 8.2046076950332880e-28, 2.4409654886964413e-26, 6.4156025663739209e-25, 1.4954510277528916e-23, 3.1025363444064255e-22, 5.7477855676921120e-21, 9.5376732466503112e-20, 1.4215508257408722e-18, 1.9080516525917262e-17, 2.3119223992445814e-16, 2.5344536275316043e-15, 2.5189945152766989e-14, 2.2742721378405763e-13, 1.8685821935956322e-12, 1.3994739517759176e-11, 9.5692629429270517e-11, 5.9825297159286590e-10, 3.4243028086561824e-09, 1.7967512803433057e-08, 8.6525026250843954e-08, 3.8283102346903316e-07, 1.5578439536677208e-06, 5.8357960655860304e-06, 2.0142490747188856e-05, 6.4107957353545819e-05, 1.8828587640798520e-04, 5.1065276380199355e-04, 1.2796927737216395e-03, 2.9648560622765260e-03, 6.3539216222626869e-03, 1.2601446134450314e-02, 2.3137547830647125e-02, 3.9345000709058629e-02, 6.1983091960651798e-02, 9.0486600174251544e-02, 1.2243869169055180e-01, 1.5358645412541436e-01, 1.7862576228606980e-01, 1.9263278589714239e-01, 1.9263278589714239e-01, 1.7862576228606980e-01, 1.5358645412541436e-01, 1.2243869169055180e-01, 9.0486600174251544e-02, 6.1983091960651798e-02, 3.9345000709058629e-02, 2.3137547830647125e-02, 1.2601446134450314e-02, 6.3539216222626869e-03, 2.9648560622765260e-03, 1.2796927737216395e-03, 5.1065276380199355e-04, 1.8828587640798520e-04, 6.4107957353545819e-05, 2.0142490747188856e-05, 5.8357960655860304e-06, 1.5578439536677208e-06, 3.8283102346903316e-07, 8.6525026250843954e-08, 1.7967512803433057e-08, 3.4243028086561824e-09, 5.9825297159286590e-10, 9.5692629429270517e-11, 1.3994739517759176e-11, 1.8685821935956322e-12, 2.2742721378405763e-13, 2.5189945152766989e-14, 2.5344536275316043e-15, 2.3119223992445814e-16, 1.9080516525917262e-17, 1.4215508257408722e-18, 9.5376732466503112e-20, 5.7477855676921120e-21, 3.1025363444064255e-22, 1.4954510277528916e-23, 6.4156025663739209e-25, 2.4409654886964413e-26, 8.2046076950332880e-28, 2.4259782593432643e-29, 6.2811433857681812e-31, 1.4168038025321554e-32, 2.7687058280430152e-34, 4.6587143166611642e-36, 6.7037119216509246e-38, 8.1870801342500945e-40, 8.4144007328158726e-42, 7.2087130229885203e-44, 5.0927511908300209e-46, 2.9307665929739616e-48, 1.3546817753059001e-50, 4.9483338463613849e-53, 1.4015247946309535e-55, 3.0097211186016156e-58, 4.7707625290237234e-61, 5.4030149717578019e-64, 4.1991937638649886e-67, 2.1283034461639501e-70, 6.5833865033387550e-74, 1.1367258528662723e-77, 9.6613261772636215e-82, 3.3469757581791224e-86, 3.4655965116643281e-91, 5.9364731594787663e-97, 3.7204460108518457e-104}, {5.3476826111026365e-105, 8.9485710679509321e-98, 5.4370243471100807e-92, 5.4441378603550616e-87, 1.6254006780310087e-82, 1.9746831356131776e-78, 1.1794217215696164e-74, 3.9284007348254153e-71, 7.9796183204186807e-68, 1.0563843092209409e-64, 9.5924087114315112e-62, 6.2207574186530967e-59, 2.9767954168841160e-56, 1.0797369730934170e-53, 3.0360436451965334e-51, 6.7450137912280108e-49, 1.2034270735300903e-46, 1.7487964745761127e-44, 2.0954606929273772e-42, 2.0928182450743565e-40, 1.7589155981687000e-38, 1.2546216106083190e-36, 7.6531182757967849e-35, 4.0196809205772165e-33, 1.8291657781800354e-31, 7.2519108515928950e-30, 2.5176731485459177e-28, 7.6897052483356061e-27, 2.0750476694679341e-25, 4.9664572942742541e-24, 1.0580876836793333e-22, 2.0131999550178635e-21, 3.4313613065500532e-20, 5.2539364144662411e-19, 7.2456324501572317e-18, 9.0217967422636200e-17, 1.0165109952415262e-15, 1.0385841011593362e-14, 9.6411044899350535e-14, 8.1461816331285264e-13, 6.2756146921948126e-12, 4.4148505508362490e-11, 2.8403341656010478e-10, 1.6734368028761769e-09, 9.0404035956869064e-09, 4.4835197499650446e-08, 2.0435322677073055e-07, 8.5687946165889204e-07, 3.3086178947400949e-06, 1.1774562755908359e-05, 3.8651667203812415e-05, 1.1712338225370822e-04, 3.2784720468186990e-04, 8.4825701574449603e-04, 2.0298461578116241e-03, 4.4947646714684642e-03, 9.2143589576985860e-03, 1.7495331329372001e-02, 3.0778087957022211e-02, 5.0184153739443245e-02, 7.5861280569172768e-02, 1.0634224601517195e-01, 1.3826358695373833e-01, 1.6675980772407939e-01, 1.8659628095711822e-01, 1.9371820170604062e-01, 1.8659628095711822e-01, 1.6675980772407939e-01, 1.3826358695373833e-01, 1.0634224601517195e-01, 7.5861280569172768e-02, 5.0184153739443245e-02, 3.0778087957022211e-02, 1.7495331329372001e-02, 9.2143589576985860e-03, 4.4947646714684642e-03, 2.0298461578116241e-03, 8.4825701574449603e-04, 3.2784720468186990e-04, 1.1712338225370822e-04, 3.8651667203812415e-05, 1.1774562755908359e-05, 3.3086178947400949e-06, 8.5687946165889204e-07, 2.0435322677073055e-07, 4.4835197499650446e-08, 9.0404035956869064e-09, 1.6734368028761769e-09, 2.8403341656010478e-10, 4.4148505508362490e-11, 6.2756146921948126e-12, 8.1461816331285264e-13, 9.6411044899350535e-14, 1.0385841011593362e-14, 1.0165109952415262e-15, 9.0217967422636200e-17, 7.2456324501572317e-18, 5.2539364144662411e-19, 3.4313613065500532e-20, 2.0131999550178635e-21, 1.0580876836793333e-22, 4.9664572942742541e-24, 2.0750476694679341e-25, 7.6897052483356061e-27, 2.5176731485459177e-28, 7.2519108515928950e-30, 1.8291657781800354e-31, 4.0196809205772165e-33, 7.6531182757967849e-35, 1.2546216106083190e-36, 1.7589155981687000e-38, 2.0928182450743565e-40, 2.0954606929273772e-42, 1.7487964745761127e-44, 1.2034270735300903e-46, 6.7450137912280108e-49, 3.0360436451965334e-51, 1.0797369730934170e-53, 2.9767954168841160e-56, 6.2207574186530967e-59, 9.5924087114315112e-62, 1.0563843092209409e-64, 7.9796183204186807e-68, 3.9284007348254153e-71, 1.1794217215696164e-74, 1.9746831356131776e-78, 1.6254006780310087e-82, 5.4441378603550616e-87, 5.4370243471100807e-92, 8.9485710679509321e-98, 5.3476826111026365e-105}, {7.6842766516367719e-106, 1.3481426814084330e-98, 8.5232824201455338e-93, 8.8466828631703380e-88, 2.7313386049487823e-83, 3.4257032455364114e-79, 2.1096988030040495e-75, 7.2385503439630423e-72, 1.5134726683009566e-68, 2.0611376551597914e-65, 1.9243761113547505e-62, 1.2826427266230406e-59, 6.3061655444515630e-57, 2.3494568244414183e-54, 6.7840814198640183e-52, 1.5474546466895863e-49, 2.8342684935250220e-47, 4.2276037377430170e-45, 5.1990976532787586e-43, 5.3289760352121873e-41, 4.5962221753185640e-39, 3.3643504079348503e-37, 2.1059885157863759e-35, 1.1351213650894055e-33, 5.3008778122412928e-32, 2.1567929048213211e-30, 7.6849291812936124e-29, 2.4091492702687982e-27, 6.6731359742375955e-26, 1.6395930158211436e-24, 3.5862705417926132e-23, 7.0063164858326786e-22, 1.2263229445163221e-20, 1.9284904334361852e-19, 2.7319104369658748e-18, 3.4946872798000184e-17, 4.0459872349113726e-16, 4.2484216574797647e-15, 4.0538431929767204e-14, 3.5215468617192942e-13, 2.7897431630242835e-12, 2.0185811443148509e-11, 1.3360415395259884e-10, 8.0999556201008525e-10, 4.5039223844610038e-09, 2.2996588427898263e-08, 1.0794018969942840e-07, 4.6622930297370394e-07, 1.8549414274389103e-06, 6.8039737747046242e-06, 2.3027980530130599e-05, 7.1968372723672767e-05, 2.0783849443716974e-04, 5.5499593798384811e-04, 1.3711669594184176e-03, 3.1358975655376973e-03, 6.6422701758844281e-03, 1.3036021883614270e-02, 2.3714690293508239e-02, 4.0002156173129341e-02, 6.2585382403901088e-02, 9.0844086374182967e-02, 1.2236194224535350e-01, 1.5296604436543901e-01, 1.7749954969646717e-01, 1.9120062497846860e-01, 1.9120062497846860e-01, 1.7749954969646717e-01, 1.5296604436543901e-01, 1.2236194224535350e-01, 9.0844086374182967e-02, 6.2585382403901088e-02, 4.0002156173129341e-02, 2.3714690293508239e-02, 1.3036021883614270e-02, 6.6422701758844281e-03, 3.1358975655376973e-03, 1.3711669594184176e-03, 5.5499593798384811e-04, 2.0783849443716974e-04, 7.1968372723672767e-05, 2.3027980530130599e-05, 6.8039737747046242e-06, 1.8549414274389103e-06, 4.6622930297370394e-07, 1.0794018969942840e-07, 2.2996588427898263e-08, 4.5039223844610038e-09, 8.0999556201008525e-10, 1.3360415395259884e-10, 2.0185811443148509e-11, 2.7897431630242835e-12, 3.5215468617192942e-13, 4.0538431929767204e-14, 4.2484216574797647e-15, 4.0459872349113726e-16, 3.4946872798000184e-17, 2.7319104369658748e-18, 1.9284904334361852e-19, 1.2263229445163221e-20, 7.0063164858326786e-22, 3.5862705417926132e-23, 1.6395930158211436e-24, 6.6731359742375955e-26, 2.4091492702687982e-27, 7.6849291812936124e-29, 2.1567929048213211e-30, 5.3008778122412928e-32, 1.1351213650894055e-33, 2.1059885157863759e-35, 3.3643504079348503e-37, 4.5962221753185640e-39, 5.3289760352121873e-41, 5.1990976532787586e-43, 4.2276037377430170e-45, 2.8342684935250220e-47, 1.5474546466895863e-49, 6.7840814198640183e-52, 2.3494568244414183e-54, 6.3061655444515630e-57, 1.2826427266230406e-59, 1.9243761113547505e-62, 2.0611376551597914e-65, 1.5134726683009566e-68, 7.2385503439630423e-72, 2.1096988030040495e-75, 3.4257032455364114e-79, 2.7313386049487823e-83, 8.8466828631703380e-88, 8.5232824201455338e-93, 1.3481426814084330e-98, 7.6842766516367719e-106}, {1.1038467599988350e-106, 2.0299162819709644e-99, 1.3351165545454540e-93, 1.4361908901012819e-88, 4.5844662610976337e-84, 5.9349976525016213e-80, 3.7680124485137400e-76, 1.3315304198313815e-72, 2.8651973069480425e-69, 4.0133192434618745e-66, 3.8520167842143179e-63, 2.6383248122689808e-60, 1.3324956798179218e-57, 5.0982905111217610e-55, 1.5114881547668727e-52, 3.5392080595751209e-50, 6.6532981134843764e-48, 1.0184623032786348e-45, 1.2852633429954566e-43, 1.3517324859318610e-41, 1.1962163965744953e-39, 8.9837835745312106e-38, 5.7697747333366196e-36, 3.1907496278196311e-34, 1.5288163843577720e-32, 6.3824723629696159e-31, 2.3335393536670584e-29, 7.5069091034254989e-28, 2.1339408990452690e-26, 5.3812272933845995e-25, 1.2081587782243251e-23, 2.4230032186653206e-22, 4.3541619756512954e-21, 7.0308758150274706e-20, 1.0228495371481795e-18, 1.3439170617083339e-17, 1.5983699268748500e-16, 1.7244201781932836e-15, 1.6909213145415565e-14, 1.5097790665682497e-13, 1.2295731019067163e-12, 9.1482393782595353e-12, 6.2274132191241200e-11, 3.8838846452764459e-10, 2.2221554698762070e-09, 1.1677641217752186e-08, 5.6428156340858430e-08, 2.5098662449728381e-07, 1.0285882365095455e-06, 3.8874166532037593e-06, 1.3560417245137210e-05, 4.3693239040909913e-05, 1.3013545776424483e-04, 3.5851189054336881e-04, 9.1411456482270634e-04, 2.1583740072268734e-03, 4.7217142757868197e-03, 9.5745050499428906e-03, 1.8003325023065602e-02, 3.1402556502212124e-02, 5.0826454983412143e-02, 7.6356275486723038e-02, 1.0649485597288683e-01, 1.3791833004859055e-01, 1.6587737779249406e-01, 1.8529706602349078e-01, 1.9226167387366441e-01, 1.8529706602349078e-01, 1.6587737779249406e-01, 1.3791833004859055e-01, 1.0649485597288683e-01, 7.6356275486723038e-02, 5.0826454983412143e-02, 3.1402556502212124e-02, 1.8003325023065602e-02, 9.5745050499428906e-03, 4.7217142757868197e-03, 2.1583740072268734e-03, 9.1411456482270634e-04, 3.5851189054336881e-04, 1.3013545776424483e-04, 4.3693239040909913e-05, 1.3560417245137210e-05, 3.8874166532037593e-06, 1.0285882365095455e-06, 2.5098662449728381e-07, 5.6428156340858430e-08, 1.1677641217752186e-08, 2.2221554698762070e-09, 3.8838846452764459e-10, 6.2274132191241200e-11, 9.1482393782595353e-12, 1.2295731019067163e-12, 1.5097790665682497e-13, 1.6909213145415565e-14, 1.7244201781932836e-15, 1.5983699268748500e-16, 1.3439170617083339e-17, 1.0228495371481795e-18, 7.0308758150274706e-20, 4.3541619756512954e-21, 2.4230032186653206e-22, 1.2081587782243251e-23, 5.3812272933845995e-25, 2.1339408990452690e-26, 7.5069091034254989e-28, 2.3335393536670584e-29, 6.3824723629696159e-31, 1.5288163843577720e-32, 3.1907496278196311e-34, 5.7697747333366196e-36, 8.9837835745312106e-38, 1.1962163965744953e-39, 1.3517324859318610e-41, 1.2852633429954566e-43, 1.0184623032786348e-45, 6.6532981134843764e-48, 3.5392080595751209e-50, 1.5114881547668727e-52, 5.0982905111217610e-55, 1.3324956798179218e-57, 2.6383248122689808e-60, 3.8520167842143179e-63, 4.0133192434618745e-66, 2.8651973069480425e-69, 1.3315304198313815e-72, 3.7680124485137400e-76, 5.9349976525016213e-80, 4.5844662610976337e-84, 1.4361908901012819e-88, 1.3351165545454540e-93, 2.0299162819709644e-99, 1.1038467599988350e-106}, {1.5852022154122762e-107, 3.0548054158892936e-100, 2.0897891620152027e-94, 2.3293228753706694e-89, 7.6861123200181953e-85, 1.0268748980780725e-80, 6.7197562830108496e-77, 2.4452549463378667e-73, 5.4141833815112683e-70, 7.7987351892856256e-67, 7.6937052841722558e-64, 5.4140880882527221e-61, 2.8084445413684342e-58, 1.1033315179441334e-55, 3.3578943438527196e-53, 8.0698691825802516e-51, 1.5567833435482675e-48, 2.4451923543925048e-46, 3.1658838545522830e-44, 3.4158346081733210e-42, 3.1009657171113824e-40, 2.3889887847651522e-38, 1.5738945493185839e-36, 8.9283867523289446e-35, 4.3884114191019410e-33, 1.8794344951812523e-31, 7.0495273821073143e-30, 2.3266903412110293e-28, 6.7861521642478146e-27, 1.7559922329924036e-25, 4.0458189399870260e-24, 8.3276681875539800e-23, 1.5360712580259943e-21, 2.5462929950511611e-20, 3.8033125448314512e-19, 5.1314188262140908e-18, 6.2679375130394878e-17, 6.9461573699177854e-16, 6.9976953274028973e-15, 6.4202984348233192e-14, 5.3739121421360399e-13, 4.1101386023109489e-12, 2.8767484176405797e-11, 1.8451534167067902e-10, 1.0859592046532814e-09, 5.8718148797495608e-09, 2.9201210196159125e-08, 1.3370799258052363e-07, 5.6424627677752911e-07, 2.1965028260725411e-06, 7.8943275081059988e-06, 2.6215639412143949e-05, 8.0497734201318759e-05, 2.2870525172954362e-04, 6.0159714197281571e-04, 1.4659454148941060e-03, 3.3108212147861167e-03, 6.9336514656727563e-03, 1.3470344826444706e-02, 2.4285561078700165e-02, 4.0645578943455961e-02, 6.3168189419948478e-02, 9.1182028088582376e-02, 1.2227380245007502e-01, 1.5234939813711931e-01, 1.7639383039152406e-01, 1.8979993309264909e-01, 1.8979993309264909e-01, 1.7639383039152406e-01, 1.5234939813711931e-01, 1.2227380245007502e-01, 9.1182028088582376e-02, 6.3168189419948478e-02, 4.0645578943455961e-02, 2.4285561078700165e-02, 1.3470344826444706e-02, 6.9336514656727563e-03, 3.3108212147861167e-03, 1.4659454148941060e-03, 6.0159714197281571e-04, 2.2870525172954362e-04, 8.0497734201318759e-05, 2.6215639412143949e-05, 7.8943275081059988e-06, 2.1965028260725411e-06, 5.6424627677752911e-07, 1.3370799258052363e-07, 2.9201210196159125e-08, 5.8718148797495608e-09, 1.0859592046532814e-09, 1.8451534167067902e-10, 2.8767484176405797e-11, 4.1101386023109489e-12, 5.3739121421360399e-13, 6.4202984348233192e-14, 6.9976953274028973e-15, 6.9461573699177854e-16, 6.2679375130394878e-17, 5.1314188262140908e-18, 3.8033125448314512e-19, 2.5462929950511611e-20, 1.5360712580259943e-21, 8.3276681875539800e-23, 4.0458189399870260e-24, 1.7559922329924036e-25, 6.7861521642478146e-27, 2.3266903412110293e-28, 7.0495273821073143e-30, 1.8794344951812523e-31, 4.3884114191019410e-33, 8.9283867523289446e-35, 1.5738945493185839e-36, 2.3889887847651522e-38, 3.1009657171113824e-40, 3.4158346081733210e-42, 3.1658838545522830e-44, 2.4451923543925048e-46, 1.5567833435482675e-48, 8.0698691825802516e-51, 3.3578943438527196e-53, 1.1033315179441334e-55, 2.8084445413684342e-58, 5.4140880882527221e-61, 7.6937052841722558e-64, 7.7987351892856256e-67, 5.4141833815112683e-70, 2.4452549463378667e-73, 6.7197562830108496e-77, 1.0268748980780725e-80, 7.6861123200181953e-85, 2.3293228753706694e-89, 2.0897891620152027e-94, 3.0548054158892936e-100, 1.5852022154122762e-107}, {2.2757903447048717e-108, 4.5946784737513260e-101, 3.2685938252533535e-95, 3.7743169785683037e-90, 1.2871697383667851e-85, 1.7743864842451219e-81, 1.1966100169534770e-77, 4.4831207104684604e-74, 1.0212230702897007e-70, 1.5124472591580667e-67, 1.5333631698716670e-64, 1.1084367892237507e-61, 5.9044668946443965e-59, 2.3813770140907575e-56, 7.4386721348341212e-54, 1.8345006104189449e-51, 3.6310691969704462e-49, 5.8508598523019220e-47, 7.7706802795811407e-45, 8.5997500074472335e-43, 8.0073315846684445e-41, 6.3269186795493014e-39, 4.2749818807535224e-37, 2.4872103396508171e-35, 1.2538186619197742e-33, 5.5075144968159152e-32, 2.1188905321706446e-30, 7.1735092247885270e-29, 2.1463025081080465e-27, 5.6976909711813352e-26, 1.3468870756541617e-24, 2.8447276912580344e-23, 5.3848024996122255e-22, 9.1613793530553680e-21, 1.4046424779365027e-19, 1.9456017248888693e-18, 2.4401660157799310e-17, 2.7770723790106855e-16, 2.8735526657240152e-15, 2.7084363045358423e-14, 2.3293514464982674e-13, 1.8309133143528682e-12, 1.3172552368556761e-11, 8.6866283016645484e-11, 5.2575217351973056e-10, 2.9240918874514531e-09, 1.4961568756142573e-08, 7.0502109098437831e-08, 3.0626482923803324e-07, 1.2276189268114097e-06, 4.5443796787236290e-06, 1.5548071919772645e-05, 4.9202833580003181e-05, 1.4411581751672914e-04, 3.9094357332687408e-04, 9.8276091717415027e-04, 2.2905612451458858e-03, 4.9522684042317359e-03, 9.9362495542868867e-03, 1.8508238320820009e-02, 3.2017035703904927e-02, 5.1451871301553709e-02, 7.6831201307210703e-02, 1.0663137077642493e-01, 1.3756889121351917e-01, 1.6500723131965989e-01, 1.8402451115016699e-01, 1.9083751332645207e-01, 1.8402451115016699e-01, 1.6500723131965989e-01, 1.3756889121351917e-01, 1.0663137077642493e-01, 7.6831201307210703e-02, 5.1451871301553709e-02, 3.2017035703904927e-02, 1.8508238320820009e-02, 9.9362495542868867e-03, 4.9522684042317359e-03, 2.2905612451458858e-03, 9.8276091717415027e-04, 3.9094357332687408e-04, 1.4411581751672914e-04, 4.9202833580003181e-05, 1.5548071919772645e-05, 4.5443796787236290e-06, 1.2276189268114097e-06, 3.0626482923803324e-07, 7.0502109098437831e-08, 1.4961568756142573e-08, 2.9240918874514531e-09, 5.2575217351973056e-10, 8.6866283016645484e-11, 1.3172552368556761e-11, 1.8309133143528682e-12, 2.3293514464982674e-13, 2.7084363045358423e-14, 2.8735526657240152e-15, 2.7770723790106855e-16, 2.4401660157799310e-17, 1.9456017248888693e-18, 1.4046424779365027e-19, 9.1613793530553680e-21, 5.3848024996122255e-22, 2.8447276912580344e-23, 1.3468870756541617e-24, 5.6976909711813352e-26, 2.1463025081080465e-27, 7.1735092247885270e-29, 2.1188905321706446e-30, 5.5075144968159152e-32, 1.2538186619197742e-33, 2.4872103396508171e-35, 4.2749818807535224e-37, 6.3269186795493014e-39, 8.0073315846684445e-41, 8.5997500074472335e-43, 7.7706802795811407e-45, 5.8508598523019220e-47, 3.6310691969704462e-49, 1.8345006104189449e-51, 7.4386721348341212e-54, 2.3813770140907575e-56, 5.9044668946443965e-59, 1.1084367892237507e-61, 1.5333631698716670e-64, 1.5124472591580667e-67, 1.0212230702897007e-70, 4.4831207104684604e-74, 1.1966100169534770e-77, 1.7743864842451219e-81, 1.2871697383667851e-85, 3.7743169785683037e-90, 3.2685938252533535e-95, 4.5946784737513260e-101, 2.2757903447048717e-108}, {3.2662778348790219e-109, 6.9071006009219448e-102, 5.1085629363787234e-96, 6.1100313027084669e-91, 2.1531900867437274e-86, 3.0621042209000059e-82, 2.1277376772398947e-78, 8.2059605065764682e-75, 1.9227730563170089e-71, 2.9274096096614171e-68, 3.0495045268798647e-65, 2.2641169845080718e-62, 1.2382980686348502e-59, 5.1263348642622049e-57, 1.6432629457353511e-54, 4.1579427709675079e-52, 8.4425869514003785e-50, 1.3953581486228228e-47, 1.9006681419175218e-45, 2.1571532321739302e-43, 2.0597137897723631e-41, 1.6688589526897371e-39, 1.1562775861404743e-37, 6.8982672254135044e-36, 3.5658879405329104e-34, 1.6062235506206207e-32, 6.3371488059404152e-31, 2.2002659780562692e-29, 6.7518197536098842e-28, 1.8384352926742758e-26, 4.4579796693281321e-25, 9.6593405936315995e-24, 1.8759587883105718e-22, 3.2750072247643929e-21, 5.1531219168800766e-20, 7.3260730719021186e-19, 9.4321973070076218e-18, 1.1021086847913827e-16, 1.1710396791414340e-15, 1.1336050130083279e-14, 1.0014937399406310e-13, 8.0878754293572482e-13, 5.9796723109076469e-12, 4.0531324359847441e-11, 2.5220174708373236e-10, 1.4423973477091834e-09, 7.5910433713044797e-09, 3.6801425167297173e-08, 1.6451664884983423e-07, 6.7880160807256645e-07, 2.5872670138074200e-06, 9.1170822839813128e-06, 2.9724333423383228e-05, 8.9724509010453385e-05, 2.5091729952798149e-04, 6.5046837318858926e-04, 1.5639824929501397e-03, 3.4894828544320858e-03, 7.2278157943492030e-03, 1.3904131095041473e-02, 2.4850005571417737e-02, 4.1275438102408031e-02, 6.3732095470061270e-02, 9.1501274267677846e-02, 1.2217500065832824e-01, 1.5173668408251911e-01, 1.7530801211052990e-01, 1.8842957463583779e-01, 1.8842957463583779e-01, 1.7530801211052990e-01, 1.5173668408251911e-01, 1.2217500065832824e-01, 9.1501274267677846e-02, 6.3732095470061270e-02, 4.1275438102408031e-02, 2.4850005571417737e-02, 1.3904131095041473e-02, 7.2278157943492030e-03, 3.4894828544320858e-03, 1.5639824929501397e-03, 6.5046837318858926e-04, 2.5091729952798149e-04, 8.9724509010453385e-05, 2.9724333423383228e-05, 9.1170822839813128e-06, 2.5872670138074200e-06, 6.7880160807256645e-07, 1.6451664884983423e-07, 3.6801425167297173e-08, 7.5910433713044797e-09, 1.4423973477091834e-09, 2.5220174708373236e-10, 4.0531324359847441e-11, 5.9796723109076469e-12, 8.0878754293572482e-13, 1.0014937399406310e-13, 1.1336050130083279e-14, 1.1710396791414340e-15, 1.1021086847913827e-16, 9.4321973070076218e-18, 7.3260730719021186e-19, 5.1531219168800766e-20, 3.2750072247643929e-21, 1.8759587883105718e-22, 9.6593405936315995e-24, 4.4579796693281321e-25, 1.8384352926742758e-26, 6.7518197536098842e-28, 2.2002659780562692e-29, 6.3371488059404152e-31, 1.6062235506206207e-32, 3.5658879405329104e-34, 6.8982672254135044e-36, 1.1562775861404743e-37, 1.6688589526897371e-39, 2.0597137897723631e-41, 2.1571532321739302e-43, 1.9006681419175218e-45, 1.3953581486228228e-47, 8.4425869514003785e-50, 4.1579427709675079e-52, 1.6432629457353511e-54, 5.1263348642622049e-57, 1.2382980686348502e-59, 2.2641169845080718e-62, 3.0495045268798647e-65, 2.9274096096614171e-68, 1.9227730563170089e-71, 8.2059605065764682e-75, 2.1277376772398947e-78, 3.0621042209000059e-82, 2.1531900867437274e-86, 6.1100313027084669e-91, 5.1085629363787234e-96, 6.9071006009219448e-102, 3.2662778348790219e-109}, {4.6865023080529104e-110, 1.0377874004830612e-102, 7.9784749096307812e-97, 9.8821174227967692e-92, 3.5979287498244655e-87, 5.2776428357398472e-83, 3.7779666227111211e-79, 1.4996171154683470e-75, 3.6138115204304974e-72, 5.6551650475163530e-69, 6.0520249291763858e-66, 4.6142654439156290e-63, 2.5906808193011388e-60, 1.1006724998865391e-57, 3.6200846949796910e-55, 9.3965049756134747e-53, 1.9569075431422824e-50, 3.3168917267338703e-48, 4.6329566465533973e-46, 5.3914438385767737e-44, 5.2781068509974114e-42, 4.3845152623372787e-40, 3.1144817985274696e-38, 1.9049498787300406e-36, 1.0095682854224567e-34, 4.6623959142602483e-33, 1.8860299651335772e-31, 6.7143368715209606e-30, 2.1127537039024262e-28, 5.8994042231272372e-27, 1.4671212494779564e-25, 3.2605011152464131e-24, 6.4955255161731863e-23, 1.1633403477038459e-21, 1.8781142293296228e-20, 2.7399173517222677e-19, 3.6203893599581944e-18, 4.3421867882952047e-17, 4.7366003944880216e-16, 4.7080515903807368e-15, 4.2715858467937535e-14, 3.5433804833163948e-13, 2.6914605808295047e-12, 1.8746383733203776e-11, 1.1989016690827638e-10, 7.0489725875624514e-10, 3.8145955545353021e-09, 1.9020527069551235e-08, 8.7475726975743740e-08, 3.7140992001185702e-07, 1.4571432947497977e-06, 5.2867540339888927e-06, 1.7751862632560425e-05, 5.5204240789547246e-05, 1.5909525194144218e-04, 4.2516612395155680e-04, 1.0541825457525329e-03, 2.4263153829887293e-03, 5.1862282813377051e-03, 1.0299316731984193e-02, 1.9009837222668049e-02, 3.2621520059018146e-02, 5.2060779315091815e-02, 7.7286794858634558e-02, 1.0675261357345991e-01, 1.3721574664493244e-01, 1.6414915672894112e-01, 1.8277772077559612e-01, 1.8944453877662401e-01, 1.8277772077559612e-01, 1.6414915672894112e-01, 1.3721574664493244e-01, 1.0675261357345991e-01, 7.7286794858634558e-02, 5.2060779315091815e-02, 3.2621520059018146e-02, 1.9009837222668049e-02, 1.0299316731984193e-02, 5.1862282813377051e-03, 2.4263153829887293e-03, 1.0541825457525329e-03, 4.2516612395155680e-04, 1.5909525194144218e-04, 5.5204240789547246e-05, 1.7751862632560425e-05, 5.2867540339888927e-06, 1.4571432947497977e-06, 3.7140992001185702e-07, 8.7475726975743740e-08, 1.9020527069551235e-08, 3.8145955545353021e-09, 7.0489725875624514e-10, 1.1989016690827638e-10, 1.8746383733203776e-11, 2.6914605808295047e-12, 3.5433804833163948e-13, 4.2715858467937535e-14, 4.7080515903807368e-15, 4.7366003944880216e-16, 4.3421867882952047e-17, 3.6203893599581944e-18, 2.7399173517222677e-19, 1.8781142293296228e-20, 1.1633403477038459e-21, 6.4955255161731863e-23, 3.2605011152464131e-24, 1.4671212494779564e-25, 5.8994042231272372e-27, 2.1127537039024262e-28, 6.7143368715209606e-30, 1.8860299651335772e-31, 4.6623959142602483e-33, 1.0095682854224567e-34, 1.9049498787300406e-36, 3.1144817985274696e-38, 4.3845152623372787e-40, 5.2781068509974114e-42, 5.3914438385767737e-44, 4.6329566465533973e-46, 3.3168917267338703e-48, 1.9569075431422824e-50, 9.3965049756134747e-53, 3.6200846949796910e-55, 1.1006724998865391e-57, 2.5906808193011388e-60, 4.6142654439156290e-63, 6.0520249291763858e-66, 5.6551650475163530e-69, 3.6138115204304974e-72, 1.4996171154683470e-75, 3.7779666227111211e-79, 5.2776428357398472e-83, 3.5979287498244655e-87, 9.8821174227967692e-92, 7.9784749096307812e-97, 1.0377874004830612e-102, 4.6865023080529104e-110}, {6.7223469064836171e-111, 1.5584604318709814e-103, 1.2451690475064742e-97, 1.5968463027613036e-92, 6.0055451530824495e-88, 9.0848000543271587e-84, 6.6985500695669678e-80, 2.7361658102621640e-76, 6.7802095889475983e-73, 1.0903770909317098e-69, 1.1985921850382964e-66, 9.3828601952142795e-64, 5.4070585225542087e-61, 2.3572025385780174e-58, 7.9532902157128368e-56, 2.1173804777066541e-53, 4.5220720973223149e-51, 7.8591635665593126e-49, 1.1254750686853198e-46, 1.3427041430602204e-44, 1.3474889050314146e-42, 1.1474212047422846e-40, 8.3547107388260308e-39, 5.2380609435106477e-37, 2.8455586990614318e-35, 1.3470860626931207e-33, 5.5860425698193572e-32, 2.0386781124262974e-30, 6.5767258559351848e-29, 1.8828451569167714e-27, 4.8012341582972026e-26, 1.0941854437188646e-24, 2.2355486477720061e-23, 4.1066490153458769e-22, 6.8008865930090286e-21, 1.0178867789337611e-19, 1.3800519281469149e-18, 1.6985968059071478e-17, 1.9017680123139647e-16, 1.9404932122013048e-15, 1.8076531130346059e-14, 1.5398466784483034e-13, 1.2013344715990716e-12, 8.5959906732140100e-12, 5.6487797699597178e-11, 3.4133713929443775e-10, 1.8988505331522261e-09, 9.7353434088062900e-09, 4.6047775382709491e-08, 2.0113005931537178e-07, 8.1197441052941798e-07, 3.0322448415500775e-06, 1.0482793298607957e-05, 3.3573050144199230e-05, 9.9676496285740638e-05, 2.7450358985306201e-04, 7.0161767403489428e-04, 1.6652282490644866e-03, 3.6717374087279781e-03, 7.5245206122160650e-03, 1.4337113630217399e-02, 2.5407889466847185e-02, 4.1891912442268933e-02, 6.4277668190634463e-02, 9.1802633810630571e-02, 1.2206621940114575e-01, 1.5112804960523191e-01, 1.7424152504403007e-01, 1.8708847054904945e-01, 1.8708847054904945e-01, 1.7424152504403007e-01, 1.5112804960523191e-01, 1.2206621940114575e-01, 9.1802633810630571e-02, 6.4277668190634463e-02, 4.1891912442268933e-02, 2.5407889466847185e-02, 1.4337113630217399e-02, 7.5245206122160650e-03, 3.6717374087279781e-03, 1.6652282490644866e-03, 7.0161767403489428e-04, 2.7450358985306201e-04, 9.9676496285740638e-05, 3.3573050144199230e-05, 1.0482793298607957e-05, 3.0322448415500775e-06, 8.1197441052941798e-07, 2.0113005931537178e-07, 4.6047775382709491e-08, 9.7353434088062900e-09, 1.8988505331522261e-09, 3.4133713929443775e-10, 5.6487797699597178e-11, 8.5959906732140100e-12, 1.2013344715990716e-12, 1.5398466784483034e-13, 1.8076531130346059e-14, 1.9404932122013048e-15, 1.9017680123139647e-16, 1.6985968059071478e-17, 1.3800519281469149e-18, 1.0178867789337611e-19, 6.8008865930090286e-21, 4.1066490153458769e-22, 2.2355486477720061e-23, 1.0941854437188646e-24, 4.8012341582972026e-26, 1.8828451569167714e-27, 6.5767258559351848e-29, 2.0386781124262974e-30, 5.5860425698193572e-32, 1.3470860626931207e-33, 2.8455586990614318e-35, 5.2380609435106477e-37, 8.3547107388260308e-39, 1.1474212047422846e-40, 1.3474889050314146e-42, 1.3427041430602204e-44, 1.1254750686853198e-46, 7.8591635665593126e-49, 4.5220720973223149e-51, 2.1173804777066541e-53, 7.9532902157128368e-56, 2.3572025385780174e-58, 5.4070585225542087e-61, 9.3828601952142795e-64, 1.1985921850382964e-66, 1.0903770909317098e-69, 6.7802095889475983e-73, 2.7361658102621640e-76, 6.6985500695669678e-80, 9.0848000543271587e-84, 6.0055451530824495e-88, 1.5968463027613036e-92, 1.2451690475064742e-97, 1.5584604318709814e-103, 6.7223469064836171e-111}, {9.6398630558977581e-112, 2.3391641752283700e-104, 1.9419047430148712e-98, 2.5780282869707508e-93, 1.0013546946979084e-88, 1.5618992863642802e-84, 1.1860256149765069e-80, 4.9845319901386102e-77, 1.2699036539452659e-73, 2.0984019099670130e-70, 2.3689362034001624e-67, 1.9037493843202249e-64, 1.1258502033609599e-61, 5.0354502440866812e-59, 1.7426389319046294e-56, 4.7576590995159999e-54, 1.0418263136743596e-51, 1.8562658771588515e-49, 2.7249577678833700e-47, 3.3321800978024594e-45, 3.4274481444478336e-43, 2.9912154191216358e-41, 2.2321555171303588e-39, 1.4342596614707723e-37, 7.9853025164866527e-36, 3.8743074669761106e-34, 1.6466139693318358e-32, 6.1594817750585881e-31, 2.0367481580156025e-29, 5.9772735819833118e-28, 1.5625565508848433e-26, 3.6509499167114885e-25, 7.6484446772058021e-24, 1.4407768646001281e-22, 2.4470614433838565e-21, 3.7566695291667047e-20, 5.2249355965739373e-19, 6.5981079437776417e-18, 7.5804607661939761e-17, 7.9383130347919212e-16, 7.5907028620400909e-15, 6.6385260183760165e-14, 5.3182112719426004e-13, 3.9083095195736355e-12, 2.6383151459347353e-11, 1.6380456665860958e-10, 9.3648087516475362e-10, 4.9354207551905105e-09, 2.4002106969319454e-08, 1.0781831043581527e-07, 4.4775845772911881e-07, 1.7205483203483572e-06, 6.1220977817639379e-06, 2.0186382119025494e-05, 6.1721031633452369e-05, 1.7510316724439029e-04, 4.6120030826672870e-04, 1.1283616065624156e-03, 2.5655409728187234e-03, 5.4233979404253157e-03, 1.0663442942343464e-02, 1.9507907091601058e-02, 3.3216020285214413e-02, 5.2653553807060320e-02, 7.7723764833089265e-02, 1.0685936247311774e-01, 1.3685933683570478e-01, 1.6330294257556086e-01, 1.8155584069555794e-01, 1.8808162842571305e-01, 1.8155584069555794e-01, 1.6330294257556086e-01, 1.3685933683570478e-01, 1.0685936247311774e-01, 7.7723764833089265e-02, 5.2653553807060320e-02, 3.3216020285214413e-02, 1.9507907091601058e-02, 1.0663442942343464e-02, 5.4233979404253157e-03, 2.5655409728187234e-03, 1.1283616065624156e-03, 4.6120030826672870e-04, 1.7510316724439029e-04, 6.1721031633452369e-05, 2.0186382119025494e-05, 6.1220977817639379e-06, 1.7205483203483572e-06, 4.4775845772911881e-07, 1.0781831043581527e-07, 2.4002106969319454e-08, 4.9354207551905105e-09, 9.3648087516475362e-10, 1.6380456665860958e-10, 2.6383151459347353e-11, 3.9083095195736355e-12, 5.3182112719426004e-13, 6.6385260183760165e-14, 7.5907028620400909e-15, 7.9383130347919212e-16, 7.5804607661939761e-17, 6.5981079437776417e-18, 5.2249355965739373e-19, 3.7566695291667047e-20, 2.4470614433838565e-21, 1.4407768646001281e-22, 7.6484446772058021e-24, 3.6509499167114885e-25, 1.5625565508848433e-26, 5.9772735819833118e-28, 2.0367481580156025e-29, 6.1594817750585881e-31, 1.6466139693318358e-32, 3.8743074669761106e-34, 7.9853025164866527e-36, 1.4342596614707723e-37, 2.2321555171303588e-39, 2.9912154191216358e-41, 3.4274481444478336e-43, 3.3321800978024594e-45, 2.7249577678833700e-47, 1.8562658771588515e-49, 1.0418263136743596e-51, 4.7576590995159999e-54, 1.7426389319046294e-56, 5.0354502440866812e-59, 1.1258502033609599e-61, 1.9037493843202249e-64, 2.3689362034001624e-67, 2.0984019099670130e-70, 1.2699036539452659e-73, 4.9845319901386102e-77, 1.1860256149765069e-80, 1.5618992863642802e-84, 1.0013546946979084e-88, 2.5780282869707508e-93, 1.9419047430148712e-98, 2.3391641752283700e-104, 9.6398630558977581e-112}, {1.3819748652176074e-112, 3.5091818441132373e-105, 3.0263733342631031e-99, 4.1584216000446123e-94, 1.6678802978259982e-89, 2.6820059816501053e-85, 2.0970348613054561e-81, 9.0664032095201726e-78, 2.3744232682771987e-74, 4.0308051146214329e-71, 4.6725947222676983e-68, 3.8542403780632908e-65, 2.3387627697862867e-62, 1.0729932979377662e-59, 3.8081687860913558e-57, 1.0660224990923822e-54, 2.3931046396310541e-52, 4.3706076964057967e-50, 6.5758217028615195e-48, 8.2408262629145279e-46, 8.6863577038588966e-44, 7.7681876124982396e-42, 5.9400458445057631e-40, 3.9109426504580767e-38, 2.2311802993712928e-36, 1.1092621876592673e-34, 4.8310493095269011e-33, 1.8519160989732117e-31, 6.2757371777744156e-30, 1.8875929093999227e-28, 5.0576726716251256e-27, 1.2113423787195963e-25, 2.6014811007021294e-24, 5.0242965481154138e-23, 8.7498945768853231e-22, 1.3775031653677140e-20, 1.9649805509896429e-19, 2.5453305256296733e-18, 3.0000691187992888e-17, 3.2236051617172698e-16, 3.1633284490034087e-15, 2.8395986506952882e-14, 2.3353492711597277e-13, 1.7622103628998908e-12, 1.2216962997815707e-11, 7.7914682997538544e-11, 4.5765854976073951e-10, 2.4786353105487376e-09, 1.2390357485809571e-08, 5.7223858055497259e-08, 2.4439179961675454e-07, 9.6600646013167157e-07, 3.5367142158469601e-06, 1.2002319438047467e-05, 3.7780839366269368e-05, 1.1038074912944360e-04, 2.9949084760834345e-04, 7.5504927141389195e-04, 1.7696288232331070e-03, 3.8574393750280067e-03, 7.8235307009575233e-03, 1.4769041560724656e-02, 2.5959097306055404e-02, 4.2495188992312062e-02, 6.4805460287971808e-02, 9.2086877576565612e-02, 1.2194809856528342e-01, 1.5052362288934179e-01, 1.7319382084353874e-01, 1.8577559474964558e-01, 1.8577559474964558e-01, 1.7319382084353874e-01, 1.5052362288934179e-01, 1.2194809856528342e-01, 9.2086877576565612e-02, 6.4805460287971808e-02, 4.2495188992312062e-02, 2.5959097306055404e-02, 1.4769041560724656e-02, 7.8235307009575233e-03, 3.8574393750280067e-03, 1.7696288232331070e-03, 7.5504927141389195e-04, 2.9949084760834345e-04, 1.1038074912944360e-04, 3.7780839366269368e-05, 1.2002319438047467e-05, 3.5367142158469601e-06, 9.6600646013167157e-07, 2.4439179961675454e-07, 5.7223858055497259e-08, 1.2390357485809571e-08, 2.4786353105487376e-09, 4.5765854976073951e-10, 7.7914682997538544e-11, 1.2216962997815707e-11, 1.7622103628998908e-12, 2.3353492711597277e-13, 2.8395986506952882e-14, 3.1633284490034087e-15, 3.2236051617172698e-16, 3.0000691187992888e-17, 2.5453305256296733e-18, 1.9649805509896429e-19, 1.3775031653677140e-20, 8.7498945768853231e-22, 5.0242965481154138e-23, 2.6014811007021294e-24, 1.2113423787195963e-25, 5.0576726716251256e-27, 1.8875929093999227e-28, 6.2757371777744156e-30, 1.8519160989732117e-31, 4.8310493095269011e-33, 1.1092621876592673e-34, 2.2311802993712928e-36, 3.9109426504580767e-38, 5.9400458445057631e-40, 7.7681876124982396e-42, 8.6863577038588966e-44, 8.2408262629145279e-46, 6.5758217028615195e-48, 4.3706076964057967e-50, 2.3931046396310541e-52, 1.0660224990923822e-54, 3.8081687860913558e-57, 1.0729932979377662e-59, 2.3387627697862867e-62, 3.8542403780632908e-65, 4.6725947222676983e-68, 4.0308051146214329e-71, 2.3744232682771987e-74, 9.0664032095201726e-78, 2.0970348613054561e-81, 2.6820059816501053e-85, 1.6678802978259982e-89, 4.1584216000446123e-94, 3.0263733342631031e-99, 3.5091818441132373e-105, 1.3819748652176074e-112}, {1.9806611743021416e-113, 5.2617952692292333e-106, 4.7131990325935266e-100, 6.7017830703194019e-95, 2.7751659416516980e-90, 4.5998341384092458e-86, 3.7027394072850406e-82, 1.6465801492558192e-78, 4.4321525706156201e-75, 7.7285235953959866e-72, 9.1980779235827154e-69, 7.7863635474467061e-66, 4.8472018976182706e-63, 2.2808008160100623e-60, 8.3001996570148669e-58, 2.3819600570060440e-55, 5.4809275321322830e-53, 1.0258876994968507e-50, 1.5817079781846762e-48, 2.0310845466149993e-46, 2.1935503204230003e-44, 2.0098426331457899e-42, 1.5745331638769155e-40, 1.0620797611432563e-38, 6.2076082159887624e-37, 3.1618692048946272e-35, 1.4108563317113768e-33, 5.5412911024876112e-32, 1.9240852596678829e-30, 5.9301271167711558e-29, 1.6282950449666844e-27, 3.9967858207858083e-26, 8.7976197776883766e-25, 1.7416595619626179e-23, 3.1094324529576228e-22, 5.0189377569399244e-21, 7.3412947992638873e-20, 9.7524056424221390e-19, 1.1789993455088293e-17, 1.2995830094215584e-16, 1.3084437330245737e-15, 1.2052816831862512e-14, 1.0173726615206055e-13, 7.8806482946078899e-13, 5.6095283428337204e-12, 3.6739040139866195e-11, 2.2165913480620041e-10, 1.2333492148378478e-09, 6.3355479710981103e-09, 3.0075005874343488e-08, 1.3205310627276386e-07, 5.3676540058539977e-07, 2.0214361392302868e-06, 7.0582654033955854e-06, 2.2866437400066508e-05, 6.8776486666748005e-05, 1.9216752502494505e-04, 4.9906383375612176e-04, 1.2052761990741546e-03, 2.7081400657517538e-03, 5.6635846018365278e-03, 1.1028376452466447e-02, 2.0002251583713944e-02, 3.3800561758698749e-02, 5.3230566834836512e-02, 7.8142792739003333e-02, 1.0695235327964076e-01, 1.3650006936059866e-01, 1.6246837812900003e-01, 1.8035805565273866e-01, 1.8674771616737459e-01, 1.8035805565273866e-01, 1.6246837812900003e-01, 1.3650006936059866e-01, 1.0695235327964076e-01, 7.8142792739003333e-02, 5.3230566834836512e-02, 3.3800561758698749e-02, 2.0002251583713944e-02, 1.1028376452466447e-02, 5.6635846018365278e-03, 2.7081400657517538e-03, 1.2052761990741546e-03, 4.9906383375612176e-04, 1.9216752502494505e-04, 6.8776486666748005e-05, 2.2866437400066508e-05, 7.0582654033955854e-06, 2.0214361392302868e-06, 5.3676540058539977e-07, 1.3205310627276386e-07, 3.0075005874343488e-08, 6.3355479710981103e-09, 1.2333492148378478e-09, 2.2165913480620041e-10, 3.6739040139866195e-11, 5.6095283428337204e-12, 7.8806482946078899e-13, 1.0173726615206055e-13, 1.2052816831862512e-14, 1.3084437330245737e-15, 1.2995830094215584e-16, 1.1789993455088293e-17, 9.7524056424221390e-19, 7.3412947992638873e-20, 5.0189377569399244e-21, 3.1094324529576228e-22, 1.7416595619626179e-23, 8.7976197776883766e-25, 3.9967858207858083e-26, 1.6282950449666844e-27, 5.9301271167711558e-29, 1.9240852596678829e-30, 5.5412911024876112e-32, 1.4108563317113768e-33, 3.1618692048946272e-35, 6.2076082159887624e-37, 1.0620797611432563e-38, 1.5745331638769155e-40, 2.0098426331457899e-42, 2.1935503204230003e-44, 2.0310845466149993e-46, 1.5817079781846762e-48, 1.0258876994968507e-50, 5.4809275321322830e-53, 2.3819600570060440e-55, 8.3001996570148669e-58, 2.2808008160100623e-60, 4.8472018976182706e-63, 7.7863635474467061e-66, 9.1980779235827154e-69, 7.7285235953959866e-72, 4.4321525706156201e-75, 1.6465801492558192e-78, 3.7027394072850406e-82, 4.5998341384092458e-86, 2.7751659416516980e-90, 6.7017830703194019e-95, 4.7131990325935266e-100, 5.2617952692292333e-106, 1.9806611743021416e-113}, {2.8379348362554196e-114, 7.8858321167381958e-107, 7.3351907294176643e-101, 1.0791401722330717e-95, 4.6128120689561502e-91, 7.8796483529297319e-87, 6.5291103196563761e-83, 2.9859071017101074e-79, 8.2594238150373050e-76, 1.4791530184295327e-72, 1.8070968918430098e-69, 1.5696742395566467e-66, 1.0023248619238131e-63, 4.8364134393087594e-61, 1.8044278404363096e-58, 5.3077896463877236e-56, 1.2516691340073944e-53, 2.4006692740362835e-51, 3.7923450617699092e-49, 4.9890808610628276e-47, 5.5197834921993867e-45, 5.1808064286331934e-43, 4.1575196368970433e-41, 2.8726311560209485e-39, 1.7198340431536187e-37, 8.9732693547519472e-36, 4.1015179356507749e-34, 1.6502257188992863e-32, 5.8701285325766118e-31, 1.8535450041434515e-29, 5.2145562564115323e-28, 1.3115164390064590e-26, 2.9583134344508206e-25, 6.0020532911752611e-24, 1.0982988908956421e-22, 1.8172013379429154e-21, 2.7250115798124682e-20, 3.7116593876307894e-19, 4.6014038935013638e-18, 5.2019302408782819e-17, 5.3723712748625257e-16, 5.0771526984812688e-15, 4.3975029340499356e-14, 3.4959048726655372e-13, 2.5543256450392521e-12, 1.7175688761100677e-11, 1.0641335972971535e-10, 6.0815188314211019e-10, 3.2093758879421831e-09, 1.5654930566151192e-08, 7.0648903615829459e-08, 2.9522889815634413e-07, 1.1433046682221214e-06, 4.1062137791532273e-06, 1.3686795544658825e-05, 4.2366755055396916e-05, 1.2186350361528871e-04, 3.2590355495495157e-04, 8.1076372459361551e-04, 1.8771268090367514e-03, 4.0464432735401257e-03, 8.1246183048277309e-03, 1.5199679576417248e-02, 2.6503531097710236e-02, 4.3085461690763743e-02, 6.5316009514185674e-02, 9.2354740298272661e-02, 1.2182123832712786e-01, 1.4992351472225099e-01, 1.7216437167539980e-01, 1.8448997083421120e-01, 1.8448997083421120e-01, 1.7216437167539980e-01, 1.4992351472225099e-01, 1.2182123832712786e-01, 9.2354740298272661e-02, 6.5316009514185674e-02, 4.3085461690763743e-02, 2.6503531097710236e-02, 1.5199679576417248e-02, 8.1246183048277309e-03, 4.0464432735401257e-03, 1.8771268090367514e-03, 8.1076372459361551e-04, 3.2590355495495157e-04, 1.2186350361528871e-04, 4.2366755055396916e-05, 1.3686795544658825e-05, 4.1062137791532273e-06, 1.1433046682221214e-06, 2.9522889815634413e-07, 7.0648903615829459e-08, 1.5654930566151192e-08, 3.2093758879421831e-09, 6.0815188314211019e-10, 1.0641335972971535e-10, 1.7175688761100677e-11, 2.5543256450392521e-12, 3.4959048726655372e-13, 4.3975029340499356e-14, 5.0771526984812688e-15, 5.3723712748625257e-16, 5.2019302408782819e-17, 4.6014038935013638e-18, 3.7116593876307894e-19, 2.7250115798124682e-20, 1.8172013379429154e-21, 1.0982988908956421e-22, 6.0020532911752611e-24, 2.9583134344508206e-25, 1.3115164390064590e-26, 5.2145562564115323e-28, 1.8535450041434515e-29, 5.8701285325766118e-31, 1.6502257188992863e-32, 4.1015179356507749e-34, 8.9732693547519472e-36, 1.7198340431536187e-37, 2.8726311560209485e-39, 4.1575196368970433e-41, 5.1808064286331934e-43, 5.5197834921993867e-45, 4.9890808610628276e-47, 3.7923450617699092e-49, 2.4006692740362835e-51, 1.2516691340073944e-53, 5.3077896463877236e-56, 1.8044278404363096e-58, 4.8364134393087594e-61, 1.0023248619238131e-63, 1.5696742395566467e-66, 1.8070968918430098e-69, 1.4791530184295327e-72, 8.2594238150373050e-76, 2.9859071017101074e-79, 6.5291103196563761e-83, 7.8796483529297319e-87, 4.6128120689561502e-91, 1.0791401722330717e-95, 7.3351907294176643e-101, 7.8858321167381958e-107, 2.8379348362554196e-114}, {4.0651653045385065e-115, 1.1812699945481087e-107, 1.1408091037467098e-101, 1.7361831916251206e-96, 7.6595061701919539e-92, 1.3482180200386414e-87, 1.1497555722475321e-83, 5.4065905193630812e-80, 1.5366409186618650e-76, 2.8258657002435720e-73, 3.5434157687072630e-70, 3.1577316852342737e-67, 2.0680029879339054e-64, 1.0231020536481417e-61, 3.9127659587819162e-59, 1.1795593319147925e-56, 2.8502626581292134e-54, 5.6008912228881934e-52, 9.0638661704615042e-50, 1.2214291755276681e-47, 1.3841464531877442e-45, 1.3306007915064349e-43, 1.0936052280580312e-41, 7.7388088770231391e-40, 4.7451186753733802e-38, 2.5356047070173512e-36, 1.1870121009809329e-34, 4.8915667031805749e-33, 1.7822371990214424e-31, 5.7644513660319519e-30, 1.6612582615477246e-28, 4.2804618347791540e-27, 9.8922322140449142e-26, 2.0564738212957134e-24, 3.8562115828650105e-23, 6.5389458924467930e-22, 1.0050517825377878e-20, 1.4033245536407663e-19, 1.7836445099325982e-18, 2.0676254282785005e-17, 2.1899168813282935e-16, 2.1227770911527276e-15, 1.8861860904057362e-14, 1.5385347856793465e-13, 1.1536439246054796e-12, 7.9623160515403962e-12, 5.0644993569234348e-11, 2.9720520664121096e-10, 1.6108731738857700e-09, 8.0720587699486656e-09, 3.7430932220185756e-08, 1.6076054796089227e-07, 6.4000756781336375e-07, 2.3636229043243477e-06, 8.1033917859954005e-06, 2.5807006976135383e-05, 7.6393528572820399e-05, 2.1031479179566012e-04, 5.3877140763670364e-04, 1.2849006257472789e-03, 2.8540126420656033e-03, 5.9065989999834033e-03, 1.1393877212953164e-02, 2.0492691616955331e-02, 3.4375183073736520e-02, 5.3792186966533914e-02, 7.8544533849893697e-02, 1.0703228204562122e-01, 1.3613832142377319e-01, 1.6164525387078738e-01, 1.7918358709477061e-01, 1.8544178808228795e-01, 1.7918358709477061e-01, 1.6164525387078738e-01, 1.3613832142377319e-01, 1.0703228204562122e-01, 7.8544533849893697e-02, 5.3792186966533914e-02, 3.4375183073736520e-02, 2.0492691616955331e-02, 1.1393877212953164e-02, 5.9065989999834033e-03, 2.8540126420656033e-03, 1.2849006257472789e-03, 5.3877140763670364e-04, 2.1031479179566012e-04, 7.6393528572820399e-05, 2.5807006976135383e-05, 8.1033917859954005e-06, 2.3636229043243477e-06, 6.4000756781336375e-07, 1.6076054796089227e-07, 3.7430932220185756e-08, 8.0720587699486656e-09, 1.6108731738857700e-09, 2.9720520664121096e-10, 5.0644993569234348e-11, 7.9623160515403962e-12, 1.1536439246054796e-12, 1.5385347856793465e-13, 1.8861860904057362e-14, 2.1227770911527276e-15, 2.1899168813282935e-16, 2.0676254282785005e-17, 1.7836445099325982e-18, 1.4033245536407663e-19, 1.0050517825377878e-20, 6.5389458924467930e-22, 3.8562115828650105e-23, 2.0564738212957134e-24, 9.8922322140449142e-26, 4.2804618347791540e-27, 1.6612582615477246e-28, 5.7644513660319519e-30, 1.7822371990214424e-31, 4.8915667031805749e-33, 1.1870121009809329e-34, 2.5356047070173512e-36, 4.7451186753733802e-38, 7.7388088770231391e-40, 1.0936052280580312e-41, 1.3306007915064349e-43, 1.3841464531877442e-45, 1.2214291755276681e-47, 9.0638661704615042e-50, 5.6008912228881934e-52, 2.8502626581292134e-54, 1.1795593319147925e-56, 3.9127659587819162e-59, 1.0231020536481417e-61, 2.0680029879339054e-64, 3.1577316852342737e-67, 3.5434157687072630e-70, 2.8258657002435720e-73, 1.5366409186618650e-76, 5.4065905193630812e-80, 1.1497555722475321e-83, 1.3482180200386414e-87, 7.6595061701919539e-92, 1.7361831916251206e-96, 1.1408091037467098e-101, 1.1812699945481087e-107, 4.0651653045385065e-115}, {5.8215540266145185e-116, 1.7686479321265132e-108, 1.7730623068856681e-102, 2.7909232189455364e-97, 1.2705722231489315e-92, 2.3041370774073117e-88, 2.0220172247445533e-84, 9.7753535494291230e-81, 2.8542469937135876e-77, 5.3891664187060082e-74, 6.9347342664174447e-71, 6.3393303649456501e-68, 4.2572743226051364e-65, 2.1591730776951801e-62, 8.4632278622572117e-60, 2.6143765867593842e-57, 6.4722677680216748e-55, 1.3028416632725528e-52, 2.1595419825453231e-50, 2.9805109745607960e-48, 3.4589808905752308e-46, 3.4051398010375247e-44, 2.8658496493850430e-42, 2.0766525261834300e-40, 1.3038602059242759e-38, 7.1344872719593792e-37, 3.4201248592076866e-35, 1.4432903376167608e-33, 5.3852783517497647e-32, 1.7838570362707828e-30, 5.2653274547677795e-29, 1.3896193908215000e-27, 3.2896623243386845e-26, 7.0060070837042623e-25, 1.3459870964148325e-23, 2.3386559482775554e-22, 3.6836215601895347e-21, 5.2713950568645777e-20, 6.8677255495973648e-19, 8.1615638298029365e-18, 8.8631701623207850e-17, 8.8103300045560730e-16, 8.0291277303592449e-15, 6.7183131113433536e-14, 5.1685673461842002e-13, 3.6606905840155156e-12, 2.3898379902347417e-11, 1.4397371489675669e-10, 8.0125910717950545e-10, 4.1235783120777111e-09, 1.9642460747885040e-08, 8.6680352990322611e-08, 3.5465537239549829e-07, 1.3464428002356888e-06, 4.7465352780258519e-06, 1.5547603684619328e-05, 4.7349798947666790e-05, 1.3415011473384580e-04, 3.5376394702118597e-04, 8.6875807961727194e-04, 1.9876616088445901e-03, 4.2386040557315851e-03, 8.4275632150598145e-03, 1.5628807300276451e-02, 2.7041109022394049e-02, 4.3662930188759774e-02, 6.5809838711917215e-02, 9.2606922401635969e-02, 1.2168620186278144e-01, 1.4932782014181728e-01, 1.7115266931753381e-01, 1.8323066902877375e-01, 1.8323066902877375e-01, 1.7115266931753381e-01, 1.4932782014181728e-01, 1.2168620186278144e-01, 9.2606922401635969e-02, 6.5809838711917215e-02, 4.3662930188759774e-02, 2.7041109022394049e-02, 1.5628807300276451e-02, 8.4275632150598145e-03, 4.2386040557315851e-03, 1.9876616088445901e-03, 8.6875807961727194e-04, 3.5376394702118597e-04, 1.3415011473384580e-04, 4.7349798947666790e-05, 1.5547603684619328e-05, 4.7465352780258519e-06, 1.3464428002356888e-06, 3.5465537239549829e-07, 8.6680352990322611e-08, 1.9642460747885040e-08, 4.1235783120777111e-09, 8.0125910717950545e-10, 1.4397371489675669e-10, 2.3898379902347417e-11, 3.6606905840155156e-12, 5.1685673461842002e-13, 6.7183131113433536e-14, 8.0291277303592449e-15, 8.8103300045560730e-16, 8.8631701623207850e-17, 8.1615638298029365e-18, 6.8677255495973648e-19, 5.2713950568645777e-20, 3.6836215601895347e-21, 2.3386559482775554e-22, 1.3459870964148325e-23, 7.0060070837042623e-25, 3.2896623243386845e-26, 1.3896193908215000e-27, 5.2653274547677795e-29, 1.7838570362707828e-30, 5.3852783517497647e-32, 1.4432903376167608e-33, 3.4201248592076866e-35, 7.1344872719593792e-37, 1.3038602059242759e-38, 2.0766525261834300e-40, 2.8658496493850430e-42, 3.4051398010375247e-44, 3.4589808905752308e-46, 2.9805109745607960e-48, 2.1595419825453231e-50, 1.3028416632725528e-52, 6.4722677680216748e-55, 2.6143765867593842e-57, 8.4632278622572117e-60, 2.1591730776951801e-62, 4.2572743226051364e-65, 6.3393303649456501e-68, 6.9347342664174447e-71, 5.3891664187060082e-74, 2.8542469937135876e-77, 9.7753535494291230e-81, 2.0220172247445533e-84, 2.3041370774073117e-88, 1.2705722231489315e-92, 2.7909232189455364e-97, 1.7730623068856681e-102, 1.7686479321265132e-108, 5.8215540266145185e-116}, {8.3346219931731252e-117, 2.6468336179684675e-109, 2.7538984203799183e-103, 4.4826957080916534e-98, 2.1055559670183425e-93, 3.9333042153463284e-89, 3.5513952096001502e-85, 1.7648636462384819e-81, 5.2931716200065506e-78, 1.0259659682881671e-74, 1.3546124768341285e-71, 1.2700634063455813e-68, 8.7450484044987438e-66, 4.5461329246587614e-63, 1.8260394178147789e-60, 5.7792816013390868e-58, 1.4656166079834788e-55, 3.0217106412347761e-53, 5.1294451668154943e-51, 7.2494810877533628e-49, 8.6147071643386152e-47, 8.6832052790729524e-45, 7.4822992810294955e-43, 5.5510153038363309e-41, 3.5683132140145833e-39, 1.9990336800405551e-37, 9.8114235481332920e-36, 4.2392471038699379e-34, 1.6195898700068922e-32, 5.4933861932302487e-31, 1.6604056318842839e-29, 4.4876913417614677e-28, 1.0880533660044361e-26, 2.3734409390889848e-25, 4.6708788240159748e-24, 8.3141586271431848e-23, 1.3417423881673005e-21, 1.9674928839115667e-20, 2.6269310713002712e-19, 3.1997441855901569e-18, 3.5620366003569210e-17, 3.6302240823037884e-16, 3.3924183801506980e-15, 2.9112006503092275e-14, 2.2973505987627707e-13, 1.6693328537504025e-12, 1.1182840247910251e-11, 6.9144057864820654e-11, 3.9502105053420148e-10, 2.0873156939372195e-09, 1.0211061576622443e-08, 4.6286545842406255e-08, 1.9458139349161944e-07, 7.5918662435991949e-07, 2.7511365949804849e-06, 9.2658749369498393e-06, 2.9023198119388909e-05, 8.4594658849625380e-05, 2.2956989796967087e-04, 5.8033480492528523e-04, 1.3672056490331354e-03, 3.0030570133818706e-03, 6.1522556633449429e-03, 1.1759716605478240e-02, 2.0979064379787655e-02, 3.4939934715514299e-02, 5.4338778627529040e-02, 7.8929618144152600e-02, 1.0709980745724954e-01, 1.3577444219071524e-01, 1.6083336191837752e-01, 1.7803169108709616e-01, 1.8416287919896177e-01, 1.7803169108709616e-01, 1.6083336191837752e-01, 1.3577444219071524e-01, 1.0709980745724954e-01, 7.8929618144152600e-02, 5.4338778627529040e-02, 3.4939934715514299e-02, 2.0979064379787655e-02, 1.1759716605478240e-02, 6.1522556633449429e-03, 3.0030570133818706e-03, 1.3672056490331354e-03, 5.8033480492528523e-04, 2.2956989796967087e-04, 8.4594658849625380e-05, 2.9023198119388909e-05, 9.2658749369498393e-06, 2.7511365949804849e-06, 7.5918662435991949e-07, 1.9458139349161944e-07, 4.6286545842406255e-08, 1.0211061576622443e-08, 2.0873156939372195e-09, 3.9502105053420148e-10, 6.9144057864820654e-11, 1.1182840247910251e-11, 1.6693328537504025e-12, 2.2973505987627707e-13, 2.9112006503092275e-14, 3.3924183801506980e-15, 3.6302240823037884e-16, 3.5620366003569210e-17, 3.1997441855901569e-18, 2.6269310713002712e-19, 1.9674928839115667e-20, 1.3417423881673005e-21, 8.3141586271431848e-23, 4.6708788240159748e-24, 2.3734409390889848e-25, 1.0880533660044361e-26, 4.4876913417614677e-28, 1.6604056318842839e-29, 5.4933861932302487e-31, 1.6195898700068922e-32, 4.2392471038699379e-34, 9.8114235481332920e-36, 1.9990336800405551e-37, 3.5683132140145833e-39, 5.5510153038363309e-41, 7.4822992810294955e-43, 8.6832052790729524e-45, 8.6147071643386152e-47, 7.2494810877533628e-49, 5.1294451668154943e-51, 3.0217106412347761e-53, 1.4656166079834788e-55, 5.7792816013390868e-58, 1.8260394178147789e-60, 4.5461329246587614e-63, 8.7450484044987438e-66, 1.2700634063455813e-68, 1.3546124768341285e-71, 1.0259659682881671e-74, 5.2931716200065506e-78, 1.7648636462384819e-81, 3.5513952096001502e-85, 3.9333042153463284e-89, 2.1055559670183425e-93, 4.4826957080916534e-98, 2.7538984203799183e-103, 2.6468336179684675e-109, 8.3346219931731252e-117}, {1.1929450990497388e-117, 3.9591990974598804e-110, 4.2745275541790886e-104, 7.1940582732963705e-99, 3.4858463341267156e-94, 6.7067764488470954e-90, 6.2295239916515678e-86, 3.1817588164569700e-82, 9.8006355361055656e-79, 1.9498222863573950e-75, 2.6411200905371024e-72, 2.5394077671157272e-69, 1.7924826309087973e-66, 9.5498361457830398e-64, 3.9302490205746199e-61, 1.2742413782141750e-58, 3.3097280501169341e-56, 6.9880745770528625e-54, 1.2146673922184433e-51, 1.7576627452371236e-49, 2.1383500879761454e-47, 2.2064997583491492e-45, 1.9463790072121561e-43, 1.4781646220486795e-41, 9.7267315160133413e-40, 5.5780033470752983e-38, 2.8025392714968451e-36, 1.2395973767055291e-34, 4.8482501635459064e-33, 1.6835590125100971e-31, 5.2099674531110126e-30, 1.4417990594032542e-28, 3.5795224098780112e-27, 7.9961758900246410e-26, 1.6116510554151974e-24, 2.9383411496603336e-23, 4.8574792709615864e-22, 7.2973076814277955e-21, 9.9829502923346154e-20, 1.2460703643781112e-18, 1.4216815546927034e-17, 1.4851721687462022e-16, 1.4228468795430129e-15, 1.2519744100239038e-14, 1.0132054243548976e-13, 7.5515422033135666e-13, 5.1897461393175068e-12, 3.2925485308161026e-11, 1.9304840630938534e-10, 1.0471078941135214e-09, 5.2592465173501358e-09, 2.4482298403820274e-08, 1.0571641536621842e-07, 4.2377549476354214e-07, 1.5781624324532756e-06, 5.4637147044287493e-06, 1.7596343655070067e-05, 5.2748866067347142e-05, 1.4726499921039843e-04, 3.8309201801330436e-04, 9.2902602860733265e-04, 2.1011697743361312e-03, 4.4337774736073364e-03, 8.7321528128579372e-03, 1.6056218663448245e-02, 2.7571764216085648e-02, 4.4227798774476149e-02, 6.6287455917162549e-02, 9.2844091734104794e-02, 1.2154351785304160e-01, 1.4873661992593393e-01, 1.7015822429768401e-01, 1.8199680336473223e-01, 1.8199680336473223e-01, 1.7015822429768401e-01, 1.4873661992593393e-01, 1.2154351785304160e-01, 9.2844091734104794e-02, 6.6287455917162549e-02, 4.4227798774476149e-02, 2.7571764216085648e-02, 1.6056218663448245e-02, 8.7321528128579372e-03, 4.4337774736073364e-03, 2.1011697743361312e-03, 9.2902602860733265e-04, 3.8309201801330436e-04, 1.4726499921039843e-04, 5.2748866067347142e-05, 1.7596343655070067e-05, 5.4637147044287493e-06, 1.5781624324532756e-06, 4.2377549476354214e-07, 1.0571641536621842e-07, 2.4482298403820274e-08, 5.2592465173501358e-09, 1.0471078941135214e-09, 1.9304840630938534e-10, 3.2925485308161026e-11, 5.1897461393175068e-12, 7.5515422033135666e-13, 1.0132054243548976e-13, 1.2519744100239038e-14, 1.4228468795430129e-15, 1.4851721687462022e-16, 1.4216815546927034e-17, 1.2460703643781112e-18, 9.9829502923346154e-20, 7.2973076814277955e-21, 4.8574792709615864e-22, 2.9383411496603336e-23, 1.6116510554151974e-24, 7.9961758900246410e-26, 3.5795224098780112e-27, 1.4417990594032542e-28, 5.2099674531110126e-30, 1.6835590125100971e-31, 4.8482501635459064e-33, 1.2395973767055291e-34, 2.8025392714968451e-36, 5.5780033470752983e-38, 9.7267315160133413e-40, 1.4781646220486795e-41, 1.9463790072121561e-43, 2.2064997583491492e-45, 2.1383500879761454e-47, 1.7576627452371236e-49, 1.2146673922184433e-51, 6.9880745770528625e-54, 3.3097280501169341e-56, 1.2742413782141750e-58, 3.9302490205746199e-61, 9.5498361457830398e-64, 1.7924826309087973e-66, 2.5394077671157272e-69, 2.6411200905371024e-72, 1.9498222863573950e-75, 9.8006355361055656e-79, 3.1817588164569700e-82, 6.2295239916515678e-86, 6.7067764488470954e-90, 3.4858463341267156e-94, 7.1940582732963705e-99, 4.2745275541790886e-104, 3.9591990974598804e-110, 1.1929450990497388e-117}, {1.7070406181366590e-118, 5.9195113844414591e-111, 6.6305252022274385e-105, 1.1536024679706741e-99, 5.7653910975637400e-95, 1.1423077010030593e-90, 1.0913377348991997e-86, 5.7280704066660911e-83, 1.8118187632234171e-79, 3.6992788142779886e-76, 5.1399529790115008e-73, 5.0672863794680850e-70, 3.6662464654865143e-67, 2.0015272638354942e-64, 8.4387742209978957e-62, 2.8023099391369100e-59, 7.4539706347406648e-57, 1.6114689883841890e-54, 2.8677408135139503e-52, 4.2481015098521193e-50, 5.2903245181279725e-48, 5.5876178971908134e-46, 5.0448907217391667e-44, 3.9213661446271294e-42, 2.6409880203075402e-40, 1.5501131114814050e-38, 7.9712569158416828e-37, 3.6087469701637568e-35, 1.4446952835847923e-33, 5.1351616577255980e-32, 1.6267414726790182e-30, 4.6086441078964235e-29, 1.1714111882873408e-27, 2.6792736258069186e-26, 5.5296079664300731e-25, 1.0324183959837516e-23, 1.7479927721363103e-22, 2.6897676451867309e-21, 3.7695192606286801e-20, 4.8205800888162673e-19, 5.6356840948811206e-18, 6.0335058787737898e-17, 5.9246665636288388e-16, 5.3441830122937569e-15, 4.4343905593075405e-14, 3.3891924837505246e-13, 2.3889528428660744e-12, 1.5547996800001229e-11, 9.3534621545646173e-11, 5.2065241132424465e-10, 2.6842310976125569e-09, 1.2828665113850952e-08, 5.6885421998531753e-08, 2.3421973604647242e-07, 8.9613156437377830e-07, 3.1882138059205163e-06, 1.0554357586582146e-05, 3.2530204545596872e-05, 9.3401898795249160e-05, 2.4995620584101932e-04, 6.2376294512410423e-04, 1.4521587444586976e-03, 3.1551701974875863e-03, 6.4003731513496125e-03, 1.2125677167472506e-02, 2.1461222380505476e-02, 3.5494877838398289e-02, 5.4870701544829148e-02, 7.9298651231443446e-02, 1.0715555306319222e-01, 1.3540875492462576e-01, 1.6003249638444184e-01, 1.7690165636825916e-01, 1.8291007049692826e-01, 1.7690165636825916e-01, 1.6003249638444184e-01, 1.3540875492462576e-01, 1.0715555306319222e-01, 7.9298651231443446e-02, 5.4870701544829148e-02, 3.5494877838398289e-02, 2.1461222380505476e-02, 1.2125677167472506e-02, 6.4003731513496125e-03, 3.1551701974875863e-03, 1.4521587444586976e-03, 6.2376294512410423e-04, 2.4995620584101932e-04, 9.3401898795249160e-05, 3.2530204545596872e-05, 1.0554357586582146e-05, 3.1882138059205163e-06, 8.9613156437377830e-07, 2.3421973604647242e-07, 5.6885421998531753e-08, 1.2828665113850952e-08, 2.6842310976125569e-09, 5.2065241132424465e-10, 9.3534621545646173e-11, 1.5547996800001229e-11, 2.3889528428660744e-12, 3.3891924837505246e-13, 4.4343905593075405e-14, 5.3441830122937569e-15, 5.9246665636288388e-16, 6.0335058787737898e-17, 5.6356840948811206e-18, 4.8205800888162673e-19, 3.7695192606286801e-20, 2.6897676451867309e-21, 1.7479927721363103e-22, 1.0324183959837516e-23, 5.5296079664300731e-25, 2.6792736258069186e-26, 1.1714111882873408e-27, 4.6086441078964235e-29, 1.6267414726790182e-30, 5.1351616577255980e-32, 1.4446952835847923e-33, 3.6087469701637568e-35, 7.9712569158416828e-37, 1.5501131114814050e-38, 2.6409880203075402e-40, 3.9213661446271294e-42, 5.0448907217391667e-44, 5.5876178971908134e-46, 5.2903245181279725e-48, 4.2481015098521193e-50, 2.8677408135139503e-52, 1.6114689883841890e-54, 7.4539706347406648e-57, 2.8023099391369100e-59, 8.4387742209978957e-62, 2.0015272638354942e-64, 3.6662464654865143e-67, 5.0672863794680850e-70, 5.1399529790115008e-73, 3.6992788142779886e-76, 1.8118187632234171e-79, 5.7280704066660911e-83, 1.0913377348991997e-86, 1.1423077010030593e-90, 5.7653910975637400e-95, 1.1536024679706741e-99, 6.6305252022274385e-105, 5.9195113844414591e-111, 1.7070406181366590e-118}, {2.4420658728359029e-119, 8.8463582669186499e-112, 1.0278520435124409e-105, 1.8483749220636043e-100, 9.5264999562099965e-96, 1.9434401044261462e-91, 1.9094951070499896e-87, 1.0297738588062730e-83, 3.3443041190506409e-80, 7.0066129472632568e-77, 9.9847674734222346e-74, 1.0091718959432019e-70, 7.4829681064377069e-68, 4.1855384000761587e-65, 1.8075959008515128e-62, 6.1472579038779528e-60, 1.6742548573659892e-57, 3.7056307854458431e-55, 6.7504839696392484e-53, 1.0235353311199910e-50, 1.3045775870281223e-48, 1.4101600092151863e-46, 1.3029538434289154e-44, 1.0364256329737640e-42, 7.1430632340356861e-41, 4.2904029597408759e-39, 2.2577848908542067e-37, 1.0460259894518416e-35, 4.2855476518701719e-34, 1.5590004744721381e-32, 5.0546933927274757e-31, 1.4657489608244835e-29, 3.8136046756805110e-28, 8.9292832689033937e-27, 1.8867047659679220e-25, 3.6067468226756066e-24, 6.2530721763179845e-23, 9.8539255836953708e-22, 1.4143965820612745e-20, 1.8527994733871280e-19, 2.2190951508494865e-18, 2.4342129329346826e-17, 2.4494846944487187e-16, 2.2645381737872469e-15, 1.9261422339406544e-14, 1.5093097961491213e-13, 1.0909182729913857e-12, 7.2818111329385306e-12, 4.4936440478669596e-11, 2.5663720011644112e-10, 1.3577644240845783e-09, 6.6605391288638309e-09, 3.0321186483039541e-08, 1.2819858780710668e-07, 5.0378676249733306e-07, 1.8413731465659074e-06, 6.2640223021607951e-06, 1.9844802959774770e-05, 5.8582692413005888e-05, 1.6123158507144338e-04, 4.1390553680515079e-04, 9.9155807247580142e-04, 2.2175853317597280e-03, 4.6318204121044990e-03, 9.0381820758826531e-03, 1.6481721286763326e-02, 2.8095443629279886e-02, 4.4780275406602559e-02, 6.6749354510874270e-02, 9.3066885205695463e-02, 1.2139368280029710e-01, 1.4814998194065979e-01, 1.6918056507168472e-01, 1.8078752906102052e-01, 1.8078752906102052e-01, 1.6918056507168472e-01, 1.4814998194065979e-01, 1.2139368280029710e-01, 9.3066885205695463e-02, 6.6749354510874270e-02, 4.4780275406602559e-02, 2.8095443629279886e-02, 1.6481721286763326e-02, 9.0381820758826531e-03, 4.6318204121044990e-03, 2.2175853317597280e-03, 9.9155807247580142e-04, 4.1390553680515079e-04, 1.6123158507144338e-04, 5.8582692413005888e-05, 1.9844802959774770e-05, 6.2640223021607951e-06, 1.8413731465659074e-06, 5.0378676249733306e-07, 1.2819858780710668e-07, 3.0321186483039541e-08, 6.6605391288638309e-09, 1.3577644240845783e-09, 2.5663720011644112e-10, 4.4936440478669596e-11, 7.2818111329385306e-12, 1.0909182729913857e-12, 1.5093097961491213e-13, 1.9261422339406544e-14, 2.2645381737872469e-15, 2.4494846944487187e-16, 2.4342129329346826e-17, 2.2190951508494865e-18, 1.8527994733871280e-19, 1.4143965820612745e-20, 9.8539255836953708e-22, 6.2530721763179845e-23, 3.6067468226756066e-24, 1.8867047659679220e-25, 8.9292832689033937e-27, 3.8136046756805110e-28, 1.4657489608244835e-29, 5.0546933927274757e-31, 1.5590004744721381e-32, 4.2855476518701719e-34, 1.0460259894518416e-35, 2.2577848908542067e-37, 4.2904029597408759e-39, 7.1430632340356861e-41, 1.0364256329737640e-42, 1.3029538434289154e-44, 1.4101600092151863e-46, 1.3045775870281223e-48, 1.0235353311199910e-50, 6.7504839696392484e-53, 3.7056307854458431e-55, 1.6742548573659892e-57, 6.1472579038779528e-60, 1.8075959008515128e-62, 4.1855384000761587e-65, 7.4829681064377069e-68, 1.0091718959432019e-70, 9.9847674734222346e-74, 7.0066129472632568e-77, 3.3443041190506409e-80, 1.0297738588062730e-83, 1.9094951070499896e-87, 1.9434401044261462e-91, 9.5264999562099965e-96, 1.8483749220636043e-100, 1.0278520435124409e-105, 8.8463582669186499e-112, 2.4420658728359029e-119}, {3.4927077138614495e-120, 1.3214344265685972e-112, 1.5923529644019419e-106, 2.9592365392916602e-101, 1.5726312834383212e-96, 3.3028107528503361e-92, 3.3368715475506461e-88, 1.8487368270391726e-84, 6.1636129673212566e-81, 1.3248817176167857e-77, 1.9361289427704634e-74, 2.0059128285660820e-71, 1.5241335107478225e-68, 8.7332836494574003e-66, 3.8627717414010648e-63, 1.3451211690839924e-60, 3.7506692343030420e-58, 8.4975513070583486e-56, 1.5843787624675853e-53, 2.4585380900294205e-51, 3.2067130430374953e-49, 3.5468958347722111e-47, 3.3533561409072355e-45, 2.7292702435888796e-43, 1.9246140375840066e-41, 1.1827867549833032e-39, 6.3685955808210726e-38, 3.0190103270136603e-36, 1.2656167558393507e-34, 4.7112145637232019e-33, 1.5631232313432506e-31, 4.6386822641081590e-30, 1.2351960569462707e-28, 2.9601529366809405e-27, 6.4022761029959671e-26, 1.2529044419038621e-24, 2.2238719447561208e-23, 3.5882695810709981e-22, 5.2741804743987912e-21, 7.0757399180811555e-20, 8.6802800075429983e-19, 9.7541289549630027e-18, 1.0056284258182538e-16, 9.5266259491509481e-16, 8.3044572801891268e-15, 6.6701332750751410e-14, 4.9425874408492004e-13, 3.3828553008734636e-12, 2.1409348303068694e-11, 1.2542010220460425e-10, 6.8076912279459116e-10, 3.4268964379715692e-09, 1.6011995715635929e-08, 6.9500026302554605e-08, 2.8044586426011501e-07, 1.0528006766858483e-06, 3.6792955563634022e-06, 1.1977707839841136e-05, 3.6343264722217326e-05, 1.0283673489115176e-04, 2.7149548605395329e-04, 6.6906197625873226e-04, 1.5397243486054463e-03, 3.3102482665201089e-03, 6.6507742518744171e-03, 1.2491552298533356e-02, 2.1939032537498546e-02, 3.6040083142086628e-02, 5.5388310278285176e-02, 7.9652215262150924e-02, 1.0720010935792797e-01, 1.3504155894527325e-01, 1.5924245367972575e-01, 1.7579280253635429e-01, 1.8168248613117691e-01, 1.7579280253635429e-01, 1.5924245367972575e-01, 1.3504155894527325e-01, 1.0720010935792797e-01, 7.9652215262150924e-02, 5.5388310278285176e-02, 3.6040083142086628e-02, 2.1939032537498546e-02, 1.2491552298533356e-02, 6.6507742518744171e-03, 3.3102482665201089e-03, 1.5397243486054463e-03, 6.6906197625873226e-04, 2.7149548605395329e-04, 1.0283673489115176e-04, 3.6343264722217326e-05, 1.1977707839841136e-05, 3.6792955563634022e-06, 1.0528006766858483e-06, 2.8044586426011501e-07, 6.9500026302554605e-08, 1.6011995715635929e-08, 3.4268964379715692e-09, 6.8076912279459116e-10, 1.2542010220460425e-10, 2.1409348303068694e-11, 3.3828553008734636e-12, 4.9425874408492004e-13, 6.6701332750751410e-14, 8.3044572801891268e-15, 9.5266259491509481e-16, 1.0056284258182538e-16, 9.7541289549630027e-18, 8.6802800075429983e-19, 7.0757399180811555e-20, 5.2741804743987912e-21, 3.5882695810709981e-22, 2.2238719447561208e-23, 1.2529044419038621e-24, 6.4022761029959671e-26, 2.9601529366809405e-27, 1.2351960569462707e-28, 4.6386822641081590e-30, 1.5631232313432506e-31, 4.7112145637232019e-33, 1.2656167558393507e-34, 3.0190103270136603e-36, 6.3685955808210726e-38, 1.1827867549833032e-39, 1.9246140375840066e-41, 2.7292702435888796e-43, 3.3533561409072355e-45, 3.5468958347722111e-47, 3.2067130430374953e-49, 2.4585380900294205e-51, 1.5843787624675853e-53, 8.4975513070583486e-56, 3.7506692343030420e-58, 1.3451211690839924e-60, 3.8627717414010648e-63, 8.7332836494574003e-66, 1.5241335107478225e-68, 2.0059128285660820e-71, 1.9361289427704634e-74, 1.3248817176167857e-77, 6.1636129673212566e-81, 1.8487368270391726e-84, 3.3368715475506461e-88, 3.3028107528503361e-92, 1.5726312834383212e-96, 2.9592365392916602e-101, 1.5923529644019419e-106, 1.3214344265685972e-112, 3.4927077138614495e-120}, {4.9941282442606218e-121, 1.9730195235183967e-113, 2.4653426103610859e-107, 4.7340081105291807e-102, 2.5936668261705122e-97, 5.6069447675960520e-93, 5.8240937771374570e-89, 3.3144783626996768e-85, 1.1342570222437056e-81, 2.5011096149430186e-78, 3.7476379174495528e-75, 3.9794814788876447e-72, 3.0979908735545725e-69, 1.8182439901095753e-66, 8.2354102738652040e-64, 2.9360923690156291e-61, 8.3803809757287599e-59, 1.9432660775004502e-56, 3.7079038793856585e-54, 5.8875467910577051e-52, 7.8572573935602256e-50, 8.8917221680510199e-48, 8.6005009516161168e-46, 7.1611639319733097e-44, 5.1661373788013124e-42, 3.2479669251550536e-40, 1.7890987177636214e-38, 8.6765699223362474e-37, 3.7212625316226216e-35, 1.4172340427766930e-33, 4.8110787981190828e-32, 1.4608586938294995e-30, 3.9805330733973355e-29, 9.7620761562971344e-28, 2.1608244949042565e-26, 4.3281046749583524e-25, 7.8636681438025253e-24, 1.2989130984240299e-22, 1.9546850118180088e-21, 2.6851626691585123e-20, 3.3733593511587544e-19, 3.8824303202657657e-18, 4.1001349905289425e-17, 3.9793051828221563e-16, 3.5542824359476288e-15, 2.9256051436471688e-14, 2.2220151125790449e-13, 1.5590549255574669e-12, 1.0116812009960419e-11, 6.0778437594159535e-11, 3.3838207012562939e-10, 1.7475098827142176e-09, 8.3784654573163473e-09, 3.7324734098992270e-08, 1.5461411843105312e-07, 5.9598254897039207e-07, 2.1391519688131322e-06, 7.1539515355890577e-06, 2.2304926470707147e-05, 6.4869805018180065e-05, 1.7607226778935711e-04, 4.4622007110453903e-04, 1.0563416857043819e-03, 2.3368400915518292e-03, 4.8325911868397145e-03, 9.3454535527143379e-03, 1.6905135871613127e-02, 2.8612106958160764e-02, 4.5320570847252710e-02, 6.7196013411209815e-02, 9.3275910346104995e-02, 1.2123716317285059e-01, 1.4756796236123393e-01, 1.6821923724022270e-01, 1.7960204009494329e-01, 1.7960204009494329e-01, 1.6821923724022270e-01, 1.4756796236123393e-01, 1.2123716317285059e-01, 9.3275910346104995e-02, 6.7196013411209815e-02, 4.5320570847252710e-02, 2.8612106958160764e-02, 1.6905135871613127e-02, 9.3454535527143379e-03, 4.8325911868397145e-03, 2.3368400915518292e-03, 1.0563416857043819e-03, 4.4622007110453903e-04, 1.7607226778935711e-04, 6.4869805018180065e-05, 2.2304926470707147e-05, 7.1539515355890577e-06, 2.1391519688131322e-06, 5.9598254897039207e-07, 1.5461411843105312e-07, 3.7324734098992270e-08, 8.3784654573163473e-09, 1.7475098827142176e-09, 3.3838207012562939e-10, 6.0778437594159535e-11, 1.0116812009960419e-11, 1.5590549255574669e-12, 2.2220151125790449e-13, 2.9256051436471688e-14, 3.5542824359476288e-15, 3.9793051828221563e-16, 4.1001349905289425e-17, 3.8824303202657657e-18, 3.3733593511587544e-19, 2.6851626691585123e-20, 1.9546850118180088e-21, 1.2989130984240299e-22, 7.8636681438025253e-24, 4.3281046749583524e-25, 2.1608244949042565e-26, 9.7620761562971344e-28, 3.9805330733973355e-29, 1.4608586938294995e-30, 4.8110787981190828e-32, 1.4172340427766930e-33, 3.7212625316226216e-35, 8.6765699223362474e-37, 1.7890987177636214e-38, 3.2479669251550536e-40, 5.1661373788013124e-42, 7.1611639319733097e-44, 8.6005009516161168e-46, 8.8917221680510199e-48, 7.8572573935602256e-50, 5.8875467910577051e-52, 3.7079038793856585e-54, 1.9432660775004502e-56, 8.3803809757287599e-59, 2.9360923690156291e-61, 8.2354102738652040e-64, 1.8182439901095753e-66, 3.0979908735545725e-69, 3.9794814788876447e-72, 3.7476379174495528e-75, 2.5011096149430186e-78, 1.1342570222437056e-81, 3.3144783626996768e-85, 5.8240937771374570e-89, 5.6069447675960520e-93, 2.5936668261705122e-97, 4.7340081105291807e-102, 2.4653426103610859e-107, 1.9730195235183967e-113, 4.9941282442606218e-121}, {7.1392222017713907e-122, 2.9445845110667619e-114, 3.8145868837135596e-108, 7.5673169898909099e-103, 4.2736593644380303e-98, 9.5083335143727237e-94, 1.0152930470452851e-89, 5.9342954899998552e-86, 2.0842120266141319e-82, 4.7139344340961388e-79, 7.2413131304484502e-76, 7.8798610228883591e-73, 6.2842892805603737e-70, 3.7773465198180638e-67, 1.7517513408453002e-64, 6.3932209199477197e-62, 1.8676726441679446e-59, 4.4319273103122463e-57, 8.6528507374176976e-55, 1.4056977850593077e-52, 1.9192002948401386e-50, 2.2217716370141584e-48, 2.1982691386986115e-46, 1.8722764372760468e-44, 1.3815703248778117e-42, 8.8845643289761640e-41, 5.0058533566520875e-39, 2.4832338706643681e-37, 1.0894227474485724e-35, 4.2442335712525587e-34, 1.4739090369348960e-32, 4.5785676785685073e-31, 1.2763864929327656e-29, 3.2028196423033392e-28, 7.2542458795704827e-27, 1.4869262820581125e-25, 2.7648741131715751e-24, 4.6744604380487021e-23, 7.2007069149677438e-22, 1.0126623472614820e-20, 1.3025790505179032e-19, 1.5351372541981349e-18, 1.6603563330241997e-17, 1.6505566788948694e-16, 1.5102835946897961e-15, 1.2737138463928603e-14, 9.9133825544714478e-14, 7.1289732797212971e-13, 4.7421458438831827e-12, 2.9209512270101235e-11, 1.6676562560887225e-10, 8.8333847125166249e-10, 4.3447745740955300e-09, 1.9860254178505552e-08, 8.4433687619112637e-08, 3.3409895046160263e-07, 1.2312829806627210e-06, 4.2290221665164350e-06, 1.3544999036061644e-05, 4.0477621043373221e-05, 1.1292006863438276e-04, 2.9420790203745482e-04, 7.1623536508659178e-04, 1.6298641009901027e-03, 3.4681866693627482e-03, 6.9032861428781267e-03, 1.2857145952636101e-02, 2.2412375310366960e-02, 3.6575629838591243e-02, 5.5891953828813568e-02, 7.9990869817108165e-02, 1.0723403572962083e-01, 1.3467313142650547e-01, 1.5846303276659124e-01, 1.7470447835636663e-01, 1.8047929085878514e-01, 1.7470447835636663e-01, 1.5846303276659124e-01, 1.3467313142650547e-01, 1.0723403572962083e-01, 7.9990869817108165e-02, 5.5891953828813568e-02, 3.6575629838591243e-02, 2.2412375310366960e-02, 1.2857145952636101e-02, 6.9032861428781267e-03, 3.4681866693627482e-03, 1.6298641009901027e-03, 7.1623536508659178e-04, 2.9420790203745482e-04, 1.1292006863438276e-04, 4.0477621043373221e-05, 1.3544999036061644e-05, 4.2290221665164350e-06, 1.2312829806627210e-06, 3.3409895046160263e-07, 8.4433687619112637e-08, 1.9860254178505552e-08, 4.3447745740955300e-09, 8.8333847125166249e-10, 1.6676562560887225e-10, 2.9209512270101235e-11, 4.7421458438831827e-12, 7.1289732797212971e-13, 9.9133825544714478e-14, 1.2737138463928603e-14, 1.5102835946897961e-15, 1.6505566788948694e-16, 1.6603563330241997e-17, 1.5351372541981349e-18, 1.3025790505179032e-19, 1.0126623472614820e-20, 7.2007069149677438e-22, 4.6744604380487021e-23, 2.7648741131715751e-24, 1.4869262820581125e-25, 7.2542458795704827e-27, 3.2028196423033392e-28, 1.2763864929327656e-29, 4.5785676785685073e-31, 1.4739090369348960e-32, 4.2442335712525587e-34, 1.0894227474485724e-35, 2.4832338706643681e-37, 5.0058533566520875e-39, 8.8845643289761640e-41, 1.3815703248778117e-42, 1.8722764372760468e-44, 2.1982691386986115e-46, 2.2217716370141584e-48, 1.9192002948401386e-50, 1.4056977850593077e-52, 8.6528507374176976e-55, 4.4319273103122463e-57, 1.8676726441679446e-59, 6.3932209199477197e-62, 1.7517513408453002e-64, 3.7773465198180638e-67, 6.2842892805603737e-70, 7.8798610228883591e-73, 7.2413131304484502e-76, 4.7139344340961388e-79, 2.0842120266141319e-82, 5.9342954899998552e-86, 1.0152930470452851e-89, 9.5083335143727237e-94, 4.2736593644380303e-98, 7.5673169898909099e-103, 3.8145868837135596e-108, 2.9445845110667619e-114, 7.1392222017713907e-122}, {1.0203215419405115e-122, 4.3926409088220260e-115, 5.8986558173681245e-109, 1.2087105293093391e-103, 7.0353980850250737e-99, 1.6107326288260005e-94, 1.7678067289525790e-90, 1.0610697100358954e-86, 3.8241442068780522e-83, 8.8702923923721366e-80, 1.3967624162820115e-76, 1.5573928888055416e-73, 1.2722188115916827e-70, 7.8305641247237068e-68, 3.7176883954596755e-65, 1.3887513560879043e-62, 4.1517737028880682e-60, 1.0080675510766497e-57, 2.0135706193376487e-55, 3.3463102229914590e-53, 4.6733192109921242e-51, 5.5335945022909141e-49, 5.5997707655432161e-47, 4.8778201649868724e-45, 3.6811705155316592e-43, 2.4210413787496984e-41, 1.3950773628177882e-39, 7.0777866064732306e-38, 3.1757468989046869e-36, 1.2654132053176338e-34, 4.4947480753641788e-33, 1.4281952005441561e-31, 4.0727582182469552e-30, 1.0454808582283026e-28, 2.4226185736538330e-27, 5.0807355599009919e-26, 9.6670785467690252e-25, 1.6725361565602745e-23, 2.6368638947823986e-22, 3.7957111549106315e-21, 4.9980289800251531e-20, 6.0306098179642906e-19, 6.6786804983364280e-18, 6.7991402460144679e-17, 6.3720317811650348e-16, 5.5049284400726915e-15, 4.3896449685818035e-14, 3.2346882306340970e-13, 2.2052168865195276e-12, 1.3923473891503035e-11, 8.1499619365601122e-11, 4.4267370542157585e-10, 2.2331409933577818e-09, 1.0471618689062924e-08, 4.5678915072122709e-08, 1.8549839541616252e-07, 7.0175441742037147e-07, 2.4747420668926454e-06, 8.1402071214919003e-06, 2.4988785980142873e-05, 7.1628474554958981e-05, 1.9180837279585649e-04, 4.8004901932197877e-04, 1.1233614820028411e-03, 2.4588639421196687e-03, 5.0359498094177816e-03, 9.6537773093780983e-03, 1.7326295602536231e-02, 2.9121725644242560e-02, 4.5848897885251948e-02, 6.7627897299374851e-02, 9.3471746781564918e-02, 1.2107439739077461e-01, 1.4699060677873937e-01, 1.6727380280253201e-01, 1.7843956694581845e-01, 1.7843956694581845e-01, 1.6727380280253201e-01, 1.4699060677873937e-01, 1.2107439739077461e-01, 9.3471746781564918e-02, 6.7627897299374851e-02, 4.5848897885251948e-02, 2.9121725644242560e-02, 1.7326295602536231e-02, 9.6537773093780983e-03, 5.0359498094177816e-03, 2.4588639421196687e-03, 1.1233614820028411e-03, 4.8004901932197877e-04, 1.9180837279585649e-04, 7.1628474554958981e-05, 2.4988785980142873e-05, 8.1402071214919003e-06, 2.4747420668926454e-06, 7.0175441742037147e-07, 1.8549839541616252e-07, 4.5678915072122709e-08, 1.0471618689062924e-08, 2.2331409933577818e-09, 4.4267370542157585e-10, 8.1499619365601122e-11, 1.3923473891503035e-11, 2.2052168865195276e-12, 3.2346882306340970e-13, 4.3896449685818035e-14, 5.5049284400726915e-15, 6.3720317811650348e-16, 6.7991402460144679e-17, 6.6786804983364280e-18, 6.0306098179642906e-19, 4.9980289800251531e-20, 3.7957111549106315e-21, 2.6368638947823986e-22, 1.6725361565602745e-23, 9.6670785467690252e-25, 5.0807355599009919e-26, 2.4226185736538330e-27, 1.0454808582283026e-28, 4.0727582182469552e-30, 1.4281952005441561e-31, 4.4947480753641788e-33, 1.2654132053176338e-34, 3.1757468989046869e-36, 7.0777866064732306e-38, 1.3950773628177882e-39, 2.4210413787496984e-41, 3.6811705155316592e-43, 4.8778201649868724e-45, 5.5997707655432161e-47, 5.5335945022909141e-49, 4.6733192109921242e-51, 3.3463102229914590e-53, 2.0135706193376487e-55, 1.0080675510766497e-57, 4.1517737028880682e-60, 1.3887513560879043e-62, 3.7176883954596755e-65, 7.8305641247237068e-68, 1.2722188115916827e-70, 1.5573928888055416e-73, 1.3967624162820115e-76, 8.8702923923721366e-80, 3.8241442068780522e-83, 1.0610697100358954e-86, 1.7678067289525790e-90, 1.6107326288260005e-94, 7.0353980850250737e-99, 1.2087105293093391e-103, 5.8986558173681245e-109, 4.3926409088220260e-115, 1.0203215419405115e-122}, {1.4578716888574380e-123, 6.5499584195542182e-116, 9.1158441302395916e-110, 1.9291851130201365e-104, 1.1571376888010415e-99, 2.7257668732866951e-95, 3.0744291780743119e-91, 1.8947250431186403e-87, 7.0064183028413687e-84, 1.6664955389849393e-80, 2.6895662316444978e-77, 3.0723812680200150e-74, 2.5704405332276809e-71, 1.6198772061572697e-68, 7.8722498229365745e-66, 3.0095177392268181e-63, 9.2061099904566106e-61, 2.2868504296047653e-58, 4.6726874994563693e-56, 7.9427931843455534e-54, 1.1344972574084324e-51, 1.3738127684763008e-49, 1.4217090927665081e-47, 1.2663997582044745e-45, 9.7729455955061106e-44, 6.5725138972034875e-42, 3.8727324373725659e-40, 2.0091450762048232e-38, 9.2185663859103873e-37, 3.7563551936945986e-35, 1.3644995796552897e-33, 4.4341465741479497e-32, 1.2932715429724819e-30, 3.3956536214966241e-29, 8.0487680064663208e-28, 1.7268001245109222e-26, 3.3613905413108243e-25, 5.9504202589874584e-24, 9.5995603721747768e-23, 1.4141461815469168e-21, 1.9058394524305284e-20, 2.3538938440623925e-19, 2.6687563232163005e-18, 2.7817760484437033e-17, 2.6696608032295694e-16, 2.3621238776008329e-15, 1.9293848215014542e-14, 1.4565613270987712e-13, 1.0174797099588637e-12, 6.5837630407380247e-12, 3.9501281887181556e-11, 2.1996223199610065e-10, 1.1378158851290800e-09, 5.4720083734809282e-09, 2.4485807329829557e-08, 1.0202255589712521e-07, 3.9608954710479925e-07, 1.4337991258427923e-06, 4.8422272544211524e-06, 1.5265488972373680e-05, 4.4948480076886716e-05, 1.2367217082799177e-04, 3.1811200186972611e-04, 7.6528399238001590e-04, 1.7225370790285232e-03, 3.6288805291928589e-03, 7.1577405214717574e-03, 1.3222272319718250e-02, 2.2881143871485050e-02, 3.7101604703410701e-02, 5.6381975314828768e-02, 8.0315152775434245e-02, 1.0725786228191081e-01, 1.3430372904700771e-01, 1.5769403536946561e-01, 1.7363606017905039e-01, 1.7929968765055787e-01, 1.7363606017905039e-01, 1.5769403536946561e-01, 1.3430372904700771e-01, 1.0725786228191081e-01, 8.0315152775434245e-02, 5.6381975314828768e-02, 3.7101604703410701e-02, 2.2881143871485050e-02, 1.3222272319718250e-02, 7.1577405214717574e-03, 3.6288805291928589e-03, 1.7225370790285232e-03, 7.6528399238001590e-04, 3.1811200186972611e-04, 1.2367217082799177e-04, 4.4948480076886716e-05, 1.5265488972373680e-05, 4.8422272544211524e-06, 1.4337991258427923e-06, 3.9608954710479925e-07, 1.0202255589712521e-07, 2.4485807329829557e-08, 5.4720083734809282e-09, 1.1378158851290800e-09, 2.1996223199610065e-10, 3.9501281887181556e-11, 6.5837630407380247e-12, 1.0174797099588637e-12, 1.4565613270987712e-13, 1.9293848215014542e-14, 2.3621238776008329e-15, 2.6696608032295694e-16, 2.7817760484437033e-17, 2.6687563232163005e-18, 2.3538938440623925e-19, 1.9058394524305284e-20, 1.4141461815469168e-21, 9.5995603721747768e-23, 5.9504202589874584e-24, 3.3613905413108243e-25, 1.7268001245109222e-26, 8.0487680064663208e-28, 3.3956536214966241e-29, 1.2932715429724819e-30, 4.4341465741479497e-32, 1.3644995796552897e-33, 3.7563551936945986e-35, 9.2185663859103873e-37, 2.0091450762048232e-38, 3.8727324373725659e-40, 6.5725138972034875e-42, 9.7729455955061106e-44, 1.2663997582044745e-45, 1.4217090927665081e-47, 1.3738127684763008e-49, 1.1344972574084324e-51, 7.9427931843455534e-54, 4.6726874994563693e-56, 2.2868504296047653e-58, 9.2061099904566106e-61, 3.0095177392268181e-63, 7.8722498229365745e-66, 1.6198772061572697e-68, 2.5704405332276809e-71, 3.0723812680200150e-74, 2.6895662316444978e-77, 1.6664955389849393e-80, 7.0064183028413687e-84, 1.8947250431186403e-87, 3.0744291780743119e-91, 2.7257668732866951e-95, 1.1571376888010415e-99, 1.9291851130201365e-104, 9.1158441302395916e-110, 6.5499584195542182e-116, 1.4578716888574380e-123}, {2.0825660478904760e-124, 9.7625806330567035e-117, 1.4079328290981535e-110, 3.0768081483238432e-105, 1.9014873630323964e-100, 4.6079244634146070e-96, 5.3405557808694215e-92, 3.3789567793532434e-88, 1.2818424753415062e-84, 3.1260093916222602e-81, 5.1701750558611924e-78, 6.0500487002887184e-75, 5.1832685019930213e-72, 3.3439902942647502e-69, 1.6632668027272507e-66, 6.5065315377220389e-64, 2.0362992343457651e-61, 5.1742950935108869e-59, 1.0813687999683845e-56, 1.8798749780879993e-54, 2.7458133331828386e-52, 3.3999899766205468e-50, 3.5976656083923711e-48, 3.2766076271604045e-46, 2.5853058405449532e-44, 1.7776460048844266e-42, 1.0709222498944708e-40, 5.6804446369555694e-39, 2.6648525467274738e-37, 1.1102669670225965e-35, 4.1238340545301011e-34, 1.3703279298000201e-32, 4.0870885738671846e-31, 1.0974483844909332e-29, 2.6604572771951219e-28, 5.8380527272929378e-27, 1.1624651194307257e-25, 2.1051475426760218e-24, 3.4745776974200654e-23, 5.2372761374065798e-22, 7.2227982269547378e-21, 9.1298647949536611e-20, 1.0594921794825161e-18, 1.1305197522298609e-17, 1.1108048214201895e-16, 1.0064014746615927e-15, 8.4185702868695228e-15, 6.5097729971311742e-14, 4.6585402153758067e-13, 3.0885703725214258e-12, 1.8990163158421596e-11, 1.0838710379194289e-10, 5.7477002127859619e-10, 2.8342947222693205e-09, 1.3006943860141712e-08, 5.5591582741553296e-08, 2.2143724484223221e-07, 8.2259408138485364e-07, 2.8515507236878458e-06, 9.2296922270054013e-06, 2.7908549833980887e-05, 7.8876670613220481e-05, 2.0846012412302649e-04, 5.1540364930051158e-04, 1.1925993797900470e-03, 2.5835851277422653e-03, 5.2417582224628060e-03, 9.9629708516368199e-03, 1.7745045563417383e-02, 2.9624281938924940e-02, 4.6365470641524055e-02, 6.8045456872924986e-02, 9.3654947635056565e-02, 1.2090579766618584e-01, 1.4641795120378570e-01, 1.6634383944546130e-01, 1.7729937449709982e-01, 1.7729937449709982e-01, 1.6634383944546130e-01, 1.4641795120378570e-01, 1.2090579766618584e-01, 9.3654947635056565e-02, 6.8045456872924986e-02, 4.6365470641524055e-02, 2.9624281938924940e-02, 1.7745045563417383e-02, 9.9629708516368199e-03, 5.2417582224628060e-03, 2.5835851277422653e-03, 1.1925993797900470e-03, 5.1540364930051158e-04, 2.0846012412302649e-04, 7.8876670613220481e-05, 2.7908549833980887e-05, 9.2296922270054013e-06, 2.8515507236878458e-06, 8.2259408138485364e-07, 2.2143724484223221e-07, 5.5591582741553296e-08, 1.3006943860141712e-08, 2.8342947222693205e-09, 5.7477002127859619e-10, 1.0838710379194289e-10, 1.8990163158421596e-11, 3.0885703725214258e-12, 4.6585402153758067e-13, 6.5097729971311742e-14, 8.4185702868695228e-15, 1.0064014746615927e-15, 1.1108048214201895e-16, 1.1305197522298609e-17, 1.0594921794825161e-18, 9.1298647949536611e-20, 7.2227982269547378e-21, 5.2372761374065798e-22, 3.4745776974200654e-23, 2.1051475426760218e-24, 1.1624651194307257e-25, 5.8380527272929378e-27, 2.6604572771951219e-28, 1.0974483844909332e-29, 4.0870885738671846e-31, 1.3703279298000201e-32, 4.1238340545301011e-34, 1.1102669670225965e-35, 2.6648525467274738e-37, 5.6804446369555694e-39, 1.0709222498944708e-40, 1.7776460048844266e-42, 2.5853058405449532e-44, 3.2766076271604045e-46, 3.5976656083923711e-48, 3.3999899766205468e-50, 2.7458133331828386e-52, 1.8798749780879993e-54, 1.0813687999683845e-56, 5.1742950935108869e-59, 2.0362992343457651e-61, 6.5065315377220389e-64, 1.6632668027272507e-66, 3.3439902942647502e-69, 5.1832685019930213e-72, 6.0500487002887184e-75, 5.1701750558611924e-78, 3.1260093916222602e-81, 1.2818424753415062e-84, 3.3789567793532434e-88, 5.3405557808694215e-92, 4.6079244634146070e-96, 1.9014873630323964e-100, 3.0768081483238432e-105, 1.4079328290981535e-110, 9.7625806330567035e-117, 2.0825660478904760e-124}, {2.9742440544925765e-125, 1.4544742104415291e-117, 2.1732568643306002e-111, 4.9034921609592363e-106, 3.1218947762576099e-101, 7.7817715084363300e-97, 9.2663025096531715e-93, 6.0181049060844634e-89, 2.3418402716705127e-85, 5.8546944803309517e-82, 9.9220223776303372e-79, 1.1892107956658327e-75, 1.0431826368600407e-72, 6.8889436382474771e-70, 3.5064990884120332e-67, 1.4034428812712122e-64, 4.4930692768932806e-62, 1.1677337858216425e-59, 2.4957603118464674e-57, 4.4365856613493741e-55, 6.6258941032515879e-53, 8.3883165922512944e-51, 9.0744120512086595e-49, 8.4490059406933366e-47, 6.8149889325650219e-45, 4.7903177946790465e-43, 2.9501316492565748e-41, 1.5996806743635201e-39, 7.6718304654322104e-38, 3.2676791768964119e-36, 1.2408362449919783e-34, 4.2155847725706856e-33, 1.2855517878737815e-31, 3.5296150194332557e-30, 8.7497557637466758e-29, 1.9635223775022683e-27, 3.9986259229284162e-26, 7.4065187877720327e-25, 1.2504748686909515e-23, 1.9282493305400296e-22, 2.7207846792186873e-21, 3.5191108460642354e-20, 4.1792457685713468e-19, 4.5641951147736119e-18, 4.5905709762107554e-17, 4.2579719891425731e-16, 3.6469920289222789e-15, 2.8879673414801644e-14, 2.1167713706852141e-13, 1.4376384719405419e-12, 9.0565354971087218e-12, 5.2969771654748994e-11, 2.8789912587990587e-10, 1.4553534068219742e-09, 6.8479451315824872e-09, 3.0015309064632456e-08, 1.2263753200782247e-07, 4.6740187357094381e-07, 1.6627017535681513e-06, 5.5239309109102710e-06, 1.7148598641483128e-05, 4.9770974063404784e-05, 1.3511264030161956e-04, 3.4322471703307256e-04, 8.1620625227316382e-04, 1.8177000254213835e-03, 3.7922249171946417e-03, 7.4139737035166485e-03, 1.3586755499761058e-02, 2.3345243317359717e-02, 3.7618101204680170e-02, 5.6858711709023881e-02, 8.0625581158863605e-02, 1.0727209153833471e-01, 1.3393358950744624e-01, 1.5693526614765907e-01, 1.7258695046281516e-01, 1.7814291547216715e-01, 1.7258695046281516e-01, 1.5693526614765907e-01, 1.3393358950744624e-01, 1.0727209153833471e-01, 8.0625581158863605e-02, 5.6858711709023881e-02, 3.7618101204680170e-02, 2.3345243317359717e-02, 1.3586755499761058e-02, 7.4139737035166485e-03, 3.7922249171946417e-03, 1.8177000254213835e-03, 8.1620625227316382e-04, 3.4322471703307256e-04, 1.3511264030161956e-04, 4.9770974063404784e-05, 1.7148598641483128e-05, 5.5239309109102710e-06, 1.6627017535681513e-06, 4.6740187357094381e-07, 1.2263753200782247e-07, 3.0015309064632456e-08, 6.8479451315824872e-09, 1.4553534068219742e-09, 2.8789912587990587e-10, 5.2969771654748994e-11, 9.0565354971087218e-12, 1.4376384719405419e-12, 2.1167713706852141e-13, 2.8879673414801644e-14, 3.6469920289222789e-15, 4.2579719891425731e-16, 4.5905709762107554e-17, 4.5641951147736119e-18, 4.1792457685713468e-19, 3.5191108460642354e-20, 2.7207846792186873e-21, 1.9282493305400296e-22, 1.2504748686909515e-23, 7.4065187877720327e-25, 3.9986259229284162e-26, 1.9635223775022683e-27, 8.7497557637466758e-29, 3.5296150194332557e-30, 1.2855517878737815e-31, 4.2155847725706856e-33, 1.2408362449919783e-34, 3.2676791768964119e-36, 7.6718304654322104e-38, 1.5996806743635201e-39, 2.9501316492565748e-41, 4.7903177946790465e-43, 6.8149889325650219e-45, 8.4490059406933366e-47, 9.0744120512086595e-49, 8.3883165922512944e-51, 6.6258941032515879e-53, 4.4365856613493741e-55, 2.4957603118464674e-57, 1.1677337858216425e-59, 4.4930692768932806e-62, 1.4034428812712122e-64, 3.5064990884120332e-67, 6.8889436382474771e-70, 1.0431826368600407e-72, 1.1892107956658327e-75, 9.9220223776303372e-79, 5.8546944803309517e-82, 2.3418402716705127e-85, 6.0181049060844634e-89, 9.2663025096531715e-93, 7.7817715084363300e-97, 3.1218947762576099e-101, 4.9034921609592363e-106, 2.1732568643306002e-111, 1.4544742104415291e-117, 2.9742440544925765e-125}, {4.2467223153569913e-126, 2.1660313165253327e-118, 3.3526412389934468e-112, 7.8089506311734750e-107, 5.1211062371557049e-102, 1.3128438701986923e-97, 1.6059434510399780e-93, 1.0704932710164072e-89, 4.2723909537910979e-86, 1.0948479687576274e-82, 1.9009714466058216e-79, 2.3333732870895970e-76, 2.0954987289754821e-73, 1.4163011238027347e-70, 7.3764205708401192e-68, 3.0202620912677113e-65, 9.8899383346021114e-63, 2.6286294129074487e-60, 5.7447123101943819e-58, 1.0441146661857655e-55, 1.5941894796140349e-53, 2.0631744724119192e-51, 2.2815057723526744e-49, 2.1713655679015281e-47, 1.7902127496153674e-45, 1.2862015727088547e-43, 8.0963481474532886e-42, 4.4873140335977730e-40, 2.1997031006119584e-38, 9.5769420875142906e-37, 3.7173934630972095e-35, 1.2910298923887236e-33, 4.0247941719917949e-32, 1.1297479501227750e-30, 2.8633730681601511e-29, 6.5701662464695220e-28, 1.3681807173905664e-26, 2.5916454156396681e-25, 4.4751190749666469e-24, 7.0583497822483184e-23, 1.0188011695097018e-21, 1.3481278810188344e-20, 1.6381331947152628e-19, 1.8307185107770479e-18, 1.8844546640240470e-17, 1.7891286411123497e-16, 1.5687514682212088e-15, 1.2719076381502738e-14, 9.5465675547568851e-14, 6.6405134257786806e-13, 4.2851307836098596e-12, 2.5677582201989908e-11, 1.4301024597508902e-10, 7.4092720692344339e-10, 3.5737970851749710e-09, 1.6060537813990750e-08, 6.7293992111962037e-08, 2.6306912128825106e-07, 9.6009499955544809e-07, 3.2731466120984474e-06, 1.0429494937549579e-05, 3.1076452822469759e-05, 8.6632019755194801e-05, 2.2604661890533189e-04, 5.5229314310309603e-04, 1.2640347665701273e-03, 2.7109305106750477e-03, 5.4498805064709423e-03, 1.0272859026411405e-02, 1.8161242168807858e-02, 3.0119768029475406e-02, 4.6870503949025956e-02, 6.8449129121212759e-02, 9.3826040853472042e-02, 1.2073175170965833e-01, 1.4585002297738520e-01, 1.6542893986636190e-01, 1.7618076008397315e-01, 1.7618076008397315e-01, 1.6542893986636190e-01, 1.4585002297738520e-01, 1.2073175170965833e-01, 9.3826040853472042e-02, 6.8449129121212759e-02, 4.6870503949025956e-02, 3.0119768029475406e-02, 1.8161242168807858e-02, 1.0272859026411405e-02, 5.4498805064709423e-03, 2.7109305106750477e-03, 1.2640347665701273e-03, 5.5229314310309603e-04, 2.2604661890533189e-04, 8.6632019755194801e-05, 3.1076452822469759e-05, 1.0429494937549579e-05, 3.2731466120984474e-06, 9.6009499955544809e-07, 2.6306912128825106e-07, 6.7293992111962037e-08, 1.6060537813990750e-08, 3.5737970851749710e-09, 7.4092720692344339e-10, 1.4301024597508902e-10, 2.5677582201989908e-11, 4.2851307836098596e-12, 6.6405134257786806e-13, 9.5465675547568851e-14, 1.2719076381502738e-14, 1.5687514682212088e-15, 1.7891286411123497e-16, 1.8844546640240470e-17, 1.8307185107770479e-18, 1.6381331947152628e-19, 1.3481278810188344e-20, 1.0188011695097018e-21, 7.0583497822483184e-23, 4.4751190749666469e-24, 2.5916454156396681e-25, 1.3681807173905664e-26, 6.5701662464695220e-28, 2.8633730681601511e-29, 1.1297479501227750e-30, 4.0247941719917949e-32, 1.2910298923887236e-33, 3.7173934630972095e-35, 9.5769420875142906e-37, 2.1997031006119584e-38, 4.4873140335977730e-40, 8.0963481474532886e-42, 1.2862015727088547e-43, 1.7902127496153674e-45, 2.1713655679015281e-47, 2.2815057723526744e-49, 2.0631744724119192e-51, 1.5941894796140349e-53, 1.0441146661857655e-55, 5.7447123101943819e-58, 2.6286294129074487e-60, 9.8899383346021114e-63, 3.0202620912677113e-65, 7.3764205708401192e-68, 1.4163011238027347e-70, 2.0954987289754821e-73, 2.3333732870895970e-76, 1.9009714466058216e-79, 1.0948479687576274e-82, 4.2723909537910979e-86, 1.0704932710164072e-89, 1.6059434510399780e-93, 1.3128438701986923e-97, 5.1211062371557049e-102, 7.8089506311734750e-107, 3.3526412389934468e-112, 2.1660313165253327e-118, 4.2467223153569913e-126}, {6.0622191716662980e-127, 3.2243541187800939e-119, 5.1690742816237208e-113, 1.2426977160105404e-107, 8.3933287533777738e-103, 2.2126569238728289e-98, 2.7801189404282378e-94, 1.9017852686354782e-90, 7.7836404960844694e-87, 2.0443095742420186e-83, 3.6361329490246816e-80, 4.5702928776404487e-77, 4.2014053957085256e-74, 2.9059246516402931e-71, 1.5484204394570369e-68, 6.4850166385488236e-66, 2.1717290123179292e-63, 5.9022979463583546e-61, 1.3188160319392796e-58, 2.4504276066974761e-56, 3.8244861009984640e-54, 5.0591506359259702e-52, 5.7180427835175108e-50, 5.5619189779622956e-48, 4.6865094097082296e-46, 3.4411166261243821e-44, 2.2137173158797545e-42, 1.2539021346574782e-40, 6.2819019919798964e-39, 2.7952039819044771e-37, 1.1089145782361913e-35, 3.9362772026982286e-34, 1.2543049763002862e-32, 3.5989403271252947e-31, 9.3246229360624703e-30, 2.1873567871874991e-28, 4.6570323992852519e-27, 9.0198508148124766e-26, 1.5926655666987673e-24, 2.5689779244357800e-23, 3.7925166697437060e-22, 5.1332963733171119e-21, 6.3810270087780860e-20, 7.2960970893548457e-19, 7.6848696141461809e-18, 7.4667368566800348e-17, 6.7010236404093807e-16, 5.5616305380816712e-15, 4.2738351786402332e-14, 3.0441295544509839e-13, 2.0118060311112926e-12, 1.2348350013212526e-11, 7.0457887005315459e-11, 3.7404445985544352e-10, 1.8490262742729560e-09, 8.5176899942265963e-09, 3.6590845237002989e-08, 1.4668615688059134e-07, 5.4909587760916178e-07, 1.9204753233550013e-06, 6.2793321142086111e-06, 1.9203890628511156e-05, 5.4960123823238632e-05, 1.4726036700166861e-04, 3.6956136752144001e-04, 8.6899815474605370e-04, 1.9153075674406669e-03, 3.9581151034971717e-03, 7.6718266966305298e-03, 1.3950429172087464e-02, 2.3804589918929770e-02, 3.8125218704480275e-02, 5.7322493628469834e-02, 8.0922651951388633e-02, 1.0727720003748800e-01, 1.3356293292585539e-01, 1.5618653283532280e-01, 1.7155657639082103e-01, 1.7700824722075201e-01, 1.7155657639082103e-01, 1.5618653283532280e-01, 1.3356293292585539e-01, 1.0727720003748800e-01, 8.0922651951388633e-02, 5.7322493628469834e-02, 3.8125218704480275e-02, 2.3804589918929770e-02, 1.3950429172087464e-02, 7.6718266966305298e-03, 3.9581151034971717e-03, 1.9153075674406669e-03, 8.6899815474605370e-04, 3.6956136752144001e-04, 1.4726036700166861e-04, 5.4960123823238632e-05, 1.9203890628511156e-05, 6.2793321142086111e-06, 1.9204753233550013e-06, 5.4909587760916178e-07, 1.4668615688059134e-07, 3.6590845237002989e-08, 8.5176899942265963e-09, 1.8490262742729560e-09, 3.7404445985544352e-10, 7.0457887005315459e-11, 1.2348350013212526e-11, 2.0118060311112926e-12, 3.0441295544509839e-13, 4.2738351786402332e-14, 5.5616305380816712e-15, 6.7010236404093807e-16, 7.4667368566800348e-17, 7.6848696141461809e-18, 7.2960970893548457e-19, 6.3810270087780860e-20, 5.1332963733171119e-21, 3.7925166697437060e-22, 2.5689779244357800e-23, 1.5926655666987673e-24, 9.0198508148124766e-26, 4.6570323992852519e-27, 2.1873567871874991e-28, 9.3246229360624703e-30, 3.5989403271252947e-31, 1.2543049763002862e-32, 3.9362772026982286e-34, 1.1089145782361913e-35, 2.7952039819044771e-37, 6.2819019919798964e-39, 1.2539021346574782e-40, 2.2137173158797545e-42, 3.4411166261243821e-44, 4.6865094097082296e-46, 5.5619189779622956e-48, 5.7180427835175108e-50, 5.0591506359259702e-52, 3.8244861009984640e-54, 2.4504276066974761e-56, 1.3188160319392796e-58, 5.9022979463583546e-61, 2.1717290123179292e-63, 6.4850166385488236e-66, 1.5484204394570369e-68, 2.9059246516402931e-71, 4.2014053957085256e-74, 4.5702928776404487e-77, 3.6361329490246816e-80, 2.0443095742420186e-83, 7.7836404960844694e-87, 1.9017852686354782e-90, 2.7801189404282378e-94, 2.2126569238728289e-98, 8.3933287533777738e-103, 1.2426977160105404e-107, 5.1690742816237208e-113, 3.2243541187800939e-119, 6.0622191716662980e-127}, {8.6518898286288247e-128, 4.7977981754547922e-120, 7.9650930361988897e-114, 1.9761840987326553e-108, 1.3744652069324438e-103, 3.7255148645554058e-99, 4.8074121331969427e-95, 3.3744153060134342e-91, 1.4161180265335159e-87, 3.8114504571794760e-84, 6.9438585136020447e-81, 8.9360817516471687e-78, 8.4079759000226087e-75, 5.9504405763416772e-72, 3.2435033695316742e-69, 1.3893312175841125e-66, 4.7576408366455308e-64, 1.3220024862368775e-61, 3.0197052622687561e-59, 5.7351470833255443e-57, 9.1486995119191431e-55, 1.2368470663040083e-52, 1.4286078076592960e-50, 1.4200335880405776e-48, 1.2226957787809403e-46, 9.1739205502621965e-45, 6.0306042099204429e-43, 3.4904884601063066e-41, 1.7869095381531890e-39, 8.1249855483381444e-38, 3.2939528684311649e-36, 1.1948989473488384e-34, 3.8912956469188826e-33, 1.1411267330350244e-31, 3.0219294698888464e-30, 7.2459465976943397e-29, 1.5770256477583313e-27, 3.1226061139317796e-26, 5.6372579181684656e-25, 9.2975592528325581e-24, 1.4036014280320261e-22, 1.9429670019227641e-21, 2.4703591186430466e-20, 2.8894203773544814e-19, 3.1135796480328694e-18, 3.0953725694775336e-17, 2.8427562189767261e-16, 2.4147784190996735e-15, 1.8994699453982887e-14, 1.3851048606782092e-13, 9.3729953674226721e-13, 5.8917523372705995e-12, 3.4433525991626855e-11, 1.8726953725774312e-10, 9.4854377303416358e-10, 4.4780357696096071e-09, 1.9718477984120434e-08, 8.1042320257489110e-08, 3.1108717616071734e-07, 1.1159535961120921e-06, 3.7432563998726419e-06, 1.1746874098316171e-05, 3.4504766489542566e-05, 9.4911766414585672e-05, 2.4458580745649063e-04, 5.9072464709476020e-04, 1.3376446613946990e-03, 2.8408258176521148e-03, 5.6601830605110866e-03, 1.0583273905359803e-02, 1.8574752611538813e-02, 3.0608185223036027e-02, 4.7364212800332400e-02, 6.8839337618374755e-02, 9.3985530465238165e-02, 1.2055262431349997e-01, 1.4528684159808489e-01, 1.6452871112826625e-01, 1.7508305167467292e-01, 1.7508305167467292e-01, 1.6452871112826625e-01, 1.4528684159808489e-01, 1.2055262431349997e-01, 9.3985530465238165e-02, 6.8839337618374755e-02, 4.7364212800332400e-02, 3.0608185223036027e-02, 1.8574752611538813e-02, 1.0583273905359803e-02, 5.6601830605110866e-03, 2.8408258176521148e-03, 1.3376446613946990e-03, 5.9072464709476020e-04, 2.4458580745649063e-04, 9.4911766414585672e-05, 3.4504766489542566e-05, 1.1746874098316171e-05, 3.7432563998726419e-06, 1.1159535961120921e-06, 3.1108717616071734e-07, 8.1042320257489110e-08, 1.9718477984120434e-08, 4.4780357696096071e-09, 9.4854377303416358e-10, 1.8726953725774312e-10, 3.4433525991626855e-11, 5.8917523372705995e-12, 9.3729953674226721e-13, 1.3851048606782092e-13, 1.8994699453982887e-14, 2.4147784190996735e-15, 2.8427562189767261e-16, 3.0953725694775336e-17, 3.1135796480328694e-18, 2.8894203773544814e-19, 2.4703591186430466e-20, 1.9429670019227641e-21, 1.4036014280320261e-22, 9.2975592528325581e-24, 5.6372579181684656e-25, 3.1226061139317796e-26, 1.5770256477583313e-27, 7.2459465976943397e-29, 3.0219294698888464e-30, 1.1411267330350244e-31, 3.8912956469188826e-33, 1.1948989473488384e-34, 3.2939528684311649e-36, 8.1249855483381444e-38, 1.7869095381531890e-39, 3.4904884601063066e-41, 6.0306042099204429e-43, 9.1739205502621965e-45, 1.2226957787809403e-46, 1.4200335880405776e-48, 1.4286078076592960e-50, 1.2368470663040083e-52, 9.1486995119191431e-55, 5.7351470833255443e-57, 3.0197052622687561e-59, 1.3220024862368775e-61, 4.7576408366455308e-64, 1.3893312175841125e-66, 3.2435033695316742e-69, 5.9504405763416772e-72, 8.4079759000226087e-75, 8.9360817516471687e-78, 6.9438585136020447e-81, 3.8114504571794760e-84, 1.4161180265335159e-87, 3.3744153060134342e-91, 4.8074121331969427e-95, 3.7255148645554058e-99, 1.3744652069324438e-103, 1.9761840987326553e-108, 7.9650930361988897e-114, 4.7977981754547922e-120, 8.6518898286288247e-128}, {1.2345052237856376e-128, 7.1361565819334150e-121, 1.2266594150983389e-114, 3.1403768309606574e-109, 2.2488806415651994e-104, 6.2666361422341182e-100, 8.3038517132199445e-96, 5.9799996465821154e-92, 2.5729286682716097e-88, 7.0956475615088519e-85, 1.3239358802678529e-81, 1.7442238644011473e-78, 1.6795285148575302e-75, 1.2160739161745740e-72, 6.7800483155694390e-70, 2.9698887117979696e-67, 1.0398334915263462e-64, 2.9537631885955336e-62, 6.8964075076110458e-60, 1.3386610121664405e-57, 2.1822972256453033e-55, 3.0148592722499396e-53, 3.5582391595026354e-51, 3.6138684655576511e-49, 3.1792871272966973e-47, 2.4372213779029665e-45, 1.6369116080171861e-43, 9.6799943605644117e-42, 5.0631425091072337e-40, 2.3522144528005868e-38, 9.7436152093981038e-37, 3.6115822674301904e-35, 1.2018288490038798e-33, 3.6015212879811887e-32, 9.7468625406557925e-31, 2.3885355396506504e-29, 5.3132702519188496e-28, 1.0753756973350715e-26, 1.9845716557598769e-25, 3.3462806594548906e-24, 5.1650319326919827e-23, 7.3109577835953338e-22, 9.5059376788875581e-21, 1.1371572178214573e-19, 1.2534183670047640e-18, 1.2747621562807485e-17, 1.1978221703435283e-16, 1.0411788127158037e-15, 8.3817954183785831e-15, 6.2561571481732302e-14, 4.3340112417705868e-13, 2.7894047381925510e-12, 1.6694572089431568e-11, 9.2995420785846948e-11, 4.8253510985881196e-10, 2.3340778029825478e-09, 1.0532686874011172e-08, 4.4371096492273068e-08, 1.7461444759106688e-07, 6.4230905783791856e-07, 2.2097354109635801e-06, 7.1138004485475131e-06, 2.1441047304603760e-05, 6.0530803203101914e-05, 1.6013349936228681e-04, 3.9713567276994117e-04, 9.2365343040052964e-04, 2.0153124277213861e-03, 4.1264467864295497e-03, 7.9311452492789869e-03, 1.4313136262234679e-02, 2.4259110409796711e-02, 3.8623061726879737e-02, 5.7773645171755317e-02, 8.1206842893413358e-02, 1.0727363982645181e-01, 1.3319196312197995e-01, 1.5544764635273797e-01, 1.7054438857615731e-01, 1.7589498780426926e-01, 1.7054438857615731e-01, 1.5544764635273797e-01, 1.3319196312197995e-01, 1.0727363982645181e-01, 8.1206842893413358e-02, 5.7773645171755317e-02, 3.8623061726879737e-02, 2.4259110409796711e-02, 1.4313136262234679e-02, 7.9311452492789869e-03, 4.1264467864295497e-03, 2.0153124277213861e-03, 9.2365343040052964e-04, 3.9713567276994117e-04, 1.6013349936228681e-04, 6.0530803203101914e-05, 2.1441047304603760e-05, 7.1138004485475131e-06, 2.2097354109635801e-06, 6.4230905783791856e-07, 1.7461444759106688e-07, 4.4371096492273068e-08, 1.0532686874011172e-08, 2.3340778029825478e-09, 4.8253510985881196e-10, 9.2995420785846948e-11, 1.6694572089431568e-11, 2.7894047381925510e-12, 4.3340112417705868e-13, 6.2561571481732302e-14, 8.3817954183785831e-15, 1.0411788127158037e-15, 1.1978221703435283e-16, 1.2747621562807485e-17, 1.2534183670047640e-18, 1.1371572178214573e-19, 9.5059376788875581e-21, 7.3109577835953338e-22, 5.1650319326919827e-23, 3.3462806594548906e-24, 1.9845716557598769e-25, 1.0753756973350715e-26, 5.3132702519188496e-28, 2.3885355396506504e-29, 9.7468625406557925e-31, 3.6015212879811887e-32, 1.2018288490038798e-33, 3.6115822674301904e-35, 9.7436152093981038e-37, 2.3522144528005868e-38, 5.0631425091072337e-40, 9.6799943605644117e-42, 1.6369116080171861e-43, 2.4372213779029665e-45, 3.1792871272966973e-47, 3.6138684655576511e-49, 3.5582391595026354e-51, 3.0148592722499396e-53, 2.1822972256453033e-55, 1.3386610121664405e-57, 6.8964075076110458e-60, 2.9537631885955336e-62, 1.0398334915263462e-64, 2.9698887117979696e-67, 6.7800483155694390e-70, 1.2160739161745740e-72, 1.6795285148575302e-75, 1.7442238644011473e-78, 1.3239358802678529e-81, 7.0956475615088519e-85, 2.5729286682716097e-88, 5.9799996465821154e-92, 8.3038517132199445e-96, 6.2666361422341182e-100, 2.2488806415651994e-104, 3.1403768309606574e-109, 1.2266594150983389e-114, 7.1361565819334150e-121, 1.2345052237856376e-128}, {1.7610777213868225e-129, 1.0609912453053086e-121, 1.8880558326632475e-115, 4.9869144791066677e-110, 3.6765138012657772e-105, 1.0530846293412266e-100, 1.4327597465974048e-96, 1.0584620865577655e-92, 4.6684664948676272e-89, 1.3190436630179440e-85, 2.5202632570592097e-82, 3.3987392362121908e-79, 3.3488181154099359e-76, 2.4804288326920011e-73, 1.4143430079239634e-70, 6.3346915410241234e-68, 2.2674306256941818e-65, 6.5836081498721399e-63, 1.5709872468845785e-60, 3.1162632356321267e-58, 5.1910061298697851e-56, 7.3273399650957289e-54, 8.8354796635334199e-52, 9.1677552430019203e-50, 8.2395121572045278e-48, 6.4526516804970545e-46, 4.4272600478065905e-44, 2.6745508857556167e-42, 1.4291089046778579e-40, 6.7826401946708970e-39, 2.8703150932676095e-37, 1.0869482703973487e-35, 3.6955025716069553e-34, 1.1315067191371783e-32, 3.1289601063429292e-31, 7.8353356972027161e-30, 1.7811808982463465e-28, 3.6843324819342597e-27, 6.9494876383385912e-26, 1.1977696964648504e-24, 1.8899444794564548e-23, 2.7350044749786203e-22, 3.6360647433609545e-21, 4.4479270726420680e-20, 5.0139935781581053e-19, 5.2157884028434802e-18, 5.0135017597656447e-17, 4.4585078370462008e-16, 3.6726238537048878e-15, 2.8053332193363147e-14, 1.9891563745557595e-13, 1.3105682814703333e-12, 8.0308637715632703e-12, 4.5809917511320124e-11, 2.4345153103464099e-10, 1.2063179828327093e-09, 5.5773560719102751e-09, 2.4077676519331747e-08, 9.7119175861531978e-08, 3.6624118990378204e-07, 1.2919701008614705e-06, 4.2657607173255093e-06, 1.3189244631563864e-05, 3.8205770006826046e-05, 1.0373273668170783e-04, 2.6409447862081663e-04, 6.3070332659971552e-04, 1.4134038747122414e-03, 2.9731958710714898e-03, 5.8725347587191210e-03, 1.0894054653347555e-02, 1.8985454327504647e-02, 3.1089543185356148e-02, 4.7846811856586229e-02, 6.9216492829879864e-02, 9.4133897771831843e-02, 1.2036875882166113e-01, 1.4472841947349580e-01, 1.6364277404586250e-01, 1.7400560617482017e-01, 1.7400560617482017e-01, 1.6364277404586250e-01, 1.4472841947349580e-01, 1.2036875882166113e-01, 9.4133897771831843e-02, 6.9216492829879864e-02, 4.7846811856586229e-02, 3.1089543185356148e-02, 1.8985454327504647e-02, 1.0894054653347555e-02, 5.8725347587191210e-03, 2.9731958710714898e-03, 1.4134038747122414e-03, 6.3070332659971552e-04, 2.6409447862081663e-04, 1.0373273668170783e-04, 3.8205770006826046e-05, 1.3189244631563864e-05, 4.2657607173255093e-06, 1.2919701008614705e-06, 3.6624118990378204e-07, 9.7119175861531978e-08, 2.4077676519331747e-08, 5.5773560719102751e-09, 1.2063179828327093e-09, 2.4345153103464099e-10, 4.5809917511320124e-11, 8.0308637715632703e-12, 1.3105682814703333e-12, 1.9891563745557595e-13, 2.8053332193363147e-14, 3.6726238537048878e-15, 4.4585078370462008e-16, 5.0135017597656447e-17, 5.2157884028434802e-18, 5.0139935781581053e-19, 4.4479270726420680e-20, 3.6360647433609545e-21, 2.7350044749786203e-22, 1.8899444794564548e-23, 1.1977696964648504e-24, 6.9494876383385912e-26, 3.6843324819342597e-27, 1.7811808982463465e-28, 7.8353356972027161e-30, 3.1289601063429292e-31, 1.1315067191371783e-32, 3.6955025716069553e-34, 1.0869482703973487e-35, 2.8703150932676095e-37, 6.7826401946708970e-39, 1.4291089046778579e-40, 2.6745508857556167e-42, 4.4272600478065905e-44, 6.4526516804970545e-46, 8.2395121572045278e-48, 9.1677552430019203e-50, 8.8354796635334199e-52, 7.3273399650957289e-54, 5.1910061298697851e-56, 3.1162632356321267e-58, 1.5709872468845785e-60, 6.5836081498721399e-63, 2.2674306256941818e-65, 6.3346915410241234e-68, 1.4143430079239634e-70, 2.4804288326920011e-73, 3.3488181154099359e-76, 3.3987392362121908e-79, 2.5202632570592097e-82, 1.3190436630179440e-85, 4.6684664948676272e-89, 1.0584620865577655e-92, 1.4327597465974048e-96, 1.0530846293412266e-100, 3.6765138012657772e-105, 4.9869144791066677e-110, 1.8880558326632475e-115, 1.0609912453053086e-121, 1.7610777213868225e-129}, {2.5117056700120872e-130, 1.5768344953215994e-122, 2.9044636530400262e-116, 7.9137283674998714e-111, 6.0054708822621273e-106, 1.7679796472043246e-101, 2.4694368635244847e-97, 1.8712284923478763e-93, 8.4595142859097527e-90, 2.4484925972797376e-86, 4.7901098788291739e-83, 6.6115362451933797e-80, 6.6651975922997095e-77, 5.0496259060528478e-74, 2.9443577961646315e-71, 1.3482570840246656e-68, 4.9330325826042063e-66, 1.4638938206976037e-63, 3.5696603658904023e-61, 7.2351735603462302e-59, 1.2313651255661928e-56, 1.7756983991411928e-54, 2.1873288432589287e-52, 2.3183952076674861e-50, 2.1283904185528713e-48, 1.7025628600075561e-46, 1.1931897574643388e-44, 7.3626408195179616e-43, 4.0184547253394729e-41, 1.9480947197049647e-39, 8.4210939788616602e-38, 3.2575341809749061e-36, 1.1313879341749972e-34, 3.5389381244383855e-33, 9.9980778309899927e-32, 2.5579997011243763e-30, 5.9416331503292959e-29, 1.2558645009560268e-27, 2.4207882624773725e-26, 4.2641635772547449e-25, 6.8770962222233684e-24, 1.0173048420715203e-22, 1.3826289575432440e-21, 1.7292550621372860e-20, 1.9932479444365377e-19, 2.1204345027937428e-18, 2.0846204533947437e-17, 1.8963226940193161e-16, 1.5980648038540025e-15, 1.2489882385266198e-14, 9.0627897868794926e-14, 6.1113514542896781e-13, 3.8334734795673616e-12, 2.2387867842316195e-11, 1.2183208011102774e-10, 6.1827585936607041e-10, 2.9281826160122555e-09, 1.2951325071150348e-08, 5.3532512893353530e-08, 2.0690866853712093e-07, 7.4825803592771974e-07, 2.5332274890078433e-06, 8.0328671931181133e-06, 2.3869848947287937e-05, 6.6497705172595715e-05, 1.7374941584438457e-04, 4.2595976788697434e-04, 9.8016363676181151e-04, 2.1176656262735217e-03, 4.2971163011999540e-03, 8.1917798784339399e-03, 1.4674728608435711e-02, 2.4708741311255288e-02, 3.9111739287652818e-02, 5.8212483797557772e-02, 8.1478613249930595e-02, 1.0726183985947185e-01, 1.3282086880025051e-01, 1.5471842089261012e-01, 1.6954985984858575e-01, 1.7480247235206883e-01, 1.6954985984858575e-01, 1.5471842089261012e-01, 1.3282086880025051e-01, 1.0726183985947185e-01, 8.1478613249930595e-02, 5.8212483797557772e-02, 3.9111739287652818e-02, 2.4708741311255288e-02, 1.4674728608435711e-02, 8.1917798784339399e-03, 4.2971163011999540e-03, 2.1176656262735217e-03, 9.8016363676181151e-04, 4.2595976788697434e-04, 1.7374941584438457e-04, 6.6497705172595715e-05, 2.3869848947287937e-05, 8.0328671931181133e-06, 2.5332274890078433e-06, 7.4825803592771974e-07, 2.0690866853712093e-07, 5.3532512893353530e-08, 1.2951325071150348e-08, 2.9281826160122555e-09, 6.1827585936607041e-10, 1.2183208011102774e-10, 2.2387867842316195e-11, 3.8334734795673616e-12, 6.1113514542896781e-13, 9.0627897868794926e-14, 1.2489882385266198e-14, 1.5980648038540025e-15, 1.8963226940193161e-16, 2.0846204533947437e-17, 2.1204345027937428e-18, 1.9932479444365377e-19, 1.7292550621372860e-20, 1.3826289575432440e-21, 1.0173048420715203e-22, 6.8770962222233684e-24, 4.2641635772547449e-25, 2.4207882624773725e-26, 1.2558645009560268e-27, 5.9416331503292959e-29, 2.5579997011243763e-30, 9.9980778309899927e-32, 3.5389381244383855e-33, 1.1313879341749972e-34, 3.2575341809749061e-36, 8.4210939788616602e-38, 1.9480947197049647e-39, 4.0184547253394729e-41, 7.3626408195179616e-43, 1.1931897574643388e-44, 1.7025628600075561e-46, 2.1283904185528713e-48, 2.3183952076674861e-50, 2.1873288432589287e-52, 1.7756983991411928e-54, 1.2313651255661928e-56, 7.2351735603462302e-59, 3.5696603658904023e-61, 1.4638938206976037e-63, 4.9330325826042063e-66, 1.3482570840246656e-68, 2.9443577961646315e-71, 5.0496259060528478e-74, 6.6651975922997095e-77, 6.6115362451933797e-80, 4.7901098788291739e-83, 2.4484925972797376e-86, 8.4595142859097527e-90, 1.8712284923478763e-93, 2.4694368635244847e-97, 1.7679796472043246e-101, 6.0054708822621273e-106, 7.9137283674998714e-111, 2.9044636530400262e-116, 1.5768344953215994e-122, 2.5117056700120872e-130}, {3.5814970887800193e-131, 2.3425513711144864e-123, 4.4656005878580503e-117, 1.2549679546936818e-111, 9.8017329285864726e-107, 2.9653839872557489e-102, 4.2516584957198355e-98, 3.3041628702723710e-94, 1.5309029297604490e-90, 4.5385580031078324e-87, 9.0901963341946014e-84, 1.2839971949179289e-80, 1.3242215741981033e-77, 1.0260459032147593e-74, 6.1171687686353920e-72, 2.8634705175373264e-69, 1.0708169155525760e-66, 3.2473167974844921e-64, 8.0909309792517176e-62, 1.6754390708913517e-59, 2.9129572580930014e-57, 4.2909222783948995e-55, 5.3988684348783699e-53, 5.8447003073435629e-51, 5.4802004204685326e-49, 4.4772141969183521e-47, 3.2045539320239441e-45, 2.0194963974060789e-43, 1.1256982521722169e-41, 5.5735541782797091e-40, 2.4607034140503088e-38, 9.7221219580876439e-37, 3.4489022958731964e-35, 1.1019416508568278e-33, 3.1800971964673699e-32, 8.3116537305566989e-31, 1.9723475111279380e-29, 4.2593300365187824e-28, 8.3889785533018652e-27, 1.5099943444312937e-25, 2.4887063965856610e-24, 3.7625921372478096e-23, 5.2269932699489526e-22, 6.6828358472667806e-21, 7.8752810946470447e-20, 8.5660876502561181e-19, 8.6117182742222153e-18, 8.0118871420831184e-17, 6.9061126848313650e-16, 5.5217099395406411e-15, 4.0993475210626060e-14, 2.8287311125546069e-13, 1.8159956877481757e-12, 1.0856048964794633e-11, 6.0482344698906487e-11, 3.1429016861706717e-10, 1.5244189642430853e-09, 6.9064794339712537e-09, 2.9246755983618971e-08, 1.1583508882541563e-07, 4.2933935551544649e-07, 1.4900490066410718e-06, 4.8446895241968929e-06, 1.4764162429716271e-05, 4.2191721743284952e-05, 1.1311130499099743e-04, 2.8458825008902025e-04, 6.7223242445783719e-04, 1.4912851650067261e-03, 3.1079648052231286e-03, 6.0868070844442837e-03, 1.1205047384266207e-02, 1.9393234478244935e-02, 3.1563859231069517e-02, 4.8318515012084520e-02, 6.9580992429206442e-02, 9.4271602476518737e-02, 1.2018047849522055e-01, 1.4417476260347803e-01, 1.6277076260081147e-01, 1.7294780784506847e-01, 1.7294780784506847e-01, 1.6277076260081147e-01, 1.4417476260347803e-01, 1.2018047849522055e-01, 9.4271602476518737e-02, 6.9580992429206442e-02, 4.8318515012084520e-02, 3.1563859231069517e-02, 1.9393234478244935e-02, 1.1205047384266207e-02, 6.0868070844442837e-03, 3.1079648052231286e-03, 1.4912851650067261e-03, 6.7223242445783719e-04, 2.8458825008902025e-04, 1.1311130499099743e-04, 4.2191721743284952e-05, 1.4764162429716271e-05, 4.8446895241968929e-06, 1.4900490066410718e-06, 4.2933935551544649e-07, 1.1583508882541563e-07, 2.9246755983618971e-08, 6.9064794339712537e-09, 1.5244189642430853e-09, 3.1429016861706717e-10, 6.0482344698906487e-11, 1.0856048964794633e-11, 1.8159956877481757e-12, 2.8287311125546069e-13, 4.0993475210626060e-14, 5.5217099395406411e-15, 6.9061126848313650e-16, 8.0118871420831184e-17, 8.6117182742222153e-18, 8.5660876502561181e-19, 7.8752810946470447e-20, 6.6828358472667806e-21, 5.2269932699489526e-22, 3.7625921372478096e-23, 2.4887063965856610e-24, 1.5099943444312937e-25, 8.3889785533018652e-27, 4.2593300365187824e-28, 1.9723475111279380e-29, 8.3116537305566989e-31, 3.1800971964673699e-32, 1.1019416508568278e-33, 3.4489022958731964e-35, 9.7221219580876439e-37, 2.4607034140503088e-38, 5.5735541782797091e-40, 1.1256982521722169e-41, 2.0194963974060789e-43, 3.2045539320239441e-45, 4.4772141969183521e-47, 5.4802004204685326e-49, 5.8447003073435629e-51, 5.3988684348783699e-53, 4.2909222783948995e-55, 2.9129572580930014e-57, 1.6754390708913517e-59, 8.0909309792517176e-62, 3.2473167974844921e-64, 1.0708169155525760e-66, 2.8634705175373264e-69, 6.1171687686353920e-72, 1.0260459032147593e-74, 1.3242215741981033e-77, 1.2839971949179289e-80, 9.0901963341946014e-84, 4.5385580031078324e-87, 1.5309029297604490e-90, 3.3041628702723710e-94, 4.2516584957198355e-98, 2.9653839872557489e-102, 9.8017329285864726e-107, 1.2549679546936818e-111, 4.4656005878580503e-117, 2.3425513711144864e-123, 3.5814970887800193e-131}, {5.1058382388659269e-132, 3.4787452134261360e-124, 6.8621328476606254e-118, 1.9887929527241800e-112, 1.5984806988768767e-107, 4.9691113060541562e-103, 7.3123967185564915e-99, 5.8275341127995904e-95, 2.7668599413210135e-91, 8.4008516795919007e-88, 1.7224108182682644e-84, 2.4894935837631581e-81, 2.6262929329466987e-78, 2.0809367058140554e-75, 1.2683653376027615e-72, 6.0687062439892660e-70, 2.3192577160038707e-67, 7.1865618890614741e-65, 1.8293638224274986e-62, 3.8697820973543049e-60, 6.8723829518191775e-58, 1.0339639913382959e-55, 1.3286530592326351e-53, 1.4689382904493016e-51, 1.4065458992870208e-49, 1.1734649400073276e-47, 8.5768492248869891e-46, 5.5194857702963127e-44, 3.1417689022491827e-42, 1.5884965434373284e-40, 7.1618254982458697e-39, 2.8896676701682861e-37, 1.0469000850542053e-35, 3.4161633966903074e-34, 1.0069252468038614e-32, 2.6880974156578509e-31, 6.5158094363462302e-30, 1.4374174204375062e-28, 2.8922727144899803e-27, 5.3189806528533866e-26, 8.9574942952228153e-25, 1.3838820621840956e-23, 1.9647377828565719e-22, 2.5674274750397857e-21, 3.0926768131345034e-20, 3.4389885933401063e-19, 3.5348317750763591e-18, 3.3627744521880394e-17, 2.9643952991648909e-16, 2.4242278762902340e-15, 1.8410778220221309e-14, 1.2997777867558265e-13, 8.5384118147611980e-13, 5.2237944008745323e-12, 2.9789583264039043e-11, 1.5847474437596250e-10, 7.8704836352169759e-10, 3.6517281221510981e-09, 1.5839569546032163e-08, 6.4270494029387501e-08, 2.4409702642671850e-07, 8.6823986929119786e-07, 2.8938252044645185e-06, 9.0422158488303162e-06, 2.6500151909252169e-05, 7.2875309659252541e-05, 1.8812470050977485e-04, 4.5604422468456632e-04, 1.0385182654144745e-03, 2.2223166735266457e-03, 4.4700208091087738e-03, 8.4535858780912364e-03, 1.5035066629455310e-02, 2.5153428292907908e-02, 3.9591364280961522e-02, 5.8639320239639699e-02, 8.1738404552485058e-02, 1.0724220730838535e-01, 1.3244982464015054e-01, 1.5399867398459949e-01, 1.6857248411687309e-01, 1.7373006454622800e-01, 1.6857248411687309e-01, 1.5399867398459949e-01, 1.3244982464015054e-01, 1.0724220730838535e-01, 8.1738404552485058e-02, 5.8639320239639699e-02, 3.9591364280961522e-02, 2.5153428292907908e-02, 1.5035066629455310e-02, 8.4535858780912364e-03, 4.4700208091087738e-03, 2.2223166735266457e-03, 1.0385182654144745e-03, 4.5604422468456632e-04, 1.8812470050977485e-04, 7.2875309659252541e-05, 2.6500151909252169e-05, 9.0422158488303162e-06, 2.8938252044645185e-06, 8.6823986929119786e-07, 2.4409702642671850e-07, 6.4270494029387501e-08, 1.5839569546032163e-08, 3.6517281221510981e-09, 7.8704836352169759e-10, 1.5847474437596250e-10, 2.9789583264039043e-11, 5.2237944008745323e-12, 8.5384118147611980e-13, 1.2997777867558265e-13, 1.8410778220221309e-14, 2.4242278762902340e-15, 2.9643952991648909e-16, 3.3627744521880394e-17, 3.5348317750763591e-18, 3.4389885933401063e-19, 3.0926768131345034e-20, 2.5674274750397857e-21, 1.9647377828565719e-22, 1.3838820621840956e-23, 8.9574942952228153e-25, 5.3189806528533866e-26, 2.8922727144899803e-27, 1.4374174204375062e-28, 6.5158094363462302e-30, 2.6880974156578509e-31, 1.0069252468038614e-32, 3.4161633966903074e-34, 1.0469000850542053e-35, 2.8896676701682861e-37, 7.1618254982458697e-39, 1.5884965434373284e-40, 3.1417689022491827e-42, 5.5194857702963127e-44, 8.5768492248869891e-46, 1.1734649400073276e-47, 1.4065458992870208e-49, 1.4689382904493016e-51, 1.3286530592326351e-53, 1.0339639913382959e-55, 6.8723829518191775e-58, 3.8697820973543049e-60, 1.8293638224274986e-62, 7.1865618890614741e-65, 2.3192577160038707e-67, 6.0687062439892660e-70, 1.2683653376027615e-72, 2.0809367058140554e-75, 2.6262929329466987e-78, 2.4894935837631581e-81, 1.7224108182682644e-84, 8.4008516795919007e-88, 2.7668599413210135e-91, 5.8275341127995904e-95, 7.3123967185564915e-99, 4.9691113060541562e-103, 1.5984806988768767e-107, 1.9887929527241800e-112, 6.8621328476606254e-118, 3.4787452134261360e-124, 5.1058382388659269e-132}, {7.2774136808374355e-133, 5.1640253363781065e-125, 1.0539163395229755e-118, 3.1495974864069521e-113, 2.6047400909049849e-108, 8.3190735956096083e-104, 1.2563394260844383e-99, 1.0266029334944310e-95, 4.9942483588606006e-92, 1.5528225080749898e-88, 3.2586916028699435e-85, 4.8189357949651464e-82, 5.1995900683110418e-79, 4.2125456733725475e-76, 2.6247146396219082e-73, 1.2834925357232391e-70, 5.0121772980919659e-68, 1.5867585378958465e-65, 4.1261409970889649e-63, 8.9152934736506373e-61, 1.6170383864591641e-58, 2.4845512749608618e-56, 3.2602867516914131e-54, 3.6806734534292869e-52, 3.5986560950072034e-50, 3.0655422197589668e-48, 2.2877484525825812e-46, 1.5032084002307616e-44, 8.7364621051992394e-43, 4.5101690564191873e-41, 2.0762677615749785e-39, 8.5540504547638604e-38, 3.1645195547118431e-36, 1.0544772050999357e-34, 3.1740376151073218e-33, 8.6536469704170907e-32, 2.1423361912655937e-30, 4.8272033657573108e-29, 9.9214758418835271e-28, 1.8639024742210292e-26, 3.2068221113110570e-25, 5.0619653821736361e-24, 7.3433969692709968e-23, 9.8063138469438635e-22, 1.2072647224673922e-20, 1.3721655943148051e-19, 1.4417902155501092e-18, 1.4022988180739114e-17, 1.2639871956315117e-16, 1.0570613866427036e-15, 8.2106561126223668e-15, 5.9294550957769600e-14, 3.9849788475246675e-13, 2.4946167855672290e-12, 1.4558577681248529e-11, 7.9272325104664409e-11, 4.0303485756427884e-10, 1.9146717079546461e-09, 8.5049436556100333e-09, 3.5346942618254887e-08, 1.3752997102467001e-07, 5.0124990214178011e-07, 1.7121991444326337e-06, 5.4842169146680313e-06, 1.6479308921225968e-05, 4.6474831646589210e-05, 1.2306336370474281e-04, 3.0608156336295680e-04, 7.1531332284984861e-04, 1.5712593917201550e-03, 3.2450562679797843e-03, 6.3028742438160333e-03, 1.1516105006399560e-02, 1.9797989451736150e-02, 3.2031157662458190e-02, 4.8779535009276516e-02, 6.9933221621689870e-02, 9.4399083753525778e-02, 1.1998808778160919e-01, 1.4362587120152381e-01, 1.6191232338499803e-01, 1.7190906682322146e-01, 1.7190906682322146e-01, 1.6191232338499803e-01, 1.4362587120152381e-01, 1.1998808778160919e-01, 9.4399083753525778e-02, 6.9933221621689870e-02, 4.8779535009276516e-02, 3.2031157662458190e-02, 1.9797989451736150e-02, 1.1516105006399560e-02, 6.3028742438160333e-03, 3.2450562679797843e-03, 1.5712593917201550e-03, 7.1531332284984861e-04, 3.0608156336295680e-04, 1.2306336370474281e-04, 4.6474831646589210e-05, 1.6479308921225968e-05, 5.4842169146680313e-06, 1.7121991444326337e-06, 5.0124990214178011e-07, 1.3752997102467001e-07, 3.5346942618254887e-08, 8.5049436556100333e-09, 1.9146717079546461e-09, 4.0303485756427884e-10, 7.9272325104664409e-11, 1.4558577681248529e-11, 2.4946167855672290e-12, 3.9849788475246675e-13, 5.9294550957769600e-14, 8.2106561126223668e-15, 1.0570613866427036e-15, 1.2639871956315117e-16, 1.4022988180739114e-17, 1.4417902155501092e-18, 1.3721655943148051e-19, 1.2072647224673922e-20, 9.8063138469438635e-22, 7.3433969692709968e-23, 5.0619653821736361e-24, 3.2068221113110570e-25, 1.8639024742210292e-26, 9.9214758418835271e-28, 4.8272033657573108e-29, 2.1423361912655937e-30, 8.6536469704170907e-32, 3.1740376151073218e-33, 1.0544772050999357e-34, 3.1645195547118431e-36, 8.5540504547638604e-38, 2.0762677615749785e-39, 4.5101690564191873e-41, 8.7364621051992394e-43, 1.5032084002307616e-44, 2.2877484525825812e-46, 3.0655422197589668e-48, 3.5986560950072034e-50, 3.6806734534292869e-52, 3.2602867516914131e-54, 2.4845512749608618e-56, 1.6170383864591641e-58, 8.9152934736506373e-61, 4.1261409970889649e-63, 1.5867585378958465e-65, 5.0121772980919659e-68, 1.2834925357232391e-70, 2.6247146396219082e-73, 4.2125456733725475e-76, 5.1995900683110418e-79, 4.8189357949651464e-82, 3.2586916028699435e-85, 1.5528225080749898e-88, 4.9942483588606006e-92, 1.0266029334944310e-95, 1.2563394260844383e-99, 8.3190735956096083e-104, 2.6047400909049849e-108, 3.1495974864069521e-113, 1.0539163395229755e-118, 5.1640253363781065e-125, 7.2774136808374355e-133}, {1.0370401330404128e-133, 7.6628104007938171e-126, 1.6177944458582779e-119, 4.9846209741944082e-114, 4.2410903981966999e-109, 1.3914702767711137e-104, 2.1562790735643016e-100, 1.8064249655941844e-96, 9.0033176079341812e-93, 2.8662892545517945e-89, 6.1560200907369249e-86, 9.3130571849846176e-83, 1.0276539331534194e-79, 8.5120283276029899e-77, 5.4209234698248101e-74, 2.7089105182625548e-71, 1.0808323828410104e-68, 3.4954669585711314e-66, 9.2841597125229309e-64, 2.0487495492161133e-61, 3.7947795686740356e-59, 5.9537760035157825e-57, 7.9771959541897771e-55, 9.1949435242106659e-53, 9.1785078949346243e-51, 7.9824553719798949e-49, 6.0817267689790556e-47, 4.0796548388663509e-45, 2.4206136388252030e-43, 1.2757690988603576e-41, 5.9959663570350600e-40, 2.5220557090360086e-38, 9.5260156082741867e-37, 3.2409917090630152e-35, 9.9611495020508274e-34, 2.7731632192036800e-32, 7.0108006530723495e-31, 1.6132689567876035e-29, 3.3864807517869285e-28, 6.4981402796424245e-27, 1.1420079983768409e-25, 1.8415308229503966e-24, 2.7293664944237734e-23, 3.7240665643118182e-22, 4.6849502295754945e-21, 5.4418440370928148e-20, 5.8442290512558873e-19, 5.8103464142089000e-18, 5.3541848627525126e-17, 4.5782053131046985e-16, 3.6364250808804760e-15, 2.6857950742667181e-14, 1.8463211087063347e-13, 1.1824213225107695e-12, 7.0605885367663953e-12, 3.9342842554083200e-11, 2.0472924906259976e-10, 9.9563021167170463e-10, 4.5281139927096718e-09, 1.9271612548094547e-08, 7.6800568196628212e-08, 2.8675127848315921e-07, 1.0036330972927129e-06, 3.2945281705899829e-06, 1.0147672170741122e-05, 2.9341866948530294e-05, 7.9677853191228106e-05, 2.0327512248096151e-04, 4.8739807702018396e-04, 1.0987048493532403e-03, 2.3292137543048106e-03, 4.6450584683976901e-03, 8.7164233107623907e-03, 1.5394018995268760e-02, 2.5593125567577809e-02, 4.0062052918626051e-02, 5.9054458453798808e-02, 8.1986641314913386e-02, 1.0721512879081883e-01, 1.3207899230191014e-01, 1.5328822654091181e-01, 1.6761177530123578e-01, 1.7267715506412973e-01, 1.6761177530123578e-01, 1.5328822654091181e-01, 1.3207899230191014e-01, 1.0721512879081883e-01, 8.1986641314913386e-02, 5.9054458453798808e-02, 4.0062052918626051e-02, 2.5593125567577809e-02, 1.5394018995268760e-02, 8.7164233107623907e-03, 4.6450584683976901e-03, 2.3292137543048106e-03, 1.0987048493532403e-03, 4.8739807702018396e-04, 2.0327512248096151e-04, 7.9677853191228106e-05, 2.9341866948530294e-05, 1.0147672170741122e-05, 3.2945281705899829e-06, 1.0036330972927129e-06, 2.8675127848315921e-07, 7.6800568196628212e-08, 1.9271612548094547e-08, 4.5281139927096718e-09, 9.9563021167170463e-10, 2.0472924906259976e-10, 3.9342842554083200e-11, 7.0605885367663953e-12, 1.1824213225107695e-12, 1.8463211087063347e-13, 2.6857950742667181e-14, 3.6364250808804760e-15, 4.5782053131046985e-16, 5.3541848627525126e-17, 5.8103464142089000e-18, 5.8442290512558873e-19, 5.4418440370928148e-20, 4.6849502295754945e-21, 3.7240665643118182e-22, 2.7293664944237734e-23, 1.8415308229503966e-24, 1.1420079983768409e-25, 6.4981402796424245e-27, 3.3864807517869285e-28, 1.6132689567876035e-29, 7.0108006530723495e-31, 2.7731632192036800e-32, 9.9611495020508274e-34, 3.2409917090630152e-35, 9.5260156082741867e-37, 2.5220557090360086e-38, 5.9959663570350600e-40, 1.2757690988603576e-41, 2.4206136388252030e-43, 4.0796548388663509e-45, 6.0817267689790556e-47, 7.9824553719798949e-49, 9.1785078949346243e-51, 9.1949435242106659e-53, 7.9771959541897771e-55, 5.9537760035157825e-57, 3.7947795686740356e-59, 2.0487495492161133e-61, 9.2841597125229309e-64, 3.4954669585711314e-66, 1.0808323828410104e-68, 2.7089105182625548e-71, 5.4209234698248101e-74, 8.5120283276029899e-77, 1.0276539331534194e-79, 9.3130571849846176e-83, 6.1560200907369249e-86, 2.8662892545517945e-89, 9.0033176079341812e-93, 1.8064249655941844e-96, 2.1562790735643016e-100, 1.3914702767711137e-104, 4.2410903981966999e-109, 4.9846209741944082e-114, 1.6177944458582779e-119, 7.6628104007938171e-126, 1.0370401330404128e-133}, {1.4774864044730919e-134, 1.1366413967312580e-126, 2.4820647345980668e-120, 7.8835864352328026e-115, 6.9000209771443205e-110, 2.3253044708336631e-105, 3.6970767260897540e-101, 3.1749907175216285e-97, 1.6210276225797838e-93, 5.2835329659655297e-90, 1.1612190047837748e-86, 1.7969751555347008e-83, 2.0276116391228268e-80, 1.7168527133451101e-77, 1.1174481216103580e-74, 5.7057155838516782e-72, 2.3257094876339456e-69, 7.6827297329990042e-67, 2.0840476902701378e-64, 4.6963320200403117e-62, 8.8821741614196649e-60, 1.4228297251266947e-57, 1.9462991520350709e-55, 2.2902568991273256e-53, 2.3338081888304624e-51, 2.0719270806826472e-49, 1.6113919045974023e-47, 1.1033912986165171e-45, 6.6828682986466127e-44, 3.5953723054115794e-42, 1.7249314720204933e-40, 7.4065841467302406e-39, 2.8558675123113318e-37, 9.9193674854686742e-36, 3.1125293650397015e-34, 8.8470553643068575e-33, 2.2836747845517017e-31, 5.3659089984759047e-30, 1.1502283587852324e-28, 2.2540053407015112e-27, 4.0457517920854419e-26, 6.6636084030909077e-25, 1.0088605806727544e-23, 1.4062620052335121e-22, 1.8074912939358217e-21, 2.1452843610753105e-20, 2.3544032965183590e-19, 2.3923239898564218e-18, 2.2533431601785240e-17, 1.9696954324441430e-16, 1.5995738956856818e-15, 1.2080546491164034e-14, 8.4930831160690606e-14, 5.5633632513833882e-13, 3.3984267451196722e-12, 1.9374997522123724e-11, 1.0317252591614767e-10, 5.1352562907714339e-10, 2.3907560585436029e-09, 1.0417563656335543e-08, 4.2512972951519652e-08, 1.6257453952247463e-07, 5.8290254892118051e-07, 1.9605333794325452e-06, 6.1886554017466215e-06, 1.8342475402473601e-05, 5.1067234537777706e-05, 1.3360429556693264e-04, 3.2858768305186580e-04, 7.5994560780524184e-04, 1.6532956640381497e-03, 3.3843936084184865e-03, 6.5206132604078895e-03, 1.1827087059306185e-02, 2.0199624381625723e-02, 3.2491469153777909e-02, 4.9230083099421298e-02, 7.0273553473008815e-02, 9.4516761260745735e-02, 1.1979187349505478e-01, 1.4308174026017673e-01, 1.6106711507035643e-01, 1.7088881774276651e-01, 1.7088881774276651e-01, 1.6106711507035643e-01, 1.4308174026017673e-01, 1.1979187349505478e-01, 9.4516761260745735e-02, 7.0273553473008815e-02, 4.9230083099421298e-02, 3.2491469153777909e-02, 2.0199624381625723e-02, 1.1827087059306185e-02, 6.5206132604078895e-03, 3.3843936084184865e-03, 1.6532956640381497e-03, 7.5994560780524184e-04, 3.2858768305186580e-04, 1.3360429556693264e-04, 5.1067234537777706e-05, 1.8342475402473601e-05, 6.1886554017466215e-06, 1.9605333794325452e-06, 5.8290254892118051e-07, 1.6257453952247463e-07, 4.2512972951519652e-08, 1.0417563656335543e-08, 2.3907560585436029e-09, 5.1352562907714339e-10, 1.0317252591614767e-10, 1.9374997522123724e-11, 3.3984267451196722e-12, 5.5633632513833882e-13, 8.4930831160690606e-14, 1.2080546491164034e-14, 1.5995738956856818e-15, 1.9696954324441430e-16, 2.2533431601785240e-17, 2.3923239898564218e-18, 2.3544032965183590e-19, 2.1452843610753105e-20, 1.8074912939358217e-21, 1.4062620052335121e-22, 1.0088605806727544e-23, 6.6636084030909077e-25, 4.0457517920854419e-26, 2.2540053407015112e-27, 1.1502283587852324e-28, 5.3659089984759047e-30, 2.2836747845517017e-31, 8.8470553643068575e-33, 3.1125293650397015e-34, 9.9193674854686742e-36, 2.8558675123113318e-37, 7.4065841467302406e-39, 1.7249314720204933e-40, 3.5953723054115794e-42, 6.6828682986466127e-44, 1.1033912986165171e-45, 1.6113919045974023e-47, 2.0719270806826472e-49, 2.3338081888304624e-51, 2.2902568991273256e-53, 1.9462991520350709e-55, 1.4228297251266947e-57, 8.8821741614196649e-60, 4.6963320200403117e-62, 2.0840476902701378e-64, 7.6827297329990042e-67, 2.3257094876339456e-69, 5.7057155838516782e-72, 1.1174481216103580e-74, 1.7168527133451101e-77, 2.0276116391228268e-80, 1.7969751555347008e-83, 1.1612190047837748e-86, 5.2835329659655297e-90, 1.6210276225797838e-93, 3.1749907175216285e-97, 3.6970767260897540e-101, 2.3253044708336631e-105, 6.9000209771443205e-110, 7.8835864352328026e-115, 2.4820647345980668e-120, 1.1366413967312580e-126, 1.4774864044730919e-134}, {2.1045621159574830e-135, 1.6853736680140806e-127, 3.8060787191717414e-121, 1.2460431717780355e-115, 1.1217254900384875e-110, 3.8823686733906794e-106, 6.3324559268876792e-102, 5.5741078533835752e-98, 2.9150063258205350e-94, 9.7261605479925101e-91, 2.1872204017818973e-87, 3.4618487459964773e-84, 3.9938420292542256e-81, 3.4566329048643892e-78, 2.2990777865226915e-75, 1.1993601521489046e-72, 4.9937669382694245e-70, 1.6848180938195073e-67, 4.6671413158696264e-65, 1.0738850147584223e-62, 2.0736313112573398e-60, 3.3911184321991622e-58, 4.7353070830108189e-56, 5.6878446259603137e-54, 5.9160971507025675e-52, 5.3608992748856614e-50, 4.2554770940703958e-48, 2.9740995846398285e-46, 1.8385123238649587e-44, 1.0095495376276113e-42, 4.9435800520554766e-41, 2.1666198058800618e-39, 8.5272688786829149e-38, 3.0232780766836873e-36, 9.6838410701764544e-35, 2.8099176317436489e-33, 7.4047930191407272e-32, 1.7763620673555590e-30, 3.8878538387006395e-29, 7.7794521016127823e-28, 1.4259174843705503e-26, 2.3985064022625709e-25, 3.7088241471290263e-24, 5.2806166677136793e-23, 6.9334558099800012e-22, 8.4073193071442628e-21, 9.4275495388536763e-20, 9.7888471796527459e-19, 9.4228636835633407e-18, 8.4188202692459649e-17, 6.9888828000995662e-16, 5.3963258195263796e-15, 3.8792170840235010e-14, 2.5986297789613529e-13, 1.6235905955395716e-12, 9.4688541385973895e-12, 5.1587531828242437e-11, 2.6274698033796913e-10, 1.2519243488472937e-09, 5.5840692373466946e-09, 2.3330544086080361e-08, 9.1359564208430839e-08, 3.3548824403388151e-07, 1.1558985161302230e-06, 3.7384592935259604e-06, 1.1355193773739383e-05, 3.2404937824118138e-05, 8.6919300398468442e-05, 2.1921561912382546e-04, 5.2002884998328185e-04, 1.1607090699966350e-03, 2.4383039027033393e-03, 4.8221285878206101e-03, 8.9801569838840641e-03, 1.5751462301844443e-02, 2.6027795319202608e-02, 4.0523924217918790e-02, 5.9458195592787075e-02, 8.2223731723011229e-02, 1.0718097152174927e-01, 1.3170852135471239e-01, 1.5258690288545360e-01, 1.6666726633087006e-01, 1.7164316012362582e-01, 1.6666726633087006e-01, 1.5258690288545360e-01, 1.3170852135471239e-01, 1.0718097152174927e-01, 8.2223731723011229e-02, 5.9458195592787075e-02, 4.0523924217918790e-02, 2.6027795319202608e-02, 1.5751462301844443e-02, 8.9801569838840641e-03, 4.8221285878206101e-03, 2.4383039027033393e-03, 1.1607090699966350e-03, 5.2002884998328185e-04, 2.1921561912382546e-04, 8.6919300398468442e-05, 3.2404937824118138e-05, 1.1355193773739383e-05, 3.7384592935259604e-06, 1.1558985161302230e-06, 3.3548824403388151e-07, 9.1359564208430839e-08, 2.3330544086080361e-08, 5.5840692373466946e-09, 1.2519243488472937e-09, 2.6274698033796913e-10, 5.1587531828242437e-11, 9.4688541385973895e-12, 1.6235905955395716e-12, 2.5986297789613529e-13, 3.8792170840235010e-14, 5.3963258195263796e-15, 6.9888828000995662e-16, 8.4188202692459649e-17, 9.4228636835633407e-18, 9.7888471796527459e-19, 9.4275495388536763e-20, 8.4073193071442628e-21, 6.9334558099800012e-22, 5.2806166677136793e-23, 3.7088241471290263e-24, 2.3985064022625709e-25, 1.4259174843705503e-26, 7.7794521016127823e-28, 3.8878538387006395e-29, 1.7763620673555590e-30, 7.4047930191407272e-32, 2.8099176317436489e-33, 9.6838410701764544e-35, 3.0232780766836873e-36, 8.5272688786829149e-38, 2.1666198058800618e-39, 4.9435800520554766e-41, 1.0095495376276113e-42, 1.8385123238649587e-44, 2.9740995846398285e-46, 4.2554770940703958e-48, 5.3608992748856614e-50, 5.9160971507025675e-52, 5.6878446259603137e-54, 4.7353070830108189e-56, 3.3911184321991622e-58, 2.0736313112573398e-60, 1.0738850147584223e-62, 4.6671413158696264e-65, 1.6848180938195073e-67, 4.9937669382694245e-70, 1.1993601521489046e-72, 2.2990777865226915e-75, 3.4566329048643892e-78, 3.9938420292542256e-81, 3.4618487459964773e-84, 2.1872204017818973e-87, 9.7261605479925101e-91, 2.9150063258205350e-94, 5.5741078533835752e-98, 6.3324559268876792e-102, 3.8823686733906794e-106, 1.1217254900384875e-110, 1.2460431717780355e-115, 3.8060787191717414e-121, 1.6853736680140806e-127, 2.1045621159574830e-135}, {2.9971690491012730e-136, 2.4980891398206762e-128, 5.8333713614299987e-122, 1.9681709423933214e-116, 1.8221727762675135e-111, 6.4763280099261484e-107, 1.0835544161526790e-102, 9.7751589620462579e-99, 5.2354686514639054e-95, 1.7880404661796150e-91, 4.1137899834361915e-88, 6.6588269447352457e-85, 7.8536797447719853e-82, 6.9470795412027442e-79, 4.7212966724403236e-76, 2.5160708333635340e-73, 1.0700081200070465e-70, 3.6866210764241453e-68, 1.0427591853094809e-65, 2.4496158809944983e-63, 4.8287654459243867e-61, 8.0607602578177551e-59, 1.1488941335553380e-56, 1.4084920383852964e-54, 1.4951953571335084e-52, 1.3827452604659908e-50, 1.1201727218381219e-48, 7.9894861866156147e-47, 5.0402806679659781e-45, 2.8245056542381498e-43, 1.4115238161648369e-41, 6.3134908835445427e-40, 2.5359952829354267e-38, 9.1766156441607901e-37, 3.0000961317861622e-35, 8.8855426938068462e-34, 2.3901684056219713e-32, 5.8532507898005387e-31, 1.3078348727191383e-29, 2.6717694287109624e-28, 5.0001529132188371e-27, 8.5882149512444349e-26, 1.3561502945339099e-24, 1.9719885628376035e-23, 2.6445905466631306e-22, 3.2756544281813711e-21, 3.7524614126630812e-20, 3.9808239456321635e-19, 3.9155933049886526e-18, 3.5751188594220651e-17, 3.0333673764885698e-16, 2.3941367575799993e-15, 1.7594869510962716e-14, 1.2051394761470136e-13, 7.6998498930386894e-13, 4.5928264710545402e-12, 2.5595903423630225e-11, 1.3337516615570700e-10, 6.5027567060176707e-10, 2.9684197043117582e-09, 1.2694911467897228e-08, 5.0894009383117858e-08, 1.9137169385842292e-07, 6.7528978068278956e-07, 2.2372679339319808e-06, 6.9624497238718160e-06, 2.0361547224732169e-05, 5.5980964406792492e-05, 1.4474894898356766e-04, 3.5211870018385556e-04, 8.0612713585123284e-04, 1.7373614851938118e-03, 3.5259000508765289e-03, 6.7399040525805923e-03, 1.2137859543972172e-02, 2.0598052684982535e-02, 3.2944830178350461e-02, 4.9670368744572549e-02, 7.0602349240131604e-02, 9.4625036098936688e-02, 1.1959210591508003e-01, 1.4254236006576013e-01, 1.6023480790396424e-01, 1.6988651844048314e-01, 1.6988651844048314e-01, 1.6023480790396424e-01, 1.4254236006576013e-01, 1.1959210591508003e-01, 9.4625036098936688e-02, 7.0602349240131604e-02, 4.9670368744572549e-02, 3.2944830178350461e-02, 2.0598052684982535e-02, 1.2137859543972172e-02, 6.7399040525805923e-03, 3.5259000508765289e-03, 1.7373614851938118e-03, 8.0612713585123284e-04, 3.5211870018385556e-04, 1.4474894898356766e-04, 5.5980964406792492e-05, 2.0361547224732169e-05, 6.9624497238718160e-06, 2.2372679339319808e-06, 6.7528978068278956e-07, 1.9137169385842292e-07, 5.0894009383117858e-08, 1.2694911467897228e-08, 2.9684197043117582e-09, 6.5027567060176707e-10, 1.3337516615570700e-10, 2.5595903423630225e-11, 4.5928264710545402e-12, 7.6998498930386894e-13, 1.2051394761470136e-13, 1.7594869510962716e-14, 2.3941367575799993e-15, 3.0333673764885698e-16, 3.5751188594220651e-17, 3.9155933049886526e-18, 3.9808239456321635e-19, 3.7524614126630812e-20, 3.2756544281813711e-21, 2.6445905466631306e-22, 1.9719885628376035e-23, 1.3561502945339099e-24, 8.5882149512444349e-26, 5.0001529132188371e-27, 2.6717694287109624e-28, 1.3078348727191383e-29, 5.8532507898005387e-31, 2.3901684056219713e-32, 8.8855426938068462e-34, 3.0000961317861622e-35, 9.1766156441607901e-37, 2.5359952829354267e-38, 6.3134908835445427e-40, 1.4115238161648369e-41, 2.8245056542381498e-43, 5.0402806679659781e-45, 7.9894861866156147e-47, 1.1201727218381219e-48, 1.3827452604659908e-50, 1.4951953571335084e-52, 1.4084920383852964e-54, 1.1488941335553380e-56, 8.0607602578177551e-59, 4.8287654459243867e-61, 2.4496158809944983e-63, 1.0427591853094809e-65, 3.6866210764241453e-68, 1.0700081200070465e-70, 2.5160708333635340e-73, 4.7212966724403236e-76, 6.9470795412027442e-79, 7.8536797447719853e-82, 6.6588269447352457e-85, 4.1137899834361915e-88, 1.7880404661796150e-91, 5.2354686514639054e-95, 9.7751589620462579e-99, 1.0835544161526790e-102, 6.4763280099261484e-107, 1.8221727762675135e-111, 1.9681709423933214e-116, 5.8333713614299987e-122, 2.4980891398206762e-128, 2.9971690491012730e-136}, {4.2674931553342203e-137, 3.7013509844210040e-129, 8.9359543576021383e-123, 3.1068184196664260e-117, 2.9577586950025811e-112, 1.0793940202510381e-107, 1.8522459789363982e-103, 1.7123515642355668e-99, 9.3917005928096861e-96, 3.2827539517233995e-92, 7.7262644929909970e-89, 1.2788460726412831e-85, 1.5418407850274678e-82, 1.3937615371156682e-79, 9.6774116872500576e-77, 5.2679228724311439e-74, 2.2879261623118261e-71, 8.0492001695776603e-69, 2.3244392181338319e-66, 5.5743129455028007e-64, 1.1216194835766520e-61, 1.9110201175931197e-59, 2.7798349876894280e-57, 3.4779129275742834e-55, 3.7676299883874885e-53, 3.5555263388415704e-51, 2.9391917507565755e-49, 2.1391283000208420e-47, 1.3770363396814081e-45, 7.8742105891358037e-44, 4.0154223770167576e-42, 1.8327311167318893e-40, 7.5123280800309780e-39, 2.7740812006389936e-37, 9.2554744703184908e-36, 2.7976499634157274e-34, 7.6807810254033586e-33, 1.9198421026192681e-31, 4.3786397679911876e-30, 9.1312863995714357e-29, 1.7445924812851179e-27, 3.0593178878006020e-26, 4.9326008142373812e-25, 7.3241393698795336e-24, 1.0030774102469258e-22, 1.2689360428385754e-21, 1.4847983173617774e-20, 1.6090879587826797e-19, 1.6169926387796005e-18, 1.5085327113052835e-17, 1.3079623075775175e-16, 1.0550654299237249e-15, 7.9256160807813284e-15, 5.5495687412198589e-14, 3.6252638108375508e-13, 2.2112377011770522e-12, 1.2603426258460018e-11, 6.7177337738006964e-11, 3.3507655233538448e-10, 1.5650990540810345e-09, 6.8499863308168436e-09, 2.8109038530404097e-08, 1.0820676942101237e-07, 3.9097121047484011e-07, 1.3265796796150300e-06, 4.2288616562734994e-06, 1.2670859378200327e-05, 3.5699320251985919e-05, 9.4613317406319364e-05, 2.3596028278015030e-04, 5.5394259248142631e-04, 1.2245148633746915e-03, 2.5495331679026910e-03, 5.0011317639987000e-03, 9.2446564129297221e-03, 1.6107280751087583e-02, 2.6457407162359760e-02, 4.0977099534106338e-02, 5.9850822005640535e-02, 8.2450068298432835e-02, 1.0714008439362262e-01, 1.3133855013394508e-01, 1.5189453076872492e-01, 1.6573850820195182e-01, 1.7062752012289428e-01, 1.6573850820195182e-01, 1.5189453076872492e-01, 1.3133855013394508e-01, 1.0714008439362262e-01, 8.2450068298432835e-02, 5.9850822005640535e-02, 4.0977099534106338e-02, 2.6457407162359760e-02, 1.6107280751087583e-02, 9.2446564129297221e-03, 5.0011317639987000e-03, 2.5495331679026910e-03, 1.2245148633746915e-03, 5.5394259248142631e-04, 2.3596028278015030e-04, 9.4613317406319364e-05, 3.5699320251985919e-05, 1.2670859378200327e-05, 4.2288616562734994e-06, 1.3265796796150300e-06, 3.9097121047484011e-07, 1.0820676942101237e-07, 2.8109038530404097e-08, 6.8499863308168436e-09, 1.5650990540810345e-09, 3.3507655233538448e-10, 6.7177337738006964e-11, 1.2603426258460018e-11, 2.2112377011770522e-12, 3.6252638108375508e-13, 5.5495687412198589e-14, 7.9256160807813284e-15, 1.0550654299237249e-15, 1.3079623075775175e-16, 1.5085327113052835e-17, 1.6169926387796005e-18, 1.6090879587826797e-19, 1.4847983173617774e-20, 1.2689360428385754e-21, 1.0030774102469258e-22, 7.3241393698795336e-24, 4.9326008142373812e-25, 3.0593178878006020e-26, 1.7445924812851179e-27, 9.1312863995714357e-29, 4.3786397679911876e-30, 1.9198421026192681e-31, 7.6807810254033586e-33, 2.7976499634157274e-34, 9.2554744703184908e-36, 2.7740812006389936e-37, 7.5123280800309780e-39, 1.8327311167318893e-40, 4.0154223770167576e-42, 7.8742105891358037e-44, 1.3770363396814081e-45, 2.1391283000208420e-47, 2.9391917507565755e-49, 3.5555263388415704e-51, 3.7676299883874885e-53, 3.4779129275742834e-55, 2.7798349876894280e-57, 1.9110201175931197e-59, 1.1216194835766520e-61, 5.5743129455028007e-64, 2.3244392181338319e-66, 8.0492001695776603e-69, 2.2879261623118261e-71, 5.2679228724311439e-74, 9.6774116872500576e-77, 1.3937615371156682e-79, 1.5418407850274678e-82, 1.2788460726412831e-85, 7.7262644929909970e-89, 3.2827539517233995e-92, 9.3917005928096861e-96, 1.7123515642355668e-99, 1.8522459789363982e-103, 1.0793940202510381e-107, 2.9577586950025811e-112, 3.1068184196664260e-117, 8.9359543576021383e-123, 3.7013509844210040e-129, 4.2674931553342203e-137}, {6.0750158130606195e-138, 5.4821992024733287e-130, 1.3681822165982846e-123, 4.9011169950359405e-118, 4.7974396933811439e-113, 1.7974392277078273e-108, 3.1631548152333414e-104, 2.9963165563522804e-100, 1.6827169561417482e-96, 6.0190850814126162e-93, 1.4490438595507066e-89, 2.4523185664718153e-86, 3.0220219471047618e-83, 2.7913874973199548e-80, 1.9799592744971097e-77, 1.1008005267477927e-74, 4.8820589020655159e-72, 1.7536229837285863e-69, 5.1696909850843693e-67, 1.2654633658209892e-64, 2.5987959219621812e-62, 4.5188057419567269e-60, 6.7077790006444227e-58, 8.5635704641083388e-56, 9.4658821709007862e-54, 9.1146156997272630e-52, 7.6876441303763667e-50, 5.7085575439180572e-48, 3.7493520841061347e-46, 2.1874580274727376e-44, 1.1381244408182845e-42, 5.3001743821412355e-41, 2.2167101442428974e-39, 8.3523638615101674e-38, 2.8435471995138850e-36, 8.7709151746020293e-35, 2.4573526663074424e-33, 6.2684680341301147e-32, 1.4591317861612538e-30, 3.1058077266730593e-29, 6.0569508661768345e-28, 1.0842625724312578e-26, 1.7847202502838671e-25, 2.7056507791212747e-24, 3.7836354660151275e-23, 4.8878185643771254e-22, 5.8409861850177518e-21, 6.4652715404585129e-20, 6.6366701688022747e-19, 6.3252994285961157e-18, 5.6034658987730242e-17, 4.6187988803389262e-16, 3.5458950811944735e-15, 2.5377705512106429e-14, 1.6946972716989475e-13, 1.0568382827043380e-12, 6.1595020440963285e-12, 3.3576005591117169e-11, 1.7130382466099029e-10, 8.1856149500888656e-10, 3.6657050674739318e-09, 1.5393813958417279e-08, 6.0654560255829627e-08, 2.2435783940914669e-07, 7.7946793854749263e-07, 2.5447213452537048e-06, 7.8101702177205490e-06, 2.2544487920551540e-05, 6.1227929783044720e-05, 1.5651161607055494e-04, 3.7668553922014524e-04, 8.5385410230442147e-04, 1.8234228920144958e-03, 3.6694988559735154e-03, 6.9606294949961902e-03, 1.2448294747794275e-02, 2.0993195618512490e-02, 3.3391282475767885e-02, 5.0100599356951693e-02, 7.0919958702876942e-02, 9.4724291720265918e-02, 1.1938903980933140e-01, 1.4200771666714165e-01, 1.5941508322714990e-01, 1.6890164874640598e-01, 1.6890164874640598e-01, 1.5941508322714990e-01, 1.4200771666714165e-01, 1.1938903980933140e-01, 9.4724291720265918e-02, 7.0919958702876942e-02, 5.0100599356951693e-02, 3.3391282475767885e-02, 2.0993195618512490e-02, 1.2448294747794275e-02, 6.9606294949961902e-03, 3.6694988559735154e-03, 1.8234228920144958e-03, 8.5385410230442147e-04, 3.7668553922014524e-04, 1.5651161607055494e-04, 6.1227929783044720e-05, 2.2544487920551540e-05, 7.8101702177205490e-06, 2.5447213452537048e-06, 7.7946793854749263e-07, 2.2435783940914669e-07, 6.0654560255829627e-08, 1.5393813958417279e-08, 3.6657050674739318e-09, 8.1856149500888656e-10, 1.7130382466099029e-10, 3.3576005591117169e-11, 6.1595020440963285e-12, 1.0568382827043380e-12, 1.6946972716989475e-13, 2.5377705512106429e-14, 3.5458950811944735e-15, 4.6187988803389262e-16, 5.6034658987730242e-17, 6.3252994285961157e-18, 6.6366701688022747e-19, 6.4652715404585129e-20, 5.8409861850177518e-21, 4.8878185643771254e-22, 3.7836354660151275e-23, 2.7056507791212747e-24, 1.7847202502838671e-25, 1.0842625724312578e-26, 6.0569508661768345e-28, 3.1058077266730593e-29, 1.4591317861612538e-30, 6.2684680341301147e-32, 2.4573526663074424e-33, 8.7709151746020293e-35, 2.8435471995138850e-36, 8.3523638615101674e-38, 2.2167101442428974e-39, 5.3001743821412355e-41, 1.1381244408182845e-42, 2.1874580274727376e-44, 3.7493520841061347e-46, 5.7085575439180572e-48, 7.6876441303763667e-50, 9.1146156997272630e-52, 9.4658821709007862e-54, 8.5635704641083388e-56, 6.7077790006444227e-58, 4.5188057419567269e-60, 2.5987959219621812e-62, 1.2654633658209892e-64, 5.1696909850843693e-67, 1.7536229837285863e-69, 4.8820589020655159e-72, 1.1008005267477927e-74, 1.9799592744971097e-77, 2.7913874973199548e-80, 3.0220219471047618e-83, 2.4523185664718153e-86, 1.4490438595507066e-89, 6.0190850814126162e-93, 1.6827169561417482e-96, 2.9963165563522804e-100, 3.1631548152333414e-104, 1.7974392277078273e-108, 4.7974396933811439e-113, 4.9011169950359405e-118, 1.3681822165982846e-123, 5.4821992024733287e-130, 6.0750158130606195e-138}, {8.6464098495106045e-139, 8.1169547967150641e-131, 2.0937788694250258e-124, 7.7268624062801043e-119, 7.7755878030242305e-114, 2.9905793066209871e-109, 5.3966031917331080e-105, 5.2373672835160608e-101, 3.0113519152678094e-97, 1.1021983838887256e-93, 2.7138416423119788e-90, 4.6954865769208796e-87, 5.9136418179343394e-84, 5.5809142352163536e-81, 4.0435337904295643e-78, 2.2958300915077279e-75, 1.0396325878228644e-72, 3.8123200620819477e-70, 1.1471867481155006e-67, 2.8660528596806035e-65, 6.0065917977528455e-63, 1.0657711610182893e-60, 1.6142564784909037e-58, 2.1026978884308611e-56, 2.3713251069838819e-54, 2.3294898984397351e-52, 2.0044580918502007e-50, 1.5184626573152095e-48, 1.0174299157427975e-46, 6.0556195147012746e-45, 3.2142710908365357e-43, 1.5270851777984907e-41, 6.5158604619910054e-40, 2.5048070243067333e-38, 8.7004606571271586e-37, 2.7381749245865647e-35, 7.8277738587896100e-34, 2.0375540992709603e-32, 4.8399847326203970e-31, 1.0513633818680897e-29, 2.0926202706959383e-28, 3.8234939104131151e-27, 6.4242027780709820e-26, 9.9421354277925673e-25, 1.4194294864852321e-23, 1.8722162613285435e-22, 2.2845745768934510e-21, 2.5824265914439110e-20, 2.7074430614342264e-19, 2.6357601492491789e-18, 2.3853221384019439e-17, 2.0087998156976881e-16, 1.5758126400353855e-15, 1.1525451076836792e-14, 7.8665152475648879e-14, 5.0146808941799565e-13, 2.9880423319270495e-12, 1.6654840593814865e-11, 8.6899012302376471e-11, 4.2472082249711324e-10, 1.9457386067825712e-09, 8.3602716973645751e-09, 3.3710054470838133e-08, 1.2762506765080952e-07, 4.5391122547936338e-07, 1.5173031250618367e-06, 4.7690949847434419e-06, 1.4100857760918970e-05, 3.9234961307384339e-05, 1.0277324714018339e-04, 2.5352235086933272e-04, 5.8914391280362889e-04, 1.2901045250613646e-03, 2.6628467710093206e-03, 5.1819700035925865e-03, 9.5097957728564348e-03, 1.6461365836824633e-02, 2.6881937632071830e-02, 4.1421702134247403e-02, 6.0232621258249110e-02, 8.2666028537237118e-02, 1.0709279898985245e-01, 1.3096920653341185e-01, 1.5121094137038713e-01, 1.6482506909185640e-01, 1.6962969836778974e-01, 1.6482506909185640e-01, 1.5121094137038713e-01, 1.3096920653341185e-01, 1.0709279898985245e-01, 8.2666028537237118e-02, 6.0232621258249110e-02, 4.1421702134247403e-02, 2.6881937632071830e-02, 1.6461365836824633e-02, 9.5097957728564348e-03, 5.1819700035925865e-03, 2.6628467710093206e-03, 1.2901045250613646e-03, 5.8914391280362889e-04, 2.5352235086933272e-04, 1.0277324714018339e-04, 3.9234961307384339e-05, 1.4100857760918970e-05, 4.7690949847434419e-06, 1.5173031250618367e-06, 4.5391122547936338e-07, 1.2762506765080952e-07, 3.3710054470838133e-08, 8.3602716973645751e-09, 1.9457386067825712e-09, 4.2472082249711324e-10, 8.6899012302376471e-11, 1.6654840593814865e-11, 2.9880423319270495e-12, 5.0146808941799565e-13, 7.8665152475648879e-14, 1.1525451076836792e-14, 1.5758126400353855e-15, 2.0087998156976881e-16, 2.3853221384019439e-17, 2.6357601492491789e-18, 2.7074430614342264e-19, 2.5824265914439110e-20, 2.2845745768934510e-21, 1.8722162613285435e-22, 1.4194294864852321e-23, 9.9421354277925673e-25, 6.4242027780709820e-26, 3.8234939104131151e-27, 2.0926202706959383e-28, 1.0513633818680897e-29, 4.8399847326203970e-31, 2.0375540992709603e-32, 7.8277738587896100e-34, 2.7381749245865647e-35, 8.7004606571271586e-37, 2.5048070243067333e-38, 6.5158604619910054e-40, 1.5270851777984907e-41, 3.2142710908365357e-43, 6.0556195147012746e-45, 1.0174299157427975e-46, 1.5184626573152095e-48, 2.0044580918502007e-50, 2.3294898984397351e-52, 2.3713251069838819e-54, 2.1026978884308611e-56, 1.6142564784909037e-58, 1.0657711610182893e-60, 6.0065917977528455e-63, 2.8660528596806035e-65, 1.1471867481155006e-67, 3.8123200620819477e-70, 1.0396325878228644e-72, 2.2958300915077279e-75, 4.0435337904295643e-78, 5.5809142352163536e-81, 5.9136418179343394e-84, 4.6954865769208796e-87, 2.7138416423119788e-90, 1.1021983838887256e-93, 3.0113519152678094e-97, 5.2373672835160608e-101, 5.3966031917331080e-105, 2.9905793066209871e-109, 7.7755878030242305e-114, 7.7268624062801043e-119, 2.0937788694250258e-124, 8.1169547967150641e-131, 8.6464098495106045e-139}, {1.2303789814620092e-139, 1.2013699333289992e-131, 3.2026074548384006e-125, 1.2174269794916373e-119, 1.2593229738553804e-114, 4.9714964520806193e-110, 9.1982052962411378e-106, 9.1447911140134055e-102, 5.3827092462530275e-98, 2.0157286790487118e-94, 5.0755707227503414e-91, 8.9771058574961900e-88, 1.1553649373808784e-84, 1.1139151556417037e-81, 8.2429409894791420e-79, 4.7790526311204645e-76, 2.2094400576899919e-73, 8.2703192545553517e-71, 2.5400223834270154e-68, 6.4759951809357819e-66, 1.3849218619189611e-63, 2.5072557278333359e-61, 3.8744806525565368e-59, 5.1487100357555966e-57, 5.9234211353878837e-55, 5.9358962183919884e-53, 5.2102035909462387e-51, 4.0261165631274628e-49, 2.7517389408826910e-47, 1.6706338169898752e-45, 9.0454023907569489e-44, 4.3836632815273276e-42, 1.9080203924026029e-40, 7.4822875434667983e-39, 2.6513404940738975e-37, 8.5126426420369604e-36, 2.4827942651601884e-34, 6.5937510349118087e-33, 1.5981308016388612e-31, 3.5423572866413238e-30, 7.1949797524882649e-29, 1.3416207816913450e-27, 2.3006552131922817e-26, 3.6342070015972533e-25, 5.2963698057770957e-24, 7.1317120414745996e-23, 8.8849961119116762e-22, 1.0255026540751254e-20, 1.0979177006155230e-19, 1.0916029509464340e-18, 1.0090271979231116e-17, 8.6804078056359369e-17, 6.9567797833146074e-16, 5.1989584985238723e-15, 3.6262025536343989e-14, 2.3625593061240154e-13, 1.4389854608144821e-12, 8.1997932243736651e-12, 4.3745620487604465e-11, 2.1864887185791365e-10, 1.0245209689572339e-09, 4.5031898910426613e-09, 1.8577866622072818e-08, 7.1975399855994780e-08, 2.6200414925731448e-07, 8.9655811991941417e-07, 2.8853130691641410e-06, 8.7365058018499081e-06, 2.4899323348910079e-05, 6.6819890242436042e-05, 1.6890601339725517e-04, 4.0229796846567709e-04, 9.0312111074868030e-04, 1.9114445894976445e-03, 3.8151134691487313e-03, 7.1826754657021994e-03, 1.2758271065775782e-02, 2.1384981853074116e-02, 3.3830872556682462e-02, 5.0520980072118506e-02, 7.1226720494510898e-02, 9.4814894788900164e-02, 1.1918291538647637e-01, 1.4147779230279267e-01, 1.5860763301741698e-01, 1.6793370935002905e-01, 1.6793370935002905e-01, 1.5860763301741698e-01, 1.4147779230279267e-01, 1.1918291538647637e-01, 9.4814894788900164e-02, 7.1226720494510898e-02, 5.0520980072118506e-02, 3.3830872556682462e-02, 2.1384981853074116e-02, 1.2758271065775782e-02, 7.1826754657021994e-03, 3.8151134691487313e-03, 1.9114445894976445e-03, 9.0312111074868030e-04, 4.0229796846567709e-04, 1.6890601339725517e-04, 6.6819890242436042e-05, 2.4899323348910079e-05, 8.7365058018499081e-06, 2.8853130691641410e-06, 8.9655811991941417e-07, 2.6200414925731448e-07, 7.1975399855994780e-08, 1.8577866622072818e-08, 4.5031898910426613e-09, 1.0245209689572339e-09, 2.1864887185791365e-10, 4.3745620487604465e-11, 8.1997932243736651e-12, 1.4389854608144821e-12, 2.3625593061240154e-13, 3.6262025536343989e-14, 5.1989584985238723e-15, 6.9567797833146074e-16, 8.6804078056359369e-17, 1.0090271979231116e-17, 1.0916029509464340e-18, 1.0979177006155230e-19, 1.0255026540751254e-20, 8.8849961119116762e-22, 7.1317120414745996e-23, 5.2963698057770957e-24, 3.6342070015972533e-25, 2.3006552131922817e-26, 1.3416207816913450e-27, 7.1949797524882649e-29, 3.5423572866413238e-30, 1.5981308016388612e-31, 6.5937510349118087e-33, 2.4827942651601884e-34, 8.5126426420369604e-36, 2.6513404940738975e-37, 7.4822875434667983e-39, 1.9080203924026029e-40, 4.3836632815273276e-42, 9.0454023907569489e-44, 1.6706338169898752e-45, 2.7517389408826910e-47, 4.0261165631274628e-49, 5.2102035909462387e-51, 5.9358962183919884e-53, 5.9234211353878837e-55, 5.1487100357555966e-57, 3.8744806525565368e-59, 2.5072557278333359e-61, 1.3849218619189611e-63, 6.4759951809357819e-66, 2.5400223834270154e-68, 8.2703192545553517e-71, 2.2094400576899919e-73, 4.7790526311204645e-76, 8.2429409894791420e-79, 1.1139151556417037e-81, 1.1553649373808784e-84, 8.9771058574961900e-88, 5.0755707227503414e-91, 2.0157286790487118e-94, 5.3827092462530275e-98, 9.1447911140134055e-102, 9.1982052962411378e-106, 4.9714964520806193e-110, 1.2593229738553804e-114, 1.2174269794916373e-119, 3.2026074548384006e-125, 1.2013699333289992e-131, 1.2303789814620092e-139}, {1.7504813313443110e-140, 1.7774902414670824e-132, 4.8962631916290320e-126, 1.9169773412509448e-120, 2.0380950317636651e-115, 8.2575913221058373e-111, 1.5662913179616934e-106, 1.5950515939148060e-102, 9.6102475509992629e-99, 3.6817405361106414e-95, 9.4795771929584613e-92, 1.7137636253252277e-88, 2.2537069207131266e-85, 2.2195670363270061e-82, 1.6773665243938764e-79, 9.9294168393320748e-77, 4.6861855398798507e-74, 1.7903790379405142e-71, 5.6115831515377673e-69, 1.4599152900352242e-66, 3.1854832448751424e-64, 5.8835568128153365e-62, 9.2750122555037185e-60, 1.2572829274411131e-57, 1.4754337744917936e-55, 1.5080977336171035e-53, 1.3501492314506362e-51, 1.0641162728147897e-49, 7.4179019446614824e-48, 4.5933036667242678e-46, 2.5365532103719637e-44, 1.2538070457653651e-42, 5.5662423908008861e-41, 2.2264349328620495e-39, 8.0473188469528885e-38, 2.6355807192340085e-36, 7.8414692242533960e-35, 2.1244914229476255e-33, 5.2531973592621732e-32, 1.1880047374923401e-30, 2.4620531629619134e-29, 4.6845665497518896e-28, 8.1977521328279625e-27, 1.3215706261902287e-25, 1.9657684577473083e-24, 2.7018364834425692e-23, 3.4361611658856167e-22, 4.0489821139593706e-21, 4.4260400812843420e-20, 4.4935788616135659e-19, 4.2418977594565075e-18, 3.7271474634420088e-17, 3.0512318816558229e-16, 2.3295237031463167e-15, 1.6601293173811213e-14, 1.1052712006706022e-13, 6.8801511055288008e-13, 4.0073848073937339e-12, 2.1856088643011424e-11, 1.1169403547356809e-10, 5.3519948055672733e-10, 2.4060047025435626e-09, 1.0153711719361421e-08, 4.0247544813147544e-08, 1.4992205080398724e-07, 5.2506826823537642e-07, 1.7297783253854633e-06, 5.3626317222650889e-06, 1.5651476474775071e-05, 4.3021779350373374e-05, 1.1141208654585957e-04, 2.7191419917337988e-04, 6.2563601676209426e-04, 1.3574588134771591e-03, 2.7781892530593399e-03, 5.3645468312921761e-03, 9.7754538393799058e-03, 1.6813616037549516e-02, 2.7301369702544091e-02, 4.1857856809001823e-02, 6.0603870172343872e-02, 8.2871975523587077e-02, 1.0703943053616907e-01, 1.3060060873789656e-01, 1.5053596929119434e-01, 1.6392653352569631e-01, 1.6864917988011466e-01, 1.6392653352569631e-01, 1.5053596929119434e-01, 1.3060060873789656e-01, 1.0703943053616907e-01, 8.2871975523587077e-02, 6.0603870172343872e-02, 4.1857856809001823e-02, 2.7301369702544091e-02, 1.6813616037549516e-02, 9.7754538393799058e-03, 5.3645468312921761e-03, 2.7781892530593399e-03, 1.3574588134771591e-03, 6.2563601676209426e-04, 2.7191419917337988e-04, 1.1141208654585957e-04, 4.3021779350373374e-05, 1.5651476474775071e-05, 5.3626317222650889e-06, 1.7297783253854633e-06, 5.2506826823537642e-07, 1.4992205080398724e-07, 4.0247544813147544e-08, 1.0153711719361421e-08, 2.4060047025435626e-09, 5.3519948055672733e-10, 1.1169403547356809e-10, 2.1856088643011424e-11, 4.0073848073937339e-12, 6.8801511055288008e-13, 1.1052712006706022e-13, 1.6601293173811213e-14, 2.3295237031463167e-15, 3.0512318816558229e-16, 3.7271474634420088e-17, 4.2418977594565075e-18, 4.4935788616135659e-19, 4.4260400812843420e-20, 4.0489821139593706e-21, 3.4361611658856167e-22, 2.7018364834425692e-23, 1.9657684577473083e-24, 1.3215706261902287e-25, 8.1977521328279625e-27, 4.6845665497518896e-28, 2.4620531629619134e-29, 1.1880047374923401e-30, 5.2531973592621732e-32, 2.1244914229476255e-33, 7.8414692242533960e-35, 2.6355807192340085e-36, 8.0473188469528885e-38, 2.2264349328620495e-39, 5.5662423908008861e-41, 1.2538070457653651e-42, 2.5365532103719637e-44, 4.5933036667242678e-46, 7.4179019446614824e-48, 1.0641162728147897e-49, 1.3501492314506362e-51, 1.5080977336171035e-53, 1.4754337744917936e-55, 1.2572829274411131e-57, 9.2750122555037185e-60, 5.8835568128153365e-62, 3.1854832448751424e-64, 1.4599152900352242e-66, 5.6115831515377673e-69, 1.7903790379405142e-71, 4.6861855398798507e-74, 9.9294168393320748e-77, 1.6773665243938764e-79, 2.2195670363270061e-82, 2.2537069207131266e-85, 1.7137636253252277e-88, 9.4795771929584613e-92, 3.6817405361106414e-95, 9.6102475509992629e-99, 1.5950515939148060e-102, 1.5662913179616934e-106, 8.2575913221058373e-111, 2.0380950317636651e-115, 1.9169773412509448e-120, 4.8962631916290320e-126, 1.7774902414670824e-132, 1.7504813313443110e-140}, {2.4899600964326729e-141, 2.6289723724457029e-133, 7.4819712112270593e-127, 3.0166712841087998e-121, 3.2960842775717504e-116, 1.3704328437984587e-111, 2.6646059822111242e-107, 2.7792048294771247e-103, 1.7138296773072837e-99, 6.7162796391421331e-96, 1.7680841960979503e-92, 3.2668637275061076e-89, 4.3893173430676675e-86, 4.4153132623096831e-83, 3.4072707861884866e-80, 2.0591798858084703e-77, 9.9197548192127678e-75, 3.8678293788234498e-72, 1.2370523208691571e-69, 3.2836627133699974e-67, 7.3095353354239491e-65, 1.3772094187709065e-62, 2.2145636638702121e-60, 3.0619202170369175e-58, 3.6647661995973869e-56, 3.8203649763779160e-54, 3.4881351774083147e-52, 2.8036775536310555e-50, 1.9931613619579773e-48, 1.2586567146117010e-46, 7.0884044215753474e-45, 3.5732404426806206e-43, 1.6178126120857497e-41, 6.5996510428781978e-40, 2.4328759328467202e-38, 8.1267763573550637e-37, 2.4662127220461684e-35, 6.8155261813509929e-34, 1.7191030917484011e-32, 3.9660195668953352e-31, 8.3853154776461475e-30, 1.6278171201629848e-28, 2.9065390998814081e-27, 4.7813433896247487e-26, 7.2578010107444783e-25, 1.0180797851831930e-23, 1.3215548441960911e-22, 1.5895976396503745e-21, 1.7738996763753002e-20, 1.8387513781865510e-19, 1.7723693479759404e-18, 1.5903120371435548e-17, 1.3296671955521453e-16, 1.0369288823537636e-15, 7.5490426637877302e-15, 5.1350286901144194e-14, 3.2662837995375004e-13, 1.9442795471244843e-12, 1.0838609818985724e-11, 5.6623712315092519e-11, 2.7740673531720516e-10, 1.2752593807305187e-09, 5.5042412134787782e-09, 2.2317961616833082e-08, 8.5054483756057923e-08, 3.0481775749836127e-07, 1.0277468837741270e-06, 3.2615617411254204e-06, 9.7462566160282362e-06, 2.7434125933222057e-05, 7.2768434100256330e-05, 1.8194526534270113e-04, 4.2896461357756435e-04, 9.5392124328337667e-04, 2.0013900802573659e-03, 3.9626676572752555e-03, 7.4059308800968815e-03, 1.3067672819155697e-02, 2.1773347066246198e-02, 3.4263651242794235e-02, 5.0931713552683139e-02, 7.1522962430052642e-02, 9.4897195996236208e-02, 1.1897395918444152e-01, 1.4095256578997853e-01, 1.5781215945203400e-01, 1.6698222073712451e-01, 1.6698222073712451e-01, 1.5781215945203400e-01, 1.4095256578997853e-01, 1.1897395918444152e-01, 9.4897195996236208e-02, 7.1522962430052642e-02, 5.0931713552683139e-02, 3.4263651242794235e-02, 2.1773347066246198e-02, 1.3067672819155697e-02, 7.4059308800968815e-03, 3.9626676572752555e-03, 2.0013900802573659e-03, 9.5392124328337667e-04, 4.2896461357756435e-04, 1.8194526534270113e-04, 7.2768434100256330e-05, 2.7434125933222057e-05, 9.7462566160282362e-06, 3.2615617411254204e-06, 1.0277468837741270e-06, 3.0481775749836127e-07, 8.5054483756057923e-08, 2.2317961616833082e-08, 5.5042412134787782e-09, 1.2752593807305187e-09, 2.7740673531720516e-10, 5.6623712315092519e-11, 1.0838609818985724e-11, 1.9442795471244843e-12, 3.2662837995375004e-13, 5.1350286901144194e-14, 7.5490426637877302e-15, 1.0369288823537636e-15, 1.3296671955521453e-16, 1.5903120371435548e-17, 1.7723693479759404e-18, 1.8387513781865510e-19, 1.7738996763753002e-20, 1.5895976396503745e-21, 1.3215548441960911e-22, 1.0180797851831930e-23, 7.2578010107444783e-25, 4.7813433896247487e-26, 2.9065390998814081e-27, 1.6278171201629848e-28, 8.3853154776461475e-30, 3.9660195668953352e-31, 1.7191030917484011e-32, 6.8155261813509929e-34, 2.4662127220461684e-35, 8.1267763573550637e-37, 2.4328759328467202e-38, 6.5996510428781978e-40, 1.6178126120857497e-41, 3.5732404426806206e-43, 7.0884044215753474e-45, 1.2586567146117010e-46, 1.9931613619579773e-48, 2.8036775536310555e-50, 3.4881351774083147e-52, 3.8203649763779160e-54, 3.6647661995973869e-56, 3.0619202170369175e-58, 2.2145636638702121e-60, 1.3772094187709065e-62, 7.3095353354239491e-65, 3.2836627133699974e-67, 1.2370523208691571e-69, 3.8678293788234498e-72, 9.9197548192127678e-75, 2.0591798858084703e-77, 3.4072707861884866e-80, 4.4153132623096831e-83, 4.3893173430676675e-86, 3.2668637275061076e-89, 1.7680841960979503e-92, 6.7162796391421331e-96, 1.7138296773072837e-99, 2.7792048294771247e-103, 2.6646059822111242e-107, 1.3704328437984587e-111, 3.2960842775717504e-116, 3.0166712841087998e-121, 7.4819712112270593e-127, 2.6289723724457029e-133, 2.4899600964326729e-141}, {3.5411506471568517e-142, 3.8870007298929211e-134, 1.1427720218874746e-127, 4.7443699591186030e-122, 5.3267445942905176e-117, 2.2724999081578913e-112, 4.5288568274049433e-108, 4.8374430266711206e-104, 3.0528486739600850e-100, 1.2236703652880107e-96, 3.2933121419749483e-93, 6.2184654173606399e-90, 8.5354199357192903e-87, 8.7687858501113383e-84, 6.9091769993084969e-81, 4.2624770595798820e-78, 2.0957319191157142e-75, 8.3387106103658512e-73, 2.7211703761612434e-70, 7.3690229255476969e-68, 1.6733234438392451e-65, 3.2158114928338939e-63, 5.2740829263623727e-61, 7.4369351842678165e-59, 9.0774918435864705e-57, 9.6499842697585386e-55, 8.9847110119503318e-53, 7.3640839458387673e-51, 5.3383547450946618e-49, 3.4375135972727117e-47, 1.9740530949677369e-45, 1.0147285474798106e-43, 4.6848975802870826e-42, 1.9488875555428468e-40, 7.3264228854645894e-39, 2.4958088668373114e-37, 7.7243461606513683e-36, 2.1771495752866995e-34, 5.6010600122601367e-33, 1.3180336788235122e-31, 2.8426307813064235e-30, 5.6294266388452469e-29, 1.0254685909108741e-27, 1.7211387969394399e-26, 2.6657834170950206e-25, 3.8158515821307025e-24, 5.0550170089602786e-23, 6.2057205211001172e-22, 7.0687611828654942e-21, 7.4798012691484967e-20, 7.3607060012414608e-19, 6.7436191474716113e-18, 5.7576889770247240e-17, 4.5856377569387674e-16, 3.4098950541891060e-15, 2.3694365058853221e-14, 1.5398051925046748e-13, 9.3656673457701801e-13, 5.3355866239683074e-12, 2.8490354792258560e-11, 1.4268284555926340e-10, 6.7061742381683788e-10, 2.9598086074993327e-09, 1.2273853303242205e-08, 4.7847173987299635e-08, 1.7543109823449902e-07, 6.0525229343483686e-07, 1.9657973702696829e-06, 6.0130527402628209e-06, 1.7329090398329860e-05, 4.7069644542722322e-05, 1.2054246571768105e-04, 2.9114733811626920e-04, 6.6342074803749660e-04, 1.4265570512383724e-03, 2.8955046143597550e-03, 5.5487673845870103e-03, 1.0041513921437970e-02, 1.7163936516514416e-02, 2.7715692333499325e-02, 4.2285689519455438e-02, 6.0964838880386028e-02, 8.3068258519182064e-02, 1.0698027879398084e-01, 1.3023286590097533e-01, 1.4986945253577164e-01, 1.6304250159157527e-01, 1.6768547028079969e-01, 1.6304250159157527e-01, 1.4986945253577164e-01, 1.3023286590097533e-01, 1.0698027879398084e-01, 8.3068258519182064e-02, 6.0964838880386028e-02, 4.2285689519455438e-02, 2.7715692333499325e-02, 1.7163936516514416e-02, 1.0041513921437970e-02, 5.5487673845870103e-03, 2.8955046143597550e-03, 1.4265570512383724e-03, 6.6342074803749660e-04, 2.9114733811626920e-04, 1.2054246571768105e-04, 4.7069644542722322e-05, 1.7329090398329860e-05, 6.0130527402628209e-06, 1.9657973702696829e-06, 6.0525229343483686e-07, 1.7543109823449902e-07, 4.7847173987299635e-08, 1.2273853303242205e-08, 2.9598086074993327e-09, 6.7061742381683788e-10, 1.4268284555926340e-10, 2.8490354792258560e-11, 5.3355866239683074e-12, 9.3656673457701801e-13, 1.5398051925046748e-13, 2.3694365058853221e-14, 3.4098950541891060e-15, 4.5856377569387674e-16, 5.7576889770247240e-17, 6.7436191474716113e-18, 7.3607060012414608e-19, 7.4798012691484967e-20, 7.0687611828654942e-21, 6.2057205211001172e-22, 5.0550170089602786e-23, 3.8158515821307025e-24, 2.6657834170950206e-25, 1.7211387969394399e-26, 1.0254685909108741e-27, 5.6294266388452469e-29, 2.8426307813064235e-30, 1.3180336788235122e-31, 5.6010600122601367e-33, 2.1771495752866995e-34, 7.7243461606513683e-36, 2.4958088668373114e-37, 7.3264228854645894e-39, 1.9488875555428468e-40, 4.6848975802870826e-42, 1.0147285474798106e-43, 1.9740530949677369e-45, 3.4375135972727117e-47, 5.3383547450946618e-49, 7.3640839458387673e-51, 8.9847110119503318e-53, 9.6499842697585386e-55, 9.0774918435864705e-57, 7.4369351842678165e-59, 5.2740829263623727e-61, 3.2158114928338939e-63, 1.6733234438392451e-65, 7.3690229255476969e-68, 2.7211703761612434e-70, 8.3387106103658512e-73, 2.0957319191157142e-75, 4.2624770595798820e-78, 6.9091769993084969e-81, 8.7687858501113383e-84, 8.5354199357192903e-87, 6.2184654173606399e-90, 3.2933121419749483e-93, 1.2236703652880107e-96, 3.0528486739600850e-100, 4.8374430266711206e-104, 4.5288568274049433e-108, 2.2724999081578913e-112, 5.3267445942905176e-117, 4.7443699591186030e-122, 1.1427720218874746e-127, 3.8870007298929211e-134, 3.5411506471568517e-142}, {5.0351722883464185e-143, 5.7450587562745078e-135, 1.7446064596498268e-128, 7.4571213334341600e-123, 8.6023715273839571e-118, 3.7652628313310755e-113, 7.6903016009308287e-109, 8.4113401468636500e-105, 5.4319085709594968e-101, 2.2267204629384821e-97, 6.1261103396048387e-94, 1.1819905626126024e-90, 1.6572504238354695e-87, 1.7386395392283553e-84, 1.3986045504550338e-81, 8.8071523423621673e-79, 4.4190897787947332e-76, 1.7941108043227645e-73, 5.9730812278268291e-71, 1.6500317832456593e-68, 3.8217018216862523e-66, 7.4907171097897077e-64, 1.2528614722567282e-61, 1.8015494058808057e-59, 2.2422904341536794e-57, 2.4305731255545130e-55, 2.3074311289682700e-53, 1.9283073358698602e-51, 1.4252524566058730e-49, 9.3573522665893741e-48, 5.4788838446141128e-46, 2.8715169045497604e-44, 1.3517494625509147e-42, 5.7335891630321996e-41, 2.1977946695381225e-39, 7.6344180491439718e-38, 2.4094190488253342e-36, 6.9253812367067252e-35, 1.8169855856152196e-33, 4.3607057687085942e-32, 9.5923503135464682e-31, 1.9376278309334056e-29, 3.6004726047782310e-28, 6.1647472746508888e-27, 9.7413623207618448e-26, 1.4227116244089339e-24, 1.9231607886931175e-23, 2.4093040723082529e-22, 2.8008499497491982e-21, 3.0250061661788475e-20, 3.0387132211276073e-19, 2.8421271873321773e-18, 2.4775756264214477e-17, 2.0149141590187015e-16, 1.5301273364381654e-15, 1.0859626897815736e-14, 7.2089869379341516e-14, 4.4796392616415365e-13, 2.6076028723419556e-12, 1.4228958097317545e-11, 7.2832614256562299e-11, 3.4992319867238825e-10, 1.5789636824184370e-09, 6.6952823181138107e-09, 2.6692828097969734e-08, 1.0010785492509061e-07, 3.5334287745169781e-07, 1.1742867585331092e-06, 3.6760831094679487e-06, 1.0844326360928105e-05, 3.0156999060878010e-05, 7.9084957328144794e-05, 1.9564188997236542e-04, 4.5669297388226392e-04, 1.0062461311647175e-03, 2.0932217887326024e-03, 4.1120856339170011e-03, 7.6302877130003874e-03, 1.3376390072548504e-02, 2.2158233552618596e-02, 3.4689673239772116e-02, 5.1332999819585050e-02, 7.1809001831171768e-02, 9.4971530833224349e-02, 1.1876238489882553e-01, 1.4043201287954626e-01, 1.5702837449220031e-01, 1.6604672219204664e-01, 1.6604672219204664e-01, 1.5702837449220031e-01, 1.4043201287954626e-01, 1.1876238489882553e-01, 9.4971530833224349e-02, 7.1809001831171768e-02, 5.1332999819585050e-02, 3.4689673239772116e-02, 2.2158233552618596e-02, 1.3376390072548504e-02, 7.6302877130003874e-03, 4.1120856339170011e-03, 2.0932217887326024e-03, 1.0062461311647175e-03, 4.5669297388226392e-04, 1.9564188997236542e-04, 7.9084957328144794e-05, 3.0156999060878010e-05, 1.0844326360928105e-05, 3.6760831094679487e-06, 1.1742867585331092e-06, 3.5334287745169781e-07, 1.0010785492509061e-07, 2.6692828097969734e-08, 6.6952823181138107e-09, 1.5789636824184370e-09, 3.4992319867238825e-10, 7.2832614256562299e-11, 1.4228958097317545e-11, 2.6076028723419556e-12, 4.4796392616415365e-13, 7.2089869379341516e-14, 1.0859626897815736e-14, 1.5301273364381654e-15, 2.0149141590187015e-16, 2.4775756264214477e-17, 2.8421271873321773e-18, 3.0387132211276073e-19, 3.0250061661788475e-20, 2.8008499497491982e-21, 2.4093040723082529e-22, 1.9231607886931175e-23, 1.4227116244089339e-24, 9.7413623207618448e-26, 6.1647472746508888e-27, 3.6004726047782310e-28, 1.9376278309334056e-29, 9.5923503135464682e-31, 4.3607057687085942e-32, 1.8169855856152196e-33, 6.9253812367067252e-35, 2.4094190488253342e-36, 7.6344180491439718e-38, 2.1977946695381225e-39, 5.7335891630321996e-41, 1.3517494625509147e-42, 2.8715169045497604e-44, 5.4788838446141128e-46, 9.3573522665893741e-48, 1.4252524566058730e-49, 1.9283073358698602e-51, 2.3074311289682700e-53, 2.4305731255545130e-55, 2.2422904341536794e-57, 1.8015494058808057e-59, 1.2528614722567282e-61, 7.4907171097897077e-64, 3.8217018216862523e-66, 1.6500317832456593e-68, 5.9730812278268291e-71, 1.7941108043227645e-73, 4.4190897787947332e-76, 8.8071523423621673e-79, 1.3986045504550338e-81, 1.7386395392283553e-84, 1.6572504238354695e-87, 1.1819905626126024e-90, 6.1261103396048387e-94, 2.2267204629384821e-97, 5.4319085709594968e-101, 8.4113401468636500e-105, 7.6903016009308287e-109, 3.7652628313310755e-113, 8.6023715273839571e-118, 7.4571213334341600e-123, 1.7446064596498268e-128, 5.7450587562745078e-135, 5.0351722883464185e-143}, {7.1581854941568756e-144, 8.4884228757564859e-136, 2.6621446843016668e-129, 1.1714088250630149e-123, 1.3882583385637704e-118, 6.2335512554508696e-114, 1.3046719672955675e-109, 1.4610767163662094e-105, 9.6541517663049285e-102, 4.0470443036783296e-98, 1.1380585129708444e-94, 2.2435189643567695e-91, 3.2128730776926215e-88, 3.4417484237908715e-85, 2.8263134922810747e-82, 1.8164480123517544e-79, 9.3003877258546557e-77, 3.8523675927861067e-74, 1.3083561453477787e-71, 3.6865159997894300e-69, 8.7082600252251548e-67, 1.7406436581415539e-64, 2.9687147399709626e-62, 4.3527424404558593e-60, 5.5237929617045550e-58, 6.1047069753060061e-56, 5.9085581038387938e-54, 5.0340269517910206e-52, 3.7932466358096469e-50, 2.5389205160417814e-48, 1.5155318342592620e-46, 8.0977464419800098e-45, 3.8862848936787104e-43, 1.6805797332715199e-41, 6.5678744364293848e-40, 2.3261212178440308e-38, 7.4851978878895327e-37, 2.1937508830604144e-35, 5.8690540840121578e-34, 1.4363784560339465e-32, 3.2222344142269078e-31, 6.6381799678904965e-30, 1.2580944858403407e-28, 2.1972252658847511e-27, 3.5417421260548565e-26, 5.2769903994937601e-25, 7.2776858868650826e-24, 9.3028399771791796e-23, 1.1035696761428192e-21, 1.2163644574829813e-20, 1.2470907989461904e-19, 1.1906056130964038e-18, 1.0595326417660698e-17, 8.7974278780040251e-17, 6.8216435985574468e-16, 4.9441425800883030e-15, 3.3521165632319237e-14, 2.1277112806959519e-13, 1.2653006101080342e-12, 7.0545233223348931e-12, 3.6899828977436854e-11, 1.8119180456089166e-10, 8.3573910554417999e-10, 3.6229939665804831e-09, 1.4769397910223943e-08, 5.6647039057714555e-08, 2.0451241808924649e-07, 6.9532414269249713e-07, 2.2272343809174102e-06, 6.7240427138149140e-06, 1.9140150173987354e-05, 5.1388360015799239e-05, 1.3017662891537081e-04, 3.1123241184750341e-04, 7.0249863037702334e-04, 1.4973772242764213e-03, 3.0147364453737358e-03, 5.7345384962421463e-03, 1.0307863786080675e-02, 1.7512238829626020e-02, 2.8124900042797892e-02, 4.2705327076181680e-02, 6.1315790894116422e-02, 8.3255213529058528e-02, 1.0691562889960281e-01, 1.2986607877253428e-01, 1.4921123248756085e-01, 1.6217258820124303e-01, 1.6673809474249007e-01, 1.6217258820124303e-01, 1.4921123248756085e-01, 1.2986607877253428e-01, 1.0691562889960281e-01, 8.3255213529058528e-02, 6.1315790894116422e-02, 4.2705327076181680e-02, 2.8124900042797892e-02, 1.7512238829626020e-02, 1.0307863786080675e-02, 5.7345384962421463e-03, 3.0147364453737358e-03, 1.4973772242764213e-03, 7.0249863037702334e-04, 3.1123241184750341e-04, 1.3017662891537081e-04, 5.1388360015799239e-05, 1.9140150173987354e-05, 6.7240427138149140e-06, 2.2272343809174102e-06, 6.9532414269249713e-07, 2.0451241808924649e-07, 5.6647039057714555e-08, 1.4769397910223943e-08, 3.6229939665804831e-09, 8.3573910554417999e-10, 1.8119180456089166e-10, 3.6899828977436854e-11, 7.0545233223348931e-12, 1.2653006101080342e-12, 2.1277112806959519e-13, 3.3521165632319237e-14, 4.9441425800883030e-15, 6.8216435985574468e-16, 8.7974278780040251e-17, 1.0595326417660698e-17, 1.1906056130964038e-18, 1.2470907989461904e-19, 1.2163644574829813e-20, 1.1035696761428192e-21, 9.3028399771791796e-23, 7.2776858868650826e-24, 5.2769903994937601e-25, 3.5417421260548565e-26, 2.1972252658847511e-27, 1.2580944858403407e-28, 6.6381799678904965e-30, 3.2222344142269078e-31, 1.4363784560339465e-32, 5.8690540840121578e-34, 2.1937508830604144e-35, 7.4851978878895327e-37, 2.3261212178440308e-38, 6.5678744364293848e-40, 1.6805797332715199e-41, 3.8862848936787104e-43, 8.0977464419800098e-45, 1.5155318342592620e-46, 2.5389205160417814e-48, 3.7932466358096469e-50, 5.0340269517910206e-52, 5.9085581038387938e-54, 6.1047069753060061e-56, 5.5237929617045550e-58, 4.3527424404558593e-60, 2.9687147399709626e-62, 1.7406436581415539e-64, 8.7082600252251548e-67, 3.6865159997894300e-69, 1.3083561453477787e-71, 3.8523675927861067e-74, 9.3003877258546557e-77, 1.8164480123517544e-79, 2.8263134922810747e-82, 3.4417484237908715e-85, 3.2128730776926215e-88, 2.2435189643567695e-91, 1.1380585129708444e-94, 4.0470443036783296e-98, 9.6541517663049285e-102, 1.4610767163662094e-105, 1.3046719672955675e-109, 6.2335512554508696e-114, 1.3882583385637704e-118, 1.1714088250630149e-123, 2.6621446843016668e-129, 8.4884228757564859e-136, 7.1581854941568756e-144}, {1.0174451907169722e-144, 1.2537577338109092e-136, 4.0603558490313254e-130, 1.8390471781108747e-124, 2.2388300710588648e-119, 1.0311647067706544e-114, 2.2113953581884588e-110, 2.5353839157043305e-106, 1.7139381704010506e-102, 7.3466025769339733e-99, 2.1114364896149106e-95, 4.2524253414775605e-92, 6.2193919080044227e-89, 6.8022938891305936e-86, 5.7017766571657716e-83, 3.7396644213938176e-80, 1.9536604993085239e-77, 8.2555014673420022e-75, 2.8598818663126844e-72, 8.2184808615623598e-70, 1.9797683901166225e-67, 4.0351646934878695e-65, 7.0170567960964978e-63, 1.0489546649192595e-60, 1.3571109461554121e-58, 1.5290034639304410e-56, 1.5086081632928153e-54, 1.3102411068553504e-52, 1.0064229300129089e-50, 6.8667092650473948e-49, 4.1782480984927090e-47, 2.2757544084791531e-45, 1.1133537204234619e-43, 4.9079810854674800e-42, 1.9553490062333371e-40, 7.0599294307578851e-39, 2.3160882385061203e-37, 6.9205465629360576e-36, 1.8877397396823247e-34, 4.7107012996283542e-33, 1.0775571184918142e-31, 2.2637292363656048e-30, 4.3753093336081546e-29, 7.7932715085212503e-28, 1.2812781788064907e-26, 1.9472758171895140e-25, 2.7395824646129918e-24, 3.5726754325441841e-23, 4.3241778048815671e-22, 4.8633316486835449e-21, 5.0883502730989637e-20, 4.9579227287808755e-19, 4.5034462009468205e-18, 3.8170938055666007e-17, 3.0217745531718828e-16, 2.2362025898948135e-15, 1.5482439389379285e-14, 1.0036629079256339e-13, 6.0964973515510935e-13, 3.4723560883860410e-12, 1.8557142556642682e-11, 9.3114559517381624e-11, 4.3894092072618305e-10, 1.9450249932898343e-09, 8.1060721426662619e-09, 3.1789582778002615e-08, 1.1737053608502818e-07, 4.0816183881635333e-07, 1.3374965511498204e-06, 4.1315876560548306e-06, 1.2035714382322826e-05, 3.3076061707490808e-05, 8.5780643722862892e-05, 2.1000778733594350e-04, 4.8548944122296688e-04, 1.0600860254999084e-03, 2.1869011800911028e-03, 4.2632921737953853e-03, 7.8556410099729287e-03, 1.3684318450535705e-02, 2.2539589851423701e-02, 3.5108996740976929e-02, 5.1725036108245200e-02, 7.2085145846744095e-02, 9.5038220322125194e-02, 1.1854839415593066e-01, 1.3991610657942335e-01, 1.5625599948674623e-01, 1.6512677086080088e-01, 1.6512677086080088e-01, 1.5625599948674623e-01, 1.3991610657942335e-01, 1.1854839415593066e-01, 9.5038220322125194e-02, 7.2085145846744095e-02, 5.1725036108245200e-02, 3.5108996740976929e-02, 2.2539589851423701e-02, 1.3684318450535705e-02, 7.8556410099729287e-03, 4.2632921737953853e-03, 2.1869011800911028e-03, 1.0600860254999084e-03, 4.8548944122296688e-04, 2.1000778733594350e-04, 8.5780643722862892e-05, 3.3076061707490808e-05, 1.2035714382322826e-05, 4.1315876560548306e-06, 1.3374965511498204e-06, 4.0816183881635333e-07, 1.1737053608502818e-07, 3.1789582778002615e-08, 8.1060721426662619e-09, 1.9450249932898343e-09, 4.3894092072618305e-10, 9.3114559517381624e-11, 1.8557142556642682e-11, 3.4723560883860410e-12, 6.0964973515510935e-13, 1.0036629079256339e-13, 1.5482439389379285e-14, 2.2362025898948135e-15, 3.0217745531718828e-16, 3.8170938055666007e-17, 4.5034462009468205e-18, 4.9579227287808755e-19, 5.0883502730989637e-20, 4.8633316486835449e-21, 4.3241778048815671e-22, 3.5726754325441841e-23, 2.7395824646129918e-24, 1.9472758171895140e-25, 1.2812781788064907e-26, 7.7932715085212503e-28, 4.3753093336081546e-29, 2.2637292363656048e-30, 1.0775571184918142e-31, 4.7107012996283542e-33, 1.8877397396823247e-34, 6.9205465629360576e-36, 2.3160882385061203e-37, 7.0599294307578851e-39, 1.9553490062333371e-40, 4.9079810854674800e-42, 1.1133537204234619e-43, 2.2757544084791531e-45, 4.1782480984927090e-47, 6.8667092650473948e-49, 1.0064229300129089e-50, 1.3102411068553504e-52, 1.5086081632928153e-54, 1.5290034639304410e-56, 1.3571109461554121e-58, 1.0489546649192595e-60, 7.0170567960964978e-63, 4.0351646934878695e-65, 1.9797683901166225e-67, 8.2184808615623598e-70, 2.8598818663126844e-72, 8.2555014673420022e-75, 1.9536604993085239e-77, 3.7396644213938176e-80, 5.7017766571657716e-83, 6.8022938891305936e-86, 6.2193919080044227e-89, 4.2524253414775605e-92, 2.1114364896149106e-95, 7.3466025769339733e-99, 1.7139381704010506e-102, 2.5353839157043305e-106, 2.2113953581884588e-110, 1.0311647067706544e-114, 2.2388300710588648e-119, 1.8390471781108747e-124, 4.0603558490313254e-130, 1.2537577338109092e-136, 1.0174451907169722e-144}, {1.4459034710264201e-145, 1.8512101069007797e-137, 6.1900866973604703e-131, 2.8855379169821182e-125, 3.6080591054052492e-120, 1.7044183943684018e-115, 3.7449189704395232e-111, 4.3952304904350605e-107, 3.0394872358078098e-103, 1.3320382883615053e-99, 3.9122879439382170e-96, 8.0489834136101609e-93, 1.2021477111483726e-89, 1.3422872316499288e-86, 1.1483443011896613e-83, 7.6855073087396857e-81, 4.0962408560880496e-78, 1.7656535944547459e-75, 6.2384154226153306e-73, 1.8282206685181686e-70, 4.4907236877039048e-68, 9.3322988518723512e-66, 1.6545283606525458e-63, 2.5213872637605977e-61, 3.3253581541518404e-59, 3.8190282366232640e-57, 3.8408503131563961e-55, 3.4001469878023392e-53, 2.6620432033111890e-51, 1.8512591668862315e-49, 1.1481424339931328e-47, 6.3739969672637270e-46, 3.1784051437766470e-44, 1.4281570152975713e-42, 5.7996825799748193e-41, 2.1345161706875471e-39, 7.1381873166360108e-38, 2.1743217660681791e-36, 6.0463752750772134e-35, 1.5382579845230378e-33, 3.5875473238148687e-32, 7.6845885182041777e-31, 1.5145049680016594e-29, 2.7509103704580098e-28, 4.6123845343733745e-27, 7.1493666161606643e-26, 1.0259279798609206e-24, 1.3647547675188007e-23, 1.6851209810753113e-22, 1.9336042594232875e-21, 2.0642309881609900e-20, 2.0524462477993889e-19, 1.9026226109394554e-18, 1.6459732365754106e-17, 1.3300948716108394e-16, 1.0048759007103044e-15, 7.1035141604691271e-15, 4.7022739273699201e-14, 2.9170375040074331e-13, 1.6970108678299655e-12, 9.2646537879215591e-12, 4.7495690973542646e-11, 2.2878306073735174e-10, 1.0360690148079607e-09, 4.4135301064719171e-09, 1.7694607842914065e-08, 6.6798391472451806e-08, 2.3755404518235753e-07, 7.9619631902655087e-07, 2.5160446644029356e-06, 7.4993851915062359e-06, 2.1091170590509833e-05, 5.5987643740857493e-05, 1.4032641744066531e-04, 3.3217919994016825e-04, 7.4286891131823533e-04, 1.5698960784933606e-03, 3.1358280493826080e-03, 5.9217687653631513e-03, 1.0574395576910816e-02, 1.7858440641500769e-02, 2.8528992504062382e-02, 4.3116896847977884e-02, 6.1656983184778281e-02, 8.3433163844430863e-02, 1.0684575215294285e-01, 1.2950034028006346e-01, 1.4856115387707583e-01, 1.6131642239308974e-01, 1.6580659700649841e-01, 1.6131642239308974e-01, 1.4856115387707583e-01, 1.2950034028006346e-01, 1.0684575215294285e-01, 8.3433163844430863e-02, 6.1656983184778281e-02, 4.3116896847977884e-02, 2.8528992504062382e-02, 1.7858440641500769e-02, 1.0574395576910816e-02, 5.9217687653631513e-03, 3.1358280493826080e-03, 1.5698960784933606e-03, 7.4286891131823533e-04, 3.3217919994016825e-04, 1.4032641744066531e-04, 5.5987643740857493e-05, 2.1091170590509833e-05, 7.4993851915062359e-06, 2.5160446644029356e-06, 7.9619631902655087e-07, 2.3755404518235753e-07, 6.6798391472451806e-08, 1.7694607842914065e-08, 4.4135301064719171e-09, 1.0360690148079607e-09, 2.2878306073735174e-10, 4.7495690973542646e-11, 9.2646537879215591e-12, 1.6970108678299655e-12, 2.9170375040074331e-13, 4.7022739273699201e-14, 7.1035141604691271e-15, 1.0048759007103044e-15, 1.3300948716108394e-16, 1.6459732365754106e-17, 1.9026226109394554e-18, 2.0524462477993889e-19, 2.0642309881609900e-20, 1.9336042594232875e-21, 1.6851209810753113e-22, 1.3647547675188007e-23, 1.0259279798609206e-24, 7.1493666161606643e-26, 4.6123845343733745e-27, 2.7509103704580098e-28, 1.5145049680016594e-29, 7.6845885182041777e-31, 3.5875473238148687e-32, 1.5382579845230378e-33, 6.0463752750772134e-35, 2.1743217660681791e-36, 7.1381873166360108e-38, 2.1345161706875471e-39, 5.7996825799748193e-41, 1.4281570152975713e-42, 3.1784051437766470e-44, 6.3739969672637270e-46, 1.1481424339931328e-47, 1.8512591668862315e-49, 2.6620432033111890e-51, 3.4001469878023392e-53, 3.8408503131563961e-55, 3.8190282366232640e-57, 3.3253581541518404e-59, 2.5213872637605977e-61, 1.6545283606525458e-63, 9.3322988518723512e-66, 4.4907236877039048e-68, 1.8282206685181686e-70, 6.2384154226153306e-73, 1.7656535944547459e-75, 4.0962408560880496e-78, 7.6855073087396857e-81, 1.1483443011896613e-83, 1.3422872316499288e-86, 1.2021477111483726e-89, 8.0489834136101609e-93, 3.9122879439382170e-96, 1.3320382883615053e-99, 3.0394872358078098e-103, 4.3952304904350605e-107, 3.7449189704395232e-111, 1.7044183943684018e-115, 3.6080591054052492e-120, 2.8855379169821182e-125, 6.1900866973604703e-131, 1.8512101069007797e-137, 1.4459034710264201e-145}, {2.0544167081187589e-146, 2.7324651628287789e-138, 9.4326009424734410e-132, 4.5249380509459828e-126, 5.8107301413051742e-121, 2.8150324044562284e-116, 6.3362635154258981e-112, 7.6118645291179184e-108, 5.3843632439536920e-104, 2.4123127079122074e-100, 7.2398333677694101e-97, 1.5214189335297059e-93, 2.3202235060376314e-90, 2.6445775673882037e-87, 2.3089447193822174e-84, 1.5767056174162126e-81, 8.5727195865402764e-79, 3.7689704357176965e-76, 1.3580443028284028e-73, 4.0582349306406949e-71, 1.0163600799789738e-68, 2.1532917098122703e-66, 3.8916837271887350e-64, 6.0453772000204261e-62, 8.1267907500285513e-60, 9.5128584361969727e-58, 9.7509710005032432e-56, 8.7976987433650472e-54, 7.0198773756157181e-52, 4.9753094376640113e-50, 3.1447462107627518e-48, 1.7792627000157171e-46, 9.0423237558527988e-45, 4.1409133307449204e-43, 1.7138906209368488e-41, 6.4290783512879458e-40, 2.1913996777475932e-38, 6.8039020082108794e-37, 1.9286270378988431e-35, 5.0017461082503641e-34, 1.1891915619808499e-32, 2.5969337466904165e-31, 5.2182308893507914e-30, 9.6642798753295627e-29, 1.6523003694364310e-27, 2.6117599911695471e-26, 3.8222432521976105e-25, 5.1859356642906214e-24, 6.5314813585357555e-23, 7.6453095155047312e-22, 8.3267040963735343e-21, 8.4472663315088944e-20, 7.9904365646153140e-19, 7.0543936381041909e-18, 5.8181634606657441e-17, 4.4867423723460479e-16, 3.2378602233952898e-15, 2.1883227889949076e-14, 1.3861757281246388e-13, 8.2354944810071531e-13, 4.5921996541535561e-12, 2.4048711144413950e-11, 1.1835015186215515e-10, 5.4765134657351679e-10, 2.3841694011026308e-09, 9.7699965359482599e-09, 3.7704288545104245e-08, 1.3709740387891837e-07, 4.6989603841203290e-07, 1.5187614573110066e-06, 4.6308779212753262e-06, 1.3325507543076759e-05, 3.6199433343496547e-05, 9.2866446344988979e-05, 2.2505423008074610e-04, 5.1535932107027135e-04, 1.1154298676886345e-03, 2.2823888738018917e-03, 4.4162127170279562e-03, 8.0818888889421375e-03, 1.3991358954534535e-02, 2.2917370391076095e-02, 3.5521683059969993e-02, 5.2108016747135361e-02, 7.2351691768296089e-02, 9.5097571709914869e-02, 1.1833217723448959e-01, 1.3940481744965749e-01, 1.5549476479437641e-01, 1.6422194087055850e-01, 1.6422194087055850e-01, 1.5549476479437641e-01, 1.3940481744965749e-01, 1.1833217723448959e-01, 9.5097571709914869e-02, 7.2351691768296089e-02, 5.2108016747135361e-02, 3.5521683059969993e-02, 2.2917370391076095e-02, 1.3991358954534535e-02, 8.0818888889421375e-03, 4.4162127170279562e-03, 2.2823888738018917e-03, 1.1154298676886345e-03, 5.1535932107027135e-04, 2.2505423008074610e-04, 9.2866446344988979e-05, 3.6199433343496547e-05, 1.3325507543076759e-05, 4.6308779212753262e-06, 1.5187614573110066e-06, 4.6989603841203290e-07, 1.3709740387891837e-07, 3.7704288545104245e-08, 9.7699965359482599e-09, 2.3841694011026308e-09, 5.4765134657351679e-10, 1.1835015186215515e-10, 2.4048711144413950e-11, 4.5921996541535561e-12, 8.2354944810071531e-13, 1.3861757281246388e-13, 2.1883227889949076e-14, 3.2378602233952898e-15, 4.4867423723460479e-16, 5.8181634606657441e-17, 7.0543936381041909e-18, 7.9904365646153140e-19, 8.4472663315088944e-20, 8.3267040963735343e-21, 7.6453095155047312e-22, 6.5314813585357555e-23, 5.1859356642906214e-24, 3.8222432521976105e-25, 2.6117599911695471e-26, 1.6523003694364310e-27, 9.6642798753295627e-29, 5.2182308893507914e-30, 2.5969337466904165e-31, 1.1891915619808499e-32, 5.0017461082503641e-34, 1.9286270378988431e-35, 6.8039020082108794e-37, 2.1913996777475932e-38, 6.4290783512879458e-40, 1.7138906209368488e-41, 4.1409133307449204e-43, 9.0423237558527988e-45, 1.7792627000157171e-46, 3.1447462107627518e-48, 4.9753094376640113e-50, 7.0198773756157181e-52, 8.7976987433650472e-54, 9.7509710005032432e-56, 9.5128584361969727e-58, 8.1267907500285513e-60, 6.0453772000204261e-62, 3.8916837271887350e-64, 2.1532917098122703e-66, 1.0163600799789738e-68, 4.0582349306406949e-71, 1.3580443028284028e-73, 3.7689704357176965e-76, 8.5727195865402764e-79, 1.5767056174162126e-81, 2.3089447193822174e-84, 2.6445775673882037e-87, 2.3202235060376314e-90, 1.5214189335297059e-93, 7.2398333677694101e-97, 2.4123127079122074e-100, 5.3843632439536920e-104, 7.6118645291179184e-108, 6.3362635154258981e-112, 2.8150324044562284e-116, 5.8107301413051742e-121, 4.5249380509459828e-126, 9.4326009424734410e-132, 2.7324651628287789e-138, 2.0544167081187589e-146}, {2.9184983704075192e-147, 4.0319183713400766e-139, 1.4367134541050939e-132, 7.0917398018507910e-127, 9.3517988737392972e-122, 4.6457185244440549e-117, 1.0711309190325783e-112, 1.3169706905085093e-108, 9.5280026251390744e-105, 4.3635736981957750e-101, 1.3380638102406329e-97, 2.8718782241763001e-94, 4.4716757994553476e-91, 5.2022930902389893e-88, 4.6349150479031114e-85, 3.2290491038758581e-82, 1.7908398704126536e-79, 8.0297842302329272e-77, 2.9503683873426791e-74, 8.9893224354049310e-72, 2.2951885774902920e-69, 4.9569512961693677e-67, 9.1317952402850698e-65, 1.4458391823512865e-62, 1.9809319471106229e-60, 2.3631742826980710e-58, 2.4686029155016893e-56, 2.2697566491840546e-54, 1.8456028929462080e-52, 1.3329759770755586e-50, 8.5857720828783205e-49, 4.9502403838758848e-47, 2.5636716593985549e-45, 1.1964123882499316e-43, 5.0463692733981642e-42, 1.9291541526211061e-40, 6.7015535541500665e-39, 2.1206217889043141e-37, 6.1266403471398839e-36, 1.6195131761876436e-34, 3.9248683542722297e-33, 8.7371187009076405e-32, 1.7897414312928308e-30, 3.3792749075968173e-29, 5.8905961617051956e-28, 9.4940326558644130e-27, 1.4168234014649860e-25, 1.9603740051045881e-24, 2.5181065241794600e-23, 3.0063944491537587e-22, 3.3400431583218902e-21, 3.4567219838648987e-20, 3.3360382939472660e-19, 3.0052255828362505e-18, 2.5293356487116101e-17, 1.9906862214252033e-16, 1.4663260946610058e-15, 1.0116632951507467e-14, 6.5425658781468336e-14, 3.9689851927958321e-13, 2.2600968959480387e-12, 1.2088512678946103e-11, 6.0769364101383090e-11, 2.8728746426712136e-10, 1.2779384152123448e-09, 5.3517155996766336e-09, 2.1109723472766886e-08, 7.8466356162788103e-08, 2.7497279026009702e-07, 9.0883362098124687e-07, 2.8342636150206807e-06, 8.3429573893995674e-06, 2.3188718962635865e-05, 6.0877111145275987e-05, 1.5100325433613592e-04, 3.5399662151566394e-04, 7.8452960713547043e-04, 1.6440892137594167e-03, 3.2587225571780792e-03, 6.1103686178933300e-03, 1.0841005727093818e-02, 1.8202465449941120e-02, 2.8927974168057351e-02, 4.3520526497899684e-02, 6.1988666273243780e-02, 8.3602420563279559e-02, 1.0677090675896843e-01, 1.2913573606742534e-01, 1.4791906474448899e-01, 1.6047364667465450e-01, 1.6489053845950130e-01, 1.6047364667465450e-01, 1.4791906474448899e-01, 1.2913573606742534e-01, 1.0677090675896843e-01, 8.3602420563279559e-02, 6.1988666273243780e-02, 4.3520526497899684e-02, 2.8927974168057351e-02, 1.8202465449941120e-02, 1.0841005727093818e-02, 6.1103686178933300e-03, 3.2587225571780792e-03, 1.6440892137594167e-03, 7.8452960713547043e-04, 3.5399662151566394e-04, 1.5100325433613592e-04, 6.0877111145275987e-05, 2.3188718962635865e-05, 8.3429573893995674e-06, 2.8342636150206807e-06, 9.0883362098124687e-07, 2.7497279026009702e-07, 7.8466356162788103e-08, 2.1109723472766886e-08, 5.3517155996766336e-09, 1.2779384152123448e-09, 2.8728746426712136e-10, 6.0769364101383090e-11, 1.2088512678946103e-11, 2.2600968959480387e-12, 3.9689851927958321e-13, 6.5425658781468336e-14, 1.0116632951507467e-14, 1.4663260946610058e-15, 1.9906862214252033e-16, 2.5293356487116101e-17, 3.0052255828362505e-18, 3.3360382939472660e-19, 3.4567219838648987e-20, 3.3400431583218902e-21, 3.0063944491537587e-22, 2.5181065241794600e-23, 1.9603740051045881e-24, 1.4168234014649860e-25, 9.4940326558644130e-27, 5.8905961617051956e-28, 3.3792749075968173e-29, 1.7897414312928308e-30, 8.7371187009076405e-32, 3.9248683542722297e-33, 1.6195131761876436e-34, 6.1266403471398839e-36, 2.1206217889043141e-37, 6.7015535541500665e-39, 1.9291541526211061e-40, 5.0463692733981642e-42, 1.1964123882499316e-43, 2.5636716593985549e-45, 4.9502403838758848e-47, 8.5857720828783205e-49, 1.3329759770755586e-50, 1.8456028929462080e-52, 2.2697566491840546e-54, 2.4686029155016893e-56, 2.3631742826980710e-58, 1.9809319471106229e-60, 1.4458391823512865e-62, 9.1317952402850698e-65, 4.9569512961693677e-67, 2.2951885774902920e-69, 8.9893224354049310e-72, 2.9503683873426791e-74, 8.0297842302329272e-77, 1.7908398704126536e-79, 3.2290491038758581e-82, 4.6349150479031114e-85, 5.2022930902389893e-88, 4.4716757994553476e-91, 2.8718782241763001e-94, 1.3380638102406329e-97, 4.3635736981957750e-101, 9.5280026251390744e-105, 1.3169706905085093e-108, 1.0711309190325783e-112, 4.6457185244440549e-117, 9.3517988737392972e-122, 7.0917398018507910e-127, 1.4367134541050939e-132, 4.0319183713400766e-139, 2.9184983704075192e-147}, {4.1452696623483395e-148, 5.9474161464872244e-140, 2.1873318060197500e-133, 1.1108350634945189e-127, 1.5040760324474137e-122, 7.6610437292542439e-118, 1.8091479691129481e-113, 2.2763600768872421e-109, 1.6842534274181958e-105, 7.8840222434465455e-102, 2.4699093339298307e-98, 5.4137540405290719e-95, 8.6056883186768174e-92, 1.0218043358339510e-88, 9.2888951681828944e-86, 6.6016471696136248e-83, 3.7342898142071596e-80, 1.7074874775824880e-77, 6.3969105456232966e-75, 1.9870439601235429e-72, 5.1717638304628555e-70, 1.1385038568984282e-67, 2.1376722221415430e-65, 3.4493784123174178e-63, 4.8161711078239858e-61, 5.8549015274027961e-59, 6.2323324068554731e-57, 5.8390470979220446e-55, 4.8378847700931107e-53, 3.5603170842517748e-51, 2.3366431061277383e-49, 1.3727341637645679e-47, 7.2439067732577147e-46, 3.4446682433867826e-44, 1.4805046972403839e-42, 5.7672996866961233e-41, 2.0415908964489771e-39, 6.5835338360421613e-38, 1.9383756218147382e-36, 5.2220236908204409e-35, 1.2898503021552704e-33, 2.9266129491084507e-32, 6.1107571504811921e-31, 1.1761496941464036e-29, 2.0900714057742614e-28, 3.4343583117038137e-27, 5.2255927032642325e-26, 7.3725440555518383e-25, 9.6570947115181529e-24, 1.1758429681040065e-22, 1.3323707929307384e-21, 1.4065250811244644e-20, 1.3847330443129062e-19, 1.2726463913998945e-18, 1.0928940877684042e-17, 8.7773275665944823e-17, 6.5982162774306465e-16, 4.6464228722152545e-15, 3.0673938466320995e-14, 1.8997359653204635e-13, 1.1045578960219544e-12, 6.0330789028505752e-12, 3.0975214481618230e-11, 1.4957890384694261e-10, 6.7975116544323199e-10, 2.9085970464514601e-09, 1.1724370655087347e-08, 4.4542518892262074e-08, 1.5956404054013332e-07, 5.3920679976732085e-07, 1.7195329738679880e-06, 5.1768455512555845e-06, 1.4718871925099586e-05, 3.9535219175273295e-05, 1.0035307023681430e-04, 2.4079185627092926e-04, 5.4630685564139225e-04, 1.1722653593393563e-03, 2.3796447518820959e-03, 4.5707734636933712e-03, 8.3089325331250057e-03, 1.4297417780659441e-02, 2.3291535150151157e-02, 3.5927796289914674e-02, 5.2482133056536061e-02, 7.2608927339705281e-02, 9.5149879125439124e-02, 1.1811391373984721e-01, 1.3889811387154746e-01, 1.5474440942350939e-01, 1.6333182250163769e-01, 1.6333182250163769e-01, 1.5474440942350939e-01, 1.3889811387154746e-01, 1.1811391373984721e-01, 9.5149879125439124e-02, 7.2608927339705281e-02, 5.2482133056536061e-02, 3.5927796289914674e-02, 2.3291535150151157e-02, 1.4297417780659441e-02, 8.3089325331250057e-03, 4.5707734636933712e-03, 2.3796447518820959e-03, 1.1722653593393563e-03, 5.4630685564139225e-04, 2.4079185627092926e-04, 1.0035307023681430e-04, 3.9535219175273295e-05, 1.4718871925099586e-05, 5.1768455512555845e-06, 1.7195329738679880e-06, 5.3920679976732085e-07, 1.5956404054013332e-07, 4.4542518892262074e-08, 1.1724370655087347e-08, 2.9085970464514601e-09, 6.7975116544323199e-10, 1.4957890384694261e-10, 3.0975214481618230e-11, 6.0330789028505752e-12, 1.1045578960219544e-12, 1.8997359653204635e-13, 3.0673938466320995e-14, 4.6464228722152545e-15, 6.5982162774306465e-16, 8.7773275665944823e-17, 1.0928940877684042e-17, 1.2726463913998945e-18, 1.3847330443129062e-19, 1.4065250811244644e-20, 1.3323707929307384e-21, 1.1758429681040065e-22, 9.6570947115181529e-24, 7.3725440555518383e-25, 5.2255927032642325e-26, 3.4343583117038137e-27, 2.0900714057742614e-28, 1.1761496941464036e-29, 6.1107571504811921e-31, 2.9266129491084507e-32, 1.2898503021552704e-33, 5.2220236908204409e-35, 1.9383756218147382e-36, 6.5835338360421613e-38, 2.0415908964489771e-39, 5.7672996866961233e-41, 1.4805046972403839e-42, 3.4446682433867826e-44, 7.2439067732577147e-46, 1.3727341637645679e-47, 2.3366431061277383e-49, 3.5603170842517748e-51, 4.8378847700931107e-53, 5.8390470979220446e-55, 6.2323324068554731e-57, 5.8549015274027961e-59, 4.8161711078239858e-61, 3.4493784123174178e-63, 2.1376722221415430e-65, 1.1385038568984282e-67, 5.1717638304628555e-70, 1.9870439601235429e-72, 6.3969105456232966e-75, 1.7074874775824880e-77, 3.7342898142071596e-80, 6.6016471696136248e-83, 9.2888951681828944e-86, 1.0218043358339510e-88, 8.6056883186768174e-92, 5.4137540405290719e-95, 2.4699093339298307e-98, 7.8840222434465455e-102, 1.6842534274181958e-105, 2.2763600768872421e-109, 1.8091479691129481e-113, 7.6610437292542439e-118, 1.5040760324474137e-122, 1.1108350634945189e-127, 2.1873318060197500e-133, 5.9474161464872244e-140, 4.1452696623483395e-148}, {5.8866637956879832e-149, 8.7701238593349446e-141, 3.3286398376690490e-134, 1.7390228685740816e-128, 2.4174491971248305e-123, 1.2623847464849609e-118, 3.0530327446766110e-114, 3.9308789125198654e-110, 2.9740999490947605e-106, 1.4228368487505154e-102, 4.5535119727458115e-99, 1.0191828364399763e-95, 1.6537960518565174e-92, 2.0039262792917714e-89, 1.8586066284522124e-86, 1.3473832322197353e-83, 7.7728521820677718e-81, 3.6240329528761601e-78, 1.3842194496021173e-75, 4.3831680288373217e-73, 1.1628357927637541e-70, 2.6089921702855559e-68, 4.9923292649319471e-66, 8.2091330064948600e-64, 1.1679600204323236e-61, 1.4467547750792869e-59, 1.5691297806630218e-57, 1.4978576876165396e-55, 1.2644313857762022e-53, 9.4805533849020122e-52, 6.3392777437739552e-50, 3.7943396524379168e-48, 2.0399882317508400e-46, 9.8835394906743943e-45, 4.3280559299142535e-43, 1.7178434457904729e-41, 6.1961228512356421e-40, 2.0359401385923293e-38, 6.1082242612809361e-37, 1.6768933675263854e-35, 4.2210054325158127e-34, 9.7605477823793654e-33, 2.0771142264898199e-31, 4.0748381699253249e-30, 7.3810648870417183e-29, 1.2363547377218958e-27, 1.9178022081467005e-26, 2.7586033246049575e-25, 3.6843129796217172e-24, 4.5743951370215857e-23, 5.2859323137468154e-22, 5.6910915175835955e-21, 5.7148760619818976e-20, 5.3577677281181046e-19, 4.6939007358067331e-18, 3.8463054439056453e-17, 2.9504021972772029e-16, 2.1202927606877813e-15, 1.4286304928072976e-14, 9.0316979019406731e-14, 5.3609851542957339e-13, 2.9897229802024487e-12, 1.5674715085860065e-11, 7.7305137154009676e-11, 3.5884068378224706e-10, 1.5685984370316076e-09, 6.4603917825466764e-09, 2.5081389998281072e-08, 9.1830644706366585e-08, 3.1721513586827257e-07, 1.0342536339020313e-06, 3.1840053712593505e-06, 9.2587247391013518e-06, 2.5439403557345701e-05, 6.6066258510845340e-05, 1.6221813086114782e-04, 3.7669274161032700e-04, 8.2747754872833888e-04, 1.7199311750936504e-03, 3.3833630340537615e-03, 6.3002503573431189e-03, 1.1107594867856934e-02, 1.8544242319012489e-02, 2.9321853906612717e-02, 4.3916343744405027e-02, 6.2311084328469719e-02, 8.3763283089409293e-02, 1.0669133852506041e-01, 1.2877234499448006e-01, 1.4728481639742919e-01, 1.5964391640203837e-01, 1.6398949726573361e-01, 1.5964391640203837e-01, 1.4728481639742919e-01, 1.2877234499448006e-01, 1.0669133852506041e-01, 8.3763283089409293e-02, 6.2311084328469719e-02, 4.3916343744405027e-02, 2.9321853906612717e-02, 1.8544242319012489e-02, 1.1107594867856934e-02, 6.3002503573431189e-03, 3.3833630340537615e-03, 1.7199311750936504e-03, 8.2747754872833888e-04, 3.7669274161032700e-04, 1.6221813086114782e-04, 6.6066258510845340e-05, 2.5439403557345701e-05, 9.2587247391013518e-06, 3.1840053712593505e-06, 1.0342536339020313e-06, 3.1721513586827257e-07, 9.1830644706366585e-08, 2.5081389998281072e-08, 6.4603917825466764e-09, 1.5685984370316076e-09, 3.5884068378224706e-10, 7.7305137154009676e-11, 1.5674715085860065e-11, 2.9897229802024487e-12, 5.3609851542957339e-13, 9.0316979019406731e-14, 1.4286304928072976e-14, 2.1202927606877813e-15, 2.9504021972772029e-16, 3.8463054439056453e-17, 4.6939007358067331e-18, 5.3577677281181046e-19, 5.7148760619818976e-20, 5.6910915175835955e-21, 5.2859323137468154e-22, 4.5743951370215857e-23, 3.6843129796217172e-24, 2.7586033246049575e-25, 1.9178022081467005e-26, 1.2363547377218958e-27, 7.3810648870417183e-29, 4.0748381699253249e-30, 2.0771142264898199e-31, 9.7605477823793654e-33, 4.2210054325158127e-34, 1.6768933675263854e-35, 6.1082242612809361e-37, 2.0359401385923293e-38, 6.1961228512356421e-40, 1.7178434457904729e-41, 4.3280559299142535e-43, 9.8835394906743943e-45, 2.0399882317508400e-46, 3.7943396524379168e-48, 6.3392777437739552e-50, 9.4805533849020122e-52, 1.2644313857762022e-53, 1.4978576876165396e-55, 1.5691297806630218e-57, 1.4467547750792869e-59, 1.1679600204323236e-61, 8.2091330064948600e-64, 4.9923292649319471e-66, 2.6089921702855559e-68, 1.1628357927637541e-70, 4.3831680288373217e-73, 1.3842194496021173e-75, 3.6240329528761601e-78, 7.7728521820677718e-81, 1.3473832322197353e-83, 1.8586066284522124e-86, 2.0039262792917714e-89, 1.6537960518565174e-92, 1.0191828364399763e-95, 4.5535119727458115e-99, 1.4228368487505154e-102, 2.9740999490947605e-106, 3.9308789125198654e-110, 3.0530327446766110e-114, 1.2623847464849609e-118, 2.4174491971248305e-123, 1.7390228685740816e-128, 3.3286398376690490e-134, 8.7701238593349446e-141, 5.8866637956879832e-149}, {8.3581373975539108e-150, 1.2928412877755577e-141, 5.0632382588324120e-135, 2.7209602221952139e-129, 3.8829389622015062e-124, 2.0785832875875387e-119, 5.1477595408996125e-115, 6.7815072200124497e-111, 5.2462701695642363e-107, 2.5648912231375885e-103, 8.3845258592424195e-100, 1.9161630252069163e-96, 3.1736968736455641e-93, 3.9241298067673186e-90, 3.7129493377218318e-87, 2.7453553081368732e-84, 1.6150344379416257e-81, 7.6774327866656284e-79, 2.9894343828423281e-76, 9.6489070550182607e-74, 2.6089586336270140e-71, 5.9654008943367430e-69, 1.1631966527487701e-66, 1.9489490740739864e-64, 2.8252664298663074e-62, 3.5656104439409607e-60, 3.9399315442250632e-58, 3.8315828065199010e-56, 3.2951200002417535e-54, 2.5169328462380233e-52, 1.7144956007470846e-50, 1.0454204091183458e-48, 5.7258874684495484e-47, 2.8261341310391440e-45, 1.2607977361040919e-43, 5.0982121558902017e-42, 1.8734745650648728e-40, 6.2719136180711063e-39, 1.9172254945419127e-37, 5.3629616050774624e-36, 1.3755486543958331e-34, 3.2412811142581749e-33, 7.0292474203881568e-32, 1.4053678782835759e-30, 2.5945192595304142e-29, 4.4296347519346036e-28, 7.0039976811745699e-27, 1.0270246629696484e-25, 1.3983996188477357e-24, 1.7702189074849013e-23, 2.0857890645994067e-22, 2.2900155277371847e-21, 2.3452218050389733e-20, 2.2425235675550114e-19, 2.0040402270860207e-18, 1.6752540366716003e-17, 1.3110796195605400e-16, 9.6139706301947510e-16, 6.6105224464386113e-15, 4.2652608433469510e-14, 2.5842479214605026e-13, 1.4712572098023350e-12, 7.8755658569412608e-12, 3.9661851656268533e-11, 1.8802196827204209e-10, 8.3950345085448172e-10, 3.5321294226177634e-09, 1.4010751708171831e-08, 5.2419925848831286e-08, 1.8506755890537394e-07, 6.1679613744986908e-07, 1.9413286157507076e-06, 5.7724680860172742e-06, 1.6221044402072930e-05, 4.3091495767535577e-05, 1.0825095642068624e-04, 2.5723066429963950e-04, 5.7833524878596126e-04, 1.2305790314187559e-03, 2.4786280618533298e-03, 4.7269014592664482e-03, 8.5366761761569536e-03, 1.4602406139195508e-02, 2.3662049334306538e-02, 3.6327402988086469e-02, 5.2847573265457019e-02, 7.2857131060649991e-02, 9.5195424202311488e-02, 1.1789377323403843e-01, 1.3839596229316664e-01, 1.5400468068882942e-01, 1.6245602140829696e-01, 1.6245602140829696e-01, 1.5400468068882942e-01, 1.3839596229316664e-01, 1.1789377323403843e-01, 9.5195424202311488e-02, 7.2857131060649991e-02, 5.2847573265457019e-02, 3.6327402988086469e-02, 2.3662049334306538e-02, 1.4602406139195508e-02, 8.5366761761569536e-03, 4.7269014592664482e-03, 2.4786280618533298e-03, 1.2305790314187559e-03, 5.7833524878596126e-04, 2.5723066429963950e-04, 1.0825095642068624e-04, 4.3091495767535577e-05, 1.6221044402072930e-05, 5.7724680860172742e-06, 1.9413286157507076e-06, 6.1679613744986908e-07, 1.8506755890537394e-07, 5.2419925848831286e-08, 1.4010751708171831e-08, 3.5321294226177634e-09, 8.3950345085448172e-10, 1.8802196827204209e-10, 3.9661851656268533e-11, 7.8755658569412608e-12, 1.4712572098023350e-12, 2.5842479214605026e-13, 4.2652608433469510e-14, 6.6105224464386113e-15, 9.6139706301947510e-16, 1.3110796195605400e-16, 1.6752540366716003e-17, 2.0040402270860207e-18, 2.2425235675550114e-19, 2.3452218050389733e-20, 2.2900155277371847e-21, 2.0857890645994067e-22, 1.7702189074849013e-23, 1.3983996188477357e-24, 1.0270246629696484e-25, 7.0039976811745699e-27, 4.4296347519346036e-28, 2.5945192595304142e-29, 1.4053678782835759e-30, 7.0292474203881568e-32, 3.2412811142581749e-33, 1.3755486543958331e-34, 5.3629616050774624e-36, 1.9172254945419127e-37, 6.2719136180711063e-39, 1.8734745650648728e-40, 5.0982121558902017e-42, 1.2607977361040919e-43, 2.8261341310391440e-45, 5.7258874684495484e-47, 1.0454204091183458e-48, 1.7144956007470846e-50, 2.5169328462380233e-52, 3.2951200002417535e-54, 3.8315828065199010e-56, 3.9399315442250632e-58, 3.5656104439409607e-60, 2.8252664298663074e-62, 1.9489490740739864e-64, 1.1631966527487701e-66, 5.9654008943367430e-69, 2.6089586336270140e-71, 9.6489070550182607e-74, 2.9894343828423281e-76, 7.6774327866656284e-79, 1.6150344379416257e-81, 2.7453553081368732e-84, 3.7129493377218318e-87, 3.9241298067673186e-90, 3.1736968736455641e-93, 1.9161630252069163e-96, 8.3845258592424195e-100, 2.5648912231375885e-103, 5.2462701695642363e-107, 6.7815072200124497e-111, 5.1477595408996125e-115, 2.0785832875875387e-119, 3.8829389622015062e-124, 2.7209602221952139e-129, 5.0632382588324120e-135, 1.2928412877755577e-141, 8.3581373975539108e-150}, {1.1865178694667318e-150, 1.9052328091840223e-142, 7.6984112043987381e-136, 4.2550288152769099e-130, 6.2327840907767578e-125, 3.4199371076928271e-120, 8.6723736530813987e-116, 1.1688387166643387e-111, 9.2447904963657574e-108, 4.6184277629201267e-104, 1.5419925530578493e-100, 3.5978676971165183e-97, 6.0819398055170106e-94, 7.6728915952440279e-91, 7.4056905596969795e-88, 5.5844689207576789e-85, 3.3498078614715179e-82, 1.6234441963286573e-79, 6.4436381052523653e-77, 2.1197593898507255e-74, 5.8410998823252364e-72, 1.3609591582325947e-69, 2.7039668570857215e-67, 4.6159532490505087e-65, 6.8172254689772145e-63, 8.7649300109604261e-61, 9.8662587260951024e-59, 9.7741261753796815e-57, 8.5624277958175666e-55, 6.6621826190749697e-53, 4.6227110569813219e-51, 2.8712161421730314e-49, 1.6018948070503715e-47, 8.0538675955345321e-46, 3.6600273200497822e-44, 1.5076237023555035e-42, 5.6437809696463000e-41, 1.9247883296069542e-39, 5.9942100762419949e-38, 1.7082702187606927e-36, 4.4641638317895058e-35, 1.0718010386176091e-33, 2.3684402708428834e-32, 4.8253003329308802e-31, 9.0781689354637632e-30, 1.5795898083977327e-28, 2.5455821620542874e-27, 3.8046791468512480e-26, 5.2807723431418099e-25, 6.8148555847519964e-24, 8.1865279023956756e-23, 9.1644244237263828e-22, 9.5703407786302617e-21, 9.3325018346830289e-20, 8.5060423271066705e-19, 7.2528021781457044e-18, 5.7903374085298744e-17, 4.3318599899726389e-16, 3.0391558780794568e-15, 2.0010535409370048e-14, 1.2373574238435096e-13, 7.1903669458823460e-13, 3.9291706318326725e-12, 2.0202524727399665e-11, 9.7794253591584735e-11, 4.4592266183083370e-10, 1.9163195825780139e-09, 7.7651658482449274e-09, 2.9683092240535501e-08, 1.0708625929490390e-07, 3.6475807440990068e-07, 1.1735270767794228e-06, 3.5674612381232805e-06, 1.0250735219808427e-05, 2.7849862113005195e-05, 7.1564447183165722e-05, 1.7398159469356308e-04, 4.0027477960329739e-04, 8.7170842819435444e-04, 1.7973955409015775e-03, 3.5096925793779445e-03, 6.4913282065116552e-03, 1.1374067733309335e-02, 1.8883705620831706e-02, 2.9710644677922813e-02, 4.4304476145580723e-02, 6.2624475272894761e-02, 8.3916039610710105e-02, 1.0660728151712012e-01, 1.2841023960066572e-01, 1.4665826336478710e-01, 1.5882689919380447e-01, 1.6310306755078369e-01, 1.5882689919380447e-01, 1.4665826336478710e-01, 1.2841023960066572e-01, 1.0660728151712012e-01, 8.3916039610710105e-02, 6.2624475272894761e-02, 4.4304476145580723e-02, 2.9710644677922813e-02, 1.8883705620831706e-02, 1.1374067733309335e-02, 6.4913282065116552e-03, 3.5096925793779445e-03, 1.7973955409015775e-03, 8.7170842819435444e-04, 4.0027477960329739e-04, 1.7398159469356308e-04, 7.1564447183165722e-05, 2.7849862113005195e-05, 1.0250735219808427e-05, 3.5674612381232805e-06, 1.1735270767794228e-06, 3.6475807440990068e-07, 1.0708625929490390e-07, 2.9683092240535501e-08, 7.7651658482449274e-09, 1.9163195825780139e-09, 4.4592266183083370e-10, 9.7794253591584735e-11, 2.0202524727399665e-11, 3.9291706318326725e-12, 7.1903669458823460e-13, 1.2373574238435096e-13, 2.0010535409370048e-14, 3.0391558780794568e-15, 4.3318599899726389e-16, 5.7903374085298744e-17, 7.2528021781457044e-18, 8.5060423271066705e-19, 9.3325018346830289e-20, 9.5703407786302617e-21, 9.1644244237263828e-22, 8.1865279023956756e-23, 6.8148555847519964e-24, 5.2807723431418099e-25, 3.8046791468512480e-26, 2.5455821620542874e-27, 1.5795898083977327e-28, 9.0781689354637632e-30, 4.8253003329308802e-31, 2.3684402708428834e-32, 1.0718010386176091e-33, 4.4641638317895058e-35, 1.7082702187606927e-36, 5.9942100762419949e-38, 1.9247883296069542e-39, 5.6437809696463000e-41, 1.5076237023555035e-42, 3.6600273200497822e-44, 8.0538675955345321e-46, 1.6018948070503715e-47, 2.8712161421730314e-49, 4.6227110569813219e-51, 6.6621826190749697e-53, 8.5624277958175666e-55, 9.7741261753796815e-57, 9.8662587260951024e-59, 8.7649300109604261e-61, 6.8172254689772145e-63, 4.6159532490505087e-65, 2.7039668570857215e-67, 1.3609591582325947e-69, 5.8410998823252364e-72, 2.1197593898507255e-74, 6.4436381052523653e-77, 1.6234441963286573e-79, 3.3498078614715179e-82, 5.5844689207576789e-85, 7.4056905596969795e-88, 7.6728915952440279e-91, 6.0819398055170106e-94, 3.5978676971165183e-97, 1.5419925530578493e-100, 4.6184277629201267e-104, 9.2447904963657574e-108, 1.1688387166643387e-111, 8.6723736530813987e-116, 3.4199371076928271e-120, 6.2327840907767578e-125, 4.2550288152769099e-130, 7.6984112043987381e-136, 1.9052328091840223e-142, 1.1865178694667318e-150}, {1.6840859823147192e-151, 2.8068259915465668e-143, 1.1700024361722009e-136, 6.6504100620446623e-131, 9.9982626870689096e-126, 5.6227251746796540e-121, 1.4598025546816272e-116, 2.0126980605111617e-112, 1.6274180017356631e-108, 8.3068317564996415e-105, 2.8324541894274240e-101, 6.7467686874093196e-98, 1.1639059887066096e-94, 1.4980806006797597e-91, 1.4748024918249946e-88, 1.1340919960793407e-85, 6.9358925722736469e-83, 3.4266063564656041e-80, 1.3862443412766689e-77, 4.6475320184424221e-75, 1.3049987561313226e-72, 3.0981254141048187e-70, 6.2713089100746324e-68, 1.0906635714604883e-65, 1.6409070764036964e-63, 2.1490689833897993e-61, 2.4641241627782225e-59, 2.4864657741894790e-57, 2.2186336768274302e-55, 1.7582563693437111e-53, 1.2426111111041695e-51, 7.8609642161410873e-50, 4.4670071717223134e-48, 2.2875134062797375e-46, 1.0588298166277823e-44, 4.4424843586907703e-43, 1.6939665809360599e-41, 5.8848055182020130e-40, 1.8668536705967508e-38, 5.4197686272780061e-37, 1.4428750537835282e-35, 3.5292920298964982e-34, 7.9458957717354865e-33, 1.6494369134608046e-31, 3.1620314656015991e-30, 5.6065555004969651e-29, 9.2077125425461603e-28, 1.4025749559057771e-26, 1.9841800348065493e-25, 2.6100548891439468e-24, 3.1962255598539348e-23, 3.6477448742277230e-22, 3.8838880473136030e-21, 3.8618679709476893e-20, 3.5894545533623586e-19, 3.1214143458455917e-18, 2.5417847367765562e-17, 1.9397457159226965e-16, 1.3883744241015343e-15, 9.3270625462533699e-15, 5.8852482736096351e-14, 3.4902504651461380e-13, 1.9466883562172841e-12, 1.0217552929953939e-11, 5.0496076724281894e-11, 2.3510718451740779e-10, 1.0318035977700679e-09, 4.2703647703012249e-09, 1.6675261164947539e-08, 6.1462809064451552e-08, 2.1392739679622303e-07, 7.0340742267172300e-07, 2.1857314406758851e-06, 6.4208055079598766e-06, 1.7837324122194181e-05, 4.6876297088489141e-05, 1.1657026717177768e-04, 2.7438000977925001e-04, 6.1144669240944507e-04, 1.2903563124214057e-03, 2.5792975144676013e-03, 4.8845246714536682e-03, 8.7650270802736002e-03, 1.4906240076216418e-02, 2.4028883068628805e-02, 3.6720571883816493e-02, 5.3204522444878222e-02, 7.3096572483403829e-02, 9.5234476669428525e-02, 1.1767191582495477e-01, 1.3789832745338026e-01, 1.5327533388369177e-01, 1.6159415788497841e-01, 1.6159415788497841e-01, 1.5327533388369177e-01, 1.3789832745338026e-01, 1.1767191582495477e-01, 9.5234476669428525e-02, 7.3096572483403829e-02, 5.3204522444878222e-02, 3.6720571883816493e-02, 2.4028883068628805e-02, 1.4906240076216418e-02, 8.7650270802736002e-03, 4.8845246714536682e-03, 2.5792975144676013e-03, 1.2903563124214057e-03, 6.1144669240944507e-04, 2.7438000977925001e-04, 1.1657026717177768e-04, 4.6876297088489141e-05, 1.7837324122194181e-05, 6.4208055079598766e-06, 2.1857314406758851e-06, 7.0340742267172300e-07, 2.1392739679622303e-07, 6.1462809064451552e-08, 1.6675261164947539e-08, 4.2703647703012249e-09, 1.0318035977700679e-09, 2.3510718451740779e-10, 5.0496076724281894e-11, 1.0217552929953939e-11, 1.9466883562172841e-12, 3.4902504651461380e-13, 5.8852482736096351e-14, 9.3270625462533699e-15, 1.3883744241015343e-15, 1.9397457159226965e-16, 2.5417847367765562e-17, 3.1214143458455917e-18, 3.5894545533623586e-19, 3.8618679709476893e-20, 3.8838880473136030e-21, 3.6477448742277230e-22, 3.1962255598539348e-23, 2.6100548891439468e-24, 1.9841800348065493e-25, 1.4025749559057771e-26, 9.2077125425461603e-28, 5.6065555004969651e-29, 3.1620314656015991e-30, 1.6494369134608046e-31, 7.9458957717354865e-33, 3.5292920298964982e-34, 1.4428750537835282e-35, 5.4197686272780061e-37, 1.8668536705967508e-38, 5.8848055182020130e-40, 1.6939665809360599e-41, 4.4424843586907703e-43, 1.0588298166277823e-44, 2.2875134062797375e-46, 4.4670071717223134e-48, 7.8609642161410873e-50, 1.2426111111041695e-51, 1.7582563693437111e-53, 2.2186336768274302e-55, 2.4864657741894790e-57, 2.4641241627782225e-59, 2.1490689833897993e-61, 1.6409070764036964e-63, 1.0906635714604883e-65, 6.2713089100746324e-68, 3.0981254141048187e-70, 1.3049987561313226e-72, 4.6475320184424221e-75, 1.3862443412766689e-77, 3.4266063564656041e-80, 6.9358925722736469e-83, 1.1340919960793407e-85, 1.4748024918249946e-88, 1.4980806006797597e-91, 1.1639059887066096e-94, 6.7467686874093196e-98, 2.8324541894274240e-101, 8.3068317564996415e-105, 1.6274180017356631e-108, 2.0126980605111617e-112, 1.4598025546816272e-116, 5.6227251746796540e-121, 9.9982626870689096e-126, 6.6504100620446623e-131, 1.1700024361722009e-136, 2.8068259915465668e-143, 1.6840859823147192e-151}, {2.3899020087783538e-152, 4.1337932844079439e-144, 1.7774077118017352e-137, 1.0388721680141190e-131, 1.6028413383110423e-126, 9.2375467812799180e-122, 2.4552181378752603e-117, 3.4625987620456931e-113, 2.8619431556076958e-109, 1.4924416386535932e-105, 5.1966730435893490e-102, 1.2635422959480214e-98, 2.2243270327788831e-95, 2.9206395863825604e-92, 2.9324498160004818e-89, 2.2993488113263748e-86, 1.4336286376453945e-83, 7.2194564657826763e-81, 2.9766194663244294e-78, 1.0169377873705381e-75, 2.9095299074235018e-73, 7.0373804171328241e-71, 1.4512217440971957e-68, 2.5709836724164109e-66, 3.9400295587538806e-64, 5.2559492672815257e-62, 6.1380579859214437e-60, 6.3081846096424608e-58, 5.7325826101059963e-56, 4.6268156176755226e-54, 3.3301662675561347e-52, 2.1455339764954737e-50, 1.2416693105547687e-48, 6.4756889941564796e-47, 3.0527217350206308e-45, 1.3044685923509235e-43, 5.0660482804550958e-42, 1.7925263383158762e-40, 5.7919770166825449e-39, 1.7127600543267554e-37, 4.6447431828997982e-36, 1.1573309534274821e-34, 2.6544306695450948e-33, 5.6136594541327730e-32, 1.0964361374105204e-30, 1.9808277135032592e-29, 3.3148509472564812e-28, 5.1455269820153546e-27, 7.4183584908683151e-26, 9.9456309833303069e-25, 1.2413968193571878e-23, 1.4441897483451718e-22, 1.5675836145616411e-21, 1.5891496108132932e-20, 1.5060515461273932e-19, 1.3355156911983980e-18, 1.1090885964042391e-17, 8.6327149787564008e-17, 6.3027647004538790e-16, 4.3195605416094461e-15, 2.7808623921464611e-14, 1.6828396856093499e-13, 9.5787095713446750e-13, 5.1314070230067691e-12, 2.5887038946092999e-11, 1.2305056649947358e-10, 5.5140053605655075e-10, 2.3304976685688244e-09, 9.2946430660480328e-09, 3.4995595911608765e-08, 1.2444418429985038e-07, 4.1810988437722446e-07, 1.3277780039510742e-06, 3.9868978854768734e-06, 1.1323113503918158e-05, 3.0426750494245559e-05, 7.7380888614623922e-05, 1.8630373980043952e-04, 4.2474911952990744e-04, 9.1721684584915764e-04, 1.8764550081725386e-03, 3.6376544190370392e-03, 6.6835183409171238e-03, 1.1640333062329629e-02, 1.9220794786116900e-02, 3.0094363212091947e-02, 4.4685050904584946e-02, 6.2929070893539232e-02, 8.4060967557359437e-02, 1.0651895867711307e-01, 1.2804948653534245e-01, 1.4603926334720602e-01, 1.5802227437713226e-01, 1.6223085863339984e-01, 1.5802227437713226e-01, 1.4603926334720602e-01, 1.2804948653534245e-01, 1.0651895867711307e-01, 8.4060967557359437e-02, 6.2929070893539232e-02, 4.4685050904584946e-02, 3.0094363212091947e-02, 1.9220794786116900e-02, 1.1640333062329629e-02, 6.6835183409171238e-03, 3.6376544190370392e-03, 1.8764550081725386e-03, 9.1721684584915764e-04, 4.2474911952990744e-04, 1.8630373980043952e-04, 7.7380888614623922e-05, 3.0426750494245559e-05, 1.1323113503918158e-05, 3.9868978854768734e-06, 1.3277780039510742e-06, 4.1810988437722446e-07, 1.2444418429985038e-07, 3.4995595911608765e-08, 9.2946430660480328e-09, 2.3304976685688244e-09, 5.5140053605655075e-10, 1.2305056649947358e-10, 2.5887038946092999e-11, 5.1314070230067691e-12, 9.5787095713446750e-13, 1.6828396856093499e-13, 2.7808623921464611e-14, 4.3195605416094461e-15, 6.3027647004538790e-16, 8.6327149787564008e-17, 1.1090885964042391e-17, 1.3355156911983980e-18, 1.5060515461273932e-19, 1.5891496108132932e-20, 1.5675836145616411e-21, 1.4441897483451718e-22, 1.2413968193571878e-23, 9.9456309833303069e-25, 7.4183584908683151e-26, 5.1455269820153546e-27, 3.3148509472564812e-28, 1.9808277135032592e-29, 1.0964361374105204e-30, 5.6136594541327730e-32, 2.6544306695450948e-33, 1.1573309534274821e-34, 4.6447431828997982e-36, 1.7127600543267554e-37, 5.7919770166825449e-39, 1.7925263383158762e-40, 5.0660482804550958e-42, 1.3044685923509235e-43, 3.0527217350206308e-45, 6.4756889941564796e-47, 1.2416693105547687e-48, 2.1455339764954737e-50, 3.3301662675561347e-52, 4.6268156176755226e-54, 5.7325826101059963e-56, 6.3081846096424608e-58, 6.1380579859214437e-60, 5.2559492672815257e-62, 3.9400295587538806e-64, 2.5709836724164109e-66, 1.4512217440971957e-68, 7.0373804171328241e-71, 2.9095299074235018e-73, 1.0169377873705381e-75, 2.9766194663244294e-78, 7.2194564657826763e-81, 1.4336286376453945e-83, 2.2993488113263748e-86, 2.9324498160004818e-89, 2.9206395863825604e-92, 2.2243270327788831e-95, 1.2635422959480214e-98, 5.1966730435893490e-102, 1.4924416386535932e-105, 2.8619431556076958e-109, 3.4625987620456931e-113, 2.4552181378752603e-117, 9.2375467812799180e-122, 1.6028413383110423e-126, 1.0388721680141190e-131, 1.7774077118017352e-137, 4.1337932844079439e-144, 2.3899020087783538e-152}, {3.3909583926202969e-153, 6.0862398111746403e-145, 2.6990049104808299e-138, 1.6219807504695568e-132, 2.5679266269176032e-127, 1.5165281109964923e-122, 4.1260001698114066e-118, 5.9515348152406019e-114, 5.0279031031404388e-110, 2.6784561524395333e-106, 9.5230206639834012e-103, 2.3633738761330501e-99, 4.2451210579798656e-96, 5.6858261506014681e-93, 5.8218672370402156e-90, 4.6543449390713426e-87, 2.9582182277022238e-84, 1.5183294739007438e-81, 6.3795487359338829e-79, 2.2208089866950920e-76, 6.4735410582641528e-74, 1.5951103254298808e-71, 3.3507196700207861e-69, 6.0464069117443835e-67, 9.4376753651859668e-65, 1.2822191213791653e-62, 1.5249989655376484e-60, 1.5960849625455376e-58, 1.4770796663837213e-56, 1.2140312147914462e-54, 8.8982101270994950e-53, 5.8379315269148491e-51, 3.4404622652833074e-49, 1.8272036259234053e-47, 8.7716947482766774e-46, 3.8170926065847122e-44, 1.5096656333028563e-42, 5.4400265472252386e-41, 1.7901934646856910e-39, 5.3916646781027312e-38, 1.4892193296848201e-36, 3.7795868784349260e-35, 8.8301666493717958e-34, 1.9022911023392480e-32, 3.7850530748490676e-31, 6.9665700818714156e-30, 1.1878115612451122e-28, 1.8786842016880562e-27, 2.7599602414845152e-26, 3.7707755724079553e-25, 4.7967389479007740e-24, 5.6876402480164174e-23, 6.2928558569586138e-22, 6.5032337700285951e-21, 6.2833568961437137e-20, 5.6810615766852734e-19, 4.8108093342629945e-18, 3.8186952800271027e-17, 2.8435455634715359e-16, 1.9878218878928244e-15, 1.3054944744238950e-14, 8.0602086244990039e-14, 4.6813428453581271e-13, 2.5592533379055519e-12, 1.3177335517890257e-11, 6.3937241128218932e-11, 2.9249655637661996e-10, 1.2622501489006109e-09, 5.1408413936157202e-09, 1.9768915482746416e-08, 7.1808683672368473e-08, 2.4648607700088249e-07, 7.9982594734022375e-07, 2.4543893859357136e-06, 7.1249965705005385e-06, 1.9573063938461480e-05, 5.0897601014117974e-05, 1.2532087255275024e-04, 2.9224860429386435e-04, 6.4564239421835911e-04, 1.3515815953737001e-03, 2.6816113762841770e-03, 5.0435720589444479e-03, 8.9938955083231700e-03, 1.5208840297800851e-02, 2.4392011104876491e-02, 3.7107373608297196e-02, 5.3553162455639902e-02, 7.3327512502661077e-02, 9.5267294910895362e-02, 1.1744849271751398e-01, 1.3740517258624155e-01, 1.5255613196758108e-01, 1.6074586617490177e-01, 1.6074586617490177e-01, 1.5255613196758108e-01, 1.3740517258624155e-01, 1.1744849271751398e-01, 9.5267294910895362e-02, 7.3327512502661077e-02, 5.3553162455639902e-02, 3.7107373608297196e-02, 2.4392011104876491e-02, 1.5208840297800851e-02, 8.9938955083231700e-03, 5.0435720589444479e-03, 2.6816113762841770e-03, 1.3515815953737001e-03, 6.4564239421835911e-04, 2.9224860429386435e-04, 1.2532087255275024e-04, 5.0897601014117974e-05, 1.9573063938461480e-05, 7.1249965705005385e-06, 2.4543893859357136e-06, 7.9982594734022375e-07, 2.4648607700088249e-07, 7.1808683672368473e-08, 1.9768915482746416e-08, 5.1408413936157202e-09, 1.2622501489006109e-09, 2.9249655637661996e-10, 6.3937241128218932e-11, 1.3177335517890257e-11, 2.5592533379055519e-12, 4.6813428453581271e-13, 8.0602086244990039e-14, 1.3054944744238950e-14, 1.9878218878928244e-15, 2.8435455634715359e-16, 3.8186952800271027e-17, 4.8108093342629945e-18, 5.6810615766852734e-19, 6.2833568961437137e-20, 6.5032337700285951e-21, 6.2928558569586138e-22, 5.6876402480164174e-23, 4.7967389479007740e-24, 3.7707755724079553e-25, 2.7599602414845152e-26, 1.8786842016880562e-27, 1.1878115612451122e-28, 6.9665700818714156e-30, 3.7850530748490676e-31, 1.9022911023392480e-32, 8.8301666493717958e-34, 3.7795868784349260e-35, 1.4892193296848201e-36, 5.3916646781027312e-38, 1.7901934646856910e-39, 5.4400265472252386e-41, 1.5096656333028563e-42, 3.8170926065847122e-44, 8.7716947482766774e-46, 1.8272036259234053e-47, 3.4404622652833074e-49, 5.8379315269148491e-51, 8.8982101270994950e-53, 1.2140312147914462e-54, 1.4770796663837213e-56, 1.5960849625455376e-58, 1.5249989655376484e-60, 1.2822191213791653e-62, 9.4376753651859668e-65, 6.0464069117443835e-67, 3.3507196700207861e-69, 1.5951103254298808e-71, 6.4735410582641528e-74, 2.2208089866950920e-76, 6.3795487359338829e-79, 1.5183294739007438e-81, 2.9582182277022238e-84, 4.6543449390713426e-87, 5.8218672370402156e-90, 5.6858261506014681e-93, 4.2451210579798656e-96, 2.3633738761330501e-99, 9.5230206639834012e-103, 2.6784561524395333e-106, 5.0279031031404388e-110, 5.9515348152406019e-114, 4.1260001698114066e-118, 1.5165281109964923e-122, 2.5679266269176032e-127, 1.6219807504695568e-132, 2.6990049104808299e-138, 6.0862398111746403e-145, 3.3909583926202969e-153}, {4.8105196926800447e-154, 8.9581349097014215e-146, 4.0967387783316221e-139, 2.5310532151069106e-133, 4.1115283174204790e-128, 2.4878902559132056e-123, 6.9281121543161367e-119, 1.0220279314543827e-114, 8.8243129868960541e-111, 4.8017711254332563e-107, 1.7430737935309201e-103, 4.4149829449283152e-100, 8.0909195748902241e-97, 1.1053200966532163e-93, 1.1540787556182570e-90, 9.4062445961729118e-88, 6.0938287850722912e-85, 3.1875459729105427e-82, 1.3647333597873649e-79, 4.8404013281274901e-77, 1.4373955207015468e-74, 3.6078416607613653e-72, 7.7193542145188385e-70, 1.4187152411878090e-67, 2.2552327816162141e-65, 3.1202888315880434e-63, 3.7791134625824903e-61, 4.0276289664497742e-59, 3.7954127913999138e-57, 3.1764227614962876e-55, 2.3706043434701509e-53, 1.5836556658561472e-51, 9.5030686706332782e-50, 5.1390369637842554e-48, 2.5120644517965854e-46, 1.1131134062886865e-44, 4.4828688752777018e-43, 1.6449624113929946e-41, 5.5124888578291881e-40, 1.6907462404862362e-38, 4.7559672339276421e-37, 1.2293279880804420e-35, 2.9252024556839558e-34, 6.4187377483908620e-33, 1.3009300303447977e-31, 2.4391335868389452e-30, 4.2366796233867587e-29, 6.8268728000449227e-28, 1.0218585868330291e-26, 1.4225584486944289e-25, 1.8440385833763509e-24, 2.2283071036811595e-23, 2.5127294052122314e-22, 2.6467919286881548e-21, 2.6068354747780742e-20, 2.4028313064323887e-19, 2.0745586965632990e-18, 1.6791123823339180e-17, 1.2750493352152407e-16, 9.0906021055959760e-16, 6.0895673953539301e-15, 3.8353345411384518e-14, 2.2726043918949056e-13, 1.2676970629687990e-12, 6.6608945127799692e-12, 3.2985045445873824e-11, 1.5402785642655144e-10, 6.7857514014962344e-10, 2.8217661921664192e-09, 1.1080667611835489e-08, 4.1107393732952725e-08, 1.4413206230487042e-07, 4.7781084115403341e-07, 1.4981838617872995e-06, 4.4446553339045300e-06, 1.2480054945286184e-05, 3.3176731522024002e-05, 8.3524630257267974e-05, 1.9919419791658306e-04, 4.5012132211052618e-04, 9.6399635747843960e-04, 1.9570814745659979e-03, 3.7671919910449735e-03, 6.8767389146135380e-03, 1.1906303498193138e-02, 1.9555454063496128e-02, 3.0473029715843637e-02, 4.5058194694576482e-02, 6.3225096957716942e-02, 8.4198334040706369e-02, 1.0642658240453728e-01, 1.2769014695749564e-01, 1.4542767716486577e-01, 1.5722973246415300e-01, 1.6137249430200609e-01, 1.5722973246415300e-01, 1.4542767716486577e-01, 1.2769014695749564e-01, 1.0642658240453728e-01, 8.4198334040706369e-02, 6.3225096957716942e-02, 4.5058194694576482e-02, 3.0473029715843637e-02, 1.9555454063496128e-02, 1.1906303498193138e-02, 6.8767389146135380e-03, 3.7671919910449735e-03, 1.9570814745659979e-03, 9.6399635747843960e-04, 4.5012132211052618e-04, 1.9919419791658306e-04, 8.3524630257267974e-05, 3.3176731522024002e-05, 1.2480054945286184e-05, 4.4446553339045300e-06, 1.4981838617872995e-06, 4.7781084115403341e-07, 1.4413206230487042e-07, 4.1107393732952725e-08, 1.1080667611835489e-08, 2.8217661921664192e-09, 6.7857514014962344e-10, 1.5402785642655144e-10, 3.2985045445873824e-11, 6.6608945127799692e-12, 1.2676970629687990e-12, 2.2726043918949056e-13, 3.8353345411384518e-14, 6.0895673953539301e-15, 9.0906021055959760e-16, 1.2750493352152407e-16, 1.6791123823339180e-17, 2.0745586965632990e-18, 2.4028313064323887e-19, 2.6068354747780742e-20, 2.6467919286881548e-21, 2.5127294052122314e-22, 2.2283071036811595e-23, 1.8440385833763509e-24, 1.4225584486944289e-25, 1.0218585868330291e-26, 6.8268728000449227e-28, 4.2366796233867587e-29, 2.4391335868389452e-30, 1.3009300303447977e-31, 6.4187377483908620e-33, 2.9252024556839558e-34, 1.2293279880804420e-35, 4.7559672339276421e-37, 1.6907462404862362e-38, 5.5124888578291881e-40, 1.6449624113929946e-41, 4.4828688752777018e-43, 1.1131134062886865e-44, 2.5120644517965854e-46, 5.1390369637842554e-48, 9.5030686706332782e-50, 1.5836556658561472e-51, 2.3706043434701509e-53, 3.1764227614962876e-55, 3.7954127913999138e-57, 4.0276289664497742e-59, 3.7791134625824903e-61, 3.1202888315880434e-63, 2.2552327816162141e-65, 1.4187152411878090e-67, 7.7193542145188385e-70, 3.6078416607613653e-72, 1.4373955207015468e-74, 4.8404013281274901e-77, 1.3647333597873649e-79, 3.1875459729105427e-82, 6.0938287850722912e-85, 9.4062445961729118e-88, 1.1540787556182570e-90, 1.1053200966532163e-93, 8.0909195748902241e-97, 4.4149829449283152e-100, 1.7430737935309201e-103, 4.8017711254332563e-107, 8.8243129868960541e-111, 1.0220279314543827e-114, 6.9281121543161367e-119, 2.4878902559132056e-123, 4.1115283174204790e-128, 2.5310532151069106e-133, 4.0967387783316221e-139, 8.9581349097014215e-146, 4.8105196926800447e-154}, {6.8232197942250040e-155, 1.3181218114180107e-146, 6.2157350428501506e-140, 3.9475798303387850e-134, 6.5789265659620338e-129, 4.0785124308845132e-124, 1.1623859612267819e-119, 1.7535057075593614e-115, 1.5472021309193150e-111, 8.5990905704820439e-108, 3.1867892204083499e-104, 8.2372979129162400e-101, 1.5400245034982435e-97, 2.1456921017005163e-94, 2.2843171180826872e-91, 1.8979497846368726e-88, 1.2532102545185035e-85, 6.6801061673807505e-83, 2.9141025510545569e-80, 1.0529633740939257e-77, 3.1851858054210446e-75, 8.1431135103329952e-73, 1.7744839092477200e-70, 3.3212610596524388e-68, 5.3763688423964646e-66, 7.5746019148953009e-64, 9.3412200164700803e-62, 1.0136702052099045e-59, 9.7258603579728974e-58, 8.2874406983788114e-56, 6.2972157268746326e-54, 4.2830642136217272e-52, 2.6167460089856425e-50, 1.4407389710981317e-48, 7.1704184113766286e-47, 3.2349665837355912e-45, 1.3265135880257318e-43, 4.9561856762703143e-42, 1.6911721771605448e-40, 5.2817945954838791e-39, 1.5129382111557171e-37, 3.9824232345150253e-36, 9.6505627399970417e-35, 2.1566756583641779e-33, 4.4519543419059356e-32, 8.5019504368590908e-31, 1.5042535921639604e-29, 2.4692068347694563e-28, 3.7652687650201339e-27, 5.3404226168220292e-26, 7.0535560842160286e-25, 8.6851943617712193e-24, 9.9804891048351136e-23, 1.0714309730247980e-21, 1.0755595219737973e-20, 1.0105554063847399e-19, 8.8944609945993243e-19, 7.3396140181061249e-18, 5.6828205180213369e-17, 4.1316021764480691e-16, 2.8225916935311505e-15, 1.8132136826440378e-14, 1.0959822792780298e-13, 6.2370678258135157e-13, 3.3437645093788376e-12, 1.6897122210470246e-11, 8.0527347789629487e-11, 3.6211627179619072e-10, 1.5372205783801174e-09, 6.1632086713433375e-09, 2.3347964326766498e-08, 8.3606844554454458e-08, 2.8310992931625352e-07, 9.0687938435499206e-07, 2.7490144224436228e-06, 7.8882549269903193e-06, 2.1433661822155404e-05, 5.5163316323048505e-05, 1.3451233819198536e-04, 3.1084451589835123e-04, 6.8092260658474482e-04, 1.4142383035108275e-03, 2.7855275571971620e-03, 5.2039736325766575e-03, 9.2231946903286923e-03, 1.5510131997231313e-02, 2.4751412543080331e-02, 3.7487880444774385e-02, 5.3893671909463224e-02, 7.3550203638163128e-02, 9.5294126497036155e-02, 1.1722364672954393e-01, 1.3691645960749019e-01, 1.5184684526785858e-01, 1.5991079381814263e-01, 1.5991079381814263e-01, 1.5184684526785858e-01, 1.3691645960749019e-01, 1.1722364672954393e-01, 9.5294126497036155e-02, 7.3550203638163128e-02, 5.3893671909463224e-02, 3.7487880444774385e-02, 2.4751412543080331e-02, 1.5510131997231313e-02, 9.2231946903286923e-03, 5.2039736325766575e-03, 2.7855275571971620e-03, 1.4142383035108275e-03, 6.8092260658474482e-04, 3.1084451589835123e-04, 1.3451233819198536e-04, 5.5163316323048505e-05, 2.1433661822155404e-05, 7.8882549269903193e-06, 2.7490144224436228e-06, 9.0687938435499206e-07, 2.8310992931625352e-07, 8.3606844554454458e-08, 2.3347964326766498e-08, 6.1632086713433375e-09, 1.5372205783801174e-09, 3.6211627179619072e-10, 8.0527347789629487e-11, 1.6897122210470246e-11, 3.3437645093788376e-12, 6.2370678258135157e-13, 1.0959822792780298e-13, 1.8132136826440378e-14, 2.8225916935311505e-15, 4.1316021764480691e-16, 5.6828205180213369e-17, 7.3396140181061249e-18, 8.8944609945993243e-19, 1.0105554063847399e-19, 1.0755595219737973e-20, 1.0714309730247980e-21, 9.9804891048351136e-23, 8.6851943617712193e-24, 7.0535560842160286e-25, 5.3404226168220292e-26, 3.7652687650201339e-27, 2.4692068347694563e-28, 1.5042535921639604e-29, 8.5019504368590908e-31, 4.4519543419059356e-32, 2.1566756583641779e-33, 9.6505627399970417e-35, 3.9824232345150253e-36, 1.5129382111557171e-37, 5.2817945954838791e-39, 1.6911721771605448e-40, 4.9561856762703143e-42, 1.3265135880257318e-43, 3.2349665837355912e-45, 7.1704184113766286e-47, 1.4407389710981317e-48, 2.6167460089856425e-50, 4.2830642136217272e-52, 6.2972157268746326e-54, 8.2874406983788114e-56, 9.7258603579728974e-58, 1.0136702052099045e-59, 9.3412200164700803e-62, 7.5746019148953009e-64, 5.3763688423964646e-66, 3.3212610596524388e-68, 1.7744839092477200e-70, 8.1431135103329952e-73, 3.1851858054210446e-75, 1.0529633740939257e-77, 2.9141025510545569e-80, 6.6801061673807505e-83, 1.2532102545185035e-85, 1.8979497846368726e-88, 2.2843171180826872e-91, 2.1456921017005163e-94, 1.5400245034982435e-97, 8.2372979129162400e-101, 3.1867892204083499e-104, 8.5990905704820439e-108, 1.5472021309193150e-111, 1.7535057075593614e-115, 1.1623859612267819e-119, 4.0785124308845132e-124, 6.5789265659620338e-129, 3.9475798303387850e-134, 6.2157350428501506e-140, 1.3181218114180107e-146, 6.8232197942250040e-155}, {9.6764302762857911e-156, 1.9389386338649253e-147, 9.4268794388387584e-141, 6.1537049528839255e-135, 1.0520595245806230e-129, 6.6813621694344271e-125, 1.9486722540934962e-120, 3.0058398378782854e-116, 2.7101250640991562e-112, 1.5383037549430030e-108, 5.8195869131646608e-105, 1.5349872474118010e-101, 2.9274184968148517e-98, 4.1594648723850271e-95, 4.5147260427833628e-92, 3.8235833994762416e-89, 2.5729913678738507e-86, 1.3975076314494611e-83, 6.2111050589991735e-81, 2.2862048443444402e-78, 7.0441083482496365e-76, 1.8341247494924424e-73, 4.0702482203595230e-71, 7.7576584194845979e-69, 1.2786993882275677e-66, 1.8342905501305085e-64, 2.3031479777875351e-62, 2.5445408528816102e-60, 2.4855538228455434e-58, 2.1561995344944781e-56, 1.6679549705866419e-54, 1.1549259780000125e-52, 7.1833013403181687e-51, 4.0263574453603144e-49, 2.0400456628439797e-47, 9.3700002807816908e-46, 3.9116867251382951e-44, 1.4879647423347193e-42, 5.1693708373553046e-41, 1.6438042759677152e-39, 4.7942896465195374e-38, 1.2849980190682212e-36, 3.1708729314553754e-35, 7.2161081218241727e-34, 1.5169921976469880e-32, 2.9504597948207525e-31, 5.3168727228967571e-30, 8.8896336943576362e-29, 1.3808362593425483e-27, 1.9951324606202683e-26, 2.6846378493690218e-25, 3.3679964757574780e-24, 3.9436002250852672e-23, 4.3140992488603084e-22, 4.4134945997917874e-21, 4.2263869813792336e-20, 3.7916648002202093e-19, 3.1895272336827489e-18, 2.5176935915196902e-17, 1.8663270859468551e-16, 1.3001503435609439e-15, 8.5176175587843442e-15, 5.2510379021912937e-14, 3.0482099219006810e-13, 1.6671499873186635e-12, 8.5956677592000092e-12, 4.1801607084826671e-11, 1.9183890700529380e-10, 8.3123118452689150e-10, 3.4021150696080136e-09, 1.3158571431631216e-08, 4.8115154735048105e-08, 1.6639485157072335e-07, 5.4443385920665998e-07, 1.6859754012772494e-06, 4.9431447402619969e-06, 1.3725819438547434e-05, 3.6106464014912190e-05, 9.0004542316217840e-05, 2.1266213156628891e-04, 4.7639613833099480e-04, 1.0120395216254993e-03, 2.0392461173393923e-03, 3.8982490246164416e-03, 7.0709100790306376e-03, 1.2171895486539193e-02, 1.9887632287530231e-02, 3.0846667595353164e-02, 4.5424033501544080e-02, 6.3512773332392206e-02, 8.4328396273560896e-02, 1.0633035510412364e-01, 1.2733227690715612e-01, 1.4482336870308740e-01, 1.5644897465655389e-01, 1.6052761213288572e-01, 1.5644897465655389e-01, 1.4482336870308740e-01, 1.2733227690715612e-01, 1.0633035510412364e-01, 8.4328396273560896e-02, 6.3512773332392206e-02, 4.5424033501544080e-02, 3.0846667595353164e-02, 1.9887632287530231e-02, 1.2171895486539193e-02, 7.0709100790306376e-03, 3.8982490246164416e-03, 2.0392461173393923e-03, 1.0120395216254993e-03, 4.7639613833099480e-04, 2.1266213156628891e-04, 9.0004542316217840e-05, 3.6106464014912190e-05, 1.3725819438547434e-05, 4.9431447402619969e-06, 1.6859754012772494e-06, 5.4443385920665998e-07, 1.6639485157072335e-07, 4.8115154735048105e-08, 1.3158571431631216e-08, 3.4021150696080136e-09, 8.3123118452689150e-10, 1.9183890700529380e-10, 4.1801607084826671e-11, 8.5956677592000092e-12, 1.6671499873186635e-12, 3.0482099219006810e-13, 5.2510379021912937e-14, 8.5176175587843442e-15, 1.3001503435609439e-15, 1.8663270859468551e-16, 2.5176935915196902e-17, 3.1895272336827489e-18, 3.7916648002202093e-19, 4.2263869813792336e-20, 4.4134945997917874e-21, 4.3140992488603084e-22, 3.9436002250852672e-23, 3.3679964757574780e-24, 2.6846378493690218e-25, 1.9951324606202683e-26, 1.3808362593425483e-27, 8.8896336943576362e-29, 5.3168727228967571e-30, 2.9504597948207525e-31, 1.5169921976469880e-32, 7.2161081218241727e-34, 3.1708729314553754e-35, 1.2849980190682212e-36, 4.7942896465195374e-38, 1.6438042759677152e-39, 5.1693708373553046e-41, 1.4879647423347193e-42, 3.9116867251382951e-44, 9.3700002807816908e-46, 2.0400456628439797e-47, 4.0263574453603144e-49, 7.1833013403181687e-51, 1.1549259780000125e-52, 1.6679549705866419e-54, 2.1561995344944781e-56, 2.4855538228455434e-58, 2.5445408528816102e-60, 2.3031479777875351e-62, 1.8342905501305085e-64, 1.2786993882275677e-66, 7.7576584194845979e-69, 4.0702482203595230e-71, 1.8341247494924424e-73, 7.0441083482496365e-76, 2.2862048443444402e-78, 6.2111050589991735e-81, 1.3975076314494611e-83, 2.5729913678738507e-86, 3.8235833994762416e-89, 4.5147260427833628e-92, 4.1594648723850271e-95, 2.9274184968148517e-98, 1.5349872474118010e-101, 5.8195869131646608e-105, 1.5383037549430030e-108, 2.7101250640991562e-112, 3.0058398378782854e-116, 1.9486722540934962e-120, 6.6813621694344271e-125, 1.0520595245806230e-129, 6.1537049528839255e-135, 9.4268794388387584e-141, 1.9389386338649253e-147, 9.6764302762857911e-156}, {1.3720504154302014e-156, 2.8513090679363871e-148, 1.4291119261031478e-141, 9.5878345367776407e-136, 1.6813631090843168e-130, 1.0937641473652881e-125, 3.2642500496954800e-121, 5.1480442370317754e-117, 4.7425471562207601e-113, 2.7489983469746781e-109, 1.0615412978825736e-105, 2.8568935742124688e-102, 5.5574407262791218e-99, 8.0520048626328837e-96, 8.9097729474744936e-93, 7.6909567014190078e-90, 5.2740027603411657e-87, 2.9186112720938588e-84, 1.3214406564729561e-81, 4.9544462772840985e-79, 1.5547429149839197e-76, 4.1226034386806711e-74, 9.3161574688297957e-72, 1.8079563460381452e-69, 3.0341692292606370e-67, 4.4312923121519367e-65, 5.6644240327335667e-63, 6.3708774357395162e-61, 6.3351435391240280e-59, 5.5944362188420675e-57, 4.4053385520999193e-55, 3.1050807666511750e-53, 1.9659178072617245e-51, 1.1217013968671671e-49, 5.7853802707668581e-48, 2.7049816006551789e-46, 1.1495533915103732e-44, 4.4515141949278675e-43, 1.5743976688633690e-41, 5.0968507385634822e-40, 1.5134439954515047e-38, 4.1300163134837491e-37, 1.0376574212671890e-35, 2.4044973436406753e-34, 5.1472183288770750e-33, 1.0194603568070278e-31, 1.8709115794220601e-30, 3.1858380070837839e-29, 5.0402581729336372e-28, 7.4179265516977060e-27, 1.0167813330369454e-25, 1.2995016885518635e-24, 1.5502266336408172e-23, 1.7279241662380531e-22, 1.8012995272732974e-21, 1.7578400079602021e-20, 1.6072599968378759e-19, 1.3780640314290736e-18, 1.1088556613183840e-17, 8.3797787500377154e-17, 5.9519054533347666e-16, 3.9759844018964598e-15, 2.4996755476537754e-14, 1.4799417664726766e-13, 8.2563190162426826e-13, 4.3426586703108686e-12, 2.1547012918303077e-11, 1.0090299262094598e-10, 4.4618936758916388e-10, 1.8639520759198730e-09, 7.3594054861502447e-09, 2.7474235203608662e-08, 9.7018924643039030e-08, 3.2418977135736030e-07, 1.0254381425692049e-06, 3.0713815320154091e-06, 8.7138650801478641e-06, 2.3424552293210665e-05, 5.9681270208738333e-05, 1.4415391428196787e-04, 3.3017517124886084e-04, 7.1728665634025713e-04, 1.4783089544886255e-03, 2.8910036930282720e-03, 5.3656605093971325e-03, 9.4528407852602792e-03, 1.5810044685497838e-02, 2.5107070566959051e-02, 3.7862166097742164e-02, 5.4226226141723462e-02, 7.3764890309958767e-02, 9.5315208688082131e-02, 1.1699751277485990e-01, 1.3643214928471140e-01, 1.5114725119507466e-01, 1.5908860103657232e-01, 1.5908860103657232e-01, 1.5114725119507466e-01, 1.3643214928471140e-01, 1.1699751277485990e-01, 9.5315208688082131e-02, 7.3764890309958767e-02, 5.4226226141723462e-02, 3.7862166097742164e-02, 2.5107070566959051e-02, 1.5810044685497838e-02, 9.4528407852602792e-03, 5.3656605093971325e-03, 2.8910036930282720e-03, 1.4783089544886255e-03, 7.1728665634025713e-04, 3.3017517124886084e-04, 1.4415391428196787e-04, 5.9681270208738333e-05, 2.3424552293210665e-05, 8.7138650801478641e-06, 3.0713815320154091e-06, 1.0254381425692049e-06, 3.2418977135736030e-07, 9.7018924643039030e-08, 2.7474235203608662e-08, 7.3594054861502447e-09, 1.8639520759198730e-09, 4.4618936758916388e-10, 1.0090299262094598e-10, 2.1547012918303077e-11, 4.3426586703108686e-12, 8.2563190162426826e-13, 1.4799417664726766e-13, 2.4996755476537754e-14, 3.9759844018964598e-15, 5.9519054533347666e-16, 8.3797787500377154e-17, 1.1088556613183840e-17, 1.3780640314290736e-18, 1.6072599968378759e-19, 1.7578400079602021e-20, 1.8012995272732974e-21, 1.7279241662380531e-22, 1.5502266336408172e-23, 1.2995016885518635e-24, 1.0167813330369454e-25, 7.4179265516977060e-27, 5.0402581729336372e-28, 3.1858380070837839e-29, 1.8709115794220601e-30, 1.0194603568070278e-31, 5.1472183288770750e-33, 2.4044973436406753e-34, 1.0376574212671890e-35, 4.1300163134837491e-37, 1.5134439954515047e-38, 5.0968507385634822e-40, 1.5743976688633690e-41, 4.4515141949278675e-43, 1.1495533915103732e-44, 2.7049816006551789e-46, 5.7853802707668581e-48, 1.1217013968671671e-49, 1.9659178072617245e-51, 3.1050807666511750e-53, 4.4053385520999193e-55, 5.5944362188420675e-57, 6.3351435391240280e-59, 6.3708774357395162e-61, 5.6644240327335667e-63, 4.4312923121519367e-65, 3.0341692292606370e-67, 1.8079563460381452e-69, 9.3161574688297957e-72, 4.1226034386806711e-74, 1.5547429149839197e-76, 4.9544462772840985e-79, 1.3214406564729561e-81, 2.9186112720938588e-84, 5.2740027603411657e-87, 7.6909567014190078e-90, 8.9097729474744936e-93, 8.0520048626328837e-96, 5.5574407262791218e-99, 2.8568935742124688e-102, 1.0615412978825736e-105, 2.7489983469746781e-109, 4.7425471562207601e-113, 5.1480442370317754e-117, 3.2642500496954800e-121, 1.0937641473652881e-125, 1.6813631090843168e-130, 9.5878345367776407e-136, 1.4291119261031478e-141, 2.8513090679363871e-148, 1.3720504154302014e-156}, {1.9451569748580915e-157, 4.1917692496623074e-149, 2.1656533203264049e-142, 1.4930848367233329e-136, 2.6854744034643652e-131, 1.7892892532014627e-126, 5.4637061901241444e-122, 8.8092712504606827e-118, 8.2912095929290215e-114, 4.9074274510768621e-110, 1.9341588617846345e-106, 5.3107713773093621e-103, 1.0536661811562218e-99, 1.5565848726847315e-96, 1.7557722156935769e-93, 1.5446161289516271e-90, 1.0792867414624379e-87, 6.0849467639302215e-85, 2.8063950432169120e-82, 1.0716703469936493e-79, 3.4248444263060510e-77, 9.2475643800642814e-75, 2.1277914455786410e-72, 4.2042110347158325e-70, 7.1831202945319969e-68, 1.0679652291289812e-65, 1.3896846788334397e-63, 1.5910268843395548e-61, 1.6104220743828299e-59, 1.4475542666378789e-57, 1.1602357060613541e-55, 8.3238465917891379e-54, 5.3641275790400676e-52, 3.1152601083577022e-50, 1.6354424962643853e-48, 7.7832174172965086e-47, 3.3668417110773493e-45, 1.3271170300689291e-43, 4.7778763656316077e-42, 1.5745422805731105e-40, 4.7595446906951574e-39, 1.3222509215279862e-37, 3.3821840940140512e-36, 7.9793659216047449e-35, 1.7391569791608673e-33, 3.5073691468931601e-32, 6.5544111912453122e-31, 1.1365779583643404e-29, 1.8312631014871582e-28, 2.7449324565145490e-27, 3.8322872065908508e-26, 4.9890778549827656e-25, 6.0629582449560457e-24, 6.8848488569478251e-23, 7.3125997647970303e-22, 7.2714081831677253e-21, 6.7751229891684194e-20, 5.9201437592343701e-19, 4.8552433914811921e-18, 3.7401100817855975e-17, 2.7081193971598301e-16, 1.8444288831090382e-15, 1.1823696121971421e-14, 7.1386313730701460e-14, 4.0616946929687980e-13, 2.1791052221508088e-12, 1.1029706356088577e-11, 5.2697432068365651e-11, 2.3777643019834690e-10, 1.0136912013567245e-09, 4.0850156582808148e-09, 1.5567430501187781e-08, 5.6124175036636782e-08, 1.9149546201420412e-07, 6.1858506291091545e-07, 1.8924364481789124e-06, 5.4848459956508166e-06, 1.5064725177098550e-05, 3.9222592074287836e-05, 9.6829305369002766e-05, 2.2671622856088540e-04, 5.0357752441741071e-04, 1.0613379467370166e-03, 2.1229194690909154e-03, 4.0307696130016573e-03, 7.2659539954360898e-03, 1.2437029172215985e-02, 2.0217282655364367e-02, 3.1215303196211058e-02, 4.5782692483561545e-02, 6.3792314106331613e-02, 8.4451401972617260e-02, 1.0623046970193420e-01, 1.2697592765070259e-01, 1.4422620485622731e-01, 1.5567971237666092e-01, 1.5969586284722317e-01, 1.5567971237666092e-01, 1.4422620485622731e-01, 1.2697592765070259e-01, 1.0623046970193420e-01, 8.4451401972617260e-02, 6.3792314106331613e-02, 4.5782692483561545e-02, 3.1215303196211058e-02, 2.0217282655364367e-02, 1.2437029172215985e-02, 7.2659539954360898e-03, 4.0307696130016573e-03, 2.1229194690909154e-03, 1.0613379467370166e-03, 5.0357752441741071e-04, 2.2671622856088540e-04, 9.6829305369002766e-05, 3.9222592074287836e-05, 1.5064725177098550e-05, 5.4848459956508166e-06, 1.8924364481789124e-06, 6.1858506291091545e-07, 1.9149546201420412e-07, 5.6124175036636782e-08, 1.5567430501187781e-08, 4.0850156582808148e-09, 1.0136912013567245e-09, 2.3777643019834690e-10, 5.2697432068365651e-11, 1.1029706356088577e-11, 2.1791052221508088e-12, 4.0616946929687980e-13, 7.1386313730701460e-14, 1.1823696121971421e-14, 1.8444288831090382e-15, 2.7081193971598301e-16, 3.7401100817855975e-17, 4.8552433914811921e-18, 5.9201437592343701e-19, 6.7751229891684194e-20, 7.2714081831677253e-21, 7.3125997647970303e-22, 6.8848488569478251e-23, 6.0629582449560457e-24, 4.9890778549827656e-25, 3.8322872065908508e-26, 2.7449324565145490e-27, 1.8312631014871582e-28, 1.1365779583643404e-29, 6.5544111912453122e-31, 3.5073691468931601e-32, 1.7391569791608673e-33, 7.9793659216047449e-35, 3.3821840940140512e-36, 1.3222509215279862e-37, 4.7595446906951574e-39, 1.5745422805731105e-40, 4.7778763656316077e-42, 1.3271170300689291e-43, 3.3668417110773493e-45, 7.7832174172965086e-47, 1.6354424962643853e-48, 3.1152601083577022e-50, 5.3641275790400676e-52, 8.3238465917891379e-54, 1.1602357060613541e-55, 1.4475542666378789e-57, 1.6104220743828299e-59, 1.5910268843395548e-61, 1.3896846788334397e-63, 1.0679652291289812e-65, 7.1831202945319969e-68, 4.2042110347158325e-70, 2.1277914455786410e-72, 9.2475643800642814e-75, 3.4248444263060510e-77, 1.0716703469936493e-79, 2.8063950432169120e-82, 6.0849467639302215e-85, 1.0792867414624379e-87, 1.5446161289516271e-90, 1.7557722156935769e-93, 1.5565848726847315e-96, 1.0536661811562218e-99, 5.3107713773093621e-103, 1.9341588617846345e-106, 4.9074274510768621e-110, 8.2912095929290215e-114, 8.8092712504606827e-118, 5.4637061901241444e-122, 1.7892892532014627e-126, 2.6854744034643652e-131, 1.4930848367233329e-136, 2.1656533203264049e-142, 4.1917692496623074e-149, 1.9451569748580915e-157}, {2.7572081394930497e-158, 6.1606195891114038e-150, 3.2804813831912987e-143, 2.3239698294632731e-137, 4.2866809471010448e-132, 2.9250839726119467e-127, 9.1380522604480418e-123, 1.5061298645822260e-118, 1.4481443283610901e-114, 8.7515402609102180e-111, 3.5201601974984495e-107, 9.8605307314410817e-104, 1.9951459370163873e-100, 3.0050341197440912e-97, 3.4549517863933081e-94, 3.0974015995404665e-91, 2.2051316618251230e-88, 1.2664932443877347e-85, 5.9494906351077990e-83, 2.3137758798623088e-80, 7.5297591329388192e-78, 2.0701649292513591e-75, 4.8496085133984147e-73, 9.7550576247941725e-71, 1.6966738887834285e-68, 2.5677846130096429e-66, 3.4010587398231950e-64, 3.9632860731065032e-62, 4.0830488118084828e-60, 3.7353956966630745e-58, 3.0471769779359536e-56, 2.2249520894879323e-54, 1.4592805785267631e-52, 8.6253646389571326e-51, 4.6085517173721152e-49, 2.2322309293391554e-47, 9.8278883256522070e-46, 3.9428752392560041e-44, 1.4448263309190163e-42, 4.8464578191552559e-41, 1.4912109536234187e-39, 4.2170331394849629e-38, 1.0980633083650227e-36, 2.6372704388350129e-35, 5.8519678162563370e-34, 1.2015551933775674e-32, 2.2862239823374585e-31, 4.0367549228098398e-30, 6.6230590346823284e-29, 1.0109795409268771e-27, 1.4374775988383664e-26, 1.9060160602736751e-25, 2.3593174689076554e-24, 2.7291375088225280e-23, 2.9530245244292184e-22, 2.9916750627894004e-21, 2.8402168199630962e-20, 2.5289725099536307e-19, 2.1136880764547752e-18, 1.6594882054957410e-17, 1.2247874128456919e-16, 8.5035945941928308e-16, 5.5576041209463139e-15, 3.4212940713768145e-14, 1.9850553217879612e-13, 1.0861345804029464e-12, 5.6073947890454799e-12, 2.7329486591769151e-11, 1.2580856861713816e-10, 5.4727113377318889e-10, 2.2506273484860213e-09, 8.7538457447490308e-09, 3.2215483374955876e-08, 1.1221944492414074e-07, 3.7014154510322367e-07, 1.1564156154340975e-06, 3.4233275145786425e-06, 9.6051781722267405e-06, 2.5551197899130104e-05, 6.4459196331247565e-05, 1.5425452576992943e-04, 3.5024735925131938e-04, 7.5473297532327498e-04, 1.5437752230132358e-03, 2.9979972233121189e-03, 5.5285649600795095e-03, 9.6827528386239439e-03, 1.6108512025371353e-02, 2.5458972192611309e-02, 3.8230305479849361e-02, 5.4550997194724032e-02, 7.3971809106191291e-02, 9.5330768912038982e-02, 1.1677021831583778e-01, 1.3595220139257186e-01, 1.5045713397116045e-01, 1.5827896015320714e-01, 1.5827896015320714e-01, 1.5045713397116045e-01, 1.3595220139257186e-01, 1.1677021831583778e-01, 9.5330768912038982e-02, 7.3971809106191291e-02, 5.4550997194724032e-02, 3.8230305479849361e-02, 2.5458972192611309e-02, 1.6108512025371353e-02, 9.6827528386239439e-03, 5.5285649600795095e-03, 2.9979972233121189e-03, 1.5437752230132358e-03, 7.5473297532327498e-04, 3.5024735925131938e-04, 1.5425452576992943e-04, 6.4459196331247565e-05, 2.5551197899130104e-05, 9.6051781722267405e-06, 3.4233275145786425e-06, 1.1564156154340975e-06, 3.7014154510322367e-07, 1.1221944492414074e-07, 3.2215483374955876e-08, 8.7538457447490308e-09, 2.2506273484860213e-09, 5.4727113377318889e-10, 1.2580856861713816e-10, 2.7329486591769151e-11, 5.6073947890454799e-12, 1.0861345804029464e-12, 1.9850553217879612e-13, 3.4212940713768145e-14, 5.5576041209463139e-15, 8.5035945941928308e-16, 1.2247874128456919e-16, 1.6594882054957410e-17, 2.1136880764547752e-18, 2.5289725099536307e-19, 2.8402168199630962e-20, 2.9916750627894004e-21, 2.9530245244292184e-22, 2.7291375088225280e-23, 2.3593174689076554e-24, 1.9060160602736751e-25, 1.4374775988383664e-26, 1.0109795409268771e-27, 6.6230590346823284e-29, 4.0367549228098398e-30, 2.2862239823374585e-31, 1.2015551933775674e-32, 5.8519678162563370e-34, 2.6372704388350129e-35, 1.0980633083650227e-36, 4.2170331394849629e-38, 1.4912109536234187e-39, 4.8464578191552559e-41, 1.4448263309190163e-42, 3.9428752392560041e-44, 9.8278883256522070e-46, 2.2322309293391554e-47, 4.6085517173721152e-49, 8.6253646389571326e-51, 1.4592805785267631e-52, 2.2249520894879323e-54, 3.0471769779359536e-56, 3.7353956966630745e-58, 4.0830488118084828e-60, 3.9632860731065032e-62, 3.4010587398231950e-64, 2.5677846130096429e-66, 1.6966738887834285e-68, 9.7550576247941725e-71, 4.8496085133984147e-73, 2.0701649292513591e-75, 7.5297591329388192e-78, 2.3137758798623088e-80, 5.9494906351077990e-83, 1.2664932443877347e-85, 2.2051316618251230e-88, 3.0974015995404665e-91, 3.4549517863933081e-94, 3.0050341197440912e-97, 1.9951459370163873e-100, 9.8605307314410817e-104, 3.5201601974984495e-107, 8.7515402609102180e-111, 1.4481443283610901e-114, 1.5061298645822260e-118, 9.1380522604480418e-123, 2.9250839726119467e-127, 4.2866809471010448e-132, 2.3239698294632731e-137, 3.2804813831912987e-143, 6.1606195891114038e-150, 2.7572081394930497e-158}, {3.9076471690941080e-159, 9.0516231985655450e-151, 4.9672234319145855e-144, 3.6154341661312203e-138, 6.8385535268994495e-133, 4.7785893786651104e-128, 1.5271628772769884e-123, 2.5728411822428113e-119, 2.5269536248805626e-115, 1.5590872025715406e-111, 6.3995909265162004e-108, 1.8286346030132772e-104, 3.7730702714400253e-101, 5.7934780549600130e-98, 6.7888152108219864e-95, 6.2017960981784824e-92, 4.4982131286438984e-89, 2.6316100628013750e-86, 1.2590645102017268e-83, 4.9863539974326119e-81, 1.6522944213413452e-78, 4.6250118175679923e-76, 1.1030078970560833e-73, 2.2585685158900422e-71, 3.9985750751823772e-69, 6.1594934342804038e-67, 8.3034758916801791e-65, 9.8479077342924136e-63, 1.0325295240318946e-60, 9.6133222464273388e-59, 7.9807919503856858e-57, 5.9302840185272367e-55, 3.9582000609173701e-53, 2.3808961922219179e-51, 1.2945943475503535e-49, 6.3814434194007278e-48, 2.8592815645992017e-46, 1.1674410264648282e-44, 4.3538446893851820e-43, 1.4863772701012763e-41, 4.6548397931087811e-40, 1.3398281145584983e-38, 3.5510998957536425e-37, 8.6816489289737604e-36, 1.9610184560405483e-34, 4.0989946034555524e-33, 7.9401630700838486e-32, 1.4273966207691636e-30, 2.3845069143279796e-29, 3.7062734865446578e-28, 5.3663645149930618e-27, 7.2463592171380759e-26, 9.1353566359276092e-25, 1.0763247315298265e-23, 1.1863095918086436e-22, 1.2243177639523886e-21, 1.1841779286732196e-20, 1.0743199749303155e-19, 9.1494332489911347e-19, 7.3203566611052359e-18, 5.5063768554293231e-17, 3.8967149070515473e-16, 2.5960894208342548e-15, 1.6293142388397836e-14, 9.6386743368990212e-14, 5.3778391218729220e-13, 2.8314924455552075e-12, 1.4075632287720228e-11, 6.6097087557103094e-11, 2.9333592912411779e-10, 1.2308733220895705e-09, 4.8855519350876319e-09, 1.8350327790289198e-08, 6.5248828381395632e-08, 2.1971536691628579e-07, 7.0090428369282574e-07, 2.1189035330905069e-06, 6.0723051489799535e-06, 1.6501142336395539e-05, 4.2531734642799478e-05, 1.0400739885143485e-04, 2.4136469790269507e-04, 5.3166865805501619e-04, 1.1118823380073424e-03, 2.2080714903093502e-03, 4.1646982803793314e-03, 7.4617948415810062e-03, 1.2701628295481309e-02, 2.0544362511894173e-02, 3.1578965559564402e-02, 4.6134295845117745e-02, 6.4063927714297891e-02, 8.4567589743710897e-02, 1.0612711013185427e-01, 1.2662114600203433e-01, 1.4363605547026137e-01, 1.5492166682336009e-01, 1.5887690970441684e-01, 1.5492166682336009e-01, 1.4363605547026137e-01, 1.2662114600203433e-01, 1.0612711013185427e-01, 8.4567589743710897e-02, 6.4063927714297891e-02, 4.6134295845117745e-02, 3.1578965559564402e-02, 2.0544362511894173e-02, 1.2701628295481309e-02, 7.4617948415810062e-03, 4.1646982803793314e-03, 2.2080714903093502e-03, 1.1118823380073424e-03, 5.3166865805501619e-04, 2.4136469790269507e-04, 1.0400739885143485e-04, 4.2531734642799478e-05, 1.6501142336395539e-05, 6.0723051489799535e-06, 2.1189035330905069e-06, 7.0090428369282574e-07, 2.1971536691628579e-07, 6.5248828381395632e-08, 1.8350327790289198e-08, 4.8855519350876319e-09, 1.2308733220895705e-09, 2.9333592912411779e-10, 6.6097087557103094e-11, 1.4075632287720228e-11, 2.8314924455552075e-12, 5.3778391218729220e-13, 9.6386743368990212e-14, 1.6293142388397836e-14, 2.5960894208342548e-15, 3.8967149070515473e-16, 5.5063768554293231e-17, 7.3203566611052359e-18, 9.1494332489911347e-19, 1.0743199749303155e-19, 1.1841779286732196e-20, 1.2243177639523886e-21, 1.1863095918086436e-22, 1.0763247315298265e-23, 9.1353566359276092e-25, 7.2463592171380759e-26, 5.3663645149930618e-27, 3.7062734865446578e-28, 2.3845069143279796e-29, 1.4273966207691636e-30, 7.9401630700838486e-32, 4.0989946034555524e-33, 1.9610184560405483e-34, 8.6816489289737604e-36, 3.5510998957536425e-37, 1.3398281145584983e-38, 4.6548397931087811e-40, 1.4863772701012763e-41, 4.3538446893851820e-43, 1.1674410264648282e-44, 2.8592815645992017e-46, 6.3814434194007278e-48, 1.2945943475503535e-49, 2.3808961922219179e-51, 3.9582000609173701e-53, 5.9302840185272367e-55, 7.9807919503856858e-57, 9.6133222464273388e-59, 1.0325295240318946e-60, 9.8479077342924136e-63, 8.3034758916801791e-65, 6.1594934342804038e-67, 3.9985750751823772e-69, 2.2585685158900422e-71, 1.1030078970560833e-73, 4.6250118175679923e-76, 1.6522944213413452e-78, 4.9863539974326119e-81, 1.2590645102017268e-83, 2.6316100628013750e-86, 4.4982131286438984e-89, 6.2017960981784824e-92, 6.7888152108219864e-95, 5.7934780549600130e-98, 3.7730702714400253e-101, 1.8286346030132772e-104, 6.3995909265162004e-108, 1.5590872025715406e-111, 2.5269536248805626e-115, 2.5728411822428113e-119, 1.5271628772769884e-123, 4.7785893786651104e-128, 6.8385535268994495e-133, 3.6154341661312203e-138, 4.9672234319145855e-144, 9.0516231985655450e-151, 3.9076471690941080e-159}, {5.5372309477634655e-160, 1.3295499920372636e-151, 7.5182851789608105e-145, 5.6218117631932678e-139, 1.0903164404085858e-133, 7.8013060714659609e-129, 2.5502660858886434e-124, 4.3913191972243959e-120, 4.4053240904063359e-116, 2.7746976743925027e-112, 1.1621599260631149e-108, 3.3872112245822123e-105, 7.1263773535131733e-102, 1.1154449265558409e-98, 1.3320789562852151e-95, 1.2398999039839109e-92, 9.1613585633591115e-90, 5.4590825264344227e-87, 2.6598715295190543e-84, 1.0726407876436278e-81, 3.6188278671651930e-79, 1.0312393292677344e-76, 2.5035350436180196e-74, 5.2179989944251382e-72, 9.4025005576362417e-70, 1.4740979038429450e-67, 2.0223861173713801e-65, 2.4409225876304963e-63, 2.6043821060405426e-61, 2.4675003119821257e-59, 2.0845067543701599e-57, 1.5761631000101791e-55, 1.0705056723174281e-53, 6.5523461103489109e-52, 3.6254089691585309e-50, 1.8184989576075493e-48, 8.2913990414809887e-47, 3.4450097830357403e-45, 1.3074430076121838e-43, 4.5423930481987850e-42, 1.4477028628289723e-40, 4.2408968311262046e-39, 1.1439892419798912e-37, 2.8466218480726145e-36, 6.5448147609160573e-35, 1.3925226088255375e-33, 2.7459089931491756e-32, 5.0252446557042918e-31, 8.5465806757782117e-30, 1.3525065257212417e-28, 1.9939689031724527e-27, 2.7417253568038711e-26, 3.5198681528057952e-25, 4.2235075145104786e-24, 4.7412259196608422e-23, 4.9840723225381343e-22, 4.9106724438195655e-21, 4.5386744987288709e-20, 3.9382188462775671e-19, 3.2106160083645321e-18, 2.4610138689948007e-17, 1.7749316371092158e-16, 1.2052626919006545e-15, 7.7106596673007474e-15, 4.6502415038307999e-14, 2.6453661839732785e-13, 1.4202436007691954e-12, 7.2000553706787476e-12, 3.4484441377850428e-11, 1.5611080651132002e-10, 6.6828734274332115e-10, 2.7064654297770221e-09, 1.0373610614267088e-08, 3.7645745874679117e-08, 1.2939635385192320e-07, 4.2140690642224546e-07, 1.3007683229247929e-06, 3.8067496326313364e-06, 1.0565607635971951e-05, 2.7819080771995885e-05, 6.9504723426630250e-05, 1.6482276370905397e-04, 3.7106723611638040e-04, 7.9325913151483628e-04, 1.6106180017909323e-03, 3.1064654644112318e-03, 5.6926204501420372e-03, 9.9128527364234706e-03, 1.6405471669264392e-02, 2.5807108029946707e-02, 3.8592374515300572e-02, 5.4868153810335302e-02, 7.4171189043357108e-02, 9.5341025218153283e-02, 1.1654188378760408e-01, 1.3547657485442111e-01, 1.4977628436985038e-01, 1.5748155504372183e-01, 1.5748155504372183e-01, 1.4977628436985038e-01, 1.3547657485442111e-01, 1.1654188378760408e-01, 9.5341025218153283e-02, 7.4171189043357108e-02, 5.4868153810335302e-02, 3.8592374515300572e-02, 2.5807108029946707e-02, 1.6405471669264392e-02, 9.9128527364234706e-03, 5.6926204501420372e-03, 3.1064654644112318e-03, 1.6106180017909323e-03, 7.9325913151483628e-04, 3.7106723611638040e-04, 1.6482276370905397e-04, 6.9504723426630250e-05, 2.7819080771995885e-05, 1.0565607635971951e-05, 3.8067496326313364e-06, 1.3007683229247929e-06, 4.2140690642224546e-07, 1.2939635385192320e-07, 3.7645745874679117e-08, 1.0373610614267088e-08, 2.7064654297770221e-09, 6.6828734274332115e-10, 1.5611080651132002e-10, 3.4484441377850428e-11, 7.2000553706787476e-12, 1.4202436007691954e-12, 2.6453661839732785e-13, 4.6502415038307999e-14, 7.7106596673007474e-15, 1.2052626919006545e-15, 1.7749316371092158e-16, 2.4610138689948007e-17, 3.2106160083645321e-18, 3.9382188462775671e-19, 4.5386744987288709e-20, 4.9106724438195655e-21, 4.9840723225381343e-22, 4.7412259196608422e-23, 4.2235075145104786e-24, 3.5198681528057952e-25, 2.7417253568038711e-26, 1.9939689031724527e-27, 1.3525065257212417e-28, 8.5465806757782117e-30, 5.0252446557042918e-31, 2.7459089931491756e-32, 1.3925226088255375e-33, 6.5448147609160573e-35, 2.8466218480726145e-36, 1.1439892419798912e-37, 4.2408968311262046e-39, 1.4477028628289723e-40, 4.5423930481987850e-42, 1.3074430076121838e-43, 3.4450097830357403e-45, 8.2913990414809887e-47, 1.8184989576075493e-48, 3.6254089691585309e-50, 6.5523461103489109e-52, 1.0705056723174281e-53, 1.5761631000101791e-55, 2.0845067543701599e-57, 2.4675003119821257e-59, 2.6043821060405426e-61, 2.4409225876304963e-63, 2.0223861173713801e-65, 1.4740979038429450e-67, 9.4025005576362417e-70, 5.2179989944251382e-72, 2.5035350436180196e-74, 1.0312393292677344e-76, 3.6188278671651930e-79, 1.0726407876436278e-81, 2.6598715295190543e-84, 5.4590825264344227e-87, 9.1613585633591115e-90, 1.2398999039839109e-92, 1.3320789562852151e-95, 1.1154449265558409e-98, 7.1263773535131733e-102, 3.3872112245822123e-105, 1.1621599260631149e-108, 2.7746976743925027e-112, 4.4053240904063359e-116, 4.3913191972243959e-120, 2.5502660858886434e-124, 7.8013060714659609e-129, 1.0903164404085858e-133, 5.6218117631932678e-139, 7.5182851789608105e-145, 1.3295499920372636e-151, 5.5372309477634655e-160}, {7.8451635230016858e-161, 1.9523607750140259e-152, 1.1375077401246616e-145, 8.7373530318096058e-140, 1.7373540565570015e-134, 1.2727518873570116e-129, 4.2555627733290781e-125, 7.4887926040201802e-121, 7.6728599246194710e-117, 4.9331494690374170e-113, 2.1081805704508371e-109, 6.2668746307989698e-106, 1.3443162713188522e-102, 2.1447717307711369e-99, 2.6100910182768806e-96, 2.4752041309788718e-93, 1.8629470575327606e-90, 1.1305871177614866e-87, 5.6095106427386894e-85, 2.3032570747054949e-82, 7.9109829843002634e-80, 2.2948435687570354e-77, 5.6707499982586783e-75, 1.2029596296647568e-72, 2.2060845936398770e-70, 3.5197550034683429e-68, 4.9140189431762165e-66, 6.0352629400444085e-64, 6.5524291595185267e-62, 6.3168313216462770e-60, 5.4297718879402538e-58, 4.1774383436193032e-56, 2.8868574992210366e-54, 1.7978766039740882e-52, 1.0121575932082767e-50, 5.1657784424151435e-49, 2.3965562741555340e-47, 1.0131990990489010e-45, 3.9127390924870208e-44, 1.3832722270346481e-42, 4.4862136218811265e-41, 1.3373657357984576e-39, 3.6713213079441595e-38, 9.2972768440223579e-37, 2.1755444131733555e-35, 4.7112703089400342e-34, 9.4560355326075165e-33, 1.7615330473782583e-31, 3.0497304146140982e-30, 4.9132641478669298e-29, 7.3745987634168783e-28, 1.0324336757120609e-26, 1.3496248520015288e-25, 1.6490733800656049e-24, 1.8852558386853772e-23, 2.0184180321625388e-22, 2.0255846228536046e-21, 1.9070317011573267e-20, 1.6857232563417842e-19, 1.4001409738252677e-18, 1.0935411714915941e-17, 8.0367861053116616e-17, 5.5616740488492008e-16, 3.6264613629986606e-15, 2.2293626576566599e-14, 1.2928616191624445e-13, 7.0768307534960783e-13, 3.6582348996540792e-12, 1.7867762742843070e-11, 8.2498114987726634e-11, 3.6024058170237729e-10, 1.4883529382284672e-09, 5.8205576663344680e-09, 2.1554622191079048e-08, 7.5613014701765766e-08, 2.5135518772343285e-07, 7.9206548159012504e-07, 2.3667653844440894e-06, 6.7081316695963449e-06, 1.8039486708167727e-05, 4.6040475362243668e-05, 1.1154709040626857e-04, 2.5661526702463013e-04, 5.6067195570805187e-04, 1.1636625437784563e-03, 2.2946716387392549e-03, 4.2999800431004790e-03, 7.6583588130546571e-03, 1.2965620087982580e-02, 2.0868833143304531e-02, 3.1937686193532246e-02, 4.6478966725271985e-02, 6.4327817062627538e-02, 8.4677189450608162e-02, 1.0602045179435517e-01, 1.2626797462143288e-01, 1.4305279328441931e-01, 1.5417456855130846e-01, 1.5807042792926745e-01, 1.5417456855130846e-01, 1.4305279328441931e-01, 1.2626797462143288e-01, 1.0602045179435517e-01, 8.4677189450608162e-02, 6.4327817062627538e-02, 4.6478966725271985e-02, 3.1937686193532246e-02, 2.0868833143304531e-02, 1.2965620087982580e-02, 7.6583588130546571e-03, 4.2999800431004790e-03, 2.2946716387392549e-03, 1.1636625437784563e-03, 5.6067195570805187e-04, 2.5661526702463013e-04, 1.1154709040626857e-04, 4.6040475362243668e-05, 1.8039486708167727e-05, 6.7081316695963449e-06, 2.3667653844440894e-06, 7.9206548159012504e-07, 2.5135518772343285e-07, 7.5613014701765766e-08, 2.1554622191079048e-08, 5.8205576663344680e-09, 1.4883529382284672e-09, 3.6024058170237729e-10, 8.2498114987726634e-11, 1.7867762742843070e-11, 3.6582348996540792e-12, 7.0768307534960783e-13, 1.2928616191624445e-13, 2.2293626576566599e-14, 3.6264613629986606e-15, 5.5616740488492008e-16, 8.0367861053116616e-17, 1.0935411714915941e-17, 1.4001409738252677e-18, 1.6857232563417842e-19, 1.9070317011573267e-20, 2.0255846228536046e-21, 2.0184180321625388e-22, 1.8852558386853772e-23, 1.6490733800656049e-24, 1.3496248520015288e-25, 1.0324336757120609e-26, 7.3745987634168783e-28, 4.9132641478669298e-29, 3.0497304146140982e-30, 1.7615330473782583e-31, 9.4560355326075165e-33, 4.7112703089400342e-34, 2.1755444131733555e-35, 9.2972768440223579e-37, 3.6713213079441595e-38, 1.3373657357984576e-39, 4.4862136218811265e-41, 1.3832722270346481e-42, 3.9127390924870208e-44, 1.0131990990489010e-45, 2.3965562741555340e-47, 5.1657784424151435e-49, 1.0121575932082767e-50, 1.7978766039740882e-52, 2.8868574992210366e-54, 4.1774383436193032e-56, 5.4297718879402538e-58, 6.3168313216462770e-60, 6.5524291595185267e-62, 6.0352629400444085e-64, 4.9140189431762165e-66, 3.5197550034683429e-68, 2.2060845936398770e-70, 1.2029596296647568e-72, 5.6707499982586783e-75, 2.2948435687570354e-77, 7.9109829843002634e-80, 2.3032570747054949e-82, 5.6095106427386894e-85, 1.1305871177614866e-87, 1.8629470575327606e-90, 2.4752041309788718e-93, 2.6100910182768806e-96, 2.1447717307711369e-99, 1.3443162713188522e-102, 6.2668746307989698e-106, 2.1081805704508371e-109, 4.9331494690374170e-113, 7.6728599246194710e-117, 7.4887926040201802e-121, 4.2555627733290781e-125, 1.2727518873570116e-129, 1.7373540565570015e-134, 8.7373530318096058e-140, 1.1375077401246616e-145, 1.9523607750140259e-152, 7.8451635230016858e-161}, {1.1113325242665607e-161, 2.8661157405088651e-153, 1.7203699801925772e-146, 1.3572912678569801e-140, 2.7667745801693423e-135, 2.0750643806729351e-130, 7.0958232027421688e-126, 1.2760468594731325e-121, 1.3351777371855847e-117, 8.7619375020369923e-114, 3.8201658326880149e-110, 1.1581310985408031e-106, 2.5327817240407812e-103, 4.1185419255140006e-100, 5.1071272449783039e-97, 4.9339716820592914e-94, 3.7824070114676548e-91, 2.3376600104580566e-88, 1.1809947785806983e-85, 4.9369057800338342e-83, 1.7261669173831611e-80, 5.0968500275659627e-78, 1.2818807628470368e-75, 2.7674728413631406e-73, 5.1647694116231104e-71, 8.3851919880334988e-69, 1.1912098546399618e-66, 1.4886103795423663e-64, 1.6443955400649481e-62, 1.6129133242366921e-60, 1.4105633288272223e-58, 1.1041151603377387e-56, 7.7628198468094521e-55, 4.9186136364477312e-53, 2.8172193314312900e-51, 1.4628544044995270e-49, 6.9047962388108693e-48, 2.9700444136624115e-46, 1.1669783057995060e-44, 4.1977240232717920e-43, 1.3852328747381678e-41, 4.2018792516358609e-40, 1.1737667874934990e-38, 3.0248112870289189e-37, 7.2029787582674604e-36, 1.5874640120654814e-34, 3.2427846726141820e-33, 6.1484526840191010e-32, 1.0834946554226288e-30, 1.7768523467499803e-29, 2.7149541158618372e-28, 3.8695229489123667e-27, 5.1500223036312467e-26, 6.4071917092815282e-25, 7.4586793696524265e-24, 8.1320524064342075e-23, 8.3113512372523795e-22, 7.9697999021291434e-21, 7.1759828546746257e-20, 6.0717113565204395e-19, 4.8312403419891758e-18, 3.6176893189785955e-17, 2.5510691957075621e-16, 1.6951627656128116e-15, 1.0621010070430722e-14, 6.2782746989491113e-14, 3.5033054765081019e-13, 1.8463363234967078e-12, 9.1951726021293097e-12, 4.3294831001094053e-11, 1.9281472420443613e-10, 8.1257537810009703e-10, 3.2418174605425769e-09, 1.2248647054749650e-08, 4.3845698417608257e-08, 1.4875155394404803e-07, 4.7845376510326057e-07, 1.4594959469005024e-06, 4.2236041008124797e-06, 1.1598624726140732e-05, 3.0233694291010849e-05, 7.4825364488004140e-05, 1.7586687773524874e-04, 3.9264033171199677e-04, 8.3286186061158249e-04, 1.6788174607182051e-03, 3.2163656781061659e-03, 5.8577616753894349e-03, 1.0143065156003795e-02, 1.6700865101051256e-02, 2.6151472056325592e-02, 3.8948449958622955e-02, 5.5177861430971059e-02, 7.4363251819021731e-02, 9.5346186707308309e-02, 1.1631262299580138e-01, 1.3500522787142605e-01, 1.4910449946872065e-01, 1.5669608061804552e-01, 1.5669608061804552e-01, 1.4910449946872065e-01, 1.3500522787142605e-01, 1.1631262299580138e-01, 9.5346186707308309e-02, 7.4363251819021731e-02, 5.5177861430971059e-02, 3.8948449958622955e-02, 2.6151472056325592e-02, 1.6700865101051256e-02, 1.0143065156003795e-02, 5.8577616753894349e-03, 3.2163656781061659e-03, 1.6788174607182051e-03, 8.3286186061158249e-04, 3.9264033171199677e-04, 1.7586687773524874e-04, 7.4825364488004140e-05, 3.0233694291010849e-05, 1.1598624726140732e-05, 4.2236041008124797e-06, 1.4594959469005024e-06, 4.7845376510326057e-07, 1.4875155394404803e-07, 4.3845698417608257e-08, 1.2248647054749650e-08, 3.2418174605425769e-09, 8.1257537810009703e-10, 1.9281472420443613e-10, 4.3294831001094053e-11, 9.1951726021293097e-12, 1.8463363234967078e-12, 3.5033054765081019e-13, 6.2782746989491113e-14, 1.0621010070430722e-14, 1.6951627656128116e-15, 2.5510691957075621e-16, 3.6176893189785955e-17, 4.8312403419891758e-18, 6.0717113565204395e-19, 7.1759828546746257e-20, 7.9697999021291434e-21, 8.3113512372523795e-22, 8.1320524064342075e-23, 7.4586793696524265e-24, 6.4071917092815282e-25, 5.1500223036312467e-26, 3.8695229489123667e-27, 2.7149541158618372e-28, 1.7768523467499803e-29, 1.0834946554226288e-30, 6.1484526840191010e-32, 3.2427846726141820e-33, 1.5874640120654814e-34, 7.2029787582674604e-36, 3.0248112870289189e-37, 1.1737667874934990e-38, 4.2018792516358609e-40, 1.3852328747381678e-41, 4.1977240232717920e-43, 1.1669783057995060e-44, 2.9700444136624115e-46, 6.9047962388108693e-48, 1.4628544044995270e-49, 2.8172193314312900e-51, 4.9186136364477312e-53, 7.7628198468094521e-55, 1.1041151603377387e-56, 1.4105633288272223e-58, 1.6129133242366921e-60, 1.6443955400649481e-62, 1.4886103795423663e-64, 1.1912098546399618e-66, 8.3851919880334988e-69, 5.1647694116231104e-71, 2.7674728413631406e-73, 1.2818807628470368e-75, 5.0968500275659627e-78, 1.7261669173831611e-80, 4.9369057800338342e-83, 1.1809947785806983e-85, 2.3376600104580566e-88, 3.7824070114676548e-91, 4.9339716820592914e-94, 5.1071272449783039e-97, 4.1185419255140006e-100, 2.5327817240407812e-103, 1.1581310985408031e-106, 3.8201658326880149e-110, 8.7619375020369923e-114, 1.3351777371855847e-117, 1.2760468594731325e-121, 7.0958232027421688e-126, 2.0750643806729351e-130, 2.7667745801693423e-135, 1.3572912678569801e-140, 1.7203699801925772e-146, 2.8661157405088651e-153, 1.1113325242665607e-161}, {1.5740526693584465e-162, 4.2063621518212007e-154, 2.6008944296538456e-147, 2.1074517218240589e-141, 4.4036325515199439e-136, 3.3809077673415763e-131, 1.1822946408488032e-126, 2.1725144459735252e-122, 2.3212763347728001e-118, 1.5547020684816359e-114, 6.9150182989560957e-111, 2.1377995126059837e-107, 4.7660941708469085e-104, 7.8984266909061953e-101, 9.9792660546750878e-98, 9.8208576850538984e-95, 7.6677750665974574e-92, 4.8256764019125120e-89, 2.4821990706514334e-86, 1.0563282231662235e-83, 3.7595217722773437e-81, 1.1298318188883590e-78, 2.8919012660409682e-76, 6.3534513888384988e-74, 1.2065320173749644e-71, 1.9931390693715852e-69, 2.8809012333842463e-67, 3.6628479225209667e-65, 4.1164923961054212e-63, 4.1077464167348542e-61, 3.6546677508675100e-59, 2.9102221244239064e-57, 2.0815358697976881e-55, 1.3417085980893448e-53, 7.8178603818978630e-52, 4.1297412217775072e-50, 1.9830414431093633e-48, 8.6778002491153641e-47, 3.4688352621558211e-45, 1.2694602644562695e-43, 4.2621053825441441e-42, 1.3153901362816908e-40, 3.7386729623017851e-39, 9.8033645273483504e-38, 2.3754629195463299e-36, 5.3274424573468086e-35, 1.1074717912785746e-33, 2.1369895498120545e-32, 3.8327370697542584e-31, 6.3974120073582433e-30, 9.9497591435745215e-29, 1.4435514631174776e-27, 1.9558597204465646e-26, 2.4773098248022596e-25, 2.9362302035583120e-24, 3.2596930342072210e-23, 3.3925841234631972e-22, 3.3130211274194918e-21, 3.0381735933104597e-20, 2.6183914995557019e-19, 2.1223329298239927e-18, 1.6190413502935239e-17, 1.1632214089861438e-16, 7.8760411702639125e-16, 5.0287848550079939e-15, 3.0295892003599562e-14, 1.7231158339195911e-13, 9.2573881503227024e-13, 4.7003287276740161e-12, 2.2565549953554105e-11, 1.0248110528690129e-10, 4.4046822285487214e-10, 1.7924282778278772e-09, 6.9087593674811365e-09, 2.5232222625609405e-08, 8.7350604983433712e-08, 2.8673524946820525e-07, 8.9277708976484127e-07, 2.6374622880097546e-06, 7.3949955626738131e-06, 1.9684213310007427e-05, 4.9755352753869857e-05, 1.1945642608697544e-04, 2.7247518029396975e-04, 5.9058909090482672e-04, 1.2166676013683477e-03, 2.3826889355841037e-03, 4.4365604655715969e-03, 7.8555741198391739e-03, 1.3228935168893997e-02, 2.1190659578816773e-02, 3.2291498859030154e-02, 4.6816827098479806e-02, 6.4584179655610197e-02, 8.4780422567999614e-02, 1.0591066198925958e-01, 1.2591645229378781e-01, 1.4247629387217531e-01, 1.5343815707202285e-01, 1.5727610417082902e-01, 1.5343815707202285e-01, 1.4247629387217531e-01, 1.2591645229378781e-01, 1.0591066198925958e-01, 8.4780422567999614e-02, 6.4584179655610197e-02, 4.6816827098479806e-02, 3.2291498859030154e-02, 2.1190659578816773e-02, 1.3228935168893997e-02, 7.8555741198391739e-03, 4.4365604655715969e-03, 2.3826889355841037e-03, 1.2166676013683477e-03, 5.9058909090482672e-04, 2.7247518029396975e-04, 1.1945642608697544e-04, 4.9755352753869857e-05, 1.9684213310007427e-05, 7.3949955626738131e-06, 2.6374622880097546e-06, 8.9277708976484127e-07, 2.8673524946820525e-07, 8.7350604983433712e-08, 2.5232222625609405e-08, 6.9087593674811365e-09, 1.7924282778278772e-09, 4.4046822285487214e-10, 1.0248110528690129e-10, 2.2565549953554105e-11, 4.7003287276740161e-12, 9.2573881503227024e-13, 1.7231158339195911e-13, 3.0295892003599562e-14, 5.0287848550079939e-15, 7.8760411702639125e-16, 1.1632214089861438e-16, 1.6190413502935239e-17, 2.1223329298239927e-18, 2.6183914995557019e-19, 3.0381735933104597e-20, 3.3130211274194918e-21, 3.3925841234631972e-22, 3.2596930342072210e-23, 2.9362302035583120e-24, 2.4773098248022596e-25, 1.9558597204465646e-26, 1.4435514631174776e-27, 9.9497591435745215e-29, 6.3974120073582433e-30, 3.8327370697542584e-31, 2.1369895498120545e-32, 1.1074717912785746e-33, 5.3274424573468086e-35, 2.3754629195463299e-36, 9.8033645273483504e-38, 3.7386729623017851e-39, 1.3153901362816908e-40, 4.2621053825441441e-42, 1.2694602644562695e-43, 3.4688352621558211e-45, 8.6778002491153641e-47, 1.9830414431093633e-48, 4.1297412217775072e-50, 7.8178603818978630e-52, 1.3417085980893448e-53, 2.0815358697976881e-55, 2.9102221244239064e-57, 3.6546677508675100e-59, 4.1077464167348542e-61, 4.1164923961054212e-63, 3.6628479225209667e-65, 2.8809012333842463e-67, 1.9931390693715852e-69, 1.2065320173749644e-71, 6.3534513888384988e-74, 2.8919012660409682e-76, 1.1298318188883590e-78, 3.7595217722773437e-81, 1.0563282231662235e-83, 2.4821990706514334e-86, 4.8256764019125120e-89, 7.6677750665974574e-92, 9.8208576850538984e-95, 9.9792660546750878e-98, 7.8984266909061953e-101, 4.7660941708469085e-104, 2.1377995126059837e-107, 6.9150182989560957e-111, 1.5547020684816359e-114, 2.3212763347728001e-118, 2.1725144459735252e-122, 1.1822946408488032e-126, 3.3809077673415763e-131, 4.4036325515199439e-136, 2.1074517218240589e-141, 2.6008944296538456e-147, 4.2063621518212007e-154, 1.5740526693584465e-162}, {2.2290934963031539e-163, 6.1716304223418473e-155, 3.9305958509063355e-148, 3.2706601334834755e-142, 7.0049069648137550e-137, 5.5049260050287900e-132, 1.9684692530020812e-127, 3.6957545112422320e-123, 4.0320327117616306e-119, 2.7559362749699724e-115, 1.2503894738744883e-111, 3.9416969862084461e-108, 8.9577890237321700e-105, 1.5127860735379895e-101, 1.9472732376896783e-98, 1.9519789398323314e-95, 1.5520652579926001e-92, 9.9458309202670908e-90, 5.2083206235820379e-87, 2.2562215375682347e-84, 8.1731118972592471e-82, 2.4997514837476365e-79, 6.5111285362111366e-77, 1.4555888776738779e-74, 2.8125155025369667e-72, 4.7271089337772468e-70, 6.9513137370020262e-68, 8.9912466505154563e-66, 1.0279594830695334e-63, 1.0434894316959833e-61, 9.4440639857201346e-60, 7.6499247670821092e-58, 5.5658406725957325e-56, 3.6493796373809251e-54, 2.1630323514364711e-52, 1.1622901525905010e-50, 5.6773339224732908e-49, 2.5272570465088243e-47, 1.0276815273410889e-45, 3.8259457909463708e-44, 1.3067728287128299e-42, 4.1029828415971428e-41, 1.1864415902523173e-39, 3.1652198121078916e-38, 7.8035886293155777e-37, 1.7807430428966829e-35, 3.7667945725159055e-34, 7.3963969744653024e-33, 1.3499836949356773e-31, 2.2932424003565328e-30, 3.6300293183361797e-29, 5.3605436078106824e-28, 7.3930155412655720e-27, 9.5323773039462743e-26, 1.1502145928125925e-24, 1.3000662757028629e-23, 1.3776941782313042e-22, 1.3699807056265559e-21, 1.2794012136597428e-20, 1.1229742763811151e-19, 9.2710336687274256e-19, 7.2042972150393114e-18, 5.2729781171856177e-17, 3.6375048889083554e-16, 2.3664867578847666e-15, 1.4528301518132017e-14, 8.4213476872404286e-14, 4.6114644502136799e-13, 2.3867692880717110e-12, 1.1681801468249808e-11, 5.4092941845487156e-11, 2.3708105480750139e-10, 9.8392832670094020e-10, 3.8682673753498617e-09, 1.4411972185221586e-08, 5.0903013962041357e-08, 1.7050141340191249e-07, 5.4177677321026202e-07, 1.6336412605871983e-06, 4.6759044289293238e-06, 1.2707753951032874e-05, 3.2800534876023489e-05, 8.0428506528979537e-05, 1.8739476963256670e-04, 4.1497155710923123e-04, 8.7353709789879039e-04, 1.7483531042542699e-03, 3.3276551358222884e-03, 6.0239245919995622e-03, 1.0373317514267365e-02, 1.6994637482018023e-02, 2.6492061401939205e-02, 3.9298609227795579e-02, 5.5480282208033298e-02, 7.4548212057078664e-02, 9.5346453940664169e-02, 1.1608254348974273e-01, 1.3453811804025481e-01, 1.4844158241213595e-01, 1.5592224232989221e-01, 1.5592224232989221e-01, 1.4844158241213595e-01, 1.3453811804025481e-01, 1.1608254348974273e-01, 9.5346453940664169e-02, 7.4548212057078664e-02, 5.5480282208033298e-02, 3.9298609227795579e-02, 2.6492061401939205e-02, 1.6994637482018023e-02, 1.0373317514267365e-02, 6.0239245919995622e-03, 3.3276551358222884e-03, 1.7483531042542699e-03, 8.7353709789879039e-04, 4.1497155710923123e-04, 1.8739476963256670e-04, 8.0428506528979537e-05, 3.2800534876023489e-05, 1.2707753951032874e-05, 4.6759044289293238e-06, 1.6336412605871983e-06, 5.4177677321026202e-07, 1.7050141340191249e-07, 5.0903013962041357e-08, 1.4411972185221586e-08, 3.8682673753498617e-09, 9.8392832670094020e-10, 2.3708105480750139e-10, 5.4092941845487156e-11, 1.1681801468249808e-11, 2.3867692880717110e-12, 4.6114644502136799e-13, 8.4213476872404286e-14, 1.4528301518132017e-14, 2.3664867578847666e-15, 3.6375048889083554e-16, 5.2729781171856177e-17, 7.2042972150393114e-18, 9.2710336687274256e-19, 1.1229742763811151e-19, 1.2794012136597428e-20, 1.3699807056265559e-21, 1.3776941782313042e-22, 1.3000662757028629e-23, 1.1502145928125925e-24, 9.5323773039462743e-26, 7.3930155412655720e-27, 5.3605436078106824e-28, 3.6300293183361797e-29, 2.2932424003565328e-30, 1.3499836949356773e-31, 7.3963969744653024e-33, 3.7667945725159055e-34, 1.7807430428966829e-35, 7.8035886293155777e-37, 3.1652198121078916e-38, 1.1864415902523173e-39, 4.1029828415971428e-41, 1.3067728287128299e-42, 3.8259457909463708e-44, 1.0276815273410889e-45, 2.5272570465088243e-47, 5.6773339224732908e-49, 1.1622901525905010e-50, 2.1630323514364711e-52, 3.6493796373809251e-54, 5.5658406725957325e-56, 7.6499247670821092e-58, 9.4440639857201346e-60, 1.0434894316959833e-61, 1.0279594830695334e-63, 8.9912466505154563e-66, 6.9513137370020262e-68, 4.7271089337772468e-70, 2.8125155025369667e-72, 1.4555888776738779e-74, 6.5111285362111366e-77, 2.4997514837476365e-79, 8.1731118972592471e-82, 2.2562215375682347e-84, 5.2083206235820379e-87, 9.9458309202670908e-90, 1.5520652579926001e-92, 1.9519789398323314e-95, 1.9472732376896783e-98, 1.5127860735379895e-101, 8.9577890237321700e-105, 3.9416969862084461e-108, 1.2503894738744883e-111, 2.7559362749699724e-115, 4.0320327117616306e-119, 3.6957545112422320e-123, 1.9684692530020812e-127, 5.5049260050287900e-132, 7.0049069648137550e-137, 3.2706601334834755e-142, 3.9305958509063355e-148, 6.1716304223418473e-155, 2.2290934963031539e-163}, } golang-gonum-v1-gonum-0.14.0/integrate/quad/hermite_test.go000066400000000000000000005214671450372207100236140ustar00rootroot00000000000000// Copyright ©2016 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 quad import ( "fmt" "math" "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestHermite(t *testing.T) { t.Parallel() for cas, test := range []struct { n int f func(float64) float64 ev float64 tol float64 }{ { n: 2, f: func(x float64) float64 { return 1 }, ev: math.SqrtPi, tol: 1e-14, }, { n: 4, f: func(x float64) float64 { return math.Exp(-2 * 0.5 * x) }, ev: math.SqrtPi * math.Exp(0.25), tol: 1e-4, }, { n: 9, f: func(x float64) float64 { return math.Exp(-2 * 0.5 * x) }, ev: math.SqrtPi * math.Exp(0.25), tol: 1e-12, }, { n: 10, f: func(x float64) float64 { return math.Exp(-2 * 0.5 * x) }, ev: math.SqrtPi * math.Exp(0.25), tol: 1e-12, }, { n: 15, f: func(x float64) float64 { return math.Exp(-2 * 2 * x) }, ev: math.SqrtPi * math.Exp(4), tol: 1e-4, }, { n: 22, f: func(x float64) float64 { return math.Exp(-2 * 2 * x) }, ev: math.SqrtPi * math.Exp(4), tol: 1e-12, }, { n: 21, f: func(x float64) float64 { return math.Exp(-2 * 2 * x) }, ev: math.SqrtPi * math.Exp(4), tol: 1e-12, }, { n: 1000, f: func(x float64) float64 { return math.Exp(-2 * 2 * x) }, ev: math.SqrtPi * math.Exp(4), tol: 1e-12, }, } { ev := Fixed(test.f, math.Inf(-1), math.Inf(1), test.n, Hermite{}, 0) if !scalar.EqualWithinAbsOrRel(test.ev, ev, test.tol, test.tol) { t.Errorf("Case %d: expected value mismatch.\nWant %v\ngot %v", cas, test.ev, ev) } } } func TestHermiteLocations(t *testing.T) { t.Parallel() // Test the hermite locations and weights against other precomputed table. // Data from http://dlmf.nist.gov/3.5. for _, test := range []struct { n int x []float64 w []float64 tol float64 }{ // Evaluated from Chebfun. { n: 5, x: []float64{-0.202018287045609e1, -0.958572464613819, 0, 0.958572464613819, 0.202018287045609e1}, w: []float64{0.199532420590459e-1, 0.393619323152241, 0.945308720482942, 0.393619323152241, 0.199532420590459e-1}, tol: 1e-14, }, { n: 10, x: []float64{-0.343615911883773760e1, -0.253273167423278980e1, -0.175668364929988177e1, -0.103661082978951365e1, -0.342901327223704609, 0.342901327223704609, 0.103661082978951365e1, 0.175668364929988177e1, 0.253273167423278980e1, 0.343615911883773760e1}, w: []float64{0.764043285523262063e-5, 0.134364574678123269e-2, 0.338743944554810631e-1, 0.240138611082314686, 0.610862633735325799, 0.610862633735325799, 0.240138611082314686, 0.338743944554810631e-1, 0.134364574678123269e-2, 0.764043285523262063e-5}, tol: 1e-14, }, { n: 215, x: []float64{-2.0083110126223993e+01, -1.9573161931385755e+01, -1.9153731166695263e+01, -1.8781558404513735e+01, -1.8440108632764016e+01, -1.8120857960601569e+01, -1.7818692349773503e+01, -1.7530242081974308e+01, -1.7253139752773148e+01, -1.6985642449377284e+01, -1.6726420346886542e+01, -1.6474429782282726e+01, -1.6228832750513551e+01, -1.5988943547145137e+01, -1.5754192102761674e+01, -1.5524098014731747e+01, -1.5298251677453143e+01, -1.5076300264808333e+01, -1.4857937115425768e+01, -1.4642893558208563e+01, -1.4430932522616979e+01, -1.4221843477251845e+01, -1.4015438372554696e+01, -1.3811548353270942e+01, -1.3610021068540190e+01, -1.3410718451340038e+01, -1.3213514870431910e+01, -1.3018295580800100e+01, -1.2824955415404188e+01, -1.2633397673617059e+01, -1.2443533171189967e+01, -1.2255279423804318e+01, -1.2068559941826503e+01, -1.1883303618198463e+01, -1.1699444194777641e+01, -1.1516919795109878e+01, -1.1335672513742256e+01, -1.1155648053883823e+01, -1.0976795406593546e+01, -1.0799066565787168e+01, -1.0622416274262394e+01, -1.0446801796686490e+01, -1.0272182716104577e+01, -1.0098520751035824e+01, -9.9257795906487338e+00, -9.7539247458611111e+00, -9.5829234145081710e+00, -9.4127443589734394e+00, -9.2433577948895387e+00, -9.0747352896969389e+00, -8.9068496700026394e+00, -8.7396749368126798e+00, -8.5731861878255415e+00, -8.4073595460710955e+00, -8.2421720942637187e+00, -8.0776018143113824e+00, -7.9136275314855800e+00, -7.7502288628124383e+00, -7.5873861692931381e+00, -7.4250805116042331e+00, -7.2632936089653120e+00, -7.1020078008938672e+00, -6.9412060115960434e+00, -6.7808717167671544e+00, -6.6209889125982082e+00, -6.4615420868046280e+00, -6.3025161915109100e+00, -6.1438966178406549e+00, -5.9856691720754620e+00, -5.8278200532585673e+00, -5.6703358321303936e+00, -5.5132034312931157e+00, -5.3564101065103049e+00, -5.1999434290559226e+00, -5.0437912690340267e+00, -4.8879417795972326e+00, -4.7323833819978187e+00, -4.5771047514106780e+00, -4.4220948034722349e+00, -4.2673426814837114e+00, -4.1128377442311503e+00, -3.9585695543782120e+00, -3.8045278673909002e+00, -3.6507026209565665e+00, -3.4970839248619634e+00, -3.3436620512978501e+00, -3.1904274255596032e+00, -3.0373706171156218e+00, -2.8844823310168755e+00, -2.7317533996228827e+00, -2.5791747746208049e+00, -2.4267375193157439e+00, -2.2744328011717010e+00, -2.1222518845837395e+00, -1.9701861238629792e+00, -1.8182269564169717e+00, -1.6663658961089640e+00, -1.5145945267802365e+00, -1.3629044959205205e+00, -1.2112875084719879e+00, -1.0597353207530273e+00, -9.0823973448851325e-01, -7.5679259093351370e-01, -6.0538576507805808e-01, -4.5401115992078167e-01, -3.0266070079942864e-01, -1.5132632976672361e-01, 7.9483151672010196e-15, 1.5132632976672361e-01, 3.0266070079942864e-01, 4.5401115992078167e-01, 6.0538576507805808e-01, 7.5679259093351370e-01, 9.0823973448851325e-01, 1.0597353207530273e+00, 1.2112875084719879e+00, 1.3629044959205205e+00, 1.5145945267802365e+00, 1.6663658961089640e+00, 1.8182269564169717e+00, 1.9701861238629792e+00, 2.1222518845837395e+00, 2.2744328011717010e+00, 2.4267375193157439e+00, 2.5791747746208049e+00, 2.7317533996228827e+00, 2.8844823310168755e+00, 3.0373706171156218e+00, 3.1904274255596032e+00, 3.3436620512978501e+00, 3.4970839248619634e+00, 3.6507026209565665e+00, 3.8045278673909002e+00, 3.9585695543782120e+00, 4.1128377442311503e+00, 4.2673426814837114e+00, 4.4220948034722349e+00, 4.5771047514106780e+00, 4.7323833819978187e+00, 4.8879417795972326e+00, 5.0437912690340267e+00, 5.1999434290559226e+00, 5.3564101065103049e+00, 5.5132034312931157e+00, 5.6703358321303936e+00, 5.8278200532585673e+00, 5.9856691720754620e+00, 6.1438966178406549e+00, 6.3025161915109100e+00, 6.4615420868046280e+00, 6.6209889125982082e+00, 6.7808717167671544e+00, 6.9412060115960434e+00, 7.1020078008938672e+00, 7.2632936089653120e+00, 7.4250805116042331e+00, 7.5873861692931381e+00, 7.7502288628124383e+00, 7.9136275314855800e+00, 8.0776018143113824e+00, 8.2421720942637187e+00, 8.4073595460710955e+00, 8.5731861878255415e+00, 8.7396749368126798e+00, 8.9068496700026394e+00, 9.0747352896969389e+00, 9.2433577948895387e+00, 9.4127443589734394e+00, 9.5829234145081710e+00, 9.7539247458611111e+00, 9.9257795906487338e+00, 1.0098520751035824e+01, 1.0272182716104577e+01, 1.0446801796686490e+01, 1.0622416274262394e+01, 1.0799066565787168e+01, 1.0976795406593546e+01, 1.1155648053883823e+01, 1.1335672513742256e+01, 1.1516919795109878e+01, 1.1699444194777641e+01, 1.1883303618198463e+01, 1.2068559941826503e+01, 1.2255279423804318e+01, 1.2443533171189967e+01, 1.2633397673617059e+01, 1.2824955415404188e+01, 1.3018295580800100e+01, 1.3213514870431910e+01, 1.3410718451340038e+01, 1.3610021068540190e+01, 1.3811548353270942e+01, 1.4015438372554696e+01, 1.4221843477251845e+01, 1.4430932522616979e+01, 1.4642893558208563e+01, 1.4857937115425768e+01, 1.5076300264808333e+01, 1.5298251677453143e+01, 1.5524098014731747e+01, 1.5754192102761674e+01, 1.5988943547145137e+01, 1.6228832750513551e+01, 1.6474429782282726e+01, 1.6726420346886542e+01, 1.6985642449377284e+01, 1.7253139752773148e+01, 1.7530242081974308e+01, 1.7818692349773503e+01, 1.8120857960601569e+01, 1.8440108632764016e+01, 1.8781558404513735e+01, 1.9153731166695263e+01, 1.9573161931385755e+01, 2.0083110126223993e+01}, w: []float64{4.0474005560499094e-176, 1.8797130400856443e-167, 1.8432377040276421e-160, 2.2601442864626069e-154, 6.9363023753259492e-149, 7.6575370428605554e-144, 3.7894855074137878e-139, 9.7310398950542353e-135, 1.4382941114934084e-130, 1.3214094652141891e-126, 8.0053233705919762e-123, 3.3506484324551954e-119, 1.0061133084529732e-115, 2.2355880918528976e-112, 3.7723274691873339e-109, 4.9410774014014167e-106, 5.1189805080467357e-103, 4.2633269887655389e-100, 2.8951564896303124e-97, 1.6231768954981774e-94, 7.5966487579367170e-92, 2.9971587600601123e-89, 1.0056653752640396e-86, 2.8926565116618279e-84, 7.1838069610206879e-82, 1.5504440487214177e-79, 2.9253709118548054e-77, 4.8516529695481360e-75, 7.1080340648382430e-73, 9.2417798747589595e-71, 1.0709039437896534e-68, 1.1102986726619406e-66, 1.0337280935884043e-64, 8.6720569345151135e-63, 6.5759615285599325e-61, 4.5206307708839604e-59, 2.8251413443094276e-57, 1.6091856250751163e-55, 8.3743579179261028e-54, 3.9908716881614503e-52, 1.7453732998154445e-50, 7.0192904730947679e-49, 2.6008368230936308e-47, 8.8947358191690260e-46, 2.8125213532676820e-44, 8.2357837374304705e-43, 2.2368010157343200e-41, 5.6428177886700861e-40, 1.3240736407971940e-38, 2.8936578029605094e-37, 5.8971855560501346e-36, 1.1220768467833071e-34, 1.9956009474900652e-33, 3.3209946083724174e-32, 5.1767166839129889e-31, 7.5658951790722304e-30, 1.0377543674300410e-28, 1.3370496163293642e-27, 1.6195422525877890e-26, 1.8458039741402227e-25, 1.9809275961773415e-24, 2.0034006172471768e-23, 1.9107136033126365e-22, 1.7196934641222891e-21, 1.4615728740382834e-20, 1.1737567188678477e-19, 8.9122322093114715e-19, 6.4017277272147784e-18, 4.3526236743179514e-17, 2.8027154496363443e-16, 1.7100226833829111e-15, 9.8907988394494626e-15, 5.4258798698008971e-14, 2.8243097014577004e-13, 1.3955439320917938e-12, 6.5484943121277863e-12, 2.9192823809511808e-11, 1.2368298646403665e-10, 4.9819378483709125e-10, 1.9084879833147422e-09, 6.9554442384546823e-09, 2.4123461087320678e-08, 7.9645691304111948e-08, 2.5038904484412268e-07, 7.4974774628062337e-07, 2.1388110362272039e-06, 5.8142267442915587e-06, 1.5065139508846480e-05, 3.7214305501073257e-05, 8.7657861198914500e-05, 1.9692436368292282e-04, 4.2200152760283493e-04, 8.6279569789330843e-04, 1.6832545363270029e-03, 3.1340302956109622e-03, 5.5696401904272858e-03, 9.4487851093380676e-03, 1.5303805411902717e-02, 2.3666975130344652e-02, 3.4949960453868167e-02, 4.9288724246681882e-02, 6.6386134961517171e-02, 8.5401153510804823e-02, 1.0493731687783339e-01, 1.2316720474285285e-01, 1.3809371553328023e-01, 1.4790300421921079e-01, 1.5132498974070285e-01, 1.4790300421921079e-01, 1.3809371553328023e-01, 1.2316720474285285e-01, 1.0493731687783339e-01, 8.5401153510804823e-02, 6.6386134961517171e-02, 4.9288724246681882e-02, 3.4949960453868167e-02, 2.3666975130344652e-02, 1.5303805411902717e-02, 9.4487851093380676e-03, 5.5696401904272858e-03, 3.1340302956109622e-03, 1.6832545363270029e-03, 8.6279569789330843e-04, 4.2200152760283493e-04, 1.9692436368292282e-04, 8.7657861198914500e-05, 3.7214305501073257e-05, 1.5065139508846480e-05, 5.8142267442915587e-06, 2.1388110362272039e-06, 7.4974774628062337e-07, 2.5038904484412268e-07, 7.9645691304111948e-08, 2.4123461087320678e-08, 6.9554442384546823e-09, 1.9084879833147422e-09, 4.9819378483709125e-10, 1.2368298646403665e-10, 2.9192823809511808e-11, 6.5484943121277863e-12, 1.3955439320917938e-12, 2.8243097014577004e-13, 5.4258798698008971e-14, 9.8907988394494626e-15, 1.7100226833829111e-15, 2.8027154496363443e-16, 4.3526236743179514e-17, 6.4017277272147784e-18, 8.9122322093114715e-19, 1.1737567188678477e-19, 1.4615728740382834e-20, 1.7196934641222891e-21, 1.9107136033126365e-22, 2.0034006172471768e-23, 1.9809275961773415e-24, 1.8458039741402227e-25, 1.6195422525877890e-26, 1.3370496163293642e-27, 1.0377543674300410e-28, 7.5658951790722304e-30, 5.1767166839129889e-31, 3.3209946083724174e-32, 1.9956009474900652e-33, 1.1220768467833071e-34, 5.8971855560501346e-36, 2.8936578029605094e-37, 1.3240736407971940e-38, 5.6428177886700861e-40, 2.2368010157343200e-41, 8.2357837374304705e-43, 2.8125213532676820e-44, 8.8947358191690260e-46, 2.6008368230936308e-47, 7.0192904730947679e-49, 1.7453732998154445e-50, 3.9908716881614503e-52, 8.3743579179261028e-54, 1.6091856250751163e-55, 2.8251413443094276e-57, 4.5206307708839604e-59, 6.5759615285599325e-61, 8.6720569345151135e-63, 1.0337280935884043e-64, 1.1102986726619406e-66, 1.0709039437896534e-68, 9.2417798747589595e-71, 7.1080340648382430e-73, 4.8516529695481360e-75, 2.9253709118548054e-77, 1.5504440487214177e-79, 7.1838069610206879e-82, 2.8926565116618279e-84, 1.0056653752640396e-86, 2.9971587600601123e-89, 7.5966487579367170e-92, 1.6231768954981774e-94, 2.8951564896303124e-97, 4.2633269887655389e-100, 5.1189805080467357e-103, 4.9410774014014167e-106, 3.7723274691873339e-109, 2.2355880918528976e-112, 1.0061133084529732e-115, 3.3506484324551954e-119, 8.0053233705919762e-123, 1.3214094652141891e-126, 1.4382941114934084e-130, 9.7310398950542353e-135, 3.7894855074137878e-139, 7.6575370428605554e-144, 6.9363023753259492e-149, 2.2601442864626069e-154, 1.8432377040276421e-160, 1.8797130400856443e-167, 4.0474005560499094e-176}, tol: 1e-14, }, { n: 216, x: []float64{-2.0131752068397390e+01, -1.9622211733828486e+01, -1.9203122650098184e+01, -1.8831257901839155e+01, -1.8490094811217439e+01, -1.8171115805943941e+01, -1.7869210618319627e+01, -1.7581012003064874e+01, -1.7304154286393636e+01, -1.7036895825521608e+01, -1.6777907762072694e+01, -1.6526147190139376e+01, -1.6280776711860355e+01, -1.6041111119395726e+01, -1.5806580756275796e+01, -1.5576705568204593e+01, -1.5351076247103551e+01, -1.5129340223792830e+01, -1.4911191060978103e+01, -1.4696360284715409e+01, -1.4484610999323769e+01, -1.4275732829628778e+01, -1.4069537866591046e+01, -1.3865857382137794e+01, -1.3664539141187824e+01, -1.3465445182689793e+01, -1.3268449972893279e+01, -1.3073438856897617e+01, -1.2880306751340244e+01, -1.2688957033629340e+01, -1.2499300592587632e+01, -1.2311255012587219e+01, -1.2124743868808109e+01, -1.1939696115566026e+01, -1.1756045553033841e+01, -1.1573730360348824e+01, -1.1392692685219812e+01, -1.1212878281848150e+01, -1.1034236190346626e+01, -1.0856718451952171e+01, -1.0680279855235202e+01, -1.0504877709252620e+01, -1.0330471640205081e+01, -1.0157023408668081e+01, -9.9844967448895385e+00, -9.8128572000013108e+00, -9.6420720112891818e+00, -9.4721099799172528e+00, -9.3029413597147883e+00, -9.1345377558145096e+00, -8.9668720320849413e+00, -8.7999182264315081e+00, -8.6336514731539875e+00, -8.4680479316454296e+00, -8.3030847208017082e+00, -8.1387398585838486e+00, -7.9749922062384426e+00, -7.8118214167366684e+00, -7.6492078870405447e+00, -7.4871327138470951e+00, -7.3255776524981444e+00, -7.1645250787759087e+00, -7.0039579533331269e+00, -6.8438597885318986e+00, -6.6842146174875827e+00, -6.5250069651340752e+00, -6.3662218211444577e+00, -6.2078446145563948e+00, -6.0498611899661094e+00, -5.8922577851667635e+00, -5.7350210101185848e+00, -5.5781378271479722e+00, -5.4215955322816969e+00, -5.2653817376305465e+00, -5.1094843547439881e+00, -4.9538915788638089e+00, -4.7985918740108131e+00, -4.6435739588438905e+00, -4.4888267932355790e+00, -4.3343395655126109e+00, -4.1801016803139959e+00, -4.0261027470226392e+00, -3.8723325687298416e+00, -3.7187811316950210e+00, -3.5654385952656149e+00, -3.4122952822245907e+00, -3.2593416695353823e+00, -3.1065683794558021e+00, -2.9539661709946619e+00, -2.8015259316863266e+00, -2.6492386696600243e+00, -2.4970955059821409e+00, -2.3450876672510903e+00, -2.1932064784252856e+00, -2.0414433558661624e+00, -1.8897898005787916e+00, -1.7382373916337388e+00, -1.5867777797546210e+00, -1.4354026810562848e+00, -1.2841038709195900e+00, -1.1328731779888348e+00, -9.8170247827895785e-01, -8.3058368937955573e-01, -6.7950876474356448e-01, -5.2846968804856509e-01, -3.7745846761911317e-01, -2.2646713089859094e-01, -7.5487718959414210e-02, 7.5487718959414210e-02, 2.2646713089859094e-01, 3.7745846761911317e-01, 5.2846968804856509e-01, 6.7950876474356448e-01, 8.3058368937955573e-01, 9.8170247827895785e-01, 1.1328731779888348e+00, 1.2841038709195900e+00, 1.4354026810562848e+00, 1.5867777797546210e+00, 1.7382373916337388e+00, 1.8897898005787916e+00, 2.0414433558661624e+00, 2.1932064784252856e+00, 2.3450876672510903e+00, 2.4970955059821409e+00, 2.6492386696600243e+00, 2.8015259316863266e+00, 2.9539661709946619e+00, 3.1065683794558021e+00, 3.2593416695353823e+00, 3.4122952822245907e+00, 3.5654385952656149e+00, 3.7187811316950210e+00, 3.8723325687298416e+00, 4.0261027470226392e+00, 4.1801016803139959e+00, 4.3343395655126109e+00, 4.4888267932355790e+00, 4.6435739588438905e+00, 4.7985918740108131e+00, 4.9538915788638089e+00, 5.1094843547439881e+00, 5.2653817376305465e+00, 5.4215955322816969e+00, 5.5781378271479722e+00, 5.7350210101185848e+00, 5.8922577851667635e+00, 6.0498611899661094e+00, 6.2078446145563948e+00, 6.3662218211444577e+00, 6.5250069651340752e+00, 6.6842146174875827e+00, 6.8438597885318986e+00, 7.0039579533331269e+00, 7.1645250787759087e+00, 7.3255776524981444e+00, 7.4871327138470951e+00, 7.6492078870405447e+00, 7.8118214167366684e+00, 7.9749922062384426e+00, 8.1387398585838486e+00, 8.3030847208017082e+00, 8.4680479316454296e+00, 8.6336514731539875e+00, 8.7999182264315081e+00, 8.9668720320849413e+00, 9.1345377558145096e+00, 9.3029413597147883e+00, 9.4721099799172528e+00, 9.6420720112891818e+00, 9.8128572000013108e+00, 9.9844967448895385e+00, 1.0157023408668081e+01, 1.0330471640205081e+01, 1.0504877709252620e+01, 1.0680279855235202e+01, 1.0856718451952171e+01, 1.1034236190346626e+01, 1.1212878281848150e+01, 1.1392692685219812e+01, 1.1573730360348824e+01, 1.1756045553033841e+01, 1.1939696115566026e+01, 1.2124743868808109e+01, 1.2311255012587219e+01, 1.2499300592587632e+01, 1.2688957033629340e+01, 1.2880306751340244e+01, 1.3073438856897617e+01, 1.3268449972893279e+01, 1.3465445182689793e+01, 1.3664539141187824e+01, 1.3865857382137794e+01, 1.4069537866591046e+01, 1.4275732829628778e+01, 1.4484610999323769e+01, 1.4696360284715409e+01, 1.4911191060978103e+01, 1.5129340223792830e+01, 1.5351076247103551e+01, 1.5576705568204593e+01, 1.5806580756275796e+01, 1.6041111119395726e+01, 1.6280776711860355e+01, 1.6526147190139376e+01, 1.6777907762072694e+01, 1.7036895825521608e+01, 1.7304154286393636e+01, 1.7581012003064874e+01, 1.7869210618319627e+01, 1.8171115805943941e+01, 1.8490094811217439e+01, 1.8831257901839155e+01, 1.9203122650098184e+01, 1.9622211733828486e+01, 2.0131752068397390e+01}, w: []float64{5.7186844211118222e-177, 2.7466189949527236e-168, 2.7698274929964049e-161, 3.4828172461418377e-155, 1.0940903755394791e-149, 1.2347606047124676e-144, 6.2404773612052171e-140, 1.6353340891378212e-135, 2.4650950171742754e-131, 2.3085411036710099e-127, 1.4249650100034198e-123, 6.0746030482858092e-120, 1.8572077169453742e-116, 4.2005766103289114e-113, 7.2131362796894811e-110, 9.6125997143450870e-107, 1.0130358260780602e-103, 8.5810245129266594e-101, 5.9257988910096090e-98, 3.3780606107607827e-95, 1.6073077596553874e-92, 6.4463886647737192e-90, 2.1986159587286647e-87, 6.4275556938243753e-85, 1.6222763835321407e-82, 3.5581101139323407e-80, 6.8220148646876484e-78, 1.1496573365594917e-75, 1.7114200608857651e-73, 2.2608688324572314e-71, 2.6617645198762597e-69, 2.8038024736345674e-67, 2.6521234350652613e-65, 2.2603869398967457e-63, 1.7413601437152754e-61, 1.2161701083247541e-59, 7.7214787759599970e-58, 4.4681959655564470e-56, 2.3623580471674404e-54, 1.1437576644069702e-52, 5.0819691921164956e-51, 2.0764486091263794e-49, 7.8168818968667932e-48, 2.7161609526051418e-46, 8.7263192332605962e-45, 2.5963610791198993e-43, 7.1651564650842932e-42, 1.8367370768736730e-40, 4.3795689659428445e-39, 9.7263842188046952e-38, 2.0144288376257676e-36, 3.8953956971431042e-35, 7.0411654624671892e-34, 1.1909731529300876e-32, 1.8870059773886237e-31, 2.8034152482012231e-30, 3.9088957466494064e-29, 5.1199371899987404e-28, 6.3051173258996659e-27, 7.3062988441733997e-26, 7.9729602997232079e-25, 8.1994951837475763e-24, 7.9526775811935095e-23, 7.2794477168595113e-22, 6.2925924422563063e-21, 5.1402243977739270e-20, 3.9702645520078747e-19, 2.9013105636885269e-18, 2.0070043240260125e-17, 1.3149628048888219e-16, 8.1641639956286359e-16, 4.8056898389707300e-15, 2.6831763736632487e-14, 1.4216321504480736e-13, 7.1508314522575616e-13, 3.4161417919950439e-12, 1.5505876032631646e-11, 6.6896188793649314e-11, 2.7441476023994389e-10, 1.0706905991113023e-09, 3.9747846429602356e-09, 1.4044052119190546e-08, 4.7242215798796869e-08, 1.5133894631903387e-07, 4.6181858824280925e-07, 1.3427778873836719e-06, 3.7209613424878082e-06, 9.8293533546629111e-06, 2.4757612288389546e-05, 5.9469805842774389e-05, 1.3626145195379436e-04, 2.9786395909886146e-04, 6.2130683688573309e-04, 1.2368227283931328e-03, 2.3501040099770882e-03, 4.2629032262842719e-03, 7.3827553287034008e-03, 1.2208924001688722e-02, 1.9280976823883154e-02, 2.9081432020399377e-02, 4.1896299298471870e-02, 5.7655710815363609e-02, 7.5795804675644604e-02, 9.5193937891141694e-02, 1.1422353375366404e-01, 1.3094856577352781e-01, 1.4343569727181574e-01, 1.5011822522474477e-01, 1.5011822522474477e-01, 1.4343569727181574e-01, 1.3094856577352781e-01, 1.1422353375366404e-01, 9.5193937891141694e-02, 7.5795804675644604e-02, 5.7655710815363609e-02, 4.1896299298471870e-02, 2.9081432020399377e-02, 1.9280976823883154e-02, 1.2208924001688722e-02, 7.3827553287034008e-03, 4.2629032262842719e-03, 2.3501040099770882e-03, 1.2368227283931328e-03, 6.2130683688573309e-04, 2.9786395909886146e-04, 1.3626145195379436e-04, 5.9469805842774389e-05, 2.4757612288389546e-05, 9.8293533546629111e-06, 3.7209613424878082e-06, 1.3427778873836719e-06, 4.6181858824280925e-07, 1.5133894631903387e-07, 4.7242215798796869e-08, 1.4044052119190546e-08, 3.9747846429602356e-09, 1.0706905991113023e-09, 2.7441476023994389e-10, 6.6896188793649314e-11, 1.5505876032631646e-11, 3.4161417919950439e-12, 7.1508314522575616e-13, 1.4216321504480736e-13, 2.6831763736632487e-14, 4.8056898389707300e-15, 8.1641639956286359e-16, 1.3149628048888219e-16, 2.0070043240260125e-17, 2.9013105636885269e-18, 3.9702645520078747e-19, 5.1402243977739270e-20, 6.2925924422563063e-21, 7.2794477168595113e-22, 7.9526775811935095e-23, 8.1994951837475763e-24, 7.9729602997232079e-25, 7.3062988441733997e-26, 6.3051173258996659e-27, 5.1199371899987404e-28, 3.9088957466494064e-29, 2.8034152482012231e-30, 1.8870059773886237e-31, 1.1909731529300876e-32, 7.0411654624671892e-34, 3.8953956971431042e-35, 2.0144288376257676e-36, 9.7263842188046952e-38, 4.3795689659428445e-39, 1.8367370768736730e-40, 7.1651564650842932e-42, 2.5963610791198993e-43, 8.7263192332605962e-45, 2.7161609526051418e-46, 7.8168818968667932e-48, 2.0764486091263794e-49, 5.0819691921164956e-51, 1.1437576644069702e-52, 2.3623580471674404e-54, 4.4681959655564470e-56, 7.7214787759599970e-58, 1.2161701083247541e-59, 1.7413601437152754e-61, 2.2603869398967457e-63, 2.6521234350652613e-65, 2.8038024736345674e-67, 2.6617645198762597e-69, 2.2608688324572314e-71, 1.7114200608857651e-73, 1.1496573365594917e-75, 6.8220148646876484e-78, 3.5581101139323407e-80, 1.6222763835321407e-82, 6.4275556938243753e-85, 2.1986159587286647e-87, 6.4463886647737192e-90, 1.6073077596553874e-92, 3.3780606107607827e-95, 5.9257988910096090e-98, 8.5810245129266594e-101, 1.0130358260780602e-103, 9.6125997143450870e-107, 7.2131362796894811e-110, 4.2005766103289114e-113, 1.8572077169453742e-116, 6.0746030482858092e-120, 1.4249650100034198e-123, 2.3085411036710099e-127, 2.4650950171742754e-131, 1.6353340891378212e-135, 6.2404773612052171e-140, 1.2347606047124676e-144, 1.0940903755394791e-149, 3.4828172461418377e-155, 2.7698274929964049e-161, 2.7466189949527236e-168, 5.7186844211118222e-177}, tol: 1e-14, }, { n: 217, x: []float64{-2.0180280152078982e+01, -1.9671145428267970e+01, -1.9252396116029669e+01, -1.8880837640701767e+01, -1.8539959593913657e+01, -1.8221250688860252e+01, -1.7919604408706316e+01, -1.7631655968298805e+01, -1.7355041415469405e+01, -1.7088020370809854e+01, -1.6829264937408070e+01, -1.6577732962488266e+01, -1.6332587652172350e+01, -1.6093144292573264e+01, -1.5858833637952957e+01, -1.5629175980464554e+01, -1.5403762307923412e+01, -1.5182240306661464e+01, -1.4964303762199654e+01, -1.4749684396618285e+01, -1.4538145488075983e+01, -1.4329476816694543e+01, -1.4123490613100632e+01, -1.3920018275613611e+01, -1.3718907684195138e+01, -1.3520020983073742e+01, -1.3323232735334253e+01, -1.3128428375570619e+01, -1.2935502903505391e+01, -1.2744359774012816e+01, -1.2554909948437734e+01, -1.2367071079310476e+01, -1.2180766806106346e+01, -1.1995926144008331e+01, -1.1812482951007951e+01, -1.1630375461345015e+01, -1.1449545875407471e+01, -1.1269939997911081e+01, -1.1091506917547994e+01, -1.0914198722404091e+01, -1.0737970246351363e+01, -1.0562778842365235e+01, -1.0388584179329960e+01, -1.0215348059403579e+01, -1.0043034253437085e+01, -9.8716083522966080e+00, -9.7010376322345699e+00, -9.5312909327068294e+00, -9.3623385452449437e+00, -9.1941521121732386e+00, -9.0267045341142556e+00, -8.8599698853577831e+00, -8.6939233362816957e+00, -8.5285410821102356e+00, -8.3638002773794167e+00, -8.1996789755519419e+00, -8.0361560732874953e+00, -7.8732112589291026e+00, -7.7108249648145373e+00, -7.5489783230637100e+00, -7.3876531245300106e+00, -7.2268317806359086e+00, -7.0664972878418659e+00, -6.9066331945227768e+00, -6.7472235700485381e+00, -6.5882529758852613e+00, -6.4297064385510465e+00, -6.2715694242761426e+00, -6.1138278152311072e+00, -5.9564678871991967e+00, -5.7994762885802258e+00, -5.6428400206233480e+00, -5.4865464187949282e+00, -5.3305831351959538e+00, -5.1749381219506319e+00, -5.0195996154942355e+00, -4.8645561216944264e+00, -4.7097964017452645e+00, -4.5553094587783480e+00, -4.4010845251394572e+00, -4.2471110502834843e+00, -4.0933786892435746e+00, -3.9398772916341032e+00, -3.7865968911497059e+00, -3.6335276955255318e+00, -3.4806600769262501e+00, -3.3279845627335654e+00, -3.1754918267040755e+00, -3.0231726804711898e+00, -2.8710180653663722e+00, -2.7190190445367941e+00, -2.5671667953376018e+00, -2.4154526019785036e+00, -2.2638678484054164e+00, -2.1124040113990956e+00, -1.9610526538735082e+00, -1.8098054183577674e+00, -1.6586540206460576e+00, -1.5075902436008417e+00, -1.3566059310952046e+00, -1.2056929820809235e+00, -1.0548433447690717e+00, -9.0404901091087708e-01, -7.5330201016646747e-01, -6.0259440454997382e-01, -4.5191828293935077e-01, -3.0126575563983427e-01, -1.5062894899007009e-01, 7.9851131193273576e-15, 1.5062894899007009e-01, 3.0126575563983427e-01, 4.5191828293935077e-01, 6.0259440454997382e-01, 7.5330201016646747e-01, 9.0404901091087708e-01, 1.0548433447690717e+00, 1.2056929820809235e+00, 1.3566059310952046e+00, 1.5075902436008417e+00, 1.6586540206460576e+00, 1.8098054183577674e+00, 1.9610526538735082e+00, 2.1124040113990956e+00, 2.2638678484054164e+00, 2.4154526019785036e+00, 2.5671667953376018e+00, 2.7190190445367941e+00, 2.8710180653663722e+00, 3.0231726804711898e+00, 3.1754918267040755e+00, 3.3279845627335654e+00, 3.4806600769262501e+00, 3.6335276955255318e+00, 3.7865968911497059e+00, 3.9398772916341032e+00, 4.0933786892435746e+00, 4.2471110502834843e+00, 4.4010845251394572e+00, 4.5553094587783480e+00, 4.7097964017452645e+00, 4.8645561216944264e+00, 5.0195996154942355e+00, 5.1749381219506319e+00, 5.3305831351959538e+00, 5.4865464187949282e+00, 5.6428400206233480e+00, 5.7994762885802258e+00, 5.9564678871991967e+00, 6.1138278152311072e+00, 6.2715694242761426e+00, 6.4297064385510465e+00, 6.5882529758852613e+00, 6.7472235700485381e+00, 6.9066331945227768e+00, 7.0664972878418659e+00, 7.2268317806359086e+00, 7.3876531245300106e+00, 7.5489783230637100e+00, 7.7108249648145373e+00, 7.8732112589291026e+00, 8.0361560732874953e+00, 8.1996789755519419e+00, 8.3638002773794167e+00, 8.5285410821102356e+00, 8.6939233362816957e+00, 8.8599698853577831e+00, 9.0267045341142556e+00, 9.1941521121732386e+00, 9.3623385452449437e+00, 9.5312909327068294e+00, 9.7010376322345699e+00, 9.8716083522966080e+00, 1.0043034253437085e+01, 1.0215348059403579e+01, 1.0388584179329960e+01, 1.0562778842365235e+01, 1.0737970246351363e+01, 1.0914198722404091e+01, 1.1091506917547994e+01, 1.1269939997911081e+01, 1.1449545875407471e+01, 1.1630375461345015e+01, 1.1812482951007951e+01, 1.1995926144008331e+01, 1.2180766806106346e+01, 1.2367071079310476e+01, 1.2554909948437734e+01, 1.2744359774012816e+01, 1.2935502903505391e+01, 1.3128428375570619e+01, 1.3323232735334253e+01, 1.3520020983073742e+01, 1.3718907684195138e+01, 1.3920018275613611e+01, 1.4123490613100632e+01, 1.4329476816694543e+01, 1.4538145488075983e+01, 1.4749684396618285e+01, 1.4964303762199654e+01, 1.5182240306661464e+01, 1.5403762307923412e+01, 1.5629175980464554e+01, 1.5858833637952957e+01, 1.6093144292573264e+01, 1.6332587652172350e+01, 1.6577732962488266e+01, 1.6829264937408070e+01, 1.7088020370809854e+01, 1.7355041415469405e+01, 1.7631655968298805e+01, 1.7919604408706316e+01, 1.8221250688860252e+01, 1.8539959593913657e+01, 1.8880837640701767e+01, 1.9252396116029669e+01, 1.9671145428267970e+01, 2.0180280152078982e+01}, w: []float64{8.0790134837724204e-178, 4.0123708332001955e-169, 4.1608342695810454e-162, 5.3647010323313458e-156, 1.7249035730335862e-150, 1.9898962894711550e-145, 1.0270178951244021e-140, 2.7462859803070011e-136, 4.2216443703754674e-132, 4.0296773344706320e-128, 2.5341526783446447e-124, 1.1002243777181162e-120, 3.4246772430261828e-117, 7.8839348684832184e-114, 1.3776135348531781e-110, 1.8677560466742519e-107, 2.0021556471031417e-104, 1.7247770196475562e-101, 1.2111464936797437e-98, 7.0196501028640057e-96, 3.3954234881610162e-93, 1.3842435843570204e-90, 4.7985036069815231e-88, 1.4256947701704702e-85, 3.6567711491235357e-83, 8.1499750643585127e-81, 1.5877740343548737e-78, 2.7187040652791320e-76, 4.1119602314337377e-74, 5.5188731969772834e-72, 6.6010643664052121e-70, 7.0639875689587789e-68, 6.7880577161215916e-66, 5.8772891020073188e-64, 4.5996045356018730e-62, 3.2633290432137694e-60, 2.1047497049395128e-58, 1.2372745780617511e-56, 6.6453150452727337e-55, 3.2684621263244055e-53, 1.4753196845067616e-51, 6.1238771021510087e-50, 2.3420591906941631e-48, 8.2677634302135741e-47, 2.6986236644096577e-45, 8.1576808396884509e-44, 2.2873393442828659e-42, 5.9575720207549899e-41, 1.4433986536815081e-39, 3.2572816931648467e-38, 6.8552334632687487e-37, 1.3471217671214917e-35, 2.4745963539025701e-34, 4.2538970187949130e-33, 6.8502295544213803e-32, 1.0344007225282243e-30, 1.4660497224001333e-29, 1.9519881038552925e-28, 2.4437079996027598e-27, 2.8788818637419581e-26, 3.1940663724110344e-25, 3.3399348780894923e-24, 3.2939758359327470e-23, 3.0661414593245886e-22, 2.6955142404467904e-21, 2.2394681775190790e-20, 1.7594079537257698e-19, 1.3078564789171130e-18, 9.2038260248200122e-18, 6.1351365453804107e-17, 3.8757039748543155e-16, 2.3214598330581677e-15, 1.3190482037051148e-14, 7.1128747627508331e-14, 3.6416855631427732e-13, 1.7709744825377116e-12, 8.1836457113383607e-12, 3.5947660428421198e-11, 1.5015547963310099e-10, 5.9663534866912190e-10, 2.2558892777245505e-09, 8.1190427548544262e-09, 2.7822813440253852e-08, 9.0809483027322313e-08, 2.8236711509871372e-07, 8.3668655155751835e-07, 2.3631134387385760e-06, 6.3632839492173400e-06, 1.6339902252008705e-05, 4.0020290652701539e-05, 9.3510362001206373e-05, 2.0848221478522648e-04, 4.4359250162546185e-04, 9.0090002804434576e-04, 1.7466777765574378e-03, 3.2333646918818863e-03, 5.7155709629331409e-03, 9.6489576482962046e-03, 1.5558416546311961e-02, 2.3963959563684092e-02, 3.5261402555428784e-02, 4.9570551047913969e-02, 6.6582815385485522e-02, 8.5455825791019971e-02, 1.0480572103134121e-01, 1.2283174514792664e-01, 1.3757292020567533e-01, 1.4725235676872742e-01, 1.5062763955757250e-01, 1.4725235676872742e-01, 1.3757292020567533e-01, 1.2283174514792664e-01, 1.0480572103134121e-01, 8.5455825791019971e-02, 6.6582815385485522e-02, 4.9570551047913969e-02, 3.5261402555428784e-02, 2.3963959563684092e-02, 1.5558416546311961e-02, 9.6489576482962046e-03, 5.7155709629331409e-03, 3.2333646918818863e-03, 1.7466777765574378e-03, 9.0090002804434576e-04, 4.4359250162546185e-04, 2.0848221478522648e-04, 9.3510362001206373e-05, 4.0020290652701539e-05, 1.6339902252008705e-05, 6.3632839492173400e-06, 2.3631134387385760e-06, 8.3668655155751835e-07, 2.8236711509871372e-07, 9.0809483027322313e-08, 2.7822813440253852e-08, 8.1190427548544262e-09, 2.2558892777245505e-09, 5.9663534866912190e-10, 1.5015547963310099e-10, 3.5947660428421198e-11, 8.1836457113383607e-12, 1.7709744825377116e-12, 3.6416855631427732e-13, 7.1128747627508331e-14, 1.3190482037051148e-14, 2.3214598330581677e-15, 3.8757039748543155e-16, 6.1351365453804107e-17, 9.2038260248200122e-18, 1.3078564789171130e-18, 1.7594079537257698e-19, 2.2394681775190790e-20, 2.6955142404467904e-21, 3.0661414593245886e-22, 3.2939758359327470e-23, 3.3399348780894923e-24, 3.1940663724110344e-25, 2.8788818637419581e-26, 2.4437079996027598e-27, 1.9519881038552925e-28, 1.4660497224001333e-29, 1.0344007225282243e-30, 6.8502295544213803e-32, 4.2538970187949130e-33, 2.4745963539025701e-34, 1.3471217671214917e-35, 6.8552334632687487e-37, 3.2572816931648467e-38, 1.4433986536815081e-39, 5.9575720207549899e-41, 2.2873393442828659e-42, 8.1576808396884509e-44, 2.6986236644096577e-45, 8.2677634302135741e-47, 2.3420591906941631e-48, 6.1238771021510087e-50, 1.4753196845067616e-51, 3.2684621263244055e-53, 6.6453150452727337e-55, 1.2372745780617511e-56, 2.1047497049395128e-58, 3.2633290432137694e-60, 4.5996045356018730e-62, 5.8772891020073188e-64, 6.7880577161215916e-66, 7.0639875689587789e-68, 6.6010643664052121e-70, 5.5188731969772834e-72, 4.1119602314337377e-74, 2.7187040652791320e-76, 1.5877740343548737e-78, 8.1499750643585127e-81, 3.6567711491235357e-83, 1.4256947701704702e-85, 4.7985036069815231e-88, 1.3842435843570204e-90, 3.3954234881610162e-93, 7.0196501028640057e-96, 1.2111464936797437e-98, 1.7247770196475562e-101, 2.0021556471031417e-104, 1.8677560466742519e-107, 1.3776135348531781e-110, 7.8839348684832184e-114, 3.4246772430261828e-117, 1.1002243777181162e-120, 2.5341526783446447e-124, 4.0296773344706320e-128, 4.2216443703754674e-132, 2.7462859803070011e-136, 1.0270178951244021e-140, 1.9898962894711550e-145, 1.7249035730335862e-150, 5.3647010323313458e-156, 4.1608342695810454e-162, 4.0123708332001955e-169, 8.0790134837724204e-178}, tol: 1e-14, }, { n: 218, x: []float64{-2.0228695170577915e+01, -1.9719963830858333e+01, -1.9301552400253843e+01, -1.8930298474919816e+01, -1.8589703851801165e+01, -1.8271263496827501e+01, -1.7969874624529179e+01, -1.7682174897106314e+01, -1.7405802075069708e+01, -1.7139017035820078e+01, -1.6880492838899503e+01, -1.6629188080724916e+01, -1.6384266568226192e+01, -1.6145044078855118e+01, -1.5910951775414047e+01, -1.5681510294638914e+01, -1.5456310918627016e+01, -1.5235001587812036e+01, -1.5017276309282583e+01, -1.4802867000027815e+01, -1.4591537111039028e+01, -1.4383076576817141e+01, -1.4177297766812716e+01, -1.3974032204957940e+01, -1.3773127885530926e+01, -1.3574447057358521e+01, -1.3377864379717227e+01, -1.3183265376084384e+01, -1.2990545128683925e+01, -1.2799607169295788e+01, -1.2610362531246457e+01, -1.2422728934700823e+01, -1.2236630082919943e+01, -1.2051995051456386e+01, -1.1868757755632400e+01, -1.1686856484310367e+01, -1.1506233490083723e+01, -1.1326834627713886e+01, -1.1148609034007171e+01, -1.0971508843435563e+01, -1.0795488934711024e+01, -1.0620506704266159e+01, -1.0446521863206758e+01, -1.0273496254809785e+01, -1.0101393690063306e+01, -9.9301797990985268e+00, -9.7598218966614141e+00, -9.5902888600219054e+00, -9.4215510179308293e+00, -9.2535800494152092e+00, -9.0863488913560904e+00, -8.9198316539249092e+00, -8.7540035430671104e+00, -8.5888407893192067e+00, -8.4243205823293916e+00, -8.2604210105245137e+00, -8.0971210054295799e+00, -7.9344002902008972e+00, -7.7722393319820444e+00, -7.6106192977338623e+00, -7.4495220132267015e+00, -7.2889299249154647e+00, -7.1288260644465895e+00, -6.9691940155714960e+00, -6.8100178832631793e+00, -6.6512822648525844e+00, -6.4929722230189020e+00, -6.3350732604836884e+00, -6.1775712962725331e+00, -6.0204526434206276e+00, -5.8637039880096422e+00, -5.7073123694332661e+00, -5.5512651617979705e+00, -5.3955500563732679e+00, -5.2401550450133421e+00, -5.0850684044781733e+00, -4.9302786815884012e+00, -4.7757746791533817e+00, -4.6215454426166902e+00, -4.4675802473678914e+00, -4.3138685866729931e+00, -4.1604001601800418e+00, -4.0071648629591818e+00, -3.8541527750397258e+00, -3.7013541514093888e+00, -3.5487594124432715e+00, -3.3963591347324886e+00, -3.2441440422843915e+00, -3.0921049980680149e+00, -2.9402329958803848e+00, -2.7885191525106028e+00, -2.6369547001801932e+00, -2.4855309792393636e+00, -2.3342394311001944e+00, -2.1830715913886820e+00, -2.0320190832985223e+00, -1.8810736111306099e+00, -1.7302269540027844e+00, -1.5794709597152470e+00, -1.4287975387577758e+00, -1.2781986584451195e+00, -1.1276663371680935e+00, -9.7719263874768358e-01, -8.2676966688043974e-01, -6.7638955966349490e-01, -5.2604448418800387e-01, -3.7572663118998539e-01, -2.2542820974780486e-01, -7.5141442015907556e-02, 7.5141442015907556e-02, 2.2542820974780486e-01, 3.7572663118998539e-01, 5.2604448418800387e-01, 6.7638955966349490e-01, 8.2676966688043974e-01, 9.7719263874768358e-01, 1.1276663371680935e+00, 1.2781986584451195e+00, 1.4287975387577758e+00, 1.5794709597152470e+00, 1.7302269540027844e+00, 1.8810736111306099e+00, 2.0320190832985223e+00, 2.1830715913886820e+00, 2.3342394311001944e+00, 2.4855309792393636e+00, 2.6369547001801932e+00, 2.7885191525106028e+00, 2.9402329958803848e+00, 3.0921049980680149e+00, 3.2441440422843915e+00, 3.3963591347324886e+00, 3.5487594124432715e+00, 3.7013541514093888e+00, 3.8541527750397258e+00, 4.0071648629591818e+00, 4.1604001601800418e+00, 4.3138685866729931e+00, 4.4675802473678914e+00, 4.6215454426166902e+00, 4.7757746791533817e+00, 4.9302786815884012e+00, 5.0850684044781733e+00, 5.2401550450133421e+00, 5.3955500563732679e+00, 5.5512651617979705e+00, 5.7073123694332661e+00, 5.8637039880096422e+00, 6.0204526434206276e+00, 6.1775712962725331e+00, 6.3350732604836884e+00, 6.4929722230189020e+00, 6.6512822648525844e+00, 6.8100178832631793e+00, 6.9691940155714960e+00, 7.1288260644465895e+00, 7.2889299249154647e+00, 7.4495220132267015e+00, 7.6106192977338623e+00, 7.7722393319820444e+00, 7.9344002902008972e+00, 8.0971210054295799e+00, 8.2604210105245137e+00, 8.4243205823293916e+00, 8.5888407893192067e+00, 8.7540035430671104e+00, 8.9198316539249092e+00, 9.0863488913560904e+00, 9.2535800494152092e+00, 9.4215510179308293e+00, 9.5902888600219054e+00, 9.7598218966614141e+00, 9.9301797990985268e+00, 1.0101393690063306e+01, 1.0273496254809785e+01, 1.0446521863206758e+01, 1.0620506704266159e+01, 1.0795488934711024e+01, 1.0971508843435563e+01, 1.1148609034007171e+01, 1.1326834627713886e+01, 1.1506233490083723e+01, 1.1686856484310367e+01, 1.1868757755632400e+01, 1.2051995051456386e+01, 1.2236630082919943e+01, 1.2422728934700823e+01, 1.2610362531246457e+01, 1.2799607169295788e+01, 1.2990545128683925e+01, 1.3183265376084384e+01, 1.3377864379717227e+01, 1.3574447057358521e+01, 1.3773127885530926e+01, 1.3974032204957940e+01, 1.4177297766812716e+01, 1.4383076576817141e+01, 1.4591537111039028e+01, 1.4802867000027815e+01, 1.5017276309282583e+01, 1.5235001587812036e+01, 1.5456310918627016e+01, 1.5681510294638914e+01, 1.5910951775414047e+01, 1.6145044078855118e+01, 1.6384266568226192e+01, 1.6629188080724916e+01, 1.6880492838899503e+01, 1.7139017035820078e+01, 1.7405802075069708e+01, 1.7682174897106314e+01, 1.7969874624529179e+01, 1.8271263496827501e+01, 1.8589703851801165e+01, 1.8930298474919816e+01, 1.9301552400253843e+01, 1.9719963830858333e+01, 2.0228695170577915e+01}, w: []float64{1.1412038714903467e-178, 5.8600364276414301e-170, 6.2483530291970031e-163, 8.2600389517381484e-157, 2.7180946943728827e-151, 3.2050447674896954e-146, 1.6891299829881347e-141, 4.6087117363873922e-137, 7.2242769320344098e-133, 7.0281073750791237e-129, 4.5026465211632589e-125, 1.9907761957745900e-121, 6.3085296819235091e-118, 1.4780807064034936e-114, 2.6279883692096037e-111, 3.6246331337631131e-108, 3.9519127727199950e-105, 3.4620642776922925e-102, 2.4718758245223020e-99, 1.4565168188237643e-96, 7.1616419809360768e-94, 2.9675903948483656e-91, 1.0455125036940855e-88, 3.1567897170935801e-86, 8.2277370866559977e-84, 1.8632623782187992e-81, 3.6882177983197069e-79, 6.4162031293430147e-77, 9.8590364210588088e-75, 1.3442782637610740e-72, 1.6333988316711487e-70, 1.7756459769101764e-68, 1.7332892347041021e-66, 1.5244548820160086e-64, 1.2118948225793116e-62, 8.7339153184655864e-61, 5.7220382749093667e-59, 3.4167937984322514e-57, 1.8641137908561576e-55, 9.3133897167275065e-54, 4.2703424814876432e-52, 1.8006175119892686e-50, 6.9955013175656585e-49, 2.5086717527911961e-47, 8.3184624948029151e-46, 2.5546048751257637e-44, 7.2770684318833216e-43, 1.9256515369002052e-41, 4.7401499620934791e-40, 1.0868621062998897e-38, 2.3241907456347607e-37, 4.6409284690005433e-36, 8.6630347696542139e-35, 1.5133539937177412e-33, 2.4766678429636503e-32, 3.8008678166597364e-31, 5.4751646602962371e-30, 7.4097643192715769e-29, 9.4293221065635326e-28, 1.1292370018541933e-26, 1.2736861289852883e-25, 1.3540721404735189e-24, 1.3578087095789605e-23, 1.2851527881373697e-22, 1.1488929806753338e-21, 9.7071144039920359e-21, 7.7562537574525747e-20, 5.8643464026904450e-19, 4.1979458289914584e-18, 2.8466716026161652e-17, 1.8295539696950399e-16, 1.1150004956688747e-15, 6.4466274804790879e-15, 3.5376499268729578e-14, 1.8433622668090456e-13, 9.1243282637242511e-13, 4.2919888935314847e-12, 1.9193290587578772e-11, 8.1626646177788407e-11, 3.3026130822100178e-10, 1.2716614885102940e-09, 4.6613505196508951e-09, 1.6270858113762294e-08, 5.4099533071374670e-08, 1.7138819219313466e-07, 5.1747190361086424e-07, 1.4894285947831174e-06, 4.0877345728852175e-06, 1.0699746166171350e-05, 2.6716804837681635e-05, 6.3650699225936851e-05, 1.4471442394637491e-04, 3.1404212609163355e-04, 6.5058509971884274e-04, 1.2868513657693481e-03, 2.4306591608453860e-03, 4.3848013160776717e-03, 7.5554485133504786e-03, 1.2436693679604333e-02, 1.9558227968032915e-02, 2.9388347600235249e-02, 4.2196739277833864e-02, 5.7899315166709715e-02, 7.5925444911783990e-02, 9.5157950558542009e-02, 1.1399005091049424e-01, 1.3051762867943345e-01, 1.4284462872400217e-01, 1.4943738595687683e-01, 1.4943738595687683e-01, 1.4284462872400217e-01, 1.3051762867943345e-01, 1.1399005091049424e-01, 9.5157950558542009e-02, 7.5925444911783990e-02, 5.7899315166709715e-02, 4.2196739277833864e-02, 2.9388347600235249e-02, 1.9558227968032915e-02, 1.2436693679604333e-02, 7.5554485133504786e-03, 4.3848013160776717e-03, 2.4306591608453860e-03, 1.2868513657693481e-03, 6.5058509971884274e-04, 3.1404212609163355e-04, 1.4471442394637491e-04, 6.3650699225936851e-05, 2.6716804837681635e-05, 1.0699746166171350e-05, 4.0877345728852175e-06, 1.4894285947831174e-06, 5.1747190361086424e-07, 1.7138819219313466e-07, 5.4099533071374670e-08, 1.6270858113762294e-08, 4.6613505196508951e-09, 1.2716614885102940e-09, 3.3026130822100178e-10, 8.1626646177788407e-11, 1.9193290587578772e-11, 4.2919888935314847e-12, 9.1243282637242511e-13, 1.8433622668090456e-13, 3.5376499268729578e-14, 6.4466274804790879e-15, 1.1150004956688747e-15, 1.8295539696950399e-16, 2.8466716026161652e-17, 4.1979458289914584e-18, 5.8643464026904450e-19, 7.7562537574525747e-20, 9.7071144039920359e-21, 1.1488929806753338e-21, 1.2851527881373697e-22, 1.3578087095789605e-23, 1.3540721404735189e-24, 1.2736861289852883e-25, 1.1292370018541933e-26, 9.4293221065635326e-28, 7.4097643192715769e-29, 5.4751646602962371e-30, 3.8008678166597364e-31, 2.4766678429636503e-32, 1.5133539937177412e-33, 8.6630347696542139e-35, 4.6409284690005433e-36, 2.3241907456347607e-37, 1.0868621062998897e-38, 4.7401499620934791e-40, 1.9256515369002052e-41, 7.2770684318833216e-43, 2.5546048751257637e-44, 8.3184624948029151e-46, 2.5086717527911961e-47, 6.9955013175656585e-49, 1.8006175119892686e-50, 4.2703424814876432e-52, 9.3133897167275065e-54, 1.8641137908561576e-55, 3.4167937984322514e-57, 5.7220382749093667e-59, 8.7339153184655864e-61, 1.2118948225793116e-62, 1.5244548820160086e-64, 1.7332892347041021e-66, 1.7756459769101764e-68, 1.6333988316711487e-70, 1.3442782637610740e-72, 9.8590364210588088e-75, 6.4162031293430147e-77, 3.6882177983197069e-79, 1.8632623782187992e-81, 8.2277370866559977e-84, 3.1567897170935801e-86, 1.0455125036940855e-88, 2.9675903948483656e-91, 7.1616419809360768e-94, 1.4565168188237643e-96, 2.4718758245223020e-99, 3.4620642776922925e-102, 3.9519127727199950e-105, 3.6246331337631131e-108, 2.6279883692096037e-111, 1.4780807064034936e-114, 6.3085296819235091e-118, 1.9907761957745900e-121, 4.5026465211632589e-125, 7.0281073750791237e-129, 7.2242769320344098e-133, 4.6087117363873922e-137, 1.6891299829881347e-141, 3.2050447674896954e-146, 2.7180946943728827e-151, 8.2600389517381484e-157, 6.2483530291970031e-163, 5.8600364276414301e-170, 1.1412038714903467e-178}, tol: 1e-14, }, { n: 219, x: []float64{-2.0276997908046905e+01, -1.9768667748260523e+01, -1.9350592328749663e+01, -1.8979641248255188e+01, -1.8639328445512675e+01, -1.8321155106754730e+01, -1.8020022158568153e+01, -1.7732569697856896e+01, -1.7456437188959409e+01, -1.7189886759582706e+01, -1.6931592420762687e+01, -1.6680513514209245e+01, -1.6435814444517028e+01, -1.6196811477889465e+01, -1.5962936183500821e+01, -1.5733709540823362e+01, -1.5508723124641774e+01, -1.5287625128097030e+01, -1.5070109778611977e+01, -1.4855909186982135e+01, -1.4644786976036578e+01, -1.4436533233749541e+01, -1.4230960467563948e+01, -1.4027900326255610e+01, -1.3827200917702472e+01, -1.3628724594657513e+01, -1.3432346111954516e+01, -1.3237951081351927e+01, -1.3045434667000123e+01, -1.2854700477033081e+01, -1.2665659616227074e+01, -1.2478229871866438e+01, -1.2292335010497055e+01, -1.2107904167551959e+01, -1.1924871315204850e+01, -1.1743174796469416e+01, -1.1562756915679721e+01, -1.1383563577182978e+01, -1.1205543965443459e+01, -1.1028650260865531e+01, -1.0852837386548828e+01, -1.0678062781931233e+01, -1.0504286199887655e+01, -1.0331469524360219e+01, -1.0159576606018058e+01, -9.9885731137985694e+00, -9.8184264004786943e+00, -9.6491053806754916e+00, -9.4805804198871506e+00, -9.3128232333657657e+00, -9.1458067937670240e+00, -8.9795052466532344e+00, -8.8138938330391774e+00, -8.6489488182673355e+00, -8.4846474265831215e+00, -8.3209677808533336e+00, -8.1578888469343305e+00, -7.9953903822513528e+00, -7.8334528881984324e+00, -7.6720575660104693e+00, -7.5111862757957555e+00, -7.3508214984498235e+00, -7.1909463001999656e+00, -7.0315442995549828e+00, -6.8725996364571813e+00, -6.7140969434532645e+00, -6.5560213187184688e+00, -6.3983583007839497e+00, -6.2410938448312283e+00, -6.0842143004302391e+00, -5.9277063906083614e+00, -5.7715571921480873e+00, -5.6157541170197165e+00, -5.4602848948636904e+00, -5.3051375564443513e+00, -5.1503004180034342e+00, -4.9957620664475568e+00, -4.8415113453092564e+00, -4.6875373414259709e+00, -4.5338293722856466e+00, -4.3803769739918419e+00, -4.2271698898044328e+00, -4.0741980592156279e+00, -3.9214516075238026e+00, -3.7689208358703388e+00, -3.6165962117072561e+00, -3.4644683596654966e+00, -3.3125280527959076e+00, -3.1607662041567641e+00, -3.0091738587233952e+00, -2.8577421855969432e+00, -2.7064624704909552e+00, -2.5553261084754681e+00, -2.4043245969596510e+00, -2.2534495288951528e+00, -2.1026925861830650e+00, -1.9520455332686681e+00, -1.8015002109084974e+00, -1.6510485300954487e+00, -1.5006824661279821e+00, -1.3503940528101779e+00, -1.2001753767700742e+00, -1.0500185718839765e+00, -8.9991581379505270e-01, -7.4985931451474896e-01, -5.9984131709602384e-01, -4.4985409036765389e-01, -2.9988992371893503e-01, -1.4994112192465620e-01, 8.0217422708380516e-15, 1.4994112192465620e-01, 2.9988992371893503e-01, 4.4985409036765389e-01, 5.9984131709602384e-01, 7.4985931451474896e-01, 8.9991581379505270e-01, 1.0500185718839765e+00, 1.2001753767700742e+00, 1.3503940528101779e+00, 1.5006824661279821e+00, 1.6510485300954487e+00, 1.8015002109084974e+00, 1.9520455332686681e+00, 2.1026925861830650e+00, 2.2534495288951528e+00, 2.4043245969596510e+00, 2.5553261084754681e+00, 2.7064624704909552e+00, 2.8577421855969432e+00, 3.0091738587233952e+00, 3.1607662041567641e+00, 3.3125280527959076e+00, 3.4644683596654966e+00, 3.6165962117072561e+00, 3.7689208358703388e+00, 3.9214516075238026e+00, 4.0741980592156279e+00, 4.2271698898044328e+00, 4.3803769739918419e+00, 4.5338293722856466e+00, 4.6875373414259709e+00, 4.8415113453092564e+00, 4.9957620664475568e+00, 5.1503004180034342e+00, 5.3051375564443513e+00, 5.4602848948636904e+00, 5.6157541170197165e+00, 5.7715571921480873e+00, 5.9277063906083614e+00, 6.0842143004302391e+00, 6.2410938448312283e+00, 6.3983583007839497e+00, 6.5560213187184688e+00, 6.7140969434532645e+00, 6.8725996364571813e+00, 7.0315442995549828e+00, 7.1909463001999656e+00, 7.3508214984498235e+00, 7.5111862757957555e+00, 7.6720575660104693e+00, 7.8334528881984324e+00, 7.9953903822513528e+00, 8.1578888469343305e+00, 8.3209677808533336e+00, 8.4846474265831215e+00, 8.6489488182673355e+00, 8.8138938330391774e+00, 8.9795052466532344e+00, 9.1458067937670240e+00, 9.3128232333657657e+00, 9.4805804198871506e+00, 9.6491053806754916e+00, 9.8184264004786943e+00, 9.9885731137985694e+00, 1.0159576606018058e+01, 1.0331469524360219e+01, 1.0504286199887655e+01, 1.0678062781931233e+01, 1.0852837386548828e+01, 1.1028650260865531e+01, 1.1205543965443459e+01, 1.1383563577182978e+01, 1.1562756915679721e+01, 1.1743174796469416e+01, 1.1924871315204850e+01, 1.2107904167551959e+01, 1.2292335010497055e+01, 1.2478229871866438e+01, 1.2665659616227074e+01, 1.2854700477033081e+01, 1.3045434667000123e+01, 1.3237951081351927e+01, 1.3432346111954516e+01, 1.3628724594657513e+01, 1.3827200917702472e+01, 1.4027900326255610e+01, 1.4230960467563948e+01, 1.4436533233749541e+01, 1.4644786976036578e+01, 1.4855909186982135e+01, 1.5070109778611977e+01, 1.5287625128097030e+01, 1.5508723124641774e+01, 1.5733709540823362e+01, 1.5962936183500821e+01, 1.6196811477889465e+01, 1.6435814444517028e+01, 1.6680513514209245e+01, 1.6931592420762687e+01, 1.7189886759582706e+01, 1.7456437188959409e+01, 1.7732569697856896e+01, 1.8020022158568153e+01, 1.8321155106754730e+01, 1.8639328445512675e+01, 1.8979641248255188e+01, 1.9350592328749663e+01, 1.9768667748260523e+01, 2.0276997908046905e+01}, w: []float64{1.6118004761490936e-179, 8.5565157993831952e-171, 9.3801386072360495e-164, 1.2712817065467470e-157, 4.2810879764792902e-152, 5.1593581306426363e-147, 2.7763562197121041e-142, 7.7287684331971630e-138, 1.2353061004428027e-133, 1.2247428452374434e-129, 7.9930519467022852e-126, 3.5986937020445443e-122, 1.1608863141459933e-118, 2.7680773700442792e-115, 5.0074481042562811e-112, 7.0254966797767812e-109, 7.7903695739499256e-106, 6.9398586398625168e-103, 5.0378132240927281e-100, 3.0176790544586562e-97, 1.5082063803644767e-94, 6.3518001539538009e-92, 2.2741855202923794e-89, 6.9776584966048747e-87, 1.8479046829051634e-84, 4.2518674704681371e-82, 8.5507393331426323e-80, 1.5112093165489227e-77, 2.3589639789454550e-75, 3.2673822149378061e-73, 4.0328590535463278e-71, 4.4532356700297110e-69, 4.4154958570004513e-67, 3.9446173154369991e-65, 3.1851636643508064e-63, 2.3315719656364080e-61, 1.5515360955581329e-59, 9.4102483913550526e-58, 5.2146771930312127e-56, 2.6462964683019027e-54, 1.2324622103285675e-52, 5.2785960684684324e-51, 2.0830950016909702e-49, 7.5881492915547110e-48, 2.5559164938518617e-46, 7.9735166177827294e-45, 2.3073707359625722e-43, 6.2027848314701266e-42, 1.5511852212359039e-40, 3.6134675099711877e-39, 7.8508422681776689e-38, 1.5928021832222874e-36, 3.0210523716429586e-35, 5.3626533220153980e-34, 8.9182314112122594e-33, 1.3908724042317442e-31, 2.0361886950192076e-30, 2.8006915544325587e-29, 3.6224809761826824e-28, 4.4096199762595120e-27, 5.0558656605721755e-26, 5.4641111784906703e-25, 5.5704394297442813e-24, 5.3605363007899914e-23, 4.8726597293407410e-22, 4.1864031729275524e-21, 3.4017282707064429e-20, 2.6157557992877646e-19, 1.9044895750724533e-18, 1.3136464708861073e-17, 8.5885898614439566e-17, 5.3250576372585674e-16, 3.1325104388327040e-15, 1.7491400171437906e-14, 9.2749216025525341e-14, 4.6723068181067832e-13, 2.2369795792044991e-12, 1.0182840690359900e-11, 4.4087115371635113e-11, 1.8161128736541464e-10, 7.1204644180465281e-10, 2.6579545759517285e-09, 9.4491700732305002e-09, 3.2001745961210195e-08, 1.0327820095258369e-07, 3.1769761704760471e-07, 9.3174969312259845e-07, 2.6059663547935113e-06, 6.9521878670475772e-06, 1.7695019387908094e-05, 4.2977984770344540e-05, 9.9630005120895210e-05, 2.2047640877838706e-04, 4.6583912781443418e-04, 9.3989854709223869e-04, 1.8111811218635974e-03, 3.3337948402502641e-03, 5.8622951858897081e-03, 9.8491710526776490e-03, 1.5811821288832947e-02, 2.4258117817844916e-02, 3.5568359860607475e-02, 4.9846708381161745e-02, 6.6773674520725357e-02, 8.5505952447471292e-02, 1.0467230074567024e-01, 1.2249815849737687e-01, 1.3705778627617005e-01, 1.4661020932556390e-01, 1.4993984211667696e-01, 1.4661020932556390e-01, 1.3705778627617005e-01, 1.2249815849737687e-01, 1.0467230074567024e-01, 8.5505952447471292e-02, 6.6773674520725357e-02, 4.9846708381161745e-02, 3.5568359860607475e-02, 2.4258117817844916e-02, 1.5811821288832947e-02, 9.8491710526776490e-03, 5.8622951858897081e-03, 3.3337948402502641e-03, 1.8111811218635974e-03, 9.3989854709223869e-04, 4.6583912781443418e-04, 2.2047640877838706e-04, 9.9630005120895210e-05, 4.2977984770344540e-05, 1.7695019387908094e-05, 6.9521878670475772e-06, 2.6059663547935113e-06, 9.3174969312259845e-07, 3.1769761704760471e-07, 1.0327820095258369e-07, 3.2001745961210195e-08, 9.4491700732305002e-09, 2.6579545759517285e-09, 7.1204644180465281e-10, 1.8161128736541464e-10, 4.4087115371635113e-11, 1.0182840690359900e-11, 2.2369795792044991e-12, 4.6723068181067832e-13, 9.2749216025525341e-14, 1.7491400171437906e-14, 3.1325104388327040e-15, 5.3250576372585674e-16, 8.5885898614439566e-17, 1.3136464708861073e-17, 1.9044895750724533e-18, 2.6157557992877646e-19, 3.4017282707064429e-20, 4.1864031729275524e-21, 4.8726597293407410e-22, 5.3605363007899914e-23, 5.5704394297442813e-24, 5.4641111784906703e-25, 5.0558656605721755e-26, 4.4096199762595120e-27, 3.6224809761826824e-28, 2.8006915544325587e-29, 2.0361886950192076e-30, 1.3908724042317442e-31, 8.9182314112122594e-33, 5.3626533220153980e-34, 3.0210523716429586e-35, 1.5928021832222874e-36, 7.8508422681776689e-38, 3.6134675099711877e-39, 1.5511852212359039e-40, 6.2027848314701266e-42, 2.3073707359625722e-43, 7.9735166177827294e-45, 2.5559164938518617e-46, 7.5881492915547110e-48, 2.0830950016909702e-49, 5.2785960684684324e-51, 1.2324622103285675e-52, 2.6462964683019027e-54, 5.2146771930312127e-56, 9.4102483913550526e-58, 1.5515360955581329e-59, 2.3315719656364080e-61, 3.1851636643508064e-63, 3.9446173154369991e-65, 4.4154958570004513e-67, 4.4532356700297110e-69, 4.0328590535463278e-71, 3.2673822149378061e-73, 2.3589639789454550e-75, 1.5112093165489227e-77, 8.5507393331426323e-80, 4.2518674704681371e-82, 1.8479046829051634e-84, 6.9776584966048747e-87, 2.2741855202923794e-89, 6.3518001539538009e-92, 1.5082063803644767e-94, 3.0176790544586562e-97, 5.0378132240927281e-100, 6.9398586398625168e-103, 7.7903695739499256e-106, 7.0254966797767812e-109, 5.0074481042562811e-112, 2.7680773700442792e-115, 1.1608863141459933e-118, 3.5986937020445443e-122, 7.9930519467022852e-126, 1.2247428452374434e-129, 1.2353061004428027e-133, 7.7287684331971630e-138, 2.7763562197121041e-142, 5.1593581306426363e-147, 4.2810879764792902e-152, 1.2712817065467470e-157, 9.3801386072360495e-164, 8.5565157993831952e-171, 1.6118004761490936e-179}, tol: 1e-14, }, { n: 220, x: []float64{-2.0325189139629405e+01, -1.9817257977795947e+01, -1.9399516717870224e+01, -1.9028866794578029e+01, -1.8688834225534919e+01, -1.8370926385157830e+01, -1.8070047892967271e+01, -1.7782841268044042e+01, -1.7506947669788651e+01, -1.7240630469775191e+01, -1.6982564625621777e+01, -1.6731710220470223e+01, -1.6487232253468321e+01, -1.6248447477010238e+01, -1.6014787864496149e+01, -1.5785774736307584e+01, -1.5560999958339213e+01, -1.5340111975060188e+01, -1.5122805233008011e+01, -1.4908812035694833e+01, -1.4697896176804390e+01, -1.4489847896889446e+01, -1.4284479840564213e+01, -1.4081623780688842e+01, -1.3881127938034011e+01, -1.3682854768615876e+01, -1.3486679122200039e+01, -1.3292486698232523e+01, -1.3100172742223814e+01, -1.2909640938118768e+01, -1.2720802461619986e+01, -1.2533575166624548e+01, -1.2347882882470566e+01, -1.2163654803990811e+01, -1.1980824959739557e+01, -1.1799331746419007e+01, -1.1619117519647554e+01, -1.1440128232906956e+01, -1.1262313117871999e+01, -1.1085624400434606e+01, -1.0910017047638791e+01, -1.0735448541485018e+01, -1.0561878676174262e+01, -1.0389269375869560e+01, -1.0217584530474927e+01, -1.0046789847284987e+01, -9.8768527166552929e+00, -9.7077420900935678e+00, -9.5394283693840993e+00, -9.3718833055374660e+00, -9.2050799065113704e+00, -9.0389923527798217e+00, -8.8735959199405876e+00, -8.7088669076480283e+00, -8.5447825742424133e+00, -8.3813210765192689e+00, -8.2184614141456525e+00, -8.0561833782850805e+00, -7.8944675040409047e+00, -7.7332950263697580e+00, -7.5726478391539116e+00, -7.4125084571532707e+00, -7.2528599805868588e+00, -7.0936860621182607e+00, -6.9349708760424020e+00, -6.7766990894903305e+00, -6.6188558354865279e+00, -6.4614266877089035e+00, -6.3043976368153372e+00, -6.1477550682134519e+00, -5.9914857411611600e+00, -5.8355767690955807e+00, -5.6800156010969900e+00, -5.5247900044023472e+00, -5.3698880478903845e+00, -5.2152980864665599e+00, -5.0610087462822682e+00, -4.9070089107279511e+00, -4.7532877071444766e+00, -4.5998344942017342e+00, -4.4466388498971172e+00, -4.2936905601303739e+00, -4.1409796078143595e+00, -3.9884961624844180e+00, -3.8362305703715940e+00, -3.6841733449075362e+00, -3.5323151576310980e+00, -3.3806468294686467e+00, -3.2291593223621100e+00, -3.0778437312202702e+00, -2.9266912761707076e+00, -2.7756932950907438e+00, -2.6248412363975424e+00, -2.4741266520783536e+00, -2.3235411909430654e+00, -2.1730765920823036e+00, -2.0227246785151167e+00, -1.8724773510110999e+00, -1.7223265820726865e+00, -1.5722644100637477e+00, -1.4222829334715719e+00, -1.2723743052896335e+00, -1.1225307275089995e+00, -9.7274444570696528e-01, -8.2300774372149477e-01, -6.7331293840074014e-01, -5.2365237441695056e-01, -3.7401841913451778e-01, -2.2440345752197671e-01, -7.4799887098051757e-02, 7.4799887098051757e-02, 2.2440345752197671e-01, 3.7401841913451778e-01, 5.2365237441695056e-01, 6.7331293840074014e-01, 8.2300774372149477e-01, 9.7274444570696528e-01, 1.1225307275089995e+00, 1.2723743052896335e+00, 1.4222829334715719e+00, 1.5722644100637477e+00, 1.7223265820726865e+00, 1.8724773510110999e+00, 2.0227246785151167e+00, 2.1730765920823036e+00, 2.3235411909430654e+00, 2.4741266520783536e+00, 2.6248412363975424e+00, 2.7756932950907438e+00, 2.9266912761707076e+00, 3.0778437312202702e+00, 3.2291593223621100e+00, 3.3806468294686467e+00, 3.5323151576310980e+00, 3.6841733449075362e+00, 3.8362305703715940e+00, 3.9884961624844180e+00, 4.1409796078143595e+00, 4.2936905601303739e+00, 4.4466388498971172e+00, 4.5998344942017342e+00, 4.7532877071444766e+00, 4.9070089107279511e+00, 5.0610087462822682e+00, 5.2152980864665599e+00, 5.3698880478903845e+00, 5.5247900044023472e+00, 5.6800156010969900e+00, 5.8355767690955807e+00, 5.9914857411611600e+00, 6.1477550682134519e+00, 6.3043976368153372e+00, 6.4614266877089035e+00, 6.6188558354865279e+00, 6.7766990894903305e+00, 6.9349708760424020e+00, 7.0936860621182607e+00, 7.2528599805868588e+00, 7.4125084571532707e+00, 7.5726478391539116e+00, 7.7332950263697580e+00, 7.8944675040409047e+00, 8.0561833782850805e+00, 8.2184614141456525e+00, 8.3813210765192689e+00, 8.5447825742424133e+00, 8.7088669076480283e+00, 8.8735959199405876e+00, 9.0389923527798217e+00, 9.2050799065113704e+00, 9.3718833055374660e+00, 9.5394283693840993e+00, 9.7077420900935678e+00, 9.8768527166552929e+00, 1.0046789847284987e+01, 1.0217584530474927e+01, 1.0389269375869560e+01, 1.0561878676174262e+01, 1.0735448541485018e+01, 1.0910017047638791e+01, 1.1085624400434606e+01, 1.1262313117871999e+01, 1.1440128232906956e+01, 1.1619117519647554e+01, 1.1799331746419007e+01, 1.1980824959739557e+01, 1.2163654803990811e+01, 1.2347882882470566e+01, 1.2533575166624548e+01, 1.2720802461619986e+01, 1.2909640938118768e+01, 1.3100172742223814e+01, 1.3292486698232523e+01, 1.3486679122200039e+01, 1.3682854768615876e+01, 1.3881127938034011e+01, 1.4081623780688842e+01, 1.4284479840564213e+01, 1.4489847896889446e+01, 1.4697896176804390e+01, 1.4908812035694833e+01, 1.5122805233008011e+01, 1.5340111975060188e+01, 1.5560999958339213e+01, 1.5785774736307584e+01, 1.6014787864496149e+01, 1.6248447477010238e+01, 1.6487232253468321e+01, 1.6731710220470223e+01, 1.6982564625621777e+01, 1.7240630469775191e+01, 1.7506947669788651e+01, 1.7782841268044042e+01, 1.8070047892967271e+01, 1.8370926385157830e+01, 1.8688834225534919e+01, 1.9028866794578029e+01, 1.9399516717870224e+01, 1.9817257977795947e+01, 2.0325189139629405e+01}, w: []float64{2.2761605731502931e-180, 1.2490844229282551e-171, 1.4077080884426324e-164, 1.9558070725961945e-158, 6.7396164617778564e-153, 8.3007451278928549e-148, 4.5605427168506885e-143, 1.2952107195320918e-138, 2.1106922482765282e-134, 2.1325182525295938e-130, 1.4176541142180510e-126, 6.4990818384221324e-123, 2.1340663816447175e-119, 5.1782994410611593e-116, 9.5303885471678039e-113, 1.3600769560707746e-109, 1.5337501625076215e-106, 1.3892626373123839e-103, 1.0252931948997944e-100, 6.2430026550428978e-98, 3.1713496923820005e-95, 1.3573663268548106e-92, 4.9385791079870452e-90, 1.5396613562557895e-87, 4.1428768007295419e-85, 9.6845718261332366e-83, 1.9785969337019459e-80, 3.5522955000635345e-78, 5.6327088700629997e-76, 7.9248469784581938e-74, 9.9353884108905009e-72, 1.1143371044053519e-69, 1.1222249771693660e-67, 1.0182568638449594e-65, 8.3508496445242703e-64, 6.2085535684767686e-62, 4.1960840622737107e-60, 2.5847807937901128e-58, 1.4547608917709417e-56, 7.4980265458380947e-55, 3.5467498009174184e-53, 1.5428702374218767e-51, 6.1841637682672203e-50, 2.2881100073201874e-48, 7.8282784948541621e-47, 2.4806114249059706e-45, 7.2916745732054914e-44, 1.9911806078855746e-42, 5.0584298583405264e-41, 1.1970700137586669e-39, 2.6422337190194530e-38, 5.4462015155980312e-37, 1.0495069994748297e-35, 1.8928725655710039e-34, 3.1985659419085236e-33, 5.0689745622498271e-32, 7.5410079936029980e-31, 1.0540919389712685e-29, 1.3856239612378123e-28, 1.7143191474654609e-27, 1.9978524188114189e-26, 2.1947842513043781e-25, 2.2745432296820405e-24, 2.2252271383645215e-23, 2.0564749726923156e-22, 1.7964719327802204e-21, 1.4843379300503135e-20, 1.1606915413845120e-19, 8.5944540731309027e-19, 6.0293824390549243e-18, 4.0096487904356170e-17, 2.5289217277543671e-16, 1.5134484435681475e-15, 8.5980922774659504e-15, 4.6390554602844329e-14, 2.3781148094626393e-13, 1.1587426167580950e-12, 5.3685841373417416e-12, 2.3659835874748833e-11, 9.9219381603477156e-11, 3.9606009206879336e-10, 1.5053791970450186e-09, 5.4498580894419877e-09, 1.8797800781026250e-08, 6.1792198822459984e-08, 1.9363392840773747e-07, 5.7857719375034532e-07, 1.6488403637671232e-06, 4.4826356596959815e-06, 1.1628419918195159e-05, 2.8789242845201347e-05, 6.8037279449589797e-05, 1.5351500720814013e-04, 3.3076323494923371e-04, 6.8063888690970183e-04, 1.3378748383672085e-03, 2.5123201954271616e-03, 4.5076732111920138e-03, 7.7285957578851656e-03, 1.2663915587278220e-02, 1.9833481075447929e-02, 2.9691593353631068e-02, 4.2492045448586743e-02, 5.8137078835965875e-02, 7.6049788530935164e-02, 9.5118681388506904e-02, 1.1375654825578213e-01, 1.3009049092173738e-01, 1.4226074789149157e-01, 1.4876572633109977e-01, 1.4876572633109977e-01, 1.4226074789149157e-01, 1.3009049092173738e-01, 1.1375654825578213e-01, 9.5118681388506904e-02, 7.6049788530935164e-02, 5.8137078835965875e-02, 4.2492045448586743e-02, 2.9691593353631068e-02, 1.9833481075447929e-02, 1.2663915587278220e-02, 7.7285957578851656e-03, 4.5076732111920138e-03, 2.5123201954271616e-03, 1.3378748383672085e-03, 6.8063888690970183e-04, 3.3076323494923371e-04, 1.5351500720814013e-04, 6.8037279449589797e-05, 2.8789242845201347e-05, 1.1628419918195159e-05, 4.4826356596959815e-06, 1.6488403637671232e-06, 5.7857719375034532e-07, 1.9363392840773747e-07, 6.1792198822459984e-08, 1.8797800781026250e-08, 5.4498580894419877e-09, 1.5053791970450186e-09, 3.9606009206879336e-10, 9.9219381603477156e-11, 2.3659835874748833e-11, 5.3685841373417416e-12, 1.1587426167580950e-12, 2.3781148094626393e-13, 4.6390554602844329e-14, 8.5980922774659504e-15, 1.5134484435681475e-15, 2.5289217277543671e-16, 4.0096487904356170e-17, 6.0293824390549243e-18, 8.5944540731309027e-19, 1.1606915413845120e-19, 1.4843379300503135e-20, 1.7964719327802204e-21, 2.0564749726923156e-22, 2.2252271383645215e-23, 2.2745432296820405e-24, 2.1947842513043781e-25, 1.9978524188114189e-26, 1.7143191474654609e-27, 1.3856239612378123e-28, 1.0540919389712685e-29, 7.5410079936029980e-31, 5.0689745622498271e-32, 3.1985659419085236e-33, 1.8928725655710039e-34, 1.0495069994748297e-35, 5.4462015155980312e-37, 2.6422337190194530e-38, 1.1970700137586669e-39, 5.0584298583405264e-41, 1.9911806078855746e-42, 7.2916745732054914e-44, 2.4806114249059706e-45, 7.8282784948541621e-47, 2.2881100073201874e-48, 6.1841637682672203e-50, 1.5428702374218767e-51, 3.5467498009174184e-53, 7.4980265458380947e-55, 1.4547608917709417e-56, 2.5847807937901128e-58, 4.1960840622737107e-60, 6.2085535684767686e-62, 8.3508496445242703e-64, 1.0182568638449594e-65, 1.1222249771693660e-67, 1.1143371044053519e-69, 9.9353884108905009e-72, 7.9248469784581938e-74, 5.6327088700629997e-76, 3.5522955000635345e-78, 1.9785969337019459e-80, 9.6845718261332366e-83, 4.1428768007295419e-85, 1.5396613562557895e-87, 4.9385791079870452e-90, 1.3573663268548106e-92, 3.1713496923820005e-95, 6.2430026550428978e-98, 1.0252931948997944e-100, 1.3892626373123839e-103, 1.5337501625076215e-106, 1.3600769560707746e-109, 9.5303885471678039e-113, 5.1782994410611593e-116, 2.1340663816447175e-119, 6.4990818384221324e-123, 1.4176541142180510e-126, 2.1325182525295938e-130, 2.1106922482765282e-134, 1.2952107195320918e-138, 4.5605427168506885e-143, 8.3007451278928549e-148, 6.7396164617778564e-153, 1.9558070725961945e-158, 1.4077080884426324e-164, 1.2490844229282551e-171, 2.2761605731502931e-180}, tol: 1e-14, }, { n: 1000, x: []float64{-4.4209152497996392e+01, -4.3816642022906109e+01, -4.3494771146334074e+01, -4.3209908104582034e+01, -4.2949182188453079e+01, -4.2705951529047212e+01, -4.2476227524277085e+01, -4.2257379812646654e+01, -4.2047559014075354e+01, -4.1845402643747086e+01, -4.1649870480923305e+01, -4.1460145678774452e+01, -4.1275572014249832e+01, -4.1095612279765099e+01, -4.0919819679199151e+01, -4.0747817561006038e+01, -4.0579284685508064e+01, -4.0413944276381194e+01, -4.0251555726823973e+01, -4.0091908210099085e+01, -3.9934815683324643e+01, -3.9780112928508778e+01, -3.9627652377915460e+01, -3.9477301540882898e+01, -3.9328940897733005e+01, -3.9182462160622038e+01, -3.9037766825696743e+01, -3.8894764958744780e+01, -3.8753374169663459e+01, -3.8613518740869551e+01, -3.8475128882166949e+01, -3.8338140090226339e+01, -3.8202492595171613e+01, -3.8068130880140181e+01, -3.7935003262326774e+01, -3.7803061526106617e+01, -3.7672260600494710e+01, -3.7542558274527337e+01, -3.7413914945224782e+01, -3.7286293393664437e+01, -3.7159658585403463e+01, -3.7033977492073106e+01, -3.6909218931447313e+01, -3.6785353423686914e+01, -3.6662353061792466e+01, -3.6540191394576318e+01, -3.6418843320698095e+01, -3.6298284992504144e+01, -3.6178493728578346e+01, -3.6059447934053360e+01, -3.5941127027851913e+01, -3.5823511376131307e+01, -3.5706582231293183e+01, -3.5590321675996748e+01, -3.5474712571679902e+01, -3.5359738511149921e+01, -3.5245383774854993e+01, -3.5131633290491287e+01, -3.5018472595637796e+01, -3.4905887803144765e+01, -3.4793865569030025e+01, -3.4682393062663479e+01, -3.4571457939042368e+01, -3.4461048312979749e+01, -3.4351152735046398e+01, -3.4241760169121903e+01, -3.4132859971424416e+01, -3.4024441870901214e+01, -3.3916495950872942e+01, -3.3809012631834399e+01, -3.3701982655323533e+01, -3.3595397068778212e+01, -3.3489247211307294e+01, -3.3383524700309152e+01, -3.3278221418876420e+01, -3.3173329503930695e+01, -3.3068841335036161e+01, -3.2964749523844645e+01, -3.2861046904129154e+01, -3.2757726522365701e+01, -3.2654781628827138e+01, -3.2552205669154873e+01, -3.2449992276377536e+01, -3.2348135263347665e+01, -3.2246628615569911e+01, -3.2145466484395946e+01, -3.2044643180563561e+01, -3.1944153168058502e+01, -3.1843991058279617e+01, -3.1744151604489051e+01, -3.1644629696530501e+01, -3.1545420355799866e+01, -3.1446518730453519e+01, -3.1347920090840642e+01, -3.1249619825146823e+01, -3.1151613435236992e+01, -3.1053896532686657e+01, -3.0956464834991067e+01, -3.0859314161942471e+01, -3.0762440432166571e+01, -3.0665839659809521e+01, -3.0569507951367541e+01, -3.0473441502651706e+01, -3.0377636595880823e+01, -3.0282089596895890e+01, -3.0186796952489885e+01, -3.0091755187847035e+01, -2.9996960904086251e+01, -2.9902410775903341e+01, -2.9808101549307406e+01, -2.9714030039446573e+01, -2.9620193128519009e+01, -2.9526587763764987e+01, -2.9433210955536232e+01, -2.9340059775438863e+01, -2.9247131354546639e+01, -2.9154422881681075e+01, -2.9061931601755546e+01, -2.8969654814180412e+01, -2.8877589871326357e+01, -2.8785734177043501e+01, -2.8694085185233607e+01, -2.8602640398473323e+01, -2.8511397366685994e+01, -2.8420353685860018e+01, -2.8329506996811961e+01, -2.8238854983992127e+01, -2.8148395374331187e+01, -2.8058125936125919e+01, -2.7968044477962561e+01, -2.7878148847676105e+01, -2.7788436931344155e+01, -2.7698906652314001e+01, -2.7609555970261415e+01, -2.7520382880279982e+01, -2.7431385411999880e+01, -2.7342561628734678e+01, -2.7253909626655357e+01, -2.7165427533990211e+01, -2.7077113510249937e+01, -2.6988965745476666e+01, -2.6900982459516204e+01, -2.6813161901312569e+01, -2.6725502348223944e+01, -2.6638002105359295e+01, -2.6550659504934920e+01, -2.6463472905650097e+01, -2.6376440692081239e+01, -2.6289561274093888e+01, -2.6202833086271735e+01, -2.6116254587362352e+01, -2.6029824259738753e+01, -2.5943540608876461e+01, -2.5857402162845347e+01, -2.5771407471815856e+01, -2.5685555107579106e+01, -2.5599843663080311e+01, -2.5514271751965165e+01, -2.5428838008138701e+01, -2.5343541085336156e+01, -2.5258379656705593e+01, -2.5173352414401720e+01, -2.5088458069190668e+01, -2.5003695350065200e+01, -2.4919063003870239e+01, -2.4834559794938261e+01, -2.4750184504734069e+01, -2.4665935931509065e+01, -2.4581812889964240e+01, -2.4497814210922002e+01, -2.4413938741006234e+01, -2.4330185342330651e+01, -2.4246552892194927e+01, -2.4163040282788444e+01, -2.4079646420901529e+01, -2.3996370227643787e+01, -2.3913210638169407e+01, -2.3830166601409211e+01, -2.3747237079809292e+01, -2.3664421049075887e+01, -2.3581717497926537e+01, -2.3499125427847165e+01, -2.3416643852854872e+01, -2.3334271799266503e+01, -2.3252008305472639e+01, -2.3169852421716808e+01, -2.3087803209879958e+01, -2.3005859743269887e+01, -2.2924021106415548e+01, -2.2842286394866068e+01, -2.2760654714994427e+01, -2.2679125183805475e+01, -2.2597696928748395e+01, -2.2516369087533366e+01, -2.2435140807952337e+01, -2.2354011247703728e+01, -2.2272979574221061e+01, -2.2192044964505438e+01, -2.2111206604961527e+01, -2.2030463691237291e+01, -2.1949815428067097e+01, -2.1869261029118242e+01, -2.1788799716840746e+01, -2.1708430722320461e+01, -2.1628153285135163e+01, -2.1547966653213770e+01, -2.1467870082698525e+01, -2.1387862837810047e+01, -2.1307944190715197e+01, -2.1228113421397740e+01, -2.1148369817531513e+01, -2.1068712674356462e+01, -2.0989141294556969e+01, -2.0909654988142822e+01, -2.0830253072332479e+01, -2.0750934871438766e+01, -2.0671699716756873e+01, -2.0592546946454480e+01, -2.0513475905464212e+01, -2.0434485945378121e+01, -2.0355576424344289e+01, -2.0276746706965469e+01, -2.0197996164199605e+01, -2.0119324173262470e+01, -2.0040730117532004e+01, -1.9962213386454575e+01, -1.9883773375453060e+01, -1.9805409485836627e+01, -1.9727121124712237e+01, -1.9648907704897862e+01, -1.9570768644837273e+01, -1.9492703368516462e+01, -1.9414711305381655e+01, -1.9336791890258731e+01, -1.9258944563274309e+01, -1.9181168769778076e+01, -1.9103463960266723e+01, -1.9025829590309190e+01, -1.8948265120473195e+01, -1.8870770016253275e+01, -1.8793343747999923e+01, -1.8715985790850127e+01, -1.8638695624659118e+01, -1.8561472733933261e+01, -1.8484316607764278e+01, -1.8407226739764468e+01, -1.8330202628003185e+01, -1.8253243774944330e+01, -1.8176349687385034e+01, -1.8099519876395316e+01, -1.8022753857258820e+01, -1.7946051149414522e+01, -1.7869411276399575e+01, -1.7792833765792906e+01, -1.7716318149159967e+01, -1.7639863961998302e+01, -1.7563470743684078e+01, -1.7487138037419523e+01, -1.7410865390181165e+01, -1.7334652352669064e+01, -1.7258498479256687e+01, -1.7182403327941838e+01, -1.7106366460298190e+01, -1.7030387441427770e+01, -1.6954465839914089e+01, -1.6878601227776095e+01, -1.6802793180422885e+01, -1.6727041276609075e+01, -1.6651345098390959e+01, -1.6575704231083332e+01, -1.6500118263217015e+01, -1.6424586786496938e+01, -1.6349109395761158e+01, -1.6273685688940152e+01, -1.6198315267017090e+01, -1.6122997733988477e+01, -1.6047732696825530e+01, -1.5972519765436108e+01, -1.5897358552627267e+01, -1.5822248674068314e+01, -1.5747189748254526e+01, -1.5672181396471283e+01, -1.5597223242758899e+01, -1.5522314913877866e+01, -1.5447456039274654e+01, -1.5372646251048026e+01, -1.5297885183915893e+01, -1.5223172475182583e+01, -1.5148507764706597e+01, -1.5073890694868956e+01, -1.4999320910541865e+01, -1.4924798059057919e+01, -1.4850321790179690e+01, -1.4775891756069882e+01, -1.4701507611261734e+01, -1.4627169012629992e+01, -1.4552875619362283e+01, -1.4478627092930742e+01, -1.4404423097064305e+01, -1.4330263297721130e+01, -1.4256147363061572e+01, -1.4182074963421478e+01, -1.4108045771285859e+01, -1.4034059461262968e+01, -1.3960115710058595e+01, -1.3886214196450945e+01, -1.3812354601265659e+01, -1.3738536607351282e+01, -1.3664759899554996e+01, -1.3591024164698768e+01, -1.3517329091555750e+01, -1.3443674370827010e+01, -1.3370059695118606e+01, -1.3296484758918925e+01, -1.3222949258576309e+01, -1.3149452892277091e+01, -1.3075995360023759e+01, -1.3002576363613498e+01, -1.2929195606617004e+01, -1.2855852794357594e+01, -1.2782547633890516e+01, -1.2709279833982581e+01, -1.2636049105092079e+01, -1.2562855159348816e+01, -1.2489697710534655e+01, -1.2416576474064003e+01, -1.2343491166964800e+01, -1.2270441507859598e+01, -1.2197427216946915e+01, -1.2124448015982836e+01, -1.2051503628262809e+01, -1.1978593778603777e+01, -1.1905718193326296e+01, -1.1832876600237160e+01, -1.1760068728611978e+01, -1.1687294309178153e+01, -1.1614553074097962e+01, -1.1541844756951871e+01, -1.1469169092722094e+01, -1.1396525817776201e+01, -1.1323914669851092e+01, -1.1251335388037116e+01, -1.1178787712762269e+01, -1.1106271385776719e+01, -1.1033786150137431e+01, -1.0961331750192977e+01, -1.0888907931568552e+01, -1.0816514441151119e+01, -1.0744151027074789e+01, -1.0671817438706267e+01, -1.0599513426630580e+01, -1.0527238742636838e+01, -1.0454993139704326e+01, -1.0382776371988530e+01, -1.0310588194807536e+01, -1.0238428364628392e+01, -1.0166296639053789e+01, -1.0094192776808759e+01, -1.0022116537727552e+01, -9.9500676827407002e+00, -9.8780459738622000e+00, -9.8060511741767478e+00, -9.7340830478272817e+00, -9.6621413600024599e+00, -9.5902258769244622e+00, -9.5183363658367455e+00, -9.4464725949920272e+00, -9.3746343336404276e+00, -9.3028213520175971e+00, -9.2310334213331053e+00, -9.1592703137588636e+00, -9.0875318024176934e+00, -9.0158176613720489e+00, -8.9441276656127418e+00, -8.8724615910478946e+00, -8.8008192144919590e+00, -8.7292003136548022e+00, -8.6576046671310181e+00, -8.5860320543891664e+00, -8.5144822557612869e+00, -8.4429550524324064e+00, -8.3714502264301647e+00, -8.2999675606146148e+00, -8.2285068386679985e+00, -8.1570678450846863e+00, -8.0856503651612233e+00, -8.0142541849864681e+00, -7.9428790914317364e+00, -7.8715248721411362e+00, -7.8001913155219809e+00, -7.7288782107351981e+00, -7.6575853476859654e+00, -7.5863125170142718e+00, -7.5150595100856830e+00, -7.4438261189821455e+00, -7.3726121364928936e+00, -7.3014173561053433e+00, -7.2302415719962072e+00, -7.1590845790225792e+00, -7.0879461727131350e+00, -7.0168261492593915e+00, -6.9457243055070377e+00, -6.8746404389473783e+00, -6.8035743477087536e+00, -6.7325258305481759e+00, -6.6614946868428833e+00, -6.5904807165820172e+00, -6.5194837203584086e+00, -6.4485034993603865e+00, -6.3775398553636435e+00, -6.3065925907231932e+00, -6.2356615083653448e+00, -6.1647464117798050e+00, -6.0938471050117666e+00, -6.0229633926541144e+00, -5.9520950798396655e+00, -5.8812419722334273e+00, -5.8104038760250001e+00, -5.7395805979209671e+00, -5.6687719451373138e+00, -5.5979777253920124e+00, -5.5271977468975306e+00, -5.4564318183534688e+00, -5.3856797489392338e+00, -5.3149413483067578e+00, -5.2442164265731881e+00, -5.1735047943138541e+00, -5.1028062625549762e+00, -5.0321206427666185e+00, -4.9614477468556784e+00, -4.8907873871588254e+00, -4.8201393764355940e+00, -4.7495035278614024e+00, -4.6788796550207188e+00, -4.6082675719001784e+00, -4.5376670928818852e+00, -4.4670780327365147e+00, -4.3965002066167251e+00, -4.3259334300503776e+00, -4.2553775189339653e+00, -4.1848322895259793e+00, -4.1142975584402999e+00, -4.0437731426397594e+00, -3.9732588594295453e+00, -3.9027545264507393e+00, -3.8322599616740045e+00, -3.7617749833929883e+00, -3.6912994102181265e+00, -3.6208330610702295e+00, -3.5503757551741288e+00, -3.4799273120524967e+00, -3.4094875515195500e+00, -3.3390562936747945e+00, -3.2686333588968939e+00, -3.1982185678374546e+00, -3.1278117414149098e+00, -3.0574127008083849e+00, -2.9870212674516683e+00, -2.9166372630270403e+00, -2.8462605094593112e+00, -2.7758908289098359e+00, -2.7055280437703884e+00, -2.6351719766573134e+00, -2.5648224504055106e+00, -2.4944792880625717e+00, -2.4241423128827679e+00, -2.3538113483212042e+00, -2.2834862180280453e+00, -2.2131667458424626e+00, -2.1428527557870032e+00, -2.0725440720616515e+00, -2.0022405190380281e+00, -1.9319419212536983e+00, -1.8616481034062751e+00, -1.7913588903478110e+00, -1.7210741070789255e+00, -1.6507935787431380e+00, -1.5805171306212125e+00, -1.5102445881253126e+00, -1.4399757767935024e+00, -1.3697105222839356e+00, -1.2994486503691949e+00, -1.2291899869307410e+00, -1.1589343579531839e+00, -1.0886815895186863e+00, -1.0184315078012904e+00, -9.4818393906140797e-01, -8.7793870964012810e-01, -8.0769564595361953e-01, -7.3745457448757024e-01, -6.6721532179163556e-01, -5.9697771447375625e-01, -5.2674157919469489e-01, -4.5650674266238528e-01, -3.8627303162643217e-01, -3.1604027287250513e-01, -2.4580829321681560e-01, -1.7557691950049939e-01, -1.0534597858419388e-01, -3.5115297342303772e-02, 3.5115297342303772e-02, 1.0534597858419388e-01, 1.7557691950049939e-01, 2.4580829321681560e-01, 3.1604027287250513e-01, 3.8627303162643217e-01, 4.5650674266238528e-01, 5.2674157919469489e-01, 5.9697771447375625e-01, 6.6721532179163556e-01, 7.3745457448757024e-01, 8.0769564595361953e-01, 8.7793870964012810e-01, 9.4818393906140797e-01, 1.0184315078012904e+00, 1.0886815895186863e+00, 1.1589343579531839e+00, 1.2291899869307410e+00, 1.2994486503691949e+00, 1.3697105222839356e+00, 1.4399757767935024e+00, 1.5102445881253126e+00, 1.5805171306212125e+00, 1.6507935787431380e+00, 1.7210741070789255e+00, 1.7913588903478110e+00, 1.8616481034062751e+00, 1.9319419212536983e+00, 2.0022405190380281e+00, 2.0725440720616515e+00, 2.1428527557870032e+00, 2.2131667458424626e+00, 2.2834862180280453e+00, 2.3538113483212042e+00, 2.4241423128827679e+00, 2.4944792880625717e+00, 2.5648224504055106e+00, 2.6351719766573134e+00, 2.7055280437703884e+00, 2.7758908289098359e+00, 2.8462605094593112e+00, 2.9166372630270403e+00, 2.9870212674516683e+00, 3.0574127008083849e+00, 3.1278117414149098e+00, 3.1982185678374546e+00, 3.2686333588968939e+00, 3.3390562936747945e+00, 3.4094875515195500e+00, 3.4799273120524967e+00, 3.5503757551741288e+00, 3.6208330610702295e+00, 3.6912994102181265e+00, 3.7617749833929883e+00, 3.8322599616740045e+00, 3.9027545264507393e+00, 3.9732588594295453e+00, 4.0437731426397594e+00, 4.1142975584402999e+00, 4.1848322895259793e+00, 4.2553775189339653e+00, 4.3259334300503776e+00, 4.3965002066167251e+00, 4.4670780327365147e+00, 4.5376670928818852e+00, 4.6082675719001784e+00, 4.6788796550207188e+00, 4.7495035278614024e+00, 4.8201393764355940e+00, 4.8907873871588254e+00, 4.9614477468556784e+00, 5.0321206427666185e+00, 5.1028062625549762e+00, 5.1735047943138541e+00, 5.2442164265731881e+00, 5.3149413483067578e+00, 5.3856797489392338e+00, 5.4564318183534688e+00, 5.5271977468975306e+00, 5.5979777253920124e+00, 5.6687719451373138e+00, 5.7395805979209671e+00, 5.8104038760250001e+00, 5.8812419722334273e+00, 5.9520950798396655e+00, 6.0229633926541144e+00, 6.0938471050117666e+00, 6.1647464117798050e+00, 6.2356615083653448e+00, 6.3065925907231932e+00, 6.3775398553636435e+00, 6.4485034993603865e+00, 6.5194837203584086e+00, 6.5904807165820172e+00, 6.6614946868428833e+00, 6.7325258305481759e+00, 6.8035743477087536e+00, 6.8746404389473783e+00, 6.9457243055070377e+00, 7.0168261492593915e+00, 7.0879461727131350e+00, 7.1590845790225792e+00, 7.2302415719962072e+00, 7.3014173561053433e+00, 7.3726121364928936e+00, 7.4438261189821455e+00, 7.5150595100856830e+00, 7.5863125170142718e+00, 7.6575853476859654e+00, 7.7288782107351981e+00, 7.8001913155219809e+00, 7.8715248721411362e+00, 7.9428790914317364e+00, 8.0142541849864681e+00, 8.0856503651612233e+00, 8.1570678450846863e+00, 8.2285068386679985e+00, 8.2999675606146148e+00, 8.3714502264301647e+00, 8.4429550524324064e+00, 8.5144822557612869e+00, 8.5860320543891664e+00, 8.6576046671310181e+00, 8.7292003136548022e+00, 8.8008192144919590e+00, 8.8724615910478946e+00, 8.9441276656127418e+00, 9.0158176613720489e+00, 9.0875318024176934e+00, 9.1592703137588636e+00, 9.2310334213331053e+00, 9.3028213520175971e+00, 9.3746343336404276e+00, 9.4464725949920272e+00, 9.5183363658367455e+00, 9.5902258769244622e+00, 9.6621413600024599e+00, 9.7340830478272817e+00, 9.8060511741767478e+00, 9.8780459738622000e+00, 9.9500676827407002e+00, 1.0022116537727552e+01, 1.0094192776808759e+01, 1.0166296639053789e+01, 1.0238428364628392e+01, 1.0310588194807536e+01, 1.0382776371988530e+01, 1.0454993139704326e+01, 1.0527238742636838e+01, 1.0599513426630580e+01, 1.0671817438706267e+01, 1.0744151027074789e+01, 1.0816514441151119e+01, 1.0888907931568552e+01, 1.0961331750192977e+01, 1.1033786150137431e+01, 1.1106271385776719e+01, 1.1178787712762269e+01, 1.1251335388037116e+01, 1.1323914669851092e+01, 1.1396525817776201e+01, 1.1469169092722094e+01, 1.1541844756951871e+01, 1.1614553074097962e+01, 1.1687294309178153e+01, 1.1760068728611978e+01, 1.1832876600237160e+01, 1.1905718193326296e+01, 1.1978593778603777e+01, 1.2051503628262809e+01, 1.2124448015982836e+01, 1.2197427216946915e+01, 1.2270441507859598e+01, 1.2343491166964800e+01, 1.2416576474064003e+01, 1.2489697710534655e+01, 1.2562855159348816e+01, 1.2636049105092079e+01, 1.2709279833982581e+01, 1.2782547633890516e+01, 1.2855852794357594e+01, 1.2929195606617004e+01, 1.3002576363613498e+01, 1.3075995360023759e+01, 1.3149452892277091e+01, 1.3222949258576309e+01, 1.3296484758918925e+01, 1.3370059695118606e+01, 1.3443674370827010e+01, 1.3517329091555750e+01, 1.3591024164698768e+01, 1.3664759899554996e+01, 1.3738536607351282e+01, 1.3812354601265659e+01, 1.3886214196450945e+01, 1.3960115710058595e+01, 1.4034059461262968e+01, 1.4108045771285859e+01, 1.4182074963421478e+01, 1.4256147363061572e+01, 1.4330263297721130e+01, 1.4404423097064305e+01, 1.4478627092930742e+01, 1.4552875619362283e+01, 1.4627169012629992e+01, 1.4701507611261734e+01, 1.4775891756069882e+01, 1.4850321790179690e+01, 1.4924798059057919e+01, 1.4999320910541865e+01, 1.5073890694868956e+01, 1.5148507764706597e+01, 1.5223172475182583e+01, 1.5297885183915893e+01, 1.5372646251048026e+01, 1.5447456039274654e+01, 1.5522314913877866e+01, 1.5597223242758899e+01, 1.5672181396471283e+01, 1.5747189748254526e+01, 1.5822248674068314e+01, 1.5897358552627267e+01, 1.5972519765436108e+01, 1.6047732696825530e+01, 1.6122997733988477e+01, 1.6198315267017090e+01, 1.6273685688940152e+01, 1.6349109395761158e+01, 1.6424586786496938e+01, 1.6500118263217015e+01, 1.6575704231083332e+01, 1.6651345098390959e+01, 1.6727041276609075e+01, 1.6802793180422885e+01, 1.6878601227776095e+01, 1.6954465839914089e+01, 1.7030387441427770e+01, 1.7106366460298190e+01, 1.7182403327941838e+01, 1.7258498479256687e+01, 1.7334652352669064e+01, 1.7410865390181165e+01, 1.7487138037419523e+01, 1.7563470743684078e+01, 1.7639863961998302e+01, 1.7716318149159967e+01, 1.7792833765792906e+01, 1.7869411276399575e+01, 1.7946051149414522e+01, 1.8022753857258820e+01, 1.8099519876395316e+01, 1.8176349687385034e+01, 1.8253243774944330e+01, 1.8330202628003185e+01, 1.8407226739764468e+01, 1.8484316607764278e+01, 1.8561472733933261e+01, 1.8638695624659118e+01, 1.8715985790850127e+01, 1.8793343747999923e+01, 1.8870770016253275e+01, 1.8948265120473195e+01, 1.9025829590309190e+01, 1.9103463960266723e+01, 1.9181168769778076e+01, 1.9258944563274309e+01, 1.9336791890258731e+01, 1.9414711305381655e+01, 1.9492703368516462e+01, 1.9570768644837273e+01, 1.9648907704897862e+01, 1.9727121124712237e+01, 1.9805409485836627e+01, 1.9883773375453060e+01, 1.9962213386454575e+01, 2.0040730117532004e+01, 2.0119324173262470e+01, 2.0197996164199605e+01, 2.0276746706965469e+01, 2.0355576424344289e+01, 2.0434485945378121e+01, 2.0513475905464212e+01, 2.0592546946454480e+01, 2.0671699716756873e+01, 2.0750934871438766e+01, 2.0830253072332479e+01, 2.0909654988142822e+01, 2.0989141294556969e+01, 2.1068712674356462e+01, 2.1148369817531513e+01, 2.1228113421397740e+01, 2.1307944190715197e+01, 2.1387862837810047e+01, 2.1467870082698525e+01, 2.1547966653213770e+01, 2.1628153285135163e+01, 2.1708430722320461e+01, 2.1788799716840746e+01, 2.1869261029118242e+01, 2.1949815428067097e+01, 2.2030463691237291e+01, 2.2111206604961527e+01, 2.2192044964505438e+01, 2.2272979574221061e+01, 2.2354011247703728e+01, 2.2435140807952337e+01, 2.2516369087533366e+01, 2.2597696928748395e+01, 2.2679125183805475e+01, 2.2760654714994427e+01, 2.2842286394866068e+01, 2.2924021106415548e+01, 2.3005859743269887e+01, 2.3087803209879958e+01, 2.3169852421716808e+01, 2.3252008305472639e+01, 2.3334271799266503e+01, 2.3416643852854872e+01, 2.3499125427847165e+01, 2.3581717497926537e+01, 2.3664421049075887e+01, 2.3747237079809292e+01, 2.3830166601409211e+01, 2.3913210638169407e+01, 2.3996370227643787e+01, 2.4079646420901529e+01, 2.4163040282788444e+01, 2.4246552892194927e+01, 2.4330185342330651e+01, 2.4413938741006234e+01, 2.4497814210922002e+01, 2.4581812889964240e+01, 2.4665935931509065e+01, 2.4750184504734069e+01, 2.4834559794938261e+01, 2.4919063003870239e+01, 2.5003695350065200e+01, 2.5088458069190668e+01, 2.5173352414401720e+01, 2.5258379656705593e+01, 2.5343541085336156e+01, 2.5428838008138701e+01, 2.5514271751965165e+01, 2.5599843663080311e+01, 2.5685555107579106e+01, 2.5771407471815856e+01, 2.5857402162845347e+01, 2.5943540608876461e+01, 2.6029824259738753e+01, 2.6116254587362352e+01, 2.6202833086271735e+01, 2.6289561274093888e+01, 2.6376440692081239e+01, 2.6463472905650097e+01, 2.6550659504934920e+01, 2.6638002105359295e+01, 2.6725502348223944e+01, 2.6813161901312569e+01, 2.6900982459516204e+01, 2.6988965745476666e+01, 2.7077113510249937e+01, 2.7165427533990211e+01, 2.7253909626655357e+01, 2.7342561628734678e+01, 2.7431385411999880e+01, 2.7520382880279982e+01, 2.7609555970261415e+01, 2.7698906652314001e+01, 2.7788436931344155e+01, 2.7878148847676105e+01, 2.7968044477962561e+01, 2.8058125936125919e+01, 2.8148395374331187e+01, 2.8238854983992127e+01, 2.8329506996811961e+01, 2.8420353685860018e+01, 2.8511397366685994e+01, 2.8602640398473323e+01, 2.8694085185233607e+01, 2.8785734177043501e+01, 2.8877589871326357e+01, 2.8969654814180412e+01, 2.9061931601755546e+01, 2.9154422881681075e+01, 2.9247131354546639e+01, 2.9340059775438863e+01, 2.9433210955536232e+01, 2.9526587763764987e+01, 2.9620193128519009e+01, 2.9714030039446573e+01, 2.9808101549307406e+01, 2.9902410775903341e+01, 2.9996960904086251e+01, 3.0091755187847035e+01, 3.0186796952489885e+01, 3.0282089596895890e+01, 3.0377636595880823e+01, 3.0473441502651706e+01, 3.0569507951367541e+01, 3.0665839659809521e+01, 3.0762440432166571e+01, 3.0859314161942471e+01, 3.0956464834991067e+01, 3.1053896532686657e+01, 3.1151613435236992e+01, 3.1249619825146823e+01, 3.1347920090840642e+01, 3.1446518730453519e+01, 3.1545420355799866e+01, 3.1644629696530501e+01, 3.1744151604489051e+01, 3.1843991058279617e+01, 3.1944153168058502e+01, 3.2044643180563561e+01, 3.2145466484395946e+01, 3.2246628615569911e+01, 3.2348135263347665e+01, 3.2449992276377536e+01, 3.2552205669154873e+01, 3.2654781628827138e+01, 3.2757726522365701e+01, 3.2861046904129154e+01, 3.2964749523844645e+01, 3.3068841335036161e+01, 3.3173329503930695e+01, 3.3278221418876420e+01, 3.3383524700309152e+01, 3.3489247211307294e+01, 3.3595397068778212e+01, 3.3701982655323533e+01, 3.3809012631834399e+01, 3.3916495950872942e+01, 3.4024441870901214e+01, 3.4132859971424416e+01, 3.4241760169121903e+01, 3.4351152735046398e+01, 3.4461048312979749e+01, 3.4571457939042368e+01, 3.4682393062663479e+01, 3.4793865569030025e+01, 3.4905887803144765e+01, 3.5018472595637796e+01, 3.5131633290491287e+01, 3.5245383774854993e+01, 3.5359738511149921e+01, 3.5474712571679902e+01, 3.5590321675996748e+01, 3.5706582231293183e+01, 3.5823511376131307e+01, 3.5941127027851913e+01, 3.6059447934053360e+01, 3.6178493728578346e+01, 3.6298284992504144e+01, 3.6418843320698095e+01, 3.6540191394576318e+01, 3.6662353061792466e+01, 3.6785353423686914e+01, 3.6909218931447313e+01, 3.7033977492073106e+01, 3.7159658585403463e+01, 3.7286293393664437e+01, 3.7413914945224782e+01, 3.7542558274527337e+01, 3.7672260600494710e+01, 3.7803061526106617e+01, 3.7935003262326774e+01, 3.8068130880140181e+01, 3.8202492595171613e+01, 3.8338140090226339e+01, 3.8475128882166949e+01, 3.8613518740869551e+01, 3.8753374169663459e+01, 3.8894764958744780e+01, 3.9037766825696743e+01, 3.9182462160622038e+01, 3.9328940897733005e+01, 3.9477301540882898e+01, 3.9627652377915460e+01, 3.9780112928508778e+01, 3.9934815683324643e+01, 4.0091908210099085e+01, 4.0251555726823973e+01, 4.0413944276381194e+01, 4.0579284685508064e+01, 4.0747817561006038e+01, 4.0919819679199151e+01, 4.1095612279765099e+01, 4.1275572014249832e+01, 4.1460145678774452e+01, 4.1649870480923305e+01, 4.1845402643747086e+01, 4.2047559014075354e+01, 4.2257379812646654e+01, 4.2476227524277085e+01, 4.2705951529047212e+01, 4.2949182188453079e+01, 4.3209908104582034e+01, 4.3494771146334074e+01, 4.3816642022906109e+01, 4.4209152497996392e+01}, w: []float64{0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 3.3329668468450492e-320, 4.0075986642718961e-318, 4.5836615691792330e-316, 5.1176127714709937e-314, 5.5782006898201854e-312, 5.9370037176434776e-310, 6.1710869359890172e-308, 6.2654270878892558e-306, 6.2145076952356061e-304, 6.0228361617963862e-302, 5.7043185644899271e-300, 5.2806082652713648e-298, 4.7786980462699519e-296, 4.2281234022459736e-294, 3.6581718467738525e-292, 3.0954507956523426e-290, 2.5620704080272207e-288, 2.0745725241264515e-286, 1.6436097663423948e-284, 1.2742732003636313e-282, 9.6689753826506193e-281, 7.1814456801699481e-279, 5.2217421416236178e-277, 3.7174816966218167e-275, 2.5916065469690241e-273, 1.7694253405272601e-271, 1.1832968405584233e-269, 7.7518975576944083e-268, 4.9754115871874643e-266, 3.1290300730289451e-264, 1.9284240264071905e-262, 1.1648205513661696e-260, 6.8965220392645158e-259, 4.0028201360407956e-257, 2.2778043641496056e-255, 1.2709546476364080e-253, 6.9543286969416096e-252, 3.7319816642354106e-250, 1.9643998334224751e-248, 1.0143147290142510e-246, 5.1382328650179621e-245, 2.5538665369453056e-243, 1.2455769147570116e-241, 5.9617648426249594e-240, 2.8006220781933600e-238, 1.2913751775454810e-236, 5.8453559227891224e-235, 2.5975977120672768e-233, 1.1333825292477732e-231, 4.8558536412609862e-230, 2.0430517869416229e-228, 8.4422388386550666e-227, 3.4264124275993631e-225, 1.3660423686167456e-223, 5.3501942181727508e-222, 2.0587026324216422e-220, 7.7834793264643977e-219, 2.8916581954653459e-217, 1.0557222065673938e-215, 3.7880694907273763e-214, 1.3359414633484673e-212, 4.6311979145640239e-211, 1.5782306240050564e-209, 5.2875341973740781e-208, 1.7417085836085446e-206, 5.6411930354623643e-205, 1.7966885166110605e-203, 5.6274778917186968e-202, 1.7335102418187571e-200, 5.2522174425854836e-199, 1.5652883428261183e-197, 4.5889434629100622e-196, 1.3235146297070864e-194, 3.7555461091485998e-193, 1.0485183834985678e-191, 2.8804977787988646e-190, 7.7871258963661253e-189, 2.0717353930894859e-187, 5.4246006309405095e-186, 1.3979971540967563e-184, 3.5463219412740393e-183, 8.8554655257623945e-182, 2.1768760700085122e-180, 5.2683241452994028e-179, 1.2553211635344571e-177, 2.9451512664628267e-176, 6.8038898787652193e-175, 1.5478543777968840e-173, 3.4677839663641647e-172, 7.6515383450168328e-171, 1.6628216886897738e-169, 3.5593273811283599e-168, 7.5048219822215126e-167, 1.5587902032532034e-165, 3.1895844350948167e-164, 6.4298937541404803e-163, 1.2770873146297890e-161, 2.4992406762554122e-160, 4.8193627314441185e-159, 9.1577398393994249e-158, 1.7148534423668942e-156, 3.1646695790053421e-155, 5.7559205521726687e-154, 1.0318306794654569e-152, 1.8231871651497053e-151, 3.1754477204679572e-150, 5.4519400815462508e-149, 9.2276445953465577e-148, 1.5397329022186058e-146, 2.5330019418366902e-145, 4.1084868631522107e-144, 6.5705990846248260e-143, 1.0361555453376311e-141, 1.6112461600760618e-140, 2.4707887826290998e-139, 3.7365067262616700e-138, 5.5727784652837080e-137, 8.1973391110091452e-136, 1.1892911728913853e-134, 1.7019097734602088e-133, 2.4023517577408972e-132, 3.3450829826077675e-131, 4.5947908528904288e-130, 6.2263179873318509e-129, 8.3237975699379756e-128, 1.0978782422293458e-126, 1.4287193329226953e-125, 1.8344977691984857e-124, 2.3242468856634865e-123, 2.9057566734636031e-122, 3.5848013541900561e-121, 4.3643201011221327e-120, 5.2436098752156138e-119, 6.2176015753999047e-118, 7.2762975927456467e-117, 8.4044484286651008e-116, 9.5815369347020579e-115, 1.0782120545724555e-113, 1.1976555369726998e-112, 1.3132093168021923e-111, 1.4214306236084630e-110, 1.5188759914460687e-109, 1.6022822189494409e-108, 1.6687478601660490e-107, 1.7159011632384579e-106, 1.7420408695770434e-105, 1.7462381930467704e-104, 1.7283914491118722e-103, 1.6892288684937835e-102, 1.6302596600457935e-101, 1.5536778758574346e-100, 1.4622275809196764e-99, 1.3590408202563549e-98, 1.2474616193874682e-97, 1.1308696244314536e-96, 1.0125160327802958e-95, 8.9538238503709081e-95, 7.8206990104609633e-94, 6.7472372997026518e-93, 5.7499313869447363e-92, 4.8402563555834996e-91, 4.0249058822982866e-90, 3.3062621228934451e-89, 2.6830293789353161e-88, 2.1509606264107007e-87, 1.7036114781391146e-86, 1.3330664066276539e-85, 1.0305951518623542e-84, 7.8721132506904387e-84, 5.9411871493166694e-83, 4.4304253111256539e-82, 3.2645205816409649e-81, 2.3768765122027434e-80, 1.7100875682708707e-79, 1.2158102629355303e-78, 8.5420101452037198e-78, 5.9307849802130665e-77, 4.0694244255316937e-76, 2.7595184467913268e-75, 1.8493700277748019e-74, 1.2249408613163427e-73, 8.0189539522785623e-73, 5.1885022241593757e-72, 3.3181673688922034e-71, 2.0974748886451008e-70, 1.3105318083913364e-69, 8.0939533379932165e-69, 4.9413553496512498e-68, 2.9820407337754590e-67, 1.7789874895279432e-66, 1.0491406305859313e-65, 6.1165364987659488e-65, 3.5253152759474540e-64, 2.0087239862730963e-63, 1.1315709177343451e-62, 6.3021931416666470e-62, 3.4702373903635070e-61, 1.8892665906870333e-60, 1.0169575920927853e-59, 5.4124867967047064e-59, 2.8482890022548686e-58, 1.4820851523028527e-57, 7.6255782662767904e-57, 3.8796404008463247e-56, 1.9518106701136368e-55, 9.7100129027526196e-55, 4.7768997974014920e-54, 2.3239398491612035e-53, 1.1180576701525420e-52, 5.3195165510395952e-52, 2.5029763689774771e-51, 1.1647316378880106e-50, 5.3602786943809252e-50, 2.4397706595195753e-49, 1.0982936194156852e-48, 4.8899379879160616e-48, 2.1533330989172484e-47, 9.3788484682437942e-47, 4.0404120146067421e-46, 1.7216582220922559e-45, 7.2563902256297714e-45, 3.0251986512140371e-44, 1.2475382033165966e-43, 5.0889423919887406e-43, 2.0534394826865196e-42, 8.1964137583105787e-42, 3.2363856080594989e-41, 1.2641477416407965e-40, 4.8847605989668363e-40, 1.8672533221548388e-39, 7.0612935196951311e-39, 2.6417568903758940e-38, 9.7776710583318967e-38, 3.5802911787217544e-37, 1.2970237375676620e-36, 4.6486878345616557e-36, 1.6484352599338373e-35, 5.7833378697531460e-35, 2.0075040700651605e-34, 6.8946382222670282e-34, 2.3428777403438029e-33, 7.8772879147862415e-33, 2.6205868311897299e-32, 8.6262266028303368e-32, 2.8096311791269716e-31, 9.0550221579615647e-31, 2.8876664192770605e-30, 9.1122854941717965e-30, 2.8453509035148136e-29, 8.7918028150808172e-29, 2.6881837159369457e-28, 8.1336242788329602e-28, 2.4353344728003697e-27, 7.2158518959500610e-27, 2.1158075825687643e-26, 6.1394478289562773e-26, 1.7629987629083774e-25, 5.0101319085046131e-25, 1.4090474655086476e-24, 3.9218067686130826e-24, 1.0802781850376285e-23, 2.9449542387975020e-23, 7.9454711482554462e-23, 2.1215999344125686e-22, 5.6067938151587689e-22, 1.4664842311858356e-21, 3.7962634220532337e-21, 9.7264816603883115e-21, 2.4664936245525687e-20, 6.1906074549278360e-20, 1.5378705407232610e-19, 3.7813221317079150e-19, 9.2025684357177584e-19, 2.2167665318045311e-18, 5.2854304894605380e-18, 1.2473669179231829e-17, 2.9138380453817078e-17, 6.7374842509995276e-17, 1.5420379617888631e-16, 3.4935024197829202e-16, 7.8342854947400979e-16, 1.7390566642632192e-15, 3.8212693116409553e-15, 8.3116005961883490e-15, 1.7895682715395592e-14, 3.8141862420255930e-14, 8.0472764307002063e-14, 1.6807095910482497e-13, 3.4748531426400642e-13, 7.1118646783760585e-13, 1.4409103280748072e-12, 2.8900143727527258e-12, 5.7382005087901198e-12, 1.1278910422361978e-11, 2.1947106970283908e-11, 4.2277477293524813e-11, 8.0624196629608479e-11, 1.5221208598065262e-10, 2.8448743011328098e-10, 5.2639286110224670e-10, 9.6425649803121777e-10, 1.7486926968693157e-09, 3.1396076182667553e-09, 5.5805985109895517e-09, 9.8204691294517891e-09, 1.7109299168762458e-08, 2.9510948481539917e-08, 5.0395001696989557e-08, 8.5201541017792893e-08, 1.4261507022163221e-07, 2.3634347938818411e-07, 3.8777898392560284e-07, 6.2992596495326851e-07, 1.0131213408959264e-06, 1.6132519497006137e-06, 2.5433945667023898e-06, 3.9700690907623210e-06, 6.1356010118598152e-06, 9.3884255415649498e-06, 1.4223513143507425e-05, 2.1335422543862233e-05, 3.1686745345790127e-05, 4.6594831688914123e-05, 6.7839596902281318e-05, 9.7794806816374214e-05, 1.3958441538648416e-04, 1.9726417155921489e-04, 2.7602672333940944e-04, 3.8242575576777089e-04, 5.2461128756050050e-04, 7.1256417605653876e-04, 9.5831329960547609e-04, 1.2761140785636331e-03, 1.6825623704389105e-03, 2.1966138706150684e-03, 2.8394766158808572e-03, 3.6343437380220228e-03, 4.6059359641037120e-03, 5.7798291360525392e-03, 7.1815516617926393e-03, 8.8354504500150321e-03, 1.0763341256408045e-02, 1.2982979738738085e-02, 1.5506411627211223e-02, 1.8338282523509799e-02, 2.1474207807753411e-02, 2.4899318588318450e-02, 2.8587108202015418e-02, 3.2498703362722522e-02, 3.6582673133333132e-02, 4.0775466771331127e-02, 4.5002538542463881e-02, 4.9180175360908490e-02, 5.3217994313108079e-02, 5.7022025487230163e-02, 6.0498245497917852e-02, 6.3556383402228842e-02, 6.6113787870520968e-02, 6.8099126303218016e-02, 6.9455685670940681e-02, 7.0144062233596524e-02, 7.0144062233596524e-02, 6.9455685670940681e-02, 6.8099126303218016e-02, 6.6113787870520968e-02, 6.3556383402228842e-02, 6.0498245497917852e-02, 5.7022025487230163e-02, 5.3217994313108079e-02, 4.9180175360908490e-02, 4.5002538542463881e-02, 4.0775466771331127e-02, 3.6582673133333132e-02, 3.2498703362722522e-02, 2.8587108202015418e-02, 2.4899318588318450e-02, 2.1474207807753411e-02, 1.8338282523509799e-02, 1.5506411627211223e-02, 1.2982979738738085e-02, 1.0763341256408045e-02, 8.8354504500150321e-03, 7.1815516617926393e-03, 5.7798291360525392e-03, 4.6059359641037120e-03, 3.6343437380220228e-03, 2.8394766158808572e-03, 2.1966138706150684e-03, 1.6825623704389105e-03, 1.2761140785636331e-03, 9.5831329960547609e-04, 7.1256417605653876e-04, 5.2461128756050050e-04, 3.8242575576777089e-04, 2.7602672333940944e-04, 1.9726417155921489e-04, 1.3958441538648416e-04, 9.7794806816374214e-05, 6.7839596902281318e-05, 4.6594831688914123e-05, 3.1686745345790127e-05, 2.1335422543862233e-05, 1.4223513143507425e-05, 9.3884255415649498e-06, 6.1356010118598152e-06, 3.9700690907623210e-06, 2.5433945667023898e-06, 1.6132519497006137e-06, 1.0131213408959264e-06, 6.2992596495326851e-07, 3.8777898392560284e-07, 2.3634347938818411e-07, 1.4261507022163221e-07, 8.5201541017792893e-08, 5.0395001696989557e-08, 2.9510948481539917e-08, 1.7109299168762458e-08, 9.8204691294517891e-09, 5.5805985109895517e-09, 3.1396076182667553e-09, 1.7486926968693157e-09, 9.6425649803121777e-10, 5.2639286110224670e-10, 2.8448743011328098e-10, 1.5221208598065262e-10, 8.0624196629608479e-11, 4.2277477293524813e-11, 2.1947106970283908e-11, 1.1278910422361978e-11, 5.7382005087901198e-12, 2.8900143727527258e-12, 1.4409103280748072e-12, 7.1118646783760585e-13, 3.4748531426400642e-13, 1.6807095910482497e-13, 8.0472764307002063e-14, 3.8141862420255930e-14, 1.7895682715395592e-14, 8.3116005961883490e-15, 3.8212693116409553e-15, 1.7390566642632192e-15, 7.8342854947400979e-16, 3.4935024197829202e-16, 1.5420379617888631e-16, 6.7374842509995276e-17, 2.9138380453817078e-17, 1.2473669179231829e-17, 5.2854304894605380e-18, 2.2167665318045311e-18, 9.2025684357177584e-19, 3.7813221317079150e-19, 1.5378705407232610e-19, 6.1906074549278360e-20, 2.4664936245525687e-20, 9.7264816603883115e-21, 3.7962634220532337e-21, 1.4664842311858356e-21, 5.6067938151587689e-22, 2.1215999344125686e-22, 7.9454711482554462e-23, 2.9449542387975020e-23, 1.0802781850376285e-23, 3.9218067686130826e-24, 1.4090474655086476e-24, 5.0101319085046131e-25, 1.7629987629083774e-25, 6.1394478289562773e-26, 2.1158075825687643e-26, 7.2158518959500610e-27, 2.4353344728003697e-27, 8.1336242788329602e-28, 2.6881837159369457e-28, 8.7918028150808172e-29, 2.8453509035148136e-29, 9.1122854941717965e-30, 2.8876664192770605e-30, 9.0550221579615647e-31, 2.8096311791269716e-31, 8.6262266028303368e-32, 2.6205868311897299e-32, 7.8772879147862415e-33, 2.3428777403438029e-33, 6.8946382222670282e-34, 2.0075040700651605e-34, 5.7833378697531460e-35, 1.6484352599338373e-35, 4.6486878345616557e-36, 1.2970237375676620e-36, 3.5802911787217544e-37, 9.7776710583318967e-38, 2.6417568903758940e-38, 7.0612935196951311e-39, 1.8672533221548388e-39, 4.8847605989668363e-40, 1.2641477416407965e-40, 3.2363856080594989e-41, 8.1964137583105787e-42, 2.0534394826865196e-42, 5.0889423919887406e-43, 1.2475382033165966e-43, 3.0251986512140371e-44, 7.2563902256297714e-45, 1.7216582220922559e-45, 4.0404120146067421e-46, 9.3788484682437942e-47, 2.1533330989172484e-47, 4.8899379879160616e-48, 1.0982936194156852e-48, 2.4397706595195753e-49, 5.3602786943809252e-50, 1.1647316378880106e-50, 2.5029763689774771e-51, 5.3195165510395952e-52, 1.1180576701525420e-52, 2.3239398491612035e-53, 4.7768997974014920e-54, 9.7100129027526196e-55, 1.9518106701136368e-55, 3.8796404008463247e-56, 7.6255782662767904e-57, 1.4820851523028527e-57, 2.8482890022548686e-58, 5.4124867967047064e-59, 1.0169575920927853e-59, 1.8892665906870333e-60, 3.4702373903635070e-61, 6.3021931416666470e-62, 1.1315709177343451e-62, 2.0087239862730963e-63, 3.5253152759474540e-64, 6.1165364987659488e-65, 1.0491406305859313e-65, 1.7789874895279432e-66, 2.9820407337754590e-67, 4.9413553496512498e-68, 8.0939533379932165e-69, 1.3105318083913364e-69, 2.0974748886451008e-70, 3.3181673688922034e-71, 5.1885022241593757e-72, 8.0189539522785623e-73, 1.2249408613163427e-73, 1.8493700277748019e-74, 2.7595184467913268e-75, 4.0694244255316937e-76, 5.9307849802130665e-77, 8.5420101452037198e-78, 1.2158102629355303e-78, 1.7100875682708707e-79, 2.3768765122027434e-80, 3.2645205816409649e-81, 4.4304253111256539e-82, 5.9411871493166694e-83, 7.8721132506904387e-84, 1.0305951518623542e-84, 1.3330664066276539e-85, 1.7036114781391146e-86, 2.1509606264107007e-87, 2.6830293789353161e-88, 3.3062621228934451e-89, 4.0249058822982866e-90, 4.8402563555834996e-91, 5.7499313869447363e-92, 6.7472372997026518e-93, 7.8206990104609633e-94, 8.9538238503709081e-95, 1.0125160327802958e-95, 1.1308696244314536e-96, 1.2474616193874682e-97, 1.3590408202563549e-98, 1.4622275809196764e-99, 1.5536778758574346e-100, 1.6302596600457935e-101, 1.6892288684937835e-102, 1.7283914491118722e-103, 1.7462381930467704e-104, 1.7420408695770434e-105, 1.7159011632384579e-106, 1.6687478601660490e-107, 1.6022822189494409e-108, 1.5188759914460687e-109, 1.4214306236084630e-110, 1.3132093168021923e-111, 1.1976555369726998e-112, 1.0782120545724555e-113, 9.5815369347020579e-115, 8.4044484286651008e-116, 7.2762975927456467e-117, 6.2176015753999047e-118, 5.2436098752156138e-119, 4.3643201011221327e-120, 3.5848013541900561e-121, 2.9057566734636031e-122, 2.3242468856634865e-123, 1.8344977691984857e-124, 1.4287193329226953e-125, 1.0978782422293458e-126, 8.3237975699379756e-128, 6.2263179873318509e-129, 4.5947908528904288e-130, 3.3450829826077675e-131, 2.4023517577408972e-132, 1.7019097734602088e-133, 1.1892911728913853e-134, 8.1973391110091452e-136, 5.5727784652837080e-137, 3.7365067262616700e-138, 2.4707887826290998e-139, 1.6112461600760618e-140, 1.0361555453376311e-141, 6.5705990846248260e-143, 4.1084868631522107e-144, 2.5330019418366902e-145, 1.5397329022186058e-146, 9.2276445953465577e-148, 5.4519400815462508e-149, 3.1754477204679572e-150, 1.8231871651497053e-151, 1.0318306794654569e-152, 5.7559205521726687e-154, 3.1646695790053421e-155, 1.7148534423668942e-156, 9.1577398393994249e-158, 4.8193627314441185e-159, 2.4992406762554122e-160, 1.2770873146297890e-161, 6.4298937541404803e-163, 3.1895844350948167e-164, 1.5587902032532034e-165, 7.5048219822215126e-167, 3.5593273811283599e-168, 1.6628216886897738e-169, 7.6515383450168328e-171, 3.4677839663641647e-172, 1.5478543777968840e-173, 6.8038898787652193e-175, 2.9451512664628267e-176, 1.2553211635344571e-177, 5.2683241452994028e-179, 2.1768760700085122e-180, 8.8554655257623945e-182, 3.5463219412740393e-183, 1.3979971540967563e-184, 5.4246006309405095e-186, 2.0717353930894859e-187, 7.7871258963661253e-189, 2.8804977787988646e-190, 1.0485183834985678e-191, 3.7555461091485998e-193, 1.3235146297070864e-194, 4.5889434629100622e-196, 1.5652883428261183e-197, 5.2522174425854836e-199, 1.7335102418187571e-200, 5.6274778917186968e-202, 1.7966885166110605e-203, 5.6411930354623643e-205, 1.7417085836085446e-206, 5.2875341973740781e-208, 1.5782306240050564e-209, 4.6311979145640239e-211, 1.3359414633484673e-212, 3.7880694907273763e-214, 1.0557222065673938e-215, 2.8916581954653459e-217, 7.7834793264643977e-219, 2.0587026324216422e-220, 5.3501942181727508e-222, 1.3660423686167456e-223, 3.4264124275993631e-225, 8.4422388386550666e-227, 2.0430517869416229e-228, 4.8558536412609862e-230, 1.1333825292477732e-231, 2.5975977120672768e-233, 5.8453559227891224e-235, 1.2913751775454810e-236, 2.8006220781933600e-238, 5.9617648426249594e-240, 1.2455769147570116e-241, 2.5538665369453056e-243, 5.1382328650179621e-245, 1.0143147290142510e-246, 1.9643998334224751e-248, 3.7319816642354106e-250, 6.9543286969416096e-252, 1.2709546476364080e-253, 2.2778043641496056e-255, 4.0028201360407956e-257, 6.8965220392645158e-259, 1.1648205513661696e-260, 1.9284240264071905e-262, 3.1290300730289451e-264, 4.9754115871874643e-266, 7.7518975576944083e-268, 1.1832968405584233e-269, 1.7694253405272601e-271, 2.5916065469690241e-273, 3.7174816966218167e-275, 5.2217421416236178e-277, 7.1814456801699481e-279, 9.6689753826506193e-281, 1.2742732003636313e-282, 1.6436097663423948e-284, 2.0745725241264515e-286, 2.5620704080272207e-288, 3.0954507956523426e-290, 3.6581718467738525e-292, 4.2281234022459736e-294, 4.7786980462699519e-296, 5.2806082652713648e-298, 5.7043185644899271e-300, 6.0228361617963862e-302, 6.2145076952356061e-304, 6.2654270878892558e-306, 6.1710869359890172e-308, 5.9370037176434776e-310, 5.5782006898201854e-312, 5.1176127714709937e-314, 4.5836615691792330e-316, 4.0075986642718961e-318, 3.3329668468450492e-320, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00}, tol: 1e-13, }, } { h := Hermite{} x := make([]float64, test.n) weight := make([]float64, test.n) h.FixedLocations(x, weight, math.Inf(-1), math.Inf(1)) if !floats.EqualApprox(x, test.x, test.tol) { t.Errorf("n = %v, x mismatch", test.n) fmt.Println(x) fmt.Println() fmt.Println(test.x) //t.Errorf("x mismatch. \nWant %v\ngot %v", test.x, x) } if !floats.EqualApprox(weight, test.w, test.tol) { t.Errorf("n = %v, w mismatch", test.n) //t.Errorf("w mismatch. Want %v, got %v", test.w, weight) } } } func TestHermiteInitialGuesses(t *testing.T) { t.Parallel() for _, test := range []struct { n int want []float64 }{ // Evaluated from Chebfun. { n: 215, want: []float64{0, 0.151326329763712, 0.302660700793398, 0.454011159911720, 0.605385765065948, 0.756792590918330, 0.908239734470234, 1.059735320731617, 1.211287508447394, 1.362904495892717, 1.514594526749157, 1.666365896074552, 1.818226956379164, 1.970186123821706, 2.122251884538916, 2.274432801123240, 2.426737519263548, 2.579174774564779, 2.731753399562905, 2.884482330952826, 3.037370617047366, 3.190427425487010, 3.343662051220745, 3.497083924780193, 3.650702620869949, 3.804527867299248, 3.958569554281313, 4.112837744128784, 4.267342681375636, 4.422094803358200, 4.577104751290402, 4.732383381871004, 4.887941779463563, 5.043791268893151, 5.199943428907478, 5.356410106353889, 5.513203431128299, 5.670335831956713, 5.827820053075521, 5.985669171882509, 6.143896617637219, 6.302516191296349, 6.461542086578262, 6.620988912359293, 6.780871716514890, 6.941206011329554, 7.102007800612191, 7.263293608667420, 7.425080511288993, 7.587386168959320, 7.750228862458692, 7.913627531110426, 8.077601813913194, 8.242172093840729, 8.407359545621334, 8.573186187346858, 8.739674936302684, 8.906849669458699, 9.074735289116129, 9.243357794268617, 9.412744358308792, 9.582923413795772, 9.753924745096450, 9.925779589826769, 10.098520750150884, 10.272182715150265, 10.446801795655594, 10.622416273146731, 10.799066564577450, 10.976795405279171, 11.155648052452676, 11.335672512180423, 11.516919793401330, 11.699444192903831, 11.883303616137852, 12.068559939553955, 12.255279421290370, 12.443533168399910, 12.633397670509774, 12.824955411930718, 13.018295576901773, 13.213514866037960, 13.410718446364541, 13.610021062878001, 13.811548346792373, 14.015438365098394, 14.221843468615116, 14.430932512542578, 14.642893546366283, 14.857937101386424, 15.076300248006383, 15.298251657131900, 15.524097989861344, 15.754192071913305, 15.988943508292977, 16.228832700713156, 16.474429717130270, 16.726420259572109, 16.985642328947012, 17.253139580754688, 17.530241825363181, 17.818691945179868, 18.120857274390474, 18.440107345774539, 18.781555607447057, 19.153723464992801, 19.573128956064245, 20.082675660407357}, }, { n: 216, want: []float64{7.5487718957947841e-02, 2.2646713089416223e-01, 3.7745846761172613e-01, 5.2846968803819716e-01, 6.7950876473020116e-01, 8.3058368936317251e-01, 9.8170247825952706e-01, 1.1328731779663146e+00, 1.2841038708939367e+00, 1.4354026810274640e+00, 1.5867777797225648e+00, 1.7382373915984026e+00, 1.8897898005400910e+00, 2.0414433558240375e+00, 2.1932064783796412e+00, 2.3450876672018457e+00, 2.4970955059292010e+00, 2.6492386696032790e+00, 2.8015259316256671e+00, 2.9539661709299665e+00, 3.1065683793869288e+00, 3.2593416694621893e+00, 3.4122952821469283e+00, 3.5654385951833136e+00, 3.7187811316079062e+00, 3.8723325686377130e+00, 4.0261027469252912e+00, 4.1801016802112088e+00, 4.3343395654041350e+00, 4.4888267931211692e+00, 4.6435739587232687e+00, 4.7985918738836766e+00, 4.9538915787298405e+00, 5.1094843546028494e+00, 5.2653817374818566e+00, 5.4215955321250595e+00, 5.5781378269829656e+00, 5.7350210099447425e+00, 5.8922577849835758e+00, 6.0498611897730488e+00, 6.2078446143528714e+00, 6.3662218209298418e+00, 6.5250069649076838e+00, 6.6842146172486627e+00, 6.8438597882796577e+00, 7.0039579530666876e+00, 7.1645250784943162e+00, 7.3255776522003675e+00, 7.4871327135320032e+00, 7.6492078867069049e+00, 7.8118214163831334e+00, 7.9749922058635363e+00, 8.1387398581859554e+00, 8.3030847203790454e+00, 8.4680479311960379e+00, 8.6336514726757141e+00, 8.7999182259219690e+00, 8.9668720315415094e+00, 9.1345377552342626e+00, 9.3029413590944845e+00, 9.4721099792532808e+00, 9.6420720105775217e+00, 9.8128571992374614e+00, 9.9844967440684584e+00, 1.0157023407784097e+01, 1.0330471639251822e+01, 1.0504877708222864e+01, 1.0680279854120787e+01, 1.0856718450743809e+01, 1.1034236189033734e+01, 1.1212878280418622e+01, 1.1392692683659751e+01, 1.1573730358642214e+01, 1.1756045551162156e+01, 1.1939696113507749e+01, 1.2124743866538131e+01, 1.2311255010076101e+01, 1.2499300589800702e+01, 1.2688957030525529e+01, 1.2880306747870632e+01, 1.3073438853003600e+01, 1.3268449968504161e+01, 1.3465445177719724e+01, 1.3664539135531767e+01, 1.3865857375666192e+01, 1.4069537859142688e+01, 1.4275732821001174e+01, 1.4484610989259913e+01, 1.4696360272885402e+01, 1.4911191046953165e+01, 1.5129340207007946e+01, 1.5351076226802732e+01, 1.5576705543358910e+01, 1.5806580725457744e+01, 1.6041111080581306e+01, 1.6280776662107755e+01, 1.6526147125048691e+01, 1.6777907674840002e+01, 1.7036895705202610e+01, 1.7304154114531990e+01, 1.7581011746684457e+01, 1.7869210214084568e+01, 1.8171115120332015e+01, 1.8490093525334313e+01, 1.8831255107137672e+01, 1.9203114954794152e+01, 1.9622178785373663e+01, 2.0131752068311702e+01}, }, } { got := make([]float64, test.n/2+test.n%2) for i := range got { got[i] = Hermite{}.hermiteInitialGuess(i, test.n) } if !floats.EqualApprox(got, test.want, 1e-14) { t.Errorf("n = %v, hermite initial guesses mismatch", test.n) } } } func TestHermiteLocationsAsy0(t *testing.T) { t.Parallel() for _, test := range []struct { n int x []float64 w []float64 }{ // Evaluated from Chebfun. { n: 215, x: []float64{-7.9483151672010196e-15, 1.5132632976672361e-01, 3.0266070079942864e-01, 4.5401115992078167e-01, 6.0538576507805808e-01, 7.5679259093351370e-01, 9.0823973448851325e-01, 1.0597353207530273e+00, 1.2112875084719879e+00, 1.3629044959205205e+00, 1.5145945267802365e+00, 1.6663658961089640e+00, 1.8182269564169717e+00, 1.9701861238629792e+00, 2.1222518845837395e+00, 2.2744328011717010e+00, 2.4267375193157439e+00, 2.5791747746208049e+00, 2.7317533996228827e+00, 2.8844823310168755e+00, 3.0373706171156218e+00, 3.1904274255596032e+00, 3.3436620512978501e+00, 3.4970839248619634e+00, 3.6507026209565665e+00, 3.8045278673909002e+00, 3.9585695543782120e+00, 4.1128377442311503e+00, 4.2673426814837114e+00, 4.4220948034722349e+00, 4.5771047514106780e+00, 4.7323833819978187e+00, 4.8879417795972326e+00, 5.0437912690340267e+00, 5.1999434290559226e+00, 5.3564101065103049e+00, 5.5132034312931157e+00, 5.6703358321303936e+00, 5.8278200532585673e+00, 5.9856691720754620e+00, 6.1438966178406549e+00, 6.3025161915109100e+00, 6.4615420868046280e+00, 6.6209889125982082e+00, 6.7808717167671544e+00, 6.9412060115960434e+00, 7.1020078008938672e+00, 7.2632936089653120e+00, 7.4250805116042331e+00, 7.5873861692931381e+00, 7.7502288628124383e+00, 7.9136275314855800e+00, 8.0776018143113824e+00, 8.2421720942637187e+00, 8.4073595460710955e+00, 8.5731861878255415e+00, 8.7396749368126798e+00, 8.9068496700026394e+00, 9.0747352896969389e+00, 9.2433577948895387e+00, 9.4127443589734394e+00, 9.5829234145081710e+00, 9.7539247458611111e+00, 9.9257795906487338e+00, 1.0098520751035824e+01, 1.0272182716104577e+01, 1.0446801796686490e+01, 1.0622416274262394e+01, 1.0799066565787168e+01, 1.0976795406593546e+01, 1.1155648053883823e+01, 1.1335672513742256e+01, 1.1516919795109878e+01, 1.1699444194777641e+01, 1.1883303618198463e+01, 1.2068559941826503e+01, 1.2255279423804318e+01, 1.2443533171189967e+01, 1.2633397673617059e+01, 1.2824955415404188e+01, 1.3018295580800100e+01, 1.3213514870431910e+01, 1.3410718451340038e+01, 1.3610021068540190e+01, 1.3811548353270942e+01, 1.4015438372554696e+01, 1.4221843477251845e+01, 1.4430932522616979e+01, 1.4642893558208563e+01, 1.4857937115425768e+01, 1.5076300264808333e+01, 1.5298251677453143e+01, 1.5524098014731747e+01, 1.5754192102761674e+01, 1.5988943547145137e+01, 1.6228832750513551e+01, 1.6474429782282726e+01, 1.6726420346886542e+01, 1.6985642449377284e+01, 1.7253139752773148e+01, 1.7530242081974308e+01, 1.7818692349773503e+01, 1.8120857960601569e+01, 1.8440108632764016e+01, 1.8781558404513735e+01, 1.9153731166695263e+01, 1.9573161931385755e+01, 2.0083110126223993e+01}, w: []float64{5.8004562850365771e-04, 5.6692877486338696e-04, 5.2932867305102921e-04, 4.7211368597165944e-04, 4.0223648470876573e-04, 3.2735218319190782e-04, 2.5446548811048362e-04, 1.8892919855999243e-04, 1.3396711152850057e-04, 9.0718165504482523e-05, 5.8661199606591556e-05, 3.6218251240150691e-05, 2.1349054444552587e-05, 1.2013089019084848e-05, 6.4521031002773646e-06, 3.3071925113778075e-06, 1.6175791039359969e-06, 7.5483313427524376e-07, 3.3600239642860852e-07, 1.4264659961771696e-07, 5.7746366478382785e-08, 2.2286582090203475e-08, 8.1983021699506761e-09, 2.8738670556378732e-09, 9.5976924324201262e-10, 3.0529085215378481e-10, 9.2467927287192434e-11, 2.6660996519674056e-11, 7.3154481204350507e-12, 1.9096325566425540e-12, 4.7409073505752031e-13, 1.1189936218333804e-13, 2.5101111888653927e-14, 5.3492761412487281e-15, 1.0825895304391782e-15, 2.0798005039728529e-16, 3.7912539356931888e-17, 6.5547084049896133e-18, 1.0743122119399353e-18, 1.6684093877262400e-19, 2.4538539136228336e-20, 3.4161583900178126e-21, 4.4991409209589655e-22, 5.6023724685401444e-23, 6.5917775903350454e-24, 7.3239791710744789e-25, 7.6792588730186891e-26, 7.5931172671070367e-27, 7.0751732949679160e-28, 6.2078867832748634e-29, 5.1250608797215456e-30, 3.9778286806416675e-31, 2.9000923323091595e-32, 1.9842934651116758e-33, 1.2729744163019100e-34, 7.6493618655638258e-36, 4.3010461850159373e-37, 2.2604572504006732e-38, 1.1091714341886240e-39, 5.0753225126752125e-41, 2.1629552371814077e-42, 8.5739087326714758e-44, 3.1568681170134092e-45, 1.0780709245918455e-46, 3.4094518277810594e-48, 9.9692987408874913e-50, 2.6905726285477170e-51, 6.6902112757430557e-53, 1.5297458011420645e-54, 3.2099851519180199e-56, 6.1681886704578063e-58, 1.0829083084555836e-59, 1.7328083889009238e-61, 2.5206396804555329e-63, 3.3240965181095399e-65, 3.9623955222122382e-67, 4.2558991248868728e-69, 4.1048947183601511e-71, 3.5424776999043975e-73, 2.7245890408644923e-75, 1.8596929038788086e-77, 1.1213274238978696e-79, 5.9430256314002078e-82, 2.7536336403486887e-84, 1.1087876280230634e-86, 3.8548279808836764e-89, 1.1488445098745636e-91, 2.9118805234147757e-94, 6.2218187764965726e-97, 1.1097458975689325e-99, 1.6341809683598844e-102, 1.9621625424695376e-105, 1.8939702898325753e-108, 1.4459753551186440e-111, 8.5692594596311645e-115, 3.8565449589488849e-118, 1.2843410590864927e-121, 3.0685300780965873e-125, 5.0651104293759753e-129, 5.5131423653412833e-133, 3.7300165435945031e-137, 1.4525522232777015e-141, 2.9352196847507026e-146, 2.6587623615117695e-151, 8.6633861029598960e-157, 7.0653364942986233e-163, 7.2051505413036788e-170, 1.5514139491189097e-178}, }, { n: 216, x: []float64{7.5487718959414210e-02, 2.2646713089859094e-01, 3.7745846761911317e-01, 5.2846968804856509e-01, 6.7950876474356448e-01, 8.3058368937955573e-01, 9.8170247827895785e-01, 1.1328731779888348e+00, 1.2841038709195900e+00, 1.4354026810562848e+00, 1.5867777797546210e+00, 1.7382373916337388e+00, 1.8897898005787916e+00, 2.0414433558661624e+00, 2.1932064784252856e+00, 2.3450876672510903e+00, 2.4970955059821409e+00, 2.6492386696600243e+00, 2.8015259316863266e+00, 2.9539661709946619e+00, 3.1065683794558021e+00, 3.2593416695353823e+00, 3.4122952822245907e+00, 3.5654385952656149e+00, 3.7187811316950210e+00, 3.8723325687298416e+00, 4.0261027470226392e+00, 4.1801016803139959e+00, 4.3343395655126109e+00, 4.4888267932355790e+00, 4.6435739588438905e+00, 4.7985918740108131e+00, 4.9538915788638089e+00, 5.1094843547439881e+00, 5.2653817376305465e+00, 5.4215955322816969e+00, 5.5781378271479722e+00, 5.7350210101185848e+00, 5.8922577851667635e+00, 6.0498611899661094e+00, 6.2078446145563948e+00, 6.3662218211444577e+00, 6.5250069651340752e+00, 6.6842146174875827e+00, 6.8438597885318986e+00, 7.0039579533331269e+00, 7.1645250787759087e+00, 7.3255776524981444e+00, 7.4871327138470951e+00, 7.6492078870405447e+00, 7.8118214167366684e+00, 7.9749922062384426e+00, 8.1387398585838486e+00, 8.3030847208017082e+00, 8.4680479316454296e+00, 8.6336514731539875e+00, 8.7999182264315081e+00, 8.9668720320849413e+00, 9.1345377558145096e+00, 9.3029413597147883e+00, 9.4721099799172528e+00, 9.6420720112891818e+00, 9.8128572000013108e+00, 9.9844967448895385e+00, 1.0157023408668081e+01, 1.0330471640205081e+01, 1.0504877709252620e+01, 1.0680279855235202e+01, 1.0856718451952171e+01, 1.1034236190346626e+01, 1.1212878281848150e+01, 1.1392692685219812e+01, 1.1573730360348824e+01, 1.1756045553033841e+01, 1.1939696115566026e+01, 1.2124743868808109e+01, 1.2311255012587219e+01, 1.2499300592587632e+01, 1.2688957033629340e+01, 1.2880306751340244e+01, 1.3073438856897617e+01, 1.3268449972893279e+01, 1.3465445182689793e+01, 1.3664539141187824e+01, 1.3865857382137794e+01, 1.4069537866591046e+01, 1.4275732829628778e+01, 1.4484610999323769e+01, 1.4696360284715409e+01, 1.4911191060978103e+01, 1.5129340223792830e+01, 1.5351076247103551e+01, 1.5576705568204593e+01, 1.5806580756275796e+01, 1.6041111119395726e+01, 1.6280776711860355e+01, 1.6526147190139376e+01, 1.6777907762072694e+01, 1.7036895825521608e+01, 1.7304154286393636e+01, 1.7581012003064874e+01, 1.7869210618319627e+01, 1.8171115805943941e+01, 1.8490094811217439e+01, 1.8831257901839155e+01, 1.9203122650098184e+01, 1.9622211733828486e+01, 2.0131752068397390e+01}, w: []float64{5.7408951238509774e-04, 5.4853385977693967e-04, 5.0077995633045094e-04, 4.3681926493182888e-04, 3.6404534695321319e-04, 2.8986205027358900e-04, 2.2048980967270541e-04, 1.6022189177224014e-04, 1.1121464501100074e-04, 7.3735261435177744e-05, 4.6689968632275442e-05, 2.8233496634858870e-05, 1.6302404527221912e-05, 8.9873835313609794e-06, 4.7299184092204348e-06, 2.3760322139117827e-06, 1.1391060264678187e-06, 5.2109775739704647e-07, 2.2742736124678848e-07, 9.4679280581569520e-08, 3.7589897335857270e-08, 1.4229883676778969e-08, 5.1351173480468011e-09, 1.7661093963625318e-09, 5.7875785413194057e-10, 1.8066600901602130e-10, 5.3707955985666741e-11, 1.5200567246892033e-11, 4.0945877360252466e-12, 1.0494304449814065e-12, 2.5582770078364328e-13, 5.9298335011290506e-14, 1.3064177735039720e-14, 2.7346561920969734e-15, 5.4366757055637182e-16, 1.0261135273171614e-16, 1.8378155831501011e-17, 3.1221798154524404e-18, 5.0287455392773255e-19, 7.6752848097550855e-20, 1.1095334788910946e-20, 1.5183281292392555e-21, 1.9657499371912346e-22, 2.4064442018314010e-23, 2.7838422576260478e-24, 3.0413021389695441e-25, 3.1356913424697775e-26, 3.0490587561112177e-27, 2.7941107980138270e-28, 2.4112340295373517e-29, 1.9579916032501855e-30, 1.4948591683644822e-31, 1.0720958700672810e-32, 7.2163812209007653e-34, 4.5545782039839515e-35, 2.6927171840186886e-36, 1.4896964129251313e-37, 7.7036780004272946e-39, 3.7196117693798106e-40, 1.6748563396289038e-41, 7.0241404150854973e-43, 2.7401344340734534e-44, 9.9291319468776600e-46, 3.3371619908503302e-47, 1.0387276524925886e-48, 2.9893704843803614e-50, 7.9408570659652511e-52, 1.9434716944530867e-53, 4.3740144067322860e-55, 9.0342460240718143e-57, 1.7087495134365174e-58, 2.9528859528856670e-60, 4.6509376421165100e-62, 6.6593952486160953e-64, 8.6442830921042970e-66, 1.0142381095581560e-67, 1.0722439547251424e-69, 1.0179251007077803e-71, 8.6461259693742430e-74, 6.5448969088799971e-76, 4.3965762236216239e-78, 2.6089085327841006e-80, 1.3607099985773063e-82, 6.2039892663366641e-85, 2.4580575133840935e-87, 8.4080554628125066e-90, 2.4652597109139967e-92, 6.1467455174872763e-95, 1.2918545805718045e-97, 2.2661732049781124e-100, 3.2815976681148591e-103, 3.8741015126651295e-106, 3.6760977386321105e-109, 2.7584831111443303e-112, 1.6064052012003602e-115, 7.1024252453209961e-119, 2.3230796238780657e-122, 5.4494213912665180e-126, 8.8284366174946482e-130, 9.4271378060446301e-134, 6.2539251873936211e-138, 2.3865140957941506e-142, 4.7220323342515999e-147, 4.1840743138172546e-152, 1.3319161291512504e-157, 1.0592510752538756e-163, 1.0503755670967946e-170, 2.1869674690632971e-179}, }, } { n := test.n x := make([]float64, n/2+n%2) w := make([]float64, n/2+n%2) for i := range x { x[i], w[i] = Hermite{}.locationsAsy0(i, n) } if !floats.EqualApprox(x, test.x, 1e-13) { t.Errorf("n = %v, x mismatch", n) fmt.Println(x[107]) fmt.Println(test.x[107]) } if !floats.EqualApprox(w, test.w, 1e-13) { t.Errorf("n = %v, w mismatch", n) } } } func TestHermiteAsyAiry(t *testing.T) { t.Parallel() for _, test := range []struct { n int theta []float64 val []float64 dval []float64 }{ { n: 215, theta: []float64{1.5707963267948966e+00, 1.5635071294267224e+00, 1.5562171573546757e+00, 1.5489256352159648e+00, 1.5416317863284521e+00, 1.5343348320272066e+00, 1.5270339909965103e+00, 1.5197284785957685e+00, 1.5124175061777518e+00, 1.5051002803975593e+00, 1.4977760025106577e+00, 1.4904438676582881e+00, 1.4831030641384946e+00, 1.4757527726609410e+00, 1.4683921655836265e+00, 1.4610204061295120e+00, 1.4536366475809854e+00, 1.4462400324499760e+00, 1.4388296916214274e+00, 1.4314047434676882e+00, 1.4239642929312548e+00, 1.4165074305731233e+00, 1.4090332315838545e+00, 1.4015407547542300e+00, 1.3940290414022056e+00, 1.3864971142525955e+00, 1.3789439762656834e+00, 1.3713686094106747e+00, 1.3637699733795743e+00, 1.3561470042367485e+00, 1.3484986129990375e+00, 1.3408236841408716e+00, 1.3331210740183812e+00, 1.3253896092059803e+00, 1.3176280847383373e+00, 1.3098352622500289e+00, 1.3020098680044709e+00, 1.2941505908029671e+00, 1.2862560797638511e+00, 1.2783249419607658e+00, 1.2703557399080556e+00, 1.2623469888800907e+00, 1.2542971540500127e+00, 1.2462046474319508e+00, 1.2380678246090893e+00, 1.2298849812281600e+00, 1.2216543492388388e+00, 1.2133740928542220e+00, 1.2050423042059359e+00, 1.1966569986644591e+00, 1.1882161097919153e+00, 1.1797174838907749e+00, 1.1711588741076131e+00, 1.1625379340461441e+00, 1.1538522108381697e+00, 1.1450991376146524e+00, 1.1362760253118058e+00, 1.1273800537386238e+00, 1.1184082618225748e+00, 1.1093575369389341e+00, 1.1002246032162142e+00, 1.0910060086950395e+00, 1.0816981112001869e+00, 1.0722970627649082e+00, 1.0627987924225111e+00, 1.0531989871517369e+00, 1.0434930707289145e+00, 1.0336761802000907e+00, 1.0237431396389916e+00, 1.0136884308001370e+00, 1.0035061602085740e+00, 9.9319002214595331e-01, 9.8273325689369295e-01, 9.7212860347355579e-01, 9.6136824597870241e-01, 9.5044375240720391e-01, 9.3934600468605900e-01, 9.2806511829511895e-01, 9.1659034955139063e-01, 9.0490998817422319e-01, 8.9301123219309975e-01, 8.8088004154453947e-01, 8.6850096578161351e-01, 8.5585694011780433e-01, 8.4292904244735056e-01, 8.2969620188675874e-01, 8.1613484656631152e-01, 8.0221847457494289e-01, 7.8791712669745728e-01, 7.7319673223616503e-01, 7.5801828879746735e-01, 7.4233682191908168e-01, 7.2610004838413222e-01, 7.0924663405346811e-01, 6.9170388642137270e-01, 6.7338464244284535e-01, 6.5418298314185364e-01, 6.3396819041411068e-01, 6.1257598542667102e-01, 5.8979540387821172e-01, 5.6534835113739590e-01, 5.3885619819698471e-01, 5.0978185232293227e-01, 4.7732127920035572e-01, 4.4017830784988765e-01, 3.9602307074600884e-01, 3.3985069280702440e-01, 2.5624520569356829e-01}, val: []float64{-2.7524590607067879e-13, -1.2484792737707130e-10, 2.5043777255407545e-10, -3.7621487726711831e-10, 5.0266571286479591e-10, -6.3022107051014496e-10, 7.5847898514904004e-10, -8.8850597267422281e-10, 1.0201287099545048e-09, -1.1532700149758681e-09, 1.2885402426941860e-09, -1.4262514564750722e-09, 1.5667774694950304e-09, -1.7098460348004283e-09, 1.8563663242006209e-09, -2.0060430373954962e-09, 2.1597272205910619e-09, -2.3174687646872261e-09, 2.4795270439737100e-09, -2.6462815453642877e-09, 2.8188431716836157e-09, -2.9962948915230151e-09, 3.1805879826447352e-09, -3.3709772507788239e-09, 3.5681573894354513e-09, -3.7732681484183285e-09, 3.9863813736176932e-09, -4.2080297462347532e-09, 4.4391671460302399e-09, -4.6802436355831232e-09, 4.9322546933533433e-09, -5.1957881449299223e-09, 5.4715433664057677e-09, -5.7608265327475837e-09, 6.0644153161437157e-09, -6.3835515563504339e-09, 6.7192819880764795e-09, -7.0729371214636086e-09, 7.4458702579674617e-09, -7.8396410076078555e-09, 8.2556088536449877e-09, -8.6960989460562939e-09, 9.1626310723815202e-09, -9.6575986146054327e-09, 1.0182896152806950e-08, -1.0741758184989815e-08, 1.1337214303287172e-08, -1.1971481080324528e-08, 1.2648762056240369e-08, -1.3372488830525768e-08, 1.4147041859097387e-08, -1.4977276046958432e-08, 1.5868475891599271e-08, -1.6825823997480545e-08, 1.7856900524878266e-08, -1.8967833880184117e-08, 2.0167708166421882e-08, -2.1465280681285451e-08, 2.2870631970634630e-08, -2.4395881051717265e-08, 2.6054060647767539e-08, -2.7859818527100110e-08, 2.9830454146699167e-08, -3.1984835487787522e-08, 3.4345470368342559e-08, -3.6937900081988413e-08, 3.9790883510012329e-08, -4.2938418365980210e-08, 4.6419377177480922e-08, -5.0279213559974237e-08, 5.4570799296449321e-08, -5.9356303125081130e-08, 6.4708755363671345e-08, -7.0714511032393380e-08, 7.7475892426711618e-08, -8.5115456468135130e-08, 9.3779863576446978e-08, -1.0364644483987255e-07, 1.1493006182865740e-07, -1.2789317815470753e-07, 1.4285900893044798e-07, -1.6022759919461249e-07, 1.8049814080062288e-07, -2.0429953256541455e-07, 2.3243044535889061e-07, -2.6591504027157263e-07, 3.0608147425737922e-07, -3.5467098673335754e-07, 4.1399606056878556e-07, -4.8716979156405424e-07, 5.7844824292016844e-07, -6.9374768843585542e-07, 8.4144962449118331e-07, -1.0336795693201387e-06, 1.2884020459910342e-06, -1.6329629222918408e-06, 2.1103031286712709e-06, -2.7903321871954755e-06, 3.7918023218017778e-06, -5.3269144947324421e-06, 7.7989206456257246e-06, -1.2034979469568085e-05, 1.9905658561076196e-05, -3.6224899321604820e-05, 7.5828952282754516e-05, -1.9870421394114517e-04, 7.9136577883937422e-04, -9.1266148556594703e-03}, dval: []float64{-2.9359856130945122e+01, 2.9359466144908318e+01, -2.9358296010652477e+01, 2.9356345199427643e+01, -2.9353612829040124e+01, 2.9350097662433203e+01, -2.9345798105693621e+01, 2.9340712205476308e+01, -2.9334837645838910e+01, 2.9328171744474840e+01, -2.9320711448331572e+01, 2.9312453328598885e+01, -2.9303393575049100e+01, 2.9293527989709109e+01, -2.9282851979841201e+01, 2.9271360550207458e+01, -2.9259048294588819e+01, 2.9245909386527540e+01, -2.9231937569258221e+01, 2.9217126144788914e+01, -2.9201467962090302e+01, 2.9184955404346876e+01, -2.9167580375219231e+01, 2.9149334284062498e+01, -2.9130208030040425e+01, 2.9110191985068752e+01, -2.9089275975516287e+01, 2.9067449262584436e+01, -2.9044700521279459e+01, 2.9021017817883425e+01, -2.8996388585821325e+01, 2.8970799599811933e+01, -2.8944236948180023e+01, 2.8916686003195348e+01, -2.8888131389291605e+01, 2.8858556949003951e+01, -2.8827945706448649e+01, 2.8796279828150279e+01, -2.8763540581003511e+01, 2.8729708287134507e+01, -2.8694762275403512e+01, 2.8658680829263385e+01, -2.8621441130659093e+01, 2.8583019199620328e+01, -2.8543389829161509e+01, 2.8502526515061927e+01, -2.8460401380051497e+01, 2.8416985091874277e+01, -2.8372246774642264e+01, 2.8326153912823031e+01, -2.8278672247129006e+01, 2.8229765661486788e+01, -2.8179396060166667e+01, 2.8127523234037287e+01, -2.8074104714780372e+01, 2.8019095615750665e+01, -2.7962448457994284e+01, 2.7904112979739956e+01, -2.7844035927448619e+01, 2.7782160826241125e+01, -2.7718427727214667e+01, 2.7652772928798932e+01, -2.7585128668881747e+01, 2.7515422783940370e+01, -2.7443578330833645e+01, 2.7369513166223737e+01, -2.7293139477783004e+01, 2.7214363260373997e+01, -2.7133083729234610e+01, 2.7049192660814331e+01, -2.6962573650237655e+01, 2.6873101272350414e+01, -2.6780640130847800e+01, 2.6685043776981303e+01, -2.6586153475654008e+01, 2.6483796792158788e+01, -2.6377785967154090e+01, 2.6267916040395331e+01, -2.6153962674834343e+01, 2.6035679621411951e+01, -2.5912795750458177e+01, 2.5785011557068390e+01, -2.5651995023754676e+01, 2.5513376692151432e+01, -2.5368743753874771e+01, 2.5217632914945654e+01, -2.5059521712941240e+01, 2.4893817863127197e+01, -2.4719846067215368e+01, 2.4536831517922174e+01, -2.4343879046260469e+01, 2.4139946442705973e+01, -2.3923809867871942e+01, 2.3694018337866666e+01, -2.3448832829666316e+01, 2.3186143264519330e+01, -2.2903352884396824e+01, 2.2597213200674400e+01, -2.2263581543467414e+01, 2.1897052703993687e+01, -2.1490376258364485e+01, 2.1033488463000687e+01, -2.0511802124454178e+01, 1.9902938182242686e+01, -1.9169784832381577e+01, 1.8243381598901596e+01, -1.6969663168974311e+01, 1.4853826851969115e+01}, }, { n: 215, theta: []float64{1.5707963267948968e+00, 1.5635071294265777e+00, 1.5562171573543850e+00, 1.5489256352155283e+00, 1.5416317863278686e+00, 1.5343348320264747e+00, 1.5270339909956292e+00, 1.5197284785947358e+00, 1.5124175061765655e+00, 1.5051002803962170e+00, 1.4977760025091569e+00, 1.4904438676566254e+00, 1.4831030641366665e+00, 1.4757527726589439e+00, 1.4683921655814560e+00, 1.4610204061271637e+00, 1.4536366475784539e+00, 1.4462400324472560e+00, 1.4388296916185130e+00, 1.4314047434645731e+00, 1.4239642929279313e+00, 1.4165074305695844e+00, 1.4090332315800913e+00, 1.4015407547502341e+00, 1.3940290413979675e+00, 1.3864971142481046e+00, 1.3789439762609286e+00, 1.3713686094056443e+00, 1.3637699733742550e+00, 1.3561470042311266e+00, 1.3484986129930978e+00, 1.3408236841345980e+00, 1.3331210740117563e+00, 1.3253896091989852e+00, 1.3176280847309516e+00, 1.3098352622422307e+00, 1.3020098679962364e+00, 1.2941505907942705e+00, 1.2862560797546647e+00, 1.2783249419510594e+00, 1.2703557398977969e+00, 1.2623469888692436e+00, 1.2542971540385390e+00, 1.2462046474198085e+00, 1.2380678245962331e+00, 1.2298849812145400e+00, 1.2216543492243996e+00, 1.2133740928389052e+00, 1.2050423041896758e+00, 1.1966569986471847e+00, 1.1882161097735480e+00, 1.1797174838712285e+00, 1.1711588740867924e+00, 1.1625379340239450e+00, 1.1538522108144755e+00, 1.1450991375893356e+00, 1.1362760252847235e+00, 1.1273800537096179e+00, 1.1184082617914692e+00, 1.1093575369055320e+00, 1.1002246031802951e+00, 1.0910060086563567e+00, 1.0816981111584625e+00, 1.0722970627198296e+00, 1.0627987923737243e+00, 1.0531989870988405e+00, 1.0434930706714527e+00, 1.0336761801375436e+00, 1.0237431395707643e+00, 1.0136884307255469e+00, 1.0035061601268345e+00, 9.9319002205615470e-01, 9.8273325679477930e-01, 9.7212860336429585e-01, 9.6136824585765468e-01, 9.5044375227267230e-01, 9.3934600453603823e-01, 9.2806511812722514e-01, 9.1659034936277473e-01, 9.0490998796145916e-01, 8.9301123195204113e-01, 8.8088004127013353e-01, 8.6850096546765831e-01, 8.5585693975662547e-01, 8.4292904202937069e-01, 8.2969620139991496e-01, 8.1613484599525510e-01, 8.0221847389992995e-01, 7.8791712589278218e-01, 7.7319673126791522e-01, 7.5801828762024448e-01, 7.4233682047111893e-01, 7.2610004657985505e-01, 7.0924663177187774e-01, 6.9170388348738876e-01, 6.7338463859636577e-01, 6.5418297798453895e-01, 6.3396818331389482e-01, 6.1257597533770680e-01, 5.8979538898074346e-01, 5.6534832806423485e-01, 5.3885616021897675e-01, 5.0978178458826806e-01, 4.7732114425935024e-01, 4.4017799165717791e-01, 3.9602210904603868e-01, 3.3984592789666196e-01, 2.5616263514373872e-01}, val: []float64{-2.7524577037687927e-13, -1.3157296144588393e-13, -1.4217705189589319e-13, -9.3051784272423659e-14, 6.2263913433904649e-14, -7.2338165854311426e-14, 1.6489823942055246e-13, 8.2086154015730068e-14, 1.7030857773598118e-13, 1.9200825273544764e-13, 3.4144423192398587e-13, -1.3350292964848512e-13, 7.7406393378692183e-16, 3.0802286839980475e-15, 1.0626665274130983e-13, 9.7508116816654928e-14, -1.2286283979350783e-13, 1.6602061523803380e-13, 1.2145800400612989e-14, -2.0125760394077007e-13, 1.1752853222876857e-13, 1.5246361311903834e-13, -1.7100196342840500e-13, -9.0852635256292980e-14, -7.8101776477326909e-14, -8.6215405399587178e-14, -1.8424041061507494e-13, -1.7748959370373156e-13, 1.6659488983250428e-14, -2.3029664495695825e-14, 4.9882044749360307e-14, -1.6935708059066857e-13, -1.6889419531778083e-14, -1.5488691966202885e-13, 4.7496471682336465e-15, -6.0236075531674274e-14, -4.7790439973748918e-14, 1.0528243973915236e-14, -1.4481370116381506e-13, 4.8870674172048881e-14, 5.9145722182844837e-14, -3.6252017525118028e-14, -1.4799821290649442e-13, 7.8483748114372226e-14, -3.1698431394015554e-14, -2.1250000650523357e-13, -1.2207160366356720e-13, -4.4799710774576449e-14, -6.6076225108040054e-14, 4.9432907671096125e-14, 1.1714372287574581e-13, 7.1071624668919607e-14, -1.4699620399669987e-13, 4.9028118279404591e-14, 5.6995970859340297e-15, 1.8655926516135062e-14, 3.2409175615798361e-14, 7.1510069979380908e-14, -7.2558225742592175e-14, 4.1294505314113302e-14, -1.8304081875904709e-14, 1.3492357431194347e-13, -2.0526864648283952e-13, 1.1949578558177085e-14, 5.3441698191945163e-14, 4.9207462229933007e-14, -1.9962117626180037e-13, 8.2375100050737861e-15, 5.8811770905000782e-14, -3.8856969371752553e-15, 4.8345877891596704e-14, -1.2020353849039574e-13, 1.0795889278969854e-14, 2.7165003590955340e-14, 7.9664181703224841e-15, -3.1357633506603503e-14, 3.0114465704049404e-14, 5.4841545026050259e-14, 8.3356466046602926e-14, 3.4875109219720919e-14, 5.3887688890067731e-14, -8.5090430827758076e-15, 1.4753806570541977e-14, 4.1314792687095403e-15, 2.8114340045724569e-14, -8.9380771455156681e-15, -3.2451925819727029e-14, 5.0739464388639648e-14, 5.2751575373088884e-14, 3.8348847777085630e-14, -3.1825724566756715e-14, 6.6426259272244758e-14, -6.4295491511138863e-14, 8.9401622475124014e-15, 2.5866873030708164e-14, 9.6302605421508054e-14, 4.6623114840341440e-14, -1.7497072577375209e-14, 3.3453526916664849e-14, -5.5592329550244261e-14, 1.4115683421722400e-13, -3.9306913138151204e-13, 1.2007938611150981e-12, -4.7530501604406474e-12, 2.5399685303214922e-11, -2.2827587443604869e-10, 5.3187001008179367e-09, -1.4222383864770318e-06}, dval: []float64{-2.9359856130945126e+01, 2.9359466144908307e+01, -2.9358296010652474e+01, 2.9356345199427643e+01, -2.9353612829040117e+01, 2.9350097662433203e+01, -2.9345798105693628e+01, 2.9340712205476311e+01, -2.9334837645838906e+01, 2.9328171744474847e+01, -2.9320711448331569e+01, 2.9312453328598881e+01, -2.9303393575049114e+01, 2.9293527989709105e+01, -2.9282851979841208e+01, 2.9271360550207465e+01, -2.9259048294588812e+01, 2.9245909386527540e+01, -2.9231937569258211e+01, 2.9217126144788910e+01, -2.9201467962090309e+01, 2.9184955404346905e+01, -2.9167580375219234e+01, 2.9149334284062515e+01, -2.9130208030040418e+01, 2.9110191985068738e+01, -2.9089275975516284e+01, 2.9067449262584432e+01, -2.9044700521279456e+01, 2.9021017817883422e+01, -2.8996388585821315e+01, 2.8970799599811926e+01, -2.8944236948180027e+01, 2.8916686003195355e+01, -2.8888131389291594e+01, 2.8858556949003940e+01, -2.8827945706448645e+01, 2.8796279828150276e+01, -2.8763540581003515e+01, 2.8729708287134510e+01, -2.8694762275403530e+01, 2.8658680829263389e+01, -2.8621441130659079e+01, 2.8583019199620328e+01, -2.8543389829161509e+01, 2.8502526515061930e+01, -2.8460401380051490e+01, 2.8416985091874288e+01, -2.8372246774642264e+01, 2.8326153912823038e+01, -2.8278672247129016e+01, 2.8229765661486780e+01, -2.8179396060166667e+01, 2.8127523234037294e+01, -2.8074104714780368e+01, 2.8019095615750661e+01, -2.7962448457994284e+01, 2.7904112979739949e+01, -2.7844035927448619e+01, 2.7782160826241114e+01, -2.7718427727214678e+01, 2.7652772928798946e+01, -2.7585128668881751e+01, 2.7515422783940377e+01, -2.7443578330833653e+01, 2.7369513166223744e+01, -2.7293139477783015e+01, 2.7214363260374000e+01, -2.7133083729234624e+01, 2.7049192660814349e+01, -2.6962573650237655e+01, 2.6873101272350418e+01, -2.6780640130847814e+01, 2.6685043776981328e+01, -2.6586153475654026e+01, 2.6483796792158806e+01, -2.6377785967154097e+01, 2.6267916040395356e+01, -2.6153962674834389e+01, 2.6035679621411997e+01, -2.5912795750458240e+01, 2.5785011557068451e+01, -2.5651995023754750e+01, 2.5513376692151542e+01, -2.5368743753874902e+01, 2.5217632914945817e+01, -2.5059521712941454e+01, 2.4893817863127474e+01, -2.4719846067215741e+01, 2.4536831517922678e+01, -2.4343879046261161e+01, 2.4139946442706947e+01, -2.3923809867873366e+01, 2.3694018337868730e+01, -2.3448832829669414e+01, 2.3186143264524166e+01, -2.2903352884404576e+01, 2.2597213200687420e+01, -2.2263581543490410e+01, 2.1897052704036881e+01, -2.1490376258452002e+01, 2.1033488463196051e+01, -2.0511802124949831e+01, 1.9902938183741984e+01, -1.9169784838249630e+01, 1.8243381633602635e+01, -1.6969663610835688e+01, 1.4853865657323199e+01}, }, { n: 215, theta: []float64{1.5707963267948970e+00, 1.5635071294265774e+00, 1.5562171573543853e+00, 1.5489256352155283e+00, 1.5416317863278686e+00, 1.5343348320264747e+00, 1.5270339909956290e+00, 1.5197284785947358e+00, 1.5124175061765652e+00, 1.5051002803962172e+00, 1.4977760025091564e+00, 1.4904438676566252e+00, 1.4831030641366665e+00, 1.4757527726589439e+00, 1.4683921655814558e+00, 1.4610204061271639e+00, 1.4536366475784541e+00, 1.4462400324472562e+00, 1.4388296916185130e+00, 1.4314047434645729e+00, 1.4239642929279310e+00, 1.4165074305695846e+00, 1.4090332315800915e+00, 1.4015407547502341e+00, 1.3940290413979675e+00, 1.3864971142481046e+00, 1.3789439762609288e+00, 1.3713686094056441e+00, 1.3637699733742550e+00, 1.3561470042311266e+00, 1.3484986129930978e+00, 1.3408236841345977e+00, 1.3331210740117563e+00, 1.3253896091989850e+00, 1.3176280847309516e+00, 1.3098352622422307e+00, 1.3020098679962364e+00, 1.2941505907942705e+00, 1.2862560797546649e+00, 1.2783249419510594e+00, 1.2703557398977969e+00, 1.2623469888692436e+00, 1.2542971540385393e+00, 1.2462046474198085e+00, 1.2380678245962331e+00, 1.2298849812145398e+00, 1.2216543492243999e+00, 1.2133740928389052e+00, 1.2050423041896758e+00, 1.1966569986471847e+00, 1.1882161097735477e+00, 1.1797174838712285e+00, 1.1711588740867926e+00, 1.1625379340239450e+00, 1.1538522108144755e+00, 1.1450991375893356e+00, 1.1362760252847235e+00, 1.1273800537096179e+00, 1.1184082617914692e+00, 1.1093575369055320e+00, 1.1002246031802951e+00, 1.0910060086563569e+00, 1.0816981111584627e+00, 1.0722970627198296e+00, 1.0627987923737243e+00, 1.0531989870988405e+00, 1.0434930706714529e+00, 1.0336761801375436e+00, 1.0237431395707643e+00, 1.0136884307255469e+00, 1.0035061601268345e+00, 9.9319002205615448e-01, 9.8273325679477930e-01, 9.7212860336429585e-01, 9.6136824585765468e-01, 9.5044375227267230e-01, 9.3934600453603823e-01, 9.2806511812722525e-01, 9.1659034936277461e-01, 9.0490998796145927e-01, 8.9301123195204102e-01, 8.8088004127013353e-01, 8.6850096546765831e-01, 8.5585693975662547e-01, 8.4292904202937069e-01, 8.2969620139991496e-01, 8.1613484599525521e-01, 8.0221847389993006e-01, 7.8791712589278207e-01, 7.7319673126791533e-01, 7.5801828762024459e-01, 7.4233682047111904e-01, 7.2610004657985516e-01, 7.0924663177187774e-01, 6.9170388348738865e-01, 6.7338463859636599e-01, 6.5418297798453884e-01, 6.3396818331389482e-01, 6.1257597533770669e-01, 5.8979538898074335e-01, 5.6534832806423441e-01, 5.3885616021897553e-01, 5.0978178458826395e-01, 4.7732114425933253e-01, 4.4017799165707200e-01, 3.9602210904493385e-01, 3.3984592786463697e-01, 2.5616262227240338e-01}, val: []float64{-4.8194502666337268e-14, -1.8219292956257052e-14, 8.5393034645390052e-14, -9.3051784272423659e-14, 6.2263913433904649e-14, -7.2338165854311426e-14, -6.2580913476718581e-14, 8.2086154015730068e-14, -5.7165830534287467e-14, -3.5936383892293965e-14, -1.1380084519138131e-13, 9.4176333524136458e-14, 7.7406393378692183e-16, 3.0802286839980475e-15, -2.3573275472589349e-13, -1.3018327378045775e-13, 1.0520206501483371e-13, -6.2213644291038904e-14, 1.2145800400612989e-14, 2.7271297683652584e-14, -2.2535922871268711e-13, -7.6298928186738198e-14, 1.7255690675064885e-13, -9.0852635256292980e-14, -7.8101776477326909e-14, -8.6215405399587178e-14, 4.5189259409156241e-14, 1.6773935900994068e-13, 1.6659488983250428e-14, -2.3029664495695825e-14, 4.9882044749360307e-14, 1.1850055135335312e-13, -1.6889419531778083e-14, 7.5802404690310745e-14, 4.7496471682336465e-15, -6.0236075531674274e-14, -4.7790439973748918e-14, 1.0528243973915236e-14, 2.0302122716337677e-13, 4.8870674172048881e-14, 5.9145722182844837e-14, -3.6252017525118028e-14, 2.6839385139099395e-14, 7.8483748114372226e-14, -3.1698431394015554e-14, -3.7141479062747567e-14, 1.1275835568784933e-13, -4.4799710774576449e-14, -6.6076225108040054e-14, 4.9432907671096125e-14, -1.1915508175098585e-13, 7.1071624668919607e-14, 1.4874359999295257e-13, 4.9028118279404591e-14, 5.6995970859340297e-15, 1.8655926516135062e-14, 3.2409175615798361e-14, 7.1510069979380908e-14, -7.2558225742592175e-14, 4.1294505314113302e-14, -1.8304081875904709e-14, -4.6448090671875563e-14, 9.6949756857760571e-14, 1.1949578558177085e-14, 5.3441698191945163e-14, 4.9207462229933007e-14, -1.6005168277506475e-14, 8.2375100050737861e-15, 5.8811770905000782e-14, -3.8856969371752553e-15, 4.8345877891596704e-14, 9.6875037765842389e-14, 1.0795889278969854e-14, 2.7165003590955340e-14, 7.9664181703224841e-15, -3.1357633506603503e-14, 3.0114465704049404e-14, 5.4841606599486569e-14, 1.9665914005907120e-14, -2.8849555274550242e-14, -4.2752529356173103e-14, -8.5090430827758076e-15, 1.4753806570541977e-14, 4.1314792687095403e-15, 2.8114340045724569e-14, -8.9380771455156681e-15, 3.6308713608736668e-16, -4.9851972317585696e-14, -9.9115770904832069e-14, -1.2903366624947848e-14, 5.3938844852967152e-14, -3.7521135648997941e-14, 4.0086325460559029e-14, 8.9401622475124014e-15, -9.8967441436620103e-14, -6.5207531930586132e-14, 4.6622484011593159e-14, -1.7497072577375209e-14, 3.3453526916664849e-14, 4.8715471045751314e-14, 3.3943255654417215e-14, 5.7122398702729805e-15, -9.4574045519538209e-16, 7.2999684957756045e-15, 2.7503783126358897e-14, -7.8728766754343666e-15, 3.5695346037194369e-14, -6.2144904069338325e-14}, dval: []float64{-2.9359856130945122e+01, 2.9359466144908321e+01, -2.9358296010652467e+01, 2.9356345199427643e+01, -2.9353612829040117e+01, 2.9350097662433203e+01, -2.9345798105693628e+01, 2.9340712205476311e+01, -2.9334837645838913e+01, 2.9328171744474844e+01, -2.9320711448331572e+01, 2.9312453328598878e+01, -2.9303393575049114e+01, 2.9293527989709105e+01, -2.9282851979841219e+01, 2.9271360550207469e+01, -2.9259048294588819e+01, 2.9245909386527547e+01, -2.9231937569258211e+01, 2.9217126144788914e+01, -2.9201467962090305e+01, 2.9184955404346880e+01, -2.9167580375219234e+01, 2.9149334284062515e+01, -2.9130208030040418e+01, 2.9110191985068738e+01, -2.9089275975516287e+01, 2.9067449262584439e+01, -2.9044700521279456e+01, 2.9021017817883422e+01, -2.8996388585821315e+01, 2.8970799599811929e+01, -2.8944236948180027e+01, 2.8916686003195352e+01, -2.8888131389291594e+01, 2.8858556949003940e+01, -2.8827945706448645e+01, 2.8796279828150276e+01, -2.8763540581003500e+01, 2.8729708287134510e+01, -2.8694762275403530e+01, 2.8658680829263389e+01, -2.8621441130659086e+01, 2.8583019199620328e+01, -2.8543389829161509e+01, 2.8502526515061934e+01, -2.8460401380051490e+01, 2.8416985091874288e+01, -2.8372246774642264e+01, 2.8326153912823038e+01, -2.8278672247129023e+01, 2.8229765661486780e+01, -2.8179396060166667e+01, 2.8127523234037294e+01, -2.8074104714780368e+01, 2.8019095615750661e+01, -2.7962448457994284e+01, 2.7904112979739949e+01, -2.7844035927448619e+01, 2.7782160826241114e+01, -2.7718427727214678e+01, 2.7652772928798939e+01, -2.7585128668881751e+01, 2.7515422783940377e+01, -2.7443578330833653e+01, 2.7369513166223744e+01, -2.7293139477783015e+01, 2.7214363260374000e+01, -2.7133083729234624e+01, 2.7049192660814349e+01, -2.6962573650237655e+01, 2.6873101272350418e+01, -2.6780640130847814e+01, 2.6685043776981328e+01, -2.6586153475654026e+01, 2.6483796792158806e+01, -2.6377785967154097e+01, 2.6267916040395356e+01, -2.6153962674834375e+01, 2.6035679621411987e+01, -2.5912795750458244e+01, 2.5785011557068451e+01, -2.5651995023754750e+01, 2.5513376692151542e+01, -2.5368743753874902e+01, 2.5217632914945817e+01, -2.5059521712941446e+01, 2.4893817863127481e+01, -2.4719846067215748e+01, 2.4536831517922678e+01, -2.4343879046261172e+01, 2.4139946442706954e+01, -2.3923809867873342e+01, 2.3694018337868730e+01, -2.3448832829669424e+01, 2.3186143264524159e+01, -2.2903352884404576e+01, 2.2597213200687420e+01, -2.2263581543490410e+01, 2.1897052704036888e+01, -2.1490376258451999e+01, 2.1033488463196083e+01, -2.0511802124949803e+01, 1.9902938183742044e+01, -1.9169784838249644e+01, 1.8243381633602628e+01, -1.6969663610835667e+01, 1.4853865657324123e+01}, }, { n: 216, theta: []float64{1.5671686105755729e+00, 1.5599127961686350e+00, 1.5526558355349958e+00, 1.5453969634500344e+00, 1.5381354130763418e+00, 1.5308704153134880e+00, 1.5236011981426352e+00, 1.5163269859644990e+00, 1.5090469989291080e+00, 1.5017604522557937e+00, 1.4944665555417909e+00, 1.4871645120577743e+00, 1.4798535180286077e+00, 1.4725327618975033e+00, 1.4652014235717277e+00, 1.4578586736478822e+00, 1.4505036726147191e+00, 1.4431355700313173e+00, 1.4357535036783504e+00, 1.4283565986800277e+00, 1.4209439665941588e+00, 1.4135147044676193e+00, 1.4060678938543345e+00, 1.3986025997926903e+00, 1.3911178697390723e+00, 1.3836127324540022e+00, 1.3760861968370792e+00, 1.3685372507066480e+00, 1.3609648595198076e+00, 1.3533679650280226e+00, 1.3457454838632317e+00, 1.3380963060489126e+00, 1.3304192934301153e+00, 1.3227132780159603e+00, 1.3149770602275335e+00, 1.3072094070434859e+00, 1.2994090500349611e+00, 1.2915746832807011e+00, 1.2837049611523335e+00, 1.2757984959588993e+00, 1.2678538554386305e+00, 1.2598695600848058e+00, 1.2518440802912205e+00, 1.2437758333013242e+00, 1.2356631799434625e+00, 1.2275044211328083e+00, 1.2192977941185159e+00, 1.2110414684522999e+00, 1.2027335416520410e+00, 1.1943720345310531e+00, 1.1859548861603062e+00, 1.1774799484271210e+00, 1.1689449801495315e+00, 1.1603476407006212e+00, 1.1516854830915373e+00, 1.1429559464555037e+00, 1.1341563478678038e+00, 1.1252838734282915e+00, 1.1163355685232694e+00, 1.1073083271723616e+00, 1.0981988803530085e+00, 1.0890037831801158e+00, 1.0797194008007944e+00, 1.0703418928435628e+00, 1.0608671962372638e+00, 1.0512910061865695e+00, 1.0416087550574320e+00, 1.0318155888861182e+00, 1.0219063411782010e+00, 1.0118755036074250e+00, 1.0017171931566209e+00, 9.9142511516121901e-01, 9.8099252161709072e-01, 9.7041216399420693e-01, 9.5967623965057169e-01, 9.4877633076008561e-01, 9.3770333444439402e-01, 9.2644738252057113e-01, 9.1499774892808761e-01, 9.0334274245922008e-01, 8.9146958185913860e-01, 8.7936424964779292e-01, 8.6701132009412707e-01, 8.5439375557323693e-01, 8.4149266395991695e-01, 8.2828700761781482e-01, 8.1475325173188318e-01, 8.0086493591225205e-01, 7.8659214774134534e-01, 7.7190086960046345e-01, 7.5675215971653753e-01, 7.4110111338801099e-01, 7.2489552835323978e-01, 7.0807416530075917e-01, 6.9056444397251160e-01, 6.7227933577676646e-01, 6.5311308498739518e-01, 6.3293517484306561e-01, 6.1158157942775537e-01, 5.8884165912926645e-01, 5.6443774724725360e-01, 5.3799179737419422e-01, 5.0896754324534177e-01, 4.7656218794974137e-01, 4.3948155571863207e-01, 3.9539936631707273e-01, 3.3931845258954985e-01, 2.5576413756997579e-01}, val: []float64{6.1063360924047490e-11, -1.8435203658490556e-10, 3.0743162265786900e-10, -4.3161999307057153e-10, 5.5600184481941261e-10, -6.8154103751235407e-10, 8.0806640731641332e-10, -9.3648670703302450e-10, 1.0665511846836497e-09, -1.1984227187029326e-09, 1.3320294714997634e-09, -1.4683350272554789e-09, 1.6073141540400390e-09, -1.7488108299475996e-09, 1.8942373170611600e-09, -2.0425637634202854e-09, 2.1952560444756934e-09, -2.3517907718469464e-09, 2.5131243047743498e-09, -2.6788312866718815e-09, 2.8501736508238295e-09, -3.0272882762354559e-09, 3.2101466593235099e-09, -3.3995591281295402e-09, 3.5962230906180571e-09, -3.8005765479605162e-09, 4.0130477356611703e-09, -4.2339156669326267e-09, 4.4646349512119503e-09, -4.7049927091960580e-09, 4.9561002253847192e-09, -5.2191334055490069e-09, 5.4945583626542044e-09, -5.7832433193687254e-09, 6.0863314853460021e-09, -6.4051174909280434e-09, 6.7403553891566650e-09, -7.0933989938263408e-09, 7.4659234299589640e-09, -7.8591408458401506e-09, 8.2751055799843569e-09, -8.7148794606644850e-09, 9.1813301061361439e-09, -9.6760514978089342e-09, 1.0201632305616356e-08, -1.0760129925294149e-08, 1.1355163586751651e-08, -1.1989527720947381e-08, 1.2666360398983932e-08, -1.3390280463762196e-08, 1.4164961106968852e-08, -1.4995012747245716e-08, 1.5885976564229918e-08, -1.6843921766929025e-08, 1.7874947115661739e-08, -1.8986267082409428e-08, 2.0186191955347422e-08, -2.1484132370733845e-08, 2.2890126360750540e-08, -2.4415809556224372e-08, 2.6074391376958674e-08, -2.7880720950296676e-08, 2.9852038341333996e-08, -3.2007470796983141e-08, 3.4369209413828328e-08, -3.6962720963996261e-08, 3.9816961736227733e-08, -4.2965941232291533e-08, 4.6448638367911141e-08, -5.0310249303133202e-08, 5.4604204622873211e-08, -5.9392177920227513e-08, 6.4747522871256546e-08, -7.0756457006013807e-08, 7.7521575966439530e-08, -8.5165469547851754e-08, 9.3834858505459719e-08, -1.0370708662191418e-07, 1.1499734508496046e-07, -1.2796816261852297e-07, 1.4294288769073078e-07, -1.6032201969864769e-07, 1.8060502833216690e-07, -2.0442120587020166e-07, 2.3256958638562142e-07, -2.6607532013847684e-07, 3.0626738095928866e-07, -3.5488829260119791e-07, 4.1425182777935264e-07, -4.8747349724306658e-07, 5.7881217418665015e-07, -6.9418829303134906e-07, 8.4198941248161877e-07, -1.0343491900465793e-06, 1.2892453275257475e-06, -1.6340426463170451e-06, 2.1117130712431397e-06, -2.7922162634453614e-06, 3.7943899196860205e-06, -5.3305886421188924e-06, 7.8043580879824044e-06, -1.2043461755474721e-05, 1.9919842840142057e-05, -3.6251001189673213e-05, 7.5884216611786810e-05, -1.9885074842226311e-04, 7.9195669340038259e-04, -1.8028552886227383e-09}, dval: []float64{-2.9427800603424885e+01, 2.9427025985916121e+01, -2.9425476404186753e+01, 2.9423151164251298e+01, -2.9420049223750460e+01, 2.9416169190288226e+01, -2.9411509319206207e+01, 2.9406067510787029e+01, -2.9399841306877359e+01, 2.9392827886918830e+01, -2.9385024063373031e+01, 2.9376426276524445e+01, -2.9367030588643040e+01, 2.9356832677485638e+01, -2.9345827829112856e+01, 2.9334010929995458e+01, -2.9321376458381245e+01, 2.9307918474890496e+01, -2.9293630612304742e+01, 2.9278506064510260e+01, -2.9262537574553473e+01, 2.9245717421762187e+01, -2.9228037407881232e+01, 2.9209488842167364e+01, -2.9190062525382210e+01, 2.9169748732617208e+01, -2.9148537194877900e+01, 2.9126417079348521e+01, -2.9103376968250728e+01, 2.9079404836201942e+01, -2.9054488025970496e+01, 2.9028613222515041e+01, -2.9001766425185139e+01, 2.8973932917948382e+01, -2.8945097237496739e+01, 2.8915243139070405e+01, -2.8884353559822184e+01, 2.8852410579527451e+01, -2.8819395378426641e+01, 2.8785288191964121e+01, -2.8750068262165129e+01, 2.8713713785364632e+01, -2.8676201855972838e+01, 2.8637508405928582e+01, -2.8597608139454216e+01, 2.8556474462684317e+01, -2.8514079407692357e+01, 2.8470393550387154e+01, -2.8425385921689980e+01, 2.8379023911335469e+01, -2.8331273163562241e+01, 2.8282097463870919e+01, -2.8231458615927721e+01, 2.8179316307577007e+01, -2.8125627964795978e+01, 2.8070348592274335e+01, -2.8013430599129791e+01, 2.7954823608071283e+01, -2.7894474246092045e+01, 2.7832325914509102e+01, -2.7768318535855649e+01, 2.7702388274772812e+01, -2.7634467229625290e+01, 2.7564483091071313e+01, -2.7492358763234872e+01, 2.7418011942441147e+01, -2.7341354647661582e+01, 2.7262292695845463e+01, -2.7180725114157759e+01, 2.7096543479754125e+01, -2.7009631176051933e+01, 2.6919862552432274e+01, -2.6827101971847423e+01, 2.6731202727801637e+01, -2.6632005808479860e+01, 2.6529338481236699e+01, -2.6423012664989045e+01, 2.6312823050968596e+01, -2.6198544923370154e+01, 2.6079931620126878e+01, -2.5956711559610614e+01, 2.5828584740479602e+01, -2.5695218597789456e+01, 2.5556243066913400e+01, -2.5411244665072719e+01, 2.5259759344501671e+01, -2.5101263795907457e+01, 2.4935164777812641e+01, -2.4760785904535670e+01, 2.4577351124781824e+01, -2.4383963836126313e+01, 2.4179580164227872e+01, -2.3962974319140965e+01, 2.3732693009179656e+01, -2.3486994450692443e+01, 2.3223765221215142e+01, -2.2940404454619134e+01, 2.2633658531147908e+01, -2.2299378247064869e+01, 2.1932149880547183e+01, -2.1524711604262862e+01, 2.1066983867982440e+01, -2.0544356598262947e+01, 1.9934415682618429e+01, -1.9199991275984207e+01, 1.8272015227078569e+01, -1.6996182114611788e+01, 1.4876958810870860e+01}, }, { n: 216, theta: []float64{1.5671686105755023e+00, 1.5599127961684220e+00, 1.5526558355346407e+00, 1.5453969634495357e+00, 1.5381354130756992e+00, 1.5308704153127000e+00, 1.5236011981417006e+00, 1.5163269859634152e+00, 1.5090469989278730e+00, 1.5017604522544048e+00, 1.4944665555402459e+00, 1.4871645120560699e+00, 1.4798535180267400e+00, 1.4725327618954691e+00, 1.4652014235695219e+00, 1.4578586736455008e+00, 1.4505036726121565e+00, 1.4431355700285682e+00, 1.4357535036754083e+00, 1.4283565986768869e+00, 1.4209439665908115e+00, 1.4135147044640579e+00, 1.4060678938505511e+00, 1.3986025997886760e+00, 1.3911178697348172e+00, 1.3836127324494960e+00, 1.3760861968323106e+00, 1.3685372507016056e+00, 1.3609648595144777e+00, 1.3533679650223920e+00, 1.3457454838572851e+00, 1.3380963060426339e+00, 1.3304192934234869e+00, 1.3227132780089634e+00, 1.3149770602201478e+00, 1.3072094070356892e+00, 1.2994090500267301e+00, 1.2915746832720101e+00, 1.2837049611431546e+00, 1.2757984959492026e+00, 1.2678538554283829e+00, 1.2598695600739727e+00, 1.2518440802797628e+00, 1.2437758332892002e+00, 1.2356631799306261e+00, 1.2275044211192108e+00, 1.2192977941041021e+00, 1.2110414684370108e+00, 1.2027335416358120e+00, 1.1943720345138122e+00, 1.1859548861419755e+00, 1.1774799484076148e+00, 1.1689449801287550e+00, 1.1603476406784692e+00, 1.1516854830678944e+00, 1.1429559464302423e+00, 1.1341563478407819e+00, 1.1252838733993509e+00, 1.1163355684922343e+00, 1.1073083271390356e+00, 1.0981988803171721e+00, 1.0890037831415225e+00, 1.0797194007591668e+00, 1.0703418927985888e+00, 1.0608671961885900e+00, 1.0512910061337959e+00, 1.0416087550001036e+00, 1.0318155888237164e+00, 1.0219063411101317e+00, 1.0118755035330074e+00, 1.0017171930750695e+00, 9.9142511507162645e-01, 9.8099252151840288e-01, 9.7041216388519547e-01, 9.5967623952979786e-01, 9.4877633062585665e-01, 9.3770333429470865e-01, 9.2644738235305046e-01, 9.1499774873988793e-01, 9.0334274224692235e-01, 8.9146958161860457e-01, 8.7936424937397950e-01, 8.6701131978084423e-01, 8.5439375521282512e-01, 8.4149266354281749e-01, 8.2828700713198744e-01, 8.1475325116200825e-01, 8.0086493523862246e-01, 7.8659214693830359e-01, 7.7190086863415974e-01, 7.5675215854165734e-01, 7.4110111194290051e-01, 7.2489552655247935e-01, 7.0807416302356885e-01, 6.9056444104412407e-01, 6.7227933193754241e-01, 6.5311307983969791e-01, 6.3293516775593595e-01, 6.1158156935716357e-01, 5.8884164425859431e-01, 5.6443772421506910e-01, 5.3799175946275157e-01, 5.0896747562778555e-01, 4.7656205323872197e-01, 4.3948124005672007e-01, 3.9539840620540745e-01, 3.3931369540774287e-01, 2.5576413755369809e-01}, val: []float64{-2.1420664007171084e-13, 5.3170379037842784e-14, -3.4734236933038639e-15, 2.3242110868118431e-13, 3.7943143720204046e-14, -5.7160511614569708e-14, 2.1177269961331864e-13, -3.4948583926844979e-14, 1.7369271883827313e-13, 3.5623756291990570e-13, 6.5520118362261941e-14, 1.1255590127344777e-13, 9.4867994932892441e-14, -6.1601712969494469e-14, 4.7023788875015558e-14, -1.4272998866826663e-13, -2.6605445153274162e-14, -2.5223571223200907e-13, -1.3724084095111965e-13, -7.0111736669803626e-14, 5.7347666545680944e-14, -5.0924962889888544e-14, -5.2683776576685045e-15, -2.1544335394504838e-13, 4.0230445264824984e-15, 6.9175538975130938e-15, -1.1339463388095042e-13, -3.9896959286779273e-14, -8.8360560296236634e-14, -1.0474371284611670e-13, 1.2687327963040444e-14, -1.7782734520430910e-13, 2.0086781777635686e-13, -7.5400883703521135e-14, 1.2278140016266356e-13, -1.1244970732922019e-13, 1.6072100253117342e-14, 5.2340169298568757e-15, 1.1013085876614924e-13, -9.6621831158318670e-15, -1.8366177977891496e-13, 1.0601073284832238e-14, -1.3784763212103856e-13, -1.5863525424166753e-13, -1.6638681463670250e-13, 8.6360908147481066e-14, -7.8672683965135368e-14, 6.8378486764803313e-14, 9.0534733729868808e-14, 6.6505185887739604e-15, 3.3141885340142080e-15, -2.0537396911778824e-13, 7.3393589371575821e-14, 9.8483281662822096e-14, -2.3812738806298458e-13, 6.5975425886450090e-15, 8.7013139463913052e-14, 7.5278742714453987e-14, -1.0708940266003440e-13, 2.0958580081069137e-13, -1.5480716019053119e-14, 4.8469624575186930e-15, -6.1362291991375536e-14, -3.5942923464396180e-14, -7.6176865685553763e-14, 1.0095757892256693e-13, -4.2683956504767779e-14, -4.8938621882647329e-14, 1.6489272569372713e-15, -1.1390338364880240e-13, 2.1513601964632049e-14, -1.0152923724696736e-14, -3.9597826958407387e-14, -8.5123156147931521e-14, -6.5276802085245163e-14, 6.3966825794140229e-14, -2.8207572680644779e-14, -5.9767990455898208e-15, -1.1189271498293956e-13, -4.5600777141900301e-14, 1.5226732724861721e-14, 3.9473540473700922e-14, -5.6017378761616795e-15, -2.4079255903843183e-14, -3.1139558336514997e-14, -5.6034014603771978e-14, 6.9309294575728887e-14, -3.7871955014469560e-14, 4.2988763678275364e-14, 1.0661412180664073e-14, 6.2069599395465107e-14, -4.8913422170368503e-14, 3.3884911719768557e-14, 2.8191908465098299e-15, 2.1228960171536080e-14, -5.6191478942893769e-14, -1.4786950368470112e-14, -2.1665036441200809e-14, 1.4936420829725019e-14, -1.1615745673091571e-13, 1.4661728300981146e-13, -3.6088669931521093e-13, 1.1825080499589470e-12, -4.7300739521811106e-12, 2.5459387908526307e-11, -2.2842779135337983e-10, 5.3230524570865730e-09, 1.8504694403187737e-14}, dval: []float64{-2.9427800603424888e+01, 2.9427025985916128e+01, -2.9425476404186732e+01, 2.9423151164251305e+01, -2.9420049223750453e+01, 2.9416169190288219e+01, -2.9411509319206210e+01, 2.9406067510787015e+01, -2.9399841306877356e+01, 2.9392827886918813e+01, -2.9385024063373031e+01, 2.9376426276524445e+01, -2.9367030588643043e+01, 2.9356832677485624e+01, -2.9345827829112846e+01, 2.9334010929995465e+01, -2.9321376458381234e+01, 2.9307918474890485e+01, -2.9293630612304742e+01, 2.9278506064510257e+01, -2.9262537574553480e+01, 2.9245717421762187e+01, -2.9228037407881235e+01, 2.9209488842167364e+01, -2.9190062525382206e+01, 2.9169748732617215e+01, -2.9148537194877896e+01, 2.9126417079348521e+01, -2.9103376968250736e+01, 2.9079404836201938e+01, -2.9054488025970500e+01, 2.9028613222515034e+01, -2.9001766425185131e+01, 2.8973932917948375e+01, -2.8945097237496743e+01, 2.8915243139070423e+01, -2.8884353559822181e+01, 2.8852410579527444e+01, -2.8819395378426645e+01, 2.8785288191964142e+01, -2.8750068262165122e+01, 2.8713713785364636e+01, -2.8676201855972852e+01, 2.8637508405928578e+01, -2.8597608139454227e+01, 2.8556474462684314e+01, -2.8514079407692350e+01, 2.8470393550387161e+01, -2.8425385921689987e+01, 2.8379023911335462e+01, -2.8331273163562233e+01, 2.8282097463870926e+01, -2.8231458615927728e+01, 2.8179316307577018e+01, -2.8125627964795974e+01, 2.8070348592274335e+01, -2.8013430599129794e+01, 2.7954823608071287e+01, -2.7894474246092045e+01, 2.7832325914509109e+01, -2.7768318535855656e+01, 2.7702388274772812e+01, -2.7634467229625294e+01, 2.7564483091071331e+01, -2.7492358763234883e+01, 2.7418011942441158e+01, -2.7341354647661582e+01, 2.7262292695845463e+01, -2.7180725114157763e+01, 2.7096543479754128e+01, -2.7009631176051940e+01, 2.6919862552432292e+01, -2.6827101971847430e+01, 2.6731202727801641e+01, -2.6632005808479885e+01, 2.6529338481236724e+01, -2.6423012664989066e+01, 2.6312823050968632e+01, -2.6198544923370196e+01, 2.6079931620126928e+01, -2.5956711559610671e+01, 2.5828584740479652e+01, -2.5695218597789530e+01, 2.5556243066913513e+01, -2.5411244665072843e+01, 2.5259759344501834e+01, -2.5101263795907666e+01, 2.4935164777812918e+01, -2.4760785904536036e+01, 2.4577351124782325e+01, -2.4383963836127013e+01, 2.4179580164228856e+01, -2.3962974319142369e+01, 2.3732693009181720e+01, -2.3486994450695558e+01, 2.3223765221219963e+01, -2.2940404454626893e+01, 2.2633658531160954e+01, -2.2299378247087898e+01, 2.1932149880590437e+01, -2.1524711604350518e+01, 2.1066983868178077e+01, -2.0544356598759389e+01, 1.9934415684120079e+01, -1.9199991281861426e+01, 1.8272015261833435e+01, -1.6996182557157578e+01, 1.4876958810870862e+01}, }, } { got := make([]float64, len(test.theta)) gotD := make([]float64, len(test.theta)) for i := range got { got[i], gotD[i] = Hermite{}.hermpolyAsyAiry(i, test.n, test.theta[i]) } if !floats.EqualApprox(test.val, got, 1e-12) { t.Errorf("n = %v, hermpolyAsyAiry mismatch", test.n) } if !floats.EqualApprox(test.dval, gotD, 1e-12) { t.Errorf("n = %v, hermpolyAsyAiry deriv mismatch", test.n) } } } golang-gonum-v1-gonum-0.14.0/integrate/quad/internal/000077500000000000000000000000001450372207100223665ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/integrate/quad/internal/PrintGoSlice.m000066400000000000000000000004701450372207100251070ustar00rootroot00000000000000% Copyright ©2016 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. function PrintGoSlice(a) fprintf('[]float64{') for i = 1:length(a) fprintf('%1.16e, ',a(i)) end fprintf('}\n') endgolang-gonum-v1-gonum-0.14.0/integrate/quad/internal/genherm.m000066400000000000000000000011751450372207100241750ustar00rootroot00000000000000% Copyright ©2016 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. clc clear all close all % Generate herm points min = 216; max = 216; fprintf('xCache = [][]float64{\n') for i = min:max [x,w] = hermpts(i); fprintf('{') for j = 1:i-1 fprintf('%1.16e, ',x(j)) end fprintf('%1.16e},\n',x(i)) end fprintf('}\n') fprintf('wCache = [][]float64{\n') for i = min:max [x,w] = hermpts(i); fprintf('{') for j = 1:i-1 fprintf('%1.16e, ',w(j)) end fprintf('%1.16e},\n',w(i)) end fprintf('}\n') golang-gonum-v1-gonum-0.14.0/integrate/quad/internal/hermpts.m000066400000000000000000000423211450372207100242300ustar00rootroot00000000000000% Copyright (c) 2015, The Chancellor, Masters and Scholars of the University % of Oxford, and the Chebfun Developers. % Copyright (c) 2016 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 University of Oxford nor the names of its % contributors may be used to endorse or promote products derived from % this software without specific prior written permission. % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND % ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED % WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE % DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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. function [x, w, v] = hermpts(n, varargin) %HERMPTS Hermite points and Gauss-Hermite Quadrature Weights. % HERMPTS(N) returns N Hermite points X in (-inf, inf). By default these are % roots of the 'physicist'-type Hermite polynomials, which are orthogonal with % respect to the weight exp(-x.^2). % % HERMPTS(N, 'PROB') normalises instead by the probablist's definition (with % weight exp(-x.^2/2)), which gives rise to monomials. % % [X, W] = HERMPTS(N) returns also a row vector W of weights for Gauss-Hermite % quadrature. [X,W,V] = HERMPTS(N) returns in addition a column vector V of % the barycentric weights corresponding to X. % % [X, W] = HERMPTS(N, METHOD) where METHOD is one of 'GW', 'REC', 'GLR', or % 'ASY' allows the user to select which method is used. 'GW' will use the % traditional Golub-Welsch eigenvalue method [1], best when n<=20. 'REC' % uses Newton's method with polynomial evaluation via the 3-term % recurrence for Hermite polynomials. 'GLR' uses Glaser-Liu-Rokhlin % fast algorithm which is much faster for large N [2]. 'ASY' uses Newton's % method with polynomial evaluation via asymptotic formula. 'ASY' is the % fastest for N>=200, 'GLR' is the most accurate for nodes close to 0. % By default HERMPTS uses 'GW' when N <= 20, 'REC' for 21<=N<200, and % 'ASY' when N>=200. % % References: % [1] G. H. Golub and J. A. Welsch, "Calculation of Gauss quadrature % rules", Math. Comp. 23:221-230, 1969, % [2] A. Glaser, X. Liu and V. Rokhlin, "A fast algorithm for the % calculation of the roots of special functions", SIAM Journal % on Scientific Computing", 29(4):1420-1438:, 2007. % [3] A. Townsend, T. Trogdon and S. Olver, Fast computation of Gauss % nodes and weights on the whole real line, submitted, 2014. % % See also CHEBPTS, LEGPTS, LAGPTS, and JACPTS. % Copyright 2015 by The University of Oxford and The Chebfun Developers. % See http://www.chebfun.org/ for Chebfun information. % % 'GW' by Nick Trefethen, March 2009 - algorithm adapted from [1]. % 'GLR' by Nick Hale, March 2010 - algorithm adapted from [2]. % Defaults: method = 'default'; type = 'phys'; if ( n < 0 ) error('CHEBFUN:hermpts:n', 'First input should be a positive integer.'); end % Return empty vector if n = 0. if ( n == 0 ) [x, w, v] = deal([]); return end % Check the inputs while ( ~isempty(varargin) ) s = varargin{1}; varargin(1) = []; if ( strcmpi(s, 'GW') ) method = 'GW'; elseif ( strcmpi(s,'glr') ) method = 'GLR'; elseif ( strcmpi(s,'rec') ) method = 'REC'; elseif ( strcmpi(s,'asy') ) method = 'ASY'; elseif ( strncmpi(s, 'phys', 3) ) type = 'phys'; elseif ( strncmpi(s, 'prob', 3) ) type = 'prob'; else error('CHEBFUN:hermpts:input', 'Unrecognised input string; %s.', s); end end % Three cases: % % N <= 20: Use GW % 21<=N<200: Use REC % N>=200: Use ASY if ( n == 1 ) % n = 1 case is trivial x = 0; w = sqrt(pi); v = 1; elseif ( (n < 21 && strcmpi(method,'default')) || strcmpi(method,'GW') ) % GW, see [1] beta = sqrt(.5*(1:n-1)); % 3-term recurrence coeffs T = diag(beta, 1) + diag(beta, -1); % Jacobi matrix [V, D] = eig(T); % Eigenvalue decomposition [x, indx] = sort(diag(D)); % Hermite points w = sqrt(pi)*V(1, indx).^2; % weights v = abs(V(1, indx)).'; % Barycentric weights v = v./max(v); % Normalize v(2:2:n) = -v(2:2:n); % Enforce symmetry: ii = 1:floor(n/2); x = x(ii); w = w(ii); vmid = v(floor(n/2)+1); v = v(ii); if ( mod(n, 2) ) x = [x ; 0 ; -x(end:-1:1)]; w = [w, sqrt(pi) - sum(2*w), w(end:-1:1)]; v = [v ; vmid ; v(end:-1:1)]; else x = [x ; -x(end:-1:1)]; w = [w, w(end:-1:1)]; v = [v ; -v(end:-1:1)]; end elseif ( strcmpi(method,'GLR') ) % Fast, see [2] [x, ders] = alg0_Herm(n); % Nodes and H_n'(x) w = (2*exp(-x.^2)./ders.^2)'; % Quadrature weights v = exp(-x.^2/2)./ders; % Barycentric weights v = v./max(abs(v)); % Normalize if ( ~mod(n, 2) ) ii = (n/2+1):n; v(ii) = -v(ii); end elseif ( (n < 200 && strcmpi(method,'default')) || strcmpi(method,'REC') ) [x, w, v] = hermpts_rec( n ); else [x, w, v] = hermpts_asy( n ); end % Normalise so that sum(w) = sqrt(pi) w = (sqrt(pi)/sum(w))*w; if ( strcmpi(type, 'prob') ) x = x*sqrt(2); w = w*sqrt(2); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%%%%%%%%%%%%%%%%%%%%%% Routines for GLR algorithm %%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Driver for 'GLR'. function [roots, ders] = alg0_Herm(n) % Compute coefficients of H_m(0), H_m'(0), m = 0,..,N. Hm2 = 0; Hm1 = pi^(-1/4); Hpm2 = 0; Hpm1 = 0; for k = 0:n-1 H = -sqrt(k/(k+1))*Hm2; Hp = sqrt(2/(k+1))*Hm1-sqrt(k/(k+1))*Hpm2; Hm2 = Hm1; Hm1 = H; Hpm2 = Hpm1; Hpm1 = Hp; end % allocate storage roots = zeros(n, 1); ders = zeros(n, 1); if ( mod(n,2) ) % zero is a root: roots((n-1)/2) = 0; ders((n+1)/2) = Hp; else % find first root: [roots(n/2+1), ders(n/2+1)] = alg2_Herm(H,n); end % compute roots and derivatives: [roots, ders] = alg1_Herm(roots, ders); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Main algorithm for 'GLR' function [roots, ders] = alg1_Herm(roots, ders) n = length(roots); s = mod(n, 2); N = (n - s) / 2; % number of terms in Taylor expansion m = 30; % initialise hh1 = ones(m + 1, 1); u = zeros(1, m + 1); up = zeros(1, m + 1); for j = (N + 1):(n - 1) % previous root x = roots(j); % initial approx h = rk2_Herm(pi/2,-pi/2,x,n) - x; % scaling M = 1/h; % recurrence relation for Hermite polynomials c1 = -(2*n+1-x^2)/M^2; c2 = 2*x./M^3; c3 = 1./M^4; u(1) = 0; u(2) = ders(j)/M; u(3) = .5*c1*u(1); u(4) = (c1*u(2) + c2*u(1))/6; up(1) = u(2); up(2) = 2*u(3)*M; up(3) = 3*u(4)*M; up(m+1) = 0; for k = 2:m-2 u(k+3) = (c1*u(k+1) + c2*u(k) + c3*u(k-1))/((k+1)*(k+2)); up(k+2) = (k+2)*u(k+3)*M; end % flip for more accuracy in inner product calculation u = u(m+1:-1:1); up = up(m+1:-1:1); % Newton iteration hh = hh1; hh(end) = M; step = inf; l = 0; z = zeros(m, 1); while ( (abs(step) > eps) && (l < 10) ) l = l + 1; step = (u*hh)/(up*hh); h = h - step; % powers of h (This is the fastest way!) hh = [M ; cumprod(M*h + z)]; % flip for more accuracy in inner product calculation hh = hh(end:-1:1); end % update roots(j+1) = x + h; ders(j+1) = up*hh; end % nodes are symmetric roots(1:N+s) = -roots(n:-1:N+1); ders(1:N+s) = ders(n:-1:N+1); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % find the first root (note H_n'(0) = 0) function [x1, d1] = alg2_Herm(Hn0, n) % advance ODE via Runge-Kutta for initial approx x1 = rk2_Herm(0, -pi/2, 0, n); % number of terms in Taylor expansion m = 30; % scaling M = 1/x1; % c = log10(n); % M = 1./x1.^(1-1.25/(c)); % initialise u = zeros(1,m+1); up = zeros(1,m+1); % recurrence relation for Legendre polynomials u(1) = Hn0; u(3) = -.5*(2*n+1)*u(1)/M^2; up(1) = 0; up(2) = 2*u(3)*M; for k = 2:2:m-2 u(k+3) = (-(2*n+1)*u(k+1)/M^2 + u(k-1)/M^4)/((k+1)*(k+2)); up(k+2) = (k+2)*u(k+3)*M; end % flip for more accuracy in inner product calculation u = u(m+1:-1:1); up = up(m+1:-1:1); z = zeros(m, 1); x1k = [M ; cumprod(M*x1 + z)]; step = inf; l = 0; % Newton iteration while ( (abs(step) > eps) && (l < 10) ) l = l + 1; step = (u*x1k)/(up*x1k); x1 = x1 - step; % powers of h (This is the fastest way!) x1k = [1 ; cumprod(M*x1 + z)]; x1k = x1k(end:-1:1); end % Update derivative d1 = up*x1k; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Runge-Kutta for Hermite Equation function x = rk2_Herm(t, tn, x, n) m = 10; h = (tn-t)/m; for j = 1:m k1 = -h/(sqrt(2*n+1-x^2) - .5*x*sin(2*t)/(2*n+1-x^2)); t = t + h; k2 = -h/(sqrt(2*n+1-(x+k1)^2) - .5*x*sin(2*t)/(2*n+1-(x+k1)^2)); x = x + .5*(k1 + k2); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%%%%%%%%%%%%%%%%%%%%%% Routines for ASY algorithm %%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [x, w, v] = hermpts_asy(n) % HERMPTS_ASY, fast algorithm for computing Gauss-Hermite nodes and weights % using Newton's method with polynomial evaluation via asymptotic expansions. % % x = Gauss-Hermite nodes, w = quad weights, v = bary weights. % % See [3]. [x, w, v] = hermpts_asy0( n ); if mod(n,2) == 1 % fold out x = [-x(end:-1:1);x(2:end)]; w = [w(end:-1:1) w(2:end)]; w = (sqrt(pi)/sum(w))*w; v = [v(end:-1:1);v(2:end)]; v = v./max(abs(v)); else x = [-x(end:-1:1);x]; w = [w(end:-1:1) w]; w = (sqrt(pi)/sum(w))*w; v = [v(end:-1:1);-v]; v = v./max(abs(v)); end % debug %tic, exact = hermpts(n); toc %semilogy(abs(exact-x)) end function [x, w, v] = hermpts_asy0(n) % Compute Hermite nodes and weights using asymptotic formula x0 = HermiteInitialGuesses(n); % get initial guesses t0 = x0./sqrt(2*n+1); theta0 = acos(t0); % convert to theta-variable for k = 1:20 [val, dval] = hermpoly_asy_airy(n, theta0); dt = -val./(sqrt(2)*sqrt(2*n+1)*dval.*sin(theta0)); theta0 = theta0 - dt; % Newton update if norm(dt,inf) < sqrt(eps)/10, break; end end t0 = cos(theta0); x = sqrt(2*n+1)*t0; % back to x-variable ders = x.*val + sqrt(2)*dval; %ders = dval; w = (exp(-x.^2)./ders.^2)'; % quadrature weights v = exp(-x.^2/2)./ders; % Barycentric weights end function [val, dval] = hermpoly_asy_airy(n, theta) % HERMPOLY_ASY evaluation hermite poly using Airy asymptotic formula in % theta-space. musq = 2*n+1; cosT = cos(theta); sinT = sin(theta); sin2T = 2*cosT.*sinT; eta = .5*theta - .25*sin2T; chi = -(3*eta/2).^(2/3); phi = (-chi./sinT.^2).^(1/4); const = 2*sqrt(pi)*musq^(1/6)*phi; Airy0 = real(airy(musq.^(2/3)*chi)); Airy1 = real(airy(1,musq.^(2/3)*chi)); % Terms in (12.10.43): a0 = 1; b0 = 1; a1 = 15/144; b1 = -7/5*a1; a2 = 5*7*9*11/2/144^2; b2 = -13/11*a2; a3 = 7*9*11*13*15*17/6/144^3; b3 = -19/17*a3; % u polynomials in (12.10.9) u0 = 1; u1 = (cosT.^3-6*cosT)/24; u2 = (-9*cosT.^4 + 249*cosT.^2 + 145)/1152; u3 = (-4042*cosT.^9+18189*cosT.^7-28287*cosT.^5-151995*cosT.^3-259290*cosT)/414720; %first term A0 = 1; val = A0*Airy0; %second term B0 = -(a0*phi.^6.*u1+a1*u0)./chi.^2; val = val + B0.*Airy1./musq.^(4/3); %third term A1 = (b0*phi.^12.*u2 + b1*phi.^6.*u1 + b2*u0)./chi.^3; val = val + A1.*Airy0/musq.^2; %fourth term B1 = -(phi.^18.*u3 + a1*phi.^12.*u2 + a2*phi.^6.*u1 + a3*u0)./chi.^5; val = val + B1.*Airy1./musq.^(4/3+2); val = const.*val; %% Derivative eta = .5*theta - .25*sin2T; chi = -(3*eta/2).^(2/3); phi = (-chi./sinT.^2).^(1/4); const = sqrt(2*pi)*musq^(1/3)./phi; % v polynomials in (12.10.10) v0 = 1; v1 = (cosT.^3+6*cosT)/24; v2 = (15*cosT.^4-327*cosT.^2-143)/1152; v3 = (259290*cosT + 238425*cosT.^3 - 36387*cosT.^5 + 18189*cosT.^7 -... 4042*cosT.^9)/414720; %first term C0 = -(b0*phi.^6.*v1 + b1.*v0)./chi; dval = C0.*Airy0/musq.^(2/3); % %second term D0 = a0*v0; dval = dval + D0*Airy1; % %third term C1 = -(phi.^18.*v3 + b1*phi.^12.*v2 + b2*phi.^6.*v1 + b3*v0)./chi.^4; dval = dval + C1.*Airy0/musq.^(2/3+2); %fourth term D1 = (a0*phi.^12.*v2 + a1*phi.^6.*v1 + a2*v0)./chi.^3; dval = dval + D1.*Airy1/musq.^2; dval = const.*dval; end function x_init = HermiteInitialGuesses(n) %HERMITEINTITIALGUESSES(N), Initial guesses for Hermite zeros. % % [1] L. Gatteschi, Asymptotics and bounds for the zeros of Laguerre % polynomials: a survey, J. Comput. Appl. Math., 144 (2002), pp. 7-27. % % [2] F. G. Tricomi, Sugli zeri delle funzioni di cui si conosce una % rappresentazione asintotica, Ann. Mat. Pura Appl. 26 (1947), pp. 283-300. % Gatteschi formula involving airy roots [1]. % These initial guess are good near x = sqrt(n+1/2); if mod(n,2) == 1 m = (n-1)/2; bess = (1:m)'*pi; a = .5; else m = n/2; bess = ((0:m-1)'+.5)*pi; a = -.5; end nu = 4*m + 2*a + 2; T = @(t) t.^(2/3).*(1+5/48*t.^(-2)-5/36*t.^(-4)+(77125/82944)*t.^(-6) -... 108056875/6967296*t.^(-8)+162375596875/334430208*t.^(-10)); airyrts = -T(3/8*pi*(4*(1:m)'-1)); airyrts_exact = [ -2.338107410459762 % Exact Airy roots. -4.087949444130970 -5.520559828095555 -6.786708090071765 -7.944133587120863 -9.022650853340979 -10.040174341558084 -11.008524303733260 -11.936015563236262 -12.828776752865757]; airyrts(1:10) = airyrts_exact; % correct first 10. x_init = sqrt(nu + 2^(2/3)*airyrts*nu^(1/3) +... 1/5*2^(4/3)*airyrts.^2*nu^(-1/3) +... (11/35-a^2-12/175*airyrts.^3)/nu +... (16/1575*airyrts+92/7875*airyrts.^4)*2^(2/3)*nu^(-5/3) -... (15152/3031875*airyrts.^5+1088/121275*airyrts.^2)*2^(1/3)*nu^(-7/3)); x_init_airy = real(x_init(end:-1:1)); % Tricomi initial guesses. Equation (2.1) in [1]. Originally in [2]. % These initial guesses are good near x = 0 . Note: zeros of besselj(+/-.5,x) % are integer and half-integer multiples of pi. % x_init_bess = bess/sqrt(nu).*sqrt((1+ (bess.^2+2*(a^2-1))/3/nu^2) ); Tnk0 = pi/2*ones(m,1); nu = (4*m+2*a+2); rhs = (4*m-4*(1:m)'+3)./nu*pi; for k = 1:7 val = Tnk0 - sin(Tnk0) - rhs; dval = 1 - cos(Tnk0); dTnk0 = val./dval; Tnk0 = Tnk0 - dTnk0; end tnk = cos(Tnk0/2).^2; x_init_sin = sqrt(nu*tnk - (5./(4*(1-tnk).^2) - 1./(1-tnk)-1+3*a^2)/3/nu); % Patch together p = 0.4985+eps; x_init = [x_init_sin(1:floor(p*n));x_init_airy(ceil(p*n):end)]; if mod(n,2) == 1 x_init = [0;x_init]; x_init = x_init(1:m+1); else x_init = x_init(1:m); end % debug: %y = hermpts(n); %semilogy(abs(y - x_init)); %yhalf = -y(m:-1:1); %semilogy(abs(yhalf - x_init)); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%%%%%%%%%%%%%%%%%%%%%% Routines for REC algorithm %%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [x, w, v] = hermpts_rec(n) % Compute Hermite nodes and weights using recurrence relation. x0 = HermiteInitialGuesses(n); x0 = x0.*sqrt(2); for kk = 1:10 [val, dval] = hermpoly_rec(n, x0); dx = val./dval; dx(isnan(dx)) = 0; x0 = x0 - dx; if norm(dx, inf)= max { panic("legendre: min >= max") } if math.IsInf(min, 0) || math.IsInf(max, 0) { panic("legendre: infinite bound") } for i := range x { x[i], weight[i] = l.boundedLocation(len(x), i, min, max) } } func (l Legendre) FixedLocationSingle(n, k int, min, max float64) (x, weight float64) { if min >= max { panic("legendre: min >= max") } if math.IsInf(min, 0) || math.IsInf(max, 0) { panic("legendre: infinite bound") } return l.boundedLocation(n, k, min, max) } func (l Legendre) boundedLocation(n, k int, min, max float64) (x, weight float64) { x, weight = l.location(n, k) return (x+1)/2*(max-min) + min, weight * (max - min) / 2 } // Algorithm adapted from http://sourceforge.net/projects/fastgausslegendrequadrature. // Original Copyright Notice: //******************************************* // Copyright (C) 2014 by Ignace Bogaert * //******************************************* // This software package is based on the paper // I. Bogaert, "Iteration-Free Computation of Gauss-Legendre Quadrature Nodes and Weights", // to be published in the SIAM Journal of Scientific Computing. // The main features of this software are: // - Speed: due to the simple formulas and the O(1) complexity computation of individual Gauss-Legendre // quadrature nodes and weights. This makes it compatible with parallel computing paradigms. // - Accuracy: the error on the nodes and weights is within a few ulps (see the paper for details). // Disclaimer: // THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 REGENTS 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. // location finds the location and weight for location k given n total samples. func (l Legendre) location(n, k int) (x, weight float64) { // Note: k is 1-indexed in the original algorithm. It has been translated to // zero-indexed here. if n < 101 { theta, weight := l.tabulated(n, k) return math.Cos(theta), weight } if 2*k+1 > n { theta, weight := l.computed(n, n-k) return math.Cos(math.Pi - theta), weight } theta, weight := l.computed(n, k+1) return math.Cos(theta), weight } // Returns tabulated theta and weight values: valid for l <= 100 func (l Legendre) tabulated(n, k int) (theta, weight float64) { if n%2 == 1 { n2 := (n - 1) / 2 if k == n2 { return math.Pi / 2, 2.0 / (cl[n] * cl[n]) } if k < n2 { return oddThetaZeros[n2-1][n2-k-1], oddWeights[n2-1][n2-k-1] } return math.Pi - oddThetaZeros[n2-1][k-n2-1], oddWeights[n2-1][k-n2-1] } n2 := n / 2 if k < n2 { return evenThetaZeros[n2-1][n2-k-1], evenWeights[n2-1][n2-k-1] } return math.Pi - evenThetaZeros[n2-1][k-n2], evenWeights[n2-1][k-n2] } func (l Legendre) computed(n, k int) (theta, weight float64) { // First, get the bessel zero w := 1.0 / (float64(n) + 0.5) nu := besselJZero(k) theta = w * nu x := theta * theta // Get the asymptotic BesselJ(1, nu) squared b := besselJ1Squared(k) // Get the Chebyshev interpolants for the nodes. sf1t := (((((-1.29052996274280508473467968379e-12*x+2.40724685864330121825976175184e-10)*x-3.13148654635992041468855740012e-8)*x+0.275573168962061235623801563453e-5)*x-0.148809523713909147898955880165e-3)*x+0.416666666665193394525296923981e-2)*x - 0.416666666666662959639712457549e-1 sf2t := (((((+2.20639421781871003734786884322e-9*x-7.53036771373769326811030753538e-8)*x+0.161969259453836261731700382098e-5)*x-0.253300326008232025914059965302e-4)*x+0.282116886057560434805998583817e-3)*x-0.209022248387852902722635654229e-2)*x + 0.815972221772932265640401128517e-2 sf3t := (((((-2.97058225375526229899781956673e-8*x+5.55845330223796209655886325712e-7)*x-0.567797841356833081642185432056e-5)*x+0.418498100329504574443885193835e-4)*x-0.251395293283965914823026348764e-3)*x+0.128654198542845137196151147483e-2)*x - 0.416012165620204364833694266818e-2 // and the weights wsf1t := ((((((((-2.20902861044616638398573427475e-14*x+2.30365726860377376873232578871e-12)*x-1.75257700735423807659851042318e-10)*x+1.03756066927916795821098009353e-8)*x-4.63968647553221331251529631098e-7)*x+0.149644593625028648361395938176e-4)*x-0.326278659594412170300449074873e-3)*x+0.436507936507598105249726413120e-2)*x-0.305555555555553028279487898503e-1)*x + 0.833333333333333302184063103900e-1 wsf2t := (((((((+3.63117412152654783455929483029e-12*x+7.67643545069893130779501844323e-11)*x-7.12912857233642220650643150625e-9)*x+2.11483880685947151466370130277e-7)*x-0.381817918680045468483009307090e-5)*x+0.465969530694968391417927388162e-4)*x-0.407297185611335764191683161117e-3)*x+0.268959435694729660779984493795e-2)*x - 0.111111111111214923138249347172e-1 wsf3t := (((((((+2.01826791256703301806643264922e-9*x-4.38647122520206649251063212545e-8)*x+5.08898347288671653137451093208e-7)*x-0.397933316519135275712977531366e-5)*x+0.200559326396458326778521795392e-4)*x-0.422888059282921161626339411388e-4)*x-0.105646050254076140548678457002e-3)*x-0.947969308958577323145923317955e-4)*x + 0.656966489926484797412985260842e-2 // Then refine with the paper expansions nuSin := nu / math.Sin(theta) bNuSin := b * nuSin wInvSinc := w * w * nuSin wIS2 := wInvSinc * wInvSinc // Finally, compute the node and the weight theta = w * (nu + theta*wInvSinc*(sf1t+wIS2*(sf2t+wIS2*sf3t))) deno := bNuSin + bNuSin*wIS2*(wsf1t+wIS2*(wsf2t+wIS2*wsf3t)) weight = 2.0 * w / deno return theta, weight } func besselJZero(k int) float64 { if k < 20 { return jz[k-1] } z := math.Pi * (float64(k) - 0.25) r := 1.0 / z r2 := r * r z += r * (0.125 + r2*(-0.807291666666666666666666666667e-1+r2*(0.246028645833333333333333333333+r2*(-1.82443876720610119047619047619+r2*(25.3364147973439050099206349206+r2*(-567.644412135183381139802038240+r2*(18690.4765282320653831636345064+r2*(-8.49353580299148769921876983660e5+5.09225462402226769498681286758e7*r2)))))))) return z } func besselJ1Squared(k int) float64 { if k < 21 { return j1[k-1] } x := 1.0 / (float64(k) - 0.25) x2 := x * x return x * (0.202642367284675542887758926420 + x2*x2*(-0.303380429711290253026202643516e-3+x2*(0.198924364245969295201137972743e-3+x2*(-0.228969902772111653038747229723e-3+x2*(0.433710719130746277915572905025e-3+x2*(-0.123632349727175414724737657367e-2+x2*(0.496101423268883102872271417616e-2+x2*(-0.266837393702323757700998557826e-1+.185395398206345628711318848386*x2)))))))) } // Tabulated values var jz = [20]float64{2.40482555769577276862163187933, 5.52007811028631064959660411281, 8.65372791291101221695419871266, 11.7915344390142816137430449119, 14.9309177084877859477625939974, 18.0710639679109225431478829756, 21.2116366298792589590783933505, 24.3524715307493027370579447632, 27.4934791320402547958772882346, 30.6346064684319751175495789269, 33.7758202135735686842385463467, 36.9170983536640439797694930633, 40.0584257646282392947993073740, 43.1997917131767303575240727287, 46.3411883716618140186857888791, 49.4826098973978171736027615332, 52.6240518411149960292512853804, 55.7655107550199793116834927735, 58.9069839260809421328344066346, 62.0484691902271698828525002646} var j1 = [21]float64{0.269514123941916926139021992911, 0.115780138582203695807812836182, 0.0736863511364082151406476811985, 0.0540375731981162820417749182758, 0.0426614290172430912655106063495, 0.0352421034909961013587473033648, 0.0300210701030546726750888157688, 0.0261473914953080885904584675399, 0.0231591218246913922652676382178, 0.0207838291222678576039808057297, 0.0188504506693176678161056800214, 0.0172461575696650082995240053542, 0.0158935181059235978027065594287, 0.0147376260964721895895742982592, 0.0137384651453871179182880484134, 0.0128661817376151328791406637228, 0.0120980515486267975471075438497, 0.0114164712244916085168627222986, 0.0108075927911802040115547286830, 0.0102603729262807628110423992790, 0.00976589713979105054059846736696} // Tabulated nodes and weights // The required theta values for the Legendre nodes for l <= 100 var evenThetaZeros = [][]float64{ {0.9553166181245092781638573e0}, {0.1223899586470372591854100e1, 0.5332956802491269896325121e0}, {0.1329852612388110166006182e1, 0.8483666264874876548310910e0, 0.3696066519448289481138796e0}, {0.1386317078892131346282665e1, 0.1017455539490153431016397e1, 0.6490365804607796100719162e0, 0.2827570635937967783987981e0}, {0.1421366498439524924081833e1, 0.1122539327631709474018620e1, 0.8238386589997556048023640e0, 0.5255196555285001171749362e0, 0.2289442988470260178701589e0}, {0.1445233238471440081118261e1, 0.1194120375947706635968399e1, 0.9430552870605735796668951e0, 0.6921076988818410126677201e0, 0.4414870814893317611922530e0, 0.1923346793046672033050762e0}, {0.1462529992921481833498746e1, 0.1246003586776677662375070e1, 0.1029498592525136749641068e1, 0.8130407055389454598609888e0, 0.5966877608172733931509619e0, 0.3806189306666775272453522e0, 0.1658171411523664030454318e0}, {0.1475640280808194256470687e1, 0.1285331444322965257106517e1, 0.1095033401803444343034890e1, 0.9047575323895165085030778e0, 0.7145252532340252146626998e0, 0.5243866409035941583262629e0, 0.3344986386876292124968005e0, 0.1457246820036738335698855e0}, {0.1485919440392653014379727e1, 0.1316167494718022699851110e1, 0.1146421481056642228295923e1, 0.9766871104439832694094465e0, 0.8069738930788195349918620e0, 0.6373005058706191519531139e0, 0.4677113145328286263205134e0, 0.2983460782092324727528346e0, 0.1299747364196768405406564e0}, {0.1494194914310399553510039e1, 0.1340993178589955138305166e1, 0.1187794926634098887711586e1, 0.1034603297590104231043189e1, 0.8814230742890135843662021e0, 0.7282625848696072912405713e0, 0.5751385026314284688366450e0, 0.4220907301111166004529037e0, 0.2692452880289302424376614e0, 0.1172969277059561308491253e0}, {0.1501000399130816063282492e1, 0.1361409225664372117193308e1, 0.1221820208990359866348145e1, 0.1082235198111836788818162e1, 0.9426568273796608630446470e0, 0.8030892957063359443650460e0, 0.6635400754448062852164288e0, 0.5240242709487281141128643e0, 0.3845781703583910933413978e0, 0.2453165389983612942439953e0, 0.1068723357985259945018899e0}, {0.1506695545558101030878728e1, 0.1378494427506219143960887e1, 0.1250294703417272987066314e1, 0.1122097523267250692925104e1, 0.9939044422989454674968570e0, 0.8657177770401081355080608e0, 0.7375413075437535618804594e0, 0.6093818382449565759195927e0, 0.4812531951313686873528891e0, 0.3531886675690780704072227e0, 0.2252936226353075734690198e0, 0.9814932949793685067733311e-1}, {0.1511531546703289231944719e1, 0.1393002286179807923400254e1, 0.1274473959424494104852958e1, 0.1155947313793812040125722e1, 0.1037423319077439147088755e1, 0.9189033445598992550553862e0, 0.8003894803353296871788647e0, 0.6818851814129298518332401e0, 0.5633967073169293284500428e0, 0.4449368152119130526034289e0, 0.3265362611165358134766736e0, 0.2082924425598466358987549e0, 0.9074274842993199730441784e-1}, {0.1515689149557281132993364e1, 0.1405475003062348722192382e1, 0.1295261501292316172835393e1, 0.1185049147889021579229406e1, 0.1074838574917869281769567e1, 0.9646306371285440922680794e0, 0.8544265718392254369377945e0, 0.7442282945111358297916378e0, 0.6340389954584301734412433e0, 0.5238644768825679339859620e0, 0.4137165857369637683488098e0, 0.3036239070914333637971179e0, 0.1936769929947376175341314e0, 0.8437551461511597225722252e-1}, {0.1519301729274526620713294e1, 0.1416312682230741743401738e1, 0.1313324092045794720169874e1, 0.1210336308624476413072722e1, 0.1107349759228459143499061e1, 0.1004365001539081003659288e1, 0.9013828087667156388167226e0, 0.7984043170121235411718744e0, 0.6954313000299367256853883e0, 0.5924667257887385542924194e0, 0.4895160050896970092628705e0, 0.3865901987860504829542802e0, 0.2837160095793466884313556e0, 0.1809780449917272162574031e0, 0.7884320726554945051322849e-1}, {0.1522469852641529230282387e1, 0.1425817011963825344615095e1, 0.1329164502391080681347666e1, 0.1232512573416362994802398e1, 0.1135861522840293704616614e1, 0.1039211728068951568003361e1, 0.9425636940046777101926515e0, 0.8459181315837993237739032e0, 0.7492760951181414487254243e0, 0.6526392394594561548023681e0, 0.5560103418005302722406995e0, 0.4593944730762095704649700e0, 0.3628020075350028174968692e0, 0.2662579994723859636910796e0, 0.1698418454282150179319973e0, 0.7399171309970959768773072e-1}, {0.1525270780617194430047563e1, 0.1434219768045409606267345e1, 0.1343169000217435981125683e1, 0.1252118659062444379491066e1, 0.1161068957629157748792749e1, 0.1070020159291475075961444e1, 0.9789726059789103169325141e0, 0.8879267623988119819560021e0, 0.7968832893748414870413015e0, 0.7058431727509840105946884e0, 0.6148079652926100198490992e0, 0.5237802779694730663856110e0, 0.4327648832448234459097574e0, 0.3417715500266717765568488e0, 0.2508238767288223767569849e0, 0.1599966542668327644694431e0, 0.6970264809814094464033170e-1}, {0.1527764849261740485876940e1, 0.1441701954349064743573367e1, 0.1355639243522655042028688e1, 0.1269576852063768424508476e1, 0.1183514935851550608323947e1, 0.1097453683555812711123880e1, 0.1011393333949027021740881e1, 0.9253342019812867059380523e0, 0.8392767201322475821509486e0, 0.7532215073977623159515351e0, 0.6671694908788198522546767e0, 0.5811221342350705406265672e0, 0.4950819018993074588093747e0, 0.4090533017972007314666814e0, 0.3230455648729987995657071e0, 0.2370809940997936908335290e0, 0.1512302802537625099602687e0, 0.6588357082399222649528476e-1}, {0.1529999863223206659623262e1, 0.1448406982124841835685420e1, 0.1366814241651488684482888e1, 0.1285221744143731581870833e1, 0.1203629605904952775544878e1, 0.1122037965173751996510051e1, 0.1040446993107623345153211e1, 0.9588569097730895525404200e0, 0.8772680085516152329147030e0, 0.7956806951062012653043722e0, 0.7140955526031660805347356e0, 0.6325134568448222221560326e0, 0.5509357927460004487348532e0, 0.4693648943475422765864580e0, 0.3878050333015201414955289e0, 0.3062649591511896679168503e0, 0.2247658146033686460963295e0, 0.1433746167818849555570557e0, 0.6246124541276674097388211e-1}, {0.1532014188279762793560699e1, 0.1454449946977268522285131e1, 0.1376885814601482670609845e1, 0.1299321869764876494939757e1, 0.1221758200747475205847413e1, 0.1144194910846247537582396e1, 0.1066632125552939823863593e1, 0.9890700026972186303565530e0, 0.9115087474225932692070479e0, 0.8339486352158799520695092e0, 0.7563900488174808348719219e0, 0.6788335401193977027577509e0, 0.6012799395312684623216685e0, 0.5237305617022755897200291e0, 0.4461876237541810478131970e0, 0.3686551849119556335824055e0, 0.2911415613085158758589405e0, 0.2136668503694680525340165e0, 0.1362947587312224822844743e0, 0.5937690028966411906487257e-1}, {0.1533838971193864306068338e1, 0.1459924288056445029654271e1, 0.1386009690354996919044862e1, 0.1312095239305276612560739e1, 0.1238181002944535867235042e1, 0.1164267059803796726229370e1, 0.1090353503721897748980095e1, 0.1016440450472067349837507e1, 0.9425280472651469176638349e0, 0.8686164868955467866176243e0, 0.7947060295895204342519786e0, 0.7207970381018823842440224e0, 0.6468900366403721167107352e0, 0.5729858150363658839291287e0, 0.4990856247464946058899833e0, 0.4251915773724379089467945e0, 0.3513075400485981451355368e0, 0.2774414365914335857735201e0, 0.2036124177925793565507033e0, 0.1298811916061515892914930e0, 0.5658282534660210272754152e-1}, {0.1535499761264077326499892e1, 0.1464906652494521470377318e1, 0.1394313611500109323616335e1, 0.1323720686538524176057236e1, 0.1253127930763390908996314e1, 0.1182535404796980113294400e1, 0.1111943180033868679273393e1, 0.1041351343083674290731439e1, 0.9707600019805773720746280e0, 0.9001692951667510715040632e0, 0.8295794049297955988640329e0, 0.7589905782114329186155957e0, 0.6884031600807736268672129e0, 0.6178176499732537480601935e0, 0.5472348011493452159473826e0, 0.4766558078624760377875119e0, 0.4060826859477620301047824e0, 0.3355191279517093844978473e0, 0.2649727008485465487101933e0, 0.1944616940738156405895778e0, 0.1240440866043499301839465e0, 0.5403988657613871827831605e-1}, {0.1537017713608809830855653e1, 0.1469460505124226636602925e1, 0.1401903350962364703169699e1, 0.1334346289590505369693957e1, 0.1266789363044399933941254e1, 0.1199232618763735058848455e1, 0.1131676111906105521856066e1, 0.1064119908394702657537061e1, 0.9965640890815034701957497e0, 0.9290087556203499065939494e0, 0.8614540390091103102510609e0, 0.7939001124053586164046432e0, 0.7263472110048245091518914e0, 0.6587956640463586742461796e0, 0.5912459486086227271608064e0, 0.5236987847717837556177452e0, 0.4561553147193391989386660e0, 0.3886174669444433167860783e0, 0.3210887745896478259115420e0, 0.2535764786314617292100029e0, 0.1860980813776342452540915e0, 0.1187090676924131329841811e0, 0.5171568198966901682810573e-1}, {0.1538410494858190444190279e1, 0.1473638845472165977392911e1, 0.1408867240039222913928858e1, 0.1344095709533508756473909e1, 0.1279324287566779722061664e1, 0.1214553011719528935181709e1, 0.1149781925191718586091000e1, 0.1085011078936665906275419e1, 0.1020240534516704208782618e1, 0.9554703680422404498752066e0, 0.8907006757608306209160649e0, 0.8259315822134856671969566e0, 0.7611632524946588128425351e0, 0.6963959112887657683892237e0, 0.6316298735371143844913976e0, 0.5668655960010826255149266e0, 0.5021037684870694065589284e0, 0.4373454855522296089897130e0, 0.3725925956833896735786860e0, 0.3078484858841616878136371e0, 0.2431200981264999375962973e0, 0.1784242126043536701754986e0, 0.1138140258514833068653307e0, 0.4958315373802413441075340e-1}, {0.1539692973716708504412697e1, 0.1477486279394502338589519e1, 0.1415279620944410339318226e1, 0.1353073023537942666830874e1, 0.1290866514321280958405103e1, 0.1228660123395079609266898e1, 0.1166453885011658611362850e1, 0.1104247839096738022319035e1, 0.1042042033248543055386770e1, 0.9798365254403234947595400e0, 0.9176313877712591840677176e0, 0.8554267118081827231209625e0, 0.7932226163976800550406599e0, 0.7310192594231560707888939e0, 0.6688168560730805146438886e0, 0.6066157082814543103941755e0, 0.5444162542389049922529553e0, 0.4822191559963931133878621e0, 0.4200254643636986308379697e0, 0.3578369542536859435571624e0, 0.2956568781922605524959448e0, 0.2334919029083292837123583e0, 0.1713581437497397360313735e0, 0.1093066902335822942650053e0, 0.4761952998197036029817629e-1}, {0.1540877753740080417345045e1, 0.1481040617373741365390254e1, 0.1421203510518656600018143e1, 0.1361366453804322852131292e1, 0.1301529469356044341206877e1, 0.1241692581525935716830402e1, 0.1181855817774264617619371e1, 0.1122019209772750368801179e1, 0.1062182794829879659341536e1, 0.1002346617783007482854908e1, 0.9425107335729934538419206e0, 0.8826752108319277463183701e0, 0.8228401370047382776784725e0, 0.7630056258499810562932058e0, 0.7031718287376427885875898e0, 0.6433389522119553277924537e0, 0.5835072863023426715977658e0, 0.5236772521416453354847559e0, 0.4638494862268433259444639e0, 0.4040249990308909882616381e0, 0.3442054975680110060507306e0, 0.2843941101955779333389742e0, 0.2245972494281051799602510e0, 0.1648304164747050021714385e0, 0.1051427544146599992432949e0, 0.4580550859172367960799915e-1}, {0.1541975588842621898865181e1, 0.1484334121018556567335167e1, 0.1426692677652358867201800e1, 0.1369051275783071487471360e1, 0.1311409933595114953831618e1, 0.1253768670970438091691833e1, 0.1196127510146226323327062e1, 0.1138486476526912406867032e1, 0.1080845599717322003702293e1, 0.1023204914871722785830020e1, 0.9655644644970043364617272e0, 0.9079243009168822510582606e0, 0.8502844897148263889326479e0, 0.7926451146568312828354346e0, 0.7350062849078710810840430e0, 0.6773681459074923011631400e0, 0.6197308962817025162722438e0, 0.5620948151095422609589585e0, 0.5044603077892199488064657e0, 0.4468279872027509013135997e0, 0.3891988265038338944044115e0, 0.3315744698431505326770711e0, 0.2739579305700525818998611e0, 0.2163553856859193758294342e0, 0.1587817673749480300092784e0, 0.1012844151694839452028589e0, 0.4412462056235422293371300e-1}, {0.1542995710582548837472073e1, 0.1487394484904746766220933e1, 0.1431793279635669382208875e1, 0.1376192108950239363921811e1, 0.1320590987909222553912422e1, 0.1264989932881031519687125e1, 0.1209388962038683919740547e1, 0.1153788095965648154683658e1, 0.1098187358416032947576489e1, 0.1042586777292402877200408e1, 0.9869863859317282394719449e0, 0.9313862248321055503829503e0, 0.8757863440192765677772914e0, 0.8201868063589761051746975e0, 0.7645876922981545448147078e0, 0.7089891068198449136125464e0, 0.6533911899285832425290628e0, 0.5977941329592257586198087e0, 0.5421982048745539015834188e0, 0.4866037965045890355211229e0, 0.4310114988353693539492225e0, 0.3754222503860499120445385e0, 0.3198376369331602148544626e0, 0.2642605649958747239907310e0, 0.2086969927688100977274751e0, 0.1531613237261629042774314e0, 0.9769922156300582041279299e-1, 0.4256272861907242306694832e-1}, {0.1543946088331101630230404e1, 0.1490245617072432741470241e1, 0.1436545162952171175361532e1, 0.1382844737841275627385236e1, 0.1329144354302189376680665e1, 0.1275444025914442882448630e1, 0.1221743767654456436125309e1, 0.1168043596353244531685999e1, 0.1114343531263457295536939e1, 0.1060643594778787047442989e1, 0.1006943813366184678568021e1, 0.9532442187977767941200107e0, 0.8995448498101763729640445e0, 0.8458457543830885615091264e0, 0.7921469929325243736682034e0, 0.7384486428849507503612470e0, 0.6847508053901545384892447e0, 0.6310536154445759741044291e0, 0.5773572576394624029563656e0, 0.5236619915567428835581025e0, 0.4699681944935857341529219e0, 0.4162764370726533962791279e0, 0.3625876255789859906927245e0, 0.3089032914359211154562848e0, 0.2552262416643531728802047e0, 0.2015622306384971766058615e0, 0.1479251692966707827334002e0, 0.9435916010280739398532997e-1, 0.4110762866287674188292735e-1}, {0.1544833637851665335244669e1, 0.1492908264756388370493025e1, 0.1440982906138650837480037e1, 0.1389057572001580364167786e1, 0.1337132272892735072773304e1, 0.1285207020157876647295968e1, 0.1233281826234298389291217e1, 0.1181356705000596722238457e1, 0.1129431672204958843918638e1, 0.1077506746001711267258715e1, 0.1025581947637229234301640e1, 0.9736573023432582093437126e0, 0.9217328405213548692702866e0, 0.8698085993416727107979968e0, 0.8178846249414537373941032e0, 0.7659609755086193214466010e0, 0.7140377257012462393241274e0, 0.6621149731355525426273686e0, 0.6101928481720243483360470e0, 0.5582715291407654489802101e0, 0.5063512668959282414914789e0, 0.4544324261262307197237056e0, 0.4025155584642650335664553e0, 0.3506015401168133792671488e0, 0.2986918517703509333332016e0, 0.2467892075469457255751440e0, 0.1948991714956708008247732e0, 0.1430351946011564171352354e0, 0.9123992133264713232350199e-1, 0.3974873026126591246235829e-1}, {0.1545664389841685834178882e1, 0.1495400520006868605194165e1, 0.1445136662469633349524466e1, 0.1394872825707861196682996e1, 0.1344609018631531661347402e1, 0.1294345250782284139500904e1, 0.1244081532562166402923175e1, 0.1193817875503760392032898e1, 0.1143554292597402872188167e1, 0.1093290798696377946301336e1, 0.1043027411028491785799717e1, 0.9927641498535133311947588e0, 0.9425010393224361375194941e0, 0.8922381086194002226900769e0, 0.8419753935054036625982058e0, 0.7917129384431112475049142e0, 0.7414507995789214800057706e0, 0.6911890490185720721582180e0, 0.6409277811053987947460976e0, 0.5906671218914768219060599e0, 0.5404072438741681591850965e0, 0.4901483897634232956856935e0, 0.4398909124691513811974471e0, 0.3896353458699818240468259e0, 0.3393825380385224469051922e0, 0.2891339221891949677776928e0, 0.2388921255071779766209942e0, 0.1886625339124777570188312e0, 0.1384581678870181657476050e0, 0.8832030722827102577102185e-1, 0.3847679847963676404657822e-1}, {0.1546443627125265521960044e1, 0.1497738231263909315513507e1, 0.1449032845902631477147772e1, 0.1400327478265391242178337e1, 0.1351622135921668846451224e1, 0.1302916826944702448727527e1, 0.1254211560091483702838765e1, 0.1205506345013417018443405e1, 0.1156801192508980685500292e1, 0.1108096114833249453312212e1, 0.1059391126084216587933501e1, 0.1010686242693213908544820e1, 0.9619814840575052973573711e0, 0.9132768733691264344256970e0, 0.8645724387181842642305406e0, 0.8158682145859558652971026e0, 0.7671642439014559105969752e0, 0.7184605809290069459742089e0, 0.6697572954095121564500879e0, 0.6210544786425143220264938e0, 0.5723522526623283741373995e0, 0.5236507845164779831804685e0, 0.4749503092950064087413842e0, 0.4262511688770346357064771e0, 0.3775538805043668894422883e0, 0.3288592658750793954850446e0, 0.2801687136893753887834348e0, 0.2314847695998852605184853e0, 0.1828126524563463299986617e0, 0.1341649789468091132459783e0, 0.8558174883654483804697753e-1, 0.3728374374031613183399036e-1}, {0.1547175997094614757138430e1, 0.1499935340679181525271649e1, 0.1452694693272706215568985e1, 0.1405454061061768876728643e1, 0.1358213450511184239883293e1, 0.1310972868490444296079765e1, 0.1263732322416537730871712e1, 0.1216491820419724046503073e1, 0.1169251371540540180758674e1, 0.1122010985968754004469355e1, 0.1074770675338453464761893e1, 0.1027530453098431393666936e1, 0.9802903349842005856557204e0, 0.9330503396284544173873149e0, 0.8858104893623263267477775e0, 0.8385708112832335506864354e0, 0.7913313387011139500976360e0, 0.7440921131314510897906335e0, 0.6968531870945337206139839e0, 0.6496146281309018959581539e0, 0.6023765246993705639765525e0, 0.5551389950762090311242875e0, 0.5079022012032895030848024e0, 0.4606663710240282967569630e0, 0.4134318360639670775957014e0, 0.3661990979414348851212686e0, 0.3189689535781378596191439e0, 0.2717427498485401725509746e0, 0.2245229557871702595200694e0, 0.1773146332323969343091350e0, 0.1301300193754780766338959e0, 0.8300791095077070533235660e-1, 0.3616244959900389221395842e-1}, {0.1547865604457777747119921e1, 0.1502004162357357213441384e1, 0.1456142728021903760325049e1, 0.1410281306774684706589738e1, 0.1364419904164498130803254e1, 0.1318558526067441138200403e1, 0.1272697178801115154796514e1, 0.1226835869256177571730448e1, 0.1180974605051351016009903e1, 0.1135113394719709026888693e1, 0.1089252247936466574864114e1, 0.1043391175801911243726755e1, 0.9975301911979639874925565e0, 0.9516693092438447484954432e0, 0.9058085478865097428655118e0, 0.8599479286766250282572181e0, 0.8140874778035996603018790e0, 0.7682272274981820559251592e0, 0.7223672179660643783333797e0, 0.6765075001043380283085699e0, 0.6306481393987597674748178e0, 0.5847892216487432573582268e0, 0.5389308616059791284685642e0, 0.4930732164176132508179420e0, 0.4472165073094733435432890e0, 0.4013610560689043520551232e0, 0.3555073496130768130758891e0, 0.3096561615434305328219637e0, 0.2638087993597793691714182e0, 0.2179676599607749036552390e0, 0.1721376573496165890967450e0, 0.1263306713881449555499955e0, 0.8058436603519718986295825e-1, 0.3510663068970053260227480e-1}, {0.1548516088202564202943238e1, 0.1503955613246577879586994e1, 0.1459395145012190281751360e1, 0.1414834688100222735099866e1, 0.1370274247295441414922756e1, 0.1325713827649021532002630e1, 0.1281153434570536124285912e1, 0.1236593073933169034954499e1, 0.1192032752196710979323473e1, 0.1147472476554108430135576e1, 0.1102912255109027578275434e1, 0.1058352097094263144928973e1, 0.1013792013144153206047048e1, 0.9692320156388929821870602e0, 0.9246721191454417746654622e0, 0.8801123409896300773149632e0, 0.8355527020087518049947413e0, 0.7909932275560464363973909e0, 0.7464339488624693592395086e0, 0.7018749049145358048463504e0, 0.6573161450929179933243905e0, 0.6127577329584494909986789e0, 0.5681997518140860838771656e0, 0.5236423130979094957496400e0, 0.4790855694444512920982626e0, 0.4345297357523596151738496e0, 0.3899751246318782591316393e0, 0.3454222091410984787772492e0, 0.3008717408917773811461237e0, 0.2563249902500918978614004e0, 0.2117842860782107775954396e0, 0.1672544029381415755198150e0, 0.1227468836419337342946123e0, 0.7829832364814667171382217e-1, 0.3411071484766340151578357e-1}, {0.1549130685823945998342524e1, 0.1505799405819664254557106e1, 0.1462468131657470292685966e1, 0.1419136867330461353369368e1, 0.1375805616982638895139986e1, 0.1332474384976155365522566e1, 0.1289143175965912901391449e1, 0.1245811994984327181800398e1, 0.1202480847539690438616688e1, 0.1159149739732435788417226e1, 0.1115818678394807971862305e1, 0.1072487671261111519215409e1, 0.1029156727178025494814510e1, 0.9858258563677261466814511e0, 0.9424950707611702085500992e0, 0.8991643844255133860018485e0, 0.8558338141192845596532563e0, 0.8125033800232146117493243e0, 0.7691731067161328174004981e0, 0.7258430244984030733808537e0, 0.6825131712172895509836733e0, 0.6391835948321685576634513e0, 0.5958543570955633038336902e0, 0.5525255389612023677479152e0, 0.5091972487450747080139606e0, 0.4658696348260689008126722e0, 0.4225429061321313393543928e0, 0.3792173666095906812269559e0, 0.3358934762285008809293807e0, 0.2925719658301625547639832e0, 0.2492540707015179370724365e0, 0.2059420554273186332219697e0, 0.1626405628266886976038507e0, 0.1193608172622853851645011e0, 0.7613840464754681957544313e-1, 0.3316974474186058622824911e-1}, {0.1549712287207882890839045e1, 0.1507544209724862511636878e1, 0.1465376137339015815734558e1, 0.1423208073529702865859582e1, 0.1381040021900765225468989e1, 0.1338871986235691269778498e1, 0.1296703970558498635765633e1, 0.1254535979202491212629656e1, 0.1212368016889500927716256e1, 0.1170200088822853513468851e1, 0.1128032200798161849314963e1, 0.1085864359337236600941540e1, 0.1043696571852037437540940e1, 0.1001528846847853898635169e1, 0.9593611941780778060127795e0, 0.9171936253674231737318512e0, 0.8750261540268988114426643e0, 0.8328587963932301252176965e0, 0.7906915720393251716472997e0, 0.7485245048233193695739358e0, 0.7063576241759074809548715e0, 0.6641909668761970070284373e0, 0.6220245795476036586681135e0, 0.5798585222396645710869275e0, 0.5376928736905555113005422e0, 0.4955277392687366749125653e0, 0.4533632633323484070376718e0, 0.4111996491651493998151895e0, 0.3690371925202636251212886e0, 0.3268763409876008462653069e0, 0.2847178057580674399826003e0, 0.2425627889274157106498810e0, 0.2004134942584602007834507e0, 0.1582744399049656648660257e0, 0.1161565488818554609430574e0, 0.7409445176394481360104851e-1, 0.3227929535095246410912398e-1}, {0.1550263480064160377720298e1, 0.1509197788083808185665328e1, 0.1468132100566875710992083e1, 0.1427066420556418463513913e1, 0.1386000751198712817289420e1, 0.1344935095788765217267069e1, 0.1303869457820298477498722e1, 0.1262803841041882838326682e1, 0.1221738249521212843639205e1, 0.1180672687719991159061894e1, 0.1139607160582508034089119e1, 0.1098541673641858946868449e1, 0.1057476233148907719560749e1, 0.1016410846230700992453501e1, 0.9753455210872527645472818e0, 0.9342802672387126698703291e0, 0.8932150958393123732306518e0, 0.8521500200807685012223049e0, 0.8110850557169691024167180e0, 0.7700202217553081279468270e0, 0.7289555413804262510029339e0, 0.6878910432074509889956044e0, 0.6468267630110350344178276e0, 0.6057627461556542068727688e0, 0.5646990510834698732732127e0, 0.5236357544389875315454201e0, 0.4825729588028297682338108e0, 0.4415108047277878179738561e0, 0.4004494901533595099830119e0, 0.3593893030723592157150581e0, 0.3183306793460978083354355e0, 0.2772743115465352362860883e0, 0.2362213703174823832436869e0, 0.1951740017836102296584907e0, 0.1541366059551230775894261e0, 0.1131198202589878992052369e0, 0.7215736988593890187079586e-1, 0.3143540438351454384152236e-1}, {0.1550786588415152297375587e1, 0.1510767112957397367780716e1, 0.1470747641421582916022579e1, 0.1430728176478592843861361e1, 0.1390708720885325111445925e1, 0.1350689277522434511387126e1, 0.1310669849435604714836514e1, 0.1270650439881648370588402e1, 0.1230631052380981613091250e1, 0.1190611690778358944744052e1, 0.1150592359314214516523625e1, 0.1110573062709576809284752e1, 0.1070553806268363352417161e1, 0.1030534596002003296175373e1, 0.9905154387828984834423913e0, 0.9504963425353941517573974e0, 0.9104773164759498161192732e0, 0.8704583714184727086854142e0, 0.8304395201669023270865304e0, 0.7904207780260519973626051e0, 0.7504021634749074983118715e0, 0.7103836990664583264642972e0, 0.6703654126486745769832673e0, 0.6303473390491956215820085e0, 0.5903295224434431765765323e0, 0.5503120197533818815098408e0, 0.5102949056413983084126817e0, 0.4702782800468414863285692e0, 0.4302622799152491769326599e0, 0.3902470981180917254123191e0, 0.3502330152869736207185960e0, 0.3102204561556976356809728e0, 0.2702100956292792195263915e0, 0.2302030745053307298726703e0, 0.1902014842102915167005070e0, 0.1502096126336221315300686e0, 0.1102378261690820867329259e0, 0.7031899075931525095025389e-1, 0.3063451333411226493032265e-1}, {0.1551283705347968314195100e1, 0.1512258463601911009913297e1, 0.1473233225313284690780287e1, 0.1434207992834186122366616e1, 0.1395182768588723275108301e1, 0.1356157555104474252423723e1, 0.1317132355046745793679891e1, 0.1278107171256650000336432e1, 0.1239082006794203284097135e1, 0.1200056864987904389011051e1, 0.1161031749492588664002624e1, 0.1122006664357811755961100e1, 0.1082981614109627397900573e1, 0.1043956603849447575483550e1, 0.1004931639374790125389322e1, 0.9659067273282460489273148e0, 0.9268818753831082867718635e0, 0.8878570924770502938457708e0, 0.8488323891094102606331406e0, 0.8098077777236123075833052e0, 0.7707832732049530424809748e0, 0.7317588935368492604710264e0, 0.6927346606780251833003950e0, 0.6537106017528970872810663e0, 0.6146867506941756306797580e0, 0.5756631505519364744300804e0, 0.5366398568077528417370132e0, 0.4976169422443344500752625e0, 0.4585945042946725387136724e0, 0.4195726764797194195007418e0, 0.3805516468579533335376469e0, 0.3415316890685593880011997e0, 0.3025132172735989410463832e0, 0.2634968895917008761291809e0, 0.2244838184598823563259898e0, 0.1854760433267094750424413e0, 0.1464777455344068532549101e0, 0.1074990339130794792907032e0, 0.6857195785426972961368108e-1, 0.2987341732561906608807860e-1}, {0.1551756721003315464043007e1, 0.1513677510435354867644006e1, 0.1475598302924814895692182e1, 0.1437519100549654116408972e1, 0.1399439905448387106945081e1, 0.1361360719846430407096351e1, 0.1323281546084682430842605e1, 0.1285202386651141609385598e1, 0.1247123244216506877361870e1, 0.1209044121674894401873626e1, 0.1170965022191058363946285e1, 0.1132885949255841486220662e1, 0.1094806906752030657845562e1, 0.1056727899033393535018723e1, 0.1018648931020478788570327e1, 0.9805700083178549567966928e0, 0.9424911373589552049711100e0, 0.9044123255867553868253384e0, 0.8663335816813894348633149e0, 0.8282549158498738099497389e0, 0.7901763401989443875774432e0, 0.7520978692204962458482329e0, 0.7140195204316730003387055e0, 0.6759413152305656820841666e0, 0.6378632800575392064866756e0, 0.5997854479978337579981629e0, 0.5617078610344953281799357e0, 0.5236305732820186728652802e0, 0.4855536557378012985520074e0, 0.4474772034530068342865487e0, 0.4094013466928584958758982e0, 0.3713262689388439070717808e0, 0.3332522371792479009733062e0, 0.2951796555193184134657530e0, 0.2571091661074227554417865e0, 0.2190418543971735546480404e0, 0.1809797103814301725822348e0, 0.1429268140230164119614409e0, 0.1048930290780323497410212e0, 0.6690962797843649866645769e-1, 0.2914922224685900914817542e-1}, {0.1552207346590136182648920e1, 0.1515029387081184115266415e1, 0.1477851430283927973458023e1, 0.1440673478039699629370259e1, 0.1403495532240969264030648e1, 0.1366317594853508812224152e1, 0.1329139667940348087929429e1, 0.1291961753688162615428688e1, 0.1254783854436838464182091e1, 0.1217605972713102930414639e1, 0.1180428111269300876868432e1, 0.1143250273128649048802100e1, 0.1106072461638634327789036e1, 0.1068894680534663975270023e1, 0.1031716934016664760314029e1, 0.9945392268421176498894610e0, 0.9573615644400829018748874e0, 0.9201839530522288586731642e0, 0.8830063999088902711516820e0, 0.8458289134509915302518266e0, 0.8086515036126424512848147e0, 0.7714741821849085841225787e0, 0.7342969632895448309937051e0, 0.6971198640037406540069491e0, 0.6599429051953912854163132e0, 0.6227661126567800124770610e0, 0.5855895186691062254659102e0, 0.5484131642019636734351025e0, 0.5112371020703309674589504e0, 0.4740614015734592960802666e0, 0.4368861554959151187817336e0, 0.3997114910036376358365916e0, 0.3625375872199777754435892e0, 0.3253647047992267079974806e0, 0.2881932382678453273830096e0, 0.2510238145617968753500674e0, 0.2138574934303919974438356e0, 0.1766962177535783269128215e0, 0.1395439709154010255199071e0, 0.1024103832005221866954023e0, 0.6532598686141261097119747e-1, 0.2845930797694291389393445e-1}, {0.1552637135069155811491072e1, 0.1516318752418798211357541e1, 0.1480000372180291690418989e1, 0.1443681995989991700140976e1, 0.1407363625527612735973164e1, 0.1371045262534953065860219e1, 0.1334726908836065747097909e1, 0.1298408566359386697763653e1, 0.1262090237162411913706886e1, 0.1225771923459625279363960e1, 0.1189453627654523146514386e1, 0.1153135352376772077918208e1, 0.1116817100525785826106551e1, 0.1080498875322336017099434e1, 0.1044180680370244915946738e1, 0.1007862519730785566833872e1, 0.9715443980131875264637689e0, 0.9352263204856910439167915e0, 0.8989082932130182550456316e0, 0.8625903232280967802521182e0, 0.8262724187486163930514201e0, 0.7899545894528804342126058e0, 0.7536368468349768085155075e0, 0.7173192046673890278545072e0, 0.6810016796111441673128480e0, 0.6446842920316340773745262e0, 0.6083670671059611518530899e0, 0.5720500363511797523369558e0, 0.5357332397728172506411618e0, 0.4994167289487775362163415e0, 0.4631005715608865274454686e0, 0.4267848582339839676363509e0, 0.3904697131799790288672503e0, 0.3541553113674441557740819e0, 0.3178419074113077198829473e0, 0.2815298867038369044519273e0, 0.2452198616736214006194288e0, 0.2089128675558041239775998e0, 0.1726108022974787183994402e0, 0.1363175571713249458600521e0, 0.1000425397881322914313825e0, 0.6381557644960651200944222e-1, 0.2780129671121636039734655e-1}, {0.1553047499032218401181962e1, 0.1517549844221432542461907e1, 0.1482052191561582448658478e1, 0.1446554542510861055782865e1, 0.1411056898564365493121105e1, 0.1375559261269981001734724e1, 0.1340061632245437638964436e1, 0.1304564013196950335363525e1, 0.1269066405939915513649123e1, 0.1233568812422221364483924e1, 0.1198071234750839346739124e1, 0.1162573675222508872274463e1, 0.1127076136359515473862368e1, 0.1091578620951808778363231e1, 0.1056081132107029235444226e1, 0.1020583673310438024843461e1, 0.9850862484973095869616622e0, 0.9495888621411026369897815e0, 0.9140915193617473526041913e0, 0.8785942260597805964360395e0, 0.8430969890839839780181254e0, 0.8075998164428632814935249e0, 0.7721027175741014967901450e0, 0.7366057036915554827257553e0, 0.7011087882372792641869964e0, 0.6656119874777629720186974e0, 0.6301153213012084608241887e0, 0.5946188142997514629085459e0, 0.5591224972630766104664894e0, 0.5236264092783024624074546e0, 0.4881306007441175888503326e0, 0.4526351377998500905914452e0, 0.4171401090099414677462070e0, 0.3816456357674021470057899e0, 0.3461518890753412856675063e0, 0.3106591177837409768492156e0, 0.2751676985649013361686770e0, 0.2396782299970584002479842e0, 0.2041917239104339765549482e0, 0.1687100353513348647833163e0, 0.1332369676454340307348264e0, 0.9778171579501174586520881e-1, 0.6237343205901608270979365e-1, 0.2717302558182235133513210e-1}, {0.1553439726211153891540573e1, 0.1518726525682668668950427e1, 0.1484013327077361052080319e1, 0.1449300131698066374929113e1, 0.1414586940879145218883617e1, 0.1379873756000009717714844e1, 0.1345160578499605494109603e1, 0.1310447409892181029407508e1, 0.1275734251784724823396464e1, 0.1241021105896515467487132e1, 0.1206307974081314658309029e1, 0.1171594858352843571506531e1, 0.1136881760914326165420300e1, 0.1102168684193068774494217e1, 0.1067455630881287279906518e1, 0.1032742603984709761582283e1, 0.9980296068808995413713835e0, 0.9633166433897968474836258e0, 0.9286037178597176902839922e0, 0.8938908352730483454962679e0, 0.8591780013772376740585140e0, 0.8244652228485703565016715e0, 0.7897525074988288740747291e0, 0.7550398645386622329842600e0, 0.7203273049167972965433221e0, 0.6856148417619669061621766e0, 0.6509024909658764678789680e0, 0.6161902719627732109904446e0, 0.5814782087876726421060849e0, 0.5467663315368932859708410e0, 0.5120546784214694424751802e0, 0.4773432987146161851453875e0, 0.4426322570828636775769209e0, 0.4079216401227574252826633e0, 0.3732115665343573673240355e0, 0.3385022035318641142927744e0, 0.3037937944563405612019789e0, 0.2690867076466992914990193e0, 0.2343815284441088285495466e0, 0.1996792463094099012688324e0, 0.1649816752853099621072722e0, 0.1302925346385956500837770e0, 0.9562081616094948269905207e-1, 0.6099502786102040135198395e-1, 0.2657252290854776665952679e-1}, {0.1553814992974904767594241e1, 0.1519852325907741898557817e1, 0.1485889660564341242674032e1, 0.1451926998111647785152899e1, 0.1417964339743630985906479e1, 0.1384001686692845945859686e1, 0.1350039040242776872946770e1, 0.1316076401741232369348729e1, 0.1282113772615099921371445e1, 0.1248151154386817288949698e1, 0.1214188548692984168143550e1, 0.1180225957305622474388020e1, 0.1146263382156703179022046e1, 0.1112300825366698998613230e1, 0.1078338289278105103916832e1, 0.1044375776495107627552926e1, 0.1010413289930890288650173e1, 0.9764508328644780886953041e0, 0.9424884090095589354132202e0, 0.9085260225984488659490189e0, 0.8745636784853451215455853e0, 0.8406013822743460048537475e0, 0.8066391404795569177534715e0, 0.7726769607271702244889884e0, 0.7387148520130367387469271e0, 0.7047528250344497011443004e0, 0.6707908926224332706815892e0, 0.6368290703120276715090693e0, 0.6028673771049329733376093e0, 0.5689058365047911420524623e0, 0.5349444779460832748774921e0, 0.5009833388030907720537138e0, 0.4670224672735823328060142e0, 0.4330619266162571710985599e0, 0.3991018015460700850326972e0, 0.3651422081877256344485503e0, 0.3311833101314466311103548e0, 0.2972253454486352538763297e0, 0.2632686745061683534910424e0, 0.2293138699815081215985284e0, 0.1953618999343470689252174e0, 0.1614145391777897730914718e0, 0.1274754265555317105245073e0, 0.9355335943686297111639257e-1, 0.5967622944002585907962555e-1, 0.2599798753052849047032580e-1}, {0.1554174376112911655131098e1, 0.1520930475263640362170511e1, 0.1487686575963027013435604e1, 0.1454442679258803180913942e1, 0.1421198786221944168258440e1, 0.1387954897956585365296993e1, 0.1354711015610581847809736e1, 0.1321467140386931222410853e1, 0.1288223273556309404505081e1, 0.1254979416471008337267759e1, 0.1221735570580615776412743e1, 0.1188491737449843097435062e1, 0.1155247918778991542491874e1, 0.1122004116427655660730083e1, 0.1088760332442401967089102e1, 0.1055516569089340593777585e1, 0.1022272828892740925095715e1, 0.9890291146811467076264609e0, 0.9557854296428465678959260e0, 0.9225417773930866874628226e0, 0.8892981620561221868061383e0, 0.8560545883661619186153440e0, 0.8228110617925680415850631e0, 0.7895675886964734656602191e0, 0.7563241765284943282959446e0, 0.7230808340807681383862155e0, 0.6898375718116413059811978e0, 0.6565944022687408111136058e0, 0.6233513406471279431598408e0, 0.5901084055357449335782332e0, 0.5568656199307345199294838e0, 0.5236230126340485109018232e0, 0.4903806202198476810807501e0, 0.4571384898571183050552302e0, 0.4238966834573972483152713e0, 0.3906552839347125500730013e0, 0.3574144049483910279156003e0, 0.3241742066189948531421192e0, 0.2909349219721993995636414e0, 0.2576969037411283384416169e0, 0.2244607124763750082606152e0, 0.1912272957431274569912962e0, 0.1579983907861406744991899e0, 0.1247775594308675650267811e0, 0.9157341285433675818728635e-1, 0.5841325237532701385812948e-1, 0.2544777076240816313972829e-1}, {0.1554518863153354618809409e1, 0.1521963936333782670214978e1, 0.1489409010908686292228052e1, 0.1456854087820918568482631e1, 0.1424299168033388494075931e1, 0.1391744252537595165009714e1, 0.1359189342362693116905575e1, 0.1326634438585269225516707e1, 0.1294079542340034988016159e1, 0.1261524654831668904330407e1, 0.1228969777348083696352705e1, 0.1196414911275444418157033e1, 0.1163860058115329026827193e1, 0.1131305219504506571098859e1, 0.1098750397237914982841550e1, 0.1066195593295557461150055e1, 0.1033640809874212986016967e1, 0.1001086049425085324651032e1, 0.9685313146988134601280153e0, 0.9359766087996588330547245e0, 0.9034219352512048766203636e0, 0.8708672980765996496647291e0, 0.8383127018973108640833295e0, 0.8057581520556423644789438e0, 0.7732036547680256450048242e0, 0.7406492173185620802637676e0, 0.7080948483057714882525616e0, 0.6755405579604902654406567e0, 0.6429863585601198571817691e0, 0.6104322649751623629236805e0, 0.5778782954001507969801437e0, 0.5453244723459250134170285e0, 0.5127708240092147734858477e0, 0.4802173861982495342372455e0, 0.4476642050968422792532389e0, 0.4151113413261211455132671e0, 0.3825588760747025757978563e0, 0.3500069206395502661556462e0, 0.3174556318161704671189642e0, 0.2849052377944113082878058e0, 0.2523560839907875626097181e0, 0.2198087193323827316322426e0, 0.1872640717400572601243546e0, 0.1547238424480887172335593e0, 0.1221915194567498709631299e0, 0.8967553546914315204781840e-1, 0.5720262597323678474637133e-1, 0.2492036059421555107245208e-1}, {0.1554849361424470843090118e1, 0.1522955431101933730645303e1, 0.1491061502037751976297424e1, 0.1459167575082261894770634e1, 0.1427273651103158170602525e1, 0.1395379730992862183093282e1, 0.1363485815676330697886480e1, 0.1331591906119453530640248e1, 0.1299698003338207337770238e1, 0.1267804108408757103237650e1, 0.1235910222478728395590872e1, 0.1204016346779913703159712e1, 0.1172122482642727288439229e1, 0.1140228631512787910483320e1, 0.1108334794970091261912531e1, 0.1076440974751339138680154e1, 0.1044547172776127017814204e1, 0.1012653391177865049408482e1, 0.9807596323405319627306720e0, 0.9488658989426541583823449e0, 0.9169721940102869797082899e0, 0.8850785209812848825432963e0, 0.8531848837838285971960304e0, 0.8212912869330969580404013e0, 0.7893977356512249782795147e0, 0.7575042360174185552669765e0, 0.7256107951575083863622461e0, 0.6937174214856350398887716e0, 0.6618241250156435481462849e0, 0.6299309177668761147121611e0, 0.5980378142995696297245189e0, 0.5661448324309071185385071e0, 0.5342519942071113461815355e0, 0.5023593272451872220760104e0, 0.4704668666194035162003700e0, 0.4385746575692260390945883e0, 0.4066827594785525726660483e0, 0.3747912518813925812276922e0, 0.3429002438089823350625543e0, 0.3110098888674705209106637e0, 0.2791204106078991711912441e0, 0.2472321474279120600810915e0, 0.2153456371036966567922014e0, 0.1834617887100953140198272e0, 0.1515822689338083535939382e0, 0.1197104949484175660714864e0, 0.8785472823121690639967810e-1, 0.5604116141749524467628553e-1, 0.2441436781606819510490200e-1}, {0.1555166706034023842787706e1, 0.1523907464890582273398300e1, 0.1492648224885016483409279e1, 0.1461388986785839210767990e1, 0.1430129751376631035251350e1, 0.1398870519462421720845393e1, 0.1367611291876438076975682e1, 0.1336352069487341263827064e1, 0.1305092853207091240256110e1, 0.1273833643999595441027728e1, 0.1242574442890323705495464e1, 0.1211315250977103200801981e1, 0.1180056069442347222927677e1, 0.1148796899567022469820701e1, 0.1117537742746723499546780e1, 0.1086278600510304367969825e1, 0.1055019474541620880304106e1, 0.1023760366705069175705639e1, 0.9925012790757765081567637e0, 0.9612422139755203374385844e0, 0.9299831740157389822411293e0, 0.8987241621493743180375722e0, 0.8674651817337867269827651e0, 0.8362062366076504452859926e0, 0.8049473311856388413561914e0, 0.7736884705759381993127359e0, 0.7424296607273230664538510e0, 0.7111709086148904840060001e0, 0.6799122224768919982385331e0, 0.6486536121198915829209739e0, 0.6173950893164463798129595e0, 0.5861366683298159921278400e0, 0.5548783666157332634604655e0, 0.5236202057751242467455922e0, 0.4923622128691229579358494e0, 0.4611044222679868504944176e0, 0.4298468783051183048132298e0, 0.3985896391770900735176252e0, 0.3673327828297899556279530e0, 0.3360764161195064368209114e0, 0.3048206895905456571224703e0, 0.2735658223403245791263072e0, 0.2423121460275046288225596e0, 0.2110601877217048587999889e0, 0.1798108384023314561549010e0, 0.1485657315840060835766576e0, 0.1173282164330337207824850e0, 0.8610639001623934211634967e-1, 0.5492592372249737419414775e-1, 0.2392851379957687254895331e-1}, } var oddThetaZeros = [][]float64{ {0.6847192030022829138880982e0}, {0.1002176803643121641749915e1, 0.4366349492255221620374655e0}, {0.1152892953722227341986065e1, 0.7354466143229520469385622e0, 0.3204050902900619825355950e0}, {0.1240573923404363422789550e1, 0.9104740292261473250358755e0, 0.5807869795060065580284919e0, 0.2530224166119306882187233e0}, {0.1297877729331450368298142e1, 0.1025003226369574843297844e1, 0.7522519395990821317003373e0, 0.4798534223256743217333579e0, 0.2090492874137409414071522e0}, {0.1338247676100454369194835e1, 0.1105718066248490075175419e1, 0.8732366099401630367220948e0, 0.6408663264733867770811230e0, 0.4088002373420211722955679e0, 0.1780944581262765470585931e0}, {0.1368219536992351783359098e1, 0.1165652065603030148723847e1, 0.9631067821301481995711685e0, 0.7606069572889918619145483e0, 0.5582062109125313357140248e0, 0.3560718303314725022788878e0, 0.1551231069747375098418591e0}, {0.1391350647015287461874435e1, 0.1211909966211469688151240e1, 0.1032480728417239563449772e1, 0.8530732514258505686069670e0, 0.6737074594242522259878462e0, 0.4944303818194983217354808e0, 0.3153898594929282395996014e0, 0.1373998952992547671039022e0}, {0.1409742336767428999667236e1, 0.1248691224331339221187704e1, 0.1087646521650454938943641e1, 0.9266134127998189551499083e0, 0.7656007620508340547558669e0, 0.6046261769405451549818494e0, 0.4437316659960951760051408e0, 0.2830497588453068048261493e0, 0.1233108673082312764916251e0}, {0.1424715475176742734932665e1, 0.1278636375242898727771561e1, 0.1132561101012537613667002e1, 0.9864925055883793730483278e0, 0.8404350520135058972624775e0, 0.6943966110110701016065380e0, 0.5483930281810389839680525e0, 0.4024623099018152227701990e0, 0.2567245837448891192759858e0, 0.1118422651428890834760883e0}, {0.1437141935303526306632113e1, 0.1303488659735581140681362e1, 0.1169837785762829821262819e1, 0.1036190996404462300207004e1, 0.9025507517347875930425807e0, 0.7689210263823624893974324e0, 0.6353089402976822861185532e0, 0.5017289283414202278167583e0, 0.3682157131008289798868520e0, 0.2348791589702580223688923e0, 0.1023252788872632487579640e0}, {0.1447620393135667144403507e1, 0.1324445197736386798102445e1, 0.1201271573324181312770120e1, 0.1078100568411879956441542e1, 0.9549336362382321811515336e0, 0.8317729718814276781352878e0, 0.7086221837538611370849622e0, 0.5854877911108011727748238e0, 0.4623830630132757357909198e0, 0.3393399712563371486343129e0, 0.2164597408964339264361902e0, 0.9430083986305519349231898e-1}, {0.1456575541704195839944967e1, 0.1342355260834552126304154e1, 0.1228136043468909663499174e1, 0.1113918572282611841378549e1, 0.9997037539874953933323299e0, 0.8854928869950799998575862e0, 0.7712879690777516856072467e0, 0.6570923167092416238233585e0, 0.5429119513798658239789812e0, 0.4287591577660783587509129e0, 0.3146635662674373982102762e0, 0.2007190266590380629766487e0, 0.8744338280630300217927750e-1}, {0.1464317002991565219979113e1, 0.1357838033080061766980173e1, 0.1251359804334884770836945e1, 0.1144882777708662655968171e1, 0.1038407544520296695714932e1, 0.9319349156915986836657782e0, 0.8254660749671546663859351e0, 0.7190028636037068047812305e0, 0.6125483562383020473196681e0, 0.5061081521562999836102547e0, 0.3996936914666951732317457e0, 0.2933325857619472952507468e0, 0.1871123137498061864373407e0, 0.8151560650977882057817999e-1}, {0.1471075823713997440657641e1, 0.1371355574944658989649887e1, 0.1271635855736122280723838e1, 0.1171916986981363820797100e1, 0.1072199368669106404814915e1, 0.9724835301003496870596165e0, 0.8727702114891848603047954e0, 0.7730605060747958359120755e0, 0.6733561257504194406005404e0, 0.5736599396529727772420934e0, 0.4739771829190733570809765e0, 0.3743185619229329461021810e0, 0.2747099287638327553949437e0, 0.1752332025619508475799133e0, 0.7634046205384429302353073e-1}, {0.1477027911291552393547878e1, 0.1383259682348271685979143e1, 0.1289491840051302622319481e1, 0.1195724613675799550484673e1, 0.1101958282220461402990667e1, 0.1008193204014774090964219e1, 0.9144298626454031699590564e0, 0.8206689427646120483710056e0, 0.7269114630504563073034288e0, 0.6331590254855162126233733e0, 0.5394143214244183829842424e0, 0.4456822679082866369288652e0, 0.3519729273095236644049666e0, 0.2583106041071417718760275e0, 0.1647723231643112502628240e0, 0.7178317184275122449502857e-1}, {0.1482309554825692463999299e1, 0.1393822922226542123661077e1, 0.1305336577335833571381699e1, 0.1216850687682353365944624e1, 0.1128365453024608460982204e1, 0.1039881123511957522668140e1, 0.9513980267579228357946521e0, 0.8629166105524045911461307e0, 0.7744375139383604902604254e0, 0.6859616923374368587817328e0, 0.5974906525247623278123711e0, 0.5090269299866796725116786e0, 0.4205751610647263669405267e0, 0.3321448379994943116084719e0, 0.2437588931448048912587688e0, 0.1554900095178924564386865e0, 0.6773932498157585698088354e-1}, {0.1487027983239550912222135e1, 0.1403259745496922270264564e1, 0.1319491725464661433609663e1, 0.1235724047968681189212364e1, 0.1151956859289811446164825e1, 0.1068190338689553494802072e1, 0.9844247150109837231349622e0, 0.9006602918737365182850484e0, 0.8168974877846821404275069e0, 0.7331369031796229223580227e0, 0.6493794386888650054486281e0, 0.5656265174356596757139537e0, 0.4818805368222631487731579e0, 0.3981458834052590173509113e0, 0.3144315409387123154212535e0, 0.2307592167302372059759857e0, 0.1471977156945989772472748e0, 0.6412678117309944052403703e-1}, {0.1491268718102344688271411e1, 0.1411741190914640487505771e1, 0.1332213830951015404441941e1, 0.1252686732830809999680267e1, 0.1173160005794509313174730e1, 0.1093633781237958896879965e1, 0.1014108223243148393065201e1, 0.9345835440325075907377330e0, 0.8550600276575269107773349e0, 0.7755380679025248517258532e0, 0.6960182317959841585145109e0, 0.6165013717819833504477346e0, 0.5369888366794912945318079e0, 0.4574829005269902932408889e0, 0.3779877260196973978940863e0, 0.2985118404618624984946326e0, 0.2190758506462427957069113e0, 0.1397450765119767349146353e0, 0.6088003363863534825005464e-1}, {0.1495100801651051409999732e1, 0.1419405340110198552778393e1, 0.1343710008748627892724810e1, 0.1268014880389353000310414e1, 0.1192320038028903827079750e1, 0.1116625579891689469044026e1, 0.1040931626310454794079799e1, 0.9652383295306942866661884e0, 0.8895458882533946571137358e0, 0.8138545700535261740447950e0, 0.7381647473570304814395029e0, 0.6624769578126105498149624e0, 0.5867920109947446493391737e0, 0.5111111891461744489290992e0, 0.4354366553151050147918632e0, 0.3597723703299625354660452e0, 0.2841264494060559943920389e0, 0.2085185052177154996230005e0, 0.1330107089065635461375419e0, 0.5794620170990797798650123e-1}, {0.1498580583401444174317386e1, 0.1426364890228584522673414e1, 0.1354149299629923281192036e1, 0.1281933868420423988034246e1, 0.1209718660626713399048551e1, 0.1137503750956414845248481e1, 0.1065289229411733880607916e1, 0.9930752076949068878557126e0, 0.9208618284397049456535757e0, 0.8486492789905562098591586e0, 0.7764378127156926158031943e0, 0.7042277832708635930867344e0, 0.6320197021480767602848178e0, 0.5598143404345395912377042e0, 0.4876129202946139420188428e0, 0.4154175043169533365541148e0, 0.3432318703096418027524597e0, 0.2710637595435203246492797e0, 0.1989318822110657561806962e0, 0.1268955503926593166308254e0, 0.5528212871240371048241379e-1}, {0.1501754508594837337089856e1, 0.1432712730475143340404518e1, 0.1363671034069754274950592e1, 0.1294629464249430679064317e1, 0.1225588071083248538559259e1, 0.1156546912269029268686830e1, 0.1087506056298747798071893e1, 0.1018465586752840651469411e1, 0.9494256083335850798964741e0, 0.8803862556198167553278643e0, 0.8113477061841624760598814e0, 0.7423102009244498727845341e0, 0.6732740767851639064676858e0, 0.6042398217472142478598295e0, 0.5352081720899522889584566e0, 0.4661802954366277026594659e0, 0.3971581629712621730826920e0, 0.3281453857685808451825081e0, 0.2591493642052661979197670e0, 0.1901879854885491785792565e0, 0.1213179541186130699071317e0, 0.5285224511635143601147552e-1}, {0.1504661202517196460191540e1, 0.1438526110541037227495230e1, 0.1372391084315255737540026e1, 0.1306256159670931796771616e1, 0.1240121376243315949825014e1, 0.1173986779205849344923421e1, 0.1107852421486856229076325e1, 0.1041718366715156747157745e1, 0.9755846932657442605621389e0, 0.9094514999854931965227238e0, 0.8433189145364798253029042e0, 0.7771871059265138564989363e0, 0.7110563039566125173946002e0, 0.6449268305419475123120585e0, 0.5787991523675322133651034e0, 0.5126739740395088296453592e0, 0.4465524134105889084933393e0, 0.3804363581140941600870992e0, 0.3143292666717729726674543e0, 0.2482382273986418438740754e0, 0.1821803739336923550363257e0, 0.1162100228791666307841708e0, 0.5062697144246344520692308e-1}, {0.1507333049739684406957329e1, 0.1443869798951040686809862e1, 0.1380406601553595646811530e1, 0.1316943486448336467960940e1, 0.1253480485358734060913055e1, 0.1190017634088428795118215e1, 0.1126554974102287077081806e1, 0.1063092554588577221978254e1, 0.9996304352342330000643921e0, 0.9361686900661624628632729e0, 0.8727074129127595264965883e0, 0.8092467253835331800652228e0, 0.7457867888716805068068402e0, 0.6823278231980088937854296e0, 0.6188701366516795329577182e0, 0.5554141765061554178407906e0, 0.4919606183965743300387332e0, 0.4285105345527885639657014e0, 0.3650657359209552112046854e0, 0.3016295408979540017854803e0, 0.2382087510453128743250072e0, 0.1748198074104535338147956e0, 0.1115148317291502081079519e0, 0.4858150828905663931389750e-1}, {0.1509797405521643600800862e1, 0.1448798505784201776188819e1, 0.1387799649767640868379247e1, 0.1326800860997572277878513e1, 0.1265802165120213614545418e1, 0.1204803590828283748583827e1, 0.1143805171007496028164312e1, 0.1082806944206958485218487e1, 0.1021808956582037259849130e1, 0.9608112645303606832220554e0, 0.8998139383584991342974664e0, 0.8388170675106567024157190e0, 0.7778207682214244793380700e0, 0.7168251950382156442798800e0, 0.6558305587295081487906238e0, 0.5948371551492265376377962e0, 0.5338454137827292925154468e0, 0.4728559836463229599006206e0, 0.4118698949811841042358258e0, 0.3508888880839026413717319e0, 0.2899161521835467942607342e0, 0.2289582244272697168835150e0, 0.1680309071251709912058722e0, 0.1071842976730454709494914e0, 0.4669490825917857848258897e-1}, {0.1512077535592702651885542e1, 0.1453358762182399391553360e1, 0.1394640024852448295479492e1, 0.1335921342914185177270306e1, 0.1277202737290683500323248e1, 0.1218484231207691826029908e1, 0.1159765851037557179133987e1, 0.1101047627365156083369632e1, 0.1042329596373083545617043e1, 0.9836118016874520301049009e0, 0.9248942968954766185908511e0, 0.8661771490588063053774554e0, 0.8074604437333368789787031e0, 0.7487442923247565105494255e0, 0.6900288431709550365296138e0, 0.6313142987730108226833704e0, 0.5726009435739572428629866e0, 0.5138891906843943809444838e0, 0.4551796645660731149033106e0, 0.3964733566771858874923011e0, 0.3377719420068963817561906e0, 0.2790784903284342592940125e0, 0.2203992941938221111139898e0, 0.1617495649772923108686624e0, 0.1031775271253784724197264e0, 0.4494935602951385601335598e-1}, {0.1514193352804819997509006e1, 0.1457590393617468793209691e1, 0.1400987464419153080392546e1, 0.1344384581184662080889348e1, 0.1287781761126833878758488e1, 0.1231179023218584237510462e1, 0.1174576388822640925688125e1, 0.1117973882475943676285829e1, 0.1061371532893653466992815e1, 0.1004769374285310770780417e1, 0.9481674481184788854172919e0, 0.8915658055327279211293483e0, 0.8349645107156934027761499e0, 0.7783636457331086848148917e0, 0.7217633176118399859733190e0, 0.6651636690166557413471029e0, 0.6085648948549621671933311e0, 0.5519672690500084950513985e0, 0.4953711895788266953367288e0, 0.4387772581729219934583483e0, 0.3821864303519236078766179e0, 0.3256003205491779498477363e0, 0.2690218877324958059454348e0, 0.2124571975249336244841297e0, 0.1559209129891515317090843e0, 0.9945952063842375053227931e-1, 0.4332960406341033436157524e-1}, {0.1516162000094549207021851e1, 0.1461527685790782385188426e1, 0.1406893396579229558427657e1, 0.1352259145769086826235918e1, 0.1297624947629923059740243e1, 0.1242990817790597917328601e1, 0.1188356773715062198539162e1, 0.1133722835287525783953663e1, 0.1079089025551156002698850e1, 0.1024455371662101389801169e1, 0.9698219061474760364582928e0, 0.9151886685974009713577537e0, 0.8605557079864861100238346e0, 0.8059230859253162466918892e0, 0.7512908813164713594661588e0, 0.6966591971861112012613682e0, 0.6420281709850565965229799e0, 0.5873979906122764301937499e0, 0.5327689202536826556885353e0, 0.4781413438508069051295597e0, 0.4235158420269503798571552e0, 0.3688933369002844229314675e0, 0.3142753865947702189467806e0, 0.2596648470121556361200229e0, 0.2050675726616484232653526e0, 0.1504977164639767777858359e0, 0.9600014792058154736462106e-1, 0.4182252607645932321862773e-1}, {0.1517998315905975681819213e1, 0.1465200315462026532129551e1, 0.1412402336143180968579639e1, 0.1359604389111228213837104e1, 0.1306806486279734731351497e1, 0.1254008640622089183072742e1, 0.1201210866535131048800458e1, 0.1148413180281179970113571e1, 0.1095615600538999408768381e1, 0.1042818149105710558651372e1, 0.9900208518088600875617620e0, 0.9372237397138955502862203e0, 0.8844268507524555199840381e0, 0.8316302319600398731649744e0, 0.7788339426133210890795576e0, 0.7260380587255163256281298e0, 0.6732426796448045921910045e0, 0.6204479380061240544867289e0, 0.5676540152134466427854705e0, 0.5148611664077887834613451e0, 0.4620697624728053757183766e0, 0.4092803643735033357684553e0, 0.3564938631002461237979451e0, 0.3037117642790043703921396e0, 0.2509368276982060978106092e0, 0.1981747109679032915697317e0, 0.1454390911823840643137232e0, 0.9277332955453467429763451e-1, 0.4041676055113025684436480e-1}, {0.1519715208823086817411929e1, 0.1468634099702062550682430e1, 0.1417553008469014674939490e1, 0.1366471944542347269659860e1, 0.1315390917933946912760115e1, 0.1264309939489363760018555e1, 0.1213229021168654147755139e1, 0.1162148176384137345494752e1, 0.1111067420416500738111992e1, 0.1059986770938296676746064e1, 0.1008906248685091746434581e1, 0.9578258783312407255956784e0, 0.9067456896525242756445150e0, 0.8556657190967860708153477e0, 0.8045860119448479090873824e0, 0.7535066253423996943740445e0, 0.7024276326462752642452137e0, 0.6513491298057893513225544e0, 0.6002712449887427739045163e0, 0.5491941535583390603837715e0, 0.4981181022276018128369963e0, 0.4470434496975185070560821e0, 0.3959707385770101868486847e0, 0.3449008307748737032772825e0, 0.2938351828535981363494671e0, 0.2427764647581323719392653e0, 0.1917301500230701193408602e0, 0.1407094708800750523796875e0, 0.8975637836633630394302762e-1, 0.3910242380354419363081899e-1}, {0.1521323961422700444944464e1, 0.1471851603590422118622546e1, 0.1422379260986849454727777e1, 0.1372906941604798453293218e1, 0.1323434653909307929892118e1, 0.1273962407026590487708892e1, 0.1224490210963055761921526e1, 0.1175018076866133593082748e1, 0.1125546017342156230227131e1, 0.1076074046851682267877939e1, 0.1026602182210094558879809e1, 0.9771304432322302018639612e0, 0.9276588535760335871906045e0, 0.8781874418647315968408864e0, 0.8287162432047307488040550e0, 0.7792453012756761070555010e0, 0.7297746712644485550469075e0, 0.6803044240724808212528033e0, 0.6308346524943159683026367e0, 0.5813654805388740483542438e0, 0.5318970779332963132260134e0, 0.4824296835154055410257004e0, 0.4329636445908698102350729e0, 0.3834994865870752458854056e0, 0.3340380441799942088370002e0, 0.2845807279748544733570760e0, 0.2351301237470960623526672e0, 0.1856915325646991222655151e0, 0.1362777698319134965765757e0, 0.8692946525012054120187353e-1, 0.3787087726949234365520114e-1}, {0.1522834478472358672931947e1, 0.1474872636605138418026177e1, 0.1426910807768284322082436e1, 0.1378948998781055367310047e1, 0.1330987216841224680164684e1, 0.1283025469674968454386883e1, 0.1235063765709222885799986e1, 0.1187102114275073728898860e1, 0.1139140525853183114841234e1, 0.1091179012375759666645271e1, 0.1043217587604604879578741e1, 0.9952562676120370548458597e0, 0.9472950714021223337048082e0, 0.8993340217254078241758816e0, 0.8513731461641338285808219e0, 0.8034124786014693431693904e0, 0.7554520612457602368887930e0, 0.7074919474732165281510693e0, 0.6595322059052657580628641e0, 0.6115729263971504325174172e0, 0.5636142290734363894767612e0, 0.5156562783879918167717991e0, 0.4676993058012953469089537e0, 0.4197436479350834076514896e0, 0.3717898140987174444032373e0, 0.3238386134116156886828960e0, 0.2758914133405791810724762e0, 0.2279507206431424610498769e0, 0.1800216744637006612298520e0, 0.1321166988439841543825694e0, 0.8427518284958235696897899e-1, 0.3671453742186897322954009e-1}, {0.1524255491013576804195881e1, 0.1477714660784952783237945e1, 0.1431173841758652772349485e1, 0.1384633039781787069436630e1, 0.1338092261006965672253841e1, 0.1291551512012124788593875e1, 0.1245010799937299944123195e1, 0.1198470132644670409416924e1, 0.1151929518909907204916554e1, 0.1105388968655282680015213e1, 0.1058848493238442193822372e1, 0.1012308105815651361079674e1, 0.9657678218054126734684090e0, 0.9192276594886802366068293e0, 0.8726876407972167893294764e0, 0.8261477923647281669131478e0, 0.7796081469509049827753598e0, 0.7330687454042532567721262e0, 0.6865296394193009886613469e0, 0.6399908954920466591029822e0, 0.5934526007301573325059582e0, 0.5469148716199143611697357e0, 0.5003778676688561814362271e0, 0.4538418134105091550464446e0, 0.4073070354279485829740435e0, 0.3607740278788822846227453e0, 0.3142435758510728338330843e0, 0.2677170062389944640113953e0, 0.2211967514739567668334169e0, 0.1746877983807874325844051e0, 0.1282022028383479964348629e0, 0.8177818680168764430245080e-1, 0.3562671947817428176226631e-1}, {0.1525594725214770881206476e1, 0.1480393128432045740356817e1, 0.1435191541323085582529217e1, 0.1389989968924959812091252e1, 0.1344788416522907866060817e1, 0.1299586889746827997174554e1, 0.1254385394680661996389736e1, 0.1209183937989395175829969e1, 0.1163982527069600127515982e1, 0.1118781170231154762473596e1, 0.1073579876920155012130433e1, 0.1028378657996412636748477e1, 0.9831775260837211038023103e0, 0.9379764960179657076015136e0, 0.8927755854282048597997986e0, 0.8475748155007347757967789e0, 0.8023742119985848209905761e0, 0.7571738066433708695662393e0, 0.7119736390205872251796930e0, 0.6667737592565460745639184e0, 0.6215742318591892056934095e0, 0.5763751413603713322640298e0, 0.5311766008298875656047892e0, 0.4859787651249621588538330e0, 0.4407818522612533891543536e0, 0.3955861793705505114602136e0, 0.3503922263398633798966312e0, 0.3052007556167344348049303e0, 0.2600130558662051177480644e0, 0.2148314894784555841956251e0, 0.1696608997322034095150907e0, 0.1245129955389270002683579e0, 0.7942489891978153749097006e-1, 0.3460150809198016850782325e-1}, {0.1526859042890589526378487e1, 0.1482921763148403842276533e1, 0.1438984491795164536567108e1, 0.1395047233189252525231459e1, 0.1351109991891878034957302e1, 0.1307172772745304669260382e1, 0.1263235580960968906699379e1, 0.1219298422221050703835127e1, 0.1175361302797916700875697e1, 0.1131424229697065895207730e1, 0.1087487210830887883186060e1, 0.1043550255232887174273672e1, 0.9996133733253190253881393e0, 0.9556765772578535710715874e0, 0.9117398813415957196221754e0, 0.8678033026125661948850687e0, 0.8238668615732247310812836e0, 0.7799305831824293601507400e0, 0.7359944981977457886183921e0, 0.6920586450266629333858465e0, 0.6481230723279649663476697e0, 0.6041878427445000852182582e0, 0.5602530383870993537615272e0, 0.5163187691099712879003757e0, 0.4723851853891499571797438e0, 0.4284524990953311047063058e0, 0.3845210184454249891341793e0, 0.3405912098612419399584605e0, 0.2966638144233703899038032e0, 0.2527400847124078576715667e0, 0.2088223170017057788708674e0, 0.1649152190599722827308055e0, 0.1210301722471160155498167e0, 0.7720326018898817828206987e-1, 0.3363364974516995102167462e-1}, {0.1528054559083405137047563e1, 0.1485312794997097705446883e1, 0.1442571038214470776579613e1, 0.1399829292522320013570493e1, 0.1357087561874166765548658e1, 0.1314345850454078759228779e1, 0.1271604162748143389685638e1, 0.1228862503626296926524085e1, 0.1186120878437839368895715e1, 0.1143379293124832099340074e1, 0.1100637754358770795248912e1, 0.1057896269707576280860569e1, 0.1015154847842238156769126e1, 0.9724134987956584339974640e0, 0.9296722342907946818431047e0, 0.8869310681617368097575324e0, 0.8441900169008687429295884e0, 0.8014491003793523040286325e0, 0.7587083428093935362576859e0, 0.7159677740493625646700975e0, 0.6732274314040501413860867e0, 0.6304873621547357085895928e0, 0.5877476271899241333221832e0, 0.5450083063396327078463020e0, 0.5022695064252395155059223e0, 0.4595313737871711838065652e0, 0.4167941144922007176438387e0, 0.3740580283336802289311736e0, 0.3313235690067746553700419e0, 0.2885914573933480330041531e0, 0.2458629119584249278750153e0, 0.2031401664615301668533461e0, 0.1604278005405711652039491e0, 0.1177368858339244458607172e0, 0.7510252408650086658441596e-1, 0.3271846270775478856070884e-1}, {0.1529186740959505109653289e1, 0.1487577158293388707508111e1, 0.1445967582009979387718202e1, 0.1404358015412336440816745e1, 0.1362748461941311565399969e1, 0.1321138925227929972823825e1, 0.1279529409151733277951100e1, 0.1237919917907156982173977e1, 0.1196310456080472987418488e1, 0.1154701028740456700905269e1, 0.1113091641546798022997704e1, 0.1071482300881451340842721e1, 0.1029873014009735917989475e1, 0.9882637892802373569245916e0, 0.9466546363756944528310758e0, 0.9050455666314926033869497e0, 0.8634365934447506520344540e0, 0.8218277328062565148449433e0, 0.7802190040012226850703573e0, 0.7386104305454957746359112e0, 0.6970020414556031913861513e0, 0.6553938730008771105113861e0, 0.6137859711661063914322283e0, 0.5721783951857430999179669e0, 0.5305712227365694155165922e0, 0.4889645577740232855661796e0, 0.4473585427277744403333139e0, 0.4057533781735039172217875e0, 0.3641493559322687127223795e0, 0.3225469176515179389138545e0, 0.2809467650889194227770571e0, 0.2393500844055270891104500e0, 0.1977590501629603151642330e0, 0.1561781206604067112364815e0, 0.1146180742271483316267615e0, 0.7311308274978660184520447e-1, 0.3185176130791400787169333e-1}, {0.1530260491394766313570510e1, 0.1489724658775115137266557e1, 0.1449188831753177403184250e1, 0.1408653013220734918131897e1, 0.1368117206184034069757975e1, 0.1327581413807020172726043e1, 0.1287045639459248683416470e1, 0.1246509886770075360771330e1, 0.1205974159691064843702080e1, 0.1165438462569017837684371e1, 0.1124902800232641860108690e1, 0.1084367178096737546333982e1, 0.1043831602288925654461738e1, 0.1003296079805520648394589e1, 0.9627606187053432591598275e0, 0.9222252283533212928777294e0, 0.8816899197300536544215117e0, 0.8411547058297167490229198e0, 0.8006196021777239861105672e0, 0.7600846275129127849719743e0, 0.7195498046991648764002008e0, 0.6790151619622966197448464e0, 0.6384807345966275863946969e0, 0.5979465673637771458800754e0, 0.5574127179353942966481713e0, 0.5168792619515766918187819e0, 0.4763463006547495614450433e0, 0.4358139727703203523144583e0, 0.3952824736706231680817472e0, 0.3547520876199503791717895e0, 0.3142232448436673832093046e0, 0.2736966289659020439688229e0, 0.2331733955144496369946707e0, 0.1926556629116315949109922e0, 0.1521477743835989472840536e0, 0.1116602300918232453371161e0, 0.7122632005925390425640031e-1, 0.3102979192734513847869512e-1}, {0.1531280219945530918862887e1, 0.1491764115543711582608611e1, 0.1452248016067723206269747e1, 0.1412731924058150689920340e1, 0.1373215842151127100608219e1, 0.1333699773114208203180680e1, 0.1294183719885939986844436e1, 0.1254667685620366764206205e1, 0.1215151673737978313041594e1, 0.1175635687984935008823566e1, 0.1136119732502868295328130e1, 0.1096603811912170337964094e1, 0.1057087931412518476253055e1, 0.1017572096905509113863513e1, 0.9780563151458206514020694e0, 0.9385405939294598498464432e0, 0.8990249423306286659734381e0, 0.8595093710029676968794279e0, 0.8199938925669823205931282e0, 0.7804785221142635001130339e0, 0.7409632778721439753645470e0, 0.7014481820920565808095373e0, 0.6619332622550151160558599e0, 0.6224185527349885679868616e0, 0.5829040971371158016902326e0, 0.5433899516536147244946347e0, 0.5038761899947552937603140e0, 0.4643629108305196256509391e0, 0.4248502493722176391609139e0, 0.3853383960541810555628366e0, 0.3458276279674767760058527e0, 0.3063183644932167228808922e0, 0.2668112720373341483108662e0, 0.2273074770384765519559169e0, 0.1878090446069578429818381e0, 0.1483202086882449059764783e0, 0.1088512052741322662621244e0, 0.6943448689600673838300180e-1, 0.3024917865720923179577363e-1}, {0.1532249903371281818085917e1, 0.1493703482108998740614827e1, 0.1455157065195200346809599e1, 0.1416610654869340270223431e1, 0.1378064253450997606022340e1, 0.1339517863369794055919890e1, 0.1300971487198245305453001e1, 0.1262425127688525048786896e1, 0.1223878787814308166546501e1, 0.1185332470819113339105535e1, 0.1146786180272904774996439e1, 0.1108239920139165765487189e1, 0.1069693694855262920629379e1, 0.1031147509429735196850587e1, 0.9926013695612463310882198e0, 0.9540552817854489715123326e0, 0.9155092536580933534978986e0, 0.8769632939856246206308699e0, 0.8384174131186299393233148e0, 0.7998716233293992826192237e0, 0.7613259393034545837300323e0, 0.7227803787876118667749166e0, 0.6842349634562860931661901e0, 0.6456897200871628101751519e0, 0.6071446821835496233813653e0, 0.5685998922550279415939221e0, 0.5300554050908430047380815e0, 0.4915112925697217767572364e0, 0.4529676509187802579380104e0, 0.4144246120108054286121629e0, 0.3758823615873930314093573e0, 0.3373411699211847213003570e0, 0.2988014460838619282843952e0, 0.2602638401106843145315994e0, 0.2217294507811754336425535e0, 0.1832002925124018168986342e0, 0.1446804953347050655563166e0, 0.1061800440374660771048480e0, 0.6773059476567831336488402e-1, 0.2950687695527422224851832e-1}, {0.1533173137460634461235066e1, 0.1495549950040734249895393e1, 0.1457926766471340970762709e1, 0.1420303588732694442267846e1, 0.1382680418872520759663065e1, 0.1345057259031099988676433e1, 0.1307434111468678960501903e1, 0.1269810978596001635506341e1, 0.1232187863008871596257323e1, 0.1194564767527851916244615e1, 0.1156941695244461089553108e1, 0.1119318649575559636172662e1, 0.1081695634328067979412755e1, 0.1044072653776750930510111e1, 0.1006449712758602402124214e1, 0.9688268167884441336521039e0, 0.9312039722018274751677424e0, 0.8935811863333633591901354e0, 0.8559584677414483220357356e0, 0.8183358264943738874932307e0, 0.7807132745385688213392421e0, 0.7430908261781095392995681e0, 0.7054684987070400358784448e0, 0.6678463132547297820965882e0, 0.6302242959332082940279826e0, 0.5926024794204980683238426e0, 0.5549809051864955237054951e0, 0.5173596266878257139037738e0, 0.4797387140623364241772428e0, 0.4421182612140318859822955e0, 0.4044983968396638104610711e0, 0.3668793022152994411560368e0, 0.3292612411240570212440856e0, 0.2916446128242035199998930e0, 0.2540300517665934607689814e0, 0.2164186303985620085027010e0, 0.1788123148742007754778852e0, 0.1412151362884411752920148e0, 0.1036368402634645114775150e0, 0.6610832470916409695729856e-1, 0.2880013396280840229218334e-1}, {0.1534053181584449084854269e1, 0.1497310038074501005766978e1, 0.1460566897984002644464183e1, 0.1423823763069232867789940e1, 0.1387080635143547965139117e1, 0.1350337516098480646600889e1, 0.1313594407926723776707731e1, 0.1276851312747612578778902e1, 0.1240108232835827171448969e1, 0.1203365170654181674634873e1, 0.1166622128891556900019450e1, 0.1129879110507284864268762e1, 0.1093136118783624474731954e1, 0.1056393157388405786003046e1, 0.1019650230450503114577901e1, 0.9829073426515786199715451e0, 0.9461644993385942743541994e0, 0.9094217066630320811486021e0, 0.8726789717547518480094350e0, 0.8359363029411928866147184e0, 0.7991937100265521402467844e0, 0.7624512046511992388808212e0, 0.7257088007597790982554974e0, 0.6889665152185689899094400e0, 0.6522243686409073299342467e0, 0.6154823865075504175164916e0, 0.5787406007128420496638175e0, 0.5419990517384125648087865e0, 0.5052577917731960988645056e0, 0.4685168892980173635234519e0, 0.4317764360047099160222576e0, 0.3950365575646972937604113e0, 0.3582974309994310205507555e0, 0.3215593139080007759227897e0, 0.2848225961961619069649047e0, 0.2480878974611689122432227e0, 0.2113562650517154915467591e0, 0.1746296191183898065201571e0, 0.1379118964507339113271975e0, 0.1012126146941469342401701e0, 0.6456194899726137278760257e-1, 0.2812645439079299219187419e-1}, {0.1534892997139557227614279e1, 0.1498989668998897501276994e1, 0.1463086343903285773505644e1, 0.1427183023414814244376429e1, 0.1391279709144040438287602e1, 0.1355376402767821814937864e1, 0.1319473106048673173924451e1, 0.1283569820856137399848247e1, 0.1247666549190742942502495e1, 0.1211763293211231530413995e1, 0.1175860055265884319525693e1, 0.1139956837928964066704190e1, 0.1104053644043538840797350e1, 0.1068150476772278342447444e1, 0.1032247339658243608912598e1, 0.9963442366982618328585493e0, 0.9604411724322426430586723e0, 0.9245381520528253319358567e0, 0.8886351815411563067305273e0, 0.8527322678365406966379400e0, 0.8168294190504262166761188e0, 0.7809266447390142664026016e0, 0.7450239562542930157586944e0, 0.7091213672012904985883029e0, 0.6732188940411854039055226e0, 0.6373165568977466866717861e0, 0.6014143806519714388063208e0, 0.5655123964528129857845238e0, 0.5296106438411039715966193e0, 0.4937091737981756577948229e0, 0.4578080532255782153525438e0, 0.4219073717059785387344039e0, 0.3860072520255396095683859e0, 0.3501078671472635990145335e0, 0.3142094687704932495909488e0, 0.2783124378775218384923333e0, 0.2424173798924625361874772e0, 0.2065253182141071551836492e0, 0.1706381290938671641708352e0, 0.1347596593282315198612592e0, 0.9889920900871122533586553e-1, 0.6308626356388784057588631e-1, 0.2748357108440508277394892e-1}, {0.1535695280838629983064694e1, 0.1500594236235067817656313e1, 0.1465493194350303789230585e1, 0.1430392156577492526495371e1, 0.1395291124351096810858349e1, 0.1360190099162024176252063e1, 0.1325089082574000089379322e1, 0.1289988076241572027256558e1, 0.1254887081930202663795858e1, 0.1219786101538994920367859e1, 0.1184685137126702182946916e1, 0.1149584190941820846004092e1, 0.1114483265457749469332035e1, 0.1079382363414242848588494e1, 0.1044281487866708939888712e1, 0.1009180642245317812316634e1, 0.9740798304264509422659935e0, 0.9389790568197674899837757e0, 0.9038783264751749171405213e0, 0.8687776452153701566068907e0, 0.8336770198015192229270720e0, 0.7985764581422970742698971e0, 0.7634759695602610192254430e0, 0.7283755651349081311799055e0, 0.6932752581495918103871962e0, 0.6581750646810479477537782e0, 0.6230750043877162525265513e0, 0.5879751015798285374141491e0, 0.5528753866962970290878822e0, 0.5177758983811020490994086e0, 0.4826766864637186565865902e0, 0.4475778163386701445336738e0, 0.4124793755752883735361361e0, 0.3773814842049053432591527e0, 0.3422843113148581639684411e0, 0.3071881029697497767338606e0, 0.2720932316284942932084102e0, 0.2370002891767127567222407e0, 0.2019102761348421810146637e0, 0.1668250268181992892198073e0, 0.1317483020532982541977987e0, 0.9668919410176593344830717e-1, 0.6167652949817792358742135e-1, 0.2686941953400762687915995e-1}, {0.1536462493634653558154673e1, 0.1502128661685489464262068e1, 0.1467794832169950298839286e1, 0.1433461006333747476463744e1, 0.1399127185457927306909792e1, 0.1364793370871767472755746e1, 0.1330459563966682507229700e1, 0.1296125766211456950047804e1, 0.1261791979169174443914592e1, 0.1227458204516276373551266e1, 0.1193124444064268679881601e1, 0.1158790699784705540565424e1, 0.1124456973838220917338613e1, 0.1090123268608563332983681e1, 0.1055789586742829027889885e1, 0.1021455931199402224481903e1, 0.9871223053055240306873772e0, 0.9527887128269590857605072e0, 0.9184551580529615732874848e0, 0.8841216459007313197085517e0, 0.8497881820448998068986446e0, 0.8154547730794463756650640e0, 0.7811214267220410983907210e0, 0.7467881520744805288579630e0, 0.7124549599581423848996086e0, 0.6781218633510390484774053e0, 0.6437888779643722276961833e0, 0.6094560230135452763170614e0, 0.5751233222647905281576305e0, 0.5407908054797110156395425e0, 0.5064585104462232763044121e0, 0.4721264858937837018545325e0, 0.4377947957771643018072936e0, 0.4034635257416918872885646e0, 0.3691327931855416440777167e0, 0.3348027634909946151567752e0, 0.3004736773353657517478163e0, 0.2661458990278703974149616e0, 0.2318200075085118064771005e0, 0.1974969814205034596217949e0, 0.1631786149772797106698111e0, 0.1288685867945150272796250e0, 0.9457579039019365184018477e-1, 0.6032842220945916819748797e-1, 0.2628211572883546008386342e-1}, {0.1537196885933572311910085e1, 0.1503597446159129663218426e1, 0.1469998008568304160871417e1, 0.1436398574277729377094190e1, 0.1402799144434368418084898e1, 0.1369199720226542342210552e1, 0.1335600302895785666466344e1, 0.1302000893749787833197270e1, 0.1268401494176718217187838e1, 0.1234802105661283063077015e1, 0.1201202729802928570677208e1, 0.1167603368336689119731474e1, 0.1134004023157288628212183e1, 0.1100404696347243386055709e1, 0.1066805390209896030700280e1, 0.1033206107308545748870827e1, 0.9996068505131472996246808e0, 0.9660076230564559666956844e0, 0.9324084286020318648375284e0, 0.8988092713272342656758064e0, 0.8652101560253048754543914e0, 0.8316110882319595313175680e0, 0.7980120743837286767240920e0, 0.7644131220178278512956878e0, 0.7308142400269308414762795e0, 0.6972154389873656296775555e0, 0.6636167315867435235683334e0, 0.6300181331881122315700717e0, 0.5964196625844131090385918e0, 0.5628213430226633060114218e0, 0.5292232036175455988770345e0, 0.4956252813388603291268380e0, 0.4620276238643496856689332e0, 0.4284302937718012609061760e0, 0.3948333748659561479104270e0, 0.3612369820255324850503899e0, 0.3276412770872600895283016e0, 0.2940464955725917238672137e0, 0.2604529939906062681054034e0, 0.2268613388903867245835696e0, 0.1932724879746856807613294e0, 0.1596881970714452359218090e0, 0.1261120661032951679792394e0, 0.9255279834764232165670211e-1, 0.5903798711627596210077655e-1, 0.2571993685288741305807485e-1}, {0.1537900519639177351485509e1, 0.1505004713461118831562885e1, 0.1472108909246876714959093e1, 0.1439213107999753788389740e1, 0.1406317310749171844429399e1, 0.1373421518560135827011261e1, 0.1340525732543378926238078e1, 0.1307629953866399941713193e1, 0.1274734183765634621652739e1, 0.1241838423560042429086765e1, 0.1208942674666441461574345e1, 0.1176046938616989970936899e1, 0.1143151217079296988032361e1, 0.1110255511879752164142939e1, 0.1077359825030803093319347e1, 0.1044464158763086533573607e1, 0.1011568515563550961534623e1, 0.9786728982210094134846821e0, 0.9457773098809579873452675e0, 0.9128817541120207886160886e0, 0.8799862349870845994262022e0, 0.8470907571831347751008168e0, 0.8141953261050969543263697e0, 0.7812999480407721032432037e0, 0.7484046303564402266425896e0, 0.7155093817462244075628281e0, 0.6826142125533466396520346e0, 0.6497191351887403950357432e0, 0.6168241646833332909207560e0, 0.5839293194266532352434130e0, 0.5510346221695150324949297e0, 0.5181401014079633610544426e0, 0.4852457933290632607369490e0, 0.4523517446039431388003505e0, 0.4194580164920722423612656e0, 0.3865646910356375140534892e0, 0.3536718807003189971969294e0, 0.3207797439266498255416416e0, 0.2878885112969848452450724e0, 0.2549985318477515756044100e0, 0.2221103602568508117102717e0, 0.1892249341643785313168465e0, 0.1563439726212394862316010e0, 0.1234710001537068179882843e0, 0.9061453776736619019094845e-1, 0.5780160090309369034797044e-1, 0.2518130440638251656980999e-1}, {0.1538575287485045780713568e1, 0.1506354249056545799167351e1, 0.1474133212398093554231315e1, 0.1441912178413208451704314e1, 0.1409691148027973881079186e1, 0.1377470122199186272616473e1, 0.1345249101923067139210221e1, 0.1313028088244711409410919e1, 0.1280807082268469343020428e1, 0.1248586085169490583375238e1, 0.1216365098206699074213627e1, 0.1184144122737518830558069e1, 0.1151923160234735793613503e1, 0.1119702212305964062886069e1, 0.1087481280716290811591462e1, 0.1055260367414810028339009e1, 0.1023039474565930165787482e1, 0.9908186045865674272211987e0, 0.9585977601906320722299056e0, 0.9263769444426036830464570e0, 0.8941561608225061952846411e0, 0.8619354133052817812042663e0, 0.8297147064584916186566054e0, 0.7974940455635382827549679e0, 0.7652734367673509855003551e0, 0.7330528872739117793257283e0, 0.7008324055884451343305450e0, 0.6686120018320298047193041e0, 0.6363916881515750209117372e0, 0.6041714792607289968809847e0, 0.5719513931632926368357825e0, 0.5397314521353000325496229e0, 0.5075116840805377280486923e0, 0.4752921244363891783961832e0, 0.4430728189095547215892704e0, 0.4108538274961112658763390e0, 0.3786352305487998074788803e0, 0.3464171382200184643128623e0, 0.3141997056941599156198233e0, 0.2819831588178046655599196e0, 0.2497678394619649260592757e0, 0.2175542909210219972765731e0, 0.1853434315961135904158300e0, 0.1531369452704970394027659e0, 0.1209382841678252589048669e0, 0.8875579450016283173293810e-1, 0.5661593754525190873771522e-1, 0.2466476940450737058975552e-1}, {0.1539222930035210331902410e1, 0.1507649534071729882214386e1, 0.1476076139707032453353232e1, 0.1444502747756546556830706e1, 0.1412929359055252480197337e1, 0.1381355974464721552102928e1, 0.1349782594880622732927647e1, 0.1318209221240839295255046e1, 0.1286635854534357387243172e1, 0.1255062495811112994872428e1, 0.1223489146193015470717893e1, 0.1191915806886406014313715e1, 0.1160342479196260434661502e1, 0.1128769164542510055952304e1, 0.1097195864478936528824546e1, 0.1065622580715200621234508e1, 0.1034049315142698534418744e1, 0.1002476069865111021377467e1, 0.9709028472347329448081481e0, 0.9393296498959608456620406e0, 0.9077564808376970380335442e0, 0.8761833434569334264096395e0, 0.8446102416364528348063321e0, 0.8130371798404960344077378e0, 0.7814641632334840064334645e0, 0.7498911978285964532098456e0, 0.7183182906753955596314298e0, 0.6867454500990591398232408e0, 0.6551726860086246453663390e0, 0.6236000102986843027011345e0, 0.5920274373793840619034224e0, 0.5604549848852622707385612e0, 0.5288826746375584896948472e0, 0.4973105339724571989307663e0, 0.4657385976085971045914307e0, 0.4341669103277770901346174e0, 0.4025955309141879357899857e0, 0.3710245380997234377015025e0, 0.3394540398171456073906403e0, 0.3078841881262277508367562e0, 0.2763152043287541015913350e0, 0.2447474234189502677044064e0, 0.2131813777658572006989977e0, 0.1816179673056091210434906e0, 0.1500588419721174291665790e0, 0.1185073845935281602210493e0, 0.8697177361567243680812898e-1, 0.5547793843128156580348541e-1, 0.2416899936118312040170588e-1}, } // The weights of these nodes var evenWeights = [][]float64{ {1.0}, {0.6521451548625461426269364e0, 0.3478548451374538573730642e0}, {0.4679139345726910473898704e0, 0.3607615730481386075698336e0, 0.1713244923791703450402969e0}, {0.3626837833783619829651504e0, 0.3137066458778872873379622e0, 0.2223810344533744705443556e0, 0.1012285362903762591525320e0}, {0.2955242247147528701738930e0, 0.2692667193099963550912268e0, 0.2190863625159820439955350e0, 0.1494513491505805931457764e0, 0.6667134430868813759356850e-1}, {0.2491470458134027850005624e0, 0.2334925365383548087608498e0, 0.2031674267230659217490644e0, 0.1600783285433462263346522e0, 0.1069393259953184309602552e0, 0.4717533638651182719461626e-1}, {0.2152638534631577901958766e0, 0.2051984637212956039659240e0, 0.1855383974779378137417164e0, 0.1572031671581935345696019e0, 0.1215185706879031846894145e0, 0.8015808715976020980563266e-1, 0.3511946033175186303183410e-1}, {0.1894506104550684962853967e0, 0.1826034150449235888667636e0, 0.1691565193950025381893119e0, 0.1495959888165767320815019e0, 0.1246289712555338720524763e0, 0.9515851168249278480992520e-1, 0.6225352393864789286284360e-1, 0.2715245941175409485178166e-1}, {0.1691423829631435918406565e0, 0.1642764837458327229860538e0, 0.1546846751262652449254180e0, 0.1406429146706506512047311e0, 0.1225552067114784601845192e0, 0.1009420441062871655628144e0, 0.7642573025488905652912984e-1, 0.4971454889496979645333512e-1, 0.2161601352648331031334248e-1}, {0.1527533871307258506980843e0, 0.1491729864726037467878288e0, 0.1420961093183820513292985e0, 0.1316886384491766268984948e0, 0.1181945319615184173123774e0, 0.1019301198172404350367504e0, 0.8327674157670474872475850e-1, 0.6267204833410906356950596e-1, 0.4060142980038694133103928e-1, 0.1761400713915211831186249e-1}, {0.1392518728556319933754102e0, 0.1365414983460151713525738e0, 0.1311735047870623707329649e0, 0.1232523768105124242855609e0, 0.1129322960805392183934005e0, 0.1004141444428809649320786e0, 0.8594160621706772741444398e-1, 0.6979646842452048809496104e-1, 0.5229333515268328594031142e-1, 0.3377490158481415479330258e-1, 0.1462799529827220068498987e-1}, {0.1279381953467521569740562e0, 0.1258374563468282961213754e0, 0.1216704729278033912044631e0, 0.1155056680537256013533445e0, 0.1074442701159656347825772e0, 0.9761865210411388826988072e-1, 0.8619016153195327591718514e-1, 0.7334648141108030573403386e-1, 0.5929858491543678074636724e-1, 0.4427743881741980616860272e-1, 0.2853138862893366318130802e-1, 0.1234122979998719954680507e-1}, {0.1183214152792622765163711e0, 0.1166604434852965820446624e0, 0.1133618165463196665494407e0, 0.1084718405285765906565795e0, 0.1020591610944254232384142e0, 0.9421380035591414846366474e-1, 0.8504589431348523921044770e-1, 0.7468414976565974588707538e-1, 0.6327404632957483553945402e-1, 0.5097582529714781199831990e-1, 0.3796238329436276395030342e-1, 0.2441785109263190878961718e-1, 0, .1055137261734300715565387e-1}, {0.1100470130164751962823763e0, 0.1087111922582941352535716e0, 0.1060557659228464179104165e0, 0.1021129675780607698142166e0, 0.9693065799792991585048880e-1, 0.9057174439303284094218612e-1, 0.8311341722890121839039666e-1, 0.7464621423456877902393178e-1, 0.6527292396699959579339794e-1, 0.5510734567571674543148330e-1, 0.4427293475900422783958756e-1, 0.3290142778230437997763004e-1, 0.2113211259277125975149896e-1, 0.9124282593094517738816778e-2}, {0.1028526528935588403412856e0, 0.1017623897484055045964290e0, 0.9959342058679526706278018e-1, 0.9636873717464425963946864e-1, 0.9212252223778612871763266e-1, 0.8689978720108297980238752e-1, 0.8075589522942021535469516e-1, 0.7375597473770520626824384e-1, 0.6597422988218049512812820e-1, 0.5749315621761906648172152e-1, 0.4840267283059405290293858e-1, 0.3879919256962704959680230e-1, 0.2878470788332336934971862e-1, 0.1846646831109095914230276e-1, 0.7968192496166605615469690e-2}, {0.9654008851472780056676488e-1, 0.9563872007927485941908208e-1, 0.9384439908080456563918026e-1, 0.9117387869576388471286854e-1, 0.8765209300440381114277140e-1, 0.8331192422694675522219922e-1, 0.7819389578707030647174106e-1, 0.7234579410884850622539954e-1, 0.6582222277636184683765034e-1, 0.5868409347853554714528360e-1, 0.5099805926237617619616316e-1, 0.4283589802222668065687810e-1, 0.3427386291302143310268716e-1, 0.2539206530926205945575196e-1, 0.1627439473090567060516896e-1, 0.7018610009470096600404748e-2}, {0.9095674033025987361533764e-1, 0.9020304437064072957394216e-1, 0.8870189783569386928707642e-1, 0.8646573974703574978424688e-1, 0.8351309969984565518702044e-1, 0.7986844433977184473881888e-1, 0.7556197466003193127083398e-1, 0.7062937581425572499903896e-1, 0.6511152155407641137854442e-1, 0.5905413582752449319396124e-1, 0.5250741457267810616824590e-1, 0.4552561152335327245382266e-1, 0.3816659379638751632176606e-1, 0.3049138063844613180944194e-1, 0.2256372198549497008409476e-1, 0.1445016274859503541520101e-1, 0.6229140555908684718603220e-2}, {0.8598327567039474749008516e-1, 0.8534668573933862749185052e-1, 0.8407821897966193493345756e-1, 0.8218726670433970951722338e-1, 0.7968782891207160190872470e-1, 0.7659841064587067452875784e-1, 0.7294188500565306135387342e-1, 0.6874532383573644261368974e-1, 0.6403979735501548955638454e-1, 0.5886014424532481730967550e-1, 0.5324471397775991909202590e-1, 0.4723508349026597841661708e-1, 0.4087575092364489547411412e-1, 0.3421381077030722992124474e-1, 0.2729862149856877909441690e-1, 0.2018151529773547153209770e-1, 0.1291594728406557440450307e-1, 0.5565719664245045361251818e-2}, {0.8152502928038578669921876e-1, 0.8098249377059710062326952e-1, 0.7990103324352782158602774e-1, 0.7828784465821094807537540e-1, 0.7615366354844639606599344e-1, 0.7351269258474345714520658e-1, 0.7038250706689895473928292e-1, 0.6678393797914041193504612e-1, 0.6274093339213305405296984e-1, 0.5828039914699720602230556e-1, 0.5343201991033231997375704e-1, 0.4822806186075868337435238e-1, 0.4270315850467443423587832e-1, 0.3689408159402473816493978e-1, 0.3083950054517505465873166e-1, 0.2457973973823237589520214e-1, 0.1815657770961323689887502e-1, 0.1161344471646867417766868e-1, 0.5002880749639345675901886e-2}, {0.7750594797842481126372404e-1, 0.7703981816424796558830758e-1, 0.7611036190062624237155810e-1, 0.7472316905796826420018930e-1, 0.7288658239580405906051074e-1, 0.7061164739128677969548346e-1, 0.6791204581523390382569024e-1, 0.6480401345660103807455446e-1, 0.6130624249292893916653822e-1, 0.5743976909939155136661768e-1, 0.5322784698393682435499678e-1, 0.4869580763507223206143380e-1, 0.4387090818567327199167442e-1, 0.3878216797447201763997196e-1, 0.3346019528254784739267780e-1, 0.2793700698002340109848970e-1, 0.2224584919416695726150432e-1, 0.1642105838190788871286396e-1, 0.1049828453115281361474434e-1, 0.4521277098533191258471490e-2}, {0.7386423423217287999638556e-1, 0.7346081345346752826402828e-1, 0.7265617524380410488790570e-1, 0.7145471426517098292181042e-1, 0.6986299249259415976615480e-1, 0.6788970337652194485536350e-1, 0.6554562436490897892700504e-1, 0.6284355804500257640931846e-1, 0.5979826222758665431283142e-1, 0.5642636935801838164642686e-1, 0.5274629569917407034394234e-1, 0.4877814079280324502744954e-1, 0.4454357777196587787431674e-1, 0.4006573518069226176059618e-1, 0.3536907109759211083266214e-1, 0.3047924069960346836290502e-1, 0.2542295952611304788674188e-1, 0.2022786956905264475705664e-1, 0.1492244369735749414467869e-1, 0.9536220301748502411822340e-2, 0.4105998604649084610599928e-2}, {0.7054915778935406881133824e-1, 0.7019768547355821258714200e-1, 0.6949649186157257803708402e-1, 0.6844907026936666098545864e-1, 0.6706063890629365239570506e-1, 0.6533811487918143498424096e-1, 0.6329007973320385495013890e-1, 0.6092673670156196803855800e-1, 0.5825985987759549533421064e-1, 0.5530273556372805254874660e-1, 0.5207009609170446188123162e-1, 0.4857804644835203752763920e-1, 0.4484398408197003144624282e-1, 0.4088651231034621890844686e-1, 0.3672534781380887364290888e-1, 0.3238122281206982088084682e-1, 0.2787578282128101008111450e-1, 0.2323148190201921062895910e-1, 0.1847148173681474917204335e-1, 0.1361958675557998552020491e-1, 0.8700481367524844122565470e-2, 0.3745404803112777515171456e-2}, {0.6751868584903645882021418e-1, 0.6721061360067817586237416e-1, 0.6659587476845488737576196e-1, 0.6567727426778120737875756e-1, 0.6445900346713906958827948e-1, 0.6294662106439450817895206e-1, 0.6114702772465048101535670e-1, 0.5906843459554631480755080e-1, 0.5672032584399123581687444e-1, 0.5411341538585675449163752e-1, 0.5125959800714302133536554e-1, 0.4817189510171220053046892e-1, 0.4486439527731812676709458e-1, 0.4135219010967872970421980e-1, 0.3765130535738607132766076e-1, 0.3377862799910689652060416e-1, 0.2975182955220275579905234e-1, 0.2558928639713001063470016e-1, 0.2130999875413650105447862e-1, 0.1693351400783623804623151e-1, 0.1247988377098868420673525e-1, 0.7969898229724622451610710e-2, 0.3430300868107048286016700e-2}, {0.6473769681268392250302496e-1, 0.6446616443595008220650418e-1, 0.6392423858464818662390622e-1, 0.6311419228625402565712596e-1, 0.6203942315989266390419786e-1, 0.6070443916589388005296916e-1, 0.5911483969839563574647484e-1, 0.5727729210040321570515042e-1, 0.5519950369998416286820356e-1, 0.5289018948519366709550490e-1, 0.5035903555385447495780746e-1, 0.4761665849249047482590674e-1, 0.4467456085669428041944838e-1, 0.4154508294346474921405856e-1, 0.3824135106583070631721688e-1, 0.3477722256477043889254814e-1, 0.3116722783279808890206628e-1, 0.2742650970835694820007336e-1, 0.2357076083932437914051962e-1, 0.1961616045735552781446139e-1, 0.1557931572294384872817736e-1, 0.1147723457923453948959265e-1, 0.7327553901276262102386656e-2, 0.3153346052305838632678320e-2}, {0.6217661665534726232103316e-1, 0.6193606742068324338408750e-1, 0.6145589959031666375640678e-1, 0.6073797084177021603175000e-1, 0.5978505870426545750957640e-1, 0.5860084981322244583512250e-1, 0.5718992564772838372302946e-1, 0.5555774480621251762356746e-1, 0.5371062188899624652345868e-1, 0.5165570306958113848990528e-1, 0.4940093844946631492124360e-1, 0.4695505130394843296563322e-1, 0.4432750433880327549202254e-1, 0.4152846309014769742241230e-1, 0.3856875661258767524477018e-1, 0.3545983561514615416073452e-1, 0.3221372822357801664816538e-1, 0.2884299358053519802990658e-1, 0.2536067357001239044019428e-1, 0.2178024317012479298159128e-1, 0.1811556071348939035125903e-1, 0.1438082276148557441937880e-1, 0.1059054838365096926356876e-1, 0.6759799195745401502778824e-2, 0.2908622553155140958394976e-2}, {0.5981036574529186024778538e-1, 0.5959626017124815825831088e-1, 0.5916881546604297036933200e-1, 0.5852956177181386855029062e-1, 0.5768078745252682765393200e-1, 0.5662553090236859719080832e-1, 0.5536756966930265254904124e-1, 0.5391140693275726475083694e-1, 0.5226225538390699303439404e-1, 0.5042601856634237721821144e-1, 0.4840926974407489685396032e-1, 0.4621922837278479350764582e-1, 0.4386373425900040799512978e-1, 0.4135121950056027167904044e-1, 0.3869067831042397898510146e-1, 0.3589163483509723294194276e-1, 0.3296410908971879791501014e-1, 0.2991858114714394664128188e-1, 0.2676595374650401344949324e-1, 0.2351751355398446159032286e-1, 0.2018489150798079220298930e-1, 0.1678002339630073567792252e-1, 0.1331511498234096065660116e-1, 0.9802634579462752061952706e-2, 0.6255523962973276899717754e-2, 0.2691316950047111118946698e-2}, {0.5761753670714702467237616e-1, 0.5742613705411211485929010e-1, 0.5704397355879459856782852e-1, 0.5647231573062596503104434e-1, 0.5571306256058998768336982e-1, 0.5476873621305798630622270e-1, 0.5364247364755361127210060e-1, 0.5233801619829874466558872e-1, 0.5085969714618814431970910e-1, 0.4921242732452888606879048e-1, 0.4740167880644499105857626e-1, 0.4543346672827671397485208e-1, 0.4331432930959701544192564e-1, 0.4105130613664497422171834e-1, 0.3865191478210251683685736e-1, 0.3612412584038355258288694e-1, 0.3347633646437264571604038e-1, 0.3071734249787067605400450e-1, 0.2785630931059587028700164e-1, 0.2490274146720877305005456e-1, 0.2186645142285308594551102e-1, 0.1875752762146937791200757e-1, 0.1558630303592413170296832e-1, 0.1236332812884764416646861e-1, 0.9099369455509396948032734e-2, 0.5805611015239984878826112e-2, 0.2497481835761585775945054e-2}, {0.5557974630651439584627342e-1, 0.5540795250324512321779340e-1, 0.5506489590176242579630464e-1, 0.5455163687088942106175058e-1, 0.5386976186571448570895448e-1, 0.5302137852401076396799152e-1, 0.5200910915174139984305222e-1, 0.5083608261779848056012412e-1, 0.4950592468304757891996610e-1, 0.4802274679360025812073550e-1, 0.4639113337300189676219012e-1, 0.4461612765269228321341510e-1, 0.4270321608466708651103858e-1, 0.4065831138474451788012514e-1, 0.3848773425924766248682568e-1, 0.3619819387231518603588452e-1, 0.3379676711561176129542654e-1, 0.3129087674731044786783572e-1, 0.2868826847382274172988602e-1, 0.2599698705839195219181960e-1, 0.2322535156256531693725830e-1, 0.2038192988240257263480560e-1, 0.1747551291140094650495930e-1, 0.1451508927802147180777130e-1, 0.1150982434038338217377419e-1, 0.8469063163307887661628584e-2, 0.5402522246015337761313780e-2, 0.2323855375773215501098716e-2}, {0.5368111986333484886390600e-1, 0.5352634330405825210061082e-1, 0.5321723644657901410348096e-1, 0.5275469052637083342964580e-1, 0.5214003918366981897126058e-1, 0.5137505461828572547451486e-1, 0.5046194247995312529765992e-1, 0.4940333550896239286651076e-1, 0.4820228594541774840657052e-1, 0.4686225672902634691841818e-1, 0.4538711151481980250398048e-1, 0.4378110353364025103902560e-1, 0.4204886332958212599457020e-1, 0.4019538540986779688807676e-1, 0.3822601384585843322945902e-1, 0.3614642686708727054078062e-1, 0.3396262049341601079772722e-1, 0.3168089125380932732029244e-1, 0.2930781804416049071839382e-1, 0.2685024318198186847590714e-1, 0.2431525272496395254025850e-1, 0.2171015614014623576691612e-1, 0.1904246546189340865578709e-1, 0.1631987423497096505212063e-1, 0.1355023711298881214517933e-1, 0.1074155353287877411685532e-1, 0.7901973849998674754018608e-2, 0.5039981612650243085015810e-2, 0.2167723249627449943047768e-2}, {0.5190787763122063973286496e-1, 0.5176794317491018754380368e-1, 0.5148845150098093399504444e-1, 0.5107015606985562740454910e-1, 0.5051418453250937459823872e-1, 0.4982203569055018101115930e-1, 0.4899557545575683538947578e-1, 0.4803703181997118096366674e-1, 0.4694898884891220484701330e-1, 0.4573437971611448664719662e-1, 0.4439647879578711332778398e-1, 0.4293889283593564195423128e-1, 0.4136555123558475561316394e-1, 0.3968069545238079947012286e-1, 0.3788886756924344403094056e-1, 0.3599489805108450306657888e-1, 0.3400389272494642283491466e-1, 0.3192121901929632894945890e-1, 0.2975249150078894524083642e-1, 0.2750355674992479163522324e-1, 0.2518047762152124837957096e-1, 0.2278951694399781986378308e-1, 0.2033712072945728677503268e-1, 0.1782990101420772026039605e-1, 0.1527461859678479930672510e-1, 0.1267816647681596013149540e-1, 0.1004755718228798435788578e-1, 0.7389931163345455531517530e-2, 0.4712729926953568640893942e-2, 0.2026811968873758496433874e-2}, {0.5024800037525628168840300e-1, 0.5012106956904328807480410e-1, 0.4986752859495239424476130e-1, 0.4948801791969929252786578e-1, 0.4898349622051783710485112e-1, 0.4835523796347767283480314e-1, 0.4760483018410123227045008e-1, 0.4673416847841552480220700e-1, 0.4574545221457018077723242e-1, 0.4464117897712441429364478e-1, 0.4342413825804741958006920e-1, 0.4209740441038509664302268e-1, 0.4066432888241744096828524e-1, 0.3912853175196308412331100e-1, 0.3749389258228002998561838e-1, 0.3576454062276814128558760e-1, 0.3394484437941054509111762e-1, 0.3203940058162467810633926e-1, 0.3005302257398987007700934e-1, 0.2799072816331463754123820e-1, 0.2585772695402469802709536e-1, 0.2365940720868279257451652e-1, 0.2140132227766996884117906e-1, 0.1908917665857319873250324e-1, 0.1672881179017731628855027e-1, 0.1432619182380651776740340e-1, 0.1188739011701050194481938e-1, 0.9418579428420387637936636e-2, 0.6926041901830960871704530e-2, 0.4416333456930904813271960e-2, 0.1899205679513690480402948e-2}, {0.4869095700913972038336538e-1, 0.4857546744150342693479908e-1, 0.4834476223480295716976954e-1, 0.4799938859645830772812614e-1, 0.4754016571483030866228214e-1, 0.4696818281621001732532634e-1, 0.4628479658131441729595326e-1, 0.4549162792741814447977098e-1, 0.4459055816375656306013478e-1, 0.4358372452932345337682780e-1, 0.4247351512365358900733972e-1, 0.4126256324262352861015628e-1, 0.3995374113272034138665686e-1, 0.3855015317861562912896262e-1, 0.3705512854024004604041492e-1, 0.3547221325688238381069330e-1, 0.3380516183714160939156536e-1, 0.3205792835485155358546770e-1, 0.3023465707240247886797386e-1, 0.2833967261425948322751098e-1, 0.2637746971505465867169136e-1, 0.2435270256871087333817770e-1, 0.2227017380838325415929788e-1, 0.2013482315353020937234076e-1, 0.1795171577569734308504602e-1, 0.1572603047602471932196614e-1, 0.1346304789671864259806029e-1, 0.1116813946013112881859029e-1, 0.8846759826363947723030856e-2, 0.6504457968978362856118112e-2, 0.4147033260562467635287472e-2, 0.1783280721696432947292054e-2}, {0.4722748126299855484563332e-1, 0.4712209828764473218544518e-1, 0.4691156748762082774625404e-1, 0.4659635863958410362582412e-1, 0.4617717509791597547166640e-1, 0.4565495222527305612043888e-1, 0.4503085530544150021519278e-1, 0.4430627694315316190460328e-1, 0.4348283395666747864757528e-1, 0.4256236377005571631890662e-1, 0.4154692031324188131773448e-1, 0.4043876943895497912586836e-1, 0.3924038386682833018781280e-1, 0.3795443766594162094913028e-1, 0.3658380028813909441368980e-1, 0.3513153016547255590064132e-1, 0.3360086788611223267034862e-1, 0.3199522896404688727128174e-1, 0.3031819621886851919364104e-1, 0.2857351178293187118282268e-1, 0.2676506875425000190879332e-1, 0.2489690251475737263773110e-1, 0.2297318173532665591809836e-1, 0.2099819909186462577733052e-1, 0.1897636172277132593486659e-1, 0.1691218147224521718035102e-1, 0.1481026500273396017364296e-1, 0.1267530398126168187644599e-1, 0.1051206598770575465737803e-1, 0.8325388765990901416725080e-2, 0.6120192018447936365568516e-2, 0.3901625641744248259228942e-2, 0.1677653744007238599334225e-2}, {0.4584938738725097468656398e-1, 0.4575296541606795051900614e-1, 0.4556032425064828598070770e-1, 0.4527186901844377786941174e-1, 0.4488820634542666782635216e-1, 0.4441014308035275590934876e-1, 0.4383868459795605201060492e-1, 0.4317503268464422322584344e-1, 0.4242058301114249930061428e-1, 0.4157692219740291648457550e-1, 0.4064582447595407614088174e-1, 0.3962924796071230802540652e-1, 0.3852933052910671449325372e-1, 0.3734838532618666771607896e-1, 0.3608889590017987071497568e-1, 0.3475351097975151316679320e-1, 0.3334503890398068790314300e-1, 0.3186644171682106493934736e-1, 0.3032082893855398034157906e-1, 0.2871145102748499071080394e-1, 0.2704169254590396155797848e-1, 0.2531506504517639832390244e-1, 0.2353519968587633336129308e-1, 0.2170583961037807980146532e-1, 0.1983083208795549829102926e-1, 0.1791412045792315248940600e-1, 0.1595973590961380007213420e-1, 0.1397178917445765581596455e-1, 0.1195446231976944210322336e-1, 0.9912001251585937209131520e-2, 0.7848711393177167415052160e-2, 0.5768969918729952021468320e-2, 0.3677366595011730633570254e-2, 0.1581140256372912939103728e-2}, {0.4454941715975466720216750e-1, 0.4446096841724637082355728e-1, 0.4428424653905540677579966e-1, 0.4401960239018345875735580e-1, 0.4366756139720144025254848e-1, 0.4322882250506869978939520e-1, 0.4270425678944977776996576e-1, 0.4209490572728440602098398e-1, 0.4140197912904520863822652e-1, 0.4062685273678961635122600e-1, 0.3977106549277656747784952e-1, 0.3883631648407340397900292e-1, 0.3782446156922281719727230e-1, 0.3673750969367269534804046e-1, 0.3557761890129238053276980e-1, 0.3434709204990653756854510e-1, 0.3304837223937242047087430e-1, 0.3168403796130848173465310e-1, 0.3025679798015423781653688e-1, 0.2876948595580828066131070e-1, 0.2722505481866441715910742e-1, 0.2562657090846848279898494e-1, 0.2397720788910029227868640e-1, 0.2228024045225659583389064e-1, 0.2053903782432645338449270e-1, 0.1875705709313342341545081e-1, 0.1693783637630293253183738e-1, 0.1508498786544312768229492e-1, 0.1320219081467674762507440e-1, 0.1129318464993153764963015e-1, 0.9361762769699026811498692e-2, 0.7411769363190210362109460e-2, 0.5447111874217218312821680e-2, 0.3471894893078143254999524e-2, 0.1492721288844515731042666e-2}, {0.4332111216548653707639384e-1, 0.4323978130522261748526514e-1, 0.4307727227491369974525036e-1, 0.4283389016833881366683982e-1, 0.4251009191005772007780078e-1, 0.4210648539758646414658732e-1, 0.4162382836013859820760788e-1, 0.4106302693607506110193610e-1, 0.4042513397173397004332898e-1, 0.3971134704483490178239872e-1, 0.3892300621616966379996300e-1, 0.3806159151380216383437540e-1, 0.3712872015450289946055536e-1, 0.3612614350763799298563092e-1, 0.3505574380721787043413848e-1, 0.3391953061828605949719618e-1, 0.3271963706429384670431246e-1, 0.3145831582256181397777608e-1, 0.3013793489537547929298290e-1, 0.2876097316470176109512506e-1, 0.2733001573895093443379638e-1, 0.2584774910065589028389804e-1, 0.2431695606441916432634724e-1, 0.2274051055503575445593134e-1, 0.2112137221644055350981986e-1, 0.1946258086329427804301667e-1, 0.1776725078920065359435915e-1, 0.1603856495028515521816122e-1, 0.1427976905455419326655572e-1, 0.1249416561987375776778277e-1, 0.1068510816535189715895734e-1, 0.8855996073706153383956510e-2, 0.7010272321861863296081600e-2, 0.5151436018790886908248502e-2, 0.3283169774667495801897558e-2, 0.1411516393973434135715864e-2}, {0.4215870660994342212223066e-1, 0.4208374996915697247489576e-1, 0.4193396995777702146995522e-1, 0.4170963287924075437870998e-1, 0.4141113759675351082006810e-1, 0.4103901482412726684741876e-1, 0.4059392618219472805807676e-1, 0.4007666302247696675915112e-1, 0.3948814502019646832363280e-1, 0.3882941853913770775808220e-1, 0.3810165477126324889635168e-1, 0.3730614765439415573370658e-1, 0.3644431157165856448181076e-1, 0.3551767883680095992585374e-1, 0.3452789696982646100333388e-1, 0.3347672576782876626372244e-1, 0.3236603417621699952527994e-1, 0.3119779696591542603337254e-1, 0.2997409122246118733996502e-1, 0.2869709265326987534209508e-1, 0.2736907171967935230243778e-1, 0.2599238960072378786677346e-1, 0.2456949399594276724564910e-1, 0.2310291477491582303093246e-1, 0.2159525948167588896969968e-1, 0.2004920870279494425273506e-1, 0.1846751130897987978285368e-1, 0.1685297958202485358484807e-1, 0.1520848424340123480887426e-1, 0.1353694941178749434105245e-1, 0.1184134754749966732316814e-1, 0.1012469453828730542112095e-1, 0.8390045433971397064089364e-2, 0.6640492909114357634760192e-2, 0.4879179758594144584288316e-2, 0.3109420149896754678673688e-2, 0.1336761650069883550325931e-2}, {0.4105703691622942259325972e-1, 0.4098780546479395154130842e-1, 0.4084945930182849228039176e-1, 0.4064223171029473877745496e-1, 0.4036647212284402315409558e-1, 0.4002264553259682611646172e-1, 0.3961133170906205842314674e-1, 0.3913322422051844076750754e-1, 0.3858912926450673834292118e-1, 0.3797996430840528319523540e-1, 0.3730675654238160982756716e-1, 0.3657064114732961700724404e-1, 0.3577285938071394752777924e-1, 0.3491475648355076744412550e-1, 0.3399777941205638084674262e-1, 0.3302347439779174100654158e-1, 0.3199348434042160006853510e-1, 0.3090954603749159538993714e-1, 0.2977348725590504095670750e-1, 0.2858722365005400377397500e-1, 0.2735275553182752167415270e-1, 0.2607216449798598352427480e-1, 0.2474760992065967164326474e-1, 0.2338132530701118662247962e-1, 0.2197561453441624916801320e-1, 0.2053284796790802109297466e-1, 0.1905545846719058280680223e-1, 0.1754593729147423095419928e-1, 0.1600682991224857088850986e-1, 0.1444073174827667993988980e-1, 0.1285028384751014494492467e-1, 0.1123816856966768723967455e-1, 0.9607105414713754082404616e-2, 0.7959847477239734621118374e-2, 0.6299180497328445866575096e-2, 0.4627935228037421326126844e-2, 0.2949102953642474900394994e-2, 0.1267791634085359663272804e-2}, {0.4001146511842048298877858e-1, 0.3994739036908802487930490e-1, 0.3981934348036408922503176e-1, 0.3962752950781054295639346e-1, 0.3937225562423312193722022e-1, 0.3905393062777341314731136e-1, 0.3867306428725767400389548e-1, 0.3823026652585098764962036e-1, 0.3772624644432424786429014e-1, 0.3716181118549838685067108e-1, 0.3653786464168470064819248e-1, 0.3585540600719169544500572e-1, 0.3511552817821718947488010e-1, 0.3431941600268909029029166e-1, 0.3346834438285897797298150e-1, 0.3256367623368904440805548e-1, 0.3160686030030479773888294e-1, 0.3059942883801304528943330e-1, 0.2954299515860694641162030e-1, 0.2843925104689751626239046e-1, 0.2728996405162436486456432e-1, 0.2609697465510883502983394e-1, 0.2486219332622245076144308e-1, 0.2358759746145747209645146e-1, 0.2227522821911388676305032e-1, 0.2092718725187772678537816e-1, 0.1954563334339992337791787e-1, 0.1813277895498232864440684e-1, 0.1669088668934389186621294e-1, 0.1522226568017845169331591e-1, 0.1372926792014414839372596e-1, 0.1221428454978988639768250e-1, 0.1067974215748111335351669e-1, 0.9128099227255087276943326e-2, 0.7561843189439718826977318e-2, 0.5983489944440407989648850e-2, 0.4395596039460346742737866e-2, 0.2800868811838630411609396e-2, 0.1204024566067353280336448e-2}, {0.3901781365630665481128044e-1, 0.3895839596276953119862554e-1, 0.3883965105905196893177418e-1, 0.3866175977407646332707712e-1, 0.3842499300695942318521238e-1, 0.3812971131447763834420674e-1, 0.3777636436200139748977496e-1, 0.3736549023873049002670538e-1, 0.3689771463827600883915092e-1, 0.3637374990583597804396502e-1, 0.3579439395341605460286146e-1, 0.3516052904474759349552658e-1, 0.3447312045175392879436434e-1, 0.3373321498461152281667534e-1, 0.3294193939764540138283636e-1, 0.3210049867348777314805654e-1, 0.3121017418811470164244288e-1, 0.3027232175955798066122008e-1, 0.2928836958326784769276746e-1, 0.2825981605727686239675312e-1, 0.2718822750048638067441898e-1, 0.2607523576756511790296854e-1, 0.2492253576411549110511808e-1, 0.2373188286593010129319242e-1, 0.2250509024633246192622164e-1, 0.2124402611578200638871032e-1, 0.1995061087814199892889169e-1, 0.1862681420829903142873492e-1, 0.1727465205626930635858456e-1, 0.1589618358372568804490352e-1, 0.1449350804050907611696272e-1, 0.1306876159240133929378674e-1, 0.1162411412079782691646643e-1, 0.1016176604110306452083288e-1, 0.8683945269260858426408640e-2, 0.7192904768117312752674654e-2, 0.5690922451403198649270494e-2, 0.4180313124694895236739096e-2, 0.2663533589512681669292770e-2, 0.1144950003186941534544369e-2}, {0.3807230964014187120769602e-1, 0.3801710843143526990530278e-1, 0.3790678605050578477946422e-1, 0.3774150245427586967153708e-1, 0.3752149728818502087157412e-1, 0.3724708953872766418784006e-1, 0.3691867707095445699853162e-1, 0.3653673605160765284219780e-1, 0.3610182025872702307569544e-1, 0.3561456027872747268049598e-1, 0.3507566259211269038478042e-1, 0.3448590854915070550737888e-1, 0.3384615323699685874463648e-1, 0.3315732423990721132775848e-1, 0.3242042029434060507783656e-1, 0.3163650984090024553762352e-1, 0.3080672947521562981366802e-1, 0.2993228230001272463508596e-1, 0.2901443618076440396145302e-1, 0.2805452190745423047171398e-1, 0.2705393126512477151978662e-1, 0.2601411501601702375386842e-1, 0.2493658079624075515577230e-1, 0.2382289093004782634222678e-1, 0.2267466016491410310244200e-1, 0.2149355333077484404348958e-1, 0.2028128292691215890157032e-1, 0.1903960664017892507303976e-1, 0.1777032479849840714698234e-1, 0.1647527776398370889101217e-1, 0.1515634327076256178846848e-1, 0.1381543371412645938772740e-1, 0.1245449340114210467973318e-1, 0.1107549578175989632022419e-1, 0.9680440704371073736965104e-2, 0.8271351818383685604431294e-2, 0.6850274534183526184325356e-2, 0.5419276232446765090703842e-2, 0.3980457937856074619030326e-2, 0.2536054696856106109823094e-2, 0.1090118595275830866109234e-2}, {0.3717153701903406760328362e-1, 0.3712016261260209427372758e-1, 0.3701748480379452058524442e-1, 0.3686364550259030771845208e-1, 0.3665885732875907563657692e-1, 0.3640340331800212248862624e-1, 0.3609763653077256670175260e-1, 0.3574197956431530727788894e-1, 0.3533692396860127616038866e-1, 0.3488302956696330845641672e-1, 0.3438092368237270062133504e-1, 0.3383130027042598480372494e-1, 0.3323491896024044407471552e-1, 0.3259260400458425718361322e-1, 0.3190524314069272748402282e-1, 0.3117378636334566129196750e-1, 0.3039924461190246977311372e-1, 0.2958268837311084528960516e-1, 0.2872524620162180221266452e-1, 0.2782810316025840603576668e-1, 0.2689249918219763751581640e-1, 0.2591972735733464772516052e-1, 0.2491113214520642888439108e-1, 0.2386810751695823938471552e-1, 0.2279209502894212933888898e-1, 0.2168458183064482298924430e-1, 0.2054709860975627861152400e-1, 0.1938121747731880864780669e-1, 0.1818854979605654992760044e-1, 0.1697074395521161134308213e-1, 0.1572948309558359820159970e-1, 0.1446648278916118624227443e-1, 0.1318348867918234598679997e-1, 0.1188227408980122349505120e-1, 0.1056463762300824526484878e-1, 0.9232400784190247014382770e-2, 0.7887405752648146382107148e-2, 0.6531513687713654601121566e-2, 0.5166605182746808329881136e-2, 0.3794591650452349696393000e-2, 0.2417511265443122855238466e-2, 0.1039133516451971889197062e-2}, {0.3631239537581333828231516e-1, 0.3626450208420238743149194e-1, 0.3616877866860063758274494e-1, 0.3602535138093525771008956e-1, 0.3583440939092405578977942e-1, 0.3559620453657549559069116e-1, 0.3531105099203420508058466e-1, 0.3497932485321009937141316e-1, 0.3460146364173769225993442e-1, 0.3417796572791990463423808e-1, 0.3370938967341755486497158e-1, 0.3319635349455159712009034e-1, 0.3263953384718992195609868e-1, 0.3203966513429401611022852e-1, 0.3139753853730286555853332e-1, 0.3071400097263205318303994e-1, 0.2998995397466493249133840e-1, 0.2922635250670994458366154e-1, 0.2842420370149349475731242e-1, 0.2758456553285124838738412e-1, 0.2670854542037220957530654e-1, 0.2579729876883953540777106e-1, 0.2485202744439983591832606e-1, 0.2387397818947900497321768e-1, 0.2286444097854800644577274e-1, 0.2182474731692762780068420e-1, 0.2075626848490914279058154e-1, 0.1966041372956217980740210e-1, 0.1853862840670985920631482e-1, 0.1739239207569054238672012e-1, 0.1622321654972902258808405e-1, 0.1503264390508137868494523e-1, 0.1382224445276667086664874e-1, 0.1259361467806969781040954e-1, 0.1134837515617770397716730e-1, 0.1008816846038610565467284e-1, 0.8814657101954815703782366e-2, 0.7529521612194562606844596e-2, 0.6234459139140123463885784e-2, 0.4931184096960103696423408e-2, 0.3621439249610901437553882e-2, 0.2307087488809902925963262e-2, 0.9916432666203635255681510e-3}, {0.3549206430171454529606746e-1, 0.3544734460447076970614316e-1, 0.3535796155642384379366902e-1, 0.3522402777945910853287866e-1, 0.3504571202900426139658624e-1, 0.3482323898139935499312912e-1, 0.3455688895080708413486530e-1, 0.3424699753602007873736958e-1, 0.3389395519761025923989258e-1, 0.3349820676595309252806520e-1, 0.3306025088074670014528066e-1, 0.3258063936273210868623942e-1, 0.3205997651840638806926700e-1, 0.3149891837860489232004182e-1, 0.3089817187191219763370292e-1, 0.3025849393394352533513752e-1, 0.2958069055361934911335230e-1, 0.2886561575763542924647688e-1, 0.2811417053440861349157908e-1, 0.2732730169885533083562360e-1, 0.2650600069943473772140906e-1, 0.2565130236896194788477952e-1, 0.2476428362076873302532156e-1, 0.2384606209185966126357838e-1, 0.2289779473478114232724788e-1, 0.2192067635998985359563460e-1, 0.2091593813057662423225406e-1, 0.1988484601127411324360109e-1, 0.1882869917375545139470985e-1, 0.1774882836032407455649534e-1, 0.1664659420821765604511323e-1, 0.1552338553693355384016474e-1, 0.1438061760129994423593466e-1, 0.1321973031362791170818164e-1, 0.1204218643958121230973900e-1, 0.1084946977542927125940107e-1, 0.9643083322053204400769368e-2, 0.8424547492702473015098308e-2, 0.7195398459796372059759572e-2, 0.5957186996138046583131162e-2, 0.4711479279598661743021848e-2, 0.3459867667862796423976646e-2, 0.2204058563143696628535344e-2, 0.9473355981619272667700360e-3}, {0.3470797248895005792046014e-1, 0.3466615208568824018827232e-1, 0.3458256166949689141805380e-1, 0.3445730196032425617459566e-1, 0.3429052388637504193169728e-1, 0.3408242840225399546360508e-1, 0.3383326624683168725792750e-1, 0.3354333764112427668293316e-1, 0.3321299192655131651404080e-1, 0.3284262714400750457863018e-1, 0.3243268955425561691178950e-1, 0.3198367310021857603945600e-1, 0.3149611881181863607695780e-1, 0.3097061415408092094593650e-1, 0.3040779231928695269039426e-1, 0.2980833146403127548714788e-1, 0.2917295389210074248655798e-1, 0.2850242518416141631875546e-1, 0.2779755327530227515803874e-1, 0.2705918748154795852161408e-1, 0.2628821747651458736159580e-1, 0.2548557221944322848446706e-1, 0.2465221883590485293596628e-1, 0.2378916145252872321010090e-1, 0.2289743998716318463498862e-1, 0.2197812889593413383869188e-1, 0.2103233587872256311706242e-1, 0.2006120054463959596453232e-1, 0.1906589303913731842532399e-1, 0.1804761263446023616404962e-1, 0.1700758628522267570939747e-1, 0.1594706715100663901320649e-1, 0.1486733308804332405038481e-1, 0.1376968511233709343075118e-1, 0.1265544583716812886887583e-1, 0.1152595788914805885059348e-1, 0.1038258230989321461380844e-1, 0.9226696957741990940319884e-2, 0.8059694944620015658670990e-2, 0.6882983208463284314729370e-2, 0.5697981560747352600849438e-2, 0.4506123613674977864136850e-2, 0.3308867243336018195431340e-2, 0.2107778774526329891473788e-2, 0.9059323712148330937360098e-3}, {0.3395777082810234796700260e-1, 0.3391860442372254949502722e-1, 0.3384031678893360189141840e-1, 0.3372299821957387169380074e-1, 0.3356678402920367631007550e-1, 0.3337185439303681030780114e-1, 0.3313843414012938182262046e-1, 0.3286679249406566032646806e-1, 0.3255724276244004524316198e-1, 0.3221014197549332953574452e-1, 0.3182589047432008582597260e-1, 0.3140493144912217791614030e-1, 0.3094775042804103166804096e-1, 0.3045487471715832098063528e-1, 0.2992687279231107330786762e-1, 0.2936435364342281261274650e-1, 0.2876796607210717582237958e-1, 0.2813839794335440451445112e-1, 0.2747637539216417339517938e-1, 0.2678266198604032330048838e-1, 0.2605805784431417922245786e-1, 0.2530339871531322569754810e-1, 0.2451955501244097425717108e-1, 0.2370743081028191239353720e-1, 0.2286796280189254240434106e-1, 0.2200211921848585739874382e-1, 0.2111089871276246180997612e-1, 0.2019532920718748374956428e-1, 0.1925646670855947471237209e-1, 0.1829539409026755729118717e-1, 0.1731321984368977636114053e-1, 0.1631107680025595800481463e-1, 0.1529012082579650150690625e-1, 0.1425152948895392526580707e-1, 0.1319650070571113802911160e-1, 0.1212625136263771052929676e-1, 0.1104201592263539422398575e-1, 0.9945045019726082041770092e-2, 0.8836604056467877374547944e-2, 0.7717971837373568504533128e-2, 0.6590439334214895223179124e-2, 0.5455308908000870987158870e-2, 0.4313895331861700472339122e-2, 0.3167535943396097874261610e-2, 0.2017671366262838591883234e-2, 0.8671851787671421353540866e-3}, {0.3323930891781532080070524e-1, 0.3320257661860686379876634e-1, 0.3312915261254696321600516e-1, 0.3301911803949165507667076e-1, 0.3287259449712959072614770e-1, 0.3268974390660630715252838e-1, 0.3247076833358767948450850e-1, 0.3221590976496030711281812e-1, 0.3192544984141561392584074e-1, 0.3159970954621320046477392e-1, 0.3123904885046741788219108e-1, 0.3084386631534918741110674e-1, 0.3041459865164271220328128e-1, 0.2995172023714386920008800e-1, 0.2945574259243367639719146e-1, 0.2892721381560625584227516e-1, 0.2836671797657610681272962e-1, 0.2777487447163422062065088e-1, 0.2715233733896656472388262e-1, 0.2649979453589169919669406e-1, 0.2581796717861672816440260e-1, 0.2510760874535240512858038e-1, 0.2436950424366898830634656e-1, 0.2360446934301438228050796e-1, 0.2281334947335523641001192e-1, 0.2199701889094007717339700e-1, 0.2115637971222138981504522e-1, 0.2029236091701113217988866e-1, 0.1940591732198200488605189e-1, 0.1849802852566591095380957e-1, 0.1756969782614325199872555e-1, 0.1662195111266549663832874e-1, 0.1565583573251555786002188e-1, 0.1467241933449946420426407e-1, 0.1367278869060687850644038e-1, 0.1265804849763899444482439e-1, 0.1162932016112241459607371e-1, 0.1058774056495412223672440e-1, 0.9534460832865158250063918e-2, 0.8470645094534635999910406e-2, 0.7397469288142356200862272e-2, 0.6316120091036448223107804e-2, 0.5227794289507767545307002e-2, 0.4133699875407776483295790e-2, 0.3035065891038628027389626e-2, 0.1933219888725418943121000e-2, 0.8308716126821624946495838e-3}, {0.3255061449236316624196142e-1, 0.3251611871386883598720548e-1, 0.3244716371406426936401278e-1, 0.3234382256857592842877486e-1, 0.3220620479403025066866710e-1, 0.3203445623199266321813896e-1, 0.3182875889441100653475374e-1, 0.3158933077072716855802074e-1, 0.3131642559686135581278434e-1, 0.3101033258631383742324982e-1, 0.3067137612366914901422878e-1, 0.3029991542082759379408878e-1, 0.2989634413632838598438796e-1, 0.2946108995816790597043632e-1, 0.2899461415055523654267862e-1, 0.2849741106508538564559948e-1, 0.2797000761684833443981840e-1, 0.2741296272602924282342110e-1, 0.2682686672559176219805676e-1, 0.2621234073567241391345816e-1, 0.2557003600534936149879724e-1, 0.2490063322248361028838244e-1, 0.2420484179236469128226730e-1, 0.2348339908592621984223612e-1, 0.2273706965832937400134754e-1, 0.2196664443874434919475618e-1, 0.2117293989219129898767356e-1, 0.2035679715433332459524556e-1, 0.1951908114014502241008485e-1, 0.1866067962741146738515655e-1, 0.1778250231604526083761406e-1, 0.1688547986424517245047785e-1, 0.1597056290256229138061685e-1, 0.1503872102699493800587588e-1, 0.1409094177231486091586166e-1, 0.1312822956696157263706415e-1, 0.1215160467108831963518178e-1, 0.1116210209983849859121361e-1, 0.1016077053500841575758671e-1, 0.9148671230783386632584044e-2, 0.8126876925698759217383246e-2, 0.7096470791153865269143206e-2, 0.6058545504235961683315686e-2, 0.5014202742927517692471308e-2, 0.3964554338444686673733524e-2, 0.2910731817934946408411678e-2, 0.1853960788946921732331620e-2, 0.7967920655520124294367096e-3}, {0.3188987535287646727794502e-1, 0.3185743815812401071309920e-1, 0.3179259676252863019831786e-1, 0.3169541712034925160907410e-1, 0.3156599807910805290145092e-1, 0.3140447127904656151748860e-1, 0.3121100101922626441684056e-1, 0.3098578409040993463104290e-1, 0.3072904957489366992001356e-1, 0.3044105861349325839490764e-1, 0.3012210413992189884853100e-1, 0.2977251058282947626617570e-1, 0.2939263353580649216776328e-1, 0.2898285939568834204744914e-1, 0.2854360496952788570349054e-1, 0.2807531705063613875324586e-1, 0.2757847196412239390009986e-1, 0.2705357508239612827767608e-1, 0.2650116031112363935248738e-1, 0.2592178954616244891846836e-1, 0.2531605210202609734314644e-1, 0.2468456411246099618197954e-1, 0.2402796790374549880324124e-1, 0.2334693134134927471268304e-1, 0.2264214715061843311126274e-1, 0.2191433221217865041901888e-1, 0.2116422683277485691127980e-1, 0.2039259399229191457948346e-1, 0.1960021856772633077323700e-1, 0.1878790653490468656148738e-1, 0.1795648414877062812244296e-1, 0.1710679710308990026235402e-1, 0.1623970967045369565272614e-1, 0.1535610382349775576849818e-1, 0.1445687833830440197756895e-1, 0.1354294788102946514364726e-1, 0.1261524207892195285778215e-1, 0.1167470457713812428742924e-1, 0.1072229208322431712024324e-1, 0.9758973402174096835348026e-2, 0.8785728467392263202699392e-2, 0.7803547379100754890979542e-2, 0.6813429479165215998771186e-2, 0.5816382546439639112764538e-2, 0.4813422398586770918478190e-2, 0.3805574085352359565512666e-2, 0.2793881135722130870629084e-2, 0.1779477041014528741695358e-2, 0.7647669822743134580383448e-3}, {0.3125542345386335694764248e-1, 0.3122488425484935773237650e-1, 0.3116383569620990678381832e-1, 0.3107233742756651658781016e-1, 0.3095047885049098823406346e-1, 0.3079837903115259042771392e-1, 0.3061618658398044849645950e-1, 0.3040407952645482001650792e-1, 0.3016226510516914491906862e-1, 0.2989097959333283091683684e-1, 0.2959048805991264251175454e-1, 0.2926108411063827662011896e-1, 0.2890308960112520313487610e-1, 0.2851685432239509799093676e-1, 0.2810275565910117331764820e-1, 0.2766119822079238829420408e-1, 0.2719261344657688013649158e-1, 0.2669745918357096266038448e-1, 0.2617621923954567634230892e-1, 0.2562940291020811607564182e-1, 0.2505754448157958970376402e-1, 0.2446120270795705271997480e-1, 0.2384096026596820596256040e-1, 0.2319742318525412162248878e-1, 0.2253122025633627270179672e-1, 0.2184300241624738631395360e-1, 0.2113344211252764154267220e-1, 0.2040323264620943276683910e-1, 0.1965308749443530586538157e-1, 0.1888373961337490455294131e-1, 0.1809594072212811666439111e-1, 0.1729046056832358243934388e-1, 0.1646808617614521264310506e-1, 0.1562962107754600272393719e-1, 0.1477588452744130176887969e-1, 0.1390771070371877268795387e-1, 0.1302594789297154228555807e-1, 0.1213145766297949740774437e-1, 0.1122511402318597711722209e-1, 0.1030780257486896958578198e-1, 0.9380419653694457951417628e-2, 0.8443871469668971402620252e-2, 0.7499073255464711578829804e-2, 0.6546948450845322764152444e-2, 0.5588428003865515157213478e-2, 0.4624450063422119351093868e-2, 0.3655961201326375182342828e-2, 0.2683925371553482419437272e-2, 0.1709392653518105239533969e-2, 0.7346344905056717304142370e-3}, } var oddWeights = [][]float64{ {0.5555555555555555555555555}, {0.4786286704993664680412916e0, 0.2369268850561890875142644e0}, {0.3818300505051189449503698e0, 0.2797053914892766679014680e0, 0.1294849661688696932706118e0}, {0.3123470770400028400686304e0, 0.2606106964029354623187428e0, 0.1806481606948574040584721e0, 0.8127438836157441197189206e-1}, {0.2628045445102466621806890e0, 0.2331937645919904799185238e0, 0.1862902109277342514260979e0, 0.1255803694649046246346947e0, 0.5566856711617366648275374e-1}, {0.2262831802628972384120902e0, 0.2078160475368885023125234e0, 0.1781459807619457382800468e0, 0.1388735102197872384636019e0, 0.9212149983772844791442126e-1, 0.4048400476531587952001996e-1}, {0.1984314853271115764561182e0, 0.1861610000155622110268006e0, 0.1662692058169939335532006e0, 0.1395706779261543144478051e0, 0.1071592204671719350118693e0, 0.7036604748810812470926662e-1, 0.3075324199611726835462762e-1}, {0.1765627053669926463252710e0, 0.1680041021564500445099705e0, 0.1540457610768102880814317e0, 0.1351363684685254732863199e0, 0.1118838471934039710947887e0, 0.8503614831717918088353538e-1, 0.5545952937398720112944102e-1, 0.2414830286854793196010920e-1}, {0.1589688433939543476499565e0, 0.1527660420658596667788553e0, 0.1426067021736066117757460e0, 0.1287539625393362276755159e0, 0.1115666455473339947160242e0, 0.9149002162244999946446222e-1, 0.6904454273764122658070790e-1, 0.4481422676569960033283728e-1, 0.1946178822972647703631351e-1}, {0.1445244039899700590638271e0, 0.1398873947910731547221335e0, 0.1322689386333374617810526e0, 0.1218314160537285341953671e0, 0.1087972991671483776634747e0, 0.9344442345603386155329010e-1, 0.7610011362837930201705132e-1, 0.5713442542685720828363528e-1, 0.3695378977085249379995034e-1, 0.1601722825777433332422273e-1}, {0.1324620394046966173716425e0, 0.1289057221880821499785954e0, 0.1230490843067295304675784e0, 0.1149966402224113649416434e0, 0.1048920914645414100740861e0, 0.9291576606003514747701876e-1, 0.7928141177671895492289248e-1, 0.6423242140852585212716980e-1, 0.4803767173108466857164124e-1, 0.3098800585697944431069484e-1, 0.1341185948714177208130864e-1}, {0.1222424429903100416889594e0, 0.1194557635357847722281782e0, 0.1148582591457116483393255e0, 0.1085196244742636531160939e0, 0.1005359490670506442022068e0, 0.9102826198296364981149704e-1, 0.8014070033500101801323524e-1, 0.6803833381235691720718712e-1, 0.5490469597583519192593686e-1, 0.4093915670130631265562402e-1, 0.2635498661503213726190216e-1, 0.1139379850102628794789998e-1}, {0.1134763461089651486203700e0, 0.1112524883568451926721632e0, 0.1075782857885331872121629e0, 0.1025016378177457986712478e0, 0.9608872737002850756565252e-1, 0.8842315854375695019432262e-1, 0.7960486777305777126307488e-1, 0.6974882376624559298432254e-1, 0.5898353685983359911030058e-1, 0.4744941252061506270409646e-1, 0.3529705375741971102257772e-1, 0.2268623159618062319603554e-1, 0.9798996051294360261149438e-2}, {0.1058761550973209414065914e0, 0.1040733100777293739133284e0, 0.1010912737599149661218204e0, 0.9696383409440860630190016e-1, 0.9173775713925876334796636e-1, 0.8547225736617252754534480e-1, 0.7823832713576378382814484e-1, 0.7011793325505127856958160e-1, 0.6120309065707913854210970e-1, 0.5159482690249792391259412e-1, 0.4140206251868283610482948e-1, 0.3074049220209362264440778e-1, 0.1973208505612270598385931e-1, 0.8516903878746409654261436e-2}, {0.9922501122667230787487546e-1, 0.9774333538632872509347402e-1, 0.9529024291231951280720412e-1, 0.9189011389364147821536290e-1, 0.8757674060847787612619794e-1, 0.8239299176158926390382334e-1, 0.7639038659877661642635764e-1, 0.6962858323541036616775632e-1, 0.6217478656102842691034334e-1, 0.5410308242491685371166596e-1, 0.4549370752720110290231576e-1, 0.3643227391238546402439264e-1, 0.2700901918497942180060860e-1, 0.1731862079031058246315918e-1, 0.7470831579248775858700554e-2}, {0.9335642606559611616099912e-1, 0.9212398664331684621324104e-1, 0.9008195866063857723974370e-1, 0.8724828761884433760728158e-1, 0.8364787606703870761392808e-1, 0.7931236479488673836390848e-1, 0.7427985484395414934247216e-1, 0.6859457281865671280595482e-1, 0.6230648253031748003162750e-1, 0.5547084663166356128494468e-1, 0.4814774281871169567014706e-1, 0.4040154133166959156340938e-1, 0.3230035863232895328156104e-1, 0.2391554810174948035053310e-1, 0.1532170151293467612794584e-1, 0.6606227847587378058647800e-2}, {0.8814053043027546297073886e-1, 0.8710444699718353424332214e-1, 0.8538665339209912522594402e-1, 0.8300059372885658837992644e-1, 0.7996494224232426293266204e-1, 0.7630345715544205353865872e-1, 0.7204479477256006466546180e-1, 0.6722228526908690396430546e-1, 0.6187367196608018888701398e-1, 0.5604081621237012857832772e-1, 0.4976937040135352980519956e-1, 0.4310842232617021878230592e-1, 0.3611011586346338053271748e-1, 0.2882926010889425404871630e-1, 0.2132297991148358088343844e-1, 0.1365082834836149226640441e-1, 0.5883433420443084975750336e-2}, {0.8347457362586278725225302e-1, 0.8259527223643725089123018e-1, 0.8113662450846503050987774e-1, 0.7910886183752938076721222e-1, 0.7652620757052923788588804e-1, 0.7340677724848817272462668e-1, 0.6977245155570034488508154e-1, 0.6564872287275124948402376e-1, 0.6106451652322598613098804e-1, 0.5605198799827491780853916e-1, 0.5064629765482460160387558e-1, 0.4488536466243716665741054e-1, 0.3880960250193454448896226e-1, 0.3246163984752148106723444e-1, 0.2588603699055893352275954e-1, 0.1912904448908396604350259e-1, 0.1223878010030755652630649e-1, 0.5273057279497939351724544e-2}, {0.7927622256836847101015574e-1, 0.7852361328737117672506330e-1, 0.7727455254468201672851160e-1, 0.7553693732283605770478448e-1, 0.7332175341426861738115402e-1, 0.7064300597060876077011486e-1, 0.6751763096623126536302120e-1, 0.6396538813868238898670650e-1, 0.6000873608859614957494160e-1, 0.5567269034091629990739094e-1, 0.5098466529212940521402098e-1, 0.4597430110891663188417682e-1, 0.4067327684793384393905618e-1, 0.3511511149813133076106530e-1, 0.2933495598390337859215654e-1, 0.2336938483217816459471240e-1, 0.1725622909372491904080491e-1, 0.1103478893916459424267603e-1, 0.4752944691635101370775866e-2}, {0.7547874709271582402724706e-1, 0.7482962317622155189130518e-1, 0.7375188202722346993928094e-1, 0.7225169686102307339634646e-1, 0.7033766062081749748165896e-1, 0.6802073676087676673553342e-1, 0.6531419645352741043616384e-1, 0.6223354258096631647157330e-1, 0.5879642094987194499118590e-1, 0.5502251924257874188014710e-1, 0.5093345429461749478117008e-1, 0.4655264836901434206075674e-1, 0.4190519519590968942934048e-1, 0.3701771670350798843526154e-1, 0.3191821173169928178706676e-1, 0.2663589920711044546754900e-1, 0.2120106336877955307569710e-1, 0.1564493840781858853082666e-1, 0.9999938773905945338496546e-2, 0.4306140358164887684003630e-2}, {0.7202750197142197434530754e-1, 0.7146373425251414129758106e-1, 0.7052738776508502812628636e-1, 0.6922334419365668428229950e-1, 0.6755840222936516919240796e-1, 0.6554124212632279749123378e-1, 0.6318238044939611232562970e-1, 0.6049411524999129451967862e-1, 0.5749046195691051942760910e-1, 0.5418708031888178686337342e-1, 0.5060119278439015652385048e-1, 0.4675149475434658001064704e-1, 0.4265805719798208376380686e-1, 0.3834222219413265757212856e-1, 0.3382649208686029234496834e-1, 0.2913441326149849491594084e-1, 0.2429045661383881590201850e-1, 0.1931990142368390039612543e-1, 0.1424875643157648610854214e-1, 0.9103996637401403318866628e-2, 0.3919490253844127282968528e-2}, {0.6887731697766132288200278e-1, 0.6838457737866967453169206e-1, 0.6756595416360753627091012e-1, 0.6642534844984252808291474e-1, 0.6496819575072343085382664e-1, 0.6320144007381993774996374e-1, 0.6113350083106652250188634e-1, 0.5877423271884173857436156e-1, 0.5613487875978647664392382e-1, 0.5322801673126895194590376e-1, 0.5006749923795202979913194e-1, 0.4666838771837336526776814e-1, 0.4304688070916497115169120e-1, 0.3922023672930244756418756e-1, 0.3520669220160901624770010e-1, 0.3102537493451546716250854e-1, 0.2669621396757766480567536e-1, 0.2223984755057873239395080e-1, 0.1767753525793759061709347e-1, 0.1303110499158278432063191e-1, 0.8323189296218241645734836e-2, 0.3582663155283558931145652e-2}, {0.6599053358881047453357062e-1, 0.6555737776654974025114294e-1, 0.6483755623894572670260402e-1, 0.6383421660571703063129384e-1, 0.6255174622092166264056434e-1, 0.6099575300873964533071060e-1, 0.5917304094233887597615438e-1, 0.5709158029323154022201646e-1, 0.5476047278153022595712512e-1, 0.5218991178005714487221170e-1, 0.4939113774736116960457022e-1, 0.4637638908650591120440168e-1, 0.4315884864847953826830162e-1, 0.3975258612253100378090162e-1, 0.3617249658417495161345948e-1, 0.3243423551518475676761786e-1, 0.2855415070064338650473990e-1, 0.2454921165965881853783378e-1, 0.2043693814766842764203432e-1, 0.1623533314643305967072624e-1, 0.1196284846431232096394232e-1, 0.7638616295848833614105174e-2, 0.3287453842528014883248206e-2}, {0.6333550929649174859083696e-1, 0.6295270746519569947439960e-1, 0.6231641732005726740107682e-1, 0.6142920097919293629682652e-1, 0.6029463095315201730310616e-1, 0.5891727576002726602452756e-1, 0.5730268153018747548516450e-1, 0.5545734967480358869043158e-1, 0.5338871070825896852794302e-1, 0.5110509433014459067462262e-1, 0.4861569588782824027765094e-1, 0.4593053935559585354249958e-1, 0.4306043698125959798834538e-1, 0.4001694576637302136860494e-1, 0.3681232096300068981946734e-1, 0.3345946679162217434248744e-1, 0.2997188462058382535069014e-1, 0.2636361892706601696094518e-1, 0.2264920158744667649877160e-1, 0.1884359585308945844445106e-1, 0.1496214493562465102958377e-1, 0.1102055103159358049750846e-1, 0.7035099590086451473452956e-2, 0.3027278988922905077484090e-2}, {0.6088546484485634388119860e-1, 0.6054550693473779513812526e-1, 0.5998031577750325209006396e-1, 0.5919199392296154378353896e-1, 0.5818347398259214059843780e-1, 0.5695850772025866210007778e-1, 0.5552165209573869301673704e-1, 0.5387825231304556143409938e-1, 0.5203442193669708756413650e-1, 0.4999702015005740977954886e-1, 0.4777362624062310199999514e-1, 0.4537251140765006874816670e-1, 0.4280260799788008665360980e-1, 0.4007347628549645318680892e-1, 0.3719526892326029284290846e-1, 0.3417869320418833623620910e-1, 0.3103497129016000845442504e-1, 0.2777579859416247719599602e-1, 0.2441330057378143427314164e-1, 0.2095998840170321057979252e-1, 0.1742871472340105225950284e-1, 0.1383263400647782229668883e-1, 0.1018519129782172993923731e-1, 0.6500337783252600292109494e-2, 0.2796807171089895575547228e-2}, {0.5861758623272026331807196e-1, 0.5831431136225600755627570e-1, 0.5781001499171319631968304e-1, 0.5710643553626719177338328e-1, 0.5620599838173970980865512e-1, 0.5511180752393359900234954e-1, 0.5382763486873102904208140e-1, 0.5235790722987271819970160e-1, 0.5070769106929271529648556e-1, 0.4888267503269914042044844e-1, 0.4688915034075031402187278e-1, 0.4473398910367281021276570e-1, 0.4242462063452001359228150e-1, 0.3996900584354038212709364e-1, 0.3737560980348291567417214e-1, 0.3465337258353423795838740e-1, 0.3181167845901932306323576e-1, 0.2886032361782373626279970e-1, 0.2580948251075751771396152e-1, 0.2266967305707020839878928e-1, 0.1945172110763689538804750e-1, 0.1616672525668746392806095e-1, 0.1282602614424037917915135e-1, 0.9441202284940344386662890e-2, 0.6024276226948673281242120e-2, 0.2591683720567031811603734e-2}, {0.5651231824977200140065834e-1, 0.5624063407108436802827906e-1, 0.5578879419528408710293598e-1, 0.5515824600250868759665114e-1, 0.5435100932991110207032224e-1, 0.5336967000160547272357054e-1, 0.5221737154563208456439348e-1, 0.5089780512449397922477522e-1, 0.4941519771155173948075862e-1, 0.4777429855120069555003682e-1, 0.4598036394628383810390480e-1, 0.4403914042160658989516800e-1, 0.4195684631771876239520718e-1, 0.3974015187433717960946388e-1, 0.3739615786796554528291572e-1, 0.3493237287358988740726862e-1, 0.3235668922618583168470572e-1, 0.2967735776516104122129630e-1, 0.2690296145639627066711996e-1, 0.2404238800972562200779126e-1, 0.2110480166801645412020978e-1, 0.1809961452072906240796732e-1, 0.1503645833351178821315019e-1, 0.1192516071984861217075236e-1, 0.8775746107058528177390204e-2, 0.5598632266560767354082364e-2, 0.2408323619979788819164582e-2}, {0.5455280360476188648013898e-1, 0.5430847145249864313874678e-1, 0.5390206148329857464280950e-1, 0.5333478658481915842657698e-1, 0.5260833972917743244023134e-1, 0.5172488892051782472062386e-1, 0.5068707072492740865664050e-1, 0.4949798240201967899383808e-1, 0.4816117266168775126885110e-1, 0.4668063107364150378384082e-1, 0.4506077616138115779721374e-1, 0.4330644221621519659643210e-1, 0.4142286487080111036319668e-1, 0.3941566547548011408995280e-1, 0.3729083432441731735473546e-1, 0.3505471278231261750575064e-1, 0.3271397436637156854248994e-1, 0.3027560484269399945849064e-1, 0.2774688140218019232125814e-1, 0.2513535099091812264727322e-1, 0.2244880789077643807968978e-1, 0.1969527069948852038242318e-1, 0.1688295902344154903500062e-1, 0.1402027079075355617024753e-1, 0.1111576373233599014567619e-1, 0.8178160067821232626211086e-2, 0.5216533474718779390504886e-2, 0.2243753872250662909727492e-2}, {0.5272443385912793196130422e-1, 0.5250390264782873905094128e-1, 0.5213703364837539138398724e-1, 0.5162484939089148214644000e-1, 0.5096877742539391685024800e-1, 0.5017064634299690281072034e-1, 0.4923268067936198577969374e-1, 0.4815749471460644038814684e-1, 0.4694808518696201919315986e-1, 0.4560782294050976983186828e-1, 0.4414044353029738069079808e-1, 0.4255003681106763866730838e-1, 0.4084103553868670766020196e-1, 0.3901820301616000950303072e-1, 0.3708661981887092269183778e-1, 0.3505166963640010878371850e-1, 0.3291902427104527775751116e-1, 0.3069462783611168323975056e-1, 0.2838468020053479790515332e-1, 0.2599561973129850018665014e-1, 0.2353410539371336342527500e-1, 0.2100699828843718735046168e-1, 0.1842134275361002936061624e-1, 0.1578434731308146614732024e-1, 0.1310336630634519101831859e-1, 0.1038588550099586219379846e-1, 0.7639529453487575142699186e-2, 0.4872239168265284768580414e-2, 0.2095492284541223402697724e-2}, {0.5101448703869726354373512e-1, 0.5081476366881834320770052e-1, 0.5048247038679740464814450e-1, 0.5001847410817825342505160e-1, 0.4942398534673558993996884e-1, 0.4870055505641152608753004e-1, 0.4785007058509560716183348e-1, 0.4687475075080906597642932e-1, 0.4577714005314595937133982e-1, 0.4456010203508348827154136e-1, 0.4322681181249609790104358e-1, 0.4178074779088849206667564e-1, 0.4022568259099824736764020e-1, 0.3856567320700817274615216e-1, 0.3680505042315481738432126e-1, 0.3494840751653335109085198e-1, 0.3300058827590741063272390e-1, 0.3096667436839739482469792e-1, 0.2885197208818340150434184e-1, 0.2666199852415088966281066e-1, 0.2440246718754420291534050e-1, 0.2207927314831904400247522e-1, 0.1969847774610118133051782e-1, 0.1726629298761374359443389e-1, 0.1478906588493791454617878e-1, 0.1227326350781210462927897e-1, 0.9725461830356133736135366e-2, 0.7152354991749089585834616e-2, 0.4560924006012417184541648e-2, 0.1961453361670282671779431e-2}, {0.4941183303991817896703964e-1, 0.4923038042374756078504314e-1, 0.4892845282051198994470936e-1, 0.4850678909788384786409014e-1, 0.4796642113799513141105276e-1, 0.4730867131226891908060508e-1, 0.4653514924538369651039536e-1, 0.4564774787629260868588592e-1, 0.4464863882594139537033256e-1, 0.4354026708302759079896428e-1, 0.4232534502081582298250554e-1, 0.4100684575966639863511004e-1, 0.3958799589154409398480778e-1, 0.3807226758434955676363856e-1, 0.3646337008545728963045232e-1, 0.3476524064535587769718026e-1, 0.3298203488377934176568344e-1, 0.3111811662221981750821608e-1, 0.2917804720828052694555162e-1, 0.2716657435909793322519012e-1, 0.2508862055334498661862972e-1, 0.2294927100488993314894282e-1, 0.2075376125803909077534152e-1, 0.1850746446016127040926083e-1, 0.1621587841033833888228333e-1, 0.1388461261611561082486681e-1, 0.1151937607688004175075116e-1, 0.9125968676326656354058462e-2, 0.6710291765960136251908410e-2, 0.4278508346863761866081200e-2, 0.1839874595577084117085868e-2}, {0.4790669250049586203134730e-1, 0.4774134868124062155903898e-1, 0.4746619823288550315264446e-1, 0.4708187401045452224600686e-1, 0.4658925997223349830225508e-1, 0.4598948914665169696389334e-1, 0.4528394102630023065712822e-1, 0.4447423839508297442732352e-1, 0.4356224359580048653228480e-1, 0.4255005424675580271921714e-1, 0.4143999841724029302268646e-1, 0.4023462927300553381544642e-1, 0.3893671920405119761667398e-1, 0.3754925344825770980977246e-1, 0.3607542322556527393216642e-1, 0.3451861839854905862522142e-1, 0.3288241967636857498404946e-1, 0.3117059038018914246443218e-1, 0.2938706778931066806264472e-1, 0.2753595408845034394249940e-1, 0.2562150693803775821408458e-1, 0.2364812969128723669878144e-1, 0.2162036128493406284165378e-1, 0.1954286583675006282683714e-1, 0.1742042199767024849536596e-1, 0.1525791214644831034926464e-1, 0.1306031163999484633616732e-1, 0.1083267878959796862151440e-1, 0.8580148266881459893636434e-2, 0.6307942578971754550189764e-2, 0.4021524172003736347075858e-2, 0.1729258251300250898337759e-2}, {0.4649043816026462820831466e-1, 0.4633935168241562110844706e-1, 0.4608790448976157619721740e-1, 0.4573664116106369093689412e-1, 0.4528632245466953156805004e-1, 0.4473792366088982547214182e-1, 0.4409263248975101830783160e-1, 0.4335184649869951735915584e-1, 0.4251717006583049147154770e-1, 0.4159041091519924309854838e-1, 0.4057357620174452522725164e-1, 0.3946886816430888264288692e-1, 0.3827867935617948064763712e-1, 0.3700558746349258202313488e-1, 0.3565234972274500666133270e-1, 0.3422189694953664673983902e-1, 0.3271732719153120542712204e-1, 0.3114189901947282393742616e-1, 0.2949902447094566969584718e-1, 0.2779226166243676998720012e-1, 0.2602530708621323880370460e-1, 0.2420198760967316472069180e-1, 0.2232625219645207692279754e-1, 0.2040216337134354044925720e-1, 0.1843388845680457387216616e-1, 0.1642569062253087920472674e-1, 0.1438191982720055093097663e-1, 0.1230700384928815052195302e-1, 0.1020544003410244098666155e-1, 0.8081790299023136215346300e-2, 0.5940693177582235216514606e-2, 0.3787008301825508445960626e-2, 0.1628325035240012866460003e-2}, {0.4515543023614546051651704e-1, 0.4501700814039980219871620e-1, 0.4478661887831255754213528e-1, 0.4446473312204713809623108e-1, 0.4405200846590928438098588e-1, 0.4354928808292674103357578e-1, 0.4295759900230521387841984e-1, 0.4227815001128051285158270e-1, 0.4151232918565450208287406e-1, 0.4066170105406160053752604e-1, 0.3972800340176164120645862e-1, 0.3871314372049251393273936e-1, 0.3761919531164090650815840e-1, 0.3644839305070051405664348e-1, 0.3520312882168348614775456e-1, 0.3388594663083228949780964e-1, 0.3249953740964611124473418e-1, 0.3104673351789053903268552e-1, 0.2953050295790671177981110e-1, 0.2795394331218770599086132e-1, 0.2632027541686948379176090e-1, 0.2463283678454245536433616e-1, 0.2289507479074078565552120e-1, 0.2111053963987189462789068e-1, 0.1928287712884940278924393e-1, 0.1741582123196982913207401e-1, 0.1551318654340616473976910e-1, 0.1357886064907567099981112e-1, 0.1161679661067196554873961e-1, 0.9631006150415575588660562e-2, 0.7625555931201510611459992e-2, 0.5604579927870594828535346e-2, 0.3572416739397372609702552e-2, 0.1535976952792084075135094e-2}, {0.4389487921178858632125256e-1, 0.4376774491340214497230982e-1, 0.4355612710410853337113396e-1, 0.4326043426324126659885626e-1, 0.4288123715758043502060704e-1, 0.4241926773962459303533940e-1, 0.4187541773473300618954268e-1, 0.4125073691986602424910896e-1, 0.4054643109724689643492514e-1, 0.3976385976685758167433708e-1, 0.3890453350226294749240264e-1, 0.3797011103483115621441804e-1, 0.3696239605198203185608278e-1, 0.3588333371564891077796844e-1, 0.3473500690768218837536532e-1, 0.3351963220945403083440624e-1, 0.3223955562344352694190700e-1, 0.3089724804509072169860608e-1, 0.2949530049370881246493644e-1, 0.2803641911174149061798030e-1, 0.2652341994215790800810512e-1, 0.2495922349431387305527612e-1, 0.2334684910922325263171504e-1, 0.2168940913598536796183230e-1, 0.1999010293235011128748561e-1, 0.1825221070467867050232934e-1, 0.1647908720746239655059230e-1, 0.1467415533461152920040808e-1, 0.1284089966808780607041846e-1, 0.1098286015429855170627475e-1, 0.9103626461992005851317578e-2, 0.7206835281831493387342912e-2, 0.5296182844025892632677844e-2, 0.3375555496730675865126842e-2, 0.1451267330029397268489446e-2}, {0.4270273086485722207660098e-1, 0.4258568982601838702576300e-1, 0.4239085899223159440537396e-1, 0.4211859425425563626894556e-1, 0.4176939294869285375410172e-1, 0.4134389294952549452688336e-1, 0.4084287150293886154936056e-1, 0.4026724380756003336494178e-1, 0.3961806134270614331650800e-1, 0.3889650994769673952047552e-1, 0.3810390765573980059550798e-1, 0.3724170228634977315689404e-1, 0.3631146880069778469034650e-1, 0.3531490642472828750906318e-1, 0.3425383554530221541412972e-1, 0.3313019438504384067706900e-1, 0.3194603546197670648650132e-1, 0.3070352184043350493812614e-1, 0.2940492318011656010545704e-1, 0.2805261159057206032380240e-1, 0.2664905729872748295223048e-1, 0.2519682413753831281333190e-1, 0.2369856486421897462660896e-1, 0.2215701631704007205676952e-1, 0.2057499442036116916601972e-1, 0.1895538904867002168973610e-1, 0.1730115876248908300560664e-1, 0.1561532543359142299553300e-1, 0.1390096878831465086752053e-1, 0.1216122092928111272776412e-1, 0.1039926099500053220130511e-1, 0.8618310479532247613912182e-2, 0.6821631349174792362208078e-2, 0.5012538571606190263812266e-2, 0.3194524377289034522078870e-2, 0.1373376462759619223985654e-2}, {0.4157356944178127878299940e-1, 0.4146558103261909213524834e-1, 0.4128580808246718908346088e-1, 0.4103456181139210667622250e-1, 0.4071227717293733029875788e-1, 0.4031951210114157755817430e-1, 0.3985694654465635257596536e-1, 0.3932538128963516252076754e-1, 0.3872573657343257584146640e-1, 0.3805905049151360313563098e-1, 0.3732647720033209016730652e-1, 0.3652928491929033900685118e-1, 0.3566885373524045308911856e-1, 0.3474667321333040653509838e-1, 0.3376433981833409264695562e-1, 0.3272355415093422052152286e-1, 0.3162611800374964805603220e-1, 0.3047393124221453920313760e-1, 0.2926898851572598680503318e-1, 0.2801337580478054082525924e-1, 0.2670926681012085177235442e-1, 0.2535891919021637909420806e-1, 0.2396467065371695917476570e-1, 0.2252893491386577645054636e-1, 0.2105419751228284223644546e-1, 0.1954301152012788937957076e-1, 0.1799799312564505063794604e-1, 0.1642181711902464004359937e-1, 0.1481721228981446852013731e-1, 0.1318695676282480211961300e-1, 0.1153387332830449596681366e-1, 0.9860824916114018392051822e-2, 0.8170710707327826403717118e-2, 0.6466464907037538401963982e-2, 0.4751069185015273965898868e-2, 0.3027671014606041291230134e-2, 0.1301591717375855993899257e-2}, {0.4050253572678803195524960e-1, 0.4040269003221775617032620e-1, 0.4023646282485108419526524e-1, 0.4000412721559123741035150e-1, 0.3970606493128931068103760e-1, 0.3934276568757015193713232e-1, 0.3891482638423378562103292e-1, 0.3842295012455452367368120e-1, 0.3786794506008932026166678e-1, 0.3725072306289371887876038e-1, 0.3657229822732745453345840e-1, 0.3583378520391196260264276e-1, 0.3503639736797827845487748e-1, 0.3418144482611567926531782e-1, 0.3327033226369854530283962e-1, 0.3230455663703097559357210e-1, 0.3128570471390543339395640e-1, 0.3021545046662299869139892e-1, 0.2909555232176876134870268e-1, 0.2792785027127696854150716e-1, 0.2671426284955789083200264e-1, 0.2545678398169440375263742e-1, 0.2415747970795584494059388e-1, 0.2281848479012952051290956e-1, 0.2144199920545613550512462e-1, 0.2003028453431617639624646e-1, 0.1858566024834148550917969e-1, 0.1711049990653110417623953e-1, 0.1560722726874913129508073e-1, 0.1407831234002700405016720e-1, 0.1252626736922736518735940e-1, 0.1095364285391135423859170e-1, 0.9363023692386430769260798e-2, 0.7757025950083070731841176e-2, 0.6138296159756341839268696e-2, 0.4509523600205835333238688e-2, 0.2873553083652691657275240e-2, 0.1235291177139409614163874e-2}, {0.3948525740129116475372166e-1, 0.3939275600474300393426418e-1, 0.3923874749659464355491890e-1, 0.3902347234287979602650502e-1, 0.3874726667023996706818530e-1, 0.3841056174110417740541666e-1, 0.3801388328032604954551756e-1, 0.3755785065432977047790708e-1, 0.3704317590404678415983790e-1, 0.3647066263315342752925638e-1, 0.3584120475334575228920704e-1, 0.3515578508861113112825058e-1, 0.3441547384067660088259166e-1, 0.3362142691803093004992252e-1, 0.3277488413113081785342150e-1, 0.3187716725661117036051890e-1, 0.3092967797352483528829388e-1, 0.2993389567483836289564858e-1, 0.2889137515760726678163634e-1, 0.2780374419544705894443552e-1, 0.2667270099710555653788310e-1, 0.2550001155512877394733978e-1, 0.2428750688879949263942200e-1, 0.2303708018571902627697914e-1, 0.2175068384660807976864198e-1, 0.2043032643814085987844290e-1, 0.1907806955893748858478357e-1, 0.1769602462431041786466318e-1, 0.1628634957619168209183741e-1, 0.1485124552635006931857919e-1, 0.1339295334482567619730830e-1, 0.1191375021511699869960077e-1, 0.1041594620451338257918368e-1, 0.8901880982652486253740074e-2, 0.7373921131330176830391914e-2, 0.5834459868763465589211910e-2, 0.4285929113126531218219446e-2, 0.2730907065754855918535274e-2, 0.1173930129956613021207112e-2}, {0.3851778959688469523783810e-1, 0.3843192958037517210025656e-1, 0.3828897129558352443032002e-1, 0.3808912713547560183102332e-1, 0.3783269400830055924757518e-1, 0.3752005289647583785923924e-1, 0.3715166829056371214474266e-1, 0.3672808749918043951690600e-1, 0.3624993983586341279832570e-1, 0.3571793568410456853072614e-1, 0.3513286544193937941597898e-1, 0.3449559834765979589474544e-1, 0.3380708118839624555119598e-1, 0.3306833689348800442087536e-1, 0.3228046301473268887240310e-1, 0.3144463009577406641803652e-1, 0.3056207993305266189565968e-1, 0.2963412373090559765847516e-1, 0.2866214015356067622579182e-1, 0.2764757327692492691108618e-1, 0.2659193044321992109092004e-1, 0.2549678002166567706947970e-1, 0.2436374907856309733249090e-1, 0.2319452096027391988145570e-1, 0.2199083279275163277050144e-1, 0.2075447290144560853952252e-1, 0.1948727815560191821592671e-1, 0.1819113124125576115176324e-1, 0.1686795786763513947433495e-1, 0.1551972391246436293824549e-1, 0.1414843251323606554825229e-1, 0.1275612111513442100025550e-1, 0.1134485849541625576200880e-1, 0.9916741809595875499750926e-2, 0.8473893785345565449616918e-2, 0.7018460484931625511609624e-2, 0.5552611370256278902273182e-2, 0.4078551113421395586018386e-2, 0.2598622299928953013499446e-2, 0.1117029847124606606122469e-2}, {0.3759656394395517759196934e-1, 0.3751672450373727271505762e-1, 0.3738378433575740441091762e-1, 0.3719793160197673054400130e-1, 0.3695942935618497107975802e-1, 0.3666861517167809004390068e-1, 0.3632590066346228889989584e-1, 0.3593177090566064734733082e-1, 0.3548678374494710264584324e-1, 0.3499156901097965473152462e-1, 0.3444682762495051683252180e-1, 0.3385333060751519869931002e-1, 0.3321191798750501518117324e-1, 0.3252349761296806599129116e-1, 0.3178904386622215064354856e-1, 0.3100959628473919484306724e-1, 0.3018625808981441705410184e-1, 0.2932019462510452791804122e-1, 0.2841263170724764156375054e-1, 0.2746485389090326123892810e-1, 0.2647820265067376248510830e-1, 0.2545407448248949675081806e-1, 0.2439391892715855749743432e-1, 0.2329923651890054937016126e-1, 0.2217157666180362262199056e-1, 0.2101253543726991787400918e-1, 0.1982375334565493904931242e-1, 0.1860691298547847284166721e-1, 0.1736373667382462235016547e-1, 0.1609598401193537091543832e-1, 0.1480544940071787768084914e-1, 0.1349395951237523498069998e-1, 0.1216337072779861206303406e-1, 0.1081556655803715872036043e-1, 0.9452455092479699888244178e-2, 0.8075966593123452283593892e-2, 0.6688051635243685741358420e-2, 0.5290681445859865555240374e-2, 0.3885859435353202192003776e-2, 0.2475719322545939743331242e-2, 0.1064168219666567756385077e-2}, {0.3671834473341961622215226e-1, 0.3664397593378570248640692e-1, 0.3652013948874488485747660e-1, 0.3634700257169520376675674e-1, 0.3612479890936246037475190e-1, 0.3585382846628081255691520e-1, 0.3553445703985569908199156e-1, 0.3516711576655578824981280e-1, 0.3475230053990063752924744e-1, 0.3429057134102984670822224e-1, 0.3378255148275753033131186e-1, 0.3322892676813276976252854e-1, 0.3263044456464217818903764e-1, 0.3198791279530467445976990e-1, 0.3130219884802087044839684e-1, 0.3057422840464999572392432e-1, 0.2980498419139588737561256e-1, 0.2899550465219015208986610e-1, 0.2814688254686507584638292e-1, 0.2726026347601116478577010e-1, 0.2633684433451435982173160e-1, 0.2537787169586608847736972e-1, 0.2438464012943568314241580e-1, 0.2335849045298989189769872e-1, 0.2230080792283937418945736e-1, 0.2121302036408937967241628e-1, 0.2009659624357542174179408e-1, 0.1895304268818284044680496e-1, 0.1778390345139817090774314e-1, 0.1659075683115467007520452e-1, 0.1537521354238962687440865e-1, 0.1413891454840083293055609e-1, 0.1288352885649808429050626e-1, 0.1161075128670389800962475e-1, 0.1032230023052424589381722e-1, 0.9019915439993631278967098e-2, 0.7705355960382757079897960e-2, 0.6380398587897515098686098e-2, 0.5046838426924442725450432e-2, 0.3706500125759316706868292e-2, 0.2361331704285020896763904e-2, 0.1014971908967743695374167e-2}, {0.3588019106018701587773518e-1, 0.3581080434383374175662560e-1, 0.3569525919440943377647946e-1, 0.3553370454416059391133478e-1, 0.3532634862941021369843054e-1, 0.3507345872215153655662536e-1, 0.3477536078554782924871120e-1, 0.3443243905378224376593820e-1, 0.3404513553679937345518354e-1, 0.3361394945057693558422230e-1, 0.3313943657366202353628890e-1, 0.3262220853080144392580048e-1, 0.3206293200458966777765818e-1, 0.3146232787615076393796228e-1, 0.3082117029596223415371898e-1, 0.3014028568601882474395096e-1, 0.2942055167462304824922484e-1, 0.2866289596517621838858744e-1, 0.2786829514042920598963448e-1, 0.2703777340373580728397710e-1, 0.2617240125893355894972542e-1, 0.2527329413055707316411874e-1, 0.2434161092616763233921348e-1, 0.2337855254266017225782364e-1, 0.2238536031848547821419758e-1, 0.2136331443380253159361604e-1, 0.2031373226065556952656956e-1, 0.1923796666535655878505047e-1, 0.1813740426535425205021816e-1, 0.1701346364300153443364516e-1, 0.1586759351882631900292224e-1, 0.1470127088723984222989451e-1, 0.1351599911824565808188095e-1, 0.1231330603004803654228712e-1, 0.1109474194056071927972064e-1, 0.9861877713701826716584494e-2, 0.8616302838488951832949878e-2, 0.7359623648818063660769462e-2, 0.6093462047634872130101964e-2, 0.4819456238501885899307624e-2, 0.3539271655388628540179688e-2, 0.2254690753752853092482060e-2, 0.9691097381770753376096654e-3}, {0.3507942401790202531716760e-1, 0.3501458416619644336915306e-1, 0.3490660650856070989101148e-1, 0.3475562407298142092081152e-1, 0.3456182286913780813643384e-1, 0.3432544165923908781796544e-1, 0.3404677166387108716735582e-1, 0.3372615620321457070630952e-1, 0.3336399027407732093971928e-1, 0.3296072006326111707429234e-1, 0.3251684239786320696758578e-1, 0.3203290413318958550703170e-1, 0.3150950147903428365879858e-1, 0.3094727926515484478947892e-1, 0.3034693014684912934340756e-1, 0.2970919375161245962730194e-1, 0.2903485576792681183001942e-1, 0.2832474697730520722803496e-1, 0.2757974223078458253347716e-1, 0.2680075937112917771256550e-1, 0.2598875810207383625148160e-1, 0.2514473880600256862281534e-1, 0.2426974131152233927366188e-1, 0.2336484361245544582716880e-1, 0.2243116053983636712835892e-1, 0.2146984238856114084341254e-1, 0.2048207350040027021224486e-1, 0.1946907080515187313867415e-1, 0.1843208232178411567584622e-1, 0.1737238562150240166964102e-1, 0.1629128625479238457754130e-1, 0.1519011614466612339747308e-1, 0.1407023194864448281388687e-1, 0.1293301339260267729158710e-1, 0.1177986158087489217661933e-1, 0.1061219728997218803268093e-1, 0.9431459260797890539711922e-2, 0.8239102525389078730572362e-2, 0.7036596870989114137389446e-2, 0.5825425788770107459644064e-2, 0.4607087343463241433054622e-2, 0.3383104792407455132632698e-2, 0.2155112582219113764637582e-2, 0.9262871051934728155239026e-3}, {0.3431359817623139857242020e-1, 0.3425291647165106006719224e-1, 0.3415185977541012618567448e-1, 0.3401054720622907866548866e-1, 0.3382914533369793579365620e-1, 0.3360786798193575310982430e-1, 0.3334697597754983863697838e-1, 0.3304677684219179120016898e-1, 0.3270762443007278294842040e-1, 0.3232991851086539448409380e-1, 0.3191410429848369728859888e-1, 0.3146067192629708854519032e-1, 0.3097015586939654421561894e-1, 0.3044313431459439490344712e-1, 0.2988022847890037493277136e-1, 0.2928210187727747971826382e-1, 0.2864945954054102439649608e-1, 0.2798304718432316638118606e-1, 0.2728365033008298027898986e-1, 0.2655209337919890810307922e-1, 0.2578923864123601618879028e-1, 0.2499598531753495743256148e-1, 0.2417326844132287942221788e-1, 0.2332205777559880283599600e-1, 0.2244335667009737337332098e-1, 0.2153820087868566629622426e-1, 0.2060765733859846074045938e-1, 0.1965282291296914660474199e-1, 0.1867482309816812542178599e-1, 0.1767481069752190506037194e-1, 0.1665396446306124017225753e-1, 0.1561348770705005975095101e-1, 0.1455460688520869608484063e-1, 0.1347857015383097919431856e-1, 0.1238664590355674305453526e-1, 0.1128012127376968298340906e-1, 0.1016030065441547672889225e-1, 0.9028504189234487748913298e-2, 0.7886066314628901599629988e-2, 0.6734334432268884665261132e-2, 0.5574668047479788997832340e-2, 0.4408439747302676819065170e-2, 0.3237045507972104977098260e-2, 0.2061987122032229660677942e-2, 0.8862412406694141765769646e-3}, {0.3358047670273290820423322e-1, 0.3352360509236689973246714e-1, 0.3342889041048296629425518e-1, 0.3329643957561578934524218e-1, 0.3312640210470322597293962e-1, 0.3291896994430459113247722e-1, 0.3267437725392241575486392e-1, 0.3239290014167229270630344e-1, 0.3207485635259921958171598e-1, 0.3172060490999230883258760e-1, 0.3133054571010280192591498e-1, 0.3090511907072293590876800e-1, 0.3044480523413530949647580e-1, 0.2995012382499392416587776e-1, 0.2942163326374897748551588e-1, 0.2885993013627770636290672e-1, 0.2826564852043306435742870e-1, 0.2763945927027071971311622e-1, 0.2698206925876273304878794e-1, 0.2629422057985327475229788e-1, 0.2557668971075783892217594e-1, 0.2483028663545258189183534e-1, 0.2405585393034465615306556e-1, 0.2325426581315775168991978e-1, 0.2242642715610957188910656e-1, 0.2157327246449981801505782e-1, 0.2069576482186873448858912e-1, 0.1979489480292792866805571e-1, 0.1887167935550803461442971e-1, 0.1792716065281371317885285e-1, 0.1696240491732901090122756e-1, 0.1597850121778211678831695e-1, 0.1497656024067188095391932e-1, 0.1395771303800797072406999e-1, 0.1292310975318535045602668e-1, 0.1187391832744712509861298e-1, 0.1081132319054248938202577e-1, 0.9736523941887687826947068e-2, 0.8650734035428648314139846e-2, 0.7555179500769820751618632e-2, 0.6451097794311275889059324e-2, 0.5339737098169214613757504e-2, 0.4222357382406607998634106e-2, 0.3100240403099316775464478e-2, 0.1974768768686808388940061e-2, 0.8487371680679110048896640e-3}, {0.3287800959763194823557646e-1, 0.3282463569369918669308888e-1, 0.3273574336068393226919658e-1, 0.3261142878598215425670652e-1, 0.3245182648620325926685946e-1, 0.3225710916161441434734840e-1, 0.3202748750926769529295728e-1, 0.3176320999501228029097900e-1, 0.3146456258463840201321734e-1, 0.3113186843444399825682258e-1, 0.3076548754155891475295788e-1, 0.3036581635440506677724356e-1, 0.2993328734371411225240016e-1, 0.2946836853456688237515152e-1, 0.2897156299996101153484194e-1, 0.2844340831645486261311894e-1, 0.2788447598247691424309350e-1, 0.2729537079993022266578380e-1, 0.2667673021976135431896846e-1, 0.2602922365220227153290076e-1, 0.2535355174243201293660006e-1, 0.2465044561244261997612948e-1, 0.2392066606993061007707546e-1, 0.2316500278507139174920030e-1, 0.2238427343606939184041926e-1, 0.2157932282441140120676856e-1, 0.2075102196078490181790884e-1, 0.1990026712265721124487174e-1, 0.1902797888454570639306994e-1, 0.1813510112204514410759734e-1, 0.1722259999071698441334003e-1, 0.1629146288099104326591566e-1, 0.1534269735028835663459242e-1, 0.1437733003365908208357459e-1, 0.1339640553436828544136536e-1, 0.1240098529611606104018197e-1, 0.1139214645908584403924275e-1, 0.1037098070311609684083942e-1, 0.9338593083876397086740596e-2, 0.8296100874530990238145090e-2, 0.7244632443933199672626606e-2, 0.6185326261033323769312750e-2, 0.5119330329927718280032034e-2, 0.4047803316371759906879922e-2, 0.2971924240818190718436604e-2, 0.1892968377922935762776147e-2, 0.8135642494541165010544716e-3}, {0.3220431459661350533475748e-1, 0.3215415737958550153577998e-1, 0.3207061987527279934927952e-1, 0.3195378880670864194528382e-1, 0.3180378546007149044495368e-1, 0.3162076555877401604294910e-1, 0.3140491910180172362457798e-1, 0.3115647016646904145775102e-1, 0.3087567667579765382432642e-1, 0.3056283013075858386135104e-1, 0.3021825530765601453452082e-1, 0.2984230992096702903457814e-1, 0.2943538425198732086424294e-1, 0.2899790074366843187205222e-1, 0.2853031356206718751823808e-1, 0.2803310812486267752680532e-1, 0.2750680059743034256009616e-1, 0.2695193735699644067363378e-1, 0.2636909442542934975707846e-1, 0.2575887687125678489535242e-1, 0.2512191818153004673565192e-1, 0.2445887960418784729059960e-1, 0.2377044946160306882104198e-1, 0.2305734243602599579639616e-1, 0.2232029882766713237862322e-1, 0.2156008378619171827843500e-1, 0.2077748651642656849799008e-1, 0.1997331945910804688818908e-1, 0.1914841744752812933525703e-1, 0.1830363684096414082229124e-1, 0.1743985463580780463940516e-1, 0.1655796755534245662902801e-1, 0.1565889111915692052020687e-1, 0.1474355869323695017635984e-1, 0.1381292052185304327114855e-1, 0.1286794274249338667571135e-1, 0.1190960638533075683273654e-1, 0.1093890635919594895396767e-1, 0.9956850427084044948237490e-2, 0.8964458176697999432566250e-2, 0.7962759997865495595598110e-2, 0.6952796096469405526464256e-2, 0.5935615630788222954183688e-2, 0.4912276262166028130833504e-2, 0.3883845329489294421733034e-2, 0.2851409243213055771419126e-2, 0.1816146398210039609502983e-2, 0.7805332219425612457264822e-3}, {0.3155766036791122885809208e-1, 0.3151046648162834771323796e-1, 0.3143186227722154616152128e-1, 0.3132192610907518012817474e-1, 0.3118076756395815837033438e-1, 0.3100852735178559535833486e-1, 0.3080537716535627949917920e-1, 0.3057151950920577999218210e-1, 0.3030718749774580397961262e-1, 0.3001264462289103447190280e-1, 0.2968818449140509844801766e-1, 0.2933413053222750347643324e-1, 0.2895083567407331040373860e-1, 0.2853868199362694972663692e-1, 0.2809808033468091126593440e-1, 0.2762946989859901232207604e-1, 0.2713331780651255092639320e-1, 0.2661011863368585130179228e-1, 0.2606039391651548254092866e-1, 0.2548469163265475465058230e-1, 0.2488358565478194644598738e-1, 0.2425767517855707823164026e-1, 0.2360758412533789404661778e-1, 0.2293396052025105528408320e-1, 0.2223747584623937158435550e-1, 0.2151882437473022381824646e-1, 0.2077872247359421120742490e-1, 0.2001790789308656620794778e-1, 0.1923713903048718479867380e-1, 0.1843719417417849927098560e-1, 0.1761887072792438050675710e-1, 0.1678298441613870708950299e-1, 0.1593036847096084971103802e-1, 0.1506187280199023331295260e-1, 0.1417836314957944606614279e-1, 0.1328072022265728347995425e-1, 0.1236983882217516210343368e-1, 0.1144662695149825376113323e-1, 0.1051200491552474540574917e-1, 0.9566904411326136356898158e-2, 0.8612267615478888991732218e-2, 0.7649046279335257935390770e-2, 0.6678200860575098165183170e-2, 0.5700699773395926875152328e-2, 0.4717519037520830079689318e-2, 0.3729643487243034749198276e-2, 0.2738075873626878091327392e-2, 0.1743906958219244938639563e-2, 0.7494736467374053633626714e-3}, } // The factor in front of the direct product representation var cl = [...]float64{1.0, 1.0, -0.5000000000000000000000000e0, -0.1500000000000000000000000e1, 0.3750000000000000000000000e0, 0.1875000000000000000000000e1, -0.3125000000000000000000000e0, -0.2187500000000000000000000e1, 0.2734375000000000000000000e0, 0.2460937500000000000000000e1, -0.2460937500000000000000000e0, -0.2707031250000000000000000e1, 0.2255859375000000000000000e0, 0.2932617187500000000000000e1, -0.2094726562500000000000000e0, -0.3142089843750000000000000e1, 0.1963806152343750000000000e0, 0.3338470458984375000000000e1, -0.1854705810546875000000000e0, -0.3523941040039062500000000e1, 0.1761970520019531250000000e0, 0.3700138092041015625000000e1, -0.1681880950927734375000000e0, -0.3868326187133789062500000e1, 0.1611802577972412109375000e0, 0.4029506444931030273437500e1, -0.1549810171127319335937500e0, -0.4184487462043762207031250e1, 0.1494459807872772216796875e0, 0.4333933442831039428710938e1, -0.1444644480943679809570312e0, -0.4478397890925407409667969e1, 0.1399499340914189815521240e0, 0.4618347825016826391220093e1, -0.1358337595593184232711792e0, -0.4754181584576144814491272e1, 0.1320605995715595781803131e0, 0.4886242184147704392671585e1, -0.1285853206354659050703049e0, -0.5014827504783170297741890e1, 0.1253706876195792574435472e0, 0.5140198192402749555185437e1, -0.1223856712476845132187009e0, -0.5262583863650434068404138e1, 0.1196041787193280470091850e0, 0.5382188042369762115413323e1, -0.1170040878776035242481157e0, -0.5499192130247365639661439e1, 0.1145665027134867841596133e0, 0.5613758632960852423821052e1, -0.1122751726592170484764210e0, -0.5726033805620069472297473e1, 0.1101160347234628744672591e0, 0.5836149840343532346764732e1, -0.1080768488952505990141617e0, -0.5944226689238782945778894e1, 0.1061469051649782668889088e0, 0.6050373594403761212667803e1, -0.1043167861104096760804794e0, -0.6154690380514170888748282e1, 0.1025781730085695148124714e0, 0.6257268553522740403560753e1, -0.1009236863471409742509799e0, -0.6358192239869881377811733e1, 0.9934675374796689652830833e-1, 0.6457538993617848274340042e1, -0.9784149990330073142939457e-1, -0.6555380493521149005769436e1, 0.9640265431648748537896230e-1, 0.6651783147837636491148399e1, -0.9502547354053766415926284e-1, -0.6746808621378174155307661e1, 0.9370567529691908549038419e-1, 0.6840514296675093240798046e1, -0.9243938238750126001078440e-1, -0.6932953679062594500808830e1, 0.9122307472450782237906355e-1, 0.7024176753787102323187894e1, -0.9005354812547567081010120e-1, -0.7114230301912577993997995e1, 0.8892787877390722492497493e-1, 0.7203158180686485218922970e1, -0.8784339244739616120637768e-1, -0.7291001573133881380129347e1, 0.8679763777540334976344461e-1, 0.7377799210909284729892792e1, -0.8578836291754982244061386e-1, -0.7463587573826834552333406e1, 0.8481349515712311991287961e-1, 0.7548401068983957672246285e1, -0.8387112298871064080273650e-1, -0.7632272191972668313049022e1, 0.8295948034752900340270676e-1, 0.7715231672320197316451729e1, -0.8207693268425741826012477e-1, -0.7797308605004454734711853e1, 0.8122196463546307015324847e-1, 0.7878530569639917804865102e1, -0.8039316907795834494760308e-1, -0.7958923738717876149812705e1, 0.7958923738717876149812705e-1} golang-gonum-v1-gonum-0.14.0/integrate/quad/legendre_test.go000066400000000000000000000040621450372207100237270ustar00rootroot00000000000000// 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 quad import ( "math" "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestLegendre(t *testing.T) { t.Parallel() for i, test := range []struct { f func(float64) float64 min, max float64 n []int tol []float64 ans float64 }{ // Tolerances determined from intuition and a bit of post-hoc tweaking. { f: func(x float64) float64 { return math.Exp(x) }, min: -3, max: 5, n: []int{3, 4, 6, 7, 15, 16, 300, 301}, tol: []float64{5e-2, 5e-3, 5e-6, 1e-7, 1e-14, 1e-14, 1e-14, 1e-14}, ans: math.Exp(5) - math.Exp(-3), }, } { for j, n := range test.n { ans := Fixed(test.f, test.min, test.max, n, Legendre{}, 0) if !scalar.EqualWithinAbsOrRel(ans, test.ans, test.tol[j], test.tol[j]) { t.Errorf("Mismatch. Case = %d, n = %d. Want %v, got %v", i, n, test.ans, ans) } ans2 := Fixed(test.f, test.min, test.max, n, Legendre{}, 3) if !scalar.EqualWithinAbsOrRel(ans2, test.ans, test.tol[j], test.tol[j]) { t.Errorf("Mismatch concurrent. Case = %d, n = %d. Want %v, got %v", i, n, test.ans, ans) } } } } func TestLegendreSingle(t *testing.T) { t.Parallel() for c, test := range []struct { n int min, max float64 }{ { n: 100, min: -1, max: 1, }, { n: 50, min: -3, max: -1, }, { n: 1000, min: 2, max: 7, }, } { l := Legendre{} n := test.n xs := make([]float64, n) weights := make([]float64, n) l.FixedLocations(xs, weights, test.min, test.max) xsSingle := make([]float64, n) weightsSingle := make([]float64, n) for i := range xsSingle { xsSingle[i], weightsSingle[i] = l.FixedLocationSingle(n, i, test.min, test.max) } if !floats.Equal(xs, xsSingle) { t.Errorf("Case %d: xs mismatch batch and single", c) } if !floats.Equal(weights, weightsSingle) { t.Errorf("Case %d: weights mismatch batch and single", c) } } } golang-gonum-v1-gonum-0.14.0/integrate/quad/quad.go000066400000000000000000000104161450372207100220350ustar00rootroot00000000000000// 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 quad import ( "math" "sync" ) // FixedLocationer computes a set of quadrature locations and weights and stores // them in-place into x and weight respectively. The number of points generated is equal to // the len(x). The weights and locations should be chosen such that // // int_min^max f(x) dx ≈ \sum_i w_i f(x_i) type FixedLocationer interface { FixedLocations(x, weight []float64, min, max float64) } // FixedLocationSingle returns the location and weight for element k in a // fixed quadrature rule with n total samples and integral bounds from min to max. type FixedLocationSingler interface { FixedLocationSingle(n, k int, min, max float64) (x, weight float64) } // Fixed approximates the integral of the function f from min to max using a fixed // n-point quadrature rule. During evaluation, f will be evaluated n times using // the weights and locations specified by rule. That is, Fixed estimates // // int_min^max f(x) dx ≈ \sum_i w_i f(x_i) // // If rule is nil, an acceptable default is chosen, otherwise it is // assumed that the properties of the integral match the assumptions of rule. // For example, Legendre assumes that the integration bounds are finite. If // rule is also a FixedLocationSingler, the quadrature points are computed // individually rather than as a unit. // // If concurrent <= 0, f is evaluated serially, while if concurrent > 0, f // may be evaluated with at most concurrent simultaneous evaluations. // // min must be less than or equal to max, and n must be positive, otherwise // Fixed will panic. func Fixed(f func(float64) float64, min, max float64, n int, rule FixedLocationer, concurrent int) float64 { // TODO(btracey): When there are Hermite polynomial quadrature, add an additional // example to the documentation comment that talks about weight functions. if n <= 0 { panic("quad: non-positive number of locations") } if min > max { panic("quad: min > max") } if min == max { return 0 } intfunc := f // If rule is non-nil it is assumed that the function and the constraints // of rule are aligned. If it is nil, wrap the function and do something // reasonable. // TODO(btracey): Replace wrapping with other quadrature rules when // we have rules that support infinite-bound integrals. if rule == nil { // int_a^b f(x)dx = int_u^-1(a)^u^-1(b) f(u(t))u'(t)dt switch { case math.IsInf(max, 1) && math.IsInf(min, -1): // u(t) = (t/(1-t^2)) min = -1 max = 1 intfunc = func(x float64) float64 { v := 1 - x*x return f(x/v) * (1 + x*x) / (v * v) } case math.IsInf(max, 1): // u(t) = a + t / (1-t) a := min min = 0 max = 1 intfunc = func(x float64) float64 { v := 1 - x return f(a+x/v) / (v * v) } case math.IsInf(min, -1): // u(t) = a - (1-t)/t a := max min = 0 max = 1 intfunc = func(x float64) float64 { return f(a-(1-x)/x) / (x * x) } } rule = Legendre{} } singler, isSingler := rule.(FixedLocationSingler) var xs, weights []float64 if !isSingler { xs = make([]float64, n) weights = make([]float64, n) rule.FixedLocations(xs, weights, min, max) } if concurrent > n { concurrent = n } if concurrent <= 0 { var integral float64 // Evaluate in serial. if isSingler { for k := 0; k < n; k++ { x, weight := singler.FixedLocationSingle(n, k, min, max) integral += weight * intfunc(x) } return integral } for i, x := range xs { integral += weights[i] * intfunc(x) } return integral } // Evaluate concurrently tasks := make(chan int) // Launch distributor go func() { for i := 0; i < n; i++ { tasks <- i } close(tasks) }() var mux sync.Mutex var integral float64 var wg sync.WaitGroup wg.Add(concurrent) for i := 0; i < concurrent; i++ { // Launch workers go func() { defer wg.Done() var subIntegral float64 for k := range tasks { var x, weight float64 if isSingler { x, weight = singler.FixedLocationSingle(n, k, min, max) } else { x = xs[k] weight = weights[k] } f := intfunc(x) subIntegral += f * weight } mux.Lock() integral += subIntegral mux.Unlock() }() } wg.Wait() return integral } golang-gonum-v1-gonum-0.14.0/integrate/quad/quad_test.go000066400000000000000000000071451450372207100231010ustar00rootroot00000000000000// 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 quad import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/stat/distuv" ) func TestFixed(t *testing.T) { t.Parallel() for i, test := range []struct { f func(float64) float64 min, max float64 n []int tol []float64 ans float64 }{ // Tolerances determined from intuition and a bit of post-hoc tweaking. { f: func(x float64) float64 { return math.Exp(x) }, min: -3, max: 5, n: []int{3, 4, 6, 7, 15, 16, 300, 301}, tol: []float64{5e-2, 5e-3, 5e-6, 1e-7, 1e-14, 1e-14, 1e-14, 1e-14}, ans: math.Exp(5) - math.Exp(-3), }, { f: distuv.UnitNormal.Prob, min: math.Inf(-1), max: math.Inf(1), n: []int{15, 16, 50, 51, 300, 301}, tol: []float64{5e-3, 1e-3, 1e-7, 1e-7, 1e-14, 1e-14}, ans: 1, }, { f: func(x float64) float64 { return math.Exp(-x) }, min: 5, max: math.Inf(1), n: []int{15, 16, 50, 51, 300, 301}, tol: []float64{5e-3, 1e-3, 1e-7, 1e-7, 1e-14, 1e-14}, ans: math.Exp(-5), }, { f: func(x float64) float64 { return math.Exp(x) }, min: math.Inf(-1), max: -5, n: []int{15, 16, 50, 51, 300, 301}, tol: []float64{5e-3, 1e-3, 1e-7, 1e-7, 1e-14, 1e-14}, ans: math.Exp(-5), }, { f: func(x float64) float64 { return math.Exp(x) }, min: 3, max: 3, n: []int{15, 16, 50, 51, 300, 301}, tol: []float64{0, 0, 0, 0, 0, 0}, ans: 0, }, } { for j, n := range test.n { ans := Fixed(test.f, test.min, test.max, n, nil, 0) if !scalar.EqualWithinAbsOrRel(ans, test.ans, test.tol[j], test.tol[j]) { t.Errorf("Case %d, n = %d: Mismatch. Want %v, got %v", i, n, test.ans, ans) } ans2 := Fixed(test.f, test.min, test.max, n, nil, 3) if !scalar.EqualWithinAbsOrRel(ans2, test.ans, test.tol[j], test.tol[j]) { t.Errorf("Case %d, n = %d: Mismatch concurrent. Want %v, got %v", i, n, test.ans, ans) } } } } // legendreNonSingle wraps Legendre but does not implement FixedLocationSingle. type legendreNonSingle struct { Legendre Legendre } func (l legendreNonSingle) FixedLocations(x, weight []float64, min, max float64) { l.Legendre.FixedLocations(x, weight, min, max) } func TestFixedNonSingle(t *testing.T) { t.Parallel() // TODO(btracey): Add tests with infinite bounds when we have native support // for indefinite integrals. for i, test := range []struct { f func(float64) float64 min, max float64 n []int tol []float64 ans float64 }{ // Tolerances determined from intuition and a bit of post-hoc tweaking. { f: func(x float64) float64 { return math.Exp(x) }, min: -3, max: 5, n: []int{3, 4, 6, 7, 15, 16, 300, 301}, tol: []float64{5e-2, 5e-3, 5e-6, 1e-7, 1e-14, 1e-14, 1e-14, 1e-14}, ans: math.Exp(5) - math.Exp(-3), }, { f: func(x float64) float64 { return math.Exp(x) }, min: 3, max: 3, n: []int{3, 4, 6, 7, 15, 16, 300, 301}, tol: []float64{0, 0, 0, 0, 0, 0, 0, 0}, ans: 0, }, } { for j, n := range test.n { ans := Fixed(test.f, test.min, test.max, n, legendreNonSingle{}, 0) if !scalar.EqualWithinAbsOrRel(ans, test.ans, test.tol[j], test.tol[j]) { t.Errorf("Case = %d, n = %d: Mismatch. Want %v, got %v", i, n, test.ans, ans) } ans2 := Fixed(test.f, test.min, test.max, n, legendreNonSingle{}, 3) if !scalar.EqualWithinAbsOrRel(ans2, test.ans, test.tol[j], test.tol[j]) { t.Errorf("Case = %d, n = %d: Mismatch concurrent. Want %v, got %v", i, n, test.ans, ans) } } } } golang-gonum-v1-gonum-0.14.0/integrate/romberg.go000066400000000000000000000027641450372207100216150ustar00rootroot00000000000000// Copyright ©2019 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 integrate import ( "math" "math/bits" ) // Romberg returns an approximate value of the integral // // \int_a^b f(x)dx // // computed using the Romberg's method. The function f is given // as a slice of equally-spaced samples, that is, // // f[i] = f(a + i*dx) // // and dx is the spacing between the samples. // // The length of f must be 2^k + 1, where k is a positive integer, // and dx must be positive. // // See https://en.wikipedia.org/wiki/Romberg%27s_method for a description of // the algorithm. func Romberg(f []float64, dx float64) float64 { if len(f) < 3 { panic("integral: invalid slice length: must be at least 3") } if dx <= 0 { panic("integral: invalid spacing: must be larger than 0") } n := len(f) - 1 k := bits.Len(uint(n - 1)) if len(f) != 1< test.tol { t.Errorf("Test #%d: %v, n=%v: unexpected result; got=%v want=%v diff=%v", i, test.integral.Name, n, got, want, diff) } } } golang-gonum-v1-gonum-0.14.0/integrate/simpsons.go000066400000000000000000000035431450372207100220270ustar00rootroot00000000000000// Copyright ©2019 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 integrate import "sort" // Simpsons returns an approximate value of the integral // // \int_a^b f(x)dx // // computed using the Simpsons's method. The function f is given as a slice of // samples evaluated at locations in x, that is, // // f[i] = f(x[i]), x[0] = a, x[len(x)-1] = b // // The slice x must be sorted in strictly increasing order. x and f must be of // equal length and the length must be at least 3. // // See https://en.wikipedia.org/wiki/Simpson%27s_rule#Composite_Simpson's_rule_for_irregularly_spaced_data // for more information. func Simpsons(x, f []float64) float64 { n := len(x) switch { case len(f) != n: panic("integrate: slice length mismatch") case n < 3: panic("integrate: input data too small") case !sort.Float64sAreSorted(x): panic("integrate: must be sorted") } var integral float64 for i := 1; i < n-1; i += 2 { h0 := x[i] - x[i-1] h1 := x[i+1] - x[i] if h0 == 0 || h1 == 0 { panic("integrate: repeated abscissa") } h0p2 := h0 * h0 h0p3 := h0 * h0 * h0 h1p2 := h1 * h1 h1p3 := h1 * h1 * h1 hph := h0 + h1 a0 := (2*h0p3 - h1p3 + 3*h1*h0p2) / (6 * h0 * hph) a1 := (h0p3 + h1p3 + 3*h0*h1*hph) / (6 * h0 * h1) a2 := (-h0p3 + 2*h1p3 + 3*h0*h1p2) / (6 * h1 * hph) integral += a0 * f[i-1] integral += a1 * f[i] integral += a2 * f[i+1] } if n%2 == 0 { h0 := x[n-2] - x[n-3] h1 := x[n-1] - x[n-2] if h0 == 0 || h1 == 0 { panic("integrate: repeated abscissa") } h1p2 := h1 * h1 h1p3 := h1 * h1 * h1 hph := h0 + h1 a0 := -1 * h1p3 / (6 * h0 * hph) a1 := (h1p2 + 3*h0*h1) / (6 * h0) a2 := (2*h1p2 + 3*h0*h1) / (6 * hph) integral += a0 * f[n-3] integral += a1 * f[n-2] integral += a2 * f[n-1] } return integral } golang-gonum-v1-gonum-0.14.0/integrate/simpsons_test.go000066400000000000000000000035141450372207100230640ustar00rootroot00000000000000// Copyright ©2019 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 integrate import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/integrate/testquad" ) func TestSimpsons(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i, test := range []struct { integral testquad.Integral n int tol float64 }{ {integral: testquad.Constant(0), n: 3, tol: 0}, {integral: testquad.Constant(0), n: 4, tol: 0}, {integral: testquad.Constant(0), n: 10, tol: 0}, {integral: testquad.Poly(0), n: 3, tol: 1e-14}, {integral: testquad.Poly(0), n: 4, tol: 1e-14}, {integral: testquad.Poly(0), n: 10, tol: 1e-14}, {integral: testquad.Poly(1), n: 3, tol: 1e-14}, {integral: testquad.Poly(1), n: 4, tol: 1e-14}, {integral: testquad.Poly(1), n: 10, tol: 1e-14}, {integral: testquad.Poly(2), n: 3, tol: 1e-14}, {integral: testquad.Poly(2), n: 4, tol: 1e-14}, {integral: testquad.Poly(2), n: 10, tol: 1e-14}, {integral: testquad.Poly(3), n: 1000, tol: 1e-8}, {integral: testquad.Poly(4), n: 1000, tol: 1e-8}, {integral: testquad.Poly(5), n: 1000, tol: 1e-7}, {integral: testquad.Sin(), n: 100, tol: 1e-8}, {integral: testquad.XExpMinusX(), n: 201, tol: 1e-8}, {integral: testquad.Sqrt(), n: 1e4, tol: 1e-6}, {integral: testquad.ExpOverX2Plus1(), n: 100, tol: 1e-7}, } { n := test.n a := test.integral.A b := test.integral.B x := jitterSpan(n, a, b, rnd) y := make([]float64, n) for i, xi := range x { y[i] = test.integral.F(xi) } got := Simpsons(x, y) want := test.integral.Value diff := math.Abs(got - want) if diff > test.tol { t.Errorf("Test #%d: %v, n=%v: unexpected result; got=%v want=%v diff=%v", i, test.integral.Name, n, got, want, diff) } } } golang-gonum-v1-gonum-0.14.0/integrate/testquad/000077500000000000000000000000001450372207100214525ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/integrate/testquad/testquad.go000066400000000000000000000041571450372207100236420ustar00rootroot00000000000000// Copyright ©2019 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 testquad provides integrals for testing quadrature algorithms. package testquad import ( "fmt" "math" ) // Integral is a definite integral // // ∫_a^b f(x)dx // // with a known value. type Integral struct { Name string A, B float64 // Integration limits F func(float64) float64 // Integrand Value float64 } // Constant returns the integral of a constant function // // ∫_{-1}^2 alpha dx func Constant(alpha float64) Integral { return Integral{ Name: fmt.Sprintf("∫_{-1}^{2} %vdx", alpha), A: -1, B: 2, F: func(float64) float64 { return alpha }, Value: 3 * alpha, } } // Poly returns the integral of a polynomial // // ∫_{-1}^2 x^degree dx func Poly(degree int) Integral { d := float64(degree) return Integral{ Name: fmt.Sprintf("∫_{-1}^{2} x^%vdx", degree), A: -1, B: 2, F: func(x float64) float64 { return math.Pow(x, d) }, Value: (math.Pow(2, d+1) - math.Pow(-1, d+1)) / (d + 1), } } // Sin returns the integral // // ∫_0^1 sin(x)dx func Sin() Integral { return Integral{ Name: "∫_0^1 sin(x)dx", A: 0, B: 1, F: func(x float64) float64 { return math.Sin(x) }, Value: 1 - math.Cos(1), } } // XExpMinusX returns the integral // // ∫_0^1 x*exp(-x)dx func XExpMinusX() Integral { return Integral{ Name: "∫_0^1 x*exp(-x)dx", A: 0, B: 1, F: func(x float64) float64 { return x * math.Exp(-x) }, Value: (math.E - 2) / math.E, } } // Sqrt returns the integral // // ∫_0^1 sqrt(x)dx func Sqrt() Integral { return Integral{ Name: "∫_0^1 sqrt(x)dx", A: 0, B: 1, F: func(x float64) float64 { return math.Sqrt(x) }, Value: 2 / 3.0, } } // ExpOverX2Plus1 returns the integral // // ∫_0^1 exp(x)/(x*x+1)dx func ExpOverX2Plus1() Integral { return Integral{ Name: "∫_0^1 exp(x)/(x*x+1)dx", A: 0, B: 1, F: func(x float64) float64 { return math.Exp(x) / (x*x + 1) }, Value: 1.270724139833620220138, } } golang-gonum-v1-gonum-0.14.0/integrate/trapezoidal.go000066400000000000000000000023571450372207100224740ustar00rootroot00000000000000// Copyright ©2016 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 integrate import "sort" // Trapezoidal returns an approximate value of the integral // // \int_a^b f(x) dx // // computed using the trapezoidal rule. The function f is given as a slice of // samples evaluated at locations in x, that is, // // f[i] = f(x[i]), x[0] = a, x[len(x)-1] = b // // The slice x must be sorted in strictly increasing order. x and f must be of // equal length and the length must be at least 2. // // The trapezoidal rule approximates f by a piecewise linear function and // estimates // // \int_x[i]^x[i+1] f(x) dx // // as // // (x[i+1] - x[i]) * (f[i] + f[i+1])/2 // // More details on the trapezoidal rule can be found at: // https://en.wikipedia.org/wiki/Trapezoidal_rule func Trapezoidal(x, f []float64) float64 { n := len(x) switch { case len(f) != n: panic("integrate: slice length mismatch") case n < 2: panic("integrate: input data too small") case !sort.Float64sAreSorted(x): panic("integrate: input must be sorted") } integral := 0.0 for i := 0; i < n-1; i++ { integral += 0.5 * (x[i+1] - x[i]) * (f[i+1] + f[i]) } return integral } golang-gonum-v1-gonum-0.14.0/integrate/trapezoidal_test.go000066400000000000000000000037571450372207100235400ustar00rootroot00000000000000// Copyright ©2016 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 integrate import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/integrate/testquad" ) func TestTrapezoidal(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i, test := range []struct { integral testquad.Integral n int tol float64 }{ {integral: testquad.Constant(0), n: 2, tol: 0}, {integral: testquad.Constant(0), n: 10, tol: 0}, {integral: testquad.Poly(0), n: 2, tol: 1e-14}, {integral: testquad.Poly(0), n: 10, tol: 1e-14}, {integral: testquad.Poly(1), n: 2, tol: 1e-14}, {integral: testquad.Poly(1), n: 10, tol: 1e-14}, {integral: testquad.Poly(2), n: 1e5, tol: 1e-8}, {integral: testquad.Poly(3), n: 1e5, tol: 1e-8}, {integral: testquad.Poly(4), n: 1e5, tol: 1e-7}, {integral: testquad.Poly(5), n: 1e5, tol: 1e-7}, {integral: testquad.Sin(), n: 1e5, tol: 1e-11}, {integral: testquad.XExpMinusX(), n: 1e5, tol: 1e-10}, {integral: testquad.Sqrt(), n: 1e5, tol: 1e-8}, {integral: testquad.ExpOverX2Plus1(), n: 1e5, tol: 1e-10}, } { n := test.n a := test.integral.A b := test.integral.B x := jitterSpan(n, a, b, rnd) y := make([]float64, n) for i, xi := range x { y[i] = test.integral.F(xi) } got := Trapezoidal(x, y) want := test.integral.Value diff := math.Abs(got - want) if diff > test.tol { t.Errorf("Test #%d: %v, n=%v: unexpected result; got=%v want=%v diff=%v", i, test.integral.Name, n, got, want, diff) } } } func jitterSpan(n int, a, b float64, rnd *rand.Rand) []float64 { dx := (b - a) / float64(n-1) x := make([]float64, n) x[0] = a for i := 1; i < n-1; i++ { // Set x[i] to its regular location. x[i] = a + float64(i)*dx // Generate a random number in [-1,1). jitter := 2*rnd.Float64() - 1 // Jitter x[i] without crossing over its neighbors. x[i] += 0.4 * jitter * dx } x[n-1] = b return x } golang-gonum-v1-gonum-0.14.0/internal/000077500000000000000000000000001450372207100174525ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/README.md000066400000000000000000000004771450372207100207410ustar00rootroot00000000000000# Gonum internal [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/internal)](https://pkg.go.dev/gonum.org/v1/gonum/internal) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/internal?status.svg)](https://godocs.io/gonum.org/v1/gonum/internal) This is the set of internal packages for the Gonum project. golang-gonum-v1-gonum-0.14.0/internal/asm/000077500000000000000000000000001450372207100202325ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/asm/bench_gen.sh000077500000000000000000000016071450372207100225050ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright ©2016 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. cat c64/bench_test.go \ | gofmt -r 'complex(float32(n), float32(n)) -> float32(n)' \ | gofmt -r 'complex64 -> float32' \ | gofmt -r '1 + 1i -> 1' \ | gofmt -r '2 + 2i -> 2' \ | sed 's/C64/F32/g' \ | sed 's/c64/f32/g' \ > f32/bench_test.go cat c64/bench_test.go \ | gofmt -r 'complex(float32(n), float32(n)) -> float64(n)' \ | gofmt -r 'complex64 -> float64' \ | gofmt -r '1 + 1i -> 1' \ | gofmt -r '2 + 2i -> 2' \ | sed 's/C64/F64/g' \ | sed 's/c64/f64/g' \ > f64/bench_test.go cat c64/bench_test.go \ | gofmt -r 'float32 -> float64' \ | gofmt -r 'complex64 -> complex128' \ | sed 's/C64/C128/g' \ | sed 's/c64/c128/g' \ > c128/bench_test.go golang-gonum-v1-gonum-0.14.0/internal/asm/c128/000077500000000000000000000000001450372207100207075ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/asm/c128/asm_test.go000066400000000000000000000057051450372207100230640ustar00rootroot00000000000000// 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 c128_test import ( "math" "math/cmplx" "testing" "gonum.org/v1/gonum/cmplxs/cscalar" "gonum.org/v1/gonum/floats/scalar" ) const ( msgVal = "%v: unexpected value at %v Got: %v Expected: %v" msgGuard = "%v: Guard violated in %s vector %v %v" ) var ( nan = math.NaN() cnan = cmplx.NaN() cinf = cmplx.Inf() ) // TODO(kortschak): Harmonise the situation in asm/{f32,f64} and their sinks. const testLen = 1e5 var x = make([]complex128, testLen) // guardVector copies the source vector (vec) into a new slice with guards. // Guards guarded[:gdLn] and guarded[len-gdLn:] will be filled with sigil value gdVal. func guardVector(vec []complex128, gdVal complex128, gdLn int) (guarded []complex128) { guarded = make([]complex128, len(vec)+gdLn*2) copy(guarded[gdLn:], vec) for i := 0; i < gdLn; i++ { guarded[i] = gdVal guarded[len(guarded)-1-i] = gdVal } return guarded } // isValidGuard will test for violated guards, generated by guardVector. func isValidGuard(vec []complex128, gdVal complex128, gdLn int) bool { for i := 0; i < gdLn; i++ { if !cscalar.Same(vec[i], gdVal) || !cscalar.Same(vec[len(vec)-1-i], gdVal) { return false } } return true } // guardIncVector copies the source vector (vec) into a new incremented slice with guards. // End guards will be length gdLen. // Internal and end guards will be filled with sigil value gdVal. func guardIncVector(vec []complex128, gdVal complex128, inc, gdLen int) (guarded []complex128) { if inc < 0 { inc = -inc } inrLen := len(vec) * inc guarded = make([]complex128, inrLen+gdLen*2) for i := range guarded { guarded[i] = gdVal } for i, v := range vec { guarded[gdLen+i*inc] = v } return guarded } // checkValidIncGuard will test for violated guards, generated by guardIncVector func checkValidIncGuard(t *testing.T, vec []complex128, gdVal complex128, inc, gdLen int) { srcLn := len(vec) - 2*gdLen for i := range vec { switch { case cscalar.Same(vec[i], gdVal): // Correct value case (i-gdLen)%inc == 0 && (i-gdLen)/inc < len(vec): // Ignore input values case i < gdLen: t.Errorf("Front guard violated at %d %v", i, vec[:gdLen]) case i > gdLen+srcLn: t.Errorf("Back guard violated at %d %v", i-gdLen-srcLn, vec[gdLen+srcLn:]) default: t.Errorf("Internal guard violated at %d %v", i-gdLen, vec[gdLen:gdLen+srcLn]) } } } // sameApprox tests for nan-aware equality within tolerance. func sameApprox(a, b, tol float64) bool { return scalar.Same(a, b) || scalar.EqualWithinAbsOrRel(a, b, tol, tol) } // sameCmplxApprox tests for nan-aware equality within tolerance. func sameCmplxApprox(a, b complex128, tol float64) bool { return cscalar.Same(a, b) || cscalar.EqualWithinAbsOrRel(a, b, tol, tol) } var ( // Offset sets for testing alignment handling in Unitary assembly functions. align1 = []int{0, 1} ) golang-gonum-v1-gonum-0.14.0/internal/asm/c128/axpyinc_amd64.s000066400000000000000000000104521450372207100235430ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVDDUP X2, X3 #define MOVDDUP_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xDA // MOVDDUP X4, X5 #define MOVDDUP_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xEC // MOVDDUP X6, X7 #define MOVDDUP_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xFE // MOVDDUP X8, X9 #define MOVDDUP_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC8 // ADDSUBPD X2, X3 #define ADDSUBPD_X2_X3 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // ADDSUBPD X4, X5 #define ADDSUBPD_X4_X5 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // ADDSUBPD X6, X7 #define ADDSUBPD_X6_X7 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // ADDSUBPD X8, X9 #define ADDSUBPD_X8_X9 BYTE $0x66; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyInc(alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) TEXT ·AxpyInc(SB), NOSPLIT, $0 MOVQ x_base+16(FP), SI // SI = &x MOVQ y_base+40(FP), DI // DI = &y MOVQ n+64(FP), CX // CX = n CMPQ CX, $0 // if n==0 { return } JE axpyi_end MOVQ ix+88(FP), R8 // R8 = ix // Load the first index SHLQ $4, R8 // R8 *= sizeof(complex128) MOVQ iy+96(FP), R9 // R9 = iy SHLQ $4, R9 // R9 *= sizeof(complex128) LEAQ (SI)(R8*1), SI // SI = &(x[ix]) LEAQ (DI)(R9*1), DI // DI = &(y[iy]) MOVQ DI, DX // DX = DI // Separate Read/Write pointers MOVQ incX+72(FP), R8 // R8 = incX SHLQ $4, R8 // R8 *= sizeof(complex128) MOVQ incY+80(FP), R9 // R9 = iy SHLQ $4, R9 // R9 *= sizeof(complex128) MOVUPS alpha+0(FP), X0 // X0 = { imag(a), real(a) } MOVAPS X0, X1 SHUFPD $0x1, X1, X1 // X1 = { real(a), imag(a) } MOVAPS X0, X10 // Copy X0 and X1 for pipelining MOVAPS X1, X11 MOVQ CX, BX ANDQ $3, CX // CX = n % 4 SHRQ $2, BX // BX = floor( n / 4 ) JZ axpyi_tail // if BX == 0 { goto axpyi_tail } axpyi_loop: // do { MOVUPS (SI), X2 // X_i = { imag(x[i]), real(x[i]) } MOVUPS (SI)(R8*1), X4 LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) MOVUPS (SI), X6 MOVUPS (SI)(R8*1), X8 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_X2_X3 MOVDDUP_X4_X5 MOVDDUP_X6_X7 MOVDDUP_X8_X9 // X_i = { imag(x[i]), imag(x[i]) } SHUFPD $0x3, X2, X2 SHUFPD $0x3, X4, X4 SHUFPD $0x3, X6, X6 SHUFPD $0x3, X8, X8 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X1, X2 MULPD X0, X3 MULPD X11, X4 MULPD X10, X5 MULPD X1, X6 MULPD X0, X7 MULPD X11, X8 MULPD X10, X9 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DX), X3 ADDPD (DX)(R9*1), X5 LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) ADDPD (DX), X7 ADDPD (DX)(R9*1), X9 MOVUPS X3, (DI) // dst[i] = X_(i+1) MOVUPS X5, (DI)(R9*1) LEAQ (DI)(R9*2), DI MOVUPS X7, (DI) MOVUPS X9, (DI)(R9*1) LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) LEAQ (DI)(R9*2), DI // DI = &(DI[incY*2]) DECQ BX JNZ axpyi_loop // } while --BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE axpyi_end axpyi_tail: // do { MOVUPS (SI), X2 // X_i = { imag(x[i]), real(x[i]) } MOVDDUP_X2_X3 // X_(i+1) = { real(x[i], real(x[i]) } SHUFPD $0x3, X2, X2 // X_i = { imag(x[i]), imag(x[i]) } MULPD X1, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X0, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DI), X3 MOVUPS X3, (DI) // y[i] = X_i ADDQ R8, SI // SI = &(SI[incX]) ADDQ R9, DI // DI = &(DI[incY]) LOOP axpyi_tail // } while --CX > 0 axpyi_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/axpyincto_amd64.s000066400000000000000000000111441450372207100241050ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVDDUP X2, X3 #define MOVDDUP_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xDA // MOVDDUP X4, X5 #define MOVDDUP_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xEC // MOVDDUP X6, X7 #define MOVDDUP_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xFE // MOVDDUP X8, X9 #define MOVDDUP_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC8 // ADDSUBPD X2, X3 #define ADDSUBPD_X2_X3 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // ADDSUBPD X4, X5 #define ADDSUBPD_X4_X5 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // ADDSUBPD X6, X7 #define ADDSUBPD_X6_X7 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // ADDSUBPD X8, X9 #define ADDSUBPD_X8_X9 BYTE $0x66; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyIncTo(dst []complex128, incDst, idst uintptr, alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) TEXT ·AxpyIncTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ x_base+56(FP), SI // SI = &x MOVQ y_base+80(FP), DX // DX = &y MOVQ n+104(FP), CX // CX = n CMPQ CX, $0 // if n==0 { return } JE axpyi_end MOVQ ix+128(FP), R8 // R8 = ix // Load the first index SHLQ $4, R8 // R8 *= sizeof(complex128) MOVQ iy+136(FP), R9 // R9 = iy SHLQ $4, R9 // R9 *= sizeof(complex128) MOVQ idst+32(FP), R10 // R10 = idst SHLQ $4, R10 // R10 *= sizeof(complex128) LEAQ (SI)(R8*1), SI // SI = &(x[ix]) LEAQ (DX)(R9*1), DX // DX = &(y[iy]) LEAQ (DI)(R10*1), DI // DI = &(dst[idst]) MOVQ incX+112(FP), R8 // R8 = incX SHLQ $4, R8 // R8 *= sizeof(complex128) MOVQ incY+120(FP), R9 // R9 = incY SHLQ $4, R9 // R9 *= sizeof(complex128) MOVQ incDst+24(FP), R10 // R10 = incDst SHLQ $4, R10 // R10 *= sizeof(complex128) MOVUPS alpha+40(FP), X0 // X0 = { imag(a), real(a) } MOVAPS X0, X1 SHUFPD $0x1, X1, X1 // X1 = { real(a), imag(a) } MOVAPS X0, X10 // Copy X0 and X1 for pipelining MOVAPS X1, X11 MOVQ CX, BX ANDQ $3, CX // CX = n % 4 SHRQ $2, BX // BX = floor( n / 4 ) JZ axpyi_tail // if BX == 0 { goto axpyi_tail } axpyi_loop: // do { MOVUPS (SI), X2 // X_i = { imag(x[i]), real(x[i]) } MOVUPS (SI)(R8*1), X4 LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) MOVUPS (SI), X6 MOVUPS (SI)(R8*1), X8 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_X2_X3 MOVDDUP_X4_X5 MOVDDUP_X6_X7 MOVDDUP_X8_X9 // X_i = { imag(x[i]), imag(x[i]) } SHUFPD $0x3, X2, X2 SHUFPD $0x3, X4, X4 SHUFPD $0x3, X6, X6 SHUFPD $0x3, X8, X8 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X1, X2 MULPD X0, X3 MULPD X11, X4 MULPD X10, X5 MULPD X1, X6 MULPD X0, X7 MULPD X11, X8 MULPD X10, X9 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DX), X3 ADDPD (DX)(R9*1), X5 LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) ADDPD (DX), X7 ADDPD (DX)(R9*1), X9 MOVUPS X3, (DI) // dst[i] = X_(i+1) MOVUPS X5, (DI)(R10*1) LEAQ (DI)(R10*2), DI MOVUPS X7, (DI) MOVUPS X9, (DI)(R10*1) LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) LEAQ (DI)(R10*2), DI // DI = &(DI[incDst*2]) DECQ BX JNZ axpyi_loop // } while --BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE axpyi_end axpyi_tail: // do { MOVUPS (SI), X2 // X_i = { imag(x[i]), real(x[i]) } MOVDDUP_X2_X3 // X_(i+1) = { real(x[i], real(x[i]) } SHUFPD $0x3, X2, X2 // X_i = { imag(x[i]), imag(x[i]) } MULPD X1, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X0, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DX), X3 MOVUPS X3, (DI) // y[i] X_(i+1) ADDQ R8, SI // SI += incX ADDQ R9, DX // DX += incY ADDQ R10, DI // DI += incDst LOOP axpyi_tail // } while --CX > 0 axpyi_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/axpyunitary_amd64.s000066400000000000000000000074061450372207100244720ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVDDUP X2, X3 #define MOVDDUP_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xDA // MOVDDUP X4, X5 #define MOVDDUP_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xEC // MOVDDUP X6, X7 #define MOVDDUP_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xFE // MOVDDUP X8, X9 #define MOVDDUP_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC8 // ADDSUBPD X2, X3 #define ADDSUBPD_X2_X3 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // ADDSUBPD X4, X5 #define ADDSUBPD_X4_X5 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // ADDSUBPD X6, X7 #define ADDSUBPD_X6_X7 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // ADDSUBPD X8, X9 #define ADDSUBPD_X8_X9 BYTE $0x66; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyUnitary(alpha complex128, x, y []complex128) TEXT ·AxpyUnitary(SB), NOSPLIT, $0 MOVQ x_base+16(FP), SI // SI = &x MOVQ y_base+40(FP), DI // DI = &y MOVQ x_len+24(FP), CX // CX = min( len(x), len(y) ) CMPQ y_len+48(FP), CX CMOVQLE y_len+48(FP), CX CMPQ CX, $0 // if CX == 0 { return } JE caxy_end PXOR X0, X0 // Clear work registers and cache-align loop PXOR X1, X1 MOVUPS alpha+0(FP), X0 // X0 = { imag(a), real(a) } MOVAPS X0, X1 SHUFPD $0x1, X1, X1 // X1 = { real(a), imag(a) } XORQ AX, AX // i = 0 MOVAPS X0, X10 // Copy X0 and X1 for pipelining MOVAPS X1, X11 MOVQ CX, BX ANDQ $3, CX // CX = n % 4 SHRQ $2, BX // BX = floor( n / 4 ) JZ caxy_tail // if BX == 0 { goto caxy_tail } caxy_loop: // do { MOVUPS (SI)(AX*8), X2 // X_i = { imag(x[i]), real(x[i]) } MOVUPS 16(SI)(AX*8), X4 MOVUPS 32(SI)(AX*8), X6 MOVUPS 48(SI)(AX*8), X8 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_X2_X3 MOVDDUP_X4_X5 MOVDDUP_X6_X7 MOVDDUP_X8_X9 // X_i = { imag(x[i]), imag(x[i]) } SHUFPD $0x3, X2, X2 SHUFPD $0x3, X4, X4 SHUFPD $0x3, X6, X6 SHUFPD $0x3, X8, X8 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X1, X2 MULPD X0, X3 MULPD X11, X4 MULPD X10, X5 MULPD X1, X6 MULPD X0, X7 MULPD X11, X8 MULPD X10, X9 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DI)(AX*8), X3 ADDPD 16(DI)(AX*8), X5 ADDPD 32(DI)(AX*8), X7 ADDPD 48(DI)(AX*8), X9 MOVUPS X3, (DI)(AX*8) // y[i] = X_(i+1) MOVUPS X5, 16(DI)(AX*8) MOVUPS X7, 32(DI)(AX*8) MOVUPS X9, 48(DI)(AX*8) ADDQ $8, AX // i += 8 DECQ BX JNZ caxy_loop // } while --BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE caxy_end caxy_tail: // do { MOVUPS (SI)(AX*8), X2 // X_i = { imag(x[i]), real(x[i]) } MOVDDUP_X2_X3 // X_(i+1) = { real(x[i], real(x[i]) } SHUFPD $0x3, X2, X2 // X_i = { imag(x[i]), imag(x[i]) } MULPD X1, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X0, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DI)(AX*8), X3 MOVUPS X3, (DI)(AX*8) // y[i] = X_(i+1) ADDQ $2, AX // i += 2 LOOP caxy_tail // } while --CX > 0 caxy_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/axpyunitaryto_amd64.s000066400000000000000000000077021450372207100250340ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVDDUP X2, X3 #define MOVDDUP_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xDA // MOVDDUP X4, X5 #define MOVDDUP_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xEC // MOVDDUP X6, X7 #define MOVDDUP_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0x12; BYTE $0xFE // MOVDDUP X8, X9 #define MOVDDUP_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC8 // ADDSUBPD X2, X3 #define ADDSUBPD_X2_X3 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // ADDSUBPD X4, X5 #define ADDSUBPD_X4_X5 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // ADDSUBPD X6, X7 #define ADDSUBPD_X6_X7 BYTE $0x66; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // ADDSUBPD X8, X9 #define ADDSUBPD_X8_X9 BYTE $0x66; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyUnitaryTo(dst []complex128, alpha complex64, x, y []complex128) TEXT ·AxpyUnitaryTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ x_base+40(FP), SI // SI = &x MOVQ y_base+64(FP), DX // DX = &y MOVQ x_len+48(FP), CX // CX = min( len(x), len(y), len(dst) ) CMPQ y_len+72(FP), CX CMOVQLE y_len+72(FP), CX CMPQ dst_len+8(FP), CX CMOVQLE dst_len+8(FP), CX CMPQ CX, $0 // if CX == 0 { return } JE caxy_end MOVUPS alpha+24(FP), X0 // X0 = { imag(a), real(a) } MOVAPS X0, X1 SHUFPD $0x1, X1, X1 // X1 = { real(a), imag(a) } XORQ AX, AX // i = 0 MOVAPS X0, X10 // Copy X0 and X1 for pipelining MOVAPS X1, X11 MOVQ CX, BX ANDQ $3, CX // CX = n % 4 SHRQ $2, BX // BX = floor( n / 4 ) JZ caxy_tail // if BX == 0 { goto caxy_tail } caxy_loop: // do { MOVUPS (SI)(AX*8), X2 // X_i = { imag(x[i]), real(x[i]) } MOVUPS 16(SI)(AX*8), X4 MOVUPS 32(SI)(AX*8), X6 MOVUPS 48(SI)(AX*8), X8 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_X2_X3 // Load and duplicate imag elements (xi, xi) MOVDDUP_X4_X5 MOVDDUP_X6_X7 MOVDDUP_X8_X9 // X_i = { imag(x[i]), imag(x[i]) } SHUFPD $0x3, X2, X2 // duplicate real elements (xr, xr) SHUFPD $0x3, X4, X4 SHUFPD $0x3, X6, X6 SHUFPD $0x3, X8, X8 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X1, X2 MULPD X0, X3 MULPD X11, X4 MULPD X10, X5 MULPD X1, X6 MULPD X0, X7 MULPD X11, X8 MULPD X10, X9 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DX)(AX*8), X3 ADDPD 16(DX)(AX*8), X5 ADDPD 32(DX)(AX*8), X7 ADDPD 48(DX)(AX*8), X9 MOVUPS X3, (DI)(AX*8) // y[i] = X_(i+1) MOVUPS X5, 16(DI)(AX*8) MOVUPS X7, 32(DI)(AX*8) MOVUPS X9, 48(DI)(AX*8) ADDQ $8, AX // i += 8 DECQ BX JNZ caxy_loop // } while --BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE caxy_end caxy_tail: // Same calculation, but read in values to avoid trampling memory MOVUPS (SI)(AX*8), X2 // X_i = { imag(x[i]), real(x[i]) } MOVDDUP_X2_X3 // X_(i+1) = { real(x[i], real(x[i]) } SHUFPD $0x3, X2, X2 // X_i = { imag(x[i]), imag(x[i]) } MULPD X1, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X0, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 // X_(i+1) = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } ADDPD (DX)(AX*8), X3 MOVUPS X3, (DI)(AX*8) // y[i] = X_(i+1) ADDQ $2, AX // i += 2 LOOP caxy_tail // } while --CX > 0 caxy_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/benchDot_test.go000066400000000000000000000025541450372207100240310ustar00rootroot00000000000000// 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 c128 import ( "fmt" "testing" ) func BenchmarkDotUnitary(t *testing.B) { for _, test := range []struct { name string f func(x, y []complex128) complex128 }{ {"DotcUnitary", DotcUnitary}, {"DotuUnitary", DotuUnitary}, } { for _, v := range []int64{1, 2, 3, 4, 5, 10, 100, 1e3, 5e3, 1e4, 5e4} { t.Run(fmt.Sprintf("%s-%d", test.name, v), func(b *testing.B) { x, y := x[:v], y[:v] b.SetBytes(256 * v) for i := 0; i < b.N; i++ { benchSink = test.f(x, y) } }) } } } func BenchmarkDotInc(t *testing.B) { for _, test := range []struct { name string f func(x, y []complex128, n, incX, incY, ix, iy uintptr) complex128 }{ {"DotcInc", DotcInc}, {"DotuInc", DotuInc}, } { for _, ln := range []int{1, 2, 3, 4, 5, 10, 100, 1e3, 5e3, 1e4, 5e4} { for _, inc := range []int{1, 2, 4, 10, -1, -2, -4, -10} { t.Run(fmt.Sprintf("%s-%d-inc%d", test.name, ln, inc), func(b *testing.B) { b.SetBytes(int64(256 * ln)) var idx int if inc < 0 { idx = (-ln + 1) * inc } for i := 0; i < b.N; i++ { benchSink = test.f(x, y, uintptr(ln), uintptr(inc), uintptr(inc), uintptr(idx), uintptr(idx)) } }) } } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/bench_test.go000066400000000000000000000404321450372207100233570ustar00rootroot00000000000000// Copyright ©2016 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 c128 import "testing" var ( a = complex128(2 + 2i) x = make([]complex128, 1000000) y = make([]complex128, 1000000) z = make([]complex128, 1000000) ) func init() { for n := range x { x[n] = complex(float64(n), float64(n)) y[n] = complex(float64(n), float64(n)) } } func benchaxpyu(t *testing.B, n int, f func(a complex128, x, y []complex128)) { x, y := x[:n], y[:n] for i := 0; i < t.N; i++ { f(a, x, y) } } func naiveaxpyu(a complex128, x, y []complex128) { for i, v := range x { y[i] += a * v } } func BenchmarkC128AxpyUnitary1(t *testing.B) { benchaxpyu(t, 1, AxpyUnitary) } func BenchmarkC128AxpyUnitary2(t *testing.B) { benchaxpyu(t, 2, AxpyUnitary) } func BenchmarkC128AxpyUnitary3(t *testing.B) { benchaxpyu(t, 3, AxpyUnitary) } func BenchmarkC128AxpyUnitary4(t *testing.B) { benchaxpyu(t, 4, AxpyUnitary) } func BenchmarkC128AxpyUnitary5(t *testing.B) { benchaxpyu(t, 5, AxpyUnitary) } func BenchmarkC128AxpyUnitary10(t *testing.B) { benchaxpyu(t, 10, AxpyUnitary) } func BenchmarkC128AxpyUnitary100(t *testing.B) { benchaxpyu(t, 100, AxpyUnitary) } func BenchmarkC128AxpyUnitary1000(t *testing.B) { benchaxpyu(t, 1000, AxpyUnitary) } func BenchmarkC128AxpyUnitary5000(t *testing.B) { benchaxpyu(t, 5000, AxpyUnitary) } func BenchmarkC128AxpyUnitary10000(t *testing.B) { benchaxpyu(t, 10000, AxpyUnitary) } func BenchmarkC128AxpyUnitary50000(t *testing.B) { benchaxpyu(t, 50000, AxpyUnitary) } func BenchmarkLC128AxpyUnitary1(t *testing.B) { benchaxpyu(t, 1, naiveaxpyu) } func BenchmarkLC128AxpyUnitary2(t *testing.B) { benchaxpyu(t, 2, naiveaxpyu) } func BenchmarkLC128AxpyUnitary3(t *testing.B) { benchaxpyu(t, 3, naiveaxpyu) } func BenchmarkLC128AxpyUnitary4(t *testing.B) { benchaxpyu(t, 4, naiveaxpyu) } func BenchmarkLC128AxpyUnitary5(t *testing.B) { benchaxpyu(t, 5, naiveaxpyu) } func BenchmarkLC128AxpyUnitary10(t *testing.B) { benchaxpyu(t, 10, naiveaxpyu) } func BenchmarkLC128AxpyUnitary100(t *testing.B) { benchaxpyu(t, 100, naiveaxpyu) } func BenchmarkLC128AxpyUnitary1000(t *testing.B) { benchaxpyu(t, 1000, naiveaxpyu) } func BenchmarkLC128AxpyUnitary5000(t *testing.B) { benchaxpyu(t, 5000, naiveaxpyu) } func BenchmarkLC128AxpyUnitary10000(t *testing.B) { benchaxpyu(t, 10000, naiveaxpyu) } func BenchmarkLC128AxpyUnitary50000(t *testing.B) { benchaxpyu(t, 50000, naiveaxpyu) } func benchaxpyut(t *testing.B, n int, f func(d []complex128, a complex128, x, y []complex128)) { x, y, z := x[:n], y[:n], z[:n] for i := 0; i < t.N; i++ { f(z, a, x, y) } } func naiveaxpyut(d []complex128, a complex128, x, y []complex128) { for i, v := range x { d[i] = y[i] + a*v } } func BenchmarkC128AxpyUnitaryTo1(t *testing.B) { benchaxpyut(t, 1, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo2(t *testing.B) { benchaxpyut(t, 2, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo3(t *testing.B) { benchaxpyut(t, 3, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo4(t *testing.B) { benchaxpyut(t, 4, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo5(t *testing.B) { benchaxpyut(t, 5, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo10(t *testing.B) { benchaxpyut(t, 10, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo100(t *testing.B) { benchaxpyut(t, 100, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo1000(t *testing.B) { benchaxpyut(t, 1000, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo5000(t *testing.B) { benchaxpyut(t, 5000, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo10000(t *testing.B) { benchaxpyut(t, 10000, AxpyUnitaryTo) } func BenchmarkC128AxpyUnitaryTo50000(t *testing.B) { benchaxpyut(t, 50000, AxpyUnitaryTo) } func BenchmarkLC128AxpyUnitaryTo1(t *testing.B) { benchaxpyut(t, 1, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo2(t *testing.B) { benchaxpyut(t, 2, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo3(t *testing.B) { benchaxpyut(t, 3, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo4(t *testing.B) { benchaxpyut(t, 4, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo5(t *testing.B) { benchaxpyut(t, 5, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo10(t *testing.B) { benchaxpyut(t, 10, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo100(t *testing.B) { benchaxpyut(t, 100, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo1000(t *testing.B) { benchaxpyut(t, 1000, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo5000(t *testing.B) { benchaxpyut(t, 5000, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo10000(t *testing.B) { benchaxpyut(t, 10000, naiveaxpyut) } func BenchmarkLC128AxpyUnitaryTo50000(t *testing.B) { benchaxpyut(t, 50000, naiveaxpyut) } func benchaxpyinc(t *testing.B, ln, t_inc int, f func(alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr)) { n, inc := uintptr(ln), uintptr(t_inc) var idx int if t_inc < 0 { idx = (-ln + 1) * t_inc } for i := 0; i < t.N; i++ { f(1+1i, x, y, n, inc, inc, uintptr(idx), uintptr(idx)) } } func naiveaxpyinc(alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } func BenchmarkC128AxpyIncN1Inc1(b *testing.B) { benchaxpyinc(b, 1, 1, AxpyInc) } func BenchmarkC128AxpyIncN2Inc1(b *testing.B) { benchaxpyinc(b, 2, 1, AxpyInc) } func BenchmarkC128AxpyIncN2Inc2(b *testing.B) { benchaxpyinc(b, 2, 2, AxpyInc) } func BenchmarkC128AxpyIncN2Inc4(b *testing.B) { benchaxpyinc(b, 2, 4, AxpyInc) } func BenchmarkC128AxpyIncN2Inc10(b *testing.B) { benchaxpyinc(b, 2, 10, AxpyInc) } func BenchmarkC128AxpyIncN3Inc1(b *testing.B) { benchaxpyinc(b, 3, 1, AxpyInc) } func BenchmarkC128AxpyIncN3Inc2(b *testing.B) { benchaxpyinc(b, 3, 2, AxpyInc) } func BenchmarkC128AxpyIncN3Inc4(b *testing.B) { benchaxpyinc(b, 3, 4, AxpyInc) } func BenchmarkC128AxpyIncN3Inc10(b *testing.B) { benchaxpyinc(b, 3, 10, AxpyInc) } func BenchmarkC128AxpyIncN4Inc1(b *testing.B) { benchaxpyinc(b, 4, 1, AxpyInc) } func BenchmarkC128AxpyIncN4Inc2(b *testing.B) { benchaxpyinc(b, 4, 2, AxpyInc) } func BenchmarkC128AxpyIncN4Inc4(b *testing.B) { benchaxpyinc(b, 4, 4, AxpyInc) } func BenchmarkC128AxpyIncN4Inc10(b *testing.B) { benchaxpyinc(b, 4, 10, AxpyInc) } func BenchmarkC128AxpyIncN10Inc1(b *testing.B) { benchaxpyinc(b, 10, 1, AxpyInc) } func BenchmarkC128AxpyIncN10Inc2(b *testing.B) { benchaxpyinc(b, 10, 2, AxpyInc) } func BenchmarkC128AxpyIncN10Inc4(b *testing.B) { benchaxpyinc(b, 10, 4, AxpyInc) } func BenchmarkC128AxpyIncN10Inc10(b *testing.B) { benchaxpyinc(b, 10, 10, AxpyInc) } func BenchmarkC128AxpyIncN1000Inc1(b *testing.B) { benchaxpyinc(b, 1000, 1, AxpyInc) } func BenchmarkC128AxpyIncN1000Inc2(b *testing.B) { benchaxpyinc(b, 1000, 2, AxpyInc) } func BenchmarkC128AxpyIncN1000Inc4(b *testing.B) { benchaxpyinc(b, 1000, 4, AxpyInc) } func BenchmarkC128AxpyIncN1000Inc10(b *testing.B) { benchaxpyinc(b, 1000, 10, AxpyInc) } func BenchmarkC128AxpyIncN100000Inc1(b *testing.B) { benchaxpyinc(b, 100000, 1, AxpyInc) } func BenchmarkC128AxpyIncN100000Inc2(b *testing.B) { benchaxpyinc(b, 100000, 2, AxpyInc) } func BenchmarkC128AxpyIncN100000Inc4(b *testing.B) { benchaxpyinc(b, 100000, 4, AxpyInc) } func BenchmarkC128AxpyIncN100000Inc10(b *testing.B) { benchaxpyinc(b, 100000, 10, AxpyInc) } func BenchmarkC128AxpyIncN100000IncM1(b *testing.B) { benchaxpyinc(b, 100000, -1, AxpyInc) } func BenchmarkC128AxpyIncN100000IncM2(b *testing.B) { benchaxpyinc(b, 100000, -2, AxpyInc) } func BenchmarkC128AxpyIncN100000IncM4(b *testing.B) { benchaxpyinc(b, 100000, -4, AxpyInc) } func BenchmarkC128AxpyIncN100000IncM10(b *testing.B) { benchaxpyinc(b, 100000, -10, AxpyInc) } func BenchmarkLC128AxpyIncN1Inc1(b *testing.B) { benchaxpyinc(b, 1, 1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN2Inc1(b *testing.B) { benchaxpyinc(b, 2, 1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN2Inc2(b *testing.B) { benchaxpyinc(b, 2, 2, naiveaxpyinc) } func BenchmarkLC128AxpyIncN2Inc4(b *testing.B) { benchaxpyinc(b, 2, 4, naiveaxpyinc) } func BenchmarkLC128AxpyIncN2Inc10(b *testing.B) { benchaxpyinc(b, 2, 10, naiveaxpyinc) } func BenchmarkLC128AxpyIncN3Inc1(b *testing.B) { benchaxpyinc(b, 3, 1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN3Inc2(b *testing.B) { benchaxpyinc(b, 3, 2, naiveaxpyinc) } func BenchmarkLC128AxpyIncN3Inc4(b *testing.B) { benchaxpyinc(b, 3, 4, naiveaxpyinc) } func BenchmarkLC128AxpyIncN3Inc10(b *testing.B) { benchaxpyinc(b, 3, 10, naiveaxpyinc) } func BenchmarkLC128AxpyIncN4Inc1(b *testing.B) { benchaxpyinc(b, 4, 1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN4Inc2(b *testing.B) { benchaxpyinc(b, 4, 2, naiveaxpyinc) } func BenchmarkLC128AxpyIncN4Inc4(b *testing.B) { benchaxpyinc(b, 4, 4, naiveaxpyinc) } func BenchmarkLC128AxpyIncN4Inc10(b *testing.B) { benchaxpyinc(b, 4, 10, naiveaxpyinc) } func BenchmarkLC128AxpyIncN10Inc1(b *testing.B) { benchaxpyinc(b, 10, 1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN10Inc2(b *testing.B) { benchaxpyinc(b, 10, 2, naiveaxpyinc) } func BenchmarkLC128AxpyIncN10Inc4(b *testing.B) { benchaxpyinc(b, 10, 4, naiveaxpyinc) } func BenchmarkLC128AxpyIncN10Inc10(b *testing.B) { benchaxpyinc(b, 10, 10, naiveaxpyinc) } func BenchmarkLC128AxpyIncN1000Inc1(b *testing.B) { benchaxpyinc(b, 1000, 1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN1000Inc2(b *testing.B) { benchaxpyinc(b, 1000, 2, naiveaxpyinc) } func BenchmarkLC128AxpyIncN1000Inc4(b *testing.B) { benchaxpyinc(b, 1000, 4, naiveaxpyinc) } func BenchmarkLC128AxpyIncN1000Inc10(b *testing.B) { benchaxpyinc(b, 1000, 10, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000Inc1(b *testing.B) { benchaxpyinc(b, 100000, 1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000Inc2(b *testing.B) { benchaxpyinc(b, 100000, 2, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000Inc4(b *testing.B) { benchaxpyinc(b, 100000, 4, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000Inc10(b *testing.B) { benchaxpyinc(b, 100000, 10, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000IncM1(b *testing.B) { benchaxpyinc(b, 100000, -1, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000IncM2(b *testing.B) { benchaxpyinc(b, 100000, -2, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000IncM4(b *testing.B) { benchaxpyinc(b, 100000, -4, naiveaxpyinc) } func BenchmarkLC128AxpyIncN100000IncM10(b *testing.B) { benchaxpyinc(b, 100000, -10, naiveaxpyinc) } func benchaxpyincto(t *testing.B, ln, t_inc int, f func(dst []complex128, incDst, idst uintptr, alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr)) { n, inc := uintptr(ln), uintptr(t_inc) var idx int if t_inc < 0 { idx = (-ln + 1) * t_inc } for i := 0; i < t.N; i++ { f(z, inc, uintptr(idx), 1+1i, x, y, n, inc, inc, uintptr(idx), uintptr(idx)) } } func naiveaxpyincto(dst []complex128, incDst, idst uintptr, alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } func BenchmarkC128AxpyIncToN1Inc1(b *testing.B) { benchaxpyincto(b, 1, 1, AxpyIncTo) } func BenchmarkC128AxpyIncToN2Inc1(b *testing.B) { benchaxpyincto(b, 2, 1, AxpyIncTo) } func BenchmarkC128AxpyIncToN2Inc2(b *testing.B) { benchaxpyincto(b, 2, 2, AxpyIncTo) } func BenchmarkC128AxpyIncToN2Inc4(b *testing.B) { benchaxpyincto(b, 2, 4, AxpyIncTo) } func BenchmarkC128AxpyIncToN2Inc10(b *testing.B) { benchaxpyincto(b, 2, 10, AxpyIncTo) } func BenchmarkC128AxpyIncToN3Inc1(b *testing.B) { benchaxpyincto(b, 3, 1, AxpyIncTo) } func BenchmarkC128AxpyIncToN3Inc2(b *testing.B) { benchaxpyincto(b, 3, 2, AxpyIncTo) } func BenchmarkC128AxpyIncToN3Inc4(b *testing.B) { benchaxpyincto(b, 3, 4, AxpyIncTo) } func BenchmarkC128AxpyIncToN3Inc10(b *testing.B) { benchaxpyincto(b, 3, 10, AxpyIncTo) } func BenchmarkC128AxpyIncToN4Inc1(b *testing.B) { benchaxpyincto(b, 4, 1, AxpyIncTo) } func BenchmarkC128AxpyIncToN4Inc2(b *testing.B) { benchaxpyincto(b, 4, 2, AxpyIncTo) } func BenchmarkC128AxpyIncToN4Inc4(b *testing.B) { benchaxpyincto(b, 4, 4, AxpyIncTo) } func BenchmarkC128AxpyIncToN4Inc10(b *testing.B) { benchaxpyincto(b, 4, 10, AxpyIncTo) } func BenchmarkC128AxpyIncToN10Inc1(b *testing.B) { benchaxpyincto(b, 10, 1, AxpyIncTo) } func BenchmarkC128AxpyIncToN10Inc2(b *testing.B) { benchaxpyincto(b, 10, 2, AxpyIncTo) } func BenchmarkC128AxpyIncToN10Inc4(b *testing.B) { benchaxpyincto(b, 10, 4, AxpyIncTo) } func BenchmarkC128AxpyIncToN10Inc10(b *testing.B) { benchaxpyincto(b, 10, 10, AxpyIncTo) } func BenchmarkC128AxpyIncToN1000Inc1(b *testing.B) { benchaxpyincto(b, 1000, 1, AxpyIncTo) } func BenchmarkC128AxpyIncToN1000Inc2(b *testing.B) { benchaxpyincto(b, 1000, 2, AxpyIncTo) } func BenchmarkC128AxpyIncToN1000Inc4(b *testing.B) { benchaxpyincto(b, 1000, 4, AxpyIncTo) } func BenchmarkC128AxpyIncToN1000Inc10(b *testing.B) { benchaxpyincto(b, 1000, 10, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000Inc1(b *testing.B) { benchaxpyincto(b, 100000, 1, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000Inc2(b *testing.B) { benchaxpyincto(b, 100000, 2, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000Inc4(b *testing.B) { benchaxpyincto(b, 100000, 4, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000Inc10(b *testing.B) { benchaxpyincto(b, 100000, 10, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000IncM1(b *testing.B) { benchaxpyincto(b, 100000, -1, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000IncM2(b *testing.B) { benchaxpyincto(b, 100000, -2, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000IncM4(b *testing.B) { benchaxpyincto(b, 100000, -4, AxpyIncTo) } func BenchmarkC128AxpyIncToN100000IncM10(b *testing.B) { benchaxpyincto(b, 100000, -10, AxpyIncTo) } func BenchmarkLC128AxpyIncToN1Inc1(b *testing.B) { benchaxpyincto(b, 1, 1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN2Inc1(b *testing.B) { benchaxpyincto(b, 2, 1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN2Inc2(b *testing.B) { benchaxpyincto(b, 2, 2, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN2Inc4(b *testing.B) { benchaxpyincto(b, 2, 4, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN2Inc10(b *testing.B) { benchaxpyincto(b, 2, 10, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN3Inc1(b *testing.B) { benchaxpyincto(b, 3, 1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN3Inc2(b *testing.B) { benchaxpyincto(b, 3, 2, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN3Inc4(b *testing.B) { benchaxpyincto(b, 3, 4, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN3Inc10(b *testing.B) { benchaxpyincto(b, 3, 10, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN4Inc1(b *testing.B) { benchaxpyincto(b, 4, 1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN4Inc2(b *testing.B) { benchaxpyincto(b, 4, 2, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN4Inc4(b *testing.B) { benchaxpyincto(b, 4, 4, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN4Inc10(b *testing.B) { benchaxpyincto(b, 4, 10, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN10Inc1(b *testing.B) { benchaxpyincto(b, 10, 1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN10Inc2(b *testing.B) { benchaxpyincto(b, 10, 2, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN10Inc4(b *testing.B) { benchaxpyincto(b, 10, 4, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN10Inc10(b *testing.B) { benchaxpyincto(b, 10, 10, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN1000Inc1(b *testing.B) { benchaxpyincto(b, 1000, 1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN1000Inc2(b *testing.B) { benchaxpyincto(b, 1000, 2, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN1000Inc4(b *testing.B) { benchaxpyincto(b, 1000, 4, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN1000Inc10(b *testing.B) { benchaxpyincto(b, 1000, 10, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000Inc1(b *testing.B) { benchaxpyincto(b, 100000, 1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000Inc2(b *testing.B) { benchaxpyincto(b, 100000, 2, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000Inc4(b *testing.B) { benchaxpyincto(b, 100000, 4, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000Inc10(b *testing.B) { benchaxpyincto(b, 100000, 10, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000IncM1(b *testing.B) { benchaxpyincto(b, 100000, -1, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000IncM2(b *testing.B) { benchaxpyincto(b, 100000, -2, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000IncM4(b *testing.B) { benchaxpyincto(b, 100000, -4, naiveaxpyincto) } func BenchmarkLC128AxpyIncToN100000IncM10(b *testing.B) { benchaxpyincto(b, 100000, -10, naiveaxpyincto) } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/doc.go000066400000000000000000000004321450372207100220020ustar00rootroot00000000000000// 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 c128 provides complex128 vector primitives. package c128 // import "gonum.org/v1/gonum/internal/asm/c128" golang-gonum-v1-gonum-0.14.0/internal/asm/c128/dot_test.go000066400000000000000000000123211450372207100230620ustar00rootroot00000000000000// 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 c128 import ( "fmt" "testing" "gonum.org/v1/gonum/cmplxs/cscalar" ) var dotTests = []struct { x, y []complex128 wantu, wantc complex128 wantuRev, wantcRev complex128 n int }{ { x: []complex128{}, y: []complex128{}, n: 0, wantu: 0, wantc: 0, wantuRev: 0, wantcRev: 0, }, { x: []complex128{1 + 1i}, y: []complex128{1 + 1i}, n: 1, wantu: 0 + 2i, wantc: 2, wantuRev: 0 + 2i, wantcRev: 2, }, { x: []complex128{1 + 2i}, y: []complex128{1 + 1i}, n: 1, wantu: -1 + 3i, wantc: 3 - 1i, wantuRev: -1 + 3i, wantcRev: 3 - 1i, }, { x: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, y: []complex128{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, n: 10, wantu: -210 + 2860i, wantc: 2870 + 0i, wantuRev: -210 + 1540i, wantcRev: 1550 + 0i, }, { x: []complex128{1 + 1i, 1 + 1i, 1 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 3i, 1 + 1i, 1 + 1i, 1 + 4i}, y: []complex128{1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i}, n: 10, wantu: -22 + 36i, wantc: 42 + 4i, wantuRev: -22 + 36i, wantcRev: 42 + 4i, }, { x: []complex128{1 + 1i, 1 + 1i, 2 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 1i}, y: []complex128{1 + 2i, 1 + 2i, 1 + 3i, 1 + 2i, 1 + 3i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i}, n: 10, wantu: -10 + 37i, wantc: 34 + 17i, wantuRev: -10 + 36i, wantcRev: 34 + 16i, }, { x: []complex128{1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, complex(inf, 1), 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i}, y: []complex128{1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i}, n: 10, wantu: complex(inf, inf), wantc: complex(inf, inf), wantuRev: complex(inf, inf), wantcRev: complex(inf, inf), }, } func TestDotcUnitary(t *testing.T) { const gd = 1 + 5i for i, test := range dotTests { for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, align.x, align.y) xgLn, ygLn := 4+align.x, 4+align.y xg, yg := guardVector(test.x, gd, xgLn), guardVector(test.y, gd, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] res := DotcUnitary(x, y) if !cscalar.Same(res, test.wantc) { t.Errorf(msgVal, prefix, i, res, test.wantc) } if !isValidGuard(xg, gd, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, gd, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } } } } func TestDotcInc(t *testing.T) { const gd, gdLn = 2 + 5i, 4 for i, test := range dotTests { for _, inc := range newIncSet(1, 2, 5, 10, -1, -2, -5, -10) { xg, yg := guardIncVector(test.x, gd, inc.x, gdLn), guardIncVector(test.y, gd, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] want := test.wantc var ix, iy int if inc.x < 0 { ix, want = -inc.x*(test.n-1), test.wantcRev } if inc.y < 0 { iy, want = -inc.y*(test.n-1), test.wantcRev } prefix := fmt.Sprintf("Test %v (x:%v y:%v) (ix:%v iy:%v)", i, inc.x, inc.y, ix, iy) res := DotcInc(x, y, uintptr(test.n), uintptr(inc.x), uintptr(inc.y), uintptr(ix), uintptr(iy)) if inc.x*inc.y > 0 { want = test.wantc } if !cscalar.Same(res, want) { t.Errorf(msgVal, prefix, i, res, want) t.Error(x, y) } checkValidIncGuard(t, xg, gd, inc.x, gdLn) checkValidIncGuard(t, yg, gd, inc.y, gdLn) } } } func TestDotuUnitary(t *testing.T) { const gd = 1 + 5i for i, test := range dotTests { for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, align.x, align.y) xgLn, ygLn := 4+align.x, 4+align.y xg, yg := guardVector(test.x, gd, xgLn), guardVector(test.y, gd, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] res := DotuUnitary(x, y) if !cscalar.Same(res, test.wantu) { t.Errorf(msgVal, prefix, i, res, test.wantu) } if !isValidGuard(xg, gd, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, gd, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } } } } func TestDotuInc(t *testing.T) { const gd, gdLn = 1 + 5i, 4 for i, test := range dotTests { for _, inc := range newIncSet(1, 2, 5, 10, -1, -2, -5, -10) { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, inc.x, inc.y) xg, yg := guardIncVector(test.x, gd, inc.x, gdLn), guardIncVector(test.y, gd, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] want := test.wantc var ix, iy int if inc.x < 0 { ix, want = -inc.x*(test.n-1), test.wantuRev } if inc.y < 0 { iy, want = -inc.y*(test.n-1), test.wantuRev } res := DotuInc(x, y, uintptr(test.n), uintptr(inc.x), uintptr(inc.y), uintptr(ix), uintptr(iy)) if inc.x*inc.y > 0 { want = test.wantu } if !cscalar.Same(res, want) { t.Errorf(msgVal, prefix, i, res, want) } checkValidIncGuard(t, xg, gd, inc.x, gdLn) checkValidIncGuard(t, yg, gd, inc.y, gdLn) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/dotcinc_amd64.s000066400000000000000000000122621450372207100235140ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVDDUP_XPTR__X3 LONG $0x1E120FF2 // MOVDDUP (SI), X3 #define MOVDDUP_XPTR_INCX__X5 LONG $0x120F42F2; WORD $0x062C // MOVDDUP (SI)(R8*1), X5 #define MOVDDUP_XPTR_INCX_2__X7 LONG $0x120F42F2; WORD $0x463C // MOVDDUP (SI)(R8*2), X7 #define MOVDDUP_XPTR_INCx3X__X9 LONG $0x120F46F2; WORD $0x0E0C // MOVDDUP (SI)(R9*1), X9 #define MOVDDUP_8_XPTR__X2 LONG $0x56120FF2; BYTE $0x08 // MOVDDUP 8(SI), X2 #define MOVDDUP_8_XPTR_INCX__X4 LONG $0x120F42F2; WORD $0x0664; BYTE $0x08 // MOVDDUP 8(SI)(R8*1), X4 #define MOVDDUP_8_XPTR_INCX_2__X6 LONG $0x120F42F2; WORD $0x4674; BYTE $0x08 // MOVDDUP 8(SI)(R8*2), X6 #define MOVDDUP_8_XPTR_INCx3X__X8 LONG $0x120F46F2; WORD $0x0E44; BYTE $0x08 // MOVDDUP 8(SI)(R9*1), X8 #define ADDSUBPD_X2_X3 LONG $0xDAD00F66 // ADDSUBPD X2, X3 #define ADDSUBPD_X4_X5 LONG $0xECD00F66 // ADDSUBPD X4, X5 #define ADDSUBPD_X6_X7 LONG $0xFED00F66 // ADDSUBPD X6, X7 #define ADDSUBPD_X8_X9 LONG $0xD00F4566; BYTE $0xC8 // ADDSUBPD X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define INC_X R8 #define INCx3_X R9 #define INC_Y R10 #define INCx3_Y R11 #define NEG1 X15 #define P_NEG1 X14 // func DotcInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) TEXT ·DotcInc(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y MOVQ n+48(FP), LEN // LEN = n PXOR SUM, SUM // SUM = 0 CMPQ LEN, $0 // if LEN == 0 { return } JE dot_end PXOR P_SUM, P_SUM // P_SUM = 0 MOVQ ix+72(FP), INC_X // INC_X = ix * sizeof(complex128) SHLQ $4, INC_X MOVQ iy+80(FP), INC_Y // INC_Y = iy * sizeof(complex128) SHLQ $4, INC_Y LEAQ (X_PTR)(INC_X*1), X_PTR // X_PTR = &(X_PTR[ix]) LEAQ (Y_PTR)(INC_Y*1), Y_PTR // Y_PTR = &(Y_PTR[iy]) MOVQ incX+56(FP), INC_X // INC_X = incX SHLQ $4, INC_X // INC_X *= sizeof(complex128) MOVQ incY+64(FP), INC_Y // INC_Y = incY SHLQ $4, INC_Y // INC_Y *= sizeof(complex128) MOVSD $(-1.0), NEG1 SHUFPD $0, NEG1, NEG1 // { -1, -1 } MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = n % 4 SHRQ $2, LEN // LEN = floor( n / 4 ) JZ dot_tail // if n <= 4 { goto dot_tail } MOVAPS NEG1, P_NEG1 // Copy NEG1 to P_NEG1 for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = 3 * incX * sizeof(complex128) LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = 3 * incY * sizeof(complex128) dot_loop: // do { MOVDDUP_XPTR__X3 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_XPTR_INCX__X5 MOVDDUP_XPTR_INCX_2__X7 MOVDDUP_XPTR_INCx3X__X9 MOVDDUP_8_XPTR__X2 // X_i = { imag(x[i]), imag(x[i]) } MOVDDUP_8_XPTR_INCX__X4 MOVDDUP_8_XPTR_INCX_2__X6 MOVDDUP_8_XPTR_INCx3X__X8 // X_i = { -imag(x[i]), -imag(x[i]) } MULPD NEG1, X2 MULPD P_NEG1, X4 MULPD NEG1, X6 MULPD P_NEG1, X8 // X_j = { imag(y[i]), real(y[i]) } MOVUPS (Y_PTR), X10 MOVUPS (Y_PTR)(INC_Y*1), X11 MOVUPS (Y_PTR)(INC_Y*2), X12 MOVUPS (Y_PTR)(INCx3_Y*1), X13 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X10, X3 MULPD X11, X5 MULPD X12, X7 MULPD X13, X9 // X_j = { real(y[i]), imag(y[i]) } SHUFPD $0x1, X10, X10 SHUFPD $0x1, X11, X11 SHUFPD $0x1, X12, X12 SHUFPD $0x1, X13, X13 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X10, X2 MULPD X11, X4 MULPD X12, X6 MULPD X13, X8 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // psum += result[i] ADDPD X3, SUM ADDPD X5, P_SUM ADDPD X7, SUM ADDPD X9, P_SUM LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[incX*4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[incY*4]) DECQ LEN JNZ dot_loop // } while --LEN > 0 ADDPD P_SUM, SUM // sum += psum CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail: // do { MOVDDUP_XPTR__X3 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_8_XPTR__X2 // X_i = { imag(x[i]), imag(x[i]) } MULPD NEG1, X2 // X_i = { -imag(x[i]) , -imag(x[i]) } MOVUPS (Y_PTR), X10 // X_j = { imag(y[i]) , real(y[i]) } MULPD X10, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } SHUFPD $0x1, X10, X10 // X_j = { real(y[i]) , imag(y[i]) } MULPD X10, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDPD X3, SUM // sum += result[i] ADDQ INC_X, X_PTR // X_PTR += incX ADDQ INC_Y, Y_PTR // Y_PTR += incY DECQ TAIL JNZ dot_tail // } while --TAIL > 0 dot_end: MOVUPS SUM, sum+88(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/dotcunitary_amd64.s000066400000000000000000000112031450372207100244300ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVDDUP_XPTR_IDX_8__X3 LONG $0x1C120FF2; BYTE $0xC6 // MOVDDUP (SI)(AX*8), X3 #define MOVDDUP_16_XPTR_IDX_8__X5 LONG $0x6C120FF2; WORD $0x10C6 // MOVDDUP 16(SI)(AX*8), X5 #define MOVDDUP_32_XPTR_IDX_8__X7 LONG $0x7C120FF2; WORD $0x20C6 // MOVDDUP 32(SI)(AX*8), X7 #define MOVDDUP_48_XPTR_IDX_8__X9 LONG $0x120F44F2; WORD $0xC64C; BYTE $0x30 // MOVDDUP 48(SI)(AX*8), X9 #define MOVDDUP_XPTR_IIDX_8__X2 LONG $0x14120FF2; BYTE $0xD6 // MOVDDUP (SI)(DX*8), X2 #define MOVDDUP_16_XPTR_IIDX_8__X4 LONG $0x64120FF2; WORD $0x10D6 // MOVDDUP 16(SI)(DX*8), X4 #define MOVDDUP_32_XPTR_IIDX_8__X6 LONG $0x74120FF2; WORD $0x20D6 // MOVDDUP 32(SI)(DX*8), X6 #define MOVDDUP_48_XPTR_IIDX_8__X8 LONG $0x120F44F2; WORD $0xD644; BYTE $0x30 // MOVDDUP 48(SI)(DX*8), X8 #define ADDSUBPD_X2_X3 LONG $0xDAD00F66 // ADDSUBPD X2, X3 #define ADDSUBPD_X4_X5 LONG $0xECD00F66 // ADDSUBPD X4, X5 #define ADDSUBPD_X6_X7 LONG $0xFED00F66 // ADDSUBPD X6, X7 #define ADDSUBPD_X8_X9 LONG $0xD00F4566; BYTE $0xC8 // ADDSUBPD X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define IDX AX #define I_IDX DX #define NEG1 X15 #define P_NEG1 X14 // func DotcUnitary(x, y []complex128) (sum complex128) TEXT ·DotcUnitary(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y MOVQ x_len+8(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+32(FP), LEN CMOVQLE y_len+32(FP), LEN PXOR SUM, SUM // sum = 0 CMPQ LEN, $0 // if LEN == 0 { return } JE dot_end XORPS P_SUM, P_SUM // psum = 0 MOVSD $(-1.0), NEG1 SHUFPD $0, NEG1, NEG1 // { -1, -1 } XORQ IDX, IDX // i := 0 MOVQ $1, I_IDX // j := 1 MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = floor( TAIL / 4 ) SHRQ $2, LEN // LEN = TAIL % 4 JZ dot_tail // if LEN == 0 { goto dot_tail } MOVAPS NEG1, P_NEG1 // Copy NEG1 to P_NEG1 for pipelining dot_loop: // do { MOVDDUP_XPTR_IDX_8__X3 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_16_XPTR_IDX_8__X5 MOVDDUP_32_XPTR_IDX_8__X7 MOVDDUP_48_XPTR_IDX_8__X9 MOVDDUP_XPTR_IIDX_8__X2 // X_i = { imag(x[i]), imag(x[i]) } MOVDDUP_16_XPTR_IIDX_8__X4 MOVDDUP_32_XPTR_IIDX_8__X6 MOVDDUP_48_XPTR_IIDX_8__X8 // X_i = { -imag(x[i]), -imag(x[i]) } MULPD NEG1, X2 MULPD P_NEG1, X4 MULPD NEG1, X6 MULPD P_NEG1, X8 // X_j = { imag(y[i]), real(y[i]) } MOVUPS (Y_PTR)(IDX*8), X10 MOVUPS 16(Y_PTR)(IDX*8), X11 MOVUPS 32(Y_PTR)(IDX*8), X12 MOVUPS 48(Y_PTR)(IDX*8), X13 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X10, X3 MULPD X11, X5 MULPD X12, X7 MULPD X13, X9 // X_j = { real(y[i]), imag(y[i]) } SHUFPD $0x1, X10, X10 SHUFPD $0x1, X11, X11 SHUFPD $0x1, X12, X12 SHUFPD $0x1, X13, X13 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X10, X2 MULPD X11, X4 MULPD X12, X6 MULPD X13, X8 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // psum += result[i] ADDPD X3, SUM ADDPD X5, P_SUM ADDPD X7, SUM ADDPD X9, P_SUM ADDQ $8, IDX // IDX += 8 ADDQ $8, I_IDX // I_IDX += 8 DECQ LEN JNZ dot_loop // } while --LEN > 0 ADDPD P_SUM, SUM // sum += psum CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail: // do { MOVDDUP_XPTR_IDX_8__X3 // X_(i+1) = { real(x[i]) , real(x[i]) } MOVDDUP_XPTR_IIDX_8__X2 // X_i = { imag(x[i]) , imag(x[i]) } MULPD NEG1, X2 // X_i = { -imag(x[i]) , -imag(x[i]) } MOVUPS (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]) , real(y[i]) } MULPD X10, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } SHUFPD $0x1, X10, X10 // X_j = { real(y[i]) , imag(y[i]) } MULPD X10, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDPD X3, SUM // SUM += result[i] ADDQ $2, IDX // IDX += 2 ADDQ $2, I_IDX // I_IDX += 2 DECQ TAIL JNZ dot_tail // } while --TAIL > 0 dot_end: MOVUPS SUM, sum+48(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/dotuinc_amd64.s000066400000000000000000000114441450372207100235370ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVDDUP_XPTR__X3 LONG $0x1E120FF2 // MOVDDUP (SI), X3 #define MOVDDUP_XPTR_INCX__X5 LONG $0x120F42F2; WORD $0x062C // MOVDDUP (SI)(R8*1), X5 #define MOVDDUP_XPTR_INCX_2__X7 LONG $0x120F42F2; WORD $0x463C // MOVDDUP (SI)(R8*2), X7 #define MOVDDUP_XPTR_INCx3X__X9 LONG $0x120F46F2; WORD $0x0E0C // MOVDDUP (SI)(R9*1), X9 #define MOVDDUP_8_XPTR__X2 LONG $0x56120FF2; BYTE $0x08 // MOVDDUP 8(SI), X2 #define MOVDDUP_8_XPTR_INCX__X4 LONG $0x120F42F2; WORD $0x0664; BYTE $0x08 // MOVDDUP 8(SI)(R8*1), X4 #define MOVDDUP_8_XPTR_INCX_2__X6 LONG $0x120F42F2; WORD $0x4674; BYTE $0x08 // MOVDDUP 8(SI)(R8*2), X6 #define MOVDDUP_8_XPTR_INCx3X__X8 LONG $0x120F46F2; WORD $0x0E44; BYTE $0x08 // MOVDDUP 8(SI)(R9*1), X8 #define ADDSUBPD_X2_X3 LONG $0xDAD00F66 // ADDSUBPD X2, X3 #define ADDSUBPD_X4_X5 LONG $0xECD00F66 // ADDSUBPD X4, X5 #define ADDSUBPD_X6_X7 LONG $0xFED00F66 // ADDSUBPD X6, X7 #define ADDSUBPD_X8_X9 LONG $0xD00F4566; BYTE $0xC8 // ADDSUBPD X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define INC_X R8 #define INCx3_X R9 #define INC_Y R10 #define INCx3_Y R11 // func DotuInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) TEXT ·DotuInc(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y MOVQ n+48(FP), LEN // LEN = n PXOR SUM, SUM // sum = 0 CMPQ LEN, $0 // if LEN == 0 { return } JE dot_end MOVQ ix+72(FP), INC_X // INC_X = ix * sizeof(complex128) SHLQ $4, INC_X MOVQ iy+80(FP), INC_Y // INC_Y = iy * sizeof(complex128) SHLQ $4, INC_Y LEAQ (X_PTR)(INC_X*1), X_PTR // X_PTR = &(X_PTR[ix]) LEAQ (Y_PTR)(INC_Y*1), Y_PTR // Y_PTR = &(Y_PTR[iy]) MOVQ incX+56(FP), INC_X // INC_X = incX SHLQ $4, INC_X // INC_X *= sizeof(complex128) MOVQ incY+64(FP), INC_Y // INC_Y = incY SHLQ $4, INC_Y // INC_Y *= sizeof(complex128) MOVQ LEN, TAIL ANDQ $3, TAIL // LEN = LEN % 4 SHRQ $2, LEN // LEN = floor( LEN / 4 ) JZ dot_tail // if LEN <= 4 { goto dot_tail } PXOR P_SUM, P_SUM // psum = 0 LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = 3 * incX * sizeof(complex128) LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = 3 * incY * sizeof(complex128) dot_loop: // do { MOVDDUP_XPTR__X3 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_XPTR_INCX__X5 MOVDDUP_XPTR_INCX_2__X7 MOVDDUP_XPTR_INCx3X__X9 MOVDDUP_8_XPTR__X2 // X_i = { imag(x[i]), imag(x[i]) } MOVDDUP_8_XPTR_INCX__X4 MOVDDUP_8_XPTR_INCX_2__X6 MOVDDUP_8_XPTR_INCx3X__X8 // X_j = { imag(y[i]), real(y[i]) } MOVUPS (Y_PTR), X10 MOVUPS (Y_PTR)(INC_Y*1), X11 MOVUPS (Y_PTR)(INC_Y*2), X12 MOVUPS (Y_PTR)(INCx3_Y*1), X13 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X10, X3 MULPD X11, X5 MULPD X12, X7 MULPD X13, X9 // X_j = { real(y[i]), imag(y[i]) } SHUFPD $0x1, X10, X10 SHUFPD $0x1, X11, X11 SHUFPD $0x1, X12, X12 SHUFPD $0x1, X13, X13 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X10, X2 MULPD X11, X4 MULPD X12, X6 MULPD X13, X8 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // psum += result[i] ADDPD X3, SUM ADDPD X5, P_SUM ADDPD X7, SUM ADDPD X9, P_SUM LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[incX*4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[incY*4]) DECQ LEN JNZ dot_loop // } while --BX > 0 ADDPD P_SUM, SUM // sum += psum CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail: // do { MOVDDUP_XPTR__X3 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_8_XPTR__X2 // X_i = { imag(x[i]), imag(x[i]) } MOVUPS (Y_PTR), X10 // X_j = { imag(y[i]) , real(y[i]) } MULPD X10, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } SHUFPD $0x1, X10, X10 // X_j = { real(y[i]) , imag(y[i]) } MULPD X10, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDPD X3, SUM // sum += result[i] ADDQ INC_X, X_PTR // X_PTR += incX ADDQ INC_Y, Y_PTR // Y_PTR += incY DECQ TAIL // --TAIL JNZ dot_tail // } while TAIL > 0 dot_end: MOVUPS SUM, sum+88(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/dotuunitary_amd64.s000066400000000000000000000104501450372207100244550ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVDDUP_XPTR_IDX_8__X3 LONG $0x1C120FF2; BYTE $0xC6 // MOVDDUP (SI)(AX*8), X3 #define MOVDDUP_16_XPTR_IDX_8__X5 LONG $0x6C120FF2; WORD $0x10C6 // MOVDDUP 16(SI)(AX*8), X5 #define MOVDDUP_32_XPTR_IDX_8__X7 LONG $0x7C120FF2; WORD $0x20C6 // MOVDDUP 32(SI)(AX*8), X7 #define MOVDDUP_48_XPTR_IDX_8__X9 LONG $0x120F44F2; WORD $0xC64C; BYTE $0x30 // MOVDDUP 48(SI)(AX*8), X9 #define MOVDDUP_XPTR_IIDX_8__X2 LONG $0x14120FF2; BYTE $0xD6 // MOVDDUP (SI)(DX*8), X2 #define MOVDDUP_16_XPTR_IIDX_8__X4 LONG $0x64120FF2; WORD $0x10D6 // MOVDDUP 16(SI)(DX*8), X4 #define MOVDDUP_32_XPTR_IIDX_8__X6 LONG $0x74120FF2; WORD $0x20D6 // MOVDDUP 32(SI)(DX*8), X6 #define MOVDDUP_48_XPTR_IIDX_8__X8 LONG $0x120F44F2; WORD $0xD644; BYTE $0x30 // MOVDDUP 48(SI)(DX*8), X8 #define ADDSUBPD_X2_X3 LONG $0xDAD00F66 // ADDSUBPD X2, X3 #define ADDSUBPD_X4_X5 LONG $0xECD00F66 // ADDSUBPD X4, X5 #define ADDSUBPD_X6_X7 LONG $0xFED00F66 // ADDSUBPD X6, X7 #define ADDSUBPD_X8_X9 LONG $0xD00F4566; BYTE $0xC8 // ADDSUBPD X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define IDX AX #define I_IDX DX // func DotuUnitary(x, y []complex128) (sum complex128) TEXT ·DotuUnitary(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y MOVQ x_len+8(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+32(FP), LEN CMOVQLE y_len+32(FP), LEN PXOR SUM, SUM // SUM = 0 CMPQ LEN, $0 // if LEN == 0 { return } JE dot_end PXOR P_SUM, P_SUM // P_SUM = 0 XORQ IDX, IDX // IDX = 0 MOVQ $1, DX // j = 1 MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = floor( LEN / 4 ) SHRQ $2, LEN // LEN = LEN % 4 JZ dot_tail // if LEN == 0 { goto dot_tail } dot_loop: // do { MOVDDUP_XPTR_IDX_8__X3 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_16_XPTR_IDX_8__X5 MOVDDUP_32_XPTR_IDX_8__X7 MOVDDUP_48_XPTR_IDX_8__X9 MOVDDUP_XPTR_IIDX_8__X2 // X_i = { imag(x[i]), imag(x[i]) } MOVDDUP_16_XPTR_IIDX_8__X4 MOVDDUP_32_XPTR_IIDX_8__X6 MOVDDUP_48_XPTR_IIDX_8__X8 // X_j = { imag(y[i]), real(y[i]) } MOVUPS (Y_PTR)(IDX*8), X10 MOVUPS 16(Y_PTR)(IDX*8), X11 MOVUPS 32(Y_PTR)(IDX*8), X12 MOVUPS 48(Y_PTR)(IDX*8), X13 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPD X10, X3 MULPD X11, X5 MULPD X12, X7 MULPD X13, X9 // X_j = { real(y[i]), imag(y[i]) } SHUFPD $0x1, X10, X10 SHUFPD $0x1, X11, X11 SHUFPD $0x1, X12, X12 SHUFPD $0x1, X13, X13 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPD X10, X2 MULPD X11, X4 MULPD X12, X6 MULPD X13, X8 // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 // psum += result[i] ADDPD X3, SUM ADDPD X5, P_SUM ADDPD X7, SUM ADDPD X9, P_SUM ADDQ $8, IDX // IDX += 8 ADDQ $8, I_IDX // I_IDX += 8 DECQ LEN JNZ dot_loop // } while --LEN > 0 ADDPD P_SUM, SUM // SUM += P_SUM CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail: // do { MOVDDUP_XPTR_IDX_8__X3 // X_(i+1) = { real(x[i] , real(x[i]) } MOVDDUP_XPTR_IIDX_8__X2 // X_i = { imag(x[i]) , imag(x[i]) } MOVUPS (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]) , real(y[i]) } MULPD X10, X3 // X_(i+1) = { imag(a) * real(x[i]), real(a) * real(x[i]) } SHUFPD $0x1, X10, X10 // X_j = { real(y[i]) , imag(y[i]) } MULPD X10, X2 // X_i = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_(i+1) = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDPD X3, SUM // psum += result[i] ADDQ $2, IDX // IDX += 2 ADDQ $2, I_IDX // I_IDX += 2 DECQ TAIL // --TAIL JNZ dot_tail // } while TAIL > 0 dot_end: MOVUPS SUM, sum+48(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/dscalinc_amd64.s000066400000000000000000000035061450372207100236520ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SRC SI #define DST SI #define LEN CX #define TAIL BX #define INC R9 #define INC3 R10 #define ALPHA X0 #define ALPHA_2 X1 #define MOVDDUP_ALPHA LONG $0x44120FF2; WORD $0x0824 // MOVDDUP 8(SP), X0 // func DscalInc(alpha float64, x []complex128, n, inc uintptr) TEXT ·DscalInc(SB), NOSPLIT, $0 MOVQ x_base+8(FP), SRC // SRC = &x MOVQ n+32(FP), LEN // LEN = n CMPQ LEN, $0 // if LEN == 0 { return } JE dscal_end MOVDDUP_ALPHA // ALPHA = alpha MOVQ inc+40(FP), INC // INC = inc SHLQ $4, INC // INC = INC * sizeof(complex128) LEAQ (INC)(INC*2), INC3 // INC3 = 3 * INC MOVUPS ALPHA, ALPHA_2 // Copy ALPHA and ALPHA_2 for pipelining MOVQ LEN, TAIL // TAIL = LEN SHRQ $2, LEN // LEN = floor( n / 4 ) JZ dscal_tail // if LEN == 0 { goto dscal_tail } dscal_loop: // do { MOVUPS (SRC), X2 // X_i = x[i] MOVUPS (SRC)(INC*1), X3 MOVUPS (SRC)(INC*2), X4 MOVUPS (SRC)(INC3*1), X5 MULPD ALPHA, X2 // X_i *= ALPHA MULPD ALPHA_2, X3 MULPD ALPHA, X4 MULPD ALPHA_2, X5 MOVUPS X2, (DST) // x[i] = X_i MOVUPS X3, (DST)(INC*1) MOVUPS X4, (DST)(INC*2) MOVUPS X5, (DST)(INC3*1) LEAQ (SRC)(INC*4), SRC // SRC += INC*4 DECQ LEN JNZ dscal_loop // } while --LEN > 0 dscal_tail: ANDQ $3, TAIL // TAIL = TAIL % 4 JE dscal_end // if TAIL == 0 { return } dscal_tail_loop: // do { MOVUPS (SRC), X2 // X_i = x[i] MULPD ALPHA, X2 // X_i *= ALPHA MOVUPS X2, (DST) // x[i] = X_i ADDQ INC, SRC // SRC += INC DECQ TAIL JNZ dscal_tail_loop // } while --TAIL > 0 dscal_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/dscalunitary_amd64.s000066400000000000000000000032521450372207100245720ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SRC SI #define DST SI #define LEN CX #define IDX AX #define TAIL BX #define ALPHA X0 #define ALPHA_2 X1 #define MOVDDUP_ALPHA LONG $0x44120FF2; WORD $0x0824 // MOVDDUP 8(SP), X0 // func DscalUnitary(alpha float64, x []complex128) TEXT ·DscalUnitary(SB), NOSPLIT, $0 MOVQ x_base+8(FP), SRC // SRC = &x MOVQ x_len+16(FP), LEN // LEN = len(x) CMPQ LEN, $0 // if LEN == 0 { return } JE dscal_end MOVDDUP_ALPHA // ALPHA = alpha XORQ IDX, IDX // IDX = 0 MOVUPS ALPHA, ALPHA_2 // Copy ALPHA to ALPHA_2 for pipelining MOVQ LEN, TAIL // TAIL = LEN SHRQ $2, LEN // LEN = floor( n / 4 ) JZ dscal_tail // if LEN == 0 { goto dscal_tail } dscal_loop: // do { MOVUPS (SRC)(IDX*8), X2 // X_i = x[i] MOVUPS 16(SRC)(IDX*8), X3 MOVUPS 32(SRC)(IDX*8), X4 MOVUPS 48(SRC)(IDX*8), X5 MULPD ALPHA, X2 // X_i *= ALPHA MULPD ALPHA_2, X3 MULPD ALPHA, X4 MULPD ALPHA_2, X5 MOVUPS X2, (DST)(IDX*8) // x[i] = X_i MOVUPS X3, 16(DST)(IDX*8) MOVUPS X4, 32(DST)(IDX*8) MOVUPS X5, 48(DST)(IDX*8) ADDQ $8, IDX // IDX += 8 DECQ LEN JNZ dscal_loop // } while --LEN > 0 dscal_tail: ANDQ $3, TAIL // TAIL = TAIL % 4 JZ dscal_end // if TAIL == 0 { return } dscal_tail_loop: // do { MOVUPS (SRC)(IDX*8), X2 // X_i = x[i] MULPD ALPHA, X2 // X_i *= ALPHA MOVUPS X2, (DST)(IDX*8) // x[i] = X_i ADDQ $2, IDX // IDX += 2 DECQ TAIL JNZ dscal_tail_loop // } while --TAIL > 0 dscal_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/l2norm_test.go000066400000000000000000000124041450372207100235070ustar00rootroot00000000000000// Copyright ©2019 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 c128_test import ( "fmt" "math" "math/cmplx" "testing" . "gonum.org/v1/gonum/internal/asm/c128" ) // nanwith copied from floats package func nanwith(payload uint64) complex128 { const ( nanBits = 0x7ff8000000000000 nanMask = 0xfff8000000000000 ) nan := math.Float64frombits(nanBits | (payload &^ nanMask)) return complex(nan, nan) } func TestL2NormUnitary(t *testing.T) { const tol = 1e-15 var src_gd complex128 = 1 for j, v := range []struct { want float64 x []complex128 }{ {want: 0, x: []complex128{}}, {want: 2, x: []complex128{2}}, {want: 2, x: []complex128{2i}}, {want: math.Sqrt(8), x: []complex128{2 + 2i}}, {want: 3.7416573867739413, x: []complex128{1, 2, 3}}, {want: 3.7416573867739413, x: []complex128{-1, -2, -3}}, {want: 3.7416573867739413, x: []complex128{1i, 2i, 3i}}, {want: 3.7416573867739413, x: []complex128{-1i, -2i, -3i}}, {want: math.Sqrt(28), x: []complex128{1 + 1i, 2 + 2i, 3 + 3i}}, {want: math.Sqrt(28), x: []complex128{-1 - 1i, -2 - 2i, -3 - 3i}}, {want: nan, x: []complex128{cnan}}, {want: nan, x: []complex128{1, cinf, 3, nanwith(25), 5}}, {want: 17.88854381999832, x: []complex128{8, -8, 8, -8, 8}}, {want: 2.23606797749979, x: []complex128{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, {want: 17.88854381999832, x: []complex128{8i, -8i, 8i, -8i, 8i}}, {want: 2.23606797749979, x: []complex128{0, 1i, 0, -1i, 0, 1i, 0, -1i, 0, 1i}}, {want: math.Sqrt(640), x: []complex128{8 + 8i, -8 - 8i, 8 + 8i, -8 - 8i, 8 + 8i}}, {want: math.Sqrt(10), x: []complex128{0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L2NormUnitary(src) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Norm error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func TestL2DistanceUnitary(t *testing.T) { const tol = 1e-15 var src_gd complex128 = 1 for j, v := range []struct { want float64 x, y []complex128 }{ {want: 0, x: []complex128{}, y: []complex128{}}, {want: 2, x: []complex128{3}, y: []complex128{1}}, {want: 2, x: []complex128{3i}, y: []complex128{1i}}, {want: 3.7416573867739413, x: []complex128{2, 4, 6}, y: []complex128{1, 2, 3}}, {want: 3.7416573867739413, x: []complex128{1, 2, 3}, y: []complex128{2, 4, 6}}, {want: 3.7416573867739413, x: []complex128{2i, 4i, 6i}, y: []complex128{1i, 2i, 3i}}, {want: 3.7416573867739413, x: []complex128{1i, 2i, 3i}, y: []complex128{2i, 4i, 6i}}, {want: math.Sqrt(28), x: []complex128{2 + 2i, 4 + 4i, 6 + 6i}, y: []complex128{1 + 1i, 2 + 2i, 3 + 3i}}, {want: math.Sqrt(28), x: []complex128{1 + 1i, 2 + 2i, 3 + 3i}, y: []complex128{2 + 2i, 4 + 4i, 6 + 6i}}, {want: nan, x: []complex128{cnan}, y: []complex128{0}}, {want: 17.88854381999832, x: []complex128{9, -9, 9, -9, 9}, y: []complex128{1, -1, 1, -1, 1}}, {want: 2.23606797749979, x: []complex128{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}, y: []complex128{0, 2, 0, -2, 0, 2, 0, -2, 0, 2}}, {want: 17.88854381999832, x: []complex128{9i, -9i, 9i, -9i, 9i}, y: []complex128{1i, -1i, 1i, -1i, 1i}}, {want: 2.23606797749979, x: []complex128{0, 1i, 0, -1i, 0, 1i, 0, -1i, 0, 1i}, y: []complex128{0, 2i, 0, -2i, 0, 2i, 0, -2i, 0, 2i}}, {want: math.Sqrt(640), x: []complex128{9 + 9i, -9 - 9i, 9 + 9i, -9 - 9i, 9 + 9i}, y: []complex128{1 + 1i, -1 - 1i, 1 + 1i, -1 - 1i, 1 + 1i}}, {want: math.Sqrt(10), x: []complex128{0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i}, y: []complex128{0, 2 + 2i, 0, -2 - 2i, 0, 2 + 2i, 0, -2 - 2i, 0, 2 + 2i}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) v.y = guardVector(v.y, src_gd, g_ln) srcX := v.x[g_ln : len(v.x)-g_ln] srcY := v.y[g_ln : len(v.y)-g_ln] ret := L2DistanceUnitary(srcX, srcY) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Distance error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func BenchmarkL2NormNetlib(b *testing.B) { netlib := func(x []complex128) (sum float64) { var scale float64 sumSquares := 1.0 for _, v := range x { if v == 0 { continue } absxi := cmplx.Abs(v) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } tests := []struct { name string f func(x []complex128) float64 }{ {"L2NormUnitaryNetlib", netlib}, {"L2NormUnitary", L2NormUnitary}, } x[0] = 4 // replace the leading zero (edge case) for _, test := range tests { for _, ln := range []uintptr{1, 3, 10, 30, 1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5} { b.Run(fmt.Sprintf("%s-%d", test.name, ln), func(b *testing.B) { b.SetBytes(int64(64 * ln)) x := x[:ln] b.ResetTimer() for i := 0; i < b.N; i++ { test.f(x) } }) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/scal.go000066400000000000000000000013451450372207100221630ustar00rootroot00000000000000// Copyright ©2016 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 c128 // ScalUnitaryTo is // // for i, v := range x { // dst[i] = alpha * v // } func ScalUnitaryTo(dst []complex128, alpha complex128, x []complex128) { for i, v := range x { dst[i] = alpha * v } } // ScalIncTo is // // var idst, ix uintptr // for i := 0; i < int(n); i++ { // dst[idst] = alpha * x[ix] // ix += incX // idst += incDst // } func ScalIncTo(dst []complex128, incDst uintptr, alpha complex128, x []complex128, n, incX uintptr) { var idst, ix uintptr for i := 0; i < int(n); i++ { dst[idst] = alpha * x[ix] ix += incX idst += incDst } } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/scalUnitary_amd64.s000066400000000000000000000066561450372207100244010ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SRC SI #define DST SI #define LEN CX #define IDX AX #define TAIL BX #define ALPHA X0 #define ALPHA_C X1 #define ALPHA2 X10 #define ALPHA_C2 X11 #define MOVDDUP_X2_X3 LONG $0xDA120FF2 // MOVDDUP X2, X3 #define MOVDDUP_X4_X5 LONG $0xEC120FF2 // MOVDDUP X4, X5 #define MOVDDUP_X6_X7 LONG $0xFE120FF2 // MOVDDUP X6, X7 #define MOVDDUP_X8_X9 LONG $0x120F45F2; BYTE $0xC8 // MOVDDUP X8, X9 #define ADDSUBPD_X2_X3 LONG $0xDAD00F66 // ADDSUBPD X2, X3 #define ADDSUBPD_X4_X5 LONG $0xECD00F66 // ADDSUBPD X4, X5 #define ADDSUBPD_X6_X7 LONG $0xFED00F66 // ADDSUBPD X6, X7 #define ADDSUBPD_X8_X9 LONG $0xD00F4566; BYTE $0xC8 // ADDSUBPD X8, X9 // func ScalUnitary(alpha complex128, x []complex128) TEXT ·ScalUnitary(SB), NOSPLIT, $0 MOVQ x_base+16(FP), SRC // SRC = &x MOVQ x_len+24(FP), LEN // LEN = len(x) CMPQ LEN, $0 // if LEN == 0 { return } JE scal_end MOVUPS alpha+0(FP), ALPHA // ALPHA = { imag(alpha), real(alpha) } MOVAPS ALPHA, ALPHA_C SHUFPD $0x1, ALPHA_C, ALPHA_C // ALPHA_C = { real(alpha), imag(alpha) } XORQ IDX, IDX // IDX = 0 MOVAPS ALPHA, ALPHA2 // Copy ALPHA and ALPHA_C for pipelining MOVAPS ALPHA_C, ALPHA_C2 MOVQ LEN, TAIL SHRQ $2, LEN // LEN = floor( n / 4 ) JZ scal_tail // if BX == 0 { goto scal_tail } scal_loop: // do { MOVUPS (SRC)(IDX*8), X2 // X_i = { imag(x[i]), real(x[i]) } MOVUPS 16(SRC)(IDX*8), X4 MOVUPS 32(SRC)(IDX*8), X6 MOVUPS 48(SRC)(IDX*8), X8 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_X2_X3 MOVDDUP_X4_X5 MOVDDUP_X6_X7 MOVDDUP_X8_X9 // X_i = { imag(x[i]), imag(x[i]) } SHUFPD $0x3, X2, X2 SHUFPD $0x3, X4, X4 SHUFPD $0x3, X6, X6 SHUFPD $0x3, X8, X8 // X_i = { real(ALPHA) * imag(x[i]), imag(ALPHA) * imag(x[i]) } // X_(i+1) = { imag(ALPHA) * real(x[i]), real(ALPHA) * real(x[i]) } MULPD ALPHA_C, X2 MULPD ALPHA, X3 MULPD ALPHA_C2, X4 MULPD ALPHA2, X5 MULPD ALPHA_C, X6 MULPD ALPHA, X7 MULPD ALPHA_C2, X8 MULPD ALPHA2, X9 // X_(i+1) = { // imag(result[i]): imag(ALPHA)*real(x[i]) + real(ALPHA)*imag(x[i]), // real(result[i]): real(ALPHA)*real(x[i]) - imag(ALPHA)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 MOVUPS X3, (DST)(IDX*8) // x[i] = X_(i+1) MOVUPS X5, 16(DST)(IDX*8) MOVUPS X7, 32(DST)(IDX*8) MOVUPS X9, 48(DST)(IDX*8) ADDQ $8, IDX // IDX += 8 DECQ LEN JNZ scal_loop // } while --LEN > 0 scal_tail: ANDQ $3, TAIL // TAIL = TAIL % 4 JZ scal_end // if TAIL == 0 { return } scal_tail_loop: // do { MOVUPS (SRC)(IDX*8), X2 // X_i = { imag(x[i]), real(x[i]) } MOVDDUP_X2_X3 // X_(i+1) = { real(x[i], real(x[i]) } SHUFPD $0x3, X2, X2 // X_i = { imag(x[i]), imag(x[i]) } MULPD ALPHA_C, X2 // X_i = { real(ALPHA) * imag(x[i]), imag(ALPHA) * imag(x[i]) } MULPD ALPHA, X3 // X_(i+1) = { imag(ALPHA) * real(x[i]), real(ALPHA) * real(x[i]) } // X_(i+1) = { // imag(result[i]): imag(ALPHA)*real(x[i]) + real(ALPHA)*imag(x[i]), // real(result[i]): real(ALPHA)*real(x[i]) - imag(ALPHA)*imag(x[i]) // } ADDSUBPD_X2_X3 MOVUPS X3, (DST)(IDX*8) // x[i] = X_(i+1) ADDQ $2, IDX // IDX += 2 DECQ TAIL JNZ scal_tail_loop // } while --LEN > 0 scal_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/scalinc_amd64.s000066400000000000000000000070211450372207100235020ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SRC SI #define DST SI #define LEN CX #define TAIL BX #define INC R9 #define INC3 R10 #define ALPHA X0 #define ALPHA_C X1 #define ALPHA2 X10 #define ALPHA_C2 X11 #define MOVDDUP_X2_X3 LONG $0xDA120FF2 // MOVDDUP X2, X3 #define MOVDDUP_X4_X5 LONG $0xEC120FF2 // MOVDDUP X4, X5 #define MOVDDUP_X6_X7 LONG $0xFE120FF2 // MOVDDUP X6, X7 #define MOVDDUP_X8_X9 LONG $0x120F45F2; BYTE $0xC8 // MOVDDUP X8, X9 #define ADDSUBPD_X2_X3 LONG $0xDAD00F66 // ADDSUBPD X2, X3 #define ADDSUBPD_X4_X5 LONG $0xECD00F66 // ADDSUBPD X4, X5 #define ADDSUBPD_X6_X7 LONG $0xFED00F66 // ADDSUBPD X6, X7 #define ADDSUBPD_X8_X9 LONG $0xD00F4566; BYTE $0xC8 // ADDSUBPD X8, X9 // func ScalInc(alpha complex128, x []complex128, n, inc uintptr) TEXT ·ScalInc(SB), NOSPLIT, $0 MOVQ x_base+16(FP), SRC // SRC = &x MOVQ n+40(FP), LEN // LEN = len(x) CMPQ LEN, $0 JE scal_end // if LEN == 0 { return } MOVQ inc+48(FP), INC // INC = inc SHLQ $4, INC // INC = INC * sizeof(complex128) LEAQ (INC)(INC*2), INC3 // INC3 = 3 * INC MOVUPS alpha+0(FP), ALPHA // ALPHA = { imag(alpha), real(alpha) } MOVAPS ALPHA, ALPHA_C SHUFPD $0x1, ALPHA_C, ALPHA_C // ALPHA_C = { real(alpha), imag(alpha) } MOVAPS ALPHA, ALPHA2 // Copy ALPHA and ALPHA_C for pipelining MOVAPS ALPHA_C, ALPHA_C2 MOVQ LEN, TAIL SHRQ $2, LEN // LEN = floor( n / 4 ) JZ scal_tail // if BX == 0 { goto scal_tail } scal_loop: // do { MOVUPS (SRC), X2 // X_i = { imag(x[i]), real(x[i]) } MOVUPS (SRC)(INC*1), X4 MOVUPS (SRC)(INC*2), X6 MOVUPS (SRC)(INC3*1), X8 // X_(i+1) = { real(x[i], real(x[i]) } MOVDDUP_X2_X3 MOVDDUP_X4_X5 MOVDDUP_X6_X7 MOVDDUP_X8_X9 // X_i = { imag(x[i]), imag(x[i]) } SHUFPD $0x3, X2, X2 SHUFPD $0x3, X4, X4 SHUFPD $0x3, X6, X6 SHUFPD $0x3, X8, X8 // X_i = { real(ALPHA) * imag(x[i]), imag(ALPHA) * imag(x[i]) } // X_(i+1) = { imag(ALPHA) * real(x[i]), real(ALPHA) * real(x[i]) } MULPD ALPHA_C, X2 MULPD ALPHA, X3 MULPD ALPHA_C2, X4 MULPD ALPHA2, X5 MULPD ALPHA_C, X6 MULPD ALPHA, X7 MULPD ALPHA_C2, X8 MULPD ALPHA2, X9 // X_(i+1) = { // imag(result[i]): imag(ALPHA)*real(x[i]) + real(ALPHA)*imag(x[i]), // real(result[i]): real(ALPHA)*real(x[i]) - imag(ALPHA)*imag(x[i]) // } ADDSUBPD_X2_X3 ADDSUBPD_X4_X5 ADDSUBPD_X6_X7 ADDSUBPD_X8_X9 MOVUPS X3, (DST) // x[i] = X_(i+1) MOVUPS X5, (DST)(INC*1) MOVUPS X7, (DST)(INC*2) MOVUPS X9, (DST)(INC3*1) LEAQ (SRC)(INC*4), SRC // SRC = &(SRC[inc*4]) DECQ LEN JNZ scal_loop // } while --BX > 0 scal_tail: ANDQ $3, TAIL // TAIL = TAIL % 4 JE scal_end // if TAIL == 0 { return } scal_tail_loop: // do { MOVUPS (SRC), X2 // X_i = { imag(x[i]), real(x[i]) } MOVDDUP_X2_X3 // X_(i+1) = { real(x[i], real(x[i]) } SHUFPD $0x3, X2, X2 // X_i = { imag(x[i]), imag(x[i]) } MULPD ALPHA_C, X2 // X_i = { real(ALPHA) * imag(x[i]), imag(ALPHA) * imag(x[i]) } MULPD ALPHA, X3 // X_(i+1) = { imag(ALPHA) * real(x[i]), real(ALPHA) * real(x[i]) } // X_(i+1) = { // imag(result[i]): imag(ALPHA)*real(x[i]) + real(ALPHA)*imag(x[i]), // real(result[i]): real(ALPHA)*real(x[i]) - imag(ALPHA)*imag(x[i]) // } ADDSUBPD_X2_X3 MOVUPS X3, (DST) // x[i] = X_i ADDQ INC, SRC // SRC = &(SRC[incX]) DECQ TAIL JNZ scal_tail_loop // } while --TAIL > 0 scal_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c128/stubs.go000066400000000000000000000055401450372207100224020ustar00rootroot00000000000000// Copyright ©2020 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 c128 import ( "math" "math/cmplx" ) // Add is // // for i, v := range s { // dst[i] += v // } func Add(dst, s []complex128) { for i, v := range s { dst[i] += v } } // AddConst is // // for i := range x { // x[i] += alpha // } func AddConst(alpha complex128, x []complex128) { for i := range x { x[i] += alpha } } // CumSum is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] + v // } // return dst func CumSum(dst, s []complex128) []complex128 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] + v } return dst } // CumProd is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] * v // } // return dst func CumProd(dst, s []complex128) []complex128 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] * v } return dst } // Div is // // for i, v := range s { // dst[i] /= v // } func Div(dst, s []complex128) { for i, v := range s { dst[i] /= v } } // DivTo is // // for i, v := range s { // dst[i] = v / t[i] // } // return dst func DivTo(dst, s, t []complex128) []complex128 { for i, v := range s { dst[i] = v / t[i] } return dst } // DotUnitary is // // for i, v := range x { // sum += cmplx.Conj(v) * y[i] // } // return sum func DotUnitary(x, y []complex128) (sum complex128) { for i, v := range x { sum += cmplx.Conj(v) * y[i] } return sum } // L2DistanceUnitary returns the L2-norm of x-y. func L2DistanceUnitary(x, y []complex128) (norm float64) { var scale float64 sumSquares := 1.0 for i, v := range x { v -= y[i] if v == 0 { continue } absxi := cmplx.Abs(v) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } // L2NormUnitary returns the L2-norm of x. func L2NormUnitary(x []complex128) (norm float64) { var scale float64 sumSquares := 1.0 for _, v := range x { if v == 0 { continue } absxi := cmplx.Abs(v) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } // Sum is // // var sum complex128 // for i := range x { // sum += x[i] // } func Sum(x []complex128) complex128 { var sum complex128 for _, v := range x { sum += v } return sum } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/stubs_amd64.go000066400000000000000000000044561450372207100234020ustar00rootroot00000000000000// Copyright ©2016 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:build !noasm && !gccgo && !safe // +build !noasm,!gccgo,!safe package c128 // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha complex128, x, y []complex128) // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []complex128, alpha complex128, x, y []complex128) // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []complex128, incDst, idst uintptr, alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) // DscalUnitary is // // for i, v := range x { // x[i] = complex(real(v)*alpha, imag(v)*alpha) // } func DscalUnitary(alpha float64, x []complex128) // DscalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] = complex(real(x[ix])*alpha, imag(x[ix])*alpha) // ix += inc // } func DscalInc(alpha float64, x []complex128, n, inc uintptr) // ScalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] *= alpha // ix += incX // } func ScalInc(alpha complex128, x []complex128, n, inc uintptr) // ScalUnitary is // // for i := range x { // x[i] *= alpha // } func ScalUnitary(alpha complex128, x []complex128) // DotcUnitary is // // for i, v := range x { // sum += y[i] * cmplx.Conj(v) // } // return sum func DotcUnitary(x, y []complex128) (sum complex128) // DotcInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * cmplx.Conj(x[ix]) // ix += incX // iy += incY // } // return sum func DotcInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) // DotuUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotuUnitary(x, y []complex128) (sum complex128) // DotuInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotuInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) golang-gonum-v1-gonum-0.14.0/internal/asm/c128/stubs_noasm.go000066400000000000000000000064371450372207100236050ustar00rootroot00000000000000// Copyright ©2016 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package c128 import "math/cmplx" // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha complex128, x, y []complex128) { for i, v := range x { y[i] += alpha * v } } // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []complex128, alpha complex128, x, y []complex128) { for i, v := range x { dst[i] = alpha*v + y[i] } } // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []complex128, incDst, idst uintptr, alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } // DscalUnitary is // // for i, v := range x { // x[i] = complex(real(v)*alpha, imag(v)*alpha) // } func DscalUnitary(alpha float64, x []complex128) { for i, v := range x { x[i] = complex(real(v)*alpha, imag(v)*alpha) } } // DscalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] = complex(real(x[ix])*alpha, imag(x[ix])*alpha) // ix += inc // } func DscalInc(alpha float64, x []complex128, n, inc uintptr) { var ix uintptr for i := 0; i < int(n); i++ { x[ix] = complex(real(x[ix])*alpha, imag(x[ix])*alpha) ix += inc } } // ScalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] *= alpha // ix += incX // } func ScalInc(alpha complex128, x []complex128, n, inc uintptr) { var ix uintptr for i := 0; i < int(n); i++ { x[ix] *= alpha ix += inc } } // ScalUnitary is // // for i := range x { // x[i] *= alpha // } func ScalUnitary(alpha complex128, x []complex128) { for i := range x { x[i] *= alpha } } // DotcUnitary is // // for i, v := range x { // sum += y[i] * cmplx.Conj(v) // } // return sum func DotcUnitary(x, y []complex128) (sum complex128) { for i, v := range x { sum += y[i] * cmplx.Conj(v) } return sum } // DotcInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * cmplx.Conj(x[ix]) // ix += incX // iy += incY // } // return sum func DotcInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) { for i := 0; i < int(n); i++ { sum += y[iy] * cmplx.Conj(x[ix]) ix += incX iy += incY } return sum } // DotuUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotuUnitary(x, y []complex128) (sum complex128) { for i, v := range x { sum += y[i] * v } return sum } // DotuInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotuInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) { for i := 0; i < int(n); i++ { sum += y[iy] * x[ix] ix += incX iy += incY } return sum } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/stubs_test.go000066400000000000000000000574041450372207100234470ustar00rootroot00000000000000// Copyright ©2016 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 c128_test import ( "fmt" "testing" "gonum.org/v1/gonum/cmplxs/cscalar" . "gonum.org/v1/gonum/internal/asm/c128" ) func TestAdd(t *testing.T) { var src_gd, dst_gd complex128 = 1, 0 for j, v := range []struct { dst, src, expect []complex128 }{ { dst: []complex128{1 + 1i}, src: []complex128{0}, expect: []complex128{1 + 1i}, }, { dst: []complex128{1, 2, 3}, src: []complex128{1 + 1i}, expect: []complex128{2 + 1i, 2, 3}, }, { dst: []complex128{}, src: []complex128{}, expect: []complex128{}, }, { dst: []complex128{1}, src: []complex128{cnan}, expect: []complex128{cnan}, }, { dst: []complex128{8, 8, 8, 8, 8}, src: []complex128{2 + 1i, 4 - 1i, cnan, 8 + 1i, 9 - 1i}, expect: []complex128{10 + 1i, 12 - 1i, cnan, 16 + 1i, 17 - 1i}, }, { dst: []complex128{0, 1 + 1i, 2, 3 - 1i, 4}, src: []complex128{cinf, 4, cnan, 8 + 1i, 9 - 1i}, expect: []complex128{cinf, 5 + 1i, cnan, 11, 13 - 1i}, }, { dst: make([]complex128, 50)[1:49], src: make([]complex128, 50)[1:49], expect: make([]complex128, 50)[1:49], }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] Add(dst, src) for i := range v.expect { if !cscalar.Same(dst[i], v.expect[i]) { t.Errorf("Test %d Add error at %d Got: %v Expected: %v", j, i, dst[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestAddConst(t *testing.T) { var src_gd complex128 = 0 for j, v := range []struct { alpha complex128 src, expect []complex128 }{ { alpha: 1 + 1i, src: []complex128{0}, expect: []complex128{1 + 1i}, }, { alpha: 5, src: []complex128{}, expect: []complex128{}, }, { alpha: 1, src: []complex128{cnan}, expect: []complex128{cnan}, }, { alpha: 8 + 1i, src: []complex128{2, 4, cnan, 8, 9}, expect: []complex128{10 + 1i, 12 + 1i, cnan, 16 + 1i, 17 + 1i}, }, { alpha: cinf, src: []complex128{cinf, 4, cnan, 8, 9}, expect: []complex128{cinf, cinf, cnan, cinf, cinf}, }, } { g_ln := 4 + j%2 v.src = guardVector(v.src, src_gd, g_ln) src := v.src[g_ln : len(v.src)-g_ln] AddConst(v.alpha, src) for i := range v.expect { if !cscalar.Same(src[i], v.expect[i]) { t.Errorf("Test %d AddConst error at %d Got: %v Expected: %v", j, i, src[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:g_ln], v.src[len(v.src)-g_ln:]) } } } var axpyTests = []struct { incX, incY, incDst int ix, iy, idst uintptr a complex128 dst, x, y []complex128 ex []complex128 }{ {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 1i, dst: []complex128{5}, x: []complex128{1}, y: []complex128{1i}, ex: []complex128{1 + 2i}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 2i, dst: []complex128{0, 0, 0}, x: []complex128{0, 0, 0}, y: []complex128{1, 1, 1}, ex: []complex128{1, 1, 1}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 2i, dst: []complex128{0, 0, 0}, x: []complex128{0, 0}, y: []complex128{1, 1, 1}, ex: []complex128{1, 1}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 2i, dst: []complex128{1i, 1i, 1i}, x: []complex128{1i, 1i, 1i}, y: []complex128{1, 2, 1}, ex: []complex128{-1 + 1i, 1i, -1 + 1i}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: -1i, dst: []complex128{1i, 1i, 1i}, x: []complex128{1i, 1i, 1i}, y: []complex128{1, 2, 1}, ex: []complex128{2, 3, 2}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: -1i, dst: []complex128{1i, 1i, 1i}, x: []complex128{1i, 1i, 1i, 1i, 1i}[1:4], y: []complex128{1, 1, 2, 1, 1}[1:4], ex: []complex128{2, 3, 2}}, {incX: 2, incY: 4, incDst: 3, ix: 0, iy: 0, idst: 0, a: -2, dst: []complex128{1i, 1i, 1i, 1i, 1i}, x: []complex128{2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i}, y: []complex128{1, 1, 2, 1, 1}, ex: []complex128{-3 - 2i, -3 - 2i, -2 - 2i, -3 - 2i, -3 - 2i}}, // Run big test twice, once aligned once unaligned. {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 - 1i, dst: make([]complex128, 10), x: []complex128{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex128{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex128{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 - 1i, dst: make([]complex128, 10), x: []complex128{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex128{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex128{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, {incX: -2, incY: -2, incDst: -3, ix: 18, iy: 18, idst: 27, a: 1 - 1i, dst: make([]complex128, 10), x: []complex128{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex128{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex128{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, {incX: -2, incY: 2, incDst: -3, ix: 18, iy: 0, idst: 27, a: 1 - 1i, dst: make([]complex128, 10), x: []complex128{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex128{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex128{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, } func TestAxpyUnitary(t *testing.T) { const xGdVal, yGdVal = 1, 1 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] AxpyUnitary(test.a, x, y) for i := range test.ex { if y[i] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, y[i], test.ex[i]) } } if !isValidGuard(test.x, xGdVal, xgLn) { t.Errorf("Test %d Guard violated in x vector %v %v", cas, test.x[:xgLn], test.x[len(test.x)-xgLn:]) } if !isValidGuard(test.y, yGdVal, ygLn) { t.Errorf("Test %d Guard violated in y vector %v %v", cas, test.y[:ygLn], test.y[len(test.y)-ygLn:]) } } } func TestAxpyUnitaryTo(t *testing.T) { const xGdVal, yGdVal, dstGdVal = 1, 1, 0 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) test.dst = guardVector(test.dst, dstGdVal, xgLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] dst := test.dst[xgLn : len(test.dst)-xgLn] AxpyUnitaryTo(dst, test.a, x, y) for i := range test.ex { if dst[i] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, dst[i], test.ex[i]) } } if !isValidGuard(test.x, xGdVal, xgLn) { t.Errorf("Test %d Guard violated in x vector %v %v", cas, test.x[:xgLn], test.x[len(test.x)-xgLn:]) } if !isValidGuard(test.y, yGdVal, ygLn) { t.Errorf("Test %d Guard violated in y vector %v %v", cas, test.y[:ygLn], test.y[len(test.y)-ygLn:]) } if !isValidGuard(test.dst, dstGdVal, xgLn) { t.Errorf("Test %d Guard violated in dst vector %v %v", cas, test.dst[:xgLn], test.dst[len(test.dst)-xgLn:]) } } } func TestAxpyInc(t *testing.T) { const xGdVal, yGdVal = 1, 1 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardIncVector(test.x, xGdVal, test.incX, xgLn), guardIncVector(test.y, yGdVal, test.incY, ygLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] AxpyInc(test.a, x, y, uintptr(len(test.ex)), uintptr(test.incX), uintptr(test.incY), test.ix, test.iy) for i := range test.ex { if y[int(test.iy)+i*test.incY] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, y[i*test.incY], test.ex[i]) } } checkValidIncGuard(t, test.x, xGdVal, test.incX, xgLn) checkValidIncGuard(t, test.y, yGdVal, test.incY, ygLn) } } func TestAxpyIncTo(t *testing.T) { const xGdVal, yGdVal, dstGdVal = 1, 1, 0 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardIncVector(test.x, xGdVal, test.incX, xgLn), guardIncVector(test.y, yGdVal, test.incY, ygLn) test.dst = guardIncVector(test.dst, dstGdVal, test.incDst, xgLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] dst := test.dst[xgLn : len(test.dst)-xgLn] AxpyIncTo(dst, uintptr(test.incDst), test.idst, test.a, x, y, uintptr(len(test.ex)), uintptr(test.incX), uintptr(test.incY), test.ix, test.iy) for i := range test.ex { if dst[int(test.idst)+i*test.incDst] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, dst[i*test.incDst], test.ex[i]) } } checkValidIncGuard(t, test.x, xGdVal, test.incX, xgLn) checkValidIncGuard(t, test.y, yGdVal, test.incY, ygLn) checkValidIncGuard(t, test.dst, dstGdVal, test.incDst, xgLn) } } func TestCumSum(t *testing.T) { var src_gd, dst_gd complex128 = -1, 0 for j, v := range []struct { dst, src, expect []complex128 }{ { dst: []complex128{}, src: []complex128{}, expect: []complex128{}, }, { dst: []complex128{0}, src: []complex128{1 + 1i}, expect: []complex128{1 + 1i}, }, { dst: []complex128{cnan}, src: []complex128{cnan}, expect: []complex128{cnan}, }, { dst: []complex128{0, 0, 0}, src: []complex128{1, 2 + 1i, 3 + 2i}, expect: []complex128{1, 3 + 1i, 6 + 3i}, }, { dst: []complex128{0, 0, 0, 0}, src: []complex128{1, 2 + 1i, 3 + 2i}, expect: []complex128{1, 3 + 1i, 6 + 3i}, }, { dst: []complex128{0, 0, 0, 0}, src: []complex128{1, 2 + 1i, 3 + 2i, 4 + 3i}, expect: []complex128{1, 3 + 1i, 6 + 3i, 10 + 6i}, }, { dst: []complex128{1, cnan, cnan, 1, 1}, src: []complex128{1, 1, cnan, 1, 1}, expect: []complex128{1, 2, cnan, cnan, cnan}, }, { dst: []complex128{cnan, 4, cinf, cinf, 9}, src: []complex128{cinf, 4, cnan, cinf, 9}, expect: []complex128{cinf, cinf, cnan, cnan, cnan}, }, { dst: make([]complex128, 16), src: []complex128{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, expect: []complex128{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, }, } { g_ln := 4 + j%2 v.src, v.dst = guardVector(v.src, src_gd, g_ln), guardVector(v.dst, dst_gd, g_ln) src, dst := v.src[g_ln:len(v.src)-g_ln], v.dst[g_ln:len(v.dst)-g_ln] ret := CumSum(dst, src) for i := range v.expect { if !cscalar.Same(ret[i], v.expect[i]) { t.Errorf("Test %d CumSum error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !cscalar.Same(ret[i], dst[i]) { t.Errorf("Test %d CumSum ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.src, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:g_ln], v.src[len(v.src)-g_ln:]) } if !isValidGuard(v.dst, dst_gd, g_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:g_ln], v.dst[len(v.dst)-g_ln:]) } } } func TestCumProd(t *testing.T) { var src_gd, dst_gd complex128 = -1, 1 for j, v := range []struct { dst, src, expect []complex128 }{ { dst: []complex128{}, src: []complex128{}, expect: []complex128{}, }, { dst: []complex128{1}, src: []complex128{1 + 1i}, expect: []complex128{1 + 1i}, }, { dst: []complex128{cnan}, src: []complex128{cnan}, expect: []complex128{cnan}, }, { dst: []complex128{0, 0, 0, 0}, src: []complex128{1, 2 + 1i, 3 + 2i, 4 + 3i}, expect: []complex128{1, 2 + 1i, 4 + 7i, -5 + 40i}, }, { dst: []complex128{0, 0, 0}, src: []complex128{1, 2 + 1i, 3 + 2i}, expect: []complex128{1, 2 + 1i, 4 + 7i}, }, { dst: []complex128{0, 0, 0, 0}, src: []complex128{1, 2 + 1i, 3 + 2i}, expect: []complex128{1, 2 + 1i, 4 + 7i}, }, { dst: []complex128{cnan, 1, cnan, 1, 0}, src: []complex128{1, 1, cnan, 1, 1}, expect: []complex128{1, 1, cnan, cnan, cnan}, }, { dst: []complex128{cnan, 4, cnan, cinf, 9}, src: []complex128{cinf, 4, cnan, cinf, 9}, expect: []complex128{cinf, cnan, cnan, cnan, cnan}, }, { dst: make([]complex128, 18), src: []complex128{2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i}, expect: []complex128{2i, -4, -8i, 16, 32i, -64, -128i, 256, 512i, -1024, -2048i, 4096, 8192i, -16384, -32768i, 65536}, }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] ret := CumProd(dst, src) for i := range v.expect { if !cscalar.Same(ret[i], v.expect[i]) { t.Errorf("Test %d CumProd error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !cscalar.Same(ret[i], dst[i]) { t.Errorf("Test %d CumProd ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestDiv(t *testing.T) { const tol = 1e-15 var src_gd, dst_gd complex128 = -1, 0.5 for j, v := range []struct { dst, src, expect []complex128 }{ { dst: []complex128{1 + 1i}, src: []complex128{1 + 1i}, expect: []complex128{1}, }, { dst: []complex128{cnan}, src: []complex128{cnan}, expect: []complex128{cnan}, }, { dst: []complex128{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i}, src: []complex128{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i}, expect: []complex128{1, 1, 1, 1}, }, { dst: []complex128{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i, 2 + 2i, 4 + 2i, 6 + 2i, 8 + 2i}, src: []complex128{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i, 1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i}, expect: []complex128{1, 1, 1, 1, 2, 2, 2, 2}, }, { dst: []complex128{2 + 2i, 4 + 8i, 6 - 12i}, src: []complex128{1 + 1i, 2 + 4i, 3 - 6i}, expect: []complex128{2, 2, 2}, }, { dst: []complex128{0, 0, 0, 0}, src: []complex128{1 + 1i, 2 + 2i, 3 + 3i}, expect: []complex128{0, 0, 0}, }, { dst: []complex128{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, src: []complex128{1, 1, cnan, 1, 1, 1, 1, cnan, 1, 1}, expect: []complex128{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, }, { dst: []complex128{cinf, 4, cnan, cinf, 9, cinf, 4, cnan, cinf, 9}, src: []complex128{cinf, 4, cnan, cinf, 3, cinf, 4, cnan, cinf, 3}, expect: []complex128{cnan, 1, cnan, cnan, 3, cnan, 1, cnan, cnan, 3}, }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] Div(dst, src) for i := range v.expect { if !sameCmplxApprox(dst[i], v.expect[i], tol) { t.Errorf("Test %d Div error at %d Got: %v Expected: %v", j, i, dst[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestDivTo(t *testing.T) { const tol = 1e-15 var dst_gd, x_gd, y_gd complex128 = -1, 0.5, 0.25 for j, v := range []struct { dst, x, y, expect []complex128 }{ { dst: []complex128{1 - 1i}, x: []complex128{1 + 1i}, y: []complex128{1 + 1i}, expect: []complex128{1}, }, { dst: []complex128{1}, x: []complex128{cnan}, y: []complex128{cnan}, expect: []complex128{cnan}, }, { dst: []complex128{-2, -2, -2}, x: []complex128{1 + 1i, 2 + 1i, 3 + 1i}, y: []complex128{1 + 1i, 2 + 1i, 3 + 1i}, expect: []complex128{1, 1, 1}, }, { dst: []complex128{0, 0, 0}, x: []complex128{2 + 2i, 4 + 4i, 6 + 6i}, y: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, expect: []complex128{2, 2, 2}, }, { dst: []complex128{-1, -1, -1}, x: []complex128{0, 0, 0}, y: []complex128{1 + 1i, 2 + 1i, 3 + 1i}, expect: []complex128{0, 0, 0}, }, { dst: []complex128{cinf, cinf, cinf, cinf, cinf, cinf, cinf, cinf, cinf, cinf}, x: []complex128{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, y: []complex128{1, 1, cnan, 1, 1, 1, 1, cnan, 1, 1}, expect: []complex128{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, }, { dst: []complex128{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, x: []complex128{cinf, 4, cnan, cinf, 9, cinf, 4, cnan, cinf, 9}, y: []complex128{cinf, 4, cnan, cinf, 3, cinf, 4, cnan, cinf, 3}, expect: []complex128{cnan, 1, cnan, cnan, 3, cnan, 1, cnan, cnan, 3}, }, } { xg_ln, yg_ln := 4+j%2, 4+j%3 v.y, v.x = guardVector(v.y, y_gd, yg_ln), guardVector(v.x, x_gd, xg_ln) y, x := v.y[yg_ln:len(v.y)-yg_ln], v.x[xg_ln:len(v.x)-xg_ln] v.dst = guardVector(v.dst, dst_gd, xg_ln) dst := v.dst[xg_ln : len(v.dst)-xg_ln] ret := DivTo(dst, x, y) for i := range v.expect { if !sameCmplxApprox(ret[i], v.expect[i], tol) { t.Errorf("Test %d DivTo error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !cscalar.Same(ret[i], dst[i]) { t.Errorf("Test %d DivTo ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.y, y_gd, yg_ln) { t.Errorf("Test %d Guard violated in y vector %v %v", j, v.y[:yg_ln], v.y[len(v.y)-yg_ln:]) } if !isValidGuard(v.x, x_gd, xg_ln) { t.Errorf("Test %d Guard violated in x vector %v %v", j, v.x[:xg_ln], v.x[len(v.x)-xg_ln:]) } if !isValidGuard(v.dst, dst_gd, xg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:xg_ln], v.dst[len(v.dst)-xg_ln:]) } } } var dscalTests = []struct { alpha float64 x []complex128 want []complex128 }{ { alpha: 0, x: []complex128{}, want: []complex128{}, }, { alpha: 1, x: []complex128{1 + 2i}, want: []complex128{1 + 2i}, }, { alpha: 2, x: []complex128{1 + 2i}, want: []complex128{2 + 4i}, }, { alpha: 2, x: []complex128{1 + 2i, 3 + 5i, 6 + 11i, 12 - 23i}, want: []complex128{2 + 4i, 6 + 10i, 12 + 22i, 24 - 46i}, }, { alpha: 3, x: []complex128{1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i}, want: []complex128{3 + 6i, 15 + 12i, 9 + 18i, 24 + 36i, -9 - 6i, -15 + 15i}, }, { alpha: 5, x: []complex128{1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i, 1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i}, want: []complex128{5 + 10i, 25 + 20i, 15 + 30i, 40 + 60i, -15 - 10i, -25 + 25i, 5 + 10i, 25 + 20i, 15 + 30i, 40 + 60i, -15 - 10i, -25 + 25i}, }, } func TestDscalUnitary(t *testing.T) { const xGdVal = -0.5 for i, test := range dscalTests { for _, align := range align1 { prefix := fmt.Sprintf("Test %v (x:%v)", i, align) xgLn := 4 + align xg := guardVector(test.x, xGdVal, xgLn) x := xg[xgLn : len(xg)-xgLn] DscalUnitary(test.alpha, x) for i := range test.want { if !cscalar.Same(x[i], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i], test.want[i]) } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } } } } func TestDscalInc(t *testing.T) { const xGdVal = -0.5 gdLn := 4 for i, test := range dscalTests { n := len(test.x) for _, incX := range []int{1, 2, 3, 4, 7, 10} { prefix := fmt.Sprintf("Test %v (x:%v)", i, incX) xg := guardIncVector(test.x, xGdVal, incX, gdLn) x := xg[gdLn : len(xg)-gdLn] DscalInc(test.alpha, x, uintptr(n), uintptr(incX)) for i := range test.want { if !cscalar.Same(x[i*incX], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i*incX], test.want[i]) } } checkValidIncGuard(t, xg, xGdVal, incX, gdLn) } } } var scalTests = []struct { alpha complex128 x []complex128 want []complex128 }{ { alpha: 0, x: []complex128{}, want: []complex128{}, }, { alpha: 1 + 1i, x: []complex128{1 + 2i}, want: []complex128{-1 + 3i}, }, { alpha: 2 + 3i, x: []complex128{1 + 2i}, want: []complex128{-4 + 7i}, }, { alpha: 2 - 4i, x: []complex128{1 + 2i}, want: []complex128{10}, }, { alpha: 2 + 8i, x: []complex128{1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i}, want: []complex128{-14 + 12i, -22 + 48i, -42 + 36i, -80 + 88i, 10 - 28i, -50 - 30i}, }, { alpha: 5 - 10i, x: []complex128{1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i, 1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i}, want: []complex128{25, 65 - 30i, 75, 160 - 20i, -35 + 20i, 25 + 75i, 25, 65 - 30i, 75, 160 - 20i, -35 + 20i, 25 + 75i}, }, } func TestScalUnitary(t *testing.T) { const xGdVal = -0.5 for i, test := range scalTests { for _, align := range align1 { prefix := fmt.Sprintf("Test %v (x:%v)", i, align) xgLn := 4 + align xg := guardVector(test.x, xGdVal, xgLn) x := xg[xgLn : len(xg)-xgLn] ScalUnitary(test.alpha, x) for i := range test.want { if !cscalar.Same(x[i], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i], test.want[i]) } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } } } } func TestScalInc(t *testing.T) { const xGdVal = -0.5 gdLn := 4 for i, test := range scalTests { n := len(test.x) for _, inc := range []int{1, 2, 3, 4, 7, 10} { prefix := fmt.Sprintf("Test %v (x:%v)", i, inc) xg := guardIncVector(test.x, xGdVal, inc, gdLn) x := xg[gdLn : len(xg)-gdLn] ScalInc(test.alpha, x, uintptr(n), uintptr(inc)) for i := range test.want { if !cscalar.Same(x[i*inc], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i*inc], test.want[i]) } } checkValidIncGuard(t, xg, xGdVal, inc, gdLn) } } } func TestSum(t *testing.T) { var srcGd complex128 = -1 for j, v := range []struct { src []complex128 expect complex128 }{ { src: []complex128{}, expect: 0, }, { src: []complex128{1}, expect: 1, }, { src: []complex128{cnan}, expect: cnan, }, { src: []complex128{1 + 1i, 2 + 2i, 3 + 3i}, expect: 6 + 6i, }, { src: []complex128{1 + 1i, -4, 3 - 1i}, expect: 0, }, { src: []complex128{1 - 1i, 2 + 2i, 3 - 3i, 4 + 4i}, expect: 10 + 2i, }, { src: []complex128{1, 1, cnan, 1, 1}, expect: cnan, }, { src: []complex128{cinf, 4, cnan, cinf, 9}, expect: cnan, }, { src: []complex128{1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 9 + 9i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 5 + 5i, 1 + 1i}, expect: 29 + 29i, }, { src: []complex128{1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 9 + 9i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 5 + 5i, 11 + 11i, 1 + 1i, 1 + 1i, 1 + 1i, 9 + 9i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 5 + 5i, 1 + 1i}, expect: 67 + 67i, }, } { gdLn := 4 + j%2 gsrc := guardVector(v.src, srcGd, gdLn) src := gsrc[gdLn : len(gsrc)-gdLn] ret := Sum(src) if !cscalar.Same(ret, v.expect) { t.Errorf("Test %d Sum error Got: %v Expected: %v", j, ret, v.expect) } if !isValidGuard(gsrc, srcGd, gdLn) { t.Errorf("Test %d Guard violated in src vector %v %v", j, gsrc[:gdLn], gsrc[len(gsrc)-gdLn:]) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c128/util_test.go000066400000000000000000000054661450372207100232650ustar00rootroot00000000000000// Copyright ©2016 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 c128 import ( "math" "testing" ) const ( msgVal = "%v: unexpected value at %v Got: %v Expected: %v" msgGuard = "%v: Guard violated in %s vector %v %v" ) var ( inf = math.Inf(1) benchSink complex128 ) func guardVector(vec []complex128, guard_val complex128, guard_len int) (guarded []complex128) { guarded = make([]complex128, len(vec)+guard_len*2) copy(guarded[guard_len:], vec) for i := 0; i < guard_len; i++ { guarded[i] = guard_val guarded[len(guarded)-1-i] = guard_val } return guarded } func isValidGuard(vec []complex128, guard_val complex128, guard_len int) bool { for i := 0; i < guard_len; i++ { if vec[i] != guard_val || vec[len(vec)-1-i] != guard_val { return false } } return true } func guardIncVector(vec []complex128, guard_val complex128, inc, guard_len int) (guarded []complex128) { s_ln := len(vec) * inc if inc < 0 { s_ln = len(vec) * -inc } guarded = make([]complex128, s_ln+guard_len*2) for i, cas := 0, 0; i < len(guarded); i++ { switch { case i < guard_len, i > guard_len+s_ln: guarded[i] = guard_val case (i-guard_len)%(inc) == 0 && cas < len(vec): guarded[i] = vec[cas] cas++ default: guarded[i] = guard_val } } return guarded } func checkValidIncGuard(t *testing.T, vec []complex128, guard_val complex128, inc, guard_len int) { s_ln := len(vec) - 2*guard_len if inc < 0 { s_ln = len(vec) * -inc } for i := range vec { switch { case vec[i] == guard_val: // Correct value case i < guard_len: t.Errorf("Front guard violated at %d %v", i, vec[:guard_len]) case i > guard_len+s_ln: t.Errorf("Back guard violated at %d %v", i-guard_len-s_ln, vec[guard_len+s_ln:]) case (i-guard_len)%inc == 0 && (i-guard_len)/inc < len(vec): // Ignore input values default: t.Errorf("Internal guard violated at %d %v", i-guard_len, vec[guard_len:guard_len+s_ln]) } } } var ( // Offset sets for testing alignment handling in Unitary assembly functions. align1 = []int{0, 1} align2 = newIncSet(0, 1) align3 = newIncToSet(0, 1) ) type incSet struct { x, y int } // genInc will generate all (x,y) combinations of the input increment set. func newIncSet(inc ...int) []incSet { n := len(inc) is := make([]incSet, n*n) for x := range inc { for y := range inc { is[x*n+y] = incSet{inc[x], inc[y]} } } return is } type incToSet struct { dst, x, y int } // genIncTo will generate all (dst,x,y) combinations of the input increment set. func newIncToSet(inc ...int) []incToSet { n := len(inc) is := make([]incToSet, n*n*n) for i, dst := range inc { for x := range inc { for y := range inc { is[i*n*n+x*n+y] = incToSet{dst, inc[x], inc[y]} } } } return is } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/000077500000000000000000000000001450372207100206265ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/asm/c64/asm_test.go000066400000000000000000000063161450372207100230020ustar00rootroot00000000000000// 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 c64_test import ( "testing" "gonum.org/v1/gonum/cmplxs/cscalar" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/internal/cmplx64" "gonum.org/v1/gonum/internal/math32" ) const ( msgVal = "%v: unexpected value at %v Got: %v Expected: %v" msgGuard = "%v: Guard violated in %s vector %v %v" ) var ( nan = math32.NaN() cnan = cmplx64.NaN() cinf = cmplx64.Inf() ) // TODO(kortschak): Harmonise the situation in asm/{f32,f64} and their sinks. const testLen = 1e5 var x = make([]complex64, testLen) // guardVector copies the source vector (vec) into a new slice with guards. // Guards guarded[:gdLn] and guarded[len-gdLn:] will be filled with sigil value gdVal. func guardVector(vec []complex64, gdVal complex64, gdLn int) (guarded []complex64) { guarded = make([]complex64, len(vec)+gdLn*2) copy(guarded[gdLn:], vec) for i := 0; i < gdLn; i++ { guarded[i] = gdVal guarded[len(guarded)-1-i] = gdVal } return guarded } // isValidGuard will test for violated guards, generated by guardVector. func isValidGuard(vec []complex64, gdVal complex64, gdLn int) bool { for i := 0; i < gdLn; i++ { if !sameCmplx(vec[i], gdVal) || !sameCmplx(vec[len(vec)-1-i], gdVal) { return false } } return true } // guardIncVector copies the source vector (vec) into a new incremented slice with guards. // End guards will be length gdLen. // Internal and end guards will be filled with sigil value gdVal. func guardIncVector(vec []complex64, gdVal complex64, inc, gdLen int) (guarded []complex64) { if inc < 0 { inc = -inc } inrLen := len(vec) * inc guarded = make([]complex64, inrLen+gdLen*2) for i := range guarded { guarded[i] = gdVal } for i, v := range vec { guarded[gdLen+i*inc] = v } return guarded } // checkValidIncGuard will test for violated guards, generated by guardIncVector func checkValidIncGuard(t *testing.T, vec []complex64, gdVal complex64, inc, gdLen int) { srcLn := len(vec) - 2*gdLen for i := range vec { switch { case sameCmplx(vec[i], gdVal): // Correct value case (i-gdLen)%inc == 0 && (i-gdLen)/inc < len(vec): // Ignore input values case i < gdLen: t.Errorf("Front guard violated at %d %v", i, vec[:gdLen]) case i > gdLen+srcLn: t.Errorf("Back guard violated at %d %v", i-gdLen-srcLn, vec[gdLen+srcLn:]) default: t.Errorf("Internal guard violated at %d %v", i-gdLen, vec[gdLen:gdLen+srcLn]) } } } // sameApprox tests for nan-aware equality within tolerance. func sameApprox(a, b, tol float32) bool { return scalar.Same(float64(a), float64(b)) || scalar.EqualWithinAbsOrRel(float64(a), float64(b), float64(tol), float64(tol)) } // sameCmplx tests for nan-aware equality. func sameCmplx(a, b complex64) bool { return cscalar.Same(complex128(a), complex128(b)) } // sameCmplxApprox tests for nan-aware equality within tolerance. func sameCmplxApprox(a, b complex64, tol float32) bool { return sameCmplx(a, b) || cscalar.EqualWithinAbsOrRel(complex128(a), complex128(b), float64(tol), float64(tol)) } var ( // Offset sets for testing alignment handling in Unitary assembly functions. align1 = []int{0, 1} ) golang-gonum-v1-gonum-0.14.0/internal/asm/c64/axpyinc_amd64.s000066400000000000000000000111161450372207100234600ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVSHDUP X3, X2 #define MOVSHDUP_X3_X2 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xD3 // MOVSLDUP X3, X3 #define MOVSLDUP_X3_X3 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xDB // ADDSUBPS X2, X3 #define ADDSUBPS_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // MOVSHDUP X5, X4 #define MOVSHDUP_X5_X4 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xE5 // MOVSLDUP X5, X5 #define MOVSLDUP_X5_X5 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xED // ADDSUBPS X4, X5 #define ADDSUBPS_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // MOVSHDUP X7, X6 #define MOVSHDUP_X7_X6 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xF7 // MOVSLDUP X7, X7 #define MOVSLDUP_X7_X7 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xFF // ADDSUBPS X6, X7 #define ADDSUBPS_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // MOVSHDUP X9, X8 #define MOVSHDUP_X9_X8 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x16; BYTE $0xC1 // MOVSLDUP X9, X9 #define MOVSLDUP_X9_X9 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC9 // ADDSUBPS X8, X9 #define ADDSUBPS_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyInc(alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) TEXT ·AxpyInc(SB), NOSPLIT, $0 MOVQ x_base+8(FP), SI // SI = &x MOVQ y_base+32(FP), DI // DI = &y MOVQ n+56(FP), CX // CX = n CMPQ CX, $0 // if n==0 { return } JE axpyi_end MOVQ ix+80(FP), R8 // R8 = ix MOVQ iy+88(FP), R9 // R9 = iy LEAQ (SI)(R8*8), SI // SI = &(x[ix]) LEAQ (DI)(R9*8), DI // DI = &(y[iy]) MOVQ DI, DX // DX = DI // Read/Write pointers MOVQ incX+64(FP), R8 // R8 = incX SHLQ $3, R8 // R8 *= sizeof(complex64) MOVQ incY+72(FP), R9 // R9 = incY SHLQ $3, R9 // R9 *= sizeof(complex64) MOVSD alpha+0(FP), X0 // X0 = { 0, 0, imag(a), real(a) } MOVAPS X0, X1 SHUFPS $0x11, X1, X1 // X1 = { 0, 0, real(a), imag(a) } MOVAPS X0, X10 // Copy X0 and X1 for pipelining MOVAPS X1, X11 MOVQ CX, BX ANDQ $3, CX // CX = n % 4 SHRQ $2, BX // BX = floor( n / 4 ) JZ axpyi_tail // if BX == 0 { goto axpyi_tail } axpyi_loop: // do { MOVSD (SI), X3 // X_i = { imag(x[i+1]), real(x[i+1]) } MOVSD (SI)(R8*1), X5 LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) MOVSD (SI), X7 MOVSD (SI)(R8*1), X9 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSHDUP_X3_X2 MOVSHDUP_X5_X4 MOVSHDUP_X7_X6 MOVSHDUP_X9_X8 // X_i = { real(x[i]), real(x[i]) } MOVSLDUP_X3_X3 MOVSLDUP_X5_X5 MOVSLDUP_X7_X7 MOVSLDUP_X9_X9 // X_(i-1) = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_i = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPS X1, X2 MULPS X0, X3 MULPS X11, X4 MULPS X10, X5 MULPS X1, X6 MULPS X0, X7 MULPS X11, X8 MULPS X10, X9 // X_i = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]), // } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // X_i = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } MOVSD (DX), X2 MOVSD (DX)(R9*1), X4 LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) MOVSD (DX), X6 MOVSD (DX)(R9*1), X8 ADDPS X2, X3 ADDPS X4, X5 ADDPS X6, X7 ADDPS X8, X9 MOVSD X3, (DI) // y[i] = X_i MOVSD X5, (DI)(R9*1) LEAQ (DI)(R9*2), DI // DI = &(DI[incDst]) MOVSD X7, (DI) MOVSD X9, (DI)(R9*1) LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) LEAQ (DI)(R9*2), DI // DI = &(DI[incDst]) DECQ BX JNZ axpyi_loop // } while --BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE axpyi_end axpyi_tail: // do { MOVSD (SI), X3 // X_i = { imag(x[i+1]), real(x[i+1]) } MOVSHDUP_X3_X2 // X_(i-1) = { real(x[i]), real(x[i]) } MOVSLDUP_X3_X3 // X_i = { imag(x[i]), imag(x[i]) } // X_i = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X_(i-1) = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPS X1, X2 MULPS X0, X3 // X_i = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]), // } ADDSUBPS_X2_X3 // (ai*x1r+ar*x1i, ar*x1r-ai*x1i) // X_i = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } MOVSD (DI), X4 ADDPS X4, X3 MOVSD X3, (DI) // y[i] = X_i ADDQ R8, SI // SI += incX ADDQ R9, DI // DI += incY LOOP axpyi_tail // } while --CX > 0 axpyi_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/axpyincto_amd64.s000066400000000000000000000112501450372207100240220ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVSHDUP X3, X2 #define MOVSHDUP_X3_X2 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xD3 // MOVSLDUP X3, X3 #define MOVSLDUP_X3_X3 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xDB // ADDSUBPS X2, X3 #define ADDSUBPS_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // MOVSHDUP X5, X4 #define MOVSHDUP_X5_X4 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xE5 // MOVSLDUP X5, X5 #define MOVSLDUP_X5_X5 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xED // ADDSUBPS X4, X5 #define ADDSUBPS_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // MOVSHDUP X7, X6 #define MOVSHDUP_X7_X6 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xF7 // MOVSLDUP X7, X7 #define MOVSLDUP_X7_X7 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xFF // ADDSUBPS X6, X7 #define ADDSUBPS_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // MOVSHDUP X9, X8 #define MOVSHDUP_X9_X8 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x16; BYTE $0xC1 // MOVSLDUP X9, X9 #define MOVSLDUP_X9_X9 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC9 // ADDSUBPS X8, X9 #define ADDSUBPS_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyIncTo(dst []complex64, incDst, idst uintptr, alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) TEXT ·AxpyIncTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ x_base+48(FP), SI // SI = &x MOVQ y_base+72(FP), DX // DX = &y MOVQ n+96(FP), CX // CX = n CMPQ CX, $0 // if n==0 { return } JE axpyi_end MOVQ ix+120(FP), R8 // Load the first index MOVQ iy+128(FP), R9 MOVQ idst+32(FP), R10 LEAQ (SI)(R8*8), SI // SI = &(x[ix]) LEAQ (DX)(R9*8), DX // DX = &(y[iy]) LEAQ (DI)(R10*8), DI // DI = &(dst[idst]) MOVQ incX+104(FP), R8 // Incrementors*8 for easy iteration (ADDQ) SHLQ $3, R8 MOVQ incY+112(FP), R9 SHLQ $3, R9 MOVQ incDst+24(FP), R10 SHLQ $3, R10 MOVSD alpha+40(FP), X0 // X0 = { 0, 0, imag(a), real(a) } MOVAPS X0, X1 SHUFPS $0x11, X1, X1 // X1 = { 0, 0, real(a), imag(a) } MOVAPS X0, X10 // Copy X0 and X1 for pipelining MOVAPS X1, X11 MOVQ CX, BX ANDQ $3, CX // CX = n % 4 SHRQ $2, BX // BX = floor( n / 4 ) JZ axpyi_tail // if BX == 0 { goto axpyi_tail } axpyi_loop: // do { MOVSD (SI), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSD (SI)(R8*1), X5 LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) MOVSD (SI), X7 MOVSD (SI)(R8*1), X9 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSHDUP_X3_X2 MOVSHDUP_X5_X4 MOVSHDUP_X7_X6 MOVSHDUP_X9_X8 // X_i = { real(x[i]), real(x[i]) } MOVSLDUP_X3_X3 MOVSLDUP_X5_X5 MOVSLDUP_X7_X7 MOVSLDUP_X9_X9 // X_(i-1) = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } // X_i = { imag(a) * real(x[i]), real(a) * real(x[i]) } MULPS X1, X2 MULPS X0, X3 MULPS X11, X4 MULPS X10, X5 MULPS X1, X6 MULPS X0, X7 MULPS X11, X8 MULPS X10, X9 // X_i = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]), // } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // X_i = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } MOVSD (DX), X2 MOVSD (DX)(R9*1), X4 LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) MOVSD (DX), X6 MOVSD (DX)(R9*1), X8 ADDPS X2, X3 ADDPS X4, X5 ADDPS X6, X7 ADDPS X8, X9 MOVSD X3, (DI) // y[i] = X_i MOVSD X5, (DI)(R10*1) LEAQ (DI)(R10*2), DI // DI = &(DI[incDst]) MOVSD X7, (DI) MOVSD X9, (DI)(R10*1) LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) LEAQ (DI)(R10*2), DI // DI = &(DI[incDst]) DECQ BX JNZ axpyi_loop // } while --BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE axpyi_end axpyi_tail: MOVSD (SI), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X_i = { real(x[i]), real(x[i]) } // X_i = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X_(i-1) = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPS X1, X2 MULPS X0, X3 // X_i = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]), // } ADDSUBPS_X2_X3 // X_i = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]) } MOVSD (DX), X4 ADDPS X4, X3 MOVSD X3, (DI) // y[i] = X_i ADDQ R8, SI // SI += incX ADDQ R9, DX // DX += incY ADDQ R10, DI // DI += incDst LOOP axpyi_tail // } while --CX > 0 axpyi_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/axpyunitary_amd64.s000066400000000000000000000126211450372207100244040ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVSHDUP X3, X2 #define MOVSHDUP_X3_X2 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xD3 // MOVSLDUP X3, X3 #define MOVSLDUP_X3_X3 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xDB // ADDSUBPS X2, X3 #define ADDSUBPS_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // MOVSHDUP X5, X4 #define MOVSHDUP_X5_X4 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xE5 // MOVSLDUP X5, X5 #define MOVSLDUP_X5_X5 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xED // ADDSUBPS X4, X5 #define ADDSUBPS_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // MOVSHDUP X7, X6 #define MOVSHDUP_X7_X6 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xF7 // MOVSLDUP X7, X7 #define MOVSLDUP_X7_X7 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xFF // ADDSUBPS X6, X7 #define ADDSUBPS_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // MOVSHDUP X9, X8 #define MOVSHDUP_X9_X8 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x16; BYTE $0xC1 // MOVSLDUP X9, X9 #define MOVSLDUP_X9_X9 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC9 // ADDSUBPS X8, X9 #define ADDSUBPS_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyUnitary(alpha complex64, x, y []complex64) TEXT ·AxpyUnitary(SB), NOSPLIT, $0 MOVQ x_base+8(FP), SI // SI = &x MOVQ y_base+32(FP), DI // DI = &y MOVQ x_len+16(FP), CX // CX = min( len(x), len(y) ) CMPQ y_len+40(FP), CX CMOVQLE y_len+40(FP), CX CMPQ CX, $0 // if CX == 0 { return } JE caxy_end PXOR X0, X0 // Clear work registers and cache-align loop PXOR X1, X1 MOVSD alpha+0(FP), X0 // X0 = { 0, 0, imag(a), real(a) } SHUFPD $0, X0, X0 // X0 = { imag(a), real(a), imag(a), real(a) } MOVAPS X0, X1 SHUFPS $0x11, X1, X1 // X1 = { real(a), imag(a), real(a), imag(a) } XORQ AX, AX // i = 0 MOVQ DI, BX // Align on 16-byte boundary for ADDPS ANDQ $15, BX // BX = &y & 15 JZ caxy_no_trim // if BX == 0 { goto caxy_no_trim } // Trim first value in unaligned buffer XORPS X2, X2 // Clear work registers and cache-align loop XORPS X3, X3 XORPS X4, X4 MOVSD (SI)(AX*8), X3 // X3 = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X2 = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X3 = { real(x[i]), real(x[i]) } MULPS X1, X2 // X2 = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPS X0, X3 // X3 = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X3 = { imag(a)*real(x[i]) + real(a)*imag(x[i]), real(a)*real(x[i]) - imag(a)*imag(x[i]) } ADDSUBPS_X2_X3 MOVSD (DI)(AX*8), X4 // X3 += y[i] ADDPS X4, X3 MOVSD X3, (DI)(AX*8) // y[i] = X3 INCQ AX // i++ DECQ CX // --CX JZ caxy_end // if CX == 0 { return } caxy_no_trim: MOVAPS X0, X10 // Copy X0 and X1 for pipelineing MOVAPS X1, X11 MOVQ CX, BX ANDQ $7, CX // CX = n % 8 SHRQ $3, BX // BX = floor( n / 8 ) JZ caxy_tail // if BX == 0 { goto caxy_tail } caxy_loop: // do { // X_i = { imag(x[i]), real(x[i]), imag(x[i+1]), real(x[i+1]) } MOVUPS (SI)(AX*8), X3 MOVUPS 16(SI)(AX*8), X5 MOVUPS 32(SI)(AX*8), X7 MOVUPS 48(SI)(AX*8), X9 // X_(i-1) = { imag(x[i]), imag(x[i]), imag(x[i]+1), imag(x[i]+1) } MOVSHDUP_X3_X2 MOVSHDUP_X5_X4 MOVSHDUP_X7_X6 MOVSHDUP_X9_X8 // X_i = { real(x[i]), real(x[i]), real(x[i+1]), real(x[i+1]) } MOVSLDUP_X3_X3 MOVSLDUP_X5_X5 MOVSLDUP_X7_X7 MOVSLDUP_X9_X9 // X_i = { imag(a) * real(x[i]), real(a) * real(x[i]), // imag(a) * real(x[i+1]), real(a) * real(x[i+1]) } // X_(i-1) = { real(a) * imag(x[i]), imag(a) * imag(x[i]), // real(a) * imag(x[i+1]), imag(a) * imag(x[i+1]) } MULPS X1, X2 MULPS X0, X3 MULPS X11, X4 MULPS X10, X5 MULPS X1, X6 MULPS X0, X7 MULPS X11, X8 MULPS X10, X9 // X_i = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]), // imag(result[i+1]): imag(a)*real(x[i+1]) + real(a)*imag(x[i+1]), // real(result[i+1]): real(a)*real(x[i+1]) - imag(a)*imag(x[i+1]), // } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // X_i = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]), // imag(result[i+1]) + imag(y[i+1]), real(result[i+1]) + real(y[i+1]) } ADDPS (DI)(AX*8), X3 ADDPS 16(DI)(AX*8), X5 ADDPS 32(DI)(AX*8), X7 ADDPS 48(DI)(AX*8), X9 MOVUPS X3, (DI)(AX*8) // y[i:i+1] = X_i MOVUPS X5, 16(DI)(AX*8) MOVUPS X7, 32(DI)(AX*8) MOVUPS X9, 48(DI)(AX*8) ADDQ $8, AX // i += 8 DECQ BX // --BX JNZ caxy_loop // } while BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE caxy_end caxy_tail: // do { MOVSD (SI)(AX*8), X3 // X3 = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X2 = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X3 = { real(x[i]), real(x[i]) } MULPS X1, X2 // X2 = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPS X0, X3 // X3 = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X3 = { imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(a)*real(x[i]) - imag(a)*imag(x[i]) } ADDSUBPS_X2_X3 MOVSD (DI)(AX*8), X4 // X3 += y[i] ADDPS X4, X3 MOVSD X3, (DI)(AX*8) // y[i] = X3 INCQ AX // ++i LOOP caxy_tail // } while --CX > 0 caxy_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/axpyunitaryto_amd64.s000066400000000000000000000124731450372207100247540ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // MOVSHDUP X3, X2 #define MOVSHDUP_X3_X2 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xD3 // MOVSLDUP X3, X3 #define MOVSLDUP_X3_X3 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xDB // ADDSUBPS X2, X3 #define ADDSUBPS_X2_X3 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xDA // MOVSHDUP X5, X4 #define MOVSHDUP_X5_X4 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xE5 // MOVSLDUP X5, X5 #define MOVSLDUP_X5_X5 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xED // ADDSUBPS X4, X5 #define ADDSUBPS_X4_X5 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xEC // MOVSHDUP X7, X6 #define MOVSHDUP_X7_X6 BYTE $0xF3; BYTE $0x0F; BYTE $0x16; BYTE $0xF7 // MOVSLDUP X7, X7 #define MOVSLDUP_X7_X7 BYTE $0xF3; BYTE $0x0F; BYTE $0x12; BYTE $0xFF // ADDSUBPS X6, X7 #define ADDSUBPS_X6_X7 BYTE $0xF2; BYTE $0x0F; BYTE $0xD0; BYTE $0xFE // MOVSHDUP X9, X8 #define MOVSHDUP_X9_X8 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x16; BYTE $0xC1 // MOVSLDUP X9, X9 #define MOVSLDUP_X9_X9 BYTE $0xF3; BYTE $0x45; BYTE $0x0F; BYTE $0x12; BYTE $0xC9 // ADDSUBPS X8, X9 #define ADDSUBPS_X8_X9 BYTE $0xF2; BYTE $0x45; BYTE $0x0F; BYTE $0xD0; BYTE $0xC8 // func AxpyUnitaryTo(dst []complex64, alpha complex64, x, y []complex64) TEXT ·AxpyUnitaryTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ x_base+32(FP), SI // SI = &x MOVQ y_base+56(FP), DX // DX = &y MOVQ x_len+40(FP), CX CMPQ y_len+64(FP), CX // CX = min( len(x), len(y), len(dst) ) CMOVQLE y_len+64(FP), CX CMPQ dst_len+8(FP), CX CMOVQLE dst_len+8(FP), CX CMPQ CX, $0 // if CX == 0 { return } JE caxy_end MOVSD alpha+24(FP), X0 // X0 = { 0, 0, imag(a), real(a) } SHUFPD $0, X0, X0 // X0 = { imag(a), real(a), imag(a), real(a) } MOVAPS X0, X1 SHUFPS $0x11, X1, X1 // X1 = { real(a), imag(a), real(a), imag(a) } XORQ AX, AX // i = 0 MOVQ DX, BX // Align on 16-byte boundary for ADDPS ANDQ $15, BX // BX = &y & 15 JZ caxy_no_trim // if BX == 0 { goto caxy_no_trim } MOVSD (SI)(AX*8), X3 // X3 = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X2 = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X3 = { real(x[i]), real(x[i]) } MULPS X1, X2 // X2 = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPS X0, X3 // X3 = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X3 = { imag(a)*real(x[i]) + real(a)*imag(x[i]), real(a)*real(x[i]) - imag(a)*imag(x[i]) } ADDSUBPS_X2_X3 MOVSD (DX)(AX*8), X4 // X3 += y[i] ADDPS X4, X3 MOVSD X3, (DI)(AX*8) // dst[i] = X3 INCQ AX // i++ DECQ CX // --CX JZ caxy_tail // if BX == 0 { goto caxy_tail } caxy_no_trim: MOVAPS X0, X10 // Copy X0 and X1 for pipelineing MOVAPS X1, X11 MOVQ CX, BX ANDQ $7, CX // CX = n % 8 SHRQ $3, BX // BX = floor( n / 8 ) JZ caxy_tail // if BX == 0 { goto caxy_tail } caxy_loop: // X_i = { imag(x[i]), real(x[i]), imag(x[i+1]), real(x[i+1]) } MOVUPS (SI)(AX*8), X3 MOVUPS 16(SI)(AX*8), X5 MOVUPS 32(SI)(AX*8), X7 MOVUPS 48(SI)(AX*8), X9 // X_(i-1) = { imag(x[i]), imag(x[i]), imag(x[i]+1), imag(x[i]+1) } MOVSHDUP_X3_X2 MOVSHDUP_X5_X4 MOVSHDUP_X7_X6 MOVSHDUP_X9_X8 // X_i = { real(x[i]), real(x[i]), real(x[i+1]), real(x[i+1]) } MOVSLDUP_X3_X3 MOVSLDUP_X5_X5 MOVSLDUP_X7_X7 MOVSLDUP_X9_X9 // X_i = { imag(a) * real(x[i]), real(a) * real(x[i]), // imag(a) * real(x[i+1]), real(a) * real(x[i+1]) } // X_(i-1) = { real(a) * imag(x[i]), imag(a) * imag(x[i]), // real(a) * imag(x[i+1]), imag(a) * imag(x[i+1]) } MULPS X1, X2 MULPS X0, X3 MULPS X11, X4 MULPS X10, X5 MULPS X1, X6 MULPS X0, X7 MULPS X11, X8 MULPS X10, X9 // X_i = { // imag(result[i]): imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(result[i]): real(a)*real(x[i]) - imag(a)*imag(x[i]), // imag(result[i+1]): imag(a)*real(x[i+1]) + real(a)*imag(x[i+1]), // real(result[i+1]): real(a)*real(x[i+1]) - imag(a)*imag(x[i+1]), // } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // X_i = { imag(result[i]) + imag(y[i]), real(result[i]) + real(y[i]), // imag(result[i+1]) + imag(y[i+1]), real(result[i+1]) + real(y[i+1]) } ADDPS (DX)(AX*8), X3 ADDPS 16(DX)(AX*8), X5 ADDPS 32(DX)(AX*8), X7 ADDPS 48(DX)(AX*8), X9 MOVUPS X3, (DI)(AX*8) // y[i:i+1] = X_i MOVUPS X5, 16(DI)(AX*8) MOVUPS X7, 32(DI)(AX*8) MOVUPS X9, 48(DI)(AX*8) ADDQ $8, AX // i += 8 DECQ BX // --BX JNZ caxy_loop // } while BX > 0 CMPQ CX, $0 // if CX == 0 { return } JE caxy_end caxy_tail: // do { MOVSD (SI)(AX*8), X3 // X3 = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X2 = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X3 = { real(x[i]), real(x[i]) } MULPS X1, X2 // X2 = { real(a) * imag(x[i]), imag(a) * imag(x[i]) } MULPS X0, X3 // X3 = { imag(a) * real(x[i]), real(a) * real(x[i]) } // X3 = { imag(a)*real(x[i]) + real(a)*imag(x[i]), // real(a)*real(x[i]) - imag(a)*imag(x[i]) } ADDSUBPS_X2_X3 MOVSD (DX)(AX*8), X4 // X3 += y[i] ADDPS X4, X3 MOVSD X3, (DI)(AX*8) // y[i] = X3 INCQ AX // ++i LOOP caxy_tail // } while --CX > 0 caxy_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/benchDot_test.go000066400000000000000000000025541450372207100237500ustar00rootroot00000000000000// 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 c64 import ( "fmt" "testing" ) var benchSink complex64 func BenchmarkDotUnitary(t *testing.B) { for _, tst := range []struct { name string f func(x, y []complex64) complex64 }{ {"DotcUnitary", DotcUnitary}, {"DotuUnitary", DotuUnitary}, } { for _, v := range []int64{1, 2, 3, 4, 5, 10, 100, 1e3, 5e3, 1e4, 5e4} { t.Run(fmt.Sprintf("%s-%d", tst.name, v), func(b *testing.B) { x, y := x[:v], y[:v] b.SetBytes(128 * v) for i := 0; i < b.N; i++ { benchSink = tst.f(x, y) } }) } } } func BenchmarkDotInc(t *testing.B) { for _, tst := range []struct { name string f func(x, y []complex64, n, incX, incY, ix, iy uintptr) complex64 }{ {"DotcInc", DotcInc}, {"DotuInc", DotuInc}, } { for _, ln := range []int{1, 2, 3, 4, 5, 10, 100, 1e3, 5e3, 1e4, 5e4} { for _, inc := range []int{1, 2, 4, 10, -1, -2, -4, -10} { t.Run(fmt.Sprintf("%s-%d-inc%d", tst.name, ln, inc), func(b *testing.B) { b.SetBytes(int64(128 * ln)) var idx int if inc < 0 { idx = (-ln + 1) * inc } for i := 0; i < b.N; i++ { benchSink = tst.f(x, y, uintptr(ln), uintptr(inc), uintptr(inc), uintptr(idx), uintptr(idx)) } }) } } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/bench_test.go000066400000000000000000000401411450372207100232730ustar00rootroot00000000000000// Copyright ©2016 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 c64 import "testing" var ( a = complex64(2 + 2i) x = make([]complex64, 1000000) y = make([]complex64, 1000000) z = make([]complex64, 1000000) ) func init() { for n := range x { x[n] = complex(float32(n), float32(n)) y[n] = complex(float32(n), float32(n)) } } func benchaxpyu(t *testing.B, n int, f func(a complex64, x, y []complex64)) { x, y := x[:n], y[:n] for i := 0; i < t.N; i++ { f(a, x, y) } } func naiveaxpyu(a complex64, x, y []complex64) { for i, v := range x { y[i] += a * v } } func BenchmarkC64AxpyUnitary1(t *testing.B) { benchaxpyu(t, 1, AxpyUnitary) } func BenchmarkC64AxpyUnitary2(t *testing.B) { benchaxpyu(t, 2, AxpyUnitary) } func BenchmarkC64AxpyUnitary3(t *testing.B) { benchaxpyu(t, 3, AxpyUnitary) } func BenchmarkC64AxpyUnitary4(t *testing.B) { benchaxpyu(t, 4, AxpyUnitary) } func BenchmarkC64AxpyUnitary5(t *testing.B) { benchaxpyu(t, 5, AxpyUnitary) } func BenchmarkC64AxpyUnitary10(t *testing.B) { benchaxpyu(t, 10, AxpyUnitary) } func BenchmarkC64AxpyUnitary100(t *testing.B) { benchaxpyu(t, 100, AxpyUnitary) } func BenchmarkC64AxpyUnitary1000(t *testing.B) { benchaxpyu(t, 1000, AxpyUnitary) } func BenchmarkC64AxpyUnitary5000(t *testing.B) { benchaxpyu(t, 5000, AxpyUnitary) } func BenchmarkC64AxpyUnitary10000(t *testing.B) { benchaxpyu(t, 10000, AxpyUnitary) } func BenchmarkC64AxpyUnitary50000(t *testing.B) { benchaxpyu(t, 50000, AxpyUnitary) } func BenchmarkLC64AxpyUnitary1(t *testing.B) { benchaxpyu(t, 1, naiveaxpyu) } func BenchmarkLC64AxpyUnitary2(t *testing.B) { benchaxpyu(t, 2, naiveaxpyu) } func BenchmarkLC64AxpyUnitary3(t *testing.B) { benchaxpyu(t, 3, naiveaxpyu) } func BenchmarkLC64AxpyUnitary4(t *testing.B) { benchaxpyu(t, 4, naiveaxpyu) } func BenchmarkLC64AxpyUnitary5(t *testing.B) { benchaxpyu(t, 5, naiveaxpyu) } func BenchmarkLC64AxpyUnitary10(t *testing.B) { benchaxpyu(t, 10, naiveaxpyu) } func BenchmarkLC64AxpyUnitary100(t *testing.B) { benchaxpyu(t, 100, naiveaxpyu) } func BenchmarkLC64AxpyUnitary1000(t *testing.B) { benchaxpyu(t, 1000, naiveaxpyu) } func BenchmarkLC64AxpyUnitary5000(t *testing.B) { benchaxpyu(t, 5000, naiveaxpyu) } func BenchmarkLC64AxpyUnitary10000(t *testing.B) { benchaxpyu(t, 10000, naiveaxpyu) } func BenchmarkLC64AxpyUnitary50000(t *testing.B) { benchaxpyu(t, 50000, naiveaxpyu) } func benchaxpyut(t *testing.B, n int, f func(d []complex64, a complex64, x, y []complex64)) { x, y, z := x[:n], y[:n], z[:n] for i := 0; i < t.N; i++ { f(z, a, x, y) } } func naiveaxpyut(d []complex64, a complex64, x, y []complex64) { for i, v := range x { d[i] = y[i] + a*v } } func BenchmarkC64AxpyUnitaryTo1(t *testing.B) { benchaxpyut(t, 1, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo2(t *testing.B) { benchaxpyut(t, 2, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo3(t *testing.B) { benchaxpyut(t, 3, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo4(t *testing.B) { benchaxpyut(t, 4, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo5(t *testing.B) { benchaxpyut(t, 5, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo10(t *testing.B) { benchaxpyut(t, 10, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo100(t *testing.B) { benchaxpyut(t, 100, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo1000(t *testing.B) { benchaxpyut(t, 1000, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo5000(t *testing.B) { benchaxpyut(t, 5000, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo10000(t *testing.B) { benchaxpyut(t, 10000, AxpyUnitaryTo) } func BenchmarkC64AxpyUnitaryTo50000(t *testing.B) { benchaxpyut(t, 50000, AxpyUnitaryTo) } func BenchmarkLC64AxpyUnitaryTo1(t *testing.B) { benchaxpyut(t, 1, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo2(t *testing.B) { benchaxpyut(t, 2, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo3(t *testing.B) { benchaxpyut(t, 3, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo4(t *testing.B) { benchaxpyut(t, 4, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo5(t *testing.B) { benchaxpyut(t, 5, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo10(t *testing.B) { benchaxpyut(t, 10, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo100(t *testing.B) { benchaxpyut(t, 100, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo1000(t *testing.B) { benchaxpyut(t, 1000, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo5000(t *testing.B) { benchaxpyut(t, 5000, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo10000(t *testing.B) { benchaxpyut(t, 10000, naiveaxpyut) } func BenchmarkLC64AxpyUnitaryTo50000(t *testing.B) { benchaxpyut(t, 50000, naiveaxpyut) } func benchaxpyinc(t *testing.B, ln, t_inc int, f func(alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr)) { n, inc := uintptr(ln), uintptr(t_inc) var idx int if t_inc < 0 { idx = (-ln + 1) * t_inc } for i := 0; i < t.N; i++ { f(1+1i, x, y, n, inc, inc, uintptr(idx), uintptr(idx)) } } func naiveaxpyinc(alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } func BenchmarkC64AxpyIncN1Inc1(b *testing.B) { benchaxpyinc(b, 1, 1, AxpyInc) } func BenchmarkC64AxpyIncN2Inc1(b *testing.B) { benchaxpyinc(b, 2, 1, AxpyInc) } func BenchmarkC64AxpyIncN2Inc2(b *testing.B) { benchaxpyinc(b, 2, 2, AxpyInc) } func BenchmarkC64AxpyIncN2Inc4(b *testing.B) { benchaxpyinc(b, 2, 4, AxpyInc) } func BenchmarkC64AxpyIncN2Inc10(b *testing.B) { benchaxpyinc(b, 2, 10, AxpyInc) } func BenchmarkC64AxpyIncN3Inc1(b *testing.B) { benchaxpyinc(b, 3, 1, AxpyInc) } func BenchmarkC64AxpyIncN3Inc2(b *testing.B) { benchaxpyinc(b, 3, 2, AxpyInc) } func BenchmarkC64AxpyIncN3Inc4(b *testing.B) { benchaxpyinc(b, 3, 4, AxpyInc) } func BenchmarkC64AxpyIncN3Inc10(b *testing.B) { benchaxpyinc(b, 3, 10, AxpyInc) } func BenchmarkC64AxpyIncN4Inc1(b *testing.B) { benchaxpyinc(b, 4, 1, AxpyInc) } func BenchmarkC64AxpyIncN4Inc2(b *testing.B) { benchaxpyinc(b, 4, 2, AxpyInc) } func BenchmarkC64AxpyIncN4Inc4(b *testing.B) { benchaxpyinc(b, 4, 4, AxpyInc) } func BenchmarkC64AxpyIncN4Inc10(b *testing.B) { benchaxpyinc(b, 4, 10, AxpyInc) } func BenchmarkC64AxpyIncN10Inc1(b *testing.B) { benchaxpyinc(b, 10, 1, AxpyInc) } func BenchmarkC64AxpyIncN10Inc2(b *testing.B) { benchaxpyinc(b, 10, 2, AxpyInc) } func BenchmarkC64AxpyIncN10Inc4(b *testing.B) { benchaxpyinc(b, 10, 4, AxpyInc) } func BenchmarkC64AxpyIncN10Inc10(b *testing.B) { benchaxpyinc(b, 10, 10, AxpyInc) } func BenchmarkC64AxpyIncN1000Inc1(b *testing.B) { benchaxpyinc(b, 1000, 1, AxpyInc) } func BenchmarkC64AxpyIncN1000Inc2(b *testing.B) { benchaxpyinc(b, 1000, 2, AxpyInc) } func BenchmarkC64AxpyIncN1000Inc4(b *testing.B) { benchaxpyinc(b, 1000, 4, AxpyInc) } func BenchmarkC64AxpyIncN1000Inc10(b *testing.B) { benchaxpyinc(b, 1000, 10, AxpyInc) } func BenchmarkC64AxpyIncN100000Inc1(b *testing.B) { benchaxpyinc(b, 100000, 1, AxpyInc) } func BenchmarkC64AxpyIncN100000Inc2(b *testing.B) { benchaxpyinc(b, 100000, 2, AxpyInc) } func BenchmarkC64AxpyIncN100000Inc4(b *testing.B) { benchaxpyinc(b, 100000, 4, AxpyInc) } func BenchmarkC64AxpyIncN100000Inc10(b *testing.B) { benchaxpyinc(b, 100000, 10, AxpyInc) } func BenchmarkC64AxpyIncN100000IncM1(b *testing.B) { benchaxpyinc(b, 100000, -1, AxpyInc) } func BenchmarkC64AxpyIncN100000IncM2(b *testing.B) { benchaxpyinc(b, 100000, -2, AxpyInc) } func BenchmarkC64AxpyIncN100000IncM4(b *testing.B) { benchaxpyinc(b, 100000, -4, AxpyInc) } func BenchmarkC64AxpyIncN100000IncM10(b *testing.B) { benchaxpyinc(b, 100000, -10, AxpyInc) } func BenchmarkLC64AxpyIncN1Inc1(b *testing.B) { benchaxpyinc(b, 1, 1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN2Inc1(b *testing.B) { benchaxpyinc(b, 2, 1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN2Inc2(b *testing.B) { benchaxpyinc(b, 2, 2, naiveaxpyinc) } func BenchmarkLC64AxpyIncN2Inc4(b *testing.B) { benchaxpyinc(b, 2, 4, naiveaxpyinc) } func BenchmarkLC64AxpyIncN2Inc10(b *testing.B) { benchaxpyinc(b, 2, 10, naiveaxpyinc) } func BenchmarkLC64AxpyIncN3Inc1(b *testing.B) { benchaxpyinc(b, 3, 1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN3Inc2(b *testing.B) { benchaxpyinc(b, 3, 2, naiveaxpyinc) } func BenchmarkLC64AxpyIncN3Inc4(b *testing.B) { benchaxpyinc(b, 3, 4, naiveaxpyinc) } func BenchmarkLC64AxpyIncN3Inc10(b *testing.B) { benchaxpyinc(b, 3, 10, naiveaxpyinc) } func BenchmarkLC64AxpyIncN4Inc1(b *testing.B) { benchaxpyinc(b, 4, 1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN4Inc2(b *testing.B) { benchaxpyinc(b, 4, 2, naiveaxpyinc) } func BenchmarkLC64AxpyIncN4Inc4(b *testing.B) { benchaxpyinc(b, 4, 4, naiveaxpyinc) } func BenchmarkLC64AxpyIncN4Inc10(b *testing.B) { benchaxpyinc(b, 4, 10, naiveaxpyinc) } func BenchmarkLC64AxpyIncN10Inc1(b *testing.B) { benchaxpyinc(b, 10, 1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN10Inc2(b *testing.B) { benchaxpyinc(b, 10, 2, naiveaxpyinc) } func BenchmarkLC64AxpyIncN10Inc4(b *testing.B) { benchaxpyinc(b, 10, 4, naiveaxpyinc) } func BenchmarkLC64AxpyIncN10Inc10(b *testing.B) { benchaxpyinc(b, 10, 10, naiveaxpyinc) } func BenchmarkLC64AxpyIncN1000Inc1(b *testing.B) { benchaxpyinc(b, 1000, 1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN1000Inc2(b *testing.B) { benchaxpyinc(b, 1000, 2, naiveaxpyinc) } func BenchmarkLC64AxpyIncN1000Inc4(b *testing.B) { benchaxpyinc(b, 1000, 4, naiveaxpyinc) } func BenchmarkLC64AxpyIncN1000Inc10(b *testing.B) { benchaxpyinc(b, 1000, 10, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000Inc1(b *testing.B) { benchaxpyinc(b, 100000, 1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000Inc2(b *testing.B) { benchaxpyinc(b, 100000, 2, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000Inc4(b *testing.B) { benchaxpyinc(b, 100000, 4, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000Inc10(b *testing.B) { benchaxpyinc(b, 100000, 10, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000IncM1(b *testing.B) { benchaxpyinc(b, 100000, -1, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000IncM2(b *testing.B) { benchaxpyinc(b, 100000, -2, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000IncM4(b *testing.B) { benchaxpyinc(b, 100000, -4, naiveaxpyinc) } func BenchmarkLC64AxpyIncN100000IncM10(b *testing.B) { benchaxpyinc(b, 100000, -10, naiveaxpyinc) } func benchaxpyincto(t *testing.B, ln, t_inc int, f func(dst []complex64, incDst, idst uintptr, alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr)) { n, inc := uintptr(ln), uintptr(t_inc) var idx int if t_inc < 0 { idx = (-ln + 1) * t_inc } for i := 0; i < t.N; i++ { f(z, inc, uintptr(idx), 1+1i, x, y, n, inc, inc, uintptr(idx), uintptr(idx)) } } func naiveaxpyincto(dst []complex64, incDst, idst uintptr, alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } func BenchmarkC64AxpyIncToN1Inc1(b *testing.B) { benchaxpyincto(b, 1, 1, AxpyIncTo) } func BenchmarkC64AxpyIncToN2Inc1(b *testing.B) { benchaxpyincto(b, 2, 1, AxpyIncTo) } func BenchmarkC64AxpyIncToN2Inc2(b *testing.B) { benchaxpyincto(b, 2, 2, AxpyIncTo) } func BenchmarkC64AxpyIncToN2Inc4(b *testing.B) { benchaxpyincto(b, 2, 4, AxpyIncTo) } func BenchmarkC64AxpyIncToN2Inc10(b *testing.B) { benchaxpyincto(b, 2, 10, AxpyIncTo) } func BenchmarkC64AxpyIncToN3Inc1(b *testing.B) { benchaxpyincto(b, 3, 1, AxpyIncTo) } func BenchmarkC64AxpyIncToN3Inc2(b *testing.B) { benchaxpyincto(b, 3, 2, AxpyIncTo) } func BenchmarkC64AxpyIncToN3Inc4(b *testing.B) { benchaxpyincto(b, 3, 4, AxpyIncTo) } func BenchmarkC64AxpyIncToN3Inc10(b *testing.B) { benchaxpyincto(b, 3, 10, AxpyIncTo) } func BenchmarkC64AxpyIncToN4Inc1(b *testing.B) { benchaxpyincto(b, 4, 1, AxpyIncTo) } func BenchmarkC64AxpyIncToN4Inc2(b *testing.B) { benchaxpyincto(b, 4, 2, AxpyIncTo) } func BenchmarkC64AxpyIncToN4Inc4(b *testing.B) { benchaxpyincto(b, 4, 4, AxpyIncTo) } func BenchmarkC64AxpyIncToN4Inc10(b *testing.B) { benchaxpyincto(b, 4, 10, AxpyIncTo) } func BenchmarkC64AxpyIncToN10Inc1(b *testing.B) { benchaxpyincto(b, 10, 1, AxpyIncTo) } func BenchmarkC64AxpyIncToN10Inc2(b *testing.B) { benchaxpyincto(b, 10, 2, AxpyIncTo) } func BenchmarkC64AxpyIncToN10Inc4(b *testing.B) { benchaxpyincto(b, 10, 4, AxpyIncTo) } func BenchmarkC64AxpyIncToN10Inc10(b *testing.B) { benchaxpyincto(b, 10, 10, AxpyIncTo) } func BenchmarkC64AxpyIncToN1000Inc1(b *testing.B) { benchaxpyincto(b, 1000, 1, AxpyIncTo) } func BenchmarkC64AxpyIncToN1000Inc2(b *testing.B) { benchaxpyincto(b, 1000, 2, AxpyIncTo) } func BenchmarkC64AxpyIncToN1000Inc4(b *testing.B) { benchaxpyincto(b, 1000, 4, AxpyIncTo) } func BenchmarkC64AxpyIncToN1000Inc10(b *testing.B) { benchaxpyincto(b, 1000, 10, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000Inc1(b *testing.B) { benchaxpyincto(b, 100000, 1, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000Inc2(b *testing.B) { benchaxpyincto(b, 100000, 2, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000Inc4(b *testing.B) { benchaxpyincto(b, 100000, 4, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000Inc10(b *testing.B) { benchaxpyincto(b, 100000, 10, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000IncM1(b *testing.B) { benchaxpyincto(b, 100000, -1, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000IncM2(b *testing.B) { benchaxpyincto(b, 100000, -2, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000IncM4(b *testing.B) { benchaxpyincto(b, 100000, -4, AxpyIncTo) } func BenchmarkC64AxpyIncToN100000IncM10(b *testing.B) { benchaxpyincto(b, 100000, -10, AxpyIncTo) } func BenchmarkLC64AxpyIncToN1Inc1(b *testing.B) { benchaxpyincto(b, 1, 1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN2Inc1(b *testing.B) { benchaxpyincto(b, 2, 1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN2Inc2(b *testing.B) { benchaxpyincto(b, 2, 2, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN2Inc4(b *testing.B) { benchaxpyincto(b, 2, 4, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN2Inc10(b *testing.B) { benchaxpyincto(b, 2, 10, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN3Inc1(b *testing.B) { benchaxpyincto(b, 3, 1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN3Inc2(b *testing.B) { benchaxpyincto(b, 3, 2, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN3Inc4(b *testing.B) { benchaxpyincto(b, 3, 4, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN3Inc10(b *testing.B) { benchaxpyincto(b, 3, 10, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN4Inc1(b *testing.B) { benchaxpyincto(b, 4, 1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN4Inc2(b *testing.B) { benchaxpyincto(b, 4, 2, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN4Inc4(b *testing.B) { benchaxpyincto(b, 4, 4, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN4Inc10(b *testing.B) { benchaxpyincto(b, 4, 10, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN10Inc1(b *testing.B) { benchaxpyincto(b, 10, 1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN10Inc2(b *testing.B) { benchaxpyincto(b, 10, 2, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN10Inc4(b *testing.B) { benchaxpyincto(b, 10, 4, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN10Inc10(b *testing.B) { benchaxpyincto(b, 10, 10, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN1000Inc1(b *testing.B) { benchaxpyincto(b, 1000, 1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN1000Inc2(b *testing.B) { benchaxpyincto(b, 1000, 2, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN1000Inc4(b *testing.B) { benchaxpyincto(b, 1000, 4, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN1000Inc10(b *testing.B) { benchaxpyincto(b, 1000, 10, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000Inc1(b *testing.B) { benchaxpyincto(b, 100000, 1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000Inc2(b *testing.B) { benchaxpyincto(b, 100000, 2, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000Inc4(b *testing.B) { benchaxpyincto(b, 100000, 4, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000Inc10(b *testing.B) { benchaxpyincto(b, 100000, 10, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000IncM1(b *testing.B) { benchaxpyincto(b, 100000, -1, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000IncM2(b *testing.B) { benchaxpyincto(b, 100000, -2, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000IncM4(b *testing.B) { benchaxpyincto(b, 100000, -4, naiveaxpyincto) } func BenchmarkLC64AxpyIncToN100000IncM10(b *testing.B) { benchaxpyincto(b, 100000, -10, naiveaxpyincto) } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/conj.go000066400000000000000000000003711450372207100221070ustar00rootroot00000000000000// 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 c64 func conj(c complex64) complex64 { return complex(real(c), -imag(c)) } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/doc.go000066400000000000000000000004261450372207100217240ustar00rootroot00000000000000// 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 c64 provides complex64 vector primitives. package c64 // import "gonum.org/v1/gonum/internal/asm/c64" golang-gonum-v1-gonum-0.14.0/internal/asm/c64/dot_test.go000066400000000000000000000124431450372207100230060ustar00rootroot00000000000000// 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 c64 import ( "fmt" "math" "testing" ) const ( msgVal = "%v: unexpected value at %v Got: %v Expected: %v" msgGuard = "%v: Guard violated in %s vector %v %v" ) var ( inf = float32(math.Inf(1)) ) var dotTests = []struct { x, y []complex64 wantu, wantc complex64 wantuRev, wantcRev complex64 n int }{ { x: []complex64{}, y: []complex64{}, n: 0, wantu: 0, wantc: 0, wantuRev: 0, wantcRev: 0, }, { x: []complex64{1 + 1i}, y: []complex64{1 + 1i}, n: 1, wantu: 0 + 2i, wantc: 2, wantuRev: 0 + 2i, wantcRev: 2, }, { x: []complex64{1 + 2i}, y: []complex64{1 + 1i}, n: 1, wantu: -1 + 3i, wantc: 3 - 1i, wantuRev: -1 + 3i, wantcRev: 3 - 1i, }, { x: []complex64{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, y: []complex64{1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i, 9 + 10i, 11 + 12i, 13 + 14i, 15 + 16i, 17 + 18i, 19 + 20i}, n: 10, wantu: -210 + 2860i, wantc: 2870 + 0i, wantuRev: -210 + 1540i, wantcRev: 1550 + 0i, }, { x: []complex64{1 + 1i, 1 + 1i, 1 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 3i, 1 + 1i, 1 + 1i, 1 + 4i}, y: []complex64{1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i}, n: 10, wantu: -22 + 36i, wantc: 42 + 4i, wantuRev: -22 + 36i, wantcRev: 42 + 4i, }, { x: []complex64{1 + 1i, 1 + 1i, 2 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 1i}, y: []complex64{1 + 2i, 1 + 2i, 1 + 3i, 1 + 2i, 1 + 3i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i}, n: 10, wantu: -10 + 37i, wantc: 34 + 17i, wantuRev: -10 + 36i, wantcRev: 34 + 16i, }, { x: []complex64{1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, complex(inf, 1), 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i}, y: []complex64{1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i, 1 + 2i}, n: 10, wantu: complex(inf, inf), wantc: complex(inf, inf), wantuRev: complex(inf, inf), wantcRev: complex(inf, inf), }, } func TestDotcUnitary(t *testing.T) { const gd = 1 + 5i for i, test := range dotTests { for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, align.x, align.y) xgLn, ygLn := 4+align.x, 4+align.y xg, yg := guardVector(test.x, gd, xgLn), guardVector(test.y, gd, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] res := DotcUnitary(x, y) if !same(res, test.wantc) { t.Errorf(msgVal, prefix, i, res, test.wantc) } if !isValidGuard(xg, gd, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, gd, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } } } } func TestDotcInc(t *testing.T) { const gd, gdLn = 2 + 5i, 4 for i, test := range dotTests { for _, inc := range newIncSet(1, 2, 5, 10, -1, -2, -5, -10) { xg, yg := guardIncVector(test.x, gd, inc.x, gdLn), guardIncVector(test.y, gd, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] want := test.wantc var ix, iy int if inc.x < 0 { ix, want = -inc.x*(test.n-1), test.wantcRev } if inc.y < 0 { iy, want = -inc.y*(test.n-1), test.wantcRev } prefix := fmt.Sprintf("Test %v (x:%v y:%v) (ix:%v iy:%v)", i, inc.x, inc.y, ix, iy) res := DotcInc(x, y, uintptr(test.n), uintptr(inc.x), uintptr(inc.y), uintptr(ix), uintptr(iy)) if inc.x*inc.y > 0 { want = test.wantc } if !same(res, want) { t.Errorf(msgVal, prefix, i, res, want) t.Error(x, y) } checkValidIncGuard(t, xg, gd, inc.x, gdLn) checkValidIncGuard(t, yg, gd, inc.y, gdLn) } } } func TestDotuUnitary(t *testing.T) { const gd = 1 + 5i for i, test := range dotTests { for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, align.x, align.y) xgLn, ygLn := 4+align.x, 4+align.y xg, yg := guardVector(test.x, gd, xgLn), guardVector(test.y, gd, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] res := DotuUnitary(x, y) if !same(res, test.wantu) { t.Errorf(msgVal, prefix, i, res, test.wantu) } if !isValidGuard(xg, gd, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, gd, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } } } } func TestDotuInc(t *testing.T) { const gd, gdLn = 1 + 5i, 4 for i, test := range dotTests { for _, inc := range newIncSet(1, 2, 5, 10, -1, -2, -5, -10) { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, inc.x, inc.y) xg, yg := guardIncVector(test.x, gd, inc.x, gdLn), guardIncVector(test.y, gd, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] want := test.wantc var ix, iy int if inc.x < 0 { ix, want = -inc.x*(test.n-1), test.wantuRev } if inc.y < 0 { iy, want = -inc.y*(test.n-1), test.wantuRev } res := DotuInc(x, y, uintptr(test.n), uintptr(inc.x), uintptr(inc.y), uintptr(ix), uintptr(iy)) if inc.x*inc.y > 0 { want = test.wantu } if !same(res, want) { t.Errorf(msgVal, prefix, i, res, want) } checkValidIncGuard(t, xg, gd, inc.x, gdLn) checkValidIncGuard(t, yg, gd, inc.y, gdLn) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/dotcinc_amd64.s000066400000000000000000000114431450372207100234330ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVSHDUP_X3_X2 LONG $0xD3160FF3 // MOVSHDUP X3, X2 #define MOVSHDUP_X5_X4 LONG $0xE5160FF3 // MOVSHDUP X5, X4 #define MOVSHDUP_X7_X6 LONG $0xF7160FF3 // MOVSHDUP X7, X6 #define MOVSHDUP_X9_X8 LONG $0x160F45F3; BYTE $0xC1 // MOVSHDUP X9, X8 #define MOVSLDUP_X3_X3 LONG $0xDB120FF3 // MOVSLDUP X3, X3 #define MOVSLDUP_X5_X5 LONG $0xED120FF3 // MOVSLDUP X5, X5 #define MOVSLDUP_X7_X7 LONG $0xFF120FF3 // MOVSLDUP X7, X7 #define MOVSLDUP_X9_X9 LONG $0x120F45F3; BYTE $0xC9 // MOVSLDUP X9, X9 #define ADDSUBPS_X2_X3 LONG $0xDAD00FF2 // ADDSUBPS X2, X3 #define ADDSUBPS_X4_X5 LONG $0xECD00FF2 // ADDSUBPS X4, X5 #define ADDSUBPS_X6_X7 LONG $0xFED00FF2 // ADDSUBPS X6, X7 #define ADDSUBPS_X8_X9 LONG $0xD00F45F2; BYTE $0xC8 // ADDSUBPS X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define INC_X R8 #define INCx3_X R9 #define INC_Y R10 #define INCx3_Y R11 #define NEG1 X15 #define P_NEG1 X14 // func DotcInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) TEXT ·DotcInc(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y PXOR SUM, SUM // SUM = 0 PXOR P_SUM, P_SUM // P_SUM = 0 MOVQ n+48(FP), LEN // LEN = n CMPQ LEN, $0 // if LEN == 0 { return } JE dotc_end MOVQ ix+72(FP), INC_X MOVQ iy+80(FP), INC_Y LEAQ (X_PTR)(INC_X*8), X_PTR // X_PTR = &(X_PTR[ix]) LEAQ (Y_PTR)(INC_Y*8), Y_PTR // Y_PTR = &(Y_PTR[iy]) MOVQ incX+56(FP), INC_X // INC_X = incX * sizeof(complex64) SHLQ $3, INC_X MOVQ incY+64(FP), INC_Y // INC_Y = incY * sizeof(complex64) SHLQ $3, INC_Y MOVSS $(-1.0), NEG1 SHUFPS $0, NEG1, NEG1 // { -1, -1, -1, -1 } MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = LEN % 4 SHRQ $2, LEN // LEN = floor( LEN / 4 ) JZ dotc_tail // if LEN == 0 { goto dotc_tail } MOVUPS NEG1, P_NEG1 // Copy NEG1 for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = INC_Y * 3 dotc_loop: // do { MOVSD (X_PTR), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSD (X_PTR)(INC_X*1), X5 MOVSD (X_PTR)(INC_X*2), X7 MOVSD (X_PTR)(INCx3_X*1), X9 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSHDUP_X3_X2 MOVSHDUP_X5_X4 MOVSHDUP_X7_X6 MOVSHDUP_X9_X8 // X_i = { real(x[i]), real(x[i]) } MOVSLDUP_X3_X3 MOVSLDUP_X5_X5 MOVSLDUP_X7_X7 MOVSLDUP_X9_X9 // X_(i-1) = { -imag(x[i]), -imag(x[i]) } MULPS NEG1, X2 MULPS P_NEG1, X4 MULPS NEG1, X6 MULPS P_NEG1, X8 // X_j = { imag(y[i]), real(y[i]) } MOVSD (Y_PTR), X10 MOVSD (Y_PTR)(INC_Y*1), X11 MOVSD (Y_PTR)(INC_Y*2), X12 MOVSD (Y_PTR)(INCx3_Y*1), X13 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } MULPS X10, X3 MULPS X11, X5 MULPS X12, X7 MULPS X13, X9 // X_j = { real(y[i]), imag(y[i]) } SHUFPS $0xB1, X10, X10 SHUFPS $0xB1, X11, X11 SHUFPS $0xB1, X12, X12 SHUFPS $0xB1, X13, X13 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } MULPS X10, X2 MULPS X11, X4 MULPS X12, X6 MULPS X13, X8 // X_i = { // imag(result[i]): imag(y[i]) * real(x[i]) + real(y[i]) * imag(x[i]), // real(result[i]): real(y[i]) * real(x[i]) - imag(y[i]) * imag(x[i]) } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // SUM += X_i ADDPS X3, SUM ADDPS X5, P_SUM ADDPS X7, SUM ADDPS X9, P_SUM LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[INC_X*4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[INC_Y*4]) DECQ LEN JNZ dotc_loop // } while --LEN > 0 ADDPS P_SUM, SUM // SUM = { P_SUM + SUM } CMPQ TAIL, $0 // if TAIL == 0 { return } JE dotc_end dotc_tail: // do { MOVSD (X_PTR), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X_i = { real(x[i]), real(x[i]) } MULPS NEG1, X2 // X_(i-1) = { -imag(x[i]), imag(x[i]) } MOVUPS (Y_PTR), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0x1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 ADDPS X3, SUM // SUM += X_i ADDQ INC_X, X_PTR // X_PTR += INC_X ADDQ INC_Y, Y_PTR // Y_PTR += INC_Y DECQ TAIL JNZ dotc_tail // } while --TAIL > 0 dotc_end: MOVSD SUM, sum+88(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/dotcunitary_amd64.s000066400000000000000000000165061450372207100243620ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVSLDUP_XPTR_IDX_8__X3 LONG $0x1C120FF3; BYTE $0xC6 // MOVSLDUP (SI)(AX*8), X3 #define MOVSLDUP_16_XPTR_IDX_8__X5 LONG $0x6C120FF3; WORD $0x10C6 // MOVSLDUP 16(SI)(AX*8), X5 #define MOVSLDUP_32_XPTR_IDX_8__X7 LONG $0x7C120FF3; WORD $0x20C6 // MOVSLDUP 32(SI)(AX*8), X7 #define MOVSLDUP_48_XPTR_IDX_8__X9 LONG $0x120F44F3; WORD $0xC64C; BYTE $0x30 // MOVSLDUP 48(SI)(AX*8), X9 #define MOVSHDUP_XPTR_IDX_8__X2 LONG $0x14160FF3; BYTE $0xC6 // MOVSHDUP (SI)(AX*8), X2 #define MOVSHDUP_16_XPTR_IDX_8__X4 LONG $0x64160FF3; WORD $0x10C6 // MOVSHDUP 16(SI)(AX*8), X4 #define MOVSHDUP_32_XPTR_IDX_8__X6 LONG $0x74160FF3; WORD $0x20C6 // MOVSHDUP 32(SI)(AX*8), X6 #define MOVSHDUP_48_XPTR_IDX_8__X8 LONG $0x160F44F3; WORD $0xC644; BYTE $0x30 // MOVSHDUP 48(SI)(AX*8), X8 #define MOVSHDUP_X3_X2 LONG $0xD3160FF3 // MOVSHDUP X3, X2 #define MOVSLDUP_X3_X3 LONG $0xDB120FF3 // MOVSLDUP X3, X3 #define ADDSUBPS_X2_X3 LONG $0xDAD00FF2 // ADDSUBPS X2, X3 #define ADDSUBPS_X4_X5 LONG $0xECD00FF2 // ADDSUBPS X4, X5 #define ADDSUBPS_X6_X7 LONG $0xFED00FF2 // ADDSUBPS X6, X7 #define ADDSUBPS_X8_X9 LONG $0xD00F45F2; BYTE $0xC8 // ADDSUBPS X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define IDX AX #define I_IDX DX #define NEG1 X15 #define P_NEG1 X14 // func DotcUnitary(x, y []complex64) (sum complex64) TEXT ·DotcUnitary(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y PXOR SUM, SUM // SUM = 0 PXOR P_SUM, P_SUM // P_SUM = 0 MOVQ x_len+8(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+32(FP), LEN CMOVQLE y_len+32(FP), LEN CMPQ LEN, $0 // if LEN == 0 { return } JE dotc_end XORQ IDX, IDX // i = 0 MOVSS $(-1.0), NEG1 SHUFPS $0, NEG1, NEG1 // { -1, -1, -1, -1 } MOVQ X_PTR, DX ANDQ $15, DX // DX = &x & 15 JZ dotc_aligned // if DX == 0 { goto dotc_aligned } MOVSD (X_PTR)(IDX*8), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X_i = { real(x[i]), real(x[i]) } MOVSD (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS NEG1, X2 // X_(i-1) = { -imag(x[i]), imag(x[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0x1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 MOVAPS X3, SUM // SUM = X_i INCQ IDX // IDX++ DECQ LEN // LEN-- JZ dotc_ret // if LEN == 0 { goto dotc_ret } dotc_aligned: MOVQ LEN, TAIL ANDQ $7, TAIL // TAIL = LEN % 8 SHRQ $3, LEN // LEN = floor( LEN / 8 ) JZ dotc_tail // if LEN == 0 { return } MOVUPS NEG1, P_NEG1 // Copy NEG1 for pipelining dotc_loop: // do { MOVSLDUP_XPTR_IDX_8__X3 // X_i = { real(x[i]), real(x[i]), real(x[i+1]), real(x[i+1]) } MOVSLDUP_16_XPTR_IDX_8__X5 MOVSLDUP_32_XPTR_IDX_8__X7 MOVSLDUP_48_XPTR_IDX_8__X9 MOVSHDUP_XPTR_IDX_8__X2 // X_(i-1) = { imag(x[i]), imag(x[i]), imag(x[i+1]), imag(x[i+1]) } MOVSHDUP_16_XPTR_IDX_8__X4 MOVSHDUP_32_XPTR_IDX_8__X6 MOVSHDUP_48_XPTR_IDX_8__X8 // X_j = { imag(y[i]), real(y[i]), imag(y[i+1]), real(y[i+1]) } MOVUPS (Y_PTR)(IDX*8), X10 MOVUPS 16(Y_PTR)(IDX*8), X11 MOVUPS 32(Y_PTR)(IDX*8), X12 MOVUPS 48(Y_PTR)(IDX*8), X13 // X_(i-1) = { -imag(x[i]), -imag(x[i]), -imag(x[i]+1), -imag(x[i]+1) } MULPS NEG1, X2 MULPS P_NEG1, X4 MULPS NEG1, X6 MULPS P_NEG1, X8 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]), // imag(y[i+1]) * real(x[i+1]), real(y[i+1]) * real(x[i+1]) } MULPS X10, X3 MULPS X11, X5 MULPS X12, X7 MULPS X13, X9 // X_j = { real(y[i]), imag(y[i]), real(y[i+1]), imag(y[i+1]) } SHUFPS $0xB1, X10, X10 SHUFPS $0xB1, X11, X11 SHUFPS $0xB1, X12, X12 SHUFPS $0xB1, X13, X13 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]), // real(y[i+1]) * imag(x[i+1]), imag(y[i+1]) * imag(x[i+1]) } MULPS X10, X2 MULPS X11, X4 MULPS X12, X6 MULPS X13, X8 // X_i = { // imag(result[i]): imag(y[i]) * real(x[i]) + real(y[i]) * imag(x[i]), // real(result[i]): real(y[i]) * real(x[i]) - imag(y[i]) * imag(x[i]), // imag(result[i+1]): imag(y[i+1]) * real(x[i+1]) + real(y[i+1]) * imag(x[i+1]), // real(result[i+1]): real(y[i+1]) * real(x[i+1]) - imag(y[i+1]) * imag(x[i+1]), // } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // SUM += X_i ADDPS X3, SUM ADDPS X5, P_SUM ADDPS X7, SUM ADDPS X9, P_SUM ADDQ $8, IDX // IDX += 8 DECQ LEN JNZ dotc_loop // } while --LEN > 0 ADDPS SUM, P_SUM // P_SUM = { P_SUM[1] + SUM[1], P_SUM[0] + SUM[0] } XORPS SUM, SUM // SUM = 0 CMPQ TAIL, $0 // if TAIL == 0 { return } JE dotc_end dotc_tail: MOVQ TAIL, LEN SHRQ $1, LEN // LEN = floor( LEN / 2 ) JZ dotc_tail_one // if LEN == 0 { goto dotc_tail_one } dotc_tail_two: // do { MOVSLDUP_XPTR_IDX_8__X3 // X_i = { real(x[i]), real(x[i]), real(x[i+1]), real(x[i+1]) } MOVSHDUP_XPTR_IDX_8__X2 // X_(i-1) = { imag(x[i]), imag(x[i]), imag(x[i]+1), imag(x[i]+1) } MOVUPS (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS NEG1, X2 // X_(i-1) = { -imag(x[i]), imag(x[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0xB1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 ADDPS X3, SUM // SUM += X_i ADDQ $2, IDX // IDX += 2 DECQ LEN JNZ dotc_tail_two // } while --LEN > 0 ADDPS SUM, P_SUM // P_SUM = { P_SUM[1] + SUM[1], P_SUM[0] + SUM[0] } XORPS SUM, SUM // SUM = 0 ANDQ $1, TAIL JZ dotc_end dotc_tail_one: MOVSD (X_PTR)(IDX*8), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X_i = { real(x[i]), real(x[i]) } MOVSD (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS NEG1, X2 // X_(i-1) = { -imag(x[i]), imag(x[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0x1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 ADDPS X3, SUM // SUM += X_i dotc_end: ADDPS P_SUM, SUM // SUM = { P_SUM[0] + SUM[0] } MOVHLPS P_SUM, P_SUM // P_SUM = { P_SUM[1], P_SUM[1] } ADDPS P_SUM, SUM // SUM = { P_SUM[1] + SUM[0] } dotc_ret: MOVSD SUM, sum+48(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/dotuinc_amd64.s000066400000000000000000000106411450372207100234540ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVSHDUP_X3_X2 LONG $0xD3160FF3 // MOVSHDUP X3, X2 #define MOVSHDUP_X5_X4 LONG $0xE5160FF3 // MOVSHDUP X5, X4 #define MOVSHDUP_X7_X6 LONG $0xF7160FF3 // MOVSHDUP X7, X6 #define MOVSHDUP_X9_X8 LONG $0x160F45F3; BYTE $0xC1 // MOVSHDUP X9, X8 #define MOVSLDUP_X3_X3 LONG $0xDB120FF3 // MOVSLDUP X3, X3 #define MOVSLDUP_X5_X5 LONG $0xED120FF3 // MOVSLDUP X5, X5 #define MOVSLDUP_X7_X7 LONG $0xFF120FF3 // MOVSLDUP X7, X7 #define MOVSLDUP_X9_X9 LONG $0x120F45F3; BYTE $0xC9 // MOVSLDUP X9, X9 #define ADDSUBPS_X2_X3 LONG $0xDAD00FF2 // ADDSUBPS X2, X3 #define ADDSUBPS_X4_X5 LONG $0xECD00FF2 // ADDSUBPS X4, X5 #define ADDSUBPS_X6_X7 LONG $0xFED00FF2 // ADDSUBPS X6, X7 #define ADDSUBPS_X8_X9 LONG $0xD00F45F2; BYTE $0xC8 // ADDSUBPS X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define INC_X R8 #define INCx3_X R9 #define INC_Y R10 #define INCx3_Y R11 // func DotuInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) TEXT ·DotuInc(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y PXOR SUM, SUM // SUM = 0 PXOR P_SUM, P_SUM // P_SUM = 0 MOVQ n+48(FP), LEN // LEN = n CMPQ LEN, $0 // if LEN == 0 { return } JE dotu_end MOVQ ix+72(FP), INC_X MOVQ iy+80(FP), INC_Y LEAQ (X_PTR)(INC_X*8), X_PTR // X_PTR = &(X_PTR[ix]) LEAQ (Y_PTR)(INC_Y*8), Y_PTR // Y_PTR = &(Y_PTR[iy]) MOVQ incX+56(FP), INC_X // INC_X = incX * sizeof(complex64) SHLQ $3, INC_X MOVQ incY+64(FP), INC_Y // INC_Y = incY * sizeof(complex64) SHLQ $3, INC_Y MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = LEN % 4 SHRQ $2, LEN // LEN = floor( LEN / 4 ) JZ dotu_tail // if TAIL == 0 { goto dotu_tail } LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = INC_Y * 3 dotu_loop: // do { MOVSD (X_PTR), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSD (X_PTR)(INC_X*1), X5 MOVSD (X_PTR)(INC_X*2), X7 MOVSD (X_PTR)(INCx3_X*1), X9 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSHDUP_X3_X2 MOVSHDUP_X5_X4 MOVSHDUP_X7_X6 MOVSHDUP_X9_X8 // X_i = { real(x[i]), real(x[i]) } MOVSLDUP_X3_X3 MOVSLDUP_X5_X5 MOVSLDUP_X7_X7 MOVSLDUP_X9_X9 // X_j = { imag(y[i]), real(y[i]) } MOVSD (Y_PTR), X10 MOVSD (Y_PTR)(INC_Y*1), X11 MOVSD (Y_PTR)(INC_Y*2), X12 MOVSD (Y_PTR)(INCx3_Y*1), X13 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } MULPS X10, X3 MULPS X11, X5 MULPS X12, X7 MULPS X13, X9 // X_j = { real(y[i]), imag(y[i]) } SHUFPS $0xB1, X10, X10 SHUFPS $0xB1, X11, X11 SHUFPS $0xB1, X12, X12 SHUFPS $0xB1, X13, X13 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } MULPS X10, X2 MULPS X11, X4 MULPS X12, X6 MULPS X13, X8 // X_i = { // imag(result[i]): imag(y[i]) * real(x[i]) + real(y[i]) * imag(x[i]), // real(result[i]): real(y[i]) * real(x[i]) - imag(y[i]) * imag(x[i]) } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // SUM += X_i ADDPS X3, SUM ADDPS X5, P_SUM ADDPS X7, SUM ADDPS X9, P_SUM LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[INC_X*4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[INC_Y*4]) DECQ LEN JNZ dotu_loop // } while --LEN > 0 ADDPS P_SUM, SUM // SUM = { P_SUM + SUM } CMPQ TAIL, $0 // if TAIL == 0 { return } JE dotu_end dotu_tail: // do { MOVSD (X_PTR), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X_i = { real(x[i]), real(x[i]) } MOVUPS (Y_PTR), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0x1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 ADDPS X3, SUM // SUM += X_i ADDQ INC_X, X_PTR // X_PTR += INC_X ADDQ INC_Y, Y_PTR // Y_PTR += INC_Y DECQ TAIL JNZ dotu_tail // } while --TAIL > 0 dotu_end: MOVSD SUM, sum+88(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/dotuunitary_amd64.s000066400000000000000000000156021450372207100244000ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVSLDUP_XPTR_IDX_8__X3 LONG $0x1C120FF3; BYTE $0xC6 // MOVSLDUP (SI)(AX*8), X3 #define MOVSLDUP_16_XPTR_IDX_8__X5 LONG $0x6C120FF3; WORD $0x10C6 // MOVSLDUP 16(SI)(AX*8), X5 #define MOVSLDUP_32_XPTR_IDX_8__X7 LONG $0x7C120FF3; WORD $0x20C6 // MOVSLDUP 32(SI)(AX*8), X7 #define MOVSLDUP_48_XPTR_IDX_8__X9 LONG $0x120F44F3; WORD $0xC64C; BYTE $0x30 // MOVSLDUP 48(SI)(AX*8), X9 #define MOVSHDUP_XPTR_IDX_8__X2 LONG $0x14160FF3; BYTE $0xC6 // MOVSHDUP (SI)(AX*8), X2 #define MOVSHDUP_16_XPTR_IDX_8__X4 LONG $0x64160FF3; WORD $0x10C6 // MOVSHDUP 16(SI)(AX*8), X4 #define MOVSHDUP_32_XPTR_IDX_8__X6 LONG $0x74160FF3; WORD $0x20C6 // MOVSHDUP 32(SI)(AX*8), X6 #define MOVSHDUP_48_XPTR_IDX_8__X8 LONG $0x160F44F3; WORD $0xC644; BYTE $0x30 // MOVSHDUP 48(SI)(AX*8), X8 #define MOVSHDUP_X3_X2 LONG $0xD3160FF3 // MOVSHDUP X3, X2 #define MOVSLDUP_X3_X3 LONG $0xDB120FF3 // MOVSLDUP X3, X3 #define ADDSUBPS_X2_X3 LONG $0xDAD00FF2 // ADDSUBPS X2, X3 #define ADDSUBPS_X4_X5 LONG $0xECD00FF2 // ADDSUBPS X4, X5 #define ADDSUBPS_X6_X7 LONG $0xFED00FF2 // ADDSUBPS X6, X7 #define ADDSUBPS_X8_X9 LONG $0xD00F45F2; BYTE $0xC8 // ADDSUBPS X8, X9 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define SUM X0 #define P_SUM X1 #define IDX AX #define I_IDX DX #define NEG1 X15 #define P_NEG1 X14 // func DotuUnitary(x, y []complex64) (sum complex64) TEXT ·DotuUnitary(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y PXOR SUM, SUM // SUM = 0 PXOR P_SUM, P_SUM // P_SUM = 0 MOVQ x_len+8(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+32(FP), LEN CMOVQLE y_len+32(FP), LEN CMPQ LEN, $0 // if LEN == 0 { return } JE dotu_end XORQ IDX, IDX // IDX = 0 MOVQ X_PTR, DX ANDQ $15, DX // DX = &x & 15 JZ dotu_aligned // if DX == 0 { goto dotu_aligned } MOVSD (X_PTR)(IDX*8), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X_i = { real(x[i]), real(x[i]) } MOVSD (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0x1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 MOVAPS X3, SUM // SUM = X_i INCQ IDX // IDX++ DECQ LEN // LEN-- JZ dotu_end // if LEN == 0 { goto dotu_end } dotu_aligned: MOVQ LEN, TAIL ANDQ $7, TAIL // TAIL = LEN % 8 SHRQ $3, LEN // LEN = floor( LEN / 8 ) JZ dotu_tail // if LEN == 0 { goto dotu_tail } PXOR P_SUM, P_SUM dotu_loop: // do { MOVSLDUP_XPTR_IDX_8__X3 // X_i = { real(x[i]), real(x[i]), real(x[i+1]), real(x[i+1]) } MOVSLDUP_16_XPTR_IDX_8__X5 MOVSLDUP_32_XPTR_IDX_8__X7 MOVSLDUP_48_XPTR_IDX_8__X9 MOVSHDUP_XPTR_IDX_8__X2 // X_(i-1) = { imag(x[i]), imag(x[i]), imag(x[i]+1), imag(x[i]+1) } MOVSHDUP_16_XPTR_IDX_8__X4 MOVSHDUP_32_XPTR_IDX_8__X6 MOVSHDUP_48_XPTR_IDX_8__X8 // X_j = { imag(y[i]), real(y[i]), imag(y[i+1]), real(y[i+1]) } MOVUPS (Y_PTR)(IDX*8), X10 MOVUPS 16(Y_PTR)(IDX*8), X11 MOVUPS 32(Y_PTR)(IDX*8), X12 MOVUPS 48(Y_PTR)(IDX*8), X13 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]), // imag(y[i+1]) * real(x[i+1]), real(y[i+1]) * real(x[i+1]) } MULPS X10, X3 MULPS X11, X5 MULPS X12, X7 MULPS X13, X9 // X_j = { real(y[i]), imag(y[i]), real(y[i+1]), imag(y[i+1]) } SHUFPS $0xB1, X10, X10 SHUFPS $0xB1, X11, X11 SHUFPS $0xB1, X12, X12 SHUFPS $0xB1, X13, X13 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]), // real(y[i+1]) * imag(x[i+1]), imag(y[i+1]) * imag(x[i+1]) } MULPS X10, X2 MULPS X11, X4 MULPS X12, X6 MULPS X13, X8 // X_i = { // imag(result[i]): imag(y[i]) * real(x[i]) + real(y[i]) * imag(x[i]), // real(result[i]): real(y[i]) * real(x[i]) - imag(y[i]) * imag(x[i]), // imag(result[i+1]): imag(y[i+1]) * real(x[i+1]) + real(y[i+1]) * imag(x[i+1]), // real(result[i+1]): real(y[i+1]) * real(x[i+1]) - imag(y[i+1]) * imag(x[i+1]), // } ADDSUBPS_X2_X3 ADDSUBPS_X4_X5 ADDSUBPS_X6_X7 ADDSUBPS_X8_X9 // SUM += X_i ADDPS X3, SUM ADDPS X5, P_SUM ADDPS X7, SUM ADDPS X9, P_SUM ADDQ $8, IDX // IDX += 8 DECQ LEN JNZ dotu_loop // } while --LEN > 0 ADDPS SUM, P_SUM // P_SUM = { P_SUM[1] + SUM[1], P_SUM[0] + SUM[0] } XORPS SUM, SUM // SUM = 0 CMPQ TAIL, $0 // if TAIL == 0 { return } JE dotu_end dotu_tail: MOVQ TAIL, LEN SHRQ $1, LEN // LEN = floor( LEN / 2 ) JZ dotu_tail_one // if LEN == 0 { goto dotc_tail_one } dotu_tail_two: // do { MOVSLDUP_XPTR_IDX_8__X3 // X_i = { real(x[i]), real(x[i]), real(x[i+1]), real(x[i+1]) } MOVSHDUP_XPTR_IDX_8__X2 // X_(i-1) = { imag(x[i]), imag(x[i]), imag(x[i]+1), imag(x[i]+1) } MOVUPS (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0xB1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 ADDPS X3, SUM // SUM += X_i ADDQ $2, IDX // IDX += 2 DECQ LEN JNZ dotu_tail_two // } while --LEN > 0 ADDPS SUM, P_SUM // P_SUM = { P_SUM[1] + SUM[1], P_SUM[0] + SUM[0] } XORPS SUM, SUM // SUM = 0 ANDQ $1, TAIL JZ dotu_end dotu_tail_one: MOVSD (X_PTR)(IDX*8), X3 // X_i = { imag(x[i]), real(x[i]) } MOVSHDUP_X3_X2 // X_(i-1) = { imag(x[i]), imag(x[i]) } MOVSLDUP_X3_X3 // X_i = { real(x[i]), real(x[i]) } MOVSD (Y_PTR)(IDX*8), X10 // X_j = { imag(y[i]), real(y[i]) } MULPS X10, X3 // X_i = { imag(y[i]) * real(x[i]), real(y[i]) * real(x[i]) } SHUFPS $0x1, X10, X10 // X_j = { real(y[i]), imag(y[i]) } MULPS X10, X2 // X_(i-1) = { real(y[i]) * imag(x[i]), imag(y[i]) * imag(x[i]) } // X_i = { // imag(result[i]): imag(y[i])*real(x[i]) + real(y[i])*imag(x[i]), // real(result[i]): real(y[i])*real(x[i]) - imag(y[i])*imag(x[i]) } ADDSUBPS_X2_X3 ADDPS X3, SUM // SUM += X_i dotu_end: ADDPS P_SUM, SUM // SUM = { P_SUM[0] + SUM[0] } MOVHLPS P_SUM, P_SUM // P_SUM = { P_SUM[1], P_SUM[1] } ADDPS P_SUM, SUM // SUM = { P_SUM[1] + SUM[0] } dotu_ret: MOVSD SUM, sum+48(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/c64/l2norm_test.go000066400000000000000000000124351450372207100234320ustar00rootroot00000000000000// Copyright ©2019 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 c64_test import ( "fmt" "math" "testing" . "gonum.org/v1/gonum/internal/asm/c64" "gonum.org/v1/gonum/internal/cmplx64" "gonum.org/v1/gonum/internal/math32" ) // nanwith copied from floats package func nanwith(payload uint32) complex64 { const ( nanBits = 0x7ff80000 nanMask = 0xfff80000 ) nan := math.Float32frombits(nanBits | (payload &^ nanMask)) return complex(nan, nan) } func TestL2NormUnitary(t *testing.T) { const tol = 1e-7 var src_gd complex64 = 1 for j, v := range []struct { want float32 x []complex64 }{ {want: 0, x: []complex64{}}, {want: 2, x: []complex64{2}}, {want: 2, x: []complex64{2i}}, {want: math32.Sqrt(8), x: []complex64{2 + 2i}}, {want: 3.7416573867739413, x: []complex64{1, 2, 3}}, {want: 3.7416573867739413, x: []complex64{-1, -2, -3}}, {want: 3.7416573867739413, x: []complex64{1i, 2i, 3i}}, {want: 3.7416573867739413, x: []complex64{-1i, -2i, -3i}}, {want: math32.Sqrt(28), x: []complex64{1 + 1i, 2 + 2i, 3 + 3i}}, {want: math32.Sqrt(28), x: []complex64{-1 - 1i, -2 - 2i, -3 - 3i}}, {want: nan, x: []complex64{cnan}}, {want: nan, x: []complex64{1, cinf, 3, nanwith(25), 5}}, {want: 17.88854381999832, x: []complex64{8, -8, 8, -8, 8}}, {want: 2.23606797749979, x: []complex64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, {want: 17.88854381999832, x: []complex64{8i, -8i, 8i, -8i, 8i}}, {want: 2.23606797749979, x: []complex64{0, 1i, 0, -1i, 0, 1i, 0, -1i, 0, 1i}}, {want: math32.Sqrt(640), x: []complex64{8 + 8i, -8 - 8i, 8 + 8i, -8 - 8i, 8 + 8i}}, {want: math32.Sqrt(10), x: []complex64{0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L2NormUnitary(src) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Norm error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func TestL2DistanceUnitary(t *testing.T) { const tol = 1e-7 var src_gd complex64 = 1 for j, v := range []struct { want float32 x, y []complex64 }{ {want: 0, x: []complex64{}, y: []complex64{}}, {want: 2, x: []complex64{3}, y: []complex64{1}}, {want: 2, x: []complex64{3i}, y: []complex64{1i}}, {want: 3.7416573867739413, x: []complex64{2, 4, 6}, y: []complex64{1, 2, 3}}, {want: 3.7416573867739413, x: []complex64{1, 2, 3}, y: []complex64{2, 4, 6}}, {want: 3.7416573867739413, x: []complex64{2i, 4i, 6i}, y: []complex64{1i, 2i, 3i}}, {want: 3.7416573867739413, x: []complex64{1i, 2i, 3i}, y: []complex64{2i, 4i, 6i}}, {want: math32.Sqrt(28), x: []complex64{2 + 2i, 4 + 4i, 6 + 6i}, y: []complex64{1 + 1i, 2 + 2i, 3 + 3i}}, {want: math32.Sqrt(28), x: []complex64{1 + 1i, 2 + 2i, 3 + 3i}, y: []complex64{2 + 2i, 4 + 4i, 6 + 6i}}, {want: nan, x: []complex64{cnan}, y: []complex64{0}}, {want: 17.88854381999832, x: []complex64{9, -9, 9, -9, 9}, y: []complex64{1, -1, 1, -1, 1}}, {want: 2.23606797749979, x: []complex64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}, y: []complex64{0, 2, 0, -2, 0, 2, 0, -2, 0, 2}}, {want: 17.88854381999832, x: []complex64{9i, -9i, 9i, -9i, 9i}, y: []complex64{1i, -1i, 1i, -1i, 1i}}, {want: 2.23606797749979, x: []complex64{0, 1i, 0, -1i, 0, 1i, 0, -1i, 0, 1i}, y: []complex64{0, 2i, 0, -2i, 0, 2i, 0, -2i, 0, 2i}}, {want: math32.Sqrt(640), x: []complex64{9 + 9i, -9 - 9i, 9 + 9i, -9 - 9i, 9 + 9i}, y: []complex64{1 + 1i, -1 - 1i, 1 + 1i, -1 - 1i, 1 + 1i}}, {want: math32.Sqrt(10), x: []complex64{0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i}, y: []complex64{0, 2 + 2i, 0, -2 - 2i, 0, 2 + 2i, 0, -2 - 2i, 0, 2 + 2i}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) v.y = guardVector(v.y, src_gd, g_ln) srcX := v.x[g_ln : len(v.x)-g_ln] srcY := v.y[g_ln : len(v.y)-g_ln] ret := L2DistanceUnitary(srcX, srcY) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Distance error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func BenchmarkL2NormNetlib(b *testing.B) { netlib := func(x []complex64) (sum float32) { var scale float32 sumSquares := float32(1.0) for _, v := range x { if v == 0 { continue } absxi := cmplx64.Abs(v) if math32.IsNaN(absxi) { return math32.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math32.IsInf(scale, 1) { return math32.Inf(1) } return scale * math32.Sqrt(sumSquares) } tests := []struct { name string f func(x []complex64) float32 }{ {"L2NormUnitaryNetlib", netlib}, {"L2NormUnitary", L2NormUnitary}, } x[0] = 4 // replace the leading zero (edge case) for _, test := range tests { for _, ln := range []uintptr{1, 3, 10, 30, 1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5} { b.Run(fmt.Sprintf("%s-%d", test.name, ln), func(b *testing.B) { b.SetBytes(int64(64 * ln)) x := x[:ln] b.ResetTimer() for i := 0; i < b.N; i++ { test.f(x) } }) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/scal.go000066400000000000000000000032471450372207100221050ustar00rootroot00000000000000// Copyright ©2016 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 c64 // ScalUnitary is // // for i := range x { // x[i] *= alpha // } func ScalUnitary(alpha complex64, x []complex64) { for i := range x { x[i] *= alpha } } // ScalUnitaryTo is // // for i, v := range x { // dst[i] = alpha * v // } func ScalUnitaryTo(dst []complex64, alpha complex64, x []complex64) { for i, v := range x { dst[i] = alpha * v } } // ScalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] *= alpha // ix += incX // } func ScalInc(alpha complex64, x []complex64, n, incX uintptr) { var ix uintptr for i := 0; i < int(n); i++ { x[ix] *= alpha ix += incX } } // ScalIncTo is // // var idst, ix uintptr // for i := 0; i < int(n); i++ { // dst[idst] = alpha * x[ix] // ix += incX // idst += incDst // } func ScalIncTo(dst []complex64, incDst uintptr, alpha complex64, x []complex64, n, incX uintptr) { var idst, ix uintptr for i := 0; i < int(n); i++ { dst[idst] = alpha * x[ix] ix += incX idst += incDst } } // SscalUnitary is // // for i, v := range x { // x[i] = complex(real(v)*alpha, imag(v)*alpha) // } func SscalUnitary(alpha float32, x []complex64) { for i, v := range x { x[i] = complex(real(v)*alpha, imag(v)*alpha) } } // SscalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] = complex(real(x[ix])*alpha, imag(x[ix])*alpha) // ix += inc // } func SscalInc(alpha float32, x []complex64, n, inc uintptr) { var ix uintptr for i := 0; i < int(n); i++ { x[ix] = complex(real(x[ix])*alpha, imag(x[ix])*alpha) ix += inc } } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/stubs.go000066400000000000000000000056521450372207100223250ustar00rootroot00000000000000// Copyright ©2020 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 c64 import ( "gonum.org/v1/gonum/internal/cmplx64" "gonum.org/v1/gonum/internal/math32" ) // Add is // // for i, v := range s { // dst[i] += v // } func Add(dst, s []complex64) { for i, v := range s { dst[i] += v } } // AddConst is // // for i := range x { // x[i] += alpha // } func AddConst(alpha complex64, x []complex64) { for i := range x { x[i] += alpha } } // CumSum is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] + v // } // return dst func CumSum(dst, s []complex64) []complex64 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] + v } return dst } // CumProd is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] * v // } // return dst func CumProd(dst, s []complex64) []complex64 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] * v } return dst } // Div is // // for i, v := range s { // dst[i] /= v // } func Div(dst, s []complex64) { for i, v := range s { dst[i] /= v } } // DivTo is // // for i, v := range s { // dst[i] = v / t[i] // } // return dst func DivTo(dst, s, t []complex64) []complex64 { for i, v := range s { dst[i] = v / t[i] } return dst } // DotUnitary is // // for i, v := range x { // sum += conj(v) * y[i] // } // return sum func DotUnitary(x, y []complex64) (sum complex64) { for i, v := range x { sum += cmplx64.Conj(v) * y[i] } return sum } // L2DistanceUnitary returns the L2-norm of x-y. func L2DistanceUnitary(x, y []complex64) (norm float32) { var scale float32 sumSquares := float32(1.0) for i, v := range x { v -= y[i] if v == 0 { continue } absxi := cmplx64.Abs(v) if math32.IsNaN(absxi) { return math32.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math32.IsInf(scale, 1) { return math32.Inf(1) } return scale * math32.Sqrt(sumSquares) } // L2NormUnitary returns the L2-norm of x. func L2NormUnitary(x []complex64) (norm float32) { var scale float32 sumSquares := float32(1.0) for _, v := range x { if v == 0 { continue } absxi := cmplx64.Abs(v) if math32.IsNaN(absxi) { return math32.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math32.IsInf(scale, 1) { return math32.Inf(1) } return scale * math32.Sqrt(sumSquares) } // Sum is // // var sum complex64 // for i := range x { // sum += x[i] // } func Sum(x []complex64) complex64 { var sum complex64 for _, v := range x { sum += v } return sum } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/stubs_amd64.go000066400000000000000000000032071450372207100233120ustar00rootroot00000000000000// Copyright ©2016 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:build !noasm && !gccgo && !safe // +build !noasm,!gccgo,!safe package c64 // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha complex64, x, y []complex64) // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []complex64, alpha complex64, x, y []complex64) // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []complex64, incDst, idst uintptr, alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) // DotcUnitary is // // for i, v := range x { // sum += y[i] * conj(v) // } // return sum func DotcUnitary(x, y []complex64) (sum complex64) // DotcInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * conj(x[ix]) // ix += incX // iy += incY // } // return sum func DotcInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) // DotuUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotuUnitary(x, y []complex64) (sum complex64) // DotuInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotuInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) golang-gonum-v1-gonum-0.14.0/internal/asm/c64/stubs_noasm.go000066400000000000000000000044221450372207100235140ustar00rootroot00000000000000// Copyright ©2016 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package c64 // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha complex64, x, y []complex64) { for i, v := range x { y[i] += alpha * v } } // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []complex64, alpha complex64, x, y []complex64) { for i, v := range x { dst[i] = alpha*v + y[i] } } // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []complex64, incDst, idst uintptr, alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } // DotcUnitary is // // for i, v := range x { // sum += y[i] * conj(v) // } // return sum func DotcUnitary(x, y []complex64) (sum complex64) { for i, v := range x { sum += y[i] * conj(v) } return sum } // DotcInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * conj(x[ix]) // ix += incX // iy += incY // } // return sum func DotcInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) { for i := 0; i < int(n); i++ { sum += y[iy] * conj(x[ix]) ix += incX iy += incY } return sum } // DotuUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotuUnitary(x, y []complex64) (sum complex64) { for i, v := range x { sum += y[i] * v } return sum } // DotuInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotuInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) { for i := 0; i < int(n); i++ { sum += y[iy] * x[ix] ix += incX iy += incY } return sum } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/stubs_test.go000066400000000000000000000527411450372207100233650ustar00rootroot00000000000000// Copyright ©2016 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 c64_test import ( "fmt" "testing" . "gonum.org/v1/gonum/internal/asm/c64" ) func TestAdd(t *testing.T) { var src_gd, dst_gd complex64 = 1, 0 for j, v := range []struct { dst, src, expect []complex64 }{ { dst: []complex64{1 + 1i}, src: []complex64{0}, expect: []complex64{1 + 1i}, }, { dst: []complex64{1, 2, 3}, src: []complex64{1 + 1i}, expect: []complex64{2 + 1i, 2, 3}, }, { dst: []complex64{}, src: []complex64{}, expect: []complex64{}, }, { dst: []complex64{1}, src: []complex64{cnan}, expect: []complex64{cnan}, }, { dst: []complex64{8, 8, 8, 8, 8}, src: []complex64{2 + 1i, 4 - 1i, cnan, 8 + 1i, 9 - 1i}, expect: []complex64{10 + 1i, 12 - 1i, cnan, 16 + 1i, 17 - 1i}, }, { dst: []complex64{0, 1 + 1i, 2, 3 - 1i, 4}, src: []complex64{cinf, 4, cnan, 8 + 1i, 9 - 1i}, expect: []complex64{cinf, 5 + 1i, cnan, 11, 13 - 1i}, }, { dst: make([]complex64, 50)[1:49], src: make([]complex64, 50)[1:49], expect: make([]complex64, 50)[1:49], }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] Add(dst, src) for i := range v.expect { if !sameCmplx(dst[i], v.expect[i]) { t.Errorf("Test %d Add error at %d Got: %v Expected: %v", j, i, dst[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestAddConst(t *testing.T) { var src_gd complex64 = 0 for j, v := range []struct { alpha complex64 src, expect []complex64 }{ { alpha: 1 + 1i, src: []complex64{0}, expect: []complex64{1 + 1i}, }, { alpha: 5, src: []complex64{}, expect: []complex64{}, }, { alpha: 1, src: []complex64{cnan}, expect: []complex64{cnan}, }, { alpha: 8 + 1i, src: []complex64{2, 4, cnan, 8, 9}, expect: []complex64{10 + 1i, 12 + 1i, cnan, 16 + 1i, 17 + 1i}, }, { alpha: cinf, src: []complex64{cinf, 4, cnan, 8, 9}, expect: []complex64{cinf, cinf, cnan, cinf, cinf}, }, } { g_ln := 4 + j%2 v.src = guardVector(v.src, src_gd, g_ln) src := v.src[g_ln : len(v.src)-g_ln] AddConst(v.alpha, src) for i := range v.expect { if !sameCmplx(src[i], v.expect[i]) { t.Errorf("Test %d AddConst error at %d Got: %v Expected: %v", j, i, src[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:g_ln], v.src[len(v.src)-g_ln:]) } } } var axpyTests = []struct { incX, incY, incDst int ix, iy, idst uintptr a complex64 dst, x, y []complex64 ex []complex64 }{ {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 1i, dst: []complex64{5}, x: []complex64{1}, y: []complex64{1i}, ex: []complex64{1 + 2i}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 2i, dst: []complex64{0, 0, 0}, x: []complex64{0, 0, 0}, y: []complex64{1, 1, 1}, ex: []complex64{1, 1, 1}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 2i, dst: []complex64{0, 0, 0}, x: []complex64{0, 0}, y: []complex64{1, 1, 1}, ex: []complex64{1, 1}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 + 2i, dst: []complex64{1i, 1i, 1i}, x: []complex64{1i, 1i, 1i}, y: []complex64{1, 2, 1}, ex: []complex64{-1 + 1i, 1i, -1 + 1i}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: -1i, dst: []complex64{1i, 1i, 1i}, x: []complex64{1i, 1i, 1i}, y: []complex64{1, 2, 1}, ex: []complex64{2, 3, 2}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: -1i, dst: []complex64{1i, 1i, 1i}, x: []complex64{1i, 1i, 1i, 1i, 1i}[1:4], y: []complex64{1, 1, 2, 1, 1}[1:4], ex: []complex64{2, 3, 2}}, {incX: 2, incY: 4, incDst: 3, ix: 0, iy: 0, idst: 0, a: -2, dst: []complex64{1i, 1i, 1i, 1i, 1i}, x: []complex64{2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i}, y: []complex64{1, 1, 2, 1, 1}, ex: []complex64{-3 - 2i, -3 - 2i, -2 - 2i, -3 - 2i, -3 - 2i}}, // Run big test twice, once aligned once unaligned. {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 - 1i, dst: make([]complex64, 10), x: []complex64{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex64{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex64{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 1 - 1i, dst: make([]complex64, 10), x: []complex64{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex64{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex64{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, {incX: -2, incY: -2, incDst: -3, ix: 18, iy: 18, idst: 27, a: 1 - 1i, dst: make([]complex64, 10), x: []complex64{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex64{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex64{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, {incX: -2, incY: 2, incDst: -3, ix: 18, iy: 0, idst: 27, a: 1 - 1i, dst: make([]complex64, 10), x: []complex64{1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i, 1i}, y: []complex64{1, 1, 2, 1, 1, 1, 1, 2, 1, 1}, ex: []complex64{2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 2 + 1i, 3 + 1i, 2 + 1i, 2 + 1i}}, } func TestAxpyUnitary(t *testing.T) { const xGdVal, yGdVal = 1, 1 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] AxpyUnitary(test.a, x, y) for i := range test.ex { if y[i] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, y[i], test.ex[i]) } } if !isValidGuard(test.x, xGdVal, xgLn) { t.Errorf("Test %d Guard violated in x vector %v %v", cas, test.x[:xgLn], test.x[len(test.x)-xgLn:]) } if !isValidGuard(test.y, yGdVal, ygLn) { t.Errorf("Test %d Guard violated in y vector %v %v", cas, test.y[:ygLn], test.y[len(test.y)-ygLn:]) } } } func TestAxpyUnitaryTo(t *testing.T) { const xGdVal, yGdVal, dstGdVal = 1, 1, 0 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) test.dst = guardVector(test.dst, dstGdVal, xgLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] dst := test.dst[xgLn : len(test.dst)-xgLn] AxpyUnitaryTo(dst, test.a, x, y) for i := range test.ex { if dst[i] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, dst[i], test.ex[i]) } } if !isValidGuard(test.x, xGdVal, xgLn) { t.Errorf("Test %d Guard violated in x vector %v %v", cas, test.x[:xgLn], test.x[len(test.x)-xgLn:]) } if !isValidGuard(test.y, yGdVal, ygLn) { t.Errorf("Test %d Guard violated in y vector %v %v", cas, test.y[:ygLn], test.y[len(test.y)-ygLn:]) } if !isValidGuard(test.dst, dstGdVal, xgLn) { t.Errorf("Test %d Guard violated in dst vector %v %v", cas, test.dst[:xgLn], test.dst[len(test.dst)-xgLn:]) } } } func TestAxpyInc(t *testing.T) { const xGdVal, yGdVal = 1, 1 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardIncVector(test.x, xGdVal, test.incX, xgLn), guardIncVector(test.y, yGdVal, test.incY, ygLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] AxpyInc(test.a, x, y, uintptr(len(test.ex)), uintptr(test.incX), uintptr(test.incY), test.ix, test.iy) for i := range test.ex { if y[int(test.iy)+i*test.incY] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, y[i*test.incY], test.ex[i]) } } checkValidIncGuard(t, test.x, xGdVal, test.incX, xgLn) checkValidIncGuard(t, test.y, yGdVal, test.incY, ygLn) } } func TestAxpyIncTo(t *testing.T) { const xGdVal, yGdVal, dstGdVal = 1, 1, 0 for cas, test := range axpyTests { xgLn, ygLn := 4+cas%2, 4+cas%3 test.x, test.y = guardIncVector(test.x, xGdVal, test.incX, xgLn), guardIncVector(test.y, yGdVal, test.incY, ygLn) test.dst = guardIncVector(test.dst, dstGdVal, test.incDst, xgLn) x, y := test.x[xgLn:len(test.x)-xgLn], test.y[ygLn:len(test.y)-ygLn] dst := test.dst[xgLn : len(test.dst)-xgLn] AxpyIncTo(dst, uintptr(test.incDst), test.idst, test.a, x, y, uintptr(len(test.ex)), uintptr(test.incX), uintptr(test.incY), test.ix, test.iy) for i := range test.ex { if dst[int(test.idst)+i*test.incDst] != test.ex[i] { t.Errorf("Test %d Unexpected result at %d Got: %v Expected: %v", cas, i, dst[i*test.incDst], test.ex[i]) } } checkValidIncGuard(t, test.x, xGdVal, test.incX, xgLn) checkValidIncGuard(t, test.y, yGdVal, test.incY, ygLn) checkValidIncGuard(t, test.dst, dstGdVal, test.incDst, xgLn) } } func TestCumSum(t *testing.T) { var src_gd, dst_gd complex64 = -1, 0 for j, v := range []struct { dst, src, expect []complex64 }{ { dst: []complex64{}, src: []complex64{}, expect: []complex64{}, }, { dst: []complex64{0}, src: []complex64{1 + 1i}, expect: []complex64{1 + 1i}, }, { dst: []complex64{cnan}, src: []complex64{cnan}, expect: []complex64{cnan}, }, { dst: []complex64{0, 0, 0}, src: []complex64{1, 2 + 1i, 3 + 2i}, expect: []complex64{1, 3 + 1i, 6 + 3i}, }, { dst: []complex64{0, 0, 0, 0}, src: []complex64{1, 2 + 1i, 3 + 2i}, expect: []complex64{1, 3 + 1i, 6 + 3i}, }, { dst: []complex64{0, 0, 0, 0}, src: []complex64{1, 2 + 1i, 3 + 2i, 4 + 3i}, expect: []complex64{1, 3 + 1i, 6 + 3i, 10 + 6i}, }, { dst: []complex64{1, cnan, cnan, 1, 1}, src: []complex64{1, 1, cnan, 1, 1}, expect: []complex64{1, 2, cnan, cnan, cnan}, }, { dst: []complex64{cnan, 4, cinf, cinf, 9}, src: []complex64{cinf, 4, cnan, cinf, 9}, expect: []complex64{cinf, cinf, cnan, cnan, cnan}, }, { dst: make([]complex64, 16), src: []complex64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, expect: []complex64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, }, } { g_ln := 4 + j%2 v.src, v.dst = guardVector(v.src, src_gd, g_ln), guardVector(v.dst, dst_gd, g_ln) src, dst := v.src[g_ln:len(v.src)-g_ln], v.dst[g_ln:len(v.dst)-g_ln] ret := CumSum(dst, src) for i := range v.expect { if !sameCmplx(ret[i], v.expect[i]) { t.Errorf("Test %d CumSum error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !sameCmplx(ret[i], dst[i]) { t.Errorf("Test %d CumSum ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.src, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:g_ln], v.src[len(v.src)-g_ln:]) } if !isValidGuard(v.dst, dst_gd, g_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:g_ln], v.dst[len(v.dst)-g_ln:]) } } } func TestCumProd(t *testing.T) { var src_gd, dst_gd complex64 = -1, 1 for j, v := range []struct { dst, src, expect []complex64 }{ { dst: []complex64{}, src: []complex64{}, expect: []complex64{}, }, { dst: []complex64{1}, src: []complex64{1 + 1i}, expect: []complex64{1 + 1i}, }, { dst: []complex64{cnan}, src: []complex64{cnan}, expect: []complex64{cnan}, }, { dst: []complex64{0, 0, 0, 0}, src: []complex64{1, 2 + 1i, 3 + 2i, 4 + 3i}, expect: []complex64{1, 2 + 1i, 4 + 7i, -5 + 40i}, }, { dst: []complex64{0, 0, 0}, src: []complex64{1, 2 + 1i, 3 + 2i}, expect: []complex64{1, 2 + 1i, 4 + 7i}, }, { dst: []complex64{0, 0, 0, 0}, src: []complex64{1, 2 + 1i, 3 + 2i}, expect: []complex64{1, 2 + 1i, 4 + 7i}, }, { dst: []complex64{cnan, 1, cnan, 1, 0}, src: []complex64{1, 1, cnan, 1, 1}, expect: []complex64{1, 1, cnan, cnan, cnan}, }, { dst: []complex64{cnan, 4, cnan, cinf, 9}, src: []complex64{cinf, 4, cnan, cinf, 9}, expect: []complex64{cinf, cnan, cnan, cnan, cnan}, }, { dst: make([]complex64, 18), src: []complex64{2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i, 2i}, expect: []complex64{2i, -4, -8i, 16, 32i, -64, -128i, 256, 512i, -1024, -2048i, 4096, 8192i, -16384, -32768i, 65536}, }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] ret := CumProd(dst, src) for i := range v.expect { if !sameCmplx(ret[i], v.expect[i]) { t.Errorf("Test %d CumProd error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !sameCmplx(ret[i], dst[i]) { t.Errorf("Test %d CumProd ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestDiv(t *testing.T) { const tol = 1e-7 var src_gd, dst_gd complex64 = -1, 0.5 for j, v := range []struct { dst, src, expect []complex64 }{ { dst: []complex64{1 + 1i}, src: []complex64{1 + 1i}, expect: []complex64{1}, }, { dst: []complex64{cnan}, src: []complex64{cnan}, expect: []complex64{cnan}, }, { dst: []complex64{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i}, src: []complex64{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i}, expect: []complex64{1, 1, 1, 1}, }, { dst: []complex64{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i, 2 + 2i, 4 + 2i, 6 + 2i, 8 + 2i}, src: []complex64{1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i, 1 + 1i, 2 + 1i, 3 + 1i, 4 + 1i}, expect: []complex64{1, 1, 1, 1, 2, 2, 2, 2}, }, { dst: []complex64{2 + 2i, 4 + 8i, 6 - 12i}, src: []complex64{1 + 1i, 2 + 4i, 3 - 6i}, expect: []complex64{2, 2, 2}, }, { dst: []complex64{0, 0, 0, 0}, src: []complex64{1 + 1i, 2 + 2i, 3 + 3i}, expect: []complex64{0, 0, 0}, }, { dst: []complex64{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, src: []complex64{1, 1, cnan, 1, 1, 1, 1, cnan, 1, 1}, expect: []complex64{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, }, { dst: []complex64{cinf, 4, cnan, cinf, 9, cinf, 4, cnan, cinf, 9}, src: []complex64{cinf, 4, cnan, cinf, 3, cinf, 4, cnan, cinf, 3}, expect: []complex64{cnan, 1, cnan, cnan, 3, cnan, 1, cnan, cnan, 3}, }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] Div(dst, src) for i := range v.expect { if !sameCmplxApprox(dst[i], v.expect[i], tol) { t.Errorf("Test %d Div error at %d Got: %v Expected: %v", j, i, dst[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestDivTo(t *testing.T) { const tol = 1e-7 var dst_gd, x_gd, y_gd complex64 = -1, 0.5, 0.25 for j, v := range []struct { dst, x, y, expect []complex64 }{ { dst: []complex64{1 - 1i}, x: []complex64{1 + 1i}, y: []complex64{1 + 1i}, expect: []complex64{1}, }, { dst: []complex64{1}, x: []complex64{cnan}, y: []complex64{cnan}, expect: []complex64{cnan}, }, { dst: []complex64{-2, -2, -2}, x: []complex64{1 + 1i, 2 + 1i, 3 + 1i}, y: []complex64{1 + 1i, 2 + 1i, 3 + 1i}, expect: []complex64{1, 1, 1}, }, { dst: []complex64{0, 0, 0}, x: []complex64{2 + 2i, 4 + 4i, 6 + 6i}, y: []complex64{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}, expect: []complex64{2, 2, 2}, }, { dst: []complex64{-1, -1, -1}, x: []complex64{0, 0, 0}, y: []complex64{1 + 1i, 2 + 1i, 3 + 1i}, expect: []complex64{0, 0, 0}, }, { dst: []complex64{cinf, cinf, cinf, cinf, cinf, cinf, cinf, cinf, cinf, cinf}, x: []complex64{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, y: []complex64{1, 1, cnan, 1, 1, 1, 1, cnan, 1, 1}, expect: []complex64{cnan, 1, cnan, 1, 0, cnan, 1, cnan, 1, 0}, }, { dst: []complex64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, x: []complex64{cinf, 4, cnan, cinf, 9, cinf, 4, cnan, cinf, 9}, y: []complex64{cinf, 4, cnan, cinf, 3, cinf, 4, cnan, cinf, 3}, expect: []complex64{cnan, 1, cnan, cnan, 3, cnan, 1, cnan, cnan, 3}, }, } { xg_ln, yg_ln := 4+j%2, 4+j%3 v.y, v.x = guardVector(v.y, y_gd, yg_ln), guardVector(v.x, x_gd, xg_ln) y, x := v.y[yg_ln:len(v.y)-yg_ln], v.x[xg_ln:len(v.x)-xg_ln] v.dst = guardVector(v.dst, dst_gd, xg_ln) dst := v.dst[xg_ln : len(v.dst)-xg_ln] ret := DivTo(dst, x, y) for i := range v.expect { if !sameCmplxApprox(ret[i], v.expect[i], tol) { t.Errorf("Test %d DivTo error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !sameCmplxApprox(ret[i], dst[i], tol) { t.Errorf("Test %d DivTo ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.y, y_gd, yg_ln) { t.Errorf("Test %d Guard violated in y vector %v %v", j, v.y[:yg_ln], v.y[len(v.y)-yg_ln:]) } if !isValidGuard(v.x, x_gd, xg_ln) { t.Errorf("Test %d Guard violated in x vector %v %v", j, v.x[:xg_ln], v.x[len(v.x)-xg_ln:]) } if !isValidGuard(v.dst, dst_gd, xg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:xg_ln], v.dst[len(v.dst)-xg_ln:]) } } } var scalTests = []struct { alpha complex64 x []complex64 want []complex64 }{ { alpha: 0, x: []complex64{}, want: []complex64{}, }, { alpha: 1 + 1i, x: []complex64{1 + 2i}, want: []complex64{-1 + 3i}, }, { alpha: 2 + 3i, x: []complex64{1 + 2i}, want: []complex64{-4 + 7i}, }, { alpha: 2 - 4i, x: []complex64{1 + 2i}, want: []complex64{10}, }, { alpha: 2 + 8i, x: []complex64{1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i}, want: []complex64{-14 + 12i, -22 + 48i, -42 + 36i, -80 + 88i, 10 - 28i, -50 - 30i}, }, { alpha: 5 - 10i, x: []complex64{1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i, 1 + 2i, 5 + 4i, 3 + 6i, 8 + 12i, -3 - 2i, -5 + 5i}, want: []complex64{25, 65 - 30i, 75, 160 - 20i, -35 + 20i, 25 + 75i, 25, 65 - 30i, 75, 160 - 20i, -35 + 20i, 25 + 75i}, }, } func TestScalUnitary(t *testing.T) { const xGdVal = -0.5 for i, test := range scalTests { for _, align := range align1 { prefix := fmt.Sprintf("Test %v (x:%v)", i, align) xgLn := 4 + align xg := guardVector(test.x, xGdVal, xgLn) x := xg[xgLn : len(xg)-xgLn] ScalUnitary(test.alpha, x) for i := range test.want { if !sameCmplx(x[i], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i], test.want[i]) } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } } } } func TestScalInc(t *testing.T) { const xGdVal = -0.5 gdLn := 4 for i, test := range scalTests { n := len(test.x) for _, inc := range []int{1, 2, 3, 4, 7, 10} { prefix := fmt.Sprintf("Test %v (x:%v)", i, inc) xg := guardIncVector(test.x, xGdVal, inc, gdLn) x := xg[gdLn : len(xg)-gdLn] ScalInc(test.alpha, x, uintptr(n), uintptr(inc)) for i := range test.want { if !sameCmplx(x[i*inc], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i*inc], test.want[i]) } } checkValidIncGuard(t, xg, xGdVal, inc, gdLn) } } } func TestSum(t *testing.T) { var srcGd complex64 = -1 for j, v := range []struct { src []complex64 expect complex64 }{ { src: []complex64{}, expect: 0, }, { src: []complex64{1}, expect: 1, }, { src: []complex64{cnan}, expect: cnan, }, { src: []complex64{1 + 1i, 2 + 2i, 3 + 3i}, expect: 6 + 6i, }, { src: []complex64{1 + 1i, -4, 3 - 1i}, expect: 0, }, { src: []complex64{1 - 1i, 2 + 2i, 3 - 3i, 4 + 4i}, expect: 10 + 2i, }, { src: []complex64{1, 1, cnan, 1, 1}, expect: cnan, }, { src: []complex64{cinf, 4, cnan, cinf, 9}, expect: cnan, }, { src: []complex64{1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 9 + 9i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 5 + 5i, 1 + 1i}, expect: 29 + 29i, }, { src: []complex64{1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 9 + 9i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 5 + 5i, 11 + 11i, 1 + 1i, 1 + 1i, 1 + 1i, 9 + 9i, 1 + 1i, 1 + 1i, 1 + 1i, 2 + 2i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 1 + 1i, 5 + 5i, 1 + 1i}, expect: 67 + 67i, }, } { gdLn := 4 + j%2 gsrc := guardVector(v.src, srcGd, gdLn) src := gsrc[gdLn : len(gsrc)-gdLn] ret := Sum(src) if !sameCmplx(ret, v.expect) { t.Errorf("Test %d Sum error Got: %v Expected: %v", j, ret, v.expect) } if !isValidGuard(gsrc, srcGd, gdLn) { t.Errorf("Test %d Guard violated in src vector %v %v", j, gsrc[:gdLn], gsrc[len(gsrc)-gdLn:]) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/c64/util_test.go000066400000000000000000000047631450372207100232030ustar00rootroot00000000000000// 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 c64 import ( "testing" "gonum.org/v1/gonum/cmplxs/cscalar" ) func same(x, y complex64) bool { return cscalar.Same(complex128(x), complex128(y)) } func guardVector(vec []complex64, gdVal complex64, gdLen int) (guarded []complex64) { guarded = make([]complex64, len(vec)+gdLen*2) copy(guarded[gdLen:], vec) for i := 0; i < gdLen; i++ { guarded[i] = gdVal guarded[len(guarded)-1-i] = gdVal } return guarded } func isValidGuard(vec []complex64, gdVal complex64, gdLen int) bool { for i := 0; i < gdLen; i++ { if !same(vec[i], gdVal) || !same(vec[len(vec)-1-i], gdVal) { return false } } return true } func guardIncVector(vec []complex64, gdVal complex64, inc, gdLen int) (guarded []complex64) { if inc < 0 { inc = -inc } inrLen := len(vec) * inc guarded = make([]complex64, inrLen+gdLen*2) for i := range guarded { guarded[i] = gdVal } for i, v := range vec { guarded[gdLen+i*inc] = v } return guarded } func checkValidIncGuard(t *testing.T, vec []complex64, gdVal complex64, inc, gdLen int) { srcLen := len(vec) - 2*gdLen if inc < 0 { srcLen = len(vec) * -inc } for i := range vec { switch { case same(vec[i], gdVal): // Correct value case (i-gdLen)%inc == 0 && (i-gdLen)/inc < len(vec): // Ignore input values case i < gdLen: t.Errorf("Front guard violated at %d %v", i, vec[:gdLen]) case i > gdLen+srcLen: t.Errorf("Back guard violated at %d %v", i-gdLen-srcLen, vec[gdLen+srcLen:]) default: t.Errorf("Internal guard violated at %d %v", i-gdLen, vec[gdLen:gdLen+srcLen]) } } } var ( // Offset sets for testing alignment handling in Unitary assembly functions. align1 = []int{0, 1} align2 = newIncSet(0, 1) align3 = newIncToSet(0, 1) ) type incSet struct { x, y int } // genInc will generate all (x,y) combinations of the input increment set. func newIncSet(inc ...int) []incSet { n := len(inc) is := make([]incSet, n*n) for x := range inc { for y := range inc { is[x*n+y] = incSet{inc[x], inc[y]} } } return is } type incToSet struct { dst, x, y int } // genIncTo will generate all (dst,x,y) combinations of the input increment set. func newIncToSet(inc ...int) []incToSet { n := len(inc) is := make([]incToSet, n*n*n) for i, dst := range inc { for x := range inc { for y := range inc { is[i*n*n+x*n+y] = incToSet{dst, inc[x], inc[y]} } } } return is } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/000077500000000000000000000000001450372207100206245ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/asm/f32/axpyinc_amd64.s000066400000000000000000000044011450372207100234550ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func AxpyInc(alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) TEXT ·AxpyInc(SB), NOSPLIT, $0 MOVQ n+56(FP), CX // CX = n CMPQ CX, $0 // if n==0 { return } JLE axpyi_end MOVQ x_base+8(FP), SI // SI = &x MOVQ y_base+32(FP), DI // DI = &y MOVQ ix+80(FP), R8 // R8 = ix MOVQ iy+88(FP), R9 // R9 = iy LEAQ (SI)(R8*4), SI // SI = &(x[ix]) LEAQ (DI)(R9*4), DI // DI = &(y[iy]) MOVQ DI, DX // DX = DI Read Pointer for y MOVQ incX+64(FP), R8 // R8 = incX SHLQ $2, R8 // R8 *= sizeof(float32) MOVQ incY+72(FP), R9 // R9 = incY SHLQ $2, R9 // R9 *= sizeof(float32) MOVSS alpha+0(FP), X0 // X0 = alpha MOVSS X0, X1 // X1 = X0 // for pipelining MOVQ CX, BX ANDQ $3, BX // BX = n % 4 SHRQ $2, CX // CX = floor( n / 4 ) JZ axpyi_tail_start // if CX == 0 { goto axpyi_tail_start } axpyi_loop: // Loop unrolled 4x do { MOVSS (SI), X2 // X_i = x[i] MOVSS (SI)(R8*1), X3 LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) MOVSS (SI), X4 MOVSS (SI)(R8*1), X5 MULSS X1, X2 // X_i *= a MULSS X0, X3 MULSS X1, X4 MULSS X0, X5 ADDSS (DX), X2 // X_i += y[i] ADDSS (DX)(R9*1), X3 LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) ADDSS (DX), X4 ADDSS (DX)(R9*1), X5 MOVSS X2, (DI) // y[i] = X_i MOVSS X3, (DI)(R9*1) LEAQ (DI)(R9*2), DI // DI = &(DI[incY*2]) MOVSS X4, (DI) MOVSS X5, (DI)(R9*1) LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) // Increment addresses LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) LEAQ (DI)(R9*2), DI // DI = &(DI[incY*2]) LOOP axpyi_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE axpyi_end axpyi_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX axpyi_tail: // do { MOVSS (SI), X2 // X2 = x[i] MULSS X1, X2 // X2 *= a ADDSS (DI), X2 // X2 += y[i] MOVSS X2, (DI) // y[i] = X2 ADDQ R8, SI // SI = &(SI[incX]) ADDQ R9, DI // DI = &(DI[incY]) LOOP axpyi_tail // } while --CX > 0 axpyi_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/axpyincto_amd64.s000066400000000000000000000050631450372207100240250ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func AxpyIncTo(dst []float32, incDst, idst uintptr, alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) TEXT ·AxpyIncTo(SB), NOSPLIT, $0 MOVQ n+96(FP), CX // CX = n CMPQ CX, $0 // if n==0 { return } JLE axpyi_end MOVQ dst_base+0(FP), DI // DI = &dst MOVQ x_base+48(FP), SI // SI = &x MOVQ y_base+72(FP), DX // DX = &y MOVQ ix+120(FP), R8 // R8 = ix // Load the first index MOVQ iy+128(FP), R9 // R9 = iy MOVQ idst+32(FP), R10 // R10 = idst LEAQ (SI)(R8*4), SI // SI = &(x[ix]) LEAQ (DX)(R9*4), DX // DX = &(y[iy]) LEAQ (DI)(R10*4), DI // DI = &(dst[idst]) MOVQ incX+104(FP), R8 // R8 = incX SHLQ $2, R8 // R8 *= sizeof(float32) MOVQ incY+112(FP), R9 // R9 = incY SHLQ $2, R9 // R9 *= sizeof(float32) MOVQ incDst+24(FP), R10 // R10 = incDst SHLQ $2, R10 // R10 *= sizeof(float32) MOVSS alpha+40(FP), X0 // X0 = alpha MOVSS X0, X1 // X1 = X0 // for pipelining MOVQ CX, BX ANDQ $3, BX // BX = n % 4 SHRQ $2, CX // CX = floor( n / 4 ) JZ axpyi_tail_start // if CX == 0 { goto axpyi_tail_start } axpyi_loop: // Loop unrolled 4x do { MOVSS (SI), X2 // X_i = x[i] MOVSS (SI)(R8*1), X3 LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) MOVSS (SI), X4 MOVSS (SI)(R8*1), X5 MULSS X1, X2 // X_i *= a MULSS X0, X3 MULSS X1, X4 MULSS X0, X5 ADDSS (DX), X2 // X_i += y[i] ADDSS (DX)(R9*1), X3 LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) ADDSS (DX), X4 ADDSS (DX)(R9*1), X5 MOVSS X2, (DI) // dst[i] = X_i MOVSS X3, (DI)(R10*1) LEAQ (DI)(R10*2), DI // DI = &(DI[incDst*2]) MOVSS X4, (DI) MOVSS X5, (DI)(R10*1) LEAQ (SI)(R8*2), SI // SI = &(SI[incX*2]) // Increment addresses LEAQ (DX)(R9*2), DX // DX = &(DX[incY*2]) LEAQ (DI)(R10*2), DI // DI = &(DI[incDst*2]) LOOP axpyi_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE axpyi_end axpyi_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX axpyi_tail: // do { MOVSS (SI), X2 // X2 = x[i] MULSS X1, X2 // X2 *= a ADDSS (DX), X2 // X2 += y[i] MOVSS X2, (DI) // dst[i] = X2 ADDQ R8, SI // SI = &(SI[incX]) ADDQ R9, DX // DX = &(DX[incY]) ADDQ R10, DI // DI = &(DI[incY]) LOOP axpyi_tail // } while --CX > 0 axpyi_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/axpyunitary_amd64.s000066400000000000000000000056771450372207100244170ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func AxpyUnitary(alpha float32, x, y []float32) TEXT ·AxpyUnitary(SB), NOSPLIT, $0 MOVQ x_base+8(FP), SI // SI = &x MOVQ y_base+32(FP), DI // DI = &y MOVQ x_len+16(FP), BX // BX = min( len(x), len(y) ) CMPQ y_len+40(FP), BX CMOVQLE y_len+40(FP), BX CMPQ BX, $0 // if BX == 0 { return } JE axpy_end MOVSS alpha+0(FP), X0 SHUFPS $0, X0, X0 // X0 = { a, a, a, a } XORQ AX, AX // i = 0 PXOR X2, X2 // 2 NOP instructions (PXOR) to align PXOR X3, X3 // loop to cache line MOVQ DI, CX ANDQ $0xF, CX // Align on 16-byte boundary for ADDPS JZ axpy_no_trim // if CX == 0 { goto axpy_no_trim } XORQ $0xF, CX // CX = 4 - floor( BX % 16 / 4 ) INCQ CX SHRQ $2, CX axpy_align: // Trim first value(s) in unaligned buffer do { MOVSS (SI)(AX*4), X2 // X2 = x[i] MULSS X0, X2 // X2 *= a ADDSS (DI)(AX*4), X2 // X2 += y[i] MOVSS X2, (DI)(AX*4) // y[i] = X2 INCQ AX // i++ DECQ BX JZ axpy_end // if --BX == 0 { return } LOOP axpy_align // } while --CX > 0 axpy_no_trim: MOVUPS X0, X1 // Copy X0 to X1 for pipelining MOVQ BX, CX ANDQ $0xF, BX // BX = len % 16 SHRQ $4, CX // CX = int( len / 16 ) JZ axpy_tail4_start // if CX == 0 { return } axpy_loop: // Loop unrolled 16x do { MOVUPS (SI)(AX*4), X2 // X2 = x[i:i+4] MOVUPS 16(SI)(AX*4), X3 MOVUPS 32(SI)(AX*4), X4 MOVUPS 48(SI)(AX*4), X5 MULPS X0, X2 // X2 *= a MULPS X1, X3 MULPS X0, X4 MULPS X1, X5 ADDPS (DI)(AX*4), X2 // X2 += y[i:i+4] ADDPS 16(DI)(AX*4), X3 ADDPS 32(DI)(AX*4), X4 ADDPS 48(DI)(AX*4), X5 MOVUPS X2, (DI)(AX*4) // dst[i:i+4] = X2 MOVUPS X3, 16(DI)(AX*4) MOVUPS X4, 32(DI)(AX*4) MOVUPS X5, 48(DI)(AX*4) ADDQ $16, AX // i += 16 LOOP axpy_loop // while (--CX) > 0 CMPQ BX, $0 // if BX == 0 { return } JE axpy_end axpy_tail4_start: // Reset loop counter for 4-wide tail loop MOVQ BX, CX // CX = floor( BX / 4 ) SHRQ $2, CX JZ axpy_tail_start // if CX == 0 { goto axpy_tail_start } axpy_tail4: // Loop unrolled 4x do { MOVUPS (SI)(AX*4), X2 // X2 = x[i] MULPS X0, X2 // X2 *= a ADDPS (DI)(AX*4), X2 // X2 += y[i] MOVUPS X2, (DI)(AX*4) // y[i] = X2 ADDQ $4, AX // i += 4 LOOP axpy_tail4 // } while --CX > 0 axpy_tail_start: // Reset loop counter for 1-wide tail loop MOVQ BX, CX // CX = BX % 4 ANDQ $3, CX JZ axpy_end // if CX == 0 { return } axpy_tail: MOVSS (SI)(AX*4), X1 // X1 = x[i] MULSS X0, X1 // X1 *= a ADDSS (DI)(AX*4), X1 // X1 += y[i] MOVSS X1, (DI)(AX*4) // y[i] = X1 INCQ AX // i++ LOOP axpy_tail // } while --CX > 0 axpy_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/axpyunitaryto_amd64.s000066400000000000000000000057231450372207100247520ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func AxpyUnitaryTo(dst []float32, alpha float32, x, y []float32) TEXT ·AxpyUnitaryTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ x_base+32(FP), SI // SI = &x MOVQ y_base+56(FP), DX // DX = &y MOVQ x_len+40(FP), BX // BX = min( len(x), len(y), len(dst) ) CMPQ y_len+64(FP), BX CMOVQLE y_len+64(FP), BX CMPQ dst_len+8(FP), BX CMOVQLE dst_len+8(FP), BX CMPQ BX, $0 // if BX == 0 { return } JE axpy_end MOVSS alpha+24(FP), X0 SHUFPS $0, X0, X0 // X0 = { a, a, a, a, } XORQ AX, AX // i = 0 MOVQ DX, CX ANDQ $0xF, CX // Align on 16-byte boundary for ADDPS JZ axpy_no_trim // if CX == 0 { goto axpy_no_trim } XORQ $0xF, CX // CX = 4 - floor ( B % 16 / 4 ) INCQ CX SHRQ $2, CX axpy_align: // Trim first value(s) in unaligned buffer do { MOVSS (SI)(AX*4), X2 // X2 = x[i] MULSS X0, X2 // X2 *= a ADDSS (DX)(AX*4), X2 // X2 += y[i] MOVSS X2, (DI)(AX*4) // y[i] = X2 INCQ AX // i++ DECQ BX JZ axpy_end // if --BX == 0 { return } LOOP axpy_align // } while --CX > 0 axpy_no_trim: MOVUPS X0, X1 // Copy X0 to X1 for pipelining MOVQ BX, CX ANDQ $0xF, BX // BX = len % 16 SHRQ $4, CX // CX = floor( len / 16 ) JZ axpy_tail4_start // if CX == 0 { return } axpy_loop: // Loop unrolled 16x do { MOVUPS (SI)(AX*4), X2 // X2 = x[i:i+4] MOVUPS 16(SI)(AX*4), X3 MOVUPS 32(SI)(AX*4), X4 MOVUPS 48(SI)(AX*4), X5 MULPS X0, X2 // X2 *= a MULPS X1, X3 MULPS X0, X4 MULPS X1, X5 ADDPS (DX)(AX*4), X2 // X2 += y[i:i+4] ADDPS 16(DX)(AX*4), X3 ADDPS 32(DX)(AX*4), X4 ADDPS 48(DX)(AX*4), X5 MOVUPS X2, (DI)(AX*4) // dst[i:i+4] = X2 MOVUPS X3, 16(DI)(AX*4) MOVUPS X4, 32(DI)(AX*4) MOVUPS X5, 48(DI)(AX*4) ADDQ $16, AX // i += 16 LOOP axpy_loop // while (--CX) > 0 CMPQ BX, $0 // if BX == 0 { return } JE axpy_end axpy_tail4_start: // Reset loop counter for 4-wide tail loop MOVQ BX, CX // CX = floor( BX / 4 ) SHRQ $2, CX JZ axpy_tail_start // if CX == 0 { goto axpy_tail_start } axpy_tail4: // Loop unrolled 4x do { MOVUPS (SI)(AX*4), X2 // X2 = x[i] MULPS X0, X2 // X2 *= a ADDPS (DX)(AX*4), X2 // X2 += y[i] MOVUPS X2, (DI)(AX*4) // y[i] = X2 ADDQ $4, AX // i += 4 LOOP axpy_tail4 // } while --CX > 0 axpy_tail_start: // Reset loop counter for 1-wide tail loop MOVQ BX, CX // CX = BX % 4 ANDQ $3, CX JZ axpy_end // if CX == 0 { return } axpy_tail: MOVSS (SI)(AX*4), X1 // X1 = x[i] MULSS X0, X1 // X1 *= a ADDSS (DX)(AX*4), X1 // X1 += y[i] MOVSS X1, (DI)(AX*4) // y[i] = X1 INCQ AX // i++ LOOP axpy_tail // } while --CX > 0 axpy_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/benchDot_test.go000066400000000000000000000041341450372207100237420ustar00rootroot00000000000000// 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 f32 import ( "fmt" "testing" ) var ( benchSink float32 benchSink64 float64 ) func BenchmarkDotUnitary(t *testing.B) { const name = "DotUnitary" for _, v := range []int64{1, 2, 3, 4, 5, 10, 100, 1e3, 5e3, 1e4, 5e4} { t.Run(fmt.Sprintf("%s-%d", name, v), func(b *testing.B) { x, y := x[:v], y[:v] b.SetBytes(32 * v) for i := 0; i < b.N; i++ { benchSink = DotUnitary(x, y) } }) } } func BenchmarkDdotUnitary(t *testing.B) { const name = "DdotUnitary" for _, v := range []int64{1, 2, 3, 4, 5, 10, 100, 1e3, 5e3, 1e4, 5e4} { t.Run(fmt.Sprintf("%s-%d", name, v), func(b *testing.B) { x, y := x[:v], y[:v] b.SetBytes(32 * v) for i := 0; i < b.N; i++ { benchSink64 = DdotUnitary(x, y) } }) } } var incsDot = []struct { len int inc []int }{ {1, []int{1}}, {3, []int{1, 2, 4, 10}}, {10, []int{1, 2, 4, 10}}, {30, []int{1, 2, 4, 10}}, {1e2, []int{1, 2, 4, 10}}, {3e2, []int{1, 2, 4, 10}}, {1e3, []int{1, 2, 4, 10}}, {3e3, []int{1, 2, 4, 10}}, {1e4, []int{1, 2, 4, 10, -1, -2, -4, -10}}, } func BenchmarkDotInc(t *testing.B) { const name = "DotInc" for _, tt := range incsDot { for _, inc := range tt.inc { t.Run(fmt.Sprintf("%s-%d-inc(%d)", name, tt.len, inc), func(b *testing.B) { b.SetBytes(int64(32 * tt.len)) idx := 0 if inc < 0 { idx = (-tt.len + 1) * inc } for i := 0; i < b.N; i++ { benchSink = DotInc(x, y, uintptr(tt.len), uintptr(inc), uintptr(inc), uintptr(idx), uintptr(idx)) } }) } } } func BenchmarkDdotInc(t *testing.B) { const name = "DdotInc" for _, tt := range incsDot { for _, inc := range tt.inc { t.Run(fmt.Sprintf("%s-%d-inc(%d)", name, tt.len, inc), func(b *testing.B) { b.SetBytes(int64(32 * tt.len)) idx := 0 if inc < 0 { idx = (-tt.len + 1) * inc } for i := 0; i < b.N; i++ { benchSink64 = DdotInc(x, y, uintptr(tt.len), uintptr(inc), uintptr(inc), uintptr(idx), uintptr(idx)) } }) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/bench_test.go000066400000000000000000000400301450372207100232660ustar00rootroot00000000000000// Copyright ©2016 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 f32 import "testing" const ( benchLen = 1e5 a = 2 ) var ( x = make([]float32, benchLen) y = make([]float32, benchLen) z = make([]float32, benchLen) ) func init() { for n := range x { x[n] = float32(n) y[n] = float32(n) } } func benchaxpyu(t *testing.B, n int, f func(a float32, x, y []float32)) { x, y := x[:n], y[:n] for i := 0; i < t.N; i++ { f(a, x, y) } } func naiveaxpyu(a float32, x, y []float32) { for i, v := range x { y[i] += a * v } } func BenchmarkF32AxpyUnitary1(t *testing.B) { benchaxpyu(t, 1, AxpyUnitary) } func BenchmarkF32AxpyUnitary2(t *testing.B) { benchaxpyu(t, 2, AxpyUnitary) } func BenchmarkF32AxpyUnitary3(t *testing.B) { benchaxpyu(t, 3, AxpyUnitary) } func BenchmarkF32AxpyUnitary4(t *testing.B) { benchaxpyu(t, 4, AxpyUnitary) } func BenchmarkF32AxpyUnitary5(t *testing.B) { benchaxpyu(t, 5, AxpyUnitary) } func BenchmarkF32AxpyUnitary10(t *testing.B) { benchaxpyu(t, 10, AxpyUnitary) } func BenchmarkF32AxpyUnitary100(t *testing.B) { benchaxpyu(t, 100, AxpyUnitary) } func BenchmarkF32AxpyUnitary1000(t *testing.B) { benchaxpyu(t, 1000, AxpyUnitary) } func BenchmarkF32AxpyUnitary5000(t *testing.B) { benchaxpyu(t, 5000, AxpyUnitary) } func BenchmarkF32AxpyUnitary10000(t *testing.B) { benchaxpyu(t, 10000, AxpyUnitary) } func BenchmarkF32AxpyUnitary50000(t *testing.B) { benchaxpyu(t, 50000, AxpyUnitary) } func BenchmarkLF32AxpyUnitary1(t *testing.B) { benchaxpyu(t, 1, naiveaxpyu) } func BenchmarkLF32AxpyUnitary2(t *testing.B) { benchaxpyu(t, 2, naiveaxpyu) } func BenchmarkLF32AxpyUnitary3(t *testing.B) { benchaxpyu(t, 3, naiveaxpyu) } func BenchmarkLF32AxpyUnitary4(t *testing.B) { benchaxpyu(t, 4, naiveaxpyu) } func BenchmarkLF32AxpyUnitary5(t *testing.B) { benchaxpyu(t, 5, naiveaxpyu) } func BenchmarkLF32AxpyUnitary10(t *testing.B) { benchaxpyu(t, 10, naiveaxpyu) } func BenchmarkLF32AxpyUnitary100(t *testing.B) { benchaxpyu(t, 100, naiveaxpyu) } func BenchmarkLF32AxpyUnitary1000(t *testing.B) { benchaxpyu(t, 1000, naiveaxpyu) } func BenchmarkLF32AxpyUnitary5000(t *testing.B) { benchaxpyu(t, 5000, naiveaxpyu) } func BenchmarkLF32AxpyUnitary10000(t *testing.B) { benchaxpyu(t, 10000, naiveaxpyu) } func BenchmarkLF32AxpyUnitary50000(t *testing.B) { benchaxpyu(t, 50000, naiveaxpyu) } func benchaxpyut(t *testing.B, n int, f func(d []float32, a float32, x, y []float32)) { x, y, z := x[:n], y[:n], z[:n] for i := 0; i < t.N; i++ { f(z, a, x, y) } } func naiveaxpyut(d []float32, a float32, x, y []float32) { for i, v := range x { d[i] = y[i] + a*v } } func BenchmarkF32AxpyUnitaryTo1(t *testing.B) { benchaxpyut(t, 1, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo2(t *testing.B) { benchaxpyut(t, 2, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo3(t *testing.B) { benchaxpyut(t, 3, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo4(t *testing.B) { benchaxpyut(t, 4, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo5(t *testing.B) { benchaxpyut(t, 5, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo10(t *testing.B) { benchaxpyut(t, 10, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo100(t *testing.B) { benchaxpyut(t, 100, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo1000(t *testing.B) { benchaxpyut(t, 1000, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo5000(t *testing.B) { benchaxpyut(t, 5000, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo10000(t *testing.B) { benchaxpyut(t, 10000, AxpyUnitaryTo) } func BenchmarkF32AxpyUnitaryTo50000(t *testing.B) { benchaxpyut(t, 50000, AxpyUnitaryTo) } func BenchmarkLF32AxpyUnitaryTo1(t *testing.B) { benchaxpyut(t, 1, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo2(t *testing.B) { benchaxpyut(t, 2, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo3(t *testing.B) { benchaxpyut(t, 3, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo4(t *testing.B) { benchaxpyut(t, 4, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo5(t *testing.B) { benchaxpyut(t, 5, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo10(t *testing.B) { benchaxpyut(t, 10, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo100(t *testing.B) { benchaxpyut(t, 100, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo1000(t *testing.B) { benchaxpyut(t, 1000, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo5000(t *testing.B) { benchaxpyut(t, 5000, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo10000(t *testing.B) { benchaxpyut(t, 10000, naiveaxpyut) } func BenchmarkLF32AxpyUnitaryTo50000(t *testing.B) { benchaxpyut(t, 50000, naiveaxpyut) } func benchaxpyinc(t *testing.B, ln, t_inc int, f func(alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr)) { n, inc := uintptr(ln), uintptr(t_inc) var idx int if t_inc < 0 { idx = (-ln + 1) * t_inc } for i := 0; i < t.N; i++ { f(1, x, y, n, inc, inc, uintptr(idx), uintptr(idx)) } } func naiveaxpyinc(alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } func BenchmarkF32AxpyIncN1Inc1(b *testing.B) { benchaxpyinc(b, 1, 1, AxpyInc) } func BenchmarkF32AxpyIncN2Inc1(b *testing.B) { benchaxpyinc(b, 2, 1, AxpyInc) } func BenchmarkF32AxpyIncN2Inc2(b *testing.B) { benchaxpyinc(b, 2, 2, AxpyInc) } func BenchmarkF32AxpyIncN2Inc4(b *testing.B) { benchaxpyinc(b, 2, 4, AxpyInc) } func BenchmarkF32AxpyIncN2Inc10(b *testing.B) { benchaxpyinc(b, 2, 10, AxpyInc) } func BenchmarkF32AxpyIncN3Inc1(b *testing.B) { benchaxpyinc(b, 3, 1, AxpyInc) } func BenchmarkF32AxpyIncN3Inc2(b *testing.B) { benchaxpyinc(b, 3, 2, AxpyInc) } func BenchmarkF32AxpyIncN3Inc4(b *testing.B) { benchaxpyinc(b, 3, 4, AxpyInc) } func BenchmarkF32AxpyIncN3Inc10(b *testing.B) { benchaxpyinc(b, 3, 10, AxpyInc) } func BenchmarkF32AxpyIncN4Inc1(b *testing.B) { benchaxpyinc(b, 4, 1, AxpyInc) } func BenchmarkF32AxpyIncN4Inc2(b *testing.B) { benchaxpyinc(b, 4, 2, AxpyInc) } func BenchmarkF32AxpyIncN4Inc4(b *testing.B) { benchaxpyinc(b, 4, 4, AxpyInc) } func BenchmarkF32AxpyIncN4Inc10(b *testing.B) { benchaxpyinc(b, 4, 10, AxpyInc) } func BenchmarkF32AxpyIncN10Inc1(b *testing.B) { benchaxpyinc(b, 10, 1, AxpyInc) } func BenchmarkF32AxpyIncN10Inc2(b *testing.B) { benchaxpyinc(b, 10, 2, AxpyInc) } func BenchmarkF32AxpyIncN10Inc4(b *testing.B) { benchaxpyinc(b, 10, 4, AxpyInc) } func BenchmarkF32AxpyIncN10Inc10(b *testing.B) { benchaxpyinc(b, 10, 10, AxpyInc) } func BenchmarkF32AxpyIncN1000Inc1(b *testing.B) { benchaxpyinc(b, 1000, 1, AxpyInc) } func BenchmarkF32AxpyIncN1000Inc2(b *testing.B) { benchaxpyinc(b, 1000, 2, AxpyInc) } func BenchmarkF32AxpyIncN1000Inc4(b *testing.B) { benchaxpyinc(b, 1000, 4, AxpyInc) } func BenchmarkF32AxpyIncN1000Inc10(b *testing.B) { benchaxpyinc(b, 1000, 10, AxpyInc) } func BenchmarkF32AxpyIncN100000Inc1(b *testing.B) { benchaxpyinc(b, 100000, 1, AxpyInc) } func BenchmarkF32AxpyIncN100000Inc2(b *testing.B) { benchaxpyinc(b, 100000, 2, AxpyInc) } func BenchmarkF32AxpyIncN100000Inc4(b *testing.B) { benchaxpyinc(b, 100000, 4, AxpyInc) } func BenchmarkF32AxpyIncN100000Inc10(b *testing.B) { benchaxpyinc(b, 100000, 10, AxpyInc) } func BenchmarkF32AxpyIncN100000IncM1(b *testing.B) { benchaxpyinc(b, 100000, -1, AxpyInc) } func BenchmarkF32AxpyIncN100000IncM2(b *testing.B) { benchaxpyinc(b, 100000, -2, AxpyInc) } func BenchmarkF32AxpyIncN100000IncM4(b *testing.B) { benchaxpyinc(b, 100000, -4, AxpyInc) } func BenchmarkF32AxpyIncN100000IncM10(b *testing.B) { benchaxpyinc(b, 100000, -10, AxpyInc) } func BenchmarkLF32AxpyIncN1Inc1(b *testing.B) { benchaxpyinc(b, 1, 1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN2Inc1(b *testing.B) { benchaxpyinc(b, 2, 1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN2Inc2(b *testing.B) { benchaxpyinc(b, 2, 2, naiveaxpyinc) } func BenchmarkLF32AxpyIncN2Inc4(b *testing.B) { benchaxpyinc(b, 2, 4, naiveaxpyinc) } func BenchmarkLF32AxpyIncN2Inc10(b *testing.B) { benchaxpyinc(b, 2, 10, naiveaxpyinc) } func BenchmarkLF32AxpyIncN3Inc1(b *testing.B) { benchaxpyinc(b, 3, 1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN3Inc2(b *testing.B) { benchaxpyinc(b, 3, 2, naiveaxpyinc) } func BenchmarkLF32AxpyIncN3Inc4(b *testing.B) { benchaxpyinc(b, 3, 4, naiveaxpyinc) } func BenchmarkLF32AxpyIncN3Inc10(b *testing.B) { benchaxpyinc(b, 3, 10, naiveaxpyinc) } func BenchmarkLF32AxpyIncN4Inc1(b *testing.B) { benchaxpyinc(b, 4, 1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN4Inc2(b *testing.B) { benchaxpyinc(b, 4, 2, naiveaxpyinc) } func BenchmarkLF32AxpyIncN4Inc4(b *testing.B) { benchaxpyinc(b, 4, 4, naiveaxpyinc) } func BenchmarkLF32AxpyIncN4Inc10(b *testing.B) { benchaxpyinc(b, 4, 10, naiveaxpyinc) } func BenchmarkLF32AxpyIncN10Inc1(b *testing.B) { benchaxpyinc(b, 10, 1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN10Inc2(b *testing.B) { benchaxpyinc(b, 10, 2, naiveaxpyinc) } func BenchmarkLF32AxpyIncN10Inc4(b *testing.B) { benchaxpyinc(b, 10, 4, naiveaxpyinc) } func BenchmarkLF32AxpyIncN10Inc10(b *testing.B) { benchaxpyinc(b, 10, 10, naiveaxpyinc) } func BenchmarkLF32AxpyIncN1000Inc1(b *testing.B) { benchaxpyinc(b, 1000, 1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN1000Inc2(b *testing.B) { benchaxpyinc(b, 1000, 2, naiveaxpyinc) } func BenchmarkLF32AxpyIncN1000Inc4(b *testing.B) { benchaxpyinc(b, 1000, 4, naiveaxpyinc) } func BenchmarkLF32AxpyIncN1000Inc10(b *testing.B) { benchaxpyinc(b, 1000, 10, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000Inc1(b *testing.B) { benchaxpyinc(b, 100000, 1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000Inc2(b *testing.B) { benchaxpyinc(b, 100000, 2, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000Inc4(b *testing.B) { benchaxpyinc(b, 100000, 4, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000Inc10(b *testing.B) { benchaxpyinc(b, 100000, 10, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000IncM1(b *testing.B) { benchaxpyinc(b, 100000, -1, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000IncM2(b *testing.B) { benchaxpyinc(b, 100000, -2, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000IncM4(b *testing.B) { benchaxpyinc(b, 100000, -4, naiveaxpyinc) } func BenchmarkLF32AxpyIncN100000IncM10(b *testing.B) { benchaxpyinc(b, 100000, -10, naiveaxpyinc) } func benchaxpyincto(t *testing.B, ln, t_inc int, f func(dst []float32, incDst, idst uintptr, alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr)) { n, inc := uintptr(ln), uintptr(t_inc) var idx int if t_inc < 0 { idx = (-ln + 1) * t_inc } for i := 0; i < t.N; i++ { f(z, inc, uintptr(idx), 1, x, y, n, inc, inc, uintptr(idx), uintptr(idx)) } } func naiveaxpyincto(dst []float32, incDst, idst uintptr, alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } func BenchmarkF32AxpyIncToN1Inc1(b *testing.B) { benchaxpyincto(b, 1, 1, AxpyIncTo) } func BenchmarkF32AxpyIncToN2Inc1(b *testing.B) { benchaxpyincto(b, 2, 1, AxpyIncTo) } func BenchmarkF32AxpyIncToN2Inc2(b *testing.B) { benchaxpyincto(b, 2, 2, AxpyIncTo) } func BenchmarkF32AxpyIncToN2Inc4(b *testing.B) { benchaxpyincto(b, 2, 4, AxpyIncTo) } func BenchmarkF32AxpyIncToN2Inc10(b *testing.B) { benchaxpyincto(b, 2, 10, AxpyIncTo) } func BenchmarkF32AxpyIncToN3Inc1(b *testing.B) { benchaxpyincto(b, 3, 1, AxpyIncTo) } func BenchmarkF32AxpyIncToN3Inc2(b *testing.B) { benchaxpyincto(b, 3, 2, AxpyIncTo) } func BenchmarkF32AxpyIncToN3Inc4(b *testing.B) { benchaxpyincto(b, 3, 4, AxpyIncTo) } func BenchmarkF32AxpyIncToN3Inc10(b *testing.B) { benchaxpyincto(b, 3, 10, AxpyIncTo) } func BenchmarkF32AxpyIncToN4Inc1(b *testing.B) { benchaxpyincto(b, 4, 1, AxpyIncTo) } func BenchmarkF32AxpyIncToN4Inc2(b *testing.B) { benchaxpyincto(b, 4, 2, AxpyIncTo) } func BenchmarkF32AxpyIncToN4Inc4(b *testing.B) { benchaxpyincto(b, 4, 4, AxpyIncTo) } func BenchmarkF32AxpyIncToN4Inc10(b *testing.B) { benchaxpyincto(b, 4, 10, AxpyIncTo) } func BenchmarkF32AxpyIncToN10Inc1(b *testing.B) { benchaxpyincto(b, 10, 1, AxpyIncTo) } func BenchmarkF32AxpyIncToN10Inc2(b *testing.B) { benchaxpyincto(b, 10, 2, AxpyIncTo) } func BenchmarkF32AxpyIncToN10Inc4(b *testing.B) { benchaxpyincto(b, 10, 4, AxpyIncTo) } func BenchmarkF32AxpyIncToN10Inc10(b *testing.B) { benchaxpyincto(b, 10, 10, AxpyIncTo) } func BenchmarkF32AxpyIncToN1000Inc1(b *testing.B) { benchaxpyincto(b, 1000, 1, AxpyIncTo) } func BenchmarkF32AxpyIncToN1000Inc2(b *testing.B) { benchaxpyincto(b, 1000, 2, AxpyIncTo) } func BenchmarkF32AxpyIncToN1000Inc4(b *testing.B) { benchaxpyincto(b, 1000, 4, AxpyIncTo) } func BenchmarkF32AxpyIncToN1000Inc10(b *testing.B) { benchaxpyincto(b, 1000, 10, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000Inc1(b *testing.B) { benchaxpyincto(b, 100000, 1, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000Inc2(b *testing.B) { benchaxpyincto(b, 100000, 2, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000Inc4(b *testing.B) { benchaxpyincto(b, 100000, 4, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000Inc10(b *testing.B) { benchaxpyincto(b, 100000, 10, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000IncM1(b *testing.B) { benchaxpyincto(b, 100000, -1, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000IncM2(b *testing.B) { benchaxpyincto(b, 100000, -2, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000IncM4(b *testing.B) { benchaxpyincto(b, 100000, -4, AxpyIncTo) } func BenchmarkF32AxpyIncToN100000IncM10(b *testing.B) { benchaxpyincto(b, 100000, -10, AxpyIncTo) } func BenchmarkLF32AxpyIncToN1Inc1(b *testing.B) { benchaxpyincto(b, 1, 1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN2Inc1(b *testing.B) { benchaxpyincto(b, 2, 1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN2Inc2(b *testing.B) { benchaxpyincto(b, 2, 2, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN2Inc4(b *testing.B) { benchaxpyincto(b, 2, 4, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN2Inc10(b *testing.B) { benchaxpyincto(b, 2, 10, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN3Inc1(b *testing.B) { benchaxpyincto(b, 3, 1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN3Inc2(b *testing.B) { benchaxpyincto(b, 3, 2, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN3Inc4(b *testing.B) { benchaxpyincto(b, 3, 4, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN3Inc10(b *testing.B) { benchaxpyincto(b, 3, 10, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN4Inc1(b *testing.B) { benchaxpyincto(b, 4, 1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN4Inc2(b *testing.B) { benchaxpyincto(b, 4, 2, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN4Inc4(b *testing.B) { benchaxpyincto(b, 4, 4, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN4Inc10(b *testing.B) { benchaxpyincto(b, 4, 10, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN10Inc1(b *testing.B) { benchaxpyincto(b, 10, 1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN10Inc2(b *testing.B) { benchaxpyincto(b, 10, 2, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN10Inc4(b *testing.B) { benchaxpyincto(b, 10, 4, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN10Inc10(b *testing.B) { benchaxpyincto(b, 10, 10, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN1000Inc1(b *testing.B) { benchaxpyincto(b, 1000, 1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN1000Inc2(b *testing.B) { benchaxpyincto(b, 1000, 2, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN1000Inc4(b *testing.B) { benchaxpyincto(b, 1000, 4, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN1000Inc10(b *testing.B) { benchaxpyincto(b, 1000, 10, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000Inc1(b *testing.B) { benchaxpyincto(b, 100000, 1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000Inc2(b *testing.B) { benchaxpyincto(b, 100000, 2, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000Inc4(b *testing.B) { benchaxpyincto(b, 100000, 4, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000Inc10(b *testing.B) { benchaxpyincto(b, 100000, 10, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000IncM1(b *testing.B) { benchaxpyincto(b, 100000, -1, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000IncM2(b *testing.B) { benchaxpyincto(b, 100000, -2, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000IncM4(b *testing.B) { benchaxpyincto(b, 100000, -4, naiveaxpyincto) } func BenchmarkLF32AxpyIncToN100000IncM10(b *testing.B) { benchaxpyincto(b, 100000, -10, naiveaxpyincto) } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/ddotinc_amd64.s000066400000000000000000000045721450372207100234370ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define INC_X R8 #define INCx3_X R10 #define INC_Y R9 #define INCx3_Y R11 #define SUM X0 #define P_SUM X1 // func DdotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float64) TEXT ·DdotInc(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y MOVQ n+48(FP), LEN // LEN = n PXOR SUM, SUM // SUM = 0 CMPQ LEN, $0 JE dot_end MOVQ ix+72(FP), INC_X // INC_X = ix MOVQ iy+80(FP), INC_Y // INC_Y = iy LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(x[ix]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(y[iy]) MOVQ incX+56(FP), INC_X // INC_X = incX * sizeof(float32) SHLQ $2, INC_X MOVQ incY+64(FP), INC_Y // INC_Y = incY * sizeof(float32) SHLQ $2, INC_Y MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = LEN % 4 SHRQ $2, LEN // LEN = floor( LEN / 4 ) JZ dot_tail // if LEN == 0 { goto dot_tail } PXOR P_SUM, P_SUM // P_SUM = 0 for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = INC_Y * 3 dot_loop: // Loop unrolled 4x do { CVTSS2SD (X_PTR), X2 // X_i = x[i:i+1] CVTSS2SD (X_PTR)(INC_X*1), X3 CVTSS2SD (X_PTR)(INC_X*2), X4 CVTSS2SD (X_PTR)(INCx3_X*1), X5 CVTSS2SD (Y_PTR), X6 // X_j = y[i:i+1] CVTSS2SD (Y_PTR)(INC_Y*1), X7 CVTSS2SD (Y_PTR)(INC_Y*2), X8 CVTSS2SD (Y_PTR)(INCx3_Y*1), X9 MULSD X6, X2 // X_i *= X_j MULSD X7, X3 MULSD X8, X4 MULSD X9, X5 ADDSD X2, SUM // SUM += X_i ADDSD X3, P_SUM ADDSD X4, SUM ADDSD X5, P_SUM LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[INC_X * 4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[INC_Y * 4]) DECQ LEN JNZ dot_loop // } while --LEN > 0 ADDSD P_SUM, SUM // SUM += P_SUM CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail: // do { CVTSS2SD (X_PTR), X2 // X2 = x[i] CVTSS2SD (Y_PTR), X3 // X2 *= y[i] MULSD X3, X2 ADDSD X2, SUM // SUM += X2 ADDQ INC_X, X_PTR // X_PTR += INC_X ADDQ INC_Y, Y_PTR // Y_PTR += INC_Y DECQ TAIL JNZ dot_tail // } while --TAIL > 0 dot_end: MOVSD SUM, sum+88(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/ddotunitary_amd64.s000066400000000000000000000054761450372207100243650ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define HADDPD_SUM_SUM LONG $0xC07C0F66 // @ HADDPD X0, X0 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define IDX AX #define SUM X0 #define P_SUM X1 // func DdotUnitary(x, y []float32) (sum float32) TEXT ·DdotUnitary(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y MOVQ x_len+8(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+32(FP), LEN CMOVQLE y_len+32(FP), LEN PXOR SUM, SUM // psum = 0 CMPQ LEN, $0 JE dot_end XORQ IDX, IDX MOVQ Y_PTR, DX ANDQ $0xF, DX // Align on 16-byte boundary for ADDPS JZ dot_no_trim // if DX == 0 { goto dot_no_trim } SUBQ $16, DX dot_align: // Trim first value(s) in unaligned buffer do { CVTSS2SD (X_PTR)(IDX*4), X2 // X2 = float64(x[i]) CVTSS2SD (Y_PTR)(IDX*4), X3 // X3 = float64(y[i]) MULSD X3, X2 ADDSD X2, SUM // SUM += X2 INCQ IDX // IDX++ DECQ LEN JZ dot_end // if --TAIL == 0 { return } ADDQ $4, DX JNZ dot_align // } while --LEN > 0 dot_no_trim: PXOR P_SUM, P_SUM // P_SUM = 0 for pipelining MOVQ LEN, TAIL ANDQ $0x7, TAIL // TAIL = LEN % 8 SHRQ $3, LEN // LEN = floor( LEN / 8 ) JZ dot_tail_start // if LEN == 0 { goto dot_tail_start } dot_loop: // Loop unrolled 8x do { CVTPS2PD (X_PTR)(IDX*4), X2 // X_i = x[i:i+1] CVTPS2PD 8(X_PTR)(IDX*4), X3 CVTPS2PD 16(X_PTR)(IDX*4), X4 CVTPS2PD 24(X_PTR)(IDX*4), X5 CVTPS2PD (Y_PTR)(IDX*4), X6 // X_j = y[i:i+1] CVTPS2PD 8(Y_PTR)(IDX*4), X7 CVTPS2PD 16(Y_PTR)(IDX*4), X8 CVTPS2PD 24(Y_PTR)(IDX*4), X9 MULPD X6, X2 // X_i *= X_j MULPD X7, X3 MULPD X8, X4 MULPD X9, X5 ADDPD X2, SUM // SUM += X_i ADDPD X3, P_SUM ADDPD X4, SUM ADDPD X5, P_SUM ADDQ $8, IDX // IDX += 8 DECQ LEN JNZ dot_loop // } while --LEN > 0 ADDPD P_SUM, SUM // SUM += P_SUM CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail_start: MOVQ TAIL, LEN SHRQ $1, LEN JZ dot_tail_one dot_tail_two: CVTPS2PD (X_PTR)(IDX*4), X2 // X_i = x[i:i+1] CVTPS2PD (Y_PTR)(IDX*4), X6 // X_j = y[i:i+1] MULPD X6, X2 // X_i *= X_j ADDPD X2, SUM // SUM += X_i ADDQ $2, IDX // IDX += 2 DECQ LEN JNZ dot_tail_two // } while --LEN > 0 ANDQ $1, TAIL JZ dot_end dot_tail_one: CVTSS2SD (X_PTR)(IDX*4), X2 // X2 = float64(x[i]) CVTSS2SD (Y_PTR)(IDX*4), X3 // X3 = float64(y[i]) MULSD X3, X2 // X2 *= X3 ADDSD X2, SUM // SUM += X2 dot_end: HADDPD_SUM_SUM // SUM = \sum{ SUM[i] } MOVSD SUM, sum+48(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/doc.go000066400000000000000000000004241450372207100217200ustar00rootroot00000000000000// 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 f32 provides float32 vector primitives. package f32 // import "gonum.org/v1/gonum/internal/asm/f32" golang-gonum-v1-gonum-0.14.0/internal/asm/f32/dot_test.go000066400000000000000000000113571450372207100230070ustar00rootroot00000000000000// 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 f32_test import ( "fmt" "math" "testing" "gonum.org/v1/gonum/floats/scalar" . "gonum.org/v1/gonum/internal/asm/f32" ) var dotTests = []struct { x, y []float32 sWant float32 // single-precision dWant float64 // double-precision sWantRev float32 // single-precision increment dWantRev float64 // double-precision increment n int ix, iy int }{ { // 0 x: []float32{}, y: []float32{}, n: 0, sWant: 0, dWant: 0, sWantRev: 0, dWantRev: 0, ix: 0, iy: 0, }, { // 1 x: []float32{0}, y: []float32{0}, n: 1, sWant: 0, dWant: 0, sWantRev: 0, dWantRev: 0, ix: 0, iy: 0, }, { // 2 x: []float32{1}, y: []float32{1}, n: 1, sWant: 1, dWant: 1, sWantRev: 1, dWantRev: 1, ix: 0, iy: 0, }, { // 3 x: []float32{1, 2, 3, 4, 5, 6, 7, 8}, y: []float32{2, 2, 2, 2, 2, 2, 2, 2}, n: 8, sWant: 72, dWant: 72, sWantRev: 72, dWantRev: 72, ix: 1, iy: 1, }, { // 4 x: []float32{math.MaxFloat32}, y: []float32{2}, n: 1, sWant: inf, dWant: 2 * float64(math.MaxFloat32), sWantRev: inf, dWantRev: 2 * float64(math.MaxFloat32), ix: 0, iy: 0, }, { // 5 x: []float32{1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2}, y: []float32{3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2}, n: 20, sWant: 70, dWant: 70, sWantRev: 80, dWantRev: 80, ix: 0, iy: 0, }, } func TestDotUnitary(t *testing.T) { const xGdVal, yGdVal = 0.5, 0.25 for i, test := range dotTests { for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, align.x, align.y) xgLn, ygLn := 8+align.x, 8+align.y xg, yg := guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] res := DotUnitary(x, y) if !same(res, test.sWant) { t.Errorf(msgRes, prefix, res, test.sWant) } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, yGdVal, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } } } } func TestDotInc(t *testing.T) { const xGdVal, yGdVal, gdLn = 0.5, 0.25, 8 for i, test := range dotTests { for _, inc := range newIncSet(1, 2, 3, 4, 7, 10, -1, -2, -5, -10) { xg, yg := guardIncVector(test.x, xGdVal, inc.x, gdLn), guardIncVector(test.y, yGdVal, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] want := test.sWant var ix, iy int if inc.x < 0 { ix = -inc.x * (test.n - 1) } if inc.y < 0 { iy = -inc.y * (test.n - 1) } if inc.x*inc.y < 0 { want = test.sWantRev } prefix := fmt.Sprintf("Test %v (x:%v y:%v) (ix:%v iy:%v)", i, inc.x, inc.y, ix, iy) res := DotInc(x, y, uintptr(test.n), uintptr(inc.x), uintptr(inc.y), uintptr(ix), uintptr(iy)) if !same(res, want) { t.Errorf(msgRes, prefix, res, want) } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) } } } func TestDdotUnitary(t *testing.T) { const xGdVal, yGdVal = 0.5, 0.25 for i, test := range dotTests { for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, align.x, align.y) xgLn, ygLn := 8+align.x, 8+align.y xg, yg := guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] res := DdotUnitary(x, y) if !scalar.Same(res, test.dWant) { t.Errorf(msgRes, prefix, res, test.dWant) } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, yGdVal, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } } } } func TestDdotInc(t *testing.T) { const xGdVal, yGdVal, gdLn = 0.5, 0.25, 8 for i, test := range dotTests { for _, inc := range newIncSet(1, 2, 3, 4, 7, 10, -1, -2, -5, -10) { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, inc.x, inc.y) xg, yg := guardIncVector(test.x, xGdVal, inc.x, gdLn), guardIncVector(test.y, yGdVal, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] want := test.dWant var ix, iy int if inc.x < 0 { ix = -inc.x * (test.n - 1) } if inc.y < 0 { iy = -inc.y * (test.n - 1) } if inc.x*inc.y < 0 { want = test.dWantRev } res := DdotInc(x, y, uintptr(test.n), uintptr(inc.x), uintptr(inc.y), uintptr(ix), uintptr(iy)) if !scalar.Same(res, want) { t.Errorf(msgRes, prefix, res, want) } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/dotinc_amd64.s000066400000000000000000000043711450372207100232700ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define INC_X R8 #define INCx3_X R10 #define INC_Y R9 #define INCx3_Y R11 #define SUM X0 #define P_SUM X1 // func DotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float32) TEXT ·DotInc(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y PXOR SUM, SUM // SUM = 0 MOVQ n+48(FP), LEN // LEN = n CMPQ LEN, $0 JE dot_end MOVQ ix+72(FP), INC_X // INC_X = ix MOVQ iy+80(FP), INC_Y // INC_Y = iy LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(x[ix]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(y[iy]) MOVQ incX+56(FP), INC_X // INC_X := incX * sizeof(float32) SHLQ $2, INC_X MOVQ incY+64(FP), INC_Y // INC_Y := incY * sizeof(float32) SHLQ $2, INC_Y MOVQ LEN, TAIL ANDQ $0x3, TAIL // TAIL = LEN % 4 SHRQ $2, LEN // LEN = floor( LEN / 4 ) JZ dot_tail // if LEN == 0 { goto dot_tail } PXOR P_SUM, P_SUM // P_SUM = 0 for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = INC_Y * 3 dot_loop: // Loop unrolled 4x do { MOVSS (X_PTR), X2 // X_i = x[i:i+1] MOVSS (X_PTR)(INC_X*1), X3 MOVSS (X_PTR)(INC_X*2), X4 MOVSS (X_PTR)(INCx3_X*1), X5 MULSS (Y_PTR), X2 // X_i *= y[i:i+1] MULSS (Y_PTR)(INC_Y*1), X3 MULSS (Y_PTR)(INC_Y*2), X4 MULSS (Y_PTR)(INCx3_Y*1), X5 ADDSS X2, SUM // SUM += X_i ADDSS X3, P_SUM ADDSS X4, SUM ADDSS X5, P_SUM LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[INC_X * 4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[INC_Y * 4]) DECQ LEN JNZ dot_loop // } while --LEN > 0 ADDSS P_SUM, SUM // P_SUM += SUM CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail: // do { MOVSS (X_PTR), X2 // X2 = x[i] MULSS (Y_PTR), X2 // X2 *= y[i] ADDSS X2, SUM // SUM += X2 ADDQ INC_X, X_PTR // X_PTR += INC_X ADDQ INC_Y, Y_PTR // Y_PTR += INC_Y DECQ TAIL JNZ dot_tail // } while --TAIL > 0 dot_end: MOVSS SUM, sum+88(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/dotunitary_amd64.s000066400000000000000000000056441450372207100242160ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define HADDPS_SUM_SUM LONG $0xC07C0FF2 // @ HADDPS X0, X0 #define X_PTR SI #define Y_PTR DI #define LEN CX #define TAIL BX #define IDX AX #define SUM X0 #define P_SUM X1 // func DotUnitary(x, y []float32) (sum float32) TEXT ·DotUnitary(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ y_base+24(FP), Y_PTR // Y_PTR = &y PXOR SUM, SUM // SUM = 0 MOVQ x_len+8(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+32(FP), LEN CMOVQLE y_len+32(FP), LEN CMPQ LEN, $0 JE dot_end XORQ IDX, IDX MOVQ Y_PTR, DX ANDQ $0xF, DX // Align on 16-byte boundary for MULPS JZ dot_no_trim // if DX == 0 { goto dot_no_trim } SUBQ $16, DX dot_align: // Trim first value(s) in unaligned buffer do { MOVSS (X_PTR)(IDX*4), X2 // X2 = x[i] MULSS (Y_PTR)(IDX*4), X2 // X2 *= y[i] ADDSS X2, SUM // SUM += X2 INCQ IDX // IDX++ DECQ LEN JZ dot_end // if --TAIL == 0 { return } ADDQ $4, DX JNZ dot_align // } while --DX > 0 dot_no_trim: PXOR P_SUM, P_SUM // P_SUM = 0 for pipelining MOVQ LEN, TAIL ANDQ $0xF, TAIL // TAIL = LEN % 16 SHRQ $4, LEN // LEN = floor( LEN / 16 ) JZ dot_tail4_start // if LEN == 0 { goto dot_tail4_start } dot_loop: // Loop unrolled 16x do { MOVUPS (X_PTR)(IDX*4), X2 // X_i = x[i:i+1] MOVUPS 16(X_PTR)(IDX*4), X3 MOVUPS 32(X_PTR)(IDX*4), X4 MOVUPS 48(X_PTR)(IDX*4), X5 MULPS (Y_PTR)(IDX*4), X2 // X_i *= y[i:i+1] MULPS 16(Y_PTR)(IDX*4), X3 MULPS 32(Y_PTR)(IDX*4), X4 MULPS 48(Y_PTR)(IDX*4), X5 ADDPS X2, SUM // SUM += X_i ADDPS X3, P_SUM ADDPS X4, SUM ADDPS X5, P_SUM ADDQ $16, IDX // IDX += 16 DECQ LEN JNZ dot_loop // } while --LEN > 0 ADDPS P_SUM, SUM // SUM += P_SUM CMPQ TAIL, $0 // if TAIL == 0 { return } JE dot_end dot_tail4_start: // Reset loop counter for 4-wide tail loop MOVQ TAIL, LEN // LEN = floor( TAIL / 4 ) SHRQ $2, LEN JZ dot_tail_start // if LEN == 0 { goto dot_tail_start } dot_tail4_loop: // Loop unrolled 4x do { MOVUPS (X_PTR)(IDX*4), X2 // X_i = x[i:i+1] MULPS (Y_PTR)(IDX*4), X2 // X_i *= y[i:i+1] ADDPS X2, SUM // SUM += X_i ADDQ $4, IDX // i += 4 DECQ LEN JNZ dot_tail4_loop // } while --LEN > 0 dot_tail_start: // Reset loop counter for 1-wide tail loop ANDQ $3, TAIL // TAIL = TAIL % 4 JZ dot_end // if TAIL == 0 { return } dot_tail: // do { MOVSS (X_PTR)(IDX*4), X2 // X2 = x[i] MULSS (Y_PTR)(IDX*4), X2 // X2 *= y[i] ADDSS X2, SUM // psum += X2 INCQ IDX // IDX++ DECQ TAIL JNZ dot_tail // } while --TAIL > 0 dot_end: HADDPS_SUM_SUM // SUM = \sum{ SUM[i] } HADDPS_SUM_SUM MOVSS SUM, sum+48(FP) // return SUM RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/ge_amd64.go000066400000000000000000000010051450372207100225350ustar00rootroot00000000000000// 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. //go:build !noasm && !gccgo && !safe // +build !noasm,!gccgo,!safe package f32 // Ger performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar. func Ger(m, n uintptr, alpha float32, x []float32, incX uintptr, y []float32, incY uintptr, a []float32, lda uintptr) golang-gonum-v1-gonum-0.14.0/internal/asm/f32/ge_amd64.s000066400000000000000000000315351450372207100224050ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SIZE 4 #define BITSIZE 2 #define KERNELSIZE 3 #define M_DIM m+0(FP) #define M CX #define N_DIM n+8(FP) #define N BX #define TMP1 R14 #define TMP2 R15 #define X_PTR SI #define Y y_base+56(FP) #define Y_PTR DX #define A_ROW AX #define A_PTR DI #define INC_X R8 #define INC3_X R9 #define INC_Y R10 #define INC3_Y R11 #define LDA R12 #define LDA3 R13 #define ALPHA X0 #define ALPHA_SPILL al-16(SP) #define LOAD_ALPHA \ MOVSS alpha+16(FP), ALPHA \ SHUFPS $0, ALPHA, ALPHA #define LOAD_SCALED4 \ PREFETCHNTA 16*SIZE(X_PTR) \ MOVDDUP (X_PTR), X1 \ MOVDDUP 2*SIZE(X_PTR), X3 \ MOVSHDUP X1, X2 \ MOVSHDUP X3, X4 \ MOVSLDUP X1, X1 \ MOVSLDUP X3, X3 \ MULPS ALPHA, X1 \ MULPS ALPHA, X2 \ MULPS ALPHA, X3 \ MULPS ALPHA, X4 #define LOAD_SCALED2 \ MOVDDUP (X_PTR), X1 \ MOVSHDUP X1, X2 \ MOVSLDUP X1, X1 \ MULPS ALPHA, X1 \ MULPS ALPHA, X2 #define LOAD_SCALED1 \ MOVSS (X_PTR), X1 \ SHUFPS $0, X1, X1 \ MULPS ALPHA, X1 #define LOAD_SCALED4_INC \ PREFETCHNTA (X_PTR)(INC_X*8) \ MOVSS (X_PTR), X1 \ MOVSS (X_PTR)(INC_X*1), X2 \ MOVSS (X_PTR)(INC_X*2), X3 \ MOVSS (X_PTR)(INC3_X*1), X4 \ SHUFPS $0, X1, X1 \ SHUFPS $0, X2, X2 \ SHUFPS $0, X3, X3 \ SHUFPS $0, X4, X4 \ MULPS ALPHA, X1 \ MULPS ALPHA, X2 \ MULPS ALPHA, X3 \ MULPS ALPHA, X4 #define LOAD_SCALED2_INC \ MOVSS (X_PTR), X1 \ MOVSS (X_PTR)(INC_X*1), X2 \ SHUFPS $0, X1, X1 \ SHUFPS $0, X2, X2 \ MULPS ALPHA, X1 \ MULPS ALPHA, X2 #define KERNEL_LOAD8 \ MOVUPS (Y_PTR), X5 \ MOVUPS 4*SIZE(Y_PTR), X6 #define KERNEL_LOAD8_INC \ MOVSS (Y_PTR), X5 \ MOVSS (Y_PTR)(INC_Y*1), X6 \ MOVSS (Y_PTR)(INC_Y*2), X7 \ MOVSS (Y_PTR)(INC3_Y*1), X8 \ UNPCKLPS X6, X5 \ UNPCKLPS X8, X7 \ MOVLHPS X7, X5 \ LEAQ (Y_PTR)(INC_Y*4), Y_PTR \ MOVSS (Y_PTR), X6 \ MOVSS (Y_PTR)(INC_Y*1), X7 \ MOVSS (Y_PTR)(INC_Y*2), X8 \ MOVSS (Y_PTR)(INC3_Y*1), X9 \ UNPCKLPS X7, X6 \ UNPCKLPS X9, X8 \ MOVLHPS X8, X6 #define KERNEL_LOAD4 \ MOVUPS (Y_PTR), X5 #define KERNEL_LOAD4_INC \ MOVSS (Y_PTR), X5 \ MOVSS (Y_PTR)(INC_Y*1), X6 \ MOVSS (Y_PTR)(INC_Y*2), X7 \ MOVSS (Y_PTR)(INC3_Y*1), X8 \ UNPCKLPS X6, X5 \ UNPCKLPS X8, X7 \ MOVLHPS X7, X5 #define KERNEL_LOAD2 \ MOVSD (Y_PTR), X5 #define KERNEL_LOAD2_INC \ MOVSS (Y_PTR), X5 \ MOVSS (Y_PTR)(INC_Y*1), X6 \ UNPCKLPS X6, X5 #define KERNEL_4x8 \ MOVUPS X5, X7 \ MOVUPS X6, X8 \ MOVUPS X5, X9 \ MOVUPS X6, X10 \ MOVUPS X5, X11 \ MOVUPS X6, X12 \ MULPS X1, X5 \ MULPS X1, X6 \ MULPS X2, X7 \ MULPS X2, X8 \ MULPS X3, X9 \ MULPS X3, X10 \ MULPS X4, X11 \ MULPS X4, X12 #define STORE_4x8 \ MOVUPS ALPHA, ALPHA_SPILL \ MOVUPS (A_PTR), X13 \ ADDPS X13, X5 \ MOVUPS 4*SIZE(A_PTR), X14 \ ADDPS X14, X6 \ MOVUPS (A_PTR)(LDA*1), X15 \ ADDPS X15, X7 \ MOVUPS 4*SIZE(A_PTR)(LDA*1), X0 \ ADDPS X0, X8 \ MOVUPS (A_PTR)(LDA*2), X13 \ ADDPS X13, X9 \ MOVUPS 4*SIZE(A_PTR)(LDA*2), X14 \ ADDPS X14, X10 \ MOVUPS (A_PTR)(LDA3*1), X15 \ ADDPS X15, X11 \ MOVUPS 4*SIZE(A_PTR)(LDA3*1), X0 \ ADDPS X0, X12 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, 4*SIZE(A_PTR) \ MOVUPS X7, (A_PTR)(LDA*1) \ MOVUPS X8, 4*SIZE(A_PTR)(LDA*1) \ MOVUPS X9, (A_PTR)(LDA*2) \ MOVUPS X10, 4*SIZE(A_PTR)(LDA*2) \ MOVUPS X11, (A_PTR)(LDA3*1) \ MOVUPS X12, 4*SIZE(A_PTR)(LDA3*1) \ MOVUPS ALPHA_SPILL, ALPHA \ ADDQ $8*SIZE, A_PTR #define KERNEL_4x4 \ MOVUPS X5, X6 \ MOVUPS X5, X7 \ MOVUPS X5, X8 \ MULPS X1, X5 \ MULPS X2, X6 \ MULPS X3, X7 \ MULPS X4, X8 #define STORE_4x4 \ MOVUPS (A_PTR), X13 \ ADDPS X13, X5 \ MOVUPS (A_PTR)(LDA*1), X14 \ ADDPS X14, X6 \ MOVUPS (A_PTR)(LDA*2), X15 \ ADDPS X15, X7 \ MOVUPS (A_PTR)(LDA3*1), X13 \ ADDPS X13, X8 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, (A_PTR)(LDA*1) \ MOVUPS X7, (A_PTR)(LDA*2) \ MOVUPS X8, (A_PTR)(LDA3*1) \ ADDQ $4*SIZE, A_PTR #define KERNEL_4x2 \ MOVUPS X5, X6 \ MOVUPS X5, X7 \ MOVUPS X5, X8 \ MULPS X1, X5 \ MULPS X2, X6 \ MULPS X3, X7 \ MULPS X4, X8 #define STORE_4x2 \ MOVSD (A_PTR), X9 \ ADDPS X9, X5 \ MOVSD (A_PTR)(LDA*1), X10 \ ADDPS X10, X6 \ MOVSD (A_PTR)(LDA*2), X11 \ ADDPS X11, X7 \ MOVSD (A_PTR)(LDA3*1), X12 \ ADDPS X12, X8 \ MOVSD X5, (A_PTR) \ MOVSD X6, (A_PTR)(LDA*1) \ MOVSD X7, (A_PTR)(LDA*2) \ MOVSD X8, (A_PTR)(LDA3*1) \ ADDQ $2*SIZE, A_PTR #define KERNEL_4x1 \ MOVSS (Y_PTR), X5 \ MOVSS X5, X6 \ MOVSS X5, X7 \ MOVSS X5, X8 \ MULSS X1, X5 \ MULSS X2, X6 \ MULSS X3, X7 \ MULSS X4, X8 #define STORE_4x1 \ ADDSS (A_PTR), X5 \ ADDSS (A_PTR)(LDA*1), X6 \ ADDSS (A_PTR)(LDA*2), X7 \ ADDSS (A_PTR)(LDA3*1), X8 \ MOVSS X5, (A_PTR) \ MOVSS X6, (A_PTR)(LDA*1) \ MOVSS X7, (A_PTR)(LDA*2) \ MOVSS X8, (A_PTR)(LDA3*1) \ ADDQ $SIZE, A_PTR #define KERNEL_2x8 \ MOVUPS X5, X7 \ MOVUPS X6, X8 \ MULPS X1, X5 \ MULPS X1, X6 \ MULPS X2, X7 \ MULPS X2, X8 #define STORE_2x8 \ MOVUPS (A_PTR), X9 \ ADDPS X9, X5 \ MOVUPS 4*SIZE(A_PTR), X10 \ ADDPS X10, X6 \ MOVUPS (A_PTR)(LDA*1), X11 \ ADDPS X11, X7 \ MOVUPS 4*SIZE(A_PTR)(LDA*1), X12 \ ADDPS X12, X8 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, 4*SIZE(A_PTR) \ MOVUPS X7, (A_PTR)(LDA*1) \ MOVUPS X8, 4*SIZE(A_PTR)(LDA*1) \ ADDQ $8*SIZE, A_PTR #define KERNEL_2x4 \ MOVUPS X5, X6 \ MULPS X1, X5 \ MULPS X2, X6 #define STORE_2x4 \ MOVUPS (A_PTR), X9 \ ADDPS X9, X5 \ MOVUPS (A_PTR)(LDA*1), X11 \ ADDPS X11, X6 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, (A_PTR)(LDA*1) \ ADDQ $4*SIZE, A_PTR #define KERNEL_2x2 \ MOVSD X5, X6 \ MULPS X1, X5 \ MULPS X2, X6 #define STORE_2x2 \ MOVSD (A_PTR), X7 \ ADDPS X7, X5 \ MOVSD (A_PTR)(LDA*1), X8 \ ADDPS X8, X6 \ MOVSD X5, (A_PTR) \ MOVSD X6, (A_PTR)(LDA*1) \ ADDQ $2*SIZE, A_PTR #define KERNEL_2x1 \ MOVSS (Y_PTR), X5 \ MOVSS X5, X6 \ MULSS X1, X5 \ MULSS X2, X6 #define STORE_2x1 \ ADDSS (A_PTR), X5 \ ADDSS (A_PTR)(LDA*1), X6 \ MOVSS X5, (A_PTR) \ MOVSS X6, (A_PTR)(LDA*1) \ ADDQ $SIZE, A_PTR #define KERNEL_1x8 \ MULPS X1, X5 \ MULPS X1, X6 #define STORE_1x8 \ MOVUPS (A_PTR), X7 \ ADDPS X7, X5 \ MOVUPS 4*SIZE(A_PTR), X8 \ ADDPS X8, X6 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, 4*SIZE(A_PTR) \ ADDQ $8*SIZE, A_PTR #define KERNEL_1x4 \ MULPS X1, X5 \ MULPS X1, X6 #define STORE_1x4 \ MOVUPS (A_PTR), X7 \ ADDPS X7, X5 \ MOVUPS X5, (A_PTR) \ ADDQ $4*SIZE, A_PTR #define KERNEL_1x2 \ MULPS X1, X5 #define STORE_1x2 \ MOVSD (A_PTR), X6 \ ADDPS X6, X5 \ MOVSD X5, (A_PTR) \ ADDQ $2*SIZE, A_PTR #define KERNEL_1x1 \ MOVSS (Y_PTR), X5 \ MULSS X1, X5 #define STORE_1x1 \ ADDSS (A_PTR), X5 \ MOVSS X5, (A_PTR) \ ADDQ $SIZE, A_PTR // func Ger(m, n uintptr, alpha float32, // x []float32, incX uintptr, // y []float32, incY uintptr, // a []float32, lda uintptr) TEXT ·Ger(SB), 0, $16-120 MOVQ M_DIM, M MOVQ N_DIM, N CMPQ M, $0 JE end CMPQ N, $0 JE end LOAD_ALPHA MOVQ x_base+24(FP), X_PTR MOVQ y_base+56(FP), Y_PTR MOVQ a_base+88(FP), A_ROW MOVQ A_ROW, A_PTR MOVQ lda+112(FP), LDA // LDA = LDA * sizeof(float32) SHLQ $BITSIZE, LDA LEAQ (LDA)(LDA*2), LDA3 // LDA3 = LDA * 3 CMPQ incY+80(FP), $1 // Check for dense vector Y (fast-path) JNE inc CMPQ incX+48(FP), $1 // Check for dense vector X (fast-path) JNE inc SHRQ $2, M JZ r2 r4: // LOAD 4 LOAD_SCALED4 MOVQ N_DIM, N SHRQ $KERNELSIZE, N JZ r4c4 r4c8: // 4x8 KERNEL KERNEL_LOAD8 KERNEL_4x8 STORE_4x8 ADDQ $8*SIZE, Y_PTR DECQ N JNZ r4c8 r4c4: TESTQ $4, N_DIM JZ r4c2 // 4x4 KERNEL KERNEL_LOAD4 KERNEL_4x4 STORE_4x4 ADDQ $4*SIZE, Y_PTR r4c2: TESTQ $2, N_DIM JZ r4c1 // 4x2 KERNEL KERNEL_LOAD2 KERNEL_4x2 STORE_4x2 ADDQ $2*SIZE, Y_PTR r4c1: TESTQ $1, N_DIM JZ r4end // 4x1 KERNEL KERNEL_4x1 STORE_4x1 ADDQ $SIZE, Y_PTR r4end: ADDQ $4*SIZE, X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ M JNZ r4 r2: TESTQ $2, M_DIM JZ r1 // LOAD 2 LOAD_SCALED2 MOVQ N_DIM, N SHRQ $KERNELSIZE, N JZ r2c4 r2c8: // 2x8 KERNEL KERNEL_LOAD8 KERNEL_2x8 STORE_2x8 ADDQ $8*SIZE, Y_PTR DECQ N JNZ r2c8 r2c4: TESTQ $4, N_DIM JZ r2c2 // 2x4 KERNEL KERNEL_LOAD4 KERNEL_2x4 STORE_2x4 ADDQ $4*SIZE, Y_PTR r2c2: TESTQ $2, N_DIM JZ r2c1 // 2x2 KERNEL KERNEL_LOAD2 KERNEL_2x2 STORE_2x2 ADDQ $2*SIZE, Y_PTR r2c1: TESTQ $1, N_DIM JZ r2end // 2x1 KERNEL KERNEL_2x1 STORE_2x1 ADDQ $SIZE, Y_PTR r2end: ADDQ $2*SIZE, X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR r1: TESTQ $1, M_DIM JZ end // LOAD 1 LOAD_SCALED1 MOVQ N_DIM, N SHRQ $KERNELSIZE, N JZ r1c4 r1c8: // 1x8 KERNEL KERNEL_LOAD8 KERNEL_1x8 STORE_1x8 ADDQ $8*SIZE, Y_PTR DECQ N JNZ r1c8 r1c4: TESTQ $4, N_DIM JZ r1c2 // 1x4 KERNEL KERNEL_LOAD4 KERNEL_1x4 STORE_1x4 ADDQ $4*SIZE, Y_PTR r1c2: TESTQ $2, N_DIM JZ r1c1 // 1x2 KERNEL KERNEL_LOAD2 KERNEL_1x2 STORE_1x2 ADDQ $2*SIZE, Y_PTR r1c1: TESTQ $1, N_DIM JZ end // 1x1 KERNEL KERNEL_1x1 STORE_1x1 end: RET inc: // Algorithm for incY != 0 ( split loads in kernel ) MOVQ incX+48(FP), INC_X // INC_X = incX * sizeof(float32) SHLQ $BITSIZE, INC_X MOVQ incY+80(FP), INC_Y // INC_Y = incY * sizeof(float32) SHLQ $BITSIZE, INC_Y LEAQ (INC_X)(INC_X*2), INC3_X // INC3_X = INC_X * 3 LEAQ (INC_Y)(INC_Y*2), INC3_Y // INC3_Y = INC_Y * 3 XORQ TMP2, TMP2 MOVQ M, TMP1 SUBQ $1, TMP1 IMULQ INC_X, TMP1 NEGQ TMP1 CMPQ INC_X, $0 CMOVQLT TMP1, TMP2 LEAQ (X_PTR)(TMP2*SIZE), X_PTR XORQ TMP2, TMP2 MOVQ N, TMP1 SUBQ $1, TMP1 IMULQ INC_Y, TMP1 NEGQ TMP1 CMPQ INC_Y, $0 CMOVQLT TMP1, TMP2 LEAQ (Y_PTR)(TMP2*SIZE), Y_PTR SHRQ $2, M JZ inc_r2 inc_r4: // LOAD 4 LOAD_SCALED4_INC MOVQ N_DIM, N SHRQ $KERNELSIZE, N JZ inc_r4c4 inc_r4c8: // 4x4 KERNEL KERNEL_LOAD8_INC KERNEL_4x8 STORE_4x8 LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ N JNZ inc_r4c8 inc_r4c4: TESTQ $4, N_DIM JZ inc_r4c2 // 4x4 KERNEL KERNEL_LOAD4_INC KERNEL_4x4 STORE_4x4 LEAQ (Y_PTR)(INC_Y*4), Y_PTR inc_r4c2: TESTQ $2, N_DIM JZ inc_r4c1 // 4x2 KERNEL KERNEL_LOAD2_INC KERNEL_4x2 STORE_4x2 LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_r4c1: TESTQ $1, N_DIM JZ inc_r4end // 4x1 KERNEL KERNEL_4x1 STORE_4x1 ADDQ INC_Y, Y_PTR inc_r4end: LEAQ (X_PTR)(INC_X*4), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ M JNZ inc_r4 inc_r2: TESTQ $2, M_DIM JZ inc_r1 // LOAD 2 LOAD_SCALED2_INC MOVQ N_DIM, N SHRQ $KERNELSIZE, N JZ inc_r2c4 inc_r2c8: // 2x8 KERNEL KERNEL_LOAD8_INC KERNEL_2x8 STORE_2x8 LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ N JNZ inc_r2c8 inc_r2c4: TESTQ $4, N_DIM JZ inc_r2c2 // 2x4 KERNEL KERNEL_LOAD4_INC KERNEL_2x4 STORE_2x4 LEAQ (Y_PTR)(INC_Y*4), Y_PTR inc_r2c2: TESTQ $2, N_DIM JZ inc_r2c1 // 2x2 KERNEL KERNEL_LOAD2_INC KERNEL_2x2 STORE_2x2 LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_r2c1: TESTQ $1, N_DIM JZ inc_r2end // 2x1 KERNEL KERNEL_2x1 STORE_2x1 ADDQ INC_Y, Y_PTR inc_r2end: LEAQ (X_PTR)(INC_X*2), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR inc_r1: TESTQ $1, M_DIM JZ end // LOAD 1 LOAD_SCALED1 MOVQ N_DIM, N SHRQ $KERNELSIZE, N JZ inc_r1c4 inc_r1c8: // 1x8 KERNEL KERNEL_LOAD8_INC KERNEL_1x8 STORE_1x8 LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ N JNZ inc_r1c8 inc_r1c4: TESTQ $4, N_DIM JZ inc_r1c2 // 1x4 KERNEL KERNEL_LOAD4_INC KERNEL_1x4 STORE_1x4 LEAQ (Y_PTR)(INC_Y*4), Y_PTR inc_r1c2: TESTQ $2, N_DIM JZ inc_r1c1 // 1x2 KERNEL KERNEL_LOAD2_INC KERNEL_1x2 STORE_1x2 LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_r1c1: TESTQ $1, N_DIM JZ inc_end // 1x1 KERNEL KERNEL_1x1 STORE_1x1 inc_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/ge_noasm.go000066400000000000000000000017451450372207100227520ustar00rootroot00000000000000// 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. //go:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f32 // Ger performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar. func Ger(m, n uintptr, alpha float32, x []float32, incX uintptr, y []float32, incY uintptr, a []float32, lda uintptr) { if incX == 1 && incY == 1 { x = x[:m] y = y[:n] for i, xv := range x { AxpyUnitary(alpha*xv, y, a[uintptr(i)*lda:uintptr(i)*lda+n]) } return } var ky, kx uintptr if int(incY) < 0 { ky = uintptr(-int(n-1) * int(incY)) } if int(incX) < 0 { kx = uintptr(-int(m-1) * int(incX)) } ix := kx for i := 0; i < int(m); i++ { AxpyInc(alpha*x[ix], y, a[uintptr(i)*lda:uintptr(i)*lda+n], uintptr(n), uintptr(incY), 1, uintptr(ky), 0) ix += incX } } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/ge_test.go000066400000000000000000000234121450372207100226070ustar00rootroot00000000000000// 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 f32_test import ( "fmt" "testing" . "gonum.org/v1/gonum/internal/asm/f32" ) var gerTests = []struct { x, y, a []float32 want []float32 }{ // m x n ( kernels executed ) { // 1 x 1 (1x1) x: []float32{2}, y: []float32{4.4}, a: []float32{10}, want: []float32{18.8}, }, { // 3 x 2 ( 2x2, 1x2 ) x: []float32{-2, -3, 0}, y: []float32{-1.1, 5}, a: []float32{ 1.3, 2.4, 2.6, 2.8, -1.3, -4.3, }, want: []float32{3.5, -7.6, 5.9, -12.2, -1.3, -4.3}, }, { // 3 x 3 ( 2x2, 2x1, 1x2, 1x1 ) x: []float32{-2, 7, 12}, y: []float32{-1.1, 0, 6}, a: []float32{ 1.3, 2.4, 3.5, 2.6, 2.8, 3.3, -1.3, -4.3, -9.7, }, want: []float32{3.5, 2.4, -8.5, -5.1, 2.8, 45.3, -14.5, -4.3, 62.3}, }, { // 5 x 3 ( 4x2, 4x1, 1x2, 1x1 ) x: []float32{-2, -3, 0, 1, 2}, y: []float32{-1.1, 5, 0}, a: []float32{ 1.3, 2.4, 3.5, 2.6, 2.8, 3.3, -1.3, -4.3, -9.7, 8, 9, -10, -12, -14, -6, }, want: []float32{3.5, -7.6, 3.5, 5.9, -12.2, 3.3, -1.3, -4.3, -9.7, 6.9, 14, -10, -14.2, -4, -6}, }, { // 3 x 6 ( 2x4, 2x2, 1x4, 1x2 ) x: []float32{-2, -3, 0}, y: []float32{-1.1, 5, 0, 9, 19, 22}, a: []float32{ 1.3, 2.4, 3.5, 4.8, 1.11, -9, 2.6, 2.8, 3.3, -3.4, 6.2, -8.7, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9, }, want: []float32{3.5, -7.6, 3.5, -13.2, -36.89, -53, 5.9, -12.2, 3.3, -30.4, -50.8, -74.7, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9}, }, { // 5 x 5 ( 4x4, 4x1, 1x4, 1x1) x: []float32{-2, 0, 2, 0, 7}, y: []float32{-1.1, 8, 7, 3, 5}, a: []float32{ 1.3, 2.4, 3.5, 2.2, 8.3, 2.6, 2.8, 3.3, 4.4, -1.5, -1.3, -4.3, -9.7, -8.8, 6.2, 8, 9, -10, -11, 12, -12, -14, -6, -2, 4, }, want: []float32{ 3.5, -13.6, -10.5, -3.8, -1.7, 2.6, 2.8, 3.3, 4.4, -1.5, -3.5, 11.7, 4.3, -2.8, 16.2, 8, 9, -10, -11, 12, -19.700000000000003, 42, 43, 19, 39, }, }, { // 7 x 7 ( 4x4, 4x2, 4x1, 2x4, 2x2, 2x1, 1x4, 1x2, 1x1 ) < nan test > x: []float32{-2, 8, 9, -3, -1.2, 5, 4.5}, y: []float32{-1.1, nan, 19, 11, -9.22, 7, 3.3}, a: []float32{ 1.3, 2.4, 3.5, 4.8, 1.11, -9, 2.2, 2.6, 2.8, 3.3, -3.4, 6.2, -8.7, 5.1, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9, 8, 5, -2.5, 1.8, -3.6, 2.8, 4.9, 7, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9, 8, 2.6, 2.8, 3.3, -3.4, 6.2, -8.7, 5.1, 1.3, 2.4, 3.5, 4.8, 1.11, -9, 2.2, }, want: []float32{ 3.5, nan, -34.5, -17.2, 19.55, -23, -4.4, -6.2, nan, 155.3, 84.6, -67.56, 47.3, 31.5, -11.2, nan, 161.3, 95.9, -74.08, 71.9, 37.7, 8.3, nan, -55.2, -36.6, 30.46, -16.1, -2.9, 0.02, nan, -32.5, -16.3, 19.964, 0.5, 4.04, -2.9, nan, 98.3, 51.6, -39.9, 26.3, 21.6, -3.65, nan, 89, 54.3, -40.38, 22.5, 17.05, }, }, { // 15 x 15 ( 4x8 4x4, 4x2, 4x1, 2x8, 2x4, 2x2, 2x1, 1x8, 1x4, 1x2, 1x1 ) < nan test > x: []float32{6.2, -5, 88.68, 43.4, -30.5, -40.2, 19.9, 3, 19.9, -40.2, -30.5, 43.4, 88.68, -5, 6.2}, y: []float32{1.5, 21.7, -28.7, -11.9, 18.1, 3.1, 21, 8, 21, 3.1, 18.1, -11.9, -28.7, 21.7, 1.5}, a: []float32{ -20.5, 17.1, -8.4, -23.8, 3.9, 7.7, 6.25, 2.9, -0.29, 25.6, -9.4, 36.5, 9.7, 2.3, 4.1, -34.1, 10.3, 4.5, -42.05, 9.4, 4, 19.2, 9.8, -32.7, 4.1, 4.4, -22.5, -7.8, 3.6, -24.5, 21.7, 8.6, -13.82, 3.05, -2.29, 39.4, -40, 7.9, -2.5, -7.7, 18.1, -25.5, -18.5, 43.2, 2.1, -20.5, 17.1, -8.4, -23.8, 3.9, 7.7, 6.25, 2.9, -0.29, 25.6, -9.4, 36.5, 9.7, 2.3, 4.1, -34.1, 10.3, 4.5, -42.05, 9.4, 4, 19.2, 9.8, -32.7, 4.1, 4.4, -22.5, -7.8, 3.6, -24.5, 21.7, 8.6, -13.82, 3.05, -2.29, 39.4, -40, 7.9, -2.5, -7.7, 18.1, -25.5, -18.5, 43.2, 2.1, 21.7, 8.6, -13.82, 3.05, -2.29, 39.4, -40, 7.9, -2.5, -7.7, 18.1, -25.5, -18.5, 43.2, 2.1, -34.1, 10.3, 4.5, -42.05, 9.4, 4, 19.2, 9.8, -32.7, 4.1, 4.4, -22.5, -7.8, 3.6, -24.5, -20.5, 17.1, -8.4, -23.8, 3.9, 7.7, 6.25, 2.9, -0.29, 25.6, -9.4, 36.5, 9.7, 2.3, 4.1, 21.7, 8.6, -13.82, 3.05, -2.29, 39.4, -40, 7.9, -2.5, -7.7, 18.1, -25.5, -18.5, 43.2, 2.1, -34.1, 10.3, 4.5, -42.05, 9.4, 4, 19.2, 9.8, -32.7, 4.1, 4.4, -22.5, -7.8, 3.6, -24.5, -20.5, 17.1, -8.4, -23.8, 3.9, 7.7, 6.25, 2.9, -0.29, 25.6, -9.4, 36.5, 9.7, 2.3, 4.1, -20.5, 17.1, -8.4, -23.8, 3.9, 7.7, 6.25, 2.9, -0.29, 25.6, -9.4, 36.5, 9.7, 2.3, 4.1, 21.7, 8.6, -13.82, 3.05, -2.29, 39.4, -40, 7.9, -2.5, -7.7, 18.1, -25.5, -18.5, 43.2, 2.1, -34.1, 10.3, 4.5, -42.05, 9.4, 4, 19.2, 9.8, -32.7, 4.1, 4.4, -22.5, -7.8, 3.6, -24.5, }, want: []float32{ -11.200001, 151.64, -186.34, -97.58, 116.12, 26.919998, 136.45, 52.5, 129.91, 44.82, 102.82, -37.28, -168.24, 136.84, 13.4, -41.6, -98.2, 148, 17.45, -81.1, -11.5, -85.8, -30.2, -137.7, -11.4, -86.1, 37, 135.7, -104.9, -32, 154.72, 1932.956, -2558.936, -1052.242, 1602.818, 314.30798, 1822.28, 717.34, 1859.78, 267.20798, 1623.208, -1080.792, -2563.616, 1967.556, 135.12001, 44.600006, 958.88007, -1253.9801, -540.26, 789.44006, 142.23999, 917.65, 350.1, 911.11005, 160.14, 776.14, -479.96002, -1235.8801, 944.0801, 69.200005, -79.85, -651.55005, 879.85004, 320.9, -542.64996, -90.549995, -621.3, -234.2, -673.2, -90.45, -547.64996, 340.44998, 867.55005, -658.25006, -70.25, -38.600002, -863.74005, 1139.9202, 481.43, -729.91003, -85.21999, -884.2, -313.7, -846.7, -132.31999, -709.5201, 452.88, 1135.2401, -829.14, -58.200005, 51.55, 440.43002, -584.95, -233.75998, 357.9, 101.09, 377.9, 167.09999, 415.4, 53.989998, 378.29, -262.31, -589.63, 475.03003, 31.949999, -29.599998, 75.40001, -81.600006, -77.75, 63.700005, 13.299999, 82.2, 33.8, 30.3, 13.4, 58.700005, -58.199997, -93.90001, 68.700005, -20, 9.349998, 448.93002, -579.53, -260.61, 364.09, 69.39, 424.15, 162.09999, 417.61, 87.29, 350.79, -200.30998, -561.43, 434.13, 33.949997, -38.600002, -863.74005, 1139.9202, 481.43, -729.91003, -85.21999, -884.2, -313.7, -846.7, -132.31999, -709.5201, 452.88, 1135.2401, -829.14, -58.200005, -79.85, -651.55005, 879.85004, 320.9, -542.64996, -90.549995, -621.3, -234.2, -673.2, -90.45, -547.64996, 340.44998, 867.55005, -658.25006, -70.25, 44.600006, 958.88007, -1253.9801, -540.26, 789.44006, 142.23999, 917.65, 350.1, 911.11005, 160.14, 776.14, -479.96002, -1235.8801, 944.0801, 69.200005, 112.520004, 1941.456, -2553.5159, -1079.092, 1609.008, 282.608, 1868.53, 712.34, 1861.99, 300.508, 1595.708, -1018.792, -2535.416, 1926.6561, 137.12001, 14.200001, -99.9, 129.68, 62.55, -92.79, 23.900002, -145, -32.1, -107.5, -23.2, -72.4, 34, 125, -65.3, -5.4, -24.8, 144.84, -173.44, -115.83, 121.62, 23.22, 149.4, 59.399998, 97.5, 23.32, 116.62, -96.28, -185.74, 138.14, -15.200001, }, }, } func TestGer(t *testing.T) { const ( tol = 1e-6 xGdVal, yGdVal, aGdVal = -0.5, 1.5, 10 gdLn = 4 ) for i, test := range gerTests { m, n := len(test.x), len(test.y) for _, align := range align2 { prefix := fmt.Sprintf("Test %v (%vx%v) align(x:%v,y:%v,a:%v)", i, m, n, align.x, align.y, align.x^align.y) xgLn, ygLn, agLn := gdLn+align.x, gdLn+align.y, gdLn+align.x^align.y xg, yg := guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] ag := guardVector(test.a, aGdVal, agLn) a := ag[agLn : len(ag)-agLn] var alpha float32 = 1.0 Ger(uintptr(m), uintptr(n), alpha, x, 1, y, 1, a, uintptr(n)) for i := range test.want { if !sameApprox(a[i], test.want[i], tol) { t.Errorf(msgVal, prefix, i, a[i], test.want[i]) return } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, yGdVal, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } if !isValidGuard(ag, aGdVal, agLn) { t.Errorf(msgGuard, prefix, "a", ag[:agLn], ag[len(ag)-agLn:]) t.Errorf(msgReadOnly, prefix, "x") } if !sameStrided(test.y, y, 1) { t.Errorf(msgReadOnly, prefix, "y") } } for _, inc := range newIncSet(1, 2) { prefix := fmt.Sprintf("Test %v (%vx%v) inc(x:%v,y:%v)", i, m, n, inc.x, inc.y) xg := guardIncVector(test.x, xGdVal, inc.x, gdLn) yg := guardIncVector(test.y, yGdVal, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] ag := guardVector(test.a, aGdVal, gdLn) a := ag[gdLn : len(ag)-gdLn] var alpha float32 = 3.5 Ger(uintptr(m), uintptr(n), alpha, x, uintptr(inc.x), y, uintptr(inc.y), a, uintptr(n)) for i := range test.want { want := alpha*test.x[i/n]*test.y[i%n] + test.a[i] if !sameApprox(a[i], want, tol) { t.Errorf(msgVal, prefix, i, a[i], want) } } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) if !isValidGuard(ag, aGdVal, gdLn) { t.Errorf(msgGuard, prefix, "a", ag[:gdLn], ag[len(ag)-gdLn:]) } if !sameStrided(test.x, x, inc.x) { t.Errorf(msgReadOnly, prefix, "x") } if !sameStrided(test.y, y, inc.y) { t.Errorf(msgReadOnly, prefix, "y") } } } } func BenchmarkGer(t *testing.B) { const alpha = 3 for _, dims := range newIncSet(3, 10, 30, 100, 300, 1e3, 3e3, 1e4) { m, n := dims.x, dims.y if m/n >= 100 || n/m >= 100 { continue } for _, inc := range newIncSet(1, 3, 4, 10) { t.Run(fmt.Sprintf("Dger %dx%d (%d %d)", m, n, inc.x, inc.y), func(b *testing.B) { x, y, a := gerData(m, n, inc.x, inc.y) b.ResetTimer() for i := 0; i < b.N; i++ { Ger(uintptr(m), uintptr(n), alpha, x, uintptr(inc.x), y, uintptr(inc.y), a, uintptr(n)) } }) } } } func gerData(m, n, incX, incY int) (x, y, a []float32) { x = make([]float32, m*incX) y = make([]float32, n*incY) a = make([]float32, m*n) ln := len(x) if len(y) > ln { ln = len(y) } if len(a) > ln { ln = len(a) } for i := 0; i < ln; i++ { v := float32(i) if i < len(a) { a[i] = v } if i < len(x) { x[i] = v } if i < len(y) { y[i] = v } } return x, y, a } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/gemv.go000066400000000000000000000041551450372207100221160ustar00rootroot00000000000000// 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 f32 // GemvN computes // // y = alpha * A * x + beta * y // // where A is an m×n dense matrix, x and y are vectors, and alpha and beta are scalars. func GemvN(m, n uintptr, alpha float32, a []float32, lda uintptr, x []float32, incX uintptr, beta float32, y []float32, incY uintptr) { var kx, ky, i uintptr if int(incX) < 0 { kx = uintptr(-int(n-1) * int(incX)) } if int(incY) < 0 { ky = uintptr(-int(m-1) * int(incY)) } if incX == 1 && incY == 1 { if beta == 0 { for i = 0; i < m; i++ { y[i] = alpha * DotUnitary(a[lda*i:lda*i+n], x) } return } for i = 0; i < m; i++ { y[i] = y[i]*beta + alpha*DotUnitary(a[lda*i:lda*i+n], x) } return } iy := ky if beta == 0 { for i = 0; i < m; i++ { y[iy] = alpha * DotInc(x, a[lda*i:lda*i+n], n, incX, 1, kx, 0) iy += incY } return } for i = 0; i < m; i++ { y[iy] = y[iy]*beta + alpha*DotInc(x, a[lda*i:lda*i+n], n, incX, 1, kx, 0) iy += incY } } // GemvT computes // // y = alpha * Aᵀ * x + beta * y // // where A is an m×n dense matrix, x and y are vectors, and alpha and beta are scalars. func GemvT(m, n uintptr, alpha float32, a []float32, lda uintptr, x []float32, incX uintptr, beta float32, y []float32, incY uintptr) { var kx, ky, i uintptr if int(incX) < 0 { kx = uintptr(-int(m-1) * int(incX)) } if int(incY) < 0 { ky = uintptr(-int(n-1) * int(incY)) } switch { case beta == 0: // beta == 0 is special-cased to memclear if incY == 1 { for i := range y { y[i] = 0 } } else { iy := ky for i := 0; i < int(n); i++ { y[iy] = 0 iy += incY } } case int(incY) < 0: ScalInc(beta, y, n, uintptr(int(-incY))) case incY == 1: ScalUnitary(beta, y[:n]) default: ScalInc(beta, y, n, incY) } if incX == 1 && incY == 1 { for i = 0; i < m; i++ { AxpyUnitaryTo(y, alpha*x[i], a[lda*i:lda*i+n], y) } return } ix := kx for i = 0; i < m; i++ { AxpyInc(alpha*x[ix], a[lda*i:lda*i+n], y, n, 1, incY, 0, ky) ix += incX } } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/gemv_test.go000066400000000000000000000502271450372207100231560ustar00rootroot00000000000000// 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 f32_test import ( "fmt" "testing" . "gonum.org/v1/gonum/internal/asm/f32" "gonum.org/v1/gonum/internal/math32" ) type SgemvCase struct { m int n int A []float32 x []float32 y []float32 NoTrans []SgemvSubcase Trans []SgemvSubcase } type SgemvSubcase struct { alpha float32 beta float32 want []float32 wantRevX []float32 wantRevY []float32 wantRevXY []float32 } var SgemvCases = []SgemvCase{ { // 1x1 m: 1, n: 1, A: []float32{4.1}, x: []float32{2.2}, y: []float32{6.8}, NoTrans: []SgemvSubcase{ // (1x1) {alpha: 0, beta: 0, want: []float32{0}, wantRevX: []float32{0}, wantRevY: []float32{0}, wantRevXY: []float32{0}, }, {alpha: 0, beta: 1, want: []float32{6.8}, wantRevX: []float32{6.8}, wantRevY: []float32{6.8}, wantRevXY: []float32{6.8}, }, {alpha: 1, beta: 0, want: []float32{9.02}, wantRevX: []float32{9.02}, wantRevY: []float32{9.02}, wantRevXY: []float32{9.02}, }, {alpha: 8, beta: -6, want: []float32{31.36}, wantRevX: []float32{31.36}, wantRevY: []float32{31.36}, wantRevXY: []float32{31.36}, }, }, Trans: []SgemvSubcase{ // (1x1) {alpha: 0, beta: 0, want: []float32{0}, wantRevX: []float32{0}, wantRevY: []float32{0}, wantRevXY: []float32{0}, }, {alpha: 0, beta: 1, want: []float32{2.2}, wantRevX: []float32{2.2}, wantRevY: []float32{2.2}, wantRevXY: []float32{2.2}, }, {alpha: 1, beta: 0, want: []float32{27.88}, wantRevX: []float32{27.88}, wantRevY: []float32{27.88}, wantRevXY: []float32{27.88}, }, {alpha: 8, beta: -6, want: []float32{209.84}, wantRevX: []float32{209.84}, wantRevY: []float32{209.84}, wantRevXY: []float32{209.84}, }, }, }, { // 3x2 m: 3, n: 2, A: []float32{ 4.67, 2.75, 0.48, 1.21, 2.28, 2.82, }, x: []float32{3.38, 3}, y: []float32{2.8, 1.71, 2.64}, NoTrans: []SgemvSubcase{ // (2x2, 1x2) {alpha: 0, beta: 0, want: []float32{0, 0, 0}, wantRevX: []float32{0, 0, 0}, wantRevY: []float32{0, 0, 0}, wantRevXY: []float32{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{2.8, 1.71, 2.64}, wantRevX: []float32{2.8, 1.71, 2.64}, wantRevY: []float32{2.8, 1.71, 2.64}, wantRevXY: []float32{2.8, 1.71, 2.64}, }, {alpha: 1, beta: 0, want: []float32{24.0346, 5.2524, 16.1664}, wantRevX: []float32{23.305, 5.5298, 16.3716}, wantRevY: []float32{16.1664, 5.2524, 24.0346}, wantRevXY: []float32{16.3716, 5.5298, 23.305}, }, {alpha: 8, beta: -6, want: []float32{175.4768, 31.7592, 113.4912}, wantRevX: []float32{169.64, 33.9784, 115.1328}, wantRevY: []float32{112.5312, 31.7592, 176.4368}, wantRevXY: []float32{114.1728, 33.9784, 170.6}, }, }, Trans: []SgemvSubcase{ // (2x2) {alpha: 0, beta: 0, want: []float32{0, 0}, wantRevX: []float32{0, 0}, wantRevY: []float32{0, 0}, wantRevXY: []float32{0, 0}, }, {alpha: 0, beta: 1, want: []float32{3.38, 3}, wantRevX: []float32{3.38, 3}, wantRevY: []float32{3.38, 3}, wantRevXY: []float32{3.38, 3}, }, {alpha: 1, beta: 0, want: []float32{19.916, 17.2139}, wantRevX: []float32{19.5336, 17.2251}, wantRevY: []float32{17.2139, 19.916}, wantRevXY: []float32{17.2251, 19.5336}, }, {alpha: 8, beta: -6, want: []float32{139.048, 119.7112}, wantRevX: []float32{135.9888, 119.8008}, wantRevY: []float32{117.4312, 141.328}, wantRevXY: []float32{117.5208, 138.2688}, }, }, }, { // 3x3 m: 3, n: 3, A: []float32{ 4.38, 4.4, 4.26, 4.18, 0.56, 2.57, 2.59, 2.07, 0.46, }, x: []float32{4.82, 1.82, 1.12}, y: []float32{0.24, 1.41, 3.45}, NoTrans: []SgemvSubcase{ // (2x2, 2x1, 1x2, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0}, wantRevX: []float32{0, 0, 0}, wantRevY: []float32{0, 0, 0}, wantRevXY: []float32{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{0.24, 1.41, 3.45}, wantRevX: []float32{0.24, 1.41, 3.45}, wantRevY: []float32{0.24, 1.41, 3.45}, wantRevXY: []float32{0.24, 1.41, 3.45}, }, {alpha: 1, beta: 0, want: []float32{33.8908, 24.0452, 16.7664}, wantRevX: []float32{33.4468, 18.0882, 8.8854}, wantRevY: []float32{16.7664, 24.0452, 33.8908}, wantRevXY: []float32{8.8854, 18.0882, 33.4468}, }, {alpha: 8, beta: -6, want: []float32{269.6864, 183.9016, 113.4312}, wantRevX: []float32{266.1344, 136.2456, 50.3832}, wantRevY: []float32{132.6912, 183.9016, 250.4264}, wantRevXY: []float32{69.6432, 136.2456, 246.8744}, }, }, Trans: []SgemvSubcase{ // (2x2, 1x2, 2x1, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0}, wantRevX: []float32{0, 0, 0}, wantRevY: []float32{0, 0, 0}, wantRevXY: []float32{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{4.82, 1.82, 1.12}, wantRevX: []float32{4.82, 1.82, 1.12}, wantRevY: []float32{4.82, 1.82, 1.12}, wantRevXY: []float32{4.82, 1.82, 1.12}, }, {alpha: 1, beta: 0, want: []float32{15.8805, 8.9871, 6.2331}, wantRevX: []float32{21.6264, 16.4664, 18.4311}, wantRevY: []float32{6.2331, 8.9871, 15.8805}, wantRevXY: []float32{18.4311, 16.4664, 21.6264}, }, {alpha: 8, beta: -6, want: []float32{98.124, 60.9768, 43.1448}, wantRevX: []float32{144.0912, 120.8112, 140.7288}, wantRevY: []float32{20.9448, 60.9768, 120.324}, wantRevXY: []float32{118.5288, 120.8112, 166.2912}, }, }, }, { // 5x3 m: 5, n: 3, A: []float32{ 4.1, 6.2, 8.1, 9.6, 3.5, 9.1, 10, 7, 3, 1, 1, 2, 9, 2, 5, }, x: []float32{1, 2, 3}, y: []float32{7, 8, 9, 10, 11}, NoTrans: []SgemvSubcase{ //(4x2, 4x1, 1x2, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0, 0, 0}, wantRevX: []float32{0, 0, 0, 0, 0}, wantRevY: []float32{0, 0, 0, 0, 0}, wantRevXY: []float32{0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{7, 8, 9, 10, 11}, wantRevX: []float32{7, 8, 9, 10, 11}, wantRevY: []float32{7, 8, 9, 10, 11}, wantRevXY: []float32{7, 8, 9, 10, 11}, }, {alpha: 1, beta: 0, want: []float32{40.8, 43.9, 33, 9, 28}, wantRevX: []float32{32.8, 44.9, 47, 7, 36}, wantRevY: []float32{28, 9, 33, 43.9, 40.8}, wantRevXY: []float32{36, 7, 47, 44.9, 32.8}, }, {alpha: 8, beta: -6, want: []float32{284.4, 303.2, 210, 12, 158}, wantRevX: []float32{220.4, 311.2, 322, -4, 222}, wantRevY: []float32{182, 24, 210, 291.2, 260.4}, wantRevXY: []float32{246, 8, 322, 299.2, 196.4}, }, }, Trans: []SgemvSubcase{ //( 2x4, 1x4, 2x1, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0}, wantRevX: []float32{0, 0, 0}, wantRevY: []float32{0, 0, 0}, wantRevXY: []float32{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{1, 2, 3}, wantRevX: []float32{1, 2, 3}, wantRevY: []float32{1, 2, 3}, wantRevXY: []float32{1, 2, 3}, }, {alpha: 1, beta: 0, want: []float32{304.5, 166.4, 231.5}, wantRevX: []float32{302.1, 188.2, 258.1}, wantRevY: []float32{231.5, 166.4, 304.5}, wantRevXY: []float32{258.1, 188.2, 302.1}, }, {alpha: 8, beta: -6, want: []float32{2430, 1319.2, 1834}, wantRevX: []float32{2410.8, 1493.6, 2046.8}, wantRevY: []float32{1846, 1319.2, 2418}, wantRevXY: []float32{2058.8, 1493.6, 2398.8}, }, }, }, { // 3x5 m: 3, n: 5, A: []float32{ 1.4, 2.34, 3.96, 0.96, 2.3, 3.43, 0.62, 1.09, 0.2, 3.56, 1.15, 0.58, 3.8, 1.16, 0.01, }, x: []float32{2.34, 2.82, 4.73, 0.22, 3.91}, y: []float32{2.46, 2.22, 4.75}, NoTrans: []SgemvSubcase{ // (2x4, 2x1, 1x4, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0}, wantRevX: []float32{0, 0, 0}, wantRevY: []float32{0, 0, 0}, wantRevXY: []float32{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{2.46, 2.22, 4.75}, wantRevX: []float32{2.46, 2.22, 4.75}, wantRevY: []float32{2.46, 2.22, 4.75}, wantRevXY: []float32{2.46, 2.22, 4.75}, }, {alpha: 1, beta: 0, want: []float32{37.8098, 28.8939, 22.5949}, wantRevX: []float32{32.8088, 27.5978, 25.8927}, wantRevY: []float32{22.5949, 28.8939, 37.8098}, wantRevXY: []float32{25.8927, 27.5978, 32.8088}, }, {alpha: 8, beta: -6, want: []float32{287.7184, 217.8312, 152.2592}, wantRevX: []float32{247.7104, 207.4624, 178.6416}, wantRevY: []float32{165.9992, 217.8312, 273.9784}, wantRevXY: []float32{192.3816, 207.4624, 233.9704}, }, }, Trans: []SgemvSubcase{ // (4x2, 1x2, 4x1, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0, 0, 0}, wantRevX: []float32{0, 0, 0, 0, 0}, wantRevY: []float32{0, 0, 0, 0, 0}, wantRevXY: []float32{0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{2.34, 2.82, 4.73, 0.22, 3.91}, wantRevX: []float32{2.34, 2.82, 4.73, 0.22, 3.91}, wantRevY: []float32{2.34, 2.82, 4.73, 0.22, 3.91}, wantRevXY: []float32{2.34, 2.82, 4.73, 0.22, 3.91}, }, {alpha: 1, beta: 0, want: []float32{16.5211, 9.8878, 30.2114, 8.3156, 13.6087}, wantRevX: []float32{17.0936, 13.9182, 30.5778, 7.8576, 18.8528}, wantRevY: []float32{13.6087, 8.3156, 30.2114, 9.8878, 16.5211}, wantRevXY: []float32{18.8528, 7.8576, 30.5778, 13.9182, 17.0936}, }, {alpha: 8, beta: -6, want: []float32{118.1288, 62.1824, 213.3112, 65.2048, 85.4096}, wantRevX: []float32{122.7088, 94.4256, 216.2424, 61.5408, 127.3624}, wantRevY: []float32{94.8296, 49.6048, 213.3112, 77.7824, 108.7088}, wantRevXY: []float32{136.7824, 45.9408, 216.2424, 110.0256, 113.2888}, }, }, }, { // 7x7 & nan test m: 7, n: 7, A: []float32{ 0.9, 2.6, 0.5, 1.8, 2.3, 0.6, 0.2, 1.6, 0.6, 1.3, 2.1, 1.4, 0.4, 0.8, 2.9, 0.9, 2.3, 2.5, 1.4, 1.8, 1.6, 2.6, 2.8, 2.1, 0.3, nan, 2.2, 1.3, 0.2, 2.2, 1.8, 1.8, 2.1, 1.3, 1.4, 1.7, 1.4, 2.3, 2., 1., 0., 1.4, 2.1, 1.9, 0.8, 2.9, 1.3, 0.3, 1.3, }, x: []float32{0.4, 2.8, 3.5, 0.3, 0.6, 2.5, 3.1}, y: []float32{3.2, 4.4, 5., 4.3, 4.1, 1.4, 0.2}, NoTrans: []SgemvSubcase{ // (4x4, 4x2, 4x1, 2x4, 2x2, 2x1, 1x4, 1x2, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0, nan, 0, 0, 0}, wantRevX: []float32{0, 0, 0, nan, 0, 0, 0}, wantRevY: []float32{0, 0, 0, nan, 0, 0, 0}, wantRevXY: []float32{0, 0, 0, nan, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, wantRevX: []float32{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, wantRevY: []float32{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, wantRevXY: []float32{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, }, {alpha: 1, beta: 0, want: []float32{13.43, 11.82, 22.78, nan, 21.93, 18.19, 15.39}, wantRevX: []float32{19.94, 14.21, 23.95, nan, 19.29, 14.81, 18.52}, wantRevY: []float32{15.39, 18.19, 21.93, nan, 22.78, 11.82, 13.43}, wantRevXY: []float32{18.52, 14.81, 19.29, nan, 23.95, 14.21, 19.94}, }, {alpha: 8, beta: -6, want: []float32{88.24, 68.16, 152.24, nan, 150.84, 137.12, 121.92}, wantRevX: []float32{140.32, 87.28, 161.6, nan, 129.72, 110.08, 146.96}, wantRevY: []float32{103.92, 119.12, 145.44, nan, 157.64, 86.16, 106.24}, wantRevXY: []float32{128.96, 92.08, 124.32, nan, 167., 105.28, 158.32}, }, }, Trans: []SgemvSubcase{ // (4x4, 2x4, 1x4, 4x2, 2x2, 1x2, 4x1, 2x1, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0, 0, nan, 0, 0}, wantRevX: []float32{0, 0, 0, 0, nan, 0, 0}, wantRevY: []float32{0, 0, nan, 0, 0, 0, 0}, wantRevXY: []float32{0, 0, nan, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{0.4, 2.8, 3.5, 0.3, nan, 2.5, 3.1}, wantRevX: []float32{0.4, 2.8, 3.5, 0.3, nan, 2.5, 3.1}, wantRevY: []float32{0.4, 2.8, nan, 0.3, 0.6, 2.5, 3.1}, wantRevXY: []float32{0.4, 2.8, nan, 0.3, 0.6, 2.5, 3.1}, }, {alpha: 1, beta: 0, want: []float32{39.22, 38.86, 38.61, 39.55, nan, 27.53, 25.71}, wantRevX: []float32{40.69, 40.33, 42.06, 41.92, nan, 24.98, 30.63}, wantRevY: []float32{25.71, 27.53, nan, 39.55, 38.61, 38.86, 39.22}, wantRevXY: []float32{30.63, 24.98, nan, 41.92, 42.06, 40.33, 40.69}, }, {alpha: 8, beta: -6, want: []float32{311.36, 294.08, 287.88, 314.6, nan, 205.24, 187.08}, wantRevX: []float32{323.12, 305.84, 315.48, 333.56, nan, 184.84, 226.44}, wantRevY: []float32{203.28, 203.44, nan, 314.6, 305.28, 295.88, 295.16}, wantRevXY: []float32{242.64, 183.04, nan, 333.56, 332.88, 307.64, 306.92}, }, }, }, { // 11x11 m: 11, n: 11, A: []float32{ 0.4, 3., 2.5, 2., 0.4, 2., 2., 1., 0.1, 0.3, 2., 1.7, 0.7, 2.6, 1.6, 0.5, 2.4, 3., 0.9, 0.1, 2.8, 1.3, 1.1, 2.2, 1.5, 0.8, 2.9, 0.4, 0.5, 1.7, 0.8, 2.6, 0.7, 2.2, 1.7, 0.8, 2.9, 0.7, 0.7, 1.7, 1.8, 1.9, 2.4, 1.9, 0.3, 0.5, 1.6, 1.5, 1.5, 2.4, 1.7, 1.2, 1.9, 2.8, 1.2, 1.4, 2.2, 1.7, 1.4, 2.7, 1.4, 0.9, 1.8, 0.5, 1.2, 1.9, 0.8, 2.3, 1.7, 1.3, 2., 2.8, 2.6, 0.4, 2.5, 1.3, 0.5, 2.4, 2.8, 1.1, 0.2, 0.4, 2.8, 0.5, 0.5, 0., 2.8, 1.9, 2.3, 1.8, 2.3, 1.7, 1.1, 0.1, 1.4, 1.2, 1.9, 0.5, 0.6, 0.6, 2.4, 1.2, 0.3, 1.4, 1.3, 2.5, 2.6, 0., 1.3, 2.6, 0.7, 1.5, 0.2, 1.4, 1.1, 1.8, 0.2, 1., 1., 0.6, 1.2, }, x: []float32{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, y: []float32{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, NoTrans: []SgemvSubcase{ // (4x4, 4x2, 4x1, 2x4, 2x2, 2x1, 1x4, 1x2, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevX: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevY: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevXY: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, wantRevX: []float32{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, wantRevY: []float32{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, wantRevXY: []float32{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, }, {alpha: 1, beta: 0, want: []float32{32.71, 38.93, 33.55, 45.46, 39.24, 38.41, 46.23, 25.78, 37.33, 37.42, 24.63}, wantRevX: []float32{39.82, 43.78, 37.73, 41.19, 40.17, 44.41, 42.75, 28.14, 35.6, 41.25, 23.9}, wantRevY: []float32{24.63, 37.42, 37.33, 25.78, 46.23, 38.41, 39.24, 45.46, 33.55, 38.93, 32.71}, wantRevXY: []float32{23.9, 41.25, 35.6, 28.14, 42.75, 44.41, 40.17, 41.19, 37.73, 43.78, 39.82}, }, {alpha: 8, beta: -6, want: []float32{238.88, 291.04, 258.8, 334.88, 288.12, 304.28, 357.84, 191.24, 289.64, 282.56, 173.64}, wantRevX: []float32{295.76, 329.84, 292.24, 300.72, 295.56, 352.28, 330., 210.12, 275.8, 313.2, 167.8}, wantRevY: []float32{174.24, 278.96, 289.04, 177.44, 344.04, 304.28, 301.92, 348.68, 259.4, 294.64, 238.28}, wantRevXY: []float32{168.4, 309.6, 275.2, 196.32, 316.2, 352.28, 309.36, 314.52, 292.84, 333.44, 295.16}, }, }, Trans: []SgemvSubcase{ // (4x4, 2x4, 1x4, 4x2, 2x2, 1x2, 4x1, 2x1, 1x1) {alpha: 0, beta: 0, want: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevX: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevY: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevXY: []float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float32{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, wantRevX: []float32{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, wantRevY: []float32{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, wantRevXY: []float32{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, }, {alpha: 1, beta: 0, want: []float32{37.07, 55.58, 46.05, 47.34, 33.88, 54.19, 50.85, 39.31, 31.29, 55.31, 46.98}, wantRevX: []float32{38.11, 63.38, 46.44, 40.04, 34.63, 59.27, 50.13, 35.45, 28.26, 51.64, 46.22}, wantRevY: []float32{46.98, 55.31, 31.29, 39.31, 50.85, 54.19, 33.88, 47.34, 46.05, 55.58, 37.07}, wantRevXY: []float32{46.22, 51.64, 28.26, 35.45, 50.13, 59.27, 34.63, 40.04, 46.44, 63.38, 38.11}, }, {alpha: 8, beta: -6, want: []float32{281.56, 437.44, 363.6, 361.32, 250.64, 422.72, 379.2, 294.68, 227.52, 437.08, 369.24}, wantRevX: []float32{289.88, 499.84, 366.72, 302.92, 256.64, 463.36, 373.44, 263.8, 203.28, 407.72, 363.16}, wantRevY: []float32{360.84, 435.28, 245.52, 297.08, 386.4, 422.72, 243.44, 358.92, 345.6, 439.24, 289.96}, wantRevXY: []float32{354.76, 405.92, 221.28, 266.2, 380.64, 463.36, 249.44, 300.52, 348.72, 501.64, 298.28}, }, }, }, } func TestGemv(t *testing.T) { for _, test := range SgemvCases { t.Run(fmt.Sprintf("(%vx%v)", test.m, test.n), func(tt *testing.T) { for i, cas := range test.NoTrans { tt.Run(fmt.Sprintf("NoTrans case %v", i), func(st *testing.T) { sgemvcomp(st, test, false, cas, i) }) } for i, cas := range test.Trans { tt.Run(fmt.Sprintf("Trans case %v", i), func(st *testing.T) { sgemvcomp(st, test, true, cas, i) }) } }) } } func sgemvcomp(t *testing.T, test SgemvCase, trans bool, cas SgemvSubcase, i int) { const ( tol = 1e-6 xGdVal, yGdVal, aGdVal = 0.5, 1.5, 10 gdLn = 4 ) if trans { test.x, test.y = test.y, test.x } prefix := fmt.Sprintf("Test (%vx%v) t:%v (a:%v,b:%v)", test.m, test.n, trans, cas.alpha, cas.beta) xg, yg := guardVector(test.x, xGdVal, gdLn), guardVector(test.y, yGdVal, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] ag := guardVector(test.A, aGdVal, gdLn) a := ag[gdLn : len(ag)-gdLn] lda := uintptr(test.n) if trans { GemvT(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, 1, cas.beta, y, 1) } else { GemvN(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, 1, cas.beta, y, 1) } for i := range cas.want { if !sameApprox(y[i], cas.want[i], tol) { t.Errorf(msgVal, prefix, i, y[i], cas.want[i]) } } if !isValidGuard(xg, xGdVal, gdLn) { t.Errorf(msgGuard, prefix, "x", xg[:gdLn], xg[len(xg)-gdLn:]) } if !isValidGuard(yg, yGdVal, gdLn) { t.Errorf(msgGuard, prefix, "y", yg[:gdLn], yg[len(yg)-gdLn:]) } if !isValidGuard(ag, aGdVal, gdLn) { t.Errorf(msgGuard, prefix, "a", ag[:gdLn], ag[len(ag)-gdLn:]) } if !equalStrided(test.x, x, 1) { t.Errorf(msgReadOnly, prefix, "x") } if !equalStrided(test.A, a, 1) { t.Errorf(msgReadOnly, prefix, "a") } for _, inc := range newIncSet(-1, 1, 2, 3, 90) { incPrefix := fmt.Sprintf("%s inc(x:%v, y:%v)", prefix, inc.x, inc.y) want, incY := cas.want, inc.y switch { case inc.x < 0 && inc.y < 0: want = cas.wantRevXY incY = -inc.y case inc.x < 0: want = cas.wantRevX case inc.y < 0: want = cas.wantRevY incY = -inc.y } xg, yg := guardIncVector(test.x, xGdVal, inc.x, gdLn), guardIncVector(test.y, yGdVal, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] ag := guardVector(test.A, aGdVal, gdLn) a := ag[gdLn : len(ag)-gdLn] if trans { GemvT(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, uintptr(inc.x), cas.beta, y, uintptr(inc.y)) } else { GemvN(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, uintptr(inc.x), cas.beta, y, uintptr(inc.y)) } for i := range want { if !sameApprox(y[i*incY], want[i], tol) { t.Errorf(msgVal, incPrefix, i, y[i*incY], want[i]) t.Error(y[i*incY] - want[i]) } } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) if !isValidGuard(ag, aGdVal, gdLn) { t.Errorf(msgGuard, incPrefix, "a", ag[:gdLn], ag[len(ag)-gdLn:]) } if !equalStrided(test.x, x, inc.x) { t.Errorf(msgReadOnly, incPrefix, "x") } if !equalStrided(test.A, a, 1) { t.Errorf(msgReadOnly, incPrefix, "a") } } } // equalStrided returns true if the strided vector x contains elements of the // dense vector ref at indices i*inc, false otherwise. func equalStrided(ref, x []float32, inc int) bool { if inc < 0 { inc = -inc } for i, v := range ref { if !scalarSame(x[i*inc], v) { return false } } return true } func scalarSame(a, b float32) bool { return a == b || (math32.IsNaN(a) && math32.IsNaN(b)) } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/l2norm.go000066400000000000000000000035221450372207100223660ustar00rootroot00000000000000// Copyright ©2019 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 f32 import "gonum.org/v1/gonum/internal/math32" // L2NormUnitary is the level 2 norm of x. func L2NormUnitary(x []float32) (sum float32) { var scale float32 var sumSquares float32 = 1 for _, v := range x { if v == 0 { continue } absxi := math32.Abs(v) if math32.IsNaN(absxi) { return math32.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math32.IsInf(scale, 1) { return math32.Inf(1) } return scale * math32.Sqrt(sumSquares) } // L2NormInc is the level 2 norm of x. func L2NormInc(x []float32, n, incX uintptr) (sum float32) { var scale float32 var sumSquares float32 = 1 for ix := uintptr(0); ix < n*incX; ix += incX { val := x[ix] if val == 0 { continue } absxi := math32.Abs(val) if math32.IsNaN(absxi) { return math32.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math32.IsInf(scale, 1) { return math32.Inf(1) } return scale * math32.Sqrt(sumSquares) } // L2DistanceUnitary is the L2 norm of x-y. func L2DistanceUnitary(x, y []float32) (sum float32) { var scale float32 var sumSquares float32 = 1 for i, v := range x { v -= y[i] if v == 0 { continue } absxi := math32.Abs(v) if math32.IsNaN(absxi) { return math32.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math32.IsInf(scale, 1) { return math32.Inf(1) } return scale * math32.Sqrt(sumSquares) } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/l2norm_test.go000066400000000000000000000061041450372207100234240ustar00rootroot00000000000000// Copyright ©2019 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 f32_test import ( "testing" . "gonum.org/v1/gonum/internal/asm/f32" ) func TestL2NormUnitary(t *testing.T) { const tol = 1e-7 var src_gd float32 = 1 for j, v := range []struct { want float32 x []float32 }{ {want: 0, x: []float32{}}, {want: 2, x: []float32{2}}, {want: 3.7416573867739413, x: []float32{1, 2, 3}}, {want: 3.7416573867739413, x: []float32{-1, -2, -3}}, {want: nan, x: []float32{nan}}, {want: 17.88854381999832, x: []float32{8, -8, 8, -8, 8}}, {want: 2.23606797749979, x: []float32{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L2NormUnitary(src) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Norm error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func TestL2NormInc(t *testing.T) { const tol = 1e-7 var src_gd float32 = 1 for j, v := range []struct { inc int want float32 x []float32 }{ {inc: 2, want: 0, x: []float32{}}, {inc: 3, want: 2, x: []float32{2}}, {inc: 10, want: 3.7416573867739413, x: []float32{1, 2, 3}}, {inc: 5, want: 3.7416573867739413, x: []float32{-1, -2, -3}}, {inc: 3, want: nan, x: []float32{nan}}, {inc: 15, want: 17.88854381999832, x: []float32{8, -8, 8, -8, 8}}, {inc: 1, want: 2.23606797749979, x: []float32{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, } { g_ln, ln := 4+j%2, len(v.x) v.x = guardIncVector(v.x, src_gd, v.inc, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L2NormInc(src, uintptr(ln), uintptr(v.inc)) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2NormInc error Got: %f Expected: %f", j, ret, v.want) } checkValidIncGuard(t, v.x, src_gd, v.inc, g_ln) } } func TestL2DistanceUnitary(t *testing.T) { const tol = 1e-7 var src_gd float32 = 1 for j, v := range []struct { want float32 x, y []float32 }{ {want: 0, x: []float32{}, y: []float32{}}, {want: 2, x: []float32{3}, y: []float32{1}}, {want: 3.7416573867739413, x: []float32{2, 4, 6}, y: []float32{1, 2, 3}}, {want: 3.7416573867739413, x: []float32{1, 2, 3}, y: []float32{2, 4, 6}}, {want: nan, x: []float32{nan}, y: []float32{0}}, {want: 17.88854381999832, x: []float32{9, -9, 9, -9, 9}, y: []float32{1, -1, 1, -1, 1}}, {want: 2.23606797749979, x: []float32{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}, y: []float32{0, 2, 0, -2, 0, 2, 0, -2, 0, 2}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) v.y = guardVector(v.y, src_gd, g_ln) srcX := v.x[g_ln : len(v.x)-g_ln] srcY := v.y[g_ln : len(v.y)-g_ln] ret := L2DistanceUnitary(srcX, srcY) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Distance error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/scal.go000066400000000000000000000021471450372207100221010ustar00rootroot00000000000000// Copyright ©2016 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 f32 // ScalUnitary is // // for i := range x { // x[i] *= alpha // } func ScalUnitary(alpha float32, x []float32) { for i := range x { x[i] *= alpha } } // ScalUnitaryTo is // // for i, v := range x { // dst[i] = alpha * v // } func ScalUnitaryTo(dst []float32, alpha float32, x []float32) { for i, v := range x { dst[i] = alpha * v } } // ScalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] *= alpha // ix += incX // } func ScalInc(alpha float32, x []float32, n, incX uintptr) { var ix uintptr for i := 0; i < int(n); i++ { x[ix] *= alpha ix += incX } } // ScalIncTo is // // var idst, ix uintptr // for i := 0; i < int(n); i++ { // dst[idst] = alpha * x[ix] // ix += incX // idst += incDst // } func ScalIncTo(dst []float32, incDst uintptr, alpha float32, x []float32, n, incX uintptr) { var idst, ix uintptr for i := 0; i < int(n); i++ { dst[idst] = alpha * x[ix] ix += incX idst += incDst } } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/stubs_amd64.go000066400000000000000000000033541450372207100233130ustar00rootroot00000000000000// Copyright ©2016 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:build !noasm && !gccgo && !safe // +build !noasm,!gccgo,!safe package f32 // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha float32, x, y []float32) // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []float32, alpha float32, x, y []float32) // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []float32, incDst, idst uintptr, alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) // DdotUnitary is // // for i, v := range x { // sum += float64(y[i]) * float64(v) // } // return func DdotUnitary(x, y []float32) (sum float64) // DdotInc is // // for i := 0; i < int(n); i++ { // sum += float64(y[iy]) * float64(x[ix]) // ix += incX // iy += incY // } // return func DdotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float64) // DotUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotUnitary(x, y []float32) (sum float32) // DotInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float32) // Sum is // // var sum float32 // for _, v := range x { // sum += v // } // return sum func Sum(x []float32) float32 golang-gonum-v1-gonum-0.14.0/internal/asm/f32/stubs_noasm.go000066400000000000000000000047101450372207100235120ustar00rootroot00000000000000// Copyright ©2016 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f32 // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha float32, x, y []float32) { for i, v := range x { y[i] += alpha * v } } // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []float32, alpha float32, x, y []float32) { for i, v := range x { dst[i] = alpha*v + y[i] } } // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []float32, incDst, idst uintptr, alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } // DotUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotUnitary(x, y []float32) (sum float32) { for i, v := range x { sum += y[i] * v } return sum } // DotInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float32) { for i := 0; i < int(n); i++ { sum += y[iy] * x[ix] ix += incX iy += incY } return sum } // DdotUnitary is // // for i, v := range x { // sum += float64(y[i]) * float64(v) // } // return func DdotUnitary(x, y []float32) (sum float64) { for i, v := range x { sum += float64(y[i]) * float64(v) } return } // DdotInc is // // for i := 0; i < int(n); i++ { // sum += float64(y[iy]) * float64(x[ix]) // ix += incX // iy += incY // } // return func DdotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float64) { for i := 0; i < int(n); i++ { sum += float64(y[iy]) * float64(x[ix]) ix += incX iy += incY } return } // Sum is // // var sum float32 // for _, v := range x { // sum += v // } // return sum func Sum(x []float32) float32 { var sum float32 for _, v := range x { sum += v } return sum } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/stubs_test.go000066400000000000000000000144131450372207100233550ustar00rootroot00000000000000// 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 f32_test import ( "testing" . "gonum.org/v1/gonum/internal/asm/f32" ) var tests = []struct { incX, incY, incDst uintptr ix, iy, idst uintptr a float32 dst, x, y []float32 ex []float32 }{ {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 3, dst: []float32{5}, x: []float32{2}, y: []float32{1}, ex: []float32{7}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 5, dst: []float32{0, 0, 0}, x: []float32{0, 0, 0}, y: []float32{1, 1, 1}, ex: []float32{1, 1, 1}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 5, dst: []float32{0, 0, 0}, x: []float32{0, 0}, y: []float32{1, 1, 1}, ex: []float32{1, 1}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: -1, dst: []float32{-1, -1, -1}, x: []float32{1, 1, 1}, y: []float32{1, 2, 1}, ex: []float32{0, 1, 0}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: -1, dst: []float32{1, 1, 1}, x: []float32{1, 2, 1}, y: []float32{-1, -2, -1}, ex: []float32{-2, -4, -2}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 2.5, dst: []float32{1, 1, 1, 1, 1}, x: []float32{1, 2, 3, 2, 1}, y: []float32{0, 0, 0, 0, 0}, ex: []float32{2.5, 5, 7.5, 5, 2.5}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, // Run big test twice, once aligned once unaligned. a: 16.5, dst: make([]float32, 20), x: []float32{.5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5, .5}, y: []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, ex: []float32{9.25, 10.25, 11.25, 12.25, 13.25, 14.25, 15.25, 16.25, 17.25, 18.25, 9.25, 10.25, 11.25, 12.25, 13.25, 14.25, 15.25, 16.25, 17.25, 18.25}}, {incX: 2, incY: 2, incDst: 3, ix: 0, iy: 0, idst: 0, a: 16.5, dst: make([]float32, 10), x: []float32{.5, .5, .5, .5, .5, .5, .5, .5, .5, .5}, y: []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, ex: []float32{9.25, 10.25, 11.25, 12.25, 13.25, 14.25, 15.25, 16.25, 17.25, 18.25}}, } func TestAxpyUnitary(t *testing.T) { for j, v := range tests { gdLn := 4 + j%2 v.x, v.y = guardVector(v.x, 1, gdLn), guardVector(v.y, 1, gdLn) x, y := v.x[gdLn:len(v.x)-gdLn], v.y[gdLn:len(v.y)-gdLn] AxpyUnitary(v.a, x, y) for i := range v.ex { if !same(y[i], v.ex[i]) { t.Error("Test", j, "Unexpected result at", i, "Got:", int(y[i]), "Expected:", v.ex[i]) } } if !isValidGuard(v.x, 1, gdLn) { t.Error("Test", j, "Guard violated in x vector", v.x[:gdLn], v.x[len(v.x)-gdLn:]) } if !isValidGuard(v.y, 1, gdLn) { t.Error("Test", j, "Guard violated in y vector", v.y[:gdLn], v.y[len(v.x)-gdLn:]) } } } func TestAxpyUnitaryTo(t *testing.T) { for j, v := range tests { gdLn := 4 + j%2 v.x, v.y = guardVector(v.x, 1, gdLn), guardVector(v.y, 1, gdLn) v.dst = guardVector(v.dst, 0, gdLn) x, y := v.x[gdLn:len(v.x)-gdLn], v.y[gdLn:len(v.y)-gdLn] dst := v.dst[gdLn : len(v.dst)-gdLn] AxpyUnitaryTo(dst, v.a, x, y) for i := range v.ex { if !same(v.ex[i], dst[i]) { t.Error("Test", j, "Unexpected result at", i, "Got:", dst[i], "Expected:", v.ex[i]) } } if !isValidGuard(v.x, 1, gdLn) { t.Error("Test", j, "Guard violated in x vector", v.x[:gdLn], v.x[len(v.x)-gdLn:]) } if !isValidGuard(v.y, 1, gdLn) { t.Error("Test", j, "Guard violated in y vector", v.y[:gdLn], v.y[len(v.x)-gdLn:]) } if !isValidGuard(v.dst, 0, gdLn) { t.Error("Test", j, "Guard violated in x vector", v.x[:gdLn], v.x[len(v.x)-gdLn:]) } } } func TestAxpyInc(t *testing.T) { for j, v := range tests { gdLn := 4 + j%2 v.x, v.y = guardIncVector(v.x, 1, int(v.incX), gdLn), guardIncVector(v.y, 1, int(v.incY), gdLn) x, y := v.x[gdLn:len(v.x)-gdLn], v.y[gdLn:len(v.y)-gdLn] AxpyInc(v.a, x, y, uintptr(len(v.ex)), v.incX, v.incY, v.ix, v.iy) for i := range v.ex { if !same(y[i*int(v.incY)], v.ex[i]) { t.Error("Test", j, "Unexpected result at", i, "Got:", y[i*int(v.incY)], "Expected:", v.ex[i]) t.Error("Result:", y) t.Error("Expect:", v.ex) } } checkValidIncGuard(t, v.x, 1, int(v.incX), gdLn) checkValidIncGuard(t, v.y, 1, int(v.incY), gdLn) } } func TestAxpyIncTo(t *testing.T) { for j, v := range tests { gdLn := 4 + j%2 v.x, v.y = guardIncVector(v.x, 1, int(v.incX), gdLn), guardIncVector(v.y, 1, int(v.incY), gdLn) v.dst = guardIncVector(v.dst, 0, int(v.incDst), gdLn) x, y := v.x[gdLn:len(v.x)-gdLn], v.y[gdLn:len(v.y)-gdLn] dst := v.dst[gdLn : len(v.dst)-gdLn] AxpyIncTo(dst, v.incDst, v.idst, v.a, x, y, uintptr(len(v.ex)), v.incX, v.incY, v.ix, v.iy) for i := range v.ex { if !same(dst[i*int(v.incDst)], v.ex[i]) { t.Error("Test", j, "Unexpected result at", i, "Got:", dst[i*int(v.incDst)], "Expected:", v.ex[i]) t.Error(v.dst) t.Error(v.ex) } } checkValidIncGuard(t, v.x, 1, int(v.incX), gdLn) checkValidIncGuard(t, v.y, 1, int(v.incY), gdLn) checkValidIncGuard(t, v.dst, 0, int(v.incDst), gdLn) } } func TestSum(t *testing.T) { var srcGd float32 = -1 for j, v := range []struct { src []float32 expect float32 }{ { src: []float32{}, expect: 0, }, { src: []float32{1}, expect: 1, }, { src: []float32{nan}, expect: nan, }, { src: []float32{1, 2, 3}, expect: 6, }, { src: []float32{1, -4, 3}, expect: 0, }, { src: []float32{1, 2, 3, 4}, expect: 10, }, { src: []float32{1, 1, nan, 1, 1}, expect: nan, }, { src: []float32{inf, 4, nan, -inf, 9}, expect: nan, }, { src: []float32{1, 1, 1, 1, 9, 1, 1, 1, 2, 1, 1, 1, 1, 1, 5, 1}, expect: 29, }, { src: []float32{1, 1, 1, 1, 9, 1, 1, 1, 2, 1, 1, 1, 1, 1, 5, 11, 1, 1, 1, 9, 1, 1, 1, 2, 1, 1, 1, 1, 1, 5, 1}, expect: 67, }, } { for _, i := range [4]int{0, 1, 2, 3} { gdLn := 4 + j%4 + i gsrc := guardVector(v.src, srcGd, gdLn) src := gsrc[gdLn : len(gsrc)-gdLn] ret := Sum(src) if !same(ret, v.expect) { t.Errorf("Test %d Sum error Got: %v Expected: %v", j, ret, v.expect) } if !isValidGuard(gsrc, srcGd, gdLn) { t.Errorf("Test %d Guard violated in src vector %v %v", j, gsrc[:gdLn], gsrc[len(gsrc)-gdLn:]) } } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f32/sum_amd64.s000066400000000000000000000043001450372207100226040ustar00rootroot00000000000000// Copyright ©2021 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define IDX AX #define LEN CX #define TAIL BX #define SUM X0 #define SUM_1 X1 #define SUM_2 X2 #define SUM_3 X3 // func Sum(x []float32) float32 TEXT ·Sum(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ x_len+8(FP), LEN // LEN = len(x) XORQ IDX, IDX // i = 0 PXOR SUM, SUM // p_sum_i = 0 CMPQ LEN, $0 // if LEN == 0 { return 0 } JE sum_end PXOR SUM_1, SUM_1 PXOR SUM_2, SUM_2 PXOR SUM_3, SUM_3 MOVQ X_PTR, TAIL // Check memory alignment ANDQ $15, TAIL // TAIL = &x % 16 JZ no_trim // if TAIL == 0 { goto no_trim } SUBQ $16, TAIL // TAIL -= 16 sum_align: // Align on 16-byte boundary do { ADDSS (X_PTR)(IDX*4), SUM // SUM += x[0] INCQ IDX // i++ DECQ LEN // LEN-- JZ sum_end // if LEN == 0 { return } ADDQ $4, TAIL // TAIL += 4 JNZ sum_align // } while TAIL < 0 no_trim: MOVQ LEN, TAIL SHRQ $4, LEN // LEN = floor( n / 16 ) JZ sum_tail8 // if LEN == 0 { goto sum_tail8 } sum_loop: // sum 16x wide do { ADDPS (X_PTR)(IDX*4), SUM // sum_i += x[i:i+4] ADDPS 16(X_PTR)(IDX*4), SUM_1 ADDPS 32(X_PTR)(IDX*4), SUM_2 ADDPS 48(X_PTR)(IDX*4), SUM_3 ADDQ $16, IDX // i += 16 DECQ LEN JNZ sum_loop // } while --LEN > 0 sum_tail8: ADDPS SUM_3, SUM ADDPS SUM_2, SUM_1 TESTQ $8, TAIL JZ sum_tail4 ADDPS (X_PTR)(IDX*4), SUM // sum_i += x[i:i+4] ADDPS 16(X_PTR)(IDX*4), SUM_1 ADDQ $8, IDX sum_tail4: ADDPS SUM_1, SUM TESTQ $4, TAIL JZ sum_tail2 ADDPS (X_PTR)(IDX*4), SUM // sum_i += x[i:i+4] ADDQ $4, IDX sum_tail2: HADDPS SUM, SUM // sum_i[:2] += sum_i[2:4] TESTQ $2, TAIL JZ sum_tail1 MOVSD (X_PTR)(IDX*4), SUM_1 // reuse SUM_1 ADDPS SUM_1, SUM // sum_i += x[i:i+2] ADDQ $2, IDX sum_tail1: HADDPS SUM, SUM // sum_i[0] += sum_i[1] TESTQ $1, TAIL JZ sum_end ADDSS (X_PTR)(IDX*4), SUM sum_end: // return sum MOVSS SUM, ret+24(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f32/util_test.go000066400000000000000000000061421450372207100231720ustar00rootroot00000000000000// 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 f32_test import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" ) const ( msgRes = "%v: unexpected result Got: %v Expected: %v" msgVal = "%v: unexpected value at %v Got: %v Expected: %v" msgGuard = "%v: guard violated in %s vector %v %v" msgReadOnly = "%v: modified read-only %v argument" ) var ( nan = float32(math.NaN()) inf = float32(math.Inf(1)) ) // sameApprox tests for nan-aware equality within tolerance. func sameApprox(x, y, tol float32) bool { a, b := float64(x), float64(y) return same(x, y) || scalar.EqualWithinAbsOrRel(a, b, float64(tol), float64(tol)) } func same(x, y float32) bool { return scalar.Same(float64(x), float64(y)) } // sameStrided returns true if the strided vector x contains elements of the // dense vector ref at indices i*inc, false otherwise. func sameStrided(ref, x []float32, inc int) bool { if inc < 0 { inc = -inc } for i, v := range ref { if !same(x[i*inc], v) { return false } } return true } func guardVector(v []float32, g float32, gdLn int) (guarded []float32) { guarded = make([]float32, len(v)+gdLn*2) copy(guarded[gdLn:], v) for i := 0; i < gdLn; i++ { guarded[i] = g guarded[len(guarded)-1-i] = g } return guarded } func isValidGuard(v []float32, g float32, gdLn int) bool { for i := 0; i < gdLn; i++ { if !same(v[i], g) || !same(v[len(v)-1-i], g) { return false } } return true } func guardIncVector(vec []float32, gdVal float32, inc, gdLen int) (guarded []float32) { if inc < 0 { inc = -inc } inrLen := len(vec) * inc guarded = make([]float32, inrLen+gdLen*2) for i := range guarded { guarded[i] = gdVal } for i, v := range vec { guarded[gdLen+i*inc] = v } return guarded } func checkValidIncGuard(t *testing.T, v []float32, g float32, inc, gdLn int) { srcLn := len(v) - 2*gdLn for i := range v { switch { case same(v[i], g): // Correct value case i < gdLn: t.Error("Front guard violated at", i, v[:gdLn]) case i > gdLn+srcLn: t.Error("Back guard violated at", i-gdLn-srcLn, v[gdLn+srcLn:]) case (i-gdLn)%inc == 0 && (i-gdLn)/inc < len(v): default: t.Error("Internal guard violated at", i-gdLn, v[gdLn:gdLn+srcLn]) } } } var ( // Offset sets for testing alignment handling in Unitary assembly functions. align2 = newIncSet(0, 1, 2, 3) align3 = newIncToSet(0, 1, 2, 3) ) type incSet struct { x, y int } // genInc will generate all (x,y) combinations of the input increment set. func newIncSet(inc ...int) []incSet { n := len(inc) is := make([]incSet, n*n) for x := range inc { for y := range inc { is[x*n+y] = incSet{inc[x], inc[y]} } } return is } type incToSet struct { dst, x, y int } // genIncTo will generate all (dst,x,y) combinations of the input increment set. func newIncToSet(inc ...int) []incToSet { n := len(inc) is := make([]incToSet, n*n*n) for i, dst := range inc { for x := range inc { for y := range inc { is[i*n*n+x*n+y] = incToSet{dst, inc[x], inc[y]} } } } return is } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/000077500000000000000000000000001450372207100206315ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/asm/f64/abssum_amd64.s000066400000000000000000000043371450372207100233110ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func L1Norm(x []float64) float64 TEXT ·L1Norm(SB), NOSPLIT, $0 MOVQ x_base+0(FP), SI // SI = &x MOVQ x_len+8(FP), CX // CX = len(x) XORQ AX, AX // i = 0 PXOR X0, X0 // p_sum_i = 0 PXOR X1, X1 PXOR X2, X2 PXOR X3, X3 PXOR X4, X4 PXOR X5, X5 PXOR X6, X6 PXOR X7, X7 CMPQ CX, $0 // if CX == 0 { return 0 } JE absum_end MOVQ CX, BX ANDQ $7, BX // BX = len(x) % 8 SHRQ $3, CX // CX = floor( len(x) / 8 ) JZ absum_tail_start // if CX == 0 { goto absum_tail_start } absum_loop: // do { // p_sum += max( p_sum + x[i], p_sum - x[i] ) MOVUPS (SI)(AX*8), X8 // X_i = x[i:i+1] MOVUPS 16(SI)(AX*8), X9 MOVUPS 32(SI)(AX*8), X10 MOVUPS 48(SI)(AX*8), X11 ADDPD X8, X0 // p_sum_i += X_i ( positive values ) ADDPD X9, X2 ADDPD X10, X4 ADDPD X11, X6 SUBPD X8, X1 // p_sum_(i+1) -= X_i ( negative values ) SUBPD X9, X3 SUBPD X10, X5 SUBPD X11, X7 MAXPD X1, X0 // p_sum_i = max( p_sum_i, p_sum_(i+1) ) MAXPD X3, X2 MAXPD X5, X4 MAXPD X7, X6 MOVAPS X0, X1 // p_sum_(i+1) = p_sum_i MOVAPS X2, X3 MOVAPS X4, X5 MOVAPS X6, X7 ADDQ $8, AX // i += 8 LOOP absum_loop // } while --CX > 0 // p_sum_0 = \sum_{i=1}^{3}( p_sum_(i*2) ) ADDPD X3, X0 ADDPD X5, X7 ADDPD X7, X0 // p_sum_0[0] = p_sum_0[0] + p_sum_0[1] MOVAPS X0, X1 SHUFPD $0x3, X0, X0 // lower( p_sum_0 ) = upper( p_sum_0 ) ADDSD X1, X0 CMPQ BX, $0 JE absum_end // if BX == 0 { goto absum_end } absum_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX XORPS X8, X8 // X_8 = 0 absum_tail: // do { // p_sum += max( p_sum + x[i], p_sum - x[i] ) MOVSD (SI)(AX*8), X8 // X_8 = x[i] MOVSD X0, X1 // p_sum_1 = p_sum_0 ADDSD X8, X0 // p_sum_0 += X_8 SUBSD X8, X1 // p_sum_1 -= X_8 MAXSD X1, X0 // p_sum_0 = max( p_sum_0, p_sum_1 ) INCQ AX // i++ LOOP absum_tail // } while --CX > 0 absum_end: // return p_sum_0 MOVSD X0, sum+24(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/abssuminc_amd64.s000066400000000000000000000047071450372207100240040ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func L1NormInc(x []float64, n, incX int) (sum float64) TEXT ·L1NormInc(SB), NOSPLIT, $0 MOVQ x_base+0(FP), SI // SI = &x MOVQ n+24(FP), CX // CX = n MOVQ incX+32(FP), AX // AX = increment * sizeof( float64 ) SHLQ $3, AX MOVQ AX, DX // DX = AX * 3 IMULQ $3, DX PXOR X0, X0 // p_sum_i = 0 PXOR X1, X1 PXOR X2, X2 PXOR X3, X3 PXOR X4, X4 PXOR X5, X5 PXOR X6, X6 PXOR X7, X7 CMPQ CX, $0 // if CX == 0 { return 0 } JE absum_end MOVQ CX, BX ANDQ $7, BX // BX = n % 8 SHRQ $3, CX // CX = floor( n / 8 ) JZ absum_tail_start // if CX == 0 { goto absum_tail_start } absum_loop: // do { // p_sum = max( p_sum + x[i], p_sum - x[i] ) MOVSD (SI), X8 // X_i[0] = x[i] MOVSD (SI)(AX*1), X9 MOVSD (SI)(AX*2), X10 MOVSD (SI)(DX*1), X11 LEAQ (SI)(AX*4), SI // SI = SI + 4 MOVHPD (SI), X8 // X_i[1] = x[i+4] MOVHPD (SI)(AX*1), X9 MOVHPD (SI)(AX*2), X10 MOVHPD (SI)(DX*1), X11 ADDPD X8, X0 // p_sum_i += X_i ( positive values ) ADDPD X9, X2 ADDPD X10, X4 ADDPD X11, X6 SUBPD X8, X1 // p_sum_(i+1) -= X_i ( negative values ) SUBPD X9, X3 SUBPD X10, X5 SUBPD X11, X7 MAXPD X1, X0 // p_sum_i = max( p_sum_i, p_sum_(i+1) ) MAXPD X3, X2 MAXPD X5, X4 MAXPD X7, X6 MOVAPS X0, X1 // p_sum_(i+1) = p_sum_i MOVAPS X2, X3 MOVAPS X4, X5 MOVAPS X6, X7 LEAQ (SI)(AX*4), SI // SI = SI + 4 LOOP absum_loop // } while --CX > 0 // p_sum_0 = \sum_{i=1}^{3}( p_sum_(i*2) ) ADDPD X3, X0 ADDPD X5, X7 ADDPD X7, X0 // p_sum_0[0] = p_sum_0[0] + p_sum_0[1] MOVAPS X0, X1 SHUFPD $0x3, X0, X0 // lower( p_sum_0 ) = upper( p_sum_0 ) ADDSD X1, X0 CMPQ BX, $0 JE absum_end // if BX == 0 { goto absum_end } absum_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX XORPS X8, X8 // X_8 = 0 absum_tail: // do { // p_sum += max( p_sum + x[i], p_sum - x[i] ) MOVSD (SI), X8 // X_8 = x[i] MOVSD X0, X1 // p_sum_1 = p_sum_0 ADDSD X8, X0 // p_sum_0 += X_8 SUBSD X8, X1 // p_sum_1 -= X_8 MAXSD X1, X0 // p_sum_0 = max( p_sum_0, p_sum_1 ) ADDQ AX, SI // i++ LOOP absum_tail // } while --CX > 0 absum_end: // return p_sum_0 MOVSD X0, sum+40(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/add_amd64.s000066400000000000000000000036441450372207100225470ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func Add(dst, s []float64) TEXT ·Add(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ dst_len+8(FP), CX // CX = len(dst) MOVQ s_base+24(FP), SI // SI = &s CMPQ s_len+32(FP), CX // CX = max( CX, len(s) ) CMOVQLE s_len+32(FP), CX CMPQ CX, $0 // if CX == 0 { return } JE add_end XORQ AX, AX MOVQ DI, BX ANDQ $0x0F, BX // BX = &dst & 15 JZ add_no_trim // if BX == 0 { goto add_no_trim } // Align on 16-bit boundary MOVSD (SI)(AX*8), X0 // X0 = s[i] ADDSD (DI)(AX*8), X0 // X0 += dst[i] MOVSD X0, (DI)(AX*8) // dst[i] = X0 INCQ AX // i++ DECQ CX // --CX JE add_end // if CX == 0 { return } add_no_trim: MOVQ CX, BX ANDQ $7, BX // BX = len(dst) % 8 SHRQ $3, CX // CX = floor( len(dst) / 8 ) JZ add_tail_start // if CX == 0 { goto add_tail_start } add_loop: // Loop unrolled 8x do { MOVUPS (SI)(AX*8), X0 // X_i = s[i:i+1] MOVUPS 16(SI)(AX*8), X1 MOVUPS 32(SI)(AX*8), X2 MOVUPS 48(SI)(AX*8), X3 ADDPD (DI)(AX*8), X0 // X_i += dst[i:i+1] ADDPD 16(DI)(AX*8), X1 ADDPD 32(DI)(AX*8), X2 ADDPD 48(DI)(AX*8), X3 MOVUPS X0, (DI)(AX*8) // dst[i:i+1] = X_i MOVUPS X1, 16(DI)(AX*8) MOVUPS X2, 32(DI)(AX*8) MOVUPS X3, 48(DI)(AX*8) ADDQ $8, AX // i += 8 LOOP add_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE add_end add_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX add_tail: // do { MOVSD (SI)(AX*8), X0 // X0 = s[i] ADDSD (DI)(AX*8), X0 // X0 += dst[i] MOVSD X0, (DI)(AX*8) // dst[i] = X0 INCQ AX // ++i LOOP add_tail // } while --CX > 0 add_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/addconst_amd64.s000066400000000000000000000027721450372207100236170ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func Addconst(alpha float64, x []float64) TEXT ·AddConst(SB), NOSPLIT, $0 MOVQ x_base+8(FP), SI // SI = &x MOVQ x_len+16(FP), CX // CX = len(x) CMPQ CX, $0 // if len(x) == 0 { return } JE ac_end MOVSD alpha+0(FP), X4 // X4 = { a, a } SHUFPD $0, X4, X4 MOVUPS X4, X5 // X5 = X4 XORQ AX, AX // i = 0 MOVQ CX, BX ANDQ $7, BX // BX = len(x) % 8 SHRQ $3, CX // CX = floor( len(x) / 8 ) JZ ac_tail_start // if CX == 0 { goto ac_tail_start } ac_loop: // Loop unrolled 8x do { MOVUPS (SI)(AX*8), X0 // X_i = s[i:i+1] MOVUPS 16(SI)(AX*8), X1 MOVUPS 32(SI)(AX*8), X2 MOVUPS 48(SI)(AX*8), X3 ADDPD X4, X0 // X_i += a ADDPD X5, X1 ADDPD X4, X2 ADDPD X5, X3 MOVUPS X0, (SI)(AX*8) // s[i:i+1] = X_i MOVUPS X1, 16(SI)(AX*8) MOVUPS X2, 32(SI)(AX*8) MOVUPS X3, 48(SI)(AX*8) ADDQ $8, AX // i += 8 LOOP ac_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE ac_end ac_tail_start: // Reset loop counters MOVQ BX, CX // Loop counter: CX = BX ac_tail: // do { MOVSD (SI)(AX*8), X0 // X0 = s[i] ADDSD X4, X0 // X0 += a MOVSD X0, (SI)(AX*8) // s[i] = X0 INCQ AX // ++i LOOP ac_tail // } while --CX > 0 ac_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/asm_test.go000066400000000000000000000122311450372207100227760ustar00rootroot00000000000000// 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 f64_test import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) const ( msgVal = "%v: unexpected value at %v Got: %v Expected: %v" msgGuard = "%v: Guard violated in %s vector %v %v" msgReadOnly = "%v: modified read-only %v argument" ) var ( nan = math.NaN() inf = math.Inf(1) ) // newGuardedVector allocates a new slice and returns it as three subslices. // v is a strided vector that contains elements of data at indices i*inc and // NaN elsewhere. frontGuard and backGuard are filled with NaN values, and // their backing arrays are directly adjacent to v in memory. The three slices // can be used to detect invalid memory reads and writes. func newGuardedVector(data []float64, inc int) (v, frontGuard, backGuard []float64) { if inc < 0 { inc = -inc } guard := 2 * inc size := (len(data)-1)*inc + 1 whole := make([]float64, size+2*guard) v = whole[guard : len(whole)-guard] for i := range whole { whole[i] = math.NaN() } for i, d := range data { v[i*inc] = d } return v, whole[:guard], whole[len(whole)-guard:] } // allNaN returns true if x contains only NaN values, and false otherwise. func allNaN(x []float64) bool { for _, v := range x { if !math.IsNaN(v) { return false } } return true } // equalStrided returns true if the strided vector x contains elements of the // dense vector ref at indices i*inc, false otherwise. func equalStrided(ref, x []float64, inc int) bool { if inc < 0 { inc = -inc } for i, v := range ref { if !scalar.Same(x[i*inc], v) { return false } } return true } // nonStridedWrite returns false if all elements of x at non-stride indices are // equal to NaN, true otherwise. func nonStridedWrite(x []float64, inc int) bool { if inc < 0 { inc = -inc } for i, v := range x { if i%inc != 0 && !math.IsNaN(v) { return true } } return false } // guardVector copies the source vector (vec) into a new slice with guards. // Guards guarded[:gdLn] and guarded[len-gdLn:] will be filled with sigil value gdVal. func guardVector(vec []float64, gdVal float64, gdLn int) (guarded []float64) { guarded = make([]float64, len(vec)+gdLn*2) copy(guarded[gdLn:], vec) for i := 0; i < gdLn; i++ { guarded[i] = gdVal guarded[len(guarded)-1-i] = gdVal } return guarded } // isValidGuard will test for violated guards, generated by guardVector. func isValidGuard(vec []float64, gdVal float64, gdLn int) bool { for i := 0; i < gdLn; i++ { if !scalar.Same(vec[i], gdVal) || !scalar.Same(vec[len(vec)-1-i], gdVal) { return false } } return true } // guardIncVector copies the source vector (vec) into a new incremented slice with guards. // End guards will be length gdLen. // Internal and end guards will be filled with sigil value gdVal. func guardIncVector(vec []float64, gdVal float64, inc, gdLen int) (guarded []float64) { if inc < 0 { inc = -inc } inrLen := len(vec) * inc guarded = make([]float64, inrLen+gdLen*2) for i := range guarded { guarded[i] = gdVal } for i, v := range vec { guarded[gdLen+i*inc] = v } return guarded } // checkValidIncGuard will test for violated guards, generated by guardIncVector func checkValidIncGuard(t *testing.T, vec []float64, gdVal float64, inc, gdLen int) { srcLn := len(vec) - 2*gdLen for i := range vec { switch { case scalar.Same(vec[i], gdVal): // Correct value case (i-gdLen)%inc == 0 && (i-gdLen)/inc < len(vec): // Ignore input values case i < gdLen: t.Errorf("Front guard violated at %d %v", i, vec[:gdLen]) case i > gdLen+srcLn: t.Errorf("Back guard violated at %d %v", i-gdLen-srcLn, vec[gdLen+srcLn:]) default: t.Errorf("Internal guard violated at %d %v", i-gdLen, vec[gdLen:gdLen+srcLn]) } } } // sameApprox tests for nan-aware equality within tolerance. func sameApprox(a, b, tol float64) bool { return scalar.Same(a, b) || scalar.EqualWithinAbsOrRel(a, b, tol, tol) } var ( // Offset sets for testing alignment handling in Unitary assembly functions. align1 = []int{0, 1} align2 = newIncSet(0, 1) align3 = newIncToSet(0, 1) ) type incSet struct { x, y int } // genInc will generate all (x,y) combinations of the input increment set. func newIncSet(inc ...int) []incSet { n := len(inc) is := make([]incSet, n*n) for x := range inc { for y := range inc { is[x*n+y] = incSet{inc[x], inc[y]} } } return is } type incToSet struct { dst, x, y int } // genIncTo will generate all (dst,x,y) combinations of the input increment set. func newIncToSet(inc ...int) []incToSet { n := len(inc) is := make([]incToSet, n*n*n) for i, dst := range inc { for x := range inc { for y := range inc { is[i*n*n+x*n+y] = incToSet{dst, inc[x], inc[y]} } } } return is } var benchSink []float64 func randomSlice(n, inc int) []float64 { if inc < 0 { inc = -inc } x := make([]float64, (n-1)*inc+1) for i := range x { x[i] = rand.Float64() } return x } func randSlice(n, inc int, r *rand.Rand) []float64 { if inc < 0 { inc = -inc } x := make([]float64, (n-1)*inc+1) for i := range x { x[i] = r.Float64() } return x } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/axpy.go000066400000000000000000000024001450372207100221350ustar00rootroot00000000000000// 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f64 // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha float64, x, y []float64) { for i, v := range x { y[i] += alpha * v } } // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []float64, alpha float64, x, y []float64) { for i, v := range x { dst[i] = alpha*v + y[i] } } // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []float64, incDst, idst uintptr, alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/axpy_test.go000066400000000000000000000166231450372207100232100ustar00rootroot00000000000000// 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 f64_test import ( "fmt" "testing" "gonum.org/v1/gonum/floats/scalar" . "gonum.org/v1/gonum/internal/asm/f64" ) var axpyTests = []struct { alpha float64 x []float64 y []float64 want []float64 wantRev []float64 // Result when x is traversed in reverse direction. }{ { alpha: 0, x: []float64{}, y: []float64{}, want: []float64{}, wantRev: []float64{}, }, { alpha: 0, x: []float64{2}, y: []float64{-3}, want: []float64{-3}, wantRev: []float64{-3}, }, { alpha: 1, x: []float64{2}, y: []float64{-3}, want: []float64{-1}, wantRev: []float64{-1}, }, { alpha: 3, x: []float64{2}, y: []float64{-3}, want: []float64{3}, wantRev: []float64{3}, }, { alpha: -3, x: []float64{2}, y: []float64{-3}, want: []float64{-9}, wantRev: []float64{-9}, }, { alpha: 1, x: []float64{1, 5}, y: []float64{2, -3}, want: []float64{3, 2}, wantRev: []float64{7, -2}, }, { alpha: 1, x: []float64{2, 3, 4}, y: []float64{-3, -2, -1}, want: []float64{-1, 1, 3}, wantRev: []float64{1, 1, 1}, }, { alpha: 0, x: []float64{0, 0, 1, 1, 2, -3, -4}, y: []float64{0, 1, 0, 3, -4, 5, -6}, want: []float64{0, 1, 0, 3, -4, 5, -6}, wantRev: []float64{0, 1, 0, 3, -4, 5, -6}, }, { alpha: 1, x: []float64{0, 0, 1, 1, 2, -3, -4}, y: []float64{0, 1, 0, 3, -4, 5, -6}, want: []float64{0, 1, 1, 4, -2, 2, -10}, wantRev: []float64{-4, -2, 2, 4, -3, 5, -6}, }, { alpha: 3, x: []float64{0, 0, 1, 1, 2, -3, -4}, y: []float64{0, 1, 0, 3, -4, 5, -6}, want: []float64{0, 1, 3, 6, 2, -4, -18}, wantRev: []float64{-12, -8, 6, 6, -1, 5, -6}, }, { alpha: -3, x: []float64{0, 0, 1, 1, 2, -3, -4, 0, 0, 1, 1, 2, -3, -4}, y: []float64{0, 1, 0, 3, -4, 5, -6, 0, 1, 0, 3, -4, 5, -6}, want: []float64{0, 1, -3, 0, -10, 14, 6, 0, 1, -3, 0, -10, 14, 6}, wantRev: []float64{12, 10, -6, 0, -7, 5, -6, 12, 10, -6, 0, -7, 5, -6}, }, { alpha: -5, x: []float64{0, 0, 1, 1, 2, -3, -4, 5, 1, 2, -3, -4, 5}, y: []float64{0, 1, 0, 3, -4, 5, -6, 7, 3, -4, 5, -6, 7}, want: []float64{0, 1, -5, -2, -14, 20, 14, -18, -2, -14, 20, 14, -18}, wantRev: []float64{-25, 21, 15, -7, -9, -20, 14, 22, -7, -9, 0, -6, 7}, }, } func TestAxpyUnitary(t *testing.T) { const xGdVal, yGdVal = -1, 0.5 for i, test := range axpyTests { for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v y:%v)", i, align.x, align.y) xgLn, ygLn := 4+align.x, 4+align.y xg, yg := guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] AxpyUnitary(test.alpha, x, y) for i := range test.want { if !scalar.Same(y[i], test.want[i]) { t.Errorf(msgVal, prefix, i, y[i], test.want[i]) } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, yGdVal, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } if !equalStrided(test.x, x, 1) { t.Errorf("%v: modified read-only x argument", prefix) } } } } func TestAxpyUnitaryTo(t *testing.T) { const dstGdVal, xGdVal, yGdVal = 1, -1, 0.5 for i, test := range axpyTests { for _, align := range align3 { prefix := fmt.Sprintf("Test %v (x:%v y:%v dst:%v)", i, align.x, align.y, align.dst) dgLn, xgLn, ygLn := 4+align.dst, 4+align.x, 4+align.y dstOrig := make([]float64, len(test.x)) xg, yg := guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) dstg := guardVector(dstOrig, dstGdVal, dgLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] dst := dstg[dgLn : len(dstg)-dgLn] AxpyUnitaryTo(dst, test.alpha, x, y) for i := range test.want { if !scalar.Same(dst[i], test.want[i]) { t.Errorf(msgVal, prefix, i, dst[i], test.want[i]) } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, yGdVal, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } if !isValidGuard(dstg, dstGdVal, dgLn) { t.Errorf(msgGuard, prefix, "dst", dstg[:dgLn], dstg[len(dstg)-dgLn:]) } if !equalStrided(test.x, x, 1) { t.Errorf("%v: modified read-only x argument", prefix) } if !equalStrided(test.y, y, 1) { t.Errorf("%v: modified read-only y argument", prefix) } } } } func TestAxpyInc(t *testing.T) { const xGdVal, yGdVal = -1, 0.5 gdLn := 4 for i, test := range axpyTests { n := len(test.x) for _, inc := range newIncSet(-7, -4, -3, -2, -1, 1, 2, 3, 4, 7) { var ix, iy int if inc.x < 0 { ix = (-n + 1) * inc.x } if inc.y < 0 { iy = (-n + 1) * inc.y } prefix := fmt.Sprintf("test %v, inc.x = %v, inc.y = %v", i, inc.x, inc.y) xg := guardIncVector(test.x, xGdVal, inc.x, gdLn) yg := guardIncVector(test.y, yGdVal, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] AxpyInc(test.alpha, x, y, uintptr(n), uintptr(inc.x), uintptr(inc.y), uintptr(ix), uintptr(iy)) want := test.want if inc.x*inc.y < 0 { want = test.wantRev } if inc.y < 0 { inc.y = -inc.y } for i := range want { if !scalar.Same(y[i*inc.y], want[i]) { t.Errorf(msgVal, prefix, i, y[iy+i*inc.y], want[i]) } } if !equalStrided(test.x, x, inc.x) { t.Errorf("%v: modified read-only x argument", prefix) } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) } } } func TestAxpyIncTo(t *testing.T) { const dstGdVal, xGdVal, yGdVal = 1, -1, 0.5 var want []float64 gdLn := 4 for i, test := range axpyTests { n := len(test.x) for _, inc := range newIncToSet(-7, -4, -3, -2, -1, 1, 2, 3, 4, 7) { var ix, iy, idst uintptr if inc.x < 0 { ix = uintptr((-n + 1) * inc.x) } if inc.y < 0 { iy = uintptr((-n + 1) * inc.y) } if inc.dst < 0 { idst = uintptr((-n + 1) * inc.dst) } prefix := fmt.Sprintf("Test %v: (x: %v, y: %v, dst:%v)", i, inc.x, inc.y, inc.dst) dstOrig := make([]float64, len(test.want)) xg := guardIncVector(test.x, xGdVal, inc.x, gdLn) yg := guardIncVector(test.y, yGdVal, inc.y, gdLn) dstg := guardIncVector(dstOrig, dstGdVal, inc.dst, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] dst := dstg[gdLn : len(dstg)-gdLn] AxpyIncTo(dst, uintptr(inc.dst), idst, test.alpha, x, y, uintptr(n), uintptr(inc.x), uintptr(inc.y), ix, iy) want = test.want if inc.x*inc.y < 0 { want = test.wantRev } iW, incW := 0, 1 if inc.y*inc.dst < 0 { iW, incW = len(want)-1, -1 } if inc.dst < 0 { inc.dst = -inc.dst } for i := range want { if !scalar.Same(dst[i*inc.dst], want[iW+i*incW]) { t.Errorf(msgVal, prefix, i, dst[i*inc.dst], want[iW+i*incW]) } } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) checkValidIncGuard(t, dstg, dstGdVal, inc.dst, gdLn) if !equalStrided(test.x, x, inc.x) { t.Errorf("%v: modified read-only x argument", prefix) } if !equalStrided(test.y, y, inc.y) { t.Errorf("%v: modified read-only y argument", prefix) } } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/axpyinc_amd64.s000066400000000000000000000113651450372207100234710ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define Y_PTR DI #define DST_PTR DI #define IDX AX #define LEN CX #define TAIL BX #define INC_X R8 #define INCx3_X R11 #define INC_Y R9 #define INCx3_Y R12 #define INC_DST R9 #define INCx3_DST R12 #define ALPHA X0 #define ALPHA_2 X1 // func AxpyInc(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) TEXT ·AxpyInc(SB), NOSPLIT, $0 MOVQ x_base+8(FP), X_PTR // X_PTR = &x MOVQ y_base+32(FP), Y_PTR // Y_PTR = &y MOVQ n+56(FP), LEN // LEN = n CMPQ LEN, $0 // if LEN == 0 { return } JE end MOVQ ix+80(FP), INC_X MOVQ iy+88(FP), INC_Y LEAQ (X_PTR)(INC_X*8), X_PTR // X_PTR = &(x[ix]) LEAQ (Y_PTR)(INC_Y*8), Y_PTR // Y_PTR = &(y[iy]) MOVQ Y_PTR, DST_PTR // DST_PTR = Y_PTR // Write pointer MOVQ incX+64(FP), INC_X // INC_X = incX * sizeof(float64) SHLQ $3, INC_X MOVQ incY+72(FP), INC_Y // INC_Y = incY * sizeof(float64) SHLQ $3, INC_Y MOVSD alpha+0(FP), ALPHA // ALPHA = alpha MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = n % 4 SHRQ $2, LEN // LEN = floor( n / 4 ) JZ tail_start // if LEN == 0 { goto tail_start } MOVAPS ALPHA, ALPHA_2 // ALPHA_2 = ALPHA for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = INC_Y * 3 loop: // do { // y[i] += alpha * x[i] unrolled 4x. MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MOVSD (X_PTR)(INC_X*2), X4 MOVSD (X_PTR)(INCx3_X*1), X5 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA_2, X3 MULSD ALPHA, X4 MULSD ALPHA_2, X5 ADDSD (Y_PTR), X2 // X_i += y[i] ADDSD (Y_PTR)(INC_Y*1), X3 ADDSD (Y_PTR)(INC_Y*2), X4 ADDSD (Y_PTR)(INCx3_Y*1), X5 MOVSD X2, (DST_PTR) // y[i] = X_i MOVSD X3, (DST_PTR)(INC_DST*1) MOVSD X4, (DST_PTR)(INC_DST*2) MOVSD X5, (DST_PTR)(INCx3_DST*1) LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[incX*4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[incY*4]) DECQ LEN JNZ loop // } while --LEN > 0 CMPQ TAIL, $0 // if TAIL == 0 { return } JE end tail_start: // Reset Loop registers MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( LEN / 2 ) JZ tail_one tail_two: MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA, X3 ADDSD (Y_PTR), X2 // X_i += y[i] ADDSD (Y_PTR)(INC_Y*1), X3 MOVSD X2, (DST_PTR) // y[i] = X_i MOVSD X3, (DST_PTR)(INC_DST*1) LEAQ (X_PTR)(INC_X*2), X_PTR // X_PTR = &(X_PTR[incX*2]) LEAQ (Y_PTR)(INC_Y*2), Y_PTR // Y_PTR = &(Y_PTR[incY*2]) ANDQ $1, TAIL JZ end // if TAIL == 0 { goto end } tail_one: // y[i] += alpha * x[i] for the last n % 4 iterations. MOVSD (X_PTR), X2 // X2 = x[i] MULSD ALPHA, X2 // X2 *= a ADDSD (Y_PTR), X2 // X2 += y[i] MOVSD X2, (DST_PTR) // y[i] = X2 end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/axpyincto_amd64.s000066400000000000000000000121761450372207100240350ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define Y_PTR DI #define DST_PTR DX #define IDX AX #define LEN CX #define TAIL BX #define INC_X R8 #define INCx3_X R11 #define INC_Y R9 #define INCx3_Y R12 #define INC_DST R10 #define INCx3_DST R13 #define ALPHA X0 #define ALPHA_2 X1 // func AxpyIncTo(dst []float64, incDst, idst uintptr, alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) TEXT ·AxpyIncTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DST_PTR // DST_PTR := &dst MOVQ x_base+48(FP), X_PTR // X_PTR := &x MOVQ y_base+72(FP), Y_PTR // Y_PTR := &y MOVQ n+96(FP), LEN // LEN := n CMPQ LEN, $0 // if LEN == 0 { return } JE end MOVQ ix+120(FP), INC_X LEAQ (X_PTR)(INC_X*8), X_PTR // X_PTR = &(x[ix]) MOVQ iy+128(FP), INC_Y LEAQ (Y_PTR)(INC_Y*8), Y_PTR // Y_PTR = &(dst[idst]) MOVQ idst+32(FP), INC_DST LEAQ (DST_PTR)(INC_DST*8), DST_PTR // DST_PTR = &(y[iy]) MOVQ incX+104(FP), INC_X // INC_X = incX * sizeof(float64) SHLQ $3, INC_X MOVQ incY+112(FP), INC_Y // INC_Y = incY * sizeof(float64) SHLQ $3, INC_Y MOVQ incDst+24(FP), INC_DST // INC_DST = incDst * sizeof(float64) SHLQ $3, INC_DST MOVSD alpha+40(FP), ALPHA MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = n % 4 SHRQ $2, LEN // LEN = floor( n / 4 ) JZ tail_start // if LEN == 0 { goto tail_start } MOVSD ALPHA, ALPHA_2 // ALPHA_2 = ALPHA for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 LEAQ (INC_Y)(INC_Y*2), INCx3_Y // INCx3_Y = INC_Y * 3 LEAQ (INC_DST)(INC_DST*2), INCx3_DST // INCx3_DST = INC_DST * 3 loop: // do { // y[i] += alpha * x[i] unrolled 2x. MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MOVSD (X_PTR)(INC_X*2), X4 MOVSD (X_PTR)(INCx3_X*1), X5 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA_2, X3 MULSD ALPHA, X4 MULSD ALPHA_2, X5 ADDSD (Y_PTR), X2 // X_i += y[i] ADDSD (Y_PTR)(INC_Y*1), X3 ADDSD (Y_PTR)(INC_Y*2), X4 ADDSD (Y_PTR)(INCx3_Y*1), X5 MOVSD X2, (DST_PTR) // y[i] = X_i MOVSD X3, (DST_PTR)(INC_DST*1) MOVSD X4, (DST_PTR)(INC_DST*2) MOVSD X5, (DST_PTR)(INCx3_DST*1) LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[incX*4]) LEAQ (Y_PTR)(INC_Y*4), Y_PTR // Y_PTR = &(Y_PTR[incY*4]) LEAQ (DST_PTR)(INC_DST*4), DST_PTR // DST_PTR = &(DST_PTR[incDst*4] DECQ LEN JNZ loop // } while --LEN > 0 CMPQ TAIL, $0 // if TAIL == 0 { return } JE end tail_start: // Reset Loop registers MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( LEN / 2 ) JZ tail_one tail_two: MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA, X3 ADDSD (Y_PTR), X2 // X_i += y[i] ADDSD (Y_PTR)(INC_Y*1), X3 MOVSD X2, (DST_PTR) // y[i] = X_i MOVSD X3, (DST_PTR)(INC_DST*1) LEAQ (X_PTR)(INC_X*2), X_PTR // X_PTR = &(X_PTR[incX*2]) LEAQ (Y_PTR)(INC_Y*2), Y_PTR // Y_PTR = &(Y_PTR[incY*2]) LEAQ (DST_PTR)(INC_DST*2), DST_PTR // DST_PTR = &(DST_PTR[incY*2] ANDQ $1, TAIL JZ end // if TAIL == 0 { goto end } tail_one: MOVSD (X_PTR), X2 // X2 = x[i] MULSD ALPHA, X2 // X2 *= a ADDSD (Y_PTR), X2 // X2 += y[i] MOVSD X2, (DST_PTR) // y[i] = X2 end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/axpyunitary_amd64.s000066400000000000000000000107041450372207100244070ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define Y_PTR DI #define DST_PTR DI #define IDX AX #define LEN CX #define TAIL BX #define ALPHA X0 #define ALPHA_2 X1 // func AxpyUnitary(alpha float64, x, y []float64) TEXT ·AxpyUnitary(SB), NOSPLIT, $0 MOVQ x_base+8(FP), X_PTR // X_PTR := &x MOVQ y_base+32(FP), Y_PTR // Y_PTR := &y MOVQ x_len+16(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+40(FP), LEN CMOVQLE y_len+40(FP), LEN CMPQ LEN, $0 // if LEN == 0 { return } JE end XORQ IDX, IDX MOVSD alpha+0(FP), ALPHA // ALPHA := { alpha, alpha } SHUFPD $0, ALPHA, ALPHA MOVUPS ALPHA, ALPHA_2 // ALPHA_2 := ALPHA for pipelining MOVQ Y_PTR, TAIL // Check memory alignment ANDQ $15, TAIL // TAIL = &y % 16 JZ no_trim // if TAIL == 0 { goto no_trim } // Align on 16-byte boundary MOVSD (X_PTR), X2 // X2 := x[0] MULSD ALPHA, X2 // X2 *= a ADDSD (Y_PTR), X2 // X2 += y[0] MOVSD X2, (DST_PTR) // y[0] = X2 INCQ IDX // i++ DECQ LEN // LEN-- JZ end // if LEN == 0 { return } no_trim: MOVQ LEN, TAIL ANDQ $7, TAIL // TAIL := n % 8 SHRQ $3, LEN // LEN = floor( n / 8 ) JZ tail_start // if LEN == 0 { goto tail2_start } loop: // do { // y[i] += alpha * x[i] unrolled 8x. MOVUPS (X_PTR)(IDX*8), X2 // X_i = x[i] MOVUPS 16(X_PTR)(IDX*8), X3 MOVUPS 32(X_PTR)(IDX*8), X4 MOVUPS 48(X_PTR)(IDX*8), X5 MULPD ALPHA, X2 // X_i *= a MULPD ALPHA_2, X3 MULPD ALPHA, X4 MULPD ALPHA_2, X5 ADDPD (Y_PTR)(IDX*8), X2 // X_i += y[i] ADDPD 16(Y_PTR)(IDX*8), X3 ADDPD 32(Y_PTR)(IDX*8), X4 ADDPD 48(Y_PTR)(IDX*8), X5 MOVUPS X2, (DST_PTR)(IDX*8) // y[i] = X_i MOVUPS X3, 16(DST_PTR)(IDX*8) MOVUPS X4, 32(DST_PTR)(IDX*8) MOVUPS X5, 48(DST_PTR)(IDX*8) ADDQ $8, IDX // i += 8 DECQ LEN JNZ loop // } while --LEN > 0 CMPQ TAIL, $0 // if TAIL == 0 { return } JE end tail_start: // Reset loop registers MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( TAIL / 2 ) JZ tail_one // if TAIL == 0 { goto tail } tail_two: // do { MOVUPS (X_PTR)(IDX*8), X2 // X2 = x[i] MULPD ALPHA, X2 // X2 *= a ADDPD (Y_PTR)(IDX*8), X2 // X2 += y[i] MOVUPS X2, (DST_PTR)(IDX*8) // y[i] = X2 ADDQ $2, IDX // i += 2 DECQ LEN JNZ tail_two // } while --LEN > 0 ANDQ $1, TAIL JZ end // if TAIL == 0 { goto end } tail_one: MOVSD (X_PTR)(IDX*8), X2 // X2 = x[i] MULSD ALPHA, X2 // X2 *= a ADDSD (Y_PTR)(IDX*8), X2 // X2 += y[i] MOVSD X2, (DST_PTR)(IDX*8) // y[i] = X2 end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/axpyunitaryto_amd64.s000066400000000000000000000111271450372207100247520ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define Y_PTR DX #define DST_PTR DI #define IDX AX #define LEN CX #define TAIL BX #define ALPHA X0 #define ALPHA_2 X1 // func AxpyUnitaryTo(dst []float64, alpha float64, x, y []float64) TEXT ·AxpyUnitaryTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DST_PTR // DST_PTR := &dst MOVQ x_base+32(FP), X_PTR // X_PTR := &x MOVQ y_base+56(FP), Y_PTR // Y_PTR := &y MOVQ x_len+40(FP), LEN // LEN = min( len(x), len(y), len(dst) ) CMPQ y_len+64(FP), LEN CMOVQLE y_len+64(FP), LEN CMPQ dst_len+8(FP), LEN CMOVQLE dst_len+8(FP), LEN CMPQ LEN, $0 JE end // if LEN == 0 { return } XORQ IDX, IDX // IDX = 0 MOVSD alpha+24(FP), ALPHA SHUFPD $0, ALPHA, ALPHA // ALPHA := { alpha, alpha } MOVQ Y_PTR, TAIL // Check memory alignment ANDQ $15, TAIL // TAIL = &y % 16 JZ no_trim // if TAIL == 0 { goto no_trim } // Align on 16-byte boundary MOVSD (X_PTR), X2 // X2 := x[0] MULSD ALPHA, X2 // X2 *= a ADDSD (Y_PTR), X2 // X2 += y[0] MOVSD X2, (DST_PTR) // y[0] = X2 INCQ IDX // i++ DECQ LEN // LEN-- JZ end // if LEN == 0 { return } no_trim: MOVQ LEN, TAIL ANDQ $7, TAIL // TAIL := n % 8 SHRQ $3, LEN // LEN = floor( n / 8 ) JZ tail_start // if LEN == 0 { goto tail_start } MOVUPS ALPHA, ALPHA_2 // ALPHA_2 := ALPHA for pipelining loop: // do { // y[i] += alpha * x[i] unrolled 8x. MOVUPS (X_PTR)(IDX*8), X2 // X_i = x[i] MOVUPS 16(X_PTR)(IDX*8), X3 MOVUPS 32(X_PTR)(IDX*8), X4 MOVUPS 48(X_PTR)(IDX*8), X5 MULPD ALPHA, X2 // X_i *= alpha MULPD ALPHA_2, X3 MULPD ALPHA, X4 MULPD ALPHA_2, X5 ADDPD (Y_PTR)(IDX*8), X2 // X_i += y[i] ADDPD 16(Y_PTR)(IDX*8), X3 ADDPD 32(Y_PTR)(IDX*8), X4 ADDPD 48(Y_PTR)(IDX*8), X5 MOVUPS X2, (DST_PTR)(IDX*8) // y[i] = X_i MOVUPS X3, 16(DST_PTR)(IDX*8) MOVUPS X4, 32(DST_PTR)(IDX*8) MOVUPS X5, 48(DST_PTR)(IDX*8) ADDQ $8, IDX // i += 8 DECQ LEN JNZ loop // } while --LEN > 0 CMPQ TAIL, $0 // if TAIL == 0 { return } JE end tail_start: // Reset loop registers MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( TAIL / 2 ) JZ tail_one // if LEN == 0 { goto tail } tail_two: // do { MOVUPS (X_PTR)(IDX*8), X2 // X2 = x[i] MULPD ALPHA, X2 // X2 *= alpha ADDPD (Y_PTR)(IDX*8), X2 // X2 += y[i] MOVUPS X2, (DST_PTR)(IDX*8) // y[i] = X2 ADDQ $2, IDX // i += 2 DECQ LEN JNZ tail_two // } while --LEN > 0 ANDQ $1, TAIL JZ end // if TAIL == 0 { goto end } tail_one: MOVSD (X_PTR)(IDX*8), X2 // X2 = x[i] MULSD ALPHA, X2 // X2 *= a ADDSD (Y_PTR)(IDX*8), X2 // X2 += y[i] MOVSD X2, (DST_PTR)(IDX*8) // y[i] = X2 end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/benchAxpy_test.go000066400000000000000000000074651450372207100241540ustar00rootroot00000000000000// 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 f64_test import ( "fmt" "testing" . "gonum.org/v1/gonum/internal/asm/f64" ) const testLen = 1e5 var ( a = 2.0 x = make([]float64, testLen) y = make([]float64, testLen) z = make([]float64, testLen) ) func init() { for n := range x { x[n] = float64(n) y[n] = float64(n) } } func BenchmarkAxpyUnitary(t *testing.B) { naiveaxpyu := func(a float64, x, y []float64) { for i, v := range x { y[i] += a * v } } tests := []struct { name string f func(a float64, x, y []float64) }{ {"AxpyUnitary", AxpyUnitary}, {"NaiveAxpyUnitary", naiveaxpyu}, } for _, test := range tests { for _, ln := range []uintptr{1, 3, 10, 30, 1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5} { t.Run(fmt.Sprintf("%s-%d", test.name, ln), func(b *testing.B) { b.SetBytes(int64(64 * ln)) x, y := x[:ln], y[:ln] b.ResetTimer() for i := 0; i < b.N; i++ { test.f(a, x, y) } }) } } } func BenchmarkAxpyUnitaryTo(t *testing.B) { naiveaxpyut := func(d []float64, a float64, x, y []float64) { for i, v := range x { d[i] = y[i] + a*v } } tests := []struct { name string f func(z []float64, a float64, x, y []float64) }{ {"AxpyUnitaryTo", AxpyUnitaryTo}, {"NaiveAxpyUnitaryTo", naiveaxpyut}, } for _, test := range tests { for _, ln := range []uintptr{1, 3, 10, 30, 1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5} { t.Run(fmt.Sprintf("%s-%d", test.name, ln), func(b *testing.B) { b.SetBytes(int64(64 * ln)) x, y, z := x[:ln], y[:ln], z[:ln] b.ResetTimer() for i := 0; i < b.N; i++ { test.f(z, a, x, y) } }) } } } var incsAxpy = []struct { len uintptr inc []int }{ {1, []int{1}}, {2, []int{1, 2, 4, 10}}, {3, []int{1, 2, 4, 10}}, {4, []int{1, 2, 4, 10}}, {5, []int{1, 2, 4, 10}}, {10, []int{1, 2, 4, 10}}, {500, []int{1, 2, 4, 10}}, {1e3, []int{1, 2, 4, 10}}, {1e4, []int{1, 2, 4, 10, -1, -2, -4, -10}}, } func BenchmarkAxpyInc(t *testing.B) { naiveaxpyinc := func(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { y[iy] += alpha * x[ix] ix += incX iy += incY } } tests := []struct { name string f func(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) }{ {"AxpyInc", AxpyInc}, {"NaiveAxpyInc", naiveaxpyinc}, } for _, test := range tests { for _, tt := range incsAxpy { for _, inc := range tt.inc { t.Run(fmt.Sprintf("%s-%d-inc(%d)", test.name, tt.len, inc), func(b *testing.B) { b.SetBytes(int64(64 * tt.len)) var idx, tstInc uintptr = 0, uintptr(inc) if inc < 0 { idx = uintptr((-int(tt.len) + 1) * inc) } for i := 0; i < b.N; i++ { test.f(a, x, y, uintptr(tt.len), tstInc, tstInc, idx, idx) } }) } } } } func BenchmarkAxpyIncTo(t *testing.B) { naiveaxpyincto := func(dst []float64, incDst, idst uintptr, alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) { for i := 0; i < int(n); i++ { dst[idst] = alpha*x[ix] + y[iy] ix += incX iy += incY idst += incDst } } tests := []struct { name string f func(dst []float64, incDst, idst uintptr, alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) }{ {"AxpyIncTo", AxpyIncTo}, {"NaiveAxpyIncTo", naiveaxpyincto}, } for _, test := range tests { for _, tt := range incsAxpy { for _, inc := range tt.inc { t.Run(fmt.Sprintf("%s-%d-inc(%d)", test.name, tt.len, inc), func(b *testing.B) { b.SetBytes(int64(64 * tt.len)) var idx, tstInc uintptr = 0, uintptr(inc) if inc < 0 { idx = uintptr((-int(tt.len) + 1) * inc) } for i := 0; i < b.N; i++ { test.f(z, tstInc, idx, a, x, y, uintptr(tt.len), tstInc, tstInc, idx, idx) } }) } } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/benchScal_test.go000066400000000000000000000036311450372207100241040ustar00rootroot00000000000000// 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 f64_test import ( "fmt" "testing" . "gonum.org/v1/gonum/internal/asm/f64" ) var uniScal = []int64{1, 3, 10, 30, 1e2, 3e2, 1e3, 3e3, 1e4, 3e4} func BenchmarkScalUnitary(t *testing.B) { tstName := "ScalUnitary" for _, ln := range uniScal { t.Run(fmt.Sprintf("%s-%d", tstName, ln), func(b *testing.B) { b.SetBytes(64 * ln) x := x[:ln] b.ResetTimer() for i := 0; i < b.N; i++ { ScalUnitary(a, x) } }) } } func BenchmarkScalUnitaryTo(t *testing.B) { tstName := "ScalUnitaryTo" for _, ln := range uniScal { t.Run(fmt.Sprintf("%s-%d", tstName, ln), func(b *testing.B) { b.SetBytes(64 * ln) x, y := x[:ln], y[:ln] b.ResetTimer() for i := 0; i < b.N; i++ { ScalUnitaryTo(y, a, x) } }) } } var incScal = []struct { len uintptr inc []int }{ {1, []int{1}}, {3, []int{1, 2, 4, 10}}, {10, []int{1, 2, 4, 10}}, {30, []int{1, 2, 4, 10}}, {1e2, []int{1, 2, 4, 10}}, {3e2, []int{1, 2, 4, 10}}, {1e3, []int{1, 2, 4, 10}}, {3e3, []int{1, 2, 4, 10}}, {1e4, []int{1, 2, 4, 10}}, } func BenchmarkScalInc(t *testing.B) { tstName := "ScalInc" for _, tt := range incScal { for _, inc := range tt.inc { t.Run(fmt.Sprintf("%s-%d-inc(%d)", tstName, tt.len, inc), func(b *testing.B) { b.SetBytes(int64(64 * tt.len)) tstInc := uintptr(inc) for i := 0; i < b.N; i++ { ScalInc(a, x, uintptr(tt.len), tstInc) } }) } } } func BenchmarkScalIncTo(t *testing.B) { tstName := "ScalIncTo" for _, tt := range incScal { for _, inc := range tt.inc { t.Run(fmt.Sprintf("%s-%d-inc(%d)", tstName, tt.len, inc), func(b *testing.B) { b.SetBytes(int64(64 * tt.len)) tstInc := uintptr(inc) for i := 0; i < b.N; i++ { ScalIncTo(z, tstInc, a, x, uintptr(tt.len), tstInc) } }) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/bench_other_test.go000066400000000000000000000541271450372207100245100ustar00rootroot00000000000000// Copyright ©2016 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 f64_test import ( "math" "testing" . "gonum.org/v1/gonum/internal/asm/f64" ) func benchL1Norm(f func(x []float64) float64, sz int, t *testing.B) { dst := y[:sz] for i := 0; i < t.N; i++ { f(dst) } } var naiveL1Norm = func(x []float64) (sum float64) { for _, v := range x { sum += math.Abs(v) } return sum } func BenchmarkL1Norm1(t *testing.B) { benchL1Norm(L1Norm, 1, t) } func BenchmarkL1Norm2(t *testing.B) { benchL1Norm(L1Norm, 2, t) } func BenchmarkL1Norm3(t *testing.B) { benchL1Norm(L1Norm, 3, t) } func BenchmarkL1Norm4(t *testing.B) { benchL1Norm(L1Norm, 4, t) } func BenchmarkL1Norm5(t *testing.B) { benchL1Norm(L1Norm, 5, t) } func BenchmarkL1Norm10(t *testing.B) { benchL1Norm(L1Norm, 10, t) } func BenchmarkL1Norm100(t *testing.B) { benchL1Norm(L1Norm, 100, t) } func BenchmarkL1Norm1000(t *testing.B) { benchL1Norm(L1Norm, 1000, t) } func BenchmarkL1Norm10000(t *testing.B) { benchL1Norm(L1Norm, 10000, t) } func BenchmarkL1Norm100000(t *testing.B) { benchL1Norm(L1Norm, 100000, t) } func BenchmarkL1Norm500000(t *testing.B) { benchL1Norm(L1Norm, 500000, t) } func BenchmarkLL1Norm1(t *testing.B) { benchL1Norm(naiveL1Norm, 1, t) } func BenchmarkLL1Norm2(t *testing.B) { benchL1Norm(naiveL1Norm, 2, t) } func BenchmarkLL1Norm3(t *testing.B) { benchL1Norm(naiveL1Norm, 3, t) } func BenchmarkLL1Norm4(t *testing.B) { benchL1Norm(naiveL1Norm, 4, t) } func BenchmarkLL1Norm5(t *testing.B) { benchL1Norm(naiveL1Norm, 5, t) } func BenchmarkLL1Norm10(t *testing.B) { benchL1Norm(naiveL1Norm, 10, t) } func BenchmarkLL1Norm100(t *testing.B) { benchL1Norm(naiveL1Norm, 100, t) } func BenchmarkLL1Norm1000(t *testing.B) { benchL1Norm(naiveL1Norm, 1000, t) } func BenchmarkLL1Norm10000(t *testing.B) { benchL1Norm(naiveL1Norm, 10000, t) } func BenchmarkLL1Norm100000(t *testing.B) { benchL1Norm(naiveL1Norm, 100000, t) } func BenchmarkLL1Norm500000(t *testing.B) { benchL1Norm(naiveL1Norm, 500000, t) } func benchL1NormInc(t *testing.B, ln, inc int, f func(x []float64, n, incX int) float64) { for i := 0; i < t.N; i++ { f(x, ln, inc) } } var naiveL1NormInc = func(x []float64, n, incX int) (sum float64) { for i := 0; i < n*incX; i += incX { sum += math.Abs(x[i]) } return sum } func BenchmarkF64L1NormIncN1Inc1(b *testing.B) { benchL1NormInc(b, 1, 1, L1NormInc) } func BenchmarkF64L1NormIncN2Inc1(b *testing.B) { benchL1NormInc(b, 2, 1, L1NormInc) } func BenchmarkF64L1NormIncN2Inc2(b *testing.B) { benchL1NormInc(b, 2, 2, L1NormInc) } func BenchmarkF64L1NormIncN2Inc4(b *testing.B) { benchL1NormInc(b, 2, 4, L1NormInc) } func BenchmarkF64L1NormIncN2Inc10(b *testing.B) { benchL1NormInc(b, 2, 10, L1NormInc) } func BenchmarkF64L1NormIncN3Inc1(b *testing.B) { benchL1NormInc(b, 3, 1, L1NormInc) } func BenchmarkF64L1NormIncN3Inc2(b *testing.B) { benchL1NormInc(b, 3, 2, L1NormInc) } func BenchmarkF64L1NormIncN3Inc4(b *testing.B) { benchL1NormInc(b, 3, 4, L1NormInc) } func BenchmarkF64L1NormIncN3Inc10(b *testing.B) { benchL1NormInc(b, 3, 10, L1NormInc) } func BenchmarkF64L1NormIncN4Inc1(b *testing.B) { benchL1NormInc(b, 4, 1, L1NormInc) } func BenchmarkF64L1NormIncN4Inc2(b *testing.B) { benchL1NormInc(b, 4, 2, L1NormInc) } func BenchmarkF64L1NormIncN4Inc4(b *testing.B) { benchL1NormInc(b, 4, 4, L1NormInc) } func BenchmarkF64L1NormIncN4Inc10(b *testing.B) { benchL1NormInc(b, 4, 10, L1NormInc) } func BenchmarkF64L1NormIncN10Inc1(b *testing.B) { benchL1NormInc(b, 10, 1, L1NormInc) } func BenchmarkF64L1NormIncN10Inc2(b *testing.B) { benchL1NormInc(b, 10, 2, L1NormInc) } func BenchmarkF64L1NormIncN10Inc4(b *testing.B) { benchL1NormInc(b, 10, 4, L1NormInc) } func BenchmarkF64L1NormIncN10Inc10(b *testing.B) { benchL1NormInc(b, 10, 10, L1NormInc) } func BenchmarkF64L1NormIncN1000Inc1(b *testing.B) { benchL1NormInc(b, 1000, 1, L1NormInc) } func BenchmarkF64L1NormIncN1000Inc2(b *testing.B) { benchL1NormInc(b, 1000, 2, L1NormInc) } func BenchmarkF64L1NormIncN1000Inc4(b *testing.B) { benchL1NormInc(b, 1000, 4, L1NormInc) } func BenchmarkF64L1NormIncN1000Inc10(b *testing.B) { benchL1NormInc(b, 1000, 10, L1NormInc) } func BenchmarkF64L1NormIncN100000Inc1(b *testing.B) { benchL1NormInc(b, 100000, 1, L1NormInc) } func BenchmarkF64L1NormIncN100000Inc2(b *testing.B) { benchL1NormInc(b, 100000, 2, L1NormInc) } func BenchmarkF64L1NormIncN100000Inc4(b *testing.B) { benchL1NormInc(b, 100000, 4, L1NormInc) } func BenchmarkF64L1NormIncN100000Inc10(b *testing.B) { benchL1NormInc(b, 100000, 10, L1NormInc) } func BenchmarkLF64L1NormIncN1Inc1(b *testing.B) { benchL1NormInc(b, 1, 1, naiveL1NormInc) } func BenchmarkLF64L1NormIncN2Inc1(b *testing.B) { benchL1NormInc(b, 2, 1, naiveL1NormInc) } func BenchmarkLF64L1NormIncN2Inc2(b *testing.B) { benchL1NormInc(b, 2, 2, naiveL1NormInc) } func BenchmarkLF64L1NormIncN2Inc4(b *testing.B) { benchL1NormInc(b, 2, 4, naiveL1NormInc) } func BenchmarkLF64L1NormIncN2Inc10(b *testing.B) { benchL1NormInc(b, 2, 10, naiveL1NormInc) } func BenchmarkLF64L1NormIncN3Inc1(b *testing.B) { benchL1NormInc(b, 3, 1, naiveL1NormInc) } func BenchmarkLF64L1NormIncN3Inc2(b *testing.B) { benchL1NormInc(b, 3, 2, naiveL1NormInc) } func BenchmarkLF64L1NormIncN3Inc4(b *testing.B) { benchL1NormInc(b, 3, 4, naiveL1NormInc) } func BenchmarkLF64L1NormIncN3Inc10(b *testing.B) { benchL1NormInc(b, 3, 10, naiveL1NormInc) } func BenchmarkLF64L1NormIncN4Inc1(b *testing.B) { benchL1NormInc(b, 4, 1, naiveL1NormInc) } func BenchmarkLF64L1NormIncN4Inc2(b *testing.B) { benchL1NormInc(b, 4, 2, naiveL1NormInc) } func BenchmarkLF64L1NormIncN4Inc4(b *testing.B) { benchL1NormInc(b, 4, 4, naiveL1NormInc) } func BenchmarkLF64L1NormIncN4Inc10(b *testing.B) { benchL1NormInc(b, 4, 10, naiveL1NormInc) } func BenchmarkLF64L1NormIncN10Inc1(b *testing.B) { benchL1NormInc(b, 10, 1, naiveL1NormInc) } func BenchmarkLF64L1NormIncN10Inc2(b *testing.B) { benchL1NormInc(b, 10, 2, naiveL1NormInc) } func BenchmarkLF64L1NormIncN10Inc4(b *testing.B) { benchL1NormInc(b, 10, 4, naiveL1NormInc) } func BenchmarkLF64L1NormIncN10Inc10(b *testing.B) { benchL1NormInc(b, 10, 10, naiveL1NormInc) } func BenchmarkLF64L1NormIncN1000Inc1(b *testing.B) { benchL1NormInc(b, 1000, 1, naiveL1NormInc) } func BenchmarkLF64L1NormIncN1000Inc2(b *testing.B) { benchL1NormInc(b, 1000, 2, naiveL1NormInc) } func BenchmarkLF64L1NormIncN1000Inc4(b *testing.B) { benchL1NormInc(b, 1000, 4, naiveL1NormInc) } func BenchmarkLF64L1NormIncN1000Inc10(b *testing.B) { benchL1NormInc(b, 1000, 10, naiveL1NormInc) } func BenchmarkLF64L1NormIncN100000Inc1(b *testing.B) { benchL1NormInc(b, 100000, 1, naiveL1NormInc) } func BenchmarkLF64L1NormIncN100000Inc2(b *testing.B) { benchL1NormInc(b, 100000, 2, naiveL1NormInc) } func BenchmarkLF64L1NormIncN100000Inc4(b *testing.B) { benchL1NormInc(b, 100000, 4, naiveL1NormInc) } func BenchmarkLF64L1NormIncN100000Inc10(b *testing.B) { benchL1NormInc(b, 100000, 10, naiveL1NormInc) } func benchAdd(f func(dst, s []float64), sz int, t *testing.B) { dst, s := y[:sz], x[:sz] for i := 0; i < t.N; i++ { f(dst, s) } } var naiveAdd = func(dst, s []float64) { for i, v := range s { dst[i] += v } } func BenchmarkAdd1(t *testing.B) { benchAdd(Add, 1, t) } func BenchmarkAdd2(t *testing.B) { benchAdd(Add, 2, t) } func BenchmarkAdd3(t *testing.B) { benchAdd(Add, 3, t) } func BenchmarkAdd4(t *testing.B) { benchAdd(Add, 4, t) } func BenchmarkAdd5(t *testing.B) { benchAdd(Add, 5, t) } func BenchmarkAdd10(t *testing.B) { benchAdd(Add, 10, t) } func BenchmarkAdd100(t *testing.B) { benchAdd(Add, 100, t) } func BenchmarkAdd1000(t *testing.B) { benchAdd(Add, 1000, t) } func BenchmarkAdd10000(t *testing.B) { benchAdd(Add, 10000, t) } func BenchmarkAdd100000(t *testing.B) { benchAdd(Add, 100000, t) } func BenchmarkAdd500000(t *testing.B) { benchAdd(Add, 500000, t) } func BenchmarkLAdd1(t *testing.B) { benchAdd(naiveAdd, 1, t) } func BenchmarkLAdd2(t *testing.B) { benchAdd(naiveAdd, 2, t) } func BenchmarkLAdd3(t *testing.B) { benchAdd(naiveAdd, 3, t) } func BenchmarkLAdd4(t *testing.B) { benchAdd(naiveAdd, 4, t) } func BenchmarkLAdd5(t *testing.B) { benchAdd(naiveAdd, 5, t) } func BenchmarkLAdd10(t *testing.B) { benchAdd(naiveAdd, 10, t) } func BenchmarkLAdd100(t *testing.B) { benchAdd(naiveAdd, 100, t) } func BenchmarkLAdd1000(t *testing.B) { benchAdd(naiveAdd, 1000, t) } func BenchmarkLAdd10000(t *testing.B) { benchAdd(naiveAdd, 10000, t) } func BenchmarkLAdd100000(t *testing.B) { benchAdd(naiveAdd, 100000, t) } func BenchmarkLAdd500000(t *testing.B) { benchAdd(naiveAdd, 500000, t) } func benchAddConst(f func(a float64, x []float64), sz int, t *testing.B) { a, x := 1., x[:sz] for i := 0; i < t.N; i++ { f(a, x) } } var naiveAddConst = func(a float64, x []float64) { for i := range x { x[i] += a } } func BenchmarkAddConst1(t *testing.B) { benchAddConst(AddConst, 1, t) } func BenchmarkAddConst2(t *testing.B) { benchAddConst(AddConst, 2, t) } func BenchmarkAddConst3(t *testing.B) { benchAddConst(AddConst, 3, t) } func BenchmarkAddConst4(t *testing.B) { benchAddConst(AddConst, 4, t) } func BenchmarkAddConst5(t *testing.B) { benchAddConst(AddConst, 5, t) } func BenchmarkAddConst10(t *testing.B) { benchAddConst(AddConst, 10, t) } func BenchmarkAddConst100(t *testing.B) { benchAddConst(AddConst, 100, t) } func BenchmarkAddConst1000(t *testing.B) { benchAddConst(AddConst, 1000, t) } func BenchmarkAddConst10000(t *testing.B) { benchAddConst(AddConst, 10000, t) } func BenchmarkAddConst100000(t *testing.B) { benchAddConst(AddConst, 100000, t) } func BenchmarkAddConst500000(t *testing.B) { benchAddConst(AddConst, 500000, t) } func BenchmarkLAddConst1(t *testing.B) { benchAddConst(naiveAddConst, 1, t) } func BenchmarkLAddConst2(t *testing.B) { benchAddConst(naiveAddConst, 2, t) } func BenchmarkLAddConst3(t *testing.B) { benchAddConst(naiveAddConst, 3, t) } func BenchmarkLAddConst4(t *testing.B) { benchAddConst(naiveAddConst, 4, t) } func BenchmarkLAddConst5(t *testing.B) { benchAddConst(naiveAddConst, 5, t) } func BenchmarkLAddConst10(t *testing.B) { benchAddConst(naiveAddConst, 10, t) } func BenchmarkLAddConst100(t *testing.B) { benchAddConst(naiveAddConst, 100, t) } func BenchmarkLAddConst1000(t *testing.B) { benchAddConst(naiveAddConst, 1000, t) } func BenchmarkLAddConst10000(t *testing.B) { benchAddConst(naiveAddConst, 10000, t) } func BenchmarkLAddConst100000(t *testing.B) { benchAddConst(naiveAddConst, 100000, t) } func BenchmarkLAddConst500000(t *testing.B) { benchAddConst(naiveAddConst, 500000, t) } func benchCumSum(f func(a, b []float64) []float64, sz int, t *testing.B) { a, b := x[:sz], y[:sz] for i := 0; i < t.N; i++ { f(a, b) } } var naiveCumSum = func(dst, s []float64) []float64 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] + v } return dst } func BenchmarkCumSum1(t *testing.B) { benchCumSum(CumSum, 1, t) } func BenchmarkCumSum2(t *testing.B) { benchCumSum(CumSum, 2, t) } func BenchmarkCumSum3(t *testing.B) { benchCumSum(CumSum, 3, t) } func BenchmarkCumSum4(t *testing.B) { benchCumSum(CumSum, 4, t) } func BenchmarkCumSum5(t *testing.B) { benchCumSum(CumSum, 5, t) } func BenchmarkCumSum10(t *testing.B) { benchCumSum(CumSum, 10, t) } func BenchmarkCumSum100(t *testing.B) { benchCumSum(CumSum, 100, t) } func BenchmarkCumSum1000(t *testing.B) { benchCumSum(CumSum, 1000, t) } func BenchmarkCumSum10000(t *testing.B) { benchCumSum(CumSum, 10000, t) } func BenchmarkCumSum100000(t *testing.B) { benchCumSum(CumSum, 100000, t) } func BenchmarkCumSum500000(t *testing.B) { benchCumSum(CumSum, 500000, t) } func BenchmarkLCumSum1(t *testing.B) { benchCumSum(naiveCumSum, 1, t) } func BenchmarkLCumSum2(t *testing.B) { benchCumSum(naiveCumSum, 2, t) } func BenchmarkLCumSum3(t *testing.B) { benchCumSum(naiveCumSum, 3, t) } func BenchmarkLCumSum4(t *testing.B) { benchCumSum(naiveCumSum, 4, t) } func BenchmarkLCumSum5(t *testing.B) { benchCumSum(naiveCumSum, 5, t) } func BenchmarkLCumSum10(t *testing.B) { benchCumSum(naiveCumSum, 10, t) } func BenchmarkLCumSum100(t *testing.B) { benchCumSum(naiveCumSum, 100, t) } func BenchmarkLCumSum1000(t *testing.B) { benchCumSum(naiveCumSum, 1000, t) } func BenchmarkLCumSum10000(t *testing.B) { benchCumSum(naiveCumSum, 10000, t) } func BenchmarkLCumSum100000(t *testing.B) { benchCumSum(naiveCumSum, 100000, t) } func BenchmarkLCumSum500000(t *testing.B) { benchCumSum(naiveCumSum, 500000, t) } func benchCumProd(f func(a, b []float64) []float64, sz int, t *testing.B) { a, b := x[:sz], y[:sz] for i := 0; i < t.N; i++ { f(a, b) } } var naiveCumProd = func(dst, s []float64) []float64 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] + v } return dst } func BenchmarkCumProd1(t *testing.B) { benchCumProd(CumProd, 1, t) } func BenchmarkCumProd2(t *testing.B) { benchCumProd(CumProd, 2, t) } func BenchmarkCumProd3(t *testing.B) { benchCumProd(CumProd, 3, t) } func BenchmarkCumProd4(t *testing.B) { benchCumProd(CumProd, 4, t) } func BenchmarkCumProd5(t *testing.B) { benchCumProd(CumProd, 5, t) } func BenchmarkCumProd10(t *testing.B) { benchCumProd(CumProd, 10, t) } func BenchmarkCumProd100(t *testing.B) { benchCumProd(CumProd, 100, t) } func BenchmarkCumProd1000(t *testing.B) { benchCumProd(CumProd, 1000, t) } func BenchmarkCumProd10000(t *testing.B) { benchCumProd(CumProd, 10000, t) } func BenchmarkCumProd100000(t *testing.B) { benchCumProd(CumProd, 100000, t) } func BenchmarkCumProd500000(t *testing.B) { benchCumProd(CumProd, 500000, t) } func BenchmarkLCumProd1(t *testing.B) { benchCumProd(naiveCumProd, 1, t) } func BenchmarkLCumProd2(t *testing.B) { benchCumProd(naiveCumProd, 2, t) } func BenchmarkLCumProd3(t *testing.B) { benchCumProd(naiveCumProd, 3, t) } func BenchmarkLCumProd4(t *testing.B) { benchCumProd(naiveCumProd, 4, t) } func BenchmarkLCumProd5(t *testing.B) { benchCumProd(naiveCumProd, 5, t) } func BenchmarkLCumProd10(t *testing.B) { benchCumProd(naiveCumProd, 10, t) } func BenchmarkLCumProd100(t *testing.B) { benchCumProd(naiveCumProd, 100, t) } func BenchmarkLCumProd1000(t *testing.B) { benchCumProd(naiveCumProd, 1000, t) } func BenchmarkLCumProd10000(t *testing.B) { benchCumProd(naiveCumProd, 10000, t) } func BenchmarkLCumProd100000(t *testing.B) { benchCumProd(naiveCumProd, 100000, t) } func BenchmarkLCumProd500000(t *testing.B) { benchCumProd(naiveCumProd, 500000, t) } func benchDiv(f func(a, b []float64), sz int, t *testing.B) { a, b := x[:sz], y[:sz] for i := 0; i < t.N; i++ { f(a, b) } } var naiveDiv = func(a, b []float64) { for i, v := range b { a[i] /= v } } func BenchmarkDiv1(t *testing.B) { benchDiv(Div, 1, t) } func BenchmarkDiv2(t *testing.B) { benchDiv(Div, 2, t) } func BenchmarkDiv3(t *testing.B) { benchDiv(Div, 3, t) } func BenchmarkDiv4(t *testing.B) { benchDiv(Div, 4, t) } func BenchmarkDiv5(t *testing.B) { benchDiv(Div, 5, t) } func BenchmarkDiv10(t *testing.B) { benchDiv(Div, 10, t) } func BenchmarkDiv100(t *testing.B) { benchDiv(Div, 100, t) } func BenchmarkDiv1000(t *testing.B) { benchDiv(Div, 1000, t) } func BenchmarkDiv10000(t *testing.B) { benchDiv(Div, 10000, t) } func BenchmarkDiv100000(t *testing.B) { benchDiv(Div, 100000, t) } func BenchmarkDiv500000(t *testing.B) { benchDiv(Div, 500000, t) } func BenchmarkLDiv1(t *testing.B) { benchDiv(naiveDiv, 1, t) } func BenchmarkLDiv2(t *testing.B) { benchDiv(naiveDiv, 2, t) } func BenchmarkLDiv3(t *testing.B) { benchDiv(naiveDiv, 3, t) } func BenchmarkLDiv4(t *testing.B) { benchDiv(naiveDiv, 4, t) } func BenchmarkLDiv5(t *testing.B) { benchDiv(naiveDiv, 5, t) } func BenchmarkLDiv10(t *testing.B) { benchDiv(naiveDiv, 10, t) } func BenchmarkLDiv100(t *testing.B) { benchDiv(naiveDiv, 100, t) } func BenchmarkLDiv1000(t *testing.B) { benchDiv(naiveDiv, 1000, t) } func BenchmarkLDiv10000(t *testing.B) { benchDiv(naiveDiv, 10000, t) } func BenchmarkLDiv100000(t *testing.B) { benchDiv(naiveDiv, 100000, t) } func BenchmarkLDiv500000(t *testing.B) { benchDiv(naiveDiv, 500000, t) } func benchDivTo(f func(dst, a, b []float64) []float64, sz int, t *testing.B) { dst, a, b := z[:sz], x[:sz], y[:sz] for i := 0; i < t.N; i++ { f(dst, a, b) } } var naiveDivTo = func(dst, s, t []float64) []float64 { for i, v := range s { dst[i] = v / t[i] } return dst } func BenchmarkDivTo1(t *testing.B) { benchDivTo(DivTo, 1, t) } func BenchmarkDivTo2(t *testing.B) { benchDivTo(DivTo, 2, t) } func BenchmarkDivTo3(t *testing.B) { benchDivTo(DivTo, 3, t) } func BenchmarkDivTo4(t *testing.B) { benchDivTo(DivTo, 4, t) } func BenchmarkDivTo5(t *testing.B) { benchDivTo(DivTo, 5, t) } func BenchmarkDivTo10(t *testing.B) { benchDivTo(DivTo, 10, t) } func BenchmarkDivTo100(t *testing.B) { benchDivTo(DivTo, 100, t) } func BenchmarkDivTo1000(t *testing.B) { benchDivTo(DivTo, 1000, t) } func BenchmarkDivTo10000(t *testing.B) { benchDivTo(DivTo, 10000, t) } func BenchmarkDivTo100000(t *testing.B) { benchDivTo(DivTo, 100000, t) } func BenchmarkDivTo500000(t *testing.B) { benchDivTo(DivTo, 500000, t) } func BenchmarkLDivTo1(t *testing.B) { benchDivTo(naiveDivTo, 1, t) } func BenchmarkLDivTo2(t *testing.B) { benchDivTo(naiveDivTo, 2, t) } func BenchmarkLDivTo3(t *testing.B) { benchDivTo(naiveDivTo, 3, t) } func BenchmarkLDivTo4(t *testing.B) { benchDivTo(naiveDivTo, 4, t) } func BenchmarkLDivTo5(t *testing.B) { benchDivTo(naiveDivTo, 5, t) } func BenchmarkLDivTo10(t *testing.B) { benchDivTo(naiveDivTo, 10, t) } func BenchmarkLDivTo100(t *testing.B) { benchDivTo(naiveDivTo, 100, t) } func BenchmarkLDivTo1000(t *testing.B) { benchDivTo(naiveDivTo, 1000, t) } func BenchmarkLDivTo10000(t *testing.B) { benchDivTo(naiveDivTo, 10000, t) } func BenchmarkLDivTo100000(t *testing.B) { benchDivTo(naiveDivTo, 100000, t) } func BenchmarkLDivTo500000(t *testing.B) { benchDivTo(naiveDivTo, 500000, t) } func benchL1Dist(f func(a, b []float64) float64, sz int, t *testing.B) { a, b := x[:sz], y[:sz] for i := 0; i < t.N; i++ { f(a, b) } } var naiveL1Dist = func(s, t []float64) float64 { var norm float64 for i, v := range s { norm += math.Abs(t[i] - v) } return norm } func BenchmarkL1Dist1(t *testing.B) { benchL1Dist(L1Dist, 1, t) } func BenchmarkL1Dist2(t *testing.B) { benchL1Dist(L1Dist, 2, t) } func BenchmarkL1Dist3(t *testing.B) { benchL1Dist(L1Dist, 3, t) } func BenchmarkL1Dist4(t *testing.B) { benchL1Dist(L1Dist, 4, t) } func BenchmarkL1Dist5(t *testing.B) { benchL1Dist(L1Dist, 5, t) } func BenchmarkL1Dist10(t *testing.B) { benchL1Dist(L1Dist, 10, t) } func BenchmarkL1Dist100(t *testing.B) { benchL1Dist(L1Dist, 100, t) } func BenchmarkL1Dist1000(t *testing.B) { benchL1Dist(L1Dist, 1000, t) } func BenchmarkL1Dist10000(t *testing.B) { benchL1Dist(L1Dist, 10000, t) } func BenchmarkL1Dist100000(t *testing.B) { benchL1Dist(L1Dist, 100000, t) } func BenchmarkL1Dist500000(t *testing.B) { benchL1Dist(L1Dist, 500000, t) } func BenchmarkLL1Dist1(t *testing.B) { benchL1Dist(naiveL1Dist, 1, t) } func BenchmarkLL1Dist2(t *testing.B) { benchL1Dist(naiveL1Dist, 2, t) } func BenchmarkLL1Dist3(t *testing.B) { benchL1Dist(naiveL1Dist, 3, t) } func BenchmarkLL1Dist4(t *testing.B) { benchL1Dist(naiveL1Dist, 4, t) } func BenchmarkLL1Dist5(t *testing.B) { benchL1Dist(naiveL1Dist, 5, t) } func BenchmarkLL1Dist10(t *testing.B) { benchL1Dist(naiveL1Dist, 10, t) } func BenchmarkLL1Dist100(t *testing.B) { benchL1Dist(naiveL1Dist, 100, t) } func BenchmarkLL1Dist1000(t *testing.B) { benchL1Dist(naiveL1Dist, 1000, t) } func BenchmarkLL1Dist10000(t *testing.B) { benchL1Dist(naiveL1Dist, 10000, t) } func BenchmarkLL1Dist100000(t *testing.B) { benchL1Dist(naiveL1Dist, 100000, t) } func BenchmarkLL1Dist500000(t *testing.B) { benchL1Dist(naiveL1Dist, 500000, t) } func benchLinfDist(f func(a, b []float64) float64, sz int, t *testing.B) { a, b := x[:sz], y[:sz] for i := 0; i < t.N; i++ { f(a, b) } } var naiveLinfDist = func(s, t []float64) float64 { var norm float64 if len(s) == 0 { return 0 } norm = math.Abs(t[0] - s[0]) for i, v := range s[1:] { absDiff := math.Abs(t[i+1] - v) if absDiff > norm || math.IsNaN(norm) { norm = absDiff } } return norm } func BenchmarkLinfDist1(t *testing.B) { benchLinfDist(LinfDist, 1, t) } func BenchmarkLinfDist2(t *testing.B) { benchLinfDist(LinfDist, 2, t) } func BenchmarkLinfDist3(t *testing.B) { benchLinfDist(LinfDist, 3, t) } func BenchmarkLinfDist4(t *testing.B) { benchLinfDist(LinfDist, 4, t) } func BenchmarkLinfDist5(t *testing.B) { benchLinfDist(LinfDist, 5, t) } func BenchmarkLinfDist10(t *testing.B) { benchLinfDist(LinfDist, 10, t) } func BenchmarkLinfDist100(t *testing.B) { benchLinfDist(LinfDist, 100, t) } func BenchmarkLinfDist1000(t *testing.B) { benchLinfDist(LinfDist, 1000, t) } func BenchmarkLinfDist10000(t *testing.B) { benchLinfDist(LinfDist, 10000, t) } func BenchmarkLinfDist100000(t *testing.B) { benchLinfDist(LinfDist, 100000, t) } func BenchmarkLinfDist500000(t *testing.B) { benchLinfDist(LinfDist, 500000, t) } func BenchmarkLLinfDist1(t *testing.B) { benchLinfDist(naiveLinfDist, 1, t) } func BenchmarkLLinfDist2(t *testing.B) { benchLinfDist(naiveLinfDist, 2, t) } func BenchmarkLLinfDist3(t *testing.B) { benchLinfDist(naiveLinfDist, 3, t) } func BenchmarkLLinfDist4(t *testing.B) { benchLinfDist(naiveLinfDist, 4, t) } func BenchmarkLLinfDist5(t *testing.B) { benchLinfDist(naiveLinfDist, 5, t) } func BenchmarkLLinfDist10(t *testing.B) { benchLinfDist(naiveLinfDist, 10, t) } func BenchmarkLLinfDist100(t *testing.B) { benchLinfDist(naiveLinfDist, 100, t) } func BenchmarkLLinfDist1000(t *testing.B) { benchLinfDist(naiveLinfDist, 1000, t) } func BenchmarkLLinfDist10000(t *testing.B) { benchLinfDist(naiveLinfDist, 10000, t) } func BenchmarkLLinfDist100000(t *testing.B) { benchLinfDist(naiveLinfDist, 100000, t) } func BenchmarkLLinfDist500000(t *testing.B) { benchLinfDist(naiveLinfDist, 500000, t) } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/cumprod_amd64.s000066400000000000000000000040641450372207100234650ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" TEXT ·CumProd(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ dst_len+8(FP), CX // CX = len(dst) MOVQ s_base+24(FP), SI // SI = &s CMPQ s_len+32(FP), CX // CX = max( CX, len(s) ) CMOVQLE s_len+32(FP), CX MOVQ CX, ret_len+56(FP) // len(ret) = CX CMPQ CX, $0 // if CX == 0 { return } JE cp_end XORQ AX, AX // i = 0 MOVSD (SI), X5 // p_prod = { s[0], s[0] } SHUFPD $0, X5, X5 MOVSD X5, (DI) // dst[0] = s[0] INCQ AX // ++i DECQ CX // -- CX JZ cp_end // if CX == 0 { return } MOVQ CX, BX ANDQ $3, BX // BX = CX % 4 SHRQ $2, CX // CX = floor( CX / 4 ) JZ cp_tail_start // if CX == 0 { goto cp_tail_start } cp_loop: // Loop unrolled 4x do { MOVUPS (SI)(AX*8), X0 // X0 = s[i:i+1] MOVUPS 16(SI)(AX*8), X2 MOVAPS X0, X1 // X1 = X0 MOVAPS X2, X3 SHUFPD $1, X1, X1 // { X1[0], X1[1] } = { X1[1], X1[0] } SHUFPD $1, X3, X3 MULPD X0, X1 // X1 *= X0 MULPD X2, X3 SHUFPD $2, X1, X0 // { X0[0], X0[1] } = { X0[0], X1[1] } SHUFPD $3, X1, X1 // { X1[0], X1[1] } = { X1[1], X1[1] } SHUFPD $2, X3, X2 SHUFPD $3, X3, X3 MULPD X5, X0 // X0 *= p_prod MULPD X1, X5 // p_prod *= X1 MULPD X5, X2 MOVUPS X0, (DI)(AX*8) // dst[i] = X0 MOVUPS X2, 16(DI)(AX*8) MULPD X3, X5 ADDQ $4, AX // i += 4 LOOP cp_loop // } while --CX > 0 // if BX == 0 { return } CMPQ BX, $0 JE cp_end cp_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX cp_tail: // do { MULSD (SI)(AX*8), X5 // p_prod *= s[i] MOVSD X5, (DI)(AX*8) // dst[i] = p_prod INCQ AX // ++i LOOP cp_tail // } while --CX > 0 cp_end: MOVQ DI, ret_base+48(FP) // &ret = &dst MOVQ dst_cap+16(FP), SI // cap(ret) = cap(dst) MOVQ SI, ret_cap+64(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/cumsum_amd64.s000066400000000000000000000036521450372207100233270ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" TEXT ·CumSum(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ dst_len+8(FP), CX // CX = len(dst) MOVQ s_base+24(FP), SI // SI = &s CMPQ s_len+32(FP), CX // CX = max( CX, len(s) ) CMOVQLE s_len+32(FP), CX MOVQ CX, ret_len+56(FP) // len(ret) = CX CMPQ CX, $0 // if CX == 0 { return } JE cs_end XORQ AX, AX // i = 0 PXOR X5, X5 // p_sum = 0 MOVQ CX, BX ANDQ $3, BX // BX = CX % 4 SHRQ $2, CX // CX = floor( CX / 4 ) JZ cs_tail_start // if CX == 0 { goto cs_tail_start } cs_loop: // Loop unrolled 4x do { MOVUPS (SI)(AX*8), X0 // X0 = s[i:i+1] MOVUPS 16(SI)(AX*8), X2 MOVAPS X0, X1 // X1 = X0 MOVAPS X2, X3 SHUFPD $1, X1, X1 // { X1[0], X1[1] } = { X1[1], X1[0] } SHUFPD $1, X3, X3 ADDPD X0, X1 // X1 += X0 ADDPD X2, X3 SHUFPD $2, X1, X0 // { X0[0], X0[1] } = { X0[0], X1[1] } SHUFPD $3, X1, X1 // { X1[0], X1[1] } = { X1[1], X1[1] } SHUFPD $2, X3, X2 SHUFPD $3, X3, X3 ADDPD X5, X0 // X0 += p_sum ADDPD X1, X5 // p_sum += X1 ADDPD X5, X2 MOVUPS X0, (DI)(AX*8) // dst[i] = X0 MOVUPS X2, 16(DI)(AX*8) ADDPD X3, X5 ADDQ $4, AX // i += 4 LOOP cs_loop // } while --CX > 0 // if BX == 0 { return } CMPQ BX, $0 JE cs_end cs_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX cs_tail: // do { ADDSD (SI)(AX*8), X5 // p_sum *= s[i] MOVSD X5, (DI)(AX*8) // dst[i] = p_sum INCQ AX // ++i LOOP cs_tail // } while --CX > 0 cs_end: MOVQ DI, ret_base+48(FP) // &ret = &dst MOVQ dst_cap+16(FP), SI // cap(ret) = cap(dst) MOVQ SI, ret_cap+64(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/div_amd64.s000066400000000000000000000036601450372207100225770ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func Div(dst, s []float64) TEXT ·Div(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ dst_len+8(FP), CX // CX = len(dst) MOVQ s_base+24(FP), SI // SI = &s CMPQ s_len+32(FP), CX // CX = max( CX, len(s) ) CMOVQLE s_len+32(FP), CX CMPQ CX, $0 // if CX == 0 { return } JE div_end XORQ AX, AX // i = 0 MOVQ SI, BX ANDQ $15, BX // BX = &s & 15 JZ div_no_trim // if BX == 0 { goto div_no_trim } // Align on 16-bit boundary MOVSD (DI)(AX*8), X0 // X0 = dst[i] DIVSD (SI)(AX*8), X0 // X0 /= s[i] MOVSD X0, (DI)(AX*8) // dst[i] = X0 INCQ AX // ++i DECQ CX // --CX JZ div_end // if CX == 0 { return } div_no_trim: MOVQ CX, BX ANDQ $7, BX // BX = len(dst) % 8 SHRQ $3, CX // CX = floor( len(dst) / 8 ) JZ div_tail_start // if CX == 0 { goto div_tail_start } div_loop: // Loop unrolled 8x do { MOVUPS (DI)(AX*8), X0 // X0 = dst[i:i+1] MOVUPS 16(DI)(AX*8), X1 MOVUPS 32(DI)(AX*8), X2 MOVUPS 48(DI)(AX*8), X3 DIVPD (SI)(AX*8), X0 // X0 /= s[i:i+1] DIVPD 16(SI)(AX*8), X1 DIVPD 32(SI)(AX*8), X2 DIVPD 48(SI)(AX*8), X3 MOVUPS X0, (DI)(AX*8) // dst[i] = X0 MOVUPS X1, 16(DI)(AX*8) MOVUPS X2, 32(DI)(AX*8) MOVUPS X3, 48(DI)(AX*8) ADDQ $8, AX // i += 8 LOOP div_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE div_end div_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX div_tail: // do { MOVSD (DI)(AX*8), X0 // X0 = dst[i] DIVSD (SI)(AX*8), X0 // X0 /= s[i] MOVSD X0, (DI)(AX*8) // dst[i] = X0 INCQ AX // ++i LOOP div_tail // } while --CX > 0 div_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/divto_amd64.s000066400000000000000000000042601450372207100231370ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func DivTo(dst, x, y []float64) TEXT ·DivTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DI // DI = &dst MOVQ dst_len+8(FP), CX // CX = len(dst) MOVQ x_base+24(FP), SI // SI = &x MOVQ y_base+48(FP), DX // DX = &y CMPQ x_len+32(FP), CX // CX = max( len(dst), len(x), len(y) ) CMOVQLE x_len+32(FP), CX CMPQ y_len+56(FP), CX CMOVQLE y_len+56(FP), CX MOVQ CX, ret_len+80(FP) // len(ret) = CX CMPQ CX, $0 // if CX == 0 { return } JE div_end XORQ AX, AX // i = 0 MOVQ DX, BX ANDQ $15, BX // BX = &y & OxF JZ div_no_trim // if BX == 0 { goto div_no_trim } // Align on 16-bit boundary MOVSD (SI)(AX*8), X0 // X0 = s[i] DIVSD (DX)(AX*8), X0 // X0 /= t[i] MOVSD X0, (DI)(AX*8) // dst[i] = X0 INCQ AX // ++i DECQ CX // --CX JZ div_end // if CX == 0 { return } div_no_trim: MOVQ CX, BX ANDQ $7, BX // BX = len(dst) % 8 SHRQ $3, CX // CX = floor( len(dst) / 8 ) JZ div_tail_start // if CX == 0 { goto div_tail_start } div_loop: // Loop unrolled 8x do { MOVUPS (SI)(AX*8), X0 // X0 = x[i:i+1] MOVUPS 16(SI)(AX*8), X1 MOVUPS 32(SI)(AX*8), X2 MOVUPS 48(SI)(AX*8), X3 DIVPD (DX)(AX*8), X0 // X0 /= y[i:i+1] DIVPD 16(DX)(AX*8), X1 DIVPD 32(DX)(AX*8), X2 DIVPD 48(DX)(AX*8), X3 MOVUPS X0, (DI)(AX*8) // dst[i:i+1] = X0 MOVUPS X1, 16(DI)(AX*8) MOVUPS X2, 32(DI)(AX*8) MOVUPS X3, 48(DI)(AX*8) ADDQ $8, AX // i += 8 LOOP div_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE div_end div_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX div_tail: // do { MOVSD (SI)(AX*8), X0 // X0 = x[i] DIVSD (DX)(AX*8), X0 // X0 /= y[i] MOVSD X0, (DI)(AX*8) INCQ AX // ++i LOOP div_tail // } while --CX > 0 div_end: MOVQ DI, ret_base+72(FP) // &ret = &dst MOVQ dst_cap+16(FP), DI // cap(ret) = cap(dst) MOVQ DI, ret_cap+88(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/doc.go000066400000000000000000000004241450372207100217250ustar00rootroot00000000000000// 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 f64 provides float64 vector primitives. package f64 // import "gonum.org/v1/gonum/internal/asm/f64" golang-gonum-v1-gonum-0.14.0/internal/asm/f64/dot.go000066400000000000000000000013471450372207100217530ustar00rootroot00000000000000// 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f64 // DotUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotUnitary(x, y []float64) (sum float64) { for i, v := range x { sum += y[i] * v } return sum } // DotInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotInc(x, y []float64, n, incX, incY, ix, iy uintptr) (sum float64) { for i := 0; i < int(n); i++ { sum += y[iy] * x[ix] ix += incX iy += incY } return sum } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/dot_amd64.s000066400000000000000000000102041450372207100225730ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" // func DdotUnitary(x, y []float64) (sum float64) // This function assumes len(y) >= len(x). TEXT ·DotUnitary(SB), NOSPLIT, $0 MOVQ x+0(FP), R8 MOVQ x_len+8(FP), DI // n = len(x) MOVQ y+24(FP), R9 MOVSD $(0.0), X7 // sum = 0 MOVSD $(0.0), X8 // sum = 0 MOVQ $0, SI // i = 0 SUBQ $4, DI // n -= 4 JL tail_uni // if n < 0 goto tail_uni loop_uni: // sum += x[i] * y[i] unrolled 4x. MOVUPD 0(R8)(SI*8), X0 MOVUPD 0(R9)(SI*8), X1 MOVUPD 16(R8)(SI*8), X2 MOVUPD 16(R9)(SI*8), X3 MULPD X1, X0 MULPD X3, X2 ADDPD X0, X7 ADDPD X2, X8 ADDQ $4, SI // i += 4 SUBQ $4, DI // n -= 4 JGE loop_uni // if n >= 0 goto loop_uni tail_uni: ADDQ $4, DI // n += 4 JLE end_uni // if n <= 0 goto end_uni onemore_uni: // sum += x[i] * y[i] for the remaining 1-3 elements. MOVSD 0(R8)(SI*8), X0 MOVSD 0(R9)(SI*8), X1 MULSD X1, X0 ADDSD X0, X7 ADDQ $1, SI // i++ SUBQ $1, DI // n-- JNZ onemore_uni // if n != 0 goto onemore_uni end_uni: // Add the four sums together. ADDPD X8, X7 MOVSD X7, X0 UNPCKHPD X7, X7 ADDSD X0, X7 MOVSD X7, sum+48(FP) // Return final sum. RET // func DdotInc(x, y []float64, n, incX, incY, ix, iy uintptr) (sum float64) TEXT ·DotInc(SB), NOSPLIT, $0 MOVQ x+0(FP), R8 MOVQ y+24(FP), R9 MOVQ n+48(FP), CX MOVQ incX+56(FP), R11 MOVQ incY+64(FP), R12 MOVQ ix+72(FP), R13 MOVQ iy+80(FP), R14 MOVSD $(0.0), X7 // sum = 0 LEAQ (R8)(R13*8), SI // p = &x[ix] LEAQ (R9)(R14*8), DI // q = &y[ix] SHLQ $3, R11 // incX *= sizeof(float64) SHLQ $3, R12 // indY *= sizeof(float64) SUBQ $2, CX // n -= 2 JL tail_inc // if n < 0 goto tail_inc loop_inc: // sum += *p * *q unrolled 2x. MOVHPD (SI), X0 MOVHPD (DI), X1 ADDQ R11, SI // p += incX ADDQ R12, DI // q += incY MOVLPD (SI), X0 MOVLPD (DI), X1 ADDQ R11, SI // p += incX ADDQ R12, DI // q += incY MULPD X1, X0 ADDPD X0, X7 SUBQ $2, CX // n -= 2 JGE loop_inc // if n >= 0 goto loop_inc tail_inc: ADDQ $2, CX // n += 2 JLE end_inc // if n <= 0 goto end_inc // sum += *p * *q for the last iteration if n is odd. MOVSD (SI), X0 MULSD (DI), X0 ADDSD X0, X7 end_inc: // Add the two sums together. MOVSD X7, X0 UNPCKHPD X7, X7 ADDSD X0, X7 MOVSD X7, sum+88(FP) // Return final sum. RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/dot_test.go000066400000000000000000000177321450372207100230170ustar00rootroot00000000000000// 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 f64_test import ( "fmt" "math" "testing" "golang.org/x/exp/rand" . "gonum.org/v1/gonum/internal/asm/f64" ) func TestDotUnitary(t *testing.T) { for i, test := range []struct { xData []float64 yData []float64 want float64 }{ { xData: []float64{2}, yData: []float64{-3}, want: -6, }, { xData: []float64{2, 3}, yData: []float64{-3, 4}, want: 6, }, { xData: []float64{2, 3, -4}, yData: []float64{-3, 4, 5}, want: -14, }, { xData: []float64{2, 3, -4, -5}, yData: []float64{-3, 4, 5, -6}, want: 16, }, { xData: []float64{0, 2, 3, -4, -5}, yData: []float64{0, -3, 4, 5, -6}, want: 16, }, { xData: []float64{0, 0, 2, 3, -4, -5}, yData: []float64{0, 1, -3, 4, 5, -6}, want: 16, }, { xData: []float64{0, 0, 1, 1, 2, -3, -4}, yData: []float64{0, 1, 0, 3, -4, 5, -6}, want: 4, }, { xData: []float64{0, 0, 1, 1, 2, -3, -4, 5}, yData: []float64{0, 1, 0, 3, -4, 5, -6, 7}, want: 39, }, } { const msgGuard = "test %v: out-of-bounds write to %v argument\nfront guard: %v\nback guard: %v" x, xFront, xBack := newGuardedVector(test.xData, 1) y, yFront, yBack := newGuardedVector(test.yData, 1) got := DotUnitary(x, y) if !allNaN(xFront) || !allNaN(xBack) { t.Errorf(msgGuard, i, "x", xFront, xBack) } if !allNaN(yFront) || !allNaN(yBack) { t.Errorf(msgGuard, i, "y", yFront, yBack) } if !equalStrided(test.xData, x, 1) { t.Errorf("test %v: modified read-only x argument", i) } if !equalStrided(test.yData, y, 1) { t.Errorf("test %v: modified read-only y argument", i) } if math.IsNaN(got) { t.Errorf("test %v: invalid memory read", i) continue } if got != test.want { t.Errorf("test %v: unexpected result. want %v, got %v", i, test.want, got) } } } func TestDotInc(t *testing.T) { for i, test := range []struct { xData []float64 yData []float64 want float64 wantRev float64 // Result when one of the vectors is reversed. }{ { xData: []float64{2}, yData: []float64{-3}, want: -6, wantRev: -6, }, { xData: []float64{2, 3}, yData: []float64{-3, 4}, want: 6, wantRev: -1, }, { xData: []float64{2, 3, -4}, yData: []float64{-3, 4, 5}, want: -14, wantRev: 34, }, { xData: []float64{2, 3, -4, -5}, yData: []float64{-3, 4, 5, -6}, want: 16, wantRev: 2, }, { xData: []float64{0, 2, 3, -4, -5}, yData: []float64{0, -3, 4, 5, -6}, want: 16, wantRev: 34, }, { xData: []float64{0, 0, 2, 3, -4, -5}, yData: []float64{0, 1, -3, 4, 5, -6}, want: 16, wantRev: -5, }, { xData: []float64{0, 0, 1, 1, 2, -3, -4}, yData: []float64{0, 1, 0, 3, -4, 5, -6}, want: 4, wantRev: -4, }, { xData: []float64{0, 0, 1, 1, 2, -3, -4, 5}, yData: []float64{0, 1, 0, 3, -4, 5, -6, 7}, want: 39, wantRev: 3, }, } { const msgGuard = "%v: out-of-bounds write to %v argument\nfront guard: %v\nback guard: %v" for _, incX := range []int{-7, -3, -2, -1, 1, 2, 3, 7} { for _, incY := range []int{-7, -3, -2, -1, 1, 2, 3, 7} { n := len(test.xData) x, xFront, xBack := newGuardedVector(test.xData, incX) y, yFront, yBack := newGuardedVector(test.yData, incY) var ix, iy int if incX < 0 { ix = (-n + 1) * incX } if incY < 0 { iy = (-n + 1) * incY } got := DotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy)) prefix := fmt.Sprintf("test %v, incX = %v, incY = %v", i, incX, incY) if !allNaN(xFront) || !allNaN(xBack) { t.Errorf(msgGuard, prefix, "x", xFront, xBack) } if !allNaN(yFront) || !allNaN(yBack) { t.Errorf(msgGuard, prefix, "y", yFront, yBack) } if nonStridedWrite(x, incX) || !equalStrided(test.xData, x, incX) { t.Errorf("%v: modified read-only x argument", prefix) } if nonStridedWrite(y, incY) || !equalStrided(test.yData, y, incY) { t.Errorf("%v: modified read-only y argument", prefix) } if math.IsNaN(got) { t.Errorf("%v: invalid memory read", prefix) continue } want := test.want if incX*incY < 0 { want = test.wantRev } if got != want { t.Errorf("%v: unexpected result. want %v, got %v", prefix, want, got) } } } } } func BenchmarkDotUnitaryN1(b *testing.B) { dotUnitaryBenchmark(b, 1) } func BenchmarkDotUnitaryN2(b *testing.B) { dotUnitaryBenchmark(b, 2) } func BenchmarkDotUnitaryN3(b *testing.B) { dotUnitaryBenchmark(b, 3) } func BenchmarkDotUnitaryN4(b *testing.B) { dotUnitaryBenchmark(b, 4) } func BenchmarkDotUnitaryN10(b *testing.B) { dotUnitaryBenchmark(b, 10) } func BenchmarkDotUnitaryN100(b *testing.B) { dotUnitaryBenchmark(b, 100) } func BenchmarkDotUnitaryN1000(b *testing.B) { dotUnitaryBenchmark(b, 1000) } func BenchmarkDotUnitaryN10000(b *testing.B) { dotUnitaryBenchmark(b, 10000) } func BenchmarkDotUnitaryN100000(b *testing.B) { dotUnitaryBenchmark(b, 100000) } var r float64 func dotUnitaryBenchmark(b *testing.B, n int) { x := make([]float64, n) for i := range x { x[i] = rand.Float64() } y := make([]float64, n) for i := range y { y[i] = rand.Float64() } b.ResetTimer() for i := 0; i < b.N; i++ { r = DotUnitary(x, y) } } func BenchmarkDotIncN1Inc1(b *testing.B) { dotIncBenchmark(b, 1, 1) } func BenchmarkDotIncN2Inc1(b *testing.B) { dotIncBenchmark(b, 2, 1) } func BenchmarkDotIncN2Inc2(b *testing.B) { dotIncBenchmark(b, 2, 2) } func BenchmarkDotIncN2Inc4(b *testing.B) { dotIncBenchmark(b, 2, 4) } func BenchmarkDotIncN2Inc10(b *testing.B) { dotIncBenchmark(b, 2, 10) } func BenchmarkDotIncN3Inc1(b *testing.B) { dotIncBenchmark(b, 3, 1) } func BenchmarkDotIncN3Inc2(b *testing.B) { dotIncBenchmark(b, 3, 2) } func BenchmarkDotIncN3Inc4(b *testing.B) { dotIncBenchmark(b, 3, 4) } func BenchmarkDotIncN3Inc10(b *testing.B) { dotIncBenchmark(b, 3, 10) } func BenchmarkDotIncN4Inc1(b *testing.B) { dotIncBenchmark(b, 4, 1) } func BenchmarkDotIncN4Inc2(b *testing.B) { dotIncBenchmark(b, 4, 2) } func BenchmarkDotIncN4Inc4(b *testing.B) { dotIncBenchmark(b, 4, 4) } func BenchmarkDotIncN4Inc10(b *testing.B) { dotIncBenchmark(b, 4, 10) } func BenchmarkDotIncN10Inc1(b *testing.B) { dotIncBenchmark(b, 10, 1) } func BenchmarkDotIncN10Inc2(b *testing.B) { dotIncBenchmark(b, 10, 2) } func BenchmarkDotIncN10Inc4(b *testing.B) { dotIncBenchmark(b, 10, 4) } func BenchmarkDotIncN10Inc10(b *testing.B) { dotIncBenchmark(b, 10, 10) } func BenchmarkDotIncN1000Inc1(b *testing.B) { dotIncBenchmark(b, 1000, 1) } func BenchmarkDotIncN1000Inc2(b *testing.B) { dotIncBenchmark(b, 1000, 2) } func BenchmarkDotIncN1000Inc4(b *testing.B) { dotIncBenchmark(b, 1000, 4) } func BenchmarkDotIncN1000Inc10(b *testing.B) { dotIncBenchmark(b, 1000, 10) } func BenchmarkDotIncN100000Inc1(b *testing.B) { dotIncBenchmark(b, 100000, 1) } func BenchmarkDotIncN100000Inc2(b *testing.B) { dotIncBenchmark(b, 100000, 2) } func BenchmarkDotIncN100000Inc4(b *testing.B) { dotIncBenchmark(b, 100000, 4) } func BenchmarkDotIncN100000Inc10(b *testing.B) { dotIncBenchmark(b, 100000, 10) } func BenchmarkDotIncN100000IncM1(b *testing.B) { dotIncBenchmark(b, 100000, -1) } func BenchmarkDotIncN100000IncM2(b *testing.B) { dotIncBenchmark(b, 100000, -2) } func BenchmarkDotIncN100000IncM4(b *testing.B) { dotIncBenchmark(b, 100000, -4) } func BenchmarkDotIncN100000IncM10(b *testing.B) { dotIncBenchmark(b, 100000, -10) } func dotIncBenchmark(b *testing.B, n, inc int) { absInc := inc if inc < 0 { absInc = -inc } x := make([]float64, (n-1)*absInc+1) for i := range x { x[i] = rand.Float64() } y := make([]float64, (n-1)*absInc+1) for i := range y { y[i] = rand.Float64() } var ini int if inc < 0 { ini = (-n + 1) * inc } b.ResetTimer() for i := 0; i < b.N; i++ { r = DotInc(x, y, uintptr(n), uintptr(inc), uintptr(inc), uintptr(ini), uintptr(ini)) } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/ge_amd64.go000066400000000000000000000020651450372207100225510ustar00rootroot00000000000000// 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. //go:build !noasm && !gccgo && !safe // +build !noasm,!gccgo,!safe package f64 // Ger performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar. func Ger(m, n uintptr, alpha float64, x []float64, incX uintptr, y []float64, incY uintptr, a []float64, lda uintptr) // GemvN computes // // y = alpha * A * x + beta * y // // where A is an m×n dense matrix, x and y are vectors, and alpha and beta are scalars. func GemvN(m, n uintptr, alpha float64, a []float64, lda uintptr, x []float64, incX uintptr, beta float64, y []float64, incY uintptr) // GemvT computes // // y = alpha * Aᵀ * x + beta * y // // where A is an m×n dense matrix, x and y are vectors, and alpha and beta are scalars. func GemvT(m, n uintptr, alpha float64, a []float64, lda uintptr, x []float64, incX uintptr, beta float64, y []float64, incY uintptr) golang-gonum-v1-gonum-0.14.0/internal/asm/f64/ge_noasm.go000066400000000000000000000056051450372207100227560ustar00rootroot00000000000000// 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. //go:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f64 // Ger performs the rank-one operation // // A += alpha * x * yᵀ // // where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar. func Ger(m, n uintptr, alpha float64, x []float64, incX uintptr, y []float64, incY uintptr, a []float64, lda uintptr) { if incX == 1 && incY == 1 { x = x[:m] y = y[:n] for i, xv := range x { AxpyUnitary(alpha*xv, y, a[uintptr(i)*lda:uintptr(i)*lda+n]) } return } var ky, kx uintptr if int(incY) < 0 { ky = uintptr(-int(n-1) * int(incY)) } if int(incX) < 0 { kx = uintptr(-int(m-1) * int(incX)) } ix := kx for i := 0; i < int(m); i++ { AxpyInc(alpha*x[ix], y, a[uintptr(i)*lda:uintptr(i)*lda+n], n, incY, 1, ky, 0) ix += incX } } // GemvN computes // // y = alpha * A * x + beta * y // // where A is an m×n dense matrix, x and y are vectors, and alpha and beta are scalars. func GemvN(m, n uintptr, alpha float64, a []float64, lda uintptr, x []float64, incX uintptr, beta float64, y []float64, incY uintptr) { var kx, ky, i uintptr if int(incX) < 0 { kx = uintptr(-int(n-1) * int(incX)) } if int(incY) < 0 { ky = uintptr(-int(m-1) * int(incY)) } if incX == 1 && incY == 1 { if beta == 0 { for i = 0; i < m; i++ { y[i] = alpha * DotUnitary(a[lda*i:lda*i+n], x) } return } for i = 0; i < m; i++ { y[i] = y[i]*beta + alpha*DotUnitary(a[lda*i:lda*i+n], x) } return } iy := ky if beta == 0 { for i = 0; i < m; i++ { y[iy] = alpha * DotInc(x, a[lda*i:lda*i+n], n, incX, 1, kx, 0) iy += incY } return } for i = 0; i < m; i++ { y[iy] = y[iy]*beta + alpha*DotInc(x, a[lda*i:lda*i+n], n, incX, 1, kx, 0) iy += incY } } // GemvT computes // // y = alpha * Aᵀ * x + beta * y // // where A is an m×n dense matrix, x and y are vectors, and alpha and beta are scalars. func GemvT(m, n uintptr, alpha float64, a []float64, lda uintptr, x []float64, incX uintptr, beta float64, y []float64, incY uintptr) { var kx, ky, i uintptr if int(incX) < 0 { kx = uintptr(-int(m-1) * int(incX)) } if int(incY) < 0 { ky = uintptr(-int(n-1) * int(incY)) } switch { case beta == 0: // beta == 0 is special-cased to memclear if incY == 1 { for i := range y { y[i] = 0 } } else { iy := ky for i := 0; i < int(n); i++ { y[iy] = 0 iy += incY } } case int(incY) < 0: ScalInc(beta, y, n, uintptr(int(-incY))) case incY == 1: ScalUnitary(beta, y[:n]) default: ScalInc(beta, y, n, incY) } if incX == 1 && incY == 1 { for i = 0; i < m; i++ { AxpyUnitaryTo(y, alpha*x[i], a[lda*i:lda*i+n], y) } return } ix := kx for i = 0; i < m; i++ { AxpyInc(alpha*x[ix], a[lda*i:lda*i+n], y, n, 1, incY, 0, ky) ix += incX } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/ge_test.go000066400000000000000000000140321450372207100226120ustar00rootroot00000000000000// 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 f64_test import ( "fmt" "testing" . "gonum.org/v1/gonum/internal/asm/f64" ) var gerTests = []struct { x, y, a []float64 want []float64 }{ // m x n ( kernels executed ) { // 1 x 1 (1x1) x: []float64{2}, y: []float64{4.4}, a: []float64{10}, want: []float64{18.8}, }, { // 3 x 2 ( 2x2, 1x2 ) x: []float64{-2, -3, 0}, y: []float64{-1.1, 5}, a: []float64{ 1.3, 2.4, 2.6, 2.8, -1.3, -4.3, }, want: []float64{3.5, -7.6, 5.9, -12.2, -1.3, -4.3}, }, { // 3 x 3 ( 2x2, 2x1, 1x2, 1x1 ) x: []float64{-2, 7, 12}, y: []float64{-1.1, 0, 6}, a: []float64{ 1.3, 2.4, 3.5, 2.6, 2.8, 3.3, -1.3, -4.3, -9.7, }, want: []float64{3.5, 2.4, -8.5, -5.1, 2.8, 45.3, -14.5, -4.3, 62.3}, }, { // 5 x 3 ( 4x2, 4x1, 1x2, 1x1 ) x: []float64{-2, -3, 0, 1, 2}, y: []float64{-1.1, 5, 0}, a: []float64{ 1.3, 2.4, 3.5, 2.6, 2.8, 3.3, -1.3, -4.3, -9.7, 8, 9, -10, -12, -14, -6, }, want: []float64{3.5, -7.6, 3.5, 5.9, -12.2, 3.3, -1.3, -4.3, -9.7, 6.9, 14, -10, -14.2, -4, -6}, }, { // 3 x 6 ( 2x4, 2x2, 1x4, 1x2 ) x: []float64{-2, -3, 0}, y: []float64{-1.1, 5, 0, 9, 19, 22}, a: []float64{ 1.3, 2.4, 3.5, 4.8, 1.11, -9, 2.6, 2.8, 3.3, -3.4, 6.2, -8.7, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9, }, want: []float64{3.5, -7.6, 3.5, -13.2, -36.89, -53, 5.9, -12.2, 3.3, -30.4, -50.8, -74.7, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9}, }, { // 5 x 5 ( 4x4, 4x1, 1x4, 1x1) x: []float64{-2, 0, 2, 0, 7}, y: []float64{-1.1, 8, 7, 3, 5}, a: []float64{ 1.3, 2.4, 3.5, 2.2, 8.3, 2.6, 2.8, 3.3, 4.4, -1.5, -1.3, -4.3, -9.7, -8.8, 6.2, 8, 9, -10, -11, 12, -12, -14, -6, -2, 4, }, want: []float64{ 3.5, -13.6, -10.5, -3.8, -1.7, 2.6, 2.8, 3.3, 4.4, -1.5, -3.5, 11.7, 4.3, -2.8, 16.2, 8, 9, -10, -11, 12, -19.700000000000003, 42, 43, 19, 39, }, }, { // 7 x 7 ( 4x4, 4x2, 4x1, 2x4, 2x2, 2x1, 1x4, 1x2, 1x1 ) < nan test > x: []float64{-2, 8, 9, -3, -1.2, 5, 4.5}, y: []float64{-1.1, nan, 19, 11, -9.22, 7, 3.3}, a: []float64{ 1.3, 2.4, 3.5, 4.8, 1.11, -9, 2.2, 2.6, 2.8, 3.3, -3.4, 6.2, -8.7, 5.1, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9, 8, 5, -2.5, 1.8, -3.6, 2.8, 4.9, 7, -1.3, -4.3, -9.7, -3.1, 8.9, 8.9, 8, 2.6, 2.8, 3.3, -3.4, 6.2, -8.7, 5.1, 1.3, 2.4, 3.5, 4.8, 1.11, -9, 2.2, }, want: []float64{ 3.5, nan, -34.5, -17.2, 19.55, -23, -4.4, -6.2, nan, 155.3, 84.6, -67.56, 47.3, 31.5, -11.2, nan, 161.3, 95.9, -74.08, 71.9, 37.7, 8.3, nan, -55.2, -36.6, 30.46, -16.1, -2.9, 0.02, nan, -32.5, -16.3, 19.964, 0.5, 4.04, -2.9, nan, 98.3, 51.6, -39.9, 26.3, 21.6, -3.65, nan, 89, 54.3, -40.38, 22.5, 17.05, }, }, } func TestGer(t *testing.T) { const ( tol = 1e-15 xGdVal, yGdVal, aGdVal = -0.5, 1.5, 10 gdLn = 4 ) for i, test := range gerTests { m, n := len(test.x), len(test.y) for _, align := range align2 { prefix := fmt.Sprintf("Test %v (%vx%v) align(x:%v,y:%v,a:%v)", i, m, n, align.x, align.y, align.x^align.y) xgLn, ygLn, agLn := gdLn+align.x, gdLn+align.y, gdLn+align.x^align.y xg, yg := guardVector(test.x, xGdVal, xgLn), guardVector(test.y, yGdVal, ygLn) x, y := xg[xgLn:len(xg)-xgLn], yg[ygLn:len(yg)-ygLn] ag := guardVector(test.a, aGdVal, agLn) a := ag[agLn : len(ag)-agLn] alpha := 1.0 Ger(uintptr(m), uintptr(n), alpha, x, 1, y, 1, a, uintptr(n)) for i := range test.want { if !sameApprox(a[i], test.want[i], tol) { t.Errorf(msgVal, prefix, i, a[i], test.want[i]) t.Error(a) return } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(yg, yGdVal, ygLn) { t.Errorf(msgGuard, prefix, "y", yg[:ygLn], yg[len(yg)-ygLn:]) } if !isValidGuard(ag, aGdVal, agLn) { t.Errorf(msgGuard, prefix, "a", ag[:agLn], ag[len(ag)-agLn:]) } if !equalStrided(test.x, x, 1) { t.Errorf(msgReadOnly, prefix, "x") } if !equalStrided(test.y, y, 1) { t.Errorf(msgReadOnly, prefix, "y") } } for _, inc := range newIncSet(1, 2) { prefix := fmt.Sprintf("Test %v (%vx%v) inc(x:%v,y:%v)", i, m, n, inc.x, inc.y) xg := guardIncVector(test.x, xGdVal, inc.x, gdLn) yg := guardIncVector(test.y, yGdVal, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] ag := guardVector(test.a, aGdVal, gdLn) a := ag[gdLn : len(ag)-gdLn] alpha := 3.5 Ger(uintptr(m), uintptr(n), alpha, x, uintptr(inc.x), y, uintptr(inc.y), a, uintptr(n)) for i := range test.want { want := alpha*(test.want[i]-test.a[i]) + test.a[i] if !sameApprox(a[i], want, tol) { t.Errorf(msgVal, prefix, i, a[i], want) } } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) if !isValidGuard(ag, aGdVal, gdLn) { t.Errorf(msgGuard, prefix, "a", ag[:gdLn], ag[len(ag)-gdLn:]) } if !equalStrided(test.x, x, inc.x) { t.Errorf(msgReadOnly, prefix, "x") } if !equalStrided(test.y, y, inc.y) { t.Errorf(msgReadOnly, prefix, "y") } } } } func BenchmarkGer(t *testing.B) { const alpha = 3 for _, dims := range newIncSet(3, 10, 30, 100, 300, 1e3, 3e3, 1e4) { m, n := dims.x, dims.y if m/n >= 100 || n/m >= 100 { continue } for _, inc := range newIncSet(1, 3, 4, 10) { t.Run(fmt.Sprintf("Dger %dx%d (%d %d)", m, n, inc.x, inc.y), func(b *testing.B) { x, y, a := gerData(m, n, inc.x, inc.y) b.ResetTimer() for i := 0; i < b.N; i++ { Ger(uintptr(m), uintptr(n), alpha, x, uintptr(inc.x), y, uintptr(inc.y), a, uintptr(n)) } }) } } } func gerData(m, n, incX, incY int) (x, y, a []float64) { x = make([]float64, m*incX) y = make([]float64, n*incY) a = make([]float64, m*n) ln := len(x) if len(y) > ln { ln = len(y) } if len(a) > ln { ln = len(a) } for i := 0; i < ln; i++ { v := float64(i) if i < len(a) { a[i] = v } if i < len(x) { x[i] = v } if i < len(y) { y[i] = v } } return x, y, a } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/gemvN_amd64.s000066400000000000000000000264311450372207100230720ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SIZE 8 #define M_DIM m+0(FP) #define M CX #define N_DIM n+8(FP) #define N BX #define TMP1 R14 #define TMP2 R15 #define X_PTR SI #define X x_base+56(FP) #define INC_X R8 #define INC3_X R9 #define Y_PTR DX #define Y y_base+96(FP) #define INC_Y R10 #define INC3_Y R11 #define A_ROW AX #define A_PTR DI #define LDA R12 #define LDA3 R13 #define ALPHA X15 #define BETA X14 #define INIT4 \ XORPS X0, X0 \ XORPS X1, X1 \ XORPS X2, X2 \ XORPS X3, X3 #define INIT2 \ XORPS X0, X0 \ XORPS X1, X1 #define INIT1 \ XORPS X0, X0 #define KERNEL_LOAD4 \ MOVUPS (X_PTR), X12 \ MOVUPS 2*SIZE(X_PTR), X13 #define KERNEL_LOAD2 \ MOVUPS (X_PTR), X12 #define KERNEL_LOAD4_INC \ MOVSD (X_PTR), X12 \ MOVHPD (X_PTR)(INC_X*1), X12 \ MOVSD (X_PTR)(INC_X*2), X13 \ MOVHPD (X_PTR)(INC3_X*1), X13 #define KERNEL_LOAD2_INC \ MOVSD (X_PTR), X12 \ MOVHPD (X_PTR)(INC_X*1), X12 #define KERNEL_4x4 \ MOVUPS (A_PTR), X4 \ MOVUPS 2*SIZE(A_PTR), X5 \ MOVUPS (A_PTR)(LDA*1), X6 \ MOVUPS 2*SIZE(A_PTR)(LDA*1), X7 \ MOVUPS (A_PTR)(LDA*2), X8 \ MOVUPS 2*SIZE(A_PTR)(LDA*2), X9 \ MOVUPS (A_PTR)(LDA3*1), X10 \ MOVUPS 2*SIZE(A_PTR)(LDA3*1), X11 \ MULPD X12, X4 \ MULPD X13, X5 \ MULPD X12, X6 \ MULPD X13, X7 \ MULPD X12, X8 \ MULPD X13, X9 \ MULPD X12, X10 \ MULPD X13, X11 \ ADDPD X4, X0 \ ADDPD X5, X0 \ ADDPD X6, X1 \ ADDPD X7, X1 \ ADDPD X8, X2 \ ADDPD X9, X2 \ ADDPD X10, X3 \ ADDPD X11, X3 \ ADDQ $4*SIZE, A_PTR #define KERNEL_4x2 \ MOVUPS (A_PTR), X4 \ MOVUPS (A_PTR)(LDA*1), X5 \ MOVUPS (A_PTR)(LDA*2), X6 \ MOVUPS (A_PTR)(LDA3*1), X7 \ MULPD X12, X4 \ MULPD X12, X5 \ MULPD X12, X6 \ MULPD X12, X7 \ ADDPD X4, X0 \ ADDPD X5, X1 \ ADDPD X6, X2 \ ADDPD X7, X3 \ ADDQ $2*SIZE, A_PTR #define KERNEL_4x1 \ MOVDDUP (X_PTR), X12 \ MOVSD (A_PTR), X4 \ MOVHPD (A_PTR)(LDA*1), X4 \ MOVSD (A_PTR)(LDA*2), X5 \ MOVHPD (A_PTR)(LDA3*1), X5 \ MULPD X12, X4 \ MULPD X12, X5 \ ADDPD X4, X0 \ ADDPD X5, X2 \ ADDQ $SIZE, A_PTR #define STORE4 \ MOVUPS (Y_PTR), X4 \ MOVUPS 2*SIZE(Y_PTR), X5 \ MULPD ALPHA, X0 \ MULPD ALPHA, X2 \ MULPD BETA, X4 \ MULPD BETA, X5 \ ADDPD X0, X4 \ ADDPD X2, X5 \ MOVUPS X4, (Y_PTR) \ MOVUPS X5, 2*SIZE(Y_PTR) #define STORE4_INC \ MOVSD (Y_PTR), X4 \ MOVHPD (Y_PTR)(INC_Y*1), X4 \ MOVSD (Y_PTR)(INC_Y*2), X5 \ MOVHPD (Y_PTR)(INC3_Y*1), X5 \ MULPD ALPHA, X0 \ MULPD ALPHA, X2 \ MULPD BETA, X4 \ MULPD BETA, X5 \ ADDPD X0, X4 \ ADDPD X2, X5 \ MOVLPD X4, (Y_PTR) \ MOVHPD X4, (Y_PTR)(INC_Y*1) \ MOVLPD X5, (Y_PTR)(INC_Y*2) \ MOVHPD X5, (Y_PTR)(INC3_Y*1) #define KERNEL_2x4 \ MOVUPS (A_PTR), X8 \ MOVUPS 2*SIZE(A_PTR), X9 \ MOVUPS (A_PTR)(LDA*1), X10 \ MOVUPS 2*SIZE(A_PTR)(LDA*1), X11 \ MULPD X12, X8 \ MULPD X13, X9 \ MULPD X12, X10 \ MULPD X13, X11 \ ADDPD X8, X0 \ ADDPD X10, X1 \ ADDPD X9, X0 \ ADDPD X11, X1 \ ADDQ $4*SIZE, A_PTR #define KERNEL_2x2 \ MOVUPS (A_PTR), X8 \ MOVUPS (A_PTR)(LDA*1), X9 \ MULPD X12, X8 \ MULPD X12, X9 \ ADDPD X8, X0 \ ADDPD X9, X1 \ ADDQ $2*SIZE, A_PTR #define KERNEL_2x1 \ MOVDDUP (X_PTR), X12 \ MOVSD (A_PTR), X8 \ MOVHPD (A_PTR)(LDA*1), X8 \ MULPD X12, X8 \ ADDPD X8, X0 \ ADDQ $SIZE, A_PTR #define STORE2 \ MOVUPS (Y_PTR), X4 \ MULPD ALPHA, X0 \ MULPD BETA, X4 \ ADDPD X0, X4 \ MOVUPS X4, (Y_PTR) #define STORE2_INC \ MOVSD (Y_PTR), X4 \ MOVHPD (Y_PTR)(INC_Y*1), X4 \ MULPD ALPHA, X0 \ MULPD BETA, X4 \ ADDPD X0, X4 \ MOVSD X4, (Y_PTR) \ MOVHPD X4, (Y_PTR)(INC_Y*1) #define KERNEL_1x4 \ MOVUPS (A_PTR), X8 \ MOVUPS 2*SIZE(A_PTR), X9 \ MULPD X12, X8 \ MULPD X13, X9 \ ADDPD X8, X0 \ ADDPD X9, X0 \ ADDQ $4*SIZE, A_PTR #define KERNEL_1x2 \ MOVUPS (A_PTR), X8 \ MULPD X12, X8 \ ADDPD X8, X0 \ ADDQ $2*SIZE, A_PTR #define KERNEL_1x1 \ MOVSD (X_PTR), X12 \ MOVSD (A_PTR), X8 \ MULSD X12, X8 \ ADDSD X8, X0 \ ADDQ $SIZE, A_PTR #define STORE1 \ HADDPD X0, X0 \ MOVSD (Y_PTR), X4 \ MULSD ALPHA, X0 \ MULSD BETA, X4 \ ADDSD X0, X4 \ MOVSD X4, (Y_PTR) // func GemvN(m, n int, // alpha float64, // a []float64, lda int, // x []float64, incX int, // beta float64, // y []float64, incY int) TEXT ·GemvN(SB), NOSPLIT, $32-128 MOVQ M_DIM, M MOVQ N_DIM, N CMPQ M, $0 JE end CMPQ N, $0 JE end MOVDDUP alpha+16(FP), ALPHA MOVDDUP beta+88(FP), BETA MOVQ x_base+56(FP), X_PTR MOVQ y_base+96(FP), Y_PTR MOVQ a_base+24(FP), A_ROW MOVQ incY+120(FP), INC_Y MOVQ lda+48(FP), LDA // LDA = LDA * sizeof(float64) SHLQ $3, LDA LEAQ (LDA)(LDA*2), LDA3 // LDA3 = LDA * 3 MOVQ A_ROW, A_PTR XORQ TMP2, TMP2 MOVQ M, TMP1 SUBQ $1, TMP1 IMULQ INC_Y, TMP1 NEGQ TMP1 CMPQ INC_Y, $0 CMOVQLT TMP1, TMP2 LEAQ (Y_PTR)(TMP2*SIZE), Y_PTR MOVQ Y_PTR, Y SHLQ $3, INC_Y // INC_Y = incY * sizeof(float64) LEAQ (INC_Y)(INC_Y*2), INC3_Y // INC3_Y = INC_Y * 3 MOVSD $0.0, X0 COMISD BETA, X0 JNE gemv_start // if beta != 0 { goto gemv_start } gemv_clear: // beta == 0 is special cased to clear memory (no nan handling) XORPS X0, X0 XORPS X1, X1 XORPS X2, X2 XORPS X3, X3 CMPQ incY+120(FP), $1 // Check for dense vector X (fast-path) JNE inc_clear SHRQ $3, M JZ clear4 clear8: MOVUPS X0, (Y_PTR) MOVUPS X1, 16(Y_PTR) MOVUPS X2, 32(Y_PTR) MOVUPS X3, 48(Y_PTR) ADDQ $8*SIZE, Y_PTR DECQ M JNZ clear8 clear4: TESTQ $4, M_DIM JZ clear2 MOVUPS X0, (Y_PTR) MOVUPS X1, 16(Y_PTR) ADDQ $4*SIZE, Y_PTR clear2: TESTQ $2, M_DIM JZ clear1 MOVUPS X0, (Y_PTR) ADDQ $2*SIZE, Y_PTR clear1: TESTQ $1, M_DIM JZ prep_end MOVSD X0, (Y_PTR) JMP prep_end inc_clear: SHRQ $2, M JZ inc_clear2 inc_clear4: MOVSD X0, (Y_PTR) MOVSD X1, (Y_PTR)(INC_Y*1) MOVSD X2, (Y_PTR)(INC_Y*2) MOVSD X3, (Y_PTR)(INC3_Y*1) LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ M JNZ inc_clear4 inc_clear2: TESTQ $2, M_DIM JZ inc_clear1 MOVSD X0, (Y_PTR) MOVSD X1, (Y_PTR)(INC_Y*1) LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_clear1: TESTQ $1, M_DIM JZ prep_end MOVSD X0, (Y_PTR) prep_end: MOVQ Y, Y_PTR MOVQ M_DIM, M gemv_start: CMPQ incX+80(FP), $1 // Check for dense vector X (fast-path) JNE inc SHRQ $2, M JZ r2 r4: // LOAD 4 INIT4 MOVQ N_DIM, N SHRQ $2, N JZ r4c2 r4c4: // 4x4 KERNEL KERNEL_LOAD4 KERNEL_4x4 ADDQ $4*SIZE, X_PTR DECQ N JNZ r4c4 r4c2: TESTQ $2, N_DIM JZ r4c1 // 4x2 KERNEL KERNEL_LOAD2 KERNEL_4x2 ADDQ $2*SIZE, X_PTR r4c1: HADDPD X1, X0 HADDPD X3, X2 TESTQ $1, N_DIM JZ r4end // 4x1 KERNEL KERNEL_4x1 ADDQ $SIZE, X_PTR r4end: CMPQ INC_Y, $SIZE JNZ r4st_inc STORE4 ADDQ $4*SIZE, Y_PTR JMP r4inc r4st_inc: STORE4_INC LEAQ (Y_PTR)(INC_Y*4), Y_PTR r4inc: MOVQ X, X_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ M JNZ r4 r2: TESTQ $2, M_DIM JZ r1 // LOAD 2 INIT2 MOVQ N_DIM, N SHRQ $2, N JZ r2c2 r2c4: // 2x4 KERNEL KERNEL_LOAD4 KERNEL_2x4 ADDQ $4*SIZE, X_PTR DECQ N JNZ r2c4 r2c2: TESTQ $2, N_DIM JZ r2c1 // 2x2 KERNEL KERNEL_LOAD2 KERNEL_2x2 ADDQ $2*SIZE, X_PTR r2c1: HADDPD X1, X0 TESTQ $1, N_DIM JZ r2end // 2x1 KERNEL KERNEL_2x1 ADDQ $SIZE, X_PTR r2end: CMPQ INC_Y, $SIZE JNE r2st_inc STORE2 ADDQ $2*SIZE, Y_PTR JMP r2inc r2st_inc: STORE2_INC LEAQ (Y_PTR)(INC_Y*2), Y_PTR r2inc: MOVQ X, X_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR r1: TESTQ $1, M_DIM JZ end // LOAD 1 INIT1 MOVQ N_DIM, N SHRQ $2, N JZ r1c2 r1c4: // 1x4 KERNEL KERNEL_LOAD4 KERNEL_1x4 ADDQ $4*SIZE, X_PTR DECQ N JNZ r1c4 r1c2: TESTQ $2, N_DIM JZ r1c1 // 1x2 KERNEL KERNEL_LOAD2 KERNEL_1x2 ADDQ $2*SIZE, X_PTR r1c1: TESTQ $1, N_DIM JZ r1end // 1x1 KERNEL KERNEL_1x1 r1end: STORE1 end: RET inc: // Algorithm for incX != 1 ( split loads in kernel ) MOVQ incX+80(FP), INC_X // INC_X = incX XORQ TMP2, TMP2 // TMP2 = 0 MOVQ N, TMP1 // TMP1 = N SUBQ $1, TMP1 // TMP1 -= 1 NEGQ TMP1 // TMP1 = -TMP1 IMULQ INC_X, TMP1 // TMP1 *= INC_X CMPQ INC_X, $0 // if INC_X < 0 { TMP2 = TMP1 } CMOVQLT TMP1, TMP2 LEAQ (X_PTR)(TMP2*SIZE), X_PTR // X_PTR = X_PTR[TMP2] MOVQ X_PTR, X // X = X_PTR SHLQ $3, INC_X LEAQ (INC_X)(INC_X*2), INC3_X // INC3_X = INC_X * 3 SHRQ $2, M JZ inc_r2 inc_r4: // LOAD 4 INIT4 MOVQ N_DIM, N SHRQ $2, N JZ inc_r4c2 inc_r4c4: // 4x4 KERNEL KERNEL_LOAD4_INC KERNEL_4x4 LEAQ (X_PTR)(INC_X*4), X_PTR DECQ N JNZ inc_r4c4 inc_r4c2: TESTQ $2, N_DIM JZ inc_r4c1 // 4x2 KERNEL KERNEL_LOAD2_INC KERNEL_4x2 LEAQ (X_PTR)(INC_X*2), X_PTR inc_r4c1: HADDPD X1, X0 HADDPD X3, X2 TESTQ $1, N_DIM JZ inc_r4end // 4x1 KERNEL KERNEL_4x1 ADDQ INC_X, X_PTR inc_r4end: CMPQ INC_Y, $SIZE JNE inc_r4st_inc STORE4 ADDQ $4*SIZE, Y_PTR JMP inc_r4inc inc_r4st_inc: STORE4_INC LEAQ (Y_PTR)(INC_Y*4), Y_PTR inc_r4inc: MOVQ X, X_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ M JNZ inc_r4 inc_r2: TESTQ $2, M_DIM JZ inc_r1 // LOAD 2 INIT2 MOVQ N_DIM, N SHRQ $2, N JZ inc_r2c2 inc_r2c4: // 2x4 KERNEL KERNEL_LOAD4_INC KERNEL_2x4 LEAQ (X_PTR)(INC_X*4), X_PTR DECQ N JNZ inc_r2c4 inc_r2c2: TESTQ $2, N_DIM JZ inc_r2c1 // 2x2 KERNEL KERNEL_LOAD2_INC KERNEL_2x2 LEAQ (X_PTR)(INC_X*2), X_PTR inc_r2c1: HADDPD X1, X0 TESTQ $1, N_DIM JZ inc_r2end // 2x1 KERNEL KERNEL_2x1 ADDQ INC_X, X_PTR inc_r2end: CMPQ INC_Y, $SIZE JNE inc_r2st_inc STORE2 ADDQ $2*SIZE, Y_PTR JMP inc_r2inc inc_r2st_inc: STORE2_INC LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_r2inc: MOVQ X, X_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR inc_r1: TESTQ $1, M_DIM JZ inc_end // LOAD 1 INIT1 MOVQ N_DIM, N SHRQ $2, N JZ inc_r1c2 inc_r1c4: // 1x4 KERNEL KERNEL_LOAD4_INC KERNEL_1x4 LEAQ (X_PTR)(INC_X*4), X_PTR DECQ N JNZ inc_r1c4 inc_r1c2: TESTQ $2, N_DIM JZ inc_r1c1 // 1x2 KERNEL KERNEL_LOAD2_INC KERNEL_1x2 LEAQ (X_PTR)(INC_X*2), X_PTR inc_r1c1: TESTQ $1, N_DIM JZ inc_r1end // 1x1 KERNEL KERNEL_1x1 inc_r1end: STORE1 inc_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/gemvT_amd64.s000066400000000000000000000303511450372207100230740ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SIZE 8 #define M_DIM n+8(FP) #define M CX #define N_DIM m+0(FP) #define N BX #define TMP1 R14 #define TMP2 R15 #define X_PTR SI #define X x_base+56(FP) #define Y_PTR DX #define Y y_base+96(FP) #define A_ROW AX #define A_PTR DI #define INC_X R8 #define INC3_X R9 #define INC_Y R10 #define INC3_Y R11 #define LDA R12 #define LDA3 R13 #define ALPHA X15 #define BETA X14 #define INIT4 \ MOVDDUP (X_PTR), X8 \ MOVDDUP (X_PTR)(INC_X*1), X9 \ MOVDDUP (X_PTR)(INC_X*2), X10 \ MOVDDUP (X_PTR)(INC3_X*1), X11 \ MULPD ALPHA, X8 \ MULPD ALPHA, X9 \ MULPD ALPHA, X10 \ MULPD ALPHA, X11 #define INIT2 \ MOVDDUP (X_PTR), X8 \ MOVDDUP (X_PTR)(INC_X*1), X9 \ MULPD ALPHA, X8 \ MULPD ALPHA, X9 #define INIT1 \ MOVDDUP (X_PTR), X8 \ MULPD ALPHA, X8 #define KERNEL_LOAD4 \ MOVUPS (Y_PTR), X0 \ MOVUPS 2*SIZE(Y_PTR), X1 #define KERNEL_LOAD2 \ MOVUPS (Y_PTR), X0 #define KERNEL_LOAD4_INC \ MOVSD (Y_PTR), X0 \ MOVHPD (Y_PTR)(INC_Y*1), X0 \ MOVSD (Y_PTR)(INC_Y*2), X1 \ MOVHPD (Y_PTR)(INC3_Y*1), X1 #define KERNEL_LOAD2_INC \ MOVSD (Y_PTR), X0 \ MOVHPD (Y_PTR)(INC_Y*1), X0 #define KERNEL_4x4 \ MOVUPS (A_PTR), X4 \ MOVUPS 2*SIZE(A_PTR), X5 \ MOVUPS (A_PTR)(LDA*1), X6 \ MOVUPS 2*SIZE(A_PTR)(LDA*1), X7 \ MULPD X8, X4 \ MULPD X8, X5 \ MULPD X9, X6 \ MULPD X9, X7 \ ADDPD X4, X0 \ ADDPD X5, X1 \ ADDPD X6, X0 \ ADDPD X7, X1 \ MOVUPS (A_PTR)(LDA*2), X4 \ MOVUPS 2*SIZE(A_PTR)(LDA*2), X5 \ MOVUPS (A_PTR)(LDA3*1), X6 \ MOVUPS 2*SIZE(A_PTR)(LDA3*1), X7 \ MULPD X10, X4 \ MULPD X10, X5 \ MULPD X11, X6 \ MULPD X11, X7 \ ADDPD X4, X0 \ ADDPD X5, X1 \ ADDPD X6, X0 \ ADDPD X7, X1 \ ADDQ $4*SIZE, A_PTR #define KERNEL_4x2 \ MOVUPS (A_PTR), X4 \ MOVUPS 2*SIZE(A_PTR), X5 \ MOVUPS (A_PTR)(LDA*1), X6 \ MOVUPS 2*SIZE(A_PTR)(LDA*1), X7 \ MULPD X8, X4 \ MULPD X8, X5 \ MULPD X9, X6 \ MULPD X9, X7 \ ADDPD X4, X0 \ ADDPD X5, X1 \ ADDPD X6, X0 \ ADDPD X7, X1 \ ADDQ $4*SIZE, A_PTR #define KERNEL_4x1 \ MOVUPS (A_PTR), X4 \ MOVUPS 2*SIZE(A_PTR), X5 \ MULPD X8, X4 \ MULPD X8, X5 \ ADDPD X4, X0 \ ADDPD X5, X1 \ ADDQ $4*SIZE, A_PTR #define STORE4 \ MOVUPS X0, (Y_PTR) \ MOVUPS X1, 2*SIZE(Y_PTR) #define STORE4_INC \ MOVLPD X0, (Y_PTR) \ MOVHPD X0, (Y_PTR)(INC_Y*1) \ MOVLPD X1, (Y_PTR)(INC_Y*2) \ MOVHPD X1, (Y_PTR)(INC3_Y*1) #define KERNEL_2x4 \ MOVUPS (A_PTR), X4 \ MOVUPS (A_PTR)(LDA*1), X5 \ MOVUPS (A_PTR)(LDA*2), X6 \ MOVUPS (A_PTR)(LDA3*1), X7 \ MULPD X8, X4 \ MULPD X9, X5 \ MULPD X10, X6 \ MULPD X11, X7 \ ADDPD X4, X0 \ ADDPD X5, X0 \ ADDPD X6, X0 \ ADDPD X7, X0 \ ADDQ $2*SIZE, A_PTR #define KERNEL_2x2 \ MOVUPS (A_PTR), X4 \ MOVUPS (A_PTR)(LDA*1), X5 \ MULPD X8, X4 \ MULPD X9, X5 \ ADDPD X4, X0 \ ADDPD X5, X0 \ ADDQ $2*SIZE, A_PTR #define KERNEL_2x1 \ MOVUPS (A_PTR), X4 \ MULPD X8, X4 \ ADDPD X4, X0 \ ADDQ $2*SIZE, A_PTR #define STORE2 \ MOVUPS X0, (Y_PTR) #define STORE2_INC \ MOVLPD X0, (Y_PTR) \ MOVHPD X0, (Y_PTR)(INC_Y*1) #define KERNEL_1x4 \ MOVSD (Y_PTR), X0 \ MOVSD (A_PTR), X4 \ MOVSD (A_PTR)(LDA*1), X5 \ MOVSD (A_PTR)(LDA*2), X6 \ MOVSD (A_PTR)(LDA3*1), X7 \ MULSD X8, X4 \ MULSD X9, X5 \ MULSD X10, X6 \ MULSD X11, X7 \ ADDSD X4, X0 \ ADDSD X5, X0 \ ADDSD X6, X0 \ ADDSD X7, X0 \ MOVSD X0, (Y_PTR) \ ADDQ $SIZE, A_PTR #define KERNEL_1x2 \ MOVSD (Y_PTR), X0 \ MOVSD (A_PTR), X4 \ MOVSD (A_PTR)(LDA*1), X5 \ MULSD X8, X4 \ MULSD X9, X5 \ ADDSD X4, X0 \ ADDSD X5, X0 \ MOVSD X0, (Y_PTR) \ ADDQ $SIZE, A_PTR #define KERNEL_1x1 \ MOVSD (Y_PTR), X0 \ MOVSD (A_PTR), X4 \ MULSD X8, X4 \ ADDSD X4, X0 \ MOVSD X0, (Y_PTR) \ ADDQ $SIZE, A_PTR #define SCALE_8(PTR, SCAL) \ MOVUPS (PTR), X0 \ MOVUPS 16(PTR), X1 \ MOVUPS 32(PTR), X2 \ MOVUPS 48(PTR), X3 \ MULPD SCAL, X0 \ MULPD SCAL, X1 \ MULPD SCAL, X2 \ MULPD SCAL, X3 \ MOVUPS X0, (PTR) \ MOVUPS X1, 16(PTR) \ MOVUPS X2, 32(PTR) \ MOVUPS X3, 48(PTR) #define SCALE_4(PTR, SCAL) \ MOVUPS (PTR), X0 \ MOVUPS 16(PTR), X1 \ MULPD SCAL, X0 \ MULPD SCAL, X1 \ MOVUPS X0, (PTR) \ MOVUPS X1, 16(PTR) \ #define SCALE_2(PTR, SCAL) \ MOVUPS (PTR), X0 \ MULPD SCAL, X0 \ MOVUPS X0, (PTR) \ #define SCALE_1(PTR, SCAL) \ MOVSD (PTR), X0 \ MULSD SCAL, X0 \ MOVSD X0, (PTR) \ #define SCALEINC_4(PTR, INC, INC3, SCAL) \ MOVSD (PTR), X0 \ MOVSD (PTR)(INC*1), X1 \ MOVSD (PTR)(INC*2), X2 \ MOVSD (PTR)(INC3*1), X3 \ MULSD SCAL, X0 \ MULSD SCAL, X1 \ MULSD SCAL, X2 \ MULSD SCAL, X3 \ MOVSD X0, (PTR) \ MOVSD X1, (PTR)(INC*1) \ MOVSD X2, (PTR)(INC*2) \ MOVSD X3, (PTR)(INC3*1) #define SCALEINC_2(PTR, INC, SCAL) \ MOVSD (PTR), X0 \ MOVSD (PTR)(INC*1), X1 \ MULSD SCAL, X0 \ MULSD SCAL, X1 \ MOVSD X0, (PTR) \ MOVSD X1, (PTR)(INC*1) // func GemvT(m, n int, // alpha float64, // a []float64, lda int, // x []float64, incX int, // beta float64, // y []float64, incY int) TEXT ·GemvT(SB), NOSPLIT, $32-128 MOVQ M_DIM, M MOVQ N_DIM, N CMPQ M, $0 JE end CMPQ N, $0 JE end MOVDDUP alpha+16(FP), ALPHA MOVQ x_base+56(FP), X_PTR MOVQ y_base+96(FP), Y_PTR MOVQ a_base+24(FP), A_ROW MOVQ incY+120(FP), INC_Y // INC_Y = incY * sizeof(float64) MOVQ lda+48(FP), LDA // LDA = LDA * sizeof(float64) SHLQ $3, LDA LEAQ (LDA)(LDA*2), LDA3 // LDA3 = LDA * 3 MOVQ A_ROW, A_PTR MOVQ incX+80(FP), INC_X // INC_X = incX * sizeof(float64) XORQ TMP2, TMP2 MOVQ N, TMP1 SUBQ $1, TMP1 NEGQ TMP1 IMULQ INC_X, TMP1 CMPQ INC_X, $0 CMOVQLT TMP1, TMP2 LEAQ (X_PTR)(TMP2*SIZE), X_PTR MOVQ X_PTR, X SHLQ $3, INC_X LEAQ (INC_X)(INC_X*2), INC3_X // INC3_X = INC_X * 3 CMPQ incY+120(FP), $1 // Check for dense vector Y (fast-path) JNE inc MOVSD $1.0, X0 COMISD beta+88(FP), X0 JE gemv_start MOVSD $0.0, X0 COMISD beta+88(FP), X0 JE gemv_clear MOVDDUP beta+88(FP), BETA SHRQ $3, M JZ scal4 scal8: SCALE_8(Y_PTR, BETA) ADDQ $8*SIZE, Y_PTR DECQ M JNZ scal8 scal4: TESTQ $4, M_DIM JZ scal2 SCALE_4(Y_PTR, BETA) ADDQ $4*SIZE, Y_PTR scal2: TESTQ $2, M_DIM JZ scal1 SCALE_2(Y_PTR, BETA) ADDQ $2*SIZE, Y_PTR scal1: TESTQ $1, M_DIM JZ prep_end SCALE_1(Y_PTR, BETA) JMP prep_end gemv_clear: // beta == 0 is special cased to clear memory (no nan handling) XORPS X0, X0 XORPS X1, X1 XORPS X2, X2 XORPS X3, X3 SHRQ $3, M JZ clear4 clear8: MOVUPS X0, (Y_PTR) MOVUPS X1, 16(Y_PTR) MOVUPS X2, 32(Y_PTR) MOVUPS X3, 48(Y_PTR) ADDQ $8*SIZE, Y_PTR DECQ M JNZ clear8 clear4: TESTQ $4, M_DIM JZ clear2 MOVUPS X0, (Y_PTR) MOVUPS X1, 16(Y_PTR) ADDQ $4*SIZE, Y_PTR clear2: TESTQ $2, M_DIM JZ clear1 MOVUPS X0, (Y_PTR) ADDQ $2*SIZE, Y_PTR clear1: TESTQ $1, M_DIM JZ prep_end MOVSD X0, (Y_PTR) prep_end: MOVQ Y, Y_PTR MOVQ M_DIM, M gemv_start: SHRQ $2, N JZ c2 c4: // LOAD 4 INIT4 MOVQ M_DIM, M SHRQ $2, M JZ c4r2 c4r4: // 4x4 KERNEL KERNEL_LOAD4 KERNEL_4x4 STORE4 ADDQ $4*SIZE, Y_PTR DECQ M JNZ c4r4 c4r2: TESTQ $2, M_DIM JZ c4r1 // 4x2 KERNEL KERNEL_LOAD2 KERNEL_2x4 STORE2 ADDQ $2*SIZE, Y_PTR c4r1: TESTQ $1, M_DIM JZ c4end // 4x1 KERNEL KERNEL_1x4 ADDQ $SIZE, Y_PTR c4end: LEAQ (X_PTR)(INC_X*4), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ N JNZ c4 c2: TESTQ $2, N_DIM JZ c1 // LOAD 2 INIT2 MOVQ M_DIM, M SHRQ $2, M JZ c2r2 c2r4: // 2x4 KERNEL KERNEL_LOAD4 KERNEL_4x2 STORE4 ADDQ $4*SIZE, Y_PTR DECQ M JNZ c2r4 c2r2: TESTQ $2, M_DIM JZ c2r1 // 2x2 KERNEL KERNEL_LOAD2 KERNEL_2x2 STORE2 ADDQ $2*SIZE, Y_PTR c2r1: TESTQ $1, M_DIM JZ c2end // 2x1 KERNEL KERNEL_1x2 ADDQ $SIZE, Y_PTR c2end: LEAQ (X_PTR)(INC_X*2), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR c1: TESTQ $1, N_DIM JZ end // LOAD 1 INIT1 MOVQ M_DIM, M SHRQ $2, M JZ c1r2 c1r4: // 1x4 KERNEL KERNEL_LOAD4 KERNEL_4x1 STORE4 ADDQ $4*SIZE, Y_PTR DECQ M JNZ c1r4 c1r2: TESTQ $2, M_DIM JZ c1r1 // 1x2 KERNEL KERNEL_LOAD2 KERNEL_2x1 STORE2 ADDQ $2*SIZE, Y_PTR c1r1: TESTQ $1, M_DIM JZ end // 1x1 KERNEL KERNEL_1x1 end: RET inc: // Algorithm for incX != 0 ( split loads in kernel ) XORQ TMP2, TMP2 MOVQ M, TMP1 SUBQ $1, TMP1 IMULQ INC_Y, TMP1 NEGQ TMP1 CMPQ INC_Y, $0 CMOVQLT TMP1, TMP2 LEAQ (Y_PTR)(TMP2*SIZE), Y_PTR MOVQ Y_PTR, Y SHLQ $3, INC_Y LEAQ (INC_Y)(INC_Y*2), INC3_Y // INC3_Y = INC_Y * 3 MOVSD $1.0, X0 COMISD beta+88(FP), X0 JE inc_gemv_start MOVSD $0.0, X0 COMISD beta+88(FP), X0 JE inc_gemv_clear MOVDDUP beta+88(FP), BETA SHRQ $2, M JZ inc_scal2 inc_scal4: SCALEINC_4(Y_PTR, INC_Y, INC3_Y, BETA) LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ M JNZ inc_scal4 inc_scal2: TESTQ $2, M_DIM JZ inc_scal1 SCALEINC_2(Y_PTR, INC_Y, BETA) LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_scal1: TESTQ $1, M_DIM JZ inc_prep_end SCALE_1(Y_PTR, BETA) JMP inc_prep_end inc_gemv_clear: // beta == 0 is special-cased to clear memory (no nan handling) XORPS X0, X0 XORPS X1, X1 XORPS X2, X2 XORPS X3, X3 SHRQ $2, M JZ inc_clear2 inc_clear4: MOVSD X0, (Y_PTR) MOVSD X1, (Y_PTR)(INC_Y*1) MOVSD X2, (Y_PTR)(INC_Y*2) MOVSD X3, (Y_PTR)(INC3_Y*1) LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ M JNZ inc_clear4 inc_clear2: TESTQ $2, M_DIM JZ inc_clear1 MOVSD X0, (Y_PTR) MOVSD X1, (Y_PTR)(INC_Y*1) LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_clear1: TESTQ $1, M_DIM JZ inc_prep_end MOVSD X0, (Y_PTR) inc_prep_end: MOVQ Y, Y_PTR MOVQ M_DIM, M inc_gemv_start: SHRQ $2, N JZ inc_c2 inc_c4: // LOAD 4 INIT4 MOVQ M_DIM, M SHRQ $2, M JZ inc_c4r2 inc_c4r4: // 4x4 KERNEL KERNEL_LOAD4_INC KERNEL_4x4 STORE4_INC LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ M JNZ inc_c4r4 inc_c4r2: TESTQ $2, M_DIM JZ inc_c4r1 // 4x2 KERNEL KERNEL_LOAD2_INC KERNEL_2x4 STORE2_INC LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_c4r1: TESTQ $1, M_DIM JZ inc_c4end // 4x1 KERNEL KERNEL_1x4 ADDQ INC_Y, Y_PTR inc_c4end: LEAQ (X_PTR)(INC_X*4), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ N JNZ inc_c4 inc_c2: TESTQ $2, N_DIM JZ inc_c1 // LOAD 2 INIT2 MOVQ M_DIM, M SHRQ $2, M JZ inc_c2r2 inc_c2r4: // 2x4 KERNEL KERNEL_LOAD4_INC KERNEL_4x2 STORE4_INC LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ M JNZ inc_c2r4 inc_c2r2: TESTQ $2, M_DIM JZ inc_c2r1 // 2x2 KERNEL KERNEL_LOAD2_INC KERNEL_2x2 STORE2_INC LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_c2r1: TESTQ $1, M_DIM JZ inc_c2end // 2x1 KERNEL KERNEL_1x2 ADDQ INC_Y, Y_PTR inc_c2end: LEAQ (X_PTR)(INC_X*2), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR inc_c1: TESTQ $1, N_DIM JZ inc_end // LOAD 1 INIT1 MOVQ M_DIM, M SHRQ $2, M JZ inc_c1r2 inc_c1r4: // 1x4 KERNEL KERNEL_LOAD4_INC KERNEL_4x1 STORE4_INC LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ M JNZ inc_c1r4 inc_c1r2: TESTQ $2, M_DIM JZ inc_c1r1 // 1x2 KERNEL KERNEL_LOAD2_INC KERNEL_2x1 STORE2_INC LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_c1r1: TESTQ $1, M_DIM JZ inc_end // 1x1 KERNEL KERNEL_1x1 inc_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/gemv_test.go000066400000000000000000000473341450372207100231700ustar00rootroot00000000000000// 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 f64_test import ( "fmt" "testing" . "gonum.org/v1/gonum/internal/asm/f64" ) type DgemvCase struct { m int n int A []float64 x []float64 y []float64 NoTrans []DgemvSubcase Trans []DgemvSubcase } type DgemvSubcase struct { alpha float64 beta float64 want []float64 wantRevX []float64 wantRevY []float64 wantRevXY []float64 } var DgemvCases = []DgemvCase{ { // 1x1 m: 1, n: 1, A: []float64{4.1}, x: []float64{2.2}, y: []float64{6.8}, NoTrans: []DgemvSubcase{ // (1x1) {alpha: 0, beta: 0, want: []float64{0}, wantRevX: []float64{0}, wantRevY: []float64{0}, wantRevXY: []float64{0}, }, {alpha: 0, beta: 1, want: []float64{6.8}, wantRevX: []float64{6.8}, wantRevY: []float64{6.8}, wantRevXY: []float64{6.8}, }, {alpha: 1, beta: 0, want: []float64{9.02}, wantRevX: []float64{9.02}, wantRevY: []float64{9.02}, wantRevXY: []float64{9.02}, }, {alpha: 8, beta: -6, want: []float64{31.36}, wantRevX: []float64{31.36}, wantRevY: []float64{31.36}, wantRevXY: []float64{31.36}, }, }, Trans: []DgemvSubcase{ // (1x1) {alpha: 0, beta: 0, want: []float64{0}, wantRevX: []float64{0}, wantRevY: []float64{0}, wantRevXY: []float64{0}, }, {alpha: 0, beta: 1, want: []float64{2.2}, wantRevX: []float64{2.2}, wantRevY: []float64{2.2}, wantRevXY: []float64{2.2}, }, {alpha: 1, beta: 0, want: []float64{27.88}, wantRevX: []float64{27.88}, wantRevY: []float64{27.88}, wantRevXY: []float64{27.88}, }, {alpha: 8, beta: -6, want: []float64{209.84}, wantRevX: []float64{209.84}, wantRevY: []float64{209.84}, wantRevXY: []float64{209.84}, }, }, }, { // 3x2 m: 3, n: 2, A: []float64{ 4.67, 2.75, 0.48, 1.21, 2.28, 2.82, }, x: []float64{3.38, 3}, y: []float64{2.8, 1.71, 2.64}, NoTrans: []DgemvSubcase{ // (2x2, 1x2) {alpha: 0, beta: 0, want: []float64{0, 0, 0}, wantRevX: []float64{0, 0, 0}, wantRevY: []float64{0, 0, 0}, wantRevXY: []float64{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{2.8, 1.71, 2.64}, wantRevX: []float64{2.8, 1.71, 2.64}, wantRevY: []float64{2.8, 1.71, 2.64}, wantRevXY: []float64{2.8, 1.71, 2.64}, }, {alpha: 1, beta: 0, want: []float64{24.0346, 5.2524, 16.1664}, wantRevX: []float64{23.305, 5.5298, 16.3716}, wantRevY: []float64{16.1664, 5.2524, 24.0346}, wantRevXY: []float64{16.3716, 5.5298, 23.305}, }, {alpha: 8, beta: -6, want: []float64{175.4768, 31.7592, 113.4912}, wantRevX: []float64{169.64, 33.9784, 115.1328}, wantRevY: []float64{112.5312, 31.7592, 176.4368}, wantRevXY: []float64{114.1728, 33.9784, 170.6}, }, }, Trans: []DgemvSubcase{ // (2x2) {alpha: 0, beta: 0, want: []float64{0, 0}, wantRevX: []float64{0, 0}, wantRevY: []float64{0, 0}, wantRevXY: []float64{0, 0}, }, {alpha: 0, beta: 1, want: []float64{3.38, 3}, wantRevX: []float64{3.38, 3}, wantRevY: []float64{3.38, 3}, wantRevXY: []float64{3.38, 3}, }, {alpha: 1, beta: 0, want: []float64{19.916, 17.2139}, wantRevX: []float64{19.5336, 17.2251}, wantRevY: []float64{17.2139, 19.916}, wantRevXY: []float64{17.2251, 19.5336}, }, {alpha: 8, beta: -6, want: []float64{139.048, 119.7112}, wantRevX: []float64{135.9888, 119.8008}, wantRevY: []float64{117.4312, 141.328}, wantRevXY: []float64{117.5208, 138.2688}, }, }, }, { // 3x3 m: 3, n: 3, A: []float64{ 4.38, 4.4, 4.26, 4.18, 0.56, 2.57, 2.59, 2.07, 0.46, }, x: []float64{4.82, 1.82, 1.12}, y: []float64{0.24, 1.41, 3.45}, NoTrans: []DgemvSubcase{ // (2x2, 2x1, 1x2, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0}, wantRevX: []float64{0, 0, 0}, wantRevY: []float64{0, 0, 0}, wantRevXY: []float64{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{0.24, 1.41, 3.45}, wantRevX: []float64{0.24, 1.41, 3.45}, wantRevY: []float64{0.24, 1.41, 3.45}, wantRevXY: []float64{0.24, 1.41, 3.45}, }, {alpha: 1, beta: 0, want: []float64{33.8908, 24.0452, 16.7664}, wantRevX: []float64{33.4468, 18.0882, 8.8854}, wantRevY: []float64{16.7664, 24.0452, 33.8908}, wantRevXY: []float64{8.8854, 18.0882, 33.4468}, }, {alpha: 8, beta: -6, want: []float64{269.6864, 183.9016, 113.4312}, wantRevX: []float64{266.1344, 136.2456, 50.3832}, wantRevY: []float64{132.6912, 183.9016, 250.4264}, wantRevXY: []float64{69.6432, 136.2456, 246.8744}, }, }, Trans: []DgemvSubcase{ // (2x2, 1x2, 2x1, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0}, wantRevX: []float64{0, 0, 0}, wantRevY: []float64{0, 0, 0}, wantRevXY: []float64{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{4.82, 1.82, 1.12}, wantRevX: []float64{4.82, 1.82, 1.12}, wantRevY: []float64{4.82, 1.82, 1.12}, wantRevXY: []float64{4.82, 1.82, 1.12}, }, {alpha: 1, beta: 0, want: []float64{15.8805, 8.9871, 6.2331}, wantRevX: []float64{21.6264, 16.4664, 18.4311}, wantRevY: []float64{6.2331, 8.9871, 15.8805}, wantRevXY: []float64{18.4311, 16.4664, 21.6264}, }, {alpha: 8, beta: -6, want: []float64{98.124, 60.9768, 43.1448}, wantRevX: []float64{144.0912, 120.8112, 140.7288}, wantRevY: []float64{20.9448, 60.9768, 120.324}, wantRevXY: []float64{118.5288, 120.8112, 166.2912}, }, }, }, { // 5x3 m: 5, n: 3, A: []float64{ 4.1, 6.2, 8.1, 9.6, 3.5, 9.1, 10, 7, 3, 1, 1, 2, 9, 2, 5, }, x: []float64{1, 2, 3}, y: []float64{7, 8, 9, 10, 11}, NoTrans: []DgemvSubcase{ //(4x2, 4x1, 1x2, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0, 0, 0}, wantRevX: []float64{0, 0, 0, 0, 0}, wantRevY: []float64{0, 0, 0, 0, 0}, wantRevXY: []float64{0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{7, 8, 9, 10, 11}, wantRevX: []float64{7, 8, 9, 10, 11}, wantRevY: []float64{7, 8, 9, 10, 11}, wantRevXY: []float64{7, 8, 9, 10, 11}, }, {alpha: 1, beta: 0, want: []float64{40.8, 43.9, 33, 9, 28}, wantRevX: []float64{32.8, 44.9, 47, 7, 36}, wantRevY: []float64{28, 9, 33, 43.9, 40.8}, wantRevXY: []float64{36, 7, 47, 44.9, 32.8}, }, {alpha: 8, beta: -6, want: []float64{284.4, 303.2, 210, 12, 158}, wantRevX: []float64{220.4, 311.2, 322, -4, 222}, wantRevY: []float64{182, 24, 210, 291.2, 260.4}, wantRevXY: []float64{246, 8, 322, 299.2, 196.4}, }, }, Trans: []DgemvSubcase{ //( 2x4, 1x4, 2x1, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0}, wantRevX: []float64{0, 0, 0}, wantRevY: []float64{0, 0, 0}, wantRevXY: []float64{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{1, 2, 3}, wantRevX: []float64{1, 2, 3}, wantRevY: []float64{1, 2, 3}, wantRevXY: []float64{1, 2, 3}, }, {alpha: 1, beta: 0, want: []float64{304.5, 166.4, 231.5}, wantRevX: []float64{302.1, 188.2, 258.1}, wantRevY: []float64{231.5, 166.4, 304.5}, wantRevXY: []float64{258.1, 188.2, 302.1}, }, {alpha: 8, beta: -6, want: []float64{2430, 1319.2, 1834}, wantRevX: []float64{2410.8, 1493.6, 2046.8}, wantRevY: []float64{1846, 1319.2, 2418}, wantRevXY: []float64{2058.8, 1493.6, 2398.8}, }, }, }, { // 3x5 m: 3, n: 5, A: []float64{ 1.4, 2.34, 3.96, 0.96, 2.3, 3.43, 0.62, 1.09, 0.2, 3.56, 1.15, 0.58, 3.8, 1.16, 0.01, }, x: []float64{2.34, 2.82, 4.73, 0.22, 3.91}, y: []float64{2.46, 2.22, 4.75}, NoTrans: []DgemvSubcase{ // (2x4, 2x1, 1x4, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0}, wantRevX: []float64{0, 0, 0}, wantRevY: []float64{0, 0, 0}, wantRevXY: []float64{0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{2.46, 2.22, 4.75}, wantRevX: []float64{2.46, 2.22, 4.75}, wantRevY: []float64{2.46, 2.22, 4.75}, wantRevXY: []float64{2.46, 2.22, 4.75}, }, {alpha: 1, beta: 0, want: []float64{37.8098, 28.8939, 22.5949}, wantRevX: []float64{32.8088, 27.5978, 25.8927}, wantRevY: []float64{22.5949, 28.8939, 37.8098}, wantRevXY: []float64{25.8927, 27.5978, 32.8088}, }, {alpha: 8, beta: -6, want: []float64{287.7184, 217.8312, 152.2592}, wantRevX: []float64{247.7104, 207.4624, 178.6416}, wantRevY: []float64{165.9992, 217.8312, 273.9784}, wantRevXY: []float64{192.3816, 207.4624, 233.9704}, }, }, Trans: []DgemvSubcase{ // (4x2, 1x2, 4x1, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0, 0, 0}, wantRevX: []float64{0, 0, 0, 0, 0}, wantRevY: []float64{0, 0, 0, 0, 0}, wantRevXY: []float64{0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{2.34, 2.82, 4.73, 0.22, 3.91}, wantRevX: []float64{2.34, 2.82, 4.73, 0.22, 3.91}, wantRevY: []float64{2.34, 2.82, 4.73, 0.22, 3.91}, wantRevXY: []float64{2.34, 2.82, 4.73, 0.22, 3.91}, }, {alpha: 1, beta: 0, want: []float64{16.5211, 9.8878, 30.2114, 8.3156, 13.6087}, wantRevX: []float64{17.0936, 13.9182, 30.5778, 7.8576, 18.8528}, wantRevY: []float64{13.6087, 8.3156, 30.2114, 9.8878, 16.5211}, wantRevXY: []float64{18.8528, 7.8576, 30.5778, 13.9182, 17.0936}, }, {alpha: 8, beta: -6, want: []float64{118.1288, 62.1824, 213.3112, 65.2048, 85.4096}, wantRevX: []float64{122.7088, 94.4256, 216.2424, 61.5408, 127.3624}, wantRevY: []float64{94.8296, 49.6048, 213.3112, 77.7824, 108.7088}, wantRevXY: []float64{136.7824, 45.9408, 216.2424, 110.0256, 113.2888}, }, }, }, { // 7x7 & nan test m: 7, n: 7, A: []float64{ 0.9, 2.6, 0.5, 1.8, 2.3, 0.6, 0.2, 1.6, 0.6, 1.3, 2.1, 1.4, 0.4, 0.8, 2.9, 0.9, 2.3, 2.5, 1.4, 1.8, 1.6, 2.6, 2.8, 2.1, 0.3, nan, 2.2, 1.3, 0.2, 2.2, 1.8, 1.8, 2.1, 1.3, 1.4, 1.7, 1.4, 2.3, 2., 1., 0., 1.4, 2.1, 1.9, 0.8, 2.9, 1.3, 0.3, 1.3, }, x: []float64{0.4, 2.8, 3.5, 0.3, 0.6, 2.5, 3.1}, y: []float64{3.2, 4.4, 5., 4.3, 4.1, 1.4, 0.2}, NoTrans: []DgemvSubcase{ // (4x4, 4x2, 4x1, 2x4, 2x2, 2x1, 1x4, 1x2, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0, nan, 0, 0, 0}, wantRevX: []float64{0, 0, 0, nan, 0, 0, 0}, wantRevY: []float64{0, 0, 0, nan, 0, 0, 0}, wantRevXY: []float64{0, 0, 0, nan, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, wantRevX: []float64{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, wantRevY: []float64{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, wantRevXY: []float64{3.2, 4.4, 5., nan, 4.1, 1.4, 0.2}, }, {alpha: 1, beta: 0, want: []float64{13.43, 11.82, 22.78, nan, 21.93, 18.19, 15.39}, wantRevX: []float64{19.94, 14.21, 23.95, nan, 19.29, 14.81, 18.52}, wantRevY: []float64{15.39, 18.19, 21.93, nan, 22.78, 11.82, 13.43}, wantRevXY: []float64{18.52, 14.81, 19.29, nan, 23.95, 14.21, 19.94}, }, {alpha: 8, beta: -6, want: []float64{88.24, 68.16, 152.24, nan, 150.84, 137.12, 121.92}, wantRevX: []float64{140.32, 87.28, 161.6, nan, 129.72, 110.08, 146.96}, wantRevY: []float64{103.92, 119.12, 145.44, nan, 157.64, 86.16, 106.24}, wantRevXY: []float64{128.96, 92.08, 124.32, nan, 167., 105.28, 158.32}, }, }, Trans: []DgemvSubcase{ // (4x4, 2x4, 1x4, 4x2, 2x2, 1x2, 4x1, 2x1, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0, 0, nan, 0, 0}, wantRevX: []float64{0, 0, 0, 0, nan, 0, 0}, wantRevY: []float64{0, 0, nan, 0, 0, 0, 0}, wantRevXY: []float64{0, 0, nan, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{0.4, 2.8, 3.5, 0.3, nan, 2.5, 3.1}, wantRevX: []float64{0.4, 2.8, 3.5, 0.3, nan, 2.5, 3.1}, wantRevY: []float64{0.4, 2.8, nan, 0.3, 0.6, 2.5, 3.1}, wantRevXY: []float64{0.4, 2.8, nan, 0.3, 0.6, 2.5, 3.1}, }, {alpha: 1, beta: 0, want: []float64{39.22, 38.86, 38.61, 39.55, nan, 27.53, 25.71}, wantRevX: []float64{40.69, 40.33, 42.06, 41.92, nan, 24.98, 30.63}, wantRevY: []float64{25.71, 27.53, nan, 39.55, 38.61, 38.86, 39.22}, wantRevXY: []float64{30.63, 24.98, nan, 41.92, 42.06, 40.33, 40.69}, }, {alpha: 8, beta: -6, want: []float64{311.36, 294.08, 287.88, 314.6, nan, 205.24, 187.08}, wantRevX: []float64{323.12, 305.84, 315.48, 333.56, nan, 184.84, 226.44}, wantRevY: []float64{203.28, 203.44, nan, 314.6, 305.28, 295.88, 295.16}, wantRevXY: []float64{242.64, 183.04, nan, 333.56, 332.88, 307.64, 306.92}, }, }, }, { // 11x11 m: 11, n: 11, A: []float64{ 0.4, 3., 2.5, 2., 0.4, 2., 2., 1., 0.1, 0.3, 2., 1.7, 0.7, 2.6, 1.6, 0.5, 2.4, 3., 0.9, 0.1, 2.8, 1.3, 1.1, 2.2, 1.5, 0.8, 2.9, 0.4, 0.5, 1.7, 0.8, 2.6, 0.7, 2.2, 1.7, 0.8, 2.9, 0.7, 0.7, 1.7, 1.8, 1.9, 2.4, 1.9, 0.3, 0.5, 1.6, 1.5, 1.5, 2.4, 1.7, 1.2, 1.9, 2.8, 1.2, 1.4, 2.2, 1.7, 1.4, 2.7, 1.4, 0.9, 1.8, 0.5, 1.2, 1.9, 0.8, 2.3, 1.7, 1.3, 2., 2.8, 2.6, 0.4, 2.5, 1.3, 0.5, 2.4, 2.8, 1.1, 0.2, 0.4, 2.8, 0.5, 0.5, 0., 2.8, 1.9, 2.3, 1.8, 2.3, 1.7, 1.1, 0.1, 1.4, 1.2, 1.9, 0.5, 0.6, 0.6, 2.4, 1.2, 0.3, 1.4, 1.3, 2.5, 2.6, 0., 1.3, 2.6, 0.7, 1.5, 0.2, 1.4, 1.1, 1.8, 0.2, 1., 1., 0.6, 1.2, }, x: []float64{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, y: []float64{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, NoTrans: []DgemvSubcase{ // (4x4, 4x2, 4x1, 2x4, 2x2, 2x1, 1x4, 1x2, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevX: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevY: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevXY: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, wantRevX: []float64{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, wantRevY: []float64{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, wantRevXY: []float64{3.8, 3.4, 1.6, 4.8, 4.3, 0.5, 2., 2.5, 1.5, 2.8, 3.9}, }, {alpha: 1, beta: 0, want: []float64{32.71, 38.93, 33.55, 45.46, 39.24, 38.41, 46.23, 25.78, 37.33, 37.42, 24.63}, wantRevX: []float64{39.82, 43.78, 37.73, 41.19, 40.17, 44.41, 42.75, 28.14, 35.6, 41.25, 23.9}, wantRevY: []float64{24.63, 37.42, 37.33, 25.78, 46.23, 38.41, 39.24, 45.46, 33.55, 38.93, 32.71}, wantRevXY: []float64{23.9, 41.25, 35.6, 28.14, 42.75, 44.41, 40.17, 41.19, 37.73, 43.78, 39.82}, }, {alpha: 8, beta: -6, want: []float64{238.88, 291.04, 258.8, 334.88, 288.12, 304.28, 357.84, 191.24, 289.64, 282.56, 173.64}, wantRevX: []float64{295.76, 329.84, 292.24, 300.72, 295.56, 352.28, 330., 210.12, 275.8, 313.2, 167.8}, wantRevY: []float64{174.24, 278.96, 289.04, 177.44, 344.04, 304.28, 301.92, 348.68, 259.4, 294.64, 238.28}, wantRevXY: []float64{168.4, 309.6, 275.2, 196.32, 316.2, 352.28, 309.36, 314.52, 292.84, 333.44, 295.16}, }, }, Trans: []DgemvSubcase{ // (4x4, 2x4, 1x4, 4x2, 2x2, 1x2, 4x1, 2x1, 1x1) {alpha: 0, beta: 0, want: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevX: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevY: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, wantRevXY: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, {alpha: 0, beta: 1, want: []float64{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, wantRevX: []float64{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, wantRevY: []float64{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, wantRevXY: []float64{2.5, 1.2, 0.8, 2.9, 3.4, 1.8, 4.6, 3.3, 3.8, 0.9, 1.1}, }, {alpha: 1, beta: 0, want: []float64{37.07, 55.58, 46.05, 47.34, 33.88, 54.19, 50.85, 39.31, 31.29, 55.31, 46.98}, wantRevX: []float64{38.11, 63.38, 46.44, 40.04, 34.63, 59.27, 50.13, 35.45, 28.26, 51.64, 46.22}, wantRevY: []float64{46.98, 55.31, 31.29, 39.31, 50.85, 54.19, 33.88, 47.34, 46.05, 55.58, 37.07}, wantRevXY: []float64{46.22, 51.64, 28.26, 35.45, 50.13, 59.27, 34.63, 40.04, 46.44, 63.38, 38.11}, }, {alpha: 8, beta: -6, want: []float64{281.56, 437.44, 363.6, 361.32, 250.64, 422.72, 379.2, 294.68, 227.52, 437.08, 369.24}, wantRevX: []float64{289.88, 499.84, 366.72, 302.92, 256.64, 463.36, 373.44, 263.8, 203.28, 407.72, 363.16}, wantRevY: []float64{360.84, 435.28, 245.52, 297.08, 386.4, 422.72, 243.44, 358.92, 345.6, 439.24, 289.96}, wantRevXY: []float64{354.76, 405.92, 221.28, 266.2, 380.64, 463.36, 249.44, 300.52, 348.72, 501.64, 298.28}, }, }, }, } func TestGemv(t *testing.T) { for _, test := range DgemvCases { t.Run(fmt.Sprintf("(%vx%v)", test.m, test.n), func(tt *testing.T) { for i, cas := range test.NoTrans { tt.Run(fmt.Sprintf("NoTrans case %v", i), func(st *testing.T) { dgemvcomp(st, test, false, cas, i) }) } for i, cas := range test.Trans { tt.Run(fmt.Sprintf("Trans case %v", i), func(st *testing.T) { dgemvcomp(st, test, true, cas, i) }) } }) } } func dgemvcomp(t *testing.T, test DgemvCase, trans bool, cas DgemvSubcase, i int) { const ( tol = 1e-15 xGdVal, yGdVal, aGdVal = 0.5, 1.5, 10 gdLn = 4 ) if trans { test.x, test.y = test.y, test.x } prefix := fmt.Sprintf("Test (%vx%v) t:%v (a:%v,b:%v)", test.m, test.n, trans, cas.alpha, cas.beta) xg, yg := guardVector(test.x, xGdVal, gdLn), guardVector(test.y, yGdVal, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] ag := guardVector(test.A, aGdVal, gdLn) a := ag[gdLn : len(ag)-gdLn] lda := uintptr(test.n) if trans { GemvT(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, 1, cas.beta, y, 1) } else { GemvN(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, 1, cas.beta, y, 1) } for i := range cas.want { if !sameApprox(y[i], cas.want[i], tol) { t.Errorf(msgVal, prefix, i, y[i], cas.want[i]) } } if !isValidGuard(xg, xGdVal, gdLn) { t.Errorf(msgGuard, prefix, "x", xg[:gdLn], xg[len(xg)-gdLn:]) } if !isValidGuard(yg, yGdVal, gdLn) { t.Errorf(msgGuard, prefix, "y", yg[:gdLn], yg[len(yg)-gdLn:]) } if !isValidGuard(ag, aGdVal, gdLn) { t.Errorf(msgGuard, prefix, "a", ag[:gdLn], ag[len(ag)-gdLn:]) } if !equalStrided(test.x, x, 1) { t.Errorf(msgReadOnly, prefix, "x") } if !equalStrided(test.A, a, 1) { t.Errorf(msgReadOnly, prefix, "a") } for _, inc := range newIncSet(-1, 1, 2, 3, 90) { incPrefix := fmt.Sprintf("%s inc(x:%v, y:%v)", prefix, inc.x, inc.y) want, incY := cas.want, inc.y switch { case inc.x < 0 && inc.y < 0: want = cas.wantRevXY incY = -inc.y case inc.x < 0: want = cas.wantRevX case inc.y < 0: want = cas.wantRevY incY = -inc.y } xg, yg := guardIncVector(test.x, xGdVal, inc.x, gdLn), guardIncVector(test.y, yGdVal, inc.y, gdLn) x, y := xg[gdLn:len(xg)-gdLn], yg[gdLn:len(yg)-gdLn] ag := guardVector(test.A, aGdVal, gdLn) a := ag[gdLn : len(ag)-gdLn] if trans { GemvT(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, uintptr(inc.x), cas.beta, y, uintptr(inc.y)) } else { GemvN(uintptr(test.m), uintptr(test.n), cas.alpha, a, lda, x, uintptr(inc.x), cas.beta, y, uintptr(inc.y)) } for i := range want { if !sameApprox(y[i*incY], want[i], tol) { t.Errorf(msgVal, incPrefix, i, y[i*incY], want[i]) t.Error(y[i*incY] - want[i]) } } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, yg, yGdVal, inc.y, gdLn) if !isValidGuard(ag, aGdVal, gdLn) { t.Errorf(msgGuard, incPrefix, "a", ag[:gdLn], ag[len(ag)-gdLn:]) } if !equalStrided(test.x, x, inc.x) { t.Errorf(msgReadOnly, incPrefix, "x") } if !equalStrided(test.A, a, 1) { t.Errorf(msgReadOnly, incPrefix, "a") } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/ger_amd64.s000066400000000000000000000230651450372207100225730ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SIZE 8 #define M_DIM m+0(FP) #define M CX #define N_DIM n+8(FP) #define N BX #define TMP1 R14 #define TMP2 R15 #define X_PTR SI #define Y y_base+56(FP) #define Y_PTR DX #define A_ROW AX #define A_PTR DI #define INC_X R8 #define INC3_X R9 #define INC_Y R10 #define INC3_Y R11 #define LDA R12 #define LDA3 R13 #define ALPHA X0 #define LOAD4 \ PREFETCHNTA (X_PTR )(INC_X*8) \ MOVDDUP (X_PTR), X1 \ MOVDDUP (X_PTR)(INC_X*1), X2 \ MOVDDUP (X_PTR)(INC_X*2), X3 \ MOVDDUP (X_PTR)(INC3_X*1), X4 \ MULPD ALPHA, X1 \ MULPD ALPHA, X2 \ MULPD ALPHA, X3 \ MULPD ALPHA, X4 #define LOAD2 \ MOVDDUP (X_PTR), X1 \ MOVDDUP (X_PTR)(INC_X*1), X2 \ MULPD ALPHA, X1 \ MULPD ALPHA, X2 #define LOAD1 \ MOVDDUP (X_PTR), X1 \ MULPD ALPHA, X1 #define KERNEL_LOAD4 \ MOVUPS (Y_PTR), X5 \ MOVUPS 2*SIZE(Y_PTR), X6 #define KERNEL_LOAD4_INC \ MOVLPD (Y_PTR), X5 \ MOVHPD (Y_PTR)(INC_Y*1), X5 \ MOVLPD (Y_PTR)(INC_Y*2), X6 \ MOVHPD (Y_PTR)(INC3_Y*1), X6 #define KERNEL_LOAD2 \ MOVUPS (Y_PTR), X5 #define KERNEL_LOAD2_INC \ MOVLPD (Y_PTR), X5 \ MOVHPD (Y_PTR)(INC_Y*1), X5 #define KERNEL_4x4 \ MOVUPS X5, X7 \ MOVUPS X6, X8 \ MOVUPS X5, X9 \ MOVUPS X6, X10 \ MOVUPS X5, X11 \ MOVUPS X6, X12 \ MULPD X1, X5 \ MULPD X1, X6 \ MULPD X2, X7 \ MULPD X2, X8 \ MULPD X3, X9 \ MULPD X3, X10 \ MULPD X4, X11 \ MULPD X4, X12 #define STORE_4x4 \ MOVUPS (A_PTR), X13 \ ADDPD X13, X5 \ MOVUPS 2*SIZE(A_PTR), X14 \ ADDPD X14, X6 \ MOVUPS (A_PTR)(LDA*1), X15 \ ADDPD X15, X7 \ MOVUPS 2*SIZE(A_PTR)(LDA*1), X0 \ ADDPD X0, X8 \ MOVUPS (A_PTR)(LDA*2), X13 \ ADDPD X13, X9 \ MOVUPS 2*SIZE(A_PTR)(LDA*2), X14 \ ADDPD X14, X10 \ MOVUPS (A_PTR)(LDA3*1), X15 \ ADDPD X15, X11 \ MOVUPS 2*SIZE(A_PTR)(LDA3*1), X0 \ ADDPD X0, X12 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, 2*SIZE(A_PTR) \ MOVUPS X7, (A_PTR)(LDA*1) \ MOVUPS X8, 2*SIZE(A_PTR)(LDA*1) \ MOVUPS X9, (A_PTR)(LDA*2) \ MOVUPS X10, 2*SIZE(A_PTR)(LDA*2) \ MOVUPS X11, (A_PTR)(LDA3*1) \ MOVUPS X12, 2*SIZE(A_PTR)(LDA3*1) \ ADDQ $4*SIZE, A_PTR #define KERNEL_4x2 \ MOVUPS X5, X6 \ MOVUPS X5, X7 \ MOVUPS X5, X8 \ MULPD X1, X5 \ MULPD X2, X6 \ MULPD X3, X7 \ MULPD X4, X8 #define STORE_4x2 \ MOVUPS (A_PTR), X9 \ ADDPD X9, X5 \ MOVUPS (A_PTR)(LDA*1), X10 \ ADDPD X10, X6 \ MOVUPS (A_PTR)(LDA*2), X11 \ ADDPD X11, X7 \ MOVUPS (A_PTR)(LDA3*1), X12 \ ADDPD X12, X8 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, (A_PTR)(LDA*1) \ MOVUPS X7, (A_PTR)(LDA*2) \ MOVUPS X8, (A_PTR)(LDA3*1) \ ADDQ $2*SIZE, A_PTR #define KERNEL_4x1 \ MOVSD (Y_PTR), X5 \ MOVSD X5, X6 \ MOVSD X5, X7 \ MOVSD X5, X8 \ MULSD X1, X5 \ MULSD X2, X6 \ MULSD X3, X7 \ MULSD X4, X8 #define STORE_4x1 \ ADDSD (A_PTR), X5 \ ADDSD (A_PTR)(LDA*1), X6 \ ADDSD (A_PTR)(LDA*2), X7 \ ADDSD (A_PTR)(LDA3*1), X8 \ MOVSD X5, (A_PTR) \ MOVSD X6, (A_PTR)(LDA*1) \ MOVSD X7, (A_PTR)(LDA*2) \ MOVSD X8, (A_PTR)(LDA3*1) \ ADDQ $SIZE, A_PTR #define KERNEL_2x4 \ MOVUPS X5, X7 \ MOVUPS X6, X8 \ MULPD X1, X5 \ MULPD X1, X6 \ MULPD X2, X7 \ MULPD X2, X8 #define STORE_2x4 \ MOVUPS (A_PTR), X9 \ ADDPD X9, X5 \ MOVUPS 2*SIZE(A_PTR), X10 \ ADDPD X10, X6 \ MOVUPS (A_PTR)(LDA*1), X11 \ ADDPD X11, X7 \ MOVUPS 2*SIZE(A_PTR)(LDA*1), X12 \ ADDPD X12, X8 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, 2*SIZE(A_PTR) \ MOVUPS X7, (A_PTR)(LDA*1) \ MOVUPS X8, 2*SIZE(A_PTR)(LDA*1) \ ADDQ $4*SIZE, A_PTR #define KERNEL_2x2 \ MOVUPS X5, X6 \ MULPD X1, X5 \ MULPD X2, X6 #define STORE_2x2 \ MOVUPS (A_PTR), X7 \ ADDPD X7, X5 \ MOVUPS (A_PTR)(LDA*1), X8 \ ADDPD X8, X6 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, (A_PTR)(LDA*1) \ ADDQ $2*SIZE, A_PTR #define KERNEL_2x1 \ MOVSD (Y_PTR), X5 \ MOVSD X5, X6 \ MULSD X1, X5 \ MULSD X2, X6 #define STORE_2x1 \ ADDSD (A_PTR), X5 \ ADDSD (A_PTR)(LDA*1), X6 \ MOVSD X5, (A_PTR) \ MOVSD X6, (A_PTR)(LDA*1) \ ADDQ $SIZE, A_PTR #define KERNEL_1x4 \ MULPD X1, X5 \ MULPD X1, X6 #define STORE_1x4 \ MOVUPS (A_PTR), X7 \ ADDPD X7, X5 \ MOVUPS 2*SIZE(A_PTR), X8 \ ADDPD X8, X6 \ MOVUPS X5, (A_PTR) \ MOVUPS X6, 2*SIZE(A_PTR) \ ADDQ $4*SIZE, A_PTR #define KERNEL_1x2 \ MULPD X1, X5 #define STORE_1x2 \ MOVUPS (A_PTR), X6 \ ADDPD X6, X5 \ MOVUPS X5, (A_PTR) \ ADDQ $2*SIZE, A_PTR #define KERNEL_1x1 \ MOVSD (Y_PTR), X5 \ MULSD X1, X5 #define STORE_1x1 \ ADDSD (A_PTR), X5 \ MOVSD X5, (A_PTR) \ ADDQ $SIZE, A_PTR // func Ger(m, n uintptr, alpha float64, // x []float64, incX uintptr, // y []float64, incY uintptr, // a []float64, lda uintptr) TEXT ·Ger(SB), NOSPLIT, $0 MOVQ M_DIM, M MOVQ N_DIM, N CMPQ M, $0 JE end CMPQ N, $0 JE end MOVDDUP alpha+16(FP), ALPHA MOVQ x_base+24(FP), X_PTR MOVQ y_base+56(FP), Y_PTR MOVQ a_base+88(FP), A_ROW MOVQ incX+48(FP), INC_X // INC_X = incX * sizeof(float64) SHLQ $3, INC_X MOVQ lda+112(FP), LDA // LDA = LDA * sizeof(float64) SHLQ $3, LDA LEAQ (LDA)(LDA*2), LDA3 // LDA3 = LDA * 3 LEAQ (INC_X)(INC_X*2), INC3_X // INC3_X = INC_X * 3 MOVQ A_ROW, A_PTR XORQ TMP2, TMP2 MOVQ M, TMP1 SUBQ $1, TMP1 IMULQ INC_X, TMP1 NEGQ TMP1 CMPQ INC_X, $0 CMOVQLT TMP1, TMP2 LEAQ (X_PTR)(TMP2*SIZE), X_PTR CMPQ incY+80(FP), $1 // Check for dense vector Y (fast-path) JG inc JL end SHRQ $2, M JZ r2 r4: // LOAD 4 LOAD4 MOVQ N_DIM, N SHRQ $2, N JZ r4c2 r4c4: // 4x4 KERNEL KERNEL_LOAD4 KERNEL_4x4 STORE_4x4 ADDQ $4*SIZE, Y_PTR DECQ N JNZ r4c4 // Reload ALPHA after it's clobbered by STORE_4x4 MOVDDUP alpha+16(FP), ALPHA r4c2: TESTQ $2, N_DIM JZ r4c1 // 4x2 KERNEL KERNEL_LOAD2 KERNEL_4x2 STORE_4x2 ADDQ $2*SIZE, Y_PTR r4c1: TESTQ $1, N_DIM JZ r4end // 4x1 KERNEL KERNEL_4x1 STORE_4x1 ADDQ $SIZE, Y_PTR r4end: LEAQ (X_PTR)(INC_X*4), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ M JNZ r4 r2: TESTQ $2, M_DIM JZ r1 // LOAD 2 LOAD2 MOVQ N_DIM, N SHRQ $2, N JZ r2c2 r2c4: // 2x4 KERNEL KERNEL_LOAD4 KERNEL_2x4 STORE_2x4 ADDQ $4*SIZE, Y_PTR DECQ N JNZ r2c4 r2c2: TESTQ $2, N_DIM JZ r2c1 // 2x2 KERNEL KERNEL_LOAD2 KERNEL_2x2 STORE_2x2 ADDQ $2*SIZE, Y_PTR r2c1: TESTQ $1, N_DIM JZ r2end // 2x1 KERNEL KERNEL_2x1 STORE_2x1 ADDQ $SIZE, Y_PTR r2end: LEAQ (X_PTR)(INC_X*2), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR r1: TESTQ $1, M_DIM JZ end // LOAD 1 LOAD1 MOVQ N_DIM, N SHRQ $2, N JZ r1c2 r1c4: // 1x4 KERNEL KERNEL_LOAD4 KERNEL_1x4 STORE_1x4 ADDQ $4*SIZE, Y_PTR DECQ N JNZ r1c4 r1c2: TESTQ $2, N_DIM JZ r1c1 // 1x2 KERNEL KERNEL_LOAD2 KERNEL_1x2 STORE_1x2 ADDQ $2*SIZE, Y_PTR r1c1: TESTQ $1, N_DIM JZ end // 1x1 KERNEL KERNEL_1x1 STORE_1x1 ADDQ $SIZE, Y_PTR end: RET inc: // Algorithm for incY != 1 ( split loads in kernel ) MOVQ incY+80(FP), INC_Y // INC_Y = incY * sizeof(float64) SHLQ $3, INC_Y LEAQ (INC_Y)(INC_Y*2), INC3_Y // INC3_Y = INC_Y * 3 XORQ TMP2, TMP2 MOVQ N, TMP1 SUBQ $1, TMP1 IMULQ INC_Y, TMP1 NEGQ TMP1 CMPQ INC_Y, $0 CMOVQLT TMP1, TMP2 LEAQ (Y_PTR)(TMP2*SIZE), Y_PTR SHRQ $2, M JZ inc_r2 inc_r4: // LOAD 4 LOAD4 MOVQ N_DIM, N SHRQ $2, N JZ inc_r4c2 inc_r4c4: // 4x4 KERNEL KERNEL_LOAD4_INC KERNEL_4x4 STORE_4x4 LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ N JNZ inc_r4c4 // Reload ALPHA after it's clobbered by STORE_4x4 MOVDDUP alpha+16(FP), ALPHA inc_r4c2: TESTQ $2, N_DIM JZ inc_r4c1 // 4x2 KERNEL KERNEL_LOAD2_INC KERNEL_4x2 STORE_4x2 LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_r4c1: TESTQ $1, N_DIM JZ inc_r4end // 4x1 KERNEL KERNEL_4x1 STORE_4x1 ADDQ INC_Y, Y_PTR inc_r4end: LEAQ (X_PTR)(INC_X*4), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*4), A_ROW MOVQ A_ROW, A_PTR DECQ M JNZ inc_r4 inc_r2: TESTQ $2, M_DIM JZ inc_r1 // LOAD 2 LOAD2 MOVQ N_DIM, N SHRQ $2, N JZ inc_r2c2 inc_r2c4: // 2x4 KERNEL KERNEL_LOAD4_INC KERNEL_2x4 STORE_2x4 LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ N JNZ inc_r2c4 inc_r2c2: TESTQ $2, N_DIM JZ inc_r2c1 // 2x2 KERNEL KERNEL_LOAD2_INC KERNEL_2x2 STORE_2x2 LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_r2c1: TESTQ $1, N_DIM JZ inc_r2end // 2x1 KERNEL KERNEL_2x1 STORE_2x1 ADDQ INC_Y, Y_PTR inc_r2end: LEAQ (X_PTR)(INC_X*2), X_PTR MOVQ Y, Y_PTR LEAQ (A_ROW)(LDA*2), A_ROW MOVQ A_ROW, A_PTR inc_r1: TESTQ $1, M_DIM JZ end // LOAD 1 LOAD1 MOVQ N_DIM, N SHRQ $2, N JZ inc_r1c2 inc_r1c4: // 1x4 KERNEL KERNEL_LOAD4_INC KERNEL_1x4 STORE_1x4 LEAQ (Y_PTR)(INC_Y*4), Y_PTR DECQ N JNZ inc_r1c4 inc_r1c2: TESTQ $2, N_DIM JZ inc_r1c1 // 1x2 KERNEL KERNEL_LOAD2_INC KERNEL_1x2 STORE_1x2 LEAQ (Y_PTR)(INC_Y*2), Y_PTR inc_r1c1: TESTQ $1, N_DIM JZ end // 1x1 KERNEL KERNEL_1x1 STORE_1x1 ADDQ INC_Y, Y_PTR inc_end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/l1norm_amd64.s000066400000000000000000000032151450372207100232210ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func L1Dist(s, t []float64) float64 TEXT ·L1Dist(SB), NOSPLIT, $0 MOVQ s_base+0(FP), DI // DI = &s MOVQ t_base+24(FP), SI // SI = &t MOVQ s_len+8(FP), CX // CX = len(s) CMPQ t_len+32(FP), CX // CX = max( CX, len(t) ) CMOVQLE t_len+32(FP), CX PXOR X3, X3 // norm = 0 CMPQ CX, $0 // if CX == 0 { return 0 } JE l1_end XORQ AX, AX // i = 0 MOVQ CX, BX ANDQ $1, BX // BX = CX % 2 SHRQ $1, CX // CX = floor( CX / 2 ) JZ l1_tail_start // if CX == 0 { return 0 } l1_loop: // Loop unrolled 2x do { MOVUPS (SI)(AX*8), X0 // X0 = t[i:i+1] MOVUPS (DI)(AX*8), X1 // X1 = s[i:i+1] MOVAPS X0, X2 SUBPD X1, X0 SUBPD X2, X1 MAXPD X1, X0 // X0 = max( X0 - X1, X1 - X0 ) ADDPD X0, X3 // norm += X0 ADDQ $2, AX // i += 2 LOOP l1_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE l1_end l1_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX PXOR X0, X0 // reset X0, X1 to break dependencies PXOR X1, X1 l1_tail: MOVSD (SI)(AX*8), X0 // X0 = t[i] MOVSD (DI)(AX*8), X1 // x1 = s[i] MOVAPD X0, X2 SUBSD X1, X0 SUBSD X2, X1 MAXSD X1, X0 // X0 = max( X0 - X1, X1 - X0 ) ADDSD X0, X3 // norm += X0 l1_end: MOVAPS X3, X2 SHUFPD $1, X2, X2 ADDSD X3, X2 // X2 = X3[1] + X3[0] MOVSD X2, ret+48(FP) // return X2 RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/l2norm_amd64.s000066400000000000000000000057721450372207100232340ustar00rootroot00000000000000// Copyright ©2019 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SUMSQ X0 #define ABSX X1 #define SCALE X2 #define ZERO X3 #define TMP X4 #define ABSMASK X5 #define INF X7 #define INFMASK X11 #define NANMASK X12 #define IDX AX #define LEN SI #define X_ DI #define ABSMASK_DATA l2nrodata<>+0(SB) #define INF_DATA l2nrodata<>+8(SB) #define NAN_DATA l2nrodata<>+16(SB) // AbsMask DATA l2nrodata<>+0(SB)/8, $0x7FFFFFFFFFFFFFFF // Inf DATA l2nrodata<>+8(SB)/8, $0x7FF0000000000000 // NaN DATA l2nrodata<>+16(SB)/8, $0xFFF8000000000000 GLOBL l2nrodata<>+0(SB), RODATA, $24 // L2NormUnitary returns the L2-norm of x. // func L2NormUnitary(x []float64) (norm float64) TEXT ·L2NormUnitary(SB), NOSPLIT, $0 MOVQ x_len+8(FP), LEN // LEN = len(x) MOVQ x_base+0(FP), X_ PXOR ZERO, ZERO CMPQ LEN, $0 // if LEN == 0 { return 0 } JZ retZero PXOR INFMASK, INFMASK PXOR NANMASK, NANMASK MOVSD $1.0, SUMSQ // ssq = 1 XORPS SCALE, SCALE MOVSD ABSMASK_DATA, ABSMASK MOVSD INF_DATA, INF XORQ IDX, IDX // idx == 0 initZero: // for ;x[i]==0; i++ {} // Skip all leading zeros, to avoid divide by zero NaN MOVSD (X_)(IDX*8), ABSX // absxi = x[i] UCOMISD ABSX, ZERO JP retNaN // if isNaN(x[i]) { return NaN } JNE loop // if x[i] != 0 { goto loop } INCQ IDX // i++ CMPQ IDX, LEN JE retZero // if i == LEN { return 0 } JMP initZero loop: MOVSD (X_)(IDX*8), ABSX // absxi = x[i] MOVUPS ABSX, TMP CMPSD ABSX, TMP, $3 ORPD TMP, NANMASK // NANMASK = NANMASK | IsNaN(absxi) MOVSD INF, TMP ANDPD ABSMASK, ABSX // absxi == Abs(absxi) CMPSD ABSX, TMP, $0 ORPD TMP, INFMASK // INFMASK = INFMASK | IsInf(absxi) UCOMISD SCALE, ABSX JA adjScale // IF SCALE > ABSXI { goto adjScale } DIVSD SCALE, ABSX // absxi = scale / absxi MULSD ABSX, ABSX // absxi *= absxi ADDSD ABSX, SUMSQ // sumsq += absxi INCQ IDX // i++ CMPQ IDX, LEN JNE loop // if i < LEN { continue } JMP retSum // if i == LEN { goto retSum } adjScale: // Scale > Absxi DIVSD ABSX, SCALE // tmp = absxi / scale MULSD SCALE, SUMSQ // sumsq *= tmp MULSD SCALE, SUMSQ // sumsq *= tmp ADDSD $1.0, SUMSQ // sumsq += 1 MOVUPS ABSX, SCALE // scale = absxi INCQ IDX // i++ CMPQ IDX, LEN JNE loop // if i < LEN { continue } retSum: // Calculate return value SQRTSD SUMSQ, SUMSQ // sumsq = sqrt(sumsq) MULSD SCALE, SUMSQ // sumsq += scale MOVQ SUMSQ, R10 // tmp = sumsq UCOMISD ZERO, INFMASK CMOVQPS INF_DATA, R10 // if INFMASK { tmp = INF } UCOMISD ZERO, NANMASK CMOVQPS NAN_DATA, R10 // if NANMASK { tmp = NaN } MOVQ R10, norm+24(FP) // return tmp RET retZero: MOVSD ZERO, norm+24(FP) // return 0 RET retNaN: MOVSD NAN_DATA, TMP // return NaN MOVSD TMP, norm+24(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/l2norm_noasm.go000066400000000000000000000035141450372207100235710ustar00rootroot00000000000000// Copyright ©2019 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f64 import "math" // L2NormUnitary returns the L2-norm of x. func L2NormUnitary(x []float64) (norm float64) { var scale float64 sumSquares := 1.0 for _, v := range x { if v == 0 { continue } absxi := math.Abs(v) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } // L2NormInc returns the L2-norm of x. func L2NormInc(x []float64, n, incX uintptr) (norm float64) { var scale float64 sumSquares := 1.0 for ix := uintptr(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 { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } // L2DistanceUnitary returns the L2-norm of x-y. func L2DistanceUnitary(x, y []float64) (norm float64) { var scale float64 sumSquares := 1.0 for i, v := range x { v -= y[i] if v == 0 { continue } absxi := math.Abs(v) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/l2norm_test.go000066400000000000000000000106031450372207100234300ustar00rootroot00000000000000// Copyright ©2019 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 f64_test import ( "fmt" "math" "testing" . "gonum.org/v1/gonum/internal/asm/f64" ) // nanwith copied from floats package func nanwith(payload uint64) float64 { const ( nanBits = 0x7ff8000000000000 nanMask = 0xfff8000000000000 ) return math.Float64frombits(nanBits | (payload &^ nanMask)) } func TestL2NormUnitary(t *testing.T) { const tol = 1e-15 var src_gd float64 = 1 for j, v := range []struct { want float64 x []float64 }{ {want: 0, x: []float64{}}, {want: 2, x: []float64{2}}, {want: 3.7416573867739413, x: []float64{1, 2, 3}}, {want: 3.7416573867739413, x: []float64{-1, -2, -3}}, {want: nan, x: []float64{nan}}, {want: nan, x: []float64{1, inf, 3, nanwith(25), 5}}, {want: 17.88854381999832, x: []float64{8, -8, 8, -8, 8}}, {want: 2.23606797749979, x: []float64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L2NormUnitary(src) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Norm error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func TestL2NormInc(t *testing.T) { const tol = 1e-15 var src_gd float64 = 1 for j, v := range []struct { inc int want float64 x []float64 }{ {inc: 2, want: 0, x: []float64{}}, {inc: 3, want: 2, x: []float64{2}}, {inc: 10, want: 3.7416573867739413, x: []float64{1, 2, 3}}, {inc: 5, want: 3.7416573867739413, x: []float64{-1, -2, -3}}, {inc: 3, want: nan, x: []float64{nan}}, {inc: 15, want: 17.88854381999832, x: []float64{8, -8, 8, -8, 8}}, {inc: 1, want: 2.23606797749979, x: []float64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, } { g_ln, ln := 4+j%2, len(v.x) v.x = guardIncVector(v.x, src_gd, v.inc, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L2NormInc(src, uintptr(ln), uintptr(v.inc)) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2NormInc error Got: %f Expected: %f", j, ret, v.want) } checkValidIncGuard(t, v.x, src_gd, v.inc, g_ln) } } func TestL2DistanceUnitary(t *testing.T) { const tol = 1e-15 var src_gd float64 = 1 for j, v := range []struct { want float64 x, y []float64 }{ {want: 0, x: []float64{}, y: []float64{}}, {want: 2, x: []float64{3}, y: []float64{1}}, {want: 3.7416573867739413, x: []float64{2, 4, 6}, y: []float64{1, 2, 3}}, {want: 3.7416573867739413, x: []float64{1, 2, 3}, y: []float64{2, 4, 6}}, {want: nan, x: []float64{nan}, y: []float64{0}}, {want: 17.88854381999832, x: []float64{9, -9, 9, -9, 9}, y: []float64{1, -1, 1, -1, 1}}, {want: 2.23606797749979, x: []float64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}, y: []float64{0, 2, 0, -2, 0, 2, 0, -2, 0, 2}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) v.y = guardVector(v.y, src_gd, g_ln) srcX := v.x[g_ln : len(v.x)-g_ln] srcY := v.y[g_ln : len(v.y)-g_ln] ret := L2DistanceUnitary(srcX, srcY) if !sameApprox(ret, v.want, tol) { t.Errorf("Test %d L2Distance error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func BenchmarkL2NormNetlib(b *testing.B) { netlib := func(x []float64) (sum float64) { var scale float64 sumSquares := 1.0 for _, v := range x { if v == 0 { continue } absxi := math.Abs(v) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { s := scale / absxi sumSquares = 1 + sumSquares*s*s scale = absxi } else { s := absxi / scale sumSquares += s * s } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } tests := []struct { name string f func(x []float64) float64 }{ {"L2NormUnitaryNetlib", netlib}, {"L2NormUnitary", L2NormUnitary}, } x[0] = randomSlice(1, 1)[0] // replace the leading zero (edge case) for _, test := range tests { for _, ln := range []uintptr{1, 3, 10, 30, 1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5} { b.Run(fmt.Sprintf("%s-%d", test.name, ln), func(b *testing.B) { b.SetBytes(int64(64 * ln)) x := x[:ln] b.ResetTimer() for i := 0; i < b.N; i++ { test.f(x) } }) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/l2normdist_amd64.s000066400000000000000000000063531450372207100241140ustar00rootroot00000000000000// Copyright ©2019 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SUMSQ X0 #define ABSX X1 #define SCALE X2 #define ZERO X3 #define TMP X4 #define ABSMASK X5 #define INF X7 #define INFMASK X11 #define NANMASK X12 #define IDX AX #define X_ DI #define Y_ BX #define LEN SI #define ABSMASK_DATA l2nrodata<>+0(SB) #define INF_DATA l2nrodata<>+8(SB) #define NAN_DATA l2nrodata<>+16(SB) // AbsMask DATA l2nrodata<>+0(SB)/8, $0x7FFFFFFFFFFFFFFF // Inf DATA l2nrodata<>+8(SB)/8, $0x7FF0000000000000 // NaN DATA l2nrodata<>+16(SB)/8, $0xFFF8000000000000 GLOBL l2nrodata<>+0(SB), RODATA, $24 // L2DistanceUnitary returns the L2-norm of x-y. // func L2DistanceUnitary(x,y []float64) (norm float64) TEXT ·L2DistanceUnitary(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_ MOVQ y_base+24(FP), Y_ PXOR ZERO, ZERO MOVQ x_len+8(FP), LEN // LEN = min( len(x), len(y) ) CMPQ y_len+32(FP), LEN CMOVQLE y_len+32(FP), LEN CMPQ LEN, $0 // if LEN == 0 { return 0 } JZ retZero PXOR INFMASK, INFMASK PXOR NANMASK, NANMASK MOVSD $1.0, SUMSQ // ssq = 1 XORPS SCALE, SCALE MOVSD ABSMASK_DATA, ABSMASK MOVSD INF_DATA, INF XORQ IDX, IDX // idx == 0 initZero: // for ;x[i]==0; i++ {} // Skip all leading zeros, to avoid divide by zero NaN MOVSD (X_)(IDX*8), ABSX // absxi = x[i] SUBSD (Y_)(IDX*8), ABSX // absxi = x[i]-y[i] UCOMISD ABSX, ZERO JP retNaN // if isNaN(absxi) { return NaN } JNE loop // if absxi != 0 { goto loop } INCQ IDX // i++ CMPQ IDX, LEN JE retZero // if i == LEN { return 0 } JMP initZero loop: MOVSD (X_)(IDX*8), ABSX // absxi = x[i] SUBSD (Y_)(IDX*8), ABSX // absxi = x[i]-y[i] MOVUPS ABSX, TMP CMPSD ABSX, TMP, $3 ORPD TMP, NANMASK // NANMASK = NANMASK | IsNaN(absxi) MOVSD INF, TMP ANDPD ABSMASK, ABSX // absxi == Abs(absxi) CMPSD ABSX, TMP, $0 ORPD TMP, INFMASK // INFMASK = INFMASK | IsInf(absxi) UCOMISD SCALE, ABSX JA adjScale // IF SCALE > ABSXI { goto adjScale } DIVSD SCALE, ABSX // absxi = scale / absxi MULSD ABSX, ABSX // absxi *= absxi ADDSD ABSX, SUMSQ // sumsq += absxi INCQ IDX // i++ CMPQ IDX, LEN JNE loop // if i < LEN { continue } JMP retSum // if i == LEN { goto retSum } adjScale: // Scale > Absxi DIVSD ABSX, SCALE // tmp = absxi / scale MULSD SCALE, SUMSQ // sumsq *= tmp MULSD SCALE, SUMSQ // sumsq *= tmp ADDSD $1.0, SUMSQ // sumsq += 1 MOVUPS ABSX, SCALE // scale = absxi INCQ IDX // i++ CMPQ IDX, LEN JNE loop // if i < LEN { continue } retSum: // Calculate return value SQRTSD SUMSQ, SUMSQ // sumsq = sqrt(sumsq) MULSD SCALE, SUMSQ // sumsq += scale MOVQ SUMSQ, R10 // tmp = sumsq UCOMISD ZERO, INFMASK CMOVQPS INF_DATA, R10 // if INFMASK { tmp = INF } UCOMISD ZERO, NANMASK CMOVQPS NAN_DATA, R10 // if NANMASK { tmp = NaN } MOVQ R10, norm+48(FP) // return tmp RET retZero: MOVSD ZERO, norm+48(FP) // return 0 RET retNaN: MOVSD NAN_DATA, TMP // return NaN MOVSD TMP, norm+48(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/l2norminc_amd64.s000066400000000000000000000060111450372207100237110ustar00rootroot00000000000000// Copyright ©2019 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" #define SUMSQ X0 #define ABSX X1 #define SCALE X2 #define ZERO X3 #define TMP X4 #define ABSMASK X5 #define INF X7 #define INFMASK X11 #define NANMASK X12 #define IDX AX #define LEN SI #define INC BX #define X_ DI #define ABSMASK_DATA l2nrodata<>+0(SB) #define INF_DATA l2nrodata<>+8(SB) #define NAN_DATA l2nrodata<>+16(SB) // AbsMask DATA l2nrodata<>+0(SB)/8, $0x7FFFFFFFFFFFFFFF // Inf DATA l2nrodata<>+8(SB)/8, $0x7FF0000000000000 // NaN DATA l2nrodata<>+16(SB)/8, $0xFFF8000000000000 GLOBL l2nrodata<>+0(SB), RODATA, $24 // func L2NormInc(x []float64, n, incX uintptr) (norm float64) TEXT ·L2NormInc(SB), NOSPLIT, $0 MOVQ n+24(FP), LEN // LEN = len(x) MOVQ incX+32(FP), INC MOVQ x_base+0(FP), X_ XORPS ZERO, ZERO CMPQ LEN, $0 // if LEN == 0 { return 0 } JZ retZero XORPS INFMASK, INFMASK XORPS NANMASK, NANMASK MOVSD $1.0, SUMSQ // ssq = 1 XORPS SCALE, SCALE MOVSD ABSMASK_DATA, ABSMASK MOVSD INF_DATA, INF SHLQ $3, INC // INC *= sizeof(float64) initZero: // for ;x[i]==0; i++ {} // Skip all leading zeros, to avoid divide by zero NaN MOVSD (X_), ABSX // absxi = x[i] UCOMISD ABSX, ZERO JP retNaN // if isNaN(x[i]) { return NaN } JNZ loop // if x[i] != 0 { goto loop } ADDQ INC, X_ // i += INC DECQ LEN // LEN-- JZ retZero // if LEN == 0 { return 0 } JMP initZero loop: MOVSD (X_), ABSX // absxi = x[i] MOVUPS ABSX, TMP CMPSD ABSX, TMP, $3 ORPD TMP, NANMASK // NANMASK = NANMASK | IsNaN(absxi) MOVSD INF, TMP ANDPD ABSMASK, ABSX // absxi == Abs(absxi) CMPSD ABSX, TMP, $0 ORPD TMP, INFMASK // INFMASK = INFMASK | IsInf(absxi) UCOMISD SCALE, ABSX JA adjScale // IF SCALE > ABSXI { goto adjScale } DIVSD SCALE, ABSX // absxi = scale / absxi MULSD ABSX, ABSX // absxi *= absxi ADDSD ABSX, SUMSQ // sumsq += absxi ADDQ INC, X_ // i += INC DECQ LEN // LEN-- JNZ loop // if LEN > 0 { continue } JMP retSum // if LEN == 0 { goto retSum } adjScale: // Scale > Absxi DIVSD ABSX, SCALE // tmp = absxi / scale MULSD SCALE, SUMSQ // sumsq *= tmp MULSD SCALE, SUMSQ // sumsq *= tmp ADDSD $1.0, SUMSQ // sumsq += 1 MOVUPS ABSX, SCALE // scale = absxi ADDQ INC, X_ // i += INC DECQ LEN // LEN-- JNZ loop // if LEN > 0 { continue } retSum: // Calculate return value SQRTSD SUMSQ, SUMSQ // sumsq = sqrt(sumsq) MULSD SCALE, SUMSQ // sumsq += scale MOVQ SUMSQ, R10 // tmp = sumsq UCOMISD ZERO, INFMASK CMOVQPS INF_DATA, R10 // if INFMASK { tmp = INF } UCOMISD ZERO, NANMASK CMOVQPS NAN_DATA, R10 // if NANMASK { tmp = NaN } MOVQ R10, norm+40(FP) // return tmp RET retZero: MOVSD ZERO, norm+40(FP) // return 0 RET retNaN: MOVSD NAN_DATA, TMP // return NaN MOVSD TMP, norm+40(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/linfnorm_amd64.s000066400000000000000000000032561450372207100236420ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !noasm,!gccgo,!safe #include "textflag.h" // func LinfDist(s, t []float64) float64 TEXT ·LinfDist(SB), NOSPLIT, $0 MOVQ s_base+0(FP), DI // DI = &s MOVQ t_base+24(FP), SI // SI = &t MOVQ s_len+8(FP), CX // CX = len(s) CMPQ t_len+32(FP), CX // CX = max( CX, len(t) ) CMOVQLE t_len+32(FP), CX PXOR X3, X3 // norm = 0 CMPQ CX, $0 // if CX == 0 { return 0 } JE l1_end XORQ AX, AX // i = 0 MOVQ CX, BX ANDQ $1, BX // BX = CX % 2 SHRQ $1, CX // CX = floor( CX / 2 ) JZ l1_tail_start // if CX == 0 { return 0 } l1_loop: // Loop unrolled 2x do { MOVUPS (SI)(AX*8), X0 // X0 = t[i:i+1] MOVUPS (DI)(AX*8), X1 // X1 = s[i:i+1] MOVAPS X0, X2 SUBPD X1, X0 SUBPD X2, X1 MAXPD X1, X0 // X0 = max( X0 - X1, X1 - X0 ) MAXPD X0, X3 // norm = max( norm, X0 ) ADDQ $2, AX // i += 2 LOOP l1_loop // } while --CX > 0 CMPQ BX, $0 // if BX == 0 { return } JE l1_end l1_tail_start: // Reset loop registers MOVQ BX, CX // Loop counter: CX = BX PXOR X0, X0 // reset X0, X1 to break dependencies PXOR X1, X1 l1_tail: MOVSD (SI)(AX*8), X0 // X0 = t[i] MOVSD (DI)(AX*8), X1 // X1 = s[i] MOVAPD X0, X2 SUBSD X1, X0 SUBSD X2, X1 MAXSD X1, X0 // X0 = max( X0 - X1, X1 - X0 ) MAXSD X0, X3 // norm = max( norm, X0 ) l1_end: MOVAPS X3, X2 SHUFPD $1, X2, X2 MAXSD X3, X2 // X2 = max( X3[1], X3[0] ) MOVSD X2, ret+48(FP) // return X2 RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/scal.go000066400000000000000000000022661450372207100221100ustar00rootroot00000000000000// Copyright ©2016 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f64 // ScalUnitary is // // for i := range x { // x[i] *= alpha // } func ScalUnitary(alpha float64, x []float64) { for i := range x { x[i] *= alpha } } // ScalUnitaryTo is // // for i, v := range x { // dst[i] = alpha * v // } func ScalUnitaryTo(dst []float64, alpha float64, x []float64) { for i, v := range x { dst[i] = alpha * v } } // ScalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] *= alpha // ix += incX // } func ScalInc(alpha float64, x []float64, n, incX uintptr) { var ix uintptr for i := 0; i < int(n); i++ { x[ix] *= alpha ix += incX } } // ScalIncTo is // // var idst, ix uintptr // for i := 0; i < int(n); i++ { // dst[idst] = alpha * x[ix] // ix += incX // idst += incDst // } func ScalIncTo(dst []float64, incDst uintptr, alpha float64, x []float64, n, incX uintptr) { var idst, ix uintptr for i := 0; i < int(n); i++ { dst[idst] = alpha * x[ix] ix += incX idst += incDst } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/scal_test.go000066400000000000000000000105201450372207100231370ustar00rootroot00000000000000// Copyright ©2016 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 f64_test import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" . "gonum.org/v1/gonum/internal/asm/f64" ) var scalTests = []struct { alpha float64 x []float64 want []float64 }{ { alpha: 0, x: []float64{}, want: []float64{}, }, { alpha: 0, x: []float64{1}, want: []float64{0}, }, { alpha: 1, x: []float64{1}, want: []float64{1}, }, { alpha: 2, x: []float64{1, -2}, want: []float64{2, -4}, }, { alpha: 2, x: []float64{1, -2, 3}, want: []float64{2, -4, 6}, }, { alpha: 2, x: []float64{1, -2, 3, 4}, want: []float64{2, -4, 6, 8}, }, { alpha: 2, x: []float64{1, -2, 3, 4, -5}, want: []float64{2, -4, 6, 8, -10}, }, { alpha: 2, x: []float64{0, 1, -2, 3, 4, -5, 6, -7}, want: []float64{0, 2, -4, 6, 8, -10, 12, -14}, }, { alpha: 2, x: []float64{0, 1, -2, 3, 4, -5, 6, -7, 8}, want: []float64{0, 2, -4, 6, 8, -10, 12, -14, 16}, }, { alpha: 2, x: []float64{0, 1, -2, 3, 4, -5, 6, -7, 8, 9}, want: []float64{0, 2, -4, 6, 8, -10, 12, -14, 16, 18}, }, { alpha: 3, x: []float64{0, 1, -2, 3, 4, -5, 6, -7, 8, 9, 12}, want: []float64{0, 3, -6, 9, 12, -15, 18, -21, 24, 27, 36}, }, } func TestScalUnitary(t *testing.T) { const xGdVal = -0.5 for i, test := range scalTests { for _, align := range align1 { prefix := fmt.Sprintf("Test %v (x:%v)", i, align) xgLn := 4 + align xg := guardVector(test.x, xGdVal, xgLn) x := xg[xgLn : len(xg)-xgLn] ScalUnitary(test.alpha, x) for i := range test.want { if !scalar.Same(x[i], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i], test.want[i]) } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } } } } func TestScalUnitaryTo(t *testing.T) { const xGdVal, dstGdVal = -1, 0.5 rng := rand.New(rand.NewSource(42)) for i, test := range scalTests { n := len(test.x) for _, align := range align2 { prefix := fmt.Sprintf("Test %v (x:%v dst:%v)", i, align.x, align.y) xgLn, dgLn := 4+align.x, 4+align.y xg := guardVector(test.x, xGdVal, xgLn) dg := guardVector(randSlice(n, 1, rng), dstGdVal, dgLn) x, dst := xg[xgLn:len(xg)-xgLn], dg[dgLn:len(dg)-dgLn] ScalUnitaryTo(dst, test.alpha, x) for i := range test.want { if !scalar.Same(dst[i], test.want[i]) { t.Errorf(msgVal, prefix, i, dst[i], test.want[i]) } } if !isValidGuard(xg, xGdVal, xgLn) { t.Errorf(msgGuard, prefix, "x", xg[:xgLn], xg[len(xg)-xgLn:]) } if !isValidGuard(dg, dstGdVal, dgLn) { t.Errorf(msgGuard, prefix, "y", dg[:dgLn], dg[len(dg)-dgLn:]) } if !equalStrided(test.x, x, 1) { t.Errorf(msgReadOnly, prefix, "x") } } } } func TestScalInc(t *testing.T) { const xGdVal = -0.5 gdLn := 4 for i, test := range scalTests { n := len(test.x) for _, incX := range []int{1, 2, 3, 4, 7, 10} { prefix := fmt.Sprintf("Test %v (x:%v)", i, incX) xg := guardIncVector(test.x, xGdVal, incX, gdLn) x := xg[gdLn : len(xg)-gdLn] ScalInc(test.alpha, x, uintptr(n), uintptr(incX)) for i := range test.want { if !scalar.Same(x[i*incX], test.want[i]) { t.Errorf(msgVal, prefix, i, x[i*incX], test.want[i]) } } checkValidIncGuard(t, xg, xGdVal, incX, gdLn) } } } func TestScalIncTo(t *testing.T) { const xGdVal, dstGdVal = -1, 0.5 gdLn := 4 rng := rand.New(rand.NewSource(42)) for i, test := range scalTests { n := len(test.x) for _, inc := range newIncSet(1, 2, 3, 4, 7, 10) { prefix := fmt.Sprintf("test %v (x:%v dst:%v)", i, inc.x, inc.y) xg := guardIncVector(test.x, xGdVal, inc.x, gdLn) dg := guardIncVector(randSlice(n, 1, rng), dstGdVal, inc.y, gdLn) x, dst := xg[gdLn:len(xg)-gdLn], dg[gdLn:len(dg)-gdLn] ScalIncTo(dst, uintptr(inc.y), test.alpha, x, uintptr(n), uintptr(inc.x)) for i := range test.want { if !scalar.Same(dst[i*inc.y], test.want[i]) { t.Errorf(msgVal, prefix, i, dst[i*inc.y], test.want[i]) } } checkValidIncGuard(t, xg, xGdVal, inc.x, gdLn) checkValidIncGuard(t, dg, dstGdVal, inc.y, gdLn) if !equalStrided(test.x, x, inc.x) { t.Errorf("%v: modified read-only x argument", prefix) } } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/scalinc_amd64.s000066400000000000000000000074101450372207100234260ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define LEN CX #define TAIL BX #define INC_X R8 #define INCx3_X R9 #define ALPHA X0 #define ALPHA_2 X1 // func ScalInc(alpha float64, x []float64, n, incX uintptr) TEXT ·ScalInc(SB), NOSPLIT, $0 MOVSD alpha+0(FP), ALPHA // ALPHA = alpha MOVQ x_base+8(FP), X_PTR // X_PTR = &x MOVQ incX+40(FP), INC_X // INC_X = incX SHLQ $3, INC_X // INC_X *= sizeof(float64) MOVQ n+32(FP), LEN // LEN = n CMPQ LEN, $0 JE end // if LEN == 0 { return } MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = LEN % 4 SHRQ $2, LEN // LEN = floor( LEN / 4 ) JZ tail_start // if LEN == 0 { goto tail_start } MOVUPS ALPHA, ALPHA_2 // ALPHA_2 = ALPHA for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 loop: // do { // x[i] *= alpha unrolled 4x. MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MOVSD (X_PTR)(INC_X*2), X4 MOVSD (X_PTR)(INCx3_X*1), X5 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA_2, X3 MULSD ALPHA, X4 MULSD ALPHA_2, X5 MOVSD X2, (X_PTR) // x[i] = X_i MOVSD X3, (X_PTR)(INC_X*1) MOVSD X4, (X_PTR)(INC_X*2) MOVSD X5, (X_PTR)(INCx3_X*1) LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[incX*4]) DECQ LEN JNZ loop // } while --LEN > 0 CMPQ TAIL, $0 JE end // if TAIL == 0 { return } tail_start: // Reset loop registers MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( LEN / 2 ) JZ tail_one tail_two: // do { MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA, X3 MOVSD X2, (X_PTR) // x[i] = X_i MOVSD X3, (X_PTR)(INC_X*1) LEAQ (X_PTR)(INC_X*2), X_PTR // X_PTR = &(X_PTR[incX*2]) ANDQ $1, TAIL JZ end tail_one: MOVSD (X_PTR), X2 // X_i = x[i] MULSD ALPHA, X2 // X_i *= ALPHA MOVSD X2, (X_PTR) // x[i] = X_i end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/scalincto_amd64.s000066400000000000000000000104661450372207100237760ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define DST_PTR DI #define LEN CX #define TAIL BX #define INC_X R8 #define INCx3_X R9 #define INC_DST R10 #define INCx3_DST R11 #define ALPHA X0 #define ALPHA_2 X1 // func ScalIncTo(dst []float64, incDst uintptr, alpha float64, x []float64, n, incX uintptr) TEXT ·ScalIncTo(SB), NOSPLIT, $0 MOVQ dst_base+0(FP), DST_PTR // DST_PTR = &dst MOVQ incDst+24(FP), INC_DST // INC_DST = incDst SHLQ $3, INC_DST // INC_DST *= sizeof(float64) MOVSD alpha+32(FP), ALPHA // ALPHA = alpha MOVQ x_base+40(FP), X_PTR // X_PTR = &x MOVQ n+64(FP), LEN // LEN = n MOVQ incX+72(FP), INC_X // INC_X = incX SHLQ $3, INC_X // INC_X *= sizeof(float64) CMPQ LEN, $0 JE end // if LEN == 0 { return } MOVQ LEN, TAIL ANDQ $3, TAIL // TAIL = LEN % 4 SHRQ $2, LEN // LEN = floor( LEN / 4 ) JZ tail_start // if LEN == 0 { goto tail_start } MOVUPS ALPHA, ALPHA_2 // ALPHA_2 = ALPHA for pipelining LEAQ (INC_X)(INC_X*2), INCx3_X // INCx3_X = INC_X * 3 LEAQ (INC_DST)(INC_DST*2), INCx3_DST // INCx3_DST = INC_DST * 3 loop: // do { // x[i] *= alpha unrolled 4x. MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MOVSD (X_PTR)(INC_X*2), X4 MOVSD (X_PTR)(INCx3_X*1), X5 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA_2, X3 MULSD ALPHA, X4 MULSD ALPHA_2, X5 MOVSD X2, (DST_PTR) // dst[i] = X_i MOVSD X3, (DST_PTR)(INC_DST*1) MOVSD X4, (DST_PTR)(INC_DST*2) MOVSD X5, (DST_PTR)(INCx3_DST*1) LEAQ (X_PTR)(INC_X*4), X_PTR // X_PTR = &(X_PTR[incX*4]) LEAQ (DST_PTR)(INC_DST*4), DST_PTR // DST_PTR = &(DST_PTR[incDst*4]) DECQ LEN JNZ loop // } while --LEN > 0 CMPQ TAIL, $0 JE end // if TAIL == 0 { return } tail_start: // Reset loop registers MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( LEN / 2 ) JZ tail_one tail_two: MOVSD (X_PTR), X2 // X_i = x[i] MOVSD (X_PTR)(INC_X*1), X3 MULSD ALPHA, X2 // X_i *= a MULSD ALPHA, X3 MOVSD X2, (DST_PTR) // dst[i] = X_i MOVSD X3, (DST_PTR)(INC_DST*1) LEAQ (X_PTR)(INC_X*2), X_PTR // X_PTR = &(X_PTR[incX*2]) LEAQ (DST_PTR)(INC_DST*2), DST_PTR // DST_PTR = &(DST_PTR[incDst*2]) ANDQ $1, TAIL JZ end tail_one: MOVSD (X_PTR), X2 // X_i = x[i] MULSD ALPHA, X2 // X_i *= ALPHA MOVSD X2, (DST_PTR) // x[i] = X_i end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/scalunitary_amd64.s000066400000000000000000000072351450372207100243550ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVDDUP_ALPHA LONG $0x44120FF2; WORD $0x0824 // @ MOVDDUP XMM0, 8[RSP] #define X_PTR SI #define DST_PTR DI #define IDX AX #define LEN CX #define TAIL BX #define ALPHA X0 #define ALPHA_2 X1 // func ScalUnitary(alpha float64, x []float64) TEXT ·ScalUnitary(SB), NOSPLIT, $0 MOVDDUP_ALPHA // ALPHA = { alpha, alpha } MOVQ x_base+8(FP), X_PTR // X_PTR = &x MOVQ x_len+16(FP), LEN // LEN = len(x) CMPQ LEN, $0 JE end // if LEN == 0 { return } XORQ IDX, IDX // IDX = 0 MOVQ LEN, TAIL ANDQ $7, TAIL // TAIL = LEN % 8 SHRQ $3, LEN // LEN = floor( LEN / 8 ) JZ tail_start // if LEN == 0 { goto tail_start } MOVUPS ALPHA, ALPHA_2 loop: // do { // x[i] *= alpha unrolled 8x. MOVUPS (X_PTR)(IDX*8), X2 // X_i = x[i] MOVUPS 16(X_PTR)(IDX*8), X3 MOVUPS 32(X_PTR)(IDX*8), X4 MOVUPS 48(X_PTR)(IDX*8), X5 MULPD ALPHA, X2 // X_i *= ALPHA MULPD ALPHA_2, X3 MULPD ALPHA, X4 MULPD ALPHA_2, X5 MOVUPS X2, (X_PTR)(IDX*8) // x[i] = X_i MOVUPS X3, 16(X_PTR)(IDX*8) MOVUPS X4, 32(X_PTR)(IDX*8) MOVUPS X5, 48(X_PTR)(IDX*8) ADDQ $8, IDX // i += 8 DECQ LEN JNZ loop // while --LEN > 0 CMPQ TAIL, $0 JE end // if TAIL == 0 { return } tail_start: // Reset loop registers MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( TAIL / 2 ) JZ tail_one // if n == 0 goto end tail_two: // do { MOVUPS (X_PTR)(IDX*8), X2 // X_i = x[i] MULPD ALPHA, X2 // X_i *= ALPHA MOVUPS X2, (X_PTR)(IDX*8) // x[i] = X_i ADDQ $2, IDX // i += 2 DECQ LEN JNZ tail_two // while --LEN > 0 ANDQ $1, TAIL JZ end // if TAIL == 0 { return } tail_one: // x[i] *= alpha for the remaining element. MOVSD (X_PTR)(IDX*8), X2 MULSD ALPHA, X2 MOVSD X2, (X_PTR)(IDX*8) end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/scalunitaryto_amd64.s000066400000000000000000000075761450372207100247300ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // Some of the loop unrolling code is copied from: // http://golang.org/src/math/big/arith_amd64.s // which is distributed under these terms: // // Copyright (c) 2012 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !noasm,!gccgo,!safe #include "textflag.h" #define MOVDDUP_ALPHA LONG $0x44120FF2; WORD $0x2024 // @ MOVDDUP 32(SP), X0 /*XMM0, 32[RSP]*/ #define X_PTR SI #define DST_PTR DI #define IDX AX #define LEN CX #define TAIL BX #define ALPHA X0 #define ALPHA_2 X1 // func ScalUnitaryTo(dst []float64, alpha float64, x []float64) // This function assumes len(dst) >= len(x). TEXT ·ScalUnitaryTo(SB), NOSPLIT, $0 MOVQ x_base+32(FP), X_PTR // X_PTR = &x MOVQ dst_base+0(FP), DST_PTR // DST_PTR = &dst MOVDDUP_ALPHA // ALPHA = { alpha, alpha } MOVQ x_len+40(FP), LEN // LEN = len(x) CMPQ LEN, $0 JE end // if LEN == 0 { return } XORQ IDX, IDX // IDX = 0 MOVQ LEN, TAIL ANDQ $7, TAIL // TAIL = LEN % 8 SHRQ $3, LEN // LEN = floor( LEN / 8 ) JZ tail_start // if LEN == 0 { goto tail_start } MOVUPS ALPHA, ALPHA_2 // ALPHA_2 = ALPHA for pipelining loop: // do { // dst[i] = alpha * x[i] unrolled 8x. MOVUPS (X_PTR)(IDX*8), X2 // X_i = x[i] MOVUPS 16(X_PTR)(IDX*8), X3 MOVUPS 32(X_PTR)(IDX*8), X4 MOVUPS 48(X_PTR)(IDX*8), X5 MULPD ALPHA, X2 // X_i *= ALPHA MULPD ALPHA_2, X3 MULPD ALPHA, X4 MULPD ALPHA_2, X5 MOVUPS X2, (DST_PTR)(IDX*8) // dst[i] = X_i MOVUPS X3, 16(DST_PTR)(IDX*8) MOVUPS X4, 32(DST_PTR)(IDX*8) MOVUPS X5, 48(DST_PTR)(IDX*8) ADDQ $8, IDX // i += 8 DECQ LEN JNZ loop // while --LEN > 0 CMPQ TAIL, $0 JE end // if TAIL == 0 { return } tail_start: // Reset loop counters MOVQ TAIL, LEN // Loop counter: LEN = TAIL SHRQ $1, LEN // LEN = floor( TAIL / 2 ) JZ tail_one // if LEN == 0 { goto tail_one } tail_two: // do { MOVUPS (X_PTR)(IDX*8), X2 // X_i = x[i] MULPD ALPHA, X2 // X_i *= ALPHA MOVUPS X2, (DST_PTR)(IDX*8) // dst[i] = X_i ADDQ $2, IDX // i += 2 DECQ LEN JNZ tail_two // while --LEN > 0 ANDQ $1, TAIL JZ end // if TAIL == 0 { return } tail_one: MOVSD (X_PTR)(IDX*8), X2 // X_i = x[i] MULSD ALPHA, X2 // X_i *= ALPHA MOVSD X2, (DST_PTR)(IDX*8) // dst[i] = X_i end: RET golang-gonum-v1-gonum-0.14.0/internal/asm/f64/stubs_amd64.go000066400000000000000000000123511450372207100233150ustar00rootroot00000000000000// 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:build !noasm && !gccgo && !safe // +build !noasm,!gccgo,!safe package f64 // L1Norm is // // for _, v := range x { // sum += math.Abs(v) // } // return sum func L1Norm(x []float64) (sum float64) // L1NormInc is // // for i := 0; i < n*incX; i += incX { // sum += math.Abs(x[i]) // } // return sum func L1NormInc(x []float64, n, incX int) (sum float64) // AddConst is // // for i := range x { // x[i] += alpha // } func AddConst(alpha float64, x []float64) // Add is // // for i, v := range s { // dst[i] += v // } func Add(dst, s []float64) // AxpyUnitary is // // for i, v := range x { // y[i] += alpha * v // } func AxpyUnitary(alpha float64, x, y []float64) // AxpyUnitaryTo is // // for i, v := range x { // dst[i] = alpha*v + y[i] // } func AxpyUnitaryTo(dst []float64, alpha float64, x, y []float64) // AxpyInc is // // for i := 0; i < int(n); i++ { // y[iy] += alpha * x[ix] // ix += incX // iy += incY // } func AxpyInc(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) // AxpyIncTo is // // for i := 0; i < int(n); i++ { // dst[idst] = alpha*x[ix] + y[iy] // ix += incX // iy += incY // idst += incDst // } func AxpyIncTo(dst []float64, incDst, idst uintptr, alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) // CumSum is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] + v // } // return dst func CumSum(dst, s []float64) []float64 // CumProd is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] * v // } // return dst func CumProd(dst, s []float64) []float64 // Div is // // for i, v := range s { // dst[i] /= v // } func Div(dst, s []float64) // DivTo is // // for i, v := range s { // dst[i] = v / t[i] // } // return dst func DivTo(dst, x, y []float64) []float64 // DotUnitary is // // for i, v := range x { // sum += y[i] * v // } // return sum func DotUnitary(x, y []float64) (sum float64) // DotInc is // // for i := 0; i < int(n); i++ { // sum += y[iy] * x[ix] // ix += incX // iy += incY // } // return sum func DotInc(x, y []float64, n, incX, incY, ix, iy uintptr) (sum float64) // L1Dist is // // var norm float64 // for i, v := range s { // norm += math.Abs(t[i] - v) // } // return norm func L1Dist(s, t []float64) float64 // LinfDist is // // var norm float64 // if len(s) == 0 { // return 0 // } // norm = math.Abs(t[0] - s[0]) // for i, v := range s[1:] { // absDiff := math.Abs(t[i+1] - v) // if absDiff > norm || math.IsNaN(norm) { // norm = absDiff // } // } // return norm func LinfDist(s, t []float64) float64 // ScalUnitary is // // for i := range x { // x[i] *= alpha // } func ScalUnitary(alpha float64, x []float64) // ScalUnitaryTo is // // for i, v := range x { // dst[i] = alpha * v // } func ScalUnitaryTo(dst []float64, alpha float64, x []float64) // ScalInc is // // var ix uintptr // for i := 0; i < int(n); i++ { // x[ix] *= alpha // ix += incX // } func ScalInc(alpha float64, x []float64, n, incX uintptr) // ScalIncTo is // // var idst, ix uintptr // for i := 0; i < int(n); i++ { // dst[idst] = alpha * x[ix] // ix += incX // idst += incDst // } func ScalIncTo(dst []float64, incDst uintptr, alpha float64, x []float64, n, incX uintptr) // Sum is // // var sum float64 // for i := range x { // sum += x[i] // } func Sum(x []float64) float64 // L2NormUnitary returns the L2-norm of x. // // var scale float64 // sumSquares := 1.0 // for _, v := range x { // if v == 0 { // continue // } // absxi := math.Abs(v) // if math.IsNaN(absxi) { // return math.NaN() // } // if scale < absxi { // s := scale / absxi // sumSquares = 1 + sumSquares*s*s // scale = absxi // } else { // s := absxi / scale // sumSquares += s * s // } // if math.IsInf(scale, 1) { // return math.Inf(1) // } // } // return scale * math.Sqrt(sumSquares) func L2NormUnitary(x []float64) (norm float64) // L2NormInc returns the L2-norm of x. // // var scale float64 // sumSquares := 1.0 // for ix := uintptr(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 { // s := scale / absxi // sumSquares = 1 + sumSquares*s*s // scale = absxi // } else { // s := absxi / scale // sumSquares += s * s // } // } // if math.IsInf(scale, 1) { // return math.Inf(1) // } // return scale * math.Sqrt(sumSquares) func L2NormInc(x []float64, n, incX uintptr) (norm float64) // L2DistanceUnitary returns the L2-norm of x-y. // // var scale float64 // sumSquares := 1.0 // for i, v := range x { // v -= y[i] // if v == 0 { // continue // } // absxi := math.Abs(v) // if math.IsNaN(absxi) { // return math.NaN() // } // if scale < absxi { // s := scale / absxi // sumSquares = 1 + sumSquares*s*s // scale = absxi // } else { // s := absxi / scale // sumSquares += s * s // } // } // if math.IsInf(scale, 1) { // return math.Inf(1) // } // return scale * math.Sqrt(sumSquares) func L2DistanceUnitary(x, y []float64) (norm float64) golang-gonum-v1-gonum-0.14.0/internal/asm/f64/stubs_noasm.go000066400000000000000000000054461450372207100235260ustar00rootroot00000000000000// Copyright ©2016 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:build !amd64 || noasm || gccgo || safe // +build !amd64 noasm gccgo safe package f64 import "math" // L1Norm is // // for _, v := range x { // sum += math.Abs(v) // } // return sum func L1Norm(x []float64) (sum float64) { for _, v := range x { sum += math.Abs(v) } return sum } // L1NormInc is // // for i := 0; i < n*incX; i += incX { // sum += math.Abs(x[i]) // } // return sum func L1NormInc(x []float64, n, incX int) (sum float64) { for i := 0; i < n*incX; i += incX { sum += math.Abs(x[i]) } return sum } // Add is // // for i, v := range s { // dst[i] += v // } func Add(dst, s []float64) { for i, v := range s { dst[i] += v } } // AddConst is // // for i := range x { // x[i] += alpha // } func AddConst(alpha float64, x []float64) { for i := range x { x[i] += alpha } } // CumSum is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] + v // } // return dst func CumSum(dst, s []float64) []float64 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] + v } return dst } // CumProd is // // if len(s) == 0 { // return dst // } // dst[0] = s[0] // for i, v := range s[1:] { // dst[i+1] = dst[i] * v // } // return dst func CumProd(dst, s []float64) []float64 { if len(s) == 0 { return dst } dst[0] = s[0] for i, v := range s[1:] { dst[i+1] = dst[i] * v } return dst } // Div is // // for i, v := range s { // dst[i] /= v // } func Div(dst, s []float64) { for i, v := range s { dst[i] /= v } } // DivTo is // // for i, v := range s { // dst[i] = v / t[i] // } // return dst func DivTo(dst, s, t []float64) []float64 { for i, v := range s { dst[i] = v / t[i] } return dst } // L1Dist is // // var norm float64 // for i, v := range s { // norm += math.Abs(t[i] - v) // } // return norm func L1Dist(s, t []float64) float64 { var norm float64 for i, v := range s { norm += math.Abs(t[i] - v) } return norm } // LinfDist is // // var norm float64 // if len(s) == 0 { // return 0 // } // norm = math.Abs(t[0] - s[0]) // for i, v := range s[1:] { // absDiff := math.Abs(t[i+1] - v) // if absDiff > norm || math.IsNaN(norm) { // norm = absDiff // } // } // return norm func LinfDist(s, t []float64) float64 { var norm float64 if len(s) == 0 { return 0 } norm = math.Abs(t[0] - s[0]) for i, v := range s[1:] { absDiff := math.Abs(t[i+1] - v) if absDiff > norm || math.IsNaN(norm) { norm = absDiff } } return norm } // Sum is // // var sum float64 // for i := range x { // sum += x[i] // } func Sum(x []float64) float64 { var sum float64 for _, v := range x { sum += v } return sum } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/stubs_test.go000066400000000000000000000411341450372207100233620ustar00rootroot00000000000000// Copyright ©2016 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 f64_test import ( "testing" "gonum.org/v1/gonum/floats/scalar" . "gonum.org/v1/gonum/internal/asm/f64" ) func TestL1Norm(t *testing.T) { var src_gd float64 = 1 for j, v := range []struct { want float64 x []float64 }{ {want: 0, x: []float64{}}, {want: 2, x: []float64{2}}, {want: 6, x: []float64{1, 2, 3}}, {want: 6, x: []float64{-1, -2, -3}}, {want: nan, x: []float64{nan}}, {want: 40, x: []float64{8, -8, 8, -8, 8}}, {want: 5, x: []float64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, } { g_ln := 4 + j%2 v.x = guardVector(v.x, src_gd, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L1Norm(src) if !scalar.Same(ret, v.want) { t.Errorf("Test %d L1Norm error Got: %f Expected: %f", j, ret, v.want) } if !isValidGuard(v.x, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) } } } func TestL1NormInc(t *testing.T) { var src_gd float64 = 1 for j, v := range []struct { inc int want float64 x []float64 }{ {inc: 2, want: 0, x: []float64{}}, {inc: 3, want: 2, x: []float64{2}}, {inc: 10, want: 6, x: []float64{1, 2, 3}}, {inc: 5, want: 6, x: []float64{-1, -2, -3}}, {inc: 3, want: nan, x: []float64{nan}}, {inc: 15, want: 40, x: []float64{8, -8, 8, -8, 8}}, {inc: 1, want: 5, x: []float64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, } { g_ln, ln := 4+j%2, len(v.x) v.x = guardIncVector(v.x, src_gd, v.inc, g_ln) src := v.x[g_ln : len(v.x)-g_ln] ret := L1NormInc(src, ln, v.inc) if !scalar.Same(ret, v.want) { t.Errorf("Test %d L1NormInc error Got: %f Expected: %f", j, ret, v.want) } checkValidIncGuard(t, v.x, src_gd, v.inc, g_ln) } } func TestAdd(t *testing.T) { var src_gd, dst_gd float64 = 1, 0 for j, v := range []struct { dst, src, expect []float64 }{ { dst: []float64{1}, src: []float64{0}, expect: []float64{1}, }, { dst: []float64{1, 2, 3}, src: []float64{1}, expect: []float64{2, 2, 3}, }, { dst: []float64{}, src: []float64{}, expect: []float64{}, }, { dst: []float64{1}, src: []float64{nan}, expect: []float64{nan}, }, { dst: []float64{8, 8, 8, 8, 8}, src: []float64{2, 4, nan, 8, 9}, expect: []float64{10, 12, nan, 16, 17}, }, { dst: []float64{0, 1, 2, 3, 4}, src: []float64{-inf, 4, nan, 8, 9}, expect: []float64{-inf, 5, nan, 11, 13}, }, { dst: make([]float64, 50)[1:49], src: make([]float64, 50)[1:49], expect: make([]float64, 50)[1:49], }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] Add(dst, src) for i := range v.expect { if !scalar.Same(dst[i], v.expect[i]) { t.Errorf("Test %d Add error at %d Got: %v Expected: %v", j, i, dst[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestAddConst(t *testing.T) { var src_gd float64 = 0 for j, v := range []struct { alpha float64 src, expect []float64 }{ { alpha: 1, src: []float64{0}, expect: []float64{1}, }, { alpha: 5, src: []float64{}, expect: []float64{}, }, { alpha: 1, src: []float64{nan}, expect: []float64{nan}, }, { alpha: 8, src: []float64{2, 4, nan, 8, 9}, expect: []float64{10, 12, nan, 16, 17}, }, { alpha: inf, src: []float64{-inf, 4, nan, 8, 9}, expect: []float64{nan, inf, nan, inf, inf}, }, } { g_ln := 4 + j%2 v.src = guardVector(v.src, src_gd, g_ln) src := v.src[g_ln : len(v.src)-g_ln] AddConst(v.alpha, src) for i := range v.expect { if !scalar.Same(src[i], v.expect[i]) { t.Errorf("Test %d AddConst error at %d Got: %v Expected: %v", j, i, src[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:g_ln], v.src[len(v.src)-g_ln:]) } } } func TestCumSum(t *testing.T) { var src_gd, dst_gd float64 = -1, 0 for j, v := range []struct { dst, src, expect []float64 }{ { dst: []float64{}, src: []float64{}, expect: []float64{}, }, { dst: []float64{0}, src: []float64{1}, expect: []float64{1}, }, { dst: []float64{nan}, src: []float64{nan}, expect: []float64{nan}, }, { dst: []float64{0, 0, 0}, src: []float64{1, 2, 3}, expect: []float64{1, 3, 6}, }, { dst: []float64{0, 0, 0, 0}, src: []float64{1, 2, 3}, expect: []float64{1, 3, 6}, }, { dst: []float64{0, 0, 0, 0}, src: []float64{1, 2, 3, 4}, expect: []float64{1, 3, 6, 10}, }, { dst: []float64{1, nan, nan, 1, 1}, src: []float64{1, 1, nan, 1, 1}, expect: []float64{1, 2, nan, nan, nan}, }, { dst: []float64{nan, 4, inf, -inf, 9}, src: []float64{inf, 4, nan, -inf, 9}, expect: []float64{inf, inf, nan, nan, nan}, }, { dst: make([]float64, 16), src: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, expect: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, }, } { g_ln := 4 + j%2 v.src, v.dst = guardVector(v.src, src_gd, g_ln), guardVector(v.dst, dst_gd, g_ln) src, dst := v.src[g_ln:len(v.src)-g_ln], v.dst[g_ln:len(v.dst)-g_ln] ret := CumSum(dst, src) for i := range v.expect { if !scalar.Same(ret[i], v.expect[i]) { t.Errorf("Test %d CumSum error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !scalar.Same(ret[i], dst[i]) { t.Errorf("Test %d CumSum ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.src, src_gd, g_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:g_ln], v.src[len(v.src)-g_ln:]) } if !isValidGuard(v.dst, dst_gd, g_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:g_ln], v.dst[len(v.dst)-g_ln:]) } } } func TestCumProd(t *testing.T) { var src_gd, dst_gd float64 = -1, 1 for j, v := range []struct { dst, src, expect []float64 }{ { dst: []float64{}, src: []float64{}, expect: []float64{}, }, { dst: []float64{1}, src: []float64{1}, expect: []float64{1}, }, { dst: []float64{nan}, src: []float64{nan}, expect: []float64{nan}, }, { dst: []float64{0, 0, 0, 0}, src: []float64{1, 2, 3, 4}, expect: []float64{1, 2, 6, 24}, }, { dst: []float64{0, 0, 0}, src: []float64{1, 2, 3}, expect: []float64{1, 2, 6}, }, { dst: []float64{0, 0, 0, 0}, src: []float64{1, 2, 3}, expect: []float64{1, 2, 6}, }, { dst: []float64{nan, 1, nan, 1, 0}, src: []float64{1, 1, nan, 1, 1}, expect: []float64{1, 1, nan, nan, nan}, }, { dst: []float64{nan, 4, nan, -inf, 9}, src: []float64{inf, 4, nan, -inf, 9}, expect: []float64{inf, inf, nan, nan, nan}, }, { dst: make([]float64, 18), src: []float64{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, expect: []float64{2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536}, }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] ret := CumProd(dst, src) for i := range v.expect { if !scalar.Same(ret[i], v.expect[i]) { t.Errorf("Test %d CumProd error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !scalar.Same(ret[i], dst[i]) { t.Errorf("Test %d CumProd ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestDiv(t *testing.T) { var src_gd, dst_gd float64 = -1, 0.5 for j, v := range []struct { dst, src, expect []float64 }{ { dst: []float64{1}, src: []float64{1}, expect: []float64{1}, }, { dst: []float64{nan}, src: []float64{nan}, expect: []float64{nan}, }, { dst: []float64{1, 2, 3, 4}, src: []float64{1, 2, 3, 4}, expect: []float64{1, 1, 1, 1}, }, { dst: []float64{1, 2, 3, 4, 2, 4, 6, 8}, src: []float64{1, 2, 3, 4, 1, 2, 3, 4}, expect: []float64{1, 1, 1, 1, 2, 2, 2, 2}, }, { dst: []float64{2, 4, 6}, src: []float64{1, 2, 3}, expect: []float64{2, 2, 2}, }, { dst: []float64{0, 0, 0, 0}, src: []float64{1, 2, 3}, expect: []float64{0, 0, 0}, }, { dst: []float64{nan, 1, nan, 1, 0, nan, 1, nan, 1, 0}, src: []float64{1, 1, nan, 1, 1, 1, 1, nan, 1, 1}, expect: []float64{nan, 1, nan, 1, 0, nan, 1, nan, 1, 0}, }, { dst: []float64{inf, 4, nan, -inf, 9, inf, 4, nan, -inf, 9}, src: []float64{inf, 4, nan, -inf, 3, inf, 4, nan, -inf, 3}, expect: []float64{nan, 1, nan, nan, 3, nan, 1, nan, nan, 3}, }, } { sg_ln, dg_ln := 4+j%2, 4+j%3 v.src, v.dst = guardVector(v.src, src_gd, sg_ln), guardVector(v.dst, dst_gd, dg_ln) src, dst := v.src[sg_ln:len(v.src)-sg_ln], v.dst[dg_ln:len(v.dst)-dg_ln] Div(dst, src) for i := range v.expect { if !scalar.Same(dst[i], v.expect[i]) { t.Errorf("Test %d Div error at %d Got: %v Expected: %v", j, i, dst[i], v.expect[i]) } } if !isValidGuard(v.src, src_gd, sg_ln) { t.Errorf("Test %d Guard violated in src vector %v %v", j, v.src[:sg_ln], v.src[len(v.src)-sg_ln:]) } if !isValidGuard(v.dst, dst_gd, dg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:dg_ln], v.dst[len(v.dst)-dg_ln:]) } } } func TestDivTo(t *testing.T) { var dst_gd, x_gd, y_gd float64 = -1, 0.5, 0.25 for j, v := range []struct { dst, x, y, expect []float64 }{ { dst: []float64{1}, x: []float64{1}, y: []float64{1}, expect: []float64{1}, }, { dst: []float64{1}, x: []float64{nan}, y: []float64{nan}, expect: []float64{nan}, }, { dst: []float64{-2, -2, -2}, x: []float64{1, 2, 3}, y: []float64{1, 2, 3}, expect: []float64{1, 1, 1}, }, { dst: []float64{0, 0, 0}, x: []float64{2, 4, 6}, y: []float64{1, 2, 3, 4}, expect: []float64{2, 2, 2}, }, { dst: []float64{-1, -1, -1}, x: []float64{0, 0, 0}, y: []float64{1, 2, 3}, expect: []float64{0, 0, 0}, }, { dst: []float64{inf, inf, inf, inf, inf, inf, inf, inf, inf, inf}, x: []float64{nan, 1, nan, 1, 0, nan, 1, nan, 1, 0}, y: []float64{1, 1, nan, 1, 1, 1, 1, nan, 1, 1}, expect: []float64{nan, 1, nan, 1, 0, nan, 1, nan, 1, 0}, }, { dst: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, x: []float64{inf, 4, nan, -inf, 9, inf, 4, nan, -inf, 9}, y: []float64{inf, 4, nan, -inf, 3, inf, 4, nan, -inf, 3}, expect: []float64{nan, 1, nan, nan, 3, nan, 1, nan, nan, 3}, }, } { xg_ln, yg_ln := 4+j%2, 4+j%3 v.y, v.x = guardVector(v.y, y_gd, yg_ln), guardVector(v.x, x_gd, xg_ln) y, x := v.y[yg_ln:len(v.y)-yg_ln], v.x[xg_ln:len(v.x)-xg_ln] v.dst = guardVector(v.dst, dst_gd, xg_ln) dst := v.dst[xg_ln : len(v.dst)-xg_ln] ret := DivTo(dst, x, y) for i := range v.expect { if !scalar.Same(ret[i], v.expect[i]) { t.Errorf("Test %d DivTo error at %d Got: %v Expected: %v", j, i, ret[i], v.expect[i]) } if !scalar.Same(ret[i], dst[i]) { t.Errorf("Test %d DivTo ret/dst mismatch %d Ret: %v Dst: %v", j, i, ret[i], dst[i]) } } if !isValidGuard(v.y, y_gd, yg_ln) { t.Errorf("Test %d Guard violated in y vector %v %v", j, v.y[:yg_ln], v.y[len(v.y)-yg_ln:]) } if !isValidGuard(v.x, x_gd, xg_ln) { t.Errorf("Test %d Guard violated in x vector %v %v", j, v.x[:xg_ln], v.x[len(v.x)-xg_ln:]) } if !isValidGuard(v.dst, dst_gd, xg_ln) { t.Errorf("Test %d Guard violated in dst vector %v %v", j, v.dst[:xg_ln], v.dst[len(v.dst)-xg_ln:]) } } } func TestL1Dist(t *testing.T) { t_gd, s_gd := -inf, inf for j, v := range []struct { s, t []float64 expect float64 }{ { s: []float64{1}, t: []float64{1}, expect: 0, }, { s: []float64{nan}, t: []float64{nan}, expect: nan, }, { s: []float64{1, 2, 3, 4}, t: []float64{1, 2, 3, 4}, expect: 0, }, { s: []float64{2, 4, 6}, t: []float64{1, 2, 3, 4}, expect: 6, }, { s: []float64{0, 0, 0}, t: []float64{1, 2, 3}, expect: 6, }, { s: []float64{0, -4, -10}, t: []float64{1, 2, 3}, expect: 20, }, { s: []float64{0, 1, 0, 1, 0}, t: []float64{1, 1, inf, 1, 1}, expect: inf, }, { s: []float64{inf, 4, nan, -inf, 9}, t: []float64{inf, 4, nan, -inf, 3}, expect: nan, }, } { sg_ln, tg_ln := 4+j%2, 4+j%3 v.s, v.t = guardVector(v.s, s_gd, sg_ln), guardVector(v.t, t_gd, tg_ln) s_lc, t_lc := v.s[sg_ln:len(v.s)-sg_ln], v.t[tg_ln:len(v.t)-tg_ln] ret := L1Dist(s_lc, t_lc) if !scalar.Same(ret, v.expect) { t.Errorf("Test %d L1Dist error Got: %f Expected: %f", j, ret, v.expect) } if !isValidGuard(v.s, s_gd, sg_ln) { t.Errorf("Test %d Guard violated in s vector %v %v", j, v.s[:sg_ln], v.s[len(v.s)-sg_ln:]) } if !isValidGuard(v.t, t_gd, tg_ln) { t.Errorf("Test %d Guard violated in t vector %v %v", j, v.t[:tg_ln], v.t[len(v.t)-tg_ln:]) } } } func TestLinfDist(t *testing.T) { var t_gd, s_gd float64 = 0, inf for j, v := range []struct { s, t []float64 expect float64 }{ { s: []float64{}, t: []float64{}, expect: 0, }, { s: []float64{1}, t: []float64{1}, expect: 0, }, { s: []float64{nan}, t: []float64{nan}, expect: nan, }, { s: []float64{1, 2, 3, 4}, t: []float64{1, 2, 3, 4}, expect: 0, }, { s: []float64{2, 4, 6}, t: []float64{1, 2, 3, 4}, expect: 3, }, { s: []float64{0, 0, 0}, t: []float64{1, 2, 3}, expect: 3, }, { s: []float64{0, 1, 0, 1, 0}, t: []float64{1, 1, inf, 1, 1}, expect: inf, }, { s: []float64{inf, 4, nan, -inf, 9}, t: []float64{inf, 4, nan, -inf, 3}, expect: 6, }, } { sg_ln, tg_ln := 4+j%2, 4+j%3 v.s, v.t = guardVector(v.s, s_gd, sg_ln), guardVector(v.t, t_gd, tg_ln) s_lc, t_lc := v.s[sg_ln:len(v.s)-sg_ln], v.t[tg_ln:len(v.t)-tg_ln] ret := LinfDist(s_lc, t_lc) if !scalar.Same(ret, v.expect) { t.Errorf("Test %d LinfDist error Got: %f Expected: %f", j, ret, v.expect) } if !isValidGuard(v.s, s_gd, sg_ln) { t.Errorf("Test %d Guard violated in s vector %v %v", j, v.s[:sg_ln], v.s[len(v.s)-sg_ln:]) } if !isValidGuard(v.t, t_gd, tg_ln) { t.Errorf("Test %d Guard violated in t vector %v %v", j, v.t[:tg_ln], v.t[len(v.t)-tg_ln:]) } } } func TestSum(t *testing.T) { var srcGd float64 = -1 for j, v := range []struct { src []float64 expect float64 }{ { src: []float64{}, expect: 0, }, { src: []float64{1}, expect: 1, }, { src: []float64{nan}, expect: nan, }, { src: []float64{1, 2, 3}, expect: 6, }, { src: []float64{1, -4, 3}, expect: 0, }, { src: []float64{1, 2, 3, 4}, expect: 10, }, { src: []float64{1, 1, nan, 1, 1}, expect: nan, }, { src: []float64{inf, 4, nan, -inf, 9}, expect: nan, }, { src: []float64{1, 1, 1, 1, 9, 1, 1, 1, 2, 1, 1, 1, 1, 1, 5, 1}, expect: 29, }, { src: []float64{1, 1, 1, 1, 9, 1, 1, 1, 2, 1, 1, 1, 1, 1, 5, 11, 1, 1, 1, 9, 1, 1, 1, 2, 1, 1, 1, 1, 1, 5, 1}, expect: 67, }, } { gdLn := 4 + j%2 gsrc := guardVector(v.src, srcGd, gdLn) src := gsrc[gdLn : len(gsrc)-gdLn] ret := Sum(src) if !scalar.Same(ret, v.expect) { t.Errorf("Test %d Sum error Got: %v Expected: %v", j, ret, v.expect) } if !isValidGuard(gsrc, srcGd, gdLn) { t.Errorf("Test %d Guard violated in src vector %v %v", j, gsrc[:gdLn], gsrc[len(gsrc)-gdLn:]) } gdLn++ gsrc = guardVector(v.src, srcGd, gdLn) src = gsrc[gdLn : len(gsrc)-gdLn] ret = Sum(src) if !scalar.Same(ret, v.expect) { t.Errorf("Test %d Sum error Got: %v Expected: %v", j, ret, v.expect) } if !isValidGuard(gsrc, srcGd, gdLn) { t.Errorf("Test %d Guard violated in src vector %v %v", j, gsrc[:gdLn], gsrc[len(gsrc)-gdLn:]) } } } golang-gonum-v1-gonum-0.14.0/internal/asm/f64/sum_amd64.s000066400000000000000000000042241450372207100226160ustar00rootroot00000000000000// 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. // +build !noasm,!gccgo,!safe #include "textflag.h" #define X_PTR SI #define IDX AX #define LEN CX #define TAIL BX #define SUM X0 #define SUM_1 X1 #define SUM_2 X2 #define SUM_3 X3 // func Sum(x []float64) float64 TEXT ·Sum(SB), NOSPLIT, $0 MOVQ x_base+0(FP), X_PTR // X_PTR = &x MOVQ x_len+8(FP), LEN // LEN = len(x) XORQ IDX, IDX // i = 0 PXOR SUM, SUM // p_sum_i = 0 CMPQ LEN, $0 // if LEN == 0 { return 0 } JE sum_end PXOR SUM_1, SUM_1 PXOR SUM_2, SUM_2 PXOR SUM_3, SUM_3 MOVQ X_PTR, TAIL // Check memory alignment ANDQ $15, TAIL // TAIL = &y % 16 JZ no_trim // if TAIL == 0 { goto no_trim } // Align on 16-byte boundary ADDSD (X_PTR), X0 // X0 += x[0] INCQ IDX // i++ DECQ LEN // LEN-- JZ sum_end // if LEN == 0 { return } no_trim: MOVQ LEN, TAIL SHRQ $4, LEN // LEN = floor( n / 16 ) JZ sum_tail8 // if LEN == 0 { goto sum_tail8 } sum_loop: // sum 16x wide do { ADDPD (X_PTR)(IDX*8), SUM // sum_i += x[i:i+2] ADDPD 16(X_PTR)(IDX*8), SUM_1 ADDPD 32(X_PTR)(IDX*8), SUM_2 ADDPD 48(X_PTR)(IDX*8), SUM_3 ADDPD 64(X_PTR)(IDX*8), SUM ADDPD 80(X_PTR)(IDX*8), SUM_1 ADDPD 96(X_PTR)(IDX*8), SUM_2 ADDPD 112(X_PTR)(IDX*8), SUM_3 ADDQ $16, IDX // i += 16 DECQ LEN JNZ sum_loop // } while --LEN > 0 sum_tail8: TESTQ $8, TAIL JZ sum_tail4 ADDPD (X_PTR)(IDX*8), SUM // sum_i += x[i:i+2] ADDPD 16(X_PTR)(IDX*8), SUM_1 ADDPD 32(X_PTR)(IDX*8), SUM_2 ADDPD 48(X_PTR)(IDX*8), SUM_3 ADDQ $8, IDX sum_tail4: ADDPD SUM_3, SUM ADDPD SUM_2, SUM_1 TESTQ $4, TAIL JZ sum_tail2 ADDPD (X_PTR)(IDX*8), SUM // sum_i += x[i:i+2] ADDPD 16(X_PTR)(IDX*8), SUM_1 ADDQ $4, IDX sum_tail2: ADDPD SUM_1, SUM TESTQ $2, TAIL JZ sum_tail1 ADDPD (X_PTR)(IDX*8), SUM // sum_i += x[i:i+2] ADDQ $2, IDX sum_tail1: HADDPD SUM, SUM // sum_i[0] += sum_i[1] TESTQ $1, TAIL JZ sum_end ADDSD (X_PTR)(IDX*8), SUM sum_end: // return sum MOVSD SUM, ret+24(FP) RET golang-gonum-v1-gonum-0.14.0/internal/asm/staticcheck.conf000066400000000000000000000000371450372207100233660ustar00rootroot00000000000000checks = ["inherit", "-U1000"] golang-gonum-v1-gonum-0.14.0/internal/cmplx64/000077500000000000000000000000001450372207100207475ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/cmplx64/abs.go000066400000000000000000000010201450372207100220340ustar00rootroot00000000000000// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©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 cmplx64 import math "gonum.org/v1/gonum/internal/math32" // Abs returns the absolute value (also called the modulus) of x. func Abs(x complex64) float32 { return math.Hypot(real(x), imag(x)) } golang-gonum-v1-gonum-0.14.0/internal/cmplx64/cmath_test.go000066400000000000000000000154751450372207100234450ustar00rootroot00000000000000// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©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 cmplx64 import ( "testing" math "gonum.org/v1/gonum/internal/math32" ) // The higher-precision values in vc26 were used to derive the // input arguments vc (see also comment below). For reference // only (do not delete). // //lint:ignore U1000 See comment above. var vc26 = []complex64{ (4.97901192488367350108546816 + 7.73887247457810456552351752i), (7.73887247457810456552351752 - 0.27688005719200159404635997i), (-0.27688005719200159404635997 - 5.01060361827107492160848778i), (-5.01060361827107492160848778 + 9.63629370719841737980004837i), (9.63629370719841737980004837 + 2.92637723924396464525443662i), (2.92637723924396464525443662 + 5.22908343145930665230025625i), (5.22908343145930665230025625 + 2.72793991043601025126008608i), (2.72793991043601025126008608 + 1.82530809168085506044576505i), (1.82530809168085506044576505 - 8.68592476857560136238589621i), (-8.68592476857560136238589621 + 4.97901192488367350108546816i), } var vc = []complex64{ (4.9790119248836735e+00 + 7.7388724745781045e+00i), (7.7388724745781045e+00 - 2.7688005719200159e-01i), (-2.7688005719200159e-01 - 5.0106036182710749e+00i), (-5.0106036182710749e+00 + 9.6362937071984173e+00i), (9.6362937071984173e+00 + 2.9263772392439646e+00i), (2.9263772392439646e+00 + 5.2290834314593066e+00i), (5.2290834314593066e+00 + 2.7279399104360102e+00i), (2.7279399104360102e+00 + 1.8253080916808550e+00i), (1.8253080916808550e+00 - 8.6859247685756013e+00i), (-8.6859247685756013e+00 + 4.9790119248836735e+00i), } // The expected results below were computed by the high precision calculators // at http://keisan.casio.com/. More exact input values (array vc[], above) // were obtained by printing them with "%.26f". The answers were calculated // to 26 digits (by using the "Digit number" drop-down control of each // calculator). var abs = []float32{ 9.2022120669932650313380972e+00, 7.7438239742296106616261394e+00, 5.0182478202557746902556648e+00, 1.0861137372799545160704002e+01, 1.0070841084922199607011905e+01, 5.9922447613166942183705192e+00, 5.8978784056736762299945176e+00, 3.2822866700678709020367184e+00, 8.8756430028990417290744307e+00, 1.0011785496777731986390856e+01, } var conj = []complex64{ (4.9790119248836735e+00 - 7.7388724745781045e+00i), (7.7388724745781045e+00 + 2.7688005719200159e-01i), (-2.7688005719200159e-01 + 5.0106036182710749e+00i), (-5.0106036182710749e+00 - 9.6362937071984173e+00i), (9.6362937071984173e+00 - 2.9263772392439646e+00i), (2.9263772392439646e+00 - 5.2290834314593066e+00i), (5.2290834314593066e+00 - 2.7279399104360102e+00i), (2.7279399104360102e+00 - 1.8253080916808550e+00i), (1.8253080916808550e+00 + 8.6859247685756013e+00i), (-8.6859247685756013e+00 - 4.9790119248836735e+00i), } var sqrt = []complex64{ (2.6628203086086130543813948e+00 + 1.4531345674282185229796902e+00i), (2.7823278427251986247149295e+00 - 4.9756907317005224529115567e-02i), (1.5397025302089642757361015e+00 - 1.6271336573016637535695727e+00i), (1.7103411581506875260277898e+00 + 2.8170677122737589676157029e+00i), (3.1390392472953103383607947e+00 + 4.6612625849858653248980849e-01i), (2.1117080764822417640789287e+00 + 1.2381170223514273234967850e+00i), (2.3587032281672256703926939e+00 + 5.7827111903257349935720172e-01i), (1.7335262588873410476661577e+00 + 5.2647258220721269141550382e-01i), (2.3131094974708716531499282e+00 - 1.8775429304303785570775490e+00i), (8.1420535745048086240947359e-01 + 3.0575897587277248522656113e+00i), } // special cases var vcAbsSC = []complex64{ NaN(), } var absSC = []float32{ math.NaN(), } var vcConjSC = []complex64{ NaN(), } var conjSC = []complex64{ NaN(), } var vcIsNaNSC = []complex64{ complex(math.Inf(-1), math.Inf(-1)), complex(math.Inf(-1), math.NaN()), complex(math.NaN(), math.Inf(-1)), complex(0, math.NaN()), complex(math.NaN(), 0), complex(math.Inf(1), math.Inf(1)), complex(math.Inf(1), math.NaN()), complex(math.NaN(), math.Inf(1)), complex(math.NaN(), math.NaN()), } var isNaNSC = []bool{ false, false, false, true, true, false, false, false, true, } var vcSqrtSC = []complex64{ NaN(), } var sqrtSC = []complex64{ NaN(), } // functions borrowed from pkg/math/all_test.go func tolerance(a, b, e float32) bool { d := a - b if d < 0 { d = -d } // note: b is correct (expected) value, a is actual value. // make error tolerance a fraction of b, not a. if b != 0 { e = e * b if e < 0 { e = -e } } return d < e } func veryclose(a, b float32) bool { return tolerance(a, b, 1e-7) } func alike(a, b float32) bool { switch { case a != a && b != b: // math.IsNaN(a) && math.IsNaN(b): return true case a == b: return math.Signbit(a) == math.Signbit(b) } return false } func cTolerance(a, b complex64, e float32) bool { d := Abs(a - b) if b != 0 { e = e * Abs(b) if e < 0 { e = -e } } return d < e } func cVeryclose(a, b complex64) bool { return cTolerance(a, b, 1e-6) } func cAlike(a, b complex64) bool { switch { case IsNaN(a) && IsNaN(b): return true case a == b: return math.Signbit(real(a)) == math.Signbit(real(b)) && math.Signbit(imag(a)) == math.Signbit(imag(b)) } return false } func TestAbs(t *testing.T) { for i := 0; i < len(vc); i++ { if f := Abs(vc[i]); !veryclose(abs[i], f) { t.Errorf("Abs(%g) = %g, want %g", vc[i], f, abs[i]) } } for i := 0; i < len(vcAbsSC); i++ { if f := Abs(vcAbsSC[i]); !alike(absSC[i], f) { t.Errorf("Abs(%g) = %g, want %g", vcAbsSC[i], f, absSC[i]) } } } func TestConj(t *testing.T) { for i := 0; i < len(vc); i++ { if f := Conj(vc[i]); !cVeryclose(conj[i], f) { t.Errorf("Conj(%g) = %g, want %g", vc[i], f, conj[i]) } } for i := 0; i < len(vcConjSC); i++ { if f := Conj(vcConjSC[i]); !cAlike(conjSC[i], f) { t.Errorf("Conj(%g) = %g, want %g", vcConjSC[i], f, conjSC[i]) } } } func TestIsNaN(t *testing.T) { for i := 0; i < len(vcIsNaNSC); i++ { if f := IsNaN(vcIsNaNSC[i]); isNaNSC[i] != f { t.Errorf("IsNaN(%v) = %v, want %v", vcIsNaNSC[i], f, isNaNSC[i]) } } } func TestSqrt(t *testing.T) { for i := 0; i < len(vc); i++ { if f := Sqrt(vc[i]); !cVeryclose(sqrt[i], f) { t.Errorf("Sqrt(%g) = %g, want %g", vc[i], f, sqrt[i]) } } for i := 0; i < len(vcSqrtSC); i++ { if f := Sqrt(vcSqrtSC[i]); !cAlike(sqrtSC[i], f) { t.Errorf("Sqrt(%g) = %g, want %g", vcSqrtSC[i], f, sqrtSC[i]) } } } func BenchmarkAbs(b *testing.B) { for i := 0; i < b.N; i++ { Abs(complex(2.5, 3.5)) } } func BenchmarkConj(b *testing.B) { for i := 0; i < b.N; i++ { Conj(complex(2.5, 3.5)) } } func BenchmarkSqrt(b *testing.B) { for i := 0; i < b.N; i++ { Sqrt(complex(2.5, 3.5)) } } golang-gonum-v1-gonum-0.14.0/internal/cmplx64/conj.go000066400000000000000000000007111450372207100222260ustar00rootroot00000000000000// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©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 cmplx64 // Conj returns the complex conjugate of x. func Conj(x complex64) complex64 { return complex(real(x), -imag(x)) } golang-gonum-v1-gonum-0.14.0/internal/cmplx64/doc.go000066400000000000000000000005331450372207100220440ustar00rootroot00000000000000// 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 cmplx64 provides complex64 versions of standard library math/cmplx // package routines used by gonum/blas. package cmplx64 // import "gonum.org/v1/gonum/internal/cmplx64" golang-gonum-v1-gonum-0.14.0/internal/cmplx64/isinf.go000066400000000000000000000013021450372207100224020ustar00rootroot00000000000000// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©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 cmplx64 import math "gonum.org/v1/gonum/internal/math32" // IsInf returns true if either real(x) or imag(x) is an infinity. func IsInf(x complex64) bool { if math.IsInf(real(x), 0) || math.IsInf(imag(x), 0) { return true } return false } // Inf returns a complex infinity, complex(+Inf, +Inf). func Inf() complex64 { inf := math.Inf(1) return complex(inf, inf) } golang-gonum-v1-gonum-0.14.0/internal/cmplx64/isnan.go000066400000000000000000000014361450372207100224120ustar00rootroot00000000000000// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©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 cmplx64 import math "gonum.org/v1/gonum/internal/math32" // IsNaN returns true if either real(x) or imag(x) is NaN // and neither is an infinity. func IsNaN(x complex64) bool { switch { case math.IsInf(real(x), 0) || math.IsInf(imag(x), 0): return false case math.IsNaN(real(x)) || math.IsNaN(imag(x)): return true } return false } // NaN returns a complex “not-a-number” value. func NaN() complex64 { nan := math.NaN() return complex(nan, nan) } golang-gonum-v1-gonum-0.14.0/internal/cmplx64/sqrt.go000066400000000000000000000060121450372207100222660ustar00rootroot00000000000000// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©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 cmplx64 import math "gonum.org/v1/gonum/internal/math32" // The original C code, the long comment, and the constants // below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c. // The go code is a simplified version of the original C. // // Cephes Math Library Release 2.8: June, 2000 // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier // // The readme file at http://netlib.sandia.gov/cephes/ says: // Some software in this archive may be from the book _Methods and // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster // International, 1989) or from the Cephes Mathematical Library, a // commercial product. In either event, it is copyrighted by the author. // What you see here may be used freely but it comes with no support or // guarantee. // // The two known misprints in the book are repaired here in the // source listings for the gamma function and the incomplete beta // integral. // // Stephen L. Moshier // moshier@na-net.ornl.gov // Complex square root // // DESCRIPTION: // // If z = x + iy, r = |z|, then // // 1/2 // Re w = [ (r + x)/2 ] , // // 1/2 // Im w = [ (r - x)/2 ] . // // Cancelation error in r-x or r+x is avoided by using the // identity 2 Re w Im w = y. // // Note that -w is also a square root of z. The root chosen // is always in the right half plane and Im w has the same sign as y. // // ACCURACY: // // Relative error: // arithmetic domain # trials peak rms // DEC -10,+10 25000 3.2e-17 9.6e-18 // IEEE -10,+10 1,000,000 2.9e-16 6.1e-17 // Sqrt returns the square root of x. // The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x). func Sqrt(x complex64) complex64 { if imag(x) == 0 { if real(x) == 0 { return complex(0, 0) } if real(x) < 0 { return complex(0, math.Sqrt(-real(x))) } return complex(math.Sqrt(real(x)), 0) } if real(x) == 0 { if imag(x) < 0 { r := math.Sqrt(-0.5 * imag(x)) return complex(r, -r) } r := math.Sqrt(0.5 * imag(x)) return complex(r, r) } a := real(x) b := imag(x) var scale float32 // Rescale to avoid internal overflow or underflow. if math.Abs(a) > 4 || math.Abs(b) > 4 { a *= 0.25 b *= 0.25 scale = 2 } else { a *= 1.8014398509481984e16 // 2**54 b *= 1.8014398509481984e16 scale = 7.450580596923828125e-9 // 2**-27 } r := math.Hypot(a, b) var t float32 if a > 0 { t = math.Sqrt(0.5*r + 0.5*a) r = scale * math.Abs((0.5*b)/t) t *= scale } else { r = math.Sqrt(0.5*r - 0.5*a) t = scale * math.Abs((0.5*b)/r) r *= scale } if b < 0 { return complex(t, -r) } return complex(t, r) } golang-gonum-v1-gonum-0.14.0/internal/math32/000077500000000000000000000000001450372207100205505ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/internal/math32/doc.go000066400000000000000000000005271450372207100216500ustar00rootroot00000000000000// 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 math32 provides float32 versions of standard library math package // routines used by gonum/blas/native. package math32 // import "gonum.org/v1/gonum/internal/math32" golang-gonum-v1-gonum-0.14.0/internal/math32/math.go000066400000000000000000000070131450372207100220310ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package math32 import ( "math" ) const ( unan = 0x7fc00000 uinf = 0x7f800000 uneginf = 0xff800000 mask = 0x7f8 >> 3 shift = 32 - 8 - 1 bias = 127 ) // Abs returns the absolute value of x. // // Special cases are: // // Abs(±Inf) = +Inf // Abs(NaN) = NaN func Abs(x float32) float32 { switch { case x < 0: return -x case x == 0: return 0 // return correctly abs(-0) } return x } // Copysign returns a value with the magnitude // of x and the sign of y. func Copysign(x, y float32) float32 { const sign = 1 << 31 return math.Float32frombits(math.Float32bits(x)&^sign | math.Float32bits(y)&sign) } // Hypot returns Sqrt(p*p + q*q), taking care to avoid // unnecessary overflow and underflow. // // Special cases are: // // Hypot(±Inf, q) = +Inf // Hypot(p, ±Inf) = +Inf // Hypot(NaN, q) = NaN // Hypot(p, NaN) = NaN func Hypot(p, q float32) float32 { // special cases switch { case IsInf(p, 0) || IsInf(q, 0): return Inf(1) case IsNaN(p) || IsNaN(q): return NaN() } if p < 0 { p = -p } if q < 0 { q = -q } if p < q { p, q = q, p } if p == 0 { return 0 } q = q / p return p * Sqrt(1+q*q) } // Inf returns positive infinity if sign >= 0, negative infinity if sign < 0. func Inf(sign int) float32 { var v uint32 if sign >= 0 { v = uinf } else { v = uneginf } return math.Float32frombits(v) } // IsInf reports whether f is an infinity, according to sign. // If sign > 0, IsInf reports whether f is positive infinity. // If sign < 0, IsInf reports whether f is negative infinity. // If sign == 0, IsInf reports whether f is either infinity. func IsInf(f float32, sign int) bool { // Test for infinity by comparing against maximum float. // To avoid the floating-point hardware, could use: // x := math.Float32bits(f); // return sign >= 0 && x == uinf || sign <= 0 && x == uneginf; return sign >= 0 && f > math.MaxFloat32 || sign <= 0 && f < -math.MaxFloat32 } // IsNaN reports whether f is an IEEE 754 “not-a-number” value. func IsNaN(f float32) (is bool) { // IEEE 754 says that only NaNs satisfy f != f. // To avoid the floating-point hardware, could use: // x := math.Float32bits(f); // return uint32(x>>shift)&mask == mask && x != uinf && x != uneginf return f != f } // Max returns the larger of x or y. // // Special cases are: // // Max(x, +Inf) = Max(+Inf, x) = +Inf // Max(x, NaN) = Max(NaN, x) = NaN // Max(+0, ±0) = Max(±0, +0) = +0 // Max(-0, -0) = -0 func Max(x, y float32) float32 { // special cases switch { case IsInf(x, 1) || IsInf(y, 1): return Inf(1) case IsNaN(x) || IsNaN(y): return NaN() case x == 0 && x == y: if Signbit(x) { return y } return x } if x > y { return x } return y } // Min returns the smaller of x or y. // // Special cases are: // // Min(x, -Inf) = Min(-Inf, x) = -Inf // Min(x, NaN) = Min(NaN, x) = NaN // Min(-0, ±0) = Min(±0, -0) = -0 func Min(x, y float32) float32 { // special cases switch { case IsInf(x, -1) || IsInf(y, -1): return Inf(-1) case IsNaN(x) || IsNaN(y): return NaN() case x == 0 && x == y: if Signbit(x) { return x } return y } if x < y { return x } return y } // NaN returns an IEEE 754 “not-a-number” value. func NaN() float32 { return math.Float32frombits(unan) } golang-gonum-v1-gonum-0.14.0/internal/math32/math_test.go000066400000000000000000000170401450372207100230710ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package math32 import ( "math" "testing" "testing/quick" "gonum.org/v1/gonum/floats/scalar" ) const tol = 1e-7 func TestAbs(t *testing.T) { f := func(x float32) bool { y := Abs(x) return y == float32(math.Abs(float64(x))) } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func TestCopySign(t *testing.T) { f := func(x struct{ X, Y float32 }) bool { y := Copysign(x.X, x.Y) return y == float32(math.Copysign(float64(x.X), float64(x.Y))) } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func TestHypot(t *testing.T) { // tol is increased for Hypot to avoid failures // related to https://github.com/gonum/gonum/issues/110. const tol = 1e-6 f := func(x struct{ X, Y float32 }) bool { y := Hypot(x.X, x.Y) if math.Hypot(float64(x.X), float64(x.Y)) > math.MaxFloat32 { return true } return scalar.EqualWithinRel(float64(y), math.Hypot(float64(x.X), float64(x.Y)), tol) } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func TestInf(t *testing.T) { if float64(Inf(1)) != math.Inf(1) || float64(Inf(-1)) != math.Inf(-1) { t.Error("float32(inf) not infinite") } } func TestIsInf(t *testing.T) { posInf := float32(math.Inf(1)) negInf := float32(math.Inf(-1)) if !IsInf(posInf, 0) || !IsInf(negInf, 0) || !IsInf(posInf, 1) || !IsInf(negInf, -1) || IsInf(posInf, -1) || IsInf(negInf, 1) { t.Error("unexpected isInf value") } f := func(x struct { F float32 Sign int }) bool { y := IsInf(x.F, x.Sign) return y == math.IsInf(float64(x.F), x.Sign) } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func TestIsNaN(t *testing.T) { f := func(x float32) bool { y := IsNaN(x) return y == math.IsNaN(float64(x)) } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func TestMax(t *testing.T) { values := []float32{ Inf(-1), -12.34, -1, Copysign(0, -1), 0, 1, 12.34, Inf(1), NaN(), } for _, v1 := range values { for _, v2 := range values { got := Max(v1, v2) want := float32(math.Max(float64(v1), float64(v2))) if !alike(got, want) { t.Errorf("Max(%v, %v) = %v, want %v", v1, v2, got, want) } } } } func TestMin(t *testing.T) { values := []float32{ Inf(-1), -12.34, -1, Copysign(0, -1), 0, 1, 12.34, Inf(1), NaN(), } for _, v1 := range values { for _, v2 := range values { got := Min(v1, v2) want := float32(math.Min(float64(v1), float64(v2))) if !alike(got, want) { t.Errorf("Min(%v, %v) = %v, want %v", v1, v2, got, want) } } } } func TestNaN(t *testing.T) { if !math.IsNaN(float64(NaN())) { t.Errorf("float32(nan) is a number: %f", NaN()) } } func TestSignbit(t *testing.T) { f := func(x float32) bool { return Signbit(x) == math.Signbit(float64(x)) } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func TestSqrt(t *testing.T) { f := func(x float32) bool { y := Sqrt(x) if IsNaN(y) && IsNaN(sqrt(x)) { return true } return scalar.EqualWithinRel(float64(y), float64(sqrt(x)), tol) } if err := quick.Check(f, nil); err != nil { t.Error(err) } } // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // The original C code and the long comment below are // from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and // came with this notice. The go code is a simplified // version of the original C. // // ==================================================== // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. // // Developed at SunPro, a Sun Microsystems, Inc. business. // Permission to use, copy, modify, and distribute this // software is freely granted, provided that this notice // is preserved. // ==================================================== // // __ieee754_sqrt(x) // Return correctly rounded sqrt. // // ----------------------------------------- // | Use the hardware sqrt if you have one | // ----------------------------------------- // // Method: // // Bit by bit method using integer arithmetic. (Slow, but portable) // 1. Normalization // Scale x to y in [1,4) with even powers of 2: // find an integer k such that 1 <= (y=x*2**(2k)) < 4, then // sqrt(x) = 2**k * sqrt(y) // 2. Bit by bit computation // Let q = sqrt(y) truncated to i bit after binary point (q = 1), // i 0 // i+1 2 // s = 2*q , and y = 2 * ( y - q ). (1) // i i i i // // To compute q from q , one checks whether // i+1 i // // -(i+1) 2 // (q + 2 ) <= y. (2) // i // -(i+1) // If (2) is false, then q = q ; otherwise q = q + 2 . // i+1 i i+1 i // // With some algebraic manipulation, it is not difficult to see // that (2) is equivalent to // -(i+1) // s + 2 <= y (3) // i i // // The advantage of (3) is that s and y can be computed by // i i // the following recurrence formula: // if (3) is false // // s = s , y = y ; (4) // i+1 i i+1 i // // otherwise, // -i -(i+1) // s = s + 2 , y = y - s - 2 (5) // i+1 i i+1 i i // // One may easily use induction to prove (4) and (5). // Note. Since the left hand side of (3) contain only i+2 bits, // it does not necessary to do a full (53-bit) comparison // in (3). // 3. Final rounding // After generating the 53 bits result, we compute one more bit. // Together with the remainder, we can decide whether the // result is exact, bigger than 1/2ulp, or less than 1/2ulp // (it will never equal to 1/2ulp). // The rounding mode can be detected by checking whether // huge + tiny is equal to huge, and whether huge - tiny is // equal to huge for some floating point number "huge" and "tiny". func sqrt(x float32) float32 { // special cases switch { case x == 0 || IsNaN(x) || IsInf(x, 1): return x case x < 0: return NaN() } ix := math.Float32bits(x) // normalize x exp := int((ix >> shift) & mask) if exp == 0 { // subnormal x for ix&1<>= 1 // exp = exp/2, exponent of square root // generate sqrt(x) bit by bit ix <<= 1 var q, s uint32 // q = sqrt(x) r := uint32(1 << (shift + 1)) // r = moving bit from MSB to LSB for r != 0 { t := s + r if t <= ix { s = t + r ix -= t q += r } ix <<= 1 r >>= 1 } // final rounding if ix != 0 { // remainder, result not exact q += q & 1 // round according to extra bit } ix = q>>1 + uint32(exp-1+bias)<> 1) ) var ( extremeFloat64Unit = [...]float64{ 0, math.SmallestNonzeroFloat64, 0.5, 1 - math.SmallestNonzeroFloat64, 1, } extremeFloat64Norm = [...]float64{ -math.MaxFloat64, -math.MaxFloat64 / 2, -1, -math.SmallestNonzeroFloat64, 0, math.SmallestNonzeroFloat64, 1, math.MaxFloat64 / 2, math.MaxFloat64, } extremeFloat64Exp = [...]float64{ 0, math.SmallestNonzeroFloat64, 1, math.MaxFloat64 / 2, math.MaxFloat64, } extremeFloat32Unit = [...]float32{ 0, math.SmallestNonzeroFloat32, 0.5, 1 - math.SmallestNonzeroFloat32, 1, } extremeInt = [...]int{ 0, 1, maxInt / 2, maxInt - 1, maxInt, } extremeInt31 = [...]int32{ 0, 1, math.MaxInt32 / 2, math.MaxInt32 - 1, math.MaxInt32, } extremeInt63 = [...]int64{ 0, 1, math.MaxInt64 / 2, math.MaxInt64 - 1, math.MaxInt64, } extremeUint32 = [...]uint32{ 0, 1, math.MaxUint32 / 2, math.MaxUint32 - 1, math.MaxUint32, } extremeUint64 = [...]uint64{ 0, 1, math.MaxUint64 / 2, math.MaxUint64 - 1, math.MaxUint64, } ) golang-gonum-v1-gonum-0.14.0/internal/testrand/rand.go000066400000000000000000000040051450372207100225500ustar00rootroot00000000000000// Copyright ©2020 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 testrand provides random generation and flags for testing. package testrand import ( "flag" "golang.org/x/exp/rand" ) var ( seedFlag = flag.Uint64("testrand.seed", 1, "random seed for tests (0=randomize)") extremeFlag = flag.Float64("testrand.extreme", 0, "probability of returning extreme values") nanFlag = flag.Float64("testrand.nan", 0, "probability of returning nan") ) // TB is an interface that corresponds to a subset of *testing.T and *testing.B. type TB interface { Logf(format string, args ...interface{}) } // Source corresponds to the interface in golang.org/x/exp/rand.Source. type Source = rand.Source // Rand corresponds to golang.org/x/exp/rand.Rand. type Rand interface { ExpFloat64() float64 Float32() float32 Float64() float64 Int() int Int31() int32 Int31n(n int32) int32 Int63() int64 Int63n(n int64) int64 Intn(n int) int NormFloat64() float64 Perm(n int) []int Read(p []byte) (n int, err error) Seed(seed uint64) Shuffle(n int, swap func(i, j int)) Uint32() uint32 Uint64() uint64 Uint64n(n uint64) uint64 } // New returns a new random number generator using the global flags. func New(tb TB) Rand { seed := *seedFlag if seed == 0 { seed = rand.Uint64() } // Don't log the default case. if seed == 1 && *extremeFlag == 0 && *nanFlag == 0 { base := rand.New(rand.NewSource(seed)) return base } tb.Logf("seed=%d, prob=%.2f, nan=%.2f", seed, *extremeFlag, *nanFlag) base := rand.New(rand.NewSource(seed)) if *extremeFlag <= 0 && *nanFlag <= 0 { return base } return newExtreme(*extremeFlag, *nanFlag, base) } // NewSource returns a new source for random numbers. func NewSource(tb TB) Source { seed := *seedFlag if seed == 0 { seed = rand.Uint64() } // Don't log the default case. if seed == 1 { return rand.NewSource(seed) } tb.Logf("seed %d", seed) return rand.NewSource(seed) } golang-gonum-v1-gonum-0.14.0/interp/000077500000000000000000000000001450372207100171375ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/interp/README.md000066400000000000000000000004711450372207100204200ustar00rootroot00000000000000# Gonum interp [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/interp)](https://pkg.go.dev/gonum.org/v1/gonum/interp) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/interp?status.svg)](https://godocs.io/gonum.org/v1/gonum/interp) Package interp is an interpolation package for the Go language. golang-gonum-v1-gonum-0.14.0/interp/cubic.go000066400000000000000000000357261450372207100205700ustar00rootroot00000000000000// Copyright ©2020 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 interp import ( "math" "gonum.org/v1/gonum/mat" ) // PiecewiseCubic is a piecewise cubic 1-dimensional interpolator with // continuous value and first derivative. type PiecewiseCubic struct { // Interpolated X values. xs []float64 // Coefficients of interpolating cubic polynomials, with // len(xs) - 1 rows and 4 columns. The interpolated value // for xs[i] <= x < xs[i + 1] is defined as // sum_{k = 0}^3 coeffs.At(i, k) * (x - xs[i])^k // To guarantee left-continuity, coeffs.At(i, 0) == ys[i]. coeffs mat.Dense // Last interpolated Y value, corresponding to xs[len(xs) - 1]. lastY float64 // Last interpolated dY/dX value, corresponding to xs[len(xs) - 1]. lastDyDx float64 } // Predict returns the interpolation value at x. func (pc *PiecewiseCubic) Predict(x float64) float64 { i := findSegment(pc.xs, x) if i < 0 { return pc.coeffs.At(0, 0) } m := len(pc.xs) - 1 if x == pc.xs[i] { if i < m { return pc.coeffs.At(i, 0) } return pc.lastY } if i == m { return pc.lastY } dx := x - pc.xs[i] a := pc.coeffs.RawRowView(i) return ((a[3]*dx+a[2])*dx+a[1])*dx + a[0] } // PredictDerivative returns the predicted derivative at x. func (pc *PiecewiseCubic) PredictDerivative(x float64) float64 { i := findSegment(pc.xs, x) if i < 0 { return pc.coeffs.At(0, 1) } m := len(pc.xs) - 1 if x == pc.xs[i] { if i < m { return pc.coeffs.At(i, 1) } return pc.lastDyDx } if i == m { return pc.lastDyDx } dx := x - pc.xs[i] a := pc.coeffs.RawRowView(i) return (3*a[3]*dx+2*a[2])*dx + a[1] } // FitWithDerivatives fits a piecewise cubic predictor to (X, Y, dY/dX) value // triples provided as three slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing, // len(xs) != len(ys) or len(xs) != len(dydxs). func (pc *PiecewiseCubic) FitWithDerivatives(xs, ys, dydxs []float64) { n := len(xs) if len(ys) != n { panic(differentLengths) } if len(dydxs) != n { panic(differentLengths) } if n < 2 { panic(tooFewPoints) } m := n - 1 pc.coeffs.Reset() pc.coeffs.ReuseAs(m, 4) for i := 0; i < m; i++ { dx := xs[i+1] - xs[i] if dx <= 0 { panic(xsNotStrictlyIncreasing) } dy := ys[i+1] - ys[i] // a_0 pc.coeffs.Set(i, 0, ys[i]) // a_1 pc.coeffs.Set(i, 1, dydxs[i]) // Solve a linear equation system for a_2 and a_3. pc.coeffs.Set(i, 2, (3*dy-(2*dydxs[i]+dydxs[i+1])*dx)/dx/dx) pc.coeffs.Set(i, 3, (-2*dy+(dydxs[i]+dydxs[i+1])*dx)/dx/dx/dx) } pc.xs = append(pc.xs[:0], xs...) pc.lastY = ys[m] pc.lastDyDx = dydxs[m] } // AkimaSpline is a piecewise cubic 1-dimensional interpolator with // continuous value and first derivative, which can be fitted to (X, Y) // value pairs without providing derivatives. // See https://www.iue.tuwien.ac.at/phd/rottinger/node60.html for more details. type AkimaSpline struct { cubic PiecewiseCubic } // Predict returns the interpolation value at x. func (as *AkimaSpline) Predict(x float64) float64 { return as.cubic.Predict(x) } // PredictDerivative returns the predicted derivative at x. func (as *AkimaSpline) PredictDerivative(x float64) float64 { return as.cubic.PredictDerivative(x) } // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). Always returns nil. func (as *AkimaSpline) Fit(xs, ys []float64) error { n := len(xs) if len(ys) != n { panic(differentLengths) } dydxs := make([]float64, n) if n == 2 { dx := xs[1] - xs[0] slope := (ys[1] - ys[0]) / dx dydxs[0] = slope dydxs[1] = slope as.cubic.FitWithDerivatives(xs, ys, dydxs) return nil } slopes := akimaSlopes(xs, ys) for i := 0; i < n; i++ { wLeft, wRight := akimaWeights(slopes, i) dydxs[i] = akimaWeightedAverage(slopes[i+1], slopes[i+2], wLeft, wRight) } as.cubic.FitWithDerivatives(xs, ys, dydxs) return nil } // akimaSlopes returns slopes for Akima spline method, including the approximations // of slopes outside the data range (two on each side). // It panics if len(xs) <= 2, elements of xs are not strictly increasing // or len(xs) != len(ys). func akimaSlopes(xs, ys []float64) []float64 { n := len(xs) if n <= 2 { panic(tooFewPoints) } if len(ys) != n { panic(differentLengths) } m := n + 3 slopes := make([]float64, m) for i := 2; i < m-2; i++ { dx := xs[i-1] - xs[i-2] if dx <= 0 { panic(xsNotStrictlyIncreasing) } slopes[i] = (ys[i-1] - ys[i-2]) / dx } slopes[0] = 3*slopes[2] - 2*slopes[3] slopes[1] = 2*slopes[2] - slopes[3] slopes[m-2] = 2*slopes[m-3] - slopes[m-4] slopes[m-1] = 3*slopes[m-3] - 2*slopes[m-4] return slopes } // akimaWeightedAverage returns (v1 * w1 + v2 * w2) / (w1 + w2) for w1, w2 >= 0 (not checked). // If w1 == w2 == 0, it returns a simple average of v1 and v2. func akimaWeightedAverage(v1, v2, w1, w2 float64) float64 { w := w1 + w2 if w > 0 { return (v1*w1 + v2*w2) / w } return 0.5*v1 + 0.5*v2 } // akimaWeights returns the left and right weight for approximating // the i-th derivative with neighbouring slopes. func akimaWeights(slopes []float64, i int) (float64, float64) { wLeft := math.Abs(slopes[i+2] - slopes[i+3]) wRight := math.Abs(slopes[i+1] - slopes[i]) return wLeft, wRight } // FritschButland is a piecewise cubic 1-dimensional interpolator with // continuous value and first derivative, which can be fitted to (X, Y) // value pairs without providing derivatives. // It is monotone, local and produces a C^1 curve. Its downside is that // exhibits high tension, flattening out unnaturally the interpolated // curve between the nodes. // See Fritsch, F. N. and Butland, J., "A method for constructing local // monotone piecewise cubic interpolants" (1984), SIAM J. Sci. Statist. // Comput., 5(2), pp. 300-304. type FritschButland struct { cubic PiecewiseCubic } // Predict returns the interpolation value at x. func (fb *FritschButland) Predict(x float64) float64 { return fb.cubic.Predict(x) } // PredictDerivative returns the predicted derivative at x. func (fb *FritschButland) PredictDerivative(x float64) float64 { return fb.cubic.PredictDerivative(x) } // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). Always returns nil. func (fb *FritschButland) Fit(xs, ys []float64) error { n := len(xs) if n < 2 { panic(tooFewPoints) } if len(ys) != n { panic(differentLengths) } dydxs := make([]float64, n) if n == 2 { dx := xs[1] - xs[0] slope := (ys[1] - ys[0]) / dx dydxs[0] = slope dydxs[1] = slope fb.cubic.FitWithDerivatives(xs, ys, dydxs) return nil } slopes := calculateSlopes(xs, ys) m := len(slopes) prevSlope := slopes[0] for i := 1; i < m; i++ { slope := slopes[i] if slope*prevSlope > 0 { dydxs[i] = 3 * (xs[i+1] - xs[i-1]) / ((2*xs[i+1]-xs[i-1]-xs[i])/slopes[i-1] + (xs[i+1]+xs[i]-2*xs[i-1])/slopes[i]) } else { dydxs[i] = 0 } prevSlope = slope } dydxs[0] = fritschButlandEdgeDerivative(xs, ys, slopes, true) dydxs[m] = fritschButlandEdgeDerivative(xs, ys, slopes, false) fb.cubic.FitWithDerivatives(xs, ys, dydxs) return nil } // fritschButlandEdgeDerivative calculates dy/dx approximation for the // Fritsch-Butland method for the left or right edge node. func fritschButlandEdgeDerivative(xs, ys, slopes []float64, leftEdge bool) float64 { n := len(xs) var dE, dI, h, hE, f float64 if leftEdge { dE = slopes[0] dI = slopes[1] xE := xs[0] xM := xs[1] xI := xs[2] hE = xM - xE h = xI - xE f = xM + xI - 2*xE } else { dE = slopes[n-2] dI = slopes[n-3] xE := xs[n-1] xM := xs[n-2] xI := xs[n-3] hE = xE - xM h = xE - xI f = 2*xE - xI - xM } g := (f*dE - hE*dI) / h if g*dE <= 0 { return 0 } if dE*dI <= 0 && math.Abs(g) > 3*math.Abs(dE) { return 3 * dE } return g } // fitWithSecondDerivatives fits a piecewise cubic predictor to (X, Y, d^2Y/dX^2) value // triples provided as three slices. // It panics if any of these is true: // - len(xs) < 2, // - elements of xs are not strictly increasing, // - len(xs) != len(ys), // - len(xs) != len(d2ydx2s). // Note that this method does not guarantee on its own the continuity of first derivatives. func (pc *PiecewiseCubic) fitWithSecondDerivatives(xs, ys, d2ydx2s []float64) { n := len(xs) switch { case len(ys) != n, len(d2ydx2s) != n: panic(differentLengths) case n < 2: panic(tooFewPoints) } m := n - 1 pc.coeffs.Reset() pc.coeffs.ReuseAs(m, 4) for i := 0; i < m; i++ { dx := xs[i+1] - xs[i] if dx <= 0 { panic(xsNotStrictlyIncreasing) } dy := ys[i+1] - ys[i] dm := d2ydx2s[i+1] - d2ydx2s[i] pc.coeffs.Set(i, 0, ys[i]) // a_0 pc.coeffs.Set(i, 1, (dy-(d2ydx2s[i]+dm/3)*dx*dx/2)/dx) // a_1 pc.coeffs.Set(i, 2, d2ydx2s[i]/2) // a_2 pc.coeffs.Set(i, 3, dm/6/dx) // a_3 } pc.xs = append(pc.xs[:0], xs...) pc.lastY = ys[m] lastDx := xs[m] - xs[m-1] pc.lastDyDx = pc.coeffs.At(m-1, 1) + 2*pc.coeffs.At(m-1, 2)*lastDx + 3*pc.coeffs.At(m-1, 3)*lastDx*lastDx } // makeCubicSplineSecondDerivativeEquations generates the basic system of linear equations // which have to be satisfied by the second derivatives to make the first derivatives of a // cubic spline continuous. It panics if elements of xs are not strictly increasing, or // len(xs) != len(ys). // makeCubicSplineSecondDerivativeEquations fills a banded matrix a and a vector b // defining a system of linear equations a*m = b for second derivatives vector m. // Parameters a and b are assumed to have correct dimensions and initialised to zero. func makeCubicSplineSecondDerivativeEquations(a mat.MutableBanded, b mat.MutableVector, xs, ys []float64) { n := len(xs) if len(ys) != n { panic(differentLengths) } m := n - 1 if n > 2 { for i := 0; i < m; i++ { dx := xs[i+1] - xs[i] if dx <= 0 { panic(xsNotStrictlyIncreasing) } slope := (ys[i+1] - ys[i]) / dx if i > 0 { b.SetVec(i, b.AtVec(i)+slope) a.SetBand(i, i, a.At(i, i)+dx/3) a.SetBand(i, i+1, dx/6) } if i < m-1 { b.SetVec(i+1, b.AtVec(i+1)-slope) a.SetBand(i+1, i+1, a.At(i+1, i+1)+dx/3) a.SetBand(i+1, i, dx/6) } } } } // NaturalCubic is a piecewise cubic 1-dimensional interpolator with // continuous value, first and second derivatives, which can be fitted to (X, Y) // value pairs without providing derivatives. It uses the boundary conditions // Y′′(left end ) = Y′′(right end) = 0. // See e.g. https://www.math.drexel.edu/~tolya/cubicspline.pdf for details. type NaturalCubic struct { cubic PiecewiseCubic } // Predict returns the interpolation value at x. func (nc *NaturalCubic) Predict(x float64) float64 { return nc.cubic.Predict(x) } // PredictDerivative returns the predicted derivative at x. func (nc *NaturalCubic) PredictDerivative(x float64) float64 { return nc.cubic.PredictDerivative(x) } // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). It returns an error if solving the required system // of linear equations fails. func (nc *NaturalCubic) Fit(xs, ys []float64) error { n := len(xs) a := mat.NewTridiag(n, nil, nil, nil) b := mat.NewVecDense(n, nil) makeCubicSplineSecondDerivativeEquations(a, b, xs, ys) // Add boundary conditions y′′(left) = y′′(right) = 0: b.SetVec(0, 0) b.SetVec(n-1, 0) a.SetBand(0, 0, 1) a.SetBand(n-1, n-1, 1) x := mat.NewVecDense(n, nil) err := a.SolveVecTo(x, false, b) if err == nil { nc.cubic.fitWithSecondDerivatives(xs, ys, x.RawVector().Data) } return err } // ClampedCubic is a piecewise cubic 1-dimensional interpolator with // continuous value, first and second derivatives, which can be fitted to (X, Y) // value pairs without providing derivatives. It uses the boundary conditions // Y′(left end ) = Y′(right end) = 0. type ClampedCubic struct { cubic PiecewiseCubic } // Predict returns the interpolation value at x. func (cc *ClampedCubic) Predict(x float64) float64 { return cc.cubic.Predict(x) } // PredictDerivative returns the predicted derivative at x. func (cc *ClampedCubic) PredictDerivative(x float64) float64 { return cc.cubic.PredictDerivative(x) } // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). It returns an error if solving the required system // of linear equations fails. func (cc *ClampedCubic) Fit(xs, ys []float64) error { n := len(xs) a := mat.NewTridiag(n, nil, nil, nil) b := mat.NewVecDense(n, nil) makeCubicSplineSecondDerivativeEquations(a, b, xs, ys) // Add boundary conditions y′′(left) = y′′(right) = 0: // Condition Y′(left end) = 0: dxL := xs[1] - xs[0] b.SetVec(0, (ys[1]-ys[0])/dxL) a.SetBand(0, 0, dxL/3) a.SetBand(0, 1, dxL/6) // Condition Y′(right end) = 0: m := n - 1 dxR := xs[m] - xs[m-1] b.SetVec(m, (ys[m]-ys[m-1])/dxR) a.SetBand(m, m, -dxR/3) a.SetBand(m, m-1, -dxR/6) x := mat.NewVecDense(n, nil) err := a.SolveVecTo(x, false, b) if err == nil { cc.cubic.fitWithSecondDerivatives(xs, ys, x.RawVector().Data) } return err } // NotAKnotCubic is a piecewise cubic 1-dimensional interpolator with // continuous value, first and second derivatives, which can be fitted to (X, Y) // value pairs without providing derivatives. It imposes the condition that // the third derivative of the interpolant is continuous in the first and // last interior node. // See http://www.cs.tau.ac.il/~turkel/notes/numeng/spline_note.pdf for details. type NotAKnotCubic struct { cubic PiecewiseCubic } // Predict returns the interpolation value at x. func (nak *NotAKnotCubic) Predict(x float64) float64 { return nak.cubic.Predict(x) } // PredictDerivative returns the predicted derivative at x. func (nak *NotAKnotCubic) PredictDerivative(x float64) float64 { return nak.cubic.PredictDerivative(x) } // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 3 (because at least one interior node is required), // elements of xs are not strictly increasing or len(xs) != len(ys). // It returns an error if solving the required system of linear equations fails. func (nak *NotAKnotCubic) Fit(xs, ys []float64) error { n := len(xs) if n < 3 { panic(tooFewPoints) } a := mat.NewBandDense(n, n, 2, 2, nil) b := mat.NewVecDense(n, nil) makeCubicSplineSecondDerivativeEquations(a, b, xs, ys) // Add boundary conditions. // First interior node: dxOuter := xs[1] - xs[0] dxInner := xs[2] - xs[1] a.SetBand(0, 0, 1/dxOuter) a.SetBand(0, 1, -1/dxOuter-1/dxInner) a.SetBand(0, 2, 1/dxInner) if n > 3 { // Last interior node: m := n - 1 dxOuter = xs[m] - xs[m-1] dxInner = xs[m-1] - xs[m-2] a.SetBand(m, m, 1/dxOuter) a.SetBand(m, m-1, -1/dxOuter-1/dxInner) a.SetBand(m, m-2, 1/dxInner) } x := mat.NewVecDense(n, nil) err := x.SolveVec(a, b) if err == nil { nak.cubic.fitWithSecondDerivatives(xs, ys, x.RawVector().Data) } return err } golang-gonum-v1-gonum-0.14.0/interp/cubic_test.go000066400000000000000000000546171450372207100216270ustar00rootroot00000000000000// Copyright ©2020 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 interp import ( "math" "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func TestPiecewiseCubic(t *testing.T) { t.Parallel() const ( h = 1e-8 valueTol = 1e-13 derivTol = 1e-6 nPts = 100 ) for i, test := range []struct { xs []float64 f func(float64) float64 df func(float64) float64 }{ { xs: []float64{-1.001, 0.2, 2}, f: func(x float64) float64 { return x * x }, df: func(x float64) float64 { return 2 * x }, }, { xs: []float64{-1.2, -1.001, 0, 0.2, 2.01, 2.1}, f: func(x float64) float64 { return 4*math.Pow(x, 3) - 2*x*x + 10*x - 7 }, df: func(x float64) float64 { return 12*x*x - 4*x + 10 }, }, { xs: []float64{-1.001, 0.2, 10}, f: func(x float64) float64 { return 1.5*x - 1 }, df: func(x float64) float64 { return 1.5 }, }, { xs: []float64{-1.001, 0.2, 10}, f: func(x float64) float64 { return -1 }, df: func(x float64) float64 { return 0 }, }, } { ys := applyFunc(test.xs, test.f) dydxs := applyFunc(test.xs, test.df) var pc PiecewiseCubic pc.FitWithDerivatives(test.xs, ys, dydxs) n := len(test.xs) m := n - 1 x0 := test.xs[0] x1 := test.xs[m] x := x0 - 0.1 got := pc.Predict(x) want := ys[0] if got != want { t.Errorf("Mismatch in value extrapolated to the left for test case %d: got %v, want %g", i, got, want) } got = pc.PredictDerivative(x) want = dydxs[0] if got != want { t.Errorf("Mismatch in derivative extrapolated to the left for test case %d: got %v, want %g", i, got, want) } x = x1 + 0.1 got = pc.Predict(x) want = ys[m] if got != want { t.Errorf("Mismatch in value extrapolated to the right for test case %d: got %v, want %g", i, got, want) } got = pc.PredictDerivative(x) want = dydxs[m] if got != want { t.Errorf("Mismatch in derivative extrapolated to the right for test case %d: got %v, want %g", i, got, want) } for j := 0; j < n; j++ { x := test.xs[j] got := pc.Predict(x) want := test.f(x) if math.Abs(got-want) > valueTol { t.Errorf("Mismatch in interpolated value at x == %g for test case %d: got %v, want %g", x, i, got, want) } if j < m { got = pc.coeffs.At(j, 0) if math.Abs(got-want) > valueTol { t.Errorf("Mismatch in 0-th order interpolation coefficient in %d-th node for test case %d: got %v, want %g", j, i, got, want) } dx := (test.xs[j+1] - x) / nPts for k := 1; k < nPts; k++ { xk := x + float64(k)*dx got := pc.Predict(xk) want := test.f(xk) if math.Abs(got-want) > valueTol { t.Errorf("Mismatch in interpolated value at x == %g for test case %d: got %v, want %g", x, i, got, want) } got = pc.PredictDerivative(xk) want = discrDerivPredict(&pc, x0, x1, xk, h) if math.Abs(got-want) > derivTol { t.Errorf("Mismatch in interpolated derivative at x == %g for test case %d: got %v, want %g", x, i, got, want) } } } else { got = pc.lastY if math.Abs(got-want) > valueTol { t.Errorf("Mismatch in lastY for test case %d: got %v, want %g", i, got, want) } } if j > 0 { dx := test.xs[j] - test.xs[j-1] got = ((pc.coeffs.At(j-1, 3)*dx+pc.coeffs.At(j-1, 2))*dx+pc.coeffs.At(j-1, 1))*dx + pc.coeffs.At(j-1, 0) if math.Abs(got-want) > valueTol { t.Errorf("Interpolation coefficients in %d-th node produce mismatch in interpolated value at %g for test case %d: got %v, want %g", j-1, x, i, got, want) } } got = discrDerivPredict(&pc, x0, x1, x, h) want = test.df(x) if math.Abs(got-want) > derivTol { t.Errorf("Mismatch in numerical derivative of interpolated function at x == %g for test case %d: got %v, want %g", x, i, got, want) } got = pc.PredictDerivative(x) if math.Abs(got-want) > valueTol { t.Errorf("Mismatch in interpolated derivative value at x == %g for test case %d: got %v, want %g", x, i, got, want) } } } } func TestPiecewiseCubicFitWithDerivatives(t *testing.T) { t.Parallel() xs := []float64{-1, 0, 1} ys := make([]float64, 3) dydxs := make([]float64, 3) leftPoly := func(x float64) float64 { return x*x - x + 1 } leftPolyDerivative := func(x float64) float64 { return 2*x - 1 } rightPoly := func(x float64) float64 { return x*x*x - x + 1 } rightPolyDerivative := func(x float64) float64 { return 3*x*x - 1 } ys[0] = leftPoly(xs[0]) ys[1] = leftPoly(xs[1]) ys[2] = rightPoly(xs[2]) dydxs[0] = leftPolyDerivative(xs[0]) dydxs[1] = leftPolyDerivative(xs[1]) dydxs[2] = rightPolyDerivative(xs[2]) var pc PiecewiseCubic pc.FitWithDerivatives(xs, ys, dydxs) lastY := rightPoly(xs[2]) if pc.lastY != lastY { t.Errorf("Mismatch in lastY: got %v, want %g", pc.lastY, lastY) } lastDyDx := rightPolyDerivative(xs[2]) if pc.lastDyDx != lastDyDx { t.Errorf("Mismatch in lastDxDy: got %v, want %g", pc.lastDyDx, lastDyDx) } if !floats.Equal(pc.xs, xs) { t.Errorf("Mismatch in xs: got %v, want %v", pc.xs, xs) } coeffs := mat.NewDense(2, 4, []float64{3, -3, 1, 0, 1, -1, 0, 1}) if !mat.EqualApprox(&pc.coeffs, coeffs, 1e-14) { t.Errorf("Mismatch in coeffs: got %v, want %v", pc.coeffs, coeffs) } } func TestPiecewiseCubicFitWithDerivativesErrors(t *testing.T) { t.Parallel() for _, test := range []struct { xs, ys, dydxs []float64 }{ { xs: []float64{0, 1, 2}, ys: []float64{10, 20}, dydxs: []float64{0, 0, 0}, }, { xs: []float64{0, 1, 1}, ys: []float64{10, 20, 30}, dydxs: []float64{0, 0, 0, 0}, }, { xs: []float64{0}, ys: []float64{0}, dydxs: []float64{0}, }, { xs: []float64{0, 1, 1}, ys: []float64{10, 20, 10}, dydxs: []float64{0, 0, 0}, }, } { var pc PiecewiseCubic if !panics(func() { pc.FitWithDerivatives(test.xs, test.ys, test.dydxs) }) { t.Errorf("expected panic for xs: %v, ys: %v and dydxs: %v", test.xs, test.ys, test.dydxs) } } } func TestAkimaSpline(t *testing.T) { t.Parallel() const ( derivAbsTol = 1e-8 derivRelTol = 1e-7 h = 1e-8 nPts = 100 tol = 1e-14 ) for i, test := range []struct { xs []float64 f func(float64) float64 }{ { xs: []float64{-5, -3, -2, -1.5, -1, 0.5, 1.5, 2.5, 3}, f: func(x float64) float64 { return x * x }, }, { xs: []float64{-5, -3, -2, -1.5, -1, 0.5, 1.5, 2.5, 3}, f: func(x float64) float64 { return math.Pow(x, 3.) - x*x + 2 }, }, { xs: []float64{-5, -3, -2, -1.5, -1, 0.5, 1.5, 2.5, 3}, f: func(x float64) float64 { return -10 * x }, }, { xs: []float64{-5, -3, -2, -1.5, -1, 0.5, 1.5, 2.5, 3}, f: math.Sin, }, { xs: []float64{0, 1}, f: math.Exp, }, { xs: []float64{-1, 0.5}, f: math.Cos, }, } { var as AkimaSpline n := len(test.xs) m := n - 1 x0 := test.xs[0] x1 := test.xs[m] ys := applyFunc(test.xs, test.f) err := as.Fit(test.xs, ys) if err != nil { t.Errorf("Error when fitting AkimaSpline in test case %d: %v", i, err) } for j := 0; j < n; j++ { x := test.xs[j] got := as.Predict(x) want := test.f(x) if math.Abs(got-want) > tol { t.Errorf("Mismatch in interpolated value at x == %g for test case %d: got %v, want %g", x, i, got, want) } if j < m { dx := (test.xs[j+1] - x) / nPts for k := 1; k < nPts; k++ { xk := x + float64(k)*dx got = as.PredictDerivative(xk) want = discrDerivPredict(&as, x0, x1, xk, h) if math.Abs(got-want) > derivRelTol*math.Abs(want)+derivAbsTol { t.Errorf("Mismatch in interpolated derivative at x == %g for test case %d: got %v, want %g", x, i, got, want) } } } } if n == 2 { got := as.cubic.coeffs.At(0, 1) want := (ys[1] - ys[0]) / (test.xs[1] - test.xs[0]) if math.Abs(got-want) > tol { t.Errorf("Mismatch in approximated slope for length-2 test case %d: got %v, want %g", i, got, want) } for j := 2; i < 4; j++ { got := as.cubic.coeffs.At(0, j) if got != 0 { t.Errorf("Non-zero order-%d coefficient for length-2 test case %d: got %v", j, i, got) } } } } } func TestAkimaSplineFitErrors(t *testing.T) { t.Parallel() for _, test := range []struct { xs, ys []float64 }{ { xs: []float64{0, 1, 2}, ys: []float64{10, 20}, }, { xs: []float64{0, 1}, ys: []float64{10, 20, 30}, }, { xs: []float64{0}, ys: []float64{0}, }, { xs: []float64{0, 1, 1}, ys: []float64{10, 20, 10}, }, { xs: []float64{0, 2, 1}, ys: []float64{10, 20, 10}, }, { xs: []float64{0, 0}, ys: []float64{-1, 2}, }, { xs: []float64{0, -1}, ys: []float64{-1, 2}, }, } { var as AkimaSpline if !panics(func() { _ = as.Fit(test.xs, test.ys) }) { t.Errorf("expected panic for xs: %v and ys: %v", test.xs, test.ys) } } } func TestAkimaWeightedAverage(t *testing.T) { t.Parallel() for i, test := range []struct { v1, v2, w1, w2, want float64 // "want" values calculated by hand. }{ { v1: -1, v2: 1, w1: 0, w2: 0, want: 0, }, { v1: -1, v2: 1, w1: 1e6, w2: 1e6, want: 0, }, { v1: -1, v2: 1, w1: 1e-10, w2: 0, want: -1, }, { v1: -1, v2: 1, w1: 0, w2: 1e-10, want: 1, }, { v1: 0, v2: 1000, w1: 1e-13, w2: 3e-13, want: 750, }, { v1: 0, v2: 1000, w1: 3e-13, w2: 1e-13, want: 250, }, } { got := akimaWeightedAverage(test.v1, test.v2, test.w1, test.w2) if !scalar.EqualWithinAbsOrRel(got, test.want, 1e-14, 1e-14) { t.Errorf("Mismatch in test case %d: got %v, want %g", i, got, test.want) } } } func TestAkimaSlopes(t *testing.T) { t.Parallel() for i, test := range []struct { xs, ys, want []float64 // "want" values calculated by hand. }{ { xs: []float64{-2, 0, 1}, ys: []float64{2, 0, 1.5}, want: []float64{-6, -3.5, -1, 1.5, 4, 6.5}, }, { xs: []float64{-2, -0.5, 1}, ys: []float64{-2, -0.5, 1}, want: []float64{1, 1, 1, 1, 1, 1}, }, { xs: []float64{-2, -0.5, 1}, ys: []float64{1, 1, 1}, want: []float64{0, 0, 0, 0, 0, 0}, }, { xs: []float64{0, 1.5, 2, 4, 4.5, 5, 6, 7.5, 8}, ys: []float64{-5, -4, -3.5, -3.25, -3.25, -2.5, -1.5, -1, 2}, want: []float64{0, 1. / 3, 2. / 3, 1, 0.125, 0, 1.5, 1, 1. / 3, 6, 12 - 1./3, 18 - 2./3}, }, } { got := akimaSlopes(test.xs, test.ys) if !floats.EqualApprox(got, test.want, 1e-14) { t.Errorf("Mismatch in test case %d: got %v, want %v", i, got, test.want) } } } func TestAkimaSlopesErrors(t *testing.T) { t.Parallel() for _, test := range []struct { xs, ys []float64 }{ { xs: []float64{0, 1, 2}, ys: []float64{10, 20}, }, { xs: []float64{0, 1}, ys: []float64{10, 20, 30}, }, { xs: []float64{0, 2}, ys: []float64{0, 1}, }, { xs: []float64{0, 1, 1}, ys: []float64{10, 20, 10}, }, { xs: []float64{0, 2, 1}, ys: []float64{10, 20, 10}, }, { xs: []float64{0, 0}, ys: []float64{-1, 2}, }, { xs: []float64{0, -1}, ys: []float64{-1, 2}, }, } { if !panics(func() { akimaSlopes(test.xs, test.ys) }) { t.Errorf("expected panic for xs: %v and ys: %v", test.xs, test.ys) } } } func TestAkimaWeights(t *testing.T) { t.Parallel() const tol = 1e-14 slopes := []float64{-2, -1, -0.1, 0.2, 1.2, 2.5} // "want" values calculated by hand. want := [][]float64{ {0.3, 1}, {1, 0.9}, {1.3, 0.3}, } for i := 0; i < len(want); i++ { gotLeft, gotRight := akimaWeights(slopes, i) if math.Abs(gotLeft-want[i][0]) > tol { t.Errorf("Mismatch in left weight for node %d: got %v, want %g", i, gotLeft, want[i][0]) } if math.Abs(gotRight-want[i][1]) > tol { t.Errorf("Mismatch in left weight for node %d: got %v, want %g", i, gotRight, want[i][1]) } } } func TestFritschButland(t *testing.T) { t.Parallel() const ( tol = 1e-14 nPts = 100 ) for k, test := range []struct { xs, ys []float64 }{ { xs: []float64{0, 2}, ys: []float64{0, 0.5}, }, { xs: []float64{0, 2}, ys: []float64{0, -0.5}, }, { xs: []float64{0, 2}, ys: []float64{0, 0}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{0, 1, 2, 2.5}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{0, 1.5, 1.5, 2.5}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{0, 1.5, 1.5, 1}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{0, 2.5, 1.5, 1}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{0, 2.5, 1.5, 2}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{4, 3, 2, 1}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{4, 3, 2, 2}, }, { xs: []float64{0, 2, 3, 4}, ys: []float64{4, 3, 2, 5}, }, { xs: []float64{0, 2, 3, 4, 5, 6}, ys: []float64{0, 1, 0.5, 0.5, 1.5, 1.5}, }, { xs: []float64{0, 2, 3, 4, 5, 6}, ys: []float64{0, 1, 1.5, 2.5, 1.5, 1}, }, { xs: []float64{0, 2, 3, 4, 5, 6}, ys: []float64{0, -1, -1.5, -2.5, -1.5, -1}, }, { xs: []float64{0, 2, 3, 4, 5, 6}, ys: []float64{0, 1, 0.5, 1.5, 1, 2}, }, { xs: []float64{0, 2, 3, 4, 5, 6}, ys: []float64{0, 1, 1.5, 2.5, 3, 4}, }, { xs: []float64{0, 2, 3, 4, 5, 6}, ys: []float64{0, 0.0001, -1.5, -2.5, -0.0001, 0}, }, } { var fb FritschButland err := fb.Fit(test.xs, test.ys) if err != nil { t.Errorf("Error when fitting FritschButland in test case %d: %v", k, err) } n := len(test.xs) for i := 0; i < n; i++ { got := fb.Predict(test.xs[i]) want := test.ys[i] if got != want { t.Errorf("Mismatch in interpolated value for node %d in test case %d: got %v, want %g", i, k, got, want) } } if n == 2 { h := test.xs[1] - test.xs[0] want := (test.ys[1] - test.ys[0]) / h for i := 0; i < 2; i++ { got := fb.PredictDerivative(test.xs[i]) if !scalar.EqualWithinAbs(got, want, tol) { t.Errorf("Mismatch in approximated derivative for node %d in 2-node test case %d: got %v, want %g", i, k, got, want) } } dx := h / (nPts + 1) for i := 1; i < nPts; i++ { x := test.xs[0] + float64(i)*dx got := fb.PredictDerivative(x) if !scalar.EqualWithinAbs(got, want, tol) { t.Errorf("Mismatch in interpolated derivative for x == %g in 2-node test case %d: got %v, want %g", x, k, got, want) } } } else { m := n - 1 for i := 1; i < m; i++ { got := fb.PredictDerivative(test.xs[i]) slope := (test.ys[i+1] - test.ys[i]) / (test.xs[i+1] - test.xs[i]) prevSlope := (test.ys[i] - test.ys[i-1]) / (test.xs[i] - test.xs[i-1]) if slope*prevSlope > 0 { if got == 0 { t.Errorf("Approximated derivative is zero for node %d in test case %d: %g", i, k, got) } else if math.Signbit(slope) != math.Signbit(got) { t.Errorf("Approximated derivative has wrong sign for node %d in test case %d: got %g, want %g", i, k, math.Copysign(1, got), math.Copysign(1, slope)) } } else { if got != 0 { t.Errorf("Approximated derivative is not zero for node %d in test case %d: %g", i, k, got) } } } for i := 0; i < m; i++ { yL := test.ys[i] yR := test.ys[i+1] xL := test.xs[i] dx := (test.xs[i+1] - xL) / (nPts + 1) if yL == yR { for j := 1; j < nPts; j++ { x := xL + float64(j)*dx got := fb.Predict(x) if got != yL { t.Errorf("Mismatch in interpolated value for x == %g in test case %d: got %v, want %g", x, k, got, yL) } got = fb.PredictDerivative(x) if got != 0 { t.Errorf("Interpolated derivative not zero for x == %g in test case %d: got %v", x, k, got) } } } else { minY := math.Min(yL, yR) maxY := math.Max(yL, yR) for j := 1; j < nPts; j++ { x := xL + float64(j)*dx got := fb.Predict(x) if got < minY || got > maxY { t.Errorf("Interpolated value out of [%g, %g] bounds for x == %g in test case %d: got %v", minY, maxY, x, k, got) } got = fb.PredictDerivative(x) dy := yR - yL if got*dy < 0 { t.Errorf("Interpolated derivative has wrong sign for x == %g in test case %d: want %g, got %g", x, k, math.Copysign(1, dy), math.Copysign(1, got)) } } } } } } } func TestFritschButlandErrors(t *testing.T) { t.Parallel() for _, test := range []struct { xs, ys []float64 }{ { xs: []float64{0}, ys: []float64{0}, }, { xs: []float64{0, 1, 2}, ys: []float64{0, 1}}, { xs: []float64{0, 0, 1}, ys: []float64{0, 0, 0}, }, { xs: []float64{0, 1, 0}, ys: []float64{0, 0, 0}, }, } { var fb FritschButland if !panics(func() { _ = fb.Fit(test.xs, test.ys) }) { t.Errorf("expected panic for xs: %v and ys: %v", test.xs, test.ys) } } } func TestPiecewiseCubicFitWithSecondDerivatives(t *testing.T) { t.Parallel() const tol = 1e-14 xs := []float64{-2, 0, 3} ys := []float64{2.5, 1, 2.5} d2ydx2s := []float64{1, 2, 3} var pc PiecewiseCubic pc.fitWithSecondDerivatives(xs, ys, d2ydx2s) m := len(xs) - 1 if pc.lastY != ys[m] { t.Errorf("Mismatch in lastY: got %v, want %g", pc.lastY, ys[m]) } if !floats.Equal(pc.xs, xs) { t.Errorf("Mismatch in xs: got %v, want %v", pc.xs, xs) } for i := 0; i < len(xs); i++ { yHat := pc.Predict(xs[i]) if math.Abs(yHat-ys[i]) > tol { t.Errorf("Mismatch in predicted Y[%d]: got %v, want %g", i, yHat, ys[i]) } var d2ydx2Hat float64 if i < m { d2ydx2Hat = 2 * pc.coeffs.At(i, 2) } else { d2ydx2Hat = 2*pc.coeffs.At(m-1, 2) + 6*pc.coeffs.At(m-1, 3)*(xs[m]-xs[m-1]) } if math.Abs(d2ydx2Hat-d2ydx2s[i]) > tol { t.Errorf("Mismatch in predicted d2Y/dX2[%d]: got %v, want %g", i, d2ydx2Hat, d2ydx2s[i]) } } // Test pc.lastDyDx without copying verbatim the calculation from the tested method: lastDyDx := pc.PredictDerivative(xs[m] - tol/1000) if math.Abs(lastDyDx-pc.lastDyDx) > tol { t.Errorf("Mismatch in lastDxDy: got %v, want %g", pc.lastDyDx, lastDyDx) } } func TestPiecewiseCubicFitWithSecondDerivativesErrors(t *testing.T) { t.Parallel() for _, test := range []struct { xs, ys, d2ydx2s []float64 }{ { xs: []float64{0, 1, 2}, ys: []float64{10, 20}, d2ydx2s: []float64{0, 0, 0}, }, { xs: []float64{0, 1, 1}, ys: []float64{10, 20, 30}, d2ydx2s: []float64{0, 0, 0, 0}, }, { xs: []float64{0}, ys: []float64{0}, d2ydx2s: []float64{0}, }, { xs: []float64{0, 1, 1}, ys: []float64{10, 20, 10}, d2ydx2s: []float64{0, 0, 0}, }, } { var pc PiecewiseCubic if !panics(func() { pc.fitWithSecondDerivatives(test.xs, test.ys, test.d2ydx2s) }) { t.Errorf("expected panic for xs: %v, ys: %v and d2ydx2s: %v", test.xs, test.ys, test.d2ydx2s) } } } func TestMakeCubicSplineSecondDerivativeEquations(t *testing.T) { t.Parallel() const tol = 1e-15 xs := []float64{-1, 0, 2} ys := []float64{2, 0, 2} n := len(xs) a := mat.NewTridiag(n, nil, nil, nil) b := mat.NewVecDense(n, nil) makeCubicSplineSecondDerivativeEquations(a, b, xs, ys) if b.Len() != n { t.Errorf("Mismatch in b size: got %v, want %d", b.Len(), n) } r, c := a.Dims() if r != n || c != n { t.Errorf("Mismatch in A size: got %d x %d, want %d x %d", r, c, n, n) } expectedB := mat.NewVecDense(3, []float64{0, 3, 0}) var diffB mat.VecDense diffB.SubVec(b, expectedB) if diffB.Norm(math.Inf(1)) > tol { t.Errorf("Mismatch in b values: got %v, want %v", b, expectedB) } expectedA := mat.NewDense(3, 3, []float64{0, 0, 0, 1 / 6., 1, 2 / 6., 0, 0, 0}) var diffA mat.Dense diffA.Sub(a, expectedA) if diffA.Norm(math.Inf(1)) > tol { t.Errorf("Mismatch in A values: got %v, want %v", a, expectedA) } } func TestNaturalCubicFit(t *testing.T) { t.Parallel() xs := []float64{-1, 0, 2, 3.5} ys := []float64{2, 0, 2, 1.5} var nc NaturalCubic err := nc.Fit(xs, ys) if err != nil { t.Errorf("Error when fitting NaturalCubic: %v", err) } testXs := []float64{-1, -0.99, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.49, 3.5} // From scipy.interpolate.CubicSpline: want := []float64{ 2.0, 1.9737725526315788, 0.7664473684210527, 0.0, 0.027960526315789477, 0.6184210526315789, 1.3996710526315788, 2.0, 2.1403508771929824, 1.9122807017543857, 1.508859403508772, 1.5} for i := 0; i < len(testXs); i++ { got := nc.Predict(testXs[i]) if math.Abs(got-want[i]) > 1e-14 { t.Errorf("Mismatch in predicted Y value for x = %g: got %v, want %g", testXs[i], got, want[i]) } got = nc.PredictDerivative(testXs[i]) want := discrDerivPredict(&nc, xs[0], xs[len(xs)-1], testXs[i], 1e-9) if math.Abs(got-want) > 1e-6 { t.Errorf("Mismatch in predicted dY/dX value for x = %g: got %v, want %g", testXs[i], got, want) } } } func TestClampedCubicFit(t *testing.T) { t.Parallel() xs := []float64{-1, 0, 2, 3.5} ys := []float64{2, 0, 2, 1.5} var cc ClampedCubic err := cc.Fit(xs, ys) if err != nil { t.Errorf("Error when fitting ClampedCubic: %v", err) } testXs := []float64{-1, -0.99, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.49, 3.5} // From scipy.interpolate.CubicSpline: want := []float64{ 2.0, 1.999564111111111, 1.2021604938271606, 0.0, -0.20833333333333343, 0.41975308641975284, 1.337962962962962, 2.0, 2.026748971193416, 1.7078189300411522, 1.5001129711934151, 1.4999999999999996, } for i := 0; i < len(testXs); i++ { got := cc.Predict(testXs[i]) if math.Abs(got-want[i]) > 1e-14 { t.Errorf("Mismatch in predicted Y value for x = %g: got %v, want %g", testXs[i], got, want[i]) } got = cc.PredictDerivative(testXs[i]) want := discrDerivPredict(&cc, xs[0], xs[len(xs)-1], testXs[i], 1e-9) if math.Abs(got-want) > 1e-6 { t.Errorf("Mismatch in predicted dY/dX value for x = %g: got %v, want %g", testXs[i], got, want) } } } func TestNotAKnotCubicFit(t *testing.T) { t.Parallel() xs := []float64{-1, 0, 2, 3.5} ys := []float64{2, 0, 2, 1.5} var nak NotAKnotCubic err := nak.Fit(xs, ys) if err != nil { t.Errorf("Error when fitting NotAKnotCubic: %v", err) } testXs := []float64{-1, -0.99, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.49, 3.5} // From scipy.interpolate.CubicSpline: want := []float64{ 2.0, 1.961016095238095, 0.5582010582010581, 0.0, 0.09523809523809526, 0.6137566137566137, 1.3253968253968258, 2.0, 2.407407407407407, 2.3174603174603177, 1.5249675026455023, 1.5000000000000004, } for i := 0; i < len(testXs); i++ { got := nak.Predict(testXs[i]) if math.Abs(got-want[i]) > 1e-14 { t.Errorf("Mismatch in predicted Y value for x = %g: got %v, want %g", testXs[i], got, want[i]) } got = nak.PredictDerivative(testXs[i]) want := discrDerivPredict(&nak, xs[0], xs[len(xs)-1], testXs[i], 1e-9) if math.Abs(got-want) > 1e-6 { t.Errorf("Mismatch in predicted dY/dX value for x = %g: got %v, want %g", testXs[i], got, want) } } } golang-gonum-v1-gonum-0.14.0/interp/doc.go000066400000000000000000000007231450372207100202350ustar00rootroot00000000000000// Copyright ©2020 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 interp implements 1-dimensional algorithms for interpolating values. // Outside of the interpolation interval determined by the interpolated data, // the returned value is undefined (but we do our best to return something // reasonable). package interp // import "gonum.org/v1/gonum/interp" golang-gonum-v1-gonum-0.14.0/interp/interp.go000066400000000000000000000113151450372207100207700ustar00rootroot00000000000000// Copyright ©2020 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 interp import "sort" const ( differentLengths = "interp: input slices have different lengths" tooFewPoints = "interp: too few points for interpolation" xsNotStrictlyIncreasing = "interp: xs values not strictly increasing" ) // Predictor predicts the value of a function. It handles both // interpolation and extrapolation. type Predictor interface { // Predict returns the predicted value at x. Predict(x float64) float64 } // Fitter fits a predictor to data. type Fitter interface { // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). Returns an error if fitting fails. Fit(xs, ys []float64) error } // FittablePredictor is a Predictor which can fit itself to data. type FittablePredictor interface { Fitter Predictor } // DerivativePredictor predicts both the value and the derivative of // a function. It handles both interpolation and extrapolation. type DerivativePredictor interface { Predictor // PredictDerivative returns the predicted derivative at x. PredictDerivative(x float64) float64 } // Constant predicts a constant value. type Constant float64 // Predict returns the predicted value at x. func (c Constant) Predict(x float64) float64 { return float64(c) } // Function predicts by evaluating itself. type Function func(float64) float64 // Predict returns the predicted value at x by evaluating fn(x). func (fn Function) Predict(x float64) float64 { return fn(x) } // PiecewiseLinear is a piecewise linear 1-dimensional interpolator. type PiecewiseLinear struct { // Interpolated X values. xs []float64 // Interpolated Y data values, same len as ys. ys []float64 // Slopes of Y between neighbouring X values. len(slopes) + 1 == len(xs) == len(ys). slopes []float64 } // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). Always returns nil. func (pl *PiecewiseLinear) Fit(xs, ys []float64) error { n := len(xs) if len(ys) != n { panic(differentLengths) } if n < 2 { panic(tooFewPoints) } pl.slopes = calculateSlopes(xs, ys) pl.xs = make([]float64, n) pl.ys = make([]float64, n) copy(pl.xs, xs) copy(pl.ys, ys) return nil } // Predict returns the interpolation value at x. func (pl PiecewiseLinear) Predict(x float64) float64 { i := findSegment(pl.xs, x) if i < 0 { return pl.ys[0] } xI := pl.xs[i] if x == xI { return pl.ys[i] } n := len(pl.xs) if i == n-1 { return pl.ys[n-1] } return pl.ys[i] + pl.slopes[i]*(x-xI) } // PiecewiseConstant is a left-continuous, piecewise constant // 1-dimensional interpolator. type PiecewiseConstant struct { // Interpolated X values. xs []float64 // Interpolated Y data values, same len as ys. ys []float64 } // Fit fits a predictor to (X, Y) value pairs provided as two slices. // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). Always returns nil. func (pc *PiecewiseConstant) Fit(xs, ys []float64) error { n := len(xs) if len(ys) != n { panic(differentLengths) } if n < 2 { panic(tooFewPoints) } for i := 1; i < n; i++ { if xs[i] <= xs[i-1] { panic(xsNotStrictlyIncreasing) } } pc.xs = make([]float64, n) pc.ys = make([]float64, n) copy(pc.xs, xs) copy(pc.ys, ys) return nil } // Predict returns the interpolation value at x. func (pc PiecewiseConstant) Predict(x float64) float64 { i := findSegment(pc.xs, x) if i < 0 { return pc.ys[0] } if x == pc.xs[i] { return pc.ys[i] } n := len(pc.xs) if i == n-1 { return pc.ys[n-1] } return pc.ys[i+1] } // findSegment returns 0 <= i < len(xs) such that xs[i] <= x < xs[i + 1], where xs[len(xs)] // is assumed to be +Inf. If no such i is found, it returns -1. It assumes that len(xs) >= 2 // without checking. func findSegment(xs []float64, x float64) int { return sort.Search(len(xs), func(i int) bool { return xs[i] > x }) - 1 } // calculateSlopes calculates slopes (ys[i+1] - ys[i]) / (xs[i+1] - xs[i]). // It panics if len(xs) < 2, elements of xs are not strictly increasing // or len(xs) != len(ys). func calculateSlopes(xs, ys []float64) []float64 { n := len(xs) if n < 2 { panic(tooFewPoints) } if len(ys) != n { panic(differentLengths) } m := n - 1 slopes := make([]float64, m) prevX := xs[0] prevY := ys[0] for i := 0; i < m; i++ { x := xs[i+1] y := ys[i+1] dx := x - prevX if dx <= 0 { panic(xsNotStrictlyIncreasing) } slopes[i] = (y - prevY) / dx prevX = x prevY = y } return slopes } golang-gonum-v1-gonum-0.14.0/interp/interp_example_test.go000066400000000000000000000067661450372207100235600ustar00rootroot00000000000000// Copyright ©2020 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 interp_test import ( "fmt" "math" "os" "text/tabwriter" "gonum.org/v1/gonum/interp" ) func ExamplePredictor() { // An example of fitting different interpolation // algorithms to (X, Y) data with widely varying slope. // // Cubic interpolators have to balance the smoothness // of the generated curve with suppressing ugly wiggles // (compare the output of AkimaSpline with that of // FritschButland). xs := []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} ys := []float64{0, 0.001, 0.002, 0.1, 1, 2, 2.5, -10, -10.01, 2.49, 2.53, 2.55} var pc interp.PiecewiseConstant var pl interp.PiecewiseLinear var as interp.AkimaSpline var fb interp.FritschButland predictors := []interp.FittablePredictor{&pc, &pl, &as, &fb} for i, p := range predictors { err := p.Fit(xs, ys) if err != nil { panic(fmt.Sprintf("Error fitting %d-th predictor: %v", i, err)) } } n := len(xs) dx := 0.25 nPts := int(math.Round(float64(n-1)/dx)) + 1 w := tabwriter.NewWriter(os.Stdout, 8, 0, 1, ' ', tabwriter.AlignRight) fmt.Fprintln(w, "x\tPC\tPL\tAS\tFB\t") for i := 0; i < nPts; i++ { x := xs[0] + float64(i)*dx fmt.Fprintf(w, "%.2f", x) for _, predictor := range predictors { y := predictor.Predict(x) fmt.Fprintf(w, "\t%.2f", y) } fmt.Fprintln(w, "\t") } fmt.Fprintln(w) w.Flush() // Output: // x PC PL AS FB // 0.00 0.00 0.00 0.00 0.00 // 0.25 0.00 0.00 0.00 0.00 // 0.50 0.00 0.00 0.00 0.00 // 0.75 0.00 0.00 0.00 0.00 // 1.00 0.00 0.00 0.00 0.00 // 1.25 0.00 0.00 0.00 0.00 // 1.50 0.00 0.00 0.00 0.00 // 1.75 0.00 0.00 0.00 0.00 // 2.00 0.00 0.00 0.00 0.00 // 2.25 0.10 0.03 -0.01 0.01 // 2.50 0.10 0.05 -0.01 0.03 // 2.75 0.10 0.08 0.02 0.06 // 3.00 0.10 0.10 0.10 0.10 // 3.25 1.00 0.33 0.26 0.22 // 3.50 1.00 0.55 0.49 0.45 // 3.75 1.00 0.78 0.75 0.73 // 4.00 1.00 1.00 1.00 1.00 // 4.25 2.00 1.25 1.24 1.26 // 4.50 2.00 1.50 1.50 1.54 // 4.75 2.00 1.75 1.75 1.79 // 5.00 2.00 2.00 2.00 2.00 // 5.25 2.50 2.12 2.22 2.17 // 5.50 2.50 2.25 2.37 2.33 // 5.75 2.50 2.38 2.47 2.45 // 6.00 2.50 2.50 2.50 2.50 // 6.25 -10.00 -0.62 0.83 0.55 // 6.50 -10.00 -3.75 -2.98 -3.75 // 6.75 -10.00 -6.88 -7.18 -8.04 // 7.00 -10.00 -10.00 -10.00 -10.00 // 7.25 -10.01 -10.00 -11.16 -10.00 // 7.50 -10.01 -10.00 -11.55 -10.01 // 7.75 -10.01 -10.01 -11.18 -10.01 // 8.00 -10.01 -10.01 -10.01 -10.01 // 8.25 2.49 -6.88 -7.18 -8.06 // 8.50 2.49 -3.76 -2.99 -3.77 // 8.75 2.49 -0.63 0.82 0.53 // 9.00 2.49 2.49 2.49 2.49 // 9.25 2.53 2.50 2.50 2.51 // 9.50 2.53 2.51 2.51 2.52 // 9.75 2.53 2.52 2.52 2.52 // 10.00 2.53 2.53 2.53 2.53 // 10.25 2.55 2.53 2.54 2.54 // 10.50 2.55 2.54 2.54 2.54 // 10.75 2.55 2.54 2.55 2.55 // 11.00 2.55 2.55 2.55 2.55 } golang-gonum-v1-gonum-0.14.0/interp/interp_test.go000066400000000000000000000146721450372207100220400ustar00rootroot00000000000000// Copyright ©2020 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 interp import ( "math" "testing" "gonum.org/v1/gonum/floats" ) func TestConstant(t *testing.T) { t.Parallel() const value = 42.0 c := Constant(value) xs := []float64{math.Inf(-1), -11, 0.4, 1e9, math.Inf(1)} for _, x := range xs { y := c.Predict(x) if y != value { t.Errorf("unexpected Predict(%g) value: got: %g want: %g", x, y, value) } } } func TestFunction(t *testing.T) { fn := func(x float64) float64 { return math.Exp(x) } predictor := Function(fn) xs := []float64{-100, -1, 0, 0.5, 15} for _, x := range xs { want := fn(x) got := predictor.Predict(x) if got != want { t.Errorf("unexpected Predict(%g) value: got: %g want: %g", x, got, want) } } } func TestFindSegment(t *testing.T) { t.Parallel() xs := []float64{0, 1, 2} testXs := []float64{-0.6, 0, 0.3, 1, 1.5, 2, 2.8} expectedIs := []int{-1, 0, 0, 1, 1, 2, 2} for k, x := range testXs { i := findSegment(xs, x) if i != expectedIs[k] { t.Errorf("unexpected value of findSegment(xs, %g): got %d want: %d", x, i, expectedIs[k]) } } } func BenchmarkFindSegment(b *testing.B) { xs := []float64{0, 1.5, 3, 4.5, 6, 7.5, 9, 12, 13.5, 16.5} for i := 0; i < b.N; i++ { findSegment(xs, 0) findSegment(xs, 16.5) findSegment(xs, -1) findSegment(xs, 8.25) findSegment(xs, 4.125) findSegment(xs, 13.6) findSegment(xs, 23.6) findSegment(xs, 13.5) findSegment(xs, 6) findSegment(xs, 4.5) } } // testPiecewiseInterpolatorCreation tests common functionality in creating piecewise interpolators. func testPiecewiseInterpolatorCreation(t *testing.T, fp FittablePredictor) { type errorParams struct { xs []float64 ys []float64 } errorParamSets := []errorParams{ {[]float64{0, 1, 2}, []float64{-0.5, 1.5}}, {[]float64{0.3}, []float64{0}}, {[]float64{0.3, 0.3}, []float64{0, 0}}, {[]float64{0.3, -0.3}, []float64{0, 0}}, } for _, params := range errorParamSets { if !panics(func() { _ = fp.Fit(params.xs, params.ys) }) { t.Errorf("expected panic for xs: %v and ys: %v", params.xs, params.ys) } } } func TestPiecewiseLinearFit(t *testing.T) { t.Parallel() testPiecewiseInterpolatorCreation(t, &PiecewiseLinear{}) } // testInterpolatorPredict tests evaluation of a interpolator. func testInterpolatorPredict(t *testing.T, p Predictor, xs []float64, expectedYs []float64, tol float64) { for i, x := range xs { y := p.Predict(x) yErr := math.Abs(y - expectedYs[i]) if yErr > tol { if tol == 0 { t.Errorf("unexpected Predict(%g) value: got: %g want: %g", x, y, expectedYs[i]) } else { t.Errorf("unexpected Predict(%g) value: got: %g want: %g with tolerance: %g", x, y, expectedYs[i], tol) } } } } func TestPiecewiseLinearPredict(t *testing.T) { t.Parallel() xs := []float64{0, 1, 2} ys := []float64{-0.5, 1.5, 1} var pl PiecewiseLinear err := pl.Fit(xs, ys) if err != nil { t.Errorf("Fit error: %s", err.Error()) } testInterpolatorPredict(t, pl, xs, ys, 0) testInterpolatorPredict(t, pl, []float64{-0.4, 2.6}, []float64{-0.5, 1}, 0) testInterpolatorPredict(t, pl, []float64{0.1, 0.5, 0.8, 1.2}, []float64{-0.3, 0.5, 1.1, 1.4}, 1e-15) } func BenchmarkNewPiecewiseLinear(b *testing.B) { xs := []float64{0, 1.5, 3, 4.5, 6, 7.5, 9, 12, 13.5, 16.5} ys := []float64{0, 1, 2, 2.5, 2, 1.5, 4, 10, -2, 2} var pl PiecewiseLinear for i := 0; i < b.N; i++ { _ = pl.Fit(xs, ys) } } func BenchmarkPiecewiseLinearPredict(b *testing.B) { xs := []float64{0, 1.5, 3, 4.5, 6, 7.5, 9, 12, 13.5, 16.5} ys := []float64{0, 1, 2, 2.5, 2, 1.5, 4, 10, -2, 2} var pl PiecewiseLinear _ = pl.Fit(xs, ys) for i := 0; i < b.N; i++ { pl.Predict(0) pl.Predict(16.5) pl.Predict(-2) pl.Predict(4) pl.Predict(7.32) pl.Predict(9.0001) pl.Predict(1.4) pl.Predict(1.6) pl.Predict(30) pl.Predict(13.5) pl.Predict(4.5) } } func TestNewPiecewiseConstant(t *testing.T) { var pc PiecewiseConstant testPiecewiseInterpolatorCreation(t, &pc) } func benchmarkPiecewiseConstantPredict(b *testing.B) { xs := []float64{0, 1.5, 3, 4.5, 6, 7.5, 9, 12, 13.5, 16.5} ys := []float64{0, 1, 2, 2.5, 2, 1.5, 4, 10, -2, 2} var pc PiecewiseConstant _ = pc.Fit(xs, ys) for i := 0; i < b.N; i++ { pc.Predict(0) pc.Predict(16.5) pc.Predict(4) pc.Predict(7.32) pc.Predict(9.0001) pc.Predict(1.4) pc.Predict(1.6) pc.Predict(13.5) pc.Predict(4.5) } } func BenchmarkPiecewiseConstantPredict(b *testing.B) { benchmarkPiecewiseConstantPredict(b) } func TestPiecewiseConstantPredict(t *testing.T) { t.Parallel() xs := []float64{0, 1, 2} ys := []float64{-0.5, 1.5, 1} var pc PiecewiseConstant err := pc.Fit(xs, ys) if err != nil { t.Errorf("Fit error: %s", err.Error()) } testInterpolatorPredict(t, pc, xs, ys, 0) testXs := []float64{-0.9, 0.1, 0.5, 0.8, 1.2, 3.1} leftYs := []float64{-0.5, 1.5, 1.5, 1.5, 1, 1} testInterpolatorPredict(t, pc, testXs, leftYs, 0) } func TestCalculateSlopesErrors(t *testing.T) { t.Parallel() for _, test := range []struct { xs, ys []float64 }{ { xs: []float64{0}, ys: []float64{0}, }, { xs: []float64{0, 1, 2}, ys: []float64{0, 1}}, { xs: []float64{0, 0, 1}, ys: []float64{0, 0, 0}, }, { xs: []float64{0, 1, 0}, ys: []float64{0, 0, 0}, }, } { if !panics(func() { calculateSlopes(test.xs, test.ys) }) { t.Errorf("expected panic for xs: %v and ys: %v", test.xs, test.ys) } } } func TestCalculateSlopes(t *testing.T) { t.Parallel() for i, test := range []struct { xs, ys, want []float64 }{ { xs: []float64{0, 2, 3, 5}, ys: []float64{0, 1, 1, -1}, want: []float64{0.5, 0, -1}, }, { xs: []float64{10, 20}, ys: []float64{50, 100}, want: []float64{5}, }, } { got := calculateSlopes(test.xs, test.ys) if !floats.EqualApprox(got, test.want, 1e-14) { t.Errorf("Mismatch in calculated slopes in case %d: got %v, want %v", i, got, test.want) } } } func applyFunc(xs []float64, f func(x float64) float64) []float64 { ys := make([]float64, len(xs)) for i, x := range xs { ys[i] = f(x) } return ys } func panics(fun func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() fun() return } func discrDerivPredict(p Predictor, x0, x1, x, h float64) float64 { if x <= x0+h { return (p.Predict(x+h) - p.Predict(x)) / h } else if x >= x1-h { return (p.Predict(x) - p.Predict(x-h)) / h } else { return (p.Predict(x+h) - p.Predict(x-h)) / (2 * h) } } golang-gonum-v1-gonum-0.14.0/lapack/000077500000000000000000000000001450372207100170715ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/lapack/.gitignore000066400000000000000000000000001450372207100210470ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/lapack/README.md000066400000000000000000000015311450372207100203500ustar00rootroot00000000000000Gonum LAPACK ====== [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/lapack)](https://pkg.go.dev/gonum.org/v1/gonum/lapack) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/lapack?status.svg)](https://godocs.io/gonum.org/v1/gonum/lapack) A collection of packages to provide LAPACK functionality for the Go programming language (http://golang.org). This provides a partial implementation in native go and a wrapper using cgo to a c-based implementation. ## Installation ``` go get gonum.org/v1/gonum/lapack/... ``` ## Packages ### lapack Defines the LAPACK API based on http://www.netlib.org/lapack/lapacke.html ### lapack/gonum Go implementation of the LAPACK API (incomplete, implements the `float64` API). ### lapack/lapack64 Wrappers for an implementation of the double (i.e., `float64`) precision real parts of the LAPACK API. golang-gonum-v1-gonum-0.14.0/lapack/doc.go000066400000000000000000000004501450372207100201640ustar00rootroot00000000000000// 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 lapack provides interfaces for the LAPACK linear algebra standard. package lapack // import "gonum.org/v1/gonum/lapack" golang-gonum-v1-gonum-0.14.0/lapack/gonum/000077500000000000000000000000001450372207100202165ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/lapack/gonum/bench_test.go000066400000000000000000000010371450372207100226640ustar00rootroot00000000000000// Copyright ©2016 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 ( "testing" "gonum.org/v1/gonum/lapack/testlapack" ) func BenchmarkDgeev(b *testing.B) { testlapack.DgeevBenchmark(b, impl) } func BenchmarkDlangb(b *testing.B) { testlapack.DlangbBenchmark(b, impl) } func BenchmarkDlantb(b *testing.B) { testlapack.DlantbBenchmark(b, impl) } func BenchmarkDlaqr5(b *testing.B) { testlapack.Dlaqr5Benchmark(b, impl) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dbdsqr.go000066400000000000000000000331361450372207100220320ustar00rootroot00000000000000// 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dbdsqr performs a singular value decomposition of a real n×n bidiagonal matrix. // // The SVD of the bidiagonal matrix B is // // B = Q * S * Pᵀ // // where S is a diagonal matrix of singular values, Q is an orthogonal matrix of // left singular vectors, and P is an orthogonal matrix of right singular vectors. // // Q and P are only computed if requested. If left singular vectors are requested, // this routine returns U * Q instead of Q, and if right singular vectors are // requested Pᵀ * VT is returned instead of Pᵀ. // // Frequently Dbdsqr is used in conjunction with Dgebrd which reduces a general // matrix A into bidiagonal form. In this case, the SVD of A is // // A = (U * Q) * S * (Pᵀ * VT) // // This routine may also compute Qᵀ * C. // // d and e contain the elements of the bidiagonal matrix b. d must have length at // least n, and e must have length at least n-1. Dbdsqr will panic if there is // insufficient length. On exit, D contains the singular values of B in decreasing // order. // // VT is a matrix of size n×ncvt whose elements are stored in vt. The elements // of vt are modified to contain Pᵀ * VT on exit. VT is not used if ncvt == 0. // // U is a matrix of size nru×n whose elements are stored in u. The elements // of u are modified to contain U * Q on exit. U is not used if nru == 0. // // C is a matrix of size n×ncc whose elements are stored in c. The elements // of c are modified to contain Qᵀ * C on exit. C is not used if ncc == 0. // // work contains temporary storage and must have length at least 4*(n-1). Dbdsqr // will panic if there is insufficient working memory. // // Dbdsqr returns whether the decomposition was successful. // // Dbdsqr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dbdsqr(uplo blas.Uplo, n, ncvt, nru, ncc int, d, e, vt []float64, ldvt int, u []float64, ldu int, c []float64, ldc int, work []float64) (ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case ncvt < 0: panic(ncvtLT0) case nru < 0: panic(nruLT0) case ncc < 0: panic(nccLT0) case ldvt < max(1, ncvt): panic(badLdVT) case (ldu < max(1, n) && nru > 0) || (ldu < 1 && nru == 0): panic(badLdU) case ldc < max(1, ncc): panic(badLdC) } // Quick return if possible. if n == 0 { return true } if len(vt) < (n-1)*ldvt+ncvt && ncvt != 0 { panic(shortVT) } if len(u) < (nru-1)*ldu+n && nru != 0 { panic(shortU) } if len(c) < (n-1)*ldc+ncc && ncc != 0 { panic(shortC) } if len(d) < n { panic(shortD) } if len(e) < n-1 { panic(shortE) } if len(work) < 4*(n-1) { panic(shortWork) } var info int bi := blas64.Implementation() const maxIter = 6 if n != 1 { // If the singular vectors do not need to be computed, use qd algorithm. if !(ncvt > 0 || nru > 0 || ncc > 0) { info = impl.Dlasq1(n, d, e, work) // If info is 2 dqds didn't finish, and so try to. if info != 2 { return info == 0 } } nm1 := n - 1 nm12 := nm1 + nm1 nm13 := nm12 + nm1 idir := 0 eps := dlamchE unfl := dlamchS lower := uplo == blas.Lower var cs, sn, r float64 if lower { for i := 0; i < n-1; i++ { cs, sn, r = impl.Dlartg(d[i], e[i]) d[i] = r e[i] = sn * d[i+1] d[i+1] *= cs work[i] = cs work[nm1+i] = sn } if nru > 0 { impl.Dlasr(blas.Right, lapack.Variable, lapack.Forward, nru, n, work, work[n-1:], u, ldu) } if ncc > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Forward, n, ncc, work, work[n-1:], c, ldc) } } // Compute singular values to a relative accuracy of tol. If tol is negative // the values will be computed to an absolute accuracy of math.Abs(tol) * norm(b) tolmul := math.Max(10, math.Min(100, math.Pow(eps, -1.0/8))) tol := tolmul * eps var smax float64 for i := 0; i < n; i++ { smax = math.Max(smax, math.Abs(d[i])) } for i := 0; i < n-1; i++ { smax = math.Max(smax, math.Abs(e[i])) } var smin float64 var thresh float64 if tol >= 0 { sminoa := math.Abs(d[0]) if sminoa != 0 { mu := sminoa for i := 1; i < n; i++ { mu = math.Abs(d[i]) * (mu / (mu + math.Abs(e[i-1]))) sminoa = math.Min(sminoa, mu) if sminoa == 0 { break } } } sminoa = sminoa / math.Sqrt(float64(n)) thresh = math.Max(tol*sminoa, float64(maxIter*n*n)*unfl) } else { thresh = math.Max(math.Abs(tol)*smax, float64(maxIter*n*n)*unfl) } // Prepare for the main iteration loop for the singular values. maxIt := maxIter * n * n iter := 0 oldl2 := -1 oldm := -1 // m points to the last element of unconverged part of matrix. m := n Outer: for m > 1 { if iter > maxIt { info = 0 for i := 0; i < n-1; i++ { if e[i] != 0 { info++ } } return info == 0 } // Find diagonal block of matrix to work on. if tol < 0 && math.Abs(d[m-1]) <= thresh { d[m-1] = 0 } smax = math.Abs(d[m-1]) var l2 int var broke bool for l3 := 0; l3 < m-1; l3++ { l2 = m - l3 - 2 abss := math.Abs(d[l2]) abse := math.Abs(e[l2]) if tol < 0 && abss <= thresh { d[l2] = 0 } if abse <= thresh { broke = true break } smax = math.Max(math.Max(smax, abss), abse) } if broke { e[l2] = 0 if l2 == m-2 { // Convergence of bottom singular value, return to top. m-- continue } l2++ } else { l2 = 0 } // e[ll] through e[m-2] are nonzero, e[ll-1] is zero if l2 == m-2 { // Handle 2×2 block separately. var sinr, cosr, sinl, cosl float64 d[m-1], d[m-2], sinr, cosr, sinl, cosl = impl.Dlasv2(d[m-2], e[m-2], d[m-1]) e[m-2] = 0 if ncvt > 0 { bi.Drot(ncvt, vt[(m-2)*ldvt:], 1, vt[(m-1)*ldvt:], 1, cosr, sinr) } if nru > 0 { bi.Drot(nru, u[m-2:], ldu, u[m-1:], ldu, cosl, sinl) } if ncc > 0 { bi.Drot(ncc, c[(m-2)*ldc:], 1, c[(m-1)*ldc:], 1, cosl, sinl) } m -= 2 continue } // If working on a new submatrix, choose shift direction from larger end // diagonal element toward smaller. if l2 > oldm-1 || m-1 < oldl2 { if math.Abs(d[l2]) >= math.Abs(d[m-1]) { idir = 1 } else { idir = 2 } } // Apply convergence tests. // TODO(btracey): There is a lot of similar looking code here. See // if there is a better way to de-duplicate. if idir == 1 { // Run convergence test in forward direction. // First apply standard test to bottom of matrix. if math.Abs(e[m-2]) <= math.Abs(tol)*math.Abs(d[m-1]) || (tol < 0 && math.Abs(e[m-2]) <= thresh) { e[m-2] = 0 continue } if tol >= 0 { // If relative accuracy desired, apply convergence criterion forward. mu := math.Abs(d[l2]) smin = mu for l3 := l2; l3 < m-1; l3++ { if math.Abs(e[l3]) <= tol*mu { e[l3] = 0 continue Outer } mu = math.Abs(d[l3+1]) * (mu / (mu + math.Abs(e[l3]))) smin = math.Min(smin, mu) } } } else { // Run convergence test in backward direction. // First apply standard test to top of matrix. if math.Abs(e[l2]) <= math.Abs(tol)*math.Abs(d[l2]) || (tol < 0 && math.Abs(e[l2]) <= thresh) { e[l2] = 0 continue } if tol >= 0 { // If relative accuracy desired, apply convergence criterion backward. mu := math.Abs(d[m-1]) smin = mu for l3 := m - 2; l3 >= l2; l3-- { if math.Abs(e[l3]) <= tol*mu { e[l3] = 0 continue Outer } mu = math.Abs(d[l3]) * (mu / (mu + math.Abs(e[l3]))) smin = math.Min(smin, mu) } } } oldl2 = l2 oldm = m // Compute shift. First, test if shifting would ruin relative accuracy, // and if so set the shift to zero. var shift float64 if tol >= 0 && float64(n)*tol*(smin/smax) <= math.Max(eps, (1.0/100)*tol) { shift = 0 } else { var sl2 float64 if idir == 1 { sl2 = math.Abs(d[l2]) shift, _ = impl.Dlas2(d[m-2], e[m-2], d[m-1]) } else { sl2 = math.Abs(d[m-1]) shift, _ = impl.Dlas2(d[l2], e[l2], d[l2+1]) } // Test if shift is negligible if sl2 > 0 { if (shift/sl2)*(shift/sl2) < eps { shift = 0 } } } iter += m - l2 + 1 // If no shift, do simplified QR iteration. if shift == 0 { if idir == 1 { cs := 1.0 oldcs := 1.0 var sn, r, oldsn float64 for i := l2; i < m-1; i++ { cs, sn, r = impl.Dlartg(d[i]*cs, e[i]) if i > l2 { e[i-1] = oldsn * r } oldcs, oldsn, d[i] = impl.Dlartg(oldcs*r, d[i+1]*sn) work[i-l2] = cs work[i-l2+nm1] = sn work[i-l2+nm12] = oldcs work[i-l2+nm13] = oldsn } h := d[m-1] * cs d[m-1] = h * oldcs e[m-2] = h * oldsn if ncvt > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Forward, m-l2, ncvt, work, work[n-1:], vt[l2*ldvt:], ldvt) } if nru > 0 { impl.Dlasr(blas.Right, lapack.Variable, lapack.Forward, nru, m-l2, work[nm12:], work[nm13:], u[l2:], ldu) } if ncc > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Forward, m-l2, ncc, work[nm12:], work[nm13:], c[l2*ldc:], ldc) } if math.Abs(e[m-2]) < thresh { e[m-2] = 0 } } else { cs := 1.0 oldcs := 1.0 var sn, r, oldsn float64 for i := m - 1; i >= l2+1; i-- { cs, sn, r = impl.Dlartg(d[i]*cs, e[i-1]) if i < m-1 { e[i] = oldsn * r } oldcs, oldsn, d[i] = impl.Dlartg(oldcs*r, d[i-1]*sn) work[i-l2-1] = cs work[i-l2+nm1-1] = -sn work[i-l2+nm12-1] = oldcs work[i-l2+nm13-1] = -oldsn } h := d[l2] * cs d[l2] = h * oldcs e[l2] = h * oldsn if ncvt > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Backward, m-l2, ncvt, work[nm12:], work[nm13:], vt[l2*ldvt:], ldvt) } if nru > 0 { impl.Dlasr(blas.Right, lapack.Variable, lapack.Backward, nru, m-l2, work, work[n-1:], u[l2:], ldu) } if ncc > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Backward, m-l2, ncc, work, work[n-1:], c[l2*ldc:], ldc) } if math.Abs(e[l2]) <= thresh { e[l2] = 0 } } } else { // Use nonzero shift. if idir == 1 { // Chase bulge from top to bottom. Save cosines and sines for // later singular vector updates. f := (math.Abs(d[l2]) - shift) * (math.Copysign(1, d[l2]) + shift/d[l2]) g := e[l2] var cosl, sinl float64 for i := l2; i < m-1; i++ { cosr, sinr, r := impl.Dlartg(f, g) if i > l2 { e[i-1] = r } f = cosr*d[i] + sinr*e[i] e[i] = cosr*e[i] - sinr*d[i] g = sinr * d[i+1] d[i+1] *= cosr cosl, sinl, r = impl.Dlartg(f, g) d[i] = r f = cosl*e[i] + sinl*d[i+1] d[i+1] = cosl*d[i+1] - sinl*e[i] if i < m-2 { g = sinl * e[i+1] e[i+1] = cosl * e[i+1] } work[i-l2] = cosr work[i-l2+nm1] = sinr work[i-l2+nm12] = cosl work[i-l2+nm13] = sinl } e[m-2] = f if ncvt > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Forward, m-l2, ncvt, work, work[n-1:], vt[l2*ldvt:], ldvt) } if nru > 0 { impl.Dlasr(blas.Right, lapack.Variable, lapack.Forward, nru, m-l2, work[nm12:], work[nm13:], u[l2:], ldu) } if ncc > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Forward, m-l2, ncc, work[nm12:], work[nm13:], c[l2*ldc:], ldc) } if math.Abs(e[m-2]) <= thresh { e[m-2] = 0 } } else { // Chase bulge from top to bottom. Save cosines and sines for // later singular vector updates. f := (math.Abs(d[m-1]) - shift) * (math.Copysign(1, d[m-1]) + shift/d[m-1]) g := e[m-2] for i := m - 1; i > l2; i-- { cosr, sinr, r := impl.Dlartg(f, g) if i < m-1 { e[i] = r } f = cosr*d[i] + sinr*e[i-1] e[i-1] = cosr*e[i-1] - sinr*d[i] g = sinr * d[i-1] d[i-1] *= cosr cosl, sinl, r := impl.Dlartg(f, g) d[i] = r f = cosl*e[i-1] + sinl*d[i-1] d[i-1] = cosl*d[i-1] - sinl*e[i-1] if i > l2+1 { g = sinl * e[i-2] e[i-2] *= cosl } work[i-l2-1] = cosr work[i-l2+nm1-1] = -sinr work[i-l2+nm12-1] = cosl work[i-l2+nm13-1] = -sinl } e[l2] = f if math.Abs(e[l2]) <= thresh { e[l2] = 0 } if ncvt > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Backward, m-l2, ncvt, work[nm12:], work[nm13:], vt[l2*ldvt:], ldvt) } if nru > 0 { impl.Dlasr(blas.Right, lapack.Variable, lapack.Backward, nru, m-l2, work, work[n-1:], u[l2:], ldu) } if ncc > 0 { impl.Dlasr(blas.Left, lapack.Variable, lapack.Backward, m-l2, ncc, work, work[n-1:], c[l2*ldc:], ldc) } } } } } // All singular values converged, make them positive. for i := 0; i < n; i++ { if d[i] < 0 { d[i] *= -1 if ncvt > 0 { bi.Dscal(ncvt, -1, vt[i*ldvt:], 1) } } } // Sort the singular values in decreasing order. for i := 0; i < n-1; i++ { isub := 0 smin := d[0] for j := 1; j < n-i; j++ { if d[j] <= smin { isub = j smin = d[j] } } if isub != n-i { // Swap singular values and vectors. d[isub] = d[n-i-1] d[n-i-1] = smin if ncvt > 0 { bi.Dswap(ncvt, vt[isub*ldvt:], 1, vt[(n-i-1)*ldvt:], 1) } if nru > 0 { bi.Dswap(nru, u[isub:], ldu, u[n-i-1:], ldu) } if ncc > 0 { bi.Dswap(ncc, c[isub*ldc:], 1, c[(n-i-1)*ldc:], 1) } } } info = 0 for i := 0; i < n-1; i++ { if e[i] != 0 { info++ } } return info == 0 } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgebak.go000066400000000000000000000043011450372207100217600ustar00rootroot00000000000000// Copyright ©2016 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/blas64" "gonum.org/v1/gonum/lapack" ) // Dgebak updates an n×m matrix V as // // V = P D V if side == lapack.EVRight, // V = P D^{-1} V if side == lapack.EVLeft, // // where P and D are n×n permutation and scaling matrices, respectively, // implicitly represented by job, scale, ilo and ihi as returned by Dgebal. // // Typically, columns of the matrix V contain the right or left (determined by // side) eigenvectors of the balanced matrix output by Dgebal, and Dgebak forms // the eigenvectors of the original matrix. // // Dgebak is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgebak(job lapack.BalanceJob, side lapack.EVSide, n, ilo, ihi int, scale []float64, m int, v []float64, ldv int) { switch { case job != lapack.BalanceNone && job != lapack.Permute && job != lapack.Scale && job != lapack.PermuteScale: panic(badBalanceJob) case side != lapack.EVLeft && side != lapack.EVRight: panic(badEVSide) case n < 0: panic(nLT0) case ilo < 0 || max(0, n-1) < ilo: panic(badIlo) case ihi < min(ilo, n-1) || n <= ihi: panic(badIhi) case m < 0: panic(mLT0) case ldv < max(1, m): panic(badLdV) } // Quick return if possible. if n == 0 || m == 0 { return } if len(scale) < n { panic(shortScale) } if len(v) < (n-1)*ldv+m { panic(shortV) } // Quick return if possible. if job == lapack.BalanceNone { return } bi := blas64.Implementation() if ilo != ihi && job != lapack.Permute { // Backward balance. if side == lapack.EVRight { for i := ilo; i <= ihi; i++ { bi.Dscal(m, scale[i], v[i*ldv:], 1) } } else { for i := ilo; i <= ihi; i++ { bi.Dscal(m, 1/scale[i], v[i*ldv:], 1) } } } if job == lapack.Scale { return } // Backward permutation. for i := ilo - 1; i >= 0; i-- { k := int(scale[i]) if k == i { continue } bi.Dswap(m, v[i*ldv:], 1, v[k*ldv:], 1) } for i := ihi + 1; i < n; i++ { k := int(scale[i]) if k == i { continue } bi.Dswap(m, v[i*ldv:], 1, v[k*ldv:], 1) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgebal.go000066400000000000000000000145541450372207100217740ustar00rootroot00000000000000// Copyright ©2016 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/blas64" "gonum.org/v1/gonum/lapack" ) // Dgebal balances an n×n matrix A. Balancing consists of two stages, permuting // and scaling. Both steps are optional and depend on the value of job. // // Permuting consists of applying a permutation matrix P such that the matrix // that results from Pᵀ*A*P takes the upper block triangular form // // [ T1 X Y ] // Pᵀ A P = [ 0 B Z ], // [ 0 0 T2 ] // // where T1 and T2 are upper triangular matrices and B contains at least one // nonzero off-diagonal element in each row and column. The indices ilo and ihi // mark the starting and ending columns of the submatrix B. The eigenvalues of A // isolated in the first 0 to ilo-1 and last ihi+1 to n-1 elements on the // diagonal can be read off without any roundoff error. // // Scaling consists of applying a diagonal similarity transformation D such that // D^{-1}*B*D has the 1-norm of each row and its corresponding column nearly // equal. The output matrix is // // [ T1 X*D Y ] // [ 0 inv(D)*B*D inv(D)*Z ]. // [ 0 0 T2 ] // // Scaling may reduce the 1-norm of the matrix, and improve the accuracy of // the computed eigenvalues and/or eigenvectors. // // job specifies the operations that will be performed on A. // If job is lapack.BalanceNone, Dgebal sets scale[i] = 1 for all i and returns ilo=0, ihi=n-1. // If job is lapack.Permute, only permuting will be done. // If job is lapack.Scale, only scaling will be done. // If job is lapack.PermuteScale, both permuting and scaling will be done. // // On return, if job is lapack.Permute or lapack.PermuteScale, it will hold that // // A[i,j] == 0, for i > j and j ∈ {0, ..., ilo-1, ihi+1, ..., n-1}. // // If job is lapack.BalanceNone or lapack.Scale, or if n == 0, it will hold that // // ilo == 0 and ihi == n-1. // // On return, scale will contain information about the permutations and scaling // factors applied to A. If π(j) denotes the index of the column interchanged // with column j, and D[j,j] denotes the scaling factor applied to column j, // then // // scale[j] == π(j), for j ∈ {0, ..., ilo-1, ihi+1, ..., n-1}, // == D[j,j], for j ∈ {ilo, ..., ihi}. // // scale must have length equal to n, otherwise Dgebal will panic. // // Dgebal is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgebal(job lapack.BalanceJob, n int, a []float64, lda int, scale []float64) (ilo, ihi int) { switch { case job != lapack.BalanceNone && job != lapack.Permute && job != lapack.Scale && job != lapack.PermuteScale: panic(badBalanceJob) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } ilo = 0 ihi = n - 1 if n == 0 { return ilo, ihi } if len(scale) != n { panic(shortScale) } if job == lapack.BalanceNone { for i := range scale { scale[i] = 1 } return ilo, ihi } if len(a) < (n-1)*lda+n { panic(shortA) } bi := blas64.Implementation() swapped := true if job == lapack.Scale { goto scaling } // Permutation to isolate eigenvalues if possible. // // Search for rows isolating an eigenvalue and push them down. for swapped { swapped = false rows: for i := ihi; i >= 0; i-- { for j := 0; j <= ihi; j++ { if i == j { continue } if a[i*lda+j] != 0 { continue rows } } // Row i has only zero off-diagonal elements in the // block A[ilo:ihi+1,ilo:ihi+1]. scale[ihi] = float64(i) if i != ihi { bi.Dswap(ihi+1, a[i:], lda, a[ihi:], lda) bi.Dswap(n, a[i*lda:], 1, a[ihi*lda:], 1) } if ihi == 0 { scale[0] = 1 return ilo, ihi } ihi-- swapped = true break } } // Search for columns isolating an eigenvalue and push them left. swapped = true for swapped { swapped = false columns: for j := ilo; j <= ihi; j++ { for i := ilo; i <= ihi; i++ { if i == j { continue } if a[i*lda+j] != 0 { continue columns } } // Column j has only zero off-diagonal elements in the // block A[ilo:ihi+1,ilo:ihi+1]. scale[ilo] = float64(j) if j != ilo { bi.Dswap(ihi+1, a[j:], lda, a[ilo:], lda) bi.Dswap(n-ilo, a[j*lda+ilo:], 1, a[ilo*lda+ilo:], 1) } swapped = true ilo++ break } } scaling: for i := ilo; i <= ihi; i++ { scale[i] = 1 } if job == lapack.Permute { return ilo, ihi } // Balance the submatrix in rows ilo to ihi. const ( // sclfac should be a power of 2 to avoid roundoff errors. // Elements of scale are restricted to powers of sclfac, // therefore the matrix will be only nearly balanced. sclfac = 2 // factor determines the minimum reduction of the row and column // norms that is considered non-negligible. It must be less than 1. factor = 0.95 ) sfmin1 := dlamchS / dlamchP sfmax1 := 1 / sfmin1 sfmin2 := sfmin1 * sclfac sfmax2 := 1 / sfmin2 // Iterative loop for norm reduction. var conv bool for !conv { conv = true for i := ilo; i <= ihi; i++ { c := bi.Dnrm2(ihi-ilo+1, a[ilo*lda+i:], lda) r := bi.Dnrm2(ihi-ilo+1, a[i*lda+ilo:], 1) ica := bi.Idamax(ihi+1, a[i:], lda) ca := math.Abs(a[ica*lda+i]) ira := bi.Idamax(n-ilo, a[i*lda+ilo:], 1) ra := math.Abs(a[i*lda+ilo+ira]) // Guard against zero c or r due to underflow. if c == 0 || r == 0 { continue } g := r / sclfac f := 1.0 s := c + r for c < g && math.Max(f, math.Max(c, ca)) < sfmax2 && math.Min(r, math.Min(g, ra)) > sfmin2 { if math.IsNaN(c + f + ca + r + g + ra) { // Panic if NaN to avoid infinite loop. panic("lapack: NaN") } f *= sclfac c *= sclfac ca *= sclfac g /= sclfac r /= sclfac ra /= sclfac } g = c / sclfac for r <= g && math.Max(r, ra) < sfmax2 && math.Min(math.Min(f, c), math.Min(g, ca)) > sfmin2 { f /= sclfac c /= sclfac ca /= sclfac g /= sclfac r *= sclfac ra *= sclfac } if c+r >= factor*s { // Reduction would be negligible. continue } if f < 1 && scale[i] < 1 && f*scale[i] <= sfmin1 { continue } if f > 1 && scale[i] > 1 && scale[i] >= sfmax1/f { continue } // Now balance. scale[i] *= f bi.Dscal(n-ilo, 1/f, a[i*lda+ilo:], 1) bi.Dscal(ihi+1, f, a[i:], lda) conv = false } } return ilo, ihi } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgebd2.go000066400000000000000000000044421450372207100217000ustar00rootroot00000000000000// 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/blas" // Dgebd2 reduces an m×n matrix A to upper or lower bidiagonal form by an orthogonal // transformation. // // Qᵀ * A * P = B // // if m >= n, B is upper diagonal, otherwise B is lower bidiagonal. // d is the diagonal, len = min(m,n) // e is the off-diagonal len = min(m,n)-1 // // Dgebd2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgebd2(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. minmn := min(m, n) if minmn == 0 { return } switch { case len(d) < minmn: panic(shortD) case len(e) < minmn-1: panic(shortE) case len(tauQ) < minmn: panic(shortTauQ) case len(tauP) < minmn: panic(shortTauP) case len(work) < max(m, n): panic(shortWork) } if m >= n { for i := 0; i < n; i++ { a[i*lda+i], tauQ[i] = impl.Dlarfg(m-i, a[i*lda+i], a[min(i+1, m-1)*lda+i:], lda) d[i] = a[i*lda+i] a[i*lda+i] = 1 // Apply H_i to A[i:m, i+1:n] from the left. if i < n-1 { impl.Dlarf(blas.Left, m-i, n-i-1, a[i*lda+i:], lda, tauQ[i], a[i*lda+i+1:], lda, work) } a[i*lda+i] = d[i] if i < n-1 { a[i*lda+i+1], tauP[i] = impl.Dlarfg(n-i-1, a[i*lda+i+1], a[i*lda+min(i+2, n-1):], 1) e[i] = a[i*lda+i+1] a[i*lda+i+1] = 1 impl.Dlarf(blas.Right, m-i-1, n-i-1, a[i*lda+i+1:], 1, tauP[i], a[(i+1)*lda+i+1:], lda, work) a[i*lda+i+1] = e[i] } else { tauP[i] = 0 } } return } for i := 0; i < m; i++ { a[i*lda+i], tauP[i] = impl.Dlarfg(n-i, a[i*lda+i], a[i*lda+min(i+1, n-1):], 1) d[i] = a[i*lda+i] a[i*lda+i] = 1 if i < m-1 { impl.Dlarf(blas.Right, m-i-1, n-i, a[i*lda+i:], 1, tauP[i], a[(i+1)*lda+i:], lda, work) } a[i*lda+i] = d[i] if i < m-1 { a[(i+1)*lda+i], tauQ[i] = impl.Dlarfg(m-i-1, a[(i+1)*lda+i], a[min(i+2, m-1)*lda+i:], lda) e[i] = a[(i+1)*lda+i] a[(i+1)*lda+i] = 1 impl.Dlarf(blas.Left, m-i-1, n-i-1, a[(i+1)*lda+i:], lda, tauQ[i], a[(i+1)*lda+i+1:], lda, work) a[(i+1)*lda+i] = e[i] } else { tauQ[i] = 0 } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgebrd.go000066400000000000000000000114611450372207100217770ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dgebrd reduces a general m×n matrix A to upper or lower bidiagonal form B by // an orthogonal transformation: // // Qᵀ * A * P = B. // // The diagonal elements of B are stored in d and the off-diagonal elements are stored // in e. These are additionally stored along the diagonal of A and the off-diagonal // of A. If m >= n B is an upper-bidiagonal matrix, and if m < n B is a // lower-bidiagonal matrix. // // The remaining elements of A store the data needed to construct Q and P. // The matrices Q and P are products of elementary reflectors // // if m >= n, Q = H_0 * H_1 * ... * H_{n-1}, // P = G_0 * G_1 * ... * G_{n-2}, // if m < n, Q = H_0 * H_1 * ... * H_{m-2}, // P = G_0 * G_1 * ... * G_{m-1}, // // where // // H_i = I - tauQ[i] * v_i * v_iᵀ, // G_i = I - tauP[i] * u_i * u_iᵀ. // // As an example, on exit the entries of A when m = 6, and n = 5 // // [ d e u1 u1 u1] // [v1 d e u2 u2] // [v1 v2 d e u3] // [v1 v2 v3 d e] // [v1 v2 v3 v4 d] // [v1 v2 v3 v4 v5] // // and when m = 5, n = 6 // // [ d u1 u1 u1 u1 u1] // [ e d u2 u2 u2 u2] // [v1 e d u3 u3 u3] // [v1 v2 e d u4 u4] // [v1 v2 v3 e d u5] // // d, tauQ, and tauP must all have length at least min(m,n), and e must have // length min(m,n) - 1, unless lwork is -1 when there is no check except for // work which must have a length of at least one. // // work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= max(1,m,n) or be -1 and this function will panic otherwise. // Dgebrd is blocked decomposition, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Dgebrd, // the optimal work length will be stored into work[0]. // // Dgebrd is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgebrd(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64, lwork int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < max(1, max(m, n)) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. minmn := min(m, n) if minmn == 0 { work[0] = 1 return } nb := impl.Ilaenv(1, "DGEBRD", " ", m, n, -1, -1) lwkopt := (m + n) * nb if lwork == -1 { work[0] = float64(lwkopt) return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(d) < minmn: panic(shortD) case len(e) < minmn-1: panic(shortE) case len(tauQ) < minmn: panic(shortTauQ) case len(tauP) < minmn: panic(shortTauP) } nx := minmn ws := max(m, n) if 1 < nb && nb < minmn { // At least one blocked operation can be done. // Get the crossover point nx. nx = max(nb, impl.Ilaenv(3, "DGEBRD", " ", m, n, -1, -1)) // Determine when to switch from blocked to unblocked code. if nx < minmn { // At least one blocked operation will be done. ws = (m + n) * nb if lwork < ws { // Not enough work space for the optimal nb, // consider using a smaller block size. nbmin := impl.Ilaenv(2, "DGEBRD", " ", m, n, -1, -1) if lwork >= (m+n)*nbmin { // Enough work space for minimum block size. nb = lwork / (m + n) } else { nb = minmn nx = minmn } } } } bi := blas64.Implementation() ldworkx := nb ldworky := nb var i int for i = 0; i < minmn-nx; i += nb { // Reduce rows and columns i:i+nb to bidiagonal form and return // the matrices X and Y which are needed to update the unreduced // part of the matrix. // X is stored in the first m rows of work, y in the next rows. x := work[:m*ldworkx] y := work[m*ldworkx:] impl.Dlabrd(m-i, n-i, nb, a[i*lda+i:], lda, d[i:], e[i:], tauQ[i:], tauP[i:], x, ldworkx, y, ldworky) // Update the trailing submatrix A[i+nb:m,i+nb:n], using an update // of the form A := A - V*Y**T - X*U**T bi.Dgemm(blas.NoTrans, blas.Trans, m-i-nb, n-i-nb, nb, -1, a[(i+nb)*lda+i:], lda, y[nb*ldworky:], ldworky, 1, a[(i+nb)*lda+i+nb:], lda) bi.Dgemm(blas.NoTrans, blas.NoTrans, m-i-nb, n-i-nb, nb, -1, x[nb*ldworkx:], ldworkx, a[i*lda+i+nb:], lda, 1, a[(i+nb)*lda+i+nb:], lda) // Copy diagonal and off-diagonal elements of B back into A. if m >= n { for j := i; j < i+nb; j++ { a[j*lda+j] = d[j] a[j*lda+j+1] = e[j] } } else { for j := i; j < i+nb; j++ { a[j*lda+j] = d[j] a[(j+1)*lda+j] = e[j] } } } // Use unblocked code to reduce the remainder of the matrix. impl.Dgebd2(m-i, n-i, a[i*lda+i:], lda, d[i:], e[i:], tauQ[i:], tauP[i:], work) work[0] = float64(ws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgecon.go000066400000000000000000000052011450372207100220020ustar00rootroot00000000000000// 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dgecon estimates the reciprocal of the condition number of the n×n matrix A // given the LU decomposition of the matrix. The condition number computed may // be based on the 1-norm or the ∞-norm. // // The slice a contains the result of the LU decomposition of A as computed by Dgetrf. // // anorm is the corresponding 1-norm or ∞-norm of the original matrix A. anorm // must be non-negative. // // work must have length at least 4*n and iwork must have length at least n, // otherwise Dgecon will panic. func (impl Implementation) Dgecon(norm lapack.MatrixNorm, n int, a []float64, lda int, anorm float64, work []float64, iwork []int) float64 { switch { case norm != lapack.MaxColumnSum && norm != lapack.MaxRowSum: panic(badNorm) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case anorm < 0: panic(negANorm) } // Quick return if possible. if n == 0 { return 1 } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(work) < 4*n: panic(shortWork) case len(iwork) < n: panic(shortIWork) } // Quick return if possible. if anorm == 0 { return 0 } if math.IsNaN(anorm) { // The reference implementation treats the NaN anorm as invalid and // returns an error code. Our error handling is to panic which seems too // harsh for a runtime condition, so we just propagate the NaN instead. return anorm } bi := blas64.Implementation() var rcond, ainvnm float64 var kase int var normin bool isave := new([3]int) onenrm := norm == lapack.MaxColumnSum smlnum := dlamchS kase1 := 2 if onenrm { kase1 = 1 } for { ainvnm, kase = impl.Dlacn2(n, work[n:], work, iwork, ainvnm, kase, isave) if kase == 0 { if ainvnm != 0 { rcond = (1 / ainvnm) / anorm } return rcond } var sl, su float64 if kase == kase1 { sl = impl.Dlatrs(blas.Lower, blas.NoTrans, blas.Unit, normin, n, a, lda, work, work[2*n:]) su = impl.Dlatrs(blas.Upper, blas.NoTrans, blas.NonUnit, normin, n, a, lda, work, work[3*n:]) } else { su = impl.Dlatrs(blas.Upper, blas.Trans, blas.NonUnit, normin, n, a, lda, work, work[3*n:]) sl = impl.Dlatrs(blas.Lower, blas.Trans, blas.Unit, normin, n, a, lda, work, work[2*n:]) } scale := sl * su normin = true if scale != 1 { ix := bi.Idamax(n, work, 1) if scale == 0 || scale < math.Abs(work[ix])*smlnum { return rcond } impl.Drscl(n, scale, work, 1) } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgeev.go000066400000000000000000000217661450372207100216530ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dgeev computes the eigenvalues and, optionally, the left and/or right // eigenvectors for an n×n real nonsymmetric matrix A. // // The right eigenvector v_j of A corresponding to an eigenvalue λ_j // is defined by // // A v_j = λ_j v_j, // // and the left eigenvector u_j corresponding to an eigenvalue λ_j is defined by // // u_jᴴ A = λ_j u_jᴴ, // // where u_jᴴ is the conjugate transpose of u_j. // // On return, A will be overwritten and the left and right eigenvectors will be // stored, respectively, in the columns of the n×n matrices VL and VR in the // same order as their eigenvalues. If the j-th eigenvalue is real, then // // u_j = VL[:,j], // v_j = VR[:,j], // // and if it is not real, then j and j+1 form a complex conjugate pair and the // eigenvectors can be recovered as // // u_j = VL[:,j] + i*VL[:,j+1], // u_{j+1} = VL[:,j] - i*VL[:,j+1], // v_j = VR[:,j] + i*VR[:,j+1], // v_{j+1} = VR[:,j] - i*VR[:,j+1], // // where i is the imaginary unit. The computed eigenvectors are normalized to // have Euclidean norm equal to 1 and largest component real. // // Left eigenvectors will be computed only if jobvl == lapack.LeftEVCompute, // otherwise jobvl must be lapack.LeftEVNone. // Right eigenvectors will be computed only if jobvr == lapack.RightEVCompute, // otherwise jobvr must be lapack.RightEVNone. // For other values of jobvl and jobvr Dgeev will panic. // // wr and wi contain the real and imaginary parts, respectively, of the computed // eigenvalues. Complex conjugate pairs of eigenvalues appear consecutively with // the eigenvalue having the positive imaginary part first. // wr and wi must have length n, and Dgeev will panic otherwise. // // work must have length at least lwork and lwork must be at least max(1,4*n) if // the left or right eigenvectors are computed, and at least max(1,3*n) if no // eigenvectors are computed. For good performance, lwork must generally be // larger. On return, optimal value of lwork will be stored in work[0]. // // If lwork == -1, instead of performing Dgeev, the function only calculates the // optimal value of lwork and stores it into work[0]. // // On return, first is the index of the first valid eigenvalue. If first == 0, // all eigenvalues and eigenvectors have been computed. If first is positive, // Dgeev failed to compute all the eigenvalues, no eigenvectors have been // computed and wr[first:] and wi[first:] contain those eigenvalues which have // converged. func (impl Implementation) Dgeev(jobvl lapack.LeftEVJob, jobvr lapack.RightEVJob, n int, a []float64, lda int, wr, wi []float64, vl []float64, ldvl int, vr []float64, ldvr int, work []float64, lwork int) (first int) { wantvl := jobvl == lapack.LeftEVCompute wantvr := jobvr == lapack.RightEVCompute var minwrk int if wantvl || wantvr { minwrk = max(1, 4*n) } else { minwrk = max(1, 3*n) } switch { case jobvl != lapack.LeftEVCompute && jobvl != lapack.LeftEVNone: panic(badLeftEVJob) case jobvr != lapack.RightEVCompute && jobvr != lapack.RightEVNone: panic(badRightEVJob) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case ldvl < 1 || (ldvl < n && wantvl): panic(badLdVL) case ldvr < 1 || (ldvr < n && wantvr): panic(badLdVR) case lwork < minwrk && lwork != -1: panic(badLWork) case len(work) < lwork: panic(shortWork) } // Quick return if possible. if n == 0 { work[0] = 1 return 0 } maxwrk := 2*n + n*impl.Ilaenv(1, "DGEHRD", " ", n, 1, n, 0) if wantvl || wantvr { maxwrk = max(maxwrk, 2*n+(n-1)*impl.Ilaenv(1, "DORGHR", " ", n, 1, n, -1)) impl.Dhseqr(lapack.EigenvaluesAndSchur, lapack.SchurOrig, n, 0, n-1, a, lda, wr, wi, nil, n, work, -1) maxwrk = max(maxwrk, max(n+1, n+int(work[0]))) side := lapack.EVLeft if wantvr { side = lapack.EVRight } impl.Dtrevc3(side, lapack.EVAllMulQ, nil, n, a, lda, vl, ldvl, vr, ldvr, n, work, -1) maxwrk = max(maxwrk, n+int(work[0])) maxwrk = max(maxwrk, 4*n) } else { impl.Dhseqr(lapack.EigenvaluesOnly, lapack.SchurNone, n, 0, n-1, a, lda, wr, wi, vr, ldvr, work, -1) maxwrk = max(maxwrk, max(n+1, n+int(work[0]))) } maxwrk = max(maxwrk, minwrk) if lwork == -1 { work[0] = float64(maxwrk) return 0 } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(wr) != n: panic(badLenWr) case len(wi) != n: panic(badLenWi) case len(vl) < (n-1)*ldvl+n && wantvl: panic(shortVL) case len(vr) < (n-1)*ldvr+n && wantvr: panic(shortVR) } // Get machine constants. smlnum := math.Sqrt(dlamchS) / dlamchP bignum := 1 / smlnum // Scale A if max element outside range [smlnum,bignum]. anrm := impl.Dlange(lapack.MaxAbs, n, n, a, lda, nil) var scalea bool var cscale float64 if 0 < anrm && anrm < smlnum { scalea = true cscale = smlnum } else if anrm > bignum { scalea = true cscale = bignum } if scalea { impl.Dlascl(lapack.General, 0, 0, anrm, cscale, n, n, a, lda) } // Balance the matrix. workbal := work[:n] ilo, ihi := impl.Dgebal(lapack.PermuteScale, n, a, lda, workbal) // Reduce to upper Hessenberg form. iwrk := 2 * n tau := work[n : iwrk-1] impl.Dgehrd(n, ilo, ihi, a, lda, tau, work[iwrk:], lwork-iwrk) var side lapack.EVSide if wantvl { side = lapack.EVLeft // Copy Householder vectors to VL. impl.Dlacpy(blas.Lower, n, n, a, lda, vl, ldvl) // Generate orthogonal matrix in VL. impl.Dorghr(n, ilo, ihi, vl, ldvl, tau, work[iwrk:], lwork-iwrk) // Perform QR iteration, accumulating Schur vectors in VL. iwrk = n first = impl.Dhseqr(lapack.EigenvaluesAndSchur, lapack.SchurOrig, n, ilo, ihi, a, lda, wr, wi, vl, ldvl, work[iwrk:], lwork-iwrk) if wantvr { // Want left and right eigenvectors. // Copy Schur vectors to VR. side = lapack.EVBoth impl.Dlacpy(blas.All, n, n, vl, ldvl, vr, ldvr) } } else if wantvr { side = lapack.EVRight // Copy Householder vectors to VR. impl.Dlacpy(blas.Lower, n, n, a, lda, vr, ldvr) // Generate orthogonal matrix in VR. impl.Dorghr(n, ilo, ihi, vr, ldvr, tau, work[iwrk:], lwork-iwrk) // Perform QR iteration, accumulating Schur vectors in VR. iwrk = n first = impl.Dhseqr(lapack.EigenvaluesAndSchur, lapack.SchurOrig, n, ilo, ihi, a, lda, wr, wi, vr, ldvr, work[iwrk:], lwork-iwrk) } else { // Compute eigenvalues only. iwrk = n first = impl.Dhseqr(lapack.EigenvaluesOnly, lapack.SchurNone, n, ilo, ihi, a, lda, wr, wi, nil, 1, work[iwrk:], lwork-iwrk) } if first > 0 { if scalea { // Undo scaling. impl.Dlascl(lapack.General, 0, 0, cscale, anrm, n-first, 1, wr[first:], 1) impl.Dlascl(lapack.General, 0, 0, cscale, anrm, n-first, 1, wi[first:], 1) impl.Dlascl(lapack.General, 0, 0, cscale, anrm, ilo, 1, wr, 1) impl.Dlascl(lapack.General, 0, 0, cscale, anrm, ilo, 1, wi, 1) } work[0] = float64(maxwrk) return first } if wantvl || wantvr { // Compute left and/or right eigenvectors. impl.Dtrevc3(side, lapack.EVAllMulQ, nil, n, a, lda, vl, ldvl, vr, ldvr, n, work[iwrk:], lwork-iwrk) } bi := blas64.Implementation() if wantvl { // Undo balancing of left eigenvectors. impl.Dgebak(lapack.PermuteScale, lapack.EVLeft, n, ilo, ihi, workbal, n, vl, ldvl) // Normalize left eigenvectors and make largest component real. for i, wii := range wi { if wii < 0 { continue } if wii == 0 { scl := 1 / bi.Dnrm2(n, vl[i:], ldvl) bi.Dscal(n, scl, vl[i:], ldvl) continue } scl := 1 / impl.Dlapy2(bi.Dnrm2(n, vl[i:], ldvl), bi.Dnrm2(n, vl[i+1:], ldvl)) bi.Dscal(n, scl, vl[i:], ldvl) bi.Dscal(n, scl, vl[i+1:], ldvl) for k := 0; k < n; k++ { vi := vl[k*ldvl+i] vi1 := vl[k*ldvl+i+1] work[iwrk+k] = vi*vi + vi1*vi1 } k := bi.Idamax(n, work[iwrk:iwrk+n], 1) cs, sn, _ := impl.Dlartg(vl[k*ldvl+i], vl[k*ldvl+i+1]) bi.Drot(n, vl[i:], ldvl, vl[i+1:], ldvl, cs, sn) vl[k*ldvl+i+1] = 0 } } if wantvr { // Undo balancing of right eigenvectors. impl.Dgebak(lapack.PermuteScale, lapack.EVRight, n, ilo, ihi, workbal, n, vr, ldvr) // Normalize right eigenvectors and make largest component real. for i, wii := range wi { if wii < 0 { continue } if wii == 0 { scl := 1 / bi.Dnrm2(n, vr[i:], ldvr) bi.Dscal(n, scl, vr[i:], ldvr) continue } scl := 1 / impl.Dlapy2(bi.Dnrm2(n, vr[i:], ldvr), bi.Dnrm2(n, vr[i+1:], ldvr)) bi.Dscal(n, scl, vr[i:], ldvr) bi.Dscal(n, scl, vr[i+1:], ldvr) for k := 0; k < n; k++ { vi := vr[k*ldvr+i] vi1 := vr[k*ldvr+i+1] work[iwrk+k] = vi*vi + vi1*vi1 } k := bi.Idamax(n, work[iwrk:iwrk+n], 1) cs, sn, _ := impl.Dlartg(vr[k*ldvr+i], vr[k*ldvr+i+1]) bi.Drot(n, vr[i:], ldvr, vr[i+1:], ldvr, cs, sn) vr[k*ldvr+i+1] = 0 } } if scalea { // Undo scaling. impl.Dlascl(lapack.General, 0, 0, cscale, anrm, n-first, 1, wr[first:], 1) impl.Dlascl(lapack.General, 0, 0, cscale, anrm, n-first, 1, wi[first:], 1) } work[0] = float64(maxwrk) return first } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgehd2.go000066400000000000000000000063221450372207100217050ustar00rootroot00000000000000// Copyright ©2016 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" // Dgehd2 reduces a block of a general n×n matrix A to upper Hessenberg form H // by an orthogonal similarity transformation Qᵀ * A * Q = H. // // The matrix Q is represented as a product of (ihi-ilo) elementary // reflectors // // Q = H_{ilo} H_{ilo+1} ... H_{ihi-1}. // // Each H_i has the form // // H_i = I - tau[i] * v * vᵀ // // where v is a real vector with v[0:i+1] = 0, v[i+1] = 1 and v[ihi+1:n] = 0. // v[i+2:ihi+1] is stored on exit in A[i+2:ihi+1,i]. // // On entry, a contains the n×n general matrix to be reduced. On return, the // upper triangle and the first subdiagonal of A are overwritten with the upper // Hessenberg matrix H, and the elements below the first subdiagonal, with the // slice tau, represent the orthogonal matrix Q as a product of elementary // reflectors. // // The contents of A are illustrated by the following example, with n = 7, ilo = // 1 and ihi = 5. // On entry, // // [ a a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a ] // // on return, // // [ a a h h h h a ] // [ a h h h h a ] // [ h h h h h h ] // [ v1 h h h h h ] // [ v1 v2 h h h h ] // [ v1 v2 v3 h h h ] // [ a ] // // where a denotes an element of the original matrix A, h denotes a // modified element of the upper Hessenberg matrix H, and vi denotes an // element of the vector defining H_i. // // ilo and ihi determine the block of A that will be reduced to upper Hessenberg // form. It must hold that 0 <= ilo <= ihi <= max(0, n-1), otherwise Dgehd2 will // panic. // // On return, tau will contain the scalar factors of the elementary reflectors. // It must have length equal to n-1, otherwise Dgehd2 will panic. // // work must have length at least n, otherwise Dgehd2 will panic. // // Dgehd2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgehd2(n, ilo, ihi int, a []float64, lda int, tau, work []float64) { switch { case n < 0: panic(nLT0) case ilo < 0 || max(0, n-1) < ilo: panic(badIlo) case ihi < min(ilo, n-1) || n <= ihi: panic(badIhi) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(tau) != n-1: panic(badLenTau) case len(work) < n: panic(shortWork) } for i := ilo; i < ihi; i++ { // Compute elementary reflector H_i to annihilate A[i+2:ihi+1,i]. var aii float64 aii, tau[i] = impl.Dlarfg(ihi-i, a[(i+1)*lda+i], a[min(i+2, n-1)*lda+i:], lda) a[(i+1)*lda+i] = 1 // Apply H_i to A[0:ihi+1,i+1:ihi+1] from the right. impl.Dlarf(blas.Right, ihi+1, ihi-i, a[(i+1)*lda+i:], lda, tau[i], a[i+1:], lda, work) // Apply H_i to A[i+1:ihi+1,i+1:n] from the left. impl.Dlarf(blas.Left, ihi-i, n-i-1, a[(i+1)*lda+i:], lda, tau[i], a[(i+1)*lda+i+1:], lda, work) a[(i+1)*lda+i] = aii } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgehrd.go000066400000000000000000000136331450372207100220100ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dgehrd reduces a block of a real n×n general matrix A to upper Hessenberg // form H by an orthogonal similarity transformation Qᵀ * A * Q = H. // // The matrix Q is represented as a product of (ihi-ilo) elementary // reflectors // // Q = H_{ilo} H_{ilo+1} ... H_{ihi-1}. // // Each H_i has the form // // H_i = I - tau[i] * v * vᵀ // // where v is a real vector with v[0:i+1] = 0, v[i+1] = 1 and v[ihi+1:n] = 0. // v[i+2:ihi+1] is stored on exit in A[i+2:ihi+1,i]. // // On entry, a contains the n×n general matrix to be reduced. On return, the // upper triangle and the first subdiagonal of A will be overwritten with the // upper Hessenberg matrix H, and the elements below the first subdiagonal, with // the slice tau, represent the orthogonal matrix Q as a product of elementary // reflectors. // // The contents of a are illustrated by the following example, with n = 7, ilo = // 1 and ihi = 5. // On entry, // // [ a a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a a a a a a ] // [ a ] // // on return, // // [ a a h h h h a ] // [ a h h h h a ] // [ h h h h h h ] // [ v1 h h h h h ] // [ v1 v2 h h h h ] // [ v1 v2 v3 h h h ] // [ a ] // // where a denotes an element of the original matrix A, h denotes a // modified element of the upper Hessenberg matrix H, and vi denotes an // element of the vector defining H_i. // // ilo and ihi determine the block of A that will be reduced to upper Hessenberg // form. It must hold that 0 <= ilo <= ihi < n if n > 0, and ilo == 0 and ihi == // -1 if n == 0, otherwise Dgehrd will panic. // // On return, tau will contain the scalar factors of the elementary reflectors. // Elements tau[:ilo] and tau[ihi:] will be set to zero. tau must have length // equal to n-1 if n > 0, otherwise Dgehrd will panic. // // work must have length at least lwork and lwork must be at least max(1,n), // otherwise Dgehrd will panic. On return, work[0] contains the optimal value of // lwork. // // If lwork == -1, instead of performing Dgehrd, only the optimal value of lwork // will be stored in work[0]. // // Dgehrd is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgehrd(n, ilo, ihi int, a []float64, lda int, tau, work []float64, lwork int) { switch { case n < 0: panic(nLT0) case ilo < 0 || max(0, n-1) < ilo: panic(badIlo) case ihi < min(ilo, n-1) || n <= ihi: panic(badIhi) case lda < max(1, n): panic(badLdA) case lwork < max(1, n) && lwork != -1: panic(badLWork) case len(work) < lwork: panic(shortWork) } // Quick return if possible. if n == 0 { work[0] = 1 return } const ( nbmax = 64 ldt = nbmax + 1 tsize = ldt * nbmax ) // Compute the workspace requirements. nb := min(nbmax, impl.Ilaenv(1, "DGEHRD", " ", n, ilo, ihi, -1)) lwkopt := n*nb + tsize if lwork == -1 { work[0] = float64(lwkopt) return } if len(a) < (n-1)*lda+n { panic(shortA) } if len(tau) != n-1 { panic(badLenTau) } // Set tau[:ilo] and tau[ihi:] to zero. for i := 0; i < ilo; i++ { tau[i] = 0 } for i := ihi; i < n-1; i++ { tau[i] = 0 } // Quick return if possible. nh := ihi - ilo + 1 if nh <= 1 { work[0] = 1 return } // Determine the block size. nbmin := 2 var nx int if 1 < nb && nb < nh { // Determine when to cross over from blocked to unblocked code // (last block is always handled by unblocked code). nx = max(nb, impl.Ilaenv(3, "DGEHRD", " ", n, ilo, ihi, -1)) if nx < nh { // Determine if workspace is large enough for blocked code. if lwork < n*nb+tsize { // Not enough workspace to use optimal nb: // determine the minimum value of nb, and reduce // nb or force use of unblocked code. nbmin = max(2, impl.Ilaenv(2, "DGEHRD", " ", n, ilo, ihi, -1)) if lwork >= n*nbmin+tsize { nb = (lwork - tsize) / n } else { nb = 1 } } } } ldwork := nb // work is used as an n×nb matrix. var i int if nb < nbmin || nh <= nb { // Use unblocked code below. i = ilo } else { // Use blocked code. bi := blas64.Implementation() iwt := n * nb // Size of the matrix Y and index where the matrix T starts in work. for i = ilo; i < ihi-nx; i += nb { ib := min(nb, ihi-i) // Reduce columns [i:i+ib] to Hessenberg form, returning the // matrices V and T of the block reflector H = I - V*T*Vᵀ // which performs the reduction, and also the matrix Y = A*V*T. impl.Dlahr2(ihi+1, i+1, ib, a[i:], lda, tau[i:], work[iwt:], ldt, work, ldwork) // Apply the block reflector H to A[:ihi+1,i+ib:ihi+1] from the // right, computing A := A - Y * Vᵀ. V[i+ib,i+ib-1] must be set // to 1. ei := a[(i+ib)*lda+i+ib-1] a[(i+ib)*lda+i+ib-1] = 1 bi.Dgemm(blas.NoTrans, blas.Trans, ihi+1, ihi-i-ib+1, ib, -1, work, ldwork, a[(i+ib)*lda+i:], lda, 1, a[i+ib:], lda) a[(i+ib)*lda+i+ib-1] = ei // Apply the block reflector H to A[0:i+1,i+1:i+ib-1] from the // right. bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, i+1, ib-1, 1, a[(i+1)*lda+i:], lda, work, ldwork) for j := 0; j <= ib-2; j++ { bi.Daxpy(i+1, -1, work[j:], ldwork, a[i+j+1:], lda) } // Apply the block reflector H to A[i+1:ihi+1,i+ib:n] from the // left. impl.Dlarfb(blas.Left, blas.Trans, lapack.Forward, lapack.ColumnWise, ihi-i, n-i-ib, ib, a[(i+1)*lda+i:], lda, work[iwt:], ldt, a[(i+1)*lda+i+ib:], lda, work, ldwork) } } // Use unblocked code to reduce the rest of the matrix. impl.Dgehd2(n, i, ihi, a, lda, tau, work) work[0] = float64(lwkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgelq2.go000066400000000000000000000034031450372207100217230ustar00rootroot00000000000000// 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/blas" // Dgelq2 computes the LQ factorization of the m×n matrix A. // // In an LQ factorization, L is a lower triangular m×n matrix, and Q is an n×n // orthonormal matrix. // // a is modified to contain the information to construct L and Q. // The lower triangle of a contains the matrix L. The upper triangular elements // (not including the diagonal) contain the elementary reflectors. tau is modified // to contain the reflector scales. tau must have length of at least k = min(m,n) // and this function will panic otherwise. // // See Dgeqr2 for a description of the elementary reflectors and orthonormal // matrix Q. Q is constructed as a product of these elementary reflectors, // Q = H_{k-1} * ... * H_1 * H_0. // // work is temporary storage of length at least m and this function will panic otherwise. // // Dgelq2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgelq2(m, n int, a []float64, lda int, tau, work []float64) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. k := min(m, n) if k == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) case len(work) < m: panic(shortWork) } for i := 0; i < k; i++ { a[i*lda+i], tau[i] = impl.Dlarfg(n-i, a[i*lda+i], a[i*lda+min(i+1, n-1):], 1) if i < m-1 { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(blas.Right, m-i-1, n-i, a[i*lda+i:], 1, tau[i], a[(i+1)*lda+i:], lda, work) a[i*lda+i] = aii } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgelqf.go000066400000000000000000000047301450372207100220130ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dgelqf computes the LQ factorization of the m×n matrix A using a blocked // algorithm. See the documentation for Dgelq2 for a description of the // parameters at entry and exit. // // work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= m, and this function will panic otherwise. // Dgelqf is a blocked LQ factorization, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Dgelqf, // the optimal work length will be stored into work[0]. // // tau must have length at least min(m,n), and this function will panic otherwise. func (impl Implementation) Dgelqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < max(1, m) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } k := min(m, n) if k == 0 { work[0] = 1 return } nb := impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1) if lwork == -1 { work[0] = float64(m * nb) return } if len(a) < (m-1)*lda+n { panic(shortA) } if len(tau) < k { panic(shortTau) } // Find the optimal blocking size based on the size of available memory // and optimal machine parameters. nbmin := 2 var nx int iws := m if 1 < nb && nb < k { nx = max(0, impl.Ilaenv(3, "DGELQF", " ", m, n, -1, -1)) if nx < k { iws = m * nb if lwork < iws { nb = lwork / m nbmin = max(2, impl.Ilaenv(2, "DGELQF", " ", m, n, -1, -1)) } } } ldwork := nb // Computed blocked LQ factorization. var i int if nbmin <= nb && nb < k && nx < k { for i = 0; i < k-nx; i += nb { ib := min(k-i, nb) impl.Dgelq2(ib, n-i, a[i*lda+i:], lda, tau[i:], work) if i+ib < m { impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib, a[i*lda+i:], lda, tau[i:], work, ldwork) impl.Dlarfb(blas.Right, blas.NoTrans, lapack.Forward, lapack.RowWise, m-i-ib, n-i, ib, a[i*lda+i:], lda, work, ldwork, a[(i+ib)*lda+i:], lda, work[ib*ldwork:], ldwork) } } } // Perform unblocked LQ factorization on the remainder. if i < k { impl.Dgelq2(m-i, n-i, a[i*lda+i:], lda, tau[i:], work) } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgels.go000066400000000000000000000140271450372207100216470ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dgels finds a minimum-norm solution based on the matrices A and B using the // QR or LQ factorization. Dgels returns false if the matrix // A is singular, and true if this solution was successfully found. // // The minimization problem solved depends on the input parameters. // // 1. If m >= n and trans == blas.NoTrans, Dgels finds X such that || A*X - B||_2 // is minimized. // 2. If m < n and trans == blas.NoTrans, Dgels finds the minimum norm solution of // A * X = B. // 3. If m >= n and trans == blas.Trans, Dgels finds the minimum norm solution of // Aᵀ * X = B. // 4. If m < n and trans == blas.Trans, Dgels finds X such that || A*X - B||_2 // is minimized. // // Note that the least-squares solutions (cases 1 and 3) perform the minimization // per column of B. This is not the same as finding the minimum-norm matrix. // // The matrix A is a general matrix of size m×n and is modified during this call. // The input matrix B is of size max(m,n)×nrhs, and serves two purposes. On entry, // the elements of b specify the input matrix B. B has size m×nrhs if // trans == blas.NoTrans, and n×nrhs if trans == blas.Trans. On exit, the // leading submatrix of b contains the solution vectors X. If trans == blas.NoTrans, // this submatrix is of size n×nrhs, and of size m×nrhs otherwise. // // work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= max(m,n) + max(m,n,nrhs), and this function will panic // otherwise. A longer work will enable blocked algorithms to be called. // In the special case that lwork == -1, work[0] will be set to the optimal working // length. func (impl Implementation) Dgels(trans blas.Transpose, m, n, nrhs int, a []float64, lda int, b []float64, ldb int, work []float64, lwork int) bool { mn := min(m, n) minwrk := mn + max(mn, nrhs) switch { case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case nrhs < 0: panic(nrhsLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, nrhs): panic(badLdB) case lwork < max(1, minwrk) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if mn == 0 || nrhs == 0 { impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb) work[0] = 1 return true } // Find optimal block size. var nb int if m >= n { nb = impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1) if trans != blas.NoTrans { nb = max(nb, impl.Ilaenv(1, "DORMQR", "LN", m, nrhs, n, -1)) } else { nb = max(nb, impl.Ilaenv(1, "DORMQR", "LT", m, nrhs, n, -1)) } } else { nb = impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1) if trans != blas.NoTrans { nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LT", n, nrhs, m, -1)) } else { nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LN", n, nrhs, m, -1)) } } wsize := max(1, mn+max(mn, nrhs)*nb) work[0] = float64(wsize) if lwork == -1 { return true } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(b) < (max(m, n)-1)*ldb+nrhs: panic(shortB) } // Scale the input matrices if they contain extreme values. smlnum := dlamchS / dlamchP bignum := 1 / smlnum anrm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, nil) var iascl int if anrm > 0 && anrm < smlnum { impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, m, n, a, lda) iascl = 1 } else if anrm > bignum { impl.Dlascl(lapack.General, 0, 0, anrm, bignum, m, n, a, lda) } else if anrm == 0 { // Matrix is all zeros. impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb) return true } brow := m if trans != blas.NoTrans { brow = n } bnrm := impl.Dlange(lapack.MaxAbs, brow, nrhs, b, ldb, nil) ibscl := 0 if bnrm > 0 && bnrm < smlnum { impl.Dlascl(lapack.General, 0, 0, bnrm, smlnum, brow, nrhs, b, ldb) ibscl = 1 } else if bnrm > bignum { impl.Dlascl(lapack.General, 0, 0, bnrm, bignum, brow, nrhs, b, ldb) ibscl = 2 } // Solve the minimization problem using a QR or an LQ decomposition. var scllen int if m >= n { impl.Dgeqrf(m, n, a, lda, work, work[mn:], lwork-mn) if trans == blas.NoTrans { impl.Dormqr(blas.Left, blas.Trans, m, nrhs, n, a, lda, work[:n], b, ldb, work[mn:], lwork-mn) ok := impl.Dtrtrs(blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs, a, lda, b, ldb) if !ok { return false } scllen = n } else { ok := impl.Dtrtrs(blas.Upper, blas.Trans, blas.NonUnit, n, nrhs, a, lda, b, ldb) if !ok { return false } for i := n; i < m; i++ { for j := 0; j < nrhs; j++ { b[i*ldb+j] = 0 } } impl.Dormqr(blas.Left, blas.NoTrans, m, nrhs, n, a, lda, work[:n], b, ldb, work[mn:], lwork-mn) scllen = m } } else { impl.Dgelqf(m, n, a, lda, work, work[mn:], lwork-mn) if trans == blas.NoTrans { ok := impl.Dtrtrs(blas.Lower, blas.NoTrans, blas.NonUnit, m, nrhs, a, lda, b, ldb) if !ok { return false } for i := m; i < n; i++ { for j := 0; j < nrhs; j++ { b[i*ldb+j] = 0 } } impl.Dormlq(blas.Left, blas.Trans, n, nrhs, m, a, lda, work, b, ldb, work[mn:], lwork-mn) scllen = n } else { impl.Dormlq(blas.Left, blas.NoTrans, n, nrhs, m, a, lda, work, b, ldb, work[mn:], lwork-mn) ok := impl.Dtrtrs(blas.Lower, blas.Trans, blas.NonUnit, m, nrhs, a, lda, b, ldb) if !ok { return false } } } // Adjust answer vector based on scaling. if iascl == 1 { impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, scllen, nrhs, b, ldb) } if iascl == 2 { impl.Dlascl(lapack.General, 0, 0, anrm, bignum, scllen, nrhs, b, ldb) } if ibscl == 1 { impl.Dlascl(lapack.General, 0, 0, smlnum, bnrm, scllen, nrhs, b, ldb) } if ibscl == 2 { impl.Dlascl(lapack.General, 0, 0, bignum, bnrm, scllen, nrhs, b, ldb) } work[0] = float64(wsize) return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgeql2.go000066400000000000000000000033151450372207100217250ustar00rootroot00000000000000// Copyright ©2016 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" // Dgeql2 computes the QL factorization of the m×n matrix A. That is, Dgeql2 // computes Q and L such that // // A = Q * L // // where Q is an m×m orthonormal matrix and L is a lower trapezoidal matrix. // // Q is represented as a product of elementary reflectors, // // Q = H_{k-1} * ... * H_1 * H_0 // // where k = min(m,n) and each H_i has the form // // H_i = I - tau[i] * v_i * v_iᵀ // // Vector v_i has v[m-k+i+1:m] = 0, v[m-k+i] = 1, and v[:m-k+i+1] is stored on // exit in A[0:m-k+i-1, n-k+i]. // // tau must have length at least min(m,n), and Dgeql2 will panic otherwise. // // work is temporary memory storage and must have length at least n. // // Dgeql2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgeql2(m, n int, a []float64, lda int, tau, work []float64) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. k := min(m, n) if k == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) case len(work) < n: panic(shortWork) } var aii float64 for i := k - 1; i >= 0; i-- { // Generate elementary reflector H_i to annihilate A[0:m-k+i-1, n-k+i]. aii, tau[i] = impl.Dlarfg(m-k+i+1, a[(m-k+i)*lda+n-k+i], a[n-k+i:], lda) // Apply H_i to A[0:m-k+i, 0:n-k+i-1] from the left. a[(m-k+i)*lda+n-k+i] = 1 impl.Dlarf(blas.Left, m-k+i+1, n-k+i, a[n-k+i:], lda, tau[i], a, lda, work) a[(m-k+i)*lda+n-k+i] = aii } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgeqp3.go000066400000000000000000000113241450372207100217310ustar00rootroot00000000000000// 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 ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dgeqp3 computes a QR factorization with column pivoting of the // m×n matrix A: A*P = Q*R using Level 3 BLAS. // // The matrix Q is represented as a product of elementary reflectors // // Q = H_0 H_1 . . . H_{k-1}, where k = min(m,n). // // Each H_i has the form // // H_i = I - tau * v * vᵀ // // where tau and v are real vectors with v[0:i-1] = 0 and v[i] = 1; // v[i:m] is stored on exit in A[i:m, i], and tau in tau[i]. // // jpvt specifies a column pivot to be applied to A. If // jpvt[j] is at least zero, the jth column of A is permuted // to the front of A*P (a leading column), if jpvt[j] is -1 // the jth column of A is a free column. If jpvt[j] < -1, Dgeqp3 // will panic. On return, jpvt holds the permutation that was // applied; the jth column of A*P was the jpvt[j] column of A. // jpvt must have length n or Dgeqp3 will panic. // // tau holds the scalar factors of the elementary reflectors. // It must have length min(m, n), otherwise Dgeqp3 will panic. // // work must have length at least max(1,lwork), and lwork must be at least // 3*n+1, otherwise Dgeqp3 will panic. For optimal performance lwork must // be at least 2*n+(n+1)*nb, where nb is the optimal blocksize. On return, // work[0] will contain the optimal value of lwork. // // If lwork == -1, instead of performing Dgeqp3, only the optimal value of lwork // will be stored in work[0]. // // Dgeqp3 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgeqp3(m, n int, a []float64, lda int, jpvt []int, tau, work []float64, lwork int) { const ( inb = 1 inbmin = 2 ixover = 3 ) minmn := min(m, n) iws := 3*n + 1 if minmn == 0 { iws = 1 } switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < iws && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if minmn == 0 { work[0] = 1 return } nb := impl.Ilaenv(inb, "DGEQRF", " ", m, n, -1, -1) if lwork == -1 { work[0] = float64(2*n + (n+1)*nb) return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(jpvt) != n: panic(badLenJpvt) case len(tau) < minmn: panic(shortTau) } for _, v := range jpvt { if v < -1 || n <= v { panic(badJpvt) } } bi := blas64.Implementation() // Move initial columns up front. var nfxd int for j := 0; j < n; j++ { if jpvt[j] == -1 { jpvt[j] = j continue } if j != nfxd { bi.Dswap(m, a[j:], lda, a[nfxd:], lda) jpvt[j], jpvt[nfxd] = jpvt[nfxd], j } else { jpvt[j] = j } nfxd++ } // Factorize nfxd columns. // // Compute the QR factorization of nfxd columns and update remaining columns. if nfxd > 0 { na := min(m, nfxd) impl.Dgeqrf(m, na, a, lda, tau, work, lwork) iws = max(iws, int(work[0])) if na < n { impl.Dormqr(blas.Left, blas.Trans, m, n-na, na, a, lda, tau[:na], a[na:], lda, work, lwork) iws = max(iws, int(work[0])) } } if nfxd >= minmn { work[0] = float64(iws) return } // Factorize free columns. sm := m - nfxd sn := n - nfxd sminmn := minmn - nfxd // Determine the block size. nb = impl.Ilaenv(inb, "DGEQRF", " ", sm, sn, -1, -1) nbmin := 2 nx := 0 if 1 < nb && nb < sminmn { // Determine when to cross over from blocked to unblocked code. nx = max(0, impl.Ilaenv(ixover, "DGEQRF", " ", sm, sn, -1, -1)) if nx < sminmn { // Determine if workspace is large enough for blocked code. minws := 2*sn + (sn+1)*nb iws = max(iws, minws) if lwork < minws { // Not enough workspace to use optimal nb. Reduce // nb and determine the minimum value of nb. nb = (lwork - 2*sn) / (sn + 1) nbmin = max(2, impl.Ilaenv(inbmin, "DGEQRF", " ", sm, sn, -1, -1)) } } } // Initialize partial column norms. // The first n elements of work store the exact column norms. for j := nfxd; j < n; j++ { work[j] = bi.Dnrm2(sm, a[nfxd*lda+j:], lda) work[n+j] = work[j] } j := nfxd if nbmin <= nb && nb < sminmn && nx < sminmn { // Use blocked code initially. // Compute factorization. var fjb int for topbmn := minmn - nx; j < topbmn; j += fjb { jb := min(nb, topbmn-j) // Factorize jb columns among columns j:n. fjb = impl.Dlaqps(m, n-j, j, jb, a[j:], lda, jpvt[j:], tau[j:], work[j:n], work[j+n:2*n], work[2*n:2*n+jb], work[2*n+jb:], jb) } } // Use unblocked code to factor the last or only block. if j < minmn { impl.Dlaqp2(m, n-j, j, a[j:], lda, jpvt[j:], tau[j:], work[j:n], work[j+n:2*n], work[2*n:]) } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgeqr2.go000066400000000000000000000042111450372207100217270ustar00rootroot00000000000000// 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/blas" // Dgeqr2 computes a QR factorization of the m×n matrix A. // // In a QR factorization, Q is an m×m orthonormal matrix, and R is an // upper triangular m×n matrix. // // A is modified to contain the information to construct Q and R. // The upper triangle of a contains the matrix R. The lower triangular elements // (not including the diagonal) contain the elementary reflectors. tau is modified // to contain the reflector scales. tau must have length at least min(m,n), and // this function will panic otherwise. // // The ith elementary reflector can be explicitly constructed by first extracting // the // // v[j] = 0 j < i // v[j] = 1 j == i // v[j] = a[j*lda+i] j > i // // and computing H_i = I - tau[i] * v * vᵀ. // // The orthonormal matrix Q can be constructed from a product of these elementary // reflectors, Q = H_0 * H_1 * ... * H_{k-1}, where k = min(m,n). // // work is temporary storage of length at least n and this function will panic otherwise. // // Dgeqr2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgeqr2(m, n int, a []float64, lda int, tau, work []float64) { // TODO(btracey): This is oriented such that columns of a are eliminated. // This likely could be re-arranged to take better advantage of row-major // storage. switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case len(work) < n: panic(shortWork) } // Quick return if possible. k := min(m, n) if k == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) } for i := 0; i < k; i++ { // Generate elementary reflector H_i. a[i*lda+i], tau[i] = impl.Dlarfg(m-i, a[i*lda+i], a[min((i+1), m-1)*lda+i:], lda) if i < n-1 { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(blas.Left, m-i, n-i-1, a[i*lda+i:], lda, tau[i], a[i*lda+i+1:], lda, work) a[i*lda+i] = aii } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgeqrf.go000066400000000000000000000061111450372207100220140ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dgeqrf computes the QR factorization of the m×n matrix A using a blocked // algorithm. See the documentation for Dgeqr2 for a description of the // parameters at entry and exit. // // work is temporary storage, and lwork specifies the usable memory length. // The length of work must be at least max(1, lwork) and lwork must be -1 // or at least n, otherwise this function will panic. // Dgeqrf is a blocked QR factorization, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Dgeqrf, // the optimal work length will be stored into work[0]. // // tau must have length at least min(m,n), and this function will panic otherwise. func (impl Implementation) Dgeqrf(m, n int, a []float64, lda int, tau, work []float64, lwork int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < max(1, n) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. k := min(m, n) if k == 0 { work[0] = 1 return } // nb is the optimal blocksize, i.e. the number of columns transformed at a time. nb := impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1) if lwork == -1 { work[0] = float64(n * nb) return } if len(a) < (m-1)*lda+n { panic(shortA) } if len(tau) < k { panic(shortTau) } nbmin := 2 // Minimal block size. var nx int // Use unblocked (unless changed in the next for loop) iws := n // Only consider blocked if the suggested block size is > 1 and the // number of rows or columns is sufficiently large. if 1 < nb && nb < k { // nx is the block size at which the code switches from blocked // to unblocked. nx = max(0, impl.Ilaenv(3, "DGEQRF", " ", m, n, -1, -1)) if k > nx { iws = n * nb if lwork < iws { // Not enough workspace to use the optimal block // size. Get the minimum block size instead. nb = lwork / n nbmin = max(2, impl.Ilaenv(2, "DGEQRF", " ", m, n, -1, -1)) } } } // Compute QR using a blocked algorithm. var i int if nbmin <= nb && nb < k && nx < k { ldwork := nb for i = 0; i < k-nx; i += nb { ib := min(k-i, nb) // Compute the QR factorization of the current block. impl.Dgeqr2(m-i, ib, a[i*lda+i:], lda, tau[i:], work) if i+ib < n { // Form the triangular factor of the block reflector and apply Hᵀ // In Dlarft, work becomes the T matrix. impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib, a[i*lda+i:], lda, tau[i:], work, ldwork) impl.Dlarfb(blas.Left, blas.Trans, lapack.Forward, lapack.ColumnWise, m-i, n-i-ib, ib, a[i*lda+i:], lda, work, ldwork, a[i*lda+i+ib:], lda, work[ib*ldwork:], ldwork) } } } // Call unblocked code on the remaining columns. if i < k { impl.Dgeqr2(m-i, n-i, a[i*lda+i:], lda, tau[i:], work) } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgerq2.go000066400000000000000000000036111450372207100217320ustar00rootroot00000000000000// 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 "gonum.org/v1/gonum/blas" // Dgerq2 computes an RQ factorization of the m×n matrix A, // // A = R * Q. // // On exit, if m <= n, the upper triangle of the subarray // A[0:m, n-m:n] contains the m×m upper triangular matrix R. // If m >= n, the elements on and above the (m-n)-th subdiagonal // contain the m×n upper trapezoidal matrix R. // The remaining elements, with tau, represent the // orthogonal matrix Q as a product of min(m,n) elementary // reflectors. // // The matrix Q is represented as a product of elementary reflectors // // Q = H_0 H_1 . . . H_{min(m,n)-1}. // // Each H(i) has the form // // H_i = I - tau_i * v * vᵀ // // where v is a vector with v[0:n-k+i-1] stored in A[m-k+i, 0:n-k+i-1], // v[n-k+i:n] = 0 and v[n-k+i] = 1. // // tau must have length min(m,n) and work must have length m, otherwise // Dgerq2 will panic. // // Dgerq2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgerq2(m, n int, a []float64, lda int, tau, work []float64) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case len(work) < m: panic(shortWork) } // Quick return if possible. k := min(m, n) if k == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) } for i := k - 1; i >= 0; i-- { // Generate elementary reflector H[i] to annihilate // A[m-k+i, 0:n-k+i-1]. mki := m - k + i nki := n - k + i var aii float64 aii, tau[i] = impl.Dlarfg(nki+1, a[mki*lda+nki], a[mki*lda:], 1) // Apply H[i] to A[0:m-k+i-1, 0:n-k+i] from the right. a[mki*lda+nki] = 1 impl.Dlarf(blas.Right, mki, nki+1, a[mki*lda:], 1, tau[i], a, lda, work) a[mki*lda+nki] = aii } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgerqf.go000066400000000000000000000067301450372207100220230ustar00rootroot00000000000000// 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 ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/lapack" ) // Dgerqf computes an RQ factorization of the m×n matrix A, // // A = R * Q. // // On exit, if m <= n, the upper triangle of the subarray // A[0:m, n-m:n] contains the m×m upper triangular matrix R. // If m >= n, the elements on and above the (m-n)-th subdiagonal // contain the m×n upper trapezoidal matrix R. // The remaining elements, with tau, represent the // orthogonal matrix Q as a product of min(m,n) elementary // reflectors. // // The matrix Q is represented as a product of elementary reflectors // // Q = H_0 H_1 . . . H_{min(m,n)-1}. // // Each H(i) has the form // // H_i = I - tau_i * v * vᵀ // // where v is a vector with v[0:n-k+i-1] stored in A[m-k+i, 0:n-k+i-1], // v[n-k+i:n] = 0 and v[n-k+i] = 1. // // tau must have length min(m,n), work must have length max(1, lwork), // and lwork must be -1 or at least max(1, m), otherwise Dgerqf will panic. // On exit, work[0] will contain the optimal length for work. // // Dgerqf is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgerqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < max(1, m) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. k := min(m, n) if k == 0 { work[0] = 1 return } nb := impl.Ilaenv(1, "DGERQF", " ", m, n, -1, -1) if lwork == -1 { work[0] = float64(m * nb) return } if len(a) < (m-1)*lda+n { panic(shortA) } if len(tau) != k { panic(badLenTau) } nbmin := 2 nx := 1 iws := m var ldwork int if 1 < nb && nb < k { // Determine when to cross over from blocked to unblocked code. nx = max(0, impl.Ilaenv(3, "DGERQF", " ", m, n, -1, -1)) if nx < k { // Determine whether workspace is large enough for blocked code. iws = m * nb if lwork < iws { // Not enough workspace to use optimal nb. Reduce // nb and determine the minimum value of nb. nb = lwork / m nbmin = max(2, impl.Ilaenv(2, "DGERQF", " ", m, n, -1, -1)) } ldwork = nb } } var mu, nu int if nbmin <= nb && nb < k && nx < k { // Use blocked code initially. // The last kk rows are handled by the block method. ki := ((k - nx - 1) / nb) * nb kk := min(k, ki+nb) var i int for i = k - kk + ki; i >= k-kk; i -= nb { ib := min(k-i, nb) // Compute the RQ factorization of the current block // A[m-k+i:m-k+i+ib-1, 0:n-k+i+ib-1]. impl.Dgerq2(ib, n-k+i+ib, a[(m-k+i)*lda:], lda, tau[i:], work) if m-k+i > 0 { // Form the triangular factor of the block reflector // H = H_{i+ib-1} . . . H_{i+1} H_i. impl.Dlarft(lapack.Backward, lapack.RowWise, n-k+i+ib, ib, a[(m-k+i)*lda:], lda, tau[i:], work, ldwork) // Apply H to A[0:m-k+i-1, 0:n-k+i+ib-1] from the right. impl.Dlarfb(blas.Right, blas.NoTrans, lapack.Backward, lapack.RowWise, m-k+i, n-k+i+ib, ib, a[(m-k+i)*lda:], lda, work, ldwork, a, lda, work[ib*ldwork:], ldwork) } } mu = m - k + i + nb nu = n - k + i + nb } else { mu = m nu = n } // Use unblocked code to factor the last or only block. if mu > 0 && nu > 0 { impl.Dgerq2(mu, nu, a, lda, tau, work) } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgesc2.go000066400000000000000000000036671450372207100217300ustar00rootroot00000000000000// Copyright ©2021 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/blas64" ) // Dgesc2 solves a system of linear equations // // A * x = scale * b // // with a general n×n matrix A represented by the LU factorization with complete // pivoting // // A = P * L * U * Q // // as computed by Dgetc2. // // On entry, rhs contains the right hand side vector b. On return, it is // overwritten with the solution vector x. // // Dgesc2 returns a scale factor // // 0 <= scale <= 1 // // chosen to prevent overflow in the solution. // // Dgesc2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgesc2(n int, a []float64, lda int, rhs []float64, ipiv, jpiv []int) (scale float64) { switch { case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return 0 } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(rhs) < n: panic(shortRHS) case len(ipiv) != n: panic(badLenIpiv) case len(jpiv) != n: panic(badLenJpiv) } const smlnum = dlamchS / dlamchP // Apply permutations ipiv to rhs. impl.Dlaswp(1, rhs, 1, 0, n-1, ipiv[:n], 1) // Solve for L part. for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { rhs[j] -= float64(a[j*lda+i] * rhs[i]) } } // Check for scaling. scale = 1.0 bi := blas64.Implementation() i := bi.Idamax(n, rhs, 1) if 2*smlnum*math.Abs(rhs[i]) > math.Abs(a[(n-1)*lda+(n-1)]) { temp := 0.5 / math.Abs(rhs[i]) bi.Dscal(n, temp, rhs, 1) scale *= temp } // Solve for U part. for i := n - 1; i >= 0; i-- { temp := 1.0 / a[i*lda+i] rhs[i] *= temp for j := i + 1; j < n; j++ { rhs[i] -= float64(rhs[j] * (a[i*lda+j] * temp)) } } // Apply permutations jpiv to the solution (rhs). impl.Dlaswp(1, rhs, 1, 0, n-1, jpiv[:n], -1) return scale } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgesv.go000066400000000000000000000030471450372207100216610ustar00rootroot00000000000000// Copyright ©2021 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" // Dgesv computes the solution to a real system of linear equations // // A * X = B // // where A is an n×n matrix and X and B are n×nrhs matrices. // // The LU decomposition with partial pivoting and row interchanges is used to // factor A as // // A = P * L * U // // where P is a permutation matrix, L is unit lower triangular, and U is upper // triangular. On return, the factors L and U are stored in a; the unit diagonal // elements of L are not stored. The row pivot indices that define the // permutation matrix P are stored in ipiv. // // The factored form of A is then used to solve the system of equations A * X = // B. On entry, b contains the right hand side matrix B. On return, if ok is // true, b contains the solution matrix X. func (impl Implementation) Dgesv(n, nrhs int, a []float64, lda int, ipiv []int, b []float64, ldb int) (ok bool) { switch { case n < 0: panic(nLT0) case nrhs < 0: panic(nrhsLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, nrhs): panic(badLdB) } // Quick return if possible. if n == 0 || nrhs == 0 { return true } switch { case len(a) < (n-1)*lda+n: panic(shortAB) case len(ipiv) != n: panic(badLenIpiv) case len(b) < (n-1)*ldb+nrhs: panic(shortB) } ok = impl.Dgetrf(n, n, a, lda, ipiv) if ok { impl.Dgetrs(blas.NoTrans, n, nrhs, a, lda, ipiv, b, ldb) } return ok } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgesvd.go000066400000000000000000001310121450372207100220170ustar00rootroot00000000000000// 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) const noSVDO = "dgesvd: not coded for overwrite" // Dgesvd computes the singular value decomposition of the input matrix A. // // The singular value decomposition is // // A = U * Sigma * Vᵀ // // where Sigma is an m×n diagonal matrix containing the singular values of A, // U is an m×m orthogonal matrix and V is an n×n orthogonal matrix. The first // min(m,n) columns of U and V are the left and right singular vectors of A // respectively. // // jobU and jobVT are options for computing the singular vectors. The behavior // is as follows // // jobU == lapack.SVDAll All m columns of U are returned in u // jobU == lapack.SVDStore The first min(m,n) columns are returned in u // jobU == lapack.SVDOverwrite The first min(m,n) columns of U are written into a // jobU == lapack.SVDNone The columns of U are not computed. // // The behavior is the same for jobVT and the rows of Vᵀ. At most one of jobU // and jobVT can equal lapack.SVDOverwrite, and Dgesvd will panic otherwise. // // On entry, a contains the data for the m×n matrix A. During the call to Dgesvd // the data is overwritten. On exit, A contains the appropriate singular vectors // if either job is lapack.SVDOverwrite. // // s is a slice of length at least min(m,n) and on exit contains the singular // values in decreasing order. // // u contains the left singular vectors on exit, stored column-wise. If // jobU == lapack.SVDAll, u is of size m×m. If jobU == lapack.SVDStore u is // of size m×min(m,n). If jobU == lapack.SVDOverwrite or lapack.SVDNone, u is // not used. // // vt contains the left singular vectors on exit, stored row-wise. If // jobV == lapack.SVDAll, vt is of size n×n. If jobVT == lapack.SVDStore vt is // of size min(m,n)×n. If jobVT == lapack.SVDOverwrite or lapack.SVDNone, vt is // not used. // // work is a slice for storing temporary memory, and lwork is the usable size of // the slice. lwork must be at least max(5*min(m,n), 3*min(m,n)+max(m,n)). // If lwork == -1, instead of performing Dgesvd, the optimal work length will be // stored into work[0]. Dgesvd will panic if the working memory has insufficient // storage. // // Dgesvd returns whether the decomposition successfully completed. func (impl Implementation) Dgesvd(jobU, jobVT lapack.SVDJob, m, n int, a []float64, lda int, s, u []float64, ldu int, vt []float64, ldvt int, work []float64, lwork int) (ok bool) { if jobU == lapack.SVDOverwrite || jobVT == lapack.SVDOverwrite { panic(noSVDO) } wantua := jobU == lapack.SVDAll wantus := jobU == lapack.SVDStore wantuas := wantua || wantus wantuo := jobU == lapack.SVDOverwrite wantun := jobU == lapack.SVDNone if !(wantua || wantus || wantuo || wantun) { panic(badSVDJob) } wantva := jobVT == lapack.SVDAll wantvs := jobVT == lapack.SVDStore wantvas := wantva || wantvs wantvo := jobVT == lapack.SVDOverwrite wantvn := jobVT == lapack.SVDNone if !(wantva || wantvs || wantvo || wantvn) { panic(badSVDJob) } if wantuo && wantvo { panic(bothSVDOver) } minmn := min(m, n) minwork := 1 if minmn > 0 { minwork = max(3*minmn+max(m, n), 5*minmn) } switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case ldu < 1, wantua && ldu < m, wantus && ldu < minmn: panic(badLdU) case ldvt < 1 || (wantvas && ldvt < n): panic(badLdVT) case lwork < minwork && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if minmn == 0 { work[0] = 1 return true } // Compute optimal workspace size for subroutines. opts := string(jobU) + string(jobVT) mnthr := impl.Ilaenv(6, "DGESVD", opts, m, n, 0, 0) maxwrk := 1 var wrkbl, bdspac int if m >= n { bdspac = 5 * n impl.Dgeqrf(m, n, a, lda, nil, work, -1) lwork_dgeqrf := int(work[0]) impl.Dorgqr(m, n, n, a, lda, nil, work, -1) lwork_dorgqr_n := int(work[0]) impl.Dorgqr(m, m, n, a, lda, nil, work, -1) lwork_dorgqr_m := int(work[0]) impl.Dgebrd(n, n, a, lda, s, nil, nil, nil, work, -1) lwork_dgebrd := int(work[0]) impl.Dorgbr(lapack.GeneratePT, n, n, n, a, lda, nil, work, -1) lwork_dorgbr_p := int(work[0]) impl.Dorgbr(lapack.GenerateQ, n, n, n, a, lda, nil, work, -1) lwork_dorgbr_q := int(work[0]) if m >= mnthr { if wantun { // Path 1 (m much larger than n, jobU == None) maxwrk = n + lwork_dgeqrf maxwrk = max(maxwrk, 3*n+lwork_dgebrd) if wantvo || wantvas { maxwrk = max(maxwrk, 3*n+lwork_dorgbr_p) } maxwrk = max(maxwrk, bdspac) } else if wantuo && wantvn { // Path 2 (m much larger than n, jobU == Overwrite, jobVT == None) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_n) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = max(n*n+wrkbl, n*n+m*n+n) } else if wantuo && wantvas { // Path 3 (m much larger than n, jobU == Overwrite, jobVT == Store or All) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_n) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = max(n*n+wrkbl, n*n+m*n+n) } else if wantus && wantvn { // Path 4 (m much larger than n, jobU == Store, jobVT == None) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_n) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = n*n + wrkbl } else if wantus && wantvo { // Path 5 (m much larger than n, jobU == Store, jobVT == Overwrite) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_n) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = 2*n*n + wrkbl } else if wantus && wantvas { // Path 6 (m much larger than n, jobU == Store, jobVT == Store or All) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_n) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = n*n + wrkbl } else if wantua && wantvn { // Path 7 (m much larger than n, jobU == All, jobVT == None) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_m) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = n*n + wrkbl } else if wantua && wantvo { // Path 8 (m much larger than n, jobU == All, jobVT == Overwrite) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_m) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = 2*n*n + wrkbl } else if wantua && wantvas { // Path 9 (m much larger than n, jobU == All, jobVT == Store or All) wrkbl = n + lwork_dgeqrf wrkbl = max(wrkbl, n+lwork_dorgqr_m) wrkbl = max(wrkbl, 3*n+lwork_dgebrd) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_q) wrkbl = max(wrkbl, 3*n+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = n*n + wrkbl } } else { // Path 10 (m at least n, but not much larger) impl.Dgebrd(m, n, a, lda, s, nil, nil, nil, work, -1) lwork_dgebrd := int(work[0]) maxwrk = 3*n + lwork_dgebrd if wantus || wantuo { impl.Dorgbr(lapack.GenerateQ, m, n, n, a, lda, nil, work, -1) lwork_dorgbr_q = int(work[0]) maxwrk = max(maxwrk, 3*n+lwork_dorgbr_q) } if wantua { impl.Dorgbr(lapack.GenerateQ, m, m, n, a, lda, nil, work, -1) lwork_dorgbr_q := int(work[0]) maxwrk = max(maxwrk, 3*n+lwork_dorgbr_q) } if !wantvn { maxwrk = max(maxwrk, 3*n+lwork_dorgbr_p) } maxwrk = max(maxwrk, bdspac) } } else { bdspac = 5 * m impl.Dgelqf(m, n, a, lda, nil, work, -1) lwork_dgelqf := int(work[0]) impl.Dorglq(n, n, m, nil, n, nil, work, -1) lwork_dorglq_n := int(work[0]) impl.Dorglq(m, n, m, a, lda, nil, work, -1) lwork_dorglq_m := int(work[0]) impl.Dgebrd(m, m, a, lda, s, nil, nil, nil, work, -1) lwork_dgebrd := int(work[0]) impl.Dorgbr(lapack.GeneratePT, m, m, m, a, n, nil, work, -1) lwork_dorgbr_p := int(work[0]) impl.Dorgbr(lapack.GenerateQ, m, m, m, a, n, nil, work, -1) lwork_dorgbr_q := int(work[0]) if n >= mnthr { if wantvn { // Path 1t (n much larger than m, jobVT == None) maxwrk = m + lwork_dgelqf maxwrk = max(maxwrk, 3*m+lwork_dgebrd) if wantuo || wantuas { maxwrk = max(maxwrk, 3*m+lwork_dorgbr_q) } maxwrk = max(maxwrk, bdspac) } else if wantvo && wantun { // Path 2t (n much larger than m, jobU == None, jobVT == Overwrite) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_m) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = max(m*m+wrkbl, m*m+m*n+m) } else if wantvo && wantuas { // Path 3t (n much larger than m, jobU == Store or All, jobVT == Overwrite) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_m) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = max(m*m+wrkbl, m*m+m*n+m) } else if wantvs && wantun { // Path 4t (n much larger than m, jobU == None, jobVT == Store) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_m) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = m*m + wrkbl } else if wantvs && wantuo { // Path 5t (n much larger than m, jobU == Overwrite, jobVT == Store) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_m) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = 2*m*m + wrkbl } else if wantvs && wantuas { // Path 6t (n much larger than m, jobU == Store or All, jobVT == Store) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_m) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = m*m + wrkbl } else if wantva && wantun { // Path 7t (n much larger than m, jobU== None, jobVT == All) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_n) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, bdspac) maxwrk = m*m + wrkbl } else if wantva && wantuo { // Path 8t (n much larger than m, jobU == Overwrite, jobVT == All) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_n) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = 2*m*m + wrkbl } else if wantva && wantuas { // Path 9t (n much larger than m, jobU == Store or All, jobVT == All) wrkbl = m + lwork_dgelqf wrkbl = max(wrkbl, m+lwork_dorglq_n) wrkbl = max(wrkbl, 3*m+lwork_dgebrd) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_p) wrkbl = max(wrkbl, 3*m+lwork_dorgbr_q) wrkbl = max(wrkbl, bdspac) maxwrk = m*m + wrkbl } } else { // Path 10t (n greater than m, but not much larger) impl.Dgebrd(m, n, a, lda, s, nil, nil, nil, work, -1) lwork_dgebrd = int(work[0]) maxwrk = 3*m + lwork_dgebrd if wantvs || wantvo { impl.Dorgbr(lapack.GeneratePT, m, n, m, a, n, nil, work, -1) lwork_dorgbr_p = int(work[0]) maxwrk = max(maxwrk, 3*m+lwork_dorgbr_p) } if wantva { impl.Dorgbr(lapack.GeneratePT, n, n, m, a, n, nil, work, -1) lwork_dorgbr_p = int(work[0]) maxwrk = max(maxwrk, 3*m+lwork_dorgbr_p) } if !wantun { maxwrk = max(maxwrk, 3*m+lwork_dorgbr_q) } maxwrk = max(maxwrk, bdspac) } } maxwrk = max(maxwrk, minwork) if lwork == -1 { work[0] = float64(maxwrk) return true } if len(a) < (m-1)*lda+n { panic(shortA) } if len(s) < minmn { panic(shortS) } if (len(u) < (m-1)*ldu+m && wantua) || (len(u) < (m-1)*ldu+minmn && wantus) { panic(shortU) } if (len(vt) < (n-1)*ldvt+n && wantva) || (len(vt) < (minmn-1)*ldvt+n && wantvs) { panic(shortVT) } // Perform decomposition. eps := dlamchE smlnum := math.Sqrt(dlamchS) / eps bignum := 1 / smlnum // Scale A if max element outside range [smlnum, bignum]. anrm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, nil) var iscl bool if anrm > 0 && anrm < smlnum { iscl = true impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, m, n, a, lda) } else if anrm > bignum { iscl = true impl.Dlascl(lapack.General, 0, 0, anrm, bignum, m, n, a, lda) } bi := blas64.Implementation() var ie int if m >= n { // If A has sufficiently more rows than columns, use the QR decomposition. if m >= mnthr { // m >> n if wantun { // Path 1. itau := 0 iwork := itau + n // Compute A = Q * R. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) // Zero out below R. impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, a[lda:], lda) ie = 0 itauq := ie + n itaup := itauq + n iwork = itaup + n // Bidiagonalize R in A. impl.Dgebrd(n, n, a, lda, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) ncvt := 0 if wantvo || wantvas { impl.Dorgbr(lapack.GeneratePT, n, n, n, a, lda, work[itaup:], work[iwork:], lwork-iwork) ncvt = n } iwork = ie + n // Perform bidiagonal QR iteration computing right singular vectors // of A in A if desired. ok = impl.Dbdsqr(blas.Upper, n, ncvt, 0, 0, s, work[ie:], a, lda, work, 1, work, 1, work[iwork:]) // If right singular vectors desired in VT, copy them there. if wantvas { impl.Dlacpy(blas.All, n, n, a, lda, vt, ldvt) } } else if wantuo && wantvn { // Path 2 panic(noSVDO) } else if wantuo && wantvas { // Path 3 panic(noSVDO) } else if wantus { if wantvn { // Path 4 if lwork >= n*n+max(4*n, bdspac) { // Sufficient workspace for a fast algorithm. ir := 0 var ldworkr int if lwork >= wrkbl+lda*n { ldworkr = lda } else { ldworkr = n } itau := ir + ldworkr*n iwork := itau + n // Compute A = Q * R. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) // Copy R to work[ir:], zeroing out below it. impl.Dlacpy(blas.Upper, n, n, a, lda, work[ir:], ldworkr) impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, work[ir+ldworkr:], ldworkr) // Generate Q in A. impl.Dorgqr(m, n, n, a, lda, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Bidiagonalize R in work[ir:]. impl.Dgebrd(n, n, work[ir:], ldworkr, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Generate left vectors bidiagonalizing R in work[ir:]. impl.Dorgbr(lapack.GenerateQ, n, n, n, work[ir:], ldworkr, work[itauq:], work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left singular // vectors of R in work[ir:]. ok = impl.Dbdsqr(blas.Upper, n, 0, n, 0, s, work[ie:], work, 1, work[ir:], ldworkr, work, 1, work[iwork:]) // Multiply Q in A by left singular vectors of R in // work[ir:], storing result in U. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, n, 1, a, lda, work[ir:], ldworkr, 0, u, ldu) } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + n // Compute A = Q*R, copying result to U. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, n, a, lda, u, ldu) // Generate Q in U. impl.Dorgqr(m, n, n, u, ldu, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Zero out below R in A. impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, a[lda:], lda) // Bidiagonalize R in A. impl.Dgebrd(n, n, a, lda, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply Q in U by left vectors bidiagonalizing R. impl.Dormbr(lapack.ApplyQ, blas.Right, blas.NoTrans, m, n, n, a, lda, work[itauq:], u, ldu, work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left // singular vectors of A in U. ok = impl.Dbdsqr(blas.Upper, n, 0, m, 0, s, work[ie:], work, 1, u, ldu, work, 1, work[iwork:]) } } else if wantvo { // Path 5 panic(noSVDO) } else if wantvas { // Path 6 if lwork >= n*n+max(4*n, bdspac) { // Sufficient workspace for a fast algorithm. iu := 0 var ldworku int if lwork >= wrkbl+lda*n { ldworku = lda } else { ldworku = n } itau := iu + ldworku*n iwork := itau + n // Compute A = Q * R. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) // Copy R to work[iu:], zeroing out below it. impl.Dlacpy(blas.Upper, n, n, a, lda, work[iu:], ldworku) impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, work[iu+ldworku:], ldworku) // Generate Q in A. impl.Dorgqr(m, n, n, a, lda, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Bidiagonalize R in work[iu:], copying result to VT. impl.Dgebrd(n, n, work[iu:], ldworku, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Upper, n, n, work[iu:], ldworku, vt, ldvt) // Generate left bidiagonalizing vectors in work[iu:]. impl.Dorgbr(lapack.GenerateQ, n, n, n, work[iu:], ldworku, work[itauq:], work[iwork:], lwork-iwork) // Generate right bidiagonalizing vectors in VT. impl.Dorgbr(lapack.GeneratePT, n, n, n, vt, ldvt, work[itaup:], work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left singular // vectors of R in work[iu:], and computing right singular // vectors of R in VT. ok = impl.Dbdsqr(blas.Upper, n, n, n, 0, s, work[ie:], vt, ldvt, work[iu:], ldworku, work, 1, work[iwork:]) // Multiply Q in A by left singular vectors of R in // work[iu:], storing result in U. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, n, 1, a, lda, work[iu:], ldworku, 0, u, ldu) } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + n // Compute A = Q * R, copying result to U. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, n, a, lda, u, ldu) // Generate Q in U. impl.Dorgqr(m, n, n, u, ldu, work[itau:], work[iwork:], lwork-iwork) // Copy R to VT, zeroing out below it. impl.Dlacpy(blas.Upper, n, n, a, lda, vt, ldvt) impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, vt[ldvt:], ldvt) ie := itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Bidiagonalize R in VT. impl.Dgebrd(n, n, vt, ldvt, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply Q in U by left bidiagonalizing vectors in VT. impl.Dormbr(lapack.ApplyQ, blas.Right, blas.NoTrans, m, n, n, vt, ldvt, work[itauq:], u, ldu, work[iwork:], lwork-iwork) // Generate right bidiagonalizing vectors in VT. impl.Dorgbr(lapack.GeneratePT, n, n, n, vt, ldvt, work[itaup:], work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left singular // vectors of A in U and computing right singular vectors // of A in VT. ok = impl.Dbdsqr(blas.Upper, n, n, m, 0, s, work[ie:], vt, ldvt, u, ldu, work, 1, work[iwork:]) } } } else if wantua { if wantvn { // Path 7 if lwork >= n*n+max(max(n+m, 4*n), bdspac) { // Sufficient workspace for a fast algorithm. ir := 0 var ldworkr int if lwork >= wrkbl+lda*n { ldworkr = lda } else { ldworkr = n } itau := ir + ldworkr*n iwork := itau + n // Compute A = Q*R, copying result to U. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, n, a, lda, u, ldu) // Copy R to work[ir:], zeroing out below it. impl.Dlacpy(blas.Upper, n, n, a, lda, work[ir:], ldworkr) impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, work[ir+ldworkr:], ldworkr) // Generate Q in U. impl.Dorgqr(m, m, n, u, ldu, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Bidiagonalize R in work[ir:]. impl.Dgebrd(n, n, work[ir:], ldworkr, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Generate left bidiagonalizing vectors in work[ir:]. impl.Dorgbr(lapack.GenerateQ, n, n, n, work[ir:], ldworkr, work[itauq:], work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left singular // vectors of R in work[ir:]. ok = impl.Dbdsqr(blas.Upper, n, 0, n, 0, s, work[ie:], work, 1, work[ir:], ldworkr, work, 1, work[iwork:]) // Multiply Q in U by left singular vectors of R in // work[ir:], storing result in A. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, n, 1, u, ldu, work[ir:], ldworkr, 0, a, lda) // Copy left singular vectors of A from A to U. impl.Dlacpy(blas.All, m, n, a, lda, u, ldu) } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + n // Compute A = Q*R, copying result to U. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, n, a, lda, u, ldu) // Generate Q in U. impl.Dorgqr(m, m, n, u, ldu, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Zero out below R in A. impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, a[lda:], lda) // Bidiagonalize R in A. impl.Dgebrd(n, n, a, lda, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply Q in U by left bidiagonalizing vectors in A. impl.Dormbr(lapack.ApplyQ, blas.Right, blas.NoTrans, m, n, n, a, lda, work[itauq:], u, ldu, work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left // singular vectors of A in U. ok = impl.Dbdsqr(blas.Upper, n, 0, m, 0, s, work[ie:], work, 1, u, ldu, work, 1, work[iwork:]) } } else if wantvo { // Path 8. panic(noSVDO) } else if wantvas { // Path 9. if lwork >= n*n+max(max(n+m, 4*n), bdspac) { // Sufficient workspace for a fast algorithm. iu := 0 var ldworku int if lwork >= wrkbl+lda*n { ldworku = lda } else { ldworku = n } itau := iu + ldworku*n iwork := itau + n // Compute A = Q * R, copying result to U. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, n, a, lda, u, ldu) // Generate Q in U. impl.Dorgqr(m, m, n, u, ldu, work[itau:], work[iwork:], lwork-iwork) // Copy R to work[iu:], zeroing out below it. impl.Dlacpy(blas.Upper, n, n, a, lda, work[iu:], ldworku) impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, work[iu+ldworku:], ldworku) ie = itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Bidiagonalize R in work[iu:], copying result to VT. impl.Dgebrd(n, n, work[iu:], ldworku, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Upper, n, n, work[iu:], ldworku, vt, ldvt) // Generate left bidiagonalizing vectors in work[iu:]. impl.Dorgbr(lapack.GenerateQ, n, n, n, work[iu:], ldworku, work[itauq:], work[iwork:], lwork-iwork) // Generate right bidiagonalizing vectors in VT. impl.Dorgbr(lapack.GeneratePT, n, n, n, vt, ldvt, work[itaup:], work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left singular // vectors of R in work[iu:] and computing right // singular vectors of R in VT. ok = impl.Dbdsqr(blas.Upper, n, n, n, 0, s, work[ie:], vt, ldvt, work[iu:], ldworku, work, 1, work[iwork:]) // Multiply Q in U by left singular vectors of R in // work[iu:], storing result in A. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, n, 1, u, ldu, work[iu:], ldworku, 0, a, lda) // Copy left singular vectors of A from A to U. impl.Dlacpy(blas.All, m, n, a, lda, u, ldu) /* // Bidiagonalize R in VT. impl.Dgebrd(n, n, vt, ldvt, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply Q in U by left bidiagonalizing vectors in VT. impl.Dormbr(lapack.ApplyQ, blas.Right, blas.NoTrans, m, n, n, vt, ldvt, work[itauq:], u, ldu, work[iwork:], lwork-iwork) // Generate right bidiagonalizing vectors in VT. impl.Dorgbr(lapack.GeneratePT, n, n, n, vt, ldvt, work[itaup:], work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left singular // vectors of A in U and computing right singular vectors // of A in VT. ok = impl.Dbdsqr(blas.Upper, n, n, m, 0, s, work[ie:], vt, ldvt, u, ldu, work, 1, work[iwork:]) */ } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + n // Compute A = Q*R, copying result to U. impl.Dgeqrf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, n, a, lda, u, ldu) // Generate Q in U. impl.Dorgqr(m, m, n, u, ldu, work[itau:], work[iwork:], lwork-iwork) // Copy R from A to VT, zeroing out below it. impl.Dlacpy(blas.Upper, n, n, a, lda, vt, ldvt) if n > 1 { impl.Dlaset(blas.Lower, n-1, n-1, 0, 0, vt[ldvt:], ldvt) } ie := itau itauq := ie + n itaup := itauq + n iwork = itaup + n // Bidiagonalize R in VT. impl.Dgebrd(n, n, vt, ldvt, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply Q in U by left bidiagonalizing vectors in VT. impl.Dormbr(lapack.ApplyQ, blas.Right, blas.NoTrans, m, n, n, vt, ldvt, work[itauq:], u, ldu, work[iwork:], lwork-iwork) // Generate right bidiagonizing vectors in VT. impl.Dorgbr(lapack.GeneratePT, n, n, n, vt, ldvt, work[itaup:], work[iwork:], lwork-iwork) iwork = ie + n // Perform bidiagonal QR iteration, computing left singular // vectors of A in U and computing right singular vectors // of A in VT. ok = impl.Dbdsqr(blas.Upper, n, n, m, 0, s, work[ie:], vt, ldvt, u, ldu, work, 1, work[iwork:]) } } } } else { // Path 10. // M at least N, but not much larger. ie = 0 itauq := ie + n itaup := itauq + n iwork := itaup + n // Bidiagonalize A. impl.Dgebrd(m, n, a, lda, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) if wantuas { // Left singular vectors are desired in U. Copy result to U and // generate left biadiagonalizing vectors in U. impl.Dlacpy(blas.Lower, m, n, a, lda, u, ldu) var ncu int if wantus { ncu = n } if wantua { ncu = m } impl.Dorgbr(lapack.GenerateQ, m, ncu, n, u, ldu, work[itauq:], work[iwork:], lwork-iwork) } if wantvas { // Right singular vectors are desired in VT. Copy result to VT and // generate left biadiagonalizing vectors in VT. impl.Dlacpy(blas.Upper, n, n, a, lda, vt, ldvt) impl.Dorgbr(lapack.GeneratePT, n, n, n, vt, ldvt, work[itaup:], work[iwork:], lwork-iwork) } if wantuo { panic(noSVDO) } if wantvo { panic(noSVDO) } iwork = ie + n var nru, ncvt int if wantuas || wantuo { nru = m } if wantun { nru = 0 } if wantvas || wantvo { ncvt = n } if wantvn { ncvt = 0 } if !wantuo && !wantvo { // Perform bidiagonal QR iteration, if desired, computing left // singular vectors in U and right singular vectors in VT. ok = impl.Dbdsqr(blas.Upper, n, ncvt, nru, 0, s, work[ie:], vt, ldvt, u, ldu, work, 1, work[iwork:]) } else { // There will be two branches when the implementation is complete. panic(noSVDO) } } } else { // A has more columns than rows. If A has sufficiently more columns than // rows, first reduce using the LQ decomposition. if n >= mnthr { // n >> m. if wantvn { // Path 1t. itau := 0 iwork := itau + m // Compute A = L*Q. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) // Zero out above L. impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, a[1:], lda) ie := 0 itauq := ie + m itaup := itauq + m iwork = itaup + m // Bidiagonalize L in A. impl.Dgebrd(m, m, a, lda, s, work[ie:itauq], work[itauq:itaup], work[itaup:iwork], work[iwork:], lwork-iwork) if wantuo || wantuas { impl.Dorgbr(lapack.GenerateQ, m, m, m, a, lda, work[itauq:], work[iwork:], lwork-iwork) } iwork = ie + m nru := 0 if wantuo || wantuas { nru = m } // Perform bidiagonal QR iteration, computing left singular vectors // of A in A if desired. ok = impl.Dbdsqr(blas.Upper, m, 0, nru, 0, s, work[ie:], work, 1, a, lda, work, 1, work[iwork:]) // If left singular vectors desired in U, copy them there. if wantuas { impl.Dlacpy(blas.All, m, m, a, lda, u, ldu) } } else if wantvo && wantun { // Path 2t. panic(noSVDO) } else if wantvo && wantuas { // Path 3t. panic(noSVDO) } else if wantvs { if wantun { // Path 4t. if lwork >= m*m+max(4*m, bdspac) { // Sufficient workspace for a fast algorithm. ir := 0 var ldworkr int if lwork >= wrkbl+lda*m { ldworkr = lda } else { ldworkr = m } itau := ir + ldworkr*m iwork := itau + m // Compute A = L*Q. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) // Copy L to work[ir:], zeroing out above it. impl.Dlacpy(blas.Lower, m, m, a, lda, work[ir:], ldworkr) impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, work[ir+1:], ldworkr) // Generate Q in A. impl.Dorglq(m, n, m, a, lda, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Bidiagonalize L in work[ir:]. impl.Dgebrd(m, m, work[ir:], ldworkr, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Generate right vectors bidiagonalizing L in work[ir:]. impl.Dorgbr(lapack.GeneratePT, m, m, m, work[ir:], ldworkr, work[itaup:], work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing right singular // vectors of L in work[ir:]. ok = impl.Dbdsqr(blas.Upper, m, m, 0, 0, s, work[ie:], work[ir:], ldworkr, work, 1, work, 1, work[iwork:]) // Multiply right singular vectors of L in work[ir:] by // Q in A, storing result in VT. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, m, 1, work[ir:], ldworkr, a, lda, 0, vt, ldvt) } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + m // Compute A = L*Q. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) // Copy result to VT. impl.Dlacpy(blas.Upper, m, n, a, lda, vt, ldvt) // Generate Q in VT. impl.Dorglq(m, n, m, vt, ldvt, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Zero out above L in A. impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, a[1:], lda) // Bidiagonalize L in A. impl.Dgebrd(m, m, a, lda, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply right vectors bidiagonalizing L by Q in VT. impl.Dormbr(lapack.ApplyP, blas.Left, blas.Trans, m, n, m, a, lda, work[itaup:], vt, ldvt, work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing right // singular vectors of A in VT. ok = impl.Dbdsqr(blas.Upper, m, n, 0, 0, s, work[ie:], vt, ldvt, work, 1, work, 1, work[iwork:]) } } else if wantuo { // Path 5t. panic(noSVDO) } else if wantuas { // Path 6t. if lwork >= m*m+max(4*m, bdspac) { // Sufficient workspace for a fast algorithm. iu := 0 var ldworku int if lwork >= wrkbl+lda*m { ldworku = lda } else { ldworku = m } itau := iu + ldworku*m iwork := itau + m // Compute A = L*Q. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) // Copy L to work[iu:], zeroing out above it. impl.Dlacpy(blas.Lower, m, m, a, lda, work[iu:], ldworku) impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, work[iu+1:], ldworku) // Generate Q in A. impl.Dorglq(m, n, m, a, lda, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Bidiagonalize L in work[iu:], copying result to U. impl.Dgebrd(m, m, work[iu:], ldworku, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, m, work[iu:], ldworku, u, ldu) // Generate right bidiagionalizing vectors in work[iu:]. impl.Dorgbr(lapack.GeneratePT, m, m, m, work[iu:], ldworku, work[itaup:], work[iwork:], lwork-iwork) // Generate left bidiagonalizing vectors in U. impl.Dorgbr(lapack.GenerateQ, m, m, m, u, ldu, work[itauq:], work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing left singular // vectors of L in U and computing right singular vectors of // L in work[iu:]. ok = impl.Dbdsqr(blas.Upper, m, m, m, 0, s, work[ie:], work[iu:], ldworku, u, ldu, work, 1, work[iwork:]) // Multiply right singular vectors of L in work[iu:] by // Q in A, storing result in VT. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, m, 1, work[iu:], ldworku, a, lda, 0, vt, ldvt) } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + m // Compute A = L*Q, copying result to VT. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Upper, m, n, a, lda, vt, ldvt) // Generate Q in VT. impl.Dorglq(m, n, m, vt, ldvt, work[itau:], work[iwork:], lwork-iwork) // Copy L to U, zeroing out above it. impl.Dlacpy(blas.Lower, m, m, a, lda, u, ldu) impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, u[1:], ldu) ie := itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Bidiagonalize L in U. impl.Dgebrd(m, m, u, ldu, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply right bidiagonalizing vectors in U by Q in VT. impl.Dormbr(lapack.ApplyP, blas.Left, blas.Trans, m, n, m, u, ldu, work[itaup:], vt, ldvt, work[iwork:], lwork-iwork) // Generate left bidiagonalizing vectors in U. impl.Dorgbr(lapack.GenerateQ, m, m, m, u, ldu, work[itauq:], work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing left singular // vectors of A in U and computing right singular vectors // of A in VT. ok = impl.Dbdsqr(blas.Upper, m, n, m, 0, s, work[ie:], vt, ldvt, u, ldu, work, 1, work[iwork:]) } } } else if wantva { if wantun { // Path 7t. if lwork >= m*m+max(max(n+m, 4*m), bdspac) { // Sufficient workspace for a fast algorithm. ir := 0 var ldworkr int if lwork >= wrkbl+lda*m { ldworkr = lda } else { ldworkr = m } itau := ir + ldworkr*m iwork := itau + m // Compute A = L*Q, copying result to VT. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Upper, m, n, a, lda, vt, ldvt) // Copy L to work[ir:], zeroing out above it. impl.Dlacpy(blas.Lower, m, m, a, lda, work[ir:], ldworkr) impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, work[ir+1:], ldworkr) // Generate Q in VT. impl.Dorglq(n, n, m, vt, ldvt, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Bidiagonalize L in work[ir:]. impl.Dgebrd(m, m, work[ir:], ldworkr, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Generate right bidiagonalizing vectors in work[ir:]. impl.Dorgbr(lapack.GeneratePT, m, m, m, work[ir:], ldworkr, work[itaup:], work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing right // singular vectors of L in work[ir:]. ok = impl.Dbdsqr(blas.Upper, m, m, 0, 0, s, work[ie:], work[ir:], ldworkr, work, 1, work, 1, work[iwork:]) // Multiply right singular vectors of L in work[ir:] by // Q in VT, storing result in A. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, m, 1, work[ir:], ldworkr, vt, ldvt, 0, a, lda) // Copy right singular vectors of A from A to VT. impl.Dlacpy(blas.All, m, n, a, lda, vt, ldvt) } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + m // Compute A = L * Q, copying result to VT. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Upper, m, n, a, lda, vt, ldvt) // Generate Q in VT. impl.Dorglq(n, n, m, vt, ldvt, work[itau:], work[iwork:], lwork-iwork) ie := itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Zero out above L in A. impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, a[1:], lda) // Bidiagonalize L in A. impl.Dgebrd(m, m, a, lda, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply right bidiagonalizing vectors in A by Q in VT. impl.Dormbr(lapack.ApplyP, blas.Left, blas.Trans, m, n, m, a, lda, work[itaup:], vt, ldvt, work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing right singular // vectors of A in VT. ok = impl.Dbdsqr(blas.Upper, m, n, 0, 0, s, work[ie:], vt, ldvt, work, 1, work, 1, work[iwork:]) } } else if wantuo { panic(noSVDO) } else if wantuas { // Path 9t. if lwork >= m*m+max(max(m+n, 4*m), bdspac) { // Sufficient workspace for a fast algorithm. iu := 0 var ldworku int if lwork >= wrkbl+lda*m { ldworku = lda } else { ldworku = m } itau := iu + ldworku*m iwork := itau + m // Generate A = L * Q copying result to VT. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Upper, m, n, a, lda, vt, ldvt) // Generate Q in VT. impl.Dorglq(n, n, m, vt, ldvt, work[itau:], work[iwork:], lwork-iwork) // Copy L to work[iu:], zeroing out above it. impl.Dlacpy(blas.Lower, m, m, a, lda, work[iu:], ldworku) impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, work[iu+1:], ldworku) ie = itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Bidiagonalize L in work[iu:], copying result to U. impl.Dgebrd(m, m, work[iu:], ldworku, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Lower, m, m, work[iu:], ldworku, u, ldu) // Generate right bidiagonalizing vectors in work[iu:]. impl.Dorgbr(lapack.GeneratePT, m, m, m, work[iu:], ldworku, work[itaup:], work[iwork:], lwork-iwork) // Generate left bidiagonalizing vectors in U. impl.Dorgbr(lapack.GenerateQ, m, m, m, u, ldu, work[itauq:], work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing left singular // vectors of L in U and computing right singular vectors // of L in work[iu:]. ok = impl.Dbdsqr(blas.Upper, m, m, m, 0, s, work[ie:], work[iu:], ldworku, u, ldu, work, 1, work[iwork:]) // Multiply right singular vectors of L in work[iu:] // Q in VT, storing result in A. bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n, m, 1, work[iu:], ldworku, vt, ldvt, 0, a, lda) // Copy right singular vectors of A from A to VT. impl.Dlacpy(blas.All, m, n, a, lda, vt, ldvt) } else { // Insufficient workspace for a fast algorithm. itau := 0 iwork := itau + m // Compute A = L * Q, copying result to VT. impl.Dgelqf(m, n, a, lda, work[itau:], work[iwork:], lwork-iwork) impl.Dlacpy(blas.Upper, m, n, a, lda, vt, ldvt) // Generate Q in VT. impl.Dorglq(n, n, m, vt, ldvt, work[itau:], work[iwork:], lwork-iwork) // Copy L to U, zeroing out above it. impl.Dlacpy(blas.Lower, m, m, a, lda, u, ldu) impl.Dlaset(blas.Upper, m-1, m-1, 0, 0, u[1:], ldu) ie = itau itauq := ie + m itaup := itauq + m iwork = itaup + m // Bidiagonalize L in U. impl.Dgebrd(m, m, u, ldu, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) // Multiply right bidiagonalizing vectors in U by Q in VT. impl.Dormbr(lapack.ApplyP, blas.Left, blas.Trans, m, n, m, u, ldu, work[itaup:], vt, ldvt, work[iwork:], lwork-iwork) // Generate left bidiagonalizing vectors in U. impl.Dorgbr(lapack.GenerateQ, m, m, m, u, ldu, work[itauq:], work[iwork:], lwork-iwork) iwork = ie + m // Perform bidiagonal QR iteration, computing left singular // vectors of A in U and computing right singular vectors // of A in VT. ok = impl.Dbdsqr(blas.Upper, m, n, m, 0, s, work[ie:], vt, ldvt, u, ldu, work, 1, work[iwork:]) } } } } else { // Path 10t. // N at least M, but not much larger. ie = 0 itauq := ie + m itaup := itauq + m iwork := itaup + m // Bidiagonalize A. impl.Dgebrd(m, n, a, lda, s, work[ie:], work[itauq:], work[itaup:], work[iwork:], lwork-iwork) if wantuas { // If left singular vectors desired in U, copy result to U and // generate left bidiagonalizing vectors in U. impl.Dlacpy(blas.Lower, m, m, a, lda, u, ldu) impl.Dorgbr(lapack.GenerateQ, m, m, n, u, ldu, work[itauq:], work[iwork:], lwork-iwork) } if wantvas { // If right singular vectors desired in VT, copy result to VT // and generate right bidiagonalizing vectors in VT. impl.Dlacpy(blas.Upper, m, n, a, lda, vt, ldvt) var nrvt int if wantva { nrvt = n } else { nrvt = m } impl.Dorgbr(lapack.GeneratePT, nrvt, n, m, vt, ldvt, work[itaup:], work[iwork:], lwork-iwork) } if wantuo { panic(noSVDO) } if wantvo { panic(noSVDO) } iwork = ie + m var nru, ncvt int if wantuas || wantuo { nru = m } if wantvas || wantvo { ncvt = n } if !wantuo && !wantvo { // Perform bidiagonal QR iteration, if desired, computing left // singular vectors in U and computing right singular vectors in // VT. ok = impl.Dbdsqr(blas.Lower, m, ncvt, nru, 0, s, work[ie:], vt, ldvt, u, ldu, work, 1, work[iwork:]) } else { // There will be two branches when the implementation is complete. panic(noSVDO) } } } if !ok { if ie > 1 { for i := 0; i < minmn-1; i++ { work[i+1] = work[i+ie] } } if ie < 1 { for i := minmn - 2; i >= 0; i-- { work[i+1] = work[i+ie] } } } // Undo scaling if necessary. if iscl { if anrm > bignum { impl.Dlascl(lapack.General, 0, 0, bignum, anrm, 1, minmn, s, minmn) } if !ok && anrm > bignum { impl.Dlascl(lapack.General, 0, 0, bignum, anrm, 1, minmn-1, work[1:], minmn) } if anrm < smlnum { impl.Dlascl(lapack.General, 0, 0, smlnum, anrm, 1, minmn, s, minmn) } if !ok && anrm < smlnum { impl.Dlascl(lapack.General, 0, 0, smlnum, anrm, 1, minmn-1, work[1:], minmn) } } work[0] = float64(maxwrk) return ok } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgetc2.go000066400000000000000000000053151450372207100217210ustar00rootroot00000000000000// Copyright ©2021 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/blas64" ) // Dgetc2 computes an LU factorization with complete pivoting of the n×n matrix // A. The factorization has the form // // A = P * L * U * Q, // // where P and Q are permutation matrices, L is lower triangular with unit // diagonal elements and U is upper triangular. // // On entry, a contains the matrix A to be factored. On return, a is overwritten // with the factors L and U. The unit diagonal elements of L are not stored. // // On return, ipiv and jpiv contain the pivot indices: row i has been // interchanged with row ipiv[i] and column j has been interchanged with column // jpiv[j]. ipiv and jpiv must have length n, otherwise Dgetc2 will panic. // // If k is non-negative, then U[k,k] is likely to produce overflow when solving // for x in A*x=b and U has been perturbed to avoid the overflow. // // Dgetc2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dgetc2(n int, a []float64, lda int, ipiv, jpiv []int) (k int) { switch { case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Negative k indicates U was not perturbed. k = -1 // Quick return if possible. if n == 0 { return k } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(ipiv) != n: panic(badLenIpiv) case len(jpiv) != n: panic(badLenJpvt) } const ( eps = dlamchP smlnum = dlamchS / eps ) if n == 1 { ipiv[0], jpiv[0] = 0, 0 if math.Abs(a[0]) < smlnum { k = 0 a[0] = smlnum } return k } // Factorize A using complete pivoting. // Set pivots less than smin to smin. var smin float64 var ipv, jpv int bi := blas64.Implementation() for i := 0; i < n-1; i++ { var xmax float64 for ip := i; ip < n; ip++ { for jp := i; jp < n; jp++ { if math.Abs(a[ip*lda+jp]) >= xmax { xmax = math.Abs(a[ip*lda+jp]) ipv = ip jpv = jp } } } if i == 0 { smin = math.Max(eps*xmax, smlnum) } // Swap rows. if ipv != i { bi.Dswap(n, a[ipv*lda:], 1, a[i*lda:], 1) } ipiv[i] = ipv // Swap columns. if jpv != i { bi.Dswap(n, a[jpv:], lda, a[i:], lda) } jpiv[i] = jpv // Check for singularity. if math.Abs(a[i*lda+i]) < smin { k = i a[i*lda+i] = smin } for j := i + 1; j < n; j++ { a[j*lda+i] /= a[i*lda+i] } bi.Dger(n-i-1, n-i-1, -1, a[(i+1)*lda+i:], lda, a[i*lda+i+1:], 1, a[(i+1)*lda+i+1:], lda) } if math.Abs(a[(n-1)*lda+n-1]) < smin { k = n - 1 a[(n-1)*lda+(n-1)] = smin } // Set last pivots to last index. ipiv[n-1] = n - 1 jpiv[n-1] = n - 1 return k } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgetf2.go000066400000000000000000000041461450372207100217250ustar00rootroot00000000000000// 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/blas64" ) // Dgetf2 computes the LU decomposition of the m×n matrix A. // The LU decomposition is a factorization of a into // // A = P * L * U // // where P is a permutation matrix, L is a unit lower triangular matrix, and // U is a (usually) non-unit upper triangular matrix. On exit, L and U are stored // in place into a. // // ipiv is a permutation vector. It indicates that row i of the matrix was // changed with ipiv[i]. ipiv must have length at least min(m,n), and will panic // otherwise. ipiv is zero-indexed. // // Dgetf2 returns whether the matrix A is singular. The LU decomposition will // be computed regardless of the singularity of A, but division by zero // will occur if the false is returned and the result is used to solve a // system of equations. // // Dgetf2 is an internal routine. It is exported for testing purposes. func (Implementation) Dgetf2(m, n int, a []float64, lda int, ipiv []int) (ok bool) { mn := min(m, n) switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if mn == 0 { return true } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(ipiv) != mn: panic(badLenIpiv) } bi := blas64.Implementation() sfmin := dlamchS ok = true for j := 0; j < mn; j++ { // Find a pivot and test for singularity. jp := j + bi.Idamax(m-j, a[j*lda+j:], lda) ipiv[j] = jp if a[jp*lda+j] == 0 { ok = false } else { // Swap the rows if necessary. if jp != j { bi.Dswap(n, a[j*lda:], 1, a[jp*lda:], 1) } if j < m-1 { aj := a[j*lda+j] if math.Abs(aj) >= sfmin { bi.Dscal(m-j-1, 1/aj, a[(j+1)*lda+j:], lda) } else { for i := 0; i < m-j-1; i++ { a[(j+1)*lda+j] = a[(j+1)*lda+j] / a[lda*j+j] } } } } if j < mn-1 { bi.Dger(m-j-1, n-j-1, -1, a[(j+1)*lda+j:], lda, a[j*lda+j+1:], 1, a[(j+1)*lda+j+1:], lda) } } return ok } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgetrf.go000066400000000000000000000044231450372207100220230ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dgetrf computes the LU decomposition of the m×n matrix A. // The LU decomposition is a factorization of A into // // A = P * L * U // // where P is a permutation matrix, L is a unit lower triangular matrix, and // U is a (usually) non-unit upper triangular matrix. On exit, L and U are stored // in place into a. // // ipiv is a permutation vector. It indicates that row i of the matrix was // changed with ipiv[i]. ipiv must have length at least min(m,n), and will panic // otherwise. ipiv is zero-indexed. // // Dgetrf is the blocked version of the algorithm. // // Dgetrf returns whether the matrix A is singular. The LU decomposition will // be computed regardless of the singularity of A, but division by zero // will occur if the false is returned and the result is used to solve a // system of equations. func (impl Implementation) Dgetrf(m, n int, a []float64, lda int, ipiv []int) (ok bool) { mn := min(m, n) switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if mn == 0 { return true } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(ipiv) != mn: panic(badLenIpiv) } bi := blas64.Implementation() nb := impl.Ilaenv(1, "DGETRF", " ", m, n, -1, -1) if nb <= 1 || mn <= nb { // Use the unblocked algorithm. return impl.Dgetf2(m, n, a, lda, ipiv) } ok = true for j := 0; j < mn; j += nb { jb := min(mn-j, nb) blockOk := impl.Dgetf2(m-j, jb, a[j*lda+j:], lda, ipiv[j:j+jb]) if !blockOk { ok = false } for i := j; i <= min(m-1, j+jb-1); i++ { ipiv[i] = j + ipiv[i] } impl.Dlaswp(j, a, lda, j, j+jb-1, ipiv[:j+jb], 1) if j+jb < n { impl.Dlaswp(n-j-jb, a[j+jb:], lda, j, j+jb-1, ipiv[:j+jb], 1) bi.Dtrsm(blas.Left, blas.Lower, blas.NoTrans, blas.Unit, jb, n-j-jb, 1, a[j*lda+j:], lda, a[j*lda+j+jb:], lda) if j+jb < m { bi.Dgemm(blas.NoTrans, blas.NoTrans, m-j-jb, n-j-jb, jb, -1, a[(j+jb)*lda+j:], lda, a[j*lda+j+jb:], lda, 1, a[(j+jb)*lda+j+jb:], lda) } } } return ok } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgetri.go000066400000000000000000000061571450372207100220340ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dgetri computes the inverse of the matrix A using the LU factorization computed // by Dgetrf. On entry, a contains the PLU decomposition of A as computed by // Dgetrf and on exit contains the reciprocal of the original matrix. // // Dgetri will not perform the inversion if the matrix is singular, and returns // a boolean indicating whether the inversion was successful. // // work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= n and this function will panic otherwise. // Dgetri is a blocked inversion, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Dgetri, // the optimal work length will be stored into work[0]. func (impl Implementation) Dgetri(n int, a []float64, lda int, ipiv []int, work []float64, lwork int) (ok bool) { iws := max(1, n) switch { case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < iws && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } if n == 0 { work[0] = 1 return true } nb := impl.Ilaenv(1, "DGETRI", " ", n, -1, -1, -1) if lwork == -1 { work[0] = float64(n * nb) return true } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(ipiv) != n: panic(badLenIpiv) } // Form inv(U). ok = impl.Dtrtri(blas.Upper, blas.NonUnit, n, a, lda) if !ok { return false } nbmin := 2 if 1 < nb && nb < n { iws = max(n*nb, 1) if lwork < iws { nb = lwork / n nbmin = max(2, impl.Ilaenv(2, "DGETRI", " ", n, -1, -1, -1)) } } ldwork := nb bi := blas64.Implementation() // Solve the equation inv(A)*L = inv(U) for inv(A). // TODO(btracey): Replace this with a more row-major oriented algorithm. if nb < nbmin || n <= nb { // Unblocked code. for j := n - 1; j >= 0; j-- { for i := j + 1; i < n; i++ { // Copy current column of L to work and replace with zeros. work[i] = a[i*lda+j] a[i*lda+j] = 0 } // Compute current column of inv(A). if j < n-1 { bi.Dgemv(blas.NoTrans, n, n-j-1, -1, a[(j+1):], lda, work[(j+1):], 1, 1, a[j:], lda) } } } else { // Blocked code. nn := ((n - 1) / nb) * nb for j := nn; j >= 0; j -= nb { jb := min(nb, n-j) // Copy current block column of L to work and replace // with zeros. for jj := j; jj < j+jb; jj++ { for i := jj + 1; i < n; i++ { work[i*ldwork+(jj-j)] = a[i*lda+jj] a[i*lda+jj] = 0 } } // Compute current block column of inv(A). if j+jb < n { bi.Dgemm(blas.NoTrans, blas.NoTrans, n, jb, n-j-jb, -1, a[(j+jb):], lda, work[(j+jb)*ldwork:], ldwork, 1, a[j:], lda) } bi.Dtrsm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, n, jb, 1, work[j*ldwork:], ldwork, a[j:], lda) } } // Apply column interchanges. for j := n - 2; j >= 0; j-- { jp := ipiv[j] if jp != j { bi.Dswap(n, a[j:], lda, a[jp:], lda) } } work[0] = float64(iws) return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgetrs.go000066400000000000000000000040571450372207100220430ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dgetrs solves a system of equations using an LU factorization. // The system of equations solved is // // A * X = B if trans == blas.Trans // Aᵀ * X = B if trans == blas.NoTrans // // A is a general n×n matrix with stride lda. B is a general matrix of size n×nrhs. // // On entry b contains the elements of the matrix B. On exit, b contains the // elements of X, the solution to the system of equations. // // a and ipiv contain the LU factorization of A and the permutation indices as // computed by Dgetrf. ipiv is zero-indexed. func (impl Implementation) Dgetrs(trans blas.Transpose, n, nrhs int, a []float64, lda int, ipiv []int, b []float64, ldb int) { switch { case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTrans) case n < 0: panic(nLT0) case nrhs < 0: panic(nrhsLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, nrhs): panic(badLdB) } // Quick return if possible. if n == 0 || nrhs == 0 { return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(b) < (n-1)*ldb+nrhs: panic(shortB) case len(ipiv) != n: panic(badLenIpiv) } bi := blas64.Implementation() if trans == blas.NoTrans { // Solve A * X = B. impl.Dlaswp(nrhs, b, ldb, 0, n-1, ipiv, 1) // Solve L * X = B, updating b. bi.Dtrsm(blas.Left, blas.Lower, blas.NoTrans, blas.Unit, n, nrhs, 1, a, lda, b, ldb) // Solve U * X = B, updating b. bi.Dtrsm(blas.Left, blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs, 1, a, lda, b, ldb) return } // Solve Aᵀ * X = B. // Solve Uᵀ * X = B, updating b. bi.Dtrsm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, n, nrhs, 1, a, lda, b, ldb) // Solve Lᵀ * X = B, updating b. bi.Dtrsm(blas.Left, blas.Lower, blas.Trans, blas.Unit, n, nrhs, 1, a, lda, b, ldb) impl.Dlaswp(nrhs, b, ldb, 0, n-1, ipiv, -1) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dggsvd3.go000066400000000000000000000143701450372207100221130ustar00rootroot00000000000000// 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/blas64" "gonum.org/v1/gonum/lapack" ) // Dggsvd3 computes the generalized singular value decomposition (GSVD) // of an m×n matrix A and p×n matrix B: // // Uᵀ*A*Q = D1*[ 0 R ] // // Vᵀ*B*Q = D2*[ 0 R ] // // where U, V and Q are orthogonal matrices. // // Dggsvd3 returns k and l, the dimensions of the sub-blocks. k+l // is the effective numerical rank of the (m+p)×n matrix [ Aᵀ Bᵀ ]ᵀ. // R is a (k+l)×(k+l) nonsingular upper triangular matrix, D1 and // D2 are m×(k+l) and p×(k+l) diagonal matrices and of the following // structures, respectively: // // If m-k-l >= 0, // // k l // D1 = k [ I 0 ] // l [ 0 C ] // m-k-l [ 0 0 ] // // k l // D2 = l [ 0 S ] // p-l [ 0 0 ] // // n-k-l k l // [ 0 R ] = k [ 0 R11 R12 ] k // l [ 0 0 R22 ] l // // where // // C = diag( alpha_k, ... , alpha_{k+l} ), // S = diag( beta_k, ... , beta_{k+l} ), // C^2 + S^2 = I. // // R is stored in // // A[0:k+l, n-k-l:n] // // on exit. // // If m-k-l < 0, // // k m-k k+l-m // D1 = k [ I 0 0 ] // m-k [ 0 C 0 ] // // k m-k k+l-m // D2 = m-k [ 0 S 0 ] // k+l-m [ 0 0 I ] // p-l [ 0 0 0 ] // // n-k-l k m-k k+l-m // [ 0 R ] = k [ 0 R11 R12 R13 ] // m-k [ 0 0 R22 R23 ] // k+l-m [ 0 0 0 R33 ] // // where // // C = diag( alpha_k, ... , alpha_m ), // S = diag( beta_k, ... , beta_m ), // C^2 + S^2 = I. // // R = [ R11 R12 R13 ] is stored in A[1:m, n-k-l+1:n] // [ 0 R22 R23 ] // // and R33 is stored in // // B[m-k:l, n+m-k-l:n] on exit. // // Dggsvd3 computes C, S, R, and optionally the orthogonal transformation // matrices U, V and Q. // // jobU, jobV and jobQ are options for computing the orthogonal matrices. The behavior // is as follows // // jobU == lapack.GSVDU Compute orthogonal matrix U // jobU == lapack.GSVDNone Do not compute orthogonal matrix. // // The behavior is the same for jobV and jobQ with the exception that instead of // lapack.GSVDU these accept lapack.GSVDV and lapack.GSVDQ respectively. // The matrices U, V and Q must be m×m, p×p and n×n respectively unless the // relevant job parameter is lapack.GSVDNone. // // alpha and beta must have length n or Dggsvd3 will panic. On exit, alpha and // beta contain the generalized singular value pairs of A and B // // alpha[0:k] = 1, // beta[0:k] = 0, // // if m-k-l >= 0, // // alpha[k:k+l] = diag(C), // beta[k:k+l] = diag(S), // // if m-k-l < 0, // // alpha[k:m]= C, alpha[m:k+l]= 0 // beta[k:m] = S, beta[m:k+l] = 1. // // if k+l < n, // // alpha[k+l:n] = 0 and // beta[k+l:n] = 0. // // On exit, iwork contains the permutation required to sort alpha descending. // // iwork must have length n, work must have length at least max(1, lwork), and // lwork must be -1 or greater than n, otherwise Dggsvd3 will panic. If // lwork is -1, work[0] holds the optimal lwork on return, but Dggsvd3 does // not perform the GSVD. func (impl Implementation) Dggsvd3(jobU, jobV, jobQ lapack.GSVDJob, m, n, p int, a []float64, lda int, b []float64, ldb int, alpha, beta, u []float64, ldu int, v []float64, ldv int, q []float64, ldq int, work []float64, lwork int, iwork []int) (k, l int, ok bool) { wantu := jobU == lapack.GSVDU wantv := jobV == lapack.GSVDV wantq := jobQ == lapack.GSVDQ switch { case !wantu && jobU != lapack.GSVDNone: panic(badGSVDJob + "U") case !wantv && jobV != lapack.GSVDNone: panic(badGSVDJob + "V") case !wantq && jobQ != lapack.GSVDNone: panic(badGSVDJob + "Q") case m < 0: panic(mLT0) case n < 0: panic(nLT0) case p < 0: panic(pLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, n): panic(badLdB) case ldu < 1, wantu && ldu < m: panic(badLdU) case ldv < 1, wantv && ldv < p: panic(badLdV) case ldq < 1, wantq && ldq < n: panic(badLdQ) case len(iwork) < n: panic(shortWork) case lwork < 1 && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Determine optimal work length. impl.Dggsvp3(jobU, jobV, jobQ, m, p, n, a, lda, b, ldb, 0, 0, u, ldu, v, ldv, q, ldq, iwork, work, work, -1) lwkopt := n + int(work[0]) lwkopt = max(lwkopt, 2*n) lwkopt = max(lwkopt, 1) work[0] = float64(lwkopt) if lwork == -1 { return 0, 0, true } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(b) < (p-1)*ldb+n: panic(shortB) case wantu && len(u) < (m-1)*ldu+m: panic(shortU) case wantv && len(v) < (p-1)*ldv+p: panic(shortV) case wantq && len(q) < (n-1)*ldq+n: panic(shortQ) case len(alpha) != n: panic(badLenAlpha) case len(beta) != n: panic(badLenBeta) } // Compute the Frobenius norm of matrices A and B. anorm := impl.Dlange(lapack.Frobenius, m, n, a, lda, nil) bnorm := impl.Dlange(lapack.Frobenius, p, n, b, ldb, nil) // Get machine precision and set up threshold for determining // the effective numerical rank of the matrices A and B. tola := float64(max(m, n)) * math.Max(anorm, dlamchS) * dlamchP tolb := float64(max(p, n)) * math.Max(bnorm, dlamchS) * dlamchP // Preprocessing. k, l = impl.Dggsvp3(jobU, jobV, jobQ, m, p, n, a, lda, b, ldb, tola, tolb, u, ldu, v, ldv, q, ldq, iwork, work[:n], work[n:], lwork-n) // Compute the GSVD of two upper "triangular" matrices. _, ok = impl.Dtgsja(jobU, jobV, jobQ, m, p, n, k, l, a, lda, b, ldb, tola, tolb, alpha, beta, u, ldu, v, ldv, q, ldq, work) // Sort the singular values and store the pivot indices in iwork // Copy alpha to work, then sort alpha in work. bi := blas64.Implementation() bi.Dcopy(n, alpha, 1, work[:n], 1) ibnd := min(l, m-k) for i := 0; i < ibnd; i++ { // Scan for largest alpha_{k+i}. isub := i smax := work[k+i] for j := i + 1; j < ibnd; j++ { if v := work[k+j]; v > smax { isub = j smax = v } } if isub != i { work[k+isub] = work[k+i] work[k+i] = smax iwork[k+i] = k + isub } else { iwork[k+i] = k + i } } work[0] = float64(lwkopt) return k, l, ok } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dggsvp3.go000066400000000000000000000166011450372207100221260ustar00rootroot00000000000000// 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/lapack" ) // Dggsvp3 computes orthogonal matrices U, V and Q such that // // n-k-l k l // Uᵀ*A*Q = k [ 0 A12 A13 ] if m-k-l >= 0; // l [ 0 0 A23 ] // m-k-l [ 0 0 0 ] // // n-k-l k l // Uᵀ*A*Q = k [ 0 A12 A13 ] if m-k-l < 0; // m-k [ 0 0 A23 ] // // n-k-l k l // Vᵀ*B*Q = l [ 0 0 B13 ] // p-l [ 0 0 0 ] // // where the k×k matrix A12 and l×l matrix B13 are non-singular // upper triangular. A23 is l×l upper triangular if m-k-l >= 0, // otherwise A23 is (m-k)×l upper trapezoidal. // // Dggsvp3 returns k and l, the dimensions of the sub-blocks. k+l // is the effective numerical rank of the (m+p)×n matrix [ Aᵀ Bᵀ ]ᵀ. // // jobU, jobV and jobQ are options for computing the orthogonal matrices. The behavior // is as follows // // jobU == lapack.GSVDU Compute orthogonal matrix U // jobU == lapack.GSVDNone Do not compute orthogonal matrix. // // The behavior is the same for jobV and jobQ with the exception that instead of // lapack.GSVDU these accept lapack.GSVDV and lapack.GSVDQ respectively. // The matrices U, V and Q must be m×m, p×p and n×n respectively unless the // relevant job parameter is lapack.GSVDNone. // // tola and tolb are the convergence criteria for the Jacobi-Kogbetliantz // iteration procedure. Generally, they are the same as used in the preprocessing // step, for example, // // tola = max(m, n)*norm(A)*eps, // tolb = max(p, n)*norm(B)*eps. // // Where eps is the machine epsilon. // // iwork must have length n, work must have length at least max(1, lwork), and // lwork must be -1 or greater than zero, otherwise Dggsvp3 will panic. // // Dggsvp3 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dggsvp3(jobU, jobV, jobQ lapack.GSVDJob, m, p, n int, a []float64, lda int, b []float64, ldb int, tola, tolb float64, u []float64, ldu int, v []float64, ldv int, q []float64, ldq int, iwork []int, tau, work []float64, lwork int) (k, l int) { wantu := jobU == lapack.GSVDU wantv := jobV == lapack.GSVDV wantq := jobQ == lapack.GSVDQ switch { case !wantu && jobU != lapack.GSVDNone: panic(badGSVDJob + "U") case !wantv && jobV != lapack.GSVDNone: panic(badGSVDJob + "V") case !wantq && jobQ != lapack.GSVDNone: panic(badGSVDJob + "Q") case m < 0: panic(mLT0) case p < 0: panic(pLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, n): panic(badLdB) case ldu < 1, wantu && ldu < m: panic(badLdU) case ldv < 1, wantv && ldv < p: panic(badLdV) case ldq < 1, wantq && ldq < n: panic(badLdQ) case len(iwork) != n: panic(shortWork) case lwork < 1 && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } var lwkopt int impl.Dgeqp3(p, n, b, ldb, iwork, tau, work, -1) lwkopt = int(work[0]) if wantv { lwkopt = max(lwkopt, p) } lwkopt = max(lwkopt, min(n, p)) lwkopt = max(lwkopt, m) if wantq { lwkopt = max(lwkopt, n) } impl.Dgeqp3(m, n, a, lda, iwork, tau, work, -1) lwkopt = max(lwkopt, int(work[0])) lwkopt = max(1, lwkopt) if lwork == -1 { work[0] = float64(lwkopt) return 0, 0 } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(b) < (p-1)*ldb+n: panic(shortB) case wantu && len(u) < (m-1)*ldu+m: panic(shortU) case wantv && len(v) < (p-1)*ldv+p: panic(shortV) case wantq && len(q) < (n-1)*ldq+n: panic(shortQ) case len(tau) < n: // tau check must come after lwkopt query since // the Dggsvd3 call for lwkopt query may have // lwork == -1, and tau is provided by work. panic(shortTau) } const forward = true // QR with column pivoting of B: B*P = V*[ S11 S12 ]. // [ 0 0 ] for i := range iwork[:n] { iwork[i] = 0 } impl.Dgeqp3(p, n, b, ldb, iwork, tau, work, lwork) // Update A := A*P. impl.Dlapmt(forward, m, n, a, lda, iwork) // Determine the effective rank of matrix B. for i := 0; i < min(p, n); i++ { if math.Abs(b[i*ldb+i]) > tolb { l++ } } if wantv { // Copy the details of V, and form V. impl.Dlaset(blas.All, p, p, 0, 0, v, ldv) if p > 1 { impl.Dlacpy(blas.Lower, p-1, min(p, n), b[ldb:], ldb, v[ldv:], ldv) } impl.Dorg2r(p, p, min(p, n), v, ldv, tau, work) } // Clean up B. for i := 1; i < l; i++ { r := b[i*ldb : i*ldb+i] for j := range r { r[j] = 0 } } if p > l { impl.Dlaset(blas.All, p-l, n, 0, 0, b[l*ldb:], ldb) } if wantq { // Set Q = I and update Q := Q*P. impl.Dlaset(blas.All, n, n, 0, 1, q, ldq) impl.Dlapmt(forward, n, n, q, ldq, iwork) } if p >= l && n != l { // RQ factorization of [ S11 S12 ]: [ S11 S12 ] = [ 0 S12 ]*Z. impl.Dgerq2(l, n, b, ldb, tau, work) // Update A := A*Zᵀ. impl.Dormr2(blas.Right, blas.Trans, m, n, l, b, ldb, tau, a, lda, work) if wantq { // Update Q := Q*Zᵀ. impl.Dormr2(blas.Right, blas.Trans, n, n, l, b, ldb, tau, q, ldq, work) } // Clean up B. impl.Dlaset(blas.All, l, n-l, 0, 0, b, ldb) for i := 1; i < l; i++ { r := b[i*ldb+n-l : i*ldb+i+n-l] for j := range r { r[j] = 0 } } } // Let N-L L // A = [ A11 A12 ] M, // // then the following does the complete QR decomposition of A11: // // A11 = U*[ 0 T12 ]*P1ᵀ. // [ 0 0 ] for i := range iwork[:n-l] { iwork[i] = 0 } impl.Dgeqp3(m, n-l, a, lda, iwork[:n-l], tau, work, lwork) // Determine the effective rank of A11. for i := 0; i < min(m, n-l); i++ { if math.Abs(a[i*lda+i]) > tola { k++ } } // Update A12 := Uᵀ*A12, where A12 = A[0:m, n-l:n]. impl.Dorm2r(blas.Left, blas.Trans, m, l, min(m, n-l), a, lda, tau, a[n-l:], lda, work) if wantu { // Copy the details of U, and form U. impl.Dlaset(blas.All, m, m, 0, 0, u, ldu) if m > 1 { impl.Dlacpy(blas.Lower, m-1, min(m, n-l), a[lda:], lda, u[ldu:], ldu) } impl.Dorg2r(m, m, min(m, n-l), u, ldu, tau, work) } if wantq { // Update Q[0:n, 0:n-l] := Q[0:n, 0:n-l]*P1. impl.Dlapmt(forward, n, n-l, q, ldq, iwork[:n-l]) } // Clean up A: set the strictly lower triangular part of // A[0:k, 0:k] = 0, and A[k:m, 0:n-l] = 0. for i := 1; i < k; i++ { r := a[i*lda : i*lda+i] for j := range r { r[j] = 0 } } if m > k { impl.Dlaset(blas.All, m-k, n-l, 0, 0, a[k*lda:], lda) } if n-l > k { // RQ factorization of [ T11 T12 ] = [ 0 T12 ]*Z1. impl.Dgerq2(k, n-l, a, lda, tau, work) if wantq { // Update Q[0:n, 0:n-l] := Q[0:n, 0:n-l]*Z1ᵀ. impl.Dorm2r(blas.Right, blas.Trans, n, n-l, k, a, lda, tau, q, ldq, work) } // Clean up A. impl.Dlaset(blas.All, k, n-l-k, 0, 0, a, lda) for i := 1; i < k; i++ { r := a[i*lda+n-k-l : i*lda+i+n-k-l] for j := range r { a[j] = 0 } } } if m > k { // QR factorization of A[k:m, n-l:n]. impl.Dgeqr2(m-k, l, a[k*lda+n-l:], lda, tau, work) if wantu { // Update U[:, k:m) := U[:, k:m]*U1. impl.Dorm2r(blas.Right, blas.NoTrans, m, m-k, min(m-k, l), a[k*lda+n-l:], lda, tau, u[k:], ldu, work) } // Clean up A. for i := k + 1; i < m; i++ { r := a[i*lda+n-l : i*lda+min(n-l+i-k, n)] for j := range r { r[j] = 0 } } } work[0] = float64(lwkopt) return k, l } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dgtsv.go000066400000000000000000000045361450372207100217040ustar00rootroot00000000000000// Copyright ©2020 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" // Dgtsv solves the equation // // A * X = B // // where A is an n×n tridiagonal matrix. It uses Gaussian elimination with // partial pivoting. The equation Aᵀ * X = B may be solved by swapping the // arguments for du and dl. // // On entry, dl, d and du contain the sub-diagonal, the diagonal and the // super-diagonal, respectively, of A. On return, the first n-2 elements of dl, // the first n-1 elements of du and the first n elements of d may be // overwritten. // // On entry, b contains the n×nrhs right-hand side matrix B. On return, b will // be overwritten. If ok is true, it will be overwritten by the solution matrix X. // // Dgtsv returns whether the solution X has been successfully computed. func (impl Implementation) Dgtsv(n, nrhs int, dl, d, du []float64, b []float64, ldb int) (ok bool) { switch { case n < 0: panic(nLT0) case nrhs < 0: panic(nrhsLT0) case ldb < max(1, nrhs): panic(badLdB) } if n == 0 || nrhs == 0 { return true } switch { case len(dl) < n-1: panic(shortDL) case len(d) < n: panic(shortD) case len(du) < n-1: panic(shortDU) case len(b) < (n-1)*ldb+nrhs: panic(shortB) } dl = dl[:n-1] d = d[:n] du = du[:n-1] for i := 0; i < n-1; i++ { if math.Abs(d[i]) >= math.Abs(dl[i]) { // No row interchange required. if d[i] == 0 { return false } fact := dl[i] / d[i] d[i+1] -= fact * du[i] for j := 0; j < nrhs; j++ { b[(i+1)*ldb+j] -= fact * b[i*ldb+j] } dl[i] = 0 } else { // Interchange rows i and i+1. fact := d[i] / dl[i] d[i] = dl[i] tmp := d[i+1] d[i+1] = du[i] - fact*tmp du[i] = tmp if i+1 < n-1 { dl[i] = du[i+1] du[i+1] = -fact * dl[i] } for j := 0; j < nrhs; j++ { tmp = b[i*ldb+j] b[i*ldb+j] = b[(i+1)*ldb+j] b[(i+1)*ldb+j] = tmp - fact*b[(i+1)*ldb+j] } } } if d[n-1] == 0 { return false } // Back solve with the matrix U from the factorization. for j := 0; j < nrhs; j++ { b[(n-1)*ldb+j] /= d[n-1] if n > 1 { b[(n-2)*ldb+j] = (b[(n-2)*ldb+j] - du[n-2]*b[(n-1)*ldb+j]) / d[n-2] } for i := n - 3; i >= 0; i-- { b[i*ldb+j] = (b[i*ldb+j] - du[i]*b[(i+1)*ldb+j] - dl[i]*b[(i+2)*ldb+j]) / d[i] } } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dhseqr.go000066400000000000000000000223541450372207100220410ustar00rootroot00000000000000// Copyright ©2016 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/lapack" ) // Dhseqr computes the eigenvalues of an n×n Hessenberg matrix H and, // optionally, the matrices T and Z from the Schur decomposition // // H = Z T Zᵀ, // // where T is an n×n upper quasi-triangular matrix (the Schur form), and Z is // the n×n orthogonal matrix of Schur vectors. // // Optionally Z may be postmultiplied into an input orthogonal matrix Q so that // this routine can give the Schur factorization of a matrix A which has been // reduced to the Hessenberg form H by the orthogonal matrix Q: // // A = Q H Qᵀ = (QZ) T (QZ)ᵀ. // // If job == lapack.EigenvaluesOnly, only the eigenvalues will be computed. // If job == lapack.EigenvaluesAndSchur, the eigenvalues and the Schur form T will // be computed. // For other values of job Dhseqr will panic. // // If compz == lapack.SchurNone, no Schur vectors will be computed and Z will not be // referenced. // If compz == lapack.SchurHess, on return Z will contain the matrix of Schur // vectors of H. // If compz == lapack.SchurOrig, on entry z is assumed to contain the orthogonal // matrix Q that is the identity except for the submatrix // Q[ilo:ihi+1,ilo:ihi+1]. On return z will be updated to the product Q*Z. // // ilo and ihi determine the block of H on which Dhseqr operates. It is assumed // that H is already upper triangular in rows and columns [0:ilo] and [ihi+1:n], // although it will be only checked that the block is isolated, that is, // // ilo == 0 or H[ilo,ilo-1] == 0, // ihi == n-1 or H[ihi+1,ihi] == 0, // // and Dhseqr will panic otherwise. ilo and ihi are typically set by a previous // call to Dgebal, otherwise they should be set to 0 and n-1, respectively. It // must hold that // // 0 <= ilo <= ihi < n if n > 0, // ilo == 0 and ihi == -1 if n == 0. // // wr and wi must have length n. // // work must have length at least lwork and lwork must be at least max(1,n) // otherwise Dhseqr will panic. The minimum lwork delivers very good and // sometimes optimal performance, although lwork as large as 11*n may be // required. On return, work[0] will contain the optimal value of lwork. // // If lwork is -1, instead of performing Dhseqr, the function only estimates the // optimal workspace size and stores it into work[0]. Neither h nor z are // accessed. // // unconverged indicates whether Dhseqr computed all the eigenvalues. // // If unconverged == 0, all the eigenvalues have been computed and their real // and imaginary parts will be stored on return in wr and wi, respectively. If // two eigenvalues are computed as a complex conjugate pair, they are stored in // consecutive elements of wr and wi, say the i-th and (i+1)th, with wi[i] > 0 // and wi[i+1] < 0. // // If unconverged == 0 and job == lapack.EigenvaluesAndSchur, on return H will // contain the upper quasi-triangular matrix T from the Schur decomposition (the // Schur form). 2×2 diagonal blocks (corresponding to complex conjugate pairs of // eigenvalues) will be returned in standard form, with // // H[i,i] == H[i+1,i+1], // // and // // H[i+1,i]*H[i,i+1] < 0. // // The eigenvalues will be stored in wr and wi in the same order as on the // diagonal of the Schur form returned in H, with // // wr[i] = H[i,i], // // and, if H[i:i+2,i:i+2] is a 2×2 diagonal block, // // wi[i] = sqrt(-H[i+1,i]*H[i,i+1]), // wi[i+1] = -wi[i]. // // If unconverged == 0 and job == lapack.EigenvaluesOnly, the contents of h // on return is unspecified. // // If unconverged > 0, some eigenvalues have not converged, and the blocks // [0:ilo] and [unconverged:n] of wr and wi will contain those eigenvalues which // have been successfully computed. Failures are rare. // // If unconverged > 0 and job == lapack.EigenvaluesOnly, on return the // remaining unconverged eigenvalues are the eigenvalues of the upper Hessenberg // matrix H[ilo:unconverged,ilo:unconverged]. // // If unconverged > 0 and job == lapack.EigenvaluesAndSchur, then on // return // // (initial H) U = U (final H), (*) // // where U is an orthogonal matrix. The final H is upper Hessenberg and // H[unconverged:ihi+1,unconverged:ihi+1] is upper quasi-triangular. // // If unconverged > 0 and compz == lapack.SchurOrig, then on return // // (final Z) = (initial Z) U, // // where U is the orthogonal matrix in (*) regardless of the value of job. // // If unconverged > 0 and compz == lapack.SchurHess, then on return // // (final Z) = U, // // where U is the orthogonal matrix in (*) regardless of the value of job. // // References: // // [1] R. Byers. LAPACK 3.1 xHSEQR: Tuning and Implementation Notes on the // Small Bulge Multi-Shift QR Algorithm with Aggressive Early Deflation. // LAPACK Working Note 187 (2007) // URL: http://www.netlib.org/lapack/lawnspdf/lawn187.pdf // [2] K. Braman, R. Byers, R. Mathias. The Multishift QR Algorithm. Part I: // Maintaining Well-Focused Shifts and Level 3 Performance. SIAM J. Matrix // Anal. Appl. 23(4) (2002), pp. 929—947 // URL: http://dx.doi.org/10.1137/S0895479801384573 // [3] K. Braman, R. Byers, R. Mathias. The Multishift QR Algorithm. Part II: // Aggressive Early Deflation. SIAM J. Matrix Anal. Appl. 23(4) (2002), pp. 948—973 // URL: http://dx.doi.org/10.1137/S0895479801384585 // // Dhseqr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dhseqr(job lapack.SchurJob, compz lapack.SchurComp, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, z []float64, ldz int, work []float64, lwork int) (unconverged int) { wantt := job == lapack.EigenvaluesAndSchur wantz := compz == lapack.SchurHess || compz == lapack.SchurOrig switch { case job != lapack.EigenvaluesOnly && job != lapack.EigenvaluesAndSchur: panic(badSchurJob) case compz != lapack.SchurNone && compz != lapack.SchurHess && compz != lapack.SchurOrig: panic(badSchurComp) case n < 0: panic(nLT0) case ilo < 0 || max(0, n-1) < ilo: panic(badIlo) case ihi < min(ilo, n-1) || n <= ihi: panic(badIhi) case ldh < max(1, n): panic(badLdH) case ldz < 1, wantz && ldz < n: panic(badLdZ) case lwork < max(1, n) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if n == 0 { work[0] = 1 return 0 } // Quick return in case of a workspace query. if lwork == -1 { impl.Dlaqr04(wantt, wantz, n, ilo, ihi, h, ldh, wr, wi, ilo, ihi, z, ldz, work, -1, 1) work[0] = math.Max(float64(n), work[0]) return 0 } switch { case len(h) < (n-1)*ldh+n: panic(shortH) case wantz && len(z) < (n-1)*ldz+n: panic(shortZ) case len(wr) < n: panic(shortWr) case len(wi) < n: panic(shortWi) } const ( // Matrices of order ntiny or smaller must be processed by // Dlahqr because of insufficient subdiagonal scratch space. // This is a hard limit. ntiny = 15 // nl is the size of a local workspace to help small matrices // through a rare Dlahqr failure. nl > ntiny is required and // nl <= nmin = Ilaenv(ispec=12,...) is recommended (the default // value of nmin is 75). Using nl = 49 allows up to six // simultaneous shifts and a 16×16 deflation window. nl = 49 ) // Copy eigenvalues isolated by Dgebal. for i := 0; i < ilo; i++ { wr[i] = h[i*ldh+i] wi[i] = 0 } for i := ihi + 1; i < n; i++ { wr[i] = h[i*ldh+i] wi[i] = 0 } // Initialize Z to identity matrix if requested. if compz == lapack.SchurHess { impl.Dlaset(blas.All, n, n, 0, 1, z, ldz) } // Quick return if possible. if ilo == ihi { wr[ilo] = h[ilo*ldh+ilo] wi[ilo] = 0 return 0 } // Dlahqr/Dlaqr04 crossover point. nmin := impl.Ilaenv(12, "DHSEQR", string(job)+string(compz), n, ilo, ihi, lwork) nmin = max(ntiny, nmin) if n > nmin { // Dlaqr0 for big matrices. unconverged = impl.Dlaqr04(wantt, wantz, n, ilo, ihi, h, ldh, wr[:ihi+1], wi[:ihi+1], ilo, ihi, z, ldz, work, lwork, 1) } else { // Dlahqr for small matrices. unconverged = impl.Dlahqr(wantt, wantz, n, ilo, ihi, h, ldh, wr[:ihi+1], wi[:ihi+1], ilo, ihi, z, ldz) if unconverged > 0 { // A rare Dlahqr failure! Dlaqr04 sometimes succeeds // when Dlahqr fails. kbot := unconverged if n >= nl { // Larger matrices have enough subdiagonal // scratch space to call Dlaqr04 directly. unconverged = impl.Dlaqr04(wantt, wantz, n, ilo, kbot, h, ldh, wr[:ihi+1], wi[:ihi+1], ilo, ihi, z, ldz, work, lwork, 1) } else { // Tiny matrices don't have enough subdiagonal // scratch space to benefit from Dlaqr04. Hence, // tiny matrices must be copied into a larger // array before calling Dlaqr04. var hl [nl * nl]float64 impl.Dlacpy(blas.All, n, n, h, ldh, hl[:], nl) impl.Dlaset(blas.All, nl, nl-n, 0, 0, hl[n:], nl) var workl [nl]float64 unconverged = impl.Dlaqr04(wantt, wantz, nl, ilo, kbot, hl[:], nl, wr[:ihi+1], wi[:ihi+1], ilo, ihi, z, ldz, workl[:], nl, 1) work[0] = workl[0] if wantt || unconverged > 0 { impl.Dlacpy(blas.All, n, n, hl[:], nl, h, ldh) } } } } // Zero out under the first subdiagonal, if necessary. if (wantt || unconverged > 0) && n > 2 { impl.Dlaset(blas.Lower, n-2, n-2, 0, 0, h[2*ldh:], ldh) } work[0] = math.Max(float64(n), work[0]) return unconverged } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlabrd.go000066400000000000000000000151771450372207100220100ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dlabrd reduces the first NB rows and columns of a real general m×n matrix // A to upper or lower bidiagonal form by an orthogonal transformation // // Q**T * A * P // // If m >= n, A is reduced to upper bidiagonal form and upon exit the elements // on and below the diagonal in the first nb columns represent the elementary // reflectors, and the elements above the diagonal in the first nb rows represent // the matrix P. If m < n, A is reduced to lower bidiagonal form and the elements // P is instead stored above the diagonal. // // The reduction to bidiagonal form is stored in d and e, where d are the diagonal // elements, and e are the off-diagonal elements. // // The matrices Q and P are products of elementary reflectors // // Q = H_0 * H_1 * ... * H_{nb-1} // P = G_0 * G_1 * ... * G_{nb-1} // // where // // H_i = I - tauQ[i] * v_i * v_iᵀ // G_i = I - tauP[i] * u_i * u_iᵀ // // As an example, on exit the entries of A when m = 6, n = 5, and nb = 2 // // [ 1 1 u1 u1 u1] // [v1 1 1 u2 u2] // [v1 v2 a a a] // [v1 v2 a a a] // [v1 v2 a a a] // [v1 v2 a a a] // // and when m = 5, n = 6, and nb = 2 // // [ 1 u1 u1 u1 u1 u1] // [ 1 1 u2 u2 u2 u2] // [v1 1 a a a a] // [v1 v2 a a a a] // [v1 v2 a a a a] // // Dlabrd also returns the matrices X and Y which are used with U and V to // apply the transformation to the unreduced part of the matrix // // A := A - V*Yᵀ - X*Uᵀ // // and returns the matrices X and Y which are needed to apply the // transformation to the unreduced part of A. // // X is an m×nb matrix, Y is an n×nb matrix. d, e, taup, and tauq must all have // length at least nb. Dlabrd will panic if these size constraints are violated. // // Dlabrd is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlabrd(m, n, nb int, a []float64, lda int, d, e, tauQ, tauP, x []float64, ldx int, y []float64, ldy int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case nb < 0: panic(nbLT0) case nb > n: panic(nbGTN) case nb > m: panic(nbGTM) case lda < max(1, n): panic(badLdA) case ldx < max(1, nb): panic(badLdX) case ldy < max(1, nb): panic(badLdY) } if m == 0 || n == 0 || nb == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(d) < nb: panic(shortD) case len(e) < nb: panic(shortE) case len(tauQ) < nb: panic(shortTauQ) case len(tauP) < nb: panic(shortTauP) case len(x) < (m-1)*ldx+nb: panic(shortX) case len(y) < (n-1)*ldy+nb: panic(shortY) } bi := blas64.Implementation() if m >= n { // Reduce to upper bidiagonal form. for i := 0; i < nb; i++ { bi.Dgemv(blas.NoTrans, m-i, i, -1, a[i*lda:], lda, y[i*ldy:], 1, 1, a[i*lda+i:], lda) bi.Dgemv(blas.NoTrans, m-i, i, -1, x[i*ldx:], ldx, a[i:], lda, 1, a[i*lda+i:], lda) a[i*lda+i], tauQ[i] = impl.Dlarfg(m-i, a[i*lda+i], a[min(i+1, m-1)*lda+i:], lda) d[i] = a[i*lda+i] if i < n-1 { // Compute Y[i+1:n, i]. a[i*lda+i] = 1 bi.Dgemv(blas.Trans, m-i, n-i-1, 1, a[i*lda+i+1:], lda, a[i*lda+i:], lda, 0, y[(i+1)*ldy+i:], ldy) bi.Dgemv(blas.Trans, m-i, i, 1, a[i*lda:], lda, a[i*lda+i:], lda, 0, y[i:], ldy) bi.Dgemv(blas.NoTrans, n-i-1, i, -1, y[(i+1)*ldy:], ldy, y[i:], ldy, 1, y[(i+1)*ldy+i:], ldy) bi.Dgemv(blas.Trans, m-i, i, 1, x[i*ldx:], ldx, a[i*lda+i:], lda, 0, y[i:], ldy) bi.Dgemv(blas.Trans, i, n-i-1, -1, a[i+1:], lda, y[i:], ldy, 1, y[(i+1)*ldy+i:], ldy) bi.Dscal(n-i-1, tauQ[i], y[(i+1)*ldy+i:], ldy) // Update A[i, i+1:n]. bi.Dgemv(blas.NoTrans, n-i-1, i+1, -1, y[(i+1)*ldy:], ldy, a[i*lda:], 1, 1, a[i*lda+i+1:], 1) bi.Dgemv(blas.Trans, i, n-i-1, -1, a[i+1:], lda, x[i*ldx:], 1, 1, a[i*lda+i+1:], 1) // Generate reflection P[i] to annihilate A[i, i+2:n]. a[i*lda+i+1], tauP[i] = impl.Dlarfg(n-i-1, a[i*lda+i+1], a[i*lda+min(i+2, n-1):], 1) e[i] = a[i*lda+i+1] a[i*lda+i+1] = 1 // Compute X[i+1:m, i]. bi.Dgemv(blas.NoTrans, m-i-1, n-i-1, 1, a[(i+1)*lda+i+1:], lda, a[i*lda+i+1:], 1, 0, x[(i+1)*ldx+i:], ldx) bi.Dgemv(blas.Trans, n-i-1, i+1, 1, y[(i+1)*ldy:], ldy, a[i*lda+i+1:], 1, 0, x[i:], ldx) bi.Dgemv(blas.NoTrans, m-i-1, i+1, -1, a[(i+1)*lda:], lda, x[i:], ldx, 1, x[(i+1)*ldx+i:], ldx) bi.Dgemv(blas.NoTrans, i, n-i-1, 1, a[i+1:], lda, a[i*lda+i+1:], 1, 0, x[i:], ldx) bi.Dgemv(blas.NoTrans, m-i-1, i, -1, x[(i+1)*ldx:], ldx, x[i:], ldx, 1, x[(i+1)*ldx+i:], ldx) bi.Dscal(m-i-1, tauP[i], x[(i+1)*ldx+i:], ldx) } } return } // Reduce to lower bidiagonal form. for i := 0; i < nb; i++ { // Update A[i,i:n] bi.Dgemv(blas.NoTrans, n-i, i, -1, y[i*ldy:], ldy, a[i*lda:], 1, 1, a[i*lda+i:], 1) bi.Dgemv(blas.Trans, i, n-i, -1, a[i:], lda, x[i*ldx:], 1, 1, a[i*lda+i:], 1) // Generate reflection P[i] to annihilate A[i, i+1:n] a[i*lda+i], tauP[i] = impl.Dlarfg(n-i, a[i*lda+i], a[i*lda+min(i+1, n-1):], 1) d[i] = a[i*lda+i] if i < m-1 { a[i*lda+i] = 1 // Compute X[i+1:m, i]. bi.Dgemv(blas.NoTrans, m-i-1, n-i, 1, a[(i+1)*lda+i:], lda, a[i*lda+i:], 1, 0, x[(i+1)*ldx+i:], ldx) bi.Dgemv(blas.Trans, n-i, i, 1, y[i*ldy:], ldy, a[i*lda+i:], 1, 0, x[i:], ldx) bi.Dgemv(blas.NoTrans, m-i-1, i, -1, a[(i+1)*lda:], lda, x[i:], ldx, 1, x[(i+1)*ldx+i:], ldx) bi.Dgemv(blas.NoTrans, i, n-i, 1, a[i:], lda, a[i*lda+i:], 1, 0, x[i:], ldx) bi.Dgemv(blas.NoTrans, m-i-1, i, -1, x[(i+1)*ldx:], ldx, x[i:], ldx, 1, x[(i+1)*ldx+i:], ldx) bi.Dscal(m-i-1, tauP[i], x[(i+1)*ldx+i:], ldx) // Update A[i+1:m, i]. bi.Dgemv(blas.NoTrans, m-i-1, i, -1, a[(i+1)*lda:], lda, y[i*ldy:], 1, 1, a[(i+1)*lda+i:], lda) bi.Dgemv(blas.NoTrans, m-i-1, i+1, -1, x[(i+1)*ldx:], ldx, a[i:], lda, 1, a[(i+1)*lda+i:], lda) // Generate reflection Q[i] to annihilate A[i+2:m, i]. a[(i+1)*lda+i], tauQ[i] = impl.Dlarfg(m-i-1, a[(i+1)*lda+i], a[min(i+2, m-1)*lda+i:], lda) e[i] = a[(i+1)*lda+i] a[(i+1)*lda+i] = 1 // Compute Y[i+1:n, i]. bi.Dgemv(blas.Trans, m-i-1, n-i-1, 1, a[(i+1)*lda+i+1:], lda, a[(i+1)*lda+i:], lda, 0, y[(i+1)*ldy+i:], ldy) bi.Dgemv(blas.Trans, m-i-1, i, 1, a[(i+1)*lda:], lda, a[(i+1)*lda+i:], lda, 0, y[i:], ldy) bi.Dgemv(blas.NoTrans, n-i-1, i, -1, y[(i+1)*ldy:], ldy, y[i:], ldy, 1, y[(i+1)*ldy+i:], ldy) bi.Dgemv(blas.Trans, m-i-1, i+1, 1, x[(i+1)*ldx:], ldx, a[(i+1)*lda+i:], lda, 0, y[i:], ldy) bi.Dgemv(blas.Trans, i+1, n-i-1, -1, a[i+1:], lda, y[i:], ldy, 1, y[(i+1)*ldy+i:], ldy) bi.Dscal(n-i-1, tauQ[i], y[(i+1)*ldy+i:], ldy) } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlacn2.go000066400000000000000000000057141450372207100217170ustar00rootroot00000000000000// 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/blas64" ) // Dlacn2 estimates the 1-norm of an n×n matrix A using sequential updates with // matrix-vector products provided externally. // // Dlacn2 is called sequentially and it returns the value of est and kase to be // used on the next call. // On the initial call, kase must be 0. // In between calls, x must be overwritten by // // A * X if kase was returned as 1, // Aᵀ * X if kase was returned as 2, // // and all other parameters must not be changed. // On the final return, kase is returned as 0, v contains A*W where W is a // vector, and est = norm(V)/norm(W) is a lower bound for 1-norm of A. // // v, x, and isgn must all have length n and n must be at least 1, otherwise // Dlacn2 will panic. isave is used for temporary storage. // // Dlacn2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlacn2(n int, v, x []float64, isgn []int, est float64, kase int, isave *[3]int) (float64, int) { switch { case n < 1: panic(nLT1) case len(v) < n: panic(shortV) case len(x) < n: panic(shortX) case len(isgn) < n: panic(shortIsgn) case isave[0] < 0 || 5 < isave[0]: panic(badIsave) case isave[0] == 0 && kase != 0: panic(badIsave) } const itmax = 5 bi := blas64.Implementation() if kase == 0 { for i := 0; i < n; i++ { x[i] = 1 / float64(n) } kase = 1 isave[0] = 1 return est, kase } switch isave[0] { case 1: if n == 1 { v[0] = x[0] est = math.Abs(v[0]) kase = 0 return est, kase } est = bi.Dasum(n, x, 1) for i := 0; i < n; i++ { x[i] = math.Copysign(1, x[i]) isgn[i] = int(x[i]) } kase = 2 isave[0] = 2 return est, kase case 2: isave[1] = bi.Idamax(n, x, 1) isave[2] = 2 for i := 0; i < n; i++ { x[i] = 0 } x[isave[1]] = 1 kase = 1 isave[0] = 3 return est, kase case 3: bi.Dcopy(n, x, 1, v, 1) estold := est est = bi.Dasum(n, v, 1) sameSigns := true for i := 0; i < n; i++ { if int(math.Copysign(1, x[i])) != isgn[i] { sameSigns = false break } } if !sameSigns && est > estold { for i := 0; i < n; i++ { x[i] = math.Copysign(1, x[i]) isgn[i] = int(x[i]) } kase = 2 isave[0] = 4 return est, kase } case 4: jlast := isave[1] isave[1] = bi.Idamax(n, x, 1) if x[jlast] != math.Abs(x[isave[1]]) && isave[2] < itmax { isave[2] += 1 for i := 0; i < n; i++ { x[i] = 0 } x[isave[1]] = 1 kase = 1 isave[0] = 3 return est, kase } case 5: tmp := 2 * (bi.Dasum(n, x, 1)) / float64(3*n) if tmp > est { bi.Dcopy(n, x, 1, v, 1) est = tmp } kase = 0 return est, kase } // Iteration complete. Final stage altsgn := 1.0 for i := 0; i < n; i++ { x[i] = altsgn * (1 + float64(i)/float64(n-1)) altsgn *= -1 } kase = 1 isave[0] = 5 return est, kase } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlacpy.go000066400000000000000000000024331450372207100220230ustar00rootroot00000000000000// 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/blas" // Dlacpy copies the elements of A specified by uplo into B. Uplo can specify // a triangular portion with blas.Upper or blas.Lower, or can specify all of the // elements with blas.All. // // Dlacpy is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlacpy(uplo blas.Uplo, m, n int, a []float64, lda int, b []float64, ldb int) { switch { case uplo != blas.Upper && uplo != blas.Lower && uplo != blas.All: panic(badUplo) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, n): panic(badLdB) } if m == 0 || n == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(b) < (m-1)*ldb+n: panic(shortB) } switch uplo { case blas.Upper: for i := 0; i < m; i++ { for j := i; j < n; j++ { b[i*ldb+j] = a[i*lda+j] } } case blas.Lower: for i := 0; i < m; i++ { for j := 0; j < min(i+1, n); j++ { b[i*ldb+j] = a[i*lda+j] } } case blas.All: for i := 0; i < m; i++ { for j := 0; j < n; j++ { b[i*ldb+j] = a[i*lda+j] } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlae2.go000066400000000000000000000021061450372207100215330ustar00rootroot00000000000000// Copyright ©2016 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" // Dlae2 computes the eigenvalues of a 2×2 symmetric matrix // // [a b] // [b c] // // and returns the eigenvalue with the larger absolute value as rt1 and the // smaller as rt2. // // Dlae2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlae2(a, b, c float64) (rt1, rt2 float64) { sm := a + c df := a - c adf := math.Abs(df) tb := b + b ab := math.Abs(tb) acmx := c acmn := a if math.Abs(a) > math.Abs(c) { acmx = a acmn = c } var rt float64 if adf > ab { rt = adf * math.Sqrt(1+(ab/adf)*(ab/adf)) } else if adf < ab { rt = ab * math.Sqrt(1+(adf/ab)*(adf/ab)) } else { rt = ab * math.Sqrt2 } if sm < 0 { rt1 = 0.5 * (sm - rt) rt2 = (acmx/rt1)*acmn - (b/rt1)*b return rt1, rt2 } if sm > 0 { rt1 = 0.5 * (sm + rt) rt2 = (acmx/rt1)*acmn - (b/rt1)*b return rt1, rt2 } rt1 = 0.5 * rt rt2 = -0.5 * rt return rt1, rt2 } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaev2.go000066400000000000000000000032661450372207100217310ustar00rootroot00000000000000// 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" // Dlaev2 computes the Eigen decomposition of a symmetric 2×2 matrix. // The matrix is given by // // [a b] // [b c] // // Dlaev2 returns rt1 and rt2, the eigenvalues of the matrix where |RT1| > |RT2|, // and [cs1, sn1] which is the unit right eigenvalue for RT1. // // [ cs1 sn1] [a b] [cs1 -sn1] = [rt1 0] // [-sn1 cs1] [b c] [sn1 cs1] [ 0 rt2] // // Dlaev2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaev2(a, b, c float64) (rt1, rt2, cs1, sn1 float64) { sm := a + c df := a - c adf := math.Abs(df) tb := b + b ab := math.Abs(tb) acmx := c acmn := a if math.Abs(a) > math.Abs(c) { acmx = a acmn = c } var rt float64 if adf > ab { rt = adf * math.Sqrt(1+(ab/adf)*(ab/adf)) } else if adf < ab { rt = ab * math.Sqrt(1+(adf/ab)*(adf/ab)) } else { rt = ab * math.Sqrt(2) } var sgn1 float64 if sm < 0 { rt1 = 0.5 * (sm - rt) sgn1 = -1 rt2 = (acmx/rt1)*acmn - (b/rt1)*b } else if sm > 0 { rt1 = 0.5 * (sm + rt) sgn1 = 1 rt2 = (acmx/rt1)*acmn - (b/rt1)*b } else { rt1 = 0.5 * rt rt2 = -0.5 * rt sgn1 = 1 } var cs, sgn2 float64 if df >= 0 { cs = df + rt sgn2 = 1 } else { cs = df - rt sgn2 = -1 } acs := math.Abs(cs) if acs > ab { ct := -tb / cs sn1 = 1 / math.Sqrt(1+ct*ct) cs1 = ct * sn1 } else { if ab == 0 { cs1 = 1 sn1 = 0 } else { tn := -cs / tb cs1 = 1 / math.Sqrt(1+tn*tn) sn1 = tn * cs1 } } if sgn1 == sgn2 { tn := cs1 cs1 = -sn1 sn1 = tn } return rt1, rt2, cs1, sn1 } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaexc.go000066400000000000000000000200301450372207100220000ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dlaexc swaps two adjacent diagonal blocks of order 1 or 2 in an n×n upper // quasi-triangular matrix T by an orthogonal similarity transformation. // // T must be in Schur canonical form, that is, block upper triangular with 1×1 // and 2×2 diagonal blocks; each 2×2 diagonal block has its diagonal elements // equal and its off-diagonal elements of opposite sign. On return, T will // contain the updated matrix again in Schur canonical form. // // If wantq is true, the transformation is accumulated in the n×n matrix Q, // otherwise Q is not referenced. // // j1 is the index of the first row of the first block. n1 and n2 are the order // of the first and second block, respectively. // // work must have length at least n, otherwise Dlaexc will panic. // // If ok is false, the transformed matrix T would be too far from Schur form. // The blocks are not swapped, and T and Q are not modified. // // If n1 and n2 are both equal to 1, Dlaexc will always return true. // // Dlaexc is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaexc(wantq bool, n int, t []float64, ldt int, q []float64, ldq int, j1, n1, n2 int, work []float64) (ok bool) { switch { case n < 0: panic(nLT0) case ldt < max(1, n): panic(badLdT) case wantq && ldt < max(1, n): panic(badLdQ) case j1 < 0 || n <= j1: panic(badJ1) case len(work) < n: panic(shortWork) case n1 < 0 || 2 < n1: panic(badN1) case n2 < 0 || 2 < n2: panic(badN2) } if n == 0 || n1 == 0 || n2 == 0 { return true } switch { case len(t) < (n-1)*ldt+n: panic(shortT) case wantq && len(q) < (n-1)*ldq+n: panic(shortQ) } if j1+n1 >= n { // TODO(vladimir-ch): Reference LAPACK does this check whether // the start of the second block is in the matrix T. It returns // true if it is not and moreover it does not check whether the // whole second block fits into T. This does not feel // satisfactory. The only caller of Dlaexc is Dtrexc, so if the // caller makes sure that this does not happen, we could be // stricter here. return true } j2 := j1 + 1 j3 := j1 + 2 bi := blas64.Implementation() if n1 == 1 && n2 == 1 { // Swap two 1×1 blocks. t11 := t[j1*ldt+j1] t22 := t[j2*ldt+j2] // Determine the transformation to perform the interchange. cs, sn, _ := impl.Dlartg(t[j1*ldt+j2], t22-t11) // Apply transformation to the matrix T. if n-j3 > 0 { bi.Drot(n-j3, t[j1*ldt+j3:], 1, t[j2*ldt+j3:], 1, cs, sn) } if j1 > 0 { bi.Drot(j1, t[j1:], ldt, t[j2:], ldt, cs, sn) } t[j1*ldt+j1] = t22 t[j2*ldt+j2] = t11 if wantq { // Accumulate transformation in the matrix Q. bi.Drot(n, q[j1:], ldq, q[j2:], ldq, cs, sn) } return true } // Swapping involves at least one 2×2 block. // // Copy the diagonal block of order n1+n2 to the local array d and // compute its norm. nd := n1 + n2 var d [16]float64 const ldd = 4 impl.Dlacpy(blas.All, nd, nd, t[j1*ldt+j1:], ldt, d[:], ldd) dnorm := impl.Dlange(lapack.MaxAbs, nd, nd, d[:], ldd, work) // Compute machine-dependent threshold for test for accepting swap. eps := dlamchP thresh := math.Max(10*eps*dnorm, dlamchS/eps) // Solve T11*X - X*T22 = scale*T12 for X. var x [4]float64 const ldx = 2 scale, _, _ := impl.Dlasy2(false, false, -1, n1, n2, d[:], ldd, d[n1*ldd+n1:], ldd, d[n1:], ldd, x[:], ldx) // Swap the adjacent diagonal blocks. switch { case n1 == 1 && n2 == 2: // Generate elementary reflector H so that // ( scale, X11, X12 ) H = ( 0, 0, * ) u := [3]float64{scale, x[0], 1} _, tau := impl.Dlarfg(3, x[1], u[:2], 1) t11 := t[j1*ldt+j1] // Perform swap provisionally on diagonal block in d. impl.Dlarfx(blas.Left, 3, 3, u[:], tau, d[:], ldd, work) impl.Dlarfx(blas.Right, 3, 3, u[:], tau, d[:], ldd, work) // Test whether to reject swap. if math.Max(math.Abs(d[2*ldd]), math.Max(math.Abs(d[2*ldd+1]), math.Abs(d[2*ldd+2]-t11))) > thresh { return false } // Accept swap: apply transformation to the entire matrix T. impl.Dlarfx(blas.Left, 3, n-j1, u[:], tau, t[j1*ldt+j1:], ldt, work) impl.Dlarfx(blas.Right, j2+1, 3, u[:], tau, t[j1:], ldt, work) t[j3*ldt+j1] = 0 t[j3*ldt+j2] = 0 t[j3*ldt+j3] = t11 if wantq { // Accumulate transformation in the matrix Q. impl.Dlarfx(blas.Right, n, 3, u[:], tau, q[j1:], ldq, work) } case n1 == 2 && n2 == 1: // Generate elementary reflector H so that: // H ( -X11 ) = ( * ) // ( -X21 ) = ( 0 ) // ( scale ) = ( 0 ) u := [3]float64{1, -x[ldx], scale} _, tau := impl.Dlarfg(3, -x[0], u[1:], 1) t33 := t[j3*ldt+j3] // Perform swap provisionally on diagonal block in D. impl.Dlarfx(blas.Left, 3, 3, u[:], tau, d[:], ldd, work) impl.Dlarfx(blas.Right, 3, 3, u[:], tau, d[:], ldd, work) // Test whether to reject swap. if math.Max(math.Abs(d[ldd]), math.Max(math.Abs(d[2*ldd]), math.Abs(d[0]-t33))) > thresh { return false } // Accept swap: apply transformation to the entire matrix T. impl.Dlarfx(blas.Right, j3+1, 3, u[:], tau, t[j1:], ldt, work) impl.Dlarfx(blas.Left, 3, n-j1-1, u[:], tau, t[j1*ldt+j2:], ldt, work) t[j1*ldt+j1] = t33 t[j2*ldt+j1] = 0 t[j3*ldt+j1] = 0 if wantq { // Accumulate transformation in the matrix Q. impl.Dlarfx(blas.Right, n, 3, u[:], tau, q[j1:], ldq, work) } default: // n1 == 2 && n2 == 2 // Generate elementary reflectors H_1 and H_2 so that: // H_2 H_1 ( -X11 -X12 ) = ( * * ) // ( -X21 -X22 ) ( 0 * ) // ( scale 0 ) ( 0 0 ) // ( 0 scale ) ( 0 0 ) u1 := [3]float64{1, -x[ldx], scale} _, tau1 := impl.Dlarfg(3, -x[0], u1[1:], 1) temp := -tau1 * (x[1] + u1[1]*x[ldx+1]) u2 := [3]float64{1, -temp * u1[2], scale} _, tau2 := impl.Dlarfg(3, -temp*u1[1]-x[ldx+1], u2[1:], 1) // Perform swap provisionally on diagonal block in D. impl.Dlarfx(blas.Left, 3, 4, u1[:], tau1, d[:], ldd, work) impl.Dlarfx(blas.Right, 4, 3, u1[:], tau1, d[:], ldd, work) impl.Dlarfx(blas.Left, 3, 4, u2[:], tau2, d[ldd:], ldd, work) impl.Dlarfx(blas.Right, 4, 3, u2[:], tau2, d[1:], ldd, work) // Test whether to reject swap. m1 := math.Max(math.Abs(d[2*ldd]), math.Abs(d[2*ldd+1])) m2 := math.Max(math.Abs(d[3*ldd]), math.Abs(d[3*ldd+1])) if math.Max(m1, m2) > thresh { return false } // Accept swap: apply transformation to the entire matrix T. j4 := j1 + 3 impl.Dlarfx(blas.Left, 3, n-j1, u1[:], tau1, t[j1*ldt+j1:], ldt, work) impl.Dlarfx(blas.Right, j4+1, 3, u1[:], tau1, t[j1:], ldt, work) impl.Dlarfx(blas.Left, 3, n-j1, u2[:], tau2, t[j2*ldt+j1:], ldt, work) impl.Dlarfx(blas.Right, j4+1, 3, u2[:], tau2, t[j2:], ldt, work) t[j3*ldt+j1] = 0 t[j3*ldt+j2] = 0 t[j4*ldt+j1] = 0 t[j4*ldt+j2] = 0 if wantq { // Accumulate transformation in the matrix Q. impl.Dlarfx(blas.Right, n, 3, u1[:], tau1, q[j1:], ldq, work) impl.Dlarfx(blas.Right, n, 3, u2[:], tau2, q[j2:], ldq, work) } } if n2 == 2 { // Standardize new 2×2 block T11. a, b := t[j1*ldt+j1], t[j1*ldt+j2] c, d := t[j2*ldt+j1], t[j2*ldt+j2] var cs, sn float64 t[j1*ldt+j1], t[j1*ldt+j2], t[j2*ldt+j1], t[j2*ldt+j2], _, _, _, _, cs, sn = impl.Dlanv2(a, b, c, d) if n-j1-2 > 0 { bi.Drot(n-j1-2, t[j1*ldt+j1+2:], 1, t[j2*ldt+j1+2:], 1, cs, sn) } if j1 > 0 { bi.Drot(j1, t[j1:], ldt, t[j2:], ldt, cs, sn) } if wantq { bi.Drot(n, q[j1:], ldq, q[j2:], ldq, cs, sn) } } if n1 == 2 { // Standardize new 2×2 block T22. j3 := j1 + n2 j4 := j3 + 1 a, b := t[j3*ldt+j3], t[j3*ldt+j4] c, d := t[j4*ldt+j3], t[j4*ldt+j4] var cs, sn float64 t[j3*ldt+j3], t[j3*ldt+j4], t[j4*ldt+j3], t[j4*ldt+j4], _, _, _, _, cs, sn = impl.Dlanv2(a, b, c, d) if n-j3-2 > 0 { bi.Drot(n-j3-2, t[j3*ldt+j3+2:], 1, t[j4*ldt+j3+2:], 1, cs, sn) } bi.Drot(j3, t[j3:], ldt, t[j4:], ldt, cs, sn) if wantq { bi.Drot(n, q[j3:], ldq, q[j4:], ldq, cs, sn) } } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlag2.go000066400000000000000000000147561450372207100215530ustar00rootroot00000000000000// Copyright ©2021 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" // Dlag2 computes the eigenvalues of a 2×2 generalized eigenvalue problem // // A - w*B // // where B is an upper triangular matrix. // // Dlag2 uses scaling as necessary to avoid over-/underflow. Scaling results in // a modified eigenvalue problem // // s*A - w*B // // where s is a non-negative scaling factor chosen so that w, w*B, and s*A do // not overflow and, if possible, do not underflow, either. // // scale1 and scale2 are used to avoid over-/underflow in the eigenvalue // equation which defines the first and second eigenvalue respectively. Note // that scale1 and scale2 may be zero or less than the underflow threshold if // the corresponding exact eigenvalue is sufficiently large. // // If the eigenvalues are real, then: // - wi is zero, // - the eigenvalues are wr1/scale1 and wr2/scale2. // // If the eigenvalues are complex, then: // - wi is non-negative, // - the eigenvalues are (wr1 ± wi*i)/scale1, // - wr1 = wr2, // - scale1 = scale2. // // Dlag2 assumes that the one-norm of A and B is less than 1/dlamchS. Entries of // A less than sqrt(dlamchS)*norm(A) are subject to being treated as zero. The // diagonals of B should be at least sqrt(dlamchS) times the largest element of // B (in absolute value); if a diagonal is smaller than that, then // ±sqrt(dlamchS) will be used instead of that diagonal. // // Dlag2 is an internal routine. It is exported for testing purposes. func (Implementation) Dlag2(a []float64, lda int, b []float64, ldb int) (scale1, scale2, wr1, wr2, wi float64) { switch { case lda < 2: panic(badLdA) case ldb < 2: panic(badLdB) case len(a) < lda+2: panic(shortA) case len(b) < ldb+2: panic(shortB) } const ( safmin = dlamchS safmax = 1 / safmin fuzzy1 = 1 + 1e-5 ) rtmin := math.Sqrt(safmin) rtmax := 1 / rtmin // Scale A. anorm := math.Max(math.Abs(a[0])+math.Abs(a[lda]), math.Abs(a[1])+math.Abs(a[lda+1])) anorm = math.Max(anorm, safmin) ascale := 1 / anorm a11 := ascale * a[0] a21 := ascale * a[lda] a12 := ascale * a[1] a22 := ascale * a[lda+1] // Perturb B if necessary to insure non-singularity. b11 := b[0] b12 := b[1] b22 := b[ldb+1] bmin := rtmin * math.Max(math.Max(math.Abs(b11), math.Abs(b12)), math.Max(math.Abs(b22), rtmin)) if math.Abs(b11) < bmin { b11 = math.Copysign(bmin, b11) } if math.Abs(b22) < bmin { b22 = math.Copysign(bmin, b22) } // Scale B. bnorm := math.Max(math.Max(math.Abs(b11), math.Abs(b12)+math.Abs(b22)), safmin) bsize := math.Max(math.Abs(b11), math.Abs(b22)) bscale := 1 / bsize b11 *= bscale b12 *= bscale b22 *= bscale // Compute larger eigenvalue by method described by C. van Loan. var ( as12, abi22 float64 pp, qq, shift float64 ) binv11 := 1 / b11 binv22 := 1 / b22 s1 := a11 * binv11 s2 := a22 * binv22 // AS is A shifted by -shift*B. if math.Abs(s1) <= math.Abs(s2) { shift = s1 as12 = a12 - shift*b12 as22 := a22 - shift*b22 ss := a21 * (binv11 * binv22) abi22 = as22*binv22 - ss*b12 pp = 0.5 * abi22 qq = ss * as12 } else { shift = s2 as12 = a12 - shift*b12 as11 := a11 - shift*b11 ss := a21 * (binv11 * binv22) abi22 = -ss * b12 pp = 0.5 * (as11*binv11 + abi22) qq = ss * as12 } var discr, r float64 if math.Abs(pp*rtmin) >= 1 { tmp := rtmin * pp discr = tmp*tmp + qq*safmin r = math.Sqrt(math.Abs(discr)) * rtmax } else { pp2 := pp * pp if pp2+math.Abs(qq) <= safmin { tmp := rtmax * pp discr = tmp*tmp + qq*safmax r = math.Sqrt(math.Abs(discr)) * rtmin } else { discr = pp2 + qq r = math.Sqrt(math.Abs(discr)) } } // TODO(vladimir-ch): Is the following comment from the reference needed in // a Go implementation? // // Note: the test of r in the following `if` is to cover the case when discr // is small and negative and is flushed to zero during the calculation of r. // On machines which have a consistent flush-to-zero threshold and handle // numbers above that threshold correctly, it would not be necessary. if discr >= 0 || r == 0 { sum := pp + math.Copysign(r, pp) diff := pp - math.Copysign(r, pp) wbig := shift + sum // Compute smaller eigenvalue. wsmall := shift + diff if 0.5*math.Abs(wbig) > math.Max(math.Abs(wsmall), safmin) { wdet := (a11*a22 - a12*a21) * (binv11 * binv22) wsmall = wdet / wbig } // Choose (real) eigenvalue closest to 2,2 element of A*B^{-1} for wr1. if pp > abi22 { wr1 = math.Min(wbig, wsmall) wr2 = math.Max(wbig, wsmall) } else { wr1 = math.Max(wbig, wsmall) wr2 = math.Min(wbig, wsmall) } } else { // Complex eigenvalues. wr1 = shift + pp wr2 = wr1 wi = r } // Further scaling to avoid underflow and overflow in computing // scale1 and overflow in computing w*B. // // This scale factor (wscale) is bounded from above using c1 and c2, // and from below using c3 and c4: // - c1 implements the condition s*A must never overflow. // - c2 implements the condition w*B must never overflow. // - c3, with c2, implement the condition that s*A - w*B must never overflow. // - c4 implements the condition s should not underflow. // - c5 implements the condition max(s,|w|) should be at least 2. c1 := bsize * (safmin * math.Max(1, ascale)) c2 := safmin * math.Max(1, bnorm) c3 := bsize * safmin c4 := 1.0 c5 := 1.0 if ascale <= 1 || bsize <= 1 { c5 = math.Min(1, ascale*bsize) if ascale <= 1 && bsize <= 1 { c4 = math.Min(1, (ascale/safmin)*bsize) } } // Scale first eigenvalue. wabs := math.Abs(wr1) + math.Abs(wi) wsize := math.Max(math.Max(safmin, c1), math.Max(fuzzy1*(wabs*c2+c3), math.Min(c4, 0.5*math.Max(wabs, c5)))) maxABsize := math.Max(ascale, bsize) minABsize := math.Min(ascale, bsize) if wsize != 1 { wscale := 1 / wsize if wsize > 1 { scale1 = (maxABsize * wscale) * minABsize } else { scale1 = (minABsize * wscale) * maxABsize } wr1 *= wscale if wi != 0 { wi *= wscale wr2 = wr1 scale2 = scale1 } } else { scale1 = ascale * bsize scale2 = scale1 } // Scale second eigenvalue if real. if wi == 0 { wsize = math.Max(math.Max(safmin, c1), math.Max(fuzzy1*(math.Abs(wr2)*c2+c3), math.Min(c4, 0.5*math.Max(math.Abs(wr2), c5)))) if wsize != 1 { wscale := 1 / wsize if wsize > 1 { scale2 = (maxABsize * wscale) * minABsize } else { scale2 = (minABsize * wscale) * maxABsize } wr2 *= wscale } else { scale2 = ascale * bsize } } return scale1, scale2, wr1, wr2, wi } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlags2.go000066400000000000000000000121021450372207100217150ustar00rootroot00000000000000// 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" // Dlags2 computes 2-by-2 orthogonal matrices U, V and Q with the // triangles of A and B specified by upper. // // If upper is true // // Uᵀ*A*Q = Uᵀ*[ a1 a2 ]*Q = [ x 0 ] // [ 0 a3 ] [ x x ] // // and // // Vᵀ*B*Q = Vᵀ*[ b1 b2 ]*Q = [ x 0 ] // [ 0 b3 ] [ x x ] // // otherwise // // Uᵀ*A*Q = Uᵀ*[ a1 0 ]*Q = [ x x ] // [ a2 a3 ] [ 0 x ] // // and // // Vᵀ*B*Q = Vᵀ*[ b1 0 ]*Q = [ x x ] // [ b2 b3 ] [ 0 x ]. // // The rows of the transformed A and B are parallel, where // // U = [ csu snu ], V = [ csv snv ], Q = [ csq snq ] // [ -snu csu ] [ -snv csv ] [ -snq csq ] // // Dlags2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlags2(upper bool, a1, a2, a3, b1, b2, b3 float64) (csu, snu, csv, snv, csq, snq float64) { if upper { // Input matrices A and B are upper triangular matrices. // // Form matrix C = A*adj(B) = [ a b ] // [ 0 d ] a := a1 * b3 d := a3 * b1 b := a2*b1 - a1*b2 // The SVD of real 2-by-2 triangular C. // // [ csl -snl ]*[ a b ]*[ csr snr ] = [ r 0 ] // [ snl csl ] [ 0 d ] [ -snr csr ] [ 0 t ] _, _, snr, csr, snl, csl := impl.Dlasv2(a, b, d) if math.Abs(csl) >= math.Abs(snl) || math.Abs(csr) >= math.Abs(snr) { // Compute the [0, 0] and [0, 1] elements of Uᵀ*A and Vᵀ*B, // and [0, 1] element of |U|ᵀ*|A| and |V|ᵀ*|B|. ua11r := csl * a1 ua12 := csl*a2 + snl*a3 vb11r := csr * b1 vb12 := csr*b2 + snr*b3 aua12 := math.Abs(csl)*math.Abs(a2) + math.Abs(snl)*math.Abs(a3) avb12 := math.Abs(csr)*math.Abs(b2) + math.Abs(snr)*math.Abs(b3) // Zero [0, 1] elements of Uᵀ*A and Vᵀ*B. if math.Abs(ua11r)+math.Abs(ua12) != 0 { if aua12/(math.Abs(ua11r)+math.Abs(ua12)) <= avb12/(math.Abs(vb11r)+math.Abs(vb12)) { csq, snq, _ = impl.Dlartg(-ua11r, ua12) } else { csq, snq, _ = impl.Dlartg(-vb11r, vb12) } } else { csq, snq, _ = impl.Dlartg(-vb11r, vb12) } csu = csl snu = -snl csv = csr snv = -snr } else { // Compute the [1, 0] and [1, 1] elements of Uᵀ*A and Vᵀ*B, // and [1, 1] element of |U|ᵀ*|A| and |V|ᵀ*|B|. ua21 := -snl * a1 ua22 := -snl*a2 + csl*a3 vb21 := -snr * b1 vb22 := -snr*b2 + csr*b3 aua22 := math.Abs(snl)*math.Abs(a2) + math.Abs(csl)*math.Abs(a3) avb22 := math.Abs(snr)*math.Abs(b2) + math.Abs(csr)*math.Abs(b3) // Zero [1, 1] elements of Uᵀ*A and Vᵀ*B, and then swap. if math.Abs(ua21)+math.Abs(ua22) != 0 { if aua22/(math.Abs(ua21)+math.Abs(ua22)) <= avb22/(math.Abs(vb21)+math.Abs(vb22)) { csq, snq, _ = impl.Dlartg(-ua21, ua22) } else { csq, snq, _ = impl.Dlartg(-vb21, vb22) } } else { csq, snq, _ = impl.Dlartg(-vb21, vb22) } csu = snl snu = csl csv = snr snv = csr } } else { // Input matrices A and B are lower triangular matrices // // Form matrix C = A*adj(B) = [ a 0 ] // [ c d ] a := a1 * b3 d := a3 * b1 c := a2*b3 - a3*b2 // The SVD of real 2-by-2 triangular C // // [ csl -snl ]*[ a 0 ]*[ csr snr ] = [ r 0 ] // [ snl csl ] [ c d ] [ -snr csr ] [ 0 t ] _, _, snr, csr, snl, csl := impl.Dlasv2(a, c, d) if math.Abs(csr) >= math.Abs(snr) || math.Abs(csl) >= math.Abs(snl) { // Compute the [1, 0] and [1, 1] elements of Uᵀ*A and Vᵀ*B, // and [1, 0] element of |U|ᵀ*|A| and |V|ᵀ*|B|. ua21 := -snr*a1 + csr*a2 ua22r := csr * a3 vb21 := -snl*b1 + csl*b2 vb22r := csl * b3 aua21 := math.Abs(snr)*math.Abs(a1) + math.Abs(csr)*math.Abs(a2) avb21 := math.Abs(snl)*math.Abs(b1) + math.Abs(csl)*math.Abs(b2) // Zero [1, 0] elements of Uᵀ*A and Vᵀ*B. if (math.Abs(ua21) + math.Abs(ua22r)) != 0 { if aua21/(math.Abs(ua21)+math.Abs(ua22r)) <= avb21/(math.Abs(vb21)+math.Abs(vb22r)) { csq, snq, _ = impl.Dlartg(ua22r, ua21) } else { csq, snq, _ = impl.Dlartg(vb22r, vb21) } } else { csq, snq, _ = impl.Dlartg(vb22r, vb21) } csu = csr snu = -snr csv = csl snv = -snl } else { // Compute the [0, 0] and [0, 1] elements of Uᵀ *A and Vᵀ *B, // and [0, 0] element of |U|ᵀ*|A| and |V|ᵀ*|B|. ua11 := csr*a1 + snr*a2 ua12 := snr * a3 vb11 := csl*b1 + snl*b2 vb12 := snl * b3 aua11 := math.Abs(csr)*math.Abs(a1) + math.Abs(snr)*math.Abs(a2) avb11 := math.Abs(csl)*math.Abs(b1) + math.Abs(snl)*math.Abs(b2) // Zero [0, 0] elements of Uᵀ*A and Vᵀ*B, and then swap. if (math.Abs(ua11) + math.Abs(ua12)) != 0 { if aua11/(math.Abs(ua11)+math.Abs(ua12)) <= avb11/(math.Abs(vb11)+math.Abs(vb12)) { csq, snq, _ = impl.Dlartg(ua12, ua11) } else { csq, snq, _ = impl.Dlartg(vb12, vb11) } } else { csq, snq, _ = impl.Dlartg(vb12, vb11) } csu = snr snu = csr csv = snl snv = csl } } return csu, snu, csv, snv, csq, snq } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlagtm.go000066400000000000000000000046061450372207100220230ustar00rootroot00000000000000// Copyright ©2020 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" // Dlagtm performs one of the matrix-matrix operations // // C = alpha * A * B + beta * C if trans == blas.NoTrans // C = alpha * Aᵀ * B + beta * C if trans == blas.Trans or blas.ConjTrans // // where A is an m×m tridiagonal matrix represented by its diagonals dl, d, du, // B and C are m×n dense matrices, and alpha and beta are scalars. func (impl Implementation) Dlagtm(trans blas.Transpose, m, n int, alpha float64, dl, d, du []float64, b []float64, ldb int, beta float64, c []float64, ldc int) { switch { case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case ldb < max(1, n): panic(badLdB) case ldc < max(1, n): panic(badLdC) } if m == 0 || n == 0 { return } switch { case len(dl) < m-1: panic(shortDL) case len(d) < m: panic(shortD) case len(du) < m-1: panic(shortDU) case len(b) < (m-1)*ldb+n: panic(shortB) case len(c) < (m-1)*ldc+n: panic(shortC) } if beta != 1 { if beta == 0 { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] *= beta } } } } if alpha == 0 { return } if m == 1 { if alpha == 1 { for j := 0; j < n; j++ { c[j] += d[0] * b[j] } } else { for j := 0; j < n; j++ { c[j] += alpha * d[0] * b[j] } } return } if trans != blas.NoTrans { dl, du = du, dl } if alpha == 1 { for j := 0; j < n; j++ { c[j] += d[0]*b[j] + du[0]*b[ldb+j] } for i := 1; i < m-1; i++ { for j := 0; j < n; j++ { c[i*ldc+j] += dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j] } } for j := 0; j < n; j++ { c[(m-1)*ldc+j] += dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j] } } else { for j := 0; j < n; j++ { c[j] += alpha * (d[0]*b[j] + du[0]*b[ldb+j]) } for i := 1; i < m-1; i++ { for j := 0; j < n; j++ { c[i*ldc+j] += alpha * (dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j]) } } for j := 0; j < n; j++ { c[(m-1)*ldc+j] += alpha * (dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j]) } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlahqr.go000066400000000000000000000315311450372207100220230ustar00rootroot00000000000000// Copyright ©2016 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/blas64" ) // Dlahqr computes the eigenvalues and Schur factorization of a block of an n×n // upper Hessenberg matrix H, using the double-shift/single-shift QR algorithm. // // h and ldh represent the matrix H. Dlahqr works primarily with the Hessenberg // submatrix H[ilo:ihi+1,ilo:ihi+1], but applies transformations to all of H if // wantt is true. It is assumed that H[ihi+1:n,ihi+1:n] is already upper // quasi-triangular, although this is not checked. // // It must hold that // // 0 <= ilo <= max(0,ihi), and ihi < n, // // and that // // H[ilo,ilo-1] == 0, if ilo > 0, // // otherwise Dlahqr will panic. // // If unconverged is zero on return, wr[ilo:ihi+1] and wi[ilo:ihi+1] will contain // respectively the real and imaginary parts of the computed eigenvalues ilo // to ihi. If two eigenvalues are computed as a complex conjugate pair, they are // stored in consecutive elements of wr and wi, say the i-th and (i+1)th, with // wi[i] > 0 and wi[i+1] < 0. If wantt is true, the eigenvalues are stored in // the same order as on the diagonal of the Schur form returned in H, with // wr[i] = H[i,i], and, if H[i:i+2,i:i+2] is a 2×2 diagonal block, // wi[i] = sqrt(abs(H[i+1,i]*H[i,i+1])) and wi[i+1] = -wi[i]. // // wr and wi must have length ihi+1. // // z and ldz represent an n×n matrix Z. If wantz is true, the transformations // will be applied to the submatrix Z[iloz:ihiz+1,ilo:ihi+1] and it must hold that // // 0 <= iloz <= ilo, and ihi <= ihiz < n. // // If wantz is false, z is not referenced. // // unconverged indicates whether Dlahqr computed all the eigenvalues ilo to ihi // in a total of 30 iterations per eigenvalue. // // If unconverged is zero, all the eigenvalues ilo to ihi have been computed and // will be stored on return in wr[ilo:ihi+1] and wi[ilo:ihi+1]. // // If unconverged is zero and wantt is true, H[ilo:ihi+1,ilo:ihi+1] will be // overwritten on return by upper quasi-triangular full Schur form with any // 2×2 diagonal blocks in standard form. // // If unconverged is zero and if wantt is false, the contents of h on return is // unspecified. // // If unconverged is positive, some eigenvalues have not converged, and // wr[unconverged:ihi+1] and wi[unconverged:ihi+1] contain those eigenvalues // which have been successfully computed. // // If unconverged is positive and wantt is true, then on return // // (initial H)*U = U*(final H), (*) // // where U is an orthogonal matrix. The final H is upper Hessenberg and // H[unconverged:ihi+1,unconverged:ihi+1] is upper quasi-triangular. // // If unconverged is positive and wantt is false, on return the remaining // unconverged eigenvalues are the eigenvalues of the upper Hessenberg matrix // H[ilo:unconverged,ilo:unconverged]. // // If unconverged is positive and wantz is true, then on return // // (final Z) = (initial Z)*U, // // where U is the orthogonal matrix in (*) regardless of the value of wantt. // // Dlahqr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlahqr(wantt, wantz bool, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, iloz, ihiz int, z []float64, ldz int) (unconverged int) { switch { case n < 0: panic(nLT0) case ilo < 0, max(0, ihi) < ilo: panic(badIlo) case ihi >= n: panic(badIhi) case ldh < max(1, n): panic(badLdH) case wantz && (iloz < 0 || ilo < iloz): panic(badIloz) case wantz && (ihiz < ihi || n <= ihiz): panic(badIhiz) case ldz < 1, wantz && ldz < n: panic(badLdZ) } // Quick return if possible. if n == 0 { return 0 } switch { case len(h) < (n-1)*ldh+n: panic(shortH) case len(wr) != ihi+1: panic(shortWr) case len(wi) != ihi+1: panic(shortWi) case wantz && len(z) < (n-1)*ldz+n: panic(shortZ) case ilo > 0 && h[ilo*ldh+ilo-1] != 0: panic(notIsolated) } if ilo == ihi { wr[ilo] = h[ilo*ldh+ilo] wi[ilo] = 0 return 0 } // Clear out the trash. for j := ilo; j < ihi-2; j++ { h[(j+2)*ldh+j] = 0 h[(j+3)*ldh+j] = 0 } if ilo <= ihi-2 { h[ihi*ldh+ihi-2] = 0 } nh := ihi - ilo + 1 nz := ihiz - iloz + 1 // Set machine-dependent constants for the stopping criterion. ulp := dlamchP smlnum := float64(nh) / ulp * dlamchS // i1 and i2 are the indices of the first row and last column of H to // which transformations must be applied. If eigenvalues only are being // computed, i1 and i2 are set inside the main loop. var i1, i2 int if wantt { i1 = 0 i2 = n - 1 } itmax := 30 * max(10, nh) // Total number of QR iterations allowed. // kdefl counts the number of iterations since a deflation. kdefl := 0 // The main loop begins here. i is the loop index and decreases from ihi // to ilo in steps of 1 or 2. Each iteration of the loop works with the // active submatrix in rows and columns l to i. Eigenvalues i+1 to ihi // have already converged. Either l = ilo or H[l,l-1] is negligible so // that the matrix splits. bi := blas64.Implementation() i := ihi for i >= ilo { l := ilo // Perform QR iterations on rows and columns ilo to i until a // submatrix of order 1 or 2 splits off at the bottom because a // subdiagonal element has become negligible. converged := false for its := 0; its <= itmax; its++ { // Look for a single small subdiagonal element. var k int for k = i; k > l; k-- { if math.Abs(h[k*ldh+k-1]) <= smlnum { break } tst := math.Abs(h[(k-1)*ldh+k-1]) + math.Abs(h[k*ldh+k]) if tst == 0 { if k-2 >= ilo { tst += math.Abs(h[(k-1)*ldh+k-2]) } if k+1 <= ihi { tst += math.Abs(h[(k+1)*ldh+k]) } } // The following is a conservative small // subdiagonal deflation criterion due to Ahues // & Tisseur (LAWN 122, 1997). It has better // mathematical foundation and improves accuracy // in some cases. if math.Abs(h[k*ldh+k-1]) <= ulp*tst { ab := math.Max(math.Abs(h[k*ldh+k-1]), math.Abs(h[(k-1)*ldh+k])) ba := math.Min(math.Abs(h[k*ldh+k-1]), math.Abs(h[(k-1)*ldh+k])) aa := math.Max(math.Abs(h[k*ldh+k]), math.Abs(h[(k-1)*ldh+k-1]-h[k*ldh+k])) bb := math.Min(math.Abs(h[k*ldh+k]), math.Abs(h[(k-1)*ldh+k-1]-h[k*ldh+k])) s := aa + ab if ab/s*ba <= math.Max(smlnum, aa/s*bb*ulp) { break } } } l = k if l > ilo { // H[l,l-1] is negligible. h[l*ldh+l-1] = 0 } if l >= i-1 { // Break the loop because a submatrix of order 1 // or 2 has split off. converged = true break } kdefl++ // Now the active submatrix is in rows and columns l to // i. If eigenvalues only are being computed, only the // active submatrix need be transformed. if !wantt { i1 = l i2 = i } const ( dat1 = 0.75 dat2 = -0.4375 kexsh = 10 ) var h11, h21, h12, h22 float64 switch { case kdefl%(2*kexsh) == 0: // Exceptional shift. s := math.Abs(h[i*ldh+i-1]) + math.Abs(h[(i-1)*ldh+i-2]) h11 = dat1*s + h[i*ldh+i] h12 = dat2 * s h21 = s h22 = h11 case kdefl%kexsh == 0: // Exceptional shift. s := math.Abs(h[(l+1)*ldh+l]) + math.Abs(h[(l+2)*ldh+l+1]) h11 = dat1*s + h[l*ldh+l] h12 = dat2 * s h21 = s h22 = h11 default: // Prepare to use Francis' double shift (i.e., // 2nd degree generalized Rayleigh quotient). h11 = h[(i-1)*ldh+i-1] h21 = h[i*ldh+i-1] h12 = h[(i-1)*ldh+i] h22 = h[i*ldh+i] } s := math.Abs(h11) + math.Abs(h12) + math.Abs(h21) + math.Abs(h22) var ( rt1r, rt1i float64 rt2r, rt2i float64 ) if s != 0 { h11 /= s h21 /= s h12 /= s h22 /= s tr := (h11 + h22) / 2 det := (h11-tr)*(h22-tr) - h12*h21 rtdisc := math.Sqrt(math.Abs(det)) if det >= 0 { // Complex conjugate shifts. rt1r = tr * s rt2r = rt1r rt1i = rtdisc * s rt2i = -rt1i } else { // Real shifts (use only one of them). rt1r = tr + rtdisc rt2r = tr - rtdisc if math.Abs(rt1r-h22) <= math.Abs(rt2r-h22) { rt1r *= s rt2r = rt1r } else { rt2r *= s rt1r = rt2r } rt1i = 0 rt2i = 0 } } // Look for two consecutive small subdiagonal elements. var m int var v [3]float64 for m = i - 2; m >= l; m-- { // Determine the effect of starting the // double-shift QR iteration at row m, and see // if this would make H[m,m-1] negligible. The // following uses scaling to avoid overflows and // most underflows. h21s := h[(m+1)*ldh+m] s := math.Abs(h[m*ldh+m]-rt2r) + math.Abs(rt2i) + math.Abs(h21s) h21s /= s v[0] = h21s*h[m*ldh+m+1] + (h[m*ldh+m]-rt1r)*((h[m*ldh+m]-rt2r)/s) - rt2i/s*rt1i v[1] = h21s * (h[m*ldh+m] + h[(m+1)*ldh+m+1] - rt1r - rt2r) v[2] = h21s * h[(m+2)*ldh+m+1] s = math.Abs(v[0]) + math.Abs(v[1]) + math.Abs(v[2]) v[0] /= s v[1] /= s v[2] /= s if m == l { break } dsum := math.Abs(h[(m-1)*ldh+m-1]) + math.Abs(h[m*ldh+m]) + math.Abs(h[(m+1)*ldh+m+1]) if math.Abs(h[m*ldh+m-1])*(math.Abs(v[1])+math.Abs(v[2])) <= ulp*math.Abs(v[0])*dsum { break } } // Double-shift QR step. for k := m; k < i; k++ { // The first iteration of this loop determines a // reflection G from the vector V and applies it // from left and right to H, thus creating a // non-zero bulge below the subdiagonal. // // Each subsequent iteration determines a // reflection G to restore the Hessenberg form // in the (k-1)th column, and thus chases the // bulge one step toward the bottom of the // active submatrix. nr is the order of G. nr := min(3, i-k+1) if k > m { bi.Dcopy(nr, h[k*ldh+k-1:], ldh, v[:], 1) } var t0 float64 v[0], t0 = impl.Dlarfg(nr, v[0], v[1:], 1) if k > m { h[k*ldh+k-1] = v[0] h[(k+1)*ldh+k-1] = 0 if k < i-1 { h[(k+2)*ldh+k-1] = 0 } } else if m > l { // Use the following instead of H[k,k-1] = -H[k,k-1] // to avoid a bug when v[1] and v[2] underflow. h[k*ldh+k-1] *= 1 - t0 } t1 := t0 * v[1] if nr == 3 { t2 := t0 * v[2] // Apply G from the left to transform // the rows of the matrix in columns k // to i2. for j := k; j <= i2; j++ { sum := h[k*ldh+j] + v[1]*h[(k+1)*ldh+j] + v[2]*h[(k+2)*ldh+j] h[k*ldh+j] -= sum * t0 h[(k+1)*ldh+j] -= sum * t1 h[(k+2)*ldh+j] -= sum * t2 } // Apply G from the right to transform // the columns of the matrix in rows i1 // to min(k+3,i). for j := i1; j <= min(k+3, i); j++ { sum := h[j*ldh+k] + v[1]*h[j*ldh+k+1] + v[2]*h[j*ldh+k+2] h[j*ldh+k] -= sum * t0 h[j*ldh+k+1] -= sum * t1 h[j*ldh+k+2] -= sum * t2 } if wantz { // Accumulate transformations in the matrix Z. for j := iloz; j <= ihiz; j++ { sum := z[j*ldz+k] + v[1]*z[j*ldz+k+1] + v[2]*z[j*ldz+k+2] z[j*ldz+k] -= sum * t0 z[j*ldz+k+1] -= sum * t1 z[j*ldz+k+2] -= sum * t2 } } } else if nr == 2 { // Apply G from the left to transform // the rows of the matrix in columns k // to i2. for j := k; j <= i2; j++ { sum := h[k*ldh+j] + v[1]*h[(k+1)*ldh+j] h[k*ldh+j] -= sum * t0 h[(k+1)*ldh+j] -= sum * t1 } // Apply G from the right to transform // the columns of the matrix in rows i1 // to min(k+3,i). for j := i1; j <= i; j++ { sum := h[j*ldh+k] + v[1]*h[j*ldh+k+1] h[j*ldh+k] -= sum * t0 h[j*ldh+k+1] -= sum * t1 } if wantz { // Accumulate transformations in the matrix Z. for j := iloz; j <= ihiz; j++ { sum := z[j*ldz+k] + v[1]*z[j*ldz+k+1] z[j*ldz+k] -= sum * t0 z[j*ldz+k+1] -= sum * t1 } } } } } if !converged { // The QR iteration finished without splitting off a // submatrix of order 1 or 2. return i + 1 } if l == i { // H[i,i-1] is negligible: one eigenvalue has converged. wr[i] = h[i*ldh+i] wi[i] = 0 } else if l == i-1 { // H[i-1,i-2] is negligible: a pair of eigenvalues have converged. // Transform the 2×2 submatrix to standard Schur form, // and compute and store the eigenvalues. var cs, sn float64 a, b := h[(i-1)*ldh+i-1], h[(i-1)*ldh+i] c, d := h[i*ldh+i-1], h[i*ldh+i] a, b, c, d, wr[i-1], wi[i-1], wr[i], wi[i], cs, sn = impl.Dlanv2(a, b, c, d) h[(i-1)*ldh+i-1], h[(i-1)*ldh+i] = a, b h[i*ldh+i-1], h[i*ldh+i] = c, d if wantt { // Apply the transformation to the rest of H. if i2 > i { bi.Drot(i2-i, h[(i-1)*ldh+i+1:], 1, h[i*ldh+i+1:], 1, cs, sn) } bi.Drot(i-i1-1, h[i1*ldh+i-1:], ldh, h[i1*ldh+i:], ldh, cs, sn) } if wantz { // Apply the transformation to Z. bi.Drot(nz, z[iloz*ldz+i-1:], ldz, z[iloz*ldz+i:], ldz, cs, sn) } } // Reset deflation counter. kdefl = 0 // Return to start of the main loop with new value of i. i = l - 1 } return 0 } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlahr2.go000066400000000000000000000134261450372207100217270ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" ) // Dlahr2 reduces the first nb columns of a real general n×(n-k+1) matrix A so // that elements below the k-th subdiagonal are zero. The reduction is performed // by an orthogonal similarity transformation Qᵀ * A * Q. Dlahr2 returns the // matrices V and T which determine Q as a block reflector I - V*T*Vᵀ, and // also the matrix Y = A * V * T. // // The matrix Q is represented as a product of nb elementary reflectors // // Q = H_0 * H_1 * ... * H_{nb-1}. // // Each H_i has the form // // H_i = I - tau[i] * v * vᵀ, // // where v is a real vector with v[0:i+k-1] = 0 and v[i+k-1] = 1. v[i+k:n] is // stored on exit in A[i+k+1:n,i]. // // The elements of the vectors v together form the (n-k+1)×nb matrix // V which is needed, with T and Y, to apply the transformation to the // unreduced part of the matrix, using an update of the form // // A = (I - V*T*Vᵀ) * (A - Y*Vᵀ). // // On entry, a contains the n×(n-k+1) general matrix A. On return, the elements // on and above the k-th subdiagonal in the first nb columns are overwritten // with the corresponding elements of the reduced matrix; the elements below the // k-th subdiagonal, with the slice tau, represent the matrix Q as a product of // elementary reflectors. The other columns of A are unchanged. // // The contents of A on exit are illustrated by the following example // with n = 7, k = 3 and nb = 2: // // [ a a a a a ] // [ a a a a a ] // [ a a a a a ] // [ h h a a a ] // [ v0 h a a a ] // [ v0 v1 a a a ] // [ v0 v1 a a a ] // // where a denotes an element of the original matrix A, h denotes a // modified element of the upper Hessenberg matrix H, and vi denotes an // element of the vector defining H_i. // // k is the offset for the reduction. Elements below the k-th subdiagonal in the // first nb columns are reduced to zero. // // nb is the number of columns to be reduced. // // On entry, a represents the n×(n-k+1) matrix A. On return, the elements on and // above the k-th subdiagonal in the first nb columns are overwritten with the // corresponding elements of the reduced matrix. The elements below the k-th // subdiagonal, with the slice tau, represent the matrix Q as a product of // elementary reflectors. The other columns of A are unchanged. // // tau will contain the scalar factors of the elementary reflectors. It must // have length at least nb. // // t and ldt represent the nb×nb upper triangular matrix T, and y and ldy // represent the n×nb matrix Y. // // Dlahr2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlahr2(n, k, nb int, a []float64, lda int, tau, t []float64, ldt int, y []float64, ldy int) { switch { case n < 0: panic(nLT0) case k < 0: panic(kLT0) case nb < 0: panic(nbLT0) case nb > n: panic(nbGTN) case lda < max(1, n-k+1): panic(badLdA) case ldt < max(1, nb): panic(badLdT) case ldy < max(1, nb): panic(badLdY) } // Quick return if possible. if n < 0 { return } switch { case len(a) < (n-1)*lda+n-k+1: panic(shortA) case len(tau) < nb: panic(shortTau) case len(t) < (nb-1)*ldt+nb: panic(shortT) case len(y) < (n-1)*ldy+nb: panic(shortY) } // Quick return if possible. if n == 1 { return } bi := blas64.Implementation() var ei float64 for i := 0; i < nb; i++ { if i > 0 { // Update A[k:n,i]. // Update i-th column of A - Y * Vᵀ. bi.Dgemv(blas.NoTrans, n-k, i, -1, y[k*ldy:], ldy, a[(k+i-1)*lda:], 1, 1, a[k*lda+i:], lda) // Apply I - V * Tᵀ * Vᵀ to this column (call it b) // from the left, using the last column of T as // workspace. // Let V = [ V1 ] and b = [ b1 ] (first i rows) // [ V2 ] [ b2 ] // where V1 is unit lower triangular. // // w := V1ᵀ * b1. bi.Dcopy(i, a[k*lda+i:], lda, t[nb-1:], ldt) bi.Dtrmv(blas.Lower, blas.Trans, blas.Unit, i, a[k*lda:], lda, t[nb-1:], ldt) // w := w + V2ᵀ * b2. bi.Dgemv(blas.Trans, n-k-i, i, 1, a[(k+i)*lda:], lda, a[(k+i)*lda+i:], lda, 1, t[nb-1:], ldt) // w := Tᵀ * w. bi.Dtrmv(blas.Upper, blas.Trans, blas.NonUnit, i, t, ldt, t[nb-1:], ldt) // b2 := b2 - V2*w. bi.Dgemv(blas.NoTrans, n-k-i, i, -1, a[(k+i)*lda:], lda, t[nb-1:], ldt, 1, a[(k+i)*lda+i:], lda) // b1 := b1 - V1*w. bi.Dtrmv(blas.Lower, blas.NoTrans, blas.Unit, i, a[k*lda:], lda, t[nb-1:], ldt) bi.Daxpy(i, -1, t[nb-1:], ldt, a[k*lda+i:], lda) a[(k+i-1)*lda+i-1] = ei } // Generate the elementary reflector H_i to annihilate // A[k+i+1:n,i]. ei, tau[i] = impl.Dlarfg(n-k-i, a[(k+i)*lda+i], a[min(k+i+1, n-1)*lda+i:], lda) a[(k+i)*lda+i] = 1 // Compute Y[k:n,i]. bi.Dgemv(blas.NoTrans, n-k, n-k-i, 1, a[k*lda+i+1:], lda, a[(k+i)*lda+i:], lda, 0, y[k*ldy+i:], ldy) bi.Dgemv(blas.Trans, n-k-i, i, 1, a[(k+i)*lda:], lda, a[(k+i)*lda+i:], lda, 0, t[i:], ldt) bi.Dgemv(blas.NoTrans, n-k, i, -1, y[k*ldy:], ldy, t[i:], ldt, 1, y[k*ldy+i:], ldy) bi.Dscal(n-k, tau[i], y[k*ldy+i:], ldy) // Compute T[0:i,i]. bi.Dscal(i, -tau[i], t[i:], ldt) bi.Dtrmv(blas.Upper, blas.NoTrans, blas.NonUnit, i, t, ldt, t[i:], ldt) t[i*ldt+i] = tau[i] } a[(k+nb-1)*lda+nb-1] = ei // Compute Y[0:k,0:nb]. impl.Dlacpy(blas.All, k, nb, a[1:], lda, y, ldy) bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, k, nb, 1, a[k*lda:], lda, y, ldy) if n > k+nb { bi.Dgemm(blas.NoTrans, blas.NoTrans, k, nb, n-k-nb, 1, a[1+nb:], lda, a[(k+nb)*lda:], lda, 1, y, ldy) } bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.NonUnit, k, nb, 1, t, ldt, y, ldy) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaln2.go000066400000000000000000000236411450372207100217270ustar00rootroot00000000000000// Copyright ©2016 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" // Dlaln2 solves a linear equation or a system of 2 linear equations of the form // // (ca A - w D) X = scale B if trans == false, // (ca Aᵀ - w D) X = scale B if trans == true, // // where A is a na×na real matrix, ca is a real scalar, D is a na×na diagonal // real matrix, w is a scalar, real if nw == 1, complex if nw == 2, and X and B // are na×1 matrices, real if w is real, complex if w is complex. // // If w is complex, X and B are represented as na×2 matrices, the first column // of each being the real part and the second being the imaginary part. // // na and nw must be 1 or 2, otherwise Dlaln2 will panic. // // d1 and d2 are the diagonal elements of D. d2 is not used if na == 1. // // wr and wi represent the real and imaginary part, respectively, of the scalar // w. wi is not used if nw == 1. // // smin is the desired lower bound on the singular values of A. This should be // a safe distance away from underflow or overflow, say, between // (underflow/machine precision) and (overflow*machine precision). // // If both singular values of (ca A - w D) are less than smin, smin*identity // will be used instead of (ca A - w D). If only one singular value is less than // smin, one element of (ca A - w D) will be perturbed enough to make the // smallest singular value roughly smin. If both singular values are at least // smin, (ca A - w D) will not be perturbed. In any case, the perturbation will // be at most some small multiple of max(smin, ulp*norm(ca A - w D)). The // singular values are computed by infinity-norm approximations, and thus will // only be correct to a factor of 2 or so. // // All input quantities are assumed to be smaller than overflow by a reasonable // factor. // // scale is a scaling factor less than or equal to 1 which is chosen so that X // can be computed without overflow. X is further scaled if necessary to assure // that norm(ca A - w D)*norm(X) is less than overflow. // // xnorm contains the infinity-norm of X when X is regarded as a na×nw real // matrix. // // ok will be false if (ca A - w D) had to be perturbed to make its smallest // singular value greater than smin, otherwise ok will be true. // // Dlaln2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaln2(trans bool, na, nw int, smin, ca float64, a []float64, lda int, d1, d2 float64, b []float64, ldb int, wr, wi float64, x []float64, ldx int) (scale, xnorm float64, ok bool) { // TODO(vladimir-ch): Consider splitting this function into two, one // handling the real case (nw == 1) and the other handling the complex // case (nw == 2). Given that Go has complex types, their signatures // would be simpler and more natural, and the implementation not as // convoluted. switch { case na != 1 && na != 2: panic(badNa) case nw != 1 && nw != 2: panic(badNw) case lda < na: panic(badLdA) case len(a) < (na-1)*lda+na: panic(shortA) case ldb < nw: panic(badLdB) case len(b) < (na-1)*ldb+nw: panic(shortB) case ldx < nw: panic(badLdX) case len(x) < (na-1)*ldx+nw: panic(shortX) } smlnum := 2 * dlamchS bignum := 1 / smlnum smini := math.Max(smin, smlnum) ok = true scale = 1 if na == 1 { // 1×1 (i.e., scalar) system C X = B. if nw == 1 { // Real 1×1 system. // C = ca A - w D. csr := ca*a[0] - wr*d1 cnorm := math.Abs(csr) // If |C| < smini, use C = smini. if cnorm < smini { csr = smini cnorm = smini ok = false } // Check scaling for X = B / C. bnorm := math.Abs(b[0]) if cnorm < 1 && bnorm > math.Max(1, bignum*cnorm) { scale = 1 / bnorm } // Compute X. x[0] = b[0] * scale / csr xnorm = math.Abs(x[0]) return scale, xnorm, ok } // Complex 1×1 system (w is complex). // C = ca A - w D. csr := ca*a[0] - wr*d1 csi := -wi * d1 cnorm := math.Abs(csr) + math.Abs(csi) // If |C| < smini, use C = smini. if cnorm < smini { csr = smini csi = 0 cnorm = smini ok = false } // Check scaling for X = B / C. bnorm := math.Abs(b[0]) + math.Abs(b[1]) if cnorm < 1 && bnorm > math.Max(1, bignum*cnorm) { scale = 1 / bnorm } // Compute X. cx := complex(scale*b[0], scale*b[1]) / complex(csr, csi) x[0], x[1] = real(cx), imag(cx) xnorm = math.Abs(x[0]) + math.Abs(x[1]) return scale, xnorm, ok } // 2×2 system. // Compute the real part of // C = ca A - w D // or // C = ca Aᵀ - w D. crv := [4]float64{ ca*a[0] - wr*d1, ca * a[1], ca * a[lda], ca*a[lda+1] - wr*d2, } if trans { crv[1] = ca * a[lda] crv[2] = ca * a[1] } pivot := [4][4]int{ {0, 1, 2, 3}, {1, 0, 3, 2}, {2, 3, 0, 1}, {3, 2, 1, 0}, } if nw == 1 { // Real 2×2 system (w is real). // Find the largest element in C. var cmax float64 var icmax int for j, v := range crv { v = math.Abs(v) if v > cmax { cmax = v icmax = j } } // If norm(C) < smini, use smini*identity. if cmax < smini { bnorm := math.Max(math.Abs(b[0]), math.Abs(b[ldb])) if smini < 1 && bnorm > math.Max(1, bignum*smini) { scale = 1 / bnorm } temp := scale / smini x[0] = temp * b[0] x[ldx] = temp * b[ldb] xnorm = temp * bnorm ok = false return scale, xnorm, ok } // Gaussian elimination with complete pivoting. // Form upper triangular matrix // [ur11 ur12] // [ 0 ur22] ur11 := crv[icmax] ur12 := crv[pivot[icmax][1]] cr21 := crv[pivot[icmax][2]] cr22 := crv[pivot[icmax][3]] ur11r := 1 / ur11 lr21 := ur11r * cr21 ur22 := cr22 - ur12*lr21 // If smaller pivot < smini, use smini. if math.Abs(ur22) < smini { ur22 = smini ok = false } var br1, br2 float64 if icmax > 1 { // If the pivot lies in the second row, swap the rows. br1 = b[ldb] br2 = b[0] } else { br1 = b[0] br2 = b[ldb] } br2 -= lr21 * br1 // Apply the Gaussian elimination step to the right-hand side. bbnd := math.Max(math.Abs(ur22*ur11r*br1), math.Abs(br2)) if bbnd > 1 && math.Abs(ur22) < 1 && bbnd >= bignum*math.Abs(ur22) { scale = 1 / bbnd } // Solve the linear system ur*xr=br. xr2 := br2 * scale / ur22 xr1 := scale*br1*ur11r - ur11r*ur12*xr2 if icmax&0x1 != 0 { // If the pivot lies in the second column, swap the components of the solution. x[0] = xr2 x[ldx] = xr1 } else { x[0] = xr1 x[ldx] = xr2 } xnorm = math.Max(math.Abs(xr1), math.Abs(xr2)) // Further scaling if norm(A)*norm(X) > overflow. if xnorm > 1 && cmax > 1 && xnorm > bignum/cmax { temp := cmax / bignum x[0] *= temp x[ldx] *= temp xnorm *= temp scale *= temp } return scale, xnorm, ok } // Complex 2×2 system (w is complex). // Find the largest element in C. civ := [4]float64{ -wi * d1, 0, 0, -wi * d2, } var cmax float64 var icmax int for j, v := range crv { v := math.Abs(v) if v+math.Abs(civ[j]) > cmax { cmax = v + math.Abs(civ[j]) icmax = j } } // If norm(C) < smini, use smini*identity. if cmax < smini { br1 := math.Abs(b[0]) + math.Abs(b[1]) br2 := math.Abs(b[ldb]) + math.Abs(b[ldb+1]) bnorm := math.Max(br1, br2) if smini < 1 && bnorm > 1 && bnorm > bignum*smini { scale = 1 / bnorm } temp := scale / smini x[0] = temp * b[0] x[1] = temp * b[1] x[ldb] = temp * b[ldb] x[ldb+1] = temp * b[ldb+1] xnorm = temp * bnorm ok = false return scale, xnorm, ok } // Gaussian elimination with complete pivoting. ur11 := crv[icmax] ui11 := civ[icmax] ur12 := crv[pivot[icmax][1]] ui12 := civ[pivot[icmax][1]] cr21 := crv[pivot[icmax][2]] ci21 := civ[pivot[icmax][2]] cr22 := crv[pivot[icmax][3]] ci22 := civ[pivot[icmax][3]] var ( ur11r, ui11r float64 lr21, li21 float64 ur12s, ui12s float64 ur22, ui22 float64 ) if icmax == 0 || icmax == 3 { // Off-diagonals of pivoted C are real. if math.Abs(ur11) > math.Abs(ui11) { temp := ui11 / ur11 ur11r = 1 / (ur11 * (1 + temp*temp)) ui11r = -temp * ur11r } else { temp := ur11 / ui11 ui11r = -1 / (ui11 * (1 + temp*temp)) ur11r = -temp * ui11r } lr21 = cr21 * ur11r li21 = cr21 * ui11r ur12s = ur12 * ur11r ui12s = ur12 * ui11r ur22 = cr22 - ur12*lr21 ui22 = ci22 - ur12*li21 } else { // Diagonals of pivoted C are real. ur11r = 1 / ur11 // ui11r is already 0. lr21 = cr21 * ur11r li21 = ci21 * ur11r ur12s = ur12 * ur11r ui12s = ui12 * ur11r ur22 = cr22 - ur12*lr21 + ui12*li21 ui22 = -ur12*li21 - ui12*lr21 } u22abs := math.Abs(ur22) + math.Abs(ui22) // If smaller pivot < smini, use smini. if u22abs < smini { ur22 = smini ui22 = 0 ok = false } var br1, bi1 float64 var br2, bi2 float64 if icmax > 1 { // If the pivot lies in the second row, swap the rows. br1 = b[ldb] bi1 = b[ldb+1] br2 = b[0] bi2 = b[1] } else { br1 = b[0] bi1 = b[1] br2 = b[ldb] bi2 = b[ldb+1] } br2 += -lr21*br1 + li21*bi1 bi2 += -li21*br1 - lr21*bi1 bbnd1 := u22abs * (math.Abs(ur11r) + math.Abs(ui11r)) * (math.Abs(br1) + math.Abs(bi1)) bbnd2 := math.Abs(br2) + math.Abs(bi2) bbnd := math.Max(bbnd1, bbnd2) if bbnd > 1 && u22abs < 1 && bbnd >= bignum*u22abs { scale = 1 / bbnd br1 *= scale bi1 *= scale br2 *= scale bi2 *= scale } cx2 := complex(br2, bi2) / complex(ur22, ui22) xr2, xi2 := real(cx2), imag(cx2) xr1 := ur11r*br1 - ui11r*bi1 - ur12s*xr2 + ui12s*xi2 xi1 := ui11r*br1 + ur11r*bi1 - ui12s*xr2 - ur12s*xi2 if icmax&0x1 != 0 { // If the pivot lies in the second column, swap the components of the solution. x[0] = xr2 x[1] = xi2 x[ldx] = xr1 x[ldx+1] = xi1 } else { x[0] = xr1 x[1] = xi1 x[ldx] = xr2 x[ldx+1] = xi2 } xnorm = math.Max(math.Abs(xr1)+math.Abs(xi1), math.Abs(xr2)+math.Abs(xi2)) // Further scaling if norm(A)*norm(X) > overflow. if xnorm > 1 && cmax > 1 && xnorm > bignum/cmax { temp := cmax / bignum x[0] *= temp x[1] *= temp x[ldx] *= temp x[ldx+1] *= temp xnorm *= temp scale *= temp } return scale, xnorm, ok } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlangb.go000066400000000000000000000037031450372207100217770ustar00rootroot00000000000000// Copyright ©2021 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/asm/f64" "gonum.org/v1/gonum/lapack" ) // Dlangb returns the given norm of an m×n band matrix with kl sub-diagonals and // ku super-diagonals. func (impl Implementation) Dlangb(norm lapack.MatrixNorm, m, n, kl, ku int, ab []float64, ldab int) float64 { ncol := kl + 1 + ku switch { case norm != lapack.MaxAbs && norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius: panic(badNorm) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case kl < 0: panic(klLT0) case ku < 0: panic(kuLT0) case ldab < ncol: panic(badLdA) } // Quick return if possible. if m == 0 || n == 0 { return 0 } switch { case len(ab) < min(m, n+kl)*ldab: panic(shortAB) } var value float64 switch norm { case lapack.MaxAbs: for i := 0; i < min(m, n+kl); i++ { l := max(0, kl-i) u := min(n+kl-i, ncol) for _, aij := range ab[i*ldab+l : i*ldab+u] { aij = math.Abs(aij) if aij > value || math.IsNaN(aij) { value = aij } } } case lapack.MaxRowSum: for i := 0; i < min(m, n+kl); i++ { l := max(0, kl-i) u := min(n+kl-i, ncol) sum := f64.L1Norm(ab[i*ldab+l : i*ldab+u]) if sum > value || math.IsNaN(sum) { value = sum } } case lapack.MaxColumnSum: for j := 0; j < min(m+ku, n); j++ { jb := min(kl+j, ncol-1) ib := max(0, j-ku) jlen := min(j+kl, m-1) - ib + 1 sum := f64.L1NormInc(ab[ib*ldab+jb:], jlen, max(1, ldab-1)) if sum > value || math.IsNaN(sum) { value = sum } } case lapack.Frobenius: scale := 0.0 sum := 1.0 for i := 0; i < min(m, n+kl); i++ { l := max(0, kl-i) u := min(n+kl-i, ncol) ilen := u - l scale, sum = impl.Dlassq(ilen, ab[i*ldab+l:], 1, scale, sum) } value = scale * math.Sqrt(sum) } return value } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlange.go000066400000000000000000000044211450372207100220000ustar00rootroot00000000000000// 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/lapack" ) // Dlange returns the value of the specified norm of a general m×n matrix A: // // lapack.MaxAbs: the maximum absolute value of any element. // lapack.MaxColumnSum: the maximum column sum of the absolute values of the elements (1-norm). // lapack.MaxRowSum: the maximum row sum of the absolute values of the elements (infinity-norm). // lapack.Frobenius: the square root of the sum of the squares of the elements (Frobenius norm). // // If norm == lapack.MaxColumnSum, work must be of length n, and this function will // panic otherwise. There are no restrictions on work for the other matrix norms. func (impl Implementation) Dlange(norm lapack.MatrixNorm, m, n int, a []float64, lda int, work []float64) float64 { // TODO(btracey): These should probably be refactored to use BLAS calls. switch { case norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius && norm != lapack.MaxAbs: panic(badNorm) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if m == 0 || n == 0 { return 0 } switch { case len(a) < (m-1)*lda+n: panic(badLdA) case norm == lapack.MaxColumnSum && len(work) < n: panic(shortWork) } switch norm { case lapack.MaxAbs: var value float64 for i := 0; i < m; i++ { for j := 0; j < n; j++ { value = math.Max(value, math.Abs(a[i*lda+j])) } } return value case lapack.MaxColumnSum: for i := 0; i < n; i++ { work[i] = 0 } for i := 0; i < m; i++ { for j := 0; j < n; j++ { work[j] += math.Abs(a[i*lda+j]) } } var value float64 for i := 0; i < n; i++ { value = math.Max(value, work[i]) } return value case lapack.MaxRowSum: var value float64 for i := 0; i < m; i++ { var sum float64 for j := 0; j < n; j++ { sum += math.Abs(a[i*lda+j]) } value = math.Max(value, sum) } return value default: // lapack.Frobenius scale := 0.0 sum := 1.0 for i := 0; i < m; i++ { scale, sum = impl.Dlassq(n, a[i*lda:], 1, scale, sum) } return scale * math.Sqrt(sum) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlangt.go000066400000000000000000000044401450372207100220200ustar00rootroot00000000000000// Copyright ©2020 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/lapack" ) // Dlangt returns the value of the given norm of an n×n tridiagonal matrix // represented by the three diagonals. // // d must have length at least n and dl and du must have length at least n-1. func (impl Implementation) Dlangt(norm lapack.MatrixNorm, n int, dl, d, du []float64) float64 { switch { case norm != lapack.MaxAbs && norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius: panic(badNorm) case n < 0: panic(nLT0) } if n == 0 { return 0 } switch { case len(dl) < n-1: panic(shortDL) case len(d) < n: panic(shortD) case len(du) < n-1: panic(shortDU) } dl = dl[:n-1] d = d[:n] du = du[:n-1] var anorm float64 switch norm { case lapack.MaxAbs: for _, diag := range [][]float64{dl, d, du} { for _, di := range diag { if math.IsNaN(di) { return di } di = math.Abs(di) if di > anorm { anorm = di } } } case lapack.MaxColumnSum: if n == 1 { return math.Abs(d[0]) } anorm = math.Abs(d[0]) + math.Abs(dl[0]) if math.IsNaN(anorm) { return anorm } tmp := math.Abs(du[n-2]) + math.Abs(d[n-1]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } for i := 1; i < n-1; i++ { tmp = math.Abs(du[i-1]) + math.Abs(d[i]) + math.Abs(dl[i]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } } case lapack.MaxRowSum: if n == 1 { return math.Abs(d[0]) } anorm = math.Abs(d[0]) + math.Abs(du[0]) if math.IsNaN(anorm) { return anorm } tmp := math.Abs(dl[n-2]) + math.Abs(d[n-1]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } for i := 1; i < n-1; i++ { tmp = math.Abs(dl[i-1]) + math.Abs(d[i]) + math.Abs(du[i]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } } case lapack.Frobenius: scale := 0.0 ssq := 1.0 scale, ssq = impl.Dlassq(n, d, 1, scale, ssq) if n > 1 { scale, ssq = impl.Dlassq(n-1, dl, 1, scale, ssq) scale, ssq = impl.Dlassq(n-1, du, 1, scale, ssq) } anorm = scale * math.Sqrt(ssq) } return anorm } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlansb.go000066400000000000000000000056601450372207100220170ustar00rootroot00000000000000// Copyright ©2019 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/lapack" ) // Dlansb returns the given norm of an n×n symmetric band matrix with kd // super-diagonals. // // When norm is lapack.MaxColumnSum or lapack.MaxRowSum, the length of work must // be at least n. func (impl Implementation) Dlansb(norm lapack.MatrixNorm, uplo blas.Uplo, n, kd int, ab []float64, ldab int, work []float64) float64 { switch { case norm != lapack.MaxAbs && norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius: panic(badNorm) case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case kd < 0: panic(kdLT0) case ldab < kd+1: panic(badLdA) } // Quick return if possible. if n == 0 { return 0 } switch { case len(ab) < (n-1)*ldab+kd+1: panic(shortAB) case len(work) < n && (norm == lapack.MaxColumnSum || norm == lapack.MaxRowSum): panic(shortWork) } var value float64 switch norm { case lapack.MaxAbs: if uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j < min(n-i, kd+1); j++ { aij := math.Abs(ab[i*ldab+j]) if aij > value || math.IsNaN(aij) { value = aij } } } } else { for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd+1; j++ { aij := math.Abs(ab[i*ldab+j]) if aij > value || math.IsNaN(aij) { value = aij } } } } case lapack.MaxColumnSum, lapack.MaxRowSum: work = work[:n] var sum float64 if uplo == blas.Upper { for i := range work { work[i] = 0 } for i := 0; i < n; i++ { sum := work[i] + math.Abs(ab[i*ldab]) for j := i + 1; j < min(i+kd+1, n); j++ { aij := math.Abs(ab[i*ldab+j-i]) sum += aij work[j] += aij } if sum > value || math.IsNaN(sum) { value = sum } } } else { for i := 0; i < n; i++ { sum = 0 for j := max(0, i-kd); j < i; j++ { aij := math.Abs(ab[i*ldab+kd+j-i]) sum += aij work[j] += aij } work[i] = sum + math.Abs(ab[i*ldab+kd]) } for _, sum := range work { if sum > value || math.IsNaN(sum) { value = sum } } } case lapack.Frobenius: scale := 0.0 sum := 1.0 if uplo == blas.Upper { if kd > 0 { // Sum off-diagonals. for i := 0; i < n-1; i++ { ilen := min(n-i-1, kd) scale, sum = impl.Dlassq(ilen, ab[i*ldab+1:], 1, scale, sum) } sum *= 2 } // Sum diagonal. scale, sum = impl.Dlassq(n, ab, ldab, scale, sum) } else { if kd > 0 { // Sum off-diagonals. for i := 1; i < n; i++ { ilen := min(i, kd) scale, sum = impl.Dlassq(ilen, ab[i*ldab+kd-ilen:], 1, scale, sum) } sum *= 2 } // Sum diagonal. scale, sum = impl.Dlassq(n, ab[kd:], ldab, scale, sum) } value = scale * math.Sqrt(sum) } return value } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlanst.go000066400000000000000000000032611450372207100220340ustar00rootroot00000000000000// Copyright ©2016 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/lapack" ) // Dlanst computes the specified norm of a symmetric tridiagonal matrix A. // The diagonal elements of A are stored in d and the off-diagonal elements // are stored in e. func (impl Implementation) Dlanst(norm lapack.MatrixNorm, n int, d, e []float64) float64 { switch { case norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius && norm != lapack.MaxAbs: panic(badNorm) case n < 0: panic(nLT0) } if n == 0 { return 0 } switch { case len(d) < n: panic(shortD) case len(e) < n-1: panic(shortE) } switch norm { default: panic(badNorm) case lapack.MaxAbs: anorm := math.Abs(d[n-1]) for i := 0; i < n-1; i++ { sum := math.Abs(d[i]) if anorm < sum || math.IsNaN(sum) { anorm = sum } sum = math.Abs(e[i]) if anorm < sum || math.IsNaN(sum) { anorm = sum } } return anorm case lapack.MaxColumnSum, lapack.MaxRowSum: if n == 1 { return math.Abs(d[0]) } anorm := math.Abs(d[0]) + math.Abs(e[0]) sum := math.Abs(e[n-2]) + math.Abs(d[n-1]) if anorm < sum || math.IsNaN(sum) { anorm = sum } for i := 1; i < n-1; i++ { sum := math.Abs(d[i]) + math.Abs(e[i]) + math.Abs(e[i-1]) if anorm < sum || math.IsNaN(sum) { anorm = sum } } return anorm case lapack.Frobenius: var scale float64 sum := 1.0 if n > 1 { scale, sum = impl.Dlassq(n-1, e, 1, scale, sum) sum = 2 * sum } scale, sum = impl.Dlassq(n, d, 1, scale, sum) return scale * math.Sqrt(sum) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlansy.go000066400000000000000000000052451450372207100220450ustar00rootroot00000000000000// 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/lapack" ) // Dlansy returns the value of the specified norm of an n×n symmetric matrix. If // norm == lapack.MaxColumnSum or norm == lapack.MaxRowSum, work must have length // at least n, otherwise work is unused. func (impl Implementation) Dlansy(norm lapack.MatrixNorm, uplo blas.Uplo, n int, a []float64, lda int, work []float64) float64 { switch { case norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius && norm != lapack.MaxAbs: panic(badNorm) case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return 0 } switch { case len(a) < (n-1)*lda+n: panic(shortA) case (norm == lapack.MaxColumnSum || norm == lapack.MaxRowSum) && len(work) < n: panic(shortWork) } switch norm { case lapack.MaxAbs: if uplo == blas.Upper { var max float64 for i := 0; i < n; i++ { for j := i; j < n; j++ { v := math.Abs(a[i*lda+j]) if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } } return max } var max float64 for i := 0; i < n; i++ { for j := 0; j <= i; j++ { v := math.Abs(a[i*lda+j]) if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } } return max case lapack.MaxRowSum, lapack.MaxColumnSum: // A symmetric matrix has the same 1-norm and ∞-norm. for i := 0; i < n; i++ { work[i] = 0 } if uplo == blas.Upper { for i := 0; i < n; i++ { work[i] += math.Abs(a[i*lda+i]) for j := i + 1; j < n; j++ { v := math.Abs(a[i*lda+j]) work[i] += v work[j] += v } } } else { for i := 0; i < n; i++ { for j := 0; j < i; j++ { v := math.Abs(a[i*lda+j]) work[i] += v work[j] += v } work[i] += math.Abs(a[i*lda+i]) } } var max float64 for i := 0; i < n; i++ { v := work[i] if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } return max default: // lapack.Frobenius: scale := 0.0 sum := 1.0 // Sum off-diagonals. if uplo == blas.Upper { for i := 0; i < n-1; i++ { scale, sum = impl.Dlassq(n-i-1, a[i*lda+i+1:], 1, scale, sum) } } else { for i := 1; i < n; i++ { scale, sum = impl.Dlassq(i, a[i*lda:], 1, scale, sum) } } sum *= 2 // Sum diagonal. scale, sum = impl.Dlassq(n, a, lda+1, scale, sum) return scale * math.Sqrt(sum) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlantb.go000066400000000000000000000102331450372207100220100ustar00rootroot00000000000000// Copyright ©2020 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/lapack" ) // Dlantb returns the value of the given norm of an n×n triangular band matrix A // with k+1 diagonals. // // When norm is lapack.MaxColumnSum, the length of work must be at least n. func (impl Implementation) Dlantb(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k int, a []float64, lda int, work []float64) float64 { switch { case norm != lapack.MaxAbs && norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius: panic(badNorm) case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case k < 0: panic(kdLT0) case lda < k+1: panic(badLdA) } // Quick return if possible. if n == 0 { return 0 } switch { case len(a) < (n-1)*lda+k+1: panic(shortAB) case len(work) < n && norm == lapack.MaxColumnSum: panic(shortWork) } var value float64 switch norm { case lapack.MaxAbs: if uplo == blas.Upper { var jfirst int if diag == blas.Unit { value = 1 jfirst = 1 } for i := 0; i < n; i++ { for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { if math.IsNaN(aij) { return aij } aij = math.Abs(aij) if aij > value { value = aij } } } } else { jlast := k + 1 if diag == blas.Unit { value = 1 jlast = k } for i := 0; i < n; i++ { for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] { if math.IsNaN(aij) { return math.NaN() } aij = math.Abs(aij) if aij > value { value = aij } } } } case lapack.MaxRowSum: var sum float64 if uplo == blas.Upper { var jfirst int if diag == blas.Unit { jfirst = 1 } for i := 0; i < n; i++ { sum = 0 if diag == blas.Unit { sum = 1 } for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { sum += math.Abs(aij) } if math.IsNaN(sum) { return math.NaN() } if sum > value { value = sum } } } else { jlast := k + 1 if diag == blas.Unit { jlast = k } for i := 0; i < n; i++ { sum = 0 if diag == blas.Unit { sum = 1 } for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] { sum += math.Abs(aij) } if math.IsNaN(sum) { return math.NaN() } if sum > value { value = sum } } } case lapack.MaxColumnSum: work = work[:n] if diag == blas.Unit { for i := range work { work[i] = 1 } } else { for i := range work { work[i] = 0 } } if uplo == blas.Upper { var jfirst int if diag == blas.Unit { jfirst = 1 } for i := 0; i < n; i++ { for j, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { work[i+jfirst+j] += math.Abs(aij) } } } else { jlast := k + 1 if diag == blas.Unit { jlast = k } for i := 0; i < n; i++ { off := max(0, k-i) for j, aij := range a[i*lda+off : i*lda+jlast] { work[i+j+off-k] += math.Abs(aij) } } } for _, wi := range work { if math.IsNaN(wi) { return math.NaN() } if wi > value { value = wi } } case lapack.Frobenius: var scale, sum float64 switch uplo { case blas.Upper: if diag == blas.Unit { scale = 1 sum = float64(n) if k > 0 { for i := 0; i < n-1; i++ { ilen := min(n-i-1, k) scale, sum = impl.Dlassq(ilen, a[i*lda+1:], 1, scale, sum) } } } else { scale = 0 sum = 1 for i := 0; i < n; i++ { ilen := min(n-i, k+1) scale, sum = impl.Dlassq(ilen, a[i*lda:], 1, scale, sum) } } case blas.Lower: if diag == blas.Unit { scale = 1 sum = float64(n) if k > 0 { for i := 1; i < n; i++ { ilen := min(i, k) scale, sum = impl.Dlassq(ilen, a[i*lda+k-ilen:], 1, scale, sum) } } } else { scale = 0 sum = 1 for i := 0; i < n; i++ { ilen := min(i, k) + 1 scale, sum = impl.Dlassq(ilen, a[i*lda+k+1-ilen:], 1, scale, sum) } } } value = scale * math.Sqrt(sum) } return value } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlantr.go000066400000000000000000000117501450372207100220350ustar00rootroot00000000000000// 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/lapack" ) // Dlantr computes the specified norm of an m×n trapezoidal matrix A. If // norm == lapack.MaxColumnSum work must have length at least n, otherwise work // is unused. func (impl Implementation) Dlantr(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 { switch { case norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius && norm != lapack.MaxAbs: panic(badNorm) case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case diag != blas.Unit && diag != blas.NonUnit: panic(badDiag) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. minmn := min(m, n) if minmn == 0 { return 0 } switch { case len(a) < (m-1)*lda+n: panic(shortA) case norm == lapack.MaxColumnSum && len(work) < n: panic(shortWork) } switch norm { case lapack.MaxAbs: if diag == blas.Unit { value := 1.0 if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i + 1; j < n; j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value } for i := 1; i < m; i++ { for j := 0; j < min(i, n); j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value } var value float64 if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i; j < n; j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value } for i := 0; i < m; i++ { for j := 0; j <= min(i, n-1); j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value case lapack.MaxColumnSum: if diag == blas.Unit { for i := 0; i < minmn; i++ { work[i] = 1 } for i := minmn; i < n; i++ { work[i] = 0 } if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i + 1; j < n; j++ { work[j] += math.Abs(a[i*lda+j]) } } } else { for i := 1; i < m; i++ { for j := 0; j < min(i, n); j++ { work[j] += math.Abs(a[i*lda+j]) } } } } else { for i := 0; i < n; i++ { work[i] = 0 } if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i; j < n; j++ { work[j] += math.Abs(a[i*lda+j]) } } } else { for i := 0; i < m; i++ { for j := 0; j <= min(i, n-1); j++ { work[j] += math.Abs(a[i*lda+j]) } } } } var max float64 for _, v := range work[:n] { if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } return max case lapack.MaxRowSum: var maxsum float64 if diag == blas.Unit { if uplo == blas.Upper { for i := 0; i < m; i++ { var sum float64 if i < minmn { sum = 1 } for j := i + 1; j < n; j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return math.NaN() } if sum > maxsum { maxsum = sum } } return maxsum } else { for i := 0; i < m; i++ { var sum float64 if i < minmn { sum = 1 } for j := 0; j < min(i, n); j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return math.NaN() } if sum > maxsum { maxsum = sum } } return maxsum } } else { if uplo == blas.Upper { for i := 0; i < m; i++ { var sum float64 for j := i; j < n; j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return sum } if sum > maxsum { maxsum = sum } } return maxsum } else { for i := 0; i < m; i++ { var sum float64 for j := 0; j <= min(i, n-1); j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return sum } if sum > maxsum { maxsum = sum } } return maxsum } } default: // lapack.Frobenius: var scale, sum float64 if diag == blas.Unit { scale = 1 sum = float64(min(m, n)) if uplo == blas.Upper { for i := 0; i < min(m, n); i++ { scale, sum = impl.Dlassq(n-i-1, a[i*lda+i+1:], 1, scale, sum) } } else { for i := 1; i < m; i++ { scale, sum = impl.Dlassq(min(i, n), a[i*lda:], 1, scale, sum) } } } else { scale = 0 sum = 1 if uplo == blas.Upper { for i := 0; i < min(m, n); i++ { scale, sum = impl.Dlassq(n-i, a[i*lda+i:], 1, scale, sum) } } else { for i := 0; i < m; i++ { scale, sum = impl.Dlassq(min(i+1, n), a[i*lda:], 1, scale, sum) } } } return scale * math.Sqrt(sum) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlanv2.go000066400000000000000000000070301450372207100217330ustar00rootroot00000000000000// Copyright ©2016 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" // Dlanv2 computes the Schur factorization of a real 2×2 matrix: // // [ a b ] = [ cs -sn ] * [ aa bb ] * [ cs sn ] // [ c d ] [ sn cs ] [ cc dd ] * [-sn cs ] // // If cc is zero, aa and dd are real eigenvalues of the matrix. Otherwise it // holds that aa = dd and bb*cc < 0, and aa ± sqrt(bb*cc) are complex conjugate // eigenvalues. The real and imaginary parts of the eigenvalues are returned in // (rt1r,rt1i) and (rt2r,rt2i). func (impl Implementation) Dlanv2(a, b, c, d float64) (aa, bb, cc, dd float64, rt1r, rt1i, rt2r, rt2i float64, cs, sn float64) { switch { case c == 0: // Matrix is already upper triangular. aa = a bb = b cc = 0 dd = d cs = 1 sn = 0 case b == 0: // Matrix is lower triangular, swap rows and columns. aa = d bb = -c cc = 0 dd = a cs = 0 sn = 1 case a == d && math.Signbit(b) != math.Signbit(c): // Matrix is already in the standard Schur form. aa = a bb = b cc = c dd = d cs = 1 sn = 0 default: temp := a - d p := temp / 2 bcmax := math.Max(math.Abs(b), math.Abs(c)) bcmis := math.Min(math.Abs(b), math.Abs(c)) if b*c < 0 { bcmis *= -1 } scale := math.Max(math.Abs(p), bcmax) z := p/scale*p + bcmax/scale*bcmis eps := dlamchP if z >= 4*eps { // Real eigenvalues. Compute aa and dd. if p > 0 { z = p + math.Sqrt(scale)*math.Sqrt(z) } else { z = p - math.Sqrt(scale)*math.Sqrt(z) } aa = d + z dd = d - bcmax/z*bcmis // Compute bb and the rotation matrix. tau := impl.Dlapy2(c, z) cs = z / tau sn = c / tau bb = b - c cc = 0 } else { // Complex eigenvalues, or real (almost) equal eigenvalues. // Make diagonal elements equal. safmn2 := math.Pow(dlamchB, math.Log(dlamchS/dlamchE)/math.Log(dlamchB)/2) safmx2 := 1 / safmn2 sigma := b + c loop: for iter := 0; iter < 20; iter++ { scale = math.Max(math.Abs(temp), math.Abs(sigma)) switch { case scale >= safmx2: sigma *= safmn2 temp *= safmn2 case scale <= safmn2: sigma *= safmx2 temp *= safmx2 default: break loop } } p = temp / 2 tau := impl.Dlapy2(sigma, temp) cs = math.Sqrt((1 + math.Abs(sigma)/tau) / 2) sn = -p / (tau * cs) if sigma < 0 { sn *= -1 } // Compute [ aa bb ] = [ a b ] [ cs -sn ] // [ cc dd ] [ c d ] [ sn cs ] aa = a*cs + b*sn bb = -a*sn + b*cs cc = c*cs + d*sn dd = -c*sn + d*cs // Compute [ a b ] = [ cs sn ] [ aa bb ] // [ c d ] [-sn cs ] [ cc dd ] a = aa*cs + cc*sn b = bb*cs + dd*sn c = -aa*sn + cc*cs d = -bb*sn + dd*cs temp = (a + d) / 2 aa = temp bb = b cc = c dd = temp if cc != 0 { if bb != 0 { if math.Signbit(bb) == math.Signbit(cc) { // Real eigenvalues, reduce to // upper triangular form. sab := math.Sqrt(math.Abs(bb)) sac := math.Sqrt(math.Abs(cc)) p = sab * sac if cc < 0 { p *= -1 } tau = 1 / math.Sqrt(math.Abs(bb+cc)) aa = temp + p bb = bb - cc cc = 0 dd = temp - p cs1 := sab * tau sn1 := sac * tau cs, sn = cs*cs1-sn*sn1, cs*sn1+sn*cs1 } } else { bb = -cc cc = 0 cs, sn = -sn, cs } } } } // Store eigenvalues in (rt1r,rt1i) and (rt2r,rt2i). rt1r = aa rt2r = dd if cc != 0 { rt1i = math.Sqrt(math.Abs(bb)) * math.Sqrt(math.Abs(cc)) rt2i = -rt1i } return } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlapll.go000066400000000000000000000025621450372207100220220ustar00rootroot00000000000000// 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 "gonum.org/v1/gonum/blas/blas64" // Dlapll returns the smallest singular value of the n×2 matrix A = [ x y ]. // The function first computes the QR factorization of A = Q*R, and then computes // the SVD of the 2-by-2 upper triangular matrix r. // // The contents of x and y are overwritten during the call. // // Dlapll is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlapll(n int, x []float64, incX int, y []float64, incY int) float64 { switch { case n < 0: panic(nLT0) case incX <= 0: panic(badIncX) case incY <= 0: panic(badIncY) } // Quick return if possible. if n == 0 { return 0 } switch { case len(x) < 1+(n-1)*incX: panic(shortX) case len(y) < 1+(n-1)*incY: panic(shortY) } // Quick return if possible. if n == 1 { return 0 } // Compute the QR factorization of the N-by-2 matrix [ X Y ]. a00, tau := impl.Dlarfg(n, x[0], x[incX:], incX) x[0] = 1 bi := blas64.Implementation() c := -tau * bi.Ddot(n, x, incX, y, incY) bi.Daxpy(n, c, x, incX, y, incY) a11, _ := impl.Dlarfg(n-1, y[incY], y[2*incY:], incY) // Compute the SVD of 2-by-2 upper triangular matrix. ssmin, _ := impl.Dlas2(a00, y[0], a11) return ssmin } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlapmr.go000066400000000000000000000031521450372207100220250ustar00rootroot00000000000000// Copyright ©2022 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/blas64" // Dlapmr rearranges the rows of the m×n matrix X as specified by the permutation // k[0],k[1],...,k[m-1] of the integers 0,...,m-1. // // If forward is true, a forward permutation is applied: // // X[k[i],0:n] is moved to X[i,0:n] for i=0,1,...,m-1. // // If forward is false, a backward permutation is applied: // // X[i,0:n] is moved to X[k[i],0:n] for i=0,1,...,m-1. // // k must have length m, otherwise Dlapmr will panic. func (impl Implementation) Dlapmr(forward bool, m, n int, x []float64, ldx int, k []int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case ldx < max(1, n): panic(badLdX) } // Quick return if possible. if m == 0 || n == 0 { return } switch { case len(x) < (m-1)*ldx+n: panic(shortX) case len(k) != m: panic(badLenK) } // Quick return if possible. if m == 1 { return } bi := blas64.Implementation() for i, ki := range k { k[i] = -(ki + 1) } if forward { for i, ki := range k { if ki >= 0 { continue } j := i k[j] = -k[j] - 1 in := k[j] for { if k[in] >= 0 { break } bi.Dswap(n, x[j*ldx:], 1, x[in*ldx:], 1) k[in] = -k[in] - 1 j = in in = k[in] } } } else { for i, ki := range k { if ki >= 0 { continue } k[i] = -ki - 1 j := k[i] for { if j == i { break } bi.Dswap(n, x[i*ldx:], 1, x[j*ldx:], 1) k[j] = -k[j] - 1 j = k[j] } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlapmt.go000066400000000000000000000031171450372207100220300ustar00rootroot00000000000000// 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 "gonum.org/v1/gonum/blas/blas64" // Dlapmt rearranges the columns of the m×n matrix X as specified by the // permutation k_0, k_1, ..., k_n-1 of the integers 0, ..., n-1. // // If forward is true a forward permutation is performed: // // X[0:m, k[j]] is moved to X[0:m, j] for j = 0, 1, ..., n-1. // // otherwise a backward permutation is performed: // // X[0:m, j] is moved to X[0:m, k[j]] for j = 0, 1, ..., n-1. // // k must have length n, otherwise Dlapmt will panic. k is zero-indexed. func (impl Implementation) Dlapmt(forward bool, m, n int, x []float64, ldx int, k []int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case ldx < max(1, n): panic(badLdX) } // Quick return if possible. if m == 0 || n == 0 { return } switch { case len(x) < (m-1)*ldx+n: panic(shortX) case len(k) != n: panic(badLenK) } // Quick return if possible. if n == 1 { return } for i, v := range k { v++ k[i] = -v } bi := blas64.Implementation() if forward { for j, v := range k { if v >= 0 { continue } k[j] = -v i := -v - 1 for k[i] < 0 { bi.Dswap(m, x[j:], ldx, x[i:], ldx) k[i] = -k[i] j = i i = k[i] - 1 } } } else { for i, v := range k { if v >= 0 { continue } k[i] = -v j := -v - 1 for j != i { bi.Dswap(m, x[j:], ldx, x[i:], ldx) k[j] = -k[j] j = k[j] - 1 } } } for i := range k { k[i]-- } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlapy2.go000066400000000000000000000006141450372207100217410ustar00rootroot00000000000000// 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" // Dlapy2 is the LAPACK version of math.Hypot. // // Dlapy2 is an internal routine. It is exported for testing purposes. func (Implementation) Dlapy2(x, y float64) float64 { return math.Hypot(x, y) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaqp2.go000066400000000000000000000066151450372207100217400ustar00rootroot00000000000000// 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/blas/blas64" ) // Dlaqp2 computes a QR factorization with column pivoting of the block A[offset:m, 0:n] // of the m×n matrix A. The block A[0:offset, 0:n] is accordingly pivoted, but not factorized. // // On exit, the upper triangle of block A[offset:m, 0:n] is the triangular factor obtained. // The elements in block A[offset:m, 0:n] below the diagonal, together with tau, represent // the orthogonal matrix Q as a product of elementary reflectors. // // offset is number of rows of the matrix A that must be pivoted but not factorized. // offset must not be negative otherwise Dlaqp2 will panic. // // On exit, jpvt holds the permutation that was applied; the jth column of A*P was the // jpvt[j] column of A. jpvt must have length n, otherwise Dlaqp2 will panic. // // On exit tau holds the scalar factors of the elementary reflectors. It must have length // at least min(m-offset, n) otherwise Dlaqp2 will panic. // // vn1 and vn2 hold the partial and complete column norms respectively. They must have length n, // otherwise Dlaqp2 will panic. // // work must have length n, otherwise Dlaqp2 will panic. // // Dlaqp2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaqp2(m, n, offset int, a []float64, lda int, jpvt []int, tau, vn1, vn2, work []float64) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case offset < 0: panic(offsetLT0) case offset > m: panic(offsetGTM) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if m == 0 || n == 0 { return } mn := min(m-offset, n) switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(jpvt) != n: panic(badLenJpvt) case len(tau) < mn: panic(shortTau) case len(vn1) < n: panic(shortVn1) case len(vn2) < n: panic(shortVn2) case len(work) < n: panic(shortWork) } tol3z := math.Sqrt(dlamchE) bi := blas64.Implementation() // Compute factorization. for i := 0; i < mn; i++ { offpi := offset + i // Determine ith pivot column and swap if necessary. p := i + bi.Idamax(n-i, vn1[i:], 1) if p != i { bi.Dswap(m, a[p:], lda, a[i:], lda) jpvt[p], jpvt[i] = jpvt[i], jpvt[p] vn1[p] = vn1[i] vn2[p] = vn2[i] } // Generate elementary reflector H_i. if offpi < m-1 { a[offpi*lda+i], tau[i] = impl.Dlarfg(m-offpi, a[offpi*lda+i], a[(offpi+1)*lda+i:], lda) } else { tau[i] = 0 } if i < n-1 { // Apply H_iᵀ to A[offset+i:m, i:n] from the left. aii := a[offpi*lda+i] a[offpi*lda+i] = 1 impl.Dlarf(blas.Left, m-offpi, n-i-1, a[offpi*lda+i:], lda, tau[i], a[offpi*lda+i+1:], lda, work) a[offpi*lda+i] = aii } // Update partial column norms. for j := i + 1; j < n; j++ { if vn1[j] == 0 { continue } // The following marked lines follow from the // analysis in Lapack Working Note 176. r := math.Abs(a[offpi*lda+j]) / vn1[j] // * temp := math.Max(0, 1-r*r) // * r = vn1[j] / vn2[j] // * temp2 := temp * r * r // * if temp2 < tol3z { var v float64 if offpi < m-1 { v = bi.Dnrm2(m-offpi-1, a[(offpi+1)*lda+j:], lda) } vn1[j] = v vn2[j] = v } else { vn1[j] *= math.Sqrt(temp) // * } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaqps.go000066400000000000000000000134221450372207100220330ustar00rootroot00000000000000// 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/blas/blas64" ) // Dlaqps computes a step of QR factorization with column pivoting // of an m×n matrix A by using Blas-3. It tries to factorize nb // columns from A starting from the row offset, and updates all // of the matrix with Dgemm. // // In some cases, due to catastrophic cancellations, it cannot // factorize nb columns. Hence, the actual number of factorized // columns is returned in kb. // // Dlaqps computes a QR factorization with column pivoting of the // block A[offset:m, 0:nb] of the m×n matrix A. The block // A[0:offset, 0:n] is accordingly pivoted, but not factorized. // // On exit, the upper triangle of block A[offset:m, 0:kb] is the // triangular factor obtained. The elements in block A[offset:m, 0:n] // below the diagonal, together with tau, represent the orthogonal // matrix Q as a product of elementary reflectors. // // offset is number of rows of the matrix A that must be pivoted but // not factorized. offset must not be negative otherwise Dlaqps will panic. // // On exit, jpvt holds the permutation that was applied; the jth column // of A*P was the jpvt[j] column of A. jpvt must have length n, // otherwise Dlapqs will panic. // // On exit tau holds the scalar factors of the elementary reflectors. // It must have length nb, otherwise Dlapqs will panic. // // vn1 and vn2 hold the partial and complete column norms respectively. // They must have length n, otherwise Dlapqs will panic. // // auxv must have length nb, otherwise Dlaqps will panic. // // f and ldf represent an n×nb matrix F that is overwritten during the // call. // // Dlaqps is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaqps(m, n, offset, nb int, a []float64, lda int, jpvt []int, tau, vn1, vn2, auxv, f []float64, ldf int) (kb int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case offset < 0: panic(offsetLT0) case offset > m: panic(offsetGTM) case nb < 0: panic(nbLT0) case nb > n: panic(nbGTN) case lda < max(1, n): panic(badLdA) case ldf < max(1, nb): panic(badLdF) } if m == 0 || n == 0 { return 0 } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(jpvt) != n: panic(badLenJpvt) case len(vn1) < n: panic(shortVn1) case len(vn2) < n: panic(shortVn2) } if nb == 0 { return 0 } switch { case len(tau) < nb: panic(shortTau) case len(auxv) < nb: panic(shortAuxv) case len(f) < (n-1)*ldf+nb: panic(shortF) } if offset == m { return 0 } lastrk := min(m, n+offset) lsticc := -1 tol3z := math.Sqrt(dlamchE) bi := blas64.Implementation() var k, rk int for ; k < nb && lsticc == -1; k++ { rk = offset + k // Determine kth pivot column and swap if necessary. p := k + bi.Idamax(n-k, vn1[k:], 1) if p != k { bi.Dswap(m, a[p:], lda, a[k:], lda) bi.Dswap(k, f[p*ldf:], 1, f[k*ldf:], 1) jpvt[p], jpvt[k] = jpvt[k], jpvt[p] vn1[p] = vn1[k] vn2[p] = vn2[k] } // Apply previous Householder reflectors to column K: // // A[rk:m, k] = A[rk:m, k] - A[rk:m, 0:k-1]*F[k, 0:k-1]ᵀ. if k > 0 { bi.Dgemv(blas.NoTrans, m-rk, k, -1, a[rk*lda:], lda, f[k*ldf:], 1, 1, a[rk*lda+k:], lda) } // Generate elementary reflector H_k. if rk < m-1 { a[rk*lda+k], tau[k] = impl.Dlarfg(m-rk, a[rk*lda+k], a[(rk+1)*lda+k:], lda) } else { tau[k] = 0 } akk := a[rk*lda+k] a[rk*lda+k] = 1 // Compute kth column of F: // // Compute F[k+1:n, k] = tau[k]*A[rk:m, k+1:n]ᵀ*A[rk:m, k]. if k < n-1 { bi.Dgemv(blas.Trans, m-rk, n-k-1, tau[k], a[rk*lda+k+1:], lda, a[rk*lda+k:], lda, 0, f[(k+1)*ldf+k:], ldf) } // Padding F[0:k, k] with zeros. for j := 0; j < k; j++ { f[j*ldf+k] = 0 } // Incremental updating of F: // // F[0:n, k] := F[0:n, k] - tau[k]*F[0:n, 0:k-1]*A[rk:m, 0:k-1]ᵀ*A[rk:m,k]. if k > 0 { bi.Dgemv(blas.Trans, m-rk, k, -tau[k], a[rk*lda:], lda, a[rk*lda+k:], lda, 0, auxv, 1) bi.Dgemv(blas.NoTrans, n, k, 1, f, ldf, auxv, 1, 1, f[k:], ldf) } // Update the current row of A: // // A[rk, k+1:n] = A[rk, k+1:n] - A[rk, 0:k]*F[k+1:n, 0:k]ᵀ. if k < n-1 { bi.Dgemv(blas.NoTrans, n-k-1, k+1, -1, f[(k+1)*ldf:], ldf, a[rk*lda:], 1, 1, a[rk*lda+k+1:], 1) } // Update partial column norms. if rk < lastrk-1 { for j := k + 1; j < n; j++ { if vn1[j] == 0 { continue } // The following marked lines follow from the // analysis in Lapack Working Note 176. r := math.Abs(a[rk*lda+j]) / vn1[j] // * temp := math.Max(0, 1-r*r) // * r = vn1[j] / vn2[j] // * temp2 := temp * r * r // * if temp2 < tol3z { // vn2 is used here as a collection of // indices into vn2 and also a collection // of column norms. vn2[j] = float64(lsticc) lsticc = j } else { vn1[j] *= math.Sqrt(temp) // * } } } a[rk*lda+k] = akk } kb = k rk = offset + kb // Apply the block reflector to the rest of the matrix: // // A[offset+kb+1:m, kb+1:n] := A[offset+kb+1:m, kb+1:n] - A[offset+kb+1:m, 1:kb]*F[kb+1:n, 1:kb]ᵀ. if kb < min(n, m-offset) { bi.Dgemm(blas.NoTrans, blas.Trans, m-rk, n-kb, kb, -1, a[rk*lda:], lda, f[kb*ldf:], ldf, 1, a[rk*lda+kb:], lda) } // Recomputation of difficult columns. for lsticc >= 0 { itemp := int(vn2[lsticc]) // NOTE: The computation of vn1[lsticc] relies on the fact that // Dnrm2 does not fail on vectors with norm below the value of // sqrt(dlamchS) v := bi.Dnrm2(m-rk, a[rk*lda+lsticc:], lda) vn1[lsticc] = v vn2[lsticc] = v lsticc = itemp } return kb } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaqr04.go000066400000000000000000000374131450372207100220240ustar00rootroot00000000000000// Copyright ©2016 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" ) // Dlaqr04 computes the eigenvalues of a block of an n×n upper Hessenberg matrix // H, and optionally the matrices T and Z from the Schur decomposition // // H = Z T Zᵀ // // where T is an upper quasi-triangular matrix (the Schur form), and Z is the // orthogonal matrix of Schur vectors. // // wantt indicates whether the full Schur form T is required. If wantt is false, // then only enough of H will be updated to preserve the eigenvalues. // // wantz indicates whether the n×n matrix of Schur vectors Z is required. If it // is true, the orthogonal similarity transformation will be accumulated into // Z[iloz:ihiz+1,ilo:ihi+1], otherwise Z will not be referenced. // // ilo and ihi determine the block of H on which Dlaqr04 operates. It must hold that // // 0 <= ilo <= ihi < n if n > 0, // ilo == 0 and ihi == -1 if n == 0, // // and the block must be isolated, that is, // // ilo == 0 or H[ilo,ilo-1] == 0, // ihi == n-1 or H[ihi+1,ihi] == 0, // // otherwise Dlaqr04 will panic. // // wr and wi must have length ihi+1. // // iloz and ihiz specify the rows of Z to which transformations will be applied // if wantz is true. It must hold that // // 0 <= iloz <= ilo, and ihi <= ihiz < n, // // otherwise Dlaqr04 will panic. // // work must have length at least lwork and lwork must be // // lwork >= 1 if n <= 11, // lwork >= n if n > 11, // // otherwise Dlaqr04 will panic. lwork as large as 6*n may be required for // optimal performance. On return, work[0] will contain the optimal value of // lwork. // // If lwork is -1, instead of performing Dlaqr04, the function only estimates the // optimal workspace size and stores it into work[0]. Neither h nor z are // accessed. // // recur is the non-negative recursion depth. For recur > 0, Dlaqr04 behaves // as DLAQR0, for recur == 0 it behaves as DLAQR4. // // unconverged indicates whether Dlaqr04 computed all the eigenvalues of H[ilo:ihi+1,ilo:ihi+1]. // // If unconverged is zero and wantt is true, H will contain on return the upper // quasi-triangular matrix T from the Schur decomposition. 2×2 diagonal blocks // (corresponding to complex conjugate pairs of eigenvalues) will be returned in // standard form, with H[i,i] == H[i+1,i+1] and H[i+1,i]*H[i,i+1] < 0. // // If unconverged is zero and if wantt is false, the contents of h on return is // unspecified. // // If unconverged is zero, all the eigenvalues have been computed and their real // and imaginary parts will be stored on return in wr[ilo:ihi+1] and // wi[ilo:ihi+1], respectively. If two eigenvalues are computed as a complex // conjugate pair, they are stored in consecutive elements of wr and wi, say the // i-th and (i+1)th, with wi[i] > 0 and wi[i+1] < 0. If wantt is true, then the // eigenvalues are stored in the same order as on the diagonal of the Schur form // returned in H, with wr[i] = H[i,i] and, if H[i:i+2,i:i+2] is a 2×2 diagonal // block, wi[i] = sqrt(-H[i+1,i]*H[i,i+1]) and wi[i+1] = -wi[i]. // // If unconverged is positive, some eigenvalues have not converged, and // wr[unconverged:ihi+1] and wi[unconverged:ihi+1] will contain those // eigenvalues which have been successfully computed. Failures are rare. // // If unconverged is positive and wantt is true, then on return // // (initial H)*U = U*(final H), (*) // // where U is an orthogonal matrix. The final H is upper Hessenberg and // H[unconverged:ihi+1,unconverged:ihi+1] is upper quasi-triangular. // // If unconverged is positive and wantt is false, on return the remaining // unconverged eigenvalues are the eigenvalues of the upper Hessenberg matrix // H[ilo:unconverged,ilo:unconverged]. // // If unconverged is positive and wantz is true, then on return // // (final Z) = (initial Z)*U, // // where U is the orthogonal matrix in (*) regardless of the value of wantt. // // References: // // [1] K. Braman, R. Byers, R. Mathias. The Multishift QR Algorithm. Part I: // Maintaining Well-Focused Shifts and Level 3 Performance. SIAM J. Matrix // Anal. Appl. 23(4) (2002), pp. 929—947 // URL: http://dx.doi.org/10.1137/S0895479801384573 // [2] K. Braman, R. Byers, R. Mathias. The Multishift QR Algorithm. Part II: // Aggressive Early Deflation. SIAM J. Matrix Anal. Appl. 23(4) (2002), pp. 948—973 // URL: http://dx.doi.org/10.1137/S0895479801384585 // // Dlaqr04 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaqr04(wantt, wantz bool, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, iloz, ihiz int, z []float64, ldz int, work []float64, lwork int, recur int) (unconverged int) { const ( // Matrices of order ntiny or smaller must be processed by // Dlahqr because of insufficient subdiagonal scratch space. // This is a hard limit. ntiny = 15 // Exceptional deflation windows: try to cure rare slow // convergence by varying the size of the deflation window after // kexnw iterations. kexnw = 5 // Exceptional shifts: try to cure rare slow convergence with // ad-hoc exceptional shifts every kexsh iterations. kexsh = 6 // See https://github.com/gonum/lapack/pull/151#discussion_r68162802 // and the surrounding discussion for an explanation where these // constants come from. // TODO(vladimir-ch): Similar constants for exceptional shifts // are used also in dlahqr.go. The first constant is different // there, it is equal to 3. Why? And does it matter? wilk1 = 0.75 wilk2 = -0.4375 ) switch { case n < 0: panic(nLT0) case ilo < 0 || max(0, n-1) < ilo: panic(badIlo) case ihi < min(ilo, n-1) || n <= ihi: panic(badIhi) case ldh < max(1, n): panic(badLdH) case wantz && (iloz < 0 || ilo < iloz): panic(badIloz) case wantz && (ihiz < ihi || n <= ihiz): panic(badIhiz) case ldz < 1, wantz && ldz < n: panic(badLdZ) case lwork < 1 && lwork != -1: panic(badLWork) // TODO(vladimir-ch): Enable if and when we figure out what the minimum // necessary lwork value is. Dlaqr04 says that the minimum is n which // clashes with Dlaqr23's opinion about optimal work when nw <= 2 // (independent of n). // case lwork < n && n > ntiny && lwork != -1: // panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) case recur < 0: panic(recurLT0) } // Quick return. if n == 0 { work[0] = 1 return 0 } if lwork != -1 { switch { case len(h) < (n-1)*ldh+n: panic(shortH) case len(wr) != ihi+1: panic(badLenWr) case len(wi) != ihi+1: panic(badLenWi) case wantz && len(z) < (n-1)*ldz+n: panic(shortZ) case ilo > 0 && h[ilo*ldh+ilo-1] != 0: panic(notIsolated) case ihi+1 < n && h[(ihi+1)*ldh+ihi] != 0: panic(notIsolated) } } if n <= ntiny { // Tiny matrices must use Dlahqr. if lwork == -1 { work[0] = 1 return 0 } return impl.Dlahqr(wantt, wantz, n, ilo, ihi, h, ldh, wr, wi, iloz, ihiz, z, ldz) } // Use small bulge multi-shift QR with aggressive early deflation on // larger-than-tiny matrices. var jbcmpz string if wantt { jbcmpz = "S" } else { jbcmpz = "E" } if wantz { jbcmpz += "V" } else { jbcmpz += "N" } var fname string if recur > 0 { fname = "DLAQR0" } else { fname = "DLAQR4" } // nwr is the recommended deflation window size. n is greater than ntiny, // so there is enough subdiagonal workspace for nwr >= 2 as required. // (In fact, there is enough subdiagonal space for nwr >= 4.) // TODO(vladimir-ch): If there is enough space for nwr >= 4, should we // use it? nwr := impl.Ilaenv(13, fname, jbcmpz, n, ilo, ihi, lwork) nwr = max(2, nwr) nwr = min(ihi-ilo+1, min((n-1)/3, nwr)) // nsr is the recommended number of simultaneous shifts. n is greater than // ntiny, so there is enough subdiagonal workspace for nsr to be even and // greater than or equal to two as required. nsr := impl.Ilaenv(15, fname, jbcmpz, n, ilo, ihi, lwork) nsr = min(nsr, min((n-3)/6, ihi-ilo)) nsr = max(2, nsr&^1) // Workspace query call to Dlaqr23. impl.Dlaqr23(wantt, wantz, n, ilo, ihi, nwr+1, h, ldh, iloz, ihiz, z, ldz, wr, wi, h, ldh, n, h, ldh, n, h, ldh, work, -1, recur) // Optimal workspace is max(Dlaqr5, Dlaqr23). lwkopt := max(3*nsr/2, int(work[0])) // Quick return in case of workspace query. if lwork == -1 { work[0] = float64(lwkopt) return 0 } // Dlahqr/Dlaqr04 crossover point. nmin := impl.Ilaenv(12, fname, jbcmpz, n, ilo, ihi, lwork) nmin = max(ntiny, nmin) // Nibble determines when to skip a multi-shift QR sweep (Dlaqr5). nibble := impl.Ilaenv(14, fname, jbcmpz, n, ilo, ihi, lwork) nibble = max(0, nibble) // Computation mode of far-from-diagonal orthogonal updates in Dlaqr5. kacc22 := impl.Ilaenv(16, fname, jbcmpz, n, ilo, ihi, lwork) kacc22 = max(0, min(kacc22, 2)) // nwmax is the largest possible deflation window for which there is // sufficient workspace. nwmax := min((n-1)/3, lwork/2) nw := nwmax // Start with maximum deflation window size. // nsmax is the largest number of simultaneous shifts for which there is // sufficient workspace. nsmax := min((n-3)/6, 2*lwork/3) &^ 1 ndfl := 1 // Number of iterations since last deflation. ndec := 0 // Deflation window size decrement. // Main loop. var ( itmax = max(30, 2*kexsh) * max(10, (ihi-ilo+1)) it = 0 ) for kbot := ihi; kbot >= ilo; { if it == itmax { unconverged = kbot + 1 break } it++ // Locate active block. ktop := ilo for k := kbot; k >= ilo+1; k-- { if h[k*ldh+k-1] == 0 { ktop = k break } } // Select deflation window size nw. // // Typical Case: // If possible and advisable, nibble the entire active block. // If not, use size min(nwr,nwmax) or min(nwr+1,nwmax) // depending upon which has the smaller corresponding // subdiagonal entry (a heuristic). // // Exceptional Case: // If there have been no deflations in kexnw or more // iterations, then vary the deflation window size. At first, // because larger windows are, in general, more powerful than // smaller ones, rapidly increase the window to the maximum // possible. Then, gradually reduce the window size. nh := kbot - ktop + 1 nwupbd := min(nh, nwmax) if ndfl < kexnw { nw = min(nwupbd, nwr) } else { nw = min(nwupbd, 2*nw) } if nw < nwmax { if nw >= nh-1 { nw = nh } else { kwtop := kbot - nw + 1 if math.Abs(h[kwtop*ldh+kwtop-1]) > math.Abs(h[(kwtop-1)*ldh+kwtop-2]) { nw++ } } } if ndfl < kexnw { ndec = -1 } else if ndec >= 0 || nw >= nwupbd { ndec++ if nw-ndec < 2 { ndec = 0 } nw -= ndec } // Split workspace under the subdiagonal of H into: // - an nw×nw work array V in the lower left-hand corner, // - an nw×nhv horizontal work array along the bottom edge (nhv // must be at least nw but more is better), // - an nve×nw vertical work array along the left-hand-edge // (nhv can be any positive integer but more is better). kv := n - nw kt := nw kwv := nw + 1 nhv := n - kwv - kt // Aggressive early deflation. ls, ld := impl.Dlaqr23(wantt, wantz, n, ktop, kbot, nw, h, ldh, iloz, ihiz, z, ldz, wr[:kbot+1], wi[:kbot+1], h[kv*ldh:], ldh, nhv, h[kv*ldh+kt:], ldh, nhv, h[kwv*ldh:], ldh, work, lwork, recur) // Adjust kbot accounting for new deflations. kbot -= ld // ks points to the shifts. ks := kbot - ls + 1 // Skip an expensive QR sweep if there is a (partly heuristic) // reason to expect that many eigenvalues will deflate without // it. Here, the QR sweep is skipped if many eigenvalues have // just been deflated or if the remaining active block is small. if ld > 0 && (100*ld > nw*nibble || kbot-ktop+1 <= min(nmin, nwmax)) { // ld is positive, note progress. ndfl = 1 continue } // ns is the nominal number of simultaneous shifts. This may be // lowered (slightly) if Dlaqr23 did not provide that many // shifts. ns := min(min(nsmax, nsr), max(2, kbot-ktop)) &^ 1 // If there have been no deflations in a multiple of kexsh // iterations, then try exceptional shifts. Otherwise use shifts // provided by Dlaqr23 above or from the eigenvalues of a // trailing principal submatrix. if ndfl%kexsh == 0 { ks = kbot - ns + 1 for i := kbot; i > max(ks, ktop+1); i -= 2 { ss := math.Abs(h[i*ldh+i-1]) + math.Abs(h[(i-1)*ldh+i-2]) aa := wilk1*ss + h[i*ldh+i] _, _, _, _, wr[i-1], wi[i-1], wr[i], wi[i], _, _ = impl.Dlanv2(aa, ss, wilk2*ss, aa) } if ks == ktop { wr[ks+1] = h[(ks+1)*ldh+ks+1] wi[ks+1] = 0 wr[ks] = wr[ks+1] wi[ks] = wi[ks+1] } } else { // If we got ns/2 or fewer shifts, use Dlahqr or recur // into Dlaqr04 on a trailing principal submatrix to get // more. Since ns <= nsmax <=(n+6)/9, there is enough // space below the subdiagonal to fit an ns×ns scratch // array. if kbot-ks+1 <= ns/2 { ks = kbot - ns + 1 kt = n - ns impl.Dlacpy(blas.All, ns, ns, h[ks*ldh+ks:], ldh, h[kt*ldh:], ldh) if ns > nmin && recur > 0 { ks += impl.Dlaqr04(false, false, ns, 1, ns-1, h[kt*ldh:], ldh, wr[ks:ks+ns], wi[ks:ks+ns], 0, 0, nil, 0, work, lwork, recur-1) } else { ks += impl.Dlahqr(false, false, ns, 0, ns-1, h[kt*ldh:], ldh, wr[ks:ks+ns], wi[ks:ks+ns], 0, 0, nil, 1) } // In case of a rare QR failure use eigenvalues // of the trailing 2×2 principal submatrix. if ks >= kbot { aa := h[(kbot-1)*ldh+kbot-1] bb := h[(kbot-1)*ldh+kbot] cc := h[kbot*ldh+kbot-1] dd := h[kbot*ldh+kbot] _, _, _, _, wr[kbot-1], wi[kbot-1], wr[kbot], wi[kbot], _, _ = impl.Dlanv2(aa, bb, cc, dd) ks = kbot - 1 } } if kbot-ks+1 > ns { // Sorting the shifts helps a little. Bubble // sort keeps complex conjugate pairs together. sorted := false for k := kbot; k > ks; k-- { if sorted { break } sorted = true for i := ks; i < k; i++ { if math.Abs(wr[i])+math.Abs(wi[i]) >= math.Abs(wr[i+1])+math.Abs(wi[i+1]) { continue } sorted = false wr[i], wr[i+1] = wr[i+1], wr[i] wi[i], wi[i+1] = wi[i+1], wi[i] } } } // Shuffle shifts into pairs of real shifts and pairs of // complex conjugate shifts using the fact that complex // conjugate shifts are already adjacent to one another. // TODO(vladimir-ch): The shuffling here could probably // be removed but I'm not sure right now and it's safer // to leave it. for i := kbot; i > ks+1; i -= 2 { if wi[i] == -wi[i-1] { continue } wr[i], wr[i-1], wr[i-2] = wr[i-1], wr[i-2], wr[i] wi[i], wi[i-1], wi[i-2] = wi[i-1], wi[i-2], wi[i] } } // If there are only two shifts and both are real, then use only one. if kbot-ks+1 == 2 && wi[kbot] == 0 { if math.Abs(wr[kbot]-h[kbot*ldh+kbot]) < math.Abs(wr[kbot-1]-h[kbot*ldh+kbot]) { wr[kbot-1] = wr[kbot] } else { wr[kbot] = wr[kbot-1] } } // Use up to ns of the smallest magnitude shifts. If there // aren't ns shifts available, then use them all, possibly // dropping one to make the number of shifts even. ns = min(ns, kbot-ks+1) &^ 1 ks = kbot - ns + 1 // Split workspace under the subdiagonal into: // - a kdu×kdu work array U in the lower left-hand-corner, // - a kdu×nhv horizontal work array WH along the bottom edge // (nhv must be at least kdu but more is better), // - an nhv×kdu vertical work array WV along the left-hand-edge // (nhv must be at least kdu but more is better). kdu := 2 * ns ku := n - kdu kwh := kdu kwv = kdu + 3 nhv = n - kwv - kdu // Small-bulge multi-shift QR sweep. impl.Dlaqr5(wantt, wantz, kacc22, n, ktop, kbot, ns, wr[ks:ks+ns], wi[ks:ks+ns], h, ldh, iloz, ihiz, z, ldz, work, 3, h[ku*ldh:], ldh, nhv, h[kwv*ldh:], ldh, nhv, h[ku*ldh+kwh:], ldh) // Note progress (or the lack of it). if ld > 0 { ndfl = 1 } else { ndfl++ } } work[0] = float64(lwkopt) return unconverged } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaqr1.go000066400000000000000000000034131450372207100217320ustar00rootroot00000000000000// Copyright ©2016 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" // Dlaqr1 sets v to a scalar multiple of the first column of the product // // (H - (sr1 + i*si1)*I)*(H - (sr2 + i*si2)*I) // // where H is a 2×2 or 3×3 matrix, I is the identity matrix of the same size, // and i is the imaginary unit. Scaling is done to avoid overflows and most // underflows. // // n is the order of H and must be either 2 or 3. It must hold that either sr1 = // sr2 and si1 = -si2, or si1 = si2 = 0. The length of v must be equal to n. If // any of these conditions is not met, Dlaqr1 will panic. // // Dlaqr1 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaqr1(n int, h []float64, ldh int, sr1, si1, sr2, si2 float64, v []float64) { switch { case n != 2 && n != 3: panic("lapack: n must be 2 or 3") case ldh < n: panic(badLdH) case len(h) < (n-1)*ldh+n: panic(shortH) case !((sr1 == sr2 && si1 == -si2) || (si1 == 0 && si2 == 0)): panic(badShifts) case len(v) != n: panic(shortV) } if n == 2 { s := math.Abs(h[0]-sr2) + math.Abs(si2) + math.Abs(h[ldh]) if s == 0 { v[0] = 0 v[1] = 0 } else { h21s := h[ldh] / s v[0] = h21s*h[1] + (h[0]-sr1)*((h[0]-sr2)/s) - si1*(si2/s) v[1] = h21s * (h[0] + h[ldh+1] - sr1 - sr2) } return } s := math.Abs(h[0]-sr2) + math.Abs(si2) + math.Abs(h[ldh]) + math.Abs(h[2*ldh]) if s == 0 { v[0] = 0 v[1] = 0 v[2] = 0 } else { h21s := h[ldh] / s h31s := h[2*ldh] / s v[0] = (h[0]-sr1)*((h[0]-sr2)/s) - si1*(si2/s) + h[1]*h21s + h[2]*h31s v[1] = h21s*(h[0]+h[ldh+1]-sr1-sr2) + h[ldh+2]*h31s v[2] = h31s*(h[0]+h[2*ldh+2]-sr1-sr2) + h21s*h[2*ldh+1] } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaqr23.go000066400000000000000000000303311450372207100220150ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dlaqr23 performs the orthogonal similarity transformation of an n×n upper // Hessenberg matrix to detect and deflate fully converged eigenvalues from a // trailing principal submatrix using aggressive early deflation [1]. // // On return, H will be overwritten by a new Hessenberg matrix that is a // perturbation of an orthogonal similarity transformation of H. It is hoped // that on output H will have many zero subdiagonal entries. // // If wantt is true, the matrix H will be fully updated so that the // quasi-triangular Schur factor can be computed. If wantt is false, then only // enough of H will be updated to preserve the eigenvalues. // // If wantz is true, the orthogonal similarity transformation will be // accumulated into Z[iloz:ihiz+1,ktop:kbot+1], otherwise Z is not referenced. // // ktop and kbot determine a block [ktop:kbot+1,ktop:kbot+1] along the diagonal // of H. It must hold that // // 0 <= ilo <= ihi < n if n > 0, // ilo == 0 and ihi == -1 if n == 0, // // and the block must be isolated, that is, it must hold that // // ktop == 0 or H[ktop,ktop-1] == 0, // kbot == n-1 or H[kbot+1,kbot] == 0, // // otherwise Dlaqr23 will panic. // // nw is the deflation window size. It must hold that // // 0 <= nw <= kbot-ktop+1, // // otherwise Dlaqr23 will panic. // // iloz and ihiz specify the rows of the n×n matrix Z to which transformations // will be applied if wantz is true. It must hold that // // 0 <= iloz <= ktop, and kbot <= ihiz < n, // // otherwise Dlaqr23 will panic. // // sr and si must have length kbot+1, otherwise Dlaqr23 will panic. // // v and ldv represent an nw×nw work matrix. // t and ldt represent an nw×nh work matrix, and nh must be at least nw. // wv and ldwv represent an nv×nw work matrix. // // work must have length at least lwork and lwork must be at least max(1,2*nw), // otherwise Dlaqr23 will panic. Larger values of lwork may result in greater // efficiency. On return, work[0] will contain the optimal value of lwork. // // If lwork is -1, instead of performing Dlaqr23, the function only estimates the // optimal workspace size and stores it into work[0]. Neither h nor z are // accessed. // // recur is the non-negative recursion depth. For recur > 0, Dlaqr23 behaves // as DLAQR3, for recur == 0 it behaves as DLAQR2. // // On return, ns and nd will contain respectively the number of unconverged // (i.e., approximate) eigenvalues and converged eigenvalues that are stored in // sr and si. // // On return, the real and imaginary parts of approximate eigenvalues that may // be used for shifts will be stored respectively in sr[kbot-nd-ns+1:kbot-nd+1] // and si[kbot-nd-ns+1:kbot-nd+1]. // // On return, the real and imaginary parts of converged eigenvalues will be // stored respectively in sr[kbot-nd+1:kbot+1] and si[kbot-nd+1:kbot+1]. // // References: // // [1] K. Braman, R. Byers, R. Mathias. The Multishift QR Algorithm. Part II: // Aggressive Early Deflation. SIAM J. Matrix Anal. Appl 23(4) (2002), pp. 948—973 // URL: http://dx.doi.org/10.1137/S0895479801384585 func (impl Implementation) Dlaqr23(wantt, wantz bool, n, ktop, kbot, nw int, h []float64, ldh int, iloz, ihiz int, z []float64, ldz int, sr, si []float64, v []float64, ldv int, nh int, t []float64, ldt int, nv int, wv []float64, ldwv int, work []float64, lwork int, recur int) (ns, nd int) { switch { case n < 0: panic(nLT0) case ktop < 0 || max(0, n-1) < ktop: panic(badKtop) case kbot < min(ktop, n-1) || n <= kbot: panic(badKbot) case nw < 0 || kbot-ktop+1+1 < nw: panic(badNw) case ldh < max(1, n): panic(badLdH) case wantz && (iloz < 0 || ktop < iloz): panic(badIloz) case wantz && (ihiz < kbot || n <= ihiz): panic(badIhiz) case ldz < 1, wantz && ldz < n: panic(badLdZ) case ldv < max(1, nw): panic(badLdV) case nh < nw: panic(badNh) case ldt < max(1, nh): panic(badLdT) case nv < 0: panic(nvLT0) case ldwv < max(1, nw): panic(badLdWV) case lwork < max(1, 2*nw) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) case recur < 0: panic(recurLT0) } // Quick return for zero window size. if nw == 0 { work[0] = 1 return 0, 0 } // LAPACK code does not enforce the documented behavior // nw <= kbot-ktop+1 // but we do (we panic above). jw := nw lwkopt := max(1, 2*nw) if jw > 2 { // Workspace query call to Dgehrd. impl.Dgehrd(jw, 0, jw-2, t, ldt, work, work, -1) lwk1 := int(work[0]) // Workspace query call to Dormhr. impl.Dormhr(blas.Right, blas.NoTrans, jw, jw, 0, jw-2, t, ldt, work, v, ldv, work, -1) lwk2 := int(work[0]) if recur > 0 { // Workspace query call to Dlaqr04. impl.Dlaqr04(true, true, jw, 0, jw-1, t, ldt, sr, si, 0, jw-1, v, ldv, work, -1, recur-1) lwk3 := int(work[0]) // Optimal workspace. lwkopt = max(jw+max(lwk1, lwk2), lwk3) } else { // Optimal workspace. lwkopt = jw + max(lwk1, lwk2) } } // Quick return in case of workspace query. if lwork == -1 { work[0] = float64(lwkopt) return 0, 0 } // Check input slices only if not doing workspace query. switch { case len(h) < (n-1)*ldh+n: panic(shortH) case len(v) < (nw-1)*ldv+nw: panic(shortV) case len(t) < (nw-1)*ldt+nh: panic(shortT) case len(wv) < (nv-1)*ldwv+nw: panic(shortWV) case wantz && len(z) < (n-1)*ldz+n: panic(shortZ) case len(sr) != kbot+1: panic(badLenSr) case len(si) != kbot+1: panic(badLenSi) case ktop > 0 && h[ktop*ldh+ktop-1] != 0: panic(notIsolated) case kbot+1 < n && h[(kbot+1)*ldh+kbot] != 0: panic(notIsolated) } // Machine constants. ulp := dlamchP smlnum := float64(n) / ulp * dlamchS // Setup deflation window. var s float64 kwtop := kbot - jw + 1 if kwtop != ktop { s = h[kwtop*ldh+kwtop-1] } if kwtop == kbot { // 1×1 deflation window. sr[kwtop] = h[kwtop*ldh+kwtop] si[kwtop] = 0 ns = 1 nd = 0 if math.Abs(s) <= math.Max(smlnum, ulp*math.Abs(h[kwtop*ldh+kwtop])) { ns = 0 nd = 1 if kwtop > ktop { h[kwtop*ldh+kwtop-1] = 0 } } work[0] = 1 return ns, nd } // Convert to spike-triangular form. In case of a rare QR failure, this // routine continues to do aggressive early deflation using that part of // the deflation window that converged using infqr here and there to // keep track. impl.Dlacpy(blas.Upper, jw, jw, h[kwtop*ldh+kwtop:], ldh, t, ldt) bi := blas64.Implementation() bi.Dcopy(jw-1, h[(kwtop+1)*ldh+kwtop:], ldh+1, t[ldt:], ldt+1) impl.Dlaset(blas.All, jw, jw, 0, 1, v, ldv) nmin := impl.Ilaenv(12, "DLAQR3", "SV", jw, 0, jw-1, lwork) var infqr int if recur > 0 && jw > nmin { infqr = impl.Dlaqr04(true, true, jw, 0, jw-1, t, ldt, sr[kwtop:], si[kwtop:], 0, jw-1, v, ldv, work, lwork, recur-1) } else { infqr = impl.Dlahqr(true, true, jw, 0, jw-1, t, ldt, sr[kwtop:], si[kwtop:], 0, jw-1, v, ldv) } // Note that ilo == 0 which conveniently coincides with the success // value of infqr, that is, infqr as an index always points to the first // converged eigenvalue. // Dtrexc needs a clean margin near the diagonal. for j := 0; j < jw-3; j++ { t[(j+2)*ldt+j] = 0 t[(j+3)*ldt+j] = 0 } if jw >= 3 { t[(jw-1)*ldt+jw-3] = 0 } ns = jw ilst := infqr // Deflation detection loop. for ilst < ns { bulge := false if ns >= 2 { bulge = t[(ns-1)*ldt+ns-2] != 0 } if !bulge { // Real eigenvalue. abst := math.Abs(t[(ns-1)*ldt+ns-1]) if abst == 0 { abst = math.Abs(s) } if math.Abs(s*v[ns-1]) <= math.Max(smlnum, ulp*abst) { // Deflatable. ns-- } else { // Undeflatable, move it up out of the way. // Dtrexc can not fail in this case. _, ilst, _ = impl.Dtrexc(lapack.UpdateSchur, jw, t, ldt, v, ldv, ns-1, ilst, work) ilst++ } continue } // Complex conjugate pair. abst := math.Abs(t[(ns-1)*ldt+ns-1]) + math.Sqrt(math.Abs(t[(ns-1)*ldt+ns-2]))*math.Sqrt(math.Abs(t[(ns-2)*ldt+ns-1])) if abst == 0 { abst = math.Abs(s) } if math.Max(math.Abs(s*v[ns-1]), math.Abs(s*v[ns-2])) <= math.Max(smlnum, ulp*abst) { // Deflatable. ns -= 2 } else { // Undeflatable, move them up out of the way. // Dtrexc does the right thing with ilst in case of a // rare exchange failure. _, ilst, _ = impl.Dtrexc(lapack.UpdateSchur, jw, t, ldt, v, ldv, ns-1, ilst, work) ilst += 2 } } // Return to Hessenberg form. if ns == 0 { s = 0 } if ns < jw { // Sorting diagonal blocks of T improves accuracy for graded // matrices. Bubble sort deals well with exchange failures. sorted := false i := ns for !sorted { sorted = true kend := i - 1 i = infqr var k int if i == ns-1 || t[(i+1)*ldt+i] == 0 { k = i + 1 } else { k = i + 2 } for k <= kend { var evi float64 if k == i+1 { evi = math.Abs(t[i*ldt+i]) } else { evi = math.Abs(t[i*ldt+i]) + math.Sqrt(math.Abs(t[(i+1)*ldt+i]))*math.Sqrt(math.Abs(t[i*ldt+i+1])) } var evk float64 if k == kend || t[(k+1)*ldt+k] == 0 { evk = math.Abs(t[k*ldt+k]) } else { evk = math.Abs(t[k*ldt+k]) + math.Sqrt(math.Abs(t[(k+1)*ldt+k]))*math.Sqrt(math.Abs(t[k*ldt+k+1])) } if evi >= evk { i = k } else { sorted = false _, ilst, ok := impl.Dtrexc(lapack.UpdateSchur, jw, t, ldt, v, ldv, i, k, work) if ok { i = ilst } else { i = k } } if i == kend || t[(i+1)*ldt+i] == 0 { k = i + 1 } else { k = i + 2 } } } } // Restore shift/eigenvalue array from T. for i := jw - 1; i >= infqr; { if i == infqr || t[i*ldt+i-1] == 0 { sr[kwtop+i] = t[i*ldt+i] si[kwtop+i] = 0 i-- continue } aa := t[(i-1)*ldt+i-1] bb := t[(i-1)*ldt+i] cc := t[i*ldt+i-1] dd := t[i*ldt+i] _, _, _, _, sr[kwtop+i-1], si[kwtop+i-1], sr[kwtop+i], si[kwtop+i], _, _ = impl.Dlanv2(aa, bb, cc, dd) i -= 2 } if ns < jw || s == 0 { if ns > 1 && s != 0 { // Reflect spike back into lower triangle. bi.Dcopy(ns, v[:ns], 1, work[:ns], 1) _, tau := impl.Dlarfg(ns, work[0], work[1:ns], 1) work[0] = 1 impl.Dlaset(blas.Lower, jw-2, jw-2, 0, 0, t[2*ldt:], ldt) impl.Dlarf(blas.Left, ns, jw, work[:ns], 1, tau, t, ldt, work[jw:]) impl.Dlarf(blas.Right, ns, ns, work[:ns], 1, tau, t, ldt, work[jw:]) impl.Dlarf(blas.Right, jw, ns, work[:ns], 1, tau, v, ldv, work[jw:]) impl.Dgehrd(jw, 0, ns-1, t, ldt, work[:jw-1], work[jw:], lwork-jw) } // Copy updated reduced window into place. if kwtop > 0 { h[kwtop*ldh+kwtop-1] = s * v[0] } impl.Dlacpy(blas.Upper, jw, jw, t, ldt, h[kwtop*ldh+kwtop:], ldh) bi.Dcopy(jw-1, t[ldt:], ldt+1, h[(kwtop+1)*ldh+kwtop:], ldh+1) // Accumulate orthogonal matrix in order to update H and Z, if // requested. if ns > 1 && s != 0 { // work[:ns-1] contains the elementary reflectors stored // by a call to Dgehrd above. impl.Dormhr(blas.Right, blas.NoTrans, jw, ns, 0, ns-1, t, ldt, work[:ns-1], v, ldv, work[jw:], lwork-jw) } // Update vertical slab in H. var ltop int if !wantt { ltop = ktop } for krow := ltop; krow < kwtop; krow += nv { kln := min(nv, kwtop-krow) bi.Dgemm(blas.NoTrans, blas.NoTrans, kln, jw, jw, 1, h[krow*ldh+kwtop:], ldh, v, ldv, 0, wv, ldwv) impl.Dlacpy(blas.All, kln, jw, wv, ldwv, h[krow*ldh+kwtop:], ldh) } // Update horizontal slab in H. if wantt { for kcol := kbot + 1; kcol < n; kcol += nh { kln := min(nh, n-kcol) bi.Dgemm(blas.Trans, blas.NoTrans, jw, kln, jw, 1, v, ldv, h[kwtop*ldh+kcol:], ldh, 0, t, ldt) impl.Dlacpy(blas.All, jw, kln, t, ldt, h[kwtop*ldh+kcol:], ldh) } } // Update vertical slab in Z. if wantz { for krow := iloz; krow <= ihiz; krow += nv { kln := min(nv, ihiz-krow+1) bi.Dgemm(blas.NoTrans, blas.NoTrans, kln, jw, jw, 1, z[krow*ldz+kwtop:], ldz, v, ldv, 0, wv, ldwv) impl.Dlacpy(blas.All, kln, jw, wv, ldwv, z[krow*ldz+kwtop:], ldz) } } } // The number of deflations. nd = jw - ns // Shifts are converged eigenvalues that could not be deflated. // Subtracting infqr from the spike length takes care of the case of a // rare QR failure while calculating eigenvalues of the deflation // window. ns -= infqr work[0] = float64(lwkopt) return ns, nd } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaqr5.go000066400000000000000000000447261450372207100217520ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" ) // Dlaqr5 performs a single small-bulge multi-shift QR sweep on an isolated // block of a Hessenberg matrix. // // wantt and wantz determine whether the quasi-triangular Schur factor and the // orthogonal Schur factor, respectively, will be computed. // // kacc22 specifies the computation mode of far-from-diagonal orthogonal // updates. Permitted values are: // // 0: Dlaqr5 will not accumulate reflections and will not use matrix-matrix // multiply to update far-from-diagonal matrix entries. // 1: Dlaqr5 will accumulate reflections and use matrix-matrix multiply to // update far-from-diagonal matrix entries. // 2: Same as kacc22=1. This option used to enable exploiting the 2×2 structure // during matrix multiplications, but this is no longer supported. // // For other values of kacc2 Dlaqr5 will panic. // // n is the order of the Hessenberg matrix H. // // ktop and kbot are indices of the first and last row and column of an isolated // diagonal block upon which the QR sweep will be applied. It must hold that // // ktop == 0, or 0 < ktop <= n-1 and H[ktop, ktop-1] == 0, and // kbot == n-1, or 0 <= kbot < n-1 and H[kbot+1, kbot] == 0, // // otherwise Dlaqr5 will panic. // // nshfts is the number of simultaneous shifts. It must be positive and even, // otherwise Dlaqr5 will panic. // // sr and si contain the real and imaginary parts, respectively, of the shifts // of origin that define the multi-shift QR sweep. On return both slices may be // reordered by Dlaqr5. Their length must be equal to nshfts, otherwise Dlaqr5 // will panic. // // h and ldh represent the Hessenberg matrix H of size n×n. On return // multi-shift QR sweep with shifts sr+i*si has been applied to the isolated // diagonal block in rows and columns ktop through kbot, inclusive. // // iloz and ihiz specify the rows of Z to which transformations will be applied // if wantz is true. It must hold that 0 <= iloz <= ihiz < n, otherwise Dlaqr5 // will panic. // // z and ldz represent the matrix Z of size n×n. If wantz is true, the QR sweep // orthogonal similarity transformation is accumulated into // z[iloz:ihiz,iloz:ihiz] from the right, otherwise z not referenced. // // v and ldv represent an auxiliary matrix V of size (nshfts/2)×3. Note that V // is transposed with respect to the reference netlib implementation. // // u and ldu represent an auxiliary matrix of size (2*nshfts)×(2*nshfts). // // wh and ldwh represent an auxiliary matrix of size (2*nshfts-1)×nh. // // wv and ldwv represent an auxiliary matrix of size nv×(2*nshfts-1). // // Dlaqr5 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaqr5(wantt, wantz bool, kacc22 int, n, ktop, kbot, nshfts int, sr, si []float64, h []float64, ldh int, iloz, ihiz int, z []float64, ldz int, v []float64, ldv int, u []float64, ldu int, nv int, wv []float64, ldwv int, nh int, wh []float64, ldwh int) { switch { case kacc22 != 0 && kacc22 != 1 && kacc22 != 2: panic(badKacc22) case n < 0: panic(nLT0) case ktop < 0 || n <= ktop: panic(badKtop) case kbot < 0 || n <= kbot: panic(badKbot) case nshfts < 0: panic(nshftsLT0) case nshfts&0x1 != 0: panic(nshftsOdd) case len(sr) != nshfts: panic(badLenSr) case len(si) != nshfts: panic(badLenSi) case ldh < max(1, n): panic(badLdH) case len(h) < (n-1)*ldh+n: panic(shortH) case wantz && ihiz >= n: panic(badIhiz) case wantz && iloz < 0 || ihiz < iloz: panic(badIloz) case ldz < 1, wantz && ldz < n: panic(badLdZ) case wantz && len(z) < (n-1)*ldz+n: panic(shortZ) case ldv < 3: // V is transposed w.r.t. reference lapack. panic(badLdV) case len(v) < (nshfts/2-1)*ldv+3: panic(shortV) case ldu < max(1, 2*nshfts): panic(badLdU) case len(u) < (2*nshfts-1)*ldu+2*nshfts: panic(shortU) case nv < 0: panic(nvLT0) case ldwv < max(1, 2*nshfts): panic(badLdWV) case len(wv) < (nv-1)*ldwv+2*nshfts: panic(shortWV) case nh < 0: panic(nhLT0) case ldwh < max(1, nh): panic(badLdWH) case len(wh) < (2*nshfts-1)*ldwh+nh: panic(shortWH) case ktop > 0 && h[ktop*ldh+ktop-1] != 0: panic(notIsolated) case kbot < n-1 && h[(kbot+1)*ldh+kbot] != 0: panic(notIsolated) } // If there are no shifts, then there is nothing to do. if nshfts < 2 { return } // If the active block is empty or 1×1, then there is nothing to do. if ktop >= kbot { return } // Shuffle shifts into pairs of real shifts and pairs of complex // conjugate shifts assuming complex conjugate shifts are already // adjacent to one another. for i := 0; i < nshfts-2; i += 2 { if si[i] == -si[i+1] { continue } sr[i], sr[i+1], sr[i+2] = sr[i+1], sr[i+2], sr[i] si[i], si[i+1], si[i+2] = si[i+1], si[i+2], si[i] } // Note: lapack says that nshfts must be even but allows it to be odd // anyway. We panic above if nshfts is not even, so reducing it by one // is unnecessary. The only caller Dlaqr04 uses only even nshfts. // // The original comment and code from lapack-3.6.0/SRC/dlaqr5.f:341: // * ==== NSHFTS is supposed to be even, but if it is odd, // * . then simply reduce it by one. The shuffle above // * . ensures that the dropped shift is real and that // * . the remaining shifts are paired. ==== // * // NS = NSHFTS - MOD( NSHFTS, 2 ) ns := nshfts safmin := dlamchS ulp := dlamchP smlnum := safmin * float64(n) / ulp // Use accumulated reflections to update far-from-diagonal entries? accum := kacc22 == 1 || kacc22 == 2 // Clear trash. if ktop+2 <= kbot { h[(ktop+2)*ldh+ktop] = 0 } // nbmps = number of 2-shift bulges in the chain. nbmps := ns / 2 // kdu = width of slab. kdu := 4 * nbmps // Create and chase chains of nbmps bulges. for incol := ktop - 2*nbmps + 1; incol <= kbot-2; incol += 2 * nbmps { // jtop is an index from which updates from the right start. var jtop int switch { case accum: jtop = max(ktop, incol) case wantt: default: jtop = ktop } ndcol := incol + kdu if accum { impl.Dlaset(blas.All, kdu, kdu, 0, 1, u, ldu) } // Near-the-diagonal bulge chase. The following loop performs // the near-the-diagonal part of a small bulge multi-shift QR // sweep. Each 4*nbmps column diagonal chunk extends from // column incol to column ndcol (including both column incol and // column ndcol). The following loop chases a 2*nbmps+1 column // long chain of nbmps bulges 2*nbmps columns to the right. // (incol may be less than ktop and ndcol may be greater than // kbot indicating phantom columns from which to chase bulges // before they are actually introduced or to which to chase // bulges beyond column kbot.) for krcol := incol; krcol <= min(incol+2*nbmps-1, kbot-2); krcol++ { // Bulges number mtop to mbot are active double implicit // shift bulges. There may or may not also be small 2×2 // bulge, if there is room. The inactive bulges (if any) // must wait until the active bulges have moved down the // diagonal to make room. The phantom matrix paradigm // described above helps keep track. mtop := max(0, (ktop-krcol)/2) mbot := min(nbmps, (kbot-krcol-1)/2) - 1 m22 := mbot + 1 bmp22 := (mbot < nbmps-1) && (krcol+2*m22 == kbot-2) // Generate reflections to chase the chain right one column. // The minimum value of k is ktop-1. if bmp22 { // Special case: 2×2 reflection at bottom treated separately. k := krcol + 2*m22 if k == ktop-1 { impl.Dlaqr1(2, h[(k+1)*ldh+k+1:], ldh, sr[2*m22], si[2*m22], sr[2*m22+1], si[2*m22+1], v[m22*ldv:m22*ldv+2]) beta := v[m22*ldv] _, v[m22*ldv] = impl.Dlarfg(2, beta, v[m22*ldv+1:m22*ldv+2], 1) } else { beta := h[(k+1)*ldh+k] v[m22*ldv+1] = h[(k+2)*ldh+k] beta, v[m22*ldv] = impl.Dlarfg(2, beta, v[m22*ldv+1:m22*ldv+2], 1) h[(k+1)*ldh+k] = beta h[(k+2)*ldh+k] = 0 } // Perform update from right within computational window. t1 := v[m22*ldv] t2 := t1 * v[m22*ldv+1] for j := jtop; j <= min(kbot, k+3); j++ { refsum := h[j*ldh+k+1] + v[m22*ldv+1]*h[j*ldh+k+2] h[j*ldh+k+1] -= refsum * t1 h[j*ldh+k+2] -= refsum * t2 } // Perform update from left within computational window. var jbot int switch { case accum: jbot = min(ndcol, kbot) case wantt: jbot = n - 1 default: jbot = kbot } t1 = v[m22*ldv] t2 = t1 * v[m22*ldv+1] for j := k + 1; j <= jbot; j++ { refsum := h[(k+1)*ldh+j] + v[m22*ldv+1]*h[(k+2)*ldh+j] h[(k+1)*ldh+j] -= refsum * t1 h[(k+2)*ldh+j] -= refsum * t2 } // The following convergence test requires that the traditional // small-compared-to-nearby-diagonals criterion and the Ahues & // Tisseur (LAWN 122, 1997) criteria both be satisfied. The latter // improves accuracy in some examples. Falling back on an alternate // convergence criterion when tst1 or tst2 is zero (as done here) is // traditional but probably unnecessary. if k >= ktop && h[(k+1)*ldh+k] != 0 { tst1 := math.Abs(h[k*ldh+k]) + math.Abs(h[(k+1)*ldh+k+1]) if tst1 == 0 { if k >= ktop+1 { tst1 += math.Abs(h[k*ldh+k-1]) } if k >= ktop+2 { tst1 += math.Abs(h[k*ldh+k-2]) } if k >= ktop+3 { tst1 += math.Abs(h[k*ldh+k-3]) } if k <= kbot-2 { tst1 += math.Abs(h[(k+2)*ldh+k+1]) } if k <= kbot-3 { tst1 += math.Abs(h[(k+3)*ldh+k+1]) } if k <= kbot-4 { tst1 += math.Abs(h[(k+4)*ldh+k+1]) } } if math.Abs(h[(k+1)*ldh+k]) <= math.Max(smlnum, ulp*tst1) { h12 := math.Max(math.Abs(h[(k+1)*ldh+k]), math.Abs(h[k*ldh+k+1])) h21 := math.Min(math.Abs(h[(k+1)*ldh+k]), math.Abs(h[k*ldh+k+1])) h11 := math.Max(math.Abs(h[(k+1)*ldh+k+1]), math.Abs(h[k*ldh+k]-h[(k+1)*ldh+k+1])) h22 := math.Min(math.Abs(h[(k+1)*ldh+k+1]), math.Abs(h[k*ldh+k]-h[(k+1)*ldh+k+1])) scl := h11 + h12 tst2 := h22 * (h11 / scl) if tst2 == 0 || h21*(h12/scl) <= math.Max(smlnum, ulp*tst2) { h[(k+1)*ldh+k] = 0 } } } // Accumulate orthogonal transformations. if accum { kms := k - incol - 1 t1 = v[m22*ldv] t2 = t1 * v[m22*ldv+1] for j := max(0, ktop-incol-1); j < kdu; j++ { refsum := u[j*ldu+kms+1] + v[m22*ldv+1]*u[j*ldu+kms+2] u[j*ldu+kms+1] -= refsum * t1 u[j*ldu+kms+2] -= refsum * t2 } } else if wantz { t1 = v[m22*ldv] t2 = t1 * v[m22*ldv+1] for j := iloz; j <= ihiz; j++ { refsum := z[j*ldz+k+1] + v[m22*ldv+1]*z[j*ldz+k+2] z[j*ldz+k+1] -= refsum * t1 z[j*ldz+k+2] -= refsum * t2 } } } // Normal case: Chain of 3×3 reflections. for m := mbot; m >= mtop; m-- { k := krcol + 2*m if k == ktop-1 { impl.Dlaqr1(3, h[ktop*ldh+ktop:], ldh, sr[2*m], si[2*m], sr[2*m+1], si[2*m+1], v[m*ldv:m*ldv+3]) alpha := v[m*ldv] _, v[m*ldv] = impl.Dlarfg(3, alpha, v[m*ldv+1:m*ldv+3], 1) } else { // Perform delayed transformation of row below m-th bulge. // Exploit fact that first two elements of row are actually // zero. t1 := v[m*ldv] t2 := t1 * v[m*ldv+1] t3 := t1 * v[m*ldv+2] refsum := v[m*ldv+2] * h[(k+3)*ldh+k+2] h[(k+3)*ldh+k] = -refsum * t1 h[(k+3)*ldh+k+1] = -refsum * t2 h[(k+3)*ldh+k+2] -= refsum * t3 // Calculate reflection to move m-th bulge one step. beta := h[(k+1)*ldh+k] v[m*ldv+1] = h[(k+2)*ldh+k] v[m*ldv+2] = h[(k+3)*ldh+k] beta, v[m*ldv] = impl.Dlarfg(3, beta, v[m*ldv+1:m*ldv+3], 1) // A bulge may collapse because of vigilant deflation or // destructive underflow. In the underflow case, try the // two-small-subdiagonals trick to try to reinflate the // bulge. if h[(k+3)*ldh+k] != 0 || h[(k+3)*ldh+k+1] != 0 || h[(k+3)*ldh+k+2] == 0 { // Typical case: not collapsed (yet). h[(k+1)*ldh+k] = beta h[(k+2)*ldh+k] = 0 h[(k+3)*ldh+k] = 0 } else { // Atypical case: collapsed. Attempt to reintroduce // ignoring H[k+1,k] and H[k+2,k]. If the fill resulting // from the new reflector is too large, then abandon it. // Otherwise, use the new one. var vt [3]float64 impl.Dlaqr1(3, h[(k+1)*ldh+k+1:], ldh, sr[2*m], si[2*m], sr[2*m+1], si[2*m+1], vt[:]) _, vt[0] = impl.Dlarfg(3, vt[0], vt[1:3], 1) t1 = vt[0] t2 = t1 * vt[1] t3 = t1 * vt[2] refsum = h[(k+1)*ldh+k] + vt[1]*h[(k+2)*ldh+k] dsum := math.Abs(h[k*ldh+k]) + math.Abs(h[(k+1)*ldh+k+1]) + math.Abs(h[(k+2)*ldh+k+2]) if math.Abs(h[(k+2)*ldh+k]-refsum*t2)+math.Abs(refsum*t3) > ulp*dsum { // Starting a new bulge here would create // non-negligible fill. Use the old one with // trepidation. h[(k+1)*ldh+k] = beta h[(k+2)*ldh+k] = 0 h[(k+3)*ldh+k] = 0 } else { // Starting a new bulge here would create only // negligible fill. Replace the old reflector with // the new one. h[(k+1)*ldh+k] -= refsum * t1 h[(k+2)*ldh+k] = 0 h[(k+3)*ldh+k] = 0 v[m*ldv] = vt[0] v[m*ldv+1] = vt[1] v[m*ldv+2] = vt[2] } } } // Apply reflection from the right and the first column of // update from the left. These updates are required for the // vigilant deflation check. We still delay most of the updates // from the left for efficiency. t1 := v[m*ldv] t2 := t1 * v[m*ldv+1] t3 := t1 * v[m*ldv+2] for j := jtop; j <= min(kbot, k+3); j++ { refsum := h[j*ldh+k+1] + v[m*ldv+1]*h[j*ldh+k+2] + v[m*ldv+2]*h[j*ldh+k+3] h[j*ldh+k+1] -= refsum * t1 h[j*ldh+k+2] -= refsum * t2 h[j*ldh+k+3] -= refsum * t3 } // Perform update from left for subsequent column. refsum := h[(k+1)*ldh+k+1] + v[m*ldv+1]*h[(k+2)*ldh+k+1] + v[m*ldv+2]*h[(k+3)*ldh+k+1] h[(k+1)*ldh+k+1] -= refsum * t1 h[(k+2)*ldh+k+1] -= refsum * t2 h[(k+3)*ldh+k+1] -= refsum * t3 // The following convergence test requires that the tradition // small-compared-to-nearby-diagonals criterion and the Ahues & // Tisseur (LAWN 122, 1997) criteria both be satisfied. The // latter improves accuracy in some examples. Falling back on an // alternate convergence criterion when tst1 or tst2 is zero (as // done here) is traditional but probably unnecessary. if k < ktop { continue } if h[(k+1)*ldh+k] != 0 { tst1 := math.Abs(h[k*ldh+k]) + math.Abs(h[(k+1)*ldh+k+1]) if tst1 == 0 { if k >= ktop+1 { tst1 += math.Abs(h[k*ldh+k-1]) } if k >= ktop+2 { tst1 += math.Abs(h[k*ldh+k-2]) } if k >= ktop+3 { tst1 += math.Abs(h[k*ldh+k-3]) } if k <= kbot-2 { tst1 += math.Abs(h[(k+2)*ldh+k+1]) } if k <= kbot-3 { tst1 += math.Abs(h[(k+3)*ldh+k+1]) } if k <= kbot-4 { tst1 += math.Abs(h[(k+4)*ldh+k+1]) } } if math.Abs(h[(k+1)*ldh+k]) <= math.Max(smlnum, ulp*tst1) { h12 := math.Max(math.Abs(h[(k+1)*ldh+k]), math.Abs(h[k*ldh+k+1])) h21 := math.Min(math.Abs(h[(k+1)*ldh+k]), math.Abs(h[k*ldh+k+1])) h11 := math.Max(math.Abs(h[(k+1)*ldh+k+1]), math.Abs(h[k*ldh+k]-h[(k+1)*ldh+k+1])) h22 := math.Min(math.Abs(h[(k+1)*ldh+k+1]), math.Abs(h[k*ldh+k]-h[(k+1)*ldh+k+1])) scl := h11 + h12 tst2 := h22 * (h11 / scl) if tst2 == 0 || h21*(h12/scl) <= math.Max(smlnum, ulp*tst2) { h[(k+1)*ldh+k] = 0 } } } } // Multiply H by reflections from the left. var jbot int switch { case accum: jbot = min(ndcol, kbot) case wantt: jbot = n - 1 default: jbot = kbot } for m := mbot; m >= mtop; m-- { k := krcol + 2*m t1 := v[m*ldv] t2 := t1 * v[m*ldv+1] t3 := t1 * v[m*ldv+2] for j := max(ktop, krcol+2*(m+1)); j <= jbot; j++ { refsum := h[(k+1)*ldh+j] + v[m*ldv+1]*h[(k+2)*ldh+j] + v[m*ldv+2]*h[(k+3)*ldh+j] h[(k+1)*ldh+j] -= refsum * t1 h[(k+2)*ldh+j] -= refsum * t2 h[(k+3)*ldh+j] -= refsum * t3 } } // Accumulate orthogonal transformations. if accum { // Accumulate U. If necessary, update Z later with an // efficient matrix-matrix multiply. for m := mbot; m >= mtop; m-- { k := krcol + 2*m kms := k - incol - 1 i2 := max(0, ktop-incol-1) i2 = max(i2, kms-(krcol-incol)) i4 := min(kdu, krcol+2*mbot-incol+5) t1 := v[m*ldv] t2 := t1 * v[m*ldv+1] t3 := t1 * v[m*ldv+2] for j := i2; j < i4; j++ { refsum := u[j*ldu+kms+1] + v[m*ldv+1]*u[j*ldu+kms+2] + v[m*ldv+2]*u[j*ldu+kms+3] u[j*ldu+kms+1] -= refsum * t1 u[j*ldu+kms+2] -= refsum * t2 u[j*ldu+kms+3] -= refsum * t3 } } } else if wantz { // U is not accumulated, so update Z now by multiplying by // reflections from the right. for m := mbot; m >= mtop; m-- { k := krcol + 2*m t1 := v[m*ldv] t2 := t1 * v[m*ldv+1] t3 := t1 * v[m*ldv+2] for j := iloz; j <= ihiz; j++ { refsum := z[j*ldz+k+1] + v[m*ldv+1]*z[j*ldz+k+2] + v[m*ldv+2]*z[j*ldz+k+3] z[j*ldz+k+1] -= refsum * t1 z[j*ldz+k+2] -= refsum * t2 z[j*ldz+k+3] -= refsum * t3 } } } } // Use U (if accumulated) to update far-from-diagonal entries in H. // If required, use U to update Z as well. if !accum { continue } jtop, jbot := ktop, kbot if wantt { jtop = 0 jbot = n - 1 } bi := blas64.Implementation() k1 := max(0, ktop-incol-1) nu := kdu - max(0, ndcol-kbot) - k1 // Horizontal multiply. for jcol := min(ndcol, kbot) + 1; jcol <= jbot; jcol += nh { jlen := min(nh, jbot-jcol+1) bi.Dgemm(blas.Trans, blas.NoTrans, nu, jlen, nu, 1, u[k1*ldu+k1:], ldu, h[(incol+k1+1)*ldh+jcol:], ldh, 0, wh, ldwh) impl.Dlacpy(blas.All, nu, jlen, wh, ldwh, h[(incol+k1+1)*ldh+jcol:], ldh) } // Vertical multiply. for jrow := jtop; jrow < max(ktop, incol); jrow += nv { jlen := min(nv, max(ktop, incol)-jrow) bi.Dgemm(blas.NoTrans, blas.NoTrans, jlen, nu, nu, 1, h[jrow*ldh+incol+k1+1:], ldh, u[k1*ldu+k1:], ldu, 0, wv, ldwv) impl.Dlacpy(blas.All, jlen, nu, wv, ldwv, h[jrow*ldh+incol+k1+1:], ldh) } // Z multiply (also vertical). if wantz { for jrow := iloz; jrow <= ihiz; jrow += nv { jlen := min(nv, ihiz-jrow+1) bi.Dgemm(blas.NoTrans, blas.NoTrans, jlen, nu, nu, 1, z[jrow*ldz+incol+k1+1:], ldz, u[k1*ldu+k1:], ldu, 0, wv, ldwv) impl.Dlacpy(blas.All, jlen, nu, wv, ldwv, z[jrow*ldz+incol+k1+1:], ldz) } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlarf.go000066400000000000000000000050011450372207100216310ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dlarf applies an elementary reflector H to an m×n matrix C: // // C = H * C if side == blas.Left // C = C * H if side == blas.Right // // H is represented in the form // // H = I - tau * v * vᵀ // // where tau is a scalar and v is a vector. // // work must have length at least m if side == blas.Left and // at least n if side == blas.Right. // // Dlarf is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlarf(side blas.Side, m, n int, v []float64, incv int, tau float64, c []float64, ldc int, work []float64) { switch { case side != blas.Left && side != blas.Right: panic(badSide) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case incv == 0: panic(zeroIncV) case ldc < max(1, n): panic(badLdC) } if m == 0 || n == 0 { return } applyleft := side == blas.Left lenV := n if applyleft { lenV = m } switch { case len(v) < 1+(lenV-1)*abs(incv): panic(shortV) case len(c) < (m-1)*ldc+n: panic(shortC) case (applyleft && len(work) < n) || (!applyleft && len(work) < m): panic(shortWork) } lastv := -1 // last non-zero element of v lastc := -1 // last non-zero row/column of C if tau != 0 { if applyleft { lastv = m - 1 } else { lastv = n - 1 } var i int if incv > 0 { i = lastv * incv } // Look for the last non-zero row in v. for lastv >= 0 && v[i] == 0 { lastv-- i -= incv } if applyleft { // Scan for the last non-zero column in C[0:lastv, :] lastc = impl.Iladlc(lastv+1, n, c, ldc) } else { // Scan for the last non-zero row in C[:, 0:lastv] lastc = impl.Iladlr(m, lastv+1, c, ldc) } } if lastv == -1 || lastc == -1 { return } bi := blas64.Implementation() if applyleft { // Form H * C // w[0:lastc+1] = c[1:lastv+1, 1:lastc+1]ᵀ * v[1:lastv+1,1] bi.Dgemv(blas.Trans, lastv+1, lastc+1, 1, c, ldc, v, incv, 0, work, 1) // c[0: lastv, 0: lastc] = c[...] - w[0:lastv, 1] * v[1:lastc, 1]ᵀ bi.Dger(lastv+1, lastc+1, -tau, v, incv, work, 1, c, ldc) } else { // Form C * H // w[0:lastc+1,1] := c[0:lastc+1,0:lastv+1] * v[0:lastv+1,1] bi.Dgemv(blas.NoTrans, lastc+1, lastv+1, 1, c, ldc, v, incv, 0, work, 1) // c[0:lastc+1,0:lastv+1] = c[...] - w[0:lastc+1,0] * v[0:lastv+1,0]ᵀ bi.Dger(lastc+1, lastv+1, -tau, work, 1, v, incv, c, ldc) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlarfb.go000066400000000000000000000276751450372207100220200ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dlarfb applies a block reflector to a matrix. // // In the call to Dlarfb, the mxn c is multiplied by the implicitly defined matrix h as follows: // // c = h * c if side == Left and trans == NoTrans // c = c * h if side == Right and trans == NoTrans // c = hᵀ * c if side == Left and trans == Trans // c = c * hᵀ if side == Right and trans == Trans // // h is a product of elementary reflectors. direct sets the direction of multiplication // // h = h_1 * h_2 * ... * h_k if direct == Forward // h = h_k * h_k-1 * ... * h_1 if direct == Backward // // The combination of direct and store defines the orientation of the elementary // reflectors. In all cases the ones on the diagonal are implicitly represented. // // If direct == lapack.Forward and store == lapack.ColumnWise // // V = [ 1 ] // [v1 1 ] // [v1 v2 1] // [v1 v2 v3] // [v1 v2 v3] // // If direct == lapack.Forward and store == lapack.RowWise // // V = [ 1 v1 v1 v1 v1] // [ 1 v2 v2 v2] // [ 1 v3 v3] // // If direct == lapack.Backward and store == lapack.ColumnWise // // V = [v1 v2 v3] // [v1 v2 v3] // [ 1 v2 v3] // [ 1 v3] // [ 1] // // If direct == lapack.Backward and store == lapack.RowWise // // V = [v1 v1 1 ] // [v2 v2 v2 1 ] // [v3 v3 v3 v3 1] // // An elementary reflector can be explicitly constructed by extracting the // corresponding elements of v, placing a 1 where the diagonal would be, and // placing zeros in the remaining elements. // // t is a k×k matrix containing the block reflector, and this function will panic // if t is not of sufficient size. See Dlarft for more information. // // work is a temporary storage matrix with stride ldwork. // work must be of size at least n×k side == Left and m×k if side == Right, and // this function will panic if this size is not met. // // Dlarfb is an internal routine. It is exported for testing purposes. func (Implementation) Dlarfb(side blas.Side, trans blas.Transpose, direct lapack.Direct, store lapack.StoreV, m, n, k int, v []float64, ldv int, t []float64, ldt int, c []float64, ldc int, work []float64, ldwork int) { nv := m if side == blas.Right { nv = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case trans != blas.Trans && trans != blas.NoTrans: panic(badTrans) case direct != lapack.Forward && direct != lapack.Backward: panic(badDirect) case store != lapack.ColumnWise && store != lapack.RowWise: panic(badStoreV) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case store == lapack.ColumnWise && ldv < max(1, k): panic(badLdV) case store == lapack.RowWise && ldv < max(1, nv): panic(badLdV) case ldt < max(1, k): panic(badLdT) case ldc < max(1, n): panic(badLdC) case ldwork < max(1, k): panic(badLdWork) } if m == 0 || n == 0 { return } nw := n if side == blas.Right { nw = m } switch { case store == lapack.ColumnWise && len(v) < (nv-1)*ldv+k: panic(shortV) case store == lapack.RowWise && len(v) < (k-1)*ldv+nv: panic(shortV) case len(t) < (k-1)*ldt+k: panic(shortT) case len(c) < (m-1)*ldc+n: panic(shortC) case len(work) < (nw-1)*ldwork+k: panic(shortWork) } bi := blas64.Implementation() transt := blas.Trans if trans == blas.Trans { transt = blas.NoTrans } // TODO(btracey): This follows the original Lapack code where the // elements are copied into the columns of the working array. The // loops should go in the other direction so the data is written // into the rows of work so the copy is not strided. A bigger change // would be to replace work with workᵀ, but benchmarks would be // needed to see if the change is merited. if store == lapack.ColumnWise { if direct == lapack.Forward { // V1 is the first k rows of C. V2 is the remaining rows. if side == blas.Left { // W = Cᵀ V = C1ᵀ V1 + C2ᵀ V2 (stored in work). // W = C1. for j := 0; j < k; j++ { bi.Dcopy(n, c[j*ldc:], 1, work[j:], ldwork) } // W = W * V1. bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, n, k, 1, v, ldv, work, ldwork) if m > k { // W = W + C2ᵀ V2. bi.Dgemm(blas.Trans, blas.NoTrans, n, k, m-k, 1, c[k*ldc:], ldc, v[k*ldv:], ldv, 1, work, ldwork) } // W = W * Tᵀ or W * T. bi.Dtrmm(blas.Right, blas.Upper, transt, blas.NonUnit, n, k, 1, t, ldt, work, ldwork) // C -= V * Wᵀ. if m > k { // C2 -= V2 * Wᵀ. bi.Dgemm(blas.NoTrans, blas.Trans, m-k, n, k, -1, v[k*ldv:], ldv, work, ldwork, 1, c[k*ldc:], ldc) } // W *= V1ᵀ. bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, n, k, 1, v, ldv, work, ldwork) // C1 -= Wᵀ. // TODO(btracey): This should use blas.Axpy. for i := 0; i < n; i++ { for j := 0; j < k; j++ { c[j*ldc+i] -= work[i*ldwork+j] } } return } // Form C = C * H or C * Hᵀ, where C = (C1 C2). // W = C1. for i := 0; i < k; i++ { bi.Dcopy(m, c[i:], ldc, work[i:], ldwork) } // W *= V1. bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, m, k, 1, v, ldv, work, ldwork) if n > k { bi.Dgemm(blas.NoTrans, blas.NoTrans, m, k, n-k, 1, c[k:], ldc, v[k*ldv:], ldv, 1, work, ldwork) } // W *= T or Tᵀ. bi.Dtrmm(blas.Right, blas.Upper, trans, blas.NonUnit, m, k, 1, t, ldt, work, ldwork) if n > k { bi.Dgemm(blas.NoTrans, blas.Trans, m, n-k, k, -1, work, ldwork, v[k*ldv:], ldv, 1, c[k:], ldc) } // C -= W * Vᵀ. bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, m, k, 1, v, ldv, work, ldwork) // C -= W. // TODO(btracey): This should use blas.Axpy. for i := 0; i < m; i++ { for j := 0; j < k; j++ { c[i*ldc+j] -= work[i*ldwork+j] } } return } // V = (V1) // = (V2) (last k rows) // Where V2 is unit upper triangular. if side == blas.Left { // Form H * C or // W = Cᵀ V. // W = C2ᵀ. for j := 0; j < k; j++ { bi.Dcopy(n, c[(m-k+j)*ldc:], 1, work[j:], ldwork) } // W *= V2. bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, n, k, 1, v[(m-k)*ldv:], ldv, work, ldwork) if m > k { // W += C1ᵀ * V1. bi.Dgemm(blas.Trans, blas.NoTrans, n, k, m-k, 1, c, ldc, v, ldv, 1, work, ldwork) } // W *= T or Tᵀ. bi.Dtrmm(blas.Right, blas.Lower, transt, blas.NonUnit, n, k, 1, t, ldt, work, ldwork) // C -= V * Wᵀ. if m > k { bi.Dgemm(blas.NoTrans, blas.Trans, m-k, n, k, -1, v, ldv, work, ldwork, 1, c, ldc) } // W *= V2ᵀ. bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, n, k, 1, v[(m-k)*ldv:], ldv, work, ldwork) // C2 -= Wᵀ. // TODO(btracey): This should use blas.Axpy. for i := 0; i < n; i++ { for j := 0; j < k; j++ { c[(m-k+j)*ldc+i] -= work[i*ldwork+j] } } return } // Form C * H or C * Hᵀ where C = (C1 C2). // W = C * V. // W = C2. for j := 0; j < k; j++ { bi.Dcopy(m, c[n-k+j:], ldc, work[j:], ldwork) } // W = W * V2. bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, m, k, 1, v[(n-k)*ldv:], ldv, work, ldwork) if n > k { bi.Dgemm(blas.NoTrans, blas.NoTrans, m, k, n-k, 1, c, ldc, v, ldv, 1, work, ldwork) } // W *= T or Tᵀ. bi.Dtrmm(blas.Right, blas.Lower, trans, blas.NonUnit, m, k, 1, t, ldt, work, ldwork) // C -= W * Vᵀ. if n > k { // C1 -= W * V1ᵀ. bi.Dgemm(blas.NoTrans, blas.Trans, m, n-k, k, -1, work, ldwork, v, ldv, 1, c, ldc) } // W *= V2ᵀ. bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, m, k, 1, v[(n-k)*ldv:], ldv, work, ldwork) // C2 -= W. // TODO(btracey): This should use blas.Axpy. for i := 0; i < m; i++ { for j := 0; j < k; j++ { c[i*ldc+n-k+j] -= work[i*ldwork+j] } } return } // Store = Rowwise. if direct == lapack.Forward { // V = (V1 V2) where v1 is unit upper triangular. if side == blas.Left { // Form H * C or Hᵀ * C where C = (C1; C2). // W = Cᵀ * Vᵀ. // W = C1ᵀ. for j := 0; j < k; j++ { bi.Dcopy(n, c[j*ldc:], 1, work[j:], ldwork) } // W *= V1ᵀ. bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, n, k, 1, v, ldv, work, ldwork) if m > k { bi.Dgemm(blas.Trans, blas.Trans, n, k, m-k, 1, c[k*ldc:], ldc, v[k:], ldv, 1, work, ldwork) } // W *= T or Tᵀ. bi.Dtrmm(blas.Right, blas.Upper, transt, blas.NonUnit, n, k, 1, t, ldt, work, ldwork) // C -= Vᵀ * Wᵀ. if m > k { bi.Dgemm(blas.Trans, blas.Trans, m-k, n, k, -1, v[k:], ldv, work, ldwork, 1, c[k*ldc:], ldc) } // W *= V1. bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, n, k, 1, v, ldv, work, ldwork) // C1 -= Wᵀ. // TODO(btracey): This should use blas.Axpy. for i := 0; i < n; i++ { for j := 0; j < k; j++ { c[j*ldc+i] -= work[i*ldwork+j] } } return } // Form C * H or C * Hᵀ where C = (C1 C2). // W = C * Vᵀ. // W = C1. for j := 0; j < k; j++ { bi.Dcopy(m, c[j:], ldc, work[j:], ldwork) } // W *= V1ᵀ. bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, m, k, 1, v, ldv, work, ldwork) if n > k { bi.Dgemm(blas.NoTrans, blas.Trans, m, k, n-k, 1, c[k:], ldc, v[k:], ldv, 1, work, ldwork) } // W *= T or Tᵀ. bi.Dtrmm(blas.Right, blas.Upper, trans, blas.NonUnit, m, k, 1, t, ldt, work, ldwork) // C -= W * V. if n > k { bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n-k, k, -1, work, ldwork, v[k:], ldv, 1, c[k:], ldc) } // W *= V1. bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, m, k, 1, v, ldv, work, ldwork) // C1 -= W. // TODO(btracey): This should use blas.Axpy. for i := 0; i < m; i++ { for j := 0; j < k; j++ { c[i*ldc+j] -= work[i*ldwork+j] } } return } // V = (V1 V2) where V2 is the last k columns and is lower unit triangular. if side == blas.Left { // Form H * C or Hᵀ C where C = (C1 ; C2). // W = Cᵀ * Vᵀ. // W = C2ᵀ. for j := 0; j < k; j++ { bi.Dcopy(n, c[(m-k+j)*ldc:], 1, work[j:], ldwork) } // W *= V2ᵀ. bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, n, k, 1, v[m-k:], ldv, work, ldwork) if m > k { bi.Dgemm(blas.Trans, blas.Trans, n, k, m-k, 1, c, ldc, v, ldv, 1, work, ldwork) } // W *= T or Tᵀ. bi.Dtrmm(blas.Right, blas.Lower, transt, blas.NonUnit, n, k, 1, t, ldt, work, ldwork) // C -= Vᵀ * Wᵀ. if m > k { bi.Dgemm(blas.Trans, blas.Trans, m-k, n, k, -1, v, ldv, work, ldwork, 1, c, ldc) } // W *= V2. bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, n, k, 1, v[m-k:], ldv, work, ldwork) // C2 -= Wᵀ. // TODO(btracey): This should use blas.Axpy. for i := 0; i < n; i++ { for j := 0; j < k; j++ { c[(m-k+j)*ldc+i] -= work[i*ldwork+j] } } return } // Form C * H or C * Hᵀ where C = (C1 C2). // W = C * Vᵀ. // W = C2. for j := 0; j < k; j++ { bi.Dcopy(m, c[n-k+j:], ldc, work[j:], ldwork) } // W *= V2ᵀ. bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, m, k, 1, v[n-k:], ldv, work, ldwork) if n > k { bi.Dgemm(blas.NoTrans, blas.Trans, m, k, n-k, 1, c, ldc, v, ldv, 1, work, ldwork) } // W *= T or Tᵀ. bi.Dtrmm(blas.Right, blas.Lower, trans, blas.NonUnit, m, k, 1, t, ldt, work, ldwork) // C -= W * V. if n > k { bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n-k, k, -1, work, ldwork, v, ldv, 1, c, ldc) } // W *= V2. bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, m, k, 1, v[n-k:], ldv, work, ldwork) // C1 -= W. // TODO(btracey): This should use blas.Axpy. for i := 0; i < m; i++ { for j := 0; j < k; j++ { c[i*ldc+n-k+j] -= work[i*ldwork+j] } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlarfg.go000066400000000000000000000031351450372207100220060ustar00rootroot00000000000000// 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/blas64" ) // Dlarfg generates an elementary reflector for a Householder matrix. It creates // a real elementary reflector of order n such that // // H * (alpha) = (beta) // ( x) ( 0) // Hᵀ * H = I // // H is represented in the form // // H = 1 - tau * (1; v) * (1 vᵀ) // // where tau is a real scalar. // // On entry, x contains the vector x, on exit it contains v. // // Dlarfg is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlarfg(n int, alpha float64, x []float64, incX int) (beta, tau float64) { switch { case n < 0: panic(nLT0) case incX <= 0: panic(badIncX) } if n <= 1 { return alpha, 0 } if len(x) < 1+(n-2)*abs(incX) { panic(shortX) } bi := blas64.Implementation() xnorm := bi.Dnrm2(n-1, x, incX) if xnorm == 0 { return alpha, 0 } beta = -math.Copysign(impl.Dlapy2(alpha, xnorm), alpha) safmin := dlamchS / dlamchE knt := 0 if math.Abs(beta) < safmin { // xnorm and beta may be inaccurate, scale x and recompute. rsafmn := 1 / safmin for { knt++ bi.Dscal(n-1, rsafmn, x, incX) beta *= rsafmn alpha *= rsafmn if math.Abs(beta) >= safmin { break } } xnorm = bi.Dnrm2(n-1, x, incX) beta = -math.Copysign(impl.Dlapy2(alpha, xnorm), alpha) } tau = (beta - alpha) / beta bi.Dscal(n-1, 1/(alpha-beta), x, incX) for j := 0; j < knt; j++ { beta *= safmin } return beta, tau } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlarft.go000066400000000000000000000102721450372207100220230ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dlarft forms the triangular factor T of a block reflector H, storing the answer // in t. // // H = I - V * T * Vᵀ if store == lapack.ColumnWise // H = I - Vᵀ * T * V if store == lapack.RowWise // // H is defined by a product of the elementary reflectors where // // H = H_0 * H_1 * ... * H_{k-1} if direct == lapack.Forward // H = H_{k-1} * ... * H_1 * H_0 if direct == lapack.Backward // // t is a k×k triangular matrix. t is upper triangular if direct = lapack.Forward // and lower triangular otherwise. This function will panic if t is not of // sufficient size. // // store describes the storage of the elementary reflectors in v. See // Dlarfb for a description of layout. // // tau contains the scalar factors of the elementary reflectors H_i. // // Dlarft is an internal routine. It is exported for testing purposes. func (Implementation) Dlarft(direct lapack.Direct, store lapack.StoreV, n, k int, v []float64, ldv int, tau []float64, t []float64, ldt int) { mv, nv := n, k if store == lapack.RowWise { mv, nv = k, n } switch { case direct != lapack.Forward && direct != lapack.Backward: panic(badDirect) case store != lapack.RowWise && store != lapack.ColumnWise: panic(badStoreV) case n < 0: panic(nLT0) case k < 1: panic(kLT1) case ldv < max(1, nv): panic(badLdV) case len(tau) < k: panic(shortTau) case ldt < max(1, k): panic(shortT) } if n == 0 { return } switch { case len(v) < (mv-1)*ldv+nv: panic(shortV) case len(t) < (k-1)*ldt+k: panic(shortT) } bi := blas64.Implementation() // TODO(btracey): There are a number of minor obvious loop optimizations here. // TODO(btracey): It may be possible to rearrange some of the code so that // index of 1 is more common in the Dgemv. if direct == lapack.Forward { prevlastv := n - 1 for i := 0; i < k; i++ { prevlastv = max(i, prevlastv) if tau[i] == 0 { for j := 0; j <= i; j++ { t[j*ldt+i] = 0 } continue } var lastv int if store == lapack.ColumnWise { // skip trailing zeros for lastv = n - 1; lastv >= i+1; lastv-- { if v[lastv*ldv+i] != 0 { break } } for j := 0; j < i; j++ { t[j*ldt+i] = -tau[i] * v[i*ldv+j] } j := min(lastv, prevlastv) bi.Dgemv(blas.Trans, j-i, i, -tau[i], v[(i+1)*ldv:], ldv, v[(i+1)*ldv+i:], ldv, 1, t[i:], ldt) } else { for lastv = n - 1; lastv >= i+1; lastv-- { if v[i*ldv+lastv] != 0 { break } } for j := 0; j < i; j++ { t[j*ldt+i] = -tau[i] * v[j*ldv+i] } j := min(lastv, prevlastv) bi.Dgemv(blas.NoTrans, i, j-i, -tau[i], v[i+1:], ldv, v[i*ldv+i+1:], 1, 1, t[i:], ldt) } bi.Dtrmv(blas.Upper, blas.NoTrans, blas.NonUnit, i, t, ldt, t[i:], ldt) t[i*ldt+i] = tau[i] if i > 1 { prevlastv = max(prevlastv, lastv) } else { prevlastv = lastv } } return } prevlastv := 0 for i := k - 1; i >= 0; i-- { if tau[i] == 0 { for j := i; j < k; j++ { t[j*ldt+i] = 0 } continue } var lastv int if i < k-1 { if store == lapack.ColumnWise { for lastv = 0; lastv < i; lastv++ { if v[lastv*ldv+i] != 0 { break } } for j := i + 1; j < k; j++ { t[j*ldt+i] = -tau[i] * v[(n-k+i)*ldv+j] } j := max(lastv, prevlastv) bi.Dgemv(blas.Trans, n-k+i-j, k-i-1, -tau[i], v[j*ldv+i+1:], ldv, v[j*ldv+i:], ldv, 1, t[(i+1)*ldt+i:], ldt) } else { for lastv = 0; lastv < i; lastv++ { if v[i*ldv+lastv] != 0 { break } } for j := i + 1; j < k; j++ { t[j*ldt+i] = -tau[i] * v[j*ldv+n-k+i] } j := max(lastv, prevlastv) bi.Dgemv(blas.NoTrans, k-i-1, n-k+i-j, -tau[i], v[(i+1)*ldv+j:], ldv, v[i*ldv+j:], 1, 1, t[(i+1)*ldt+i:], ldt) } bi.Dtrmv(blas.Lower, blas.NoTrans, blas.NonUnit, k-i-1, t[(i+1)*ldt+i+1:], ldt, t[(i+1)*ldt+i:], ldt) if i > 0 { prevlastv = min(prevlastv, lastv) } else { prevlastv = lastv } } t[i*ldt+i] = tau[i] } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlarfx.go000066400000000000000000000270071450372207100220330ustar00rootroot00000000000000// Copyright ©2016 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" // Dlarfx applies an elementary reflector H to a real m×n matrix C, from either // the left or the right, with loop unrolling when the reflector has order less // than 11. // // H is represented in the form // // H = I - tau * v * vᵀ, // // where tau is a real scalar and v is a real vector. If tau = 0, then H is // taken to be the identity matrix. // // v must have length equal to m if side == blas.Left, and equal to n if side == // blas.Right, otherwise Dlarfx will panic. // // c and ldc represent the m×n matrix C. On return, C is overwritten by the // matrix H * C if side == blas.Left, or C * H if side == blas.Right. // // work must have length at least n if side == blas.Left, and at least m if side // == blas.Right, otherwise Dlarfx will panic. work is not referenced if H has // order < 11. // // Dlarfx is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlarfx(side blas.Side, m, n int, v []float64, tau float64, c []float64, ldc int, work []float64) { switch { case side != blas.Left && side != blas.Right: panic(badSide) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case ldc < max(1, n): panic(badLdC) } // Quick return if possible. if m == 0 || n == 0 { return } nh := m lwork := n if side == blas.Right { nh = n lwork = m } switch { case len(v) < nh: panic(shortV) case len(c) < (m-1)*ldc+n: panic(shortC) case nh > 10 && len(work) < lwork: panic(shortWork) } if tau == 0 { return } if side == blas.Left { // Form H * C, where H has order m. switch m { default: // Code for general m. impl.Dlarf(side, m, n, v, 1, tau, c, ldc, work) return case 0: // No-op for zero size matrix. return case 1: // Special code for 1×1 Householder matrix. t0 := 1 - tau*v[0]*v[0] for j := 0; j < n; j++ { c[j] *= t0 } return case 2: // Special code for 2×2 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 } return case 3: // Special code for 3×3 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 } return case 4: // Special code for 4×4 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] + v3*c[3*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 c[3*ldc+j] -= sum * t3 } return case 5: // Special code for 5×5 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] + v3*c[3*ldc+j] + v4*c[4*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 c[3*ldc+j] -= sum * t3 c[4*ldc+j] -= sum * t4 } return case 6: // Special code for 6×6 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] + v3*c[3*ldc+j] + v4*c[4*ldc+j] + v5*c[5*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 c[3*ldc+j] -= sum * t3 c[4*ldc+j] -= sum * t4 c[5*ldc+j] -= sum * t5 } return case 7: // Special code for 7×7 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] + v3*c[3*ldc+j] + v4*c[4*ldc+j] + v5*c[5*ldc+j] + v6*c[6*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 c[3*ldc+j] -= sum * t3 c[4*ldc+j] -= sum * t4 c[5*ldc+j] -= sum * t5 c[6*ldc+j] -= sum * t6 } return case 8: // Special code for 8×8 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 v7 := v[7] t7 := tau * v7 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] + v3*c[3*ldc+j] + v4*c[4*ldc+j] + v5*c[5*ldc+j] + v6*c[6*ldc+j] + v7*c[7*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 c[3*ldc+j] -= sum * t3 c[4*ldc+j] -= sum * t4 c[5*ldc+j] -= sum * t5 c[6*ldc+j] -= sum * t6 c[7*ldc+j] -= sum * t7 } return case 9: // Special code for 9×9 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 v7 := v[7] t7 := tau * v7 v8 := v[8] t8 := tau * v8 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] + v3*c[3*ldc+j] + v4*c[4*ldc+j] + v5*c[5*ldc+j] + v6*c[6*ldc+j] + v7*c[7*ldc+j] + v8*c[8*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 c[3*ldc+j] -= sum * t3 c[4*ldc+j] -= sum * t4 c[5*ldc+j] -= sum * t5 c[6*ldc+j] -= sum * t6 c[7*ldc+j] -= sum * t7 c[8*ldc+j] -= sum * t8 } return case 10: // Special code for 10×10 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 v7 := v[7] t7 := tau * v7 v8 := v[8] t8 := tau * v8 v9 := v[9] t9 := tau * v9 for j := 0; j < n; j++ { sum := v0*c[j] + v1*c[ldc+j] + v2*c[2*ldc+j] + v3*c[3*ldc+j] + v4*c[4*ldc+j] + v5*c[5*ldc+j] + v6*c[6*ldc+j] + v7*c[7*ldc+j] + v8*c[8*ldc+j] + v9*c[9*ldc+j] c[j] -= sum * t0 c[ldc+j] -= sum * t1 c[2*ldc+j] -= sum * t2 c[3*ldc+j] -= sum * t3 c[4*ldc+j] -= sum * t4 c[5*ldc+j] -= sum * t5 c[6*ldc+j] -= sum * t6 c[7*ldc+j] -= sum * t7 c[8*ldc+j] -= sum * t8 c[9*ldc+j] -= sum * t9 } return } } // Form C * H, where H has order n. switch n { default: // Code for general n. impl.Dlarf(side, m, n, v, 1, tau, c, ldc, work) return case 0: // No-op for zero size matrix. return case 1: // Special code for 1×1 Householder matrix. t0 := 1 - tau*v[0]*v[0] for j := 0; j < m; j++ { c[j*ldc] *= t0 } return case 2: // Special code for 2×2 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] cs[0] -= sum * t0 cs[1] -= sum * t1 } return case 3: // Special code for 3×3 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 } return case 4: // Special code for 4×4 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] + v3*cs[3] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 cs[3] -= sum * t3 } return case 5: // Special code for 5×5 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] + v3*cs[3] + v4*cs[4] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 cs[3] -= sum * t3 cs[4] -= sum * t4 } return case 6: // Special code for 6×6 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] + v3*cs[3] + v4*cs[4] + v5*cs[5] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 cs[3] -= sum * t3 cs[4] -= sum * t4 cs[5] -= sum * t5 } return case 7: // Special code for 7×7 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] + v3*cs[3] + v4*cs[4] + v5*cs[5] + v6*cs[6] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 cs[3] -= sum * t3 cs[4] -= sum * t4 cs[5] -= sum * t5 cs[6] -= sum * t6 } return case 8: // Special code for 8×8 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 v7 := v[7] t7 := tau * v7 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] + v3*cs[3] + v4*cs[4] + v5*cs[5] + v6*cs[6] + v7*cs[7] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 cs[3] -= sum * t3 cs[4] -= sum * t4 cs[5] -= sum * t5 cs[6] -= sum * t6 cs[7] -= sum * t7 } return case 9: // Special code for 9×9 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 v7 := v[7] t7 := tau * v7 v8 := v[8] t8 := tau * v8 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] + v3*cs[3] + v4*cs[4] + v5*cs[5] + v6*cs[6] + v7*cs[7] + v8*cs[8] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 cs[3] -= sum * t3 cs[4] -= sum * t4 cs[5] -= sum * t5 cs[6] -= sum * t6 cs[7] -= sum * t7 cs[8] -= sum * t8 } return case 10: // Special code for 10×10 Householder matrix. v0 := v[0] t0 := tau * v0 v1 := v[1] t1 := tau * v1 v2 := v[2] t2 := tau * v2 v3 := v[3] t3 := tau * v3 v4 := v[4] t4 := tau * v4 v5 := v[5] t5 := tau * v5 v6 := v[6] t6 := tau * v6 v7 := v[7] t7 := tau * v7 v8 := v[8] t8 := tau * v8 v9 := v[9] t9 := tau * v9 for j := 0; j < m; j++ { cs := c[j*ldc:] sum := v0*cs[0] + v1*cs[1] + v2*cs[2] + v3*cs[3] + v4*cs[4] + v5*cs[5] + v6*cs[6] + v7*cs[7] + v8*cs[8] + v9*cs[9] cs[0] -= sum * t0 cs[1] -= sum * t1 cs[2] -= sum * t2 cs[3] -= sum * t3 cs[4] -= sum * t4 cs[5] -= sum * t5 cs[6] -= sum * t6 cs[7] -= sum * t7 cs[8] -= sum * t8 cs[9] -= sum * t9 } return } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlartg.go000066400000000000000000000032651450372207100220300ustar00rootroot00000000000000// 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" // Dlartg generates a plane rotation so that // // [ cs sn] * [f] = [r] // [-sn cs] [g] = [0] // // where cs*cs + sn*sn = 1. // // This is a more accurate version of BLAS Drotg that uses scaling to avoid // overflow or underflow, with the other differences that // - cs >= 0 // - if g = 0, then cs = 1 and sn = 0 // - if f = 0 and g != 0, then cs = 0 and sn = sign(1,g) // // Dlartg is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlartg(f, g float64) (cs, sn, r float64) { // Implementation based on Supplemental Material to: // // Edward Anderson // Algorithm 978: Safe Scaling in the Level 1 BLAS // ACM Trans. Math. Softw. 44, 1, Article 12 (2017) // DOI: https://doi.org/10.1145/3061665 // // For further details see: // // W. Pereira, A. Lotfi, J. Langou // Numerical analysis of Givens rotation // DOI: https://doi.org/10.48550/arXiv.2211.04010 if g == 0 { return 1, 0, f } g1 := math.Abs(g) if f == 0 { return 0, math.Copysign(1, g), g1 } const safmin = dlamchS const safmax = 1 / safmin rtmin := math.Sqrt(safmin) rtmax := math.Sqrt(safmax / 2) f1 := math.Abs(f) if rtmin < f1 && f1 < rtmax && rtmin < g1 && g1 < rtmax { d := math.Sqrt(f*f + g*g) cs = f1 / d r = math.Copysign(d, f) sn = g / r return cs, sn, r } u := math.Min(math.Max(safmin, math.Max(f1, g1)), safmax) fs := f / u gs := g / u d := math.Sqrt(fs*fs + gs*gs) cs = math.Abs(fs) / d r = math.Copysign(d, f) sn = gs / r r *= u return cs, sn, r } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlas2.go000066400000000000000000000022711450372207100215540ustar00rootroot00000000000000// 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" // Dlas2 computes the singular values of the 2×2 matrix defined by // // [F G] // [0 H] // // The smaller and larger singular values are returned in that order. // // Dlas2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlas2(f, g, h float64) (ssmin, ssmax float64) { fa := math.Abs(f) ga := math.Abs(g) ha := math.Abs(h) fhmin := math.Min(fa, ha) fhmax := math.Max(fa, ha) if fhmin == 0 { if fhmax == 0 { return 0, ga } v := math.Min(fhmax, ga) / math.Max(fhmax, ga) return 0, math.Max(fhmax, ga) * math.Sqrt(1+v*v) } if ga < fhmax { as := 1 + fhmin/fhmax at := (fhmax - fhmin) / fhmax au := (ga / fhmax) * (ga / fhmax) c := 2 / (math.Sqrt(as*as+au) + math.Sqrt(at*at+au)) return fhmin * c, fhmax / c } au := fhmax / ga if au == 0 { return fhmin * fhmax / ga, ga } as := 1 + fhmin/fhmax at := (fhmax - fhmin) / fhmax c := 1 / (math.Sqrt(1+(as*au)*(as*au)) + math.Sqrt(1+(at*au)*(at*au))) return 2 * (fhmin * c) * au, ga / (c + c) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlascl.go000066400000000000000000000043101450372207100220050ustar00rootroot00000000000000// 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/lapack" ) // Dlascl multiplies an m×n matrix by the scalar cto/cfrom. // // cfrom must not be zero, and cto and cfrom must not be NaN, otherwise Dlascl // will panic. // // Dlascl is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlascl(kind lapack.MatrixType, kl, ku int, cfrom, cto float64, m, n int, a []float64, lda int) { switch kind { default: panic(badMatrixType) case 'H', 'B', 'Q', 'Z': // See dlascl.f. panic("not implemented") case lapack.General, lapack.UpperTri, lapack.LowerTri: if lda < max(1, n) { panic(badLdA) } } switch { case cfrom == 0: panic(zeroCFrom) case math.IsNaN(cfrom): panic(nanCFrom) case math.IsNaN(cto): panic(nanCTo) case m < 0: panic(mLT0) case n < 0: panic(nLT0) } if n == 0 || m == 0 { return } switch kind { case lapack.General, lapack.UpperTri, lapack.LowerTri: if len(a) < (m-1)*lda+n { panic(shortA) } } smlnum := dlamchS bignum := 1 / smlnum cfromc := cfrom ctoc := cto cfrom1 := cfromc * smlnum for { var done bool var mul, ctol float64 if cfrom1 == cfromc { // cfromc is inf. mul = ctoc / cfromc done = true ctol = ctoc } else { ctol = ctoc / bignum if ctol == ctoc { // ctoc is either 0 or inf. mul = ctoc done = true cfromc = 1 } else if math.Abs(cfrom1) > math.Abs(ctoc) && ctoc != 0 { mul = smlnum done = false cfromc = cfrom1 } else if math.Abs(ctol) > math.Abs(cfromc) { mul = bignum done = false ctoc = ctol } else { mul = ctoc / cfromc done = true } } switch kind { case lapack.General: for i := 0; i < m; i++ { for j := 0; j < n; j++ { a[i*lda+j] = a[i*lda+j] * mul } } case lapack.UpperTri: for i := 0; i < m; i++ { for j := i; j < n; j++ { a[i*lda+j] = a[i*lda+j] * mul } } case lapack.LowerTri: for i := 0; i < m; i++ { for j := 0; j <= min(i, n-1); j++ { a[i*lda+j] = a[i*lda+j] * mul } } } if done { break } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaset.go000066400000000000000000000024321450372207100220220ustar00rootroot00000000000000// 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/blas" // Dlaset sets the off-diagonal elements of A to alpha, and the diagonal // elements to beta. If uplo == blas.Upper, only the elements in the upper // triangular part are set. If uplo == blas.Lower, only the elements in the // lower triangular part are set. If uplo is otherwise, all of the elements of A // are set. // // Dlaset is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaset(uplo blas.Uplo, m, n int, alpha, beta float64, a []float64, lda int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } minmn := min(m, n) if minmn == 0 { return } if len(a) < (m-1)*lda+n { panic(shortA) } switch uplo { case blas.Upper: for i := 0; i < m; i++ { for j := i + 1; j < n; j++ { a[i*lda+j] = alpha } } case blas.Lower: for i := 0; i < m; i++ { for j := 0; j < min(i, n); j++ { a[i*lda+j] = alpha } } default: for i := 0; i < m; i++ { for j := 0; j < n; j++ { a[i*lda+j] = alpha } } } for i := 0; i < minmn; i++ { a[i*lda+i] = beta } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasq1.go000066400000000000000000000047101450372207100217340ustar00rootroot00000000000000// 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/blas64" "gonum.org/v1/gonum/lapack" ) // Dlasq1 computes the singular values of an n×n bidiagonal matrix with diagonal // d and off-diagonal e. On exit, d contains the singular values in decreasing // order, and e is overwritten. d must have length at least n, e must have // length at least n-1, and the input work must have length at least 4*n. Dlasq1 // will panic if these conditions are not met. // // Dlasq1 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasq1(n int, d, e, work []float64) (info int) { if n < 0 { panic(nLT0) } if n == 0 { return info } switch { case len(d) < n: panic(shortD) case len(e) < n-1: panic(shortE) case len(work) < 4*n: panic(shortWork) } if n == 1 { d[0] = math.Abs(d[0]) return info } if n == 2 { d[1], d[0] = impl.Dlas2(d[0], e[0], d[1]) return info } // Estimate the largest singular value. var sigmx float64 for i := 0; i < n-1; i++ { d[i] = math.Abs(d[i]) sigmx = math.Max(sigmx, math.Abs(e[i])) } d[n-1] = math.Abs(d[n-1]) // Early return if sigmx is zero (matrix is already diagonal). if sigmx == 0 { impl.Dlasrt(lapack.SortDecreasing, n, d) return info } for i := 0; i < n; i++ { sigmx = math.Max(sigmx, d[i]) } // Copy D and E into WORK (in the Z format) and scale (squaring the // input data makes scaling by a power of the radix pointless). eps := dlamchP safmin := dlamchS scale := math.Sqrt(eps / safmin) bi := blas64.Implementation() bi.Dcopy(n, d, 1, work, 2) bi.Dcopy(n-1, e, 1, work[1:], 2) impl.Dlascl(lapack.General, 0, 0, sigmx, scale, 2*n-1, 1, work, 1) // Compute the q's and e's. for i := 0; i < 2*n-1; i++ { work[i] *= work[i] } work[2*n-1] = 0 info = impl.Dlasq2(n, work) if info == 0 { for i := 0; i < n; i++ { d[i] = math.Sqrt(work[i]) } impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, d, 1) } else if info == 2 { // Maximum number of iterations exceeded. Move data from work // into D and E so the calling subroutine can try to finish. for i := 0; i < n; i++ { d[i] = math.Sqrt(work[2*i]) e[i] = math.Sqrt(work[2*i+1]) } impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, d, 1) impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, e, 1) } return info } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasq2.go000066400000000000000000000222421450372207100217350ustar00rootroot00000000000000// 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/lapack" ) // Dlasq2 computes all the eigenvalues of the symmetric positive // definite tridiagonal matrix associated with the qd array Z. Eigevalues // are computed to high relative accuracy avoiding denormalization, underflow // and overflow. // // To see the relation of Z to the tridiagonal matrix, let L be a // unit lower bidiagonal matrix with sub-diagonals Z(2,4,6,,..) and // let U be an upper bidiagonal matrix with 1's above and diagonal // Z(1,3,5,,..). The tridiagonal is L*U or, if you prefer, the // symmetric tridiagonal to which it is similar. // // info returns a status error. The return codes mean as follows: // // 0: The algorithm completed successfully. // 1: A split was marked by a positive value in e. // 2: Current block of Z not diagonalized after 100*n iterations (in inner // while loop). On exit Z holds a qd array with the same eigenvalues as // the given Z. // 3: Termination criterion of outer while loop not met (program created more // than N unreduced blocks). // // z must have length at least 4*n, and must not contain any negative elements. // Dlasq2 will panic otherwise. // // Dlasq2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasq2(n int, z []float64) (info int) { if n < 0 { panic(nLT0) } if n == 0 { return info } if len(z) < 4*n { panic(shortZ) } if n == 1 { if z[0] < 0 { panic(negZ) } return info } const cbias = 1.5 eps := dlamchP safmin := dlamchS tol := eps * 100 tol2 := tol * tol if n == 2 { if z[1] < 0 || z[2] < 0 { panic(negZ) } else if z[2] > z[0] { z[0], z[2] = z[2], z[0] } z[4] = z[0] + z[1] + z[2] if z[1] > z[2]*tol2 { t := 0.5 * (z[0] - z[2] + z[1]) s := z[2] * (z[1] / t) if s <= t { s = z[2] * (z[1] / (t * (1 + math.Sqrt(1+s/t)))) } else { s = z[2] * (z[1] / (t + math.Sqrt(t)*math.Sqrt(t+s))) } t = z[0] + s + z[1] z[2] *= z[0] / t z[0] = t } z[1] = z[2] z[5] = z[1] + z[0] return info } // Check for negative data and compute sums of q's and e's. z[2*n-1] = 0 emin := z[1] var d, e, qmax float64 var i1, n1 int for k := 0; k < 2*(n-1); k += 2 { if z[k] < 0 || z[k+1] < 0 { panic(negZ) } d += z[k] e += z[k+1] qmax = math.Max(qmax, z[k]) emin = math.Min(emin, z[k+1]) } if z[2*(n-1)] < 0 { panic(negZ) } d += z[2*(n-1)] // Check for diagonality. if e == 0 { for k := 1; k < n; k++ { z[k] = z[2*k] } impl.Dlasrt(lapack.SortDecreasing, n, z) z[2*(n-1)] = d return info } trace := d + e // Check for zero data. if trace == 0 { z[2*(n-1)] = 0 return info } // Rearrange data for locality: Z=(q1,qq1,e1,ee1,q2,qq2,e2,ee2,...). for k := 2 * n; k >= 2; k -= 2 { z[2*k-1] = 0 z[2*k-2] = z[k-1] z[2*k-3] = 0 z[2*k-4] = z[k-2] } i0 := 0 n0 := n - 1 // Reverse the qd-array, if warranted. // z[4*i0-3] --> z[4*(i0+1)-3-1] --> z[4*i0] if cbias*z[4*i0] < z[4*n0] { ipn4Out := 4 * (i0 + n0 + 2) for i4loop := 4 * (i0 + 1); i4loop <= 2*(i0+n0+1); i4loop += 4 { i4 := i4loop - 1 ipn4 := ipn4Out - 1 z[i4-3], z[ipn4-i4-4] = z[ipn4-i4-4], z[i4-3] z[i4-1], z[ipn4-i4-6] = z[ipn4-i4-6], z[i4-1] } } // Initial split checking via dqd and Li's test. pp := 0 for k := 0; k < 2; k++ { d = z[4*n0+pp] for i4loop := 4*n0 + pp; i4loop >= 4*(i0+1)+pp; i4loop -= 4 { i4 := i4loop - 1 if z[i4-1] <= tol2*d { z[i4-1] = math.Copysign(0, -1) d = z[i4-3] } else { d = z[i4-3] * (d / (d + z[i4-1])) } } // dqd maps Z to ZZ plus Li's test. emin = z[4*(i0+1)+pp] d = z[4*i0+pp] for i4loop := 4*(i0+1) + pp; i4loop <= 4*n0+pp; i4loop += 4 { i4 := i4loop - 1 z[i4-2*pp-2] = d + z[i4-1] if z[i4-1] <= tol2*d { z[i4-1] = math.Copysign(0, -1) z[i4-2*pp-2] = d z[i4-2*pp] = 0 d = z[i4+1] } else if safmin*z[i4+1] < z[i4-2*pp-2] && safmin*z[i4-2*pp-2] < z[i4+1] { tmp := z[i4+1] / z[i4-2*pp-2] z[i4-2*pp] = z[i4-1] * tmp d *= tmp } else { z[i4-2*pp] = z[i4+1] * (z[i4-1] / z[i4-2*pp-2]) d = z[i4+1] * (d / z[i4-2*pp-2]) } emin = math.Min(emin, z[i4-2*pp]) } z[4*(n0+1)-pp-3] = d // Now find qmax. qmax = z[4*(i0+1)-pp-3] for i4loop := 4*(i0+1) - pp + 2; i4loop <= 4*(n0+1)+pp-2; i4loop += 4 { i4 := i4loop - 1 qmax = math.Max(qmax, z[i4]) } // Prepare for the next iteration on K. pp = 1 - pp } // Initialise variables to pass to DLASQ3. var ttype int var dmin1, dmin2, dn, dn1, dn2, g, tau float64 var tempq float64 iter := 2 var nFail int nDiv := 2 * (n0 - i0) var i4 int outer: for iwhila := 1; iwhila <= n+1; iwhila++ { // Test for completion. if n0 < 0 { // Move q's to the front. for k := 1; k < n; k++ { z[k] = z[4*k] } // Sort and compute sum of eigenvalues. impl.Dlasrt(lapack.SortDecreasing, n, z) e = 0 for k := n - 1; k >= 0; k-- { e += z[k] } // Store trace, sum(eigenvalues) and information on performance. z[2*n] = trace z[2*n+1] = e z[2*n+2] = float64(iter) z[2*n+3] = float64(nDiv) / float64(n*n) z[2*n+4] = 100 * float64(nFail) / float64(iter) return info } // While array unfinished do // e[n0] holds the value of sigma when submatrix in i0:n0 // splits from the rest of the array, but is negated. var desig float64 var sigma float64 if n0 != n-1 { sigma = -z[4*(n0+1)-2] } if sigma < 0 { info = 1 return info } // Find last unreduced submatrix's top index i0, find qmax and // emin. Find Gershgorin-type bound if Q's much greater than E's. var emax float64 if n0 > i0 { emin = math.Abs(z[4*(n0+1)-6]) } else { emin = 0 } qmin := z[4*(n0+1)-4] qmax = qmin zSmall := false for i4loop := 4 * (n0 + 1); i4loop >= 8; i4loop -= 4 { i4 = i4loop - 1 if z[i4-5] <= 0 { zSmall = true break } if qmin >= 4*emax { qmin = math.Min(qmin, z[i4-3]) emax = math.Max(emax, z[i4-5]) } qmax = math.Max(qmax, z[i4-7]+z[i4-5]) emin = math.Min(emin, z[i4-5]) } if !zSmall { i4 = 3 } i0 = (i4+1)/4 - 1 pp = 0 if n0-i0 > 1 { dee := z[4*i0] deemin := dee kmin := i0 for i4loop := 4*(i0+1) + 1; i4loop <= 4*(n0+1)-3; i4loop += 4 { i4 := i4loop - 1 dee = z[i4] * (dee / (dee + z[i4-2])) if dee <= deemin { deemin = dee kmin = (i4+4)/4 - 1 } } if (kmin-i0)*2 < n0-kmin && deemin <= 0.5*z[4*n0] { ipn4Out := 4 * (i0 + n0 + 2) pp = 2 for i4loop := 4 * (i0 + 1); i4loop <= 2*(i0+n0+1); i4loop += 4 { i4 := i4loop - 1 ipn4 := ipn4Out - 1 z[i4-3], z[ipn4-i4-4] = z[ipn4-i4-4], z[i4-3] z[i4-2], z[ipn4-i4-3] = z[ipn4-i4-3], z[i4-2] z[i4-1], z[ipn4-i4-6] = z[ipn4-i4-6], z[i4-1] z[i4], z[ipn4-i4-5] = z[ipn4-i4-5], z[i4] } } } // Put -(initial shift) into DMIN. dmin := -math.Max(0, qmin-2*math.Sqrt(qmin)*math.Sqrt(emax)) // Now i0:n0 is unreduced. // PP = 0 for ping, PP = 1 for pong. // PP = 2 indicates that flipping was applied to the Z array and // that the tests for deflation upon entry in Dlasq3 should // not be performed. nbig := 100 * (n0 - i0 + 1) for iwhilb := 0; iwhilb < nbig; iwhilb++ { if i0 > n0 { continue outer } // While submatrix unfinished take a good dqds step. i0, n0, pp, dmin, sigma, desig, qmax, nFail, iter, nDiv, ttype, dmin1, dmin2, dn, dn1, dn2, g, tau = impl.Dlasq3(i0, n0, z, pp, dmin, sigma, desig, qmax, nFail, iter, nDiv, ttype, dmin1, dmin2, dn, dn1, dn2, g, tau) pp = 1 - pp // When emin is very small check for splits. if pp == 0 && n0-i0 >= 3 { if z[4*(n0+1)-1] <= tol2*qmax || z[4*(n0+1)-2] <= tol2*sigma { splt := i0 - 1 qmax = z[4*i0] emin = z[4*(i0+1)-2] oldemn := z[4*(i0+1)-1] for i4loop := 4 * (i0 + 1); i4loop <= 4*(n0-2); i4loop += 4 { i4 := i4loop - 1 if z[i4] <= tol2*z[i4-3] || z[i4-1] <= tol2*sigma { z[i4-1] = -sigma splt = i4 / 4 qmax = 0 emin = z[i4+3] oldemn = z[i4+4] } else { qmax = math.Max(qmax, z[i4+1]) emin = math.Min(emin, z[i4-1]) oldemn = math.Min(oldemn, z[i4]) } } z[4*(n0+1)-2] = emin z[4*(n0+1)-1] = oldemn i0 = splt + 1 } } } // Maximum number of iterations exceeded, restore the shift // sigma and place the new d's and e's in a qd array. // This might need to be done for several blocks. info = 2 i1 = i0 for { tempq = z[4*i0] z[4*i0] += sigma for k := i0 + 1; k <= n0; k++ { tempe := z[4*(k+1)-6] z[4*(k+1)-6] *= tempq / z[4*(k+1)-8] tempq = z[4*k] z[4*k] += sigma + tempe - z[4*(k+1)-6] } // Prepare to do this on the previous block if there is one. if i1 <= 0 { break } n1 = i1 - 1 for i1 >= 1 && z[4*(i1+1)-6] >= 0 { i1 -= 1 } sigma = -z[4*(n1+1)-2] } for k := 0; k < n; k++ { z[2*k] = z[4*k] // Only the block 1..N0 is unfinished. The rest of the e's // must be essentially zero, although sometimes other data // has been stored in them. if k < n0 { z[2*(k+1)-1] = z[4*(k+1)-1] } else { z[2*(k+1)] = 0 } } return info } info = 3 return info } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasq3.go000066400000000000000000000107611450372207100217410ustar00rootroot00000000000000// 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" // Dlasq3 checks for deflation, computes a shift (tau) and calls dqds. // In case of failure it changes shifts, and tries again until output // is positive. // // Dlasq3 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasq3(i0, n0 int, z []float64, pp int, dmin, sigma, desig, qmax float64, nFail, iter, nDiv int, ttype int, dmin1, dmin2, dn, dn1, dn2, g, tau float64) ( i0Out, n0Out, ppOut int, dminOut, sigmaOut, desigOut, qmaxOut float64, nFailOut, iterOut, nDivOut, ttypeOut int, dmin1Out, dmin2Out, dnOut, dn1Out, dn2Out, gOut, tauOut float64) { switch { case i0 < 0: panic(i0LT0) case n0 < 0: panic(n0LT0) case len(z) < 4*n0: panic(shortZ) case pp != 0 && pp != 1 && pp != 2: panic(badPp) } const cbias = 1.5 n0in := n0 eps := dlamchP tol := eps * 100 tol2 := tol * tol var nn int var t float64 for { if n0 < i0 { return i0, n0, pp, dmin, sigma, desig, qmax, nFail, iter, nDiv, ttype, dmin1, dmin2, dn, dn1, dn2, g, tau } if n0 == i0 { z[4*(n0+1)-4] = z[4*(n0+1)+pp-4] + sigma n0-- continue } nn = 4*(n0+1) + pp - 1 if n0 != i0+1 { // Check whether e[n0-1] is negligible, 1 eigenvalue. if z[nn-5] > tol2*(sigma+z[nn-3]) && z[nn-2*pp-4] > tol2*z[nn-7] { // Check whether e[n0-2] is negligible, 2 eigenvalues. if z[nn-9] > tol2*sigma && z[nn-2*pp-8] > tol2*z[nn-11] { break } } else { z[4*(n0+1)-4] = z[4*(n0+1)+pp-4] + sigma n0-- continue } } if z[nn-3] > z[nn-7] { z[nn-3], z[nn-7] = z[nn-7], z[nn-3] } t = 0.5 * (z[nn-7] - z[nn-3] + z[nn-5]) if z[nn-5] > z[nn-3]*tol2 && t != 0 { s := z[nn-3] * (z[nn-5] / t) if s <= t { s = z[nn-3] * (z[nn-5] / (t * (1 + math.Sqrt(1+s/t)))) } else { s = z[nn-3] * (z[nn-5] / (t + math.Sqrt(t)*math.Sqrt(t+s))) } t = z[nn-7] + (s + z[nn-5]) z[nn-3] *= z[nn-7] / t z[nn-7] = t } z[4*(n0+1)-8] = z[nn-7] + sigma z[4*(n0+1)-4] = z[nn-3] + sigma n0 -= 2 } if pp == 2 { pp = 0 } // Reverse the qd-array, if warranted. if dmin <= 0 || n0 < n0in { if cbias*z[4*(i0+1)+pp-4] < z[4*(n0+1)+pp-4] { ipn4Out := 4 * (i0 + n0 + 2) for j4loop := 4 * (i0 + 1); j4loop <= 2*((i0+1)+(n0+1)-1); j4loop += 4 { ipn4 := ipn4Out - 1 j4 := j4loop - 1 z[j4-3], z[ipn4-j4-4] = z[ipn4-j4-4], z[j4-3] z[j4-2], z[ipn4-j4-3] = z[ipn4-j4-3], z[j4-2] z[j4-1], z[ipn4-j4-6] = z[ipn4-j4-6], z[j4-1] z[j4], z[ipn4-j4-5] = z[ipn4-j4-5], z[j4] } if n0-i0 <= 4 { z[4*(n0+1)+pp-2] = z[4*(i0+1)+pp-2] z[4*(n0+1)-pp-1] = z[4*(i0+1)-pp-1] } dmin2 = math.Min(dmin2, z[4*(i0+1)-pp-2]) z[4*(n0+1)+pp-2] = math.Min(math.Min(z[4*(n0+1)+pp-2], z[4*(i0+1)+pp-2]), z[4*(i0+1)+pp+2]) z[4*(n0+1)-pp-1] = math.Min(math.Min(z[4*(n0+1)-pp-1], z[4*(i0+1)-pp-1]), z[4*(i0+1)-pp+3]) qmax = math.Max(math.Max(qmax, z[4*(i0+1)+pp-4]), z[4*(i0+1)+pp]) dmin = math.Copysign(0, -1) // Fortran code has -zero, but -0 in go is 0 } } // Choose a shift. tau, ttype, g = impl.Dlasq4(i0, n0, z, pp, n0in, dmin, dmin1, dmin2, dn, dn1, dn2, tau, ttype, g) // Call dqds until dmin > 0. loop: for { i0, n0, pp, tau, sigma, dmin, dmin1, dmin2, dn, dn1, dn2 = impl.Dlasq5(i0, n0, z, pp, tau, sigma) nDiv += n0 - i0 + 2 iter++ switch { case dmin >= 0 && dmin1 >= 0: // Success. goto done case dmin < 0 && dmin1 > 0 && z[4*n0-pp-1] < tol*(sigma+dn1) && math.Abs(dn) < tol*sigma: // Convergence hidden by negative dn. z[4*n0-pp+1] = 0 dmin = 0 goto done case dmin < 0: // Tau too big. Select new Tau and try again. nFail++ if ttype < -22 { // Failed twice. Play it safe. tau = 0 } else if dmin1 > 0 { // Late failure. Gives excellent shift. tau = (tau + dmin) * (1 - 2*eps) ttype -= 11 } else { // Early failure. Divide by 4. tau = tau / 4 ttype -= 12 } case math.IsNaN(dmin): if tau == 0 { break loop } tau = 0 default: // Possible underflow. Play it safe. break loop } } // Risk of underflow. dmin, dmin1, dmin2, dn, dn1, dn2 = impl.Dlasq6(i0, n0, z, pp) nDiv += n0 - i0 + 2 iter++ tau = 0 done: if tau < sigma { desig += tau t = sigma + desig desig -= t - sigma } else { t = sigma + tau desig += sigma - (t - tau) } sigma = t return i0, n0, pp, dmin, sigma, desig, qmax, nFail, iter, nDiv, ttype, dmin1, dmin2, dn, dn1, dn2, g, tau } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasq4.go000066400000000000000000000132601450372207100217370ustar00rootroot00000000000000// 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" // Dlasq4 computes an approximation to the smallest eigenvalue using values of d // from the previous transform. // i0, n0, and n0in are zero-indexed. // // Dlasq4 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasq4(i0, n0 int, z []float64, pp int, n0in int, dmin, dmin1, dmin2, dn, dn1, dn2, tau float64, ttype int, g float64) (tauOut float64, ttypeOut int, gOut float64) { switch { case i0 < 0: panic(i0LT0) case n0 < 0: panic(n0LT0) case len(z) < 4*n0: panic(shortZ) case pp != 0 && pp != 1: panic(badPp) } const ( cnst1 = 0.563 cnst2 = 1.01 cnst3 = 1.05 cnstthird = 0.333 // TODO(btracey): Fix? ) // A negative dmin forces the shift to take that absolute value // ttype records the type of shift. if dmin <= 0 { tau = -dmin ttype = -1 return tau, ttype, g } nn := 4*(n0+1) + pp - 1 // -1 for zero indexing s := math.NaN() // Poison s so that failure to take a path below is obvious if n0in == n0 { // No eigenvalues deflated. if dmin == dn || dmin == dn1 { b1 := math.Sqrt(z[nn-3]) * math.Sqrt(z[nn-5]) b2 := math.Sqrt(z[nn-7]) * math.Sqrt(z[nn-9]) a2 := z[nn-7] + z[nn-5] if dmin == dn && dmin1 == dn1 { gap2 := dmin2 - a2 - dmin2/4 var gap1 float64 if gap2 > 0 && gap2 > b2 { gap1 = a2 - dn - (b2/gap2)*b2 } else { gap1 = a2 - dn - (b1 + b2) } if gap1 > 0 && gap1 > b1 { s = math.Max(dn-(b1/gap1)*b1, 0.5*dmin) ttype = -2 } else { s = 0 if dn > b1 { s = dn - b1 } if a2 > b1+b2 { s = math.Min(s, a2-(b1+b2)) } s = math.Max(s, cnstthird*dmin) ttype = -3 } } else { ttype = -4 s = dmin / 4 var gam float64 var np int if dmin == dn { gam = dn a2 = 0 if z[nn-5] > z[nn-7] { return tau, ttype, g } b2 = z[nn-5] / z[nn-7] np = nn - 9 } else { np = nn - 2*pp gam = dn1 if z[np-4] > z[np-2] { return tau, ttype, g } a2 = z[np-4] / z[np-2] if z[nn-9] > z[nn-11] { return tau, ttype, g } b2 = z[nn-9] / z[nn-11] np = nn - 13 } // Approximate contribution to norm squared from i < nn-1. a2 += b2 for i4loop := np + 1; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 { i4 := i4loop - 1 if b2 == 0 { break } b1 = b2 if z[i4] > z[i4-2] { return tau, ttype, g } b2 *= z[i4] / z[i4-2] a2 += b2 if 100*math.Max(b2, b1) < a2 || cnst1 < a2 { break } } a2 *= cnst3 // Rayleigh quotient residual bound. if a2 < cnst1 { s = gam * (1 - math.Sqrt(a2)) / (1 + a2) } } } else if dmin == dn2 { ttype = -5 s = dmin / 4 // Compute contribution to norm squared from i > nn-2. np := nn - 2*pp b1 := z[np-2] b2 := z[np-6] gam := dn2 if z[np-8] > b2 || z[np-4] > b1 { return tau, ttype, g } a2 := (z[np-8] / b2) * (1 + z[np-4]/b1) // Approximate contribution to norm squared from i < nn-2. if n0-i0 > 2 { b2 = z[nn-13] / z[nn-15] a2 += b2 for i4loop := (nn + 1) - 17; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 { i4 := i4loop - 1 if b2 == 0 { break } b1 = b2 if z[i4] > z[i4-2] { return tau, ttype, g } b2 *= z[i4] / z[i4-2] a2 += b2 if 100*math.Max(b2, b1) < a2 || cnst1 < a2 { break } } a2 *= cnst3 } if a2 < cnst1 { s = gam * (1 - math.Sqrt(a2)) / (1 + a2) } } else { // Case 6, no information to guide us. if ttype == -6 { g += cnstthird * (1 - g) } else if ttype == -18 { g = cnstthird / 4 } else { g = 1.0 / 4 } s = g * dmin ttype = -6 } } else if n0in == (n0 + 1) { // One eigenvalue just deflated. Use DMIN1, DN1 for DMIN and DN. if dmin1 == dn1 && dmin2 == dn2 { ttype = -7 s = cnstthird * dmin1 if z[nn-5] > z[nn-7] { return tau, ttype, g } b1 := z[nn-5] / z[nn-7] b2 := b1 if b2 != 0 { for i4loop := 4*(n0+1) - 9 + pp; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 { i4 := i4loop - 1 a2 := b1 if z[i4] > z[i4-2] { return tau, ttype, g } b1 *= z[i4] / z[i4-2] b2 += b1 if 100*math.Max(b1, a2) < b2 { break } } } b2 = math.Sqrt(cnst3 * b2) a2 := dmin1 / (1 + b2*b2) gap2 := 0.5*dmin2 - a2 if gap2 > 0 && gap2 > b2*a2 { s = math.Max(s, a2*(1-cnst2*a2*(b2/gap2)*b2)) } else { s = math.Max(s, a2*(1-cnst2*b2)) ttype = -8 } } else { s = dmin1 / 4 if dmin1 == dn1 { s = 0.5 * dmin1 } ttype = -9 } } else if n0in == (n0 + 2) { // Two eigenvalues deflated. Use DMIN2, DN2 for DMIN and DN. if dmin2 == dn2 && 2*z[nn-5] < z[nn-7] { ttype = -10 s = cnstthird * dmin2 if z[nn-5] > z[nn-7] { return tau, ttype, g } b1 := z[nn-5] / z[nn-7] b2 := b1 if b2 != 0 { for i4loop := 4*(n0+1) - 9 + pp; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 { i4 := i4loop - 1 if z[i4] > z[i4-2] { return tau, ttype, g } b1 *= z[i4] / z[i4-2] b2 += b1 if 100*b1 < b2 { break } } } b2 = math.Sqrt(cnst3 * b2) a2 := dmin2 / (1 + b2*b2) gap2 := z[nn-7] + z[nn-9] - math.Sqrt(z[nn-11])*math.Sqrt(z[nn-9]) - a2 if gap2 > 0 && gap2 > b2*a2 { s = math.Max(s, a2*(1-cnst2*a2*(b2/gap2)*b2)) } else { s = math.Max(s, a2*(1-cnst2*b2)) } } else { s = dmin2 / 4 ttype = -11 } } else if n0in > n0+2 { // Case 12, more than two eigenvalues deflated. No information. s = 0 ttype = -12 } tau = s return tau, ttype, g } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasq5.go000066400000000000000000000067601450372207100217470ustar00rootroot00000000000000// 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" // Dlasq5 computes one dqds transform in ping-pong form. // i0 and n0 are zero-indexed. // // Dlasq5 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasq5(i0, n0 int, z []float64, pp int, tau, sigma float64) (i0Out, n0Out, ppOut int, tauOut, sigmaOut, dmin, dmin1, dmin2, dn, dnm1, dnm2 float64) { // The lapack function has inputs for ieee and eps, but Go requires ieee so // these are unnecessary. switch { case i0 < 0: panic(i0LT0) case n0 < 0: panic(n0LT0) case len(z) < 4*n0: panic(shortZ) case pp != 0 && pp != 1: panic(badPp) } if n0-i0-1 <= 0 { return i0, n0, pp, tau, sigma, dmin, dmin1, dmin2, dn, dnm1, dnm2 } eps := dlamchP dthresh := eps * (sigma + tau) if tau < dthresh*0.5 { tau = 0 } var j4 int var emin float64 if tau != 0 { j4 = 4*i0 + pp emin = z[j4+4] d := z[j4] - tau dmin = d // In the reference there are code paths that actually return this value. // dmin1 = -z[j4] if pp == 0 { for j4loop := 4 * (i0 + 1); j4loop <= 4*((n0+1)-3); j4loop += 4 { j4 := j4loop - 1 z[j4-2] = d + z[j4-1] tmp := z[j4+1] / z[j4-2] d = d*tmp - tau dmin = math.Min(dmin, d) z[j4] = z[j4-1] * tmp emin = math.Min(z[j4], emin) } } else { for j4loop := 4 * (i0 + 1); j4loop <= 4*((n0+1)-3); j4loop += 4 { j4 := j4loop - 1 z[j4-3] = d + z[j4] tmp := z[j4+2] / z[j4-3] d = d*tmp - tau dmin = math.Min(dmin, d) z[j4-1] = z[j4] * tmp emin = math.Min(z[j4-1], emin) } } // Unroll the last two steps. dnm2 = d dmin2 = dmin j4 = 4*((n0+1)-2) - pp - 1 j4p2 := j4 + 2*pp - 1 z[j4-2] = dnm2 + z[j4p2] z[j4] = z[j4p2+2] * (z[j4p2] / z[j4-2]) dnm1 = z[j4p2+2]*(dnm2/z[j4-2]) - tau dmin = math.Min(dmin, dnm1) dmin1 = dmin j4 += 4 j4p2 = j4 + 2*pp - 1 z[j4-2] = dnm1 + z[j4p2] z[j4] = z[j4p2+2] * (z[j4p2] / z[j4-2]) dn = z[j4p2+2]*(dnm1/z[j4-2]) - tau dmin = math.Min(dmin, dn) } else { // This is the version that sets d's to zero if they are small enough. j4 = 4*(i0+1) + pp - 4 emin = z[j4+4] d := z[j4] - tau dmin = d // In the reference there are code paths that actually return this value. // dmin1 = -z[j4] if pp == 0 { for j4loop := 4 * (i0 + 1); j4loop <= 4*((n0+1)-3); j4loop += 4 { j4 := j4loop - 1 z[j4-2] = d + z[j4-1] tmp := z[j4+1] / z[j4-2] d = d*tmp - tau if d < dthresh { d = 0 } dmin = math.Min(dmin, d) z[j4] = z[j4-1] * tmp emin = math.Min(z[j4], emin) } } else { for j4loop := 4 * (i0 + 1); j4loop <= 4*((n0+1)-3); j4loop += 4 { j4 := j4loop - 1 z[j4-3] = d + z[j4] tmp := z[j4+2] / z[j4-3] d = d*tmp - tau if d < dthresh { d = 0 } dmin = math.Min(dmin, d) z[j4-1] = z[j4] * tmp emin = math.Min(z[j4-1], emin) } } // Unroll the last two steps. dnm2 = d dmin2 = dmin j4 = 4*((n0+1)-2) - pp - 1 j4p2 := j4 + 2*pp - 1 z[j4-2] = dnm2 + z[j4p2] z[j4] = z[j4p2+2] * (z[j4p2] / z[j4-2]) dnm1 = z[j4p2+2]*(dnm2/z[j4-2]) - tau dmin = math.Min(dmin, dnm1) dmin1 = dmin j4 += 4 j4p2 = j4 + 2*pp - 1 z[j4-2] = dnm1 + z[j4p2] z[j4] = z[j4p2+2] * (z[j4p2] / z[j4-2]) dn = z[j4p2+2]*(dnm1/z[j4-2]) - tau dmin = math.Min(dmin, dn) } z[j4+2] = dn z[4*(n0+1)-pp-1] = emin return i0, n0, pp, tau, sigma, dmin, dmin1, dmin2, dn, dnm1, dnm2 } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasq6.go000066400000000000000000000055631450372207100217500ustar00rootroot00000000000000// 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" // Dlasq6 computes one dqd transform in ping-pong form with protection against // overflow and underflow. z has length at least 4*(n0+1) and holds the qd array. // i0 is the zero-based first index. // n0 is the zero-based last index. // // Dlasq6 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasq6(i0, n0 int, z []float64, pp int) (dmin, dmin1, dmin2, dn, dnm1, dnm2 float64) { switch { case i0 < 0: panic(i0LT0) case n0 < 0: panic(n0LT0) case len(z) < 4*n0: panic(shortZ) case pp != 0 && pp != 1: panic(badPp) } if n0-i0-1 <= 0 { return dmin, dmin1, dmin2, dn, dnm1, dnm2 } safmin := dlamchS j4 := 4*(i0+1) + pp - 4 // -4 rather than -3 for zero indexing emin := z[j4+4] d := z[j4] dmin = d if pp == 0 { for j4loop := 4 * (i0 + 1); j4loop <= 4*((n0+1)-3); j4loop += 4 { j4 := j4loop - 1 // Translate back to zero-indexed. z[j4-2] = d + z[j4-1] if z[j4-2] == 0 { z[j4] = 0 d = z[j4+1] dmin = d emin = 0 } else if safmin*z[j4+1] < z[j4-2] && safmin*z[j4-2] < z[j4+1] { tmp := z[j4+1] / z[j4-2] z[j4] = z[j4-1] * tmp d *= tmp } else { z[j4] = z[j4+1] * (z[j4-1] / z[j4-2]) d = z[j4+1] * (d / z[j4-2]) } dmin = math.Min(dmin, d) emin = math.Min(emin, z[j4]) } } else { for j4loop := 4 * (i0 + 1); j4loop <= 4*((n0+1)-3); j4loop += 4 { j4 := j4loop - 1 z[j4-3] = d + z[j4] if z[j4-3] == 0 { z[j4-1] = 0 d = z[j4+2] dmin = d emin = 0 } else if safmin*z[j4+2] < z[j4-3] && safmin*z[j4-3] < z[j4+2] { tmp := z[j4+2] / z[j4-3] z[j4-1] = z[j4] * tmp d *= tmp } else { z[j4-1] = z[j4+2] * (z[j4] / z[j4-3]) d = z[j4+2] * (d / z[j4-3]) } dmin = math.Min(dmin, d) emin = math.Min(emin, z[j4-1]) } } // Unroll last two steps. dnm2 = d dmin2 = dmin j4 = 4*(n0-1) - pp - 1 j4p2 := j4 + 2*pp - 1 z[j4-2] = dnm2 + z[j4p2] if z[j4-2] == 0 { z[j4] = 0 dnm1 = z[j4p2+2] dmin = dnm1 emin = 0 } else if safmin*z[j4p2+2] < z[j4-2] && safmin*z[j4-2] < z[j4p2+2] { tmp := z[j4p2+2] / z[j4-2] z[j4] = z[j4p2] * tmp dnm1 = dnm2 * tmp } else { z[j4] = z[j4p2+2] * (z[j4p2] / z[j4-2]) dnm1 = z[j4p2+2] * (dnm2 / z[j4-2]) } dmin = math.Min(dmin, dnm1) dmin1 = dmin j4 += 4 j4p2 = j4 + 2*pp - 1 z[j4-2] = dnm1 + z[j4p2] if z[j4-2] == 0 { z[j4] = 0 dn = z[j4p2+2] dmin = dn emin = 0 } else if safmin*z[j4p2+2] < z[j4-2] && safmin*z[j4-2] < z[j4p2+2] { tmp := z[j4p2+2] / z[j4-2] z[j4] = z[j4p2] * tmp dn = dnm1 * tmp } else { z[j4] = z[j4p2+2] * (z[j4p2] / z[j4-2]) dn = z[j4p2+2] * (dnm1 / z[j4-2]) } dmin = math.Min(dmin, dn) z[j4+2] = dn z[4*(n0+1)-pp-1] = emin return dmin, dmin1, dmin2, dn, dnm1, dnm2 } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasr.go000066400000000000000000000154731450372207100216640ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dlasr applies a sequence of plane rotations to the m×n matrix A. This series // of plane rotations is implicitly represented by a matrix P. P is multiplied // by a depending on the value of side -- A = P * A if side == lapack.Left, // A = A * Pᵀ if side == lapack.Right. // // The exact value of P depends on the value of pivot, but in all cases P is // implicitly represented by a series of 2×2 rotation matrices. The entries of // rotation matrix k are defined by s[k] and c[k] // // R(k) = [ c[k] s[k]] // [-s[k] s[k]] // // If direct == lapack.Forward, the rotation matrices are applied as // P = P(z-1) * ... * P(2) * P(1), while if direct == lapack.Backward they are // applied as P = P(1) * P(2) * ... * P(n). // // pivot defines the mapping of the elements in R(k) to P(k). // If pivot == lapack.Variable, the rotation is performed for the (k, k+1) plane. // // P(k) = [1 ] // [ ... ] // [ 1 ] // [ c[k] s[k] ] // [ -s[k] c[k] ] // [ 1 ] // [ ... ] // [ 1] // // if pivot == lapack.Top, the rotation is performed for the (1, k+1) plane, // // P(k) = [c[k] s[k] ] // [ 1 ] // [ ... ] // [ 1 ] // [-s[k] c[k] ] // [ 1 ] // [ ... ] // [ 1] // // and if pivot == lapack.Bottom, the rotation is performed for the (k, z) plane. // // P(k) = [1 ] // [ ... ] // [ 1 ] // [ c[k] s[k]] // [ 1 ] // [ ... ] // [ 1 ] // [ -s[k] c[k]] // // s and c have length m - 1 if side == blas.Left, and n - 1 if side == blas.Right. // // Dlasr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasr(side blas.Side, pivot lapack.Pivot, direct lapack.Direct, m, n int, c, s, a []float64, lda int) { switch { case side != blas.Left && side != blas.Right: panic(badSide) case pivot != lapack.Variable && pivot != lapack.Top && pivot != lapack.Bottom: panic(badPivot) case direct != lapack.Forward && direct != lapack.Backward: panic(badDirect) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if m == 0 || n == 0 { return } if side == blas.Left { if len(c) < m-1 { panic(shortC) } if len(s) < m-1 { panic(shortS) } } else { if len(c) < n-1 { panic(shortC) } if len(s) < n-1 { panic(shortS) } } if len(a) < (m-1)*lda+n { panic(shortA) } if side == blas.Left { if pivot == lapack.Variable { if direct == lapack.Forward { for j := 0; j < m-1; j++ { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < n; i++ { tmp2 := a[j*lda+i] tmp := a[(j+1)*lda+i] a[(j+1)*lda+i] = ctmp*tmp - stmp*tmp2 a[j*lda+i] = stmp*tmp + ctmp*tmp2 } } } return } for j := m - 2; j >= 0; j-- { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < n; i++ { tmp2 := a[j*lda+i] tmp := a[(j+1)*lda+i] a[(j+1)*lda+i] = ctmp*tmp - stmp*tmp2 a[j*lda+i] = stmp*tmp + ctmp*tmp2 } } } return } else if pivot == lapack.Top { if direct == lapack.Forward { for j := 1; j < m; j++ { ctmp := c[j-1] stmp := s[j-1] if ctmp != 1 || stmp != 0 { for i := 0; i < n; i++ { tmp := a[j*lda+i] tmp2 := a[i] a[j*lda+i] = ctmp*tmp - stmp*tmp2 a[i] = stmp*tmp + ctmp*tmp2 } } } return } for j := m - 1; j >= 1; j-- { ctmp := c[j-1] stmp := s[j-1] if ctmp != 1 || stmp != 0 { for i := 0; i < n; i++ { ctmp := c[j-1] stmp := s[j-1] if ctmp != 1 || stmp != 0 { for i := 0; i < n; i++ { tmp := a[j*lda+i] tmp2 := a[i] a[j*lda+i] = ctmp*tmp - stmp*tmp2 a[i] = stmp*tmp + ctmp*tmp2 } } } } } return } if direct == lapack.Forward { for j := 0; j < m-1; j++ { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < n; i++ { tmp := a[j*lda+i] tmp2 := a[(m-1)*lda+i] a[j*lda+i] = stmp*tmp2 + ctmp*tmp a[(m-1)*lda+i] = ctmp*tmp2 - stmp*tmp } } } return } for j := m - 2; j >= 0; j-- { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < n; i++ { tmp := a[j*lda+i] tmp2 := a[(m-1)*lda+i] a[j*lda+i] = stmp*tmp2 + ctmp*tmp a[(m-1)*lda+i] = ctmp*tmp2 - stmp*tmp } } } return } if pivot == lapack.Variable { if direct == lapack.Forward { for j := 0; j < n-1; j++ { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < m; i++ { tmp := a[i*lda+j+1] tmp2 := a[i*lda+j] a[i*lda+j+1] = ctmp*tmp - stmp*tmp2 a[i*lda+j] = stmp*tmp + ctmp*tmp2 } } } return } for j := n - 2; j >= 0; j-- { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < m; i++ { tmp := a[i*lda+j+1] tmp2 := a[i*lda+j] a[i*lda+j+1] = ctmp*tmp - stmp*tmp2 a[i*lda+j] = stmp*tmp + ctmp*tmp2 } } } return } else if pivot == lapack.Top { if direct == lapack.Forward { for j := 1; j < n; j++ { ctmp := c[j-1] stmp := s[j-1] if ctmp != 1 || stmp != 0 { for i := 0; i < m; i++ { tmp := a[i*lda+j] tmp2 := a[i*lda] a[i*lda+j] = ctmp*tmp - stmp*tmp2 a[i*lda] = stmp*tmp + ctmp*tmp2 } } } return } for j := n - 1; j >= 1; j-- { ctmp := c[j-1] stmp := s[j-1] if ctmp != 1 || stmp != 0 { for i := 0; i < m; i++ { tmp := a[i*lda+j] tmp2 := a[i*lda] a[i*lda+j] = ctmp*tmp - stmp*tmp2 a[i*lda] = stmp*tmp + ctmp*tmp2 } } } return } if direct == lapack.Forward { for j := 0; j < n-1; j++ { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < m; i++ { tmp := a[i*lda+j] tmp2 := a[i*lda+n-1] a[i*lda+j] = stmp*tmp2 + ctmp*tmp a[i*lda+n-1] = ctmp*tmp2 - stmp*tmp } } } return } for j := n - 2; j >= 0; j-- { ctmp := c[j] stmp := s[j] if ctmp != 1 || stmp != 0 { for i := 0; i < m; i++ { tmp := a[i*lda+j] tmp2 := a[i*lda+n-1] a[i*lda+j] = stmp*tmp2 + ctmp*tmp a[i*lda+n-1] = ctmp*tmp2 - stmp*tmp } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasrt.go000066400000000000000000000015621450372207100220420ustar00rootroot00000000000000// 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 ( "sort" "gonum.org/v1/gonum/lapack" ) // Dlasrt sorts the numbers in the input slice d. If s == lapack.SortIncreasing, // the elements are sorted in increasing order. If s == lapack.SortDecreasing, // the elements are sorted in decreasing order. For other values of s Dlasrt // will panic. // // Dlasrt is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasrt(s lapack.Sort, n int, d []float64) { switch { case n < 0: panic(nLT0) case len(d) < n: panic(shortD) } d = d[:n] switch s { default: panic(badSort) case lapack.SortIncreasing: sort.Float64s(d) case lapack.SortDecreasing: sort.Sort(sort.Reverse(sort.Float64Slice(d))) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlassq.go000066400000000000000000000061021450372207100220330ustar00rootroot00000000000000// 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" // Dlassq updates a sum of squares represented in scaled form. Dlassq returns // the values scl and smsq such that // // scl^2*smsq = X[0]^2 + ... + X[n-1]^2 + scale^2*sumsq // // The value of sumsq is assumed to be non-negative. // // Dlassq is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlassq(n int, x []float64, incx int, scale float64, sumsq float64) (scl, smsq float64) { // Implementation based on Supplemental Material to: // Edward Anderson. 2017. Algorithm 978: Safe Scaling in the Level 1 BLAS. // ACM Trans. Math. Softw. 44, 1, Article 12 (July 2017), 28 pages. // DOI: https://doi.org/10.1145/3061665 switch { case n < 0: panic(nLT0) case incx <= 0: panic(badIncX) case len(x) < 1+(n-1)*incx: panic(shortX) } if math.IsNaN(scale) || math.IsNaN(sumsq) { return scale, sumsq } if sumsq == 0 { scale = 1 } if scale == 0 { scale = 1 sumsq = 0 } if n == 0 { return scale, sumsq } // Compute the sum of squares in 3 accumulators: // - abig: sum of squares scaled down to avoid overflow // - asml: sum of squares scaled up to avoid underflow // - amed: sum of squares that do not require scaling // The thresholds and multipliers are: // - values bigger than dtbig are scaled down by dsbig // - values smaller than dtsml are scaled up by dssml var ( isBig bool asml, amed, abig float64 ) for i, ix := 0, 0; i < n; i++ { ax := math.Abs(x[ix]) switch { case ax > dtbig: ax *= dsbig abig += ax * ax isBig = true case ax < dtsml: if !isBig { ax *= dssml asml += ax * ax } default: amed += ax * ax } ix += incx } // Put the existing sum of squares into one of the accumulators. if sumsq > 0 { ax := scale * math.Sqrt(sumsq) switch { case ax > dtbig: // We assume scale >= sqrt( TINY*EPS ) / dsbig, that is, if the // scaled sum is big then its scaling factor should not be too // small. v := scale * dsbig abig += (v * v) * sumsq case ax < dtsml: if !isBig { // We assume scale <= sqrt( HUGE ) / dssml, that is, if the // scaled sum is small then its scaling factor should not be too // big. v := scale * dssml asml += (v * v) * sumsq } default: amed += scale * scale * sumsq } } // Combine abig and amed or amed and asml if more than one accumulator was // used. switch { case abig > 0: // Combine abig and amed: if amed > 0 || math.IsNaN(amed) { abig += (amed * dsbig) * dsbig } scale = 1 / dsbig sumsq = abig case asml > 0: // Combine amed and asml: if amed > 0 || math.IsNaN(amed) { amed = math.Sqrt(amed) asml = math.Sqrt(asml) / dssml ymin, ymax := asml, amed if asml > amed { ymin, ymax = amed, asml } scale = 1 sumsq = ymax * ymax * (1 + (ymin/ymax)*(ymin/ymax)) } else { scale = 1 / dssml sumsq = asml } default: scale = 1 sumsq = amed } return scale, sumsq } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasv2.go000066400000000000000000000050071450372207100217420ustar00rootroot00000000000000// 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" // Dlasv2 computes the singular value decomposition of a 2×2 matrix. // // [ csl snl] [f g] [csr -snr] = [ssmax 0] // [-snl csl] [0 h] [snr csr] = [ 0 ssmin] // // ssmax is the larger absolute singular value, and ssmin is the smaller absolute // singular value. [cls, snl] and [csr, snr] are the left and right singular vectors. // // Dlasv2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasv2(f, g, h float64) (ssmin, ssmax, snr, csr, snl, csl float64) { ft := f fa := math.Abs(ft) ht := h ha := math.Abs(h) // pmax points to the largest element of the matrix in terms of absolute value. // 1 if F, 2 if G, 3 if H. pmax := 1 swap := ha > fa if swap { pmax = 3 ft, ht = ht, ft fa, ha = ha, fa } gt := g ga := math.Abs(gt) var clt, crt, slt, srt float64 if ga == 0 { ssmin = ha ssmax = fa clt = 1 crt = 1 slt = 0 srt = 0 } else { gasmall := true if ga > fa { pmax = 2 if (fa / ga) < dlamchE { gasmall = false ssmax = ga if ha > 1 { ssmin = fa / (ga / ha) } else { ssmin = (fa / ga) * ha } clt = 1 slt = ht / gt srt = 1 crt = ft / gt } } if gasmall { d := fa - ha l := d / fa if d == fa { // deal with inf l = 1 } m := gt / ft t := 2 - l s := math.Hypot(t, m) var r float64 if l == 0 { r = math.Abs(m) } else { r = math.Hypot(l, m) } a := 0.5 * (s + r) ssmin = ha / a ssmax = fa * a if m == 0 { if l == 0 { t = math.Copysign(2, ft) * math.Copysign(1, gt) } else { t = gt/math.Copysign(d, ft) + m/t } } else { t = (m/(s+t) + m/(r+l)) * (1 + a) } l = math.Hypot(t, 2) crt = 2 / l srt = t / l clt = (crt + srt*m) / a slt = (ht / ft) * srt / a } } if swap { csl = srt snl = crt csr = slt snr = clt } else { csl = clt snl = slt csr = crt snr = srt } var tsign float64 switch pmax { case 1: tsign = math.Copysign(1, csr) * math.Copysign(1, csl) * math.Copysign(1, f) case 2: tsign = math.Copysign(1, snr) * math.Copysign(1, csl) * math.Copysign(1, g) case 3: tsign = math.Copysign(1, snr) * math.Copysign(1, snl) * math.Copysign(1, h) } ssmax = math.Copysign(ssmax, tsign) ssmin = math.Copysign(ssmin, tsign*math.Copysign(1, f)*math.Copysign(1, h)) return ssmin, ssmax, snr, csr, snl, csl } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlaswp.go000066400000000000000000000030021450372207100220320ustar00rootroot00000000000000// 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/blas/blas64" // Dlaswp swaps the rows k1 to k2 of a rectangular matrix A according to the // indices in ipiv so that row k is swapped with ipiv[k]. // // n is the number of columns of A and incX is the increment for ipiv. If incX // is 1, the swaps are applied from k1 to k2. If incX is -1, the swaps are // applied in reverse order from k2 to k1. For other values of incX Dlaswp will // panic. ipiv must have length k2+1, otherwise Dlaswp will panic. // // The indices k1, k2, and the elements of ipiv are zero-based. // // Dlaswp is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlaswp(n int, a []float64, lda int, k1, k2 int, ipiv []int, incX int) { switch { case n < 0: panic(nLT0) case k1 < 0: panic(badK1) case k2 < k1: panic(badK2) case lda < max(1, n): panic(badLdA) case len(a) < k2*lda+n: // A must have at least k2+1 rows. panic(shortA) case len(ipiv) != k2+1: panic(badLenIpiv) case incX != 1 && incX != -1: panic(absIncNotOne) } if n == 0 { return } bi := blas64.Implementation() if incX == 1 { for k := k1; k <= k2; k++ { if k == ipiv[k] { continue } bi.Dswap(n, a[k*lda:], 1, a[ipiv[k]*lda:], 1) } return } for k := k2; k >= k1; k-- { if k == ipiv[k] { continue } bi.Dswap(n, a[k*lda:], 1, a[ipiv[k]*lda:], 1) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlasy2.go000066400000000000000000000204101450372207100217400ustar00rootroot00000000000000// Copyright ©2016 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/blas64" ) // Dlasy2 solves the Sylvester matrix equation where the matrices are of order 1 // or 2. It computes the unknown n1×n2 matrix X so that // // TL*X + sgn*X*TR = scale*B if tranl == false and tranr == false, // TLᵀ*X + sgn*X*TR = scale*B if tranl == true and tranr == false, // TL*X + sgn*X*TRᵀ = scale*B if tranl == false and tranr == true, // TLᵀ*X + sgn*X*TRᵀ = scale*B if tranl == true and tranr == true, // // where TL is n1×n1, TR is n2×n2, B is n1×n2, and 1 <= n1,n2 <= 2. // // isgn must be 1 or -1, and n1 and n2 must be 0, 1, or 2, but these conditions // are not checked. // // Dlasy2 returns three values, a scale factor that is chosen less than or equal // to 1 to prevent the solution overflowing, the infinity norm of the solution, // and an indicator of success. If ok is false, TL and TR have eigenvalues that // are too close, so TL or TR is perturbed to get a non-singular equation. // // Dlasy2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlasy2(tranl, tranr bool, isgn, n1, n2 int, tl []float64, ldtl int, tr []float64, ldtr int, b []float64, ldb int, x []float64, ldx int) (scale, xnorm float64, ok bool) { // TODO(vladimir-ch): Add input validation checks conditionally skipped // using the build tag mechanism. ok = true // Quick return if possible. if n1 == 0 || n2 == 0 { return scale, xnorm, ok } // Set constants to control overflow. eps := dlamchP smlnum := dlamchS / eps sgn := float64(isgn) if n1 == 1 && n2 == 1 { // 1×1 case: TL11*X + sgn*X*TR11 = B11. tau1 := tl[0] + sgn*tr[0] bet := math.Abs(tau1) if bet <= smlnum { tau1 = smlnum bet = smlnum ok = false } scale = 1 gam := math.Abs(b[0]) if smlnum*gam > bet { scale = 1 / gam } x[0] = b[0] * scale / tau1 xnorm = math.Abs(x[0]) return scale, xnorm, ok } if n1+n2 == 3 { // 1×2 or 2×1 case. var ( smin float64 tmp [4]float64 // tmp is used as a 2×2 row-major matrix. btmp [2]float64 ) if n1 == 1 && n2 == 2 { // 1×2 case: TL11*[X11 X12] + sgn*[X11 X12]*op[TR11 TR12] = [B11 B12]. // [TR21 TR22] smin = math.Abs(tl[0]) smin = math.Max(smin, math.Max(math.Abs(tr[0]), math.Abs(tr[1]))) smin = math.Max(smin, math.Max(math.Abs(tr[ldtr]), math.Abs(tr[ldtr+1]))) smin = math.Max(eps*smin, smlnum) tmp[0] = tl[0] + sgn*tr[0] tmp[3] = tl[0] + sgn*tr[ldtr+1] if tranr { tmp[1] = sgn * tr[1] tmp[2] = sgn * tr[ldtr] } else { tmp[1] = sgn * tr[ldtr] tmp[2] = sgn * tr[1] } btmp[0] = b[0] btmp[1] = b[1] } else { // 2×1 case: op[TL11 TL12]*[X11] + sgn*[X11]*TR11 = [B11]. // [TL21 TL22]*[X21] [X21] [B21] smin = math.Abs(tr[0]) smin = math.Max(smin, math.Max(math.Abs(tl[0]), math.Abs(tl[1]))) smin = math.Max(smin, math.Max(math.Abs(tl[ldtl]), math.Abs(tl[ldtl+1]))) smin = math.Max(eps*smin, smlnum) tmp[0] = tl[0] + sgn*tr[0] tmp[3] = tl[ldtl+1] + sgn*tr[0] if tranl { tmp[1] = tl[ldtl] tmp[2] = tl[1] } else { tmp[1] = tl[1] tmp[2] = tl[ldtl] } btmp[0] = b[0] btmp[1] = b[ldb] } // Solve 2×2 system using complete pivoting. // Set pivots less than smin to smin. bi := blas64.Implementation() ipiv := bi.Idamax(len(tmp), tmp[:], 1) // Compute the upper triangular matrix [u11 u12]. // [ 0 u22] u11 := tmp[ipiv] if math.Abs(u11) <= smin { ok = false u11 = smin } locu12 := [4]int{1, 0, 3, 2} // Index in tmp of the element on the same row as the pivot. u12 := tmp[locu12[ipiv]] locl21 := [4]int{2, 3, 0, 1} // Index in tmp of the element on the same column as the pivot. l21 := tmp[locl21[ipiv]] / u11 locu22 := [4]int{3, 2, 1, 0} // Index in tmp of the remaining element. u22 := tmp[locu22[ipiv]] - l21*u12 if math.Abs(u22) <= smin { ok = false u22 = smin } if ipiv&0x2 != 0 { // true for ipiv equal to 2 and 3. // The pivot was in the second row, swap the elements of // the right-hand side. btmp[0], btmp[1] = btmp[1], btmp[0]-l21*btmp[1] } else { btmp[1] -= l21 * btmp[0] } scale = 1 if 2*smlnum*math.Abs(btmp[1]) > math.Abs(u22) || 2*smlnum*math.Abs(btmp[0]) > math.Abs(u11) { scale = 0.5 / math.Max(math.Abs(btmp[0]), math.Abs(btmp[1])) btmp[0] *= scale btmp[1] *= scale } // Solve the system [u11 u12] [x21] = [ btmp[0] ]. // [ 0 u22] [x22] [ btmp[1] ] x22 := btmp[1] / u22 x21 := btmp[0]/u11 - (u12/u11)*x22 if ipiv&0x1 != 0 { // true for ipiv equal to 1 and 3. // The pivot was in the second column, swap the elements // of the solution. x21, x22 = x22, x21 } x[0] = x21 if n1 == 1 { x[1] = x22 xnorm = math.Abs(x[0]) + math.Abs(x[1]) } else { x[ldx] = x22 xnorm = math.Max(math.Abs(x[0]), math.Abs(x[ldx])) } return scale, xnorm, ok } // 2×2 case: op[TL11 TL12]*[X11 X12] + SGN*[X11 X12]*op[TR11 TR12] = [B11 B12]. // [TL21 TL22] [X21 X22] [X21 X22] [TR21 TR22] [B21 B22] // // Solve equivalent 4×4 system using complete pivoting. // Set pivots less than smin to smin. smin := math.Max(math.Abs(tr[0]), math.Abs(tr[1])) smin = math.Max(smin, math.Max(math.Abs(tr[ldtr]), math.Abs(tr[ldtr+1]))) smin = math.Max(smin, math.Max(math.Abs(tl[0]), math.Abs(tl[1]))) smin = math.Max(smin, math.Max(math.Abs(tl[ldtl]), math.Abs(tl[ldtl+1]))) smin = math.Max(eps*smin, smlnum) var t [4][4]float64 t[0][0] = tl[0] + sgn*tr[0] t[1][1] = tl[0] + sgn*tr[ldtr+1] t[2][2] = tl[ldtl+1] + sgn*tr[0] t[3][3] = tl[ldtl+1] + sgn*tr[ldtr+1] if tranl { t[0][2] = tl[ldtl] t[1][3] = tl[ldtl] t[2][0] = tl[1] t[3][1] = tl[1] } else { t[0][2] = tl[1] t[1][3] = tl[1] t[2][0] = tl[ldtl] t[3][1] = tl[ldtl] } if tranr { t[0][1] = sgn * tr[1] t[1][0] = sgn * tr[ldtr] t[2][3] = sgn * tr[1] t[3][2] = sgn * tr[ldtr] } else { t[0][1] = sgn * tr[ldtr] t[1][0] = sgn * tr[1] t[2][3] = sgn * tr[ldtr] t[3][2] = sgn * tr[1] } var btmp [4]float64 btmp[0] = b[0] btmp[1] = b[1] btmp[2] = b[ldb] btmp[3] = b[ldb+1] // Perform elimination. var jpiv [4]int // jpiv records any column swaps for pivoting. for i := 0; i < 3; i++ { var ( xmax float64 ipsv, jpsv int ) for ip := i; ip < 4; ip++ { for jp := i; jp < 4; jp++ { if math.Abs(t[ip][jp]) >= xmax { xmax = math.Abs(t[ip][jp]) ipsv = ip jpsv = jp } } } if ipsv != i { // The pivot is not in the top row of the unprocessed // block, swap rows ipsv and i of t and btmp. t[ipsv], t[i] = t[i], t[ipsv] btmp[ipsv], btmp[i] = btmp[i], btmp[ipsv] } if jpsv != i { // The pivot is not in the left column of the // unprocessed block, swap columns jpsv and i of t. for k := 0; k < 4; k++ { t[k][jpsv], t[k][i] = t[k][i], t[k][jpsv] } } jpiv[i] = jpsv if math.Abs(t[i][i]) < smin { ok = false t[i][i] = smin } for k := i + 1; k < 4; k++ { t[k][i] /= t[i][i] btmp[k] -= t[k][i] * btmp[i] for j := i + 1; j < 4; j++ { t[k][j] -= t[k][i] * t[i][j] } } } if math.Abs(t[3][3]) < smin { ok = false t[3][3] = smin } scale = 1 if 8*smlnum*math.Abs(btmp[0]) > math.Abs(t[0][0]) || 8*smlnum*math.Abs(btmp[1]) > math.Abs(t[1][1]) || 8*smlnum*math.Abs(btmp[2]) > math.Abs(t[2][2]) || 8*smlnum*math.Abs(btmp[3]) > math.Abs(t[3][3]) { maxbtmp := math.Max(math.Abs(btmp[0]), math.Abs(btmp[1])) maxbtmp = math.Max(maxbtmp, math.Max(math.Abs(btmp[2]), math.Abs(btmp[3]))) scale = (1.0 / 8.0) / maxbtmp btmp[0] *= scale btmp[1] *= scale btmp[2] *= scale btmp[3] *= scale } // Compute the solution of the upper triangular system t * tmp = btmp. var tmp [4]float64 for i := 3; i >= 0; i-- { temp := 1 / t[i][i] tmp[i] = btmp[i] * temp for j := i + 1; j < 4; j++ { tmp[i] -= temp * t[i][j] * tmp[j] } } for i := 2; i >= 0; i-- { if jpiv[i] != i { tmp[i], tmp[jpiv[i]] = tmp[jpiv[i]], tmp[i] } } x[0] = tmp[0] x[1] = tmp[1] x[ldx] = tmp[2] x[ldx+1] = tmp[3] xnorm = math.Max(math.Abs(tmp[0])+math.Abs(tmp[1]), math.Abs(tmp[2])+math.Abs(tmp[3])) return scale, xnorm, ok } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlatbs.go000066400000000000000000000267431450372207100220320ustar00rootroot00000000000000// Copyright ©2019 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/blas/blas64" ) // Dlatbs solves a triangular banded system of equations // // A * x = s*b if trans == blas.NoTrans // Aᵀ * x = s*b if trans == blas.Trans or blas.ConjTrans // // where A is an upper or lower triangular band matrix, x and b are n-element // vectors, and s is a scaling factor chosen so that the components of x will be // less than the overflow threshold. // // On entry, x contains the right-hand side b of the triangular system. // On return, x is overwritten by the solution vector x. // // normin specifies whether the cnorm parameter contains the column norms of A on // entry. If it is true, cnorm[j] contains the norm of the off-diagonal part of // the j-th column of A. If it is false, the norms will be computed and stored // in cnorm. // // Dlatbs returns the scaling factor s for the triangular system. If the matrix // A is singular (A[j,j]==0 for some j), then scale is set to 0 and a // non-trivial solution to A*x = 0 is returned. // // Dlatbs is an internal routine. It is exported for testing purposes. func (Implementation) Dlatbs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, normin bool, n, kd int, ab []float64, ldab int, x, cnorm []float64) (scale float64) { noTran := trans == blas.NoTrans switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case !noTran && trans != blas.Trans && trans != blas.ConjTrans: panic(badTrans) case diag != blas.NonUnit && diag != blas.Unit: panic(badDiag) case n < 0: panic(nLT0) case kd < 0: panic(kdLT0) case ldab < kd+1: panic(badLdA) } // Quick return if possible. if n == 0 { return 1 } switch { case len(ab) < (n-1)*ldab+kd+1: panic(shortAB) case len(x) < n: panic(shortX) case len(cnorm) < n: panic(shortCNorm) } // Parameters to control overflow. smlnum := dlamchS / dlamchP bignum := 1 / smlnum bi := blas64.Implementation() kld := max(1, ldab-1) if !normin { // Compute the 1-norm of each column, not including the diagonal. if uplo == blas.Upper { for j := 0; j < n; j++ { jlen := min(j, kd) if jlen > 0 { cnorm[j] = bi.Dasum(jlen, ab[(j-jlen)*ldab+jlen:], kld) } else { cnorm[j] = 0 } } } else { for j := 0; j < n; j++ { jlen := min(n-j-1, kd) if jlen > 0 { cnorm[j] = bi.Dasum(jlen, ab[(j+1)*ldab+kd-1:], kld) } else { cnorm[j] = 0 } } } } // Set up indices and increments for loops below. var ( jFirst, jLast, jInc int maind int ) if noTran { if uplo == blas.Upper { jFirst = n - 1 jLast = -1 jInc = -1 maind = 0 } else { jFirst = 0 jLast = n jInc = 1 maind = kd } } else { if uplo == blas.Upper { jFirst = 0 jLast = n jInc = 1 maind = 0 } else { jFirst = n - 1 jLast = -1 jInc = -1 maind = kd } } // Scale the column norms by tscal if the maximum element in cnorm is // greater than bignum. tmax := cnorm[bi.Idamax(n, cnorm, 1)] tscal := 1.0 if tmax > bignum { tscal = 1 / (smlnum * tmax) bi.Dscal(n, tscal, cnorm, 1) } // Compute a bound on the computed solution vector to see if the Level 2 // BLAS routine Dtbsv can be used. xMax := math.Abs(x[bi.Idamax(n, x, 1)]) xBnd := xMax grow := 0.0 // Compute the growth only if the maximum element in cnorm is NOT greater // than bignum. if tscal != 1 { goto skipComputeGrow } if noTran { // Compute the growth in A * x = b. if diag == blas.NonUnit { // A is non-unit triangular. // // Compute grow = 1/G_j and xBnd = 1/M_j. // Initially, G_0 = max{x(i), i=1,...,n}. grow = 1 / math.Max(xBnd, smlnum) xBnd = grow for j := jFirst; j != jLast; j += jInc { if grow <= smlnum { // Exit the loop because the growth factor is too small. goto skipComputeGrow } // M_j = G_{j-1} / abs(A[j,j]) tjj := math.Abs(ab[j*ldab+maind]) xBnd = math.Min(xBnd, math.Min(1, tjj)*grow) if tjj+cnorm[j] >= smlnum { // G_j = G_{j-1}*( 1 + cnorm[j] / abs(A[j,j]) ) grow *= tjj / (tjj + cnorm[j]) } else { // G_j could overflow, set grow to 0. grow = 0 } } grow = xBnd } else { // A is unit triangular. // // Compute grow = 1/G_j, where G_0 = max{x(i), i=1,...,n}. grow = math.Min(1, 1/math.Max(xBnd, smlnum)) for j := jFirst; j != jLast; j += jInc { if grow <= smlnum { // Exit the loop because the growth factor is too small. goto skipComputeGrow } // G_j = G_{j-1}*( 1 + cnorm[j] ) grow /= 1 + cnorm[j] } } } else { // Compute the growth in Aᵀ * x = b. if diag == blas.NonUnit { // A is non-unit triangular. // // Compute grow = 1/G_j and xBnd = 1/M_j. // Initially, G_0 = max{x(i), i=1,...,n}. grow = 1 / math.Max(xBnd, smlnum) xBnd = grow for j := jFirst; j != jLast; j += jInc { if grow <= smlnum { // Exit the loop because the growth factor is too small. goto skipComputeGrow } // G_j = max( G_{j-1}, M_{j-1}*( 1 + cnorm[j] ) ) xj := 1 + cnorm[j] grow = math.Min(grow, xBnd/xj) // M_j = M_{j-1}*( 1 + cnorm[j] ) / abs(A[j,j]) tjj := math.Abs(ab[j*ldab+maind]) if xj > tjj { xBnd *= tjj / xj } } grow = math.Min(grow, xBnd) } else { // A is unit triangular. // // Compute grow = 1/G_j, where G_0 = max{x(i), i=1,...,n}. grow = math.Min(1, 1/math.Max(xBnd, smlnum)) for j := jFirst; j != jLast; j += jInc { if grow <= smlnum { // Exit the loop because the growth factor is too small. goto skipComputeGrow } // G_j = G_{j-1}*( 1 + cnorm[j] ) grow /= 1 + cnorm[j] } } } skipComputeGrow: if grow*tscal > smlnum { // The reciprocal of the bound on elements of X is not too small, use // the Level 2 BLAS solve. bi.Dtbsv(uplo, trans, diag, n, kd, ab, ldab, x, 1) // Scale the column norms by 1/tscal for return. if tscal != 1 { bi.Dscal(n, 1/tscal, cnorm, 1) } return 1 } // Use a Level 1 BLAS solve, scaling intermediate results. scale = 1 if xMax > bignum { // Scale x so that its components are less than or equal to bignum in // absolute value. scale = bignum / xMax bi.Dscal(n, scale, x, 1) xMax = bignum } if noTran { // Solve A * x = b. for j := jFirst; j != jLast; j += jInc { // Compute x[j] = b[j] / A[j,j], scaling x if necessary. xj := math.Abs(x[j]) tjjs := tscal if diag == blas.NonUnit { tjjs *= ab[j*ldab+maind] } tjj := math.Abs(tjjs) switch { case tjj > smlnum: // smlnum < abs(A[j,j]) if tjj < 1 && xj > tjj*bignum { // Scale x by 1/b[j]. rec := 1 / xj bi.Dscal(n, rec, x, 1) scale *= rec xMax *= rec } x[j] /= tjjs xj = math.Abs(x[j]) case tjj > 0: // 0 < abs(A[j,j]) <= smlnum if xj > tjj*bignum { // Scale x by (1/abs(x[j]))*abs(A[j,j])*bignum to avoid // overflow when dividing by A[j,j]. rec := tjj * bignum / xj if cnorm[j] > 1 { // Scale by 1/cnorm[j] to avoid overflow when // multiplying x[j] times column j. rec /= cnorm[j] } bi.Dscal(n, rec, x, 1) scale *= rec xMax *= rec } x[j] /= tjjs xj = math.Abs(x[j]) default: // A[j,j] == 0: Set x[0:n] = 0, x[j] = 1, and scale = 0, and // compute a solution to A*x = 0. for i := range x[:n] { x[i] = 0 } x[j] = 1 xj = 1 scale = 0 xMax = 0 } // Scale x if necessary to avoid overflow when adding a multiple of // column j of A. switch { case xj > 1: rec := 1 / xj if cnorm[j] > (bignum-xMax)*rec { // Scale x by 1/(2*abs(x[j])). rec *= 0.5 bi.Dscal(n, rec, x, 1) scale *= rec } case xj*cnorm[j] > bignum-xMax: // Scale x by 1/2. bi.Dscal(n, 0.5, x, 1) scale *= 0.5 } if uplo == blas.Upper { if j > 0 { // Compute the update // x[max(0,j-kd):j] := x[max(0,j-kd):j] - x[j] * A[max(0,j-kd):j,j] jlen := min(j, kd) if jlen > 0 { bi.Daxpy(jlen, -x[j]*tscal, ab[(j-jlen)*ldab+jlen:], kld, x[j-jlen:], 1) } i := bi.Idamax(j, x, 1) xMax = math.Abs(x[i]) } } else if j < n-1 { // Compute the update // x[j+1:min(j+kd,n)] := x[j+1:min(j+kd,n)] - x[j] * A[j+1:min(j+kd,n),j] jlen := min(kd, n-j-1) if jlen > 0 { bi.Daxpy(jlen, -x[j]*tscal, ab[(j+1)*ldab+kd-1:], kld, x[j+1:], 1) } i := j + 1 + bi.Idamax(n-j-1, x[j+1:], 1) xMax = math.Abs(x[i]) } } } else { // Solve Aᵀ * x = b. for j := jFirst; j != jLast; j += jInc { // Compute x[j] = b[j] - sum A[k,j]*x[k]. // k!=j xj := math.Abs(x[j]) tjjs := tscal if diag == blas.NonUnit { tjjs *= ab[j*ldab+maind] } tjj := math.Abs(tjjs) rec := 1 / math.Max(1, xMax) uscal := tscal if cnorm[j] > (bignum-xj)*rec { // If x[j] could overflow, scale x by 1/(2*xMax). rec *= 0.5 if tjj > 1 { // Divide by A[j,j] when scaling x if A[j,j] > 1. rec = math.Min(1, rec*tjj) uscal /= tjjs } if rec < 1 { bi.Dscal(n, rec, x, 1) scale *= rec xMax *= rec } } var sumj float64 if uscal == 1 { // If the scaling needed for A in the dot product is 1, call // Ddot to perform the dot product... if uplo == blas.Upper { jlen := min(j, kd) if jlen > 0 { sumj = bi.Ddot(jlen, ab[(j-jlen)*ldab+jlen:], kld, x[j-jlen:], 1) } } else { jlen := min(n-j-1, kd) if jlen > 0 { sumj = bi.Ddot(jlen, ab[(j+1)*ldab+kd-1:], kld, x[j+1:], 1) } } } else { // ...otherwise, use in-line code for the dot product. if uplo == blas.Upper { jlen := min(j, kd) for i := 0; i < jlen; i++ { sumj += (ab[(j-jlen+i)*ldab+jlen-i] * uscal) * x[j-jlen+i] } } else { jlen := min(n-j-1, kd) for i := 0; i < jlen; i++ { sumj += (ab[(j+1+i)*ldab+kd-1-i] * uscal) * x[j+i+1] } } } if uscal == tscal { // Compute x[j] := ( x[j] - sumj ) / A[j,j] // if 1/A[j,j] was not used to scale the dot product. x[j] -= sumj xj = math.Abs(x[j]) // Compute x[j] = x[j] / A[j,j], scaling if necessary. // Note: the reference implementation skips this step for blas.Unit matrices // when tscal is equal to 1 but it complicates the logic and only saves // the comparison and division in the first switch-case. Not skipping it // is also consistent with the NoTrans case above. switch { case tjj > smlnum: // smlnum < abs(A[j,j]): if tjj < 1 && xj > tjj*bignum { // Scale x by 1/abs(x[j]). rec := 1 / xj bi.Dscal(n, rec, x, 1) scale *= rec xMax *= rec } x[j] /= tjjs case tjj > 0: // 0 < abs(A[j,j]) <= smlnum: if xj > tjj*bignum { // Scale x by (1/abs(x[j]))*abs(A[j,j])*bignum. rec := (tjj * bignum) / xj bi.Dscal(n, rec, x, 1) scale *= rec xMax *= rec } x[j] /= tjjs default: // A[j,j] == 0: Set x[0:n] = 0, x[j] = 1, and scale = 0, and // compute a solution Aᵀ * x = 0. for i := range x[:n] { x[i] = 0 } x[j] = 1 scale = 0 xMax = 0 } } else { // Compute x[j] := x[j] / A[j,j] - sumj // if the dot product has already been divided by 1/A[j,j]. x[j] = x[j]/tjjs - sumj } xMax = math.Max(xMax, math.Abs(x[j])) } scale /= tscal } // Scale the column norms by 1/tscal for return. if tscal != 1 { bi.Dscal(n, 1/tscal, cnorm, 1) } return scale } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlatdf.go000066400000000000000000000124701450372207100220070ustar00rootroot00000000000000// Copyright ©2021 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/blas64" "gonum.org/v1/gonum/lapack" ) // Dlatdf computes a contribution to the reciprocal Dif-estimate by solving // // Z * x = h - f // // and choosing the vector h such that the norm of x is as large as possible. // // The n×n matrix Z is represented by its LU factorization as computed by Dgetc2 // and has the form // // Z = P * L * U * Q // // where P and Q are permutation matrices, L is lower triangular with unit // diagonal elements and U is upper triangular. // // job specifies the heuristic method for computing the contribution. // // If job is lapack.LocalLookAhead, all entries of h are chosen as either +1 or // -1. // // If job is lapack.NormalizedNullVector, an approximate null-vector e of Z is // computed using Dgecon and normalized. h is chosen as ±e with the sign giving // the greater value of 2-norm(x). This strategy is about 5 times as expensive // as LocalLookAhead. // // On entry, rhs holds the contribution f from earlier solved sub-systems. On // return, rhs holds the solution x. // // ipiv and jpiv contain the pivot indices as returned by Dgetc2: row i of the // matrix has been interchanged with row ipiv[i] and column j of the matrix has // been interchanged with column jpiv[j]. // // n must be at most 8, ipiv and jpiv must have length n, and rhs must have // length at least n, otherwise Dlatdf will panic. // // rdsum and rdscal represent the sum of squares of computed contributions to // the Dif-estimate from earlier solved sub-systems. rdscal is the scaling // factor used to prevent overflow in rdsum. Dlatdf returns this sum of squares // updated with the contributions from the current sub-system. // // Dlatdf is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlatdf(job lapack.MaximizeNormXJob, n int, z []float64, ldz int, rhs []float64, rdsum, rdscal float64, ipiv, jpiv []int) (scale, sum float64) { switch { case job != lapack.LocalLookAhead && job != lapack.NormalizedNullVector: panic(badMaximizeNormXJob) case n < 0: panic(nLT0) case n > 8: panic("lapack: n > 8") case ldz < max(1, n): panic(badLdZ) } // Quick return if possible. if n == 0 { return } switch { case len(z) < (n-1)*ldz+n: panic(shortZ) case len(rhs) < n: panic(shortRHS) case len(ipiv) != n: panic(badLenIpiv) case len(jpiv) != n: panic(badLenJpiv) } const maxdim = 8 var ( xps [maxdim]float64 xms [maxdim]float64 work [4 * maxdim]float64 iwork [maxdim]int ) bi := blas64.Implementation() xp := xps[:n] xm := xms[:n] if job == lapack.NormalizedNullVector { // Compute approximate nullvector xm of Z. _ = impl.Dgecon(lapack.MaxRowSum, n, z, ldz, 1, work[:], iwork[:]) // This relies on undocumented content in work[n:2*n] stored by Dgecon. bi.Dcopy(n, work[n:], 1, xm, 1) // Compute rhs. impl.Dlaswp(1, xm, 1, 0, n-2, ipiv[:n-1], -1) tmp := 1 / bi.Dnrm2(n, xm, 1) bi.Dscal(n, tmp, xm, 1) bi.Dcopy(n, xm, 1, xp, 1) bi.Daxpy(n, 1, rhs, 1, xp, 1) bi.Daxpy(n, -1.0, xm, 1, rhs, 1) _ = impl.Dgesc2(n, z, ldz, rhs, ipiv, jpiv) _ = impl.Dgesc2(n, z, ldz, xp, ipiv, jpiv) if bi.Dasum(n, xp, 1) > bi.Dasum(n, rhs, 1) { bi.Dcopy(n, xp, 1, rhs, 1) } // Compute and return the updated sum of squares. return impl.Dlassq(n, rhs, 1, rdscal, rdsum) } // Apply permutations ipiv to rhs impl.Dlaswp(1, rhs, 1, 0, n-2, ipiv[:n-1], 1) // Solve for L-part choosing rhs either to +1 or -1. pmone := -1.0 for j := 0; j < n-2; j++ { bp := rhs[j] + 1 bm := rhs[j] - 1 // Look-ahead for L-part rhs[0:n-2] = +1 or -1, splus and sminu computed // more efficiently than in https://doi.org/10.1109/9.29404. splus := 1 + bi.Ddot(n-j-1, z[(j+1)*ldz+j:], ldz, z[(j+1)*ldz+j:], ldz) sminu := bi.Ddot(n-j-1, z[(j+1)*ldz+j:], ldz, rhs[j+1:], 1) splus *= rhs[j] switch { case splus > sminu: rhs[j] = bp case sminu > splus: rhs[j] = bm default: // In this case the updating sums are equal and we can choose rsh[j] // +1 or -1. The first time this happens we choose -1, thereafter // +1. This is a simple way to get good estimates of matrices like // Byers well-known example (see https://doi.org/10.1109/9.29404). rhs[j] += pmone pmone = 1 } // Compute remaining rhs. bi.Daxpy(n-j-1, -rhs[j], z[(j+1)*ldz+j:], ldz, rhs[j+1:], 1) } // Solve for U-part, look-ahead for rhs[n-1] = ±1. This is not done in // Bsolve and will hopefully give us a better estimate because any // ill-conditioning of the original matrix is transferred to U and not to L. // U[n-1,n-1] is an approximation to sigma_min(LU). bi.Dcopy(n-1, rhs, 1, xp, 1) xp[n-1] = rhs[n-1] + 1 rhs[n-1] -= 1 var splus, sminu float64 for i := n - 1; i >= 0; i-- { tmp := 1 / z[i*ldz+i] xp[i] *= tmp rhs[i] *= tmp for k := i + 1; k < n; k++ { xp[i] -= xp[k] * (z[i*ldz+k] * tmp) rhs[i] -= rhs[k] * (z[i*ldz+k] * tmp) } splus += math.Abs(xp[i]) sminu += math.Abs(rhs[i]) } if splus > sminu { bi.Dcopy(n, xp, 1, rhs, 1) } // Apply the permutations jpiv to the computed solution (rhs). impl.Dlaswp(1, rhs, 1, 0, n-2, jpiv[:n-1], -1) // Compute and return the updated sum of squares. return impl.Dlassq(n, rhs, 1, rdscal, rdsum) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlatrd.go000066400000000000000000000131551450372207100220240ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" ) // Dlatrd reduces nb rows and columns of a real n×n symmetric matrix A to symmetric // tridiagonal form. It computes the orthonormal similarity transformation // // Qᵀ * A * Q // // and returns the matrices V and W to apply to the unreduced part of A. If // uplo == blas.Upper, the upper triangle is supplied and the last nb rows are // reduced. If uplo == blas.Lower, the lower triangle is supplied and the first // nb rows are reduced. // // a contains the symmetric matrix on entry with active triangular half specified // by uplo. On exit, the nb columns have been reduced to tridiagonal form. The // diagonal contains the diagonal of the reduced matrix, the off-diagonal is // set to 1, and the remaining elements contain the data to construct Q. // // If uplo == blas.Upper, with n = 5 and nb = 2 on exit a is // // [ a a a v4 v5] // [ a a v4 v5] // [ a 1 v5] // [ d 1] // [ d] // // If uplo == blas.Lower, with n = 5 and nb = 2, on exit a is // // [ d ] // [ 1 d ] // [v1 1 a ] // [v1 v2 a a ] // [v1 v2 a a a] // // e contains the superdiagonal elements of the reduced matrix. If uplo == blas.Upper, // e[n-nb:n-1] contains the last nb columns of the reduced matrix, while if // uplo == blas.Lower, e[:nb] contains the first nb columns of the reduced matrix. // e must have length at least n-1, and Dlatrd will panic otherwise. // // tau contains the scalar factors of the elementary reflectors needed to construct Q. // The reflectors are stored in tau[n-nb:n-1] if uplo == blas.Upper, and in // tau[:nb] if uplo == blas.Lower. tau must have length n-1, and Dlatrd will panic // otherwise. // // w is an n×nb matrix. On exit it contains the data to update the unreduced part // of A. // // The matrix Q is represented as a product of elementary reflectors. Each reflector // H has the form // // I - tau * v * vᵀ // // If uplo == blas.Upper, // // Q = H_{n-1} * H_{n-2} * ... * H_{n-nb} // // where v[:i-1] is stored in A[:i-1,i], v[i-1] = 1, and v[i:n] = 0. // // If uplo == blas.Lower, // // Q = H_0 * H_1 * ... * H_{nb-1} // // where v[:i+1] = 0, v[i+1] = 1, and v[i+2:n] is stored in A[i+2:n,i]. // // The vectors v form the n×nb matrix V which is used with W to apply a // symmetric rank-2 update to the unreduced part of A // // A = A - V * Wᵀ - W * Vᵀ // // Dlatrd is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlatrd(uplo blas.Uplo, n, nb int, a []float64, lda int, e, tau, w []float64, ldw int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case nb < 0: panic(nbLT0) case nb > n: panic(nbGTN) case lda < max(1, n): panic(badLdA) case ldw < max(1, nb): panic(badLdW) } if n == 0 { return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(w) < (n-1)*ldw+nb: panic(shortW) case len(e) < n-1: panic(shortE) case len(tau) < n-1: panic(shortTau) } bi := blas64.Implementation() if uplo == blas.Upper { for i := n - 1; i >= n-nb; i-- { iw := i - n + nb if i < n-1 { // Update A(0:i, i). bi.Dgemv(blas.NoTrans, i+1, n-i-1, -1, a[i+1:], lda, w[i*ldw+iw+1:], 1, 1, a[i:], lda) bi.Dgemv(blas.NoTrans, i+1, n-i-1, -1, w[iw+1:], ldw, a[i*lda+i+1:], 1, 1, a[i:], lda) } if i > 0 { // Generate elementary reflector H_i to annihilate A(0:i-2,i). e[i-1], tau[i-1] = impl.Dlarfg(i, a[(i-1)*lda+i], a[i:], lda) a[(i-1)*lda+i] = 1 // Compute W(0:i-1, i). bi.Dsymv(blas.Upper, i, 1, a, lda, a[i:], lda, 0, w[iw:], ldw) if i < n-1 { bi.Dgemv(blas.Trans, i, n-i-1, 1, w[iw+1:], ldw, a[i:], lda, 0, w[(i+1)*ldw+iw:], ldw) bi.Dgemv(blas.NoTrans, i, n-i-1, -1, a[i+1:], lda, w[(i+1)*ldw+iw:], ldw, 1, w[iw:], ldw) bi.Dgemv(blas.Trans, i, n-i-1, 1, a[i+1:], lda, a[i:], lda, 0, w[(i+1)*ldw+iw:], ldw) bi.Dgemv(blas.NoTrans, i, n-i-1, -1, w[iw+1:], ldw, w[(i+1)*ldw+iw:], ldw, 1, w[iw:], ldw) } bi.Dscal(i, tau[i-1], w[iw:], ldw) alpha := -0.5 * tau[i-1] * bi.Ddot(i, w[iw:], ldw, a[i:], lda) bi.Daxpy(i, alpha, a[i:], lda, w[iw:], ldw) } } } else { // Reduce first nb columns of lower triangle. for i := 0; i < nb; i++ { // Update A(i:n, i) bi.Dgemv(blas.NoTrans, n-i, i, -1, a[i*lda:], lda, w[i*ldw:], 1, 1, a[i*lda+i:], lda) bi.Dgemv(blas.NoTrans, n-i, i, -1, w[i*ldw:], ldw, a[i*lda:], 1, 1, a[i*lda+i:], lda) if i < n-1 { // Generate elementary reflector H_i to annihilate A(i+2:n,i). e[i], tau[i] = impl.Dlarfg(n-i-1, a[(i+1)*lda+i], a[min(i+2, n-1)*lda+i:], lda) a[(i+1)*lda+i] = 1 // Compute W(i+1:n,i). bi.Dsymv(blas.Lower, n-i-1, 1, a[(i+1)*lda+i+1:], lda, a[(i+1)*lda+i:], lda, 0, w[(i+1)*ldw+i:], ldw) bi.Dgemv(blas.Trans, n-i-1, i, 1, w[(i+1)*ldw:], ldw, a[(i+1)*lda+i:], lda, 0, w[i:], ldw) bi.Dgemv(blas.NoTrans, n-i-1, i, -1, a[(i+1)*lda:], lda, w[i:], ldw, 1, w[(i+1)*ldw+i:], ldw) bi.Dgemv(blas.Trans, n-i-1, i, 1, a[(i+1)*lda:], lda, a[(i+1)*lda+i:], lda, 0, w[i:], ldw) bi.Dgemv(blas.NoTrans, n-i-1, i, -1, w[(i+1)*ldw:], ldw, w[i:], ldw, 1, w[(i+1)*ldw+i:], ldw) bi.Dscal(n-i-1, tau[i], w[(i+1)*ldw+i:], ldw) alpha := -0.5 * tau[i] * bi.Ddot(n-i-1, w[(i+1)*ldw+i:], ldw, a[(i+1)*lda+i:], lda) bi.Daxpy(n-i-1, alpha, a[(i+1)*lda+i:], lda, w[(i+1)*ldw+i:], ldw) } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlatrs.go000066400000000000000000000220371450372207100220420ustar00rootroot00000000000000// 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dlatrs solves a triangular system of equations scaled to prevent overflow. It // solves // // A * x = scale * b if trans == blas.NoTrans // Aᵀ * x = scale * b if trans == blas.Trans // // where the scale s is set for numeric stability. // // A is an n×n triangular matrix. On entry, the slice x contains the values of // b, and on exit it contains the solution vector x. // // If normin == true, cnorm is an input and cnorm[j] contains the norm of the off-diagonal // part of the j^th column of A. If trans == blas.NoTrans, cnorm[j] must be greater // than or equal to the infinity norm, and greater than or equal to the one-norm // otherwise. If normin == false, then cnorm is treated as an output, and is set // to contain the 1-norm of the off-diagonal part of the j^th column of A. // // Dlatrs is an internal routine. It is exported for testing purposes. func (impl Implementation) Dlatrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, normin bool, n int, a []float64, lda int, x []float64, cnorm []float64) (scale float64) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTrans) case diag != blas.Unit && diag != blas.NonUnit: panic(badDiag) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return 1 } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(x) < n: panic(shortX) case len(cnorm) < n: panic(shortCNorm) } upper := uplo == blas.Upper nonUnit := diag == blas.NonUnit smlnum := dlamchS / dlamchP bignum := 1 / smlnum scale = 1 bi := blas64.Implementation() if !normin { if upper { cnorm[0] = 0 for j := 1; j < n; j++ { cnorm[j] = bi.Dasum(j, a[j:], lda) } } else { for j := 0; j < n-1; j++ { cnorm[j] = bi.Dasum(n-j-1, a[(j+1)*lda+j:], lda) } cnorm[n-1] = 0 } } // Scale the column norms by tscal if the maximum element in cnorm is greater than bignum. imax := bi.Idamax(n, cnorm, 1) var tscal float64 if cnorm[imax] <= bignum { tscal = 1 } else { tmax := cnorm[imax] // Avoid NaN generation if entries in cnorm exceed the overflow // threshold. if tmax <= math.MaxFloat64 { // Case 1: All entries in cnorm are valid floating-point numbers. tscal = 1 / (smlnum * tmax) bi.Dscal(n, tscal, cnorm, 1) } else { // Case 2: At least one column norm of A cannot be represented as // floating-point number. Find the offdiagonal entry A[i,j] with the // largest absolute value. If this entry is not +/- Infinity, use // this value as tscal. tmax = 0 if upper { // A is upper triangular. for j := 1; j < n; j++ { tmax = math.Max(impl.Dlange(lapack.MaxAbs, j, 1, a[j:], lda, nil), tmax) } } else { // A is lower triangular. for j := 0; j < n-1; j++ { tmax = math.Max(impl.Dlange(lapack.MaxAbs, n-j-1, 1, a[(j+1)*lda+j:], lda, nil), tmax) } } if tmax <= math.MaxFloat64 { tscal = 1 / (smlnum * tmax) for j := 0; j < n; j++ { if cnorm[j] <= math.MaxFloat64 { cnorm[j] *= tscal } else { // Recompute the 1-norm without introducing Infinity in // the summation. cnorm[j] = 0 if upper { for i := 0; i < j; i++ { cnorm[j] += tscal * math.Abs(a[i*lda+j]) } } else { for i := j + 1; i < n; i++ { cnorm[j] += tscal * math.Abs(a[i*lda+j]) } } } } } else { // At least one entry of A is not a valid floating-point entry. // Rely on Dtrsv to propagate Inf and NaN. bi.Dtrsv(uplo, trans, diag, n, a, lda, x, 1) return } } } // Compute a bound on the computed solution vector to see if bi.Dtrsv can be used. j := bi.Idamax(n, x, 1) xmax := math.Abs(x[j]) xbnd := xmax var grow float64 var jfirst, jlast, jinc int if trans == blas.NoTrans { if upper { jfirst = n - 1 jlast = -1 jinc = -1 } else { jfirst = 0 jlast = n jinc = 1 } // Compute the growth in A * x = b. if tscal != 1 { grow = 0 goto Solve } if nonUnit { grow = 1 / math.Max(xbnd, smlnum) xbnd = grow for j := jfirst; j != jlast; j += jinc { if grow <= smlnum { goto Solve } tjj := math.Abs(a[j*lda+j]) xbnd = math.Min(xbnd, math.Min(1, tjj)*grow) if tjj+cnorm[j] >= smlnum { grow *= tjj / (tjj + cnorm[j]) } else { grow = 0 } } grow = xbnd } else { grow = math.Min(1, 1/math.Max(xbnd, smlnum)) for j := jfirst; j != jlast; j += jinc { if grow <= smlnum { goto Solve } grow *= 1 / (1 + cnorm[j]) } } } else { if upper { jfirst = 0 jlast = n jinc = 1 } else { jfirst = n - 1 jlast = -1 jinc = -1 } if tscal != 1 { grow = 0 goto Solve } if nonUnit { grow = 1 / (math.Max(xbnd, smlnum)) xbnd = grow for j := jfirst; j != jlast; j += jinc { if grow <= smlnum { goto Solve } xj := 1 + cnorm[j] grow = math.Min(grow, xbnd/xj) tjj := math.Abs(a[j*lda+j]) if xj > tjj { xbnd *= tjj / xj } } grow = math.Min(grow, xbnd) } else { grow = math.Min(1, 1/math.Max(xbnd, smlnum)) for j := jfirst; j != jlast; j += jinc { if grow <= smlnum { goto Solve } xj := 1 + cnorm[j] grow /= xj } } } Solve: if grow*tscal > smlnum { // Use the Level 2 BLAS solve if the reciprocal of the bound on // elements of X is not too small. bi.Dtrsv(uplo, trans, diag, n, a, lda, x, 1) if tscal != 1 { bi.Dscal(n, 1/tscal, cnorm, 1) } return scale } // Use a Level 1 BLAS solve, scaling intermediate results. if xmax > bignum { scale = bignum / xmax bi.Dscal(n, scale, x, 1) xmax = bignum } if trans == blas.NoTrans { for j := jfirst; j != jlast; j += jinc { xj := math.Abs(x[j]) var tjj, tjjs float64 if nonUnit { tjjs = a[j*lda+j] * tscal } else { tjjs = tscal if tscal == 1 { goto Skip1 } } tjj = math.Abs(tjjs) if tjj > smlnum { if tjj < 1 { if xj > tjj*bignum { rec := 1 / xj bi.Dscal(n, rec, x, 1) scale *= rec xmax *= rec } } x[j] /= tjjs xj = math.Abs(x[j]) } else if tjj > 0 { if xj > tjj*bignum { rec := (tjj * bignum) / xj if cnorm[j] > 1 { rec /= cnorm[j] } bi.Dscal(n, rec, x, 1) scale *= rec xmax *= rec } x[j] /= tjjs xj = math.Abs(x[j]) } else { for i := 0; i < n; i++ { x[i] = 0 } x[j] = 1 xj = 1 scale = 0 xmax = 0 } Skip1: if xj > 1 { rec := 1 / xj if cnorm[j] > (bignum-xmax)*rec { rec *= 0.5 bi.Dscal(n, rec, x, 1) scale *= rec } } else if xj*cnorm[j] > bignum-xmax { bi.Dscal(n, 0.5, x, 1) scale *= 0.5 } if upper { if j > 0 { bi.Daxpy(j, -x[j]*tscal, a[j:], lda, x, 1) i := bi.Idamax(j, x, 1) xmax = math.Abs(x[i]) } } else { if j < n-1 { bi.Daxpy(n-j-1, -x[j]*tscal, a[(j+1)*lda+j:], lda, x[j+1:], 1) i := j + bi.Idamax(n-j-1, x[j+1:], 1) xmax = math.Abs(x[i]) } } } } else { for j := jfirst; j != jlast; j += jinc { xj := math.Abs(x[j]) uscal := tscal rec := 1 / math.Max(xmax, 1) var tjjs float64 if cnorm[j] > (bignum-xj)*rec { rec *= 0.5 if nonUnit { tjjs = a[j*lda+j] * tscal } else { tjjs = tscal } tjj := math.Abs(tjjs) if tjj > 1 { rec = math.Min(1, rec*tjj) uscal /= tjjs } if rec < 1 { bi.Dscal(n, rec, x, 1) scale *= rec xmax *= rec } } var sumj float64 if uscal == 1 { if upper { sumj = bi.Ddot(j, a[j:], lda, x, 1) } else if j < n-1 { sumj = bi.Ddot(n-j-1, a[(j+1)*lda+j:], lda, x[j+1:], 1) } } else { if upper { for i := 0; i < j; i++ { sumj += (a[i*lda+j] * uscal) * x[i] } } else if j < n { for i := j + 1; i < n; i++ { sumj += (a[i*lda+j] * uscal) * x[i] } } } if uscal == tscal { x[j] -= sumj xj := math.Abs(x[j]) var tjjs float64 if nonUnit { tjjs = a[j*lda+j] * tscal } else { tjjs = tscal if tscal == 1 { goto Skip2 } } tjj := math.Abs(tjjs) if tjj > smlnum { if tjj < 1 { if xj > tjj*bignum { rec = 1 / xj bi.Dscal(n, rec, x, 1) scale *= rec xmax *= rec } } x[j] /= tjjs } else if tjj > 0 { if xj > tjj*bignum { rec = (tjj * bignum) / xj bi.Dscal(n, rec, x, 1) scale *= rec xmax *= rec } x[j] /= tjjs } else { for i := 0; i < n; i++ { x[i] = 0 } x[j] = 1 scale = 0 xmax = 0 } } else { x[j] = x[j]/tjjs - sumj } Skip2: xmax = math.Max(xmax, math.Abs(x[j])) } } scale /= tscal if tscal != 1 { bi.Dscal(n, 1/tscal, cnorm, 1) } return scale } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlauu2.go000066400000000000000000000030441450372207100217420ustar00rootroot00000000000000// 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/blas/blas64" ) // Dlauu2 computes the product // // U * Uᵀ if uplo is blas.Upper // Lᵀ * L if uplo is blas.Lower // // where U or L is stored in the upper or lower triangular part of A. // Only the upper or lower triangle of the result is stored, overwriting // the corresponding factor in A. func (impl Implementation) Dlauu2(uplo blas.Uplo, n int, a []float64, lda int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return } if len(a) < (n-1)*lda+n { panic(shortA) } bi := blas64.Implementation() if uplo == blas.Upper { // Compute the product U*Uᵀ. for i := 0; i < n; i++ { aii := a[i*lda+i] if i < n-1 { a[i*lda+i] = bi.Ddot(n-i, a[i*lda+i:], 1, a[i*lda+i:], 1) bi.Dgemv(blas.NoTrans, i, n-i-1, 1, a[i+1:], lda, a[i*lda+i+1:], 1, aii, a[i:], lda) } else { bi.Dscal(i+1, aii, a[i:], lda) } } } else { // Compute the product Lᵀ*L. for i := 0; i < n; i++ { aii := a[i*lda+i] if i < n-1 { a[i*lda+i] = bi.Ddot(n-i, a[i*lda+i:], lda, a[i*lda+i:], lda) bi.Dgemv(blas.Trans, n-i-1, i, 1, a[(i+1)*lda:], lda, a[(i+1)*lda+i:], lda, aii, a[i*lda:], 1) } else { bi.Dscal(i+1, aii, a[i*lda:], 1) } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dlauum.go000066400000000000000000000041741450372207100220420ustar00rootroot00000000000000// 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/blas/blas64" ) // Dlauum computes the product // // U * Uᵀ if uplo is blas.Upper // Lᵀ * L if uplo is blas.Lower // // where U or L is stored in the upper or lower triangular part of A. // Only the upper or lower triangle of the result is stored, overwriting // the corresponding factor in A. func (impl Implementation) Dlauum(uplo blas.Uplo, n int, a []float64, lda int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return } if len(a) < (n-1)*lda+n { panic(shortA) } // Determine the block size. opts := "U" if uplo == blas.Lower { opts = "L" } nb := impl.Ilaenv(1, "DLAUUM", opts, n, -1, -1, -1) if nb <= 1 || n <= nb { // Use unblocked code. impl.Dlauu2(uplo, n, a, lda) return } // Use blocked code. bi := blas64.Implementation() if uplo == blas.Upper { // Compute the product U*Uᵀ. for i := 0; i < n; i += nb { ib := min(nb, n-i) bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.NonUnit, i, ib, 1, a[i*lda+i:], lda, a[i:], lda) impl.Dlauu2(blas.Upper, ib, a[i*lda+i:], lda) if n-i-ib > 0 { bi.Dgemm(blas.NoTrans, blas.Trans, i, ib, n-i-ib, 1, a[i+ib:], lda, a[i*lda+i+ib:], lda, 1, a[i:], lda) bi.Dsyrk(blas.Upper, blas.NoTrans, ib, n-i-ib, 1, a[i*lda+i+ib:], lda, 1, a[i*lda+i:], lda) } } } else { // Compute the product Lᵀ*L. for i := 0; i < n; i += nb { ib := min(nb, n-i) bi.Dtrmm(blas.Left, blas.Lower, blas.Trans, blas.NonUnit, ib, i, 1, a[i*lda+i:], lda, a[i*lda:], lda) impl.Dlauu2(blas.Lower, ib, a[i*lda+i:], lda) if n-i-ib > 0 { bi.Dgemm(blas.Trans, blas.NoTrans, ib, i, n-i-ib, 1, a[(i+ib)*lda+i:], lda, a[(i+ib)*lda:], lda, 1, a[i*lda:], lda) bi.Dsyrk(blas.Lower, blas.Trans, ib, n-i-ib, 1, a[(i+ib)*lda+i:], lda, 1, a[i*lda+i:], lda) } } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/doc.go000066400000000000000000000031011450372207100213050ustar00rootroot00000000000000// 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 is a pure-go implementation of the LAPACK API. The LAPACK API defines // a set of algorithms for advanced matrix operations. // // The function definitions and implementations follow that of the netlib reference // implementation. See http://www.netlib.org/lapack/explore-html/ for more // information, and http://www.netlib.org/lapack/explore-html/d4/de1/_l_i_c_e_n_s_e_source.html // for more license information. // // Slice function arguments frequently represent vectors and matrices. The data // layout is identical to that found in https://pkg.go.dev/gonum.org/v1/gonum/blas/gonum. // // Most LAPACK functions are built on top the routines defined in the BLAS API, // and as such the computation time for many LAPACK functions is // dominated by BLAS calls. Here, BLAS is accessed through the // blas64 package (https://pkg.go.dev/gonum.org/v1/gonum/blas/blas64). In particular, // this implies that an external BLAS library will be used if it is // registered in blas64. // // The full LAPACK capability has not been implemented at present. The full // API is very large, containing approximately 200 functions for double precision // alone. Future additions will be focused on supporting the Gonum matrix // package (https://pkg.go.dev/gonum.org/v1/gonum/mat), though pull requests // with implementations and tests for LAPACK function are encouraged. package gonum // import "gonum.org/v1/gonum/lapack/gonum" golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorg2l.go000066400000000000000000000034531450372207100217430ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" ) // Dorg2l generates an m×n matrix Q with orthonormal columns which is defined // as the last n columns of a product of k elementary reflectors of order m. // // Q = H_{k-1} * ... * H_1 * H_0 // // See Dgelqf for more information. It must be that m >= n >= k. // // tau contains the scalar reflectors computed by Dgeqlf. tau must have length // at least k, and Dorg2l will panic otherwise. // // work contains temporary memory, and must have length at least n. Dorg2l will // panic otherwise. // // Dorg2l is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorg2l(m, n, k int, a []float64, lda int, tau, work []float64) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case n > m: panic(nGTM) case k < 0: panic(kLT0) case k > n: panic(kGTN) case lda < max(1, n): panic(badLdA) } if n == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) case len(work) < n: panic(shortWork) } // Initialize columns 0:n-k to columns of the unit matrix. for j := 0; j < n-k; j++ { for l := 0; l < m; l++ { a[l*lda+j] = 0 } a[(m-n+j)*lda+j] = 1 } bi := blas64.Implementation() for i := 0; i < k; i++ { ii := n - k + i // Apply H_i to A[0:m-k+i, 0:n-k+i] from the left. a[(m-n+ii)*lda+ii] = 1 impl.Dlarf(blas.Left, m-n+ii+1, ii, a[ii:], lda, tau[i], a, lda, work) bi.Dscal(m-n+ii, -tau[i], a[ii:], lda) a[(m-n+ii)*lda+ii] = 1 - tau[i] // Set A[m-k+i:m, n-k+i+1] to zero. for l := m - n + ii + 1; l < m; l++ { a[l*lda+ii] = 0 } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorg2r.go000066400000000000000000000031411450372207100217430ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dorg2r generates an m×n matrix Q with orthonormal columns defined by the // product of elementary reflectors as computed by Dgeqrf. // // Q = H_0 * H_1 * ... * H_{k-1} // // len(tau) >= k, 0 <= k <= n, 0 <= n <= m, len(work) >= n. // Dorg2r will panic if these conditions are not met. // // Dorg2r is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorg2r(m, n, k int, a []float64, lda int, tau []float64, work []float64) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case n > m: panic(nGTM) case k < 0: panic(kLT0) case k > n: panic(kGTN) case lda < max(1, n): panic(badLdA) } if n == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) case len(work) < n: panic(shortWork) } bi := blas64.Implementation() // Initialize columns k+1:n to columns of the unit matrix. for l := 0; l < m; l++ { for j := k; j < n; j++ { a[l*lda+j] = 0 } } for j := k; j < n; j++ { a[j*lda+j] = 1 } for i := k - 1; i >= 0; i-- { for i := range work { work[i] = 0 } if i < n-1 { a[i*lda+i] = 1 impl.Dlarf(blas.Left, m-i, n-i-1, a[i*lda+i:], lda, tau[i], a[i*lda+i+1:], lda, work) } if i < m-1 { bi.Dscal(m-i-1, -tau[i], a[(i+1)*lda+i:], lda) } a[i*lda+i] = 1 - tau[i] for l := 0; l < i; l++ { a[l*lda+i] = 0 } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorgbr.go000066400000000000000000000075141450372207100220330ustar00rootroot00000000000000// 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/lapack" // Dorgbr generates one of the matrices Q or Pᵀ computed by Dgebrd // computed from the decomposition Dgebrd. See Dgebd2 for the description of // Q and Pᵀ. // // If vect == lapack.GenerateQ, then a is assumed to have been an m×k matrix and // Q is of order m. If m >= k, then Dorgbr returns the first n columns of Q // where m >= n >= k. If m < k, then Dorgbr returns Q as an m×m matrix. // // If vect == lapack.GeneratePT, then A is assumed to have been a k×n matrix, and // Pᵀ is of order n. If k < n, then Dorgbr returns the first m rows of Pᵀ, // where n >= m >= k. If k >= n, then Dorgbr returns Pᵀ as an n×n matrix. // // Dorgbr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorgbr(vect lapack.GenOrtho, m, n, k int, a []float64, lda int, tau, work []float64, lwork int) { wantq := vect == lapack.GenerateQ mn := min(m, n) switch { case vect != lapack.GenerateQ && vect != lapack.GeneratePT: panic(badGenOrtho) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case wantq && n > m: panic(nGTM) case wantq && n < min(m, k): panic("lapack: n < min(m,k)") case !wantq && m > n: panic(mGTN) case !wantq && m < min(n, k): panic("lapack: m < min(n,k)") case lda < max(1, n) && lwork != -1: // Normally, we follow the reference and require the leading // dimension to be always valid, even in case of workspace // queries. However, if a caller provided a placeholder value // for lda (and a) when doing a workspace query that didn't // fulfill the condition here, it would cause a panic. This is // exactly what Dgesvd does. panic(badLdA) case lwork < max(1, mn) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. work[0] = 1 if m == 0 || n == 0 { return } if wantq { if m >= k { impl.Dorgqr(m, n, k, a, lda, tau, work, -1) } else if m > 1 { impl.Dorgqr(m-1, m-1, m-1, a[lda+1:], lda, tau, work, -1) } } else { if k < n { impl.Dorglq(m, n, k, a, lda, tau, work, -1) } else if n > 1 { impl.Dorglq(n-1, n-1, n-1, a[lda+1:], lda, tau, work, -1) } } lworkopt := int(work[0]) lworkopt = max(lworkopt, mn) if lwork == -1 { work[0] = float64(lworkopt) return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case wantq && len(tau) < min(m, k): panic(shortTau) case !wantq && len(tau) < min(n, k): panic(shortTau) } if wantq { // Form Q, determined by a call to Dgebrd to reduce an m×k matrix. if m >= k { impl.Dorgqr(m, n, k, a, lda, tau, work, lwork) } else { // Shift the vectors which define the elementary reflectors one // column to the right, and set the first row and column of Q to // those of the unit matrix. for j := m - 1; j >= 1; j-- { a[j] = 0 for i := j + 1; i < m; i++ { a[i*lda+j] = a[i*lda+j-1] } } a[0] = 1 for i := 1; i < m; i++ { a[i*lda] = 0 } if m > 1 { // Form Q[1:m-1, 1:m-1] impl.Dorgqr(m-1, m-1, m-1, a[lda+1:], lda, tau, work, lwork) } } } else { // Form Pᵀ, determined by a call to Dgebrd to reduce a k×n matrix. if k < n { impl.Dorglq(m, n, k, a, lda, tau, work, lwork) } else { // Shift the vectors which define the elementary reflectors one // row downward, and set the first row and column of Pᵀ to // those of the unit matrix. a[0] = 1 for i := 1; i < n; i++ { a[i*lda] = 0 } for j := 1; j < n; j++ { for i := j - 1; i >= 1; i-- { a[i*lda+j] = a[(i-1)*lda+j] } a[j] = 0 } if n > 1 { impl.Dorglq(n-1, n-1, n-1, a[lda+1:], lda, tau, work, lwork) } } } work[0] = float64(lworkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorghr.go000066400000000000000000000055131450372207100220360ustar00rootroot00000000000000// Copyright ©2016 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 // Dorghr generates an n×n orthogonal matrix Q which is defined as the product // of ihi-ilo elementary reflectors: // // Q = H_{ilo} H_{ilo+1} ... H_{ihi-1}. // // a and lda represent an n×n matrix that contains the elementary reflectors, as // returned by Dgehrd. On return, a is overwritten by the n×n orthogonal matrix // Q. Q will be equal to the identity matrix except in the submatrix // Q[ilo+1:ihi+1,ilo+1:ihi+1]. // // ilo and ihi must have the same values as in the previous call of Dgehrd. It // must hold that // // 0 <= ilo <= ihi < n if n > 0, // ilo = 0, ihi = -1 if n == 0. // // tau contains the scalar factors of the elementary reflectors, as returned by // Dgehrd. tau must have length n-1. // // work must have length at least max(1,lwork) and lwork must be at least // ihi-ilo. For optimum performance lwork must be at least (ihi-ilo)*nb where nb // is the optimal blocksize. On return, work[0] will contain the optimal value // of lwork. // // If lwork == -1, instead of performing Dorghr, only the optimal value of lwork // will be stored into work[0]. // // If any requirement on input sizes is not met, Dorghr will panic. // // Dorghr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorghr(n, ilo, ihi int, a []float64, lda int, tau, work []float64, lwork int) { nh := ihi - ilo switch { case ilo < 0 || max(1, n) <= ilo: panic(badIlo) case ihi < min(ilo, n-1) || n <= ihi: panic(badIhi) case lda < max(1, n): panic(badLdA) case lwork < max(1, nh) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if n == 0 { work[0] = 1 return } lwkopt := max(1, nh) * impl.Ilaenv(1, "DORGQR", " ", nh, nh, nh, -1) if lwork == -1 { work[0] = float64(lwkopt) return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(tau) < n-1: panic(shortTau) } // Shift the vectors which define the elementary reflectors one column // to the right. for i := ilo + 2; i < ihi+1; i++ { copy(a[i*lda+ilo+1:i*lda+i], a[i*lda+ilo:i*lda+i-1]) } // Set the first ilo+1 and the last n-ihi-1 rows and columns to those of // the identity matrix. for i := 0; i < ilo+1; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 } a[i*lda+i] = 1 } for i := ilo + 1; i < ihi+1; i++ { for j := 0; j <= ilo; j++ { a[i*lda+j] = 0 } for j := i; j < n; j++ { a[i*lda+j] = 0 } } for i := ihi + 1; i < n; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 } a[i*lda+i] = 1 } if nh > 0 { // Generate Q[ilo+1:ihi+1,ilo+1:ihi+1]. impl.Dorgqr(nh, nh, nh, a[(ilo+1)*lda+ilo+1:], lda, tau[ilo:ihi], work, lwork) } work[0] = float64(lwkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorgl2.go000066400000000000000000000027671450372207100217520ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dorgl2 generates an m×n matrix Q with orthonormal rows defined by the // first m rows product of elementary reflectors as computed by Dgelqf. // // Q = H_0 * H_1 * ... * H_{k-1} // // len(tau) >= k, 0 <= k <= m, 0 <= m <= n, len(work) >= m. // Dorgl2 will panic if these conditions are not met. // // Dorgl2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorgl2(m, n, k int, a []float64, lda int, tau, work []float64) { switch { case m < 0: panic(mLT0) case n < m: panic(nLTM) case k < 0: panic(kLT0) case k > m: panic(kGTM) case lda < max(1, m): panic(badLdA) } if m == 0 { return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) case len(work) < m: panic(shortWork) } bi := blas64.Implementation() if k < m { for i := k; i < m; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 } } for j := k; j < m; j++ { a[j*lda+j] = 1 } } for i := k - 1; i >= 0; i-- { if i < n-1 { if i < m-1 { a[i*lda+i] = 1 impl.Dlarf(blas.Right, m-i-1, n-i, a[i*lda+i:], 1, tau[i], a[(i+1)*lda+i:], lda, work) } bi.Dscal(n-i-1, -tau[i], a[i*lda+i+1:], 1) } a[i*lda+i] = 1 - tau[i] for l := 0; l < i; l++ { a[i*lda+l] = 0 } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorglq.go000066400000000000000000000057251450372207100220460ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dorglq generates an m×n matrix Q with orthonormal columns defined by the // product of elementary reflectors as computed by Dgelqf. // // Q = H_0 * H_1 * ... * H_{k-1} // // Dorglq is the blocked version of Dorgl2 that makes greater use of level-3 BLAS // routines. // // len(tau) >= k, 0 <= k <= m, and 0 <= m <= n. // // work is temporary storage, and lwork specifies the usable memory length. At minimum, // lwork >= m, and the amount of blocking is limited by the usable length. // If lwork == -1, instead of computing Dorglq the optimal work length is stored // into work[0]. // // Dorglq will panic if the conditions on input values are not met. // // Dorglq is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorglq(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) { switch { case m < 0: panic(mLT0) case n < m: panic(nLTM) case k < 0: panic(kLT0) case k > m: panic(kGTM) case lda < max(1, n): panic(badLdA) case lwork < max(1, m) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } if m == 0 { work[0] = 1 return } nb := impl.Ilaenv(1, "DORGLQ", " ", m, n, k, -1) if lwork == -1 { work[0] = float64(m * nb) return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) } nbmin := 2 // Minimum block size var nx int // Crossover size from blocked to unblocked code iws := m // Length of work needed var ldwork int if 1 < nb && nb < k { nx = max(0, impl.Ilaenv(3, "DORGLQ", " ", m, n, k, -1)) if nx < k { ldwork = nb iws = m * ldwork if lwork < iws { nb = lwork / m ldwork = nb nbmin = max(2, impl.Ilaenv(2, "DORGLQ", " ", m, n, k, -1)) } } } var ki, kk int if nbmin <= nb && nb < k && nx < k { // The first kk rows are handled by the blocked method. ki = ((k - nx - 1) / nb) * nb kk = min(k, ki+nb) for i := kk; i < m; i++ { for j := 0; j < kk; j++ { a[i*lda+j] = 0 } } } if kk < m { // Perform the operation on columns kk to the end. impl.Dorgl2(m-kk, n-kk, k-kk, a[kk*lda+kk:], lda, tau[kk:], work) } if kk > 0 { // Perform the operation on column-blocks for i := ki; i >= 0; i -= nb { ib := min(nb, k-i) if i+ib < m { impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib, a[i*lda+i:], lda, tau[i:], work, ldwork) impl.Dlarfb(blas.Right, blas.Trans, lapack.Forward, lapack.RowWise, m-i-ib, n-i, ib, a[i*lda+i:], lda, work, ldwork, a[(i+ib)*lda+i:], lda, work[ib*ldwork:], ldwork) } impl.Dorgl2(ib, n-i, ib, a[i*lda+i:], lda, tau[i:], work) for l := i; l < i+ib; l++ { for j := 0; j < i; j++ { a[l*lda+j] = 0 } } } } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorgql.go000066400000000000000000000071261450372207100220430ustar00rootroot00000000000000// Copyright ©2016 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/lapack" ) // Dorgql generates the m×n matrix Q with orthonormal columns defined as the // last n columns of a product of k elementary reflectors of order m // // Q = H_{k-1} * ... * H_1 * H_0. // // It must hold that // // 0 <= k <= n <= m, // // and Dorgql will panic otherwise. // // On entry, the (n-k+i)-th column of A must contain the vector which defines // the elementary reflector H_i, for i=0,...,k-1, and tau[i] must contain its // scalar factor. On return, a contains the m×n matrix Q. // // tau must have length at least k, and Dorgql will panic otherwise. // // work must have length at least max(1,lwork), and lwork must be at least // max(1,n), otherwise Dorgql will panic. For optimum performance lwork must // be a sufficiently large multiple of n. // // If lwork == -1, instead of computing Dorgql the optimal work length is stored // into work[0]. // // Dorgql is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorgql(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case n > m: panic(nGTM) case k < 0: panic(kLT0) case k > n: panic(kGTN) case lda < max(1, n): panic(badLdA) case lwork < max(1, n) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if n == 0 { work[0] = 1 return } nb := impl.Ilaenv(1, "DORGQL", " ", m, n, k, -1) if lwork == -1 { work[0] = float64(n * nb) return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) } nbmin := 2 var nx, ldwork int iws := n if 1 < nb && nb < k { // Determine when to cross over from blocked to unblocked code. nx = max(0, impl.Ilaenv(3, "DORGQL", " ", m, n, k, -1)) if nx < k { // Determine if workspace is large enough for blocked code. iws = n * nb if lwork < iws { // Not enough workspace to use optimal nb: reduce nb and determine // the minimum value of nb. nb = lwork / n nbmin = max(2, impl.Ilaenv(2, "DORGQL", " ", m, n, k, -1)) } ldwork = nb } } var kk int if nbmin <= nb && nb < k && nx < k { // Use blocked code after the first block. The last kk columns are handled // by the block method. kk = min(k, ((k-nx+nb-1)/nb)*nb) // Set A(m-kk:m, 0:n-kk) to zero. for i := m - kk; i < m; i++ { for j := 0; j < n-kk; j++ { a[i*lda+j] = 0 } } } // Use unblocked code for the first or only block. impl.Dorg2l(m-kk, n-kk, k-kk, a, lda, tau, work) if kk > 0 { // Use blocked code. for i := k - kk; i < k; i += nb { ib := min(nb, k-i) if n-k+i > 0 { // Form the triangular factor of the block reflector // H = H_{i+ib-1} * ... * H_{i+1} * H_i. impl.Dlarft(lapack.Backward, lapack.ColumnWise, m-k+i+ib, ib, a[n-k+i:], lda, tau[i:], work, ldwork) // Apply H to A[0:m-k+i+ib, 0:n-k+i] from the left. impl.Dlarfb(blas.Left, blas.NoTrans, lapack.Backward, lapack.ColumnWise, m-k+i+ib, n-k+i, ib, a[n-k+i:], lda, work, ldwork, a, lda, work[ib*ldwork:], ldwork) } // Apply H to rows 0:m-k+i+ib of current block. impl.Dorg2l(m-k+i+ib, ib, ib, a[n-k+i:], lda, tau[i:], work) // Set rows m-k+i+ib:m of current block to zero. for j := n - k + i; j < n-k+i+ib; j++ { for l := m - k + i + ib; l < m; l++ { a[l*lda+j] = 0 } } } } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorgqr.go000066400000000000000000000070231450372207100220450ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dorgqr generates an m×n matrix Q with orthonormal columns defined by the // product of elementary reflectors // // Q = H_0 * H_1 * ... * H_{k-1} // // as computed by Dgeqrf. // Dorgqr is the blocked version of Dorg2r that makes greater use of level-3 BLAS // routines. // // The length of tau must be at least k, and the length of work must be at least n. // It also must be that 0 <= k <= n and 0 <= n <= m. // // work is temporary storage, and lwork specifies the usable memory length. At // minimum, lwork >= n, and the amount of blocking is limited by the usable // length. If lwork == -1, instead of computing Dorgqr the optimal work length // is stored into work[0]. // // Dorgqr will panic if the conditions on input values are not met. // // Dorgqr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorgqr(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case n > m: panic(nGTM) case k < 0: panic(kLT0) case k > n: panic(kGTN) case lda < max(1, n) && lwork != -1: // Normally, we follow the reference and require the leading // dimension to be always valid, even in case of workspace // queries. However, if a caller provided a placeholder value // for lda (and a) when doing a workspace query that didn't // fulfill the condition here, it would cause a panic. This is // exactly what Dgesvd does. panic(badLdA) case lwork < max(1, n) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } if n == 0 { work[0] = 1 return } nb := impl.Ilaenv(1, "DORGQR", " ", m, n, k, -1) // work is treated as an n×nb matrix if lwork == -1 { work[0] = float64(n * nb) return } switch { case len(a) < (m-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) } nbmin := 2 // Minimum block size var nx int // Crossover size from blocked to unblocked code iws := n // Length of work needed var ldwork int if 1 < nb && nb < k { nx = max(0, impl.Ilaenv(3, "DORGQR", " ", m, n, k, -1)) if nx < k { ldwork = nb iws = n * ldwork if lwork < iws { nb = lwork / n ldwork = nb nbmin = max(2, impl.Ilaenv(2, "DORGQR", " ", m, n, k, -1)) } } } var ki, kk int if nbmin <= nb && nb < k && nx < k { // The first kk columns are handled by the blocked method. ki = ((k - nx - 1) / nb) * nb kk = min(k, ki+nb) for i := 0; i < kk; i++ { for j := kk; j < n; j++ { a[i*lda+j] = 0 } } } if kk < n { // Perform the operation on columns kk to the end. impl.Dorg2r(m-kk, n-kk, k-kk, a[kk*lda+kk:], lda, tau[kk:], work) } if kk > 0 { // Perform the operation on column-blocks. for i := ki; i >= 0; i -= nb { ib := min(nb, k-i) if i+ib < n { impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib, a[i*lda+i:], lda, tau[i:], work, ldwork) impl.Dlarfb(blas.Left, blas.NoTrans, lapack.Forward, lapack.ColumnWise, m-i, n-i-ib, ib, a[i*lda+i:], lda, work, ldwork, a[i*lda+i+ib:], lda, work[ib*ldwork:], ldwork) } impl.Dorg2r(m-i, ib, ib, a[i*lda+i:], lda, tau[i:], work) // Set rows 0:i-1 of current block to zero. for j := i; j < i+ib; j++ { for l := 0; l < i; l++ { a[l*lda+j] = 0 } } } } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorgr2.go000066400000000000000000000037501450372207100217510ustar00rootroot00000000000000// Copyright ©2021 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/blas/blas64" ) // Dorgr2 generates an m×n real matrix Q with orthonormal rows, which is defined // as the last m rows of a product of k elementary reflectors of order n // // Q = H_0 * H_1 * ... * H_{k-1} // // as returned by Dgerqf. // // On entry, the (m-k+i)-th row of A must contain the vector which defines the // elementary reflector H_i, for i = 0,1,...,k, as returned by Dgerqf. On // return, A will contain the m×n matrix Q. // // The i-th element of tau must contain the scalar factor of the elementary // reflector H_i, as returned by Dgerqf. // // It must hold that // // n >= m >= k >= 0, // // the length of tau must be k and the length of work must be m, otherwise // Dorgr2 will panic. // // Dorgr2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorgr2(m, n, k int, a []float64, lda int, tau, work []float64) { switch { case k < 0: panic(kLT0) case m < k: panic(kGTM) case n < m: panic(mGTN) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if m == 0 { return } switch { case len(tau) != k: panic(badLenTau) case len(a) < (m-1)*lda+n: panic(shortA) case len(work) < m: panic(shortWork) } // Initialise rows 0:m-k to rows of the unit matrix. for l := 0; l < m-k; l++ { row := a[l*lda : l*lda+n] for j := range row { row[j] = 0 } a[l*lda+n-m+l] = 1 } bi := blas64.Implementation() for i := 0; i < k; i++ { ii := m - k + i // Apply H_i to A[0:m-k+i+1, 0:n-k+i+1] from the right. a[ii*lda+n-m+ii] = 1 impl.Dlarf(blas.Right, ii, n-m+ii+1, a[ii*lda:], 1, tau[i], a, lda, work) bi.Dscal(n-m+ii, -tau[i], a[ii*lda:], 1) a[ii*lda+n-m+ii] = 1 - tau[i] // Set A[m-k+i, n-k+i:n] to zero. for l := n - m + ii + 1; l < n; l++ { a[ii*lda+l] = 0 } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorgtr.go000066400000000000000000000056441450372207100220570ustar00rootroot00000000000000// Copyright ©2016 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" // Dorgtr generates a real orthogonal matrix Q which is defined as the product // of n-1 elementary reflectors of order n as returned by Dsytrd. // // The construction of Q depends on the value of uplo: // // Q = H_{n-1} * ... * H_1 * H_0 if uplo == blas.Upper // Q = H_0 * H_1 * ... * H_{n-1} if uplo == blas.Lower // // where H_i is constructed from the elementary reflectors as computed by Dsytrd. // See the documentation for Dsytrd for more information. // // tau must have length at least n-1, and Dorgtr will panic otherwise. // // work is temporary storage, and lwork specifies the usable memory length. At // minimum, lwork >= max(1,n-1), and Dorgtr will panic otherwise. The amount of blocking // is limited by the usable length. // If lwork == -1, instead of computing Dorgtr the optimal work length is stored // into work[0]. // // Dorgtr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorgtr(uplo blas.Uplo, n int, a []float64, lda int, tau, work []float64, lwork int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < max(1, n-1) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } if n == 0 { work[0] = 1 return } var nb int if uplo == blas.Upper { nb = impl.Ilaenv(1, "DORGQL", " ", n-1, n-1, n-1, -1) } else { nb = impl.Ilaenv(1, "DORGQR", " ", n-1, n-1, n-1, -1) } lworkopt := max(1, n-1) * nb if lwork == -1 { work[0] = float64(lworkopt) return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(tau) < n-1: panic(shortTau) } if uplo == blas.Upper { // Q was determined by a call to Dsytrd with uplo == blas.Upper. // Shift the vectors which define the elementary reflectors one column // to the left, and set the last row and column of Q to those of the unit // matrix. for j := 0; j < n-1; j++ { for i := 0; i < j; i++ { a[i*lda+j] = a[i*lda+j+1] } a[(n-1)*lda+j] = 0 } for i := 0; i < n-1; i++ { a[i*lda+n-1] = 0 } a[(n-1)*lda+n-1] = 1 // Generate Q[0:n-1, 0:n-1]. impl.Dorgql(n-1, n-1, n-1, a, lda, tau, work, lwork) } else { // Q was determined by a call to Dsytrd with uplo == blas.Upper. // Shift the vectors which define the elementary reflectors one column // to the right, and set the first row and column of Q to those of the unit // matrix. for j := n - 1; j > 0; j-- { a[j] = 0 for i := j + 1; i < n; i++ { a[i*lda+j] = a[i*lda+j-1] } } a[0] = 1 for i := 1; i < n; i++ { a[i*lda] = 0 } if n > 1 { // Generate Q[1:n, 1:n]. impl.Dorgqr(n-1, n-1, n-1, a[lda+1:], lda, tau, work, lwork) } } work[0] = float64(lworkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorm2r.go000066400000000000000000000052371450372207100217610ustar00rootroot00000000000000// 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/blas" // Dorm2r multiplies a general matrix C by an orthogonal matrix from a QR factorization // determined by Dgeqrf. // // C = Q * C if side == blas.Left and trans == blas.NoTrans // C = Qᵀ * C if side == blas.Left and trans == blas.Trans // C = C * Q if side == blas.Right and trans == blas.NoTrans // C = C * Qᵀ if side == blas.Right and trans == blas.Trans // // If side == blas.Left, a is a matrix of size m×k, and if side == blas.Right // a is of size n×k. // // tau contains the Householder factors and is of length at least k and this function // will panic otherwise. // // work is temporary storage of length at least n if side == blas.Left // and at least m if side == blas.Right and this function will panic otherwise. // // Dorm2r is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorm2r(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) { left := side == blas.Left switch { case !left && side != blas.Right: panic(badSide) case trans != blas.Trans && trans != blas.NoTrans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case left && k > m: panic(kGTM) case !left && k > n: panic(kGTN) case lda < max(1, k): panic(badLdA) case ldc < max(1, n): panic(badLdC) } // Quick return if possible. if m == 0 || n == 0 || k == 0 { return } switch { case left && len(a) < (m-1)*lda+k: panic(shortA) case !left && len(a) < (n-1)*lda+k: panic(shortA) case len(c) < (m-1)*ldc+n: panic(shortC) case len(tau) < k: panic(shortTau) case left && len(work) < n: panic(shortWork) case !left && len(work) < m: panic(shortWork) } if left { if trans == blas.NoTrans { for i := k - 1; i >= 0; i-- { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m-i, n, a[i*lda+i:], lda, tau[i], c[i*ldc:], ldc, work) a[i*lda+i] = aii } return } for i := 0; i < k; i++ { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m-i, n, a[i*lda+i:], lda, tau[i], c[i*ldc:], ldc, work) a[i*lda+i] = aii } return } if trans == blas.NoTrans { for i := 0; i < k; i++ { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m, n-i, a[i*lda+i:], lda, tau[i], c[i:], ldc, work) a[i*lda+i] = aii } return } for i := k - 1; i >= 0; i-- { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m, n-i, a[i*lda+i:], lda, tau[i], c[i:], ldc, work) a[i*lda+i] = aii } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dormbr.go000066400000000000000000000121571450372207100220400ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dormbr applies a multiplicative update to the matrix C based on a // decomposition computed by Dgebrd. // // Dormbr overwrites the m×n matrix C with // // Q * C if vect == lapack.ApplyQ, side == blas.Left, and trans == blas.NoTrans // C * Q if vect == lapack.ApplyQ, side == blas.Right, and trans == blas.NoTrans // Qᵀ * C if vect == lapack.ApplyQ, side == blas.Left, and trans == blas.Trans // C * Qᵀ if vect == lapack.ApplyQ, side == blas.Right, and trans == blas.Trans // // P * C if vect == lapack.ApplyP, side == blas.Left, and trans == blas.NoTrans // C * P if vect == lapack.ApplyP, side == blas.Right, and trans == blas.NoTrans // Pᵀ * C if vect == lapack.ApplyP, side == blas.Left, and trans == blas.Trans // C * Pᵀ if vect == lapack.ApplyP, side == blas.Right, and trans == blas.Trans // // where P and Q are the orthogonal matrices determined by Dgebrd when reducing // a matrix A to bidiagonal form: A = Q * B * Pᵀ. See Dgebrd for the // definitions of Q and P. // // If vect == lapack.ApplyQ, A is assumed to have been an nq×k matrix, while if // vect == lapack.ApplyP, A is assumed to have been a k×nq matrix. nq = m if // side == blas.Left, while nq = n if side == blas.Right. // // tau must have length min(nq,k), and Dormbr will panic otherwise. tau contains // the elementary reflectors to construct Q or P depending on the value of // vect. // // work must have length at least max(1,lwork), and lwork must be either -1 or // at least max(1,n) if side == blas.Left, and at least max(1,m) if side == // blas.Right. For optimum performance lwork should be at least n*nb if side == // blas.Left, and at least m*nb if side == blas.Right, where nb is the optimal // block size. On return, work[0] will contain the optimal value of lwork. // // If lwork == -1, the function only calculates the optimal value of lwork and // returns it in work[0]. // // Dormbr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dormbr(vect lapack.ApplyOrtho, side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) { nq := n nw := m if side == blas.Left { nq = m nw = n } applyQ := vect == lapack.ApplyQ switch { case !applyQ && vect != lapack.ApplyP: panic(badApplyOrtho) case side != blas.Left && side != blas.Right: panic(badSide) case trans != blas.NoTrans && trans != blas.Trans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case applyQ && lda < max(1, min(nq, k)): panic(badLdA) case !applyQ && lda < max(1, nq): panic(badLdA) case ldc < max(1, n): panic(badLdC) case lwork < max(1, nw) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if m == 0 || n == 0 { work[0] = 1 return } // The current implementation does not use opts, but a future change may // use these options so construct them. var opts string if side == blas.Left { opts = "L" } else { opts = "R" } if trans == blas.Trans { opts += "T" } else { opts += "N" } var nb int if applyQ { if side == blas.Left { nb = impl.Ilaenv(1, "DORMQR", opts, m-1, n, m-1, -1) } else { nb = impl.Ilaenv(1, "DORMQR", opts, m, n-1, n-1, -1) } } else { if side == blas.Left { nb = impl.Ilaenv(1, "DORMLQ", opts, m-1, n, m-1, -1) } else { nb = impl.Ilaenv(1, "DORMLQ", opts, m, n-1, n-1, -1) } } lworkopt := max(1, nw) * nb if lwork == -1 { work[0] = float64(lworkopt) return } minnqk := min(nq, k) switch { case applyQ && len(a) < (nq-1)*lda+minnqk: panic(shortA) case !applyQ && len(a) < (minnqk-1)*lda+nq: panic(shortA) case len(tau) < minnqk: panic(shortTau) case len(c) < (m-1)*ldc+n: panic(shortC) } if applyQ { // Change the operation to get Q depending on the size of the initial // matrix to Dgebrd. The size matters due to the storage location of // the off-diagonal elements. if nq >= k { impl.Dormqr(side, trans, m, n, k, a, lda, tau[:k], c, ldc, work, lwork) } else if nq > 1 { mi := m ni := n - 1 i1 := 0 i2 := 1 if side == blas.Left { mi = m - 1 ni = n i1 = 1 i2 = 0 } impl.Dormqr(side, trans, mi, ni, nq-1, a[lda:], lda, tau[:nq-1], c[i1*ldc+i2:], ldc, work, lwork) } work[0] = float64(lworkopt) return } transt := blas.Trans if trans == blas.Trans { transt = blas.NoTrans } // Change the operation to get P depending on the size of the initial // matrix to Dgebrd. The size matters due to the storage location of // the off-diagonal elements. if nq > k { impl.Dormlq(side, transt, m, n, k, a, lda, tau, c, ldc, work, lwork) } else if nq > 1 { mi := m ni := n - 1 i1 := 0 i2 := 1 if side == blas.Left { mi = m - 1 ni = n i1 = 1 i2 = 0 } impl.Dormlq(side, transt, mi, ni, nq-1, a[1:], lda, tau, c[i1*ldc+i2:], ldc, work, lwork) } work[0] = float64(lworkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dormhr.go000066400000000000000000000076021450372207100220450ustar00rootroot00000000000000// Copyright ©2016 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" // Dormhr multiplies an m×n general matrix C with an nq×nq orthogonal matrix Q // // Q * C if side == blas.Left and trans == blas.NoTrans, // Qᵀ * C if side == blas.Left and trans == blas.Trans, // C * Q if side == blas.Right and trans == blas.NoTrans, // C * Qᵀ if side == blas.Right and trans == blas.Trans, // // where nq == m if side == blas.Left and nq == n if side == blas.Right. // // Q is defined implicitly as the product of ihi-ilo elementary reflectors, as // returned by Dgehrd: // // Q = H_{ilo} H_{ilo+1} ... H_{ihi-1}. // // Q is equal to the identity matrix except in the submatrix // Q[ilo+1:ihi+1,ilo+1:ihi+1]. // // ilo and ihi must have the same values as in the previous call of Dgehrd. It // must hold that // // 0 <= ilo <= ihi < m if m > 0 and side == blas.Left, // ilo = 0 and ihi = -1 if m = 0 and side == blas.Left, // 0 <= ilo <= ihi < n if n > 0 and side == blas.Right, // ilo = 0 and ihi = -1 if n = 0 and side == blas.Right. // // a and lda represent an m×m matrix if side == blas.Left and an n×n matrix if // side == blas.Right. The matrix contains vectors which define the elementary // reflectors, as returned by Dgehrd. // // tau contains the scalar factors of the elementary reflectors, as returned by // Dgehrd. tau must have length m-1 if side == blas.Left and n-1 if side == // blas.Right. // // c and ldc represent the m×n matrix C. On return, c is overwritten by the // product with Q. // // work must have length at least max(1,lwork), and lwork must be at least // max(1,n), if side == blas.Left, and max(1,m), if side == blas.Right. For // optimum performance lwork should be at least n*nb if side == blas.Left and // m*nb if side == blas.Right, where nb is the optimal block size. On return, // work[0] will contain the optimal value of lwork. // // If lwork == -1, instead of performing Dormhr, only the optimal value of lwork // will be stored in work[0]. // // If any requirement on input sizes is not met, Dormhr will panic. // // Dormhr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dormhr(side blas.Side, trans blas.Transpose, m, n, ilo, ihi int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) { nq := n // The order of Q. nw := m // The minimum length of work. if side == blas.Left { nq = m nw = n } switch { case side != blas.Left && side != blas.Right: panic(badSide) case trans != blas.NoTrans && trans != blas.Trans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case ilo < 0 || max(1, nq) <= ilo: panic(badIlo) case ihi < min(ilo, nq-1) || nq <= ihi: panic(badIhi) case lda < max(1, nq): panic(badLdA) case lwork < max(1, nw) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if m == 0 || n == 0 { work[0] = 1 return } nh := ihi - ilo var nb int if side == blas.Left { opts := "LN" if trans == blas.Trans { opts = "LT" } nb = impl.Ilaenv(1, "DORMQR", opts, nh, n, nh, -1) } else { opts := "RN" if trans == blas.Trans { opts = "RT" } nb = impl.Ilaenv(1, "DORMQR", opts, m, nh, nh, -1) } lwkopt := max(1, nw) * nb if lwork == -1 { work[0] = float64(lwkopt) return } if nh == 0 { work[0] = 1 return } switch { case len(a) < (nq-1)*lda+nq: panic(shortA) case len(c) < (m-1)*ldc+n: panic(shortC) case len(tau) != nq-1: panic(badLenTau) } if side == blas.Left { impl.Dormqr(side, trans, nh, n, nh, a[(ilo+1)*lda+ilo:], lda, tau[ilo:ihi], c[(ilo+1)*ldc:], ldc, work, lwork) } else { impl.Dormqr(side, trans, m, nh, nh, a[(ilo+1)*lda+ilo:], lda, tau[ilo:ihi], c[ilo+1:], ldc, work, lwork) } work[0] = float64(lwkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dorml2.go000066400000000000000000000053211450372207100217450ustar00rootroot00000000000000// 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/blas" // Dorml2 multiplies a general matrix C by an orthogonal matrix from an LQ factorization // determined by Dgelqf. // // C = Q * C if side == blas.Left and trans == blas.NoTrans // C = Qᵀ * C if side == blas.Left and trans == blas.Trans // C = C * Q if side == blas.Right and trans == blas.NoTrans // C = C * Qᵀ if side == blas.Right and trans == blas.Trans // // If side == blas.Left, a is a matrix of side k×m, and if side == blas.Right // a is of size k×n. // // tau contains the Householder factors and is of length at least k and this function will // panic otherwise. // // work is temporary storage of length at least n if side == blas.Left // and at least m if side == blas.Right and this function will panic otherwise. // // Dorml2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dorml2(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) { left := side == blas.Left switch { case !left && side != blas.Right: panic(badSide) case trans != blas.Trans && trans != blas.NoTrans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case left && k > m: panic(kGTM) case !left && k > n: panic(kGTN) case left && lda < max(1, m): panic(badLdA) case !left && lda < max(1, n): panic(badLdA) } // Quick return if possible. if m == 0 || n == 0 || k == 0 { return } switch { case left && len(a) < (k-1)*lda+m: panic(shortA) case !left && len(a) < (k-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) case len(c) < (m-1)*ldc+n: panic(shortC) case left && len(work) < n: panic(shortWork) case !left && len(work) < m: panic(shortWork) } notrans := trans == blas.NoTrans switch { case left && notrans: for i := 0; i < k; i++ { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m-i, n, a[i*lda+i:], 1, tau[i], c[i*ldc:], ldc, work) a[i*lda+i] = aii } case left && !notrans: for i := k - 1; i >= 0; i-- { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m-i, n, a[i*lda+i:], 1, tau[i], c[i*ldc:], ldc, work) a[i*lda+i] = aii } case !left && notrans: for i := k - 1; i >= 0; i-- { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m, n-i, a[i*lda+i:], 1, tau[i], c[i:], ldc, work) a[i*lda+i] = aii } case !left && !notrans: for i := 0; i < k; i++ { aii := a[i*lda+i] a[i*lda+i] = 1 impl.Dlarf(side, m, n-i, a[i*lda+i:], 1, tau[i], c[i:], ldc, work) a[i*lda+i] = aii } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dormlq.go000066400000000000000000000105301450372207100220420ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dormlq multiplies the matrix C by the orthogonal matrix Q defined by the // slices a and tau. A and tau are as returned from Dgelqf. // // C = Q * C if side == blas.Left and trans == blas.NoTrans // C = Qᵀ * C if side == blas.Left and trans == blas.Trans // C = C * Q if side == blas.Right and trans == blas.NoTrans // C = C * Qᵀ if side == blas.Right and trans == blas.Trans // // If side == blas.Left, A is a matrix of side k×m, and if side == blas.Right // A is of size k×n. This uses a blocked algorithm. // // work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right, // and this function will panic otherwise. // Dormlq uses a block algorithm, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Dormlq, // the optimal work length will be stored into work[0]. // // tau contains the Householder scales and must have length at least k, and // this function will panic otherwise. func (impl Implementation) Dormlq(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) { left := side == blas.Left nw := m if left { nw = n } switch { case !left && side != blas.Right: panic(badSide) case trans != blas.Trans && trans != blas.NoTrans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case left && k > m: panic(kGTM) case !left && k > n: panic(kGTN) case left && lda < max(1, m): panic(badLdA) case !left && lda < max(1, n): panic(badLdA) case lwork < max(1, nw) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if m == 0 || n == 0 || k == 0 { work[0] = 1 return } const ( nbmax = 64 ldt = nbmax tsize = nbmax * ldt ) opts := string(side) + string(trans) nb := min(nbmax, impl.Ilaenv(1, "DORMLQ", opts, m, n, k, -1)) lworkopt := max(1, nw)*nb + tsize if lwork == -1 { work[0] = float64(lworkopt) return } switch { case left && len(a) < (k-1)*lda+m: panic(shortA) case !left && len(a) < (k-1)*lda+n: panic(shortA) case len(tau) < k: panic(shortTau) case len(c) < (m-1)*ldc+n: panic(shortC) } nbmin := 2 if 1 < nb && nb < k { iws := nw*nb + tsize if lwork < iws { nb = (lwork - tsize) / nw nbmin = max(2, impl.Ilaenv(2, "DORMLQ", opts, m, n, k, -1)) } } if nb < nbmin || k <= nb { // Call unblocked code. impl.Dorml2(side, trans, m, n, k, a, lda, tau, c, ldc, work) work[0] = float64(lworkopt) return } t := work[:tsize] wrk := work[tsize:] ldwrk := nb notrans := trans == blas.NoTrans transt := blas.NoTrans if notrans { transt = blas.Trans } switch { case left && notrans: for i := 0; i < k; i += nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.RowWise, m-i, ib, a[i*lda+i:], lda, tau[i:], t, ldt) impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m-i, n, ib, a[i*lda+i:], lda, t, ldt, c[i*ldc:], ldc, wrk, ldwrk) } case left && !notrans: for i := ((k - 1) / nb) * nb; i >= 0; i -= nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.RowWise, m-i, ib, a[i*lda+i:], lda, tau[i:], t, ldt) impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m-i, n, ib, a[i*lda+i:], lda, t, ldt, c[i*ldc:], ldc, wrk, ldwrk) } case !left && notrans: for i := ((k - 1) / nb) * nb; i >= 0; i -= nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib, a[i*lda+i:], lda, tau[i:], t, ldt) impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m, n-i, ib, a[i*lda+i:], lda, t, ldt, c[i:], ldc, wrk, ldwrk) } case !left && !notrans: for i := 0; i < k; i += nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib, a[i*lda+i:], lda, tau[i:], t, ldt) impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m, n-i, ib, a[i*lda+i:], lda, t, ldt, c[i:], ldc, wrk, ldwrk) } } work[0] = float64(lworkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dormqr.go000066400000000000000000000112641450372207100220550ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/lapack" ) // Dormqr multiplies an m×n matrix C by an orthogonal matrix Q as // // C = Q * C if side == blas.Left and trans == blas.NoTrans, // C = Qᵀ * C if side == blas.Left and trans == blas.Trans, // C = C * Q if side == blas.Right and trans == blas.NoTrans, // C = C * Qᵀ if side == blas.Right and trans == blas.Trans, // // where Q is defined as the product of k elementary reflectors // // Q = H_0 * H_1 * ... * H_{k-1}. // // If side == blas.Left, A is an m×k matrix and 0 <= k <= m. // If side == blas.Right, A is an n×k matrix and 0 <= k <= n. // The ith column of A contains the vector which defines the elementary // reflector H_i and tau[i] contains its scalar factor. tau must have length k // and Dormqr will panic otherwise. Dgeqrf returns A and tau in the required // form. // // work must have length at least max(1,lwork), and lwork must be at least n if // side == blas.Left and at least m if side == blas.Right, otherwise Dormqr will // panic. // // work is temporary storage, and lwork specifies the usable memory length. At // minimum, lwork >= m if side == blas.Left and lwork >= n if side == // blas.Right, and this function will panic otherwise. Larger values of lwork // will generally give better performance. On return, work[0] will contain the // optimal value of lwork. // // If lwork is -1, instead of performing Dormqr, the optimal workspace size will // be stored into work[0]. func (impl Implementation) Dormqr(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) { left := side == blas.Left nq := n nw := m if left { nq = m nw = n } switch { case !left && side != blas.Right: panic(badSide) case trans != blas.NoTrans && trans != blas.Trans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case left && k > m: panic(kGTM) case !left && k > n: panic(kGTN) case lda < max(1, k): panic(badLdA) case ldc < max(1, n): panic(badLdC) case lwork < max(1, nw) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if m == 0 || n == 0 || k == 0 { work[0] = 1 return } const ( nbmax = 64 ldt = nbmax tsize = nbmax * ldt ) opts := string(side) + string(trans) nb := min(nbmax, impl.Ilaenv(1, "DORMQR", opts, m, n, k, -1)) lworkopt := max(1, nw)*nb + tsize if lwork == -1 { work[0] = float64(lworkopt) return } switch { case len(a) < (nq-1)*lda+k: panic(shortA) case len(tau) != k: panic(badLenTau) case len(c) < (m-1)*ldc+n: panic(shortC) } nbmin := 2 if 1 < nb && nb < k { if lwork < nw*nb+tsize { nb = (lwork - tsize) / nw nbmin = max(2, impl.Ilaenv(2, "DORMQR", opts, m, n, k, -1)) } } if nb < nbmin || k <= nb { // Call unblocked code. impl.Dorm2r(side, trans, m, n, k, a, lda, tau, c, ldc, work) work[0] = float64(lworkopt) return } var ( ldwork = nb notrans = trans == blas.NoTrans ) switch { case left && notrans: for i := ((k - 1) / nb) * nb; i >= 0; i -= nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib, a[i*lda+i:], lda, tau[i:], work[:tsize], ldt) impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m-i, n, ib, a[i*lda+i:], lda, work[:tsize], ldt, c[i*ldc:], ldc, work[tsize:], ldwork) } case left && !notrans: for i := 0; i < k; i += nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib, a[i*lda+i:], lda, tau[i:], work[:tsize], ldt) impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m-i, n, ib, a[i*lda+i:], lda, work[:tsize], ldt, c[i*ldc:], ldc, work[tsize:], ldwork) } case !left && notrans: for i := 0; i < k; i += nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.ColumnWise, n-i, ib, a[i*lda+i:], lda, tau[i:], work[:tsize], ldt) impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m, n-i, ib, a[i*lda+i:], lda, work[:tsize], ldt, c[i:], ldc, work[tsize:], ldwork) } case !left && !notrans: for i := ((k - 1) / nb) * nb; i >= 0; i -= nb { ib := min(nb, k-i) impl.Dlarft(lapack.Forward, lapack.ColumnWise, n-i, ib, a[i*lda+i:], lda, tau[i:], work[:tsize], ldt) impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m, n-i, ib, a[i*lda+i:], lda, work[:tsize], ldt, c[i:], ldc, work[tsize:], ldwork) } } work[0] = float64(lworkopt) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dormr2.go000066400000000000000000000052161450372207100217560ustar00rootroot00000000000000// 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/blas" // Dormr2 multiplies a general matrix C by an orthogonal matrix from a RQ factorization // determined by Dgerqf. // // C = Q * C if side == blas.Left and trans == blas.NoTrans // C = Qᵀ * C if side == blas.Left and trans == blas.Trans // C = C * Q if side == blas.Right and trans == blas.NoTrans // C = C * Qᵀ if side == blas.Right and trans == blas.Trans // // If side == blas.Left, a is a matrix of size k×m, and if side == blas.Right // a is of size k×n. // // tau contains the Householder factors and is of length at least k and this function // will panic otherwise. // // work is temporary storage of length at least n if side == blas.Left // and at least m if side == blas.Right and this function will panic otherwise. // // Dormr2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dormr2(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) { left := side == blas.Left nq := n nw := m if left { nq = m nw = n } switch { case !left && side != blas.Right: panic(badSide) case trans != blas.NoTrans && trans != blas.Trans: panic(badTrans) case m < 0: panic(mLT0) case n < 0: panic(nLT0) case k < 0: panic(kLT0) case left && k > m: panic(kGTM) case !left && k > n: panic(kGTN) case lda < max(1, nq): panic(badLdA) case ldc < max(1, n): panic(badLdC) } // Quick return if possible. if m == 0 || n == 0 || k == 0 { return } switch { case len(a) < (k-1)*lda+nq: panic(shortA) case len(tau) < k: panic(shortTau) case len(c) < (m-1)*ldc+n: panic(shortC) case len(work) < nw: panic(shortWork) } if left { if trans == blas.NoTrans { for i := k - 1; i >= 0; i-- { aii := a[i*lda+(m-k+i)] a[i*lda+(m-k+i)] = 1 impl.Dlarf(side, m-k+i+1, n, a[i*lda:], 1, tau[i], c, ldc, work) a[i*lda+(m-k+i)] = aii } return } for i := 0; i < k; i++ { aii := a[i*lda+(m-k+i)] a[i*lda+(m-k+i)] = 1 impl.Dlarf(side, m-k+i+1, n, a[i*lda:], 1, tau[i], c, ldc, work) a[i*lda+(m-k+i)] = aii } return } if trans == blas.NoTrans { for i := 0; i < k; i++ { aii := a[i*lda+(n-k+i)] a[i*lda+(n-k+i)] = 1 impl.Dlarf(side, m, n-k+i+1, a[i*lda:], 1, tau[i], c, ldc, work) a[i*lda+(n-k+i)] = aii } return } for i := k - 1; i >= 0; i-- { aii := a[i*lda+(n-k+i)] a[i*lda+(n-k+i)] = 1 impl.Dlarf(side, m, n-k+i+1, a[i*lda:], 1, tau[i], c, ldc, work) a[i*lda+(n-k+i)] = aii } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpbcon.go000066400000000000000000000050261450372207100220150ustar00rootroot00000000000000// Copyright ©2019 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/blas/blas64" ) // Dpbcon returns an estimate of the reciprocal of the condition number (in the // 1-norm) of an n×n symmetric positive definite band matrix using the Cholesky // factorization // // A = Uᵀ*U if uplo == blas.Upper // A = L*Lᵀ if uplo == blas.Lower // // computed by Dpbtrf. The estimate is obtained for norm(inv(A)), and the // reciprocal of the condition number is computed as // // rcond = 1 / (anorm * norm(inv(A))). // // The length of work must be at least 3*n and the length of iwork must be at // least n. func (impl Implementation) Dpbcon(uplo blas.Uplo, n, kd int, ab []float64, ldab int, anorm float64, work []float64, iwork []int) (rcond float64) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case kd < 0: panic(kdLT0) case ldab < kd+1: panic(badLdA) case anorm < 0: panic(badNorm) } // Quick return if possible. if n == 0 { return 1 } switch { case len(ab) < (n-1)*ldab+kd+1: panic(shortAB) case len(work) < 3*n: panic(shortWork) case len(iwork) < n: panic(shortIWork) } // Quick return if possible. if anorm == 0 { return 0 } const smlnum = dlamchS var ( ainvnm float64 kase int isave [3]int normin bool // Denote work slices. x = work[:n] v = work[n : 2*n] cnorm = work[2*n : 3*n] ) // Estimate the 1-norm of the inverse. bi := blas64.Implementation() for { ainvnm, kase = impl.Dlacn2(n, v, x, iwork, ainvnm, kase, &isave) if kase == 0 { break } var op1, op2 blas.Transpose if uplo == blas.Upper { // Multiply x by inv(Uᵀ), op1 = blas.Trans // then by inv(Uᵀ). op2 = blas.NoTrans } else { // Multiply x by inv(L), op1 = blas.NoTrans // then by inv(Lᵀ). op2 = blas.Trans } scaleL := impl.Dlatbs(uplo, op1, blas.NonUnit, normin, n, kd, ab, ldab, x, cnorm) normin = true scaleU := impl.Dlatbs(uplo, op2, blas.NonUnit, normin, n, kd, ab, ldab, x, cnorm) // Multiply x by 1/scale if doing so will not cause overflow. scale := scaleL * scaleU if scale != 1 { ix := bi.Idamax(n, x, 1) if scale < math.Abs(x[ix])*smlnum || scale == 0 { return 0 } impl.Drscl(n, scale, x, 1) } } if ainvnm == 0 { return 0 } // Return the estimate of the reciprocal condition number. return (1 / ainvnm) / anorm } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpbtf2.go000066400000000000000000000057361450372207100217410ustar00rootroot00000000000000// 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/blas/blas64" ) // Dpbtf2 computes the Cholesky factorization of a symmetric positive banded // matrix ab. The matrix ab is n×n with kd diagonal bands. The Cholesky // factorization computed is // // A = Uᵀ * U if ul == blas.Upper // A = L * Lᵀ if ul == blas.Lower // // ul also specifies the storage of ab. If ul == blas.Upper, then // ab is stored as an upper-triangular banded matrix with kd super-diagonals, // and if ul == blas.Lower, ab is stored as a lower-triangular banded matrix // with kd sub-diagonals. On exit, the banded matrix U or L is stored in-place // into ab depending on the value of ul. Dpbtf2 returns whether the factorization // was successfully completed. // // The band storage scheme is illustrated below when n = 6, and kd = 2. // The resulting Cholesky decomposition is stored in the same elements as the // input band matrix (a11 becomes u11 or l11, etc.). // // ul = blas.Upper // a11 a12 a13 // a22 a23 a24 // a33 a34 a35 // a44 a45 a46 // a55 a56 * // a66 * * // // ul = blas.Lower // * * a11 // * a21 a22 // a31 a32 a33 // a42 a43 a44 // a53 a54 a55 // a64 a65 a66 // // Dpbtf2 is the unblocked version of the algorithm, see Dpbtrf for the blocked // version. // // Dpbtf2 is an internal routine, exported for testing purposes. func (Implementation) Dpbtf2(uplo blas.Uplo, n, kd int, ab []float64, ldab int) (ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case kd < 0: panic(kdLT0) case ldab < kd+1: panic(badLdA) } // Quick return if possible. if n == 0 { return true } if len(ab) < (n-1)*ldab+kd+1 { panic(shortAB) } bi := blas64.Implementation() kld := max(1, ldab-1) if uplo == blas.Upper { // Compute the Cholesky factorization A = Uᵀ * U. for j := 0; j < n; j++ { // Compute U(j,j) and test for non-positive-definiteness. ajj := ab[j*ldab] if ajj <= 0 { return false } ajj = math.Sqrt(ajj) ab[j*ldab] = ajj // Compute elements j+1:j+kn of row j and update the trailing submatrix // within the band. kn := min(kd, n-j-1) if kn > 0 { bi.Dscal(kn, 1/ajj, ab[j*ldab+1:], 1) bi.Dsyr(blas.Upper, kn, -1, ab[j*ldab+1:], 1, ab[(j+1)*ldab:], kld) } } return true } // Compute the Cholesky factorization A = L * Lᵀ. for j := 0; j < n; j++ { // Compute L(j,j) and test for non-positive-definiteness. ajj := ab[j*ldab+kd] if ajj <= 0 { return false } ajj = math.Sqrt(ajj) ab[j*ldab+kd] = ajj // Compute elements j+1:j+kn of column j and update the trailing submatrix // within the band. kn := min(kd, n-j-1) if kn > 0 { bi.Dscal(kn, 1/ajj, ab[(j+1)*ldab+kd-1:], kld) bi.Dsyr(blas.Lower, kn, -1, ab[(j+1)*ldab+kd-1:], kld, ab[(j+1)*ldab+kd:], kld) } } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpbtrf.go000066400000000000000000000144031450372207100220300ustar00rootroot00000000000000// Copyright ©2019 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/blas/blas64" ) // Dpbtrf computes the Cholesky factorization of an n×n symmetric positive // definite band matrix // // A = Uᵀ * U if uplo == blas.Upper // A = L * Lᵀ if uplo == blas.Lower // // where U is an upper triangular band matrix and L is lower triangular. kd is // the number of super- or sub-diagonals of A. // // The band storage scheme is illustrated below when n = 6 and kd = 2. Elements // marked * are not used by the function. // // uplo == blas.Upper // On entry: On return: // a00 a01 a02 u00 u01 u02 // a11 a12 a13 u11 u12 u13 // a22 a23 a24 u22 u23 u24 // a33 a34 a35 u33 u34 u35 // a44 a45 * u44 u45 * // a55 * * u55 * * // // uplo == blas.Lower // On entry: On return: // * * a00 * * l00 // * a10 a11 * l10 l11 // a20 a21 a22 l20 l21 l22 // a31 a32 a33 l31 l32 l33 // a42 a43 a44 l42 l43 l44 // a53 a54 a55 l53 l54 l55 func (impl Implementation) Dpbtrf(uplo blas.Uplo, n, kd int, ab []float64, ldab int) (ok bool) { const nbmax = 32 switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case kd < 0: panic(kdLT0) case ldab < kd+1: panic(badLdA) } // Quick return if possible. if n == 0 { return true } if len(ab) < (n-1)*ldab+kd+1 { panic(shortAB) } opts := string(blas.Upper) if uplo == blas.Lower { opts = string(blas.Lower) } nb := impl.Ilaenv(1, "DPBTRF", opts, n, kd, -1, -1) // The block size must not exceed the semi-bandwidth kd, and must not // exceed the limit set by the size of the local array work. nb = min(nb, nbmax) if nb <= 1 || kd < nb { // Use unblocked code. return impl.Dpbtf2(uplo, n, kd, ab, ldab) } // Use blocked code. ldwork := nb work := make([]float64, nb*ldwork) bi := blas64.Implementation() if uplo == blas.Upper { // Compute the Cholesky factorization of a symmetric band // matrix, given the upper triangle of the matrix in band // storage. // Process the band matrix one diagonal block at a time. for i := 0; i < n; i += nb { ib := min(nb, n-i) // Factorize the diagonal block. ok := impl.Dpotf2(uplo, ib, ab[i*ldab:], ldab-1) if !ok { return false } if i+ib >= n { continue } // Update the relevant part of the trailing submatrix. // If A11 denotes the diagonal block which has just been // factorized, then we need to update the remaining // blocks in the diagram: // // A11 A12 A13 // A22 A23 // A33 // // The numbers of rows and columns in the partitioning // are ib, i2, i3 respectively. The blocks A12, A22 and // A23 are empty if ib = kd. The upper triangle of A13 // lies outside the band. i2 := min(kd-ib, n-i-ib) if i2 > 0 { // Update A12. bi.Dtrsm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, ib, i2, 1, ab[i*ldab:], ldab-1, ab[i*ldab+ib:], ldab-1) // Update A22. bi.Dsyrk(blas.Upper, blas.Trans, i2, ib, -1, ab[i*ldab+ib:], ldab-1, 1, ab[(i+ib)*ldab:], ldab-1) } i3 := min(ib, n-i-kd) if i3 > 0 { // Copy the lower triangle of A13 into the work array. for ii := 0; ii < ib; ii++ { for jj := 0; jj <= min(ii, i3-1); jj++ { work[ii*ldwork+jj] = ab[(i+ii)*ldab+kd-ii+jj] } } // Update A13 (in the work array). bi.Dtrsm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, ib, i3, 1, ab[i*ldab:], ldab-1, work, ldwork) // Update A23. if i2 > 0 { bi.Dgemm(blas.Trans, blas.NoTrans, i2, i3, ib, -1, ab[i*ldab+ib:], ldab-1, work, ldwork, 1, ab[(i+ib)*ldab+kd-ib:], ldab-1) } // Update A33. bi.Dsyrk(blas.Upper, blas.Trans, i3, ib, -1, work, ldwork, 1, ab[(i+kd)*ldab:], ldab-1) // Copy the lower triangle of A13 back into place. for ii := 0; ii < ib; ii++ { for jj := 0; jj <= min(ii, i3-1); jj++ { ab[(i+ii)*ldab+kd-ii+jj] = work[ii*ldwork+jj] } } } } } else { // Compute the Cholesky factorization of a symmetric band // matrix, given the lower triangle of the matrix in band // storage. // Process the band matrix one diagonal block at a time. for i := 0; i < n; i += nb { ib := min(nb, n-i) // Factorize the diagonal block. ok := impl.Dpotf2(uplo, ib, ab[i*ldab+kd:], ldab-1) if !ok { return false } if i+ib >= n { continue } // Update the relevant part of the trailing submatrix. // If A11 denotes the diagonal block which has just been // factorized, then we need to update the remaining // blocks in the diagram: // // A11 // A21 A22 // A31 A32 A33 // // The numbers of rows and columns in the partitioning // are ib, i2, i3 respectively. The blocks A21, A22 and // A32 are empty if ib = kd. The lowr triangle of A31 // lies outside the band. i2 := min(kd-ib, n-i-ib) if i2 > 0 { // Update A21. bi.Dtrsm(blas.Right, blas.Lower, blas.Trans, blas.NonUnit, i2, ib, 1, ab[i*ldab+kd:], ldab-1, ab[(i+ib)*ldab+kd-ib:], ldab-1) // Update A22. bi.Dsyrk(blas.Lower, blas.NoTrans, i2, ib, -1, ab[(i+ib)*ldab+kd-ib:], ldab-1, 1, ab[(i+ib)*ldab+kd:], ldab-1) } i3 := min(ib, n-i-kd) if i3 > 0 { // Copy the upper triangle of A31 into the work array. for ii := 0; ii < i3; ii++ { for jj := ii; jj < ib; jj++ { work[ii*ldwork+jj] = ab[(ii+i+kd)*ldab+jj-ii] } } // Update A31 (in the work array). bi.Dtrsm(blas.Right, blas.Lower, blas.Trans, blas.NonUnit, i3, ib, 1, ab[i*ldab+kd:], ldab-1, work, ldwork) // Update A32. if i2 > 0 { bi.Dgemm(blas.NoTrans, blas.Trans, i3, i2, ib, -1, work, ldwork, ab[(i+ib)*ldab+kd-ib:], ldab-1, 1, ab[(i+kd)*ldab+ib:], ldab-1) } // Update A33. bi.Dsyrk(blas.Lower, blas.NoTrans, i3, ib, -1, work, ldwork, 1, ab[(i+kd)*ldab+kd:], ldab-1) // Copy the upper triangle of A31 back into place. for ii := 0; ii < i3; ii++ { for jj := ii; jj < ib; jj++ { ab[(ii+i+kd)*ldab+jj-ii] = work[ii*ldwork+jj] } } } } } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpbtrs.go000066400000000000000000000037241450372207100220510ustar00rootroot00000000000000// Copyright ©2019 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/blas/blas64" ) // Dpbtrs solves a system of linear equations A*X = B with an n×n symmetric // positive definite band matrix A using the Cholesky factorization // // A = Uᵀ * U if uplo == blas.Upper // A = L * Lᵀ if uplo == blas.Lower // // computed by Dpbtrf. kd is the number of super- or sub-diagonals of A. See the // documentation for Dpbtrf for a description of the band storage format of A. // // On entry, b contains the n×nrhs right hand side matrix B. On return, it is // overwritten with the solution matrix X. func (Implementation) Dpbtrs(uplo blas.Uplo, n, kd, nrhs int, ab []float64, ldab int, b []float64, ldb int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case kd < 0: panic(kdLT0) case nrhs < 0: panic(nrhsLT0) case ldab < kd+1: panic(badLdA) case ldb < max(1, nrhs): panic(badLdB) } // Quick return if possible. if n == 0 || nrhs == 0 { return } if len(ab) < (n-1)*ldab+kd+1 { panic(shortAB) } if len(b) < (n-1)*ldb+nrhs { panic(shortB) } bi := blas64.Implementation() if uplo == blas.Upper { // Solve A*X = B where A = Uᵀ*U. for j := 0; j < nrhs; j++ { // Solve Uᵀ*Y = B, overwriting B with Y. bi.Dtbsv(blas.Upper, blas.Trans, blas.NonUnit, n, kd, ab, ldab, b[j:], ldb) // Solve U*X = Y, overwriting Y with X. bi.Dtbsv(blas.Upper, blas.NoTrans, blas.NonUnit, n, kd, ab, ldab, b[j:], ldb) } } else { // Solve A*X = B where A = L*Lᵀ. for j := 0; j < nrhs; j++ { // Solve L*Y = B, overwriting B with Y. bi.Dtbsv(blas.Lower, blas.NoTrans, blas.NonUnit, n, kd, ab, ldab, b[j:], ldb) // Solve Lᵀ*X = Y, overwriting Y with X. bi.Dtbsv(blas.Lower, blas.Trans, blas.NonUnit, n, kd, ab, ldab, b[j:], ldb) } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpocon.go000066400000000000000000000043111450372207100220260ustar00rootroot00000000000000// 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/blas/blas64" ) // Dpocon estimates the reciprocal of the condition number of a positive-definite // matrix A given the Cholesky decomposition of A. The condition number computed // is based on the 1-norm and the ∞-norm. // // anorm is the 1-norm and the ∞-norm of the original matrix A. // // work is a temporary data slice of length at least 3*n and Dpocon will panic otherwise. // // iwork is a temporary data slice of length at least n and Dpocon will panic otherwise. func (impl Implementation) Dpocon(uplo blas.Uplo, n int, a []float64, lda int, anorm float64, work []float64, iwork []int) float64 { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case anorm < 0: panic(negANorm) } // Quick return if possible. if n == 0 { return 1 } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(work) < 3*n: panic(shortWork) case len(iwork) < n: panic(shortIWork) } if anorm == 0 { return 0 } bi := blas64.Implementation() var ( smlnum = dlamchS rcond float64 sl, su float64 normin bool ainvnm float64 kase int isave [3]int ) for { ainvnm, kase = impl.Dlacn2(n, work[n:], work, iwork, ainvnm, kase, &isave) if kase == 0 { if ainvnm != 0 { rcond = (1 / ainvnm) / anorm } return rcond } if uplo == blas.Upper { sl = impl.Dlatrs(blas.Upper, blas.Trans, blas.NonUnit, normin, n, a, lda, work, work[2*n:]) normin = true su = impl.Dlatrs(blas.Upper, blas.NoTrans, blas.NonUnit, normin, n, a, lda, work, work[2*n:]) } else { sl = impl.Dlatrs(blas.Lower, blas.NoTrans, blas.NonUnit, normin, n, a, lda, work, work[2*n:]) normin = true su = impl.Dlatrs(blas.Lower, blas.Trans, blas.NonUnit, normin, n, a, lda, work, work[2*n:]) } scale := sl * su if scale != 1 { ix := bi.Idamax(n, work, 1) if scale == 0 || scale < math.Abs(work[ix])*smlnum { return rcond } impl.Drscl(n, scale, work, 1) } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpotf2.go000066400000000000000000000036431450372207100217510ustar00rootroot00000000000000// 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/blas/blas64" ) // Dpotf2 computes the Cholesky decomposition of the symmetric positive definite // matrix a. If ul == blas.Upper, then a is stored as an upper-triangular matrix, // and a = Uᵀ U is stored in place into a. If ul == blas.Lower, then a = L Lᵀ // is computed and stored in-place into a. If a is not positive definite, false // is returned. This is the unblocked version of the algorithm. // // Dpotf2 is an internal routine. It is exported for testing purposes. func (Implementation) Dpotf2(ul blas.Uplo, n int, a []float64, lda int) (ok bool) { switch { case ul != blas.Upper && ul != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return true } if len(a) < (n-1)*lda+n { panic(shortA) } bi := blas64.Implementation() if ul == blas.Upper { for j := 0; j < n; j++ { ajj := a[j*lda+j] if j != 0 { ajj -= bi.Ddot(j, a[j:], lda, a[j:], lda) } if ajj <= 0 || math.IsNaN(ajj) { a[j*lda+j] = ajj return false } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj if j < n-1 { bi.Dgemv(blas.Trans, j, n-j-1, -1, a[j+1:], lda, a[j:], lda, 1, a[j*lda+j+1:], 1) bi.Dscal(n-j-1, 1/ajj, a[j*lda+j+1:], 1) } } return true } for j := 0; j < n; j++ { ajj := a[j*lda+j] if j != 0 { ajj -= bi.Ddot(j, a[j*lda:], 1, a[j*lda:], 1) } if ajj <= 0 || math.IsNaN(ajj) { a[j*lda+j] = ajj return false } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj if j < n-1 { bi.Dgemv(blas.NoTrans, n-j-1, j, -1, a[(j+1)*lda:], lda, a[j*lda:], 1, 1, a[(j+1)*lda+j:], lda) bi.Dscal(n-j-1, 1/ajj, a[(j+1)*lda+j:], lda) } } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpotrf.go000066400000000000000000000042111450372207100220410ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dpotrf computes the Cholesky decomposition of the symmetric positive definite // matrix a. If ul == blas.Upper, then a is stored as an upper-triangular matrix, // and a = Uᵀ U is stored in place into a. If ul == blas.Lower, then a = L Lᵀ // is computed and stored in-place into a. If a is not positive definite, false // is returned. This is the blocked version of the algorithm. func (impl Implementation) Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool) { switch { case ul != blas.Upper && ul != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return true } if len(a) < (n-1)*lda+n { panic(shortA) } nb := impl.Ilaenv(1, "DPOTRF", string(ul), n, -1, -1, -1) if nb <= 1 || n <= nb { return impl.Dpotf2(ul, n, a, lda) } bi := blas64.Implementation() if ul == blas.Upper { for j := 0; j < n; j += nb { jb := min(nb, n-j) bi.Dsyrk(blas.Upper, blas.Trans, jb, j, -1, a[j:], lda, 1, a[j*lda+j:], lda) ok = impl.Dpotf2(blas.Upper, jb, a[j*lda+j:], lda) if !ok { return ok } if j+jb < n { bi.Dgemm(blas.Trans, blas.NoTrans, jb, n-j-jb, j, -1, a[j:], lda, a[j+jb:], lda, 1, a[j*lda+j+jb:], lda) bi.Dtrsm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, jb, n-j-jb, 1, a[j*lda+j:], lda, a[j*lda+j+jb:], lda) } } return true } for j := 0; j < n; j += nb { jb := min(nb, n-j) bi.Dsyrk(blas.Lower, blas.NoTrans, jb, j, -1, a[j*lda:], lda, 1, a[j*lda+j:], lda) ok := impl.Dpotf2(blas.Lower, jb, a[j*lda+j:], lda) if !ok { return ok } if j+jb < n { bi.Dgemm(blas.NoTrans, blas.Trans, n-j-jb, jb, j, -1, a[(j+jb)*lda:], lda, a[j*lda:], lda, 1, a[(j+jb)*lda+j:], lda) bi.Dtrsm(blas.Right, blas.Lower, blas.Trans, blas.NonUnit, n-j-jb, jb, 1, a[j*lda+j:], lda, a[(j+jb)*lda+j:], lda) } } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpotri.go000066400000000000000000000022071450372207100220470ustar00rootroot00000000000000// Copyright ©2019 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" // Dpotri computes the inverse of a real symmetric positive definite matrix A // using its Cholesky factorization. // // On entry, a contains the triangular factor U or L from the Cholesky // factorization A = Uᵀ*U or A = L*Lᵀ, as computed by Dpotrf. // On return, a contains the upper or lower triangle of the (symmetric) // inverse of A, overwriting the input factor U or L. func (impl Implementation) Dpotri(uplo blas.Uplo, n int, a []float64, lda int) (ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return true } if len(a) < (n-1)*lda+n { panic(shortA) } // Invert the triangular Cholesky factor U or L. ok = impl.Dtrtri(uplo, blas.NonUnit, n, a, lda) if !ok { return false } // Form inv(U)*inv(U)ᵀ or inv(L)ᵀ*inv(L). impl.Dlauum(uplo, n, a, lda) return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpotrs.go000066400000000000000000000035761450372207100220730ustar00rootroot00000000000000// 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/blas/blas64" ) // Dpotrs solves a system of n linear equations A*X = B where A is an n×n // symmetric positive definite matrix and B is an n×nrhs matrix. The matrix A is // represented by its Cholesky factorization // // A = Uᵀ*U if uplo == blas.Upper // A = L*Lᵀ if uplo == blas.Lower // // as computed by Dpotrf. On entry, B contains the right-hand side matrix B, on // return it contains the solution matrix X. func (Implementation) Dpotrs(uplo blas.Uplo, n, nrhs int, a []float64, lda int, b []float64, ldb int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case nrhs < 0: panic(nrhsLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, nrhs): panic(badLdB) } // Quick return if possible. if n == 0 || nrhs == 0 { return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(b) < (n-1)*ldb+nrhs: panic(shortB) } bi := blas64.Implementation() if uplo == blas.Upper { // Solve Uᵀ * U * X = B where U is stored in the upper triangle of A. // Solve Uᵀ * X = B, overwriting B with X. bi.Dtrsm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, n, nrhs, 1, a, lda, b, ldb) // Solve U * X = B, overwriting B with X. bi.Dtrsm(blas.Left, blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs, 1, a, lda, b, ldb) } else { // Solve L * Lᵀ * X = B where L is stored in the lower triangle of A. // Solve L * X = B, overwriting B with X. bi.Dtrsm(blas.Left, blas.Lower, blas.NoTrans, blas.NonUnit, n, nrhs, 1, a, lda, b, ldb) // Solve Lᵀ * X = B, overwriting B with X. bi.Dtrsm(blas.Left, blas.Lower, blas.Trans, blas.NonUnit, n, nrhs, 1, a, lda, b, ldb) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpstf2.go000066400000000000000000000120031450372207100217430ustar00rootroot00000000000000// Copyright ©2021 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/blas/blas64" ) // Dpstf2 computes the Cholesky factorization with complete pivoting of an n×n // symmetric positive semidefinite matrix A. // // The factorization has the form // // Pᵀ * A * P = Uᵀ * U , if uplo = blas.Upper, // Pᵀ * A * P = L * Lᵀ, if uplo = blas.Lower, // // where U is an upper triangular matrix, L is lower triangular, and P is a // permutation matrix. // // tol is a user-defined tolerance. The algorithm terminates if the pivot is // less than or equal to tol. If tol is negative, then n*eps*max(A[k,k]) will be // used instead. // // On return, A contains the factor U or L from the Cholesky factorization and // piv contains P stored such that P[piv[k],k] = 1. // // Dpstf2 returns the computed rank of A and whether the factorization can be // used to solve a system. Dpstf2 does not attempt to check that A is positive // semi-definite, so if ok is false, the matrix A is either rank deficient or is // not positive semidefinite. // // The length of piv must be n and the length of work must be at least 2*n, // otherwise Dpstf2 will panic. // // Dpstf2 is an internal routine. It is exported for testing purposes. func (Implementation) Dpstf2(uplo blas.Uplo, n int, a []float64, lda int, piv []int, tol float64, work []float64) (rank int, ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return 0, true } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(piv) != n: panic(badLenPiv) case len(work) < 2*n: panic(shortWork) } // Initialize piv. for i := range piv[:n] { piv[i] = i } // Compute the first pivot. pvt := 0 ajj := a[0] for i := 1; i < n; i++ { aii := a[i*lda+i] if aii > ajj { pvt = i ajj = aii } } if ajj <= 0 || math.IsNaN(ajj) { return 0, false } // Compute stopping value if not supplied. dstop := tol if dstop < 0 { dstop = float64(n) * dlamchE * ajj } // Set first half of work to zero, holds dot products. dots := work[:n] for i := range dots { dots[i] = 0 } work2 := work[n : 2*n] bi := blas64.Implementation() if uplo == blas.Upper { // Compute the Cholesky factorization Pᵀ * A * P = Uᵀ * U. for j := 0; j < n; j++ { // Update dot products and compute possible pivots which are stored // in the second half of work. for i := j; i < n; i++ { if j > 0 { tmp := a[(j-1)*lda+i] dots[i] += tmp * tmp } work2[i] = a[i*lda+i] - dots[i] } if j > 0 { // Find the pivot. pvt = j ajj = work2[pvt] for k := j + 1; k < n; k++ { wk := work2[k] if wk > ajj { pvt = k ajj = wk } } // Test for exit. if ajj <= dstop || math.IsNaN(ajj) { a[j*lda+j] = ajj return j, false } } if j != pvt { // Swap pivot rows and columns. a[pvt*lda+pvt] = a[j*lda+j] bi.Dswap(j, a[j:], lda, a[pvt:], lda) if pvt < n-1 { bi.Dswap(n-pvt-1, a[j*lda+(pvt+1):], 1, a[pvt*lda+(pvt+1):], 1) } bi.Dswap(pvt-j-1, a[j*lda+(j+1):], 1, a[(j+1)*lda+pvt:], lda) // Swap dot products and piv. dots[j], dots[pvt] = dots[pvt], dots[j] piv[j], piv[pvt] = piv[pvt], piv[j] } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj // Compute elements j+1:n of row j. if j < n-1 { bi.Dgemv(blas.Trans, j, n-j-1, -1, a[j+1:], lda, a[j:], lda, 1, a[j*lda+j+1:], 1) bi.Dscal(n-j-1, 1/ajj, a[j*lda+j+1:], 1) } } } else { // Compute the Cholesky factorization Pᵀ * A * P = L * Lᵀ. for j := 0; j < n; j++ { // Update dot products and compute possible pivots which are stored // in the second half of work. for i := j; i < n; i++ { if j > 0 { tmp := a[i*lda+(j-1)] dots[i] += tmp * tmp } work2[i] = a[i*lda+i] - dots[i] } if j > 0 { // Find the pivot. pvt = j ajj = work2[pvt] for k := j + 1; k < n; k++ { wk := work2[k] if wk > ajj { pvt = k ajj = wk } } // Test for exit. if ajj <= dstop || math.IsNaN(ajj) { a[j*lda+j] = ajj return j, false } } if j != pvt { // Swap pivot rows and columns. a[pvt*lda+pvt] = a[j*lda+j] bi.Dswap(j, a[j*lda:], 1, a[pvt*lda:], 1) if pvt < n-1 { bi.Dswap(n-pvt-1, a[(pvt+1)*lda+j:], lda, a[(pvt+1)*lda+pvt:], lda) } bi.Dswap(pvt-j-1, a[(j+1)*lda+j:], lda, a[pvt*lda+(j+1):], 1) // Swap dot products and piv. dots[j], dots[pvt] = dots[pvt], dots[j] piv[j], piv[pvt] = piv[pvt], piv[j] } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj // Compute elements j+1:n of column j. if j < n-1 { bi.Dgemv(blas.NoTrans, n-j-1, j, -1, a[(j+1)*lda:], lda, a[j*lda:], 1, 1, a[(j+1)*lda+j:], lda) bi.Dscal(n-j-1, 1/ajj, a[(j+1)*lda+j:], lda) } } } return n, true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dpstrf.go000066400000000000000000000137671450372207100220650ustar00rootroot00000000000000// Copyright ©2021 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/blas/blas64" ) // Dpstrf computes the Cholesky factorization with complete pivoting of an n×n // symmetric positive semidefinite matrix A. // // The factorization has the form // // Pᵀ * A * P = Uᵀ * U , if uplo = blas.Upper, // Pᵀ * A * P = L * Lᵀ, if uplo = blas.Lower, // // where U is an upper triangular matrix, L is lower triangular, and P is a // permutation matrix. // // tol is a user-defined tolerance. The algorithm terminates if the pivot is // less than or equal to tol. If tol is negative, then n*eps*max(A[k,k]) will be // used instead. // // On return, A contains the factor U or L from the Cholesky factorization and // piv contains P stored such that P[piv[k],k] = 1. // // Dpstrf returns the computed rank of A and whether the factorization can be // used to solve a system. Dpstrf does not attempt to check that A is positive // semi-definite, so if ok is false, the matrix A is either rank deficient or is // not positive semidefinite. // // The length of piv must be n and the length of work must be at least 2*n, // otherwise Dpstrf will panic. // // Dpstrf is an internal routine. It is exported for testing purposes. func (impl Implementation) Dpstrf(uplo blas.Uplo, n int, a []float64, lda int, piv []int, tol float64, work []float64) (rank int, ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return 0, true } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(piv) != n: panic(badLenPiv) case len(work) < 2*n: panic(shortWork) } // Get block size. nb := impl.Ilaenv(1, "DPOTRF", string(uplo), n, -1, -1, -1) if nb <= 1 || n <= nb { // Use unblocked code. return impl.Dpstf2(uplo, n, a, lda, piv, tol, work) } // Initialize piv. for i := range piv[:n] { piv[i] = i } // Compute the first pivot. pvt := 0 ajj := a[0] for i := 1; i < n; i++ { aii := a[i*lda+i] if aii > ajj { pvt = i ajj = aii } } if ajj <= 0 || math.IsNaN(ajj) { return 0, false } // Compute stopping value if not supplied. dstop := tol if dstop < 0 { dstop = float64(n) * dlamchE * ajj } bi := blas64.Implementation() // Split work in half, the first half holds dot products. dots := work[:n] work2 := work[n : 2*n] if uplo == blas.Upper { // Compute the Cholesky factorization Pᵀ * A * P = Uᵀ * U. for k := 0; k < n; k += nb { // Account for last block not being nb wide. jb := min(nb, n-k) // Set relevant part of dot products to zero. for i := k; i < n; i++ { dots[i] = 0 } for j := k; j < k+jb; j++ { // Update dot products and compute possible pivots which are stored // in the second half of work. for i := j; i < n; i++ { if j > k { tmp := a[(j-1)*lda+i] dots[i] += tmp * tmp } work2[i] = a[i*lda+i] - dots[i] } if j > 0 { // Find the pivot. pvt = j ajj = work2[pvt] for l := j + 1; l < n; l++ { wl := work2[l] if wl > ajj { pvt = l ajj = wl } } // Test for exit. if ajj <= dstop || math.IsNaN(ajj) { a[j*lda+j] = ajj return j, false } } if j != pvt { // Swap pivot rows and columns. a[pvt*lda+pvt] = a[j*lda+j] bi.Dswap(j, a[j:], lda, a[pvt:], lda) if pvt < n-1 { bi.Dswap(n-pvt-1, a[j*lda+(pvt+1):], 1, a[pvt*lda+(pvt+1):], 1) } bi.Dswap(pvt-j-1, a[j*lda+(j+1):], 1, a[(j+1)*lda+pvt:], lda) // Swap dot products and piv. dots[j], dots[pvt] = dots[pvt], dots[j] piv[j], piv[pvt] = piv[pvt], piv[j] } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj // Compute elements j+1:n of row j. if j < n-1 { bi.Dgemv(blas.Trans, j-k, n-j-1, -1, a[k*lda+j+1:], lda, a[k*lda+j:], lda, 1, a[j*lda+j+1:], 1) bi.Dscal(n-j-1, 1/ajj, a[j*lda+j+1:], 1) } } // Update trailing matrix. if k+jb < n { j := k + jb bi.Dsyrk(blas.Upper, blas.Trans, n-j, jb, -1, a[k*lda+j:], lda, 1, a[j*lda+j:], lda) } } } else { // Compute the Cholesky factorization Pᵀ * A * P = L * Lᵀ. for k := 0; k < n; k += nb { // Account for last block not being nb wide. jb := min(nb, n-k) // Set relevant part of dot products to zero. for i := k; i < n; i++ { dots[i] = 0 } for j := k; j < k+jb; j++ { // Update dot products and compute possible pivots which are stored // in the second half of work. for i := j; i < n; i++ { if j > k { tmp := a[i*lda+(j-1)] dots[i] += tmp * tmp } work2[i] = a[i*lda+i] - dots[i] } if j > 0 { // Find the pivot. pvt = j ajj = work2[pvt] for l := j + 1; l < n; l++ { wl := work2[l] if wl > ajj { pvt = l ajj = wl } } // Test for exit. if ajj <= dstop || math.IsNaN(ajj) { a[j*lda+j] = ajj return j, false } } if j != pvt { // Swap pivot rows and columns. a[pvt*lda+pvt] = a[j*lda+j] bi.Dswap(j, a[j*lda:], 1, a[pvt*lda:], 1) if pvt < n-1 { bi.Dswap(n-pvt-1, a[(pvt+1)*lda+j:], lda, a[(pvt+1)*lda+pvt:], lda) } bi.Dswap(pvt-j-1, a[(j+1)*lda+j:], lda, a[pvt*lda+(j+1):], 1) // Swap dot products and piv. dots[j], dots[pvt] = dots[pvt], dots[j] piv[j], piv[pvt] = piv[pvt], piv[j] } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj // Compute elements j+1:n of column j. if j < n-1 { bi.Dgemv(blas.NoTrans, n-j-1, j-k, -1, a[(j+1)*lda+k:], lda, a[j*lda+k:], 1, 1, a[(j+1)*lda+j:], lda) bi.Dscal(n-j-1, 1/ajj, a[(j+1)*lda+j:], lda) } } // Update trailing matrix. if k+jb < n { j := k + jb bi.Dsyrk(blas.Lower, blas.NoTrans, n-j, jb, -1, a[j*lda+k:], lda, 1, a[j*lda+j:], lda) } } } return n, true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/drscl.go000066400000000000000000000022161450372207100216550ustar00rootroot00000000000000// 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/blas64" ) // Drscl multiplies the vector x by 1/a being careful to avoid overflow or // underflow where possible. // // Drscl is an internal routine. It is exported for testing purposes. func (impl Implementation) Drscl(n int, a float64, x []float64, incX int) { switch { case n < 0: panic(nLT0) case incX <= 0: panic(badIncX) } // Quick return if possible. if n == 0 { return } if len(x) < 1+(n-1)*incX { panic(shortX) } bi := blas64.Implementation() cden := a cnum := 1.0 smlnum := dlamchS bignum := 1 / smlnum for { cden1 := cden * smlnum cnum1 := cnum / bignum var mul float64 var done bool switch { case cnum != 0 && math.Abs(cden1) > math.Abs(cnum): mul = smlnum done = false cden = cden1 case math.Abs(cnum1) > math.Abs(cden): mul = bignum done = false cnum = cnum1 default: mul = cnum / cden done = true } bi.Dscal(n, mul, x, incX) if done { break } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dsteqr.go000066400000000000000000000212201450372207100220440ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dsteqr computes the eigenvalues and optionally the eigenvectors of a symmetric // tridiagonal matrix using the implicit QL or QR method. The eigenvectors of a // full or band symmetric matrix can also be found if Dsytrd, Dsptrd, or Dsbtrd // have been used to reduce this matrix to tridiagonal form. // // d, on entry, contains the diagonal elements of the tridiagonal matrix. On exit, // d contains the eigenvalues in ascending order. d must have length n and // Dsteqr will panic otherwise. // // e, on entry, contains the off-diagonal elements of the tridiagonal matrix on // entry, and is overwritten during the call to Dsteqr. e must have length n-1 and // Dsteqr will panic otherwise. // // z, on entry, contains the n×n orthogonal matrix used in the reduction to // tridiagonal form if compz == lapack.EVOrig. On exit, if // compz == lapack.EVOrig, z contains the orthonormal eigenvectors of the // original symmetric matrix, and if compz == lapack.EVTridiag, z contains the // orthonormal eigenvectors of the symmetric tridiagonal matrix. z is not used // if compz == lapack.EVCompNone. // // work must have length at least max(1, 2*n-2) if the eigenvectors are computed, // and Dsteqr will panic otherwise. // // Dsteqr is an internal routine. It is exported for testing purposes. func (impl Implementation) Dsteqr(compz lapack.EVComp, n int, d, e, z []float64, ldz int, work []float64) (ok bool) { switch { case compz != lapack.EVCompNone && compz != lapack.EVTridiag && compz != lapack.EVOrig: panic(badEVComp) case n < 0: panic(nLT0) case ldz < 1, compz != lapack.EVCompNone && ldz < n: panic(badLdZ) } // Quick return if possible. if n == 0 { return true } switch { case len(d) < n: panic(shortD) case len(e) < n-1: panic(shortE) case compz != lapack.EVCompNone && len(z) < (n-1)*ldz+n: panic(shortZ) case compz != lapack.EVCompNone && len(work) < max(1, 2*n-2): panic(shortWork) } var icompz int if compz == lapack.EVOrig { icompz = 1 } else if compz == lapack.EVTridiag { icompz = 2 } if n == 1 { if icompz == 2 { z[0] = 1 } return true } bi := blas64.Implementation() eps := dlamchE eps2 := eps * eps safmin := dlamchS safmax := 1 / safmin ssfmax := math.Sqrt(safmax) / 3 ssfmin := math.Sqrt(safmin) / eps2 // Compute the eigenvalues and eigenvectors of the tridiagonal matrix. if icompz == 2 { impl.Dlaset(blas.All, n, n, 0, 1, z, ldz) } const maxit = 30 nmaxit := n * maxit jtot := 0 // Determine where the matrix splits and choose QL or QR iteration for each // block, according to whether top or bottom diagonal element is smaller. l1 := 0 nm1 := n - 1 type scaletype int const ( down scaletype = iota + 1 up ) var iscale scaletype for { if l1 > n-1 { // Order eigenvalues and eigenvectors. if icompz == 0 { impl.Dlasrt(lapack.SortIncreasing, n, d) } else { // TODO(btracey): Consider replacing this sort with a call to sort.Sort. for ii := 1; ii < n; ii++ { i := ii - 1 k := i p := d[i] for j := ii; j < n; j++ { if d[j] < p { k = j p = d[j] } } if k != i { d[k] = d[i] d[i] = p bi.Dswap(n, z[i:], ldz, z[k:], ldz) } } } return true } if l1 > 0 { e[l1-1] = 0 } var m int if l1 <= nm1 { for m = l1; m < nm1; m++ { test := math.Abs(e[m]) if test == 0 { break } if test <= (math.Sqrt(math.Abs(d[m]))*math.Sqrt(math.Abs(d[m+1])))*eps { e[m] = 0 break } } } l := l1 lsv := l lend := m lendsv := lend l1 = m + 1 if lend == l { continue } // Scale submatrix in rows and columns L to Lend anorm := impl.Dlanst(lapack.MaxAbs, lend-l+1, d[l:], e[l:]) switch { case anorm == 0: continue case anorm > ssfmax: iscale = down // Pretend that d and e are matrices with 1 column. impl.Dlascl(lapack.General, 0, 0, anorm, ssfmax, lend-l+1, 1, d[l:], 1) impl.Dlascl(lapack.General, 0, 0, anorm, ssfmax, lend-l, 1, e[l:], 1) case anorm < ssfmin: iscale = up impl.Dlascl(lapack.General, 0, 0, anorm, ssfmin, lend-l+1, 1, d[l:], 1) impl.Dlascl(lapack.General, 0, 0, anorm, ssfmin, lend-l, 1, e[l:], 1) } // Choose between QL and QR. if math.Abs(d[lend]) < math.Abs(d[l]) { lend = lsv l = lendsv } if lend > l { // QL Iteration. Look for small subdiagonal element. for { if l != lend { for m = l; m < lend; m++ { v := math.Abs(e[m]) if v*v <= (eps2*math.Abs(d[m]))*math.Abs(d[m+1])+safmin { break } } } else { m = lend } if m < lend { e[m] = 0 } p := d[l] if m == l { // Eigenvalue found. l++ if l > lend { break } continue } // If remaining matrix is 2×2, use Dlae2 to compute its eigensystem. if m == l+1 { if icompz > 0 { d[l], d[l+1], work[l], work[n-1+l] = impl.Dlaev2(d[l], e[l], d[l+1]) impl.Dlasr(blas.Right, lapack.Variable, lapack.Backward, n, 2, work[l:], work[n-1+l:], z[l:], ldz) } else { d[l], d[l+1] = impl.Dlae2(d[l], e[l], d[l+1]) } e[l] = 0 l += 2 if l > lend { break } continue } if jtot == nmaxit { break } jtot++ // Form shift g := (d[l+1] - p) / (2 * e[l]) r := impl.Dlapy2(g, 1) g = d[m] - p + e[l]/(g+math.Copysign(r, g)) s := 1.0 c := 1.0 p = 0.0 // Inner loop for i := m - 1; i >= l; i-- { f := s * e[i] b := c * e[i] c, s, r = impl.Dlartg(g, f) if i != m-1 { e[i+1] = r } g = d[i+1] - p r = (d[i]-g)*s + 2*c*b p = s * r d[i+1] = g + p g = c*r - b // If eigenvectors are desired, then save rotations. if icompz > 0 { work[i] = c work[n-1+i] = -s } } // If eigenvectors are desired, then apply saved rotations. if icompz > 0 { mm := m - l + 1 impl.Dlasr(blas.Right, lapack.Variable, lapack.Backward, n, mm, work[l:], work[n-1+l:], z[l:], ldz) } d[l] -= p e[l] = g } } else { // QR Iteration. // Look for small superdiagonal element. for { if l != lend { for m = l; m > lend; m-- { v := math.Abs(e[m-1]) if v*v <= (eps2*math.Abs(d[m])*math.Abs(d[m-1]) + safmin) { break } } } else { m = lend } if m > lend { e[m-1] = 0 } p := d[l] if m == l { // Eigenvalue found l-- if l < lend { break } continue } // If remaining matrix is 2×2, use Dlae2 to compute its eigenvalues. if m == l-1 { if icompz > 0 { d[l-1], d[l], work[m], work[n-1+m] = impl.Dlaev2(d[l-1], e[l-1], d[l]) impl.Dlasr(blas.Right, lapack.Variable, lapack.Forward, n, 2, work[m:], work[n-1+m:], z[l-1:], ldz) } else { d[l-1], d[l] = impl.Dlae2(d[l-1], e[l-1], d[l]) } e[l-1] = 0 l -= 2 if l < lend { break } continue } if jtot == nmaxit { break } jtot++ // Form shift. g := (d[l-1] - p) / (2 * e[l-1]) r := impl.Dlapy2(g, 1) g = d[m] - p + (e[l-1])/(g+math.Copysign(r, g)) s := 1.0 c := 1.0 p = 0.0 // Inner loop. for i := m; i < l; i++ { f := s * e[i] b := c * e[i] c, s, r = impl.Dlartg(g, f) if i != m { e[i-1] = r } g = d[i] - p r = (d[i+1]-g)*s + 2*c*b p = s * r d[i] = g + p g = c*r - b // If eigenvectors are desired, then save rotations. if icompz > 0 { work[i] = c work[n-1+i] = s } } // If eigenvectors are desired, then apply saved rotations. if icompz > 0 { mm := l - m + 1 impl.Dlasr(blas.Right, lapack.Variable, lapack.Forward, n, mm, work[m:], work[n-1+m:], z[m:], ldz) } d[l] -= p e[l-1] = g } } // Undo scaling if necessary. switch iscale { case down: // Pretend that d and e are matrices with 1 column. impl.Dlascl(lapack.General, 0, 0, ssfmax, anorm, lendsv-lsv+1, 1, d[lsv:], 1) impl.Dlascl(lapack.General, 0, 0, ssfmax, anorm, lendsv-lsv, 1, e[lsv:], 1) case up: impl.Dlascl(lapack.General, 0, 0, ssfmin, anorm, lendsv-lsv+1, 1, d[lsv:], 1) impl.Dlascl(lapack.General, 0, 0, ssfmin, anorm, lendsv-lsv, 1, e[lsv:], 1) } // Check for no convergence to an eigenvalue after a total of n*maxit iterations. if jtot >= nmaxit { break } } for i := 0; i < n-1; i++ { if e[i] != 0 { return false } } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dsterf.go000066400000000000000000000134301450372207100220350ustar00rootroot00000000000000// Copyright ©2016 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/lapack" ) // Dsterf computes all eigenvalues of a symmetric tridiagonal matrix using the // Pal-Walker-Kahan variant of the QL or QR algorithm. // // d contains the diagonal elements of the tridiagonal matrix on entry, and // contains the eigenvalues in ascending order on exit. d must have length at // least n, or Dsterf will panic. // // e contains the off-diagonal elements of the tridiagonal matrix on entry, and is // overwritten during the call to Dsterf. e must have length of at least n-1 or // Dsterf will panic. // // Dsterf is an internal routine. It is exported for testing purposes. func (impl Implementation) Dsterf(n int, d, e []float64) (ok bool) { if n < 0 { panic(nLT0) } // Quick return if possible. if n == 0 { return true } switch { case len(d) < n: panic(shortD) case len(e) < n-1: panic(shortE) } if n == 1 { return true } const ( none = 0 // The values are not scaled. down = 1 // The values are scaled below ssfmax threshold. up = 2 // The values are scaled below ssfmin threshold. ) // Determine the unit roundoff for this environment. eps := dlamchE eps2 := eps * eps safmin := dlamchS safmax := 1 / safmin ssfmax := math.Sqrt(safmax) / 3 ssfmin := math.Sqrt(safmin) / eps2 // Compute the eigenvalues of the tridiagonal matrix. maxit := 30 nmaxit := n * maxit jtot := 0 l1 := 0 for { if l1 > n-1 { impl.Dlasrt(lapack.SortIncreasing, n, d) return true } if l1 > 0 { e[l1-1] = 0 } var m int for m = l1; m < n-1; m++ { if math.Abs(e[m]) <= math.Sqrt(math.Abs(d[m]))*math.Sqrt(math.Abs(d[m+1]))*eps { e[m] = 0 break } } l := l1 lsv := l lend := m lendsv := lend l1 = m + 1 if lend == 0 { continue } // Scale submatrix in rows and columns l to lend. anorm := impl.Dlanst(lapack.MaxAbs, lend-l+1, d[l:], e[l:]) iscale := none if anorm == 0 { continue } if anorm > ssfmax { iscale = down impl.Dlascl(lapack.General, 0, 0, anorm, ssfmax, lend-l+1, 1, d[l:], n) impl.Dlascl(lapack.General, 0, 0, anorm, ssfmax, lend-l, 1, e[l:], n) } else if anorm < ssfmin { iscale = up impl.Dlascl(lapack.General, 0, 0, anorm, ssfmin, lend-l+1, 1, d[l:], n) impl.Dlascl(lapack.General, 0, 0, anorm, ssfmin, lend-l, 1, e[l:], n) } el := e[l:lend] for i, v := range el { el[i] *= v } // Choose between QL and QR iteration. if math.Abs(d[lend]) < math.Abs(d[l]) { lend = lsv l = lendsv } if lend >= l { // QL Iteration. // Look for small sub-diagonal element. for { if l != lend { for m = l; m < lend; m++ { if math.Abs(e[m]) <= eps2*(math.Abs(d[m]*d[m+1])) { break } } } else { m = lend } if m < lend { e[m] = 0 } p := d[l] if m == l { // Eigenvalue found. l++ if l > lend { break } continue } // If remaining matrix is 2 by 2, use Dlae2 to compute its eigenvalues. if m == l+1 { d[l], d[l+1] = impl.Dlae2(d[l], math.Sqrt(e[l]), d[l+1]) e[l] = 0 l += 2 if l > lend { break } continue } if jtot == nmaxit { break } jtot++ // Form shift. rte := math.Sqrt(e[l]) sigma := (d[l+1] - p) / (2 * rte) r := impl.Dlapy2(sigma, 1) sigma = p - (rte / (sigma + math.Copysign(r, sigma))) c := 1.0 s := 0.0 gamma := d[m] - sigma p = gamma * gamma // Inner loop. for i := m - 1; i >= l; i-- { bb := e[i] r := p + bb if i != m-1 { e[i+1] = s * r } oldc := c c = p / r s = bb / r oldgam := gamma alpha := d[i] gamma = c*(alpha-sigma) - s*oldgam d[i+1] = oldgam + (alpha - gamma) if c != 0 { p = (gamma * gamma) / c } else { p = oldc * bb } } e[l] = s * p d[l] = sigma + gamma } } else { for { // QR Iteration. // Look for small super-diagonal element. for m = l; m > lend; m-- { if math.Abs(e[m-1]) <= eps2*math.Abs(d[m]*d[m-1]) { break } } if m > lend { e[m-1] = 0 } p := d[l] if m == l { // Eigenvalue found. l-- if l < lend { break } continue } // If remaining matrix is 2 by 2, use Dlae2 to compute its eigenvalues. if m == l-1 { d[l], d[l-1] = impl.Dlae2(d[l], math.Sqrt(e[l-1]), d[l-1]) e[l-1] = 0 l -= 2 if l < lend { break } continue } if jtot == nmaxit { break } jtot++ // Form shift. rte := math.Sqrt(e[l-1]) sigma := (d[l-1] - p) / (2 * rte) r := impl.Dlapy2(sigma, 1) sigma = p - (rte / (sigma + math.Copysign(r, sigma))) c := 1.0 s := 0.0 gamma := d[m] - sigma p = gamma * gamma // Inner loop. for i := m; i < l; i++ { bb := e[i] r := p + bb if i != m { e[i-1] = s * r } oldc := c c = p / r s = bb / r oldgam := gamma alpha := d[i+1] gamma = c*(alpha-sigma) - s*oldgam d[i] = oldgam + alpha - gamma if c != 0 { p = (gamma * gamma) / c } else { p = oldc * bb } } e[l-1] = s * p d[l] = sigma + gamma } } // Undo scaling if necessary switch iscale { case down: impl.Dlascl(lapack.General, 0, 0, ssfmax, anorm, lendsv-lsv+1, 1, d[lsv:], n) case up: impl.Dlascl(lapack.General, 0, 0, ssfmin, anorm, lendsv-lsv+1, 1, d[lsv:], n) } // Check for no convergence to an eigenvalue after a total of n*maxit iterations. if jtot >= nmaxit { break } } for _, v := range e[:n-1] { if v != 0 { return false } } impl.Dlasrt(lapack.SortIncreasing, n, d) return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dsyev.go000066400000000000000000000065011450372207100217010ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dsyev computes all eigenvalues and, optionally, the eigenvectors of a real // symmetric matrix A. // // w contains the eigenvalues in ascending order upon return. w must have length // at least n, and Dsyev will panic otherwise. // // On entry, a contains the elements of the symmetric matrix A in the triangular // portion specified by uplo. If jobz == lapack.EVCompute, a contains the // orthonormal eigenvectors of A on exit, otherwise jobz must be lapack.EVNone // and on exit the specified triangular region is overwritten. // // work is temporary storage, and lwork specifies the usable memory length. At minimum, // lwork >= 3*n-1, and Dsyev will panic otherwise. The amount of blocking is // limited by the usable length. If lwork == -1, instead of computing Dsyev the // optimal work length is stored into work[0]. func (impl Implementation) Dsyev(jobz lapack.EVJob, uplo blas.Uplo, n int, a []float64, lda int, w, work []float64, lwork int) (ok bool) { switch { case jobz != lapack.EVNone && jobz != lapack.EVCompute: panic(badEVJob) case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < max(1, 3*n-1) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if n == 0 { return true } var opts string if uplo == blas.Upper { opts = "U" } else { opts = "L" } nb := impl.Ilaenv(1, "DSYTRD", opts, n, -1, -1, -1) lworkopt := max(1, (nb+2)*n) if lwork == -1 { work[0] = float64(lworkopt) return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(w) < n: panic(shortW) } if n == 1 { w[0] = a[0] work[0] = 2 if jobz == lapack.EVCompute { a[0] = 1 } return true } safmin := dlamchS eps := dlamchP smlnum := safmin / eps bignum := 1 / smlnum rmin := math.Sqrt(smlnum) rmax := math.Sqrt(bignum) // Scale matrix to allowable range, if necessary. anrm := impl.Dlansy(lapack.MaxAbs, uplo, n, a, lda, work) scaled := false var sigma float64 if anrm > 0 && anrm < rmin { scaled = true sigma = rmin / anrm } else if anrm > rmax { scaled = true sigma = rmax / anrm } if scaled { kind := lapack.LowerTri if uplo == blas.Upper { kind = lapack.UpperTri } impl.Dlascl(kind, 0, 0, 1, sigma, n, n, a, lda) } var inde int indtau := inde + n indwork := indtau + n llwork := lwork - indwork impl.Dsytrd(uplo, n, a, lda, w, work[inde:], work[indtau:], work[indwork:], llwork) // For eigenvalues only, call Dsterf. For eigenvectors, first call Dorgtr // to generate the orthogonal matrix, then call Dsteqr. if jobz == lapack.EVNone { ok = impl.Dsterf(n, w, work[inde:]) } else { impl.Dorgtr(uplo, n, a, lda, work[indtau:], work[indwork:], llwork) ok = impl.Dsteqr(lapack.EVComp(jobz), n, w, work[inde:], a, lda, work[indtau:]) } if !ok { return false } // If the matrix was scaled, then rescale eigenvalues appropriately. if scaled { bi := blas64.Implementation() bi.Dscal(n, 1/sigma, w, 1) } work[0] = float64(lworkopt) return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dsytd2.go000066400000000000000000000102071450372207100217560ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" ) // Dsytd2 reduces a symmetric n×n matrix A to symmetric tridiagonal form T by // an orthogonal similarity transformation // // Qᵀ * A * Q = T // // On entry, the matrix is contained in the specified triangle of a. On exit, // if uplo == blas.Upper, the diagonal and first super-diagonal of a are // overwritten with the elements of T. The elements above the first super-diagonal // are overwritten with the elementary reflectors that are used with // the elements written to tau in order to construct Q. If uplo == blas.Lower, // the elements are written in the lower triangular region. // // d must have length at least n. e and tau must have length at least n-1. Dsytd2 // will panic if these sizes are not met. // // Q is represented as a product of elementary reflectors. // If uplo == blas.Upper // // Q = H_{n-2} * ... * H_1 * H_0 // // and if uplo == blas.Lower // // Q = H_0 * H_1 * ... * H_{n-2} // // where // // H_i = I - tau * v * vᵀ // // where tau is stored in tau[i], and v is stored in a. // // If uplo == blas.Upper, v[0:i-1] is stored in A[0:i-1,i+1], v[i] = 1, and // v[i+1:] = 0. The elements of a are // // [ d e v2 v3 v4] // [ d e v3 v4] // [ d e v4] // [ d e] // [ d] // // If uplo == blas.Lower, v[0:i+1] = 0, v[i+1] = 1, and v[i+2:] is stored in // A[i+2:n,i]. // The elements of a are // // [ d ] // [ e d ] // [v1 e d ] // [v1 v2 e d ] // [v1 v2 v3 e d] // // Dsytd2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dsytd2(uplo blas.Uplo, n int, a []float64, lda int, d, e, tau []float64) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } // Quick return if possible. if n == 0 { return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(d) < n: panic(shortD) case len(e) < n-1: panic(shortE) case len(tau) < n-1: panic(shortTau) } bi := blas64.Implementation() if uplo == blas.Upper { // Reduce the upper triangle of A. for i := n - 2; i >= 0; i-- { // Generate elementary reflector H_i = I - tau * v * vᵀ to // annihilate A[i:i-1, i+1]. var taui float64 a[i*lda+i+1], taui = impl.Dlarfg(i+1, a[i*lda+i+1], a[i+1:], lda) e[i] = a[i*lda+i+1] if taui != 0 { // Apply H_i from both sides to A[0:i,0:i]. a[i*lda+i+1] = 1 // Compute x := tau * A * v storing x in tau[0:i]. bi.Dsymv(uplo, i+1, taui, a, lda, a[i+1:], lda, 0, tau, 1) // Compute w := x - 1/2 * tau * (xᵀ * v) * v. alpha := -0.5 * taui * bi.Ddot(i+1, tau, 1, a[i+1:], lda) bi.Daxpy(i+1, alpha, a[i+1:], lda, tau, 1) // Apply the transformation as a rank-2 update // A = A - v * wᵀ - w * vᵀ. bi.Dsyr2(uplo, i+1, -1, a[i+1:], lda, tau, 1, a, lda) a[i*lda+i+1] = e[i] } d[i+1] = a[(i+1)*lda+i+1] tau[i] = taui } d[0] = a[0] return } // Reduce the lower triangle of A. for i := 0; i < n-1; i++ { // Generate elementary reflector H_i = I - tau * v * vᵀ to // annihilate A[i+2:n, i]. var taui float64 a[(i+1)*lda+i], taui = impl.Dlarfg(n-i-1, a[(i+1)*lda+i], a[min(i+2, n-1)*lda+i:], lda) e[i] = a[(i+1)*lda+i] if taui != 0 { // Apply H_i from both sides to A[i+1:n, i+1:n]. a[(i+1)*lda+i] = 1 // Compute x := tau * A * v, storing y in tau[i:n-1]. bi.Dsymv(uplo, n-i-1, taui, a[(i+1)*lda+i+1:], lda, a[(i+1)*lda+i:], lda, 0, tau[i:], 1) // Compute w := x - 1/2 * tau * (xᵀ * v) * v. alpha := -0.5 * taui * bi.Ddot(n-i-1, tau[i:], 1, a[(i+1)*lda+i:], lda) bi.Daxpy(n-i-1, alpha, a[(i+1)*lda+i:], lda, tau[i:], 1) // Apply the transformation as a rank-2 update // A = A - v * wᵀ - w * vᵀ. bi.Dsyr2(uplo, n-i-1, -1, a[(i+1)*lda+i:], lda, tau[i:], 1, a[(i+1)*lda+i+1:], lda) a[(i+1)*lda+i] = e[i] } d[i] = a[i*lda+i] tau[i] = taui } d[n-1] = a[(n-1)*lda+n-1] } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dsytrd.go000066400000000000000000000123171450372207100220620ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" ) // Dsytrd reduces a symmetric n×n matrix A to symmetric tridiagonal form by an // orthogonal similarity transformation // // Qᵀ * A * Q = T // // where Q is an orthonormal matrix and T is symmetric and tridiagonal. // // On entry, a contains the elements of the input matrix in the triangle specified // by uplo. On exit, the diagonal and sub/super-diagonal are overwritten by the // corresponding elements of the tridiagonal matrix T. The remaining elements in // the triangle, along with the array tau, contain the data to construct Q as // the product of elementary reflectors. // // If uplo == blas.Upper, Q is constructed with // // Q = H_{n-2} * ... * H_1 * H_0 // // where // // H_i = I - tau_i * v * vᵀ // // v is constructed as v[i+1:n] = 0, v[i] = 1, v[0:i-1] is stored in A[0:i-1, i+1]. // The elements of A are // // [ d e v1 v2 v3] // [ d e v2 v3] // [ d e v3] // [ d e] // [ e] // // If uplo == blas.Lower, Q is constructed with // // Q = H_0 * H_1 * ... * H_{n-2} // // where // // H_i = I - tau_i * v * vᵀ // // v is constructed as v[0:i+1] = 0, v[i+1] = 1, v[i+2:n] is stored in A[i+2:n, i]. // The elements of A are // // [ d ] // [ e d ] // [v0 e d ] // [v0 v1 e d ] // [v0 v1 v2 e d] // // d must have length n, and e and tau must have length n-1. Dsytrd will panic if // these conditions are not met. // // work is temporary storage, and lwork specifies the usable memory length. At minimum, // lwork >= 1, and Dsytrd will panic otherwise. The amount of blocking is // limited by the usable length. // If lwork == -1, instead of computing Dsytrd the optimal work length is stored // into work[0]. // // Dsytrd is an internal routine. It is exported for testing purposes. func (impl Implementation) Dsytrd(uplo blas.Uplo, n int, a []float64, lda int, d, e, tau, work []float64, lwork int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case lwork < 1 && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if n == 0 { work[0] = 1 return } nb := impl.Ilaenv(1, "DSYTRD", string(uplo), n, -1, -1, -1) lworkopt := n * nb if lwork == -1 { work[0] = float64(lworkopt) return } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(d) < n: panic(shortD) case len(e) < n-1: panic(shortE) case len(tau) < n-1: panic(shortTau) } bi := blas64.Implementation() nx := n iws := 1 var ldwork int if 1 < nb && nb < n { // Determine when to cross over from blocked to unblocked code. The last // block is always handled by unblocked code. nx = max(nb, impl.Ilaenv(3, "DSYTRD", string(uplo), n, -1, -1, -1)) if nx < n { // Determine if workspace is large enough for blocked code. ldwork = nb iws = n * ldwork if lwork < iws { // Not enough workspace to use optimal nb: determine the minimum // value of nb and reduce nb or force use of unblocked code by // setting nx = n. nb = max(lwork/n, 1) nbmin := impl.Ilaenv(2, "DSYTRD", string(uplo), n, -1, -1, -1) if nb < nbmin { nx = n } } } else { nx = n } } else { nb = 1 } ldwork = nb if uplo == blas.Upper { // Reduce the upper triangle of A. Columns 0:kk are handled by the // unblocked method. var i int kk := n - ((n-nx+nb-1)/nb)*nb for i = n - nb; i >= kk; i -= nb { // Reduce columns i:i+nb to tridiagonal form and form the matrix W // which is needed to update the unreduced part of the matrix. impl.Dlatrd(uplo, i+nb, nb, a, lda, e, tau, work, ldwork) // Update the unreduced submatrix A[0:i-1,0:i-1], using an update // of the form A = A - V*Wᵀ - W*Vᵀ. bi.Dsyr2k(uplo, blas.NoTrans, i, nb, -1, a[i:], lda, work, ldwork, 1, a, lda) // Copy superdiagonal elements back into A, and diagonal elements into D. for j := i; j < i+nb; j++ { a[(j-1)*lda+j] = e[j-1] d[j] = a[j*lda+j] } } // Use unblocked code to reduce the last or only block // check that i == kk. impl.Dsytd2(uplo, kk, a, lda, d, e, tau) } else { var i int // Reduce the lower triangle of A. for i = 0; i < n-nx; i += nb { // Reduce columns 0:i+nb to tridiagonal form and form the matrix W // which is needed to update the unreduced part of the matrix. impl.Dlatrd(uplo, n-i, nb, a[i*lda+i:], lda, e[i:], tau[i:], work, ldwork) // Update the unreduced submatrix A[i+ib:n, i+ib:n], using an update // of the form A = A + V*Wᵀ - W*Vᵀ. bi.Dsyr2k(uplo, blas.NoTrans, n-i-nb, nb, -1, a[(i+nb)*lda+i:], lda, work[nb*ldwork:], ldwork, 1, a[(i+nb)*lda+i+nb:], lda) // Copy subdiagonal elements back into A, and diagonal elements into D. for j := i; j < i+nb; j++ { a[(j+1)*lda+j] = e[j] d[j] = a[j*lda+j] } } // Use unblocked code to reduce the last or only block. impl.Dsytd2(uplo, n-i, a[i*lda+i:], lda, d[i:], e[i:], tau[i:]) } work[0] = float64(iws) } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtbtrs.go000066400000000000000000000033661450372207100220570ustar00rootroot00000000000000// Copyright ©2020 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/blas/blas64" ) // Dtbtrs solves a triangular system of the form // // A * X = B if trans == blas.NoTrans // Aᵀ * X = B if trans == blas.Trans or blas.ConjTrans // // where A is an n×n triangular band matrix with kd super- or subdiagonals, and // B is an n×nrhs matrix. // // Dtbtrs returns whether A is non-singular. If A is singular, no solution X is // computed. func (impl Implementation) Dtbtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, kd, nrhs int, a []float64, lda int, b []float64, ldb int) (ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTrans) case diag != blas.NonUnit && diag != blas.Unit: panic(badDiag) case n < 0: panic(nLT0) case kd < 0: panic(kdLT0) case nrhs < 0: panic(nrhsLT0) case lda < kd+1: panic(badLdA) case ldb < max(1, nrhs): panic(badLdB) } // Quick return if possible. if n == 0 { return true } switch { case len(a) < (n-1)*lda+kd+1: panic(shortA) case len(b) < (n-1)*ldb+nrhs: panic(shortB) } // Check for singularity. if diag == blas.NonUnit { if uplo == blas.Upper { for i := 0; i < n; i++ { if a[i*lda] == 0 { return false } } } else { for i := 0; i < n; i++ { if a[i*lda+kd] == 0 { return false } } } } // Solve A * X = B or Aᵀ * X = B. bi := blas64.Implementation() for j := 0; j < nrhs; j++ { bi.Dtbsv(uplo, trans, diag, n, kd, a, lda, b[j:], ldb) } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtgsja.go000066400000000000000000000235731450372207100220330ustar00rootroot00000000000000// 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dtgsja computes the generalized singular value decomposition (GSVD) // of two real upper triangular or trapezoidal matrices A and B. // // A and B have the following forms, which may be obtained by the // preprocessing subroutine Dggsvp from a general m×n matrix A and p×n // matrix B: // // n-k-l k l // A = k [ 0 A12 A13 ] if m-k-l >= 0; // l [ 0 0 A23 ] // m-k-l [ 0 0 0 ] // // n-k-l k l // A = k [ 0 A12 A13 ] if m-k-l < 0; // m-k [ 0 0 A23 ] // // n-k-l k l // B = l [ 0 0 B13 ] // p-l [ 0 0 0 ] // // where the k×k matrix A12 and l×l matrix B13 are non-singular // upper triangular. A23 is l×l upper triangular if m-k-l >= 0, // otherwise A23 is (m-k)×l upper trapezoidal. // // On exit, // // Uᵀ*A*Q = D1*[ 0 R ], Vᵀ*B*Q = D2*[ 0 R ], // // where U, V and Q are orthogonal matrices. // R is a non-singular upper triangular matrix, and D1 and D2 are // diagonal matrices, which are of the following structures: // // If m-k-l >= 0, // // k l // D1 = k [ I 0 ] // l [ 0 C ] // m-k-l [ 0 0 ] // // k l // D2 = l [ 0 S ] // p-l [ 0 0 ] // // n-k-l k l // [ 0 R ] = k [ 0 R11 R12 ] k // l [ 0 0 R22 ] l // // where // // C = diag( alpha_k, ... , alpha_{k+l} ), // S = diag( beta_k, ... , beta_{k+l} ), // C^2 + S^2 = I. // // R is stored in // // A[0:k+l, n-k-l:n] // // on exit. // // If m-k-l < 0, // // k m-k k+l-m // D1 = k [ I 0 0 ] // m-k [ 0 C 0 ] // // k m-k k+l-m // D2 = m-k [ 0 S 0 ] // k+l-m [ 0 0 I ] // p-l [ 0 0 0 ] // // n-k-l k m-k k+l-m // [ 0 R ] = k [ 0 R11 R12 R13 ] // m-k [ 0 0 R22 R23 ] // k+l-m [ 0 0 0 R33 ] // // where // // C = diag( alpha_k, ... , alpha_m ), // S = diag( beta_k, ... , beta_m ), // C^2 + S^2 = I. // // R = [ R11 R12 R13 ] is stored in A[0:m, n-k-l:n] // [ 0 R22 R23 ] // // and R33 is stored in // // B[m-k:l, n+m-k-l:n] on exit. // // The computation of the orthogonal transformation matrices U, V or Q // is optional. These matrices may either be formed explicitly, or they // may be post-multiplied into input matrices U1, V1, or Q1. // // Dtgsja essentially uses a variant of Kogbetliantz algorithm to reduce // min(l,m-k)×l triangular or trapezoidal matrix A23 and l×l // matrix B13 to the form: // // U1ᵀ*A13*Q1 = C1*R1; V1ᵀ*B13*Q1 = S1*R1, // // where U1, V1 and Q1 are orthogonal matrices. C1 and S1 are diagonal // matrices satisfying // // C1^2 + S1^2 = I, // // and R1 is an l×l non-singular upper triangular matrix. // // jobU, jobV and jobQ are options for computing the orthogonal matrices. The behavior // is as follows // // jobU == lapack.GSVDU Compute orthogonal matrix U // jobU == lapack.GSVDUnit Use unit-initialized matrix // jobU == lapack.GSVDNone Do not compute orthogonal matrix. // // The behavior is the same for jobV and jobQ with the exception that instead of // lapack.GSVDU these accept lapack.GSVDV and lapack.GSVDQ respectively. // The matrices U, V and Q must be m×m, p×p and n×n respectively unless the // relevant job parameter is lapack.GSVDNone. // // k and l specify the sub-blocks in the input matrices A and B: // // A23 = A[k:min(k+l,m), n-l:n) and B13 = B[0:l, n-l:n] // // of A and B, whose GSVD is going to be computed by Dtgsja. // // tola and tolb are the convergence criteria for the Jacobi-Kogbetliantz // iteration procedure. Generally, they are the same as used in the preprocessing // step, for example, // // tola = max(m, n)*norm(A)*eps, // tolb = max(p, n)*norm(B)*eps, // // where eps is the machine epsilon. // // work must have length at least 2*n, otherwise Dtgsja will panic. // // alpha and beta must have length n or Dtgsja will panic. On exit, alpha and // beta contain the generalized singular value pairs of A and B // // alpha[0:k] = 1, // beta[0:k] = 0, // // if m-k-l >= 0, // // alpha[k:k+l] = diag(C), // beta[k:k+l] = diag(S), // // if m-k-l < 0, // // alpha[k:m]= C, alpha[m:k+l]= 0 // beta[k:m] = S, beta[m:k+l] = 1. // // if k+l < n, // // alpha[k+l:n] = 0 and // beta[k+l:n] = 0. // // On exit, A[n-k:n, 0:min(k+l,m)] contains the triangular matrix R or part of R // and if necessary, B[m-k:l, n+m-k-l:n] contains a part of R. // // Dtgsja returns whether the routine converged and the number of iteration cycles // that were run. // // Dtgsja is an internal routine. It is exported for testing purposes. func (impl Implementation) Dtgsja(jobU, jobV, jobQ lapack.GSVDJob, m, p, n, k, l int, a []float64, lda int, b []float64, ldb int, tola, tolb float64, alpha, beta, u []float64, ldu int, v []float64, ldv int, q []float64, ldq int, work []float64) (cycles int, ok bool) { const maxit = 40 initu := jobU == lapack.GSVDUnit wantu := initu || jobU == lapack.GSVDU initv := jobV == lapack.GSVDUnit wantv := initv || jobV == lapack.GSVDV initq := jobQ == lapack.GSVDUnit wantq := initq || jobQ == lapack.GSVDQ switch { case !initu && !wantu && jobU != lapack.GSVDNone: panic(badGSVDJob + "U") case !initv && !wantv && jobV != lapack.GSVDNone: panic(badGSVDJob + "V") case !initq && !wantq && jobQ != lapack.GSVDNone: panic(badGSVDJob + "Q") case m < 0: panic(mLT0) case p < 0: panic(pLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) case len(a) < (m-1)*lda+n: panic(shortA) case ldb < max(1, n): panic(badLdB) case len(b) < (p-1)*ldb+n: panic(shortB) case len(alpha) != n: panic(badLenAlpha) case len(beta) != n: panic(badLenBeta) case ldu < 1, wantu && ldu < m: panic(badLdU) case wantu && len(u) < (m-1)*ldu+m: panic(shortU) case ldv < 1, wantv && ldv < p: panic(badLdV) case wantv && len(v) < (p-1)*ldv+p: panic(shortV) case ldq < 1, wantq && ldq < n: panic(badLdQ) case wantq && len(q) < (n-1)*ldq+n: panic(shortQ) case len(work) < 2*n: panic(shortWork) } // Initialize U, V and Q, if necessary if initu { impl.Dlaset(blas.All, m, m, 0, 1, u, ldu) } if initv { impl.Dlaset(blas.All, p, p, 0, 1, v, ldv) } if initq { impl.Dlaset(blas.All, n, n, 0, 1, q, ldq) } bi := blas64.Implementation() minTol := math.Min(tola, tolb) // Loop until convergence. upper := false for cycles = 1; cycles <= maxit; cycles++ { upper = !upper for i := 0; i < l-1; i++ { for j := i + 1; j < l; j++ { var a1, a2, a3 float64 if k+i < m { a1 = a[(k+i)*lda+n-l+i] } if k+j < m { a3 = a[(k+j)*lda+n-l+j] } b1 := b[i*ldb+n-l+i] b3 := b[j*ldb+n-l+j] var b2 float64 if upper { if k+i < m { a2 = a[(k+i)*lda+n-l+j] } b2 = b[i*ldb+n-l+j] } else { if k+j < m { a2 = a[(k+j)*lda+n-l+i] } b2 = b[j*ldb+n-l+i] } csu, snu, csv, snv, csq, snq := impl.Dlags2(upper, a1, a2, a3, b1, b2, b3) // Update (k+i)-th and (k+j)-th rows of matrix A: Uᵀ*A. if k+j < m { bi.Drot(l, a[(k+j)*lda+n-l:], 1, a[(k+i)*lda+n-l:], 1, csu, snu) } // Update i-th and j-th rows of matrix B: Vᵀ*B. bi.Drot(l, b[j*ldb+n-l:], 1, b[i*ldb+n-l:], 1, csv, snv) // Update (n-l+i)-th and (n-l+j)-th columns of matrices // A and B: A*Q and B*Q. bi.Drot(min(k+l, m), a[n-l+j:], lda, a[n-l+i:], lda, csq, snq) bi.Drot(l, b[n-l+j:], ldb, b[n-l+i:], ldb, csq, snq) if upper { if k+i < m { a[(k+i)*lda+n-l+j] = 0 } b[i*ldb+n-l+j] = 0 } else { if k+j < m { a[(k+j)*lda+n-l+i] = 0 } b[j*ldb+n-l+i] = 0 } // Update orthogonal matrices U, V, Q, if desired. if wantu && k+j < m { bi.Drot(m, u[k+j:], ldu, u[k+i:], ldu, csu, snu) } if wantv { bi.Drot(p, v[j:], ldv, v[i:], ldv, csv, snv) } if wantq { bi.Drot(n, q[n-l+j:], ldq, q[n-l+i:], ldq, csq, snq) } } } if !upper { // The matrices A13 and B13 were lower triangular at the start // of the cycle, and are now upper triangular. // // Convergence test: test the parallelism of the corresponding // rows of A and B. var error float64 for i := 0; i < min(l, m-k); i++ { bi.Dcopy(l-i, a[(k+i)*lda+n-l+i:], 1, work, 1) bi.Dcopy(l-i, b[i*ldb+n-l+i:], 1, work[l:], 1) ssmin := impl.Dlapll(l-i, work, 1, work[l:], 1) error = math.Max(error, ssmin) } if math.Abs(error) <= minTol { // The algorithm has converged. // Compute the generalized singular value pairs (alpha, beta) // and set the triangular matrix R to array A. for i := 0; i < k; i++ { alpha[i] = 1 beta[i] = 0 } for i := 0; i < min(l, m-k); i++ { a1 := a[(k+i)*lda+n-l+i] b1 := b[i*ldb+n-l+i] gamma := b1 / a1 if !math.IsInf(gamma, 0) { // Change sign if necessary. if gamma < 0 { bi.Dscal(l-i, -1, b[i*ldb+n-l+i:], 1) if wantv { bi.Dscal(p, -1, v[i:], ldv) } } beta[k+i], alpha[k+i], _ = impl.Dlartg(math.Abs(gamma), 1) if alpha[k+i] >= beta[k+i] { bi.Dscal(l-i, 1/alpha[k+i], a[(k+i)*lda+n-l+i:], 1) } else { bi.Dscal(l-i, 1/beta[k+i], b[i*ldb+n-l+i:], 1) bi.Dcopy(l-i, b[i*ldb+n-l+i:], 1, a[(k+i)*lda+n-l+i:], 1) } } else { alpha[k+i] = 0 beta[k+i] = 1 bi.Dcopy(l-i, b[i*ldb+n-l+i:], 1, a[(k+i)*lda+n-l+i:], 1) } } for i := m; i < k+l; i++ { alpha[i] = 0 beta[i] = 1 } if k+l < n { for i := k + l; i < n; i++ { alpha[i] = 0 beta[i] = 0 } } return cycles, true } } } // The algorithm has not converged after maxit cycles. return cycles, false } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtrcon.go000066400000000000000000000042011450372207100220330ustar00rootroot00000000000000// 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dtrcon estimates the reciprocal of the condition number of a triangular matrix A. // The condition number computed may be based on the 1-norm or the ∞-norm. // // work is a temporary data slice of length at least 3*n and Dtrcon will panic otherwise. // // iwork is a temporary data slice of length at least n and Dtrcon will panic otherwise. func (impl Implementation) Dtrcon(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int, work []float64, iwork []int) float64 { switch { case norm != lapack.MaxColumnSum && norm != lapack.MaxRowSum: panic(badNorm) case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case diag != blas.NonUnit && diag != blas.Unit: panic(badDiag) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } if n == 0 { return 1 } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(work) < 3*n: panic(shortWork) case len(iwork) < n: panic(shortIWork) } bi := blas64.Implementation() var rcond float64 smlnum := dlamchS * float64(n) anorm := impl.Dlantr(norm, uplo, diag, n, n, a, lda, work) if anorm <= 0 { return rcond } var ainvnm float64 var normin bool kase1 := 2 if norm == lapack.MaxColumnSum { kase1 = 1 } var kase int isave := new([3]int) var scale float64 for { ainvnm, kase = impl.Dlacn2(n, work[n:], work, iwork, ainvnm, kase, isave) if kase == 0 { if ainvnm != 0 { rcond = (1 / anorm) / ainvnm } return rcond } if kase == kase1 { scale = impl.Dlatrs(uplo, blas.NoTrans, diag, normin, n, a, lda, work, work[2*n:]) } else { scale = impl.Dlatrs(uplo, blas.Trans, diag, normin, n, a, lda, work, work[2*n:]) } normin = true if scale != 1 { ix := bi.Idamax(n, work, 1) xnorm := math.Abs(work[ix]) if scale == 0 || scale < xnorm*smlnum { return rcond } impl.Drscl(n, scale, work, 1) } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtrevc3.go000066400000000000000000000664451450372207100221360ustar00rootroot00000000000000// Copyright ©2016 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/blas/blas64" "gonum.org/v1/gonum/lapack" ) // Dtrevc3 computes some or all of the right and/or left eigenvectors of an n×n // upper quasi-triangular matrix T in Schur canonical form. Matrices of this // type are produced by the Schur factorization of a real general matrix A // // A = Q T Qᵀ, // // as computed by Dhseqr. // // The right eigenvector x of T corresponding to an // eigenvalue λ is defined by // // T x = λ x, // // and the left eigenvector y is defined by // // yᵀ T = λ yᵀ. // // The eigenvalues are read directly from the diagonal blocks of T. // // This routine returns the matrices X and/or Y of right and left eigenvectors // of T, or the products Q*X and/or Q*Y, where Q is an input matrix. If Q is the // orthogonal factor that reduces a matrix A to Schur form T, then Q*X and Q*Y // are the matrices of right and left eigenvectors of A. // // If side == lapack.EVRight, only right eigenvectors will be computed. // If side == lapack.EVLeft, only left eigenvectors will be computed. // If side == lapack.EVBoth, both right and left eigenvectors will be computed. // For other values of side, Dtrevc3 will panic. // // If howmny == lapack.EVAll, all right and/or left eigenvectors will be // computed. // If howmny == lapack.EVAllMulQ, all right and/or left eigenvectors will be // computed and multiplied from left by the matrices in VR and/or VL. // If howmny == lapack.EVSelected, right and/or left eigenvectors will be // computed as indicated by selected. // For other values of howmny, Dtrevc3 will panic. // // selected specifies which eigenvectors will be computed. It must have length n // if howmny == lapack.EVSelected, and it is not referenced otherwise. // If w_j is a real eigenvalue, the corresponding real eigenvector will be // computed if selected[j] is true. // If w_j and w_{j+1} are the real and imaginary parts of a complex eigenvalue, // the corresponding complex eigenvector is computed if either selected[j] or // selected[j+1] is true, and on return selected[j] will be set to true and // selected[j+1] will be set to false. // // VL and VR are n×mm matrices. If howmny is lapack.EVAll or // lapack.AllEVMulQ, mm must be at least n. If howmny is // lapack.EVSelected, mm must be large enough to store the selected // eigenvectors. Each selected real eigenvector occupies one column and each // selected complex eigenvector occupies two columns. If mm is not sufficiently // large, Dtrevc3 will panic. // // On entry, if howmny is lapack.EVAllMulQ, it is assumed that VL (if side // is lapack.EVLeft or lapack.EVBoth) contains an n×n matrix QL, // and that VR (if side is lapack.EVRight or lapack.EVBoth) contains // an n×n matrix QR. QL and QR are typically the orthogonal matrix Q of Schur // vectors returned by Dhseqr. // // On return, if side is lapack.EVLeft or lapack.EVBoth, // VL will contain: // // if howmny == lapack.EVAll, the matrix Y of left eigenvectors of T, // if howmny == lapack.EVAllMulQ, the matrix Q*Y, // if howmny == lapack.EVSelected, the left eigenvectors of T specified by // selected, stored consecutively in the // columns of VL, in the same order as their // eigenvalues. // // VL is not referenced if side == lapack.EVRight. // // On return, if side is lapack.EVRight or lapack.EVBoth, // VR will contain: // // if howmny == lapack.EVAll, the matrix X of right eigenvectors of T, // if howmny == lapack.EVAllMulQ, the matrix Q*X, // if howmny == lapack.EVSelected, the left eigenvectors of T specified by // selected, stored consecutively in the // columns of VR, in the same order as their // eigenvalues. // // VR is not referenced if side == lapack.EVLeft. // // Complex eigenvectors corresponding to a complex eigenvalue are stored in VL // and VR in two consecutive columns, the first holding the real part, and the // second the imaginary part. // // Each eigenvector will be normalized so that the element of largest magnitude // has magnitude 1. Here the magnitude of a complex number (x,y) is taken to be // |x| + |y|. // // work must have length at least lwork and lwork must be at least max(1,3*n), // otherwise Dtrevc3 will panic. For optimum performance, lwork should be at // least n+2*n*nb, where nb is the optimal blocksize. // // If lwork == -1, instead of performing Dtrevc3, the function only estimates // the optimal workspace size based on n and stores it into work[0]. // // Dtrevc3 returns the number of columns in VL and/or VR actually used to store // the eigenvectors. // // Dtrevc3 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dtrevc3(side lapack.EVSide, howmny lapack.EVHowMany, selected []bool, n int, t []float64, ldt int, vl []float64, ldvl int, vr []float64, ldvr int, mm int, work []float64, lwork int) (m int) { bothv := side == lapack.EVBoth rightv := side == lapack.EVRight || bothv leftv := side == lapack.EVLeft || bothv switch { case !rightv && !leftv: panic(badEVSide) case howmny != lapack.EVAll && howmny != lapack.EVAllMulQ && howmny != lapack.EVSelected: panic(badEVHowMany) case n < 0: panic(nLT0) case ldt < max(1, n): panic(badLdT) case mm < 0: panic(mmLT0) case ldvl < 1: // ldvl and ldvr are also checked below after the computation of // m (number of columns of VL and VR) in case of howmny == EVSelected. panic(badLdVL) case ldvr < 1: panic(badLdVR) case lwork < max(1, 3*n) && lwork != -1: panic(badLWork) case len(work) < max(1, lwork): panic(shortWork) } // Quick return if possible. if n == 0 { work[0] = 1 return 0 } // Normally we don't check slice lengths until after the workspace // query. However, even in case of the workspace query we need to // compute and return the value of m, and since the computation accesses t, // we put the length check of t here. if len(t) < (n-1)*ldt+n { panic(shortT) } if howmny == lapack.EVSelected { if len(selected) != n { panic(badLenSelected) } // Set m to the number of columns required to store the selected // eigenvectors, and standardize the slice selected. // Each selected real eigenvector occupies one column and each // selected complex eigenvector occupies two columns. for j := 0; j < n; { if j == n-1 || t[(j+1)*ldt+j] == 0 { // Diagonal 1×1 block corresponding to a // real eigenvalue. if selected[j] { m++ } j++ } else { // Diagonal 2×2 block corresponding to a // complex eigenvalue. if selected[j] || selected[j+1] { selected[j] = true selected[j+1] = false m += 2 } j += 2 } } } else { m = n } if mm < m { panic(badMm) } // Quick return in case of a workspace query. nb := impl.Ilaenv(1, "DTREVC", string(side)+string(howmny), n, -1, -1, -1) if lwork == -1 { work[0] = float64(n + 2*n*nb) return m } // Quick return if no eigenvectors were selected. if m == 0 { return 0 } switch { case leftv && ldvl < mm: panic(badLdVL) case leftv && len(vl) < (n-1)*ldvl+mm: panic(shortVL) case rightv && ldvr < mm: panic(badLdVR) case rightv && len(vr) < (n-1)*ldvr+mm: panic(shortVR) } // Use blocked version of back-transformation if sufficient workspace. // Zero-out the workspace to avoid potential NaN propagation. const ( nbmin = 8 nbmax = 128 ) if howmny == lapack.EVAllMulQ && lwork >= n+2*n*nbmin { nb = min((lwork-n)/(2*n), nbmax) impl.Dlaset(blas.All, n, 1+2*nb, 0, 0, work[:n+2*nb*n], 1+2*nb) } else { nb = 1 } // Set the constants to control overflow. ulp := dlamchP smlnum := float64(n) / ulp * dlamchS bignum := (1 - ulp) / smlnum // Split work into a vector of column norms and an n×2*nb matrix b. norms := work[:n] ldb := 2 * nb b := work[n : n+n*ldb] // Compute 1-norm of each column of strictly upper triangular part of T // to control overflow in triangular solver. norms[0] = 0 for j := 1; j < n; j++ { var cn float64 for i := 0; i < j; i++ { cn += math.Abs(t[i*ldt+j]) } norms[j] = cn } bi := blas64.Implementation() var ( x [4]float64 iv int // Index of column in current block. is int // ip is used below to specify the real or complex eigenvalue: // ip == 0, real eigenvalue, // 1, first of conjugate complex pair (wr,wi), // -1, second of conjugate complex pair (wr,wi). ip int iscomplex [nbmax]int // Stores ip for each column in current block. ) if side == lapack.EVLeft { goto leftev } // Compute right eigenvectors. // For complex right vector, iv-1 is for real part and iv for complex // part. Non-blocked version always uses iv=1, blocked version starts // with iv=nb-1 and goes down to 0 or 1. iv = max(2, nb) - 1 ip = 0 is = m - 1 for ki := n - 1; ki >= 0; ki-- { if ip == -1 { // Previous iteration (ki+1) was second of // conjugate pair, so this ki is first of // conjugate pair. ip = 1 continue } if ki == 0 || t[ki*ldt+ki-1] == 0 { // Last column or zero on sub-diagonal, so this // ki must be real eigenvalue. ip = 0 } else { // Non-zero on sub-diagonal, so this ki is // second of conjugate pair. ip = -1 } if howmny == lapack.EVSelected { if ip == 0 { if !selected[ki] { continue } } else if !selected[ki-1] { continue } } // Compute the ki-th eigenvalue (wr,wi). wr := t[ki*ldt+ki] var wi float64 if ip != 0 { wi = math.Sqrt(math.Abs(t[ki*ldt+ki-1])) * math.Sqrt(math.Abs(t[(ki-1)*ldt+ki])) } smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum) if ip == 0 { // Real right eigenvector. b[ki*ldb+iv] = 1 // Form right-hand side. for k := 0; k < ki; k++ { b[k*ldb+iv] = -t[k*ldt+ki] } // Solve upper quasi-triangular system: // [ T[0:ki,0:ki] - wr ]*X = scale*b. for j := ki - 1; j >= 0; { if j == 0 || t[j*ldt+j-1] == 0 { // 1×1 diagonal block. scale, xnorm, _ := impl.Dlaln2(false, 1, 1, smin, 1, t[j*ldt+j:], ldt, 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:1], 2) // Scale X[0,0] to avoid overflow when updating the // right-hand side. if xnorm > 1 && norms[j] > bignum/xnorm { x[0] /= xnorm scale /= xnorm } // Scale if necessary. if scale != 1 { bi.Dscal(ki+1, scale, b[iv:], ldb) } b[j*ldb+iv] = x[0] // Update right-hand side. bi.Daxpy(j, -x[0], t[j:], ldt, b[iv:], ldb) j-- } else { // 2×2 diagonal block. scale, xnorm, _ := impl.Dlaln2(false, 2, 1, smin, 1, t[(j-1)*ldt+j-1:], ldt, 1, 1, b[(j-1)*ldb+iv:], ldb, wr, 0, x[:3], 2) // Scale X[0,0] and X[1,0] to avoid overflow // when updating the right-hand side. if xnorm > 1 { beta := math.Max(norms[j-1], norms[j]) if beta > bignum/xnorm { x[0] /= xnorm x[2] /= xnorm scale /= xnorm } } // Scale if necessary. if scale != 1 { bi.Dscal(ki+1, scale, b[iv:], ldb) } b[(j-1)*ldb+iv] = x[0] b[j*ldb+iv] = x[2] // Update right-hand side. bi.Daxpy(j-1, -x[0], t[j-1:], ldt, b[iv:], ldb) bi.Daxpy(j-1, -x[2], t[j:], ldt, b[iv:], ldb) j -= 2 } } // Copy the vector x or Q*x to VR and normalize. switch { case howmny != lapack.EVAllMulQ: // No back-transform: copy x to VR and normalize. bi.Dcopy(ki+1, b[iv:], ldb, vr[is:], ldvr) ii := bi.Idamax(ki+1, vr[is:], ldvr) remax := 1 / math.Abs(vr[ii*ldvr+is]) bi.Dscal(ki+1, remax, vr[is:], ldvr) for k := ki + 1; k < n; k++ { vr[k*ldvr+is] = 0 } case nb == 1: // Version 1: back-transform each vector with GEMV, Q*x. if ki > 0 { bi.Dgemv(blas.NoTrans, n, ki, 1, vr, ldvr, b[iv:], ldb, b[ki*ldb+iv], vr[ki:], ldvr) } ii := bi.Idamax(n, vr[ki:], ldvr) remax := 1 / math.Abs(vr[ii*ldvr+ki]) bi.Dscal(n, remax, vr[ki:], ldvr) default: // Version 2: back-transform block of vectors with GEMM. // Zero out below vector. for k := ki + 1; k < n; k++ { b[k*ldb+iv] = 0 } iscomplex[iv] = ip // Back-transform and normalization is done below. } } else { // Complex right eigenvector. // Initial solve // [ ( T[ki-1,ki-1] T[ki-1,ki] ) - (wr + i*wi) ]*X = 0. // [ ( T[ki, ki-1] T[ki, ki] ) ] if math.Abs(t[(ki-1)*ldt+ki]) >= math.Abs(t[ki*ldt+ki-1]) { b[(ki-1)*ldb+iv-1] = 1 b[ki*ldb+iv] = wi / t[(ki-1)*ldt+ki] } else { b[(ki-1)*ldb+iv-1] = -wi / t[ki*ldt+ki-1] b[ki*ldb+iv] = 1 } b[ki*ldb+iv-1] = 0 b[(ki-1)*ldb+iv] = 0 // Form right-hand side. for k := 0; k < ki-1; k++ { b[k*ldb+iv-1] = -b[(ki-1)*ldb+iv-1] * t[k*ldt+ki-1] b[k*ldb+iv] = -b[ki*ldb+iv] * t[k*ldt+ki] } // Solve upper quasi-triangular system: // [ T[0:ki-1,0:ki-1] - (wr+i*wi) ]*X = scale*(b1+i*b2) for j := ki - 2; j >= 0; { if j == 0 || t[j*ldt+j-1] == 0 { // 1×1 diagonal block. scale, xnorm, _ := impl.Dlaln2(false, 1, 2, smin, 1, t[j*ldt+j:], ldt, 1, 1, b[j*ldb+iv-1:], ldb, wr, wi, x[:2], 2) // Scale X[0,0] and X[0,1] to avoid // overflow when updating the right-hand side. if xnorm > 1 && norms[j] > bignum/xnorm { x[0] /= xnorm x[1] /= xnorm scale /= xnorm } // Scale if necessary. if scale != 1 { bi.Dscal(ki+1, scale, b[iv-1:], ldb) bi.Dscal(ki+1, scale, b[iv:], ldb) } b[j*ldb+iv-1] = x[0] b[j*ldb+iv] = x[1] // Update the right-hand side. bi.Daxpy(j, -x[0], t[j:], ldt, b[iv-1:], ldb) bi.Daxpy(j, -x[1], t[j:], ldt, b[iv:], ldb) j-- } else { // 2×2 diagonal block. scale, xnorm, _ := impl.Dlaln2(false, 2, 2, smin, 1, t[(j-1)*ldt+j-1:], ldt, 1, 1, b[(j-1)*ldb+iv-1:], ldb, wr, wi, x[:], 2) // Scale X to avoid overflow when updating // the right-hand side. if xnorm > 1 { beta := math.Max(norms[j-1], norms[j]) if beta > bignum/xnorm { rec := 1 / xnorm x[0] *= rec x[1] *= rec x[2] *= rec x[3] *= rec scale *= rec } } // Scale if necessary. if scale != 1 { bi.Dscal(ki+1, scale, b[iv-1:], ldb) bi.Dscal(ki+1, scale, b[iv:], ldb) } b[(j-1)*ldb+iv-1] = x[0] b[(j-1)*ldb+iv] = x[1] b[j*ldb+iv-1] = x[2] b[j*ldb+iv] = x[3] // Update the right-hand side. bi.Daxpy(j-1, -x[0], t[j-1:], ldt, b[iv-1:], ldb) bi.Daxpy(j-1, -x[1], t[j-1:], ldt, b[iv:], ldb) bi.Daxpy(j-1, -x[2], t[j:], ldt, b[iv-1:], ldb) bi.Daxpy(j-1, -x[3], t[j:], ldt, b[iv:], ldb) j -= 2 } } // Copy the vector x or Q*x to VR and normalize. switch { case howmny != lapack.EVAllMulQ: // No back-transform: copy x to VR and normalize. bi.Dcopy(ki+1, b[iv-1:], ldb, vr[is-1:], ldvr) bi.Dcopy(ki+1, b[iv:], ldb, vr[is:], ldvr) emax := 0.0 for k := 0; k <= ki; k++ { emax = math.Max(emax, math.Abs(vr[k*ldvr+is-1])+math.Abs(vr[k*ldvr+is])) } remax := 1 / emax bi.Dscal(ki+1, remax, vr[is-1:], ldvr) bi.Dscal(ki+1, remax, vr[is:], ldvr) for k := ki + 1; k < n; k++ { vr[k*ldvr+is-1] = 0 vr[k*ldvr+is] = 0 } case nb == 1: // Version 1: back-transform each vector with GEMV, Q*x. if ki-1 > 0 { bi.Dgemv(blas.NoTrans, n, ki-1, 1, vr, ldvr, b[iv-1:], ldb, b[(ki-1)*ldb+iv-1], vr[ki-1:], ldvr) bi.Dgemv(blas.NoTrans, n, ki-1, 1, vr, ldvr, b[iv:], ldb, b[ki*ldb+iv], vr[ki:], ldvr) } else { bi.Dscal(n, b[(ki-1)*ldb+iv-1], vr[ki-1:], ldvr) bi.Dscal(n, b[ki*ldb+iv], vr[ki:], ldvr) } emax := 0.0 for k := 0; k < n; k++ { emax = math.Max(emax, math.Abs(vr[k*ldvr+ki-1])+math.Abs(vr[k*ldvr+ki])) } remax := 1 / emax bi.Dscal(n, remax, vr[ki-1:], ldvr) bi.Dscal(n, remax, vr[ki:], ldvr) default: // Version 2: back-transform block of vectors with GEMM. // Zero out below vector. for k := ki + 1; k < n; k++ { b[k*ldb+iv-1] = 0 b[k*ldb+iv] = 0 } iscomplex[iv-1] = -ip iscomplex[iv] = ip iv-- // Back-transform and normalization is done below. } } if nb > 1 { // Blocked version of back-transform. // For complex case, ki2 includes both vectors (ki-1 and ki). ki2 := ki if ip != 0 { ki2-- } // Columns iv:nb of b are valid vectors. // When the number of vectors stored reaches nb-1 or nb, // or if this was last vector, do the Gemm. if iv < 2 || ki2 == 0 { bi.Dgemm(blas.NoTrans, blas.NoTrans, n, nb-iv, ki2+nb-iv, 1, vr, ldvr, b[iv:], ldb, 0, b[nb+iv:], ldb) // Normalize vectors. var remax float64 for k := iv; k < nb; k++ { if iscomplex[k] == 0 { // Real eigenvector. ii := bi.Idamax(n, b[nb+k:], ldb) remax = 1 / math.Abs(b[ii*ldb+nb+k]) } else if iscomplex[k] == 1 { // First eigenvector of conjugate pair. emax := 0.0 for ii := 0; ii < n; ii++ { emax = math.Max(emax, math.Abs(b[ii*ldb+nb+k])+math.Abs(b[ii*ldb+nb+k+1])) } remax = 1 / emax // Second eigenvector of conjugate pair // will reuse this value of remax. } bi.Dscal(n, remax, b[nb+k:], ldb) } impl.Dlacpy(blas.All, n, nb-iv, b[nb+iv:], ldb, vr[ki2:], ldvr) iv = nb - 1 } else { iv-- } } is-- if ip != 0 { is-- } } if side == lapack.EVRight { return m } leftev: // Compute left eigenvectors. // For complex left vector, iv is for real part and iv+1 for complex // part. Non-blocked version always uses iv=0. Blocked version starts // with iv=0, goes up to nb-2 or nb-1. iv = 0 ip = 0 is = 0 for ki := 0; ki < n; ki++ { if ip == 1 { // Previous iteration ki-1 was first of conjugate pair, // so this ki is second of conjugate pair. ip = -1 continue } if ki == n-1 || t[(ki+1)*ldt+ki] == 0 { // Last column or zero on sub-diagonal, so this ki must // be real eigenvalue. ip = 0 } else { // Non-zero on sub-diagonal, so this ki is first of // conjugate pair. ip = 1 } if howmny == lapack.EVSelected && !selected[ki] { continue } // Compute the ki-th eigenvalue (wr,wi). wr := t[ki*ldt+ki] var wi float64 if ip != 0 { wi = math.Sqrt(math.Abs(t[ki*ldt+ki+1])) * math.Sqrt(math.Abs(t[(ki+1)*ldt+ki])) } smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum) if ip == 0 { // Real left eigenvector. b[ki*ldb+iv] = 1 // Form right-hand side. for k := ki + 1; k < n; k++ { b[k*ldb+iv] = -t[ki*ldt+k] } // Solve transposed quasi-triangular system: // [ T[ki+1:n,ki+1:n] - wr ]ᵀ * X = scale*b vmax := 1.0 vcrit := bignum for j := ki + 1; j < n; { if j == n-1 || t[(j+1)*ldt+j] == 0 { // 1×1 diagonal block. // Scale if necessary to avoid overflow // when forming the right-hand side. if norms[j] > vcrit { rec := 1 / vmax bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb) vmax = 1 } b[j*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j:], ldt, b[(ki+1)*ldb+iv:], ldb) // Solve [ T[j,j] - wr ]ᵀ * X = b. scale, _, _ := impl.Dlaln2(false, 1, 1, smin, 1, t[j*ldt+j:], ldt, 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:1], 2) // Scale if necessary. if scale != 1 { bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) } b[j*ldb+iv] = x[0] vmax = math.Max(math.Abs(b[j*ldb+iv]), vmax) vcrit = bignum / vmax j++ } else { // 2×2 diagonal block. // Scale if necessary to avoid overflow // when forming the right-hand side. beta := math.Max(norms[j], norms[j+1]) if beta > vcrit { bi.Dscal(n-ki, 1/vmax, b[ki*ldb+iv:], ldb) vmax = 1 } b[j*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j:], ldt, b[(ki+1)*ldb+iv:], ldb) b[(j+1)*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j+1:], ldt, b[(ki+1)*ldb+iv:], ldb) // Solve // [ T[j,j]-wr T[j,j+1] ]ᵀ * X = scale*[ b1 ] // [ T[j+1,j] T[j+1,j+1]-wr ] [ b2 ] scale, _, _ := impl.Dlaln2(true, 2, 1, smin, 1, t[j*ldt+j:], ldt, 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:3], 2) // Scale if necessary. if scale != 1 { bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) } b[j*ldb+iv] = x[0] b[(j+1)*ldb+iv] = x[2] vmax = math.Max(vmax, math.Max(math.Abs(b[j*ldb+iv]), math.Abs(b[(j+1)*ldb+iv]))) vcrit = bignum / vmax j += 2 } } // Copy the vector x or Q*x to VL and normalize. switch { case howmny != lapack.EVAllMulQ: // No back-transform: copy x to VL and normalize. bi.Dcopy(n-ki, b[ki*ldb+iv:], ldb, vl[ki*ldvl+is:], ldvl) ii := bi.Idamax(n-ki, vl[ki*ldvl+is:], ldvl) + ki remax := 1 / math.Abs(vl[ii*ldvl+is]) bi.Dscal(n-ki, remax, vl[ki*ldvl+is:], ldvl) for k := 0; k < ki; k++ { vl[k*ldvl+is] = 0 } case nb == 1: // Version 1: back-transform each vector with Gemv, Q*x. if n-ki-1 > 0 { bi.Dgemv(blas.NoTrans, n, n-ki-1, 1, vl[ki+1:], ldvl, b[(ki+1)*ldb+iv:], ldb, b[ki*ldb+iv], vl[ki:], ldvl) } ii := bi.Idamax(n, vl[ki:], ldvl) remax := 1 / math.Abs(vl[ii*ldvl+ki]) bi.Dscal(n, remax, vl[ki:], ldvl) default: // Version 2: back-transform block of vectors with Gemm // zero out above vector. for k := 0; k < ki; k++ { b[k*ldb+iv] = 0 } iscomplex[iv] = ip // Back-transform and normalization is done below. } } else { // Complex left eigenvector. // Initial solve: // [ [ T[ki,ki] T[ki,ki+1] ]ᵀ - (wr - i* wi) ]*X = 0. // [ [ T[ki+1,ki] T[ki+1,ki+1] ] ] if math.Abs(t[ki*ldt+ki+1]) >= math.Abs(t[(ki+1)*ldt+ki]) { b[ki*ldb+iv] = wi / t[ki*ldt+ki+1] b[(ki+1)*ldb+iv+1] = 1 } else { b[ki*ldb+iv] = 1 b[(ki+1)*ldb+iv+1] = -wi / t[(ki+1)*ldt+ki] } b[(ki+1)*ldb+iv] = 0 b[ki*ldb+iv+1] = 0 // Form right-hand side. for k := ki + 2; k < n; k++ { b[k*ldb+iv] = -b[ki*ldb+iv] * t[ki*ldt+k] b[k*ldb+iv+1] = -b[(ki+1)*ldb+iv+1] * t[(ki+1)*ldt+k] } // Solve transposed quasi-triangular system: // [ T[ki+2:n,ki+2:n]ᵀ - (wr-i*wi) ]*X = b1+i*b2 vmax := 1.0 vcrit := bignum for j := ki + 2; j < n; { if j == n-1 || t[(j+1)*ldt+j] == 0 { // 1×1 diagonal block. // Scale if necessary to avoid overflow // when forming the right-hand side elements. if norms[j] > vcrit { rec := 1 / vmax bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb) bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb) vmax = 1 } b[j*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv:], ldb) b[j*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv+1:], ldb) // Solve [ T[j,j]-(wr-i*wi) ]*(X11+i*X12) = b1+i*b2. scale, _, _ := impl.Dlaln2(false, 1, 2, smin, 1, t[j*ldt+j:], ldt, 1, 1, b[j*ldb+iv:], ldb, wr, -wi, x[:2], 2) // Scale if necessary. if scale != 1 { bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb) } b[j*ldb+iv] = x[0] b[j*ldb+iv+1] = x[1] vmax = math.Max(vmax, math.Max(math.Abs(b[j*ldb+iv]), math.Abs(b[j*ldb+iv+1]))) vcrit = bignum / vmax j++ } else { // 2×2 diagonal block. // Scale if necessary to avoid overflow // when forming the right-hand side elements. if math.Max(norms[j], norms[j+1]) > vcrit { rec := 1 / vmax bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb) bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb) vmax = 1 } b[j*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv:], ldb) b[j*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv+1:], ldb) b[(j+1)*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j+1:], ldt, b[(ki+2)*ldb+iv:], ldb) b[(j+1)*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j+1:], ldt, b[(ki+2)*ldb+iv+1:], ldb) // Solve 2×2 complex linear equation // [ [T[j,j] T[j,j+1] ]ᵀ - (wr-i*wi)*I ]*X = scale*b // [ [T[j+1,j] T[j+1,j+1]] ] scale, _, _ := impl.Dlaln2(true, 2, 2, smin, 1, t[j*ldt+j:], ldt, 1, 1, b[j*ldb+iv:], ldb, wr, -wi, x[:], 2) // Scale if necessary. if scale != 1 { bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb) } b[j*ldb+iv] = x[0] b[j*ldb+iv+1] = x[1] b[(j+1)*ldb+iv] = x[2] b[(j+1)*ldb+iv+1] = x[3] vmax01 := math.Max(math.Abs(x[0]), math.Abs(x[1])) vmax23 := math.Max(math.Abs(x[2]), math.Abs(x[3])) vmax = math.Max(vmax, math.Max(vmax01, vmax23)) vcrit = bignum / vmax j += 2 } } // Copy the vector x or Q*x to VL and normalize. switch { case howmny != lapack.EVAllMulQ: // No back-transform: copy x to VL and normalize. bi.Dcopy(n-ki, b[ki*ldb+iv:], ldb, vl[ki*ldvl+is:], ldvl) bi.Dcopy(n-ki, b[ki*ldb+iv+1:], ldb, vl[ki*ldvl+is+1:], ldvl) emax := 0.0 for k := ki; k < n; k++ { emax = math.Max(emax, math.Abs(vl[k*ldvl+is])+math.Abs(vl[k*ldvl+is+1])) } remax := 1 / emax bi.Dscal(n-ki, remax, vl[ki*ldvl+is:], ldvl) bi.Dscal(n-ki, remax, vl[ki*ldvl+is+1:], ldvl) for k := 0; k < ki; k++ { vl[k*ldvl+is] = 0 vl[k*ldvl+is+1] = 0 } case nb == 1: // Version 1: back-transform each vector with GEMV, Q*x. if n-ki-2 > 0 { bi.Dgemv(blas.NoTrans, n, n-ki-2, 1, vl[ki+2:], ldvl, b[(ki+2)*ldb+iv:], ldb, b[ki*ldb+iv], vl[ki:], ldvl) bi.Dgemv(blas.NoTrans, n, n-ki-2, 1, vl[ki+2:], ldvl, b[(ki+2)*ldb+iv+1:], ldb, b[(ki+1)*ldb+iv+1], vl[ki+1:], ldvl) } else { bi.Dscal(n, b[ki*ldb+iv], vl[ki:], ldvl) bi.Dscal(n, b[(ki+1)*ldb+iv+1], vl[ki+1:], ldvl) } emax := 0.0 for k := 0; k < n; k++ { emax = math.Max(emax, math.Abs(vl[k*ldvl+ki])+math.Abs(vl[k*ldvl+ki+1])) } remax := 1 / emax bi.Dscal(n, remax, vl[ki:], ldvl) bi.Dscal(n, remax, vl[ki+1:], ldvl) default: // Version 2: back-transform block of vectors with GEMM. // Zero out above vector. // Could go from ki-nv+1 to ki-1. for k := 0; k < ki; k++ { b[k*ldb+iv] = 0 b[k*ldb+iv+1] = 0 } iscomplex[iv] = ip iscomplex[iv+1] = -ip iv++ // Back-transform and normalization is done below. } } if nb > 1 { // Blocked version of back-transform. // For complex case, ki2 includes both vectors ki and ki+1. ki2 := ki if ip != 0 { ki2++ } // Columns [0:iv] of work are valid vectors. When the // number of vectors stored reaches nb-1 or nb, or if // this was last vector, do the Gemm. if iv >= nb-2 || ki2 == n-1 { bi.Dgemm(blas.NoTrans, blas.NoTrans, n, iv+1, n-ki2+iv, 1, vl[ki2-iv:], ldvl, b[(ki2-iv)*ldb:], ldb, 0, b[nb:], ldb) // Normalize vectors. var remax float64 for k := 0; k <= iv; k++ { if iscomplex[k] == 0 { // Real eigenvector. ii := bi.Idamax(n, b[nb+k:], ldb) remax = 1 / math.Abs(b[ii*ldb+nb+k]) } else if iscomplex[k] == 1 { // First eigenvector of conjugate pair. emax := 0.0 for ii := 0; ii < n; ii++ { emax = math.Max(emax, math.Abs(b[ii*ldb+nb+k])+math.Abs(b[ii*ldb+nb+k+1])) } remax = 1 / emax // Second eigenvector of conjugate pair // will reuse this value of remax. } bi.Dscal(n, remax, b[nb+k:], ldb) } impl.Dlacpy(blas.All, n, iv+1, b[nb:], ldb, vl[ki2-iv:], ldvl) iv = 0 } else { iv++ } } is++ if ip != 0 { is++ } } return m } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtrexc.go000066400000000000000000000145231450372207100220430ustar00rootroot00000000000000// Copyright ©2016 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/lapack" // Dtrexc reorders the real Schur factorization of a n×n real matrix // // A = Q*T*Qᵀ // // so that the diagonal block of T with row index ifst is moved to row ilst. // // On entry, T must be in Schur canonical form, that is, block upper triangular // with 1×1 and 2×2 diagonal blocks; each 2×2 diagonal block has its diagonal // elements equal and its off-diagonal elements of opposite sign. // // On return, T will be reordered by an orthogonal similarity transformation Z // as Zᵀ*T*Z, and will be again in Schur canonical form. // // If compq is lapack.UpdateSchur, on return the matrix Q of Schur vectors will be // updated by post-multiplying it with Z. // If compq is lapack.UpdateSchurNone, the matrix Q is not referenced and will not be // updated. // For other values of compq Dtrexc will panic. // // ifst and ilst specify the reordering of the diagonal blocks of T. The block // with row index ifst is moved to row ilst, by a sequence of transpositions // between adjacent blocks. // // If ifst points to the second row of a 2×2 block, ifstOut will point to the // first row, otherwise it will be equal to ifst. // // ilstOut will point to the first row of the block in its final position. If ok // is true, ilstOut may differ from ilst by +1 or -1. // // It must hold that // // 0 <= ifst < n, and 0 <= ilst < n, // // otherwise Dtrexc will panic. // // If ok is false, two adjacent blocks were too close to swap because the // problem is very ill-conditioned. T may have been partially reordered, and // ilstOut will point to the first row of the block at the position to which it // has been moved. // // work must have length at least n, otherwise Dtrexc will panic. // // Dtrexc is an internal routine. It is exported for testing purposes. func (impl Implementation) Dtrexc(compq lapack.UpdateSchurComp, n int, t []float64, ldt int, q []float64, ldq int, ifst, ilst int, work []float64) (ifstOut, ilstOut int, ok bool) { switch { case compq != lapack.UpdateSchur && compq != lapack.UpdateSchurNone: panic(badUpdateSchurComp) case n < 0: panic(nLT0) case ldt < max(1, n): panic(badLdT) case ldq < 1, compq == lapack.UpdateSchur && ldq < n: panic(badLdQ) case (ifst < 0 || n <= ifst) && n > 0: panic(badIfst) case (ilst < 0 || n <= ilst) && n > 0: panic(badIlst) } // Quick return if possible. if n == 0 { return ifst, ilst, true } switch { case len(t) < (n-1)*ldt+n: panic(shortT) case compq == lapack.UpdateSchur && len(q) < (n-1)*ldq+n: panic(shortQ) case len(work) < n: panic(shortWork) } // Quick return if possible. if n == 1 { return ifst, ilst, true } // Determine the first row of specified block // and find out it is 1×1 or 2×2. if ifst > 0 && t[ifst*ldt+ifst-1] != 0 { ifst-- } nbf := 1 // Size of the first block. if ifst+1 < n && t[(ifst+1)*ldt+ifst] != 0 { nbf = 2 } // Determine the first row of the final block // and find out it is 1×1 or 2×2. if ilst > 0 && t[ilst*ldt+ilst-1] != 0 { ilst-- } nbl := 1 // Size of the last block. if ilst+1 < n && t[(ilst+1)*ldt+ilst] != 0 { nbl = 2 } ok = true wantq := compq == lapack.UpdateSchur switch { case ifst == ilst: return ifst, ilst, true case ifst < ilst: // Update ilst. switch { case nbf == 2 && nbl == 1: ilst-- case nbf == 1 && nbl == 2: ilst++ } here := ifst for here < ilst { // Swap block with next one below. if nbf == 1 || nbf == 2 { // Current block either 1×1 or 2×2. nbnext := 1 // Size of the next block. if here+nbf+1 < n && t[(here+nbf+1)*ldt+here+nbf] != 0 { nbnext = 2 } ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, nbf, nbnext, work) if !ok { return ifst, here, false } here += nbnext // Test if 2×2 block breaks into two 1×1 blocks. if nbf == 2 && t[(here+1)*ldt+here] == 0 { nbf = 3 } continue } // Current block consists of two 1×1 blocks each of // which must be swapped individually. nbnext := 1 // Size of the next block. if here+3 < n && t[(here+3)*ldt+here+2] != 0 { nbnext = 2 } ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here+1, 1, nbnext, work) if !ok { return ifst, here, false } if nbnext == 1 { // Swap two 1×1 blocks, no problems possible. impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, nbnext, work) here++ continue } // Recompute nbnext in case 2×2 split. if t[(here+2)*ldt+here+1] == 0 { nbnext = 1 } if nbnext == 2 { // 2×2 block did not split. ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, nbnext, work) if !ok { return ifst, here, false } } else { // 2×2 block did split. impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, 1, work) impl.Dlaexc(wantq, n, t, ldt, q, ldq, here+1, 1, 1, work) } here += 2 } return ifst, here, true default: // ifst > ilst here := ifst for here > ilst { // Swap block with next one above. nbnext := 1 if here >= 2 && t[(here-1)*ldt+here-2] != 0 { nbnext = 2 } if nbf == 1 || nbf == 2 { // Current block either 1×1 or 2×2. ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-nbnext, nbnext, nbf, work) if !ok { return ifst, here, false } here -= nbnext // Test if 2×2 block breaks into two 1×1 blocks. if nbf == 2 && t[(here+1)*ldt+here] == 0 { nbf = 3 } continue } // Current block consists of two 1×1 blocks each of // which must be swapped individually. ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-nbnext, nbnext, 1, work) if !ok { return ifst, here, false } if nbnext == 1 { // Swap two 1×1 blocks, no problems possible. impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, nbnext, 1, work) here-- continue } // Recompute nbnext in case 2×2 split. if t[here*ldt+here-1] == 0 { nbnext = 1 } if nbnext == 2 { // 2×2 block did not split. ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-1, 2, 1, work) if !ok { return ifst, here, false } } else { // 2×2 block did split. impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, 1, work) impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-1, 1, 1, work) } here -= 2 } return ifst, here, true } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtrti2.go000066400000000000000000000030601450372207100217540ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dtrti2 computes the inverse of a triangular matrix, storing the result in place // into a. This is the BLAS level 2 version of the algorithm. // // Dtrti2 is an internal routine. It is exported for testing purposes. func (impl Implementation) Dtrti2(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case diag != blas.NonUnit && diag != blas.Unit: panic(badDiag) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } if n == 0 { return } if len(a) < (n-1)*lda+n { panic(shortA) } bi := blas64.Implementation() nonUnit := diag == blas.NonUnit // TODO(btracey): Replace this with a row-major ordering. if uplo == blas.Upper { for j := 0; j < n; j++ { var ajj float64 if nonUnit { ajj = 1 / a[j*lda+j] a[j*lda+j] = ajj ajj *= -1 } else { ajj = -1 } bi.Dtrmv(blas.Upper, blas.NoTrans, diag, j, a, lda, a[j:], lda) bi.Dscal(j, ajj, a[j:], lda) } return } for j := n - 1; j >= 0; j-- { var ajj float64 if nonUnit { ajj = 1 / a[j*lda+j] a[j*lda+j] = ajj ajj *= -1 } else { ajj = -1 } if j < n-1 { bi.Dtrmv(blas.Lower, blas.NoTrans, diag, n-j-1, a[(j+1)*lda+j+1:], lda, a[(j+1)*lda+j:], lda) bi.Dscal(n-j-1, ajj, a[(j+1)*lda+j:], lda) } } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtrtri.go000066400000000000000000000037741450372207100220700ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dtrtri computes the inverse of a triangular matrix, storing the result in place // into a. This is the BLAS level 3 version of the algorithm which builds upon // Dtrti2 to operate on matrix blocks instead of only individual columns. // // Dtrtri will not perform the inversion if the matrix is singular, and returns // a boolean indicating whether the inversion was successful. func (impl Implementation) Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) (ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case diag != blas.NonUnit && diag != blas.Unit: panic(badDiag) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } if n == 0 { return true } if len(a) < (n-1)*lda+n { panic(shortA) } if diag == blas.NonUnit { for i := 0; i < n; i++ { if a[i*lda+i] == 0 { return false } } } bi := blas64.Implementation() nb := impl.Ilaenv(1, "DTRTRI", "UD", n, -1, -1, -1) if nb <= 1 || nb > n { impl.Dtrti2(uplo, diag, n, a, lda) return true } if uplo == blas.Upper { for j := 0; j < n; j += nb { jb := min(nb, n-j) bi.Dtrmm(blas.Left, blas.Upper, blas.NoTrans, diag, j, jb, 1, a, lda, a[j:], lda) bi.Dtrsm(blas.Right, blas.Upper, blas.NoTrans, diag, j, jb, -1, a[j*lda+j:], lda, a[j:], lda) impl.Dtrti2(blas.Upper, diag, jb, a[j*lda+j:], lda) } return true } nn := ((n - 1) / nb) * nb for j := nn; j >= 0; j -= nb { jb := min(nb, n-j) if j+jb <= n-1 { bi.Dtrmm(blas.Left, blas.Lower, blas.NoTrans, diag, n-j-jb, jb, 1, a[(j+jb)*lda+j+jb:], lda, a[(j+jb)*lda+j:], lda) bi.Dtrsm(blas.Right, blas.Lower, blas.NoTrans, diag, n-j-jb, jb, -1, a[j*lda+j:], lda, a[(j+jb)*lda+j:], lda) } impl.Dtrti2(blas.Lower, diag, jb, a[j*lda+j:], lda) } return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/dtrtrs.go000066400000000000000000000025341450372207100220730ustar00rootroot00000000000000// 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/blas" "gonum.org/v1/gonum/blas/blas64" ) // Dtrtrs solves a triangular system of the form A * X = B or Aᵀ * X = B. Dtrtrs // returns whether the solve completed successfully. If A is singular, no solve is performed. func (impl Implementation) Dtrtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, nrhs int, a []float64, lda int, b []float64, ldb int) (ok bool) { switch { case uplo != blas.Upper && uplo != blas.Lower: panic(badUplo) case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: panic(badTrans) case diag != blas.NonUnit && diag != blas.Unit: panic(badDiag) case n < 0: panic(nLT0) case nrhs < 0: panic(nrhsLT0) case lda < max(1, n): panic(badLdA) case ldb < max(1, nrhs): panic(badLdB) } if n == 0 { return true } switch { case len(a) < (n-1)*lda+n: panic(shortA) case len(b) < (n-1)*ldb+nrhs: panic(shortB) } // Check for singularity. nounit := diag == blas.NonUnit if nounit { for i := 0; i < n; i++ { if a[i*lda+i] == 0 { return false } } } bi := blas64.Implementation() bi.Dtrsm(blas.Left, uplo, trans, diag, n, nrhs, 1, a, lda, b, ldb) return true } golang-gonum-v1-gonum-0.14.0/lapack/gonum/errors.go000066400000000000000000000170441450372207100220670ustar00rootroot00000000000000// 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 // This list is duplicated in netlib/lapack/netlib. Keep in sync. const ( // Panic strings for bad enumeration values. badApplyOrtho = "lapack: bad ApplyOrtho" badBalanceJob = "lapack: bad BalanceJob" badDiag = "lapack: bad Diag" badDirect = "lapack: bad Direct" badEVComp = "lapack: bad EVComp" badEVHowMany = "lapack: bad EVHowMany" badEVJob = "lapack: bad EVJob" badEVSide = "lapack: bad EVSide" badGSVDJob = "lapack: bad GSVDJob" badGenOrtho = "lapack: bad GenOrtho" badLeftEVJob = "lapack: bad LeftEVJob" badMatrixType = "lapack: bad MatrixType" badMaximizeNormXJob = "lapack: bad MaximizeNormXJob" badNorm = "lapack: bad Norm" badPivot = "lapack: bad Pivot" badRightEVJob = "lapack: bad RightEVJob" badSVDJob = "lapack: bad SVDJob" badSchurComp = "lapack: bad SchurComp" badSchurJob = "lapack: bad SchurJob" badSide = "lapack: bad Side" badSort = "lapack: bad Sort" badStoreV = "lapack: bad StoreV" badTrans = "lapack: bad Trans" badUpdateSchurComp = "lapack: bad UpdateSchurComp" badUplo = "lapack: bad Uplo" bothSVDOver = "lapack: both jobU and jobVT are lapack.SVDOverwrite" // Panic strings for bad numerical and string values. badIfst = "lapack: ifst out of range" badIhi = "lapack: ihi out of range" badIhiz = "lapack: ihiz out of range" badIlo = "lapack: ilo out of range" badIloz = "lapack: iloz out of range" badIlst = "lapack: ilst out of range" badIsave = "lapack: bad isave value" badIspec = "lapack: bad ispec value" badJ1 = "lapack: j1 out of range" badJpvt = "lapack: bad element of jpvt" badK1 = "lapack: k1 out of range" badK2 = "lapack: k2 out of range" badKacc22 = "lapack: invalid value of kacc22" badKbot = "lapack: kbot out of range" badKtop = "lapack: ktop out of range" badLWork = "lapack: insufficient declared workspace length" badMm = "lapack: mm out of range" badN1 = "lapack: bad value of n1" badN2 = "lapack: bad value of n2" badNa = "lapack: bad value of na" badName = "lapack: bad name" badNh = "lapack: bad value of nh" badNw = "lapack: bad value of nw" badPp = "lapack: bad value of pp" badShifts = "lapack: bad shifts" i0LT0 = "lapack: i0 < 0" kGTM = "lapack: k > m" kGTN = "lapack: k > n" kLT0 = "lapack: k < 0" kLT1 = "lapack: k < 1" kdLT0 = "lapack: kd < 0" klLT0 = "lapack: kl < 0" kuLT0 = "lapack: ku < 0" mGTN = "lapack: m > n" mLT0 = "lapack: m < 0" mmLT0 = "lapack: mm < 0" n0LT0 = "lapack: n0 < 0" nGTM = "lapack: n > m" nLT0 = "lapack: n < 0" nLT1 = "lapack: n < 1" nLTM = "lapack: n < m" nanCFrom = "lapack: cfrom is NaN" nanCTo = "lapack: cto is NaN" nbGTM = "lapack: nb > m" nbGTN = "lapack: nb > n" nbLT0 = "lapack: nb < 0" nccLT0 = "lapack: ncc < 0" ncvtLT0 = "lapack: ncvt < 0" negANorm = "lapack: anorm < 0" negZ = "lapack: negative z value" nhLT0 = "lapack: nh < 0" notIsolated = "lapack: block is not isolated" nrhsLT0 = "lapack: nrhs < 0" nruLT0 = "lapack: nru < 0" nshftsLT0 = "lapack: nshfts < 0" nshftsOdd = "lapack: nshfts must be even" nvLT0 = "lapack: nv < 0" offsetGTM = "lapack: offset > m" offsetLT0 = "lapack: offset < 0" pLT0 = "lapack: p < 0" recurLT0 = "lapack: recur < 0" zeroCFrom = "lapack: zero cfrom" // Panic strings for bad slice lengths. badLenAlpha = "lapack: bad length of alpha" badLenBeta = "lapack: bad length of beta" badLenIpiv = "lapack: bad length of ipiv" badLenJpiv = "lapack: bad length of jpiv" badLenJpvt = "lapack: bad length of jpvt" badLenK = "lapack: bad length of k" badLenPiv = "lapack: bad length of piv" badLenSelected = "lapack: bad length of selected" badLenSi = "lapack: bad length of si" badLenSr = "lapack: bad length of sr" badLenTau = "lapack: bad length of tau" badLenWi = "lapack: bad length of wi" badLenWr = "lapack: bad length of wr" // Panic strings for insufficient slice lengths. shortA = "lapack: insufficient length of a" shortAB = "lapack: insufficient length of ab" shortAuxv = "lapack: insufficient length of auxv" shortB = "lapack: insufficient length of b" shortC = "lapack: insufficient length of c" shortCNorm = "lapack: insufficient length of cnorm" shortD = "lapack: insufficient length of d" shortDL = "lapack: insufficient length of dl" shortDU = "lapack: insufficient length of du" shortE = "lapack: insufficient length of e" shortF = "lapack: insufficient length of f" shortH = "lapack: insufficient length of h" shortIWork = "lapack: insufficient length of iwork" shortIsgn = "lapack: insufficient length of isgn" shortQ = "lapack: insufficient length of q" shortRHS = "lapack: insufficient length of rhs" shortS = "lapack: insufficient length of s" shortScale = "lapack: insufficient length of scale" shortT = "lapack: insufficient length of t" shortTau = "lapack: insufficient length of tau" shortTauP = "lapack: insufficient length of tauP" shortTauQ = "lapack: insufficient length of tauQ" shortU = "lapack: insufficient length of u" shortV = "lapack: insufficient length of v" shortVL = "lapack: insufficient length of vl" shortVR = "lapack: insufficient length of vr" shortVT = "lapack: insufficient length of vt" shortVn1 = "lapack: insufficient length of vn1" shortVn2 = "lapack: insufficient length of vn2" shortW = "lapack: insufficient length of w" shortWH = "lapack: insufficient length of wh" shortWV = "lapack: insufficient length of wv" shortWi = "lapack: insufficient length of wi" shortWork = "lapack: insufficient length of work" shortWr = "lapack: insufficient length of wr" shortX = "lapack: insufficient length of x" shortY = "lapack: insufficient length of y" shortZ = "lapack: insufficient length of z" // Panic strings for bad leading dimensions of matrices. badLdA = "lapack: bad leading dimension of A" badLdB = "lapack: bad leading dimension of B" badLdC = "lapack: bad leading dimension of C" badLdF = "lapack: bad leading dimension of F" badLdH = "lapack: bad leading dimension of H" badLdQ = "lapack: bad leading dimension of Q" badLdT = "lapack: bad leading dimension of T" badLdU = "lapack: bad leading dimension of U" badLdV = "lapack: bad leading dimension of V" badLdVL = "lapack: bad leading dimension of VL" badLdVR = "lapack: bad leading dimension of VR" badLdVT = "lapack: bad leading dimension of VT" badLdW = "lapack: bad leading dimension of W" badLdWH = "lapack: bad leading dimension of WH" badLdWV = "lapack: bad leading dimension of WV" badLdWork = "lapack: bad leading dimension of Work" badLdX = "lapack: bad leading dimension of X" badLdY = "lapack: bad leading dimension of Y" badLdZ = "lapack: bad leading dimension of Z" // Panic strings for bad vector increments. absIncNotOne = "lapack: increment not one or negative one" badIncX = "lapack: incX <= 0" badIncY = "lapack: incY <= 0" zeroIncV = "lapack: incv == 0" ) golang-gonum-v1-gonum-0.14.0/lapack/gonum/iladlc.go000066400000000000000000000016551450372207100220040ustar00rootroot00000000000000// 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 // Iladlc scans a matrix for its last non-zero column. Returns -1 if the matrix // is all zeros. // // Iladlc is an internal routine. It is exported for testing purposes. func (Implementation) Iladlc(m, n int, a []float64, lda int) int { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } if n == 0 || m == 0 { return -1 } if len(a) < (m-1)*lda+n { panic(shortA) } // Test common case where corner is non-zero. if a[n-1] != 0 || a[(m-1)*lda+(n-1)] != 0 { return n - 1 } // Scan each row tracking the highest column seen. highest := -1 for i := 0; i < m; i++ { for j := n - 1; j >= 0; j-- { if a[i*lda+j] != 0 { highest = max(highest, j) break } } } return highest } golang-gonum-v1-gonum-0.14.0/lapack/gonum/iladlr.go000066400000000000000000000015221450372207100220140ustar00rootroot00000000000000// 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 // Iladlr scans a matrix for its last non-zero row. Returns -1 if the matrix // is all zeros. // // Iladlr is an internal routine. It is exported for testing purposes. func (Implementation) Iladlr(m, n int, a []float64, lda int) int { switch { case m < 0: panic(mLT0) case n < 0: panic(nLT0) case lda < max(1, n): panic(badLdA) } if n == 0 || m == 0 { return -1 } if len(a) < (m-1)*lda+n { panic(shortA) } // Check the common case where the corner is non-zero if a[(m-1)*lda] != 0 || a[(m-1)*lda+n-1] != 0 { return m - 1 } for i := m - 1; i >= 0; i-- { for j := 0; j < n; j++ { if a[i*lda+j] != 0 { return i } } } return -1 } golang-gonum-v1-gonum-0.14.0/lapack/gonum/ilaenv.go000066400000000000000000000152431450372207100220300ustar00rootroot00000000000000// 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 // Ilaenv returns algorithm tuning parameters for the algorithm given by the // input string. ispec specifies the parameter to return: // // 1: The optimal block size for a blocked algorithm. // 2: The minimum block size for a blocked algorithm. // 3: The block size of unprocessed data at which a blocked algorithm should // crossover to an unblocked version. // 4: The number of shifts. // 5: The minimum column dimension for blocking to be used. // 6: The crossover point for SVD (to use QR factorization or not). // 7: The number of processors. // 8: The crossover point for multi-shift in QR and QZ methods for non-symmetric eigenvalue problems. // 9: Maximum size of the subproblems in divide-and-conquer algorithms. // 10: ieee infinity and NaN arithmetic can be trusted not to trap. // 11: ieee infinity arithmetic can be trusted not to trap. // 12...16: parameters for Dhseqr and related functions. See Iparmq for more // information. // // Ilaenv is an internal routine. It is exported for testing purposes. func (impl Implementation) Ilaenv(ispec int, name string, opts string, n1, n2, n3, n4 int) int { // TODO(btracey): Replace this with a constant lookup? A list of constants? sname := name[0] == 'S' || name[0] == 'D' cname := name[0] == 'C' || name[0] == 'Z' if !sname && !cname { panic(badName) } c2 := name[1:3] c3 := name[3:6] c4 := c3[1:3] switch ispec { default: panic(badIspec) case 1: switch c2 { default: panic(badName) case "GE": switch c3 { default: panic(badName) case "TRF": if sname { return 64 } return 64 case "QRF", "RQF", "LQF", "QLF": if sname { return 32 } return 32 case "HRD": if sname { return 32 } return 32 case "BRD": if sname { return 32 } return 32 case "TRI": if sname { return 64 } return 64 } case "PO": switch c3 { default: panic(badName) case "TRF": if sname { return 64 } return 64 } case "SY": switch c3 { default: panic(badName) case "TRF": if sname { return 64 } return 64 case "TRD": return 32 case "GST": return 64 } case "HE": switch c3 { default: panic(badName) case "TRF": return 64 case "TRD": return 32 case "GST": return 64 } case "OR": switch c3[0] { default: panic(badName) case 'G': switch c3[1:] { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 32 } case 'M': switch c3[1:] { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 32 } } case "UN": switch c3[0] { default: panic(badName) case 'G': switch c3[1:] { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 32 } case 'M': switch c3[1:] { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 32 } } case "GB": switch c3 { default: panic(badName) case "TRF": if sname { if n4 <= 64 { return 1 } return 32 } if n4 <= 64 { return 1 } return 32 } case "PB": switch c3 { default: panic(badName) case "TRF": if sname { if n2 <= 64 { return 1 } return 32 } if n2 <= 64 { return 1 } return 32 } case "TR": switch c3 { default: panic(badName) case "TRI": if sname { return 64 } return 64 case "EVC": if sname { return 64 } return 64 } case "LA": switch c3 { default: panic(badName) case "UUM": if sname { return 64 } return 64 } case "ST": if sname && c3 == "EBZ" { return 1 } panic(badName) } case 2: switch c2 { default: panic(badName) case "GE": switch c3 { default: panic(badName) case "QRF", "RQF", "LQF", "QLF": if sname { return 2 } return 2 case "HRD": if sname { return 2 } return 2 case "BRD": if sname { return 2 } return 2 case "TRI": if sname { return 2 } return 2 } case "SY": switch c3 { default: panic(badName) case "TRF": if sname { return 8 } return 8 case "TRD": if sname { return 2 } panic(badName) } case "HE": if c3 == "TRD" { return 2 } panic(badName) case "OR": if !sname { panic(badName) } switch c3[0] { default: panic(badName) case 'G': switch c4 { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 2 } case 'M': switch c4 { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 2 } } case "UN": switch c3[0] { default: panic(badName) case 'G': switch c4 { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 2 } case 'M': switch c4 { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 2 } } } case 3: switch c2 { default: panic(badName) case "GE": switch c3 { default: panic(badName) case "QRF", "RQF", "LQF", "QLF": if sname { return 128 } return 128 case "HRD": if sname { return 128 } return 128 case "BRD": if sname { return 128 } return 128 } case "SY": if sname && c3 == "TRD" { return 32 } panic(badName) case "HE": if c3 == "TRD" { return 32 } panic(badName) case "OR": switch c3[0] { default: panic(badName) case 'G': switch c4 { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 128 } } case "UN": switch c3[0] { default: panic(badName) case 'G': switch c4 { default: panic(badName) case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR": return 128 } } } case 4: // Used by xHSEQR return 6 case 5: // Not used return 2 case 6: // Used by xGELSS and xGESVD return int(float64(min(n1, n2)) * 1.6) case 7: // Not used return 1 case 8: // Used by xHSEQR return 50 case 9: // used by xGELSD and xGESDD return 25 case 10: // Go guarantees ieee return 1 case 11: // Go guarantees ieee return 1 case 12, 13, 14, 15, 16: // Dhseqr and related functions for eigenvalue problems. return impl.Iparmq(ispec, name, opts, n1, n2, n3, n4) } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/iparmq.go000066400000000000000000000052651450372207100220460ustar00rootroot00000000000000// Copyright ©2016 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" // Iparmq returns problem and machine dependent parameters useful for Dhseqr and // related subroutines for eigenvalue problems. // // ispec specifies the parameter to return: // // 12: Crossover point between Dlahqr and Dlaqr0. Will be at least 11. // 13: Deflation window size. // 14: Nibble crossover point. Determines when to skip a multi-shift QR sweep. // 15: Number of simultaneous shifts in a multishift QR iteration. // 16: Select structured matrix multiply. // // For other values of ispec Iparmq will panic. // // name is the name of the calling function. name must be in uppercase but this // is not checked. // // opts is not used and exists for future use. // // n is the order of the Hessenberg matrix H. // // ilo and ihi specify the block [ilo:ihi+1,ilo:ihi+1] that is being processed. // // lwork is the amount of workspace available. // // Except for ispec input parameters are not checked. // // Iparmq is an internal routine. It is exported for testing purposes. func (Implementation) Iparmq(ispec int, name, opts string, n, ilo, ihi, lwork int) int { nh := ihi - ilo + 1 ns := 2 switch { case nh >= 30: ns = 4 case nh >= 60: ns = 10 case nh >= 150: ns = max(10, nh/int(math.Log(float64(nh))/math.Ln2)) case nh >= 590: ns = 64 case nh >= 3000: ns = 128 case nh >= 6000: ns = 256 } ns = max(2, ns-(ns%2)) switch ispec { default: panic(badIspec) case 12: // Matrices of order smaller than nmin get sent to Dlahqr, the // classic double shift algorithm. This must be at least 11. const nmin = 75 return nmin case 13: const knwswp = 500 if nh <= knwswp { return ns } return 3 * ns / 2 case 14: // Skip a computationally expensive multi-shift QR sweep with // Dlaqr5 whenever aggressive early deflation finds at least // nibble*(window size)/100 deflations. The default, small, // value reflects the expectation that the cost of looking // through the deflation window with Dlaqr3 will be // substantially smaller. const nibble = 14 return nibble case 15: return ns case 16: if len(name) != 6 { panic(badName) } const ( k22min = 14 kacmin = 14 ) var acc22 int switch { case name[1:] == "GGHRD" || name[1:] == "GGHD3": acc22 = 1 if nh >= k22min { acc22 = 2 } case name[3:] == "EXC": if nh >= kacmin { acc22 = 1 } if nh >= k22min { acc22 = 2 } case name[1:] == "HSEQR" || name[1:5] == "LAQR": if ns >= kacmin { acc22 = 1 } if ns >= k22min { acc22 = 2 } } return acc22 } } golang-gonum-v1-gonum-0.14.0/lapack/gonum/lapack.go000066400000000000000000000044141450372207100220030ustar00rootroot00000000000000// 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/lapack" // Implementation is the native Go implementation of LAPACK routines. It // is built on top of calls to the return of blas64.Implementation(), so while // this code is in pure Go, the underlying BLAS implementation may not be. type Implementation struct{} var _ lapack.Float64 = Implementation{} 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 } func abs(a int) int { if a < 0 { return -a } return a } const ( // dlamchE is the machine epsilon. For IEEE this is 2^{-53}. dlamchE = 0x1p-53 // dlamchB is the radix of the machine (the base of the number system). dlamchB = 2 // dlamchP is base * eps. dlamchP = dlamchB * dlamchE // dlamchS is the "safe minimum", that is, the lowest number such that // 1/dlamchS does not overflow, or also the smallest normal number. // For IEEE this is 2^{-1022}. dlamchS = 0x1p-1022 // Blue's scaling constants // // An n-vector x is well-scaled if // dtsml ≤ |xᵢ| ≤ dtbig for 0 ≤ i < n and n ≤ 1/dlamchP, // where // dtsml = 2^ceil((expmin-1)/2) = 2^ceil((-1021-1)/2) = 2^{-511} = 1.4916681462400413e-154 // dtbig = 2^floor((expmax-digits+1)/2) = 2^floor((1024-53+1)/2) = 2^{486} = 1.997919072202235e+146 // If any xᵢ is not well-scaled, then multiplying small values by dssml and // large values by dsbig avoids underflow or overflow when computing the sum // of squares \sum_0^{n-1} (xᵢ)². // dssml = 2^{-floor((expmin-digits)/2)} = 2^{-floor((-1021-53)/2)} = 2^537 = 4.4989137945431964e+161 // dsbig = 2^{-ceil((expmax+digits-1)/2)} = 2^{-ceil((1024+53-1)/2)} = 2^{-538} = 1.1113793747425387e-162 // // References: // - Anderson E. (2017) // Algorithm 978: Safe Scaling in the Level 1 BLAS // ACM Trans Math Softw 44:1--28 // https://doi.org/10.1145/3061665 // - Blue, James L. (1978) // A Portable Fortran Program to Find the Euclidean Norm of a Vector // ACM Trans Math Softw 4:15--23 // https://doi.org/10.1145/355769.355771 dtsml = 0x1p-511 dtbig = 0x1p486 dssml = 0x1p537 dsbig = 0x1p-538 ) golang-gonum-v1-gonum-0.14.0/lapack/gonum/lapack_test.go000066400000000000000000000245131450372207100230440ustar00rootroot00000000000000// 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 ( "testing" "gonum.org/v1/gonum/lapack/testlapack" ) var impl = Implementation{} func TestDbdsqr(t *testing.T) { t.Parallel() testlapack.DbdsqrTest(t, impl) } func TestDhseqr(t *testing.T) { t.Parallel() testlapack.DhseqrTest(t, impl) } func TestDgebak(t *testing.T) { t.Parallel() testlapack.DgebakTest(t, impl) } func TestDgebal(t *testing.T) { t.Parallel() testlapack.DgebalTest(t, impl) } func TestDgebd2(t *testing.T) { t.Parallel() testlapack.Dgebd2Test(t, impl) } func TestDgebrd(t *testing.T) { t.Parallel() testlapack.DgebrdTest(t, impl) } func TestDgecon(t *testing.T) { t.Parallel() testlapack.DgeconTest(t, impl) } func TestDgeev(t *testing.T) { t.Parallel() testlapack.DgeevTest(t, impl) } func TestDgehd2(t *testing.T) { t.Parallel() testlapack.Dgehd2Test(t, impl) } func TestDgehrd(t *testing.T) { t.Parallel() testlapack.DgehrdTest(t, impl) } func TestDgelqf(t *testing.T) { t.Parallel() testlapack.DgelqfTest(t, impl) } func TestDgelq2(t *testing.T) { t.Parallel() testlapack.Dgelq2Test(t, impl) } func TestDgeql2(t *testing.T) { t.Parallel() testlapack.Dgeql2Test(t, impl) } func TestDgels(t *testing.T) { t.Parallel() testlapack.DgelsTest(t, impl) } func TestDgerq2(t *testing.T) { t.Parallel() testlapack.Dgerq2Test(t, impl) } func TestDgesc2(t *testing.T) { t.Parallel() testlapack.Dgesc2Test(t, impl) } func TestDgeqp3(t *testing.T) { t.Parallel() testlapack.Dgeqp3Test(t, impl) } func TestDgeqr2(t *testing.T) { t.Parallel() testlapack.Dgeqr2Test(t, impl) } func TestDgeqrf(t *testing.T) { t.Parallel() testlapack.DgeqrfTest(t, impl) } func TestDgerqf(t *testing.T) { t.Parallel() testlapack.DgerqfTest(t, impl) } func TestDgesv(t *testing.T) { t.Parallel() testlapack.DgesvTest(t, impl) } func TestDgesvd(t *testing.T) { t.Parallel() const tol = 1e-13 testlapack.DgesvdTest(t, impl, tol) } func TestDgetc2(t *testing.T) { t.Parallel() testlapack.Dgetc2Test(t, impl) } func TestDgetri(t *testing.T) { t.Parallel() testlapack.DgetriTest(t, impl) } func TestDgetf2(t *testing.T) { t.Parallel() testlapack.Dgetf2Test(t, impl) } func TestDgetrf(t *testing.T) { t.Parallel() testlapack.DgetrfTest(t, impl) } func TestDgetrs(t *testing.T) { t.Parallel() testlapack.DgetrsTest(t, impl) } func TestDggsvd3(t *testing.T) { t.Parallel() testlapack.Dggsvd3Test(t, impl) } func TestDggsvp3(t *testing.T) { t.Parallel() testlapack.Dggsvp3Test(t, impl) } func TestDgtsv(t *testing.T) { t.Parallel() testlapack.DgtsvTest(t, impl) } func TestDlabrd(t *testing.T) { t.Parallel() testlapack.DlabrdTest(t, impl) } func TestDlacn2(t *testing.T) { t.Parallel() testlapack.Dlacn2Test(t, impl) } func TestDlacpy(t *testing.T) { t.Parallel() testlapack.DlacpyTest(t, impl) } func TestDlae2(t *testing.T) { t.Parallel() testlapack.Dlae2Test(t, impl) } func TestDlaev2(t *testing.T) { t.Parallel() testlapack.Dlaev2Test(t, impl) } func TestDlaexc(t *testing.T) { t.Parallel() testlapack.DlaexcTest(t, impl) } func TestDlag2(t *testing.T) { t.Parallel() testlapack.Dlag2Test(t, impl) } func TestDlags2(t *testing.T) { t.Parallel() testlapack.Dlags2Test(t, impl) } func TestDlagtm(t *testing.T) { t.Parallel() testlapack.DlagtmTest(t, impl) } func TestDlahqr(t *testing.T) { t.Parallel() testlapack.DlahqrTest(t, impl) } func TestDlahr2(t *testing.T) { t.Parallel() testlapack.Dlahr2Test(t, impl) } func TestDlaln2(t *testing.T) { t.Parallel() testlapack.Dlaln2Test(t, impl) } func TestDlangb(t *testing.T) { t.Parallel() testlapack.DlangbTest(t, impl) } func TestDlange(t *testing.T) { t.Parallel() testlapack.DlangeTest(t, impl) } func TestDlangt(t *testing.T) { t.Parallel() testlapack.DlangtTest(t, impl) } func TestDlapy2(t *testing.T) { t.Parallel() testlapack.Dlapy2Test(t, impl) } func TestDlapll(t *testing.T) { t.Parallel() testlapack.DlapllTest(t, impl) } func TestDlapmr(t *testing.T) { t.Parallel() testlapack.DlapmrTest(t, impl) } func TestDlapmt(t *testing.T) { t.Parallel() testlapack.DlapmtTest(t, impl) } func TestDlas2(t *testing.T) { t.Parallel() testlapack.Dlas2Test(t, impl) } func TestDlascl(t *testing.T) { t.Parallel() testlapack.DlasclTest(t, impl) } func TestDlaset(t *testing.T) { t.Parallel() testlapack.DlasetTest(t, impl) } func TestDlasrt(t *testing.T) { t.Parallel() testlapack.DlasrtTest(t, impl) } func TestDlassq(t *testing.T) { t.Parallel() testlapack.DlassqTest(t, impl) } func TestDlaswp(t *testing.T) { t.Parallel() testlapack.DlaswpTest(t, impl) } func TestDlasy2(t *testing.T) { t.Parallel() testlapack.Dlasy2Test(t, impl) } func TestDlansb(t *testing.T) { t.Parallel() testlapack.DlansbTest(t, impl) } func TestDlanst(t *testing.T) { t.Parallel() testlapack.DlanstTest(t, impl) } func TestDlansy(t *testing.T) { t.Parallel() testlapack.DlansyTest(t, impl) } func TestDlantb(t *testing.T) { t.Parallel() testlapack.DlantbTest(t, impl) } func TestDlantr(t *testing.T) { t.Parallel() testlapack.DlantrTest(t, impl) } func TestDlanv2(t *testing.T) { t.Parallel() testlapack.Dlanv2Test(t, impl) } func TestDlaqr04(t *testing.T) { t.Parallel() testlapack.Dlaqr04Test(t, impl) } func TestDlaqp2(t *testing.T) { t.Parallel() testlapack.Dlaqp2Test(t, impl) } func TestDlaqps(t *testing.T) { t.Parallel() testlapack.DlaqpsTest(t, impl) } func TestDlaqr1(t *testing.T) { t.Parallel() testlapack.Dlaqr1Test(t, impl) } func TestDlaqr23(t *testing.T) { t.Parallel() testlapack.Dlaqr23Test(t, impl) } func TestDlaqr5(t *testing.T) { t.Parallel() testlapack.Dlaqr5Test(t, impl) } func TestDlarf(t *testing.T) { t.Parallel() testlapack.DlarfTest(t, impl) } func TestDlarfb(t *testing.T) { t.Parallel() testlapack.DlarfbTest(t, impl) } func TestDlarfg(t *testing.T) { t.Parallel() testlapack.DlarfgTest(t, impl) } func TestDlarft(t *testing.T) { t.Parallel() testlapack.DlarftTest(t, impl) } func TestDlarfx(t *testing.T) { t.Parallel() testlapack.DlarfxTest(t, impl) } func TestDlartg(t *testing.T) { t.Parallel() testlapack.DlartgTest(t, impl) } func TestDlasq1(t *testing.T) { t.Parallel() testlapack.Dlasq1Test(t, impl) } func TestDlasq2(t *testing.T) { t.Parallel() testlapack.Dlasq2Test(t, impl) } func TestDlasr(t *testing.T) { t.Parallel() testlapack.DlasrTest(t, impl) } func TestDlasv2(t *testing.T) { t.Parallel() testlapack.Dlasv2Test(t, impl) } func TestDlatbs(t *testing.T) { t.Parallel() testlapack.DlatbsTest(t, impl) } func TestDlatrd(t *testing.T) { t.Parallel() testlapack.DlatrdTest(t, impl) } func TestDlatrs(t *testing.T) { t.Parallel() testlapack.DlatrsTest(t, impl) } func TestDlauu2(t *testing.T) { t.Parallel() testlapack.Dlauu2Test(t, impl) } func TestDlauum(t *testing.T) { t.Parallel() testlapack.DlauumTest(t, impl) } func TestDorg2r(t *testing.T) { t.Parallel() testlapack.Dorg2rTest(t, impl) } func TestDorgbr(t *testing.T) { t.Parallel() testlapack.DorgbrTest(t, impl) } func TestDorghr(t *testing.T) { t.Parallel() testlapack.DorghrTest(t, impl) } func TestDorg2l(t *testing.T) { t.Parallel() testlapack.Dorg2lTest(t, impl) } func TestDorgl2(t *testing.T) { t.Parallel() testlapack.Dorgl2Test(t, impl) } func TestDorglq(t *testing.T) { t.Parallel() testlapack.DorglqTest(t, impl) } func TestDorgql(t *testing.T) { t.Parallel() testlapack.DorgqlTest(t, impl) } func TestDorgqr(t *testing.T) { t.Parallel() testlapack.DorgqrTest(t, impl) } func TestDorgr2(t *testing.T) { t.Parallel() testlapack.Dorgr2Test(t, impl) } func TestDorgtr(t *testing.T) { t.Parallel() testlapack.DorgtrTest(t, impl) } func TestDormbr(t *testing.T) { t.Parallel() testlapack.DormbrTest(t, impl) } func TestDormhr(t *testing.T) { t.Parallel() testlapack.DormhrTest(t, impl) } func TestDorml2(t *testing.T) { t.Parallel() testlapack.Dorml2Test(t, impl) } func TestDormlq(t *testing.T) { t.Parallel() testlapack.DormlqTest(t, impl) } func TestDormqr(t *testing.T) { t.Parallel() testlapack.DormqrTest(t, impl) } func TestDormr2(t *testing.T) { t.Parallel() testlapack.Dormr2Test(t, impl) } func TestDorm2r(t *testing.T) { t.Parallel() testlapack.Dorm2rTest(t, impl) } func TestDpbcon(t *testing.T) { t.Parallel() testlapack.DpbconTest(t, impl) } func TestDpbtf2(t *testing.T) { t.Parallel() testlapack.Dpbtf2Test(t, impl) } func TestDpbtrf(t *testing.T) { t.Parallel() testlapack.DpbtrfTest(t, impl) } func TestDpbtrs(t *testing.T) { t.Parallel() testlapack.DpbtrsTest(t, impl) } func TestDpocon(t *testing.T) { t.Parallel() testlapack.DpoconTest(t, impl) } func TestDpotf2(t *testing.T) { t.Parallel() testlapack.Dpotf2Test(t, impl) } func TestDpotrf(t *testing.T) { t.Parallel() testlapack.DpotrfTest(t, impl) } func TestDpotri(t *testing.T) { t.Parallel() testlapack.DpotriTest(t, impl) } func TestDpotrs(t *testing.T) { t.Parallel() testlapack.DpotrsTest(t, impl) } func TestDpstf2(t *testing.T) { t.Parallel() testlapack.Dpstf2Test(t, impl) } func TestDpstrf(t *testing.T) { t.Parallel() testlapack.DpstrfTest(t, impl) } func TestDrscl(t *testing.T) { t.Parallel() testlapack.DrsclTest(t, impl) } func TestDsteqr(t *testing.T) { t.Parallel() testlapack.DsteqrTest(t, impl) } func TestDsterf(t *testing.T) { t.Parallel() testlapack.DsterfTest(t, impl) } func TestDsyev(t *testing.T) { t.Parallel() testlapack.DsyevTest(t, impl) } func TestDsytd2(t *testing.T) { t.Parallel() testlapack.Dsytd2Test(t, impl) } func TestDsytrd(t *testing.T) { t.Parallel() testlapack.DsytrdTest(t, impl) } func TestDtgsja(t *testing.T) { t.Parallel() testlapack.DtgsjaTest(t, impl) } func TestDtbtrs(t *testing.T) { t.Parallel() testlapack.DtbtrsTest(t, impl) } func TestDtrcon(t *testing.T) { t.Parallel() testlapack.DtrconTest(t, impl) } func TestDtrevc3(t *testing.T) { t.Parallel() testlapack.Dtrevc3Test(t, impl) } func TestDtrexc(t *testing.T) { t.Parallel() testlapack.DtrexcTest(t, impl) } func TestDtrti2(t *testing.T) { t.Parallel() testlapack.Dtrti2Test(t, impl) } func TestDtrtri(t *testing.T) { t.Parallel() testlapack.DtrtriTest(t, impl) } func TestDtrtrs(t *testing.T) { t.Parallel() testlapack.DtrtrsTest(t, impl) } func TestIladlc(t *testing.T) { t.Parallel() testlapack.IladlcTest(t, impl) } func TestIladlr(t *testing.T) { t.Parallel() testlapack.IladlrTest(t, impl) } golang-gonum-v1-gonum-0.14.0/lapack/lapack.go000066400000000000000000000217221450372207100206570ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package lapack import "gonum.org/v1/gonum/blas" // Complex128 defines the public complex128 LAPACK API supported by gonum/lapack. type Complex128 interface{} // Float64 defines the public float64 LAPACK API supported by gonum/lapack. type Float64 interface { Dgecon(norm MatrixNorm, n int, a []float64, lda int, anorm float64, work []float64, iwork []int) float64 Dgeev(jobvl LeftEVJob, jobvr RightEVJob, n int, a []float64, lda int, wr, wi []float64, vl []float64, ldvl int, vr []float64, ldvr int, work []float64, lwork int) (first int) Dgels(trans blas.Transpose, m, n, nrhs int, a []float64, lda int, b []float64, ldb int, work []float64, lwork int) bool Dgelqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) Dgeqrf(m, n int, a []float64, lda int, tau, work []float64, lwork int) Dgesvd(jobU, jobVT SVDJob, m, n int, a []float64, lda int, s, u []float64, ldu int, vt []float64, ldvt int, work []float64, lwork int) (ok bool) Dgetrf(m, n int, a []float64, lda int, ipiv []int) (ok bool) Dgetri(n int, a []float64, lda int, ipiv []int, work []float64, lwork int) (ok bool) Dgetrs(trans blas.Transpose, n, nrhs int, a []float64, lda int, ipiv []int, b []float64, ldb int) Dggsvd3(jobU, jobV, jobQ GSVDJob, m, n, p int, a []float64, lda int, b []float64, ldb int, alpha, beta, u []float64, ldu int, v []float64, ldv int, q []float64, ldq int, work []float64, lwork int, iwork []int) (k, l int, ok bool) Dlantr(norm MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 Dlange(norm MatrixNorm, m, n int, a []float64, lda int, work []float64) float64 Dlansy(norm MatrixNorm, uplo blas.Uplo, n int, a []float64, lda int, work []float64) float64 Dlapmr(forward bool, m, n int, x []float64, ldx int, k []int) Dlapmt(forward bool, m, n int, x []float64, ldx int, k []int) Dormqr(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) Dormlq(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) Dpbcon(uplo blas.Uplo, n, kd int, ab []float64, ldab int, anorm float64, work []float64, iwork []int) float64 Dpbtrf(uplo blas.Uplo, n, kd int, ab []float64, ldab int) (ok bool) Dpbtrs(uplo blas.Uplo, n, kd, nrhs int, ab []float64, ldab int, b []float64, ldb int) Dpocon(uplo blas.Uplo, n int, a []float64, lda int, anorm float64, work []float64, iwork []int) float64 Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool) Dpotri(ul blas.Uplo, n int, a []float64, lda int) (ok bool) Dpotrs(ul blas.Uplo, n, nrhs int, a []float64, lda int, b []float64, ldb int) Dpstrf(uplo blas.Uplo, n int, a []float64, lda int, piv []int, tol float64, work []float64) (rank int, ok bool) Dsyev(jobz EVJob, uplo blas.Uplo, n int, a []float64, lda int, w, work []float64, lwork int) (ok bool) Dtbtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, kd, nrhs int, a []float64, lda int, b []float64, ldb int) (ok bool) Dtrcon(norm MatrixNorm, uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int, work []float64, iwork []int) float64 Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) (ok bool) Dtrtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, nrhs int, a []float64, lda int, b []float64, ldb int) (ok bool) } // Direct specifies the direction of the multiplication for the Householder matrix. type Direct byte const ( Forward Direct = 'F' // Reflectors are right-multiplied, H_0 * H_1 * ... * H_{k-1}. Backward Direct = 'B' // Reflectors are left-multiplied, H_{k-1} * ... * H_1 * H_0. ) // Sort is the sorting order. type Sort byte const ( SortIncreasing Sort = 'I' SortDecreasing Sort = 'D' ) // StoreV indicates the storage direction of elementary reflectors. type StoreV byte const ( ColumnWise StoreV = 'C' // Reflector stored in a column of the matrix. RowWise StoreV = 'R' // Reflector stored in a row of the matrix. ) // MatrixNorm represents the kind of matrix norm to compute. type MatrixNorm byte const ( MaxAbs MatrixNorm = 'M' // max(abs(A(i,j))) MaxColumnSum MatrixNorm = 'O' // Maximum absolute column sum (one norm) MaxRowSum MatrixNorm = 'I' // Maximum absolute row sum (infinity norm) Frobenius MatrixNorm = 'F' // Frobenius norm (sqrt of sum of squares) ) // MatrixType represents the kind of matrix represented in the data. type MatrixType byte const ( General MatrixType = 'G' // A general dense matrix. UpperTri MatrixType = 'U' // An upper triangular matrix. LowerTri MatrixType = 'L' // A lower triangular matrix. ) // Pivot specifies the pivot type for plane rotations. type Pivot byte const ( Variable Pivot = 'V' Top Pivot = 'T' Bottom Pivot = 'B' ) // ApplyOrtho specifies which orthogonal matrix is applied in Dormbr. type ApplyOrtho byte const ( ApplyP ApplyOrtho = 'P' // Apply P or Pᵀ. ApplyQ ApplyOrtho = 'Q' // Apply Q or Qᵀ. ) // GenOrtho specifies which orthogonal matrix is generated in Dorgbr. type GenOrtho byte const ( GeneratePT GenOrtho = 'P' // Generate Pᵀ. GenerateQ GenOrtho = 'Q' // Generate Q. ) // SVDJob specifies the singular vector computation type for SVD. type SVDJob byte const ( SVDAll SVDJob = 'A' // Compute all columns of the orthogonal matrix U or V. SVDStore SVDJob = 'S' // Compute the singular vectors and store them in the orthogonal matrix U or V. SVDOverwrite SVDJob = 'O' // Compute the singular vectors and overwrite them on the input matrix A. SVDNone SVDJob = 'N' // Do not compute singular vectors. ) // GSVDJob specifies the singular vector computation type for Generalized SVD. type GSVDJob byte const ( GSVDU GSVDJob = 'U' // Compute orthogonal matrix U. GSVDV GSVDJob = 'V' // Compute orthogonal matrix V. GSVDQ GSVDJob = 'Q' // Compute orthogonal matrix Q. GSVDUnit GSVDJob = 'I' // Use unit-initialized matrix. GSVDNone GSVDJob = 'N' // Do not compute orthogonal matrix. ) // EVComp specifies how eigenvectors are computed in Dsteqr. type EVComp byte const ( EVOrig EVComp = 'V' // Compute eigenvectors of the original symmetric matrix. EVTridiag EVComp = 'I' // Compute eigenvectors of the tridiagonal matrix. EVCompNone EVComp = 'N' // Do not compute eigenvectors. ) // EVJob specifies whether eigenvectors are computed in Dsyev. type EVJob byte const ( EVCompute EVJob = 'V' // Compute eigenvectors. EVNone EVJob = 'N' // Do not compute eigenvectors. ) // LeftEVJob specifies whether left eigenvectors are computed in Dgeev. type LeftEVJob byte const ( LeftEVCompute LeftEVJob = 'V' // Compute left eigenvectors. LeftEVNone LeftEVJob = 'N' // Do not compute left eigenvectors. ) // RightEVJob specifies whether right eigenvectors are computed in Dgeev. type RightEVJob byte const ( RightEVCompute RightEVJob = 'V' // Compute right eigenvectors. RightEVNone RightEVJob = 'N' // Do not compute right eigenvectors. ) // BalanceJob specifies matrix balancing operation. type BalanceJob byte const ( Permute BalanceJob = 'P' Scale BalanceJob = 'S' PermuteScale BalanceJob = 'B' BalanceNone BalanceJob = 'N' ) // SchurJob specifies whether the Schur form is computed in Dhseqr. type SchurJob byte const ( EigenvaluesOnly SchurJob = 'E' EigenvaluesAndSchur SchurJob = 'S' ) // SchurComp specifies whether and how the Schur vectors are computed in Dhseqr. type SchurComp byte const ( SchurOrig SchurComp = 'V' // Compute Schur vectors of the original matrix. SchurHess SchurComp = 'I' // Compute Schur vectors of the upper Hessenberg matrix. SchurNone SchurComp = 'N' // Do not compute Schur vectors. ) // UpdateSchurComp specifies whether the matrix of Schur vectors is updated in Dtrexc. type UpdateSchurComp byte const ( UpdateSchur UpdateSchurComp = 'V' // Update the matrix of Schur vectors. UpdateSchurNone UpdateSchurComp = 'N' // Do not update the matrix of Schur vectors. ) // EVSide specifies what eigenvectors are computed in Dtrevc3. type EVSide byte const ( EVRight EVSide = 'R' // Compute only right eigenvectors. EVLeft EVSide = 'L' // Compute only left eigenvectors. EVBoth EVSide = 'B' // Compute both right and left eigenvectors. ) // EVHowMany specifies which eigenvectors are computed in Dtrevc3 and how. type EVHowMany byte const ( EVAll EVHowMany = 'A' // Compute all right and/or left eigenvectors. EVAllMulQ EVHowMany = 'B' // Compute all right and/or left eigenvectors multiplied by an input matrix. EVSelected EVHowMany = 'S' // Compute selected right and/or left eigenvectors. ) // MaximizeNormX specifies the heuristic method for computing a contribution to // the reciprocal Dif-estimate in Dlatdf. type MaximizeNormXJob byte const ( LocalLookAhead MaximizeNormXJob = 0 // Solve Z*x=h-f where h is a vector of ±1. NormalizedNullVector MaximizeNormXJob = 2 // Compute an approximate null-vector e of Z, normalize e and solve Z*x=±e-f. ) golang-gonum-v1-gonum-0.14.0/lapack/lapack64/000077500000000000000000000000001450372207100204765ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/lapack/lapack64/doc.go000066400000000000000000000021021450372207100215650ustar00rootroot00000000000000// 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 lapack64 provides a set of convenient wrapper functions for LAPACK // calls, as specified in the netlib standard (www.netlib.org). // // The native Go routines are used by default, and the Use function can be used // to set an alternative implementation. // // If the type of matrix (General, Symmetric, etc.) is known and fixed, it is // used in the wrapper signature. In many cases, however, the type of the matrix // changes during the call to the routine, for example the matrix is symmetric on // entry and is triangular on exit. In these cases the correct types should be checked // in the documentation. // // The full set of Lapack functions is very large, and it is not clear that a // full implementation is desirable, let alone feasible. Please open up an issue // if there is a specific function you need and/or are willing to implement. package lapack64 // import "gonum.org/v1/gonum/lapack/lapack64" golang-gonum-v1-gonum-0.14.0/lapack/lapack64/lapack64.go000066400000000000000000001045451450372207100224430ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package lapack64 import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/gonum" ) var lapack64 lapack.Float64 = gonum.Implementation{} // Use sets the LAPACK float64 implementation to be used by subsequent BLAS calls. // The default implementation is native.Implementation. func Use(l lapack.Float64) { lapack64 = l } // Tridiagonal represents a tridiagonal matrix using its three diagonals. type Tridiagonal struct { N int DL []float64 D []float64 DU []float64 } func max(a, b int) int { if a > b { return a } return b } // Potrf computes the Cholesky factorization of a. // The factorization has the form // // A = Uᵀ * U if a.Uplo == blas.Upper, or // A = L * Lᵀ if a.Uplo == blas.Lower, // // where U is an upper triangular matrix and L is lower triangular. // The triangular matrix is returned in t, and the underlying data between // a and t is shared. The returned bool indicates whether a is positive // definite and the factorization could be finished. func Potrf(a blas64.Symmetric) (t blas64.Triangular, ok bool) { ok = lapack64.Dpotrf(a.Uplo, a.N, a.Data, max(1, a.Stride)) t.Uplo = a.Uplo t.N = a.N t.Data = a.Data t.Stride = a.Stride t.Diag = blas.NonUnit return } // Potri computes the inverse of a real symmetric positive definite matrix A // using its Cholesky factorization. // // On entry, t contains the triangular factor U or L from the Cholesky // factorization A = Uᵀ*U or A = L*Lᵀ, as computed by Potrf. // // On return, the upper or lower triangle of the (symmetric) inverse of A is // stored in t, overwriting the input factor U or L, and also returned in a. The // underlying data between a and t is shared. // // The returned bool indicates whether the inverse was computed successfully. func Potri(t blas64.Triangular) (a blas64.Symmetric, ok bool) { ok = lapack64.Dpotri(t.Uplo, t.N, t.Data, max(1, t.Stride)) a.Uplo = t.Uplo a.N = t.N a.Data = t.Data a.Stride = t.Stride return } // Potrs solves a system of n linear equations A*X = B where A is an n×n // symmetric positive definite matrix and B is an n×nrhs matrix, using the // Cholesky factorization A = Uᵀ*U or A = L*Lᵀ. t contains the corresponding // triangular factor as returned by Potrf. On entry, B contains the right-hand // side matrix B, on return it contains the solution matrix X. func Potrs(t blas64.Triangular, b blas64.General) { lapack64.Dpotrs(t.Uplo, t.N, b.Cols, t.Data, max(1, t.Stride), b.Data, max(1, b.Stride)) } // Pbcon returns an estimate of the reciprocal of the condition number (in the // 1-norm) of an n×n symmetric positive definite band matrix using the Cholesky // factorization // // A = Uᵀ*U if uplo == blas.Upper // A = L*Lᵀ if uplo == blas.Lower // // computed by Pbtrf. The estimate is obtained for norm(inv(A)), and the // reciprocal of the condition number is computed as // // rcond = 1 / (anorm * norm(inv(A))). // // The length of work must be at least 3*n and the length of iwork must be at // least n. func Pbcon(a blas64.SymmetricBand, anorm float64, work []float64, iwork []int) float64 { return lapack64.Dpbcon(a.Uplo, a.N, a.K, a.Data, a.Stride, anorm, work, iwork) } // Pbtrf computes the Cholesky factorization of an n×n symmetric positive // definite band matrix // // A = Uᵀ * U if a.Uplo == blas.Upper // A = L * Lᵀ if a.Uplo == blas.Lower // // where U and L are upper, respectively lower, triangular band matrices. // // The triangular matrix U or L is returned in t, and the underlying data // between a and t is shared. The returned bool indicates whether A is positive // definite and the factorization could be finished. func Pbtrf(a blas64.SymmetricBand) (t blas64.TriangularBand, ok bool) { ok = lapack64.Dpbtrf(a.Uplo, a.N, a.K, a.Data, max(1, a.Stride)) t.Uplo = a.Uplo t.Diag = blas.NonUnit t.N = a.N t.K = a.K t.Data = a.Data t.Stride = a.Stride return t, ok } // Pbtrs solves a system of linear equations A*X = B with an n×n symmetric // positive definite band matrix A using the Cholesky factorization // // A = Uᵀ * U if t.Uplo == blas.Upper // A = L * Lᵀ if t.Uplo == blas.Lower // // t contains the corresponding triangular factor as returned by Pbtrf. // // On entry, b contains the right hand side matrix B. On return, it is // overwritten with the solution matrix X. func Pbtrs(t blas64.TriangularBand, b blas64.General) { lapack64.Dpbtrs(t.Uplo, t.N, t.K, b.Cols, t.Data, max(1, t.Stride), b.Data, max(1, b.Stride)) } // Pstrf computes the Cholesky factorization with complete pivoting of an n×n // symmetric positive semidefinite matrix A. // // The factorization has the form // // Pᵀ * A * P = Uᵀ * U , if a.Uplo = blas.Upper, // Pᵀ * A * P = L * Lᵀ, if a.Uplo = blas.Lower, // // where U is an upper triangular matrix, L is lower triangular, and P is a // permutation matrix. // // tol is a user-defined tolerance. The algorithm terminates if the pivot is // less than or equal to tol. If tol is negative, then n*eps*max(A[k,k]) will be // used instead. // // The triangular factor U or L from the Cholesky factorization is returned in t // and the underlying data between a and t is shared. P is stored on return in // vector piv such that P[piv[k],k] = 1. // // Pstrf returns the computed rank of A and whether the factorization can be // used to solve a system. Pstrf does not attempt to check that A is positive // semi-definite, so if ok is false, the matrix A is either rank deficient or is // not positive semidefinite. // // The length of piv must be n and the length of work must be at least 2*n, // otherwise Pstrf will panic. func Pstrf(a blas64.Symmetric, piv []int, tol float64, work []float64) (t blas64.Triangular, rank int, ok bool) { rank, ok = lapack64.Dpstrf(a.Uplo, a.N, a.Data, max(1, a.Stride), piv, tol, work) t.Uplo = a.Uplo t.Diag = blas.NonUnit t.N = a.N t.Data = a.Data t.Stride = a.Stride return t, rank, ok } // Gecon estimates the reciprocal of the condition number of the n×n matrix A // given the LU decomposition of the matrix. The condition number computed may // be based on the 1-norm or the ∞-norm. // // a contains the result of the LU decomposition of A as computed by Getrf. // // anorm is the corresponding 1-norm or ∞-norm of the original matrix A. // // work is a temporary data slice of length at least 4*n and Gecon will panic otherwise. // // iwork is a temporary data slice of length at least n and Gecon will panic otherwise. func Gecon(norm lapack.MatrixNorm, a blas64.General, anorm float64, work []float64, iwork []int) float64 { return lapack64.Dgecon(norm, a.Cols, a.Data, max(1, a.Stride), anorm, work, iwork) } // Gels finds a minimum-norm solution based on the matrices A and B using the // QR or LQ factorization. Gels returns false if the matrix // A is singular, and true if this solution was successfully found. // // The minimization problem solved depends on the input parameters. // // 1. If m >= n and trans == blas.NoTrans, Gels finds X such that || A*X - B||_2 // is minimized. // 2. If m < n and trans == blas.NoTrans, Gels finds the minimum norm solution of // A * X = B. // 3. If m >= n and trans == blas.Trans, Gels finds the minimum norm solution of // Aᵀ * X = B. // 4. If m < n and trans == blas.Trans, Gels finds X such that || A*X - B||_2 // is minimized. // // Note that the least-squares solutions (cases 1 and 3) perform the minimization // per column of B. This is not the same as finding the minimum-norm matrix. // // The matrix A is a general matrix of size m×n and is modified during this call. // The input matrix B is of size max(m,n)×nrhs, and serves two purposes. On entry, // the elements of b specify the input matrix B. B has size m×nrhs if // trans == blas.NoTrans, and n×nrhs if trans == blas.Trans. On exit, the // leading submatrix of b contains the solution vectors X. If trans == blas.NoTrans, // this submatrix is of size n×nrhs, and of size m×nrhs otherwise. // // Work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= max(m,n) + max(m,n,nrhs), and this function will panic // otherwise. A longer work will enable blocked algorithms to be called. // In the special case that lwork == -1, work[0] will be set to the optimal working // length. func Gels(trans blas.Transpose, a blas64.General, b blas64.General, work []float64, lwork int) bool { return lapack64.Dgels(trans, a.Rows, a.Cols, b.Cols, a.Data, max(1, a.Stride), b.Data, max(1, b.Stride), work, lwork) } // Geqrf computes the QR factorization of the m×n matrix A using a blocked // algorithm. A is modified to contain the information to construct Q and R. // The upper triangle of a contains the matrix R. The lower triangular elements // (not including the diagonal) contain the elementary reflectors. tau is modified // to contain the reflector scales. tau must have length at least min(m,n), and // this function will panic otherwise. // // The ith elementary reflector can be explicitly constructed by first extracting // the // // v[j] = 0 j < i // v[j] = 1 j == i // v[j] = a[j*lda+i] j > i // // and computing H_i = I - tau[i] * v * vᵀ. // // The orthonormal matrix Q can be constructed from a product of these elementary // reflectors, Q = H_0 * H_1 * ... * H_{k-1}, where k = min(m,n). // // Work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= m and this function will panic otherwise. // Geqrf is a blocked QR factorization, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Geqrf, // the optimal work length will be stored into work[0]. func Geqrf(a blas64.General, tau, work []float64, lwork int) { lapack64.Dgeqrf(a.Rows, a.Cols, a.Data, max(1, a.Stride), tau, work, lwork) } // Gelqf computes the LQ factorization of the m×n matrix A using a blocked // algorithm. A is modified to contain the information to construct L and Q. The // lower triangle of a contains the matrix L. The elements above the diagonal // and the slice tau represent the matrix Q. tau is modified to contain the // reflector scales. tau must have length at least min(m,n), and this function // will panic otherwise. // // See Geqrf for a description of the elementary reflectors and orthonormal // matrix Q. Q is constructed as a product of these elementary reflectors, // Q = H_{k-1} * ... * H_1 * H_0. // // Work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= m and this function will panic otherwise. // Gelqf is a blocked LQ factorization, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Gelqf, // the optimal work length will be stored into work[0]. func Gelqf(a blas64.General, tau, work []float64, lwork int) { lapack64.Dgelqf(a.Rows, a.Cols, a.Data, max(1, a.Stride), tau, work, lwork) } // Gesvd computes the singular value decomposition of the input matrix A. // // The singular value decomposition is // // A = U * Sigma * Vᵀ // // where Sigma is an m×n diagonal matrix containing the singular values of A, // U is an m×m orthogonal matrix and V is an n×n orthogonal matrix. The first // min(m,n) columns of U and V are the left and right singular vectors of A // respectively. // // jobU and jobVT are options for computing the singular vectors. The behavior // is as follows // // jobU == lapack.SVDAll All m columns of U are returned in u // jobU == lapack.SVDStore The first min(m,n) columns are returned in u // jobU == lapack.SVDOverwrite The first min(m,n) columns of U are written into a // jobU == lapack.SVDNone The columns of U are not computed. // // The behavior is the same for jobVT and the rows of Vᵀ. At most one of jobU // and jobVT can equal lapack.SVDOverwrite, and Gesvd will panic otherwise. // // On entry, a contains the data for the m×n matrix A. During the call to Gesvd // the data is overwritten. On exit, A contains the appropriate singular vectors // if either job is lapack.SVDOverwrite. // // s is a slice of length at least min(m,n) and on exit contains the singular // values in decreasing order. // // u contains the left singular vectors on exit, stored columnwise. If // jobU == lapack.SVDAll, u is of size m×m. If jobU == lapack.SVDStore u is // of size m×min(m,n). If jobU == lapack.SVDOverwrite or lapack.SVDNone, u is // not used. // // vt contains the left singular vectors on exit, stored rowwise. If // jobV == lapack.SVDAll, vt is of size n×m. If jobVT == lapack.SVDStore vt is // of size min(m,n)×n. If jobVT == lapack.SVDOverwrite or lapack.SVDNone, vt is // not used. // // work is a slice for storing temporary memory, and lwork is the usable size of // the slice. lwork must be at least max(5*min(m,n), 3*min(m,n)+max(m,n)). // If lwork == -1, instead of performing Gesvd, the optimal work length will be // stored into work[0]. Gesvd will panic if the working memory has insufficient // storage. // // Gesvd returns whether the decomposition successfully completed. func Gesvd(jobU, jobVT lapack.SVDJob, a, u, vt blas64.General, s, work []float64, lwork int) (ok bool) { return lapack64.Dgesvd(jobU, jobVT, a.Rows, a.Cols, a.Data, max(1, a.Stride), s, u.Data, max(1, u.Stride), vt.Data, max(1, vt.Stride), work, lwork) } // Getrf computes the LU decomposition of the m×n matrix A. // The LU decomposition is a factorization of A into // // A = P * L * U // // where P is a permutation matrix, L is a unit lower triangular matrix, and // U is a (usually) non-unit upper triangular matrix. On exit, L and U are stored // in place into a. // // ipiv is a permutation vector. It indicates that row i of the matrix was // changed with ipiv[i]. ipiv must have length at least min(m,n), and will panic // otherwise. ipiv is zero-indexed. // // Getrf is the blocked version of the algorithm. // // Getrf returns whether the matrix A is singular. The LU decomposition will // be computed regardless of the singularity of A, but division by zero // will occur if the false is returned and the result is used to solve a // system of equations. func Getrf(a blas64.General, ipiv []int) bool { return lapack64.Dgetrf(a.Rows, a.Cols, a.Data, max(1, a.Stride), ipiv) } // Getri computes the inverse of the matrix A using the LU factorization computed // by Getrf. On entry, a contains the PLU decomposition of A as computed by // Getrf and on exit contains the reciprocal of the original matrix. // // Getri will not perform the inversion if the matrix is singular, and returns // a boolean indicating whether the inversion was successful. // // Work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= n and this function will panic otherwise. // Getri is a blocked inversion, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Getri, // the optimal work length will be stored into work[0]. func Getri(a blas64.General, ipiv []int, work []float64, lwork int) (ok bool) { return lapack64.Dgetri(a.Cols, a.Data, max(1, a.Stride), ipiv, work, lwork) } // Getrs solves a system of equations using an LU factorization. // The system of equations solved is // // A * X = B if trans == blas.Trans // Aᵀ * X = B if trans == blas.NoTrans // // A is a general n×n matrix with stride lda. B is a general matrix of size n×nrhs. // // On entry b contains the elements of the matrix B. On exit, b contains the // elements of X, the solution to the system of equations. // // a and ipiv contain the LU factorization of A and the permutation indices as // computed by Getrf. ipiv is zero-indexed. func Getrs(trans blas.Transpose, a blas64.General, b blas64.General, ipiv []int) { lapack64.Dgetrs(trans, a.Cols, b.Cols, a.Data, max(1, a.Stride), ipiv, b.Data, max(1, b.Stride)) } // Ggsvd3 computes the generalized singular value decomposition (GSVD) // of an m×n matrix A and p×n matrix B: // // Uᵀ*A*Q = D1*[ 0 R ] // // Vᵀ*B*Q = D2*[ 0 R ] // // where U, V and Q are orthogonal matrices. // // Ggsvd3 returns k and l, the dimensions of the sub-blocks. k+l // is the effective numerical rank of the (m+p)×n matrix [ Aᵀ Bᵀ ]ᵀ. // R is a (k+l)×(k+l) nonsingular upper triangular matrix, D1 and // D2 are m×(k+l) and p×(k+l) diagonal matrices and of the following // structures, respectively: // // If m-k-l >= 0, // // k l // D1 = k [ I 0 ] // l [ 0 C ] // m-k-l [ 0 0 ] // // k l // D2 = l [ 0 S ] // p-l [ 0 0 ] // // n-k-l k l // [ 0 R ] = k [ 0 R11 R12 ] k // l [ 0 0 R22 ] l // // where // // C = diag( alpha_k, ... , alpha_{k+l} ), // S = diag( beta_k, ... , beta_{k+l} ), // C^2 + S^2 = I. // // R is stored in // // A[0:k+l, n-k-l:n] // // on exit. // // If m-k-l < 0, // // k m-k k+l-m // D1 = k [ I 0 0 ] // m-k [ 0 C 0 ] // // k m-k k+l-m // D2 = m-k [ 0 S 0 ] // k+l-m [ 0 0 I ] // p-l [ 0 0 0 ] // // n-k-l k m-k k+l-m // [ 0 R ] = k [ 0 R11 R12 R13 ] // m-k [ 0 0 R22 R23 ] // k+l-m [ 0 0 0 R33 ] // // where // // C = diag( alpha_k, ... , alpha_m ), // S = diag( beta_k, ... , beta_m ), // C^2 + S^2 = I. // // R = [ R11 R12 R13 ] is stored in A[1:m, n-k-l+1:n] // [ 0 R22 R23 ] // // and R33 is stored in // // B[m-k:l, n+m-k-l:n] on exit. // // Ggsvd3 computes C, S, R, and optionally the orthogonal transformation // matrices U, V and Q. // // jobU, jobV and jobQ are options for computing the orthogonal matrices. The behavior // is as follows // // jobU == lapack.GSVDU Compute orthogonal matrix U // jobU == lapack.GSVDNone Do not compute orthogonal matrix. // // The behavior is the same for jobV and jobQ with the exception that instead of // lapack.GSVDU these accept lapack.GSVDV and lapack.GSVDQ respectively. // The matrices U, V and Q must be m×m, p×p and n×n respectively unless the // relevant job parameter is lapack.GSVDNone. // // alpha and beta must have length n or Ggsvd3 will panic. On exit, alpha and // beta contain the generalized singular value pairs of A and B // // alpha[0:k] = 1, // beta[0:k] = 0, // // if m-k-l >= 0, // // alpha[k:k+l] = diag(C), // beta[k:k+l] = diag(S), // // if m-k-l < 0, // // alpha[k:m]= C, alpha[m:k+l]= 0 // beta[k:m] = S, beta[m:k+l] = 1. // // if k+l < n, // // alpha[k+l:n] = 0 and // beta[k+l:n] = 0. // // On exit, iwork contains the permutation required to sort alpha descending. // // iwork must have length n, work must have length at least max(1, lwork), and // lwork must be -1 or greater than n, otherwise Ggsvd3 will panic. If // lwork is -1, work[0] holds the optimal lwork on return, but Ggsvd3 does // not perform the GSVD. func Ggsvd3(jobU, jobV, jobQ lapack.GSVDJob, a, b blas64.General, alpha, beta []float64, u, v, q blas64.General, work []float64, lwork int, iwork []int) (k, l int, ok bool) { return lapack64.Dggsvd3(jobU, jobV, jobQ, a.Rows, a.Cols, b.Rows, a.Data, max(1, a.Stride), b.Data, max(1, b.Stride), alpha, beta, u.Data, max(1, u.Stride), v.Data, max(1, v.Stride), q.Data, max(1, q.Stride), work, lwork, iwork) } // Gtsv solves one of the equations // // A * X = B if trans == blas.NoTrans // Aᵀ * X = B if trans == blas.Trans or blas.ConjTrans // // where A is an n×n tridiagonal matrix. It uses Gaussian elimination with // partial pivoting. // // On entry, a contains the matrix A, on return it will be overwritten. // // On entry, b contains the n×nrhs right-hand side matrix B. On return, it will // be overwritten. If ok is true, it will be overwritten by the solution matrix X. // // Gtsv returns whether the solution X has been successfully computed. // // Dgtsv is not part of the lapack.Float64 interface and so calls to Gtsv are // always executed by the Gonum implementation. func Gtsv(trans blas.Transpose, a Tridiagonal, b blas64.General) (ok bool) { if trans != blas.NoTrans { a.DL, a.DU = a.DU, a.DL } return gonum.Implementation{}.Dgtsv(a.N, b.Cols, a.DL, a.D, a.DU, b.Data, max(1, b.Stride)) } // Lagtm performs one of the matrix-matrix operations // // C = alpha * A * B + beta * C if trans == blas.NoTrans // C = alpha * Aᵀ * B + beta * C if trans == blas.Trans or blas.ConjTrans // // where A is an m×m tridiagonal matrix represented by its diagonals dl, d, du, // B and C are m×n dense matrices, and alpha and beta are scalars. // // Dlagtm is not part of the lapack.Float64 interface and so calls to Lagtm are // always executed by the Gonum implementation. func Lagtm(trans blas.Transpose, alpha float64, a Tridiagonal, b blas64.General, beta float64, c blas64.General) { gonum.Implementation{}.Dlagtm(trans, c.Rows, c.Cols, alpha, a.DL, a.D, a.DU, b.Data, max(1, b.Stride), beta, c.Data, max(1, c.Stride)) } // Lange computes the matrix norm of the general m×n matrix A. The input norm // specifies the norm computed. // // lapack.MaxAbs: the maximum absolute value of an element. // lapack.MaxColumnSum: the maximum column sum of the absolute values of the entries. // lapack.MaxRowSum: the maximum row sum of the absolute values of the entries. // lapack.Frobenius: the square root of the sum of the squares of the entries. // // If norm == lapack.MaxColumnSum, work must be of length n, and this function will panic otherwise. // There are no restrictions on work for the other matrix norms. func Lange(norm lapack.MatrixNorm, a blas64.General, work []float64) float64 { return lapack64.Dlange(norm, a.Rows, a.Cols, a.Data, max(1, a.Stride), work) } // Langb returns the given norm of a general m×n band matrix with kl sub-diagonals and // ku super-diagonals. // // Dlangb is not part of the lapack.Float64 interface and so calls to Langb are always // executed by the Gonum implementation. func Langb(norm lapack.MatrixNorm, a blas64.Band) float64 { return gonum.Implementation{}.Dlangb(norm, a.Rows, a.Cols, a.KL, a.KU, a.Data, max(1, a.Stride)) } // Langt computes the specified norm of an n×n tridiagonal matrix. // // Dlangt is not part of the lapack.Float64 interface and so calls to Langt are // always executed by the Gonum implementation. func Langt(norm lapack.MatrixNorm, a Tridiagonal) float64 { return gonum.Implementation{}.Dlangt(norm, a.N, a.DL, a.D, a.DU) } // Lansb computes the specified norm of an n×n symmetric band matrix. If // norm == lapack.MaxColumnSum or norm == lapack.MaxRowSum, work must have length // at least n and this function will panic otherwise. // There are no restrictions on work for the other matrix norms. // // Dlansb is not part of the lapack.Float64 interface and so calls to Lansb are always // executed by the Gonum implementation. func Lansb(norm lapack.MatrixNorm, a blas64.SymmetricBand, work []float64) float64 { return gonum.Implementation{}.Dlansb(norm, a.Uplo, a.N, a.K, a.Data, max(1, a.Stride), work) } // Lansy computes the specified norm of an n×n symmetric matrix. If // norm == lapack.MaxColumnSum or norm == lapack.MaxRowSum, work must have length // at least n and this function will panic otherwise. // There are no restrictions on work for the other matrix norms. func Lansy(norm lapack.MatrixNorm, a blas64.Symmetric, work []float64) float64 { return lapack64.Dlansy(norm, a.Uplo, a.N, a.Data, max(1, a.Stride), work) } // Lantr computes the specified norm of an m×n trapezoidal matrix A. If // norm == lapack.MaxColumnSum work must have length at least n and this function // will panic otherwise. There are no restrictions on work for the other matrix norms. func Lantr(norm lapack.MatrixNorm, a blas64.Triangular, work []float64) float64 { return lapack64.Dlantr(norm, a.Uplo, a.Diag, a.N, a.N, a.Data, max(1, a.Stride), work) } // Lantb computes the specified norm of an n×n triangular band matrix A. If // norm == lapack.MaxColumnSum work must have length at least n and this function // will panic otherwise. There are no restrictions on work for the other matrix // norms. func Lantb(norm lapack.MatrixNorm, a blas64.TriangularBand, work []float64) float64 { return gonum.Implementation{}.Dlantb(norm, a.Uplo, a.Diag, a.N, a.K, a.Data, max(1, a.Stride), work) } // Lapmr rearranges the rows of the m×n matrix X as specified by the permutation // k[0],k[1],...,k[m-1] of the integers 0,...,m-1. // // If forward is true, a forward permutation is applied: // // X[k[i],0:n] is moved to X[i,0:n] for i=0,1,...,m-1. // // If forward is false, a backward permutation is applied: // // X[i,0:n] is moved to X[k[i],0:n] for i=0,1,...,m-1. // // k must have length m, otherwise Lapmr will panic. func Lapmr(forward bool, x blas64.General, k []int) { lapack64.Dlapmr(forward, x.Rows, x.Cols, x.Data, max(1, x.Stride), k) } // Lapmt rearranges the columns of the m×n matrix X as specified by the // permutation k_0, k_1, ..., k_{n-1} of the integers 0, ..., n-1. // // If forward is true a forward permutation is performed: // // X[0:m, k[j]] is moved to X[0:m, j] for j = 0, 1, ..., n-1. // // otherwise a backward permutation is performed: // // X[0:m, j] is moved to X[0:m, k[j]] for j = 0, 1, ..., n-1. // // k must have length n, otherwise Lapmt will panic. k is zero-indexed. func Lapmt(forward bool, x blas64.General, k []int) { lapack64.Dlapmt(forward, x.Rows, x.Cols, x.Data, max(1, x.Stride), k) } // Ormlq multiplies the matrix C by the othogonal matrix Q defined by // A and tau. A and tau are as returned from Gelqf. // // C = Q * C if side == blas.Left and trans == blas.NoTrans // C = Qᵀ * C if side == blas.Left and trans == blas.Trans // C = C * Q if side == blas.Right and trans == blas.NoTrans // C = C * Qᵀ if side == blas.Right and trans == blas.Trans // // If side == blas.Left, A is a matrix of side k×m, and if side == blas.Right // A is of size k×n. This uses a blocked algorithm. // // Work is temporary storage, and lwork specifies the usable memory length. // At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right, // and this function will panic otherwise. // Ormlq uses a block algorithm, but the block size is limited // by the temporary space available. If lwork == -1, instead of performing Ormlq, // the optimal work length will be stored into work[0]. // // Tau contains the Householder scales and must have length at least k, and // this function will panic otherwise. func Ormlq(side blas.Side, trans blas.Transpose, a blas64.General, tau []float64, c blas64.General, work []float64, lwork int) { lapack64.Dormlq(side, trans, c.Rows, c.Cols, a.Rows, a.Data, max(1, a.Stride), tau, c.Data, max(1, c.Stride), work, lwork) } // Ormqr multiplies an m×n matrix C by an orthogonal matrix Q as // // C = Q * C if side == blas.Left and trans == blas.NoTrans, // C = Qᵀ * C if side == blas.Left and trans == blas.Trans, // C = C * Q if side == blas.Right and trans == blas.NoTrans, // C = C * Qᵀ if side == blas.Right and trans == blas.Trans, // // where Q is defined as the product of k elementary reflectors // // Q = H_0 * H_1 * ... * H_{k-1}. // // If side == blas.Left, A is an m×k matrix and 0 <= k <= m. // If side == blas.Right, A is an n×k matrix and 0 <= k <= n. // The ith column of A contains the vector which defines the elementary // reflector H_i and tau[i] contains its scalar factor. tau must have length k // and Ormqr will panic otherwise. Geqrf returns A and tau in the required // form. // // work must have length at least max(1,lwork), and lwork must be at least n if // side == blas.Left and at least m if side == blas.Right, otherwise Ormqr will // panic. // // work is temporary storage, and lwork specifies the usable memory length. At // minimum, lwork >= m if side == blas.Left and lwork >= n if side == // blas.Right, and this function will panic otherwise. Larger values of lwork // will generally give better performance. On return, work[0] will contain the // optimal value of lwork. // // If lwork is -1, instead of performing Ormqr, the optimal workspace size will // be stored into work[0]. func Ormqr(side blas.Side, trans blas.Transpose, a blas64.General, tau []float64, c blas64.General, work []float64, lwork int) { lapack64.Dormqr(side, trans, c.Rows, c.Cols, a.Cols, a.Data, max(1, a.Stride), tau, c.Data, max(1, c.Stride), work, lwork) } // Pocon estimates the reciprocal of the condition number of a positive-definite // matrix A given the Cholesky decomposition of A. The condition number computed // is based on the 1-norm and the ∞-norm. // // anorm is the 1-norm and the ∞-norm of the original matrix A. // // work is a temporary data slice of length at least 3*n and Pocon will panic otherwise. // // iwork is a temporary data slice of length at least n and Pocon will panic otherwise. func Pocon(a blas64.Symmetric, anorm float64, work []float64, iwork []int) float64 { return lapack64.Dpocon(a.Uplo, a.N, a.Data, max(1, a.Stride), anorm, work, iwork) } // Syev computes all eigenvalues and, optionally, the eigenvectors of a real // symmetric matrix A. // // w contains the eigenvalues in ascending order upon return. w must have length // at least n, and Syev will panic otherwise. // // On entry, a contains the elements of the symmetric matrix A in the triangular // portion specified by uplo. If jobz == lapack.EVCompute, a contains the // orthonormal eigenvectors of A on exit, otherwise jobz must be lapack.EVNone // and on exit the specified triangular region is overwritten. // // Work is temporary storage, and lwork specifies the usable memory length. At minimum, // lwork >= 3*n-1, and Syev will panic otherwise. The amount of blocking is // limited by the usable length. If lwork == -1, instead of computing Syev the // optimal work length is stored into work[0]. func Syev(jobz lapack.EVJob, a blas64.Symmetric, w, work []float64, lwork int) (ok bool) { return lapack64.Dsyev(jobz, a.Uplo, a.N, a.Data, max(1, a.Stride), w, work, lwork) } // Tbtrs solves a triangular system of the form // // A * X = B if trans == blas.NoTrans // Aᵀ * X = B if trans == blas.Trans or blas.ConjTrans // // where A is an n×n triangular band matrix, and B is an n×nrhs matrix. // // Tbtrs returns whether A is non-singular. If A is singular, no solutions X // are computed. func Tbtrs(trans blas.Transpose, a blas64.TriangularBand, b blas64.General) (ok bool) { return lapack64.Dtbtrs(a.Uplo, trans, a.Diag, a.N, a.K, b.Cols, a.Data, max(1, a.Stride), b.Data, max(1, b.Stride)) } // Trcon estimates the reciprocal of the condition number of a triangular matrix A. // The condition number computed may be based on the 1-norm or the ∞-norm. // // work is a temporary data slice of length at least 3*n and Trcon will panic otherwise. // // iwork is a temporary data slice of length at least n and Trcon will panic otherwise. func Trcon(norm lapack.MatrixNorm, a blas64.Triangular, work []float64, iwork []int) float64 { return lapack64.Dtrcon(norm, a.Uplo, a.Diag, a.N, a.Data, max(1, a.Stride), work, iwork) } // Trtri computes the inverse of a triangular matrix, storing the result in place // into a. // // Trtri will not perform the inversion if the matrix is singular, and returns // a boolean indicating whether the inversion was successful. func Trtri(a blas64.Triangular) (ok bool) { return lapack64.Dtrtri(a.Uplo, a.Diag, a.N, a.Data, max(1, a.Stride)) } // Trtrs solves a triangular system of the form A * X = B or Aᵀ * X = B. Trtrs // returns whether the solve completed successfully. If A is singular, no solve is performed. func Trtrs(trans blas.Transpose, a blas64.Triangular, b blas64.General) (ok bool) { return lapack64.Dtrtrs(a.Uplo, trans, a.Diag, a.N, b.Cols, a.Data, max(1, a.Stride), b.Data, max(1, b.Stride)) } // Geev computes the eigenvalues and, optionally, the left and/or right // eigenvectors for an n×n real nonsymmetric matrix A. // // The right eigenvector v_j of A corresponding to an eigenvalue λ_j // is defined by // // A v_j = λ_j v_j, // // and the left eigenvector u_j corresponding to an eigenvalue λ_j is defined by // // u_jᴴ A = λ_j u_jᴴ, // // where u_jᴴ is the conjugate transpose of u_j. // // On return, A will be overwritten and the left and right eigenvectors will be // stored, respectively, in the columns of the n×n matrices VL and VR in the // same order as their eigenvalues. If the j-th eigenvalue is real, then // // u_j = VL[:,j], // v_j = VR[:,j], // // and if it is not real, then j and j+1 form a complex conjugate pair and the // eigenvectors can be recovered as // // u_j = VL[:,j] + i*VL[:,j+1], // u_{j+1} = VL[:,j] - i*VL[:,j+1], // v_j = VR[:,j] + i*VR[:,j+1], // v_{j+1} = VR[:,j] - i*VR[:,j+1], // // where i is the imaginary unit. The computed eigenvectors are normalized to // have Euclidean norm equal to 1 and largest component real. // // Left eigenvectors will be computed only if jobvl == lapack.LeftEVCompute, // otherwise jobvl must be lapack.LeftEVNone. // Right eigenvectors will be computed only if jobvr == lapack.RightEVCompute, // otherwise jobvr must be lapack.RightEVNone. // For other values of jobvl and jobvr Geev will panic. // // On return, wr and wi will contain the real and imaginary parts, respectively, // of the computed eigenvalues. Complex conjugate pairs of eigenvalues appear // consecutively with the eigenvalue having the positive imaginary part first. // wr and wi must have length n, and Geev will panic otherwise. // // work must have length at least lwork and lwork must be at least max(1,4*n) if // the left or right eigenvectors are computed, and at least max(1,3*n) if no // eigenvectors are computed. For good performance, lwork must generally be // larger. On return, optimal value of lwork will be stored in work[0]. // // If lwork == -1, instead of performing Geev, the function only calculates the // optimal value of lwork and stores it into work[0]. // // On return, first will be the index of the first valid eigenvalue. // If first == 0, all eigenvalues and eigenvectors have been computed. // If first is positive, Geev failed to compute all the eigenvalues, no // eigenvectors have been computed and wr[first:] and wi[first:] contain those // eigenvalues which have converged. func Geev(jobvl lapack.LeftEVJob, jobvr lapack.RightEVJob, a blas64.General, wr, wi []float64, vl, vr blas64.General, work []float64, lwork int) (first int) { n := a.Rows if a.Cols != n { panic("lapack64: matrix not square") } if jobvl == lapack.LeftEVCompute && (vl.Rows != n || vl.Cols != n) { panic("lapack64: bad size of VL") } if jobvr == lapack.RightEVCompute && (vr.Rows != n || vr.Cols != n) { panic("lapack64: bad size of VR") } return lapack64.Dgeev(jobvl, jobvr, n, a.Data, max(1, a.Stride), wr, wi, vl.Data, max(1, vl.Stride), vr.Data, max(1, vr.Stride), work, lwork) } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/000077500000000000000000000000001450372207100212245ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dbdsqr.go000066400000000000000000000125011450372207100230310ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) type Dbdsqrer interface { Dbdsqr(uplo blas.Uplo, n, ncvt, nru, ncc int, d, e, vt []float64, ldvt int, u []float64, ldu int, c []float64, ldc int, work []float64) (ok bool) } func DbdsqrTest(t *testing.T, impl Dbdsqrer) { rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, test := range []struct { n, ncvt, nru, ncc, ldvt, ldu, ldc int }{ {5, 5, 5, 5, 0, 0, 0}, {10, 10, 10, 10, 0, 0, 0}, {10, 11, 12, 13, 0, 0, 0}, {20, 13, 12, 11, 0, 0, 0}, {5, 5, 5, 5, 6, 7, 8}, {10, 10, 10, 10, 30, 40, 50}, {10, 12, 11, 13, 30, 40, 50}, {20, 12, 13, 11, 30, 40, 50}, {130, 130, 130, 500, 900, 900, 500}, } { for cas := 0; cas < 10; cas++ { n := test.n ncvt := test.ncvt nru := test.nru ncc := test.ncc ldvt := test.ldvt ldu := test.ldu ldc := test.ldc if ldvt == 0 { ldvt = max(1, ncvt) } if ldu == 0 { ldu = max(1, n) } if ldc == 0 { ldc = max(1, ncc) } d := make([]float64, n) for i := range d { d[i] = rnd.NormFloat64() } e := make([]float64, n-1) for i := range e { e[i] = rnd.NormFloat64() } dCopy := make([]float64, len(d)) copy(dCopy, d) eCopy := make([]float64, len(e)) copy(eCopy, e) work := make([]float64, 4*(n-1)) for i := range work { work[i] = rnd.NormFloat64() } // First test the decomposition of the bidiagonal matrix. Set // pt and u equal to I with the correct size. At the result // of Dbdsqr, p and u will contain the data of Pᵀ and Q, which // will be used in the next step to test the multiplication // with Q and VT. q := make([]float64, n*n) ldq := n pt := make([]float64, n*n) ldpt := n for i := 0; i < n; i++ { q[i*ldq+i] = 1 } for i := 0; i < n; i++ { pt[i*ldpt+i] = 1 } ok := impl.Dbdsqr(uplo, n, n, n, 0, d, e, pt, ldpt, q, ldq, nil, 1, work) isUpper := uplo == blas.Upper errStr := fmt.Sprintf("isUpper = %v, n = %v, ncvt = %v, nru = %v, ncc = %v", isUpper, n, ncvt, nru, ncc) if !ok { t.Errorf("Unexpected Dbdsqr failure: %s", errStr) } bMat := constructBidiagonal(uplo, n, dCopy, eCopy) sMat := constructBidiagonal(uplo, n, d, e) tmp := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } ansMat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, q, ldq, sMat.Data, sMat.Stride, 0, tmp.Data, tmp.Stride) bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, tmp.Data, tmp.Stride, pt, ldpt, 0, ansMat.Data, ansMat.Stride) same := true for i := 0; i < n; i++ { for j := 0; j < n; j++ { if !scalar.EqualWithinAbsOrRel(ansMat.Data[i*ansMat.Stride+j], bMat.Data[i*bMat.Stride+j], 1e-8, 1e-8) { same = false } } } if !same { t.Errorf("Bidiagonal mismatch. %s", errStr) } if !sort.IsSorted(sort.Reverse(sort.Float64Slice(d))) { t.Errorf("D is not sorted. %s", errStr) } // The above computed the real P and Q. Now input data for Vᵀ, // U, and C to check that the multiplications happen properly. dAns := make([]float64, len(d)) copy(dAns, d) eAns := make([]float64, len(e)) copy(eAns, e) u := make([]float64, nru*ldu) for i := range u { u[i] = rnd.NormFloat64() } uCopy := make([]float64, len(u)) copy(uCopy, u) vt := make([]float64, n*ldvt) for i := range vt { vt[i] = rnd.NormFloat64() } vtCopy := make([]float64, len(vt)) copy(vtCopy, vt) c := make([]float64, n*ldc) for i := range c { c[i] = rnd.NormFloat64() } cCopy := make([]float64, len(c)) copy(cCopy, c) // Reset input data copy(d, dCopy) copy(e, eCopy) impl.Dbdsqr(uplo, n, ncvt, nru, ncc, d, e, vt, ldvt, u, ldu, c, ldc, work) // Check result. if !floats.EqualApprox(d, dAns, 1e-14) { t.Errorf("D mismatch second time. %s", errStr) } if !floats.EqualApprox(e, eAns, 1e-14) { t.Errorf("E mismatch second time. %s", errStr) } ans := make([]float64, len(vtCopy)) copy(ans, vtCopy) ldans := ldvt bi.Dgemm(blas.NoTrans, blas.NoTrans, n, ncvt, n, 1, pt, ldpt, vtCopy, ldvt, 0, ans, ldans) if !floats.EqualApprox(ans, vt, 1e-10) { t.Errorf("Vt result mismatch. %s", errStr) } ans = make([]float64, len(uCopy)) copy(ans, uCopy) ldans = ldu bi.Dgemm(blas.NoTrans, blas.NoTrans, nru, n, n, 1, uCopy, ldu, q, ldq, 0, ans, ldans) if !floats.EqualApprox(ans, u, 1e-10) { t.Errorf("U result mismatch. %s", errStr) } ans = make([]float64, len(cCopy)) copy(ans, cCopy) ldans = ldc bi.Dgemm(blas.Trans, blas.NoTrans, n, ncc, n, 1, q, ldq, cCopy, ldc, 0, ans, ldans) if !floats.EqualApprox(ans, c, 1e-10) { t.Errorf("C result mismatch. %s", errStr) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgebak.go000066400000000000000000000061401450372207100227710ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgebaker interface { Dgebak(job lapack.BalanceJob, side lapack.EVSide, n, ilo, ihi int, scale []float64, m int, v []float64, ldv int) } func DgebakTest(t *testing.T, impl Dgebaker) { rnd := rand.New(rand.NewSource(1)) for _, job := range []lapack.BalanceJob{lapack.BalanceNone, lapack.Permute, lapack.Scale, lapack.PermuteScale} { for _, side := range []lapack.EVSide{lapack.EVLeft, lapack.EVRight} { for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 10, 18, 31, 53} { for _, extra := range []int{0, 11} { for cas := 0; cas < 100; cas++ { m := rnd.Intn(n + 1) v := randomGeneral(n, m, m+extra, rnd) var ilo, ihi int if v.Rows > 0 { ihi = rnd.Intn(n) ilo = rnd.Intn(ihi + 1) } else { ihi = -1 } testDgebak(t, impl, job, side, ilo, ihi, v, rnd) } } } } } } func testDgebak(t *testing.T, impl Dgebaker, job lapack.BalanceJob, side lapack.EVSide, ilo, ihi int, v blas64.General, rnd *rand.Rand) { const tol = 1e-15 n := v.Rows m := v.Cols extra := v.Stride - v.Cols // Create D and D^{-1} by generating random scales between ilo and ihi. d := eye(n, n) dinv := eye(n, n) scale := nanSlice(n) if job == lapack.Scale || job == lapack.PermuteScale { if ilo == ihi { scale[ilo] = 1 } else { for i := ilo; i <= ihi; i++ { scale[i] = 2 * rnd.Float64() d.Data[i*d.Stride+i] = scale[i] dinv.Data[i*dinv.Stride+i] = 1 / scale[i] } } } // Create P by generating random column swaps. p := eye(n, n) if job == lapack.Permute || job == lapack.PermuteScale { // Make up some random permutations. for i := n - 1; i > ihi; i-- { scale[i] = float64(rnd.Intn(i + 1)) blas64.Swap(blas64.Vector{N: n, Data: p.Data[i:], Inc: p.Stride}, blas64.Vector{N: n, Data: p.Data[int(scale[i]):], Inc: p.Stride}) } for i := 0; i < ilo; i++ { scale[i] = float64(i + rnd.Intn(ihi-i+1)) blas64.Swap(blas64.Vector{N: n, Data: p.Data[i:], Inc: p.Stride}, blas64.Vector{N: n, Data: p.Data[int(scale[i]):], Inc: p.Stride}) } } got := cloneGeneral(v) impl.Dgebak(job, side, n, ilo, ihi, scale, m, got.Data, got.Stride) prefix := fmt.Sprintf("Case job=%c, side=%c, n=%v, ilo=%v, ihi=%v, m=%v, extra=%v", job, side, n, ilo, ihi, m, extra) if !generalOutsideAllNaN(got) { t.Errorf("%v: out-of-range write to V\n%v", prefix, got.Data) } // Compute D*V or D^{-1}*V and store into dv. dv := zeros(n, m, m) if side == lapack.EVRight { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, d, v, 0, dv) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, dinv, v, 0, dv) } // Compute P*D*V or P*D^{-1}*V and store into want. want := zeros(n, m, m) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, p, dv, 0, want) if !equalApproxGeneral(want, got, tol) { t.Errorf("%v: unexpected value of V", prefix) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgebal.go000066400000000000000000000113021450372207100227660ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgebaler interface { Dgebal(job lapack.BalanceJob, n int, a []float64, lda int, scale []float64) (int, int) } func DgebalTest(t *testing.T, impl Dgebaler) { rnd := rand.New(rand.NewSource(1)) for _, job := range []lapack.BalanceJob{lapack.BalanceNone, lapack.Permute, lapack.Scale, lapack.PermuteScale} { for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 10, 18, 31, 53, 100} { for _, extra := range []int{0, 11} { for cas := 0; cas < 100; cas++ { a := unbalancedSparseGeneral(n, n, n+extra, 2*n, rnd) testDgebal(t, impl, job, a) } } } } } func testDgebal(t *testing.T, impl Dgebaler, job lapack.BalanceJob, a blas64.General) { const tol = 1e-14 n := a.Rows extra := a.Stride - n var scale []float64 if n > 0 { scale = nanSlice(n) } want := cloneGeneral(a) ilo, ihi := impl.Dgebal(job, n, a.Data, a.Stride, scale) prefix := fmt.Sprintf("Case job=%c, n=%v, extra=%v", job, n, extra) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A\n%v", prefix, a.Data) } if n == 0 { if ilo != 0 { t.Errorf("%v: unexpected ilo when n=0. Want 0, got %v", prefix, ilo) } if ihi != -1 { t.Errorf("%v: unexpected ihi when n=0. Want -1, got %v", prefix, ihi) } return } if job == lapack.BalanceNone { if ilo != 0 { t.Errorf("%v: unexpected ilo when job=BalanceNone. Want 0, got %v", prefix, ilo) } if ihi != n-1 { t.Errorf("%v: unexpected ihi when job=BalanceNone. Want %v, got %v", prefix, n-1, ihi) } k := -1 for i := range scale { if scale[i] != 1 { k = i break } } if k != -1 { t.Errorf("%v: unexpected scale[%v] when job=BalanceNone. Want 1, got %v", prefix, k, scale[k]) } if !equalApproxGeneral(a, want, 0) { t.Errorf("%v: unexpected modification of A when job=BalanceNone", prefix) } return } if ilo < 0 || ihi < ilo || n <= ihi { t.Errorf("%v: invalid ordering of ilo=%v and ihi=%v", prefix, ilo, ihi) } if ilo >= 2 && !isUpperTriangular(blas64.General{Rows: ilo - 1, Cols: ilo - 1, Data: a.Data, Stride: a.Stride}) { t.Errorf("%v: T1 is not upper triangular", prefix) } m := n - ihi - 1 // Order of T2. k := ihi + 1 if m >= 2 && !isUpperTriangular(blas64.General{Rows: m, Cols: m, Data: a.Data[k*a.Stride+k:], Stride: a.Stride}) { t.Errorf("%v: T2 is not upper triangular", prefix) } if job == lapack.Permute || job == lapack.PermuteScale { // Check that all rows in [ilo:ihi+1] have at least one nonzero // off-diagonal element. zeroRow := -1 for i := ilo; i <= ihi; i++ { onlyZeros := true for j := ilo; j <= ihi; j++ { if i != j && a.Data[i*a.Stride+j] != 0 { onlyZeros = false break } } if onlyZeros { zeroRow = i break } } if zeroRow != -1 && ilo != ihi { t.Errorf("%v: row %v has only zero off-diagonal elements, ilo=%v, ihi=%v", prefix, zeroRow, ilo, ihi) } // Check that all columns in [ilo:ihi+1] have at least one nonzero // off-diagonal element. zeroCol := -1 for j := ilo; j <= ihi; j++ { onlyZeros := true for i := ilo; i <= ihi; i++ { if i != j && a.Data[i*a.Stride+j] != 0 { onlyZeros = false break } } if onlyZeros { zeroCol = j break } } if zeroCol != -1 && ilo != ihi { t.Errorf("%v: column %v has only zero off-diagonal elements, ilo=%v, ihi=%v", prefix, zeroCol, ilo, ihi) } // Create the permutation matrix P. p := eye(n, n) for j := n - 1; j > ihi; j-- { blas64.Swap(blas64.Vector{N: n, Data: p.Data[j:], Inc: p.Stride}, blas64.Vector{N: n, Data: p.Data[int(scale[j]):], Inc: p.Stride}) } for j := 0; j < ilo; j++ { blas64.Swap(blas64.Vector{N: n, Data: p.Data[j:], Inc: p.Stride}, blas64.Vector{N: n, Data: p.Data[int(scale[j]):], Inc: p.Stride}) } // Compute Pᵀ*A*P and store into want. ap := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, want, p, 0, ap) blas64.Gemm(blas.Trans, blas.NoTrans, 1, p, ap, 0, want) } if job == lapack.Scale || job == lapack.PermuteScale { // Modify want by D and D^{-1}. d := eye(n, n) dinv := eye(n, n) for i := ilo; i <= ihi; i++ { d.Data[i*d.Stride+i] = scale[i] dinv.Data[i*dinv.Stride+i] = 1 / scale[i] } ad := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, want, d, 0, ad) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, dinv, ad, 0, want) } if !equalApproxGeneral(want, a, tol) { t.Errorf("%v: unexpected value of A, ilo=%v, ihi=%v", prefix, ilo, ihi) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgebd2.go000066400000000000000000000026531450372207100227100ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" ) type Dgebd2er interface { Dgebd2(m, n int, a []float64, lda int, d, e, tauq, taup, work []float64) } func Dgebd2Test(t *testing.T, impl Dgebd2er) { rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, lda int }{ {3, 4, 0}, {4, 3, 0}, {3, 4, 10}, {4, 3, 10}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate m×n matrix A and fill it with random numbers. a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } // Store a copy of A for later comparison. aCopy := make([]float64, len(a)) copy(aCopy, a) // Allocate slices for the main and off diagonal. nb := min(m, n) d := nanSlice(nb) e := nanSlice(nb - 1) // Allocate slices for scalar factors of elementary reflectors // and fill them with NaNs. tauP := nanSlice(nb) tauQ := nanSlice(nb) // Allocate workspace. work := nanSlice(max(m, n)) // Reduce A to upper or lower bidiagonal form by an orthogonal // transformation. impl.Dgebd2(m, n, a, lda, d, e, tauQ, tauP, work) // Check that it holds Qᵀ * A * P = B where B is represented by // d and e. checkBidiagonal(t, m, n, nb, a, lda, d, e, tauP, tauQ, aCopy) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgebrd.go000066400000000000000000000061661450372207100230130ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dgebrder interface { Dgebrd(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64, lwork int) Dgebd2er } func DgebrdTest(t *testing.T, impl Dgebrder) { rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, lda int }{ {100, 100, 0}, {100, 150, 0}, {150, 100, 0}, {100, 100, 200}, {100, 150, 200}, {150, 100, 200}, {300, 300, 0}, {300, 400, 0}, {400, 300, 0}, {300, 300, 500}, {300, 400, 500}, {300, 400, 500}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } minmn := min(m, n) a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } d := make([]float64, minmn) e := make([]float64, minmn-1) tauP := make([]float64, minmn) tauQ := make([]float64, minmn) work := make([]float64, max(m, n)) for i := range work { work[i] = math.NaN() } // Store a. aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute the true answer with the unblocked algorithm. impl.Dgebd2(m, n, a, lda, d, e, tauQ, tauP, work) aAns := make([]float64, len(a)) copy(aAns, a) dAns := make([]float64, len(d)) copy(dAns, d) eAns := make([]float64, len(e)) copy(eAns, e) tauQAns := make([]float64, len(tauQ)) copy(tauQAns, tauQ) tauPAns := make([]float64, len(tauP)) copy(tauPAns, tauP) // Test with optimal work. lwork := -1 copy(a, aCopy) impl.Dgebrd(m, n, a, lda, d, e, tauQ, tauP, work, lwork) work = make([]float64, int(work[0])) lwork = len(work) for i := range work { work[i] = math.NaN() } for i := range d { d[i] = math.NaN() } for i := range e { e[i] = math.NaN() } for i := range tauQ { tauQ[i] = math.NaN() } for i := range tauP { tauP[i] = math.NaN() } impl.Dgebrd(m, n, a, lda, d, e, tauQ, tauP, work, lwork) // Test answers if !floats.EqualApprox(a, aAns, 1e-10) { t.Errorf("a mismatch") } if !floats.EqualApprox(d, dAns, 1e-10) { t.Errorf("d mismatch") } if !floats.EqualApprox(e, eAns, 1e-10) { t.Errorf("e mismatch") } if !floats.EqualApprox(tauQ, tauQAns, 1e-10) { t.Errorf("tauQ mismatch") } if !floats.EqualApprox(tauP, tauPAns, 1e-10) { t.Errorf("tauP mismatch") } // Test with shorter than optimal work. lwork-- copy(a, aCopy) for i := range d { d[i] = 0 } for i := range e { e[i] = 0 } for i := range tauP { tauP[i] = 0 } for i := range tauQ { tauQ[i] = 0 } impl.Dgebrd(m, n, a, lda, d, e, tauQ, tauP, work, lwork) // Test answers if !floats.EqualApprox(a, aAns, 1e-10) { t.Errorf("a mismatch") } if !floats.EqualApprox(d, dAns, 1e-10) { t.Errorf("d mismatch") } if !floats.EqualApprox(e, eAns, 1e-10) { t.Errorf("e mismatch") } if !floats.EqualApprox(tauQ, tauQAns, 1e-10) { t.Errorf("tauQ mismatch") } if !floats.EqualApprox(tauP, tauPAns, 1e-10) { t.Errorf("tauP mismatch") } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgecon.go000066400000000000000000000047071450372207100230220ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dgeconer interface { Dgecon(norm lapack.MatrixNorm, n int, a []float64, lda int, anorm float64, work []float64, iwork []int) float64 Dgetrier Dlanger } func DgeconTest(t *testing.T, impl Dgeconer) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50} { for _, lda := range []int{max(1, n), n + 3} { dgeconTest(t, impl, rnd, n, lda) } } } func dgeconTest(t *testing.T, impl Dgeconer, rnd *rand.Rand, n, lda int) { const ratioThresh = 10 // Generate a random square matrix A with elements uniformly in [-1,1). a := make([]float64, max(0, (n-1)*lda+n)) for i := range a { a[i] = 2*rnd.Float64() - 1 } // Allocate work slices. iwork := make([]int, n) work := make([]float64, max(1, 4*n)) // Compute the LU factorization of A. aFac := make([]float64, len(a)) copy(aFac, a) ipiv := make([]int, n) ok := impl.Dgetrf(n, n, aFac, lda, ipiv) if !ok { t.Fatalf("n=%v,lda=%v: bad matrix, Dgetrf failed", n, lda) } aFacCopy := make([]float64, len(aFac)) copy(aFacCopy, aFac) // Compute the inverse A^{-1} from the LU factorization. aInv := make([]float64, len(aFac)) copy(aInv, aFac) ok = impl.Dgetri(n, aInv, lda, ipiv, work, len(work)) if !ok { t.Fatalf("n=%v,lda=%v: bad matrix, Dgetri failed", n, lda) } for _, norm := range []lapack.MatrixNorm{lapack.MaxColumnSum, lapack.MaxRowSum} { name := fmt.Sprintf("norm=%v,n=%v,lda=%v", string(norm), n, lda) // Compute the norm of A and A^{-1}. aNorm := impl.Dlange(norm, n, n, a, lda, work) aInvNorm := impl.Dlange(norm, n, n, aInv, lda, work) // Compute a good estimate of the condition number // rcondWant := 1/(norm(A) * norm(inv(A))) rcondWant := 1.0 if aNorm > 0 && aInvNorm > 0 { rcondWant = 1 / aNorm / aInvNorm } // Compute an estimate of rcond using the LU factorization and Dgecon. rcondGot := impl.Dgecon(norm, n, aFac, lda, aNorm, work, iwork) if !floats.Equal(aFac, aFacCopy) { t.Errorf("%v: unexpected modification of aFac", name) } ratio := rCondTestRatio(rcondGot, rcondWant) if ratio >= ratioThresh { t.Errorf("%v: unexpected value of rcond; got=%v, want=%v (ratio=%v)", name, rcondGot, rcondWant, ratio) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgeev.go000066400000000000000000000477031450372207100226600ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "math/cmplx" "strconv" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgeever interface { Dgeev(jobvl lapack.LeftEVJob, jobvr lapack.RightEVJob, n int, a []float64, lda int, wr, wi []float64, vl []float64, ldvl int, vr []float64, ldvr int, work []float64, lwork int) int } type dgeevTest struct { a blas64.General evWant []complex128 // If nil, the eigenvalues are not known. valTol float64 // Tolerance for eigenvalue checks. vecTol float64 // Tolerance for eigenvector checks. } func DgeevTest(t *testing.T, impl Dgeever) { rnd := rand.New(rand.NewSource(1)) for i, test := range []dgeevTest{ { a: A123{}.Matrix(), evWant: A123{}.Eigenvalues(), }, dgeevTestForAntisymRandom(10, rnd), dgeevTestForAntisymRandom(11, rnd), dgeevTestForAntisymRandom(50, rnd), dgeevTestForAntisymRandom(51, rnd), dgeevTestForAntisymRandom(100, rnd), dgeevTestForAntisymRandom(101, rnd), { a: Circulant(2).Matrix(), evWant: Circulant(2).Eigenvalues(), }, { a: Circulant(3).Matrix(), evWant: Circulant(3).Eigenvalues(), }, { a: Circulant(4).Matrix(), evWant: Circulant(4).Eigenvalues(), }, { a: Circulant(5).Matrix(), evWant: Circulant(5).Eigenvalues(), }, { a: Circulant(10).Matrix(), evWant: Circulant(10).Eigenvalues(), }, { a: Circulant(15).Matrix(), evWant: Circulant(15).Eigenvalues(), valTol: 1e-12, }, { a: Circulant(30).Matrix(), evWant: Circulant(30).Eigenvalues(), valTol: 1e-11, }, { a: Circulant(50).Matrix(), evWant: Circulant(50).Eigenvalues(), valTol: 1e-11, }, { a: Circulant(101).Matrix(), evWant: Circulant(101).Eigenvalues(), valTol: 1e-10, }, { a: Circulant(150).Matrix(), evWant: Circulant(150).Eigenvalues(), valTol: 1e-9, }, { a: Clement(2).Matrix(), evWant: Clement(2).Eigenvalues(), }, { a: Clement(3).Matrix(), evWant: Clement(3).Eigenvalues(), }, { a: Clement(4).Matrix(), evWant: Clement(4).Eigenvalues(), }, { a: Clement(5).Matrix(), evWant: Clement(5).Eigenvalues(), }, { a: Clement(10).Matrix(), evWant: Clement(10).Eigenvalues(), }, { a: Clement(15).Matrix(), evWant: Clement(15).Eigenvalues(), }, { a: Clement(30).Matrix(), evWant: Clement(30).Eigenvalues(), valTol: 1e-11, }, { a: Clement(50).Matrix(), evWant: Clement(50).Eigenvalues(), valTol: 1e-8, }, { a: Creation(2).Matrix(), evWant: Creation(2).Eigenvalues(), }, { a: Creation(3).Matrix(), evWant: Creation(3).Eigenvalues(), }, { a: Creation(4).Matrix(), evWant: Creation(4).Eigenvalues(), }, { a: Creation(5).Matrix(), evWant: Creation(5).Eigenvalues(), }, { a: Creation(10).Matrix(), evWant: Creation(10).Eigenvalues(), }, { a: Creation(15).Matrix(), evWant: Creation(15).Eigenvalues(), }, { a: Creation(30).Matrix(), evWant: Creation(30).Eigenvalues(), }, { a: Creation(50).Matrix(), evWant: Creation(50).Eigenvalues(), }, { a: Creation(101).Matrix(), evWant: Creation(101).Eigenvalues(), }, { a: Creation(150).Matrix(), evWant: Creation(150).Eigenvalues(), }, { a: Diagonal(0).Matrix(), evWant: Diagonal(0).Eigenvalues(), }, { a: Diagonal(10).Matrix(), evWant: Diagonal(10).Eigenvalues(), }, { a: Diagonal(50).Matrix(), evWant: Diagonal(50).Eigenvalues(), }, { a: Diagonal(151).Matrix(), evWant: Diagonal(151).Eigenvalues(), }, { a: Downshift(2).Matrix(), evWant: Downshift(2).Eigenvalues(), }, { a: Downshift(3).Matrix(), evWant: Downshift(3).Eigenvalues(), }, { a: Downshift(4).Matrix(), evWant: Downshift(4).Eigenvalues(), }, { a: Downshift(5).Matrix(), evWant: Downshift(5).Eigenvalues(), }, { a: Downshift(10).Matrix(), evWant: Downshift(10).Eigenvalues(), }, { a: Downshift(15).Matrix(), evWant: Downshift(15).Eigenvalues(), }, { a: Downshift(30).Matrix(), evWant: Downshift(30).Eigenvalues(), }, { a: Downshift(50).Matrix(), evWant: Downshift(50).Eigenvalues(), }, { a: Downshift(101).Matrix(), evWant: Downshift(101).Eigenvalues(), }, { a: Downshift(150).Matrix(), evWant: Downshift(150).Eigenvalues(), }, { a: Fibonacci(2).Matrix(), evWant: Fibonacci(2).Eigenvalues(), }, { a: Fibonacci(3).Matrix(), evWant: Fibonacci(3).Eigenvalues(), }, { a: Fibonacci(4).Matrix(), evWant: Fibonacci(4).Eigenvalues(), }, { a: Fibonacci(5).Matrix(), evWant: Fibonacci(5).Eigenvalues(), }, { a: Fibonacci(10).Matrix(), evWant: Fibonacci(10).Eigenvalues(), }, { a: Fibonacci(15).Matrix(), evWant: Fibonacci(15).Eigenvalues(), }, { a: Fibonacci(30).Matrix(), evWant: Fibonacci(30).Eigenvalues(), }, { a: Fibonacci(50).Matrix(), evWant: Fibonacci(50).Eigenvalues(), }, { a: Fibonacci(101).Matrix(), evWant: Fibonacci(101).Eigenvalues(), }, { a: Fibonacci(150).Matrix(), evWant: Fibonacci(150).Eigenvalues(), }, { a: Gear(2).Matrix(), evWant: Gear(2).Eigenvalues(), }, { a: Gear(3).Matrix(), evWant: Gear(3).Eigenvalues(), }, { a: Gear(4).Matrix(), evWant: Gear(4).Eigenvalues(), valTol: 1e-7, vecTol: 1e-8, }, { a: Gear(5).Matrix(), evWant: Gear(5).Eigenvalues(), }, { a: Gear(10).Matrix(), evWant: Gear(10).Eigenvalues(), valTol: 1e-8, }, { a: Gear(15).Matrix(), evWant: Gear(15).Eigenvalues(), }, { a: Gear(30).Matrix(), evWant: Gear(30).Eigenvalues(), valTol: 1e-8, }, { a: Gear(50).Matrix(), evWant: Gear(50).Eigenvalues(), valTol: 1e-8, }, { a: Gear(101).Matrix(), evWant: Gear(101).Eigenvalues(), }, { a: Gear(150).Matrix(), evWant: Gear(150).Eigenvalues(), valTol: 1e-8, }, { a: Grcar{N: 10, K: 3}.Matrix(), evWant: Grcar{N: 10, K: 3}.Eigenvalues(), }, { a: Grcar{N: 10, K: 7}.Matrix(), evWant: Grcar{N: 10, K: 7}.Eigenvalues(), }, { a: Grcar{N: 11, K: 7}.Matrix(), evWant: Grcar{N: 11, K: 7}.Eigenvalues(), }, { a: Grcar{N: 50, K: 3}.Matrix(), evWant: Grcar{N: 50, K: 3}.Eigenvalues(), }, { a: Grcar{N: 51, K: 3}.Matrix(), evWant: Grcar{N: 51, K: 3}.Eigenvalues(), }, { a: Grcar{N: 50, K: 10}.Matrix(), evWant: Grcar{N: 50, K: 10}.Eigenvalues(), }, { a: Grcar{N: 51, K: 10}.Matrix(), evWant: Grcar{N: 51, K: 10}.Eigenvalues(), }, { a: Grcar{N: 50, K: 30}.Matrix(), evWant: Grcar{N: 50, K: 30}.Eigenvalues(), }, { a: Grcar{N: 150, K: 2}.Matrix(), evWant: Grcar{N: 150, K: 2}.Eigenvalues(), }, { a: Grcar{N: 150, K: 148}.Matrix(), evWant: Grcar{N: 150, K: 148}.Eigenvalues(), }, { a: Hanowa{N: 6, Alpha: 17}.Matrix(), evWant: Hanowa{N: 6, Alpha: 17}.Eigenvalues(), }, { a: Hanowa{N: 50, Alpha: -1}.Matrix(), evWant: Hanowa{N: 50, Alpha: -1}.Eigenvalues(), }, { a: Hanowa{N: 100, Alpha: -1}.Matrix(), evWant: Hanowa{N: 100, Alpha: -1}.Eigenvalues(), }, { a: Lesp(2).Matrix(), evWant: Lesp(2).Eigenvalues(), }, { a: Lesp(3).Matrix(), evWant: Lesp(3).Eigenvalues(), }, { a: Lesp(4).Matrix(), evWant: Lesp(4).Eigenvalues(), }, { a: Lesp(5).Matrix(), evWant: Lesp(5).Eigenvalues(), }, { a: Lesp(10).Matrix(), evWant: Lesp(10).Eigenvalues(), }, { a: Lesp(15).Matrix(), evWant: Lesp(15).Eigenvalues(), }, { a: Lesp(30).Matrix(), evWant: Lesp(30).Eigenvalues(), }, { a: Lesp(50).Matrix(), evWant: Lesp(50).Eigenvalues(), valTol: 1e-12, }, { a: Lesp(101).Matrix(), evWant: Lesp(101).Eigenvalues(), valTol: 1e-12, }, { a: Lesp(150).Matrix(), evWant: Lesp(150).Eigenvalues(), valTol: 1e-12, }, { a: Rutis{}.Matrix(), evWant: Rutis{}.Eigenvalues(), }, { a: Tris{N: 74, X: 1, Y: -2, Z: 1}.Matrix(), evWant: Tris{N: 74, X: 1, Y: -2, Z: 1}.Eigenvalues(), }, { a: Tris{N: 74, X: 1, Y: 2, Z: -3}.Matrix(), evWant: Tris{N: 74, X: 1, Y: 2, Z: -3}.Eigenvalues(), }, { a: Tris{N: 75, X: 1, Y: 2, Z: -3}.Matrix(), evWant: Tris{N: 75, X: 1, Y: 2, Z: -3}.Eigenvalues(), }, { a: Wilk4{}.Matrix(), evWant: Wilk4{}.Eigenvalues(), }, { a: Wilk12{}.Matrix(), evWant: Wilk12{}.Eigenvalues(), valTol: 1e-7, }, { a: Wilk20(0).Matrix(), evWant: Wilk20(0).Eigenvalues(), }, { a: Wilk20(1e-10).Matrix(), evWant: Wilk20(1e-10).Eigenvalues(), valTol: 1e-12, }, { a: Zero(1).Matrix(), evWant: Zero(1).Eigenvalues(), }, { a: Zero(10).Matrix(), evWant: Zero(10).Eigenvalues(), }, { a: Zero(50).Matrix(), evWant: Zero(50).Eigenvalues(), }, { a: Zero(100).Matrix(), evWant: Zero(100).Eigenvalues(), }, } { for _, jobvl := range []lapack.LeftEVJob{lapack.LeftEVCompute, lapack.LeftEVNone} { for _, jobvr := range []lapack.RightEVJob{lapack.RightEVCompute, lapack.RightEVNone} { for _, extra := range []int{0, 11} { for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { testDgeev(t, impl, strconv.Itoa(i), test, jobvl, jobvr, extra, wl) } } } } } for _, n := range []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, 50, 51, 100, 101} { for _, jobvl := range []lapack.LeftEVJob{lapack.LeftEVCompute, lapack.LeftEVNone} { for _, jobvr := range []lapack.RightEVJob{lapack.RightEVCompute, lapack.RightEVNone} { for cas := 0; cas < 10; cas++ { // Create a block diagonal matrix with // random eigenvalues of random multiplicity. ev := make([]complex128, n) tmat := zeros(n, n, n) for i := 0; i < n; { re := rnd.NormFloat64() if i == n-1 || rnd.Float64() < 0.5 { // Real eigenvalue. nb := rnd.Intn(min(4, n-i)) + 1 for k := 0; k < nb; k++ { tmat.Data[i*tmat.Stride+i] = re ev[i] = complex(re, 0) i++ } continue } // Complex eigenvalue. im := rnd.NormFloat64() nb := rnd.Intn(min(4, (n-i)/2)) + 1 for k := 0; k < nb; k++ { // 2×2 block for the complex eigenvalue. tmat.Data[i*tmat.Stride+i] = re tmat.Data[(i+1)*tmat.Stride+i+1] = re tmat.Data[(i+1)*tmat.Stride+i] = -im tmat.Data[i*tmat.Stride+i+1] = im ev[i] = complex(re, im) ev[i+1] = complex(re, -im) i += 2 } } // Compute A = Q T Qᵀ where Q is an // orthogonal matrix. q := randomOrthogonal(n, rnd) tq := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.Trans, 1, tmat, q, 0, tq) a := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, tq, 0, a) test := dgeevTest{ a: a, evWant: ev, vecTol: 1e-7, } testDgeev(t, impl, "random", test, jobvl, jobvr, 0, optimumWork) } } } } } func testDgeev(t *testing.T, impl Dgeever, tc string, test dgeevTest, jobvl lapack.LeftEVJob, jobvr lapack.RightEVJob, extra int, wl worklen) { const defaultTol = 1e-13 valTol := test.valTol if valTol == 0 { valTol = defaultTol } vecTol := test.vecTol if vecTol == 0 { vecTol = defaultTol } a := cloneGeneral(test.a) n := a.Rows var vl blas64.General if jobvl == lapack.LeftEVCompute { vl = nanGeneral(n, n, n) } else { vl.Stride = 1 } var vr blas64.General if jobvr == lapack.RightEVCompute { vr = nanGeneral(n, n, n) } else { vr.Stride = 1 } wr := make([]float64, n) wi := make([]float64, n) var lwork int switch wl { case minimumWork: if jobvl == lapack.LeftEVCompute || jobvr == lapack.RightEVCompute { lwork = max(1, 4*n) } else { lwork = max(1, 3*n) } case mediumWork: work := make([]float64, 1) impl.Dgeev(jobvl, jobvr, n, a.Data, a.Stride, wr, wi, vl.Data, vl.Stride, vr.Data, vr.Stride, work, -1) if jobvl == lapack.LeftEVCompute || jobvr == lapack.RightEVCompute { lwork = (int(work[0]) + 4*n) / 2 } else { lwork = (int(work[0]) + 3*n) / 2 } lwork = max(1, lwork) case optimumWork: work := make([]float64, 1) impl.Dgeev(jobvl, jobvr, n, a.Data, a.Stride, wr, wi, vl.Data, vl.Stride, vr.Data, vr.Stride, work, -1) lwork = int(work[0]) } work := make([]float64, lwork) first := impl.Dgeev(jobvl, jobvr, n, a.Data, a.Stride, wr, wi, vl.Data, vl.Stride, vr.Data, vr.Stride, work, len(work)) prefix := fmt.Sprintf("Case #%v: n=%v, jobvl=%c, jobvr=%c, extra=%v, work=%v", tc, n, jobvl, jobvr, extra, wl) if !generalOutsideAllNaN(vl) { t.Errorf("%v: out-of-range write to VL", prefix) } if !generalOutsideAllNaN(vr) { t.Errorf("%v: out-of-range write to VR", prefix) } if first > 0 { t.Logf("%v: all eigenvalues haven't been computed, first=%v", prefix, first) } // Check that conjugate pair eigenvalues are ordered correctly. for i := first; i < n; { if wi[i] == 0 { i++ continue } if wr[i] != wr[i+1] { t.Errorf("%v: real parts of %vth conjugate pair not equal", prefix, i) } if wi[i] < 0 || wi[i+1] >= 0 { t.Errorf("%v: unexpected ordering of %vth conjugate pair", prefix, i) } i += 2 } // Check the computed eigenvalues against provided known eigenvalues. if test.evWant != nil { used := make([]bool, n) for i := first; i < n; i++ { evGot := complex(wr[i], wi[i]) idx := -1 for k, evWant := range test.evWant { if !used[k] && cmplx.Abs(evWant-evGot) < valTol { idx = k used[k] = true break } } if idx == -1 { t.Errorf("%v: unexpected eigenvalue %v", prefix, evGot) } } } if first > 0 || (jobvl == lapack.LeftEVNone && jobvr == lapack.RightEVNone) { // No eigenvectors have been computed. return } // Check that the columns of VL and VR are eigenvectors that: // - correspond to the computed eigenvalues // - have Euclidean norm equal to 1 // - have the largest component real bi := blas64.Implementation() if jobvr == lapack.RightEVCompute { resid := residualRightEV(test.a, vr, wr, wi) if resid > vecTol { t.Errorf("%v: unexpected right eigenvectors; residual=%v, want<=%v", prefix, resid, vecTol) } for j := 0; j < n; j++ { nrm := 1.0 if wi[j] == 0 { nrm = bi.Dnrm2(n, vr.Data[j:], vr.Stride) } else if wi[j] > 0 { nrm = math.Hypot(bi.Dnrm2(n, vr.Data[j:], vr.Stride), bi.Dnrm2(n, vr.Data[j+1:], vr.Stride)) } diff := math.Abs(nrm - 1) if diff > defaultTol { t.Errorf("%v: unexpected Euclidean norm of right eigenvector; |VR[%v]-1|=%v, want<=%v", prefix, j, diff, defaultTol) } if wi[j] > 0 { var vmax float64 // Largest component in the column var vrmax float64 // Largest real component in the column for i := 0; i < n; i++ { vtest := math.Hypot(vr.Data[i*vr.Stride+j], vr.Data[i*vr.Stride+j+1]) vmax = math.Max(vmax, vtest) if vr.Data[i*vr.Stride+j+1] == 0 { vrmax = math.Max(vrmax, math.Abs(vr.Data[i*vr.Stride+j])) } } if vrmax/vmax < 1-defaultTol { t.Errorf("%v: largest component of %vth right eigenvector is not real", prefix, j) } } } } if jobvl == lapack.LeftEVCompute { resid := residualLeftEV(test.a, vl, wr, wi) if resid > vecTol { t.Errorf("%v: unexpected left eigenvectors; residual=%v, want<=%v", prefix, resid, vecTol) } for j := 0; j < n; j++ { nrm := 1.0 if wi[j] == 0 { nrm = bi.Dnrm2(n, vl.Data[j:], vl.Stride) } else if wi[j] > 0 { nrm = math.Hypot(bi.Dnrm2(n, vl.Data[j:], vl.Stride), bi.Dnrm2(n, vl.Data[j+1:], vl.Stride)) } diff := math.Abs(nrm - 1) if diff > defaultTol { t.Errorf("%v: unexpected Euclidean norm of left eigenvector; |VL[%v]-1|=%v, want<=%v", prefix, j, diff, defaultTol) } if wi[j] > 0 { var vmax float64 // Largest component in the column var vrmax float64 // Largest real component in the column for i := 0; i < n; i++ { vtest := math.Hypot(vl.Data[i*vl.Stride+j], vl.Data[i*vl.Stride+j+1]) vmax = math.Max(vmax, vtest) if vl.Data[i*vl.Stride+j+1] == 0 { vrmax = math.Max(vrmax, math.Abs(vl.Data[i*vl.Stride+j])) } } if vrmax/vmax < 1-defaultTol { t.Errorf("%v: largest component of %vth left eigenvector is not real", prefix, j) } } } } } func dgeevTestForAntisymRandom(n int, rnd *rand.Rand) dgeevTest { a := NewAntisymRandom(n, rnd) return dgeevTest{ a: a.Matrix(), evWant: a.Eigenvalues(), } } // residualRightEV returns the residual // // | A E - E W|_1 / ( |A|_1 |E|_1 ) // // where the columns of E contain the right eigenvectors of A and W is a block diagonal matrix with // a 1×1 block for each real eigenvalue and a 2×2 block for each complex conjugate pair. func residualRightEV(a, e blas64.General, wr, wi []float64) float64 { // The implementation follows DGET22 routine from the Reference LAPACK's // testing suite. n := a.Rows if n == 0 { return 0 } bi := blas64.Implementation() ldr := n r := make([]float64, n*ldr) var ( wmat [4]float64 ipair int ) for j := 0; j < n; j++ { if ipair == 0 && wi[j] != 0 { ipair = 1 } switch ipair { case 0: // Real eigenvalue, multiply j-th column of E with it. bi.Daxpy(n, wr[j], e.Data[j:], e.Stride, r[j:], ldr) case 1: // First of complex conjugate pair of eigenvalues wmat[0], wmat[1] = wr[j], wi[j] wmat[2], wmat[3] = -wi[j], wr[j] bi.Dgemm(blas.NoTrans, blas.NoTrans, n, 2, 2, 1, e.Data[j:], e.Stride, wmat[:], 2, 0, r[j:], ldr) ipair = 2 case 2: // Second of complex conjugate pair of eigenvalues ipair = 0 } } bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, a.Data, a.Stride, e.Data, e.Stride, -1, r, ldr) const eps = dlamchE anorm := math.Max(dlange(lapack.MaxColumnSum, n, n, a.Data, a.Stride), safmin) enorm := math.Max(dlange(lapack.MaxColumnSum, n, n, e.Data, e.Stride), eps) errnorm := dlange(lapack.MaxColumnSum, n, n, r, ldr) / enorm if anorm > errnorm { return errnorm / anorm } if anorm < 1 { return math.Min(errnorm, anorm) / anorm } return math.Min(errnorm/anorm, 1) } // residualLeftEV returns the residual // // | Aᵀ E - E Wᵀ|_1 / ( |Aᵀ|_1 |E|_1 ) // // where the columns of E contain the left eigenvectors of A and W is a block diagonal matrix with // a 1×1 block for each real eigenvalue and a 2×2 block for each complex conjugate pair. func residualLeftEV(a, e blas64.General, wr, wi []float64) float64 { // The implementation follows DGET22 routine from the Reference LAPACK's // testing suite. n := a.Rows if n == 0 { return 0 } bi := blas64.Implementation() ldr := n r := make([]float64, n*ldr) var ( wmat [4]float64 ipair int ) for j := 0; j < n; j++ { if ipair == 0 && wi[j] != 0 { ipair = 1 } switch ipair { case 0: // Real eigenvalue, multiply j-th column of E with it. bi.Daxpy(n, wr[j], e.Data[j:], e.Stride, r[j:], ldr) case 1: // First of complex conjugate pair of eigenvalues wmat[0], wmat[1] = wr[j], wi[j] wmat[2], wmat[3] = -wi[j], wr[j] bi.Dgemm(blas.NoTrans, blas.Trans, n, 2, 2, 1, e.Data[j:], e.Stride, wmat[:], 2, 0, r[j:], ldr) ipair = 2 case 2: // Second of complex conjugate pair of eigenvalues ipair = 0 } } bi.Dgemm(blas.Trans, blas.NoTrans, n, n, n, 1, a.Data, a.Stride, e.Data, e.Stride, -1, r, ldr) const eps = dlamchE anorm := math.Max(dlange(lapack.MaxRowSum, n, n, a.Data, a.Stride), safmin) enorm := math.Max(dlange(lapack.MaxColumnSum, n, n, e.Data, e.Stride), eps) errnorm := dlange(lapack.MaxColumnSum, n, n, r, ldr) / enorm if anorm > errnorm { return errnorm / anorm } if anorm < 1 { return math.Min(errnorm, anorm) / anorm } return math.Min(errnorm/anorm, 1) } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgeev_bench.go000066400000000000000000000040211450372207100240010ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) func DgeevBenchmark(b *testing.B, impl Dgeever) { var resultGeneral blas64.General rnd := rand.New(rand.NewSource(1)) benchmarks := []struct { name string a blas64.General }{ {"AntisymRandom3", NewAntisymRandom(3, rnd).Matrix()}, {"AntisymRandom4", NewAntisymRandom(4, rnd).Matrix()}, {"AntisymRandom5", NewAntisymRandom(5, rnd).Matrix()}, {"AntisymRandom10", NewAntisymRandom(10, rnd).Matrix()}, {"AntisymRandom50", NewAntisymRandom(50, rnd).Matrix()}, {"AntisymRandom100", NewAntisymRandom(100, rnd).Matrix()}, {"AntisymRandom200", NewAntisymRandom(200, rnd).Matrix()}, {"AntisymRandom500", NewAntisymRandom(500, rnd).Matrix()}, {"Circulant3", Circulant(3).Matrix()}, {"Circulant4", Circulant(4).Matrix()}, {"Circulant5", Circulant(5).Matrix()}, {"Circulant10", Circulant(10).Matrix()}, {"Circulant50", Circulant(50).Matrix()}, {"Circulant100", Circulant(100).Matrix()}, {"Circulant200", Circulant(200).Matrix()}, {"Circulant500", Circulant(500).Matrix()}, } for _, bm := range benchmarks { n := bm.a.Rows a := zeros(n, n, n) vl := zeros(n, n, n) vr := zeros(n, n, n) wr := make([]float64, n) wi := make([]float64, n) work := make([]float64, 1) impl.Dgeev(lapack.LeftEVCompute, lapack.RightEVCompute, n, a.Data, a.Stride, wr, wi, vl.Data, vl.Stride, vr.Data, vr.Stride, work, -1) work = make([]float64, int(work[0])) b.Run(bm.name, func(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() copyGeneral(a, bm.a) b.StartTimer() impl.Dgeev(lapack.LeftEVCompute, lapack.RightEVCompute, n, a.Data, a.Stride, wr, wi, vl.Data, vl.Stride, vr.Data, vr.Stride, work, len(work)) } resultGeneral = a }) } if resultGeneral.Data == nil { b.Error("unexpected nil data") } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgehd2.go000066400000000000000000000113161450372207100227120ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dgehd2er interface { Dgehd2(n, ilo, ihi int, a []float64, lda int, tau, work []float64) } func Dgehd2Test(t *testing.T, impl Dgehd2er) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 4, 5, 7, 10, 30} { for _, extra := range []int{0, 1, 13} { for cas := 0; cas < 100; cas++ { testDgehd2(t, impl, n, extra, rnd) } } } } func testDgehd2(t *testing.T, impl Dgehd2er, n, extra int, rnd *rand.Rand) { const tol = 1e-14 ilo := rnd.Intn(n) ihi := rnd.Intn(n) if ilo > ihi { ilo, ihi = ihi, ilo } tau := nanSlice(n - 1) work := nanSlice(n) a := randomGeneral(n, n, n+extra, rnd) // NaN out elements under the diagonal except // for the [ilo:ihi,ilo:ihi] block. for i := 1; i <= ihi; i++ { for j := 0; j < min(ilo, i); j++ { a.Data[i*a.Stride+j] = math.NaN() } } for i := ihi + 1; i < n; i++ { for j := 0; j < i; j++ { a.Data[i*a.Stride+j] = math.NaN() } } aCopy := a aCopy.Data = make([]float64, len(a.Data)) copy(aCopy.Data, a.Data) impl.Dgehd2(n, ilo, ihi, a.Data, a.Stride, tau, work) prefix := fmt.Sprintf("Case n=%v, ilo=%v, ihi=%v, extra=%v", n, ilo, ihi, extra) // Check any invalid modifications of a. if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A\n%v", prefix, a.Data) } for i := ilo; i <= ihi; i++ { for j := 0; j < min(ilo, i); j++ { if !math.IsNaN(a.Data[i*a.Stride+j]) { t.Errorf("%v: expected NaN at A[%v,%v]", prefix, i, j) } } } for i := ihi + 1; i < n; i++ { for j := 0; j < i; j++ { if !math.IsNaN(a.Data[i*a.Stride+j]) { t.Errorf("%v: expected NaN at A[%v,%v]", prefix, i, j) } } } for i := 0; i <= ilo; i++ { for j := i; j < ilo+1; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification at A[%v,%v]", prefix, i, j) } } for j := ihi + 1; j < n; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification at A[%v,%v]", prefix, i, j) } } } for i := ihi + 1; i < n; i++ { for j := i; j < n; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification at A[%v,%v]", prefix, i, j) } } } // Check that tau has been assigned properly. for i, v := range tau { if i < ilo || i >= ihi { if !math.IsNaN(v) { t.Errorf("%v: expected NaN at tau[%v]", prefix, i) } } else { if math.IsNaN(v) { t.Errorf("%v: unexpected NaN at tau[%v]", prefix, i) } } } // Extract Q and check that it is orthogonal. q := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < q.Rows; i++ { q.Data[i*q.Stride+i] = 1 } qCopy := q qCopy.Data = make([]float64, len(q.Data)) for j := ilo; j < ihi; j++ { h := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < h.Rows; i++ { h.Data[i*h.Stride+i] = 1 } v := blas64.Vector{ Inc: 1, Data: make([]float64, n), } v.Data[j+1] = 1 for i := j + 2; i < ihi+1; i++ { v.Data[i] = a.Data[i*a.Stride+j] } blas64.Ger(-tau[j], v, v, h) copy(qCopy.Data, q.Data) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, h, 0, q) } if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("%v: Q is not orthogonal; resid=%v, want<=%v", prefix, resid, tol) } // Overwrite NaN elements of aCopy with zeros // (we will multiply with it below). for i := 1; i <= ihi; i++ { for j := 0; j < min(ilo, i); j++ { aCopy.Data[i*aCopy.Stride+j] = 0 } } for i := ihi + 1; i < n; i++ { for j := 0; j < i; j++ { aCopy.Data[i*aCopy.Stride+j] = 0 } } // Construct Qᵀ * AOrig * Q and check that it is // equal to A from Dgehd2. aq := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aCopy, q, 0, aq) qaq := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, aq, 0, qaq) for i := ilo; i <= ihi; i++ { for j := ilo; j <= ihi; j++ { qaqij := qaq.Data[i*qaq.Stride+j] if j < i-1 { if math.Abs(qaqij) > tol { t.Errorf("%v: Qᵀ*A*Q is not upper Hessenberg, [%v,%v]=%v", prefix, i, j, qaqij) } continue } diff := qaqij - a.Data[i*a.Stride+j] if math.Abs(diff) > tol { t.Errorf("%v: Qᵀ*AOrig*Q and A are not equal, diff at [%v,%v]=%v", prefix, i, j, diff) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgehrd.go000066400000000000000000000125371450372207100230200ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dgehrder interface { Dgehrd(n, ilo, ihi int, a []float64, lda int, tau, work []float64, lwork int) Dorgqr(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) } func DgehrdTest(t *testing.T, impl Dgehrder) { rnd := rand.New(rand.NewSource(1)) // Randomized tests for small matrix sizes that will most likely // use the unblocked algorithm. for _, n := range []int{1, 2, 3, 4, 5, 10, 34} { for _, extra := range []int{0, 13} { for _, optwork := range []bool{true, false} { for cas := 0; cas < 10; cas++ { ilo := rnd.Intn(n) ihi := rnd.Intn(n) if ilo > ihi { ilo, ihi = ihi, ilo } testDgehrd(t, impl, n, ilo, ihi, extra, optwork, rnd) } } } } // These are selected tests for larger matrix sizes to test the blocked // algorithm. Use sizes around several powers of two because that is // where the blocked path will most likely start to be taken. For // example, at present the blocked algorithm is used for sizes larger // than 129. for _, test := range []struct { n, ilo, ihi int }{ {0, 0, -1}, {68, 0, 63}, {68, 0, 64}, {68, 0, 65}, {68, 0, 66}, {68, 0, 67}, {132, 2, 129}, {132, 1, 129}, // Size = 129, unblocked. {132, 0, 129}, // Size = 130, blocked. {132, 1, 130}, {132, 0, 130}, {132, 1, 131}, {132, 0, 131}, {260, 2, 257}, {260, 1, 257}, {260, 0, 257}, {260, 0, 258}, {260, 0, 259}, } { for _, extra := range []int{0, 13} { for _, optwork := range []bool{true, false} { testDgehrd(t, impl, test.n, test.ilo, test.ihi, extra, optwork, rnd) } } } } func testDgehrd(t *testing.T, impl Dgehrder, n, ilo, ihi, extra int, optwork bool, rnd *rand.Rand) { const tol = 1e-13 a := randomGeneral(n, n, n+extra, rnd) aCopy := a aCopy.Data = make([]float64, len(a.Data)) copy(aCopy.Data, a.Data) var tau []float64 if n > 1 { tau = nanSlice(n - 1) } var work []float64 if optwork { work = nanSlice(1) impl.Dgehrd(n, ilo, ihi, a.Data, a.Stride, tau, work, -1) work = nanSlice(int(work[0])) } else { work = nanSlice(max(1, n)) } impl.Dgehrd(n, ilo, ihi, a.Data, a.Stride, tau, work, len(work)) if n == 0 { // Just make sure there is no panic. return } prefix := fmt.Sprintf("Case n=%v, ilo=%v, ihi=%v, extra=%v", n, ilo, ihi, extra) // Check any invalid modifications of a. if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A\n%v", prefix, a.Data) } for i := ilo; i <= ihi; i++ { for j := 0; j < min(ilo, i); j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification of A[%v,%v]", prefix, i, j) } } } for i := ihi + 1; i < n; i++ { for j := 0; j < i; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification of A[%v,%v]", prefix, i, j) } } } for i := 0; i <= ilo; i++ { for j := i; j < ilo+1; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification at A[%v,%v]", prefix, i, j) } } for j := ihi + 1; j < n; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification at A[%v,%v]", prefix, i, j) } } } for i := ihi + 1; i < n; i++ { for j := i; j < n; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected modification at A[%v,%v]", prefix, i, j) } } } // Check that tau has been assigned properly. for i, v := range tau { if math.IsNaN(v) { t.Errorf("%v: unexpected NaN at tau[%v]", prefix, i) } } // Extract Q and check that it is orthogonal. q := eye(n, n) if ilo != ihi { for i := ilo + 2; i <= ihi; i++ { for j := ilo + 1; j < ihi; j++ { q.Data[i*q.Stride+j] = a.Data[i*a.Stride+j-1] } } nh := ihi - ilo impl.Dorgqr(nh, nh, nh, q.Data[(ilo+1)*q.Stride+ilo+1:], q.Stride, tau[ilo:ihi], work, len(work)) } if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("%v: Q is not orthogonal; resid=%v, want<=%v", prefix, resid, tol) } // Construct Qᵀ * AOrig * Q and check that it is upper Hessenberg. aq := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aCopy, q, 0, aq) qaq := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, aq, 0, qaq) for i := 0; i <= ilo; i++ { for j := ilo + 1; j <= ihi; j++ { qaqij := qaq.Data[i*qaq.Stride+j] diff := qaqij - a.Data[i*a.Stride+j] if math.Abs(diff) > tol { t.Errorf("%v: Qᵀ*AOrig*Q and A are not equal, diff at [%v,%v]=%v", prefix, i, j, diff) } } } for i := ilo + 1; i <= ihi; i++ { for j := ilo; j < n; j++ { qaqij := qaq.Data[i*qaq.Stride+j] if j < i-1 { if math.Abs(qaqij) > tol { t.Errorf("%v: Qᵀ*AOrig*Q is not upper Hessenberg, [%v,%v]=%v", prefix, i, j, qaqij) } continue } diff := qaqij - a.Data[i*a.Stride+j] if math.Abs(diff) > tol { t.Errorf("%v: Qᵀ*AOrig*Q and A are not equal, diff at [%v,%v]=%v", prefix, i, j, diff) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgelq2.go000066400000000000000000000040021450372207100227250ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dgelq2er interface { Dgelq2(m, n int, a []float64, lda int, tau, work []float64) } func Dgelq2Test(t *testing.T, impl Dgelq2er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for c, test := range []struct { m, n, lda int }{ {1, 1, 0}, {2, 2, 0}, {3, 2, 0}, {2, 3, 0}, {1, 12, 0}, {2, 6, 0}, {3, 4, 0}, {4, 3, 0}, {6, 2, 0}, {1, 12, 0}, {1, 1, 20}, {2, 2, 20}, {3, 2, 20}, {2, 3, 20}, {1, 12, 20}, {2, 6, 20}, {3, 4, 20}, {4, 3, 20}, {6, 2, 20}, {1, 12, 20}, } { n := test.n m := test.m lda := test.lda if lda == 0 { lda = test.n } k := min(m, n) tau := make([]float64, k) for i := range tau { tau[i] = rnd.Float64() } work := make([]float64, m) for i := range work { work[i] = rnd.Float64() } a := make([]float64, m*lda) for i := 0; i < m*lda; i++ { a[i] = rnd.Float64() } aCopy := make([]float64, len(a)) copy(aCopy, a) impl.Dgelq2(m, n, a, lda, tau, work) Q := constructQ("LQ", m, n, a, lda, tau) // Check that Q is orthogonal. if resid := residualOrthogonal(Q, false); resid > tol { t.Errorf("Case %v: Q not orthogonal; resid=%v, want<=%v", c, resid, tol) } L := blas64.General{ Rows: m, Cols: n, Stride: n, Data: make([]float64, m*n), } for i := 0; i < m; i++ { for j := 0; j <= min(i, n-1); j++ { L.Data[i*L.Stride+j] = a[i*lda+j] } } ans := blas64.General{ Rows: m, Cols: n, Stride: lda, Data: make([]float64, m*lda), } copy(ans.Data, aCopy) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, L, Q, 0, ans) if !floats.EqualApprox(aCopy, ans.Data, tol) { t.Errorf("Case %v, LQ mismatch. Want %v, got %v.", c, aCopy, ans.Data) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgelqf.go000066400000000000000000000043411450372207100230170ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dgelqfer interface { Dgelq2er Dgelqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) } func DgelqfTest(t *testing.T, impl Dgelqfer) { const tol = 1e-12 rnd := rand.New(rand.NewSource(1)) for c, test := range []struct { m, n, lda int }{ {10, 5, 0}, {5, 10, 0}, {10, 10, 0}, {300, 5, 0}, {3, 500, 0}, {200, 200, 0}, {300, 200, 0}, {204, 300, 0}, {1, 3000, 0}, {3000, 1, 0}, {10, 5, 30}, {5, 10, 30}, {10, 10, 30}, {300, 5, 500}, {3, 500, 600}, {200, 200, 300}, {300, 200, 300}, {204, 300, 400}, {1, 3000, 4000}, {3000, 1, 4000}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate m×n matrix A and fill it with random numbers. a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } // Store a copy of A for later comparison. aCopy := make([]float64, len(a)) copy(aCopy, a) // Allocate a slice for scalar factors of elementary reflectors // and fill it with random numbers. tau := make([]float64, n) for i := 0; i < n; i++ { tau[i] = rnd.NormFloat64() } // Compute the expected result using unblocked LQ algorithm and // store it want. want := make([]float64, len(a)) copy(want, a) impl.Dgelq2(m, n, want, lda, tau, make([]float64, m)) for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { copy(a, aCopy) var lwork int switch wl { case minimumWork: lwork = m case mediumWork: work := make([]float64, 1) impl.Dgelqf(m, n, a, lda, tau, work, -1) lwork = int(work[0]) - 2*m case optimumWork: work := make([]float64, 1) impl.Dgelqf(m, n, a, lda, tau, work, -1) lwork = int(work[0]) } work := make([]float64, lwork) // Compute the LQ factorization of A. impl.Dgelqf(m, n, a, lda, tau, work, len(work)) // Compare the result with Dgelq2. if !floats.EqualApprox(want, a, tol) { t.Errorf("Case %v, workspace type %v, unexpected result", c, wl) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgels.go000066400000000000000000000103571450372207100226570ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dgelser interface { Dgels(trans blas.Transpose, m, n, nrhs int, a []float64, lda int, b []float64, ldb int, work []float64, lwork int) bool } func DgelsTest(t *testing.T, impl Dgelser) { rnd := rand.New(rand.NewSource(1)) for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, test := range []struct { m, n, nrhs, lda, ldb int }{ {3, 4, 5, 0, 0}, {3, 5, 4, 0, 0}, {4, 3, 5, 0, 0}, {4, 5, 3, 0, 0}, {5, 3, 4, 0, 0}, {5, 4, 3, 0, 0}, {3, 4, 5, 10, 20}, {3, 5, 4, 10, 20}, {4, 3, 5, 10, 20}, {4, 5, 3, 10, 20}, {5, 3, 4, 10, 20}, {5, 4, 3, 10, 20}, {3, 4, 5, 20, 10}, {3, 5, 4, 20, 10}, {4, 3, 5, 20, 10}, {4, 5, 3, 20, 10}, {5, 3, 4, 20, 10}, {5, 4, 3, 20, 10}, {200, 300, 400, 0, 0}, {200, 400, 300, 0, 0}, {300, 200, 400, 0, 0}, {300, 400, 200, 0, 0}, {400, 200, 300, 0, 0}, {400, 300, 200, 0, 0}, {200, 300, 400, 500, 600}, {200, 400, 300, 500, 600}, {300, 200, 400, 500, 600}, {300, 400, 200, 500, 600}, {400, 200, 300, 500, 600}, {400, 300, 200, 500, 600}, {200, 300, 400, 600, 500}, {200, 400, 300, 600, 500}, {300, 200, 400, 600, 500}, {300, 400, 200, 600, 500}, {400, 200, 300, 600, 500}, {400, 300, 200, 600, 500}, } { m := test.m n := test.n nrhs := test.nrhs lda := test.lda if lda == 0 { lda = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() } aCopy := make([]float64, len(a)) copy(aCopy, a) // Size of b is the same trans or no trans, because the number of rows // has to be the max of (m,n). mb := max(m, n) nb := nrhs ldb := test.ldb if ldb == 0 { ldb = nb } b := make([]float64, mb*ldb) for i := range b { b[i] = rnd.Float64() } bCopy := make([]float64, len(b)) copy(bCopy, b) // Find optimal work length. work := make([]float64, 1) impl.Dgels(trans, m, n, nrhs, a, lda, b, ldb, work, -1) // Perform linear solve work = make([]float64, int(work[0])) lwork := len(work) for i := range work { work[i] = rnd.Float64() } impl.Dgels(trans, m, n, nrhs, a, lda, b, ldb, work, lwork) // Check that the answer is correct by comparing to the normal equations. aMat := blas64.General{ Rows: m, Cols: n, Stride: lda, Data: make([]float64, len(aCopy)), } copy(aMat.Data, aCopy) szAta := n if trans == blas.Trans { szAta = m } aTA := blas64.General{ Rows: szAta, Cols: szAta, Stride: szAta, Data: make([]float64, szAta*szAta), } // Compute Aᵀ * A if notrans and A * Aᵀ otherwise. if trans == blas.NoTrans { blas64.Gemm(blas.Trans, blas.NoTrans, 1, aMat, aMat, 0, aTA) } else { blas64.Gemm(blas.NoTrans, blas.Trans, 1, aMat, aMat, 0, aTA) } // Multiply by X. X := blas64.General{ Rows: szAta, Cols: nrhs, Stride: ldb, Data: b, } ans := blas64.General{ Rows: aTA.Rows, Cols: X.Cols, Stride: X.Cols, Data: make([]float64, aTA.Rows*X.Cols), } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aTA, X, 0, ans) B := blas64.General{ Rows: szAta, Cols: nrhs, Stride: ldb, Data: make([]float64, len(bCopy)), } copy(B.Data, bCopy) var ans2 blas64.General if trans == blas.NoTrans { ans2 = blas64.General{ Rows: aMat.Cols, Cols: B.Cols, Stride: B.Cols, Data: make([]float64, aMat.Cols*B.Cols), } } else { ans2 = blas64.General{ Rows: aMat.Rows, Cols: B.Cols, Stride: B.Cols, Data: make([]float64, aMat.Rows*B.Cols), } } // Compute Aᵀ B if Trans or A * B otherwise if trans == blas.NoTrans { blas64.Gemm(blas.Trans, blas.NoTrans, 1, aMat, B, 0, ans2) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aMat, B, 0, ans2) } if !floats.EqualApprox(ans.Data, ans2.Data, 1e-12) { t.Errorf("Normal equations not satisfied") } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgeql2.go000066400000000000000000000045331450372207100227360ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dgeql2er interface { Dgeql2(m, n int, a []float64, lda int, tau, work []float64) } func Dgeql2Test(t *testing.T, impl Dgeql2er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) // TODO(btracey): Add tests for m < n. for _, test := range []struct { m, n, lda int }{ {5, 5, 0}, {5, 3, 0}, {5, 4, 0}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } tau := nanSlice(min(m, n)) work := nanSlice(n) aCopy := make([]float64, len(a)) copy(aCopy, a) impl.Dgeql2(m, n, a, lda, tau, work) k := min(m, n) // Construct Q. q := blas64.General{ Rows: m, Cols: m, Stride: m, Data: make([]float64, m*m), } for i := 0; i < m; i++ { q.Data[i*q.Stride+i] = 1 } for i := 0; i < k; i++ { h := blas64.General{Rows: m, Cols: m, Stride: m, Data: make([]float64, m*m)} for j := 0; j < m; j++ { h.Data[j*h.Stride+j] = 1 } v := blas64.Vector{Inc: 1, Data: make([]float64, m)} v.Data[m-k+i] = 1 for j := 0; j < m-k+i; j++ { v.Data[j] = a[j*lda+n-k+i] } blas64.Ger(-tau[i], v, v, h) qTmp := blas64.General{Rows: q.Rows, Cols: q.Cols, Stride: q.Stride, Data: make([]float64, len(q.Data))} copy(qTmp.Data, q.Data) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, qTmp, 0, q) } if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Q is not orthogonal; resid=%v, want<=%v", resid, tol) } l := blas64.General{ Rows: m, Cols: n, Stride: n, Data: make([]float64, m*n), } if m >= n { for i := m - n; i < m; i++ { for j := 0; j <= min(i-(m-n), n-1); j++ { l.Data[i*l.Stride+j] = a[i*lda+j] } } } else { panic("untested") } ans := blas64.General{Rows: m, Cols: n, Stride: lda, Data: make([]float64, len(a))} copy(ans.Data, a) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, l, 0, ans) if !floats.EqualApprox(ans.Data, aCopy, tol) { t.Errorf("Reconstruction mismatch: m = %v, n = %v", m, n) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgeqp3.go000066400000000000000000000063171450372207100227450ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgeqp3er interface { Dlapmter Dgeqp3(m, n int, a []float64, lda int, jpvt []int, tau, work []float64, lwork int) } func Dgeqp3Test(t *testing.T, impl Dgeqp3er) { rnd := rand.New(rand.NewSource(1)) for _, m := range []int{0, 1, 2, 3, 4, 5, 12, 23, 129} { for _, n := range []int{0, 1, 2, 3, 4, 5, 12, 23, 129} { for _, lda := range []int{max(1, n), n + 3} { dgeqp3Test(t, impl, rnd, m, n, lda) } } } } func dgeqp3Test(t *testing.T, impl Dgeqp3er, rnd *rand.Rand, m, n, lda int) { const ( tol = 1e-14 all = iota some none ) for _, free := range []int{all, some, none} { name := fmt.Sprintf("m=%d,n=%d,lda=%d,", m, n, lda) // Allocate m×n matrix A and fill it with random numbers. a := randomGeneral(m, n, lda, rnd) // Store a copy of A for later comparison. aCopy := cloneGeneral(a) // Allocate a slice of column pivots. jpvt := make([]int, n) for j := range jpvt { switch free { case all: // All columns are free. jpvt[j] = -1 name += "free=all" case some: // Some columns are free, some are leading columns. jpvt[j] = rnd.Intn(2) - 1 // -1 or 0 name += "free=some" case none: // All columns are leading. jpvt[j] = 0 name += "free=none" default: panic("bad freedom") } } // Allocate a slice for scalar factors of elementary // reflectors and fill it with random numbers. Dgeqp3 // will overwrite them with valid data. k := min(m, n) tau := make([]float64, k) for i := range tau { tau[i] = rnd.Float64() } // Get optimal workspace size for Dgeqp3. work := make([]float64, 1) impl.Dgeqp3(m, n, a.Data, a.Stride, jpvt, tau, work, -1) lwork := int(work[0]) work = make([]float64, lwork) for i := range work { work[i] = rnd.Float64() } // Compute a QR factorization of A with column pivoting. impl.Dgeqp3(m, n, a.Data, a.Stride, jpvt, tau, work, lwork) // Compute Q based on the elementary reflectors stored in A. q := constructQ("QR", m, n, a.Data, a.Stride, tau) // Check that Q is orthogonal. if resid := residualOrthogonal(q, false); resid > tol*float64(max(m, n)) { t.Errorf("Case %v: Q not orthogonal; resid=%v, want<=%v", name, resid, tol*float64(max(m, n))) } // Copy the upper triangle of A into R. r := zeros(m, n, lda) for i := 0; i < m; i++ { for j := i; j < n; j++ { r.Data[i*r.Stride+j] = a.Data[i*a.Stride+j] } } // Compute Q*R - A*P: // 1. Rearrange the columns of A based on the permutation in jpvt. qrap := cloneGeneral(aCopy) impl.Dlapmt(true, qrap.Rows, qrap.Cols, qrap.Data, qrap.Stride, jpvt) // Compute Q*R - A*P. blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, r, -1, qrap) // Check that |Q*R - A*P| is small. resid := dlange(lapack.MaxColumnSum, qrap.Rows, qrap.Cols, qrap.Data, qrap.Stride) if resid > tol*float64(max(m, n)) { t.Errorf("Case %v: |Q*R - A*P|=%v, want<=%v", name, resid, tol*float64(max(m, n))) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgeqr2.go000066400000000000000000000036141450372207100227430ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgeqr2er interface { Dgeqr2(m, n int, a []float64, lda int, tau []float64, work []float64) } func Dgeqr2Test(t *testing.T, impl Dgeqr2er) { rnd := rand.New(rand.NewSource(1)) for _, m := range []int{0, 1, 2, 3, 4, 5, 6, 12, 23} { for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 12, 23} { for _, lda := range []int{max(1, n), n + 4} { dgeqr2Test(t, impl, rnd, m, n, lda) } } } } func dgeqr2Test(t *testing.T, impl Dgeqr2er, rnd *rand.Rand, m, n, lda int) { const tol = 1e-14 name := fmt.Sprintf("m=%d,n=%d,lda=%d", m, n, lda) a := randomGeneral(m, n, lda, rnd) aCopy := cloneGeneral(a) k := min(m, n) tau := make([]float64, k) for i := range tau { tau[i] = rnd.Float64() } work := make([]float64, n) for i := range work { work[i] = rnd.Float64() } impl.Dgeqr2(m, n, a.Data, a.Stride, tau, work) // Test that the QR factorization has completed successfully. Compute // Q based on the vectors. q := constructQ("QR", m, n, a.Data, a.Stride, tau) // Check that Q is orthogonal. if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case %v: Q not orthogonal; resid=%v, want<=%v", name, resid, tol) } // Check that |Q*R - A| is small. r := zeros(m, n, n) for i := 0; i < m; i++ { for j := i; j < n; j++ { r.Data[i*r.Stride+j] = a.Data[i*a.Stride+j] } } qra := cloneGeneral(aCopy) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, r, -1, qra) resid := dlange(lapack.MaxColumnSum, qra.Rows, qra.Cols, qra.Data, qra.Stride) if resid > tol*float64(m) { t.Errorf("Case %v: |Q*R - A|=%v, want<=%v", name, resid, tol*float64(m)) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgeqrf.go000066400000000000000000000043421450372207100230260ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dgeqrfer interface { Dgeqr2er Dgeqrf(m, n int, a []float64, lda int, tau, work []float64, lwork int) } func DgeqrfTest(t *testing.T, impl Dgeqrfer) { const tol = 1e-12 rnd := rand.New(rand.NewSource(1)) for c, test := range []struct { m, n, lda int }{ {10, 5, 0}, {5, 10, 0}, {10, 10, 0}, {300, 5, 0}, {3, 500, 0}, {200, 200, 0}, {300, 200, 0}, {204, 300, 0}, {1, 3000, 0}, {3000, 1, 0}, {10, 5, 20}, {5, 10, 20}, {10, 10, 20}, {300, 5, 400}, {3, 500, 600}, {200, 200, 300}, {300, 200, 300}, {204, 300, 400}, {1, 3000, 4000}, {3000, 1, 4000}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = test.n } // Allocate m×n matrix A and fill it with random numbers. a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } // Store a copy of A for later comparison. aCopy := make([]float64, len(a)) copy(aCopy, a) // Allocate a slice for scalar factors of elementary reflectors // and fill it with random numbers. tau := make([]float64, n) for i := 0; i < n; i++ { tau[i] = rnd.Float64() } // Compute the expected result using unblocked QR algorithm and // store it in want. want := make([]float64, len(a)) copy(want, a) impl.Dgeqr2(m, n, want, lda, tau, make([]float64, n)) for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { copy(a, aCopy) var lwork int switch wl { case minimumWork: lwork = n case mediumWork: work := make([]float64, 1) impl.Dgeqrf(m, n, a, lda, tau, work, -1) lwork = int(work[0]) - 2*n case optimumWork: work := make([]float64, 1) impl.Dgeqrf(m, n, a, lda, tau, work, -1) lwork = int(work[0]) } work := make([]float64, lwork) // Compute the QR factorization of A. impl.Dgeqrf(m, n, a, lda, tau, work, len(work)) // Compare the result with Dgeqr2. if !floats.EqualApprox(want, a, tol) { t.Errorf("Case %v, workspace %v, unexpected result.", c, wl) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgerq2.go000066400000000000000000000036471450372207100227510ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgerq2er interface { Dgerq2(m, n int, a []float64, lda int, tau []float64, work []float64) } func Dgerq2Test(t *testing.T, impl Dgerq2er) { rnd := rand.New(rand.NewSource(1)) for _, m := range []int{0, 1, 2, 3, 4, 5, 6, 12, 23} { for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 12, 23} { for _, lda := range []int{max(1, n), n + 4} { dgerq2Test(t, impl, rnd, m, n, lda) } } } } func dgerq2Test(t *testing.T, impl Dgerq2er, rnd *rand.Rand, m, n, lda int) { const tol = 1e-14 name := fmt.Sprintf("m=%d,n=%d,lda=%d", m, n, lda) a := randomGeneral(m, n, lda, rnd) aCopy := cloneGeneral(a) k := min(m, n) tau := make([]float64, k) for i := range tau { tau[i] = rnd.Float64() } work := make([]float64, m) for i := range work { work[i] = rnd.Float64() } impl.Dgerq2(m, n, a.Data, a.Stride, tau, work) // Test that the RQ factorization has completed successfully. Compute // Q based on the vectors. q := constructQ("RQ", m, n, a.Data, a.Stride, tau) // Check that Q is orthogonal. if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case %v: Q not orthogonal; resid=%v, want<=%v", name, resid, tol) } // Check that |R*Q - A| is small. r := zeros(m, n, n) for i := 0; i < m; i++ { off := m - n for j := max(0, i-off); j < n; j++ { r.Data[i*r.Stride+j] = a.Data[i*a.Stride+j] } } qra := cloneGeneral(aCopy) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, r, q, -1, qra) resid := dlange(lapack.MaxColumnSum, qra.Rows, qra.Cols, qra.Data, qra.Stride) if resid > tol*float64(m) { t.Errorf("Case %v: |R*Q - A|=%v, want<=%v", name, resid, tol*float64(m)) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgerqf.go000066400000000000000000000045051450372207100230270ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgerqfer interface { Dgerqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) } func DgerqfTest(t *testing.T, impl Dgerqfer) { rnd := rand.New(rand.NewSource(1)) for _, m := range []int{0, 1, 2, 3, 4, 5, 6, 12, 129, 160} { for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 12, 129, 160} { for _, lda := range []int{max(1, n), n + 4} { dgerqfTest(t, impl, rnd, m, n, lda) } } } } func dgerqfTest(t *testing.T, impl Dgerqfer, rnd *rand.Rand, m, n, lda int) { const tol = 1e-14 a := randomGeneral(m, n, lda, rnd) aCopy := cloneGeneral(a) k := min(m, n) tau := make([]float64, k) for i := range tau { tau[i] = rnd.Float64() } work := []float64{0} impl.Dgerqf(m, n, a.Data, a.Stride, tau, work, -1) lwkopt := int(work[0]) for _, wk := range []struct { name string length int }{ {name: "short", length: m}, {name: "medium", length: lwkopt - 1}, {name: "long", length: lwkopt}, } { name := fmt.Sprintf("m=%d,n=%d,lda=%d,work=%v", m, n, lda, wk.name) lwork := max(max(1, m), wk.length) work = make([]float64, lwork) for i := range work { work[i] = rnd.Float64() } copyGeneral(a, aCopy) impl.Dgerqf(m, n, a.Data, a.Stride, tau, work, lwork) // Test that the RQ factorization has completed successfully. Compute // Q based on the vectors. q := constructQ("RQ", m, n, a.Data, a.Stride, tau) // Check that Q is orthogonal. if resid := residualOrthogonal(q, false); resid > tol*float64(m) { t.Errorf("Case %v: Q not orthogonal; resid=%v, want<=%v", name, resid, tol*float64(m)) } // Check that A = R * Q r := zeros(m, n, n) for i := 0; i < m; i++ { off := m - n for j := max(0, i-off); j < n; j++ { r.Data[i*r.Stride+j] = a.Data[i*a.Stride+j] } } qra := cloneGeneral(aCopy) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, r, q, -1, qra) resid := dlange(lapack.MaxColumnSum, qra.Rows, qra.Cols, qra.Data, qra.Stride) if resid > tol*float64(m) { t.Errorf("Case %v: |R*Q - A|=%v, want<=%v", name, resid, tol*float64(m)) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgesc2.go000066400000000000000000000051501450372207100227230ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dgesc2er interface { Dgesc2(n int, a []float64, lda int, rhs []float64, ipiv, jpiv []int) (scale float64) Dgetc2er } func Dgesc2Test(t *testing.T, impl Dgesc2er) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 20, 50} { for _, lda := range []int{n, n + 3} { testDgesc2(t, impl, rnd, n, lda, false) testDgesc2(t, impl, rnd, n, lda, true) } } } func testDgesc2(t *testing.T, impl Dgesc2er, rnd *rand.Rand, n, lda int, big bool) { const tol = 1e-14 name := fmt.Sprintf("n=%v,lda=%v,big=%v", n, lda, big) // Generate random general matrix. a := randomGeneral(n, n, max(1, lda), rnd) // Generate a random right hand side vector. b := randomGeneral(n, 1, 1, rnd) if big { for i := 0; i < n; i++ { b.Data[i] *= bignum } } // Compute the LU factorization of A with full pivoting. lu := cloneGeneral(a) ipiv := make([]int, n) jpiv := make([]int, n) impl.Dgetc2(n, lu.Data, lu.Stride, ipiv, jpiv) // Make copies of const input to Dgesc2. luCopy := cloneGeneral(lu) ipivCopy := make([]int, len(ipiv)) copy(ipivCopy, ipiv) jpivCopy := make([]int, len(jpiv)) copy(jpivCopy, jpiv) // Call Dgesc2 to solve A*x = scale*b. x := cloneGeneral(b) scale := impl.Dgesc2(n, lu.Data, lu.Stride, x.Data, ipiv, jpiv) if n == 0 { return } // Check that const input to Dgesc2 hasn't been modified. if !floats.Same(lu.Data, luCopy.Data) { t.Errorf("%v: unexpected modification in lu", name) } if !intsEqual(ipiv, ipivCopy) { t.Errorf("%v: unexpected modification in ipiv", name) } if !intsEqual(jpiv, jpivCopy) { t.Errorf("%v: unexpected modification in jpiv", name) } if scale <= 0 || 1 < scale { t.Errorf("%v: scale %v out of bounds (0,1]", name, scale) } if !big && scale != 1 { t.Errorf("%v: unexpected scaling, scale=%v", name, scale) } // Compute the difference rhs := A*x - scale*b. diff := b for i := 0; i < n; i++ { diff.Data[i] *= scale } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, a, x, -1, diff) // Compute the residual |A*x - scale*b| / |x|. xnorm := dlange(lapack.MaxColumnSum, n, 1, x.Data, 1) resid := dlange(lapack.MaxColumnSum, n, 1, diff.Data, 1) / xnorm if resid > tol || math.IsNaN(resid) { t.Errorf("%v: unexpected result; resid=%v, want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgesv.go000066400000000000000000000111271450372207100226650ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgesver interface { Dgesv(n, nrhs int, a []float64, lda int, ipiv []int, b []float64, ldb int) bool Dgetri(n int, a []float64, lda int, ipiv []int, work []float64, lwork int) bool } func DgesvTest(t *testing.T, impl Dgesver) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50, 100} { for _, nrhs := range []int{0, 1, 2, 5} { for _, lda := range []int{max(1, n), n + 5} { for _, ldb := range []int{max(1, nrhs), nrhs + 5} { dgesvTest(t, impl, rnd, n, nrhs, lda, ldb) } } } } } func dgesvTest(t *testing.T, impl Dgesver, rnd *rand.Rand, n, nrhs, lda, ldb int) { const tol = 1e-15 name := fmt.Sprintf("n=%v,nrhs=%v,lda=%v,ldb=%v", n, nrhs, lda, ldb) // Create a random system matrix A and the solution X. a := randomGeneral(n, n, lda, rnd) xWant := randomGeneral(n, nrhs, ldb, rnd) // Compute the right hand side matrix B = A*X. b := zeros(n, nrhs, ldb) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, a, xWant, 0, b) // Allocate a slice for row pivots and fill it with invalid indices. ipiv := make([]int, n) for i := range ipiv { ipiv[i] = -1 } // Call Dgesv to solve A*X = B. lu := cloneGeneral(a) xGot := cloneGeneral(b) ok := impl.Dgesv(n, nrhs, lu.Data, lu.Stride, ipiv, xGot.Data, xGot.Stride) if !ok { t.Errorf("%v: unexpected failure in Dgesv", name) return } if n == 0 || nrhs == 0 { return } // Check that all elements of ipiv have been set. ipivSet := true for _, ipv := range ipiv { if ipv == -1 { ipivSet = false break } } if !ipivSet { t.Fatalf("%v: not all elements of ipiv set", name) return } // Compute the reciprocal of the condition number of A from its LU // decomposition before it's overwritten further below. aInv := cloneGeneral(lu) impl.Dgetri(n, aInv.Data, aInv.Stride, ipiv, make([]float64, n), n) ainvnorm := dlange(lapack.MaxColumnSum, n, n, aInv.Data, aInv.Stride) anorm := dlange(lapack.MaxColumnSum, n, n, a.Data, a.Stride) rcond := 1 / anorm / ainvnorm // Reconstruct matrix A from factors and compute residual. // // Extract L and U from lu. l := zeros(n, n, n) u := zeros(n, n, n) for i := 0; i < n; i++ { for j := 0; j < i; j++ { l.Data[i*l.Stride+j] = lu.Data[i*lu.Stride+j] } l.Data[i*l.Stride+i] = 1 for j := i; j < n; j++ { u.Data[i*u.Stride+j] = lu.Data[i*lu.Stride+j] } } // Compute L*U. blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, l, u, 0, lu) // Apply P to L*U. for i := n - 1; i >= 0; i-- { ip := ipiv[i] if ip == i { continue } row1 := blas64.Vector{N: n, Data: lu.Data[i*lu.Stride:], Inc: 1} row2 := blas64.Vector{N: n, Data: lu.Data[ip*lu.Stride:], Inc: 1} blas64.Swap(row1, row2) } // Compute P*L*U - A. for i := 0; i < n; i++ { for j := 0; j < n; j++ { lu.Data[i*lu.Stride+j] -= a.Data[i*a.Stride+j] } } // Compute the residual |P*L*U - A|. resid := dlange(lapack.MaxColumnSum, n, n, lu.Data, lu.Stride) resid /= float64(n) * anorm if resid > tol || math.IsNaN(resid) { t.Errorf("%v: residual |P*L*U - A| is too large, got %v, want <= %v", name, resid, tol) } // Compute residual of the computed solution. // // Compute B - A*X. blas64.Gemm(blas.NoTrans, blas.NoTrans, -1, a, xGot, 1, b) // Compute the maximum over the number of right hand sides of |B - A*X| / (|A| * |X|). resid = 0 for j := 0; j < nrhs; j++ { bnorm := blas64.Asum(blas64.Vector{N: n, Data: b.Data[j:], Inc: b.Stride}) xnorm := blas64.Asum(blas64.Vector{N: n, Data: xGot.Data[j:], Inc: xGot.Stride}) resid = math.Max(resid, bnorm/anorm/xnorm) } if resid > tol || math.IsNaN(resid) { t.Errorf("%v: residual |B - A*X| is too large, got %v, want <= %v", name, resid, tol) } // Compare the computed solution with the generated exact solution. // // Compute X - XWANT. for i := 0; i < n; i++ { for j := 0; j < nrhs; j++ { xGot.Data[i*xGot.Stride+j] -= xWant.Data[i*xWant.Stride+j] } } // Compute the maximum of |X - XWANT|/|XWANT| over all the vectors X and XWANT. resid = 0 for j := 0; j < nrhs; j++ { xnorm := dlange(lapack.MaxAbs, n, 1, xWant.Data[j:], xWant.Stride) diff := dlange(lapack.MaxAbs, n, 1, xGot.Data[j:], xGot.Stride) resid = math.Max(resid, diff/xnorm*rcond) } if resid > tol || math.IsNaN(resid) { t.Errorf("%v: residual |X-XWANT| is too large, got %v, want <= %v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgesvd.go000066400000000000000000000313121450372207100230270ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dgesvder interface { Dgesvd(jobU, jobVT lapack.SVDJob, m, n int, a []float64, lda int, s, u []float64, ldu int, vt []float64, ldvt int, work []float64, lwork int) (ok bool) } func DgesvdTest(t *testing.T, impl Dgesvder, tol float64) { for _, m := range []int{0, 1, 2, 3, 4, 5, 10, 150, 300} { for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 150} { for _, mtype := range []int{1, 2, 3, 4, 5} { dgesvdTest(t, impl, m, n, mtype, tol) } } } } // dgesvdTest tests a Dgesvd implementation on an m×n matrix A generated // according to mtype as: // - the zero matrix if mtype == 1, // - the identity matrix if mtype == 2, // - a random matrix with a given condition number and singular values if mtype == 3, 4, or 5. // // It first computes the full SVD A = U*Sigma*Vᵀ and checks that // - U has orthonormal columns, and Vᵀ has orthonormal rows, // - U*Sigma*Vᵀ multiply back to A, // - the singular values are non-negative and sorted in decreasing order. // // Then all combinations of partial SVD results are computed and checked whether // they match the full SVD result. func dgesvdTest(t *testing.T, impl Dgesvder, m, n, mtype int, tol float64) { const tolOrtho = 1e-15 rnd := rand.New(rand.NewSource(1)) // Use a fixed leading dimension to reduce testing time. lda := n + 3 ldu := m + 5 ldvt := n + 7 minmn := min(m, n) // Allocate A and fill it with random values. The in-range elements will // be overwritten below according to mtype. a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } var aNorm float64 switch mtype { default: panic("unknown test matrix type") case 1: // Zero matrix. for i := 0; i < m; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 } } aNorm = 0 case 2: // Identity matrix. for i := 0; i < m; i++ { for j := 0; j < n; j++ { if i == j { a[i*lda+i] = 1 } else { a[i*lda+j] = 0 } } } aNorm = 1 case 3, 4, 5: // Scaled random matrix. // Generate singular values. s := make([]float64, minmn) Dlatm1(s, 4, // s[i] = 1 - i*(1-1/cond)/(minmn-1) float64(max(1, minmn)), // where cond = max(1,minmn) false, // signs of s[i] are not randomly flipped 1, rnd) // random numbers are drawn uniformly from [0,1) // Decide scale factor for the singular values based on the matrix type. aNorm = 1 if mtype == 4 { aNorm = smlnum } if mtype == 5 { aNorm = bignum } // Scale singular values so that the maximum singular value is // equal to aNorm (we know that the singular values are // generated above to be spread linearly between 1/cond and 1). floats.Scale(aNorm, s) // Generate A by multiplying S by random orthogonal matrices // from left and right. Dlagge(m, n, max(0, m-1), max(0, n-1), s, a, lda, rnd, make([]float64, m+n)) } aCopy := make([]float64, len(a)) copy(aCopy, a) for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { // Restore A because Dgesvd overwrites it. copy(a, aCopy) // Allocate slices that will be used below to store the results of full // SVD and fill them. uAll := make([]float64, m*ldu) for i := range uAll { uAll[i] = rnd.NormFloat64() } vtAll := make([]float64, n*ldvt) for i := range vtAll { vtAll[i] = rnd.NormFloat64() } sAll := make([]float64, min(m, n)) for i := range sAll { sAll[i] = math.NaN() } prefix := fmt.Sprintf("m=%v,n=%v,work=%v,mtype=%v", m, n, wl, mtype) // Determine workspace size based on wl. minwork := max(1, max(5*min(m, n), 3*min(m, n)+max(m, n))) var lwork int switch wl { case minimumWork: lwork = minwork case mediumWork: work := make([]float64, 1) impl.Dgesvd(lapack.SVDAll, lapack.SVDAll, m, n, a, lda, sAll, uAll, ldu, vtAll, ldvt, work, -1) lwork = (int(work[0]) + minwork) / 2 case optimumWork: work := make([]float64, 1) impl.Dgesvd(lapack.SVDAll, lapack.SVDAll, m, n, a, lda, sAll, uAll, ldu, vtAll, ldvt, work, -1) lwork = int(work[0]) } work := make([]float64, max(1, lwork)) for i := range work { work[i] = math.NaN() } // Compute the full SVD which will be used later for checking the partial results. ok := impl.Dgesvd(lapack.SVDAll, lapack.SVDAll, m, n, a, lda, sAll, uAll, ldu, vtAll, ldvt, work, len(work)) if !ok { t.Fatalf("Case %v: unexpected failure in full SVD", prefix) } // Check that uAll, sAll, and vtAll multiply back to A by computing a residual // |A - U*S*VT| / (n*aNorm) if resid := svdFullResidual(m, n, aNorm, aCopy, lda, uAll, ldu, sAll, vtAll, ldvt); resid > tol { t.Errorf("Case %v: original matrix not recovered for full SVD, |A - U*D*VT|=%v", prefix, resid) } if minmn > 0 { // Check that uAll is orthogonal. q := blas64.General{Rows: m, Cols: m, Data: uAll, Stride: ldu} if resid := residualOrthogonal(q, false); resid > tolOrtho*float64(m) { t.Errorf("Case %v: UAll is not orthogonal; resid=%v, want<=%v", prefix, resid, tolOrtho*float64(m)) } // Check that vtAll is orthogonal. q = blas64.General{Rows: n, Cols: n, Data: vtAll, Stride: ldvt} if resid := residualOrthogonal(q, false); resid > tolOrtho*float64(n) { t.Errorf("Case %v: VTAll is not orthogonal; resid=%v, want<=%v", prefix, resid, tolOrtho*float64(n)) } } // Check that singular values are decreasing. if !sort.IsSorted(sort.Reverse(sort.Float64Slice(sAll))) { t.Errorf("Case %v: singular values from full SVD are not decreasing", prefix) } // Check that singular values are non-negative. if minmn > 0 && floats.Min(sAll) < 0 { t.Errorf("Case %v: some singular values from full SVD are negative", prefix) } // Do partial SVD and compare the results to sAll, uAll, and vtAll. for _, jobU := range []lapack.SVDJob{lapack.SVDAll, lapack.SVDStore, lapack.SVDOverwrite, lapack.SVDNone} { for _, jobVT := range []lapack.SVDJob{lapack.SVDAll, lapack.SVDStore, lapack.SVDOverwrite, lapack.SVDNone} { if jobU == lapack.SVDOverwrite || jobVT == lapack.SVDOverwrite { // Not implemented. continue } if jobU == lapack.SVDAll && jobVT == lapack.SVDAll { // Already checked above. continue } prefix := prefix + ",job=" + svdJobString(jobU) + "U-" + svdJobString(jobVT) + "VT" // Restore A to its original values. copy(a, aCopy) // Allocate slices for the results of partial SVD and fill them. u := make([]float64, m*ldu) for i := range u { u[i] = rnd.NormFloat64() } vt := make([]float64, n*ldvt) for i := range vt { vt[i] = rnd.NormFloat64() } s := make([]float64, min(m, n)) for i := range s { s[i] = math.NaN() } for i := range work { work[i] = math.NaN() } ok := impl.Dgesvd(jobU, jobVT, m, n, a, lda, s, u, ldu, vt, ldvt, work, len(work)) if !ok { t.Fatalf("Case %v: unexpected failure in partial Dgesvd", prefix) } if minmn == 0 { // No panic and the result is ok, there is // nothing else to check. continue } // Check that U has orthogonal columns and that it matches UAll. switch jobU { case lapack.SVDStore: q := blas64.General{Rows: m, Cols: minmn, Data: u, Stride: ldu} if resid := residualOrthogonal(q, false); resid > tolOrtho*float64(m) { t.Errorf("Case %v: columns of U are not orthogonal; resid=%v, want<=%v", prefix, resid, tolOrtho*float64(m)) } if res := svdPartialUResidual(m, minmn, u, uAll, ldu); res > tol { t.Errorf("Case %v: columns of U do not match UAll", prefix) } case lapack.SVDAll: q := blas64.General{Rows: m, Cols: m, Data: u, Stride: ldu} if resid := residualOrthogonal(q, false); resid > tolOrtho*float64(m) { t.Errorf("Case %v: columns of U are not orthogonal; resid=%v, want<=%v", prefix, resid, tolOrtho*float64(m)) } if res := svdPartialUResidual(m, m, u, uAll, ldu); res > tol { t.Errorf("Case %v: columns of U do not match UAll", prefix) } } // Check that VT has orthogonal rows and that it matches VTAll. switch jobVT { case lapack.SVDStore: q := blas64.General{Rows: minmn, Cols: n, Data: vtAll, Stride: ldvt} if resid := residualOrthogonal(q, true); resid > tolOrtho*float64(n) { t.Errorf("Case %v: rows of VT are not orthogonal; resid=%v, want<=%v", prefix, resid, tolOrtho*float64(n)) } if res := svdPartialVTResidual(minmn, n, vt, vtAll, ldvt); res > tol { t.Errorf("Case %v: rows of VT do not match VTAll", prefix) } case lapack.SVDAll: q := blas64.General{Rows: n, Cols: n, Data: vtAll, Stride: ldvt} if resid := residualOrthogonal(q, true); resid > tolOrtho*float64(n) { t.Errorf("Case %v: rows of VT are not orthogonal; resid=%v, want<=%v", prefix, resid, tolOrtho*float64(n)) } if res := svdPartialVTResidual(n, n, vt, vtAll, ldvt); res > tol { t.Errorf("Case %v: rows of VT do not match VTAll", prefix) } } // Check that singular values are decreasing. if !sort.IsSorted(sort.Reverse(sort.Float64Slice(s))) { t.Errorf("Case %v: singular values from full SVD are not decreasing", prefix) } // Check that singular values are non-negative. if floats.Min(s) < 0 { t.Errorf("Case %v: some singular values from full SVD are negative", prefix) } if !floats.EqualApprox(s, sAll, tol/10) { t.Errorf("Case %v: singular values differ between full and partial SVD\n%v\n%v", prefix, s, sAll) } } } } } // svdFullResidual returns // // |A - U*D*VT| / (n * aNorm) // // where U, D, and VT are as computed by Dgesvd with jobU = jobVT = lapack.SVDAll. func svdFullResidual(m, n int, aNorm float64, a []float64, lda int, u []float64, ldu int, d []float64, vt []float64, ldvt int) float64 { // The implementation follows TESTING/dbdt01.f from the reference. minmn := min(m, n) if minmn == 0 { return 0 } // j-th column of A - U*D*VT. aMinusUDVT := make([]float64, m) // D times the j-th column of VT. dvt := make([]float64, minmn) // Compute the residual |A - U*D*VT| one column at a time. var resid float64 for j := 0; j < n; j++ { // Copy j-th column of A to aj. blas64.Copy(blas64.Vector{N: m, Data: a[j:], Inc: lda}, blas64.Vector{N: m, Data: aMinusUDVT, Inc: 1}) // Multiply D times j-th column of VT. for i := 0; i < minmn; i++ { dvt[i] = d[i] * vt[i*ldvt+j] } // Compute the j-th column of A - U*D*VT. blas64.Gemv(blas.NoTrans, -1, blas64.General{Rows: m, Cols: minmn, Data: u, Stride: ldu}, blas64.Vector{N: minmn, Data: dvt, Inc: 1}, 1, blas64.Vector{N: m, Data: aMinusUDVT, Inc: 1}) resid = math.Max(resid, blas64.Asum(blas64.Vector{N: m, Data: aMinusUDVT, Inc: 1})) } if aNorm == 0 { if resid != 0 { // Original matrix A is zero but the residual is non-zero, // return infinity. return math.Inf(1) } // Original matrix A is zero, residual is zero, return 0. return 0 } // Original matrix A is non-zero. if aNorm >= resid { resid = resid / aNorm / float64(n) } else { if aNorm < 1 { resid = math.Min(resid, float64(n)*aNorm) / aNorm / float64(n) } else { resid = math.Min(resid/aNorm, float64(n)) / float64(n) } } return resid } // svdPartialUResidual compares U and URef to see if their columns span the same // spaces. It returns the maximum over columns of // // |URef(i) - S*U(i)| // // where URef(i) and U(i) are the i-th columns of URef and U, respectively, and // S is ±1 chosen to minimize the expression. func svdPartialUResidual(m, n int, u, uRef []float64, ldu int) float64 { var res float64 for j := 0; j < n; j++ { imax := blas64.Iamax(blas64.Vector{N: m, Data: uRef[j:], Inc: ldu}) s := math.Copysign(1, uRef[imax*ldu+j]) * math.Copysign(1, u[imax*ldu+j]) for i := 0; i < m; i++ { diff := math.Abs(uRef[i*ldu+j] - s*u[i*ldu+j]) res = math.Max(res, diff) } } return res } // svdPartialVTResidual compares VT and VTRef to see if their rows span the same // spaces. It returns the maximum over rows of // // |VTRef(i) - S*VT(i)| // // where VTRef(i) and VT(i) are the i-th columns of VTRef and VT, respectively, and // S is ±1 chosen to minimize the expression. func svdPartialVTResidual(m, n int, vt, vtRef []float64, ldvt int) float64 { var res float64 for i := 0; i < m; i++ { jmax := blas64.Iamax(blas64.Vector{N: n, Data: vtRef[i*ldvt:], Inc: 1}) s := math.Copysign(1, vtRef[i*ldvt+jmax]) * math.Copysign(1, vt[i*ldvt+jmax]) for j := 0; j < n; j++ { diff := math.Abs(vtRef[i*ldvt+j] - s*vt[i*ldvt+j]) res = math.Max(res, diff) } } return res } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgetc2.go000066400000000000000000000065201450372207100227260ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgetc2er interface { Dgetc2(n int, a []float64, lda int, ipiv, jpiv []int) (k int) } func Dgetc2Test(t *testing.T, impl Dgetc2er) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 20} { for _, lda := range []int{n, n + 5} { dgetc2Test(t, impl, rnd, n, lda, false) dgetc2Test(t, impl, rnd, n, lda, true) } } } func dgetc2Test(t *testing.T, impl Dgetc2er, rnd *rand.Rand, n, lda int, perturb bool) { const tol = 1e-14 name := fmt.Sprintf("n=%v,lda=%v,perturb=%v", n, lda, perturb) // Generate a random lower-triangular matrix with unit diagonal. l := randomGeneral(n, n, max(1, n), rnd) for i := 0; i < n; i++ { l.Data[i*l.Stride+i] = 1 for j := i + 1; j < n; j++ { l.Data[i*l.Stride+j] = 0 } } // Generate a random upper-triangular matrix. u := randomGeneral(n, n, max(1, n), rnd) for i := 0; i < n; i++ { for j := 0; j < i; j++ { u.Data[i*u.Stride+j] = 0 } } if perturb && n > 0 { // Make U singular by randomly placing a zero on the diagonal. i := rnd.Intn(n) u.Data[i*u.Stride+i] = 0 } // Construct A = L*U. a := zeros(n, n, max(1, lda)) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, l, u, 0, a) // Allocate slices for pivots and pre-fill them with invalid indices. ipiv := make([]int, n) jpiv := make([]int, n) for i := 0; i < n; i++ { ipiv[i] = -1 jpiv[i] = -1 } // Call Dgetc2 to compute the LU decomposition. lu := cloneGeneral(a) k := impl.Dgetc2(n, lu.Data, lu.Stride, ipiv, jpiv) if n == 0 { return } if perturb && k < 0 { t.Errorf("%v: expected matrix perturbation", name) } // Verify all indices have been set. for i := 0; i < n; i++ { if ipiv[i] < 0 { t.Errorf("%v: ipiv[%d] is not set", name, i) } if jpiv[i] < 0 { t.Errorf("%v: jpiv[%d] is not set", name, i) } } // Construct L and U matrices from Dgetc2 output. l = zeros(n, n, n) u = zeros(n, n, n) for i := 0; i < n; i++ { for j := 0; j < i; j++ { l.Data[i*l.Stride+j] = lu.Data[i*lu.Stride+j] } l.Data[i*l.Stride+i] = 1 for j := i; j < n; j++ { u.Data[i*u.Stride+j] = lu.Data[i*lu.Stride+j] } } diff := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, l, u, 0, diff) // Apply permutation matrices P and Q to L*U. for i := n - 1; i >= 0; i-- { ipv := ipiv[i] if ipv != i { row1 := blas64.Vector{N: n, Data: diff.Data[i*diff.Stride:], Inc: 1} row2 := blas64.Vector{N: n, Data: diff.Data[ipv*diff.Stride:], Inc: 1} blas64.Swap(row1, row2) } jpv := jpiv[i] if jpv != i { col1 := blas64.Vector{N: n, Data: diff.Data[i:], Inc: diff.Stride} col2 := blas64.Vector{N: n, Data: diff.Data[jpv:], Inc: diff.Stride} blas64.Swap(col1, col2) } } // Compute the residual |P*L*U*Q - A| and check that it is small. for i := 0; i < n; i++ { for j := 0; j < n; j++ { diff.Data[i*diff.Stride+j] -= a.Data[i*a.Stride+j] } } resid := dlange(lapack.MaxColumnSum, n, n, diff.Data, diff.Stride) if resid > tol || math.IsNaN(resid) { t.Errorf("%v: unexpected result; resid=%v, want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgetf2.go000066400000000000000000000073451450372207100227370ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dgetf2er interface { Dgetf2(m, n int, a []float64, lda int, ipiv []int) bool } func Dgetf2Test(t *testing.T, impl Dgetf2er) { rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, lda int }{ {10, 10, 0}, {10, 5, 0}, {10, 5, 0}, {10, 10, 20}, {5, 10, 20}, {10, 5, 20}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() } aCopy := make([]float64, len(a)) copy(aCopy, a) mn := min(m, n) ipiv := make([]int, mn) for i := range ipiv { ipiv[i] = rnd.Int() } ok := impl.Dgetf2(m, n, a, lda, ipiv) checkPLU(t, ok, m, n, lda, ipiv, a, aCopy, 1e-14, true) } // Test with singular matrices (random matrices are almost surely non-singular). for _, test := range []struct { m, n, lda int a []float64 }{ { m: 2, n: 2, lda: 2, a: []float64{ 1, 0, 0, 0, }, }, { m: 2, n: 2, lda: 2, a: []float64{ 1, 5, 2, 10, }, }, { m: 3, n: 3, lda: 3, // row 3 = row1 + 2 * row2 a: []float64{ 1, 5, 7, 2, 10, -3, 5, 25, 1, }, }, { m: 3, n: 4, lda: 4, // row 3 = row1 + 2 * row2 a: []float64{ 1, 5, 7, 9, 2, 10, -3, 11, 5, 25, 1, 31, }, }, } { if impl.Dgetf2(test.m, test.n, test.a, test.lda, make([]int, min(test.m, test.n))) { t.Log("Returned ok with singular matrix.") } } } // checkPLU checks that the PLU factorization contained in factorize matches // the original matrix contained in original. func checkPLU(t *testing.T, ok bool, m, n, lda int, ipiv []int, factorized, original []float64, tol float64, print bool) { var hasZeroDiagonal bool for i := 0; i < min(m, n); i++ { if factorized[i*lda+i] == 0 { hasZeroDiagonal = true break } } if hasZeroDiagonal && ok { t.Error("Has a zero diagonal but returned ok") } if !hasZeroDiagonal && !ok { t.Error("Non-zero diagonal but returned !ok") } // Check that the LU decomposition is correct. mn := min(m, n) l := make([]float64, m*mn) ldl := mn u := make([]float64, mn*n) ldu := n for i := 0; i < m; i++ { for j := 0; j < n; j++ { v := factorized[i*lda+j] switch { case i == j: l[i*ldl+i] = 1 u[i*ldu+i] = v case i > j: l[i*ldl+j] = v case i < j: u[i*ldu+j] = v } } } LU := blas64.General{ Rows: m, Cols: n, Stride: n, Data: make([]float64, m*n), } U := blas64.General{ Rows: mn, Cols: n, Stride: ldu, Data: u, } L := blas64.General{ Rows: m, Cols: mn, Stride: ldl, Data: l, } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, L, U, 0, LU) p := make([]float64, m*m) ldp := m for i := 0; i < m; i++ { p[i*ldp+i] = 1 } for i := len(ipiv) - 1; i >= 0; i-- { v := ipiv[i] blas64.Swap(blas64.Vector{N: m, Inc: 1, Data: p[i*ldp:]}, blas64.Vector{N: m, Inc: 1, Data: p[v*ldp:]}) } P := blas64.General{ Rows: m, Cols: m, Stride: m, Data: p, } aComp := blas64.General{ Rows: m, Cols: n, Stride: lda, Data: make([]float64, m*lda), } copy(aComp.Data, factorized) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, P, LU, 0, aComp) if !floats.EqualApprox(aComp.Data, original, tol) { if print { t.Errorf("PLU multiplication does not match original matrix.\nWant: %v\nGot: %v", original, aComp.Data) return } t.Error("PLU multiplication does not match original matrix.") } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgetrf.go000066400000000000000000000025101450372207100230240ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" ) type Dgetrfer interface { Dgetrf(m, n int, a []float64, lda int, ipiv []int) bool } func DgetrfTest(t *testing.T, impl Dgetrfer) { rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, lda int }{ {10, 5, 0}, {5, 10, 0}, {10, 10, 0}, {300, 5, 0}, {3, 500, 0}, {4, 5, 0}, {300, 200, 0}, {204, 300, 0}, {1, 3000, 0}, {3000, 1, 0}, {10, 5, 20}, {5, 10, 20}, {10, 10, 20}, {300, 5, 400}, {3, 500, 600}, {200, 200, 300}, {300, 200, 300}, {204, 300, 400}, {1, 3000, 4000}, {3000, 1, 4000}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() } mn := min(m, n) ipiv := make([]int, mn) for i := range ipiv { ipiv[i] = rnd.Int() } // Cannot compare the outputs of Dgetrf and Dgetf2 because the pivoting may // happen differently. Instead check that the LPQ factorization is correct. aCopy := make([]float64, len(a)) copy(aCopy, a) ok := impl.Dgetrf(m, n, a, lda, ipiv) checkPLU(t, ok, m, n, lda, ipiv, a, aCopy, 1e-10, false) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgetri.go000066400000000000000000000042611450372207100230340ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dgetrier interface { Dgetrfer Dgetri(n int, a []float64, lda int, ipiv []int, work []float64, lwork int) bool } func DgetriTest(t *testing.T, impl Dgetrier) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() for _, test := range []struct { n, lda int }{ {5, 0}, {5, 8}, {45, 0}, {45, 50}, {63, 70}, {64, 70}, {65, 0}, {65, 70}, {66, 70}, {150, 0}, {150, 250}, } { n := test.n lda := test.lda if lda == 0 { lda = n } // Generate a random well conditioned matrix perm := rnd.Perm(n) a := make([]float64, n*lda) for i := 0; i < n; i++ { a[i*lda+perm[i]] = 1 } for i := range a { a[i] += 0.01 * rnd.Float64() } aCopy := make([]float64, len(a)) copy(aCopy, a) ipiv := make([]int, n) // Compute LU decomposition. impl.Dgetrf(n, n, a, lda, ipiv) // Test with various workspace sizes. for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { ainv := make([]float64, len(a)) copy(ainv, a) var lwork int switch wl { case minimumWork: lwork = max(1, n) case mediumWork: work := make([]float64, 1) impl.Dgetri(n, ainv, lda, ipiv, work, -1) lwork = max(int(work[0])-2*n, n) case optimumWork: work := make([]float64, 1) impl.Dgetri(n, ainv, lda, ipiv, work, -1) lwork = int(work[0]) } work := make([]float64, lwork) // Compute inverse. ok := impl.Dgetri(n, ainv, lda, ipiv, work, lwork) if !ok { t.Errorf("Unexpected singular matrix.") } // Check that A(inv) * A = I. ans := make([]float64, len(ainv)) bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, aCopy, lda, ainv, lda, 0, ans, lda) // The tolerance is so high because computing matrix inverses is very unstable. dist := distFromIdentity(n, ans, lda) if dist > tol { t.Errorf("|Inv(A) * A - I|_inf = %v is too large. n = %v, lda = %v", dist, n, lda) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgetrs.go000066400000000000000000000051651450372207100230520ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dgetrser interface { Dgetrfer Dgetrs(trans blas.Transpose, n, nrhs int, a []float64, lda int, ipiv []int, b []float64, ldb int) } func DgetrsTest(t *testing.T, impl Dgetrser) { rnd := rand.New(rand.NewSource(1)) // TODO(btracey): Put more thought into creating more regularized matrices // and what correct tolerances should be. Consider also seeding the random // number in this test to make it more robust to code changes in other // parts of the suite. for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, test := range []struct { n, nrhs, lda, ldb int tol float64 }{ {3, 3, 0, 0, 1e-12}, {3, 5, 0, 0, 1e-12}, {5, 3, 0, 0, 1e-12}, {3, 3, 8, 10, 1e-12}, {3, 5, 8, 10, 1e-12}, {5, 3, 8, 10, 1e-12}, {300, 300, 0, 0, 1e-8}, {300, 500, 0, 0, 1e-8}, {500, 300, 0, 0, 1e-6}, {300, 300, 700, 600, 1e-8}, {300, 500, 700, 600, 1e-8}, {500, 300, 700, 600, 1e-6}, } { n := test.n nrhs := test.nrhs lda := test.lda if lda == 0 { lda = n } ldb := test.ldb if ldb == 0 { ldb = nrhs } a := make([]float64, n*lda) for i := range a { a[i] = rnd.Float64() } b := make([]float64, n*ldb) for i := range b { b[i] = rnd.Float64() } aCopy := make([]float64, len(a)) copy(aCopy, a) bCopy := make([]float64, len(b)) copy(bCopy, b) ipiv := make([]int, n) for i := range ipiv { ipiv[i] = rnd.Int() } // Compute the LU factorization. impl.Dgetrf(n, n, a, lda, ipiv) // Solve the system of equations given the result. impl.Dgetrs(trans, n, nrhs, a, lda, ipiv, b, ldb) // Check that the system of equations holds. A := blas64.General{ Rows: n, Cols: n, Stride: lda, Data: aCopy, } B := blas64.General{ Rows: n, Cols: nrhs, Stride: ldb, Data: bCopy, } X := blas64.General{ Rows: n, Cols: nrhs, Stride: ldb, Data: b, } tmp := blas64.General{ Rows: n, Cols: nrhs, Stride: ldb, Data: make([]float64, n*ldb), } copy(tmp.Data, bCopy) blas64.Gemm(trans, blas.NoTrans, 1, A, X, 0, B) if !floats.EqualApprox(tmp.Data, bCopy, test.tol) { t.Errorf("Linear solve mismatch. trans = %v, n = %v, nrhs = %v, lda = %v, ldb = %v", trans, n, nrhs, lda, ldb) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dggsvd3.go000066400000000000000000000123111450372207100231120ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/lapack" ) type Dggsvd3er interface { Dggsvd3(jobU, jobV, jobQ lapack.GSVDJob, m, n, p int, a []float64, lda int, b []float64, ldb int, alpha, beta, u []float64, ldu int, v []float64, ldv int, q []float64, ldq int, work []float64, lwork int, iwork []int) (k, l int, ok bool) } func Dggsvd3Test(t *testing.T, impl Dggsvd3er) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { m, p, n, lda, ldb, ldu, ldv, ldq int ok bool }{ {m: 3, p: 3, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 10, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 10, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 5, lda: 10, ldb: 10, ldu: 10, ldv: 10, ldq: 10, ok: true}, {m: 5, p: 5, n: 5, lda: 10, ldb: 10, ldu: 10, ldv: 10, ldq: 10, ok: true}, {m: 5, p: 5, n: 10, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20, ok: true}, {m: 5, p: 5, n: 10, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20, ok: true}, {m: 5, p: 5, n: 10, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20, ok: true}, {m: 10, p: 5, n: 5, lda: 10, ldb: 10, ldu: 20, ldv: 10, ldq: 10, ok: true}, {m: 10, p: 5, n: 5, lda: 10, ldb: 10, ldu: 20, ldv: 10, ldq: 10, ok: true}, {m: 10, p: 10, n: 10, lda: 20, ldb: 20, ldu: 20, ldv: 20, ldq: 20, ok: true}, {m: 10, p: 10, n: 10, lda: 20, ldb: 20, ldu: 20, ldv: 20, ldq: 20, ok: true}, } { m := test.m p := test.p n := test.n lda := test.lda if lda == 0 { lda = n } ldb := test.ldb if ldb == 0 { ldb = n } ldu := test.ldu if ldu == 0 { ldu = m } ldv := test.ldv if ldv == 0 { ldv = p } ldq := test.ldq if ldq == 0 { ldq = n } a := randomGeneral(m, n, lda, rnd) aCopy := cloneGeneral(a) b := randomGeneral(p, n, ldb, rnd) bCopy := cloneGeneral(b) alpha := make([]float64, n) beta := make([]float64, n) u := nanGeneral(m, m, ldu) v := nanGeneral(p, p, ldv) q := nanGeneral(n, n, ldq) iwork := make([]int, n) work := []float64{0} impl.Dggsvd3(lapack.GSVDU, lapack.GSVDV, lapack.GSVDQ, m, n, p, a.Data, a.Stride, b.Data, b.Stride, alpha, beta, u.Data, u.Stride, v.Data, v.Stride, q.Data, q.Stride, work, -1, iwork) lwork := int(work[0]) work = make([]float64, lwork) k, l, ok := impl.Dggsvd3(lapack.GSVDU, lapack.GSVDV, lapack.GSVDQ, m, n, p, a.Data, a.Stride, b.Data, b.Stride, alpha, beta, u.Data, u.Stride, v.Data, v.Stride, q.Data, q.Stride, work, lwork, iwork) if !ok { if test.ok { t.Errorf("test %d unexpectedly did not converge", cas) } continue } // Check orthogonality of U, V and Q. if resid := residualOrthogonal(u, false); resid > tol { t.Errorf("Case %v: U is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } if resid := residualOrthogonal(v, false); resid > tol { t.Errorf("Case %v: V is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case %v: Q is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } // Check C^2 + S^2 = I. var elements []float64 if m-k-l >= 0 { elements = alpha[k : k+l] } else { elements = alpha[k:m] } for i := range elements { i += k d := alpha[i]*alpha[i] + beta[i]*beta[i] if !scalar.EqualWithinAbsOrRel(d, 1, tol, tol) { t.Errorf("test %d: alpha_%d^2 + beta_%d^2 != 1: got: %v", cas, i, i, d) } } zeroR, d1, d2 := constructGSVDresults(n, p, m, k, l, a, b, alpha, beta) // Check Uᵀ*A*Q = D1*[ 0 R ]. uTmp := nanGeneral(m, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, u, aCopy, 0, uTmp) uAns := nanGeneral(m, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, uTmp, q, 0, uAns) d10r := nanGeneral(m, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, d1, zeroR, 0, d10r) if !equalApproxGeneral(uAns, d10r, tol) { t.Errorf("test %d: Uᵀ*A*Q != D1*[ 0 R ]\nUᵀ*A*Q:\n%+v\nD1*[ 0 R ]:\n%+v", cas, uAns, d10r) } // Check Vᵀ*B*Q = D2*[ 0 R ]. vTmp := nanGeneral(p, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, v, bCopy, 0, vTmp) vAns := nanGeneral(p, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, vTmp, q, 0, vAns) d20r := nanGeneral(p, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, d2, zeroR, 0, d20r) if !equalApproxGeneral(vAns, d20r, tol) { t.Errorf("test %d: Vᵀ*B*Q != D2*[ 0 R ]\nVᵀ*B*Q:\n%+v\nD2*[ 0 R ]:\n%+v", cas, vAns, d20r) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dggsvp3.go000066400000000000000000000107631450372207100231370ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dggsvp3er interface { Dlanger Dggsvp3(jobU, jobV, jobQ lapack.GSVDJob, m, p, n int, a []float64, lda int, b []float64, ldb int, tola, tolb float64, u []float64, ldu int, v []float64, ldv int, q []float64, ldq int, iwork []int, tau, work []float64, lwork int) (k, l int) } func Dggsvp3Test(t *testing.T, impl Dggsvp3er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { m, p, n, lda, ldb, ldu, ldv, ldq int }{ {m: 3, p: 3, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 5, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 5, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 5, p: 5, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 5, p: 5, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 5, p: 5, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 10, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 10, p: 5, n: 5, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 10, p: 10, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 10, p: 10, n: 10, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0}, {m: 5, p: 5, n: 5, lda: 10, ldb: 10, ldu: 10, ldv: 10, ldq: 10}, {m: 5, p: 5, n: 5, lda: 10, ldb: 10, ldu: 10, ldv: 10, ldq: 10}, {m: 5, p: 5, n: 10, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20}, {m: 5, p: 5, n: 10, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20}, {m: 5, p: 5, n: 10, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20}, {m: 10, p: 5, n: 5, lda: 10, ldb: 10, ldu: 20, ldv: 10, ldq: 10}, {m: 10, p: 5, n: 5, lda: 10, ldb: 10, ldu: 20, ldv: 10, ldq: 10}, {m: 10, p: 10, n: 10, lda: 20, ldb: 20, ldu: 20, ldv: 20, ldq: 20}, {m: 10, p: 10, n: 10, lda: 20, ldb: 20, ldu: 20, ldv: 20, ldq: 20}, } { m := test.m p := test.p n := test.n lda := test.lda if lda == 0 { lda = n } ldb := test.ldb if ldb == 0 { ldb = n } ldu := test.ldu if ldu == 0 { ldu = m } ldv := test.ldv if ldv == 0 { ldv = p } ldq := test.ldq if ldq == 0 { ldq = n } a := randomGeneral(m, n, lda, rnd) aCopy := cloneGeneral(a) b := randomGeneral(p, n, ldb, rnd) bCopy := cloneGeneral(b) tola := float64(max(m, n)) * impl.Dlange(lapack.Frobenius, m, n, a.Data, a.Stride, nil) * dlamchE tolb := float64(max(p, n)) * impl.Dlange(lapack.Frobenius, p, n, b.Data, b.Stride, nil) * dlamchE u := nanGeneral(m, m, ldu) v := nanGeneral(p, p, ldv) q := nanGeneral(n, n, ldq) iwork := make([]int, n) tau := make([]float64, n) work := []float64{0} impl.Dggsvp3(lapack.GSVDU, lapack.GSVDV, lapack.GSVDQ, m, p, n, a.Data, a.Stride, b.Data, b.Stride, tola, tolb, u.Data, u.Stride, v.Data, v.Stride, q.Data, q.Stride, iwork, tau, work, -1) lwork := int(work[0]) work = make([]float64, lwork) k, l := impl.Dggsvp3(lapack.GSVDU, lapack.GSVDV, lapack.GSVDQ, m, p, n, a.Data, a.Stride, b.Data, b.Stride, tola, tolb, u.Data, u.Stride, v.Data, v.Stride, q.Data, q.Stride, iwork, tau, work, lwork) // Check orthogonality of U, V and Q. if resid := residualOrthogonal(u, false); resid > tol { t.Errorf("Case %v: U is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } if resid := residualOrthogonal(v, false); resid > tol { t.Errorf("Case %v: V is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case %v: Q is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } zeroA, zeroB := constructGSVPresults(n, p, m, k, l, a, b) // Check Uᵀ*A*Q = [ 0 RA ]. uTmp := nanGeneral(m, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, u, aCopy, 0, uTmp) uAns := nanGeneral(m, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, uTmp, q, 0, uAns) if !equalApproxGeneral(uAns, zeroA, tol) { t.Errorf("test %d: Uᵀ*A*Q != [ 0 RA ]\nUᵀ*A*Q:\n%+v\n[ 0 RA ]:\n%+v", cas, uAns, zeroA) } // Check Vᵀ*B*Q = [ 0 RB ]. vTmp := nanGeneral(p, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, v, bCopy, 0, vTmp) vAns := nanGeneral(p, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, vTmp, q, 0, vAns) if !equalApproxGeneral(vAns, zeroB, tol) { t.Errorf("test %d: Vᵀ*B*Q != [ 0 RB ]\nVᵀ*B*Q:\n%+v\n[ 0 RB ]:\n%+v", cas, vAns, zeroB) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dgtsv.go000066400000000000000000000042031450372207100227010ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dgtsver interface { Dgtsv(n, nrhs int, dl, d, du []float64, b []float64, ldb int) (ok bool) } func DgtsvTest(t *testing.T, impl Dgtsver) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 25, 50} { for _, nrhs := range []int{0, 1, 2, 3, 4, 10} { for _, ldb := range []int{max(1, nrhs), nrhs + 3} { dgtsvTest(t, impl, rnd, n, nrhs, ldb) } } } } func dgtsvTest(t *testing.T, impl Dgtsver, rnd *rand.Rand, n, nrhs, ldb int) { const ( tol = 1e-14 extra = 10 ) name := fmt.Sprintf("Case n=%d,nrhs=%d,ldb=%d", n, nrhs, ldb) if n == 0 { ok := impl.Dgtsv(n, nrhs, nil, nil, nil, nil, ldb) if !ok { t.Errorf("%v: unexpected failure for zero size matrix", name) } return } // Generate three random diagonals. var ( d, dCopy []float64 dl, dlCopy []float64 du, duCopy []float64 ) d = randomSlice(n+1+extra, rnd) dCopy = make([]float64, len(d)) copy(dCopy, d) if n > 1 { dl = randomSlice(n+extra, rnd) dlCopy = make([]float64, len(dl)) copy(dlCopy, dl) du = randomSlice(n+extra, rnd) duCopy = make([]float64, len(du)) copy(duCopy, du) } b := randomGeneral(n, nrhs, ldb, rnd) got := cloneGeneral(b) ok := impl.Dgtsv(n, nrhs, dl, d, du, got.Data, got.Stride) if !ok { t.Fatalf("%v: unexpected failure in Dgtsv", name) return } // Compute A*X - B. dlagtm(blas.NoTrans, n, nrhs, 1, dlCopy, dCopy, duCopy, got.Data, got.Stride, -1, b.Data, b.Stride) anorm := dlangt(lapack.MaxColumnSum, n, dlCopy, dCopy, duCopy) bi := blas64.Implementation() var resid float64 for j := 0; j < nrhs; j++ { bnorm := bi.Dasum(n, b.Data[j:], b.Stride) xnorm := bi.Dasum(n, got.Data[j:], got.Stride) resid = math.Max(resid, bnorm/anorm/xnorm) } if resid > tol { t.Errorf("%v: unexpected result; resid=%v,want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dhseqr.go000066400000000000000000010537521450372207100230560ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dhseqrer interface { Dhseqr(job lapack.SchurJob, compz lapack.SchurComp, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, z []float64, ldz int, work []float64, lwork int) int } type dhseqrTest struct { n int ilo int ihi int h []float64 tol float64 evWant []complex128 } func DhseqrTest(t *testing.T, impl Dhseqrer) { for i, tc := range dhseqrTests { for _, job := range []lapack.SchurJob{lapack.EigenvaluesOnly, lapack.EigenvaluesAndSchur} { for _, wantz := range []bool{false, true} { for _, extra := range []int{0, 11} { testDhseqr(t, impl, i, tc, job, wantz, extra, true) testDhseqr(t, impl, i, tc, job, wantz, extra, false) } } } } } func testDhseqr(t *testing.T, impl Dhseqrer, i int, test dhseqrTest, job lapack.SchurJob, wantz bool, extra int, optwork bool) { const tol = 1e-14 evTol := test.tol if evTol == 0 { evTol = tol } n := test.n ihi := test.ihi ilo := test.ilo h := zeros(n, n, n+extra) copyGeneral(h, blas64.General{Rows: n, Cols: n, Stride: max(1, n), Data: test.h}) hCopy := cloneGeneral(h) compz := lapack.SchurNone z := blas64.General{Stride: max(1, n)} if wantz { // First, let Dhseqr initialize Z to the identity matrix. compz = lapack.SchurHess z = nanGeneral(n, n, n+extra) } wr := nanSlice(n) wi := nanSlice(n) work := nanSlice(max(1, n)) if optwork { impl.Dhseqr(job, lapack.SchurHess, n, ilo, ihi, h.Data, h.Stride, wr, wi, z.Data, z.Stride, work, -1) work = nanSlice(int(work[0])) } unconverged := impl.Dhseqr(job, compz, n, ilo, ihi, h.Data, h.Stride, wr, wi, z.Data, z.Stride, work, len(work)) prefix := fmt.Sprintf("Case %v: job=%c, compz=%c, n=%v, ilo=%v, ihi=%v, extra=%v, optwk=%v", i, job, compz, n, ilo, ihi, extra, optwork) if unconverged > 0 { t.Logf("%v: Dhseqr did not compute all eigenvalues. unconverged=%v", prefix, unconverged) if unconverged <= ilo { t.Fatalf("%v: 0 < unconverged <= ilo", prefix) } } // Check that wr and wi have been assigned completely. if floats.HasNaN(wr) { t.Errorf("%v: wr has NaN elements", prefix) } if floats.HasNaN(wi) { t.Errorf("%v: wi has NaN elements", prefix) } // Check that complex eigenvalues are stored in consecutive elements as // complex conjugate pairs. for i := 0; i < n; { if unconverged > 0 && i == ilo { // Skip the unconverged eigenvalues. i = unconverged continue } if wi[i] == 0 { // Real eigenvalue. i++ continue } // Complex conjugate pair. if wr[i] != wr[i+1] { t.Errorf("%v: conjugate pair has real parts unequal", prefix) } if wi[i] < 0 { t.Errorf("%v: first in conjugate pair has negative imaginary part", prefix) } if wi[i+1] != -wi[i] { t.Errorf("%v: complex pair is not conjugate", prefix) } i += 2 } // Check that H contains the Schur form T. if job == lapack.EigenvaluesAndSchur { for i := 0; i < n; { if unconverged > 0 && i == ilo { // Skip the unconverged eigenvalues. i = unconverged continue } if wi[i] == 0 { // Real eigenvalue. if wr[i] != h.Data[i*h.Stride+i] { t.Errorf("%v: T not in Schur form (real eigenvalue not on diagonal)", prefix) } i++ continue } // Complex conjugate pair. im := math.Sqrt(math.Abs(h.Data[(i+1)*h.Stride+i])) * math.Sqrt(math.Abs(h.Data[i*h.Stride+i+1])) if wr[i] != h.Data[i*h.Stride+i] || wr[i] != h.Data[(i+1)*h.Stride+i+1] || math.Abs(wi[i]-im) > tol { t.Errorf("%v: conjugate pair and 2×2 diagonal block don't correspond", prefix) } i += 2 } } // Check that all the found eigenvalues are really eigenvalues. foundEV := make([]bool, len(test.evWant)) for i := 0; i < n; { if unconverged > 0 && i == ilo { // Skip the unconverged eigenvalues. i = unconverged continue } ev := complex(wr[i], wi[i]) // Use problem-specific tolerance for testing eigenvalues. found, index := containsComplex(test.evWant, ev, evTol) if !found { t.Errorf("%v: unexpected eigenvalue %v", prefix, ev) } else { foundEV[index] = true } i++ } if unconverged == 0 { // Check that all eigenvalues have been found. // This simple check assumes that all eigenvalues are // sufficiently separated from each other at least by evTol. for i := range foundEV { if !foundEV[i] { t.Errorf("%v: %vth eigenvalue not found", prefix, i) } } } if !wantz { return } // Z must be orthogonal. if resid := residualOrthogonal(z, false); resid > tol*float64(n) { t.Errorf("Case %v: Z is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } if job == lapack.EigenvaluesAndSchur { tz := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.Trans, 1, h, z, 0, tz) ztz := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, z, tz, 0, ztz) if !equalApproxGeneral(ztz, hCopy, evTol) { t.Errorf("%v: H != Z T Zᵀ", prefix) } } // Restore H. copyGeneral(h, hCopy) // Call Dhseqr again with the identity matrix given explicitly in Q. q := eye(n, n+extra) impl.Dhseqr(job, lapack.SchurOrig, n, ilo, ihi, h.Data, h.Stride, wr, wi, q.Data, q.Stride, work, len(work)) if !equalApproxGeneral(z, q, 0) { t.Errorf("%v: Z and Q are not equal", prefix) } } var dhseqrTests = []dhseqrTest{ { n: 0, ilo: 0, ihi: -1, }, { n: 1, ilo: 0, ihi: 0, h: []float64{0}, evWant: []complex128{0}, }, { n: 1, ilo: 0, ihi: 0, h: []float64{7.09965484086874e-1}, evWant: []complex128{7.09965484086874e-1}, }, { n: 2, ilo: 0, ihi: 1, h: []float64{0, 0, 0, 0}, evWant: []complex128{0}, }, { n: 2, ilo: 0, ihi: 1, h: []float64{ 1, 0, 0, 1, }, evWant: []complex128{1}, }, { n: 2, ilo: 0, ihi: 1, h: []float64{ 0, -1, 1, 0, }, evWant: []complex128{1i, -1i}, }, { n: 2, ilo: 0, ihi: 1, h: []float64{ 6.25219991450918e-1, 8.17510791994361e-1, 3.31218891622294e-1, 1.24103744878131e-1, }, evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, }, { n: 4, ilo: 1, ihi: 2, h: []float64{ 1, 0, 0, 0, 0, 6.25219991450918e-1, 8.17510791994361e-1, 0, 0, 3.31218891622294e-1, 1.24103744878131e-1, 0, 0, 0, 0, 2, }, evWant: []complex128{1, 2, 9.52203547663447e-1, -2.02879811334398e-1}, }, { n: 2, ilo: 0, ihi: 1, h: []float64{ -1.1219562276608, 6.85473513349362e-1, -8.19951061145131e-1, 1.93728523178888e-1, }, evWant: []complex128{ -4.64113852240958e-1 + 3.59580510817350e-1i, -4.64113852240958e-1 - 3.59580510817350e-1i, }, }, { n: 5, ilo: 0, ihi: 4, h: []float64{ 9.57590178533658e-1, -5.10651295522708e-1, 9.24974510015869e-1, -1.30016306879522e-1, 2.92601986926954e-2, -1.08084756637964, 1.77529701001213, -1.36480197632509, 2.23196371219601e-1, 1.12912853063308e-1, 0, -8.44075612174676e-1, 1.067867614486, -2.55782915176399e-1, -2.00598563137468e-1, 0, 0, -5.67097237165410e-1, 2.07205057427341e-1, 6.54998340743380e-1, 0, 0, 0, -1.89441413886041e-1, -4.18125416021786e-1, }, evWant: []complex128{ 2.94393309555622, 4.97029793606701e-1 + 3.63041654992384e-1i, 4.97029793606701e-1 - 3.63041654992384e-1i, -1.74079119166145e-1 + 2.01570009462092e-1i, -1.74079119166145e-1 - 2.01570009462092e-1i, }, }, { // BFW62A matrix from MatrixMarket, balanced and factorized into // upper Hessenberg form in Octave. // Eigenvalues computed by eig function in Octave. // Dhseqr considers this matrix small (n <= 75). n: 62, ilo: 0, ihi: 61, tol: 1e-12, h: []float64{ 0.7610708, -0.71474042262732, -1.03373461417302e-17, 8.218284875369092e-18, -4.39003777724509e-18, -7.633870714681998e-18, -9.951525116511751e-18, -6.538760279193677e-18, -1.656240811786753e-18, -4.915424973452908e-18, -7.590492820502813e-18, -4.532592864746854e-18, 1.137360639223451e-18, -2.088794138001457e-18, 4.330727699351238e-18, 4.88172964159538e-18, -6.438459345602974e-18, 7.414402965763168e-18, 8.592387304092668e-19, 2.905505475188102e-18, -5.210204793418634e-18, 2.377023457149656e-18, -1.958364175388968e-18, -8.746122759061733e-20, 1.839015672758814e-18, 3.097454207400904e-18, 1.545856657360309e-18, 1.713923049773744e-21, 1.333951071201153e-18, -1.256151066318485e-18, 5.489655201308922e-19, -2.191335276195054e-18, 3.211054779957158e-18, -4.585099368362507e-19, 4.064807180521144e-18, -3.621561583390336e-18, 4.638803832189033e-19, 1.306132013406548e-18, 7.71710094138792e-19, 2.320760977517361e-18, -6.538298612520761e-19, -3.498839827985687e-18, 2.699116500378558e-18, -1.653627855476782e-18, 7.006984532830204e-19, -2.829108657299736e-18, -5.260772120044258e-18, 1.014346572590618e-18, -1.751563831849658e-18, -1.850186018112724e-19, 2.870415308417256e-18, -8.423700664162806e-19, 3.498345394735042e-19, 1.448350507022323e-18, -3.119800500343431e-18, 4.170966784863917e-18, -4.413795207992463e-19, -2.550853151356032e-18, 2.058575286932081e-18, 1.11609155804576e-18, -2.819648393130598e-18, -2.691434041700446e-19, -0.71474042262732, 1.938395745278447, -1.179041092366627, 2.994496337305918e-17, -1.886890458028042e-17, -1.696051150581149e-17, -1.066654178739982e-17, -6.29828959344471e-18, -3.017613522337327e-18, -6.087774183044001e-18, -1.623722797471356e-17, -1.609066043798334e-17, 1.1222991062801e-17, -1.199415856132727e-17, 3.254808477409891e-17, 3.032574771313234e-17, -2.950307698970009e-17, 3.390164991463985e-17, 3.580652213399182e-17, -1.363239170451582e-17, 5.318959619432346e-19, -2.094826370136215e-17, 2.503105756608372e-17, 1.02172885473953e-17, 2.072365201436764e-17, 5.419721687057681e-17, 2.946627912791419e-17, -1.348815353957071e-17, -6.109538294302727e-18, 8.919596400140564e-19, -4.965011212156456e-18, -8.892555328798407e-18, -8.533370652960768e-18, 2.670935841220357e-17, 6.294143735482237e-17, -6.631964574578866e-17, 1.610888675267686e-17, -1.914212496162892e-17, 7.491989417296875e-17, 2.433601037912241e-17, -3.471972221532949e-17, 1.239231453972595e-18, 8.477927675716922e-17, 1.832368873558869e-17, -3.15614722379294e-17, -3.481308523858143e-17, 8.753655535825511e-17, -2.311094913977048e-17, -1.97736043621337e-17, -4.591312368362259e-18, -4.090767028097941e-17, 9.630744841167777e-17, 6.376373378245906e-17, 3.517117740157962e-18, -4.504796150838874e-17, 7.517908631343054e-17, 5.08947280115584e-17, -1.382149857389238e-17, -2.198919507523352e-18, 7.280187019637593e-18, -4.195544216643798e-17, -1.69351463438629e-16, 0, -1.179041092366627, 1.770797890903813, 0.9251612011433773, 0.003661446613681521, -0.005110479724841567, 0.0005014497289028411, 0.00268637752732762, -0.003137790817099964, 0.0001251340392028716, 0.005236816389348038, -0.007596537304410319, -0.003216883293048434, 0.002836879838039065, 0.006069520262676079, 0.002668518333518884, 0.009131523505676264, 0.004626632495050776, 0.00181579510454105, 0.001123900611304629, 0.001677485377614088, 0.00363754391761903, -0.0007470406844762735, 0.002833257933303097, -0.0002375815340930377, -0.002849024657372476, -0.0002629124003065383, -0.0009435052243060314, -0.001501677820905836, 0.0007867717317979819, -0.003255814847476796, 0.0001229596171032013, 0.001899497807037465, 0.001586135347885108, -0.002155598204409179, -0.004095921626627291, -0.004749259183184092, -0.0003901939289968589, -0.00126397970751315, 0.001155644134671306, 0.000291837164140963, -0.0008540793573406925, 0.0005498493646965147, -0.000512747881346778, 0.001308619245804509, -0.001057469234737898, 8.364932352209563e-05, -0.0004759538737373512, 0.0002832407173157385, -2.502295625364179e-05, -0.001116422235449543, 0.0008744887175767913, -0.001577030646119032, 0.0006630051771088335, 0.0008174386956312274, 0.0005885600522543514, -0.000529324123745168, 0.0006462360717703873, -0.0005292503950906053, -0.0008409757119361148, 0.001179292096398777, -7.042243897656571e-05, 0, 0, 0.9256234889252499, 2.188661152704918, -1.116554836905615, -0.02243454666837822, 0.001818477623431723, 0.01031345522542573, -0.02255181751639313, 0.01064389372187288, 0.02644236613167033, -0.03711341885334873, -0.01368507023909662, 0.005876976997280983, 0.04065670610764593, 0.01666467627475975, 0.04720670725274503, 0.02074371568474985, 0.02492606640786733, -0.0007477579555839802, 0.008780018993769038, 0.02228545976823896, -0.001309713708470288, 0.02515283874752867, -0.002695437114195642, -0.03058898397162627, -0.004721936411831751, -0.01112709820777293, 0.005156744291122814, 0.001266520229863774, -0.0173310067274492, 0.006032177243961209, 0.01546906824241716, 0.004122912475005991, -0.01457685983271352, -0.02472315268907353, -0.0146012575743626, 0.01613627552485761, -0.03570849487210562, 0.009634392591632741, 0.01396210133689555, -0.01085301942984549, 0.02308071799914048, -0.01534806641683973, 0.007461896675297811, 0.001678793578211992, -0.004550709803423801, -0.003543952787451961, 0.01328644094056202, 0.01722933205866279, -0.01604068924890588, 0.01061524273934986, -0.01948663408394128, 0.02488657490054273, 0.002560204204893632, -0.007049942019567433, -0.005861737475764968, 0.007063905438215945, -0.01302170441839208, -0.01452116548010346, 0.008856002952171451, 0.003352799875293177, 0, 0, 0, -1.131565669446545, 3.458875937128813, -2.92300025604371, 0.0004977656856497978, 0.006279968970473544, 0.0775979532222543, -0.07809248806636047, -0.04323656216106807, 0.05001022064587737, 0.003864067108285046, 0.04141643188583877, -0.1284617838883834, -0.04493800214431209, -0.07456343090218126, -0.01563872481200422, -0.1339020629421785, 0.04186908269102881, -0.01575262227867954, -0.05122401589211525, -0.01356095585891559, -0.1061570482803366, 0.01819813598371521, 0.1481253462698246, 0.02550194602547843, 0.04637287461870648, -0.07444378895306285, 0.01361958240422481, 0.04035022896181466, -0.04232248915252568, -0.06075940528348658, 0.027263798939883, 0.03953143432541723, 0.06518841156851282, -0.03410646432627348, -0.1414076406563496, 0.2323217246349602, -0.03415439789233707, -0.1031903658536844, 0.06725801721048928, -0.1560521418148311, 0.1014900809050588, -0.02098771321982528, -0.03982159107235207, 0.03695361299827822, 0.01067293209294729, -0.09426629859219736, -0.1345822610538289, 0.09362330513280395, -0.05670709861587474, 0.1059566486421828, -0.1760916487632087, 0.003702764511325265, 0.07422105386227762, 0.02742567045198715, -0.03734725575689604, 0.08146131944298318, 0.09081980084945049, -0.03823012624212198, -0.02882941691361127, 0, 0, 0, 0, -2.935177932025793, 5.590160898106907, -2.264162462726681, -0.02411424982833118, -0.1133643811701465, 0.1104837624251364, 0.05106708784671347, -0.03981053811687705, -0.02554107703230142, -0.06918772930550876, 0.1627330379332113, 0.0515325563326872, 0.0562468014393183, 0.0339155492439978, 0.1634368483167388, -0.06785129040640099, 0.04039982620620088, 0.04044710731973533, 0.0285518510842595, 0.1485759249940305, -0.0304537251951914, -0.2009213484930713, -0.05273834253818357, -0.03107458918212595, 0.09792748883617711, -0.0337039884304953, -0.06657284881035327, 0.04914327832710783, 0.07368372187446774, -0.0404082088678178, -0.04421178865717079, -0.0709487906769288, 0.048430647567918, 0.1864479159285081, -0.3079556699470428, 0.01491993158702447, 0.1333753802314968, -0.09591074161204663, 0.1894696359177905, -0.1319027537070656, 0.03081270942006841, 0.04847952392626505, -0.04816809266890478, -0.0008101823853040729, 0.1149477702272877, 0.1970244006374306, -0.1184305631819092, 0.07656633356645355, -0.140928669738484, 0.2423845347140408, -0.01430733985161339, -0.0967298709856266, -0.03791764167457073, 0.04501910433428818, -0.09499757971636948, -0.1139200858550714, 0.04630019674988028, 0.03975991363586522, 0, 0, 0, 0, 0, -2.266072850070115, 4.40758227065786, -2.187592801167079, 0.04541318743325212, -0.0292500337966509, -0.02398663294591961, -0.0298607436249778, 0.0765927452101913, 0.03477459705241919, -0.0257224121936686, 0.001477537977391887, 0.04674868179804328, -0.07030659618878905, 0.0114383223715982, 0.04039500147294157, -0.06165490536387656, 0.03052165142437121, -0.03151343169646251, -0.04567511071619659, 0.01389646864038026, 0.03406059858329889, 0.07777247587370216, -0.05562215591676438, -0.02972304398764038, 0.04553302018172632, 0.04905358098395964, 0.02540110963535692, 0.00741827563880251, -0.02406479350578768, 0.00798549007761889, -0.02127832597347739, 0.01170084494509563, 0.002383029926628291, 0.02969332847749644, 0.07478610531483831, 0.01311741704707942, 0.004853415796376565, 0.02254889573704177, -0.0008058983249759786, -0.01674237970384834, 0.007747220993838389, 0.001741724814996781, -0.02678508693786828, 0.03009097476646124, -0.06933693587488159, -0.006894177513041368, -0.003212920179243059, 0.006244662438662574, -0.03261491350065344, 0.03016960268159134, -0.001128724172713099, 0.01002372353957473, 0.01549185843206932, -0.01638802914727083, -0.02186759059889685, 0.02607807397124053, -0.01433672343290503, 0, 0, 0, 0, 0, 0, -2.208506791141428, 5.240066122406224, -2.182709291422287, -0.04831719550093321, -0.03858222961310988, 0.07090414091109702, 0.07618344970454043, 0.01210977758298604, -0.08775997916346844, -0.04209238321226993, -0.08158937930535407, -0.0691978468647506, -0.0718486976078294, 0.004433709126950578, -0.06338689200675134, -0.03622650750929987, -0.007019326939737634, -0.1038169299762074, -0.003664296783585897, 0.1260404715508425, 0.01449365280740196, 0.02152866502194497, -0.04579662426484265, 0.02137306190373941, 0.02841535413798802, -0.04356497460133966, -0.04882163279365745, 0.0002663261307664017, 0.04049595350038757, 0.05101584504101733, 0.02365749339968924, -0.05799471679730656, 0.1571971147245405, -0.01838060269733261, -0.05301211904637573, 0.02796283933445018, -0.0827747400120639, 0.0826539872568238, -0.004639853234141812, -0.03415100337915269, 0.02043301459221876, -0.01420687321749558, -0.07938788384250468, -0.06984431882951091, 0.01979778686221181, -0.05267713009695951, 0.05803585434476307, -0.1172598583231236, 0.01085942096095348, 0.03045318026097962, 0.03931707061762502, -0.0233260419792624, 0.02886660013519448, 0.03861548107303825, -0.03415507841094348, 0.008098200304311437, 0, 0, 0, 0, 0, 0, 0, -2.279082737682327, 4.179202389209161, 2.014339592778223, -0.04255211810632337, 0.2215228709530191, 0.04554891291433198, -0.1776754857264893, 0.008167590360928265, -0.03396600462822136, -0.2424067171263278, -0.04982603310212124, 0.08199335145408625, -0.1620942794258422, 0.002338101300086993, -0.07021142224421691, 0.09194811379254013, 0.06141720296344315, -0.04343138202962209, -0.07659354927119244, -0.1361105641705367, 0.04365095033370017, 0.1736465880725596, -0.08740865081391179, -0.01477028109128357, -0.0188999323841316, -0.01077877669937425, -0.04294670860685663, 0.01729899060655344, 0.08739236799944389, 0.182034549192379, 0.1742753783161974, -0.2051811283512857, -0.09696129832199611, 0.08343537923840838, -0.04957366782909829, 0.1265093425463374, -0.07142635715461459, 0.03516617105992843, 0.0383997617140459, -0.04104973319490962, 0.02037353120337982, 0.04757894980296348, 0.2227131172970346, -0.07280127948445575, 0.01933448054625989, -0.05548809149836405, 0.2093056702150173, -0.07255565470500472, -0.123599084041237, -0.01537223729308192, 0.002577573950277644, -0.0733551734670323, -0.03190494711187865, -0.03967527247234395, 0.07966579792866824, 0, 0, 0, 0, 0, 0, 0, 0, 1.903931035374501, 3.824975942360571, -1.918381148171332, -0.1657229385793016, -0.1612950026821678, 0.06698675826395525, 0.126725548868686, 0.05262161401229534, 0.1736974825351408, 0.1645930486922778, -0.008218244683807857, 0.0481824748986632, 0.1029912224929829, 0.04100531176584442, -0.05027752034197176, 0.03600703924093035, -0.03107821795488815, -0.09759422490480313, -0.04354787932553194, 0.08526304164417117, -0.05355786578034339, -0.0210819410892414, -0.1122497139926173, -0.02837719853579051, 0.02149997813969711, 0.06803627465540676, -0.0458177019216118, -0.09920218030202725, -0.1651400777956252, -0.0455277713939929, 0.003337830551949452, -0.06755253724103881, -0.07801076584667281, -0.04572759847378299, -0.02963338925321968, 0.07597836187621793, 0.01430341925034608, -0.02647305556934371, 0.0228555845523007, 0.01546873666210535, -0.03908905892485317, -0.01513876665871793, 0.0042446623219113, 0.03015387459510092, -0.02120400053387252, -0.03598829734362344, 0.004724005614895581, 0.07940598065515762, 0.01643813194117675, 0.005515400875796831, 0.03057541214871107, -0.01882273722478993, 0.001668026830005827, -0.02913002540516653, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.035489145812599, 3.958195998136282, -2.415518953202652, -0.1018252839623988, 0.09113791429521235, -0.143125166149266, -0.02308820648298807, 0.007900495974597297, 0.0891936029052371, -0.191496963455834, 0.08058392972181647, 0.05211306893716722, -0.02786699591928707, 0.007523375632267236, -0.05648289516476343, 0.06927000214275245, 0.1738730341952659, 0.04931088211870207, 0.03078035118979117, -0.09569654581650394, 0.01335103593932622, 0.06192961771791639, -0.02060940913305214, -0.05414923078827102, 0.06346107123244546, 0.02052335161999402, 0.0759441214578726, -0.1238298106880246, -0.2507681676381417, 0.3220100931816501, -0.01147160193974397, -0.1324548043218159, 0.1477869911354369, -0.2406607672124291, 0.06431201000607845, -0.01766450147458312, -0.0548904673124562, 0.05157233284634812, 0.04488059690309322, -0.06177517133954061, -0.23112183069299, 0.2080819465459902, -0.05619520043449243, 0.1795452492137158, -0.204269300276831, -0.01430899089131678, 0.08951777845217569, -0.02653873178692821, -0.04665500591425999, 0.1362175927592773, 0.1872861054389846, -0.02109220243469613, -0.07237982467321609, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.387825495222564, 5.631333594127314, 1.792900160009439, -0.1292562242890975, 0.1708356554410346, 0.04950951151168896, -0.009914110552264667, 0.1304655891154234, 0.1609748354747077, -0.08607480442007164, 0.1610516858008479, 0.006346254683211893, 0.02530117908848513, 0.2023262116291442, -0.04991598539162005, -0.3298986278194697, -0.1487726465103999, 0.04799870466505981, 0.1882318445518781, -0.1206769872912393, -0.09574976849564885, 0.04601707138105179, 0.0715991702971735, 0.0110319870997898, -0.07468722751312951, -0.06360236467100627, 0.03066807997062939, 0.1978804308092757, -0.4403223814664722, -0.09064370852004526, 0.08638179820445273, -0.1181221434581026, 0.2272147516466281, -0.1254616867610615, -0.0001501123827163629, 0.1032892317050803, -0.05195565185717236, 0.04689531008365307, 0.1236167395644631, 0.2849021718663459, -0.08639934992977449, 0.1211622058496298, -0.1593293433814323, 0.2959939998820938, -0.06193112020165896, -0.06245227757105343, -0.04632893647720479, 0.03583128970774434, -0.07735153068129821, -0.1215213155769518, 0.01117363777162431, 0.01224071348068845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.970568498833333, 3.432745918572068, -2.179945131289983, 0.1549422681053906, 0.02156733618947362, -0.1743403098753009, 0.04884260166424702, 0.161193984588502, -0.2174611110448761, 0.05521624891494294, -0.05887323587614037, 0.1328019445063764, 0.150653877491827, -0.06531521571304157, -0.1543822385517836, -0.2043044123070031, 0.1255799677545108, 0.1951365223394271, -0.1233664137625445, -0.1191855712864921, -0.04903904444926842, 0.01721465629147372, -0.04824417949824886, -0.001809247060549745, 0.04683387964790045, 0.1406402447048902, 0.2582634735034707, -0.2591765142026595, -0.1617309876246061, 0.1040899633433518, -0.09204034179968526, 0.1659716858767694, -0.07258217699057123, 0.1238542047814545, -0.005315457299413418, -0.04888221850509963, 0.02889824196206881, 0.07250335907166307, 0.3039398127688065, -0.1278843615154275, 0.03794117583347663, -0.08815038995197073, 0.3363118210052076, -0.1106312150714128, -0.1943873573646721, -0.03270119577811206, 0.02061769160692044, -0.1147396461667833, -0.04432517129006736, -0.03624512007085111, 0.1372685073992675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.971094433373163, 3.959369702740928, 1.887120354843997, -0.05026461165000308, -0.1399839889203879, -0.185627397808518, -0.04596340870656163, 0.008956420059669758, -0.1381531838530755, -0.06179826475610644, 0.03260995306247771, -0.0962297246933979, 0.05268169622571128, 0.2046211566675452, 0.1296024872478153, -0.05109478171641717, -0.06816393508471544, 0.06908783957203835, 0.1203829447316026, 0.01720249086925636, -0.03678250120900584, -0.09954728921499965, 0.08400427932827997, 0.09706474262764897, 0.1099658716687498, -0.02055867348093135, 0.1883358420037133, 0.09179573472650564, 0.0428976892444284, 0.06904499115717885, -0.07352106561747025, -0.01527177851177849, 0.007127245592600535, -0.03478704421611469, 0.003011747710224133, -0.02349766354391826, 0.01004232793292505, -0.1176867876164139, 0.02626695914041232, -0.06316783433824909, 0.07753431035296164, -0.05772959109292543, 0.01954926232340906, -0.06086028308842151, -0.003104675370067428, -0.004923780276110752, 0.008718170992460231, 0.05506074746847181, 0.02126352510068548, 0.02026026825978836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.051962095286209, 4.783354200058216, -2.891753406247233, 0.1494225282409022, 0.212321254452782, -0.2121415539790813, 0.02466897820188111, 0.06733336624204075, 0.013113247694252, 0.1066584296274234, 0.08752061927245192, 0.07922179944730777, 0.2365701476731576, 0.007588213043408364, -0.05416415411776607, -0.2020969955640969, 0.06349969928685602, -0.06132787289740503, -0.03422718627771316, -0.01952915873386353, 0.0644213739673787, 0.002115696634784188, 0.06255822113535302, -0.199371510170398, -0.3230384741719209, 0.3808208705549075, 0.04071272810763353, -0.01872027971165153, 0.175074940224908, -0.3802378821499527, -0.06108501582393667, 0.06646559313315525, -0.1623676411929772, 0.03990883781119187, 0.04487902512075174, -0.1419408834211026, -0.1568779206082137, 0.1763292664552807, -0.09481989476682466, 0.1344530334023877, -0.1823509060475661, 0.01993854821358784, 0.06058475613302417, -0.08882610769003915, -0.07025689205542202, 0.1720722409076721, 0.2549799182126544, 0.01962928250874243, -0.01708969300024939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.90166412025067, 5.683663549106058, 1.9210862649828, 0.003584348132213356, -0.04815067261613367, 0.08879292199376522, -0.005675898744132862, 0.03588291164670374, -0.1637463265891401, -0.2197707557186419, -0.08857402261688128, -0.04780383765954515, 0.007843151524149466, 0.1770531910307867, -0.01723997302062695, -0.02612834699223629, -0.00540746785723896, -0.0705490796246758, -0.04457806266766569, 0.06473113864983282, 0.006275761834464256, -0.08950765677362392, -0.1005085571651238, -0.009712772636099888, 0.1241037651167948, -0.1243232786387127, -0.2285046949724745, -0.09330919844079147, 0.05061721851550809, 0.2874490693586184, -0.03620828558028133, 0.009836453811605826, 0.06478449995192533, -0.01171663894787422, 0.006410086373602496, -0.2000108983272982, 0.03916914746487668, 0.03329096249389659, 0.07559233782463498, -0.1503685986635421, -0.006365422116363463, 0.1204026175721976, 0.125722416995956, 0.03865674591865399, -0.0001228620998850972, -0.06816612415831065, -0.03365741691324027, -0.07613321112893839, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.851490093348759, 5.320051320277479, 2.417643700741916, -0.1995237653475895, 0.07621645201183533, -0.1771833255682829, -0.01078146896182771, -0.06438976299009525, -0.2876178310323119, -0.006303714018374637, 0.356885069902641, 0.07024283797935846, 0.01881395860270091, -0.2092513663311028, 0.109718092264327, 0.02854685307727969, -0.1312757974509329, -0.1108285734230257, 0.05182740468109521, 0.07233132504659899, 0.05030539452868459, -0.06059975102985716, -0.2297336103700467, 0.5045083042485633, -0.0004325173131309776, -0.1784693418735473, 0.08394922707081144, -0.2680843663012994, 0.2671400195308918, -0.001793550843300997, -0.1325105555633781, 0.07300804882966573, -0.06897110118534086, -0.2665451791081322, -0.2630899900703882, 0.04369816343226968, -0.156643286665005, 0.1549466071737415, -0.4145076724124122, 0.07488318920361078, 0.1419270611119949, 0.1219043619914908, -0.06378625947413261, 0.08917372812331978, 0.1038377550424948, -0.08072252702869862, 0.009394294196957323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.53934911433842, 3.08124689760215, -1.480395561682393, 0.2462776680494332, 0.01710234467080554, -0.01750922521427385, -0.08464899612469672, -0.08513339146210799, 0.1497690941692451, 0.2003583687026345, 0.229975304279735, -0.06773544482684146, -0.212962762165994, 0.100805918257745, 0.1387021642494545, 0.05756587177820099, -0.02342135307890196, 0.0413142771758164, 0.01012070144816604, 0.009465626383560421, -0.1768890665508353, -0.3114326451294799, 0.334908331740353, 0.1454336469709651, -0.1253099733433882, 0.187117750616515, -0.2556659183272817, 0.05828504568732875, -0.09923486906264152, -0.01295943412712868, 0.04742766192450461, 0.002467967102260226, -0.09546651038888934, -0.3163510329005083, 0.1861927610821425, -0.06672987133018268, 0.1437750260846377, -0.3332140898455062, 0.07302040974957998, 0.1701107028641413, -0.01658898261297759, -0.05269690883993056, 0.1563566521838276, 0.1337720630335788, 0.01368561538114742, -0.1213888256015452, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.307203302598592, 2.885610538012057, 2.250703368751336, 0.07975315762421138, 0.09370441866373114, -0.1923654024839493, -0.1853398422580131, -0.201205128559576, -0.2125042330970577, -0.1602582952706193, 0.3093660817821342, 0.01852414315637842, -0.09255035727223564, -0.1924195495982953, -0.1559361270247578, -0.02917817624329287, 0.1447862761755991, -0.04690491601291951, -0.1960912348494043, -0.2042284966615884, 0.05841637536106218, 0.02291485689303238, -0.2827174856981686, -0.2943255892311636, -0.2215807563938077, 0.1152617438267267, 0.3936419107039491, 0.02096945169954771, -0.02252698024658075, 0.07773344380322408, -0.006443114230257507, -0.03639999246001423, -0.09084547229099375, -0.0397561686169364, 0.07701104659075265, 0.005605523155556855, -0.09348135695481166, -0.03124263128081152, 0.1542717927672431, 0.175465847613986, 0.0572413755901381, -0.03334819451365621, -0.1404348146594518, -0.06481871409417514, -0.04848557273226619, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.221221516792545, 4.982054100250426, 2.183210516233156, 0.0908360095708884, -0.3019054223643021, -0.5366128211639946, -0.3196918354703204, -0.1253970246067154, -0.02164532399684936, 0.2556280160777759, 0.08182827430850881, -0.03680716913431671, 0.03290225595516987, -0.1262131502004158, -0.09569394699109128, -0.005709824337923843, 0.0821878342740492, -0.1407748396690034, 0.09719614879475127, 0.2301897192422586, 0.04576646414789445, -0.2184893983754594, -0.2792745493536102, -0.363844809151781, 0.3257684950525028, 0.4790184968677053, -0.07652744991329491, 0.06377373985106835, 0.09437678117499698, -0.06131442314952967, 0.1635757313451941, -0.2796573282080887, -0.05643997532345108, 0.1152912068418917, 0.05000521333406865, -0.1112720969259657, 0.0037148809503484, 0.1093948420140112, 0.2980235424512261, 0.1525445958488788, -0.1264302662462978, -0.2913624335279468, -0.003113019822754165, -0.1134308899923566, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.400474057942684, 3.406090954274398, 1.166212384143174, -0.2629422439993046, -0.2702044042321645, -0.06636757078595552, -0.08446798536159737, 0.1313648786119294, 0.1193846426124598, -0.07246210384479049, 0.01554276290017705, 0.07103237282021825, 0.00101034194025556, -0.02392135193032525, 0.06952201574673418, -0.007400528848880757, -0.1551607153718201, -0.1651416045393484, -0.0721038672300459, 0.1237766596982622, -0.03361356917856322, -0.2622129829975602, -0.09615056687603316, 0.06891513871408637, 0.2914707059926323, -0.1250888357080352, 0.06761344442133146, 0.0799843533260796, -0.01371538646021322, 0.07103228925121174, -0.3405952917653196, 0.09927170088586629, 0.07489758155119226, 0.08314980277563824, -0.2366684526630883, 0.04202882159469431, 0.2074629307377897, 0.133356144785867, 0.0637264741453499, 0.0308975379082297, -0.1084379405587302, 0.02099441886765496, -0.1808400593316885, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.086464017862694, 5.114621438496568, 1.930881617131408, 0.1620245301097141, 0.1255287200617495, 0.3368622640783234, -0.07183251945541429, -0.3012926287551759, -0.1116975660537743, 0.113190686135744, -0.04910476738177835, -0.0465386985036234, -0.01788084091497165, 0.06748386592535341, -0.02381369375912231, 0.1493221788544871, 0.02579249903686181, -0.2497357621560777, 0.1787366301893779, 0.1598754145183457, 0.1674188524026742, 0.2477399099122946, -0.3340328954217437, -0.2111911479084411, 0.05086712720251271, -0.1292081829605008, -0.04302551258734066, -0.04971415251604733, -0.3610534332063385, 0.1892568833309398, -0.04472498978753213, -0.2065739236157566, -0.02046944574279112, -0.1756213338724003, 0.07793636245748489, 0.001237377976353086, -0.09033779335999018, -0.160410772384528, 0.08626890948440605, 0.2182749871373348, -0.0838793833068209, 0.1464287335113856, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.723745364788649, 3.894040171351998, -1.604023474297945, 0.3564682842321129, -0.068601028463067, 0.2723514789823699, 0.1226064004710703, -0.1014104100043627, -0.01893991862852569, 0.08732928681306741, 0.1555840779063216, 0.08897747453791588, -0.05848831483689518, -0.0484062742636184, -0.01943252555803195, -0.1897987807964078, -0.04208301117450661, -0.05303588371252462, 0.1133610703860842, -0.02273323404597872, 0.2540238415394855, -0.07855533407962875, -0.06507240945437587, -0.005499676266161271, 0.06537585217565781, -0.04778965574559299, 0.03306331390850831, -0.03674334203422738, 0.03096742123062764, 0.01763537013767625, -0.02727086473016628, -0.003088168719969086, 0.0435625544938414, -0.03476926734733601, -0.03196005989505435, -0.1419829052022682, -0.06959993690169985, 0.04835942714075128, 0.06791350727690673, -0.02769231996290041, 0.02869640238709043, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.887735910703242, 2.376861553923156, -2.059488107339375, -0.1636149309402013, 0.4041266030614025, 0.3896070591189961, -0.2297552131134549, -0.01184707906318158, 0.07039303277467518, 0.09925344398529366, 0.06695981045037805, -0.008491592697259171, -0.04552531630716806, -0.2274274932314481, -0.4148399842074417, -0.04458879883972757, 0.1297363092206598, 0.006733546690957063, -0.3384389296777096, 0.1168946778492827, -0.005399720520138511, 0.3552679244548678, -0.05369187330796665, 0.07272949240516048, 0.04205583963833656, -0.003676655566636833, -0.02270378608066365, -0.2966711461982461, 0.02934135424925877, 0.02865469879716708, 0.06673230222014637, -0.1838317311908014, -0.004436962897364399, 0.1509614176408774, 0.03376168246202512, 0.0005117826261220852, 0.04498835681575293, -0.07866868520578868, -0.0334252458798712, -0.08545921183065397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.342190295905557, 4.675687708808497, -2.268183880250829, 0.2090893331762786, 0.4578770822708127, -0.01884304914244323, -0.07920602266213114, 0.05860045842795304, -0.009411964143128677, -0.009484130845488712, -0.03376087164847531, 0.01728654546382909, -0.2136063948857168, -0.1250583122943451, 0.2295451258972967, -0.06031125891810103, -0.1745972831925295, -0.3612966512867564, -0.1696417690184429, 0.2894160200659208, 0.5167644047563161, -0.08805909441951841, 0.1382094329850753, 0.05099565505493066, -0.04533499187369815, 0.05797820328595679, -0.1922533222149581, -0.1102035618550493, 0.09431486137300341, -0.001494148493882944, -0.09571326182532253, -0.0247601912770405, 0.1256667582306468, 0.2120425181347171, 0.07968400246820299, -0.09760118083265475, -0.2941239252154335, -0.07105438440442044, -0.06896304227007152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.005975891768637, 3.352830695220589, -1.754960054860547, 0.1623709029576712, -0.01686728241632605, -0.03827200221784547, 0.1561794350456731, 0.1402911103849665, 0.03386692126036084, -0.2383508690881479, 0.08335746314476074, 0.1222986332072196, 0.1365597783993524, 0.1833332391744543, -0.1153402862359182, 0.06132285746330645, 0.103916564083423, 0.1352942358705118, 0.03751837000428822, -0.09780641373392215, 0.01802532012439729, 0.07461290579154131, -0.07340909507755823, 0.0263628669211833, 0.05634194666559207, 0.1326983203399266, -0.07526750794049826, -0.0255602869082238, -0.03079487759048528, 0.2087632832461296, -0.06368900481673745, -0.1885028988850317, -0.09938432303399658, -0.02813603601003281, -0.03116773548046878, -0.01139744596335172, -0.007527417596076127, 0.09996642926056981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.005352340672642, 4.225811150115511, 2.31447703108509, 0.2404320758625818, -0.1026845105793418, 0.09323203523714457, -0.07188013661735847, -0.04900547068951503, -0.01143900704943617, 0.03127208944683336, -0.1422425637959582, 0.1223555755457385, 0.3629752163517811, -0.1439880981371962, -0.2053548592359871, -0.2670448469719894, -0.2854950646499647, 0.4890836381626159, 0.4252198149550604, -0.04903353665384676, 0.1440097216561384, 0.05263434485402999, -0.05654435812537717, 0.2744897997285071, -0.1869384630385859, -0.0801988284405884, 0.1415754714387316, 0.0461903176790022, 0.07292418854739299, -0.07749396692418822, -0.01197157575397448, 0.2335354584093252, 0.1565196693950396, -0.2175672539551863, -0.294898244011832, -0.04250817996099358, -0.06254226634319582, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.023207199521003, 3.695034404904957, -1.278828575213463, -0.09576460539931182, 0.01293341047109737, -0.1025508423146749, -0.09879959800395338, 0.1293868360344177, 0.02661187351571312, -0.03208813036911215, 0.102284173268301, 0.01897487699556174, -4.171607187027272e-05, -0.2343929177751728, -0.1591895912128799, -0.3479923586821921, 0.2266119442104414, 0.1369767045914879, -0.093264948471121, 0.05584513287015452, 0.1113848723095114, 0.07805629549261404, 0.385159500396428, -0.315090514425508, 0.2619076486635123, 0.2100336864909587, 0.1489157028437222, 0.01899500010404414, -0.05839538028607237, 0.1065294735286251, 0.1429581389759609, 0.1768187396519744, -0.0107077164022975, -0.07184487656799306, 0.1053566314912159, -0.2656344309369447, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.535179041441933, 2.927516278644585, 1.069440149410428, -0.1940154888240462, -0.06435827084629098, 0.03118119256124731, 0.2144814653940334, -0.1459984300204726, -0.01884883111449459, -0.0996859848375896, -0.1929505482810151, -0.142915066638186, 0.04595119246484281, 0.09181030791542119, 0.1046793740137302, -0.1631714112553374, -0.1533173188313381, -0.008178614876768846, -0.03838516939058051, -0.04628352128726964, -0.04001834958725597, -0.3727398948175817, 0.349654467351177, -0.113952499262497, -0.101339746891288, -0.1603850568927218, -0.1309942015965596, 0.07772040042527674, 0.1275463112280693, -0.04252979249843156, -0.1408252690486143, 0.05191953638235136, 0.07165159166941262, -0.1158826338243819, 0.09369294636414835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.042176179125399, 2.455373013093171, -1.298065125007905, 0.02028671121404909, 0.003306962463612291, -0.1036220220710941, 0.0481345337164661, 0.03315299260062861, 0.04992516180471544, 0.09592872957586211, 0.03096020094331417, 0.009903127869262564, 0.01875056235671545, 0.03272160535846057, 0.01927852349784328, 0.02325854762506147, 0.04608264369572843, -0.009983430343303928, -0.01609838886434818, -0.01003965210423024, 0.02113424938210403, 0.005924265966984703, -0.05179857793569453, -0.0244630676591391, 0.01057802494355381, 0.0691716202360271, -0.02554792020429601, -0.09556309673821282, -0.01109440159507958, 0.002795432770742045, -0.03608009327148794, -0.009904492448746673, -0.004701473084555832, 0.06319402826809284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.341422080029597, 2.641177760807674, 1.591936295305328, 0.005262995989819829, 0.05712969006064635, -0.05864522459107201, -0.06744950477663363, 0.1271503047471045, 0.2094260695099903, -0.3057531846245879, -0.04037395011724824, -0.02967432474543921, -0.09059292764118339, 0.2862509429106201, 0.1048474566793039, -0.04995247127231636, 0.1184570436074571, -0.03693842645635304, -0.08306079853122639, -0.04945597334476677, 0.2089393586111927, -0.2028924047636768, 0.01499186002602688, -0.1284371246539898, 0.04369426140288886, 0.001107629872198076, 0.002549707872053236, 0.1030701664382734, 0.002039801798898688, -0.1568979174791054, -0.1881891997896287, -0.1100556548512126, 0.06948313266853789, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.629047221760682, 3.633220763136687, 1.407673550411567, 0.0339033673171226, -0.0440877649168133, -0.1309350154964067, -0.05292438726218229, 0.1243733326688556, -0.09611554125353661, -0.01801557361391788, -0.1394535956650391, -0.04800585756898997, 0.2092817652566071, 0.1937706427881193, -0.0316202819028252, 0.08185853657036937, 0.008847184587817514, -0.05390183527194951, 0.0500718698457836, -0.06277970709250076, -0.07596180328240805, 0.04008159730086977, -0.0124923156950488, -0.01841127788787308, -0.008904456301771634, 0.02894837811492813, 0.08379155755674296, 0.038658741027786, -0.1013410184828959, -0.1363862936525638, -0.04609547972146647, -0.01057837708981668, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.387217368144026, 2.728722184696696, 1.424749145313089, -0.01601470906433309, -0.07512459959692018, -0.101188344036713, -0.003441549977747002, 0.06449001937611275, -0.03196276224536809, -0.1213336580505604, -0.009099515848609243, 0.02592480117875633, 0.1486227237292286, -0.00133150660633606, 0.001532054214242922, 0.02645122343613796, -0.01679939752946042, -0.006472860460697598, -0.1046070432475455, 0.002013525317899786, 0.007407876301716394, 0.03426066213629017, -0.07238247076893806, -0.002515176653231992, 0.04897218815805249, 0.04708726516482133, 0.01321800810118652, -0.0106268999083793, -0.03069342204089823, -0.02184119543907794, -0.02064865378574994, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.391700331330132, 3.10873390469995, -1.005261568422076, 0.07033689862768554, -0.01130536743091839, -0.2012624886845097, 0.1894945671077086, 0.07933080126112255, 0.075305885120587, 0.07607468793519609, -0.2915128232499786, -0.05359107726226209, -0.0167141837673077, -0.09941630815355153, -0.003665007998583435, -0.0299234883671778, -0.3018441136613871, 0.06749072049202193, -0.04549007934188216, -0.1272169539451481, -0.04604367173781738, -0.2292387384782596, 0.1104667012348132, 0.1037443269592589, 0.003358877836343526, -0.09748118788274351, 0.1190372958872585, 0.07594840982846023, -0.02118200682737069, 0.04505746778768557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.040421536922372, 2.090179325079248, 1.054133848546223, 0.1016135668098681, 0.1058908215655909, -0.1395436464948118, -0.0005843093291569908, 0.06576578822426617, -0.01954438761767608, 0.1340460322034086, -0.1079153000090457, 0.008558237228615952, 0.05442003661392834, -0.01948493437734833, 0.03204864462372618, 0.1899187419163797, 0.02651889944688371, 0.04143699821901681, 0.06155302263071664, 0.01361677379827648, 0.1864345911285355, -0.06057118267116334, -0.1079059175548875, -0.04926446070686546, 0.04450551753882914, -0.05461151981988153, -0.001886612406799282, 0.0366915411934175, -0.01306027401322379, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.017217105119183, 2.057885109672617, 1.717830826909398, 0.08026860099733665, -0.229664599517274, 0.08592953162584042, 0.07113555573927616, 0.1205711964241209, 0.06034607492733832, -0.1241960272046997, -0.02576402132560143, 0.100546870611732, -0.06664178017945782, 0.01551828302018928, 0.01075203286396453, 0.1648555544266941, -0.06180621835112392, 0.00904698466380283, -0.08614048879659969, 0.1377785336580386, -0.02458732719586508, -0.06527069420169623, -0.09919539357362668, -0.0371614630248139, -0.01956332576116701, -0.02610087976547117, -0.01636500296481732, 0.04290323999519369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.73126542682124, 3.177372305562633, 1.069892746405991, -0.3373448837554265, 0.04914183280708707, 0.2222099960511715, 0.1000273467845214, 0.02495153836835336, -0.2988822213671982, 0.09070115558214502, 0.006890792477648951, -0.09774415864582336, 0.01733122536241725, -0.06539161565511441, 0.4180846670181008, -0.1348357420052125, -0.01486736897403777, -0.1707564509631871, 0.275788236310813, -0.03928409265616119, -0.1437568066337482, -0.159713937527644, -0.06441082113320754, -0.04838713636560495, 0.03935472474969938, -0.03034455737023176, 0.1502866267461562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.9860332560182929, 2.457690638088044, 0.7585454975233088, -0.1838919851966072, -0.04382890538941454, -0.140552844264958, 0.09130507944212898, 0.001128260213507534, 0.06804648176327489, -0.03968302808799389, 0.02820745088433483, 0.03697025018803624, 0.06358690037762478, 0.08600302483044212, 0.04484515559448902, 0.08149618479019373, -0.008400294556984093, 0.1073491700579635, -0.06306885174166355, 0.02287587454966997, 0.01464609607772943, 0.03996572206258068, -0.03555777800156044, 0.01763122405260091, -0.01550330692085902, -0.021886735564678, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.8854567164260388, 3.24250422074227, -0.9209580946507911, 0.06835402983935927, 0.05640958121017869, 0.1025591786485125, -0.08943334614410312, -0.06811365067010508, 0.1109007141056824, -0.02177056785348171, 0.03875431100769289, 0.2363367275176182, -0.09273940436583276, 0.1105048998268415, 0.01324218642906586, 0.1204923454912281, 0.1300264818238509, -0.07418265989085007, -0.160155156583538, -0.03336518282890372, 0.03274839794300601, -0.02988917934624772, 0.0313012656489897, 0.02783060486964485, -0.03014058011457086, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.9647900465381067, 1.776310496646176, -1.171438051631132, 0.05140489138825926, 0.1299377347834004, 0.2201816497369831, 0.02994176320228855, 0.04558225788991847, -0.02505795321566107, -0.07354754829932028, -0.07990068462027206, 0.03705853127225793, -0.1892721965231484, -0.0414104999094905, -0.04365760163266805, 0.004082206348271171, -0.01640857151771855, -0.04917783956511107, 0.05677253037720179, -0.01538028417587433, -0.1057997510635607, -0.1262079630007641, -0.09383731776836683, 0.1119867440818691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.059667715135062, 2.869444516413392, -0.768053436705612, -0.01982926570738622, -0.05898277292649027, 0.08032989813585734, 0.02430925291918696, -0.05541157112738762, 0.01387900032498306, 0.005672434099991189, 0.05365330433412881, -0.04355934883978447, -0.02337398496984892, -0.01686799971841361, 0.1422537288231567, -0.05666452598379437, -0.1164424129736735, -0.154242271156826, -0.04516863877735287, -0.01545725267339097, 0.05268933296374621, -0.01791535900714333, 0.08893369086218253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.006637453830663, 1.684689844069783, 0.9123803878361401, 0.3537494043954367, -0.0934425457654232, 0.125950163184819, 0.0008929568569579045, -0.05163443135049815, -0.1076491218622526, -0.0453578935139585, -0.1495191189316716, 0.0001415820705124262, -0.05006551799497391, -0.128789667082152, 0.01100316880829279, 0.1037355563583926, 0.1230844198081173, -0.01355995466456035, -0.04069963982836227, -0.2068443754239467, -0.100425014495166, 0.005750041723483063, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.7847696566083294, 2.188950883712381, -0.6166420348084849, 0.05427293688357122, -0.09172120702478551, 0.01394828380275868, -0.04214925628047594, -0.2002409114863903, 0.2374547253440619, -0.07586414645695061, -0.02243126761233804, -0.09086994858618591, -0.06440645239833823, 0.02923240705539655, 0.1008328000734136, 0.0681346127852103, -0.03404818684407405, -0.03418035480719885, 0.02177303810889437, -0.08932854185081496, 0.05516897717457826, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.5961213393185251, 2.487671728233433, 0.9779431494823534, -0.08808252008539449, 0.07346845556012158, 0.03791477768403206, 0.1133987101884693, -0.04867168124335965, 0.1007529815412284, 0.07012067318801543, 0.04686393658752402, -0.007976030601315085, 0.009647274715336393, 0.04388047564013912, 0.1448956828911585, 0.09593976527370232, 0.01772056425810449, -0.01920422214800561, 0.07683802973941063, -0.09812807079543846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.990432056210743, 2.774709587520062, -0.9402258848421475, 0.01395715665576621, 0.05464370856162152, 0.05969855937401768, -0.09840756262028037, 0.1283282686407038, 0.01393286908802421, 0.0953055258318351, 0.007548139187554635, -0.05906283649224034, -0.0006153285921519075, -0.05497497151651637, -0.008769303020395835, 0.05051213594154082, 0.09095589353294919, -0.006367749500199228, -0.04367472066475442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.9556547348028801, 2.802801220763579, -1.059088183997589, -0.06046741386547052, -0.109550403372664, 0.1079992883617651, -0.1303209308383404, 0.005273660747274722, -0.103872667440789, -0.06600322769700166, 0.05217402045757749, 0.08518450366824531, 0.09805210958705181, 0.003600709399162004, -0.05665622206864503, -0.1159528275969711, -0.04404155725184447, 0.02203210385909037, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.063540216854957, 1.744535368562572, 0.7905163601870416, 0.02656379893207305, -0.007035839152219695, 0.04085917849823771, -0.009245974538993987, 0.0249953312582957, -0.003223257434620091, 0.005723442767043741, -0.01704173254774269, -0.006825269002180425, 0.001391384124621517, 0.005712500889522121, 0.03850120618331365, 0.01404973463460888, -0.01209325063900243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.788177934248775, 1.912200014248186, -0.7537507368298558, -0.0661262783848291, 0.05943707989564052, 0.02061524812146071, 0.02585592085441167, -0.02083197113611205, 0.003987942029650998, 0.02210665757083753, -0.02360486919891839, 0.005051227537696999, -0.0006754747654496297, 0.01013804196323632, 0.01058372156918393, -0.05401144478196152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.8186713915600072, 1.708711700739236, 0.6332443934946002, 0.0347014944537665, -0.01300019502207845, 0.01605786260146845, -0.02637192977655575, -0.02304218343188766, 0.02296628976143508, -0.01424547177831386, -0.03972717940911979, -0.1167021874016301, 0.06633764648895558, -0.1293541599290803, 0.004742672723613311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5157633499563469, 1.976352201317751, 0.6234503597941091, 0.01391296633390046, -0.07272602653366068, 0.0140570704220571, 0.01336752650183375, 0.05902767787103762, -0.08819062077742636, -0.02551451255772886, 0.1312142929003566, 0.01369744243814129, 0.06473360298498254, 0.01231850487143263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.6533080656351744, 1.758802439425837, 0.4318871049206415, -0.003082957500133511, -0.09814169758462682, 0.04175539354758488, 0.0235289164184994, -0.01629543995009982, -0.05231016932343414, -0.03672204848733453, 0.009389336932342413, -0.06142381433250257, -0.01010858967311151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.4817927293509213, 1.408851322535897, -0.7676055176021872, -0.04505523423060897, 0.01813562786331449, 0.03138728238085502, 0.0007373169379419269, 0.001847667170281647, -0.01640431370966648, 0.04696818974656805, -0.004393748298759055, -0.02848496648956977, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.7883892138973269, 1.746055173045302, 0.4846783430365095, -0.0003922243062844435, 0.01186867835550373, 0.01648380387048428, -0.03174672656471393, -0.03627511739090696, -0.004853687188112606, -0.06885884936290802, -0.004917829299265958, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5208363315616994, 2.037277859382022, 0.5232085356010402, 0.07175407188317283, -0.07019064479939288, -0.02385694223436976, -0.00819063541887864, 0.07192359009199149, -0.06656167507443485, -0.04927759893361527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5819314677010843, 2.130167978098713, 0.5667361680393177, -0.01053764587057425, 0.01592751856907668, -0.01111604356574088, -0.004404610058468247, 0.03850545663289814, 0.04729794670040405, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.6488904808178829, 1.974426530381294, -0.2820471741701222, 0.02456494941736511, 0.03486280653024869, -0.01809831529884736, 0.08408521068644187, -0.006474401058818371, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.3312307167387429, 1.235934836863219, -0.2452582871525679, 0.01878427096720662, 0.04975840840483642, 0.05672553943361373, 0.01742942062643791, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.2654365696129733, 2.208256891929066, 0.3360201888498769, 0.06660725081463706, -0.01286437627536736, -0.002070231898763094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3639062481633207, 2.248588741393716, -0.1889980205327704, 0.05688507493685012, -0.04579504315826421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.1624755988486198, 1.590085647221482, 0.1168533202179821, 0.005293082667091636, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.173908380119132, 1.450043378319349, 0.02765965035599782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02984095753646376, 1.759629990218614, }, evWant: []complex128{ -0.01716884621227793, -0.1844331609734137, 0.05200651487352193, 0.1336851109127556, 0.2020936631953806, 0.3566470363060668, 0.3627207699831158, 0.4388555152488943, 0.4776853636435153, 0.5598821450074998, 0.6249350549980947, 0.6791310689291772, 0.985877008147705 + 0.01929363300192029i, 0.985877008147705 - 0.01929363300192029i, 0.9908483217835712, 1.011990761364073, 1.130046345264462, 1.323698071765709, 1.348598229483672, 1.363190626641638 + 0.05400660173350781i, 1.363190626641638 - 0.05400660173350781i, 1.632832316477256, 1.646239548684271, 1.742738908029794, 1.763069014878969, 1.789601126186348, 1.945228042429256, 1.946373262056993, 1.997152389795002, 2.261322781594966, 2.286944100979884, 2.447712649969029, 2.557857506923634, 2.608379034892128, 2.653335615965549, 2.675270309760236, 2.964219802766918 + 0.01767482509567778i, 2.964219802766918 - 0.01767482509567778i, 3.014604817775139, 3.158289371199042, 3.311794215710077, 3.389894197376214, 3.553333074879877, 3.641274442796651, 3.857556223000175, 4.045817381029103, 4.330901939363569, 4.337313647767939, 4.527400487637496, 4.917229128467305, 4.985609414964091, 5.687686849958608, 5.79422309012183, 5.997813119506478, 6.732426637899077, 6.957609338485607, 7.529842664573327, 7.609108287806763, 7.761261355516287, 8.311941758006698, 9.07053741884884, 9.217944588000314, }, }, { // TOLS90 matrix from MatrixMarket, balanced and factorized into // upper Hessenberg form in Octave. // Eigenvalues computed by eig function in Octave. // Dhseqr considers this matrix big (n > 75). n: 90, ilo: 0, ihi: 89, tol: 1e-12, h: []float64{ 0, 15.87097792952162, -0.08018778146407576, 1.923854288576926, 0.2308884192434597, 0.3394611053158814, -0.137843056509317, 0.08273319299962868, 0.09094485832017182, -0.1932984706702652, 0.1180502933247899, -0.2497600660136686, 0.05058238526630414, 0.1559958264692184, -0.1159258671363344, 0.009240657808439554, -0.07576925270220009, -0.08136563335139357, 0.03812188405626555, 0.08890970810264923, 0.03109600803532232, -0.01649595143487545, -0.03210884292964193, -0.06264912164116895, 0.02576130685189339, 0.07030469513274047, -0.03577429596420342, -0.06755584096587573, -0.01609449751643862, -0.034609250889499, -0.006417485131372289, -0.03097242984568944, 0.009636702832094541, 0.03557221482377193, 0.03197869740177413, 0.006433398911967483, -0.01135683279223704, 0.005555822920782794, 0.005082647305173025, 0.009385366191684759, 0.008128896608623586, -0.02296712755081439, -0.003777413820214802, 0.005123235117691023, -0.001849213959133196, -0.02340110883416673, 0.03713005378535863, 0.001732375396842803, -0.002750608017025007, -0.008067437745595896, 0.007330916864526544, -0.002616316716217023, -0.006297132815168344, -0.005559964495164493, -0.009996463242082429, 0.005115046921377182, 0.001491016327339477, -0.000957347151456719, 0.006745577006930539, -0.004544035710017501, -0.004411949528299773, -0.006799740101884459, 0.0005344071027975155, 0.0004690847920096184, -0.004718575501368472, -0.002540214169642457, 0.00357159293854215, -0.003314789809413553, -0.003402372051470523, 0.0006527769815598059, -0.002716170091878954, -0.001540321517093821, 0.001756589868588563, -0.001379260966541515, 2.681259838616508e-05, -0.004307760317855304, -0.001109087032949234, -0.0001659937040461595, -0.0002235436314482387, -0.00119569899683125, 0.0005623327348935116, -0.0006320070189143994, 0.001043573892153891, -0.0008750118344396425, 0.0005348270042878935, 0.0008273143853381587, -0.0006622544067919339, -0.0008492128694001077, -0.0007986665099336194, -0.0009015882205421384, -12.61872336344661, -0.7232497785660141, 7.609159226285555, 0.3870426982100038, 5.924856640096555, 0.6102682886559223, -0.1693535996869482, -1.919018099340693, -0.2138609560373459, 0.8042623392399718, 0.8674124147325857, 1.331963567449537, -1.782290696158441, -0.8346237530841022, -1.552156412468403, -0.6151273144224881, -0.7391936693539152, 0.9311934770410842, 0.6166024938842418, -1.54644771695033, -1.776481997993627, -0.934164018650274, 1.955449870926906, -2.082936149197492, -0.222464503236819, 0.1331142802435182, -0.7633944660137448, -0.8176194198678164, 0.2746498608375185, -0.1119720547510174, -0.3046093297897633, 0.093708523663493, -0.1254384253653835, -0.3826156782538976, 0.9720657328245648, 0.4435611080311743, -0.002705519800257373, 0.4068502033494004, 0.8228026417475635, 1.898141183528268, -2.19419418629088, -2.26250233043472, 1.169369389476936, -2.320900757809857, 1.963641620262248, -0.9292511308866737, 1.20566753941007, -3.909359844030778, -1.745106869690986, -0.1674293744185332, 1.824325508201922, -0.611032518780414, -0.8172751651339325, -0.379367811436249, -1.118039132172379, -2.1156899896767, 0.6317312221182597, 1.675601832555065, -0.1958681401344015, 3.202902011360347, 0.2083144054490269, 1.651454396883902, -1.879950006164014, 1.114962429097019, -3.728120039552464, 2.115800549383747, 1.993994934513307, 1.036800346894651, 2.843012388647532, 2.665528597975866, -0.08443708961414848, -1.658265513220315, 2.825691629937317, 1.163068598831327, 1.032612155987785, -0.3464359914213002, -0.7374155713124153, -0.009825846309687306, -1.878310233217088, 1.038183449333641, 0.8683442149070821, 0.2096953654957043, 1.097533010763627, -1.40566207568186, 1.539718090250373, -0.3057191046244732, 0.9596910019319377, 0.4410690813618931, -0.01734977865916698, -0.7028527205475527, 0, -21.14096588949502, -11.77071611766029, 91.38817973790069, 24.01994594814793, 7.139034668143506, -7.77684013545977, 11.8189112903465, 4.350214240774185, -13.41161300072837, 0.8429515510200203, -0.1960485971162483, -1.892239827255886, -2.481138864200454, -4.993335484535367, -1.462743953230215, -1.649744938703439, -3.306123402194819, 0.6299802354863298, 0.006312776908129815, 0.7029217322720615, 0.1969979096896496, 0.6484394805159026, 0.4612739081461551, 1.218623710778157, 1.937283920899595, -4.274393204137636, -1.417028232311232, 1.761975679896983, -1.207846701077455, -2.947009378633724, -1.111456928119195, 2.001483835367479, -0.3273985739357373, 1.27142153234808, 2.470518283440578, -0.497592748085565, -1.01776837453108, 0.1736631347448449, 0.2170284795451557, -1.102797734602059, -0.8983239378242805, 0.8376082516437703, -1.015605628895311, 1.888662040615523, -1.813946159105028, 3.745871277192266, -1.691058864813766, 0.5544744103796291, -0.95962769863539, 1.495178118153111, 0.1369976805376806, -3.134133785033962, -1.134766199832475, -2.142472928604951, 0.4360359463007911, 1.080773790484485, 0.9136687613609559, 1.421868877932455, -0.4939788885367615, 0.01579620756278606, -0.4041188740514539, -0.3370957888349073, 0.4032844546374829, -1.281049156842126, 1.334866305935072, -0.4288161314791398, -0.4076960827986253, 0.8975402184760907, 0.008483305617251051, -0.02300021991545602, -0.4779200297205075, 0.8640559542693361, 0.6740166979504152, 1.271173988705413, -0.125268363712917, -0.02783785192682384, -0.7952831181002197, -0.1834134462936435, -0.3033906534395994, -0.1842466257842833, 0.3294577790658342, 0.4265858101126394, -1.050551059782219, 0.5557053448408287, -0.07549099980078718, 0.4485085972651929, 0.604772326452039, 0.02668915155289681, -0.35958437456048, 0, 0, -71.67241414253803, -12.6925239065222, -58.51026881403752, -9.923972440030834, -18.08337737101079, 23.73437311293314, 10.42624729020936, -7.39628437264571, 6.93334510855383, -16.20186028661058, 19.09098951338167, 7.231158491837533, 25.86051183536314, 4.692849852643402, 13.50562601772541, -23.8959783279092, 10.46795736800158, 26.42552249365325, 25.55147405605497, 30.98455252329583, -38.26426057779729, 41.72459242758727, 14.01187370572939, -9.227025126956866, 17.69341876066779, 17.7058942448478, -13.2182156659012, 3.273277215940703, 7.82096407961303, -6.540134857551783, 5.302726399754003, 21.6168229759513, -35.45773268931614, -39.5771763658349, 16.91907564224343, 16.55810765769962, 10.84170890675409, 4.539182245882841, 5.966139065523301, 10.43624249585104, -6.306944364017387, 25.11309378553394, -23.98463112536712, -3.253554932408899, -26.20327820737005, 34.95346757431584, -22.06848426488626, 0.3787905650745691, 12.79793983153946, -15.15662916810503, 30.10820985389998, 17.18239253486946, 26.44238280127885, -17.53916820777098, -21.59984930800645, -20.89069843604591, -10.62614963929214, -4.16861219455282, -15.8281632392319, -15.45413424684084, 7.28126264287692, -17.30978445489622, 25.83878482866339, -18.20409699627451, 1.341279973912325, 6.060701390094514, -0.9930555858249585, -0.4770067839263625, -8.050723322366107, 15.00633993006825, -10.12301020599794, -15.02267685265745, -28.87546819977945, -4.887384695963816, 3.812851132430744, 19.10682316350844, 7.478580657962908, -7.486104775378393, 8.24517564743228, -7.51905558097683, -6.644004835040043, 16.04319982377311, -12.24015636297471, -0.4152718733052826, -15.37260980717165, -14.36579932723399, -1.30513875795791, 5.356894027365968, 0, 0, 0, 88.73441744471468, -9.667604704172753, -22.84943872004879, 5.044285909895449, -2.76004875036668, 0.3050715430090338, 2.281066203460998, -3.081685045157843, 5.563173468318147, 1.196920824152984, 0.7508125732458136, 3.261490552895722, -0.1915889730517104, 2.178042983750966, -5.719722606964433, -0.808717831824074, 3.567750315780947, 4.405620166473985, 8.068713509838501, -3.974147763943233, 4.024558504483837, 1.343369353638846, -1.554164148226279, 1.397410693322202, 1.549071510171349, -0.6861822032616559, -0.03144220974090741, -1.503375319686877, -1.213563509509453, 1.485658175240746, 1.102628808733887, -2.836353822887371, -2.651198571403894, 1.944770277514162, 1.800720538730825, 2.925044559436877, 2.489394773406274, -3.99962439548742, -1.365153890760246, 1.729186611640552, 0.90732580595284, 0.02970965138899272, -9.802670261550649, -3.377885239589956, 3.311681996737421, -2.102890043550365, -2.752571666784161, 7.725320034635699, -0.8099349955071451, 0.5680350525364315, 2.461090824551101, 1.671002962178604, -4.651796111745832, -3.019627268376409, -1.456848301794733, 0.6765376227892419, -2.208873565004413, -2.755468168868538, -2.723938546851782, 1.844529360647301, -1.962817053181678, 2.77164872022158, -0.6312645341808628, 0.9959732581947718, -0.01141276076056162, -1.047045912982139, 0.9659655272370172, -1.069371622104567, -0.564318267120407, -0.9606489624515147, -0.3731646049074267, -0.4361324066751411, -1.228953081985217, 2.112718903093324, 3.774673462225595, 2.038526286226191, -2.037134562294253, -0.6272498215703869, -0.9130826952549337, -0.5356753186936942, 1.739354952287502, -2.607676632661601, 1.167128690015535, -3.643945638175477, -2.247788469333459, 0.4447578257714688, 0.8814188227164721, 0, 0, 0, 0, 35.22951028609684, -22.61691132174376, 97.10536643650998, -3.714742139430975, 10.06500336745724, -16.35785983037913, 8.78437693523264, 1.985132974393485, -1.609800726068471, 10.55631691645605, 9.224290477011534, 4.722637143581605, 4.125150731568718, -5.396683914299057, 6.364591301561367, 8.24526687743292, 4.911724566872895, 6.542687463438916, -9.348997687795265, 14.18011100433374, 5.720905431367072, -1.582673805208176, 3.789638114574857, 6.440267872588953, -4.901278147004489, 0.421175984045115, 3.797008789173352, 0.2579925025997163, -1.093437933585557, -1.126991905684307, -4.4057666178694, -6.4297958780832, 4.918610437583255, 4.893900733343752, 7.627382484342153, 6.943539836193181, -10.22700285291435, -5.21717606135954, 5.635670539663245, -0.61979670671329, 1.025327494294112, -29.98298952616265, -10.87852244502099, 6.724183768213139, -5.415447368170939, -9.131548344141406, 25.08685243604318, -0.5163094225162969, 5.436141320006754, 5.254969244047728, 5.189340308692745, -14.05566775803058, -3.790558233978546, -2.867451571946585, -2.265074057881479, -13.27098968249704, -6.419573660857155, -2.44809433119093, 5.262803237338727, -6.396156300345669, 12.9332727436708, -2.828158861124294, 6.494893307712784, -4.900718840392307, -12.17623988734707, 2.132680032576169, -4.239391092443586, -4.723934051879516, -6.984654958110764, -2.787156581230434, 4.744573069448925, -7.311973630803457, 14.86842763617212, 11.70461213488476, 10.92665646005423, -8.812367256417245, -1.725823238463376, -0.599065820210566, -2.268141253505947, 2.588966312561057, -7.560432899806777, 4.711500915754516, -11.63409451724343, -3.784667325499409, 0.9845255581998278, 2.917504056968942, 0, 0, 0, 0, 0, -116.0630192746665, 5.887300060633501, -55.36418027265255, -2.470006763999332, 13.03531089357281, 0.1172864444746298, 2.336301687054243, 4.34928920056458, 9.106206444726951, -0.8318917014102636, 2.753642271658936, -4.563539972366368, 5.616802475300401, -0.4836767449615566, -6.113950704235537, -7.384788928153566, -6.850835642415652, 4.436028327150289, -4.972441466665182, -5.074617872073305, 2.249115729647296, -1.27635805087233, -1.815933433231301, 2.59978300016936, -0.5676863289525813, 1.704036354039219, 1.966949252223741, -2.742379099660473, -5.759265103182953, 6.226978264278319, 6.392620681348136, -0.2885756166938758, -0.2986490248004344, 5.021918870709579, 7.495865991102269, -15.19741578062141, -10.52747112766237, 9.21669911214595, -12.00882240945578, 9.449065100345695, -22.03792558203701, -5.042603937347324, -5.034444931509023, 3.887859743790752, -4.92423649287837, 15.14459404442214, 4.709447859501895, -10.68403398232012, 2.785222602001631, -3.955139727592788, -10.90921547327889, -3.836568621330626, 5.465232651370832, 4.568243480001632, -2.511523602459496, -0.9621054122709324, -0.6044291916789493, 6.467023010391031, 2.662510020284552, -3.203951737691022, 7.315143747841559, 0.2986491524564562, 0.04345879316587933, -0.3120127984400304, 4.715818739144954, -0.3713148742857386, -7.592585985711748, 1.251675665881772, 5.563320889185214, 8.934186230540199, -1.034540314919822, 1.499762588438347, 3.648805772901489, 1.867765342642769, -3.856064394520797, -4.257325323439929, 0.9065282321682452, 0.9958862297862445, -2.214139637816267, -1.516486450508368, 2.326410461051852, -3.227358821350026, -0.4749483061012461, 2.179821376672413, 0.1114550663371978, 0, 0, 0, 0, 0, 0, 53.90645393584658, -20.01147603384238, 68.25945706992877, -2.001388852130252, -0.6303875033830074, 7.681723436887633, -2.793396522752484, -3.849646005163192, 7.47502807954784, -2.524396627852584, -1.112160063163965, -0.4457759133018216, -5.425351770541893, -7.213840725579055, -0.6234582007920942, -0.3045445372121888, -1.838748235944519, -3.05429610717454, -5.218058811930899, -0.3089178689448414, -0.07503528649101057, 0.1630591210001797, 2.58742687436071, 0.8589336965724809, 0.3026886986297957, 0.0616540381895139, -1.743768523575526, 2.75507802571559, -2.587808530052548, -1.25512695563184, 3.800814529165174, 3.132593897658502, 9.751967320860086, 12.09676139406092, -18.96514427687867, -10.33529268364038, 9.423861340153673, -8.118494925333524, 6.455831882458702, -13.89851030432216, -5.253096745704963, 1.482474561585576, -0.7990859267629726, -0.1919859569182034, 14.99486076662231, 0.8403897566592956, -9.631758825484061, 7.546859017133015, 1.761650219269993, -14.8002789790671, -12.03184495751378, 1.278761976352118, -1.043958743156598, -6.425946785515577, -5.130193263963021, -8.943747092721882, 6.884559516868113, 0.02054820847870697, 1.622114564484586, 8.27790706580309, -0.4201537658318323, 6.949197674374433, 6.109317458173291, 7.745771202714325, -4.383777284917787, -5.023236465266974, 3.152075902042714, 1.185720299074054, -2.570558625807648, -2.575936989524232, 0.7822876332433506, 11.50350236141349, 2.541100031822599, -6.266519860892538, 5.220802309799155, -2.7113287362323, -0.0782755292810481, -1.306667606835813, 0.9121698644456847, 0.07469182002148761, -4.645428950155893, -1.074584465997386, 0.6604539390114011, -0.1666067442015038, 0, 0, 0, 0, 0, 0, 0, -85.98674061062438, 1.162623410299333, -104.1491535027204, 7.969764337327856, -6.932488858320204, -6.767747448265724, -7.331077471298601, -1.288550484452708, -5.088257375240862, 2.763979746955463, 2.528081478578727, -2.575430737963284, -6.921068854524492, -4.018385524701809, -1.579042698955484, -0.7534247768022768, -5.324588385519177, -4.241013196984152, -2.113061191594958, 1.678130424336868, -0.2888364599120758, -2.575220703265352, 3.435198525295604, 4.161688539607654, 4.731385858073858, -4.276207990137705, -6.32017796521583, 6.190217309330307, 4.183836067935781, 1.849953972589691, 2.606132984461453, 10.00029158683688, 12.0615055907306, -22.12319815923896, -13.94593423436807, 13.56355336723619, -14.73390655737362, 8.504539865599947, -39.98652916386596, -13.54021158220439, -0.05790828602008728, 3.121363813023208, -10.26329339936837, 29.60358127644879, 5.640693459787456, -6.225202166414575, 8.49263970223689, 1.111516509579903, -18.45973622662288, -10.78955835552373, 3.866537233352727, 8.114971974287389, -7.188761733179074, -3.287441529549332, 5.156604610165261, 10.80793451072269, -1.239076505166311, 4.628996155335966, 5.792922582124358, 2.03417264625456, -4.707373530409962, -9.448778191150614, 6.51155292021117, -3.19382039380789, -7.177226661410774, -6.832018005921634, 3.442244659675745, 10.77505720982952, -1.609927625466521, 4.733127783256045, 7.444153456927645, 6.065657625755138, -7.768628874694797, -8.73223505289636, 1.578394964028069, -0.8054671616028769, 0.5972200288905033, -8.68273678581243, 5.453422469912097, -8.723308411603904, -3.656294698422601, 3.713788968458369, 2.245164999387903, 0, 0, 0, 0, 0, 0, 0, 0, 82.30322830941419, -13.16495817094656, -40.37221874531644, -7.156146024985344, 6.407626256610186, -3.070719411573423, -1.248781274591569, -0.09188094231426196, -0.14791454863577, 10.46460085885971, 2.511645220965021, -7.306021862635426, -8.821036218813667, -11.27778024004047, 8.299073644975818, -2.786388825153335, -1.404614079695401, 1.895971545970186, -2.374603998420206, -1.895908635885413, 0.4177297064772442, 0.3179694660965782, 2.847483353627781, 2.28314647154709, -4.251315293192437, -7.351627496507233, 8.45101495879304, 6.656324309408108, 0.05811442721379975, 0.352210596662256, 7.158242198776926, 9.604014490962273, -19.05916411574244, -13.48053537548751, 11.11056501341958, -13.44816425524262, 13.03794734916214, -23.56660744892662, -3.179691183297922, -4.31381647439135, 9.383878541906311, -8.241547161602726, 15.17745487655014, 10.50533207581469, -12.3496460656361, 8.196225745083185, -0.03575510420729201, -7.579890340619093, -0.7363093925300244, 8.756813214260761, 11.93727799717407, 0.3635376217139206, 0.4603703423631014, 5.507079480435261, 9.421116342576116, 5.29496740123859, -3.941393949093798, 8.749586295075376, -3.842933870553052, -3.434396636354037, 0.7496949834113942, 5.050293641980197, -2.449146742066287, -0.1213669699610963, -2.640456287197764, 5.565782021620873, 8.693308402974377, 2.307206522787629, -4.138693274221668, -6.245432457269187, 0.202505673386626, -6.566863879917412, -11.74280124769381, 5.642870396242308, -0.659648816152216, -1.690565064770402, -5.93672734719091, 4.422450101243651, -0.7271854445212377, 0.7895970235545322, 3.96205972546395, 0.3762898199575608, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52.18436402228633, -1.17071077050581, -78.74014811145696, -2.436421299700726, -6.158177326953696, -12.84920002328411, -13.40821294858424, -5.273362519386561, -6.872625202393317, -7.634332724591617, 1.036587235099262, 6.207608782298316, 3.391369867457635, -7.524695482267034, -4.223994548482144, 1.005090702038289, -2.66480555032824, 4.646608362152693, 2.243089562166944, -3.34529856305617, 5.740218757228164, 2.12882450346135, 2.939738798956252, -0.03146392010752049, 3.38958622345852, -0.2577487623574973, -3.051389295629871, -0.697296699287094, 0.6189380855708414, -2.814647546822989, -5.010744640386618, 10.8659101121065, 7.550151766381041, -5.138398331003744, 5.941882913285983, -6.24020929364107, 6.192495406215602, -0.1393925926206985, 3.522667688918142, -0.4029078058202559, -1.086721958116794, -9.106949733745292, 1.080723194973581, 12.43512076939469, -1.559991201757955, 2.834826471699229, 10.91592518979253, 10.14280540179991, -0.4312954736361566, 0.1698301469389144, 5.224021770744672, 1.399356722825569, 3.824858056231203, 1.187505521773207, -1.25027597821317, 3.154667536052018, -8.777523547457038, 1.485334722226234, -4.846848932499968, -5.331464798306308, -2.935610863284922, 2.146754442305868, 3.916678542801113, -5.097848412152915, -1.684939990487824, 2.003333243800943, -2.22594720641393, 4.656849950049951, -5.745353345757918, 0.6044487182322886, 1.596087705639433, -5.155786671036686, 3.16998966590795, -2.175693288642318, 2.801445787424951, -3.130319162400883, 2.85020826323644, 0.1640583474231081, -0.214298568273029, -0.1740891639628268, 1.273833756482144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70.09446168050651, -11.26895002135244, -48.54705040053749, 4.118431277865748, 10.84591029041512, -0.6748674802174282, -3.045053711060402, 2.014682374966249, 2.306026198573233, -1.350656230483865, -2.329953831978132, -9.588390292055525, 3.269359204435148, 9.980505686658566, 1.082807022265471, 6.273567735324175, -5.719240792932494, -2.503890374538294, 5.253867760378612, -7.368019321193995, -5.092315009287605, -5.608336565960785, 7.85433697392239, 13.05231727795986, -10.24473853042492, -6.497760170002005, 0.7720864098024787, -0.9464942766836045, -5.75736090996403, -6.449685187648799, 14.67091581503414, 7.752227657052853, -8.313707502058552, 7.618733560061307, -10.26315766622777, 49.66932226344804, 9.396595252505557, 4.646105097651882, -1.000511699400161, 17.50139800181348, -24.58127340300144, -11.80138366202307, -5.227433380710831, -10.13287460063552, -3.337359409768342, 12.99698337996271, 3.068027046277927, -1.951738372661316, -7.666145241687218, 6.9088789851311, 0.2649618535564444, -15.99488743024383, -0.7701348417963114, 1.505671187381852, -5.323669521268157, 0.5338896728895715, -6.748253910318381, 14.64352852958436, 23.40931931143844, 4.375219426823375, -1.811045463489342, 4.773508381777763, 10.818209698722, -5.294039411650939, -18.70264738152938, -4.975296365083204, -2.600819681501243, 3.308632477674194, -6.40160106179316, 2.538884420020582, 18.76233248591015, -4.114557081532237, 0.5111695455673799, -4.794755383844113, 16.67507540569322, -6.886183084140394, 7.719834159396155, 4.933410312388084, -6.089459478292116, -3.503666218213469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66.6637247212457, -0.5663386193537134, 86.66019711942882, -15.20175735117943, 4.314620867702222, -19.41396340483079, -15.38151259581058, -4.248235572512307, -2.600133694847515, 4.086685275316547, 6.543863987851957, -3.556770106796698, -8.862927415679744, 0.5940920961482564, 0.2891990484420937, 1.2985992187588, 0.6463973107839561, -0.1897507095552844, 4.999681085896536, -0.6439357872831064, 2.066718921953054, -0.1085645365015185, 0.1070768393458224, 3.026109517007545, 1.481907260983705, 0.1499047456480452, 0.9514718442208902, 3.068093096347056, 2.714461903454389, -3.99786212133959, -1.490015954498088, 3.704196600400429, -3.084024872438948, 1.383157275632034, -16.26579452857151, -7.173167896042849, 2.321998416940817, 2.275237906163105, -6.307537188875993, 6.209730858735038, 4.018421456135293, 0.9621119492629135, 1.945276954758256, 0.4126375340548999, -3.009694590378986, -2.629957817671035, 1.384131483830782, 5.687116562672569, 1.212032906758187, 0.4457093459378468, 5.044411045879187, 2.653766535846431, 0.2411195122877111, -1.543285991977046, 0.8571968890482712, -2.832787648800616, -6.089862603942122, -4.243058413925725, -0.2712347348375778, -0.7571525905438323, -0.1391757644986091, -3.374311051582727, 0.7719310852064701, 3.726864797116653, -0.7589171772472043, 1.688124623456514, -0.06145796388713081, 2.035112211335303, -1.275417314028715, -6.847693700987137, -1.324382865895411, 1.215308587453588, 3.389389718245654, -4.298340356096036, 3.252289347232091, -3.54897896652072, -2.583331482537173, 1.391546454632447, 1.526078993538325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -76.15771433854052, -11.99852507214444, 27.62893281995865, -8.886170208363085, -9.022500867915554, -6.483908690769347, -6.478797015907496, 5.436632960504888, 10.11648415512398, 11.05236551506778, -6.555078182021158, 0.9926522830872675, 7.012674375514302, -3.958653565895998, 11.89784449953233, 4.997490823792532, -11.71308595491765, 7.473858613545575, 4.526049765812032, 2.627760851429408, -3.543040309678986, -0.6545512958150839, -1.975237359166213, -9.752416598897163, 0.1746629230980583, 3.764199942242819, -3.523765142660245, -6.526579460908251, 12.86892013415631, 9.636987335709112, -7.71437307352219, 9.374585571980461, -10.09888573625552, 2.627000532523575, -14.35239184493451, 17.7934680232572, 12.24617038938174, -6.2027891597684, -2.117824121844527, 2.304085371600412, 14.52899092304767, -1.375604453625678, 9.300885546968621, 18.94646416924206, 20.59266172433305, 2.716897787405002, 14.41056423737162, 4.669781485892746, 2.929418504934519, 8.242335741048715, 5.40876543323668, 2.002902940983452, 5.6098816375921, -14.20093255834947, 3.901682718637671, -7.337643713401271, -8.218284944457553, 3.072811403558771, -2.292798328406445, 10.69584853135417, -9.650335290149327, -4.330515729410567, 0.5204595970152146, -1.624267060418924, 8.140164084847148, -15.7637122001724, 2.453007028561554, -4.499820926337408, -18.34001755668463, 9.796120126023718, -6.012926560200856, 4.434295362280665, -9.67082400790736, 10.4548835691208, -1.769628011664158, 0.4768710210096864, 0.3854758620192356, 3.320903327037195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -43.98223406015142, -5.032665049120959, 63.89171973078309, -17.03607126733364, -11.37762317554949, -1.901161248292645, -0.8260131144255914, 12.01428472457645, 5.352225349608783, -0.3266225326728286, -15.64216660863595, 0.3825939195623905, -1.494103371722206, -5.375511858816146, -1.862194375089014, 5.63824583310378, 5.360101148587418, -5.696506781095095, -2.080871954585809, -0.7829130324044875, 6.783149785809925, -0.3661710817347401, 2.462769544154133, -0.8126745345164752, -2.507928414100153, -0.7896746658950899, -0.4314818025686951, 3.924872737975131, 3.720963560907183, -0.9854313103876566, 0.5600582865792041, -1.688187106864158, 17.44248034254651, 7.56859337644358, -2.163244623250694, -0.7929207133815144, 6.398869750639878, -6.091736851159077, -4.728849132755795, -2.854085872325754, -4.826855364681831, -3.30106640664588, 0.2719713238103212, 0.2298412502409825, -0.853005758672194, -3.263371003058645, -1.287397261994707, 0.6221723886323094, -3.488369011339807, -1.414828169574871, 0.07717807180754992, -2.684195273815242, 0.2613139899890946, -4.206641018599038, 2.982830136882203, 6.657239919946693, -2.518089625188537, -0.4552654704803235, 2.298800483965624, 2.494983397734763, -1.284395189604125, -4.238400338443188, -0.6366063645353051, -3.325393279736908, -1.764225755959617, -1.813359309843393, -0.2947559613727277, 6.320461175365693, -1.048130219904732, 1.69129533904847, -2.336845279584976, 5.580341689077066, -4.541654669729592, 3.817079261725959, 1.972729191142582, -1.594128333779149, -1.535735104483785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -59.46738063214526, -16.09510211169977, 75.92651854229776, -6.959588443327999, -2.809913552100682, -9.062449485347019, 2.929935910954824, -6.516445771274741, 5.618312537880061, 9.794206647467506, 10.44206520884292, 1.504143210681085, -1.194672878944117, -1.206412082832246, -1.592792412630419, -0.8713955483970806, -0.4430245993565414, 2.114713938914445, -0.3808503381452496, -0.3361054648766276, 1.810321218052103, 0.06324533489118153, -3.207697984086771, -1.888840647774234, -6.337450722394116, -7.051669943095036, 10.24163394168822, 4.591682020148506, -5.157620119910969, 1.350695165969617, 0.7792033958582947, -0.8363399401868995, 0.8398917333791918, -5.122390663285614, -0.589942253467838, 0.1140765360111759, -8.180634436361872, 0.782695084020231, -0.4316505953196415, -4.677604739058501, -3.371394391221965, 6.790122165196175, 5.900302157317789, -1.138518787666086, -2.696524630738898, 13.39780057844131, 4.194434073284752, 5.363099243116376, 4.110197934071277, -2.070985188896846, -1.165572235840805, -1.241624822428416, -7.086628398680193, -7.575672638929711, -1.486981977191632, -2.042873730189658, 5.495814100326541, 1.841533297055732, -6.033390059069625, 1.625951790058254, 5.031090908642416, -5.215840389266634, 1.850639244782789, 2.092351976481545, -1.480623358531872, 5.911569449582607, -1.869423525406329, -0.8096475091606794, -1.000819809262052, 1.841395444723725, 1.081170909224551, 2.284559473058704, -0.6250480378852277, -1.559903447023968, -1.853970655342937, 1.547744137147876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -96.3647680893793, 1.199043513223026, 17.60420974833172, -13.06773608748545, -13.86009320666351, 0.1767817722626665, -0.5124263274350351, -16.26448243634644, -7.14143348503811, -14.24141019732697, 2.26049840163611, -0.5232284569456099, -1.920838853591793, 4.846489507057715, 3.042770898035555, 1.294385928313621, 3.262620434881149, -2.270944593759149, -1.408453286683619, 4.497236785795636, 5.977793107223872, 0.1340518117987963, -0.6905643209085197, 4.805322551598841, 6.502377969783907, -10.47261184903601, -4.131639902258459, 5.974051724377973, -4.360075843426007, 4.73500504926485, -9.718847270507625, -2.119804026495935, -5.657677043459689, -2.856025773969369, 1.756942740498222, 1.717927994018707, 2.836097818243513, -4.425043948906356, 4.283315817519375, -2.059940986323201, -6.307828936261935, -11.44715911847551, 0.3006681108636347, -5.507293839810647, 1.536345859738123, -2.26452399462477, -4.716331237978856, -1.255956886329029, 0.7042206945918659, -2.667007107490436, 6.672978852425663, 3.262254896828355, 5.937155133580987, 1.948386865395799, 4.552963709305849, 1.788332867713114, -10.63067323751173, 5.26892419774046, 3.167593513248493, 1.170780576616151, 1.205868492329382, -0.3777966262231325, 12.93219596919667, -1.629499482312095, 5.270759888996531, 6.75414771239083, -5.680238880370791, 1.763910811059415, 0.2558270515454605, 2.632569608785784, -0.6147023174800583, -1.873856188681823, -1.734814810908174, 0.7079064341945942, -0.9150650771583158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -23.02913191459475, -22.68355714527637, -71.45920181332552, -7.335069133951983, 6.88897969406801, 14.22303129604287, -5.713578960023669, 15.25375807101405, 7.31607076966181, -22.97972556461536, 1.773867719140929, -10.21928707943674, 1.424895097068828, -6.202938372907802, -3.564833182189926, 2.874044501828823, 8.685525653278034, -6.81311188053174, 2.764368126088952, -1.051923578466305, -0.9476817080611526, 1.161644143534287, 0.8923143965210864, -1.986614015969402, -4.795152281813358, -4.571219954943216, 1.206804637019736, 1.189134886949103, -3.389219761826265, -1.403036249676163, 0.1159085048840897, 0.8722638450337192, 0.6308893671254719, 4.417698737007038, -3.617011218574619, -1.59415231672244, -0.4094009736543018, -4.615708070111476, -5.105781556006933, 7.165268502604309, -10.27990343205298, -2.449496798762735, 1.740806437896727, -1.676699767804021, 0.4392602027266447, -2.822535542169061, -7.693191637559086, -0.9799315922761813, -5.464041140223222, 1.890629379194414, -2.234640399497272, -0.9456666715392037, 0.997606186316458, -3.110634577331055, 1.532640947608809, -6.76298600927938, 1.926980466393365, -0.3975761625796731, -0.1074936397088645, 1.428032551521818, -0.2307372170405339, 10.50672618228523, -1.043253387292014, 7.351732297170027, 4.654268870350594, -10.97263974298692, 6.22881607660602, 5.315813011291942, 1.976388766185981, -1.590375718577871, -1.91368371633717, -4.647761418706064, -1.035563975020433, 0.1409584860123588, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75.07192855828178, 12.10308470349448, 73.0310118247737, -9.646003904806241, 4.932961189760345, 1.718589369927463, -15.44305085297956, -19.92076242236019, 1.289853308008594, 19.44625320979492, 4.210588674471425, -2.579319144988436, 2.410104964471558, -3.865247564242535, 0.826851006847084, -3.631426466227551, -2.842039660907502, 2.249433450127177, -3.309261383458769, 0.6757720427689214, 2.35903348697973, 2.568255552039278, -0.321803303996427, -1.108091120089183, -1.412785938851775, 1.785124078160854, 2.573232078948616, -2.076416085393783, -9.312869029610674, -4.310360243055708, 0.07839735762587302, -0.4810908104630088, 0.9952395155647055, -3.886794543907047, 2.525965274526253, 3.540664673781963, -2.704864111340364, -3.864627721141978, 4.457179505634837, -6.813519964253322, -2.007416166791153, -1.607611533013739, 10.38000897763594, -0.3046634977924537, -2.266871922238326, 2.573731821774683, -2.979571190380482, -2.320864784735163, -1.500209869827327, -5.106748863521393, -3.950957911975269, 0.7340374884876252, 1.73889407335216, 2.182641990536762, -6.356098593894809, -5.93055977994974, -0.6040135105288104, 3.029168613692871, -5.042929510576918, 5.833709461846172, 15.29860079283752, -1.235961351707758, 9.34323445595332, 3.785951093156088, -10.34177459105045, 2.911648799971752, 9.281014378066164, -0.4941493880528656, 3.071779513490743, -4.517815603760604, -6.192250219969715, -0.3317883573330157, 1.349445179208848, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -63.45021054279741, -15.82766767521525, 41.22915354775575, 4.664008353213778, -1.654066901130316, -23.18254021974398, -12.84906013980607, -0.9626027911697629, 3.41433891445458, -0.06961595567794145, -1.096971305807928, 0.8698295584855787, 3.772196521299375, 6.631293883425417, -7.052125668571361, -3.200823343555333, 3.814349784726156, 4.941784929229768, 0.6315537523938005, -0.01802357802850369, 3.141620177813325, 3.10250469485239, -4.155135005432694, 1.701739006290255, 1.540814933013846, 0.7387665729315541, -5.311958621040922, -13.02405885670838, -4.942498894115073, 2.149572755504388, 3.341124951208096, 3.870026706159178, -2.46509460954075, 0.4769961681706392, 6.604145321870847, -4.15894453283208, -3.374029939123039, 6.807566765521488, -11.58698328431105, -2.80185415106152, -0.002148524464262543, 7.754192162202266, 0.5225981165001614, 2.195290230986459, -5.408948531637178, 0.1049214015983932, -8.924285492967401, -2.350089393085131, -0.5423255417785425, -3.219609856555158, -4.390973896320624, -1.269742631984241, 4.051212063679165, -10.36139506901704, 0.3230350713187323, 1.674998606949747, 3.540984566900865, 1.18972973091647, 2.057607076615883, 13.40112401714828, -1.748763782836714, 13.13716409027571, -0.2243177932456299, -12.24721484928519, 5.87773220153188, 9.74466077242022, -0.8896869572089892, 2.189477242908632, -5.208603883097037, -8.105641911969411, -0.7300180023457923, 2.022265831725371, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -52.66687486179152, -3.101783038688906, 62.54840137160225, 9.616670950233983, -12.50481143141205, -28.04924352555032, 18.7558503771284, 14.97634693290006, 5.851320122566384, -0.1677270839150571, -2.409084137352026, -9.845991621034058, -3.801336162247693, -0.9907297274053595, -4.664351290089362, 4.309633797495072, 0.6048954669030202, 1.543984136643211, 0.7189536403742964, 5.611415033458477, 2.487672542609962, -8.621934168449286, -10.05094063299714, 8.742063873037001, -3.490157247009134, 2.066460908332703, -4.477586251672978, -5.332933548411357, -5.713234560480118, -8.240059969073409, -3.364164696488402, 6.227061542811854, 0.1791896591361718, -2.507565879175399, 3.698854501954176, -1.007279474702307, -5.481898046206347, -1.72805442027048, 1.655718519783813, -4.101110323704863, 3.320297978932387, -3.684641982534487, -2.130960673414645, 9.904486582652764, -2.376262647862093, 2.148900292669743, 4.759998469058096, -13.36944502872464, -7.978751527858369, 6.863214185815936, -1.882367548219069, -2.561088530514321, 4.873981502571982, -7.579320197588544, -1.497679078782172, 2.35834379567061, -8.385645880902972, 4.09880893561949, 4.828417395745121, 2.282140125429291, -4.833463519506268, 2.913845215609183, -1.612937226837221, -0.5525869262187749, 0.6145753612090259, -1.089608686377456, -0.3258113829684524, -2.210223671018175, -0.8097847014254713, 1.266046990796156, -0.1222971055896021, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -62.97383455884989, -15.72156846847342, -50.52987429444124, -5.821406791941631, -6.271938286848207, -28.08098151092815, 2.368560549147725, -14.39710551246207, 7.569330972477777, -13.4264330861926, 2.75461801976173, 2.688711269115824, 2.764732074458091, 8.408341398358559, -10.04776489918815, -7.396363378028368, -1.149416203511894, -1.054301083542792, -10.04596380901379, -11.69408823775871, 17.38686456253957, 8.299516226227814, -13.25762288717717, 7.349031579684647, -4.534835890890477, 25.89116419268924, -0.01992743860632668, 7.982099277597088, -0.04160883712533649, 2.573520590529096, -11.35149838346194, -4.227617111120538, 0.2168974914804734, -1.795362046493738, 5.631764300285649, 6.008575066010116, 15.72428788595154, -1.842254414189587, -0.5382261085672077, -9.552315485913649, 3.675875209168321, -2.602166724352801, 1.859610651661533, -1.895505270339744, 11.52276237353004, -6.239279748413804, -0.1297742740578715, 0.6991046300254831, -0.4208529689673289, -5.060072193399457, -1.906088726339328, 12.62054139647468, -5.130598829626098, -6.128474594316537, -7.690481592824534, -2.247055264194942, -1.447577869543198, -12.36316455006643, 2.732894276344731, -10.27755222960528, 0.5243468721916534, 9.047719038239586, -4.383971076616716, -4.842518948484556, 1.125600151566935, -1.90225576696169, 4.722031005971605, 5.306544131294808, -1.877228890927751, -0.1571777681548308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62.52508007922609, -5.719488295515556, -63.28854566104216, -24.50023292372474, -1.974567606587724, 15.49864632949223, 6.998409457393456, -5.489144318408908, -0.6799511450744802, 0.6168873226031361, 7.888491941073679, -11.5213969968209, -12.02867471563315, 7.763694194348873, 8.334853365418969, -2.380451302943409, 0.09020014258787826, 2.3486772567884, 5.673982771176749, -11.02127409093227, -3.603461078419621, 3.167170753763195, -9.711383410279849, 4.723995107208117, -25.16138896067726, -12.23741325241211, -5.007012002050583, 2.190640446078525, -2.216636720328977, -0.5859489793413336, 8.233471386988535, 3.365237643930874, 4.189743657652521, -1.395157859959696, 0.3920210029284703, -7.056426817934152, 2.580560567814978, -2.128975130545938, 4.242435652432224, 2.235031188314527, 3.444275519482045, -0.7064127681508054, 3.521919688523948, -2.59915922665114, 2.796011561611334, 7.213677229286767, -0.2401477293445469, -9.239236230514949, 6.250101954381679, 6.220350851430839, -13.83625185491088, -1.200037472412707, 6.659714118020979, 11.18894360817651, 1.029186325547049, 3.013890675288255, 11.33035543805201, -0.7441654641054523, 9.147248359723497, -2.626393685016684, -5.110468073117602, -0.06530067048820608, 4.76431701962415, -2.253412642242864, 6.519983245052911, -3.976542599366748, -2.604614469192844, 2.348858737245175, 1.219946438299759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71.32602496514716, -8.756876217814053, 35.04911984263231, 11.85596450877738, 3.138232705310344, -2.194824321913857, -2.176583710259183, -3.343478177638568, -4.236563157562049, -1.392674203474749, -10.32262876392589, -11.63217516576671, 6.360303917047404, 5.478160154717675, -1.373379667953706, 0.1222360308529321, 5.92992964189494, 6.968285486207656, -22.24412202832642, -14.08200805003572, 5.255065130840872, -9.647401891006457, 11.00321233823368, -26.63174562751841, -2.523162844598605, -6.145124307805637, 6.022273738346928, -2.926653347515803, 8.133925760802793, 8.591428362280888, -6.013423802818253, 5.249342941582124, -3.970400887670635, -1.748951928295462, -11.28492868937306, 3.683276522805945, 2.775813620317148, -1.942462052184175, 0.8891846150120821, 1.129690076778026, -5.55530433211887, 6.228804252833361, -6.493720150589822, 9.095196357844529, 8.099379043388204, 3.282276517555831, -3.970254131193375, 7.47529332111375, 3.579752526867083, -14.72795586609742, 5.127558963939634, 7.483150275119841, 8.143770403634198, 5.638865762472385, -1.070704874835951, 9.665581065265565, -1.166404516592552, 7.118528213260745, -2.114185083787445, -6.481345817022934, 2.439165766212086, 1.688770678506234, -1.42208740458422, 3.736908500476163, -2.52099822967916, -1.096365312903943, 3.115453100212649, -0.09261316039995293, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -53.91482041296031, -6.195234141533248, -84.22720528023089, -8.228357964869858, -5.335191448255144, 5.056702938346606, -7.464695583224544, 11.90761078244647, 13.09090097966719, 0.6578496842921259, -10.92616341315019, 13.03744853784803, 12.44023007567226, -1.161373459354644, -1.087744561840636, 5.932731979531396, 9.315732460781408, -21.37551613946766, -11.96248596464901, 13.63024808396517, -9.288714959320243, 7.289554080422293, -28.16285634112625, -9.571761912856207, -12.95118012023273, -3.750611197225868, -3.922432347873787, 6.124510964031026, 8.396222723906581, 0.6148965037770432, 5.13355621975811, -5.15138967657882, -8.114413035924995, -14.85090329064167, 3.39729299292902, -2.657124865451653, 11.34942261680844, -2.606547131090628, 0.1623880304796317, 0.3049177006141654, 1.35635227366094, -6.653050626870728, 8.073015458686122, 4.32132583894199, 2.212964809408603, -2.184076048165147, 9.799834020565784, 5.96606727639304, -17.42599122311193, 2.990347710352649, 8.359376262684071, 11.42371296595421, 0.9821035082629358, 3.26846258160433, 16.37981065781434, -2.885803722420936, 10.97059625603291, 1.611945735717845, -7.260237552742894, 0.9012561107562547, 4.615303611480527, -0.2799207674436057, 5.037467804678709, -4.682042101547799, -3.881526357472375, 2.728902770049329, -0.06849225345413945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75.12896070864572, -14.55114803420073, -25.88520658421626, 0.3634408911932056, -5.749148081032294, -3.987054468607347, 3.605389714269859, 18.07840198100762, -7.822123425494485, 2.924157083708025, 1.962703760694055, -2.860064629683554, 2.959145172069614, 3.93868226857773, 6.366668810634879, 5.288829466990348, -4.294038560170033, -0.08801626773445168, 5.250702110881997, -0.3152641291658385, 2.199002653107061, -17.67833947760999, -5.045964490505647, 1.211048049454066, 2.421824405506, -4.376451661909966, 6.241973769898392, 4.290964226801218, 5.969309505771088, 0.8555684941579085, -2.217790960392097, -1.35718576281381, -1.746727805108543, 0.5254608653917869, 0.8086186851967726, 5.293064595586645, -0.3599247004146829, 1.959101109902374, 8.947006788222373, -2.378495602576101, 2.723709987744103, -2.329120911932814, -11.05882331472708, -13.0794383091978, -3.452514320213396, -1.512851055243775, 0.1639755205493351, 0.0825479539228451, -15.39065507630122, -3.091131632830409, 5.338329408636449, -8.829569668743607, 8.153591122859282, 9.18321870067153, 3.77411909040066, -0.7259214307321555, -2.707742728847757, -6.070142253582127, 0.8961401710073812, 9.291034725859165, -5.172620787510649, 5.77739330996065, -5.938409073064742, -5.68284811156704, 2.213899420332612, 2.230741101606077, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40.51083229358659, -6.657401086597119, 46.1651355827067, 3.571126140204381, -16.51018529197995, -18.81764925681962, -3.560003960730173, 1.069143039257071, 7.841419461017695, -7.426825297086943, 3.636227586276667, -2.832840975189855, -4.226091127266264, -10.32558071350056, -5.423718841813621, 7.898975963852462, 9.110182036344748, -4.818572270232188, 7.517064129930646, -3.069225466093795, 13.58082569251052, 1.95336044171603, 5.706764456088048, 5.029792791510202, 3.178869494747695, -5.047323754409704, -2.736438120770565, 1.426807143702085, -1.920567914619038, 3.428205422463726, 5.74585589697081, 5.382153677222462, -0.8865556423886194, 3.914778289385668, -6.604066141662078, 3.391876836068548, 3.169728760425306, -4.677156167446953, -1.155070546015535, 3.061191481464817, -3.13123995748959, 6.494562114793292, 3.376621926659731, -4.587404098548453, -4.277527442893002, 1.474886961462322, 3.323795372963384, 5.401089673065682, 0.3253871348814484, -2.369066423960044, 3.865796037257022, -1.638291040075763, -9.722922494527154, 0.5238103099430581, -1.203361374442151, -3.74503959737966, 4.569457144757759, -0.4965825177245843, -2.765019233250034, 0.2829604726448859, -1.146952017594104, 2.265032786536537, 2.680700571952246, -1.255503266954519, 0.1637658162738065, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -45.71426451969628, 0.3451233465733878, -42.83879591649266, -9.652152512053839, 2.943077049148836, 3.595807131194814, 12.07618358595724, 7.583721776261375, -2.798504129600953, 0.3493125113412846, -0.3060685650112926, -1.969954034839694, -2.226643423419492, 0.2775817976926701, 6.61252070570618, 0.2026442823847165, -1.756653814676166, 1.358336152476414, -2.953213341300402, 5.767247508163317, 4.576452080845395, -5.48265868666933, -5.584394192816982, 5.087476338922126, -3.141525913674985, -6.275099033613296, 5.577549390317852, -4.816802787505703, -2.484144702930381, -5.941817033794925, -10.3264911173429, -5.364557843392888, -7.843223405124702, -0.5283376840825795, -0.9570442251031415, -5.24883614050029, -7.185962189820855, -2.977003550332989, 1.181048111506568, -2.173863203462683, 4.403509726183693, 5.789771709589788, -3.251326838177565, 0.833293737507765, 2.197330074627189, -6.70359339703703, 2.969866449959098, -1.167049442438063, -0.3088855619701391, 2.234922153742612, -0.8743490423992627, 9.838111926343993, -3.681537357431789, 6.247482122998323, 10.24712337154277, -4.61734564949215, -0.06307486749200926, 1.334451074280191, 5.336299550216522, -2.297158597383811, -1.096756988788949, -2.950656621747207, -1.793982883674879, -1.379935304922622, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58.4305528833414, -10.93080151481084, -73.47222018485503, 1.299575050569214, 18.14449108892977, -6.050719753243367, 0.5840217211940599, 1.960086594084849, -4.368421952540212, 1.788116554787903, 2.164491069701282, 2.358970020887192, 1.093569678019126, 1.989649218755819, -1.28823196621902, -0.5313187250208743, -0.5624844430654856, -1.907667575555907, 6.909040860485212, 2.408127751390964, 0.4215555707913529, -2.780873876588656, 1.85248203975166, 3.135639744664483, -4.380299973926649, -3.921426250428929, 1.495099382458397, 2.622560565964388, 0.2177544811958763, -0.04339424448668048, -0.2214592105458387, -2.06944907992863, 0.1763703512794778, -2.846732426447117, -0.4639421303306322, 1.287390331822631, 0.6533086995560746, -2.425549690664099, 3.088053892492399, -1.130817472618208, 1.485446373139376, 4.380685859773039, -2.57028748480229, -2.127967029034677, 3.41369029366427, 7.568188803198317, 0.496744282104129, -3.964473757500087, 0.0282299427440213, -1.96849998024905, -3.553514188828535, 0.9438074995728989, -3.104500825703638, 1.724858829778236, 1.800147082209048, 0.224333685578572, -3.291601313990126, 1.370577599850704, -3.565441527576292, 1.823418080577437, 1.52484990001091, -0.828729219973382, -1.06107451712335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60.4551144650917, -1.112031735605267, 40.52296759779913, -2.279357391039372, 4.563291267943169, 8.295632041224566, -3.939508280061141, 1.942114905022437, 3.077992623697353, 0.6979345603294407, 6.071625856395872, 9.832923870768321, -8.720411873028274, -8.458375209728874, 7.032936679862646, -3.660503707293801, 5.13609182864828, -3.763326595416756, -3.646534951906556, 3.175402986994713, 1.020866860271357, -3.886824646779147, 8.218325748247384, 3.32404792165843, -9.200062655640144, 6.295889066677559, 3.845719933212995, -3.43351185274513, 5.438009428491434, 6.112353772294139, 1.228860655027741, 1.024037136509394, -2.139240304739709, 1.532357918757432, 10.1079544033704, 4.044497472104775, -1.295614976235356, 9.473469973585541, -8.029083475961539, -4.343462366128194, 10.84815682088869, 1.011633882504112, -7.169231098330976, 8.133704565655293, 2.691632282997318, 0.8507816064460101, -3.282652921494739, -4.061244378839357, 0.05112572018852947, -3.547751950024609, 5.30365786223212, -9.690997968552335, -1.734557454096158, 2.931578504521047, -0.5834918591113373, -4.496448398993238, -3.031542637377464, -2.036988448519847, 2.154422493546257, 3.299173741623872, 1.162415691741919, -0.5670591291688311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -70.06613504205954, -9.835478687386175, 48.52214856712762, 11.48136951108488, 5.892721436902954, -3.703795834979923, 0.8429544617402316, 0.6016790749403919, -1.12542788838987, 2.368548605557095, -0.6822772589146743, -4.287688004185707, -2.594460038219845, 1.811391939430363, -3.268064562811219, 1.460904850276689, -2.864974741945764, -1.034841388002912, 1.745241178328566, 2.486796799228639, -0.2269447058580376, 3.439717265105236, 1.02136554408696, -4.705182655489384, 2.499760827621522, 1.840963673652037, 2.953808675230261, 4.276133519908038, 2.651957942115774, 0.6355241666252862, 0.57194650441768, -0.1440454915229704, 2.242291193237154, 3.579445219558762, 2.752322997747827, -2.639308831991975, 2.4577698710486, -4.752199390601385, -3.863233755634323, 3.10435637509681, -3.028301690338678, -1.02478741743191, 2.754261908266995, 0.03535310362791887, 0.6383262792814937, 0.4368852433821509, -1.380097243200454, 0.281051180629981, -3.521710925389415, 2.247365619297284, -3.14338177048046, -3.302250573466052, 2.012036598405328, 0.1368976717018865, -1.193536497653941, -2.112322112549731, 0.1388066012915721, 0.8364226293226722, 1.307996121331485, 0.8916481210688338, 0.4828704628796113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -48.35160025190098, -2.541971211171999, -40.68153564873732, 9.207954361446687, -5.556985583068949, -2.844696785788164, 2.796718046185394, 2.464041987072172, 1.893613270308423, 4.028977435880829, 1.580350980861052, -1.926871386712014, 1.936201877177753, 0.03605266371746324, 2.628195057996384, -4.803264934471255, 0.1432706764330213, 0.1079385572562689, 2.678825585163418, -1.064180917349414, -0.5008460410343695, 2.882130267316084, -0.15398049667585, -1.581309397233642, -3.437020133996731, 1.265459202748218, 1.117834225134362, 0.1360954343911673, 0.9375505319888843, 3.243740457337423, 2.092675870695559, 0.04783544042641906, 4.765463295666528, -0.4641437505818906, -0.4785294697426362, 0.9696458103026435, -8.685566793141595, -7.008778621407876, 1.595549810231035, 0.3128462080006037, -1.324425648748344, 1.053200285772633, -9.359526652432077, -1.580936494199254, 3.673447578818254, -5.544913965708159, 2.361010918728093, 4.208995052675768, 0.06177199204784918, -0.7315046900899178, -0.358711190997884, -4.578123417453783, 2.050322078756102, 3.974849259098512, -0.7452561049821164, 1.594734714218798, -1.737806196971752, -2.031916066155333, 0.5613088668818109, 0.7078249129938057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51.98712898798419, -10.91279555750407, 16.5116520014062, 7.070082094300194, 7.316626743402702, -4.062538962997873, -0.7405273411971364, -2.403988646588473, 4.735499624487429, -2.288345916874214, 1.710004157792464, 0.7759293763857303, 2.319801872864849, 3.523736483172671, -4.063099150658085, -2.492051000480119, 4.11448548909593, 7.129988646336227, -2.243669991226699, -0.01638383640626986, 5.035870505157345, -0.9263294558811588, 2.097755508212908, 1.321512562673401, 3.748642620543865, 3.497629889280451, 2.535560833332076, 6.70155773507767, -2.222025277278504, 3.745469454508642, 4.860671405997067, 1.247993743903351, 1.366709222748014, 0.15728611894614, 2.359412737808513, 2.228713531327038, -1.291887607463255, -2.502446261947766, 0.8576018641230071, 0.2591128365637439, 0.1281550783740285, 1.457088120497456, 2.804040947211357, 3.04089132770398, 0.5933410236497064, 0.5620801447638994, -3.466284049616893, 1.640115928164911, -1.286700740977786, -6.179791106131169, 1.636998061183449, -0.2159342040060719, -0.3846813123879876, -3.023642425428129, 2.529816319670621, 0.03264733953770085, 1.353325216772121, 0.7761992320974147, 0.8335576498590705, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -25.43514166894322, -8.17729396479627, -9.755663509088453, 19.19784728348034, -4.384048886049747, -7.499153400798601, 4.435169145012178, 2.435444086759126, -9.059597245945259, -5.325657224831133, 5.740599830438042, -2.492050052381312, 4.19796696197511, -4.263587721918892, 1.77146723826956, -0.4935403175135217, 0.8862361772476778, 0.718637930367225, 2.234402910854942, 1.153322927018771, -3.443329198738874, 0.6587212840847486, -0.7054120735100874, -3.07872040612198, -1.371786433350092, 1.271824407901802, -3.947941817835058, -0.8336796717965617, 0.6116519681575391, -3.071696553703523, 4.475454076327929, 0.7609188629051276, 1.92281105267744, 3.40184922477059, -8.810192326908565, -4.590741833410618, 3.734024788110379, -1.509040639411721, -1.529465630170008, 0.9461084686824491, -6.75503144580174, -2.037690055578029, 1.030666583912851, -3.882610283293217, 2.375072374836591, 5.361220748281059, 2.030587685343521, -2.594516437562062, 3.173762351676447, -3.470985476419609, 0.8394945737986235, 1.011387559197422, -0.3451056702610979, -0.5600384586317051, -1.250437490195752, -0.6594046924812333, 1.043095979522655, 0.3317341014295642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28.99829564612994, -7.919492306918029, 14.05556909884386, 7.925941651982717, 1.30923833477671, 2.711408876410578, 1.61295413285611, -1.556599660832906, -0.8098128328747748, 0.4820136628666691, 1.242144749021579, 2.59270514147219, 1.070695817241087, 0.3750106994386846, 0.1725150645491444, 1.817115818968294, -0.4814506723964737, -1.161742890285604, 1.472007131837003, -3.436966082846573, 0.6982494240111369, -0.3149935878404753, 0.423370074395463, -0.9574295293157908, 0.2421056567329433, -0.5049850377885065, -4.679003799785368, 1.836812379169509, -0.6413835068300918, 2.492048982685315, 1.392871072424903, 1.054456102018222, 1.562804344198468, -0.5360913571726491, 0.2289458184750688, -1.348818559581913, -0.7324130913590041, 0.2525553513400682, -0.719825146825839, -0.6622690818866591, -0.05716678780881196, 0.03985333634237294, -0.3355682149483769, -0.1341481930486313, -0.2245769325773339, 1.701054496016564, -2.071735516197021, 0.7197321751353539, -0.5990693757732555, 0.7461182301273023, -1.28537860516808, -0.1752635447217054, -0.01940763082982118, -0.1985636316510818, 0.9478745916084782, 0.2042482439571948, -0.4223294809395653, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -26.09223882232648, -12.37682729616652, -21.27874182963862, 4.348357266610032, 4.573400992223148, 5.451216191750214, -3.611392020039598, -0.07921190808374405, -0.8260009529279171, -0.8434890069043338, -0.4552052508830591, -0.4528369276968658, 0.485445048833045, 0.7411599447890793, -0.4977249990635382, 1.190184399027994, 0.5973815546085762, -0.787231230010092, 0.03686032549901305, -0.4890816251224443, 0.5247759592075937, -1.879966027178497, 0.7792555164671459, 1.08723712738975, -1.42032534259863, 0.1721744481327533, 0.1056055009830306, -2.005790677375433, 1.016109801476819, -1.242159849121084, 1.243013696198364, 3.432482241304956, -4.523104088240713, -1.568715574671622, 5.119814672065328, 0.3791289530216432, -2.190682514501041, 2.552754170198622, -0.449368385418214, -0.5848836895616387, -0.9128519962622303, -0.9291921116478306, 0.6344008715643001, 1.688400124637569, 0.3633977049284803, -1.575721206061369, 1.961090047103945, -0.6752069375516031, -0.7855465024767947, -0.2102475861881171, 0.6869577789805948, -1.299232189451566, 0.5683367030798885, 0.3130637568892004, 0.1545378225570001, 0.3790410707685513, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20.78430083032547, 1.185047939349582, 35.77538180501586, -6.08934280503613, -4.628055061913704, 4.470155638785817, 0.1274755893885796, -4.165150926841093, -2.90227906734488, -0.845111562541671, -1.740136245099567, -0.7946086439652909, 0.165908004480544, -0.6322554553948885, -0.7202811048901517, 0.962291525388159, 0.1867569707618253, 0.7090001464102381, -0.9034980429447981, -0.7997832600818465, 0.1057538227773544, -0.2295775902801903, -0.2167480404571516, -1.707234755317263, 2.041285551224553, -0.7878934898873934, -1.430438536425756, 5.730418488030445, 0.6926510312478421, -4.339109958364433, 6.727134105417382, -5.329326344720556, 0.2090167614184525, 9.514829796739471, 6.99752035864157, -5.726866864790069, 2.796275247427376, 2.891078173635352, 0.5284713674492778, -4.068212458937251, 0.007838785072538627, -1.603613176227203, 2.0145967452931, 0.8759256044597022, -3.80096540098218, 3.215984538447468, -2.552801380633107, 0.554399068571981, -0.3103317501790938, 1.208594964868666, -1.283494125131377, 0.7998967241899251, -0.386450465669298, -1.202893469925367, -1.317846847748221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -47.41309320362173, -6.902809138581961, 24.68993718840007, -3.13534854977696, 7.054619343395385, 5.577611289513071, -3.877117196513223, -0.705447221487262, -0.8099002262119813, -0.1565635558190763, -1.127616075289359, -0.340714841660406, 0.660945871772091, -1.386755567315061, -0.4584883778560444, 0.9198751662032315, 1.002014450214894, -0.8640902794196041, -0.8777171102898179, 2.14825103785315, 0.989246034616117, -0.007095782785030112, 1.73906114106083, 0.6255059446607256, 0.1889696248858352, 1.03385909422522, 2.226668602394364, 0.1698945168834521, -1.873328492302393, 1.635950747204321, -0.6535224611564427, -0.5212140486619968, 1.003703892471871, 3.059411904595601, -1.892088474084682, 0.9339283828820583, 2.372361621792483, 1.133949816931869, -0.1994699011958669, 0.6535725484050933, -0.9195781603438848, -1.005444925904406, 0.06444426676642491, -0.8098171033672705, -1.318065403781523, 0.229094599479945, -0.1458840598162685, 0.2580570421599906, 0.599654091348747, -0.1055495042899468, 0.8993623666137143, 0.2691782537744015, -0.1099774106379499, 0.2977644683250328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24.74429137938651, -3.056148054133861, 19.0056932068058, 16.39870702492764, 4.267138497765569, -7.263096879020432, -2.919011924763906, -0.4167087337896431, -0.8396221408817942, -1.296684951975891, 0.7231090234720337, -0.1375746950653319, 0.4893869484915677, 0.3142640879884956, -0.2220967974170002, -1.109112753429507, 1.837593002510292, 1.479112432032976, -1.096302655894103, -1.964525246159897, -0.3280412024354407, -0.9206324506519383, -3.476018583754276, 0.6640599703563438, 0.3918183916355132, -3.395485381429018, -0.003002004945104059, 3.146782410011682, -5.072333819483568, 5.41257407183969, 0.6517585511003233, -7.269221543477382, -4.056630984171059, 4.210313402070434, -4.078813743290807, -2.25180663054022, -1.292189897325851, 1.427646253569202, -0.02497439324399699, 0.4774218280565992, -0.6503459447009956, 0.2399655638403526, 1.867125503961992, -0.9832308658323502, 0.3873487083709633, 0.05281139747950379, -0.3835529630274041, -1.6917245847278, 1.122860683946538, -1.59095315900844, -0.1293462709264742, 0.744401662451372, 0.550681606700183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -34.33789589268527, -6.878943247619225, -14.64721261322692, 10.01107177766694, -10.23942535961409, -1.01498039173437, -1.897412320562053, 0.1671533339857628, -0.8712694561978971, -1.083706765312663, -0.8072110203673344, 0.8308152015963188, 0.2147544944441696, -0.5493919968376136, 0.1446575439684376, -0.6832698103437359, -0.3948442858808979, -1.115588657559433, 0.3579803772248178, 1.360983446684671, 1.00664254181845, 0.463405794612902, -0.01621384683534825, -0.8228161891870686, -0.9063503571998639, -1.803563811674677, 1.773734326519576, 0.4302873906114944, -1.04322351848609, -2.826856356023816, -1.324768966730078, -3.650267019006124, 0.4946176831514201, 0.9765254105590534, -2.029801194780261, -0.08501190782368655, 2.178344340984078, -1.920968439027878, 1.468087622744764, 0.7608787750954016, -1.000741195716964, 1.504164739818004, -0.2688678814948808, 0.6600983722848048, -1.220320200367525, 0.2410125647060634, 0.1664703506451447, -0.00850398171402288, 0.147174562643468, -0.02779982278043158, 0.8346719111354661, 1.343056942062318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24.86877278577309, -16.79318934098175, 7.458488104737861, 9.49827773740922, -2.037264532584139, 1.252205231895099, 0.5394711870719748, 2.195699736074124, -0.06182472637253196, 0.7020281028590925, 0.3258270446041916, 0.1103891416148433, 0.2807839830050392, 0.8324674121995713, -0.07707017579260933, 0.04774101018547401, -0.6651862970621468, 0.5716949794838074, 0.2786641675385044, 0.6522299722084175, 0.9870590659751258, 0.07525858148281402, 0.2573717074126062, -0.8694521708682318, -1.166811640779638, 1.298799293918699, -2.203520860482713, 0.6442208455279349, -1.644267690640131, -2.625903488982017, -2.302992147951265, 1.257444945761727, -0.08416130603880936, -1.270800555411265, -0.7611165428890112, 1.039732198091014, -1.251481617872658, 0.668700121789956, -0.6911166576485717, -0.6139792747015455, 1.608281400168625, -0.2867634337303782, 0.1637144135551453, -0.00432411765221891, 0.07102947638320466, -1.167072230215902, 1.020402395737285, -0.8250836936353415, -0.6010780760217853, 0.1575436581466232, 0.3661602997463697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -25.48744110290001, -0.8196103125693783, -28.12739691634226, -14.66875241082419, -0.615739550477418, 0.7968006490105319, 1.893633537382631, -1.654939455947577, -0.6163475289447353, -1.258986228668871, -0.1685854638534228, 0.3466358666389292, -1.426194843008651, -0.2003994306001548, -1.259905297827965, 1.344072840361883, -0.688819755049539, -1.014480774303581, -0.6295918075499517, 0.1776953465799677, -0.2343489103275878, 1.245580834373049, 0.282925806992274, 0.9010886337902754, -1.886506785726124, -1.464163182582124, 1.060688891787593, 0.9766666550692192, -0.7971522349237924, -0.3026477025841756, 0.1569473405096722, -1.562229392252153, -0.5092349552596337, 0.330008450314712, -0.6335053028536132, 0.4247451599698489, 0.0985199006348359, -0.3513889048599413, 0.06524354177060393, -0.1957245081554103, -0.9317593740728739, 0.1952654121598859, -0.2590026012553117, 0.3001134383078498, 1.986414203689662, -1.071273239462749, 1.253278874165287, 0.33617967896085, 0.7395830923202225, 1.549701849275336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31.61694956773989, -9.578300913349803, -3.504213982861134, 2.937150834658584, 0.9888020778636044, -1.024980201460239, -0.5118645161888414, -1.146567755798608, -1.444823248641867, 0.119064333528641, -0.4696982483040331, 1.095121262010022, -0.5308991134969057, -0.5197247973700743, 1.05002708888555, 1.818937037971043, -0.464288009797318, 0.6619872266917841, 3.401021092823941, -0.9482749170371739, 2.813315825246367, 1.129476242162393, 0.1981687722797381, -1.019635015614744, -3.307198789311745, -1.432171362179824, -1.184749190478042, -1.044919901810701, -0.6539226010822516, 0.4625979387292016, 0.6826291685753989, -1.87320881210041, -0.02360508954848113, 1.040603087479057, -0.4961300270289009, 1.055913719807241, -2.655638121288787, 0.1835672294990115, -0.2887263743968013, -1.414391072650056, 0.9868620830546826, 0.6374153108068793, 0.1452572712918873, -0.3526782564487305, 0.6972915252755666, -0.01466270301749871, -0.4766248436639112, 0.2560860018610663, 0.5918528531262749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16.11268891122238, -18.88517791209816, -7.849457648122431, 0.5186009516658268, 0.9174633102810905, -0.4433385845787631, 0.259117803259069, 0.4812800928303352, 0.3809278637536887, 0.1040308979050729, -0.05696819922547338, 0.04177348257977326, -0.19151417247168, -0.9633478211800127, -0.1242642511041362, 0.3111175057895781, -0.0993555030948718, 0.9200983120151756, -0.283630744431747, -0.3768440931992381, 0.2608693517536536, -0.1701114694365957, 0.1657033422918405, 0.5579125426286559, -1.625886334801126, -0.3807035749043056, 0.9640891719563836, -0.1517544113079037, -0.06175882514010688, 0.4876052179200603, -0.1171970532950455, 0.01944444533954101, 0.4490968232071326, -0.4458741922044034, 0.3254420663099036, 0.5282760372591894, -0.05934694150103174, 0.1060201539053977, 0.8283931026778301, -0.4074091722040743, 0.4784701634625882, -0.02952608481148086, -0.1915663172505298, 0.1218560114391382, -0.3518484009580818, -0.2587618544226619, -0.1011116715064274, -0.4008733499435151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10.28612342841808, -23.92112732279337, 5.771795426117762, -0.8030148991959661, 0.04406286929137412, -0.2462851679259779, -0.0790329685264313, 0.5162614125094603, 0.01081766552358586, -0.3771532498914852, 0.2371657873877063, -0.1121483962706096, -0.598902253817861, -1.018195608367853, -0.01053082672842091, -0.3684877801366509, 0.3508826267234865, -0.2390155682927431, -0.1773909049534708, 0.1757923535233533, 0.2788684363679378, -0.521760862098457, 0.3153403198775502, 0.08909424355874358, 0.3382317489455293, 0.2248194206427477, 0.6112323344458919, -0.05266682106538524, -0.857521487871565, 0.09621919673355192, 0.1820135304582492, -0.03556509270831806, 0.05480383694627229, -0.05236763037981038, 0.9935679652239512, -0.01831786321756342, 0.205863157809067, 0.3066879134775455, -0.5897438503738709, 0.1809856006527006, 0.2304158672123705, 0.1357359363236704, 0.01081706136475033, -0.2019643081867054, -0.2674765180786534, 0.1218826125012657, 0.06599894348285046, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7.508940298192356, -25.92446548490683, 0.8596283612994251, -0.885296785459307, 0.6510912736108546, 0.04489469589179211, 0.1153490121088812, 0.6103383563995985, -0.6314156415588608, 0.01915715564342266, -0.5113720254650198, 0.08321272888636021, 0.2526155635642888, 0.07676680070437664, -0.207069381512334, -0.4238244829828506, 0.1598019632669035, 0.01979690071582769, -0.1131733213057336, 0.1678269137319559, -0.06128460713493483, 0.2950474603493092, -0.05777326473555904, 0.1081544273212701, 0.1350575367841474, -0.1382598662249417, -0.02063619586362458, -0.01748166206219487, 0.1390481463209892, 0.07165704302950053, 0.1349895003361674, 0.06236059106166005, -0.1944785128320574, -0.2787255380331269, 0.01560113047175663, -0.2002320581613433, 0.3115961907926021, 0.1635870368788743, 0.05678294158098499, -0.476018191230865, 0.3068760522389033, -0.3033131104805271, 0.3509349305650783, 0.3398673523876503, -0.02472276597655712, -0.1406202583056918, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3.938841061583187, -25.33986700948118, 3.895381103905187, -0.4068328885046618, -1.020248987608946, 1.875210227283616, 0.8326849356539051, 0.3197332657604331, 0.8814021905636888, -0.191597405724302, -1.189763075075068, -1.758874335134983, -0.01899353751647506, 0.0276611350365027, 0.5048267537307356, -0.5806174579955142, -0.02276182921702848, 0.4354081702397676, -0.1913814507405756, -0.1404271457144592, 0.4293939511517911, -0.2455037565707741, -0.6287458194591844, -0.4325390080784384, 0.5663792753160686, 0.06496758462505856, -1.013812891552513, -0.6580075377114708, 0.3012766122553553, 0.7826160029411943, -0.2956334704185347, 0.5829842798108729, 1.888181195419026, 0.2434171191535548, 0.4382404847806721, -0.2260461131572888, -1.002274173244901, 0.1511392353702925, 0.959534113889126, -0.7055427039674402, 0.6121511681849879, -1.070201333103883, -0.85450815461259, 0.3517683076365886, 0.2515058817628869, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.188440162629536, -18.32569924146616, -9.589804523680115, 0.3710427014950839, 0.3218205714481496, -0.2690828162556131, 0.3778764240350382, -0.3074423748293786, 0.005775081556014241, -0.01195607972614768, 0.4411561531339875, -0.03533727446997911, -0.1118188852301485, 0.5245470238731157, -0.01500837976097037, 0.2330462173829136, 0.3097172521421208, -0.1141404752456203, -0.03010554327463865, -0.3053455023961597, -0.568283713910994, -0.4659469523334061, 0.1389552806909783, -0.2547565634519277, -0.08627456156926228, 0.4559236364597809, -0.3852998773859254, -0.2059868514232366, -0.02375049165040808, -0.3131649641419055, 0.1909454021240402, -0.2322739633649241, 0.008020950818914468, -0.08341805591326434, -0.111253448846017, 0.05259516567515898, -0.001122570051102888, 0.1514471161594721, -0.0404691113211848, -0.008872368197677635, 0.0116933627886483, -0.09874720009960319, -0.03877084404075001, 0.05002466574186254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10.03537283004762, -31.0463181244779, 1.779031435921747, 0.5805779942073915, -0.1697490764077751, -0.01914980853094367, -0.2211539569318829, -0.4216165170128795, -0.6480115775079677, -0.4142538428904219, 0.06564004090328103, -0.4941714579440745, 1.034278660942381, -0.2047718684985376, -0.01268161547420685, 0.517525878890536, -0.1043791000267504, -0.3647396058345162, 0.2111603242370048, -0.9972172123676774, -0.5115981269692284, 0.4959144934872069, 0.04212237503456763, -0.0259339732866725, -0.1242882315804042, -0.4810924645313537, -0.02365156513499566, 0.2627756243130801, -0.5274144495229729, 0.2708662778382719, 0.8165087143124619, -0.1013704061972073, 0.2726522755404825, 0.3850625905291744, -0.5191444285929395, 0.1772802840204757, 0.3334115942202089, 0.1315431110247013, -0.02250684048613707, -0.169616886212142, -0.3125742719244352, 0.04507962853556727, 0.01003848565633635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.534564874870957, -24.59524017605734, 3.803193767088361, 0.1204388472709394, 0.5761719808045163, -0.1117681261275701, -0.2329370688709992, -0.08102002281001033, 0.1428619986726483, 0.104842791253757, -0.1181730570197248, 0.4589008851142075, -0.1080200483321708, 0.1900878438866454, 0.1999148634974392, -0.1482677353246511, -0.1560253005429775, -0.148698943892873, -0.5439804195128841, -0.4178164555772285, 0.1013788135893234, -0.2170885424796042, -0.02176885122945166, 0.2064156754855712, -0.3206810843761114, -0.04373791424112124, 0.2504839663865664, -0.28090563960889, 0.1385536322071997, -0.08959168523700539, -0.05811267349918002, 0.005219295271455209, -0.0006095068025606334, 0.05188819365042641, 0.05557911001260952, 0.07279423774972828, 0.07138061600398075, -0.03756847423989253, 0.02816926549231814, -0.07480288912090098, -0.006340103202835009, 0.0003644593817090534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.032984611804681, -27.23593121948949, 10.91195300159838, -0.1955025467061237, -0.3108776615407506, -0.3861125933123738, -0.2335216115611025, -0.9691736965590945, -0.2809799173614512, -0.2879486799582545, 0.2288415268907392, -0.06960881368743468, -0.3354356497684607, -0.3414928741679384, -0.060828537807209, -0.301089195863019, 0.200552261417137, 0.1352398329475678, 0.3340834458703997, 0.07377669861905928, 0.2564987850409935, 0.3238811050529972, -0.7225355496632641, 0.2551257047021489, 0.1771742636853869, 0.06594998613853977, 0.07018408521301191, -0.05587922004114503, 0.9700092972137774, -0.2579283194903866, 0.6519487404137869, 0.5508375252467951, -0.6490234945917377, 0.1447953357975773, 0.2164634615540051, 0.3169200204043436, -0.03463118539302083, -0.151318881732286, -0.2345691835471254, -0.01993158819697678, -0.05040377327442637, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11.4540626253999, -20.77158386493728, 0.8646709228308843, 0.1362724391608822, 0.1719025418456963, -0.2551996740096885, -0.03511714486680503, 0.1843273888070675, 0.1712704953498521, -0.08238211456267275, -0.0278396535204387, 0.09282985085557675, 0.2532178349906294, 0.08197119062309449, 0.0199260300618629, 0.2535665679716856, -0.1152352645199304, -0.1736314115581865, 0.01698268605977707, 0.04658947833988694, -0.1857939567479137, 0.01460595684305768, -0.05830186068372888, 0.03887623804842972, 0.1233901766950485, -0.03958735173141364, 0.07325984287647014, 0.01640653011899173, 0.1584691045459283, -0.2308825423077231, -0.1894450711707396, 0.01097836857891495, 0.04360019357535277, 0.005697416476426774, -0.2056452089585314, 0.04960126421902575, -0.09143466075759629, -0.0152240285154079, 0.07997148646231036, 0.03173856999389955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.214993452284615, -24.05350963927314, 2.935180686952885, 0.009367576430711424, 0.02897145608792666, 1.037258110070721, 0.1361330302043889, 0.267403438521004, 0.2041268631368911, 0.009677886298345676, 0.4513281035866327, 0.4879183299083247, -0.04366463541582642, 0.1415327697743105, -0.2267638854965378, -0.4997584611277828, -0.6976848080687116, -0.02518594676737141, -0.2588366599642389, -0.2416744762736605, 0.7221885872238599, -0.5539147131834354, -0.1134910123367641, 0.2737448220857051, -0.2927880039131713, 0.2057867576341399, -0.79800324914354, 0.1932584636177841, -0.5035224041067244, -0.5321735749435307, 0.5437275964446536, -0.1399374304829474, -0.07507775144608267, -0.2918402578666227, 0.09771036738785385, 0.1114599184651533, 0.1302712088256483, 0.0519407976536088, 0.06216196476169271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.947682961146469, -25.70508238397117, -11.46177925662307, -0.3724367020684367, -0.0346498317775926, 0.06864375351559394, 0.07554361694203379, -0.367323229127421, 0.09593202864671034, 0.1377534867847666, 0.1184603670917067, -0.02650248054294359, 0.2092301771249943, -0.009852203175540166, 0.1288173411245062, -0.01556723710218602, -0.2725343716448551, -0.04882125871058738, -0.1164191596901248, -0.01306504969938954, -0.09972247608276598, -0.05244353803868229, 0.08508888288435545, 0.01494712152255306, 0.06488803226510469, -0.1140190552259744, 0.1236269753074166, -0.2360969288917616, -0.1066473633353232, 0.1264867082185493, -0.02483266501799899, -0.04114542787579798, -0.1266313954297545, 0.03448373932480522, -0.05195144188753792, 0.03249420081315806, 0.03713923614715957, 0.01317281111328615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11.69631299718309, -22.48619259551776, 0.4736607761650089, 0.3364440611411286, 0.001896101447363962, -0.01839142547031177, 0.03683300808928491, 0.04804330923877288, 0.163622475873788, 0.1554000460872887, -0.08113035605009281, 0.0394436822356209, -0.1518190651150113, -0.2391233604051897, -0.1848160862235859, 0.005028918748719988, -0.1738801952717139, -0.1389518165707553, 0.2440059223399533, -0.1912611405349515, -0.1278732887547087, 0.03594552209482393, -0.1239443437214213, 0.07601115720720845, -0.2413170999853679, 0.01830028011033026, -0.1786719142755088, -0.05040746869497416, 0.1855068663687703, -0.01469530719590392, -0.03565818225935036, -0.006393469065442842, -0.02927051217417908, 0.04981431028590561, 0.01896848487153613, -0.02389638792932929, 0.001671298450249839, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.7907072650120487, -24.90261765607406, -3.336934808793186, -0.1100561385510806, 0.03806580362882676, -0.9795899124384002, 0.2113562476336533, 0.1210755170917097, -0.5709907672936722, 0.06148724086826907, 0.4281734290575387, -0.1228023758602741, 1.217889711872614, 0.5772065011935688, -0.8854453190120086, -0.02188476051865783, 0.2939683523215479, -0.3364845598685323, 0.4389370528196214, 0.2175645153244334, 0.1003089157346634, 0.5938129566146761, -0.2639007244911475, -0.4694860419564821, 0.0619677643285282, -0.05717000630200545, -0.3202406910706038, 0.378107742758849, -0.14006136421472, -0.248450630677327, -0.1410998107329354, 0.0735235604182249, 0.006870838292283573, 0.1952510899320096, 0.0282675631387419, -0.003424908838937833, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3.437730841654131, -33.27385476914327, -6.935734943236623, 0.2090812561111312, 0.3348393450135521, -0.223586923299236, -0.07352664648222718, 0.03785759488211347, -0.1513766386596058, -0.2099960883438794, 0.1017048240174961, 0.04182607962471709, 0.237579420640883, 0.2399067162829091, 0.07523955310772605, 0.05857405848698407, -0.05389473909058243, 0.2636593955046162, 0.1468245947741072, -0.1210583952104068, 0.1524669191535411, -0.214238636532872, -0.03816758506191603, -0.1354966639865573, 0.09316724617238126, -0.01615929313522045, 0.005900244511659499, 0.1042542689707338, 0.02949183866897195, 0.037267365131775, -0.07808591456574898, 0.03857619705636327, -0.07145363560926057, 0.002429628071270416, -0.01721018579426699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6.66333148382885, -14.4614219114703, -0.8464300600479908, 0.2514104375223278, -0.09861658442109786, 0.1691348097352446, 0.1896581102869329, -0.08087907706641626, 0.01174408327349146, -0.04072839225976889, -0.21084119330376, -0.2084820021746563, 0.06459499104581255, -0.07220761842989601, -0.08081244480389148, 0.2770967905223476, -0.1130641379249503, 0.01313709061334511, 0.1053117612678122, -0.08548227871695131, 0.04755230373305874, -0.239808392738221, 0.006594669706792055, -0.1160148635147146, -0.1546465218776207, 0.1797178820270592, -0.03514352886331645, -9.157443953328604e-05, -0.08036793482879778, 0.002475861135144963, 0.05097461589006569, 0.01013677531395254, 0.0105449596442005, 0.01367406076786437, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.019923386108676, -26.76235000723083, -5.231507339253204, 0.176832541192354, 0.3017249373834541, -0.1388443978394047, 0.2312643317132779, -0.04464652755082743, 0.07808084544420522, 0.4313216233613872, 0.3080530810133845, -0.3090015643058375, 0.2364897664214366, 0.06604367687341839, -0.1876613180395572, 0.3146210580156822, 0.1784726037504162, -0.02271540068963666, 0.2342699465461129, -0.1343387528471265, 0.06625828689355771, -0.003273887803178955, 0.1450943895905023, 0.00620258099433276, -0.09380102559767173, 0.01798478433460103, -0.07862806231355808, 0.05631636830032596, -0.0196969615930718, 0.04436104332404119, 0.05354400105458426, -0.02354762170847734, -0.02514305223947428, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5.177075859399771, -33.39258164773348, 1.63759177075579, -0.06342533195251419, 0.1411980486906961, -0.1464775848775387, -0.04431760714090424, 0.01154744252601158, 0.1026506579361863, -0.02088412824928649, -0.02902179807556261, 0.01304836720502356, -0.07271697524786641, -0.07325213106164481, 0.03704096648459854, -0.05922855466144863, -0.06262650371609046, -0.03182071956590917, 0.009080904737058308, 0.1354599956171088, -0.012606916831903, 0.03239503119872632, 0.1409587222872537, -0.06002807561785677, 0.04627926839441229, 0.02573135330017627, 0.004605365395089219, -0.08725168654474108, 0.002587419133345108, -0.05185185645936881, -0.005849547735873801, -0.009771554197080978, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.064718113513358, -13.12988850942804, -3.438372519392976, 0.1264586180050162, 0.004883996372652178, -0.04481988503927746, 0.09576485030352094, -0.3955235936343703, -0.2087500394183668, 0.3073328906227044, 0.02068102374422703, -0.1083588810681304, 0.1758168533371591, -0.1756277739685251, -0.07450374022378869, -0.01630094419723318, -0.1914647508380139, 0.08895278495397248, 0.1403814278690517, -0.03489253346297209, 0.01598763641739303, 0.1131830343890914, -0.06699742805657724, 0.00240472634967058, 0.05514166821797546, 0.03884124270426484, -0.01101385248527006, 0.01954817931909242, -0.03459346077345329, -0.01274466093412686, -0.003543141293631806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3.395368558938009, -27.6115795496259, 6.02328924849129, -0.0217949039676702, 0.01713458866911107, 0.1204807990971129, -0.1903985203838578, -0.245494995765684, -0.01567899867737631, -0.0483287391034937, -0.060209365295053, -0.00658859715813279, -0.1748730515278048, -0.1172896416076897, 0.002885900683208647, -0.2725962934388483, 0.1896424602622011, 0.2547718270544993, 0.08930762271234099, -0.05000517893940885, 0.198774168883364, -0.1836169107571341, -0.001441577306058042, 0.02027315191018264, 0.07922510191796643, -0.01081020778347853, -0.05485129878921055, -0.003504265936056936, -0.01741627502898858, -0.004300648475577595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.881439123068173, -31.86267091719867, 0.3170578648639695, 0.4687236230510464, 0.02662683343011025, -0.3302193472780357, -0.477346463679984, -0.0517454341931882, -0.3336060762108314, 0.09422553730446168, 0.04946779745885752, -0.5432213903814268, -0.2492264416620409, 0.1732279550240386, -0.09454901437534985, 0.243084678749923, 0.184313316080481, 0.110429054715389, -0.03650964419849936, 0.09749969511293206, -0.1326505036247279, 0.05009598527464214, 0.1082240240233409, -0.1489278834552438, -0.08096188906466491, -0.0850388793794887, -0.1125032485965546, 0.05122382376743441, 0.05527189635692931, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.7431797386269411, -14.65117500009382, 5.823447882655948, -0.1881157144876831, -0.3008729186775366, -0.2240680575846533, 0.02294923203244657, -0.1328373063914675, 0.01835629292837719, 0.1359000574454446, -0.3469510665265196, -0.1308216630102339, -0.03496464106937285, -0.2440104038689523, 0.04193512042581821, -0.1366336497635793, 0.03231520148337453, -0.1084198723292215, -0.06739647043502352, 0.08740658296680984, -0.05956248732431352, 0.05155443563206404, -0.06543491661245913, 0.06950710262417095, -0.02430554263388206, 0.003834848628751442, 0.03034298318482847, 0.03421651369935733, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.826424710849555, -27.75807925717017, 6.49845414271845, 0.2088222638768245, 0.2567583755247717, 0.1680006630260083, 0.07113722086014379, -0.03228298686790457, -0.1031612528617338, 0.1843360031254731, 0.07332196070209686, -0.01774216015656859, 0.2986364342557484, -0.00134569499401013, 0.05460048981943994, -0.02322575505419388, 0.08264206029436941, 0.08014218496669946, 0.02559186811441928, 0.06346651700418222, -0.0449661723444516, 0.02381879758386176, -0.08682020285221281, 0.08025959489260269, -0.01003292155179478, -0.02340991530415569, -0.02962714897774685, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.435188878061354, -30.23792586523732, 0.4023394954316882, 0.1442634156119251, -0.1020481640743369, 0.2616580251348765, -0.1059180761079543, -0.08743876827521066, 0.2785769450080205, 0.04428252801918474, 0.0202832410441884, 0.04189636473520755, -0.1103209617823084, 0.08801265177191683, -0.06151324254000396, 0.01355502488640757, 0.1011883046619023, 0.01940829963761287, -0.02376145032104872, -0.04253776187455549, 0.1015931898787959, 0.004439366426774084, 0.02720943797022718, 0.03068092663135336, -0.02169503454248668, -0.04815156165797598, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.23475181130263, -25.85002095399512, -9.61072734631551, -0.2587337302523749, -0.2671090327042298, -0.1373193461266922, -0.01686645319925775, 0.1214524395626546, 0.04787321250564932, -0.0102808929635468, -0.1079687161735285, -0.1204158425469933, -0.01370170730210608, 0.03896661385808254, 0.02006408734658718, -0.01957557336743487, 0.02048657847215082, 0.03186441907330201, 0.01437600500970395, -0.07256365762710008, -0.04268726613146586, -0.004291692030780559, -0.02959742701650543, 0.009784658017416398, -0.001361411062570107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9.668539275335888, -23.18029209894821, -7.104549227457261, 0.009494835170991586, -0.2155484926554607, -0.05117708716304314, 0.09558257063666828, -0.006204864175755139, -0.0535983098279376, -0.1721078109347795, -0.1292907195966384, 0.04463480683436428, 0.03962458796875007, -0.03394918991811541, 0.0360179426993984, -0.05098248960386708, 0.05421613324558673, 0.006517343947994034, -0.02849867886559621, -0.07880371848866945, 0.02642259523254391, -0.03587610810807455, -0.0153740561986479, -0.01461543749433446, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -7.000678311567365, -23.41161932249744, 0.1115405160634775, -0.07148023127921439, -0.03829631039398255, 0.4350529946111771, 0.1273341721442011, -0.03309653396004558, 0.07269741094613814, -0.2517627759593927, -0.0916540014643315, -0.09513082346238068, 0.02936404485630485, -0.03887824155586548, 0.03259923092993516, 0.01480224718798229, -0.06089794884744876, 0.04533354466816, -0.04401696277253729, 0.08384757422274537, 0.03447473565697338, -0.03655777066458333, -0.04286881746219928, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.1997455187845329, -23.67906930857953, 3.298493240502194, -0.1847467985210671, 0.1243176781235989, -0.02243375998252476, -0.0004203531178173071, -0.1373119846655697, -0.07119941044543882, 0.0598855239376691, 0.0365497555952217, 0.09940083973287311, 0.02170561702085787, 0.02523145542278863, 0.01398860677045751, -0.02099249665794002, -0.08042834487614063, -0.04514933257707622, 0.0210691994836113, -0.01304565123088667, 0.003317809080060446, 0.01880126864882835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.363427418619814, -17.41903576009931, 9.186568349711468, 0.1111029283919205, 0.08777631782411636, -0.0106122045071789, 0.1144225997334068, -0.02466841586746403, 0.02750112055321526, -0.05524437334870362, 0.04541263818821106, 0.04741842472464215, 0.03068743352629459, -0.03255656589538247, -0.03729968912772544, 0.01062121564506963, -0.008575892547858845, 0.02301960098527405, 0.01221098646015711, -0.007828736372639752, -0.02174734678713348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9.23220561660408, -31.51893707701785, 0.629104414809966, -0.002885901152494686, -0.04654352249775812, 0.05655136143073162, 0.04644981489440897, 0.04886269814398012, 0.01421146833364892, -0.02220699538623673, 0.05311321315234985, -0.001358424574760307, 0.00136891734406154, -0.01810167863750104, 0.05846985549778336, 0.02464847599577873, 5.045357884432963e-05, 0.02313650001543124, -0.01897592900555872, -0.01000566869781843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.6213531321316156, -24.30034243436851, -1.105212323117883, 0.1225585085553164, -0.2970472162797997, -0.1131121492749726, 0.005524192917051245, -0.005016083344128715, -0.05408343623542385, -0.02819561803866161, 0.009006334912992457, -0.02024545484485562, 0.03816393987230592, -0.0007047877611201743, 0.04901678014439114, -0.05163410574806857, -0.03130055103817821, 0.03533492988517593, 0.01195601678346641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.097158496205909, -16.73710946124244, -9.426989245602673, -0.06261182983602319, -0.1059035148370443, 0.05076346286898199, 0.003678172466163399, -0.0454660155043527, 0.02462054291284395, -0.02110890517636086, 0.008241203910568698, 0.02390589384329424, 0.01198364473687612, -0.02957542631061049, 0.002236629456648171, -0.02809381563903465, 0.001689229093064753, -0.007600764285513168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9.412003466484951, -31.65984264675678, -0.1254812244514544, -0.09114636575550933, -0.0366463804259801, -0.03322040198025862, -0.01209970867041294, -0.01021849930537397, 0.02256075215944923, 0.01825223707293363, 0.003993042619294536, -0.008507286595193135, -0.02427249385479496, 0.03381794787948238, -0.02914842372731508, 0.007082873675038417, -0.006655560097220788, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.27548187849782, -16.01246939790233, 5.644600469890476, -0.04244915968443123, -0.0371436610514518, 0.0530212677895391, 0.008626194479801664, -0.02358451461610269, 0.007412437106157236, -0.04628615223361372, 0.0826909370927158, -0.01312239177378535, 0.05019812567992653, 0.05643602731883488, -0.03169977188973144, -0.02409525389114796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.831745814038495, -20.41725582289098, -1.583013759260222, -0.02098081085371714, -0.03289988933600374, -0.006011309758863401, 0.03459650459981792, 0.01348477813223562, -0.02336540423557105, -0.003969872715414671, -0.05998169351462899, 0.05263821645435009, -0.0144354245014559, -0.005674777729486418, -0.03142277004383006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.562800616132969, -36.13433050173559, 0.2585654510438173, -0.02913169721040965, 0.002592481347938085, 0.004329834978588065, 0.06325089767860387, 0.01951445115945309, -0.03070674283592272, -0.02183384192678349, 0.009849968434859515, -0.02891816499635688, 0.002667591177598971, -0.02361460878909238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2286035973327459, -15.02261004686781, 5.184122379409034, -0.0264079721355016, -0.007786216137000334, -0.008663526410932022, -0.005309693290799501, -0.006680538291880966, 0.001397532516833339, -0.01528554327177548, -0.01182046150296639, 0.005955666147884051, 0.003523919303238692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.214570242697843, -21.4621144179193, -1.555874989179182, -0.001447535808513384, 0.03124103143611023, 0.01560612912433155, 0.01254222023040845, -0.0006565581414721336, -0.005837445535672976, 0.003328905310192099, -0.003109407401498421, -0.001359993487917328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.575215080762542, -36.12196181704586, -0.009581763987488548, 0.02181190823948241, 0.004249343259232833, 0.008866640947567769, -0.008827428692463307, 0.0111903702615688, -0.008259743446844802, 0.005994103918828306, 0.02884522108807095, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.02332478841374811, -20.31760288431249, 5.902175782312199, 0.01411291075117598, -0.0401626029282366, -0.04333034577745157, 0.006563645334078613, -0.02686027801335236, 1.82653938945055e-05, -0.009451944888619017, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.843446424852287, -17.22694391469142, 4.615021811975704, 0.03880112444568462, 0.01156878860697344, -0.02011735633875036, 0.007254465185871957, 0.006976302646061595, 0.01061407563995378, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.636349195088934, -35.03142250661902, 0.03540637402307944, 0.006380325215592348, -0.01715112535803765, -0.005381045082520479, -0.02796704437114206, -0.01837431744975316, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03325953074641371, -17.29072432858197, 5.995094557622266, -0.004356649575832386, 0.01324648360020382, -0.002576747161993423, -0.0164552533090047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.976772821535572, -18.99788030681546, 0.01396461545715264, -0.007601183590626498, 0.005853929901760483, 0.0201199907208218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.002983340164191267, -20.0342372815637, -5.741448414658583, -0.01215113512395332, -0.00662723431795657, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5.752040939724589, -16.25515722920224, -0.00713497387655803, -0.004958024634924642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0004916632598946193, -12.09805746213948, 0.000198676020167099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0001765653829615133, -12.09823117436413, }, evWant: []complex128{ -0.2513649571095319 + 26.5196181977274i, -0.2513649571095319 - 26.5196181977274i, -0.3323427794627154 + 14.12147023570828i, -0.3323427794627154 - 14.12147023570828i, -0.3885760957072044 + 34.01549575140551i, -0.3885760957072044 - 34.01549575140551i, -0.4938394681672298 + 19.28755724237434i, -0.4938394681672298 - 19.28755724237434i, -0.5354723308245726 + 44.07811563049843i, -0.5354723308245726 - 44.07811563049843i, -0.8831210193505878 + 40.64617136580856i, -0.8831210193505878 - 40.64617136580856i, -1.063691744877652 + 54.90113796777709i, -1.063691744877652 - 54.90113796777709i, -1.270999250073418 + 55.92169849615225i, -1.270999250073418 - 55.92169849615225i, -1.641962795944021 + 124.0727533257146i, -1.641962795944021 - 124.0727533257146i, -1.866212165366329 + 67.51198073484791i, -1.866212165366329 - 67.51198073484791i, -2.66562659457705 + 102.4818444744388i, -2.66562659457705 - 102.4818444744388i, -2.677285588970379 + 109.3976583973073i, -2.677285588970379 - 109.3976583973073i, -3.592328373007462 + 116.2450441105874i, -3.592328373007462 - 116.2450441105874i, -3.658587455178502 + 105.6223525143237i, -3.658587455178502 - 105.6223525143237i, -3.738335632746128 + 95.41374995650723i, -3.738335632746128 - 95.41374995650723i, -4.05659124602542 + 85.08673687146815i, -4.05659124602542 - 85.08673687146815i, -11.7967401639067 + 0.03421683561959875i, -11.7967401639067 - 0.03421683561959875i, -12.06591356324058 + 0.03010079020722811i, -12.06591356324058 - 0.03010079020722811i, -12.08354870692898, -12.09435136773809 + 0.0007639916648241464i, -12.09435136773809 - 0.0007639916648241464i, -12.09785209014901 + 0.02991559300476182i, -12.09785209014901 - 0.02991559300476182i, -12.09806212746318, -12.09850417485291, -12.09864274565634, -12.10160612637007 + 0.004700099158908263i, -12.10160612637007 - 0.004700099158908263i, -12.16873692768957 + 0.02446545858852495i, -12.16873692768957 - 0.02446545858852495i, -12.23495190373921 + 0.1453184367031505i, -12.23495190373921 - 0.1453184367031505i, -13.54778407074696 + 141.1839768257274i, -13.54778407074696 - 141.1839768257274i, -15.38790969472481 + 114.0584849752244i, -15.38790969472481 - 114.0584849752244i, -23.60369882806601 + 0.2464158068361128i, -23.60369882806601 - 0.2464158068361128i, -24.04314341198735 + 0.3315626206724418i, -24.04314341198735 - 0.3315626206724418i, -24.12753399862331 + 0.1634093642552133i, -24.12753399862331 - 0.1634093642552133i, -24.18103712080912, -24.18908889661277, -24.19357072143492, -24.19567681157636, -24.20660003986661, -24.228086198612 + 0.0220672004906673i, -24.228086198612 - 0.0220672004906673i, -24.30677145425284 + 0.1813999700804981i, -24.30677145425284 - 0.1813999700804981i, -25.23862373866253 + 0.8733279005402655i, -25.23862373866253 - 0.8733279005402655i, -29.42427841595277 + 1.666886570068163i, -29.42427841595277 - 1.666886570068163i, -33.94959271558832, -35.51958918286584, -36.20666045708104 + 0.1660921702962803i, -36.20666045708104 - 0.1660921702962803i, -36.25710351845593 + 0.01052251476620707i, -36.25710351845593 - 0.01052251476620707i, -36.28714605125749, -36.29431583135849, -36.29711199023137, -36.31304183793699, -36.32232768169418, -36.37871120972082 + 0.1557647672076243i, -36.37871120972082 - 0.1557647672076243i, -36.47694233727385 + 0.3738707259908102i, -36.47694233727385 - 0.3738707259908102i, -36.66483183150206, -37.75937189360096, }, }, { // TUB100 matrix from MatrixMarket, balanced and factorized into // upper Hessenberg form in Octave, and embedded into a 104×104 // diagonal matrix to test with ilo != 0 and ihi != n-1. // Eigenvalues computed by eig function in Octave. // Dhseqr considers this matrix big (n > 75). n: 104, ilo: 2, ihi: 101, tol: 1e-10, h: []float64{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1063.761, -960.3970563202379, -0.0006079108185996773, -0.009201940691316367, 0.002442836240270196, 0.01550988534551903, -0.005482455008401117, -0.02216870959395947, 0.009747347615349792, 0.02941831540681939, -0.01530136178573213, -0.03750794345694437, 0.02225359194453896, 0.046705617938318, -0.0307619752542162, -0.05730825585675074, 0.04103856105936231, 0.06965250072575992, -0.05335624663776811, -0.08412633500439758, 0.06805680196063389, 0.1011811513254484, -0.08555957035531082, -0.1213434441393789, 0.106369291926541, 0.1452243676184516, -0.1310809449650698, 0.1735240650736495, 0.1603769717276725, 0.2070245946752049, -0.195009056622052, 0.2465616197175694, 0.2357520481176992, 0.2929587463757468, -0.2833105069304027, 0.3469005841220431, 0.3381503031304328, 0.4087132445918312, -0.4002236126054999, 0.4780213717840138, 0.4685650013761221, 0.5532750093152425, -0.5407842250274101, 0.6312148133425258, 0.6125866029330725, 0.7064838330293224, -0.6776224584955323, 0.7717672671130079, 0.728093737707456, 0.4477228711606641, -1.832801684441419, 1.950252997191289, 0.804390452586547, 0.4832557718849113, 0.3060066166102118, 0.2756451553030591, 0.1719798268352208, 0.1844690914416081, 0.1028522851629666, 0.1338501876768783, 0.05922545829023376, 0.1041210893998114, 0.0294781768570502, 0.08738772703908808, 0.008665658061761334, 0.07957418017688388, -0.005841802748350547, 0.07832978350913038, -0.01561691241238414, 0.08229737118429636, -0.02164114160477788, 0.09076446627208183, -0.02452178964005379, -0.1034535010713481, 0.02461324557496748, 0.1203839900069163, -0.02209524508102444, 0.1417838483570761, -0.01702626635186736, 0.1680394493064578, 0.009377435518891378, -0.1996795871970759, -0.0009558646643977288, 0.2373933824702814, -0.01416583764558031, 0.2820880046959302, 0.03057782300299389, -0.3349961435755344, 0.05073634798692103, -0.3978562481735693, -0.0755607412701291, -0.4732063781751494, 0.1066126139010085, -0.5648764073871733, 0.1465759215609417, 0.67885880956596, 0.2001993093624898, -0.8249735752515708, 0.2762967421832379, -7.383366696690373, 0, 0, 0, 0, -504.7000323579025, -960.7839130908893, 455.6939154064305, -0.0005890239049151091, 0.01222453307167895, 0.002380254112046573, -0.0183767018575125, -0.005347164384529943, 0.02487432959226112, 0.009507444863507727, -0.03195485414878263, -0.0149219770912947, 0.03986517031337426, 0.02169664773526838, -0.04887103316029169, -0.02998576954964119, 0.05926702273427436, 0.03999696952048423, -0.07138712464416012, -0.05199744338214077, 0.08561585141999975, 0.06632116378894419, -0.1023995009673016, -0.08337613594660015, 0.1222563158317329, 0.1036500341236005, -0.145783656379474, 0.1277114126111218, 0.173658096672846, 0.1562008437363875, -0.2066214365478053, 0.1898032066448404, 0.2454413266872829, 0.2291867817273585, -0.290828708487696, 0.2748879884412016, 0.343286767980235, 0.327114242278849, -0.4028620578438859, 0.3854382883926989, 0.4687761898935385, 0.4483798648521518, -0.5389586517254393, 0.5129393074648648, 0.6095951621601606, 0.5742741750224843, -0.6749584326212456, 0.6258664262549096, 0.7279030750048989, 0.361160520701244, -1.817820120247178, 1.493677993805868, 0.9093218408940651, 0.3437577565805193, 0.362630116371123, 0.182491216989941, 0.221714417427429, 0.1064242506044702, 0.1554403491948274, 0.05893517713417926, 0.1191987572531298, 0.02593630450949156, 0.09940153443435777, 0.001987949044964486, 0.0900967012871452, -0.01567758628187121, 0.08812023104053984, -0.02871634215129631, 0.09168600701701864, -0.03819855166921124, 0.09983277639781361, -0.04483241285443643, 0.112135778661831, 0.04908165568011769, -0.1285288605462619, -0.05123906116349945, 0.1491912175066926, -0.05147890107583802, 0.1744806002258908, -0.04989507359069757, -0.2049040909139878, 0.04652399206028981, -0.2411228487302952, -0.04134974220480257, -0.2839940475275046, -0.03428683940013912, 0.3346573639346669, 0.02513376678028306, 0.3946840836316033, 0.01348469011538719, -0.466320753537143, -0.00142779450121434, 0.5528931223683594, -0.0210105793668851, 0.6595061978534259, 0.04783831497380739, 0.7943401758885881, -0.08674091416897045, 7.282263793289921, 1.964402124200457, 0, 0, 0, 0, 0, 504.7001065567226, -960.8071533894852, -455.6899665187256, -0.0006381542544069418, -0.01696123848664222, 0.002571421839873352, 0.02356372357492877, -0.005765057328779014, -0.03054576659236009, 0.01023675166561691, 0.03816637411322649, -0.01605159633648196, -0.04669530536153424, 0.02332395960802052, 0.05642332124514469, -0.03222102273610906, -0.06767293164234266, 0.04296780496196387, 0.08080966049331523, -0.05585344634069236, -0.09625362412257953, 0.07123822293842015, 0.1144906642960898, -0.08955981060276022, -0.1360815254382584, 0.1113369911164654, -0.1616662801387938, -0.1371665625346616, -0.1919585350680096, 0.1677064944291291, -0.2277205865868329, -0.2036342514104135, -0.2697050947227386, 0.2455629056115962, -0.3185418058062836, -0.2938904117765113, -0.3745411973588626, 0.3485540671441012, -0.4373871729832214, -0.4086704182323145, -0.5057124011628437, 0.4720841567744535, -0.5766169045256523, -0.5349437472430429, -0.6453152755169759, 0.5915742979267851, -0.705252589538002, -0.6350313138183948, -0.4095510871717013, 1.601644767644169, -1.801430257336091, -0.6783540858316911, -0.4521876448242478, -0.254377814677483, -0.2609137525907964, -0.1390187634586346, -0.1780644458672355, -0.07811098364662258, -0.1332228921784263, -0.03844450844393983, -0.1080065082071247, -0.01031758532230231, -0.09498853030853376, 0.01036100507490249, -0.09032395086444481, 0.02576859065961766, -0.09180684083159034, 0.03723131440198095, -0.09818648544931335, 0.04561209756712017, -0.1088355401035232, 0.05148345180798951, 0.1235465165704314, -0.05522144380747635, -0.1423972092039827, 0.05706613305793608, -0.1656652164809836, 0.0571654881872712, -0.1937812736972878, -0.05560491141385822, 0.2273160612316538, -0.05242306351060358, -0.2670005088314752, -0.04760687919206397, -0.3137829156332985, 0.04106438412981419, 0.3689347453356511, 0.03256097086263596, 0.4342239659065471, -0.02160937448771497, 0.5121963228132351, 0.007270440886606282, 0.6066421962514198, -0.01221319300610655, -0.7234154012137514, -0.04013586770219741, 7.505393492740379, 2.207569919375577, -2.286495948142137, 0, 0, 0, 0, 0, 0, -504.7004946877645, -960.8313859426444, 455.6868630884425, -0.0004564668894400728, 0.01953047220881932, 0.002110185308335535, -0.02552492771185354, -0.004910008054476974, 0.03185603230051105, 0.008867203935794236, -0.03876493903116766, -0.0140372793617222, 0.04650258449956125, 0.02052143233325077, -0.05533916645715601, -0.02846939294478852, 0.06557394899483331, 0.03808355296447862, -0.07754536439486578, -0.04962400720722794, 0.09164110934556451, 0.06341371783532462, -0.1083072609262454, -0.07984241792495486, 0.1280548395158984, -0.09936692302911229, -0.1514604665622404, -0.1225031219103813, 0.1791553196119899, -0.1498024404391789, -0.2117929820588376, -0.181800940883612, 0.2499814001970585, -0.2189235487704594, -0.2941578702525302, -0.2613208334101781, 0.3443825148816139, -0.3086165449914435, -0.4000320253108334, -0.3595628891688978, 0.4594100673703709, -0.4116578643958037, -0.519368340488319, -0.4608838085460648, 0.5751583010135386, -0.5018561564823436, -0.6208288964715706, -0.2890646136834312, 1.547039886853192, -1.173755403489903, -0.7985207315322997, -0.2625825083083085, -0.321674668942854, -0.1352159819750655, -0.1999732725283456, -0.07366734029347159, -0.1440615953055945, -0.0338692953389332, -0.1147504606082463, -0.005029712242208511, -0.1000175433858401, 0.01695421717090311, -0.09456233266164106, 0.03415869939464086, -0.09556433616678824, 0.04784697925863496, -0.101446550453596, 0.05887259823103022, -0.1113844111571908, 0.06784319765312669, -0.1250437127185277, -0.07520036620749675, 0.1424161499432856, 0.08126890147440424, -0.1637146453439622, 0.08629375258215478, -0.189312804562382, 0.09046906112313131, 0.2197194565251569, -0.09395994411067805, 0.2555854707181692, 0.09691288686658349, 0.2977431307518454, 0.09945154948260918, -0.3472856237053809, -0.1016514559138057, -0.4057014604005721, -0.1034872918659082, 0.475092530300298, -0.1047384672449806, -0.5585328441816623, -0.1048045105961936, -0.6606855376279177, 0.1023541847811403, -7.645111917964669, -2.444190547643892, 3.259474730743878, -1.113400990501543, 0, 0, 0, 0, 0, 0, 0, 504.7005483880675, -960.8563426765877, -455.6810385506663, -0.0006211890719464708, -0.02717449361052982, 0.002624545711740859, 0.03409357098285602, -0.005942159106883158, -0.04143715413018739, 0.01059135423887447, 0.04948858776950704, -0.0166413313054562, -0.05854418379382578, 0.0242148610679564, 0.06892421088657538, -0.03349146754772453, -0.0809841818387797, 0.04471193925388908, 0.09512623948475284, -0.05818359115254906, -0.1118100512572915, 0.07428496523273895, 0.1315618312735884, -0.09346828354041023, 0.1549790152282817, 0.1162558426750438, 0.1827256545244234, -0.1432240256832661, 0.2155105496963288, 0.1749650364632709, 0.254035038834301, -0.212010638405861, 0.2988909563929731, 0.2546958843850197, 0.3503831721602568, -0.3029377534844611, 0.4082512041088586, 0.3559113648605111, 0.471283605276577, -0.411645725224325, 0.5368790186329719, 0.4666463388955495, 0.6007202940611962, -0.5157903324539884, 0.6568675698020393, 0.5528415071271306, 0.3819646735423662, -1.398313345247025, 1.702130138980118, 0.5594893184855516, 0.4345731607149444, 0.2047273101100171, 0.2544540474780775, 0.1063741954770327, 0.1778805766776483, 0.05255231548952451, 0.137900569051342, 0.01589144268877343, 0.1168704015342846, -0.01147530402843068, 0.1075993573348887, -0.03281602394973369, 0.1063490908368691, -0.04987312975903418, 0.1109852985003045, -0.06374396058252166, 0.1203212709282059, -0.07519208505179932, 0.1337915946504525, -0.08477768059074928, -0.1512472309045833, 0.09292245189830053, 0.1728188948893017, -0.09995295179709891, 0.1988310587279109, -0.1061338258071349, 0.2297560668874317, 0.1116956612897333, -0.2662028365209533, 0.1168534044651449, 0.3089378582466848, 0.1218148638037771, 0.3589424141807773, -0.1267685950073432, -0.417514018459675, -0.1318530493084198, -0.4864325194506035, 0.1370935903164596, -0.5682256141066142, -0.1422822434012505, -0.666604844323565, -0.1467513256218947, 7.839832839255147, -2.591992660256728, 3.08252939024389, -1.472235565518307, 1.200611269528463, 0, 0, 0, 0, 0, 0, 0, 0, -504.7015918274936, -960.8824172487933, 455.6786628322481, -0.0001386040108547678, 0.02825899575001721, 0.00148000990419925, -0.03396816329492456, -0.003913391729580158, 0.03999719012865367, 0.007442680878789934, -0.04659090322133554, -0.0121162968680667, 0.05400401596298283, 0.01802786748313866, -0.06251037884950617, -0.02531818062112227, 0.07241227284910066, 0.03417801432480141, -0.0840495440103118, -0.04485119411434383, 0.09780784101480898, 0.05763670862206309, -0.1141246897988619, 0.07288798740446953, 0.1334907230535002, 0.09100549877450563, -0.1564413552584702, 0.1124168465460749, 0.1835312438634551, 0.1375347555217266, -0.2152794341013849, 0.1666789233629258, 0.2520679325404323, 0.1999435400148238, -0.2939734797154126, 0.2369931492869313, 0.3405172515888476, 0.2767850762901711, -0.390345045347925, 0.3172634202969561, 0.4409132592457857, 0.3551552329611432, -0.4883580204443008, 0.3861049626417496, 0.5278024954606876, 0.221653617736939, -1.310709133012781, 0.8704550092422116, 0.7079030635461785, 0.1843303003648327, 0.289142189894577, 0.0890031466634482, 0.183755046796533, 0.04093279509465775, 0.1369845466667406, 0.008027106857080303, 0.1140671851302532, -0.01733485053642101, 0.104231064513174, -0.03796088669959809, 0.1026821086919593, -0.05525696194664861, 0.1068620954451136, -0.07011029660696497, 0.115354075966287, -0.08317464933480107, 0.1274397517866654, -0.09497453954477812, 0.1428557674294213, 0.1059485191998991, -0.1616373931580192, -0.116473125434708, 0.184018627644066, -0.1268840153469689, 0.2103748991036934, -0.1374978332735491, -0.2412002758106563, 0.1486321821340762, -0.2771135831612571, -0.1606234825346388, -0.318894700017657, -0.173836022567292, 0.3675540114045308, 0.1886613027997724, 0.4244484685316806, 0.2055082541208365, -0.4914687718702396, 0.224768184994539, 0.571342364466508, 0.246749172743278, 7.942734281408671, -2.790996821413193, -3.416416824440133, 1.502698673759963, -2.74025012280437, 0.4374074524376139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7014268866499, -960.9091609078547, -455.6702009059838, -0.0004715858695197065, -0.03982840046737102, 0.00242224023844466, 0.04693804869973257, -0.005712413463266942, -0.05453060690126599, 0.01036142963375495, 0.06291484964449161, -0.0164440331698878, -0.07241520054585564, 0.02409153161862073, 0.08338313108173702, -0.03349426180113407, -0.09620848027332857, 0.04490493324477595, 0.1113301550654768, -0.0586415214773373, -0.1292450786759426, 0.07508828443695986, -0.150513154673022, -0.09469143119899404, -0.1757538991751067, 0.1179438613939318, -0.2056275754842778, -0.1453500537954308, -0.2407890904812533, 0.1773573065390127, -0.2817971004678554, -0.2142337181273538, -0.3289552292807281, 0.255870859960439, -0.3820621733814443, -0.3014962025572454, -0.4400643963200938, 0.34931588173307, -0.5006585522123436, -0.3961850233060456, -0.5599910362173445, 0.4375268333475068, -0.612726531008857, -0.4678122672345172, -0.3569120201451431, 1.18831598199679, -1.617583791352987, -0.4321697836882517, -0.4219085060089673, -0.1510420456331972, -0.25146678538168, -0.07059891849129137, -0.1807609333405698, -0.0240329511553917, -0.1456531311906457, 0.009769195529775603, -0.1290384618111746, 0.03669700570302369, -0.1238682627899927, 0.05912761689067447, -0.1264561589974369, 0.07833483431516959, -0.1347055607275304, 0.0951733797931347, -0.1474724563406544, 0.1103088335611947, -0.1642393157936116, 0.1242996284536155, 0.1849045503710836, -0.1376315559768252, -0.2096404850603622, 0.150739321415534, -0.2388041370692126, 0.1640310219820809, -0.2728910081209138, -0.1779123181778702, 0.3125232856726328, -0.1928113592711771, -0.3584705110456833, -0.2091969136508766, -0.4117030466307595, 0.2275912605111247, 0.4734858653437208, 0.2485748286117511, 0.5455291692123926, -0.272779071272836, 0.6302263498990262, 0.3008643534306304, 8.20707478604357, 2.932590880343228, 3.566301858755951, 1.591737361864661, -2.080954844450352, 1.063336818518452, -0.312693340165919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7034311398602, -960.9369925632403, 455.6692107057009, 0.0004356100354586218, 0.03860199096161918, 0.0003618838493967148, -0.04386380370370079, -0.002169347414784144, 0.04942525667989209, 0.004982545942080307, -0.05553497828831112, -0.008840601544025953, 0.0624511939178053, 0.01382568492204521, -0.07045040500021758, -0.0200635944222586, 0.07983573655308961, 0.02772464186081651, -0.09094444742633617, -0.03702388344715066, 0.1041536259789221, -0.04821924316984402, -0.1198819820124656, -0.06160445551722481, 0.1385840425022496, -0.07749220106038934, -0.1607306169402915, -0.09617998733441638, 0.1867658703825194, -0.1178877608692904, -0.2170271396260865, -0.1426531229291118, 0.2516110942742074, -0.1701709400072701, -0.2901735669785757, -0.1995766655123539, 0.33167198231666, -0.2292104536632618, -0.3741087211620817, -0.2564669531327498, 0.4144141160994378, -0.2779196790709351, -0.4486695658607398, -0.1585148155348832, 1.108326036371431, -0.5816638331406274, -0.6376460733569355, -0.1083863705122823, -0.2651532591988918, -0.04346268036180279, -0.1731791135747381, -0.007919955521890586, -0.1343419559206488, 0.01884997316493552, -0.1172998435413015, 0.04139686964273688, -0.1122109969614702, 0.0612644512371045, -0.1146390321312077, 0.07920415164364861, -0.1222036115318655, 0.09574062739795554, -0.1335955000566879, 0.111342587990221, -0.1481684801491999, 0.1264688165440626, -0.1657058794392267, -0.1415730034357649, 0.1862665137934408, 0.1571022793772566, -0.2100850895889454, 0.1735027646062021, -0.2375159098214737, 0.1912338107828908, 0.2690093363603886, -0.2107891668533592, 0.305116325619871, 0.232719244011093, 0.3465174314368482, 0.2576565915212616, -0.3940792105482042, -0.2863453006006712, -0.4489464059320039, -0.3196699442525448, 0.5126872859904976, -0.3587010976918096, -8.28272768639917, -3.069060360130142, 3.927691039870548, 1.671176660764354, 2.407455234884137, -0.8625377998571393, 2.482297646744782, 0.1292734700574192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7028824420881, -960.9653940857651, -455.6573959835257, -0.0001045342927213557, -0.05510952876884354, 0.001813256542621175, 0.06227481799574789, -0.004858797016936023, -0.07000242917077827, 0.009264808465575517, 0.07862878594870333, -0.01511232203008351, -0.08850890488940624, 0.02254001315406766, 0.1000277135969499, -0.03174536747972971, -0.1136106715000355, 0.04298556623718725, 0.1297326922178386, -0.05657684359155325, 0.1489234556474868, 0.07288927434017092, 0.1717652930940824, -0.09233189928394896, 0.198877283105147, 0.1153205669594968, 0.2308750852817715, -0.1422162239454809, 0.2682908269428334, 0.1732165788221063, 0.3114322670825245, -0.2081820549922315, 0.3601601689508011, 0.2463834229879688, 0.4135774742746823, -0.2861906631817055, 0.4696707079443848, 0.3247907144321164, 0.5250325498506966, -0.3581320852927125, 0.5749043514816392, 0.3813740651756898, 0.33559864255759, -0.975267052557106, 1.553286395488471, 0.2975654526534304, 0.4156488593431335, 0.09371170961137179, 0.2528219529681863, 0.0318602025876451, 0.1873286487076531, -0.007406320889202832, 0.1569749836318507, -0.03858434309919215, 0.144934740453739, -0.06545817090963257, 0.1441815831728718, -0.08945270328381889, 0.1510120365349771, -0.1113416651259841, 0.1633234601502849, -0.1317257394447766, 0.1799857228617523, -0.1511744615193794, 0.2005086220062386, -0.170257066128721, -0.2248204324462682, 0.1895400302751218, 0.2531160063974417, -0.2095887459424748, 0.2857621049048731, -0.2309786288335811, 0.3232475487327383, 0.2543197035673892, -0.3661698670568465, 0.2802839275652471, 0.4152519125737978, 0.3096388181156818, 0.4713879968706516, -0.3432857433502883, -0.5357238487236324, -0.3823039298241136, -0.6097820756813976, 0.4280142297040914, -8.593418202744859, -3.211955544343986, 4.01550610066904, -1.769542946482932, -2.385993943945727, -0.9351886806923488, 1.364050528322037, -0.9080040622263671, -0.4464199288967212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7061722826078, -960.9950980825289, 455.6584934644936, 0.001353924213319257, 0.05069804235078336, -0.001403478172758728, -0.05531669887499667, 0.0005546746219488723, 0.0602176601279568, 0.001178736969878009, -0.06565366943648464, -0.003823298510146261, 0.07188614605884883, 0.007444087396122985, -0.07919288756514294, -0.0121433251462564, 0.08787498194637582, 0.01805863608944551, -0.09826218797222715, 0.02535989650826906, 0.1107152897665785, 0.0342421634090001, -0.1256225901932514, 0.04491137284146533, 0.1433858203414038, 0.05755711615621574, -0.1643879418622154, 0.07230425516591216, 0.1889319980546444, 0.08913300093328734, -0.2171379771443038, 0.107757891711349, 0.2487872536298442, 0.1274663214539597, -0.2831201330658301, 0.1469465463422727, 0.3186294299533511, 0.1641875797212851, -0.3529538909796769, 0.1765977012156841, 0.3830228392206152, 0.09923300750079445, -0.9387659102980379, 0.305398543764229, 0.5874526002501284, 0.03421711551743981, 0.2496160794636069, -0.00172104942964322, 0.1682097394146368, -0.02558725561576955, 0.1361268344344931, -0.04691707458719761, 0.1244564737090883, -0.06726669000070251, 0.1239690575086415, -0.08693811269512493, 0.1304369530627798, -0.1060389333362548, 0.141571663489697, -0.1247414524221453, 0.1561163886904096, -0.1433423840955047, 0.1734586694197238, -0.1622500485292275, 0.1933984716847243, 0.1819498382764446, -0.2159900192240643, -0.2029763815613684, 0.2414387822339389, -0.2259034630808185, 0.2700417931160715, -0.2513516107580024, -0.3021617326012637, 0.280007600114253, -0.3382255019637882, -0.3126552129313027, -0.3787429608129044, -0.3502182255490416, 0.4243439334152545, 0.3938138954989248, 0.4758372286628779, 0.4448387377462819, -8.646476556307604, 3.287657641880755, -4.395262558384979, 1.792030252359884, -2.73372973571881, -0.9241141660969929, -1.712422595404809, 0.4359874306747898, -2.432174107259886, -0.6397052114818167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7050978056665, -961.0251353455429, -455.6426293119019, 0.0005789714464947707, -0.07319751886662666, 0.0006207879061930474, 0.0802799735867732, -0.003129094635399184, -0.08803596071851463, 0.006975460706357075, 0.09683290373786249, -0.01224653915288706, -0.1070596332625383, 0.01908491954449565, 0.1191369742779648, -0.02768776308106317, -0.1335267149602703, 0.03830435886062355, -0.1507372943186485, -0.05122967843956672, -0.1713229356970986, 0.06678971375544743, -0.1958705963395601, -0.08531182846472353, -0.2249654793739225, 0.107069570838405, -0.2591211079527574, -0.1321872027422623, -0.2986553751625171, 0.160487669363109, -0.3434934131000018, -0.191273923827569, -0.3928906485362413, 0.2230621626353611, -0.4451099722739455, -0.2533460049820092, -0.4971642549076689, 0.2785681040388742, -0.5448315365001141, -0.2945449187820606, -0.3188523354151554, 0.7617168830174238, -1.512960882421318, -0.1565418889317566, -0.416770638188017, -0.0330371554958069, -0.2590939561072727, 0.009692898702806391, -0.1979815715767451, 0.04169344337350171, -0.1721638220045798, 0.07052530713197516, -0.1647923498418741, 0.09775169543831891, -0.1687258056803347, 0.1237881291548195, -0.1801639057873346, 0.1488794308490554, -0.1969463086568264, 0.1733613896964222, -0.2179209500175104, 0.1977104526182695, -0.242597178003689, 0.2225166824607487, 0.2709069147142353, -0.2484447312925564, -0.303039084913382, 0.2762089619529779, -0.3393348213625563, 0.3065757332901756, -0.3802323858876161, -0.3403810643090954, 0.4262480705852916, -0.3785664996638002, -0.4779857272391611, -0.4222285054438267, -0.5361702328195965, 0.4726795168378314, 0.6017042384742251, 0.5315431534297506, 8.988404257252103, -3.434234591407497, -4.436704087040918, 1.904958600463788, -2.667252960757383, 1.019315404694702, 1.553413773220462, 0.5240360258904643, -0.8521059937283484, 0.9531203463970385, 1.133055091391562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7100346863414, -961.0567364446957, 455.646613143601, 0.002722295284934282, 0.06461681973477371, -0.004007947943993217, -0.0683635324772939, 0.004536694220093283, 0.07238640000970466, -0.00433430930478059, -0.07694262150014541, 0.003392025878594218, 0.08229618144787393, -0.001670278858418917, -0.0887242115986121, -0.0008975016974408089, 0.09652212032887546, -0.004400201670914741, -0.1060064440564509, -0.008941741499294128, 0.1175134358385135, -0.01462879396175798, -0.1313898772830384, -0.02154950721841662, 0.1479705007616418, -0.02973757948750487, -0.1675338272440166, -0.03911447566452358, 0.1902263373250469, -0.0494038851796016, -0.2159464070642364, -0.06002011198536771, 0.24419037399957, -0.06995441855483667, -0.2738896861740276, -0.0777218007125729, 0.3033115380943844, -0.08147776924470845, -0.3301302888852998, -0.04342138832490353, 0.800108427299287, -0.04000732313755277, -0.5563775145367175, 0.03855669146460623, -0.2421457122014047, 0.04673467675853111, -0.1685947713495393, 0.05966925766215405, -0.1421356546813504, 0.07617060670611064, -0.1353431117620796, 0.09486340695112068, -0.1392947724748802, 0.1148236878882152, -0.1498272473624081, 0.1355229389653643, -0.1646584030588876, 0.1567892967260354, -0.1825265390991063, 0.1787580887629875, -0.2028097674378218, 0.2017993595211208, -0.2252868325806165, -0.2264439082886397, 0.2499694264649327, 0.2533278498840449, -0.2769901080244833, 0.2831665936584349, -0.3065367197788879, 0.31675352352134, 0.3388193022269569, -0.354979335807952, 0.3740594600432878, 0.3988728455325729, 0.412493048200239, 0.4496557166350698, -0.454379410749675, -0.5088325604398763, -9.020420590072227, -3.450565579378631, -4.828910565671182, -1.874110745373426, 3.031455262150587, -0.9554280057985601, 1.918824600147808, 0.4370410894016331, 1.245159522031377, -0.1566307455549422, 2.552719012229264, 1.137055157228564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7083084832581, -961.088403701372, -455.6259949644748, 0.001693462288155773, -0.09425609907144253, -0.00135812958186467, 0.1011210298209119, -0.0002358251806337989, -0.1088168511442754, 0.003123702470935177, 0.117746189310862, -0.007394509226016558, -0.1283352037931964, 0.01318721808082886, 0.1410426164823464, -0.02068614552863905, 0.1563657899240353, 0.03011316521908753, 0.1748410515523016, -0.04171287552624901, 0.1970333700401475, 0.05572504926140202, 0.2235071819563995, -0.07233534673786346, 0.2547659637536581, 0.09159167502337025, 0.2911438853529135, -0.1132728046470395, 0.3326320892944551, 0.1367013692972142, 0.3786326012788764, -0.1605193483772494, 0.4276675386247564, 0.1824972953091496, 0.4771381978993297, -0.199534230207109, 0.5233118023773972, 0.2080647751939719, 0.3071312523515405, -0.549473955438997, 1.498520087318462, 0.00989782058163087, 0.4257392836989572, -0.03066419348029967, 0.27053141082994, -0.05385429393158369, 0.2128586455021746, -0.07865838364579553, 0.1912804624944068, -0.1054218514397032, 0.1886052588272439, -0.1333817841205637, 0.1974301330414755, -0.1618922650232225, 0.2137720478898956, -0.1906429188221663, 0.2353555123291881, -0.2196953036046989, 0.2609640871623732, -0.2494334138871651, 0.2900702342300163, -0.2804781709204113, -0.3225735541543351, 0.3136051709871521, 0.3586152379559984, -0.3496963324210602, 0.3984605855948943, -0.3897237334354889, 0.442433754373803, 0.4347674252373997, -0.4908899809534614, 0.48605633051341, 0.5442128827277137, 0.5450303291374311, 0.6028273664098085, -0.6134359722665157, -9.383238747186924, -3.600916739919184, 4.832694315608912, 2.003470413821713, 2.931212798765991, -1.076233974356122, 1.727556840630514, -0.5584158153153711, -0.9677000168663793, -0.2850220760337975, 0.4848137226350174, -1.162124180800043, -1.793676268616248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7153141286621, -961.1217498954065, 455.6338248564796, 0.004666236513345801, 0.08033835876549655, -0.007676437270062325, -0.08295141844108442, 0.01009977011228604, 0.0858558666115623, -0.01197879976722524, -0.08931330796488612, 0.01333079539699938, 0.09358896098647876, -0.01415383176294858, -0.09895648285762505, -0.0144330727549111, 0.1057012528087135, -0.01414858625643324, -0.114120817737291, -0.01328610322696056, 0.1245201008433383, -0.01185312169985896, -0.1371974259500803, -0.009903932278386084, 0.1524155095853953, -0.007577483035196663, -0.170349858019879, -0.005151094173442019, 0.1910076219888127, -0.003106911843602696, -0.2141162385930753, -0.00219223603220216, 0.2389982098664602, -0.003428653267689329, -0.2644761408819428, -0.007993135284190185, 0.2888757583999775, -0.009238357725273051, -0.689494763421366, -0.2155878440195048, 0.5426652421405607, -0.1100760809768825, 0.2419872852187903, -0.0915757211308498, 0.1738068042043262, -0.09421490159299305, 0.1519131253021238, -0.1063902295366557, 0.1495062851706462, -0.1238496488930524, 0.1576921868225562, -0.144457445676418, 0.1722377145797942, -0.1670559652778887, 0.1907853469363053, -0.1911367180744256, 0.2120098595295308, -0.2166813899045869, 0.2352309624985876, -0.2440312262325445, 0.2601594028118362, 0.2737719046620724, -0.2867127897537385, -0.3066513544997664, 0.3148910096033804, -0.3435341329051073, 0.3446994182012239, -0.3853912741508331, -0.3761050372799959, 0.4333221867749439, -0.4090113357290798, -0.4885956544839816, -0.4432370036767068, -0.5527297958804152, 9.393725843325772, 3.559142669539414, -5.233438534663443, 1.922140772052916, 3.30916008332548, 0.9639922588619462, -2.108426983838054, 0.4210596150978028, -1.37488546401417, -0.126172291118237, -0.9417910946035264, -0.02489482226941209, -2.820413837240554, -1.65719959391188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.712822627705, -961.1549732256356, -455.6077127096619, 0.003370363513768094, -0.1184233948149237, -0.004352589134933815, 0.1249488727742578, 0.004142598150015885, -0.1325266147065525, -0.002702309633903203, 0.1415989061506627, -5.193242257853952e-05, -0.1526322638582052, 0.004242516041704322, -0.1661238420831387, -0.01002108162905441, -0.1826028877145596, 0.01755321339895132, -0.2026229299653129, -0.02699257791731359, -0.2267375503327169, 0.03843678368101805, -0.2554486834745714, -0.05185463742576753, -0.2891125143344822, 0.06697380838544749, -0.3277869557881715, -0.08312340296797521, -0.3710132247776353, 0.09904931306822057, -0.4175532297672665, -0.1127668418736266, -0.4651618147564519, 0.121590215262521, -0.510544244533257, -0.1225288992181756, -0.3005345609258526, 0.3399230830669571, -1.510041866246306, 0.1414029629131923, -0.4424813889986434, 0.0969566625439009, -0.287030472441386, 0.1002877273344002, -0.2318097264729576, 0.1179696537132148, -0.2141130560573038, 0.1428989401173152, -0.216085496212976, 0.1718969363526398, -0.2299160646037506, 0.2032113426057577, -0.2513516264549205, 0.2359542056548815, -0.2779404049836417, 0.269903604489502, -0.3083522861668259, 0.3053525231567537, -0.3419775604673035, 0.3429586234253998, 0.3786342689363086, -0.3836208986559502, -0.4183589706424067, 0.4283986271914125, -0.4612706968478629, 0.4784824630112978, -0.5074923782141396, -0.5352066248608507, 0.5571092548388775, -0.6000923998546913, -0.6101471292691906, -0.6749305319888952, -9.770051112346868, 3.712532157622387, -5.204107151313059, 2.068330691047585, -3.18125125479366, -1.111446716858055, -1.892155190902516, 0.5769109527951105, -1.074175671579627, 0.2964457689798568, 0.5539281293589068, 0.1648327863802309, -0.2172096485697859, 1.512241614146546, 2.467635656276092, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7224116592663, -961.1902571610938, 455.6205915183505, 0.007332560323131098, 0.09772650675515225, -0.01266681647409895, -0.09890946144936448, 0.01761061930967164, 0.1004319663138764, -0.02223151529100917, -0.1025589734040736, 0.02658527800478494, 0.1055543905435332, 0.0307240137177325, -0.1096846360720932, 0.03470480005138991, 0.1152206928700177, 0.03859926962869588, -0.1224372229859417, 0.04250540794695284, 0.1316063042861069, 0.04656276217394649, -0.1429819416890049, 0.05097254854312608, 0.156770043109164, 0.05602256159687267, -0.1730781884191307, 0.06211263471333318, 0.1918417495221531, 0.06976604123079083, -0.212731221653107, 0.07959687794489242, 0.2350594264866488, 0.09218568189114314, -0.2577207095948243, 0.05895216380708893, 0.6030344606072978, 0.4616425346359402, -0.5436208097610066, 0.1801615878388285, -0.2479542818639472, 0.1359942495801694, -0.1829951211861444, 0.1288696776689487, -0.1647070482516714, 0.1370851711017615, -0.166186009742888, 0.1535729004651733, -0.1783286433187104, 0.175004017949945, -0.1967160001753221, 0.1996016370756137, -0.2188405755084354, 0.2265274150255044, -0.2432545072656078, 0.255616995167631, -0.2691644778819984, 0.287188623645841, -0.296154558573445, -0.3218894031796202, 0.3239813218519342, 0.3605820289961011, -0.3524309991867358, 0.404281451485633, -0.3812277505186181, 0.4541373257413515, 0.4099740685595717, -0.5114462459203447, 0.4381037210394499, 0.5777085075240355, 9.757187794715053, 3.613965379149533, 5.610766740550909, -1.938835199033022, 3.571436149045066, -0.9542168243229318, -2.288013661621963, -0.3938480967566447, 1.496351683252224, -0.08808345484880223, 1.023046330373567, -0.06957848752644458, 0.7559950874575174, 0.1446377341673701, 3.223159785518482, 2.231109599751307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7190540960186, -961.2250192748934, -455.588180522695, 0.005760119451667827, -0.1458018459472323, -0.008617871967446157, 0.1518886251707371, 0.01036045836723483, -0.1593339434673855, -0.01095512117368798, 0.168623432319206, 0.01033715383235535, 0.1802652315855236, -0.008421308021689847, 0.194792393053006, 0.005117854913200912, 0.2127573865763628, -0.0003573018673901766, 0.2347123846839292, -0.005870115341541783, 0.2611655306170398, 0.0134514921104915, 0.2924997329898752, -0.02205646148738518, 0.3288391697120372, 0.03100724814840945, 0.3698554289066493, -0.0391314172858762, 0.4145293741812473, 0.04465629171074397, 0.4609333830920124, -0.04526915247447261, 0.5061591284697164, 0.03850943070266388, 0.2988211434046964, -0.1343140034874617, 1.545791848932921, -0.2960335360025335, 0.4663736910206594, -0.1651993031618597, 0.3081206807361616, -0.148466528783414, 0.2543776892222589, -0.1590822972569348, 0.2401547949000193, -0.1823264347853362, 0.2466363598796981, -0.2125374666877397, 0.2654664586167893, -0.2468230014420065, 0.2920378799634734, -0.28369945780944, 0.3236595023368128, -0.3226554917179421, 0.3588325700155615, -0.3638932634463122, 0.3968084947760234, -0.4081139430426112, -0.4372603761207967, 0.4563448325195634, 0.4800432615153861, -0.5098306130089106, 0.5250360251830816, -0.5699872792909377, 0.5720443097383854, 0.6384042472680606, -0.620739093955173, 0.7168958955657478, 10.1416026925784, 3.769624166608563, -5.550197612007544, -2.101714625470462, 3.418765229089471, -1.128530918815057, 2.05030202920546, 0.5843666730352316, 1.176141611311618, -0.2998770983489928, 0.6178281648963292, -0.1687738124565776, -0.2572515070648175, -0.1256951327451982, 0.01616907141314794, -1.992214070149926, -3.189662381847132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7318794445075, -961.2622111936237, 455.6076615218215, 0.01089221138384335, 0.1164944818989575, -0.01927027124317406, -0.1159105114196266, 0.02747804138380453, 0.1157590237274542, -0.03562101111504409, -0.1163053571198556, -0.04381054622555893, 0.11780798689624, -0.05217348627038508, -0.1205218765117039, -0.06086108892227842, 0.1247010612781868, -0.07005691264492792, -0.1305992812196758, -0.07998336769309033, 0.1384666763445831, -0.09090568207321333, -0.148539099266325, -0.103130632313689, 0.1610155426830076, -0.1169945067947107, -0.1760175642549749, -0.1328292092990493, 0.1935251760227961, -0.1508900371219247, -0.2132847544560474, -0.1712230826203191, 0.2346889242553419, -0.1057755931109957, -0.5357642487146973, -0.6973878233988416, 0.5555297188556486, -0.2482482426823123, 0.2583893820691848, -0.1794481217099651, 0.1949556011152848, -0.1629964039187765, 0.1794404990383949, -0.167454966242039, 0.1842879058626768, -0.1830230404376604, 0.2000060175644817, -0.205209645685749, 0.2218995693363221, -0.2316338998877495, 0.2472470804664445, -0.2611383861136601, 0.2744206707423583, -0.2934188634283356, 0.3024520161486941, -0.3287766158418658, 0.330727168992488, 0.3679203274465594, -0.3587549762608285, -0.4118259797084023, 0.3860024176740223, -0.4616568968449378, 0.4117833750068759, -0.5187284681093876, -0.4351768010753159, 0.5845252467597436, -10.10272037837622, -3.615759296992346, 5.961002309639331, -1.925982279272278, -3.820398085376841, 0.9288290974303622, -2.461282861258473, 0.3588964134966156, 1.614524108256882, 0.04643312460190491, -1.101929869918408, -0.1156934037864506, -0.8069532966049089, 0.1939414294536783, -0.6549974120119686, -0.2285123742746999, -3.758505654153285, -2.887002774786242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7275737129024, -961.2986900862034, -455.5680475291849, 0.00903586301318594, -0.1764481378529507, -0.01443633323006236, 0.1820293926317921, 0.01880447073763833, -0.1893830763324559, -0.02212739922183875, -0.1990394755651686, 0.02438113653662378, -0.2115459961113778, -0.02554785138683405, -0.2274636911241468, 0.02563963642219436, -0.2473516518290995, -0.02473404186599173, -0.271730510328668, 0.02302808689174882, -0.3010128812352733, -0.02091691897707183, -0.3353869095894007, 0.01909834439431709, -0.3746441757811209, -0.01868481784601551, -0.4179627386782013, 0.02126895992019769, -0.4636967305855159, -0.02883173464380446, -0.5092745443586736, 0.04334833925615389, -0.3014407655914791, -0.06601281923988526, -1.602324544766366, 0.4521688717502506, -0.4962602535568542, 0.2344899085974771, -0.3329721059649142, 0.1976354384687227, -0.2798012120081235, 0.201207847611257, -0.2686044483634154, 0.2227918565877333, -0.2793525517309335, 0.254208949035389, -0.3030265762539144, 0.2914075927648672, -0.3345889425740216, 0.3323002062548046, -0.3710472412454519, 0.376082825113517, -0.410672419727643, 0.4228703215020564, -0.4525090987053563, 0.4734101217025521, 0.4960038585709059, -0.5288630443220137, -0.5407310407243179, 0.5906642373893218, -0.5862073308755801, 0.6604544266659836, -0.631770882164199, -0.7400800113225439, 10.4912498465414, -3.773373232627433, 5.869292321428817, -2.105388476297262, 3.643747899009217, 1.129947070197685, -2.20333116034871, 0.5839586073720042, -1.276059903111896, -0.299240532723705, -0.6800685739125477, 0.1698588504724025, -0.2942327379600606, 0.1304150900865758, 0.03800351903695634, 0.1417197104665032, 0.1425294782604167, 2.600515797914067, 3.992077820801224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7444899137037, -961.3378869284877, 455.5961766575729, 0.01554496586389417, 0.1361607262454429, -0.02781289414814694, -0.1334206115553933, 0.04015195437573545, 0.1312610252962056, 0.0527238328643537, -0.1299420806015547, 0.06571735393480846, 0.1297113267134137, 0.07935679284872428, -0.1308093221619015, 0.09390646392500906, 0.1334765342836597, 0.1096692934744826, -0.137961097981063, 0.1269759901739711, 0.1445257840878497, 0.1461596796124059, -0.1534505818065084, 0.1675090650339144, 0.1650223724407157, 0.1911922811662067, -0.1794965959880791, 0.2171469054347325, 0.1970054498924576, 0.2449372580636083, -0.2173831194355537, 0.1495893184212565, 0.4816785595258409, 0.9209202815588715, -0.5736517097497067, 0.313353604698171, -0.2711605588560934, 0.221082155663423, -0.2081281229339226, 0.195658000237407, -0.1947111978907778, 0.1963739070246782, -0.2023853087811128, 0.2108169700402979, -0.2211665513822386, 0.2333844452691181, -0.2460259436412557, 0.2611196517524419, -0.2739795084733933, 0.2925613936013013, -0.3031638285603235, 0.3272759615201772, -0.3323671520526524, 0.3655494198939995, -0.3606901700963588, -0.4081518881755232, 0.3872850919084128, 0.4561704112264385, -0.411165351471291, 0.5109046669029912, -0.4310695720851319, 0.5738286008172455, 10.42318783741847, -3.566018330179493, -6.283039963892671, 1.885086978417805, -4.056461148196111, 0.8896096623583637, 2.629879524658232, -0.3183134586090979, 1.732009409551348, -0.003597002249112677, -1.181752365540581, 0.1607426656367353, 0.8594318003331071, 0.2409887971627989, 0.6872601018528763, -0.2776927275225095, 0.6162945944580821, 0.2949229569475111, 4.432330830999809, 3.652258417704127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7391854477888, -961.3761134831929, -455.5483160115629, 0.01339975427289111, -0.2103617083669475, -0.02212129334677451, 0.2154107935057459, 0.02989586468758025, 0.2227762054914026, -0.03675410570225757, 0.233029559420389, 0.04274488714190522, 0.2467489261215965, -0.04795860482498126, 0.2645069025107166, 0.05255917574259697, 0.2868406962417143, -0.05682989248602897, 0.3141931378633969, 0.06123725611583161, 0.3468116005115335, -0.06651167350925496, 0.3845953195758418, 0.07372631291715646, 0.4268969633578305, -0.084324035113474, 0.472317693749994, 0.09999329127000312, 0.5185766012306021, -0.122267111761034, 0.3075794130567557, 0.2594922311530679, 1.674677840688869, -0.6074411217165189, 0.530504621157434, -0.3036489093269464, 0.3604292259290603, -0.2468040165898022, 0.3070437102038547, -0.2433124059830945, 0.2983965063767964, -0.2631034380950553, 0.3130548980457453, -0.2954872738506904, 0.3412458946213262, -0.3352576648480358, 0.3774381296472452, -0.3797257621045876, 0.4182777341843855, -0.4278008133993835, 0.4617385983648974, -0.4795135491180799, 0.5065767007844517, -0.5356633184142464, -0.5519108635118929, 0.5975519447496171, 0.5969093166328796, -0.6668064787959627, 0.6405721802139768, -0.7452989581305071, 10.81295073151522, 3.725997667527157, 6.159022350342218, 2.081113170768998, -3.855102702242159, 1.117501368797665, -2.351235823926313, -0.5777697467504209, 1.374856223267653, -0.29701181947491, 0.7424138377886643, 0.1710585953742098, 0.330797445008233, -0.1353650627227564, 0.0576408564358677, -0.1510793503432264, 0.1322861784530395, -0.1959399824468592, -0.2765948893642101, -3.344039432155814, -4.906745836243842, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7613365642291, -961.4178098908683, 455.5878220684487, 0.02152739456950745, 0.155990589845504, -0.03865954626620611, -0.1506307363154621, -0.05612307601046214, 0.1460612037459447, -0.07415968563775244, -0.1425284489543925, -0.09305949879988605, 0.1402637839647557, -0.1131625092824421, -0.1394959528064121, -0.1348497243264618, 0.1404692206213771, -0.1585184900258227, -0.1434668149614358, -0.1845343498098827, 0.1488370709744961, -0.2131515106483328, -0.1570114703269528, -0.2443967819326662, 0.168490761061717, -0.2779233867878602, -0.1837542375722553, -0.3128574421494117, 0.203035425587468, -0.1900946734061147, -0.433834219025143, -1.129221067589957, 0.5923000478378968, -0.3740906900280064, 0.2836979264745814, -0.2597387711190001, 0.22062681445908, -0.2256295048723918, 0.2088235792854549, -0.2224048277552317, 0.2187578425407568, -0.2352143633671168, 0.2399405360599269, -0.2574227677607072, 0.2669932721109848, -0.2855421185023375, 0.2966388173566911, -0.317835119944384, 0.3267272928345747, -0.3537499822930283, 0.35572663703428, -0.3935627878927179, 0.382347718395156, 0.4381069694359088, -0.4052516396076142, -0.4885743991703206, 0.4228306365409398, -0.546400243704626, 10.7123505563827, -3.467401368528632, 6.574905698665654, 1.817773117729432, 4.278777619641925, -0.8378218541754415, 2.793944829112401, -0.2733177456826802, -1.849759245051467, -0.03915110965119177, -1.264069361132026, -0.2034284048409766, 0.9153371450385213, -0.2846049852576992, -0.7235404151249138, -0.3227953515570327, -0.637237958096172, 0.342187055210012, -0.6250483028853673, -0.3568764257507016, -5.257937304882959, -4.55508554936837, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7550364030109, -961.4583496977284, -455.530480379083, 0.0190938476296795, -0.2474730170941161, -0.0320248394429458, -0.2520068723070391, 0.04409746139951185, -0.2595497997911581, -0.05542064500866747, -0.2707037328264438, 0.06615890175647458, -0.2860590669957729, -0.07656112549161879, -0.3061707763092542, 0.08699898599850459, -0.3315091701035143, -0.09801668999733169, -0.3623728933478695, 0.1103893488200521, -0.3987539286431652, -0.1251703436227577, -0.4401558607610471, 0.1436810276293193, -0.4853934971597049, -0.1673540627022936, -0.5324352881075169, 0.1973214093273239, -0.3162259135719306, -0.4443061610633235, -1.756700779373999, 0.7590020979393318, -0.5670900504193579, 0.3712553167121694, -0.3890806275027168, 0.2947777467691565, -0.3348571513627888, 0.2841510646953452, -0.3282692231155715, 0.3018275022954646, -0.3463689030326972, 0.3346649164831056, -0.3785725697111055, 0.3763313412808598, -0.418806990424517, 0.4235591970882376, -0.4633012783675338, 0.4749833840580253, -0.5096588677124098, 0.5305616262560031, -0.5562508167799632, 0.5911571677427112, 0.6017445089562359, -0.658220168495264, -0.6447469122637461, 0.7335866606257689, -11.10138605254825, 3.631034314442978, 6.416520283055733, -2.030929045438653, -4.050883210517207, -1.09263234274095, 2.492947931639272, -0.5671254785083639, 1.472262538497965, 0.294648565121288, -0.8053212026371659, 0.1740959578194711, -0.3680979667177443, -0.1426477808213935, -0.07701400313898601, 0.1623356308255878, 0.1242639559307309, 0.2112653724844634, -0.2740335801422096, 0.2779853011318764, 0.3991136330708569, 4.237178417243852, 5.966755879689668, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.7839768955486, -961.5031356303735, 455.5850306639925, 0.02912480258648458, 0.1749203040042703, 0.05222060442792607, -0.1663669930730279, 0.07592414985531605, 0.1588763076469116, 0.1005831663097198, -0.1526711551376601, 0.1266078291343768, 0.1479660097637017, 0.1544547454180628, -0.1449948514511539, 0.1845887043750316, 0.1440505633533104, 0.2174126453759208, -0.1455339392818743, 0.253156701007274, 0.1499995768662069, 0.2917237939532877, -0.1581666783968385, 0.3325088566360749, 0.1708317017743966, 0.3742344872602825, -0.188600178511197, 0.2268316604370843, 0.3845480392234077, 1.318322244561246, -0.6050237732153305, 0.428731430577431, -0.2930800029727587, 0.2940064673796119, -0.2303095703759141, 0.2514426080702059, -0.2198597838188783, 0.2438453429385534, -0.2314722939759387, 0.2541700231595779, -0.2542443363261532, 0.2748630106477523, -0.2824784951384094, 0.3019732811307502, -0.3125960540799213, 0.3335263049897976, -0.342113632573852, 0.3688741680327827, -0.3690936466192343, 0.4082952782635644, -0.3917330876661867, -0.4526883946043698, 0.4080384200378837, 0.5033598302349126, -10.96490758246675, 3.324010782640217, 6.833995337770606, 1.726068427677496, -4.485538946284208, -0.7744900179888866, -2.952462441243869, 0.2245238076687357, -1.96746806450077, -0.08132430877219025, 1.349148411398959, 0.2433017034817874, 0.9753204169954288, 0.3244179414574758, -0.7646022741758332, 0.3636921476151955, 0.6637918690093022, 0.3848718174085247, 0.6393750651856561, -0.402120829041611, 0.672076261839223, 0.4236321878220717, 6.255464776858338, 5.625936364814542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.7767711685316, -961.5466022439307, -455.5167169920276, 0.02641646045759053, 0.2876293875521561, -0.04455269836068995, 0.2917046426611087, 0.06192864199017718, 0.2996413203859867, -0.07877768540105098, 0.3120491459019933, 0.09543210301352055, 0.3294985036302559, -0.1123540725858994, 0.3524803724007334, 0.1301721006693483, 0.3813326175940071, -0.1497179815896551, 0.4161216500474114, 0.1720439307471236, 0.456476553154757, -0.1983762992393827, 0.5013934945639351, 0.229926008851196, 0.5490538865200292, -0.2674630790920627, 0.3262584781762246, 0.6184594756429348, 1.841505465819113, -0.9036920907968744, 0.6037649288986811, -0.435730331781932, 0.4173633503092889, -0.3402273078184248, 0.3618792001829753, -0.3223329221765415, 0.3568694292734518, -0.3373610302359374, 0.3778471175268359, -0.3698307686701466, 0.4133989349283659, -0.4123481977579463, 0.4568802691238098, -0.4611046705689894, 0.5040519090114971, -0.5144902166835649, 0.5520670643889852, -0.5724133548481751, 0.5987991975851327, -0.6358180460131468, -0.6423152491290044, 0.7063313713285493, 11.35202456455329, -3.493500196224254, -6.638568150183083, -1.957344673859988, -4.228485425971068, 1.056606712337717, 2.626551471527081, 0.5527901502998748, -1.5670524346359, 0.2928237369304179, -0.8682190156229788, -0.1797627572714807, 0.4061836395463059, -0.1532886909026603, 0.09679996807476349, 0.1768465936273609, -0.1170417081935488, -0.2292432522445197, -0.2742907297354369, -0.2992562708270863, 0.40201700883393, -0.38229571927536, -0.5200048155415438, -5.301175868637563, -7.207800765406747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.8146309446975, -961.5954948017205, 455.5912580995108, -0.03868887300459015, 0.1914593508419486, -0.06896288380706332, -0.1789757931782649, -0.1001298844401407, 0.1678836436039876, -0.1326643353856479, -0.1583758389218828, -0.1670959289351405, 0.1506643220501891, -0.2039577762706567, -0.1450354518997625, -0.2436945939407161, 0.1419222648546592, -0.286520727014479, -0.1419791043669855, -0.3322284769841388, 0.1461191154367376, -0.3799736358824325, -0.1554340998005074, -0.4281019938694952, 0.1708890736518134, -0.2592200631304444, -0.3256852567521202, -1.483625349429867, 0.6048929864489581, -0.4753236422915989, 0.2961694592646632, -0.3223046209916502, 0.2348874153138894, -0.2714626999105824, 0.2257895769533033, -0.2588066214268311, 0.2385080365992549, -0.2654198271110554, 0.2619285315116793, -0.2829866644015172, 0.2901165131905762, -0.3071846631133203, 0.3192058852536734, -0.3358595624892154, 0.3463380609514268, -0.3683054470711298, 0.3690746037927644, -0.4048218311662792, 0.3849522860948287, 0.4463965618803197, -11.17658830910763, -3.141599888182389, -7.057308180610275, -1.612632569840935, -4.674228358739717, -0.7006254562246356, 3.103524645986586, 0.1721449712789752, 2.083843108349515, 0.1230344465499392, 1.436244916006413, 0.2805779655633087, -1.039058835442039, -0.3606873771771562, -0.8103535254099236, -0.4007449405027154, 0.6957974817861713, -0.4236310613634878, -0.6603595623427048, -0.4431665472145394, -0.6828038414913131, 0.4676302900407178, -0.7523362731509651, -0.5019606323960604, -7.451487262070271, -6.898592890440204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.8067442478319, -961.6430987511887, 455.5101352313706, 0.03574672013766993, -0.3305806211988256, -0.06018793703629798, -0.3342789822135747, 0.08398862072600807, -0.3428477394831397, -0.1075626639881692, -0.3568661462114826, 0.1314655734088672, -0.3768341259425303, -0.1564176785432246, -0.4031115942603709, 0.1833201534769062, -0.4358166092177098, -0.2132428552839921, -0.4746756170442514, 0.2473424911876484, -0.5188341233287944, -0.2866404669967078, -0.566654544358885, 0.3315822789153745, -0.3365523808315161, -0.7799477365989287, -1.92204447761313, 1.038304945171675, -0.6382333295246007, 0.4954672252621077, -0.4437009237950818, 0.3817879746615038, -0.3867630435618042, 0.3564182943353214, -0.3828941956014584, 0.3680304652111646, -0.4061335779417263, 0.3989834362533684, -0.4442583228007695, 0.4409123847406293, -0.4900404834181868, 0.4895313969246102, -0.5387255048657738, 0.5430334536942414, -0.5869290800627904, 0.6013145526212335, -0.6318954893637412, 0.6654442464724272, 11.56123863009346, -3.319983549512171, 6.821845065194244, 1.863466932603496, 4.38488470063812, 1.01067094368389, 2.749511386838089, -0.5351194258268466, -1.657256920227764, -0.2915679928571555, 0.9297221747564861, -0.1880812619045127, 0.4442416560586033, 0.167463535694055, -0.1167505114866327, 0.1950254755353985, 0.1102695455592749, -0.2505965089753026, 0.2762752306336164, 0.3233977751863117, 0.4086760961549661, 0.4088566255401637, -0.527180830087615, 0.5067736816255463, 0.6471037120006224, 6.563582277433596, 8.669169878915001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.8564496879252, -961.6978071512939, -455.611344166528, -0.05065962634433919, -0.2035667717073716, -0.08941939694818055, 0.1861819141070234, -0.1293463728361657, -0.1705641231959824, -0.1710413062870665, 0.1568853187052691, -0.2151073082088822, -0.1454027021144876, -0.2620355483771115, 0.1365557074206818, -0.3120320827642339, -0.1310718629875927, -0.364788555337083, 0.1300347438234267, -0.4192352859893375, -0.1348167335882609, -0.473360750181653, 0.1467438213440089, -0.2866158909387535, -0.2490263897518478, -1.620329947670383, 0.5848677254506903, -0.5118461330390914, 0.2897889114975229, -0.3429946413052233, 0.2320656306481047, -0.2839885316813635, 0.2246136703445073, -0.2653143559437961, 0.2379182651793468, -0.2665902029177392, 0.2609701715451156, -0.2789374326510159, 0.2877297688810677, -0.2977825578364603, 0.3140810644157221, -0.3208740171767074, 0.3367519648803812, -0.347497849625001, 0.3526960178041265, -0.3780240749856291, 11.34415339639681, 2.9276728518795, 7.241716186208386, -1.480912627484681, -4.841851735919054, -0.6174008600345655, -3.244551359081532, -0.1161699839121046, 2.196810963053788, -0.1648403832407603, 1.52378878614412, 0.3160144776303719, 1.105419207445201, 0.3942117305648183, -0.8599720166997633, -0.4347652751226382, -0.7325429176455468, -0.4593657200668957, 0.6870715556985062, -0.4812114897627066, -0.7009216608316468, -0.5083517726327081, -0.7613887957889477, 0.5458417512230326, -0.8637959811793713, -0.5970603500508016, -8.878579618167663, -8.41079729749319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.8483022209899, -961.7515375401339, -455.515103378266, 0.04757600714722041, 0.3759601994912693, -0.07952182508355922, 0.3793600134854735, 0.1109858526574028, 0.3887731574427825, -0.1426212566623932, 0.4046909058892191, 0.1752498328905884, 0.4274717745852317, -0.2098572245667174, 0.4572568690190124, 0.2475512176980405, 0.4938376701380627, -0.2894449308435921, 0.5364758189264845, 0.3364018036152697, 0.5836858088124017, -0.3885795342274033, 0.3460998677017337, 0.9269607883637689, 1.991751849844172, -1.159894903453939, 0.6683678480468542, -0.5489774865143997, 0.4666584984984303, -0.4181743697237709, 0.4083256137378595, -0.3850224904055522, 0.4052531090492756, -0.3922030940012985, 0.430154764416738, -0.4201452172640414, 0.4700533145873315, -0.4596423877934347, 0.5171413042952349, -0.5060190814650223, 0.5661040793608841, -0.5573376710742627, 0.6129220747774261, -0.6135503322915893, 11.72621780801965, -3.118567404640785, 6.963211382717763, 1.75302164155703, -4.516867569899999, -0.9561071819941682, -2.858888666291709, -0.5141429755265274, -1.740364185208108, 0.2903667692240343, 0.9878145752430977, 0.1983973188452912, -0.4807765726797618, 0.1846015909228558, -0.1358948953187996, -0.2164957212324468, -0.1043808041537456, -0.2751935128773355, -0.279826746444909, 0.3505627343904102, -0.4181686778299342, -0.4382062477600169, -0.5392140048606524, -0.5377014109662097, 0.6579315820212267, -0.6517663504946155, -0.7869275609113959, -8.05753646041288, -10.39414405360874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.9138637696153, -961.8143515653112, 455.6519677186474, -0.065587947208334, 0.2085029215343718, -0.1141904493380159, -0.1849281174071089, -0.16417292084848, 0.1635422401442634, -0.2162120711863979, -0.1445429665498645, -0.2708523356285875, 0.128343198787713, -0.3282995933633563, -0.115712162032152, -0.3881537124649574, 0.1078796554266659, -0.4491292094201663, -0.1064891874455163, -0.5088711427777188, 0.113241647884544, -0.3083741181691479, -0.1467011040433109, -1.723923205907633, 0.5382296108587682, -0.5363846735303583, 0.27092624926658, -0.3545066321432684, 0.2197099884192319, -0.287363686337111, 0.2145312764451768, -0.2614204612340402, 0.2280211406842278, -0.2553142195422838, 0.2496987336771662, -0.2598467419074491, 0.2735997743104482, -0.2703495132715409, 0.2954157424967072, -0.2845730952075546, 0.311423814533789, -0.3018822827637243, 11.46523893315575, -2.691413015229958, -7.384362245400597, 1.335236216275609, 4.985185235965488, -0.5262745591804759, -3.372485074148798, -0.05648924165287231, -2.303682267268397, 0.2076207204669117, 1.609522758219237, -0.3508002202525652, 1.172561778202216, 0.4262482117585027, 0.9119656734777154, 0.4669796982018008, -0.7727539450790861, -0.4932706593868525, -0.7182401966339386, -0.5175074770463448, 0.7247978830712355, -0.5473237053574408, -0.7783621609313609, -0.5876369322550071, -0.8723083916636201, 0.6419574139158084, -1.00657473616704, -0.7131802559475791, -10.57449072135191, -10.20410649815866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.9061412862011, -961.8770732639229, 455.5376417683805, 0.06254419195417743, -0.4232684972590032, -0.1032882224080658, -0.4264012907068119, 0.1437641786514711, -0.4367775016311054, -0.1849091479680357, -0.4547230616343913, 0.2278125351396496, -0.4803659165556683, -0.2736445954407336, -0.5135240332136976, 0.3235038064582032, -0.5535385281539781, -0.3781288842484928, -0.5990476261198098, 0.4374274060989551, -0.3541391351405594, -1.058073342162964, -2.045216966325468, 1.266080794797456, -0.6924316493113732, 0.5950376234995193, -0.4851062828675501, 0.4482900280297341, -0.4257039247593362, 0.4069187711414488, -0.4232424419027072, 0.4083834788979941, -0.4493250721690615, 0.4314669583481853, -0.4903032612085907, 0.4662810430706394, -0.5378049265577316, 0.5078722409403839, -0.5859084246214689, 0.5542724904405595, -11.84485447706039, 2.898542856056091, 7.060252299552289, 1.630303727224056, -4.621383723680353, -0.8942453459292238, 2.951610305967167, 0.4895834794482448, 1.813545938433091, 0.2881843187274703, 1.040043542488245, -0.2094177206260044, -0.5137794499925029, -0.2034268577435624, 0.1527024933413826, -0.2401406725930453, -0.1004080668438968, 0.3021385233083859, 0.2854472563703663, 0.3800924576032388, 0.4303872415260588, -0.4699267499381296, 0.5551933085574434, 0.5711417670203969, 0.6747267714850889, 0.6859780125203653, -0.8010046828883495, 0.8192592301466893, 0.94515561658495, 9.820426173212363, 12.42939017103546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 504.9930103786541, -961.9513356663066, -455.7221717257553, -0.08414743711096713, -0.2026736860667679, -0.1439128065966526, 0.1712281387505495, -0.2050964145610792, -0.1424763186319537, -0.2683067024845924, 0.1167626582609214, -0.333761142126125, -0.0948595784588155, -0.4009780128477423, 0.07811577117355756, -0.4684645116803408, -0.06843920146675211, -0.5335327087101004, 0.0679294038621997, -0.3239054824125787, -0.0116792012931699, -1.790663616927004, 0.4590524896071508, -0.5473106572190689, 0.2369585734237551, -0.3554648484778318, 0.1960271233909658, -0.2800877958506142, 0.1941244183782809, -0.2453078173802557, 0.2076091627418861, -0.2293383987055, 0.227046232106705, -0.2229498501452899, 0.2467672230652324, -0.2215577701206991, 0.2623437054600908, -0.2230571348710727, 11.53795815371153, -2.443315951606555, -7.483391968859528, -1.180817659033836, -5.101147725873458, 0.4291177015601163, 3.484008053855922, 0.006968221311336701, -2.401299468052032, 0.2524588129698827, -1.690603619495555, 0.3864574901609267, 1.238005582549325, -0.4584326101560443, 0.9641940337828574, 0.49897471755453, 0.8145568272198119, 0.5268294835097378, -0.7521215969515586, -0.5534552278380493, -0.7525858951277018, -0.5859592679598992, 0.8009010588386255, -0.6289928712031305, -0.8890676867080832, -0.6859830214698649, -1.014965640327654, 0.7599429084175442, -1.182234401254345, -0.8539617213615083, -12.58037930190747, -12.3224597531326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504.9867232586682, -962.0267397173889, -455.5858482841886, 0.08146568040030745, 0.4718570639702241, -0.1323792393628501, 0.4746520270081164, 0.1832926548394762, 0.4859370727590149, -0.2354260094769804, 0.5057808128620681, 0.2900438647951354, 0.5339800783871049, -0.3482656295242084, 0.5699120289626995, 0.410743635210365, 0.612307221970398, -0.4771765920828036, 0.3602759907915838, 1.17231410234708, 2.078779437679099, -1.355247085704674, 0.7092702971335834, -0.6327846462311433, 0.4983600087248974, -0.4713003995691609, 0.4384934063277775, -0.4210960673642488, 0.4367016135277066, -0.4152685840028347, 0.4637359288734594, -0.431277660159945, 0.5053758360548571, -0.4587373301787441, 0.5527030534382514, -0.4925622070803836, 11.91525071372664, -2.669737940207489, -7.112070179658535, -1.499950988056173, -4.695989395278955, -0.8264068408364236, 3.024764719308382, 0.4608488246132006, -1.873884959550882, -0.2834560461830024, -1.083707901266197, -0.2191901436954789, -0.5408889135616145, 0.2219393955259065, 0.1652261958197461, 0.2640887562841959, 0.09983770284304504, 0.3297673240943492, 0.2941272369903571, -0.4105473985768032, -0.4457746369230076, -0.5027821554303129, -0.5749124856717664, 0.6060241185316116, -0.6964125744179374, -0.7222036226954593, -0.8219917097087917, -0.8553991180861862, 0.961952339859114, -1.012160660965054, -1.126829376377705, -11.89125844216821, -14.82268386167739, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505.1021960848271, -962.1169026393795, 455.8338729921806, -0.1071062110747086, 0.1815070603285521, -0.179150267652292, -0.1400998028560625, -0.2522503910014173, 0.1021004970621845, -0.3266542012589974, -0.06823635379950285, -0.4018139642522497, 0.03994126095184518, -0.4760406224002068, -0.01938011015157691, -0.5463234758642321, 0.009080595156260448, -0.332710657886771, 0.1616900475175027, -1.817966811669035, 0.3426834356104604, -0.5434318586351045, 0.1858789109600244, -0.3447965208108256, 0.1597482455188877, -0.260904925528362, 0.1625453870579868, -0.2153733000095499, 0.1761648327255745, -0.1866055914925562, 0.1928056464078325, -0.1656576200451232, 0.2073444379444271, -0.1482507898985436, 11.55984343995971, -2.194330913236887, -7.539191327935495, -1.023568455741856, -5.187360036320147, -0.328277306992068, -3.575805403221234, -0.07408649072083257, 2.486163835875462, 0.3004875937099439, -1.763663794387484, 0.4247125801810033, -1.298641369289637, 0.4926794598061576, 1.013844940412112, -0.5326247822284832, 0.855408835835386, 0.5617664880260144, 0.7863621255143287, 0.5906033658897508, -0.7819719026602904, -0.625663908357995, -0.8264736550053368, -0.6712690869377209, 0.9108668466439265, -0.7306688749077851, -1.031594825877172, -0.8068049947691155, -1.19005694174046, 0.9028377648786338, -1.393080617256989, -1.022486576162642, -14.93725702842511, -14.80858779518792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 505.0986792310538, -962.2097661716811, 455.6702293933568, 0.1053158391624666, -0.5209308336066629, -0.167801730661908, -0.5231587860538264, 0.2305615961092414, -0.5350545218265784, -0.2949981297092716, -0.5563330952365698, 0.3622987997093375, -0.5863529471226727, -0.4330778853603579, -0.6238972077621375, 0.5068738237225937, -0.3645929382416744, -1.269034197433159, -2.091002309996033, 1.426568270000934, -0.7184531759372009, 0.6617359656374076, -0.5062857257808602, 0.4866398522234159, -0.4468522920838534, 0.426758635928322, -0.4461365544464869, 0.4117361542474164, -0.4743095042403939, 0.4180529165899515, -0.5166800360497492, 0.4350417285374433, -11.93487401223153, 2.441424296363036, 7.120614763298893, 1.366543100975028, 4.739536856455961, 0.7537631620120923, 3.07601221737414, 0.4269745581475306, -1.918657953164775, -0.2740524529274999, 1.116076917175963, 0.22506572849195, 0.5595705076145522, 0.2373597796023182, 0.1712561169743348, -0.2856470413363019, 0.1044690985263356, -0.3555730312438909, -0.3071946247653678, -0.4396379038796807, -0.4651362087062904, 0.5346799860173224, 0.5985834061049665, 0.640392538677784, 0.7224826043854548, -0.7585342198697523, 0.8484129027006324, 0.8926513574029241, 0.9861836715435827, 1.048258602424987, -1.145257873605194, 1.233529400113939, 1.336236455566228, 14.30571745164884, 17.61787905052259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 505.2522684045481, -962.3209091459635, -456.0021243571045, -0.135204950106543, -0.1394617235875679, -0.220127550372105, 0.08571928452292403, -0.3049409043236431, -0.03659504642708369, -0.3890574180257759, -0.006436425325169574, -0.4706108350838175, 0.04096694825184889, -0.5462820434899358, -0.06401136348259447, -0.3343815237245166, 0.3770481192076843, -1.804641348780662, 0.1862488607745145, -0.5241026690461806, 0.1165329851236274, -0.3218108422408898, 0.1103182214298427, -0.2288701150093211, 0.1197089351929335, -0.1702872232337064, 0.1340809261902273, -0.1252999394856697, 0.1478955058540885, -0.08560365295523495, 11.52576378974406, -1.954372039977865, -7.556599118670414, -0.8696416229998727, -5.243139426145771, -0.2265893727803473, -3.645001180400495, 0.1444022525350471, -2.554614576511419, -0.3526936465053139, 1.824862320705907, 0.4673053399212604, -1.35071736012791, 0.531014596069754, -1.057368223650742, 0.5699553062659776, 0.8919929683549828, -0.5999463785086376, 0.8178418137071368, 0.630579143988404, 0.809941527510296, 0.6678139095408332, -0.8520024722473533, -0.7156241704641815, -0.934272389637509, -0.7770482361065687, 1.05215121053177, -0.8548848555187463, -1.205491122946197, -0.9521918975626668, -1.398620727934507, 1.072675726622418, -1.64131363116556, -1.220973810147752, -17.67939399433237, -17.69696009914344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505.253017754159, -962.4364747394324, -455.8036682152643, 0.1351126787098899, 0.5695864039965876, -0.2104884546621504, 0.5708245939994814, 0.2862709367223656, 0.5827540820095056, -0.3637808074554126, 0.6046421105793508, 0.4436589944498553, 0.6352690932451194, -0.5253459950861361, 0.3677303232551267, 1.347453344746686, 2.082926012424898, -1.479753805386014, 0.7203282114221324, -0.6816721371214693, 0.5093388325091368, -0.4939242839721554, 0.4515458590346876, -0.4232358982106663, 0.4527789299653081, -0.396731197291685, 0.482881928016134, -0.3902827551017815, 11.89894466315718, -2.22090063369331, -7.092747734361658, -1.234026593177227, -4.753181046423188, -0.6771950822291326, -3.104140201531702, -0.3866040328596608, -1.945692839472312, -0.2572635974024494, 1.134652874596721, 0.2236606491303219, -0.5673297987656002, -0.2460750486326881, -0.1685020505679479, -0.3012253263999956, 0.116250006339078, 0.3761133268443195, -0.3261558958623166, 0.4641080126177665, 0.4894613648488647, 0.5625417455833565, 0.6266107088037656, -0.6712930493524196, -0.7526658702381472, -0.7920386924545679, -0.8791718349910133, 0.9279565248449416, -1.015643135720146, -1.083803569712843, -1.170845050805069, -1.266390093671474, 1.354037366376675, -1.485576073474351, -1.576400237129784, -17.08748638019799, -20.84557350276546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505.4566106321672, -962.5733809140785, 456.2446669456525, -0.1688459112995087, 0.07034403444173644, -0.2661925457838576, -0.00201291370003544, -0.360842606721788, -0.05949303565750251, -0.4507864673737421, 0.1115494205452214, -0.5324222730975748, -0.150692878879795, -0.3285617939930261, 0.6352611728442655, -1.750928292301286, -0.01079073303553477, -0.4892798325673497, 0.02887167931331536, -0.2862455254245249, 0.04809364620457122, -0.1833951993284249, 0.06648914871000661, -0.1090258324830243, 0.08288235905924721, -0.04388087225057338, 11.42397334205316, -1.730411869135157, -7.54872126209005, -0.7246099232898299, -5.271259193087543, -0.1273016997487224, -3.689949677751227, 0.2168582799717596, -2.60315967042078, 0.4095966898831329, -1.869993120606597, -0.5156814339442469, 1.38982674111601, 0.5753023219269168, -1.090398441258875, 0.6129015965698307, -0.9200861758805992, 0.6431623698555172, 0.842501341267445, -0.6749156741454959, 0.8325483404989181, 0.713623361375966, 0.8735437835352988, 0.7629401789412279, -0.9551462767593792, -0.8256933589190248, -1.071962632591364, -0.9045223083409126, 1.222727743028186, -1.002327294123344, -1.410056693758905, -1.122638822704943, -1.640877341853048, 1.26995573475215, -1.927844246417485, -1.45003227706329, -20.82307411706698, -21.00155992122358, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 505.4627685739322, -962.7160457792522, 456.0005200775191, 0.171584773148045, -0.6169168507138828, -0.2608304899009982, -0.6165570206329561, 0.3501697797170152, -0.627679892134454, -0.4403605479968019, -0.6489829640847168, 0.5308300518602039, -0.3709301239614179, -1.405815328723569, -2.058062413586543, 1.514443425105629, -0.7159719725315271, 0.692368587676033, -0.5085223559524636, 0.4927483234228063, -0.4539119844509412, 0.409786918662957, -0.4585601641836641, 0.369060795992091, -11.79766504079141, 2.012479939028762, 7.043555197226082, 1.105137043752469, 4.741914128289426, 0.5972094437860065, 3.109868363286502, 0.3381216846268515, 1.953867566077465, 0.2299457233923843, 1.137533669668121, 0.2109462622238532, -0.5620043637972509, -0.2436579564637029, 0.1548443572169821, 0.306307345836395, -0.1370525568840376, 0.3869435542219369, -0.3524856590577575, -0.4796460558277326, 0.5197151476832278, -0.5821783731153887, -0.6593590868915518, -0.6946136487705999, -0.7866414714126642, 0.8185951248778229, 0.913148489829942, 0.9570365064732725, 1.048232753669613, -1.114138187570384, 1.200190769798651, 1.295704602378807, 1.377356049197987, 1.509847257194258, -1.589258765649288, 1.768262183131415, 1.848069109594906, 20.23420853365266, 24.50766781694805, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 505.7302235739897, -962.8808897579297, -456.5799751938149, -0.2074665694865197, 0.03179270034629982, -0.314911648796822, -0.1160409354435016, -0.414899941317193, 0.1896042423128672, -0.5035929949910716, -0.2485406654930217, -0.3148720318285624, 0.9334281744469859, -1.658358518134329, -0.2459729705045449, -0.4395368675508144, -0.07575020637815727, -0.238298110932487, -0.02543448920587639, -0.1242798269864487, 0.00493022955061947, -0.03092176867721523, 11.22885110571361, -1.52501965073773, -7.543615992492188, -0.592424165410839, -5.281049101322963, -0.03384112642572992, -3.711740461545836, 0.2895170179898658, -2.629192995613142, 0.4707504030082303, -1.894805671641967, 0.5704662427677495, -1.411023004415436, -0.6267630427501154, 1.107747137626518, 0.662893542409588, -0.934479879776553, 0.692778028843108, -0.8551991883552512, 0.7247338818733859, 0.8447234697913153, -0.763869215310247, 0.8860283550216375, 0.8135940022344247, 0.9682811777983255, 0.8765586475933742, -1.085448060890765, -0.9552512796328857, -1.235412367552187, -1.052408869707694, 1.419557246828857, -1.171343028943237, -1.642863640112578, -1.316259793628108, -1.914688728881414, 1.492601140725079, -2.250602542324417, -1.707371208414184, -24.34911222913227, -24.69682337532403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505.741435494995, -963.0504155847199, -456.2741036613125, 0.214479472715505, 0.6621861981953745, -0.3177872890555592, 0.659477202360043, 0.4199363883935496, 0.6686966992655288, -0.5204604440629446, 0.3760250100904552, 1.440136329901755, 2.022077415101587, -1.529242860821105, 0.7070177320978236, -0.6931608182158253, 0.5052503305200324, -0.4823639976910435, 0.4557292865512613, -0.385316970783089, 11.61106437256959, -1.818394061749481, -7.001963622764721, -0.9813357744591734, -4.716881178048456, -0.5141556100260524, -3.0969906159148, -0.280097039848389, -1.943793145915662, -0.1889996708430733, -1.123912478997343, -0.18264542910118, -0.5421787669130134, -0.2251582877779384, 0.1286970772462299, 0.2956319802801666, 0.1683473607021652, -0.3827115546150297, 0.3873303842983701, -0.4809087334725033, 0.5565590506576561, 0.5882754140327704, -0.6968797879222629, 0.7050226515021639, 0.8237435880499643, 0.8327756810598531, 0.9488550233241532, -0.9742434109257527, -1.081502395328126, -1.133196471873608, -1.229668358197086, 1.3146823158554, -1.401016876114531, -1.525516610156299, -1.603885466468684, -1.775180446964151, 1.848426978531237, -2.07736997486411, -2.148126517552196, -23.69694322453203, -28.55450387022301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -506.0870994444517, -963.2380980143934, 457.0227998243373, -0.2485169973393713, -0.1708755956446555, -0.3608775819654662, 0.2702463148020641, -0.4583288971296218, -0.3528976210982101, -0.2928214663649001, 1.263652831351624, -1.529505325655311, -0.5130238387785291, -0.3760704452139064, -0.1942204111583247, -0.1786533015765691, -0.1073884668217014, -0.05177939288958904, 10.88603291358535, -1.337180308687955, -7.596957579622598, -0.4747035515000937, -5.293796730009392, 0.05043538802520772, -3.716922670417109, 0.3592165384067125, -2.632466505734362, 0.5340539274802235, -1.895818658518178, 0.6306645190841967, -1.409275395512805, 0.685196075280273, -1.103655066088433, -0.7201507688034566, 0.929097908006366, 0.7491204140241028, -0.8497455883339168, 0.7802302755862421, -0.8402329799755162, 0.8184522926487809, 0.8831625818888247, -0.8670840673667023, 0.9672225533587266, 0.928669763681313, 1.085819612885373, 1.005581967725039, -1.236140490171399, -1.100404676155905, -1.418629151651308, -1.216231218475, 1.63686735128274, -1.356940773255257, -1.897950583839266, -1.527515842606489, -2.213574416593122, 1.73441741027332, -2.602284267564217, -1.985971407789865, -28.17877747730259, -28.69146328143491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 506.0995030305882, -963.4251163002542, 456.6319082336776, 0.2614208946746435, -0.7049929537479934, -0.3775469776448249, -0.6990129299253891, 0.4897228036148983, -0.3853539179729928, -1.442770760684808, -1.98216326068838, 1.520548699194699, -0.6953740263821517, 0.6824190354472228, -0.5011233283967811, 0.4613118931865929, -11.29796537330876, 1.64449147211759, 7.022169169615215, 0.8641805347117423, 4.699276336140136, 0.4291404936096105, 3.07407334406547, 0.2123539984677152, 1.918769023964996, 0.1324679335590006, 1.09476296754075, 0.1352170432778689, 0.5077652860572863, 0.185910694584077, 0.08952722613195557, 0.2638426913931702, 0.2107393703819989, -0.3576622830692115, -0.4310960937466334, 0.4619085175014147, -0.5999884739982514, 0.5746756856778464, -0.7385868745992383, -0.6961886963160135, 0.8626657356149082, -0.8280065670824533, -0.9841390899478625, -0.9726569738046391, -1.112325598821782, 1.133551592359431, 1.25500535004336, 1.315134855586846, 1.419345051714987, -1.523232765666847, 1.612773491431782, 1.765677755404849, 1.843930722061922, 2.053380737994717, -2.123837663941296, 2.402145835888836, 2.467526732917271, 27.35441123139784, 32.85590905559759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 506.535108831963, -963.6167931351213, -457.5765788302061, -0.2861761743318959, 0.3461105740480527, -0.3947395339422998, -0.4564377447058072, -0.2617296324114806, 1.611734008281398, -1.367678013419382, -0.8010059019283635, -0.3006880659872381, -0.3213053025395997, -0.1085392364738896, 10.2725543041519, -1.168526626564622, -7.82064895354263, -0.3713337568773262, -5.352508738636831, 0.1222893217356636, -3.722102280656161, 0.4211608377876347, -2.617734196748431, 0.594901972075254, -1.871992486237874, 0.6925901148668441, -1.38058734154616, 0.74787922336183, -1.072581160949938, 0.7826644587414839, -0.8975809094419182, -0.8105767210582541, 0.8193405723194567, 0.8399098661914142, -0.8120222073214457, 0.875770220099946, -0.8576881155650289, 0.9215289264833487, 0.9444708197958593, -0.9797395325755353, 1.065205863140835, 1.052722623302901, 1.216460299462672, 1.142943964195683, -1.397905992342116, -1.253291158068077, -1.612055771894061, -1.387322544088788, 1.864373007497077, -1.549535917211965, -2.163879565979816, -1.745709327273886, -2.524523036401785, 1.983325027495365, -2.967830167452788, -2.272019538910634, -32.14658674016512, -32.79917505195669, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -506.5385766328296, -963.7950492893284, -457.0688147458119, 0.3064737493454045, 0.7451295489392065, -0.4320824231461616, 0.4015780387117531, 1.401276142639599, 1.946107688605819, -1.48150526542528, 0.6828643239680722, -0.6570927744752225, 10.7638914509755, -1.517523554864524, -7.212410025151229, -0.7594650802490791, -4.727779988834981, -0.3459479511652795, -3.056982946412603, -0.137792378203823, -1.885965897429857, -0.06147034578463532, -1.053619513536147, -0.06771520575915954, -0.4606626658479292, -0.1231959710791077, -0.03846712123960974, -0.2069083481076168, 0.2634078610725342, -0.3068550531907182, -0.4829610805074276, 0.4170585080045313, 0.6489288141016536, -0.5352933146117154, 0.7829424333419256, -0.6615771584317809, 0.9012282823913962, 0.797293809624204, -1.016026767128407, 0.9447489034757597, 1.136789528309099, 1.107026430413602, 1.271196791521118, -1.288051047513149, -1.426037977791292, -1.492842932266066, -1.60802186802236, 1.727960361905206, -1.824590624194746, -2.002232368690374, -2.084863210703189, -2.327985171787624, 2.400861196107053, -2.723108602478969, -2.789278491542184, -30.98867169157857, -37.17333705763805, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507.0685285381397, -963.9513225378075, 458.2239814297878, -0.3105094100833926, -0.5489621604214274, -0.2207001619135986, 1.956288574692065, -1.176681603230856, -1.09375598392015, -0.2158081274278867, 9.039432404200522, -1.044683628994101, -8.468785467802409, -0.2840135792540254, -5.542745543449104, 0.1779572946344857, -3.761606785421675, 0.4684797722662275, -2.598930526573113, 0.6453592933930452, -1.827562760363265, 0.7487181877066253, -1.324101584715386, 0.808286952945908, -1.010847733279209, 0.8449471423636297, -0.8346332998503472, 0.8724833572892089, -0.7577244949265606, -0.8996473668870159, 0.7532210193109008, 0.9319700291879087, -0.8023001449790493, 0.9731169256921198, -0.8923272475697563, 1.025808942383718, 1.015464062032189, -1.092414194595597, 1.167634916611444, 1.175336052505714, 1.34782203022553, 1.277290630873182, -1.557658237162463, -1.401532229855291, -1.801354910586623, -1.552090405661354, 2.085991956058786, -1.734049468830996, -2.422322212155974, -1.953922901839827, -2.826392120689291, 2.220125678702697, -3.322576673428888, -2.543480350687961, -35.98052650947123, -36.71809122641062, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 507.044358239568, -964.0731038498507, 457.5609921269437, 0.339186245230021, -0.4273969477024003, -1.29863116329144, -1.9212155175519, 1.401898391182813, -9.726271535257508, 1.553331598619713, 7.831565439526993, 0.6875158984530817, 4.876888986260434, 0.2743174969664351, 3.073278715408381, 0.06481527948414105, 1.857848936458911, -0.0172058553164797, 1.007270300003323, -0.015493908041739, 0.4052734656641692, 0.03886914827152865, -0.02120544418256508, 0.1245454447689218, -0.3236527085621929, 0.2283392770229724, -0.5404903245807748, 0.3431422365149781, 0.7009598725924222, -0.4659137295498349, -0.8273152365264473, 0.5961381254254794, -0.9363871554481444, 0.7348226673958823, -1.040881025210011, -0.8839501590062537, 1.150503496114657, -1.046240633846492, -1.272940104510185, -1.2251386270737, -1.414709746711867, 1.424957765640063, 1.581930391736834, 1.651204358082938, 1.781057179003545, -1.911084747398959, 2.01966517958886, 2.214321569792053, 2.307406860022854, 2.574510651133963, -2.657307283406697, 3.01140106208788, 3.087681881697911, 34.27753948458455, 41.14981894020637, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 507.6607402118162, -964.1324178062038, -458.9202293050566, -0.1686378441806772, 2.26918481619089, -0.9605814475857066, 5.330862093858574, -1.138949076550252, -10.32445599072876, -0.2278821376240088, -6.053185271755386, 0.2111992660067487, -3.90195016026017, 0.4916948027703619, -2.604992480633718, 0.6736549508248011, -1.775821097551055, 0.7869195888388132, -1.245117363143849, 0.85511197805049, -0.9191931180792211, 0.8969679044521599, -0.7382433689234038, 0.9261198029941115, -0.6611696707630135, 0.9518531231496314, -0.6589875072665196, -0.9803308643977939, 0.7113879440961655, 1.015736615269503, -0.8045956932013681, 1.061136120387407, -0.9298638326235749, 1.119078818816151, 1.082360654284157, -1.191995373104534, 1.260356303986052, 1.282483463463084, 1.46470232087969, 1.393532235248562, -1.698581785001543, -1.528731717952134, -1.967581344572053, -1.69251044093007, 2.280123193492441, -1.890433165088037, -2.648431439034473, -2.129603108392172, -3.090370039310071, 2.419171909638182, -3.632813078727661, -2.770878258545604, -39.30905440906147, -40.04060379184506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507.5823569101401, -964.1327952153448, -453.1525519625071, 24.40574541777206, -56.14514099816383, -2.422186406437542, -25.22429964965732, 1.444867813899084, -12.70852566601807, 2.547941134817951, -6.850174344806808, 2.975175307411678, -3.480196946314358, 2.990960801627664, -1.417378358439735, 2.740289627402432, -0.1451237393712128, 2.339923467563752, 0.6224326970934283, 1.877490924183014, 1.064055147754233, 1.410245383546048, 1.298670025286794, 0.9699280356465935, 1.407692033072784, 0.570056365428795, -1.447206482446987, -0.2126606347621276, 1.45549590027687, -0.106700427367443, 1.458217449192367, -0.3956662520866513, 1.472227262174601, 0.6631737994890589, -1.508479947856337, 0.9184906204287088, 1.574231058518403, 1.170872531544465, 1.674716872315271, -1.429622942231864, -1.814460422530907, -1.704464741494625, -1.998356318905909, 2.006172401087063, -2.232676942948992, -2.347554579943283, -2.526186304333157, -2.745015993852846, 2.891570896342571, -3.221095840304374, -3.347521504585615, -36.81977934526557, -44.35189490614219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -929.5916205582998, -941.0365306526329, -83.0205570677121, 28.17439325219577, 75.87533570257695, -1.696520866989221, 26.60699159785555, -5.409361115615388, 12.56934180801319, -6.877261269176024, 5.687519948140556, -7.195311665250237, 1.882753730836734, -6.793257487426405, -0.243954230030588, -5.985952308839798, -1.376766663139118, -5.007212173644259, -1.909776318300887, -4.012480308119807, -2.086793153052898, -3.09156896456971, -2.063263714473415, -2.286718302219568, -1.938915871123262, 1.609507069182077, 1.776860515294737, -1.053845022404726, -1.615732919376842, -0.6048003006133782, -1.477928334454509, -0.2440699657679927, 1.375377784059099, -0.0469141625735761, 1.313620215666728, 0.2854287861559656, 1.294663638447388, 0.4868539710419071, -1.318984666977386, -0.6646185691294326, -1.386978049510149, -0.8304585614062736, 1.500098994703478, -0.9948396546158864, -1.661963350617514, -1.167481907502111, -1.879718152404978, 1.357937431688009, -2.166151621008019, -1.576149522040385, -22.8426934593021, -23.12611835160169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39.74325951288207, -1186.431523127095, 891.9981651399358, -63.78630277783328, -227.1996575944138, -21.36263524515902, -134.9940747033731, -11.91053467248452, -92.38872197451053, -7.137773558531492, -66.40883312595787, -4.159839971417969, -48.55372147263157, -2.266393752869894, -35.63597637393651, -1.094787188040574, -26.12268218585725, -0.3740073215893996, -19.11470230422248, 0.09756406262595478, -14.00177931344374, 0.4539441356094622, -10.33193495392373, 0.7738574705683541, 7.757284995888257, -1.098280483037155, -6.008113485615493, 1.446238834722165, -4.877217783576145, 1.8260185749213, -4.208135864627979, -2.242051708641171, 3.885327967594733, -2.698727377102662, -3.825903864288941, -3.202420566106344, -3.972879079281471, 3.762630114298621, 4.289949398982492, 4.392965687767301, 4.757754982238793, -5.112366708632306, 5.371588692477695, 5.947098472803463, 6.140643591545218, 6.934244894234055, -7.089006463457302, 8.127774292215216, 8.258953377781268, 92.70654077487185, 110.8916502269361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 786.2689336767368, -815.9863464302587, -502.0050839453779, -90.73950140949509, -56.87432228337573, -51.99165992440596, -33.34091308622924, -34.04113075780467, -21.43377478029886, -23.06225529920733, -14.14681954842458, -15.59204793972567, -9.417386184375989, -10.29776713475104, -6.330831000664216, -6.493371297236832, -4.358412747427537, -3.752309549753657, -3.152344856102681, -1.780646844936822, -2.474087100314609, -0.3652993582829661, -2.159473586844666, -0.6519861739832791, 2.096803744336349, 1.389930130712824, -2.211583888600316, 1.937926207260219, -2.455755504596307, 2.363440987643714, 2.800164407662094, -2.717650504667941, 3.229401718516578, 3.039864785640401, 3.738480085017688, 3.361030069362782, -4.33092205126337, -3.706511692235448, -5.018136256707792, -4.098399590204935, 5.820036523452692, -4.557455346103694, -6.767262056924007, -5.104890578388991, -7.905837082177761, 5.763931574597367, -9.306048512065884, -6.560810197006163, -99.50178779115197, -96.99432423638203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -321.507651312602, -910.0072663299117, -591.4192374647588, 2.348605212951472, -124.3655421160505, 2.519037737123322, -84.26548427045947, 2.573811571186274, -59.67166318149743, 2.542520312756454, -42.7047736707389, 2.300331152371294, -30.40208946365, 1.868906337655643, -21.33294075666419, 1.342284397278395, -14.64893633535513, 0.8120400288034471, -9.763872639971726, 0.3354516359221829, -6.235124240181859, -0.06553144651026029, 3.716540641341441, 0.3931256138944335, -1.936614843167815, -0.6618294981785842, -0.6848912674945181, -0.8900811776756501, 0.199127185761292, 1.095738020332698, -0.8359393889447138, 1.294255063198197, 1.31492328463649, 1.498467646770268, 1.702006092723583, -1.719202962560454, -2.046109758511857, -1.966270920929146, -2.384503193805934, 2.249628522569334, -2.747318106025392, -2.580712635786556, -3.161596749861384, -2.974131519986319, 3.655356432931151, -3.449999148965924, -4.262437651783252, -40.50763259878801, -54.03571513338518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -344.0713331149046, -952.725510121053, -416.8443995257026, -1.06754986885831, 45.84646413547254, -1.058403868892041, 31.77101137436911, -1.019954379151325, 22.80926291367322, -0.9071659718312616, 16.5022307529763, -0.7068440514134203, 11.86549955113823, -0.4524387095841191, 8.40538251216984, -0.1887047159960708, 5.82217952814256, 0.05065134824649881, 3.9055606710333, 0.2489662036219396, 2.495002070050333, -0.4034520268008114, -1.463934384255092, 0.5196357992327747, 0.7123003579271661, 0.6066099511692123, 0.1617857928516114, 0.6740824416340541, 0.2481361170724213, -0.7308946494537877, 0.5637692276795909, 0.7845255109986143, 0.8204101808272708, 0.8411152733767217, -1.045170820232432, -0.9057592610820282, -1.259454345228306, -0.9828579943559127, 1.481169292533973, -1.076498380875339, -1.726879905570609, -1.190773320672958, -2.014212738164722, 1.33001392092199, -2.365085594225679, -1.498734072363048, -24.7211856905308, -22.78270797180551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -442.6907539702701, -958.4534825933663, -525.0790057885872, 0.4830776577375593, -34.3647256467903, 0.6314006455905202, -24.3348172625214, 0.7058287395586245, -17.41434346405917, 0.6762376591103615, -12.39697921157262, 0.5581637364705839, -8.69979036834804, 0.3923850266317464, -5.976507461418807, 0.2173455777493897, -3.987524183530083, 0.05722832788370733, -2.551827878146577, -0.07817291001085155, 1.527904886231801, 0.1888356566437113, -0.8048407679343973, -0.2797226979198223, -0.2967379564291665, -0.3574286627927332, 0.06184616772257682, 0.4283754863248733, -0.3199942490552064, 0.4980819539573895, 0.5140709901171847, 0.5710827814267276, 0.6708672126762525, -0.6511525664070008, -0.8102397807569323, -0.741692223923563, -0.9473054632669835, 0.8461535960354408, -1.094295489000015, -0.9685246843169275, -1.262227087133157, -1.113917136472349, 1.462601455450445, -1.289351439294402, -1.709469206945622, -15.37887836207466, -21.35497052390839, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -428.3101323308657, -960.7693411578422, -474.342891355963, 0.04496720051684034, 19.40931799070891, -0.1673280524757375, 13.92731470257143, -0.2557102683826377, 10.07353665325728, -0.242060653548165, 7.24394212742543, -0.1622596506986207, 5.13483244576956, -0.05331961081104578, 3.56174021542921, 0.05739982125560644, 2.395487323148687, 0.1547037661558607, 1.537813226473135, -0.2331433212654467, -0.911475734135779, 0.2933066494077648, 0.4555476781368759, 0.338711646959178, 0.1224074525370889, 0.3738275323799262, 0.1247194820414306, -0.4030263556972666, 0.313950693100759, 0.4301452572858044, 0.4667062381065167, 0.4584109424144206, -0.5994212319450118, -0.4905216003205117, -0.7250428404204554, -0.5287981906358582, 0.8543669982497838, -0.5753440721198483, -0.9973355647586041, -0.6321710321880218, -1.164486942694627, 0.701242039243045, -1.368908791826208, -0.7842864184450526, -14.12684531258338, -12.34623872489789, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -453.5947291948034, -961.2035052944622, -514.6492553039509, 0.4825672633043259, -14.63884772835812, 0.4728625789819674, -10.46609788926318, 0.4223503876316634, -7.442448460093368, 0.3329214300137407, -5.216277203642393, 0.2244794898769337, -3.578425180158726, 0.1168914409785088, -2.383907106504585, 0.02230924598695424, -1.523064408492582, -0.05507450668021285, 0.9101446618023145, 0.1163992499184654, -0.4779690543716839, -0.1653691281434937, -0.1745659182869991, -0.2063444223336585, 0.039602682285727, 0.2433424061835201, -0.1941384821064465, 0.2796828695057331, 0.3109312828739628, 0.3179775825463946, 0.4060797546311572, -0.3603111282843304, -0.4915070533384577, -0.4084758403447379, -0.5763074319912898, 0.464226600596208, -0.6678922566067029, -0.5295368917237421, -0.7730382893753434, -0.6068884203575737, 0.89897954742318, -0.699610046209151, -1.054787068983536, -8.609652087354156, -12.8579032884007, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -446.0038881412778, -961.3008847776382, -491.7175432274707, 0.1943007163358473, 9.906958572878336, 0.02345340704111558, 7.173866633051514, -0.04242250621999444, 5.166677008312024, -0.03855525151603313, 3.669944479628774, 0.002466257542828118, 2.552845379807538, 0.05656495909653988, 1.723914622877545, 0.109389231273188, 1.113704343754537, -0.154326556966241, -0.6676835332672917, 0.1897295486417266, 0.3428450695372164, 0.2165827955413441, 0.1055512320135479, 0.2369862849228626, 0.07020719515760521, -0.2532876029564753, 0.2043491608705294, 0.2676915043075377, 0.3120764248151033, 0.2821088161452195, -0.4050727622745833, -0.2981576244336274, -0.4925541862044852, -0.3172019895469589, 0.5822117700075157, -0.3404097672817541, -0.6811329794436601, -0.3687673652742239, -0.7968425416319206, 0.4030092522096378, -0.9387219855322787, -0.4433201240139981, -9.48396669353969, -7.512457904532764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.4328410845339, -961.0071327788293, -510.5524809166798, 0.4111184351918524, -6.829176411984103, 0.3361386406116716, -4.837760995294381, 0.2502764457319974, -3.37603312459292, 0.1626067927924462, -2.304361871960009, 0.08316396128852019, -1.525802347503765, 0.01755632843579077, -0.9670336043134922, -0.03330222974734559, 0.5708045845795261, 0.07150324591409365, -0.2923816210281723, -0.1003945101884875, -0.09727229178655826, -0.1234001397404901, 0.04066183518259721, 0.1434628037600845, -0.1409083950734027, 0.1628660783751044, 0.2178168134361163, 0.1832999676758237, 0.2819041405558238, -0.2060026677157682, -0.3409546634835108, -0.2319393727963857, -0.4009411424908401, 0.2619589247865226, -0.4668200628062795, -0.296933951573955, -0.5432787484033776, -0.3378788989574256, 0.6355506795869581, -0.3860209451465164, -0.7505093709414847, -5.105954891950948, -8.781352077679234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -452.3304115985688, -960.7608316563131, -498.9493530569109, 0.2350526026148503, 5.452765778836735, 0.1144413317324554, 3.942743416705443, 0.06575193956155491, 2.813198060193881, 0.05979656827468521, 1.967247253532042, 0.07476481999950792, 1.33716927453409, 0.09679248669884244, 0.8715028539151225, -0.1184142632347635, -0.5297539525430655, 0.1364376500843866, 0.279883315023392, 0.1501362016677295, 0.0967277743463185, 0.1600101117691853, 0.0392623455333137, -0.1670646460060667, 0.1431394010753874, 0.1724122128993197, 0.2264583241675105, 0.1770984549392259, -0.2981564198474064, -0.1820260600993679, -0.3653319148757525, -0.1879277629602221, 0.433953340411416, -0.1953399947167113, -0.509568285645821, -0.2045344918635905, -0.5981230469754966, 0.2153519198444021, -0.7071121725209079, -0.2267809863092065, -6.916134867991262, -4.577761093605716, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -457.2821812366932, -960.4249791586459, -508.406803593705, 0.3314600419524246, -3.131681676256192, 0.2387019139078725, -2.160834219382301, 0.1558482495866747, -1.455216313053963, 0.0871664614814559, -0.9473663287775979, 0.03419837662062589, -0.5864332248384088, -0.00432458333663224, 0.3329441537673535, 0.03128353627523617, -0.1562804280922136, -0.04999176058110387, -0.03302664185232766, -0.06346986930062509, 0.05440406541970694, 0.07411879158850035, -0.1190014687949248, 0.08368929303132233, 0.170242902230307, 0.09336390814052453, 0.2150244781654537, -0.1038994057814532, -0.2584450235024301, -0.1157578492126067, -0.3044688209695106, 0.1292115445076401, -0.3565100159947209, -0.144401977523982, -0.4180074998279228, -0.1613341173509704, 0.4930955968984639, -0.1797468301316631, -0.5875758018381303, -2.883918681365754, -6.475332235697652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455.0155128763931, -960.1981319999863, -502.3405067762259, 0.2542491852062611, 3.131489617552865, 0.1670909868692584, 2.252853211778165, 0.1252928337711295, 1.589512082778476, 0.1095856577497441, 1.091340808355062, 0.1069182126000217, 0.7200044935476559, -0.1094190566032491, -0.4450831238377702, 0.1128668647285452, 0.242278665253527, 0.1152987829103931, 0.09231415427747117, 0.1160486567327278, 0.0199468566918988, -0.1151073353429353, 0.1062892592500759, 0.1127688588569004, 0.1758680910212436, 0.1094184084764459, -0.2358574126255636, -0.1054171918706391, -0.2920380304032841, -0.1010121781961295, 0.3493514987155218, -0.09624584560739964, -0.4124750394872714, -0.09081842264154093, -0.4865154108104184, 0.08383114316573474, -0.5780232680965639, -0.07323520324207744, -5.417494102776475, -2.610329978177295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -457.4493352528837, -959.989698663586, -507.1401709474283, 0.286121368416555, -1.277585644216466, 0.1965314549725704, -0.8296361757391397, 0.126150204699882, -0.5143609771621193, 0.07411570076725935, -0.2955753603877085, 0.03772510850741548, 0.1456031206933647, -0.01346154359781873, -0.04333286374184881, -0.002152095041771392, 0.02709212845432325, -0.01203934086886425, 0.07735364223423614, 0.0184196895883106, -0.1159068759281938, 0.02282300685654621, 0.1487971666617892, 0.0262064128753012, 0.1803514533516238, -0.02907864514102102, -0.2137591327763108, -0.03161342078618522, -0.2515671959433391, 0.03371538499219204, -0.296132352891611, -0.0350175049709756, -0.3500936488703787, -0.03478013453039555, 0.4169709529674968, -0.03159734770668429, -0.5021045752952693, -1.359189375072352, -5.137658691990629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.1816434524407, -959.8717700049582, -503.9632365405722, 0.2710790852321758, 1.868103062408168, 0.201731258488131, 1.336518241630041, 0.1607751340471668, 0.9312150774562233, 0.136744864573931, 0.6245135082334604, -0.1220039814863793, -0.3939736948288325, 0.1118064051450731, 0.2212852465254199, 0.1033807000084225, 0.09161715516324435, 0.09519253715708004, 0.006912715432142194, -0.08645745594199336, 0.08374228844933723, 0.07681239647201249, 0.1463556032104103, 0.06610891321647951, -0.2007459498469933, -0.05425819168043056, -0.2518586281471307, -0.0410971094331229, 0.3040320723461977, -0.02624784596427822, -0.3614859250552229, -0.00891781755958999, -0.4289462964027577, -0.01244251094956762, -0.5126072586924517, 0.0408259308513107, -4.58392784156386, -1.246428269166816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -457.3475780693374, -959.8013715842148, -506.3396543584333, 0.2767928687754797, -0.3507679094211566, 0.1964561308894208, -0.175454380884666, 0.1369018349817932, -0.06171313754209207, 0.0948996407982716, -0.01057868944381583, -0.06660941623334156, 0.05625273023108911, 0.04841249702381548, 0.08604193382443961, 0.03731356346471822, 0.1075373379529352, -0.03107613794426697, -0.1259926823207867, -0.02817283438261568, 0.1449896389440946, -0.02768249041446454, 0.1669869201040142, 0.0291682437735234, -0.1937749805283248, 0.03258348528255475, -0.2268682319663226, -0.03823766887670215, -0.2678770945127273, 0.0468458004168191, -0.318925108122332, 0.05970717770473746, 0.3832225686061499, 0.07913811719945757, -0.4660307877839935, -0.283439945606522, -4.418862273762176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.6253594082521, -959.785934980976, -504.6940382140627, 0.2905146476860859, 1.164315682401765, 0.2287874192618208, 0.8278901909084367, 0.1855742595690876, 0.5670794972681463, -0.1543255466444327, -0.3664024755348232, 0.1304088025212251, 0.2126108080946933, 0.1106574375165147, 0.09451778970188139, 0.09297359092819958, -0.00282311457116445, -0.07598524984762452, 0.07011698901922347, 0.05880426133990931, 0.1305654348080172, 0.04082738142446098, -0.1837050518882388, -0.02156733869032677, -0.2339588783576583, -0.0004920786516655548, 0.2853442102851388, 0.02315710617373445, -0.3419026525153549, 0.05062046787596538, -0.4082936953470016, -0.08404423049499717, -0.4907590591221084, 0.1273101919619071, -4.206720311439787, -0.3002127507778516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -457.1342767647928, -959.8106159477925, -505.8018624707027, 0.2900898798822178, 0.09138444482380856, 0.2187118527593231, 0.1292492004000186, 0.1662045097025605, -0.1438635095448789, -0.1291313858324679, 0.146482412369866, 0.104009216338187, 0.1447220224795449, 0.08785328495101051, 0.1435558243554511, -0.07835861397425346, -0.1461036208296098, -0.07391291396692715, 0.1542496939603918, -0.07351683292489485, 0.1691302490659806, 0.07668777947971103, -0.191528688062261, 0.08339243901741469, -0.2222158695109802, -0.09404049750512089, -0.262283667277891, 0.1095744988108133, -0.3135425638449527, 0.1317142932715506, 0.3791044132771236, 0.1635054212875869, -0.4644162154949849, 0.4754117380195617, -4.133127727067452, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.7075938580194, -959.859187561279, -504.9641545879152, 0.3112115826946246, 0.7603819900412184, 0.2515787922254607, 0.5346525976842389, -0.2046698188884306, -0.3549498970832715, 0.1667993851467113, 0.2128194443512869, 0.1349829906843502, 0.1004097453865731, 0.1069128978938258, -0.01069617548430252, -0.08086180012056307, 0.06245121559445837, 0.05554789383536447, 0.1243240851970876, 0.02998652907082099, -0.1795147550946357, -0.003335227685768387, -0.232122564808795, 0.02527939571162375, 0.2860328739068638, 0.05697314553891727, -0.3453056616278151, 0.09340770900657025, -0.4147626826939698, -0.1373004236343103, -0.5009888584183517, 0.1933830034629809, -4.165639675833453, 0.3383554269676927, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.8782696374187, -959.9297648403151, -505.4159286188464, 0.3121561806109645, 0.2822056061123752, 0.247980497057797, -0.2569956304425891, -0.1998295916895239, 0.2284297348242049, 0.1650722678022543, 0.2029125660834568, 0.1410884792635043, 0.1841746600175908, -0.1256771230171495, -0.174184152010238, -0.1171886991653117, 0.1738211936975961, -0.1145301840222644, 0.1833868779235939, 0.1171275690499658, -0.2030007615539205, 0.1248977602701297, -0.2329370726129333, -0.1382764499321328, -0.27395747110102, 0.1583471608991634, -0.3277192476797476, 0.1871380238475298, 0.3974011701543539, 0.2282921486952801, -0.4888358484669846, 0.9965699211078363, -4.174355176167373, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.6116649438044, -960.0038871245156, -505.0023454177997, 0.3295930205438109, 0.5143442094150634, -0.2695356906932027, -0.3518849459077303, 0.2184195529530754, 0.2177473194353936, 0.1742696183299925, 0.107588929061941, 0.1351123343048535, -0.01670816731731302, -0.09919323231873232, 0.05953720029339046, 0.06503073496805913, 0.125532380449224, 0.03137214041729913, -0.1853658264427238, 0.002916428236328955, -0.2429142837357705, 0.03901258336924512, 0.3020465696948311, 0.07836548079886681, -0.3669787240345666, 0.1230474258479728, -0.4428645014247397, -0.1763255542849716, -0.5368662993446999, 0.2437700678950443, -4.391525855268358, 0.7382567408086977, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.6126089063781, -960.0836158047517, -505.1187555600291, 0.3334848577914001, -0.348428051728459, -0.2752367222186492, 0.3006944638633078, 0.2302721093152811, 0.2591967524250096, 0.1970876226025629, 0.2278690906060197, -0.1740115500094767, -0.2085463212280925, -0.1595867622233282, 0.2018162461301135, -0.1527406251408078, 0.2076385119268662, 0.1528504282670753, -0.2258110308909343, 0.1597827219954589, -0.2563523040186093, -0.173969694548823, -0.2998702186943654, 0.1965747840879211, -0.3580175279469813, 0.229863604568186, 0.4341837938265395, 0.277970170008693, -0.5347627558106645, 1.329764914690779, -4.483596648143033, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.4349056684294, -960.156647229524, -504.9319775147893, -0.3423523620698637, -0.3475550534848461, 0.2809466994778753, 0.2215706829932298, 0.2255846777578883, 0.1128246391312395, 0.1754514594654858, -0.01937340515435665, -0.1292864557086762, 0.06168462942056975, 0.08573413224271821, 0.1336954218460845, 0.04347198911094055, -0.2001906469386318, -0.00119376064663685, -0.2648271503726893, 0.04251266830607562, 0.3315045719474604, 0.0893994185444924, -0.4046778456006963, 0.1419228134888831, -0.4899638274253278, -0.2038944668407005, -0.5952966220065167, 0.2817106712351145, -4.848415701454543, 0.9427020574859393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.3526903101317, -960.2239683681914, 504.8729234307502, -0.3489451907029376, 0.3589886699197148, 0.2961466969614354, 0.310480710370148, 0.2543129428137268, 0.2722939468109425, -0.2230677496498586, -0.2472988907469534, -0.2016181817997352, 0.2366019906197148, -0.1891922917107881, 0.2403800750135453, 0.1852769979754018, -0.2584933857871972, 0.1897672879791922, -0.2909693456884552, -0.2031063479701883, -0.3384573551697876, 0.226529417912314, -0.4027594406465836, 0.2624902798236902, 0.4876253939462449, 0.3155583157701459, -0.6001811424846641, 1.506088170407175, -5.032413448243027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 456.2281437872571, -960.2817251702837, -504.8181052368888, -0.3473974178704272, -0.2160721566413612, -0.2844115901002985, -0.1109673640897398, -0.2249663433659822, 0.01558619777087037, 0.1691160884458819, -0.07065303999293307, -0.1161602619016208, -0.1496942207346384, -0.06504337994709028, 0.2242986455097327, 0.01449731249119731, 0.2977971368954605, -0.03700838008878649, -0.3740870837044805, -0.09144942901497075, 0.457896128782557, -0.1516347645680779, 0.5553971193015861, 0.221891957236842, 0.6754711755316094, -0.3094582971264419, 5.522765460179463, -0.97751110694022, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456.1038688686278, -960.3270004185782, 504.6545436979824, -0.356402682870272, -0.351340066980498, -0.309181275719597, -0.3137167192606073, 0.2710350810973345, 0.2878350893000941, 0.2426229671933997, -0.2763168527076123, 0.2239747467509561, -0.280241947819618, -0.214997170417235, 0.3000011000597085, -0.2157829211419849, 0.3359590943512027, 0.2268880461285561, 0.3890394964897786, -0.2496482263626514, 0.4613794461017247, -0.2867172754999331, -0.5572551598551461, -0.3430608494894536, 0.6847182926632671, -1.544015999089003, 5.81277117568367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 456.0159328177219, -960.3639010644911, -504.6932803542561, 0.3438026307622749, 0.09449263891861819, 0.2791924853298788, -0.0003950261355616105, -0.2158018381788221, 0.08970415379288814, 0.1544060725265021, 0.1757031383879306, 0.09475353685250953, -0.2591866322084164, -0.03594501565049272, -0.3429135694153541, 0.02344530556719954, 0.4306584188832464, 0.08549582247561358, -0.5273917016008263, 0.1532791130988579, -0.6399042657976388, -0.2316168130063649, -0.778179175299526, 0.3285885099115871, -6.416369594901841, 0.8564491667855068, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455.8653704619311, -960.3842612497629, -504.4466252991523, 0.3553710744569122, 0.3464161627180581, -0.3141480426464132, -0.3263434732993854, -0.2805185077726005, 0.318452179605292, -0.2561088381842067, 0.3256076632881188, 0.2417423068618511, -0.3493440004841665, 0.2380375239176739, -0.3907849327216811, -0.2458444207499498, -0.4514338824492233, 0.2667224509879774, -0.5339931109453619, 0.3035639225688179, 0.6434745768399498, 0.3617520533213044, -0.7890836608012997, 1.453287590263238, -6.830587030361006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455.8082369972718, -960.3994442233231, -504.5727798070742, 0.3313951499504466, 0.03334672491870352, -0.2650323687322864, 0.1237756771616079, 0.1977229200322088, 0.2152372282453819, 0.1308144824330917, -0.3074811043383469, -0.06431874746251602, -0.4022833530695494, 0.002753039484875582, 0.5030555348702184, 0.07234641380894129, -0.6149136653510678, 0.147681447081999, -0.7452813394287314, -0.2340032399414377, -0.9053839955214958, 0.3402398000888476, -7.541821253164034, 0.5849103543979055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455.6329040043291, -960.3950114540172, -504.2353754001218, -0.3460929449122671, -0.3573008762499605, -0.3114301376926339, 0.3594512386076111, -0.2833177549503088, 0.3742883157355104, 0.2642891667618492, -0.4053000240462633, 0.2559854273447855, -0.4549386843075994, -0.2598956392005766, -0.5256874172585198, 0.2779895068618159, -0.6211224810880993, 0.313525507512514, 0.7472565377041231, 0.3723660978852033, -0.9147314187079836, 1.237565421662729, -8.101822161846965, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455.6073466604758, -960.3894853751993, 504.4633572926642, -0.3103733552874035, 0.1798092000949148, 0.2419934417708158, 0.2733274466086066, 0.170608369891661, -0.3730126262676927, -0.09792141422899953, -0.4790220884834106, -0.02392951925676049, 0.5940246336099106, 0.05285511329060938, -0.72308359247846, 0.1355803277369181, -0.8742174899740623, -0.2298115577107615, -1.060011360233898, 0.3453065574734215, -8.919981193604276, 0.1624134764758667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 455.4000921853053, -960.361309464515, -504.007882194183, 0.3290914395050692, -0.3942786634383071, 0.3016661987186222, -0.4232028367455296, -0.2802278665379578, 0.4661762517445954, -0.2682364496083171, 0.5277412575464714, 0.2683110547053154, 0.6119088573807965, -0.2831724063939194, 0.7235386787769833, -0.3166483539775581, -0.8699916087218257, -0.3752194315750562, 1.063702555577482, -0.8961354452926642, 9.650619636505867, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455.411737801223, -960.33634002581, -504.3683031089997, -0.2810675792469359, -0.3568683235024433, -0.2101973773067176, 0.4610263218581945, 0.1342569173742763, 0.5773846640444537, 0.0549895002126496, -0.7072872888655298, -0.02810812468448988, 0.8554232500908963, -0.1177949641523385, 1.030291473272884, 0.2197751447614384, 1.245920882288997, -0.3445848993688538, 10.57920381944338, 0.4160829872124499, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455.1591691278096, -960.2853155130464, 503.7506267530316, 0.3049590480459953, -0.4680278418562256, -0.2856076919532088, 0.5295716933187377, -0.2723080782051216, 0.6081924100973243, 0.2695854300651085, 0.7101704945576234, -0.2814097861384926, 0.8422035444139073, -0.3125162969328145, -1.013460137059419, -0.3702351580276053, 1.238618787929362, -0.4245068253530189, 11.50934860393606, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 455.2183025514214, -960.2418420556575, 504.2904567527979, 0.2437489235262463, -0.5785902355402166, -0.1696099295696916, -0.7030543018352547, -0.08807726217552897, 0.8477643119258153, -0.0003803922022015914, -1.016538148397893, 0.09536127235557913, -1.218135087789733, -0.2047067633976007, -1.468068679276456, 0.3388478362779086, -12.55632491341529, -1.160129556695031, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454.9011576326581, -960.1679733535419, 503.4480310997173, -0.2743159215154021, 0.59210690664036, -0.2642341403577922, 0.6948327035340854, 0.2611611633095301, 0.820468994814445, -0.2710734389097403, 0.9783065442168752, -0.3001250829922114, -1.179929020129721, -0.3568752809307986, 1.442834925435452, 0.1861860221886378, 13.72072654131889, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 455.0234951961737, -960.1065185460631, -504.2341761382918, -0.1985155387376615, -0.8636702893987938, -0.1197570863030018, 1.022005815169442, -0.03046148161363051, -1.212498738675283, 0.06965185900521845, -1.44380567993779, -0.1855411271964486, -1.732900209415532, 0.3288765751169174, -14.89970702904785, -2.085331319125681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -454.6155022554338, -960.0090394364709, 503.080419120223, 0.2378578162407876, -0.7855779404374899, -0.2389268322384859, -0.9427265300586574, 0.2493889345428649, -1.133389617235434, 0.2776001160195384, 1.372380149780934, 0.3338733668864364, -1.680779007748177, -0.9514699644735849, -16.34248127983827, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454.8236752088293, -959.9291937205099, 504.2068595622975, 0.1450192700206833, -1.238921588152978, 0.05908037491561525, 1.451502248422423, -0.04247506464443443, 1.715440182112174, 0.1633637326099601, 2.049030098342237, -0.3153926679720489, 17.67488245777389, 3.216886963304409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454.2888780517075, -959.8060141768642, 502.6209139189659, -0.1963783784418207, -1.07681015710693, 0.2118129088940946, -1.30957289263114, 0.2416506844030767, 1.594926385284288, 0.2987764905571196, -1.958528602633205, -1.89790052548914, -19.45550897611078, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454.6150435510897, -959.7057073918052, -504.2207918385922, 0.08191276561459389, 1.744978959223401, -0.01623102385292412, 2.044325279439126, 0.139362395300141, 2.428380353063932, -0.2989187527977135, 20.97397716279267, 4.596081079911148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -453.9030102952942, -959.5514771839804, -502.0302313735755, -0.1509069873047727, 1.509921737993699, -0.1866506960156188, -1.853460072170985, -0.2470701568585754, 2.284756111156089, 3.070922511010462, 23.1773864785971, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -454.393273204417, -959.4263564611852, 504.2962075579032, 0.005942404933789297, 2.446660862635643, 0.1147302269971472, 2.888007099445928, -0.2794135351323237, 24.93107187619451, 6.291448555715359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 453.4308183834945, -959.2306762470356, 501.2467662460859, 0.1030197566665109, 2.15672544959436, 0.1707450834055513, -2.672257869508826, -4.548465509453017, -27.68489865384783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454.1521964870133, -959.071043583621, 504.4663679395445, 0.09038098396525029, 3.453184686592636, -0.2556696326547585, 29.74790742438, 8.418178566025752, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 452.828604749646, -958.8118098643598, -500.1677840008083, 0.05562336274628601, -3.140588015388957, -6.465358070370396, -33.25328104675387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -453.8814454933349, -958.5973523296369, -504.7879798529249, 0.2240186812962395, -35.739305932474, -11.17424401632893, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -452.0207842240151, -958.2280932680816, 498.6099988306628, -9.061273073482408, -40.32955903922403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 453.5608878051024, -957.9144120234951, 542.7656821084641, 14.91304502929086, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 450.8656330991661, -969.8578951037719, 452.1887612775597, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 787.8967774818433, -898.9789215779133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, }, evWant: []complex128{ 1, 2, -0.8238783640171078 + 1.579766228862017i, -0.8238783640171078 - 1.579766228862017i, -3.922907917607387 + 1.654540870297146i, -3.922907917607387 - 1.654540870297146i, -10.04176861796659 + 1.651471031280953i, -10.04176861796659 - 1.651471031280953i, -19.90533512613429 + 1.64196864045227i, -19.90533512613429 - 1.64196864045227i, -33.60610872827028 + 1.635560741682501i, -33.60610872827028 - 1.635560741682501i, -51.10943733404228 + 1.631805014774364i, -51.10943733404228 - 1.631805014774364i, -72.34919707090897 + 1.629522740505929i, -72.34919707090897 - 1.629522740505929i, -97.24021794530901 + 1.628064860261413i, -97.24021794530901 - 1.628064860261413i, -125.6811625494976 + 1.627074041605065i, -125.6811625494976 - 1.627074041605065i, -157.5556174346503 + 1.626392967840776i, -157.5556174346503 - 1.626392967840776i, -192.732837945876 + 1.625893674037654i, -192.732837945876 - 1.625893674037654i, -231.0684238575969 + 1.625523897559938i, -231.0684238575969 - 1.625523897559938i, -272.404932676379 + 1.625248463045784i, -272.404932676379 - 1.625248463045784i, -316.5725618120467 + 1.625029322230836i, -316.5725618120467 - 1.625029322230836i, -363.3898435346347 + 1.624863705104029i, -363.3898435346347 - 1.624863705104029i, -412.6644183160402 + 1.624734783685709i, -412.6644183160402 - 1.624734783685709i, -464.1938275598905 + 1.624629407600858i, -464.1938275598905 - 1.624629407600858i, -517.7663337295413 + 1.624555040627727i, -517.7663337295413 - 1.624555040627727i, -573.1617958392867 + 1.62448889134649i, -573.1617958392867 - 1.62448889134649i, -630.1525854166166 + 1.624445355378192i, -630.1525854166166 - 1.624445355378192i, -688.5045249303587 + 1.624414401302088i, -688.5045249303587 - 1.624414401302088i, -747.9778126976437 + 1.624396390555459i, -747.9778126976437 - 1.624396390555459i, -808.3280706224909 + 1.62438480760184i, -808.3280706224909 - 1.62438480760184i, -869.3072903249724 + 1.624387678902335i, -869.3072903249724 - 1.624387678902335i, -930.6648831979091 + 1.624396130880259i, -930.6648831979091 - 1.624396130880259i, -992.1487134378474 + 1.624417808682915i, -992.1487134378474 - 1.624417808682915i, -1053.506114553354 + 1.624453056189826i, -1053.506114553354 - 1.624453056189826i, -1114.484928198698 + 1.62449544649428i, -1114.484928198698 - 1.62449544649428i, -1174.834554234014 + 1.624553207269019i, -1174.834554234014 - 1.624553207269019i, -1234.306981514973 + 1.624623553438826i, -1234.306981514973 - 1.624623553438826i, -1292.657768972259 + 1.624709216827242i, -1292.657768972259 - 1.624709216827242i, -1349.647106741638 + 1.624814444572517i, -1349.647106741638 - 1.624814444572517i, -1405.040739357668 + 1.624951632752096i, -1405.040739357668 - 1.624951632752096i, -1458.610953350783 + 1.625104547041682i, -1458.610953350783 - 1.625104547041682i, -1510.137508646807 + 1.625304666073007i, -1510.137508646807 - 1.625304666073007i, -1559.408520122221 + 1.625548293255404i, -1559.408520122221 - 1.625548293255404i, -1606.221305250554 + 1.625851986073836i, -1606.221305250554 - 1.625851986073836i, -1650.383201531125 + 1.62624202844641i, -1650.383201531125 - 1.62624202844641i, -1691.712315735984 + 1.6267345498979i, -1691.712315735984 - 1.6267345498979i, -1730.038177420971 + 1.627388968656263i, -1730.038177420971 - 1.627388968656263i, -1765.20230058066 + 1.628268412022146i, -1765.20230058066 - 1.628268412022146i, -1797.05860162894 + 1.629473972633416i, -1797.05860162894 - 1.629473972633416i, -1825.473493639258 + 1.631220665229006i, -1825.473493639258 - 1.631220665229006i, -1850.32542664842 + 1.633834593918563i, -1850.32542664842 - 1.633834593918563i, -1871.503056018116 + 1.637993570641514i, -1871.503056018116 - 1.637993570641514i, -1888.90026514681 + 1.64508855982818i, -1888.90026514681 - 1.64508855982818i, -1902.402515327158 + 1.658179541614067i, -1902.402515327158 - 1.658179541614067i, -1911.858940404498 + 1.682209391409579i, -1911.858940404498 - 1.682209391409579i, -1916.92602113601 + 1.761877988650816i, -1916.92602113601 - 1.761877988650816i, -1930.484166851586 + 1.202676762393897i, -1930.484166851586 - 1.202676762393897i, 3, 4, }, }, } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlabrd.go000066400000000000000000000042011450372207100230000ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" ) type Dlabrder interface { Dlabrd(m, n, nb int, a []float64, lda int, d, e, tauq, taup, x []float64, ldx int, y []float64, ldy int) } func DlabrdTest(t *testing.T, impl Dlabrder) { rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, nb, lda, ldx, ldy int }{ {4, 5, 2, 0, 0, 0}, {4, 5, 4, 0, 0, 0}, {5, 5, 2, 0, 0, 0}, {5, 5, 5, 0, 0, 0}, {5, 4, 4, 0, 0, 0}, {5, 4, 4, 0, 0, 0}, {4, 5, 2, 10, 11, 12}, {4, 5, 4, 10, 11, 12}, {5, 5, 2, 10, 11, 12}, {5, 5, 5, 10, 11, 12}, {5, 4, 2, 10, 11, 12}, {5, 4, 4, 10, 11, 12}, {4, 5, 2, 11, 12, 10}, {4, 5, 4, 11, 12, 10}, {5, 5, 2, 11, 12, 10}, {5, 5, 5, 11, 12, 10}, {5, 4, 2, 11, 12, 10}, {5, 4, 4, 11, 12, 10}, {4, 5, 2, 12, 11, 10}, {4, 5, 4, 12, 11, 10}, {5, 5, 2, 12, 11, 10}, {5, 5, 5, 12, 11, 10}, {5, 4, 2, 12, 11, 10}, {5, 4, 4, 12, 11, 10}, } { m := test.m n := test.n nb := test.nb lda := test.lda if lda == 0 { lda = n } ldy := test.ldy if ldy == 0 { ldy = nb } ldx := test.ldx if ldx == 0 { ldx = nb } a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } d := make([]float64, nb) for i := range d { d[i] = math.NaN() } e := make([]float64, nb) for i := range e { e[i] = math.NaN() } tauP := make([]float64, nb) for i := range tauP { tauP[i] = math.NaN() } tauQ := make([]float64, nb) for i := range tauP { tauQ[i] = math.NaN() } x := make([]float64, m*ldx) for i := range x { x[i] = rnd.NormFloat64() } y := make([]float64, n*ldy) for i := range y { y[i] = rnd.NormFloat64() } aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute the reduction. impl.Dlabrd(m, n, nb, a, lda, d, e, tauQ, tauP, x, ldx, y, ldy) if m >= n && nb == n { tauP[n-1] = 0 } if m < n && nb == m { tauQ[m-1] = 0 } checkBidiagonal(t, m, n, nb, a, lda, d, e, tauP, tauQ, aCopy) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlacn2.go000066400000000000000000000034421450372207100227210ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlacn2er interface { Dlacn2(n int, v, x []float64, isgn []int, est float64, kase int, isave *[3]int) (float64, int) } func Dlacn2Test(t *testing.T, impl Dlacn2er) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 4, 5, 7, 10, 15, 20, 100} { for cas := 0; cas < 10; cas++ { a := randomGeneral(n, n, n, rnd) // Compute the 1-norm of A explicitly. var norm1 float64 for j := 0; j < n; j++ { var sum float64 for i := 0; i < n; i++ { sum += math.Abs(a.Data[i*a.Stride+j]) } if sum > norm1 { norm1 = sum } } // Compute the estimate of 1-norm using Dlanc2. x := make([]float64, n) work := make([]float64, n) v := make([]float64, n) isgn := make([]int, n) var ( kase int isave [3]int got float64 ) loop: for { got, kase = impl.Dlacn2(n, v, x, isgn, got, kase, &isave) switch kase { default: panic("Dlacn2 returned invalid value of kase") case 0: break loop case 1: blas64.Gemv(blas.NoTrans, 1, a, blas64.Vector{Data: x, Inc: 1}, 0, blas64.Vector{Data: work, Inc: 1}) copy(x, work) case 2: blas64.Gemv(blas.Trans, 1, a, blas64.Vector{Data: x, Inc: 1}, 0, blas64.Vector{Data: work, Inc: 1}) copy(x, work) } } // Check that got is either accurate enough or a // lower estimate of the 1-norm of A. if math.Abs(got-norm1) > 1e-8 && got > norm1 { t.Errorf("Case n=%v: not lower estimate. 1-norm %v, estimate %v", n, norm1, got) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlacpy.go000066400000000000000000000033731450372207100230350ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Dlacpyer interface { Dlacpy(uplo blas.Uplo, m, n int, a []float64, lda int, b []float64, ldb int) } func DlacpyTest(t *testing.T, impl Dlacpyer) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower, blas.All} { for _, test := range []struct { m, n, lda, ldb int }{ {3, 5, 0, 0}, {5, 5, 0, 0}, {7, 5, 0, 0}, {3, 5, 10, 12}, {5, 5, 10, 12}, {7, 5, 10, 12}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } ldb := test.ldb if ldb == 0 { ldb = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() } b := make([]float64, m*ldb) for i := range b { b[i] = rnd.Float64() } impl.Dlacpy(uplo, m, n, a, lda, b, ldb) equal := true switch uplo { case blas.Upper: for i := 0; i < m; i++ { for j := i; j < n; j++ { if b[i*ldb+j] != a[i*lda+j] { equal = false goto DoneCheck } } } case blas.Lower: for i := 0; i < m; i++ { for j := 0; j < min(i, n); j++ { if b[i*ldb+j] != a[i*lda+j] { equal = false goto DoneCheck } } } case blas.All: for i := 0; i < m; i++ { for j := 0; j < n; j++ { if b[i*ldb+j] != a[i*lda+j] { equal = false goto DoneCheck } } } } DoneCheck: if !equal { fmt.Println(blas.Lower) t.Errorf("Matrices not equal after copy. Uplo = %d, m = %d, n = %d", uplo, m, n) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlae2.go000066400000000000000000000020531450372207100225420ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" ) type Dlae2er interface { Dlae2(a, b, c float64) (rt1, rt2 float64) } func Dlae2Test(t *testing.T, impl Dlae2er) { for _, test := range []struct { a, b, c float64 }{ {-10, 5, 3}, {3, 5, -10}, {0, 3, 0}, {1, 3, 1}, {1, -3, 1}, {5, 0, 3}, {3, 0, -5}, {1, 3, 1.02}, {1.02, 3, 1}, {1, -3, -9}, } { a := test.a b := test.b c := test.c rt1, rt2 := impl.Dlae2(a, b, c) errStr := fmt.Sprintf("a = %v, b = %v, c = %v", a, b, c) // Check if rt1 and rt2 are eigenvalues by checking if det(a - λI) = 0 a1 := a - rt1 c1 := c - rt1 det := a1*c1 - b*b if math.Abs(det) > 1e-10 { t.Errorf("First eigenvalue mismatch. %s. Det = %v", errStr, det) } a2 := a - rt2 c2 := c - rt2 det = a2*c2 - b*b if math.Abs(det) > 1e-10 { t.Errorf("Second eigenvalue mismatch. %s. Det = %v", errStr, det) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaev2.go000066400000000000000000000025631450372207100227360ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" ) type Dlaev2er interface { Dlaev2(a, b, c float64) (rt1, rt2, cs1, sn1 float64) } func Dlaev2Test(t *testing.T, impl Dlaev2er) { rnd := rand.New(rand.NewSource(1)) for trial := 0; trial < 100; trial++ { a := rnd.NormFloat64() b := rnd.NormFloat64() c := rnd.NormFloat64() rt1, rt2, cs1, sn1 := impl.Dlaev2(a, b, c) tmp := mul2by2([2][2]float64{{cs1, sn1}, {-sn1, cs1}}, [2][2]float64{{a, b}, {b, c}}) ans := mul2by2(tmp, [2][2]float64{{cs1, -sn1}, {sn1, cs1}}) if math.Abs(ans[0][0]-rt1) > 1e-14 { t.Errorf("Largest eigenvalue mismatch. Returned %v, mul %v", rt1, ans[0][0]) } if math.Abs(ans[1][0]) > 1e-14 || math.Abs(ans[0][1]) > 1e-14 { t.Errorf("Non-zero off diagonal. ans[1][0] = %v, ans[0][1] = %v", ans[1][0], ans[0][1]) } if math.Abs(ans[1][1]-rt2) > 1e-14 { t.Errorf("Smallest eigenvalue mismatch. Returned %v, mul %v", rt2, ans[1][1]) } } } func mul2by2(a, b [2][2]float64) [2][2]float64 { var c [2][2]float64 c[0][0] = a[0][0]*b[0][0] + a[0][1]*b[1][0] c[0][1] = a[0][0]*b[0][1] + a[0][1]*b[1][1] c[1][0] = a[1][0]*b[0][0] + a[1][1]*b[1][0] c[1][1] = a[1][0]*b[0][1] + a[1][1]*b[1][1] return c } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaexc.go000066400000000000000000000107641450372207100230230ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlaexcer interface { Dlaexc(wantq bool, n int, t []float64, ldt int, q []float64, ldq int, j1, n1, n2 int, work []float64) bool } func DlaexcTest(t *testing.T, impl Dlaexcer) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 18, 31, 53} { for _, extra := range []int{0, 3} { for cas := 0; cas < 100; cas++ { testDlaexc(t, impl, rnd, n, extra) } } } } func testDlaexc(t *testing.T, impl Dlaexcer, rnd *rand.Rand, n, extra int) { const tol = 1e-14 // Generate random T in Schur canonical form. tmat, _, _ := randomSchurCanonical(n, n+extra, true, rnd) tmatCopy := cloneGeneral(tmat) // Randomly pick the index of the first block. j1 := rnd.Intn(n) if j1 > 0 && tmat.Data[j1*tmat.Stride+j1-1] != 0 { // Adjust j1 if it points to the second row of a 2x2 block. j1-- } // Read sizes of the two blocks based on properties of T. var n1, n2 int switch j1 { case n - 1: n1, n2 = 1, 0 case n - 2: if tmat.Data[(j1+1)*tmat.Stride+j1] == 0 { n1, n2 = 1, 1 } else { n1, n2 = 2, 0 } case n - 3: if tmat.Data[(j1+1)*tmat.Stride+j1] == 0 { n1, n2 = 1, 2 } else { n1, n2 = 2, 1 } default: if tmat.Data[(j1+1)*tmat.Stride+j1] == 0 { n1 = 1 if tmat.Data[(j1+2)*tmat.Stride+j1+1] == 0 { n2 = 1 } else { n2 = 2 } } else { n1 = 2 if tmat.Data[(j1+3)*tmat.Stride+j1+2] == 0 { n2 = 1 } else { n2 = 2 } } } name := fmt.Sprintf("Case n=%v,j1=%v,n1=%v,n2=%v,extra=%v", n, j1, n1, n2, extra) // 1. Test without accumulating Q. wantq := false work := nanSlice(n) ok := impl.Dlaexc(wantq, n, tmat.Data, tmat.Stride, nil, 1, j1, n1, n2, work) // 2. Test with accumulating Q. wantq = true tmat2 := cloneGeneral(tmatCopy) q := eye(n, n+extra) qCopy := cloneGeneral(q) work = nanSlice(n) ok2 := impl.Dlaexc(wantq, n, tmat2.Data, tmat2.Stride, q.Data, q.Stride, j1, n1, n2, work) if !generalOutsideAllNaN(tmat) { t.Errorf("%v: out-of-range write to T", name) } if !generalOutsideAllNaN(tmat2) { t.Errorf("%v: out-of-range write to T2", name) } if !generalOutsideAllNaN(q) { t.Errorf("%v: out-of-range write to Q", name) } // Check that outputs from cases 1. and 2. are exactly equal, then check one of them. if ok != ok2 { t.Errorf("%v: ok != ok2", name) } if !equalGeneral(tmat, tmat2) { t.Errorf("%v: T != T2", name) } if !ok { if n1 == 1 && n2 == 1 { t.Errorf("%v: unexpected failure", name) } else { t.Logf("%v: Dlaexc returned false", name) } } if !ok || n1 == 0 || n2 == 0 || j1+n1 >= n { // Check that T is not modified. if !equalGeneral(tmat, tmatCopy) { t.Errorf("%v: unexpected modification of T", name) } // Check that Q is not modified. if !equalGeneral(q, qCopy) { t.Errorf("%v: unexpected modification of Q", name) } return } // Check that T is not modified outside of rows and columns [j1:j1+n1+n2]. for i := 0; i < n; i++ { if j1 <= i && i < j1+n1+n2 { continue } for j := 0; j < n; j++ { if j1 <= j && j < j1+n1+n2 { continue } diff := tmat.Data[i*tmat.Stride+j] - tmatCopy.Data[i*tmatCopy.Stride+j] if diff != 0 { t.Errorf("%v: unexpected modification of T[%v,%v]", name, i, j) } } } if !isSchurCanonicalGeneral(tmat) { t.Errorf("%v: T is not in Schur canonical form", name) } // Check that Q is orthogonal. resid := residualOrthogonal(q, false) if resid > tol { t.Errorf("%v: Q is not orthogonal; resid=%v, want<=%v", name, resid, tol) } // Check that Q is unchanged outside of columns [j1:j1+n1+n2]. for i := 0; i < n; i++ { for j := 0; j < n; j++ { if j1 <= j && j < j1+n1+n2 { continue } diff := q.Data[i*q.Stride+j] - qCopy.Data[i*qCopy.Stride+j] if diff != 0 { t.Errorf("%v: unexpected modification of Q[%v,%v]", name, i, j) } } } // Check that Qᵀ * TOrig * Q == T qt := zeros(n, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, tmatCopy, 0, qt) qtq := cloneGeneral(tmat) blas64.Gemm(blas.NoTrans, blas.NoTrans, -1, qt, q, 1, qtq) resid = dlange(lapack.MaxColumnSum, n, n, qtq.Data, qtq.Stride) if resid > float64(n)*tol { t.Errorf("%v: mismatch between Qᵀ*(initial T)*Q and (final T); resid=%v, want<=%v", name, resid, float64(n)*tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlag2.go000066400000000000000000000147631450372207100225570ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dlag2er interface { Dlag2(a []float64, lda int, b []float64, ldb int) (scale1, scale2, wr1, wr2, wi float64) } func Dlag2Test(t *testing.T, impl Dlag2er) { rnd := rand.New(rand.NewSource(1)) for _, lda := range []int{2, 5} { for _, ldb := range []int{2, 5} { for aKind := 0; aKind <= 20; aKind++ { for bKind := 0; bKind <= 20; bKind++ { dlag2Test(t, impl, rnd, lda, ldb, aKind, bKind) } } } } } func dlag2Test(t *testing.T, impl Dlag2er, rnd *rand.Rand, lda, ldb int, aKind, bKind int) { const tol = 1e-14 a := makeDlag2TestMatrix(rnd, lda, aKind) b := makeDlag2TestMatrix(rnd, ldb, bKind) aCopy := cloneGeneral(a) bCopy := cloneGeneral(b) scale1, scale2, wr1, wr2, wi := impl.Dlag2(a.Data, a.Stride, b.Data, b.Stride) name := fmt.Sprintf("lda=%d,ldb=%d,aKind=%d,bKind=%d", lda, ldb, aKind, bKind) aStr := fmt.Sprintf("A = [%g,%g]\n [%g,%g]", a.Data[0], a.Data[1], a.Data[a.Stride], a.Data[a.Stride+1]) bStr := fmt.Sprintf("B = [%g,%g]\n [%g,%g]", b.Data[0], b.Data[1], 0.0, b.Data[b.Stride+1]) if !floats.Same(a.Data, aCopy.Data) { t.Errorf("%s: unexpected modification of a", name) } if !floats.Same(b.Data, bCopy.Data) { t.Errorf("%s: unexpected modification of b", name) } if wi < 0 { t.Fatalf("%s: wi is negative; wi=%g,\n%s\n%s", name, wi, aStr, bStr) return } if wi > 0 { if wr1 != wr2 { t.Fatalf("%s: complex eigenvalue but wr1 != wr2; wr1=%g, wr2=%g,\n%s\n%s", name, wr1, wr2, aStr, bStr) return } if scale1 != scale2 { t.Fatalf("%s: complex eigenvalue but scale1 != scale2; scale1=%g, scale2=%g,\n%s\n%s", name, scale1, scale2, aStr, bStr) return } } resid, err := residualDlag2(a, b, scale1, complex(wr1, wi)) if err != nil { t.Logf("%s: invalid input data: %v\n%s\n%s", name, err, aStr, bStr) return } if resid > tol || math.IsNaN(resid) { t.Errorf("%s: unexpected first eigenvalue %g with s=%g; resid=%g, want<=%g\n%s\n%s", name, complex(wr1, wi), scale1, resid, tol, aStr, bStr) } resid, err = residualDlag2(a, b, scale2, complex(wr2, -wi)) if err != nil { t.Logf("%s: invalid input data: %s\n%s\n%s", name, err, aStr, bStr) return } if resid > tol || math.IsNaN(resid) { t.Errorf("%s: unexpected second eigenvalue %g with s=%g; resid=%g, want<=%g\n%s\n%s", name, complex(wr2, -wi), scale2, resid, tol, aStr, bStr) } } func makeDlag2TestMatrix(rnd *rand.Rand, ld, kind int) blas64.General { a := zeros(2, 2, ld) switch kind { case 0: // Zero matrix. case 1: // Identity. a.Data[0] = 1 a.Data[a.Stride+1] = 1 case 2: // Large diagonal. a.Data[0] = 2 * safmax a.Data[a.Stride+1] = 2 * safmax case 3: // Tiny diagonal. a.Data[0] = safmin a.Data[a.Stride+1] = safmin case 4: // Tiny and large diagonal. a.Data[0] = safmin a.Data[a.Stride+1] = safmax case 5: // Large and tiny diagonal. a.Data[0] = safmax a.Data[a.Stride+1] = safmin case 6: // Large complex eigenvalue. a.Data[0] = safmax a.Data[1] = safmax a.Data[a.Stride] = -safmax a.Data[a.Stride+1] = safmax case 7: // Tiny complex eigenvalue. a.Data[0] = safmin a.Data[1] = safmin a.Data[a.Stride] = -safmin a.Data[a.Stride+1] = safmin case 8: // Random matrix with large elements. a.Data[0] = safmax * (2*rnd.Float64() - 1) a.Data[1] = safmax * (2*rnd.Float64() - 1) a.Data[a.Stride] = safmax * (2*rnd.Float64() - 1) a.Data[a.Stride+1] = safmax * (2*rnd.Float64() - 1) case 9: // Random matrix with tiny elements. a.Data[0] = safmin * (2*rnd.Float64() - 1) a.Data[1] = safmin * (2*rnd.Float64() - 1) a.Data[a.Stride] = safmin * (2*rnd.Float64() - 1) a.Data[a.Stride+1] = safmin * (2*rnd.Float64() - 1) default: // Random matrix. a = randomGeneral(2, 2, ld, rnd) } return a } // residualDlag2 returns the value of // // | det( s*A - w*B ) | // ------------------------------------------- // max(s*norm(A), |w|*norm(B))*norm(s*A - w*B) // // that can be used to check the generalized eigenvalues computed by Dlag2 and // an error that indicates invalid input data. func residualDlag2(a, b blas64.General, s float64, w complex128) (float64, error) { const ulp = dlamchP a11, a12 := a.Data[0], a.Data[1] a21, a22 := a.Data[a.Stride], a.Data[a.Stride+1] b11, b12 := b.Data[0], b.Data[1] b22 := b.Data[b.Stride+1] // Compute norms. absw := zabs(w) anorm := math.Max(math.Abs(a11)+math.Abs(a21), math.Abs(a12)+math.Abs(a22)) anorm = math.Max(anorm, safmin) bnorm := math.Max(math.Abs(b11), math.Abs(b12)+math.Abs(b22)) bnorm = math.Max(bnorm, safmin) // Check for possible overflow. temp := (safmin*anorm)*s + (safmin*bnorm)*absw if temp >= 1 { // Scale down to avoid overflow. s /= temp w = scale(1/temp, w) absw = zabs(w) } // Check for w and s essentially zero. s1 := math.Max(ulp*math.Max(s*anorm, absw*bnorm), safmin*math.Max(s, absw)) if s1 < safmin { if s < safmin && absw < safmin { return 1 / ulp, fmt.Errorf("ulp*max(s*|A|,|w|*|B|) < safmin and s and w could not be scaled; s=%g, |w|=%g", s, absw) } // Scale up to avoid underflow. temp = 1 / math.Max(s*anorm+absw*bnorm, safmin) s *= temp w = scale(temp, w) absw = zabs(w) s1 = math.Max(ulp*math.Max(s*anorm, absw*bnorm), safmin*math.Max(s, absw)) if s1 < safmin { return 1 / ulp, fmt.Errorf("ulp*max(s*|A|,|w|*|B|) < safmin and s and w could not be scaled; s=%g, |w|=%g", s, absw) } } // Compute C = s*A - w*B. c11 := complex(s*a11, 0) - w*complex(b11, 0) c12 := complex(s*a12, 0) - w*complex(b12, 0) c21 := complex(s*a21, 0) c22 := complex(s*a22, 0) - w*complex(b22, 0) // Compute norm(s*A - w*B). cnorm := math.Max(zabs(c11)+zabs(c21), zabs(c12)+zabs(c22)) // Compute det(s*A - w*B)/norm(s*A - w*B). cs := 1 / math.Sqrt(math.Max(cnorm, safmin)) det := cmplxdet2x2(scale(cs, c11), scale(cs, c12), scale(cs, c21), scale(cs, c22)) // Compute |det(s*A - w*B)|/(norm(s*A - w*B)*max(s*norm(A), |w|*norm(B))). return zabs(det) / s1 * ulp, nil } func zabs(z complex128) float64 { return math.Abs(real(z)) + math.Abs(imag(z)) } // scale scales the complex number c by f. func scale(f float64, c complex128) complex128 { return complex(f*real(c), f*imag(c)) } // cmplxdet2x2 returns the determinant of // // |a11 a12| // |a21 a22| func cmplxdet2x2(a11, a12, a21, a22 complex128) complex128 { return a11*a22 - a12*a21 } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlags2.go000066400000000000000000000070051450372207100227310ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" ) type Dlags2er interface { Dlags2(upper bool, a1, a2, a3, b1, b2, b3 float64) (csu, snu, csv, snv, csq, snq float64) } func Dlags2Test(t *testing.T, impl Dlags2er) { rnd := rand.New(rand.NewSource(1)) for _, upper := range []bool{true, false} { for i := 0; i < 100; i++ { // Generate randomly the elements of a 2×2 matrix A // [ a1 a2 ] or [ a1 0 ] // [ 0 a3 ] [ a2 a3 ] a1 := rnd.Float64() a2 := rnd.Float64() a3 := rnd.Float64() // Generate randomly the elements of a 2×2 matrix B. // [ b1 b2 ] or [ b1 0 ] // [ 0 b3 ] [ b2 b3 ] b1 := rnd.Float64() b2 := rnd.Float64() b3 := rnd.Float64() // Compute orthogonal matrices U, V, Q // U = [ csu snu ], V = [ csv snv ], Q = [ csq snq ] // [ -snu csu ] [ -snv csv ] [ -snq csq ] // that transform A and B. csu, snu, csv, snv, csq, snq := impl.Dlags2(upper, a1, a2, a3, b1, b2, b3) // Check that U, V, Q are orthogonal matrices (their // determinant is equal to 1). detU := det2x2(csu, snu, -snu, csu) if !scalar.EqualWithinAbsOrRel(math.Abs(detU), 1, 1e-14, 1e-14) { t.Errorf("U not orthogonal: det(U)=%v", detU) } detV := det2x2(csv, snv, -snv, csv) if !scalar.EqualWithinAbsOrRel(math.Abs(detV), 1, 1e-14, 1e-14) { t.Errorf("V not orthogonal: det(V)=%v", detV) } detQ := det2x2(csq, snq, -snq, csq) if !scalar.EqualWithinAbsOrRel(math.Abs(detQ), 1, 1e-14, 1e-14) { t.Errorf("Q not orthogonal: det(Q)=%v", detQ) } // Create U, V, Q explicitly as dense matrices. u := blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{csu, snu, -snu, csu}, } v := blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{csv, snv, -snv, csv}, } q := blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{csq, snq, -snq, csq}, } // Create A and B explicitly as dense matrices. a := blas64.General{Rows: 2, Cols: 2, Stride: 2} b := blas64.General{Rows: 2, Cols: 2, Stride: 2} if upper { a.Data = []float64{a1, a2, 0, a3} b.Data = []float64{b1, b2, 0, b3} } else { a.Data = []float64{a1, 0, a2, a3} b.Data = []float64{b1, 0, b2, b3} } tmp := blas64.General{Rows: 2, Cols: 2, Stride: 2, Data: make([]float64, 4)} // Transform A as Uᵀ*A*Q. blas64.Gemm(blas.Trans, blas.NoTrans, 1, u, a, 0, tmp) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, q, 0, a) // Transform B as Vᵀ*A*Q. blas64.Gemm(blas.Trans, blas.NoTrans, 1, v, b, 0, tmp) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, q, 0, b) // Extract elements of transformed A and B that should be equal to zero. var gotA, gotB float64 if upper { gotA = a.Data[1] gotB = b.Data[1] } else { gotA = a.Data[2] gotB = b.Data[2] } // Check that they are indeed zero. if !scalar.EqualWithinAbsOrRel(gotA, 0, 1e-14, 1e-14) { t.Errorf("unexpected non-zero value for zero triangle of Uᵀ*A*Q: %v", gotA) } if !scalar.EqualWithinAbsOrRel(gotB, 0, 1e-14, 1e-14) { t.Errorf("unexpected non-zero value for zero triangle of Vᵀ*B*Q: %v", gotB) } } } } func det2x2(a, b, c, d float64) float64 { return a*d - b*c } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlagtm.go000066400000000000000000000070301450372207100230230ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlagtmer interface { Dlagtm(trans blas.Transpose, m, n int, alpha float64, dl, d, du []float64, b []float64, ldb int, beta float64, c []float64, ldc int) } func DlagtmTest(t *testing.T, impl Dlagtmer) { rnd := rand.New(rand.NewSource(1)) for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { t.Run(transToString(trans), func(t *testing.T) { for _, m := range []int{0, 1, 2, 3, 4, 5, 10} { for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for _, ldb := range []int{max(1, n), n + 3} { for _, ldc := range []int{max(1, n), n + 4} { for _, alpha := range []float64{0, 1, rnd.NormFloat64()} { for _, beta := range []float64{0, 1, rnd.NormFloat64()} { dlagtmTest(t, impl, rnd, trans, m, n, ldb, ldc, alpha, beta) } } } } } } }) } } func dlagtmTest(t *testing.T, impl Dlagtmer, rnd *rand.Rand, trans blas.Transpose, m, n int, ldb, ldc int, alpha, beta float64) { const ( tol = 1e-14 extra = 10 ) name := fmt.Sprintf("Case m=%v,n=%v,ldb=%v,ldc=%v,alpha=%v,beta=%v", m, n, ldb, ldc, alpha, beta) // Generate three random diagonals. dl := randomSlice(n+extra, rnd) dlCopy := make([]float64, len(dl)) copy(dlCopy, dl) d := randomSlice(n+1+extra, rnd) dCopy := make([]float64, len(d)) copy(dCopy, d) du := randomSlice(n+extra, rnd) duCopy := make([]float64, len(du)) copy(duCopy, du) b := randomGeneral(m, n, ldb, rnd) bCopy := cloneGeneral(b) got := randomGeneral(m, n, ldc, rnd) want := cloneGeneral(got) // Deal with zero-sized matrices early. if m == 0 || n == 0 { impl.Dlagtm(trans, m, n, alpha, dl, d, du, b.Data, b.Stride, beta, got.Data, got.Stride) if !floats.Same(dl, dlCopy) { t.Errorf("%v: unexpected modification in dl", name) } if !floats.Same(d, dCopy) { t.Errorf("%v: unexpected modification in d", name) } if !floats.Same(du, duCopy) { t.Errorf("%v: unexpected modification in du", name) } if !floats.Same(b.Data, bCopy.Data) { t.Errorf("%v: unexpected modification in B", name) } if !floats.Same(got.Data, want.Data) { t.Errorf("%v: unexpected modification in C", name) } return } impl.Dlagtm(trans, m, n, alpha, dl, d, du, b.Data, b.Stride, beta, got.Data, got.Stride) if !floats.Same(dl, dlCopy) { t.Errorf("%v: unexpected modification in dl", name) } if !floats.Same(d, dCopy) { t.Errorf("%v: unexpected modification in d", name) } if !floats.Same(du, duCopy) { t.Errorf("%v: unexpected modification in du", name) } if !floats.Same(b.Data, bCopy.Data) { t.Errorf("%v: unexpected modification in B", name) } // Generate a dense representation of the matrix and compute the wanted result. a := zeros(m, m, m) for i := 0; i < m-1; i++ { a.Data[i*a.Stride+i] = d[i] a.Data[i*a.Stride+i+1] = du[i] a.Data[(i+1)*a.Stride+i] = dl[i] } a.Data[(m-1)*a.Stride+m-1] = d[m-1] blas64.Gemm(trans, blas.NoTrans, alpha, a, b, beta, want) for i := 0; i < m; i++ { for j := 0; j < n; j++ { got.Data[i*got.Stride+j] -= want.Data[i*want.Stride+j] } } diff := dlange(lapack.MaxColumnSum, got.Rows, got.Cols, got.Data, got.Stride) if diff > tol { t.Errorf("%v: unexpected result; diff=%v, want<=%v", name, diff, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlahqr.go000066400000000000000000000247701450372207100230400ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlahqrer interface { Dlahqr(wantt, wantz bool, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, iloz, ihiz int, z []float64, ldz int) int } type dlahqrTest struct { h blas64.General ilo, ihi int iloz, ihiz int wantt, wantz bool evWant []complex128 // Optional slice holding known eigenvalues. } func DlahqrTest(t *testing.T, impl Dlahqrer) { rnd := rand.New(rand.NewSource(1)) // Tests that choose the [ilo:ihi+1,ilo:ihi+1] and // [iloz:ihiz+1,ilo:ihi+1] blocks randomly. for _, wantt := range []bool{true, false} { for _, wantz := range []bool{true, false} { for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 18, 31, 53} { for _, extra := range []int{0, 1, 11} { for cas := 0; cas < 100; cas++ { ilo := rnd.Intn(n) ihi := rnd.Intn(n) if ilo > ihi { ilo, ihi = ihi, ilo } iloz := rnd.Intn(ilo + 1) ihiz := ihi + rnd.Intn(n-ihi) h := randomHessenberg(n, n+extra, rnd) if ilo-1 >= 0 { h.Data[ilo*h.Stride+ilo-1] = 0 } if ihi+1 < n { h.Data[(ihi+1)*h.Stride+ihi] = 0 } test := dlahqrTest{ h: h, ilo: ilo, ihi: ihi, iloz: iloz, ihiz: ihiz, wantt: wantt, wantz: wantz, } testDlahqr(t, impl, test) } } } } } // Tests that make sure that some potentially problematic corner cases, // like zero-sized matrix, are covered. for _, wantt := range []bool{true, false} { for _, wantz := range []bool{true, false} { for _, extra := range []int{0, 1, 11} { for _, test := range []dlahqrTest{ { h: randomHessenberg(0, extra, rnd), ilo: 0, ihi: -1, iloz: 0, ihiz: -1, }, { h: randomHessenberg(1, 1+extra, rnd), ilo: 0, ihi: 0, iloz: 0, ihiz: 0, }, { h: randomHessenberg(2, 2+extra, rnd), ilo: 1, ihi: 1, iloz: 1, ihiz: 1, }, { h: randomHessenberg(2, 2+extra, rnd), ilo: 0, ihi: 1, iloz: 0, ihiz: 1, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 0, iloz: 0, ihiz: 0, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 9, iloz: 0, ihiz: 9, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 1, iloz: 0, ihiz: 1, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 1, iloz: 0, ihiz: 9, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 9, ihi: 9, iloz: 0, ihiz: 9, }, } { if test.ilo-1 >= 0 { test.h.Data[test.ilo*test.h.Stride+test.ilo-1] = 0 } if test.ihi+1 < test.h.Rows { test.h.Data[(test.ihi+1)*test.h.Stride+test.ihi] = 0 } test.wantt = wantt test.wantz = wantz testDlahqr(t, impl, test) } } } } // Tests with explicit eigenvalues computed by Octave. for _, test := range []dlahqrTest{ { h: blas64.General{ Rows: 1, Cols: 1, Stride: 1, Data: []float64{7.09965484086874e-1}, }, ilo: 0, ihi: 0, iloz: 0, ihiz: 0, evWant: []complex128{7.09965484086874e-1}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ 0, -1, 1, 0, }, }, ilo: 0, ihi: 1, iloz: 0, ihiz: 1, evWant: []complex128{1i, -1i}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ 6.25219991450918e-1, 8.17510791994361e-1, 3.31218891622294e-1, 1.24103744878131e-1, }, }, ilo: 0, ihi: 1, iloz: 0, ihiz: 1, evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, }, { h: blas64.General{ Rows: 4, Cols: 4, Stride: 4, Data: []float64{ 1, 0, 0, 0, 0, 6.25219991450918e-1, 8.17510791994361e-1, 0, 0, 3.31218891622294e-1, 1.24103744878131e-1, 0, 0, 0, 0, 1, }, }, ilo: 1, ihi: 2, iloz: 0, ihiz: 3, evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ -1.1219562276608, 6.85473513349362e-1, -8.19951061145131e-1, 1.93728523178888e-1, }, }, ilo: 0, ihi: 1, iloz: 0, ihiz: 1, evWant: []complex128{ -4.64113852240958e-1 + 3.59580510817350e-1i, -4.64113852240958e-1 - 3.59580510817350e-1i, }, }, { h: blas64.General{ Rows: 5, Cols: 5, Stride: 5, Data: []float64{ 9.57590178533658e-1, -5.10651295522708e-1, 9.24974510015869e-1, -1.30016306879522e-1, 2.92601986926954e-2, -1.08084756637964, 1.77529701001213, -1.36480197632509, 2.23196371219601e-1, 1.12912853063308e-1, 0, -8.44075612174676e-1, 1.067867614486, -2.55782915176399e-1, -2.00598563137468e-1, 0, 0, -5.67097237165410e-1, 2.07205057427341e-1, 6.54998340743380e-1, 0, 0, 0, -1.89441413886041e-1, -4.18125416021786e-1, }, }, ilo: 0, ihi: 4, iloz: 0, ihiz: 4, evWant: []complex128{ 2.94393309555622, 4.97029793606701e-1 + 3.63041654992384e-1i, 4.97029793606701e-1 - 3.63041654992384e-1i, -1.74079119166145e-1 + 2.01570009462092e-1i, -1.74079119166145e-1 - 2.01570009462092e-1i, }, }, } { test.wantt = true test.wantz = true testDlahqr(t, impl, test) } } func testDlahqr(t *testing.T, impl Dlahqrer, test dlahqrTest) { const tol = 1e-14 h := cloneGeneral(test.h) n := h.Cols extra := h.Stride - h.Cols wantt := test.wantt wantz := test.wantz ilo := test.ilo ihi := test.ihi iloz := test.iloz ihiz := test.ihiz var z, zCopy blas64.General if wantz { z = eye(n, n+extra) zCopy = cloneGeneral(z) } wr := nanSlice(ihi + 1) wi := nanSlice(ihi + 1) unconverged := impl.Dlahqr(wantt, wantz, n, ilo, ihi, h.Data, h.Stride, wr, wi, iloz, ihiz, z.Data, max(1, z.Stride)) prefix := fmt.Sprintf("Case wantt=%v, wantz=%v, n=%v, ilo=%v, ihi=%v, iloz=%v, ihiz=%v, extra=%v", wantt, wantz, n, ilo, ihi, iloz, ihiz, extra) if !generalOutsideAllNaN(h) { t.Errorf("%v: out-of-range write to H\n%v", prefix, h.Data) } if !generalOutsideAllNaN(z) { t.Errorf("%v: out-of-range write to Z\n%v", prefix, z.Data) } if !isUpperHessenberg(h) { t.Logf("%v: H is not Hessenberg", prefix) } start := ilo // Index of the first computed eigenvalue. if unconverged != 0 { start = unconverged if start == ihi+1 { t.Logf("%v: no eigenvalue has converged", prefix) } } // Check that wr and wi have not been modified in [:start]. if !isAllNaN(wr[:start]) { t.Errorf("%v: unexpected modification of wr", prefix) } if !isAllNaN(wi[:start]) { t.Errorf("%v: unexpected modification of wi", prefix) } var hasReal bool for i := start; i <= ihi; { if wi[i] == 0 { // Real eigenvalue. hasReal = true // Check that the eigenvalue corresponds to a 1×1 block // on the diagonal of H. if wantt { if wr[i] != h.Data[i*h.Stride+i] { t.Errorf("%v: wr[%v] != H[%v,%v]", prefix, i, i, i) } for _, index := range []struct{ r, c int }{ {i, i - 1}, // h h h {i + 1, i - 1}, // 0 wr[i] h {i + 1, i}, // 0 0 h } { if index.r >= n || index.c < 0 { continue } if h.Data[index.r*h.Stride+index.c] != 0 { t.Errorf("%v: H[%v,%v] != 0", prefix, index.r, index.c) } } } i++ continue } // Complex eigenvalue. // In the conjugate pair the real parts must be equal. if wr[i] != wr[i+1] { t.Errorf("%v: real part of conjugate pair not equal, i=%v", prefix, i) } // The first imaginary part must be positive. if wi[i] < 0 { t.Errorf("%v: wi[%v] not positive", prefix, i) } // The second imaginary part must be negative with the same // magnitude. if wi[i] != -wi[i+1] { t.Errorf("%v: wi[%v] != -wi[%v]", prefix, i, i+1) } if wantt { // Check that wi[i] has the correct value. if wr[i] != h.Data[i*h.Stride+i] { t.Errorf("%v: wr[%v] != H[%v,%v]", prefix, i, i, i) } if wr[i] != h.Data[(i+1)*h.Stride+i+1] { t.Errorf("%v: wr[%v] != H[%v,%v]", prefix, i, i+1, i+1) } prod := math.Abs(h.Data[(i+1)*h.Stride+i] * h.Data[i*h.Stride+i+1]) if math.Abs(math.Sqrt(prod)-wi[i]) > tol { t.Errorf("%v: unexpected value of wi[%v]: want %v, got %v", prefix, i, math.Sqrt(prod), wi[i]) } // Check that the corresponding diagonal block is 2×2. for _, index := range []struct{ r, c int }{ {i, i - 1}, // i {i + 1, i - 1}, // h h h h {i + 2, i - 1}, // 0 wr[i] b h i {i + 2, i}, // 0 c wr[i+1] h {i + 2, i + 1}, // 0 0 0 h } { if index.r >= n || index.c < 0 { continue } if h.Data[index.r*h.Stride+index.c] != 0 { t.Errorf("%v: H[%v,%v] != 0", prefix, index.r, index.c) } } } i += 2 } // If the number of found eigenvalues is odd, at least one must be real. if (ihi+1-start)%2 != 0 && !hasReal { t.Errorf("%v: expected at least one real eigenvalue", prefix) } // Compare found eigenvalues to the reference, if known. if test.evWant != nil { for i := start; i <= ihi; i++ { ev := complex(wr[i], wi[i]) found, _ := containsComplex(test.evWant, ev, tol) if !found { t.Errorf("%v: unexpected eigenvalue %v", prefix, ev) } } } if !wantz { return } // Z should contain the orthogonal matrix U. if resid := residualOrthogonal(z, false); resid > tol*float64(n) { t.Errorf("Case %v: Z is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } // Z should have been modified only in the // [iloz:ihiz+1,ilo:ihi+1] block. for i := 0; i < n; i++ { for j := 0; j < n; j++ { if iloz <= i && i <= ihiz && ilo <= j && j <= ihi { continue } if z.Data[i*z.Stride+j] != zCopy.Data[i*zCopy.Stride+j] { t.Errorf("%v: Z modified outside of [iloz:ihiz+1,ilo:ihi+1] block", prefix) } } } if wantt { hu := eye(n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, test.h, z, 0, hu) uhu := eye(n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, z, hu, 0, uhu) if !equalApproxGeneral(uhu, h, 10*tol) { t.Errorf("%v: Zᵀ*(initial H)*Z and (final H) are not equal", prefix) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlahr2.go000066400000000000000000000107761450372207100227420ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlahr2er interface { Dlahr2(n, k, nb int, a []float64, lda int, tau, t []float64, ldt int, y []float64, ldy int) } func Dlahr2Test(t *testing.T, impl Dlahr2er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { n, k, nb int }{ {3, 0, 3}, {3, 1, 2}, {3, 1, 1}, {5, 0, 5}, {5, 1, 4}, {5, 1, 3}, {5, 1, 2}, {5, 1, 1}, {5, 2, 3}, {5, 2, 2}, {5, 2, 1}, {5, 3, 2}, {5, 3, 1}, {7, 3, 4}, {7, 3, 3}, {7, 3, 2}, {7, 3, 1}, {10, 0, 10}, {10, 1, 9}, {10, 1, 5}, {10, 1, 1}, {10, 5, 5}, {10, 5, 3}, {10, 5, 1}, } { for cas := 0; cas < 100; cas++ { for _, extraStride := range []int{0, 1, 10} { n := test.n k := test.k nb := test.nb a := randomGeneral(n, n-k+1, n-k+1+extraStride, rnd) aCopy := a aCopy.Data = make([]float64, len(a.Data)) copy(aCopy.Data, a.Data) tmat := nanTriangular(blas.Upper, nb, nb+extraStride) y := nanGeneral(n, nb, nb+extraStride) tau := nanSlice(nb) impl.Dlahr2(n, k, nb, a.Data, a.Stride, tau, tmat.Data, tmat.Stride, y.Data, y.Stride) prefix := fmt.Sprintf("Case n=%v, k=%v, nb=%v, ldex=%v", n, k, nb, extraStride) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A\n%v", prefix, a.Data) } if !triangularOutsideAllNaN(tmat) { t.Errorf("%v: out-of-range write to T\n%v", prefix, tmat.Data) } if !generalOutsideAllNaN(y) { t.Errorf("%v: out-of-range write to Y\n%v", prefix, y.Data) } // Check that A[:k,:] and A[:,nb:] blocks were not modified. for i := 0; i < n; i++ { for j := 0; j < n-k+1; j++ { if i >= k && j < nb { continue } if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { t.Errorf("%v: unexpected write to A[%v,%v]", prefix, i, j) } } } // Check that all elements of tau were assigned. for i, v := range tau { if math.IsNaN(v) { t.Errorf("%v: tau[%v] not assigned", prefix, i) } } // Extract V from a. v := blas64.General{ Rows: n - k + 1, Cols: nb, Stride: nb, Data: make([]float64, (n-k+1)*nb), } for j := 0; j < v.Cols; j++ { v.Data[(j+1)*v.Stride+j] = 1 for i := j + 2; i < v.Rows; i++ { v.Data[i*v.Stride+j] = a.Data[(i+k-1)*a.Stride+j] } } // VT = V. vt := v vt.Data = make([]float64, len(v.Data)) copy(vt.Data, v.Data) // VT = V * T. blas64.Trmm(blas.Right, blas.NoTrans, 1, tmat, vt) // YWant = A * V * T. ywant := blas64.General{ Rows: n, Cols: nb, Stride: nb, Data: make([]float64, n*nb), } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aCopy, vt, 0, ywant) // Compare Y and YWant. for i := 0; i < n; i++ { for j := 0; j < nb; j++ { diff := math.Abs(ywant.Data[i*ywant.Stride+j] - y.Data[i*y.Stride+j]) if diff > tol { t.Errorf("%v: unexpected Y[%v,%v], diff=%v", prefix, i, j, diff) } } } // Construct Q directly from the first nb columns of a. q := constructQ("QR", n-k, nb, a.Data[k*a.Stride:], a.Stride, tau) if resid := residualOrthogonal(q, false); resid > tol*float64(n) { t.Errorf("Case %v: Q is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } // Construct Q as the product Q = I - V*T*Vᵀ. qwant := blas64.General{ Rows: n - k + 1, Cols: n - k + 1, Stride: n - k + 1, Data: make([]float64, (n-k+1)*(n-k+1)), } for i := 0; i < qwant.Rows; i++ { qwant.Data[i*qwant.Stride+i] = 1 } blas64.Gemm(blas.NoTrans, blas.Trans, -1, vt, v, 1, qwant) if resid := residualOrthogonal(qwant, false); resid > tol*float64(n) { t.Errorf("Case %v: Q = I - V*T*Vᵀ is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } // Compare Q and QWant. Note that since Q is // (n-k)×(n-k) and QWant is (n-k+1)×(n-k+1), we // ignore the first row and column of QWant. for i := 0; i < n-k; i++ { for j := 0; j < n-k; j++ { diff := math.Abs(q.Data[i*q.Stride+j] - qwant.Data[(i+1)*qwant.Stride+j+1]) if diff > tol { t.Errorf("%v: unexpected Q[%v,%v], diff=%v", prefix, i, j, diff) } } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaln2.go000066400000000000000000000076471450372207100227450ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "math/cmplx" "testing" "golang.org/x/exp/rand" ) type Dlaln2er interface { Dlaln2(trans bool, na, nw int, smin, ca float64, a []float64, lda int, d1, d2 float64, b []float64, ldb int, wr, wi float64, x []float64, ldx int) (scale, xnorm float64, ok bool) } func Dlaln2Test(t *testing.T, impl Dlaln2er) { rnd := rand.New(rand.NewSource(1)) for _, trans := range []bool{true, false} { for _, na := range []int{1, 2} { for _, nw := range []int{1, 2} { for _, extra := range []int{0, 1, 2, 13} { for cas := 0; cas < 1000; cas++ { testDlaln2(t, impl, trans, na, nw, extra, rnd) } } } } } } func testDlaln2(t *testing.T, impl Dlaln2er, trans bool, na, nw, extra int, rnd *rand.Rand) { const tol = 1e-11 // Generate random input scalars. ca := rnd.NormFloat64() d1 := rnd.NormFloat64() d2 := rnd.NormFloat64() var w complex128 if nw == 1 { w = complex(rand.NormFloat64(), 0) } else { w = complex(rand.NormFloat64(), rand.NormFloat64()) } smin := dlamchP * (math.Abs(real(w)) + math.Abs(imag(w))) // Generate random input matrices. a := randomGeneral(na, na, na+extra, rnd) b := randomGeneral(na, nw, nw+extra, rnd) x := randomGeneral(na, nw, nw+extra, rnd) scale, xnormGot, ok := impl.Dlaln2(trans, na, nw, smin, ca, a.Data, a.Stride, d1, d2, b.Data, b.Stride, real(w), imag(w), x.Data, x.Stride) prefix := fmt.Sprintf("Case trans=%t, na=%v, nw=%v, extra=%v", trans, na, nw, extra) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A\n%v", prefix, a.Data) } if !generalOutsideAllNaN(b) { t.Errorf("%v: out-of-range write to B\n%v", prefix, b.Data) } if !generalOutsideAllNaN(x) { t.Errorf("%v: out-of-range write to X\n%v", prefix, x.Data) } // Scale is documented to be <= 1. if scale <= 0 || 1 < scale { t.Errorf("%v: invalid value of scale=%v", prefix, scale) } // Calculate the infinity norm of X explicitly. var xnormWant float64 for i := 0; i < na; i++ { var rowsum float64 for j := 0; j < nw; j++ { rowsum += math.Abs(x.Data[i*x.Stride+j]) } if rowsum > xnormWant { xnormWant = rowsum } } if xnormWant != xnormGot { t.Errorf("Case %v: unexpected xnorm with scale=%v. Want %v, got %v", prefix, scale, xnormWant, xnormGot) } if !ok { // If ok is false, the matrix has been perturbed but we don't // know how. Return without comparing both sides of the // equation. return } // Compute a complex matrix // M := ca * A - w * D // or // M := ca * Aᵀ - w * D. m := make([]complex128, na*na) if trans { // M = ca * Aᵀ for i := 0; i < na; i++ { for j := 0; j < na; j++ { m[i*na+j] = complex(ca*a.Data[j*a.Stride+i], 0) } } } else { // M = ca * Aᵀ for i := 0; i < na; i++ { for j := 0; j < na; j++ { m[i*na+j] = complex(ca*a.Data[i*a.Stride+j], 0) } } } // Subtract the diagonal matrix w * D. m[0] -= w * complex(d1, 0) if na == 2 { m[3] -= w * complex(d2, 0) } // Convert real na×2 matrices X and scale*B into complex na-vectors. cx := make([]complex128, na) cb := make([]complex128, na) switch nw { case 1: for i := 0; i < na; i++ { cx[i] = complex(x.Data[i*x.Stride], 0) cb[i] = complex(scale*b.Data[i*x.Stride], 0) } case 2: for i := 0; i < na; i++ { cx[i] = complex(x.Data[i*x.Stride], x.Data[i*x.Stride+1]) cb[i] = complex(scale*b.Data[i*b.Stride], scale*b.Data[i*b.Stride+1]) } } // Compute M * X. mx := make([]complex128, na) for i := 0; i < na; i++ { for j := 0; j < na; j++ { mx[i] += m[i*na+j] * cx[j] } } // Check whether |M * X - scale * B|_max <= tol. for i := 0; i < na; i++ { if cmplx.Abs(mx[i]-cb[i]) > tol { t.Errorf("Case %v: unexpected value of left-hand side at row %v with scale=%v. Want %v, got %v", prefix, i, scale, cb[i], mx[i]) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlangb.go000066400000000000000000000055571450372207100230160ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlangber interface { Dlangb(norm lapack.MatrixNorm, m, n, kl, ku int, ab []float64, ldab int) float64 } func DlangbTest(t *testing.T, impl Dlangber) { rnd := rand.New(rand.NewSource(1)) for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum, lapack.Frobenius} { t.Run(normToString(norm), func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for _, m := range []int{0, 1, 2, 3, 4, 5, 10} { for _, kl := range []int{0, 1, 2, 3, 4, 5, 10} { for _, ku := range []int{0, 1, 2, 3, 4, 5, 10} { for _, ldab := range []int{kl + ku + 1, kl + ku + 1 + 7} { dlangbTest(t, impl, rnd, norm, m, n, kl, ku, ldab) } } } } } }) } } func dlangbTest(t *testing.T, impl Dlangber, rnd *rand.Rand, norm lapack.MatrixNorm, m, n, kl, ku, ldab int) { const tol = 1e-14 name := fmt.Sprintf("m=%v,n=%v,kl=%v,ku=%v,ldab=%v", m, n, kl, ku, ldab) // Generate a random band matrix. ab := randomSlice(m*ldab, rnd) // Sometimes put a NaN into the matrix. if m > 0 && n > 0 && rnd.Float64() < 0.5 { i := rnd.Intn(m) ab[i*ldab+kl] = math.NaN() } abCopy := make([]float64, len(ab)) copy(abCopy, ab) // Deal with zero-sized matrices early. if m == 0 || n == 0 { got := impl.Dlangb(norm, m, n, kl, ku, nil, ldab) if got != 0 { t.Errorf("%v: unexpected result for zero-sized matrix with nil input", name) } got = impl.Dlangb(norm, m, n, kl, ku, ab, ldab) if !floats.Same(ab, abCopy) { t.Errorf("%v: unexpected modification in dl", name) } if got != 0 { t.Errorf("%v: unexpected result for zero-sized matrix with non-nil input", name) } return } got := impl.Dlangb(norm, m, n, kl, ku, ab, ldab) if !floats.Same(ab, abCopy) { t.Errorf("%v: unexpected modification in ab", name) } // Generate a dense representation of the matrix and compute the wanted result. a := zeros(m, n, n) for i := 0; i < m; i++ { for j := max(0, i-kl); j < min(i+ku+1, n); j++ { a.Data[i*a.Stride+j] = ab[i*ldab+j-i+kl] } } want := dlange(norm, a.Rows, a.Cols, a.Data, a.Stride) if math.IsNaN(want) { if !math.IsNaN(got) { t.Errorf("%v: unexpected result with NaN element; got %v, want %v", name, got, want) } return } if math.IsNaN(got) { t.Errorf("%v: unexpected NaN; want %v", name, want) return } if norm == lapack.MaxAbs { if got != want { t.Errorf("%v: unexpected result; got %v, want %v", name, got, want) } return } diff := math.Abs(got - want) if diff > tol { t.Errorf("%v: unexpected result; got %v, want %v, diff=%v", name, got, want, diff) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlangb_bench.go000066400000000000000000000040311450372207100241370ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/lapack" ) func DlangbBenchmark(b *testing.B, impl Dlangber) { var result float64 rnd := rand.New(rand.NewSource(1)) for _, bm := range []struct { n, k int }{ {n: 1000, k: 0}, {n: 1000, k: 1}, {n: 1000, k: 2}, {n: 1000, k: 5}, {n: 1000, k: 8}, {n: 1000, k: 10}, {n: 1000, k: 20}, {n: 1000, k: 30}, {n: 10000, k: 0}, {n: 10000, k: 1}, {n: 10000, k: 2}, {n: 10000, k: 5}, {n: 10000, k: 8}, {n: 10000, k: 10}, {n: 10000, k: 30}, {n: 10000, k: 60}, {n: 10000, k: 100}, } { n := bm.n k := bm.k lda := 2*k + 1 aCopy := make([]float64, n*lda) for i := range aCopy { aCopy[i] = 1 - 2*rnd.Float64() } a := make([]float64, len(aCopy)) for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum} { name := fmt.Sprintf("%v_N=%v_K=%v", normToString(norm), n, k) b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { result = impl.Dlangb(norm, n, n, k, k, a, lda) } }) } // Frobenius norm is benchmarked separately because its execution time // depends on the element magnitude. norm := lapack.Frobenius for _, scale := range []string{"Small", "Medium", "Big"} { name := fmt.Sprintf("%v_N=%v_K=%v_%v", normToString(norm), n, k, scale) var scl float64 switch scale { default: scl = 1 case "Small": scl = smlnum case "Big": scl = bignum } // Scale some elements so that the matrix contains a mix of small // and medium, all medium, or big and medium values. copy(a, aCopy) for i := range a { if i%2 == 0 { a[i] *= scl } } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { result = impl.Dlangb(norm, n, n, k, k, a, lda) } }) } } if math.IsNaN(result) { b.Error("unexpected NaN result") } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlange.go000066400000000000000000000050431450372207100230070ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlanger interface { Dlange(norm lapack.MatrixNorm, m, n int, a []float64, lda int, work []float64) float64 } func DlangeTest(t *testing.T, impl Dlanger) { rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, lda int }{ {4, 3, 0}, {3, 4, 0}, {4, 3, 100}, {3, 4, 100}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate m×n matrix A and fill it with random numbers from [-0.5, 0.5). a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() - 0.5 } // Store a copy of A for later comparison. aCopy := make([]float64, len(a)) copy(aCopy, a) // Allocate workspace slice. work := make([]float64, n) for i := range work { work[i] = rnd.Float64() } // Test various norms by comparing the result from Dlange with // explicit calculation. // Test MaxAbs norm. norm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, work) var ans float64 for i := 0; i < m; i++ { idx := blas64.Iamax(blas64.Vector{N: n, Inc: 1, Data: aCopy[i*lda:]}) ans = math.Max(ans, math.Abs(a[i*lda+idx])) } // Should be strictly equal because there is no floating point summation error. if ans != norm { t.Errorf("MaxAbs mismatch. Want %v, got %v.", ans, norm) } // Test MaxColumnSum norm. norm = impl.Dlange(lapack.MaxColumnSum, m, n, a, lda, work) ans = 0 for i := 0; i < n; i++ { sum := blas64.Asum(blas64.Vector{N: m, Inc: lda, Data: aCopy[i:]}) ans = math.Max(ans, sum) } if math.Abs(norm-ans) > 1e-14 { t.Errorf("MaxColumnSum mismatch. Want %v, got %v.", ans, norm) } // Test MaxRowSum norm. norm = impl.Dlange(lapack.MaxRowSum, m, n, a, lda, work) ans = 0 for i := 0; i < m; i++ { sum := blas64.Asum(blas64.Vector{N: n, Inc: 1, Data: aCopy[i*lda:]}) ans = math.Max(ans, sum) } if math.Abs(norm-ans) > 1e-14 { t.Errorf("MaxRowSum mismatch. Want %v, got %v.", ans, norm) } // Test Frobenius norm. norm = impl.Dlange(lapack.Frobenius, m, n, a, lda, work) ans = 0 for i := 0; i < m; i++ { sum := blas64.Nrm2(blas64.Vector{N: n, Inc: 1, Data: aCopy[i*lda:]}) ans += sum * sum } ans = math.Sqrt(ans) if math.Abs(norm-ans) > 1e-14 { t.Errorf("Frobenius norm mismatch. Want %v, got %v.", ans, norm) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlangt.go000066400000000000000000000057501450372207100230330ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlangter interface { Dlangt(norm lapack.MatrixNorm, n int, dl, d, du []float64) float64 } func DlangtTest(t *testing.T, impl Dlangter) { rnd := rand.New(rand.NewSource(1)) for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum, lapack.Frobenius} { t.Run(normToString(norm), func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for iter := 0; iter < 10; iter++ { dlangtTest(t, impl, rnd, norm, n) } } }) } } func dlangtTest(t *testing.T, impl Dlangter, rnd *rand.Rand, norm lapack.MatrixNorm, n int) { const ( tol = 1e-14 extra = 10 ) name := fmt.Sprintf("n=%v", n) // Generate three random diagonals. dl := randomSlice(n+extra, rnd) dlCopy := make([]float64, len(dl)) copy(dlCopy, dl) d := randomSlice(n+1+extra, rnd) // Sometimes put a NaN into the matrix. if n > 0 && rnd.Float64() < 0.5 { d[rnd.Intn(n)] = math.NaN() } dCopy := make([]float64, len(d)) copy(dCopy, d) du := randomSlice(n+extra, rnd) duCopy := make([]float64, len(du)) copy(duCopy, du) // Deal with zero-sized matrices early. if n == 0 { got := impl.Dlangt(norm, n, nil, nil, nil) if got != 0 { t.Errorf("%v: unexpected result for zero-sized matrix with nil input", name) } got = impl.Dlangt(norm, n, dl, d, du) if !floats.Same(dl, dlCopy) { t.Errorf("%v: unexpected modification in dl", name) } if !floats.Same(d, dCopy) { t.Errorf("%v: unexpected modification in d", name) } if !floats.Same(du, duCopy) { t.Errorf("%v: unexpected modification in du", name) } if got != 0 { t.Errorf("%v: unexpected result for zero-sized matrix with non-nil input", name) } return } // Generate a dense representation of the matrix and compute the wanted result. a := zeros(n, n, n) for i := 0; i < n-1; i++ { a.Data[i*a.Stride+i] = d[i] a.Data[i*a.Stride+i+1] = du[i] a.Data[(i+1)*a.Stride+i] = dl[i] } a.Data[(n-1)*a.Stride+n-1] = d[n-1] got := impl.Dlangt(norm, n, dl, d, du) if !floats.Same(dl, dlCopy) { t.Errorf("%v: unexpected modification in dl", name) } if !floats.Same(d, dCopy) { t.Errorf("%v: unexpected modification in d", name) } if !floats.Same(du, duCopy) { t.Errorf("%v: unexpected modification in du", name) } want := dlange(norm, n, n, a.Data, a.Stride) if math.IsNaN(want) { if !math.IsNaN(got) { t.Errorf("%v: unexpected result with NaN element; got %v, want %v", name, got, want) } return } if norm == lapack.MaxAbs { if got != want { t.Errorf("%v: unexpected result; got %v, want %v", name, got, want) } return } diff := math.Abs(got - want) if diff > tol { t.Errorf("%v: unexpected result; got %v, want %v, diff=%v", name, got, want, diff) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlansb.go000066400000000000000000000073331450372207100230240ustar00rootroot00000000000000// Copyright ©2019 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlansber interface { Dlansb(norm lapack.MatrixNorm, uplo blas.Uplo, n, kd int, ab []float64, ldab int, work []float64) float64 } func DlansbTest(t *testing.T, impl Dlansber) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for _, kd := range []int{0, (n + 1) / 4, (3*n - 1) / 4, (5*n + 1) / 4} { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, ldab := range []int{kd + 1, kd + 1 + 7} { dlansbTest(t, impl, rnd, uplo, n, kd, ldab) } } } } } func dlansbTest(t *testing.T, impl Dlansber, rnd *rand.Rand, uplo blas.Uplo, n, kd int, ldab int) { const tol = 1e-15 // Generate a random symmetric band matrix and compute all its norms. ab := make([]float64, max(0, (n-1)*ldab+kd+1)) rowsum := make([]float64, n) colsum := make([]float64, n) var frobWant, maxabsWant float64 if uplo == blas.Upper { for i := 0; i < n; i++ { for jb := 0; jb < min(n-i, kd+1); jb++ { aij := 2*rnd.Float64() - 1 ab[i*ldab+jb] = aij j := jb + i colsum[j] += math.Abs(aij) rowsum[i] += math.Abs(aij) maxabsWant = math.Max(maxabsWant, math.Abs(aij)) frobWant += aij * aij if i != j { // Take into account the symmetric elements. colsum[i] += math.Abs(aij) rowsum[j] += math.Abs(aij) frobWant += aij * aij } } } } else { for i := 0; i < n; i++ { for jb := max(0, kd-i); jb < kd+1; jb++ { aij := 2*rnd.Float64() - 1 ab[i*ldab+jb] = aij j := jb - kd + i colsum[j] += math.Abs(aij) rowsum[i] += math.Abs(aij) maxabsWant = math.Max(maxabsWant, math.Abs(aij)) frobWant += aij * aij if i != j { // Take into account the symmetric elements. colsum[i] += math.Abs(aij) rowsum[j] += math.Abs(aij) frobWant += aij * aij } } } } frobWant = math.Sqrt(frobWant) var maxcolsumWant, maxrowsumWant float64 if n > 0 { maxcolsumWant = floats.Max(colsum) maxrowsumWant = floats.Max(rowsum) } abCopy := make([]float64, len(ab)) copy(abCopy, ab) work := make([]float64, n) var maxcolsumGot, maxrowsumGot float64 for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxColumnSum, lapack.MaxRowSum, lapack.Frobenius} { name := fmt.Sprintf("norm=%v,uplo=%v,n=%v,kd=%v,ldab=%v", string(norm), string(uplo), n, kd, ldab) normGot := impl.Dlansb(norm, uplo, n, kd, ab, ldab, work) if !floats.Equal(ab, abCopy) { t.Fatalf("%v: unexpected modification of ab", name) } if norm == lapack.MaxAbs { // MaxAbs norm involves no computation, so we expect // exact equality here. if normGot != maxabsWant { t.Errorf("%v: unexpected result; got %v, want %v", name, normGot, maxabsWant) } continue } var normWant float64 switch norm { case lapack.MaxColumnSum: normWant = maxcolsumWant maxcolsumGot = normGot case lapack.MaxRowSum: normWant = maxrowsumWant maxrowsumGot = normGot case lapack.Frobenius: normWant = frobWant } if math.Abs(normGot-normWant) > tol*float64(n) { t.Errorf("%v: unexpected result; got %v, want %v", name, normGot, normWant) } } // MaxColSum and MaxRowSum norms should be exactly equal because the // matrix is symmetric. if maxcolsumGot != maxrowsumGot { name := fmt.Sprintf("uplo=%v,n=%v,kd=%v,ldab=%v", string(uplo), n, kd, ldab) t.Errorf("%v: unexpected mismatch between MaxColSum and MaxRowSum norms of A; MaxColSum %v, MaxRowSum %v", name, maxcolsumGot, maxrowsumGot) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlanst.go000066400000000000000000000031651450372207100230450ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/lapack" ) type Dlanster interface { Dlanst(norm lapack.MatrixNorm, n int, d, e []float64) float64 Dlanger } func DlanstTest(t *testing.T, impl Dlanster) { rnd := rand.New(rand.NewSource(1)) for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxColumnSum, lapack.MaxRowSum, lapack.Frobenius} { for _, n := range []int{1, 3, 10, 100} { for cas := 0; cas < 100; cas++ { // Generate randomly the main diagonal of the // symmetric tridiagonal matrix A. d := make([]float64, n) for i := range d { d[i] = rnd.NormFloat64() } // Generate randomly the off-diagonal of A. e := make([]float64, n-1) for i := range e { e[i] = rnd.NormFloat64() } // Create A in dense representation. m := n lda := n a := make([]float64, m*lda) for i := 0; i < n; i++ { a[i*lda+i] = d[i] } for i := 0; i < n-1; i++ { a[i*lda+i+1] = e[i] a[(i+1)*lda+i] = e[i] } work := make([]float64, n) // Compute a norm of A using Dlanst. syNorm := impl.Dlanst(norm, n, d, e) // Compute a reference value for the norm using // Dlange and the dense representation of A. geNorm := impl.Dlange(norm, m, n, a, lda, work) if math.Abs(syNorm-geNorm) > 1e-12 { t.Errorf("Norm mismatch: norm = %v, cas = %v, n = %v. Want %v, got %v.", string(norm), cas, n, geNorm, syNorm) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlansy.go000066400000000000000000000045371450372207100230560ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/lapack" ) type Dlansyer interface { Dlanger Dlansy(norm lapack.MatrixNorm, uplo blas.Uplo, n int, a []float64, lda int, work []float64) float64 } func DlansyTest(t *testing.T, impl Dlansyer) { rnd := rand.New(rand.NewSource(1)) for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxColumnSum, lapack.MaxRowSum, lapack.Frobenius} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, test := range []struct { n, lda int }{ {1, 0}, {3, 0}, {1, 10}, {3, 10}, } { for trial := 0; trial < 100; trial++ { n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate n×n matrix A and fill it. // Only the uplo triangle of A will be used below // to represent a symmetric matrix. a := make([]float64, lda*n) if trial == 0 { // In the first trial fill the matrix // with predictable integers. for i := range a { a[i] = float64(i) } } else { // Otherwise fill it with random numbers. for i := range a { a[i] = rnd.NormFloat64() } } // Create a dense representation of the symmetric matrix // stored in the uplo triangle of A. aDense := make([]float64, n*n) if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { v := a[i*lda+j] aDense[i*n+j] = v aDense[j*n+i] = v } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { v := a[i*lda+j] aDense[i*n+j] = v aDense[j*n+i] = v } } } work := make([]float64, n) // Compute the norm of the symmetric matrix A. got := impl.Dlansy(norm, uplo, n, a, lda, work) // Compute the reference norm value using Dlange // and the dense representation of A. want := impl.Dlange(norm, n, n, aDense, n, work) if math.Abs(want-got) > 1e-14 { t.Errorf("Norm mismatch. norm = %c, upper = %v, n = %v, lda = %v, want %v, got %v.", norm, uplo == blas.Upper, n, lda, got, want) } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlantb.go000066400000000000000000000066421450372207100230270ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlantber interface { Dlantb(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k int, a []float64, lda int, work []float64) float64 } func DlantbTest(t *testing.T, impl Dlantber) { rnd := rand.New(rand.NewSource(1)) for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum, lapack.Frobenius} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { name := normToString(norm) + uploToString(uplo) + diagToString(diag) t.Run(name, func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for _, k := range []int{0, 1, 2, 3, n, n + 2} { for _, lda := range []int{k + 1, k + 3} { for iter := 0; iter < 10; iter++ { dlantbTest(t, impl, rnd, norm, uplo, diag, n, k, lda) } } } } }) } } } } func dlantbTest(t *testing.T, impl Dlantber, rnd *rand.Rand, norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k, lda int) { const tol = 1e-14 name := fmt.Sprintf("n=%v,k=%v,lda=%v", n, k, lda) // Deal with zero-sized matrices early. if n == 0 { got := impl.Dlantb(norm, uplo, diag, n, k, nil, lda, nil) if got != 0 { t.Errorf("%v: unexpected result for zero-sized matrix", name) } return } a := make([]float64, max(0, (n-1)*lda+k+1)) if rnd.Float64() < 0.5 { // Sometimes fill A with elements between -0.5 and 0.5 so that for // blas.Unit matrices the largest element is the 1 on the main diagonal. for i := range a { // Between -0.5 and 0.5. a[i] = rnd.Float64() - 0.5 } } else { for i := range a { // Between -2 and 2. a[i] = 4*rnd.Float64() - 2 } } // Sometimes put a NaN into A. if rnd.Float64() < 0.5 { a[rnd.Intn(len(a))] = math.NaN() } // Make a copy of A for later comparison. aCopy := make([]float64, len(a)) copy(aCopy, a) var work []float64 if norm == lapack.MaxColumnSum { work = make([]float64, n) } // Fill work with random garbage. for i := range work { work[i] = rnd.NormFloat64() } got := impl.Dlantb(norm, uplo, diag, n, k, a, lda, work) if !floats.Same(a, aCopy) { t.Fatalf("%v: unexpected modification of a", name) } // Generate a dense representation of A and compute the wanted result. ldaGen := n aGen := make([]float64, n*ldaGen) if uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j < min(n-i, k+1); j++ { aGen[i*ldaGen+i+j] = a[i*lda+j] } } } else { for i := 0; i < n; i++ { for j := max(0, k-i); j < k+1; j++ { aGen[i*ldaGen+i-(k-j)] = a[i*lda+j] } } } if diag == blas.Unit { for i := 0; i < n; i++ { aGen[i*ldaGen+i] = 1 } } want := dlange(norm, n, n, aGen, ldaGen) if math.IsNaN(want) { if !math.IsNaN(got) { t.Errorf("%v: unexpected result with NaN element; got %v, want %v", name, got, want) } return } if norm == lapack.MaxAbs { if got != want { t.Errorf("%v: unexpected result; got %v, want %v", name, got, want) } return } diff := math.Abs(got - want) if diff > tol { t.Errorf("%v: unexpected result; got %v, want %v, diff=%v", name, got, want, diff) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlantb_bench.go000066400000000000000000000025671450372207100241700ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/lapack" ) func DlantbBenchmark(b *testing.B, impl Dlantber) { var result float64 rnd := rand.New(rand.NewSource(1)) for _, bm := range []struct { n, k int }{ {n: 10000, k: 1}, {n: 10000, k: 2}, {n: 10000, k: 100}, } { n := bm.n k := bm.k lda := k + 1 for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum, lapack.Frobenius} { var work []float64 if norm == lapack.MaxColumnSum { work = make([]float64, n) } for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { name := fmt.Sprintf("%v%v%vN=%vK=%v", normToString(norm), uploToString(uplo), diagToString(diag), n, k) b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } b.StartTimer() result = impl.Dlantb(norm, uplo, diag, bm.n, bm.k, a, lda, work) } }) } } } } if math.IsNaN(result) { b.Error("unexpected NaN result") } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlantr.go000066400000000000000000000071521450372207100230440ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlantrer interface { Dlanger Dlantr(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 } func DlantrTest(t *testing.T, impl Dlantrer) { rnd := rand.New(rand.NewSource(1)) for _, m := range []int{0, 1, 2, 3, 4, 5, 10} { for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { if uplo == blas.Upper && m > n { continue } if uplo == blas.Lower && n > m { continue } for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, lda := range []int{max(1, n), n + 3} { dlantrTest(t, impl, rnd, uplo, diag, m, n, lda) } } } } } } func dlantrTest(t *testing.T, impl Dlantrer, rnd *rand.Rand, uplo blas.Uplo, diag blas.Diag, m, n, lda int) { const tol = 1e-14 // Generate a random triangular matrix. If the matrix has unit diagonal, // don't set the diagonal elements to 1. a := make([]float64, max(0, (m-1)*lda+n)) for i := range a { a[i] = rnd.NormFloat64() } rowsum := make([]float64, m) colsum := make([]float64, n) var frobWant, maxabsWant float64 if diag == blas.Unit { // Account for the unit diagonal. for i := 0; i < min(m, n); i++ { rowsum[i] = 1 colsum[i] = 1 } frobWant = float64(min(m, n)) if min(m, n) > 0 { maxabsWant = 1 } } if uplo == blas.Upper { for i := 0; i < min(m, n); i++ { start := i if diag == blas.Unit { start = i + 1 } for j := start; j < n; j++ { aij := 2*rnd.Float64() - 1 a[i*lda+j] = aij rowsum[i] += math.Abs(aij) colsum[j] += math.Abs(aij) maxabsWant = math.Max(maxabsWant, math.Abs(aij)) frobWant += aij * aij } } } else { for i := 0; i < m; i++ { end := i if diag == blas.Unit { end = i - 1 } for j := 0; j <= min(end, n-1); j++ { aij := 2*rnd.Float64() - 1 a[i*lda+j] = aij rowsum[i] += math.Abs(aij) colsum[j] += math.Abs(aij) maxabsWant = math.Max(maxabsWant, math.Abs(aij)) frobWant += aij * aij } } } frobWant = math.Sqrt(frobWant) var maxcolsumWant, maxrowsumWant float64 if n > 0 { maxcolsumWant = floats.Max(colsum) } if m > 0 { maxrowsumWant = floats.Max(rowsum) } aCopy := make([]float64, len(a)) copy(aCopy, a) for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxColumnSum, lapack.MaxRowSum, lapack.Frobenius} { name := fmt.Sprintf("norm=%v,uplo=%v,diag=%v,m=%v,n=%v,lda=%v", string(norm), string(uplo), string(diag), m, n, lda) var work []float64 if norm == lapack.MaxColumnSum { work = make([]float64, n) } normGot := impl.Dlantr(norm, uplo, diag, m, n, a, lda, work) if !floats.Equal(a, aCopy) { t.Fatalf("%v: unexpected modification of a", name) } if norm == lapack.MaxAbs { // MaxAbs norm involves no floating-point computation, // so we expect exact equality here. if normGot != maxabsWant { t.Errorf("%v: unexpected result; got %v, want %v", name, normGot, maxabsWant) } continue } var normWant float64 switch norm { case lapack.MaxColumnSum: normWant = maxcolsumWant case lapack.MaxRowSum: normWant = maxrowsumWant case lapack.Frobenius: normWant = frobWant } if math.Abs(normGot-normWant) >= tol { t.Errorf("%v: unexpected result; got %v, want %v", name, normGot, normWant) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlanv2.go000066400000000000000000000070761450372207100227530ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" ) type Dlanv2er interface { Dlanv2(a, b, c, d float64) (aa, bb, cc, dd float64, rt1r, rt1i, rt2r, rt2i float64, cs, sn float64) } func Dlanv2Test(t *testing.T, impl Dlanv2er) { rnd := rand.New(rand.NewSource(1)) t.Run("UpperTriangular", func(t *testing.T) { for i := 0; i < 10; i++ { a := rnd.NormFloat64() b := rnd.NormFloat64() d := rnd.NormFloat64() dlanv2Test(t, impl, a, b, 0, d) } }) t.Run("LowerTriangular", func(t *testing.T) { for i := 0; i < 10; i++ { a := rnd.NormFloat64() c := rnd.NormFloat64() d := rnd.NormFloat64() dlanv2Test(t, impl, a, 0, c, d) } }) t.Run("StandardSchur", func(t *testing.T) { for i := 0; i < 10; i++ { a := rnd.NormFloat64() b := rnd.NormFloat64() c := rnd.NormFloat64() if math.Signbit(b) == math.Signbit(c) { c = -c } dlanv2Test(t, impl, a, b, c, a) } }) t.Run("General", func(t *testing.T) { for i := 0; i < 100; i++ { a := rnd.NormFloat64() b := rnd.NormFloat64() c := rnd.NormFloat64() d := rnd.NormFloat64() dlanv2Test(t, impl, a, b, c, d) } // https://github.com/Reference-LAPACK/lapack/issues/263 dlanv2Test(t, impl, 0, 1, -1, math.Nextafter(0, 1)) }) } func dlanv2Test(t *testing.T, impl Dlanv2er, a, b, c, d float64) { aa, bb, cc, dd, rt1r, rt1i, rt2r, rt2i, cs, sn := impl.Dlanv2(a, b, c, d) mat := fmt.Sprintf("[%v %v; %v %v]", a, b, c, d) if cc == 0 { // The eigenvalues are real, so check that the imaginary parts // are zero. if rt1i != 0 || rt2i != 0 { t.Errorf("Unexpected complex eigenvalues for %v", mat) } } else { // The eigenvalues are complex, so check that documented // conditions hold. if aa != dd { t.Errorf("Diagonal elements not equal for %v: got [%v %v]", mat, aa, dd) } if bb*cc >= 0 { t.Errorf("Non-diagonal elements have the same sign for %v: got [%v %v]", mat, bb, cc) } else { // Compute the absolute value of the imaginary part. im := math.Sqrt(-bb * cc) // Check that ±im is close to one of the returned // imaginary parts. if math.Abs(rt1i-im) > 1e-14 && math.Abs(rt1i+im) > 1e-14 { t.Errorf("Unexpected imaginary part of eigenvalue for %v: got %v, want %v or %v", mat, rt1i, im, -im) } if math.Abs(rt2i-im) > 1e-14 && math.Abs(rt2i+im) > 1e-14 { t.Errorf("Unexpected imaginary part of eigenvalue for %v: got %v, want %v or %v", mat, rt2i, im, -im) } } } // Check that the returned real parts are consistent. if rt1r != aa && rt1r != dd { t.Errorf("Unexpected real part of eigenvalue for %v: got %v, want %v or %v", mat, rt1r, aa, dd) } if rt2r != aa && rt2r != dd { t.Errorf("Unexpected real part of eigenvalue for %v: got %v, want %v or %v", mat, rt2r, aa, dd) } // Check that the columns of the orthogonal matrix have unit norm. if math.Abs(math.Hypot(cs, sn)-1) > 1e-14 { t.Errorf("Unexpected unitary matrix for %v: got cs %v, sn %v", mat, cs, sn) } // Re-compute the original matrix [a b; c d] from its factorization. gota := cs*(aa*cs-bb*sn) - sn*(cc*cs-dd*sn) gotb := cs*(aa*sn+bb*cs) - sn*(cc*sn+dd*cs) gotc := sn*(aa*cs-bb*sn) + cs*(cc*cs-dd*sn) gotd := sn*(aa*sn+bb*cs) + cs*(cc*sn+dd*cs) if math.Abs(gota-a) > 1e-14 || math.Abs(gotb-b) > 1e-14 || math.Abs(gotc-c) > 1e-14 || math.Abs(gotd-d) > 1e-14 { t.Errorf("Unexpected factorization: got [%v %v; %v %v], want [%v %v; %v %v]", gota, gotb, gotc, gotd, a, b, c, d) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlapll.go000066400000000000000000000027021450372207100230240ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/lapack" ) type Dlapller interface { Dgesvder Dlapll(n int, x []float64, incX int, y []float64, incY int) float64 } func DlapllTest(t *testing.T, impl Dlapller) { rnd := rand.New(rand.NewSource(1)) for i, m := range []int{5, 6, 9, 300, 400, 600} { n := 2 lda := n // Allocate m×2 matrix A and fill it with random numbers. a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } // Store a copy of A for later comparison. aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute the smallest singular value of A. got := impl.Dlapll(m, a[0:], lda, a[1:], lda) // Compute singular values of A independently by Dgesvd. s := make([]float64, min(m, n)) work := make([]float64, 1) impl.Dgesvd(lapack.SVDNone, lapack.SVDNone, m, n, aCopy, lda, s, nil, 1, nil, 1, work, -1) work = make([]float64, int(work[0])) impl.Dgesvd(lapack.SVDNone, lapack.SVDNone, m, n, aCopy, lda, s, nil, 1, nil, 1, work, len(work)) // Take the smallest singular value. want := s[len(s)-1] if !scalar.EqualWithinAbsOrRel(got, want, 1e-14, 1e-14) { t.Errorf("Case %d: unexpected smallest singular value, got:%f want:%f", i, got, want) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlapmr.go000066400000000000000000000041531450372207100230350ustar00rootroot00000000000000// Copyright ©2022 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlapmrer interface { Dlapmr(forwrd bool, m, n int, x []float64, ldx int, k []int) } func DlapmrTest(t *testing.T, impl Dlapmrer) { rnd := rand.New(rand.NewSource(1)) for _, fwd := range []bool{true, false} { for _, m := range []int{0, 1, 2, 3, 4, 5, 10} { for _, n := range []int{0, 1, 4} { for _, ldx := range []int{max(1, n), n + 3} { dlapmrTest(t, impl, rnd, fwd, m, n, ldx) } } } } } func dlapmrTest(t *testing.T, impl Dlapmrer, rnd *rand.Rand, fwd bool, m, n, ldx int) { name := fmt.Sprintf("forwrd=%v,m=%d,n=%d,ldx=%d", fwd, m, n, ldx) bi := blas64.Implementation() // Generate a random permutation and simultaneously apply it to the rows of the identity matrix. k := make([]int, m) for i := range k { k[i] = i } p := eye(m, m) for i := 0; i < m-1; i++ { j := i + rnd.Intn(m-i) k[i], k[j] = k[j], k[i] bi.Dswap(m, p.Data[i*p.Stride:], 1, p.Data[j*p.Stride:], 1) } kCopy := make([]int, len(k)) copy(kCopy, k) // Generate a random matrix X. x := randomGeneral(m, n, ldx, rnd) // Applying the permutation k with Dlapmr is the same as multiplying X with P or Pᵀ from the left: // - forward permutation: P * X // - backward permutation: Pᵀ* X trans := blas.NoTrans if !fwd { trans = blas.Trans } want := zeros(m, n, n) bi.Dgemm(trans, blas.NoTrans, m, n, m, 1, p.Data, p.Stride, x.Data, x.Stride, 0, want.Data, want.Stride) // Apply the permutation in k to X. impl.Dlapmr(fwd, m, n, x.Data, x.Stride, k) got := x // Check that k hasn't been modified in Dlapmr. var kmod bool for i, ki := range k { if ki != kCopy[i] { kmod = true break } } if kmod { t.Errorf("%s: unexpected modification of k", name) } // Check that Dlapmr yields the same result as multiplication with P. if !equalGeneral(got, want) { t.Errorf("%s: unexpected result", name) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlapmt.go000066400000000000000000000037721450372207100230450ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "gonum.org/v1/gonum/blas/blas64" ) type Dlapmter interface { Dlapmt(forward bool, m, n int, x []float64, ldx int, k []int) } func DlapmtTest(t *testing.T, impl Dlapmter) { for ti, test := range []struct { forward bool k []int want blas64.General }{ { forward: true, k: []int{0, 1, 2}, want: blas64.General{ Rows: 4, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, }, }, { forward: false, k: []int{0, 1, 2}, want: blas64.General{ Rows: 4, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, }, }, { forward: true, k: []int{1, 2, 0}, want: blas64.General{ Rows: 4, Cols: 3, Stride: 3, Data: []float64{ 2, 3, 1, 5, 6, 4, 8, 9, 7, 11, 12, 10, }, }, }, { forward: false, k: []int{1, 2, 0}, want: blas64.General{ Rows: 4, Cols: 3, Stride: 3, Data: []float64{ 3, 1, 2, 6, 4, 5, 9, 7, 8, 12, 10, 11, }, }, }, } { m := test.want.Rows n := test.want.Cols if len(test.k) != n { panic("bad length of k") } for _, extra := range []int{0, 11} { x := zeros(m, n, n+extra) c := 1 for i := 0; i < m; i++ { for j := 0; j < n; j++ { x.Data[i*x.Stride+j] = float64(c) c++ } } k := make([]int, len(test.k)) copy(k, test.k) impl.Dlapmt(test.forward, m, n, x.Data, x.Stride, k) prefix := fmt.Sprintf("Case %v (forward=%t,m=%v,n=%v,extra=%v)", ti, test.forward, m, n, extra) if !generalOutsideAllNaN(x) { t.Errorf("%v: out-of-range write to X", prefix) } if !equalApproxGeneral(x, test.want, 0) { t.Errorf("%v: unexpected X\n%v\n%v", prefix, x, test.want) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlapy2.go000066400000000000000000000013061450372207100227460ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) type Dlapy2er interface { Dlapy2(float64, float64) float64 } func Dlapy2Test(t *testing.T, impl Dlapy2er) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 10; i++ { x := math.Abs(1e200 * rnd.NormFloat64()) y := math.Abs(1e200 * rnd.NormFloat64()) got := impl.Dlapy2(x, y) want := math.Hypot(x, y) if !scalar.EqualWithinRel(got, want, 1e-15) { t.Errorf("Dlapy2(%g, %g) = %g, want %g", x, y, got, want) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaqp2.go000066400000000000000000000051371450372207100227440ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlaqp2er interface { Dlapmter Dlaqp2(m, n, offset int, a []float64, lda int, jpvt []int, tau, vn1, vn2, work []float64) } func Dlaqp2Test(t *testing.T, impl Dlaqp2er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for ti, test := range []struct { m, n, offset int }{ {m: 4, n: 3, offset: 0}, {m: 4, n: 3, offset: 2}, {m: 4, n: 3, offset: 4}, {m: 3, n: 4, offset: 0}, {m: 3, n: 4, offset: 1}, {m: 3, n: 4, offset: 2}, {m: 8, n: 3, offset: 0}, {m: 8, n: 3, offset: 4}, {m: 8, n: 3, offset: 8}, {m: 3, n: 8, offset: 0}, {m: 3, n: 8, offset: 1}, {m: 3, n: 8, offset: 2}, {m: 10, n: 10, offset: 0}, {m: 10, n: 10, offset: 5}, {m: 10, n: 10, offset: 10}, } { m := test.m n := test.n jpiv := make([]int, n) for _, extra := range []int{0, 11} { a := randomGeneral(m, n, n+extra, rnd) aCopy := cloneGeneral(a) for j := range jpiv { jpiv[j] = j } tau := make([]float64, n) vn1 := columnNorms(m, n, a.Data, a.Stride) vn2 := columnNorms(m, n, a.Data, a.Stride) work := make([]float64, n) impl.Dlaqp2(m, n, test.offset, a.Data, a.Stride, jpiv, tau, vn1, vn2, work) prefix := fmt.Sprintf("Case %v (offset=%d,m=%v,n=%v,extra=%v)", ti, test.offset, m, n, extra) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A", prefix) } mo := m - test.offset if mo == 0 { continue } q := constructQ("QR", mo, n, a.Data[test.offset*a.Stride:], a.Stride, tau) // Check that Q is orthogonal. if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("%v: Q is not orthogonal; resid=%v, want<=%v", prefix, resid, tol) } // Check that |A*P - Q*R| is small. impl.Dlapmt(true, aCopy.Rows, aCopy.Cols, aCopy.Data, aCopy.Stride, jpiv) qrap := blas64.General{ Rows: mo, Cols: aCopy.Cols, Stride: aCopy.Stride, Data: aCopy.Data[test.offset*aCopy.Stride:], } r := zeros(mo, n, n) for i := 0; i < mo; i++ { for j := i; j < n; j++ { r.Data[i*r.Stride+j] = a.Data[(test.offset+i)*a.Stride+j] } } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, r, -1, qrap) resid := dlange(lapack.MaxColumnSum, qrap.Rows, qrap.Cols, qrap.Data, qrap.Stride) if resid > tol { t.Errorf("%v: |Q*R - A*P|=%v, want<=%v", prefix, resid, tol) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaqps.go000066400000000000000000000053571450372207100230510ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlaqpser interface { Dlapmter Dlaqps(m, n, offset, nb int, a []float64, lda int, jpvt []int, tau, vn1, vn2, auxv, f []float64, ldf int) (kb int) } func DlaqpsTest(t *testing.T, impl Dlaqpser) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for ti, test := range []struct { m, n, nb, offset int }{ {m: 4, n: 3, nb: 2, offset: 0}, {m: 4, n: 3, nb: 1, offset: 2}, {m: 3, n: 4, nb: 2, offset: 0}, {m: 3, n: 4, nb: 1, offset: 2}, {m: 8, n: 3, nb: 2, offset: 0}, {m: 8, n: 3, nb: 1, offset: 4}, {m: 3, n: 8, nb: 2, offset: 0}, {m: 3, n: 8, nb: 1, offset: 1}, {m: 10, n: 10, nb: 3, offset: 0}, {m: 10, n: 10, nb: 2, offset: 5}, } { m := test.m n := test.n jpiv := make([]int, n) for _, extra := range []int{0, 11} { a := randomGeneral(m, n, n+extra, rnd) aCopy := cloneGeneral(a) for j := range jpiv { jpiv[j] = j } tau := make([]float64, n) vn1 := columnNorms(m, n, a.Data, a.Stride) vn2 := columnNorms(m, n, a.Data, a.Stride) auxv := make([]float64, test.nb) f := zeros(test.n, test.nb, n) kb := impl.Dlaqps(m, n, test.offset, test.nb, a.Data, a.Stride, jpiv, tau, vn1, vn2, auxv, f.Data, f.Stride) prefix := fmt.Sprintf("Case %v (m=%v,n=%v,offset=%d,nb=%v,extra=%v)", ti, m, n, test.offset, test.nb, extra) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A", prefix) } if kb != test.nb { t.Logf("%v: %v columns out of %v factorized", prefix, kb, test.nb) } mo := m - test.offset if mo == 0 { continue } q := constructQ("QR", mo, kb, a.Data[test.offset*a.Stride:], a.Stride, tau) // Check that Q is orthogonal. if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("%v: Q is not orthogonal; resid=%v, want<=%v", prefix, resid, tol) } // Check that |A*P - Q*R| is small. impl.Dlapmt(true, aCopy.Rows, aCopy.Cols, aCopy.Data, aCopy.Stride, jpiv) qrap := blas64.General{ Rows: mo, Cols: kb, Stride: aCopy.Stride, Data: aCopy.Data[test.offset*aCopy.Stride:], } r := zeros(mo, kb, n) for i := 0; i < mo; i++ { for j := i; j < kb; j++ { r.Data[i*r.Stride+j] = a.Data[(test.offset+i)*a.Stride+j] } } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, r, -1, qrap) resid := dlange(lapack.MaxColumnSum, qrap.Rows, qrap.Cols, qrap.Data, qrap.Stride) if resid > tol { t.Errorf("%v: |Q*R - A*P|=%v, want<=%v", prefix, resid, tol) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaqr04.go000066400000000000000000000254121450372207100230260ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlaqr04er interface { Dlaqr04(wantt, wantz bool, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, iloz, ihiz int, z []float64, ldz int, work []float64, lwork int, recur int) int Dlahqrer } type dlaqr04Test struct { h blas64.General ilo, ihi int iloz, ihiz int wantt, wantz bool evWant []complex128 // Optional slice holding known eigenvalues. } func Dlaqr04Test(t *testing.T, impl Dlaqr04er) { rnd := rand.New(rand.NewSource(1)) // Tests for small matrices that choose the ilo,ihi and iloz,ihiz pairs // randomly. for _, wantt := range []bool{true, false} { for _, wantz := range []bool{true, false} { for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 11, 12, 18, 29} { for _, extra := range []int{0, 11} { for recur := 0; recur <= 2; recur++ { for cas := 0; cas < n; cas++ { ilo := rnd.Intn(n) ihi := rnd.Intn(n) if ilo > ihi { ilo, ihi = ihi, ilo } iloz := rnd.Intn(ilo + 1) ihiz := ihi + rnd.Intn(n-ihi) h := randomHessenberg(n, n+extra, rnd) if ilo-1 >= 0 { h.Data[ilo*h.Stride+ilo-1] = 0 } if ihi+1 < n { h.Data[(ihi+1)*h.Stride+ihi] = 0 } test := dlaqr04Test{ h: h, ilo: ilo, ihi: ihi, iloz: iloz, ihiz: ihiz, wantt: wantt, wantz: wantz, } testDlaqr04(t, impl, test, false, recur) testDlaqr04(t, impl, test, true, recur) } } } } } } // Tests for matrices large enough to possibly use the recursion (but it // doesn't seem to be the case). for _, n := range []int{100, 500} { for cas := 0; cas < 5; cas++ { h := randomHessenberg(n, n, rnd) test := dlaqr04Test{ h: h, ilo: 0, ihi: n - 1, iloz: 0, ihiz: n - 1, wantt: true, wantz: true, } testDlaqr04(t, impl, test, true, 1) } } // Tests that make sure that some potentially problematic corner cases, // like zero-sized matrix, are covered. for _, wantt := range []bool{true, false} { for _, wantz := range []bool{true, false} { for _, extra := range []int{0, 1, 11} { for _, test := range []dlaqr04Test{ { h: randomHessenberg(0, extra, rnd), ilo: 0, ihi: -1, iloz: 0, ihiz: -1, }, { h: randomHessenberg(1, 1+extra, rnd), ilo: 0, ihi: 0, iloz: 0, ihiz: 0, }, { h: randomHessenberg(2, 2+extra, rnd), ilo: 1, ihi: 1, iloz: 1, ihiz: 1, }, { h: randomHessenberg(2, 2+extra, rnd), ilo: 0, ihi: 1, iloz: 0, ihiz: 1, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 0, iloz: 0, ihiz: 0, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 9, iloz: 0, ihiz: 9, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 1, iloz: 0, ihiz: 1, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 0, ihi: 1, iloz: 0, ihiz: 9, }, { h: randomHessenberg(10, 10+extra, rnd), ilo: 9, ihi: 9, iloz: 0, ihiz: 9, }, } { if test.ilo-1 >= 0 { test.h.Data[test.ilo*test.h.Stride+test.ilo-1] = 0 } if test.ihi+1 < test.h.Rows { test.h.Data[(test.ihi+1)*test.h.Stride+test.ihi] = 0 } test.wantt = wantt test.wantz = wantz testDlaqr04(t, impl, test, false, 1) testDlaqr04(t, impl, test, true, 1) } } } } // Tests with known eigenvalues computed by Octave. for _, test := range []dlaqr04Test{ { h: blas64.General{ Rows: 1, Cols: 1, Stride: 1, Data: []float64{7.09965484086874e-1}, }, ilo: 0, ihi: 0, iloz: 0, ihiz: 0, evWant: []complex128{7.09965484086874e-1}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ 0, -1, 1, 0, }, }, ilo: 0, ihi: 1, iloz: 0, ihiz: 1, evWant: []complex128{1i, -1i}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ 6.25219991450918e-1, 8.17510791994361e-1, 3.31218891622294e-1, 1.24103744878131e-1, }, }, ilo: 0, ihi: 1, iloz: 0, ihiz: 1, evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, }, { h: blas64.General{ Rows: 4, Cols: 4, Stride: 4, Data: []float64{ 1, 0, 0, 0, 0, 6.25219991450918e-1, 8.17510791994361e-1, 0, 0, 3.31218891622294e-1, 1.24103744878131e-1, 0, 0, 0, 0, 1, }, }, ilo: 1, ihi: 2, iloz: 0, ihiz: 3, evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ -1.1219562276608, 6.85473513349362e-1, -8.19951061145131e-1, 1.93728523178888e-1, }, }, ilo: 0, ihi: 1, iloz: 0, ihiz: 1, evWant: []complex128{ -4.64113852240958e-1 + 3.59580510817350e-1i, -4.64113852240958e-1 - 3.59580510817350e-1i, }, }, { h: blas64.General{ Rows: 5, Cols: 5, Stride: 5, Data: []float64{ 9.57590178533658e-1, -5.10651295522708e-1, 9.24974510015869e-1, -1.30016306879522e-1, 2.92601986926954e-2, -1.08084756637964, 1.77529701001213, -1.36480197632509, 2.23196371219601e-1, 1.12912853063308e-1, 0, -8.44075612174676e-1, 1.067867614486, -2.55782915176399e-1, -2.00598563137468e-1, 0, 0, -5.67097237165410e-1, 2.07205057427341e-1, 6.54998340743380e-1, 0, 0, 0, -1.89441413886041e-1, -4.18125416021786e-1, }, }, ilo: 0, ihi: 4, iloz: 0, ihiz: 4, evWant: []complex128{ 2.94393309555622, 4.97029793606701e-1 + 3.63041654992384e-1i, 4.97029793606701e-1 - 3.63041654992384e-1i, -1.74079119166145e-1 + 2.01570009462092e-1i, -1.74079119166145e-1 - 2.01570009462092e-1i, }, }, } { test.wantt = true test.wantz = true testDlaqr04(t, impl, test, false, 1) testDlaqr04(t, impl, test, true, 1) } } func testDlaqr04(t *testing.T, impl Dlaqr04er, test dlaqr04Test, optwork bool, recur int) { const tol = 1e-14 h := cloneGeneral(test.h) n := h.Cols extra := h.Stride - h.Cols wantt := test.wantt wantz := test.wantz ilo := test.ilo ihi := test.ihi iloz := test.iloz ihiz := test.ihiz var z, zCopy blas64.General if wantz { z = eye(n, n+extra) zCopy = cloneGeneral(z) } wr := nanSlice(ihi + 1) wi := nanSlice(ihi + 1) var work []float64 if optwork { work = nanSlice(1) impl.Dlaqr04(wantt, wantz, n, ilo, ihi, h.Data, h.Stride, wr, wi, iloz, ihiz, z.Data, max(1, z.Stride), work, -1, recur) work = nanSlice(int(work[0])) } else { work = nanSlice(max(1, n)) } unconverged := impl.Dlaqr04(wantt, wantz, n, ilo, ihi, h.Data, h.Stride, wr, wi, iloz, ihiz, z.Data, max(1, z.Stride), work, len(work), recur) prefix := fmt.Sprintf("Case wantt=%v, wantz=%v, n=%v, ilo=%v, ihi=%v, iloz=%v, ihiz=%v, extra=%v, opt=%v", wantt, wantz, n, ilo, ihi, iloz, ihiz, extra, optwork) if !generalOutsideAllNaN(h) { t.Errorf("%v: out-of-range write to H\n%v", prefix, h.Data) } if !generalOutsideAllNaN(z) { t.Errorf("%v: out-of-range write to Z\n%v", prefix, z.Data) } start := ilo // Index of the first computed eigenvalue. if unconverged != 0 { start = unconverged if start == ihi+1 { t.Logf("%v: no eigenvalue has converged", prefix) } } // Check that wr and wi have not been modified within [:start]. if !isAllNaN(wr[:start]) { t.Errorf("%v: unexpected modification of wr", prefix) } if !isAllNaN(wi[:start]) { t.Errorf("%v: unexpected modification of wi", prefix) } var hasReal bool for i := start; i <= ihi; { if wi[i] == 0 { // Real eigenvalue. hasReal = true // Check that the eigenvalue corresponds to a 1×1 block // on the diagonal of H. if wantt && wr[i] != h.Data[i*h.Stride+i] { t.Errorf("%v: wr[%v] != H[%v,%v]", prefix, i, i, i) } i++ continue } // Complex eigenvalue. // In the conjugate pair the real parts must be equal. if wr[i] != wr[i+1] { t.Errorf("%v: real part of conjugate pair not equal, i=%v", prefix, i) } // The first imaginary part must be positive. if wi[i] < 0 { t.Errorf("%v: wi[%v] not positive", prefix, i) } // The second imaginary part must be negative with the same // magnitude. if wi[i] != -wi[i+1] { t.Errorf("%v: wi[%v] != wi[%v]", prefix, i, i+1) } if wantt { // Check that wi[i] has the correct value. if wr[i] != h.Data[i*h.Stride+i] { t.Errorf("%v: wr[%v] != H[%v,%v]", prefix, i, i, i) } if wr[i] != h.Data[(i+1)*h.Stride+i+1] { t.Errorf("%v: wr[%v] != H[%v,%v]", prefix, i, i+1, i+1) } im := math.Sqrt(math.Abs(h.Data[(i+1)*h.Stride+i])) * math.Sqrt(math.Abs(h.Data[i*h.Stride+i+1])) if math.Abs(im-wi[i]) > tol { t.Errorf("%v: unexpected value of wi[%v]: want %v, got %v", prefix, i, im, wi[i]) } } i += 2 } // If the number of found eigenvalues is odd, at least one must be real. if (ihi+1-start)%2 != 0 && !hasReal { t.Errorf("%v: expected at least one real eigenvalue", prefix) } // Compare found eigenvalues to the reference, if known. if test.evWant != nil { for i := start; i <= ihi; i++ { ev := complex(wr[i], wi[i]) found, _ := containsComplex(test.evWant, ev, tol) if !found { t.Errorf("%v: unexpected eigenvalue %v", prefix, ev) } } } if !wantz { return } // Z should contain the orthogonal matrix U. if resid := residualOrthogonal(z, false); resid > tol*float64(n) { t.Errorf("Case %v: Z is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } // Z should have been modified only in the // [iloz:ihiz+1,ilo:ihi+1] block. for i := 0; i < n; i++ { for j := 0; j < n; j++ { if iloz <= i && i <= ihiz && ilo <= j && j <= ihi { continue } if z.Data[i*z.Stride+j] != zCopy.Data[i*zCopy.Stride+j] { t.Errorf("%v: Z modified outside of [iloz:ihiz+1,ilo:ihi+1] block", prefix) } } } if wantt { // Zero out h under the subdiagonal because Dlaqr04 uses it as // workspace. for i := 2; i < n; i++ { for j := 0; j < i-1; j++ { h.Data[i*h.Stride+j] = 0 } } hz := eye(n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, test.h, z, 0, hz) zhz := eye(n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, z, hz, 0, zhz) if !equalApproxGeneral(zhz, h, 10*tol) { t.Errorf("%v: Zᵀ*(initial H)*Z and (final H) are not equal", prefix) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaqr1.go000066400000000000000000000042611450372207100227420ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dlaqr1er interface { Dlaqr1(n int, h []float64, ldh int, sr1, si1, sr2, si2 float64, v []float64) } func Dlaqr1Test(t *testing.T, impl Dlaqr1er) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{2, 3} { for _, ldh := range []int{n, n + 1, n + 10} { for _, cas := range []int{1, 2} { for k := 0; k < 100; k++ { v := make([]float64, n) for i := range v { v[i] = math.NaN() } h := make([]float64, n*(n-1)*ldh) for i := range h { h[i] = math.NaN() } for i := 0; i < n; i++ { for j := 0; j < n; j++ { h[i*ldh+j] = rnd.NormFloat64() } } var sr1, sr2, si1, si2 float64 if cas == 1 { sr1 = rnd.NormFloat64() sr2 = sr1 si1 = rnd.NormFloat64() si2 = -si1 } else { sr1 = rnd.NormFloat64() sr2 = rnd.NormFloat64() si1 = 0 si2 = 0 } impl.Dlaqr1(n, h, ldh, sr1, si1, sr2, si2, v) // Matrix H - s1*I. h1 := make([]complex128, n*n) for i := 0; i < n; i++ { for j := 0; j < n; j++ { h1[i*n+j] = complex(h[i*ldh+j], 0) if i == j { h1[i*n+j] -= complex(sr1, si1) } } } // First column of H - s2*I. h2 := make([]complex128, n) for i := 0; i < n; i++ { h2[i] = complex(h[i*ldh], 0) } h2[0] -= complex(sr2, si2) wantv := make([]float64, n) // Multiply (H-s1*I)*(H-s2*I) to get a tentative // wantv. for i := 0; i < n; i++ { for j := 0; j < n; j++ { wantv[i] += real(h1[i*n+j] * h2[j]) } } // Get the unknown scale. scale := v[0] / wantv[0] // Compute the actual wantv. floats.Scale(scale, wantv) // The scale must be the same for all elements. if floats.Distance(wantv, v, math.Inf(1)) > 1e-13 { t.Errorf("n = %v, ldh = %v, case = %v: Unexpected value of v: got %v, want %v", n, ldh, cas, v, wantv) } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaqr23.go000066400000000000000000000234761450372207100230370ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlaqr23er interface { Dlaqr23(wantt, wantz bool, n, ktop, kbot, nw int, h []float64, ldh int, iloz, ihiz int, z []float64, ldz int, sr, si []float64, v []float64, ldv int, nh int, t []float64, ldt int, nv int, wv []float64, ldwv int, work []float64, lwork int, recur int) (ns, nd int) } type dlaqr23Test struct { wantt, wantz bool ktop, kbot int nw int h blas64.General iloz, ihiz int evWant []complex128 // Optional slice with known eigenvalues. } func newDlaqr23TestCase(wantt, wantz bool, n, ldh int, rnd *rand.Rand) dlaqr23Test { // Generate the deflation window size. var nw int if n <= 75 { // For small matrices any window size works because they will // always use Dlahrq inside Dlaqr23. nw = rnd.Intn(n) + 1 } else { // For sufficiently large matrices generate a large enough // window to assure that the Dlaqr4 path is taken. nw = 76 + rnd.Intn(n-75) } // Generate a random Hessenberg matrix. h := randomHessenberg(n, ldh, rnd) // Generate the block limits of H on which Dlaqr23 will operate so that // the restriction // 0 <= nw <= kbot-ktop+1 // is satisfied. ktop := rnd.Intn(n - nw + 1) kbot := ktop + nw - 1 kbot += rnd.Intn(n - kbot) // Make the block isolated by zeroing out the sub-diagonal elements. if ktop-1 >= 0 { h.Data[ktop*h.Stride+ktop-1] = 0 } if kbot+1 < n { h.Data[(kbot+1)*h.Stride+kbot] = 0 } // Generate the rows of Z to which transformations will be applied if // wantz is true. iloz := rnd.Intn(ktop + 1) ihiz := kbot + rnd.Intn(n-kbot) return dlaqr23Test{ wantt: wantt, wantz: wantz, ktop: ktop, kbot: kbot, nw: nw, h: h, iloz: iloz, ihiz: ihiz, } } func Dlaqr23Test(t *testing.T, impl Dlaqr23er) { rnd := rand.New(rand.NewSource(1)) // Randomized tests. for _, wantt := range []bool{true, false} { for _, wantz := range []bool{true, false} { for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 18, 31, 100} { for _, extra := range []int{0, 11} { for cas := 0; cas < 10; cas++ { test := newDlaqr23TestCase(wantt, wantz, n, n+extra, rnd) testDlaqr23(t, impl, test, false, 1, rnd) testDlaqr23(t, impl, test, true, 1, rnd) testDlaqr23(t, impl, test, false, 0, rnd) testDlaqr23(t, impl, test, true, 0, rnd) } } } } } // Tests with n=0. for _, wantt := range []bool{true, false} { for _, wantz := range []bool{true, false} { for _, extra := range []int{0, 1, 11} { test := dlaqr23Test{ wantt: wantt, wantz: wantz, h: randomHessenberg(0, extra, rnd), ktop: 0, kbot: -1, iloz: 0, ihiz: -1, nw: 0, } testDlaqr23(t, impl, test, true, 1, rnd) testDlaqr23(t, impl, test, false, 1, rnd) testDlaqr23(t, impl, test, true, 0, rnd) testDlaqr23(t, impl, test, false, 0, rnd) } } } // Tests with explicit eigenvalues computed by Octave. for _, test := range []dlaqr23Test{ { h: blas64.General{ Rows: 1, Cols: 1, Stride: 1, Data: []float64{7.09965484086874e-1}, }, ktop: 0, kbot: 0, iloz: 0, ihiz: 0, evWant: []complex128{7.09965484086874e-1}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ 0, -1, 1, 0, }, }, ktop: 0, kbot: 1, iloz: 0, ihiz: 1, evWant: []complex128{1i, -1i}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ 6.25219991450918e-1, 8.17510791994361e-1, 3.31218891622294e-1, 1.24103744878131e-1, }, }, ktop: 0, kbot: 1, iloz: 0, ihiz: 1, evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, }, { h: blas64.General{ Rows: 4, Cols: 4, Stride: 4, Data: []float64{ 1, 0, 0, 0, 0, 6.25219991450918e-1, 8.17510791994361e-1, 0, 0, 3.31218891622294e-1, 1.24103744878131e-1, 0, 0, 0, 0, 1, }, }, ktop: 1, kbot: 2, iloz: 0, ihiz: 3, evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, }, { h: blas64.General{ Rows: 2, Cols: 2, Stride: 2, Data: []float64{ -1.1219562276608, 6.85473513349362e-1, -8.19951061145131e-1, 1.93728523178888e-1, }, }, ktop: 0, kbot: 1, iloz: 0, ihiz: 1, evWant: []complex128{ -4.64113852240958e-1 + 3.59580510817350e-1i, -4.64113852240958e-1 - 3.59580510817350e-1i, }, }, { h: blas64.General{ Rows: 5, Cols: 5, Stride: 5, Data: []float64{ 9.57590178533658e-1, -5.10651295522708e-1, 9.24974510015869e-1, -1.30016306879522e-1, 2.92601986926954e-2, -1.08084756637964, 1.77529701001213, -1.36480197632509, 2.23196371219601e-1, 1.12912853063308e-1, 0, -8.44075612174676e-1, 1.067867614486, -2.55782915176399e-1, -2.00598563137468e-1, 0, 0, -5.67097237165410e-1, 2.07205057427341e-1, 6.54998340743380e-1, 0, 0, 0, -1.89441413886041e-1, -4.18125416021786e-1, }, }, ktop: 0, kbot: 4, iloz: 0, ihiz: 4, evWant: []complex128{ 2.94393309555622, 4.97029793606701e-1 + 3.63041654992384e-1i, 4.97029793606701e-1 - 3.63041654992384e-1i, -1.74079119166145e-1 + 2.01570009462092e-1i, -1.74079119166145e-1 - 2.01570009462092e-1i, }, }, } { test.wantt = true test.wantz = true test.nw = test.kbot - test.ktop + 1 testDlaqr23(t, impl, test, true, 1, rnd) testDlaqr23(t, impl, test, false, 1, rnd) testDlaqr23(t, impl, test, true, 0, rnd) testDlaqr23(t, impl, test, false, 0, rnd) } } func testDlaqr23(t *testing.T, impl Dlaqr23er, test dlaqr23Test, opt bool, recur int, rnd *rand.Rand) { const tol = 1e-14 // Clone the test matrix to avoid modifying test data. h := cloneGeneral(test.h) // Extract test values to simplify notation. n := h.Cols extra := h.Stride - h.Cols wantt := test.wantt wantz := test.wantz ktop := test.ktop kbot := test.kbot nw := test.nw iloz := test.iloz ihiz := test.ihiz var z, zCopy blas64.General if wantz { // Using the identity matrix for Z is the easiest way to check // that the transformation accumulated into it by Dlaqr23 is orthogonal. z = eye(n, n+extra) zCopy = cloneGeneral(z) } // Allocate slices for storing the converged eigenvalues, initially // filled with NaN. sr := nanSlice(kbot + 1) si := nanSlice(kbot + 1) // Allocate work matrices. v := randomGeneral(nw, nw, nw+extra, rnd) var nh int if nw > 0 { nh = nw + rnd.Intn(nw) // nh must be at least nw. } tmat := randomGeneral(nw, nh, nh+extra, rnd) var nv int if nw > 0 { nv = rnd.Intn(nw) + 1 } wv := randomGeneral(nv, nw, nw+extra, rnd) var work []float64 if opt { // Allocate work slice with optimal length. work = nanSlice(1) impl.Dlaqr23(wantt, wantz, n, ktop, kbot, nw, h.Data, h.Stride, iloz, ihiz, z.Data, max(1, z.Stride), sr, si, v.Data, v.Stride, tmat.Cols, tmat.Data, tmat.Stride, wv.Rows, wv.Data, wv.Stride, work, -1, recur) work = nanSlice(int(work[0])) } else { // Allocate work slice with minimum length. work = nanSlice(max(1, 2*nw)) } ns, nd := impl.Dlaqr23(wantt, wantz, n, ktop, kbot, nw, h.Data, h.Stride, iloz, ihiz, z.Data, max(1, z.Stride), sr, si, v.Data, v.Stride, tmat.Cols, tmat.Data, tmat.Stride, wv.Rows, wv.Data, wv.Stride, work, len(work), recur) prefix := fmt.Sprintf("Case wantt=%v, wantz=%v, n=%v, ktop=%v, kbot=%v, nw=%v, iloz=%v, ihiz=%v, extra=%v", wantt, wantz, n, ktop, kbot, nw, iloz, ihiz, extra) if !generalOutsideAllNaN(h) { t.Errorf("%v: out-of-range write to H\n%v", prefix, h.Data) } if !generalOutsideAllNaN(z) { t.Errorf("%v: out-of-range write to Z\n%v", prefix, z.Data) } if !generalOutsideAllNaN(v) { t.Errorf("%v: out-of-range write to V\n%v", prefix, v.Data) } if !generalOutsideAllNaN(tmat) { t.Errorf("%v: out-of-range write to T\n%v", prefix, tmat.Data) } if !generalOutsideAllNaN(wv) { t.Errorf("%v: out-of-range write to WV\n%v", prefix, wv.Data) } if !isAllNaN(sr[:kbot-nd-ns+1]) || !isAllNaN(sr[kbot+1:]) { t.Errorf("%v: out-of-range write to sr", prefix) } if !isAllNaN(si[:kbot-nd-ns+1]) || !isAllNaN(si[kbot+1:]) { t.Errorf("%v: out-of-range write to si", prefix) } if !isUpperHessenberg(h) { t.Errorf("%v: H is not upper Hessenberg", prefix) } if test.evWant != nil { // Check all converged eigenvalues against known eigenvalues. for i := kbot - nd + 1; i <= kbot; i++ { ev := complex(sr[i], si[i]) found, _ := containsComplex(test.evWant, ev, tol) if !found { t.Errorf("%v: unexpected eigenvalue %v", prefix, ev) } } } // Checks below need the matrix Z. if !wantz { return } // Test whether the matrix Z was modified outside the given block. var zmod bool for i := 0; i < n; i++ { for j := 0; j < n; j++ { if z.Data[i*z.Stride+j] == zCopy.Data[i*zCopy.Stride+j] { continue } if i < iloz || ihiz < i || j < kbot-nw+1 || kbot < j { zmod = true } } } if zmod { t.Errorf("%v: unexpected modification of Z", prefix) } // Check that Z is orthogonal. if resid := residualOrthogonal(z, false); resid > tol*float64(n) { t.Errorf("Case %v: Z is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } if wantt { // Check that |Zᵀ*HOrig*Z - H| is small where H is the result from Dlaqr23. hz := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, test.h, z, 0, hz) r := cloneGeneral(h) blas64.Gemm(blas.Trans, blas.NoTrans, 1, z, hz, -1, r) resid := dlange(lapack.MaxColumnSum, r.Rows, r.Cols, r.Data, r.Stride) if resid > tol*float64(n) { t.Errorf("%v: |Zᵀ*(initial H)*Z - (final H)|=%v, want<=%v", prefix, resid, tol*float64(n)) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaqr5.go000066400000000000000000000071021450372207100227430ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlaqr5er interface { Dlaqr5(wantt, wantz bool, kacc22 int, n, ktop, kbot, nshfts int, sr, si []float64, h []float64, ldh int, iloz, ihiz int, z []float64, ldz int, v []float64, ldv int, u []float64, ldu int, nh int, wh []float64, ldwh int, nv int, wv []float64, ldwv int) } func Dlaqr5Test(t *testing.T, impl Dlaqr5er) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 30} { for _, extra := range []int{0, 1, 20} { for _, kacc22 := range []int{0, 1, 2} { for cas := 0; cas < 100; cas++ { testDlaqr5(t, impl, n, extra, kacc22, rnd) } } } } } func testDlaqr5(t *testing.T, impl Dlaqr5er, n, extra, kacc22 int, rnd *rand.Rand) { const tol = 1e-14 wantt := true wantz := true nshfts := 2 * n sr := make([]float64, nshfts) si := make([]float64, nshfts) for i := 0; i < nshfts; { if i == nshfts-1 || rnd.Float64() < 0.5 { re := rnd.NormFloat64() sr[i], si[i] = re, 0 i++ continue } re := rnd.NormFloat64() im := rnd.NormFloat64() sr[i], sr[i+1] = re, re si[i], si[i+1] = im, -im i += 2 } ktop := rnd.Intn(n) kbot := rnd.Intn(n) if kbot < ktop { ktop, kbot = kbot, ktop } v := randomGeneral(nshfts/2, 3, 3+extra, rnd) u := randomGeneral(2*nshfts, 2*nshfts, 2*nshfts+extra, rnd) nh := n wh := randomGeneral(2*nshfts, n, n+extra, rnd) nv := n wv := randomGeneral(n, 2*nshfts, 2*nshfts+extra, rnd) h := randomHessenberg(n, n+extra, rnd) if ktop > 0 { h.Data[ktop*h.Stride+ktop-1] = 0 } if kbot < n-1 { h.Data[(kbot+1)*h.Stride+kbot] = 0 } hCopy := h hCopy.Data = make([]float64, len(h.Data)) copy(hCopy.Data, h.Data) z := eye(n, n+extra) impl.Dlaqr5(wantt, wantz, kacc22, n, ktop, kbot, nshfts, sr, si, h.Data, h.Stride, 0, n-1, z.Data, z.Stride, v.Data, v.Stride, u.Data, u.Stride, nv, wv.Data, wv.Stride, nh, wh.Data, wh.Stride) prefix := fmt.Sprintf("Case n=%v, extra=%v, kacc22=%v", n, extra, kacc22) if !generalOutsideAllNaN(h) { t.Errorf("%v: out-of-range write to H\n%v", prefix, h.Data) } if !generalOutsideAllNaN(z) { t.Errorf("%v: out-of-range write to Z\n%v", prefix, z.Data) } if !generalOutsideAllNaN(u) { t.Errorf("%v: out-of-range write to U\n%v", prefix, u.Data) } if !generalOutsideAllNaN(v) { t.Errorf("%v: out-of-range write to V\n%v", prefix, v.Data) } if !generalOutsideAllNaN(wh) { t.Errorf("%v: out-of-range write to WH\n%v", prefix, wh.Data) } if !generalOutsideAllNaN(wv) { t.Errorf("%v: out-of-range write to WV\n%v", prefix, wv.Data) } for i := 0; i < n; i++ { for j := 0; j < i-1; j++ { if h.Data[i*h.Stride+j] != 0 { t.Errorf("%v: H is not Hessenberg, H[%v,%v]!=0", prefix, i, j) } } } // Check that Z is orthogonal. if resid := residualOrthogonal(z, false); resid > tol*float64(n) { t.Errorf("Case %v: Z is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } // Check that |Zᵀ*HOrig*Z - H| is small where H is the result from Dlaqr5. hz := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hCopy, z, 0, hz) zhz := cloneGeneral(h) blas64.Gemm(blas.Trans, blas.NoTrans, 1, z, hz, -1, zhz) resid := dlange(lapack.MaxColumnSum, n, n, zhz.Data, zhz.Stride) if resid > tol*float64(n) { t.Errorf("%v: |Zᵀ*HOrig*Z - H|=%v, want<=%v", prefix, resid, tol*float64(n)) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaqr5_bench.go000066400000000000000000000037021450372207100241040ustar00rootroot00000000000000// Copyright ©2023 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" ) func Dlaqr5Benchmark(b *testing.B, impl Dlaqr5er) { const ( random = iota iplusj laplacian ) rnd := rand.New(rand.NewSource(1)) for _, typ := range []int{random, iplusj, laplacian} { for _, n := range []int{100, 200, 500, 1000} { h := zeros(n, n, n) var name string switch typ { case random: name = fmt.Sprintf("HessenbergRandom%d", n) h = randomHessenberg(n, n, rnd) case iplusj: name = fmt.Sprintf("HessenbergIPlusJ%d", n) for i := 0; i < n; i++ { for j := max(0, i-1); j < n; j++ { h.Data[i*h.Stride+j] = float64(i + j + 2) } } case laplacian: name = fmt.Sprintf("Laplacian%d", n) for i := 0; i < n; i++ { if i > 0 { h.Data[i*h.Stride+i-1] = -1 } h.Data[i*h.Stride+i] = 2 if i < n-1 { h.Data[i*h.Stride+i+1] = -1 } } } hCopy := cloneGeneral(h) nshifts := 2 * n sr := make([]float64, nshifts) si := make([]float64, nshifts) for i := 0; i < nshifts; { if i == nshifts-1 || rnd.Float64() < 0.5 { re := rnd.NormFloat64() sr[i], si[i] = re, 0 i++ continue } re := rnd.NormFloat64() im := rnd.NormFloat64() sr[i], sr[i+1] = re, re si[i], si[i+1] = im, -im i += 2 } v := zeros(nshifts/2, 3, 3) u := zeros(2*nshifts, 2*nshifts, 2*nshifts) nh := n wh := zeros(2*nshifts, n, n) nv := n wv := zeros(n, 2*nshifts, 2*nshifts) z := eye(n, n) b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { copyGeneral(h, hCopy) impl.Dlaqr5(true, true, 1, n, 0, n-1, nshifts, sr, si, h.Data, h.Stride, 0, n-1, z.Data, z.Stride, v.Data, v.Stride, u.Data, u.Stride, nh, wv.Data, wv.Stride, nv, wh.Data, wh.Stride) } }) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlarf.go000066400000000000000000000076301450372207100226510ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlarfer interface { Dlarf(side blas.Side, m, n int, v []float64, incv int, tau float64, c []float64, ldc int, work []float64) } func DlarfTest(t *testing.T, impl Dlarfer) { for _, side := range []blas.Side{blas.Left, blas.Right} { name := sideToString(side) t.Run(name, func(t *testing.T) { runDlarfTest(t, impl, side) }) } } func runDlarfTest(t *testing.T, impl Dlarfer, side blas.Side) { rnd := rand.New(rand.NewSource(1)) for _, m := range []int{0, 1, 2, 3, 4, 5, 10} { for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for _, incv := range []int{1, 4} { for _, ldc := range []int{max(1, n), n + 3} { for _, nnzv := range []int{0, 1, 2} { for _, nnzc := range []int{0, 1, 2} { for _, tau := range []float64{0, rnd.NormFloat64()} { dlarfTest(t, impl, rnd, side, m, n, incv, ldc, nnzv, nnzc, tau) } } } } } } } } func dlarfTest(t *testing.T, impl Dlarfer, rnd *rand.Rand, side blas.Side, m, n, incv, ldc, nnzv, nnzc int, tau float64) { const tol = 1e-14 c := make([]float64, m*ldc) for i := range c { c[i] = rnd.NormFloat64() } switch nnzc { case 0: // Zero out all of C. for i := 0; i < m; i++ { for j := 0; j < n; j++ { c[i*ldc+j] = 0 } } case 1: // Zero out right or bottom half of C. if side == blas.Left { for i := 0; i < m; i++ { for j := n / 2; j < n; j++ { c[i*ldc+j] = 0 } } } else { for i := m / 2; i < m; i++ { for j := 0; j < n; j++ { c[i*ldc+j] = 0 } } } default: // Leave C with random content. } cCopy := make([]float64, len(c)) copy(cCopy, c) var work []float64 if side == blas.Left { work = make([]float64, n) } else { work = make([]float64, m) } vlen := n if side == blas.Left { vlen = m } vlen = max(1, vlen) v := make([]float64, 1+(vlen-1)*incv) for i := range v { v[i] = rnd.NormFloat64() } switch nnzv { case 0: // Zero out all of v. for i := 0; i < vlen; i++ { v[i*incv] = 0 } case 1: // Zero out half of v. for i := vlen / 2; i < vlen; i++ { v[i*incv] = 0 } default: // Leave v with random content. } vCopy := make([]float64, len(v)) copy(vCopy, v) impl.Dlarf(side, m, n, v, incv, tau, c, ldc, work) got := c name := fmt.Sprintf("m=%d,n=%d,incv=%d,tau=%f,ldc=%d", m, n, incv, tau, ldc) if !floats.Equal(v, vCopy) { t.Errorf("%v: unexpected modification of v", name) } if tau == 0 && !floats.Equal(got, cCopy) { t.Errorf("%v: unexpected modification of C", name) } if m == 0 || n == 0 || tau == 0 { return } bi := blas64.Implementation() want := make([]float64, len(cCopy)) if side == blas.Left { // Compute want = (I - tau * v * vᵀ) * C // vtc = -tau * vᵀ * C = -tau * Cᵀ * v vtc := make([]float64, n) bi.Dgemv(blas.Trans, m, n, -tau, cCopy, ldc, v, incv, 0, vtc, 1) // want = C + v * vtcᵀ for i := 0; i < m; i++ { for j := 0; j < n; j++ { want[i*ldc+j] = cCopy[i*ldc+j] + v[i*incv]*vtc[j] } } } else { // Compute want = C * (I - tau * v * vᵀ) // cv = -tau * C * v cv := make([]float64, m) bi.Dgemv(blas.NoTrans, m, n, -tau, cCopy, ldc, v, incv, 0, cv, 1) // want = C + cv * vᵀ for i := 0; i < m; i++ { for j := 0; j < n; j++ { want[i*ldc+j] = cCopy[i*ldc+j] + cv[i]*v[j*incv] } } } diff := make([]float64, m*n) for i := 0; i < m; i++ { for j := 0; j < n; j++ { diff[i*n+j] = got[i*ldc+j] - want[i*ldc+j] } } resid := dlange(lapack.MaxColumnSum, m, n, diff, n) if resid > tol*float64(max(m, n)) { t.Errorf("%v: unexpected result; resid=%v, want<=%v", name, resid, tol*float64(max(m, n))) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlarfb.go000066400000000000000000000105701450372207100230100ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlarfber interface { Dlarfter Dlarfb(side blas.Side, trans blas.Transpose, direct lapack.Direct, store lapack.StoreV, m, n, k int, v []float64, ldv int, t []float64, ldt int, c []float64, ldc int, work []float64, ldwork int) } func DlarfbTest(t *testing.T, impl Dlarfber) { rnd := rand.New(rand.NewSource(1)) for _, store := range []lapack.StoreV{lapack.ColumnWise, lapack.RowWise} { for _, direct := range []lapack.Direct{lapack.Forward, lapack.Backward} { for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.Trans, blas.NoTrans} { for cas, test := range []struct { ma, na, cdim, lda, ldt, ldc int }{ {6, 6, 6, 0, 0, 0}, {6, 8, 10, 0, 0, 0}, {6, 10, 8, 0, 0, 0}, {8, 6, 10, 0, 0, 0}, {8, 10, 6, 0, 0, 0}, {10, 6, 8, 0, 0, 0}, {10, 8, 6, 0, 0, 0}, {6, 6, 6, 12, 15, 30}, {6, 8, 10, 12, 15, 30}, {6, 10, 8, 12, 15, 30}, {8, 6, 10, 12, 15, 30}, {8, 10, 6, 12, 15, 30}, {10, 6, 8, 12, 15, 30}, {10, 8, 6, 12, 15, 30}, {6, 6, 6, 15, 12, 30}, {6, 8, 10, 15, 12, 30}, {6, 10, 8, 15, 12, 30}, {8, 6, 10, 15, 12, 30}, {8, 10, 6, 15, 12, 30}, {10, 6, 8, 15, 12, 30}, {10, 8, 6, 15, 12, 30}, } { // Generate a matrix for QR ma := test.ma na := test.na lda := test.lda if lda == 0 { lda = na } a := make([]float64, ma*lda) for i := 0; i < ma; i++ { for j := 0; j < lda; j++ { a[i*lda+j] = rnd.Float64() } } k := min(ma, na) // H is always ma x ma var m, n, rowsWork int switch { default: panic("not implemented") case side == blas.Left: m = test.ma n = test.cdim rowsWork = n case side == blas.Right: m = test.cdim n = test.ma rowsWork = m } // Use dgeqr2 to find the v vectors tau := make([]float64, na) work := make([]float64, na) impl.Dgeqr2(ma, k, a, lda, tau, work) // Correct the v vectors based on the direct and store vMatTmp := extractVMat(ma, na, a, lda, lapack.Forward, lapack.ColumnWise) vMat := constructVMat(vMatTmp, store, direct) v := vMat.Data ldv := vMat.Stride // Use dlarft to find the t vector ldt := test.ldt if ldt == 0 { ldt = k } tm := make([]float64, k*ldt) impl.Dlarft(direct, store, ma, k, v, ldv, tau, tm, ldt) // Generate c matrix ldc := test.ldc if ldc == 0 { ldc = n } c := make([]float64, m*ldc) for i := 0; i < m; i++ { for j := 0; j < ldc; j++ { c[i*ldc+j] = rnd.Float64() } } cCopy := make([]float64, len(c)) copy(cCopy, c) ldwork := k work = make([]float64, rowsWork*k) // Call Dlarfb with this information impl.Dlarfb(side, trans, direct, store, m, n, k, v, ldv, tm, ldt, c, ldc, work, ldwork) h := constructH(tau, vMat, store, direct) cMat := blas64.General{ Rows: m, Cols: n, Stride: ldc, Data: make([]float64, m*ldc), } copy(cMat.Data, cCopy) ans := blas64.General{ Rows: m, Cols: n, Stride: ldc, Data: make([]float64, m*ldc), } copy(ans.Data, cMat.Data) switch { default: panic("not implemented") case side == blas.Left && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, cMat, 0, ans) case side == blas.Left && trans == blas.Trans: blas64.Gemm(blas.Trans, blas.NoTrans, 1, h, cMat, 0, ans) case side == blas.Right && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, cMat, h, 0, ans) case side == blas.Right && trans == blas.Trans: blas64.Gemm(blas.NoTrans, blas.Trans, 1, cMat, h, 0, ans) } if !floats.EqualApprox(ans.Data, c, 1e-14) { t.Errorf("Cas %v mismatch. Want %v, got %v.", cas, ans.Data, c) } } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlarfg.go000066400000000000000000000047701450372207100230220ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dlarfger interface { Dlarfg(n int, alpha float64, x []float64, incX int) (beta, tau float64) } func DlarfgTest(t *testing.T, impl Dlarfger) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for i, test := range []struct { alpha float64 n int x []float64 }{ { alpha: 4, n: 3, }, { alpha: -2, n: 3, }, { alpha: 0, n: 3, }, { alpha: 1, n: 1, }, { alpha: 1, n: 4, x: []float64{4, 5, 6}, }, { alpha: 1, n: 4, x: []float64{0, 0, 0}, }, { alpha: dlamchS, n: 4, x: []float64{dlamchS, dlamchS, dlamchS}, }, } { n := test.n incX := 1 var x []float64 if test.x == nil { x = make([]float64, n-1) for i := range x { x[i] = rnd.Float64() } } else { if len(test.x) != n-1 { panic("bad test") } x = make([]float64, n-1) copy(x, test.x) } xcopy := make([]float64, n-1) copy(xcopy, x) alpha := test.alpha beta, tau := impl.Dlarfg(n, alpha, x, incX) // Verify the returns and the values in v. Construct h and perform // the explicit multiplication. h := make([]float64, n*n) for i := 0; i < n; i++ { h[i*n+i] = 1 } hmat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: h, } v := make([]float64, n) copy(v[1:], x) v[0] = 1 vVec := blas64.Vector{ Inc: 1, Data: v, } blas64.Ger(-tau, vVec, vVec, hmat) eye := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } blas64.Gemm(blas.Trans, blas.NoTrans, 1, hmat, hmat, 0, eye) dist := distFromIdentity(n, eye.Data, n) if dist > tol { t.Errorf("Hᵀ * H is not close to I, dist=%v", dist) } xVec := blas64.Vector{ Inc: 1, Data: make([]float64, n), } xVec.Data[0] = test.alpha copy(xVec.Data[1:], xcopy) ans := make([]float64, n) ansVec := blas64.Vector{ Inc: 1, Data: ans, } blas64.Gemv(blas.NoTrans, 1, hmat, xVec, 0, ansVec) if math.Abs(ans[0]-beta) > tol { t.Errorf("Case %v, beta mismatch. Want %v, got %v", i, ans[0], beta) } if floats.Norm(ans[1:n], math.Inf(1)) > tol { t.Errorf("Case %v, nonzero answer %v", i, ans[1:n]) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlarft.go000066400000000000000000000103231450372207100230260ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlarfter interface { Dgeqr2er Dlarft(direct lapack.Direct, store lapack.StoreV, n, k int, v []float64, ldv int, tau []float64, t []float64, ldt int) } func DlarftTest(t *testing.T, impl Dlarfter) { rnd := rand.New(rand.NewSource(1)) for _, store := range []lapack.StoreV{lapack.ColumnWise, lapack.RowWise} { for _, direct := range []lapack.Direct{lapack.Forward, lapack.Backward} { for _, test := range []struct { m, n, ldv, ldt int }{ {6, 6, 0, 0}, {8, 6, 0, 0}, {6, 8, 0, 0}, {6, 6, 10, 15}, {8, 6, 10, 15}, {6, 8, 10, 15}, {6, 6, 15, 10}, {8, 6, 15, 10}, {6, 8, 15, 10}, } { // Generate a matrix m := test.m n := test.n lda := n if lda == 0 { lda = n } a := make([]float64, m*lda) for i := 0; i < m; i++ { for j := 0; j < lda; j++ { a[i*lda+j] = rnd.Float64() } } // Use dgeqr2 to find the v vectors tau := make([]float64, n) work := make([]float64, n) impl.Dgeqr2(m, n, a, lda, tau, work) // Construct H using these answers vMatTmp := extractVMat(m, n, a, lda, lapack.Forward, lapack.ColumnWise) vMat := constructVMat(vMatTmp, store, direct) v := vMat.Data ldv := vMat.Stride h := constructH(tau, vMat, store, direct) k := min(m, n) ldt := test.ldt if ldt == 0 { ldt = k } // Find T from the actual function tm := make([]float64, k*ldt) for i := range tm { tm[i] = 100 + rnd.Float64() } // The v data has been put into a. impl.Dlarft(direct, store, m, k, v, ldv, tau, tm, ldt) tData := make([]float64, len(tm)) copy(tData, tm) if direct == lapack.Forward { // Zero out the lower triangular portion. for i := 0; i < k; i++ { for j := 0; j < i; j++ { tData[i*ldt+j] = 0 } } } else { // Zero out the upper triangular portion. for i := 0; i < k; i++ { for j := i + 1; j < k; j++ { tData[i*ldt+j] = 0 } } } T := blas64.General{ Rows: k, Cols: k, Stride: ldt, Data: tData, } vMatT := blas64.General{ Rows: vMat.Cols, Cols: vMat.Rows, Stride: vMat.Rows, Data: make([]float64, vMat.Cols*vMat.Rows), } for i := 0; i < vMat.Rows; i++ { for j := 0; j < vMat.Cols; j++ { vMatT.Data[j*vMatT.Stride+i] = vMat.Data[i*vMat.Stride+j] } } var comp blas64.General if store == lapack.ColumnWise { // H = I - V * T * Vᵀ tmp := blas64.General{ Rows: T.Rows, Cols: vMatT.Cols, Stride: vMatT.Cols, Data: make([]float64, T.Rows*vMatT.Cols), } // T * Vᵀ blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, T, vMatT, 0, tmp) comp = blas64.General{ Rows: vMat.Rows, Cols: tmp.Cols, Stride: tmp.Cols, Data: make([]float64, vMat.Rows*tmp.Cols), } // V * (T * Vᵀ) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, vMat, tmp, 0, comp) } else { // H = I - Vᵀ * T * V tmp := blas64.General{ Rows: T.Rows, Cols: vMat.Cols, Stride: vMat.Cols, Data: make([]float64, T.Rows*vMat.Cols), } // T * V blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, T, vMat, 0, tmp) comp = blas64.General{ Rows: vMatT.Rows, Cols: tmp.Cols, Stride: tmp.Cols, Data: make([]float64, vMatT.Rows*tmp.Cols), } // Vᵀ * (T * V) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, vMatT, tmp, 0, comp) } // I - Vᵀ * T * V for i := 0; i < comp.Rows; i++ { for j := 0; j < comp.Cols; j++ { comp.Data[i*m+j] *= -1 if i == j { comp.Data[i*m+j] += 1 } } } if !floats.EqualApprox(comp.Data, h.Data, 1e-14) { t.Errorf("T does not construct proper H. Store = %v, Direct = %v.\nWant %v\ngot %v.", string(store), string(direct), h.Data, comp.Data) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlarfx.go000066400000000000000000000043251450372207100230370ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlarfxer interface { Dlarfx(side blas.Side, m, n int, v []float64, tau float64, c []float64, ldc int, work []float64) } func DlarfxTest(t *testing.T, impl Dlarfxer) { rnd := rand.New(rand.NewSource(1)) for _, side := range []blas.Side{blas.Right, blas.Left} { // For m and n greater than 10 we are testing Dlarf, so avoid unnecessary work. for m := 1; m < 12; m++ { for n := 1; n < 12; n++ { for _, extra := range []int{0, 1, 11} { for cas := 0; cas < 10; cas++ { testDlarfx(t, impl, side, m, n, extra, rnd) } } } } } } func testDlarfx(t *testing.T, impl Dlarfxer, side blas.Side, m, n, extra int, rnd *rand.Rand) { const tol = 1e-13 // Generate random input data. var v []float64 if side == blas.Left { v = randomSlice(m, rnd) } else { v = randomSlice(n, rnd) } tau := rnd.NormFloat64() ldc := n + extra c := randomGeneral(m, n, ldc, rnd) // Compute the matrix H explicitly as H := I - tau * v * vᵀ. var h blas64.General if side == blas.Left { h = eye(m, m+extra) } else { h = eye(n, n+extra) } blas64.Ger(-tau, blas64.Vector{Inc: 1, Data: v}, blas64.Vector{Inc: 1, Data: v}, h) // Compute the product H * C or C * H explicitly. cWant := nanGeneral(m, n, ldc) if side == blas.Left { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, c, 0, cWant) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, c, h, 0, cWant) } var work []float64 if h.Rows > 10 { // Allocate work only if H has order > 10. if side == blas.Left { work = make([]float64, n) } else { work = make([]float64, m) } } impl.Dlarfx(side, m, n, v, tau, c.Data, c.Stride, work) prefix := fmt.Sprintf("Case side=%c, m=%v, n=%v, extra=%v", side, m, n, extra) // Check any invalid modifications of c. if !generalOutsideAllNaN(c) { t.Errorf("%v: out-of-range write to C\n%v", prefix, c.Data) } if !equalApproxGeneral(c, cWant, tol) { t.Errorf("%v: unexpected C\n%v", prefix, c.Data) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlartg.go000066400000000000000000000040351450372207100230320ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "math" "testing" ) type Dlartger interface { Dlartg(f, g float64) (cs, sn, r float64) } func DlartgTest(t *testing.T, impl Dlartger) { const tol = 20 * ulp values := []float64{ -safmax, -1 / ulp, -1, -1.0 / 3, -ulp, -safmin, 0, safmin, ulp, 1.0 / 3, 1, 1 / ulp, safmax, math.Inf(-1), math.Inf(1), math.NaN(), } for _, f := range values { for _, g := range values { name := fmt.Sprintf("Case f=%v,g=%v", f, g) // Generate a plane rotation so that // [ cs sn] * [f] = [r] // [-sn cs] [g] = [0] // where cs*cs + sn*sn = 1. cs, sn, r := impl.Dlartg(f, g) switch { case math.IsNaN(f) || math.IsNaN(g): if !math.IsNaN(r) { t.Errorf("%v: unexpected r=%v; want NaN", name, r) } case math.IsInf(f, 0) || math.IsInf(g, 0): if !math.IsNaN(r) && !math.IsInf(r, 0) { t.Errorf("%v: unexpected r=%v; want NaN or Inf", name, r) } default: d := math.Max(math.Abs(f), math.Abs(g)) d = math.Min(math.Max(safmin, d), safmax) fs := f / d gs := g / d rs := r / d // Check that cs*f + sn*g = r. rnorm := math.Abs(rs) if rnorm == 0 { rnorm = math.Max(math.Abs(fs), math.Abs(gs)) if rnorm == 0 { rnorm = 1 } } resid := math.Abs(rs-(cs*fs+sn*gs)) / rnorm if resid > tol { t.Errorf("%v: cs*f + sn*g != r; resid=%v", name, resid) } // Check that -sn*f + cs*g = 0. resid = math.Abs(-sn*fs + cs*gs) if resid > tol { t.Errorf("%v: -sn*f + cs*g != 0; resid=%v", name, resid) } // Check that cs*cs + sn*sn = 1. resid = math.Abs(1 - (cs*cs + sn*sn)) if resid > tol { t.Errorf("%v: cs*cs + sn*sn != 1; resid=%v", name, resid) } // Check that cs is non-negative. if math.Abs(f) > math.Abs(g) && cs < 0 { t.Errorf("%v: cs is negative; cs=%v", name, cs) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlas2.go000066400000000000000000000017611450372207100225650ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" ) type Dlas2er interface { Dlas2(f, g, h float64) (min, max float64) } func Dlas2Test(t *testing.T, impl Dlas2er) { for i, test := range []struct { f, g, h, ssmin, ssmax float64 }{ // Singular values computed from Octave. {10, 30, 12, 3.567778859365365, 33.634371616111189}, {10, 30, -12, 3.567778859365365, 33.634371616111189}, {2, 30, -12, 0.741557056404952, 32.364333658088754}, {-2, 5, 12, 1.842864429909778, 13.023204317408728}, } { ssmin, ssmax := impl.Dlas2(test.f, test.g, test.h) if math.Abs(ssmin-test.ssmin) > 1e-12 { t.Errorf("Case %d, minimal singular value mismatch. Want %v, got %v", i, test.ssmin, ssmin) } if math.Abs(ssmax-test.ssmax) > 1e-12 { t.Errorf("Case %d, minimal singular value mismatch. Want %v, got %v", i, test.ssmin, ssmin) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlascl.go000066400000000000000000000056051450372207100230230ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/lapack" ) type Dlascler interface { Dlascl(kind lapack.MatrixType, kl, ku int, cfrom, cto float64, m, n int, a []float64, lda int) } func DlasclTest(t *testing.T, impl Dlascler) { const tol = 1e-15 rnd := rand.New(rand.NewSource(1)) for ti, test := range []struct { m, n int }{ {0, 0}, {1, 1}, {1, 10}, {10, 1}, {2, 2}, {2, 11}, {11, 2}, {3, 3}, {3, 11}, {11, 3}, {11, 11}, {11, 100}, {100, 11}, } { m := test.m n := test.n for _, extra := range []int{0, 11} { for _, kind := range []lapack.MatrixType{lapack.General, lapack.UpperTri, lapack.LowerTri} { a := randomGeneral(m, n, n+extra, rnd) aCopy := cloneGeneral(a) cfrom := rnd.NormFloat64() cto := rnd.NormFloat64() scale := cto / cfrom impl.Dlascl(kind, -1, -1, cfrom, cto, m, n, a.Data, a.Stride) prefix := fmt.Sprintf("Case #%v: kind=%v,m=%v,n=%v,extra=%v", ti, kind, m, n, extra) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A", prefix) } switch kind { case lapack.UpperTri: var mod bool loopLower: for i := 0; i < m; i++ { for j := 0; j < min(i, n); j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { mod = true break loopLower } } } if mod { t.Errorf("%v: unexpected modification in lower triangle of A", prefix) } case lapack.LowerTri: var mod bool loopUpper: for i := 0; i < m; i++ { for j := i + 1; j < n; j++ { if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { mod = true break loopUpper } } } if mod { t.Errorf("%v: unexpected modification in upper triangle of A", prefix) } } var resid float64 switch kind { case lapack.General: for i := 0; i < m; i++ { for j := 0; j < n; j++ { want := scale * aCopy.Data[i*aCopy.Stride+j] got := a.Data[i*a.Stride+j] resid = math.Max(resid, math.Abs(want-got)) } } case lapack.UpperTri: for i := 0; i < m; i++ { for j := i; j < n; j++ { want := scale * aCopy.Data[i*aCopy.Stride+j] got := a.Data[i*a.Stride+j] resid = math.Max(resid, math.Abs(want-got)) } } case lapack.LowerTri: for i := 0; i < m; i++ { for j := 0; j <= min(i, n-1); j++ { want := scale * aCopy.Data[i*aCopy.Stride+j] got := a.Data[i*a.Stride+j] resid = math.Max(resid, math.Abs(want-got)) } } } if resid > tol*float64(max(m, n)) { t.Errorf("%v: unexpected result; residual=%v, want<=%v", prefix, resid, tol*float64(max(m, n))) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaset.go000066400000000000000000000033211450372207100230260ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Dlaseter interface { Dlaset(uplo blas.Uplo, m, n int, alpha, beta float64, a []float64, lda int) } func DlasetTest(t *testing.T, impl Dlaseter) { rnd := rand.New(rand.NewSource(1)) for ti, test := range []struct { m, n int }{ {0, 0}, {1, 1}, {1, 10}, {10, 1}, {2, 2}, {2, 10}, {10, 2}, {11, 11}, {11, 100}, {100, 11}, } { m := test.m n := test.n for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower, blas.All} { for _, extra := range []int{0, 10} { a := randomGeneral(m, n, n+extra, rnd) alpha := 1.0 beta := 2.0 impl.Dlaset(uplo, m, n, alpha, beta, a.Data, a.Stride) prefix := fmt.Sprintf("Case #%v: m=%v,n=%v,uplo=%c,extra=%v", ti, m, n, uplo, extra) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A", prefix) } for i := 0; i < min(m, n); i++ { if a.Data[i*a.Stride+i] != beta { t.Errorf("%v: unexpected diagonal of A", prefix) } } if uplo == blas.Upper || uplo == blas.All { for i := 0; i < m; i++ { for j := i + 1; j < n; j++ { if a.Data[i*a.Stride+j] != alpha { t.Errorf("%v: unexpected upper triangle of A", prefix) } } } } if uplo == blas.Lower || uplo == blas.All { for i := 1; i < m; i++ { for j := 0; j < min(i, n); j++ { if a.Data[i*a.Stride+j] != alpha { t.Errorf("%v: unexpected lower triangle of A", prefix) } } } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlasq1.go000066400000000000000000000060341450372207100227430ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dlasq1er interface { Dlasq1(n int, d, e, work []float64) int Dgebrd(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64, lwork int) } func Dlasq1Test(t *testing.T, impl Dlasq1er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 8, 10, 30, 50} { for typ := 0; typ <= 7; typ++ { name := fmt.Sprintf("n=%v,typ=%v", n, typ) // Generate a diagonal matrix D with positive entries. d := make([]float64, n) switch typ { case 0: // The zero matrix. case 1: // The identity matrix. for i := range d { d[i] = 1 } case 2: // A diagonal matrix with evenly spaced entries 1, ..., eps. for i := 0; i < n; i++ { if i == 0 { d[0] = 1 } else { d[i] = 1 - (1-dlamchE)*float64(i)/float64(n-1) } } case 3, 4, 5: // A diagonal matrix with geometrically spaced entries 1, ..., eps. for i := 0; i < n; i++ { if i == 0 { d[0] = 1 } else { d[i] = math.Pow(dlamchE, float64(i)/float64(n-1)) } } switch typ { case 4: // Multiply by SQRT(overflow threshold). floats.Scale(math.Sqrt(1/dlamchS), d) case 5: // Multiply by SQRT(underflow threshold). floats.Scale(math.Sqrt(dlamchS), d) } case 6: // A diagonal matrix with "clustered" entries 1, eps, ..., eps. for i := range d { if i == 0 { d[i] = 1 } else { d[i] = dlamchE } } case 7: // Diagonal matrix with random entries. for i := range d { d[i] = math.Abs(rnd.NormFloat64()) } } dWant := make([]float64, n) copy(dWant, d) sort.Sort(sort.Reverse(sort.Float64Slice(dWant))) // Allocate work slice to the maximum length needed below. work := make([]float64, max(1, 4*n)) // Generate an n×n matrix A by pre- and post-multiplying D with // random orthogonal matrices: // A = U*D*V. lda := max(1, n) a := make([]float64, n*lda) Dlagge(n, n, 0, 0, d, a, lda, rnd, work) // Reduce A to bidiagonal form B represented by the diagonal d and // off-diagonal e. tauQ := make([]float64, n) tauP := make([]float64, n) e := make([]float64, max(0, n-1)) impl.Dgebrd(n, n, a, lda, d, e, tauQ, tauP, work, len(work)) // Compute the singular values of B. for i := range work { work[i] = math.NaN() } info := impl.Dlasq1(n, d, e, work) if info != 0 { t.Fatalf("%v: Dlasq1 returned non-zero info=%v", name, info) } if n == 0 { continue } if !sort.IsSorted(sort.Reverse(sort.Float64Slice(d))) { t.Errorf("%v: singular values not sorted", name) } diff := floats.Distance(d, dWant, math.Inf(1)) if diff > tol*floats.Max(dWant) { t.Errorf("%v: unexpected result; diff=%v", name, diff) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlasq2.go000066400000000000000000000061501450372207100227430ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlasq2er interface { Dlasq2(n int, z []float64) (info int) Dsyev(jobz lapack.EVJob, uplo blas.Uplo, n int, a []float64, lda int, w, work []float64, lwork int) (ok bool) } func Dlasq2Test(t *testing.T, impl Dlasq2er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 25, 50} { for k := 0; k < 10; k++ { for typ := 0; typ <= 2; typ++ { name := fmt.Sprintf("n=%v,typ=%v", n, typ) want := make([]float64, n) z := make([]float64, 4*n) switch typ { case 0: // L is the identity, U has zero diagonal. case 1: // L is the identity, U has random diagonal, and so T is upper triangular. for i := 0; i < n; i++ { z[2*i] = rnd.Float64() want[i] = z[2*i] } sort.Float64s(want) case 2: // Random tridiagonal matrix for i := range z { z[i] = rnd.Float64() } // The slice 'want' is computed below. } zCopy := make([]float64, len(z)) copy(zCopy, z) // Compute the eigenvalues of the symmetric positive definite // tridiagonal matrix associated with the slice z. info := impl.Dlasq2(n, z) if info != 0 { t.Fatalf("%v: Dlasq2 failed", name) } if n == 0 { continue } got := z[:n] if typ == 2 { // Compute the expected result. // Compute the non-symmetric tridiagonal matrix T = L*U where L and // U are represented by the slice z. ldt := n T := make([]float64, n*ldt) for i := 0; i < n; i++ { if i == 0 { T[0] = zCopy[0] } else { T[i*ldt+i] = zCopy[2*i-1] + zCopy[2*i] } if i < n-1 { T[i*ldt+i+1] = 1 T[(i+1)*ldt+i] = zCopy[2*i+1] * zCopy[2*i] } } // Compute the symmetric tridiagonal matrix by applying a similarity // transformation on T: D^{-1}*T*D. See discussion and references in // http://icl.cs.utk.edu/lapack-forum/viewtopic.php?f=5&t=4839 d := make([]float64, n) d[0] = 1 for i := 1; i < n; i++ { d[i] = d[i-1] * T[i*ldt+i-1] / T[(i-1)*ldt+i] } for i, di := range d { d[i] = math.Sqrt(di) } for i := 0; i < n; i++ { // Update only the upper triangle. for j := i; j <= min(i+1, n-1); j++ { T[i*ldt+j] *= d[j] / d[i] } } // Compute the eigenvalues of D^{-1}*T*D by using Dsyev. It's call // tree doesn't include Dlasq2. work := make([]float64, 3*n) ok := impl.Dsyev(lapack.EVNone, blas.Upper, n, T, ldt, want, work, len(work)) if !ok { t.Fatalf("%v: Dsyev failed", name) } } sort.Float64s(got) diff := floats.Distance(got, want, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected eigenvalues; diff=%v\n%v\n%v\n\n", name, diff, got, want) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlasr.go000066400000000000000000000106631450372207100226660ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlasrer interface { Dlasr(side blas.Side, pivot lapack.Pivot, direct lapack.Direct, m, n int, c, s, a []float64, lda int) } func DlasrTest(t *testing.T, impl Dlasrer) { rnd := rand.New(rand.NewSource(1)) for _, side := range []blas.Side{blas.Left, blas.Right} { for _, pivot := range []lapack.Pivot{lapack.Variable, lapack.Top, lapack.Bottom} { for _, direct := range []lapack.Direct{lapack.Forward, lapack.Backward} { for _, test := range []struct { m, n, lda int }{ {5, 5, 0}, {5, 10, 0}, {10, 5, 0}, {5, 5, 20}, {5, 10, 20}, {10, 5, 20}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate n×n matrix A and fill it with random numbers. a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() } // Allocate slices for implicitly // represented rotation matrices. var s, c []float64 if side == blas.Left { s = make([]float64, m-1) c = make([]float64, m-1) } else { s = make([]float64, n-1) c = make([]float64, n-1) } for k := range s { // Generate a random number in [0,2*pi). theta := rnd.Float64() * 2 * math.Pi s[k] = math.Sin(theta) c[k] = math.Cos(theta) } aCopy := make([]float64, len(a)) copy(a, aCopy) // Apply plane a sequence of plane // rotation in s and c to the matrix A. impl.Dlasr(side, pivot, direct, m, n, c, s, a, lda) // Compute a reference solution by multiplying A // by explicitly formed rotation matrix P. pSize := m if side == blas.Right { pSize = n } // Allocate matrix P. p := blas64.General{ Rows: pSize, Cols: pSize, Stride: pSize, Data: make([]float64, pSize*pSize), } // Allocate matrix P_k. pk := blas64.General{ Rows: pSize, Cols: pSize, Stride: pSize, Data: make([]float64, pSize*pSize), } ptmp := blas64.General{ Rows: pSize, Cols: pSize, Stride: pSize, Data: make([]float64, pSize*pSize), } // Initialize P to the identity matrix. for i := 0; i < pSize; i++ { p.Data[i*p.Stride+i] = 1 ptmp.Data[i*p.Stride+i] = 1 } // Iterate over the sequence of plane rotations. for k := range s { // Set P_k to the identity matrix. for i := range p.Data { pk.Data[i] = 0 } for i := 0; i < pSize; i++ { pk.Data[i*p.Stride+i] = 1 } // Set the corresponding elements of P_k. switch pivot { case lapack.Variable: pk.Data[k*p.Stride+k] = c[k] pk.Data[k*p.Stride+k+1] = s[k] pk.Data[(k+1)*p.Stride+k] = -s[k] pk.Data[(k+1)*p.Stride+k+1] = c[k] case lapack.Top: pk.Data[0] = c[k] pk.Data[k+1] = s[k] pk.Data[(k+1)*p.Stride] = -s[k] pk.Data[(k+1)*p.Stride+k+1] = c[k] case lapack.Bottom: pk.Data[(pSize-1-k)*p.Stride+pSize-k-1] = c[k] pk.Data[(pSize-1-k)*p.Stride+pSize-1] = s[k] pk.Data[(pSize-1)*p.Stride+pSize-1-k] = -s[k] pk.Data[(pSize-1)*p.Stride+pSize-1] = c[k] } // Compute P <- P_k * P or P <- P * P_k. if direct == lapack.Forward { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, pk, ptmp, 0, p) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, ptmp, pk, 0, p) } copy(ptmp.Data, p.Data) } aMat := blas64.General{ Rows: m, Cols: n, Stride: lda, Data: make([]float64, m*lda), } copy(a, aCopy) newA := blas64.General{ Rows: m, Cols: n, Stride: lda, Data: make([]float64, m*lda), } // Compute P * A or A * P. if side == blas.Left { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, p, aMat, 0, newA) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aMat, p, 0, newA) } // Compare the result from Dlasr with the reference solution. if !floats.EqualApprox(newA.Data, a, 1e-12) { t.Errorf("A update mismatch") } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlasrt.go000066400000000000000000000035601450372207100230500ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dlasrter interface { Dlasrt(s lapack.Sort, n int, d []float64) } func DlasrtTest(t *testing.T, impl Dlasrter) { for ti, test := range []struct { data []float64 wantInc []float64 wantDec []float64 }{ { data: nil, wantInc: nil, wantDec: nil, }, { data: []float64{}, wantInc: []float64{}, wantDec: []float64{}, }, { data: []float64{1}, wantInc: []float64{1}, wantDec: []float64{1}, }, { data: []float64{1, 2}, wantInc: []float64{1, 2}, wantDec: []float64{2, 1}, }, { data: []float64{1, 2, -3}, wantInc: []float64{-3, 1, 2}, wantDec: []float64{2, 1, -3}, }, { data: []float64{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}, wantInc: []float64{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}, wantDec: []float64{5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5}, }, { data: []float64{5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5}, wantInc: []float64{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}, wantDec: []float64{5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5}, }, { data: []float64{-2, 4, -1, 2, -4, 0, 3, 5, -5, 1, -3}, wantInc: []float64{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}, wantDec: []float64{5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5}, }, } { n := len(test.data) ds := make([]float64, n) copy(ds, test.data) impl.Dlasrt(lapack.SortIncreasing, n, ds) if !floats.Equal(ds, test.wantInc) { t.Errorf("Case #%v: unexpected result of SortIncreasing", ti) } copy(ds, test.data) impl.Dlasrt(lapack.SortDecreasing, n, ds) if !floats.Equal(ds, test.wantDec) { t.Errorf("Case #%v: unexpected result of SortIncreasing", ti) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlassq.go000066400000000000000000000074121450372207100230460ustar00rootroot00000000000000// Copyright ©2019 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dlassqer interface { Dlassq(n int, x []float64, incx int, scale, ssq float64) (float64, float64) } func DlassqTest(t *testing.T, impl Dlassqer) { values := []float64{ 0, 2 * safmin, smlnum, ulp, 1, 1 / ulp, bignum, safmax, math.Inf(1), math.NaN(), } rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 20, 30, 40} { for _, incx := range []int{1, 3} { for cas := 0; cas < 3; cas++ { for _, v0 := range values { if v0 > 1 { v0 *= 0.5 } for _, v1 := range values { if v1 > 1 { v1 = 0.5 * v1 / math.Sqrt(float64(n+1)) } dlassqTest(t, impl, rnd, n, incx, cas, v0, v1) } } } } } } func dlassqTest(t *testing.T, impl Dlassqer, rnd *rand.Rand, n, incx, cas int, v0, v1 float64) { const ( rogue = 1234.5678 tol = 1e-14 ) name := fmt.Sprintf("n=%v,incx=%v,cas=%v,v0=%v,v1=%v", n, incx, cas, v0, v1) // Generate n random values in (-1,1]. work := make([]float64, n) for i := range work { work[i] = 1 - 2*rnd.Float64() } // Compute the sum of squares by an unscaled algorithm. var workssq float64 for _, wi := range work { workssq += wi * wi } // Construct a test (n+1)-vector z as // z[0] = known value // z[1:n+1] = scaling factor * work[:] z := make([]float64, n+1) z[0] = math.Sqrt(v0) for i, wi := range work { z[i+1] = v1 * wi } // Set initial scale and ssq corresponding to z[0]. var scale, ssq float64 switch cas { case 0: scale = 1 ssq = v0 case 1: scale = math.Sqrt(v0) ssq = 1 case 2: if v0 < 1 { scale = 1.0 / 3 ssq = 9 * v0 } else { scale = 3 ssq = v0 / 9 } default: panic("bad cas") } const ( dtsml = 0x1p-511 dtbig = 0x1p486 dssml = 0x1p537 dsbig = 0x1p-538 ) if scale*math.Sqrt(ssq) > dtbig && scale < math.Sqrt(math.SmallestNonzeroFloat64/ulp)/dsbig { // The scaled sum is big but the scale itself is small. return } if scale*math.Sqrt(ssq) < dtsml && scale > math.Sqrt(math.MaxFloat64)/dssml { // The scaled sum is small but the scale itself is big. return } // Compute the expected value of the sum of squares using the (n+1)-vector z. z0 := z[0] var z1n float64 if n >= 1 { z1n = v1 * math.Sqrt(workssq) } zmin := math.Min(z0, z1n) zmax := math.Max(z0, z1n) var nrmWant float64 switch { case math.IsNaN(z0) || math.IsNaN(z1n): nrmWant = math.NaN() case zmin == zmax: nrmWant = math.Sqrt2 * zmax case zmax == 0: nrmWant = 0 default: nrmWant = zmax * math.Sqrt(1+(zmin/zmax)*(zmin/zmax)) } // Allocate input slice for Dlassq and fill it with z[1:]. x := make([]float64, max(0, 1+(n-1)*incx)) for i := range x { x[i] = rogue } for i, zi := range z[1:] { x[i*incx] = zi } xCopy := make([]float64, len(x)) copy(xCopy, x) scaleGot, ssqGot := impl.Dlassq(n, x, incx, scale, ssq) nrmGot := scaleGot * math.Sqrt(ssqGot) if !floats.Same(x, xCopy) { t.Fatalf("%v: unexpected modification of x", name) } // Check the result. switch { case math.IsNaN(nrmGot) || math.IsNaN(nrmWant): if !math.IsNaN(nrmGot) { t.Errorf("%v: expected NaN; got %v", name, nrmGot) } if !math.IsNaN(nrmWant) { t.Errorf("%v: unexpected NaN; want %v", name, nrmWant) } case nrmGot == nrmWant: case nrmWant == 0: if nrmGot > tol { t.Errorf("%v: unexpected result; got %v, want 0", name, nrmGot) } default: diff := math.Abs(nrmGot-nrmWant) / nrmWant / math.Max(1, float64(n)) if math.IsNaN(diff) || diff > tol { t.Errorf("%v: unexpected result; got %v, want %v", name, nrmGot, nrmWant) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlasv2.go000066400000000000000000000022441450372207100227500ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dlasv2er interface { Dlasv2(f, g, h float64) (ssmin, ssmax, snr, csr, snl, csl float64) } func Dlasv2Test(t *testing.T, impl Dlasv2er) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 100; i++ { f := rnd.NormFloat64() g := rnd.NormFloat64() h := rnd.NormFloat64() ssmin, ssmax, snr, csr, snl, csl := impl.Dlasv2(f, g, h) // tmp = // [ csl snl] [f g] // [-snl csl] [0 h] tmp11 := csl * f tmp12 := csl*g + snl*h tmp21 := -snl * f tmp22 := -snl*g + csl*h // lhs = // [tmp11 tmp12] [csr -snr] // [tmp21 tmp22] [snr csr] ans11 := tmp11*csr + tmp12*snr ans12 := tmp11*-snr + tmp12*csr ans21 := tmp21*csr + tmp22*snr ans22 := tmp21*-snr + tmp22*csr lhs := []float64{ans11, ans12, ans21, ans22} rhs := []float64{ssmax, 0, 0, ssmin} if !floats.EqualApprox(rhs, lhs, 1e-12) { t.Errorf("SVD mismatch. f = %v, g = %v, h = %v.\nLHS: %v\nRHS: %v", f, g, h, lhs, rhs) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlaswp.go000066400000000000000000000043151450372207100230500ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "gonum.org/v1/gonum/blas/blas64" ) type Dlaswper interface { Dlaswp(n int, a []float64, lda, k1, k2 int, ipiv []int, incX int) } func DlaswpTest(t *testing.T, impl Dlaswper) { for ti, test := range []struct { k1, k2 int ipiv []int incX int want blas64.General }{ { k1: 0, k2: 2, ipiv: []int{0, 1, 2}, incX: 1, want: blas64.General{ Rows: 4, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, }, }, { k1: 0, k2: 2, ipiv: []int{0, 1, 2}, incX: -1, want: blas64.General{ Rows: 4, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, }, }, { k1: 0, k2: 2, ipiv: []int{1, 2, 3}, incX: 1, want: blas64.General{ Rows: 5, Cols: 3, Stride: 3, Data: []float64{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 13, 14, 15, }, }, }, { k1: 0, k2: 2, ipiv: []int{1, 2, 3}, incX: -1, want: blas64.General{ Rows: 5, Cols: 3, Stride: 3, Data: []float64{ 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, }, }, }, } { m := test.want.Rows n := test.want.Cols k1 := test.k1 k2 := test.k2 if len(test.ipiv) != k2+1 { panic("bad length of ipiv") } incX := test.incX for _, extra := range []int{0, 11} { a := zeros(m, n, n+extra) c := 1 for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Data[i*a.Stride+j] = float64(c) c++ } } ipiv := make([]int, len(test.ipiv)) copy(ipiv, test.ipiv) impl.Dlaswp(n, a.Data, a.Stride, k1, k2, ipiv, incX) prefix := fmt.Sprintf("Case %v (m=%v,n=%v,k1=%v,k2=%v,extra=%v)", ti, m, n, k1, k2, extra) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A", prefix) } if !equalApproxGeneral(a, test.want, 0) { t.Errorf("%v: unexpected A\n%v\n%v", prefix, a, test.want) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlasy2.go000066400000000000000000000065731450372207100227640ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlasy2er interface { Dlasy2(tranl, tranr bool, isgn, n1, n2 int, tl []float64, ldtl int, tr []float64, ldtr int, b []float64, ldb int, x []float64, ldx int) (scale, xnorm float64, ok bool) } func Dlasy2Test(t *testing.T, impl Dlasy2er) { rnd := rand.New(rand.NewSource(1)) for _, tranl := range []bool{true, false} { for _, tranr := range []bool{true, false} { for _, isgn := range []int{1, -1} { for _, n1 := range []int{0, 1, 2} { for _, n2 := range []int{0, 1, 2} { for _, extra := range []int{0, 3} { for cas := 0; cas < 100; cas++ { var big bool if cas%2 == 0 { big = true } testDlasy2(t, impl, tranl, tranr, isgn, n1, n2, extra, big, rnd) } } } } } } } } func testDlasy2(t *testing.T, impl Dlasy2er, tranl, tranr bool, isgn, n1, n2, extra int, big bool, rnd *rand.Rand) { const tol = 1e-14 name := fmt.Sprintf("Case n1=%v, n2=%v, isgn=%v, big=%v", n1, n2, isgn, big) tl := randomGeneral(n1, n1, n1+extra, rnd) tr := randomGeneral(n2, n2, n2+extra, rnd) x := randomGeneral(n1, n2, n2+extra, rnd) b := randomGeneral(n1, n2, n2+extra, rnd) if big { for i := 0; i < n1; i++ { for j := 0; j < n2; j++ { b.Data[i*b.Stride+j] *= bignum } } } tlCopy := cloneGeneral(tl) trCopy := cloneGeneral(tr) bCopy := cloneGeneral(b) scale, xnorm, ok := impl.Dlasy2(tranl, tranr, isgn, n1, n2, tl.Data, tl.Stride, tr.Data, tr.Stride, b.Data, b.Stride, x.Data, x.Stride) // Check any invalid modifications in read-only input. if !equalGeneral(tl, tlCopy) { t.Errorf("%v: unexpected modification in TL", name) } if !equalGeneral(tr, trCopy) { t.Errorf("%v: unexpected modification in TR", name) } if !equalGeneral(b, bCopy) { t.Errorf("%v: unexpected modification in B", name) } // Check any invalid modifications of x. if !generalOutsideAllNaN(x) { t.Errorf("%v: out-of-range write to x\n%v", name, x.Data) } if n1 == 0 || n2 == 0 { return } if scale <= 0 || 1 < scale { t.Errorf("%v: invalid value of scale, want in (0,1], got %v", name, scale) } xnormWant := dlange(lapack.MaxRowSum, x.Rows, x.Cols, x.Data, x.Stride) if xnormWant != xnorm { t.Errorf("%v: unexpected xnorm: want %v, got %v", name, xnormWant, xnorm) } if !ok { t.Logf("%v: Dlasy2 returned ok=false", name) return } // Compute diff := op(TL)*X + sgn*X*op(TR) - scale*B. diff := zeros(n1, n2, n2) if tranl { blas64.Gemm(blas.Trans, blas.NoTrans, 1, tl, x, 0, diff) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tl, x, 0, diff) } if tranr { blas64.Gemm(blas.NoTrans, blas.Trans, float64(isgn), x, tr, 1, diff) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, float64(isgn), x, tr, 1, diff) } for i := 0; i < n1; i++ { for j := 0; j < n2; j++ { diff.Data[i*diff.Stride+j] -= scale * b.Data[i*b.Stride+j] } } // Check that residual |op(TL)*X + sgn*X*op(TR) - scale*B| / |X| is small. resid := dlange(lapack.MaxColumnSum, n1, n2, diff.Data, diff.Stride) / xnorm if resid > tol { t.Errorf("%v: unexpected result, resid=%v, want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlatbs.go000066400000000000000000000117451450372207100230340ustar00rootroot00000000000000// Copyright ©2019 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dlatbser interface { Dlatbs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, normin bool, n, kd int, ab []float64, ldab int, x []float64, cnorm []float64) float64 } // DlatbsTest tests Dlatbs by generating a random triangular band system and // checking that a residual for the computed solution is small. func DlatbsTest(t *testing.T, impl Dlatbser) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50} { for _, kd := range []int{0, (n + 1) / 4, (3*n - 1) / 4, (5*n + 1) / 4} { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { for _, ldab := range []int{kd + 1, kd + 1 + 7} { for _, kind := range []int{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18} { dlatbsTest(t, impl, rnd, kind, uplo, trans, n, kd, ldab) } } } } } } } func dlatbsTest(t *testing.T, impl Dlatbser, rnd *rand.Rand, kind int, uplo blas.Uplo, trans blas.Transpose, n, kd, ldab int) { const eps = 1e-15 // Allocate a triangular band matrix. var ab []float64 if n > 0 { ab = make([]float64, (n-1)*ldab+kd+1) } for i := range ab { ab[i] = rnd.NormFloat64() } // Generate a triangular test matrix and the right-hand side. diag, b := dlattb(kind, uplo, trans, n, kd, ab, ldab, rnd) // Make a copy of AB to make sure that it is not modified in Dlatbs. abCopy := make([]float64, len(ab)) copy(abCopy, ab) // Allocate cnorm and fill it with impossible result to make sure that it // _is_ updated in the first Dlatbs call below. cnorm := make([]float64, n) for i := range cnorm { cnorm[i] = -1 } // Solve the system op(A)*x = b. x := make([]float64, n) copy(x, b) scale := impl.Dlatbs(uplo, trans, diag, false, n, kd, ab, ldab, x, cnorm) name := fmt.Sprintf("kind=%v,uplo=%v,trans=%v,diag=%v,n=%v,kd=%v,ldab=%v", kind, string(uplo), string(trans), string(diag), n, kd, ldab) if !floats.Equal(ab, abCopy) { t.Errorf("%v: unexpected modification of ab", name) } if floats.Count(func(v float64) bool { return v == -1 }, cnorm) > 0 { t.Errorf("%v: expected modification of cnorm", name) } resid := dlatbsResidual(uplo, trans, diag, n, kd, ab, ldab, scale, cnorm, b, x) if resid >= eps { t.Errorf("%v: unexpected result when normin=false. residual=%v", name, resid) } // Make a copy of cnorm to check that it is _not_ modified. cnormCopy := make([]float64, len(cnorm)) copy(cnormCopy, cnorm) // Restore x. copy(x, b) // Solve the system op(A)*x = b again with normin = true. scale = impl.Dlatbs(uplo, trans, diag, true, n, kd, ab, ldab, x, cnorm) // Cannot test for exact equality because Dlatbs may scale cnorm by s and // then by 1/s before return. if !floats.EqualApprox(cnorm, cnormCopy, 1e-15) { t.Errorf("%v: unexpected modification of cnorm", name) } resid = dlatbsResidual(uplo, trans, diag, n, kd, ab, ldab, scale, cnorm, b, x) if resid >= eps { t.Errorf("%v: unexpected result when normin=true. residual=%v", name, resid) } } // dlatbsResidual returns the residual for the solution to a scaled triangular // system of equations A*x = s*b or Aᵀ*x = s*b when A is an n×n triangular // band matrix with kd super- or sub-diagonals. The residual is computed as // // norm( op(A)*x - scale*b ) / ( norm(op(A)) * norm(x) ). // // This function corresponds to DTBT03 in Reference LAPACK. func dlatbsResidual(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, kd int, ab []float64, ldab int, scale float64, cnorm, b, x []float64) float64 { if n == 0 { return 0 } // Compute the norm of the triangular matrix A using the columns norms // already computed by Dlatbs. var tnorm float64 if diag == blas.NonUnit { if uplo == blas.Upper { for j := 0; j < n; j++ { tnorm = math.Max(tnorm, math.Abs(ab[j*ldab])+cnorm[j]) } } else { for j := 0; j < n; j++ { tnorm = math.Max(tnorm, math.Abs(ab[j*ldab+kd])+cnorm[j]) } } } else { for j := 0; j < n; j++ { tnorm = math.Max(tnorm, 1+cnorm[j]) } } const ( eps = dlamchE tiny = safmin ) bi := blas64.Implementation() ix := bi.Idamax(n, x, 1) xNorm := math.Max(1, math.Abs(x[ix])) xScal := (1 / xNorm) / float64(kd+1) resid := make([]float64, len(x)) copy(resid, x) bi.Dscal(n, xScal, resid, 1) bi.Dtbmv(uplo, trans, diag, n, kd, ab, ldab, resid, 1) bi.Daxpy(n, -scale*xScal, b, 1, resid, 1) ix = bi.Idamax(n, resid, 1) residNorm := math.Abs(resid[ix]) if residNorm*tiny <= xNorm { if xNorm > 0 { residNorm /= xNorm } } else if residNorm > 0 { residNorm = 1 / eps } if residNorm*tiny <= tnorm { if tnorm > 0 { residNorm /= tnorm } } else if residNorm > 0 { residNorm = 1 / eps } return residNorm } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlatrd.go000066400000000000000000000147031450372207100230320ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlatrder interface { Dlatrd(uplo blas.Uplo, n, nb int, a []float64, lda int, e, tau, w []float64, ldw int) } func DlatrdTest(t *testing.T, impl Dlatrder) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, test := range []struct { n, nb, lda, ldw int }{ {5, 2, 0, 0}, {5, 5, 0, 0}, {5, 3, 10, 11}, {5, 5, 10, 11}, } { n := test.n nb := test.nb lda := test.lda if lda == 0 { lda = n } ldw := test.ldw if ldw == 0 { ldw = nb } // Allocate n×n matrix A and fill it with random numbers. a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } // Allocate output slices and matrix W and fill them // with NaN. All their elements should be overwritten by // Dlatrd. e := make([]float64, n-1) for i := range e { e[i] = math.NaN() } tau := make([]float64, n-1) for i := range tau { tau[i] = math.NaN() } w := make([]float64, n*ldw) for i := range w { w[i] = math.NaN() } aCopy := make([]float64, len(a)) copy(aCopy, a) // Reduce nb rows and columns of the symmetric matrix A // defined by uplo triangle to symmetric tridiagonal // form. impl.Dlatrd(uplo, n, nb, a, lda, e, tau, w, ldw) // Construct Q from elementary reflectors stored in // columns of A. q := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } // Initialize Q to the identity matrix. for i := 0; i < n; i++ { q.Data[i*q.Stride+i] = 1 } if uplo == blas.Upper { for i := n - 1; i >= n-nb; i-- { if i == 0 { continue } // Extract the elementary reflector v from A. v := blas64.Vector{ Inc: 1, Data: make([]float64, n), } for j := 0; j < i-1; j++ { v.Data[j] = a[j*lda+i] } v.Data[i-1] = 1 // Compute H = I - tau[i-1] * v * vᵀ. h := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for j := 0; j < n; j++ { h.Data[j*n+j] = 1 } blas64.Ger(-tau[i-1], v, v, h) // Update Q <- Q * H. qTmp := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } copy(qTmp.Data, q.Data) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qTmp, h, 0, q) } } else { for i := 0; i < nb; i++ { if i == n-1 { continue } // Extract the elementary reflector v from A. v := blas64.Vector{ Inc: 1, Data: make([]float64, n), } v.Data[i+1] = 1 for j := i + 2; j < n; j++ { v.Data[j] = a[j*lda+i] } // Compute H = I - tau[i] * v * vᵀ. h := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for j := 0; j < n; j++ { h.Data[j*n+j] = 1 } blas64.Ger(-tau[i], v, v, h) // Update Q <- Q * H. qTmp := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } copy(qTmp.Data, q.Data) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qTmp, h, 0, q) } } name := fmt.Sprintf("uplo=%c,n=%v,nb=%v", uplo, n, nb) if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case %v: Q is not orthogonal; resid=%v, want<=%v", name, resid, tol) } aGen := genFromSym(blas64.Symmetric{N: n, Stride: lda, Uplo: uplo, Data: aCopy}) if !dlatrdCheckDecomposition(t, uplo, n, nb, e, a, lda, aGen, q, tol) { t.Errorf("Case %v: Decomposition mismatch", name) } } } } // dlatrdCheckDecomposition checks that the first nb rows have been successfully // reduced. func dlatrdCheckDecomposition(t *testing.T, uplo blas.Uplo, n, nb int, e, a []float64, lda int, aGen, q blas64.General, tol float64) bool { // Compute ans = Qᵀ * A * Q. // ans should be a tridiagonal matrix in the first or last nb rows and // columns, depending on uplo. tmp := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } ans := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, aGen, 0, tmp) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, q, 0, ans) // Compare the output of Dlatrd (stored in a and e) with the explicit // reduction to tridiagonal matrix Qᵀ * A * Q (stored in ans). if uplo == blas.Upper { for i := n - nb; i < n; i++ { for j := 0; j < n; j++ { v := ans.Data[i*ans.Stride+j] switch { case i == j: // Diagonal elements of a and ans should match. if math.Abs(v-a[i*lda+j]) > tol { return false } case i == j-1: // Superdiagonal elements in a should be 1. if math.Abs(a[i*lda+j]-1) > tol { return false } // Superdiagonal elements of ans should match e. if math.Abs(v-e[i]) > tol { return false } case i == j+1: default: // All other elements should be 0. if math.Abs(v) > tol { return false } } } } } else { for i := 0; i < nb; i++ { for j := 0; j < n; j++ { v := ans.Data[i*ans.Stride+j] switch { case i == j: // Diagonal elements of a and ans should match. if math.Abs(v-a[i*lda+j]) > tol { return false } case i == j-1: case i == j+1: // Subdiagonal elements in a should be 1. if math.Abs(a[i*lda+j]-1) > tol { return false } // Subdiagonal elements of ans should match e. if math.Abs(v-e[i-1]) > tol { return false } default: // All other elements should be 0. if math.Abs(v) > tol { return false } } } } } return true } // genFromSym constructs a (symmetric) general matrix from the data in the // symmetric. // TODO(btracey): Replace other constructions of this with a call to this function. func genFromSym(a blas64.Symmetric) blas64.General { n := a.N lda := a.Stride uplo := a.Uplo b := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < n; i++ { for j := i; j < n; j++ { v := a.Data[i*lda+j] if uplo == blas.Lower { v = a.Data[j*lda+i] } b.Data[i*n+j] = v b.Data[j*n+i] = v } } return b } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlatrs.go000066400000000000000000000100201450372207100230350ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dlatrser interface { Dlatrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, normin bool, n int, a []float64, lda int, x []float64, cnorm []float64) (scale float64) } func DlatrsTest(t *testing.T, impl Dlatrser) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, trans := range []blas.Transpose{blas.Trans, blas.NoTrans} { for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 7, 10, 20, 50, 100} { for _, lda := range []int{n, 2*n + 1} { lda = max(1, lda) imats := []int{7, 11, 12, 13, 14, 15, 16, 17, 18, 19} if n < 6 { imats = append(imats, 19) } for _, imat := range imats { testDlatrs(t, impl, imat, uplo, trans, n, lda, rnd) } } } } } } func testDlatrs(t *testing.T, impl Dlatrser, imat int, uplo blas.Uplo, trans blas.Transpose, n, lda int, rnd *rand.Rand) { const tol = 1e-14 a := nanSlice(n * lda) b := nanSlice(n) work := make([]float64, 3*n) // Generate triangular test matrix and right hand side. diag := dlattr(imat, uplo, trans, n, a, lda, b, work, rnd) if imat <= 10 { // b has not been generated. dlarnv(b, 3, rnd) } cnorm := nanSlice(n) x := make([]float64, n) // Call Dlatrs with normin=false. copy(x, b) scale := impl.Dlatrs(uplo, trans, diag, false, n, a, lda, x, cnorm) prefix := fmt.Sprintf("Case imat=%v (n=%v,lda=%v,trans=%c,uplo=%c,diag=%c", imat, n, lda, trans, uplo, diag) for i, v := range cnorm { if math.IsNaN(v) { t.Errorf("%v: cnorm[%v] not computed (scale=%v,normin=false)", prefix, i, scale) } } resid, hasNaN := dlatrsResidual(uplo, trans, diag, n, a, lda, scale, cnorm, x, b, work[:n]) if hasNaN { t.Errorf("%v: unexpected NaN (scale=%v,normin=false)", prefix, scale) } else if resid > tol { t.Errorf("%v: residual %v too large (scale=%v,normin=false)", prefix, resid, scale) } // Call Dlatrs with normin=true because cnorm has been filled. copy(x, b) scale = impl.Dlatrs(uplo, trans, diag, true, n, a, lda, x, cnorm) resid, hasNaN = dlatrsResidual(uplo, trans, diag, n, a, lda, scale, cnorm, x, b, work[:n]) if hasNaN { t.Errorf("%v: unexpected NaN (scale=%v,normin=true)", prefix, scale) } else if resid > tol { t.Errorf("%v: residual %v too large (scale=%v,normin=true)", prefix, resid, scale) } } // dlatrsResidual returns norm(trans(A)*x-scale*b) / (norm(trans(A))*norm(x)*eps) // and whether NaN has been encountered in the process. func dlatrsResidual(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []float64, lda int, scale float64, cnorm []float64, x, b, work []float64) (resid float64, hasNaN bool) { if n == 0 { return 0, false } // Compute the norm of the triangular matrix A using the column norms // already computed by Dlatrs. var tnorm float64 if diag == blas.NonUnit { for j := 0; j < n; j++ { tnorm = math.Max(tnorm, math.Abs(a[j*lda+j])+cnorm[j]) } } else { for j := 0; j < n; j++ { tnorm = math.Max(tnorm, 1+cnorm[j]) } } const ( eps = dlamchE tiny = safmin ) bi := blas64.Implementation() // Compute norm(trans(A)*x-scale*b) / (norm(trans(A))*norm(x)*eps) copy(work, x) ix := bi.Idamax(n, work, 1) xnorm := math.Max(1, math.Abs(work[ix])) xscal := 1 / xnorm / float64(n) bi.Dscal(n, xscal, work, 1) bi.Dtrmv(uplo, trans, diag, n, a, lda, work, 1) bi.Daxpy(n, -scale*xscal, b, 1, work, 1) for _, v := range work { if math.IsNaN(v) { return 1 / eps, true } } ix = bi.Idamax(n, work, 1) resid = math.Abs(work[ix]) ix = bi.Idamax(n, x, 1) xnorm = math.Abs(x[ix]) if resid*tiny <= xnorm { if xnorm > 0 { resid /= xnorm } } else if resid > 0 { resid = 1 / eps } if resid*tiny <= tnorm { if tnorm > 0 { resid /= tnorm } } else if resid > 0 { resid = 1 / eps } return resid, false } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlauu2.go000066400000000000000000000057411450372207100227560ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dlauu2er interface { Dlauu2(uplo blas.Uplo, n int, a []float64, lda int) } func Dlauu2Test(t *testing.T, impl Dlauu2er) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { name := uploToString(uplo) t.Run(name, func(t *testing.T) { ns := []int{0, 1, 2, 3, 4, 5, 10, 25} dlauuTest(t, impl.Dlauu2, uplo, ns) }) } } func dlauuTest(t *testing.T, dlauu func(blas.Uplo, int, []float64, int), uplo blas.Uplo, ns []int) { const tol = 1e-13 bi := blas64.Implementation() rnd := rand.New(rand.NewSource(1)) for _, n := range ns { for _, lda := range []int{max(1, n), n + 11} { prefix := fmt.Sprintf("n=%v,lda=%v", n, lda) // Allocate n×n matrix A and fill it with random numbers. // Only its uplo triangle will be used below. a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } // Create a copy of A. aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute U*Uᵀ or Lᵀ*L using Dlauu?. dlauu(uplo, n, a, lda) if n == 0 { continue } // * Check that the triangle of A opposite to uplo has not been modified. // * Convert the result of Dlauu? into a dense symmetric matrix. // * Zero out the triangle in aCopy opposite to uplo. if uplo == blas.Upper { if !sameLowerTri(n, aCopy, lda, a, lda) { t.Errorf("%v: unexpected modification in lower triangle", prefix) continue } for i := 1; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = a[j*lda+i] aCopy[i*lda+j] = 0 } } } else { if !sameUpperTri(n, aCopy, lda, a, lda) { t.Errorf("%v: unexpected modification in upper triangle", prefix) continue } for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { a[i*lda+j] = a[j*lda+i] aCopy[i*lda+j] = 0 } } } // Compute U*Uᵀ or Lᵀ*L using Dgemm with U and L // represented as dense triangular matrices. r := cloneGeneral(blas64.General{Rows: n, Cols: n, Data: a, Stride: lda}) if uplo == blas.Upper { // Use aCopy as a dense representation of the upper triangular U. u := aCopy ldu := lda // Compute U*Uᵀ - A and store the result into R. bi.Dgemm(blas.NoTrans, blas.Trans, n, n, n, 1, u, ldu, u, ldu, -1, r.Data, r.Stride) } else { // Use aCopy as a dense representation of the lower triangular L. l := aCopy ldl := lda // Compute Lᵀ*L - A and store the result into R. bi.Dgemm(blas.Trans, blas.NoTrans, n, n, n, 1, l, ldl, l, ldl, -1, r.Data, r.Stride) } resid := dlange(lapack.MaxColumnSum, r.Rows, r.Cols, r.Data, r.Stride) if resid > tol*float64(n) { t.Errorf("%v: unexpected result", prefix) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dlauum.go000066400000000000000000000013221450372207100230400ustar00rootroot00000000000000// 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 testlapack import ( "testing" "gonum.org/v1/gonum/blas" ) type Dlauumer interface { Dlauum(uplo blas.Uplo, n int, a []float64, lda int) } func DlauumTest(t *testing.T, impl Dlauumer) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { name := uploToString(uplo) t.Run(name, func(t *testing.T) { // Include small and large sizes to make sure that both // unblocked and blocked paths are taken. ns := []int{0, 1, 2, 3, 4, 5, 10, 25, 31, 32, 33, 63, 64, 65, 127, 128, 129} dlauuTest(t, impl.Dlauum, uplo, ns) }) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/doc.go000066400000000000000000000004721450372207100223230ustar00rootroot00000000000000// 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 testlapack implements a set of testing routines for Lapack functions. package testlapack // import "gonum.org/v1/gonum/lapack/testlapack" golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorg2l.go000066400000000000000000000023301450372207100227420ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" ) type Dorg2ler interface { Dorg2l(m, n, k int, a []float64, lda int, tau, work []float64) Dgeql2er } func Dorg2lTest(t *testing.T, impl Dorg2ler) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, k, lda int }{ {5, 4, 3, 0}, {5, 4, 4, 0}, {3, 3, 2, 0}, {5, 5, 5, 0}, {5, 4, 3, 11}, {5, 4, 4, 11}, {3, 3, 2, 11}, {5, 5, 5, 11}, } { m := test.m n := test.n k := test.k lda := test.lda if lda == 0 { lda = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } tau := nanSlice(max(m, n)) work := make([]float64, n) impl.Dgeql2(m, n, a, lda, tau, work) impl.Dorg2l(m, n, k, a, lda, tau[n-k:], work) q := blas64.General{Rows: m, Cols: n, Data: a, Stride: lda} if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case m=%v, n=%v, k=%v, lda=%v: columns of Q not orthonormal; resid=%v, want<=%v", m, n, k, lda, resid, tol) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorg2r.go000066400000000000000000000032561450372207100227600ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) type Dorg2rer interface { Dgeqrfer Dorg2r(m, n, k int, a []float64, lda int, tau []float64, work []float64) } func Dorg2rTest(t *testing.T, impl Dorg2rer) { rnd := rand.New(rand.NewSource(1)) for ti, test := range []struct { m, n, k, lda int }{ {3, 3, 0, 0}, {4, 3, 0, 0}, {3, 3, 2, 0}, {4, 3, 2, 0}, {5, 5, 0, 20}, {5, 5, 3, 20}, {10, 5, 0, 20}, {10, 5, 2, 20}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = test.n } // Allocate m×n matrix A and fill it with random numbers. a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } // Compute the QR decomposition of A. tau := make([]float64, min(m, n)) work := make([]float64, 1) impl.Dgeqrf(m, n, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgeqrf(m, n, a, lda, tau, work, len(work)) // Compute the matrix Q explicitly using the first k elementary reflectors. k := test.k if k == 0 { k = n } q := constructQK("QR", m, n, k, a, lda, tau) // Compute the matrix Q using Dorg2r. impl.Dorg2r(m, n, k, a, lda, tau, work) // Check that the first n columns of both results match. same := true loop: for i := 0; i < m; i++ { for j := 0; j < n; j++ { if !scalar.EqualWithinAbsOrRel(q.Data[i*q.Stride+j], a[i*lda+j], 1e-12, 1e-12) { same = false break loop } } } if !same { t.Errorf("Case %v: Q mismatch", ti) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorgbr.go000066400000000000000000000065331450372207100230410ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/lapack" ) type Dorgbrer interface { Dorgbr(vect lapack.GenOrtho, m, n, k int, a []float64, lda int, tau, work []float64, lwork int) Dgebrder } func DorgbrTest(t *testing.T, impl Dorgbrer) { rnd := rand.New(rand.NewSource(1)) for _, vect := range []lapack.GenOrtho{lapack.GenerateQ, lapack.GeneratePT} { for _, test := range []struct { m, n, k, lda int }{ {5, 5, 5, 0}, {5, 5, 3, 0}, {5, 3, 5, 0}, {3, 5, 5, 0}, {3, 4, 5, 0}, {3, 5, 4, 0}, {4, 3, 5, 0}, {4, 5, 3, 0}, {5, 3, 4, 0}, {5, 4, 3, 0}, {5, 5, 5, 10}, {5, 5, 3, 10}, {5, 3, 5, 10}, {3, 5, 5, 10}, {3, 4, 5, 10}, {3, 5, 4, 10}, {4, 3, 5, 10}, {4, 5, 3, 10}, {5, 3, 4, 10}, {5, 4, 3, 10}, } { m := test.m n := test.n k := test.k lda := test.lda // Filter out bad tests if vect == lapack.GenerateQ { if m < n || n < min(m, k) || m < min(m, k) { continue } } else { if n < m || m < min(n, k) || n < min(n, k) { continue } } // Sizes for Dorgbr. var ma, na int if vect == lapack.GenerateQ { if m >= k { ma = m na = k } else { ma = m na = m } } else { if n >= k { ma = k na = n } else { ma = n na = n } } // a eventually needs to store either P or Q, so it must be // sufficiently big. var a []float64 if vect == lapack.GenerateQ { lda = max(m, lda) a = make([]float64, m*lda) } else { lda = max(n, lda) a = make([]float64, n*lda) } for i := range a { a[i] = rnd.NormFloat64() } nTau := min(ma, na) tauP := make([]float64, nTau) tauQ := make([]float64, nTau) d := make([]float64, nTau) e := make([]float64, nTau) lwork := -1 work := make([]float64, 1) impl.Dgebrd(ma, na, a, lda, d, e, tauQ, tauP, work, lwork) work = make([]float64, int(work[0])) lwork = len(work) impl.Dgebrd(ma, na, a, lda, d, e, tauQ, tauP, work, lwork) aCopy := make([]float64, len(a)) copy(aCopy, a) var tau []float64 if vect == lapack.GenerateQ { tau = tauQ } else { tau = tauP } impl.Dorgbr(vect, m, n, k, a, lda, tau, work, -1) work = make([]float64, int(work[0])) lwork = len(work) impl.Dorgbr(vect, m, n, k, a, lda, tau, work, lwork) var ans blas64.General var nRows, nCols int equal := true if vect == lapack.GenerateQ { nRows = m nCols = m if m >= k { nCols = n } ans = constructQPBidiagonal(lapack.ApplyQ, ma, na, min(m, k), aCopy, lda, tau) } else { nRows = n if k < n { nRows = m } nCols = n ansTmp := constructQPBidiagonal(lapack.ApplyP, ma, na, min(k, n), aCopy, lda, tau) // Dorgbr actually computes Pᵀ ans = transposeGeneral(ansTmp) } for i := 0; i < nRows; i++ { for j := 0; j < nCols; j++ { if !scalar.EqualWithinAbsOrRel(a[i*lda+j], ans.Data[i*ans.Stride+j], 1e-8, 1e-8) { equal = false } } } if !equal { t.Errorf("Extracted matrix mismatch. gen = %v, m = %v, n = %v, k = %v", string(vect), m, n, k) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorghr.go000066400000000000000000000051101450372207100230350ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dorghrer interface { Dorghr(n, ilo, ihi int, a []float64, lda int, tau, work []float64, lwork int) Dgehrder } func DorghrTest(t *testing.T, impl Dorghrer) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 4, 5, 6, 7, 8, 23, 34} { for _, extra := range []int{0, 1, 13} { for _, optwork := range []bool{true, false} { for cas := 0; cas < 100; cas++ { ilo := rnd.Intn(n) ihi := rnd.Intn(n) if ilo > ihi { ilo, ihi = ihi, ilo } testDorghr(t, impl, n, ilo, ihi, extra, optwork, rnd) } } } } testDorghr(t, impl, 0, 0, -1, 0, false, rnd) testDorghr(t, impl, 0, 0, -1, 0, true, rnd) } func testDorghr(t *testing.T, impl Dorghrer, n, ilo, ihi, extra int, optwork bool, rnd *rand.Rand) { const tol = 1e-14 // Construct the matrix A with elementary reflectors and scalar factors tau. a := randomGeneral(n, n, n+extra, rnd) var tau []float64 if n > 1 { tau = nanSlice(n - 1) } work := nanSlice(max(1, n)) // Minimum work for Dgehrd. impl.Dgehrd(n, ilo, ihi, a.Data, a.Stride, tau, work, len(work)) // Extract Q for later comparison. q := eye(n, n) qCopy := cloneGeneral(q) for j := ilo; j < ihi; j++ { h := eye(n, n) v := blas64.Vector{ Inc: 1, Data: make([]float64, n), } v.Data[j+1] = 1 for i := j + 2; i < ihi+1; i++ { v.Data[i] = a.Data[i*a.Stride+j] } blas64.Ger(-tau[j], v, v, h) copy(qCopy.Data, q.Data) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, h, 0, q) } if optwork { work = nanSlice(1) impl.Dorghr(n, ilo, ihi, a.Data, a.Stride, tau, work, -1) work = nanSlice(int(work[0])) } else { work = nanSlice(max(1, ihi-ilo)) } impl.Dorghr(n, ilo, ihi, a.Data, a.Stride, tau, work, len(work)) prefix := fmt.Sprintf("Case n=%v, ilo=%v, ihi=%v, extra=%v, optwork=%v", n, ilo, ihi, extra, optwork) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A\n%v", prefix, a.Data) } if resid := residualOrthogonal(a, false); resid > tol { t.Errorf("%v: A is not orthogonal; resid=%v, want<=%v", prefix, resid, tol) } for i := 0; i < n; i++ { for j := 0; j < n; j++ { aij := a.Data[i*a.Stride+j] qij := q.Data[i*q.Stride+j] if math.Abs(aij-qij) > tol { t.Errorf("%v: unexpected value of A[%v,%v]. want %v, got %v", prefix, i, j, qij, aij) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorgl2.go000066400000000000000000000024571450372207100227540ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) type Dorgl2er interface { Dgelqfer Dorgl2(m, n, k int, a []float64, lda int, tau []float64, work []float64) } func Dorgl2Test(t *testing.T, impl Dorgl2er) { rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n, lda int }{ {3, 3, 0}, {3, 4, 0}, {5, 5, 20}, {5, 10, 20}, } { m := test.m n := test.n lda := test.lda if lda == 0 { lda = test.n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.NormFloat64() } k := min(m, n) tau := make([]float64, k) work := make([]float64, 1) impl.Dgelqf(m, n, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgelqf(m, n, a, lda, tau, work, len(work)) q := constructQ("LQ", m, n, a, lda, tau) impl.Dorgl2(m, n, k, a, lda, tau, work) // Check that the first m rows match. same := true for i := 0; i < m; i++ { for j := 0; j < n; j++ { if !scalar.EqualWithinAbsOrRel(q.Data[i*q.Stride+j], a[i*lda+j], 1e-12, 1e-12) { same = false break } } } if !same { t.Errorf("Q mismatch") } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorglq.go000066400000000000000000000035661450372207100230550ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dorglqer interface { Dorgl2er Dorglq(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) } func DorglqTest(t *testing.T, impl Dorglqer) { rnd := rand.New(rand.NewSource(1)) // TODO(btracey): Base tests off of nb and nx. for _, test := range []struct{ m, n, k, lda int }{ {10, 10, 10, 0}, {10, 10, 10, 20}, {10, 30, 10, 0}, {20, 30, 10, 0}, {100, 100, 100, 0}, {100, 100, 50, 0}, {100, 130, 100, 0}, {100, 130, 50, 0}, {100, 100, 100, 150}, {100, 100, 50, 150}, {100, 130, 100, 150}, {100, 130, 50, 150}, {200, 200, 200, 0}, {200, 200, 150, 0}, {200, 230, 200, 0}, {200, 230, 150, 0}, {200, 200, 200, 250}, {200, 200, 150, 250}, {200, 230, 200, 250}, {200, 230, 150, 250}, } { m := test.m n := test.n k := test.k lda := test.lda if lda == 0 { lda = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() } work := make([]float64, 1) tau := make([]float64, m) for i := range tau { tau[i] = math.NaN() } // Compute LQ factorization. impl.Dgelqf(m, n, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgelqf(m, n, a, lda, tau, work, len(work)) aUnblocked := make([]float64, len(a)) copy(aUnblocked, a) for i := range work { work[i] = math.NaN() } impl.Dorgl2(m, n, k, aUnblocked, lda, tau, work) // make sure work isn't used before initialized for i := range work { work[i] = math.NaN() } impl.Dorglq(m, n, k, a, lda, tau, work, len(work)) if !floats.EqualApprox(a, aUnblocked, 1e-10) { t.Errorf("Q Mismatch. m = %d, n = %d, k = %d, lda = %d", m, n, k, lda) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorgql.go000066400000000000000000000064761450372207100230600ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dorgqler interface { Dorgql(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) Dlarfger } func DorgqlTest(t *testing.T, impl Dorgqler) { const tol = 1e-14 type Dorg2ler interface { Dorg2l(m, n, k int, a []float64, lda int, tau, work []float64) } dorg2ler, hasDorg2l := impl.(Dorg2ler) rnd := rand.New(rand.NewSource(1)) for _, m := range []int{0, 1, 2, 3, 4, 5, 7, 10, 15, 30, 50, 150} { for _, extra := range []int{0, 11} { for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { var k int if m >= 129 { // For large matrices make sure that k // is large enough to trigger blocked // path. k = 129 + rnd.Intn(m-129+1) } else { k = rnd.Intn(m + 1) } n := k + rnd.Intn(m-k+1) if m == 0 || n == 0 { m = 0 n = 0 k = 0 } // Generate k elementary reflectors in the last // k columns of A. a := nanGeneral(m, n, n+extra) tau := make([]float64, k) for l := 0; l < k; l++ { jj := m - k + l v := randomSlice(jj, rnd) _, tau[l] = impl.Dlarfg(len(v)+1, rnd.NormFloat64(), v, 1) j := n - k + l for i := 0; i < jj; i++ { a.Data[i*a.Stride+j] = v[i] } } aCopy := cloneGeneral(a) // Compute the full matrix Q by forming the // Householder reflectors explicitly. q := eye(m, m) qCopy := eye(m, m) for l := 0; l < k; l++ { h := eye(m, m) jj := m - k + l j := n - k + l v := blas64.Vector{Data: make([]float64, m), Inc: 1} for i := 0; i < jj; i++ { v.Data[i] = a.Data[i*a.Stride+j] } v.Data[jj] = 1 blas64.Ger(-tau[l], v, v, h) copy(qCopy.Data, q.Data) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, qCopy, 0, q) } // View the last n columns of Q as 'want'. want := blas64.General{ Rows: m, Cols: n, Stride: q.Stride, Data: q.Data[m-n:], } var lwork int switch wl { case minimumWork: lwork = max(1, n) case mediumWork: work := make([]float64, 1) impl.Dorgql(m, n, k, a.Data, a.Stride, tau, work, -1) lwork = (int(work[0]) + n) / 2 lwork = max(1, lwork) case optimumWork: work := make([]float64, 1) impl.Dorgql(m, n, k, a.Data, a.Stride, tau, work, -1) lwork = int(work[0]) } work := make([]float64, lwork) // Compute the last n columns of Q by a call to // Dorgql. impl.Dorgql(m, n, k, a.Data, a.Stride, tau, work, len(work)) prefix := fmt.Sprintf("Case m=%v,n=%v,k=%v,wl=%v", m, n, k, wl) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A", prefix) } if !equalApproxGeneral(want, a, tol) { t.Errorf("%v: unexpected Q", prefix) } // Compute the last n columns of Q by a call to // Dorg2l and check that we get the same result. if !hasDorg2l { continue } dorg2ler.Dorg2l(m, n, k, aCopy.Data, aCopy.Stride, tau, work) if !equalApproxGeneral(aCopy, a, tol) { t.Errorf("%v: mismatch between Dorgql and Dorg2l", prefix) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorgqr.go000066400000000000000000000035671450372207100230640ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) type Dorgqrer interface { Dorg2rer Dorgqr(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) } func DorgqrTest(t *testing.T, impl Dorgqrer) { rnd := rand.New(rand.NewSource(1)) // TODO(btracey): Base tests off of nb and nx. for _, test := range []struct{ m, n, k, lda int }{ {10, 10, 10, 0}, {10, 10, 10, 20}, {30, 10, 10, 0}, {30, 20, 10, 20}, {100, 100, 100, 0}, {100, 100, 50, 0}, {130, 100, 100, 0}, {130, 100, 50, 0}, {100, 100, 100, 150}, {100, 100, 50, 150}, {130, 100, 100, 150}, {130, 100, 50, 150}, {200, 200, 200, 0}, {200, 200, 150, 0}, {230, 200, 200, 0}, {230, 200, 150, 0}, {200, 200, 200, 250}, {200, 200, 150, 250}, {230, 200, 200, 250}, {230, 200, 150, 250}, } { m := test.m n := test.n k := test.k lda := test.lda if lda == 0 { lda = n } a := make([]float64, m*lda) for i := range a { a[i] = rnd.Float64() } work := make([]float64, 1) tau := make([]float64, n) for i := range tau { tau[i] = math.NaN() } // Compute QR factorization. impl.Dgeqrf(m, n, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgeqrf(m, n, a, lda, tau, work, len(work)) aUnblocked := make([]float64, len(a)) copy(aUnblocked, a) for i := range work { work[i] = math.NaN() } impl.Dorg2r(m, n, k, aUnblocked, lda, tau, work) // make sure work isn't used before initialized for i := range work { work[i] = math.NaN() } impl.Dorgqr(m, n, k, a, lda, tau, work, len(work)) if !floats.EqualApprox(a, aUnblocked, 1e-10) { t.Errorf("Q Mismatch. m = %d, n = %d, k = %d, lda = %d", m, n, k, lda) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorgr2.go000066400000000000000000000052031450372207100227520ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dorgr2er interface { Dorgr2(m, n, k int, a []float64, lda int, tau []float64, work []float64) Dgerqfer } func Dorgr2Test(t *testing.T, impl Dorgr2er) { rnd := rand.New(rand.NewSource(1)) for _, k := range []int{0, 1, 2, 5} { for _, m := range []int{k, k + 1, k + 2, k + 4} { for _, n := range []int{m, m + 1, m + 2, m + 4, m + 7} { for _, lda := range []int{max(1, n), n + 5} { dorgr2Test(t, impl, rnd, m, n, k, lda) } } } } } func dorgr2Test(t *testing.T, impl Dorgr2er, rnd *rand.Rand, m, n, k, lda int) { const tol = 1e-14 name := fmt.Sprintf("m=%v,n=%v,k=%v,lda=%v", m, n, k, lda) // Generate a random m×n matrix A. a := randomGeneral(m, n, lda, rnd) // Compute the RQ decomposition of A. rq := cloneGeneral(a) tau := make([]float64, m) work := make([]float64, 1) impl.Dgerqf(m, n, rq.Data, rq.Stride, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgerqf(m, n, rq.Data, rq.Stride, tau, work, len(work)) tauCopy := make([]float64, len(tau)) copy(tauCopy, tau) // Compute the matrix Q using Dorg2r. q := cloneGeneral(rq) impl.Dorgr2(m, n, k, q.Data, q.Stride, tau[m-k:m], work) if m == 0 { return } // Check that tau hasn't been modified. if !floats.Equal(tau, tauCopy) { t.Errorf("%v: unexpected modification in tau", name) } // Check that Q has orthonormal rows. res := residualOrthogonal(q, true) if res > tol || math.IsNaN(res) { t.Errorf("%v: residual |I - Q*Qᵀ| too large, got %v, want <= %v", name, res, tol) } if k == 0 { return } // Extract the k×m upper triangular matrix R from RQ[m-k:m,n-k:n]. r := zeros(k, m, m) for i := 0; i < k; i++ { for j := 0; j < k; j++ { ii := rq.Rows - k + i jj := rq.Cols - k + j jr := r.Cols - k + j if i <= j { r.Data[i*r.Stride+jr] = rq.Data[ii*rq.Stride+jj] } } } // Construct a view A[m-k:m,0:n] of the last k rows of A. aRec := blas64.General{ Rows: k, Cols: n, Data: a.Data[(m-k)*a.Stride:], Stride: a.Stride, } // Compute A - R*Q. blas64.Gemm(blas.NoTrans, blas.NoTrans, -1, r, q, 1, aRec) // Check that |A - R*Q| is small. res = dlange(lapack.MaxColumnSum, aRec.Rows, aRec.Cols, aRec.Data, aRec.Stride) if res > tol || math.IsNaN(res) { t.Errorf("%v: residual |A - R*Q| too large, got %v, want <= %v", name, res, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorgtr.go000066400000000000000000000104771450372207100230650ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dorgtrer interface { Dorgtr(uplo blas.Uplo, n int, a []float64, lda int, tau, work []float64, lwork int) Dsytrder } func DorgtrTest(t *testing.T, impl Dorgtrer) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { for _, test := range []struct { n, lda int }{ {1, 0}, {2, 0}, {3, 0}, {6, 0}, {33, 0}, {100, 0}, {1, 3}, {2, 5}, {3, 7}, {6, 10}, {33, 50}, {100, 120}, } { n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate n×n matrix A and fill it with random numbers. a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } aCopy := make([]float64, len(a)) copy(aCopy, a) // Allocate slices for the main diagonal and the // first off-diagonal of the tri-diagonal matrix. d := make([]float64, n) e := make([]float64, n-1) // Allocate slice for elementary reflector scales. tau := make([]float64, n-1) // Compute optimum workspace size for Dorgtr call. work := make([]float64, 1) impl.Dsytrd(uplo, n, a, lda, d, e, tau, work, -1) work = make([]float64, int(work[0])) // Compute elementary reflectors that reduce the // symmetric matrix defined by the uplo triangle // of A to a tridiagonal matrix. impl.Dsytrd(uplo, n, a, lda, d, e, tau, work, len(work)) // Compute workspace size for Dorgtr call. var lwork int switch wl { case minimumWork: lwork = max(1, n-1) case mediumWork: work := make([]float64, 1) impl.Dorgtr(uplo, n, a, lda, tau, work, -1) lwork = (int(work[0]) + n - 1) / 2 lwork = max(1, lwork) case optimumWork: work := make([]float64, 1) impl.Dorgtr(uplo, n, a, lda, tau, work, -1) lwork = int(work[0]) } work = nanSlice(lwork) // Generate an orthogonal matrix Q that reduces // the uplo triangle of A to a tridiagonal matrix. impl.Dorgtr(uplo, n, a, lda, tau, work, len(work)) q := blas64.General{ Rows: n, Cols: n, Stride: lda, Data: a, } name := fmt.Sprintf("uplo=%c,n=%v,lda=%v,work=%v", uplo, n, lda, wl) if resid := residualOrthogonal(q, false); resid > tol*float64(n) { t.Errorf("Case %v: Q is not orthogonal; resid=%v, want<=%v", name, resid, tol*float64(n)) } // Create the tridiagonal matrix explicitly in // dense representation from the diagonals d and e. tri := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < n; i++ { tri.Data[i*tri.Stride+i] = d[i] if i != n-1 { tri.Data[i*tri.Stride+i+1] = e[i] tri.Data[(i+1)*tri.Stride+i] = e[i] } } // Create the symmetric matrix A from the uplo // triangle of aCopy, storing it explicitly in dense form. aMat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { v := aCopy[i*lda+j] aMat.Data[i*aMat.Stride+j] = v aMat.Data[j*aMat.Stride+i] = v } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { v := aCopy[i*lda+j] aMat.Data[i*aMat.Stride+j] = v aMat.Data[j*aMat.Stride+i] = v } } } // Compute Qᵀ * A * Q and store the result in ans. tmp := blas64.General{Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n)} blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aMat, q, 0, tmp) ans := blas64.General{Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n)} blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, tmp, 0, ans) // Compare the tridiagonal matrix tri from // Dorgtr with the explicit computation ans. if !floats.EqualApprox(ans.Data, tri.Data, tol) { t.Errorf("Case %v: Recombination mismatch", name) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorm2r.go000066400000000000000000000070161450372207100227640ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dorm2rer interface { Dgeqrfer Dorm2r(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) } func Dorm2rTest(t *testing.T, impl Dorm2rer) { rnd := rand.New(rand.NewSource(1)) for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, test := range []struct { common, adim, cdim, lda, ldc int }{ {3, 4, 5, 0, 0}, {3, 5, 4, 0, 0}, {4, 3, 5, 0, 0}, {4, 5, 3, 0, 0}, {5, 3, 4, 0, 0}, {5, 4, 3, 0, 0}, {3, 4, 5, 6, 20}, {3, 5, 4, 6, 20}, {4, 3, 5, 6, 20}, {4, 5, 3, 6, 20}, {5, 3, 4, 6, 20}, {5, 4, 3, 6, 20}, {3, 4, 5, 20, 6}, {3, 5, 4, 20, 6}, {4, 3, 5, 20, 6}, {4, 5, 3, 20, 6}, {5, 3, 4, 20, 6}, {5, 4, 3, 20, 6}, } { var ma, na, mc, nc int if side == blas.Left { ma = test.common na = test.adim mc = test.common nc = test.cdim } else { ma = test.common na = test.adim mc = test.cdim nc = test.common } // Generate a random matrix lda := test.lda if lda == 0 { lda = na } a := make([]float64, ma*lda) for i := range a { a[i] = rnd.Float64() } ldc := test.ldc if ldc == 0 { ldc = nc } // Compute random C matrix c := make([]float64, mc*ldc) for i := range c { c[i] = rnd.Float64() } // Compute QR k := min(ma, na) tau := make([]float64, k) work := make([]float64, 1) impl.Dgeqrf(ma, na, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgeqrf(ma, na, a, lda, tau, work, len(work)) // Build Q from result q := constructQ("QR", ma, na, a, lda, tau) cMat := blas64.General{ Rows: mc, Cols: nc, Stride: ldc, Data: make([]float64, len(c)), } copy(cMat.Data, c) cMatCopy := blas64.General{ Rows: cMat.Rows, Cols: cMat.Cols, Stride: cMat.Stride, Data: make([]float64, len(cMat.Data)), } copy(cMatCopy.Data, cMat.Data) switch { default: panic("bad test") case side == blas.Left && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, cMatCopy, 0, cMat) case side == blas.Left && trans == blas.Trans: blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, cMatCopy, 0, cMat) case side == blas.Right && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, cMatCopy, q, 0, cMat) case side == blas.Right && trans == blas.Trans: blas64.Gemm(blas.NoTrans, blas.Trans, 1, cMatCopy, q, 0, cMat) } // Do Dorm2r ard compare if side == blas.Left { work = make([]float64, nc) } else { work = make([]float64, mc) } aCopy := make([]float64, len(a)) copy(aCopy, a) tauCopy := make([]float64, len(tau)) copy(tauCopy, tau) impl.Dorm2r(side, trans, mc, nc, k, a, lda, tau, c, ldc, work) if !floats.Equal(a, aCopy) { t.Errorf("a changed in call") } if !floats.Equal(tau, tauCopy) { t.Errorf("tau changed in call") } if !floats.EqualApprox(cMat.Data, c, 1e-14) { t.Errorf("Multiplication mismatch.\n Want %v \n got %v.", cMat.Data, c) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dormbr.go000066400000000000000000000106641450372207100230470ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dormbrer interface { Dormbr(vect lapack.ApplyOrtho, side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) Dgebrder } func DormbrTest(t *testing.T, impl Dormbrer) { rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() for _, vect := range []lapack.ApplyOrtho{lapack.ApplyQ, lapack.ApplyP} { for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { for _, test := range []struct { m, n, k, lda, ldc int }{ {3, 4, 5, 0, 0}, {3, 5, 4, 0, 0}, {4, 3, 5, 0, 0}, {4, 5, 3, 0, 0}, {5, 3, 4, 0, 0}, {5, 4, 3, 0, 0}, {3, 4, 5, 10, 12}, {3, 5, 4, 10, 12}, {4, 3, 5, 10, 12}, {4, 5, 3, 10, 12}, {5, 3, 4, 10, 12}, {5, 4, 3, 10, 12}, {150, 140, 130, 0, 0}, } { m := test.m n := test.n k := test.k ldc := test.ldc if ldc == 0 { ldc = n } nq := n nw := m if side == blas.Left { nq = m nw = n } // Compute a decomposition. var ma, na int var a []float64 if vect == lapack.ApplyQ { ma = nq na = k } else { ma = k na = nq } lda := test.lda if lda == 0 { lda = na } a = make([]float64, ma*lda) for i := range a { a[i] = rnd.NormFloat64() } nTau := min(nq, k) tauP := make([]float64, nTau) tauQ := make([]float64, nTau) d := make([]float64, nTau) e := make([]float64, nTau) work := make([]float64, 1) impl.Dgebrd(ma, na, a, lda, d, e, tauQ, tauP, work, -1) work = make([]float64, int(work[0])) impl.Dgebrd(ma, na, a, lda, d, e, tauQ, tauP, work, len(work)) // Apply and compare update. c := make([]float64, m*ldc) for i := range c { c[i] = rnd.NormFloat64() } cCopy := make([]float64, len(c)) copy(cCopy, c) var lwork int switch wl { case minimumWork: lwork = nw case optimumWork: impl.Dormbr(vect, side, trans, m, n, k, a, lda, tauQ, c, ldc, work, -1) lwork = int(work[0]) case mediumWork: work := make([]float64, 1) impl.Dormbr(vect, side, trans, m, n, k, a, lda, tauQ, c, ldc, work, -1) lwork = (int(work[0]) + nw) / 2 } lwork = max(1, lwork) work = make([]float64, lwork) if vect == lapack.ApplyQ { impl.Dormbr(vect, side, trans, m, n, k, a, lda, tauQ, c, ldc, work, lwork) } else { impl.Dormbr(vect, side, trans, m, n, k, a, lda, tauP, c, ldc, work, lwork) } // Check that the multiplication was correct. cOrig := blas64.General{ Rows: m, Cols: n, Stride: ldc, Data: make([]float64, len(cCopy)), } copy(cOrig.Data, cCopy) cAns := blas64.General{ Rows: m, Cols: n, Stride: ldc, Data: make([]float64, len(cCopy)), } copy(cAns.Data, cCopy) nb := min(ma, na) var mulMat blas64.General if vect == lapack.ApplyQ { mulMat = constructQPBidiagonal(lapack.ApplyQ, ma, na, nb, a, lda, tauQ) } else { mulMat = constructQPBidiagonal(lapack.ApplyP, ma, na, nb, a, lda, tauP) } mulTrans := trans if side == blas.Left { bi.Dgemm(mulTrans, blas.NoTrans, m, n, m, 1, mulMat.Data, mulMat.Stride, cOrig.Data, cOrig.Stride, 0, cAns.Data, cAns.Stride) } else { bi.Dgemm(blas.NoTrans, mulTrans, m, n, n, 1, cOrig.Data, cOrig.Stride, mulMat.Data, mulMat.Stride, 0, cAns.Data, cAns.Stride) } if !floats.EqualApprox(cAns.Data, c, 1e-13) { isApplyQ := vect == lapack.ApplyQ isLeft := side == blas.Left isTrans := trans == blas.Trans t.Errorf("C mismatch. isApplyQ: %v, isLeft: %v, isTrans: %v, m = %v, n = %v, k = %v, lda = %v, ldc = %v", isApplyQ, isLeft, isTrans, m, n, k, lda, ldc) } } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dormhr.go000066400000000000000000000071371450372207100230560ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dormhrer interface { Dormhr(side blas.Side, trans blas.Transpose, m, n, ilo, ihi int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) Dgehrder } func DormhrTest(t *testing.T, impl Dormhrer) { rnd := rand.New(rand.NewSource(1)) for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, m := range []int{1, 2, 3, 4, 5, 8, 9, 10, 23} { for _, n := range []int{1, 2, 3, 4, 5, 8, 9, 10, 23} { for _, extra := range []int{0, 1, 13} { for cas := 0; cas < 10; cas++ { nq := m if side == blas.Right { nq = n } ilo := rnd.Intn(nq) ihi := rnd.Intn(nq) if ilo > ihi { ilo, ihi = ihi, ilo } testDormhr(t, impl, side, trans, m, n, ilo, ihi, extra, true, rnd) testDormhr(t, impl, side, trans, m, n, ilo, ihi, extra, false, rnd) } } } } } } for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { testDormhr(t, impl, side, trans, 0, 0, 0, -1, 0, true, rnd) testDormhr(t, impl, side, trans, 0, 0, 0, -1, 0, false, rnd) } } } func testDormhr(t *testing.T, impl Dormhrer, side blas.Side, trans blas.Transpose, m, n, ilo, ihi, extra int, optwork bool, rnd *rand.Rand) { const tol = 1e-14 var nq, nw int switch side { case blas.Left: nq = m nw = n case blas.Right: nq = n nw = m } // Compute the elementary reflectors and tau. a := randomGeneral(nq, nq, nq+extra, rnd) var tau []float64 if nq > 1 { tau = nanSlice(nq - 1) } work := nanSlice(max(1, nq)) // Minimum work for Dgehrd. impl.Dgehrd(nq, ilo, ihi, a.Data, a.Stride, tau, work, len(work)) // Construct Q from the elementary reflectors in a and from tau. q := eye(nq, nq) qCopy := eye(nq, nq) for j := ilo; j < ihi; j++ { h := eye(nq, nq) v := blas64.Vector{ Inc: 1, Data: make([]float64, nq), } v.Data[j+1] = 1 for i := j + 2; i < ihi+1; i++ { v.Data[i] = a.Data[i*a.Stride+j] } blas64.Ger(-tau[j], v, v, h) copy(qCopy.Data, q.Data) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, h, 0, q) } c := randomGeneral(m, n, n+extra, rnd) // Compute the product of Q and C explicitly. qc := randomGeneral(m, n, n+extra, rnd) if side == blas.Left { blas64.Gemm(trans, blas.NoTrans, 1, q, c, 0, qc) } else { blas64.Gemm(blas.NoTrans, trans, 1, c, q, 0, qc) } // Compute the product of Q and C using Dormhr. if optwork { work = nanSlice(1) impl.Dormhr(side, trans, m, n, ilo, ihi, nil, a.Stride, nil, nil, c.Stride, work, -1) work = nanSlice(int(work[0])) } else { work = nanSlice(max(1, nw)) } impl.Dormhr(side, trans, m, n, ilo, ihi, a.Data, a.Stride, tau, c.Data, c.Stride, work, len(work)) // Compare the two answers. prefix := fmt.Sprintf("Case side=%c, trans=%c, m=%v, n=%v, ilo=%v, ihi=%v, extra=%v, optwork=%v", side, trans, m, n, ilo, ihi, extra, optwork) if !generalOutsideAllNaN(c) { t.Errorf("%v: out-of-range write to C\n%v", prefix, c.Data) } for i := 0; i < m; i++ { for j := 0; j < n; j++ { cij := c.Data[i*c.Stride+j] qcij := qc.Data[i*qc.Stride+j] if math.Abs(cij-qcij) > tol { t.Errorf("%v: unexpected value of the QC product at [%v,%v]: want %v, got %v", prefix, i, j, qcij, cij) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dorml2.go000066400000000000000000000074101450372207100227540ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dorml2er interface { Dgelqfer Dorml2(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) } func Dorml2Test(t *testing.T, impl Dorml2er) { rnd := rand.New(rand.NewSource(1)) // TODO(btracey): This test is not complete, because it // doesn't test individual values of m, n, and k, instead only testing // a specific subset of possible k values. for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, test := range []struct { common, adim, cdim, lda, ldc int }{ {3, 4, 5, 0, 0}, {3, 5, 4, 0, 0}, {4, 3, 5, 0, 0}, {4, 5, 3, 0, 0}, {5, 3, 4, 0, 0}, {5, 4, 3, 0, 0}, {3, 4, 5, 6, 20}, {3, 5, 4, 6, 20}, {4, 3, 5, 6, 20}, {4, 5, 3, 6, 20}, {5, 3, 4, 6, 20}, {5, 4, 3, 6, 20}, {3, 4, 5, 20, 6}, {3, 5, 4, 20, 6}, {4, 3, 5, 20, 6}, {4, 5, 3, 20, 6}, {5, 3, 4, 20, 6}, {5, 4, 3, 20, 6}, } { var ma, na, mc, nc int if side == blas.Left { ma = test.adim na = test.common mc = test.common nc = test.cdim } else { ma = test.adim na = test.common mc = test.cdim nc = test.common } // Generate a random matrix lda := test.lda if lda == 0 { lda = na } a := make([]float64, ma*lda) for i := range a { a[i] = rnd.Float64() } ldc := test.ldc if ldc == 0 { ldc = nc } // Compute random C matrix c := make([]float64, mc*ldc) for i := range c { c[i] = rnd.Float64() } // Compute LQ k := min(ma, na) tau := make([]float64, k) work := make([]float64, 1) impl.Dgelqf(ma, na, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgelqf(ma, na, a, lda, tau, work, len(work)) // Build Q from result q := constructQ("LQ", ma, na, a, lda, tau) cMat := blas64.General{ Rows: mc, Cols: nc, Stride: ldc, Data: make([]float64, len(c)), } copy(cMat.Data, c) cMatCopy := blas64.General{ Rows: cMat.Rows, Cols: cMat.Cols, Stride: cMat.Stride, Data: make([]float64, len(cMat.Data)), } copy(cMatCopy.Data, cMat.Data) switch { default: panic("bad test") case side == blas.Left && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, cMatCopy, 0, cMat) case side == blas.Left && trans == blas.Trans: blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, cMatCopy, 0, cMat) case side == blas.Right && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, cMatCopy, q, 0, cMat) case side == blas.Right && trans == blas.Trans: blas64.Gemm(blas.NoTrans, blas.Trans, 1, cMatCopy, q, 0, cMat) } // Do Dorm2r ard compare if side == blas.Left { work = make([]float64, nc) } else { work = make([]float64, mc) } aCopy := make([]float64, len(a)) copy(aCopy, a) tauCopy := make([]float64, len(tau)) copy(tauCopy, tau) impl.Dorml2(side, trans, mc, nc, k, a, lda, tau, c, ldc, work) if !floats.Equal(a, aCopy) { t.Errorf("a changed in call") } if !floats.Equal(tau, tauCopy) { t.Errorf("tau changed in call") } if !floats.EqualApprox(cMat.Data, c, 1e-14) { isLeft := side == blas.Left isTrans := trans == blas.Trans t.Errorf("Multiplication mismatch. IsLeft = %v. IsTrans = %v", isLeft, isTrans) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dormlq.go000066400000000000000000000064701450372207100230600ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dormlqer interface { Dorml2er Dormlq(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) } func DormlqTest(t *testing.T, impl Dormlqer) { rnd := rand.New(rand.NewSource(1)) for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { for _, test := range []struct { common, adim, cdim, lda, ldc int }{ {0, 0, 0, 0, 0}, {6, 7, 8, 0, 0}, {6, 8, 7, 0, 0}, {7, 6, 8, 0, 0}, {7, 8, 6, 0, 0}, {8, 6, 7, 0, 0}, {8, 7, 6, 0, 0}, {100, 200, 300, 0, 0}, {100, 300, 200, 0, 0}, {200, 100, 300, 0, 0}, {200, 300, 100, 0, 0}, {300, 100, 200, 0, 0}, {300, 200, 100, 0, 0}, {100, 200, 300, 400, 500}, {100, 300, 200, 400, 500}, {200, 100, 300, 400, 500}, {200, 300, 100, 400, 500}, {300, 100, 200, 400, 500}, {300, 200, 100, 400, 500}, {100, 200, 300, 500, 400}, {100, 300, 200, 500, 400}, {200, 100, 300, 500, 400}, {200, 300, 100, 500, 400}, {300, 100, 200, 500, 400}, {300, 200, 100, 500, 400}, } { var ma, na, mc, nc int if side == blas.Left { ma = test.adim na = test.common mc = test.common nc = test.cdim } else { ma = test.adim na = test.common mc = test.cdim nc = test.common } // Generate a random matrix lda := test.lda if lda == 0 { lda = max(1, na) } a := make([]float64, ma*lda) for i := range a { a[i] = rnd.Float64() } // Compute random C matrix ldc := test.ldc if ldc == 0 { ldc = nc } c := make([]float64, mc*ldc) for i := range c { c[i] = rnd.Float64() } // Compute LQ k := min(ma, na) tau := make([]float64, k) work := make([]float64, 1) impl.Dgelqf(ma, na, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgelqf(ma, na, a, lda, tau, work, len(work)) cCopy := make([]float64, len(c)) copy(cCopy, c) ans := make([]float64, len(c)) copy(ans, cCopy) var nw int if side == blas.Left { nw = nc } else { nw = mc } work = make([]float64, max(1, nw)) impl.Dorml2(side, trans, mc, nc, k, a, lda, tau, ans, ldc, work) var lwork int switch wl { case minimumWork: lwork = nw case optimumWork: impl.Dormlq(side, trans, mc, nc, k, a, lda, tau, c, ldc, work, -1) lwork = int(work[0]) case mediumWork: work := make([]float64, 1) impl.Dormlq(side, trans, mc, nc, k, a, lda, tau, c, ldc, work, -1) lwork = (int(work[0]) + nw) / 2 } lwork = max(1, lwork) work = make([]float64, lwork) impl.Dormlq(side, trans, mc, nc, k, a, lda, tau, c, ldc, work, lwork) if !floats.EqualApprox(c, ans, 1e-13) { t.Errorf("Dormqr and Dorm2r results mismatch") } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dormqr.go000066400000000000000000000077551450372207100230750ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dormqrer interface { Dorm2rer Dormqr(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) } func DormqrTest(t *testing.T, impl Dormqrer) { rnd := rand.New(rand.NewSource(1)) for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, test := range []struct { common, adim, cdim, lda, ldc int }{ {6, 7, 8, 0, 0}, {6, 8, 7, 0, 0}, {7, 6, 8, 0, 0}, {7, 8, 6, 0, 0}, {8, 6, 7, 0, 0}, {8, 7, 6, 0, 0}, {100, 200, 300, 0, 0}, {100, 300, 200, 0, 0}, {200, 100, 300, 0, 0}, {200, 300, 100, 0, 0}, {300, 100, 200, 0, 0}, {300, 200, 100, 0, 0}, {100, 200, 300, 400, 500}, {100, 300, 200, 400, 500}, {200, 100, 300, 400, 500}, {200, 300, 100, 400, 500}, {300, 100, 200, 400, 500}, {300, 200, 100, 400, 500}, {100, 200, 300, 500, 400}, {100, 300, 200, 500, 400}, {200, 100, 300, 500, 400}, {200, 300, 100, 500, 400}, {300, 100, 200, 500, 400}, {300, 200, 100, 500, 400}, } { var ma, na, mc, nc int if side == blas.Left { ma = test.common na = test.adim mc = test.common nc = test.cdim } else { ma = test.common na = test.adim mc = test.cdim nc = test.common } // Generate a random matrix lda := test.lda if lda == 0 { lda = na } a := make([]float64, ma*lda) for i := range a { a[i] = rnd.Float64() } // Compute random C matrix ldc := test.ldc if ldc == 0 { ldc = nc } c := make([]float64, mc*ldc) for i := range c { c[i] = rnd.Float64() } // Compute QR k := min(ma, na) tau := make([]float64, k) work := make([]float64, 1) impl.Dgeqrf(ma, na, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgeqrf(ma, na, a, lda, tau, work, len(work)) cCopy := make([]float64, len(c)) copy(cCopy, c) ans := make([]float64, len(c)) copy(ans, cCopy) if side == blas.Left { work = make([]float64, nc) } else { work = make([]float64, mc) } impl.Dorm2r(side, trans, mc, nc, k, a, lda, tau, ans, ldc, work) // Make sure Dorm2r and Dormqr match with small work for i := range work { work[i] = rnd.Float64() } copy(c, cCopy) impl.Dormqr(side, trans, mc, nc, k, a, lda, tau, c, ldc, work, len(work)) if !floats.EqualApprox(c, ans, 1e-12) { t.Errorf("Dormqr and Dorm2r mismatch for small work") } // Try with the optimum amount of work copy(c, cCopy) impl.Dormqr(side, trans, mc, nc, k, a, lda, tau, c, ldc, work, -1) work = make([]float64, int(work[0])) for i := range work { work[i] = rnd.Float64() } impl.Dormqr(side, trans, mc, nc, k, a, lda, tau, c, ldc, work, len(work)) if !floats.EqualApprox(c, ans, 1e-12) { t.Errorf("Dormqr and Dorm2r mismatch for full work") fmt.Println("ccopy") for i := 0; i < mc; i++ { fmt.Println(cCopy[i*ldc : (i+1)*ldc]) } fmt.Println("ans =") for i := 0; i < mc; i++ { fmt.Println(ans[i*ldc : (i+1)*ldc]) } fmt.Println("c =") for i := 0; i < mc; i++ { fmt.Println(c[i*ldc : (i+1)*ldc]) } } // Try with amount of work that is less than // optimal but still long enough to use the // blocked code. copy(c, cCopy) if side == blas.Left { work = make([]float64, 3*nc) } else { work = make([]float64, 3*mc) } impl.Dormqr(side, trans, mc, nc, k, a, lda, tau, c, ldc, work, len(work)) if !floats.EqualApprox(c, ans, 1e-12) { t.Errorf("Dormqr and Dorm2r mismatch for medium work") } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dormr2.go000066400000000000000000000070471450372207100227700ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dormr2er interface { Dgerqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) Dormr2(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) } func Dormr2Test(t *testing.T, impl Dormr2er) { rnd := rand.New(rand.NewSource(1)) for _, side := range []blas.Side{blas.Left, blas.Right} { for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} { for _, test := range []struct { common, adim, cdim, lda, ldc int }{ {3, 4, 5, 0, 0}, {3, 5, 4, 0, 0}, {4, 3, 5, 0, 0}, {4, 5, 3, 0, 0}, {5, 3, 4, 0, 0}, {5, 4, 3, 0, 0}, {3, 4, 5, 6, 20}, {3, 5, 4, 6, 20}, {4, 3, 5, 6, 20}, {4, 5, 3, 6, 20}, {5, 3, 4, 6, 20}, {5, 4, 3, 6, 20}, {3, 4, 5, 20, 6}, {3, 5, 4, 20, 6}, {4, 3, 5, 20, 6}, {4, 5, 3, 20, 6}, {5, 3, 4, 20, 6}, {5, 4, 3, 20, 6}, } { ma := test.adim na := test.common var mc, nc int if side == blas.Left { mc = test.common nc = test.cdim } else { mc = test.cdim nc = test.common } // Generate a random matrix lda := test.lda if lda == 0 { lda = na } a := make([]float64, ma*lda) for i := range a { a[i] = rnd.Float64() } ldc := test.ldc if ldc == 0 { ldc = nc } // Compute random C matrix c := make([]float64, mc*ldc) for i := range c { c[i] = rnd.Float64() } // Compute RQ k := min(ma, na) tau := make([]float64, k) work := make([]float64, 1) impl.Dgerqf(ma, na, a, lda, tau, work, -1) work = make([]float64, int(work[0])) impl.Dgerqf(ma, na, a, lda, tau, work, len(work)) // Build Q from result q := constructQ("RQ", ma, na, a, lda, tau) cMat := blas64.General{ Rows: mc, Cols: nc, Stride: ldc, Data: make([]float64, len(c)), } copy(cMat.Data, c) cMatCopy := blas64.General{ Rows: cMat.Rows, Cols: cMat.Cols, Stride: cMat.Stride, Data: make([]float64, len(cMat.Data)), } copy(cMatCopy.Data, cMat.Data) switch { default: panic("bad test") case side == blas.Left && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, cMatCopy, 0, cMat) case side == blas.Left && trans == blas.Trans: blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, cMatCopy, 0, cMat) case side == blas.Right && trans == blas.NoTrans: blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, cMatCopy, q, 0, cMat) case side == blas.Right && trans == blas.Trans: blas64.Gemm(blas.NoTrans, blas.Trans, 1, cMatCopy, q, 0, cMat) } // Do Dorm2r ard compare if side == blas.Left { work = make([]float64, nc) } else { work = make([]float64, mc) } aCopy := make([]float64, len(a)) copy(aCopy, a) tauCopy := make([]float64, len(tau)) copy(tauCopy, tau) impl.Dormr2(side, trans, mc, nc, k, a[(ma-k)*lda:], lda, tau, c, ldc, work) if !floats.Equal(a, aCopy) { t.Errorf("a changed in call") } if !floats.Equal(tau, tauCopy) { t.Errorf("tau changed in call") } if !floats.EqualApprox(cMat.Data, c, 1e-14) { t.Errorf("Multiplication mismatch.\n Want %v \n got %v.", cMat.Data, c) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpbcon.go000066400000000000000000000060311450372207100230200ustar00rootroot00000000000000// Copyright ©2019 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dpbconer interface { Dpbcon(uplo blas.Uplo, n, kd int, ab []float64, ldab int, anorm float64, work []float64, iwork []int) float64 Dpbtrser } // DpbconTest tests Dpbcon by generating a random symmetric band matrix A and // checking that the estimated condition number is not too different from the // condition number computed via the explicit inverse of A. func DpbconTest(t *testing.T, impl Dpbconer) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50} { for _, kd := range []int{0, (n + 1) / 4, (3*n - 1) / 4, (5*n + 1) / 4} { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, ldab := range []int{kd + 1, kd + 1 + 3} { dpbconTest(t, impl, uplo, n, kd, ldab, rnd) } } } } } func dpbconTest(t *testing.T, impl Dpbconer, uplo blas.Uplo, n, kd, ldab int, rnd *rand.Rand) { const ratioThresh = 10 name := fmt.Sprintf("uplo=%v,n=%v,kd=%v,ldab=%v", string(uplo), n, kd, ldab) // Generate a random symmetric positive definite band matrix. ab := randSymBand(uplo, n, kd, ldab, rnd) // Compute the Cholesky decomposition of A. abFac := make([]float64, len(ab)) copy(abFac, ab) ok := impl.Dpbtrf(uplo, n, kd, abFac, ldab) if !ok { t.Fatalf("%v: bad test matrix, Dpbtrf failed", name) } // Compute the norm of A. work := make([]float64, 3*n) aNorm := dlansb(lapack.MaxColumnSum, uplo, n, kd, ab, ldab, work) // Compute an estimate of rCond. iwork := make([]int, n) abFacCopy := make([]float64, len(abFac)) copy(abFacCopy, abFac) rCondGot := impl.Dpbcon(uplo, n, kd, abFac, ldab, aNorm, work, iwork) if !floats.Equal(abFac, abFacCopy) { t.Errorf("%v: unexpected modification of ab", name) } // Form the inverse of A to compute a good estimate of the condition number // rCondWant := 1/(norm(A) * norm(inv(A))) lda := max(1, n) aInv := make([]float64, n*lda) for i := 0; i < n; i++ { aInv[i*lda+i] = 1 } impl.Dpbtrs(uplo, n, kd, n, abFac, ldab, aInv, lda) aInvNorm := dlange(lapack.MaxColumnSum, n, n, aInv, lda) rCondWant := 1.0 if aNorm > 0 && aInvNorm > 0 { rCondWant = 1 / aNorm / aInvNorm } ratio := rCondTestRatio(rCondGot, rCondWant) if ratio >= ratioThresh { t.Errorf("%v: unexpected value of rcond. got=%v, want=%v (ratio=%v)", name, rCondGot, rCondWant, ratio) } } // rCondTestRatio returns a test ratio to compare two values of the reciprocal // of the condition number. // // This function corresponds to DGET06 in Reference LAPACK. func rCondTestRatio(rcond, rcondc float64) float64 { const eps = dlamchE switch { case rcond > 0 && rcondc > 0: return math.Max(rcond, rcondc)/math.Min(rcond, rcondc) - (1 - eps) case rcond > 0: return rcond / eps case rcondc > 0: return rcondc / eps default: return 0 } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpbtf2.go000066400000000000000000000035051450372207100227370ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" ) type Dpbtf2er interface { Dpbtf2(uplo blas.Uplo, n, kd int, ab []float64, ldab int) (ok bool) } // Dpbtf2Test tests Dpbtf2 on random symmetric positive definite band matrices // by checking that the Cholesky factors multiply back to the original matrix. func Dpbtf2Test(t *testing.T, impl Dpbtf2er) { // TODO(vladimir-ch): include expected-failure test case. rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 20} { for _, kd := range []int{0, (n + 1) / 4, (3*n - 1) / 4, (5*n + 1) / 4} { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, ldab := range []int{kd + 1, kd + 1 + 7} { dpbtf2Test(t, impl, rnd, uplo, n, kd, ldab) } } } } } func dpbtf2Test(t *testing.T, impl Dpbtf2er, rnd *rand.Rand, uplo blas.Uplo, n, kd int, ldab int) { const tol = 1e-12 name := fmt.Sprintf("uplo=%v,n=%v,kd=%v,ldab=%v", string(uplo), n, kd, ldab) // Generate a random symmetric positive definite band matrix. ab := randSymBand(uplo, n, kd, ldab, rnd) // Compute the Cholesky decomposition of A. abFac := make([]float64, len(ab)) copy(abFac, ab) ok := impl.Dpbtf2(uplo, n, kd, abFac, ldab) if !ok { t.Fatalf("%v: bad test matrix, Dpbtf2 failed", name) } // Reconstruct an symmetric band matrix from the Uᵀ*U or L*Lᵀ factorization, overwriting abFac. dsbmm(uplo, n, kd, abFac, ldab) // Compute and check the max-norm distance between the reconstructed and original matrix A. dist := distSymBand(uplo, n, kd, abFac, ldab, ab, ldab) if dist > tol { t.Errorf("%v: unexpected result, diff=%v", name, dist) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpbtrf.go000066400000000000000000000067451450372207100230500ustar00rootroot00000000000000// Copyright ©2019 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dpbtrfer interface { Dpbtrf(uplo blas.Uplo, n, kd int, ab []float64, ldab int) (ok bool) } // DpbtrfTest tests a band Cholesky factorization on random symmetric positive definite // band matrices by checking that the Cholesky factors multiply back to the original matrix. func DpbtrfTest(t *testing.T, impl Dpbtrfer) { // TODO(vladimir-ch): include expected-failure test case. // With the current implementation of Ilaenv the blocked code path is taken if kd > 64. // Unfortunately, with the block size nb=32 this also means that in Dpbtrf // it never happens that i2 <= 0 and the state coverage (unlike code coverage) is not complete. rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 64, 65, 66, 91, 96, 97, 101, 128, 130} { for _, kd := range []int{0, (n + 1) / 4, (3*n - 1) / 4, (5*n + 1) / 4} { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, ldab := range []int{kd + 1, kd + 1 + 7} { dpbtrfTest(t, impl, uplo, n, kd, ldab, rnd) } } } } } func dpbtrfTest(t *testing.T, impl Dpbtrfer, uplo blas.Uplo, n, kd int, ldab int, rnd *rand.Rand) { const tol = 1e-12 name := fmt.Sprintf("uplo=%v,n=%v,kd=%v,ldab=%v", string(uplo), n, kd, ldab) // Generate a random symmetric positive definite band matrix. ab := randSymBand(uplo, n, kd, ldab, rnd) // Compute the Cholesky decomposition of A. abFac := make([]float64, len(ab)) copy(abFac, ab) ok := impl.Dpbtrf(uplo, n, kd, abFac, ldab) if !ok { t.Fatalf("%v: bad test matrix, Dpbtrf failed", name) } // Reconstruct an symmetric band matrix from the Uᵀ*U or L*Lᵀ factorization, overwriting abFac. dsbmm(uplo, n, kd, abFac, ldab) // Compute and check the max-norm distance between the reconstructed and original matrix A. dist := distSymBand(uplo, n, kd, abFac, ldab, ab, ldab) if dist > tol*float64(n) { t.Errorf("%v: unexpected result, diff=%v", name, dist) } } // dsbmm computes a symmetric band matrix A // // A = Uᵀ*U if uplo == blas.Upper, // A = L*Lᵀ if uplo == blas.Lower, // // where U and L is an upper, respectively lower, triangular band matrix // stored on entry in ab. The result is stored in-place into ab. func dsbmm(uplo blas.Uplo, n, kd int, ab []float64, ldab int) { bi := blas64.Implementation() switch uplo { case blas.Upper: // Compute the product Uᵀ * U. for k := n - 1; k >= 0; k-- { klen := min(kd, n-k-1) // Number of stored off-diagonal elements in the row // Add a multiple of row k of the factor U to each of rows k+1 through n. if klen > 0 { bi.Dsyr(blas.Upper, klen, 1, ab[k*ldab+1:], 1, ab[(k+1)*ldab:], ldab-1) } // Scale row k by the diagonal element. bi.Dscal(klen+1, ab[k*ldab], ab[k*ldab:], 1) } case blas.Lower: // Compute the product L * Lᵀ. for k := n - 1; k >= 0; k-- { kc := max(0, kd-k) // Index of the first valid element in the row klen := kd - kc // Number of stored off-diagonal elements in the row // Compute the diagonal [k,k] element. ab[k*ldab+kd] = bi.Ddot(klen+1, ab[k*ldab+kc:], 1, ab[k*ldab+kc:], 1) // Compute the rest of column k. if klen > 0 { bi.Dtrmv(blas.Lower, blas.NoTrans, blas.NonUnit, klen, ab[(k-klen)*ldab+kd:], ldab-1, ab[k*ldab+kc:], 1) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpbtrs.go000066400000000000000000000052621450372207100230560ustar00rootroot00000000000000// Copyright ©2019 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dpbtrser interface { Dpbtrs(uplo blas.Uplo, n, kd, nrhs int, ab []float64, ldab int, b []float64, ldb int) Dpbtrfer } // DpbtrsTest tests Dpbtrs by comparing the computed and known, generated solutions of // a linear system with a random symmetric positive definite band matrix. func DpbtrsTest(t *testing.T, impl Dpbtrser) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 65, 100, 129} { for _, kd := range []int{0, (n + 1) / 4, (3*n - 1) / 4, (5*n + 1) / 4} { for _, nrhs := range []int{0, 1, 2, 5} { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, ldab := range []int{kd + 1, kd + 1 + 3} { for _, ldb := range []int{max(1, nrhs), nrhs + 4} { dpbtrsTest(t, impl, rnd, uplo, n, kd, nrhs, ldab, ldb) } } } } } } } func dpbtrsTest(t *testing.T, impl Dpbtrser, rnd *rand.Rand, uplo blas.Uplo, n, kd, nrhs int, ldab, ldb int) { const tol = 1e-12 name := fmt.Sprintf("uplo=%v,n=%v,kd=%v,nrhs=%v,ldab=%v,ldb=%v", string(uplo), n, kd, nrhs, ldab, ldb) // Generate a random symmetric positive definite band matrix. ab := randSymBand(uplo, n, kd, ldab, rnd) // Compute the Cholesky decomposition of A. abFac := make([]float64, len(ab)) copy(abFac, ab) ok := impl.Dpbtrf(uplo, n, kd, abFac, ldab) if !ok { t.Fatalf("%v: bad test matrix, Dpbtrs failed", name) } abFacCopy := make([]float64, len(abFac)) copy(abFacCopy, abFac) // Generate a random solution. xWant := make([]float64, n*ldb) for i := range xWant { xWant[i] = rnd.NormFloat64() } // Compute the corresponding right-hand side. bi := blas64.Implementation() b := make([]float64, len(xWant)) if n > 0 { for j := 0; j < nrhs; j++ { bi.Dsbmv(uplo, n, kd, 1, ab, ldab, xWant[j:], ldb, 0, b[j:], ldb) } } // Solve Uᵀ * U * X = B or L * Lᵀ * X = B. impl.Dpbtrs(uplo, n, kd, nrhs, abFac, ldab, b, ldb) xGot := b // Check that the Cholesky factorization matrix has not been modified. if !floats.Equal(abFac, abFacCopy) { t.Errorf("%v: unexpected modification of ab", name) } // Compute and check the max-norm difference between the computed and generated solutions. var diff float64 for i := 0; i < n; i++ { for j := 0; j < nrhs; j++ { diff = math.Max(diff, math.Abs(xWant[i*ldb+j]-xGot[i*ldb+j])) } } if diff > tol { t.Errorf("%v: unexpected result, diff=%v", name, diff) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpocon.go000066400000000000000000000101541450372207100230360ustar00rootroot00000000000000// 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 testlapack import ( "log" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/lapack" ) type Dpoconer interface { Dpotrfer Dgeconer Dlansy(norm lapack.MatrixNorm, uplo blas.Uplo, n int, a []float64, lda int, work []float64) float64 Dpocon(uplo blas.Uplo, n int, a []float64, lda int, anorm float64, work []float64, iwork []int) float64 } func DpoconTest(t *testing.T, impl Dpoconer) { for _, test := range []struct { a []float64 n int cond float64 uplo blas.Uplo }{ { a: []float64{ 89, 59, 77, 0, 107, 59, 0, 0, 89, }, uplo: blas.Upper, n: 3, cond: 0.050052137643379, }, { a: []float64{ 89, 0, 0, 59, 107, 0, 77, 59, 89, }, uplo: blas.Lower, n: 3, cond: 0.050052137643379, }, // Dgecon does not match Dpocon for this case. https://github.com/xianyi/OpenBLAS/issues/664. { a: []float64{ 2.9995576045549965, -2.0898894566158663, 3.965560740124006, 0, 1.9634729526261008, -2.8681002706874104, 0, 0, 5.502416670471008, }, uplo: blas.Upper, n: 3, cond: 0.024054837369015203, }, } { n := test.n a := make([]float64, len(test.a)) copy(a, test.a) lda := n uplo := test.uplo work := make([]float64, 3*n) anorm := impl.Dlansy(lapack.MaxColumnSum, uplo, n, a, lda, work) // Compute cholesky decomposition ok := impl.Dpotrf(uplo, n, a, lda) if !ok { t.Errorf("Bad test, matrix not positive definite") continue } iwork := make([]int, n) cond := impl.Dpocon(uplo, n, a, lda, anorm, work, iwork) // Error if not the same order, otherwise log the difference. if !scalar.EqualWithinAbsOrRel(cond, test.cond, 1e0, 1e0) { t.Errorf("Cond mismatch. Want %v, got %v.", test.cond, cond) } else if !scalar.EqualWithinAbsOrRel(cond, test.cond, 1e-14, 1e-14) { log.Printf("Dpocon cond mismatch. Want %v, got %v.", test.cond, cond) } } rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() // Randomized tests compared against Dgecon. for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, test := range []struct { n, lda int }{ {3, 0}, {3, 5}, } { for trial := 0; trial < 100; trial++ { n := test.n lda := test.lda if lda == 0 { lda = n } a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } // Multiply a by itself to make it symmetric positive definite. aCopy := make([]float64, len(a)) copy(aCopy, a) bi.Dgemm(blas.Trans, blas.NoTrans, n, n, n, 1, aCopy, lda, aCopy, lda, 0, a, lda) aDat := make([]float64, len(aCopy)) copy(aDat, a) aDense := make([]float64, len(a)) if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { v := a[i*lda+j] aDense[i*lda+j] = v aDense[j*lda+i] = v } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { v := a[i*lda+j] aDense[i*lda+j] = v aDense[j*lda+i] = v } } } work := make([]float64, 4*n) iwork := make([]int, n) anorm := impl.Dlansy(lapack.MaxColumnSum, uplo, n, a, lda, work) ok := impl.Dpotrf(uplo, n, a, lda) if !ok { t.Errorf("Bad test, matrix not positive definite") continue } got := impl.Dpocon(uplo, n, a, lda, anorm, work, iwork) denseNorm := impl.Dlange(lapack.MaxColumnSum, n, n, aDense, lda, work) ipiv := make([]int, n) impl.Dgetrf(n, n, aDense, lda, ipiv) want := impl.Dgecon(lapack.MaxColumnSum, n, aDense, lda, denseNorm, work, iwork) // Error if not the same order, otherwise log the difference. if !scalar.EqualWithinAbsOrRel(want, got, 1e0, 1e0) { t.Errorf("Dpocon and Dgecon mismatch. Dpocon %v, Dgecon %v.", got, want) } else if !scalar.EqualWithinAbsOrRel(want, got, 1e-14, 1e-14) { log.Printf("Dpocon and Dgecon mismatch. Dpocon %v, Dgecon %v.", got, want) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpotf2.go000066400000000000000000000054161450372207100227570ustar00rootroot00000000000000// 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 testlapack import ( "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" ) type Dpotf2er interface { Dpotf2(ul blas.Uplo, n int, a []float64, lda int) (ok bool) } func Dpotf2Test(t *testing.T, impl Dpotf2er) { for _, test := range []struct { a [][]float64 pos bool U [][]float64 }{ { a: [][]float64{ {23, 37, 34, 32}, {108, 71, 48, 48}, {109, 109, 67, 58}, {106, 107, 106, 63}, }, pos: true, U: [][]float64{ {4.795831523312719, 7.715033320111766, 7.089490077940543, 6.672461249826393}, {0, 3.387958215439679, -1.976308959006481, -1.026654004678691}, {0, 0, 3.582364210034111, 2.419258947036024}, {0, 0, 0, 3.401680257083044}, }, }, { a: [][]float64{ {8, 2}, {2, 4}, }, pos: true, U: [][]float64{ {2.82842712474619, 0.707106781186547}, {0, 1.870828693386971}, }, }, } { testDpotf2(t, impl, test.pos, test.a, test.U, len(test.a[0]), blas.Upper) testDpotf2(t, impl, test.pos, test.a, test.U, len(test.a[0])+5, blas.Upper) aT := transpose(test.a) L := transpose(test.U) testDpotf2(t, impl, test.pos, aT, L, len(test.a[0]), blas.Lower) testDpotf2(t, impl, test.pos, aT, L, len(test.a[0])+5, blas.Lower) } } func testDpotf2(t *testing.T, impl Dpotf2er, testPos bool, a, ans [][]float64, stride int, ul blas.Uplo) { aFlat := flattenTri(a, stride, ul) ansFlat := flattenTri(ans, stride, ul) pos := impl.Dpotf2(ul, len(a[0]), aFlat, stride) if pos != testPos { t.Errorf("Positive definite mismatch: Want %v, Got %v", testPos, pos) return } if testPos && !floats.EqualApprox(ansFlat, aFlat, 1e-14) { t.Errorf("Result mismatch: Want %v, Got %v", ansFlat, aFlat) } } // flattenTri with a certain stride. stride must be >= dimension. Puts repeatable // nonce values in non-accessed places func flattenTri(a [][]float64, stride int, ul blas.Uplo) []float64 { m := len(a) n := len(a[0]) if stride < n { panic("bad stride") } upper := ul == blas.Upper v := make([]float64, m*stride) count := 1000.0 for i := 0; i < m; i++ { for j := 0; j < stride; j++ { if j >= n || (upper && j < i) || (!upper && j > i) { // not accessed, so give a unique crazy number v[i*stride+j] = count count++ continue } v[i*stride+j] = a[i][j] } } return v } func transpose(a [][]float64) [][]float64 { m := len(a) n := len(a[0]) if m != n { panic("not square") } aNew := make([][]float64, m) for i := 0; i < m; i++ { aNew[i] = make([]float64, n) } for i := 0; i < m; i++ { if len(a[i]) != n { panic("bad n size") } for j := 0; j < n; j++ { aNew[j][i] = a[i][j] } } return aNew } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpotrf.go000066400000000000000000000056121450372207100230550ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" ) type Dpotrfer interface { Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool) } func DpotrfTest(t *testing.T, impl Dpotrfer) { const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for tc, test := range []struct { n int lda int }{ {1, 0}, {2, 0}, {3, 0}, {10, 0}, {30, 0}, {63, 0}, {65, 0}, {127, 0}, {129, 0}, {500, 0}, {1, 10}, {2, 10}, {3, 10}, {10, 20}, {30, 50}, {63, 100}, {65, 100}, {127, 200}, {129, 200}, {500, 600}, } { n := test.n // Random diagonal matrix D with positive entries. d := make([]float64, n) Dlatm1(d, 4, 10000, false, 1, rnd) // Construct a positive definite matrix A as // A = U * D * Uᵀ // where U is a random orthogonal matrix. lda := test.lda if lda == 0 { lda = n } a := make([]float64, n*lda) Dlagsy(n, 0, d, a, lda, rnd, make([]float64, 2*n)) aCopy := make([]float64, len(a)) copy(aCopy, a) ok := impl.Dpotrf(uplo, n, a, lda) if !ok { t.Errorf("Case %v: unexpected failure for positive definite matrix", tc) continue } switch uplo { case blas.Upper: for i := 0; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = 0 } } case blas.Lower: for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { a[i*lda+j] = 0 } } default: panic("bad uplo") } ans := make([]float64, len(a)) switch uplo { case blas.Upper: // Multiply Uᵀ * U. bi.Dsyrk(uplo, blas.Trans, n, n, 1, a, lda, 0, ans, lda) case blas.Lower: // Multiply L * Lᵀ. bi.Dsyrk(uplo, blas.NoTrans, n, n, 1, a, lda, 0, ans, lda) } match := true switch uplo { case blas.Upper: for i := 0; i < n; i++ { for j := i; j < n; j++ { if !scalar.EqualWithinAbsOrRel(ans[i*lda+j], aCopy[i*lda+j], tol, tol) { match = false } } } case blas.Lower: for i := 0; i < n; i++ { for j := 0; j <= i; j++ { if !scalar.EqualWithinAbsOrRel(ans[i*lda+j], aCopy[i*lda+j], tol, tol) { match = false } } } } if !match { t.Errorf("Case %v (uplo=%v,n=%v,lda=%v): unexpected result", tc, uplo, n, lda) } // Make one element of D negative so that A is not // positive definite, and check that Dpotrf fails. d[0] *= -1 Dlagsy(n, 0, d, a, lda, rnd, make([]float64, 2*n)) ok = impl.Dpotrf(uplo, n, a, lda) if ok { t.Errorf("Case %v: unexpected success for not positive definite matrix", tc) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpotri.go000066400000000000000000000060221450372207100230540ustar00rootroot00000000000000// Copyright ©2019 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dpotrier interface { Dpotri(uplo blas.Uplo, n int, a []float64, lda int) bool Dpotrf(uplo blas.Uplo, n int, a []float64, lda int) bool } func DpotriTest(t *testing.T, impl Dpotrier) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { name := uploToString(uplo) t.Run(name, func(t *testing.T) { // Include small and large sizes to make sure that both // unblocked and blocked paths are taken. ns := []int{0, 1, 2, 3, 4, 5, 10, 25, 31, 32, 33, 63, 64, 65, 127, 128, 129} const tol = 1e-12 bi := blas64.Implementation() rnd := rand.New(rand.NewSource(1)) for _, n := range ns { for _, lda := range []int{max(1, n), n + 11} { prefix := fmt.Sprintf("n=%v,lda=%v", n, lda) // Generate a random diagonal matrix D with positive entries. d := make([]float64, n) Dlatm1(d, 3, 10000, false, 2, rnd) // Construct a positive definite matrix A as // A = U * D * Uᵀ // where U is a random orthogonal matrix. a := make([]float64, n*lda) Dlagsy(n, 0, d, a, lda, rnd, make([]float64, 2*n)) // Create a copy of A. aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute the Cholesky factorization of A. ok := impl.Dpotrf(uplo, n, a, lda) if !ok { t.Fatalf("%v: unexpected Cholesky failure", prefix) } // Compute the inverse inv(A). ok = impl.Dpotri(uplo, n, a, lda) if !ok { t.Errorf("%v: unexpected failure", prefix) continue } // Check that the triangle of A opposite to uplo has not been modified. if uplo == blas.Upper && !sameLowerTri(n, aCopy, lda, a, lda) { t.Errorf("%v: unexpected modification in lower triangle", prefix) continue } if uplo == blas.Lower && !sameUpperTri(n, aCopy, lda, a, lda) { t.Errorf("%v: unexpected modification in upper triangle", prefix) continue } // Change notation for the sake of clarity. ainv := a ldainv := lda // Expand ainv into a full dense matrix so that we can call Dsymm below. if uplo == blas.Upper { for i := 1; i < n; i++ { for j := 0; j < i; j++ { ainv[i*ldainv+j] = ainv[j*ldainv+i] } } } else { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { ainv[i*ldainv+j] = ainv[j*ldainv+i] } } } // Compute A*inv(A) and store the result into want. ldwant := max(1, n) want := make([]float64, n*ldwant) bi.Dsymm(blas.Left, uplo, n, n, 1, aCopy, lda, ainv, ldainv, 0, want, ldwant) // Check that want is close to the identity matrix. dist := distFromIdentity(n, want, ldwant) if dist > tol { t.Errorf("%v: |A * inv(A) - I| = %v is too large", prefix, dist) } } } }) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpotrs.go000066400000000000000000000047501450372207100230740ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dpotrser interface { Dpotrs(uplo blas.Uplo, n, nrhs int, a []float64, lda int, b []float64, ldb int) Dpotrf(uplo blas.Uplo, n int, a []float64, lda int) bool } func DpotrsTest(t *testing.T, impl Dpotrser) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, n := range []int{1, 2, 5} { for _, nrhs := range []int{1, 2, 5, 10} { for _, ld := range []struct{ a, b int }{ {n, nrhs}, {n + 7, nrhs}, {n, nrhs + 3}, {n + 7, nrhs + 3}, } { // Construct a random SPD matrix A by first making a symmetric matrix // and then ensuring that it is diagonally dominant. a := nanGeneral(n, n, ld.a) for i := 0; i < n; i++ { for j := i; j < n; j++ { v := rnd.Float64() a.Data[i*a.Stride+j] = v a.Data[j*a.Stride+i] = v } } for i := 0; i < n; i++ { a.Data[i*a.Stride+i] += float64(n) } // Generate a random solution X. want := nanGeneral(n, nrhs, ld.b) for i := 0; i < n; i++ { for j := 0; j < nrhs; j++ { want.Data[i*want.Stride+j] = rnd.NormFloat64() } } // Compute the right-hand side matrix as A * X. b := nanGeneral(n, nrhs, ld.b) bi.Dgemm(blas.NoTrans, blas.NoTrans, n, nrhs, n, 1, a.Data, a.Stride, want.Data, want.Stride, 0, b.Data, b.Stride) // Compute the Cholesky decomposition of A. ok := impl.Dpotrf(uplo, n, a.Data, a.Stride) if !ok { panic("bad test") } aCopy := cloneGeneral(a) // Solve A * X = B. impl.Dpotrs(uplo, n, nrhs, a.Data, a.Stride, b.Data, b.Stride) name := fmt.Sprintf("uplo=%v,n=%v,nrhs=%v,lda=%v,ldb=%v", uplo, n, nrhs, a.Stride, b.Stride) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range modification of A", name) } if !equalApproxGeneral(a, aCopy, 0) { t.Errorf("%v: unexpected modification of A", name) } if !generalOutsideAllNaN(b) { t.Errorf("%v: out-of-range modification of B", name) } if !equalApproxGeneral(b, want, tol) { t.Errorf("%v: unexpected result\ngot %v\nwant %v", name, b, want) } } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpstf2.go000066400000000000000000000043421450372207100227600ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dpstf2er interface { Dpstf2(uplo blas.Uplo, n int, a []float64, lda int, piv []int, tol float64, work []float64) (rank int, ok bool) } func Dpstf2Test(t *testing.T, impl Dpstf2er) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { t.Run(uploToString(uplo), func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 20, 50} { for _, lda := range []int{max(1, n), n + 5} { for _, rank := range []int{int(0.7 * float64(n)), n} { dpstf2Test(t, impl, rnd, uplo, n, lda, rank) } } } }) } } func dpstf2Test(t *testing.T, impl Dpstf2er, rnd *rand.Rand, uplo blas.Uplo, n, lda, rankWant int) { const tol = 1e-14 name := fmt.Sprintf("n=%v,lda=%v", n, lda) bi := blas64.Implementation() // Generate a random, symmetric A with the given rank by applying rankWant // rank-1 updates to the zero matrix. a := make([]float64, n*lda) for i := 0; i < rankWant; i++ { x := randomSlice(n, rnd) bi.Dsyr(uplo, n, 1, x, 1, a, lda) } // Make a copy of A for storing the factorization. aFac := make([]float64, len(a)) copy(aFac, a) // Allocate a slice for pivots and fill it with invalid index values. piv := make([]int, n) for i := range piv { piv[i] = -1 } // Allocate the work slice. work := make([]float64, 2*n) // Call Dpstf2 to Compute the Cholesky factorization with complete pivoting. rank, ok := impl.Dpstf2(uplo, n, aFac, lda, piv, -1, work) if ok != (rank == n) { t.Errorf("%v: unexpected ok; got %v, want %v", name, ok, rank == n) } if rank != rankWant { t.Errorf("%v: unexpected rank; got %v, want %v", name, rank, rankWant) } if n == 0 { return } // Check that the residual |P*Uᵀ*U*Pᵀ - A| / n or |P*L*Lᵀ*Pᵀ - A| / n is // sufficiently small. resid := residualDpstrf(uplo, n, a, aFac, lda, rank, piv) if resid > tol || math.IsNaN(resid) { t.Errorf("%v: residual too large; got %v, want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dpstrf.go000066400000000000000000000112571450372207100230630ustar00rootroot00000000000000// Copyright ©2021 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dpstrfer interface { Dpstrf(uplo blas.Uplo, n int, a []float64, lda int, piv []int, tol float64, work []float64) (rank int, ok bool) } func DpstrfTest(t *testing.T, impl Dpstrfer) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { t.Run(uploToString(uplo), func(t *testing.T) { for _, n := range []int{0, 1, 2, 3, 4, 5, 31, 32, 33, 63, 64, 65, 127, 128, 129} { for _, lda := range []int{max(1, n), n + 5} { for _, rank := range []int{int(0.7 * float64(n)), n} { dpstrfTest(t, impl, rnd, uplo, n, lda, rank) } } } }) } } func dpstrfTest(t *testing.T, impl Dpstrfer, rnd *rand.Rand, uplo blas.Uplo, n, lda, rankWant int) { const tol = 1e-13 name := fmt.Sprintf("n=%v,lda=%v", n, lda) bi := blas64.Implementation() // Generate a random, symmetric A with the given rank by applying rankWant // rank-1 updates to the zero matrix. a := make([]float64, n*lda) for i := 0; i < rankWant; i++ { x := randomSlice(n, rnd) bi.Dsyr(uplo, n, 1, x, 1, a, lda) } // Make a copy of A for storing the factorization. aFac := make([]float64, len(a)) copy(aFac, a) // Allocate a slice for pivots and fill it with invalid index values. piv := make([]int, n) for i := range piv { piv[i] = -1 } // Allocate the work slice. work := make([]float64, 2*n) // Call Dpstrf to Compute the Cholesky factorization with complete pivoting. rank, ok := impl.Dpstrf(uplo, n, aFac, lda, piv, -1, work) if ok != (rank == n) { t.Errorf("%v: unexpected ok; got %v, want %v", name, ok, rank == n) } if rank != rankWant { t.Errorf("%v: unexpected rank; got %v, want %v", name, rank, rankWant) } if n == 0 { return } // Check that the residual |P*Uᵀ*U*Pᵀ - A| / n or |P*L*Lᵀ*Pᵀ - A| / n is // sufficiently small. resid := residualDpstrf(uplo, n, a, aFac, lda, rank, piv) if resid > tol || math.IsNaN(resid) { t.Errorf("%v: residual too large; got %v, want<=%v", name, resid, tol) } } func residualDpstrf(uplo blas.Uplo, n int, a, aFac []float64, lda int, rank int, piv []int) float64 { bi := blas64.Implementation() // Reconstruct the symmetric positive semi-definite matrix A from its L or U // factors and the permutation matrix P. perm := zeros(n, n, n) if uplo == blas.Upper { // Change notation. u, ldu := aFac, lda // Zero out last n-rank rows of the factor U. for i := rank; i < n; i++ { for j := i; j < n; j++ { u[i*ldu+j] = 0 } } // Extract U to aRec. aRec := zeros(n, n, n) for i := 0; i < n; i++ { for j := i; j < n; j++ { aRec.Data[i*aRec.Stride+j] = u[i*ldu+j] } } // Multiply U by Uᵀ from the left. bi.Dtrmm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, n, n, 1, u, ldu, aRec.Data, aRec.Stride) // Form P * Uᵀ * U * Pᵀ. for i := 0; i < n; i++ { for j := 0; j < n; j++ { if piv[i] > piv[j] { // Don't set the lower triangle. continue } if i <= j { perm.Data[piv[i]*perm.Stride+piv[j]] = aRec.Data[i*aRec.Stride+j] } else { perm.Data[piv[i]*perm.Stride+piv[j]] = aRec.Data[j*aRec.Stride+i] } } } // Compute the difference P*Uᵀ*U*Pᵀ - A. for i := 0; i < n; i++ { for j := i; j < n; j++ { perm.Data[i*perm.Stride+j] -= a[i*lda+j] } } } else { // Change notation. l, ldl := aFac, lda // Zero out last n-rank columns of the factor L. for i := rank; i < n; i++ { for j := rank; j <= i; j++ { l[i*ldl+j] = 0 } } // Extract L to aRec. aRec := zeros(n, n, n) for i := 0; i < n; i++ { for j := 0; j <= i; j++ { aRec.Data[i*aRec.Stride+j] = l[i*ldl+j] } } // Multiply L by Lᵀ from the right. bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.NonUnit, n, n, 1, l, ldl, aRec.Data, aRec.Stride) // Form P * L * Lᵀ * Pᵀ. for i := 0; i < n; i++ { for j := 0; j < n; j++ { if piv[i] < piv[j] { // Don't set the upper triangle. continue } if i >= j { perm.Data[piv[i]*perm.Stride+piv[j]] = aRec.Data[i*aRec.Stride+j] } else { perm.Data[piv[i]*perm.Stride+piv[j]] = aRec.Data[j*aRec.Stride+i] } } } // Compute the difference P*L*Lᵀ*Pᵀ - A. for i := 0; i < n; i++ { for j := 0; j <= i; j++ { perm.Data[i*perm.Stride+j] -= a[i*lda+j] } } } // Compute |P*Uᵀ*U*Pᵀ - A| / n or |P*L*Lᵀ*Pᵀ - A| / n. return dlansy(lapack.MaxColumnSum, uplo, n, perm.Data, perm.Stride) / float64(n) } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/drscl.go000066400000000000000000000023701450372207100226640ustar00rootroot00000000000000// 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 testlapack import ( "math" "testing" "gonum.org/v1/gonum/floats" ) type Drscler interface { Drscl(n int, a float64, x []float64, incX int) } func DrsclTest(t *testing.T, impl Drscler) { for _, test := range []struct { x []float64 a float64 }{ { x: []float64{1, 2, 3, 4, 5}, a: 4, }, { x: []float64{1, 2, 3, 4, 5}, a: math.MaxFloat64, }, { x: []float64{1, 2, 3, 4, 5}, a: 1e-307, }, } { xcopy := make([]float64, len(test.x)) copy(xcopy, test.x) // Cannot test the scaling directly because of floating point scaling issues // (the purpose of Drscl). Instead, check that scaling and scaling back // yields approximately x. If overflow or underflow occurs then the scaling // won't match. impl.Drscl(len(test.x), test.a, xcopy, 1) if floats.Equal(xcopy, test.x) { t.Errorf("x unchanged during call to drscl. a = %v, x = %v.", test.a, test.x) } impl.Drscl(len(test.x), 1/test.a, xcopy, 1) if !floats.EqualApprox(xcopy, test.x, 1e-14) { t.Errorf("x not equal after scaling and unscaling. a = %v, x = %v.", test.a, test.x) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dsteqr.go000066400000000000000000000102621450372207100230560ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dsteqrer interface { Dsteqr(compz lapack.EVComp, n int, d, e, z []float64, ldz int, work []float64) (ok bool) Dorgtrer } func DsteqrTest(t *testing.T, impl Dsteqrer) { rnd := rand.New(rand.NewSource(1)) for _, compz := range []lapack.EVComp{lapack.EVOrig, lapack.EVTridiag} { for _, test := range []struct { n, lda int }{ {1, 0}, {4, 0}, {8, 0}, {10, 0}, {2, 10}, {8, 10}, {10, 20}, } { for cas := 0; cas < 100; cas++ { n := test.n lda := test.lda if lda == 0 { lda = n } d := make([]float64, n) for i := range d { d[i] = rnd.Float64() } e := make([]float64, n-1) for i := range e { e[i] = rnd.Float64() } a := make([]float64, n*lda) for i := range a { a[i] = rnd.Float64() } dCopy := make([]float64, len(d)) copy(dCopy, d) eCopy := make([]float64, len(e)) copy(eCopy, e) aCopy := make([]float64, len(a)) copy(aCopy, a) if compz == lapack.EVOrig { uplo := blas.Upper tau := make([]float64, n) work := make([]float64, 1) impl.Dsytrd(blas.Upper, n, a, lda, d, e, tau, work, -1) work = make([]float64, int(work[0])) // Reduce A to symmetric tridiagonal form. impl.Dsytrd(uplo, n, a, lda, d, e, tau, work, len(work)) // Compute the orthogonal matrix Q. impl.Dorgtr(uplo, n, a, lda, tau, work, len(work)) } else { for i := 0; i < n; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 if i == j { a[i*lda+j] = 1 } } } } work := make([]float64, 2*n) aDecomp := make([]float64, len(a)) copy(aDecomp, a) dDecomp := make([]float64, len(d)) copy(dDecomp, d) eDecomp := make([]float64, len(e)) copy(eDecomp, e) impl.Dsteqr(compz, n, d, e, a, lda, work) dAns := make([]float64, len(d)) copy(dAns, d) var truth blas64.General if compz == lapack.EVOrig { truth = blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < n; i++ { for j := i; j < n; j++ { v := aCopy[i*lda+j] truth.Data[i*truth.Stride+j] = v truth.Data[j*truth.Stride+i] = v } } } else { truth = blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < n; i++ { truth.Data[i*truth.Stride+i] = dCopy[i] if i != n-1 { truth.Data[(i+1)*truth.Stride+i] = eCopy[i] truth.Data[i*truth.Stride+i+1] = eCopy[i] } } } V := blas64.General{ Rows: n, Cols: n, Stride: lda, Data: a, } if !eigenDecompCorrect(d, truth, V) { t.Errorf("Eigen reconstruction mismatch. fromFull = %v, n = %v", compz == lapack.EVOrig, n) } // Compare eigenvalues when not computing eigenvectors. for i := range work { work[i] = rnd.Float64() } impl.Dsteqr(lapack.EVCompNone, n, dDecomp, eDecomp, aDecomp, lda, work) if !floats.EqualApprox(d, dAns, 1e-8) { t.Errorf("Eigenvalue mismatch when eigenvectors not computed") } } } } } // eigenDecompCorrect returns whether the eigen decomposition is correct. // It checks if // // A * v ≈ λ * v // // where the eigenvalues λ are stored in values, and the eigenvectors are stored // in the columns of v. func eigenDecompCorrect(values []float64, A, V blas64.General) bool { n := A.Rows for i := 0; i < n; i++ { lambda := values[i] vector := make([]float64, n) ans2 := make([]float64, n) for j := range vector { v := V.Data[j*V.Stride+i] vector[j] = v ans2[j] = lambda * v } v := blas64.Vector{Inc: 1, Data: vector} ans1 := blas64.Vector{Inc: 1, Data: make([]float64, n)} blas64.Gemv(blas.NoTrans, 1, A, v, 0, ans1) if !floats.EqualApprox(ans1.Data, ans2, 1e-8) { return false } } return true } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dsterf.go000066400000000000000000000133121450372207100230420ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dsterfer interface { Dsteqrer Dlansyer Dsterf(n int, d, e []float64) (ok bool) } func DsterfTest(t *testing.T, impl Dsterfer) { const tol = 1e-14 // Tests with precomputed eigenvalues. for cas, test := range []struct { d []float64 e []float64 n int want []float64 }{ { d: []float64{1, 3, 4, 6}, e: []float64{2, 4, 5}, n: 4, // Computed from original Fortran code. want: []float64{11.046227528488854, 4.795922173417400, -2.546379458290125, 0.704229756383872}, }, } { n := test.n got := make([]float64, len(test.d)) copy(got, test.d) e := make([]float64, len(test.e)) copy(e, test.e) ok := impl.Dsterf(n, got, e) if !ok { t.Errorf("Case %d, n=%v: Dsterf failed", cas, n) continue } want := make([]float64, len(test.want)) copy(want, test.want) sort.Float64s(want) diff := floats.Distance(got, want, math.Inf(1)) if diff > tol { t.Errorf("Case %d, n=%v: unexpected result, |dGot-dWant|=%v", cas, n, diff) } } rnd := rand.New(rand.NewSource(1)) // Probabilistic tests. for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 10, 50} { for typ := 0; typ <= 8; typ++ { d := make([]float64, n) var e []float64 if n > 1 { e = make([]float64, n-1) } // Generate a tridiagonal matrix A. switch typ { case 0: // The zero matrix. case 1: // The identity matrix. for i := range d { d[i] = 1 } case 2: // A diagonal matrix with evenly spaced entries // 1, ..., eps and random signs. for i := 0; i < n; i++ { if i == 0 { d[i] = 1 } else { d[i] = 1 - (1-dlamchE)*float64(i)/float64(n-1) } if rnd.Float64() < 0.5 { d[i] *= -1 } } case 3, 4, 5: // A diagonal matrix with geometrically spaced entries // 1, ..., eps and random signs. for i := 0; i < n; i++ { if i == 0 { d[i] = 1 } else { d[i] = math.Pow(dlamchE, float64(i)/float64(n-1)) } if rnd.Float64() < 0.5 { d[i] *= -1 } } switch typ { case 4: // Multiply by SQRT(overflow threshold). floats.Scale(math.Sqrt(1/dlamchS), d) case 5: // Multiply by SQRT(underflow threshold). floats.Scale(math.Sqrt(dlamchS), d) } case 6: // A diagonal matrix with "clustered" entries 1, eps, ..., eps // and random signs. for i := range d { if i == 0 { d[i] = 1 } else { d[i] = dlamchE } } for i := range d { if rnd.Float64() < 0.5 { d[i] *= -1 } } case 7: // Diagonal matrix with random entries. for i := range d { d[i] = rnd.NormFloat64() } case 8: // Random symmetric tridiagonal matrix. for i := range d { d[i] = rnd.NormFloat64() } for i := range e { e[i] = rnd.NormFloat64() } } eCopy := make([]float64, len(e)) copy(eCopy, e) name := fmt.Sprintf("n=%d,type=%d", n, typ) // Compute the eigenvalues of A using Dsterf. dGot := make([]float64, len(d)) copy(dGot, d) ok := impl.Dsterf(n, dGot, e) if !ok { t.Errorf("%v: Dsterf failed", name) continue } if n == 0 { continue } // Test that the eigenvalues are sorted. if !sort.Float64sAreSorted(dGot) { t.Errorf("%v: eigenvalues are not sorted", name) continue } // Compute the expected eigenvalues of A using Dsteqr. dWant := make([]float64, len(d)) copy(dWant, d) copy(e, eCopy) z := nanGeneral(n, n, n) ok = impl.Dsteqr(lapack.EVTridiag, n, dWant, e, z.Data, z.Stride, make([]float64, 2*n)) if !ok { t.Errorf("%v: computing reference solution using Dsteqr failed", name) continue } if resid := residualOrthogonal(z, false); resid > tol*float64(n) { t.Errorf("%v: Z is not orthogonal; resid=%v, want<=%v", name, resid, tol*float64(n)) } // Check whether eigenvalues from Dsteqr and Dsterf (which use // different algorithms) are equal. var diff, dMax float64 for i, di := range dGot { diffAbs := math.Abs(di - dWant[i]) diff = math.Max(diff, diffAbs) dAbs := math.Max(math.Abs(di), math.Abs(dWant[i])) dMax = math.Max(dMax, dAbs) } dMax = math.Max(dlamchS, dMax) if diff > tol*dMax { t.Errorf("%v: unexpected result; |dGot-dWant|=%v", name, diff) } // Construct A as a symmetric dense matrix and compute its 1-norm. copy(e, eCopy) lda := n a := make([]float64, n*lda) var anorm, tmp float64 for i := 0; i < n-1; i++ { a[i*lda+i] = d[i] a[i*lda+i+1] = e[i] tmp2 := math.Abs(e[i]) anorm = math.Max(anorm, math.Abs(d[i])+tmp+tmp2) tmp = tmp2 } a[(n-1)*lda+n-1] = d[n-1] anorm = math.Max(anorm, math.Abs(d[n-1])+tmp) // Compute A - Z D Zᵀ. The result should be the zero matrix. bi := blas64.Implementation() for i := 0; i < n; i++ { bi.Dsyr(blas.Upper, n, -dGot[i], z.Data[i:], z.Stride, a, lda) } // Compute |A - Z D Zᵀ|. wnorm := impl.Dlansy(lapack.MaxColumnSum, blas.Upper, n, a, lda, make([]float64, n)) // Compute diff := |A - Z D Zᵀ| / (|A| N). if anorm > wnorm { diff = wnorm / anorm / float64(n) } else { if anorm < 1 { diff = math.Min(wnorm, float64(n)*anorm) / anorm / float64(n) } else { diff = math.Min(wnorm/anorm, float64(n)) / float64(n) } } // Check whether diff is small. if diff > tol { t.Errorf("%v: unexpected result; |A - Z D Zᵀ|/(|A| n)=%v", name, diff) } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dsyev.go000066400000000000000000000050451450372207100227110ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dsyever interface { Dsyev(jobz lapack.EVJob, uplo blas.Uplo, n int, a []float64, lda int, w, work []float64, lwork int) (ok bool) } func DsyevTest(t *testing.T, impl Dsyever) { rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, test := range []struct { n, lda int }{ {1, 0}, {2, 0}, {5, 0}, {10, 0}, {100, 0}, {1, 5}, {2, 5}, {5, 10}, {10, 20}, {100, 110}, } { for cas := 0; cas < 10; cas++ { n := test.n lda := test.lda if lda == 0 { lda = n } a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } aCopy := make([]float64, len(a)) copy(aCopy, a) w := make([]float64, n) for i := range w { w[i] = rnd.NormFloat64() } work := make([]float64, 1) impl.Dsyev(lapack.EVCompute, uplo, n, a, lda, w, work, -1) work = make([]float64, int(work[0])) impl.Dsyev(lapack.EVCompute, uplo, n, a, lda, w, work, len(work)) // Check that the decomposition is correct orig := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { v := aCopy[i*lda+j] orig.Data[i*orig.Stride+j] = v orig.Data[j*orig.Stride+i] = v } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { v := aCopy[i*lda+j] orig.Data[i*orig.Stride+j] = v orig.Data[j*orig.Stride+i] = v } } } V := blas64.General{ Rows: n, Cols: n, Stride: lda, Data: a, } if !eigenDecompCorrect(w, orig, V) { t.Errorf("Decomposition mismatch") } // Check that the decomposition is correct when the eigenvectors // are not computed. wAns := make([]float64, len(w)) copy(wAns, w) copy(a, aCopy) for i := range w { w[i] = rnd.Float64() } for i := range work { work[i] = rnd.Float64() } impl.Dsyev(lapack.EVNone, uplo, n, a, lda, w, work, len(work)) if !floats.EqualApprox(w, wAns, 1e-8) { t.Errorf("Eigenvalue mismatch when vectors not computed") } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dsytd2.go000066400000000000000000000075221450372207100227720ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dsytd2er interface { Dsytd2(uplo blas.Uplo, n int, a []float64, lda int, d, e, tau []float64) } func Dsytd2Test(t *testing.T, impl Dsytd2er) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, test := range []struct { n, lda int }{ {3, 0}, {4, 0}, {5, 0}, {3, 10}, {4, 10}, {5, 10}, } { n := test.n lda := test.lda if lda == 0 { lda = n } a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } aCopy := make([]float64, len(a)) copy(aCopy, a) d := make([]float64, n) for i := range d { d[i] = math.NaN() } e := make([]float64, n-1) for i := range e { e[i] = math.NaN() } tau := make([]float64, n-1) for i := range tau { tau[i] = math.NaN() } impl.Dsytd2(uplo, n, a, lda, d, e, tau) // Construct Q qMat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } qCopy := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, len(qMat.Data)), } // Set Q to I. for i := 0; i < n; i++ { qMat.Data[i*qMat.Stride+i] = 1 } for i := 0; i < n-1; i++ { hMat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } // Set H to I. for i := 0; i < n; i++ { hMat.Data[i*hMat.Stride+i] = 1 } var vi blas64.Vector if uplo == blas.Upper { vi = blas64.Vector{ Inc: 1, Data: make([]float64, n), } for j := 0; j < i; j++ { vi.Data[j] = a[j*lda+i+1] } vi.Data[i] = 1 } else { vi = blas64.Vector{ Inc: 1, Data: make([]float64, n), } vi.Data[i+1] = 1 for j := i + 2; j < n; j++ { vi.Data[j] = a[j*lda+i] } } blas64.Ger(-tau[i], vi, vi, hMat) copy(qCopy.Data, qMat.Data) // Multiply q by the new h. if uplo == blas.Upper { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hMat, qCopy, 0, qMat) } else { blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, hMat, 0, qMat) } } if resid := residualOrthogonal(qMat, false); resid > tol { t.Errorf("Q is not orthogonal; resid=%v, want<=%v", resid, tol) } // Compute Qᵀ * A * Q. aMat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, len(a)), } for i := 0; i < n; i++ { for j := i; j < n; j++ { v := aCopy[i*lda+j] if uplo == blas.Lower { v = aCopy[j*lda+i] } aMat.Data[i*aMat.Stride+j] = v aMat.Data[j*aMat.Stride+i] = v } } tmp := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } ans := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } blas64.Gemm(blas.Trans, blas.NoTrans, 1, qMat, aMat, 0, tmp) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, qMat, 0, ans) // Compare with T. tMat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < n-1; i++ { tMat.Data[i*tMat.Stride+i] = d[i] tMat.Data[i*tMat.Stride+i+1] = e[i] tMat.Data[(i+1)*tMat.Stride+i] = e[i] } tMat.Data[(n-1)*tMat.Stride+n-1] = d[n-1] same := true for i := 0; i < n; i++ { for j := 0; j < n; j++ { if math.Abs(ans.Data[i*ans.Stride+j]-tMat.Data[i*tMat.Stride+j]) > tol { same = false } } } if !same { t.Errorf("Matrix answer mismatch") } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dsytrd.go000066400000000000000000000077721450372207100231010ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dsytrder interface { Dsytrd(uplo blas.Uplo, n int, a []float64, lda int, d, e, tau, work []float64, lwork int) Dorgqr(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) Dorgql(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) } func DsytrdTest(t *testing.T, impl Dsytrder) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for tc, test := range []struct { n, lda int }{ {1, 0}, {2, 0}, {3, 0}, {4, 0}, {10, 0}, {50, 0}, {100, 0}, {150, 0}, {300, 0}, {1, 3}, {2, 3}, {3, 7}, {4, 9}, {10, 20}, {50, 70}, {100, 120}, {150, 170}, {300, 320}, } { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { n := test.n lda := test.lda if lda == 0 { lda = n } a := randomGeneral(n, n, lda, rnd) for i := 1; i < n; i++ { for j := 0; j < i; j++ { a.Data[i*a.Stride+j] = a.Data[j*a.Stride+i] } } aCopy := cloneGeneral(a) d := nanSlice(n) e := nanSlice(n - 1) tau := nanSlice(n - 1) var lwork int switch wl { case minimumWork: lwork = 1 case mediumWork: work := make([]float64, 1) impl.Dsytrd(uplo, n, a.Data, a.Stride, d, e, tau, work, -1) lwork = (int(work[0]) + 1) / 2 lwork = max(1, lwork) case optimumWork: work := make([]float64, 1) impl.Dsytrd(uplo, n, a.Data, a.Stride, d, e, tau, work, -1) lwork = int(work[0]) } work := make([]float64, lwork) impl.Dsytrd(uplo, n, a.Data, a.Stride, d, e, tau, work, lwork) prefix := fmt.Sprintf("Case #%v: uplo=%c,n=%v,lda=%v,work=%v", tc, uplo, n, lda, wl) if !generalOutsideAllNaN(a) { t.Errorf("%v: out-of-range write to A", prefix) } // Extract Q by doing what Dorgtr does. q := cloneGeneral(a) if uplo == blas.Upper { for j := 0; j < n-1; j++ { for i := 0; i < j; i++ { q.Data[i*q.Stride+j] = q.Data[i*q.Stride+j+1] } q.Data[(n-1)*q.Stride+j] = 0 } for i := 0; i < n-1; i++ { q.Data[i*q.Stride+n-1] = 0 } q.Data[(n-1)*q.Stride+n-1] = 1 if n > 1 { work = make([]float64, n-1) impl.Dorgql(n-1, n-1, n-1, q.Data, q.Stride, tau, work, len(work)) } } else { for j := n - 1; j > 0; j-- { q.Data[j] = 0 for i := j + 1; i < n; i++ { q.Data[i*q.Stride+j] = q.Data[i*q.Stride+j-1] } } q.Data[0] = 1 for i := 1; i < n; i++ { q.Data[i*q.Stride] = 0 } if n > 1 { work = make([]float64, n-1) impl.Dorgqr(n-1, n-1, n-1, q.Data[q.Stride+1:], q.Stride, tau, work, len(work)) } } if resid := residualOrthogonal(q, false); resid > tol*float64(n) { t.Errorf("%v: Q is not orthogonal; resid=%v, want<=%v", prefix, resid, tol*float64(n)) } // Construct symmetric tridiagonal T from d and e. tMat := zeros(n, n, n) for i := 0; i < n; i++ { tMat.Data[i*tMat.Stride+i] = d[i] } if uplo == blas.Upper { for j := 1; j < n; j++ { tMat.Data[(j-1)*tMat.Stride+j] = e[j-1] tMat.Data[j*tMat.Stride+j-1] = e[j-1] } } else { for j := 0; j < n-1; j++ { tMat.Data[(j+1)*tMat.Stride+j] = e[j] tMat.Data[j*tMat.Stride+j+1] = e[j] } } // Compute Qᵀ*A*Q - T. qa := zeros(n, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, aCopy, 0, qa) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qa, q, -1, tMat) // Check that |Qᵀ*A*Q - T| is small. resid := dlange(lapack.MaxColumnSum, n, n, tMat.Data, tMat.Stride) if resid > tol*float64(n) { t.Errorf("%v: |Qᵀ*A*Q - T|=%v, want<=%v", prefix, resid, tol*float64(n)) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtbtrs.go000066400000000000000000000075321450372207100230640ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dtbtrser interface { Dtbtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, kd, nrhs int, a []float64, lda int, b []float64, ldb int) bool } func DtbtrsTest(t *testing.T, impl Dtbtrser) { rnd := rand.New(rand.NewSource(1)) for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { name := transToString(trans) t.Run(name, func(t *testing.T) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 23} { for _, kd := range []int{0, 1, 2, n / 2, max(0, n-1), n, n + 5} { for _, nrhs := range []int{0, 1, 2, 3, 4, 5} { for _, lda := range []int{kd + 1, kd + 3} { for _, ldb := range []int{max(1, nrhs), nrhs + 3} { if diag == blas.Unit { dtbtrsTest(t, impl, rnd, uplo, trans, diag, n, kd, nrhs, lda, ldb, false) } else { dtbtrsTest(t, impl, rnd, uplo, trans, diag, n, kd, nrhs, lda, ldb, true) dtbtrsTest(t, impl, rnd, uplo, trans, diag, n, kd, nrhs, lda, ldb, false) } } } } } } } } }) } } func dtbtrsTest(t *testing.T, impl Dtbtrser, rnd *rand.Rand, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, kd, nrhs int, lda, ldb int, singular bool) { if singular && diag == blas.Unit { panic("blas.Unit triangular matrix cannot be singular") } const tol = 1e-14 if n == 0 { singular = false } name := fmt.Sprintf("uplo=%v,diag=%v,n=%v,kd=%v,nrhs=%v,lda=%v,ldb=%v,sing=%v", string(uplo), string(diag), n, kd, nrhs, lda, ldb, singular) // Generate a random triangular matrix A. One of its triangles won't be // referenced. a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } if singular { i := rnd.Intn(n) if uplo == blas.Upper { a[i*lda] = 0 } else { a[i*lda+kd] = 0 } } aCopy := make([]float64, len(a)) copy(aCopy, a) // Generate a random solution matrix X. x := make([]float64, n*ldb) for i := range x { x[i] = rnd.NormFloat64() } // Generate the right-hand side B as A * X or Aᵀ * X. b := make([]float64, len(x)) copy(b, x) bi := blas64.Implementation() if n > 0 { for j := 0; j < nrhs; j++ { bi.Dtbmv(uplo, trans, diag, n, kd, a, lda, b[j:], ldb) } } got := make([]float64, len(b)) copy(got, b) ok := impl.Dtbtrs(uplo, trans, diag, n, kd, nrhs, a, lda, got, ldb) if !floats.Equal(a, aCopy) { t.Errorf("%v: unexpected modification of A", name) } if ok == singular { t.Errorf("%v: misdetected singular matrix, ok=%v", name, ok) } if !ok { if !floats.Equal(got, b) { t.Errorf("%v: unexpected modification of B when singular", name) } return } if n == 0 || nrhs == 0 { return } work := make([]float64, n) // Compute the 1-norm of A or Aᵀ. var aNorm float64 if trans == blas.NoTrans { aNorm = dlantb(lapack.MaxColumnSum, uplo, diag, n, kd, a, lda, work) } else { aNorm = dlantb(lapack.MaxRowSum, uplo, diag, n, kd, a, lda, work) } // Compute the maximum over the number of right-hand sides of // |op(A)*x-b| / (|op(A)| * |x|) var resid float64 for j := 0; j < nrhs; j++ { bi.Dcopy(n, got[j:], ldb, work, 1) bi.Dtbmv(uplo, trans, diag, n, kd, a, lda, work, 1) bi.Daxpy(n, -1, b[j:], ldb, work, 1) rjNorm := bi.Dasum(n, work, 1) xNorm := bi.Dasum(n, got[j:], ldb) resid = math.Max(resid, rjNorm/aNorm/xNorm) } if resid > tol { t.Errorf("%v: unexpected result; resid=%v,want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtgsja.go000066400000000000000000000125461450372207100230370ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/lapack" ) type Dtgsjaer interface { Dlanger Dtgsja(jobU, jobV, jobQ lapack.GSVDJob, m, p, n, k, l int, a []float64, lda int, b []float64, ldb int, tola, tolb float64, alpha, beta, u []float64, ldu int, v []float64, ldv int, q []float64, ldq int, work []float64) (cycles int, ok bool) } func DtgsjaTest(t *testing.T, impl Dtgsjaer) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { m, p, n, k, l, lda, ldb, ldu, ldv, ldq int ok bool }{ {m: 5, p: 5, n: 5, k: 2, l: 2, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 5, k: 4, l: 1, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 10, k: 2, l: 2, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 10, k: 4, l: 1, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 10, k: 4, l: 2, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 5, n: 5, k: 2, l: 2, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 5, n: 5, k: 4, l: 1, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 10, n: 10, k: 5, l: 3, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 10, p: 10, n: 10, k: 6, l: 4, lda: 0, ldb: 0, ldu: 0, ldv: 0, ldq: 0, ok: true}, {m: 5, p: 5, n: 5, k: 2, l: 2, lda: 10, ldb: 10, ldu: 10, ldv: 10, ldq: 10, ok: true}, {m: 5, p: 5, n: 5, k: 4, l: 1, lda: 10, ldb: 10, ldu: 10, ldv: 10, ldq: 10, ok: true}, {m: 5, p: 5, n: 10, k: 2, l: 2, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20, ok: true}, {m: 5, p: 5, n: 10, k: 4, l: 1, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20, ok: true}, {m: 5, p: 5, n: 10, k: 4, l: 2, lda: 20, ldb: 20, ldu: 10, ldv: 10, ldq: 20, ok: true}, {m: 10, p: 5, n: 5, k: 2, l: 2, lda: 10, ldb: 10, ldu: 20, ldv: 10, ldq: 10, ok: true}, {m: 10, p: 5, n: 5, k: 4, l: 1, lda: 10, ldb: 10, ldu: 20, ldv: 10, ldq: 10, ok: true}, {m: 10, p: 10, n: 10, k: 5, l: 3, lda: 20, ldb: 20, ldu: 20, ldv: 20, ldq: 20, ok: true}, {m: 10, p: 10, n: 10, k: 6, l: 4, lda: 20, ldb: 20, ldu: 20, ldv: 20, ldq: 20, ok: true}, } { m := test.m p := test.p n := test.n k := test.k l := test.l lda := test.lda if lda == 0 { lda = n } ldb := test.ldb if ldb == 0 { ldb = n } ldu := test.ldu if ldu == 0 { ldu = m } ldv := test.ldv if ldv == 0 { ldv = p } ldq := test.ldq if ldq == 0 { ldq = n } a := blockedUpperTriGeneral(m, n, k, l, lda, true, rnd) aCopy := cloneGeneral(a) b := blockedUpperTriGeneral(p, n, k, l, ldb, false, rnd) bCopy := cloneGeneral(b) tola := float64(max(m, n)) * impl.Dlange(lapack.Frobenius, m, n, a.Data, a.Stride, nil) * dlamchE tolb := float64(max(p, n)) * impl.Dlange(lapack.Frobenius, p, n, b.Data, b.Stride, nil) * dlamchE alpha := make([]float64, n) beta := make([]float64, n) work := make([]float64, 2*n) u := nanGeneral(m, m, ldu) v := nanGeneral(p, p, ldv) q := nanGeneral(n, n, ldq) _, ok := impl.Dtgsja(lapack.GSVDUnit, lapack.GSVDUnit, lapack.GSVDUnit, m, p, n, k, l, a.Data, a.Stride, b.Data, b.Stride, tola, tolb, alpha, beta, u.Data, u.Stride, v.Data, v.Stride, q.Data, q.Stride, work) if !ok { if test.ok { t.Errorf("test %d unexpectedly did not converge", cas) } continue } // Check orthogonality of U, V and Q. if resid := residualOrthogonal(u, false); resid > tol { t.Errorf("Case %v: U is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } if resid := residualOrthogonal(v, false); resid > tol { t.Errorf("Case %v: V is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case %v: Q is not orthogonal; resid=%v, want<=%v", cas, resid, tol) } // Check C^2 + S^2 = I. var elements []float64 if m-k-l >= 0 { elements = alpha[k : k+l] } else { elements = alpha[k:m] } for i := range elements { i += k d := alpha[i]*alpha[i] + beta[i]*beta[i] if !scalar.EqualWithinAbsOrRel(d, 1, tol, tol) { t.Errorf("test %d: alpha_%d^2 + beta_%d^2 != 1: got: %v", cas, i, i, d) } } zeroR, d1, d2 := constructGSVDresults(n, p, m, k, l, a, b, alpha, beta) // Check Uᵀ*A*Q = D1*[ 0 R ]. uTmp := nanGeneral(m, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, u, aCopy, 0, uTmp) uAns := nanGeneral(m, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, uTmp, q, 0, uAns) d10r := nanGeneral(m, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, d1, zeroR, 0, d10r) if !equalApproxGeneral(uAns, d10r, tol) { t.Errorf("test %d: Uᵀ*A*Q != D1*[ 0 R ]\nUᵀ*A*Q:\n%+v\nD1*[ 0 R ]:\n%+v", cas, uAns, d10r) } // Check Vᵀ*B*Q = D2*[ 0 R ]. vTmp := nanGeneral(p, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, v, bCopy, 0, vTmp) vAns := nanGeneral(p, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, vTmp, q, 0, vAns) d20r := nanGeneral(p, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, d2, zeroR, 0, d20r) if !equalApproxGeneral(vAns, d20r, tol) { t.Errorf("test %d: Vᵀ*B*Q != D2*[ 0 R ]\nVᵀ*B*Q:\n%+v\nD2*[ 0 R ]:\n%+v", cas, vAns, d20r) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtrcon.go000066400000000000000000000071231450372207100230470ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dtrconer interface { Dtrcon(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int, work []float64, iwork []int) float64 Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) bool Dlantr(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 } func DtrconTest(t *testing.T, impl Dtrconer) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50} { for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, lda := range []int{max(1, n), n + 3} { for _, mattype := range []int{0, 1, 2} { dtrconTest(t, impl, rnd, uplo, diag, n, lda, mattype) } } } } } } func dtrconTest(t *testing.T, impl Dtrconer, rnd *rand.Rand, uplo blas.Uplo, diag blas.Diag, n, lda, mattype int) { const ratioThresh = 10 a := make([]float64, max(0, (n-1)*lda+n)) for i := range a { a[i] = rnd.Float64() } switch mattype { default: panic("bad mattype") case 0: // Matrix filled with consecutive integer values. // For lapack.MaxRowSum norm (infinity-norm) these matrices // sometimes lead to a slightly inaccurate estimate of the condition // number. c := 2.0 for i := 0; i < n; i++ { for j := 0; j < n; j++ { a[i*lda+j] = c c += 1 } } case 1: // Identity matrix. if uplo == blas.Upper { for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { a[i*lda+j] = 0 } } } else { for i := 0; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = 0 } } } if diag == blas.NonUnit { for i := 0; i < n; i++ { a[i*lda+i] = 1 } } case 2: // Matrix filled with random values uniformly in [-1,1). // These matrices often lead to a slightly inaccurate estimate // of the condition number. for i := 0; i < n; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 2*rnd.Float64() - 1 } } } aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute the inverse A^{-1}. aInv := make([]float64, len(a)) copy(aInv, a) ok := impl.Dtrtri(uplo, diag, n, aInv, lda) if !ok { t.Fatalf("uplo=%v,diag=%v,n=%v,lda=%v,mattype=%v: bad matrix, Dtrtri failed", string(uplo), string(diag), n, lda, mattype) } work := make([]float64, 3*n) iwork := make([]int, n) for _, norm := range []lapack.MatrixNorm{lapack.MaxColumnSum, lapack.MaxRowSum} { name := fmt.Sprintf("norm=%v,uplo=%v,diag=%v,n=%v,lda=%v,mattype=%v", string(norm), string(uplo), string(diag), n, lda, mattype) // Compute the norm of A and A^{-1}. aNorm := impl.Dlantr(norm, uplo, diag, n, n, a, lda, work) aInvNorm := impl.Dlantr(norm, uplo, diag, n, n, aInv, lda, work) // Compute a good estimate of the condition number // rcondWant := 1/(norm(A) * norm(inv(A))) rcondWant := 1.0 if aNorm > 0 && aInvNorm > 0 { rcondWant = 1 / aNorm / aInvNorm } // Compute an estimate of rcond using Dtrcon. rcondGot := impl.Dtrcon(norm, uplo, diag, n, a, lda, work, iwork) if !floats.Equal(a, aCopy) { t.Errorf("%v: unexpected modification of a", name) } ratio := rCondTestRatio(rcondGot, rcondWant) if ratio >= ratioThresh { t.Errorf("%v: unexpected value of rcond; got=%v, want=%v (ratio=%v)", name, rcondGot, rcondWant, ratio) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtrevc3.go000066400000000000000000000276241450372207100231400ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dtrevc3er interface { Dtrevc3(side lapack.EVSide, howmny lapack.EVHowMany, selected []bool, n int, t []float64, ldt int, vl []float64, ldvl int, vr []float64, ldvr int, mm int, work []float64, lwork int) int } func Dtrevc3Test(t *testing.T, impl Dtrevc3er) { rnd := rand.New(rand.NewSource(1)) for _, side := range []lapack.EVSide{lapack.EVRight, lapack.EVLeft, lapack.EVBoth} { var name string switch side { case lapack.EVRight: name = "EVRigth" case lapack.EVLeft: name = "EVLeft" case lapack.EVBoth: name = "EVBoth" } t.Run(name, func(t *testing.T) { runDtrevc3Test(t, impl, rnd, side) }) } } func runDtrevc3Test(t *testing.T, impl Dtrevc3er, rnd *rand.Rand, side lapack.EVSide) { for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 7, 10, 34} { for _, extra := range []int{0, 11} { for _, optwork := range []bool{true, false} { for cas := 0; cas < 10; cas++ { dtrevc3Test(t, impl, side, n, extra, optwork, rnd) } } } } } // dtrevc3Test tests Dtrevc3 by generating a random matrix T in Schur canonical // form and performing the following checks: // 1. Compute all eigenvectors of T and check that they are indeed correctly // normalized eigenvectors // 2. Compute selected eigenvectors and check that they are exactly equal to // eigenvectors from check 1. // 3. Compute all eigenvectors multiplied into a matrix Q and check that the // result is equal to eigenvectors from step 1 multiplied by Q and scaled // appropriately. func dtrevc3Test(t *testing.T, impl Dtrevc3er, side lapack.EVSide, n, extra int, optwork bool, rnd *rand.Rand) { const tol = 1e-15 name := fmt.Sprintf("n=%d,extra=%d,optwk=%v", n, extra, optwork) right := side != lapack.EVLeft left := side != lapack.EVRight // Generate a random matrix in Schur canonical form possibly with tiny or zero eigenvalues. // Zero elements of wi signify a real eigenvalue. tmat, wr, wi := randomSchurCanonical(n, n+extra, true, rnd) tmatCopy := cloneGeneral(tmat) // 1. Compute all eigenvectors of T and check that they are indeed correctly // normalized eigenvectors howmny := lapack.EVAll var vr, vl blas64.General if right { // Fill VR and VL with NaN because they should be completely overwritten in Dtrevc3. vr = nanGeneral(n, n, n+extra) } if left { vl = nanGeneral(n, n, n+extra) } var work []float64 if optwork { work = []float64{0} impl.Dtrevc3(side, howmny, nil, n, tmat.Data, tmat.Stride, vl.Data, max(1, vl.Stride), vr.Data, max(1, vr.Stride), n, work, -1) work = make([]float64, int(work[0])) } else { work = make([]float64, max(1, 3*n)) } mGot := impl.Dtrevc3(side, howmny, nil, n, tmat.Data, tmat.Stride, vl.Data, max(1, vl.Stride), vr.Data, max(1, vr.Stride), n, work, len(work)) if !generalOutsideAllNaN(tmat) { t.Errorf("%v: out-of-range write to T", name) } if !equalGeneral(tmat, tmatCopy) { t.Errorf("%v: unexpected modification of T", name) } if !generalOutsideAllNaN(vr) { t.Errorf("%v: out-of-range write to VR", name) } if !generalOutsideAllNaN(vl) { t.Errorf("%v: out-of-range write to VL", name) } mWant := n if mGot != mWant { t.Errorf("%v: unexpected value of m=%d, want %d", name, mGot, mWant) } if right { resid := residualRightEV(tmat, vr, wr, wi) if resid > tol { t.Errorf("%v: unexpected right eigenvectors; residual=%v, want<=%v", name, resid, tol) } resid = residualEVNormalization(vr, wi) if resid > tol { t.Errorf("%v: unexpected normalization of right eigenvectors; residual=%v, want<=%v", name, resid, tol) } } if left { resid := residualLeftEV(tmat, vl, wr, wi) if resid > tol { t.Errorf("%v: unexpected left eigenvectors; residual=%v, want<=%v", name, resid, tol) } resid = residualEVNormalization(vl, wi) if resid > tol { t.Errorf("%v: unexpected normalization of left eigenvectors; residual=%v, want<=%v", name, resid, tol) } } // 2. Compute selected eigenvectors and check that they are exactly equal to // eigenvectors from check 1. howmny = lapack.EVSelected // Follow DCHKHS and select last max(1,n/4) real, max(1,n/4) complex // eigenvectors instead of selecting them randomly. selected := make([]bool, n) selectedWant := make([]bool, n) var nselr, nselc int for j := n - 1; j > 0; { if wi[j] == 0 { if nselr < max(1, n/4) { nselr++ selected[j] = true selectedWant[j] = true } j-- } else { if nselc < max(1, n/4) { nselc++ // Select all columns to check that Dtrevc3 normalizes 'selected' correctly. selected[j] = true selected[j-1] = true selectedWant[j] = false selectedWant[j-1] = true } j -= 2 } } mWant = nselr + 2*nselc var vrSel, vlSel blas64.General if right { vrSel = nanGeneral(n, mWant, n+extra) } if left { vlSel = nanGeneral(n, mWant, n+extra) } if optwork { // Reallocate optimal work in case it depends on howmny and selected. work = []float64{0} impl.Dtrevc3(side, howmny, selected, n, tmat.Data, tmat.Stride, vlSel.Data, max(1, vlSel.Stride), vrSel.Data, max(1, vrSel.Stride), mWant, work, -1) work = make([]float64, int(work[0])) } mGot = impl.Dtrevc3(side, howmny, selected, n, tmat.Data, tmat.Stride, vlSel.Data, max(1, vlSel.Stride), vrSel.Data, max(1, vrSel.Stride), mWant, work, len(work)) if !generalOutsideAllNaN(tmat) { t.Errorf("%v: out-of-range write to T", name) } if !equalGeneral(tmat, tmatCopy) { t.Errorf("%v: unexpected modification of T", name) } if !generalOutsideAllNaN(vrSel) { t.Errorf("%v: out-of-range write to selected VR", name) } if !generalOutsideAllNaN(vlSel) { t.Errorf("%v: out-of-range write to selected VL", name) } if mGot != mWant { t.Errorf("%v: unexpected value of selected m=%d, want %d", name, mGot, mWant) } for i := range selected { if selected[i] != selectedWant[i] { t.Errorf("%v: unexpected selected[%v]", name, i) } } // Check that selected columns of vrSel are equal to the corresponding // columns of vr. var k int match := true if right { loopVR: for j := 0; j < n; j++ { if selected[j] && wi[j] == 0 { for i := 0; i < n; i++ { if vrSel.Data[i*vrSel.Stride+k] != vr.Data[i*vr.Stride+j] { match = false break loopVR } } k++ } else if selected[j] && wi[j] != 0 { for i := 0; i < n; i++ { if vrSel.Data[i*vrSel.Stride+k] != vr.Data[i*vr.Stride+j] || vrSel.Data[i*vrSel.Stride+k+1] != vr.Data[i*vr.Stride+j+1] { match = false break loopVR } } k += 2 } } } if !match { t.Errorf("%v: unexpected selected VR", name) } // Check that selected columns of vlSel are equal to the corresponding // columns of vl. match = true k = 0 if left { loopVL: for j := 0; j < n; j++ { if selected[j] && wi[j] == 0 { for i := 0; i < n; i++ { if vlSel.Data[i*vlSel.Stride+k] != vl.Data[i*vl.Stride+j] { match = false break loopVL } } k++ } else if selected[j] && wi[j] != 0 { for i := 0; i < n; i++ { if vlSel.Data[i*vlSel.Stride+k] != vl.Data[i*vl.Stride+j] || vlSel.Data[i*vlSel.Stride+k+1] != vl.Data[i*vl.Stride+j+1] { match = false break loopVL } } k += 2 } } } if !match { t.Errorf("%v: unexpected selected VL", name) } // 3. Compute all eigenvectors multiplied into a matrix Q and check that the // result is equal to eigenvectors from step 1 multiplied by Q and scaled // appropriately. howmny = lapack.EVAllMulQ var vrMul, qr blas64.General var vlMul, ql blas64.General if right { vrMul = randomGeneral(n, n, n+extra, rnd) qr = cloneGeneral(vrMul) } if left { vlMul = randomGeneral(n, n, n+extra, rnd) ql = cloneGeneral(vlMul) } if optwork { // Reallocate optimal work in case it depends on howmny and selected. work = []float64{0} impl.Dtrevc3(side, howmny, nil, n, tmat.Data, tmat.Stride, vlMul.Data, max(1, vlMul.Stride), vrMul.Data, max(1, vrMul.Stride), n, work, -1) work = make([]float64, int(work[0])) } mGot = impl.Dtrevc3(side, howmny, selected, n, tmat.Data, tmat.Stride, vlMul.Data, max(1, vlMul.Stride), vrMul.Data, max(1, vrMul.Stride), n, work, len(work)) if !generalOutsideAllNaN(tmat) { t.Errorf("%v: out-of-range write to T", name) } if !equalGeneral(tmat, tmatCopy) { t.Errorf("%v: unexpected modification of T", name) } if !generalOutsideAllNaN(vrMul) { t.Errorf("%v: out-of-range write to VRMul", name) } if !generalOutsideAllNaN(vlMul) { t.Errorf("%v: out-of-range write to VLMul", name) } mWant = n if mGot != mWant { t.Errorf("%v: unexpected value of m=%d, want %d", name, mGot, mWant) } if right { // Compute Q * VR explicitly and normalize to match Dtrevc3 output. qvWant := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qr, vr, 0, qvWant) normalizeEV(qvWant, wi) // Compute the difference between Dtrevc3 output and Q * VR. r := zeros(n, n, n) for i := 0; i < n; i++ { for j := 0; j < n; j++ { r.Data[i*r.Stride+j] = vrMul.Data[i*vrMul.Stride+j] - qvWant.Data[i*qvWant.Stride+j] } } qvNorm := dlange(lapack.MaxColumnSum, n, n, qvWant.Data, qvWant.Stride) resid := dlange(lapack.MaxColumnSum, n, n, r.Data, r.Stride) / qvNorm / float64(n) if resid > tol { t.Errorf("%v: unexpected VRMul; resid=%v, want <=%v", name, resid, tol) } } if left { // Compute Q * VL explicitly and normalize to match Dtrevc3 output. qvWant := zeros(n, n, n) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, ql, vl, 0, qvWant) normalizeEV(qvWant, wi) // Compute the difference between Dtrevc3 output and Q * VL. r := zeros(n, n, n) for i := 0; i < n; i++ { for j := 0; j < n; j++ { r.Data[i*r.Stride+j] = vlMul.Data[i*vlMul.Stride+j] - qvWant.Data[i*qvWant.Stride+j] } } qvNorm := dlange(lapack.MaxColumnSum, n, n, qvWant.Data, qvWant.Stride) resid := dlange(lapack.MaxColumnSum, n, n, r.Data, r.Stride) / qvNorm / float64(n) if resid > tol { t.Errorf("%v: unexpected VLMul; resid=%v, want <=%v", name, resid, tol) } } } // residualEVNormalization returns the maximum normalization error in E: // // max |max-norm(E[:,j]) - 1| func residualEVNormalization(emat blas64.General, wi []float64) float64 { n := emat.Rows if n == 0 { return 0 } var ( e = emat.Data lde = emat.Stride enrmin = math.Inf(1) enrmax float64 ipair int ) for j := 0; j < n; j++ { if ipair == 0 && j < n-1 && wi[j] != 0 { ipair = 1 } var nrm float64 switch ipair { case 0: // Real eigenvector for i := 0; i < n; i++ { nrm = math.Max(nrm, math.Abs(e[i*lde+j])) } enrmin = math.Min(enrmin, nrm) enrmax = math.Max(enrmax, nrm) case 1: // Complex eigenvector for i := 0; i < n; i++ { nrm = math.Max(nrm, math.Abs(e[i*lde+j])+math.Abs(e[i*lde+j+1])) } enrmin = math.Min(enrmin, nrm) enrmax = math.Max(enrmax, nrm) ipair = 2 case 2: ipair = 0 } } return math.Max(math.Abs(enrmin-1), math.Abs(enrmin-1)) } // normalizeEV normalizes eigenvectors in the columns of E so that the element // of largest magnitude has magnitude 1. func normalizeEV(emat blas64.General, wi []float64) { n := emat.Rows if n == 0 { return } var ( bi = blas64.Implementation() e = emat.Data lde = emat.Stride ipair int ) for j := 0; j < n; j++ { if ipair == 0 && j < n-1 && wi[j] != 0 { ipair = 1 } switch ipair { case 0: // Real eigenvector ii := bi.Idamax(n, e[j:], lde) remax := 1 / math.Abs(e[ii*lde+j]) bi.Dscal(n, remax, e[j:], lde) case 1: // Complex eigenvector var emax float64 for i := 0; i < n; i++ { emax = math.Max(emax, math.Abs(e[i*lde+j])+math.Abs(e[i*lde+j+1])) } bi.Dscal(n, 1/emax, e[j:], lde) bi.Dscal(n, 1/emax, e[j+1:], lde) ipair = 2 case 2: ipair = 0 } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtrexc.go000066400000000000000000000121201450372207100230400ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) type Dtrexcer interface { Dtrexc(compq lapack.UpdateSchurComp, n int, t []float64, ldt int, q []float64, ldq int, ifst, ilst int, work []float64) (ifstOut, ilstOut int, ok bool) } func DtrexcTest(t *testing.T, impl Dtrexcer) { rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 10, 18, 31, 53} { for _, extra := range []int{0, 3} { for cas := 0; cas < 100; cas++ { var ifst, ilst int if n > 0 { ifst = rnd.Intn(n) ilst = rnd.Intn(n) } dtrexcTest(t, impl, rnd, n, ifst, ilst, extra) } } } } func dtrexcTest(t *testing.T, impl Dtrexcer, rnd *rand.Rand, n, ifst, ilst, extra int) { const tol = 1e-13 tmat, _, _ := randomSchurCanonical(n, n+extra, true, rnd) tmatCopy := cloneGeneral(tmat) fstSize, fstFirst := schurBlockSize(tmat, ifst) lstSize, lstFirst := schurBlockSize(tmat, ilst) name := fmt.Sprintf("Case n=%v,ifst=%v,nbfst=%v,ilst=%v,nblst=%v,extra=%v", n, ifst, fstSize, ilst, lstSize, extra) // 1. Test without accumulating Q. compq := lapack.UpdateSchurNone work := nanSlice(n) ifstGot, ilstGot, ok := impl.Dtrexc(compq, n, tmat.Data, tmat.Stride, nil, 1, ifst, ilst, work) if !generalOutsideAllNaN(tmat) { t.Errorf("%v: out-of-range write to T", name) } // 2. Test with accumulating Q. compq = lapack.UpdateSchur tmat2 := cloneGeneral(tmatCopy) q := eye(n, n+extra) qCopy := cloneGeneral(q) work = nanSlice(n) ifstGot2, ilstGot2, ok2 := impl.Dtrexc(compq, n, tmat2.Data, tmat2.Stride, q.Data, q.Stride, ifst, ilst, work) if !generalOutsideAllNaN(tmat2) { t.Errorf("%v: out-of-range write to T2", name) } if !generalOutsideAllNaN(q) { t.Errorf("%v: out-of-range write to Q", name) } // Check that outputs from cases 1. and 2. are exactly equal, then check one of them. if ifstGot != ifstGot2 { t.Errorf("%v: ifstGot != ifstGot2", name) } if ilstGot != ilstGot2 { t.Errorf("%v: ilstGot != ilstGot2", name) } if ok != ok2 { t.Errorf("%v: ok != ok2", name) } if !equalGeneral(tmat, tmat2) { t.Errorf("%v: T != T2", name) } // Check that the index of the first block was correctly updated (if // necessary). ifstWant := ifst if !fstFirst { ifstWant = ifst - 1 } if ifstWant != ifstGot { t.Errorf("%v: unexpected ifst=%v, want %v", name, ifstGot, ifstWant) } // Check that the index of the last block is as expected when ok=true. // When ok=false, we don't know at which block the algorithm failed, so // we don't check. ilstWant := ilst if !lstFirst { ilstWant-- } if ok { if ifstWant < ilstWant { // If the blocks are swapped backwards, these // adjustments are not necessary, the first row of the // last block will end up at ifst. switch { case fstSize == 2 && lstSize == 1: ilstWant-- case fstSize == 1 && lstSize == 2: ilstWant++ } } if ilstWant != ilstGot { t.Errorf("%v: unexpected ilst=%v, want %v", name, ilstGot, ilstWant) } } if n <= 1 || ifstGot == ilstGot { // Too small matrix or no swapping. // Check that T was not modified. if !equalGeneral(tmat, tmatCopy) { t.Errorf("%v: unexpected modification of T when no swapping", name) } // Check that Q was not modified. if !equalGeneral(q, qCopy) { t.Errorf("%v: unexpected modification of Q when no swapping", name) } // Nothing more to check return } if !isSchurCanonicalGeneral(tmat) { t.Errorf("%v: T is not in Schur canonical form", name) } // Check that T was not modified except above the second subdiagonal in // rows and columns [modMin,modMax]. modMin := min(ifstGot, ilstGot) modMax := max(ifstGot, ilstGot) + fstSize for i := 0; i < n; i++ { for j := 0; j < n; j++ { if modMin <= i && i < modMax && j+1 >= i { continue } if modMin <= j && j < modMax && j+1 >= i { continue } diff := tmat.Data[i*tmat.Stride+j] - tmatCopy.Data[i*tmatCopy.Stride+j] if diff != 0 { t.Errorf("%v: unexpected modification at T[%v,%v]", name, i, j) } } } // Check that Q is orthogonal. resid := residualOrthogonal(q, false) if resid > tol { t.Errorf("%v: Q is not orthogonal; resid=%v, want<=%v", name, resid, tol) } // Check that Q is unchanged outside of columns [modMin,modMax]. for i := 0; i < n; i++ { for j := 0; j < n; j++ { if modMin <= j && j < modMax { continue } if q.Data[i*q.Stride+j] != qCopy.Data[i*qCopy.Stride+j] { t.Errorf("%v: unexpected modification of Q[%v,%v]", name, i, j) } } } // Check that Qᵀ * TOrig * Q == T qt := zeros(n, n, n) blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, tmatCopy, 0, qt) qtq := cloneGeneral(tmat) blas64.Gemm(blas.NoTrans, blas.NoTrans, -1, qt, q, 1, qtq) resid = dlange(lapack.MaxColumnSum, n, n, qtq.Data, qtq.Stride) if resid > tol { t.Errorf("%v: mismatch between Qᵀ*(initial T)*Q and (final T); resid=%v, want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtrti2.go000066400000000000000000000064151450372207100227710ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) type Dtrti2er interface { Dtrti2(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) } func Dtrti2Test(t *testing.T, impl Dtrti2er) { const tol = 1e-14 for _, test := range []struct { a []float64 n int uplo blas.Uplo diag blas.Diag ans []float64 }{ { a: []float64{ 2, 3, 4, 0, 5, 6, 8, 0, 8}, n: 3, uplo: blas.Upper, diag: blas.NonUnit, ans: []float64{ 0.5, -0.3, -0.025, 0, 0.2, -0.15, 8, 0, 0.125, }, }, { a: []float64{ 5, 3, 4, 0, 7, 6, 10, 0, 8}, n: 3, uplo: blas.Upper, diag: blas.Unit, ans: []float64{ 5, -3, 14, 0, 7, -6, 10, 0, 8, }, }, { a: []float64{ 2, 0, 0, 3, 5, 0, 4, 6, 8}, n: 3, uplo: blas.Lower, diag: blas.NonUnit, ans: []float64{ 0.5, 0, 0, -0.3, 0.2, 0, -0.025, -0.15, 0.125, }, }, { a: []float64{ 1, 0, 0, 3, 1, 0, 4, 6, 1}, n: 3, uplo: blas.Lower, diag: blas.Unit, ans: []float64{ 1, 0, 0, -3, 1, 0, 14, -6, 1, }, }, } { impl.Dtrti2(test.uplo, test.diag, test.n, test.a, test.n) if !floats.EqualApprox(test.ans, test.a, tol) { t.Errorf("Matrix inverse mismatch. Want %v, got %v.", test.ans, test.a) } } rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, test := range []struct { n, lda int }{ {1, 0}, {2, 0}, {3, 0}, {1, 5}, {2, 5}, {3, 5}, } { n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate n×n matrix A and fill it with random numbers. a := make([]float64, n*lda) for i := range a { a[i] = rnd.Float64() } for i := 0; i < n; i++ { // This keeps the matrices well conditioned. a[i*lda+i] += float64(n) } aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute the inverse of the uplo triangle. impl.Dtrti2(uplo, diag, n, a, lda) // Zero out the opposite triangle. if uplo == blas.Upper { for i := 1; i < n; i++ { for j := 0; j < i; j++ { aCopy[i*lda+j] = 0 a[i*lda+j] = 0 } } } else { for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { aCopy[i*lda+j] = 0 a[i*lda+j] = 0 } } } if diag == blas.Unit { // Set the diagonal of A^{-1} and A explicitly to 1. for i := 0; i < n; i++ { a[i*lda+i] = 1 aCopy[i*lda+i] = 1 } } // Compute A^{-1} * A and store the result in ans. ans := make([]float64, len(a)) bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, a, lda, aCopy, lda, 0, ans, lda) // Check that ans is close to the identity matrix. dist := distFromIdentity(n, ans, lda) if dist > tol { t.Errorf("|inv(A) * A - I| = %v. Upper = %v, unit = %v, ans = %v", dist, uplo == blas.Upper, diag == blas.Unit, ans) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtrtri.go000066400000000000000000000042701450372207100230660ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) type Dtrtrier interface { Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) bool } func DtrtriTest(t *testing.T, impl Dtrtrier) { const tol = 1e-10 rnd := rand.New(rand.NewSource(1)) bi := blas64.Implementation() for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { for _, test := range []struct { n, lda int }{ {3, 0}, {70, 0}, {200, 0}, {3, 5}, {70, 92}, {200, 205}, } { n := test.n lda := test.lda if lda == 0 { lda = n } // Allocate n×n matrix A and fill it with random numbers. a := make([]float64, n*lda) for i := range a { a[i] = rnd.Float64() } for i := 0; i < n; i++ { // This keeps the matrices well conditioned. a[i*lda+i] += float64(n) } aCopy := make([]float64, len(a)) copy(aCopy, a) // Compute the inverse of the uplo triangle. impl.Dtrtri(uplo, diag, n, a, lda) // Zero out the opposite triangle. if uplo == blas.Upper { for i := 1; i < n; i++ { for j := 0; j < i; j++ { aCopy[i*lda+j] = 0 a[i*lda+j] = 0 } } } else { for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { aCopy[i*lda+j] = 0 a[i*lda+j] = 0 } } } if diag == blas.Unit { // Set the diagonal explicitly to 1. for i := 0; i < n; i++ { a[i*lda+i] = 1 aCopy[i*lda+i] = 1 } } // Compute A^{-1} * A and store the result in ans. ans := make([]float64, len(a)) bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, a, lda, aCopy, lda, 0, ans, lda) // Check that ans is the identity matrix. dist := distFromIdentity(n, ans, lda) if dist > tol { t.Errorf("|inv(A) * A - I| = %v is too large. Upper = %v, unit = %v, n = %v, lda = %v", dist, uplo == blas.Upper, diag == blas.Unit, n, lda) } } } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/dtrtrs.go000066400000000000000000000071711450372207100231030ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" ) type Dtrtrser interface { Dtrtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, nrhs int, a []float64, lda int, b []float64, ldb int) bool } func DtrtrsTest(t *testing.T, impl Dtrtrser) { rnd := rand.New(rand.NewSource(1)) for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} { name := transToString(trans) t.Run(name, func(t *testing.T) { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { for _, n := range []int{0, 1, 2, 3, 4, 5, 10} { for _, nrhs := range []int{0, 1, 2, 3, 4, 5, 10, 15} { for _, lda := range []int{max(1, n), n + 3} { for _, ldb := range []int{max(1, nrhs), nrhs + 3} { if diag == blas.Unit { dtrtrsTest(t, impl, rnd, uplo, trans, diag, n, nrhs, lda, ldb, false) } else { dtrtrsTest(t, impl, rnd, uplo, trans, diag, n, nrhs, lda, ldb, true) dtrtrsTest(t, impl, rnd, uplo, trans, diag, n, nrhs, lda, ldb, false) } } } } } } } }) } } func dtrtrsTest(t *testing.T, impl Dtrtrser, rnd *rand.Rand, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, nrhs int, lda, ldb int, singular bool) { if singular && diag == blas.Unit { panic("blas.Unit triangular matrix cannot be singular") } const tol = 1e-14 if n == 0 { singular = false } name := fmt.Sprintf("uplo=%v,diag=%v,n=%v,nrhs=%v,lda=%v,ldb=%v,sing=%v", string(uplo), string(diag), n, nrhs, lda, ldb, singular) // Generate a random triangular matrix A. One of its triangles won't be // referenced. a := make([]float64, n*lda) for i := range a { a[i] = rnd.NormFloat64() } if singular { i := rnd.Intn(n) a[i*lda+i] = 0 } aCopy := make([]float64, len(a)) copy(aCopy, a) // Generate a random solution matrix X. x := make([]float64, n*ldb) for i := range x { x[i] = rnd.NormFloat64() } // Generate the right-hand side as A * X or Aᵀ * X. b := make([]float64, len(x)) copy(b, x) bi := blas64.Implementation() bi.Dtrmm(blas.Left, uplo, trans, diag, n, nrhs, 1, a, lda, b, ldb) got := make([]float64, len(b)) copy(got, b) ok := impl.Dtrtrs(uplo, trans, diag, n, nrhs, a, lda, got, ldb) if !floats.Equal(a, aCopy) { t.Errorf("%v: unexpected modification of A", name) } if ok == singular { t.Errorf("%v: misdetected singular matrix, ok=%v", name, ok) } if !ok { if !floats.Equal(got, b) { t.Errorf("%v: unexpected modification of B when singular", name) } return } if n == 0 || nrhs == 0 { return } work := make([]float64, n) // Compute the 1-norm of A or Aᵀ. var aNorm float64 if trans == blas.NoTrans { aNorm = dlantr(lapack.MaxColumnSum, uplo, diag, n, n, a, lda, work) } else { aNorm = dlantr(lapack.MaxRowSum, uplo, diag, n, n, a, lda, work) } // Compute the maximum over the number of right-hand sides of // |op(A)*x-b| / (|op(A)| * |x|) var resid float64 for j := 0; j < nrhs; j++ { bi.Dcopy(n, got[j:], ldb, work, 1) bi.Dtrmv(uplo, trans, diag, n, a, lda, work, 1) bi.Daxpy(n, -1, b[j:], ldb, work, 1) rjNorm := bi.Dasum(n, work, 1) xNorm := bi.Dasum(n, got[j:], ldb) resid = math.Max(resid, rjNorm/aNorm/xNorm) } if resid > tol { t.Errorf("%v: unexpected result; resid=%v,want<=%v", name, resid, tol) } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/fortran.go000066400000000000000000000017401450372207100232300ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "strings" ) // This file implements types for helping to convert to Fortran testing capabilities. //lint:file-ignore U1000 A number of functions are here that may be used in future. // fortran64 is a float64 type that prints as a double precision constant in // Fortran format. type fortran64 float64 func (f fortran64) String() string { // Replace exponent with D s := fmt.Sprintf("%0.16E", f) s = strings.Replace(s, "E", "D", 1) return s } // printFortranArray prints a Go slice as an array that can be copied into a // fortran script. func printFortranArray(z []float64, name string) { fmt.Printf("%s(1:%d) = (/%v, &\n", name, len(z), fortran64(z[0])) for i := 1; i < len(z)-1; i++ { fmt.Printf("%v, &\n", fortran64(z[i])) } fmt.Printf("%s/)\n", fortran64(z[len(z)-1])) } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/general.go000066400000000000000000001000751450372207100231730ustar00rootroot00000000000000// 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 testlapack import ( "fmt" "math" "math/cmplx" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" ) const ( // dlamchE is the machine epsilon. For IEEE this is 2^{-53}. dlamchE = 0x1p-53 dlamchB = 2 dlamchP = dlamchB * dlamchE // dlamchS is the smallest normal number. For IEEE this is 2^{-1022}. dlamchS = 0x1p-1022 safmin = dlamchS safmax = 1 / safmin ulp = dlamchP smlnum = safmin / ulp bignum = safmax * ulp ) func max(a, b int) int { if a > b { return a } return b } func min(a, b int) int { if a < b { return a } return b } // worklen describes how much workspace a test should use. type worklen int const ( minimumWork worklen = iota mediumWork optimumWork ) func (wl worklen) String() string { switch wl { case minimumWork: return "minimum" case mediumWork: return "medium" case optimumWork: return "optimum" } return "" } func normToString(norm lapack.MatrixNorm) string { switch norm { case lapack.MaxAbs: return "MaxAbs" case lapack.MaxRowSum: return "MaxRowSum" case lapack.MaxColumnSum: return "MaxColSum" case lapack.Frobenius: return "Frobenius" default: panic("invalid norm") } } func uploToString(uplo blas.Uplo) string { switch uplo { case blas.Lower: return "Lower" case blas.Upper: return "Upper" default: panic("invalid uplo") } } func diagToString(diag blas.Diag) string { switch diag { case blas.NonUnit: return "NonUnit" case blas.Unit: return "Unit" default: panic("invalid diag") } } func sideToString(side blas.Side) string { switch side { case blas.Left: return "Left" case blas.Right: return "Right" default: panic("invalid side") } } func transToString(trans blas.Transpose) string { switch trans { case blas.NoTrans: return "NoTrans" case blas.Trans: return "Trans" case blas.ConjTrans: return "ConjTrans" default: panic("invalid trans") } } // nanSlice allocates a new slice of length n filled with NaN. func nanSlice(n int) []float64 { s := make([]float64, n) for i := range s { s[i] = math.NaN() } return s } // randomSlice allocates a new slice of length n filled with random values. func randomSlice(n int, rnd *rand.Rand) []float64 { s := make([]float64, n) for i := range s { s[i] = rnd.NormFloat64() } return s } // nanGeneral allocates a new r×c general matrix filled with NaN values. func nanGeneral(r, c, stride int) blas64.General { if r < 0 || c < 0 { panic("bad matrix size") } if r == 0 || c == 0 { return blas64.General{Stride: max(1, stride)} } if stride < c { panic("bad stride") } return blas64.General{ Rows: r, Cols: c, Stride: stride, Data: nanSlice((r-1)*stride + c), } } // randomGeneral allocates a new r×c general matrix filled with random // numbers. Out-of-range elements are filled with NaN values. func randomGeneral(r, c, stride int, rnd *rand.Rand) blas64.General { ans := nanGeneral(r, c, stride) for i := 0; i < r; i++ { for j := 0; j < c; j++ { ans.Data[i*ans.Stride+j] = rnd.NormFloat64() } } return ans } // randomHessenberg allocates a new n×n Hessenberg matrix filled with zeros // under the first subdiagonal and with random numbers elsewhere. Out-of-range // elements are filled with NaN values. func randomHessenberg(n, stride int, rnd *rand.Rand) blas64.General { ans := nanGeneral(n, n, stride) for i := 0; i < n; i++ { for j := 0; j < i-1; j++ { ans.Data[i*ans.Stride+j] = 0 } for j := max(0, i-1); j < n; j++ { ans.Data[i*ans.Stride+j] = rnd.NormFloat64() } } return ans } // randomSchurCanonical returns a random, general matrix in Schur canonical // form, that is, block upper triangular with 1×1 and 2×2 diagonal blocks where // each 2×2 diagonal block has its diagonal elements equal and its off-diagonal // elements of opposite sign. bad controls whether the returned matrix will have // zero or tiny eigenvalues. func randomSchurCanonical(n, stride int, bad bool, rnd *rand.Rand) (t blas64.General, wr, wi []float64) { t = randomGeneral(n, n, stride, rnd) // Zero out the lower triangle including the diagonal which will be set later. for i := 0; i < t.Rows; i++ { for j := 0; j <= i; j++ { t.Data[i*t.Stride+j] = 0 } } // Randomly create 2×2 diagonal blocks. for i := 0; i < t.Rows; { a := rnd.NormFloat64() if bad && rnd.Float64() < 0.5 { if rnd.Float64() < 0.5 { // A quarter of real parts of eigenvalues will be tiny. a = dlamchS } else { // A quarter of them will be zero. a = 0 } } // A half of eigenvalues will be real. if rnd.Float64() < 0.5 || i == t.Rows-1 { // Store 1×1 block at the diagonal of T. t.Data[i*t.Stride+i] = a wr = append(wr, a) wi = append(wi, 0) i++ continue } // Diagonal elements are equal. d := a // Element under the diagonal is "normal". c := rnd.NormFloat64() // Element above the diagonal cannot be zero. var b float64 if bad && rnd.Float64() < 0.5 { b = dlamchS } else { b = rnd.NormFloat64() } // Make sure off-diagonal elements are of opposite sign. if math.Signbit(b) == math.Signbit(c) { c *= -1 } // Store 2×2 block at the diagonal of T. t.Data[i*t.Stride+i], t.Data[i*t.Stride+i+1] = a, b t.Data[(i+1)*t.Stride+i], t.Data[(i+1)*t.Stride+i+1] = c, d wr = append(wr, a, a) im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c)) wi = append(wi, im, -im) i += 2 } return t, wr, wi } // blockedUpperTriGeneral returns a normal random, general matrix in the form // // c-k-l k l // A = k [ 0 A12 A13 ] if r-k-l >= 0; // l [ 0 0 A23 ] // r-k-l [ 0 0 0 ] // // c-k-l k l // A = k [ 0 A12 A13 ] if r-k-l < 0; // r-k [ 0 0 A23 ] // // where the k×k matrix A12 and l×l matrix is non-singular // upper triangular. A23 is l×l upper triangular if r-k-l >= 0, // otherwise A23 is (r-k)×l upper trapezoidal. func blockedUpperTriGeneral(r, c, k, l, stride int, kblock bool, rnd *rand.Rand) blas64.General { t := l if kblock { t += k } ans := zeros(r, c, stride) for i := 0; i < min(r, t); i++ { var v float64 for v == 0 { v = rnd.NormFloat64() } ans.Data[i*ans.Stride+i+(c-t)] = v } for i := 0; i < min(r, t); i++ { for j := i + (c - t) + 1; j < c; j++ { ans.Data[i*ans.Stride+j] = rnd.NormFloat64() } } return ans } // nanTriangular allocates a new r×c triangular matrix filled with NaN values. func nanTriangular(uplo blas.Uplo, n, stride int) blas64.Triangular { if n < 0 { panic("bad matrix size") } if n == 0 { return blas64.Triangular{ Stride: max(1, stride), Uplo: uplo, Diag: blas.NonUnit, } } if stride < n { panic("bad stride") } return blas64.Triangular{ N: n, Stride: stride, Data: nanSlice((n-1)*stride + n), Uplo: uplo, Diag: blas.NonUnit, } } // generalOutsideAllNaN returns whether all out-of-range elements have NaN // values. func generalOutsideAllNaN(a blas64.General) bool { // Check after last column. for i := 0; i < a.Rows-1; i++ { for _, v := range a.Data[i*a.Stride+a.Cols : i*a.Stride+a.Stride] { if !math.IsNaN(v) { return false } } } // Check after last element. last := (a.Rows-1)*a.Stride + a.Cols if a.Rows == 0 || a.Cols == 0 { last = 0 } for _, v := range a.Data[last:] { if !math.IsNaN(v) { return false } } return true } // triangularOutsideAllNaN returns whether all out-of-triangle elements have NaN // values. func triangularOutsideAllNaN(a blas64.Triangular) bool { if a.Uplo == blas.Upper { // Check below diagonal. for i := 0; i < a.N; i++ { for _, v := range a.Data[i*a.Stride : i*a.Stride+i] { if !math.IsNaN(v) { return false } } } // Check after last column. for i := 0; i < a.N-1; i++ { for _, v := range a.Data[i*a.Stride+a.N : i*a.Stride+a.Stride] { if !math.IsNaN(v) { return false } } } } else { // Check above diagonal. for i := 0; i < a.N-1; i++ { for _, v := range a.Data[i*a.Stride+i+1 : i*a.Stride+a.Stride] { if !math.IsNaN(v) { return false } } } } // Check after last element. for _, v := range a.Data[max(0, a.N-1)*a.Stride+a.N:] { if !math.IsNaN(v) { return false } } return true } // transposeGeneral returns a new general matrix that is the transpose of the // input. Nothing is done with data outside the {rows, cols} limit of the general. func transposeGeneral(a blas64.General) blas64.General { ans := blas64.General{ Rows: a.Cols, Cols: a.Rows, Stride: a.Rows, Data: make([]float64, a.Cols*a.Rows), } for i := 0; i < a.Rows; i++ { for j := 0; j < a.Cols; j++ { ans.Data[j*ans.Stride+i] = a.Data[i*a.Stride+j] } } return ans } // columnNorms returns the column norms of a. func columnNorms(m, n int, a []float64, lda int) []float64 { bi := blas64.Implementation() norms := make([]float64, n) for j := 0; j < n; j++ { norms[j] = bi.Dnrm2(m, a[j:], lda) } return norms } // extractVMat collects the single reflectors from a into a matrix. func extractVMat(m, n int, a []float64, lda int, direct lapack.Direct, store lapack.StoreV) blas64.General { k := min(m, n) switch { default: panic("not implemented") case direct == lapack.Forward && store == lapack.ColumnWise: v := blas64.General{ Rows: m, Cols: k, Stride: k, Data: make([]float64, m*k), } for i := 0; i < k; i++ { for j := 0; j < i; j++ { v.Data[j*v.Stride+i] = 0 } v.Data[i*v.Stride+i] = 1 for j := i + 1; j < m; j++ { v.Data[j*v.Stride+i] = a[j*lda+i] } } return v case direct == lapack.Forward && store == lapack.RowWise: v := blas64.General{ Rows: k, Cols: n, Stride: n, Data: make([]float64, k*n), } for i := 0; i < k; i++ { for j := 0; j < i; j++ { v.Data[i*v.Stride+j] = 0 } v.Data[i*v.Stride+i] = 1 for j := i + 1; j < n; j++ { v.Data[i*v.Stride+j] = a[i*lda+j] } } return v } } // constructBidiagonal constructs a bidiagonal matrix with the given diagonal // and off-diagonal elements. func constructBidiagonal(uplo blas.Uplo, n int, d, e []float64) blas64.General { bMat := blas64.General{ Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), } for i := 0; i < n-1; i++ { bMat.Data[i*bMat.Stride+i] = d[i] if uplo == blas.Upper { bMat.Data[i*bMat.Stride+i+1] = e[i] } else { bMat.Data[(i+1)*bMat.Stride+i] = e[i] } } bMat.Data[(n-1)*bMat.Stride+n-1] = d[n-1] return bMat } // constructVMat transforms the v matrix based on the storage. func constructVMat(vMat blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General { m := vMat.Rows k := vMat.Cols switch { default: panic("not implemented") case store == lapack.ColumnWise && direct == lapack.Forward: ldv := k v := make([]float64, m*k) for i := 0; i < m; i++ { for j := 0; j < k; j++ { if j > i { v[i*ldv+j] = 0 } else if j == i { v[i*ldv+i] = 1 } else { v[i*ldv+j] = vMat.Data[i*vMat.Stride+j] } } } return blas64.General{ Rows: m, Cols: k, Stride: k, Data: v, } case store == lapack.RowWise && direct == lapack.Forward: ldv := m v := make([]float64, m*k) for i := 0; i < m; i++ { for j := 0; j < k; j++ { if j > i { v[j*ldv+i] = 0 } else if j == i { v[j*ldv+i] = 1 } else { v[j*ldv+i] = vMat.Data[i*vMat.Stride+j] } } } return blas64.General{ Rows: k, Cols: m, Stride: m, Data: v, } case store == lapack.ColumnWise && direct == lapack.Backward: rowsv := m ldv := k v := make([]float64, m*k) for i := 0; i < m; i++ { for j := 0; j < k; j++ { vrow := rowsv - i - 1 vcol := k - j - 1 if j > i { v[vrow*ldv+vcol] = 0 } else if j == i { v[vrow*ldv+vcol] = 1 } else { v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j] } } } return blas64.General{ Rows: rowsv, Cols: ldv, Stride: ldv, Data: v, } case store == lapack.RowWise && direct == lapack.Backward: rowsv := k ldv := m v := make([]float64, m*k) for i := 0; i < m; i++ { for j := 0; j < k; j++ { vcol := ldv - i - 1 vrow := k - j - 1 if j > i { v[vrow*ldv+vcol] = 0 } else if j == i { v[vrow*ldv+vcol] = 1 } else { v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j] } } } return blas64.General{ Rows: rowsv, Cols: ldv, Stride: ldv, Data: v, } } } func constructH(tau []float64, v blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General { m := v.Rows k := v.Cols if store == lapack.RowWise { m, k = k, m } h := blas64.General{ Rows: m, Cols: m, Stride: m, Data: make([]float64, m*m), } for i := 0; i < m; i++ { h.Data[i*m+i] = 1 } for i := 0; i < k; i++ { vecData := make([]float64, m) if store == lapack.ColumnWise { for j := 0; j < m; j++ { vecData[j] = v.Data[j*v.Cols+i] } } else { for j := 0; j < m; j++ { vecData[j] = v.Data[i*v.Cols+j] } } vec := blas64.Vector{ Inc: 1, Data: vecData, } hi := blas64.General{ Rows: m, Cols: m, Stride: m, Data: make([]float64, m*m), } for i := 0; i < m; i++ { hi.Data[i*m+i] = 1 } // hi = I - tau * v * vᵀ blas64.Ger(-tau[i], vec, vec, hi) hcopy := blas64.General{ Rows: m, Cols: m, Stride: m, Data: make([]float64, m*m), } copy(hcopy.Data, h.Data) if direct == lapack.Forward { // H = H * H_I in forward mode blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hcopy, hi, 0, h) } else { // H = H_I * H in backward mode blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hi, hcopy, 0, h) } } return h } // constructQ constructs the Q matrix from the result of dgeqrf and dgeqr2. func constructQ(kind string, m, n int, a []float64, lda int, tau []float64) blas64.General { k := min(m, n) return constructQK(kind, m, n, k, a, lda, tau) } // constructQK constructs the Q matrix from the result of dgeqrf and dgeqr2 using // the first k reflectors. func constructQK(kind string, m, n, k int, a []float64, lda int, tau []float64) blas64.General { var sz int switch kind { case "QR": sz = m case "LQ", "RQ": sz = n } q := blas64.General{ Rows: sz, Cols: sz, Stride: max(1, sz), Data: make([]float64, sz*sz), } for i := 0; i < sz; i++ { q.Data[i*sz+i] = 1 } qCopy := blas64.General{ Rows: q.Rows, Cols: q.Cols, Stride: q.Stride, Data: make([]float64, len(q.Data)), } for i := 0; i < k; i++ { h := blas64.General{ Rows: sz, Cols: sz, Stride: max(1, sz), Data: make([]float64, sz*sz), } for j := 0; j < sz; j++ { h.Data[j*sz+j] = 1 } vVec := blas64.Vector{ Inc: 1, Data: make([]float64, sz), } switch kind { case "QR": vVec.Data[i] = 1 for j := i + 1; j < sz; j++ { vVec.Data[j] = a[lda*j+i] } case "LQ": vVec.Data[i] = 1 for j := i + 1; j < sz; j++ { vVec.Data[j] = a[i*lda+j] } case "RQ": for j := 0; j < n-k+i; j++ { vVec.Data[j] = a[(m-k+i)*lda+j] } vVec.Data[n-k+i] = 1 } blas64.Ger(-tau[i], vVec, vVec, h) copy(qCopy.Data, q.Data) // Multiply q by the new h. switch kind { case "QR", "RQ": blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, h, 0, q) case "LQ": blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, qCopy, 0, q) } } return q } // checkBidiagonal checks the bidiagonal decomposition from dlabrd and dgebd2. // The input to this function is the answer returned from the routines, stored // in a, d, e, tauP, and tauQ. The data of original A matrix (before // decomposition) is input in aCopy. // // checkBidiagonal constructs the V and U matrices, and from them constructs Q // and P. Using these constructions, it checks that Qᵀ * A * P and checks that // the result is bidiagonal. func checkBidiagonal(t *testing.T, m, n, nb int, a []float64, lda int, d, e, tauP, tauQ, aCopy []float64) { // Check the answer. // Construct V and U. qMat := constructQPBidiagonal(lapack.ApplyQ, m, n, nb, a, lda, tauQ) pMat := constructQPBidiagonal(lapack.ApplyP, m, n, nb, a, lda, tauP) // Compute Qᵀ * A * P. aMat := blas64.General{ Rows: m, Cols: n, Stride: lda, Data: make([]float64, len(aCopy)), } copy(aMat.Data, aCopy) tmp1 := blas64.General{ Rows: m, Cols: n, Stride: n, Data: make([]float64, m*n), } blas64.Gemm(blas.Trans, blas.NoTrans, 1, qMat, aMat, 0, tmp1) tmp2 := blas64.General{ Rows: m, Cols: n, Stride: n, Data: make([]float64, m*n), } blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp1, pMat, 0, tmp2) // Check that the first nb rows and cols of tm2 are upper bidiagonal // if m >= n, and lower bidiagonal otherwise. correctDiag := true matchD := true matchE := true for i := 0; i < m; i++ { for j := 0; j < n; j++ { if i >= nb && j >= nb { continue } v := tmp2.Data[i*tmp2.Stride+j] if i == j { if math.Abs(d[i]-v) > 1e-12 { matchD = false } continue } if m >= n && i == j-1 { if math.Abs(e[j-1]-v) > 1e-12 { matchE = false } continue } if m < n && i-1 == j { if math.Abs(e[i-1]-v) > 1e-12 { matchE = false } continue } if math.Abs(v) > 1e-12 { correctDiag = false } } } if !correctDiag { t.Errorf("Updated A not bi-diagonal") } if !matchD { fmt.Println("d = ", d) t.Errorf("D Mismatch") } if !matchE { t.Errorf("E mismatch") } } // constructQPBidiagonal constructs Q or P from the Bidiagonal decomposition // computed by dlabrd and bgebd2. func constructQPBidiagonal(vect lapack.ApplyOrtho, m, n, nb int, a []float64, lda int, tau []float64) blas64.General { sz := n if vect == lapack.ApplyQ { sz = m } var ldv int var v blas64.General if vect == lapack.ApplyQ { ldv = nb v = blas64.General{ Rows: m, Cols: nb, Stride: ldv, Data: make([]float64, m*ldv), } } else { ldv = n v = blas64.General{ Rows: nb, Cols: n, Stride: ldv, Data: make([]float64, m*ldv), } } if vect == lapack.ApplyQ { if m >= n { for i := 0; i < m; i++ { for j := 0; j <= min(nb-1, i); j++ { if i == j { v.Data[i*ldv+j] = 1 continue } v.Data[i*ldv+j] = a[i*lda+j] } } } else { for i := 1; i < m; i++ { for j := 0; j <= min(nb-1, i-1); j++ { if i-1 == j { v.Data[i*ldv+j] = 1 continue } v.Data[i*ldv+j] = a[i*lda+j] } } } } else { if m < n { for i := 0; i < nb; i++ { for j := i; j < n; j++ { if i == j { v.Data[i*ldv+j] = 1 continue } v.Data[i*ldv+j] = a[i*lda+j] } } } else { for i := 0; i < nb; i++ { for j := i + 1; j < n; j++ { if j-1 == i { v.Data[i*ldv+j] = 1 continue } v.Data[i*ldv+j] = a[i*lda+j] } } } } // The variable name is a computation of Q, but the algorithm is mostly the // same for computing P (just with different data). qMat := blas64.General{ Rows: sz, Cols: sz, Stride: sz, Data: make([]float64, sz*sz), } hMat := blas64.General{ Rows: sz, Cols: sz, Stride: sz, Data: make([]float64, sz*sz), } // set Q to I for i := 0; i < sz; i++ { qMat.Data[i*qMat.Stride+i] = 1 } for i := 0; i < nb; i++ { qCopy := blas64.General{Rows: qMat.Rows, Cols: qMat.Cols, Stride: qMat.Stride, Data: make([]float64, len(qMat.Data))} copy(qCopy.Data, qMat.Data) // Set g and h to I for i := 0; i < sz; i++ { for j := 0; j < sz; j++ { if i == j { hMat.Data[i*sz+j] = 1 } else { hMat.Data[i*sz+j] = 0 } } } var vi blas64.Vector // H -= tauQ[i] * v[i] * v[i]^t if vect == lapack.ApplyQ { vi = blas64.Vector{ Inc: v.Stride, Data: v.Data[i:], } } else { vi = blas64.Vector{ Inc: 1, Data: v.Data[i*v.Stride:], } } blas64.Ger(-tau[i], vi, vi, hMat) // Q = Q * G[1] blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, hMat, 0, qMat) } return qMat } // printRowise prints the matrix with one row per line. This is useful for debugging. // If beyond is true, it prints beyond the final column to lda. If false, only // the columns are printed. // //lint:ignore U1000 This is useful for debugging. func printRowise(a []float64, m, n, lda int, beyond bool) { for i := 0; i < m; i++ { end := n if beyond { end = lda } fmt.Println(a[i*lda : i*lda+end]) } } func copyGeneral(dst, src blas64.General) { r := min(dst.Rows, src.Rows) c := min(dst.Cols, src.Cols) for i := 0; i < r; i++ { copy(dst.Data[i*dst.Stride:i*dst.Stride+c], src.Data[i*src.Stride:i*src.Stride+c]) } } // cloneGeneral allocates and returns an exact copy of the given general matrix. func cloneGeneral(a blas64.General) blas64.General { c := a c.Data = make([]float64, len(a.Data)) copy(c.Data, a.Data) return c } // equalGeneral returns whether the general matrices a and b are equal. func equalGeneral(a, b blas64.General) bool { if a.Rows != b.Rows || a.Cols != b.Cols { panic("bad input") } for i := 0; i < a.Rows; i++ { for j := 0; j < a.Cols; j++ { if a.Data[i*a.Stride+j] != b.Data[i*b.Stride+j] { return false } } } return true } // equalApproxGeneral returns whether the general matrices a and b are // approximately equal within given tolerance. func equalApproxGeneral(a, b blas64.General, tol float64) bool { if a.Rows != b.Rows || a.Cols != b.Cols { panic("bad input") } for i := 0; i < a.Rows; i++ { for j := 0; j < a.Cols; j++ { diff := a.Data[i*a.Stride+j] - b.Data[i*b.Stride+j] if math.IsNaN(diff) || math.Abs(diff) > tol { return false } } } return true } func intsEqual(a, b []int) bool { if len(a) != len(b) { return false } for i, ai := range a { if b[i] != ai { return false } } return true } // randSymBand returns an n×n random symmetric positive definite band matrix // with kd diagonals. func randSymBand(uplo blas.Uplo, n, kd, ldab int, rnd *rand.Rand) []float64 { // Allocate a triangular band matrix U or L and fill it with random numbers. var ab []float64 if n > 0 { ab = make([]float64, (n-1)*ldab+kd+1) } for i := range ab { ab[i] = rnd.NormFloat64() } // Make sure that the matrix U or L has a sufficiently positive diagonal. switch uplo { case blas.Upper: for i := 0; i < n; i++ { ab[i*ldab] = float64(n) + rnd.Float64() } case blas.Lower: for i := 0; i < n; i++ { ab[i*ldab+kd] = float64(n) + rnd.Float64() } } // Compute Uᵀ*U or L*Lᵀ. The resulting (symmetric) matrix A will be // positive definite and well-conditioned. dsbmm(uplo, n, kd, ab, ldab) return ab } // distSymBand returns the max-norm distance between the symmetric band matrices // A and B. func distSymBand(uplo blas.Uplo, n, kd int, a []float64, lda int, b []float64, ldb int) float64 { var dist float64 switch uplo { case blas.Upper: for i := 0; i < n; i++ { for j := 0; j < min(kd+1, n-i); j++ { dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j])) } } case blas.Lower: for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd+1; j++ { dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j])) } } } return dist } // eye returns an identity matrix of given order and stride. func eye(n, stride int) blas64.General { ans := nanGeneral(n, n, stride) for i := 0; i < n; i++ { for j := 0; j < n; j++ { ans.Data[i*ans.Stride+j] = 0 } ans.Data[i*ans.Stride+i] = 1 } return ans } // zeros returns an m×n matrix with given stride filled with zeros. func zeros(m, n, stride int) blas64.General { a := nanGeneral(m, n, stride) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Data[i*a.Stride+j] = 0 } } return a } // extract2x2Block returns the elements of T at [0,0], [0,1], [1,0], and [1,1]. func extract2x2Block(t []float64, ldt int) (a, b, c, d float64) { return t[0], t[1], t[ldt], t[ldt+1] } // isSchurCanonical returns whether the 2×2 matrix [a b; c d] is in Schur // canonical form. func isSchurCanonical(a, b, c, d float64) bool { return c == 0 || (b != 0 && a == d && math.Signbit(b) != math.Signbit(c)) } // isSchurCanonicalGeneral returns whether T is block upper triangular with 1×1 // and 2×2 diagonal blocks, each 2×2 block in Schur canonical form. The function // checks only along the diagonal and the first subdiagonal, otherwise the lower // triangle is not accessed. func isSchurCanonicalGeneral(t blas64.General) bool { n := t.Cols if t.Rows != n { panic("invalid matrix") } for j := 0; j < n-1; { if t.Data[(j+1)*t.Stride+j] == 0 { // 1×1 block. for i := j + 1; i < n; i++ { if t.Data[i*t.Stride+j] != 0 { return false } } j++ continue } // 2×2 block. a, b, c, d := extract2x2Block(t.Data[j*t.Stride+j:], t.Stride) if !isSchurCanonical(a, b, c, d) { return false } for i := j + 2; i < n; i++ { if t.Data[i*t.Stride+j] != 0 { return false } } for i := j + 2; i < n; i++ { if t.Data[i*t.Stride+j+1] != 0 { return false } } j += 2 } return true } // schurBlockEigenvalues returns the two eigenvalues of the 2×2 matrix [a b; c d] // that must be in Schur canonical form. // //lint:ignore U1000 This is useful for debugging. func schurBlockEigenvalues(a, b, c, d float64) (ev1, ev2 complex128) { if !isSchurCanonical(a, b, c, d) { panic("block not in Schur canonical form") } if c == 0 { return complex(a, 0), complex(d, 0) } im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c)) return complex(a, im), complex(a, -im) } // schurBlockSize returns the size of the diagonal block at i-th row in the // upper quasi-triangular matrix t in Schur canonical form, and whether i points // to the first row of the block. For zero-sized matrices the function returns 0 // and true. func schurBlockSize(t blas64.General, i int) (size int, first bool) { if t.Rows != t.Cols { panic("matrix not square") } if t.Rows == 0 { return 0, true } if i < 0 || t.Rows <= i { panic("index out of range") } first = true if i > 0 && t.Data[i*t.Stride+i-1] != 0 { // There is a non-zero element to the left, therefore i must // point to the second row in a 2×2 diagonal block. first = false i-- } size = 1 if i+1 < t.Rows && t.Data[(i+1)*t.Stride+i] != 0 { // There is a non-zero element below, this must be a 2×2 // diagonal block. size = 2 } return size, first } // containsComplex returns whether z is approximately equal to one of the complex // numbers in v. If z is found, its index in v will be also returned. func containsComplex(v []complex128, z complex128, tol float64) (found bool, index int) { for i := range v { if cmplx.Abs(v[i]-z) < tol { return true, i } } return false, -1 } // isAllNaN returns whether x contains only NaN values. func isAllNaN(x []float64) bool { for _, v := range x { if !math.IsNaN(v) { return false } } return true } // isUpperHessenberg returns whether h contains only zeros below the // subdiagonal. func isUpperHessenberg(h blas64.General) bool { if h.Rows != h.Cols { panic("matrix not square") } n := h.Rows for i := 0; i < n; i++ { for j := 0; j < n; j++ { if i > j+1 && h.Data[i*h.Stride+j] != 0 { return false } } } return true } // isUpperTriangular returns whether a contains only zeros below the diagonal. func isUpperTriangular(a blas64.General) bool { n := a.Rows for i := 1; i < n; i++ { for j := 0; j < i; j++ { if a.Data[i*a.Stride+j] != 0 { return false } } } return true } // unbalancedSparseGeneral returns an m×n dense matrix with a random sparse // structure consisting of nz nonzero elements. The matrix will be unbalanced by // multiplying each element randomly by its row or column index. func unbalancedSparseGeneral(m, n, stride int, nonzeros int, rnd *rand.Rand) blas64.General { a := zeros(m, n, stride) for k := 0; k < nonzeros; k++ { i := rnd.Intn(n) j := rnd.Intn(n) if rnd.Float64() < 0.5 { a.Data[i*stride+j] = float64(i+1) * rnd.NormFloat64() } else { a.Data[i*stride+j] = float64(j+1) * rnd.NormFloat64() } } return a } // rootsOfUnity returns the n complex numbers whose n-th power is equal to 1. func rootsOfUnity(n int) []complex128 { w := make([]complex128, n) for i := 0; i < n; i++ { angle := math.Pi * float64(2*i) / float64(n) w[i] = complex(math.Cos(angle), math.Sin(angle)) } return w } // constructGSVDresults returns the matrices [ 0 R ], D1 and D2 described // in the documentation of Dtgsja and Dggsvd3, and the result matrix in // the documentation for Dggsvp3. func constructGSVDresults(n, p, m, k, l int, a, b blas64.General, alpha, beta []float64) (zeroR, d1, d2 blas64.General) { // [ 0 R ] zeroR = zeros(k+l, n, n) dst := zeroR dst.Rows = min(m, k+l) dst.Cols = k + l dst.Data = zeroR.Data[n-k-l:] src := a src.Rows = min(m, k+l) src.Cols = k + l src.Data = a.Data[n-k-l:] copyGeneral(dst, src) if m < k+l { // [ 0 R ] dst.Rows = k + l - m dst.Cols = k + l - m dst.Data = zeroR.Data[m*zeroR.Stride+n-(k+l-m):] src = b src.Rows = k + l - m src.Cols = k + l - m src.Data = b.Data[(m-k)*b.Stride+n+m-k-l:] copyGeneral(dst, src) } // D1 d1 = zeros(m, k+l, k+l) for i := 0; i < k; i++ { d1.Data[i*d1.Stride+i] = 1 } for i := k; i < min(m, k+l); i++ { d1.Data[i*d1.Stride+i] = alpha[i] } // D2 d2 = zeros(p, k+l, k+l) for i := 0; i < min(l, m-k); i++ { d2.Data[i*d2.Stride+i+k] = beta[k+i] } for i := m - k; i < l; i++ { d2.Data[i*d2.Stride+i+k] = 1 } return zeroR, d1, d2 } func constructGSVPresults(n, p, m, k, l int, a, b blas64.General) (zeroA, zeroB blas64.General) { zeroA = zeros(m, n, n) dst := zeroA dst.Rows = min(m, k+l) dst.Cols = k + l dst.Data = zeroA.Data[n-k-l:] src := a dst.Rows = min(m, k+l) src.Cols = k + l src.Data = a.Data[n-k-l:] copyGeneral(dst, src) zeroB = zeros(p, n, n) dst = zeroB dst.Rows = l dst.Cols = l dst.Data = zeroB.Data[n-l:] src = b dst.Rows = l src.Cols = l src.Data = b.Data[n-l:] copyGeneral(dst, src) return zeroA, zeroB } // distFromIdentity returns the L-infinity distance of an n×n matrix A from the // identity. If A contains NaN elements, distFromIdentity will return +inf. func distFromIdentity(n int, a []float64, lda int) float64 { var dist float64 for i := 0; i < n; i++ { for j := 0; j < n; j++ { aij := a[i*lda+j] if math.IsNaN(aij) { return math.Inf(1) } if i == j { dist = math.Max(dist, math.Abs(aij-1)) } else { dist = math.Max(dist, math.Abs(aij)) } } } return dist } func sameFloat64(a, b float64) bool { return a == b || math.IsNaN(a) && math.IsNaN(b) } // sameLowerTri returns whether n×n matrices A and B are same under the diagonal. func sameLowerTri(n int, a []float64, lda int, b []float64, ldb int) bool { for i := 1; i < n; i++ { for j := 0; j < i; j++ { aij := a[i*lda+j] bij := b[i*ldb+j] if !sameFloat64(aij, bij) { return false } } } return true } // sameUpperTri returns whether n×n matrices A and B are same above the diagonal. func sameUpperTri(n int, a []float64, lda int, b []float64, ldb int) bool { for i := 0; i < n-1; i++ { for j := i + 1; j < n; j++ { aij := a[i*lda+j] bij := b[i*ldb+j] if !sameFloat64(aij, bij) { return false } } } return true } // svdJobString returns a string representation of job. func svdJobString(job lapack.SVDJob) string { switch job { case lapack.SVDAll: return "All" case lapack.SVDStore: return "Store" case lapack.SVDOverwrite: return "Overwrite" case lapack.SVDNone: return "None" } return "unknown SVD job" } // residualOrthogonal returns the residual // // |I - Q * Qᵀ| if m < n or (m == n and rowwise == true), // |I - Qᵀ * Q| otherwise. // // It can be used to check that the matrix Q is orthogonal. func residualOrthogonal(q blas64.General, rowwise bool) float64 { m, n := q.Rows, q.Cols if m == 0 || n == 0 { return 0 } var transq blas.Transpose if m < n || (m == n && rowwise) { transq = blas.NoTrans } else { transq = blas.Trans } minmn := min(m, n) // Set work = I. work := blas64.Symmetric{ Uplo: blas.Upper, N: minmn, Data: make([]float64, minmn*minmn), Stride: minmn, } for i := 0; i < minmn; i++ { work.Data[i*work.Stride+i] = 1 } // Compute // work = work - Q * Qᵀ = I - Q * Qᵀ // or // work = work - Qᵀ * Q = I - Qᵀ * Q blas64.Syrk(transq, -1, q, 1, work) return dlansy(lapack.MaxColumnSum, blas.Upper, work.N, work.Data, work.Stride) } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/iladlc.go000066400000000000000000000023371450372207100230100ustar00rootroot00000000000000// 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 testlapack import "testing" type Iladlcer interface { Iladlc(m, n int, a []float64, lda int) int } func IladlcTest(t *testing.T, impl Iladlcer) { for i, test := range []struct { a []float64 m, n, lda int ans int }{ { a: []float64{0, 0, 0, 0}, m: 1, n: 1, lda: 2, ans: -1, }, { a: []float64{0, 0, 0, 0}, m: 2, n: 2, lda: 2, ans: -1, }, { a: []float64{0, 0, 0, 0}, m: 4, n: 1, lda: 1, ans: -1, }, { a: []float64{0, 0, 0, 0}, m: 1, n: 4, lda: 4, ans: -1, }, { a: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, }, m: 2, n: 4, lda: 4, ans: 3, }, { a: []float64{ 1, 2, 3, 0, 0, 0, 0, 0, }, m: 2, n: 4, lda: 4, ans: 2, }, { a: []float64{ 0, 0, 3, 4, 0, 0, 0, 0, }, m: 2, n: 2, lda: 4, ans: -1, }, } { ans := impl.Iladlc(test.m, test.n, test.a, test.lda) if ans != test.ans { t.Errorf("Column mismatch case %v. Want: %v, got: %v", i, test.ans, ans) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/iladlr.go000066400000000000000000000023371450372207100230270ustar00rootroot00000000000000// 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 testlapack import "testing" type Iladlrer interface { Iladlr(m, n int, a []float64, lda int) int } func IladlrTest(t *testing.T, impl Iladlrer) { for i, test := range []struct { a []float64 m, n, lda int ans int }{ { a: []float64{0, 0, 0, 0}, m: 1, n: 1, lda: 2, ans: -1, }, { a: []float64{0, 0, 0, 0}, m: 2, n: 2, lda: 2, ans: -1, }, { a: []float64{0, 0, 0, 0}, m: 4, n: 1, lda: 1, ans: -1, }, { a: []float64{0, 0, 0, 0}, m: 1, n: 4, lda: 4, ans: -1, }, { a: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, }, m: 2, n: 4, lda: 4, ans: 1, }, { a: []float64{ 1, 2, 3, 0, 0, 0, 0, 0, }, m: 2, n: 4, lda: 4, ans: 0, }, { a: []float64{ 0, 0, 3, 4, 0, 0, 0, 0, }, m: 2, n: 2, lda: 4, ans: -1, }, } { ans := impl.Iladlr(test.m, test.n, test.a, test.lda) if ans != test.ans { t.Errorf("Column mismatch case %v. Want: %v, got: %v", i, test.ans, ans) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/locallapack.go000066400000000000000000000322161450372207100240250ustar00rootroot00000000000000// Copyright ©2020 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 testlapack import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/internal/asm/f64" "gonum.org/v1/gonum/lapack" ) // dlagtm is a local implementation of Dlagtm to keep code paths independent. func dlagtm(trans blas.Transpose, m, n int, alpha float64, dl, d, du []float64, b []float64, ldb int, beta float64, c []float64, ldc int) { if m == 0 || n == 0 { return } if beta != 1 { if beta == 0 { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] = 0 } } } else { for i := 0; i < m; i++ { ci := c[i*ldc : i*ldc+n] for j := range ci { ci[j] *= beta } } } } if alpha == 0 { return } if m == 1 { if alpha == 1 { for j := 0; j < n; j++ { c[j] += d[0] * b[j] } } else { for j := 0; j < n; j++ { c[j] += alpha * d[0] * b[j] } } return } if trans != blas.NoTrans { dl, du = du, dl } if alpha == 1 { for j := 0; j < n; j++ { c[j] += d[0]*b[j] + du[0]*b[ldb+j] } for i := 1; i < m-1; i++ { for j := 0; j < n; j++ { c[i*ldc+j] += dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j] } } for j := 0; j < n; j++ { c[(m-1)*ldc+j] += dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j] } } else { for j := 0; j < n; j++ { c[j] += alpha * (d[0]*b[j] + du[0]*b[ldb+j]) } for i := 1; i < m-1; i++ { for j := 0; j < n; j++ { c[i*ldc+j] += alpha * (dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j]) } } for j := 0; j < n; j++ { c[(m-1)*ldc+j] += alpha * (dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j]) } } } // dlangt is a local implementation of Dlangt to keep code paths independent. func dlangt(norm lapack.MatrixNorm, n int, dl, d, du []float64) float64 { if n == 0 { return 0 } dl = dl[:n-1] d = d[:n] du = du[:n-1] var anorm float64 switch norm { case lapack.MaxAbs: for _, diag := range [][]float64{dl, d, du} { for _, di := range diag { if math.IsNaN(di) { return di } di = math.Abs(di) if di > anorm { anorm = di } } } case lapack.MaxColumnSum: if n == 1 { return math.Abs(d[0]) } anorm = math.Abs(d[0]) + math.Abs(dl[0]) if math.IsNaN(anorm) { return anorm } tmp := math.Abs(du[n-2]) + math.Abs(d[n-1]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } for i := 1; i < n-1; i++ { tmp = math.Abs(du[i-1]) + math.Abs(d[i]) + math.Abs(dl[i]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } } case lapack.MaxRowSum: if n == 1 { return math.Abs(d[0]) } anorm = math.Abs(d[0]) + math.Abs(du[0]) if math.IsNaN(anorm) { return anorm } tmp := math.Abs(dl[n-2]) + math.Abs(d[n-1]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } for i := 1; i < n-1; i++ { tmp = math.Abs(dl[i-1]) + math.Abs(d[i]) + math.Abs(du[i]) if math.IsNaN(tmp) { return tmp } if tmp > anorm { anorm = tmp } } case lapack.Frobenius: panic("not implemented") default: panic("invalid norm") } return anorm } // dlansy is a local implementation of Dlansy to keep code paths independent. func dlansy(norm lapack.MatrixNorm, uplo blas.Uplo, n int, a []float64, lda int) float64 { if n == 0 { return 0 } work := make([]float64, n) switch norm { case lapack.MaxAbs: if uplo == blas.Upper { var max float64 for i := 0; i < n; i++ { for j := i; j < n; j++ { v := math.Abs(a[i*lda+j]) if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } } return max } var max float64 for i := 0; i < n; i++ { for j := 0; j <= i; j++ { v := math.Abs(a[i*lda+j]) if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } } return max case lapack.MaxRowSum, lapack.MaxColumnSum: // A symmetric matrix has the same 1-norm and ∞-norm. for i := 0; i < n; i++ { work[i] = 0 } if uplo == blas.Upper { for i := 0; i < n; i++ { work[i] += math.Abs(a[i*lda+i]) for j := i + 1; j < n; j++ { v := math.Abs(a[i*lda+j]) work[i] += v work[j] += v } } } else { for i := 0; i < n; i++ { for j := 0; j < i; j++ { v := math.Abs(a[i*lda+j]) work[i] += v work[j] += v } work[i] += math.Abs(a[i*lda+i]) } } var max float64 for i := 0; i < n; i++ { v := work[i] if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } return max case lapack.Frobenius: panic("not implemented") default: panic("invalid norm") } } // dlange is a local implementation of Dlange to keep code paths independent. func dlange(norm lapack.MatrixNorm, m, n int, a []float64, lda int) float64 { if m == 0 || n == 0 { return 0 } var value float64 switch norm { case lapack.MaxAbs: for i := 0; i < m; i++ { for j := 0; j < n; j++ { value = math.Max(value, math.Abs(a[i*lda+j])) } } case lapack.MaxColumnSum: work := make([]float64, n) for i := 0; i < m; i++ { for j := 0; j < n; j++ { work[j] += math.Abs(a[i*lda+j]) } } for i := 0; i < n; i++ { value = math.Max(value, work[i]) } case lapack.MaxRowSum: for i := 0; i < m; i++ { var sum float64 for j := 0; j < n; j++ { sum += math.Abs(a[i*lda+j]) } value = math.Max(value, sum) } case lapack.Frobenius: for i := 0; i < m; i++ { row := f64.L2NormUnitary(a[i*lda : i*lda+n]) value = math.Hypot(value, row) } default: panic("invalid norm") } return value } // dlansb is a local implementation of Dlansb to keep code paths independent. func dlansb(norm lapack.MatrixNorm, uplo blas.Uplo, n, kd int, ab []float64, ldab int, work []float64) float64 { if n == 0 { return 0 } var value float64 switch norm { case lapack.MaxAbs: if uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j < min(n-i, kd+1); j++ { aij := math.Abs(ab[i*ldab+j]) if aij > value || math.IsNaN(aij) { value = aij } } } } else { for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd+1; j++ { aij := math.Abs(ab[i*ldab+j]) if aij > value || math.IsNaN(aij) { value = aij } } } } case lapack.MaxColumnSum, lapack.MaxRowSum: work = work[:n] var sum float64 if uplo == blas.Upper { for i := range work { work[i] = 0 } for i := 0; i < n; i++ { sum := work[i] + math.Abs(ab[i*ldab]) for j := i + 1; j < min(i+kd+1, n); j++ { aij := math.Abs(ab[i*ldab+j-i]) sum += aij work[j] += aij } if sum > value || math.IsNaN(sum) { value = sum } } } else { for i := 0; i < n; i++ { sum = 0 for j := max(0, i-kd); j < i; j++ { aij := math.Abs(ab[i*ldab+kd+j-i]) sum += aij work[j] += aij } work[i] = sum + math.Abs(ab[i*ldab+kd]) } for _, sum := range work { if sum > value || math.IsNaN(sum) { value = sum } } } case lapack.Frobenius: panic("not implemented") default: panic("invalid norm") } return value } // dlantr is a local implementation of Dlantr to keep code paths independent. func dlantr(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 { // Quick return if possible. minmn := min(m, n) if minmn == 0 { return 0 } switch norm { case lapack.MaxAbs: if diag == blas.Unit { value := 1.0 if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i + 1; j < n; j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value } for i := 1; i < m; i++ { for j := 0; j < min(i, n); j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value } var value float64 if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i; j < n; j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value } for i := 0; i < m; i++ { for j := 0; j <= min(i, n-1); j++ { tmp := math.Abs(a[i*lda+j]) if math.IsNaN(tmp) { return tmp } if tmp > value { value = tmp } } } return value case lapack.MaxColumnSum: if diag == blas.Unit { for i := 0; i < minmn; i++ { work[i] = 1 } for i := minmn; i < n; i++ { work[i] = 0 } if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i + 1; j < n; j++ { work[j] += math.Abs(a[i*lda+j]) } } } else { for i := 1; i < m; i++ { for j := 0; j < min(i, n); j++ { work[j] += math.Abs(a[i*lda+j]) } } } } else { for i := 0; i < n; i++ { work[i] = 0 } if uplo == blas.Upper { for i := 0; i < m; i++ { for j := i; j < n; j++ { work[j] += math.Abs(a[i*lda+j]) } } } else { for i := 0; i < m; i++ { for j := 0; j <= min(i, n-1); j++ { work[j] += math.Abs(a[i*lda+j]) } } } } var max float64 for _, v := range work[:n] { if math.IsNaN(v) { return math.NaN() } if v > max { max = v } } return max case lapack.MaxRowSum: var maxsum float64 if diag == blas.Unit { if uplo == blas.Upper { for i := 0; i < m; i++ { var sum float64 if i < minmn { sum = 1 } for j := i + 1; j < n; j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return math.NaN() } if sum > maxsum { maxsum = sum } } return maxsum } else { for i := 0; i < m; i++ { var sum float64 if i < minmn { sum = 1 } for j := 0; j < min(i, n); j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return math.NaN() } if sum > maxsum { maxsum = sum } } return maxsum } } else { if uplo == blas.Upper { for i := 0; i < m; i++ { var sum float64 for j := i; j < n; j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return sum } if sum > maxsum { maxsum = sum } } return maxsum } else { for i := 0; i < m; i++ { var sum float64 for j := 0; j <= min(i, n-1); j++ { sum += math.Abs(a[i*lda+j]) } if math.IsNaN(sum) { return sum } if sum > maxsum { maxsum = sum } } return maxsum } } case lapack.Frobenius: panic("not implemented") default: panic("invalid norm") } } // dlantb is a local implementation of Dlantb to keep code paths independent. func dlantb(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k int, a []float64, lda int, work []float64) float64 { if n == 0 { return 0 } var value float64 switch norm { case lapack.MaxAbs: if uplo == blas.Upper { var jfirst int if diag == blas.Unit { value = 1 jfirst = 1 } for i := 0; i < n; i++ { for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { if math.IsNaN(aij) { return aij } aij = math.Abs(aij) if aij > value { value = aij } } } } else { jlast := k + 1 if diag == blas.Unit { value = 1 jlast = k } for i := 0; i < n; i++ { for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] { if math.IsNaN(aij) { return math.NaN() } aij = math.Abs(aij) if aij > value { value = aij } } } } case lapack.MaxRowSum: var sum float64 if uplo == blas.Upper { var jfirst int if diag == blas.Unit { jfirst = 1 } for i := 0; i < n; i++ { sum = 0 if diag == blas.Unit { sum = 1 } for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { sum += math.Abs(aij) } if math.IsNaN(sum) { return math.NaN() } if sum > value { value = sum } } } else { jlast := k + 1 if diag == blas.Unit { jlast = k } for i := 0; i < n; i++ { sum = 0 if diag == blas.Unit { sum = 1 } for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] { sum += math.Abs(aij) } if math.IsNaN(sum) { return math.NaN() } if sum > value { value = sum } } } case lapack.MaxColumnSum: work = work[:n] if diag == blas.Unit { for i := range work { work[i] = 1 } } else { for i := range work { work[i] = 0 } } if uplo == blas.Upper { var jfirst int if diag == blas.Unit { jfirst = 1 } for i := 0; i < n; i++ { for j, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { work[i+jfirst+j] += math.Abs(aij) } } } else { jlast := k + 1 if diag == blas.Unit { jlast = k } for i := 0; i < n; i++ { off := max(0, k-i) for j, aij := range a[i*lda+off : i*lda+jlast] { work[i+j+off-k] += math.Abs(aij) } } } for _, wi := range work { if math.IsNaN(wi) { return math.NaN() } if wi > value { value = wi } } case lapack.Frobenius: panic("not implemented") default: panic("invalid norm") } return value } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/matgen.go000066400000000000000000000746751450372207100230510ustar00rootroot00000000000000// 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 testlapack import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) // Dlatm1 computes the entries of dst as specified by mode, cond and rsign. // // mode describes how dst will be computed: // // |mode| == 1: dst[0] = 1 and dst[1:n] = 1/cond // |mode| == 2: dst[:n-1] = 1/cond and dst[n-1] = 1 // |mode| == 3: dst[i] = cond^{-i/(n-1)}, i=0,...,n-1 // |mode| == 4: dst[i] = 1 - i*(1-1/cond)/(n-1) // |mode| == 5: dst[i] = random number in the range (1/cond, 1) such that // their logarithms are uniformly distributed // |mode| == 6: dst[i] = random number from the distribution given by dist // // If mode is negative, the order of the elements of dst will be reversed. // For other values of mode Dlatm1 will panic. // // If rsign is true and mode is not ±6, each entry of dst will be multiplied by 1 // or -1 with probability 0.5 // // dist specifies the type of distribution to be used when mode == ±6: // // dist == 1: Uniform[0,1) // dist == 2: Uniform[-1,1) // dist == 3: Normal(0,1) // // For other values of dist Dlatm1 will panic. // // rnd is used as a source of random numbers. func Dlatm1(dst []float64, mode int, cond float64, rsign bool, dist int, rnd *rand.Rand) { amode := mode if amode < 0 { amode = -amode } if amode < 1 || 6 < amode { panic("testlapack: invalid mode") } if cond < 1 { panic("testlapack: cond < 1") } if amode == 6 && (dist < 1 || 3 < dist) { panic("testlapack: invalid dist") } n := len(dst) if n == 0 { return } switch amode { case 1: dst[0] = 1 for i := 1; i < n; i++ { dst[i] = 1 / cond } case 2: for i := 0; i < n-1; i++ { dst[i] = 1 } dst[n-1] = 1 / cond case 3: dst[0] = 1 if n > 1 { alpha := math.Pow(cond, -1/float64(n-1)) for i := 1; i < n; i++ { dst[i] = math.Pow(alpha, float64(i)) } } case 4: dst[0] = 1 if n > 1 { condInv := 1 / cond alpha := (1 - condInv) / float64(n-1) for i := 1; i < n; i++ { dst[i] = float64(n-i-1)*alpha + condInv } } case 5: alpha := math.Log(1 / cond) for i := range dst { dst[i] = math.Exp(alpha * rnd.Float64()) } case 6: switch dist { case 1: for i := range dst { dst[i] = rnd.Float64() } case 2: for i := range dst { dst[i] = 2*rnd.Float64() - 1 } case 3: for i := range dst { dst[i] = rnd.NormFloat64() } } } if rsign && amode != 6 { for i, v := range dst { if rnd.Float64() < 0.5 { dst[i] = -v } } } if mode < 0 { for i := 0; i < n/2; i++ { dst[i], dst[n-i-1] = dst[n-i-1], dst[i] } } } // Dlagsy generates an n×n symmetric matrix A, by pre- and post- multiplying a // real diagonal matrix D with a random orthogonal matrix: // // A = U * D * Uᵀ. // // work must have length at least 2*n, otherwise Dlagsy will panic. // // The parameter k is unused but it must satisfy // // 0 <= k <= n-1. func Dlagsy(n, k int, d []float64, a []float64, lda int, rnd *rand.Rand, work []float64) { checkMatrix(n, n, a, lda) if k < 0 || max(0, n-1) < k { panic("testlapack: invalid value of k") } if len(d) != n { panic("testlapack: bad length of d") } if len(work) < 2*n { panic("testlapack: insufficient work length") } // Initialize lower triangle of A to diagonal matrix. for i := 1; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = 0 } } for i := 0; i < n; i++ { a[i*lda+i] = d[i] } bi := blas64.Implementation() // Generate lower triangle of symmetric matrix. for i := n - 2; i >= 0; i-- { for j := 0; j < n-i; j++ { work[j] = rnd.NormFloat64() } wn := bi.Dnrm2(n-i, work[:n-i], 1) wa := math.Copysign(wn, work[0]) var tau float64 if wn != 0 { wb := work[0] + wa bi.Dscal(n-i-1, 1/wb, work[1:n-i], 1) work[0] = 1 tau = wb / wa } // Apply random reflection to A[i:n,i:n] from the left and the // right. // // Compute y := tau * A * u. bi.Dsymv(blas.Lower, n-i, tau, a[i*lda+i:], lda, work[:n-i], 1, 0, work[n:2*n-i], 1) // Compute v := y - 1/2 * tau * ( y, u ) * u. alpha := -0.5 * tau * bi.Ddot(n-i, work[n:2*n-i], 1, work[:n-i], 1) bi.Daxpy(n-i, alpha, work[:n-i], 1, work[n:2*n-i], 1) // Apply the transformation as a rank-2 update to A[i:n,i:n]. bi.Dsyr2(blas.Lower, n-i, -1, work[:n-i], 1, work[n:2*n-i], 1, a[i*lda+i:], lda) } // Store full symmetric matrix. for i := 1; i < n; i++ { for j := 0; j < i; j++ { a[j*lda+i] = a[i*lda+j] } } } // Dlagge generates a real general m×n matrix A, by pre- and post-multiplying // a real diagonal matrix D with random orthogonal matrices: // // A = U*D*V. // // d must have length min(m,n), and work must have length m+n, otherwise Dlagge // will panic. // // The parameters ku and kl are unused but they must satisfy // // 0 <= kl <= m-1, // 0 <= ku <= n-1. func Dlagge(m, n, kl, ku int, d []float64, a []float64, lda int, rnd *rand.Rand, work []float64) { checkMatrix(m, n, a, lda) if kl < 0 || max(0, m-1) < kl { panic("testlapack: invalid value of kl") } if ku < 0 || max(0, n-1) < ku { panic("testlapack: invalid value of ku") } if len(d) != min(m, n) { panic("testlapack: bad length of d") } if len(work) < m+n { panic("testlapack: insufficient work length") } // Initialize A to diagonal matrix. for i := 0; i < m; i++ { for j := 0; j < n; j++ { a[i*lda+j] = 0 } } for i := 0; i < min(m, n); i++ { a[i*lda+i] = d[i] } // Quick exit if the user wants a diagonal matrix. // if kl == 0 && ku == 0 { // return // } bi := blas64.Implementation() // Pre- and post-multiply A by random orthogonal matrices. for i := min(m, n) - 1; i >= 0; i-- { if i < m-1 { for j := 0; j < m-i; j++ { work[j] = rnd.NormFloat64() } wn := bi.Dnrm2(m-i, work[:m-i], 1) wa := math.Copysign(wn, work[0]) var tau float64 if wn != 0 { wb := work[0] + wa bi.Dscal(m-i-1, 1/wb, work[1:m-i], 1) work[0] = 1 tau = wb / wa } // Multiply A[i:m,i:n] by random reflection from the left. bi.Dgemv(blas.Trans, m-i, n-i, 1, a[i*lda+i:], lda, work[:m-i], 1, 0, work[m:m+n-i], 1) bi.Dger(m-i, n-i, -tau, work[:m-i], 1, work[m:m+n-i], 1, a[i*lda+i:], lda) } if i < n-1 { for j := 0; j < n-i; j++ { work[j] = rnd.NormFloat64() } wn := bi.Dnrm2(n-i, work[:n-i], 1) wa := math.Copysign(wn, work[0]) var tau float64 if wn != 0 { wb := work[0] + wa bi.Dscal(n-i-1, 1/wb, work[1:n-i], 1) work[0] = 1 tau = wb / wa } // Multiply A[i:m,i:n] by random reflection from the right. bi.Dgemv(blas.NoTrans, m-i, n-i, 1, a[i*lda+i:], lda, work[:n-i], 1, 0, work[n:n+m-i], 1) bi.Dger(m-i, n-i, -tau, work[n:n+m-i], 1, work[:n-i], 1, a[i*lda+i:], lda) } } // TODO(vladimir-ch): Reduce number of subdiagonals to kl and number of // superdiagonals to ku. } // dlarnv fills dst with random numbers from a uniform or normal distribution // specified by dist: // // dist=1: uniform(0,1), // dist=2: uniform(-1,1), // dist=3: normal(0,1). // // For other values of dist dlarnv will panic. func dlarnv(dst []float64, dist int, rnd *rand.Rand) { switch dist { default: panic("testlapack: invalid dist") case 1: for i := range dst { dst[i] = rnd.Float64() } case 2: for i := range dst { dst[i] = 2*rnd.Float64() - 1 } case 3: for i := range dst { dst[i] = rnd.NormFloat64() } } } // dlattr generates an n×n triangular test matrix A with its properties uniquely // determined by imat and uplo, and returns whether A has unit diagonal. If diag // is blas.Unit, the diagonal elements are set so that A[k,k]=k. // // trans specifies whether the matrix A or its transpose will be used. // // If imat is greater than 10, dlattr also generates the right hand side of the // linear system A*x=b, or Aᵀ*x=b. Valid values of imat are 7, and all between 11 // and 19, inclusive. // // b mush have length n, and work must have length 3*n, and dlattr will panic // otherwise. func dlattr(imat int, uplo blas.Uplo, trans blas.Transpose, n int, a []float64, lda int, b, work []float64, rnd *rand.Rand) (diag blas.Diag) { checkMatrix(n, n, a, lda) if len(b) != n { panic("testlapack: bad length of b") } if len(work) < 3*n { panic("testlapack: insufficient length of work") } if uplo != blas.Upper && uplo != blas.Lower { panic("testlapack: bad uplo") } if trans != blas.Trans && trans != blas.NoTrans { panic("testlapack: bad trans") } if n == 0 { return blas.NonUnit } const ( tiny = safmin huge = (1 - ulp) / tiny ) bi := blas64.Implementation() switch imat { default: // TODO(vladimir-ch): Implement the remaining cases. panic("testlapack: invalid or unimplemented imat") case 7: // Identity matrix. The diagonal is set to NaN. diag = blas.Unit switch uplo { case blas.Upper: for i := 0; i < n; i++ { a[i*lda+i] = math.NaN() for j := i + 1; j < n; j++ { a[i*lda+j] = 0 } } case blas.Lower: for i := 0; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = 0 } a[i*lda+i] = math.NaN() } } case 11: // Generate a triangular matrix with elements between -1 and 1, // give the diagonal norm 2 to make it well-conditioned, and // make the right hand side large so that it requires scaling. diag = blas.NonUnit switch uplo { case blas.Upper: for i := 0; i < n-1; i++ { dlarnv(a[i*lda+i:i*lda+n], 2, rnd) } case blas.Lower: for i := 1; i < n; i++ { dlarnv(a[i*lda:i*lda+i+1], 2, rnd) } } for i := 0; i < n; i++ { a[i*lda+i] = math.Copysign(2, a[i*lda+i]) } // Set the right hand side so that the largest value is huge. dlarnv(b, 2, rnd) imax := bi.Idamax(n, b, 1) bscal := huge / math.Max(1, b[imax]) bi.Dscal(n, bscal, b, 1) case 12: // Make the first diagonal element in the solve small to cause // immediate overflow when dividing by T[j,j]. The off-diagonal // elements are small (cnorm[j] < 1). diag = blas.NonUnit tscal := 1 / math.Max(1, float64(n-1)) switch uplo { case blas.Upper: for i := 0; i < n; i++ { dlarnv(a[i*lda+i:i*lda+n], 2, rnd) bi.Dscal(n-i-1, tscal, a[i*lda+i+1:], 1) a[i*lda+i] = math.Copysign(1, a[i*lda+i]) } a[(n-1)*lda+n-1] *= tiny case blas.Lower: for i := 0; i < n; i++ { dlarnv(a[i*lda:i*lda+i+1], 2, rnd) bi.Dscal(i, tscal, a[i*lda:], 1) a[i*lda+i] = math.Copysign(1, a[i*lda+i]) } a[0] *= tiny } dlarnv(b, 2, rnd) case 13: // Make the first diagonal element in the solve small to cause // immediate overflow when dividing by T[j,j]. The off-diagonal // elements are O(1) (cnorm[j] > 1). diag = blas.NonUnit switch uplo { case blas.Upper: for i := 0; i < n; i++ { dlarnv(a[i*lda+i:i*lda+n], 2, rnd) a[i*lda+i] = math.Copysign(1, a[i*lda+i]) } a[(n-1)*lda+n-1] *= tiny case blas.Lower: for i := 0; i < n; i++ { dlarnv(a[i*lda:i*lda+i+1], 2, rnd) a[i*lda+i] = math.Copysign(1, a[i*lda+i]) } a[0] *= tiny } dlarnv(b, 2, rnd) case 14: // T is diagonal with small numbers on the diagonal to // make the growth factor underflow, but a small right hand side // chosen so that the solution does not overflow. diag = blas.NonUnit switch uplo { case blas.Upper: for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { a[i*lda+j] = 0 } if (n-1-i)&0x2 == 0 { a[i*lda+i] = tiny } else { a[i*lda+i] = 1 } } case blas.Lower: for i := 0; i < n; i++ { for j := 0; j < i; j++ { a[i*lda+j] = 0 } if i&0x2 == 0 { a[i*lda+i] = tiny } else { a[i*lda+i] = 1 } } } // Set the right hand side alternately zero and small. switch uplo { case blas.Upper: b[0] = 0 for i := n - 1; i > 0; i -= 2 { b[i] = 0 b[i-1] = tiny } case blas.Lower: for i := 0; i < n-1; i += 2 { b[i] = 0 b[i+1] = tiny } b[n-1] = 0 } case 15: // Make the diagonal elements small to cause gradual overflow // when dividing by T[j,j]. To control the amount of scaling // needed, the matrix is bidiagonal. diag = blas.NonUnit texp := 1 / math.Max(1, float64(n-1)) tscal := math.Pow(tiny, texp) switch uplo { case blas.Upper: for i := 0; i < n; i++ { a[i*lda+i] = tscal if i < n-1 { a[i*lda+i+1] = -1 } for j := i + 2; j < n; j++ { a[i*lda+j] = 0 } } case blas.Lower: for i := 0; i < n; i++ { for j := 0; j < i-1; j++ { a[i*lda+j] = 0 } if i > 0 { a[i*lda+i-1] = -1 } a[i*lda+i] = tscal } } dlarnv(b, 2, rnd) case 16: // One zero diagonal element. diag = blas.NonUnit switch uplo { case blas.Upper: for i := 0; i < n; i++ { dlarnv(a[i*lda+i:i*lda+n], 2, rnd) a[i*lda+i] = math.Copysign(2, a[i*lda+i]) } case blas.Lower: for i := 0; i < n; i++ { dlarnv(a[i*lda:i*lda+i+1], 2, rnd) a[i*lda+i] = math.Copysign(2, a[i*lda+i]) } } iy := n / 2 a[iy*lda+iy] = 0 dlarnv(b, 2, rnd) bi.Dscal(n, 2, b, 1) case 17: // Make the offdiagonal elements large to cause overflow when // adding a column of T. In the non-transposed case, the matrix // is constructed to cause overflow when adding a column in // every other step. diag = blas.NonUnit tscal := (1 - ulp) / tiny texp := 1.0 switch uplo { case blas.Upper: for i := 0; i < n; i++ { for j := i; j < n; j++ { a[i*lda+j] = 0 } } for j := n - 1; j >= 1; j -= 2 { a[j] = -tscal / float64(n+1) a[j*lda+j] = 1 b[j] = texp * (1 - ulp) a[j-1] = -tscal / float64(n+1) / float64(n+2) a[(j-1)*lda+j-1] = 1 b[j-1] = texp * float64(n*n+n-1) texp *= 2 } b[0] = float64(n+1) / float64(n+2) * tscal case blas.Lower: for i := 0; i < n; i++ { for j := 0; j <= i; j++ { a[i*lda+j] = 0 } } for j := 0; j < n-1; j += 2 { a[(n-1)*lda+j] = -tscal / float64(n+1) a[j*lda+j] = 1 b[j] = texp * (1 - ulp) a[(n-1)*lda+j+1] = -tscal / float64(n+1) / float64(n+2) a[(j+1)*lda+j+1] = 1 b[j+1] = texp * float64(n*n+n-1) texp *= 2 } b[n-1] = float64(n+1) / float64(n+2) * tscal } case 18: // Generate a unit triangular matrix with elements between -1 // and 1, and make the right hand side large so that it requires // scaling. The diagonal is set to NaN. diag = blas.Unit switch uplo { case blas.Upper: for i := 0; i < n; i++ { a[i*lda+i] = math.NaN() dlarnv(a[i*lda+i+1:i*lda+n], 2, rnd) } case blas.Lower: for i := 0; i < n; i++ { dlarnv(a[i*lda:i*lda+i], 2, rnd) a[i*lda+i] = math.NaN() } } // Set the right hand side so that the largest value is huge. dlarnv(b, 2, rnd) iy := bi.Idamax(n, b, 1) bnorm := math.Abs(b[iy]) bscal := huge / math.Max(1, bnorm) bi.Dscal(n, bscal, b, 1) case 19: // Generate a triangular matrix with elements between // huge/(n-1) and huge so that at least one of the column // norms will exceed huge. // Dlatrs cannot handle this case for (typically) n>5. diag = blas.NonUnit tleft := huge / math.Max(1, float64(n-1)) tscal := huge * (float64(n-1) / math.Max(1, float64(n))) switch uplo { case blas.Upper: for i := 0; i < n; i++ { dlarnv(a[i*lda+i:i*lda+n], 2, rnd) for j := i; j < n; j++ { aij := a[i*lda+j] a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij } } case blas.Lower: for i := 0; i < n; i++ { dlarnv(a[i*lda:i*lda+i+1], 2, rnd) for j := 0; j <= i; j++ { aij := a[i*lda+j] a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij } } } dlarnv(b, 2, rnd) bi.Dscal(n, 2, b, 1) } // Flip the matrix if the transpose will be used. if trans == blas.Trans { switch uplo { case blas.Upper: for j := 0; j < n/2; j++ { bi.Dswap(n-2*j-1, a[j*lda+j:], 1, a[(j+1)*lda+n-j-1:], -lda) } case blas.Lower: for j := 0; j < n/2; j++ { bi.Dswap(n-2*j-1, a[j*lda+j:], lda, a[(n-j-1)*lda+j+1:], -1) } } } return diag } func checkMatrix(m, n int, a []float64, lda int) { if m < 0 { panic("testlapack: m < 0") } if n < 0 { panic("testlapack: n < 0") } if lda < max(1, n) { panic("testlapack: lda < max(1, n)") } if len(a) < (m-1)*lda+n { panic("testlapack: insufficient matrix slice length") } } // randomOrthogonal returns an n×n random orthogonal matrix. func randomOrthogonal(n int, rnd *rand.Rand) blas64.General { q := eye(n, n) x := make([]float64, n) v := make([]float64, n) for j := 0; j < n-1; j++ { // x represents the j-th column of a random matrix. for i := 0; i < j; i++ { x[i] = 0 } for i := j; i < n; i++ { x[i] = rnd.NormFloat64() } // Compute v that represents the elementary reflector that // annihilates the subdiagonal elements of x. reflector(v, x, j) // Compute Q * H_j and store the result into Q. applyReflector(q, q, v) } return q } // reflector generates a Householder reflector v that zeros out subdiagonal // entries in the j-th column of a matrix. func reflector(v, col []float64, j int) { n := len(col) if len(v) != n { panic("slice length mismatch") } if j < 0 || n <= j { panic("invalid column index") } for i := range v { v[i] = 0 } if j == n-1 { return } s := floats.Norm(col[j:], 2) if s == 0 { return } v[j] = col[j] + math.Copysign(s, col[j]) copy(v[j+1:], col[j+1:]) s = floats.Norm(v[j:], 2) floats.Scale(1/s, v[j:]) } // applyReflector computes Q*H where H is a Householder matrix represented by // the Householder reflector v. func applyReflector(qh blas64.General, q blas64.General, v []float64) { n := len(v) if qh.Rows != n || qh.Cols != n { panic("bad size of qh") } if q.Rows != n || q.Cols != n { panic("bad size of q") } qv := make([]float64, n) blas64.Gemv(blas.NoTrans, 1, q, blas64.Vector{Data: v, Inc: 1}, 0, blas64.Vector{Data: qv, Inc: 1}) for i := 0; i < n; i++ { for j := 0; j < n; j++ { qh.Data[i*qh.Stride+j] = q.Data[i*q.Stride+j] } } for i := 0; i < n; i++ { for j := 0; j < n; j++ { qh.Data[i*qh.Stride+j] -= 2 * qv[i] * v[j] } } var norm2 float64 for _, vi := range v { norm2 += vi * vi } norm2inv := 1 / norm2 for i := 0; i < n; i++ { for j := 0; j < n; j++ { qh.Data[i*qh.Stride+j] *= norm2inv } } } func dlattb(kind int, uplo blas.Uplo, trans blas.Transpose, n, kd int, ab []float64, ldab int, rnd *rand.Rand) (diag blas.Diag, b []float64) { switch { case kind < 1 || 18 < kind: panic("bad matrix kind") case (6 <= kind && kind <= 9) || kind == 17: diag = blas.Unit default: diag = blas.NonUnit } if n == 0 { return } const ( tiny = safmin huge = (1 - ulp) / tiny small = 0.25 * (safmin / ulp) large = 1 / small badc2 = 0.1 / ulp ) badc1 := math.Sqrt(badc2) var cndnum float64 switch { case kind == 2 || kind == 8: cndnum = badc1 case kind == 3 || kind == 9: cndnum = badc2 default: cndnum = 2 } uniformM11 := func() float64 { return 2*rnd.Float64() - 1 } // Allocate the right-hand side and fill it with random numbers. // The pathological matrix types below overwrite it with their // custom vector. b = make([]float64, n) for i := range b { b[i] = uniformM11() } bi := blas64.Implementation() switch kind { default: panic("test matrix type not implemented") case 1, 2, 3, 4, 5: // Non-unit triangular matrix // TODO(vladimir-ch) var kl, ku int switch uplo { case blas.Upper: ku = kd kl = 0 // IOFF = 1 + MAX( 0, KD-N+1 ) // PACKIT = 'Q' // 'Q' => store the upper triangle in band storage scheme // (only if matrix symmetric or upper triangular) case blas.Lower: ku = 0 kl = kd // IOFF = 1 // PACKIT = 'B' // 'B' => store the lower triangle in band storage scheme // (only if matrix symmetric or lower triangular) } anorm := 1.0 switch kind { case 4: anorm = small case 5: anorm = large } _, _, _ = kl, ku, anorm // // DIST = 'S' // UNIFORM(-1, 1) // // MODE = 3 // MODE = 3 sets D(I)=CNDNUM**(-(I-1)/(N-1)) // // TYPE = 'N' // If TYPE='N', the generated matrix is nonsymmetric // CALL DLATMS( N, N, DIST, ISEED, TYPE, B, MODE, CNDNUM, ANORM, // $ KL, KU, PACKIT, AB( IOFF, 1 ), LDAB, WORK, INFO ) panic("test matrix type not implemented") case 6: // Matrix is the identity. if uplo == blas.Upper { for i := 0; i < n; i++ { // Fill the diagonal with non-unit numbers. ab[i*ldab] = float64(i + 2) for j := 1; j < min(n-i, kd+1); j++ { ab[i*ldab+j] = 0 } } } else { for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd; j++ { ab[i*ldab+j] = 0 } // Fill the diagonal with non-unit numbers. ab[i*ldab+kd] = float64(i + 2) } } case 7, 8, 9: // Non-trivial unit triangular matrix // // A unit triangular matrix T with condition cndnum is formed. // In this version, T only has bandwidth 2, the rest of it is // zero. tnorm := math.Sqrt(cndnum) // Initialize AB to zero. if uplo == blas.Upper { for i := 0; i < n; i++ { // Fill the diagonal with non-unit numbers. ab[i*ldab] = float64(i + 2) for j := 1; j < min(n-i, kd+1); j++ { ab[i*ldab+j] = 0 } } } else { for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd; j++ { ab[i*ldab+j] = 0 } // Fill the diagonal with non-unit numbers. ab[i*ldab+kd] = float64(i + 2) } } switch kd { case 0: // Unit diagonal matrix, nothing else to do. case 1: // Special case: T is tridiagonal. Set every other // off-diagonal so that the matrix has norm tnorm+1. if n > 1 { if uplo == blas.Upper { ab[1] = math.Copysign(tnorm, uniformM11()) for i := 2; i < n-1; i += 2 { ab[i*ldab+1] = tnorm * uniformM11() } } else { ab[ldab] = math.Copysign(tnorm, uniformM11()) for i := 3; i < n; i += 2 { ab[i*ldab] = tnorm * uniformM11() } } } default: // Form a unit triangular matrix T with condition cndnum. T is given // by // | 1 + * | // | 1 + | // T = | 1 + * | // | 1 + | // | 1 + * | // | 1 + | // | . . . | // Each element marked with a '*' is formed by taking the product of // the adjacent elements marked with '+'. The '*'s can be chosen // freely, and the '+'s are chosen so that the inverse of T will // have elements of the same magnitude as T. work1 := make([]float64, n) work2 := make([]float64, n) star1 := math.Copysign(tnorm, uniformM11()) sfac := math.Sqrt(tnorm) plus1 := math.Copysign(sfac, uniformM11()) for i := 0; i < n; i += 2 { work1[i] = plus1 work2[i] = star1 if i+1 == n { continue } plus2 := star1 / plus1 work1[i+1] = plus2 plus1 = star1 / plus2 // Generate a new *-value with norm between sqrt(tnorm) // and tnorm. rexp := uniformM11() if rexp < 0 { star1 = -math.Pow(sfac, 1-rexp) } else { star1 = math.Pow(sfac, 1+rexp) } } // Copy the diagonal to AB. if uplo == blas.Upper { bi.Dcopy(n-1, work1, 1, ab[1:], ldab) if n > 2 { bi.Dcopy(n-2, work2, 1, ab[2:], ldab) } } else { bi.Dcopy(n-1, work1, 1, ab[ldab+kd-1:], ldab) if n > 2 { bi.Dcopy(n-2, work2, 1, ab[2*ldab+kd-2:], ldab) } } } // Pathological test cases 10-18: these triangular matrices are badly // scaled or badly conditioned, so when used in solving a triangular // system they may cause overflow in the solution vector. case 10: // Generate a triangular matrix with elements between -1 and 1. // Give the diagonal norm 2 to make it well-conditioned. // Make the right hand side large so that it requires scaling. if uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j < min(n-j, kd+1); j++ { ab[i*ldab+j] = uniformM11() } ab[i*ldab] = math.Copysign(2, ab[i*ldab]) } } else { for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd+1; j++ { ab[i*ldab+j] = uniformM11() } ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd]) } } // Set the right hand side so that the largest value is huge. bnorm := math.Abs(b[bi.Idamax(n, b, 1)]) bscal := huge / math.Max(1, bnorm) bi.Dscal(n, bscal, b, 1) case 11: // Make the first diagonal element in the solve small to cause // immediate overflow when dividing by T[j,j]. // The offdiagonal elements are small (cnorm[j] < 1). tscal := 1 / float64(kd+1) if uplo == blas.Upper { for i := 0; i < n; i++ { jlen := min(n-i, kd+1) arow := ab[i*ldab : i*ldab+jlen] dlarnv(arow, 2, rnd) if jlen > 1 { bi.Dscal(jlen-1, tscal, arow[1:], 1) } ab[i*ldab] = math.Copysign(1, ab[i*ldab]) } ab[(n-1)*ldab] *= tiny } else { for i := 0; i < n; i++ { jlen := min(i+1, kd+1) arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1] dlarnv(arow, 2, rnd) if jlen > 1 { bi.Dscal(jlen-1, tscal, arow[:jlen-1], 1) } ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd]) } ab[kd] *= tiny } case 12: // Make the first diagonal element in the solve small to cause // immediate overflow when dividing by T[j,j]. // The offdiagonal elements are O(1) (cnorm[j] > 1). if uplo == blas.Upper { for i := 0; i < n; i++ { jlen := min(n-i, kd+1) arow := ab[i*ldab : i*ldab+jlen] dlarnv(arow, 2, rnd) ab[i*ldab] = math.Copysign(1, ab[i*ldab]) } ab[(n-1)*ldab] *= tiny } else { for i := 0; i < n; i++ { jlen := min(i+1, kd+1) arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1] dlarnv(arow, 2, rnd) ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd]) } ab[kd] *= tiny } case 13: // T is diagonal with small numbers on the diagonal to make the growth // factor underflow, but a small right hand side chosen so that the // solution does not overflow. if uplo == blas.Upper { icount := 1 for i := n - 1; i >= 0; i-- { if icount <= 2 { ab[i*ldab] = tiny } else { ab[i*ldab] = 1 } for j := 1; j < min(n-i, kd+1); j++ { ab[i*ldab+j] = 0 } icount++ if icount > 4 { icount = 1 } } } else { icount := 1 for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd; j++ { ab[i*ldab+j] = 0 } if icount <= 2 { ab[i*ldab+kd] = tiny } else { ab[i*ldab+kd] = 1 } icount++ if icount > 4 { icount = 1 } } } // Set the right hand side alternately zero and small. if uplo == blas.Upper { b[0] = 0 for i := n - 1; i > 1; i -= 2 { b[i] = 0 b[i-1] = tiny } } else { b[n-1] = 0 for i := 0; i < n-1; i += 2 { b[i] = 0 b[i+1] = tiny } } case 14: // Make the diagonal elements small to cause gradual overflow when // dividing by T[j,j]. To control the amount of scaling needed, the // matrix is bidiagonal. tscal := math.Pow(tiny, 1/float64(kd+1)) if uplo == blas.Upper { for i := 0; i < n; i++ { ab[i*ldab] = tscal if i < n-1 && kd > 0 { ab[i*ldab+1] = -1 } for j := 2; j < min(n-i, kd+1); j++ { ab[i*ldab+j] = 0 } } b[n-1] = 1 } else { for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd-1; j++ { ab[i*ldab+j] = 0 } if i > 0 && kd > 0 { ab[i*ldab+kd-1] = -1 } ab[i*ldab+kd] = tscal } b[0] = 1 } case 15: // One zero diagonal element. iy := n / 2 if uplo == blas.Upper { for i := 0; i < n; i++ { jlen := min(n-i, kd+1) dlarnv(ab[i*ldab:i*ldab+jlen], 2, rnd) if i != iy { ab[i*ldab] = math.Copysign(2, ab[i*ldab]) } else { ab[i*ldab] = 0 } } } else { for i := 0; i < n; i++ { jlen := min(i+1, kd+1) dlarnv(ab[i*ldab+kd+1-jlen:i*ldab+kd+1], 2, rnd) if i != iy { ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd]) } else { ab[i*ldab+kd] = 0 } } } bi.Dscal(n, 2, b, 1) // case 16: // TODO(vladimir-ch) // Make the off-diagonal elements large to cause overflow when adding a // column of T. In the non-transposed case, the matrix is constructed to // cause overflow when adding a column in every other step. // Initialize the matrix to zero. // if uplo == blas.Upper { // for i := 0; i < n; i++ { // for j := 0; j < min(n-i, kd+1); j++ { // ab[i*ldab+j] = 0 // } // } // } else { // for i := 0; i < n; i++ { // for j := max(0, kd-i); j < kd+1; j++ { // ab[i*ldab+j] = 0 // } // } // } // const tscal = (1 - ulp) / (unfl / ulp) // texp := 1.0 // if kd > 0 { // if uplo == blas.Upper { // for j := n - 1; j >= 0; j -= kd { // } // } else { // for j := 0; j < n; j += kd { // } // } // } else { // // Diagonal matrix. // for i := 0; i < n; i++ { // ab[i*ldab] = 1 // b[i] = float64(i + 1) // } // } case 17: // Generate a unit triangular matrix with elements between -1 and 1, and // make the right hand side large so that it requires scaling. if uplo == blas.Upper { for i := 0; i < n; i++ { ab[i*ldab] = float64(i + 2) jlen := min(n-i-1, kd) if jlen > 0 { dlarnv(ab[i*ldab+1:i*ldab+1+jlen], 2, rnd) } } } else { for i := 0; i < n; i++ { jlen := min(i, kd) if jlen > 0 { dlarnv(ab[i*ldab+kd-jlen:i*ldab+kd], 2, rnd) } ab[i*ldab+kd] = float64(i + 2) } } // Set the right hand side so that the largest value is huge. bnorm := math.Abs(b[bi.Idamax(n, b, 1)]) bscal := huge / math.Max(1, bnorm) bi.Dscal(n, bscal, b, 1) case 18: // Generate a triangular matrix with elements between huge/kd and // huge so that at least one of the column norms will exceed huge. tleft := huge / math.Max(1, float64(kd)) // The reference LAPACK has // tscal := huge * (float64(kd) / float64(kd+1)) // but this causes overflow when computing cnorm in Dlatbs. Our choice // is more conservative but increases coverage in the same way as the // LAPACK version. tscal := huge / math.Max(1, float64(kd)) if uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j < min(n-i, kd+1); j++ { r := uniformM11() ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r } } } else { for i := 0; i < n; i++ { for j := max(0, kd-i); j < kd+1; j++ { r := uniformM11() ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r } } } bi.Dscal(n, 2, b, 1) } // Flip the matrix if the transpose will be used. if trans != blas.NoTrans { if uplo == blas.Upper { for j := 0; j < n/2; j++ { jlen := min(n-2*j-1, kd+1) bi.Dswap(jlen, ab[j*ldab:], 1, ab[(n-j-jlen)*ldab+jlen-1:], min(-ldab+1, -1)) } } else { for j := 0; j < n/2; j++ { jlen := min(n-2*j-1, kd+1) bi.Dswap(jlen, ab[j*ldab+kd:], max(ldab-1, 1), ab[(n-j-1)*ldab+kd+1-jlen:], -1) } } } return diag, b } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/matgen_test.go000066400000000000000000000037331450372207100240730ustar00rootroot00000000000000// 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 testlapack import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" ) func TestDlagsy(t *testing.T) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50} { for _, lda := range []int{0, 2*n + 1} { if lda == 0 { lda = max(1, n) } // D is the identity matrix I. d := make([]float64, n) for i := range d { d[i] = 1 } // Allocate an n×n symmetric matrix A and fill it with NaNs. a := nanSlice(n * lda) work := make([]float64, 2*n) // Compute A = U * D * Uᵀ where U is a random orthogonal matrix. Dlagsy(n, 0, d, a, lda, rnd, work) // A should be the identity matrix because // A = U * D * Uᵀ = U * I * Uᵀ = U * Uᵀ = I. dist := distFromIdentity(n, a, lda) if dist > tol { t.Errorf("Case n=%v,lda=%v: |A-I|=%v is too large", n, lda, dist) } } } } func TestDlagge(t *testing.T) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50} { for _, lda := range []int{0, 2*n + 1} { if lda == 0 { lda = max(1, n) } d := make([]float64, n) for i := range d { d[i] = 1 } a := blas64.General{ Rows: n, Cols: n, Stride: lda, Data: nanSlice(n * lda), } work := make([]float64, a.Rows+a.Cols) Dlagge(a.Rows, a.Cols, 0, 0, d, a.Data, a.Stride, rnd, work) if resid := residualOrthogonal(a, false); resid > tol { t.Errorf("Case n=%v,lda=%v: unexpected result", n, lda) } } } } func TestRandomOrthogonal(t *testing.T) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for n := 1; n <= 20; n++ { q := randomOrthogonal(n, rnd) if resid := residualOrthogonal(q, false); resid > tol { t.Errorf("Case n=%v: Q not orthogonal; resid=%v, want<=%v", n, resid, tol) } } } golang-gonum-v1-gonum-0.14.0/lapack/testlapack/test_matrices.go000066400000000000000000000320501450372207100244210ustar00rootroot00000000000000// Copyright ©2016 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 testlapack import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" ) // A123 is the non-symmetric singular matrix // // [ 1 2 3 ] // A = [ 4 5 6 ] // [ 7 8 9 ] // // It has three distinct real eigenvalues. type A123 struct{} func (A123) Matrix() blas64.General { return blas64.General{ Rows: 3, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }, } } func (A123) Eigenvalues() []complex128 { return []complex128{16.116843969807043, -1.116843969807043, 0} } func (A123) LeftEV() blas64.General { return blas64.General{ Rows: 3, Cols: 3, Stride: 3, Data: []float64{ -0.464547273387671, -0.570795531228578, -0.677043789069485, -0.882905959653586, -0.239520420054206, 0.403865119545174, 0.408248290463862, -0.816496580927726, 0.408248290463863, }, } } func (A123) RightEV() blas64.General { return blas64.General{ Rows: 3, Cols: 3, Stride: 3, Data: []float64{ -0.231970687246286, -0.785830238742067, 0.408248290463864, -0.525322093301234, -0.086751339256628, -0.816496580927726, -0.818673499356181, 0.612327560228810, 0.408248290463863, }, } } // AntisymRandom is a anti-symmetric random matrix. All its eigenvalues are // imaginary with one zero if the order is odd. type AntisymRandom struct { mat blas64.General } func NewAntisymRandom(n int, rnd *rand.Rand) AntisymRandom { a := zeros(n, n, n) for i := 0; i < n; i++ { for j := i + 1; j < n; j++ { r := rnd.NormFloat64() a.Data[i*a.Stride+j] = r a.Data[j*a.Stride+i] = -r } } return AntisymRandom{a} } func (a AntisymRandom) Matrix() blas64.General { return cloneGeneral(a.mat) } func (AntisymRandom) Eigenvalues() []complex128 { return nil } // Circulant is a generally non-symmetric matrix given by // // A[i,j] = 1 + (j-i+n)%n. // // For example, for n=5, // // [ 1 2 3 4 5 ] // [ 5 1 2 3 4 ] // A = [ 4 5 1 2 3 ] // [ 3 4 5 1 2 ] // [ 2 3 4 5 1 ] // // It has real and complex eigenvalues, some possibly repeated. type Circulant int func (c Circulant) Matrix() blas64.General { n := int(c) a := zeros(n, n, n) for i := 0; i < n; i++ { for j := 0; j < n; j++ { a.Data[i*a.Stride+j] = float64(1 + (j-i+n)%n) } } return a } func (c Circulant) Eigenvalues() []complex128 { n := int(c) w := rootsOfUnity(n) ev := make([]complex128, n) for k := 0; k < n; k++ { ev[k] = complex(float64(n), 0) } for i := n - 1; i > 0; i-- { for k := 0; k < n; k++ { ev[k] = ev[k]*w[k] + complex(float64(i), 0) } } return ev } // Clement is a generally non-symmetric matrix given by // // A[i,j] = i+1 if j == i+1, // = n-i if j == i-1, // = 0 otherwise. // // For example, for n=5, // // [ . 1 . . . ] // [ 4 . 2 . . ] // A = [ . 3 . 3 . ] // [ . . 2 . 4 ] // [ . . . 1 . ] // // It has n distinct real eigenvalues. type Clement int func (c Clement) Matrix() blas64.General { n := int(c) a := zeros(n, n, n) for i := 0; i < n; i++ { if i < n-1 { a.Data[i*a.Stride+i+1] = float64(i + 1) } if i > 0 { a.Data[i*a.Stride+i-1] = float64(n - i) } } return a } func (c Clement) Eigenvalues() []complex128 { n := int(c) ev := make([]complex128, n) for i := range ev { ev[i] = complex(float64(-n+2*i+1), 0) } return ev } // Creation is a singular non-symmetric matrix given by // // A[i,j] = i if j == i-1, // = 0 otherwise. // // For example, for n=5, // // [ . . . . . ] // [ 1 . . . . ] // A = [ . 2 . . . ] // [ . . 3 . . ] // [ . . . 4 . ] // // Zero is its only eigenvalue. type Creation int func (c Creation) Matrix() blas64.General { n := int(c) a := zeros(n, n, n) for i := 1; i < n; i++ { a.Data[i*a.Stride+i-1] = float64(i) } return a } func (c Creation) Eigenvalues() []complex128 { return make([]complex128, int(c)) } // Diagonal is a diagonal matrix given by // // A[i,j] = i+1 if i == j, // = 0 otherwise. // // For example, for n=5, // // [ 1 . . . . ] // [ . 2 . . . ] // A = [ . . 3 . . ] // [ . . . 4 . ] // [ . . . . 5 ] // // It has n real eigenvalues {1,...,n}. type Diagonal int func (d Diagonal) Matrix() blas64.General { n := int(d) a := zeros(n, n, n) for i := 0; i < n; i++ { a.Data[i*a.Stride+i] = float64(i) } return a } func (d Diagonal) Eigenvalues() []complex128 { n := int(d) ev := make([]complex128, n) for i := range ev { ev[i] = complex(float64(i), 0) } return ev } // Downshift is a non-singular upper Hessenberg matrix given by // // A[i,j] = 1 if (i-j+n)%n == 1, // = 0 otherwise. // // For example, for n=5, // // [ . . . . 1 ] // [ 1 . . . . ] // A = [ . 1 . . . ] // [ . . 1 . . ] // [ . . . 1 . ] // // Its eigenvalues are the complex roots of unity. type Downshift int func (d Downshift) Matrix() blas64.General { n := int(d) a := zeros(n, n, n) a.Data[n-1] = 1 for i := 1; i < n; i++ { a.Data[i*a.Stride+i-1] = 1 } return a } func (d Downshift) Eigenvalues() []complex128 { return rootsOfUnity(int(d)) } // Fibonacci is an upper Hessenberg matrix with 3 distinct real eigenvalues. For // example, for n=5, // // [ . 1 . . . ] // [ 1 1 . . . ] // A = [ . 1 1 . . ] // [ . . 1 1 . ] // [ . . . 1 1 ] type Fibonacci int func (f Fibonacci) Matrix() blas64.General { n := int(f) a := zeros(n, n, n) if n > 1 { a.Data[1] = 1 } for i := 1; i < n; i++ { a.Data[i*a.Stride+i-1] = 1 a.Data[i*a.Stride+i] = 1 } return a } func (f Fibonacci) Eigenvalues() []complex128 { n := int(f) ev := make([]complex128, n) if n == 0 || n == 1 { return ev } phi := 0.5 * (1 + math.Sqrt(5)) ev[0] = complex(phi, 0) for i := 1; i < n-1; i++ { ev[i] = 1 + 0i } ev[n-1] = complex(1-phi, 0) return ev } // Gear is a singular non-symmetric matrix with real eigenvalues. For example, // for n=5, // // [ . 1 . . 1 ] // [ 1 . 1 . . ] // A = [ . 1 . 1 . ] // [ . . 1 . 1 ] // [-1 . . 1 . ] type Gear int func (g Gear) Matrix() blas64.General { n := int(g) a := zeros(n, n, n) if n == 1 { return a } for i := 0; i < n-1; i++ { a.Data[i*a.Stride+i+1] = 1 } for i := 1; i < n; i++ { a.Data[i*a.Stride+i-1] = 1 } a.Data[n-1] = 1 a.Data[(n-1)*a.Stride] = -1 return a } func (g Gear) Eigenvalues() []complex128 { n := int(g) ev := make([]complex128, n) if n == 0 || n == 1 { return ev } if n == 2 { ev[0] = complex(0, 1) ev[1] = complex(0, -1) return ev } w := 0 ev[w] = math.Pi / 2 w++ phi := (n - 1) / 2 for p := 1; p <= phi; p++ { ev[w] = complex(float64(2*p)*math.Pi/float64(n), 0) w++ } phi = n / 2 for p := 1; p <= phi; p++ { ev[w] = complex(float64(2*p-1)*math.Pi/float64(n), 0) w++ } for i, v := range ev { ev[i] = complex(2*math.Cos(real(v)), 0) } return ev } // Grcar is an upper Hessenberg matrix given by // // A[i,j] = -1 if i == j+1, // = 1 if i <= j and j <= i+k, // = 0 otherwise. // // For example, for n=5 and k=2, // // [ 1 1 1 . . ] // [ -1 1 1 1 . ] // A = [ . -1 1 1 1 ] // [ . . -1 1 1 ] // [ . . . -1 1 ] // // The matrix has sensitive eigenvalues but they are not given explicitly. type Grcar struct { N int K int } func (g Grcar) Matrix() blas64.General { n := g.N a := zeros(n, n, n) for k := 0; k <= g.K; k++ { for i := 0; i < n-k; i++ { a.Data[i*a.Stride+i+k] = 1 } } for i := 1; i < n; i++ { a.Data[i*a.Stride+i-1] = -1 } return a } func (Grcar) Eigenvalues() []complex128 { return nil } // Hanowa is a non-symmetric non-singular matrix of even order given by // // A[i,j] = alpha if i == j, // = -i-1 if i < n/2 and j == i + n/2, // = i+1-n/2 if i >= n/2 and j == i - n/2, // = 0 otherwise. // // The matrix has complex eigenvalues. type Hanowa struct { N int // Order of the matrix, must be even. Alpha float64 } func (h Hanowa) Matrix() blas64.General { if h.N&0x1 != 0 { panic("lapack: matrix order must be even") } n := h.N a := zeros(n, n, n) for i := 0; i < n; i++ { a.Data[i*a.Stride+i] = h.Alpha } for i := 0; i < n/2; i++ { a.Data[i*a.Stride+i+n/2] = float64(-i - 1) } for i := n / 2; i < n; i++ { a.Data[i*a.Stride+i-n/2] = float64(i + 1 - n/2) } return a } func (h Hanowa) Eigenvalues() []complex128 { if h.N&0x1 != 0 { panic("lapack: matrix order must be even") } n := h.N ev := make([]complex128, n) for i := 0; i < n/2; i++ { ev[2*i] = complex(h.Alpha, float64(-i-1)) ev[2*i+1] = complex(h.Alpha, float64(i+1)) } return ev } // Lesp is a tridiagonal, generally non-symmetric matrix given by // // A[i,j] = -2*i-5 if i == j, // = 1/(i+1) if i == j-1, // = j+1 if i == j+1. // // For example, for n=5, // // [ -5 2 . . . ] // [ 1/2 -7 3 . . ] // A = [ . 1/3 -9 4 . ] // [ . . 1/4 -11 5 ] // [ . . . 1/5 -13 ]. // // The matrix has sensitive eigenvalues but they are not given explicitly. type Lesp int func (l Lesp) Matrix() blas64.General { n := int(l) a := zeros(n, n, n) for i := 0; i < n; i++ { a.Data[i*a.Stride+i] = float64(-2*i - 5) } for i := 0; i < n-1; i++ { a.Data[i*a.Stride+i+1] = float64(i + 2) } for i := 1; i < n; i++ { a.Data[i*a.Stride+i-1] = 1 / float64(i+1) } return a } func (Lesp) Eigenvalues() []complex128 { return nil } // Rutis is the 4×4 non-symmetric matrix // // [ 4 -5 0 3 ] // A = [ 0 4 -3 -5 ] // [ 5 -3 4 0 ] // [ 3 0 5 4 ] // // It has two distinct real eigenvalues and a pair of complex eigenvalues. type Rutis struct{} func (Rutis) Matrix() blas64.General { return blas64.General{ Rows: 4, Cols: 4, Stride: 4, Data: []float64{ 4, -5, 0, 3, 0, 4, -3, -5, 5, -3, 4, 0, 3, 0, 5, 4, }, } } func (Rutis) Eigenvalues() []complex128 { return []complex128{12, 1 + 5i, 1 - 5i, 2} } // Tris is a tridiagonal matrix given by // // A[i,j] = x if i == j-1, // = y if i == j, // = z if i == j+1. // // If x*z is negative, the matrix has complex eigenvalues. type Tris struct { N int X, Y, Z float64 } func (t Tris) Matrix() blas64.General { n := t.N a := zeros(n, n, n) for i := 1; i < n; i++ { a.Data[i*a.Stride+i-1] = t.X } for i := 0; i < n; i++ { a.Data[i*a.Stride+i] = t.Y } for i := 0; i < n-1; i++ { a.Data[i*a.Stride+i+1] = t.Z } return a } func (t Tris) Eigenvalues() []complex128 { n := t.N ev := make([]complex128, n) for i := range ev { angle := float64(i+1) * math.Pi / float64(n+1) arg := t.X * t.Z if arg >= 0 { ev[i] = complex(t.Y+2*math.Sqrt(arg)*math.Cos(angle), 0) } else { ev[i] = complex(t.Y, 2*math.Sqrt(-arg)*math.Cos(angle)) } } return ev } // Wilk4 is a 4×4 lower triangular matrix with 4 distinct real eigenvalues. type Wilk4 struct{} func (Wilk4) Matrix() blas64.General { return blas64.General{ Rows: 4, Cols: 4, Stride: 4, Data: []float64{ 0.9143e-4, 0.0, 0.0, 0.0, 0.8762, 0.7156e-4, 0.0, 0.0, 0.7943, 0.8143, 0.9504e-4, 0.0, 0.8017, 0.6123, 0.7165, 0.7123e-4, }, } } func (Wilk4) Eigenvalues() []complex128 { return []complex128{ 0.9504e-4, 0.9143e-4, 0.7156e-4, 0.7123e-4, } } // Wilk12 is a 12×12 lower Hessenberg matrix with 12 distinct real eigenvalues. type Wilk12 struct{} func (Wilk12) Matrix() blas64.General { return blas64.General{ Rows: 12, Cols: 12, Stride: 12, Data: []float64{ 12, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 7, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, } } func (Wilk12) Eigenvalues() []complex128 { return []complex128{ 32.2288915015722210, 20.1989886458770691, 12.3110774008685340, 6.9615330855671154, 3.5118559485807528, 1.5539887091319704, 0.6435053190136506, 0.2847497205488856, 0.1436465181918488, 0.0812276683076552, 0.0495074140194613, 0.0310280683208907, } } // Wilk20 is a 20×20 lower Hessenberg matrix. If the parameter is 0, the matrix // has 20 distinct real eigenvalues. If the parameter is 1e-10, the matrix has 6 // real eigenvalues and 7 pairs of complex eigenvalues. type Wilk20 float64 func (w Wilk20) Matrix() blas64.General { a := zeros(20, 20, 20) for i := 0; i < 20; i++ { a.Data[i*a.Stride+i] = float64(i + 1) } for i := 0; i < 19; i++ { a.Data[i*a.Stride+i+1] = 20 } a.Data[19*a.Stride] = float64(w) return a } func (w Wilk20) Eigenvalues() []complex128 { if float64(w) == 0 { ev := make([]complex128, 20) for i := range ev { ev[i] = complex(float64(i+1), 0) } return ev } return nil } // Zero is a matrix with all elements equal to zero. type Zero int func (z Zero) Matrix() blas64.General { n := int(z) return zeros(n, n, n) } func (z Zero) Eigenvalues() []complex128 { n := int(z) return make([]complex128, n) } golang-gonum-v1-gonum-0.14.0/mat/000077500000000000000000000000001450372207100164175ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mat/README.md000066400000000000000000000004421450372207100176760ustar00rootroot00000000000000# Gonum matrix [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/mat)](https://pkg.go.dev/gonum.org/v1/gonum/mat) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/mat?status.svg)](https://godocs.io/gonum.org/v1/gonum/mat) Package mat is a matrix package for the Go language. golang-gonum-v1-gonum-0.14.0/mat/band.go000066400000000000000000000241161450372207100176560ustar00rootroot00000000000000// 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 mat import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) var ( bandDense *BandDense _ Matrix = bandDense _ allMatrix = bandDense _ denseMatrix = bandDense _ Banded = bandDense _ RawBander = bandDense _ NonZeroDoer = bandDense _ RowNonZeroDoer = bandDense _ ColNonZeroDoer = bandDense ) // BandDense represents a band matrix in dense storage format. type BandDense struct { mat blas64.Band } // Banded is a band matrix representation. type Banded interface { Matrix // Bandwidth returns the lower and upper bandwidth values for // the matrix. The total bandwidth of the matrix is kl+ku+1. Bandwidth() (kl, ku int) // TBand is the equivalent of the T() method in the Matrix // interface but guarantees the transpose is of banded type. TBand() Banded } // A RawBander can return a blas64.Band representation of the receiver. // Changes to the blas64.Band.Data slice will be reflected in the original // matrix, changes to the Rows, Cols, KL, KU and Stride fields will not. type RawBander interface { RawBand() blas64.Band } // A MutableBanded can set elements of a band matrix. type MutableBanded interface { Banded // SetBand sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate region of the matrix. SetBand(i, j int, v float64) } var ( _ Matrix = TransposeBand{} _ Banded = TransposeBand{} _ UntransposeBander = TransposeBand{} ) // TransposeBand is a type for performing an implicit transpose of a band // matrix. It implements the Banded interface, returning values from the // transpose of the matrix within. type TransposeBand struct { Banded Banded } // At returns the value of the element at row i and column j of the transposed // matrix, that is, row j and column i of the Banded field. func (t TransposeBand) At(i, j int) float64 { return t.Banded.At(j, i) } // Dims returns the dimensions of the transposed matrix. func (t TransposeBand) Dims() (r, c int) { c, r = t.Banded.Dims() return r, c } // T performs an implicit transpose by returning the Banded field. func (t TransposeBand) T() Matrix { return t.Banded } // Bandwidth returns the lower and upper bandwidth values for // the transposed matrix. func (t TransposeBand) Bandwidth() (kl, ku int) { kl, ku = t.Banded.Bandwidth() return ku, kl } // TBand performs an implicit transpose by returning the Banded field. func (t TransposeBand) TBand() Banded { return t.Banded } // Untranspose returns the Banded field. func (t TransposeBand) Untranspose() Matrix { return t.Banded } // UntransposeBand returns the Banded field. func (t TransposeBand) UntransposeBand() Banded { return t.Banded } // NewBandDense creates a new Band matrix with r rows and c columns. If data == nil, // a new slice is allocated for the backing slice. If len(data) == min(r, c+kl)*(kl+ku+1), // data is used as the backing slice, and changes to the elements of the returned // BandDense will be reflected in data. If neither of these is true, NewBandDense // will panic. kl must be at least zero and less r, and ku must be at least zero and // less than c, otherwise NewBandDense will panic. // NewBandDense will panic if either r or c is zero. // // The data must be arranged in row-major order constructed by removing the zeros // from the rows outside the band 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 // // 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 passed to NewBandDense as []float64{*, 1, 2, 3, 4, ...} with kl=1 and ku=2. // Only the values in the band portion of the matrix are used. func NewBandDense(r, c, kl, ku int, data []float64) *BandDense { if r <= 0 || c <= 0 || kl < 0 || ku < 0 { if r == 0 || c == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if kl+1 > r || ku+1 > c { panic(ErrBandwidth) } bc := kl + ku + 1 if data != nil && len(data) != min(r, c+kl)*bc { panic(ErrShape) } if data == nil { data = make([]float64, min(r, c+kl)*bc) } return &BandDense{ mat: blas64.Band{ Rows: r, Cols: c, KL: kl, KU: ku, Stride: bc, Data: data, }, } } // NewDiagonalRect is a convenience function that returns a diagonal matrix represented by a // BandDense. The length of data must be min(r, c) otherwise NewDiagonalRect will panic. func NewDiagonalRect(r, c int, data []float64) *BandDense { return NewBandDense(r, c, 0, 0, data) } // Dims returns the number of rows and columns in the matrix. func (b *BandDense) Dims() (r, c int) { return b.mat.Rows, b.mat.Cols } // Bandwidth returns the upper and lower bandwidths of the matrix. func (b *BandDense) Bandwidth() (kl, ku int) { return b.mat.KL, b.mat.KU } // T performs an implicit transpose by returning the receiver inside a Transpose. func (b *BandDense) T() Matrix { return Transpose{b} } // TBand performs an implicit transpose by returning the receiver inside a TransposeBand. func (b *BandDense) TBand() Banded { return TransposeBand{b} } // RawBand returns the underlying blas64.Band used by the receiver. // Changes to elements in the receiver following the call will be reflected // in returned blas64.Band. func (b *BandDense) RawBand() blas64.Band { return b.mat } // SetRawBand sets the underlying blas64.Band used by the receiver. // Changes to elements in the receiver following the call will be reflected // in the input. func (b *BandDense) SetRawBand(mat blas64.Band) { b.mat = mat } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be zeroed using Reset. func (b *BandDense) IsEmpty() bool { return b.mat.Stride == 0 } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (b *BandDense) Reset() { b.mat.Rows = 0 b.mat.Cols = 0 b.mat.KL = 0 b.mat.KU = 0 b.mat.Stride = 0 b.mat.Data = b.mat.Data[:0] } // DiagView returns the diagonal as a matrix backed by the original data. func (b *BandDense) DiagView() Diagonal { n := min(b.mat.Rows, b.mat.Cols) return &DiagDense{ mat: blas64.Vector{ N: n, Inc: b.mat.Stride, Data: b.mat.Data[b.mat.KL : (n-1)*b.mat.Stride+b.mat.KL+1], }, } } // DoNonZero calls the function fn for each of the non-zero elements of b. The function fn // takes a row/column index and the element value of b at (i, j). func (b *BandDense) DoNonZero(fn func(i, j int, v float64)) { for i := 0; i < min(b.mat.Rows, b.mat.Cols+b.mat.KL); i++ { for j := max(0, i-b.mat.KL); j < min(b.mat.Cols, i+b.mat.KU+1); j++ { v := b.at(i, j) if v != 0 { fn(i, j, v) } } } } // DoRowNonZero calls the function fn for each of the non-zero elements of row i of b. The function fn // takes a row/column index and the element value of b at (i, j). func (b *BandDense) DoRowNonZero(i int, fn func(i, j int, v float64)) { if i < 0 || b.mat.Rows <= i { panic(ErrRowAccess) } for j := max(0, i-b.mat.KL); j < min(b.mat.Cols, i+b.mat.KU+1); j++ { v := b.at(i, j) if v != 0 { fn(i, j, v) } } } // DoColNonZero calls the function fn for each of the non-zero elements of column j of b. The function fn // takes a row/column index and the element value of b at (i, j). func (b *BandDense) DoColNonZero(j int, fn func(i, j int, v float64)) { if j < 0 || b.mat.Cols <= j { panic(ErrColAccess) } for i := 0; i < min(b.mat.Rows, b.mat.Cols+b.mat.KL); i++ { if i-b.mat.KL <= j && j < i+b.mat.KU+1 { v := b.at(i, j) if v != 0 { fn(i, j, v) } } } } // Zero sets all of the matrix elements to zero. func (b *BandDense) Zero() { m := b.mat.Rows kL := b.mat.KL nCol := b.mat.KU + 1 + kL for i := 0; i < m; i++ { l := max(0, kL-i) u := min(nCol, m+kL-i) zero(b.mat.Data[i*b.mat.Stride+l : i*b.mat.Stride+u]) } } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the matrix has zero size. func (b *BandDense) Norm(norm float64) float64 { if b.IsEmpty() { panic(ErrZeroLength) } lnorm := normLapack(norm, false) if lnorm == lapack.MaxColumnSum || lnorm == lapack.MaxRowSum { return lapack64.Langb(lnorm, b.mat) } return lapack64.Langb(lnorm, b.mat) } // Trace returns the trace of the matrix. // // Trace will panic with ErrSquare if the matrix is not square and with // ErrZeroLength if the matrix has zero size. func (b *BandDense) Trace() float64 { r, c := b.Dims() if r != c { panic(ErrSquare) } if b.IsEmpty() { panic(ErrZeroLength) } rb := b.RawBand() var tr float64 for i := 0; i < r; i++ { tr += rb.Data[rb.KL+i*rb.Stride] } return tr } // MulVecTo computes B⋅x or Bᵀ⋅x storing the result into dst. func (b *BandDense) MulVecTo(dst *VecDense, trans bool, x Vector) { m, n := b.Dims() if trans { m, n = n, m } if x.Len() != n { panic(ErrShape) } dst.reuseAsNonZeroed(m) t := blas.NoTrans if trans { t = blas.Trans } xMat, _ := untransposeExtract(x) if xVec, ok := xMat.(*VecDense); ok { if dst != xVec { dst.checkOverlap(xVec.mat) blas64.Gbmv(t, 1, b.mat, xVec.mat, 0, dst.mat) } else { xCopy := getVecDenseWorkspace(n, false) xCopy.CloneFromVec(xVec) blas64.Gbmv(t, 1, b.mat, xCopy.mat, 0, dst.mat) putVecDenseWorkspace(xCopy) } } else { xCopy := getVecDenseWorkspace(n, false) xCopy.CloneFromVec(x) blas64.Gbmv(t, 1, b.mat, xCopy.mat, 0, dst.mat) putVecDenseWorkspace(xCopy) } } golang-gonum-v1-gonum-0.14.0/mat/band_test.go000066400000000000000000000244611450372207100207200ustar00rootroot00000000000000// 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 mat import ( "reflect" "testing" "gonum.org/v1/gonum/blas/blas64" ) func TestNewBand(t *testing.T) { t.Parallel() for i, test := range []struct { data []float64 r, c int kl, ku int mat *BandDense dense *Dense }{ { data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, 19, 20, -1, -1, }, r: 6, c: 6, kl: 1, ku: 2, mat: &BandDense{ mat: blas64.Band{ Rows: 6, Cols: 6, KL: 1, KU: 2, Stride: 4, Data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, 19, 20, -1, -1, }, }, }, dense: NewDense(6, 6, []float64{ 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, }), }, { data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, 19, 20, -1, -1, 21, -1, -1, -1, }, r: 10, c: 6, kl: 1, ku: 2, mat: &BandDense{ mat: blas64.Band{ Rows: 10, Cols: 6, KL: 1, KU: 2, Stride: 4, Data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, 19, 20, -1, -1, 21, -1, -1, -1, }, }, }, dense: NewDense(10, 6, []float64{ 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, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }), }, { data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, }, r: 6, c: 10, kl: 1, ku: 2, mat: &BandDense{ mat: blas64.Band{ Rows: 6, Cols: 10, KL: 1, KU: 2, Stride: 4, Data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, }, }, }, dense: NewDense(6, 10, []float64{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 0, 0, }), }, } { band := NewBandDense(test.r, test.c, test.kl, test.ku, test.data) rows, cols := band.Dims() if rows != test.r { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.r) } if cols != test.c { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.c) } if !reflect.DeepEqual(band, test.mat) { t.Errorf("unexpected value via reflect for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.mat) { t.Errorf("unexpected value via mat.Equal for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.dense) { t.Errorf("unexpected value via mat.Equal(band, dense) for test %d:\ngot:\n% v\nwant:\n% v", i, Formatted(band), Formatted(test.dense)) } } } func TestNewDiagonalRect(t *testing.T) { t.Parallel() for i, test := range []struct { data []float64 r, c int mat *BandDense dense *Dense }{ { data: []float64{1, 2, 3, 4, 5, 6}, r: 6, c: 6, mat: &BandDense{ mat: blas64.Band{ Rows: 6, Cols: 6, Stride: 1, Data: []float64{1, 2, 3, 4, 5, 6}, }, }, dense: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { data: []float64{1, 2, 3, 4, 5, 6}, r: 7, c: 6, mat: &BandDense{ mat: blas64.Band{ Rows: 7, Cols: 6, Stride: 1, Data: []float64{1, 2, 3, 4, 5, 6}, }, }, dense: NewDense(7, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, }), }, { data: []float64{1, 2, 3, 4, 5, 6}, r: 6, c: 7, mat: &BandDense{ mat: blas64.Band{ Rows: 6, Cols: 7, Stride: 1, Data: []float64{1, 2, 3, 4, 5, 6}, }, }, dense: NewDense(6, 7, []float64{ 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, }), }, } { band := NewDiagonalRect(test.r, test.c, test.data) rows, cols := band.Dims() if rows != test.r { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.r) } if cols != test.c { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.c) } if !reflect.DeepEqual(band, test.mat) { t.Errorf("unexpected value via reflect for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.mat) { t.Errorf("unexpected value via mat.Equal for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.dense) { t.Errorf("unexpected value via mat.Equal(band, dense) for test %d:\ngot:\n% v\nwant:\n% v", i, Formatted(band), Formatted(test.dense)) } } } func TestBandDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*BandDense{ { mat: blas64.Band{ Rows: 6, Cols: 7, Stride: 8, KL: 1, KU: 2, Data: []float64{ -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, }, }, }, { mat: blas64.Band{ Rows: 6, Cols: 7, Stride: 8, KL: 2, KU: 1, Data: []float64{ -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } func TestBandDiagView(t *testing.T) { t.Parallel() for cas, test := range []*BandDense{ NewBandDense(1, 1, 0, 0, []float64{1}), NewBandDense(6, 6, 1, 2, []float64{ -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -1, 21, 22, -1, -1, }), NewBandDense(6, 6, 2, 1, []float64{ -1, -1, 1, 2, -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, -1, }), } { testDiagView(t, cas, test) } } func TestBandAtSet(t *testing.T) { t.Parallel() // 2 3 4 0 0 0 // 5 6 7 8 0 0 // 0 9 10 11 12 0 // 0 0 13 14 15 16 // 0 0 0 17 18 19 // 0 0 0 0 21 22 band := NewBandDense(6, 6, 1, 2, []float64{ -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -1, 21, 22, -1, -1, }) rows, cols := band.Dims() kl, ku := band.Bandwidth() // Explicitly test all indexes. want := bandImplicit{rows, cols, kl, ku, func(i, j int) float64 { return float64(i*(kl+ku) + j + kl + 1) }} for i := 0; i < 6; i++ { for j := 0; j < 6; j++ { if band.At(i, j) != want.At(i, j) { t.Errorf("unexpected value for band.At(%d, %d): got:%v want:%v", i, j, band.At(i, j), want.At(i, j)) } } } // Do that same thing via a call to Equal. if !Equal(band, want) { t.Errorf("unexpected value via mat.Equal:\ngot:\n% v\nwant:\n% v", Formatted(band), Formatted(want)) } // Check At out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { band.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { band.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } // Check Set out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { band.SetBand(row, 0, 1.2) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { band.SetBand(0, col, 1.2) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } for _, st := range []struct { row, col int }{ {row: 0, col: 3}, {row: 0, col: 4}, {row: 0, col: 5}, {row: 1, col: 4}, {row: 1, col: 5}, {row: 2, col: 5}, {row: 2, col: 0}, {row: 3, col: 1}, {row: 4, col: 2}, {row: 5, col: 3}, } { panicked, message := panics(func() { band.SetBand(st.row, st.col, 1.2) }) if !panicked || message != ErrBandSet.Error() { t.Errorf("expected panic for %+v %s", st, message) } } for _, st := range []struct { row, col int orig, new float64 }{ {row: 1, col: 2, orig: 7, new: 15}, {row: 2, col: 3, orig: 11, new: 15}, } { if e := band.At(st.row, st.col); e != st.orig { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", st.row, st.col, e, st.orig) } band.SetBand(st.row, st.col, st.new) if e := band.At(st.row, st.col); e != st.new { t.Errorf("unexpected value for At(%d, %d) after SetBand(%[1]d, %d, %v): got: %v want: %[3]v", st.row, st.col, st.new, e) } } } // bandImplicit is an implicit band matrix returning val(i, j) // for the value at (i, j). type bandImplicit struct { r, c, kl, ku int val func(i, j int) float64 } func (b bandImplicit) Dims() (r, c int) { return b.r, b.c } func (b bandImplicit) T() Matrix { return Transpose{b} } func (b bandImplicit) At(i, j int) float64 { if i < 0 || b.r <= i { panic("row") } if j < 0 || b.c <= j { panic("col") } if j < i-b.kl || i+b.ku < j { return 0 } return b.val(i, j) } golang-gonum-v1-gonum-0.14.0/mat/basictypes_test.go000066400000000000000000000134051450372207100221560ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import "gonum.org/v1/gonum/blas/blas64" func asBasicMatrix(d *Dense) *basicMatrix { return (*basicMatrix)(d) } func asBasicVector(d *VecDense) *basicVector { return (*basicVector)(d) } func asBasicSymmetric(s *SymDense) *basicSymmetric { return (*basicSymmetric)(s) } func asBasicTriangular(t *TriDense) *basicTriangular { return (*basicTriangular)(t) } func asBasicBanded(b *BandDense) *basicBanded { return (*basicBanded)(b) } func asBasicSymBanded(s *SymBandDense) *basicSymBanded { return (*basicSymBanded)(s) } func asBasicTriBanded(t *TriBandDense) *basicTriBanded { return (*basicTriBanded)(t) } func asBasicDiagonal(d *DiagDense) *basicDiagonal { return (*basicDiagonal)(d) } type basicMatrix Dense var _ Matrix = &basicMatrix{} func (m *basicMatrix) At(r, c int) float64 { return (*Dense)(m).At(r, c) } func (m *basicMatrix) Dims() (r, c int) { return (*Dense)(m).Dims() } func (m *basicMatrix) T() Matrix { return Transpose{m} } type rawMatrix struct { *basicMatrix } func (a *rawMatrix) RawMatrix() blas64.General { return a.mat } type basicVector VecDense var _ Vector = &basicVector{} func (v *basicVector) At(r, c int) float64 { return (*VecDense)(v).At(r, c) } func (v *basicVector) Dims() (r, c int) { return (*VecDense)(v).Dims() } func (v *basicVector) T() Matrix { return Transpose{v} } func (v *basicVector) AtVec(i int) float64 { return (*VecDense)(v).AtVec(i) } func (v *basicVector) Len() int { return (*VecDense)(v).Len() } type rawVector struct { *basicVector } func (v *rawVector) RawVector() blas64.Vector { return v.mat } type basicSymmetric SymDense var _ Symmetric = &basicSymmetric{} func (m *basicSymmetric) At(r, c int) float64 { return (*SymDense)(m).At(r, c) } func (m *basicSymmetric) Dims() (r, c int) { return (*SymDense)(m).Dims() } func (m *basicSymmetric) T() Matrix { return m } func (m *basicSymmetric) SymmetricDim() int { return (*SymDense)(m).SymmetricDim() } type basicTriangular TriDense var _ Triangular = &basicTriangular{} func (m *basicTriangular) At(r, c int) float64 { return (*TriDense)(m).At(r, c) } func (m *basicTriangular) Dims() (r, c int) { return (*TriDense)(m).Dims() } func (m *basicTriangular) T() Matrix { return Transpose{m} } func (m *basicTriangular) Triangle() (int, TriKind) { return (*TriDense)(m).Triangle() } func (m *basicTriangular) TTri() Triangular { return TransposeTri{m} } type basicBanded BandDense var _ Banded = &basicBanded{} func (m *basicBanded) At(r, c int) float64 { return (*BandDense)(m).At(r, c) } func (m *basicBanded) Dims() (r, c int) { return (*BandDense)(m).Dims() } func (m *basicBanded) T() Matrix { return Transpose{m} } func (m *basicBanded) Bandwidth() (kl, ku int) { return (*BandDense)(m).Bandwidth() } func (m *basicBanded) TBand() Banded { return TransposeBand{m} } type basicSymBanded SymBandDense var _ SymBanded = &basicSymBanded{} func (m *basicSymBanded) At(r, c int) float64 { return (*SymBandDense)(m).At(r, c) } func (m *basicSymBanded) Dims() (r, c int) { return (*SymBandDense)(m).Dims() } func (m *basicSymBanded) T() Matrix { return m } func (m *basicSymBanded) Bandwidth() (kl, ku int) { return (*SymBandDense)(m).Bandwidth() } func (m *basicSymBanded) TBand() Banded { return m } func (m *basicSymBanded) SymmetricDim() int { return (*SymBandDense)(m).SymmetricDim() } func (m *basicSymBanded) SymBand() (n, k int) { return (*SymBandDense)(m).SymBand() } type basicTriBanded TriBandDense var _ TriBanded = &basicTriBanded{} func (m *basicTriBanded) At(r, c int) float64 { return (*TriBandDense)(m).At(r, c) } func (m *basicTriBanded) Dims() (r, c int) { return (*TriBandDense)(m).Dims() } func (m *basicTriBanded) T() Matrix { return Transpose{m} } func (m *basicTriBanded) Triangle() (int, TriKind) { return (*TriBandDense)(m).Triangle() } func (m *basicTriBanded) TTri() Triangular { return TransposeTri{m} } func (m *basicTriBanded) Bandwidth() (kl, ku int) { return (*TriBandDense)(m).Bandwidth() } func (m *basicTriBanded) TBand() Banded { return TransposeBand{m} } func (m *basicTriBanded) TriBand() (n, k int, kind TriKind) { return (*TriBandDense)(m).TriBand() } func (m *basicTriBanded) TTriBand() TriBanded { return TransposeTriBand{m} } type basicDiagonal DiagDense var _ Diagonal = &basicDiagonal{} func (m *basicDiagonal) At(r, c int) float64 { return (*DiagDense)(m).At(r, c) } func (m *basicDiagonal) Dims() (r, c int) { return (*DiagDense)(m).Dims() } func (m *basicDiagonal) T() Matrix { return Transpose{m} } func (m *basicDiagonal) Diag() int { return (*DiagDense)(m).Diag() } func (m *basicDiagonal) SymmetricDim() int { return (*DiagDense)(m).SymmetricDim() } func (m *basicDiagonal) SymBand() (n, k int) { return (*DiagDense)(m).SymBand() } func (m *basicDiagonal) Bandwidth() (kl, ku int) { return (*DiagDense)(m).Bandwidth() } func (m *basicDiagonal) TBand() Banded { return TransposeBand{m} } func (m *basicDiagonal) Triangle() (int, TriKind) { return (*DiagDense)(m).Triangle() } func (m *basicDiagonal) TTri() Triangular { return TransposeTri{m} } func (m *basicDiagonal) TriBand() (n, k int, kind TriKind) { return (*DiagDense)(m).TriBand() } func (m *basicDiagonal) TTriBand() TriBanded { return TransposeTriBand{m} } golang-gonum-v1-gonum-0.14.0/mat/cdense.go000066400000000000000000000230211450372207100202050ustar00rootroot00000000000000// Copyright ©2019 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math/cmplx" "gonum.org/v1/gonum/blas/cblas128" ) var ( cDense *CDense _ CMatrix = cDense _ allMatrix = cDense ) // CDense is a dense matrix representation with complex data. type CDense struct { mat cblas128.General capRows, capCols int } // Dims returns the number of rows and columns in the matrix. func (m *CDense) Dims() (r, c int) { return m.mat.Rows, m.mat.Cols } // Caps returns the number of rows and columns in the backing matrix. func (m *CDense) Caps() (r, c int) { return m.capRows, m.capCols } // H performs an implicit conjugate transpose by returning the receiver inside a // ConjTranspose. func (m *CDense) H() CMatrix { return ConjTranspose{m} } // T performs an implicit transpose by returning the receiver inside a // CTranspose. func (m *CDense) T() CMatrix { return CTranspose{m} } // Conj calculates the element-wise conjugate of a and stores the result in the // receiver. // Conj will panic if m and a do not have the same dimension unless m is empty. func (m *CDense) Conj(a CMatrix) { ar, ac := a.Dims() aU, aTrans, aConj := untransposeExtractCmplx(a) m.reuseAsNonZeroed(ar, ac) if arm, ok := a.(*CDense); ok { amat := arm.mat if m != aU { m.checkOverlap(amat) } for ja, jm := 0, 0; ja < ar*amat.Stride; ja, jm = ja+amat.Stride, jm+m.mat.Stride { for i, v := range amat.Data[ja : ja+ac] { m.mat.Data[i+jm] = cmplx.Conj(v) } } return } m.checkOverlapMatrix(aU) if aTrans != aConj && m == aU { // Only make workspace if the destination is transposed // with respect to the source and they are the same // matrix. var restore func() m, restore = m.isolatedWorkspace(aU) defer restore() } for r := 0; r < ar; r++ { for c := 0; c < ac; c++ { m.set(r, c, cmplx.Conj(a.At(r, c))) } } } // Slice returns a new CMatrix that shares backing data with the receiver. // The returned matrix starts at {i,j} of the receiver and extends k-i rows // and l-j columns. The final row in the resulting matrix is k-1 and the // final column is l-1. // Slice panics with ErrIndexOutOfRange if the slice is outside the capacity // of the receiver. func (m *CDense) Slice(i, k, j, l int) CMatrix { return m.slice(i, k, j, l) } func (m *CDense) slice(i, k, j, l int) *CDense { mr, mc := m.Caps() if i < 0 || mr <= i || j < 0 || mc <= j || k < i || mr < k || l < j || mc < l { if i == k || j == l { panic(ErrZeroLength) } panic(ErrIndexOutOfRange) } t := *m t.mat.Data = t.mat.Data[i*t.mat.Stride+j : (k-1)*t.mat.Stride+l] t.mat.Rows = k - i t.mat.Cols = l - j t.capRows -= i t.capCols -= j return &t } // NewCDense creates a new complex Dense matrix with r rows and c columns. // If data == nil, a new slice is allocated for the backing slice. // If len(data) == r*c, data is used as the backing slice, and changes to the // elements of the returned CDense will be reflected in data. // If neither of these is true, NewCDense will panic. // NewCDense will panic if either r or c is zero. // // The data must be arranged in row-major order, i.e. the (i*c + j)-th // element in the data slice is the {i, j}-th element in the matrix. func NewCDense(r, c int, data []complex128) *CDense { if r <= 0 || c <= 0 { if r == 0 || c == 0 { panic(ErrZeroLength) } panic("mat: negative dimension") } if data != nil && r*c != len(data) { panic(ErrShape) } if data == nil { data = make([]complex128, r*c) } return &CDense{ mat: cblas128.General{ Rows: r, Cols: c, Stride: c, Data: data, }, capRows: r, capCols: c, } } // ReuseAs changes the receiver if it IsEmpty() to be of size r×c. // // ReuseAs re-uses the backing data slice if it has sufficient capacity, // otherwise a new slice is allocated. The backing data is zero on return. // // ReuseAs panics if the receiver is not empty, and panics if // the input sizes are less than one. To empty the receiver for re-use, // Reset should be used. func (m *CDense) ReuseAs(r, c int) { if r <= 0 || c <= 0 { if r == 0 || c == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if !m.IsEmpty() { panic(ErrReuseNonEmpty) } m.reuseAsZeroed(r, c) } // reuseAs resizes an empty matrix to a r×c matrix, // or checks that a non-empty matrix is r×c. // // reuseAs must be kept in sync with reuseAsZeroed. func (m *CDense) reuseAsNonZeroed(r, c int) { if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols { // Panic as a string, not a mat.Error. panic(badCap) } if r == 0 || c == 0 { panic(ErrZeroLength) } if m.IsEmpty() { m.mat = cblas128.General{ Rows: r, Cols: c, Stride: c, Data: useC(m.mat.Data, r*c), } m.capRows = r m.capCols = c return } if r != m.mat.Rows || c != m.mat.Cols { panic(ErrShape) } } func (m *CDense) reuseAsZeroed(r, c int) { // This must be kept in-sync with reuseAs. if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols { // Panic as a string, not a mat.Error. panic(badCap) } if r == 0 || c == 0 { panic(ErrZeroLength) } if m.IsEmpty() { m.mat = cblas128.General{ Rows: r, Cols: c, Stride: c, Data: useZeroedC(m.mat.Data, r*c), } m.capRows = r m.capCols = c return } if r != m.mat.Rows || c != m.mat.Cols { panic(ErrShape) } m.Zero() } // isolatedWorkspace returns a new dense matrix w with the size of a and // returns a callback to defer which performs cleanup at the return of the call. // This should be used when a method receiver is the same pointer as an input argument. func (m *CDense) isolatedWorkspace(a CMatrix) (w *CDense, restore func()) { r, c := a.Dims() if r == 0 || c == 0 { panic(ErrZeroLength) } w = getCDenseWorkspace(r, c, false) return w, func() { m.Copy(w) putCDenseWorkspace(w) } } // Reset zeros the dimensions of the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (m *CDense) Reset() { // Row, Cols and Stride must be zeroed in unison. m.mat.Rows, m.mat.Cols, m.mat.Stride = 0, 0, 0 m.capRows, m.capCols = 0, 0 m.mat.Data = m.mat.Data[:0] } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be zeroed using Reset. func (m *CDense) IsEmpty() bool { // It must be the case that m.Dims() returns // zeros in this case. See comment in Reset(). return m.mat.Stride == 0 } // Zero sets all of the matrix elements to zero. func (m *CDense) Zero() { r := m.mat.Rows c := m.mat.Cols for i := 0; i < r; i++ { zeroC(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]) } } // Copy makes a copy of elements of a into the receiver. It is similar to the // built-in copy; it copies as much as the overlap between the two matrices and // returns the number of rows and columns it copied. If a aliases the receiver // and is a transposed Dense or VecDense, with a non-unitary increment, Copy will // panic. // // See the Copier interface for more information. func (m *CDense) Copy(a CMatrix) (r, c int) { r, c = a.Dims() if a == m { return r, c } r = min(r, m.mat.Rows) c = min(c, m.mat.Cols) if r == 0 || c == 0 { return 0, 0 } // TODO(btracey): Check for overlap when complex version exists. // TODO(btracey): Add fast-paths. for i := 0; i < r; i++ { for j := 0; j < c; j++ { m.set(i, j, a.At(i, j)) } } return r, c } // SetRawCMatrix sets the underlying cblas128.General used by the receiver. // Changes to elements in the receiver following the call will be reflected // in b. func (m *CDense) SetRawCMatrix(b cblas128.General) { m.capRows, m.capCols = b.Rows, b.Cols m.mat = b } // RawCMatrix returns the underlying cblas128.General used by the receiver. // Changes to elements in the receiver following the call will be reflected // in returned cblas128.General. func (m *CDense) RawCMatrix() cblas128.General { return m.mat } // Grow returns the receiver expanded by r rows and c columns. If the dimensions // of the expanded matrix are outside the capacities of the receiver a new // allocation is made, otherwise not. Note the receiver itself is not modified // during the call to Grow. func (m *CDense) Grow(r, c int) CMatrix { if r < 0 || c < 0 { panic(ErrIndexOutOfRange) } if r == 0 && c == 0 { return m } r += m.mat.Rows c += m.mat.Cols var t CDense switch { case m.mat.Rows == 0 || m.mat.Cols == 0: t.mat = cblas128.General{ Rows: r, Cols: c, Stride: c, // We zero because we don't know how the matrix will be used. // In other places, the mat is immediately filled with a result; // this is not the case here. Data: useZeroedC(m.mat.Data, r*c), } case r > m.capRows || c > m.capCols: cr := max(r, m.capRows) cc := max(c, m.capCols) t.mat = cblas128.General{ Rows: r, Cols: c, Stride: cc, Data: make([]complex128, cr*cc), } t.capRows = cr t.capCols = cc // Copy the complete matrix over to the new matrix. // Including elements not currently visible. Use a temporary structure // to avoid modifying the receiver. var tmp CDense tmp.mat = cblas128.General{ Rows: m.mat.Rows, Cols: m.mat.Cols, Stride: m.mat.Stride, Data: m.mat.Data, } tmp.capRows = m.capRows tmp.capCols = m.capCols t.Copy(&tmp) return &t default: t.mat = cblas128.General{ Data: m.mat.Data[:(r-1)*m.mat.Stride+c], Rows: r, Cols: c, Stride: m.mat.Stride, } } t.capRows = r t.capCols = c return &t } golang-gonum-v1-gonum-0.14.0/mat/cdense_test.go000066400000000000000000000114431450372207100212510ustar00rootroot00000000000000// Copyright ©2019 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math/cmplx" "testing" "golang.org/x/exp/rand" ) func TestCDenseNewAtSet(t *testing.T) { t.Parallel() for cas, test := range []struct { a []complex128 rows, cols int }{ { a: []complex128{0, 0, 0, 0, 0, 0, 0, 0, 0}, rows: 3, cols: 3, }, } { aCopy := make([]complex128, len(test.a)) copy(aCopy, test.a) mZero := NewCDense(test.rows, test.cols, nil) rows, cols := mZero.Dims() if rows != test.rows { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", cas, rows, test.rows) } if cols != test.cols { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", cas, cols, test.cols) } m := NewCDense(test.rows, test.cols, aCopy) for i := 0; i < test.rows; i++ { for j := 0; j < test.cols; j++ { v := m.At(i, j) idx := i*test.rows + j if v != test.a[idx] { t.Errorf("unexpected get value for test %d at i=%d, j=%d: got: %v, want: %v", cas, i, j, v, test.a[idx]) } add := complex(float64(i+1), float64(j+1)) m.Set(i, j, v+add) if m.At(i, j) != test.a[idx]+add { t.Errorf("unexpected set value for test %d at i=%d, j=%d: got: %v, want: %v", cas, i, j, v, test.a[idx]+add) } } } } } func TestCDenseConjElem(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for r := 1; r <= 8; r++ { for c := 1; c <= 8; c++ { const ( empty = iota fit sliced self ) for _, dst := range []int{empty, fit, sliced, self} { const ( noTrans = iota trans conjTrans bothHT bothTH ) for _, src := range []int{noTrans, trans, conjTrans, bothHT, bothTH} { d := NewCDense(r, c, nil) for i := 0; i < r; i++ { for j := 0; j < c; j++ { d.Set(i, j, complex(rnd.NormFloat64(), rnd.NormFloat64())) } } var ( a CMatrix op string ) switch src { case noTrans: a = d case trans: r, c = c, r a = d.T() op = ".T" case conjTrans: r, c = c, r a = d.H() op = ".H" case bothHT: a = d.H().T() op = ".H.T" case bothTH: a = d.T().H() op = ".T.H" default: panic("invalid src op") } aCopy := NewCDense(r, c, nil) aCopy.Copy(a) var got *CDense switch dst { case empty: got = &CDense{} case fit: got = NewCDense(r, c, nil) case sliced: got = NewCDense(r*2, c*2, nil).Slice(1, r+1, 1, c+1).(*CDense) case self: if r != c && (src == conjTrans || src == trans) { continue } got = d default: panic("invalid dst size") } got.Conj(a) for i := 0; i < r; i++ { for j := 0; j < c; j++ { if got.At(i, j) != cmplx.Conj(aCopy.At(i, j)) { t.Errorf("unexpected results a%s[%d, %d] for r=%d c=%d %v != %v", op, i, j, r, c, got.At(i, j), cmplx.Conj(a.At(i, j)), ) } } } } } } } } func TestCDenseGrow(t *testing.T) { t.Parallel() m := &CDense{} m = m.Grow(10, 10).(*CDense) rows, cols := m.Dims() capRows, capCols := m.Caps() if rows != 10 { t.Errorf("unexpected value for rows: got: %d want: 10", rows) } if cols != 10 { t.Errorf("unexpected value for cols: got: %d want: 10", cols) } if capRows != 10 { t.Errorf("unexpected value for capRows: got: %d want: 10", capRows) } if capCols != 10 { t.Errorf("unexpected value for capCols: got: %d want: 10", capCols) } // Test grow within caps is in-place. m.Set(1, 1, 1) v := m.Slice(1, 5, 1, 5).(*CDense) if v.At(0, 0) != m.At(1, 1) { t.Errorf("unexpected viewed element value: got: %v want: %v", v.At(0, 0), m.At(1, 1)) } v = v.Grow(5, 5).(*CDense) if !CEqual(v, m.Slice(1, 10, 1, 10)) { t.Error("unexpected view value after grow") } // Test grow bigger than caps copies. v = v.Grow(5, 5).(*CDense) if !CEqual(v.Slice(0, 9, 0, 9), m.Slice(1, 10, 1, 10)) { t.Error("unexpected mismatched common view value after grow") } v.Set(0, 0, 0) if CEqual(v.Slice(0, 9, 0, 9), m.Slice(1, 10, 1, 10)) { t.Error("unexpected matching view value after grow past capacity") } // Test grow uses existing data slice when matrix is zero size. v.Reset() p, l := &v.mat.Data[:1][0], cap(v.mat.Data) *p = 1 // This element is at position (-1, -1) relative to v and so should not be visible. v = v.Grow(5, 5).(*CDense) if &v.mat.Data[:1][0] != p { t.Error("grow unexpectedly copied slice within cap limit") } if cap(v.mat.Data) != l { t.Errorf("unexpected change in data slice capacity: got: %d want: %d", cap(v.mat.Data), l) } if v.At(0, 0) != 0 { t.Errorf("unexpected value for At(0, 0): got: %v want: 0", v.At(0, 0)) } } golang-gonum-v1-gonum-0.14.0/mat/cholesky.go000066400000000000000000000765251450372207100206060ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack/lapack64" ) const ( badTriangle = "mat: invalid triangle" badCholesky = "mat: invalid Cholesky factorization" ) var ( _ Matrix = (*Cholesky)(nil) _ Symmetric = (*Cholesky)(nil) _ Matrix = (*BandCholesky)(nil) _ Symmetric = (*BandCholesky)(nil) _ Banded = (*BandCholesky)(nil) _ SymBanded = (*BandCholesky)(nil) _ Matrix = (*PivotedCholesky)(nil) _ Symmetric = (*PivotedCholesky)(nil) ) // Cholesky is a symmetric positive definite matrix represented by its // Cholesky decomposition. // // The decomposition can be constructed using the Factorize method. The // factorization itself can be extracted using the UTo or LTo methods, and the // original symmetric matrix can be recovered with ToSym. // // Note that this matrix representation is useful for certain operations, in // particular finding solutions to linear equations. It is very inefficient // at other operations, in particular At is slow. // // Cholesky methods may only be called on a value that has been successfully // initialized by a call to Factorize that has returned true. Calls to methods // of an unsuccessful Cholesky factorization will panic. type Cholesky struct { // The chol pointer must never be retained as a pointer outside the Cholesky // struct, either by returning chol outside the struct or by setting it to // a pointer coming from outside. The same prohibition applies to the data // slice within chol. chol *TriDense cond float64 } // updateCond updates the condition number of the Cholesky decomposition. If // norm > 0, then that norm is used as the norm of the original matrix A, otherwise // the norm is estimated from the decomposition. func (c *Cholesky) updateCond(norm float64) { n := c.chol.mat.N work := getFloat64s(3*n, false) defer putFloat64s(work) if norm < 0 { // This is an approximation. By the definition of a norm, // |AB| <= |A| |B|. // Since A = Uᵀ*U, we get for the condition number κ that // κ(A) := |A| |A^-1| = |Uᵀ*U| |A^-1| <= |Uᵀ| |U| |A^-1|, // so this will overestimate the condition number somewhat. // The norm of the original factorized matrix cannot be stored // because of update possibilities. unorm := lapack64.Lantr(CondNorm, c.chol.mat, work) lnorm := lapack64.Lantr(CondNormTrans, c.chol.mat, work) norm = unorm * lnorm } sym := c.chol.asSymBlas() iwork := getInts(n, false) v := lapack64.Pocon(sym, norm, work, iwork) putInts(iwork) c.cond = 1 / v } // Dims returns the dimensions of the matrix. func (ch *Cholesky) Dims() (r, c int) { if !ch.valid() { panic(badCholesky) } r, c = ch.chol.Dims() return r, c } // At returns the element at row i, column j. func (c *Cholesky) At(i, j int) float64 { if !c.valid() { panic(badCholesky) } n := c.SymmetricDim() if uint(i) >= uint(n) { panic(ErrRowAccess) } if uint(j) >= uint(n) { panic(ErrColAccess) } var val float64 for k := 0; k <= min(i, j); k++ { val += c.chol.at(k, i) * c.chol.at(k, j) } return val } // T returns the receiver, the transpose of a symmetric matrix. func (c *Cholesky) T() Matrix { return c } // SymmetricDim implements the Symmetric interface and returns the number of rows // in the matrix (this is also the number of columns). func (c *Cholesky) SymmetricDim() int { r, _ := c.chol.Dims() return r } // Cond returns the condition number of the factorized matrix. func (c *Cholesky) Cond() float64 { if !c.valid() { panic(badCholesky) } return c.cond } // Factorize calculates the Cholesky decomposition of the matrix A and returns // whether the matrix is positive definite. If Factorize returns false, the // factorization must not be used. func (c *Cholesky) Factorize(a Symmetric) (ok bool) { n := a.SymmetricDim() if c.chol == nil { c.chol = NewTriDense(n, Upper, nil) } else { c.chol.Reset() c.chol.reuseAsNonZeroed(n, Upper) } copySymIntoTriangle(c.chol, a) sym := c.chol.asSymBlas() work := getFloat64s(c.chol.mat.N, false) norm := lapack64.Lansy(CondNorm, sym, work) putFloat64s(work) _, ok = lapack64.Potrf(sym) if ok { c.updateCond(norm) } else { c.Reset() } return ok } // Reset resets the factorization so that it can be reused as the receiver of a // dimensionally restricted operation. func (c *Cholesky) Reset() { if c.chol != nil { c.chol.Reset() } c.cond = math.Inf(1) } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (c *Cholesky) IsEmpty() bool { return c.chol == nil || c.chol.IsEmpty() } // SetFromU sets the Cholesky decomposition from the given triangular matrix. // SetFromU panics if t is not upper triangular. If the receiver is empty it // is resized to be n×n, the size of t. If dst is non-empty, SetFromU panics // if c is not of size n×n. Note that t is copied into, not stored inside, the // receiver. func (c *Cholesky) SetFromU(t Triangular) { n, kind := t.Triangle() if kind != Upper { panic("cholesky: matrix must be upper triangular") } if c.chol == nil { c.chol = NewTriDense(n, Upper, nil) } else { c.chol.reuseAsNonZeroed(n, Upper) } c.chol.Copy(t) c.updateCond(-1) } // Clone makes a copy of the input Cholesky into the receiver, overwriting the // previous value of the receiver. Clone does not place any restrictions on receiver // shape. Clone panics if the input Cholesky is not the result of a valid decomposition. func (c *Cholesky) Clone(chol *Cholesky) { if !chol.valid() { panic(badCholesky) } n := chol.SymmetricDim() if c.chol == nil { c.chol = NewTriDense(n, Upper, nil) } else { c.chol = NewTriDense(n, Upper, use(c.chol.mat.Data, n*n)) } c.chol.Copy(chol.chol) c.cond = chol.cond } // Det returns the determinant of the matrix that has been factorized. func (c *Cholesky) Det() float64 { if !c.valid() { panic(badCholesky) } return math.Exp(c.LogDet()) } // LogDet returns the log of the determinant of the matrix that has been factorized. func (c *Cholesky) LogDet() float64 { if !c.valid() { panic(badCholesky) } var det float64 for i := 0; i < c.chol.mat.N; i++ { det += 2 * math.Log(c.chol.mat.Data[i*c.chol.mat.Stride+i]) } return det } // SolveTo finds the matrix X that solves A * X = B where A is represented // by the Cholesky decomposition. The result is stored in-place into dst. // If the Cholesky decomposition is singular or near-singular a Condition error // is returned. See the documentation for Condition for more information. func (c *Cholesky) SolveTo(dst *Dense, b Matrix) error { if !c.valid() { panic(badCholesky) } n := c.chol.mat.N bm, bn := b.Dims() if n != bm { panic(ErrShape) } dst.reuseAsNonZeroed(bm, bn) if b != dst { dst.Copy(b) } lapack64.Potrs(c.chol.mat, dst.mat) if c.cond > ConditionTolerance { return Condition(c.cond) } return nil } // SolveCholTo finds the matrix X that solves A * X = B where A and B are represented // by their Cholesky decompositions a and b. The result is stored in-place into // dst. // If the Cholesky decomposition is singular or near-singular a Condition error // is returned. See the documentation for Condition for more information. func (a *Cholesky) SolveCholTo(dst *Dense, b *Cholesky) error { if !a.valid() || !b.valid() { panic(badCholesky) } bn := b.chol.mat.N if a.chol.mat.N != bn { panic(ErrShape) } dst.reuseAsZeroed(bn, bn) dst.Copy(b.chol.T()) blas64.Trsm(blas.Left, blas.Trans, 1, a.chol.mat, dst.mat) blas64.Trsm(blas.Left, blas.NoTrans, 1, a.chol.mat, dst.mat) blas64.Trmm(blas.Right, blas.NoTrans, 1, b.chol.mat, dst.mat) if a.cond > ConditionTolerance { return Condition(a.cond) } return nil } // SolveVecTo finds the vector x that solves A * x = b where A is represented // by the Cholesky decomposition. The result is stored in-place into // dst. // If the Cholesky decomposition is singular or near-singular a Condition error // is returned. See the documentation for Condition for more information. func (c *Cholesky) SolveVecTo(dst *VecDense, b Vector) error { if !c.valid() { panic(badCholesky) } n := c.chol.mat.N if br, bc := b.Dims(); br != n || bc != 1 { panic(ErrShape) } switch rv := b.(type) { default: dst.reuseAsNonZeroed(n) return c.SolveTo(dst.asDense(), b) case RawVectorer: bmat := rv.RawVector() if dst != b { dst.checkOverlap(bmat) } dst.reuseAsNonZeroed(n) if dst != b { dst.CopyVec(b) } lapack64.Potrs(c.chol.mat, dst.asGeneral()) if c.cond > ConditionTolerance { return Condition(c.cond) } return nil } } // RawU returns the Triangular matrix used to store the Cholesky decomposition of // the original matrix A. The returned matrix should not be modified. If it is // modified, the decomposition is invalid and should not be used. func (c *Cholesky) RawU() Triangular { return c.chol } // UTo stores into dst the n×n upper triangular matrix U from a Cholesky // decomposition // // A = Uᵀ * U. // // If dst is empty, it is resized to be an n×n upper triangular matrix. When dst // is non-empty, UTo panics if dst is not n×n or not Upper. UTo will also panic // if the receiver does not contain a successful factorization. func (c *Cholesky) UTo(dst *TriDense) { if !c.valid() { panic(badCholesky) } n := c.chol.mat.N if dst.IsEmpty() { dst.ReuseAsTri(n, Upper) } else { n2, kind := dst.Triangle() if n != n2 { panic(ErrShape) } if kind != Upper { panic(ErrTriangle) } } dst.Copy(c.chol) } // LTo stores into dst the n×n lower triangular matrix L from a Cholesky // decomposition // // A = L * Lᵀ. // // If dst is empty, it is resized to be an n×n lower triangular matrix. When dst // is non-empty, LTo panics if dst is not n×n or not Lower. LTo will also panic // if the receiver does not contain a successful factorization. func (c *Cholesky) LTo(dst *TriDense) { if !c.valid() { panic(badCholesky) } n := c.chol.mat.N if dst.IsEmpty() { dst.ReuseAsTri(n, Lower) } else { n2, kind := dst.Triangle() if n != n2 { panic(ErrShape) } if kind != Lower { panic(ErrTriangle) } } dst.Copy(c.chol.TTri()) } // ToSym reconstructs the original positive definite matrix from its // Cholesky decomposition, storing the result into dst. If dst is // empty it is resized to be n×n. If dst is non-empty, ToSym panics // if dst is not of size n×n. ToSym will also panic if the receiver // does not contain a successful factorization. func (c *Cholesky) ToSym(dst *SymDense) { if !c.valid() { panic(badCholesky) } n := c.chol.mat.N if dst.IsEmpty() { dst.ReuseAsSym(n) } else { n2 := dst.SymmetricDim() if n != n2 { panic(ErrShape) } } // Create a TriDense representing the Cholesky factor U with dst's // backing slice. // Operations on u are reflected in s. u := &TriDense{ mat: blas64.Triangular{ Uplo: blas.Upper, Diag: blas.NonUnit, N: n, Data: dst.mat.Data, Stride: dst.mat.Stride, }, cap: n, } u.Copy(c.chol) // Compute the product Uᵀ*U using the algorithm from LAPACK/TESTING/LIN/dpot01.f a := u.mat.Data lda := u.mat.Stride bi := blas64.Implementation() for k := n - 1; k >= 0; k-- { a[k*lda+k] = bi.Ddot(k+1, a[k:], lda, a[k:], lda) if k > 0 { bi.Dtrmv(blas.Upper, blas.Trans, blas.NonUnit, k, a, lda, a[k:], lda) } } } // InverseTo computes the inverse of the matrix represented by its Cholesky // factorization and stores the result into s. If the factorized // matrix is ill-conditioned, a Condition error will be returned. // Note that matrix inversion is numerically unstable, and should generally be // avoided where possible, for example by using the Solve routines. func (c *Cholesky) InverseTo(dst *SymDense) error { if !c.valid() { panic(badCholesky) } dst.reuseAsNonZeroed(c.chol.mat.N) // Create a TriDense representing the Cholesky factor U with the backing // slice from dst. // Operations on u are reflected in dst. u := &TriDense{ mat: blas64.Triangular{ Uplo: blas.Upper, Diag: blas.NonUnit, N: dst.mat.N, Data: dst.mat.Data, Stride: dst.mat.Stride, }, cap: dst.mat.N, } u.Copy(c.chol) _, ok := lapack64.Potri(u.mat) if !ok { return Condition(math.Inf(1)) } if c.cond > ConditionTolerance { return Condition(c.cond) } return nil } // Scale multiplies the original matrix A by a positive constant using // its Cholesky decomposition, storing the result in-place into the receiver. // That is, if the original Cholesky factorization is // // Uᵀ * U = A // // the updated factorization is // // U'ᵀ * U' = f A = A' // // Scale panics if the constant is non-positive, or if the receiver is non-empty // and is of a different size from the input. func (c *Cholesky) Scale(f float64, orig *Cholesky) { if !orig.valid() { panic(badCholesky) } if f <= 0 { panic("cholesky: scaling by a non-positive constant") } n := orig.SymmetricDim() if c.chol == nil { c.chol = NewTriDense(n, Upper, nil) } else if c.chol.mat.N != n { panic(ErrShape) } c.chol.ScaleTri(math.Sqrt(f), orig.chol) c.cond = orig.cond // Scaling by a positive constant does not change the condition number. } // ExtendVecSym computes the Cholesky decomposition of the original matrix A, // whose Cholesky decomposition is in a, extended by a the n×1 vector v according to // // [A w] // [w' k] // // where k = v[n-1] and w = v[:n-1]. The result is stored into the receiver. // In order for the updated matrix to be positive definite, it must be the case // that k > w' A^-1 w. If this condition does not hold then ExtendVecSym will // return false and the receiver will not be updated. // // ExtendVecSym will panic if v.Len() != a.SymmetricDim()+1 or if a does not contain // a valid decomposition. func (c *Cholesky) ExtendVecSym(a *Cholesky, v Vector) (ok bool) { n := a.SymmetricDim() if v.Len() != n+1 { panic(badSliceLength) } if !a.valid() { panic(badCholesky) } // The algorithm is commented here, but see also // https://math.stackexchange.com/questions/955874/cholesky-factor-when-adding-a-row-and-column-to-already-factorized-matrix // We have A and want to compute the Cholesky of // [A w] // [w' k] // We want // [U c] // [0 d] // to be the updated Cholesky, and so it must be that // [A w] = [U' 0] [U c] // [w' k] [c' d] [0 d] // Thus, we need // 1) A = U'U (true by the original decomposition being valid), // 2) U' * c = w => c = U'^-1 w // 3) c'*c + d'*d = k => d = sqrt(k-c'*c) // First, compute c = U'^-1 a w := NewVecDense(n, nil) w.CopyVec(v) k := v.At(n, 0) var t VecDense _ = t.SolveVec(a.chol.T(), w) dot := Dot(&t, &t) if dot >= k { return false } d := math.Sqrt(k - dot) newU := NewTriDense(n+1, Upper, nil) newU.Copy(a.chol) for i := 0; i < n; i++ { newU.SetTri(i, n, t.At(i, 0)) } newU.SetTri(n, n, d) c.chol = newU c.updateCond(-1) return true } // SymRankOne performs a rank-1 update of the original matrix A and refactorizes // its Cholesky factorization, storing the result into the receiver. That is, if // in the original Cholesky factorization // // Uᵀ * U = A, // // in the updated factorization // // U'ᵀ * U' = A + alpha * x * xᵀ = A'. // // Note that when alpha is negative, the updating problem may be ill-conditioned // and the results may be inaccurate, or the updated matrix A' may not be // positive definite and not have a Cholesky factorization. SymRankOne returns // whether the updated matrix A' is positive definite. If the update fails // the receiver is left unchanged. // // SymRankOne updates a Cholesky factorization in O(n²) time. The Cholesky // factorization computation from scratch is O(n³). func (c *Cholesky) SymRankOne(orig *Cholesky, alpha float64, x Vector) (ok bool) { if !orig.valid() { panic(badCholesky) } n := orig.SymmetricDim() if r, c := x.Dims(); r != n || c != 1 { panic(ErrShape) } if orig != c { if c.chol == nil { c.chol = NewTriDense(n, Upper, nil) } else if c.chol.mat.N != n { panic(ErrShape) } c.chol.Copy(orig.chol) } if alpha == 0 { return true } // Algorithms for updating and downdating the Cholesky factorization are // described, for example, in // - J. J. Dongarra, J. R. Bunch, C. B. Moler, G. W. Stewart: LINPACK // Users' Guide. SIAM (1979), pages 10.10--10.14 // or // - P. E. Gill, G. H. Golub, W. Murray, and M. A. Saunders: Methods for // modifying matrix factorizations. Mathematics of Computation 28(126) // (1974), Method C3 on page 521 // // The implementation is based on LINPACK code // http://www.netlib.org/linpack/dchud.f // http://www.netlib.org/linpack/dchdd.f // and // https://icl.cs.utk.edu/lapack-forum/viewtopic.php?f=2&t=2646 // // According to http://icl.cs.utk.edu/lapack-forum/archives/lapack/msg00301.html // LINPACK is released under BSD license. // // See also: // - M. A. Saunders: Large-scale Linear Programming Using the Cholesky // Factorization. Technical Report Stanford University (1972) // http://i.stanford.edu/pub/cstr/reports/cs/tr/72/252/CS-TR-72-252.pdf // - Matthias Seeger: Low rank updates for the Cholesky decomposition. // EPFL Technical Report 161468 (2004) // http://infoscience.epfl.ch/record/161468 work := getFloat64s(n, false) defer putFloat64s(work) var xmat blas64.Vector if rv, ok := x.(RawVectorer); ok { xmat = rv.RawVector() } else { var tmp *VecDense tmp.CopyVec(x) xmat = tmp.RawVector() } blas64.Copy(xmat, blas64.Vector{N: n, Data: work, Inc: 1}) if alpha > 0 { // Compute rank-1 update. if alpha != 1 { blas64.Scal(math.Sqrt(alpha), blas64.Vector{N: n, Data: work, Inc: 1}) } umat := c.chol.mat stride := umat.Stride for i := 0; i < n; i++ { // Compute parameters of the Givens matrix that zeroes // the i-th element of x. c, s, r, _ := blas64.Rotg(umat.Data[i*stride+i], work[i]) if r < 0 { // Multiply by -1 to have positive diagonal // elements. r *= -1 c *= -1 s *= -1 } umat.Data[i*stride+i] = r if i < n-1 { // Multiply the extended factorization matrix by // the Givens matrix from the left. Only // the i-th row and x are modified. blas64.Rot( blas64.Vector{N: n - i - 1, Data: umat.Data[i*stride+i+1 : i*stride+n], Inc: 1}, blas64.Vector{N: n - i - 1, Data: work[i+1 : n], Inc: 1}, c, s) } } c.updateCond(-1) return true } // Compute rank-1 downdate. alpha = math.Sqrt(-alpha) if alpha != 1 { blas64.Scal(alpha, blas64.Vector{N: n, Data: work, Inc: 1}) } // Solve Uᵀ * p = x storing the result into work. ok = lapack64.Trtrs(blas.Trans, c.chol.RawTriangular(), blas64.General{ Rows: n, Cols: 1, Stride: 1, Data: work, }) if !ok { // The original matrix is singular. Should not happen, because // the factorization is valid. panic(badCholesky) } norm := blas64.Nrm2(blas64.Vector{N: n, Data: work, Inc: 1}) if norm >= 1 { // The updated matrix is not positive definite. return false } norm = math.Sqrt((1 + norm) * (1 - norm)) cos := getFloat64s(n, false) defer putFloat64s(cos) sin := getFloat64s(n, false) defer putFloat64s(sin) for i := n - 1; i >= 0; i-- { // Compute parameters of Givens matrices that zero elements of p // backwards. cos[i], sin[i], norm, _ = blas64.Rotg(norm, work[i]) if norm < 0 { norm *= -1 cos[i] *= -1 sin[i] *= -1 } } workMat := getTriDenseWorkspace(c.chol.mat.N, c.chol.triKind(), false) defer putTriWorkspace(workMat) workMat.Copy(c.chol) umat := workMat.mat stride := workMat.mat.Stride for i := n - 1; i >= 0; i-- { work[i] = 0 // Apply Givens matrices to U. blas64.Rot( blas64.Vector{N: n - i, Data: work[i:n], Inc: 1}, blas64.Vector{N: n - i, Data: umat.Data[i*stride+i : i*stride+n], Inc: 1}, cos[i], sin[i]) if umat.Data[i*stride+i] == 0 { // The matrix is singular (may rarely happen due to // floating-point effects?). ok = false } else if umat.Data[i*stride+i] < 0 { // Diagonal elements should be positive. If it happens // that on the i-th row the diagonal is negative, // multiply U from the left by an identity matrix that // has -1 on the i-th row. blas64.Scal(-1, blas64.Vector{N: n - i, Data: umat.Data[i*stride+i : i*stride+n], Inc: 1}) } } if ok { c.chol.Copy(workMat) c.updateCond(-1) } return ok } func (c *Cholesky) valid() bool { return c.chol != nil && !c.chol.IsEmpty() } // BandCholesky is a symmetric positive-definite band matrix represented by its // Cholesky decomposition. // // Note that this matrix representation is useful for certain operations, in // particular finding solutions to linear equations. It is very inefficient at // other operations, in particular At is slow. // // BandCholesky methods may only be called on a value that has been successfully // initialized by a call to Factorize that has returned true. Calls to methods // of an unsuccessful Cholesky factorization will panic. type BandCholesky struct { // The chol pointer must never be retained as a pointer outside the Cholesky // struct, either by returning chol outside the struct or by setting it to // a pointer coming from outside. The same prohibition applies to the data // slice within chol. chol *TriBandDense cond float64 } // Factorize calculates the Cholesky decomposition of the matrix A and returns // whether the matrix is positive definite. If Factorize returns false, the // factorization must not be used. func (ch *BandCholesky) Factorize(a SymBanded) (ok bool) { n, k := a.SymBand() if ch.chol == nil { ch.chol = NewTriBandDense(n, k, Upper, nil) } else { ch.chol.Reset() ch.chol.ReuseAsTriBand(n, k, Upper) } copySymBandIntoTriBand(ch.chol, a) cSym := blas64.SymmetricBand{ Uplo: blas.Upper, N: n, K: k, Data: ch.chol.RawTriBand().Data, Stride: ch.chol.RawTriBand().Stride, } _, ok = lapack64.Pbtrf(cSym) if !ok { ch.Reset() return false } work := getFloat64s(3*n, false) iwork := getInts(n, false) aNorm := lapack64.Lansb(CondNorm, cSym, work) ch.cond = 1 / lapack64.Pbcon(cSym, aNorm, work, iwork) putInts(iwork) putFloat64s(work) return true } // SolveTo finds the matrix X that solves A * X = B where A is represented by // the Cholesky decomposition. The result is stored in-place into dst. // If the Cholesky decomposition is singular or near-singular a Condition error // is returned. See the documentation for Condition for more information. func (ch *BandCholesky) SolveTo(dst *Dense, b Matrix) error { if !ch.valid() { panic(badCholesky) } br, bc := b.Dims() if br != ch.chol.mat.N { panic(ErrShape) } dst.reuseAsNonZeroed(br, bc) if b != dst { dst.Copy(b) } lapack64.Pbtrs(ch.chol.mat, dst.mat) if ch.cond > ConditionTolerance { return Condition(ch.cond) } return nil } // SolveVecTo finds the vector x that solves A * x = b where A is represented by // the Cholesky decomposition. The result is stored in-place into dst. // If the Cholesky decomposition is singular or near-singular a Condition error // is returned. See the documentation for Condition for more information. func (ch *BandCholesky) SolveVecTo(dst *VecDense, b Vector) error { if !ch.valid() { panic(badCholesky) } n := ch.chol.mat.N if br, bc := b.Dims(); br != n || bc != 1 { panic(ErrShape) } if b, ok := b.(RawVectorer); ok && dst != b { dst.checkOverlap(b.RawVector()) } dst.reuseAsNonZeroed(n) if dst != b { dst.CopyVec(b) } lapack64.Pbtrs(ch.chol.mat, dst.asGeneral()) if ch.cond > ConditionTolerance { return Condition(ch.cond) } return nil } // Cond returns the condition number of the factorized matrix. func (ch *BandCholesky) Cond() float64 { if !ch.valid() { panic(badCholesky) } return ch.cond } // Reset resets the factorization so that it can be reused as the receiver of // a dimensionally restricted operation. func (ch *BandCholesky) Reset() { if ch.chol != nil { ch.chol.Reset() } ch.cond = math.Inf(1) } // Dims returns the dimensions of the matrix. func (ch *BandCholesky) Dims() (r, c int) { if !ch.valid() { panic(badCholesky) } r, c = ch.chol.Dims() return r, c } // At returns the element at row i, column j. func (ch *BandCholesky) At(i, j int) float64 { if !ch.valid() { panic(badCholesky) } n, k, _ := ch.chol.TriBand() if uint(i) >= uint(n) { panic(ErrRowAccess) } if uint(j) >= uint(n) { panic(ErrColAccess) } if i > j { i, j = j, i } if j-i > k { return 0 } var aij float64 for k := max(0, j-k); k <= i; k++ { aij += ch.chol.at(k, i) * ch.chol.at(k, j) } return aij } // T returns the receiver, the transpose of a symmetric matrix. func (ch *BandCholesky) T() Matrix { return ch } // TBand returns the receiver, the transpose of a symmetric band matrix. func (ch *BandCholesky) TBand() Banded { return ch } // SymmetricDim implements the Symmetric interface and returns the number of rows // in the matrix (this is also the number of columns). func (ch *BandCholesky) SymmetricDim() int { n, _ := ch.chol.Triangle() return n } // Bandwidth returns the lower and upper bandwidth values for the matrix. // The total bandwidth of the matrix is kl+ku+1. func (ch *BandCholesky) Bandwidth() (kl, ku int) { _, k, _ := ch.chol.TriBand() return k, k } // SymBand returns the number of rows/columns in the matrix, and the size of the // bandwidth. The total bandwidth of the matrix is 2*k+1. func (ch *BandCholesky) SymBand() (n, k int) { n, k, _ = ch.chol.TriBand() return n, k } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for dimensionally restricted operations. The receiver can be emptied // using Reset. func (ch *BandCholesky) IsEmpty() bool { return ch == nil || ch.chol.IsEmpty() } // Det returns the determinant of the matrix that has been factorized. func (ch *BandCholesky) Det() float64 { if !ch.valid() { panic(badCholesky) } return math.Exp(ch.LogDet()) } // LogDet returns the log of the determinant of the matrix that has been factorized. func (ch *BandCholesky) LogDet() float64 { if !ch.valid() { panic(badCholesky) } var det float64 for i := 0; i < ch.chol.mat.N; i++ { det += 2 * math.Log(ch.chol.mat.Data[i*ch.chol.mat.Stride]) } return det } func (ch *BandCholesky) valid() bool { return ch.chol != nil && !ch.chol.IsEmpty() } // PivotedCholesky is a symmetric positive semi-definite matrix represented by // its Cholesky factorization with complete pivoting. // // The factorization has the form // // A = P * Uᵀ * U * Pᵀ // // where U is an upper triangular matrix and P is a permutation matrix. // // Cholesky methods may only be called on a receiver that has been successfully // initialized by a call to Factorize. SolveTo and SolveVecTo methods may only // called if Factorize has returned true. // // If the matrix A is certainly positive definite, then the unpivoted Cholesky // could be more efficient, especially for smaller matrices. type PivotedCholesky struct { chol *TriDense // The factor U piv, pivTrans []int // The permutation matrices P and Pᵀ rank int // The computed rank of A ok bool // Indicates whether and the factorization can be used for solving linear systems cond float64 // The condition number when ok is true } // Factorize computes the Cholesky factorization of the symmetric positive // semi-definite matrix A and returns whether the matrix is positive definite. // If Factorize returns false, the SolveTo methods must not be used. // // tol is a tolerance used to determine the computed rank of A. If it is // negative, a default value will be used. func (c *PivotedCholesky) Factorize(a Symmetric, tol float64) (ok bool) { n := a.SymmetricDim() c.reset(n) copySymIntoTriangle(c.chol, a) work := getFloat64s(3*c.chol.mat.N, false) defer putFloat64s(work) sym := c.chol.asSymBlas() aNorm := lapack64.Lansy(CondNorm, sym, work) _, c.rank, c.ok = lapack64.Pstrf(sym, c.piv, tol, work) if c.ok { iwork := getInts(n, false) defer putInts(iwork) c.cond = 1 / lapack64.Pocon(sym, aNorm, work, iwork) } for i, p := range c.piv { c.pivTrans[p] = i } return c.ok } // reset prepares the receiver for factorization of matrices of size n. func (c *PivotedCholesky) reset(n int) { if c.chol == nil { c.chol = NewTriDense(n, Upper, nil) } else { c.chol.Reset() c.chol.reuseAsNonZeroed(n, Upper) } c.piv = useInt(c.piv, n) c.pivTrans = useInt(c.pivTrans, n) c.rank = 0 c.ok = false c.cond = math.Inf(1) } // Dims returns the dimensions of the matrix A. func (ch *PivotedCholesky) Dims() (r, c int) { if ch.chol == nil { panic(badCholesky) } r, c = ch.chol.Dims() return r, c } // At returns the element of A at row i, column j. func (c *PivotedCholesky) At(i, j int) float64 { if c.chol == nil { panic(badCholesky) } n := c.SymmetricDim() if uint(i) >= uint(n) { panic(ErrRowAccess) } if uint(j) >= uint(n) { panic(ErrColAccess) } i = c.pivTrans[i] j = c.pivTrans[j] minij := min(min(i+1, j+1), c.rank) var val float64 for k := 0; k < minij; k++ { val += c.chol.at(k, i) * c.chol.at(k, j) } return val } // T returns the receiver, the transpose of a symmetric matrix. func (c *PivotedCholesky) T() Matrix { return c } // SymmetricDim implements the Symmetric interface and returns the number of // rows (or columns) in the matrix . func (c *PivotedCholesky) SymmetricDim() int { if c.chol == nil { panic(badCholesky) } n, _ := c.chol.Dims() return n } // Rank returns the computed rank of the matrix A. func (c *PivotedCholesky) Rank() int { if c.chol == nil { panic(badCholesky) } return c.rank } // Cond returns the condition number of the factorized matrix. func (c *PivotedCholesky) Cond() float64 { if !c.ok { panic(badCholesky) } return c.cond } // SolveTo finds the matrix X that solves A * X = B where A is represented by // the Cholesky decomposition. The result is stored in-place into dst. If the // Cholesky decomposition is singular or near-singular, a Condition error is // returned. See the documentation for Condition for more information. // // If Factorize returned false, SolveTo will panic. func (c *PivotedCholesky) SolveTo(dst *Dense, b Matrix) error { if !c.ok { panic(badCholesky) } n := c.chol.mat.N bm, bn := b.Dims() if n != bm { panic(ErrShape) } dst.reuseAsNonZeroed(bm, bn) if dst != b { dst.Copy(b) } // Permute rows of B: D = Pᵀ * B. lapack64.Lapmr(true, dst.mat, c.piv) // Solve Uᵀ * U * Y = D. lapack64.Potrs(c.chol.mat, dst.mat) // Permute rows of Y to recover the solution: X = P * Y. lapack64.Lapmr(false, dst.mat, c.piv) if c.cond > ConditionTolerance { return Condition(c.cond) } return nil } // SolveVecTo finds the vector x that solves A * x = b where A is represented by // the Cholesky decomposition. The result is stored in-place into dst. If the // Cholesky decomposition is singular or near-singular, a Condition error is // returned. See the documentation for Condition for more information. // // If Factorize returned false, SolveVecTo will panic. func (c *PivotedCholesky) SolveVecTo(dst *VecDense, b Vector) error { if !c.ok { panic(badCholesky) } n := c.chol.mat.N if br, bc := b.Dims(); br != n || bc != 1 { panic(ErrShape) } if b, ok := b.(RawVectorer); ok && dst != b { dst.checkOverlap(b.RawVector()) } dst.reuseAsNonZeroed(n) if dst != b { dst.CopyVec(b) } // Permute rows of B: D = Pᵀ * B. lapack64.Lapmr(true, dst.asGeneral(), c.piv) // Solve Uᵀ * U * Y = D. lapack64.Potrs(c.chol.mat, dst.asGeneral()) // Permute rows of Y to recover the solution: X = P * Y. lapack64.Lapmr(false, dst.asGeneral(), c.piv) if c.cond > ConditionTolerance { return Condition(c.cond) } return nil } golang-gonum-v1-gonum-0.14.0/mat/cholesky_example_test.go000066400000000000000000000062251450372207100233460ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "gonum.org/v1/gonum/mat" ) func ExampleCholesky() { // Construct a symmetric positive definite matrix. tmp := mat.NewDense(4, 4, []float64{ 2, 6, 8, -4, 1, 8, 7, -2, 2, 2, 1, 7, 8, -2, -2, 1, }) var a mat.SymDense a.SymOuterK(1, tmp) fmt.Printf("a = %0.4v\n", mat.Formatted(&a, mat.Prefix(" "))) // Compute the cholesky factorization. var chol mat.Cholesky if ok := chol.Factorize(&a); !ok { fmt.Println("a matrix is not positive semi-definite.") } // Find the determinant. fmt.Printf("\nThe determinant of a is %0.4g\n\n", chol.Det()) // Use the factorization to solve the system of equations a * x = b. b := mat.NewVecDense(4, []float64{1, 2, 3, 4}) var x mat.VecDense if err := chol.SolveVecTo(&x, b); err != nil { fmt.Println("Matrix is near singular: ", err) } fmt.Println("Solve a * x = b") fmt.Printf("x = %0.4v\n", mat.Formatted(&x, mat.Prefix(" "))) // Extract the factorization and check that it equals the original matrix. var t mat.TriDense chol.LTo(&t) var test mat.Dense test.Mul(&t, t.T()) fmt.Println() fmt.Printf("L * Lᵀ = %0.4v\n", mat.Formatted(&a, mat.Prefix(" "))) // Output: // a = ⎡120 114 -4 -16⎤ // ⎢114 118 11 -24⎥ // ⎢ -4 11 58 17⎥ // ⎣-16 -24 17 73⎦ // // The determinant of a is 1.543e+06 // // Solve a * x = b // x = ⎡ -0.239⎤ // ⎢ 0.2732⎥ // ⎢-0.04681⎥ // ⎣ 0.1031⎦ // // L * Lᵀ = ⎡120 114 -4 -16⎤ // ⎢114 118 11 -24⎥ // ⎢ -4 11 58 17⎥ // ⎣-16 -24 17 73⎦ } func ExampleCholesky_SymRankOne() { a := mat.NewSymDense(4, []float64{ 1, 1, 1, 1, 0, 2, 3, 4, 0, 0, 6, 10, 0, 0, 0, 20, }) fmt.Printf("A = %0.4v\n", mat.Formatted(a, mat.Prefix(" "))) // Compute the Cholesky factorization. var chol mat.Cholesky if ok := chol.Factorize(a); !ok { fmt.Println("matrix a is not positive definite.") } x := mat.NewVecDense(4, []float64{0, 0, 0, 1}) fmt.Printf("\nx = %0.4v\n", mat.Formatted(x, mat.Prefix(" "))) // Rank-1 update the factorization. chol.SymRankOne(&chol, 1, x) // Rank-1 update the matrix a. a.SymRankOne(a, 1, x) var au mat.SymDense chol.ToSym(&au) // Print the matrix that was updated directly. fmt.Printf("\nA' = %0.4v\n", mat.Formatted(a, mat.Prefix(" "))) // Print the matrix recovered from the factorization. fmt.Printf("\nU'ᵀ * U' = %0.4v\n", mat.Formatted(&au, mat.Prefix(" "))) // Output: // A = ⎡ 1 1 1 1⎤ // ⎢ 1 2 3 4⎥ // ⎢ 1 3 6 10⎥ // ⎣ 1 4 10 20⎦ // // x = ⎡0⎤ // ⎢0⎥ // ⎢0⎥ // ⎣1⎦ // // A' = ⎡ 1 1 1 1⎤ // ⎢ 1 2 3 4⎥ // ⎢ 1 3 6 10⎥ // ⎣ 1 4 10 21⎦ // // U'ᵀ * U' = ⎡ 1 1 1 1⎤ // ⎢ 1 2 3 4⎥ // ⎢ 1 3 6 10⎥ // ⎣ 1 4 10 21⎦ } golang-gonum-v1-gonum-0.14.0/mat/cholesky_test.go000066400000000000000000000620111450372207100216260ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "math" "strconv" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestCholesky(t *testing.T) { t.Parallel() for _, test := range []struct { a *SymDense cond float64 want *TriDense posdef bool }{ { a: NewSymDense(3, []float64{ 4, 1, 1, 0, 2, 3, 0, 0, 6, }), cond: 37, want: NewTriDense(3, true, []float64{ 2, 0.5, 0.5, 0, 1.3228756555322954, 2.0788046015507495, 0, 0, 1.195228609334394, }), posdef: true, }, } { _, n := test.a.Dims() for _, chol := range []*Cholesky{ {}, {chol: NewTriDense(n-1, true, nil)}, {chol: NewTriDense(n, true, nil)}, {chol: NewTriDense(n+1, true, nil)}, } { ok := chol.Factorize(test.a) if ok != test.posdef { t.Errorf("unexpected return from Cholesky factorization: got: ok=%t want: ok=%t", ok, test.posdef) } fc := DenseCopyOf(chol.chol) if !Equal(fc, test.want) { t.Error("incorrect Cholesky factorization") } if math.Abs(test.cond-chol.cond) > 1e-13 { t.Errorf("Condition number mismatch: Want %v, got %v", test.cond, chol.cond) } var U TriDense chol.UTo(&U) aCopy := DenseCopyOf(test.a) var a Dense a.Mul(U.TTri(), &U) if !EqualApprox(&a, aCopy, 1e-14) { t.Error("unexpected Cholesky factor product") } var L TriDense chol.LTo(&L) a.Mul(&L, L.TTri()) if !EqualApprox(&a, aCopy, 1e-14) { t.Error("unexpected Cholesky factor product") } } } } func TestCholeskyAt(t *testing.T) { t.Parallel() for _, test := range []*SymDense{ NewSymDense(3, []float64{ 53, 59, 37, 59, 83, 71, 37, 71, 101, }), } { var chol Cholesky ok := chol.Factorize(test) if !ok { t.Fatalf("Matrix not positive definite") } n := test.SymmetricDim() cn := chol.SymmetricDim() if cn != n { t.Errorf("Cholesky size does not match. Got %d, want %d", cn, n) } for i := 0; i < n; i++ { for j := 0; j < n; j++ { got := chol.At(i, j) want := test.At(i, j) if math.Abs(got-want) > 1e-12 { t.Errorf("Cholesky at does not match at %d, %d. Got %v, want %v", i, j, got, want) } } } } } func TestCholeskySolveTo(t *testing.T) { t.Parallel() for _, test := range []struct { a *SymDense b *Dense ans *Dense }{ { a: NewSymDense(2, []float64{ 1, 0, 0, 1, }), b: NewDense(2, 1, []float64{5, 6}), ans: NewDense(2, 1, []float64{5, 6}), }, { a: NewSymDense(3, []float64{ 53, 59, 37, 0, 83, 71, 37, 71, 101, }), b: NewDense(3, 1, []float64{5, 6, 7}), ans: NewDense(3, 1, []float64{0.20745069393718094, -0.17421475529583694, 0.11577794010226464}), }, } { var chol Cholesky ok := chol.Factorize(test.a) if !ok { t.Fatal("unexpected Cholesky factorization failure: not positive definite") } var x Dense err := chol.SolveTo(&x, test.b) if err != nil { t.Errorf("unexpected error from Cholesky solve: %v", err) } if !EqualApprox(&x, test.ans, 1e-12) { t.Error("incorrect Cholesky solve solution") } var ans Dense ans.Mul(test.a, &x) if !EqualApprox(&ans, test.b, 1e-12) { t.Error("incorrect Cholesky solve solution product") } } } func TestCholeskySolveCholTo(t *testing.T) { t.Parallel() for _, test := range []struct { a, b *SymDense }{ { a: NewSymDense(2, []float64{ 1, 0, 0, 1, }), b: NewSymDense(2, []float64{ 1, 0, 0, 1, }), }, { a: NewSymDense(2, []float64{ 1, 0, 0, 1, }), b: NewSymDense(2, []float64{ 2, 0, 0, 2, }), }, { a: NewSymDense(3, []float64{ 53, 59, 37, 59, 83, 71, 37, 71, 101, }), b: NewSymDense(3, []float64{ 2, -1, 0, -1, 2, -1, 0, -1, 2, }), }, } { var chola, cholb Cholesky ok := chola.Factorize(test.a) if !ok { t.Fatal("unexpected Cholesky factorization failure for a: not positive definite") } ok = cholb.Factorize(test.b) if !ok { t.Fatal("unexpected Cholesky factorization failure for b: not positive definite") } var x Dense err := chola.SolveCholTo(&x, &cholb) if err != nil { t.Errorf("unexpected error from Cholesky solve: %v", err) } var ans Dense ans.Mul(test.a, &x) if !EqualApprox(&ans, test.b, 1e-12) { var y Dense err := y.Solve(test.a, test.b) if err != nil { t.Errorf("unexpected error from dense solve: %v", err) } t.Errorf("incorrect Cholesky solve solution product\ngot solution:\n%.4v\nwant solution\n%.4v", Formatted(&x), Formatted(&y)) } } } func TestCholeskySolveVecTo(t *testing.T) { t.Parallel() for _, test := range []struct { a *SymDense b *VecDense ans *VecDense }{ { a: NewSymDense(2, []float64{ 1, 0, 0, 1, }), b: NewVecDense(2, []float64{5, 6}), ans: NewVecDense(2, []float64{5, 6}), }, { a: NewSymDense(3, []float64{ 53, 59, 37, 0, 83, 71, 0, 0, 101, }), b: NewVecDense(3, []float64{5, 6, 7}), ans: NewVecDense(3, []float64{0.20745069393718094, -0.17421475529583694, 0.11577794010226464}), }, } { var chol Cholesky ok := chol.Factorize(test.a) if !ok { t.Fatal("unexpected Cholesky factorization failure: not positive definite") } var x VecDense err := chol.SolveVecTo(&x, test.b) if err != nil { t.Errorf("unexpected error from Cholesky solve: %v", err) } if !EqualApprox(&x, test.ans, 1e-12) { t.Error("incorrect Cholesky solve solution") } var ans VecDense ans.MulVec(test.a, &x) if !EqualApprox(&ans, test.b, 1e-12) { t.Error("incorrect Cholesky solve solution product") } } } func TestCholeskyToSym(t *testing.T) { t.Parallel() for _, test := range []*SymDense{ NewSymDense(3, []float64{ 53, 59, 37, 0, 83, 71, 0, 0, 101, }), } { var chol Cholesky ok := chol.Factorize(test) if !ok { t.Fatal("unexpected Cholesky factorization failure: not positive definite") } var s SymDense chol.ToSym(&s) if !EqualApprox(&s, test, 1e-12) { t.Errorf("Cholesky reconstruction not equal to original matrix.\nWant:\n% v\nGot:\n% v\n", Formatted(test), Formatted(&s)) } } } func TestCloneCholesky(t *testing.T) { t.Parallel() for _, test := range []*SymDense{ NewSymDense(3, []float64{ 53, 59, 37, 0, 83, 71, 0, 0, 101, }), } { var chol Cholesky ok := chol.Factorize(test) if !ok { panic("bad test") } var chol2 Cholesky chol2.Clone(&chol) if chol.cond != chol2.cond { t.Errorf("condition number mismatch from empty") } if !Equal(chol.chol, chol2.chol) { t.Errorf("chol mismatch from empty") } // Corrupt chol2 and try again chol2.cond = math.NaN() chol2.chol = NewTriDense(2, Upper, nil) chol2.Clone(&chol) if chol.cond != chol2.cond { t.Errorf("condition number mismatch from non-empty") } if !Equal(chol.chol, chol2.chol) { t.Errorf("chol mismatch from non-empty") } } } func TestCholeskyInverseTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 3, 5, 9} { data := make([]float64, n*n) for i := range data { data[i] = rnd.NormFloat64() } var s SymDense s.SymOuterK(1, NewDense(n, n, data)) var chol Cholesky ok := chol.Factorize(&s) if !ok { t.Errorf("Bad test, cholesky decomposition failed") } var sInv SymDense err := chol.InverseTo(&sInv) if err != nil { t.Errorf("unexpected error from Cholesky inverse: %v", err) } var ans Dense ans.Mul(&sInv, &s) if !equalApprox(eye(n), &ans, 1e-8, false) { var diff Dense diff.Sub(eye(n), &ans) t.Errorf("SymDense times Cholesky inverse not identity. Norm diff = %v", Norm(&diff, 2)) } } } func TestCholeskySymRankOne(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 4, 5, 7, 10, 20, 50, 100} { for k := 0; k < 50; k++ { // Construct a random positive definite matrix. data := make([]float64, n*n) for i := range data { data[i] = rnd.NormFloat64() } var a SymDense a.SymOuterK(1, NewDense(n, n, data)) // Construct random data for updating. xdata := make([]float64, n) for i := range xdata { xdata[i] = rnd.NormFloat64() } x := NewVecDense(n, xdata) alpha := rnd.NormFloat64() // Compute the updated matrix directly. If alpha > 0, there are no // issues. If alpha < 0, it could be that the final matrix is not // positive definite, so instead switch the two matrices. aUpdate := NewSymDense(n, nil) if alpha > 0 { aUpdate.SymRankOne(&a, alpha, x) } else { aUpdate.CopySym(&a) a.Reset() a.SymRankOne(aUpdate, -alpha, x) } // Compare the Cholesky decomposition computed with Cholesky.SymRankOne // with that computed from updating A directly. var chol Cholesky ok := chol.Factorize(&a) if !ok { t.Errorf("Bad random test, Cholesky factorization failed") continue } var cholUpdate Cholesky ok = cholUpdate.SymRankOne(&chol, alpha, x) if !ok { t.Errorf("n=%v, alpha=%v: unexpected failure", n, alpha) continue } var aCompare SymDense cholUpdate.ToSym(&aCompare) if !EqualApprox(&aCompare, aUpdate, 1e-13) { t.Errorf("n=%v, alpha=%v: mismatch between updated matrix and from Cholesky:\nupdated:\n%v\nfrom Cholesky:\n%v", n, alpha, Formatted(aUpdate), Formatted(&aCompare)) } } } for i, test := range []struct { a *SymDense alpha float64 x []float64 wantOk bool }{ { // Update (to positive definite matrix). a: NewSymDense(4, []float64{ 1, 1, 1, 1, 0, 2, 3, 4, 0, 0, 6, 10, 0, 0, 0, 20, }), alpha: 1, x: []float64{0, 0, 0, 1}, wantOk: true, }, { // Downdate to singular matrix. a: NewSymDense(4, []float64{ 1, 1, 1, 1, 0, 2, 3, 4, 0, 0, 6, 10, 0, 0, 0, 20, }), alpha: -1, x: []float64{0, 0, 0, 1}, wantOk: false, }, { // Downdate to positive definite matrix. a: NewSymDense(4, []float64{ 1, 1, 1, 1, 0, 2, 3, 4, 0, 0, 6, 10, 0, 0, 0, 20, }), alpha: -0.5, x: []float64{0, 0, 0, 1}, wantOk: true, }, { // Issue #453. a: NewSymDense(1, []float64{1}), alpha: -1, x: []float64{0.25}, wantOk: true, }, } { var chol Cholesky ok := chol.Factorize(test.a) if !ok { t.Errorf("Case %v: bad test, Cholesky factorization failed", i) continue } x := NewVecDense(len(test.x), test.x) ok = chol.SymRankOne(&chol, test.alpha, x) if !ok { if test.wantOk { t.Errorf("Case %v: unexpected failure from SymRankOne", i) } continue } if ok && !test.wantOk { t.Errorf("Case %v: expected a failure from SymRankOne", i) } a := test.a a.SymRankOne(a, test.alpha, x) var achol SymDense chol.ToSym(&achol) if !EqualApprox(&achol, a, 1e-13) { t.Errorf("Case %v: mismatch between updated matrix and from Cholesky:\nupdated:\n%v\nfrom Cholesky:\n%v", i, Formatted(a), Formatted(&achol)) } } } func TestCholeskyExtendVecSym(t *testing.T) { t.Parallel() for cas, test := range []struct { a *SymDense }{ { a: NewSymDense(3, []float64{ 4, 1, 1, 0, 2, 3, 0, 0, 6, }), }, } { n := test.a.SymmetricDim() as := test.a.sliceSym(0, n-1) // Compute the full factorization to use later (do the full factorization // first to ensure the matrix is positive definite). var cholFull Cholesky ok := cholFull.Factorize(test.a) if !ok { panic("mat: bad test, matrix not positive definite") } var chol Cholesky ok = chol.Factorize(as) if !ok { panic("mat: bad test, subset is not positive definite") } row := NewVecDense(n, nil) for i := 0; i < n; i++ { row.SetVec(i, test.a.At(n-1, i)) } var cholNew Cholesky ok = cholNew.ExtendVecSym(&chol, row) if !ok { t.Errorf("cas %v: update not positive definite", cas) } var a SymDense cholNew.ToSym(&a) if !EqualApprox(&a, test.a, 1e-12) { t.Errorf("cas %v: mismatch", cas) } // test in-place ok = chol.ExtendVecSym(&chol, row) if !ok { t.Errorf("cas %v: in-place update not positive definite", cas) } if !equalChol(&chol, &cholNew) { t.Errorf("cas %v: Cholesky different in-place vs. new", cas) } // Test that the factorization is about right compared with the direct // full factorization. Use a high tolerance on the condition number // since the condition number with the updated rule is approximate. if !equalApproxChol(&chol, &cholFull, 1e-12, 0.3) { t.Errorf("cas %v: updated Cholesky does not match full", cas) } } } func TestCholeskyScale(t *testing.T) { t.Parallel() for cas, test := range []struct { a *SymDense f float64 }{ { a: NewSymDense(3, []float64{ 4, 1, 1, 0, 2, 3, 0, 0, 6, }), f: 0.5, }, } { var chol Cholesky ok := chol.Factorize(test.a) if !ok { t.Errorf("Case %v: bad test, Cholesky factorization failed", cas) continue } // Compare the update to a new Cholesky to an update in-place. var cholUpdate Cholesky cholUpdate.Scale(test.f, &chol) chol.Scale(test.f, &chol) if !equalChol(&chol, &cholUpdate) { t.Errorf("Case %d: cholesky mismatch new receiver", cas) } var sym SymDense chol.ToSym(&sym) var comp SymDense comp.ScaleSym(test.f, test.a) if !EqualApprox(&comp, &sym, 1e-14) { t.Errorf("Case %d: cholesky reconstruction doesn't match scaled matrix", cas) } var cholTest Cholesky cholTest.Factorize(&comp) if !equalApproxChol(&cholTest, &chol, 1e-12, 1e-12) { t.Errorf("Case %d: cholesky mismatch with scaled matrix. %v, %v", cas, cholTest.cond, chol.cond) } } } // equalApproxChol checks that the two Cholesky decompositions are equal. func equalChol(a, b *Cholesky) bool { return Equal(a.chol, b.chol) && a.cond == b.cond } // equalApproxChol checks that the two Cholesky decompositions are approximately // the same with the given tolerance on equality for the Triangular component and // condition. func equalApproxChol(a, b *Cholesky, matTol, condTol float64) bool { if !EqualApprox(a.chol, b.chol, matTol) { return false } return scalar.EqualWithinAbsOrRel(a.cond, b.cond, condTol, condTol) } func BenchmarkCholeskyFactorize(b *testing.B) { for _, n := range []int{10, 100, 1000} { b.Run("n="+strconv.Itoa(n), func(b *testing.B) { rnd := rand.New(rand.NewSource(1)) data := make([]float64, n*n) for i := range data { data[i] = rnd.NormFloat64() } var a SymDense a.SymOuterK(1, NewDense(n, n, data)) var chol Cholesky b.ResetTimer() for i := 0; i < b.N; i++ { ok := chol.Factorize(&a) if !ok { panic("not positive definite") } } }) } } func BenchmarkCholeskyToSym(b *testing.B) { for _, n := range []int{10, 100, 1000} { b.Run("n="+strconv.Itoa(n), func(b *testing.B) { rnd := rand.New(rand.NewSource(1)) data := make([]float64, n*n) for i := range data { data[i] = rnd.NormFloat64() } var a SymDense a.SymOuterK(1, NewDense(n, n, data)) var chol Cholesky ok := chol.Factorize(&a) if !ok { panic("not positive definite") } dst := NewSymDense(n, nil) b.ResetTimer() for i := 0; i < b.N; i++ { chol.ToSym(dst) } }) } } func BenchmarkCholeskyInverseTo(b *testing.B) { for _, n := range []int{10, 100, 1000} { b.Run("n="+strconv.Itoa(n), func(b *testing.B) { rnd := rand.New(rand.NewSource(1)) data := make([]float64, n*n) for i := range data { data[i] = rnd.NormFloat64() } var a SymDense a.SymOuterK(1, NewDense(n, n, data)) var chol Cholesky ok := chol.Factorize(&a) if !ok { panic("not positive definite") } dst := NewSymDense(n, nil) b.ResetTimer() for i := 0; i < b.N; i++ { err := chol.InverseTo(dst) if err != nil { b.Fatalf("unexpected error from Cholesky inverse: %v", err) } } }) } } func TestBandCholeskySolveTo(t *testing.T) { t.Parallel() const ( nrhs = 4 tol = 1e-14 ) rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 5, 10} { for _, k := range []int{0, 1, n / 2, n - 1} { k := min(k, n-1) a := NewSymBandDense(n, k, nil) for i := 0; i < n; i++ { a.SetSymBand(i, i, rnd.Float64()+float64(n)) for j := i + 1; j < min(i+k+1, n); j++ { a.SetSymBand(i, j, rnd.Float64()) } } want := NewDense(n, nrhs, nil) for i := 0; i < n; i++ { for j := 0; j < nrhs; j++ { want.Set(i, j, rnd.NormFloat64()) } } var b Dense b.Mul(a, want) for _, typ := range []SymBanded{a, (*basicSymBanded)(a)} { name := fmt.Sprintf("Case n=%d,k=%d,type=%T,nrhs=%d", n, k, typ, nrhs) var chol BandCholesky ok := chol.Factorize(typ) if !ok { t.Fatalf("%v: Factorize failed", name) } var got Dense err := chol.SolveTo(&got, &b) if err != nil { t.Errorf("%v: unexpected error from SolveTo: %v", name, err) continue } var resid Dense resid.Sub(want, &got) diff := Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution; diff=%v", name, diff) } got.Copy(&b) err = chol.SolveTo(&got, &got) if err != nil { t.Errorf("%v: unexpected error from SolveTo when dst==b: %v", name, err) continue } resid.Sub(want, &got) diff = Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution when dst==b; diff=%v", name, diff) } } } } } func TestBandCholeskySolveVecTo(t *testing.T) { t.Parallel() const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 5, 10} { for _, k := range []int{0, 1, n / 2, n - 1} { k := min(k, n-1) a := NewSymBandDense(n, k, nil) for i := 0; i < n; i++ { a.SetSymBand(i, i, rnd.Float64()+float64(n)) for j := i + 1; j < min(i+k+1, n); j++ { a.SetSymBand(i, j, rnd.Float64()) } } want := NewVecDense(n, nil) for i := 0; i < n; i++ { want.SetVec(i, rnd.NormFloat64()) } var b VecDense b.MulVec(a, want) for _, typ := range []SymBanded{a, (*basicSymBanded)(a)} { name := fmt.Sprintf("Case n=%d,k=%d,type=%T", n, k, typ) var chol BandCholesky ok := chol.Factorize(typ) if !ok { t.Fatalf("%v: Factorize failed", name) } var got VecDense err := chol.SolveVecTo(&got, &b) if err != nil { t.Errorf("%v: unexpected error from SolveVecTo: %v", name, err) continue } var resid VecDense resid.SubVec(want, &got) diff := Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution; diff=%v", name, diff) } got.CopyVec(&b) err = chol.SolveVecTo(&got, &got) if err != nil { t.Errorf("%v: unexpected error from SolveVecTo when dst==b: %v", name, err) continue } resid.SubVec(want, &got) diff = Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution when dst==b; diff=%v", name, diff) } } } } } func TestBandCholeskyAt(t *testing.T) { t.Parallel() const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 5, 10} { for _, k := range []int{0, 1, n / 2, n - 1} { k := min(k, n-1) name := fmt.Sprintf("Case n=%d,k=%d", n, k) a := NewSymBandDense(n, k, nil) for i := 0; i < n; i++ { a.SetSymBand(i, i, rnd.Float64()+float64(n)) for j := i + 1; j < min(i+k+1, n); j++ { a.SetSymBand(i, j, rnd.Float64()) } } var chol BandCholesky ok := chol.Factorize(a) if !ok { t.Fatalf("%v: Factorize failed", name) } resid := NewDense(n, n, nil) for i := 0; i < n; i++ { for j := 0; j < n; j++ { resid.Set(i, j, math.Abs(a.At(i, j)-chol.At(i, j))) } } diff := Norm(resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected result; diff=%v, want<=%v", name, diff, tol) } } } } func TestBandCholeskyDet(t *testing.T) { t.Parallel() const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 5, 10} { for _, k := range []int{0, 1, n / 2, n - 1} { k := min(k, n-1) name := fmt.Sprintf("Case n=%d,k=%d", n, k) a := NewSymBandDense(n, k, nil) aSym := NewSymDense(n, nil) for i := 0; i < n; i++ { aii := rnd.Float64() + float64(n) a.SetSymBand(i, i, aii) aSym.SetSym(i, i, aii) for j := i + 1; j < min(i+k+1, n); j++ { aij := rnd.Float64() a.SetSymBand(i, j, aij) aSym.SetSym(i, j, aij) } } var chol BandCholesky ok := chol.Factorize(a) if !ok { t.Fatalf("%v: Factorize failed", name) } var cholDense Cholesky ok = cholDense.Factorize(aSym) if !ok { t.Fatalf("%v: dense Factorize failed", name) } want := cholDense.Det() got := chol.Det() diff := math.Abs(got - want) if diff > tol { t.Errorf("%v: unexpected result; got=%v, want=%v (diff=%v)", name, got, want, diff) } } } } func TestPivotedCholesky(t *testing.T) { t.Parallel() const tol = 1e-14 src := rand.NewSource(1) for _, n := range []int{1, 2, 3, 4, 5, 10} { for _, rank := range []int{int(0.3 * float64(n)), int(0.7 * float64(n)), n} { name := fmt.Sprintf("n=%d, rank=%d", n, rank) // Generate a random symmetric semi-definite matrix A with the given rank. a := NewSymDense(n, nil) for i := 0; i < rank; i++ { x := randVecDense(n, 1, 1, src) a.SymRankOne(a, 1, x) } // Compute the pivoted Cholesky factorization of A. var chol PivotedCholesky ok := chol.Factorize(a, -1) // Check that the ok return matches the rank of A. if !ok && rank == n { t.Errorf("%s: unexpected factorization failure with full rank", name) } if ok && rank != n { t.Errorf("%s: unexpected factorization success with deficit rank", name) } // Check that the computed rank matches the rank of A. if chol.Rank() != rank { t.Errorf("%s: unexpected computed rank, got %d", name, chol.Rank()) } // Check the size. r, c := chol.Dims() if r != n || c != n { t.Errorf("n=%d, rank=%d: unexpected dims: r=%d, c=%d", n, rank, r, c) } if chol.SymmetricDim() != n { t.Errorf("n=%d, rank=%d: unexpected symmetric dim: dim=%d", n, rank, chol.SymmetricDim()) } // Compute the norm of the difference |P*Uᵀ*U*Pᵀ - A|. diff := NewDense(n, n, nil) for i := 0; i < n; i++ { for j := 0; j < n; j++ { diff.Set(i, j, chol.At(i, j)-a.At(i, j)) } } res := Norm(diff, 1) if res > tol { t.Errorf("n=%d, rank=%d: unexpected result (|diff|=%v)\ndiff = %.4g", n, rank, res, Formatted(diff, Prefix(" "))) } } } } func TestPivotedCholeskySolveTo(t *testing.T) { t.Parallel() const ( nrhs = 4 tol = 1e-14 ) rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 5, 10} { a := NewSymDense(n, nil) for i := 0; i < n; i++ { a.SetSym(i, i, rnd.Float64()+float64(n)) for j := i + 1; j < n; j++ { a.SetSym(i, j, rnd.Float64()) } } want := NewDense(n, nrhs, nil) for i := 0; i < n; i++ { for j := 0; j < nrhs; j++ { want.Set(i, j, rnd.NormFloat64()) } } var b Dense b.Mul(a, want) for _, typ := range []Symmetric{a, asBasicSymmetric(a)} { name := fmt.Sprintf("Case n=%d,type=%T,nrhs=%d", n, typ, nrhs) var chol PivotedCholesky ok := chol.Factorize(typ, -1) if !ok { t.Fatalf("%v: matrix not positive definite", name) } var got Dense err := chol.SolveTo(&got, &b) if err != nil { t.Errorf("%v: unexpected error from SolveTo: %v", name, err) continue } var resid Dense resid.Sub(want, &got) diff := Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution; diff=%v", name, diff) } got.Copy(&b) err = chol.SolveTo(&got, &got) if err != nil { t.Errorf("%v: unexpected error from SolveTo when dst==b: %v", name, err) continue } resid.Sub(want, &got) diff = Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution when dst==b; diff=%v", name, diff) } } } } func TestPivotedCholeskySolveVecTo(t *testing.T) { t.Parallel() const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 2, 3, 5, 10} { a := NewSymDense(n, nil) for i := 0; i < n; i++ { a.SetSym(i, i, rnd.Float64()+float64(n)) for j := i + 1; j < n; j++ { a.SetSym(i, j, rnd.Float64()) } } want := NewVecDense(n, nil) for i := 0; i < n; i++ { want.SetVec(i, rnd.NormFloat64()) } var b VecDense b.MulVec(a, want) for _, typ := range []Symmetric{a, asBasicSymmetric(a)} { name := fmt.Sprintf("Case n=%d,type=%T", n, typ) var chol PivotedCholesky ok := chol.Factorize(typ, -1) if !ok { t.Fatalf("%v: matrix not positive definite", name) } var got VecDense err := chol.SolveVecTo(&got, &b) if err != nil { t.Errorf("%v: unexpected error from SolveVecTo: %v", name, err) continue } var resid VecDense resid.SubVec(want, &got) diff := Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution; diff=%v", name, diff) } got.CopyVec(&b) err = chol.SolveVecTo(&got, &got) if err != nil { t.Errorf("%v: unexpected error from SolveVecTo when dst==b: %v", name, err) continue } resid.SubVec(want, &got) diff = Norm(&resid, math.Inf(1)) if diff > tol { t.Errorf("%v: unexpected solution when dst==b; diff=%v", name, diff) } } } } golang-gonum-v1-gonum-0.14.0/mat/cmatrix.go000066400000000000000000000222361450372207100204220ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "math/cmplx" "gonum.org/v1/gonum/blas/cblas128" "gonum.org/v1/gonum/floats/scalar" ) // CMatrix is the basic matrix interface type for complex matrices. type CMatrix interface { // Dims returns the dimensions of a CMatrix. Dims() (r, c int) // At returns the value of a matrix element at row i, column j. // It will panic if i or j are out of bounds for the matrix. At(i, j int) complex128 // H returns the conjugate transpose of the CMatrix. Whether H // returns a copy of the underlying data is implementation dependent. // This method may be implemented using the ConjTranspose type, which // provides an implicit matrix conjugate transpose. H() CMatrix // T returns the transpose of the CMatrix. Whether T returns a copy of the // underlying data is implementation dependent. // This method may be implemented using the CTranspose type, which // provides an implicit matrix transpose. T() CMatrix } // A RawCMatrixer can return a cblas128.General representation of the receiver. Changes to the cblas128.General.Data // slice will be reflected in the original matrix, changes to the Rows, Cols and Stride fields will not. type RawCMatrixer interface { RawCMatrix() cblas128.General } var ( _ CMatrix = ConjTranspose{} _ UnConjTransposer = ConjTranspose{} ) // ConjTranspose is a type for performing an implicit matrix conjugate transpose. // It implements the CMatrix interface, returning values from the conjugate // transpose of the matrix within. type ConjTranspose struct { CMatrix CMatrix } // At returns the value of the element at row i and column j of the conjugate // transposed matrix, that is, row j and column i of the CMatrix field. func (t ConjTranspose) At(i, j int) complex128 { z := t.CMatrix.At(j, i) return cmplx.Conj(z) } // Dims returns the dimensions of the transposed matrix. The number of rows returned // is the number of columns in the CMatrix field, and the number of columns is // the number of rows in the CMatrix field. func (t ConjTranspose) Dims() (r, c int) { c, r = t.CMatrix.Dims() return r, c } // H performs an implicit conjugate transpose by returning the CMatrix field. func (t ConjTranspose) H() CMatrix { return t.CMatrix } // T performs an implicit transpose by returning the receiver inside a // CTranspose. func (t ConjTranspose) T() CMatrix { return CTranspose{t} } // UnConjTranspose returns the CMatrix field. func (t ConjTranspose) UnConjTranspose() CMatrix { return t.CMatrix } // CTranspose is a type for performing an implicit matrix conjugate transpose. // It implements the CMatrix interface, returning values from the conjugate // transpose of the matrix within. type CTranspose struct { CMatrix CMatrix } // At returns the value of the element at row i and column j of the conjugate // transposed matrix, that is, row j and column i of the CMatrix field. func (t CTranspose) At(i, j int) complex128 { return t.CMatrix.At(j, i) } // Dims returns the dimensions of the transposed matrix. The number of rows returned // is the number of columns in the CMatrix field, and the number of columns is // the number of rows in the CMatrix field. func (t CTranspose) Dims() (r, c int) { c, r = t.CMatrix.Dims() return r, c } // H performs an implicit transpose by returning the receiver inside a // ConjTranspose. func (t CTranspose) H() CMatrix { return ConjTranspose{t} } // T performs an implicit conjugate transpose by returning the CMatrix field. func (t CTranspose) T() CMatrix { return t.CMatrix } // Untranspose returns the CMatrix field. func (t CTranspose) Untranspose() CMatrix { return t.CMatrix } // UnConjTransposer is a type that can undo an implicit conjugate transpose. type UnConjTransposer interface { // UnConjTranspose returns the underlying CMatrix stored for the implicit // conjugate transpose. UnConjTranspose() CMatrix // Note: This interface is needed to unify all of the Conjugate types. In // the cmat128 methods, we need to test if the CMatrix has been implicitly // transposed. If this is checked by testing for the specific Conjugate type // then the behavior will be different if the user uses H() or HTri() for a // triangular matrix. } // CUntransposer is a type that can undo an implicit transpose. type CUntransposer interface { // Untranspose returns the underlying CMatrix stored for the implicit // transpose. Untranspose() CMatrix // Note: This interface is needed to unify all of the CTranspose types. In // the cmat128 methods, we need to test if the CMatrix has been implicitly // transposed. If this is checked by testing for the specific CTranspose type // then the behavior will be different if the user uses T() or TTri() for a // triangular matrix. } // useC returns a complex128 slice with l elements, using c if it // has the necessary capacity, otherwise creating a new slice. func useC(c []complex128, l int) []complex128 { if l <= cap(c) { return c[:l] } return make([]complex128, l) } // useZeroedC returns a complex128 slice with l elements, using c if it // has the necessary capacity, otherwise creating a new slice. The // elements of the returned slice are guaranteed to be zero. func useZeroedC(c []complex128, l int) []complex128 { if l <= cap(c) { c = c[:l] zeroC(c) return c } return make([]complex128, l) } // zeroC zeros the given slice's elements. func zeroC(c []complex128) { for i := range c { c[i] = 0 } } // untransposeCmplx untransposes a matrix if applicable. If a is an CUntransposer // or an UnConjTransposer, then untranspose returns the underlying matrix and true for // the kind of transpose (potentially both). // If it is not, then it returns the input matrix and false for trans and conj. func untransposeCmplx(a CMatrix) (u CMatrix, trans, conj bool) { switch ut := a.(type) { case CUntransposer: trans = true u := ut.Untranspose() if uc, ok := u.(UnConjTransposer); ok { return uc.UnConjTranspose(), trans, true } return u, trans, false case UnConjTransposer: conj = true u := ut.UnConjTranspose() if ut, ok := u.(CUntransposer); ok { return ut.Untranspose(), true, conj } return u, false, conj default: return a, false, false } } // untransposeExtractCmplx returns an untransposed matrix in a built-in matrix type. // // The untransposed matrix is returned unaltered if it is a built-in matrix type. // Otherwise, if it implements a Raw method, an appropriate built-in type value // is returned holding the raw matrix value of the input. If neither of these // is possible, the untransposed matrix is returned. func untransposeExtractCmplx(a CMatrix) (u CMatrix, trans, conj bool) { ut, trans, conj := untransposeCmplx(a) switch m := ut.(type) { case *CDense: return m, trans, conj case RawCMatrixer: var d CDense d.SetRawCMatrix(m.RawCMatrix()) return &d, trans, conj default: return ut, trans, conj } } // CEqual returns whether the matrices a and b have the same size // and are element-wise equal. func CEqual(a, b CMatrix) bool { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { return false } // TODO(btracey): Add in fast-paths. for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.At(i, j) != b.At(i, j) { return false } } } return true } // CEqualApprox returns whether the matrices a and b have the same size and contain all equal // elements with tolerance for element-wise equality specified by epsilon. Matrices // with non-equal shapes are not equal. func CEqualApprox(a, b CMatrix, epsilon float64) bool { // TODO(btracey): ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if !cEqualWithinAbsOrRel(a.At(i, j), b.At(i, j), epsilon, epsilon) { return false } } } return true } // TODO(btracey): Move these into a cmplxs if/when we have one. func cEqualWithinAbsOrRel(a, b complex128, absTol, relTol float64) bool { if cEqualWithinAbs(a, b, absTol) { return true } return cEqualWithinRel(a, b, relTol) } // cEqualWithinAbs returns true if a and b have an absolute // difference of less than tol. func cEqualWithinAbs(a, b complex128, tol float64) bool { return a == b || cmplx.Abs(a-b) <= tol } const minNormalFloat64 = 2.2250738585072014e-308 // cEqualWithinRel returns true if the difference between a and b // is not greater than tol times the greater value. func cEqualWithinRel(a, b complex128, tol float64) bool { if a == b { return true } if cmplx.IsNaN(a) || cmplx.IsNaN(b) { return false } // Cannot play the same trick as in floats/scalar because there are multiple // possible infinities. if cmplx.IsInf(a) { if !cmplx.IsInf(b) { return false } ra := real(a) if math.IsInf(ra, 0) { if ra == real(b) { return scalar.EqualWithinRel(imag(a), imag(b), tol) } return false } if imag(a) == imag(b) { return scalar.EqualWithinRel(ra, real(b), tol) } return false } if cmplx.IsInf(b) { return false } delta := cmplx.Abs(a - b) if delta <= minNormalFloat64 { return delta <= tol*minNormalFloat64 } return delta/math.Max(cmplx.Abs(a), cmplx.Abs(b)) <= tol } golang-gonum-v1-gonum-0.14.0/mat/consts.go000066400000000000000000000006221450372207100202570ustar00rootroot00000000000000// Copyright ©2016 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat // TriKind represents the triangularity of the matrix. type TriKind bool const ( // Upper specifies an upper triangular matrix. Upper TriKind = true // Lower specifies a lower triangular matrix. Lower TriKind = false ) golang-gonum-v1-gonum-0.14.0/mat/dense.go000066400000000000000000000374371450372207100200620ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) var ( dense *Dense _ Matrix = dense _ allMatrix = dense _ denseMatrix = dense _ Mutable = dense _ ClonerFrom = dense _ RowViewer = dense _ ColViewer = dense _ RawRowViewer = dense _ Grower = dense _ RawMatrixSetter = dense _ RawMatrixer = dense _ Reseter = dense ) // Dense is a dense matrix representation. type Dense struct { mat blas64.General capRows, capCols int } // NewDense creates a new Dense matrix with r rows and c columns. If data == nil, // a new slice is allocated for the backing slice. If len(data) == r*c, data is // used as the backing slice, and changes to the elements of the returned Dense // will be reflected in data. If neither of these is true, NewDense will panic. // NewDense will panic if either r or c is zero. // // The data must be arranged in row-major order, i.e. the (i*c + j)-th // element in the data slice is the {i, j}-th element in the matrix. func NewDense(r, c int, data []float64) *Dense { if r <= 0 || c <= 0 { if r == 0 || c == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if data != nil && r*c != len(data) { panic(ErrShape) } if data == nil { data = make([]float64, r*c) } return &Dense{ mat: blas64.General{ Rows: r, Cols: c, Stride: c, Data: data, }, capRows: r, capCols: c, } } // ReuseAs changes the receiver if it IsEmpty() to be of size r×c. // // ReuseAs re-uses the backing data slice if it has sufficient capacity, // otherwise a new slice is allocated. The backing data is zero on return. // // ReuseAs panics if the receiver is not empty, and panics if // the input sizes are less than one. To empty the receiver for re-use, // Reset should be used. func (m *Dense) ReuseAs(r, c int) { if r <= 0 || c <= 0 { if r == 0 || c == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if !m.IsEmpty() { panic(ErrReuseNonEmpty) } m.reuseAsZeroed(r, c) } // reuseAsNonZeroed resizes an empty matrix to a r×c matrix, // or checks that a non-empty matrix is r×c. It does not zero // the data in the receiver. func (m *Dense) reuseAsNonZeroed(r, c int) { // reuseAs must be kept in sync with reuseAsZeroed. if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols { // Panic as a string, not a mat.Error. panic(badCap) } if r == 0 || c == 0 { panic(ErrZeroLength) } if m.IsEmpty() { m.mat = blas64.General{ Rows: r, Cols: c, Stride: c, Data: use(m.mat.Data, r*c), } m.capRows = r m.capCols = c return } if r != m.mat.Rows || c != m.mat.Cols { panic(ErrShape) } } // reuseAsZeroed resizes an empty matrix to a r×c matrix, // or checks that a non-empty matrix is r×c. It zeroes // all the elements of the matrix. func (m *Dense) reuseAsZeroed(r, c int) { // reuseAsZeroed must be kept in sync with reuseAsNonZeroed. if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols { // Panic as a string, not a mat.Error. panic(badCap) } if r == 0 || c == 0 { panic(ErrZeroLength) } if m.IsEmpty() { m.mat = blas64.General{ Rows: r, Cols: c, Stride: c, Data: useZeroed(m.mat.Data, r*c), } m.capRows = r m.capCols = c return } if r != m.mat.Rows || c != m.mat.Cols { panic(ErrShape) } m.Zero() } // Zero sets all of the matrix elements to zero. func (m *Dense) Zero() { r := m.mat.Rows c := m.mat.Cols for i := 0; i < r; i++ { zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]) } } // isolatedWorkspace returns a new dense matrix w with the size of a and // returns a callback to defer which performs cleanup at the return of the call. // This should be used when a method receiver is the same pointer as an input argument. func (m *Dense) isolatedWorkspace(a Matrix) (w *Dense, restore func()) { r, c := a.Dims() if r == 0 || c == 0 { panic(ErrZeroLength) } w = getDenseWorkspace(r, c, false) return w, func() { m.Copy(w) putDenseWorkspace(w) } } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (m *Dense) Reset() { // Row, Cols and Stride must be zeroed in unison. m.mat.Rows, m.mat.Cols, m.mat.Stride = 0, 0, 0 m.capRows, m.capCols = 0, 0 m.mat.Data = m.mat.Data[:0] } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (m *Dense) IsEmpty() bool { // It must be the case that m.Dims() returns // zeros in this case. See comment in Reset(). return m.mat.Stride == 0 } // asTriDense returns a TriDense with the given size and side. The backing data // of the TriDense is the same as the receiver. func (m *Dense) asTriDense(n int, diag blas.Diag, uplo blas.Uplo) *TriDense { return &TriDense{ mat: blas64.Triangular{ N: n, Stride: m.mat.Stride, Data: m.mat.Data, Uplo: uplo, Diag: diag, }, cap: n, } } // DenseCopyOf returns a newly allocated copy of the elements of a. func DenseCopyOf(a Matrix) *Dense { d := &Dense{} d.CloneFrom(a) return d } // SetRawMatrix sets the underlying blas64.General used by the receiver. // Changes to elements in the receiver following the call will be reflected // in b. func (m *Dense) SetRawMatrix(b blas64.General) { m.capRows, m.capCols = b.Rows, b.Cols m.mat = b } // RawMatrix returns the underlying blas64.General used by the receiver. // Changes to elements in the receiver following the call will be reflected // in returned blas64.General. func (m *Dense) RawMatrix() blas64.General { return m.mat } // Dims returns the number of rows and columns in the matrix. func (m *Dense) Dims() (r, c int) { return m.mat.Rows, m.mat.Cols } // Caps returns the number of rows and columns in the backing matrix. func (m *Dense) Caps() (r, c int) { return m.capRows, m.capCols } // T performs an implicit transpose by returning the receiver inside a Transpose. func (m *Dense) T() Matrix { return Transpose{m} } // ColView returns a Vector reflecting the column j, backed by the matrix data. // // See ColViewer for more information. func (m *Dense) ColView(j int) Vector { var v VecDense v.ColViewOf(m, j) return &v } // SetCol sets the values in the specified column of the matrix to the values // in src. len(src) must equal the number of rows in the receiver. func (m *Dense) SetCol(j int, src []float64) { if j >= m.mat.Cols || j < 0 { panic(ErrColAccess) } if len(src) != m.mat.Rows { panic(ErrColLength) } blas64.Copy( blas64.Vector{N: m.mat.Rows, Inc: 1, Data: src}, blas64.Vector{N: m.mat.Rows, Inc: m.mat.Stride, Data: m.mat.Data[j:]}, ) } // SetRow sets the values in the specified rows of the matrix to the values // in src. len(src) must equal the number of columns in the receiver. func (m *Dense) SetRow(i int, src []float64) { if i >= m.mat.Rows || i < 0 { panic(ErrRowAccess) } if len(src) != m.mat.Cols { panic(ErrRowLength) } copy(m.rawRowView(i), src) } // RowView returns row i of the matrix data represented as a column vector, // backed by the matrix data. // // See RowViewer for more information. func (m *Dense) RowView(i int) Vector { var v VecDense v.RowViewOf(m, i) return &v } // RawRowView returns a slice backed by the same array as backing the // receiver. func (m *Dense) RawRowView(i int) []float64 { if i >= m.mat.Rows || i < 0 { panic(ErrRowAccess) } return m.rawRowView(i) } func (m *Dense) rawRowView(i int) []float64 { return m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+m.mat.Cols] } // DiagView returns the diagonal as a matrix backed by the original data. func (m *Dense) DiagView() Diagonal { n := min(m.mat.Rows, m.mat.Cols) return &DiagDense{ mat: blas64.Vector{ N: n, Inc: m.mat.Stride + 1, Data: m.mat.Data[:(n-1)*m.mat.Stride+n], }, } } // Slice returns a new Matrix that shares backing data with the receiver. // The returned matrix starts at {i,j} of the receiver and extends k-i rows // and l-j columns. The final row in the resulting matrix is k-1 and the // final column is l-1. // Slice panics with ErrIndexOutOfRange if the slice is outside the capacity // of the receiver. func (m *Dense) Slice(i, k, j, l int) Matrix { return m.slice(i, k, j, l) } func (m *Dense) slice(i, k, j, l int) *Dense { mr, mc := m.Caps() if i < 0 || mr <= i || j < 0 || mc <= j || k < i || mr < k || l < j || mc < l { if i == k || j == l { panic(ErrZeroLength) } panic(ErrIndexOutOfRange) } t := *m t.mat.Data = t.mat.Data[i*t.mat.Stride+j : (k-1)*t.mat.Stride+l] t.mat.Rows = k - i t.mat.Cols = l - j t.capRows -= i t.capCols -= j return &t } // Grow returns the receiver expanded by r rows and c columns. If the dimensions // of the expanded matrix are outside the capacities of the receiver a new // allocation is made, otherwise not. Note the receiver itself is not modified // during the call to Grow. func (m *Dense) Grow(r, c int) Matrix { if r < 0 || c < 0 { panic(ErrIndexOutOfRange) } if r == 0 && c == 0 { return m } r += m.mat.Rows c += m.mat.Cols var t Dense switch { case m.mat.Rows == 0 || m.mat.Cols == 0: t.mat = blas64.General{ Rows: r, Cols: c, Stride: c, // We zero because we don't know how the matrix will be used. // In other places, the mat is immediately filled with a result; // this is not the case here. Data: useZeroed(m.mat.Data, r*c), } case r > m.capRows || c > m.capCols: cr := max(r, m.capRows) cc := max(c, m.capCols) t.mat = blas64.General{ Rows: r, Cols: c, Stride: cc, Data: make([]float64, cr*cc), } t.capRows = cr t.capCols = cc // Copy the complete matrix over to the new matrix. // Including elements not currently visible. Use a temporary structure // to avoid modifying the receiver. var tmp Dense tmp.mat = blas64.General{ Rows: m.mat.Rows, Cols: m.mat.Cols, Stride: m.mat.Stride, Data: m.mat.Data, } tmp.capRows = m.capRows tmp.capCols = m.capCols t.Copy(&tmp) return &t default: t.mat = blas64.General{ Data: m.mat.Data[:(r-1)*m.mat.Stride+c], Rows: r, Cols: c, Stride: m.mat.Stride, } } t.capRows = r t.capCols = c return &t } // CloneFrom makes a copy of a into the receiver, overwriting the previous value of // the receiver. The clone from operation does not make any restriction on shape and // will not cause shadowing. // // See the ClonerFrom interface for more information. func (m *Dense) CloneFrom(a Matrix) { r, c := a.Dims() mat := blas64.General{ Rows: r, Cols: c, Stride: c, } m.capRows, m.capCols = r, c aU, trans := untransposeExtract(a) switch aU := aU.(type) { case *Dense: amat := aU.mat mat.Data = make([]float64, r*c) if trans { for i := 0; i < r; i++ { blas64.Copy(blas64.Vector{N: c, Inc: amat.Stride, Data: amat.Data[i : i+(c-1)*amat.Stride+1]}, blas64.Vector{N: c, Inc: 1, Data: mat.Data[i*c : (i+1)*c]}) } } else { for i := 0; i < r; i++ { copy(mat.Data[i*c:(i+1)*c], amat.Data[i*amat.Stride:i*amat.Stride+c]) } } case *VecDense: amat := aU.mat mat.Data = make([]float64, aU.mat.N) blas64.Copy(blas64.Vector{N: aU.mat.N, Inc: amat.Inc, Data: amat.Data}, blas64.Vector{N: aU.mat.N, Inc: 1, Data: mat.Data}) default: mat.Data = make([]float64, r*c) w := *m w.mat = mat for i := 0; i < r; i++ { for j := 0; j < c; j++ { w.set(i, j, a.At(i, j)) } } *m = w return } m.mat = mat } // Copy makes a copy of elements of a into the receiver. It is similar to the // built-in copy; it copies as much as the overlap between the two matrices and // returns the number of rows and columns it copied. If a aliases the receiver // and is a transposed Dense or VecDense, with a non-unitary increment, Copy will // panic. // // See the Copier interface for more information. func (m *Dense) Copy(a Matrix) (r, c int) { r, c = a.Dims() if a == m { return r, c } r = min(r, m.mat.Rows) c = min(c, m.mat.Cols) if r == 0 || c == 0 { return 0, 0 } aU, trans := untransposeExtract(a) switch aU := aU.(type) { case *Dense: amat := aU.mat if trans { if amat.Stride != 1 { m.checkOverlap(amat) } for i := 0; i < r; i++ { blas64.Copy(blas64.Vector{N: c, Inc: amat.Stride, Data: amat.Data[i : i+(c-1)*amat.Stride+1]}, blas64.Vector{N: c, Inc: 1, Data: m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]}) } } else { switch o := offset(m.mat.Data, amat.Data); { case o < 0: for i := r - 1; i >= 0; i-- { copy(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], amat.Data[i*amat.Stride:i*amat.Stride+c]) } case o > 0: for i := 0; i < r; i++ { copy(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], amat.Data[i*amat.Stride:i*amat.Stride+c]) } default: // Nothing to do. } } case *VecDense: var n, stride int amat := aU.mat if trans { if amat.Inc != 1 { m.checkOverlap(aU.asGeneral()) } n = c stride = 1 } else { n = r stride = m.mat.Stride } if amat.Inc == 1 && stride == 1 { copy(m.mat.Data, amat.Data[:n]) break } switch o := offset(m.mat.Data, amat.Data); { case o < 0: blas64.Copy(blas64.Vector{N: n, Inc: -amat.Inc, Data: amat.Data}, blas64.Vector{N: n, Inc: -stride, Data: m.mat.Data}) case o > 0: blas64.Copy(blas64.Vector{N: n, Inc: amat.Inc, Data: amat.Data}, blas64.Vector{N: n, Inc: stride, Data: m.mat.Data}) default: // Nothing to do. } default: m.checkOverlapMatrix(aU) for i := 0; i < r; i++ { for j := 0; j < c; j++ { m.set(i, j, a.At(i, j)) } } } return r, c } // Stack appends the rows of b onto the rows of a, placing the result into the // receiver with b placed in the greater indexed rows. Stack will panic if the // two input matrices do not have the same number of columns or the constructed // stacked matrix is not the same shape as the receiver. func (m *Dense) Stack(a, b Matrix) { ar, ac := a.Dims() br, bc := b.Dims() if ac != bc || m == a || m == b { panic(ErrShape) } m.reuseAsNonZeroed(ar+br, ac) m.Copy(a) w := m.slice(ar, ar+br, 0, bc) w.Copy(b) } // Augment creates the augmented matrix of a and b, where b is placed in the // greater indexed columns. Augment will panic if the two input matrices do // not have the same number of rows or the constructed augmented matrix is // not the same shape as the receiver. func (m *Dense) Augment(a, b Matrix) { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || m == a || m == b { panic(ErrShape) } m.reuseAsNonZeroed(ar, ac+bc) m.Copy(a) w := m.slice(0, br, ac, ac+bc) w.Copy(b) } // Trace returns the trace of the matrix. // // Trace will panic with ErrSquare if the matrix is not square and with // ErrZeroLength if the matrix has zero size. func (m *Dense) Trace() float64 { r, c := m.Dims() if r != c { panic(ErrSquare) } if m.IsEmpty() { panic(ErrZeroLength) } // TODO(btracey): could use internal asm sum routine. var v float64 for i := 0; i < m.mat.Rows; i++ { v += m.mat.Data[i*m.mat.Stride+i] } return v } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrShape if the matrix has zero size. func (m *Dense) Norm(norm float64) float64 { if m.IsEmpty() { panic(ErrZeroLength) } lnorm := normLapack(norm, false) if lnorm == lapack.MaxColumnSum { work := getFloat64s(m.mat.Cols, false) defer putFloat64s(work) return lapack64.Lange(lnorm, m.mat, work) } return lapack64.Lange(lnorm, m.mat, nil) } golang-gonum-v1-gonum-0.14.0/mat/dense_arithmetic.go000066400000000000000000000500301450372207100222530ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack/lapack64" ) // Add adds a and b element-wise, placing the result in the receiver. Add // will panic if the two matrices do not have the same shape. func (m *Dense) Add(a, b Matrix) { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { panic(ErrShape) } aU, aTrans := untransposeExtract(a) bU, bTrans := untransposeExtract(b) m.reuseAsNonZeroed(ar, ac) if arm, ok := a.(*Dense); ok { if brm, ok := b.(*Dense); ok { amat, bmat := arm.mat, brm.mat if m != aU { m.checkOverlap(amat) } if m != bU { m.checkOverlap(bmat) } for ja, jb, jm := 0, 0, 0; ja < ar*amat.Stride; ja, jb, jm = ja+amat.Stride, jb+bmat.Stride, jm+m.mat.Stride { for i, v := range amat.Data[ja : ja+ac] { m.mat.Data[i+jm] = v + bmat.Data[i+jb] } } return } } m.checkOverlapMatrix(aU) m.checkOverlapMatrix(bU) var restore func() if aTrans && m == aU { m, restore = m.isolatedWorkspace(aU) defer restore() } else if bTrans && m == bU { m, restore = m.isolatedWorkspace(bU) defer restore() } for r := 0; r < ar; r++ { for c := 0; c < ac; c++ { m.set(r, c, a.At(r, c)+b.At(r, c)) } } } // Sub subtracts the matrix b from a, placing the result in the receiver. Sub // will panic if the two matrices do not have the same shape. func (m *Dense) Sub(a, b Matrix) { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { panic(ErrShape) } aU, aTrans := untransposeExtract(a) bU, bTrans := untransposeExtract(b) m.reuseAsNonZeroed(ar, ac) if arm, ok := a.(*Dense); ok { if brm, ok := b.(*Dense); ok { amat, bmat := arm.mat, brm.mat if m != aU { m.checkOverlap(amat) } if m != bU { m.checkOverlap(bmat) } for ja, jb, jm := 0, 0, 0; ja < ar*amat.Stride; ja, jb, jm = ja+amat.Stride, jb+bmat.Stride, jm+m.mat.Stride { for i, v := range amat.Data[ja : ja+ac] { m.mat.Data[i+jm] = v - bmat.Data[i+jb] } } return } } m.checkOverlapMatrix(aU) m.checkOverlapMatrix(bU) var restore func() if aTrans && m == aU { m, restore = m.isolatedWorkspace(aU) defer restore() } else if bTrans && m == bU { m, restore = m.isolatedWorkspace(bU) defer restore() } for r := 0; r < ar; r++ { for c := 0; c < ac; c++ { m.set(r, c, a.At(r, c)-b.At(r, c)) } } } // MulElem performs element-wise multiplication of a and b, placing the result // in the receiver. MulElem will panic if the two matrices do not have the same // shape. func (m *Dense) MulElem(a, b Matrix) { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { panic(ErrShape) } aU, aTrans := untransposeExtract(a) bU, bTrans := untransposeExtract(b) m.reuseAsNonZeroed(ar, ac) if arm, ok := a.(*Dense); ok { if brm, ok := b.(*Dense); ok { amat, bmat := arm.mat, brm.mat if m != aU { m.checkOverlap(amat) } if m != bU { m.checkOverlap(bmat) } for ja, jb, jm := 0, 0, 0; ja < ar*amat.Stride; ja, jb, jm = ja+amat.Stride, jb+bmat.Stride, jm+m.mat.Stride { for i, v := range amat.Data[ja : ja+ac] { m.mat.Data[i+jm] = v * bmat.Data[i+jb] } } return } } m.checkOverlapMatrix(aU) m.checkOverlapMatrix(bU) var restore func() if aTrans && m == aU { m, restore = m.isolatedWorkspace(aU) defer restore() } else if bTrans && m == bU { m, restore = m.isolatedWorkspace(bU) defer restore() } for r := 0; r < ar; r++ { for c := 0; c < ac; c++ { m.set(r, c, a.At(r, c)*b.At(r, c)) } } } // DivElem performs element-wise division of a by b, placing the result // in the receiver. DivElem will panic if the two matrices do not have the same // shape. func (m *Dense) DivElem(a, b Matrix) { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { panic(ErrShape) } aU, aTrans := untransposeExtract(a) bU, bTrans := untransposeExtract(b) m.reuseAsNonZeroed(ar, ac) if arm, ok := a.(*Dense); ok { if brm, ok := b.(*Dense); ok { amat, bmat := arm.mat, brm.mat if m != aU { m.checkOverlap(amat) } if m != bU { m.checkOverlap(bmat) } for ja, jb, jm := 0, 0, 0; ja < ar*amat.Stride; ja, jb, jm = ja+amat.Stride, jb+bmat.Stride, jm+m.mat.Stride { for i, v := range amat.Data[ja : ja+ac] { m.mat.Data[i+jm] = v / bmat.Data[i+jb] } } return } } m.checkOverlapMatrix(aU) m.checkOverlapMatrix(bU) var restore func() if aTrans && m == aU { m, restore = m.isolatedWorkspace(aU) defer restore() } else if bTrans && m == bU { m, restore = m.isolatedWorkspace(bU) defer restore() } for r := 0; r < ar; r++ { for c := 0; c < ac; c++ { m.set(r, c, a.At(r, c)/b.At(r, c)) } } } // Inverse computes the inverse of the matrix a, storing the result into the // receiver. If a is ill-conditioned, a Condition error will be returned. // Note that matrix inversion is numerically unstable, and should generally // be avoided where possible, for example by using the Solve routines. func (m *Dense) Inverse(a Matrix) error { // TODO(btracey): Special case for RawTriangular, etc. r, c := a.Dims() if r != c { panic(ErrSquare) } m.reuseAsNonZeroed(a.Dims()) aU, aTrans := untransposeExtract(a) switch rm := aU.(type) { case *Dense: if m != aU || aTrans { if m == aU || m.checkOverlap(rm.mat) { tmp := getDenseWorkspace(r, c, false) tmp.Copy(a) m.Copy(tmp) putDenseWorkspace(tmp) break } m.Copy(a) } default: m.Copy(a) } // Compute the norm of A. work := getFloat64s(4*r, false) // Length must be at least 4*r for Gecon. norm := lapack64.Lange(CondNorm, m.mat, work) // Compute the LU factorization of A. ipiv := getInts(r, false) defer putInts(ipiv) ok := lapack64.Getrf(m.mat, ipiv) if !ok { // A is exactly singular. return Condition(math.Inf(1)) } // Compute the condition number of A using the LU factorization. iwork := getInts(r, false) defer putInts(iwork) rcond := lapack64.Gecon(CondNorm, m.mat, norm, work, iwork) // Compute A^{-1} from the LU factorization regardless of the value of rcond. lapack64.Getri(m.mat, ipiv, work, -1) if int(work[0]) > len(work) { l := int(work[0]) putFloat64s(work) work = getFloat64s(l, false) } defer putFloat64s(work) ok = lapack64.Getri(m.mat, ipiv, work, len(work)) if !ok || rcond == 0 { // A is exactly singular. return Condition(math.Inf(1)) } // Check whether A is singular for computational purposes. cond := 1 / rcond if cond > ConditionTolerance { return Condition(cond) } return nil } // Mul takes the matrix product of a and b, placing the result in the receiver. // If the number of columns in a does not equal the number of rows in b, Mul will panic. func (m *Dense) Mul(a, b Matrix) { ar, ac := a.Dims() br, bc := b.Dims() if ac != br { panic(ErrShape) } aU, aTrans := untransposeExtract(a) bU, bTrans := untransposeExtract(b) m.reuseAsNonZeroed(ar, bc) var restore func() if m == aU { m, restore = m.isolatedWorkspace(aU) defer restore() } else if m == bU { m, restore = m.isolatedWorkspace(bU) defer restore() } aT := blas.NoTrans if aTrans { aT = blas.Trans } bT := blas.NoTrans if bTrans { bT = blas.Trans } // Some of the cases do not have a transpose option, so create // temporary memory. // C = Aᵀ * B = (Bᵀ * A)ᵀ // Cᵀ = Bᵀ * A. if aU, ok := aU.(*Dense); ok { if restore == nil { m.checkOverlap(aU.mat) } switch bU := bU.(type) { case *Dense: if restore == nil { m.checkOverlap(bU.mat) } blas64.Gemm(aT, bT, 1, aU.mat, bU.mat, 0, m.mat) return case *SymDense: if aTrans { c := getDenseWorkspace(ac, ar, false) blas64.Symm(blas.Left, 1, bU.mat, aU.mat, 0, c.mat) strictCopy(m, c.T()) putDenseWorkspace(c) return } blas64.Symm(blas.Right, 1, bU.mat, aU.mat, 0, m.mat) return case *TriDense: // Trmm updates in place, so copy aU first. if aTrans { c := getDenseWorkspace(ac, ar, false) var tmp Dense tmp.SetRawMatrix(aU.mat) c.Copy(&tmp) bT := blas.Trans if bTrans { bT = blas.NoTrans } blas64.Trmm(blas.Left, bT, 1, bU.mat, c.mat) strictCopy(m, c.T()) putDenseWorkspace(c) return } m.Copy(a) blas64.Trmm(blas.Right, bT, 1, bU.mat, m.mat) return case *VecDense: m.checkOverlap(bU.asGeneral()) bvec := bU.RawVector() if bTrans { // {ar,1} x {1,bc}, which is not a vector. // Instead, construct B as a General. bmat := blas64.General{ Rows: bc, Cols: 1, Stride: bvec.Inc, Data: bvec.Data, } blas64.Gemm(aT, bT, 1, aU.mat, bmat, 0, m.mat) return } cvec := blas64.Vector{ Inc: m.mat.Stride, Data: m.mat.Data, } blas64.Gemv(aT, 1, aU.mat, bvec, 0, cvec) return } } if bU, ok := bU.(*Dense); ok { if restore == nil { m.checkOverlap(bU.mat) } switch aU := aU.(type) { case *SymDense: if bTrans { c := getDenseWorkspace(bc, br, false) blas64.Symm(blas.Right, 1, aU.mat, bU.mat, 0, c.mat) strictCopy(m, c.T()) putDenseWorkspace(c) return } blas64.Symm(blas.Left, 1, aU.mat, bU.mat, 0, m.mat) return case *TriDense: // Trmm updates in place, so copy bU first. if bTrans { c := getDenseWorkspace(bc, br, false) var tmp Dense tmp.SetRawMatrix(bU.mat) c.Copy(&tmp) aT := blas.Trans if aTrans { aT = blas.NoTrans } blas64.Trmm(blas.Right, aT, 1, aU.mat, c.mat) strictCopy(m, c.T()) putDenseWorkspace(c) return } m.Copy(b) blas64.Trmm(blas.Left, aT, 1, aU.mat, m.mat) return case *VecDense: m.checkOverlap(aU.asGeneral()) avec := aU.RawVector() if aTrans { // {1,ac} x {ac, bc} // Transpose B so that the vector is on the right. cvec := blas64.Vector{ Inc: 1, Data: m.mat.Data, } bT := blas.Trans if bTrans { bT = blas.NoTrans } blas64.Gemv(bT, 1, bU.mat, avec, 0, cvec) return } // {ar,1} x {1,bc} which is not a vector result. // Instead, construct A as a General. amat := blas64.General{ Rows: ar, Cols: 1, Stride: avec.Inc, Data: avec.Data, } blas64.Gemm(aT, bT, 1, amat, bU.mat, 0, m.mat) return } } m.checkOverlapMatrix(aU) m.checkOverlapMatrix(bU) row := getFloat64s(ac, false) defer putFloat64s(row) for r := 0; r < ar; r++ { for i := range row { row[i] = a.At(r, i) } for c := 0; c < bc; c++ { var v float64 for i, e := range row { v += e * b.At(i, c) } m.mat.Data[r*m.mat.Stride+c] = v } } } // strictCopy copies a into m panicking if the shape of a and m differ. func strictCopy(m *Dense, a Matrix) { r, c := m.Copy(a) if r != m.mat.Rows || c != m.mat.Cols { // Panic with a string since this // is not a user-facing panic. panic(ErrShape.Error()) } } // Exp calculates the exponential of the matrix a, e^a, placing the result // in the receiver. Exp will panic with ErrShape if a is not square. func (m *Dense) Exp(a Matrix) { // The implementation used here is from Functions of Matrices: Theory and Computation // Chapter 10, Algorithm 10.20. https://doi.org/10.1137/1.9780898717778.ch10 r, c := a.Dims() if r != c { panic(ErrShape) } m.reuseAsNonZeroed(r, r) if r == 1 { m.mat.Data[0] = math.Exp(a.At(0, 0)) return } pade := []struct { theta float64 b []float64 }{ {theta: 0.015, b: []float64{ 120, 60, 12, 1, }}, {theta: 0.25, b: []float64{ 30240, 15120, 3360, 420, 30, 1, }}, {theta: 0.95, b: []float64{ 17297280, 8648640, 1995840, 277200, 25200, 1512, 56, 1, }}, {theta: 2.1, b: []float64{ 17643225600, 8821612800, 2075673600, 302702400, 30270240, 2162160, 110880, 3960, 90, 1, }}, } a1 := m a1.Copy(a) v := getDenseWorkspace(r, r, true) vraw := v.RawMatrix() n := r * r vvec := blas64.Vector{N: n, Inc: 1, Data: vraw.Data} defer putDenseWorkspace(v) u := getDenseWorkspace(r, r, true) uraw := u.RawMatrix() uvec := blas64.Vector{N: n, Inc: 1, Data: uraw.Data} defer putDenseWorkspace(u) a2 := getDenseWorkspace(r, r, false) defer putDenseWorkspace(a2) n1 := Norm(a, 1) for i, t := range pade { if n1 > t.theta { continue } // This loop only executes once, so // this is not as horrible as it looks. p := getDenseWorkspace(r, r, true) praw := p.RawMatrix() pvec := blas64.Vector{N: n, Inc: 1, Data: praw.Data} defer putDenseWorkspace(p) for k := 0; k < r; k++ { p.set(k, k, 1) v.set(k, k, t.b[0]) u.set(k, k, t.b[1]) } a2.Mul(a1, a1) for j := 0; j <= i; j++ { p.Mul(p, a2) blas64.Axpy(t.b[2*j+2], pvec, vvec) blas64.Axpy(t.b[2*j+3], pvec, uvec) } u.Mul(a1, u) // Use p as a workspace here and // rename u for the second call's // receiver. vmu, vpu := u, p vpu.Add(v, u) vmu.Sub(v, u) _ = m.Solve(vmu, vpu) return } // Remaining Padé table line. const theta13 = 5.4 b := [...]float64{ 64764752532480000, 32382376266240000, 7771770303897600, 1187353796428800, 129060195264000, 10559470521600, 670442572800, 33522128640, 1323241920, 40840800, 960960, 16380, 182, 1, } s := math.Log2(n1 / theta13) if s >= 0 { s = math.Ceil(s) a1.Scale(1/math.Pow(2, s), a1) } a2.Mul(a1, a1) i := getDenseWorkspace(r, r, true) for j := 0; j < r; j++ { i.set(j, j, 1) } iraw := i.RawMatrix() ivec := blas64.Vector{N: n, Inc: 1, Data: iraw.Data} defer putDenseWorkspace(i) a2raw := a2.RawMatrix() a2vec := blas64.Vector{N: n, Inc: 1, Data: a2raw.Data} a4 := getDenseWorkspace(r, r, false) a4raw := a4.RawMatrix() a4vec := blas64.Vector{N: n, Inc: 1, Data: a4raw.Data} defer putDenseWorkspace(a4) a4.Mul(a2, a2) a6 := getDenseWorkspace(r, r, false) a6raw := a6.RawMatrix() a6vec := blas64.Vector{N: n, Inc: 1, Data: a6raw.Data} defer putDenseWorkspace(a6) a6.Mul(a2, a4) // V = A_6(b_12*A_6 + b_10*A_4 + b_8*A_2) + b_6*A_6 + b_4*A_4 + b_2*A_2 +b_0*I blas64.Axpy(b[12], a6vec, vvec) blas64.Axpy(b[10], a4vec, vvec) blas64.Axpy(b[8], a2vec, vvec) v.Mul(v, a6) blas64.Axpy(b[6], a6vec, vvec) blas64.Axpy(b[4], a4vec, vvec) blas64.Axpy(b[2], a2vec, vvec) blas64.Axpy(b[0], ivec, vvec) // U = A(A_6(b_13*A_6 + b_11*A_4 + b_9*A_2) + b_7*A_6 + b_5*A_4 + b_2*A_3 +b_1*I) blas64.Axpy(b[13], a6vec, uvec) blas64.Axpy(b[11], a4vec, uvec) blas64.Axpy(b[9], a2vec, uvec) u.Mul(u, a6) blas64.Axpy(b[7], a6vec, uvec) blas64.Axpy(b[5], a4vec, uvec) blas64.Axpy(b[3], a2vec, uvec) blas64.Axpy(b[1], ivec, uvec) u.Mul(u, a1) // Use i as a workspace here and // rename u for the second call's // receiver. vmu, vpu := u, i vpu.Add(v, u) vmu.Sub(v, u) _ = m.Solve(vmu, vpu) for ; s > 0; s-- { m.Mul(m, m) } } // Pow calculates the integral power of the matrix a to n, placing the result // in the receiver. Pow will panic if n is negative or if a is not square. func (m *Dense) Pow(a Matrix, n int) { if n < 0 { panic("mat: illegal power") } r, c := a.Dims() if r != c { panic(ErrShape) } m.reuseAsNonZeroed(r, c) // Take possible fast paths. switch n { case 0: for i := 0; i < r; i++ { zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]) m.mat.Data[i*m.mat.Stride+i] = 1 } return case 1: m.Copy(a) return case 2: m.Mul(a, a) return } // Perform iterative exponentiation by squaring in work space. w := getDenseWorkspace(r, r, false) w.Copy(a) s := getDenseWorkspace(r, r, false) s.Copy(a) x := getDenseWorkspace(r, r, false) for n--; n > 0; n >>= 1 { if n&1 != 0 { x.Mul(w, s) w, x = x, w } if n != 1 { x.Mul(s, s) s, x = x, s } } m.Copy(w) putDenseWorkspace(w) putDenseWorkspace(s) putDenseWorkspace(x) } // Kronecker calculates the Kronecker product of a and b, placing the result in // the receiver. func (m *Dense) Kronecker(a, b Matrix) { ra, ca := a.Dims() rb, cb := b.Dims() m.reuseAsNonZeroed(ra*rb, ca*cb) for i := 0; i < ra; i++ { for j := 0; j < ca; j++ { m.slice(i*rb, (i+1)*rb, j*cb, (j+1)*cb).Scale(a.At(i, j), b) } } } // Scale multiplies the elements of a by f, placing the result in the receiver. // // See the Scaler interface for more information. func (m *Dense) Scale(f float64, a Matrix) { ar, ac := a.Dims() m.reuseAsNonZeroed(ar, ac) aU, aTrans := untransposeExtract(a) if rm, ok := aU.(*Dense); ok { amat := rm.mat if m == aU || m.checkOverlap(amat) { var restore func() m, restore = m.isolatedWorkspace(a) defer restore() } if !aTrans { for ja, jm := 0, 0; ja < ar*amat.Stride; ja, jm = ja+amat.Stride, jm+m.mat.Stride { for i, v := range amat.Data[ja : ja+ac] { m.mat.Data[i+jm] = v * f } } } else { for ja, jm := 0, 0; ja < ac*amat.Stride; ja, jm = ja+amat.Stride, jm+1 { for i, v := range amat.Data[ja : ja+ar] { m.mat.Data[i*m.mat.Stride+jm] = v * f } } } return } m.checkOverlapMatrix(a) for r := 0; r < ar; r++ { for c := 0; c < ac; c++ { m.set(r, c, f*a.At(r, c)) } } } // Apply applies the function fn to each of the elements of a, placing the // resulting matrix in the receiver. The function fn takes a row/column // index and element value and returns some function of that tuple. func (m *Dense) Apply(fn func(i, j int, v float64) float64, a Matrix) { ar, ac := a.Dims() m.reuseAsNonZeroed(ar, ac) aU, aTrans := untransposeExtract(a) if rm, ok := aU.(*Dense); ok { amat := rm.mat if m == aU || m.checkOverlap(amat) { var restore func() m, restore = m.isolatedWorkspace(a) defer restore() } if !aTrans { for j, ja, jm := 0, 0, 0; ja < ar*amat.Stride; j, ja, jm = j+1, ja+amat.Stride, jm+m.mat.Stride { for i, v := range amat.Data[ja : ja+ac] { m.mat.Data[i+jm] = fn(j, i, v) } } } else { for j, ja, jm := 0, 0, 0; ja < ac*amat.Stride; j, ja, jm = j+1, ja+amat.Stride, jm+1 { for i, v := range amat.Data[ja : ja+ar] { m.mat.Data[i*m.mat.Stride+jm] = fn(i, j, v) } } } return } m.checkOverlapMatrix(a) for r := 0; r < ar; r++ { for c := 0; c < ac; c++ { m.set(r, c, fn(r, c, a.At(r, c))) } } } // RankOne performs a rank-one update to the matrix a with the vectors x and // y, where x and y are treated as column vectors. The result is stored in the // receiver. The Outer method can be used instead of RankOne if a is not needed. // // m = a + alpha * x * yᵀ func (m *Dense) RankOne(a Matrix, alpha float64, x, y Vector) { ar, ac := a.Dims() if x.Len() != ar { panic(ErrShape) } if y.Len() != ac { panic(ErrShape) } if a != m { aU, _ := untransposeExtract(a) if rm, ok := aU.(*Dense); ok { m.checkOverlap(rm.RawMatrix()) } } var xmat, ymat blas64.Vector fast := true xU, _ := untransposeExtract(x) if rv, ok := xU.(*VecDense); ok { r, c := xU.Dims() xmat = rv.mat m.checkOverlap(generalFromVector(xmat, r, c)) } else { fast = false } yU, _ := untransposeExtract(y) if rv, ok := yU.(*VecDense); ok { r, c := yU.Dims() ymat = rv.mat m.checkOverlap(generalFromVector(ymat, r, c)) } else { fast = false } if fast { if m != a { m.reuseAsNonZeroed(ar, ac) m.Copy(a) } blas64.Ger(alpha, xmat, ymat, m.mat) return } m.reuseAsNonZeroed(ar, ac) for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { m.set(i, j, a.At(i, j)+alpha*x.AtVec(i)*y.AtVec(j)) } } } // Outer calculates the outer product of the vectors x and y, where x and y // are treated as column vectors, and stores the result in the receiver. // // m = alpha * x * yᵀ // // In order to update an existing matrix, see RankOne. func (m *Dense) Outer(alpha float64, x, y Vector) { r, c := x.Len(), y.Len() m.reuseAsZeroed(r, c) var xmat, ymat blas64.Vector fast := true xU, _ := untransposeExtract(x) if rv, ok := xU.(*VecDense); ok { r, c := xU.Dims() xmat = rv.mat m.checkOverlap(generalFromVector(xmat, r, c)) } else { fast = false } yU, _ := untransposeExtract(y) if rv, ok := yU.(*VecDense); ok { r, c := yU.Dims() ymat = rv.mat m.checkOverlap(generalFromVector(ymat, r, c)) } else { fast = false } if fast { for i := 0; i < r; i++ { zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]) } blas64.Ger(alpha, xmat, ymat, m.mat) return } for i := 0; i < r; i++ { for j := 0; j < c; j++ { m.set(i, j, alpha*x.AtVec(i)*y.AtVec(j)) } } } golang-gonum-v1-gonum-0.14.0/mat/dense_example_test.go000066400000000000000000000130071450372207100226170ustar00rootroot00000000000000// 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 mat_test import ( "fmt" "log" "gonum.org/v1/gonum/mat" ) func ExampleDense_Add() { // Initialize two matrices, a and b. a := mat.NewDense(2, 2, []float64{ 1, 0, 1, 0, }) b := mat.NewDense(2, 2, []float64{ 0, 1, 0, 1, }) // Add a and b, placing the result into c. // Notice that the size is automatically adjusted // when the receiver is empty (has zero size). var c mat.Dense c.Add(a, b) // Print the result using the formatter. fc := mat.Formatted(&c, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("c = %v", fc) // Output: // // c = ⎡1 1⎤ // ⎣1 1⎦ } func ExampleDense_Sub() { // Initialize two matrices, a and b. a := mat.NewDense(2, 2, []float64{ 1, 1, 1, 1, }) b := mat.NewDense(2, 2, []float64{ 1, 0, 0, 1, }) // Subtract b from a, placing the result into a. a.Sub(a, b) // Print the result using the formatter. fa := mat.Formatted(a, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("a = %v", fa) // Output: // // a = ⎡0 1⎤ // ⎣1 0⎦ } func ExampleDense_MulElem() { // Initialize two matrices, a and b. a := mat.NewDense(2, 2, []float64{ 1, 2, 3, 4, }) b := mat.NewDense(2, 2, []float64{ 1, 2, 3, 4, }) // Multiply the elements of a and b, placing the result into a. a.MulElem(a, b) // Print the result using the formatter. fa := mat.Formatted(a, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("a = %v", fa) // Output: // // a = ⎡1 4⎤ // ⎣9 16⎦ } func ExampleDense_DivElem() { // Initialize two matrices, a and b. a := mat.NewDense(2, 2, []float64{ 5, 10, 15, 20, }) b := mat.NewDense(2, 2, []float64{ 5, 5, 5, 5, }) // Divide the elements of a by b, placing the result into a. a.DivElem(a, b) // Print the result using the formatter. fa := mat.Formatted(a, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("a = %v", fa) // Output: // // a = ⎡1 2⎤ // ⎣3 4⎦ } func ExampleDense_Inverse() { // Initialize a matrix A. a := mat.NewDense(2, 2, []float64{ 2, 1, 6, 4, }) // Compute the inverse of A. var aInv mat.Dense err := aInv.Inverse(a) if err != nil { log.Fatalf("A is not invertible: %v", err) } // Print the result using the formatter. fa := mat.Formatted(&aInv, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("aInv = %.2g\n\n", fa) // Confirm that A * A^-1 = I. var I mat.Dense I.Mul(a, &aInv) fi := mat.Formatted(&I, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("I = %v\n\n", fi) // The Inverse operation, however, should typically be avoided. If the // goal is to solve a linear system // A * X = B, // then the inverse is not needed and computing the solution as // X = A^{-1} * B is slower and has worse stability properties than // solving the original problem. In this case, the SolveVec method of // VecDense (if B is a vector) or Solve method of Dense (if B is a // matrix) should be used instead of computing the Inverse of A. b := mat.NewDense(2, 2, []float64{ 2, 3, 1, 2, }) var x mat.Dense err = x.Solve(a, b) if err != nil { log.Fatalf("no solution: %v", err) } // Print the result using the formatter. fx := mat.Formatted(&x, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("x = %.1f", fx) // Output: // // aInv = ⎡ 2 -0.5⎤ // ⎣-3 1⎦ // // I = ⎡1 0⎤ // ⎣0 1⎦ // // x = ⎡ 3.5 5.0⎤ // ⎣-5.0 -7.0⎦ } func ExampleDense_Mul() { // Initialize two matrices, a and b. a := mat.NewDense(2, 2, []float64{ 4, 0, 0, 4, }) b := mat.NewDense(2, 3, []float64{ 4, 0, 0, 0, 0, 4, }) // Take the matrix product of a and b and place the result in c. var c mat.Dense c.Mul(a, b) // Print the result using the formatter. fc := mat.Formatted(&c, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("c = %v", fc) // Output: // // c = ⎡16 0 0⎤ // ⎣ 0 0 16⎦ } func ExampleDense_Exp() { // Initialize a matrix a with some data. a := mat.NewDense(2, 2, []float64{ 1, 0, 0, 1, }) // Take the exponential of the matrix and place the result in m. var m mat.Dense m.Exp(a) // Print the result using the formatter. fm := mat.Formatted(&m, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("m = %4.2f", fm) // Output: // // m = ⎡2.72 0.00⎤ // ⎣0.00 2.72⎦ } func ExampleDense_Pow() { // Initialize a matrix with some data. a := mat.NewDense(2, 2, []float64{ 4, 4, 4, 4, }) // Take the second power of matrix a and place the result in m. var m mat.Dense m.Pow(a, 2) // Print the result using the formatter. fm := mat.Formatted(&m, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("m = %v\n\n", fm) // Take the zeroth power of matrix a and place the result in n. // We expect an identity matrix of the same size as matrix a. var n mat.Dense n.Pow(a, 0) // Print the result using the formatter. fn := mat.Formatted(&n, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("n = %v", fn) // Output: // // m = ⎡32 32⎤ // ⎣32 32⎦ // // n = ⎡1 0⎤ // ⎣0 1⎦ } func ExampleDense_Scale() { // Initialize a matrix with some data. a := mat.NewDense(2, 2, []float64{ 4, 4, 4, 4, }) // Scale the matrix by a factor of 0.25 and place the result in m. var m mat.Dense m.Scale(0.25, a) // Print the result using the formatter. fm := mat.Formatted(&m, mat.Prefix(" "), mat.Squeeze()) fmt.Printf("m = %4.3f", fm) // Output: // // m = ⎡1.000 1.000⎤ // ⎣1.000 1.000⎦ } golang-gonum-v1-gonum-0.14.0/mat/dense_test.go000066400000000000000000001637071450372207100211210ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "math" "reflect" "strings" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) func TestNewDense(t *testing.T) { t.Parallel() for i, test := range []struct { a []float64 rows, cols int min, max float64 fro float64 mat *Dense }{ { []float64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 3, 3, 0, 0, 0, &Dense{ mat: blas64.General{ Rows: 3, Cols: 3, Stride: 3, Data: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0}, }, capRows: 3, capCols: 3, }, }, { []float64{ 1, 1, 1, 1, 1, 1, 1, 1, 1, }, 3, 3, 1, 1, 3, &Dense{ mat: blas64.General{ Rows: 3, Cols: 3, Stride: 3, Data: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1}, }, capRows: 3, capCols: 3, }, }, { []float64{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }, 3, 3, 0, 1, 1.7320508075688772, &Dense{ mat: blas64.General{ Rows: 3, Cols: 3, Stride: 3, Data: []float64{1, 0, 0, 0, 1, 0, 0, 0, 1}, }, capRows: 3, capCols: 3, }, }, { []float64{ -1, 0, 0, 0, -1, 0, 0, 0, -1, }, 3, 3, -1, 0, 1.7320508075688772, &Dense{ mat: blas64.General{ Rows: 3, Cols: 3, Stride: 3, Data: []float64{-1, 0, 0, 0, -1, 0, 0, 0, -1}, }, capRows: 3, capCols: 3, }, }, { []float64{ 1, 2, 3, 4, 5, 6, }, 2, 3, 1, 6, 9.539392014169458, &Dense{ mat: blas64.General{ Rows: 2, Cols: 3, Stride: 3, Data: []float64{1, 2, 3, 4, 5, 6}, }, capRows: 2, capCols: 3, }, }, { []float64{ 1, 2, 3, 4, 5, 6, }, 3, 2, 1, 6, 9.539392014169458, &Dense{ mat: blas64.General{ Rows: 3, Cols: 2, Stride: 2, Data: []float64{1, 2, 3, 4, 5, 6}, }, capRows: 3, capCols: 2, }, }, } { m := NewDense(test.rows, test.cols, test.a) rows, cols := m.Dims() if rows != test.rows { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.rows) } if cols != test.cols { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.cols) } if min := Min(m); min != test.min { t.Errorf("unexpected min for test %d: got: %v want: %v", i, min, test.min) } if max := Max(m); max != test.max { t.Errorf("unexpected max for test %d: got: %v want: %v", i, max, test.max) } if fro := Norm(m, 2); math.Abs(Norm(m, 2)-test.fro) > 1e-14 { t.Errorf("unexpected Frobenius norm for test %d: got: %v want: %v", i, fro, test.fro) } if !reflect.DeepEqual(m, test.mat) { t.Errorf("unexpected matrix for test %d", i) } if !Equal(m, test.mat) { t.Errorf("matrix does not equal expected matrix for test %d", i) } } } func TestDenseAtSet(t *testing.T) { t.Parallel() for test, af := range [][][]float64{ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, // even {{1, 2}, {4, 5}, {7, 8}}, // wide {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, //skinny } { m := NewDense(flatten(af)) rows, cols := m.Dims() for i := 0; i < rows; i++ { for j := 0; j < cols; j++ { if m.At(i, j) != af[i][j] { t.Errorf("unexpected value for At(%d, %d) for test %d: got: %v want: %v", i, j, test, m.At(i, j), af[i][j]) } v := float64(i * j) m.Set(i, j, v) if m.At(i, j) != v { t.Errorf("unexpected value for At(%d, %d) after Set(%[1]d, %d, %v) for test %d: got: %v want: %[3]v", i, j, v, test, m.At(i, j)) } } } // Check access out of bounds fails for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { m.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { m.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } // Check Set out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { m.Set(row, 0, 1.2) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { m.Set(0, col, 1.2) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } } } func TestDenseSetRowColumn(t *testing.T) { t.Parallel() for _, as := range [][][]float64{ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, } { for ri, row := range as { a := NewDense(flatten(as)) m := &Dense{} m.CloneFrom(a) a.SetRow(ri, make([]float64, a.mat.Cols)) m.Sub(m, a) nt := Norm(m, 2) nr := floats.Norm(row, 2) if math.Abs(nt-nr) > 1e-14 { t.Errorf("Row %d norm mismatch, want: %g, got: %g", ri, nr, nt) } } for ci := range as[0] { a := NewDense(flatten(as)) m := &Dense{} m.CloneFrom(a) a.SetCol(ci, make([]float64, a.mat.Rows)) col := make([]float64, a.mat.Rows) for j := range col { col[j] = float64(ci + 1 + j*a.mat.Cols) } m.Sub(m, a) nt := Norm(m, 2) nc := floats.Norm(col, 2) if math.Abs(nt-nc) > 1e-14 { t.Errorf("Column %d norm mismatch, want: %g, got: %g", ci, nc, nt) } } } } func TestDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*Dense{ { mat: blas64.General{ Rows: 4, Cols: 3, Stride: 5, Data: []float64{ 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } func TestDenseRowColView(t *testing.T) { t.Parallel() for _, test := range []struct { mat [][]float64 }{ { mat: [][]float64{ {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}, {16, 17, 18, 19, 20}, {21, 22, 23, 24, 25}, }, }, { mat: [][]float64{ {1, 2, 3, 4}, {6, 7, 8, 9}, {11, 12, 13, 14}, {16, 17, 18, 19}, {21, 22, 23, 24}, }, }, { mat: [][]float64{ {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}, {16, 17, 18, 19, 20}, }, }, } { // This over cautious approach to building a matrix data // slice is to ensure that changes to flatten in the future // do not mask a regression to the issue identified in // gonum/matrix#110. rows, cols, flat := flatten(test.mat) m := NewDense(rows, cols, flat[:len(flat):len(flat)]) for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { m.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access rows=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { m.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access cols=%d c=%d", cols, col) } } for i := 0; i < rows; i++ { vr := m.RowView(i) if vr.Len() != cols { t.Errorf("unexpected number of columns: got: %d want: %d", vr.Len(), cols) } for j := 0; j < cols; j++ { if got := vr.At(j, 0); got != test.mat[i][j] { t.Errorf("unexpected value for row.At(%d, 0): got: %v want: %v", j, got, test.mat[i][j]) } } } for j := 0; j < cols; j++ { vc := m.ColView(j) if vc.Len() != rows { t.Errorf("unexpected number of rows: got: %d want: %d", vc.Len(), rows) } for i := 0; i < rows; i++ { if got := vc.At(i, 0); got != test.mat[i][j] { t.Errorf("unexpected value for col.At(%d, 0): got: %v want: %v", i, got, test.mat[i][j]) } } } m = m.Slice(1, rows-1, 1, cols-1).(*Dense) for i := 1; i < rows-1; i++ { vr := m.RowView(i - 1) if vr.Len() != cols-2 { t.Errorf("unexpected number of columns: got: %d want: %d", vr.Len(), cols-2) } for j := 1; j < cols-1; j++ { if got := vr.At(j-1, 0); got != test.mat[i][j] { t.Errorf("unexpected value for row.At(%d, 0): got: %v want: %v", j-1, got, test.mat[i][j]) } } } for j := 1; j < cols-1; j++ { vc := m.ColView(j - 1) if vc.Len() != rows-2 { t.Errorf("unexpected number of rows: got: %d want: %d", vc.Len(), rows-2) } for i := 1; i < rows-1; i++ { if got := vc.At(i-1, 0); got != test.mat[i][j] { t.Errorf("unexpected value for col.At(%d, 0): got: %v want: %v", i-1, got, test.mat[i][j]) } } } } } func TestDenseDiagView(t *testing.T) { t.Parallel() for cas, test := range []*Dense{ NewDense(1, 1, []float64{1}), NewDense(2, 2, []float64{1, 2, 3, 4}), NewDense(3, 4, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }), NewDense(4, 3, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }), } { testDiagView(t, cas, test) } } func TestDenseGrow(t *testing.T) { t.Parallel() m := &Dense{} m = m.Grow(10, 10).(*Dense) rows, cols := m.Dims() capRows, capCols := m.Caps() if rows != 10 { t.Errorf("unexpected value for rows: got: %d want: 10", rows) } if cols != 10 { t.Errorf("unexpected value for cols: got: %d want: 10", cols) } if capRows != 10 { t.Errorf("unexpected value for capRows: got: %d want: 10", capRows) } if capCols != 10 { t.Errorf("unexpected value for capCols: got: %d want: 10", capCols) } // Test grow within caps is in-place. m.Set(1, 1, 1) v := m.Slice(1, 5, 1, 5).(*Dense) if v.At(0, 0) != m.At(1, 1) { t.Errorf("unexpected viewed element value: got: %v want: %v", v.At(0, 0), m.At(1, 1)) } v = v.Grow(5, 5).(*Dense) if !Equal(v, m.Slice(1, 10, 1, 10)) { t.Error("unexpected view value after grow") } // Test grow bigger than caps copies. v = v.Grow(5, 5).(*Dense) if !Equal(v.Slice(0, 9, 0, 9), m.Slice(1, 10, 1, 10)) { t.Error("unexpected mismatched common view value after grow") } v.Set(0, 0, 0) if Equal(v.Slice(0, 9, 0, 9), m.Slice(1, 10, 1, 10)) { t.Error("unexpected matching view value after grow past capacity") } // Test grow uses existing data slice when matrix is zero size. v.Reset() p, l := &v.mat.Data[:1][0], cap(v.mat.Data) *p = 1 // This element is at position (-1, -1) relative to v and so should not be visible. v = v.Grow(5, 5).(*Dense) if &v.mat.Data[:1][0] != p { t.Error("grow unexpectedly copied slice within cap limit") } if cap(v.mat.Data) != l { t.Errorf("unexpected change in data slice capacity: got: %d want: %d", cap(v.mat.Data), l) } if v.At(0, 0) != 0 { t.Errorf("unexpected value for At(0, 0): got: %v want: 0", v.At(0, 0)) } } func TestDenseAdd(t *testing.T) { t.Parallel() for i, test := range []struct { a, b, r [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{2, 2, 2}, {2, 2, 2}, {2, 2, 2}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{2, 0, 0}, {0, 2, 0}, {0, 0, 2}}, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-2, 0, 0}, {0, -2, 0}, {0, 0, -2}}, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{2, 4, 6}, {8, 10, 12}}, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) r := NewDense(flatten(test.r)) var temp Dense temp.Add(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from Add for test %d %v Add %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } zero(temp.mat.Data) temp.Add(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from Add for test %d %v Add %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } // These probably warrant a better check and failure. They should never happen in the wild though. temp.mat.Data = nil panicked, message := panics(func() { temp.Add(a, b) }) if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { t.Error("expected runtime panic for nil data slice") } a.Add(a, b) if !Equal(a, r) { t.Errorf("unexpected result from Add for test %d %v Add %v: got: %v want: %v", i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) } } panicked, message := panics(func() { m := NewDense(10, 10, nil) a := NewDense(5, 5, nil) m.Slice(1, 6, 1, 6).(*Dense).Add(a, m.Slice(2, 7, 2, 7)) }) if !panicked { t.Error("expected panic for overlapping matrices") } if message != regionOverlap { t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) } method := func(receiver, a, b Matrix) { type Adder interface { Add(a, b Matrix) } rd := receiver.(Adder) rd.Add(a, b) } denseComparison := func(receiver, a, b *Dense) { receiver.Add(a, b) } testTwoInput(t, "Add", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) } func TestDenseSub(t *testing.T) { t.Parallel() for i, test := range []struct { a, b, r [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{0, 0, 0}, {0, 0, 0}}, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) r := NewDense(flatten(test.r)) var temp Dense temp.Sub(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from Sub for test %d %v Sub %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } zero(temp.mat.Data) temp.Sub(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from Sub for test %d %v Sub %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } // These probably warrant a better check and failure. They should never happen in the wild though. temp.mat.Data = nil panicked, message := panics(func() { temp.Sub(a, b) }) if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { t.Error("expected runtime panic for nil data slice") } a.Sub(a, b) if !Equal(a, r) { t.Errorf("unexpected result from Sub for test %d %v Sub %v: got: %v want: %v", i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) } } panicked, message := panics(func() { m := NewDense(10, 10, nil) a := NewDense(5, 5, nil) m.Slice(1, 6, 1, 6).(*Dense).Sub(a, m.Slice(2, 7, 2, 7)) }) if !panicked { t.Error("expected panic for overlapping matrices") } if message != regionOverlap { t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) } method := func(receiver, a, b Matrix) { type Suber interface { Sub(a, b Matrix) } rd := receiver.(Suber) rd.Sub(a, b) } denseComparison := func(receiver, a, b *Dense) { receiver.Sub(a, b) } testTwoInput(t, "Sub", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) } func TestDenseMulElem(t *testing.T) { t.Parallel() for i, test := range []struct { a, b, r [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 4, 9}, {16, 25, 36}}, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) r := NewDense(flatten(test.r)) var temp Dense temp.MulElem(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from MulElem for test %d %v MulElem %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } zero(temp.mat.Data) temp.MulElem(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from MulElem for test %d %v MulElem %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } // These probably warrant a better check and failure. They should never happen in the wild though. temp.mat.Data = nil panicked, message := panics(func() { temp.MulElem(a, b) }) if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { t.Error("expected runtime panic for nil data slice") } a.MulElem(a, b) if !Equal(a, r) { t.Errorf("unexpected result from MulElem for test %d %v MulElem %v: got: %v want: %v", i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) } } panicked, message := panics(func() { m := NewDense(10, 10, nil) a := NewDense(5, 5, nil) m.Slice(1, 6, 1, 6).(*Dense).MulElem(a, m.Slice(2, 7, 2, 7)) }) if !panicked { t.Error("expected panic for overlapping matrices") } if message != regionOverlap { t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) } method := func(receiver, a, b Matrix) { type ElemMuler interface { MulElem(a, b Matrix) } rd := receiver.(ElemMuler) rd.MulElem(a, b) } denseComparison := func(receiver, a, b *Dense) { receiver.MulElem(a, b) } testTwoInput(t, "MulElem", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) } // A comparison that treats NaNs as equal, for testing. func (m *Dense) same(b Matrix) bool { br, bc := b.Dims() if br != m.mat.Rows || bc != m.mat.Cols { return false } for r := 0; r < br; r++ { for c := 0; c < bc; c++ { if av, bv := m.At(r, c), b.At(r, c); av != bv && !(math.IsNaN(av) && math.IsNaN(bv)) { return false } } } return true } func TestDenseDivElem(t *testing.T) { t.Parallel() for i, test := range []struct { a, b, r [][]float64 }{ { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{math.Inf(1), math.NaN(), math.NaN()}, {math.NaN(), math.Inf(1), math.NaN()}, {math.NaN(), math.NaN(), math.Inf(1)}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, math.NaN(), math.NaN()}, {math.NaN(), 1, math.NaN()}, {math.NaN(), math.NaN(), 1}}, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{1, math.NaN(), math.NaN()}, {math.NaN(), 1, math.NaN()}, {math.NaN(), math.NaN(), 1}}, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 1, 1}, {1, 1, 1}}, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) r := NewDense(flatten(test.r)) var temp Dense temp.DivElem(a, b) if !temp.same(r) { t.Errorf("unexpected result from DivElem for test %d %v DivElem %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } zero(temp.mat.Data) temp.DivElem(a, b) if !temp.same(r) { t.Errorf("unexpected result from DivElem for test %d %v DivElem %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } // These probably warrant a better check and failure. They should never happen in the wild though. temp.mat.Data = nil panicked, message := panics(func() { temp.DivElem(a, b) }) if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { t.Error("expected runtime panic for nil data slice") } a.DivElem(a, b) if !a.same(r) { t.Errorf("unexpected result from DivElem for test %d %v DivElem %v: got: %v want: %v", i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) } } panicked, message := panics(func() { m := NewDense(10, 10, nil) a := NewDense(5, 5, nil) m.Slice(1, 6, 1, 6).(*Dense).DivElem(a, m.Slice(2, 7, 2, 7)) }) if !panicked { t.Error("expected panic for overlapping matrices") } if message != regionOverlap { t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) } method := func(receiver, a, b Matrix) { type ElemDiver interface { DivElem(a, b Matrix) } rd := receiver.(ElemDiver) rd.DivElem(a, b) } denseComparison := func(receiver, a, b *Dense) { receiver.DivElem(a, b) } testTwoInput(t, "DivElem", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) } func TestDenseMul(t *testing.T) { t.Parallel() for i, test := range []struct { a, b, r [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{3, 3, 3}, {3, 3, 3}, {3, 3, 3}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 2}, {3, 4}, {5, 6}}, [][]float64{{22, 28}, {49, 64}}, }, { [][]float64{{0, 1, 1}, {0, 1, 1}, {0, 1, 1}}, [][]float64{{0, 1, 1}, {0, 1, 1}, {0, 1, 1}}, [][]float64{{0, 2, 2}, {0, 2, 2}, {0, 2, 2}}, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) r := NewDense(flatten(test.r)) var temp Dense temp.Mul(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from Mul for test %d %v Mul %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } zero(temp.mat.Data) temp.Mul(a, b) if !Equal(&temp, r) { t.Errorf("unexpected result from Mul for test %d %v Mul %v: got: %v want: %v", i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) } // These probably warrant a better check and failure. They should never happen in the wild though. temp.mat.Data = nil panicked, message := panics(func() { temp.Mul(a, b) }) if !panicked || message != "blas: insufficient length of c" { if message != "" { t.Errorf("expected runtime panic for nil data slice: got %q", message) } else { t.Error("expected runtime panic for nil data slice") } } } panicked, message := panics(func() { m := NewDense(10, 10, nil) a := NewDense(5, 5, nil) m.Slice(1, 6, 1, 6).(*Dense).Mul(a, m.Slice(2, 7, 2, 7)) }) if !panicked { t.Error("expected panic for overlapping matrices") } if message != regionOverlap { t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) } method := func(receiver, a, b Matrix) { type Muler interface { Mul(a, b Matrix) } rd := receiver.(Muler) rd.Mul(a, b) } denseComparison := func(receiver, a, b *Dense) { receiver.Mul(a, b) } legalSizeMul := func(ar, ac, br, bc int) bool { return ac == br } testTwoInput(t, "Mul", &Dense{}, method, denseComparison, legalTypesAll, legalSizeMul, 1e-14) } func randDense(size int, rho float64, src rand.Source) (*Dense, error) { if size == 0 { return nil, ErrZeroLength } d := &Dense{ mat: blas64.General{ Rows: size, Cols: size, Stride: size, Data: make([]float64, size*size), }, capRows: size, capCols: size, } rnd := rand.New(src) for i := 0; i < size; i++ { for j := 0; j < size; j++ { if rnd.Float64() < rho { d.Set(i, j, rnd.NormFloat64()) } } } return d, nil } func TestDenseExp(t *testing.T) { t.Parallel() for i, test := range []struct { a [][]float64 want [][]float64 mod func(*Dense) }{ // Expected values obtained from scipy.linalg.expm with the equivalent numpy.array. { a: [][]float64{{-49, 24}, {-64, 31}}, want: [][]float64{{-0.735758758144758, 0.551819099658100}, {-1.471517599088267, 1.103638240715576}}, }, { a: [][]float64{{-49, 24}, {-64, 31}}, want: [][]float64{{-0.735758758144758, 0.551819099658100}, {-1.471517599088267, 1.103638240715576}}, mod: func(a *Dense) { d := make([]float64, 100) for i := range d { d[i] = math.NaN() } *a = *NewDense(10, 10, d).Slice(1, 3, 1, 3).(*Dense) }, }, { a: [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, want: [][]float64{{2.71828182845905, 0, 0}, {0, 2.71828182845905, 0}, {0, 0, 2.71828182845905}}, }, { a: [][]float64{ {-200, 100, 100, 0}, {100, -200, 0, 100}, {100, 0, -200, 100}, {0, 100, 100, -200}, }, want: [][]float64{ {0.25, 0.25, 0.25, 0.25}, {0.25, 0.25, 0.25, 0.25}, {0.25, 0.25, 0.25, 0.25}, {0.25, 0.25, 0.25, 0.25}, }, }, } { var got Dense if test.mod != nil { test.mod(&got) } got.Exp(NewDense(flatten(test.a))) want := NewDense(flatten(test.want)) if !EqualApprox(&got, want, 1e-14) { t.Errorf("unexpected result for Exp test %d\ngot:\n%v\nwant:\n%v", i, Formatted(&got), Formatted(want)) } } } func TestDensePow(t *testing.T) { t.Parallel() for i, test := range []struct { a [][]float64 n int mod func(*Dense) want [][]float64 }{ { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 0, want: [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 0, want: [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, mod: func(a *Dense) { d := make([]float64, 100) for i := range d { d[i] = math.NaN() } *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) }, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 1, want: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 1, want: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, mod: func(a *Dense) { d := make([]float64, 100) for i := range d { d[i] = math.NaN() } *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) }, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 2, want: [][]float64{{30, 36, 42}, {66, 81, 96}, {102, 126, 150}}, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 2, want: [][]float64{{30, 36, 42}, {66, 81, 96}, {102, 126, 150}}, mod: func(a *Dense) { d := make([]float64, 100) for i := range d { d[i] = math.NaN() } *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) }, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 3, want: [][]float64{{468, 576, 684}, {1062, 1305, 1548}, {1656, 2034, 2412}}, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, n: 3, want: [][]float64{{468, 576, 684}, {1062, 1305, 1548}, {1656, 2034, 2412}}, mod: func(a *Dense) { d := make([]float64, 100) for i := range d { d[i] = math.NaN() } *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) }, }, } { var got Dense if test.mod != nil { test.mod(&got) } got.Pow(NewDense(flatten(test.a)), test.n) if !EqualApprox(&got, NewDense(flatten(test.want)), 1e-12) { t.Errorf("unexpected result for Pow test %d", i) } } } func TestDenseKronecker(t *testing.T) { t.Parallel() for i, test := range []struct { a, b Matrix want *Dense }{ { a: NewDense(1, 3, []float64{1, 2, 3}), b: NewDense(3, 1, []float64{1, 2, 3}), want: NewDense(3, 3, []float64{ 1, 2, 3, 2, 4, 6, 3, 6, 9, }), }, { a: NewDense(3, 1, []float64{1, 2, 3}), b: NewDense(1, 3, []float64{1, 2, 3}), want: NewDense(3, 3, []float64{ 1, 2, 3, 2, 4, 6, 3, 6, 9, }), }, { a: NewDense(1, 3, []float64{1, 2, 3}), b: NewDense(2, 1, []float64{1, 2}), want: NewDense(2, 3, []float64{ 1, 2, 3, 2, 4, 6, }), }, { a: NewDense(2, 1, []float64{1, 2}), b: NewDense(1, 3, []float64{1, 2, 3}), want: NewDense(2, 3, []float64{ 1, 2, 3, 2, 4, 6, }), }, { a: NewDense(1, 2, []float64{1, 2}), b: NewDense(3, 1, []float64{1, 2, 3}), want: NewDense(3, 2, []float64{ 1, 2, 2, 4, 3, 6, }), }, { a: NewDense(3, 1, []float64{1, 2, 3}), b: NewDense(1, 2, []float64{1, 2}), want: NewDense(3, 2, []float64{ 1, 2, 2, 4, 3, 6, }), }, // Examples from https://en.wikipedia.org/wiki/Kronecker_product. { a: NewDense(2, 2, []float64{1, 2, 3, 4}), b: NewDense(2, 2, []float64{0, 5, 6, 7}), want: NewDense(4, 4, []float64{ 0, 5, 0, 10, 6, 7, 12, 14, 0, 15, 0, 20, 18, 21, 24, 28, }), }, { a: NewDense(2, 3, []float64{ 1, -4, 7, -2, 3, 3, }), b: NewDense(4, 4, []float64{ 8, -9, -6, 5, 1, -3, -4, 7, 2, 8, -8, -3, 1, 2, -5, -1, }), want: NewDense(8, 12, []float64{ 8, -9, -6, 5, -32, 36, 24, -20, 56, -63, -42, 35, 1, -3, -4, 7, -4, 12, 16, -28, 7, -21, -28, 49, 2, 8, -8, -3, -8, -32, 32, 12, 14, 56, -56, -21, 1, 2, -5, -1, -4, -8, 20, 4, 7, 14, -35, -7, -16, 18, 12, -10, 24, -27, -18, 15, 24, -27, -18, 15, -2, 6, 8, -14, 3, -9, -12, 21, 3, -9, -12, 21, -4, -16, 16, 6, 6, 24, -24, -9, 6, 24, -24, -9, -2, -4, 10, 2, 3, 6, -15, -3, 3, 6, -15, -3, }), }, } { var got Dense got.Kronecker(test.a, test.b) if !Equal(&got, test.want) { t.Errorf("unexpected result for test %d\ngot:%#v want:%#v", i, &got, test.want) } } } func TestDenseScale(t *testing.T) { t.Parallel() for _, f := range []float64{0.5, 1, 3} { method := func(receiver, a Matrix) { type Scaler interface { Scale(f float64, a Matrix) } rd := receiver.(Scaler) rd.Scale(f, a) } denseComparison := func(receiver, a *Dense) { receiver.Scale(f, a) } testOneInput(t, "Scale", &Dense{}, method, denseComparison, isAnyType, isAnySize, 1e-14) } } func TestDensePowN(t *testing.T) { t.Parallel() for i, test := range []struct { a [][]float64 mod func(*Dense) }{ { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, mod: func(a *Dense) { d := make([]float64, 100) for i := range d { d[i] = math.NaN() } *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) }, }, } { for n := 1; n <= 14; n++ { var got, want Dense if test.mod != nil { test.mod(&got) } got.Pow(NewDense(flatten(test.a)), n) want.iterativePow(NewDense(flatten(test.a)), n) if !Equal(&got, &want) { t.Errorf("unexpected result for iterative Pow test %d", i) } } } } func (m *Dense) iterativePow(a Matrix, n int) { m.CloneFrom(a) for i := 1; i < n; i++ { m.Mul(m, a) } } func TestDenseCloneT(t *testing.T) { t.Parallel() for i, test := range []struct { a, want [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 4}, {2, 5}, {3, 6}}, }, } { a := NewDense(flatten(test.a)) want := NewDense(flatten(test.want)) var got, gotT Dense for j := 0; j < 2; j++ { got.CloneFrom(a.T()) if !Equal(&got, want) { t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", i, j, test.a, test.want) } gotT.CloneFrom(got.T()) if !Equal(&gotT, a) { t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", i, j, test.a, test.want) } zero(got.mat.Data) } } } func TestDenseCopyT(t *testing.T) { t.Parallel() for i, test := range []struct { a, want [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 4}, {2, 5}, {3, 6}}, }, } { a := NewDense(flatten(test.a)) want := NewDense(flatten(test.want)) ar, ac := a.Dims() got := NewDense(ac, ar, nil) rr := NewDense(ar, ac, nil) for j := 0; j < 2; j++ { got.Copy(a.T()) if !Equal(got, want) { t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", i, j, test.a, test.want) } rr.Copy(got.T()) if !Equal(rr, a) { t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", i, j, test.a, test.want) } zero(got.mat.Data) } } } func TestDenseCopyDenseAlias(t *testing.T) { t.Parallel() for _, trans := range []bool{false, true} { for di := 0; di < 2; di++ { for dj := 0; dj < 2; dj++ { for si := 0; si < 2; si++ { for sj := 0; sj < 2; sj++ { a := NewDense(3, 3, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }) src := a.Slice(si, si+2, sj, sj+2) want := DenseCopyOf(src) got := a.Slice(di, di+2, dj, dj+2).(*Dense) if trans { panicked, _ := panics(func() { got.Copy(src.T()) }) if !panicked { t.Errorf("expected panic for transpose aliased copy with offsets dst(%d,%d) src(%d,%d):\ngot:\n%v\nwant:\n%v", di, dj, si, sj, Formatted(got), Formatted(want), ) } continue } got.Copy(src) if !Equal(got, want) { t.Errorf("unexpected aliased copy result with offsets dst(%d,%d) src(%d,%d):\ngot:\n%v\nwant:\n%v", di, dj, si, sj, Formatted(got), Formatted(want), ) } } } } } } } func TestDenseCopyVecDenseAlias(t *testing.T) { t.Parallel() for _, horiz := range []bool{false, true} { for do := 0; do < 2; do++ { for di := 0; di < 3; di++ { for si := 0; si < 3; si++ { a := NewDense(3, 3, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }) var src Vector var want *Dense if horiz { src = a.RowView(si) want = DenseCopyOf(a.Slice(si, si+1, 0, 2)) } else { src = a.ColView(si) want = DenseCopyOf(a.Slice(0, 2, si, si+1)) } var got *Dense if horiz { got = a.Slice(di, di+1, do, do+2).(*Dense) got.Copy(src.T()) } else { got = a.Slice(do, do+2, di, di+1).(*Dense) got.Copy(src) } if !Equal(got, want) { t.Errorf("unexpected aliased copy result with offsets dst(%d) src(%d):\ngot:\n%v\nwant:\n%v", di, si, Formatted(got), Formatted(want), ) } } } } } } func identity(r, c int, v float64) float64 { return v } func TestDenseApply(t *testing.T) { t.Parallel() for i, test := range []struct { a, want [][]float64 fn func(r, c int, v float64) float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, identity, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, identity, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, identity, }, { [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, identity, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{1, 2, 3}, {4, 5, 6}}, identity, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{2, 4, 6}, {8, 10, 12}}, func(r, c int, v float64) float64 { return v * 2 }, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{0, 2, 0}, {0, 5, 0}}, func(r, c int, v float64) float64 { if c == 1 { return v } return 0 }, }, { [][]float64{{1, 2, 3}, {4, 5, 6}}, [][]float64{{0, 0, 0}, {4, 5, 6}}, func(r, c int, v float64) float64 { if r == 1 { return v } return 0 }, }, } { a := NewDense(flatten(test.a)) want := NewDense(flatten(test.want)) var got Dense for j := 0; j < 2; j++ { got.Apply(test.fn, a) if !Equal(&got, want) { t.Errorf("unexpected result for test %d iteration %d: got: %v want: %v", i, j, got.mat.Data, want.mat.Data) } } } for _, fn := range []func(r, c int, v float64) float64{ identity, func(r, c int, v float64) float64 { if r < c { return v } return -v }, func(r, c int, v float64) float64 { if r%2 == 0 && c%2 == 0 { return v } return -v }, func(_, _ int, v float64) float64 { return v * v }, func(_, _ int, v float64) float64 { return -v }, } { method := func(receiver, x Matrix) { type Applier interface { Apply(func(r, c int, v float64) float64, Matrix) } rd := receiver.(Applier) rd.Apply(fn, x) } denseComparison := func(receiver, x *Dense) { receiver.Apply(fn, x) } testOneInput(t, "Apply", &Dense{}, method, denseComparison, isAnyType, isAnySize, 0) } } func TestDenseClone(t *testing.T) { t.Parallel() for i, test := range []struct { a [][]float64 i, j int v float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1, 1, 1, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 0, 0, 0, }, } { a := NewDense(flatten(test.a)) b := *a a.CloneFrom(a) a.Set(test.i, test.j, test.v) if Equal(&b, a) { t.Errorf("unexpected mirror of write to cloned matrix for test %d: %v cloned and altered = %v", i, a, &b) } } } // TODO(kortschak) Roll this into testOneInput when it exists. func TestDenseCopyPanic(t *testing.T) { t.Parallel() for _, a := range []*Dense{ {}, {mat: blas64.General{Rows: 1}}, {mat: blas64.General{Cols: 1}}, } { var rows, cols int m := NewDense(1, 1, nil) panicked, message := panics(func() { rows, cols = m.Copy(a) }) if panicked { t.Errorf("unexpected panic: %v", message) } if rows != 0 { t.Errorf("unexpected rows: got: %d want: 0", rows) } if cols != 0 { t.Errorf("unexpected cols: got: %d want: 0", cols) } } } func TestDenseStack(t *testing.T) { t.Parallel() for i, test := range []struct { a, b, e [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) var s Dense s.Stack(a, b) if !Equal(&s, NewDense(flatten(test.e))) { t.Errorf("unexpected result for Stack test %d: %v stack %v = %v", i, a, b, s) } } method := func(receiver, a, b Matrix) { type Stacker interface { Stack(a, b Matrix) } rd := receiver.(Stacker) rd.Stack(a, b) } denseComparison := func(receiver, a, b *Dense) { receiver.Stack(a, b) } testTwoInput(t, "Stack", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameWidth, 0) } func TestDenseAugment(t *testing.T) { t.Parallel() for i, test := range []struct { a, b, e [][]float64 }{ { [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, [][]float64{{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}, }, { [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, [][]float64{{1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}}, }, { [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, [][]float64{{0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, [][]float64{{1, 0, 0, 0, 1, 0}, {0, 1, 0, 0, 0, 1}, {0, 0, 1, 1, 0, 0}}, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) var s Dense s.Augment(a, b) if !Equal(&s, NewDense(flatten(test.e))) { t.Errorf("unexpected result for Augment test %d: %v augment %v = %v", i, a, b, s) } } method := func(receiver, a, b Matrix) { type Augmenter interface { Augment(a, b Matrix) } rd := receiver.(Augmenter) rd.Augment(a, b) } denseComparison := func(receiver, a, b *Dense) { receiver.Augment(a, b) } testTwoInput(t, "Augment", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameHeight, 0) } func TestDenseRankOne(t *testing.T) { t.Parallel() for i, test := range []struct { x []float64 y []float64 m [][]float64 alpha float64 }{ { x: []float64{5}, y: []float64{10}, m: [][]float64{{2}}, alpha: -3, }, { x: []float64{5, 6, 1}, y: []float64{10}, m: [][]float64{{2}, {-3}, {5}}, alpha: -3, }, { x: []float64{5}, y: []float64{10, 15, 8}, m: [][]float64{{2, -3, 5}}, alpha: -3, }, { x: []float64{1, 5}, y: []float64{10, 15}, m: [][]float64{ {2, -3}, {4, -1}, }, alpha: -3, }, { x: []float64{2, 3, 9}, y: []float64{8, 9}, m: [][]float64{ {2, 3}, {4, 5}, {6, 7}, }, alpha: -3, }, { x: []float64{2, 3}, y: []float64{8, 9, 9}, m: [][]float64{ {2, 3, 6}, {4, 5, 7}, }, alpha: -3, }, } { want := &Dense{} xm := NewDense(len(test.x), 1, test.x) ym := NewDense(1, len(test.y), test.y) want.Mul(xm, ym) want.Scale(test.alpha, want) want.Add(want, NewDense(flatten(test.m))) a := NewDense(flatten(test.m)) m := &Dense{} // Check with a new matrix m.RankOne(a, test.alpha, NewVecDense(len(test.x), test.x), NewVecDense(len(test.y), test.y)) if !Equal(m, want) { t.Errorf("unexpected result for RankOne test %d iteration 0: got: %+v want: %+v", i, m, want) } // Check with the same matrix a.RankOne(a, test.alpha, NewVecDense(len(test.x), test.x), NewVecDense(len(test.y), test.y)) if !Equal(a, want) { t.Errorf("unexpected result for RankOne test %d iteration 1: got: %+v want: %+v", i, m, want) } } } func TestDenseOuter(t *testing.T) { t.Parallel() for i, test := range []struct { x []float64 y []float64 }{ { x: []float64{5}, y: []float64{10}, }, { x: []float64{5, 6, 1}, y: []float64{10}, }, { x: []float64{5}, y: []float64{10, 15, 8}, }, { x: []float64{1, 5}, y: []float64{10, 15}, }, { x: []float64{2, 3, 9}, y: []float64{8, 9}, }, { x: []float64{2, 3}, y: []float64{8, 9, 9}, }, } { for _, f := range []float64{0.5, 1, 3} { want := &Dense{} xm := NewDense(len(test.x), 1, test.x) ym := NewDense(1, len(test.y), test.y) want.Mul(xm, ym) want.Scale(f, want) var m Dense for j := 0; j < 2; j++ { // Check with a new matrix - and then again. m.Outer(f, NewVecDense(len(test.x), test.x), NewVecDense(len(test.y), test.y)) if !Equal(&m, want) { t.Errorf("unexpected result for Outer test %d iteration %d scale %v: got: %+v want: %+v", i, j, f, m, want) } } } } for _, alpha := range []float64{0, 1, -1, 2.3, -2.3} { method := func(receiver, x, y Matrix) { type outerer interface { Outer(alpha float64, x, y Vector) } m := receiver.(outerer) m.Outer(alpha, x.(Vector), y.(Vector)) } denseComparison := func(receiver, x, y *Dense) { receiver.Mul(x, y.T()) receiver.Scale(alpha, receiver) } testTwoInput(t, "Outer", &Dense{}, method, denseComparison, legalTypesVectorVector, legalSizeVector, 1e-12) } } func TestDenseInverse(t *testing.T) { t.Parallel() for i, test := range []struct { a Matrix want Matrix // nil indicates that a is singular. tol float64 }{ { a: NewDense(3, 3, []float64{ 8, 1, 6, 3, 5, 7, 4, 9, 2, }), want: NewDense(3, 3, []float64{ 0.147222222222222, -0.144444444444444, 0.063888888888889, -0.061111111111111, 0.022222222222222, 0.105555555555556, -0.019444444444444, 0.188888888888889, -0.102777777777778, }), tol: 1e-14, }, { a: NewDense(3, 3, []float64{ 8, 1, 6, 3, 5, 7, 4, 9, 2, }).T(), want: NewDense(3, 3, []float64{ 0.147222222222222, -0.144444444444444, 0.063888888888889, -0.061111111111111, 0.022222222222222, 0.105555555555556, -0.019444444444444, 0.188888888888889, -0.102777777777778, }).T(), tol: 1e-14, }, // This case does not fail, but we do not guarantee that. The success // is because the receiver and the input are aligned in the call to // inverse. If there was a misalignment, the result would likely be // incorrect and no shadowing panic would occur. { a: asBasicMatrix(NewDense(3, 3, []float64{ 8, 1, 6, 3, 5, 7, 4, 9, 2, })), want: NewDense(3, 3, []float64{ 0.147222222222222, -0.144444444444444, 0.063888888888889, -0.061111111111111, 0.022222222222222, 0.105555555555556, -0.019444444444444, 0.188888888888889, -0.102777777777778, }), tol: 1e-14, }, // The following case fails as it does not follow the shadowing rules. // Specifically, the test extracts the underlying *Dense, and uses // it as a receiver with the basicMatrix as input. The basicMatrix type // allows shadowing of the input data without providing the Raw method // required for detection of shadowing. // // We specifically state we do not check this case. // // { // a: asBasicMatrix(NewDense(3, 3, []float64{ // 8, 1, 6, // 3, 5, 7, // 4, 9, 2, // })).T(), // want: NewDense(3, 3, []float64{ // 0.147222222222222, -0.144444444444444, 0.063888888888889, // -0.061111111111111, 0.022222222222222, 0.105555555555556, // -0.019444444444444, 0.188888888888889, -0.102777777777778, // }).T(), // tol: 1e-14, // }, { a: NewDense(4, 4, []float64{ 5, 2, 8, 7, 4, 5, 8, 2, 8, 5, 3, 2, 8, 7, 7, 5, }), want: NewDense(4, 4, []float64{ 0.100548446069470, 0.021937842778793, 0.334552102376599, -0.283363802559415, -0.226691042047532, -0.067641681901280, -0.281535648994515, 0.457038391224863, 0.080438756855576, 0.217550274223035, 0.067641681901280, -0.226691042047532, 0.043875685557587, -0.244972577696527, -0.235831809872029, 0.330895795246801, }), tol: 1e-14, }, // Tests with singular matrix. { a: NewDense(1, 1, []float64{ 0, }), }, { a: NewDense(2, 2, []float64{ 0, 0, 0, 0, }), }, { a: NewDense(2, 2, []float64{ 0, 0, 0, 1, }), }, { a: NewDense(3, 3, []float64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, }), }, { a: NewDense(4, 4, []float64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }), }, { a: NewDense(4, 4, []float64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 0, 0, 20, 20, }), }, { a: NewDense(4, 4, []float64{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, }), }, { a: NewDense(4, 4, []float64{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }), }, { a: NewDense(5, 5, []float64{ 0, 1, 0, 0, 0, 4, 0, 2, 0, 0, 0, 3, 0, 3, 0, 0, 0, 2, 0, 4, 0, 0, 0, 1, 0, }), }, { a: NewDense(5, 5, []float64{ 4, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, 4, }), }, { a: NewDense(5, 5, []float64{ 2, -1, 0, 0, -1, -1, 2, -1, 0, 0, 0, -1, 2, -1, 0, 0, 0, -1, 2, -1, -1, 0, 0, -1, 2, }), }, { a: NewDense(5, 5, []float64{ 1, 2, 3, 5, 8, 2, 3, 5, 8, 13, 3, 5, 8, 13, 21, 5, 8, 13, 21, 34, 8, 13, 21, 34, 55, }), }, { a: NewDense(8, 8, []float64{ 611, 196, -192, 407, -8, -52, -49, 29, 196, 899, 113, -192, -71, -43, -8, -44, -192, 113, 899, 196, 61, 49, 8, 52, 407, -192, 196, 611, 8, 44, 59, -23, -8, -71, 61, 8, 411, -599, 208, 208, -52, -43, 49, 44, -599, 411, 208, 208, -49, -8, 8, 59, 208, 208, 99, -911, 29, -44, 52, -23, 208, 208, -911, 99, }), }, } { var got Dense err := got.Inverse(test.a) if test.want == nil { if err == nil { t.Errorf("Case %d: expected error for singular matrix", i) } continue } if err != nil { t.Errorf("Case %d: unexpected error: %v", i, err) continue } if !equalApprox(&got, test.want, test.tol, false) { t.Errorf("Case %d, inverse mismatch.", i) } var m Dense m.Mul(&got, test.a) r, _ := test.a.Dims() d := make([]float64, r*r) for i := 0; i < r*r; i += r + 1 { d[i] = 1 } eye := NewDense(r, r, d) if !equalApprox(eye, &m, 1e-14, false) { t.Errorf("Case %d, A^-1 * A != I", i) } var tmp Dense tmp.CloneFrom(test.a) aU, transposed := untranspose(test.a) if transposed { switch aU := aU.(type) { case *Dense: err = aU.Inverse(test.a) case *basicMatrix: err = (*Dense)(aU).Inverse(test.a) default: continue } m.Mul(aU, &tmp) } else { switch a := test.a.(type) { case *Dense: err = a.Inverse(test.a) m.Mul(a, &tmp) case *basicMatrix: err = (*Dense)(a).Inverse(test.a) m.Mul(a, &tmp) default: continue } } if err != nil { t.Errorf("Error computing inverse: %v", err) } if !equalApprox(eye, &m, 1e-14, false) { t.Errorf("Case %d, A^-1 * A != I", i) fmt.Println(Formatted(&m)) } } // Randomized tests const tol = 1e-16 rnd := rand.New(rand.NewSource(1)) for _, recvSameAsA := range []bool{false, true} { for _, trans := range []bool{false, true} { if trans && recvSameAsA { // Transposed argument cannot be a receiver. continue } for _, n := range []int{1, 2, 3, 5, 10, 50, 100} { name := fmt.Sprintf("n=%d,recvSameAsA=%v,trans=%v", n, recvSameAsA, trans) // Generate the contents of a random dense matrix. data := make([]float64, n*n) for i := range data { data[i] = rnd.NormFloat64() } var a Matrix var aInv Dense if recvSameAsA { aInv = *NewDense(n, n, data) a = &aInv } else { if trans { a = NewDense(n, n, data).T() } else { a = asBasicMatrix(NewDense(n, n, data)) } } var aOrig Dense aOrig.CloneFrom(a) err := aInv.Inverse(a) if err != nil { t.Errorf("%v: unexpected failure of Inverse, %v", name, err) continue } // Compute the residual |I - A^{-1} * A| / (N * |A| * |A^{-1}). var aaInv Dense aaInv.Mul(&aInv, &aOrig) for i := 0; i < n; i++ { aaInv.Set(i, i, 1-aaInv.At(i, i)) } resid := Norm(&aaInv, 1) / (float64(n) * Norm(&aOrig, 1) * Norm(&aInv, 1)) if resid > tol { t.Errorf("%v: A*A^{-1} is not identity, resid=%v,want<=%v", name, resid, tol) } } } } } var ( wd *Dense ) func BenchmarkMulDense100Half(b *testing.B) { denseMulBench(b, 100, 0.5) } func BenchmarkMulDense100Tenth(b *testing.B) { denseMulBench(b, 100, 0.1) } func BenchmarkMulDense1000Half(b *testing.B) { denseMulBench(b, 1000, 0.5) } func BenchmarkMulDense1000Tenth(b *testing.B) { denseMulBench(b, 1000, 0.1) } func BenchmarkMulDense1000Hundredth(b *testing.B) { denseMulBench(b, 1000, 0.01) } func BenchmarkMulDense1000Thousandth(b *testing.B) { denseMulBench(b, 1000, 0.001) } func denseMulBench(b *testing.B, size int, rho float64) { src := rand.NewSource(1) b.StopTimer() a, _ := randDense(size, rho, src) d, _ := randDense(size, rho, src) b.StartTimer() for i := 0; i < b.N; i++ { var n Dense n.Mul(a, d) wd = &n } } func BenchmarkPreMulDense100Half(b *testing.B) { densePreMulBench(b, 100, 0.5) } func BenchmarkPreMulDense100Tenth(b *testing.B) { densePreMulBench(b, 100, 0.1) } func BenchmarkPreMulDense1000Half(b *testing.B) { densePreMulBench(b, 1000, 0.5) } func BenchmarkPreMulDense1000Tenth(b *testing.B) { densePreMulBench(b, 1000, 0.1) } func BenchmarkPreMulDense1000Hundredth(b *testing.B) { densePreMulBench(b, 1000, 0.01) } func BenchmarkPreMulDense1000Thousandth(b *testing.B) { densePreMulBench(b, 1000, 0.001) } func densePreMulBench(b *testing.B, size int, rho float64) { src := rand.NewSource(1) b.StopTimer() a, _ := randDense(size, rho, src) d, _ := randDense(size, rho, src) wd = NewDense(size, size, nil) b.StartTimer() for i := 0; i < b.N; i++ { wd.Mul(a, d) } } func BenchmarkDenseRow10(b *testing.B) { rowDenseBench(b, 10) } func BenchmarkDenseRow100(b *testing.B) { rowDenseBench(b, 100) } func BenchmarkDenseRow1000(b *testing.B) { rowDenseBench(b, 1000) } func rowDenseBench(b *testing.B, size int) { src := rand.NewSource(1) a, _ := randDense(size, 1, src) _, c := a.Dims() dst := make([]float64, c) b.ResetTimer() for i := 0; i < b.N; i++ { Row(dst, 0, a) } } func BenchmarkDenseExp10(b *testing.B) { expDenseBench(b, 10) } func BenchmarkDenseExp100(b *testing.B) { expDenseBench(b, 100) } func BenchmarkDenseExp1000(b *testing.B) { expDenseBench(b, 1000) } func expDenseBench(b *testing.B, size int) { src := rand.NewSource(1) a, _ := randDense(size, 1, src) b.ResetTimer() var m Dense for i := 0; i < b.N; i++ { m.Exp(a) } } func BenchmarkDensePow10_3(b *testing.B) { powDenseBench(b, 10, 3) } func BenchmarkDensePow100_3(b *testing.B) { powDenseBench(b, 100, 3) } func BenchmarkDensePow1000_3(b *testing.B) { powDenseBench(b, 1000, 3) } func BenchmarkDensePow10_4(b *testing.B) { powDenseBench(b, 10, 4) } func BenchmarkDensePow100_4(b *testing.B) { powDenseBench(b, 100, 4) } func BenchmarkDensePow1000_4(b *testing.B) { powDenseBench(b, 1000, 4) } func BenchmarkDensePow10_5(b *testing.B) { powDenseBench(b, 10, 5) } func BenchmarkDensePow100_5(b *testing.B) { powDenseBench(b, 100, 5) } func BenchmarkDensePow1000_5(b *testing.B) { powDenseBench(b, 1000, 5) } func BenchmarkDensePow10_6(b *testing.B) { powDenseBench(b, 10, 6) } func BenchmarkDensePow100_6(b *testing.B) { powDenseBench(b, 100, 6) } func BenchmarkDensePow1000_6(b *testing.B) { powDenseBench(b, 1000, 6) } func BenchmarkDensePow10_7(b *testing.B) { powDenseBench(b, 10, 7) } func BenchmarkDensePow100_7(b *testing.B) { powDenseBench(b, 100, 7) } func BenchmarkDensePow1000_7(b *testing.B) { powDenseBench(b, 1000, 7) } func BenchmarkDensePow10_8(b *testing.B) { powDenseBench(b, 10, 8) } func BenchmarkDensePow100_8(b *testing.B) { powDenseBench(b, 100, 8) } func BenchmarkDensePow1000_8(b *testing.B) { powDenseBench(b, 1000, 8) } func BenchmarkDensePow10_9(b *testing.B) { powDenseBench(b, 10, 9) } func BenchmarkDensePow100_9(b *testing.B) { powDenseBench(b, 100, 9) } func BenchmarkDensePow1000_9(b *testing.B) { powDenseBench(b, 1000, 9) } func powDenseBench(b *testing.B, size, n int) { src := rand.NewSource(1) a, _ := randDense(size, 1, src) b.ResetTimer() var m Dense for i := 0; i < b.N; i++ { m.Pow(a, n) } } func BenchmarkDenseMulTransDense100Half(b *testing.B) { denseMulTransBench(b, 100, 0.5) } func BenchmarkDenseMulTransDense100Tenth(b *testing.B) { denseMulTransBench(b, 100, 0.1) } func BenchmarkDenseMulTransDense1000Half(b *testing.B) { denseMulTransBench(b, 1000, 0.5) } func BenchmarkDenseMulTransDense1000Tenth(b *testing.B) { denseMulTransBench(b, 1000, 0.1) } func BenchmarkDenseMulTransDense1000Hundredth(b *testing.B) { denseMulTransBench(b, 1000, 0.01) } func BenchmarkDenseMulTransDense1000Thousandth(b *testing.B) { denseMulTransBench(b, 1000, 0.001) } func denseMulTransBench(b *testing.B, size int, rho float64) { src := rand.NewSource(1) b.StopTimer() a, _ := randDense(size, rho, src) d, _ := randDense(size, rho, src) b.StartTimer() for i := 0; i < b.N; i++ { var n Dense n.Mul(a, d.T()) wd = &n } } func BenchmarkDenseMulTransDenseSym100Half(b *testing.B) { denseMulTransSymBench(b, 100, 0.5) } func BenchmarkDenseMulTransDenseSym100Tenth(b *testing.B) { denseMulTransSymBench(b, 100, 0.1) } func BenchmarkDenseMulTransDenseSym1000Half(b *testing.B) { denseMulTransSymBench(b, 1000, 0.5) } func BenchmarkDenseMulTransDenseSym1000Tenth(b *testing.B) { denseMulTransSymBench(b, 1000, 0.1) } func BenchmarkDenseMulTransDenseSym1000Hundredth(b *testing.B) { denseMulTransSymBench(b, 1000, 0.01) } func BenchmarkDenseMulTransDenseSym1000Thousandth(b *testing.B) { denseMulTransSymBench(b, 1000, 0.001) } func denseMulTransSymBench(b *testing.B, size int, rho float64) { src := rand.NewSource(1) b.StopTimer() a, _ := randDense(size, rho, src) b.StartTimer() for i := 0; i < b.N; i++ { var n Dense n.Mul(a, a.T()) wd = &n } } func BenchmarkDenseSum1000(b *testing.B) { denseSumBench(b, 1000) } var denseSumForBench float64 func denseSumBench(b *testing.B, size int) { src := rand.NewSource(1) a, _ := randDense(size, 1.0, src) b.ResetTimer() for i := 0; i < b.N; i++ { denseSumForBench = Sum(a) } } golang-gonum-v1-gonum-0.14.0/mat/diagonal.go000066400000000000000000000203451450372207100205300ustar00rootroot00000000000000// 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 mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) var ( diagDense *DiagDense _ Matrix = diagDense _ allMatrix = diagDense _ denseMatrix = diagDense _ Diagonal = diagDense _ MutableDiagonal = diagDense _ Triangular = diagDense _ TriBanded = diagDense _ Symmetric = diagDense _ SymBanded = diagDense _ Banded = diagDense _ RawBander = diagDense _ RawSymBander = diagDense diag Diagonal _ Matrix = diag _ Diagonal = diag _ Triangular = diag _ TriBanded = diag _ Symmetric = diag _ SymBanded = diag _ Banded = diag ) // Diagonal represents a diagonal matrix, that is a square matrix that only // has non-zero terms on the diagonal. type Diagonal interface { Matrix // Diag returns the number of rows/columns in the matrix. Diag() int // The following interfaces are included in the Diagonal // interface to allow the use of Diagonal types in // functions operating on these types. Banded SymBanded Symmetric Triangular TriBanded } // MutableDiagonal is a Diagonal matrix whose elements can be set. type MutableDiagonal interface { Diagonal SetDiag(i int, v float64) } // DiagDense represents a diagonal matrix in dense storage format. type DiagDense struct { mat blas64.Vector } // NewDiagDense creates a new Diagonal matrix with n rows and n columns. // The length of data must be n or data must be nil, otherwise NewDiagDense // will panic. NewDiagDense will panic if n is zero. func NewDiagDense(n int, data []float64) *DiagDense { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic("mat: negative dimension") } if data == nil { data = make([]float64, n) } if len(data) != n { panic(ErrShape) } return &DiagDense{ mat: blas64.Vector{N: n, Data: data, Inc: 1}, } } // Diag returns the dimension of the receiver. func (d *DiagDense) Diag() int { return d.mat.N } // Dims returns the dimensions of the matrix. func (d *DiagDense) Dims() (r, c int) { return d.mat.N, d.mat.N } // T returns the transpose of the matrix. func (d *DiagDense) T() Matrix { return d } // TTri returns the transpose of the matrix. Note that Diagonal matrices are // Upper by default. func (d *DiagDense) TTri() Triangular { return TransposeTri{d} } // TBand performs an implicit transpose by returning the receiver inside a // TransposeBand. func (d *DiagDense) TBand() Banded { return TransposeBand{d} } // TTriBand performs an implicit transpose by returning the receiver inside a // TransposeTriBand. Note that Diagonal matrices are Upper by default. func (d *DiagDense) TTriBand() TriBanded { return TransposeTriBand{d} } // Bandwidth returns the upper and lower bandwidths of the matrix. // These values are always zero for diagonal matrices. func (d *DiagDense) Bandwidth() (kl, ku int) { return 0, 0 } // SymmetricDim implements the Symmetric interface. func (d *DiagDense) SymmetricDim() int { return d.mat.N } // SymBand returns the number of rows/columns in the matrix, and the size of // the bandwidth. func (d *DiagDense) SymBand() (n, k int) { return d.mat.N, 0 } // Triangle implements the Triangular interface. func (d *DiagDense) Triangle() (int, TriKind) { return d.mat.N, Upper } // TriBand returns the number of rows/columns in the matrix, the // size of the bandwidth, and the orientation. Note that Diagonal matrices are // Upper by default. func (d *DiagDense) TriBand() (n, k int, kind TriKind) { return d.mat.N, 0, Upper } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (d *DiagDense) Reset() { // No change of Inc or n to 0 may be // made unless both are set to 0. d.mat.Inc = 0 d.mat.N = 0 d.mat.Data = d.mat.Data[:0] } // Zero sets all of the matrix elements to zero. func (d *DiagDense) Zero() { for i := 0; i < d.mat.N; i++ { d.mat.Data[d.mat.Inc*i] = 0 } } // DiagView returns the diagonal as a matrix backed by the original data. func (d *DiagDense) DiagView() Diagonal { return d } // DiagFrom copies the diagonal of m into the receiver. The receiver must // be min(r, c) long or empty, otherwise DiagFrom will panic. func (d *DiagDense) DiagFrom(m Matrix) { n := min(m.Dims()) d.reuseAsNonZeroed(n) var vec blas64.Vector switch r := m.(type) { case *DiagDense: vec = r.mat case RawBander: mat := r.RawBand() vec = blas64.Vector{ N: n, Inc: mat.Stride, Data: mat.Data[mat.KL : (n-1)*mat.Stride+mat.KL+1], } case RawMatrixer: mat := r.RawMatrix() vec = blas64.Vector{ N: n, Inc: mat.Stride + 1, Data: mat.Data[:(n-1)*mat.Stride+n], } case RawSymBander: mat := r.RawSymBand() vec = blas64.Vector{ N: n, Inc: mat.Stride, Data: mat.Data[:(n-1)*mat.Stride+1], } case RawSymmetricer: mat := r.RawSymmetric() vec = blas64.Vector{ N: n, Inc: mat.Stride + 1, Data: mat.Data[:(n-1)*mat.Stride+n], } case RawTriBander: mat := r.RawTriBand() data := mat.Data if mat.Uplo == blas.Lower { data = data[mat.K:] } vec = blas64.Vector{ N: n, Inc: mat.Stride, Data: data[:(n-1)*mat.Stride+1], } case RawTriangular: mat := r.RawTriangular() if mat.Diag == blas.Unit { for i := 0; i < n; i += d.mat.Inc { d.mat.Data[i] = 1 } return } vec = blas64.Vector{ N: n, Inc: mat.Stride + 1, Data: mat.Data[:(n-1)*mat.Stride+n], } case RawVectorer: d.mat.Data[0] = r.RawVector().Data[0] return default: for i := 0; i < n; i++ { d.setDiag(i, m.At(i, i)) } return } blas64.Copy(vec, d.mat) } // RawBand returns the underlying data used by the receiver represented // as a blas64.Band. // Changes to elements in the receiver following the call will be reflected // in returned blas64.Band. func (d *DiagDense) RawBand() blas64.Band { return blas64.Band{ Rows: d.mat.N, Cols: d.mat.N, KL: 0, KU: 0, Stride: d.mat.Inc, Data: d.mat.Data, } } // RawSymBand returns the underlying data used by the receiver represented // as a blas64.SymmetricBand. // Changes to elements in the receiver following the call will be reflected // in returned blas64.Band. func (d *DiagDense) RawSymBand() blas64.SymmetricBand { return blas64.SymmetricBand{ N: d.mat.N, K: 0, Stride: d.mat.Inc, Uplo: blas.Upper, Data: d.mat.Data, } } // reuseAsNonZeroed resizes an empty diagonal to a r×r diagonal, // or checks that a non-empty matrix is r×r. func (d *DiagDense) reuseAsNonZeroed(r int) { if r == 0 { panic(ErrZeroLength) } if d.IsEmpty() { d.mat = blas64.Vector{ Inc: 1, Data: use(d.mat.Data, r), } d.mat.N = r return } if r != d.mat.N { panic(ErrShape) } } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (d *DiagDense) IsEmpty() bool { // It must be the case that d.Dims() returns // zeros in this case. See comment in Reset(). return d.mat.Inc == 0 } // Trace returns the trace of the matrix. // // Trace will panic with ErrZeroLength if the matrix has zero size. func (d *DiagDense) Trace() float64 { if d.IsEmpty() { panic(ErrZeroLength) } rb := d.RawBand() var tr float64 for i := 0; i < rb.Rows; i++ { tr += rb.Data[rb.KL+i*rb.Stride] } return tr } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 or Inf - The maximum diagonal element magnitude // 2 - The Frobenius norm, the square root of the sum of the squares of // the diagonal elements // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the receiver has zero size. func (d *DiagDense) Norm(norm float64) float64 { if d.IsEmpty() { panic(ErrZeroLength) } switch norm { default: panic(ErrNormOrder) case 1, math.Inf(1): imax := blas64.Iamax(d.mat) return math.Abs(d.at(imax, imax)) case 2: return blas64.Nrm2(d.mat) } } golang-gonum-v1-gonum-0.14.0/mat/diagonal_test.go000066400000000000000000000272411450372207100215710ustar00rootroot00000000000000// 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 mat import ( "math" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" ) func TestNewDiagDense(t *testing.T) { t.Parallel() for i, test := range []struct { data []float64 n int mat *DiagDense dense *Dense }{ { data: []float64{1, 2, 3, 4, 5, 6}, n: 6, mat: &DiagDense{ mat: blas64.Vector{N: 6, Inc: 1, Data: []float64{1, 2, 3, 4, 5, 6}}, }, dense: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, } { band := NewDiagDense(test.n, test.data) rows, cols := band.Dims() if rows != test.n { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.n) } if cols != test.n { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.n) } if !reflect.DeepEqual(band, test.mat) { t.Errorf("unexpected value via reflect for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.mat) { t.Errorf("unexpected value via mat.Equal for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.dense) { t.Errorf("unexpected value via mat.Equal(band, dense) for test %d:\ngot:\n% v\nwant:\n% v", i, Formatted(band), Formatted(test.dense)) } } } func TestDiagDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*DiagDense{ { mat: blas64.Vector{ N: 5, Inc: 2, Data: []float64{ 1, -1, 1, -1, 1, -1, 1, -1, 1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } func TestDiagonalStride(t *testing.T) { t.Parallel() for _, test := range []struct { diag *DiagDense dense *Dense }{ { diag: &DiagDense{ mat: blas64.Vector{N: 6, Inc: 1, Data: []float64{1, 2, 3, 4, 5, 6}}, }, dense: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { diag: &DiagDense{ mat: blas64.Vector{N: 6, Inc: 2, Data: []float64{ 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, }}, }, dense: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { diag: &DiagDense{ mat: blas64.Vector{N: 6, Inc: 5, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, }}, }, dense: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, } { if !Equal(test.diag, test.dense) { t.Errorf("unexpected value via mat.Equal for stride %d: got: %v want: %v", test.diag.mat.Inc, test.diag, test.dense) } } } func TestDiagFrom(t *testing.T) { t.Parallel() for i, test := range []struct { mat Matrix want *Dense }{ { mat: NewDiagDense(6, []float64{1, 2, 3, 4, 5, 6}), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewBandDense(6, 6, 1, 1, []float64{ math.NaN(), 1, math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), 6, math.NaN(), }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewDense(6, 6, []float64{ 1, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 6, }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewDense(6, 4, []float64{ 1, math.NaN(), math.NaN(), math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), }), want: NewDense(4, 4, []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, }), }, { mat: NewDense(4, 6, []float64{ 1, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), }), want: NewDense(4, 4, []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, }), }, { mat: NewSymBandDense(6, 1, []float64{ 1, math.NaN(), 2, math.NaN(), 3, math.NaN(), 4, math.NaN(), 5, math.NaN(), 6, math.NaN(), }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewSymDense(6, []float64{ 1, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 6, }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewTriBandDense(6, 2, Upper, []float64{ 1, math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), 6, math.NaN(), math.NaN(), }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewTriBandDense(6, 2, Lower, []float64{ math.NaN(), math.NaN(), 1, math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), 6, }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewTriDense(6, Upper, []float64{ 1, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 6, }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewTriDense(6, Lower, []float64{ 1, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 6, }), want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, { mat: NewVecDense(6, []float64{1, 2, 3, 4, 5, 6}), want: NewDense(1, 1, []float64{1}), }, { mat: &basicMatrix{ mat: blas64.General{ Rows: 6, Cols: 6, Stride: 6, Data: []float64{ 1, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 2, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 3, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 4, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 5, math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 6, }, }, capRows: 6, capCols: 6, }, want: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, }), }, } { var got DiagDense got.DiagFrom(test.mat) if !Equal(&got, test.want) { r, c := test.mat.Dims() t.Errorf("unexpected value via mat.Equal for %d×%d %T test %d:\ngot:\n% v\nwant:\n% v", r, c, test.mat, i, Formatted(&got), Formatted(test.want)) } } } // diagDenseViewer takes the view of the Diagonal with the underlying Diagonal // as the DiagDense type. type diagDenseViewer interface { Matrix DiagView() Diagonal } func testDiagView(t *testing.T, cas int, test diagDenseViewer) { // Check the DiagView matches the Diagonal. r, c := test.Dims() diagView := test.DiagView() for i := 0; i < min(r, c); i++ { if diagView.At(i, i) != test.At(i, i) { t.Errorf("Diag mismatch case %d, element %d", cas, i) } } // Check that changes to the diagonal are reflected. offset := 10.0 diag := diagView.(*DiagDense) for i := 0; i < min(r, c); i++ { v := test.At(i, i) diag.SetDiag(i, v+offset) if test.At(i, i) != v+offset { t.Errorf("Diag set mismatch case %d, element %d", cas, i) } } // Check that DiagView and DiagFrom match. var diag2 DiagDense diag2.DiagFrom(test) if !Equal(diag, &diag2) { t.Errorf("Cas %d: DiagView and DiagFrom mismatch", cas) } } func TestDiagonalAtSet(t *testing.T) { t.Parallel() for _, n := range []int{1, 3, 8} { for _, nilstart := range []bool{true, false} { var diag *DiagDense if nilstart { diag = NewDiagDense(n, nil) } else { data := make([]float64, n) diag = NewDiagDense(n, data) // Test the data is used. for i := range data { data[i] = -float64(i) - 1 v := diag.At(i, i) if v != data[i] { t.Errorf("Diag shadow mismatch. Got %v, want %v", v, data[i]) } } } for i := 0; i < n; i++ { for j := 0; j < n; j++ { if i != j { if diag.At(i, j) != 0 { t.Errorf("Diag returned non-zero off diagonal element at %d, %d", i, j) } } v := float64(i) + 1 diag.SetDiag(i, v) v2 := diag.At(i, i) if v2 != v { t.Errorf("Diag at/set mismatch. Got %v, want %v", v, v2) } } } } } } func randDiagDense(size int, rnd *rand.Rand) *DiagDense { t := NewDiagDense(size, nil) for i := 0; i < size; i++ { t.SetDiag(i, rnd.Float64()) } return t } golang-gonum-v1-gonum-0.14.0/mat/doc.go000066400000000000000000000222131450372207100175130ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package mat provides implementations of float64 and complex128 matrix // structures and linear algebra operations on them. // // # Overview // // This section provides a quick overview of the mat package. The following // sections provide more in depth commentary. // // mat provides: // - Interfaces for Matrix classes (Matrix, Symmetric, Triangular) // - Concrete implementations (Dense, SymDense, TriDense, VecDense) // - Methods and functions for using matrix data (Add, Trace, SymRankOne) // - Types for constructing and using matrix factorizations (QR, LU, etc.) // - The complementary types for complex matrices, CMatrix, CSymDense, etc. // // In the documentation below, we use "matrix" as a short-hand for all of // the FooDense types implemented in this package. We use "Matrix" to // refer to the Matrix interface. // // A matrix may be constructed through the corresponding New function. If no // backing array is provided the matrix will be initialized to all zeros. // // // Allocate a zeroed real matrix of size 3×5 // zero := mat.NewDense(3, 5, nil) // // If a backing data slice is provided, the matrix will have those elements. // All matrices are stored in row-major format and users should consider // this when expressing matrix arithmetic to ensure optimal performance. // // // Generate a 6×6 matrix of random values. // data := make([]float64, 36) // for i := range data { // data[i] = rand.NormFloat64() // } // a := mat.NewDense(6, 6, data) // // Operations involving matrix data are implemented as functions when the values // of the matrix remain unchanged // // tr := mat.Trace(a) // // and are implemented as methods when the operation modifies the receiver. // // zero.Copy(a) // // Note that the input arguments to most functions and methods are interfaces // rather than concrete types `func Trace(Matrix)` rather than // `func Trace(*Dense)` allowing flexible use of internal and external // Matrix types. // // When a matrix is the destination or receiver for a function or method, // the operation will panic if the matrix is not the correct size. // An exception to this is when the destination is empty (see below). // // # Empty matrix // // An empty matrix is one that has zero size. Empty matrices are used to allow // the destination of a matrix operation to assume the correct size automatically. // This operation will re-use the backing data, if available, or will allocate // new data if necessary. The IsEmpty method returns whether the given matrix // is empty. The zero-value of a matrix is empty, and is useful for easily // getting the result of matrix operations. // // var c mat.Dense // construct a new zero-value matrix // c.Mul(a, a) // c is automatically adjusted to be the right size // // The Reset method can be used to revert a matrix to an empty matrix. // Reset should not be used when multiple different matrices share the same backing // data slice. This can cause unexpected data modifications after being resized. // An empty matrix can not be sliced even if it does have an adequately sized // backing data slice, but can be expanded using its Grow method if it exists. // // # The Matrix Interfaces // // The Matrix interface is the common link between the concrete types of real // matrices. The Matrix interface is defined by three functions: Dims, which // returns the dimensions of the Matrix, At, which returns the element in the // specified location, and T for returning a Transpose (discussed later). All of // the matrix types can perform these behaviors and so implement the interface. // Methods and functions are designed to use this interface, so in particular the method // // func (m *Dense) Mul(a, b Matrix) // // constructs a *Dense from the result of a multiplication with any Matrix types, // not just *Dense. Where more restrictive requirements must be met, there are also // additional interfaces like Symmetric and Triangular. For example, in // // func (s *SymDense) AddSym(a, b Symmetric) // // the Symmetric interface guarantees a symmetric result. // // The CMatrix interface plays the same role for complex matrices. The difference // is that the CMatrix type has the H method instead T, for returning the conjugate // transpose. // // (Conjugate) Transposes // // The T method is used for transposition on real matrices, and H is used for // conjugate transposition on complex matrices. For example, c.Mul(a.T(), b) computes // c = aᵀ * b. The mat types implement this method implicitly — // see the Transpose and Conjugate types for more details. Note that some // operations have a transpose as part of their definition, as in *SymDense.SymOuterK. // // # Matrix Factorization // // Matrix factorizations, such as the LU decomposition, typically have their own // specific data storage, and so are each implemented as a specific type. The // factorization can be computed through a call to Factorize // // var lu mat.LU // lu.Factorize(a) // // The elements of the factorization can be extracted through methods on the // factorized type, for example *LU.UTo. The factorization types can also be used // directly, as in *Cholesky.SolveTo. Some factorizations can be updated directly, // without needing to update the original matrix and refactorize, for example with // *LU.RankOne. // // # BLAS and LAPACK // // BLAS and LAPACK are the standard APIs for linear algebra routines. Many // operations in mat are implemented using calls to the wrapper functions // in gonum/blas/blas64 and gonum/lapack/lapack64 and their complex equivalents. // By default, blas64 and lapack64 call the native Go implementations of the // routines. Alternatively, it is possible to use C-based implementations of the // APIs through the respective cgo packages and the wrapper packages' "Use" // functions. The Go implementation of LAPACK makes calls through blas64, so if // a cgo BLAS implementation is registered, the lapack64 calls will be partially // executed in Go and partially executed in C. // // # Type Switching // // The Matrix abstraction enables efficiency as well as interoperability. Go's // type reflection capabilities are used to choose the most efficient routine // given the specific concrete types. For example, in // // c.Mul(a, b) // // if a and b both implement RawMatrixer, that is, they can be represented as a // blas64.General, blas64.Gemm (general matrix multiplication) is called, while // instead if b is a RawSymmetricer blas64.Symm is used (general-symmetric // multiplication), and if b is a *VecDense blas64.Gemv is used. // // There are many possible type combinations and special cases. No specific guarantees // are made about the performance of any method, and in particular, note that an // abstract matrix type may be copied into a concrete type of the corresponding // value. If there are specific special cases that are needed, please submit a // pull-request or file an issue. // // # Invariants // // Matrix input arguments to package functions are never directly modified. If an // operation changes Matrix data, the mutated matrix will be the receiver of a // method, or will be the first, dst, argument to a method named with a To suffix. // // For convenience, a matrix may be used as both a receiver and as an input, e.g. // // a.Pow(a, 6) // v.SolveVec(a.T(), v) // // though in many cases this will cause an allocation (see Element Aliasing). // An exception to this rule is Copy, which does not allow a.Copy(a.T()). // // # Element Aliasing // // Most methods in mat modify receiver data. It is forbidden for the modified // data region of the receiver to overlap the used data area of the input // arguments. The exception to this rule is when the method receiver is equal to one // of the input arguments, as in the a.Pow(a, 6) call above, or its implicit transpose. // // This prohibition is to help avoid subtle mistakes when the method needs to read // from and write to the same data region. There are ways to make mistakes using the // mat API, and mat functions will detect and complain about those. // There are many ways to make mistakes by excursion from the mat API via // interaction with raw matrix values. // // If you need to read the rest of this section to understand the behavior of // your program, you are being clever. Don't be clever. If you must be clever, // blas64 and lapack64 may be used to call the behavior directly. // // mat will use the following rules to detect overlap between the receiver and one // of the inputs: // - the input implements one of the Raw methods, and // - the address ranges of the backing data slices overlap, and // - the strides differ or there is an overlap in the used data elements. // // If such an overlap is detected, the method will panic. // // The following cases will not panic: // - the data slices do not overlap, // - there is pointer identity between the receiver and input values after // the value has been untransposed if necessary. // // mat will not attempt to detect element overlap if the input does not implement a // Raw method. Method behavior is undefined if there is undetected overlap. package mat // import "gonum.org/v1/gonum/mat" golang-gonum-v1-gonum-0.14.0/mat/eigen.go000066400000000000000000000233441450372207100200430ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) const ( badFact = "mat: use without successful factorization" noVectors = "mat: eigenvectors not computed" ) // EigenSym is a type for creating and manipulating the Eigen decomposition of // symmetric matrices. type EigenSym struct { vectorsComputed bool values []float64 vectors *Dense } // Factorize computes the eigenvalue decomposition of the symmetric matrix a. // The Eigen decomposition is defined as // // A = P * D * P^-1 // // where D is a diagonal matrix containing the eigenvalues of the matrix, and // P is a matrix of the eigenvectors of A. Factorize computes the eigenvalues // in ascending order. If the vectors input argument is false, the eigenvectors // are not computed. // // Factorize returns whether the decomposition succeeded. If the decomposition // failed, methods that require a successful factorization will panic. func (e *EigenSym) Factorize(a Symmetric, vectors bool) (ok bool) { // kill previous decomposition e.vectorsComputed = false e.values = e.values[:] n := a.SymmetricDim() sd := NewSymDense(n, nil) sd.CopySym(a) jobz := lapack.EVNone if vectors { jobz = lapack.EVCompute } w := make([]float64, n) work := []float64{0} lapack64.Syev(jobz, sd.mat, w, work, -1) work = getFloat64s(int(work[0]), false) ok = lapack64.Syev(jobz, sd.mat, w, work, len(work)) putFloat64s(work) if !ok { e.vectorsComputed = false e.values = nil e.vectors = nil return false } e.vectorsComputed = vectors e.values = w e.vectors = NewDense(n, n, sd.mat.Data) return true } // succFact returns whether the receiver contains a successful factorization. func (e *EigenSym) succFact() bool { return len(e.values) != 0 } // Values extracts the eigenvalues of the factorized matrix in ascending order. // If dst is non-nil, the values are stored in-place into dst. In this case dst // must have length n, otherwise Values will panic. If dst is nil, then a new // slice will be allocated of the proper length and filled with the eigenvalues. // // Values panics if the Eigen decomposition was not successful. func (e *EigenSym) Values(dst []float64) []float64 { if !e.succFact() { panic(badFact) } if dst == nil { dst = make([]float64, len(e.values)) } if len(dst) != len(e.values) { panic(ErrSliceLengthMismatch) } copy(dst, e.values) return dst } // VectorsTo stores the eigenvectors of the decomposition into the columns of // dst. // // If dst is empty, VectorsTo will resize dst to be n×n. When dst is // non-empty, VectorsTo will panic if dst is not n×n. VectorsTo will also // panic if the eigenvectors were not computed during the factorization, // or if the receiver does not contain a successful factorization. func (e *EigenSym) VectorsTo(dst *Dense) { if !e.succFact() { panic(badFact) } if !e.vectorsComputed { panic(noVectors) } r, c := e.vectors.Dims() if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } dst.Copy(e.vectors) } // EigenKind specifies the computation of eigenvectors during factorization. type EigenKind int const ( // EigenNone specifies to not compute any eigenvectors. EigenNone EigenKind = 0 // EigenLeft specifies to compute the left eigenvectors. EigenLeft EigenKind = 1 << iota // EigenRight specifies to compute the right eigenvectors. EigenRight // EigenBoth is a convenience value for computing both eigenvectors. EigenBoth EigenKind = EigenLeft | EigenRight ) // Eigen is a type for creating and using the eigenvalue decomposition of a dense matrix. type Eigen struct { n int // The size of the factorized matrix. kind EigenKind values []complex128 rVectors *CDense lVectors *CDense } // succFact returns whether the receiver contains a successful factorization. func (e *Eigen) succFact() bool { return e.n != 0 } // Factorize computes the eigenvalues of the square matrix a, and optionally // the eigenvectors. // // A right eigenvalue/eigenvector combination is defined by // // A * x_r = λ * x_r // // where x_r is the column vector called an eigenvector, and λ is the corresponding // eigenvalue. // // Similarly, a left eigenvalue/eigenvector combination is defined by // // x_l * A = λ * x_l // // The eigenvalues, but not the eigenvectors, are the same for both decompositions. // // Typically eigenvectors refer to right eigenvectors. // // In all cases, Factorize computes the eigenvalues of the matrix. kind // specifies which of the eigenvectors, if any, to compute. See the EigenKind // documentation for more information. // Eigen panics if the input matrix is not square. // // Factorize returns whether the decomposition succeeded. If the decomposition // failed, methods that require a successful factorization will panic. func (e *Eigen) Factorize(a Matrix, kind EigenKind) (ok bool) { // kill previous factorization. e.n = 0 e.kind = 0 // Copy a because it is modified during the Lapack call. r, c := a.Dims() if r != c { panic(ErrShape) } var sd Dense sd.CloneFrom(a) left := kind&EigenLeft != 0 right := kind&EigenRight != 0 var vl, vr Dense jobvl := lapack.LeftEVNone jobvr := lapack.RightEVNone if left { vl = *NewDense(r, r, nil) jobvl = lapack.LeftEVCompute } if right { vr = *NewDense(c, c, nil) jobvr = lapack.RightEVCompute } wr := getFloat64s(c, false) defer putFloat64s(wr) wi := getFloat64s(c, false) defer putFloat64s(wi) work := []float64{0} lapack64.Geev(jobvl, jobvr, sd.mat, wr, wi, vl.mat, vr.mat, work, -1) work = getFloat64s(int(work[0]), false) first := lapack64.Geev(jobvl, jobvr, sd.mat, wr, wi, vl.mat, vr.mat, work, len(work)) putFloat64s(work) if first != 0 { e.values = nil return false } e.n = r e.kind = kind // Construct complex eigenvalues from float64 data. values := make([]complex128, r) for i, v := range wr { values[i] = complex(v, wi[i]) } e.values = values // Construct complex eigenvectors from float64 data. var cvl, cvr CDense if left { cvl = *NewCDense(r, r, nil) e.complexEigenTo(&cvl, &vl) e.lVectors = &cvl } else { e.lVectors = nil } if right { cvr = *NewCDense(c, c, nil) e.complexEigenTo(&cvr, &vr) e.rVectors = &cvr } else { e.rVectors = nil } return true } // Kind returns the EigenKind of the decomposition. If no decomposition has been // computed, Kind returns -1. func (e *Eigen) Kind() EigenKind { if !e.succFact() { return -1 } return e.kind } // Values extracts the eigenvalues of the factorized matrix. If dst is // non-nil, the values are stored in-place into dst. In this case // dst must have length n, otherwise Values will panic. If dst is // nil, then a new slice will be allocated of the proper length and // filed with the eigenvalues. // // Values panics if the Eigen decomposition was not successful. func (e *Eigen) Values(dst []complex128) []complex128 { if !e.succFact() { panic(badFact) } if dst == nil { dst = make([]complex128, e.n) } if len(dst) != e.n { panic(ErrSliceLengthMismatch) } copy(dst, e.values) return dst } // complexEigenTo extracts the complex eigenvectors from the real matrix d // and stores them into the complex matrix dst. // // The columns of the returned n×n dense matrix contain the eigenvectors of the // decomposition in the same order as the eigenvalues. // If the j-th eigenvalue is real, then // // dst[:,j] = d[:,j], // // and if it is not real, then the elements of the j-th and (j+1)-th columns of d // form complex conjugate pairs and the eigenvectors are recovered as // // dst[:,j] = d[:,j] + i*d[:,j+1], // dst[:,j+1] = d[:,j] - i*d[:,j+1], // // where i is the imaginary unit. func (e *Eigen) complexEigenTo(dst *CDense, d *Dense) { r, c := d.Dims() cr, cc := dst.Dims() if r != cr { panic("size mismatch") } if c != cc { panic("size mismatch") } for j := 0; j < c; j++ { if imag(e.values[j]) == 0 { for i := 0; i < r; i++ { dst.set(i, j, complex(d.at(i, j), 0)) } continue } for i := 0; i < r; i++ { real := d.at(i, j) imag := d.at(i, j+1) dst.set(i, j, complex(real, imag)) dst.set(i, j+1, complex(real, -imag)) } j++ } } // VectorsTo stores the right eigenvectors of the decomposition into the columns // of dst. The computed eigenvectors are normalized to have Euclidean norm equal // to 1 and largest component real. // // If dst is empty, VectorsTo will resize dst to be n×n. When dst is // non-empty, VectorsTo will panic if dst is not n×n. VectorsTo will also // panic if the eigenvectors were not computed during the factorization, // or if the receiver does not contain a successful factorization. func (e *Eigen) VectorsTo(dst *CDense) { if !e.succFact() { panic(badFact) } if e.kind&EigenRight == 0 { panic(noVectors) } if dst.IsEmpty() { dst.ReuseAs(e.n, e.n) } else { r, c := dst.Dims() if r != e.n || c != e.n { panic(ErrShape) } } dst.Copy(e.rVectors) } // LeftVectorsTo stores the left eigenvectors of the decomposition into the // columns of dst. The computed eigenvectors are normalized to have Euclidean // norm equal to 1 and largest component real. // // If dst is empty, LeftVectorsTo will resize dst to be n×n. When dst is // non-empty, LeftVectorsTo will panic if dst is not n×n. LeftVectorsTo will also // panic if the left eigenvectors were not computed during the factorization, // or if the receiver does not contain a successful factorization func (e *Eigen) LeftVectorsTo(dst *CDense) { if !e.succFact() { panic(badFact) } if e.kind&EigenLeft == 0 { panic(noVectors) } if dst.IsEmpty() { dst.ReuseAs(e.n, e.n) } else { r, c := dst.Dims() if r != e.n || c != e.n { panic(ErrShape) } } dst.Copy(e.lVectors) } golang-gonum-v1-gonum-0.14.0/mat/eigen_example_test.go000066400000000000000000000024011450372207100226040ustar00rootroot00000000000000// 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 mat_test import ( "fmt" "log" "gonum.org/v1/gonum/mat" ) func ExampleEigenSym() { a := mat.NewSymDense(2, []float64{ 7, 0.5, 0.5, 1, }) fmt.Printf("A = %v\n\n", mat.Formatted(a, mat.Prefix(" "))) var eigsym mat.EigenSym ok := eigsym.Factorize(a, true) if !ok { log.Fatal("Symmetric eigendecomposition failed") } fmt.Printf("Eigenvalues of A:\n%1.3f\n\n", eigsym.Values(nil)) var ev mat.Dense eigsym.VectorsTo(&ev) fmt.Printf("Eigenvectors of A:\n%1.3f\n\n", mat.Formatted(&ev)) // Output: // A = ⎡ 7 0.5⎤ // ⎣0.5 1⎦ // // Eigenvalues of A: // [0.959 7.041] // // Eigenvectors of A: // ⎡ 0.082 -0.997⎤ // ⎣-0.997 -0.082⎦ // } func ExampleEigen() { a := mat.NewDense(2, 2, []float64{ 1, -1, 1, 1, }) fmt.Printf("A = %v\n\n", mat.Formatted(a, mat.Prefix(" "))) var eig mat.Eigen ok := eig.Factorize(a, mat.EigenLeft) if !ok { log.Fatal("Eigendecomposition failed") } fmt.Printf("Eigenvalues of A:\n%v\n", eig.Values(nil)) // Output: // A = ⎡ 1 -1⎤ // ⎣ 1 1⎦ // // Eigenvalues of A: // [(1+1i) (1-1i)] } golang-gonum-v1-gonum-0.14.0/mat/eigen_test.go000066400000000000000000000131441450372207100210770ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) func TestEigen(t *testing.T) { t.Parallel() for i, test := range []struct { a *Dense values []complex128 left *CDense right *CDense }{ { a: NewDense(3, 3, []float64{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }), values: []complex128{1, 1, 1}, left: NewCDense(3, 3, []complex128{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }), right: NewCDense(3, 3, []complex128{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }), }, { // Values compared with numpy. a: NewDense(4, 4, []float64{ 0.9025, 0.025, 0.475, 0.0475, 0.0475, 0.475, 0.475, 0.0025, 0.0475, 0.025, 0.025, 0.9025, 0.0025, 0.475, 0.025, 0.0475, }), values: []complex128{1, 0.7300317046114154, -0.1400158523057075 + 0.452854925738716i, -0.1400158523057075 - 0.452854925738716i}, left: NewCDense(4, 4, []complex128{ 0.5, -0.3135167160788313, -0.02058121780136903 + 0.004580939300127051i, -0.02058121780136903 - 0.004580939300127051i, 0.5, 0.7842199280224781, 0.37551026954193356 - 0.2924634904103879i, 0.37551026954193356 + 0.2924634904103879i, 0.5, 0.33202200780783525, 0.16052616322784943 + 0.3881393645202527i, 0.16052616322784943 - 0.3881393645202527i, 0.5, 0.42008065840123954, -0.7723935249234155, -0.7723935249234155, }), right: NewCDense(4, 4, []complex128{ 0.9476399565969628, -0.8637347682162745, -0.2688989440320280 - 0.1282234938321029i, -0.2688989440320280 + 0.1282234938321029i, 0.2394935907064427, 0.3457075153704627, -0.3621360383713332 - 0.2583198964498771i, -0.3621360383713332 + 0.2583198964498771i, 0.1692743801716332, 0.2706851011641580, 0.7426369401030960, 0.7426369401030960, 0.1263626404003607, 0.2473421516816520, -0.1116019576997347 + 0.3865433902819795i, -0.1116019576997347 - 0.3865433902819795i, }), }, } { var e1, e2, e3, e4 Eigen ok := e1.Factorize(test.a, EigenBoth) if !ok { panic("bad factorization") } e2.Factorize(test.a, EigenRight) e3.Factorize(test.a, EigenLeft) e4.Factorize(test.a, EigenNone) v1 := e1.Values(nil) if !cmplxEqualTol(v1, test.values, 1e-14) { t.Errorf("eigenvalue mismatch. Case %v", i) } var left CDense e1.LeftVectorsTo(&left) if !CEqualApprox(&left, test.left, 1e-14) { t.Errorf("left eigenvector mismatch. Case %v", i) } var right CDense e1.VectorsTo(&right) if !CEqualApprox(&right, test.right, 1e-14) { t.Errorf("right eigenvector mismatch. Case %v", i) } // Check that the eigenvectors and values are the same in all combinations. if !cmplxEqual(v1, e2.Values(nil)) { t.Errorf("eigenvector mismatch. Case %v", i) } if !cmplxEqual(v1, e3.Values(nil)) { t.Errorf("eigenvector mismatch. Case %v", i) } if !cmplxEqual(v1, e4.Values(nil)) { t.Errorf("eigenvector mismatch. Case %v", i) } var right2 CDense e2.VectorsTo(&right2) if !CEqual(&right, &right2) { t.Errorf("right eigenvector mismatch. Case %v", i) } var left3 CDense e3.LeftVectorsTo(&left3) if !CEqual(&left, &left3) { t.Errorf("left eigenvector mismatch. Case %v", i) } // TODO(btracey): Also add in a test for correctness when #308 is // resolved and we have a CMat.Mul(). } } func cmplxEqual(v1, v2 []complex128) bool { for i, v := range v1 { if v != v2[i] { return false } } return true } func cmplxEqualTol(v1, v2 []complex128, tol float64) bool { for i, v := range v1 { if !cEqualWithinAbsOrRel(v, v2[i], tol, tol) { return false } } return true } func TestSymEigen(t *testing.T) { t.Parallel() // Hand coded tests with results from lapack. for _, test := range []struct { mat *SymDense values []float64 vectors *Dense }{ { mat: NewSymDense(3, []float64{8, 2, 4, 2, 6, 10, 4, 10, 5}), values: []float64{-4.707679201365891, 6.294580208480216, 17.413098992885672}, vectors: NewDense(3, 3, []float64{ -0.127343483135656, -0.902414161226903, -0.411621572466779, -0.664177720955769, 0.385801900032553, -0.640331827193739, 0.736648893495999, 0.191847792659746, -0.648492738712395, }), }, } { var es EigenSym ok := es.Factorize(test.mat, true) if !ok { t.Errorf("bad factorization") } if !floats.EqualApprox(test.values, es.values, 1e-14) { t.Errorf("Eigenvalue mismatch") } if !EqualApprox(test.vectors, es.vectors, 1e-14) { t.Errorf("Eigenvector mismatch") } var es2 EigenSym es2.Factorize(test.mat, false) if !floats.EqualApprox(es2.values, es.values, 1e-14) { t.Errorf("Eigenvalue mismatch when no vectors computed") } } // Randomized tests rnd := rand.New(rand.NewSource(1)) for _, n := range []int{3, 5, 10, 70} { for cas := 0; cas < 10; cas++ { a := make([]float64, n*n) for i := range a { a[i] = rnd.NormFloat64() } s := NewSymDense(n, a) var es EigenSym ok := es.Factorize(s, true) if !ok { t.Errorf("Bad test") } // Check that the eigenvectors are orthonormal. if !isOrthonormal(es.vectors, 1e-8) { t.Errorf("Eigenvectors not orthonormal") } // Check that the eigenvalues are actually eigenvalues. for i := 0; i < n; i++ { v := NewVecDense(n, Col(nil, i, es.vectors)) var m VecDense m.MulVec(s, v) var scal VecDense scal.ScaleVec(es.values[i], v) if !EqualApprox(&m, &scal, 1e-8) { t.Errorf("Eigenvalue does not match") } } // Check that the eigenvalues are in ascending order. if !sort.Float64sAreSorted(es.values) { t.Errorf("Eigenvalues not ascending") } } } } golang-gonum-v1-gonum-0.14.0/mat/errors.go000066400000000000000000000127471450372207100202750ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "runtime" "gonum.org/v1/gonum/lapack" ) // Condition is the condition number of a matrix. The condition // number is defined as |A| * |A^-1|. // // One important use of Condition is during linear solve routines (finding x such // that A * x = b). The condition number of A indicates the accuracy of // the computed solution. A Condition error will be returned if the condition // number of A is sufficiently large. If A is exactly singular to working precision, // Condition == ∞, and the solve algorithm may have completed early. If Condition // is large and finite the solve algorithm will be performed, but the computed // solution may be inaccurate. Due to the nature of finite precision arithmetic, // the value of Condition is only an approximate test of singularity. type Condition float64 func (c Condition) Error() string { return fmt.Sprintf("matrix singular or near-singular with condition number %.4e", c) } // ConditionTolerance is the tolerance limit of the condition number. If the // condition number is above this value, the matrix is considered singular. const ConditionTolerance = 1e16 const ( // CondNorm is the matrix norm used for computing the condition number by routines // in the matrix packages. CondNorm = lapack.MaxRowSum // CondNormTrans is the norm used to compute on Aᵀ to get the same result as // computing CondNorm on A. CondNormTrans = lapack.MaxColumnSum ) const stackTraceBufferSize = 1 << 20 // Maybe will recover a panic with a type mat.Error from fn, and return this error // as the Err field of an ErrorStack. The stack trace for the panicking function will be // recovered and placed in the StackTrace field. Any other error is re-panicked. func Maybe(fn func()) (err error) { defer func() { if r := recover(); r != nil { if e, ok := r.(Error); ok { if e.string == "" { panic("mat: invalid error") } buf := make([]byte, stackTraceBufferSize) n := runtime.Stack(buf, false) err = ErrorStack{Err: e, StackTrace: string(buf[:n])} return } panic(r) } }() fn() return } // MaybeFloat will recover a panic with a type mat.Error from fn, and return this error // as the Err field of an ErrorStack. The stack trace for the panicking function will be // recovered and placed in the StackTrace field. Any other error is re-panicked. func MaybeFloat(fn func() float64) (f float64, err error) { defer func() { if r := recover(); r != nil { if e, ok := r.(Error); ok { if e.string == "" { panic("mat: invalid error") } buf := make([]byte, stackTraceBufferSize) n := runtime.Stack(buf, false) err = ErrorStack{Err: e, StackTrace: string(buf[:n])} return } panic(r) } }() return fn(), nil } // MaybeComplex will recover a panic with a type mat.Error from fn, and return this error // as the Err field of an ErrorStack. The stack trace for the panicking function will be // recovered and placed in the StackTrace field. Any other error is re-panicked. func MaybeComplex(fn func() complex128) (f complex128, err error) { defer func() { if r := recover(); r != nil { if e, ok := r.(Error); ok { if e.string == "" { panic("mat: invalid error") } buf := make([]byte, stackTraceBufferSize) n := runtime.Stack(buf, false) err = ErrorStack{Err: e, StackTrace: string(buf[:n])} return } panic(r) } }() return fn(), nil } // Error represents matrix handling errors. These errors can be recovered by Maybe wrappers. type Error struct{ string } func (err Error) Error() string { return err.string } var ( ErrNegativeDimension = Error{"mat: negative dimension"} ErrIndexOutOfRange = Error{"mat: index out of range"} ErrReuseNonEmpty = Error{"mat: reuse of non-empty matrix"} ErrRowAccess = Error{"mat: row index out of range"} ErrColAccess = Error{"mat: column index out of range"} ErrVectorAccess = Error{"mat: vector index out of range"} ErrZeroLength = Error{"mat: zero length in matrix dimension"} ErrRowLength = Error{"mat: row length mismatch"} ErrColLength = Error{"mat: col length mismatch"} ErrSquare = Error{"mat: expect square matrix"} ErrNormOrder = Error{"mat: invalid norm order for matrix"} ErrSingular = Error{"mat: matrix is singular"} ErrShape = Error{"mat: dimension mismatch"} ErrIllegalStride = Error{"mat: illegal stride"} ErrPivot = Error{"mat: malformed pivot list"} ErrTriangle = Error{"mat: triangular storage mismatch"} ErrTriangleSet = Error{"mat: triangular set out of bounds"} ErrBandwidth = Error{"mat: bandwidth out of range"} ErrBandSet = Error{"mat: band set out of bounds"} ErrDiagSet = Error{"mat: diagonal set out of bounds"} ErrSliceLengthMismatch = Error{"mat: input slice length mismatch"} ErrNotPSD = Error{"mat: input not positive symmetric definite"} ErrFailedEigen = Error{"mat: eigendecomposition not successful"} ) // ErrorStack represents matrix handling errors that have been recovered by Maybe wrappers. type ErrorStack struct { Err error // StackTrace is the stack trace // recovered by Maybe, MaybeFloat // or MaybeComplex. StackTrace string } func (err ErrorStack) Error() string { return err.Err.Error() } const badCap = "mat: bad capacity" golang-gonum-v1-gonum-0.14.0/mat/errors_test.go000066400000000000000000000021651450372207100213250ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import "testing" func leaksPanic(fn func()) (panicked bool) { defer func() { r := recover() panicked = r != nil }() _ = Maybe(fn) return } func TestMaybe(t *testing.T) { t.Parallel() for i, test := range []struct { fn func() panics bool errors bool }{ { fn: func() {}, panics: false, errors: false, }, { fn: func() { panic("panic") }, panics: true, errors: false, }, { fn: func() { panic(Error{"panic"}) }, panics: false, errors: true, }, } { panicked := leaksPanic(test.fn) if panicked != test.panics { t.Errorf("unexpected panic state for test %d: got: panicked=%t want: panicked=%t", i, panicked, test.panics) } if test.errors { err := Maybe(test.fn) stack, ok := err.(ErrorStack) if !ok { t.Errorf("unexpected error type: got:%T want:%T", stack, ErrorStack{}) } if stack.StackTrace == "" { t.Error("expected non-empty stack trace") } } } } golang-gonum-v1-gonum-0.14.0/mat/fao_data_test.go000066400000000000000000000102751450372207100215500ustar00rootroot00000000000000// 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 mat_test import "gonum.org/v1/gonum/mat" // FAO is a dataset extracted from Food and Agriculture Organization of the // United Nations "FAO Statistical Pocketbook: World Food and Agriculture 2015". // pp49-52. var FAO = struct { Africa *mat.Dense Asia *mat.Dense LatinAmericaCaribbean *mat.Dense Oceania *mat.Dense }{ Africa: mat.NewDense(21, 3, []float64{ // 1990, 2000, 2014 35.3, 38, 30.7, // Employment in agriculture (%) 9.2, 20.3, 25.2, // Employment in agriculture, female (%) 3163, 14718, 20667, // Energy consump, power irrigation (mln kWh) 2597, 2717, 2903, // Dietary energy supply (kcal/pc/day) 113, 116, 123, // Average dietary energy supply adequacy (%) 58, 55, 52, // Dietary en supp, cereals/roots/tubers (%) 18.6, 15, 10.8, // Prevalence of undernourishment (%) 8832, 10241, 13915, // GDP per capita (US$, PPP) -0.4, -0.2, 50.7, // Cereal import dependency ratio (%) 78.5, 83, 88.7, // Improved water source (% pop) // Production indices (2004-06=100) 73, 90, 121, // Net food 72, 89, 123, // Net crops 82, 92, 123, // Cereals 51, 77, 141, // Vegetable oils 74, 94, 119, // Roots and tubers 58, 86, 127, // Fruit and vegetables 86, 93, 132, // Sugar 76, 92, 115, // Livestock 83, 89, 114, // Milk 74, 91, 118, // Meat 72, 92, 119, // Fish }), Asia: mat.NewDense(21, 3, []float64{ // 1990, 2000, 2014 30.9, 24.5, 27.6, // Employment in agriculture (%) 40.9, 29.4, 31.1, // Employment in agriculture, female (%) 7614, 38316, 82411, // Energy consump, power irrigation (mln kWh) 2320, 2402, 2581, // Dietary energy supply (kcal/pc/day) 107, 110, 117, // Average dietary energy supply adequacy (%) 66, 65, 63, // Dietary en supp, cereals/roots/tubers (%) 27.6, 25.7, 19.8, // Prevalence of undernourishment (%) 3315, 3421, 4575, // GDP per capita (US$, PPP) 25.9, 28.1, 42, // Cereal import dependency ratio (%) 55.5, 61.1, 68.7, // Improved water source (% pop) // Production indices (2004-06=100) 60, 82, 129, // Net food 59, 82, 127, // Net crops 66, 79, 131, // Cereals 58, 79, 128, // Vegetable oils 50, 80, 133, // Roots and tubers 58, 82, 124, // Fruit and vegetables 76, 94, 114, // Sugar 65, 84, 126, // Livestock 59, 77, 125, // Milk 67, 87, 127, // Meat 65, 90, 119, // Fish }), LatinAmericaCaribbean: mat.NewDense(14, 3, []float64{ // 1990, 2000, 2014 19.5, 14.2, 15.8, // Employment in agriculture (%) 13.7, 6.2, 7.6, // Employment in agriculture, female (%) 2669, 2787, 3069, // Dietary energy supply (kcal/pc/day) 117, 120, 129, // Average dietary energy supply adequacy (%) 42, 41, 40, // Dietary en supp, cereals/roots/tubers (%) 14.7, 12.1, 5.5, // Prevalence of undernourishment (%) 9837, 10976, 13915, // GDP per capita (US$, PPP) 13, 12, 49.7, // Cereal import dependency ratio (%) 85.1, 89.8, 94, // Improved water source (% pop) // Production indices (2004-06=100) 60, 83, 129, // Net food 64, 83, 131, // Net crops 62, 88, 139, // Cereals 58, 84, 123, // Livestock 82, 107, 71, // Fish }), Oceania: mat.NewDense(21, 3, []float64{ // 1990, 2000, 2014 6.2, 17.1, 3.8, // Employment in agriculture (%) 4.5, 3.9, 4.4, // Employment in agriculture, female (%) 415, 1028, 8667, // Energy consump, power irrigation (mln kWh) 2454, 2436, 2542, // Dietary energy supply (kcal/pc/day) 113, 112, 114, // Average dietary energy supply adequacy (%) 49, 50, 48, // Dietary en supp, cereals/roots/tubers (%) 15.7, 16.1, 14.2, // Prevalence of undernourishment (%) 2269, 2536, 3110, // GDP per capita (US$, PPP) 95.2, 95.9, 95.4, // Cereal import dependency ratio (%) 49.7, 53.2, 55.5, // Improved water source (% pop) // Production indices (2004-06=100) 72, 99, 116, // Net food 69, 105, 126, // Net crops 77, 113, 117, // Cereals 41, 122, 215, // Vegetable oils 80, 90, 110, // Roots and tubers 66, 88, 104, // Fruit and vegetables 70, 104, 71, // Sugar 79, 97, 107, // Livestock 56, 92, 113, // Milk 79, 96, 105, // Meat 51, 78, 85, // Fish }), } golang-gonum-v1-gonum-0.14.0/mat/format.go000066400000000000000000000275211450372207100202450ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "strconv" "strings" ) // Formatted returns a fmt.Formatter for the matrix m using the given options. func Formatted(m Matrix, options ...FormatOption) fmt.Formatter { f := formatter{ matrix: m, dot: '.', } for _, o := range options { o(&f) } return f } type formatter struct { matrix Matrix prefix string margin int dot byte squeeze bool format func(m Matrix, prefix string, margin int, dot byte, squeeze bool, fs fmt.State, c rune) } // FormatOption is a functional option for matrix formatting. type FormatOption func(*formatter) // Prefix sets the formatted prefix to the string p. Prefix is a string that is prepended to // each line of output after the first line. func Prefix(p string) FormatOption { return func(f *formatter) { f.prefix = p } } // Excerpt sets the maximum number of rows and columns to print at the margins of the matrix // to m. If m is zero or less all elements are printed. func Excerpt(m int) FormatOption { return func(f *formatter) { f.margin = m } } // DotByte sets the dot character to b. The dot character is used to replace zero elements // if the result is printed with the fmt ' ' verb flag. Without a DotByte option, the default // dot character is '.'. func DotByte(b byte) FormatOption { return func(f *formatter) { f.dot = b } } // Squeeze sets the printing behavior to minimise column width for each individual column. func Squeeze() FormatOption { return func(f *formatter) { f.squeeze = true } } // FormatMATLAB sets the printing behavior to output MATLAB syntax. If MATLAB syntax is // specified, the ' ' verb flag and Excerpt option are ignored. If the alternative syntax // verb flag, '#' is used the matrix is formatted in rows and columns. func FormatMATLAB() FormatOption { return func(f *formatter) { f.format = formatMATLAB } } // FormatPython sets the printing behavior to output Python syntax. If Python syntax is // specified, the ' ' verb flag and Excerpt option are ignored. If the alternative syntax // verb flag, '#' is used the matrix is formatted in rows and columns. func FormatPython() FormatOption { return func(f *formatter) { f.format = formatPython } } // Format satisfies the fmt.Formatter interface. func (f formatter) Format(fs fmt.State, c rune) { if c == 'v' && fs.Flag('#') && f.format == nil { fmt.Fprintf(fs, "%#v", f.matrix) return } if f.format == nil { f.format = format } f.format(f.matrix, f.prefix, f.margin, f.dot, f.squeeze, fs, c) } // format prints a pretty representation of m to the fs io.Writer. The format character c // specifies the numerical representation of elements; valid values are those for float64 // specified in the fmt package, with their associated flags. In addition to this, a space // preceding a verb indicates that zero values should be represented by the dot character. // The printed range of the matrix can be limited by specifying a positive value for margin; // If margin is greater than zero, only the first and last margin rows/columns of the matrix // are output. If squeeze is true, column widths are determined on a per-column basis. // // format will not provide Go syntax output. func format(m Matrix, prefix string, margin int, dot byte, squeeze bool, fs fmt.State, c rune) { rows, cols := m.Dims() var printed int if margin <= 0 { printed = rows if cols > printed { printed = cols } } else { printed = margin } prec, pOk := fs.Precision() if !pOk { prec = -1 } var ( maxWidth int widths widther buf, pad []byte ) if squeeze { widths = make(columnWidth, cols) } else { widths = new(uniformWidth) } switch c { case 'v', 'e', 'E', 'f', 'F', 'g', 'G': if c == 'v' { buf, maxWidth = maxCellWidth(m, 'g', printed, prec, widths) } else { buf, maxWidth = maxCellWidth(m, c, printed, prec, widths) } default: fmt.Fprintf(fs, "%%!%c(%T=Dims(%d, %d))", c, m, rows, cols) return } width, _ := fs.Width() width = max(width, maxWidth) pad = make([]byte, max(width, 2)) for i := range pad { pad[i] = ' ' } first := true if rows > 2*printed || cols > 2*printed { first = false fmt.Fprintf(fs, "Dims(%d, %d)\n", rows, cols) } skipZero := fs.Flag(' ') for i := 0; i < rows; i++ { if !first { fmt.Fprint(fs, prefix) } first = false var el string switch { case rows == 1: fmt.Fprint(fs, "[") el = "]" case i == 0: fmt.Fprint(fs, "⎡") el = "⎤\n" case i < rows-1: fmt.Fprint(fs, "⎢") el = "⎥\n" default: fmt.Fprint(fs, "⎣") el = "⎦" } for j := 0; j < cols; j++ { if j >= printed && j < cols-printed { j = cols - printed - 1 if i == 0 || i == rows-1 { fmt.Fprint(fs, "... ... ") } else { fmt.Fprint(fs, " ") } continue } v := m.At(i, j) if v == 0 && skipZero { buf = buf[:1] buf[0] = dot } else { if c == 'v' { buf = strconv.AppendFloat(buf[:0], v, 'g', prec, 64) } else { buf = strconv.AppendFloat(buf[:0], v, byte(c), prec, 64) } } if fs.Flag('-') { fs.Write(buf) fs.Write(pad[:widths.width(j)-len(buf)]) } else { fs.Write(pad[:widths.width(j)-len(buf)]) fs.Write(buf) } if j < cols-1 { fs.Write(pad[:2]) } } fmt.Fprint(fs, el) if i >= printed-1 && i < rows-printed && 2*printed < rows { i = rows - printed - 1 fmt.Fprintf(fs, "%s .\n%[1]s .\n%[1]s .\n", prefix) continue } } } // formatMATLAB prints a MATLAB representation of m to the fs io.Writer. The format character c // specifies the numerical representation of elements; valid values are those for float64 // specified in the fmt package, with their associated flags. // The printed range of the matrix can be limited by specifying a positive value for margin; // If squeeze is true, column widths are determined on a per-column basis. // // formatMATLAB will not provide Go syntax output. func formatMATLAB(m Matrix, prefix string, _ int, _ byte, squeeze bool, fs fmt.State, c rune) { rows, cols := m.Dims() prec, pOk := fs.Precision() width, _ := fs.Width() if !fs.Flag('#') { switch c { case 'v', 'e', 'E', 'f', 'F', 'g', 'G': default: fmt.Fprintf(fs, "%%!%c(%T=Dims(%d, %d))", c, m, rows, cols) return } format := fmtString(fs, c, prec, width) fs.Write([]byte{'['}) for i := 0; i < rows; i++ { if i != 0 { fs.Write([]byte("; ")) } for j := 0; j < cols; j++ { if j != 0 { fs.Write([]byte{' '}) } fmt.Fprintf(fs, format, m.At(i, j)) } } fs.Write([]byte{']'}) return } if !pOk { prec = -1 } printed := rows if cols > printed { printed = cols } var ( maxWidth int widths widther buf, pad []byte ) if squeeze { widths = make(columnWidth, cols) } else { widths = new(uniformWidth) } switch c { case 'v', 'e', 'E', 'f', 'F', 'g', 'G': if c == 'v' { buf, maxWidth = maxCellWidth(m, 'g', printed, prec, widths) } else { buf, maxWidth = maxCellWidth(m, c, printed, prec, widths) } default: fmt.Fprintf(fs, "%%!%c(%T=Dims(%d, %d))", c, m, rows, cols) return } width = max(width, maxWidth) pad = make([]byte, max(width, 1)) for i := range pad { pad[i] = ' ' } for i := 0; i < rows; i++ { var el string switch { case rows == 1: fmt.Fprint(fs, "[") el = "]" case i == 0: fmt.Fprint(fs, "[\n"+prefix+" ") el = "\n" case i < rows-1: fmt.Fprint(fs, prefix+" ") el = "\n" default: fmt.Fprint(fs, prefix+" ") el = "\n" + prefix + "]" } for j := 0; j < cols; j++ { v := m.At(i, j) if c == 'v' { buf = strconv.AppendFloat(buf[:0], v, 'g', prec, 64) } else { buf = strconv.AppendFloat(buf[:0], v, byte(c), prec, 64) } if fs.Flag('-') { fs.Write(buf) fs.Write(pad[:widths.width(j)-len(buf)]) } else { fs.Write(pad[:widths.width(j)-len(buf)]) fs.Write(buf) } if j < cols-1 { fs.Write(pad[:1]) } } fmt.Fprint(fs, el) } } // formatPython prints a Python representation of m to the fs io.Writer. The format character c // specifies the numerical representation of elements; valid values are those for float64 // specified in the fmt package, with their associated flags. // The printed range of the matrix can be limited by specifying a positive value for margin; // If squeeze is true, column widths are determined on a per-column basis. // // formatPython will not provide Go syntax output. func formatPython(m Matrix, prefix string, _ int, _ byte, squeeze bool, fs fmt.State, c rune) { rows, cols := m.Dims() prec, pOk := fs.Precision() width, _ := fs.Width() if !fs.Flag('#') { switch c { case 'v', 'e', 'E', 'f', 'F', 'g', 'G': default: fmt.Fprintf(fs, "%%!%c(%T=Dims(%d, %d))", c, m, rows, cols) return } format := fmtString(fs, c, prec, width) fs.Write([]byte{'['}) if rows > 1 { fs.Write([]byte{'['}) } for i := 0; i < rows; i++ { if i != 0 { fs.Write([]byte("], [")) } for j := 0; j < cols; j++ { if j != 0 { fs.Write([]byte(", ")) } fmt.Fprintf(fs, format, m.At(i, j)) } } if rows > 1 { fs.Write([]byte{']'}) } fs.Write([]byte{']'}) return } if !pOk { prec = -1 } printed := rows if cols > printed { printed = cols } var ( maxWidth int widths widther buf, pad []byte ) if squeeze { widths = make(columnWidth, cols) } else { widths = new(uniformWidth) } switch c { case 'v', 'e', 'E', 'f', 'F', 'g', 'G': if c == 'v' { buf, maxWidth = maxCellWidth(m, 'g', printed, prec, widths) } else { buf, maxWidth = maxCellWidth(m, c, printed, prec, widths) } default: fmt.Fprintf(fs, "%%!%c(%T=Dims(%d, %d))", c, m, rows, cols) return } width = max(width, maxWidth) pad = make([]byte, max(width, 1)) for i := range pad { pad[i] = ' ' } for i := 0; i < rows; i++ { if i != 0 { fmt.Fprint(fs, prefix) } var el string switch { case rows == 1: fmt.Fprint(fs, "[") el = "]" case i == 0: fmt.Fprint(fs, "[[") el = "],\n" case i < rows-1: fmt.Fprint(fs, " [") el = "],\n" default: fmt.Fprint(fs, " [") el = "]]" } for j := 0; j < cols; j++ { v := m.At(i, j) if c == 'v' { buf = strconv.AppendFloat(buf[:0], v, 'g', prec, 64) } else { buf = strconv.AppendFloat(buf[:0], v, byte(c), prec, 64) } if fs.Flag('-') { fs.Write(buf) fs.Write(pad[:widths.width(j)-len(buf)]) } else { fs.Write(pad[:widths.width(j)-len(buf)]) fs.Write(buf) } if j < cols-1 { fs.Write([]byte{','}) fs.Write(pad[:1]) } } fmt.Fprint(fs, el) } } // This is horrible, but it's what we have. func fmtString(fs fmt.State, c rune, prec, width int) string { var b strings.Builder b.WriteByte('%') for _, f := range "0+- " { if fs.Flag(int(f)) { b.WriteByte(byte(f)) } } if width >= 0 { fmt.Fprint(&b, width) } if prec >= 0 { b.WriteByte('.') if prec > 0 { fmt.Fprint(&b, prec) } } b.WriteRune(c) return b.String() } func maxCellWidth(m Matrix, c rune, printed, prec int, w widther) ([]byte, int) { var ( buf = make([]byte, 0, 64) rows, cols = m.Dims() max int ) for i := 0; i < rows; i++ { if i >= printed-1 && i < rows-printed && 2*printed < rows { i = rows - printed - 1 continue } for j := 0; j < cols; j++ { if j >= printed && j < cols-printed { continue } buf = strconv.AppendFloat(buf, m.At(i, j), byte(c), prec, 64) if len(buf) > max { max = len(buf) } if len(buf) > w.width(j) { w.setWidth(j, len(buf)) } buf = buf[:0] } } return buf, max } type widther interface { width(i int) int setWidth(i, w int) } type uniformWidth int func (u *uniformWidth) width(_ int) int { return int(*u) } func (u *uniformWidth) setWidth(_, w int) { *u = uniformWidth(w) } type columnWidth []int func (c columnWidth) width(i int) int { return c[i] } func (c columnWidth) setWidth(i, w int) { c[i] = w } golang-gonum-v1-gonum-0.14.0/mat/format_example_test.go000066400000000000000000000075711450372207100230220ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "gonum.org/v1/gonum/mat" ) func ExampleFormatted() { a := mat.NewDense(3, 3, []float64{1, 2, 3, 0, 4, 5, 0, 0, 6}) // Create a matrix formatting value with a prefix and calculating each column // width individually... fa := mat.Formatted(a, mat.Prefix(" "), mat.Squeeze()) // and then print with and without zero value elements. fmt.Printf("with all values:\na = %v\n\n", fa) fmt.Printf("with only non-zero values:\na = % v\n\n", fa) // Modify the matrix... a.Set(0, 2, 0) // and print it without zero value elements. fmt.Printf("after modification with only non-zero values:\na = % v\n\n", fa) // Modify the matrix again... a.Set(0, 2, 123.456) // and print it using scientific notation for large exponents. fmt.Printf("after modification with scientific notation:\na = %.2g\n\n", fa) // See golang.org/pkg/fmt/ floating-point verbs for a comprehensive list. // Output: // with all values: // a = ⎡1 2 3⎤ // ⎢0 4 5⎥ // ⎣0 0 6⎦ // // with only non-zero values: // a = ⎡1 2 3⎤ // ⎢. 4 5⎥ // ⎣. . 6⎦ // // after modification with only non-zero values: // a = ⎡1 2 .⎤ // ⎢. 4 5⎥ // ⎣. . 6⎦ // // after modification with scientific notation: // a = ⎡1 2 1.2e+02⎤ // ⎢0 4 5⎥ // ⎣0 0 6⎦ } func ExampleFormatted_mATLAB() { a := mat.NewDense(3, 3, []float64{1, 2, 3, 0, 4, 5, 0, 0, 6}) // Create a matrix formatting value using MATLAB format... fa := mat.Formatted(a, mat.FormatMATLAB()) // and then print with and without layout formatting. fmt.Printf("standard syntax:\na = %v\n\n", fa) fmt.Printf("layout syntax:\na = %#v\n\n", fa) // Output: // standard syntax: // a = [1 2 3; 0 4 5; 0 0 6] // // layout syntax: // a = [ // 1 2 3 // 0 4 5 // 0 0 6 // ] } func ExampleFormatted_python() { a := mat.NewDense(3, 3, []float64{1, 2, 3, 0, 4, 5, 0, 0, 6}) // Create a matrix formatting value with a prefix using Python format... fa := mat.Formatted(a, mat.Prefix(" "), mat.FormatPython()) // and then print with and without layout formatting. fmt.Printf("standard syntax:\na = %v\n\n", fa) fmt.Printf("layout syntax:\na = %#v\n\n", fa) // Output: // standard syntax: // a = [[1, 2, 3], [0, 4, 5], [0, 0, 6]] // // layout syntax: // a = [[1, 2, 3], // [0, 4, 5], // [0, 0, 6]] } func ExampleExcerpt() { // Excerpt allows diagnostic display of very large // matrices and vectors. // The big matrix is too large to properly print... big := mat.NewDense(100, 100, nil) for i := 0; i < 100; i++ { big.Set(i, i, 1) } // so only print corner excerpts of the matrix. fmt.Printf("excerpt big identity matrix: %v\n\n", mat.Formatted(big, mat.Prefix(" "), mat.Excerpt(3))) // The long vector is also too large, ... long := mat.NewVecDense(100, nil) for i := 0; i < 100; i++ { long.SetVec(i, float64(i)) } // ... so print end excerpts of the vector, fmt.Printf("excerpt long column vector: %v\n\n", mat.Formatted(long, mat.Prefix(" "), mat.Excerpt(3))) // or its transpose. fmt.Printf("excerpt long row vector: %v\n", mat.Formatted(long.T(), mat.Prefix(" "), mat.Excerpt(3))) // Output: // excerpt big identity matrix: Dims(100, 100) // ⎡1 0 0 ... ... 0 0 0⎤ // ⎢0 1 0 0 0 0⎥ // ⎢0 0 1 0 0 0⎥ // . // . // . // ⎢0 0 0 1 0 0⎥ // ⎢0 0 0 0 1 0⎥ // ⎣0 0 0 ... ... 0 0 1⎦ // // excerpt long column vector: Dims(100, 1) // ⎡ 0⎤ // ⎢ 1⎥ // ⎢ 2⎥ // . // . // . // ⎢97⎥ // ⎢98⎥ // ⎣99⎦ // // excerpt long row vector: Dims(1, 100) // [ 0 1 2 ... ... 97 98 99] } golang-gonum-v1-gonum-0.14.0/mat/format_test.go000066400000000000000000000176631450372207100213120ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "math" "testing" ) func TestFormat(t *testing.T) { t.Parallel() type rp struct { format string output string } sqrt := func(_, _ int, v float64) float64 { return math.Sqrt(v) } for i, test := range []struct { m fmt.Formatter rep []rp }{ // Dense matrix representation { m: Formatted(NewDense(3, 3, []float64{0, 0, 0, 0, 0, 0, 0, 0, 0})), rep: []rp{ {"%v", "⎡0 0 0⎤\n⎢0 0 0⎥\n⎣0 0 0⎦"}, {"% f", "⎡. . .⎤\n⎢. . .⎥\n⎣. . .⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(3, 3, nil))}, {"%s", "%!s(*mat.Dense=Dims(3, 3))"}, }, }, { m: Formatted(NewDense(3, 3, []float64{1, 1, 1, 1, 1, 1, 1, 1, 1})), rep: []rp{ {"%v", "⎡1 1 1⎤\n⎢1 1 1⎥\n⎣1 1 1⎦"}, {"% f", "⎡1 1 1⎤\n⎢1 1 1⎥\n⎣1 1 1⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(3, 3, []float64{1, 1, 1, 1, 1, 1, 1, 1, 1}))}, }, }, { m: Formatted(NewDense(3, 3, []float64{1, 1, 1, 1, 1, 1, 1, 1, 1}), Prefix("\t")), rep: []rp{ {"%v", "⎡1 1 1⎤\n\t⎢1 1 1⎥\n\t⎣1 1 1⎦"}, {"% f", "⎡1 1 1⎤\n\t⎢1 1 1⎥\n\t⎣1 1 1⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(3, 3, []float64{1, 1, 1, 1, 1, 1, 1, 1, 1}))}, }, }, { m: Formatted(NewDense(3, 3, []float64{1, 0, 0, 0, 1, 0, 0, 0, 1})), rep: []rp{ {"%v", "⎡1 0 0⎤\n⎢0 1 0⎥\n⎣0 0 1⎦"}, {"% f", "⎡1 . .⎤\n⎢. 1 .⎥\n⎣. . 1⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(3, 3, []float64{1, 0, 0, 0, 1, 0, 0, 0, 1}))}, }, }, { m: Formatted(NewDense(2, 3, []float64{1, 2, 3, 4, 5, 6})), rep: []rp{ {"%v", "⎡1 2 3⎤\n⎣4 5 6⎦"}, {"% f", "⎡1 2 3⎤\n⎣4 5 6⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(2, 3, []float64{1, 2, 3, 4, 5, 6}))}, }, }, { m: Formatted(NewDense(3, 2, []float64{1, 2, 3, 4, 5, 6})), rep: []rp{ {"%v", "⎡1 2⎤\n⎢3 4⎥\n⎣5 6⎦"}, {"% f", "⎡1 2⎤\n⎢3 4⎥\n⎣5 6⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(3, 2, []float64{1, 2, 3, 4, 5, 6}))}, }, }, { m: func() fmt.Formatter { m := NewDense(2, 3, []float64{0, 1, 2, 3, 4, 5}) m.Apply(sqrt, m) return Formatted(m) }(), rep: []rp{ {"%v", "⎡ 0 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"}, {"%.2f", "⎡0.00 1.00 1.41⎤\n⎣1.73 2.00 2.24⎦"}, {"% f", "⎡ . 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(2, 3, []float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}))}, }, }, { m: func() fmt.Formatter { m := NewDense(3, 2, []float64{0, 1, 2, 3, 4, 5}) m.Apply(sqrt, m) return Formatted(m) }(), rep: []rp{ {"%v", "⎡ 0 1⎤\n⎢1.4142135623730951 1.7320508075688772⎥\n⎣ 2 2.23606797749979⎦"}, {"%.2f", "⎡0.00 1.00⎤\n⎢1.41 1.73⎥\n⎣2.00 2.24⎦"}, {"% f", "⎡ . 1⎤\n⎢1.4142135623730951 1.7320508075688772⎥\n⎣ 2 2.23606797749979⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(3, 2, []float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}))}, }, }, { m: func() fmt.Formatter { m := NewDense(2, 3, []float64{0, 1, 2, 3, 4, 5}) m.Apply(sqrt, m) return Formatted(m, Squeeze()) }(), rep: []rp{ {"%v", "⎡ 0 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"}, {"%.2f", "⎡0.00 1.00 1.41⎤\n⎣1.73 2.00 2.24⎦"}, {"% f", "⎡ . 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"}, {"%#v", fmt.Sprintf("%#v", NewDense(2, 3, []float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}))}, }, }, { m: func() fmt.Formatter { m := NewDense(1, 10, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) return Formatted(m, Excerpt(3)) }(), rep: []rp{ {"%v", "Dims(1, 10)\n[ 1 2 3 ... ... 8 9 10]"}, }, }, { m: func() fmt.Formatter { m := NewDense(10, 1, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) return Formatted(m, Excerpt(3)) }(), rep: []rp{ {"%v", "Dims(10, 1)\n⎡ 1⎤\n⎢ 2⎥\n⎢ 3⎥\n .\n .\n .\n⎢ 8⎥\n⎢ 9⎥\n⎣10⎦"}, }, }, { m: func() fmt.Formatter { m := NewDense(10, 10, nil) for i := 0; i < 10; i++ { m.Set(i, i, 1) } return Formatted(m, Excerpt(3)) }(), rep: []rp{ {"%v", "Dims(10, 10)\n⎡1 0 0 ... ... 0 0 0⎤\n⎢0 1 0 0 0 0⎥\n⎢0 0 1 0 0 0⎥\n .\n .\n .\n⎢0 0 0 1 0 0⎥\n⎢0 0 0 0 1 0⎥\n⎣0 0 0 ... ... 0 0 1⎦"}, }, }, { m: Formatted(NewDense(9, 1, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), FormatMATLAB()), rep: []rp{ {"%v", "[1; 2; 3; 4; 5; 6; 7; 8; 9]"}, {"%#v", "[\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n]"}, {"%s", "%!s(*mat.Dense=Dims(9, 1))"}, {"%#s", "%!s(*mat.Dense=Dims(9, 1))"}, }, }, { m: Formatted(NewDense(1, 9, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), FormatMATLAB()), rep: []rp{ {"%v", "[1 2 3 4 5 6 7 8 9]"}, {"%#v", "[1 2 3 4 5 6 7 8 9]"}, }, }, { m: Formatted(NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), FormatMATLAB()), rep: []rp{ {"%v", "[1 2 3; 4 5 6; 7 8 9]"}, {"%#v", "[\n 1 2 3\n 4 5 6\n 7 8 9\n]"}, }, }, { m: Formatted(NewDense(9, 1, []float64{1, -2, 3, 4, 5, 6, 7, 8, 9}), FormatMATLAB()), rep: []rp{ {"%v", "[1; -2; 3; 4; 5; 6; 7; 8; 9]"}, {"%#v", "[\n 1\n -2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n]"}, }, }, { m: Formatted(NewDense(1, 9, []float64{1, -2, 3, 4, 5, 6, 7, 8, 9}), FormatMATLAB()), rep: []rp{ {"%v", "[1 -2 3 4 5 6 7 8 9]"}, {"%#v", "[ 1 -2 3 4 5 6 7 8 9]"}, }, }, { m: Formatted(NewDense(3, 3, []float64{1, -2, 3, 4, 5, 6, 7, 8, 9}), FormatMATLAB()), rep: []rp{ {"%v", "[1 -2 3; 4 5 6; 7 8 9]"}, {"%#v", "[\n 1 -2 3\n 4 5 6\n 7 8 9\n]"}, }, }, { m: Formatted(NewDense(9, 1, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), FormatPython()), rep: []rp{ {"%v", "[[1], [2], [3], [4], [5], [6], [7], [8], [9]]"}, {"%#v", "[[1],\n [2],\n [3],\n [4],\n [5],\n [6],\n [7],\n [8],\n [9]]"}, {"%s", "%!s(*mat.Dense=Dims(9, 1))"}, {"%#s", "%!s(*mat.Dense=Dims(9, 1))"}, }, }, { m: Formatted(NewDense(1, 9, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), FormatPython()), rep: []rp{ {"%v", "[1, 2, 3, 4, 5, 6, 7, 8, 9]"}, {"%#v", "[1, 2, 3, 4, 5, 6, 7, 8, 9]"}, }, }, { m: Formatted(NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), FormatPython()), rep: []rp{ {"%v", "[[1, 2, 3], [4, 5, 6], [7, 8, 9]]"}, {"%#v", "[[1, 2, 3],\n [4, 5, 6],\n [7, 8, 9]]"}, }, }, { m: Formatted(NewDense(9, 1, []float64{1, -2, 3, 4, 5, 6, 7, 8, 9}), FormatPython()), rep: []rp{ {"%v", "[[1], [-2], [3], [4], [5], [6], [7], [8], [9]]"}, {"%#v", "[[ 1],\n [-2],\n [ 3],\n [ 4],\n [ 5],\n [ 6],\n [ 7],\n [ 8],\n [ 9]]"}, }, }, { m: Formatted(NewDense(1, 9, []float64{1, -2, 3, 4, 5, 6, 7, 8, 9}), FormatPython()), rep: []rp{ {"%v", "[1, -2, 3, 4, 5, 6, 7, 8, 9]"}, {"%#v", "[ 1, -2, 3, 4, 5, 6, 7, 8, 9]"}, }, }, { m: Formatted(NewDense(3, 3, []float64{1, -2, 3, 4, 5, 6, 7, 8, 9}), FormatPython()), rep: []rp{ {"%v", "[[1, -2, 3], [4, 5, 6], [7, 8, 9]]"}, {"%#v", "[[ 1, -2, 3],\n [ 4, 5, 6],\n [ 7, 8, 9]]"}, }, }, } { for j, rp := range test.rep { got := fmt.Sprintf(rp.format, test.m) if got != rp.output { t.Errorf("unexpected format result test %d part %d:\ngot:\n%s\nwant:\n%s", i, j, got, rp.output) } } } } golang-gonum-v1-gonum-0.14.0/mat/gsvd.go000066400000000000000000000263751450372207100177260ustar00rootroot00000000000000// 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 mat import ( "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) // GSVDKind specifies the treatment of singular vectors during a GSVD // factorization. type GSVDKind int const ( // GSVDNone specifies that no singular vectors should be computed during // the decomposition. GSVDNone GSVDKind = 0 // GSVDU specifies that the U singular vectors should be computed during // the decomposition. GSVDU GSVDKind = 1 << iota // GSVDV specifies that the V singular vectors should be computed during // the decomposition. GSVDV // GSVDQ specifies that the Q singular vectors should be computed during // the decomposition. GSVDQ // GSVDAll is a convenience value for computing all of the singular vectors. GSVDAll = GSVDU | GSVDV | GSVDQ ) // GSVD is a type for creating and using the Generalized Singular Value Decomposition // (GSVD) of a matrix. // // The factorization is a linear transformation of the data sets from the given // variable×sample spaces to reduced and diagonalized "eigenvariable"×"eigensample" // spaces. type GSVD struct { kind GSVDKind r, p, c, k, l int s1, s2 []float64 a, b, u, v, q blas64.General work []float64 iwork []int } // succFact returns whether the receiver contains a successful factorization. func (gsvd *GSVD) succFact() bool { return gsvd.r != 0 } // Factorize computes the generalized singular value decomposition (GSVD) of the input // the r×c matrix A and the p×c matrix B. The singular values of A and B are computed // in all cases, while the singular vectors are optionally computed depending on the // input kind. // // The full singular value decomposition (kind == GSVDAll) deconstructs A and B as // // A = U * Σ₁ * [ 0 R ] * Qᵀ // // B = V * Σ₂ * [ 0 R ] * Qᵀ // // where Σ₁ and Σ₂ are r×(k+l) and p×(k+l) diagonal matrices of singular values, and // U, V and Q are r×r, p×p and c×c orthogonal matrices of singular vectors. k+l is the // effective numerical rank of the matrix [ Aᵀ Bᵀ ]ᵀ. // // It is frequently not necessary to compute the full GSVD. Computation time and // storage costs can be reduced using the appropriate kind. Either only the singular // values can be computed (kind == SVDNone), or in conjunction with specific singular // vectors (kind bit set according to GSVDU, GSVDV and GSVDQ). // // Factorize returns whether the decomposition succeeded. If the decomposition // failed, routines that require a successful factorization will panic. func (gsvd *GSVD) Factorize(a, b Matrix, kind GSVDKind) (ok bool) { // kill the previous decomposition gsvd.r = 0 gsvd.kind = 0 r, c := a.Dims() gsvd.r, gsvd.c = r, c p, c := b.Dims() gsvd.p = p if gsvd.c != c { panic(ErrShape) } var jobU, jobV, jobQ lapack.GSVDJob switch { default: panic("gsvd: bad input kind") case kind == GSVDNone: jobU = lapack.GSVDNone jobV = lapack.GSVDNone jobQ = lapack.GSVDNone case GSVDAll&kind != 0: if GSVDU&kind != 0 { jobU = lapack.GSVDU gsvd.u = blas64.General{ Rows: r, Cols: r, Stride: r, Data: use(gsvd.u.Data, r*r), } } if GSVDV&kind != 0 { jobV = lapack.GSVDV gsvd.v = blas64.General{ Rows: p, Cols: p, Stride: p, Data: use(gsvd.v.Data, p*p), } } if GSVDQ&kind != 0 { jobQ = lapack.GSVDQ gsvd.q = blas64.General{ Rows: c, Cols: c, Stride: c, Data: use(gsvd.q.Data, c*c), } } } // A and B are destroyed on call, so copy the matrices. aCopy := DenseCopyOf(a) bCopy := DenseCopyOf(b) gsvd.s1 = use(gsvd.s1, c) gsvd.s2 = use(gsvd.s2, c) gsvd.iwork = useInt(gsvd.iwork, c) gsvd.work = use(gsvd.work, 1) lapack64.Ggsvd3(jobU, jobV, jobQ, aCopy.mat, bCopy.mat, gsvd.s1, gsvd.s2, gsvd.u, gsvd.v, gsvd.q, gsvd.work, -1, gsvd.iwork) gsvd.work = use(gsvd.work, int(gsvd.work[0])) gsvd.k, gsvd.l, ok = lapack64.Ggsvd3(jobU, jobV, jobQ, aCopy.mat, bCopy.mat, gsvd.s1, gsvd.s2, gsvd.u, gsvd.v, gsvd.q, gsvd.work, len(gsvd.work), gsvd.iwork) if ok { gsvd.a = aCopy.mat gsvd.b = bCopy.mat gsvd.kind = kind } return ok } // Kind returns the GSVDKind of the decomposition. If no decomposition has been // computed, Kind returns -1. func (gsvd *GSVD) Kind() GSVDKind { if !gsvd.succFact() { return -1 } return gsvd.kind } // Rank returns the k and l terms of the rank of [ Aᵀ Bᵀ ]ᵀ. func (gsvd *GSVD) Rank() (k, l int) { return gsvd.k, gsvd.l } // GeneralizedValues returns the generalized singular values of the factorized matrices. // If the input slice is non-nil, the values will be stored in-place into the slice. // In this case, the slice must have length min(r,c)-k, and GeneralizedValues will // panic with ErrSliceLengthMismatch otherwise. If the input slice is nil, // a new slice of the appropriate length will be allocated and returned. // // GeneralizedValues will panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) GeneralizedValues(v []float64) []float64 { if !gsvd.succFact() { panic(badFact) } r := gsvd.r c := gsvd.c k := gsvd.k d := min(r, c) if v == nil { v = make([]float64, d-k) } if len(v) != d-k { panic(ErrSliceLengthMismatch) } floats.DivTo(v, gsvd.s1[k:d], gsvd.s2[k:d]) return v } // ValuesA returns the singular values of the factorized A matrix. // If the input slice is non-nil, the values will be stored in-place into the slice. // In this case, the slice must have length min(r,c)-k, and ValuesA will panic with // ErrSliceLengthMismatch otherwise. If the input slice is nil, // a new slice of the appropriate length will be allocated and returned. // // ValuesA will panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) ValuesA(s []float64) []float64 { if !gsvd.succFact() { panic(badFact) } r := gsvd.r c := gsvd.c k := gsvd.k d := min(r, c) if s == nil { s = make([]float64, d-k) } if len(s) != d-k { panic(ErrSliceLengthMismatch) } copy(s, gsvd.s1[k:min(r, c)]) return s } // ValuesB returns the singular values of the factorized B matrix. // If the input slice is non-nil, the values will be stored in-place into the slice. // In this case, the slice must have length min(r,c)-k, and ValuesB will panic with // ErrSliceLengthMismatch otherwise. If the input slice is nil, // a new slice of the appropriate length will be allocated and returned. // // ValuesB will panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) ValuesB(s []float64) []float64 { if !gsvd.succFact() { panic(badFact) } r := gsvd.r c := gsvd.c k := gsvd.k d := min(r, c) if s == nil { s = make([]float64, d-k) } if len(s) != d-k { panic(ErrSliceLengthMismatch) } copy(s, gsvd.s2[k:d]) return s } // ZeroRTo extracts the matrix [ 0 R ] from the singular value decomposition, // storing the result into dst. [ 0 R ] is of size (k+l)×c. // // If dst is empty, ZeroRTo will resize dst to be (k+l)×c. When dst is // non-empty, ZeroRTo will panic if dst is not (k+l)×c. ZeroRTo will also panic // if the receiver does not contain a successful factorization. func (gsvd *GSVD) ZeroRTo(dst *Dense) { if !gsvd.succFact() { panic(badFact) } r := gsvd.r c := gsvd.c k := gsvd.k l := gsvd.l h := min(k+l, r) if dst.IsEmpty() { dst.ReuseAs(k+l, c) } else { r2, c2 := dst.Dims() if r2 != k+l || c != c2 { panic(ErrShape) } dst.Zero() } a := Dense{ mat: gsvd.a, capRows: r, capCols: c, } dst.slice(0, h, c-k-l, c).Copy(a.Slice(0, h, c-k-l, c)) if r < k+l { b := Dense{ mat: gsvd.b, capRows: gsvd.p, capCols: c, } dst.slice(r, k+l, c+r-k-l, c).Copy(b.Slice(r-k, l, c+r-k-l, c)) } } // SigmaATo extracts the matrix Σ₁ from the singular value decomposition, storing // the result into dst. Σ₁ is size r×(k+l). // // If dst is empty, SigmaATo will resize dst to be r×(k+l). When dst is // non-empty, SigmATo will panic if dst is not r×(k+l). SigmaATo will also // panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) SigmaATo(dst *Dense) { if !gsvd.succFact() { panic(badFact) } r := gsvd.r k := gsvd.k l := gsvd.l if dst.IsEmpty() { dst.ReuseAs(r, k+l) } else { r2, c := dst.Dims() if r2 != r || c != k+l { panic(ErrShape) } dst.Zero() } for i := 0; i < k; i++ { dst.set(i, i, 1) } for i := k; i < min(r, k+l); i++ { dst.set(i, i, gsvd.s1[i]) } } // SigmaBTo extracts the matrix Σ₂ from the singular value decomposition, storing // the result into dst. Σ₂ is size p×(k+l). // // If dst is empty, SigmaBTo will resize dst to be p×(k+l). When dst is // non-empty, SigmBTo will panic if dst is not p×(k+l). SigmaBTo will also // panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) SigmaBTo(dst *Dense) { if !gsvd.succFact() { panic(badFact) } r := gsvd.r p := gsvd.p k := gsvd.k l := gsvd.l if dst.IsEmpty() { dst.ReuseAs(p, k+l) } else { r, c := dst.Dims() if r != p || c != k+l { panic(ErrShape) } dst.Zero() } for i := 0; i < min(l, r-k); i++ { dst.set(i, i+k, gsvd.s2[k+i]) } for i := r - k; i < l; i++ { dst.set(i, i+k, 1) } } // UTo extracts the matrix U from the singular value decomposition, storing // the result into dst. U is size r×r. // // If dst is empty, UTo will resize dst to be r×r. When dst is // non-empty, UTo will panic if dst is not r×r. UTo will also // panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) UTo(dst *Dense) { if !gsvd.succFact() { panic(badFact) } if gsvd.kind&GSVDU == 0 { panic("mat: improper GSVD kind") } r := gsvd.u.Rows c := gsvd.u.Cols if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } tmp := &Dense{ mat: gsvd.u, capRows: r, capCols: c, } dst.Copy(tmp) } // VTo extracts the matrix V from the singular value decomposition, storing // the result into dst. V is size p×p. // // If dst is empty, VTo will resize dst to be p×p. When dst is // non-empty, VTo will panic if dst is not p×p. VTo will also // panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) VTo(dst *Dense) { if !gsvd.succFact() { panic(badFact) } if gsvd.kind&GSVDV == 0 { panic("mat: improper GSVD kind") } r := gsvd.v.Rows c := gsvd.v.Cols if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } tmp := &Dense{ mat: gsvd.v, capRows: r, capCols: c, } dst.Copy(tmp) } // QTo extracts the matrix Q from the singular value decomposition, storing // the result into dst. Q is size c×c. // // If dst is empty, QTo will resize dst to be c×c. When dst is // non-empty, QTo will panic if dst is not c×c. QTo will also // panic if the receiver does not contain a successful factorization. func (gsvd *GSVD) QTo(dst *Dense) { if !gsvd.succFact() { panic(badFact) } if gsvd.kind&GSVDQ == 0 { panic("mat: improper GSVD kind") } r := gsvd.q.Rows c := gsvd.q.Cols if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } tmp := &Dense{ mat: gsvd.q, capRows: r, capCols: c, } dst.Copy(tmp) } golang-gonum-v1-gonum-0.14.0/mat/gsvd_example_test.go000066400000000000000000000046431450372207100224720ustar00rootroot00000000000000// 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 mat_test import ( "fmt" "log" "math" "gonum.org/v1/gonum/mat" ) func ExampleGSVD() { // Perform a GSVD factorization on food production/consumption data for the // three years 1990, 2000 and 2014, for Africa and Latin America/Caribbean. // // See Lee et al. doi:10.1371/journal.pone.0030098 and // Alter at al. doi:10.1073/pnas.0530258100 for more details. var gsvd mat.GSVD ok := gsvd.Factorize(FAO.Africa, FAO.LatinAmericaCaribbean, mat.GSVDU|mat.GSVDV|mat.GSVDQ) if !ok { log.Fatal("GSVD factorization failed") } var u, v mat.Dense gsvd.UTo(&u) gsvd.VTo(&v) s1 := gsvd.ValuesA(nil) s2 := gsvd.ValuesB(nil) fmt.Printf("Africa\n\ts1 = %.4f\n\n\tU = %.4f\n\n", s1, mat.Formatted(&u, mat.Prefix("\t "), mat.Excerpt(2))) fmt.Printf("Latin America/Caribbean\n\ts2 = %.4f\n\n\tV = %.4f\n", s2, mat.Formatted(&v, mat.Prefix("\t "), mat.Excerpt(2))) var q, zR mat.Dense gsvd.QTo(&q) gsvd.ZeroRTo(&zR) q.Mul(&zR, &q) fmt.Printf("\nCommon basis vectors\n\n\tQᵀ = %.4f\n", mat.Formatted(q.T(), mat.Prefix("\t "))) // Calculate the antisymmetric angular distances for each eigenvariable. fmt.Println("\nSignificance:") for i := 0; i < 3; i++ { fmt.Printf("\teigenvar_%d: %+.4f\n", i, math.Atan(s1[i]/s2[i])-math.Pi/4) } // Output: // // Africa // s1 = [1.0000 0.9344 0.5118] // // U = Dims(21, 21) // ⎡-0.0005 0.0142 ... ... -0.0060 -0.0055⎤ // ⎢-0.0010 0.0019 0.0071 0.0075⎥ // . // . // . // ⎢-0.0007 -0.0024 0.9999 -0.0001⎥ // ⎣-0.0010 -0.0016 ... ... -0.0001 0.9999⎦ // // Latin America/Caribbean // s2 = [0.0047 0.3563 0.8591] // // V = Dims(14, 14) // ⎡ 0.1362 0.0008 ... ... 0.0700 0.2636⎤ // ⎢ 0.1830 -0.0040 0.2908 0.7834⎥ // . // . // . // ⎢-0.2598 -0.0324 0.9339 -0.2170⎥ // ⎣-0.8386 0.1494 ... ... -0.1639 0.4121⎦ // // Common basis vectors // // Qᵀ = ⎡ 14508.5881 4524.2933 -4813.9616⎤ // ⎢ 15562.9323 12397.1070 -16364.8933⎥ // ⎣-14262.7217 -10902.1488 15762.8719⎦ // // Significance: // eigenvar_0: +0.7807 // eigenvar_1: +0.4211 // eigenvar_2: -0.2482 } golang-gonum-v1-gonum-0.14.0/mat/gsvd_test.go000066400000000000000000000063401450372207100207530ustar00rootroot00000000000000// 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 mat import ( "fmt" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestGSVD(t *testing.T) { t.Parallel() const tol = 1e-10 for _, test := range []struct { m, p, n int }{ {5, 3, 5}, {5, 3, 3}, {3, 3, 5}, {5, 5, 5}, {5, 5, 3}, {3, 5, 5}, {150, 150, 150}, {200, 150, 150}, {150, 150, 200}, {150, 200, 150}, {200, 200, 150}, {150, 200, 200}, } { m := test.m p := test.p n := test.n t.Run(fmt.Sprintf("%v", test), func(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for trial := 0; trial < 10; trial++ { a := NewDense(m, n, nil) for i := range a.mat.Data { a.mat.Data[i] = rnd.NormFloat64() } aCopy := DenseCopyOf(a) b := NewDense(p, n, nil) for i := range b.mat.Data { b.mat.Data[i] = rnd.NormFloat64() } bCopy := DenseCopyOf(b) // Test Full decomposition. var gsvd GSVD ok := gsvd.Factorize(a, b, GSVDU|GSVDV|GSVDQ) if !ok { t.Errorf("GSVD factorization failed") } if !Equal(a, aCopy) { t.Errorf("A changed during call to GSVD.Factorize with GSVDU|GSVDV|GSVDQ") } if !Equal(b, bCopy) { t.Errorf("B changed during call to GSVD.Factorize with GSVDU|GSVDV|GSVDQ") } c, s, sigma1, sigma2, zeroR, u, v, q := extractGSVD(&gsvd) var ansU, ansV, d1R, d2R Dense ansU.Product(u.T(), a, q) ansV.Product(v.T(), b, q) d1R.Mul(sigma1, zeroR) d2R.Mul(sigma2, zeroR) if !EqualApprox(&ansU, &d1R, tol) { t.Errorf("Answer mismatch with GSVDU|GSVDV|GSVDQ\nUᵀ * A * Q:\n% 0.2f\nΣ₁ * [ 0 R ]:\n% 0.2f", Formatted(&ansU), Formatted(&d1R)) } if !EqualApprox(&ansV, &d2R, tol) { t.Errorf("Answer mismatch with GSVDU|GSVDV|GSVDQ\nVᵀ * B *Q:\n% 0.2f\nΣ₂ * [ 0 R ]:\n% 0.2f", Formatted(&d2R), Formatted(&ansV)) } // Check C^2 + S^2 = I. for i := range c { d := c[i]*c[i] + s[i]*s[i] if !scalar.EqualWithinAbsOrRel(d, 1, 1e-14, 1e-14) { t.Errorf("c_%d^2 + s_%d^2 != 1: got: %v", i, i, d) } } // Test None decomposition. ok = gsvd.Factorize(a, b, GSVDNone) if !ok { t.Errorf("GSVD factorization failed") } if !Equal(a, aCopy) { t.Errorf("A changed during call to GSVD with GSVDNone") } if !Equal(b, bCopy) { t.Errorf("B changed during call to GSVD with GSVDNone") } cNone := gsvd.ValuesA(nil) if !floats.EqualApprox(c, cNone, tol) { t.Errorf("Singular value mismatch between GSVDU|GSVDV|GSVDQ and GSVDNone decomposition") } sNone := gsvd.ValuesB(nil) if !floats.EqualApprox(s, sNone, tol) { t.Errorf("Singular value mismatch between GSVDU|GSVDV|GSVDQ and GSVDNone decomposition") } } }) } } func extractGSVD(gsvd *GSVD) (c, s []float64, s1, s2, zR, u, v, q *Dense) { s1 = &Dense{} s2 = &Dense{} zR = &Dense{} u = &Dense{} v = &Dense{} q = &Dense{} gsvd.SigmaATo(s1) gsvd.SigmaBTo(s2) gsvd.ZeroRTo(zR) gsvd.UTo(u) gsvd.VTo(v) gsvd.QTo(q) c = gsvd.ValuesA(nil) s = gsvd.ValuesB(nil) return c, s, s1, s2, zR, u, v, q } golang-gonum-v1-gonum-0.14.0/mat/hogsvd.go000066400000000000000000000135231450372207100202440ustar00rootroot00000000000000// 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 mat import ( "errors" "gonum.org/v1/gonum/blas/blas64" ) // HOGSVD is a type for creating and using the Higher Order Generalized Singular Value // Decomposition (HOGSVD) of a set of matrices. // // The factorization is a linear transformation of the data sets from the given // variable×sample spaces to reduced and diagonalized "eigenvariable"×"eigensample" // spaces. type HOGSVD struct { n int v *Dense b []Dense err error } // succFact returns whether the receiver contains a successful factorization. func (gsvd *HOGSVD) succFact() bool { return gsvd.n != 0 } // Factorize computes the higher order generalized singular value decomposition (HOGSVD) // of the n input r_i×c column tall matrices in m. HOGSV extends the GSVD case from 2 to n // input matrices. // // M_0 = U_0 * Σ_0 * Vᵀ // M_1 = U_1 * Σ_1 * Vᵀ // . // . // . // M_{n-1} = U_{n-1} * Σ_{n-1} * Vᵀ // // where U_i are r_i×c matrices of singular vectors, Σ are c×c matrices singular values, and V // is a c×c matrix of singular vectors. // // Factorize returns whether the decomposition succeeded. If the decomposition // failed, routines that require a successful factorization will panic. func (gsvd *HOGSVD) Factorize(m ...Matrix) (ok bool) { // Factorize performs the HOGSVD factorisation // essentially as described by Ponnapalli et al. // https://doi.org/10.1371/journal.pone.0028072 if len(m) < 2 { panic("hogsvd: too few matrices") } gsvd.n = 0 r, c := m[0].Dims() a := make([]Cholesky, len(m)) var ts SymDense for i, d := range m { rd, cd := d.Dims() if rd < cd { gsvd.err = ErrShape return false } if rd > r { r = rd } if cd != c { panic(ErrShape) } ts.Reset() ts.SymOuterK(1, d.T()) ok = a[i].Factorize(&ts) if !ok { gsvd.err = errors.New("hogsvd: cholesky decomposition failed") return false } } s := getDenseWorkspace(c, c, true) defer putDenseWorkspace(s) sij := getDenseWorkspace(c, c, false) defer putDenseWorkspace(sij) for i, ai := range a { for _, aj := range a[i+1:] { gsvd.err = ai.SolveCholTo(sij, &aj) if gsvd.err != nil { return false } s.Add(s, sij) gsvd.err = aj.SolveCholTo(sij, &ai) if gsvd.err != nil { return false } s.Add(s, sij) } } s.Scale(1/float64(len(m)*(len(m)-1)), s) var eig Eigen ok = eig.Factorize(s.T(), EigenRight) if !ok { gsvd.err = errors.New("hogsvd: eigen decomposition failed") return false } var vc CDense eig.VectorsTo(&vc) // vc is guaranteed to have real eigenvalues. rc, cc := vc.Dims() v := NewDense(rc, cc, nil) for i := 0; i < rc; i++ { for j := 0; j < cc; j++ { a := vc.At(i, j) v.set(i, j, real(a)) } } // Rescale the columns of v by their Frobenius norms. // Work done in cv is reflected in v. var cv VecDense for j := 0; j < c; j++ { cv.ColViewOf(v, j) cv.ScaleVec(1/blas64.Nrm2(cv.mat), &cv) } b := make([]Dense, len(m)) biT := getDenseWorkspace(c, r, false) defer putDenseWorkspace(biT) for i, d := range m { // All calls to reset will leave an emptied // matrix with capacity to store the result // without additional allocation. biT.Reset() gsvd.err = biT.Solve(v, d.T()) if gsvd.err != nil { return false } b[i].CloneFrom(biT.T()) } gsvd.n = len(m) gsvd.v = v gsvd.b = b return true } // Err returns the reason for a factorization failure. func (gsvd *HOGSVD) Err() error { return gsvd.err } // Len returns the number of matrices that have been factorized. If Len returns // zero, the factorization was not successful. func (gsvd *HOGSVD) Len() int { return gsvd.n } // UTo extracts the matrix U_n from the singular value decomposition, storing // the result in-place into dst. U_n is size r×c. // // If dst is empty, UTo will resize dst to be r×c. When dst is // non-empty, UTo will panic if dst is not r×c. UTo will also // panic if the receiver does not contain a successful factorization. func (gsvd *HOGSVD) UTo(dst *Dense, n int) { if !gsvd.succFact() { panic(badFact) } if n < 0 || gsvd.n <= n { panic("hogsvd: invalid index") } r, c := gsvd.b[n].Dims() if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } dst.Copy(&gsvd.b[n]) var v VecDense for j, f := range gsvd.Values(nil, n) { v.ColViewOf(dst, j) v.ScaleVec(1/f, &v) } } // Values returns the nth set of singular values of the factorized system. // If the input slice is non-nil, the values will be stored in-place into the slice. // In this case, the slice must have length c, and Values will panic with // ErrSliceLengthMismatch otherwise. If the input slice is nil, // a new slice of the appropriate length will be allocated and returned. // // Values will panic if the receiver does not contain a successful factorization. func (gsvd *HOGSVD) Values(s []float64, n int) []float64 { if !gsvd.succFact() { panic(badFact) } if n < 0 || gsvd.n <= n { panic("hogsvd: invalid index") } _, c := gsvd.b[n].Dims() if s == nil { s = make([]float64, c) } else if len(s) != c { panic(ErrSliceLengthMismatch) } var v VecDense for j := 0; j < c; j++ { v.ColViewOf(&gsvd.b[n], j) s[j] = blas64.Nrm2(v.mat) } return s } // VTo extracts the matrix V from the singular value decomposition, storing // the result in-place into dst. V is size c×c. // // If dst is empty, VTo will resize dst to be c×c. When dst is // non-empty, VTo will panic if dst is not c×c. VTo will also // panic if the receiver does not contain a successful factorization. func (gsvd *HOGSVD) VTo(dst *Dense) { if !gsvd.succFact() { panic(badFact) } r, c := gsvd.v.Dims() if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } dst.Copy(gsvd.v) } golang-gonum-v1-gonum-0.14.0/mat/hogsvd_example_test.go000066400000000000000000000113421450372207100230130ustar00rootroot00000000000000// 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 mat_test import ( "fmt" "log" "gonum.org/v1/gonum/mat" ) func ExampleHOGSVD() { // Perform an HOGSVD factorization on food production/consumption data for the // three years 1990, 2000 and 2014. // // See Ponnapalli et al. doi:10.1371/journal.pone.0028072 and // Alter at al. doi:10.1073/pnas.0530258100 for more details. var gsvd mat.HOGSVD ok := gsvd.Factorize(FAO.Africa, FAO.Asia, FAO.LatinAmericaCaribbean, FAO.Oceania) if !ok { log.Fatalf("HOGSVD factorization failed: %v", gsvd.Err()) } for i, n := range []string{"Africa", "Asia", "Latin America/Caribbean", "Oceania"} { var u mat.Dense gsvd.UTo(&u, i) s := gsvd.Values(nil, i) fmt.Printf("%s\n\ts_%d = %.4f\n\n\tU_%[2]d = %.4[4]f\n", n, i, s, mat.Formatted(&u, mat.Prefix("\t "))) } var v mat.Dense gsvd.VTo(&v) fmt.Printf("\nCommon basis vectors\n\n\tVᵀ = %.4f", mat.Formatted(v.T(), mat.Prefix("\t "))) // Output: // // Africa // s_0 = [45507.3278 18541.9293 21503.0778] // // U_0 = ⎡-0.0005 -0.0039 -0.0019⎤ // ⎢-0.0010 -0.0007 -0.0012⎥ // ⎢-1.0000 -0.0507 -0.9964⎥ // ⎢-0.0022 -0.2906 -0.0415⎥ // ⎢ 0.0001 -0.0127 -0.0016⎥ // ⎢ 0.0003 -0.0067 -0.0010⎥ // ⎢ 0.0003 -0.0022 -0.0003⎥ // ⎢-0.0086 -0.9550 0.0734⎥ // ⎢ 0.0017 0.0002 0.0059⎥ // ⎢-0.0002 -0.0088 -0.0014⎥ // ⎢-0.0006 -0.0078 -0.0001⎥ // ⎢-0.0005 -0.0076 0.0003⎥ // ⎢ 0.0001 -0.0090 0.0008⎥ // ⎢-0.0005 -0.0050 0.0029⎥ // ⎢-0.0011 -0.0078 -0.0012⎥ // ⎢-0.0014 -0.0058 -0.0002⎥ // ⎢ 0.0007 -0.0095 0.0020⎥ // ⎢-0.0008 -0.0081 -0.0009⎥ // ⎢ 0.0004 -0.0092 0.0006⎥ // ⎢-0.0007 -0.0079 -0.0006⎥ // ⎣-0.0011 -0.0076 -0.0010⎦ // Asia // s_1 = [77228.2804 8413.7024 14711.1879] // // U_1 = ⎡ 0.0005 -0.0080 0.0011⎤ // ⎢ 0.0008 -0.0108 0.0016⎥ // ⎢-0.9998 0.0612 0.9949⎥ // ⎢ 0.0007 -0.5734 -0.0468⎥ // ⎢ 0.0001 -0.0265 -0.0022⎥ // ⎢ 0.0001 -0.0165 -0.0019⎥ // ⎢ 0.0000 -0.0070 -0.0013⎥ // ⎢ 0.0196 -0.8148 0.0893⎥ // ⎢ 0.0002 -0.0063 0.0012⎥ // ⎢-0.0001 -0.0135 -0.0013⎥ // ⎢-0.0004 -0.0135 0.0019⎥ // ⎢-0.0005 -0.0132 0.0014⎥ // ⎢ 0.0003 -0.0155 0.0045⎥ // ⎢-0.0003 -0.0130 0.0025⎥ // ⎢-0.0007 -0.0105 0.0016⎥ // ⎢-0.0006 -0.0129 0.0007⎥ // ⎢-0.0006 -0.0178 -0.0023⎥ // ⎢-0.0003 -0.0149 0.0016⎥ // ⎢-0.0001 -0.0134 0.0030⎥ // ⎢-0.0004 -0.0154 0.0010⎥ // ⎣-0.0009 -0.0147 -0.0019⎦ // Latin America/Caribbean // s_2 = [274.1364 20736.3116 729.6947] // // U_2 = ⎡ 0.1060 -0.0021 0.0174⎤ // ⎢ 0.1415 -0.0016 0.0289⎥ // ⎢ 0.2350 -0.2669 -0.9212⎥ // ⎢ 0.0290 -0.0118 -0.0429⎥ // ⎢ 0.0226 -0.0043 -0.0213⎥ // ⎢ 0.0117 -0.0016 -0.0197⎥ // ⎢-0.6263 -0.9635 0.2234⎥ // ⎢ 0.2334 -0.0013 0.1275⎥ // ⎢-0.0358 -0.0085 -0.0498⎥ // ⎢-0.1238 -0.0054 0.0313⎥ // ⎢-0.0421 -0.0059 0.0528⎥ // ⎢-0.1471 -0.0056 0.0350⎥ // ⎢-0.2158 -0.0052 -0.0044⎥ // ⎣-0.6154 -0.0078 -0.2717⎦ // Oceania // s_3 = [8954.1914 6942.6316 17233.0561] // // U_3 = ⎡-0.0080 -0.0012 -0.0040⎤ // ⎢ 0.0004 -0.0014 0.0001⎥ // ⎢ 0.9973 -0.0315 0.9991⎥ // ⎢ 0.0473 -0.7426 -0.0359⎥ // ⎢ 0.0018 -0.0342 -0.0020⎥ // ⎢-0.0005 -0.0148 -0.0016⎥ // ⎢-0.0004 -0.0047 -0.0007⎥ // ⎢-0.0246 -0.6642 -0.0138⎥ // ⎢ 0.0003 -0.0287 -0.0023⎥ // ⎢-0.0011 -0.0148 -0.0014⎥ // ⎢-0.0108 -0.0198 -0.0039⎥ // ⎢-0.0149 -0.0183 -0.0048⎥ // ⎢-0.0178 -0.0208 -0.0075⎥ // ⎢-0.0266 -0.0063 -0.0016⎥ // ⎢-0.0012 -0.0234 -0.0006⎥ // ⎢-0.0084 -0.0184 -0.0030⎥ // ⎢-0.0232 -0.0191 -0.0124⎥ // ⎢-0.0072 -0.0226 -0.0035⎥ // ⎢-0.0150 -0.0144 -0.0045⎥ // ⎢-0.0068 -0.0227 -0.0034⎥ // ⎣-0.0127 -0.0136 -0.0049⎦ // // Common basis vectors // // Vᵀ = ⎡-0.0897 -0.4460 -0.8905⎤ // ⎢-0.4911 -0.5432 -0.6810⎥ // ⎣ 0.0644 0.2841 0.9566⎦ } golang-gonum-v1-gonum-0.14.0/mat/hogsvd_test.go000066400000000000000000000041131450372207100212760ustar00rootroot00000000000000// 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 mat import ( "testing" "golang.org/x/exp/rand" ) func TestHOGSVD(t *testing.T) { t.Parallel() const tol = 1e-10 rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { r, c int }{ {5, 3}, {5, 5}, {150, 150}, {200, 150}, // Calculating A_i*A_jᵀ and A_j*A_iᵀ fails for wide matrices. {3, 5}, } { r := test.r c := test.c for n := 3; n < 6; n++ { data := make([]Matrix, n) dataCopy := make([]*Dense, n) for trial := 0; trial < 10; trial++ { for i := range data { d := NewDense(r, c, nil) for j := range d.mat.Data { d.mat.Data[j] = rnd.Float64() } data[i] = d dataCopy[i] = DenseCopyOf(d) } var gsvd HOGSVD ok := gsvd.Factorize(data...) if r >= c { if !ok { t.Errorf("HOGSVD factorization failed for %d %d×%d matrices: %v", n, r, c, gsvd.Err()) continue } } else { if ok { t.Errorf("HOGSVD factorization unexpectedly succeeded for %d %d×%d matrices", n, r, c) } continue } for i := range data { if !Equal(data[i], dataCopy[i]) { t.Errorf("A changed during call to HOGSVD.Factorize") } } u, s, v := extractHOGSVD(&gsvd) for i, want := range data { var got Dense sigma := NewDense(c, c, nil) for j := 0; j < c; j++ { sigma.Set(j, j, s[i][j]) } got.Product(u[i], sigma, v.T()) if !EqualApprox(&got, want, tol) { t.Errorf("test %d n=%d trial %d: unexpected answer\nU_%[4]d * S_%[4]d * Vᵀ:\n% 0.2f\nD_%d:\n% 0.2f", cas, n, trial, i, Formatted(&got, Excerpt(5)), i, Formatted(want, Excerpt(5))) } } } } } } func extractHOGSVD(gsvd *HOGSVD) (u []*Dense, s [][]float64, v *Dense) { u = make([]*Dense, gsvd.Len()) s = make([][]float64, gsvd.Len()) for i := 0; i < gsvd.Len(); i++ { u[i] = &Dense{} gsvd.UTo(u[i], i) s[i] = gsvd.Values(nil, i) } v = &Dense{} gsvd.VTo(v) return u, s, v } golang-gonum-v1-gonum-0.14.0/mat/index_bound_checks.go000066400000000000000000000202501450372207100225630ustar00rootroot00000000000000// 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. // This file must be kept in sync with index_no_bound_checks.go. //go:build bounds // +build bounds package mat // At returns the element at row i, column j. func (m *Dense) At(i, j int) float64 { return m.at(i, j) } func (m *Dense) at(i, j int) float64 { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } return m.mat.Data[i*m.mat.Stride+j] } // Set sets the element at row i, column j to the value v. func (m *Dense) Set(i, j int, v float64) { m.set(i, j, v) } func (m *Dense) set(i, j int, v float64) { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } m.mat.Data[i*m.mat.Stride+j] = v } // At returns the element at row i, column j. func (m *CDense) At(i, j int) complex128 { return m.at(i, j) } func (m *CDense) at(i, j int) complex128 { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } return m.mat.Data[i*m.mat.Stride+j] } // Set sets the element at row i, column j to the value v. func (m *CDense) Set(i, j int, v complex128) { m.set(i, j, v) } func (m *CDense) set(i, j int, v complex128) { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } m.mat.Data[i*m.mat.Stride+j] = v } // At returns the element at row i. // It panics if i is out of bounds or if j is not zero. func (v *VecDense) At(i, j int) float64 { if j != 0 { panic(ErrColAccess) } return v.at(i) } // AtVec returns the element at row i. // It panics if i is out of bounds. func (v *VecDense) AtVec(i int) float64 { return v.at(i) } func (v *VecDense) at(i int) float64 { if uint(i) >= uint(v.mat.N) { panic(ErrRowAccess) } return v.mat.Data[i*v.mat.Inc] } // SetVec sets the element at row i to the value val. // It panics if i is out of bounds. func (v *VecDense) SetVec(i int, val float64) { v.setVec(i, val) } func (v *VecDense) setVec(i int, val float64) { if uint(i) >= uint(v.mat.N) { panic(ErrVectorAccess) } v.mat.Data[i*v.mat.Inc] = val } // At returns the element at row i and column j. func (t *SymDense) At(i, j int) float64 { return t.at(i, j) } func (t *SymDense) at(i, j int) float64 { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } if i > j { i, j = j, i } return t.mat.Data[i*t.mat.Stride+j] } // SetSym sets the elements at (i,j) and (j,i) to the value v. func (t *SymDense) SetSym(i, j int, v float64) { t.set(i, j, v) } func (t *SymDense) set(i, j int, v float64) { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } if i > j { i, j = j, i } t.mat.Data[i*t.mat.Stride+j] = v } // At returns the element at row i, column j. func (t *TriDense) At(i, j int) float64 { return t.at(i, j) } func (t *TriDense) at(i, j int) float64 { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } isUpper := t.isUpper() if (isUpper && i > j) || (!isUpper && i < j) { return 0 } return t.mat.Data[i*t.mat.Stride+j] } // SetTri sets the element of the triangular matrix at row i, column j to the value v. // It panics if the location is outside the appropriate half of the matrix. func (t *TriDense) SetTri(i, j int, v float64) { t.set(i, j, v) } func (t *TriDense) set(i, j int, v float64) { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } isUpper := t.isUpper() if (isUpper && i > j) || (!isUpper && i < j) { panic(ErrTriangleSet) } t.mat.Data[i*t.mat.Stride+j] = v } // At returns the element at row i, column j. func (b *BandDense) At(i, j int) float64 { return b.at(i, j) } func (b *BandDense) at(i, j int) float64 { if uint(i) >= uint(b.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(b.mat.Cols) { panic(ErrColAccess) } pj := j + b.mat.KL - i if pj < 0 || b.mat.KL+b.mat.KU+1 <= pj { return 0 } return b.mat.Data[i*b.mat.Stride+pj] } // SetBand sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate region of the matrix. func (b *BandDense) SetBand(i, j int, v float64) { b.set(i, j, v) } func (b *BandDense) set(i, j int, v float64) { if uint(i) >= uint(b.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(b.mat.Cols) { panic(ErrColAccess) } pj := j + b.mat.KL - i if pj < 0 || b.mat.KL+b.mat.KU+1 <= pj { panic(ErrBandSet) } b.mat.Data[i*b.mat.Stride+pj] = v } // At returns the element at row i, column j. func (s *SymBandDense) At(i, j int) float64 { return s.at(i, j) } func (s *SymBandDense) at(i, j int) float64 { if uint(i) >= uint(s.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(s.mat.N) { panic(ErrColAccess) } if i > j { i, j = j, i } pj := j - i if s.mat.K+1 <= pj { return 0 } return s.mat.Data[i*s.mat.Stride+pj] } // SetSymBand sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate region of the matrix. func (s *SymBandDense) SetSymBand(i, j int, v float64) { s.set(i, j, v) } func (s *SymBandDense) set(i, j int, v float64) { if uint(i) >= uint(s.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(s.mat.N) { panic(ErrColAccess) } if i > j { i, j = j, i } pj := j - i if s.mat.K+1 <= pj { panic(ErrBandSet) } s.mat.Data[i*s.mat.Stride+pj] = v } func (t *TriBandDense) At(i, j int) float64 { return t.at(i, j) } func (t *TriBandDense) at(i, j int) float64 { // TODO(btracey): Support Diag field, see #692. if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } isUpper := t.isUpper() if (isUpper && i > j) || (!isUpper && i < j) { return 0 } kl, ku := t.mat.K, 0 if isUpper { kl, ku = 0, t.mat.K } pj := j + kl - i if pj < 0 || kl+ku+1 <= pj { return 0 } return t.mat.Data[i*t.mat.Stride+pj] } func (t *TriBandDense) SetTriBand(i, j int, v float64) { t.setTriBand(i, j, v) } func (t *TriBandDense) setTriBand(i, j int, v float64) { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } isUpper := t.isUpper() if (isUpper && i > j) || (!isUpper && i < j) { panic(ErrTriangleSet) } kl, ku := t.mat.K, 0 if isUpper { kl, ku = 0, t.mat.K } pj := j + kl - i if pj < 0 || kl+ku+1 <= pj { panic(ErrBandSet) } // TODO(btracey): Support Diag field, see #692. t.mat.Data[i*t.mat.Stride+pj] = v } // At returns the element at row i, column j. func (d *DiagDense) At(i, j int) float64 { return d.at(i, j) } func (d *DiagDense) at(i, j int) float64 { if uint(i) >= uint(d.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(d.mat.N) { panic(ErrColAccess) } if i != j { return 0 } return d.mat.Data[i*d.mat.Inc] } // SetDiag sets the element at row i, column i to the value v. // It panics if the location is outside the appropriate region of the matrix. func (d *DiagDense) SetDiag(i int, v float64) { d.setDiag(i, v) } func (d *DiagDense) setDiag(i int, v float64) { if uint(i) >= uint(d.mat.N) { panic(ErrRowAccess) } d.mat.Data[i*d.mat.Inc] = v } // At returns the element at row i, column j. func (a *Tridiag) At(i, j int) float64 { return a.at(i, j) } func (a *Tridiag) at(i, j int) float64 { if uint(i) >= uint(a.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(a.mat.N) { panic(ErrColAccess) } switch i - j { case -1: return a.mat.DU[i] case 0: return a.mat.D[i] case 1: return a.mat.DL[j] default: return 0 } } // SetBand sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate region of the matrix. func (a *Tridiag) SetBand(i, j int, v float64) { a.set(i, j, v) } func (a *Tridiag) set(i, j int, v float64) { if uint(i) >= uint(a.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(a.mat.N) { panic(ErrColAccess) } switch i - j { case -1: a.mat.DU[i] = v case 0: a.mat.D[i] = v case 1: a.mat.DL[j] = v default: panic(ErrBandSet) } } golang-gonum-v1-gonum-0.14.0/mat/index_no_bound_checks.go000066400000000000000000000202171450372207100232620ustar00rootroot00000000000000// 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. // This file must be kept in sync with index_bound_checks.go. //go:build !bounds // +build !bounds package mat // At returns the element at row i, column j. func (m *Dense) At(i, j int) float64 { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } return m.at(i, j) } func (m *Dense) at(i, j int) float64 { return m.mat.Data[i*m.mat.Stride+j] } // Set sets the element at row i, column j to the value v. func (m *Dense) Set(i, j int, v float64) { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } m.set(i, j, v) } func (m *Dense) set(i, j int, v float64) { m.mat.Data[i*m.mat.Stride+j] = v } // At returns the element at row i, column j. func (m *CDense) At(i, j int) complex128 { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } return m.at(i, j) } func (m *CDense) at(i, j int) complex128 { return m.mat.Data[i*m.mat.Stride+j] } // Set sets the element at row i, column j to the value v. func (m *CDense) Set(i, j int, v complex128) { if uint(i) >= uint(m.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(m.mat.Cols) { panic(ErrColAccess) } m.set(i, j, v) } func (m *CDense) set(i, j int, v complex128) { m.mat.Data[i*m.mat.Stride+j] = v } // At returns the element at row i. // It panics if i is out of bounds or if j is not zero. func (v *VecDense) At(i, j int) float64 { if uint(i) >= uint(v.mat.N) { panic(ErrRowAccess) } if j != 0 { panic(ErrColAccess) } return v.at(i) } // AtVec returns the element at row i. // It panics if i is out of bounds. func (v *VecDense) AtVec(i int) float64 { if uint(i) >= uint(v.mat.N) { panic(ErrRowAccess) } return v.at(i) } func (v *VecDense) at(i int) float64 { return v.mat.Data[i*v.mat.Inc] } // SetVec sets the element at row i to the value val. // It panics if i is out of bounds. func (v *VecDense) SetVec(i int, val float64) { if uint(i) >= uint(v.mat.N) { panic(ErrVectorAccess) } v.setVec(i, val) } func (v *VecDense) setVec(i int, val float64) { v.mat.Data[i*v.mat.Inc] = val } // At returns the element at row i and column j. func (s *SymDense) At(i, j int) float64 { if uint(i) >= uint(s.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(s.mat.N) { panic(ErrColAccess) } return s.at(i, j) } func (s *SymDense) at(i, j int) float64 { if i > j { i, j = j, i } return s.mat.Data[i*s.mat.Stride+j] } // SetSym sets the elements at (i,j) and (j,i) to the value v. func (s *SymDense) SetSym(i, j int, v float64) { if uint(i) >= uint(s.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(s.mat.N) { panic(ErrColAccess) } s.set(i, j, v) } func (s *SymDense) set(i, j int, v float64) { if i > j { i, j = j, i } s.mat.Data[i*s.mat.Stride+j] = v } // At returns the element at row i, column j. func (t *TriDense) At(i, j int) float64 { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } return t.at(i, j) } func (t *TriDense) at(i, j int) float64 { isUpper := t.triKind() if (isUpper && i > j) || (!isUpper && i < j) { return 0 } return t.mat.Data[i*t.mat.Stride+j] } // SetTri sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate half of the matrix. func (t *TriDense) SetTri(i, j int, v float64) { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } isUpper := t.isUpper() if (isUpper && i > j) || (!isUpper && i < j) { panic(ErrTriangleSet) } t.set(i, j, v) } func (t *TriDense) set(i, j int, v float64) { t.mat.Data[i*t.mat.Stride+j] = v } // At returns the element at row i, column j. func (b *BandDense) At(i, j int) float64 { if uint(i) >= uint(b.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(b.mat.Cols) { panic(ErrColAccess) } return b.at(i, j) } func (b *BandDense) at(i, j int) float64 { pj := j + b.mat.KL - i if pj < 0 || b.mat.KL+b.mat.KU+1 <= pj { return 0 } return b.mat.Data[i*b.mat.Stride+pj] } // SetBand sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate region of the matrix. func (b *BandDense) SetBand(i, j int, v float64) { if uint(i) >= uint(b.mat.Rows) { panic(ErrRowAccess) } if uint(j) >= uint(b.mat.Cols) { panic(ErrColAccess) } pj := j + b.mat.KL - i if pj < 0 || b.mat.KL+b.mat.KU+1 <= pj { panic(ErrBandSet) } b.set(i, j, v) } func (b *BandDense) set(i, j int, v float64) { pj := j + b.mat.KL - i b.mat.Data[i*b.mat.Stride+pj] = v } // At returns the element at row i, column j. func (s *SymBandDense) At(i, j int) float64 { if uint(i) >= uint(s.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(s.mat.N) { panic(ErrColAccess) } return s.at(i, j) } func (s *SymBandDense) at(i, j int) float64 { if i > j { i, j = j, i } pj := j - i if s.mat.K+1 <= pj { return 0 } return s.mat.Data[i*s.mat.Stride+pj] } // SetSymBand sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate region of the matrix. func (s *SymBandDense) SetSymBand(i, j int, v float64) { if uint(i) >= uint(s.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(s.mat.N) { panic(ErrColAccess) } s.set(i, j, v) } func (s *SymBandDense) set(i, j int, v float64) { if i > j { i, j = j, i } pj := j - i if s.mat.K+1 <= pj { panic(ErrBandSet) } s.mat.Data[i*s.mat.Stride+pj] = v } func (t *TriBandDense) At(i, j int) float64 { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } return t.at(i, j) } func (t *TriBandDense) at(i, j int) float64 { // TODO(btracey): Support Diag field, see #692. isUpper := t.isUpper() if (isUpper && i > j) || (!isUpper && i < j) { return 0 } kl := t.mat.K ku := 0 if isUpper { ku = t.mat.K kl = 0 } pj := j + kl - i if pj < 0 || kl+ku+1 <= pj { return 0 } return t.mat.Data[i*t.mat.Stride+pj] } func (t *TriBandDense) SetTriBand(i, j int, v float64) { if uint(i) >= uint(t.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(t.mat.N) { panic(ErrColAccess) } isUpper := t.isUpper() if (isUpper && i > j) || (!isUpper && i < j) { panic(ErrTriangleSet) } kl, ku := t.mat.K, 0 if isUpper { kl, ku = 0, t.mat.K } pj := j + kl - i if pj < 0 || kl+ku+1 <= pj { panic(ErrBandSet) } // TODO(btracey): Support Diag field, see #692. t.mat.Data[i*t.mat.Stride+pj] = v } // At returns the element at row i, column j. func (d *DiagDense) At(i, j int) float64 { if uint(i) >= uint(d.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(d.mat.N) { panic(ErrColAccess) } return d.at(i, j) } func (d *DiagDense) at(i, j int) float64 { if i != j { return 0 } return d.mat.Data[i*d.mat.Inc] } // SetDiag sets the element at row i, column i to the value v. // It panics if the location is outside the appropriate region of the matrix. func (d *DiagDense) SetDiag(i int, v float64) { if uint(i) >= uint(d.mat.N) { panic(ErrRowAccess) } d.setDiag(i, v) } func (d *DiagDense) setDiag(i int, v float64) { d.mat.Data[i*d.mat.Inc] = v } // At returns the element at row i, column j. func (a *Tridiag) At(i, j int) float64 { if uint(i) >= uint(a.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(a.mat.N) { panic(ErrColAccess) } return a.at(i, j) } func (a *Tridiag) at(i, j int) float64 { switch i - j { case -1: return a.mat.DU[i] case 0: return a.mat.D[i] case 1: return a.mat.DL[j] default: return 0 } } // SetBand sets the element at row i, column j to the value v. // It panics if the location is outside the appropriate region of the matrix. func (a *Tridiag) SetBand(i, j int, v float64) { if uint(i) >= uint(a.mat.N) { panic(ErrRowAccess) } if uint(j) >= uint(a.mat.N) { panic(ErrColAccess) } a.set(i, j, v) } func (a *Tridiag) set(i, j int, v float64) { switch i - j { case -1: a.mat.DU[i] = v case 0: a.mat.D[i] = v case 1: a.mat.DL[j] = v default: panic(ErrBandSet) } } golang-gonum-v1-gonum-0.14.0/mat/inner.go000066400000000000000000000052531450372207100200660ustar00rootroot00000000000000// 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 mat import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/internal/asm/f64" ) // Inner computes the generalized inner product // // xᵀ A y // // between the vectors x and y with matrix A, where x and y are treated as // column vectors. // // This is only a true inner product if A is symmetric positive definite, though // the operation works for any matrix A. // // Inner panics if x.Len != m or y.Len != n when A is an m x n matrix. func Inner(x Vector, a Matrix, y Vector) float64 { m, n := a.Dims() if x.Len() != m { panic(ErrShape) } if y.Len() != n { panic(ErrShape) } if m == 0 || n == 0 { return 0 } var sum float64 switch a := a.(type) { case RawSymmetricer: amat := a.RawSymmetric() if amat.Uplo != blas.Upper { // Panic as a string not a mat.Error. panic(badSymTriangle) } var xmat, ymat blas64.Vector if xrv, ok := x.(RawVectorer); ok { xmat = xrv.RawVector() } else { break } if yrv, ok := y.(RawVectorer); ok { ymat = yrv.RawVector() } else { break } for i := 0; i < x.Len(); i++ { xi := x.AtVec(i) if xi != 0 { if ymat.Inc == 1 { sum += xi * f64.DotUnitary( amat.Data[i*amat.Stride+i:i*amat.Stride+n], ymat.Data[i:], ) } else { sum += xi * f64.DotInc( amat.Data[i*amat.Stride+i:i*amat.Stride+n], ymat.Data[i*ymat.Inc:], uintptr(n-i), 1, uintptr(ymat.Inc), 0, 0, ) } } yi := y.AtVec(i) if i != n-1 && yi != 0 { if xmat.Inc == 1 { sum += yi * f64.DotUnitary( amat.Data[i*amat.Stride+i+1:i*amat.Stride+n], xmat.Data[i+1:], ) } else { sum += yi * f64.DotInc( amat.Data[i*amat.Stride+i+1:i*amat.Stride+n], xmat.Data[(i+1)*xmat.Inc:], uintptr(n-i-1), 1, uintptr(xmat.Inc), 0, 0, ) } } } return sum case RawMatrixer: amat := a.RawMatrix() var ymat blas64.Vector if yrv, ok := y.(RawVectorer); ok { ymat = yrv.RawVector() } else { break } for i := 0; i < x.Len(); i++ { xi := x.AtVec(i) if xi != 0 { if ymat.Inc == 1 { sum += xi * f64.DotUnitary( amat.Data[i*amat.Stride:i*amat.Stride+n], ymat.Data, ) } else { sum += xi * f64.DotInc( amat.Data[i*amat.Stride:i*amat.Stride+n], ymat.Data, uintptr(n), 1, uintptr(ymat.Inc), 0, 0, ) } } } return sum } for i := 0; i < x.Len(); i++ { xi := x.AtVec(i) for j := 0; j < y.Len(); j++ { sum += xi * a.At(i, j) * y.AtVec(j) } } return sum } golang-gonum-v1-gonum-0.14.0/mat/inner_test.go000066400000000000000000000072651450372207100211320ustar00rootroot00000000000000// 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 mat import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/blas/testblas" ) func TestInner(t *testing.T) { t.Parallel() for i, test := range []struct { x []float64 y []float64 m [][]float64 }{ { x: []float64{5}, y: []float64{10}, m: [][]float64{{2}}, }, { x: []float64{5, 6, 1}, y: []float64{10}, m: [][]float64{{2}, {-3}, {5}}, }, { x: []float64{5}, y: []float64{10, 15}, m: [][]float64{{2, -3}}, }, { x: []float64{1, 5}, y: []float64{10, 15}, m: [][]float64{ {2, -3}, {4, -1}, }, }, { x: []float64{2, 3, 9}, y: []float64{8, 9}, m: [][]float64{ {2, 3}, {4, 5}, {6, 7}, }, }, { x: []float64{2, 3}, y: []float64{8, 9, 9}, m: [][]float64{ {2, 3, 6}, {4, 5, 7}, }, }, } { for _, inc := range []struct{ x, y int }{ {1, 1}, {1, 2}, {2, 1}, {2, 2}, } { x := NewDense(1, len(test.x), test.x) m := NewDense(flatten(test.m)) mWant := NewDense(flatten(test.m)) y := NewDense(len(test.y), 1, test.y) var tmp, cell Dense tmp.Mul(mWant, y) cell.Mul(x, &tmp) rm, cm := cell.Dims() if rm != 1 { t.Errorf("Test %d result doesn't have 1 row", i) } if cm != 1 { t.Errorf("Test %d result doesn't have 1 column", i) } want := cell.At(0, 0) got := Inner(makeVecDenseInc(inc.x, test.x), m, makeVecDenseInc(inc.y, test.y)) if got != want { t.Errorf("Test %v: want %v, got %v", i, want, got) } } } } func TestInnerSym(t *testing.T) { t.Parallel() for _, inc := range []struct{ x, y int }{ {1, 1}, {1, 2}, {2, 1}, {2, 2}, } { n := 10 xData := make([]float64, n) yData := make([]float64, n) data := make([]float64, n*n) for i := 0; i < n; i++ { xData[i] = float64(i) yData[i] = float64(i) for j := i; j < n; j++ { data[i*n+j] = float64(i*n + j) data[j*n+i] = data[i*n+j] } } x := makeVecDenseInc(inc.x, xData) y := makeVecDenseInc(inc.y, yData) m := NewDense(n, n, data) ans := Inner(x, m, y) sym := NewSymDense(n, data) // Poison the lower half of data to ensure it is not used. for i := 1; i < n; i++ { for j := 0; j < i; j++ { data[i*n+j] = math.NaN() } } if math.Abs(Inner(x, sym, y)-ans) > 1e-14 { t.Error("inner different symmetric and dense") } } } func makeVecDenseInc(inc int, f []float64) *VecDense { v := &VecDense{ mat: blas64.Vector{ N: len(f), Inc: inc, Data: make([]float64, (len(f)-1)*inc+1), }, } // Contaminate backing data in all positions... const base = 100 for i := range v.mat.Data { v.mat.Data[i] = float64(i + base) } // then write real elements. for i := range f { v.mat.Data[i*inc] = f[i] } return v } func benchmarkInner(b *testing.B, m, n int) { src := rand.NewSource(1) x := NewVecDense(m, nil) randomSlice(x.mat.Data, src) y := NewVecDense(n, nil) randomSlice(y.mat.Data, src) data := make([]float64, m*n) randomSlice(data, src) mat := &Dense{mat: blas64.General{Rows: m, Cols: n, Stride: n, Data: data}, capRows: m, capCols: n} b.ResetTimer() for i := 0; i < b.N; i++ { Inner(x, mat, y) } } func BenchmarkInnerSmSm(b *testing.B) { benchmarkInner(b, testblas.SmallMat, testblas.SmallMat) } func BenchmarkInnerMedMed(b *testing.B) { benchmarkInner(b, testblas.MediumMat, testblas.MediumMat) } func BenchmarkInnerLgLg(b *testing.B) { benchmarkInner(b, testblas.LargeMat, testblas.LargeMat) } func BenchmarkInnerLgSm(b *testing.B) { benchmarkInner(b, testblas.LargeMat, testblas.SmallMat) } golang-gonum-v1-gonum-0.14.0/mat/io.go000066400000000000000000000314271450372207100173640ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "bytes" "encoding/binary" "errors" "fmt" "io" "math" ) // version is the current on-disk codec version. const version uint32 = 0x1 // maxLen is the biggest slice/array len one can create on a 32/64b platform. const maxLen = int64(int(^uint(0) >> 1)) var ( headerSize = binary.Size(storage{}) sizeFloat64 = binary.Size(float64(0)) errWrongType = errors.New("mat: wrong data type") errTooBig = errors.New("mat: resulting data slice too big") errTooSmall = errors.New("mat: input slice too small") errBadBuffer = errors.New("mat: data buffer size mismatch") errBadSize = errors.New("mat: invalid dimension") ) // Type encoding scheme: // // Type Form Packing Uplo Unit Rows Columns kU kL // uint8 [GST] uint8 [BPF] uint8 [AUL] bool int64 int64 int64 int64 // General 'G' 'F' 'A' false r c 0 0 // Band 'G' 'B' 'A' false r c kU kL // Symmetric 'S' 'F' ul false n n 0 0 // SymmetricBand 'S' 'B' ul false n n k k // SymmetricPacked 'S' 'P' ul false n n 0 0 // Triangular 'T' 'F' ul Diag==Unit n n 0 0 // TriangularBand 'T' 'B' ul Diag==Unit n n k k // TriangularPacked 'T' 'P' ul Diag==Unit n n 0 0 // // G - general, S - symmetric, T - triangular // F - full, B - band, P - packed // A - all, U - upper, L - lower // MarshalBinary encodes the receiver into a binary form and returns the result. // // Dense is little-endian encoded as follows: // // 0 - 3 Version = 1 (uint32) // 4 'G' (byte) // 5 'F' (byte) // 6 'A' (byte) // 7 0 (byte) // 8 - 15 number of rows (int64) // 16 - 23 number of columns (int64) // 24 - 31 0 (int64) // 32 - 39 0 (int64) // 40 - .. matrix data elements (float64) // [0,0] [0,1] ... [0,ncols-1] // [1,0] [1,1] ... [1,ncols-1] // ... // [nrows-1,0] ... [nrows-1,ncols-1] func (m Dense) MarshalBinary() ([]byte, error) { bufLen := int64(headerSize) + int64(m.mat.Rows)*int64(m.mat.Cols)*int64(sizeFloat64) if bufLen <= 0 { // bufLen is too big and has wrapped around. return nil, errTooBig } header := storage{ Form: 'G', Packing: 'F', Uplo: 'A', Rows: int64(m.mat.Rows), Cols: int64(m.mat.Cols), Version: version, } buf := make([]byte, bufLen) n, err := header.marshalBinaryTo(bytes.NewBuffer(buf[:0])) if err != nil { return buf[:n], err } p := headerSize r, c := m.Dims() for i := 0; i < r; i++ { for j := 0; j < c; j++ { binary.LittleEndian.PutUint64(buf[p:p+sizeFloat64], math.Float64bits(m.at(i, j))) p += sizeFloat64 } } return buf, nil } // MarshalBinaryTo encodes the receiver into a binary form and writes it into w. // MarshalBinaryTo returns the number of bytes written into w and an error, if any. // // See MarshalBinary for the on-disk layout. func (m Dense) MarshalBinaryTo(w io.Writer) (int, error) { header := storage{ Form: 'G', Packing: 'F', Uplo: 'A', Rows: int64(m.mat.Rows), Cols: int64(m.mat.Cols), Version: version, } n, err := header.marshalBinaryTo(w) if err != nil { return n, err } r, c := m.Dims() var b [8]byte for i := 0; i < r; i++ { for j := 0; j < c; j++ { binary.LittleEndian.PutUint64(b[:], math.Float64bits(m.at(i, j))) nn, err := w.Write(b[:]) n += nn if err != nil { return n, err } } } return n, nil } // UnmarshalBinary decodes the binary form into the receiver. // It panics if the receiver is a non-empty Dense matrix. // // See MarshalBinary for the on-disk layout. // // Limited checks on the validity of the binary input are performed: // - ErrShape is returned if the number of rows or columns is negative, // - an error is returned if the resulting Dense matrix is too // big for the current architecture (e.g. a 16GB matrix written by a // 64b application and read back from a 32b application.) // // UnmarshalBinary does not limit the size of the unmarshaled matrix, and so // it should not be used on untrusted data. func (m *Dense) UnmarshalBinary(data []byte) error { if !m.IsEmpty() { panic("mat: unmarshal into non-empty matrix") } if len(data) < headerSize { return errTooSmall } var header storage err := header.unmarshalBinary(data[:headerSize]) if err != nil { return err } rows := header.Rows cols := header.Cols header.Version = 0 header.Rows = 0 header.Cols = 0 if (header != storage{Form: 'G', Packing: 'F', Uplo: 'A'}) { return errWrongType } if rows < 0 || cols < 0 { return errBadSize } size := rows * cols if size == 0 { return ErrZeroLength } if int(size) < 0 || size > maxLen { return errTooBig } if len(data) != headerSize+int(rows*cols)*sizeFloat64 { return errBadBuffer } p := headerSize m.reuseAsNonZeroed(int(rows), int(cols)) for i := range m.mat.Data { m.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[p : p+sizeFloat64])) p += sizeFloat64 } return nil } // UnmarshalBinaryFrom decodes the binary form into the receiver and returns // the number of bytes read and an error if any. // It panics if the receiver is a non-empty Dense matrix. // // See MarshalBinary for the on-disk layout. // // Limited checks on the validity of the binary input are performed: // - ErrShape is returned if the number of rows or columns is negative, // - an error is returned if the resulting Dense matrix is too // big for the current architecture (e.g. a 16GB matrix written by a // 64b application and read back from a 32b application.) // // UnmarshalBinary does not limit the size of the unmarshaled matrix, and so // it should not be used on untrusted data. func (m *Dense) UnmarshalBinaryFrom(r io.Reader) (int, error) { if !m.IsEmpty() { panic("mat: unmarshal into non-empty matrix") } var header storage n, err := header.unmarshalBinaryFrom(r) if err != nil { return n, err } rows := header.Rows cols := header.Cols header.Version = 0 header.Rows = 0 header.Cols = 0 if (header != storage{Form: 'G', Packing: 'F', Uplo: 'A'}) { return n, errWrongType } if rows < 0 || cols < 0 { return n, errBadSize } size := rows * cols if size == 0 { return n, ErrZeroLength } if int(size) < 0 || size > maxLen { return n, errTooBig } m.reuseAsNonZeroed(int(rows), int(cols)) var b [8]byte for i := range m.mat.Data { nn, err := readFull(r, b[:]) n += nn if err != nil { if err == io.EOF { return n, io.ErrUnexpectedEOF } return n, err } m.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(b[:])) } return n, nil } // MarshalBinary encodes the receiver into a binary form and returns the result. // // VecDense is little-endian encoded as follows: // // 0 - 3 Version = 1 (uint32) // 4 'G' (byte) // 5 'F' (byte) // 6 'A' (byte) // 7 0 (byte) // 8 - 15 number of elements (int64) // 16 - 23 1 (int64) // 24 - 31 0 (int64) // 32 - 39 0 (int64) // 40 - .. vector's data elements (float64) func (v VecDense) MarshalBinary() ([]byte, error) { bufLen := int64(headerSize) + int64(v.mat.N)*int64(sizeFloat64) if bufLen <= 0 { // bufLen is too big and has wrapped around. return nil, errTooBig } header := storage{ Form: 'G', Packing: 'F', Uplo: 'A', Rows: int64(v.mat.N), Cols: 1, Version: version, } buf := make([]byte, bufLen) n, err := header.marshalBinaryTo(bytes.NewBuffer(buf[:0])) if err != nil { return buf[:n], err } p := headerSize for i := 0; i < v.mat.N; i++ { binary.LittleEndian.PutUint64(buf[p:p+sizeFloat64], math.Float64bits(v.at(i))) p += sizeFloat64 } return buf, nil } // MarshalBinaryTo encodes the receiver into a binary form, writes it to w and // returns the number of bytes written and an error if any. // // See MarshalBinary for the on-disk format. func (v VecDense) MarshalBinaryTo(w io.Writer) (int, error) { header := storage{ Form: 'G', Packing: 'F', Uplo: 'A', Rows: int64(v.mat.N), Cols: 1, Version: version, } n, err := header.marshalBinaryTo(w) if err != nil { return n, err } var buf [8]byte for i := 0; i < v.mat.N; i++ { binary.LittleEndian.PutUint64(buf[:], math.Float64bits(v.at(i))) nn, err := w.Write(buf[:]) n += nn if err != nil { return n, err } } return n, nil } // UnmarshalBinary decodes the binary form into the receiver. // It panics if the receiver is a non-empty VecDense. // // See MarshalBinary for the on-disk layout. // // Limited checks on the validity of the binary input are performed: // - ErrShape is returned if the number of rows is negative, // - an error is returned if the resulting VecDense is too // big for the current architecture (e.g. a 16GB vector written by a // 64b application and read back from a 32b application.) // // UnmarshalBinary does not limit the size of the unmarshaled vector, and so // it should not be used on untrusted data. func (v *VecDense) UnmarshalBinary(data []byte) error { if !v.IsEmpty() { panic("mat: unmarshal into non-empty vector") } if len(data) < headerSize { return errTooSmall } var header storage err := header.unmarshalBinary(data[:headerSize]) if err != nil { return err } if header.Cols != 1 { return ErrShape } n := header.Rows header.Version = 0 header.Rows = 0 header.Cols = 0 if (header != storage{Form: 'G', Packing: 'F', Uplo: 'A'}) { return errWrongType } if n == 0 { return ErrZeroLength } if n < 0 { return errBadSize } if int64(maxLen) < n { return errTooBig } if len(data) != headerSize+int(n)*sizeFloat64 { return errBadBuffer } p := headerSize v.reuseAsNonZeroed(int(n)) for i := range v.mat.Data { v.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[p : p+sizeFloat64])) p += sizeFloat64 } return nil } // UnmarshalBinaryFrom decodes the binary form into the receiver, from the // io.Reader and returns the number of bytes read and an error if any. // It panics if the receiver is a non-empty VecDense. // // See MarshalBinary for the on-disk layout. // See UnmarshalBinary for the list of sanity checks performed on the input. func (v *VecDense) UnmarshalBinaryFrom(r io.Reader) (int, error) { if !v.IsEmpty() { panic("mat: unmarshal into non-empty vector") } var header storage n, err := header.unmarshalBinaryFrom(r) if err != nil { return n, err } if header.Cols != 1 { return n, ErrShape } l := header.Rows header.Version = 0 header.Rows = 0 header.Cols = 0 if (header != storage{Form: 'G', Packing: 'F', Uplo: 'A'}) { return n, errWrongType } if l == 0 { return n, ErrZeroLength } if l < 0 { return n, errBadSize } if int64(maxLen) < l { return n, errTooBig } v.reuseAsNonZeroed(int(l)) var b [8]byte for i := range v.mat.Data { nn, err := readFull(r, b[:]) n += nn if err != nil { if err == io.EOF { return n, io.ErrUnexpectedEOF } return n, err } v.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(b[:])) } return n, nil } // storage is the internal representation of the storage format of a // serialised matrix. type storage struct { Version uint32 // Keep this first. Form byte // [GST] Packing byte // [BPF] Uplo byte // [AUL] Unit bool Rows int64 Cols int64 KU int64 KL int64 } // TODO(kortschak): Consider replacing these with calls to direct // encoding/decoding of fields rather than to binary.Write/binary.Read. func (s storage) marshalBinaryTo(w io.Writer) (int, error) { buf := bytes.NewBuffer(make([]byte, 0, headerSize)) err := binary.Write(buf, binary.LittleEndian, s) if err != nil { return 0, err } return w.Write(buf.Bytes()) } func (s *storage) unmarshalBinary(buf []byte) error { err := binary.Read(bytes.NewReader(buf), binary.LittleEndian, s) if err != nil { return err } if s.Version != version { return fmt.Errorf("mat: incorrect version: %d", s.Version) } return nil } func (s *storage) unmarshalBinaryFrom(r io.Reader) (int, error) { buf := make([]byte, headerSize) n, err := readFull(r, buf) if err != nil { return n, err } return n, s.unmarshalBinary(buf[:n]) } // readFull reads from r into buf until it has read len(buf). // It returns the number of bytes copied and an error if fewer bytes were read. // If an EOF happens after reading fewer than len(buf) bytes, io.ErrUnexpectedEOF is returned. func readFull(r io.Reader, buf []byte) (int, error) { var n int var err error for n < len(buf) && err == nil { var nn int nn, err = r.Read(buf[n:]) n += nn } if n == len(buf) { return n, nil } if err == io.EOF { return n, io.ErrUnexpectedEOF } return n, err } golang-gonum-v1-gonum-0.14.0/mat/io_test.go000066400000000000000000000547141450372207100204270ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "bytes" "encoding" "encoding/binary" "io" "math" "testing" "gonum.org/v1/gonum/blas/blas64" ) var ( _ encoding.BinaryMarshaler = (*Dense)(nil) _ encoding.BinaryUnmarshaler = (*Dense)(nil) _ encoding.BinaryMarshaler = (*VecDense)(nil) _ encoding.BinaryUnmarshaler = (*VecDense)(nil) ) var sizeInt64 = binary.Size(int64(0)) var denseData = []struct { raw []byte want *Dense err error eq func(got, want Matrix) bool }{ { raw: []byte("\x01\x00\x00\x00GFA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), want: &Dense{}, err: ErrZeroLength, eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@"), want: NewDense(2, 2, []float64{1, 2, 3, 4}), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@"), want: NewDense(2, 3, []float64{1, 2, 3, 4, 5, 6}), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@"), want: NewDense(3, 2, []float64{1, 2, 3, 4, 5, 6}), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@\x00\x00\x00\x00\x00\x00\x1c@\x00\x00\x00\x00\x00\x00 @\x00\x00\x00\x00\x00\x00\"@"), want: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@"), want: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}).Slice(0, 2, 0, 2).(*Dense), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@\x00\x00\x00\x00\x00\x00 @\x00\x00\x00\x00\x00\x00\"@"), want: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}).Slice(1, 3, 1, 3).(*Dense), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@\x00\x00\x00\x00\x00\x00 @\x00\x00\x00\x00\x00\x00\"@"), want: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}).Slice(0, 3, 1, 3).(*Dense), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xff\x00\x00\x00\x00\x00\x00\xf0\u007f\x01\x00\x00\x00\x00\x00\xf8\u007f"), want: NewDense(1, 4, []float64{0, math.Inf(-1), math.Inf(+1), math.NaN()}), eq: func(got, want Matrix) bool { for _, v := range []bool{ got.At(0, 0) == 0, math.IsInf(got.At(0, 1), -1), math.IsInf(got.At(0, 2), +1), math.IsNaN(got.At(0, 3)), } { if !v { return false } } return true }, }, } func TestDenseMarshal(t *testing.T) { t.Parallel() for i, test := range denseData { buf, err := test.want.MarshalBinary() if err != nil { t.Errorf("error encoding test-%d: %v\n", i, err) continue } nrows, ncols := test.want.Dims() sz := headerSize + nrows*ncols*sizeFloat64 if len(buf) != sz { t.Errorf("encoded size test-%d: want=%d got=%d\n", i, sz, len(buf)) } if !bytes.Equal(buf, test.raw) { t.Errorf("error encoding test-%d: bytes mismatch.\n got=%q\nwant=%q\n", i, string(buf), string(test.raw), ) continue } } } func TestDenseMarshalTo(t *testing.T) { t.Parallel() for i, test := range denseData { buf := new(bytes.Buffer) n, err := test.want.MarshalBinaryTo(buf) if err != nil { t.Errorf("error encoding test-%d: %v\n", i, err) continue } nrows, ncols := test.want.Dims() sz := headerSize + nrows*ncols*sizeFloat64 if n != sz { t.Errorf("encoded size test-%d: want=%d got=%d\n", i, sz, n) } if !bytes.Equal(buf.Bytes(), test.raw) { t.Errorf("error encoding test-%d: bytes mismatch.\n got=%q\nwant=%q\n", i, buf.Bytes(), test.raw, ) continue } } } func TestDenseUnmarshal(t *testing.T) { t.Parallel() for i, test := range denseData { var v Dense err := v.UnmarshalBinary(test.raw) if err != nil { if err != test.err { t.Errorf("error decoding test-%d: %v\n", i, err) } continue } if !test.eq(&v, test.want) { t.Errorf("error decoding test-%d: values differ.\n got=%v\nwant=%v\n", i, &v, test.want, ) } } } func TestDenseUnmarshalFrom(t *testing.T) { t.Parallel() for i, test := range denseData { var v Dense buf := bytes.NewReader(test.raw) n, err := v.UnmarshalBinaryFrom(buf) if err != nil { if err != test.err { t.Errorf("error decoding test-%d: %v\n", i, err) } continue } if n != len(test.raw) { t.Errorf("error decoding test-%d: lengths differ.\n got=%d\nwant=%d\n", i, n, len(test.raw), ) } if !test.eq(&v, test.want) { t.Errorf("error decoding test-%d: values differ.\n got=%v\nwant=%v\n", i, &v, test.want, ) } } } func TestDenseUnmarshalFromError(t *testing.T) { t.Parallel() test := denseData[1] for i, tt := range []struct { beg int end int }{ { beg: 0, end: len(test.raw) - 1, }, { beg: 0, end: len(test.raw) - sizeFloat64, }, { beg: 0, end: 0, }, { beg: 0, end: 1, }, { beg: 0, end: sizeInt64, }, { beg: 0, end: sizeInt64 - 1, }, { beg: 0, end: sizeInt64 + 1, }, { beg: 0, end: 2*sizeInt64 - 1, }, { beg: 0, end: 2 * sizeInt64, }, { beg: 0, end: 2*sizeInt64 + 1, }, { beg: 0, end: 2*sizeInt64 + sizeFloat64 - 1, }, { beg: 0, end: 2*sizeInt64 + sizeFloat64, }, { beg: 0, end: 2*sizeInt64 + sizeFloat64 + 1, }, } { buf := bytes.NewReader(test.raw[tt.beg:tt.end]) var m Dense _, err := m.UnmarshalBinaryFrom(buf) if err != io.ErrUnexpectedEOF { t.Errorf("test #%d: error decoding. got=%v. want=%v\n", i, err, io.ErrUnexpectedEOF) } } } func TestDenseIORoundTrip(t *testing.T) { t.Parallel() for i, test := range denseData { buf, err := test.want.MarshalBinary() if err != nil { t.Errorf("error encoding test #%d: %v\n", i, err) } var got Dense err = got.UnmarshalBinary(buf) if err != nil { if err != test.err { t.Errorf("error decoding test #%d: %v\n", i, err) } continue } if !test.eq(&got, test.want) { t.Errorf("r/w test #%d failed\n got=%#v\nwant=%#v\n", i, &got, test.want) } wbuf := new(bytes.Buffer) _, err = test.want.MarshalBinaryTo(wbuf) if err != nil { t.Errorf("error encoding test #%d: %v\n", i, err) } if !bytes.Equal(buf, wbuf.Bytes()) { t.Errorf("r/w test #%d encoding via MarshalBinary and MarshalBinaryTo differ:\nwith-stream: %q\n no-stream: %q\n", i, wbuf.Bytes(), buf, ) } var wgot Dense _, err = wgot.UnmarshalBinaryFrom(wbuf) if err != nil { t.Errorf("error decoding test #%d: %v\n", i, err) } if !test.eq(&wgot, test.want) { t.Errorf("r/w test #%d failed\n got=%#v\nwant=%#v\n", i, &wgot, test.want) } } } var vectorData = []struct { raw []byte want *VecDense err error eq func(got, want Matrix) bool }{ { raw: []byte("\x01\x00\x00\x00GFA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), want: &VecDense{}, err: ErrZeroLength, eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@"), want: NewVecDense(4, []float64{1, 2, 3, 4}), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@"), want: NewVecDense(6, []float64{1, 2, 3, 4, 5, 6}), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\t\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@\x00\x00\x00\x00\x00\x00\x1c@\x00\x00\x00\x00\x00\x00 @\x00\x00\x00\x00\x00\x00\"@"), want: NewVecDense(9, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@"), want: NewVecDense(9, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}).SliceVec(0, 3).(*VecDense), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@"), want: NewVecDense(9, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}).SliceVec(1, 4).(*VecDense), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@\x00\x00\x00\x00\x00\x00\x1c@\x00\x00\x00\x00\x00\x00 @"), want: NewVecDense(9, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}).SliceVec(0, 8).(*VecDense), eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\b@\x00\x00\x00\x00\x00\x00\x18@"), want: &VecDense{ mat: blas64.Vector{ N: 3, Data: []float64{0, 1, 2, 3, 4, 5, 6}, Inc: 3, }, }, eq: Equal, }, { raw: []byte("\x01\x00\x00\x00GFA\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xff\x00\x00\x00\x00\x00\x00\xf0\u007f\x01\x00\x00\x00\x00\x00\xf8\u007f"), want: NewVecDense(4, []float64{0, math.Inf(-1), math.Inf(+1), math.NaN()}), eq: func(got, want Matrix) bool { for _, v := range []bool{ got.At(0, 0) == 0, math.IsInf(got.At(1, 0), -1), math.IsInf(got.At(2, 0), +1), math.IsNaN(got.At(3, 0)), } { if !v { return false } } return true }, }, } func TestVecDenseMarshal(t *testing.T) { t.Parallel() for i, test := range vectorData { buf, err := test.want.MarshalBinary() if err != nil { t.Errorf("error encoding test-%d: %v\n", i, err) continue } nrows, ncols := test.want.Dims() sz := headerSize + nrows*ncols*sizeFloat64 if len(buf) != sz { t.Errorf("encoded size test-%d: want=%d got=%d\n", i, sz, len(buf)) } if !bytes.Equal(buf, test.raw) { t.Errorf("error encoding test-%d: bytes mismatch.\n got=%q\nwant=%q\n", i, string(buf), string(test.raw), ) continue } } } func TestVecDenseMarshalTo(t *testing.T) { t.Parallel() for i, test := range vectorData { buf := new(bytes.Buffer) n, err := test.want.MarshalBinaryTo(buf) if err != nil { t.Errorf("error encoding test-%d: %v\n", i, err) continue } nrows, ncols := test.want.Dims() sz := headerSize + nrows*ncols*sizeFloat64 if n != sz { t.Errorf("encoded size test-%d: want=%d got=%d\n", i, sz, n) } if !bytes.Equal(buf.Bytes(), test.raw) { t.Errorf("error encoding test-%d: bytes mismatch.\n got=%q\nwant=%q\n", i, buf.Bytes(), test.raw, ) continue } } } func TestVecDenseUnmarshal(t *testing.T) { t.Parallel() for i, test := range vectorData { var v VecDense err := v.UnmarshalBinary(test.raw) if err != nil { if err != test.err { t.Errorf("error decoding test-%d: %v\n", i, err) } continue } if !test.eq(&v, test.want) { t.Errorf("error decoding test-%d: values differ.\n got=%v\nwant=%v\n", i, &v, test.want, ) } } } func TestVecDenseUnmarshalFrom(t *testing.T) { t.Parallel() for i, test := range vectorData { var v VecDense buf := bytes.NewReader(test.raw) n, err := v.UnmarshalBinaryFrom(buf) if err != nil { if err != test.err { t.Errorf("error decoding test-%d: %v\n", i, err) } continue } if n != len(test.raw) { t.Errorf("error decoding test-%d: lengths differ.\n got=%d\nwant=%d\n", i, n, len(test.raw), ) } if !test.eq(&v, test.want) { t.Errorf("error decoding test-%d: values differ.\n got=%v\nwant=%v\n", i, &v, test.want, ) } } } func TestVecDenseUnmarshalFromError(t *testing.T) { t.Parallel() test := vectorData[1] for i, tt := range []struct { beg int end int }{ { beg: 0, end: len(test.raw) - 1, }, { beg: 0, end: len(test.raw) - sizeFloat64, }, { beg: 0, end: 0, }, { beg: 0, end: 1, }, { beg: 0, end: sizeInt64, }, { beg: 0, end: sizeInt64 - 1, }, { beg: 0, end: sizeInt64 + 1, }, { beg: 0, end: sizeInt64 + sizeFloat64 - 1, }, { beg: 0, end: sizeInt64 + sizeFloat64, }, { beg: 0, end: sizeInt64 + sizeFloat64 + 1, }, } { buf := bytes.NewReader(test.raw[tt.beg:tt.end]) var v VecDense _, err := v.UnmarshalBinaryFrom(buf) if err != io.ErrUnexpectedEOF { t.Errorf("test #%d: error decoding. got=%v. want=%v\n", i, err, io.ErrUnexpectedEOF) } } } func TestVecDenseIORoundTrip(t *testing.T) { t.Parallel() for i, test := range vectorData { buf, err := test.want.MarshalBinary() if err != nil { t.Errorf("error encoding test #%d: %v\n", i, err) } var got VecDense err = got.UnmarshalBinary(buf) if err != nil { if err != test.err { t.Errorf("error decoding test #%d: %v\n", i, err) } continue } if !test.eq(&got, test.want) { t.Errorf("r/w test #%d failed\n got=%#v\nwant=%#v\n", i, &got, test.want) } wbuf := new(bytes.Buffer) _, err = test.want.MarshalBinaryTo(wbuf) if err != nil { t.Errorf("error encoding test #%d: %v\n", i, err) } if !bytes.Equal(buf, wbuf.Bytes()) { t.Errorf("test #%d encoding via MarshalBinary and MarshalBinaryTo differ:\nwith-stream: %q\n no-stream: %q\n", i, wbuf.Bytes(), buf, ) } var wgot VecDense _, err = wgot.UnmarshalBinaryFrom(wbuf) if err != nil { t.Errorf("error decoding test #%d: %v\n", i, err) } if !test.eq(&wgot, test.want) { t.Errorf("r/w test #%d failed\n got=%#v\nwant=%#v\n", i, &wgot, test.want) } } } func BenchmarkMarshalDense10(b *testing.B) { marshalBinaryBenchDense(b, 10) } func BenchmarkMarshalDense100(b *testing.B) { marshalBinaryBenchDense(b, 100) } func BenchmarkMarshalDense1000(b *testing.B) { marshalBinaryBenchDense(b, 1000) } func BenchmarkMarshalDense10000(b *testing.B) { marshalBinaryBenchDense(b, 10000) } func marshalBinaryBenchDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } m := NewDense(1, size, data) b.ResetTimer() for n := 0; n < b.N; n++ { _, err := m.MarshalBinary() if err != nil { b.Fatalf("unexpected error: %v", err) } } } func BenchmarkUnmarshalDense10(b *testing.B) { unmarshalBinaryBenchDense(b, 10) } func BenchmarkUnmarshalDense100(b *testing.B) { unmarshalBinaryBenchDense(b, 100) } func BenchmarkUnmarshalDense1000(b *testing.B) { unmarshalBinaryBenchDense(b, 1000) } func BenchmarkUnmarshalDense10000(b *testing.B) { unmarshalBinaryBenchDense(b, 10000) } func unmarshalBinaryBenchDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } buf, err := NewDense(1, size, data).MarshalBinary() if err != nil { b.Fatalf("error creating binary buffer (size=%d): %v\n", size, err) } b.ResetTimer() for n := 0; n < b.N; n++ { var m Dense err := m.UnmarshalBinary(buf) if err != nil { b.Fatalf("unexpected error: %v", err) } } } func BenchmarkMarshalToDense10(b *testing.B) { marshalBinaryToBenchDense(b, 10) } func BenchmarkMarshalToDense100(b *testing.B) { marshalBinaryToBenchDense(b, 100) } func BenchmarkMarshalToDense1000(b *testing.B) { marshalBinaryToBenchDense(b, 1000) } func BenchmarkMarshalToDense10000(b *testing.B) { marshalBinaryToBenchDense(b, 10000) } func marshalBinaryToBenchDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } m := NewDense(1, size, data) w := io.Discard b.ResetTimer() for n := 0; n < b.N; n++ { _, err := m.MarshalBinaryTo(w) if err != nil { b.Fatalf("unexpected error: %v", err) } } } type readerTest struct { buf []byte pos int } func (r *readerTest) Read(data []byte) (int, error) { n := copy(data, r.buf[r.pos:r.pos+len(data)]) r.pos += n return n, nil } func (r *readerTest) reset() { r.pos = 0 } func BenchmarkUnmarshalFromDense10(b *testing.B) { unmarshalBinaryFromBenchDense(b, 10) } func BenchmarkUnmarshalFromDense100(b *testing.B) { unmarshalBinaryFromBenchDense(b, 100) } func BenchmarkUnmarshalFromDense1000(b *testing.B) { unmarshalBinaryFromBenchDense(b, 1000) } func BenchmarkUnmarshalFromDense10000(b *testing.B) { unmarshalBinaryFromBenchDense(b, 10000) } func unmarshalBinaryFromBenchDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } buf, err := NewDense(1, size, data).MarshalBinary() if err != nil { b.Fatalf("error creating binary buffer (size=%d): %v\n", size, err) } r := &readerTest{buf: buf} b.ResetTimer() for n := 0; n < b.N; n++ { var m Dense _, err := m.UnmarshalBinaryFrom(r) if err != nil { b.Fatalf("unexpected error: %v", err) } r.reset() } } func BenchmarkMarshalVecDense10(b *testing.B) { marshalBinaryBenchVecDense(b, 10) } func BenchmarkMarshalVecDense100(b *testing.B) { marshalBinaryBenchVecDense(b, 100) } func BenchmarkMarshalVecDense1000(b *testing.B) { marshalBinaryBenchVecDense(b, 1000) } func BenchmarkMarshalVecDense10000(b *testing.B) { marshalBinaryBenchVecDense(b, 10000) } func marshalBinaryBenchVecDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } vec := NewVecDense(size, data) b.ResetTimer() for n := 0; n < b.N; n++ { _, err := vec.MarshalBinary() if err != nil { b.Fatalf("unexpected error: %v", err) } } } func BenchmarkUnmarshalVecDense10(b *testing.B) { unmarshalBinaryBenchVecDense(b, 10) } func BenchmarkUnmarshalVecDense100(b *testing.B) { unmarshalBinaryBenchVecDense(b, 100) } func BenchmarkUnmarshalVecDense1000(b *testing.B) { unmarshalBinaryBenchVecDense(b, 1000) } func BenchmarkUnmarshalVecDense10000(b *testing.B) { unmarshalBinaryBenchVecDense(b, 10000) } func unmarshalBinaryBenchVecDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } buf, err := NewVecDense(size, data).MarshalBinary() if err != nil { b.Fatalf("error creating binary buffer (size=%d): %v\n", size, err) } b.ResetTimer() for n := 0; n < b.N; n++ { var vec VecDense err := vec.UnmarshalBinary(buf) if err != nil { b.Fatalf("unexpected error: %v", err) } } } func BenchmarkMarshalToVecDense10(b *testing.B) { marshalBinaryToBenchVecDense(b, 10) } func BenchmarkMarshalToVecDense100(b *testing.B) { marshalBinaryToBenchVecDense(b, 100) } func BenchmarkMarshalToVecDense1000(b *testing.B) { marshalBinaryToBenchVecDense(b, 1000) } func BenchmarkMarshalToVecDense10000(b *testing.B) { marshalBinaryToBenchVecDense(b, 10000) } func marshalBinaryToBenchVecDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } vec := NewVecDense(size, data) w := io.Discard b.ResetTimer() for n := 0; n < b.N; n++ { _, err := vec.MarshalBinaryTo(w) if err != nil { b.Fatalf("unexpected error: %v", err) } } } func BenchmarkUnmarshalFromVecDense10(b *testing.B) { unmarshalBinaryFromBenchVecDense(b, 10) } func BenchmarkUnmarshalFromVecDense100(b *testing.B) { unmarshalBinaryFromBenchVecDense(b, 100) } func BenchmarkUnmarshalFromVecDense1000(b *testing.B) { unmarshalBinaryFromBenchVecDense(b, 1000) } func BenchmarkUnmarshalFromVecDense10000(b *testing.B) { unmarshalBinaryFromBenchVecDense(b, 10000) } func unmarshalBinaryFromBenchVecDense(b *testing.B, size int) { data := make([]float64, size) for i := range data { data[i] = float64(i) } buf, err := NewVecDense(size, data).MarshalBinary() if err != nil { b.Fatalf("error creating binary buffer (size=%d): %v\n", size, err) } r := &readerTest{buf: buf} b.ResetTimer() for n := 0; n < b.N; n++ { var vec VecDense _, err := vec.UnmarshalBinaryFrom(r) if err != nil { b.Fatalf("unexpected error: %v", err) } r.reset() } } golang-gonum-v1-gonum-0.14.0/mat/list_test.go000066400000000000000000001327641450372207100207750ustar00rootroot00000000000000// 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. //lint:file-ignore U1000 A number of functions are here that may be used in future. package mat import ( "fmt" "math" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) // legalSizeSameRectangular returns whether the two matrices have the same rectangular shape. func legalSizeSameRectangular(ar, ac, br, bc int) bool { if ar != br { return false } if ac != bc { return false } return true } // legalSizeSameSquare returns whether the two matrices have the same square shape. func legalSizeSameSquare(ar, ac, br, bc int) bool { if ar != br { return false } if ac != bc { return false } if ar != ac { return false } return true } // legalSizeSameHeight returns whether the two matrices have the same number of rows. func legalSizeSameHeight(ar, _, br, _ int) bool { return ar == br } // legalSizeSameWidth returns whether the two matrices have the same number of columns. func legalSizeSameWidth(_, ac, _, bc int) bool { return ac == bc } // legalSizeSolve returns whether the two matrices can be used in a linear solve. func legalSizeSolve(ar, ac, br, bc int) bool { return ar == br } // legalSizeSameVec returns whether the two matrices are column vectors. func legalSizeVector(_, ac, _, bc int) bool { return ac == 1 && bc == 1 } // legalSizeSameVec returns whether the two matrices are column vectors of the // same dimension. func legalSizeSameVec(ar, ac, br, bc int) bool { return ac == 1 && bc == 1 && ar == br } // isAnySize returns true for all matrix sizes. func isAnySize(ar, ac int) bool { return true } // isAnySize2 returns true for all matrix sizes. func isAnySize2(ar, ac, br, bc int) bool { return true } // isAnyColumnVector returns true for any column vector sizes. func isAnyColumnVector(ar, ac int) bool { return ac == 1 } // isSquare returns whether the input matrix is square. func isSquare(r, c int) bool { return r == c } // sameAnswerFloat returns whether the two inputs are both NaN or are equal. func sameAnswerFloat(a, b interface{}) bool { if math.IsNaN(a.(float64)) { return math.IsNaN(b.(float64)) } return a.(float64) == b.(float64) } // sameAnswerFloatApproxTol returns a function that determines whether its two // inputs are both NaN or within tol of each other. func sameAnswerFloatApproxTol(tol float64) func(a, b interface{}) bool { return func(a, b interface{}) bool { if math.IsNaN(a.(float64)) { return math.IsNaN(b.(float64)) } return scalar.EqualWithinAbsOrRel(a.(float64), b.(float64), tol, tol) } } func sameAnswerF64SliceOfSlice(a, b interface{}) bool { for i, v := range a.([][]float64) { if same := floats.Same(v, b.([][]float64)[i]); !same { return false } } return true } // sameAnswerBool returns whether the two inputs have the same value. func sameAnswerBool(a, b interface{}) bool { return a.(bool) == b.(bool) } // isAnyType returns true for all Matrix types. func isAnyType(Matrix) bool { return true } // legalTypesAll returns true for all Matrix types. func legalTypesAll(a, b Matrix) bool { return true } // legalTypeSym returns whether a is a Symmetric. func legalTypeSym(a Matrix) bool { _, ok := a.(Symmetric) return ok } // legalTypeTri returns whether a is a Triangular. func legalTypeTri(a Matrix) bool { _, ok := a.(Triangular) return ok } // legalTypeTriLower returns whether a is a Triangular with kind == Lower. func legalTypeTriLower(a Matrix) bool { t, ok := a.(Triangular) if !ok { return false } _, kind := t.Triangle() return kind == Lower } // legalTypeTriUpper returns whether a is a Triangular with kind == Upper. func legalTypeTriUpper(a Matrix) bool { t, ok := a.(Triangular) if !ok { return false } _, kind := t.Triangle() return kind == Upper } // legalTypesSym returns whether both input arguments are Symmetric. func legalTypesSym(a, b Matrix) bool { if _, ok := a.(Symmetric); !ok { return false } if _, ok := b.(Symmetric); !ok { return false } return true } // legalTypeVector returns whether v is a Vector. func legalTypeVector(v Matrix) bool { _, ok := v.(Vector) return ok } // legalTypeVec returns whether v is a *VecDense. func legalTypeVecDense(v Matrix) bool { _, ok := v.(*VecDense) return ok } // legalTypesVectorVector returns whether both inputs are Vector func legalTypesVectorVector(a, b Matrix) bool { if _, ok := a.(Vector); !ok { return false } if _, ok := b.(Vector); !ok { return false } return true } // legalTypesVecDenseVecDense returns whether both inputs are *VecDense. func legalTypesVecDenseVecDense(a, b Matrix) bool { if _, ok := a.(*VecDense); !ok { return false } if _, ok := b.(*VecDense); !ok { return false } return true } // legalTypesMatrixVector returns whether the first input is an arbitrary Matrix // and the second input is a Vector. func legalTypesMatrixVector(a, b Matrix) bool { _, ok := b.(Vector) return ok } // legalTypesMatrixVecDense returns whether the first input is an arbitrary Matrix // and the second input is a *VecDense. func legalTypesMatrixVecDense(a, b Matrix) bool { _, ok := b.(*VecDense) return ok } // legalDims returns whether {m,n} is a valid dimension of the given matrix type. func legalDims(a Matrix, m, n int) bool { switch t := a.(type) { default: panic("legal dims type not coded") case Untransposer: return legalDims(t.Untranspose(), n, m) case *Dense, *basicMatrix, *BandDense, *basicBanded: if m < 0 || n < 0 { return false } return true case *SymDense, *TriDense, *basicSymmetric, *basicTriangular, *SymBandDense, *basicSymBanded, *TriBandDense, *basicTriBanded, *basicDiagonal, *DiagDense, *Tridiag: if m < 0 || n < 0 || m != n { return false } return true case *VecDense, *basicVector: if m < 0 || n < 0 { return false } return n == 1 } } // returnAs returns the matrix a with the type of t. Used for making a concrete // type and changing to the basic form. func returnAs(a, t Matrix) Matrix { switch mat := a.(type) { default: panic("unknown type for a") case *Dense: switch t.(type) { default: panic("bad type") case *Dense: return mat case *basicMatrix: return asBasicMatrix(mat) } case *SymDense: switch t.(type) { default: panic("bad type") case *SymDense: return mat case *basicSymmetric: return asBasicSymmetric(mat) } case *TriDense: switch t.(type) { default: panic("bad type") case *TriDense: return mat case *basicTriangular: return asBasicTriangular(mat) } case *BandDense: switch t.(type) { default: panic("bad type") case *BandDense: return mat case *basicBanded: return asBasicBanded(mat) } case *SymBandDense: switch t.(type) { default: panic("bad type") case *SymBandDense: return mat case *basicSymBanded: return asBasicSymBanded(mat) } case *TriBandDense: switch t.(type) { default: panic("bad type") case *TriBandDense: return mat case *basicTriBanded: return asBasicTriBanded(mat) } case *DiagDense: switch t.(type) { default: panic("bad type") case *DiagDense: return mat case *basicDiagonal: return asBasicDiagonal(mat) } case *Tridiag: switch t.(type) { default: panic("bad type") case *Tridiag: return mat } } } // retranspose returns the matrix m inside an Untransposer of the type // of a. func retranspose(a, m Matrix) Matrix { switch a.(type) { case TransposeTriBand: return TransposeTriBand{m.(TriBanded)} case TransposeBand: return TransposeBand{m.(Banded)} case TransposeTri: return TransposeTri{m.(Triangular)} case Transpose: return Transpose{m} case Untransposer: panic("unknown transposer type") default: panic("a is not an untransposer") } } // makeRandOf returns a new randomly filled m×n matrix of the underlying matrix type. func makeRandOf(a Matrix, m, n int, src rand.Source) Matrix { rnd := rand.New(src) var rMatrix Matrix switch t := a.(type) { default: panic("unknown type for make rand of") case Untransposer: rMatrix = retranspose(a, makeRandOf(t.Untranspose(), n, m, src)) case *Dense, *basicMatrix: var mat = &Dense{} if m != 0 && n != 0 { mat = NewDense(m, n, nil) } for i := 0; i < m; i++ { for j := 0; j < n; j++ { mat.Set(i, j, rnd.NormFloat64()) } } rMatrix = returnAs(mat, t) case *VecDense: if m == 0 && n == 0 { return &VecDense{} } if n != 1 { panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n)) } length := m inc := 1 if t.mat.Inc != 0 { inc = t.mat.Inc } mat := &VecDense{ mat: blas64.Vector{ N: length, Inc: inc, Data: make([]float64, inc*(length-1)+1), }, } for i := 0; i < length; i++ { mat.SetVec(i, rnd.NormFloat64()) } return mat case *basicVector: if n != 1 { panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n)) } if m == 0 { return &basicVector{} } mat := NewVecDense(m, nil) for i := 0; i < m; i++ { mat.SetVec(i, rnd.NormFloat64()) } return asBasicVector(mat) case *SymDense, *basicSymmetric: if m != n { panic("bad size") } mat := &SymDense{} if n != 0 { mat = NewSymDense(n, nil) } for i := 0; i < m; i++ { for j := i; j < n; j++ { mat.SetSym(i, j, rnd.NormFloat64()) } } rMatrix = returnAs(mat, t) case *TriDense, *basicTriangular: if m != n { panic("bad size") } // This is necessary because we are making // a triangle from the zero value, which // always returns upper as true. var triKind TriKind switch t := t.(type) { case *TriDense: triKind = t.triKind() case *basicTriangular: triKind = (*TriDense)(t).triKind() } if n == 0 { uplo := blas.Upper if triKind == Lower { uplo = blas.Lower } return returnAs(&TriDense{mat: blas64.Triangular{Uplo: uplo}}, t) } mat := NewTriDense(n, triKind, nil) if triKind == Upper { for i := 0; i < m; i++ { for j := i; j < n; j++ { mat.SetTri(i, j, rnd.NormFloat64()) } } } else { for i := 0; i < m; i++ { for j := 0; j <= i; j++ { mat.SetTri(i, j, rnd.NormFloat64()) } } } rMatrix = returnAs(mat, t) case *BandDense, *basicBanded: var kl, ku int switch t := t.(type) { case *BandDense: kl = t.mat.KL ku = t.mat.KU case *basicBanded: ku = (*BandDense)(t).mat.KU kl = (*BandDense)(t).mat.KL } ku = min(ku, n-1) kl = min(kl, m-1) data := make([]float64, min(m, n+kl)*(kl+ku+1)) for i := range data { data[i] = rnd.NormFloat64() } mat := NewBandDense(m, n, kl, ku, data) rMatrix = returnAs(mat, t) case *SymBandDense, *basicSymBanded: if m != n { panic("bad size") } var k int switch t := t.(type) { case *SymBandDense: k = t.mat.K case *basicSymBanded: k = (*SymBandDense)(t).mat.K } k = min(k, m-1) // Special case for small sizes. data := make([]float64, m*(k+1)) for i := range data { data[i] = rnd.NormFloat64() } mat := NewSymBandDense(n, k, data) rMatrix = returnAs(mat, t) case *TriBandDense, *basicTriBanded: if m != n { panic("bad size") } var k int var triKind TriKind switch t := t.(type) { case *TriBandDense: k = t.mat.K triKind = t.triKind() case *basicTriBanded: k = (*TriBandDense)(t).mat.K triKind = (*TriBandDense)(t).triKind() } k = min(k, m-1) // Special case for small sizes. data := make([]float64, m*(k+1)) for i := range data { data[i] = rnd.NormFloat64() } mat := NewTriBandDense(n, k, triKind, data) rMatrix = returnAs(mat, t) case *DiagDense, *basicDiagonal: if m != n { panic("bad size") } var inc int switch t := t.(type) { case *DiagDense: inc = t.mat.Inc case *basicDiagonal: inc = (*DiagDense)(t).mat.Inc } if inc == 0 { inc = 1 } mat := &DiagDense{ mat: blas64.Vector{ N: n, Inc: inc, Data: make([]float64, inc*(n-1)+1), }, } for i := 0; i < n; i++ { mat.SetDiag(i, rnd.Float64()) } rMatrix = returnAs(mat, t) case *Tridiag: if m != n { panic("bad size") } mat := NewTridiag(n, nil, nil, nil) for i := 0; i < n; i++ { for j := max(0, i-1); j <= min(i+1, n-1); j++ { mat.SetBand(i, j, rnd.NormFloat64()) } } rMatrix = returnAs(mat, t) } if mr, mc := rMatrix.Dims(); mr != m || mc != n { panic(fmt.Sprintf("makeRandOf for %T returns wrong size: %d×%d != %d×%d", a, m, n, mr, mc)) } return rMatrix } // makeNaNOf returns a new m×n matrix of the underlying matrix type filled with NaN values. func makeNaNOf(a Matrix, m, n int) Matrix { var rMatrix Matrix switch t := a.(type) { default: panic("unknown type for makeNaNOf") case Untransposer: rMatrix = retranspose(a, makeNaNOf(t.Untranspose(), n, m)) case *Dense, *basicMatrix: var mat = &Dense{} if m != 0 && n != 0 { mat = NewDense(m, n, nil) } for i := 0; i < m; i++ { for j := 0; j < n; j++ { mat.Set(i, j, math.NaN()) } } rMatrix = returnAs(mat, t) case *VecDense: if m == 0 && n == 0 { return &VecDense{} } if n != 1 { panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n)) } length := m inc := 1 if t.mat.Inc != 0 { inc = t.mat.Inc } mat := &VecDense{ mat: blas64.Vector{ N: length, Inc: inc, Data: make([]float64, inc*(length-1)+1), }, } for i := 0; i < length; i++ { mat.SetVec(i, math.NaN()) } return mat case *basicVector: if n != 1 { panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n)) } if m == 0 { return &basicVector{} } mat := NewVecDense(m, nil) for i := 0; i < m; i++ { mat.SetVec(i, math.NaN()) } return asBasicVector(mat) case *SymDense, *basicSymmetric: if m != n { panic("bad size") } mat := &SymDense{} if n != 0 { mat = NewSymDense(n, nil) } for i := 0; i < m; i++ { for j := i; j < n; j++ { mat.SetSym(i, j, math.NaN()) } } rMatrix = returnAs(mat, t) case *TriDense, *basicTriangular: if m != n { panic("bad size") } // This is necessary because we are making // a triangle from the zero value, which // always returns upper as true. var triKind TriKind switch t := t.(type) { case *TriDense: triKind = t.triKind() case *basicTriangular: triKind = (*TriDense)(t).triKind() } if n == 0 { uplo := blas.Upper if triKind == Lower { uplo = blas.Lower } return returnAs(&TriDense{mat: blas64.Triangular{Uplo: uplo}}, t) } mat := NewTriDense(n, triKind, nil) if triKind == Upper { for i := 0; i < m; i++ { for j := i; j < n; j++ { mat.SetTri(i, j, math.NaN()) } } } else { for i := 0; i < m; i++ { for j := 0; j <= i; j++ { mat.SetTri(i, j, math.NaN()) } } } rMatrix = returnAs(mat, t) case *BandDense, *basicBanded: var kl, ku int switch t := t.(type) { case *BandDense: kl = t.mat.KL ku = t.mat.KU case *basicBanded: ku = (*BandDense)(t).mat.KU kl = (*BandDense)(t).mat.KL } ku = min(ku, n-1) kl = min(kl, m-1) data := make([]float64, min(m, n+kl)*(kl+ku+1)) for i := range data { data[i] = math.NaN() } mat := NewBandDense(m, n, kl, ku, data) rMatrix = returnAs(mat, t) case *SymBandDense, *basicSymBanded: if m != n { panic("bad size") } var k int switch t := t.(type) { case *SymBandDense: k = t.mat.K case *basicSymBanded: k = (*SymBandDense)(t).mat.K } k = min(k, m-1) // Special case for small sizes. data := make([]float64, m*(k+1)) for i := range data { data[i] = math.NaN() } mat := NewSymBandDense(n, k, data) rMatrix = returnAs(mat, t) case *TriBandDense, *basicTriBanded: if m != n { panic("bad size") } var k int var triKind TriKind switch t := t.(type) { case *TriBandDense: k = t.mat.K triKind = t.triKind() case *basicTriBanded: k = (*TriBandDense)(t).mat.K triKind = (*TriBandDense)(t).triKind() } k = min(k, m-1) // Special case for small sizes. data := make([]float64, m*(k+1)) for i := range data { data[i] = math.NaN() } mat := NewTriBandDense(n, k, triKind, data) rMatrix = returnAs(mat, t) case *DiagDense, *basicDiagonal: if m != n { panic("bad size") } var inc int switch t := t.(type) { case *DiagDense: inc = t.mat.Inc case *basicDiagonal: inc = (*DiagDense)(t).mat.Inc } if inc == 0 { inc = 1 } mat := &DiagDense{ mat: blas64.Vector{ N: n, Inc: inc, Data: make([]float64, inc*(n-1)+1), }, } for i := 0; i < n; i++ { mat.SetDiag(i, math.NaN()) } rMatrix = returnAs(mat, t) } if mr, mc := rMatrix.Dims(); mr != m || mc != n { panic(fmt.Sprintf("makeNaNOf for %T returns wrong size: %d×%d != %d×%d", a, m, n, mr, mc)) } return rMatrix } // makeCopyOf returns a copy of the matrix. func makeCopyOf(a Matrix) Matrix { switch t := a.(type) { default: panic("unknown type in makeCopyOf") case Untransposer: return retranspose(a, makeCopyOf(t.Untranspose())) case *Dense, *basicMatrix: var m Dense m.CloneFrom(a) return returnAs(&m, t) case *SymDense, *basicSymmetric: n := t.(Symmetric).SymmetricDim() m := NewSymDense(n, nil) m.CopySym(t.(Symmetric)) return returnAs(m, t) case *TriDense, *basicTriangular: n, upper := t.(Triangular).Triangle() m := NewTriDense(n, upper, nil) if upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { m.SetTri(i, j, t.At(i, j)) } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { m.SetTri(i, j, t.At(i, j)) } } } return returnAs(m, t) case *BandDense, *basicBanded: var band *BandDense switch s := t.(type) { case *BandDense: band = s case *basicBanded: band = (*BandDense)(s) } m := &BandDense{ mat: blas64.Band{ Rows: band.mat.Rows, Cols: band.mat.Cols, KL: band.mat.KL, KU: band.mat.KU, Data: make([]float64, len(band.mat.Data)), Stride: band.mat.Stride, }, } copy(m.mat.Data, band.mat.Data) return returnAs(m, t) case *SymBandDense, *basicSymBanded: var sym *SymBandDense switch s := t.(type) { case *SymBandDense: sym = s case *basicSymBanded: sym = (*SymBandDense)(s) } m := &SymBandDense{ mat: blas64.SymmetricBand{ Uplo: blas.Upper, N: sym.mat.N, K: sym.mat.K, Data: make([]float64, len(sym.mat.Data)), Stride: sym.mat.Stride, }, } copy(m.mat.Data, sym.mat.Data) return returnAs(m, t) case *TriBandDense, *basicTriBanded: var tri *TriBandDense switch s := t.(type) { case *TriBandDense: tri = s case *basicTriBanded: tri = (*TriBandDense)(s) } m := &TriBandDense{ mat: blas64.TriangularBand{ Uplo: tri.mat.Uplo, Diag: tri.mat.Diag, N: tri.mat.N, K: tri.mat.K, Data: make([]float64, len(tri.mat.Data)), Stride: tri.mat.Stride, }, } copy(m.mat.Data, tri.mat.Data) return returnAs(m, t) case *VecDense: var m VecDense m.CloneFromVec(t) return &m case *basicVector: var m VecDense m.CloneFromVec(t) return asBasicVector(&m) case *DiagDense, *basicDiagonal: var diag *DiagDense switch s := t.(type) { case *DiagDense: diag = s case *basicDiagonal: diag = (*DiagDense)(s) } d := &DiagDense{ mat: blas64.Vector{N: diag.mat.N, Inc: diag.mat.Inc, Data: make([]float64, len(diag.mat.Data))}, } copy(d.mat.Data, diag.mat.Data) return returnAs(d, t) case *Tridiag: var m Tridiag m.CloneFromTridiag(a.(*Tridiag)) return returnAs(&m, t) } } // sameType returns true if a and b have the same underlying type. func sameType(a, b Matrix) bool { return reflect.ValueOf(a).Type() == reflect.ValueOf(b).Type() } // maybeSame returns true if the two matrices could be represented by the same // pointer. func maybeSame(receiver, a Matrix) bool { rr, rc := receiver.Dims() u, trans := a.(Untransposer) if trans { a = u.Untranspose() } if !sameType(receiver, a) { return false } ar, ac := a.Dims() if rr != ar || rc != ac { return false } if _, ok := a.(Triangular); ok { // They are both triangular types. The TriType needs to match _, aKind := a.(Triangular).Triangle() _, rKind := receiver.(Triangular).Triangle() if aKind != rKind { return false } } return true } // equalApprox returns whether the elements of a and b are the same to within // the tolerance. If ignoreNaN is true the test is relaxed such that NaN == NaN. func equalApprox(a, b Matrix, tol float64, ignoreNaN bool) bool { ar, ac := a.Dims() br, bc := b.Dims() if ar != br { return false } if ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if !scalar.EqualWithinAbsOrRel(a.At(i, j), b.At(i, j), tol, tol) { if ignoreNaN && math.IsNaN(a.At(i, j)) && math.IsNaN(b.At(i, j)) { continue } return false } } } return true } // equal returns true if the matrices have equal entries. func equal(a, b Matrix) bool { ar, ac := a.Dims() br, bc := b.Dims() if ar != br { return false } if ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.At(i, j) != b.At(i, j) { return false } } } return true } // isDiagonal returns whether a is a diagonal matrix. func isDiagonal(a Matrix) bool { r, c := a.Dims() for i := 0; i < r; i++ { for j := 0; j < c; j++ { if a.At(i, j) != 0 && i != j { return false } } } return true } // equalDiagonal returns whether a and b are equal on the diagonal. func equalDiagonal(a, b Matrix) bool { ar, ac := a.Dims() br, bc := a.Dims() if min(ar, ac) != min(br, bc) { return false } for i := 0; i < min(ar, ac); i++ { if a.At(i, i) != b.At(i, i) { return false } } return true } // underlyingData extracts the underlying data of the matrix a. func underlyingData(a Matrix) []float64 { switch t := a.(type) { default: panic("matrix type not implemented for extracting underlying data") case Untransposer: return underlyingData(t.Untranspose()) case *Dense: return t.mat.Data case *SymDense: return t.mat.Data case *TriDense: return t.mat.Data case *VecDense: return t.mat.Data } } // testMatrices is a list of matrix types to test. // This test relies on the fact that the implementations of Triangle do not // corrupt the value of Uplo when they are empty. This test will fail // if that changes (and some mechanism will need to be used to force the // correct TriKind to be read). var testMatrices = []Matrix{ &Dense{}, &basicMatrix{}, Transpose{&Dense{}}, &VecDense{mat: blas64.Vector{Inc: 1}}, &VecDense{mat: blas64.Vector{Inc: 10}}, &basicVector{}, Transpose{&VecDense{mat: blas64.Vector{Inc: 1}}}, Transpose{&VecDense{mat: blas64.Vector{Inc: 10}}}, Transpose{&basicVector{}}, &BandDense{mat: blas64.Band{KL: 2, KU: 1}}, &BandDense{mat: blas64.Band{KL: 1, KU: 2}}, Transpose{&BandDense{mat: blas64.Band{KL: 2, KU: 1}}}, Transpose{&BandDense{mat: blas64.Band{KL: 1, KU: 2}}}, TransposeBand{&BandDense{mat: blas64.Band{KL: 2, KU: 1}}}, TransposeBand{&BandDense{mat: blas64.Band{KL: 1, KU: 2}}}, &SymDense{}, &basicSymmetric{}, Transpose{&basicSymmetric{}}, &TriDense{mat: blas64.Triangular{Uplo: blas.Upper}}, &TriDense{mat: blas64.Triangular{Uplo: blas.Lower}}, &basicTriangular{mat: blas64.Triangular{Uplo: blas.Upper}}, &basicTriangular{mat: blas64.Triangular{Uplo: blas.Lower}}, Transpose{&TriDense{mat: blas64.Triangular{Uplo: blas.Upper}}}, Transpose{&TriDense{mat: blas64.Triangular{Uplo: blas.Lower}}}, TransposeTri{&TriDense{mat: blas64.Triangular{Uplo: blas.Upper}}}, TransposeTri{&TriDense{mat: blas64.Triangular{Uplo: blas.Lower}}}, Transpose{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Upper}}}, Transpose{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Lower}}}, TransposeTri{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Upper}}}, TransposeTri{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Lower}}}, &SymBandDense{}, &basicSymBanded{}, Transpose{&basicSymBanded{}}, &SymBandDense{mat: blas64.SymmetricBand{K: 2}}, &basicSymBanded{mat: blas64.SymmetricBand{K: 2}}, Transpose{&basicSymBanded{mat: blas64.SymmetricBand{K: 2}}}, TransposeBand{&basicSymBanded{mat: blas64.SymmetricBand{K: 2}}}, &TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}, &TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}, &basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}, &basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}, Transpose{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, Transpose{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, Transpose{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, Transpose{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, TransposeTri{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, TransposeTri{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, TransposeTri{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, TransposeTri{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, TransposeBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, TransposeBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, TransposeBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, TransposeBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, TransposeTriBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, TransposeTriBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, TransposeTriBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}}, TransposeTriBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}}, &DiagDense{}, &DiagDense{mat: blas64.Vector{Inc: 10}}, Transpose{&DiagDense{}}, Transpose{&DiagDense{mat: blas64.Vector{Inc: 10}}}, TransposeTri{&DiagDense{}}, TransposeTri{&DiagDense{mat: blas64.Vector{Inc: 10}}}, TransposeBand{&DiagDense{}}, TransposeBand{&DiagDense{mat: blas64.Vector{Inc: 10}}}, TransposeTriBand{&DiagDense{}}, TransposeTriBand{&DiagDense{mat: blas64.Vector{Inc: 10}}}, &basicDiagonal{}, Transpose{&basicDiagonal{}}, TransposeTri{&basicDiagonal{}}, TransposeBand{&basicDiagonal{}}, TransposeTriBand{&basicDiagonal{}}, &Tridiag{}, Transpose{&Tridiag{}}, TransposeBand{&Tridiag{}}, } var sizes = []struct { ar, ac int }{ {1, 1}, {1, 3}, {3, 1}, {6, 6}, {6, 11}, {11, 6}, } func testOneInputFunc(t *testing.T, // name is the name of the function being tested. name string, // f is the function being tested. f func(a Matrix) interface{}, // denseComparison performs the same operation, but using Dense matrices for // comparison. denseComparison func(a *Dense) interface{}, // sameAnswer compares the result from two different evaluations of the function // and returns true if they are the same. The specific function being tested // determines the definition of "same". It may mean identical or it may mean // approximately equal. sameAnswer func(a, b interface{}) bool, // legalType returns true if the type of the input is a legal type for the // input of the function. legalType func(a Matrix) bool, // legalSize returns true if the size is valid for the function. legalSize func(r, c int) bool, ) { src := rand.NewSource(1) for _, aMat := range testMatrices { for _, test := range sizes { // Skip the test if the argument would not be assignable to the // method's corresponding input parameter or it is not possible // to construct an argument of the requested size. if !legalType(aMat) { continue } if !legalDims(aMat, test.ar, test.ac) { continue } a := makeRandOf(aMat, test.ar, test.ac, src) // Compute the true answer if the sizes are legal. dimsOK := legalSize(test.ar, test.ac) var want interface{} if dimsOK { var aDense Dense aDense.CloneFrom(a) want = denseComparison(&aDense) } aCopy := makeCopyOf(a) // Test the method for a zero-value of the receiver. aType, aTrans := untranspose(a) errStr := fmt.Sprintf("%v(%T), size: %#v, atrans %t", name, aType, test, aTrans) var got interface{} panicked, err := panics(func() { got = f(a) }) if !dimsOK && !panicked { t.Errorf("Did not panic with illegal size: %s", errStr) continue } if dimsOK && panicked { t.Errorf("Panicked with legal size: %s: %v", errStr, err) continue } if !equal(a, aCopy) { t.Errorf("First input argument changed in call: %s", errStr) } if !dimsOK { continue } if !sameAnswer(want, got) { t.Errorf("Answer mismatch: %s; got %v, want %v", errStr, got, want) } } } } var sizePairs = []struct { ar, ac, br, bc int }{ {1, 1, 1, 1}, {6, 6, 6, 6}, {7, 7, 7, 7}, {1, 1, 1, 5}, {1, 1, 5, 1}, {1, 5, 1, 1}, {5, 1, 1, 1}, {5, 5, 5, 1}, {5, 5, 1, 5}, {5, 1, 5, 5}, {1, 5, 5, 5}, {6, 6, 6, 11}, {6, 6, 11, 6}, {6, 11, 6, 6}, {11, 6, 6, 6}, {11, 11, 11, 6}, {11, 11, 6, 11}, {11, 6, 11, 11}, {6, 11, 11, 11}, {1, 1, 5, 5}, {1, 5, 1, 5}, {1, 5, 5, 1}, {5, 1, 1, 5}, {5, 1, 5, 1}, {5, 5, 1, 1}, {6, 6, 11, 11}, {6, 11, 6, 11}, {6, 11, 11, 6}, {11, 6, 6, 11}, {11, 6, 11, 6}, {11, 11, 6, 6}, {1, 1, 17, 11}, {1, 1, 11, 17}, {1, 11, 1, 17}, {1, 17, 1, 11}, {1, 11, 17, 1}, {1, 17, 11, 1}, {11, 1, 1, 17}, {17, 1, 1, 11}, {11, 1, 17, 1}, {17, 1, 11, 1}, {11, 17, 1, 1}, {17, 11, 1, 1}, {6, 6, 1, 11}, {6, 6, 11, 1}, {6, 11, 6, 1}, {6, 1, 6, 11}, {6, 11, 1, 6}, {6, 1, 11, 6}, {11, 6, 6, 1}, {1, 6, 6, 11}, {11, 6, 1, 6}, {1, 6, 11, 6}, {11, 1, 6, 6}, {1, 11, 6, 6}, {6, 6, 17, 1}, {6, 6, 1, 17}, {6, 1, 6, 17}, {6, 17, 6, 1}, {6, 1, 17, 6}, {6, 17, 1, 6}, {1, 6, 6, 17}, {17, 6, 6, 1}, {1, 6, 17, 6}, {17, 6, 1, 6}, {1, 17, 6, 6}, {17, 1, 6, 6}, {6, 6, 17, 11}, {6, 6, 11, 17}, {6, 11, 6, 17}, {6, 17, 6, 11}, {6, 11, 17, 6}, {6, 17, 11, 6}, {11, 6, 6, 17}, {17, 6, 6, 11}, {11, 6, 17, 6}, {17, 6, 11, 6}, {11, 17, 6, 6}, {17, 11, 6, 6}, } func testTwoInputFunc(t *testing.T, // name is the name of the function being tested. name string, // f is the function being tested. f func(a, b Matrix) interface{}, // denseComparison performs the same operation, but using Dense matrices for // comparison. denseComparison func(a, b *Dense) interface{}, // sameAnswer compares the result from two different evaluations of the function // and returns true if they are the same. The specific function being tested // determines the definition of "same". It may mean identical or it may mean // approximately equal. sameAnswer func(a, b interface{}) bool, // legalType returns true if the types of the inputs are legal for the // input of the function. legalType func(a, b Matrix) bool, // legalSize returns true if the sizes are valid for the function. legalSize func(ar, ac, br, bc int) bool, ) { src := rand.NewSource(1) for _, aMat := range testMatrices { for _, bMat := range testMatrices { // Loop over all of the size combinations (bigger, smaller, etc.). for _, test := range sizePairs { // Skip the test if the argument would not be assignable to the // method's corresponding input parameter or it is not possible // to construct an argument of the requested size. if !legalType(aMat, bMat) { continue } if !legalDims(aMat, test.ar, test.ac) { continue } if !legalDims(bMat, test.br, test.bc) { continue } a := makeRandOf(aMat, test.ar, test.ac, src) b := makeRandOf(bMat, test.br, test.bc, src) // Compute the true answer if the sizes are legal. dimsOK := legalSize(test.ar, test.ac, test.br, test.bc) var want interface{} if dimsOK { var aDense, bDense Dense aDense.CloneFrom(a) bDense.CloneFrom(b) want = denseComparison(&aDense, &bDense) } aCopy := makeCopyOf(a) bCopy := makeCopyOf(b) // Test the method for a zero-value of the receiver. aType, aTrans := untranspose(a) bType, bTrans := untranspose(b) errStr := fmt.Sprintf("%v(%T, %T), size: %#v, atrans %t, btrans %t", name, aType, bType, test, aTrans, bTrans) var got interface{} panicked, err := panics(func() { got = f(a, b) }) if !dimsOK && !panicked { t.Errorf("Did not panic with illegal size: %s", errStr) continue } if dimsOK && panicked { t.Errorf("Panicked with legal size: %s: %v", errStr, err) continue } if !equal(a, aCopy) { t.Errorf("First input argument changed in call: %s", errStr) } if !equal(b, bCopy) { t.Errorf("First input argument changed in call: %s", errStr) } if !dimsOK { continue } if !sameAnswer(want, got) { t.Errorf("Answer mismatch: %s", errStr) } } } } } // testOneInput tests a method that has one matrix input argument func testOneInput(t *testing.T, // name is the name of the method being tested. name string, // receiver is a value of the receiver type. receiver Matrix, // method is the generalized receiver.Method(a). method func(receiver, a Matrix), // denseComparison performs the same operation as method, but with dense // matrices for comparison with the result. denseComparison func(receiver, a *Dense), // legalTypes returns whether the concrete types in Matrix are valid for // the method. legalType func(a Matrix) bool, // legalSize returns whether the matrix sizes are valid for the method. legalSize func(ar, ac int) bool, // tol is the tolerance for equality when comparing method results. tol float64, ) { src := rand.NewSource(1) for _, aMat := range testMatrices { for _, test := range sizes { // Skip the test if the argument would not be assignable to the // method's corresponding input parameter or it is not possible // to construct an argument of the requested size. if !legalType(aMat) { continue } if !legalDims(aMat, test.ar, test.ac) { continue } a := makeRandOf(aMat, test.ar, test.ac, src) // Compute the true answer if the sizes are legal. dimsOK := legalSize(test.ar, test.ac) var want Dense if dimsOK { var aDense Dense aDense.CloneFrom(a) denseComparison(&want, &aDense) } aCopy := makeCopyOf(a) // Test the method for a zero-value of the receiver. aType, aTrans := untranspose(a) errStr := fmt.Sprintf("%T.%s(%T), size: %#v, atrans %v", receiver, name, aType, test, aTrans) empty := makeRandOf(receiver, 0, 0, src) panicked, err := panics(func() { method(empty, a) }) if !dimsOK && !panicked { t.Errorf("Did not panic with illegal size: %s", errStr) continue } if dimsOK && panicked { t.Errorf("Panicked with legal size: %s: %v", errStr, err) continue } if !equal(a, aCopy) { t.Errorf("First input argument changed in call: %s", errStr) } if !dimsOK { continue } if !equalApprox(empty, &want, tol, false) { t.Errorf("Answer mismatch with empty receiver: %s.\nGot:\n% v\nWant:\n% v\n", errStr, Formatted(empty), Formatted(&want)) continue } // Test the method with a non-empty-value of the receiver. // The receiver has been overwritten in place so use its size // to construct a new random matrix. rr, rc := empty.Dims() neverEmpty := makeRandOf(receiver, rr, rc, src) panicked, message := panics(func() { method(neverEmpty, a) }) if panicked { t.Errorf("Panicked with non-empty receiver: %s: %s", errStr, message) } if !equalApprox(neverEmpty, &want, tol, false) { t.Errorf("Answer mismatch non-empty receiver: %s", errStr) } // Test the method with a NaN-filled-value of the receiver. // The receiver has been overwritten in place so use its size // to construct a new NaN matrix. nanMatrix := makeNaNOf(receiver, rr, rc) panicked, message = panics(func() { method(nanMatrix, a) }) if panicked { t.Errorf("Panicked with NaN-filled receiver: %s: %s", errStr, message) } if !equalApprox(nanMatrix, &want, tol, false) { t.Errorf("Answer mismatch NaN-filled receiver: %s", errStr) } // Test with an incorrectly sized matrix. switch receiver.(type) { default: panic("matrix type not coded for incorrect receiver size") case *Dense: wrongSize := makeRandOf(receiver, rr+1, rc, src) panicked, _ = panics(func() { method(wrongSize, a) }) if !panicked { t.Errorf("Did not panic with wrong number of rows: %s", errStr) } wrongSize = makeRandOf(receiver, rr, rc+1, src) panicked, _ = panics(func() { method(wrongSize, a) }) if !panicked { t.Errorf("Did not panic with wrong number of columns: %s", errStr) } case *TriDense, *SymDense: // Add to the square size. wrongSize := makeRandOf(receiver, rr+1, rc+1, src) panicked, _ = panics(func() { method(wrongSize, a) }) if !panicked { t.Errorf("Did not panic with wrong size: %s", errStr) } case *VecDense: // Add to the column length. wrongSize := makeRandOf(receiver, rr+1, rc, src) panicked, _ = panics(func() { method(wrongSize, a) }) if !panicked { t.Errorf("Did not panic with wrong number of rows: %s", errStr) } } // The receiver and the input may share a matrix pointer // if the type and size of the receiver and one of the // arguments match. Test the method works properly // when this is the case. aMaybeSame := maybeSame(neverEmpty, a) if aMaybeSame { aSame := makeCopyOf(a) receiver = aSame u, ok := aSame.(Untransposer) if ok { receiver = u.Untranspose() } preData := underlyingData(receiver) panicked, err = panics(func() { method(receiver, aSame) }) if panicked { t.Errorf("Panics when a maybeSame: %s: %v", errStr, err) } else { if !equalApprox(receiver, &want, tol, false) { t.Errorf("Wrong answer when a maybeSame: %s", errStr) } postData := underlyingData(receiver) if !floats.Equal(preData, postData) { t.Errorf("Original data slice not modified when a maybeSame: %s", errStr) } } } } } } // testTwoInput tests a method that has two input arguments. func testTwoInput(t *testing.T, // name is the name of the method being tested. name string, // receiver is a value of the receiver type. receiver Matrix, // method is the generalized receiver.Method(a, b). method func(receiver, a, b Matrix), // denseComparison performs the same operation as method, but with dense // matrices for comparison with the result. denseComparison func(receiver, a, b *Dense), // legalTypes returns whether the concrete types in Matrix are valid for // the method. legalTypes func(a, b Matrix) bool, // legalSize returns whether the matrix sizes are valid for the method. legalSize func(ar, ac, br, bc int) bool, // tol is the tolerance for equality when comparing method results. tol float64, ) { src := rand.NewSource(1) for _, aMat := range testMatrices { for _, bMat := range testMatrices { // Loop over all of the size combinations (bigger, smaller, etc.). for _, test := range sizePairs { // Skip the test if any argument would not be assignable to the // method's corresponding input parameter or it is not possible // to construct an argument of the requested size. if !legalTypes(aMat, bMat) { continue } if !legalDims(aMat, test.ar, test.ac) { continue } if !legalDims(bMat, test.br, test.bc) { continue } a := makeRandOf(aMat, test.ar, test.ac, src) b := makeRandOf(bMat, test.br, test.bc, src) // Compute the true answer if the sizes are legal. dimsOK := legalSize(test.ar, test.ac, test.br, test.bc) var want Dense if dimsOK { var aDense, bDense Dense aDense.CloneFrom(a) bDense.CloneFrom(b) denseComparison(&want, &aDense, &bDense) } aCopy := makeCopyOf(a) bCopy := makeCopyOf(b) // Test the method for a empty-value of the receiver. aType, aTrans := untranspose(a) bType, bTrans := untranspose(b) errStr := fmt.Sprintf("%T.%s(%T, %T), sizes: %#v, atrans %v, btrans %v", receiver, name, aType, bType, test, aTrans, bTrans) empty := makeRandOf(receiver, 0, 0, src) panicked, err := panics(func() { method(empty, a, b) }) if !dimsOK && !panicked { t.Errorf("Did not panic with illegal size: %s", errStr) continue } if dimsOK && panicked { t.Errorf("Panicked with legal size: %s: %v", errStr, err) continue } if !equal(a, aCopy) { t.Errorf("First input argument changed in call: %s", errStr) } if !equal(b, bCopy) { t.Errorf("Second input argument changed in call: %s", errStr) } if !dimsOK { continue } wasEmpty, empty := empty, nil // Nil-out empty so we detect illegal use. // NaN equality is allowed because of 0/0 in DivElem test. if !equalApprox(wasEmpty, &want, tol, true) { t.Errorf("Answer mismatch with empty receiver: %s", errStr) continue } // Test the method with a non-empty-value of the receiver. // The receiver has been overwritten in place so use its size // to construct a new random matrix. rr, rc := wasEmpty.Dims() neverEmpty := makeRandOf(receiver, rr, rc, src) panicked, message := panics(func() { method(neverEmpty, a, b) }) if panicked { t.Errorf("Panicked with non-empty receiver: %s: %s", errStr, message) } // NaN equality is allowed because of 0/0 in DivElem test. if !equalApprox(neverEmpty, &want, tol, true) { t.Errorf("Answer mismatch non-empty receiver: %s", errStr) } // Test the method with a NaN-filled value of the receiver. // The receiver has been overwritten in place so use its size // to construct a new NaN matrix. nanMatrix := makeNaNOf(receiver, rr, rc) panicked, message = panics(func() { method(nanMatrix, a, b) }) if panicked { t.Errorf("Panicked with NaN-filled receiver: %s: %s", errStr, message) } // NaN equality is allowed because of 0/0 in DivElem test. if !equalApprox(nanMatrix, &want, tol, true) { t.Errorf("Answer mismatch NaN-filled receiver: %s", errStr) } // Test with an incorrectly sized matrix. switch receiver.(type) { default: panic("matrix type not coded for incorrect receiver size") case *Dense: wrongSize := makeRandOf(receiver, rr+1, rc, src) panicked, _ = panics(func() { method(wrongSize, a, b) }) if !panicked { t.Errorf("Did not panic with wrong number of rows: %s", errStr) } wrongSize = makeRandOf(receiver, rr, rc+1, src) panicked, _ = panics(func() { method(wrongSize, a, b) }) if !panicked { t.Errorf("Did not panic with wrong number of columns: %s", errStr) } case *TriDense, *SymDense: // Add to the square size. wrongSize := makeRandOf(receiver, rr+1, rc+1, src) panicked, _ = panics(func() { method(wrongSize, a, b) }) if !panicked { t.Errorf("Did not panic with wrong size: %s", errStr) } case *VecDense: // Add to the column length. wrongSize := makeRandOf(receiver, rr+1, rc, src) panicked, _ = panics(func() { method(wrongSize, a, b) }) if !panicked { t.Errorf("Did not panic with wrong number of rows: %s", errStr) } } // The receiver and an input may share a matrix pointer // if the type and size of the receiver and one of the // arguments match. Test the method works properly // when this is the case. aMaybeSame := maybeSame(neverEmpty, a) bMaybeSame := maybeSame(neverEmpty, b) if aMaybeSame { aSame := makeCopyOf(a) receiver = aSame u, ok := aSame.(Untransposer) if ok { receiver = u.Untranspose() } preData := underlyingData(receiver) panicked, err = panics(func() { method(receiver, aSame, b) }) if panicked { t.Errorf("Panics when a maybeSame: %s: %v", errStr, err) } else { if !equalApprox(receiver, &want, tol, false) { t.Errorf("Wrong answer when a maybeSame: %s", errStr) } postData := underlyingData(receiver) if !floats.Equal(preData, postData) { t.Errorf("Original data slice not modified when a maybeSame: %s", errStr) } } } if bMaybeSame { bSame := makeCopyOf(b) receiver = bSame u, ok := bSame.(Untransposer) if ok { receiver = u.Untranspose() } preData := underlyingData(receiver) panicked, err = panics(func() { method(receiver, a, bSame) }) if panicked { t.Errorf("Panics when b maybeSame: %s: %v", errStr, err) } else { if !equalApprox(receiver, &want, tol, false) { t.Errorf("Wrong answer when b maybeSame: %s", errStr) } postData := underlyingData(receiver) if !floats.Equal(preData, postData) { t.Errorf("Original data slice not modified when b maybeSame: %s", errStr) } } } if aMaybeSame && bMaybeSame { aSame := makeCopyOf(a) receiver = aSame u, ok := aSame.(Untransposer) if ok { receiver = u.Untranspose() } // Ensure that b is the correct transpose type if applicable. // The receiver is always a concrete type so use it. bSame := receiver _, ok = b.(Untransposer) if ok { bSame = retranspose(b, receiver) } // Compute the real answer for this case. It is different // from the initial answer since now a and b have the // same data. empty = makeRandOf(wasEmpty, 0, 0, src) method(empty, aSame, bSame) wasEmpty, empty = empty, nil // Nil-out empty so we detect illegal use. preData := underlyingData(receiver) panicked, err = panics(func() { method(receiver, aSame, bSame) }) if panicked { t.Errorf("Panics when both maybeSame: %s: %v", errStr, err) } else { if !equalApprox(receiver, wasEmpty, tol, false) { t.Errorf("Wrong answer when both maybeSame: %s", errStr) } postData := underlyingData(receiver) if !floats.Equal(preData, postData) { t.Errorf("Original data slice not modified when both maybeSame: %s", errStr) } } } } } } } golang-gonum-v1-gonum-0.14.0/mat/lq.go000066400000000000000000000166411450372207100173720ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) const badLQ = "mat: invalid LQ factorization" // LQ is a type for creating and using the LQ factorization of a matrix. type LQ struct { lq *Dense tau []float64 cond float64 } func (lq *LQ) updateCond(norm lapack.MatrixNorm) { // Since A = L*Q, and Q is orthogonal, we get for the condition number κ // κ(A) := |A| |A^-1| = |L*Q| |(L*Q)^-1| = |L| |Qᵀ * L^-1| // = |L| |L^-1| = κ(L), // where we used that fact that Q^-1 = Qᵀ. However, this assumes that // the matrix norm is invariant under orthogonal transformations which // is not the case for CondNorm. Hopefully the error is negligible: κ // is only a qualitative measure anyway. m := lq.lq.mat.Rows work := getFloat64s(3*m, false) iwork := getInts(m, false) l := lq.lq.asTriDense(m, blas.NonUnit, blas.Lower) v := lapack64.Trcon(norm, l.mat, work, iwork) lq.cond = 1 / v putFloat64s(work) putInts(iwork) } // Factorize computes the LQ factorization of an m×n matrix a where m <= n. The LQ // factorization always exists even if A is singular. // // The LQ decomposition is a factorization of the matrix A such that A = L * Q. // The matrix Q is an orthonormal n×n matrix, and L is an m×n lower triangular matrix. // L and Q can be extracted using the LTo and QTo methods. func (lq *LQ) Factorize(a Matrix) { lq.factorize(a, CondNorm) } func (lq *LQ) factorize(a Matrix, norm lapack.MatrixNorm) { m, n := a.Dims() if m > n { panic(ErrShape) } k := min(m, n) if lq.lq == nil { lq.lq = &Dense{} } lq.lq.CloneFrom(a) work := []float64{0} lq.tau = make([]float64, k) lapack64.Gelqf(lq.lq.mat, lq.tau, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Gelqf(lq.lq.mat, lq.tau, work, len(work)) putFloat64s(work) lq.updateCond(norm) } // isValid returns whether the receiver contains a factorization. func (lq *LQ) isValid() bool { return lq.lq != nil && !lq.lq.IsEmpty() } // Cond returns the condition number for the factorized matrix. // Cond will panic if the receiver does not contain a factorization. func (lq *LQ) Cond() float64 { if !lq.isValid() { panic(badLQ) } return lq.cond } // TODO(btracey): Add in the "Reduced" forms for extracting the m×m orthogonal // and upper triangular matrices. // LTo extracts the m×n lower trapezoidal matrix from a LQ decomposition. // // If dst is empty, LTo will resize dst to be r×c. When dst is // non-empty, LTo will panic if dst is not r×c. LTo will also panic // if the receiver does not contain a successful factorization. func (lq *LQ) LTo(dst *Dense) { if !lq.isValid() { panic(badLQ) } r, c := lq.lq.Dims() if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } // Disguise the LQ as a lower triangular. t := &TriDense{ mat: blas64.Triangular{ N: r, Stride: lq.lq.mat.Stride, Data: lq.lq.mat.Data, Uplo: blas.Lower, Diag: blas.NonUnit, }, cap: lq.lq.capCols, } dst.Copy(t) if r == c { return } // Zero right of the triangular. for i := 0; i < r; i++ { zero(dst.mat.Data[i*dst.mat.Stride+r : i*dst.mat.Stride+c]) } } // QTo extracts the n×n orthonormal matrix Q from an LQ decomposition. // // If dst is empty, QTo will resize dst to be c×c. When dst is // non-empty, QTo will panic if dst is not c×c. QTo will also panic // if the receiver does not contain a successful factorization. func (lq *LQ) QTo(dst *Dense) { if !lq.isValid() { panic(badLQ) } _, c := lq.lq.Dims() if dst.IsEmpty() { dst.ReuseAs(c, c) } else { r2, c2 := dst.Dims() if c != r2 || c != c2 { panic(ErrShape) } dst.Zero() } q := dst.mat // Set Q = I. ldq := q.Stride for i := 0; i < c; i++ { q.Data[i*ldq+i] = 1 } // Construct Q from the elementary reflectors. work := []float64{0} lapack64.Ormlq(blas.Left, blas.NoTrans, lq.lq.mat, lq.tau, q, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Ormlq(blas.Left, blas.NoTrans, lq.lq.mat, lq.tau, q, work, len(work)) putFloat64s(work) } // SolveTo finds a minimum-norm solution to a system of linear equations defined // by the matrices A and b, where A is an m×n matrix represented in its LQ factorized // form. If A is singular or near-singular a Condition error is returned. // See the documentation for Condition for more information. // // The minimization problem solved depends on the input parameters. // // If trans == false, find the minimum norm solution of A * X = B. // If trans == true, find X such that ||A*X - B||_2 is minimized. // // The solution matrix, X, is stored in place into dst. // SolveTo will panic if the receiver does not contain a factorization. func (lq *LQ) SolveTo(dst *Dense, trans bool, b Matrix) error { if !lq.isValid() { panic(badLQ) } r, c := lq.lq.Dims() br, bc := b.Dims() // The LQ solve algorithm stores the result in-place into the right hand side. // The storage for the answer must be large enough to hold both b and x. // However, this method's receiver must be the size of x. Copy b, and then // copy the result into x at the end. if trans { if c != br { panic(ErrShape) } dst.reuseAsNonZeroed(r, bc) } else { if r != br { panic(ErrShape) } dst.reuseAsNonZeroed(c, bc) } // Do not need to worry about overlap between x and b because w has its own // independent storage. w := getDenseWorkspace(max(r, c), bc, false) w.Copy(b) t := lq.lq.asTriDense(lq.lq.mat.Rows, blas.NonUnit, blas.Lower).mat if trans { work := []float64{0} lapack64.Ormlq(blas.Left, blas.NoTrans, lq.lq.mat, lq.tau, w.mat, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Ormlq(blas.Left, blas.NoTrans, lq.lq.mat, lq.tau, w.mat, work, len(work)) putFloat64s(work) ok := lapack64.Trtrs(blas.Trans, t, w.mat) if !ok { return Condition(math.Inf(1)) } } else { ok := lapack64.Trtrs(blas.NoTrans, t, w.mat) if !ok { return Condition(math.Inf(1)) } for i := r; i < c; i++ { zero(w.mat.Data[i*w.mat.Stride : i*w.mat.Stride+bc]) } work := []float64{0} lapack64.Ormlq(blas.Left, blas.Trans, lq.lq.mat, lq.tau, w.mat, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Ormlq(blas.Left, blas.Trans, lq.lq.mat, lq.tau, w.mat, work, len(work)) putFloat64s(work) } // x was set above to be the correct size for the result. dst.Copy(w) putDenseWorkspace(w) if lq.cond > ConditionTolerance { return Condition(lq.cond) } return nil } // SolveVecTo finds a minimum-norm solution to a system of linear equations. // See LQ.SolveTo for the full documentation. // SolveToVec will panic if the receiver does not contain a factorization. func (lq *LQ) SolveVecTo(dst *VecDense, trans bool, b Vector) error { if !lq.isValid() { panic(badLQ) } r, c := lq.lq.Dims() if _, bc := b.Dims(); bc != 1 { panic(ErrShape) } // The Solve implementation is non-trivial, so rather than duplicate the code, // instead recast the VecDenses as Dense and call the matrix code. bm := Matrix(b) if rv, ok := b.(RawVectorer); ok { bmat := rv.RawVector() if dst != b { dst.checkOverlap(bmat) } b := VecDense{mat: bmat} bm = b.asDense() } if trans { dst.reuseAsNonZeroed(r) } else { dst.reuseAsNonZeroed(c) } return lq.SolveTo(dst.asDense(), trans, bm) } golang-gonum-v1-gonum-0.14.0/mat/lq_test.go000066400000000000000000000076451450372207100204350ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "testing" "golang.org/x/exp/rand" ) func TestLQ(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n int }{ {5, 5}, {5, 10}, } { m := test.m n := test.n a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.NormFloat64()) } } var want Dense want.CloneFrom(a) var lq LQ lq.Factorize(a) var l, q Dense lq.QTo(&q) if !isOrthonormal(&q, 1e-10) { t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n) } lq.LTo(&l) var got Dense got.Mul(&l, &q) if !EqualApprox(&got, &want, 1e-12) { t.Errorf("LQ does not equal original matrix. \nWant: %v\nGot: %v", want, got) } } } func TestLQSolveTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, trans := range []bool{false, true} { for _, test := range []struct { m, n, bc int }{ {5, 5, 1}, {5, 10, 1}, {5, 5, 3}, {5, 10, 3}, } { m := test.m n := test.n bc := test.bc a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m if trans { br = n } b := NewDense(br, bc, nil) for i := 0; i < br; i++ { for j := 0; j < bc; j++ { b.Set(i, j, rnd.Float64()) } } var x Dense lq := &LQ{} lq.Factorize(a) err := lq.SolveTo(&x, trans, b) if err != nil { t.Errorf("unexpected error from LQ solve: %v", err) } // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b if !trans // A * Aᵀ * x = A * b if trans var lhs Dense var rhs Dense if trans { var tmp Dense tmp.Mul(a, a.T()) lhs.Mul(&tmp, &x) rhs.Mul(a, b) } else { var tmp Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) } if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } } // TODO(btracey): Add in testOneInput when it exists. } func TestLQSolveToVec(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, trans := range []bool{false, true} { for _, test := range []struct { m, n int }{ {5, 5}, {5, 10}, } { m := test.m n := test.n a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m if trans { br = n } b := NewVecDense(br, nil) for i := 0; i < br; i++ { b.SetVec(i, rnd.Float64()) } var x VecDense lq := &LQ{} lq.Factorize(a) err := lq.SolveVecTo(&x, trans, b) if err != nil { t.Errorf("unexpected error from LQ solve: %v", err) } // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b if !trans // A * Aᵀ * x = A * b if trans var lhs Dense var rhs Dense if trans { var tmp Dense tmp.Mul(a, a.T()) lhs.Mul(&tmp, &x) rhs.Mul(a, b) } else { var tmp Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) } if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } } // TODO(btracey): Add in testOneInput when it exists. } func TestLQSolveToCond(t *testing.T) { t.Parallel() for _, test := range []*Dense{ NewDense(2, 2, []float64{1, 0, 0, 1e-20}), NewDense(2, 3, []float64{1, 0, 0, 0, 1e-20, 0}), } { m, _ := test.Dims() var lq LQ lq.Factorize(test) b := NewDense(m, 2, nil) var x Dense if err := lq.SolveTo(&x, false, b); err == nil { t.Error("No error for near-singular matrix in matrix solve.") } bvec := NewVecDense(m, nil) var xvec VecDense if err := lq.SolveVecTo(&xvec, false, bvec); err == nil { t.Error("No error for near-singular matrix in matrix solve.") } } } golang-gonum-v1-gonum-0.14.0/mat/lu.go000066400000000000000000000272561450372207100174020ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) const ( badSliceLength = "mat: improper slice length" badLU = "mat: invalid LU factorization" ) // LU is a type for creating and using the LU factorization of a matrix. type LU struct { lu *Dense pivot []int cond float64 } // updateCond updates the stored condition number of the matrix. anorm is the // norm of the original matrix. If anorm is negative it will be estimated. func (lu *LU) updateCond(anorm float64, norm lapack.MatrixNorm) { n := lu.lu.mat.Cols work := getFloat64s(4*n, false) defer putFloat64s(work) iwork := getInts(n, false) defer putInts(iwork) if anorm < 0 { // This is an approximation. By the definition of a norm, // |AB| <= |A| |B|. // Since A = L*U, we get for the condition number κ that // κ(A) := |A| |A^-1| = |L*U| |A^-1| <= |L| |U| |A^-1|, // so this will overestimate the condition number somewhat. // The norm of the original factorized matrix cannot be stored // because of update possibilities. u := lu.lu.asTriDense(n, blas.NonUnit, blas.Upper) l := lu.lu.asTriDense(n, blas.Unit, blas.Lower) unorm := lapack64.Lantr(norm, u.mat, work) lnorm := lapack64.Lantr(norm, l.mat, work) anorm = unorm * lnorm } v := lapack64.Gecon(norm, lu.lu.mat, anorm, work, iwork) lu.cond = 1 / v } // Factorize computes the LU factorization of the square matrix a and stores the // result. The LU decomposition will complete regardless of the singularity of a. // // The LU factorization is computed with pivoting, and so really the decomposition // is a PLU decomposition where P is a permutation matrix. The individual matrix // factors can be extracted from the factorization using the Permutation method // on Dense, and the LU.LTo and LU.UTo methods. func (lu *LU) Factorize(a Matrix) { lu.factorize(a, CondNorm) } func (lu *LU) factorize(a Matrix, norm lapack.MatrixNorm) { r, c := a.Dims() if r != c { panic(ErrSquare) } if lu.lu == nil { lu.lu = NewDense(r, r, nil) } else { lu.lu.Reset() lu.lu.reuseAsNonZeroed(r, r) } lu.lu.Copy(a) if cap(lu.pivot) < r { lu.pivot = make([]int, r) } lu.pivot = lu.pivot[:r] work := getFloat64s(r, false) anorm := lapack64.Lange(norm, lu.lu.mat, work) putFloat64s(work) lapack64.Getrf(lu.lu.mat, lu.pivot) lu.updateCond(anorm, norm) } // isValid returns whether the receiver contains a factorization. func (lu *LU) isValid() bool { return lu.lu != nil && !lu.lu.IsEmpty() } // Cond returns the condition number for the factorized matrix. // Cond will panic if the receiver does not contain a factorization. func (lu *LU) Cond() float64 { if !lu.isValid() { panic(badLU) } return lu.cond } // Reset resets the factorization so that it can be reused as the receiver of a // dimensionally restricted operation. func (lu *LU) Reset() { if lu.lu != nil { lu.lu.Reset() } lu.pivot = lu.pivot[:0] } func (lu *LU) isZero() bool { return len(lu.pivot) == 0 } // Det returns the determinant of the matrix that has been factorized. In many // expressions, using LogDet will be more numerically stable. // Det will panic if the receiver does not contain a factorization. func (lu *LU) Det() float64 { det, sign := lu.LogDet() return math.Exp(det) * sign } // LogDet returns the log of the determinant and the sign of the determinant // for the matrix that has been factorized. Numerical stability in product and // division expressions is generally improved by working in log space. // LogDet will panic if the receiver does not contain a factorization. func (lu *LU) LogDet() (det float64, sign float64) { if !lu.isValid() { panic(badLU) } _, n := lu.lu.Dims() logDiag := getFloat64s(n, false) defer putFloat64s(logDiag) sign = 1.0 for i := 0; i < n; i++ { v := lu.lu.at(i, i) if v < 0 { sign *= -1 } if lu.pivot[i] != i { sign *= -1 } logDiag[i] = math.Log(math.Abs(v)) } return floats.Sum(logDiag), sign } // Pivot returns pivot indices that enable the construction of the permutation // matrix P (see Dense.Permutation). If swaps == nil, then new memory will be // allocated, otherwise the length of the input must be equal to the size of the // factorized matrix. // Pivot will panic if the receiver does not contain a factorization. func (lu *LU) Pivot(swaps []int) []int { if !lu.isValid() { panic(badLU) } _, n := lu.lu.Dims() if swaps == nil { swaps = make([]int, n) } if len(swaps) != n { panic(badSliceLength) } // Perform the inverse of the row swaps in order to find the final // row swap position. for i := range swaps { swaps[i] = i } for i := n - 1; i >= 0; i-- { v := lu.pivot[i] swaps[i], swaps[v] = swaps[v], swaps[i] } return swaps } // RankOne updates an LU factorization as if a rank-one update had been applied to // the original matrix A, storing the result into the receiver. That is, if in // the original LU decomposition P * L * U = A, in the updated decomposition // P * L * U = A + alpha * x * yᵀ. // RankOne will panic if orig does not contain a factorization. func (lu *LU) RankOne(orig *LU, alpha float64, x, y Vector) { if !orig.isValid() { panic(badLU) } // RankOne uses algorithm a1 on page 28 of "Multiple-Rank Updates to Matrix // Factorizations for Nonlinear Analysis and Circuit Design" by Linzhong Deng. // http://web.stanford.edu/group/SOL/dissertations/Linzhong-Deng-thesis.pdf _, n := orig.lu.Dims() if r, c := x.Dims(); r != n || c != 1 { panic(ErrShape) } if r, c := y.Dims(); r != n || c != 1 { panic(ErrShape) } if orig != lu { if lu.isZero() { if cap(lu.pivot) < n { lu.pivot = make([]int, n) } lu.pivot = lu.pivot[:n] if lu.lu == nil { lu.lu = NewDense(n, n, nil) } else { lu.lu.reuseAsNonZeroed(n, n) } } else if len(lu.pivot) != n { panic(ErrShape) } copy(lu.pivot, orig.pivot) lu.lu.Copy(orig.lu) } xs := getFloat64s(n, false) defer putFloat64s(xs) ys := getFloat64s(n, false) defer putFloat64s(ys) for i := 0; i < n; i++ { xs[i] = x.AtVec(i) ys[i] = y.AtVec(i) } // Adjust for the pivoting in the LU factorization for i, v := range lu.pivot { xs[i], xs[v] = xs[v], xs[i] } lum := lu.lu.mat omega := alpha for j := 0; j < n; j++ { ujj := lum.Data[j*lum.Stride+j] ys[j] /= ujj theta := 1 + xs[j]*ys[j]*omega beta := omega * ys[j] / theta gamma := omega * xs[j] omega -= beta * gamma lum.Data[j*lum.Stride+j] *= theta for i := j + 1; i < n; i++ { xs[i] -= lum.Data[i*lum.Stride+j] * xs[j] tmp := ys[i] ys[i] -= lum.Data[j*lum.Stride+i] * ys[j] lum.Data[i*lum.Stride+j] += beta * xs[i] lum.Data[j*lum.Stride+i] += gamma * tmp } } lu.updateCond(-1, CondNorm) } // LTo extracts the lower triangular matrix from an LU factorization. // // If dst is empty, LTo will resize dst to be a lower-triangular n×n matrix. // When dst is non-empty, LTo will panic if dst is not n×n or not Lower. // LTo will also panic if the receiver does not contain a successful // factorization. func (lu *LU) LTo(dst *TriDense) *TriDense { if !lu.isValid() { panic(badLU) } _, n := lu.lu.Dims() if dst.IsEmpty() { dst.ReuseAsTri(n, Lower) } else { n2, kind := dst.Triangle() if n != n2 { panic(ErrShape) } if kind != Lower { panic(ErrTriangle) } } // Extract the lower triangular elements. for i := 0; i < n; i++ { for j := 0; j < i; j++ { dst.mat.Data[i*dst.mat.Stride+j] = lu.lu.mat.Data[i*lu.lu.mat.Stride+j] } } // Set ones on the diagonal. for i := 0; i < n; i++ { dst.mat.Data[i*dst.mat.Stride+i] = 1 } return dst } // UTo extracts the upper triangular matrix from an LU factorization. // // If dst is empty, UTo will resize dst to be an upper-triangular n×n matrix. // When dst is non-empty, UTo will panic if dst is not n×n or not Upper. // UTo will also panic if the receiver does not contain a successful // factorization. func (lu *LU) UTo(dst *TriDense) { if !lu.isValid() { panic(badLU) } _, n := lu.lu.Dims() if dst.IsEmpty() { dst.ReuseAsTri(n, Upper) } else { n2, kind := dst.Triangle() if n != n2 { panic(ErrShape) } if kind != Upper { panic(ErrTriangle) } } // Extract the upper triangular elements. for i := 0; i < n; i++ { for j := i; j < n; j++ { dst.mat.Data[i*dst.mat.Stride+j] = lu.lu.mat.Data[i*lu.lu.mat.Stride+j] } } } // Permutation constructs an r×r permutation matrix with the given row swaps. // A permutation matrix has exactly one element equal to one in each row and column // and all other elements equal to zero. swaps[i] specifies the row with which // i will be swapped, which is equivalent to the non-zero column of row i. func (m *Dense) Permutation(r int, swaps []int) { m.reuseAsNonZeroed(r, r) for i := 0; i < r; i++ { zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+r]) v := swaps[i] if v < 0 || v >= r { panic(ErrRowAccess) } m.mat.Data[i*m.mat.Stride+v] = 1 } } // SolveTo solves a system of linear equations using the LU decomposition of a matrix. // It computes // // A * X = B if trans == false // Aᵀ * X = B if trans == true // // In both cases, A is represented in LU factorized form, and the matrix X is // stored into dst. // // If A is singular or near-singular a Condition error is returned. See // the documentation for Condition for more information. // SolveTo will panic if the receiver does not contain a factorization. func (lu *LU) SolveTo(dst *Dense, trans bool, b Matrix) error { if !lu.isValid() { panic(badLU) } _, n := lu.lu.Dims() br, bc := b.Dims() if br != n { panic(ErrShape) } // TODO(btracey): Should test the condition number instead of testing that // the determinant is exactly zero. if lu.Det() == 0 { return Condition(math.Inf(1)) } dst.reuseAsNonZeroed(n, bc) bU, _ := untranspose(b) var restore func() if dst == bU { dst, restore = dst.isolatedWorkspace(bU) defer restore() } else if rm, ok := bU.(RawMatrixer); ok { dst.checkOverlap(rm.RawMatrix()) } dst.Copy(b) t := blas.NoTrans if trans { t = blas.Trans } lapack64.Getrs(t, lu.lu.mat, dst.mat, lu.pivot) if lu.cond > ConditionTolerance { return Condition(lu.cond) } return nil } // SolveVecTo solves a system of linear equations using the LU decomposition of a matrix. // It computes // // A * x = b if trans == false // Aᵀ * x = b if trans == true // // In both cases, A is represented in LU factorized form, and the vector x is // stored into dst. // // If A is singular or near-singular a Condition error is returned. See // the documentation for Condition for more information. // SolveVecTo will panic if the receiver does not contain a factorization. func (lu *LU) SolveVecTo(dst *VecDense, trans bool, b Vector) error { if !lu.isValid() { panic(badLU) } _, n := lu.lu.Dims() if br, bc := b.Dims(); br != n || bc != 1 { panic(ErrShape) } switch rv := b.(type) { default: dst.reuseAsNonZeroed(n) return lu.SolveTo(dst.asDense(), trans, b) case RawVectorer: if dst != b { dst.checkOverlap(rv.RawVector()) } // TODO(btracey): Should test the condition number instead of testing that // the determinant is exactly zero. if lu.Det() == 0 { return Condition(math.Inf(1)) } dst.reuseAsNonZeroed(n) var restore func() if dst == b { dst, restore = dst.isolatedWorkspace(b) defer restore() } dst.CopyVec(b) vMat := blas64.General{ Rows: n, Cols: 1, Stride: dst.mat.Inc, Data: dst.mat.Data, } t := blas.NoTrans if trans { t = blas.Trans } lapack64.Getrs(t, lu.lu.mat, vMat, lu.pivot) if lu.cond > ConditionTolerance { return Condition(lu.cond) } return nil } } golang-gonum-v1-gonum-0.14.0/mat/lu_test.go000066400000000000000000000107301450372207100204260ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "testing" "golang.org/x/exp/rand" ) func TestLUD(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, n := range []int{1, 5, 10, 11, 50} { a := NewDense(n, n, nil) for i := 0; i < n; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.NormFloat64()) } } var want Dense want.CloneFrom(a) var lu LU lu.Factorize(a) var l, u TriDense lu.LTo(&l) lu.UTo(&u) var p Dense pivot := lu.Pivot(nil) p.Permutation(n, pivot) var got Dense got.Product(&p, &l, &u) if !EqualApprox(&got, &want, 1e-12) { t.Errorf("PLU does not equal original matrix.\nWant: %v\n Got: %v", want, got) } } } func TestLURankOne(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, pivoting := range []bool{true} { for _, n := range []int{3, 10, 50} { // Construct a random LU factorization lu := &LU{} lu.lu = NewDense(n, n, nil) for i := 0; i < n; i++ { for j := 0; j < n; j++ { lu.lu.Set(i, j, rnd.Float64()) } } lu.pivot = make([]int, n) for i := range lu.pivot { lu.pivot[i] = i } if pivoting { // For each row, randomly swap with itself or a row after (like is done) // in the actual LU factorization. for i := range lu.pivot { idx := i + rnd.Intn(n-i) lu.pivot[i], lu.pivot[idx] = lu.pivot[idx], lu.pivot[i] } } // Apply a rank one update. Ensure the update magnitude is larger than // the equal tolerance. alpha := rnd.Float64() + 1 x := NewVecDense(n, nil) y := NewVecDense(n, nil) for i := 0; i < n; i++ { x.setVec(i, rnd.Float64()+1) y.setVec(i, rnd.Float64()+1) } a := luReconstruct(lu) a.RankOne(a, alpha, x, y) var luNew LU luNew.RankOne(lu, alpha, x, y) lu.RankOne(lu, alpha, x, y) aR1New := luReconstruct(&luNew) aR1 := luReconstruct(lu) if !Equal(aR1, aR1New) { t.Error("Different answer when new receiver") } if !EqualApprox(aR1, a, 1e-10) { t.Errorf("Rank one mismatch, pivot %v.\nWant: %v\nGot:%v\n", pivoting, a, aR1) } } } } // luReconstruct reconstructs the original A matrix from an LU decomposition. func luReconstruct(lu *LU) *Dense { var L, U TriDense lu.LTo(&L) lu.UTo(&U) var P Dense pivot := lu.Pivot(nil) P.Permutation(len(pivot), pivot) var a Dense a.Mul(&L, &U) a.Mul(&P, &a) return &a } func TestLUSolveTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { n, bc int }{ {5, 5}, {5, 10}, {10, 5}, } { n := test.n bc := test.bc a := NewDense(n, n, nil) for i := 0; i < n; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.NormFloat64()) } } b := NewDense(n, bc, nil) for i := 0; i < n; i++ { for j := 0; j < bc; j++ { b.Set(i, j, rnd.NormFloat64()) } } var lu LU lu.Factorize(a) var x Dense if err := lu.SolveTo(&x, false, b); err != nil { continue } var got Dense got.Mul(a, &x) if !EqualApprox(&got, b, 1e-12) { t.Errorf("SolveTo mismatch for non-singular matrix. n = %v, bc = %v.\nWant: %v\nGot: %v", n, bc, b, got) } } // TODO(btracey): Add testOneInput test when such a function exists. } func TestLUSolveToCond(t *testing.T) { t.Parallel() for _, test := range []*Dense{ NewDense(2, 2, []float64{1, 0, 0, 1e-20}), } { m, _ := test.Dims() var lu LU lu.Factorize(test) b := NewDense(m, 2, nil) var x Dense if err := lu.SolveTo(&x, false, b); err == nil { t.Error("No error for near-singular matrix in matrix solve.") } bvec := NewVecDense(m, nil) var xvec VecDense if err := lu.SolveVecTo(&xvec, false, bvec); err == nil { t.Error("No error for near-singular matrix in matrix solve.") } } } func TestLUSolveVecTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, n := range []int{5, 10} { a := NewDense(n, n, nil) for i := 0; i < n; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.NormFloat64()) } } b := NewVecDense(n, nil) for i := 0; i < n; i++ { b.SetVec(i, rnd.NormFloat64()) } var lu LU lu.Factorize(a) var x VecDense if err := lu.SolveVecTo(&x, false, b); err != nil { continue } var got VecDense got.MulVec(a, &x) if !EqualApprox(&got, b, 1e-12) { t.Errorf("SolveTo mismatch n = %v.\nWant: %v\nGot: %v", n, b, got) } } // TODO(btracey): Add testOneInput test when such a function exists. } golang-gonum-v1-gonum-0.14.0/mat/matrix.go000066400000000000000000000634251450372207100202640ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/lapack" ) // Matrix is the basic matrix interface type. type Matrix interface { // Dims returns the dimensions of a Matrix. Dims() (r, c int) // At returns the value of a matrix element at row i, column j. // It will panic if i or j are out of bounds for the matrix. At(i, j int) float64 // T returns the transpose of the Matrix. Whether T returns a copy of the // underlying data is implementation dependent. // This method may be implemented using the Transpose type, which // provides an implicit matrix transpose. T() Matrix } // allMatrix represents the extra set of methods that all mat Matrix types // should satisfy. This is used to enforce compile-time consistency between the // Dense types, especially helpful when adding new features. type allMatrix interface { Reseter IsEmpty() bool Zero() } // denseMatrix represents the extra set of methods that all Dense Matrix types // should satisfy. This is used to enforce compile-time consistency between the // Dense types, especially helpful when adding new features. type denseMatrix interface { DiagView() Diagonal Tracer Normer } var ( _ Matrix = Transpose{} _ Untransposer = Transpose{} ) // Transpose is a type for performing an implicit matrix transpose. It implements // the Matrix interface, returning values from the transpose of the matrix within. type Transpose struct { Matrix Matrix } // At returns the value of the element at row i and column j of the transposed // matrix, that is, row j and column i of the Matrix field. func (t Transpose) At(i, j int) float64 { return t.Matrix.At(j, i) } // Dims returns the dimensions of the transposed matrix. The number of rows returned // is the number of columns in the Matrix field, and the number of columns is // the number of rows in the Matrix field. func (t Transpose) Dims() (r, c int) { c, r = t.Matrix.Dims() return r, c } // T performs an implicit transpose by returning the Matrix field. func (t Transpose) T() Matrix { return t.Matrix } // Untranspose returns the Matrix field. func (t Transpose) Untranspose() Matrix { return t.Matrix } // Untransposer is a type that can undo an implicit transpose. type Untransposer interface { // Note: This interface is needed to unify all of the Transpose types. In // the mat methods, we need to test if the Matrix has been implicitly // transposed. If this is checked by testing for the specific Transpose type // then the behavior will be different if the user uses T() or TTri() for a // triangular matrix. // Untranspose returns the underlying Matrix stored for the implicit transpose. Untranspose() Matrix } // UntransposeBander is a type that can undo an implicit band transpose. type UntransposeBander interface { // Untranspose returns the underlying Banded stored for the implicit transpose. UntransposeBand() Banded } // UntransposeTrier is a type that can undo an implicit triangular transpose. type UntransposeTrier interface { // Untranspose returns the underlying Triangular stored for the implicit transpose. UntransposeTri() Triangular } // UntransposeTriBander is a type that can undo an implicit triangular banded // transpose. type UntransposeTriBander interface { // Untranspose returns the underlying Triangular stored for the implicit transpose. UntransposeTriBand() TriBanded } // Mutable is a matrix interface type that allows elements to be altered. type Mutable interface { // Set alters the matrix element at row i, column j to v. // It will panic if i or j are out of bounds for the matrix. Set(i, j int, v float64) Matrix } // A RowViewer can return a Vector reflecting a row that is backed by the matrix // data. The Vector returned will have length equal to the number of columns. type RowViewer interface { RowView(i int) Vector } // A RawRowViewer can return a slice of float64 reflecting a row that is backed by the matrix // data. type RawRowViewer interface { RawRowView(i int) []float64 } // A ColViewer can return a Vector reflecting a column that is backed by the matrix // data. The Vector returned will have length equal to the number of rows. type ColViewer interface { ColView(j int) Vector } // A RawColViewer can return a slice of float64 reflecting a column that is backed by the matrix // data. type RawColViewer interface { RawColView(j int) []float64 } // A ClonerFrom can make a copy of a into the receiver, overwriting the previous value of the // receiver. The clone operation does not make any restriction on shape and will not cause // shadowing. type ClonerFrom interface { CloneFrom(a Matrix) } // A Reseter can reset the matrix so that it can be reused as the receiver of a dimensionally // restricted operation. This is commonly used when the matrix is being used as a workspace // or temporary matrix. // // If the matrix is a view, using Reset may result in data corruption in elements outside // the view. Similarly, if the matrix shares backing data with another variable, using // Reset may lead to unexpected changes in data values. type Reseter interface { Reset() } // A Copier can make a copy of elements of a into the receiver. The submatrix copied // starts at row and column 0 and has dimensions equal to the minimum dimensions of // the two matrices. The number of row and columns copied is returned. // Copy will copy from a source that aliases the receiver unless the source is transposed; // an aliasing transpose copy will panic with the exception for a special case when // the source data has a unitary increment or stride. type Copier interface { Copy(a Matrix) (r, c int) } // A Grower can grow the size of the represented matrix by the given number of rows and columns. // Growing beyond the size given by the Caps method will result in the allocation of a new // matrix and copying of the elements. If Grow is called with negative increments it will // panic with ErrIndexOutOfRange. type Grower interface { Caps() (r, c int) Grow(r, c int) Matrix } // A RawMatrixSetter can set the underlying blas64.General used by the receiver. There is no restriction // on the shape of the receiver. Changes to the receiver's elements will be reflected in the blas64.General.Data. type RawMatrixSetter interface { SetRawMatrix(a blas64.General) } // A RawMatrixer can return a blas64.General representation of the receiver. Changes to the blas64.General.Data // slice will be reflected in the original matrix, changes to the Rows, Cols and Stride fields will not. type RawMatrixer interface { RawMatrix() blas64.General } // A RawVectorer can return a blas64.Vector representation of the receiver. Changes to the blas64.Vector.Data // slice will be reflected in the original matrix, changes to the Inc field will not. type RawVectorer interface { RawVector() blas64.Vector } // A NonZeroDoer can call a function for each non-zero element of the receiver. // The parameters of the function are the element indices and its value. type NonZeroDoer interface { DoNonZero(func(i, j int, v float64)) } // A RowNonZeroDoer can call a function for each non-zero element of a row of the receiver. // The parameters of the function are the element indices and its value. type RowNonZeroDoer interface { DoRowNonZero(i int, fn func(i, j int, v float64)) } // A ColNonZeroDoer can call a function for each non-zero element of a column of the receiver. // The parameters of the function are the element indices and its value. type ColNonZeroDoer interface { DoColNonZero(j int, fn func(i, j int, v float64)) } // untranspose untransposes a matrix if applicable. If a is an Untransposer, then // untranspose returns the underlying matrix and true. If it is not, then it returns // the input matrix and false. func untranspose(a Matrix) (Matrix, bool) { if ut, ok := a.(Untransposer); ok { return ut.Untranspose(), true } return a, false } // untransposeExtract returns an untransposed matrix in a built-in matrix type. // // The untransposed matrix is returned unaltered if it is a built-in matrix type. // Otherwise, if it implements a Raw method, an appropriate built-in type value // is returned holding the raw matrix value of the input. If neither of these // is possible, the untransposed matrix is returned. func untransposeExtract(a Matrix) (Matrix, bool) { ut, trans := untranspose(a) switch m := ut.(type) { case *DiagDense, *SymBandDense, *TriBandDense, *BandDense, *TriDense, *SymDense, *Dense, *VecDense, *Tridiag: return m, trans // TODO(btracey): Add here if we ever have an equivalent of RawDiagDense. case RawSymBander: rsb := m.RawSymBand() if rsb.Uplo != blas.Upper { return ut, trans } var sb SymBandDense sb.SetRawSymBand(rsb) return &sb, trans case RawTriBander: rtb := m.RawTriBand() if rtb.Diag == blas.Unit { return ut, trans } var tb TriBandDense tb.SetRawTriBand(rtb) return &tb, trans case RawBander: var b BandDense b.SetRawBand(m.RawBand()) return &b, trans case RawTriangular: rt := m.RawTriangular() if rt.Diag == blas.Unit { return ut, trans } var t TriDense t.SetRawTriangular(rt) return &t, trans case RawSymmetricer: rs := m.RawSymmetric() if rs.Uplo != blas.Upper { return ut, trans } var s SymDense s.SetRawSymmetric(rs) return &s, trans case RawMatrixer: var d Dense d.SetRawMatrix(m.RawMatrix()) return &d, trans case RawVectorer: var v VecDense v.SetRawVector(m.RawVector()) return &v, trans case RawTridiagonaler: var d Tridiag d.SetRawTridiagonal(m.RawTridiagonal()) return &d, trans default: return ut, trans } } // TODO(btracey): Consider adding CopyCol/CopyRow if the behavior seems useful. // TODO(btracey): Add in fast paths to Row/Col for the other concrete types // (TriDense, etc.) as well as relevant interfaces (RowColer, RawRowViewer, etc.) // Col copies the elements in the jth column of the matrix into the slice dst. // The length of the provided slice must equal the number of rows, unless the // slice is nil in which case a new slice is first allocated. func Col(dst []float64, j int, a Matrix) []float64 { r, c := a.Dims() if j < 0 || j >= c { panic(ErrColAccess) } if dst == nil { dst = make([]float64, r) } else { if len(dst) != r { panic(ErrColLength) } } aU, aTrans := untranspose(a) if rm, ok := aU.(RawMatrixer); ok { m := rm.RawMatrix() if aTrans { copy(dst, m.Data[j*m.Stride:j*m.Stride+m.Cols]) return dst } blas64.Copy(blas64.Vector{N: r, Inc: m.Stride, Data: m.Data[j:]}, blas64.Vector{N: r, Inc: 1, Data: dst}, ) return dst } for i := 0; i < r; i++ { dst[i] = a.At(i, j) } return dst } // Row copies the elements in the ith row of the matrix into the slice dst. // The length of the provided slice must equal the number of columns, unless the // slice is nil in which case a new slice is first allocated. func Row(dst []float64, i int, a Matrix) []float64 { r, c := a.Dims() if i < 0 || i >= r { panic(ErrColAccess) } if dst == nil { dst = make([]float64, c) } else { if len(dst) != c { panic(ErrRowLength) } } aU, aTrans := untranspose(a) if rm, ok := aU.(RawMatrixer); ok { m := rm.RawMatrix() if aTrans { blas64.Copy(blas64.Vector{N: c, Inc: m.Stride, Data: m.Data[i:]}, blas64.Vector{N: c, Inc: 1, Data: dst}, ) return dst } copy(dst, m.Data[i*m.Stride:i*m.Stride+m.Cols]) return dst } for j := 0; j < c; j++ { dst[j] = a.At(i, j) } return dst } // Cond returns the condition number of the given matrix under the given norm. // The condition number must be based on the 1-norm, 2-norm or ∞-norm. // Cond will panic with ErrZeroLength if the matrix has zero size. // // BUG(btracey): The computation of the 1-norm and ∞-norm for non-square matrices // is inaccurate, although is typically the right order of magnitude. See // https://github.com/xianyi/OpenBLAS/issues/636. While the value returned will // change with the resolution of this bug, the result from Cond will match the // condition number used internally. func Cond(a Matrix, norm float64) float64 { m, n := a.Dims() if m == 0 || n == 0 { panic(ErrZeroLength) } var lnorm lapack.MatrixNorm switch norm { default: panic("mat: bad norm value") case 1: lnorm = lapack.MaxColumnSum case 2: var svd SVD ok := svd.Factorize(a, SVDNone) if !ok { return math.Inf(1) } return svd.Cond() case math.Inf(1): lnorm = lapack.MaxRowSum } if m == n { // Use the LU decomposition to compute the condition number. var lu LU lu.factorize(a, lnorm) return lu.Cond() } if m > n { // Use the QR factorization to compute the condition number. var qr QR qr.factorize(a, lnorm) return qr.Cond() } // Use the LQ factorization to compute the condition number. var lq LQ lq.factorize(a, lnorm) return lq.Cond() } // Det returns the determinant of the square matrix a. In many expressions using // LogDet will be more numerically stable. // // Det panics with ErrSquare if a is not square and with ErrZeroLength if a has // zero size. func Det(a Matrix) float64 { det, sign := LogDet(a) return math.Exp(det) * sign } // Dot returns the sum of the element-wise product of a and b. // // Dot panics with ErrShape if the vector sizes are unequal and with // ErrZeroLength if the sizes are zero. func Dot(a, b Vector) float64 { la := a.Len() lb := b.Len() if la != lb { panic(ErrShape) } if la == 0 { panic(ErrZeroLength) } if arv, ok := a.(RawVectorer); ok { if brv, ok := b.(RawVectorer); ok { return blas64.Dot(arv.RawVector(), brv.RawVector()) } } var sum float64 for i := 0; i < la; i++ { sum += a.At(i, 0) * b.At(i, 0) } return sum } // Equal returns whether the matrices a and b have the same size // and are element-wise equal. func Equal(a, b Matrix) bool { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { return false } aU, aTrans := untranspose(a) bU, bTrans := untranspose(b) if rma, ok := aU.(RawMatrixer); ok { if rmb, ok := bU.(RawMatrixer); ok { ra := rma.RawMatrix() rb := rmb.RawMatrix() if aTrans == bTrans { for i := 0; i < ra.Rows; i++ { for j := 0; j < ra.Cols; j++ { if ra.Data[i*ra.Stride+j] != rb.Data[i*rb.Stride+j] { return false } } } return true } for i := 0; i < ra.Rows; i++ { for j := 0; j < ra.Cols; j++ { if ra.Data[i*ra.Stride+j] != rb.Data[j*rb.Stride+i] { return false } } } return true } } if rma, ok := aU.(RawSymmetricer); ok { if rmb, ok := bU.(RawSymmetricer); ok { ra := rma.RawSymmetric() rb := rmb.RawSymmetric() // Symmetric matrices are always upper and equal to their transpose. for i := 0; i < ra.N; i++ { for j := i; j < ra.N; j++ { if ra.Data[i*ra.Stride+j] != rb.Data[i*rb.Stride+j] { return false } } } return true } } if ra, ok := aU.(*VecDense); ok { if rb, ok := bU.(*VecDense); ok { // If the raw vectors are the same length they must either both be // transposed or both not transposed (or have length 1). for i := 0; i < ra.mat.N; i++ { if ra.mat.Data[i*ra.mat.Inc] != rb.mat.Data[i*rb.mat.Inc] { return false } } return true } } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.At(i, j) != b.At(i, j) { return false } } } return true } // EqualApprox returns whether the matrices a and b have the same size and contain all equal // elements with tolerance for element-wise equality specified by epsilon. Matrices // with non-equal shapes are not equal. func EqualApprox(a, b Matrix, epsilon float64) bool { ar, ac := a.Dims() br, bc := b.Dims() if ar != br || ac != bc { return false } aU, aTrans := untranspose(a) bU, bTrans := untranspose(b) if rma, ok := aU.(RawMatrixer); ok { if rmb, ok := bU.(RawMatrixer); ok { ra := rma.RawMatrix() rb := rmb.RawMatrix() if aTrans == bTrans { for i := 0; i < ra.Rows; i++ { for j := 0; j < ra.Cols; j++ { if !scalar.EqualWithinAbsOrRel(ra.Data[i*ra.Stride+j], rb.Data[i*rb.Stride+j], epsilon, epsilon) { return false } } } return true } for i := 0; i < ra.Rows; i++ { for j := 0; j < ra.Cols; j++ { if !scalar.EqualWithinAbsOrRel(ra.Data[i*ra.Stride+j], rb.Data[j*rb.Stride+i], epsilon, epsilon) { return false } } } return true } } if rma, ok := aU.(RawSymmetricer); ok { if rmb, ok := bU.(RawSymmetricer); ok { ra := rma.RawSymmetric() rb := rmb.RawSymmetric() // Symmetric matrices are always upper and equal to their transpose. for i := 0; i < ra.N; i++ { for j := i; j < ra.N; j++ { if !scalar.EqualWithinAbsOrRel(ra.Data[i*ra.Stride+j], rb.Data[i*rb.Stride+j], epsilon, epsilon) { return false } } } return true } } if ra, ok := aU.(*VecDense); ok { if rb, ok := bU.(*VecDense); ok { // If the raw vectors are the same length they must either both be // transposed or both not transposed (or have length 1). for i := 0; i < ra.mat.N; i++ { if !scalar.EqualWithinAbsOrRel(ra.mat.Data[i*ra.mat.Inc], rb.mat.Data[i*rb.mat.Inc], epsilon, epsilon) { return false } } return true } } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if !scalar.EqualWithinAbsOrRel(a.At(i, j), b.At(i, j), epsilon, epsilon) { return false } } } return true } // LogDet returns the log of the determinant and the sign of the determinant // for the matrix that has been factorized. Numerical stability in product and // division expressions is generally improved by working in log space. // // LogDet panics with ErrSquare is a is not square and with ErrZeroLength if a // has zero size. func LogDet(a Matrix) (det float64, sign float64) { // TODO(btracey): Add specialized routines for TriDense, etc. var lu LU lu.Factorize(a) return lu.LogDet() } // Max returns the largest element value of the matrix A. // // Max will panic with ErrZeroLength if the matrix has zero size. func Max(a Matrix) float64 { r, c := a.Dims() if r == 0 || c == 0 { panic(ErrZeroLength) } // Max(A) = Max(Aᵀ) aU, _ := untranspose(a) switch m := aU.(type) { case RawMatrixer: rm := m.RawMatrix() max := math.Inf(-1) for i := 0; i < rm.Rows; i++ { for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols] { if v > max { max = v } } } return max case RawTriangular: rm := m.RawTriangular() // The max of a triangular is at least 0 unless the size is 1. if rm.N == 1 { return rm.Data[0] } max := 0.0 if rm.Uplo == blas.Upper { for i := 0; i < rm.N; i++ { for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] { if v > max { max = v } } } return max } for i := 0; i < rm.N; i++ { for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+i+1] { if v > max { max = v } } } return max case RawSymmetricer: rm := m.RawSymmetric() if rm.Uplo != blas.Upper { panic(badSymTriangle) } max := math.Inf(-1) for i := 0; i < rm.N; i++ { for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] { if v > max { max = v } } } return max default: r, c := aU.Dims() max := math.Inf(-1) for i := 0; i < r; i++ { for j := 0; j < c; j++ { v := aU.At(i, j) if v > max { max = v } } } return max } } // Min returns the smallest element value of the matrix A. // // Min will panic with ErrZeroLength if the matrix has zero size. func Min(a Matrix) float64 { r, c := a.Dims() if r == 0 || c == 0 { panic(ErrZeroLength) } // Min(A) = Min(Aᵀ) aU, _ := untranspose(a) switch m := aU.(type) { case RawMatrixer: rm := m.RawMatrix() min := math.Inf(1) for i := 0; i < rm.Rows; i++ { for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols] { if v < min { min = v } } } return min case RawTriangular: rm := m.RawTriangular() // The min of a triangular is at most 0 unless the size is 1. if rm.N == 1 { return rm.Data[0] } min := 0.0 if rm.Uplo == blas.Upper { for i := 0; i < rm.N; i++ { for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] { if v < min { min = v } } } return min } for i := 0; i < rm.N; i++ { for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+i+1] { if v < min { min = v } } } return min case RawSymmetricer: rm := m.RawSymmetric() if rm.Uplo != blas.Upper { panic(badSymTriangle) } min := math.Inf(1) for i := 0; i < rm.N; i++ { for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] { if v < min { min = v } } } return min default: r, c := aU.Dims() min := math.Inf(1) for i := 0; i < r; i++ { for j := 0; j < c; j++ { v := aU.At(i, j) if v < min { min = v } } } return min } } // A Normer can compute a norm of the matrix. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum type Normer interface { Norm(norm float64) float64 } // Norm returns the specified norm of the matrix A. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // If a is a Normer, its Norm method will be used to calculate the norm. // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrShape if the matrix has zero size. func Norm(a Matrix, norm float64) float64 { r, c := a.Dims() if r == 0 || c == 0 { panic(ErrZeroLength) } m, trans := untransposeExtract(a) if m, ok := m.(Normer); ok { if trans { switch norm { case 1: norm = math.Inf(1) case math.Inf(1): norm = 1 } } return m.Norm(norm) } switch norm { default: panic(ErrNormOrder) case 1: var max float64 for j := 0; j < c; j++ { var sum float64 for i := 0; i < r; i++ { sum += math.Abs(a.At(i, j)) } if sum > max { max = sum } } return max case 2: var sum float64 for i := 0; i < r; i++ { for j := 0; j < c; j++ { v := a.At(i, j) sum += v * v } } return math.Sqrt(sum) case math.Inf(1): var max float64 for i := 0; i < r; i++ { var sum float64 for j := 0; j < c; j++ { sum += math.Abs(a.At(i, j)) } if sum > max { max = sum } } return max } } // normLapack converts the float64 norm input in Norm to a lapack.MatrixNorm. func normLapack(norm float64, aTrans bool) lapack.MatrixNorm { switch norm { case 1: n := lapack.MaxColumnSum if aTrans { n = lapack.MaxRowSum } return n case 2: return lapack.Frobenius case math.Inf(1): n := lapack.MaxRowSum if aTrans { n = lapack.MaxColumnSum } return n default: panic(ErrNormOrder) } } // Sum returns the sum of the elements of the matrix. // // Sum will panic with ErrZeroLength if the matrix has zero size. func Sum(a Matrix) float64 { r, c := a.Dims() if r == 0 || c == 0 { panic(ErrZeroLength) } var sum float64 aU, _ := untranspose(a) switch rma := aU.(type) { case RawSymmetricer: rm := rma.RawSymmetric() for i := 0; i < rm.N; i++ { // Diagonals count once while off-diagonals count twice. sum += rm.Data[i*rm.Stride+i] var s float64 for _, v := range rm.Data[i*rm.Stride+i+1 : i*rm.Stride+rm.N] { s += v } sum += 2 * s } return sum case RawTriangular: rm := rma.RawTriangular() var startIdx, endIdx int for i := 0; i < rm.N; i++ { // Start and end index for this triangle-row. switch rm.Uplo { case blas.Upper: startIdx = i endIdx = rm.N case blas.Lower: startIdx = 0 endIdx = i + 1 default: panic(badTriangle) } for _, v := range rm.Data[i*rm.Stride+startIdx : i*rm.Stride+endIdx] { sum += v } } return sum case RawMatrixer: rm := rma.RawMatrix() for i := 0; i < rm.Rows; i++ { for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols] { sum += v } } return sum case *VecDense: rm := rma.RawVector() for i := 0; i < rm.N; i++ { sum += rm.Data[i*rm.Inc] } return sum default: r, c := a.Dims() for i := 0; i < r; i++ { for j := 0; j < c; j++ { sum += a.At(i, j) } } return sum } } // A Tracer can compute the trace of the matrix. Trace must panic with ErrSquare // if the matrix is not square. type Tracer interface { Trace() float64 } // Trace returns the trace of the matrix. If a is a Tracer, its Trace method // will be used to calculate the matrix trace. // // Trace will panic with ErrSquare if the matrix is not square and with // ErrZeroLength if the matrix has zero size. func Trace(a Matrix) float64 { r, c := a.Dims() if r == 0 || c == 0 { panic(ErrZeroLength) } m, _ := untransposeExtract(a) if t, ok := m.(Tracer); ok { return t.Trace() } if r != c { panic(ErrSquare) } var v float64 for i := 0; i < r; i++ { v += a.At(i, i) } return v } 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 } // use returns a float64 slice with l elements, using f if it // has the necessary capacity, otherwise creating a new slice. func use(f []float64, l int) []float64 { if l <= cap(f) { return f[:l] } return make([]float64, l) } // useZeroed returns a float64 slice with l elements, using f if it // has the necessary capacity, otherwise creating a new slice. The // elements of the returned slice are guaranteed to be zero. func useZeroed(f []float64, l int) []float64 { if l <= cap(f) { f = f[:l] zero(f) return f } return make([]float64, l) } // zero zeros the given slice's elements. func zero(f []float64) { for i := range f { f[i] = 0 } } // useInt returns an int slice with l elements, using i if it // has the necessary capacity, otherwise creating a new slice. func useInt(i []int, l int) []int { if l <= cap(i) { return i[:l] } return make([]int, l) } golang-gonum-v1-gonum-0.14.0/mat/matrix_example_test.go000066400000000000000000000015361450372207100230310ustar00rootroot00000000000000// Copyright ©2019 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "gonum.org/v1/gonum/mat" ) func ExampleCol() { // This example copies the second column of a matrix into col, allocating a new slice of float64. m := mat.NewDense(3, 3, []float64{ 2.0, 9.0, 3.0, 4.5, 6.7, 8.0, 1.2, 3.0, 6.0, }) col := mat.Col(nil, 1, m) fmt.Printf("col = %#v", col) // Output: // // col = []float64{9, 6.7, 3} } func ExampleRow() { // This example copies the third row of a matrix into row, allocating a new slice of float64. m := mat.NewDense(3, 3, []float64{ 2.0, 9.0, 3.0, 4.5, 6.7, 8.0, 1.2, 3.0, 6.0, }) row := mat.Row(nil, 2, m) fmt.Printf("row = %#v", row) // Output: // // row = []float64{1.2, 3, 6} } golang-gonum-v1-gonum-0.14.0/mat/matrix_test.go000066400000000000000000000442041450372207100213150ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "math" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" ) func panics(fn func()) (panicked bool, message string) { defer func() { r := recover() panicked = r != nil message = fmt.Sprint(r) }() fn() return } func flatten(f [][]float64) (r, c int, d []float64) { r = len(f) if r == 0 { panic("bad test: no row") } c = len(f[0]) d = make([]float64, 0, r*c) for _, row := range f { if len(row) != c { panic("bad test: ragged input") } d = append(d, row...) } return r, c, d } func unflatten(r, c int, d []float64) [][]float64 { m := make([][]float64, r) for i := 0; i < r; i++ { m[i] = d[i*c : (i+1)*c] } return m } // eye returns a new identity matrix of size n×n. func eye(n int) *Dense { d := make([]float64, n*n) for i := 0; i < n*n; i += n + 1 { d[i] = 1 } return NewDense(n, n, d) } func TestCol(t *testing.T) { t.Parallel() for id, af := range [][][]float64{ { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, }, { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}, }, { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, }, } { a := NewDense(flatten(af)) col := make([]float64, a.mat.Rows) for j := range af[0] { for i := range col { col[i] = float64(i*a.mat.Cols + j + 1) } if got := Col(nil, j, a); !reflect.DeepEqual(got, col) { t.Errorf("test %d: unexpected values returned for dense col %d: got: %v want: %v", id, j, got, col) } got := make([]float64, a.mat.Rows) if Col(got, j, a); !reflect.DeepEqual(got, col) { t.Errorf("test %d: unexpected values filled for dense col %d: got: %v want: %v", id, j, got, col) } } } denseComparison := func(a *Dense) interface{} { r, c := a.Dims() ans := make([][]float64, c) for j := range ans { ans[j] = make([]float64, r) for i := range ans[j] { ans[j][i] = a.At(i, j) } } return ans } f := func(a Matrix) interface{} { _, c := a.Dims() ans := make([][]float64, c) for j := range ans { ans[j] = Col(nil, j, a) } return ans } testOneInputFunc(t, "Col", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) f = func(a Matrix) interface{} { r, c := a.Dims() ans := make([][]float64, c) for j := range ans { ans[j] = make([]float64, r) Col(ans[j], j, a) } return ans } testOneInputFunc(t, "Col", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) } func TestRow(t *testing.T) { t.Parallel() for id, af := range [][][]float64{ { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, }, { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}, }, { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, }, } { a := NewDense(flatten(af)) for i, row := range af { if got := Row(nil, i, a); !reflect.DeepEqual(got, row) { t.Errorf("test %d: unexpected values returned for dense row %d: got: %v want: %v", id, i, got, row) } got := make([]float64, len(row)) if Row(got, i, a); !reflect.DeepEqual(got, row) { t.Errorf("test %d: unexpected values filled for dense row %d: got: %v want: %v", id, i, got, row) } } } denseComparison := func(a *Dense) interface{} { r, c := a.Dims() ans := make([][]float64, r) for i := range ans { ans[i] = make([]float64, c) for j := range ans[i] { ans[i][j] = a.At(i, j) } } return ans } f := func(a Matrix) interface{} { r, _ := a.Dims() ans := make([][]float64, r) for i := range ans { ans[i] = Row(nil, i, a) } return ans } testOneInputFunc(t, "Row", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) f = func(a Matrix) interface{} { r, c := a.Dims() ans := make([][]float64, r) for i := range ans { ans[i] = make([]float64, c) Row(ans[i], i, a) } return ans } testOneInputFunc(t, "Row", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) } func TestCond(t *testing.T) { t.Parallel() for i, test := range []struct { a *Dense condOne float64 condTwo float64 condInf float64 }{ { a: NewDense(3, 3, []float64{ 8, 1, 6, 3, 5, 7, 4, 9, 2, }), condOne: 16.0 / 3.0, condTwo: 4.330127018922192, condInf: 16.0 / 3.0, }, { a: NewDense(4, 4, []float64{ 2, 9, 3, 2, 10, 9, 9, 3, 1, 1, 5, 2, 8, 4, 10, 2, }), condOne: 1 / 0.024740155174938, condTwo: 34.521576567075087, condInf: 1 / 0.012034465570035, }, { a: NewDense(3, 3, []float64{ 5, 6, 7, 8, -2, 1, 7, 7, 7}), condOne: 30.769230769230749, condTwo: 21.662689498448440, condInf: 31.153846153846136, }, } { orig := DenseCopyOf(test.a) condOne := Cond(test.a, 1) if !scalar.EqualWithinAbsOrRel(test.condOne, condOne, 1e-13, 1e-13) { t.Errorf("Case %d: one norm mismatch. Want %v, got %v", i, test.condOne, condOne) } if !Equal(test.a, orig) { t.Errorf("Case %d: unexpected mutation of input matrix for one norm. Want %v, got %v", i, orig, test.a) } condTwo := Cond(test.a, 2) if !scalar.EqualWithinAbsOrRel(test.condTwo, condTwo, 1e-13, 1e-13) { t.Errorf("Case %d: two norm mismatch. Want %v, got %v", i, test.condTwo, condTwo) } if !Equal(test.a, orig) { t.Errorf("Case %d: unexpected mutation of input matrix for two norm. Want %v, got %v", i, orig, test.a) } condInf := Cond(test.a, math.Inf(1)) if !scalar.EqualWithinAbsOrRel(test.condInf, condInf, 1e-13, 1e-13) { t.Errorf("Case %d: inf norm mismatch. Want %v, got %v", i, test.condInf, condInf) } if !Equal(test.a, orig) { t.Errorf("Case %d: unexpected mutation of input matrix for inf norm. Want %v, got %v", i, orig, test.a) } } for _, test := range []struct { name string norm float64 }{ { name: "CondOne", norm: 1, }, { name: "CondTwo", norm: 2, }, { name: "CondInf", norm: math.Inf(1), }, } { f := func(a Matrix) interface{} { return Cond(a, test.norm) } denseComparison := func(a *Dense) interface{} { return Cond(a, test.norm) } testOneInputFunc(t, test.name, f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isAnySize) } } func TestDet(t *testing.T) { t.Parallel() for c, test := range []struct { a *Dense ans float64 }{ { a: NewDense(2, 2, []float64{1, 0, 0, 1}), ans: 1, }, { a: NewDense(2, 2, []float64{1, 0, 0, -1}), ans: -1, }, { a: NewDense(3, 3, []float64{ 1, 2, 0, 0, 1, 2, 0, 2, 1, }), ans: -3, }, { a: NewDense(3, 3, []float64{ 1, 2, 3, 5, 7, 9, 6, 9, 12, }), ans: 0, }, } { a := DenseCopyOf(test.a) det := Det(a) if !Equal(a, test.a) { t.Errorf("Input matrix changed during Det. Case %d.", c) } if !scalar.EqualWithinAbsOrRel(det, test.ans, 1e-14, 1e-14) { t.Errorf("Det mismatch case %d. Got %v, want %v", c, det, test.ans) } } // Perform the normal list test to ensure it works for all types. f := func(a Matrix) interface{} { return Det(a) } denseComparison := func(a *Dense) interface{} { return Det(a) } testOneInputFunc(t, "Det", f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isSquare) // Check that it gives approximately the same answer as Cholesky // Ensure the input matrices are wider than tall so they are full rank isWide := func(ar, ac int) bool { return ar <= ac } f = func(a Matrix) interface{} { ar, ac := a.Dims() if !isWide(ar, ac) { panic(ErrShape) } var tmp Dense tmp.Mul(a, a.T()) return Det(&tmp) } denseComparison = func(a *Dense) interface{} { ar, ac := a.Dims() if !isWide(ar, ac) { panic(ErrShape) } var tmp SymDense tmp.SymOuterK(1, a) var chol Cholesky ok := chol.Factorize(&tmp) if !ok { panic("bad chol test") } return chol.Det() } testOneInputFunc(t, "DetVsChol", f, denseComparison, sameAnswerFloatApproxTol(1e-10), isAnyType, isWide) } func TestDot(t *testing.T) { t.Parallel() f := func(a, b Matrix) interface{} { return Dot(a.(Vector), b.(Vector)) } denseComparison := func(a, b *Dense) interface{} { ra, ca := a.Dims() rb, cb := b.Dims() if ra != rb || ca != cb { panic(ErrShape) } var sum float64 for i := 0; i < ra; i++ { for j := 0; j < ca; j++ { sum += a.At(i, j) * b.At(i, j) } } return sum } testTwoInputFunc(t, "Dot", f, denseComparison, sameAnswerFloatApproxTol(1e-12), legalTypesVectorVector, legalSizeSameVec) } func TestEqual(t *testing.T) { t.Parallel() f := func(a, b Matrix) interface{} { return Equal(a, b) } denseComparison := func(a, b *Dense) interface{} { return Equal(a, b) } testTwoInputFunc(t, "Equal", f, denseComparison, sameAnswerBool, legalTypesAll, isAnySize2) } func TestMax(t *testing.T) { t.Parallel() // A direct test of Max with *Dense arguments is in TestNewDense. f := func(a Matrix) interface{} { return Max(a) } denseComparison := func(a *Dense) interface{} { return Max(a) } testOneInputFunc(t, "Max", f, denseComparison, sameAnswerFloat, isAnyType, isAnySize) } func TestMin(t *testing.T) { t.Parallel() // A direct test of Min with *Dense arguments is in TestNewDense. f := func(a Matrix) interface{} { return Min(a) } denseComparison := func(a *Dense) interface{} { return Min(a) } testOneInputFunc(t, "Min", f, denseComparison, sameAnswerFloat, isAnyType, isAnySize) } func TestNorm(t *testing.T) { t.Parallel() for i, test := range []struct { a [][]float64 ord float64 norm float64 }{ { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, ord: 1, norm: 30, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, ord: 2, norm: 25.495097567963924, }, { a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, ord: math.Inf(1), norm: 33, }, { a: [][]float64{{1, -2, -2}, {-4, 5, 6}}, ord: 1, norm: 8, }, { a: [][]float64{{1, -2, -2}, {-4, 5, 6}}, ord: math.Inf(1), norm: 15, }, } { a := NewDense(flatten(test.a)) if math.Abs(Norm(a, test.ord)-test.norm) > 1e-14 { t.Errorf("Mismatch test %d: %v norm = %f", i, test.a, test.norm) } } for _, test := range []struct { name string norm float64 }{ {"NormOne", 1}, {"NormTwo", 2}, {"NormInf", math.Inf(1)}, } { f := func(a Matrix) interface{} { return Norm(a, test.norm) } denseComparison := func(a *Dense) interface{} { return Norm(a, test.norm) } testOneInputFunc(t, test.name, f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isAnySize) } } func TestNormZero(t *testing.T) { t.Parallel() for _, a := range []Matrix{ &Dense{}, &SymDense{}, &SymDense{mat: blas64.Symmetric{Uplo: blas.Upper}}, &TriDense{}, &TriDense{mat: blas64.Triangular{Uplo: blas.Upper, Diag: blas.NonUnit}}, &VecDense{}, } { for _, norm := range []float64{1, 2, math.Inf(1)} { panicked, message := panics(func() { Norm(a, norm) }) if !panicked { t.Errorf("expected panic for Norm(&%T{}, %v)", a, norm) } if message != ErrZeroLength.Error() { t.Errorf("unexpected panic string for Norm(&%T{}, %v): got:%s want:%s", a, norm, message, ErrShape.Error()) } } } } func TestSum(t *testing.T) { t.Parallel() f := func(a Matrix) interface{} { return Sum(a) } denseComparison := func(a *Dense) interface{} { return Sum(a) } testOneInputFunc(t, "Sum", f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isAnySize) } func TestTrace(t *testing.T) { t.Parallel() for _, test := range []struct { a *Dense trace float64 }{ { a: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), trace: 15, }, } { trace := Trace(test.a) if trace != test.trace { t.Errorf("Trace mismatch. Want %v, got %v", test.trace, trace) } } f := func(a Matrix) interface{} { return Trace(a) } denseComparison := func(a *Dense) interface{} { return Trace(a) } testOneInputFunc(t, "Trace", f, denseComparison, sameAnswerFloatApproxTol(1e-15), isAnyType, isSquare) } func TestTracer(t *testing.T) { t.Parallel() for _, test := range []struct { a Tracer want float64 }{ { a: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), want: 15, }, { a: NewSymDense(4, []float64{1, 2, 3, 4, 0, 5, 6, 7, 0, 0, 8, 9, 0, 0, 0, 10}), want: 24, }, { a: NewBandDense(6, 6, 1, 2, []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 19, 20, 0, 0}), want: 65, }, { a: NewDiagDense(6, []float64{1, 2, 3, 4, 5, 6}), want: 21, }, { a: NewSymBandDense(6, 2, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15, 0, 0}), want: 50, }, { a: NewTriBandDense(6, 2, Upper, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15, 0, 0}), want: 50, }, { a: NewTriBandDense(6, 2, Lower, []float64{0, 0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}), want: 46, }, } { got := test.a.Trace() if got != test.want { t.Errorf("Trace mismatch. Want %v, got %v", test.want, got) } } } func TestDoer(t *testing.T) { t.Parallel() type MatrixDoer interface { Matrix NonZeroDoer RowNonZeroDoer ColNonZeroDoer } ones := func(n int) []float64 { data := make([]float64, n) for i := range data { data[i] = 1 } return data } for i, m := range []MatrixDoer{ NewTriDense(3, Lower, ones(3*3)), NewTriDense(3, Upper, ones(3*3)), NewBandDense(6, 6, 1, 1, ones(3*6)), NewBandDense(6, 10, 1, 1, ones(3*6)), NewBandDense(10, 6, 1, 1, ones(7*3)), NewSymBandDense(3, 0, ones(3)), NewSymBandDense(3, 1, ones(3*(1+1))), NewSymBandDense(6, 1, ones(6*(1+1))), NewSymBandDense(6, 2, ones(6*(2+1))), NewTriBandDense(3, 0, Upper, ones(3)), NewTriBandDense(3, 1, Upper, ones(3*(1+1))), NewTriBandDense(6, 1, Upper, ones(6*(1+1))), NewTriBandDense(6, 2, Upper, ones(6*(2+1))), NewTriBandDense(3, 0, Lower, ones(3)), NewTriBandDense(3, 1, Lower, ones(3*(1+1))), NewTriBandDense(6, 1, Lower, ones(6*(1+1))), NewTriBandDense(6, 2, Lower, ones(6*(2+1))), NewTridiag(1, nil, ones(1), nil), NewTridiag(2, ones(1), ones(2), ones(1)), NewTridiag(3, ones(2), ones(3), ones(2)), NewTridiag(4, ones(3), ones(4), ones(3)), NewTridiag(7, ones(6), ones(7), ones(6)), NewTridiag(10, ones(9), ones(10), ones(9)), } { r, c := m.Dims() want := Sum(m) // got and fn sum the accessed elements in // the Doer that is being operated on. // fn also tests that the accessed elements // are within the writable areas of the // matrix to check that only valid elements // are operated on. var got float64 fn := func(i, j int, v float64) { got += v switch m := m.(type) { case MutableTriangular: m.SetTri(i, j, v) case MutableBanded: m.SetBand(i, j, v) case MutableSymBanded: m.SetSymBand(i, j, v) case MutableTriBanded: m.SetTriBand(i, j, v) default: panic("bad test: need mutable type") } } panicked, message := panics(func() { m.DoNonZero(fn) }) if panicked { t.Errorf("unexpected panic for Doer test %d: %q", i, message) continue } if got != want { t.Errorf("unexpected Doer sum: got:%f want:%f", got, want) } // Reset got for testing with DoRowNonZero. got = 0 panicked, message = panics(func() { for i := 0; i < r; i++ { m.DoRowNonZero(i, fn) } }) if panicked { t.Errorf("unexpected panic for RowDoer test %d: %q", i, message) continue } if got != want { t.Errorf("unexpected RowDoer sum: got:%f want:%f", got, want) } // Reset got for testing with DoColNonZero. got = 0 panicked, message = panics(func() { for j := 0; j < c; j++ { m.DoColNonZero(j, fn) } }) if panicked { t.Errorf("unexpected panic for ColDoer test %d: %q", i, message) continue } if got != want { t.Errorf("unexpected ColDoer sum: got:%f want:%f", got, want) } } } func TestMulVecToer(t *testing.T) { t.Parallel() const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) random := func(n int) []float64 { d := make([]float64, n) for i := range d { d[i] = rnd.NormFloat64() } return d } type mulVecToer interface { Matrix MulVecTo(*VecDense, bool, Vector) } for _, a := range []mulVecToer{ NewBandDense(1, 1, 0, 0, random(1)), NewBandDense(3, 1, 0, 0, random(1)), NewBandDense(3, 1, 1, 0, random(4)), NewBandDense(1, 3, 0, 0, random(1)), NewBandDense(1, 3, 0, 1, random(2)), NewBandDense(7, 10, 0, 0, random(7)), NewBandDense(7, 10, 2, 3, random(42)), NewBandDense(10, 7, 0, 0, random(7)), NewBandDense(10, 7, 2, 3, random(54)), NewBandDense(10, 10, 0, 0, random(10)), NewBandDense(10, 10, 2, 3, random(60)), NewSymBandDense(1, 0, random(1)), NewSymBandDense(3, 0, random(3)), NewSymBandDense(3, 1, random(6)), NewSymBandDense(10, 0, random(10)), NewSymBandDense(10, 1, random(20)), NewSymBandDense(10, 4, random(50)), NewTridiag(1, nil, random(1), nil), NewTridiag(2, random(1), random(2), random(1)), NewTridiag(3, random(2), random(3), random(2)), NewTridiag(4, random(3), random(4), random(3)), NewTridiag(7, random(6), random(7), random(6)), NewTridiag(10, random(9), random(10), random(9)), } { // Dense copy of A used for computing the expected result. var aDense Dense aDense.CloneFrom(a) r, c := a.Dims() for _, trans := range []bool{false, true} { m, n := r, c if trans { m, n = c, r } for _, dst := range []*VecDense{ new(VecDense), NewVecDense(m, random(m)), } { for xType := 0; xType <= 3; xType++ { var x Vector switch xType { case 0: x = NewVecDense(n, random(n)) case 1: if m != n { continue } x = dst case 2: x = &rawVector{asBasicVector(NewVecDense(n, random(n)))} case 3: x = asBasicVector(NewVecDense(n, random(n))) default: panic("bad xType") } var want VecDense if !trans { want.MulVec(&aDense, x) } else { want.MulVec(aDense.T(), x) } a.MulVecTo(dst, trans, x) var diff VecDense diff.SubVec(dst, &want) if resid := Norm(&diff, 1); resid > tol*float64(m) { t.Errorf("r=%d,c=%d,trans=%t,xType=%d: unexpected result; resid=%v, want<=%v", r, c, trans, xType, resid, tol*float64(m)) } } } } } } golang-gonum-v1-gonum-0.14.0/mat/mul_test.go000066400000000000000000000110301450372207100205750ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats" ) // TODO: Need to add tests where one is overwritten. func TestMulTypes(t *testing.T) { t.Parallel() src := rand.NewSource(1) for _, test := range []struct { ar int ac int br int bc int Panics bool }{ { ar: 5, ac: 5, br: 5, bc: 5, Panics: false, }, { ar: 10, ac: 5, br: 5, bc: 3, Panics: false, }, { ar: 10, ac: 5, br: 5, bc: 8, Panics: false, }, { ar: 8, ac: 10, br: 10, bc: 3, Panics: false, }, { ar: 8, ac: 3, br: 3, bc: 10, Panics: false, }, { ar: 5, ac: 8, br: 8, bc: 10, Panics: false, }, { ar: 5, ac: 12, br: 12, bc: 8, Panics: false, }, { ar: 5, ac: 7, br: 8, bc: 10, Panics: true, }, } { ar := test.ar ac := test.ac br := test.br bc := test.bc // Generate random matrices avec := make([]float64, ar*ac) randomSlice(avec, src) a := NewDense(ar, ac, avec) bvec := make([]float64, br*bc) randomSlice(bvec, src) b := NewDense(br, bc, bvec) // Check that it panics if it is supposed to if test.Panics { c := &Dense{} fn := func() { c.Mul(a, b) } pan, _ := panics(fn) if !pan { t.Errorf("Mul did not panic with dimension mismatch") } continue } cvec := make([]float64, ar*bc) // Get correct matrix multiply answer from blas64.Gemm blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, a.mat, b.mat, 0, blas64.General{Rows: ar, Cols: bc, Stride: bc, Data: cvec}, ) avecCopy := append([]float64{}, avec...) bvecCopy := append([]float64{}, bvec...) cvecCopy := append([]float64{}, cvec...) acomp := matComp{r: ar, c: ac, data: avecCopy} bcomp := matComp{r: br, c: bc, data: bvecCopy} ccomp := matComp{r: ar, c: bc, data: cvecCopy} // Do normal multiply with empty dense d := &Dense{} testMul(t, a, b, d, acomp, bcomp, ccomp, false, "empty receiver") // Normal multiply with existing receiver c := NewDense(ar, bc, cvec) randomSlice(cvec, src) testMul(t, a, b, c, acomp, bcomp, ccomp, false, "existing receiver") // Cast a as a basic matrix am := (*basicMatrix)(a) bm := (*basicMatrix)(b) d.Reset() testMul(t, am, b, d, acomp, bcomp, ccomp, true, "a is basic, receiver is empty") d.Reset() testMul(t, a, bm, d, acomp, bcomp, ccomp, true, "b is basic, receiver is empty") d.Reset() testMul(t, am, bm, d, acomp, bcomp, ccomp, true, "both basic, receiver is empty") randomSlice(cvec, src) testMul(t, am, b, d, acomp, bcomp, ccomp, true, "a is basic, receiver is full") randomSlice(cvec, src) testMul(t, a, bm, d, acomp, bcomp, ccomp, true, "b is basic, receiver is full") randomSlice(cvec, src) testMul(t, am, bm, d, acomp, bcomp, ccomp, true, "both basic, receiver is full") } } func randomSlice(s []float64, src rand.Source) { rnd := rand.New(src) for i := range s { s[i] = rnd.NormFloat64() } } type matComp struct { r, c int data []float64 } func testMul(t *testing.T, a, b Matrix, c *Dense, acomp, bcomp, ccomp matComp, cvecApprox bool, name string) { c.Mul(a, b) var aDense *Dense switch t := a.(type) { case *Dense: aDense = t case *basicMatrix: aDense = (*Dense)(t) } var bDense *Dense switch t := b.(type) { case *Dense: bDense = t case *basicMatrix: bDense = (*Dense)(t) } if !denseEqual(aDense, acomp) { t.Errorf("a changed unexpectedly for %v", name) } if !denseEqual(bDense, bcomp) { t.Errorf("b changed unexpectedly for %v", name) } if cvecApprox { if !denseEqualApprox(c, ccomp, 1e-14) { t.Errorf("mul answer not within tol for %v", name) } return } if !denseEqual(c, ccomp) { t.Errorf("mul answer not equal for %v", name) } } func denseEqual(a *Dense, acomp matComp) bool { ar2, ac2 := a.Dims() if ar2 != acomp.r { return false } if ac2 != acomp.c { return false } if !floats.Equal(a.mat.Data, acomp.data) { return false } return true } func denseEqualApprox(a *Dense, acomp matComp, tol float64) bool { ar2, ac2 := a.Dims() if ar2 != acomp.r { return false } if ac2 != acomp.c { return false } if !floats.EqualApprox(a.mat.Data, acomp.data, tol) { return false } return true } golang-gonum-v1-gonum-0.14.0/mat/offset.go000066400000000000000000000020571450372207100202400ustar00rootroot00000000000000// 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:build !safe // +build !safe package mat import "unsafe" // offset returns the number of float64 values b[0] is after a[0]. func offset(a, b []float64) int { if &a[0] == &b[0] { return 0 } // This expression must be atomic with respect to GC moves. // At this stage this is true, because the GC does not // move. See https://golang.org/issue/12445. return int(uintptr(unsafe.Pointer(&b[0]))-uintptr(unsafe.Pointer(&a[0]))) / int(unsafe.Sizeof(float64(0))) } // offsetComplex returns the number of complex128 values b[0] is after a[0]. func offsetComplex(a, b []complex128) int { if &a[0] == &b[0] { return 0 } // This expression must be atomic with respect to GC moves. // At this stage this is true, because the GC does not // move. See https://golang.org/issue/12445. return int(uintptr(unsafe.Pointer(&b[0]))-uintptr(unsafe.Pointer(&a[0]))) / int(unsafe.Sizeof(complex128(0))) } golang-gonum-v1-gonum-0.14.0/mat/offset_appengine.go000066400000000000000000000023661450372207100222710ustar00rootroot00000000000000// 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:build safe // +build safe package mat import "reflect" var sizeOfFloat64 = int(reflect.TypeOf(float64(0)).Size()) // offset returns the number of float64 values b[0] is after a[0]. func offset(a, b []float64) int { va0 := reflect.ValueOf(a).Index(0) vb0 := reflect.ValueOf(b).Index(0) if va0.Addr() == vb0.Addr() { return 0 } // This expression must be atomic with respect to GC moves. // At this stage this is true, because the GC does not // move. See https://golang.org/issue/12445. return int(vb0.UnsafeAddr()-va0.UnsafeAddr()) / sizeOfFloat64 } var sizeOfComplex128 = int(reflect.TypeOf(complex128(0)).Size()) // offsetComplex returns the number of complex128 values b[0] is after a[0]. func offsetComplex(a, b []complex128) int { va0 := reflect.ValueOf(a).Index(0) vb0 := reflect.ValueOf(b).Index(0) if va0.Addr() == vb0.Addr() { return 0 } // This expression must be atomic with respect to GC moves. // At this stage this is true, because the GC does not // move. See https://golang.org/issue/12445. return int(vb0.UnsafeAddr()-va0.UnsafeAddr()) / sizeOfComplex128 } golang-gonum-v1-gonum-0.14.0/mat/pool.go000066400000000000000000000157561450372207100177350ustar00rootroot00000000000000// 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 mat import ( "math/bits" "sync" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/blas/cblas128" ) // poolFor returns the ceiling of base 2 log of size. It provides an index // into a pool array to a sync.Pool that will return values able to hold // size elements. func poolFor(size uint) int { if size == 0 { return 0 } return bits.Len(size - 1) } var ( // poolDense contains size stratified workspace Dense pools. // Each poolDense element i returns sized matrices with a data // slice capped at 1<= 2*len(w.mat.Data) { t.Errorf("r: %d c: %d -> len: %d cap: %d", i, j, len(w.mat.Data), cap(w.mat.Data)) } w.Set(0, 0, math.NaN()) work[l] = w } for _, w := range work { putDenseWorkspace(w) } } } } } var benchmat *Dense func poolBenchmark(n, r, c int, clear bool) { for i := 0; i < n; i++ { benchmat = getDenseWorkspace(r, c, clear) putDenseWorkspace(benchmat) } } func newBenchmark(n, r, c int) { for i := 0; i < n; i++ { benchmat = NewDense(r, c, nil) } } func BenchmarkPool10by10Uncleared(b *testing.B) { poolBenchmark(b.N, 10, 10, false) } func BenchmarkPool10by10Cleared(b *testing.B) { poolBenchmark(b.N, 10, 10, true) } func BenchmarkNew10by10(b *testing.B) { newBenchmark(b.N, 10, 10) } func BenchmarkPool100by100Uncleared(b *testing.B) { poolBenchmark(b.N, 100, 100, false) } func BenchmarkPool100by100Cleared(b *testing.B) { poolBenchmark(b.N, 100, 100, true) } func BenchmarkNew100by100(b *testing.B) { newBenchmark(b.N, 100, 100) } func BenchmarkMulWorkspaceDense100Half(b *testing.B) { denseMulWorkspaceBench(b, 100, 0.5) } func BenchmarkMulWorkspaceDense100Tenth(b *testing.B) { denseMulWorkspaceBench(b, 100, 0.1) } func BenchmarkMulWorkspaceDense1000Half(b *testing.B) { denseMulWorkspaceBench(b, 1000, 0.5) } func BenchmarkMulWorkspaceDense1000Tenth(b *testing.B) { denseMulWorkspaceBench(b, 1000, 0.1) } func BenchmarkMulWorkspaceDense1000Hundredth(b *testing.B) { denseMulWorkspaceBench(b, 1000, 0.01) } func BenchmarkMulWorkspaceDense1000Thousandth(b *testing.B) { denseMulWorkspaceBench(b, 1000, 0.001) } func denseMulWorkspaceBench(b *testing.B, size int, rho float64) { src := rand.NewSource(1) b.StopTimer() a, _ := randDense(size, rho, src) d, _ := randDense(size, rho, src) b.StartTimer() for i := 0; i < b.N; i++ { a.Mul(a, d) } } golang-gonum-v1-gonum-0.14.0/mat/product.go000066400000000000000000000112441450372207100204300ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import "fmt" // Product calculates the product of the given factors and places the result in // the receiver. The order of multiplication operations is optimized to minimize // the number of floating point operations on the basis that all matrix // multiplications are general. func (m *Dense) Product(factors ...Matrix) { // The operation order optimisation is the naive O(n^3) dynamic // programming approach and does not take into consideration // finer-grained optimisations that might be available. // // TODO(kortschak) Consider using the O(nlogn) or O(mlogn) // algorithms that are available. e.g. // // e.g. http://www.jofcis.com/publishedpapers/2014_10_10_4299_4306.pdf // // In the case that this is replaced, retain this code in // tests to compare against. r, c := m.Dims() switch len(factors) { case 0: if r != 0 || c != 0 { panic(ErrShape) } return case 1: m.reuseAsNonZeroed(factors[0].Dims()) m.Copy(factors[0]) return case 2: // Don't do work that we know the answer to. m.Mul(factors[0], factors[1]) return } p := newMultiplier(m, factors) p.optimize() result := p.multiply() m.reuseAsNonZeroed(result.Dims()) m.Copy(result) putDenseWorkspace(result) } // debugProductWalk enables debugging output for Product. const debugProductWalk = false // multiplier performs operation order optimisation and tree traversal. type multiplier struct { // factors is the ordered set of // factors to multiply. factors []Matrix // dims is the chain of factor // dimensions. dims []int // table contains the dynamic // programming costs and subchain // division indices. table table } func newMultiplier(m *Dense, factors []Matrix) *multiplier { // Check size early, but don't yet // allocate data for m. r, c := m.Dims() fr, fc := factors[0].Dims() // newMultiplier is only called with len(factors) > 2. if !m.IsEmpty() { if fr != r { panic(ErrShape) } if _, lc := factors[len(factors)-1].Dims(); lc != c { panic(ErrShape) } } dims := make([]int, len(factors)+1) dims[0] = r dims[len(dims)-1] = c pc := fc for i, f := range factors[1:] { cr, cc := f.Dims() dims[i+1] = cr if pc != cr { panic(ErrShape) } pc = cc } return &multiplier{ factors: factors, dims: dims, table: newTable(len(factors)), } } // optimize determines an optimal matrix multiply operation order. func (p *multiplier) optimize() { if debugProductWalk { fmt.Printf("chain dims: %v\n", p.dims) } const maxInt = int(^uint(0) >> 1) for f := 1; f < len(p.factors); f++ { for i := 0; i < len(p.factors)-f; i++ { j := i + f p.table.set(i, j, entry{cost: maxInt}) for k := i; k < j; k++ { cost := p.table.at(i, k).cost + p.table.at(k+1, j).cost + p.dims[i]*p.dims[k+1]*p.dims[j+1] if cost < p.table.at(i, j).cost { p.table.set(i, j, entry{cost: cost, k: k}) } } } } } // multiply walks the optimal operation tree found by optimize, // leaving the final result in the stack. It returns the // product, which may be copied but should be returned to // the workspace pool. func (p *multiplier) multiply() *Dense { result, _ := p.multiplySubchain(0, len(p.factors)-1) if debugProductWalk { r, c := result.Dims() fmt.Printf("\tpop result (%d×%d) cost=%d\n", r, c, p.table.at(0, len(p.factors)-1).cost) } return result.(*Dense) } func (p *multiplier) multiplySubchain(i, j int) (m Matrix, intermediate bool) { if i == j { return p.factors[i], false } a, aTmp := p.multiplySubchain(i, p.table.at(i, j).k) b, bTmp := p.multiplySubchain(p.table.at(i, j).k+1, j) ar, ac := a.Dims() br, bc := b.Dims() if ac != br { // Panic with a string since this // is not a user-facing panic. panic(ErrShape.Error()) } if debugProductWalk { fmt.Printf("\tpush f[%d] (%d×%d)%s * f[%d] (%d×%d)%s\n", i, ar, ac, result(aTmp), j, br, bc, result(bTmp)) } r := getDenseWorkspace(ar, bc, false) r.Mul(a, b) if aTmp { putDenseWorkspace(a.(*Dense)) } if bTmp { putDenseWorkspace(b.(*Dense)) } return r, true } type entry struct { k int // is the chain subdivision index. cost int // cost is the cost of the operation. } // table is a row major n×n dynamic programming table. type table struct { n int entries []entry } func newTable(n int) table { return table{n: n, entries: make([]entry, n*n)} } func (t table) at(i, j int) entry { return t.entries[i*t.n+j] } func (t table) set(i, j int, e entry) { t.entries[i*t.n+j] = e } type result bool func (r result) String() string { if r { return " (popped result)" } return "" } golang-gonum-v1-gonum-0.14.0/mat/product_test.go000066400000000000000000000130641450372207100214710ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "testing" "golang.org/x/exp/rand" ) type dims struct{ r, c int } var productTests = []struct { n int factors []dims product dims panics bool }{ { n: 1, factors: []dims{{3, 4}}, product: dims{3, 4}, panics: false, }, { n: 1, factors: []dims{{2, 4}}, product: dims{3, 4}, panics: true, }, { n: 3, factors: []dims{{10, 30}, {30, 5}, {5, 60}}, product: dims{10, 60}, panics: false, }, { n: 3, factors: []dims{{100, 30}, {30, 5}, {5, 60}}, product: dims{10, 60}, panics: true, }, { n: 7, factors: []dims{{60, 5}, {5, 5}, {5, 4}, {4, 10}, {10, 22}, {22, 45}, {45, 10}}, product: dims{60, 10}, panics: false, }, { n: 7, factors: []dims{{60, 5}, {5, 5}, {5, 400}, {4, 10}, {10, 22}, {22, 45}, {45, 10}}, product: dims{60, 10}, panics: true, }, { n: 3, factors: []dims{{1, 1000}, {1000, 2}, {2, 2}}, product: dims{1, 2}, panics: false, }, // Random chains. { n: 0, product: dims{0, 0}, panics: false, }, { n: 2, product: dims{60, 10}, panics: false, }, { n: 3, product: dims{60, 10}, panics: false, }, { n: 4, product: dims{60, 10}, panics: false, }, { n: 10, product: dims{60, 10}, panics: false, }, } func TestProduct(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range productTests { dimensions := test.factors if dimensions == nil && test.n > 0 { dimensions = make([]dims, test.n) for i := range dimensions { if i != 0 { dimensions[i].r = dimensions[i-1].c } dimensions[i].c = rnd.Intn(50) + 1 } dimensions[0].r = test.product.r dimensions[test.n-1].c = test.product.c } factors := make([]Matrix, test.n) for i, d := range dimensions { data := make([]float64, d.r*d.c) for i := range data { data[i] = rnd.Float64() } factors[i] = NewDense(d.r, d.c, data) } want := &Dense{} if !test.panics { var a *Dense for i, b := range factors { if i == 0 { want.CloneFrom(b) continue } a, want = want, &Dense{} want.Mul(a, b) } } got := &Dense{} if test.product.r != 0 && test.product.c != 0 { got = NewDense(test.product.r, test.product.c, nil) } panicked, message := panics(func() { got.Product(factors...) }) if test.panics { if !panicked { t.Errorf("fail to panic with product chain dimensions: %+v result dimension: %+v", dimensions, test.product) } continue } else if panicked { t.Errorf("unexpected panic %q with product chain dimensions: %+v result dimension: %+v", message, dimensions, test.product) continue } if len(factors) > 0 { p := newMultiplier(NewDense(test.product.r, test.product.c, nil), factors) p.optimize() gotCost := p.table.at(0, len(factors)-1).cost expr, wantCost, ok := bestExpressionFor(dimensions) if !ok { t.Fatal("unexpected number of expressions in brute force expression search") } if gotCost != wantCost { t.Errorf("unexpected cost for chain dimensions: %+v got: %v want: %v\n%s", dimensions, got, want, expr) } } if !EqualApprox(got, want, 1e-14) { t.Errorf("unexpected result from product chain dimensions: %+v", dimensions) } } } // node is a subexpression node. type node struct { dims left, right *node } func (n *node) String() string { if n.left == nil || n.right == nil { rows, cols := n.shape() return fmt.Sprintf("[%d×%d]", rows, cols) } rows, cols := n.shape() return fmt.Sprintf("(%s * %s):[%d×%d]", n.left, n.right, rows, cols) } // shape returns the dimensions of the result of the subexpression. func (n *node) shape() (rows, cols int) { if n.left == nil || n.right == nil { return n.r, n.c } rows, _ = n.left.shape() _, cols = n.right.shape() return rows, cols } // cost returns the cost to evaluate the subexpression. func (n *node) cost() int { if n.left == nil || n.right == nil { return 0 } lr, lc := n.left.shape() _, rc := n.right.shape() return lr*lc*rc + n.left.cost() + n.right.cost() } // expressionsFor returns a channel that can be used to iterate over all // expressions of the given factor dimensions. func expressionsFor(factors []dims) chan *node { if len(factors) == 1 { c := make(chan *node, 1) c <- &node{dims: factors[0]} close(c) return c } c := make(chan *node) go func() { for i := 1; i < len(factors); i++ { for left := range expressionsFor(factors[:i]) { for right := range expressionsFor(factors[i:]) { c <- &node{left: left, right: right} } } } close(c) }() return c } // catalan returns the nth 0-based Catalan number. func catalan(n int) int { // Work in 64-bit integers since we overflow 32-bits for some tests. p := int64(1) for k := n + 1; k < 2*n+1; k++ { p *= int64(k) } for k := 2; k < n+2; k++ { p /= int64(k) } return int(p) } // bestExpressonFor returns the lowest cost expression for the given expression // factor dimensions, the cost of the expression and whether the number of // expressions searched matches the Catalan number for the number of factors. func bestExpressionFor(factors []dims) (exp *node, cost int, ok bool) { const maxInt = int(^uint(0) >> 1) min := maxInt var best *node var n int for exp := range expressionsFor(factors) { n++ cost := exp.cost() if cost < min { min = cost best = exp } } return best, min, n == catalan(len(factors)-1) } golang-gonum-v1-gonum-0.14.0/mat/qr.go000066400000000000000000000166141450372207100174000ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) const badQR = "mat: invalid QR factorization" // QR is a type for creating and using the QR factorization of a matrix. type QR struct { qr *Dense tau []float64 cond float64 } func (qr *QR) updateCond(norm lapack.MatrixNorm) { // Since A = Q*R, and Q is orthogonal, we get for the condition number κ // κ(A) := |A| |A^-1| = |Q*R| |(Q*R)^-1| = |R| |R^-1 * Qᵀ| // = |R| |R^-1| = κ(R), // where we used that fact that Q^-1 = Qᵀ. However, this assumes that // the matrix norm is invariant under orthogonal transformations which // is not the case for CondNorm. Hopefully the error is negligible: κ // is only a qualitative measure anyway. n := qr.qr.mat.Cols work := getFloat64s(3*n, false) iwork := getInts(n, false) r := qr.qr.asTriDense(n, blas.NonUnit, blas.Upper) v := lapack64.Trcon(norm, r.mat, work, iwork) putFloat64s(work) putInts(iwork) qr.cond = 1 / v } // Factorize computes the QR factorization of an m×n matrix a where m >= n. The QR // factorization always exists even if A is singular. // // The QR decomposition is a factorization of the matrix A such that A = Q * R. // The matrix Q is an orthonormal m×m matrix, and R is an m×n upper triangular matrix. // Q and R can be extracted using the QTo and RTo methods. func (qr *QR) Factorize(a Matrix) { qr.factorize(a, CondNorm) } func (qr *QR) factorize(a Matrix, norm lapack.MatrixNorm) { m, n := a.Dims() if m < n { panic(ErrShape) } k := min(m, n) if qr.qr == nil { qr.qr = &Dense{} } qr.qr.CloneFrom(a) work := []float64{0} qr.tau = make([]float64, k) lapack64.Geqrf(qr.qr.mat, qr.tau, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Geqrf(qr.qr.mat, qr.tau, work, len(work)) putFloat64s(work) qr.updateCond(norm) } // isValid returns whether the receiver contains a factorization. func (qr *QR) isValid() bool { return qr.qr != nil && !qr.qr.IsEmpty() } // Cond returns the condition number for the factorized matrix. // Cond will panic if the receiver does not contain a factorization. func (qr *QR) Cond() float64 { if !qr.isValid() { panic(badQR) } return qr.cond } // TODO(btracey): Add in the "Reduced" forms for extracting the n×n orthogonal // and upper triangular matrices. // RTo extracts the m×n upper trapezoidal matrix from a QR decomposition. // // If dst is empty, RTo will resize dst to be r×c. When dst is non-empty, // RTo will panic if dst is not r×c. RTo will also panic if the receiver // does not contain a successful factorization. func (qr *QR) RTo(dst *Dense) { if !qr.isValid() { panic(badQR) } r, c := qr.qr.Dims() if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if c != r2 || c != c2 { panic(ErrShape) } } // Disguise the QR as an upper triangular t := &TriDense{ mat: blas64.Triangular{ N: c, Stride: qr.qr.mat.Stride, Data: qr.qr.mat.Data, Uplo: blas.Upper, Diag: blas.NonUnit, }, cap: qr.qr.capCols, } dst.Copy(t) // Zero below the triangular. for i := r; i < c; i++ { zero(dst.mat.Data[i*dst.mat.Stride : i*dst.mat.Stride+c]) } } // QTo extracts the r×r orthonormal matrix Q from a QR decomposition. // // If dst is empty, QTo will resize dst to be r×r. When dst is non-empty, // QTo will panic if dst is not r×r. QTo will also panic if the receiver // does not contain a successful factorization. func (qr *QR) QTo(dst *Dense) { if !qr.isValid() { panic(badQR) } r, _ := qr.qr.Dims() if dst.IsEmpty() { dst.ReuseAs(r, r) } else { r2, c2 := dst.Dims() if r != r2 || r != c2 { panic(ErrShape) } dst.Zero() } // Set Q = I. for i := 0; i < r*r; i += r + 1 { dst.mat.Data[i] = 1 } // Construct Q from the elementary reflectors. work := []float64{0} lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, dst.mat, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, dst.mat, work, len(work)) putFloat64s(work) } // SolveTo finds a minimum-norm solution to a system of linear equations defined // by the matrices A and b, where A is an m×n matrix represented in its QR factorized // form. If A is singular or near-singular a Condition error is returned. // See the documentation for Condition for more information. // // The minimization problem solved depends on the input parameters. // // If trans == false, find X such that ||A*X - B||_2 is minimized. // If trans == true, find the minimum norm solution of Aᵀ * X = B. // // The solution matrix, X, is stored in place into dst. // SolveTo will panic if the receiver does not contain a factorization. func (qr *QR) SolveTo(dst *Dense, trans bool, b Matrix) error { if !qr.isValid() { panic(badQR) } r, c := qr.qr.Dims() br, bc := b.Dims() // The QR solve algorithm stores the result in-place into the right hand side. // The storage for the answer must be large enough to hold both b and x. // However, this method's receiver must be the size of x. Copy b, and then // copy the result into m at the end. if trans { if c != br { panic(ErrShape) } dst.reuseAsNonZeroed(r, bc) } else { if r != br { panic(ErrShape) } dst.reuseAsNonZeroed(c, bc) } // Do not need to worry about overlap between m and b because x has its own // independent storage. w := getDenseWorkspace(max(r, c), bc, false) w.Copy(b) t := qr.qr.asTriDense(qr.qr.mat.Cols, blas.NonUnit, blas.Upper).mat if trans { ok := lapack64.Trtrs(blas.Trans, t, w.mat) if !ok { return Condition(math.Inf(1)) } for i := c; i < r; i++ { zero(w.mat.Data[i*w.mat.Stride : i*w.mat.Stride+bc]) } work := []float64{0} lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, w.mat, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, w.mat, work, len(work)) putFloat64s(work) } else { work := []float64{0} lapack64.Ormqr(blas.Left, blas.Trans, qr.qr.mat, qr.tau, w.mat, work, -1) work = getFloat64s(int(work[0]), false) lapack64.Ormqr(blas.Left, blas.Trans, qr.qr.mat, qr.tau, w.mat, work, len(work)) putFloat64s(work) ok := lapack64.Trtrs(blas.NoTrans, t, w.mat) if !ok { return Condition(math.Inf(1)) } } // X was set above to be the correct size for the result. dst.Copy(w) putDenseWorkspace(w) if qr.cond > ConditionTolerance { return Condition(qr.cond) } return nil } // SolveVecTo finds a minimum-norm solution to a system of linear equations, // // Ax = b. // // See QR.SolveTo for the full documentation. // SolveVecTo will panic if the receiver does not contain a factorization. func (qr *QR) SolveVecTo(dst *VecDense, trans bool, b Vector) error { if !qr.isValid() { panic(badQR) } r, c := qr.qr.Dims() if _, bc := b.Dims(); bc != 1 { panic(ErrShape) } // The Solve implementation is non-trivial, so rather than duplicate the code, // instead recast the VecDenses as Dense and call the matrix code. bm := Matrix(b) if rv, ok := b.(RawVectorer); ok { bmat := rv.RawVector() if dst != b { dst.checkOverlap(bmat) } b := VecDense{mat: bmat} bm = b.asDense() } if trans { dst.reuseAsNonZeroed(r) } else { dst.reuseAsNonZeroed(c) } return qr.SolveTo(dst.asDense(), trans, bm) } golang-gonum-v1-gonum-0.14.0/mat/qr_example_test.go000066400000000000000000000014761450372207100221520ustar00rootroot00000000000000// Copyright ©2022 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "log" "gonum.org/v1/gonum/mat" ) func ExampleQR_solveTo() { // QR factorization can be used for solving linear inverse problems, // as this is a more numerically stable technique than direct // matrix inversion. // // Here, we want to solve: // Ax = b var ( a = mat.NewDense(4, 2, []float64{0, 1, 1, 1, 1, 1, 2, 1}) b = mat.NewDense(4, 1, []float64{1, 0, 2, 1}) x = mat.NewDense(2, 1, nil) ) var qr mat.QR qr.Factorize(a) err := qr.SolveTo(x, false, b) if err != nil { log.Fatalf("could not solve QR: %+v", err) } fmt.Printf("%.3f\n", mat.Formatted(x)) // Output: // ⎡0.000⎤ // ⎣1.000⎦ } golang-gonum-v1-gonum-0.14.0/mat/qr_test.go000066400000000000000000000107061450372207100204330ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" ) func TestQR(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n int }{ {5, 5}, {10, 5}, } { m := test.m n := test.n a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.NormFloat64()) } } var want Dense want.CloneFrom(a) var qr QR qr.Factorize(a) var q, r Dense qr.QTo(&q) if !isOrthonormal(&q, 1e-10) { t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n) } qr.RTo(&r) var got Dense got.Mul(&q, &r) if !EqualApprox(&got, &want, 1e-12) { t.Errorf("QR does not equal original matrix. \nWant: %v\nGot: %v", want, got) } } } func isOrthonormal(q *Dense, tol float64) bool { m, n := q.Dims() if m != n { return false } for i := 0; i < m; i++ { for j := i; j < m; j++ { dot := blas64.Dot(blas64.Vector{N: m, Inc: 1, Data: q.mat.Data[i*q.mat.Stride:]}, blas64.Vector{N: m, Inc: 1, Data: q.mat.Data[j*q.mat.Stride:]}) // Dot product should be 1 if i == j and 0 otherwise. if i == j && math.Abs(dot-1) > tol { return false } if i != j && math.Abs(dot) > tol { return false } } } return true } func TestQRSolveTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, trans := range []bool{false, true} { for _, test := range []struct { m, n, bc int }{ {5, 5, 1}, {10, 5, 1}, {5, 5, 3}, {10, 5, 3}, } { m := test.m n := test.n bc := test.bc a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m if trans { br = n } b := NewDense(br, bc, nil) for i := 0; i < br; i++ { for j := 0; j < bc; j++ { b.Set(i, j, rnd.Float64()) } } var x Dense var qr QR qr.Factorize(a) err := qr.SolveTo(&x, trans, b) if err != nil { t.Errorf("unexpected error from QR solve: %v", err) } // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b if !trans // A * Aᵀ * x = A * b if trans var lhs Dense var rhs Dense if trans { var tmp Dense tmp.Mul(a, a.T()) lhs.Mul(&tmp, &x) rhs.Mul(a, b) } else { var tmp Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) } if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } } // TODO(btracey): Add in testOneInput when it exists. } func TestQRSolveVecTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, trans := range []bool{false, true} { for _, test := range []struct { m, n int }{ {5, 5}, {10, 5}, } { m := test.m n := test.n a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m if trans { br = n } b := NewVecDense(br, nil) for i := 0; i < br; i++ { b.SetVec(i, rnd.Float64()) } var x VecDense var qr QR qr.Factorize(a) err := qr.SolveVecTo(&x, trans, b) if err != nil { t.Errorf("unexpected error from QR solve: %v", err) } // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b if !trans // A * Aᵀ * x = A * b if trans var lhs Dense var rhs Dense if trans { var tmp Dense tmp.Mul(a, a.T()) lhs.Mul(&tmp, &x) rhs.Mul(a, b) } else { var tmp Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) } if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } } // TODO(btracey): Add in testOneInput when it exists. } func TestQRSolveCondTo(t *testing.T) { t.Parallel() for _, test := range []*Dense{ NewDense(2, 2, []float64{1, 0, 0, 1e-20}), NewDense(3, 2, []float64{1, 0, 0, 1e-20, 0, 0}), } { m, _ := test.Dims() var qr QR qr.Factorize(test) b := NewDense(m, 2, nil) var x Dense if err := qr.SolveTo(&x, false, b); err == nil { t.Error("No error for near-singular matrix in matrix solve.") } bvec := NewVecDense(m, nil) var xvec VecDense if err := qr.SolveVecTo(&xvec, false, bvec); err == nil { t.Error("No error for near-singular matrix in matrix solve.") } } } golang-gonum-v1-gonum-0.14.0/mat/shadow.go000066400000000000000000000134701450372207100202400ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import "gonum.org/v1/gonum/blas/blas64" // checkOverlap returns false if the receiver does not overlap data elements // referenced by the parameter and panics otherwise. // // checkOverlap methods return a boolean to allow the check call to be added to a // boolean expression, making use of short-circuit operators. func checkOverlap(a, b blas64.General) bool { if cap(a.Data) == 0 || cap(b.Data) == 0 { return false } off := offset(a.Data[:1], b.Data[:1]) if off == 0 { // At least one element overlaps. if a.Cols == b.Cols && a.Rows == b.Rows && a.Stride == b.Stride { panic(regionIdentity) } panic(regionOverlap) } if off > 0 && len(a.Data) <= off { // We know a is completely before b. return false } if off < 0 && len(b.Data) <= -off { // We know a is completely after b. return false } if a.Stride != b.Stride && a.Stride != 1 && b.Stride != 1 { // Too hard, so assume the worst; if either stride // is one it will be caught in rectanglesOverlap. panic(mismatchedStrides) } if off < 0 { off = -off a.Cols, b.Cols = b.Cols, a.Cols } if rectanglesOverlap(off, a.Cols, b.Cols, min(a.Stride, b.Stride)) { panic(regionOverlap) } return false } func (m *Dense) checkOverlap(a blas64.General) bool { return checkOverlap(m.RawMatrix(), a) } func (m *Dense) checkOverlapMatrix(a Matrix) bool { if m == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return m.checkOverlap(amat) } func (s *SymDense) checkOverlap(a blas64.General) bool { return checkOverlap(generalFromSymmetric(s.RawSymmetric()), a) } func (s *SymDense) checkOverlapMatrix(a Matrix) bool { if s == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return s.checkOverlap(amat) } // generalFromSymmetric returns a blas64.General with the backing // data and dimensions of a. func generalFromSymmetric(a blas64.Symmetric) blas64.General { return blas64.General{ Rows: a.N, Cols: a.N, Stride: a.Stride, Data: a.Data, } } func (t *TriDense) checkOverlap(a blas64.General) bool { return checkOverlap(generalFromTriangular(t.RawTriangular()), a) } func (t *TriDense) checkOverlapMatrix(a Matrix) bool { if t == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return t.checkOverlap(amat) } // generalFromTriangular returns a blas64.General with the backing // data and dimensions of a. func generalFromTriangular(a blas64.Triangular) blas64.General { return blas64.General{ Rows: a.N, Cols: a.N, Stride: a.Stride, Data: a.Data, } } func (v *VecDense) checkOverlap(a blas64.Vector) bool { mat := v.mat if cap(mat.Data) == 0 || cap(a.Data) == 0 { return false } off := offset(mat.Data[:1], a.Data[:1]) if off == 0 { // At least one element overlaps. if mat.Inc == a.Inc && len(mat.Data) == len(a.Data) { panic(regionIdentity) } panic(regionOverlap) } if off > 0 && len(mat.Data) <= off { // We know v is completely before a. return false } if off < 0 && len(a.Data) <= -off { // We know v is completely after a. return false } if mat.Inc != a.Inc && mat.Inc != 1 && a.Inc != 1 { // Too hard, so assume the worst; if either // increment is one it will be caught below. panic(mismatchedStrides) } inc := min(mat.Inc, a.Inc) if inc == 1 || off&inc == 0 { panic(regionOverlap) } return false } // generalFromVector returns a blas64.General with the backing // data and dimensions of a. func generalFromVector(a blas64.Vector, r, c int) blas64.General { return blas64.General{ Rows: r, Cols: c, Stride: a.Inc, Data: a.Data, } } func (s *SymBandDense) checkOverlap(a blas64.General) bool { return checkOverlap(generalFromSymmetricBand(s.RawSymBand()), a) } //lint:ignore U1000 This will be used when we do shadow checks for banded matrices. func (s *SymBandDense) checkOverlapMatrix(a Matrix) bool { if s == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return s.checkOverlap(amat) } // generalFromSymmetricBand returns a blas64.General with the backing // data and dimensions of a. func generalFromSymmetricBand(a blas64.SymmetricBand) blas64.General { return blas64.General{ Rows: a.N, Cols: a.K + 1, Data: a.Data, Stride: a.Stride, } } golang-gonum-v1-gonum-0.14.0/mat/shadow_common.go000066400000000000000000000036361450372207100216130ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat const ( // regionOverlap is the panic string used for the general case // of a matrix region overlap between a source and destination. regionOverlap = "mat: bad region: overlap" // regionIdentity is the panic string used for the specific // case of complete agreement between a source and a destination. regionIdentity = "mat: bad region: identical" // mismatchedStrides is the panic string used for overlapping // data slices with differing strides. mismatchedStrides = "mat: bad region: different strides" ) // rectanglesOverlap returns whether the strided rectangles a and b overlap // when b is offset by off elements after a but has at least one element before // the end of a. off must be positive. a and b have aCols and bCols respectively. // // rectanglesOverlap works by shifting both matrices left such that the left // column of a is at 0. The column indexes are flattened by obtaining the shifted // relative left and right column positions modulo the common stride. This allows // direct comparison of the column offsets when the matrix backing data slices // are known to overlap. func rectanglesOverlap(off, aCols, bCols, stride int) bool { if stride == 1 { // Unit stride means overlapping data // slices must overlap as matrices. return true } // Flatten the shifted matrix column positions // so a starts at 0, modulo the common stride. aTo := aCols // The mod stride operations here make the from // and to indexes comparable between a and b when // the data slices of a and b overlap. bFrom := off % stride bTo := (bFrom + bCols) % stride if bTo == 0 || bFrom < bTo { // b matrix is not wrapped: compare for // simple overlap. return bFrom < aTo } // b strictly wraps and so must overlap with a. return true } golang-gonum-v1-gonum-0.14.0/mat/shadow_complex.go000066400000000000000000000034741450372207100217720ustar00rootroot00000000000000// 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. // TODO(kortschak): Generate this file from shadow.go when all complex type are available. package mat import "gonum.org/v1/gonum/blas/cblas128" // checkOverlapComplex returns false if the receiver does not overlap data elements // referenced by the parameter and panics otherwise. // // checkOverlapComplex methods return a boolean to allow the check call to be added to a // boolean expression, making use of short-circuit operators. func checkOverlapComplex(a, b cblas128.General) bool { if cap(a.Data) == 0 || cap(b.Data) == 0 { return false } off := offsetComplex(a.Data[:1], b.Data[:1]) if off == 0 { // At least one element overlaps. if a.Cols == b.Cols && a.Rows == b.Rows && a.Stride == b.Stride { panic(regionIdentity) } panic(regionOverlap) } if off > 0 && len(a.Data) <= off { // We know a is completely before b. return false } if off < 0 && len(b.Data) <= -off { // We know a is completely after b. return false } if a.Stride != b.Stride && a.Stride != 1 && b.Stride != 1 { // Too hard, so assume the worst; if either stride // is one it will be caught in rectanglesOverlap. panic(mismatchedStrides) } if off < 0 { off = -off a.Cols, b.Cols = b.Cols, a.Cols } if rectanglesOverlap(off, a.Cols, b.Cols, min(a.Stride, b.Stride)) { panic(regionOverlap) } return false } func (m *CDense) checkOverlap(a cblas128.General) bool { return checkOverlapComplex(m.RawCMatrix(), a) } func (m *CDense) checkOverlapMatrix(a CMatrix) bool { if m == a { return false } var amat cblas128.General switch ar := a.(type) { default: return false case RawCMatrixer: amat = ar.RawCMatrix() } return m.checkOverlap(amat) } golang-gonum-v1-gonum-0.14.0/mat/shadow_test.go000066400000000000000000000063131450372207100212750ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "testing" "golang.org/x/exp/rand" ) func TestDenseOverlaps(t *testing.T) { t.Parallel() type view struct { i, j, r, c int *Dense } rnd := rand.New(rand.NewSource(1)) for r := 1; r < 20; r++ { for c := 1; c < 20; c++ { m := NewDense(r, c, nil) panicked, message := panics(func() { m.checkOverlap(m.RawMatrix()) }) if !panicked { t.Error("expected matrix overlap with self") } if message != regionIdentity { t.Errorf("unexpected panic message for self overlap: got: %q want: %q", message, regionIdentity) } for i := 0; i < 1000; i++ { var views [2]view for k := range views { if r > 1 { views[k].i = rnd.Intn(r - 1) views[k].r = rnd.Intn(r-views[k].i-1) + 1 } else { views[k].r = 1 } if c > 1 { views[k].j = rnd.Intn(c - 1) views[k].c = rnd.Intn(c-views[k].j-1) + 1 } else { views[k].c = 1 } views[k].Dense = m.Slice(views[k].i, views[k].i+views[k].r, views[k].j, views[k].j+views[k].c).(*Dense) panicked, _ = panics(func() { m.checkOverlap(views[k].RawMatrix()) }) if !panicked { t.Errorf("expected matrix (%d×%d) overlap with view {rows=%d:%d, cols=%d:%d}", r, c, views[k].i, views[k].i+views[k].r, views[k].j, views[k].j+views[k].c) } panicked, _ = panics(func() { views[k].checkOverlap(m.RawMatrix()) }) if !panicked { t.Errorf("expected view {rows=%d:%d, cols=%d:%d} overlap with parent (%d×%d)", views[k].i, views[k].i+views[k].r, views[k].j, views[k].j+views[k].c, r, c) } } overlapRows := intervalsOverlap( interval{views[0].i, views[0].i + views[0].r}, interval{views[1].i, views[1].i + views[1].r}, ) overlapCols := intervalsOverlap( interval{views[0].j, views[0].j + views[0].c}, interval{views[1].j, views[1].j + views[1].c}, ) want := overlapRows && overlapCols for k, v := range views { w := views[1-k] got, _ := panics(func() { v.checkOverlap(w.RawMatrix()) }) if got != want { t.Errorf("unexpected result for overlap test for {rows=%d:%d, cols=%d:%d} with {rows=%d:%d, cols=%d:%d}: got: %t want: %t", v.i, v.i+v.r, v.j, v.j+v.c, w.i, w.i+w.r, w.j, w.j+w.c, got, want) } } } } } } type interval struct{ from, to int } func intervalsOverlap(a, b interval) bool { return a.to > b.from && b.to > a.from } // See https://github.com/gonum/matrix/issues/359 for details. func TestIssue359(t *testing.T) { t.Parallel() for xi := 0; xi < 2; xi++ { for xj := 0; xj < 2; xj++ { for yi := 0; yi < 2; yi++ { for yj := 0; yj < 2; yj++ { a := NewDense(3, 3, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }) x := a.Slice(xi, xi+2, xj, xj+2).(*Dense) y := a.Slice(yi, yi+2, yj, yj+2).(*Dense) panicked, _ := panics(func() { x.checkOverlap(y.mat) }) if !panicked { t.Errorf("expected panic for aliased with offsets x(%d,%d) y(%d,%d):\nx:\n%v\ny:\n%v", xi, xj, yi, yj, Formatted(x), Formatted(y), ) } } } } } } golang-gonum-v1-gonum-0.14.0/mat/solve.go000066400000000000000000000103431450372207100200770ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack/lapack64" ) // Solve solves the linear least squares problem // // minimize over x |b - A*x|_2 // // where A is an m×n matrix, b is a given m element vector and x is n element // solution vector. Solve assumes that A has full rank, that is // // rank(A) = min(m,n) // // If m >= n, Solve finds the unique least squares solution of an overdetermined // system. // // If m < n, there is an infinite number of solutions that satisfy b-A*x=0. In // this case Solve finds the unique solution of an underdetermined system that // minimizes |x|_2. // // Several right-hand side vectors b and solution vectors x can be handled in a // single call. Vectors b are stored in the columns of the m×k matrix B. Vectors // x will be stored in-place into the n×k receiver. // // If A does not have full rank, a Condition error is returned. See the // documentation for Condition for more information. func (m *Dense) Solve(a, b Matrix) error { ar, ac := a.Dims() br, bc := b.Dims() if ar != br { panic(ErrShape) } m.reuseAsNonZeroed(ac, bc) // TODO(btracey): Add special cases for SymDense, etc. aU, aTrans := untranspose(a) bU, bTrans := untranspose(b) switch rma := aU.(type) { case RawTriangular: side := blas.Left tA := blas.NoTrans if aTrans { tA = blas.Trans } switch rm := bU.(type) { case RawMatrixer: if m != bU || bTrans { if m == bU || m.checkOverlap(rm.RawMatrix()) { tmp := getDenseWorkspace(br, bc, false) tmp.Copy(b) m.Copy(tmp) putDenseWorkspace(tmp) break } m.Copy(b) } default: if m != bU { m.Copy(b) } else if bTrans { // m and b share data so Copy cannot be used directly. tmp := getDenseWorkspace(br, bc, false) tmp.Copy(b) m.Copy(tmp) putDenseWorkspace(tmp) } } rm := rma.RawTriangular() blas64.Trsm(side, tA, 1, rm, m.mat) work := getFloat64s(3*rm.N, false) iwork := getInts(rm.N, false) cond := lapack64.Trcon(CondNorm, rm, work, iwork) putFloat64s(work) putInts(iwork) if cond > ConditionTolerance { return Condition(cond) } return nil } switch { case ar == ac: if a == b { // x = I. if ar == 1 { m.mat.Data[0] = 1 return nil } for i := 0; i < ar; i++ { v := m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+ac] zero(v) v[i] = 1 } return nil } var lu LU lu.Factorize(a) return lu.SolveTo(m, false, b) case ar > ac: var qr QR qr.Factorize(a) return qr.SolveTo(m, false, b) default: var lq LQ lq.Factorize(a) return lq.SolveTo(m, false, b) } } // SolveVec solves the linear least squares problem // // minimize over x |b - A*x|_2 // // where A is an m×n matrix, b is a given m element vector and x is n element // solution vector. Solve assumes that A has full rank, that is // // rank(A) = min(m,n) // // If m >= n, Solve finds the unique least squares solution of an overdetermined // system. // // If m < n, there is an infinite number of solutions that satisfy b-A*x=0. In // this case Solve finds the unique solution of an underdetermined system that // minimizes |x|_2. // // The solution vector x will be stored in-place into the receiver. // // If A does not have full rank, a Condition error is returned. See the // documentation for Condition for more information. func (v *VecDense) SolveVec(a Matrix, b Vector) error { if _, bc := b.Dims(); bc != 1 { panic(ErrShape) } _, c := a.Dims() // The Solve implementation is non-trivial, so rather than duplicate the code, // instead recast the VecDenses as Dense and call the matrix code. if rv, ok := b.(RawVectorer); ok { bmat := rv.RawVector() if v != b { v.checkOverlap(bmat) } v.reuseAsNonZeroed(c) m := v.asDense() // We conditionally create bm as m when b and v are identical // to prevent the overlap detection code from identifying m // and bm as overlapping but not identical. bm := m if v != b { b := VecDense{mat: bmat} bm = b.asDense() } return m.Solve(a, bm) } v.reuseAsNonZeroed(c) m := v.asDense() return m.Solve(a, b) } golang-gonum-v1-gonum-0.14.0/mat/solve_test.go000066400000000000000000000132111450372207100211330ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "testing" "golang.org/x/exp/rand" ) func TestSolve(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) // Hand-coded cases. for _, test := range []struct { a [][]float64 b [][]float64 ans [][]float64 shouldErr bool }{ { a: [][]float64{{6}}, b: [][]float64{{3}}, ans: [][]float64{{0.5}}, shouldErr: false, }, { a: [][]float64{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, }, b: [][]float64{ {3}, {2}, {1}, }, ans: [][]float64{ {3}, {2}, {1}, }, shouldErr: false, }, { a: [][]float64{ {0.8147, 0.9134, 0.5528}, {0.9058, 0.6324, 0.8723}, {0.1270, 0.0975, 0.7612}, }, b: [][]float64{ {0.278}, {0.547}, {0.958}, }, ans: [][]float64{ {-0.932687281002860}, {0.303963920182067}, {1.375216503507109}, }, shouldErr: false, }, { a: [][]float64{ {0.8147, 0.9134, 0.5528}, {0.9058, 0.6324, 0.8723}, }, b: [][]float64{ {0.278}, {0.547}, }, ans: [][]float64{ {0.25919787248965376}, {-0.25560256266441034}, {0.5432324059702451}, }, shouldErr: false, }, { a: [][]float64{ {0.8147, 0.9134, 0.9}, {0.9058, 0.6324, 0.9}, {0.1270, 0.0975, 0.1}, {1.6, 2.8, -3.5}, }, b: [][]float64{ {0.278}, {0.547}, {-0.958}, {1.452}, }, ans: [][]float64{ {0.820970340787782}, {-0.218604626527306}, {-0.212938815234215}, }, shouldErr: false, }, { a: [][]float64{ {0.8147, 0.9134, 0.231, -1.65}, {0.9058, 0.6324, 0.9, 0.72}, {0.1270, 0.0975, 0.1, 1.723}, {1.6, 2.8, -3.5, 0.987}, {7.231, 9.154, 1.823, 0.9}, }, b: [][]float64{ {0.278, 8.635}, {0.547, 9.125}, {-0.958, -0.762}, {1.452, 1.444}, {1.999, -7.234}, }, ans: [][]float64{ {1.863006789511373, 44.467887791812750}, {-1.127270935407224, -34.073794226035126}, {-0.527926457947330, -8.032133759788573}, {-0.248621916204897, -2.366366415805275}, }, shouldErr: false, }, { a: [][]float64{ {0, 0}, {0, 0}, }, b: [][]float64{ {3}, {2}, }, ans: nil, shouldErr: true, }, { a: [][]float64{ {0, 0}, {0, 0}, {0, 0}, }, b: [][]float64{ {3}, {2}, {1}, }, ans: nil, shouldErr: true, }, { a: [][]float64{ {0, 0, 0}, {0, 0, 0}, }, b: [][]float64{ {3}, {2}, }, ans: nil, shouldErr: true, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) var ans *Dense if test.ans != nil { ans = NewDense(flatten(test.ans)) } var x Dense err := x.Solve(a, b) if err != nil { if !test.shouldErr { t.Errorf("Unexpected solve error: %s", err) } continue } if err == nil && test.shouldErr { t.Errorf("Did not error during solve.") continue } if !EqualApprox(&x, ans, 1e-12) { t.Errorf("Solve answer mismatch. Want %v, got %v", ans, x) } } // Random Cases. for _, test := range []struct { m, n, bc int }{ {5, 5, 1}, {5, 10, 1}, {10, 5, 1}, {5, 5, 7}, {5, 10, 7}, {10, 5, 7}, {5, 5, 12}, {5, 10, 12}, {10, 5, 12}, } { m := test.m n := test.n bc := test.bc a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m b := NewDense(br, bc, nil) for i := 0; i < br; i++ { for j := 0; j < bc; j++ { b.Set(i, j, rnd.Float64()) } } var x Dense err := x.Solve(a, b) if err != nil { t.Errorf("unexpected error from dense solve: %v", err) } // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b var tmp, lhs, rhs Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } // Use testTwoInput. method := func(receiver, a, b Matrix) { type Solver interface { Solve(a, b Matrix) error } rd := receiver.(Solver) _ = rd.Solve(a, b) } denseComparison := func(receiver, a, b *Dense) { _ = receiver.Solve(a, b) } testTwoInput(t, "Solve", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSolve, 1e-7) } func TestSolveVec(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { m, n int }{ {5, 5}, {5, 10}, {10, 5}, {5, 5}, {5, 10}, {10, 5}, {5, 5}, {5, 10}, {10, 5}, } { m := test.m n := test.n a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m b := NewVecDense(br, nil) for i := 0; i < br; i++ { b.SetVec(i, rnd.Float64()) } var x VecDense err := x.SolveVec(a, b) if err != nil { t.Errorf("unexpected error from dense vector solve: %v", err) } // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b var tmp, lhs, rhs Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } // Use testTwoInput method := func(receiver, a, b Matrix) { type SolveVecer interface { SolveVec(a Matrix, b Vector) error } rd := receiver.(SolveVecer) _ = rd.SolveVec(a, b.(Vector)) } denseComparison := func(receiver, a, b *Dense) { _ = receiver.Solve(a, b) } testTwoInput(t, "SolveVec", &VecDense{}, method, denseComparison, legalTypesMatrixVector, legalSizeSolve, 1e-12) } golang-gonum-v1-gonum-0.14.0/mat/svd.go000066400000000000000000000271121450372207100175450ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) const badRcond = "mat: invalid rcond value" // SVD is a type for creating and using the Singular Value Decomposition // of a matrix. type SVD struct { kind SVDKind s []float64 u blas64.General vt blas64.General } // SVDKind specifies the treatment of singular vectors during an SVD // factorization. type SVDKind int const ( // SVDNone specifies that no singular vectors should be computed during // the decomposition. SVDNone SVDKind = 0 // SVDThinU specifies the thin decomposition for U should be computed. SVDThinU SVDKind = 1 << (iota - 1) // SVDFullU specifies the full decomposition for U should be computed. SVDFullU // SVDThinV specifies the thin decomposition for V should be computed. SVDThinV // SVDFullV specifies the full decomposition for V should be computed. SVDFullV // SVDThin is a convenience value for computing both thin vectors. SVDThin SVDKind = SVDThinU | SVDThinV // SVDFull is a convenience value for computing both full vectors. SVDFull SVDKind = SVDFullU | SVDFullV ) // succFact returns whether the receiver contains a successful factorization. func (svd *SVD) succFact() bool { return len(svd.s) != 0 } // Factorize computes the singular value decomposition (SVD) of the input matrix A. // The singular values of A are computed in all cases, while the singular // vectors are optionally computed depending on the input kind. // // The full singular value decomposition (kind == SVDFull) is a factorization // of an m×n matrix A of the form // // A = U * Σ * Vᵀ // // where Σ is an m×n diagonal matrix, U is an m×m orthogonal matrix, and V is an // n×n orthogonal matrix. The diagonal elements of Σ are the singular values of A. // The first min(m,n) columns of U and V are, respectively, the left and right // singular vectors of A. // // Significant storage space can be saved by using the thin representation of // the SVD (kind == SVDThin) instead of the full SVD, especially if // m >> n or m << n. The thin SVD finds // // A = U~ * Σ * V~ᵀ // // where U~ is of size m×min(m,n), Σ is a diagonal matrix of size min(m,n)×min(m,n) // and V~ is of size n×min(m,n). // // Factorize returns whether the decomposition succeeded. If the decomposition // failed, routines that require a successful factorization will panic. func (svd *SVD) Factorize(a Matrix, kind SVDKind) (ok bool) { // kill previous factorization svd.s = svd.s[:0] svd.kind = kind m, n := a.Dims() var jobU, jobVT lapack.SVDJob // TODO(btracey): This code should be modified to have the smaller // matrix written in-place into aCopy when the lapack/native/dgesvd // implementation is complete. switch { case kind&SVDFullU != 0: jobU = lapack.SVDAll svd.u = blas64.General{ Rows: m, Cols: m, Stride: m, Data: use(svd.u.Data, m*m), } case kind&SVDThinU != 0: jobU = lapack.SVDStore svd.u = blas64.General{ Rows: m, Cols: min(m, n), Stride: min(m, n), Data: use(svd.u.Data, m*min(m, n)), } default: jobU = lapack.SVDNone } switch { case kind&SVDFullV != 0: svd.vt = blas64.General{ Rows: n, Cols: n, Stride: n, Data: use(svd.vt.Data, n*n), } jobVT = lapack.SVDAll case kind&SVDThinV != 0: svd.vt = blas64.General{ Rows: min(m, n), Cols: n, Stride: n, Data: use(svd.vt.Data, min(m, n)*n), } jobVT = lapack.SVDStore default: jobVT = lapack.SVDNone } // A is destroyed on call, so copy the matrix. aCopy := DenseCopyOf(a) svd.kind = kind svd.s = use(svd.s, min(m, n)) work := []float64{0} lapack64.Gesvd(jobU, jobVT, aCopy.mat, svd.u, svd.vt, svd.s, work, -1) work = getFloat64s(int(work[0]), false) ok = lapack64.Gesvd(jobU, jobVT, aCopy.mat, svd.u, svd.vt, svd.s, work, len(work)) putFloat64s(work) if !ok { svd.kind = 0 } return ok } // Kind returns the SVDKind of the decomposition. If no decomposition has been // computed, Kind returns -1. func (svd *SVD) Kind() SVDKind { if !svd.succFact() { return -1 } return svd.kind } // Rank returns the rank of A based on the count of singular values greater than // rcond scaled by the largest singular value. // Rank will panic if the receiver does not contain a successful factorization or // rcond is negative. func (svd *SVD) Rank(rcond float64) int { if rcond < 0 { panic(badRcond) } if !svd.succFact() { panic(badFact) } s0 := svd.s[0] for i, v := range svd.s { if v <= rcond*s0 { return i } } return len(svd.s) } // Cond returns the 2-norm condition number for the factorized matrix. Cond will // panic if the receiver does not contain a successful factorization. func (svd *SVD) Cond() float64 { if !svd.succFact() { panic(badFact) } return svd.s[0] / svd.s[len(svd.s)-1] } // Values returns the singular values of the factorized matrix in descending order. // // If the input slice is non-nil, the values will be stored in-place into // the slice. In this case, the slice must have length min(m,n), and Values will // panic with ErrSliceLengthMismatch otherwise. If the input slice is nil, a new // slice of the appropriate length will be allocated and returned. // // Values will panic if the receiver does not contain a successful factorization. func (svd *SVD) Values(s []float64) []float64 { if !svd.succFact() { panic(badFact) } if s == nil { s = make([]float64, len(svd.s)) } if len(s) != len(svd.s) { panic(ErrSliceLengthMismatch) } copy(s, svd.s) return s } // UTo extracts the matrix U from the singular value decomposition. The first // min(m,n) columns are the left singular vectors and correspond to the singular // values as returned from SVD.Values. // // If dst is empty, UTo will resize dst to be m×m if the full U was computed // and size m×min(m,n) if the thin U was computed. When dst is non-empty, then // UTo will panic if dst is not the appropriate size. UTo will also panic if // the receiver does not contain a successful factorization, or if U was // not computed during factorization. func (svd *SVD) UTo(dst *Dense) { if !svd.succFact() { panic(badFact) } kind := svd.kind if kind&SVDThinU == 0 && kind&SVDFullU == 0 { panic("svd: u not computed during factorization") } r := svd.u.Rows c := svd.u.Cols if dst.IsEmpty() { dst.ReuseAs(r, c) } else { r2, c2 := dst.Dims() if r != r2 || c != c2 { panic(ErrShape) } } tmp := &Dense{ mat: svd.u, capRows: r, capCols: c, } dst.Copy(tmp) } // VTo extracts the matrix V from the singular value decomposition. The first // min(m,n) columns are the right singular vectors and correspond to the singular // values as returned from SVD.Values. // // If dst is empty, VTo will resize dst to be n×n if the full V was computed // and size n×min(m,n) if the thin V was computed. When dst is non-empty, then // VTo will panic if dst is not the appropriate size. VTo will also panic if // the receiver does not contain a successful factorization, or if V was // not computed during factorization. func (svd *SVD) VTo(dst *Dense) { if !svd.succFact() { panic(badFact) } kind := svd.kind if kind&SVDThinV == 0 && kind&SVDFullV == 0 { panic("svd: v not computed during factorization") } r := svd.vt.Rows c := svd.vt.Cols if dst.IsEmpty() { dst.ReuseAs(c, r) } else { r2, c2 := dst.Dims() if c != r2 || r != c2 { panic(ErrShape) } } tmp := &Dense{ mat: svd.vt, capRows: r, capCols: c, } dst.Copy(tmp.T()) } // SolveTo calculates the minimum-norm solution to a linear least squares problem // // minimize over n-element vectors x: |b - A*x|_2 and |x|_2 // // where b is a given m-element vector, using the SVD of m×n matrix A stored in // the receiver. A may be rank-deficient, that is, the given effective rank can be // // rank ≤ min(m,n) // // The rank can be computed using SVD.Rank. // // Several right-hand side vectors b and solution vectors x can be handled in a // single call. Vectors b are stored in the columns of the m×k matrix B and the // resulting vectors x will be stored in the columns of dst. dst must be either // empty or have the size equal to n×k. // // The decomposition must have been factorized computing both the U and V // singular vectors. // // SolveTo returns the residuals calculated from the complete SVD. For this // value to be valid the factorization must have been performed with at least // SVDFullU. func (svd *SVD) SolveTo(dst *Dense, b Matrix, rank int) []float64 { if !svd.succFact() { panic(badFact) } if rank < 1 || len(svd.s) < rank { panic("svd: rank out of range") } kind := svd.kind if kind&SVDThinU == 0 && kind&SVDFullU == 0 { panic("svd: u not computed during factorization") } if kind&SVDThinV == 0 && kind&SVDFullV == 0 { panic("svd: v not computed during factorization") } u := Dense{ mat: svd.u, capRows: svd.u.Rows, capCols: svd.u.Cols, } vt := Dense{ mat: svd.vt, capRows: svd.vt.Rows, capCols: svd.vt.Cols, } s := svd.s[:rank] _, bc := b.Dims() c := getDenseWorkspace(svd.u.Cols, bc, false) defer putDenseWorkspace(c) c.Mul(u.T(), b) y := getDenseWorkspace(rank, bc, false) defer putDenseWorkspace(y) y.DivElem(c.slice(0, rank, 0, bc), repVector{vec: s, cols: bc}) dst.Mul(vt.slice(0, rank, 0, svd.vt.Cols).T(), y) res := make([]float64, bc) if rank < svd.u.Cols { c = c.slice(len(s), svd.u.Cols, 0, bc) for j := range res { col := c.ColView(j) res[j] = Dot(col, col) } } return res } type repVector struct { vec []float64 cols int } func (m repVector) Dims() (r, c int) { return len(m.vec), m.cols } func (m repVector) At(i, j int) float64 { if i < 0 || len(m.vec) <= i || j < 0 || m.cols <= j { panic(ErrIndexOutOfRange.string) // Panic with string to prevent mat.Error recovery. } return m.vec[i] } func (m repVector) T() Matrix { return Transpose{m} } // SolveVecTo calculates the minimum-norm solution to a linear least squares problem // // minimize over n-element vectors x: |b - A*x|_2 and |x|_2 // // where b is a given m-element vector, using the SVD of m×n matrix A stored in // the receiver. A may be rank-deficient, that is, the given effective rank can be // // rank ≤ min(m,n) // // The rank can be computed using SVD.Rank. // // The resulting vector x will be stored in dst. dst must be either empty or // have length equal to n. // // The decomposition must have been factorized computing both the U and V // singular vectors. // // SolveVecTo returns the residuals calculated from the complete SVD. For this // value to be valid the factorization must have been performed with at least // SVDFullU. func (svd *SVD) SolveVecTo(dst *VecDense, b Vector, rank int) float64 { if !svd.succFact() { panic(badFact) } if rank < 1 || len(svd.s) < rank { panic("svd: rank out of range") } kind := svd.kind if kind&SVDThinU == 0 && kind&SVDFullU == 0 { panic("svd: u not computed during factorization") } if kind&SVDThinV == 0 && kind&SVDFullV == 0 { panic("svd: v not computed during factorization") } u := Dense{ mat: svd.u, capRows: svd.u.Rows, capCols: svd.u.Cols, } vt := Dense{ mat: svd.vt, capRows: svd.vt.Rows, capCols: svd.vt.Cols, } s := svd.s[:rank] c := getVecDenseWorkspace(svd.u.Cols, false) defer putVecDenseWorkspace(c) c.MulVec(u.T(), b) y := getVecDenseWorkspace(rank, false) defer putVecDenseWorkspace(y) y.DivElemVec(c.sliceVec(0, rank), NewVecDense(rank, s)) dst.MulVec(vt.slice(0, rank, 0, svd.vt.Cols).T(), y) var res float64 if rank < c.Len() { c = c.sliceVec(rank, c.Len()) res = Dot(c, c) } return res } golang-gonum-v1-gonum-0.14.0/mat/svd_example_test.go000066400000000000000000000061311450372207100223150ustar00rootroot00000000000000// Copyright ©2020 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "log" "gonum.org/v1/gonum/mat" ) func ExampleSVD_SolveTo() { // The system described by A is rank deficient. a := mat.NewDense(5, 3, []float64{ -1.7854591879711257, -0.42687285925779594, -0.12730256811265162, -0.5728984211439724, -0.10093393134001777, -0.1181901192353067, 1.2484316018707418, 0.5646683943038734, -0.48229492403243485, 0.10174927665169475, -0.5805410929482445, 1.3054473231942054, -1.134174808195733, -0.4732430202414438, 0.3528489486370508, }) // Perform an SVD retaining all singular vectors. var svd mat.SVD ok := svd.Factorize(a, mat.SVDFull) if !ok { log.Fatal("failed to factorize A") } // Determine the rank of the A matrix with a near zero condition threshold. const rcond = 1e-15 rank := svd.Rank(rcond) if rank == 0 { log.Fatal("zero rank system") } b := mat.NewDense(5, 2, []float64{ -2.318, -4.35, -0.715, 1.451, 1.836, -0.119, -0.357, 3.094, -1.636, 0.021, }) // Find a least-squares solution using the determined parts of the system. var x mat.Dense svd.SolveTo(&x, b, rank) fmt.Printf("singular values = %v\nrank = %d\nx = %.15f", format(svd.Values(nil), 4, rcond), rank, mat.Formatted(&x, mat.Prefix(" "))) // Output: // singular values = [2.685 1.526 <1e-15] // rank = 2 // x = ⎡ 1.212064313552347 1.507467451093930⎤ // ⎢ 0.415400738264774 -0.624498607705372⎥ // ⎣-0.183184442255280 2.221334193689124⎦ } func ExampleSVD_SolveVecTo() { // The system described by A is rank deficient. a := mat.NewDense(5, 3, []float64{ -1.7854591879711257, -0.42687285925779594, -0.12730256811265162, -0.5728984211439724, -0.10093393134001777, -0.1181901192353067, 1.2484316018707418, 0.5646683943038734, -0.48229492403243485, 0.10174927665169475, -0.5805410929482445, 1.3054473231942054, -1.134174808195733, -0.4732430202414438, 0.3528489486370508, }) // Perform an SVD retaining all singular vectors. var svd mat.SVD ok := svd.Factorize(a, mat.SVDFull) if !ok { log.Fatal("failed to factorize A") } // Determine the rank of the A matrix with a near zero condition threshold. const rcond = 1e-15 rank := svd.Rank(rcond) if rank == 0 { log.Fatal("zero rank system") } b := mat.NewVecDense(5, []float64{-2.318, -0.715, 1.836, -0.357, -1.636}) // Find a least-squares solution using the determined parts of the system. var x mat.VecDense svd.SolveVecTo(&x, b, rank) fmt.Printf("singular values = %v\nrank = %d\nx = %.15f", format(svd.Values(nil), 4, rcond), rank, mat.Formatted(&x, mat.Prefix(" "))) // Output: // singular values = [2.685 1.526 <1e-15] // rank = 2 // x = ⎡ 1.212064313552347⎤ // ⎢ 0.415400738264774⎥ // ⎣-0.183184442255280⎦ } func format(vals []float64, prec int, eps float64) []string { s := make([]string, len(vals)) for i, v := range vals { if v < eps { s[i] = fmt.Sprintf("<%.*g", prec, eps) continue } s[i] = fmt.Sprintf("%.*g", prec, v) } return s } golang-gonum-v1-gonum-0.14.0/mat/svd_test.go000066400000000000000000000366151450372207100206140ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) func TestSVD(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) // Hand coded tests for _, test := range []struct { a *Dense u *Dense v *Dense s []float64 }{ { a: NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0}), u: NewDense(4, 2, []float64{ -0.8174155604703632, -0.5760484367663209, -0.5760484367663209, 0.8174155604703633, 0, 0, 0, 0, }), v: NewDense(2, 2, []float64{ -0.4045535848337571, -0.9145142956773044, -0.9145142956773044, 0.4045535848337571, }), s: []float64{5.464985704219041, 0.365966190626258}, }, { // Issue #5. a: NewDense(3, 11, []float64{ 1, 1, 0, 1, 0, 0, 0, 0, 0, 11, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 12, 2, 1, 1, 0, 0, 0, 0, 0, 0, 1, 13, 3, }), u: NewDense(3, 3, []float64{ -0.5224167862273765, 0.7864430360363114, 0.3295270133658976, -0.5739526766688285, -0.03852203026050301, -0.8179818935216693, -0.6306021141833781, -0.6164603833618163, 0.4715056408282468, }), v: NewDense(11, 3, []float64{ -0.08123293141915189, 0.08528085505260324, -0.013165501690885152, -0.05423546426886932, 0.1102707844980355, 0.622210623111631, 0, 0, 0, -0.0245733326078166, 0.510179651760153, 0.25596360803140994, 0, 0, 0, 0, 0, 0, -0.026997467150282436, -0.024989929445430496, -0.6353761248025164, 0, 0, 0, -0.029662131661052707, -0.3999088672621176, 0.3662470150802212, -0.9798839760830571, 0.11328174160898856, -0.047702613241813366, -0.16755466189153964, -0.7395268089170608, 0.08395240366704032, }), s: []float64{21.259500881097434, 1.5415021616856566, 1.2873979074613628}, }, } { var svd SVD ok := svd.Factorize(test.a, SVDThin) if !ok { t.Errorf("SVD failed") } s, u, v := extractSVD(&svd) if !floats.EqualApprox(s, test.s, 1e-10) { t.Errorf("Singular value mismatch. Got %v, want %v.", s, test.s) } if !EqualApprox(u, test.u, 1e-10) { t.Errorf("U mismatch.\nGot:\n%v\nWant:\n%v", Formatted(u), Formatted(test.u)) } if !EqualApprox(v, test.v, 1e-10) { t.Errorf("V mismatch.\nGot:\n%v\nWant:\n%v", Formatted(v), Formatted(test.v)) } m, n := test.a.Dims() sigma := NewDense(min(m, n), min(m, n), nil) for i := 0; i < min(m, n); i++ { sigma.Set(i, i, s[i]) } var ans Dense ans.Product(u, sigma, v.T()) if !EqualApprox(test.a, &ans, 1e-10) { t.Errorf("A reconstruction mismatch.\nGot:\n%v\nWant:\n%v\n", Formatted(&ans), Formatted(test.a)) } for _, kind := range []SVDKind{ SVDThinU, SVDFullU, SVDThinV, SVDFullV, } { var svd SVD svd.Factorize(test.a, kind) if kind&SVDThinU == 0 && kind&SVDFullU == 0 { panicked, message := panics(func() { var dst Dense svd.UTo(&dst) }) if !panicked { t.Error("expected panic with no U matrix requested") continue } want := "svd: u not computed during factorization" if message != want { t.Errorf("unexpected message: got:%q want:%q", message, want) } } if kind&SVDThinV == 0 && kind&SVDFullV == 0 { panicked, message := panics(func() { var dst Dense svd.VTo(&dst) }) if !panicked { t.Error("expected panic with no V matrix requested") continue } want := "svd: v not computed during factorization" if message != want { t.Errorf("unexpected message: got:%q want:%q", message, want) } } } } for _, test := range []struct { m, n int }{ {5, 5}, {5, 3}, {3, 5}, {150, 150}, {200, 150}, {150, 200}, } { m := test.m n := test.n for trial := 0; trial < 10; trial++ { a := NewDense(m, n, nil) for i := range a.mat.Data { a.mat.Data[i] = rnd.NormFloat64() } aCopy := DenseCopyOf(a) // Test Full decomposition. var svd SVD ok := svd.Factorize(a, SVDFull) if !ok { t.Errorf("SVD factorization failed") } if !Equal(a, aCopy) { t.Errorf("A changed during call to SVD with full") } s, u, v := extractSVD(&svd) sigma := NewDense(m, n, nil) for i := 0; i < min(m, n); i++ { sigma.Set(i, i, s[i]) } var ansFull Dense ansFull.Product(u, sigma, v.T()) if !EqualApprox(&ansFull, a, 1e-8) { t.Errorf("Answer mismatch when SVDFull") } // Test Thin decomposition. ok = svd.Factorize(a, SVDThin) if !ok { t.Errorf("SVD factorization failed") } if !Equal(a, aCopy) { t.Errorf("A changed during call to SVD with Thin") } sThin, u, v := extractSVD(&svd) if !floats.EqualApprox(s, sThin, 1e-8) { t.Errorf("Singular value mismatch between Full and Thin decomposition") } sigma = NewDense(min(m, n), min(m, n), nil) for i := 0; i < min(m, n); i++ { sigma.Set(i, i, sThin[i]) } ansFull.Reset() ansFull.Product(u, sigma, v.T()) if !EqualApprox(&ansFull, a, 1e-8) { t.Errorf("Answer mismatch when SVDFull") } // Test None decomposition. ok = svd.Factorize(a, SVDNone) if !ok { t.Errorf("SVD factorization failed") } if !Equal(a, aCopy) { t.Errorf("A changed during call to SVD with none") } sNone := make([]float64, min(m, n)) svd.Values(sNone) if !floats.EqualApprox(s, sNone, 1e-8) { t.Errorf("Singular value mismatch between Full and None decomposition") } } } } func extractSVD(svd *SVD) (s []float64, u, v *Dense) { u = &Dense{} svd.UTo(u) v = &Dense{} svd.VTo(v) return svd.Values(nil), u, v } func TestSVDSolveTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) // Hand-coded cases. for i, test := range []struct { a []float64 m, n int b []float64 bc int rcond float64 want []float64 wm, wn int }{ { a: []float64{6}, m: 1, n: 1, b: []float64{3}, bc: 1, want: []float64{0.5}, wm: 1, wn: 1, }, { a: []float64{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }, m: 3, n: 3, b: []float64{ 3, 2, 1, }, bc: 1, want: []float64{ 3, 2, 1, }, wm: 3, wn: 1, }, { a: []float64{ 0.8147, 0.9134, 0.5528, 0.9058, 0.6324, 0.8723, 0.1270, 0.0975, 0.7612, }, m: 3, n: 3, b: []float64{ 0.278, 0.547, 0.958, }, bc: 1, want: []float64{ -0.932687281002860, 0.303963920182067, 1.375216503507109, }, wm: 3, wn: 1, }, { a: []float64{ 0.8147, 0.9134, 0.5528, 0.9058, 0.6324, 0.8723, }, m: 2, n: 3, b: []float64{ 0.278, 0.547, }, bc: 1, want: []float64{ 0.25919787248965376, -0.25560256266441034, 0.5432324059702451, }, wm: 3, wn: 1, }, { a: []float64{ 0.8147, 0.9134, 0.9, 0.9058, 0.6324, 0.9, 0.1270, 0.0975, 0.1, 1.6, 2.8, -3.5, }, m: 4, n: 3, b: []float64{ 0.278, 0.547, -0.958, 1.452, }, bc: 1, want: []float64{ 0.820970340787782, -0.218604626527306, -0.212938815234215, }, wm: 3, wn: 1, }, { a: []float64{ 0.8147, 0.9134, 0.231, -1.65, 0.9058, 0.6324, 0.9, 0.72, 0.1270, 0.0975, 0.1, 1.723, 1.6, 2.8, -3.5, 0.987, 7.231, 9.154, 1.823, 0.9, }, m: 5, n: 4, b: []float64{ 0.278, 8.635, 0.547, 9.125, -0.958, -0.762, 1.452, 1.444, 1.999, -7.234, }, bc: 2, want: []float64{ 1.863006789511373, 44.467887791812750, -1.127270935407224, -34.073794226035126, -0.527926457947330, -8.032133759788573, -0.248621916204897, -2.366366415805275, }, wm: 4, wn: 2, }, { // Test rank-deficient case compared with numpy. // >>> import numpy as np // >>> b = np.array([[-2.3181340317357653], // ... [-0.7146777651358073], // ... [1.8361340927945298], // ... [-0.35699930593018775], // ... [-1.6359508076249094]]) // >>> A = np.array([[-1.7854591879711257, -0.42687285925779594, -0.12730256811265162], // ... [-0.5728984211439724, -0.10093393134001777, -0.1181901192353067], // ... [1.2484316018707418, 0.5646683943038734, -0.48229492403243485], // ... [0.10174927665169475, -0.5805410929482445, 1.3054473231942054], // ... [-1.134174808195733, -0.4732430202414438, 0.3528489486370508]]) // >>> np.linalg.lstsq(A, b, rcond=None) // (array([[ 1.21208422], // [ 0.41541503], // [-0.18320349]]), array([], dtype=float64), 2, array([2.68451480e+00, 1.52593185e+00, 6.82840229e-17])) a: []float64{ -1.7854591879711257, -0.42687285925779594, -0.12730256811265162, -0.5728984211439724, -0.10093393134001777, -0.1181901192353067, 1.2484316018707418, 0.5646683943038734, -0.48229492403243485, 0.10174927665169475, -0.5805410929482445, 1.3054473231942054, -1.134174808195733, -0.4732430202414438, 0.3528489486370508, }, m: 5, n: 3, b: []float64{ -2.3181340317357653, -0.7146777651358073, 1.8361340927945298, -0.35699930593018775, -1.6359508076249094, }, bc: 1, rcond: 1e-15, want: []float64{ 1.2120842180372118, 0.4154150318658529, -0.1832034870198265, }, wm: 3, wn: 1, }, { a: []float64{ 0, 0, 0, 0, }, m: 2, n: 2, b: []float64{ 3, 2, }, bc: 1, }, { a: []float64{ 0, 0, 0, 0, 0, 0, }, m: 3, n: 2, b: []float64{ 3, 2, 1, }, bc: 1, }, { a: []float64{ 0, 0, 0, 0, 0, 0, }, m: 2, n: 3, b: []float64{ 3, 2, }, bc: 1, }, } { a := NewDense(test.m, test.n, test.a) b := NewDense(test.m, test.bc, test.b) var want *Dense if test.want != nil { want = NewDense(test.wm, test.wn, test.want) } var svd SVD ok := svd.Factorize(a, SVDFull) if !ok { t.Errorf("unexpected factorization failure for test %d", i) continue } var x Dense rank := svd.Rank(test.rcond) if rank == 0 { continue } svd.SolveTo(&x, b, rank) if !EqualApprox(&x, want, 1e-12) { t.Errorf("Solve answer mismatch. Want %v, got %v", want, x) } } // Random Cases. for i, test := range []struct { m, n, bc int rcond float64 }{ {m: 5, n: 5, bc: 1}, {m: 5, n: 10, bc: 1}, {m: 10, n: 5, bc: 1}, {m: 5, n: 5, bc: 7}, {m: 5, n: 10, bc: 7}, {m: 10, n: 5, bc: 7}, {m: 5, n: 5, bc: 12}, {m: 5, n: 10, bc: 12}, {m: 10, n: 5, bc: 12}, } { m := test.m n := test.n bc := test.bc a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m b := NewDense(br, bc, nil) for i := 0; i < br; i++ { for j := 0; j < bc; j++ { b.Set(i, j, rnd.Float64()) } } var svd SVD ok := svd.Factorize(a, SVDFull) if !ok { t.Errorf("unexpected factorization failure for test %d", i) continue } var x Dense rank := svd.Rank(test.rcond) if rank == 0 { continue } svd.SolveTo(&x, b, rank) // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b var tmp, lhs, rhs Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } } func TestSVDSolveVecTo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) // Hand-coded cases. for i, test := range []struct { a []float64 m, n int b []float64 rcond float64 want []float64 }{ { a: []float64{6}, m: 1, n: 1, b: []float64{3}, want: []float64{0.5}, }, { a: []float64{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }, m: 3, n: 3, b: []float64{3, 2, 1}, want: []float64{3, 2, 1}, }, { a: []float64{ 0.8147, 0.9134, 0.5528, 0.9058, 0.6324, 0.8723, 0.1270, 0.0975, 0.7612, }, m: 3, n: 3, b: []float64{0.278, 0.547, 0.958}, want: []float64{-0.932687281002860, 0.303963920182067, 1.375216503507109}, }, { a: []float64{ 0.8147, 0.9134, 0.5528, 0.9058, 0.6324, 0.8723, }, m: 2, n: 3, b: []float64{0.278, 0.547}, want: []float64{0.25919787248965376, -0.25560256266441034, 0.5432324059702451}, }, { a: []float64{ 0.8147, 0.9134, 0.9, 0.9058, 0.6324, 0.9, 0.1270, 0.0975, 0.1, 1.6, 2.8, -3.5, }, m: 4, n: 3, b: []float64{0.278, 0.547, -0.958, 1.452}, want: []float64{0.820970340787782, -0.218604626527306, -0.212938815234215}, }, { // Test rank-deficient case compared with numpy. // >>> import numpy as np // >>> b = np.array([[-2.3181340317357653], // ... [-0.7146777651358073], // ... [1.8361340927945298], // ... [-0.35699930593018775], // ... [-1.6359508076249094]]) // >>> A = np.array([[-1.7854591879711257, -0.42687285925779594, -0.12730256811265162], // ... [-0.5728984211439724, -0.10093393134001777, -0.1181901192353067], // ... [1.2484316018707418, 0.5646683943038734, -0.48229492403243485], // ... [0.10174927665169475, -0.5805410929482445, 1.3054473231942054], // ... [-1.134174808195733, -0.4732430202414438, 0.3528489486370508]]) // >>> np.linalg.lstsq(A, b, rcond=None) // (array([[ 1.21208422], // [ 0.41541503], // [-0.18320349]]), array([], dtype=float64), 2, array([2.68451480e+00, 1.52593185e+00, 6.82840229e-17])) a: []float64{ -1.7854591879711257, -0.42687285925779594, -0.12730256811265162, -0.5728984211439724, -0.10093393134001777, -0.1181901192353067, 1.2484316018707418, 0.5646683943038734, -0.48229492403243485, 0.10174927665169475, -0.5805410929482445, 1.3054473231942054, -1.134174808195733, -0.4732430202414438, 0.3528489486370508, }, m: 5, n: 3, b: []float64{-2.3181340317357653, -0.7146777651358073, 1.8361340927945298, -0.35699930593018775, -1.6359508076249094}, rcond: 1e-15, want: []float64{1.2120842180372118, 0.4154150318658529, -0.1832034870198265}, }, { a: []float64{ 0, 0, 0, 0, }, m: 2, n: 2, b: []float64{3, 2}, }, { a: []float64{ 0, 0, 0, 0, 0, 0, }, m: 3, n: 2, b: []float64{3, 2, 1}, }, { a: []float64{ 0, 0, 0, 0, 0, 0, }, m: 2, n: 3, b: []float64{3, 2}, }, } { a := NewDense(test.m, test.n, test.a) b := NewVecDense(len(test.b), test.b) var want *VecDense if test.want != nil { want = NewVecDense(len(test.want), test.want) } var svd SVD ok := svd.Factorize(a, SVDFull) if !ok { t.Errorf("unexpected factorization failure for test %d", i) continue } var x VecDense rank := svd.Rank(test.rcond) if rank == 0 { continue } svd.SolveVecTo(&x, b, rank) if !EqualApprox(&x, want, 1e-12) { t.Errorf("Solve answer mismatch. Want %v, got %v", want, x) } } // Random Cases. for i, test := range []struct { m, n int rcond float64 }{ {m: 5, n: 5}, {m: 5, n: 10}, {m: 10, n: 5}, {m: 5, n: 5}, {m: 5, n: 10}, {m: 10, n: 5}, {m: 5, n: 5}, {m: 5, n: 10}, {m: 10, n: 5}, } { m := test.m n := test.n a := NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, rnd.Float64()) } } br := m b := NewVecDense(br, nil) for i := 0; i < br; i++ { b.SetVec(i, rnd.Float64()) } var svd SVD ok := svd.Factorize(a, SVDFull) if !ok { t.Errorf("unexpected factorization failure for test %d", i) continue } var x VecDense rank := svd.Rank(test.rcond) if rank == 0 { continue } svd.SolveVecTo(&x, b, rank) // Test that the normal equations hold. // Aᵀ * A * x = Aᵀ * b var tmp, lhs, rhs Dense tmp.Mul(a.T(), a) lhs.Mul(&tmp, &x) rhs.Mul(a.T(), b) if !EqualApprox(&lhs, &rhs, 1e-10) { t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) } } } golang-gonum-v1-gonum-0.14.0/mat/symband.go000066400000000000000000000211371450372207100204070ustar00rootroot00000000000000// 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 mat import ( "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) var ( symBandDense *SymBandDense _ Matrix = symBandDense _ allMatrix = symBandDense _ denseMatrix = symBandDense _ Symmetric = symBandDense _ Banded = symBandDense _ SymBanded = symBandDense _ RawSymBander = symBandDense _ MutableSymBanded = symBandDense _ NonZeroDoer = symBandDense _ RowNonZeroDoer = symBandDense _ ColNonZeroDoer = symBandDense ) // SymBandDense represents a symmetric band matrix in dense storage format. type SymBandDense struct { mat blas64.SymmetricBand } // SymBanded is a symmetric band matrix interface type. type SymBanded interface { Banded // SymmetricDim returns the number of rows/columns in the matrix. SymmetricDim() int // SymBand returns the number of rows/columns in the matrix, and the size of // the bandwidth. SymBand() (n, k int) } // MutableSymBanded is a symmetric band matrix interface type that allows elements // to be altered. type MutableSymBanded interface { SymBanded SetSymBand(i, j int, v float64) } // A RawSymBander can return a blas64.SymmetricBand representation of the receiver. // Changes to the blas64.SymmetricBand.Data slice will be reflected in the original // matrix, changes to the N, K, Stride and Uplo fields will not. type RawSymBander interface { RawSymBand() blas64.SymmetricBand } // NewSymBandDense creates a new SymBand matrix with n rows and columns. If data == nil, // a new slice is allocated for the backing slice. If len(data) == n*(k+1), // data is used as the backing slice, and changes to the elements of the returned // SymBandDense will be reflected in data. If neither of these is true, NewSymBandDense // will panic. k must be at least zero and less than n, otherwise NewSymBandDense will panic. // // The data must be arranged in row-major order constructed by removing the zeros // from the rows outside the band and aligning the diagonals. SymBandDense matrices // are stored in the upper triangle. For example, the matrix // // 1 2 3 0 0 0 // 2 4 5 6 0 0 // 3 5 7 8 9 0 // 0 6 8 10 11 12 // 0 0 9 11 13 14 // 0 0 0 12 14 15 // // becomes (* entries are never accessed) // // 1 2 3 // 4 5 6 // 7 8 9 // 10 11 12 // 13 14 * // 15 * * // // which is passed to NewSymBandDense as []float64{1, 2, ..., 15, *, *, *} with k=2. // Only the values in the band portion of the matrix are used. func NewSymBandDense(n, k int, data []float64) *SymBandDense { if n <= 0 || k < 0 { if n == 0 { panic(ErrZeroLength) } panic("mat: negative dimension") } if k+1 > n { panic("mat: band out of range") } bc := k + 1 if data != nil && len(data) != n*bc { panic(ErrShape) } if data == nil { data = make([]float64, n*bc) } return &SymBandDense{ mat: blas64.SymmetricBand{ N: n, K: k, Stride: bc, Uplo: blas.Upper, Data: data, }, } } // Dims returns the number of rows and columns in the matrix. func (s *SymBandDense) Dims() (r, c int) { return s.mat.N, s.mat.N } // SymmetricDim returns the size of the receiver. func (s *SymBandDense) SymmetricDim() int { return s.mat.N } // Bandwidth returns the bandwidths of the matrix. func (s *SymBandDense) Bandwidth() (kl, ku int) { return s.mat.K, s.mat.K } // SymBand returns the number of rows/columns in the matrix, and the size of // the bandwidth. func (s *SymBandDense) SymBand() (n, k int) { return s.mat.N, s.mat.K } // T implements the Matrix interface. Symmetric matrices, by definition, are // equal to their transpose, and this is a no-op. func (s *SymBandDense) T() Matrix { return s } // TBand implements the Banded interface. func (s *SymBandDense) TBand() Banded { return s } // RawSymBand returns the underlying blas64.SymBand used by the receiver. // Changes to elements in the receiver following the call will be reflected // in returned blas64.SymBand. func (s *SymBandDense) RawSymBand() blas64.SymmetricBand { return s.mat } // SetRawSymBand sets the underlying blas64.SymmetricBand used by the receiver. // Changes to elements in the receiver following the call will be reflected // in the input. // // The supplied SymmetricBand must use blas.Upper storage format. func (s *SymBandDense) SetRawSymBand(mat blas64.SymmetricBand) { if mat.Uplo != blas.Upper { panic("mat: blas64.SymmetricBand does not have blas.Upper storage") } s.mat = mat } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (s *SymBandDense) IsEmpty() bool { return s.mat.Stride == 0 } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (s *SymBandDense) Reset() { s.mat.N = 0 s.mat.K = 0 s.mat.Stride = 0 s.mat.Uplo = 0 s.mat.Data = s.mat.Data[:0] } // Zero sets all of the matrix elements to zero. func (s *SymBandDense) Zero() { for i := 0; i < s.mat.N; i++ { u := min(1+s.mat.K, s.mat.N-i) zero(s.mat.Data[i*s.mat.Stride : i*s.mat.Stride+u]) } } // DiagView returns the diagonal as a matrix backed by the original data. func (s *SymBandDense) DiagView() Diagonal { n := s.mat.N return &DiagDense{ mat: blas64.Vector{ N: n, Inc: s.mat.Stride, Data: s.mat.Data[:(n-1)*s.mat.Stride+1], }, } } // DoNonZero calls the function fn for each of the non-zero elements of s. The function fn // takes a row/column index and the element value of s at (i, j). func (s *SymBandDense) DoNonZero(fn func(i, j int, v float64)) { for i := 0; i < s.mat.N; i++ { for j := max(0, i-s.mat.K); j < min(s.mat.N, i+s.mat.K+1); j++ { v := s.at(i, j) if v != 0 { fn(i, j, v) } } } } // DoRowNonZero calls the function fn for each of the non-zero elements of row i of s. The function fn // takes a row/column index and the element value of s at (i, j). func (s *SymBandDense) DoRowNonZero(i int, fn func(i, j int, v float64)) { if i < 0 || s.mat.N <= i { panic(ErrRowAccess) } for j := max(0, i-s.mat.K); j < min(s.mat.N, i+s.mat.K+1); j++ { v := s.at(i, j) if v != 0 { fn(i, j, v) } } } // DoColNonZero calls the function fn for each of the non-zero elements of column j of s. The function fn // takes a row/column index and the element value of s at (i, j). func (s *SymBandDense) DoColNonZero(j int, fn func(i, j int, v float64)) { if j < 0 || s.mat.N <= j { panic(ErrColAccess) } for i := 0; i < s.mat.N; i++ { if i-s.mat.K <= j && j < i+s.mat.K+1 { v := s.at(i, j) if v != 0 { fn(i, j, v) } } } } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the matrix has zero size. func (s *SymBandDense) Norm(norm float64) float64 { if s.IsEmpty() { panic(ErrZeroLength) } lnorm := normLapack(norm, false) if lnorm == lapack.MaxColumnSum || lnorm == lapack.MaxRowSum { work := getFloat64s(s.mat.N, false) defer putFloat64s(work) return lapack64.Lansb(lnorm, s.mat, work) } return lapack64.Lansb(lnorm, s.mat, nil) } // Trace returns the trace of the matrix. // // Trace will panic with ErrZeroLength if the matrix has zero size. func (s *SymBandDense) Trace() float64 { if s.IsEmpty() { panic(ErrZeroLength) } rb := s.RawSymBand() var tr float64 for i := 0; i < rb.N; i++ { tr += rb.Data[i*rb.Stride] } return tr } // MulVecTo computes S⋅x storing the result into dst. func (s *SymBandDense) MulVecTo(dst *VecDense, _ bool, x Vector) { n := s.mat.N if x.Len() != n { panic(ErrShape) } dst.reuseAsNonZeroed(n) xMat, _ := untransposeExtract(x) if xVec, ok := xMat.(*VecDense); ok { if dst != xVec { dst.checkOverlap(xVec.mat) blas64.Sbmv(1, s.mat, xVec.mat, 0, dst.mat) } else { xCopy := getVecDenseWorkspace(n, false) xCopy.CloneFromVec(xVec) blas64.Sbmv(1, s.mat, xCopy.mat, 0, dst.mat) putVecDenseWorkspace(xCopy) } } else { xCopy := getVecDenseWorkspace(n, false) xCopy.CloneFromVec(x) blas64.Sbmv(1, s.mat, xCopy.mat, 0, dst.mat) putVecDenseWorkspace(xCopy) } } golang-gonum-v1-gonum-0.14.0/mat/symband_test.go000066400000000000000000000132411450372207100214430ustar00rootroot00000000000000// 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 mat import ( "reflect" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) func TestNewSymBand(t *testing.T) { t.Parallel() for i, test := range []struct { data []float64 n int k int mat *SymBandDense dense *Dense }{ { data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 15, -1, -1, }, n: 6, k: 2, mat: &SymBandDense{ mat: blas64.SymmetricBand{ N: 6, K: 2, Stride: 3, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 15, -1, -1, }, }, }, dense: NewDense(6, 6, []float64{ 1, 2, 3, 0, 0, 0, 2, 4, 5, 6, 0, 0, 3, 5, 7, 8, 9, 0, 0, 6, 8, 10, 11, 12, 0, 0, 9, 11, 13, 14, 0, 0, 0, 12, 14, 15, }), }, } { band := NewSymBandDense(test.n, test.k, test.data) rows, cols := band.Dims() if rows != test.n { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.n) } if cols != test.n { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.n) } if !reflect.DeepEqual(band, test.mat) { t.Errorf("unexpected value via reflect for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.mat) { t.Errorf("unexpected value via mat.Equal for test %d: got: %v want: %v", i, band, test.mat) } if !Equal(band, test.dense) { t.Errorf("unexpected value via mat.Equal(band, dense) for test %d:\ngot:\n% v\nwant:\n% v", i, Formatted(band), Formatted(test.dense)) } } } func TestSymBandAtSet(t *testing.T) { t.Parallel() // 1 2 3 0 0 0 // 2 4 5 6 0 0 // 3 5 7 8 9 0 // 0 6 8 10 11 12 // 0 0 9 11 13 14 // 0 0 0 12 14 16 band := NewSymBandDense(6, 2, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 16, -1, -1, }) rows, cols := band.Dims() kl, ku := band.Bandwidth() // Explicitly test all indexes. want := bandImplicit{rows, cols, kl, ku, func(i, j int) float64 { if i > j { i, j = j, i } return float64(i*ku + j + 1) }} for i := 0; i < 6; i++ { for j := 0; j < 6; j++ { if band.At(i, j) != want.At(i, j) { t.Errorf("unexpected value for band.At(%d, %d): got:%v want:%v", i, j, band.At(i, j), want.At(i, j)) } } } // Do that same thing via a call to Equal. if !Equal(band, want) { t.Errorf("unexpected value via mat.Equal:\ngot:\n% v\nwant:\n% v", Formatted(band), Formatted(want)) } // Check At out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { band.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { band.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } // Check Set out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { band.SetSymBand(row, 0, 1.2) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { band.SetSymBand(0, col, 1.2) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } for _, st := range []struct { row, col int }{ {row: 0, col: 3}, {row: 0, col: 4}, {row: 0, col: 5}, {row: 1, col: 4}, {row: 1, col: 5}, {row: 2, col: 5}, {row: 3, col: 0}, {row: 4, col: 1}, {row: 5, col: 2}, } { panicked, message := panics(func() { band.SetSymBand(st.row, st.col, 1.2) }) if !panicked || message != ErrBandSet.Error() { t.Errorf("expected panic for %+v %s", st, message) } } for _, st := range []struct { row, col int orig, new float64 }{ {row: 1, col: 2, orig: 5, new: 15}, {row: 2, col: 3, orig: 8, new: 15}, } { if e := band.At(st.row, st.col); e != st.orig { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", st.row, st.col, e, st.orig) } band.SetSymBand(st.row, st.col, st.new) if e := band.At(st.row, st.col); e != st.new { t.Errorf("unexpected value for At(%d, %d) after SetSymBand(%[1]d, %d, %v): got: %v want: %[3]v", st.row, st.col, st.new, e) } } } func TestSymBandDiagView(t *testing.T) { t.Parallel() for cas, test := range []*SymBandDense{ NewSymBandDense(1, 0, []float64{1}), NewSymBandDense(6, 2, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 16, -1, -1, }), } { testDiagView(t, cas, test) } } func TestSymBandDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*SymBandDense{ { mat: blas64.SymmetricBand{ Uplo: blas.Upper, N: 6, K: 2, Stride: 5, Data: []float64{ 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } golang-gonum-v1-gonum-0.14.0/mat/symmetric.go000066400000000000000000000415741450372207100207750ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) var ( symDense *SymDense _ Matrix = symDense _ allMatrix = symDense _ denseMatrix = symDense _ Symmetric = symDense _ RawSymmetricer = symDense _ MutableSymmetric = symDense ) const badSymTriangle = "mat: blas64.Symmetric not upper" // SymDense is a symmetric matrix that uses dense storage. SymDense // matrices are stored in the upper triangle. type SymDense struct { mat blas64.Symmetric cap int } // Symmetric represents a symmetric matrix (where the element at {i, j} equals // the element at {j, i}). Symmetric matrices are always square. type Symmetric interface { Matrix // SymmetricDim returns the number of rows/columns in the matrix. SymmetricDim() int } // A RawSymmetricer can return a view of itself as a BLAS Symmetric matrix. type RawSymmetricer interface { RawSymmetric() blas64.Symmetric } // A MutableSymmetric can set elements of a symmetric matrix. type MutableSymmetric interface { Symmetric SetSym(i, j int, v float64) } // NewSymDense creates a new Symmetric matrix with n rows and columns. If data == nil, // a new slice is allocated for the backing slice. If len(data) == n*n, data is // used as the backing slice, and changes to the elements of the returned SymDense // will be reflected in data. If neither of these is true, NewSymDense will panic. // NewSymDense will panic if n is zero. // // The data must be arranged in row-major order, i.e. the (i*c + j)-th // element in the data slice is the {i, j}-th element in the matrix. // Only the values in the upper triangular portion of the matrix are used. func NewSymDense(n int, data []float64) *SymDense { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic("mat: negative dimension") } if data != nil && n*n != len(data) { panic(ErrShape) } if data == nil { data = make([]float64, n*n) } return &SymDense{ mat: blas64.Symmetric{ N: n, Stride: n, Data: data, Uplo: blas.Upper, }, cap: n, } } // Dims returns the number of rows and columns in the matrix. func (s *SymDense) Dims() (r, c int) { return s.mat.N, s.mat.N } // Caps returns the number of rows and columns in the backing matrix. func (s *SymDense) Caps() (r, c int) { return s.cap, s.cap } // T returns the receiver, the transpose of a symmetric matrix. func (s *SymDense) T() Matrix { return s } // SymmetricDim implements the Symmetric interface and returns the number of rows // and columns in the matrix. func (s *SymDense) SymmetricDim() int { return s.mat.N } // RawSymmetric returns the matrix as a blas64.Symmetric. The returned // value must be stored in upper triangular format. func (s *SymDense) RawSymmetric() blas64.Symmetric { return s.mat } // SetRawSymmetric sets the underlying blas64.Symmetric used by the receiver. // Changes to elements in the receiver following the call will be reflected // in the input. // // The supplied Symmetric must use blas.Upper storage format. func (s *SymDense) SetRawSymmetric(mat blas64.Symmetric) { if mat.Uplo != blas.Upper { panic(badSymTriangle) } s.cap = mat.N s.mat = mat } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (s *SymDense) Reset() { // N and Stride must be zeroed in unison. s.mat.N, s.mat.Stride = 0, 0 s.mat.Data = s.mat.Data[:0] } // ReuseAsSym changes the receiver if it IsEmpty() to be of size n×n. // // ReuseAsSym re-uses the backing data slice if it has sufficient capacity, // otherwise a new slice is allocated. The backing data is zero on return. // // ReuseAsSym panics if the receiver is not empty, and panics if // the input size is less than one. To empty the receiver for re-use, // Reset should be used. func (s *SymDense) ReuseAsSym(n int) { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if !s.IsEmpty() { panic(ErrReuseNonEmpty) } s.reuseAsZeroed(n) } // Zero sets all of the matrix elements to zero. func (s *SymDense) Zero() { for i := 0; i < s.mat.N; i++ { zero(s.mat.Data[i*s.mat.Stride+i : i*s.mat.Stride+s.mat.N]) } } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (s *SymDense) IsEmpty() bool { // It must be the case that m.Dims() returns // zeros in this case. See comment in Reset(). return s.mat.N == 0 } // reuseAsNonZeroed resizes an empty matrix to a n×n matrix, // or checks that a non-empty matrix is n×n. func (s *SymDense) reuseAsNonZeroed(n int) { // reuseAsNonZeroed must be kept in sync with reuseAsZeroed. if n == 0 { panic(ErrZeroLength) } if s.mat.N > s.cap { // Panic as a string, not a mat.Error. panic(badCap) } if s.IsEmpty() { s.mat = blas64.Symmetric{ N: n, Stride: n, Data: use(s.mat.Data, n*n), Uplo: blas.Upper, } s.cap = n return } if s.mat.Uplo != blas.Upper { panic(badSymTriangle) } if s.mat.N != n { panic(ErrShape) } } // reuseAsNonZeroed resizes an empty matrix to a n×n matrix, // or checks that a non-empty matrix is n×n. It then zeros the // elements of the matrix. func (s *SymDense) reuseAsZeroed(n int) { // reuseAsZeroed must be kept in sync with reuseAsNonZeroed. if n == 0 { panic(ErrZeroLength) } if s.mat.N > s.cap { // Panic as a string, not a mat.Error. panic(badCap) } if s.IsEmpty() { s.mat = blas64.Symmetric{ N: n, Stride: n, Data: useZeroed(s.mat.Data, n*n), Uplo: blas.Upper, } s.cap = n return } if s.mat.Uplo != blas.Upper { panic(badSymTriangle) } if s.mat.N != n { panic(ErrShape) } s.Zero() } func (s *SymDense) isolatedWorkspace(a Symmetric) (w *SymDense, restore func()) { n := a.SymmetricDim() if n == 0 { panic(ErrZeroLength) } w = getSymDenseWorkspace(n, false) return w, func() { s.CopySym(w) putSymDenseWorkspace(w) } } // DiagView returns the diagonal as a matrix backed by the original data. func (s *SymDense) DiagView() Diagonal { n := s.mat.N return &DiagDense{ mat: blas64.Vector{ N: n, Inc: s.mat.Stride + 1, Data: s.mat.Data[:(n-1)*s.mat.Stride+n], }, } } func (s *SymDense) AddSym(a, b Symmetric) { n := a.SymmetricDim() if n != b.SymmetricDim() { panic(ErrShape) } s.reuseAsNonZeroed(n) if a, ok := a.(RawSymmetricer); ok { if b, ok := b.(RawSymmetricer); ok { amat, bmat := a.RawSymmetric(), b.RawSymmetric() if s != a { s.checkOverlap(generalFromSymmetric(amat)) } if s != b { s.checkOverlap(generalFromSymmetric(bmat)) } for i := 0; i < n; i++ { btmp := bmat.Data[i*bmat.Stride+i : i*bmat.Stride+n] stmp := s.mat.Data[i*s.mat.Stride+i : i*s.mat.Stride+n] for j, v := range amat.Data[i*amat.Stride+i : i*amat.Stride+n] { stmp[j] = v + btmp[j] } } return } } s.checkOverlapMatrix(a) s.checkOverlapMatrix(b) for i := 0; i < n; i++ { stmp := s.mat.Data[i*s.mat.Stride : i*s.mat.Stride+n] for j := i; j < n; j++ { stmp[j] = a.At(i, j) + b.At(i, j) } } } func (s *SymDense) CopySym(a Symmetric) int { n := a.SymmetricDim() n = min(n, s.mat.N) if n == 0 { return 0 } switch a := a.(type) { case RawSymmetricer: amat := a.RawSymmetric() if amat.Uplo != blas.Upper { panic(badSymTriangle) } for i := 0; i < n; i++ { copy(s.mat.Data[i*s.mat.Stride+i:i*s.mat.Stride+n], amat.Data[i*amat.Stride+i:i*amat.Stride+n]) } default: for i := 0; i < n; i++ { stmp := s.mat.Data[i*s.mat.Stride : i*s.mat.Stride+n] for j := i; j < n; j++ { stmp[j] = a.At(i, j) } } } return n } // SymRankOne performs a symmetric rank-one update to the matrix a with x, // which is treated as a column vector, and stores the result in the receiver // // s = a + alpha * x * xᵀ func (s *SymDense) SymRankOne(a Symmetric, alpha float64, x Vector) { n := x.Len() if a.SymmetricDim() != n { panic(ErrShape) } s.reuseAsNonZeroed(n) if s != a { if rs, ok := a.(RawSymmetricer); ok { s.checkOverlap(generalFromSymmetric(rs.RawSymmetric())) } s.CopySym(a) } xU, _ := untransposeExtract(x) if rv, ok := xU.(*VecDense); ok { r, c := xU.Dims() xmat := rv.mat s.checkOverlap(generalFromVector(xmat, r, c)) blas64.Syr(alpha, xmat, s.mat) return } for i := 0; i < n; i++ { for j := i; j < n; j++ { s.set(i, j, s.at(i, j)+alpha*x.AtVec(i)*x.AtVec(j)) } } } // SymRankK performs a symmetric rank-k update to the matrix a and stores the // result into the receiver. If a is zero, see SymOuterK. // // s = a + alpha * x * x' func (s *SymDense) SymRankK(a Symmetric, alpha float64, x Matrix) { n := a.SymmetricDim() r, _ := x.Dims() if r != n { panic(ErrShape) } xMat, aTrans := untransposeExtract(x) var g blas64.General if rm, ok := xMat.(*Dense); ok { g = rm.mat } else { g = DenseCopyOf(x).mat aTrans = false } if a != s { if rs, ok := a.(RawSymmetricer); ok { s.checkOverlap(generalFromSymmetric(rs.RawSymmetric())) } s.reuseAsNonZeroed(n) s.CopySym(a) } t := blas.NoTrans if aTrans { t = blas.Trans } blas64.Syrk(t, alpha, g, 1, s.mat) } // SymOuterK calculates the outer product of x with itself and stores // the result into the receiver. It is equivalent to the matrix // multiplication // // s = alpha * x * x'. // // In order to update an existing matrix, see SymRankOne. func (s *SymDense) SymOuterK(alpha float64, x Matrix) { n, _ := x.Dims() switch { case s.IsEmpty(): s.mat = blas64.Symmetric{ N: n, Stride: n, Data: useZeroed(s.mat.Data, n*n), Uplo: blas.Upper, } s.cap = n s.SymRankK(s, alpha, x) case s.mat.Uplo != blas.Upper: panic(badSymTriangle) case s.mat.N == n: if s == x { w := getSymDenseWorkspace(n, true) w.SymRankK(w, alpha, x) s.CopySym(w) putSymDenseWorkspace(w) } else { switch r := x.(type) { case RawMatrixer: s.checkOverlap(r.RawMatrix()) case RawSymmetricer: s.checkOverlap(generalFromSymmetric(r.RawSymmetric())) case RawTriangular: s.checkOverlap(generalFromTriangular(r.RawTriangular())) } // Only zero the upper triangle. for i := 0; i < n; i++ { ri := i * s.mat.Stride zero(s.mat.Data[ri+i : ri+n]) } s.SymRankK(s, alpha, x) } default: panic(ErrShape) } } // RankTwo performs a symmetric rank-two update to the matrix a with the // vectors x and y, which are treated as column vectors, and stores the // result in the receiver // // m = a + alpha * (x * yᵀ + y * xᵀ) func (s *SymDense) RankTwo(a Symmetric, alpha float64, x, y Vector) { n := s.mat.N if x.Len() != n { panic(ErrShape) } if y.Len() != n { panic(ErrShape) } if s != a { if rs, ok := a.(RawSymmetricer); ok { s.checkOverlap(generalFromSymmetric(rs.RawSymmetric())) } } var xmat, ymat blas64.Vector fast := true xU, _ := untransposeExtract(x) if rv, ok := xU.(*VecDense); ok { r, c := xU.Dims() xmat = rv.mat s.checkOverlap(generalFromVector(xmat, r, c)) } else { fast = false } yU, _ := untransposeExtract(y) if rv, ok := yU.(*VecDense); ok { r, c := yU.Dims() ymat = rv.mat s.checkOverlap(generalFromVector(ymat, r, c)) } else { fast = false } if s != a { if rs, ok := a.(RawSymmetricer); ok { s.checkOverlap(generalFromSymmetric(rs.RawSymmetric())) } s.reuseAsNonZeroed(n) s.CopySym(a) } if fast { if s != a { s.reuseAsNonZeroed(n) s.CopySym(a) } blas64.Syr2(alpha, xmat, ymat, s.mat) return } for i := 0; i < n; i++ { s.reuseAsNonZeroed(n) for j := i; j < n; j++ { s.set(i, j, a.At(i, j)+alpha*(x.AtVec(i)*y.AtVec(j)+y.AtVec(i)*x.AtVec(j))) } } } // ScaleSym multiplies the elements of a by f, placing the result in the receiver. func (s *SymDense) ScaleSym(f float64, a Symmetric) { n := a.SymmetricDim() s.reuseAsNonZeroed(n) if a, ok := a.(RawSymmetricer); ok { amat := a.RawSymmetric() if s != a { s.checkOverlap(generalFromSymmetric(amat)) } for i := 0; i < n; i++ { for j := i; j < n; j++ { s.mat.Data[i*s.mat.Stride+j] = f * amat.Data[i*amat.Stride+j] } } return } for i := 0; i < n; i++ { for j := i; j < n; j++ { s.mat.Data[i*s.mat.Stride+j] = f * a.At(i, j) } } } // SubsetSym extracts a subset of the rows and columns of the matrix a and stores // the result in-place into the receiver. The resulting matrix size is // len(set)×len(set). Specifically, at the conclusion of SubsetSym, // s.At(i, j) equals a.At(set[i], set[j]). Note that the supplied set does not // have to be a strict subset, dimension repeats are allowed. func (s *SymDense) SubsetSym(a Symmetric, set []int) { n := len(set) na := a.SymmetricDim() s.reuseAsNonZeroed(n) var restore func() if a == s { s, restore = s.isolatedWorkspace(a) defer restore() } if a, ok := a.(RawSymmetricer); ok { raw := a.RawSymmetric() if s != a { s.checkOverlap(generalFromSymmetric(raw)) } for i := 0; i < n; i++ { ssub := s.mat.Data[i*s.mat.Stride : i*s.mat.Stride+n] r := set[i] rsub := raw.Data[r*raw.Stride : r*raw.Stride+na] for j := i; j < n; j++ { c := set[j] if r <= c { ssub[j] = rsub[c] } else { ssub[j] = raw.Data[c*raw.Stride+r] } } } return } for i := 0; i < n; i++ { for j := i; j < n; j++ { s.mat.Data[i*s.mat.Stride+j] = a.At(set[i], set[j]) } } } // SliceSym returns a new Matrix that shares backing data with the receiver. // The returned matrix starts at {i,i} of the receiver and extends k-i rows // and columns. The final row and column in the resulting matrix is k-1. // SliceSym panics with ErrIndexOutOfRange if the slice is outside the // capacity of the receiver. func (s *SymDense) SliceSym(i, k int) Symmetric { return s.sliceSym(i, k) } func (s *SymDense) sliceSym(i, k int) *SymDense { sz := s.cap if i < 0 || sz < i || k < i || sz < k { panic(ErrIndexOutOfRange) } v := *s v.mat.Data = s.mat.Data[i*s.mat.Stride+i : (k-1)*s.mat.Stride+k] v.mat.N = k - i v.cap = s.cap - i return &v } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the matrix has zero size. func (s *SymDense) Norm(norm float64) float64 { if s.IsEmpty() { panic(ErrZeroLength) } lnorm := normLapack(norm, false) if lnorm == lapack.MaxColumnSum || lnorm == lapack.MaxRowSum { work := getFloat64s(s.mat.N, false) defer putFloat64s(work) return lapack64.Lansy(lnorm, s.mat, work) } return lapack64.Lansy(lnorm, s.mat, nil) } // Trace returns the trace of the matrix. // // Trace will panic with ErrZeroLength if the matrix has zero size. func (s *SymDense) Trace() float64 { if s.IsEmpty() { panic(ErrZeroLength) } // TODO(btracey): could use internal asm sum routine. var v float64 for i := 0; i < s.mat.N; i++ { v += s.mat.Data[i*s.mat.Stride+i] } return v } // GrowSym returns the receiver expanded by n rows and n columns. If the // dimensions of the expanded matrix are outside the capacity of the receiver // a new allocation is made, otherwise not. Note that the receiver itself is // not modified during the call to GrowSquare. func (s *SymDense) GrowSym(n int) Symmetric { if n < 0 { panic(ErrIndexOutOfRange) } if n == 0 { return s } var v SymDense n += s.mat.N if s.IsEmpty() || n > s.cap { v.mat = blas64.Symmetric{ N: n, Stride: n, Uplo: blas.Upper, Data: make([]float64, n*n), } v.cap = n // Copy elements, including those not currently visible. Use a temporary // structure to avoid modifying the receiver. var tmp SymDense tmp.mat = blas64.Symmetric{ N: s.cap, Stride: s.mat.Stride, Data: s.mat.Data, Uplo: s.mat.Uplo, } tmp.cap = s.cap v.CopySym(&tmp) return &v } v.mat = blas64.Symmetric{ N: n, Stride: s.mat.Stride, Uplo: blas.Upper, Data: s.mat.Data[:(n-1)*s.mat.Stride+n], } v.cap = s.cap return &v } // PowPSD computes a^pow where a is a positive symmetric definite matrix. // // PowPSD returns an error if the matrix is not positive symmetric definite // or the Eigen decomposition is not successful. func (s *SymDense) PowPSD(a Symmetric, pow float64) error { dim := a.SymmetricDim() s.reuseAsNonZeroed(dim) var eigen EigenSym ok := eigen.Factorize(a, true) if !ok { return ErrFailedEigen } values := eigen.Values(nil) for i, v := range values { if v <= 0 { return ErrNotPSD } values[i] = math.Pow(v, pow) } var u Dense eigen.VectorsTo(&u) s.SymOuterK(values[0], u.ColView(0)) var v VecDense for i := 1; i < dim; i++ { v.ColViewOf(&u, i) s.SymRankOne(s, values[i], &v) } return nil } golang-gonum-v1-gonum-0.14.0/mat/symmetric_example_test.go000066400000000000000000000022031450372207100235310ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "gonum.org/v1/gonum/mat" ) func ExampleSymDense_SubsetSym() { n := 5 s := mat.NewSymDense(5, nil) count := 1.0 for i := 0; i < n; i++ { for j := i; j < n; j++ { s.SetSym(i, j, count) count++ } } fmt.Println("Original matrix:") fmt.Printf("%0.4v\n\n", mat.Formatted(s)) // Take the subset {0, 2, 4} var sub mat.SymDense sub.SubsetSym(s, []int{0, 2, 4}) fmt.Println("Subset {0, 2, 4}") fmt.Printf("%0.4v\n\n", mat.Formatted(&sub)) // Take the subset {0, 0, 4} sub.SubsetSym(s, []int{0, 0, 4}) fmt.Println("Subset {0, 0, 4}") fmt.Printf("%0.4v\n\n", mat.Formatted(&sub)) // Output: // Original matrix: // ⎡ 1 2 3 4 5⎤ // ⎢ 2 6 7 8 9⎥ // ⎢ 3 7 10 11 12⎥ // ⎢ 4 8 11 13 14⎥ // ⎣ 5 9 12 14 15⎦ // // Subset {0, 2, 4} // ⎡ 1 3 5⎤ // ⎢ 3 10 12⎥ // ⎣ 5 12 15⎦ // // Subset {0, 0, 4} // ⎡ 1 1 5⎤ // ⎢ 1 1 5⎥ // ⎣ 5 5 15⎦ } golang-gonum-v1-gonum-0.14.0/mat/symmetric_test.go000066400000000000000000000444201450372207100220250ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "os" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/floats/scalar" ) func TestNewSymmetric(t *testing.T) { t.Parallel() for i, test := range []struct { data []float64 n int mat *SymDense }{ { data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }, n: 3, mat: &SymDense{ mat: blas64.Symmetric{ N: 3, Stride: 3, Uplo: blas.Upper, Data: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}, }, cap: 3, }, }, } { sym := NewSymDense(test.n, test.data) rows, cols := sym.Dims() if rows != test.n { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.n) } if cols != test.n { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.n) } if !reflect.DeepEqual(sym, test.mat) { t.Errorf("unexpected data slice for test %d: got: %v want: %v", i, sym, test.mat) } m := NewDense(test.n, test.n, test.data) if !reflect.DeepEqual(sym.mat.Data, m.mat.Data) { t.Errorf("unexpected data slice mismatch for test %d: got: %v want: %v", i, sym.mat.Data, m.mat.Data) } } panicked, message := panics(func() { NewSymDense(3, []float64{1, 2}) }) if !panicked || message != ErrShape.Error() { t.Error("expected panic for invalid data slice length") } } func TestSymAtSet(t *testing.T) { t.Parallel() sym := &SymDense{ mat: blas64.Symmetric{ N: 3, Stride: 3, Uplo: blas.Upper, Data: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}, }, cap: 3, } rows, cols := sym.Dims() // Check At out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { sym.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { sym.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } // Check Set out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { sym.SetSym(row, 0, 1.2) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { sym.SetSym(0, col, 1.2) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } for _, st := range []struct { row, col int orig, new float64 }{ {row: 1, col: 2, orig: 6, new: 15}, {row: 2, col: 1, orig: 15, new: 12}, } { if e := sym.At(st.row, st.col); e != st.orig { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", st.row, st.col, e, st.orig) } if e := sym.At(st.col, st.row); e != st.orig { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", st.col, st.row, e, st.orig) } sym.SetSym(st.row, st.col, st.new) if e := sym.At(st.row, st.col); e != st.new { t.Errorf("unexpected value for At(%d, %d) after SetSym(%[1]d, %[2]d, %[4]v): got: %[3]v want: %v", st.row, st.col, e, st.new) } if e := sym.At(st.col, st.row); e != st.new { t.Errorf("unexpected value for At(%d, %d) after SetSym(%[2]d, %[1]d, %[4]v): got: %[3]v want: %v", st.col, st.row, e, st.new) } } } func TestSymDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*SymDense{ { mat: blas64.Symmetric{ Uplo: blas.Upper, N: 4, Stride: 5, Data: []float64{ 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } func TestSymDiagView(t *testing.T) { t.Parallel() for cas, test := range []*SymDense{ NewSymDense(1, []float64{1}), NewSymDense(2, []float64{1, 2, 2, 3}), NewSymDense(3, []float64{1, 2, 3, 2, 4, 5, 3, 5, 6}), } { testDiagView(t, cas, test) } } func TestSymAdd(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { n int }{ {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 10}, } { n := test.n a := NewSymDense(n, nil) for i := range a.mat.Data { a.mat.Data[i] = rnd.Float64() } b := NewSymDense(n, nil) for i := range a.mat.Data { b.mat.Data[i] = rnd.Float64() } var m Dense m.Add(a, b) // Check with new receiver var s SymDense s.AddSym(a, b) for i := 0; i < n; i++ { for j := i; j < n; j++ { want := m.At(i, j) if got := s.At(i, j); got != want { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", i, j, got, want) } } } // Check with equal receiver s.CopySym(a) s.AddSym(&s, b) for i := 0; i < n; i++ { for j := i; j < n; j++ { want := m.At(i, j) if got := s.At(i, j); got != want { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", i, j, got, want) } } } } method := func(receiver, a, b Matrix) { type addSymer interface { AddSym(a, b Symmetric) } rd := receiver.(addSymer) rd.AddSym(a.(Symmetric), b.(Symmetric)) } denseComparison := func(receiver, a, b *Dense) { receiver.Add(a, b) } testTwoInput(t, "AddSym", &SymDense{}, method, denseComparison, legalTypesSym, legalSizeSameSquare, 1e-14) } func TestCopy(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { n int }{ {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 10}, } { n := test.n a := NewSymDense(n, nil) for i := range a.mat.Data { a.mat.Data[i] = rnd.Float64() } s := NewSymDense(n, nil) s.CopySym(a) for i := 0; i < n; i++ { for j := i; j < n; j++ { want := a.At(i, j) if got := s.At(i, j); got != want { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", i, j, got, want) } } } } } // TODO(kortschak) Roll this into testOneInput when it exists. // https://github.com/gonum/matrix/issues/171 func TestSymCopyPanic(t *testing.T) { t.Parallel() var ( a SymDense n int ) m := NewSymDense(1, nil) panicked, message := panics(func() { n = m.CopySym(&a) }) if panicked { t.Errorf("unexpected panic: %v", message) } if n != 0 { t.Errorf("unexpected n: got: %d want: 0", n) } } func TestSymRankOne(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) const tol = 1e-15 for _, test := range []struct { n int }{ {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 10}, } { n := test.n alpha := 2.0 a := NewSymDense(n, nil) for i := range a.mat.Data { a.mat.Data[i] = rnd.Float64() } x := make([]float64, n) for i := range x { x[i] = rnd.Float64() } xMat := NewDense(n, 1, x) var m Dense m.Mul(xMat, xMat.T()) m.Scale(alpha, &m) m.Add(&m, a) // Check with new receiver s := NewSymDense(n, nil) s.SymRankOne(a, alpha, NewVecDense(len(x), x)) for i := 0; i < n; i++ { for j := i; j < n; j++ { want := m.At(i, j) if got := s.At(i, j); !scalar.EqualWithinAbsOrRel(got, want, tol, tol) { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", i, j, got, want) } } } // Check with reused receiver copy(s.mat.Data, a.mat.Data) s.SymRankOne(s, alpha, NewVecDense(len(x), x)) for i := 0; i < n; i++ { for j := i; j < n; j++ { want := m.At(i, j) if got := s.At(i, j); !scalar.EqualWithinAbsOrRel(got, want, tol, tol) { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", i, j, got, want) } } } } alpha := 3.0 method := func(receiver, a, b Matrix) { type SymRankOner interface { SymRankOne(a Symmetric, alpha float64, x Vector) } rd := receiver.(SymRankOner) rd.SymRankOne(a.(Symmetric), alpha, b.(Vector)) } denseComparison := func(receiver, a, b *Dense) { var tmp Dense tmp.Mul(b, b.T()) tmp.Scale(alpha, &tmp) receiver.Add(a, &tmp) } legalTypes := func(a, b Matrix) bool { _, ok := a.(Symmetric) if !ok { return false } _, ok = b.(Vector) return ok } legalSize := func(ar, ac, br, bc int) bool { if ar != ac { return false } return br == ar } testTwoInput(t, "SymRankOne", &SymDense{}, method, denseComparison, legalTypes, legalSize, 1e-14) } func TestIssue250SymRankOne(t *testing.T) { t.Parallel() x := NewVecDense(5, []float64{1, 2, 3, 4, 5}) var s1, s2 SymDense s1.SymRankOne(NewSymDense(5, nil), 1, x) s2.SymRankOne(NewSymDense(5, nil), 1, x) s2.SymRankOne(NewSymDense(5, nil), 1, x) if !Equal(&s1, &s2) { t.Error("unexpected result from repeat") } } func TestRankTwo(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, test := range []struct { n int }{ {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 10}, } { n := test.n alpha := 2.0 a := NewSymDense(n, nil) for i := range a.mat.Data { a.mat.Data[i] = rnd.Float64() } x := make([]float64, n) y := make([]float64, n) for i := range x { x[i] = rnd.Float64() y[i] = rnd.Float64() } xMat := NewDense(n, 1, x) yMat := NewDense(n, 1, y) var m Dense m.Mul(xMat, yMat.T()) var tmp Dense tmp.Mul(yMat, xMat.T()) m.Add(&m, &tmp) m.Scale(alpha, &m) m.Add(&m, a) // Check with new receiver s := NewSymDense(n, nil) s.RankTwo(a, alpha, NewVecDense(len(x), x), NewVecDense(len(y), y)) for i := 0; i < n; i++ { for j := i; j < n; j++ { if !scalar.EqualWithinAbsOrRel(s.At(i, j), m.At(i, j), 1e-14, 1e-14) { t.Errorf("unexpected element value at (%d,%d): got: %f want: %f", i, j, m.At(i, j), s.At(i, j)) } } } // Check with reused receiver copy(s.mat.Data, a.mat.Data) s.RankTwo(s, alpha, NewVecDense(len(x), x), NewVecDense(len(y), y)) for i := 0; i < n; i++ { for j := i; j < n; j++ { if !scalar.EqualWithinAbsOrRel(s.At(i, j), m.At(i, j), 1e-14, 1e-14) { t.Errorf("unexpected element value at (%d,%d): got: %f want: %f", i, j, m.At(i, j), s.At(i, j)) } } } } } func TestSymRankK(t *testing.T) { t.Parallel() alpha := 3.0 method := func(receiver, a, b Matrix) { type SymRankKer interface { SymRankK(a Symmetric, alpha float64, x Matrix) } rd := receiver.(SymRankKer) rd.SymRankK(a.(Symmetric), alpha, b) } denseComparison := func(receiver, a, b *Dense) { var tmp Dense tmp.Mul(b, b.T()) tmp.Scale(alpha, &tmp) receiver.Add(a, &tmp) } legalTypes := func(a, b Matrix) bool { _, ok := a.(Symmetric) return ok } legalSize := func(ar, ac, br, bc int) bool { if ar != ac { return false } return br == ar } testTwoInput(t, "SymRankK", &SymDense{}, method, denseComparison, legalTypes, legalSize, 1e-14) } func TestSymOuterK(t *testing.T) { t.Parallel() for _, f := range []float64{0.5, 1, 3} { method := func(receiver, x Matrix) { type SymOuterKer interface { SymOuterK(alpha float64, x Matrix) } rd := receiver.(SymOuterKer) rd.SymOuterK(f, x) } denseComparison := func(receiver, x *Dense) { receiver.Mul(x, x.T()) receiver.Scale(f, receiver) } testOneInput(t, "SymOuterK", &SymDense{}, method, denseComparison, isAnyType, isAnySize, 1e-14) } } func TestIssue250SymOuterK(t *testing.T) { t.Parallel() x := NewVecDense(5, []float64{1, 2, 3, 4, 5}) var s1, s2 SymDense s1.SymOuterK(1, x) s2.SymOuterK(1, x) s2.SymOuterK(1, x) if !Equal(&s1, &s2) { t.Error("unexpected result from repeat") } } func TestScaleSym(t *testing.T) { t.Parallel() for _, f := range []float64{0.5, 1, 3} { method := func(receiver, a Matrix) { type ScaleSymer interface { ScaleSym(f float64, a Symmetric) } rd := receiver.(ScaleSymer) rd.ScaleSym(f, a.(Symmetric)) } denseComparison := func(receiver, a *Dense) { receiver.Scale(f, a) } testOneInput(t, "ScaleSym", &SymDense{}, method, denseComparison, legalTypeSym, isSquare, 1e-14) } } func TestSubsetSym(t *testing.T) { t.Parallel() for _, test := range []struct { a *SymDense dims []int ans *SymDense }{ { a: NewSymDense(3, []float64{ 1, 2, 3, 0, 4, 5, 0, 0, 6, }), dims: []int{0, 2}, ans: NewSymDense(2, []float64{ 1, 3, 0, 6, }), }, { a: NewSymDense(3, []float64{ 1, 2, 3, 0, 4, 5, 0, 0, 6, }), dims: []int{2, 0}, ans: NewSymDense(2, []float64{ 6, 3, 0, 1, }), }, { a: NewSymDense(3, []float64{ 1, 2, 3, 0, 4, 5, 0, 0, 6, }), dims: []int{1, 1, 1}, ans: NewSymDense(3, []float64{ 4, 4, 4, 0, 4, 4, 0, 0, 4, }), }, } { var s SymDense s.SubsetSym(test.a, test.dims) if !Equal(&s, test.ans) { t.Errorf("SubsetSym mismatch dims %v\nGot:\n% v\nWant:\n% v\n", test.dims, s, test.ans) } } dims := []int{0, 2} maxDim := dims[0] for _, v := range dims { if maxDim < v { maxDim = v } } method := func(receiver, a Matrix) { type SubsetSymer interface { SubsetSym(a Symmetric, set []int) } rd := receiver.(SubsetSymer) rd.SubsetSym(a.(Symmetric), dims) } denseComparison := func(receiver, a *Dense) { *receiver = *NewDense(len(dims), len(dims), nil) sz := len(dims) for i := 0; i < sz; i++ { for j := 0; j < sz; j++ { receiver.Set(i, j, a.At(dims[i], dims[j])) } } } legalSize := func(ar, ac int) bool { return ar == ac && ar > maxDim } testOneInput(t, "SubsetSym", &SymDense{}, method, denseComparison, legalTypeSym, legalSize, 0) } func TestViewGrowSquare(t *testing.T) { t.Parallel() // n is the size of the original SymDense. // The first view uses start1, span1. The second view uses start2, span2 on // the first view. for _, test := range []struct { n, start1, span1, start2, span2 int }{ {10, 0, 10, 0, 10}, {10, 0, 8, 0, 8}, {10, 2, 8, 0, 6}, {10, 2, 7, 4, 2}, {10, 2, 6, 0, 5}, } { n := test.n s := NewSymDense(n, nil) for i := 0; i < n; i++ { for j := i; j < n; j++ { s.SetSym(i, j, float64((i+1)*n+j+1)) } } // Take a subset and check the view matches. start1 := test.start1 span1 := test.span1 v := s.sliceSym(start1, start1+span1) for i := 0; i < span1; i++ { for j := i; j < span1; j++ { if v.At(i, j) != s.At(start1+i, start1+j) { t.Errorf("View mismatch") } } } start2 := test.start2 span2 := test.span2 v2 := v.SliceSym(start2, start2+span2).(*SymDense) for i := 0; i < span2; i++ { for j := i; j < span2; j++ { if v2.At(i, j) != s.At(start1+start2+i, start1+start2+j) { t.Errorf("Second view mismatch") } } } // Check that a write to the view is reflected in the original. v2.SetSym(0, 0, 1.2) if s.At(start1+start2, start1+start2) != 1.2 { t.Errorf("Write to view not reflected in original") } // Grow the matrix back to the original view gn := n - start1 - start2 g := v2.GrowSym(gn - v2.SymmetricDim()).(*SymDense) g.SetSym(1, 1, 2.2) for i := 0; i < gn; i++ { for j := 0; j < gn; j++ { if g.At(i, j) != s.At(start1+start2+i, start1+start2+j) { t.Errorf("Grow mismatch") fmt.Printf("g=\n% v\n", Formatted(g)) fmt.Printf("s=\n% v\n", Formatted(s)) os.Exit(1) } } } // View g, then grow it and make sure all the elements were copied. gv := g.SliceSym(0, gn-1).(*SymDense) gg := gv.GrowSym(2) for i := 0; i < gn; i++ { for j := 0; j < gn; j++ { if g.At(i, j) != gg.At(i, j) { t.Errorf("Expand mismatch") } } } s.Reset() rg := s.GrowSym(n).(*SymDense) if rg.mat.Stride < n { t.Errorf("unexpected stride after GrowSym on empty matrix: got:%d want >= %d", rg.mat.Stride, n) } } } func TestPowPSD(t *testing.T) { t.Parallel() for cas, test := range []struct { a *SymDense pow float64 ans *SymDense }{ // Comparison with Matlab. { a: NewSymDense(2, []float64{10, 5, 5, 12}), pow: 0.5, ans: NewSymDense(2, []float64{3.065533767740645, 0.776210486171016, 0.776210486171016, 3.376017962209052}), }, { a: NewSymDense(2, []float64{11, -1, -1, 8}), pow: 0.5, ans: NewSymDense(2, []float64{3.312618742210524, -0.162963396980939, -0.162963396980939, 2.823728551267709}), }, { a: NewSymDense(2, []float64{10, 5, 5, 12}), pow: -0.5, ans: NewSymDense(2, []float64{0.346372134547712, -0.079637515547296, -0.079637515547296, 0.314517128328794}), }, { a: NewSymDense(3, []float64{15, -1, -3, -1, 8, 6, -3, 6, 14}), pow: 0.6, ans: NewSymDense(3, []float64{ 5.051214323034288, -0.163162161893975, -0.612153996497505, -0.163162161893976, 3.283474884617009, 1.432842761381493, -0.612153996497505, 1.432842761381494, 4.695873060862573, }), }, } { var s SymDense err := s.PowPSD(test.a, test.pow) if err != nil { panic("bad test") } if !EqualApprox(&s, test.ans, 1e-10) { t.Errorf("Case %d, pow mismatch", cas) fmt.Println(Formatted(&s)) fmt.Println(Formatted(test.ans)) } } // Compare with Dense.Pow rnd := rand.New(rand.NewSource(1)) for dim := 2; dim < 10; dim++ { for pow := 2; pow < 6; pow++ { a := NewDense(dim, dim, nil) for i := 0; i < dim; i++ { for j := 0; j < dim; j++ { a.Set(i, j, rnd.Float64()) } } var mat SymDense mat.SymOuterK(1, a) var sym SymDense err := sym.PowPSD(&mat, float64(pow)) if err != nil { t.Errorf("unexpected error: %v", err) } var dense Dense dense.Pow(&mat, pow) if !EqualApprox(&sym, &dense, 1e-10) { t.Errorf("Dim %d: pow mismatch", dim) } } } } func BenchmarkSymSum1000(b *testing.B) { symSumBench(b, 1000) } var symSumForBench float64 func symSumBench(b *testing.B, size int) { src := rand.NewSource(1) a := randSymDense(size, src) b.ResetTimer() for i := 0; i < b.N; i++ { symSumForBench = Sum(a) } } func randSymDense(size int, src rand.Source) *SymDense { rnd := rand.New(src) backData := make([]float64, size*size) for i := 0; i < size; i++ { backData[i*size+i] = rnd.Float64() for j := i + 1; j < size; j++ { v := rnd.Float64() backData[i*size+j] = v backData[j*size+i] = v } } s := NewSymDense(size, backData) return s } golang-gonum-v1-gonum-0.14.0/mat/triangular.go000066400000000000000000000474411450372207100211300ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) var ( triDense *TriDense _ Matrix = triDense _ allMatrix = triDense _ denseMatrix = triDense _ Triangular = triDense _ RawTriangular = triDense _ MutableTriangular = triDense _ NonZeroDoer = triDense _ RowNonZeroDoer = triDense _ ColNonZeroDoer = triDense ) // TriDense represents an upper or lower triangular matrix in dense storage // format. type TriDense struct { mat blas64.Triangular cap int } // Triangular represents a triangular matrix. Triangular matrices are always square. type Triangular interface { Matrix // Triangle returns the number of rows/columns in the matrix and its // orientation. Triangle() (n int, kind TriKind) // TTri is the equivalent of the T() method in the Matrix interface but // guarantees the transpose is of triangular type. TTri() Triangular } // A RawTriangular can return a blas64.Triangular representation of the receiver. // Changes to the blas64.Triangular.Data slice will be reflected in the original // matrix, changes to the N, Stride, Uplo and Diag fields will not. type RawTriangular interface { RawTriangular() blas64.Triangular } // A MutableTriangular can set elements of a triangular matrix. type MutableTriangular interface { Triangular SetTri(i, j int, v float64) } var ( _ Matrix = TransposeTri{} _ Triangular = TransposeTri{} _ UntransposeTrier = TransposeTri{} ) // TransposeTri is a type for performing an implicit transpose of a Triangular // matrix. It implements the Triangular interface, returning values from the // transpose of the matrix within. type TransposeTri struct { Triangular Triangular } // At returns the value of the element at row i and column j of the transposed // matrix, that is, row j and column i of the Triangular field. func (t TransposeTri) At(i, j int) float64 { return t.Triangular.At(j, i) } // Dims returns the dimensions of the transposed matrix. Triangular matrices are // square and thus this is the same size as the original Triangular. func (t TransposeTri) Dims() (r, c int) { c, r = t.Triangular.Dims() return r, c } // T performs an implicit transpose by returning the Triangular field. func (t TransposeTri) T() Matrix { return t.Triangular } // Triangle returns the number of rows/columns in the matrix and its orientation. func (t TransposeTri) Triangle() (int, TriKind) { n, upper := t.Triangular.Triangle() return n, !upper } // TTri performs an implicit transpose by returning the Triangular field. func (t TransposeTri) TTri() Triangular { return t.Triangular } // Untranspose returns the Triangular field. func (t TransposeTri) Untranspose() Matrix { return t.Triangular } func (t TransposeTri) UntransposeTri() Triangular { return t.Triangular } // NewTriDense creates a new Triangular matrix with n rows and columns. If data == nil, // a new slice is allocated for the backing slice. If len(data) == n*n, data is // used as the backing slice, and changes to the elements of the returned TriDense // will be reflected in data. If neither of these is true, NewTriDense will panic. // NewTriDense will panic if n is zero. // // The data must be arranged in row-major order, i.e. the (i*c + j)-th // element in the data slice is the {i, j}-th element in the matrix. // Only the values in the triangular portion corresponding to kind are used. func NewTriDense(n int, kind TriKind, data []float64) *TriDense { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic("mat: negative dimension") } if data != nil && len(data) != n*n { panic(ErrShape) } if data == nil { data = make([]float64, n*n) } uplo := blas.Lower if kind == Upper { uplo = blas.Upper } return &TriDense{ mat: blas64.Triangular{ N: n, Stride: n, Data: data, Uplo: uplo, Diag: blas.NonUnit, }, cap: n, } } func (t *TriDense) Dims() (r, c int) { return t.mat.N, t.mat.N } // Triangle returns the dimension of t and its orientation. The returned // orientation is only valid when n is not empty. func (t *TriDense) Triangle() (n int, kind TriKind) { return t.mat.N, t.triKind() } func (t *TriDense) isUpper() bool { return isUpperUplo(t.mat.Uplo) } func (t *TriDense) triKind() TriKind { return TriKind(isUpperUplo(t.mat.Uplo)) } func isUpperUplo(u blas.Uplo) bool { switch u { case blas.Upper: return true case blas.Lower: return false default: panic(badTriangle) } } // asSymBlas returns the receiver restructured as a blas64.Symmetric with the // same backing memory. Panics if the receiver is unit. // This returns a blas64.Symmetric and not a *SymDense because SymDense can only // be upper triangular. func (t *TriDense) asSymBlas() blas64.Symmetric { if t.mat.Diag == blas.Unit { panic("mat: cannot convert unit TriDense into blas64.Symmetric") } return blas64.Symmetric{ N: t.mat.N, Stride: t.mat.Stride, Data: t.mat.Data, Uplo: t.mat.Uplo, } } // T performs an implicit transpose by returning the receiver inside a Transpose. func (t *TriDense) T() Matrix { return Transpose{t} } // TTri performs an implicit transpose by returning the receiver inside a TransposeTri. func (t *TriDense) TTri() Triangular { return TransposeTri{t} } func (t *TriDense) RawTriangular() blas64.Triangular { return t.mat } // SetRawTriangular sets the underlying blas64.Triangular used by the receiver. // Changes to elements in the receiver following the call will be reflected // in the input. // // The supplied Triangular must not use blas.Unit storage format. func (t *TriDense) SetRawTriangular(mat blas64.Triangular) { if mat.Diag == blas.Unit { panic("mat: cannot set TriDense with Unit storage format") } t.cap = mat.N t.mat = mat } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (t *TriDense) Reset() { // N and Stride must be zeroed in unison. t.mat.N, t.mat.Stride = 0, 0 // Defensively zero Uplo to ensure // it is set correctly later. t.mat.Uplo = 0 t.mat.Data = t.mat.Data[:0] } // Zero sets all of the matrix elements to zero. func (t *TriDense) Zero() { if t.isUpper() { for i := 0; i < t.mat.N; i++ { zero(t.mat.Data[i*t.mat.Stride+i : i*t.mat.Stride+t.mat.N]) } return } for i := 0; i < t.mat.N; i++ { zero(t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+i+1]) } } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (t *TriDense) IsEmpty() bool { // It must be the case that t.Dims() returns // zeros in this case. See comment in Reset(). return t.mat.Stride == 0 } // untransposeTri untransposes a matrix if applicable. If a is an UntransposeTrier, then // untransposeTri returns the underlying matrix and true. If it is not, then it returns // the input matrix and false. func untransposeTri(a Triangular) (Triangular, bool) { if ut, ok := a.(UntransposeTrier); ok { return ut.UntransposeTri(), true } return a, false } // ReuseAsTri changes the receiver if it IsEmpty() to be of size n×n. // // ReuseAsTri re-uses the backing data slice if it has sufficient capacity, // otherwise a new slice is allocated. The backing data is zero on return. // // ReuseAsTri panics if the receiver is not empty, and panics if // the input size is less than one. To empty the receiver for re-use, // Reset should be used. func (t *TriDense) ReuseAsTri(n int, kind TriKind) { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if !t.IsEmpty() { panic(ErrReuseNonEmpty) } t.reuseAsZeroed(n, kind) } // reuseAsNonZeroed resizes an empty receiver to an n×n triangular matrix with the given // orientation. If the receiver is not empty, reuseAsNonZeroed checks that the receiver // is the correct size and orientation. func (t *TriDense) reuseAsNonZeroed(n int, kind TriKind) { // reuseAsNonZeroed must be kept in sync with reuseAsZeroed. if n == 0 { panic(ErrZeroLength) } ul := blas.Lower if kind == Upper { ul = blas.Upper } if t.mat.N > t.cap { // Panic as a string, not a mat.Error. panic(badCap) } if t.IsEmpty() { t.mat = blas64.Triangular{ N: n, Stride: n, Diag: blas.NonUnit, Data: use(t.mat.Data, n*n), Uplo: ul, } t.cap = n return } if t.mat.N != n { panic(ErrShape) } if t.mat.Uplo != ul { panic(ErrTriangle) } } // reuseAsZeroed resizes an empty receiver to an n×n triangular matrix with the given // orientation. If the receiver is not empty, reuseAsZeroed checks that the receiver // is the correct size and orientation. It then zeros out the matrix data. func (t *TriDense) reuseAsZeroed(n int, kind TriKind) { // reuseAsZeroed must be kept in sync with reuseAsNonZeroed. if n == 0 { panic(ErrZeroLength) } ul := blas.Lower if kind == Upper { ul = blas.Upper } if t.mat.N > t.cap { // Panic as a string, not a mat.Error. panic(badCap) } if t.IsEmpty() { t.mat = blas64.Triangular{ N: n, Stride: n, Diag: blas.NonUnit, Data: useZeroed(t.mat.Data, n*n), Uplo: ul, } t.cap = n return } if t.mat.N != n { panic(ErrShape) } if t.mat.Uplo != ul { panic(ErrTriangle) } t.Zero() } // isolatedWorkspace returns a new TriDense matrix w with the size of a and // returns a callback to defer which performs cleanup at the return of the call. // This should be used when a method receiver is the same pointer as an input argument. func (t *TriDense) isolatedWorkspace(a Triangular) (w *TriDense, restore func()) { n, kind := a.Triangle() if n == 0 { panic(ErrZeroLength) } w = getTriDenseWorkspace(n, kind, false) return w, func() { t.Copy(w) putTriWorkspace(w) } } // DiagView returns the diagonal as a matrix backed by the original data. func (t *TriDense) DiagView() Diagonal { if t.mat.Diag == blas.Unit { panic("mat: cannot take view of Unit diagonal") } n := t.mat.N return &DiagDense{ mat: blas64.Vector{ N: n, Inc: t.mat.Stride + 1, Data: t.mat.Data[:(n-1)*t.mat.Stride+n], }, } } // Copy makes a copy of elements of a into the receiver. It is similar to the // built-in copy; it copies as much as the overlap between the two matrices and // returns the number of rows and columns it copied. Only elements within the // receiver's non-zero triangle are set. // // See the Copier interface for more information. func (t *TriDense) Copy(a Matrix) (r, c int) { r, c = a.Dims() r = min(r, t.mat.N) c = min(c, t.mat.N) if r == 0 || c == 0 { return 0, 0 } switch a := a.(type) { case RawMatrixer: amat := a.RawMatrix() if t.isUpper() { for i := 0; i < r; i++ { copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c]) } } else { for i := 0; i < r; i++ { copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1]) } } case RawTriangular: amat := a.RawTriangular() aIsUpper := isUpperUplo(amat.Uplo) tIsUpper := t.isUpper() switch { case tIsUpper && aIsUpper: for i := 0; i < r; i++ { copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c]) } case !tIsUpper && !aIsUpper: for i := 0; i < r; i++ { copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1]) } default: for i := 0; i < r; i++ { t.set(i, i, amat.Data[i*amat.Stride+i]) } } default: isUpper := t.isUpper() for i := 0; i < r; i++ { if isUpper { for j := i; j < c; j++ { t.set(i, j, a.At(i, j)) } } else { for j := 0; j <= i; j++ { t.set(i, j, a.At(i, j)) } } } } return r, c } // InverseTri computes the inverse of the triangular matrix a, storing the result // into the receiver. If a is ill-conditioned, a Condition error will be returned. // Note that matrix inversion is numerically unstable, and should generally be // avoided where possible, for example by using the Solve routines. func (t *TriDense) InverseTri(a Triangular) error { t.checkOverlapMatrix(a) n, _ := a.Triangle() t.reuseAsNonZeroed(a.Triangle()) t.Copy(a) work := getFloat64s(3*n, false) iwork := getInts(n, false) cond := lapack64.Trcon(CondNorm, t.mat, work, iwork) putFloat64s(work) putInts(iwork) if math.IsInf(cond, 1) { return Condition(cond) } ok := lapack64.Trtri(t.mat) if !ok { return Condition(math.Inf(1)) } if cond > ConditionTolerance { return Condition(cond) } return nil } // MulTri takes the product of triangular matrices a and b and places the result // in the receiver. The size of a and b must match, and they both must have the // same TriKind, or Mul will panic. func (t *TriDense) MulTri(a, b Triangular) { n, kind := a.Triangle() nb, kindb := b.Triangle() if n != nb { panic(ErrShape) } if kind != kindb { panic(ErrTriangle) } aU, _ := untransposeTri(a) bU, _ := untransposeTri(b) t.checkOverlapMatrix(bU) t.checkOverlapMatrix(aU) t.reuseAsNonZeroed(n, kind) var restore func() if t == aU { t, restore = t.isolatedWorkspace(aU) defer restore() } else if t == bU { t, restore = t.isolatedWorkspace(bU) defer restore() } // Inspect types here, helps keep the loops later clean(er). _, aDiag := aU.(Diagonal) _, bDiag := bU.(Diagonal) // If they are both diagonal only need 1 loop. // All diagonal matrices are Upper. // TODO: Add fast paths for DiagDense. if aDiag && bDiag { t.Zero() for i := 0; i < n; i++ { t.SetTri(i, i, a.At(i, i)*b.At(i, i)) } return } // Now we know at least one matrix is non-diagonal. // And all diagonal matrices are all Upper. // The both-diagonal case is handled above. // TODO: Add fast paths for Dense variants. if kind == Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { switch { case aDiag: t.SetTri(i, j, a.At(i, i)*b.At(i, j)) case bDiag: t.SetTri(i, j, a.At(i, j)*b.At(j, j)) default: var v float64 for k := i; k <= j; k++ { v += a.At(i, k) * b.At(k, j) } t.SetTri(i, j, v) } } } return } for i := 0; i < n; i++ { for j := 0; j <= i; j++ { var v float64 for k := j; k <= i; k++ { v += a.At(i, k) * b.At(k, j) } t.SetTri(i, j, v) } } } // ScaleTri multiplies the elements of a by f, placing the result in the receiver. // If the receiver is non-zero, the size and kind of the receiver must match // the input, or ScaleTri will panic. func (t *TriDense) ScaleTri(f float64, a Triangular) { n, kind := a.Triangle() t.reuseAsNonZeroed(n, kind) // TODO(btracey): Improve the set of fast-paths. switch a := a.(type) { case RawTriangular: amat := a.RawTriangular() if t != a { t.checkOverlap(generalFromTriangular(amat)) } if kind == Upper { for i := 0; i < n; i++ { ts := t.mat.Data[i*t.mat.Stride+i : i*t.mat.Stride+n] as := amat.Data[i*amat.Stride+i : i*amat.Stride+n] for i, v := range as { ts[i] = v * f } } return } for i := 0; i < n; i++ { ts := t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+i+1] as := amat.Data[i*amat.Stride : i*amat.Stride+i+1] for i, v := range as { ts[i] = v * f } } return default: t.checkOverlapMatrix(a) isUpper := kind == Upper for i := 0; i < n; i++ { if isUpper { for j := i; j < n; j++ { t.set(i, j, f*a.At(i, j)) } } else { for j := 0; j <= i; j++ { t.set(i, j, f*a.At(i, j)) } } } } } // SliceTri returns a new Triangular that shares backing data with the receiver. // The returned matrix starts at {i,i} of the receiver and extends k-i rows and // columns. The final row and column in the resulting matrix is k-1. // SliceTri panics with ErrIndexOutOfRange if the slice is outside the capacity // of the receiver. func (t *TriDense) SliceTri(i, k int) Triangular { return t.sliceTri(i, k) } func (t *TriDense) sliceTri(i, k int) *TriDense { if i < 0 || t.cap < i || k < i || t.cap < k { panic(ErrIndexOutOfRange) } v := *t v.mat.Data = t.mat.Data[i*t.mat.Stride+i : (k-1)*t.mat.Stride+k] v.mat.N = k - i v.cap = t.cap - i return &v } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the matrix has zero size. func (t *TriDense) Norm(norm float64) float64 { if t.IsEmpty() { panic(ErrZeroLength) } lnorm := normLapack(norm, false) if lnorm == lapack.MaxColumnSum { work := getFloat64s(t.mat.N, false) defer putFloat64s(work) return lapack64.Lantr(lnorm, t.mat, work) } return lapack64.Lantr(lnorm, t.mat, nil) } // Trace returns the trace of the matrix. // // Trace will panic with ErrZeroLength if the matrix has zero size. func (t *TriDense) Trace() float64 { if t.IsEmpty() { panic(ErrZeroLength) } // TODO(btracey): could use internal asm sum routine. var v float64 for i := 0; i < t.mat.N; i++ { v += t.mat.Data[i*t.mat.Stride+i] } return v } // copySymIntoTriangle copies a symmetric matrix into a TriDense func copySymIntoTriangle(t *TriDense, s Symmetric) { n, upper := t.Triangle() ns := s.SymmetricDim() if n != ns { panic("mat: triangle size mismatch") } ts := t.mat.Stride if rs, ok := s.(RawSymmetricer); ok { sd := rs.RawSymmetric() ss := sd.Stride if upper { if sd.Uplo == blas.Upper { for i := 0; i < n; i++ { copy(t.mat.Data[i*ts+i:i*ts+n], sd.Data[i*ss+i:i*ss+n]) } return } for i := 0; i < n; i++ { for j := i; j < n; j++ { t.mat.Data[i*ts+j] = sd.Data[j*ss+i] } } return } if sd.Uplo == blas.Upper { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { t.mat.Data[i*ts+j] = sd.Data[j*ss+i] } } return } for i := 0; i < n; i++ { copy(t.mat.Data[i*ts:i*ts+i+1], sd.Data[i*ss:i*ss+i+1]) } return } if upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { t.mat.Data[i*ts+j] = s.At(i, j) } } return } for i := 0; i < n; i++ { for j := 0; j <= i; j++ { t.mat.Data[i*ts+j] = s.At(i, j) } } } // DoNonZero calls the function fn for each of the non-zero elements of t. The function fn // takes a row/column index and the element value of t at (i, j). func (t *TriDense) DoNonZero(fn func(i, j int, v float64)) { if t.isUpper() { for i := 0; i < t.mat.N; i++ { for j := i; j < t.mat.N; j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } return } for i := 0; i < t.mat.N; i++ { for j := 0; j <= i; j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } } // DoRowNonZero calls the function fn for each of the non-zero elements of row i of t. The function fn // takes a row/column index and the element value of t at (i, j). func (t *TriDense) DoRowNonZero(i int, fn func(i, j int, v float64)) { if i < 0 || t.mat.N <= i { panic(ErrRowAccess) } if t.isUpper() { for j := i; j < t.mat.N; j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } return } for j := 0; j <= i; j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } // DoColNonZero calls the function fn for each of the non-zero elements of column j of t. The function fn // takes a row/column index and the element value of t at (i, j). func (t *TriDense) DoColNonZero(j int, fn func(i, j int, v float64)) { if j < 0 || t.mat.N <= j { panic(ErrColAccess) } if t.isUpper() { for i := 0; i <= j; i++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } return } for i := j; i < t.mat.N; i++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } golang-gonum-v1-gonum-0.14.0/mat/triangular_test.go000066400000000000000000000375561450372207100221750ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "math" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) func TestNewTriangular(t *testing.T) { t.Parallel() for i, test := range []struct { data []float64 n int kind TriKind mat *TriDense }{ { data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }, n: 3, kind: Upper, mat: &TriDense{ mat: blas64.Triangular{ N: 3, Stride: 3, Uplo: blas.Upper, Data: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}, Diag: blas.NonUnit, }, cap: 3, }, }, } { tri := NewTriDense(test.n, test.kind, test.data) rows, cols := tri.Dims() if rows != test.n { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.n) } if cols != test.n { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.n) } if !reflect.DeepEqual(tri, test.mat) { t.Errorf("unexpected data slice for test %d: got: %v want: %v", i, tri, test.mat) } } for _, kind := range []TriKind{Lower, Upper} { panicked, message := panics(func() { NewTriDense(3, kind, []float64{1, 2}) }) if !panicked || message != ErrShape.Error() { t.Errorf("expected panic for invalid data slice length for upper=%t", kind) } } } func TestTriAtSet(t *testing.T) { t.Parallel() tri := &TriDense{ mat: blas64.Triangular{ N: 3, Stride: 3, Uplo: blas.Upper, Data: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}, Diag: blas.NonUnit, }, cap: 3, } rows, cols := tri.Dims() // Check At out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { tri.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { tri.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } // Check Set out of bounds for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { tri.SetTri(row, 0, 1.2) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { tri.SetTri(0, col, 1.2) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } for _, st := range []struct { row, col int uplo blas.Uplo }{ {row: 2, col: 1, uplo: blas.Upper}, {row: 1, col: 2, uplo: blas.Lower}, } { tri.mat.Uplo = st.uplo panicked, message := panics(func() { tri.SetTri(st.row, st.col, 1.2) }) if !panicked || message != ErrTriangleSet.Error() { t.Errorf("expected panic for %+v", st) } } for _, st := range []struct { row, col int uplo blas.Uplo orig, new float64 }{ {row: 2, col: 1, uplo: blas.Lower, orig: 8, new: 15}, {row: 1, col: 2, uplo: blas.Upper, orig: 6, new: 15}, } { tri.mat.Uplo = st.uplo if e := tri.At(st.row, st.col); e != st.orig { t.Errorf("unexpected value for At(%d, %d): got: %v want: %v", st.row, st.col, e, st.orig) } tri.SetTri(st.row, st.col, st.new) if e := tri.At(st.row, st.col); e != st.new { t.Errorf("unexpected value for At(%d, %d) after SetTri(%[1]d, %d, %v): got: %v want: %[3]v", st.row, st.col, st.new, e) } } } func TestTriDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*TriDense{ { mat: blas64.Triangular{ Uplo: blas.Upper, N: 4, Stride: 5, Data: []float64{ 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, }, }, }, { mat: blas64.Triangular{ Uplo: blas.Lower, N: 4, Stride: 5, Data: []float64{ 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } func TestTriDiagView(t *testing.T) { t.Parallel() for cas, test := range []*TriDense{ NewTriDense(1, Upper, []float64{1}), NewTriDense(2, Upper, []float64{1, 2, 0, 3}), NewTriDense(3, Upper, []float64{1, 2, 3, 0, 4, 5, 0, 0, 6}), NewTriDense(1, Lower, []float64{1}), NewTriDense(2, Lower, []float64{1, 2, 2, 3}), NewTriDense(3, Lower, []float64{1, 0, 0, 2, 3, 0, 4, 5, 6}), } { testDiagView(t, cas, test) } } func TestTriDenseCopy(t *testing.T) { t.Parallel() src := rand.NewSource(1) rnd := rand.New(src) for i := 0; i < 100; i++ { size := rnd.Intn(100) r, err := randDense(size, 0.9, src) if size == 0 { if err != ErrZeroLength { t.Fatalf("expected error %v: got: %v", ErrZeroLength, err) } continue } if err != nil { t.Fatalf("unexpected error: %v", err) } u := NewTriDense(size, true, nil) l := NewTriDense(size, false, nil) for _, typ := range []Matrix{r, (*basicMatrix)(r)} { for j := range u.mat.Data { u.mat.Data[j] = math.NaN() l.mat.Data[j] = math.NaN() } u.Copy(typ) l.Copy(typ) for m := 0; m < size; m++ { for n := 0; n < size; n++ { want := typ.At(m, n) switch { case m < n: // Upper triangular matrix. if got := u.At(m, n); got != want { t.Errorf("unexpected upper value for At(%d, %d) for test %d: got: %v want: %v", m, n, i, got, want) } case m == n: // Diagonal matrix. if got := u.At(m, n); got != want { t.Errorf("unexpected upper value for At(%d, %d) for test %d: got: %v want: %v", m, n, i, got, want) } if got := l.At(m, n); got != want { t.Errorf("unexpected diagonal value for At(%d, %d) for test %d: got: %v want: %v", m, n, i, got, want) } case m > n: // Lower triangular matrix. if got := l.At(m, n); got != want { t.Errorf("unexpected lower value for At(%d, %d) for test %d: got: %v want: %v", m, n, i, got, want) } } } } } } } func TestTriTriDenseCopy(t *testing.T) { t.Parallel() src := rand.NewSource(1) rnd := rand.New(src) for i := 0; i < 100; i++ { size := rnd.Intn(100) r, err := randDense(size, 1, src) if size == 0 { if err != ErrZeroLength { t.Fatalf("expected error %v: got: %v", ErrZeroLength, err) } continue } if err != nil { t.Fatalf("unexpected error: %v", err) } ur := NewTriDense(size, true, nil) lr := NewTriDense(size, false, nil) ur.Copy(r) lr.Copy(r) u := NewTriDense(size, true, nil) u.Copy(ur) if !equal(u, ur) { t.Fatal("unexpected result for U triangle copy of U triangle: not equal") } l := NewTriDense(size, false, nil) l.Copy(lr) if !equal(l, lr) { t.Fatal("unexpected result for L triangle copy of L triangle: not equal") } zero(u.mat.Data) u.Copy(lr) if !isDiagonal(u) { t.Fatal("unexpected result for U triangle copy of L triangle: off diagonal non-zero element") } if !equalDiagonal(u, lr) { t.Fatal("unexpected result for U triangle copy of L triangle: diagonal not equal") } zero(l.mat.Data) l.Copy(ur) if !isDiagonal(l) { t.Fatal("unexpected result for L triangle copy of U triangle: off diagonal non-zero element") } if !equalDiagonal(l, ur) { t.Fatal("unexpected result for L triangle copy of U triangle: diagonal not equal") } } } func TestTriInverse(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for _, kind := range []TriKind{Upper, Lower} { for _, n := range []int{1, 3, 5, 9} { data := make([]float64, n*n) for i := range data { data[i] = rnd.NormFloat64() } a := NewTriDense(n, kind, data) var tr TriDense err := tr.InverseTri(a) if err != nil { t.Errorf("Bad test: %s", err) } var d Dense d.Mul(a, &tr) if !equalApprox(eye(n), &d, 1e-8, false) { var diff Dense diff.Sub(eye(n), &d) t.Errorf("Tri times inverse is not identity. Norm of difference: %v", Norm(&diff, 2)) } } } } func TestTriMul(t *testing.T) { t.Parallel() method := func(receiver, a, b Matrix) { type MulTrier interface { MulTri(a, b Triangular) } receiver.(MulTrier).MulTri(a.(Triangular), b.(Triangular)) } denseComparison := func(receiver, a, b *Dense) { receiver.Mul(a, b) } legalSizeTriMul := func(ar, ac, br, bc int) bool { // Need both to be square and the sizes to be the same return ar == ac && br == bc && ar == br } // The legal types are triangles with the same TriKind. // legalTypesTri returns whether both input arguments are Triangular. legalTypes := func(a, b Matrix) bool { at, ok := a.(Triangular) if !ok { return false } bt, ok := b.(Triangular) if !ok { return false } _, ak := at.Triangle() _, bk := bt.Triangle() return ak == bk } legalTypesLower := func(a, b Matrix) bool { legal := legalTypes(a, b) if !legal { return false } _, kind := a.(Triangular).Triangle() r := kind == Lower return r } receiver := NewTriDense(3, Lower, nil) testTwoInput(t, "TriMul", receiver, method, denseComparison, legalTypesLower, legalSizeTriMul, 1e-14) legalTypesUpper := func(a, b Matrix) bool { legal := legalTypes(a, b) if !legal { return false } _, kind := a.(Triangular).Triangle() r := kind == Upper return r } receiver = NewTriDense(3, Upper, nil) testTwoInput(t, "TriMul", receiver, method, denseComparison, legalTypesUpper, legalSizeTriMul, 1e-14) } func TestScaleTri(t *testing.T) { t.Parallel() for _, f := range []float64{0.5, 1, 3} { method := func(receiver, a Matrix) { type ScaleTrier interface { ScaleTri(f float64, a Triangular) } rd := receiver.(ScaleTrier) rd.ScaleTri(f, a.(Triangular)) } denseComparison := func(receiver, a *Dense) { receiver.Scale(f, a) } testOneInput(t, "ScaleTriUpper", NewTriDense(3, Upper, nil), method, denseComparison, legalTypeTriUpper, isSquare, 1e-14) testOneInput(t, "ScaleTriLower", NewTriDense(3, Lower, nil), method, denseComparison, legalTypeTriLower, isSquare, 1e-14) } } func TestCopySymIntoTriangle(t *testing.T) { t.Parallel() nan := math.NaN() for tc, test := range []struct { n int sUplo blas.Uplo s []float64 tUplo TriKind want []float64 }{ { n: 3, sUplo: blas.Upper, s: []float64{ 1, 2, 3, nan, 4, 5, nan, nan, 6, }, tUplo: Upper, want: []float64{ 1, 2, 3, 0, 4, 5, 0, 0, 6, }, }, { n: 3, sUplo: blas.Lower, s: []float64{ 1, nan, nan, 2, 3, nan, 4, 5, 6, }, tUplo: Upper, want: []float64{ 1, 2, 4, 0, 3, 5, 0, 0, 6, }, }, { n: 3, sUplo: blas.Upper, s: []float64{ 1, 2, 3, nan, 4, 5, nan, nan, 6, }, tUplo: Lower, want: []float64{ 1, 0, 0, 2, 4, 0, 3, 5, 6, }, }, { n: 3, sUplo: blas.Lower, s: []float64{ 1, nan, nan, 2, 3, nan, 4, 5, 6, }, tUplo: Lower, want: []float64{ 1, 0, 0, 2, 3, 0, 4, 5, 6, }, }, } { n := test.n s := NewSymDense(n, test.s) // For the purpose of the test, break the assumption that // symmetric is stored in the upper triangle (only when S is // RawSymmetricer). s.mat.Uplo = test.sUplo t1 := NewTriDense(n, test.tUplo, nil) copySymIntoTriangle(t1, s) equal := true loop1: for i := 0; i < n; i++ { for j := 0; j < n; j++ { if t1.At(i, j) != test.want[i*n+j] { equal = false break loop1 } } } if !equal { t.Errorf("Case %v: unexpected T when S is RawSymmetricer", tc) } if test.sUplo == blas.Lower { continue } sb := (basicSymmetric)(*s) t2 := NewTriDense(n, test.tUplo, nil) copySymIntoTriangle(t2, &sb) equal = true loop2: for i := 0; i < n; i++ { for j := 0; j < n; j++ { if t1.At(i, j) != test.want[i*n+j] { equal = false break loop2 } } } if !equal { t.Errorf("Case %v: unexpected T when S is not RawSymmetricer", tc) } } } func TestTriSliceTri(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { n, start1, span1, start2, span2 int }{ {10, 0, 10, 0, 10}, {10, 0, 8, 0, 8}, {10, 2, 8, 0, 6}, {10, 2, 7, 4, 2}, {10, 2, 6, 0, 5}, {10, 2, 3, 1, 7}, } { n := test.n for _, kind := range []TriKind{Upper, Lower} { tri := NewTriDense(n, kind, nil) if kind == Upper { for i := 0; i < n; i++ { for j := i; j < n; j++ { tri.SetTri(i, j, rnd.Float64()) } } } else { for i := 0; i < n; i++ { for j := 0; j <= i; j++ { tri.SetTri(i, j, rnd.Float64()) } } } start1 := test.start1 span1 := test.span1 v1 := tri.SliceTri(start1, start1+span1).(*TriDense) if kind == Upper { for i := 0; i < span1; i++ { for j := i; j < span1; j++ { if v1.At(i, j) != tri.At(start1+i, start1+j) { t.Errorf("Case %d,upper: view mismatch at %v,%v", cas, i, j) } } } } else { for i := 0; i < span1; i++ { for j := 0; j <= i; j++ { if v1.At(i, j) != tri.At(start1+i, start1+j) { t.Errorf("Case %d,lower: view mismatch at %v,%v", cas, i, j) } } } } start2 := test.start2 span2 := test.span2 v2 := v1.SliceTri(start2, start2+span2).(*TriDense) if kind == Upper { for i := 0; i < span2; i++ { for j := i; j < span2; j++ { if v2.At(i, j) != tri.At(start1+start2+i, start1+start2+j) { t.Errorf("Case %d,upper: second view mismatch at %v,%v", cas, i, j) } } } } else { for i := 0; i < span1; i++ { for j := 0; j <= i; j++ { if v1.At(i, j) != tri.At(start1+i, start1+j) { t.Errorf("Case %d,lower: second view mismatch at %v,%v", cas, i, j) } } } } v2.SetTri(span2-1, span2-1, -123.45) if tri.At(start1+start2+span2-1, start1+start2+span2-1) != -123.45 { t.Errorf("Case %d: write to view not reflected in original", cas) } } } } var triSumForBench float64 func BenchmarkTriSum(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for n := 100; n <= 1600; n *= 2 { a := randTriDense(n, rnd) b.Run(fmt.Sprintf("BenchmarkTriSum%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { triSumForBench = Sum(a) } }) } } var triProductForBench *TriDense func BenchmarkTriMul(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for n := 100; n <= 1600; n *= 2 { triProductForBench = NewTriDense(n, Upper, nil) a := randTriDense(n, rnd) c := randTriDense(n, rnd) b.Run(fmt.Sprintf("BenchmarkTriMul%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { triProductForBench.MulTri(a, c) } }) } } func BenchmarkTriMulDiag(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for n := 100; n <= 1600; n *= 2 { triProductForBench = NewTriDense(n, Upper, nil) a := randTriDense(n, rnd) c := randDiagDense(n, rnd) b.Run(fmt.Sprintf("BenchmarkTriMulDiag%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { triProductForBench.MulTri(a, c) } }) } } func BenchmarkTriMul2Diag(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for n := 100; n <= 1600; n *= 2 { triProductForBench = NewTriDense(n, Upper, nil) a := randDiagDense(n, rnd) c := randDiagDense(n, rnd) b.Run(fmt.Sprintf("BenchmarkTriMul2Diag%d", n), func(b *testing.B) { for i := 0; i < b.N; i++ { triProductForBench.MulTri(a, c) } }) } } func randTriDense(size int, rnd *rand.Rand) *TriDense { t := NewTriDense(size, Upper, nil) for i := 0; i < size; i++ { for j := i; j < size; j++ { t.SetTri(i, j, rnd.Float64()) } } return t } golang-gonum-v1-gonum-0.14.0/mat/triband.go000066400000000000000000000446601450372207100204030ustar00rootroot00000000000000// 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 mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack/lapack64" ) var ( triBand TriBanded _ Banded = triBand _ Triangular = triBand triBandDense *TriBandDense _ Matrix = triBandDense _ allMatrix = triBandDense _ denseMatrix = triBandDense _ Triangular = triBandDense _ Banded = triBandDense _ TriBanded = triBandDense _ RawTriBander = triBandDense _ MutableTriBanded = triBandDense ) // TriBanded is a triangular band matrix interface type. type TriBanded interface { Banded // Triangle returns the number of rows/columns in the matrix and its // orientation. Triangle() (n int, kind TriKind) // TTri is the equivalent of the T() method in the Matrix interface but // guarantees the transpose is of triangular type. TTri() Triangular // TriBand returns the number of rows/columns in the matrix, the // size of the bandwidth, and the orientation. TriBand() (n, k int, kind TriKind) // TTriBand is the equivalent of the T() method in the Matrix interface but // guarantees the transpose is of banded triangular type. TTriBand() TriBanded } // A RawTriBander can return a blas64.TriangularBand representation of the receiver. // Changes to the blas64.TriangularBand.Data slice will be reflected in the original // matrix, changes to the N, K, Stride, Uplo and Diag fields will not. type RawTriBander interface { RawTriBand() blas64.TriangularBand } // MutableTriBanded is a triangular band matrix interface type that allows // elements to be altered. type MutableTriBanded interface { TriBanded SetTriBand(i, j int, v float64) } var ( tTriBand TransposeTriBand _ Matrix = tTriBand _ TriBanded = tTriBand _ Untransposer = tTriBand _ UntransposeTrier = tTriBand _ UntransposeBander = tTriBand _ UntransposeTriBander = tTriBand ) // TransposeTriBand is a type for performing an implicit transpose of a TriBanded // matrix. It implements the TriBanded interface, returning values from the // transpose of the matrix within. type TransposeTriBand struct { TriBanded TriBanded } // At returns the value of the element at row i and column j of the transposed // matrix, that is, row j and column i of the TriBanded field. func (t TransposeTriBand) At(i, j int) float64 { return t.TriBanded.At(j, i) } // Dims returns the dimensions of the transposed matrix. TriBanded matrices are // square and thus this is the same size as the original TriBanded. func (t TransposeTriBand) Dims() (r, c int) { c, r = t.TriBanded.Dims() return r, c } // T performs an implicit transpose by returning the TriBand field. func (t TransposeTriBand) T() Matrix { return t.TriBanded } // Triangle returns the number of rows/columns in the matrix and its orientation. func (t TransposeTriBand) Triangle() (int, TriKind) { n, upper := t.TriBanded.Triangle() return n, !upper } // TTri performs an implicit transpose by returning the TriBand field. func (t TransposeTriBand) TTri() Triangular { return t.TriBanded } // Bandwidth returns the upper and lower bandwidths of the matrix. func (t TransposeTriBand) Bandwidth() (kl, ku int) { kl, ku = t.TriBanded.Bandwidth() return ku, kl } // TBand performs an implicit transpose by returning the TriBand field. func (t TransposeTriBand) TBand() Banded { return t.TriBanded } // TriBand returns the number of rows/columns in the matrix, the // size of the bandwidth, and the orientation. func (t TransposeTriBand) TriBand() (n, k int, kind TriKind) { n, k, kind = t.TriBanded.TriBand() return n, k, !kind } // TTriBand performs an implicit transpose by returning the TriBand field. func (t TransposeTriBand) TTriBand() TriBanded { return t.TriBanded } // Untranspose returns the Triangular field. func (t TransposeTriBand) Untranspose() Matrix { return t.TriBanded } // UntransposeTri returns the underlying Triangular matrix. func (t TransposeTriBand) UntransposeTri() Triangular { return t.TriBanded } // UntransposeBand returns the underlying Banded matrix. func (t TransposeTriBand) UntransposeBand() Banded { return t.TriBanded } // UntransposeTriBand returns the underlying TriBanded matrix. func (t TransposeTriBand) UntransposeTriBand() TriBanded { return t.TriBanded } // TriBandDense represents a triangular band matrix in dense storage format. type TriBandDense struct { mat blas64.TriangularBand } // NewTriBandDense creates a new triangular banded matrix with n rows and columns, // k bands in the direction of the specified kind. If data == nil, // a new slice is allocated for the backing slice. If len(data) == n*(k+1), // data is used as the backing slice, and changes to the elements of the returned // TriBandDense will be reflected in data. If neither of these is true, NewTriBandDense // will panic. k must be at least zero and less than n, otherwise NewTriBandDense will panic. // // The data must be arranged in row-major order constructed by removing the zeros // from the rows outside the band and aligning the diagonals. For example, if // the upper-triangular banded matrix // // 1 2 3 0 0 0 // 0 4 5 6 0 0 // 0 0 7 8 9 0 // 0 0 0 10 11 12 // 0 0 0 0 13 14 // 0 0 0 0 0 15 // // becomes (* entries are never accessed) // // 1 2 3 // 4 5 6 // 7 8 9 // 10 11 12 // 13 14 * // 15 * * // // which is passed to NewTriBandDense as []float64{1, 2, ..., 15, *, *, *} // with k=2 and kind = mat.Upper. // The lower triangular banded matrix // // 1 0 0 0 0 0 // 2 3 0 0 0 0 // 4 5 6 0 0 0 // 0 7 8 9 0 0 // 0 0 10 11 12 0 // 0 0 0 13 14 15 // // becomes (* entries are never accessed) // - * 1 // - 2 3 // 4 5 6 // 7 8 9 // 10 11 12 // 13 14 15 // // which is passed to NewTriBandDense as []float64{*, *, *, 1, 2, ..., 15} // with k=2 and kind = mat.Lower. // Only the values in the band portion of the matrix are used. func NewTriBandDense(n, k int, kind TriKind, data []float64) *TriBandDense { if n <= 0 || k < 0 { if n == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if k+1 > n { panic(ErrBandwidth) } bc := k + 1 if data != nil && len(data) != n*bc { panic(ErrShape) } if data == nil { data = make([]float64, n*bc) } uplo := blas.Lower if kind { uplo = blas.Upper } return &TriBandDense{ mat: blas64.TriangularBand{ Uplo: uplo, Diag: blas.NonUnit, N: n, K: k, Data: data, Stride: bc, }, } } // Dims returns the number of rows and columns in the matrix. func (t *TriBandDense) Dims() (r, c int) { return t.mat.N, t.mat.N } // T performs an implicit transpose by returning the receiver inside a Transpose. func (t *TriBandDense) T() Matrix { return Transpose{t} } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (t *TriBandDense) IsEmpty() bool { // It must be the case that t.Dims() returns // zeros in this case. See comment in Reset(). return t.mat.Stride == 0 } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (t *TriBandDense) Reset() { t.mat.N = 0 t.mat.Stride = 0 t.mat.K = 0 t.mat.Data = t.mat.Data[:0] } // ReuseAsTriBand changes the receiver to be of size n×n, bandwidth k+1 and of // the given kind, re-using the backing data slice if it has sufficient capacity // and allocating a new slice otherwise. The backing data is zero on return. // // The receiver must be empty, n must be positive and k must be non-negative and // less than n, otherwise ReuseAsTriBand will panic. To empty the receiver for // re-use, Reset should be used. func (t *TriBandDense) ReuseAsTriBand(n, k int, kind TriKind) { if n <= 0 || k < 0 { if n == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if k+1 > n { panic(ErrBandwidth) } if !t.IsEmpty() { panic(ErrReuseNonEmpty) } t.reuseAsZeroed(n, k, kind) } // reuseAsZeroed resizes an empty receiver to an n×n triangular band matrix with // the given bandwidth and orientation. If the receiver is not empty, // reuseAsZeroed checks that the receiver has the correct size, bandwidth and // orientation. It then zeros out the matrix data. func (t *TriBandDense) reuseAsZeroed(n, k int, kind TriKind) { // reuseAsZeroed must be kept in sync with reuseAsNonZeroed. if n == 0 { panic(ErrZeroLength) } ul := blas.Lower if kind == Upper { ul = blas.Upper } if t.IsEmpty() { t.mat = blas64.TriangularBand{ Uplo: ul, Diag: blas.NonUnit, N: n, K: k, Data: useZeroed(t.mat.Data, n*(k+1)), Stride: k + 1, } return } if t.mat.N != n || t.mat.K != k { panic(ErrShape) } if t.mat.Uplo != ul { panic(ErrTriangle) } t.Zero() } // reuseAsNonZeroed resizes an empty receiver to an n×n triangular band matrix // with the given bandwidth and orientation. If the receiver is not empty, // reuseAsZeroed checks that the receiver has the correct size, bandwidth and // orientation. // //lint:ignore U1000 This will be used later. func (t *TriBandDense) reuseAsNonZeroed(n, k int, kind TriKind) { // reuseAsNonZeroed must be kept in sync with reuseAsZeroed. if n == 0 { panic(ErrZeroLength) } ul := blas.Lower if kind == Upper { ul = blas.Upper } if t.IsEmpty() { t.mat = blas64.TriangularBand{ Uplo: ul, Diag: blas.NonUnit, N: n, K: k, Data: use(t.mat.Data, n*(k+1)), Stride: k + 1, } return } if t.mat.N != n || t.mat.K != k { panic(ErrShape) } if t.mat.Uplo != ul { panic(ErrTriangle) } } // DoNonZero calls the function fn for each of the non-zero elements of t. The function fn // takes a row/column index and the element value of t at (i, j). func (t *TriBandDense) DoNonZero(fn func(i, j int, v float64)) { if t.isUpper() { for i := 0; i < t.mat.N; i++ { for j := i; j < min(i+t.mat.K+1, t.mat.N); j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } } else { for i := 0; i < t.mat.N; i++ { for j := max(0, i-t.mat.K); j <= i; j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } } } // DoRowNonZero calls the function fn for each of the non-zero elements of row i of t. The function fn // takes a row/column index and the element value of t at (i, j). func (t *TriBandDense) DoRowNonZero(i int, fn func(i, j int, v float64)) { if i < 0 || t.mat.N <= i { panic(ErrRowAccess) } if t.isUpper() { for j := i; j < min(i+t.mat.K+1, t.mat.N); j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } else { for j := max(0, i-t.mat.K); j <= i; j++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } } // DoColNonZero calls the function fn for each of the non-zero elements of column j of t. The function fn // takes a row/column index and the element value of t at (i, j). func (t *TriBandDense) DoColNonZero(j int, fn func(i, j int, v float64)) { if j < 0 || t.mat.N <= j { panic(ErrColAccess) } if t.isUpper() { for i := 0; i < t.mat.N; i++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } else { for i := 0; i < t.mat.N; i++ { v := t.at(i, j) if v != 0 { fn(i, j, v) } } } } // Zero sets all of the matrix elements to zero. func (t *TriBandDense) Zero() { if t.isUpper() { for i := 0; i < t.mat.N; i++ { u := min(1+t.mat.K, t.mat.N-i) zero(t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+u]) } return } for i := 0; i < t.mat.N; i++ { l := max(0, t.mat.K-i) zero(t.mat.Data[i*t.mat.Stride+l : i*t.mat.Stride+t.mat.K+1]) } } func (t *TriBandDense) isUpper() bool { return isUpperUplo(t.mat.Uplo) } func (t *TriBandDense) triKind() TriKind { return TriKind(isUpperUplo(t.mat.Uplo)) } // Triangle returns the dimension of t and its orientation. The returned // orientation is only valid when n is not zero. func (t *TriBandDense) Triangle() (n int, kind TriKind) { return t.mat.N, t.triKind() } // TTri performs an implicit transpose by returning the receiver inside a TransposeTri. func (t *TriBandDense) TTri() Triangular { return TransposeTri{t} } // Bandwidth returns the upper and lower bandwidths of the matrix. func (t *TriBandDense) Bandwidth() (kl, ku int) { if t.isUpper() { return 0, t.mat.K } return t.mat.K, 0 } // TBand performs an implicit transpose by returning the receiver inside a TransposeBand. func (t *TriBandDense) TBand() Banded { return TransposeBand{t} } // TriBand returns the number of rows/columns in the matrix, the // size of the bandwidth, and the orientation. func (t *TriBandDense) TriBand() (n, k int, kind TriKind) { return t.mat.N, t.mat.K, TriKind(!t.IsEmpty()) && t.triKind() } // TTriBand performs an implicit transpose by returning the receiver inside a TransposeTriBand. func (t *TriBandDense) TTriBand() TriBanded { return TransposeTriBand{t} } // RawTriBand returns the underlying blas64.TriangularBand used by the receiver. // Changes to the blas64.TriangularBand.Data slice will be reflected in the original // matrix, changes to the N, K, Stride, Uplo and Diag fields will not. func (t *TriBandDense) RawTriBand() blas64.TriangularBand { return t.mat } // SetRawTriBand sets the underlying blas64.TriangularBand used by the receiver. // Changes to elements in the receiver following the call will be reflected // in the input. // // The supplied TriangularBand must not use blas.Unit storage format. func (t *TriBandDense) SetRawTriBand(mat blas64.TriangularBand) { if mat.Diag == blas.Unit { panic("mat: cannot set TriBand with Unit storage") } t.mat = mat } // DiagView returns the diagonal as a matrix backed by the original data. func (t *TriBandDense) DiagView() Diagonal { if t.mat.Diag == blas.Unit { panic("mat: cannot take view of Unit diagonal") } n := t.mat.N data := t.mat.Data if !t.isUpper() { data = data[t.mat.K:] } return &DiagDense{ mat: blas64.Vector{ N: n, Inc: t.mat.Stride, Data: data[:(n-1)*t.mat.Stride+1], }, } } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the matrix has zero size. func (t *TriBandDense) Norm(norm float64) float64 { if t.IsEmpty() { panic(ErrZeroLength) } lnorm := normLapack(norm, false) if lnorm == lapack.MaxColumnSum { work := getFloat64s(t.mat.N, false) defer putFloat64s(work) return lapack64.Lantb(lnorm, t.mat, work) } return lapack64.Lantb(lnorm, t.mat, nil) } // Trace returns the trace of the matrix. // // Trace will panic with ErrZeroLength if the matrix has zero size. func (t *TriBandDense) Trace() float64 { if t.IsEmpty() { panic(ErrZeroLength) } rb := t.RawTriBand() var tr float64 var offsetIndex int if rb.Uplo == blas.Lower { offsetIndex = rb.K } for i := 0; i < rb.N; i++ { tr += rb.Data[offsetIndex+i*rb.Stride] } return tr } // SolveTo solves a triangular system T * X = B or Tᵀ * X = B where T is an // n×n triangular band matrix represented by the receiver and B is a given // n×nrhs matrix. If T is non-singular, the result will be stored into dst and // nil will be returned. If T is singular, the contents of dst will be undefined // and a Condition error will be returned. func (t *TriBandDense) SolveTo(dst *Dense, trans bool, b Matrix) error { n, nrhs := b.Dims() if n != t.mat.N { panic(ErrShape) } if b, ok := b.(RawMatrixer); ok && dst != b { dst.checkOverlap(b.RawMatrix()) } dst.reuseAsNonZeroed(n, nrhs) if dst != b { dst.Copy(b) } var ok bool if trans { ok = lapack64.Tbtrs(blas.Trans, t.mat, dst.mat) } else { ok = lapack64.Tbtrs(blas.NoTrans, t.mat, dst.mat) } if !ok { return Condition(math.Inf(1)) } return nil } // SolveVecTo solves a triangular system T * x = b or Tᵀ * x = b where T is an // n×n triangular band matrix represented by the receiver and b is a given // n-vector. If T is non-singular, the result will be stored into dst and nil // will be returned. If T is singular, the contents of dst will be undefined and // a Condition error will be returned. func (t *TriBandDense) SolveVecTo(dst *VecDense, trans bool, b Vector) error { n, nrhs := b.Dims() if n != t.mat.N || nrhs != 1 { panic(ErrShape) } if b, ok := b.(RawVectorer); ok && dst != b { dst.checkOverlap(b.RawVector()) } dst.reuseAsNonZeroed(n) if dst != b { dst.CopyVec(b) } var ok bool if trans { ok = lapack64.Tbtrs(blas.Trans, t.mat, dst.asGeneral()) } else { ok = lapack64.Tbtrs(blas.NoTrans, t.mat, dst.asGeneral()) } if !ok { return Condition(math.Inf(1)) } return nil } func copySymBandIntoTriBand(dst *TriBandDense, s SymBanded) { n, k, upper := dst.TriBand() ns, ks := s.SymBand() if n != ns { panic("mat: triangle size mismatch") } if k != ks { panic("mat: triangle bandwidth mismatch") } // TODO(vladimir-ch): implement the missing cases below as needed. t := dst.mat sU, _ := untransposeExtract(s) if sbd, ok := sU.(*SymBandDense); ok { s := sbd.RawSymBand() if upper { if s.Uplo == blas.Upper { // dst is upper triangular, s is stored in upper triangle. for i := 0; i < n; i++ { ilen := min(k+1, n-i) copy(t.Data[i*t.Stride:i*t.Stride+ilen], s.Data[i*s.Stride:i*s.Stride+ilen]) } } else { // dst is upper triangular, s is stored in lower triangle. // // The following is a possible implementation for this case but // is commented out due to lack of test coverage. // for i := 0; i < n; i++ { // ilen := min(k+1, n-i) // for j := 0; j < ilen; j++ { // t.Data[i*t.Stride+j] = s.Data[(i+j)*s.Stride+k-j] // } // } panic("not implemented") } } else { if s.Uplo == blas.Upper { // dst is lower triangular, s is stored in upper triangle. panic("not implemented") } else { // dst is lower triangular, s is stored in lower triangle. panic("not implemented") } } return } if upper { for i := 0; i < n; i++ { ilen := min(k+1, n-i) for j := 0; j < ilen; j++ { t.Data[i*t.Stride+j] = s.At(i, i+j) } } } else { panic("not implemented") } } golang-gonum-v1-gonum-0.14.0/mat/triband_test.go000066400000000000000000000302401450372207100214270ustar00rootroot00000000000000// 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 mat import ( "fmt" "reflect" "testing" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" ) func TestNewTriBand(t *testing.T) { t.Parallel() for cas, test := range []struct { data []float64 n, k int kind TriKind mat *TriBandDense dense *Dense }{ { data: []float64{1, 2, 3}, n: 3, k: 0, kind: Upper, mat: &TriBandDense{ mat: blas64.TriangularBand{ Diag: blas.NonUnit, Uplo: blas.Upper, N: 3, K: 0, Data: []float64{1, 2, 3}, Stride: 1, }, }, dense: NewDense(3, 3, []float64{ 1, 0, 0, 0, 2, 0, 0, 0, 3, }), }, { data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, }, n: 6, k: 1, kind: Upper, mat: &TriBandDense{ mat: blas64.TriangularBand{ Diag: blas.NonUnit, Uplo: blas.Upper, N: 6, K: 1, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, }, Stride: 2, }, }, dense: NewDense(6, 6, []float64{ 1, 2, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 11, }), }, { data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 15, -1, -1, }, n: 6, k: 2, kind: Upper, mat: &TriBandDense{ mat: blas64.TriangularBand{ Diag: blas.NonUnit, Uplo: blas.Upper, N: 6, K: 2, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 15, -1, -1, }, Stride: 3, }, }, dense: NewDense(6, 6, []float64{ 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 13, 14, 0, 0, 0, 0, 0, 15, }), }, { data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }, n: 6, k: 1, kind: Lower, mat: &TriBandDense{ mat: blas64.TriangularBand{ Diag: blas.NonUnit, Uplo: blas.Lower, N: 6, K: 1, Data: []float64{ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }, Stride: 2, }, }, dense: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 10, 11, }), }, { data: []float64{ -1, -1, 1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, }, n: 6, k: 2, kind: Lower, mat: &TriBandDense{ mat: blas64.TriangularBand{ Diag: blas.NonUnit, Uplo: blas.Lower, N: 6, K: 2, Data: []float64{ -1, -1, 1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, }, Stride: 3, }, }, dense: NewDense(6, 6, []float64{ 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 13, 14, 15, }), }, } { triBand := NewTriBandDense(test.n, test.k, test.kind, test.data) r, c := triBand.Dims() n, k, kind := triBand.TriBand() if n != test.n { t.Errorf("unexpected triband size for test %d: got: %d want: %d", cas, n, test.n) } if k != test.k { t.Errorf("unexpected triband bandwidth for test %d: got: %d want: %d", cas, k, test.k) } if kind != test.kind { t.Errorf("unexpected triband bandwidth for test %v: got: %v want: %v", cas, kind, test.kind) } if r != n { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", cas, r, n) } if c != n { t.Errorf("unexpected number of cols for test %d: got: %d want: %d", cas, c, n) } if !reflect.DeepEqual(triBand, test.mat) { t.Errorf("unexpected value via reflect for test %d: got: %v want: %v", cas, triBand, test.mat) } if !Equal(triBand, test.mat) { t.Errorf("unexpected value via mat.Equal for test %d: got: %v want: %v", cas, triBand, test.mat) } if !Equal(triBand, test.dense) { t.Errorf("unexpected value via mat.Equal(band, dense) for test %d:\ngot:\n% v\nwant:\n% v", cas, Formatted(triBand), Formatted(test.dense)) } } } func TestTriBandAtSetUpper(t *testing.T) { t.Parallel() for _, kind := range []TriKind{Upper, Lower} { var band *TriBandDense var data []float64 if kind { // 1 2 3 0 0 0 // 0 4 5 6 0 0 // 0 0 7 8 9 0 // 0 0 0 10 11 12 // 0 0 0 0 13 14 // 0 0 0 0 0 15 data = []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 15, -1, -1, } band = NewTriBandDense(6, 2, kind, data) } else { // 1 0 0 0 0 0 // 2 3 0 0 0 0 // 4 5 6 0 0 0 // 0 7 8 9 0 0 // 0 0 10 11 12 0 // 0 0 0 13 14 15 data = []float64{ -1, -1, 1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, } band = NewTriBandDense(6, 2, kind, data) } rows, cols := band.Dims() // Check At out of bounds. for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { band.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { band.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } // Check Set out of bounds // First, check outside the matrix bounds. for _, row := range []int{-1, rows, rows + 1} { panicked, message := panics(func() { band.SetTriBand(row, 0, 1.2) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) } } for _, col := range []int{-1, cols, cols + 1} { panicked, message := panics(func() { band.SetTriBand(0, col, 1.2) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) } } // Next, check outside the Triangular bounds. for _, s := range []struct{ r, c int }{ {3, 2}, } { if kind == Lower { s.r, s.c = s.c, s.r } panicked, message := panics(func() { band.SetTriBand(s.r, s.c, 1.2) }) if !panicked || message != ErrTriangleSet.Error() { t.Errorf("expected panic for invalid triangular access N=%d, r=%d c=%d", cols, s.r, s.c) } } // Finally, check inside the triangle, but outside the band. for _, s := range []struct{ r, c int }{ {1, 5}, } { if kind == Lower { s.r, s.c = s.c, s.r } panicked, message := panics(func() { band.SetTriBand(s.r, s.c, 1.2) }) if !panicked || message != ErrBandSet.Error() { t.Errorf("expected panic for invalid triangular access N=%d, r=%d c=%d", cols, s.r, s.c) } } // Test that At and Set work correctly. offset := 100.0 dataCopy := make([]float64, len(data)) copy(dataCopy, data) for i := 0; i < rows; i++ { for j := 0; j < rows; j++ { v := band.At(i, j) if v != 0 { band.SetTriBand(i, j, v+offset) } } } for i, v := range dataCopy { if v == -1 { if data[i] != -1 { t.Errorf("Set changed unexpected entry. Want %v, got %v", -1, data[i]) } } else { if v != data[i]-offset { t.Errorf("Set incorrectly changed for %v. got %v, want %v", v, data[i], v+offset) } } } } } func TestTriBandDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*TriBandDense{ { mat: blas64.TriangularBand{ Uplo: blas.Upper, N: 6, K: 2, Stride: 5, Data: []float64{ 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, }, }, }, { mat: blas64.TriangularBand{ Uplo: blas.Lower, N: 6, K: 2, Stride: 5, Data: []float64{ -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } func TestTriBandDiagView(t *testing.T) { t.Parallel() for cas, test := range []*TriBandDense{ NewTriBandDense(1, 0, Upper, []float64{1}), NewTriBandDense(4, 0, Upper, []float64{1, 2, 3, 4}), NewTriBandDense(6, 2, Upper, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 15, -1, -1, }), NewTriBandDense(1, 0, Lower, []float64{1}), NewTriBandDense(4, 0, Lower, []float64{1, 2, 3, 4}), NewTriBandDense(6, 2, Lower, []float64{ -1, -1, 1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, }), } { testDiagView(t, cas, test) } } func TestTriBandDenseSolveTo(t *testing.T) { t.Parallel() const tol = 1e-15 for tc, test := range []struct { a *TriBandDense b *Dense }{ { a: NewTriBandDense(5, 2, Upper, []float64{ -0.34, -0.49, -0.51, -0.25, -0.5, 1.03, -1.1, 0.3, -0.82, 1.69, 0.69, -2.22, -0.62, 1.22, -0.85, }), b: NewDense(5, 2, []float64{ 0.44, 1.34, 0.07, -1.45, -0.32, -0.88, -0.09, -0.15, -1.17, -0.19, }), }, { a: NewTriBandDense(5, 2, Lower, []float64{ 0, 0, -0.34, 0, -0.49, -0.25, -0.51, -0.5, -1.1, 1.03, 0.3, 1.69, -0.82, 0.69, -0.62, }), b: NewDense(5, 2, []float64{ 0.44, 1.34, 0.07, -1.45, -0.32, -0.88, -0.09, -0.15, -1.17, -0.19, }), }, } { a := test.a for _, trans := range []bool{false, true} { for _, dstSameAsB := range []bool{false, true} { name := fmt.Sprintf("Case %d,trans=%v,dstSameAsB=%v", tc, trans, dstSameAsB) n, nrhs := test.b.Dims() var dst Dense var err error if dstSameAsB { dst = *NewDense(n, nrhs, nil) dst.Copy(test.b) err = a.SolveTo(&dst, trans, &dst) } else { tmp := NewDense(n, nrhs, nil) tmp.Copy(test.b) err = a.SolveTo(&dst, trans, asBasicMatrix(tmp)) } if err != nil { t.Fatalf("%v: unexpected error from SolveTo", name) } var resid Dense if trans { resid.Mul(a.T(), &dst) } else { resid.Mul(a, &dst) } resid.Sub(&resid, test.b) diff := Norm(&resid, 1) if diff > tol { t.Errorf("%v: unexpected result; diff=%v,want<=%v", name, diff, tol) } } } } } func TestTriBandDenseSolveVecTo(t *testing.T) { t.Parallel() const tol = 1e-15 for tc, test := range []struct { a *TriBandDense b *VecDense }{ { a: NewTriBandDense(5, 2, Upper, []float64{ -0.34, -0.49, -0.51, -0.25, -0.5, 1.03, -1.1, 0.3, -0.82, 1.69, 0.69, -2.22, -0.62, 1.22, -0.85, }), b: NewVecDense(5, []float64{ 0.44, 0.07, -0.32, -0.09, -1.17, }), }, { a: NewTriBandDense(5, 2, Lower, []float64{ 0, 0, -0.34, 0, -0.49, -0.25, -0.51, -0.5, -1.1, 1.03, 0.3, 1.69, -0.82, 0.69, -0.62, }), b: NewVecDense(5, []float64{ 0.44, 0.07, -0.32, -0.09, -1.17, }), }, } { a := test.a for _, trans := range []bool{false, true} { for _, dstSameAsB := range []bool{false, true} { name := fmt.Sprintf("Case %d,trans=%v,dstSameAsB=%v", tc, trans, dstSameAsB) n, _ := test.b.Dims() var dst VecDense var err error if dstSameAsB { dst = *NewVecDense(n, nil) dst.CopyVec(test.b) err = a.SolveVecTo(&dst, trans, &dst) } else { tmp := NewVecDense(n, nil) tmp.CopyVec(test.b) err = a.SolveVecTo(&dst, trans, asBasicVector(tmp)) } if err != nil { t.Fatalf("%v: unexpected error from SolveVecTo", name) } var resid VecDense if trans { resid.MulVec(a.T(), &dst) } else { resid.MulVec(a, &dst) } resid.SubVec(&resid, test.b) diff := Norm(&resid, 1) if diff > tol { t.Errorf("%v: unexpected result; diff=%v,want<=%v", name, diff, tol) } } } } } golang-gonum-v1-gonum-0.14.0/mat/tridiag.go000066400000000000000000000240771450372207100204030ustar00rootroot00000000000000// Copyright ©2020 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/internal/asm/f64" "gonum.org/v1/gonum/lapack/lapack64" ) var ( tridiagDense *Tridiag _ Matrix = tridiagDense _ allMatrix = tridiagDense _ denseMatrix = tridiagDense _ Banded = tridiagDense _ MutableBanded = tridiagDense _ RawTridiagonaler = tridiagDense ) // A RawTridiagonaler can return a lapack64.Tridiagonal representation of the // receiver. Changes to the elements of DL, D, DU in lapack64.Tridiagonal will // be reflected in the original matrix, changes to the N field will not. type RawTridiagonaler interface { RawTridiagonal() lapack64.Tridiagonal } // Tridiag represents a tridiagonal matrix by its three diagonals. type Tridiag struct { mat lapack64.Tridiagonal } // NewTridiag creates a new n×n tridiagonal matrix with the first sub-diagonal // in dl, the main diagonal in d and the first super-diagonal in du. If all of // dl, d, and du are nil, new backing slices will be allocated for them. If dl // and du have length n-1 and d has length n, they will be used as backing // slices, and changes to the elements of the returned Tridiag will be reflected // in dl, d, du. If neither of these is true, NewTridiag will panic. func NewTridiag(n int, dl, d, du []float64) *Tridiag { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if dl != nil || d != nil || du != nil { if len(dl) != n-1 || len(d) != n || len(du) != n-1 { panic(ErrShape) } } else { d = make([]float64, n) if n > 1 { dl = make([]float64, n-1) du = make([]float64, n-1) } } return &Tridiag{ mat: lapack64.Tridiagonal{ N: n, DL: dl, D: d, DU: du, }, } } // Dims returns the number of rows and columns in the matrix. func (a *Tridiag) Dims() (r, c int) { return a.mat.N, a.mat.N } // Bandwidth returns 1, 1 - the upper and lower bandwidths of the matrix. func (a *Tridiag) Bandwidth() (kl, ku int) { return 1, 1 } // T performs an implicit transpose by returning the receiver inside a Transpose. func (a *Tridiag) T() Matrix { // An alternative would be to return the receiver with DL,DU swapped; the // untranspose function would then always return false. With Transpose the // diagonal swapping will be done in tridiagonal routines in lapack like // lapack64.Gtsv or gonum.Dlagtm based on the trans parameter. return Transpose{a} } // TBand performs an implicit transpose by returning the receiver inside a // TransposeBand. func (a *Tridiag) TBand() Banded { // An alternative would be to return the receiver with DL,DU swapped; see // explanation in T above. return TransposeBand{a} } // RawTridiagonal returns the underlying lapack64.Tridiagonal used by the // receiver. Changes to elements in the receiver following the call will be // reflected in the returned matrix. func (a *Tridiag) RawTridiagonal() lapack64.Tridiagonal { return a.mat } // SetRawTridiagonal sets the underlying lapack64.Tridiagonal used by the // receiver. Changes to elements in the receiver following the call will be // reflected in the input. func (a *Tridiag) SetRawTridiagonal(mat lapack64.Tridiagonal) { a.mat = mat } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be zeroed using // Reset. func (a *Tridiag) IsEmpty() bool { return a.mat.N == 0 } // Reset empties the matrix so that it can be reused as the receiver of a // dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. See the Reseter // interface for more information. func (a *Tridiag) Reset() { a.mat.N = 0 a.mat.DL = a.mat.DL[:0] a.mat.D = a.mat.D[:0] a.mat.DU = a.mat.DU[:0] } // CloneFromTridiag makes a copy of the input Tridiag into the receiver, // overwriting the previous value of the receiver. CloneFromTridiag does not // place any restrictions on receiver shape. func (a *Tridiag) CloneFromTridiag(from *Tridiag) { n := from.mat.N switch n { case 0: panic(ErrZeroLength) case 1: a.mat = lapack64.Tridiagonal{ N: 1, DL: use(a.mat.DL, 0), D: use(a.mat.D, 1), DU: use(a.mat.DU, 0), } a.mat.D[0] = from.mat.D[0] default: a.mat = lapack64.Tridiagonal{ N: n, DL: use(a.mat.DL, n-1), D: use(a.mat.D, n), DU: use(a.mat.DU, n-1), } copy(a.mat.DL, from.mat.DL) copy(a.mat.D, from.mat.D) copy(a.mat.DU, from.mat.DU) } } // DiagView returns the diagonal as a matrix backed by the original data. func (a *Tridiag) DiagView() Diagonal { return &DiagDense{ mat: blas64.Vector{ N: a.mat.N, Data: a.mat.D[:a.mat.N], Inc: 1, }, } } // Zero sets all of the matrix elements to zero. func (a *Tridiag) Zero() { zero(a.mat.DL) zero(a.mat.D) zero(a.mat.DU) } // Trace returns the trace of the matrix. // // Trace will panic with ErrZeroLength if the matrix has zero size. func (a *Tridiag) Trace() float64 { if a.IsEmpty() { panic(ErrZeroLength) } return f64.Sum(a.mat.D) } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The maximum absolute column sum // 2 - The Frobenius norm, the square root of the sum of the squares of the elements // Inf - The maximum absolute row sum // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the matrix has zero size. func (a *Tridiag) Norm(norm float64) float64 { if a.IsEmpty() { panic(ErrZeroLength) } return lapack64.Langt(normLapack(norm, false), a.mat) } // MulVecTo computes A⋅x or Aᵀ⋅x storing the result into dst. func (a *Tridiag) MulVecTo(dst *VecDense, trans bool, x Vector) { n := a.mat.N if x.Len() != n { panic(ErrShape) } dst.reuseAsNonZeroed(n) t := blas.NoTrans if trans { t = blas.Trans } xMat, _ := untransposeExtract(x) if xVec, ok := xMat.(*VecDense); ok && dst != xVec { dst.checkOverlap(xVec.mat) lapack64.Lagtm(t, 1, a.mat, xVec.asGeneral(), 0, dst.asGeneral()) } else { xCopy := getVecDenseWorkspace(n, false) xCopy.CloneFromVec(x) lapack64.Lagtm(t, 1, a.mat, xCopy.asGeneral(), 0, dst.asGeneral()) putVecDenseWorkspace(xCopy) } } // SolveTo solves a tridiagonal system A⋅X = B or Aᵀ⋅X = B where A is an // n×n tridiagonal matrix represented by the receiver and B is a given n×nrhs // matrix. If A is non-singular, the result will be stored into dst and nil will // be returned. If A is singular, the contents of dst will be undefined and a // Condition error will be returned. func (a *Tridiag) SolveTo(dst *Dense, trans bool, b Matrix) error { n, nrhs := b.Dims() if n != a.mat.N { panic(ErrShape) } if b, ok := b.(RawMatrixer); ok && dst != b { dst.checkOverlap(b.RawMatrix()) } dst.reuseAsNonZeroed(n, nrhs) if dst != b { dst.Copy(b) } var aCopy Tridiag aCopy.CloneFromTridiag(a) var ok bool if trans { ok = lapack64.Gtsv(blas.Trans, aCopy.mat, dst.mat) } else { ok = lapack64.Gtsv(blas.NoTrans, aCopy.mat, dst.mat) } if !ok { return Condition(math.Inf(1)) } return nil } // SolveVecTo solves a tridiagonal system A⋅X = B or Aᵀ⋅X = B where A is an // n×n tridiagonal matrix represented by the receiver and b is a given n-vector. // If A is non-singular, the result will be stored into dst and nil will be // returned. If A is singular, the contents of dst will be undefined and a // Condition error will be returned. func (a *Tridiag) SolveVecTo(dst *VecDense, trans bool, b Vector) error { n, nrhs := b.Dims() if n != a.mat.N || nrhs != 1 { panic(ErrShape) } if b, ok := b.(RawVectorer); ok && dst != b { dst.checkOverlap(b.RawVector()) } dst.reuseAsNonZeroed(n) if dst != b { dst.CopyVec(b) } var aCopy Tridiag aCopy.CloneFromTridiag(a) var ok bool if trans { ok = lapack64.Gtsv(blas.Trans, aCopy.mat, dst.asGeneral()) } else { ok = lapack64.Gtsv(blas.NoTrans, aCopy.mat, dst.asGeneral()) } if !ok { return Condition(math.Inf(1)) } return nil } // DoNonZero calls the function fn for each of the non-zero elements of A. The // function fn takes a row/column index and the element value of A at (i,j). func (a *Tridiag) DoNonZero(fn func(i, j int, v float64)) { for i, aij := range a.mat.DU { if aij != 0 { fn(i, i+1, aij) } } for i, aii := range a.mat.D { if aii != 0 { fn(i, i, aii) } } for i, aij := range a.mat.DL { if aij != 0 { fn(i+1, i, aij) } } } // DoRowNonZero calls the function fn for each of the non-zero elements of row i // of A. The function fn takes a row/column index and the element value of A at // (i,j). func (a *Tridiag) DoRowNonZero(i int, fn func(i, j int, v float64)) { n := a.mat.N if uint(i) >= uint(n) { panic(ErrRowAccess) } if n == 1 { v := a.mat.D[0] if v != 0 { fn(0, 0, v) } return } switch i { case 0: v := a.mat.D[0] if v != 0 { fn(i, 0, v) } v = a.mat.DU[0] if v != 0 { fn(i, 1, v) } case n - 1: v := a.mat.DL[n-2] if v != 0 { fn(n-1, n-2, v) } v = a.mat.D[n-1] if v != 0 { fn(n-1, n-1, v) } default: v := a.mat.DL[i-1] if v != 0 { fn(i, i-1, v) } v = a.mat.D[i] if v != 0 { fn(i, i, v) } v = a.mat.DU[i] if v != 0 { fn(i, i+1, v) } } } // DoColNonZero calls the function fn for each of the non-zero elements of // column j of A. The function fn takes a row/column index and the element value // of A at (i, j). func (a *Tridiag) DoColNonZero(j int, fn func(i, j int, v float64)) { n := a.mat.N if uint(j) >= uint(n) { panic(ErrColAccess) } if n == 1 { v := a.mat.D[0] if v != 0 { fn(0, 0, v) } return } switch j { case 0: v := a.mat.D[0] if v != 0 { fn(0, 0, v) } v = a.mat.DL[0] if v != 0 { fn(1, 0, v) } case n - 1: v := a.mat.DU[n-2] if v != 0 { fn(n-2, n-1, v) } v = a.mat.D[n-1] if v != 0 { fn(n-1, n-1, v) } default: v := a.mat.DU[j-1] if v != 0 { fn(j-1, j, v) } v = a.mat.D[j] if v != 0 { fn(j, j, v) } v = a.mat.DL[j] if v != 0 { fn(j+1, j, v) } } } golang-gonum-v1-gonum-0.14.0/mat/tridiag_test.go000066400000000000000000000266671450372207100214510ustar00rootroot00000000000000// Copyright ©2021 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "fmt" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/lapack/lapack64" ) func TestNewTridiag(t *testing.T) { for i, test := range []struct { n int dl, d, du []float64 panics bool want *Tridiag dense *Dense }{ { n: 1, dl: nil, d: []float64{1.2}, du: nil, panics: false, want: &Tridiag{ mat: lapack64.Tridiagonal{ N: 1, DL: nil, D: []float64{1.2}, DU: nil, }, }, dense: NewDense(1, 1, []float64{1.2}), }, { n: 1, dl: []float64{}, d: []float64{1.2}, du: []float64{}, panics: false, want: &Tridiag{ mat: lapack64.Tridiagonal{ N: 1, DL: []float64{}, D: []float64{1.2}, DU: []float64{}, }, }, dense: NewDense(1, 1, []float64{1.2}), }, { n: 4, dl: []float64{1.2, 2.3, 3.4}, d: []float64{4.5, 5.6, 6.7, 7.8}, du: []float64{8.9, 9.0, 0.1}, panics: false, want: &Tridiag{ mat: lapack64.Tridiagonal{ N: 4, DL: []float64{1.2, 2.3, 3.4}, D: []float64{4.5, 5.6, 6.7, 7.8}, DU: []float64{8.9, 9.0, 0.1}, }, }, dense: NewDense(4, 4, []float64{ 4.5, 8.9, 0, 0, 1.2, 5.6, 9.0, 0, 0, 2.3, 6.7, 0.1, 0, 0, 3.4, 7.8, }), }, { n: 4, dl: nil, d: nil, du: nil, panics: false, want: &Tridiag{ mat: lapack64.Tridiagonal{ N: 4, DL: []float64{0, 0, 0}, D: []float64{0, 0, 0, 0}, DU: []float64{0, 0, 0}, }, }, dense: NewDense(4, 4, nil), }, { n: -1, panics: true, }, { n: 0, panics: true, }, { n: 1, dl: []float64{1.2}, d: nil, du: nil, panics: true, }, { n: 1, dl: nil, d: []float64{1.2, 2.3}, du: nil, panics: true, }, { n: 1, dl: []float64{}, d: nil, du: []float64{}, panics: true, }, { n: 4, dl: []float64{1.2}, d: nil, du: nil, panics: true, }, { n: 4, dl: []float64{1.2, 2.3, 3.4}, d: []float64{4.5, 5.6, 6.7, 7.8, 1.2}, du: []float64{8.9, 9.0, 0.1}, panics: true, }, } { var a *Tridiag panicked, msg := panics(func() { a = NewTridiag(test.n, test.dl, test.d, test.du) }) if panicked { if !test.panics { t.Errorf("Case %d: unexpected panic: %s", i, msg) } continue } if test.panics { t.Errorf("Case %d: expected panic", i) continue } r, c := a.Dims() if r != test.n { t.Errorf("Case %d: unexpected number of rows: got=%d want=%d", i, r, test.n) } if c != test.n { t.Errorf("Case %d: unexpected number of columns: got=%d want=%d", i, c, test.n) } kl, ku := a.Bandwidth() if kl != 1 || ku != 1 { t.Errorf("Case %d: unexpected bandwidth: got=%d,%d want=1,1", i, kl, ku) } if !reflect.DeepEqual(a, test.want) { t.Errorf("Case %d: unexpected value via reflect: got=%v, want=%v", i, a, test.want) } if !Equal(a, test.want) { t.Errorf("Case %d: unexpected value via mat.Equal: got=%v, want=%v", i, a, test.want) } if !Equal(a, test.dense) { t.Errorf("Case %d: unexpected value via mat.Equal(Tridiag,Dense):\ngot:\n% v\nwant:\n% v", i, Formatted(a), Formatted(test.dense)) } } } func TestTridiagAtSet(t *testing.T) { t.Parallel() for _, n := range []int{1, 2, 3, 4, 7, 10} { tri, ref := newTestTridiag(n) name := fmt.Sprintf("Case n=%v", n) // Check At explicitly with all valid indices. for i := 0; i < n; i++ { for j := 0; j < n; j++ { if tri.At(i, j) != ref.At(i, j) { t.Errorf("%v: unexpected value for At(%d,%d): got %v, want %v", name, i, j, tri.At(i, j), ref.At(i, j)) } } } // Check At via a call to Equal. if !Equal(tri, ref) { t.Errorf("%v: unexpected value:\ngot: % v\nwant:% v", name, Formatted(tri, Prefix(" ")), Formatted(ref, Prefix(" "))) } // Check At out of bounds. for _, i := range []int{-1, n, n + 1} { for j := 0; j < n; j++ { panicked, message := panics(func() { tri.At(i, j) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("%v: expected panic for invalid row access at (%d,%d)", name, i, j) } } } for _, j := range []int{-1, n, n + 1} { for i := 0; i < n; i++ { panicked, message := panics(func() { tri.At(i, j) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("%v: expected panic for invalid column access at (%d,%d)", name, i, j) } } } // Check SetBand out of bounds. for _, i := range []int{-1, n, n + 1} { for j := 0; j < n; j++ { panicked, message := panics(func() { tri.SetBand(i, j, 1.2) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("%v: expected panic for invalid row access at (%d,%d)", name, i, j) } } } for _, j := range []int{-1, n, n + 1} { for i := 0; i < n; i++ { panicked, message := panics(func() { tri.SetBand(i, j, 1.2) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("%v: expected panic for invalid column access at (%d,%d)", name, i, j) } } } for i := 0; i < n; i++ { for j := 0; j <= i-2; j++ { panicked, message := panics(func() { tri.SetBand(i, j, 1.2) }) if !panicked || message != ErrBandSet.Error() { t.Errorf("%v: expected panic for invalid access at (%d,%d)", name, i, j) } } for j := i + 2; j < n; j++ { panicked, message := panics(func() { tri.SetBand(i, j, 1.2) }) if !panicked || message != ErrBandSet.Error() { t.Errorf("%v: expected panic for invalid access at (%d,%d)", name, i, j) } } } // Check SetBand within bandwidth. for i := 0; i < n; i++ { for j := max(0, i-1); j <= min(i+1, n-1); j++ { want := float64(i*n + j + 100) tri.SetBand(i, j, want) if got := tri.At(i, j); got != want { t.Errorf("%v: unexpected value at (%d,%d) after SetBand: got %v, want %v", name, i, j, got, want) } } } } } func newTestTridiag(n int) (*Tridiag, *Dense) { var dl, d, du []float64 d = make([]float64, n) if n > 1 { dl = make([]float64, n-1) du = make([]float64, n-1) } for i := range d { d[i] = float64(i*n + i + 1) } for j := range dl { i := j + 1 dl[j] = float64(i*n + j + 1) } for i := range du { j := i + 1 du[i] = float64(i*n + j + 1) } dense := make([]float64, n*n) for i := 0; i < n; i++ { for j := max(0, i-1); j <= min(i+1, n-1); j++ { dense[i*n+j] = float64(i*n + j + 1) } } return NewTridiag(n, dl, d, du), NewDense(n, n, dense) } func TestTridiagReset(t *testing.T) { t.Parallel() for _, n := range []int{1, 2, 3, 4, 7, 10} { a, _ := newTestTridiag(n) if a.IsEmpty() { t.Errorf("Case n=%d: matrix is empty", n) } a.Reset() if !a.IsEmpty() { t.Errorf("Case n=%d: matrix is not empty after Reset", n) } } } func TestTridiagDiagView(t *testing.T) { t.Parallel() for _, n := range []int{1, 2, 3, 4, 7, 10} { a, _ := newTestTridiag(n) testDiagView(t, n, a) } } func TestTridiagZero(t *testing.T) { t.Parallel() for _, n := range []int{1, 2, 3, 4, 7, 10} { a, _ := newTestTridiag(n) a.Zero() for i := 0; i < n; i++ { for j := 0; j < n; j++ { if a.At(i, j) != 0 { t.Errorf("Case n=%d: unexpected non-zero at (%d,%d): got %f", n, i, j, a.At(i, j)) } } } } } func TestTridiagSolveTo(t *testing.T) { t.Parallel() const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) random := func(n int) []float64 { d := make([]float64, n) for i := range d { d[i] = rnd.NormFloat64() } return d } for _, n := range []int{1, 2, 3, 4, 7, 10} { a := NewTridiag(n, random(n-1), random(n), random(n-1)) var aDense Dense aDense.CloneFrom(a) for _, trans := range []bool{false, true} { for _, nrhs := range []int{1, 2, 5} { const ( denseB = iota rawB basicB ) for _, bType := range []int{denseB, rawB, basicB} { const ( emptyDst = iota shapedDst bIsDst ) for _, dstType := range []int{emptyDst, shapedDst, bIsDst} { if dstType == bIsDst && bType != denseB { continue } var b Matrix switch bType { case denseB: b = NewDense(n, nrhs, random(n*nrhs)) case rawB: b = &rawMatrix{asBasicMatrix(NewDense(n, nrhs, random(n*nrhs)))} case basicB: b = asBasicMatrix(NewDense(n, nrhs, random(n*nrhs))) default: panic("bad bType") } var dst *Dense switch dstType { case emptyDst: dst = new(Dense) case shapedDst: dst = NewDense(n, nrhs, random(n*nrhs)) case bIsDst: dst = b.(*Dense) default: panic("bad dstType") } name := fmt.Sprintf("n=%d,nrhs=%d,trans=%t,dstType=%d,bType=%d", n, nrhs, trans, dstType, bType) var want Dense var err error if !trans { err = want.Solve(&aDense, b) } else { err = want.Solve(aDense.T(), b) } if err != nil { t.Fatalf("%v: unexpected failure when computing reference solution: %v", name, err) } err = a.SolveTo(dst, trans, b) if err != nil { t.Fatalf("%v: unexpected failure from Tridiag.SolveTo: %v", name, err) } var diff Dense diff.Sub(dst, &want) if resid := Norm(&diff, 1); resid > tol*float64(n) { t.Errorf("%v: unexpected result; resid=%v, want<=%v", name, resid, tol*float64(n)) } } } } } } } func TestTridiagSolveVecTo(t *testing.T) { t.Parallel() const tol = 1e-13 rnd := rand.New(rand.NewSource(1)) random := func(n int) []float64 { d := make([]float64, n) for i := range d { d[i] = rnd.NormFloat64() } return d } for _, n := range []int{1, 2, 3, 4, 7, 10} { a := NewTridiag(n, random(n-1), random(n), random(n-1)) var aDense Dense aDense.CloneFrom(a) for _, trans := range []bool{false, true} { const ( denseB = iota rawB basicB ) for _, bType := range []int{denseB, rawB, basicB} { const ( emptyDst = iota shapedDst bIsDst ) for _, dstType := range []int{emptyDst, shapedDst, bIsDst} { if dstType == bIsDst && bType != denseB { continue } var b Vector switch bType { case denseB: b = NewVecDense(n, random(n)) case rawB: b = &rawVector{asBasicVector(NewVecDense(n, random(n)))} case basicB: b = asBasicVector(NewVecDense(n, random(n))) default: panic("bad bType") } var dst *VecDense switch dstType { case emptyDst: dst = new(VecDense) case shapedDst: dst = NewVecDense(n, random(n)) case bIsDst: dst = b.(*VecDense) default: panic("bad dstType") } name := fmt.Sprintf("n=%d,trans=%t,dstType=%d,bType=%d", n, trans, dstType, bType) var want VecDense var err error if !trans { err = want.SolveVec(&aDense, b) } else { err = want.SolveVec(aDense.T(), b) } if err != nil { t.Fatalf("%v: unexpected failure when computing reference solution: %v", name, err) } err = a.SolveVecTo(dst, trans, b) if err != nil { t.Fatalf("%v: unexpected failure from Tridiag.SolveTo: %v", name, err) } var diff Dense diff.Sub(dst, &want) if resid := Norm(&diff, 1); resid > tol*float64(n) { t.Errorf("%v: unexpected result; resid=%v, want<=%v", name, resid, tol*float64(n)) } } } } } } golang-gonum-v1-gonum-0.14.0/mat/vector.go000066400000000000000000000447751450372207100202710ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/internal/asm/f64" ) var ( vector *VecDense _ Matrix = vector _ allMatrix = vector _ Vector = vector _ Reseter = vector _ MutableVector = vector ) // Vector is a vector. type Vector interface { Matrix AtVec(int) float64 Len() int } // A MutableVector can set elements of a vector. type MutableVector interface { Vector SetVec(i int, v float64) } // TransposeVec is a type for performing an implicit transpose of a Vector. // It implements the Vector interface, returning values from the transpose // of the vector within. type TransposeVec struct { Vector Vector } // At returns the value of the element at row i and column j of the transposed // matrix, that is, row j and column i of the Vector field. func (t TransposeVec) At(i, j int) float64 { return t.Vector.At(j, i) } // AtVec returns the element at position i. It panics if i is out of bounds. func (t TransposeVec) AtVec(i int) float64 { return t.Vector.AtVec(i) } // Dims returns the dimensions of the transposed vector. func (t TransposeVec) Dims() (r, c int) { c, r = t.Vector.Dims() return r, c } // T performs an implicit transpose by returning the Vector field. func (t TransposeVec) T() Matrix { return t.Vector } // Len returns the number of columns in the vector. func (t TransposeVec) Len() int { return t.Vector.Len() } // TVec performs an implicit transpose by returning the Vector field. func (t TransposeVec) TVec() Vector { return t.Vector } // Untranspose returns the Vector field. func (t TransposeVec) Untranspose() Matrix { return t.Vector } func (t TransposeVec) UntransposeVec() Vector { return t.Vector } // VecDense represents a column vector. type VecDense struct { mat blas64.Vector // A BLAS vector can have a negative increment, but allowing this // in the mat type complicates a lot of code, and doesn't gain anything. // VecDense must have positive increment in this package. } // NewVecDense creates a new VecDense of length n. If data == nil, // a new slice is allocated for the backing slice. If len(data) == n, data is // used as the backing slice, and changes to the elements of the returned VecDense // will be reflected in data. If neither of these is true, NewVecDense will panic. // NewVecDense will panic if n is zero. func NewVecDense(n int, data []float64) *VecDense { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic("mat: negative dimension") } if len(data) != n && data != nil { panic(ErrShape) } if data == nil { data = make([]float64, n) } return &VecDense{ mat: blas64.Vector{ N: n, Inc: 1, Data: data, }, } } // SliceVec returns a new Vector that shares backing data with the receiver. // The returned matrix starts at i of the receiver and extends k-i elements. // SliceVec panics with ErrIndexOutOfRange if the slice is outside the capacity // of the receiver. func (v *VecDense) SliceVec(i, k int) Vector { return v.sliceVec(i, k) } func (v *VecDense) sliceVec(i, k int) *VecDense { if i < 0 || k <= i || v.Cap() < k { panic(ErrIndexOutOfRange) } return &VecDense{ mat: blas64.Vector{ N: k - i, Inc: v.mat.Inc, Data: v.mat.Data[i*v.mat.Inc : (k-1)*v.mat.Inc+1], }, } } // Dims returns the number of rows and columns in the matrix. Columns is always 1 // for a non-Reset vector. func (v *VecDense) Dims() (r, c int) { if v.IsEmpty() { return 0, 0 } return v.mat.N, 1 } // Caps returns the number of rows and columns in the backing matrix. Columns is always 1 // for a non-Reset vector. func (v *VecDense) Caps() (r, c int) { if v.IsEmpty() { return 0, 0 } return v.Cap(), 1 } // Len returns the length of the vector. func (v *VecDense) Len() int { return v.mat.N } // Cap returns the capacity of the vector. func (v *VecDense) Cap() int { if v.IsEmpty() { return 0 } return (cap(v.mat.Data)-1)/v.mat.Inc + 1 } // T performs an implicit transpose by returning the receiver inside a Transpose. func (v *VecDense) T() Matrix { return Transpose{v} } // TVec performs an implicit transpose by returning the receiver inside a TransposeVec. func (v *VecDense) TVec() Vector { return TransposeVec{v} } // Reset empties the matrix so that it can be reused as the // receiver of a dimensionally restricted operation. // // Reset should not be used when the matrix shares backing data. // See the Reseter interface for more information. func (v *VecDense) Reset() { // No change of Inc or N to 0 may be // made unless both are set to 0. v.mat.Inc = 0 v.mat.N = 0 v.mat.Data = v.mat.Data[:0] } // Zero sets all of the matrix elements to zero. func (v *VecDense) Zero() { for i := 0; i < v.mat.N; i++ { v.mat.Data[v.mat.Inc*i] = 0 } } // CloneFromVec makes a copy of a into the receiver, overwriting the previous value // of the receiver. func (v *VecDense) CloneFromVec(a Vector) { if v == a { return } n := a.Len() v.mat = blas64.Vector{ N: n, Inc: 1, Data: use(v.mat.Data, n), } if r, ok := a.(RawVectorer); ok { blas64.Copy(r.RawVector(), v.mat) return } for i := 0; i < a.Len(); i++ { v.setVec(i, a.AtVec(i)) } } // VecDenseCopyOf returns a newly allocated copy of the elements of a. func VecDenseCopyOf(a Vector) *VecDense { v := &VecDense{} v.CloneFromVec(a) return v } // RawVector returns the underlying blas64.Vector used by the receiver. // Changes to elements in the receiver following the call will be reflected // in returned blas64.Vector. func (v *VecDense) RawVector() blas64.Vector { return v.mat } // SetRawVector sets the underlying blas64.Vector used by the receiver. // Changes to elements in the receiver following the call will be reflected // in the input. func (v *VecDense) SetRawVector(a blas64.Vector) { v.mat = a } // CopyVec makes a copy of elements of a into the receiver. It is similar to the // built-in copy; it copies as much as the overlap between the two vectors and // returns the number of elements it copied. func (v *VecDense) CopyVec(a Vector) int { n := min(v.Len(), a.Len()) if v == a { return n } if r, ok := a.(RawVectorer); ok { src := r.RawVector() src.N = n dst := v.mat dst.N = n blas64.Copy(src, dst) return n } for i := 0; i < n; i++ { v.setVec(i, a.AtVec(i)) } return n } // Norm returns the specified norm of the receiver. Valid norms are: // // 1 - The sum of the element magnitudes // 2 - The Euclidean norm, the square root of the sum of the squares of the elements // Inf - The maximum element magnitude // // Norm will panic with ErrNormOrder if an illegal norm is specified and with // ErrZeroLength if the vector has zero size. func (v *VecDense) Norm(norm float64) float64 { if v.IsEmpty() { panic(ErrZeroLength) } switch norm { default: panic(ErrNormOrder) case 1: return blas64.Asum(v.mat) case 2: return blas64.Nrm2(v.mat) case math.Inf(1): imax := blas64.Iamax(v.mat) return math.Abs(v.at(imax)) } } // ScaleVec scales the vector a by alpha, placing the result in the receiver. func (v *VecDense) ScaleVec(alpha float64, a Vector) { n := a.Len() if v == a { if v.mat.Inc == 1 { f64.ScalUnitary(alpha, v.mat.Data) return } f64.ScalInc(alpha, v.mat.Data, uintptr(n), uintptr(v.mat.Inc)) return } v.reuseAsNonZeroed(n) if rv, ok := a.(RawVectorer); ok { mat := rv.RawVector() v.checkOverlap(mat) if v.mat.Inc == 1 && mat.Inc == 1 { f64.ScalUnitaryTo(v.mat.Data, alpha, mat.Data) return } f64.ScalIncTo(v.mat.Data, uintptr(v.mat.Inc), alpha, mat.Data, uintptr(n), uintptr(mat.Inc)) return } for i := 0; i < n; i++ { v.setVec(i, alpha*a.AtVec(i)) } } // AddScaledVec adds the vectors a and alpha*b, placing the result in the receiver. func (v *VecDense) AddScaledVec(a Vector, alpha float64, b Vector) { if alpha == 1 { v.AddVec(a, b) return } if alpha == -1 { v.SubVec(a, b) return } ar := a.Len() br := b.Len() if ar != br { panic(ErrShape) } var amat, bmat blas64.Vector fast := true aU, _ := untransposeExtract(a) if rv, ok := aU.(*VecDense); ok { amat = rv.mat if v != a { v.checkOverlap(amat) } } else { fast = false } bU, _ := untransposeExtract(b) if rv, ok := bU.(*VecDense); ok { bmat = rv.mat if v != b { v.checkOverlap(bmat) } } else { fast = false } v.reuseAsNonZeroed(ar) switch { case alpha == 0: // v <- a if v == a { return } v.CopyVec(a) case v == a && v == b: // v <- v + alpha * v = (alpha + 1) * v blas64.Scal(alpha+1, v.mat) case !fast: // v <- a + alpha * b without blas64 support. for i := 0; i < ar; i++ { v.setVec(i, a.AtVec(i)+alpha*b.AtVec(i)) } case v == a && v != b: // v <- v + alpha * b if v.mat.Inc == 1 && bmat.Inc == 1 { // Fast path for a common case. f64.AxpyUnitaryTo(v.mat.Data, alpha, bmat.Data, amat.Data) } else { f64.AxpyInc(alpha, bmat.Data, v.mat.Data, uintptr(ar), uintptr(bmat.Inc), uintptr(v.mat.Inc), 0, 0) } default: // v <- a + alpha * b or v <- a + alpha * v if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 { // Fast path for a common case. f64.AxpyUnitaryTo(v.mat.Data, alpha, bmat.Data, amat.Data) } else { f64.AxpyIncTo(v.mat.Data, uintptr(v.mat.Inc), 0, alpha, bmat.Data, amat.Data, uintptr(ar), uintptr(bmat.Inc), uintptr(amat.Inc), 0, 0) } } } // AddVec adds the vectors a and b, placing the result in the receiver. func (v *VecDense) AddVec(a, b Vector) { ar := a.Len() br := b.Len() if ar != br { panic(ErrShape) } v.reuseAsNonZeroed(ar) aU, _ := untransposeExtract(a) bU, _ := untransposeExtract(b) if arv, ok := aU.(*VecDense); ok { if brv, ok := bU.(*VecDense); ok { amat := arv.mat bmat := brv.mat if v != a { v.checkOverlap(amat) } if v != b { v.checkOverlap(bmat) } if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 { // Fast path for a common case. f64.AxpyUnitaryTo(v.mat.Data, 1, bmat.Data, amat.Data) return } f64.AxpyIncTo(v.mat.Data, uintptr(v.mat.Inc), 0, 1, bmat.Data, amat.Data, uintptr(ar), uintptr(bmat.Inc), uintptr(amat.Inc), 0, 0) return } } for i := 0; i < ar; i++ { v.setVec(i, a.AtVec(i)+b.AtVec(i)) } } // SubVec subtracts the vector b from a, placing the result in the receiver. func (v *VecDense) SubVec(a, b Vector) { ar := a.Len() br := b.Len() if ar != br { panic(ErrShape) } v.reuseAsNonZeroed(ar) aU, _ := untransposeExtract(a) bU, _ := untransposeExtract(b) if arv, ok := aU.(*VecDense); ok { if brv, ok := bU.(*VecDense); ok { amat := arv.mat bmat := brv.mat if v != a { v.checkOverlap(amat) } if v != b { v.checkOverlap(bmat) } if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 { // Fast path for a common case. f64.AxpyUnitaryTo(v.mat.Data, -1, bmat.Data, amat.Data) return } f64.AxpyIncTo(v.mat.Data, uintptr(v.mat.Inc), 0, -1, bmat.Data, amat.Data, uintptr(ar), uintptr(bmat.Inc), uintptr(amat.Inc), 0, 0) return } } for i := 0; i < ar; i++ { v.setVec(i, a.AtVec(i)-b.AtVec(i)) } } // MulElemVec performs element-wise multiplication of a and b, placing the result // in the receiver. func (v *VecDense) MulElemVec(a, b Vector) { ar := a.Len() br := b.Len() if ar != br { panic(ErrShape) } v.reuseAsNonZeroed(ar) aU, _ := untransposeExtract(a) bU, _ := untransposeExtract(b) if arv, ok := aU.(*VecDense); ok { if brv, ok := bU.(*VecDense); ok { amat := arv.mat bmat := brv.mat if v != a { v.checkOverlap(amat) } if v != b { v.checkOverlap(bmat) } if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 { // Fast path for a common case. for i, a := range amat.Data { v.mat.Data[i] = a * bmat.Data[i] } return } var ia, ib int for i := 0; i < ar; i++ { v.setVec(i, amat.Data[ia]*bmat.Data[ib]) ia += amat.Inc ib += bmat.Inc } return } } for i := 0; i < ar; i++ { v.setVec(i, a.AtVec(i)*b.AtVec(i)) } } // DivElemVec performs element-wise division of a by b, placing the result // in the receiver. func (v *VecDense) DivElemVec(a, b Vector) { ar := a.Len() br := b.Len() if ar != br { panic(ErrShape) } v.reuseAsNonZeroed(ar) aU, _ := untransposeExtract(a) bU, _ := untransposeExtract(b) if arv, ok := aU.(*VecDense); ok { if brv, ok := bU.(*VecDense); ok { amat := arv.mat bmat := brv.mat if v != a { v.checkOverlap(amat) } if v != b { v.checkOverlap(bmat) } if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 { // Fast path for a common case. for i, a := range amat.Data { v.setVec(i, a/bmat.Data[i]) } return } var ia, ib int for i := 0; i < ar; i++ { v.setVec(i, amat.Data[ia]/bmat.Data[ib]) ia += amat.Inc ib += bmat.Inc } } } for i := 0; i < ar; i++ { v.setVec(i, a.AtVec(i)/b.AtVec(i)) } } // MulVec computes a * b. The result is stored into the receiver. // MulVec panics if the number of columns in a does not equal the number of rows in b // or if the number of columns in b does not equal 1. func (v *VecDense) MulVec(a Matrix, b Vector) { r, c := a.Dims() br, bc := b.Dims() if c != br || bc != 1 { panic(ErrShape) } aU, trans := untransposeExtract(a) var bmat blas64.Vector fast := true bU, _ := untransposeExtract(b) if rv, ok := bU.(*VecDense); ok { bmat = rv.mat if v != b { v.checkOverlap(bmat) } } else { fast = false } v.reuseAsNonZeroed(r) var restore func() if v == aU { v, restore = v.isolatedWorkspace(aU.(*VecDense)) defer restore() } else if v == b { v, restore = v.isolatedWorkspace(b) defer restore() } // TODO(kortschak): Improve the non-fast paths. switch aU := aU.(type) { case Vector: if b.Len() == 1 { // {n,1} x {1,1} v.ScaleVec(b.AtVec(0), aU) return } // {1,n} x {n,1} if fast { if rv, ok := aU.(*VecDense); ok { amat := rv.mat if v != aU { v.checkOverlap(amat) } if amat.Inc == 1 && bmat.Inc == 1 { // Fast path for a common case. v.setVec(0, f64.DotUnitary(amat.Data, bmat.Data)) return } v.setVec(0, f64.DotInc(amat.Data, bmat.Data, uintptr(c), uintptr(amat.Inc), uintptr(bmat.Inc), 0, 0)) return } } var sum float64 for i := 0; i < c; i++ { sum += aU.AtVec(i) * b.AtVec(i) } v.setVec(0, sum) return case *SymBandDense: if fast { aU.checkOverlap(v.asGeneral()) blas64.Sbmv(1, aU.mat, bmat, 0, v.mat) return } case *SymDense: if fast { aU.checkOverlap(v.asGeneral()) blas64.Symv(1, aU.mat, bmat, 0, v.mat) return } case *TriDense: if fast { v.CopyVec(b) aU.checkOverlap(v.asGeneral()) ta := blas.NoTrans if trans { ta = blas.Trans } blas64.Trmv(ta, aU.mat, v.mat) return } case *Dense: if fast { aU.checkOverlap(v.asGeneral()) t := blas.NoTrans if trans { t = blas.Trans } blas64.Gemv(t, 1, aU.mat, bmat, 0, v.mat) return } default: if fast { for i := 0; i < r; i++ { var f float64 for j := 0; j < c; j++ { f += a.At(i, j) * bmat.Data[j*bmat.Inc] } v.setVec(i, f) } return } } for i := 0; i < r; i++ { var f float64 for j := 0; j < c; j++ { f += a.At(i, j) * b.AtVec(j) } v.setVec(i, f) } } // ReuseAsVec changes the receiver if it IsEmpty() to be of size n×1. // // ReuseAsVec re-uses the backing data slice if it has sufficient capacity, // otherwise a new slice is allocated. The backing data is zero on return. // // ReuseAsVec panics if the receiver is not empty, and panics if // the input size is less than one. To empty the receiver for re-use, // Reset should be used. func (v *VecDense) ReuseAsVec(n int) { if n <= 0 { if n == 0 { panic(ErrZeroLength) } panic(ErrNegativeDimension) } if !v.IsEmpty() { panic(ErrReuseNonEmpty) } v.reuseAsZeroed(n) } // reuseAsNonZeroed resizes an empty vector to a r×1 vector, // or checks that a non-empty matrix is r×1. func (v *VecDense) reuseAsNonZeroed(r int) { // reuseAsNonZeroed must be kept in sync with reuseAsZeroed. if r == 0 { panic(ErrZeroLength) } if v.IsEmpty() { v.mat = blas64.Vector{ N: r, Inc: 1, Data: use(v.mat.Data, r), } return } if r != v.mat.N { panic(ErrShape) } } // reuseAsZeroed resizes an empty vector to a r×1 vector, // or checks that a non-empty matrix is r×1. func (v *VecDense) reuseAsZeroed(r int) { // reuseAsZeroed must be kept in sync with reuseAsNonZeroed. if r == 0 { panic(ErrZeroLength) } if v.IsEmpty() { v.mat = blas64.Vector{ N: r, Inc: 1, Data: useZeroed(v.mat.Data, r), } return } if r != v.mat.N { panic(ErrShape) } v.Zero() } // IsEmpty returns whether the receiver is empty. Empty matrices can be the // receiver for size-restricted operations. The receiver can be emptied using // Reset. func (v *VecDense) IsEmpty() bool { // It must be the case that v.Dims() returns // zeros in this case. See comment in Reset(). return v.mat.Inc == 0 } func (v *VecDense) isolatedWorkspace(a Vector) (n *VecDense, restore func()) { l := a.Len() if l == 0 { panic(ErrZeroLength) } n = getVecDenseWorkspace(l, false) return n, func() { v.CopyVec(n) putVecDenseWorkspace(n) } } // asDense returns a Dense representation of the receiver with the same // underlying data. func (v *VecDense) asDense() *Dense { return &Dense{ mat: v.asGeneral(), capRows: v.mat.N, capCols: 1, } } // asGeneral returns a blas64.General representation of the receiver with the // same underlying data. func (v *VecDense) asGeneral() blas64.General { return blas64.General{ Rows: v.mat.N, Cols: 1, Stride: v.mat.Inc, Data: v.mat.Data, } } // ColViewOf reflects the column j of the RawMatrixer m, into the receiver // backed by the same underlying data. The receiver must either be empty // have length equal to the number of rows of m. func (v *VecDense) ColViewOf(m RawMatrixer, j int) { rm := m.RawMatrix() if j >= rm.Cols || j < 0 { panic(ErrColAccess) } if !v.IsEmpty() && v.mat.N != rm.Rows { panic(ErrShape) } v.mat.Inc = rm.Stride v.mat.Data = rm.Data[j : (rm.Rows-1)*rm.Stride+j+1] v.mat.N = rm.Rows } // RowViewOf reflects the row i of the RawMatrixer m, into the receiver // backed by the same underlying data. The receiver must either be // empty or have length equal to the number of columns of m. func (v *VecDense) RowViewOf(m RawMatrixer, i int) { rm := m.RawMatrix() if i >= rm.Rows || i < 0 { panic(ErrRowAccess) } if !v.IsEmpty() && v.mat.N != rm.Cols { panic(ErrShape) } v.mat.Inc = 1 v.mat.Data = rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols] v.mat.N = rm.Cols } golang-gonum-v1-gonum-0.14.0/mat/vector_example_test.go000066400000000000000000000030341450372207100230220ustar00rootroot00000000000000// Copyright ©2019 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/mat" ) // This example shows how simple user types can be constructed to // implement basic vector functionality within the mat package. func Example_userVectors() { // Perform the cross product of [1 2 3 4] and [1 2 3]. r := row{1, 2, 3, 4} c := column{1, 2, 3} var m mat.Dense m.Mul(c, r) fmt.Println(mat.Formatted(&m)) // Output: // // ⎡ 1 2 3 4⎤ // ⎢ 2 4 6 8⎥ // ⎣ 3 6 9 12⎦ } // row is a user-defined row vector. type row []float64 // Dims, At and T minimally satisfy the mat.Matrix interface. func (v row) Dims() (r, c int) { return 1, len(v) } func (v row) At(_, j int) float64 { return v[j] } func (v row) T() mat.Matrix { return column(v) } // RawVector allows fast path computation with the vector. func (v row) RawVector() blas64.Vector { return blas64.Vector{N: len(v), Data: v, Inc: 1} } // column is a user-defined column vector. type column []float64 // Dims, At and T minimally satisfy the mat.Matrix interface. func (v column) Dims() (r, c int) { return len(v), 1 } func (v column) At(i, _ int) float64 { return v[i] } func (v column) T() mat.Matrix { return row(v) } // RawVector allows fast path computation with the vector. func (v column) RawVector() blas64.Vector { return blas64.Vector{N: len(v), Data: v, Inc: 1} } golang-gonum-v1-gonum-0.14.0/mat/vector_test.go000066400000000000000000000433551450372207100213210ustar00rootroot00000000000000// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat import ( "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/blas/blas64" ) func TestNewVecDense(t *testing.T) { t.Parallel() for i, test := range []struct { n int data []float64 vector *VecDense }{ { n: 3, data: []float64{4, 5, 6}, vector: &VecDense{ mat: blas64.Vector{ N: 3, Data: []float64{4, 5, 6}, Inc: 1, }, }, }, { n: 3, data: nil, vector: &VecDense{ mat: blas64.Vector{ N: 3, Data: []float64{0, 0, 0}, Inc: 1, }, }, }, } { v := NewVecDense(test.n, test.data) rows, cols := v.Dims() if rows != test.n { t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.n) } if cols != 1 { t.Errorf("unexpected number of cols for test %d: got: %d want: 1", i, cols) } if !reflect.DeepEqual(v, test.vector) { t.Errorf("unexpected data slice for test %d: got: %v want: %v", i, v, test.vector) } } } func TestCap(t *testing.T) { t.Parallel() for i, test := range []struct { vector *VecDense want int }{ {vector: NewVecDense(3, nil), want: 3}, { vector: &VecDense{ mat: blas64.Vector{ N: 3, Data: make([]float64, 7, 10), Inc: 3, }, }, want: 4, }, { vector: &VecDense{ mat: blas64.Vector{ N: 4, Data: make([]float64, 10), Inc: 3, }, }, want: 4, }, { vector: &VecDense{ mat: blas64.Vector{ N: 4, Data: make([]float64, 11), Inc: 3, }, }, want: 4, }, { vector: &VecDense{ mat: blas64.Vector{ N: 4, Data: make([]float64, 12), Inc: 3, }, }, want: 4, }, { vector: &VecDense{ mat: blas64.Vector{ N: 4, Data: make([]float64, 13), Inc: 3, }, }, want: 5, }, } { got := test.vector.Cap() if got != test.want { t.Errorf("unexpected capacty for test %d: got: %d want: %d", i, got, test.want) } } } func TestVecDenseAtSet(t *testing.T) { t.Parallel() for i, test := range []struct { vector *VecDense }{ { vector: &VecDense{ mat: blas64.Vector{ N: 3, Data: []float64{0, 1, 2}, Inc: 1, }, }, }, { vector: &VecDense{ mat: blas64.Vector{ N: 3, Data: []float64{0, 10, 10, 1, 10, 10, 2}, Inc: 3, }, }, }, } { v := test.vector n := test.vector.mat.N for _, row := range []int{-1, n} { panicked, message := panics(func() { v.At(row, 0) }) if !panicked || message != ErrRowAccess.Error() { t.Errorf("expected panic for invalid row access for test %d n=%d r=%d", i, n, row) } } for _, col := range []int{-1, 1} { panicked, message := panics(func() { v.At(0, col) }) if !panicked || message != ErrColAccess.Error() { t.Errorf("expected panic for invalid column access for test %d n=%d c=%d", i, n, col) } } for _, row := range []int{0, 1, n - 1} { if e := v.At(row, 0); e != float64(row) { t.Errorf("unexpected value for At(%d, 0) for test %d : got: %v want: %v", row, i, e, float64(row)) } } for _, row := range []int{-1, n} { panicked, message := panics(func() { v.SetVec(row, 100) }) if !panicked || message != ErrVectorAccess.Error() { t.Errorf("expected panic for invalid row access for test %d n=%d r=%d", i, n, row) } } for inc, row := range []int{0, 2} { v.SetVec(row, 100+float64(inc)) if e := v.At(row, 0); e != 100+float64(inc) { t.Errorf("unexpected value for At(%d, 0) after SetVec(%[1]d, %v) for test %d: got: %v want: %[2]v", row, 100+float64(inc), i, e) } } } } func TestVecDenseZero(t *testing.T) { t.Parallel() // Elements that equal 1 should be set to zero, elements that equal -1 // should remain unchanged. for _, test := range []*VecDense{ { mat: blas64.Vector{ N: 5, Inc: 2, Data: []float64{ 1, -1, 1, -1, 1, -1, 1, -1, 1, }, }, }, } { dataCopy := make([]float64, len(test.mat.Data)) copy(dataCopy, test.mat.Data) test.Zero() for i, v := range test.mat.Data { if dataCopy[i] != -1 && v != 0 { t.Errorf("Matrix not zeroed in bounds") } if dataCopy[i] == -1 && v != -1 { t.Errorf("Matrix zeroed out of bounds") } } } } func TestVecDenseMul(t *testing.T) { t.Parallel() method := func(receiver, a, b Matrix) { type mulVecer interface { MulVec(a Matrix, b Vector) } rd := receiver.(mulVecer) rd.MulVec(a, b.(Vector)) } denseComparison := func(receiver, a, b *Dense) { receiver.Mul(a, b) } legalSizeMulVec := func(ar, ac, br, bc int) bool { var legal bool if bc != 1 { legal = false } else { legal = ac == br } return legal } testTwoInput(t, "MulVec", &VecDense{}, method, denseComparison, legalTypesMatrixVector, legalSizeMulVec, 1e-14) } func TestVecDenseScale(t *testing.T) { t.Parallel() for i, test := range []struct { a Vector alpha float64 want *VecDense }{ { a: NewVecDense(3, []float64{0, 1, 2}), alpha: 0, want: NewVecDense(3, []float64{0, 0, 0}), }, { a: NewVecDense(3, []float64{0, 1, 2}), alpha: 1, want: NewVecDense(3, []float64{0, 1, 2}), }, { a: NewVecDense(3, []float64{0, 1, 2}), alpha: -2, want: NewVecDense(3, []float64{0, -2, -4}), }, { a: NewDense(3, 1, []float64{0, 1, 2}).ColView(0), alpha: 0, want: NewVecDense(3, []float64{0, 0, 0}), }, { a: NewDense(3, 1, []float64{0, 1, 2}).ColView(0), alpha: 1, want: NewVecDense(3, []float64{0, 1, 2}), }, { a: NewDense(3, 1, []float64{0, 1, 2}).ColView(0), alpha: -2, want: NewVecDense(3, []float64{0, -2, -4}), }, { a: NewDense(3, 3, []float64{ 0, 1, 2, 3, 4, 5, 6, 7, 8, }).ColView(1), alpha: -2, want: NewVecDense(3, []float64{-2, -8, -14}), }, } { var v VecDense v.ScaleVec(test.alpha, test.a.(*VecDense)) if !reflect.DeepEqual(v.RawVector(), test.want.RawVector()) { t.Errorf("test %d: unexpected result for v = alpha * a: got: %v want: %v", i, v.RawVector(), test.want.RawVector()) } v.CopyVec(test.a.(*VecDense)) v.ScaleVec(test.alpha, &v) if !reflect.DeepEqual(v.RawVector(), test.want.RawVector()) { t.Errorf("test %d: unexpected result for v = alpha * v: got: %v want: %v", i, v.RawVector(), test.want.RawVector()) } } for _, alpha := range []float64{0, 1, -1, 2.3, -2.3} { method := func(receiver, a Matrix) { type scaleVecer interface { ScaleVec(float64, Vector) } v := receiver.(scaleVecer) v.ScaleVec(alpha, a.(Vector)) } denseComparison := func(receiver, a *Dense) { receiver.Scale(alpha, a) } testOneInput(t, "ScaleVec", &VecDense{}, method, denseComparison, legalTypeVector, isAnyColumnVector, 0) } } func TestCopyVec(t *testing.T) { t.Parallel() for i, test := range []struct { src *VecDense dst *VecDense want *VecDense wantN int }{ {src: NewVecDense(1, nil), dst: NewVecDense(1, nil), want: NewVecDense(1, nil), wantN: 1}, {src: NewVecDense(3, []float64{1, 2, 3}), dst: NewVecDense(2, []float64{-1, -2}), want: NewVecDense(2, []float64{1, 2}), wantN: 2}, {src: NewVecDense(2, []float64{1, 2}), dst: NewVecDense(3, []float64{-1, -2, -3}), want: NewVecDense(3, []float64{1, 2, -3}), wantN: 2}, } { got := test.dst var n int panicked, message := panics(func() { n = got.CopyVec(test.src) }) if panicked { t.Errorf("unexpected panic during vector copy for test %d: %s", i, message) } if !Equal(got, test.want) { t.Errorf("test %d: unexpected result CopyVec:\ngot: %v\nwant:%v", i, got, test.want) } if n != test.wantN { t.Errorf("test %d: unexpected result number of elements copied: got:%d want:%d", i, n, test.wantN) } } } func TestVecDenseAddScaled(t *testing.T) { t.Parallel() for _, alpha := range []float64{0, 1, -1, 2.3, -2.3} { method := func(receiver, a, b Matrix) { type addScaledVecer interface { AddScaledVec(Vector, float64, Vector) } v := receiver.(addScaledVecer) v.AddScaledVec(a.(Vector), alpha, b.(Vector)) } denseComparison := func(receiver, a, b *Dense) { var sb Dense sb.Scale(alpha, b) receiver.Add(a, &sb) } testTwoInput(t, "AddScaledVec", &VecDense{}, method, denseComparison, legalTypesVectorVector, legalSizeSameVec, 1e-14) } } func TestVecDenseAdd(t *testing.T) { t.Parallel() for i, test := range []struct { a, b Vector want *VecDense }{ { a: NewVecDense(3, []float64{0, 1, 2}), b: NewVecDense(3, []float64{0, 2, 3}), want: NewVecDense(3, []float64{0, 3, 5}), }, { a: NewVecDense(3, []float64{0, 1, 2}), b: NewDense(3, 1, []float64{0, 2, 3}).ColView(0), want: NewVecDense(3, []float64{0, 3, 5}), }, { a: NewDense(3, 1, []float64{0, 1, 2}).ColView(0), b: NewDense(3, 1, []float64{0, 2, 3}).ColView(0), want: NewVecDense(3, []float64{0, 3, 5}), }, } { var v VecDense v.AddVec(test.a.(*VecDense), test.b.(*VecDense)) if !reflect.DeepEqual(v.RawVector(), test.want.RawVector()) { t.Errorf("unexpected result for test %d: got: %v want: %v", i, v.RawVector(), test.want.RawVector()) } } } func TestVecDenseSub(t *testing.T) { t.Parallel() for i, test := range []struct { a, b Vector want *VecDense }{ { a: NewVecDense(3, []float64{0, 1, 2}), b: NewVecDense(3, []float64{0, 0.5, 1}), want: NewVecDense(3, []float64{0, 0.5, 1}), }, { a: NewVecDense(3, []float64{0, 1, 2}), b: NewDense(3, 1, []float64{0, 0.5, 1}).ColView(0), want: NewVecDense(3, []float64{0, 0.5, 1}), }, { a: NewDense(3, 1, []float64{0, 1, 2}).ColView(0), b: NewDense(3, 1, []float64{0, 0.5, 1}).ColView(0), want: NewVecDense(3, []float64{0, 0.5, 1}), }, } { var v VecDense v.SubVec(test.a.(*VecDense), test.b.(*VecDense)) if !reflect.DeepEqual(v.RawVector(), test.want.RawVector()) { t.Errorf("unexpected result for test %d: got: %v want: %v", i, v.RawVector(), test.want.RawVector()) } } } func TestVecDenseMulElem(t *testing.T) { t.Parallel() for i, test := range []struct { a, b Vector want *VecDense }{ { a: NewVecDense(3, []float64{0, 1, 2}), b: NewVecDense(3, []float64{0, 2, 3}), want: NewVecDense(3, []float64{0, 2, 6}), }, { a: NewVecDense(3, []float64{0, 1, 2}), b: NewDense(3, 1, []float64{0, 2, 3}).ColView(0), want: NewVecDense(3, []float64{0, 2, 6}), }, { a: NewDense(3, 1, []float64{0, 1, 2}).ColView(0), b: NewDense(3, 1, []float64{0, 2, 3}).ColView(0), want: NewVecDense(3, []float64{0, 2, 6}), }, } { var v VecDense v.MulElemVec(test.a.(*VecDense), test.b.(*VecDense)) if !reflect.DeepEqual(v.RawVector(), test.want.RawVector()) { t.Errorf("unexpected result for test %d: got: %v want: %v", i, v.RawVector(), test.want.RawVector()) } } } func TestVecDenseDivElem(t *testing.T) { t.Parallel() for i, test := range []struct { a, b Vector want *VecDense }{ { a: NewVecDense(3, []float64{0.5, 1, 2}), b: NewVecDense(3, []float64{0.5, 0.5, 1}), want: NewVecDense(3, []float64{1, 2, 2}), }, { a: NewVecDense(3, []float64{0.5, 1, 2}), b: NewDense(3, 1, []float64{0.5, 0.5, 1}).ColView(0), want: NewVecDense(3, []float64{1, 2, 2}), }, { a: NewDense(3, 1, []float64{0.5, 1, 2}).ColView(0), b: NewDense(3, 1, []float64{0.5, 0.5, 1}).ColView(0), want: NewVecDense(3, []float64{1, 2, 2}), }, } { var v VecDense v.DivElemVec(test.a.(*VecDense), test.b.(*VecDense)) if !reflect.DeepEqual(v.RawVector(), test.want.RawVector()) { t.Errorf("unexpected result for test %d: got: %v want: %v", i, v.RawVector(), test.want.RawVector()) } } } func BenchmarkAddScaledVec10Inc1(b *testing.B) { addScaledVecBench(b, 10, 1) } func BenchmarkAddScaledVec100Inc1(b *testing.B) { addScaledVecBench(b, 100, 1) } func BenchmarkAddScaledVec1000Inc1(b *testing.B) { addScaledVecBench(b, 1000, 1) } func BenchmarkAddScaledVec10000Inc1(b *testing.B) { addScaledVecBench(b, 10000, 1) } func BenchmarkAddScaledVec100000Inc1(b *testing.B) { addScaledVecBench(b, 100000, 1) } func BenchmarkAddScaledVec10Inc2(b *testing.B) { addScaledVecBench(b, 10, 2) } func BenchmarkAddScaledVec100Inc2(b *testing.B) { addScaledVecBench(b, 100, 2) } func BenchmarkAddScaledVec1000Inc2(b *testing.B) { addScaledVecBench(b, 1000, 2) } func BenchmarkAddScaledVec10000Inc2(b *testing.B) { addScaledVecBench(b, 10000, 2) } func BenchmarkAddScaledVec100000Inc2(b *testing.B) { addScaledVecBench(b, 100000, 2) } func BenchmarkAddScaledVec10Inc20(b *testing.B) { addScaledVecBench(b, 10, 20) } func BenchmarkAddScaledVec100Inc20(b *testing.B) { addScaledVecBench(b, 100, 20) } func BenchmarkAddScaledVec1000Inc20(b *testing.B) { addScaledVecBench(b, 1000, 20) } func BenchmarkAddScaledVec10000Inc20(b *testing.B) { addScaledVecBench(b, 10000, 20) } func BenchmarkAddScaledVec100000Inc20(b *testing.B) { addScaledVecBench(b, 100000, 20) } func addScaledVecBench(b *testing.B, size, inc int) { src := rand.NewSource(1) x := randVecDense(size, inc, 1, src) y := randVecDense(size, inc, 1, src) b.ResetTimer() var v VecDense for i := 0; i < b.N; i++ { v.AddScaledVec(y, 2, x) } } func BenchmarkScaleVec10Inc1(b *testing.B) { scaleVecBench(b, 10, 1) } func BenchmarkScaleVec100Inc1(b *testing.B) { scaleVecBench(b, 100, 1) } func BenchmarkScaleVec1000Inc1(b *testing.B) { scaleVecBench(b, 1000, 1) } func BenchmarkScaleVec10000Inc1(b *testing.B) { scaleVecBench(b, 10000, 1) } func BenchmarkScaleVec100000Inc1(b *testing.B) { scaleVecBench(b, 100000, 1) } func BenchmarkScaleVec10Inc2(b *testing.B) { scaleVecBench(b, 10, 2) } func BenchmarkScaleVec100Inc2(b *testing.B) { scaleVecBench(b, 100, 2) } func BenchmarkScaleVec1000Inc2(b *testing.B) { scaleVecBench(b, 1000, 2) } func BenchmarkScaleVec10000Inc2(b *testing.B) { scaleVecBench(b, 10000, 2) } func BenchmarkScaleVec100000Inc2(b *testing.B) { scaleVecBench(b, 100000, 2) } func BenchmarkScaleVec10Inc20(b *testing.B) { scaleVecBench(b, 10, 20) } func BenchmarkScaleVec100Inc20(b *testing.B) { scaleVecBench(b, 100, 20) } func BenchmarkScaleVec1000Inc20(b *testing.B) { scaleVecBench(b, 1000, 20) } func BenchmarkScaleVec10000Inc20(b *testing.B) { scaleVecBench(b, 10000, 20) } func BenchmarkScaleVec100000Inc20(b *testing.B) { scaleVecBench(b, 100000, 20) } func scaleVecBench(b *testing.B, size, inc int) { src := rand.NewSource(1) x := randVecDense(size, inc, 1, src) b.ResetTimer() var v VecDense for i := 0; i < b.N; i++ { v.ScaleVec(2, x) } } func BenchmarkAddVec10Inc1(b *testing.B) { addVecBench(b, 10, 1) } func BenchmarkAddVec100Inc1(b *testing.B) { addVecBench(b, 100, 1) } func BenchmarkAddVec1000Inc1(b *testing.B) { addVecBench(b, 1000, 1) } func BenchmarkAddVec10000Inc1(b *testing.B) { addVecBench(b, 10000, 1) } func BenchmarkAddVec100000Inc1(b *testing.B) { addVecBench(b, 100000, 1) } func BenchmarkAddVec10Inc2(b *testing.B) { addVecBench(b, 10, 2) } func BenchmarkAddVec100Inc2(b *testing.B) { addVecBench(b, 100, 2) } func BenchmarkAddVec1000Inc2(b *testing.B) { addVecBench(b, 1000, 2) } func BenchmarkAddVec10000Inc2(b *testing.B) { addVecBench(b, 10000, 2) } func BenchmarkAddVec100000Inc2(b *testing.B) { addVecBench(b, 100000, 2) } func BenchmarkAddVec10Inc20(b *testing.B) { addVecBench(b, 10, 20) } func BenchmarkAddVec100Inc20(b *testing.B) { addVecBench(b, 100, 20) } func BenchmarkAddVec1000Inc20(b *testing.B) { addVecBench(b, 1000, 20) } func BenchmarkAddVec10000Inc20(b *testing.B) { addVecBench(b, 10000, 20) } func BenchmarkAddVec100000Inc20(b *testing.B) { addVecBench(b, 100000, 20) } func addVecBench(b *testing.B, size, inc int) { src := rand.NewSource(1) x := randVecDense(size, inc, 1, src) y := randVecDense(size, inc, 1, src) b.ResetTimer() var v VecDense for i := 0; i < b.N; i++ { v.AddVec(x, y) } } func BenchmarkSubVec10Inc1(b *testing.B) { subVecBench(b, 10, 1) } func BenchmarkSubVec100Inc1(b *testing.B) { subVecBench(b, 100, 1) } func BenchmarkSubVec1000Inc1(b *testing.B) { subVecBench(b, 1000, 1) } func BenchmarkSubVec10000Inc1(b *testing.B) { subVecBench(b, 10000, 1) } func BenchmarkSubVec100000Inc1(b *testing.B) { subVecBench(b, 100000, 1) } func BenchmarkSubVec10Inc2(b *testing.B) { subVecBench(b, 10, 2) } func BenchmarkSubVec100Inc2(b *testing.B) { subVecBench(b, 100, 2) } func BenchmarkSubVec1000Inc2(b *testing.B) { subVecBench(b, 1000, 2) } func BenchmarkSubVec10000Inc2(b *testing.B) { subVecBench(b, 10000, 2) } func BenchmarkSubVec100000Inc2(b *testing.B) { subVecBench(b, 100000, 2) } func BenchmarkSubVec10Inc20(b *testing.B) { subVecBench(b, 10, 20) } func BenchmarkSubVec100Inc20(b *testing.B) { subVecBench(b, 100, 20) } func BenchmarkSubVec1000Inc20(b *testing.B) { subVecBench(b, 1000, 20) } func BenchmarkSubVec10000Inc20(b *testing.B) { subVecBench(b, 10000, 20) } func BenchmarkSubVec100000Inc20(b *testing.B) { subVecBench(b, 100000, 20) } func subVecBench(b *testing.B, size, inc int) { src := rand.NewSource(1) x := randVecDense(size, inc, 1, src) y := randVecDense(size, inc, 1, src) b.ResetTimer() var v VecDense for i := 0; i < b.N; i++ { v.SubVec(x, y) } } func randVecDense(size, inc int, rho float64, src rand.Source) *VecDense { if size <= 0 { panic("bad vector size") } rnd := rand.New(src) data := make([]float64, size*inc) for i := range data { if rnd.Float64() < rho { data[i] = rnd.NormFloat64() } } return &VecDense{ mat: blas64.Vector{ N: size, Inc: inc, Data: data, }, } } func BenchmarkVectorSum100000(b *testing.B) { vectorSumBench(b, 100000) } var vectorSumForBench float64 func vectorSumBench(b *testing.B, size int) { src := rand.NewSource(1) a := randVecDense(size, 1, 1.0, src) b.ResetTimer() for i := 0; i < b.N; i++ { vectorSumForBench = Sum(a) } } golang-gonum-v1-gonum-0.14.0/mathext/000077500000000000000000000000001450372207100173105ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mathext/README.md000066400000000000000000000005271450372207100205730ustar00rootroot00000000000000# mathext [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/mathext)](https://pkg.go.dev/gonum.org/v1/gonum/mathext) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/mathext?status.svg)](https://godocs.io/gonum.org/v1/gonum/mathext) Package mathext implements basic elementary functions not included in the Go standard library. golang-gonum-v1-gonum-0.14.0/mathext/airy.go000066400000000000000000000027141450372207100206070ustar00rootroot00000000000000// Copyright ©2016 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 mathext import "gonum.org/v1/gonum/mathext/internal/amos" // AiryAi returns the value of the Airy function at z. The Airy function here, // Ai(z), is one of the two linearly independent solutions to // // y′′ - y*z = 0. // // See http://mathworld.wolfram.com/AiryFunctions.html for more detailed information. func AiryAi(z complex128) complex128 { // id specifies the order of the derivative to compute, // 0 for the function itself and 1 for the derivative. // kode specifies the scaling option. See the function // documentation for the exact behavior. id := 0 kode := 1 air, aii, _, _ := amos.Zairy(real(z), imag(z), id, kode) return complex(air, aii) } // AiryAiDeriv returns the value of the derivative of the Airy function at z. The // Airy function here, Ai(z), is one of the two linearly independent solutions to // // y′′ - y*z = 0. // // See http://mathworld.wolfram.com/AiryFunctions.html for more detailed information. func AiryAiDeriv(z complex128) complex128 { // id specifies the order of the derivative to compute, // 0 for the function itself and 1 for the derivative. // kode specifies the scaling option. See the function // documentation for the exact behavior. id := 1 kode := 1 air, aii, _, _ := amos.Zairy(real(z), imag(z), id, kode) return complex(air, aii) } golang-gonum-v1-gonum-0.14.0/mathext/airy_test.go000066400000000000000000000013301450372207100216370ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "math" "testing" ) func TestAiry(t *testing.T) { t.Parallel() for _, test := range []struct { z, ans complex128 }{ // Results computed using Octave. {5, 1.08344428136074e-04}, {5i, 29.9014823980070 + 21.6778315987835i}, } { ans := AiryAi(test.z) if math.Abs(real(ans)-real(test.ans)) > 1e-10 { t.Errorf("Real part mismatch. Got %v, want %v", real(ans), real(test.ans)) } if math.Abs(imag(ans)-imag(test.ans)) > 1e-10 { t.Errorf("Imaginary part mismatch. Got %v, want %v", imag(ans), imag(test.ans)) } } } golang-gonum-v1-gonum-0.14.0/mathext/beta.go000066400000000000000000000022031450372207100205470ustar00rootroot00000000000000// Copyright ©2016 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 mathext import "gonum.org/v1/gonum/mathext/internal/gonum" // Beta returns the value of the complete beta function B(a, b). It is defined as // // Γ(a)Γ(b) / Γ(a+b) // // Special cases are: // // B(a,b) returns NaN if a or b is Inf // B(a,b) returns NaN if a and b are 0 // B(a,b) returns NaN if a or b is NaN // B(a,b) returns NaN if a or b is < 0 // B(a,b) returns +Inf if a xor b is 0. // // See http://mathworld.wolfram.com/BetaFunction.html for more detailed informations. func Beta(a, b float64) float64 { return gonum.Beta(a, b) } // Lbeta returns the natural logarithm of the complete beta function B(a,b). // Lbeta is defined as: // // Ln(Γ(a)Γ(b)/Γ(a+b)) // // Special cases are: // // Lbeta(a,b) returns NaN if a or b is Inf // Lbeta(a,b) returns NaN if a and b are 0 // Lbeta(a,b) returns NaN if a or b is NaN // Lbeta(a,b) returns NaN if a or b is < 0 // Lbeta(a,b) returns +Inf if a xor b is 0. func Lbeta(a, b float64) float64 { return gonum.Lbeta(a, b) } golang-gonum-v1-gonum-0.14.0/mathext/beta_test.go000066400000000000000000000067571450372207100216300ustar00rootroot00000000000000// Copyright ©2016 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 mathext_test import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mathext" ) var betaTests = []struct { p, q float64 want float64 }{ { p: 1, q: 2, want: 0.5, // obtained from scipy.special.beta(1,2) (version=0.18.0) }, { p: 10, q: 20, want: 4.9925087406346778e-09, // obtained from scipy.special.beta(10,20) (version=0.18.0) }, { p: +0, q: 10, want: math.Inf(+1), }, { p: -0, q: 10, want: math.Inf(+1), }, { p: 0, q: 0, want: math.NaN(), }, { p: 0, q: math.Inf(-1), want: math.NaN(), }, { p: 10, q: math.Inf(-1), want: math.NaN(), }, { p: 0, q: math.Inf(+1), want: math.NaN(), }, { p: 10, q: math.Inf(+1), want: math.NaN(), }, { p: math.NaN(), q: 10, want: math.NaN(), }, { p: math.NaN(), q: 0, want: math.NaN(), }, { p: -1, q: 0, want: math.NaN(), }, { p: -1, q: +1, want: math.NaN(), }, } func TestBeta(t *testing.T) { t.Parallel() for i, test := range betaTests { v := mathext.Beta(test.p, test.q) testOK := func(x float64) bool { return scalar.EqualWithinAbsOrRel(x, test.want, 1e-15, 1e-15) || (math.IsNaN(test.want) && math.IsNaN(x)) } if !testOK(v) { t.Errorf("test #%d: Beta(%v, %v)=%v. want=%v\n", i, test.p, test.q, v, test.want, ) } u := mathext.Beta(test.q, test.p) if !testOK(u) { t.Errorf("test #%[1]d: Beta(%[2]v, %[3]v)=%[4]v != Beta(%[3]v, %[2]v)=%[5]v)\n", i, test.p, test.q, v, u, ) } if math.IsInf(v, +1) || math.IsNaN(v) { continue } vv := mathext.Beta(test.p, test.q+1) uu := mathext.Beta(test.p+1, test.q) if !scalar.EqualWithinAbsOrRel(v, vv+uu, 1e-15, 1e-15) { t.Errorf( "test #%[1]d: Beta(%[2]v, %[3]v)=%[4]v != Beta(%[2]v+1, %[3]v) + Beta(%[2]v, %[3]v+1) (=%[5]v + %[6]v = %[7]v)\n", i, test.p, test.q, v, uu, vv, uu+vv, ) } vbeta2 := beta2(test.p, test.q) if !scalar.EqualWithinAbsOrRel(v, vbeta2, 1e-15, 1e-15) { t.Errorf( "test #%[1]d: Beta(%[2]v, %[3]v) != Γ(p)Γ(q) / Γ(p+q) (v=%[4]v u=%[5]v)\n", i, test.p, test.q, v, vbeta2, ) } } } func beta2(x, y float64) float64 { return math.Gamma(x) * math.Gamma(y) / math.Gamma(x+y) } func BenchmarkBeta(b *testing.B) { for i := 0; i < b.N; i++ { _ = mathext.Beta(10, 20) } } func BenchmarkBeta2(b *testing.B) { for i := 0; i < b.N; i++ { _ = math.Gamma(10) * math.Gamma(20) / math.Gamma(10+20) } } func TestLbeta(t *testing.T) { t.Parallel() for i, test := range betaTests { want := math.Log(test.want) v := mathext.Lbeta(test.p, test.q) testOK := func(x float64) bool { return scalar.EqualWithinAbsOrRel(x, want, 1e-15, 1e-15) || (math.IsNaN(want) && math.IsNaN(x)) } if !testOK(v) { t.Errorf("test #%d: Lbeta(%v, %v)=%v. want=%v\n", i, test.p, test.q, v, want, ) } u := mathext.Lbeta(test.q, test.p) if !testOK(u) { t.Errorf("test #%[1]d: Lbeta(%[2]v, %[3]v)=%[4]v != Lbeta(%[3]v, %[2]v)=%[5]v)\n", i, test.p, test.q, v, u, ) } if math.IsInf(v, +1) || math.IsNaN(v) { continue } vbeta2 := math.Log(beta2(test.p, test.q)) if !scalar.EqualWithinAbsOrRel(v, vbeta2, 1e-15, 1e-15) { t.Errorf( "test #%[1]d: Lbeta(%[2]v, %[3]v) != Log(Γ(p)Γ(q) / Γ(p+q)) (v=%[4]v u=%[5]v)\n", i, test.p, test.q, v, vbeta2, ) } } } golang-gonum-v1-gonum-0.14.0/mathext/betainc.go000066400000000000000000000021431450372207100212440ustar00rootroot00000000000000// Copyright ©2016 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 mathext import "gonum.org/v1/gonum/mathext/internal/cephes" // RegIncBeta returns the value of the regularized incomplete beta function // I(x;a,b). It is defined as // // I(x;a,b) = B(x;a,b) / B(a,b) // = Γ(a+b) / (Γ(a)*Γ(b)) * int_0^x u^(a-1) * (1-u)^(b-1) du. // // The domain of definition is 0 <= x <= 1, and the parameters a and b must be positive. // For other values of x, a, and b RegIncBeta will panic. func RegIncBeta(a, b float64, x float64) float64 { return cephes.Incbet(a, b, x) } // InvRegIncBeta computes the inverse of the regularized incomplete beta function. // It returns the x for which // // y = I(x;a,b) // // The domain of definition is 0 <= y <= 1, and the parameters a and b must be // positive. For other values of x, a, and b InvRegIncBeta will panic. func InvRegIncBeta(a, b float64, y float64) float64 { if y < 0 || 1 < y { panic("mathext: parameter out of range") } return cephes.Incbi(a, b, y) } golang-gonum-v1-gonum-0.14.0/mathext/betainc_test.go000066400000000000000000000037501450372207100223100ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestIncBeta(t *testing.T) { t.Parallel() tol := 1e-14 tol2 := 1e-10 // Test against values from scipy for i, test := range []struct { a, b, x, ans float64 }{ {1, 1, 0.8, 0.8}, {1, 5, 0.8, 0.99968000000000001}, {10, 10, 0.8, 0.99842087945083291}, {10, 10, 0.1, 3.929882327128003e-06}, {10, 2, 0.4, 0.00073400320000000028}, {0.1, 0.2, 0.6, 0.69285678232066683}, {1, 10, 0.7489, 0.99999900352334858}, } { y := RegIncBeta(test.a, test.b, test.x) if !scalar.EqualWithinAbsOrRel(y, test.ans, tol, tol) { t.Errorf("Incomplete beta mismatch. Case %v: Got %v, want %v", i, y, test.ans) } yc := 1 - RegIncBeta(test.b, test.a, 1-test.x) if !scalar.EqualWithinAbsOrRel(y, yc, tol, tol) { t.Errorf("Incomplete beta complementary mismatch. Case %v: Got %v, want %v", i, y, yc) } x := InvRegIncBeta(test.a, test.b, y) if !scalar.EqualWithinAbsOrRel(x, test.x, tol2, tol2) { t.Errorf("Inverse incomplete beta mismatch. Case %v: Got %v, want %v", i, x, test.x) } } // Confirm that Invincbeta and Incbeta agree. Sweep over a variety of // a, b, and y values. tol = 1e-6 steps := 201 ints := make([]float64, steps) floats.Span(ints, 0, 1) sz := 51 min := 1e-2 max := 1e2 as := make([]float64, sz) floats.LogSpan(as, min, max) bs := make([]float64, sz) floats.LogSpan(bs, min, max) for _, a := range as { for _, b := range bs { for _, yr := range ints { x := InvRegIncBeta(a, b, yr) if x > 1-1e-6 { // Numerical error too large continue } y := RegIncBeta(a, b, x) if !scalar.EqualWithinAbsOrRel(yr, y, tol, tol) { t.Errorf("Mismatch between inv inc beta and inc beta. a = %v, b = %v, x = %v, got %v, want %v.", a, b, x, y, yr) break } } } } } golang-gonum-v1-gonum-0.14.0/mathext/digamma.go000066400000000000000000000021551450372207100212410ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "math" ) // Digamma returns the logorithmic derivative of the gamma function at x. // // ψ(x) = d/dx (Ln (Γ(x)). func Digamma(x float64) float64 { // This is adapted from // http://web.science.mq.edu.au/~mjohnson/code/digamma.c var result float64 switch { case math.IsNaN(x), math.IsInf(x, 1): return x case math.IsInf(x, -1): return math.NaN() case x == 0: return math.Copysign(math.Inf(1), -x) case x < 0: if x == math.Floor(x) { return math.NaN() } // Reflection formula, http://dlmf.nist.gov/5.5#E4 _, r := math.Modf(x) result = -math.Pi / math.Tan(math.Pi*r) x = 1 - x } for ; x < 7; x++ { // Recurrence relation, http://dlmf.nist.gov/5.5#E2 result -= 1 / x } x -= 0.5 xx := 1 / x xx2 := xx * xx xx4 := xx2 * xx2 // Asymptotic expansion, http://dlmf.nist.gov/5.11#E2 result += math.Log(x) + (1.0/24.0)*xx2 - (7.0/960.0)*xx4 + (31.0/8064.0)*xx4*xx2 - (127.0/30720.0)*xx4*xx4 return result } golang-gonum-v1-gonum-0.14.0/mathext/digamma_test.go000066400000000000000000000025151450372207100223000ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" ) var result float64 func TestDigamma(t *testing.T) { t.Parallel() const tol = 1e-10 for i, test := range []struct { x, want float64 }{ // Results computed using WolframAlpha. {0.0, math.Inf(-1)}, {math.Copysign(0.0, -1.0), math.Inf(1)}, {math.Inf(1), math.Inf(1)}, {math.Inf(-1), math.NaN()}, {math.NaN(), math.NaN()}, {-1.0, math.NaN()}, {-100.5, 4.615124601338064117341315601525112558522917517910505881343}, {0.5, -1.96351002602142347944097633299875556719315960466043}, {10, 2.251752589066721107647456163885851537211808918028330369448}, {math.Pow10(20), 46.05170185988091368035482909368728415202202143924212618733}, {-1.111111111e9, math.NaN()}, {1.46, -0.001580561987083417676105544023567034348339520110000}, } { got := Digamma(test.x) if !(math.IsNaN(got) && math.IsNaN(test.want)) && !scalar.EqualWithinAbsOrRel(got, test.want, tol, tol) { t.Errorf("test %d Digamma(%g) failed: got %g want %g", i, test.x, got, test.want) } } } func BenchmarkDigamma(b *testing.B) { var r float64 for i := 0; i < b.N; i++ { r = Digamma(-1.111111111e9) } result = r } golang-gonum-v1-gonum-0.14.0/mathext/doc.go000066400000000000000000000005001450372207100203770ustar00rootroot00000000000000// 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 mathext implements special math functions not implemented by the // Go standard library. package mathext // import "gonum.org/v1/gonum/mathext" golang-gonum-v1-gonum-0.14.0/mathext/ell_carlson.go000066400000000000000000000135061450372207100221410ustar00rootroot00000000000000// 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 mathext import ( "math" ) // EllipticRF computes the symmetric elliptic integral R_F(x,y,z): // // R_F(x,y,z) = (1/2)\int_{0}^{\infty}{1/s(t)} dt, // s(t) = \sqrt{(t+x)(t+y)(t+z)}. // // The arguments x, y, z must satisfy the following conditions, otherwise the function returns math.NaN(): // // 0 ≤ x,y,z ≤ upper, // lower ≤ x+y,y+z,z+x, // // where: // // lower = 5/(2^1022) = 1.112536929253601e-307, // upper = (2^1022)/5 = 8.988465674311580e+306. // // The definition of the symmetric elliptic integral R_F can be found in NIST // Digital Library of Mathematical Functions (http://dlmf.nist.gov/19.16.E1). func EllipticRF(x, y, z float64) float64 { // The original Fortran code was published as Algorithm 577 in ACM TOMS (http://doi.org/10.1145/355958.355970). // This code is also available as a part of SLATEC Common Mathematical Library (http://netlib.org/slatec/index.html). Later, Carlson described // an improved version in http://dx.doi.org/10.1007/BF02198293 (also available at https://arxiv.org/abs/math/9409227). const ( lower = 5.0 / (1 << 256) / (1 << 256) / (1 << 256) / (1 << 254) // 5*2^-1022 upper = 1 / lower tol = 1.2674918778210762260320167734407048051023273568443e-02 // (3ε)^(1/8) ) if x < 0 || y < 0 || z < 0 || math.IsNaN(x) || math.IsNaN(y) || math.IsNaN(z) { return math.NaN() } if upper < x || upper < y || upper < z { return math.NaN() } if x+y < lower || y+z < lower || z+x < lower { return math.NaN() } A0 := (x + y + z) / 3 An := A0 Q := math.Max(math.Max(math.Abs(A0-x), math.Abs(A0-y)), math.Abs(A0-z)) / tol xn, yn, zn := x, y, z mul := 1.0 for Q >= mul*math.Abs(An) { xnsqrt, ynsqrt, znsqrt := math.Sqrt(xn), math.Sqrt(yn), math.Sqrt(zn) lambda := xnsqrt*ynsqrt + ynsqrt*znsqrt + znsqrt*xnsqrt An = (An + lambda) * 0.25 xn = (xn + lambda) * 0.25 yn = (yn + lambda) * 0.25 zn = (zn + lambda) * 0.25 mul *= 4 } X := (A0 - x) / (mul * An) Y := (A0 - y) / (mul * An) Z := -(X + Y) E2 := X*Y - Z*Z E3 := X * Y * Z // http://dlmf.nist.gov/19.36.E1 return (1 - 1/10.0*E2 + 1/14.0*E3 + 1/24.0*E2*E2 - 3/44.0*E2*E3 - 5/208.0*E2*E2*E2 + 3/104.0*E3*E3 + 1/16.0*E2*E2*E3) / math.Sqrt(An) } // EllipticRD computes the symmetric elliptic integral R_D(x,y,z): // // R_D(x,y,z) = (1/2)\int_{0}^{\infty}{1/(s(t)(t+z))} dt, // s(t) = \sqrt{(t+x)(t+y)(t+z)}. // // The arguments x, y, z must satisfy the following conditions, otherwise the function returns math.NaN(): // // 0 ≤ x,y ≤ upper, // lower ≤ z ≤ upper, // lower ≤ x+y, // // where: // // lower = (5/(2^1022))^(1/3) = 4.809554074311679e-103, // upper = ((2^1022)/5)^(1/3) = 2.079194837087086e+102. // // The definition of the symmetric elliptic integral R_D can be found in NIST // Digital Library of Mathematical Functions (http://dlmf.nist.gov/19.16.E5). func EllipticRD(x, y, z float64) float64 { // The original Fortran code was published as Algorithm 577 in ACM TOMS (http://doi.org/10.1145/355958.355970). // This code is also available as a part of SLATEC Common Mathematical Library (http://netlib.org/slatec/index.html). Later, Carlson described // an improved version in http://dx.doi.org/10.1007/BF02198293 (also available at https://arxiv.org/abs/math/9409227). const ( lower = 4.8095540743116787026618007863123676393525016818363e-103 // (5*2^-1022)^(1/3) upper = 1 / lower tol = 9.0351169339315770474760122547068324993857488849382e-03 // (ε/5)^(1/8) ) if x < 0 || y < 0 || math.IsNaN(x) || math.IsNaN(y) || math.IsNaN(z) { return math.NaN() } if upper < x || upper < y || upper < z { return math.NaN() } if x+y < lower || z < lower { return math.NaN() } A0 := (x + y + 3*z) / 5 An := A0 Q := math.Max(math.Max(math.Abs(A0-x), math.Abs(A0-y)), math.Abs(A0-z)) / tol xn, yn, zn := x, y, z mul, s := 1.0, 0.0 for Q >= mul*math.Abs(An) { xnsqrt, ynsqrt, znsqrt := math.Sqrt(xn), math.Sqrt(yn), math.Sqrt(zn) lambda := xnsqrt*ynsqrt + ynsqrt*znsqrt + znsqrt*xnsqrt s += 1 / (mul * znsqrt * (zn + lambda)) An = (An + lambda) * 0.25 xn = (xn + lambda) * 0.25 yn = (yn + lambda) * 0.25 zn = (zn + lambda) * 0.25 mul *= 4 } X := (A0 - x) / (mul * An) Y := (A0 - y) / (mul * An) Z := -(X + Y) / 3 E2 := X*Y - 6*Z*Z E3 := (3*X*Y - 8*Z*Z) * Z E4 := 3 * (X*Y - Z*Z) * Z * Z E5 := X * Y * Z * Z * Z // http://dlmf.nist.gov/19.36.E2 return (1-3/14.0*E2+1/6.0*E3+9/88.0*E2*E2-3/22.0*E4-9/52.0*E2*E3+3/26.0*E5-1/16.0*E2*E2*E2+3/40.0*E3*E3+3/20.0*E2*E4+45/272.0*E2*E2*E3-9/68.0*(E3*E4+E2*E5))/(mul*An*math.Sqrt(An)) + 3*s } // EllipticF computes the Legendre's elliptic integral of the 1st kind F(phi,m), 0≤m<1: // // F(\phi,m) = \int_{0}^{\phi} 1 / \sqrt{1-m\sin^2(\theta)} d\theta // // Legendre's elliptic integrals can be expressed as symmetric elliptic integrals, in this case: // // F(\phi,m) = \sin\phi R_F(\cos^2\phi,1-m\sin^2\phi,1) // // The definition of F(phi,k) where k=sqrt(m) can be found in NIST Digital Library of Mathematical // Functions (http://dlmf.nist.gov/19.2.E4). func EllipticF(phi, m float64) float64 { s, c := math.Sincos(phi) return s * EllipticRF(c*c, 1-m*s*s, 1) } // EllipticE computes the Legendre's elliptic integral of the 2nd kind E(phi,m), 0≤m<1: // // E(\phi,m) = \int_{0}^{\phi} \sqrt{1-m\sin^2(\theta)} d\theta // // Legendre's elliptic integrals can be expressed as symmetric elliptic integrals, in this case: // // E(\phi,m) = \sin\phi R_F(\cos^2\phi,1-m\sin^2\phi,1)-(m/3)\sin^3\phi R_D(\cos^2\phi,1-m\sin^2\phi,1) // // The definition of E(phi,k) where k=sqrt(m) can be found in NIST Digital Library of Mathematical // Functions (http://dlmf.nist.gov/19.2.E5). func EllipticE(phi, m float64) float64 { s, c := math.Sincos(phi) x, y := c*c, 1-m*s*s return s * (EllipticRF(x, y, 1) - (m/3)*s*s*EllipticRD(x, y, 1)) } golang-gonum-v1-gonum-0.14.0/mathext/ell_carlson_test.go000066400000000000000000000067771450372207100232140ustar00rootroot00000000000000// 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 mathext import ( "math" "testing" "golang.org/x/exp/rand" ) // Testing EllipticF (and EllipticRF) using the addition theorems from http://dlmf.nist.gov/19.11.i func TestEllipticF(t *testing.T) { t.Parallel() const tol = 1.0e-14 rnd := rand.New(rand.NewSource(1)) // The following EllipticF(pi/3,m), m=0.1(0.1)0.9 was computed in Maxima 5.38.0 using Bigfloat arithmetic. vF := [...]float64{ 1.0631390181954904767742338285104637431858016483079, 1.0803778062523490005579242592072579594037132891908, 1.0991352230920430074586978843452269008747645822123, 1.1196949183404746257742176145632376703505764745654, 1.1424290580457772555013955266260457822322036529624, 1.1678400583161860445148860686430780757517286094732, 1.1966306515644649360767197589467723191317720122309, 1.2298294422249382706933871574135731278765534034979, 1.2690359140762658660446752406901433173504503955036, } phi := math.Pi / 3 for m := 1; m <= 9; m++ { mf := float64(m) / 10 delta := math.Abs(EllipticF(phi, mf) - vF[m-1]) if delta > tol { t.Fatalf("EllipticF(pi/3,m) test fail for m=%v", mf) } } for test := 0; test < 100; test++ { alpha := rnd.Float64() * math.Pi / 4 beta := rnd.Float64() * math.Pi / 4 for mi := 0; mi < 9999; mi++ { m := float64(mi) / 10000 Fa := EllipticF(alpha, m) Fb := EllipticF(beta, m) sina, cosa := math.Sincos(alpha) sinb, cosb := math.Sincos(beta) tan := (sina*math.Sqrt(1-m*sinb*sinb) + sinb*math.Sqrt(1-m*sina*sina)) / (cosa + cosb) gamma := 2 * math.Atan(tan) Fg := EllipticF(gamma, m) delta := math.Abs(Fa + Fb - Fg) if delta > tol { t.Fatalf("EllipticF test fail for m=%v, alpha=%v, beta=%v", m, alpha, beta) } } } } // Testing EllipticE (and EllipticRF, EllipticRD) using the addition theorems from http://dlmf.nist.gov/19.11.i func TestEllipticE(t *testing.T) { t.Parallel() const tol = 1.0e-14 rnd := rand.New(rand.NewSource(1)) // The following EllipticE(pi/3,m), m=0.1(0.1)0.9 was computed in Maxima 5.38.0 using Bigfloat arithmetic. vE := [...]float64{ 1.0316510822817691068014397636905610074934300946730, 1.0156973658341766636288643556414001451527597364432, 9.9929636467826398814855428365155224243586391115108e-1, 9.8240033979859736941287149003648737502960015189033e-1, 9.6495145764299257550956863602992167490195750321518e-1, 9.4687829659158090935158610908054896203271861698355e-1, 9.2809053417715769009517654522979827392794124845027e-1, 9.0847044378047233264777277954768245721857017157916e-1, 8.8785835036531301307661603341327881634688308777383e-1, } phi := math.Pi / 3 for m := 1; m <= 9; m++ { mf := float64(m) / 10 delta := math.Abs(EllipticE(phi, mf) - vE[m-1]) if delta > tol { t.Fatalf("EllipticE(pi/3,m) test fail for m=%v", mf) } } for test := 0; test < 100; test++ { alpha := rnd.Float64() * math.Pi / 4 beta := rnd.Float64() * math.Pi / 4 for mi := 0; mi < 9999; mi++ { m := float64(mi) / 10000 Ea := EllipticE(alpha, m) Eb := EllipticE(beta, m) sina, cosa := math.Sincos(alpha) sinb, cosb := math.Sincos(beta) tan := (sina*math.Sqrt(1-m*sinb*sinb) + sinb*math.Sqrt(1-m*sina*sina)) / (cosa + cosb) gamma := 2 * math.Atan(tan) Eg := EllipticE(gamma, m) delta := math.Abs(Ea + Eb - Eg - m*sina*sinb*math.Sin(gamma)) if delta > tol { t.Fatalf("EllipticE test fail for m=%v, alpha=%v, beta=%v", m, alpha, beta) } } } } golang-gonum-v1-gonum-0.14.0/mathext/ell_complete.go000066400000000000000000000432361450372207100223130ustar00rootroot00000000000000// 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 mathext import ( "math" ) // CompleteK computes the complete elliptic integral of the 1st kind, 0≤m≤1. It returns math.NaN() if m is not in [0,1]. // // K(m) = \int_{0}^{π/2} 1/{\sqrt{1-m{\sin^2θ}}} dθ func CompleteK(m float64) float64 { // Reference: // Toshio Fukushima, Precise and fast computation of complete elliptic integrals // by piecewise minimax rational function approximation, // Journal of Computational and Applied Mathematics, Volume 282, 2015, Pages 71-76. // https://doi.org/10.1016/j.cam.2014.12.038 // Original Fortran code available at: // https://www.researchgate.net/publication/295857819_xceitxt_F90_package_of_complete_elliptic_integral_computation if m < 0 || 1 < m || math.IsNaN(m) { return math.NaN() } mc := 1 - m if mc > 0.592990 { t := 2.45694208987494165*mc - 1.45694208987494165 t2 := t * t p := ((3703.75266375099019 + t2*(2744.82029097576810+t2*36.2381612593459565)) + t*(5462.47093231923466+t2*(543.839017382099411+t2*0.393188651542789784))) q := ((2077.94377067058435 + t2*(1959.05960044399275+t2*43.5464368440078942)) + t*(3398.00069767755460+t2*(472.794455487539279+t2))) return p / q } if mc > 0.350756 { t := 4.12823963605439369*mc - 1.44800482178389491 t2 := t * t p := ((4264.28203103974630 + t2*(3214.59187442783167+t2*43.2589626155454993)) + t*(6341.90978213264024+t2*(642.790566685354573+t2*0.475223892294445943))) q := ((2125.06914237062279 + t2*(2006.03187933518870+t2*44.1848041560412224)) + t*(3479.95663350926514+t2*(482.900172581418890+t2))) return p / q } if mc > 0.206924 { t := 6.95255575949719117*mc - 1.43865064797819679 t2 := t * t p := ((4870.25402224986382 + t2*(3738.29369283392307+t2*51.3609902253065926)) + t*(7307.18826377416591+t2*(754.928587580583704+t2*0.571948962277566451))) q := ((2172.51745704102287 + t2*(2056.13612019430497+t2*44.9026847057686146)) + t*(3565.04737778032566+t2*(493.962405117599400+t2))) return p / q } if mc > 0.121734 { t := 11.7384669562155183*mc - 1.42897053644793990 t2 := t * t p := ((5514.8512729127464 + t2*(4313.60788246750934+t2*60.598720224393536)) + t*(8350.4595896779631+t2*(880.27903031894216+t2*0.68504458747933773))) q := ((2218.41682813309737 + t2*(2107.97379949034285+t2*45.6911096775045314)) + t*(3650.41829123846319+t2*(505.74295207655096+t2))) return p / q } if mc > 0.071412 { t := 19.8720241643813839*mc - 1.41910098962680339 t2 := t * t p := ((6188.8743957372448 + t2*(4935.41351498551527+t2*70.981049144472361)) + t*(9459.3331440432847+t2*(1018.21910476032105+t2*0.81599895108245948))) q := ((2260.73112539748448 + t2*(2159.68721749761492+t2*46.5298955058476510)) + t*(3732.66955095581621+t2*(517.86964191812384+t2))) return p / q } if mc > 0.041770 { t := 33.7359152553808785*mc - 1.40914918021725929 t2 := t * t p := ((6879.5170681289562 + t2*(5594.8381504799829+t2*82.452856129147838)) + t*(10615.0836403687221+t2*(1167.26108955935542+t2*0.96592719058503951))) q := ((2296.88303450660439 + t2*(2208.74949754945558+t2*47.3844470709989137)) + t*(3807.37745652028212+t2*(529.79651353072921+t2))) return p / q } if mc > 0.024360 { t := 57.4382538770821367*mc - 1.39919586444572085 t2 := t * t p := ((7570.6827538712100 + t2*(6279.2661370014890+t2*94.886883830605940)) + t*(11792.9392624454532+t2*(1325.01058966228180+t2*1.13537029594409690))) q := ((2324.04824540459984 + t2*(2252.22250562615338+t2*48.2089280211559345)) + t*(3869.56755306385732+t2*(540.85752251676412+t2))) return p / q } if mc > 0.014165 { t := 98.0872976949485042*mc - 1.38940657184894556 t2 := t * t p := ((8247.2601660137746 + t2*(6974.7495213178613+t2*108.098282908839979)) + t*(12967.7060124572914+t2*(1488.54008220335966+t2*1.32411616748380686))) q := ((2340.47337508405427 + t2*(2287.70677154700516+t2*48.9575432570382154)) + t*(3915.63324533769906+t2*(550.45072377717361+t2))) return p / q } if mc > 0.008213 { t := 168.010752688172043*mc - 1.37987231182795699 t2 := t * t p := ((8894.2961573611293 + t2*(7666.5611739483371+t2*121.863474964652041)) + t*(14113.7038749808951+t2*(1654.60731579994159+t2*1.53112170837206117))) q := ((2344.88618943372377 + t2*(2313.28396270968662+t2*49.5906602613891184)) + t*(3942.81065054556536+t2*(558.07615380622169+t2))) return p / q } if mc > 0 { t := 1.0 - 121.758188238159016*mc p := -math.Log(mc*0.0625) * (34813.4518336350547 + t*(235.767716637974271+t*0.199792723884069485)) / (69483.5736412906324 + t*(614.265044703187382+t)) q := -mc * (9382.53386835986099 + t*(51.6478985993381223+t*0.00410754154682816898)) / (37327.7262507318317 + t*(408.017247271148538+t)) return p + q } return math.Inf(1) } // CompleteE computes the complete elliptic integral of the 2nd kind, 0≤m≤1. It returns math.NaN() if m is not in [0,1]. // // E(m) = \int_{0}^{π/2} {\sqrt{1-m{\sin^2θ}}} dθ func CompleteE(m float64) float64 { // Reference: // Toshio Fukushima, Precise and fast computation of complete elliptic integrals // by piecewise minimax rational function approximation, // Journal of Computational and Applied Mathematics, Volume 282, 2015, Pages 71-76. // https://doi.org/10.1016/j.cam.2014.12.038 // Original Fortran code available at: // https://www.researchgate.net/publication/295857819_xceitxt_F90_package_of_complete_elliptic_integral_computation if m < 0 || 1 < m || math.IsNaN(m) { return math.NaN() } mc := 1 - m if mc > 0.566638 { t := 2.30753965506897236*mc - 1.30753965506897236 t2 := t * t p := ((19702.2363352671642 + t2*(18177.1879313824040+t2*409.975559128654710)) + t*(31904.1559574281609+t2*(4362.94760768571862+t2*10.3244775335024885))) q := ((14241.2135819448616 + t2*(10266.4884503526076+t2*117.162100771599098)) + t*(20909.9899599927367+t2*(1934.86289070792954+t2))) return p / q } if mc > 0.315153 { t := 3.97638030101198879*mc - 1.25316818100483130 t2 := t * t p := ((16317.0721393008221 + t2*(15129.4009798463159+t2*326.113727011739428)) + t*(26627.8852140835023+t2*(3574.15857605556033+t2*7.93163724081373477))) q := ((13047.1505096551210 + t2*(9964.25173735060361+t2*117.670514069579649)) + t*(19753.5762165922376+t2*(1918.72232033637537+t2))) return p / q } if mc > 0.171355 { t := 6.95419964116329852*mc - 1.19163687951153702 t2 := t * t p := ((13577.3850240991520 + t2*(12871.9137872656293+t2*263.964361648520708)) + t*(22545.4744699553993+t2*(3000.74575264868572+t2*6.08522443139677663))) q := ((11717.3306408059832 + t2*(9619.40382323874064+t2*118.690522739531267)) + t*(18431.1264424290258+t2*(1904.06010727307491+t2))) return p / q } if mc > 0.090670 { t := 12.3938774245522712*mc - 1.12375286608415443 t2 := t * t p := ((11307.9485341543712 + t2*(11208.6068472959372+t2*219.253495956962613)) + t*(19328.6173704569489+t2*(2596.54874477084334+t2*4.66931143174036616))) q := ((10307.6837501971393 + t2*(9241.7604666150102+t2*120.498555754227847)) + t*(16982.2450249024383+t2*(1893.41905403040679+t2))) return p / q } if mc > 0.046453 { t := 22.6157360291290680*mc - 1.05056878576113260 t2 := t * t p := ((9383.1490856819874 + t2*(9977.2498973537718+t2*188.618148076418837)) + t*(16718.9730458676860+t2*(2323.49987246555537+t2*3.59313532204509922))) q := ((8877.1964704758383 + t2*(8840.2771293410661+t2*123.422125687316355)) + t*(15450.0537230364062+t2*(1889.13672102820913+t2))) return p / q } if mc > 0.022912 { t := 42.4790790535661187*mc - 0.973280659275306911 t2 := t * t p := ((7719.1171817802054 + t2*(9045.3996063894006+t2*169.386557799782496)) + t*(14521.7363804934985+t2*(2149.92068078627829+t2*2.78515570453129137))) q := ((7479.7539074698012 + t2*(8420.3848818926324+t2*127.802109608726363)) + t*(13874.4978011497847+t2*(1892.69753150329759+t2))) return p / q } if mc > 0.010809 { t := 82.6241427745187144*mc - 0.893084359249772784 t2 := t * t p := ((6261.6095608987273 + t2*(8304.3265605809870+t2*159.371262600702237)) + t*(12593.0874916293982+t2*(2048.68391263416822+t2*2.18867046462858104))) q := ((6156.4532048239501 + t2*(7979.7435857665227+t2*133.911640385965187)) + t*(12283.8373999680518+t2*(1903.60556312663537+t2))) return p / q } if mc > 0.004841 { t := 167.560321715817694*mc - 0.811159517426273458 t2 := t * t p := ((4978.06146583586728 + t2*(7664.6703673290453+t2*156.689647694892782)) + t*(10831.7178150656694+t2*(1995.66437151562090+t2*1.75859085945198570))) q := ((4935.56743322938333 + t2*(7506.8028283118051+t2*141.854303920116856)) + t*(10694.5510113880077+t2*(1918.38517009740321+t2))) return p / q } if mc > 0 { t := 1.0 - 206.568890725056806*mc p := -mc * math.Log(mc*0.0625) * (41566.6612602868736 + t*(154.034981522913482+t*0.0618072471798575991)) / (165964.442527585615 + t*(917.589668642251803+t)) q := (132232.803956682877 + t*(353.375480007017643-t*1.40105837312528026)) / (132393.665743088043 + t*(192.112635228732532-t)) return p + q } return 1 } // CompleteB computes an associate complete elliptic integral of the 2nd kind, 0≤m≤1. It returns math.NaN() if m is not in [0,1]. // // B(m) = \int_{0}^{π/2} {\cos^2θ} / {\sqrt{1-m{\sin^2θ}}} dθ func CompleteB(m float64) float64 { // Reference: // Toshio Fukushima, Precise and fast computation of complete elliptic integrals // by piecewise minimax rational function approximation, // Journal of Computational and Applied Mathematics, Volume 282, 2015, Pages 71-76. // https://doi.org/10.1016/j.cam.2014.12.038 // Original Fortran code available at: // https://www.researchgate.net/publication/295857819_xceitxt_F90_package_of_complete_elliptic_integral_computation if m < 0 || 1 < m || math.IsNaN(m) { return math.NaN() } mc := 1 - m if mc > 0.555073 { t := 2.24755971204264969*mc - 1.24755971204264969 t2 := t * t p := ((2030.25011505956379 + t2*(1727.60635612511943+t2*25.0715510300422010)) + t*(3223.16236100954529+t2*(361.164121995173076+t2*0.280355207707726826))) q := ((2420.64907902774675 + t2*(2327.48464880306840+t2*47.9870997057202318)) + t*(4034.28168313496638+t2*(549.234220839203960+t2))) return p / q } if mc > 0.302367 { t := 3.95716761770595079*mc - 1.19651690106289522 t2 := t * t p := ((2209.26925068374373 + t2*(1981.37862223307242+t2*29.7612810087709299)) + t*(3606.58475322372526+t2*(422.693774742063054+t2*0.334623999861181980))) q := ((2499.57898767250755 + t2*(2467.63998386656941+t2*50.0198090806651216)) + t*(4236.30953048456334+t2*(581.879599221457589+t2))) return p / q } if mc > 0.161052 { t := 7.07638962601280827*mc - 1.13966670204861480 t2 := t * t p := ((2359.14823394150129 + t2*(2254.30785457761760+t2*35.2259786264917876)) + t*(3983.28520266051676+t2*(492.601686517364701+t2*0.396605124984359783))) q := ((2563.95563932625156 + t2*(2633.23323959119935+t2*52.6711647124832948)) + t*(4450.19076667898892+t2*(622.983787815718489+t2))) return p / q } if mc > 0.083522 { t := 12.8982329420869341*mc - 1.07728621178898491 t2 := t * t p := ((2464.65334987833736 + t2*(2541.68516994216007+t2*41.5832527504007778)) + t*(4333.38639187691528+t2*(571.53606797524881+t2*0.465975784547025267))) q := ((2600.66956117247726 + t2*(2823.69445052534842+t2*56.136001230010910)) + t*(4661.64381841490914+t2*(674.25435972414302+t2))) return p / q } if mc > 0.041966 { t := 24.0639137549331023*mc - 1.00986620463952257 t2 := t * t p := ((2509.86724450741259 + t2*(2835.27071287535469+t2*48.9701196718008345)) + t*(4631.12336462339975+t2*(659.86172161727281+t2*0.54158304771955794))) q := ((2594.15983397593723 + t2*(3034.20118545214106+t2*60.652838995496991)) + t*(4848.17491604384532+t2*(737.15143838356850+t2))) return p / q } if mc > 0.020313 { t := 46.1829769546944996*mc - 0.938114810880709371 t2 := t * t p := ((2480.58307884128017 + t2*(3122.00900554841322+t2*57.541132641218839)) + t*(4845.57861173250699+t2*(757.31633816400643+t2*0.62119950515996627))) q := ((2528.85218300581396 + t2*(3253.86151324157460+t2*66.496093157522450)) + t*(4979.31783250484768+t2*(812.40556572486862+t2))) return p / q } if mc > 0.009408 { t := 91.7010545621274645*mc - 0.862723521320495186 t2 := t * t p := ((2365.25385348859592 + t2*(3381.09304915246175+t2*67.442026950538221)) + t*(4939.53925884558687+t2*(862.16657576129841+t2*0.70143698925710129))) q := ((2390.48737882063755 + t2*(3462.34808443022907+t2*73.934680452209164)) + t*(5015.4675579215077+t2*(898.99542983710459+t2))) return p / q } if mc > 0.004136 { t := 189.681335356600910*mc - 0.784522003034901366 t2 := t * t p := ((2160.82916040868119 + t2*(3584.53058926175721+t2*78.769178005879162)) + t*(4877.14832623847052+t2*(970.53716686804832+t2*0.77797110431753920))) q := ((2172.70451405048305 + t2*(3630.52345460629336+t2*83.173163222639080)) + t*(4916.35263668839769+t2*(993.36676027886685+t2))) return p / q } if mc > 0 { t := 1 - 106.292517006802721*mc p := mc * math.Log(mc*0.0625) * (6607.46457640413908 + t*(19.0287633783211078-t*0.00625368946932704460)) / (26150.3443630974309 + t*(354.603981274536040+t)) q := (26251.5678902584870 + t*(168.788023807915689+t*0.352150236262724288)) / (26065.7912239203873 + t*(353.916840382280456+t)) return p + q } return 1 } // CompleteD computes an associate complete elliptic integral of the 2nd kind, 0≤m≤1. It returns math.NaN() if m is not in [0,1]. // // D(m) = \int_{0}^{π/2} {\sin^2θ} / {\sqrt{1-m{\sin^2θ}}} dθ func CompleteD(m float64) float64 { // Reference: // Toshio Fukushima, Precise and fast computation of complete elliptic integrals // by piecewise minimax rational function approximation, // Journal of Computational and Applied Mathematics, Volume 282, 2015, Pages 71-76. // https://doi.org/10.1016/j.cam.2014.12.038 // Original Fortran code available at: // https://www.researchgate.net/publication/295857819_xceitxt_F90_package_of_complete_elliptic_integral_computation if m < 0 || 1 < m || math.IsNaN(m) { return math.NaN() } mc := 1 - m if mc > 0.599909 { t := 2.49943137936119533*mc - 1.49943137936119533 t2 := t * t p := ((1593.39813781813498 + t2*(1058.56241259843217+t2*11.7584241242587571)) + t*(2233.25576544961714+t2*(195.247394601357872+t2*0.101486443490307517))) q := ((1685.47865546030468 + t2*(1604.88100543517015+t2*38.6743012128666717)) + t*(2756.20968383181114+t2*(397.504162950935944+t2))) return p / q } if mc > 0.359180 { t := 4.15404874360795750*mc - 1.49205122772910617 t2 := t * t p := ((1967.01442513777287 + t2*(1329.30058268219177+t2*15.0447805948342760)) + t*(2779.87604145516343+t2*(247.475085945854673+t2*0.130547566005491628))) q := ((1749.70634057327467 + t2*(1654.40804288486242+t2*39.1895256017535337)) + t*(2853.92630369567765+t2*(406.925098588378587+t2))) return p / q } if mc > 0.214574 { t := 6.91534237860116454*mc - 1.48385267554596628 t2 := t * t p := ((2409.64196912091452 + t2*(1659.30176823041376+t2*19.1942111405094383)) + t*(3436.40744503228691+t2*(312.186468430688790+t2*0.167847673021897479))) q := ((1824.89205701262525 + t2*(1715.38574780156913+t2*39.8798253173462218)) + t*(2971.02216287936566+t2*(418.929791715319490+t2))) return p / q } if mc > 0.127875 { t := 11.5341584101316047*mc - 1.47493050669557896 t2 := t * t p := ((2926.81143179637839 + t2*(2056.45624281065334+t2*24.3811986813439843)) + t*(4214.52119721241319+t2*(391.420514384925370+t2*0.215574280659075512))) q := ((1910.33091918583314 + t2*(1787.99942542734799+t2*40.7663012893484449)) + t*(3107.04531802441481+t2*(433.673494280825971+t2))) return p / q } if mc > 0.076007 { t := 19.2797100331611013*mc - 1.46539292049047582 t2 := t * t p := ((3520.63614251102960 + t2*(2526.67111759550923+t2*30.7739877519417978)) + t*(5121.2842239226937+t2*(486.926821696342529+t2*0.276315678908126399))) q := ((2003.81997889501324 + t2*(1871.05914195570669+t2*41.8489850490387023)) + t*(3259.09205279874214+t2*(451.007555352632053+t2))) return p / q } if mc > 0.045052 { t := 32.3049588111775157*mc - 1.45540300436116944 t2 := t * t p := ((4188.00087087025347 + t2*(3072.05695847158556+t2*38.5070211470790031)) + t*(6156.0080960857764+t2*(599.76666155374012+t2*0.352955925261363680))) q := ((2101.60113938424690 + t2*(1961.76794074710108+t2*43.0997999502743622)) + t*(3421.55151253792527+t2*(470.407158843118117+t2))) return p / q } if mc > 0.026626 { t := 54.2711386084880061*mc - 1.44502333658960165 t2 := t * t p := ((4916.74442376570733 + t2*(3688.12811638360551+t2*47.6447145147811350)) + t*(7304.6632479558695+t2*(729.75841970840314+t2*0.448422756936257635))) q := ((2197.49982676612397 + t2*(2055.19657857622715+t2*44.4576261146308645)) + t*(3584.94502590860852+t2*(490.880160668822953+t2))) return p / q } if mc > 0.015689 { t := 91.4327512114839536*mc - 1.43448843375697175 t2 := t * t p := ((5688.7542903989517 + t2*(4364.21513060078954+t2*58.159468141567195)) + t*(8542.6096475195826+t2*(875.35992968472914+t2*0.56528145509695951))) q := ((2285.44062680812883 + t2*(2145.80779422696555+t2*45.8427480379028781)) + t*(3739.30422133833258+t2*(511.23253971875808+t2))) return p / q } if mc > 0.009216 { t := 154.487872701992894*mc - 1.42376023482156651 t2 := t * t p := ((6475.3392225234969 + t2*(5081.2997108708577+t2*69.910123337464043)) + t*(9829.1138694605662+t2*(1033.32687775311981+t2*0.70526087421186325))) q := ((2357.74885505777295 + t2*(2226.89527217032394+t2*47.1609071069631012)) + t*(3872.32565152553360+t2*(530.03943432061149+t2))) return p / q } if mc > 0 { t := 1 - 108.506944444444444*mc p := -math.Log(mc*0.0625) * (6.2904323649908115e6 + t*(58565.284164780476+t*(131.176674599188545+t*0.0426826410911220304))) / (1.24937550257219890e7 + t*(203580.534005225410+t*(921.17729845011868+t))) q := -(27356.1090344387530 + t*(107.767403612304371-t*0.0827769227048233593)) / (27104.0854889805978 + t*(358.708172147752755+t)) return p + q } return math.Inf(1) } golang-gonum-v1-gonum-0.14.0/mathext/ell_complete_test.go000066400000000000000000000030721450372207100233440ustar00rootroot00000000000000// 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 mathext import ( "math" "testing" ) // TestCompleteKE checks if the Legendre's relation for m=0.0001(0.0001)0.9999 // is satisfied with accuracy 1e-14. func TestCompleteKE(t *testing.T) { t.Parallel() const tol = 1.0e-14 for m := 1; m <= 9999; m++ { mf := float64(m) / 10000 mp := 1 - mf K, Kp := CompleteK(mf), CompleteK(mp) E, Ep := CompleteE(mf), CompleteE(mp) legendre := math.Abs(E*Kp + Ep*K - K*Kp - math.Pi/2) if legendre > tol { t.Fatalf("legendre > tol: m=%v, legendre=%v, tol=%v", mf, legendre, tol) } } } // TestCompleteBD checks if the relations between two associate elliptic integrals B(m), D(m) // and more common Legendre's elliptic integrals K(m), E(m) are satisfied with accuracy 1e-14 // for m=0.0001(0.0001)0.9999. // // K(m) and E(m) can be computed without cancellation problems as following: // // K(m) = B(m) + D(m), // E(m) = B(m) + (1-m)D(m). func TestCompleteBD(t *testing.T) { t.Parallel() const tol = 1.0e-14 for m := 1; m <= 9999; m++ { mf := float64(m) / 10000 B, D := CompleteB(mf), CompleteD(mf) K, E := CompleteK(mf), CompleteE(mf) difference1 := math.Abs(K - (B + D)) difference2 := math.Abs(E - (B + (1-mf)*D)) if difference1 > tol { t.Fatalf("difference1 > tol: m=%v, difference1=%v, tol=%v", mf, difference1, tol) } if difference2 > tol { t.Fatalf("difference2 > tol: m=%v, difference2=%v, tol=%v", mf, difference2, tol) } } } golang-gonum-v1-gonum-0.14.0/mathext/erf.go000066400000000000000000000110701450372207100204120ustar00rootroot00000000000000// 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 mathext import "math" /* Copyright (c) 2012 The Probab Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // NormalQuantile computes the quantile function (inverse CDF) of the standard // normal. NormalQuantile panics if the input p is less than 0 or greater than 1. func NormalQuantile(p float64) float64 { switch { case p < 0 || 1 < p: panic("mathext: quantile out of bounds") case p == 1: return math.Inf(1) case p == 0: return math.Inf(-1) } // Compute rational approximation based on the value of p. dp := p - 0.5 if math.Abs(dp) <= 0.425 { z := 0.180625 - dp*dp z1 := ((((((zQSA[0]*z+zQSA[1])*z+zQSA[2])*z+zQSA[3])*z+zQSA[4])*z+zQSA[5])*z+zQSA[6])*z + zQSA[7] z2 := ((((((zQSB[0]*z+zQSB[1])*z+zQSB[2])*z+zQSB[3])*z+zQSB[4])*z+zQSB[5])*z+zQSB[6])*z + zQSB[7] return dp * z1 / z2 } if p < 0.5 { r := math.Sqrt(-math.Log(p)) if r <= 5.0 { z := r - 1.6 z1 := ((((((zQIA[0]*z+zQIA[1])*z+zQIA[2])*z+zQIA[3])*z+zQIA[4])*z+zQIA[5])*z+zQIA[6])*z + zQIA[7] z2 := ((((((zQIB[0]*z+zQIB[1])*z+zQIB[2])*z+zQIB[3])*z+zQIB[4])*z+zQIB[5])*z+zQIB[6])*z + zQIB[7] return -z1 / z2 } z := r - 5 z1 := ((((((zQTA[0]*z+zQTA[1])*z+zQTA[2])*z+zQTA[3])*z+zQTA[4])*z+zQTA[5])*z+zQTA[6])*z + zQTA[7] z2 := ((((((zQTB[0]*z+zQTB[1])*z+zQTB[2])*z+zQTB[3])*z+zQTB[4])*z+zQTB[5])*z+zQTB[6])*z + zQTB[7] return -z1 / z2 } r := math.Sqrt(-math.Log(1 - p)) if r <= 5.0 { z := r - 1.6 z1 := ((((((zQIA[0]*z+zQIA[1])*z+zQIA[2])*z+zQIA[3])*z+zQIA[4])*z+zQIA[5])*z+zQIA[6])*z + zQIA[7] z2 := ((((((zQIB[0]*z+zQIB[1])*z+zQIB[2])*z+zQIB[3])*z+zQIB[4])*z+zQIB[5])*z+zQIB[6])*z + zQIB[7] return z1 / z2 } z := r - 5 z1 := ((((((zQTA[0]*z+zQTA[1])*z+zQTA[2])*z+zQTA[3])*z+zQTA[4])*z+zQTA[5])*z+zQTA[6])*z + zQTA[7] z2 := ((((((zQTB[0]*z+zQTB[1])*z+zQTB[2])*z+zQTB[3])*z+zQTB[4])*z+zQTB[5])*z+zQTB[6])*z + zQTB[7] return z1 / z2 } var ( zQSA = [...]float64{2509.0809287301226727, 33430.575583588128105, 67265.770927008700853, 45921.953931549871457, 13731.693765509461125, 1971.5909503065514427, 133.14166789178437745, 3.387132872796366608} zQSB = [...]float64{5226.495278852854561, 28729.085735721942674, 39307.89580009271061, 21213.794301586595867, 5394.1960214247511077, 687.1870074920579083, 42.313330701600911252, 1.0} zQIA = [...]float64{7.7454501427834140764e-4, 0.0227238449892691845833, 0.24178072517745061177, 1.27045825245236838258, 3.64784832476320460504, 5.7694972214606914055, 4.6303378461565452959, 1.42343711074968357734} zQIB = [...]float64{1.05075007164441684324e-9, 5.475938084995344946e-4, 0.0151986665636164571966, 0.14810397642748007459, 0.68976733498510000455, 1.6763848301838038494, 2.05319162663775882187, 1.0} zQTA = [...]float64{2.01033439929228813265e-7, 2.71155556874348757815e-5, 0.0012426609473880784386, 0.026532189526576123093, 0.29656057182850489123, 1.7848265399172913358, 5.4637849111641143699, 6.6579046435011037772} zQTB = [...]float64{2.04426310338993978564e-15, 1.4215117583164458887e-7, 1.8463183175100546818e-5, 7.868691311456132591e-4, 0.0148753612908506148525, 0.13692988092273580531, 0.59983220655588793769, 1.0} ) golang-gonum-v1-gonum-0.14.0/mathext/erf_test.go000066400000000000000000000025411450372207100214540ustar00rootroot00000000000000// 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 mathext import ( "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestNormalQuantile(t *testing.T) { t.Parallel() // Values from https://www.johndcook.com/blog/normal_cdf_inverse/ p := []float64{ 0.0000001, 0.00001, 0.001, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95, 0.999, 0.99999, 0.9999999, } ans := []float64{ -5.199337582187471, -4.264890793922602, -3.090232306167813, -1.6448536269514729, -1.0364333894937896, -0.6744897501960817, -0.38532046640756773, -0.12566134685507402, 0.12566134685507402, 0.38532046640756773, 0.6744897501960817, 1.0364333894937896, 1.6448536269514729, 3.090232306167813, 4.264890793922602, 5.199337582187471, } for i, v := range p { got := NormalQuantile(v) if !scalar.EqualWithinAbsOrRel(got, ans[i], 1e-10, 1e-10) { t.Errorf("Quantile mismatch. Case %d, want: %v, got: %v", i, ans[i], got) } } } var nqtmp float64 func BenchmarkNormalQuantile(b *testing.B) { ps := make([]float64, 1000) // ensure there are small values floats.Span(ps, 0, 1) for i := 0; i < b.N; i++ { for _, v := range ps { nqtmp = NormalQuantile(v) } } } golang-gonum-v1-gonum-0.14.0/mathext/gamma_inc.go000066400000000000000000000037461450372207100215640ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "gonum.org/v1/gonum/mathext/internal/cephes" ) // GammaIncReg computes the regularized incomplete Gamma integral. // // GammaIncReg(a,x) = (1/ Γ(a)) \int_0^x e^{-t} t^{a-1} dt // // The input argument a must be positive and x must be non-negative or GammaIncReg // will panic. // // See http://mathworld.wolfram.com/IncompleteGammaFunction.html // or https://en.wikipedia.org/wiki/Incomplete_gamma_function for more detailed // information. func GammaIncReg(a, x float64) float64 { return cephes.Igam(a, x) } // GammaIncRegComp computes the complemented regularized incomplete Gamma integral. // // GammaIncRegComp(a,x) = 1 - GammaIncReg(a,x) // = (1/ Γ(a)) \int_x^\infty e^{-t} t^{a-1} dt // // The input argument a must be positive and x must be non-negative or // GammaIncRegComp will panic. func GammaIncRegComp(a, x float64) float64 { return cephes.IgamC(a, x) } // GammaIncRegInv computes the inverse of the regularized incomplete Gamma integral. That is, // it returns the x such that: // // GammaIncReg(a, x) = y // // The input argument a must be positive and y must be between 0 and 1 // inclusive or GammaIncRegInv will panic. GammaIncRegInv should return a positive // number, but can return NaN if there is a failure to converge. func GammaIncRegInv(a, y float64) float64 { return gammaIncRegInv(a, y) } // GammaIncRegCompInv computes the inverse of the complemented regularized incomplete Gamma // integral. That is, it returns the x such that: // // GammaIncRegComp(a, x) = y // // The input argument a must be positive and y must be between 0 and 1 // inclusive or GammaIncRegCompInv will panic. GammaIncRegCompInv should return a // positive number, but can return 0 even with non-zero y due to underflow. func GammaIncRegCompInv(a, y float64) float64 { return cephes.IgamI(a, y) } golang-gonum-v1-gonum-0.14.0/mathext/gamma_inc_inv.go000066400000000000000000000033061450372207100224300ustar00rootroot00000000000000// Derived from SciPy's special/c_misc/gammaincinv.c // https://github.com/scipy/scipy/blob/master/scipy/special/c_misc/gammaincinv.c // 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 mathext import ( "math" "gonum.org/v1/gonum/mathext/internal/cephes" ) const ( allowedATol = 1e-306 allowedRTol = 1e-6 ) func gammaIncReg(x float64, params []float64) float64 { return cephes.Igam(params[0], x) - params[1] } // gammaIncRegInv is the inverse of the regularized incomplete Gamma integral. That is, it // returns x such that: // // Igam(a, x) = y // // The input argument a must be positive and y must be between 0 and 1 // inclusive or gammaIncRegInv will panic. gammaIncRegInv should return a // positive number, but can return NaN if there is a failure to converge. func gammaIncRegInv(a, y float64) float64 { // For y not small, we just use // IgamI(a, 1-y) // (inverse of the complemented incomplete Gamma integral). For y small, // however, 1-y is about 1, and we lose digits. if a <= 0 || y <= 0 || y >= 0.25 { return cephes.IgamI(a, 1-y) } lo := 0.0 flo := -y hi := cephes.IgamI(a, 0.75) fhi := 0.25 - y params := []float64{a, y} // Also, after we generate a small interval by bisection above, false // position will do a large step from an interval of width ~1e-4 to ~1e-14 // in one step (a=10, x=0.05, but similar for other values). result, bestX, _, errEst := falsePosition(lo, hi, flo, fhi, 2*machEp, 2*machEp, 1e-2*a, gammaIncReg, params) if result == fSolveMaxIterations && errEst > allowedATol+allowedRTol*math.Abs(bestX) { bestX = math.NaN() } return bestX } golang-gonum-v1-gonum-0.14.0/mathext/gamma_inc_test.go000066400000000000000000000103601450372207100226110ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "math" "testing" ) func TestGammaIncReg(t *testing.T) { t.Parallel() for i, test := range []struct { a, x, want float64 }{ // Results computed using scipy.special.gamminc {0, 0, 0}, {0.0001, 1, 0.99997805936186279}, {0.001, 0.005, 0.99528424172333985}, {0.01, 10, 0.99999995718295021}, {0.1, 10, 0.99999944520142825}, {0.25, 0.75, 0.89993651328449831}, {0.5, 0.5, 0.68268949213708596}, {0.5, 2, 0.95449973610364147}, {0.75, 2.5, 0.95053039734695643}, {1, 0.5, 0.39346934028736652}, {1, 1, 0.63212055882855778}, {1.5, 0.75, 0.31772966966378746}, {2.5, 1, 0.15085496391539038}, {3, 0.05, 2.0067493624397931e-05}, {3, 20, 0.99999954448504946}, {5, 50, 1}, {7, 10, 0.86985857911751696}, {10, 0.9, 4.2519575433351128e-08}, {10, 5, 0.031828057306204811}, {25, 10, 4.6949381426799868e-05}, } { if got := GammaIncReg(test.a, test.x); math.Abs(got-test.want) > 1e-10 { t.Errorf("test %d GammaIncReg(%g, %g) failed: got %g want %g", i, test.a, test.x, got, test.want) } } } func TestGammaIncRegComp(t *testing.T) { t.Parallel() for i, test := range []struct { a, x, want float64 }{ // Results computed using scipy.special.gammincc {0.00001, 0.075, 2.0866541002417804e-05}, {0.0001, 1, 2.1940638138146658e-05}, {0.001, 0.005, 0.0047157582766601536}, {0.01, 0.9, 0.0026263432520514662}, {0.25, 0.75, 0.10006348671550169}, {0.5, 0.5, 0.31731050786291404}, {0.75, 0.25, 0.65343980284081038}, {0.9, 0.01, 0.98359881081593148}, {1, 0, 1}, {1, 0.075, 0.92774348632855297}, {1, 1, 0.36787944117144233}, {1, 10, 4.5399929762484861e-05}, {1, math.Inf(1), 0}, {3, 20, 4.5551495055892125e-07}, {5, 10, 0.029252688076961127}, {10, 3, 0.99889751186988451}, {50, 25, 0.99999304669475242}, {100, 10, 1}, {500, 500, 0.49405285382921321}, {500, 550, 0.014614408126291296}, } { if got := GammaIncRegComp(test.a, test.x); math.Abs(got-test.want) > 1e-10 { t.Errorf("test %d GammaIncRegComp(%g, %g) failed: got %g want %g", i, test.a, test.x, got, test.want) } } } func TestGammaIncRegInv(t *testing.T) { t.Parallel() for i, test := range []struct { a, x, want float64 }{ // Results computed using scipy.special.gammincinv {0.001, 0.99, 2.4259428385570885e-05}, {0.01, 0.99, 0.26505255025157959}, {0.1, 0.5, 0.00059339110446022798}, {0.2, 0.8, 0.26354363204872067}, {0.25, 0.5, 0.043673802352873381}, {0.5, 0.25, 0.050765522133810789}, {0.5, 0.5, 0.22746821155978625}, {0.75, 0.25, 0.15340752707472377}, {1, 0, 0}, {1, 0.075, 0.077961541469711862}, {1, 1, math.Inf(1)}, {2.5, 0.99, 7.5431362346944937}, {10, 0.5, 9.6687146147141299}, {25, 0.01, 14.853341349420646}, {25, 0.99, 38.076945624506337}, {50, 0.75, 54.570620535040511}, {100, 0.25, 93.08583383712174}, {1000, 0.01, 927.90815979664251}, {1000, 0.99, 1075.0328320864389}, {10000, 0.5, 9999.6666686420485}, } { if got := GammaIncRegInv(test.a, test.x); math.Abs(got-test.want) > 1e-10 { t.Errorf("test %d GammaIncRegInv(%g, %g) failed: got %g want %g", i, test.a, test.x, got, test.want) } } } func TestGammaIncRegCompInv(t *testing.T) { t.Parallel() for i, test := range []struct { a, x, want float64 }{ // Results computed using scipy.special.gamminccinv {0.001, 0.01, 2.4259428385570885e-05}, {0.01, 0.01, 0.26505255025158292}, {0.03, 0.4, 2.316980536227699e-08}, {0.1, 0.5, 0.00059339110446022798}, {0.1, 0.75, 5.7917132949696076e-07}, {0.25, 0.25, 0.26062600197823282}, {0.5, 0.1, 1.3527717270477047}, {0.5, 0.5, 0.22746821155978625}, {0.75, 0.25, 1.0340914067758025}, {1, 0, math.Inf(1)}, {1, 0.5, 0.69314718055994529}, {1, 1, 0}, {3, 0.75, 1.727299417860519}, {25, 0.4, 25.945791937289371}, {25, 0.7, 22.156653488661991}, {10, 0.5, 9.6687146147141299}, {100, 0.25, 106.5510925269767}, {1000, 0.01, 1075.0328320864389}, {1000, 0.99, 927.90815979664251}, {10000, 0.5, 9999.6666686420485}, } { if got := GammaIncRegCompInv(test.a, test.x); math.Abs(got-test.want) > 1e-10 { t.Errorf("test %d GammaIncRegCompInv(%g, %g) failed: got %g want %g", i, test.a, test.x, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/mathext/internal/000077500000000000000000000000001450372207100211245ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/000077500000000000000000000000001450372207100220635ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amos.go000066400000000000000000001421321450372207100233540ustar00rootroot00000000000000// Copyright ©2016 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 amos import ( "math" "math/cmplx" ) /* The AMOS functions are included in SLATEC, and the SLATEC guide (http://www.netlib.org/slatec/guide) explicitly states: "The Library is in the public domain and distributed by the Energy Science and Technology Software Center." Mention of AMOS's inclusion in SLATEC goes back at least to this 1985 technical report from Sandia National Labs: http://infoserve.sandia.gov/sand_doc/1985/851018.pdf */ // math.NaN() are for padding to keep indexing easy. var imach = []int{-0, 5, 6, 0, 0, 32, 4, 2, 31, 2147483647, 2, 24, -125, 127, 53, -1021, 1023} var dmach = []float64{math.NaN(), 2.23e-308, 1.79e-308, 1.11e-16, 2.22e-16, 0.30103000998497009} func abs(a int) int { if a >= 0 { return a } return -a } 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 } func Zairy(ZR, ZI float64, ID, KODE int) (AIR, AII float64, NZ, IERR int) { // zairy is adapted from the original Netlib code by Donald Amos. // http://www.netlib.no/netlib/amos/zairy.f // Original comment: /* C***BEGIN PROLOGUE ZAIRY C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS AIRY FUNCTION,BESSEL FUNCTIONS OF ORDER ONE THIRD C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE AIRY FUNCTIONS AI(Z) AND DAI(Z) FOR COMPLEX Z C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C ON KODE=1, ZAIRY COMPUTES THE COMPLEX AIRY FUNCTION AI(Z) OR C ITS DERIVATIVE DAI(Z)/DZ ON ID=0 OR ID=1 RESPECTIVELY. ON C KODE=2, A SCALING OPTION CEXP(ZTA)*AI(Z) OR CEXP(ZTA)* C DAI(Z)/DZ IS PROVIDED TO REMOVE THE EXPONENTIAL DECAY IN C -PI/31.0 FROM THE K BESSEL C FUNCTIONS BY C C AI(Z)=C*SQRT(Z)*K(1/3,ZTA) , DAI(Z)=-C*Z*K(2/3,ZTA) C C=1.0/(PI*SQRT(3.0)) C ZTA=(2/3)*Z**(3/2) C C WITH THE POWER SERIES FOR CABS(Z)<=1.0. C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z IS LARGE, LOSSES C OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. CONSEQUENTLY, IF C THE MAGNITUDE OF ZETA=(2/3)*Z**1.5 EXCEEDS U1=SQRT(0.5/UR), C THEN LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR C FLAG IERR=3 IS TRIGGERED WHERE UR=math.Max(dmach[4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C ALSO, if THE MAGNITUDE OF ZETA IS LARGER THAN U2=0.5/UR, THEN C ALL SIGNIFICANCE IS LOST AND IERR=4. IN ORDER TO USE THE INT C FUNCTION, ZETA MUST BE FURTHER RESTRICTED NOT TO EXCEED THE C LARGEST INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF ZETA C MUST BE RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, C AND U3 ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE C PRECISION ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE C PRECISION ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMIT- C ING IN THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT THE MAG- C NITUDE OF Z CANNOT EXCEED 3.1E+4 IN SINGLE AND 2.1E+6 IN C DOUBLE PRECISION ARITHMETIC. THIS ALSO MEANS THAT ONE CAN C EXPECT TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, C NO DIGITS IN SINGLE PRECISION AND ONLY 7 DIGITS IN DOUBLE C PRECISION ARITHMETIC. SIMILAR CONSIDERATIONS HOLD FOR OTHER C MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. if ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 */ var AI, CONE, CSQ, CY, S1, S2, TRM1, TRM2, Z, ZTA, Z3 complex128 var AA, AD, AK, ALIM, ATRM, AZ, AZ3, BK, CC, CK, COEF, CONEI, CONER, CSQI, CSQR, C1, C2, DIG, DK, D1, D2, ELIM, FID, FNU, PTR, RL, R1M5, SFAC, STI, STR, S1I, S1R, S2I, S2R, TOL, TRM1I, TRM1R, TRM2I, TRM2R, TTH, ZEROI, ZEROR, ZTAI, ZTAR, Z3I, Z3R, ALAZ, BB float64 var IFLAG, K, K1, K2, MR, NN int var tmp complex128 // Extra element for padding. CYR := []float64{math.NaN(), 0} CYI := []float64{math.NaN(), 0} _ = AI _ = CONE _ = CSQ _ = CY _ = S1 _ = S2 _ = TRM1 _ = TRM2 _ = Z _ = ZTA _ = Z3 TTH = 6.66666666666666667e-01 C1 = 3.55028053887817240e-01 C2 = 2.58819403792806799e-01 COEF = 1.83776298473930683e-01 ZEROR = 0 ZEROI = 0 CONER = 1 CONEI = 0 NZ = 0 if ID < 0 || ID > 1 { IERR = 1 } if KODE < 1 || KODE > 2 { IERR = 1 } if IERR != 0 { return } AZ = cmplx.Abs(complex(ZR, ZI)) TOL = math.Max(dmach[4], 1.0e-18) FID = float64(ID) if AZ > 1.0e0 { goto Seventy } // POWER SERIES FOR CABS(Z)<=1. S1R = CONER S1I = CONEI S2R = CONER S2I = CONEI if AZ < TOL { goto OneSeventy } AA = AZ * AZ if AA < TOL/AZ { goto Forty } TRM1R = CONER TRM1I = CONEI TRM2R = CONER TRM2I = CONEI ATRM = 1.0e0 STR = ZR*ZR - ZI*ZI STI = ZR*ZI + ZI*ZR Z3R = STR*ZR - STI*ZI Z3I = STR*ZI + STI*ZR AZ3 = AZ * AA AK = 2.0e0 + FID BK = 3.0e0 - FID - FID CK = 4.0e0 - FID DK = 3.0e0 + FID + FID D1 = AK * DK D2 = BK * CK AD = math.Min(D1, D2) AK = 24.0e0 + 9.0e0*FID BK = 30.0e0 - 9.0e0*FID for K = 1; K <= 25; K++ { STR = (TRM1R*Z3R - TRM1I*Z3I) / D1 TRM1I = (TRM1R*Z3I + TRM1I*Z3R) / D1 TRM1R = STR S1R = S1R + TRM1R S1I = S1I + TRM1I STR = (TRM2R*Z3R - TRM2I*Z3I) / D2 TRM2I = (TRM2R*Z3I + TRM2I*Z3R) / D2 TRM2R = STR S2R = S2R + TRM2R S2I = S2I + TRM2I ATRM = ATRM * AZ3 / AD D1 = D1 + AK D2 = D2 + BK AD = math.Min(D1, D2) if ATRM < TOL*AD { goto Forty } AK = AK + 18.0e0 BK = BK + 18.0e0 } Forty: if ID == 1 { goto Fifty } AIR = S1R*C1 - C2*(ZR*S2R-ZI*S2I) AII = S1I*C1 - C2*(ZR*S2I+ZI*S2R) if KODE == 1 { return } tmp = cmplx.Sqrt(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) ZTAR = TTH * (ZR*STR - ZI*STI) ZTAI = TTH * (ZR*STI + ZI*STR) tmp = cmplx.Exp(complex(ZTAR, ZTAI)) STR = real(tmp) STI = imag(tmp) PTR = AIR*STR - AII*STI AII = AIR*STI + AII*STR AIR = PTR return Fifty: AIR = -S2R * C2 AII = -S2I * C2 if AZ <= TOL { goto Sixty } STR = ZR*S1R - ZI*S1I STI = ZR*S1I + ZI*S1R CC = C1 / (1.0e0 + FID) AIR = AIR + CC*(STR*ZR-STI*ZI) AII = AII + CC*(STR*ZI+STI*ZR) Sixty: if KODE == 1 { return } tmp = cmplx.Sqrt(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) ZTAR = TTH * (ZR*STR - ZI*STI) ZTAI = TTH * (ZR*STI + ZI*STR) tmp = cmplx.Exp(complex(ZTAR, ZTAI)) STR = real(tmp) STI = imag(tmp) PTR = STR*AIR - STI*AII AII = STR*AII + STI*AIR AIR = PTR return // CASE FOR CABS(Z)>1.0. Seventy: FNU = (1.0e0 + FID) / 3.0e0 /* SET PARAMETERS RELATED TO MACHINE CONSTANTS. TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0D-18. ELIM IS THE APPROXIMATE EXPONENTIAL OVER-&&UNDERFLOW LIMIT. EXP(-ELIM)EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR UNDERFLOW&&OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LA>=Z. DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). */ K1 = imach[15] K2 = imach[16] R1M5 = dmach[5] K = min(abs(K1), abs(K2)) ELIM = 2.303e0 * (float64(K)*R1M5 - 3.0e0) K1 = imach[14] - 1 AA = R1M5 * float64(K1) DIG = math.Min(AA, 18.0e0) AA = AA * 2.303e0 ALIM = ELIM + math.Max(-AA, -41.45e0) RL = 1.2e0*DIG + 3.0e0 ALAZ = math.Log(AZ) // TEST FOR PROPER RANGE. AA = 0.5e0 / TOL BB = float64(float32(imach[9])) * 0.5e0 AA = math.Min(AA, BB) AA = math.Pow(AA, TTH) if AZ > AA { goto TwoSixty } AA = math.Sqrt(AA) if AZ > AA { IERR = 3 } tmp = cmplx.Sqrt(complex(ZR, ZI)) CSQR = real(tmp) CSQI = imag(tmp) ZTAR = TTH * (ZR*CSQR - ZI*CSQI) ZTAI = TTH * (ZR*CSQI + ZI*CSQR) // RE(ZTA)<=0 WHEN RE(Z)<0, ESPECIALLY WHEN IM(Z) IS SMALL. IFLAG = 0 SFAC = 1.0e0 AK = ZTAI if ZR >= 0.0e0 { goto Eighty } BK = ZTAR CK = -math.Abs(BK) ZTAR = CK ZTAI = AK Eighty: if ZI != 0.0e0 { goto Ninety } if ZR > 0.0e0 { goto Ninety } ZTAR = 0.0e0 ZTAI = AK Ninety: AA = ZTAR if AA >= 0.0e0 && ZR > 0.0e0 { goto OneTen } if KODE == 2 { goto OneHundred } // OVERFLOW TEST. if AA > (-ALIM) { goto OneHundred } AA = -AA + 0.25e0*ALAZ IFLAG = 1 SFAC = TOL if AA > ELIM { goto TwoSeventy } OneHundred: // CBKNU AND CACON return EXP(ZTA)*K(FNU,ZTA) ON KODE=2. MR = 1 if ZI < 0.0e0 { MR = -1 } _, _, _, _, _, _, CYR, CYI, NN, _, _, _, _ = Zacai(ZTAR, ZTAI, FNU, KODE, MR, 1, CYR, CYI, RL, TOL, ELIM, ALIM) if NN < 0 { goto TwoEighty } NZ = NZ + NN goto OneThirty OneTen: if KODE == 2 { goto OneTwenty } // UNDERFLOW TEST. if AA < ALIM { goto OneTwenty } AA = -AA - 0.25e0*ALAZ IFLAG = 2 SFAC = 1.0e0 / TOL if AA < (-ELIM) { goto TwoTen } OneTwenty: _, _, _, _, _, CYR, CYI, NZ, _, _, _ = Zbknu(ZTAR, ZTAI, FNU, KODE, 1, CYR, CYI, TOL, ELIM, ALIM) OneThirty: S1R = CYR[1] * COEF S1I = CYI[1] * COEF if IFLAG != 0 { goto OneFifty } if ID == 1 { goto OneFourty } AIR = CSQR*S1R - CSQI*S1I AII = CSQR*S1I + CSQI*S1R return OneFourty: AIR = -(ZR*S1R - ZI*S1I) AII = -(ZR*S1I + ZI*S1R) return OneFifty: S1R = S1R * SFAC S1I = S1I * SFAC if ID == 1 { goto OneSixty } STR = S1R*CSQR - S1I*CSQI S1I = S1R*CSQI + S1I*CSQR S1R = STR AIR = S1R / SFAC AII = S1I / SFAC return OneSixty: STR = -(S1R*ZR - S1I*ZI) S1I = -(S1R*ZI + S1I*ZR) S1R = STR AIR = S1R / SFAC AII = S1I / SFAC return OneSeventy: AA = 1.0e+3 * dmach[1] S1R = ZEROR S1I = ZEROI if ID == 1 { goto OneNinety } if AZ <= AA { goto OneEighty } S1R = C2 * ZR S1I = C2 * ZI OneEighty: AIR = C1 - S1R AII = -S1I return OneNinety: AIR = -C2 AII = 0.0e0 AA = math.Sqrt(AA) if AZ <= AA { goto TwoHundred } S1R = 0.5e0 * (ZR*ZR - ZI*ZI) S1I = ZR * ZI TwoHundred: AIR = AIR + C1*S1R AII = AII + C1*S1I return TwoTen: NZ = 1 AIR = ZEROR AII = ZEROI return TwoSeventy: NZ = 0 IERR = 2 return TwoEighty: if NN == (-1) { goto TwoSeventy } NZ = 0 IERR = 5 return TwoSixty: IERR = 4 NZ = 0 return } // sbknu computes the k bessel function in the right half z plane. func Zbknu(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, TOL, ELIM, ALIM float64) (ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, TOLout, ELIMout, ALIMout float64) { /* Old dimension comment. DIMENSION YR(N), YI(N), CC(8), CSSR(3), CSRR(3), BRY(3), CYR(2), * CYI(2) */ // TODO(btracey): Find which of these are inputs/outputs/both and clean up // the function call. // YR and YI have length n (but n+1 with better indexing) var AA, AK, ASCLE, A1, A2, BB, BK, CAZ, CBI, CBR, CCHI, CCHR, CKI, CKR, COEFI, COEFR, CONEI, CONER, CRSCR, CSCLR, CSHI, CSHR, CSI, CSR, CTWOR, CZEROI, CZEROR, CZI, CZR, DNU, DNU2, DPI, ETEST, FC, FHS, FI, FK, FKS, FMUI, FMUR, FPI, FR, G1, G2, HPI, PI, PR, PTI, PTR, P1I, P1R, P2I, P2M, P2R, QI, QR, RAK, RCAZ, RTHPI, RZI, RZR, R1, S, SMUI, SMUR, SPI, STI, STR, S1I, S1R, S2I, S2R, TM, TTH, T1, T2, ELM, CELMR, ZDR, ZDI, AS, ALAS, HELIM float64 var I, IFLAG, INU, K, KFLAG, KK, KMAX, KODED, IDUM, J, IC, INUB, NW int var sinh, cosh complex128 //var sin, cos float64 var tmp, p complex128 var CSSR, CSRR, BRY [4]float64 var CYR, CYI [3]float64 KMAX = 30 CZEROR = 0 CZEROI = 0 CONER = 1 CONEI = 0 CTWOR = 2 R1 = 2 DPI = 3.14159265358979324e0 RTHPI = 1.25331413731550025e0 SPI = 1.90985931710274403e0 HPI = 1.57079632679489662e0 FPI = 1.89769999331517738e0 TTH = 6.66666666666666666e-01 CC := [9]float64{math.NaN(), 5.77215664901532861e-01, -4.20026350340952355e-02, -4.21977345555443367e-02, 7.21894324666309954e-03, -2.15241674114950973e-04, -2.01348547807882387e-05, 1.13302723198169588e-06, 6.11609510448141582e-09} CAZ = cmplx.Abs(complex(ZR, ZI)) CSCLR = 1.0e0 / TOL CRSCR = TOL CSSR[1] = CSCLR CSSR[2] = 1.0e0 CSSR[3] = CRSCR CSRR[1] = CRSCR CSRR[2] = 1.0e0 CSRR[3] = CSCLR BRY[1] = 1.0e+3 * dmach[1] / TOL BRY[2] = 1.0e0 / BRY[1] BRY[3] = dmach[2] IFLAG = 0 KODED = KODE RCAZ = 1.0e0 / CAZ STR = ZR * RCAZ STI = -ZI * RCAZ RZR = (STR + STR) * RCAZ RZI = (STI + STI) * RCAZ INU = int(float32(FNU + 0.5)) DNU = FNU - float64(INU) if math.Abs(DNU) == 0.5e0 { goto OneTen } DNU2 = 0.0e0 if math.Abs(DNU) > TOL { DNU2 = DNU * DNU } if CAZ > R1 { goto OneTen } // SERIES FOR CABS(Z)<=R1. FC = 1.0e0 tmp = cmplx.Log(complex(RZR, RZI)) SMUR = real(tmp) SMUI = imag(tmp) FMUR = SMUR * DNU FMUI = SMUI * DNU tmp = complex(FMUR, FMUI) sinh = cmplx.Sinh(tmp) cosh = cmplx.Cosh(tmp) CSHR = real(sinh) CSHI = imag(sinh) CCHR = real(cosh) CCHI = imag(cosh) if DNU == 0.0e0 { goto Ten } FC = DNU * DPI FC = FC / math.Sin(FC) SMUR = CSHR / DNU SMUI = CSHI / DNU Ten: A2 = 1.0e0 + DNU // GAM(1-Z)*GAM(1+Z)=PI*Z/SIN(PI*Z), T1=1/GAM(1-DNU), T2=1/GAM(1+DNU). T2 = math.Exp(-dgamln(A2, IDUM)) T1 = 1.0e0 / (T2 * FC) if math.Abs(DNU) > 0.1e0 { goto Forty } // SERIES FOR F0 TO RESOLVE INDETERMINACY FOR SMALL ABS(DNU). AK = 1.0e0 S = CC[1] for K = 2; K <= 8; K++ { AK = AK * DNU2 TM = CC[K] * AK S = S + TM if math.Abs(TM) < TOL { goto Thirty } } Thirty: G1 = -S goto Fifty Forty: G1 = (T1 - T2) / (DNU + DNU) Fifty: G2 = (T1 + T2) * 0.5e0 FR = FC * (CCHR*G1 + SMUR*G2) FI = FC * (CCHI*G1 + SMUI*G2) tmp = cmplx.Exp(complex(FMUR, FMUI)) STR = real(tmp) STI = imag(tmp) PR = 0.5e0 * STR / T2 PI = 0.5e0 * STI / T2 tmp = complex(0.5, 0) / complex(STR, STI) PTR = real(tmp) PTI = imag(tmp) QR = PTR / T1 QI = PTI / T1 S1R = FR S1I = FI S2R = PR S2I = PI AK = 1.0e0 A1 = 1.0e0 CKR = CONER CKI = CONEI BK = 1.0e0 - DNU2 if INU > 0 || N > 1 { goto Eighty } // GENERATE K(FNU,Z), 0.0E0 <= FNU < 0.5E0 AND N=1. if CAZ < TOL { goto Seventy } tmp = complex(ZR, ZI) * complex(ZR, ZI) CZR = real(tmp) CZI = imag(tmp) CZR = 0.25e0 * CZR CZI = 0.25e0 * CZI T1 = 0.25e0 * CAZ * CAZ Sixty: FR = (FR*AK + PR + QR) / BK FI = (FI*AK + PI + QI) / BK STR = 1.0e0 / (AK - DNU) PR = PR * STR PI = PI * STR STR = 1.0e0 / (AK + DNU) QR = QR * STR QI = QI * STR STR = CKR*CZR - CKI*CZI RAK = 1.0e0 / AK CKI = (CKR*CZI + CKI*CZR) * RAK CKR = STR * RAK S1R = CKR*FR - CKI*FI + S1R S1I = CKR*FI + CKI*FR + S1I A1 = A1 * T1 * RAK BK = BK + AK + AK + 1.0e0 AK = AK + 1.0e0 if A1 > TOL { goto Sixty } Seventy: YR[1] = S1R YI[1] = S1I if KODED == 1 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } tmp = cmplx.Exp(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) tmp = complex(S1R, S1I) * complex(STR, STI) YR[1] = real(tmp) YI[1] = imag(tmp) return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM // GENERATE K(DNU,Z) AND K(DNU+1,Z) FOR FORWARD RECURRENCE. Eighty: if CAZ < TOL { goto OneHundred } tmp = complex(ZR, ZI) * complex(ZR, ZI) CZR = real(tmp) CZI = imag(tmp) CZR = 0.25e0 * CZR CZI = 0.25e0 * CZI T1 = 0.25e0 * CAZ * CAZ Ninety: FR = (FR*AK + PR + QR) / BK FI = (FI*AK + PI + QI) / BK STR = 1.0e0 / (AK - DNU) PR = PR * STR PI = PI * STR STR = 1.0e0 / (AK + DNU) QR = QR * STR QI = QI * STR STR = CKR*CZR - CKI*CZI RAK = 1.0e0 / AK CKI = (CKR*CZI + CKI*CZR) * RAK CKR = STR * RAK S1R = CKR*FR - CKI*FI + S1R S1I = CKR*FI + CKI*FR + S1I STR = PR - FR*AK STI = PI - FI*AK S2R = CKR*STR - CKI*STI + S2R S2I = CKR*STI + CKI*STR + S2I A1 = A1 * T1 * RAK BK = BK + AK + AK + 1.0e0 AK = AK + 1.0e0 if A1 > TOL { goto Ninety } OneHundred: KFLAG = 2 A1 = FNU + 1.0e0 AK = A1 * math.Abs(SMUR) if AK > ALIM { KFLAG = 3 } STR = CSSR[KFLAG] P2R = S2R * STR P2I = S2I * STR tmp = complex(P2R, P2I) * complex(RZR, RZI) S2R = real(tmp) S2I = imag(tmp) S1R = S1R * STR S1I = S1I * STR if KODED == 1 { goto TwoTen } tmp = cmplx.Exp(complex(ZR, ZI)) FR = real(tmp) FI = imag(tmp) tmp = complex(S1R, S1I) * complex(FR, FI) S1R = real(tmp) S1I = imag(tmp) tmp = complex(S2R, S2I) * complex(FR, FI) S2R = real(tmp) S2I = imag(tmp) goto TwoTen // IFLAG=0 MEANS NO UNDERFLOW OCCURRED // IFLAG=1 MEANS AN UNDERFLOW OCCURRED- COMPUTATION PROCEEDS WITH // KODED=2 AND A TEST FOR ON SCALE VALUES IS MADE DURING FORWARD RECURSION OneTen: tmp = cmplx.Sqrt(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) tmp = complex(RTHPI, CZEROI) / complex(STR, STI) COEFR = real(tmp) COEFI = imag(tmp) KFLAG = 2 if KODED == 2 { goto OneTwenty } if ZR > ALIM { goto TwoNinety } STR = math.Exp(-ZR) * CSSR[KFLAG] //sin, cos = math.Sincos(ZI) STI = -STR * math.Sin(ZI) STR = STR * math.Cos(ZI) tmp = complex(COEFR, COEFI) * complex(STR, STI) COEFR = real(tmp) COEFI = imag(tmp) OneTwenty: if math.Abs(DNU) == 0.5e0 { goto ThreeHundred } // MILLER ALGORITHM FOR CABS(Z)>R1. AK = math.Cos(DPI * DNU) AK = math.Abs(AK) if AK == CZEROR { goto ThreeHundred } FHS = math.Abs(0.25e0 - DNU2) if FHS == CZEROR { goto ThreeHundred } // COMPUTE R2=F(E). if CABS(Z)>=R2, USE FORWARD RECURRENCE TO // DETERMINE THE BACKWARD INDEX K. R2=F(E) IS A STRAIGHT LINE ON // 12<=E<=60. E IS COMPUTED FROM 2**(-E)=B**(1-I1MACH(14))= // TOL WHERE B IS THE BASE OF THE ARITHMETIC. T1 = float64(imach[14] - 1) T1 = T1 * dmach[5] * 3.321928094e0 T1 = math.Max(T1, 12.0e0) T1 = math.Min(T1, 60.0e0) T2 = TTH*T1 - 6.0e0 if ZR != 0.0e0 { goto OneThirty } T1 = HPI goto OneFourty OneThirty: T1 = math.Atan(ZI / ZR) T1 = math.Abs(T1) OneFourty: if T2 > CAZ { goto OneSeventy } // FORWARD RECURRENCE LOOP WHEN CABS(Z)>=R2. ETEST = AK / (DPI * CAZ * TOL) FK = CONER if ETEST < CONER { goto OneEighty } FKS = CTWOR CKR = CAZ + CAZ + CTWOR P1R = CZEROR P2R = CONER for I = 1; I <= KMAX; I++ { AK = FHS / FKS CBR = CKR / (FK + CONER) PTR = P2R P2R = CBR*P2R - P1R*AK P1R = PTR CKR = CKR + CTWOR FKS = FKS + FK + FK + CTWOR FHS = FHS + FK + FK FK = FK + CONER STR = math.Abs(P2R) * FK if ETEST < STR { goto OneSixty } } goto ThreeTen OneSixty: FK = FK + SPI*T1*math.Sqrt(T2/CAZ) FHS = math.Abs(0.25 - DNU2) goto OneEighty OneSeventy: // COMPUTE BACKWARD INDEX K FOR CABS(Z) 0 || N > 1 { goto TwoHundred } ZDR = ZR ZDI = ZI if IFLAG == 1 { goto TwoSeventy } goto TwoFourty TwoHundred: // COMPUTE P1/P2=(P1/CABS(P2)*CONJG(P2)/CABS(P2) FOR SCALING. TM = cmplx.Abs(complex(P2R, P2I)) PTR = 1.0e0 / TM P1R = P1R * PTR P1I = P1I * PTR P2R = P2R * PTR P2I = -P2I * PTR tmp = complex(P1R, P1I) * complex(P2R, P2I) PTR = real(tmp) PTI = imag(tmp) STR = DNU + 0.5e0 - PTR STI = -PTI tmp = complex(STR, STI) / complex(ZR, ZI) STR = real(tmp) STI = imag(tmp) STR = STR + 1.0e0 tmp = complex(STR, STI) * complex(S1R, S1I) S2R = real(tmp) S2I = imag(tmp) // FORWARD RECURSION ON THE THREE TERM RECURSION WITH RELATION WITH // SCALING NEAR EXPONENT EXTREMES ON KFLAG=1 OR KFLAG=3 TwoTen: STR = DNU + 1.0e0 CKR = STR * RZR CKI = STR * RZI if N == 1 { INU = INU - 1 } if INU > 0 { goto TwoTwenty } if N > 1 { goto TwoFifteen } S1R = S2R S1I = S2I TwoFifteen: ZDR = ZR ZDI = ZI if IFLAG == 1 { goto TwoSeventy } goto TwoFourty TwoTwenty: INUB = 1 if IFLAG == 1 { goto TwoSixtyOne } TwoTwentyFive: P1R = CSRR[KFLAG] ASCLE = BRY[KFLAG] for I = INUB; I <= INU; I++ { STR = S2R STI = S2I S2R = CKR*STR - CKI*STI + S1R S2I = CKR*STI + CKI*STR + S1I S1R = STR S1I = STI CKR = CKR + RZR CKI = CKI + RZI if KFLAG >= 3 { continue } P2R = S2R * P1R P2I = S2I * P1R STR = math.Abs(P2R) STI = math.Abs(P2I) P2M = math.Max(STR, STI) if P2M <= ASCLE { continue } KFLAG = KFLAG + 1 ASCLE = BRY[KFLAG] S1R = S1R * P1R S1I = S1I * P1R S2R = P2R S2I = P2I STR = CSSR[KFLAG] S1R = S1R * STR S1I = S1I * STR S2R = S2R * STR S2I = S2I * STR P1R = CSRR[KFLAG] } if N != 1 { goto TwoFourty } S1R = S2R S1I = S2I TwoFourty: STR = CSRR[KFLAG] YR[1] = S1R * STR YI[1] = S1I * STR if N == 1 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } YR[2] = S2R * STR YI[2] = S2I * STR if N == 2 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } KK = 2 TwoFifty: KK = KK + 1 if KK > N { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } P1R = CSRR[KFLAG] ASCLE = BRY[KFLAG] for I = KK; I <= N; I++ { P2R = S2R P2I = S2I S2R = CKR*P2R - CKI*P2I + S1R S2I = CKI*P2R + CKR*P2I + S1I S1R = P2R S1I = P2I CKR = CKR + RZR CKI = CKI + RZI P2R = S2R * P1R P2I = S2I * P1R YR[I] = P2R YI[I] = P2I if KFLAG >= 3 { continue } STR = math.Abs(P2R) STI = math.Abs(P2I) P2M = math.Max(STR, STI) if P2M <= ASCLE { continue } KFLAG = KFLAG + 1 ASCLE = BRY[KFLAG] S1R = S1R * P1R S1I = S1I * P1R S2R = P2R S2I = P2I STR = CSSR[KFLAG] S1R = S1R * STR S1I = S1I * STR S2R = S2R * STR S2I = S2I * STR P1R = CSRR[KFLAG] } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM // IFLAG=1 CASES, FORWARD RECURRENCE ON SCALED VALUES ON UNDERFLOW. TwoSixtyOne: HELIM = 0.5e0 * ELIM ELM = math.Exp(-ELIM) CELMR = ELM ASCLE = BRY[1] ZDR = ZR ZDI = ZI IC = -1 J = 2 for I = 1; I <= INU; I++ { STR = S2R STI = S2I S2R = STR*CKR - STI*CKI + S1R S2I = STI*CKR + STR*CKI + S1I S1R = STR S1I = STI CKR = CKR + RZR CKI = CKI + RZI AS = cmplx.Abs(complex(S2R, S2I)) ALAS = math.Log(AS) P2R = -ZDR + ALAS if P2R < (-ELIM) { goto TwoSixtyThree } tmp = cmplx.Log(complex(S2R, S2I)) STR = real(tmp) STI = imag(tmp) P2R = -ZDR + STR P2I = -ZDI + STI P2M = math.Exp(P2R) / TOL // sin, cos = math.Sincos(P2I) P1R = P2M * math.Cos(P2I) P1I = P2M * math.Sin(P2I) p = complex(P1R, P1I) NW = Zuchk(p, ASCLE, TOL) if NW != 0 { goto TwoSixtyThree } J = 3 - J CYR[J] = P1R CYI[J] = P1I if IC == (I - 1) { goto TwoSixtyFour } IC = I continue TwoSixtyThree: if ALAS < HELIM { continue } ZDR = ZDR - ELIM S1R = S1R * CELMR S1I = S1I * CELMR S2R = S2R * CELMR S2I = S2I * CELMR } if N != 1 { goto TwoSeventy } S1R = S2R S1I = S2I goto TwoSeventy TwoSixtyFour: KFLAG = 1 INUB = I + 1 S2R = CYR[J] S2I = CYI[J] J = 3 - J S1R = CYR[J] S1I = CYI[J] if INUB <= INU { goto TwoTwentyFive } if N != 1 { goto TwoFourty } S1R = S2R S1I = S2I goto TwoFourty TwoSeventy: YR[1] = S1R YI[1] = S1I if N == 1 { goto TwoEighty } YR[2] = S2R YI[2] = S2I TwoEighty: ASCLE = BRY[1] _, _, FNU, N, YR, YI, NZ, RZR, RZI, _, TOL, ELIM = Zkscl(ZDR, ZDI, FNU, N, YR, YI, RZR, RZI, ASCLE, TOL, ELIM) INU = N - NZ if INU <= 0 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } KK = NZ + 1 S1R = YR[KK] S1I = YI[KK] YR[KK] = S1R * CSRR[1] YI[KK] = S1I * CSRR[1] if INU == 1 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } KK = NZ + 2 S2R = YR[KK] S2I = YI[KK] YR[KK] = S2R * CSRR[1] YI[KK] = S2I * CSRR[1] if INU == 2 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } T2 = FNU + float64(float32(KK-1)) CKR = T2 * RZR CKI = T2 * RZI KFLAG = 1 goto TwoFifty TwoNinety: // SCALE BY math.Exp(Z), IFLAG = 1 CASES. IFLAG = 1 KFLAG = 2 goto OneTwenty // FNU=HALF ODD INTEGER CASE, DNU=-0.5 ThreeHundred: S1R = COEFR S1I = COEFI S2R = COEFR S2I = COEFI goto TwoTen ThreeTen: NZ = -2 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } // SET K FUNCTIONS TO ZERO ON UNDERFLOW, CONTINUE RECURRENCE // ON SCALED FUNCTIONS UNTIL TWO MEMBERS COME ON SCALE, THEN // return WITH MIN(NZ+2,N) VALUES SCALED BY 1/TOL. func Zkscl(ZRR, ZRI, FNU float64, N int, YR, YI []float64, RZR, RZI, ASCLE, TOL, ELIM float64) ( ZRRout, ZRIout, FNUout float64, Nout int, YRout, YIout []float64, NZ int, RZRout, RZIout, ASCLEout, TOLout, ELIMout float64) { var ACS, AS, CKI, CKR, CSI, CSR, FN, STR, S1I, S1R, S2I, S2R, ZEROI, ZEROR, ZDR, ZDI, CELMR, ELM, HELIM, ALAS float64 var I, IC, KK, NN, NW int var tmp, c complex128 var CYR, CYI [3]float64 var sin, cos float64 // DIMENSION YR(N), YI(N), CYR(2), CYI(2) ZEROR = 0 ZEROI = 0 IC = 0 NN = min(2, N) for I = 1; I <= NN; I++ { S1R = YR[I] S1I = YI[I] CYR[I] = S1R CYI[I] = S1I AS = cmplx.Abs(complex(S1R, S1I)) ACS = -ZRR + math.Log(AS) NZ = NZ + 1 YR[I] = ZEROR YI[I] = ZEROI if ACS < (-ELIM) { continue } tmp = cmplx.Log(complex(S1R, S1I)) CSR = real(tmp) CSI = imag(tmp) CSR = CSR - ZRR CSI = CSI - ZRI STR = math.Exp(CSR) / TOL // sin, cos = math.Sincos(CSI) CSR = STR * math.Cos(CSI) CSI = STR * math.Sin(CSI) c = complex(CSR, CSI) NW = Zuchk(c, ASCLE, TOL) if NW != 0 { continue } YR[I] = CSR YI[I] = CSI IC = I NZ = NZ - 1 } if N == 1 { return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } if IC > 1 { goto Twenty } YR[1] = ZEROR YI[1] = ZEROI NZ = 2 Twenty: if N == 2 { return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } if NZ == 0 { return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } FN = FNU + 1.0e0 CKR = FN * RZR CKI = FN * RZI S1R = CYR[1] S1I = CYI[1] S2R = CYR[2] S2I = CYI[2] HELIM = 0.5e0 * ELIM ELM = math.Exp(-ELIM) CELMR = ELM ZDR = ZRR ZDI = ZRI // FIND TWO CONSECUTIVE Y VALUES ON SCALE. SCALE RECURRENCE IF // S2 GETS LARGER THAN EXP(ELIM/2) for I = 3; I <= N; I++ { KK = I CSR = S2R CSI = S2I S2R = CKR*CSR - CKI*CSI + S1R S2I = CKI*CSR + CKR*CSI + S1I S1R = CSR S1I = CSI CKR = CKR + RZR CKI = CKI + RZI AS = cmplx.Abs(complex(S2R, S2I)) ALAS = math.Log(AS) ACS = -ZDR + ALAS NZ = NZ + 1 YR[I] = ZEROR YI[I] = ZEROI if ACS < (-ELIM) { goto TwentyFive } tmp = cmplx.Log(complex(S2R, S2I)) CSR = real(tmp) CSI = imag(tmp) CSR = CSR - ZDR CSI = CSI - ZDI STR = math.Exp(CSR) / TOL sin, cos = math.Sincos(CSI) CSR = STR * cos CSI = STR * sin c = complex(CSR, CSI) NW = Zuchk(c, ASCLE, TOL) if NW != 0 { goto TwentyFive } YR[I] = CSR YI[I] = CSI NZ = NZ - 1 if IC == KK-1 { goto Forty } IC = KK continue TwentyFive: if ALAS < HELIM { continue } ZDR = ZDR - ELIM S1R = S1R * CELMR S1I = S1I * CELMR S2R = S2R * CELMR S2I = S2I * CELMR } NZ = N if IC == N { NZ = N - 1 } goto FourtyFive Forty: NZ = KK - 2 FourtyFive: for I = 1; I <= NZ; I++ { YR[I] = ZEROR YI[I] = ZEROI } return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } // Zuchk tests whether the magnitude of the real or imaginary part would // underflow when y is scaled by tol. // // y enters as a scaled quantity whose magnitude is greater than // // 1e3 + 3*dmach(1)/tol // // y is accepted if the underflow is at least one precision below the magnitude // of the largest component. Otherwise an underflow is assumed as the phase angle // does not have sufficient accuracy. func Zuchk(y complex128, scale, tol float64) int { absR := math.Abs(real(y)) absI := math.Abs(imag(y)) minAbs := math.Min(absR, absI) if minAbs > scale { return 0 } maxAbs := math.Max(absR, absI) minAbs /= tol if maxAbs < minAbs { return 1 } return 0 } // ZACAI APPLIES THE ANALYTIC CONTINUATION FORMULA // // K(FNU,ZN*EXP(MP))=K(FNU,ZN)*EXP(-MP*FNU) - MP*I(FNU,ZN) // MP=PI*MR*CMPLX(0.0,1.0) // // TO CONTINUE THE K FUNCTION FROM THE RIGHT HALF TO THE LEFT // HALF Z PLANE FOR USE WITH ZAIRY WHERE FNU=1/3 OR 2/3 AND N=1. // ZACAI IS THE SAME AS ZACON WITH THE PARTS FOR LARGER ORDERS AND // RECURRENCE REMOVED. A RECURSIVE CALL TO ZACON CAN RESULT if ZACON // IS CALLED FROM ZAIRY. func Zacai(ZR, ZI, FNU float64, KODE, MR, N int, YR, YI []float64, RL, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, MRout, Nout int, YRout, YIout []float64, NZ int, RLout, TOLout, ELIMout, ALIMout float64) { var ARG, ASCLE, AZ, CSGNR, CSGNI, CSPNR, CSPNI, C1R, C1I, C2R, C2I, DFNU, FMR, PI, SGN, YY, ZNR, ZNI float64 var INU, IUF, NN, NW int var zn, c1, c2, z complex128 var y []complex128 //var sin, cos float64 CYR := []float64{math.NaN(), 0, 0} CYI := []float64{math.NaN(), 0, 0} PI = math.Pi ZNR = -ZR ZNI = -ZI AZ = cmplx.Abs(complex(ZR, ZI)) NN = N DFNU = FNU + float64(float32(N-1)) if AZ <= 2.0e0 { goto Ten } if AZ*AZ*0.25 > DFNU+1.0e0 { goto Twenty } Ten: // POWER SERIES FOR THE I FUNCTION. z = complex(ZNR, ZNI) y = make([]complex128, len(YR)) for i, v := range YR { y[i] = complex(v, YI[i]) } Zseri(z, FNU, KODE, NN, y[1:], TOL, ELIM, ALIM) for i, v := range y { YR[i] = real(v) YI[i] = imag(v) } goto Forty Twenty: if AZ < RL { goto Thirty } // ASYMPTOTIC EXPANSION FOR LARGE Z FOR THE I FUNCTION. ZNR, ZNI, FNU, KODE, _, YR, YI, NW, RL, TOL, ELIM, ALIM = Zasyi(ZNR, ZNI, FNU, KODE, NN, YR, YI, RL, TOL, ELIM, ALIM) if NW < 0 { goto Eighty } goto Forty Thirty: // MILLER ALGORITHM NORMALIZED BY THE SERIES FOR THE I FUNCTION ZNR, ZNI, FNU, KODE, _, YR, YI, NW, TOL = Zmlri(ZNR, ZNI, FNU, KODE, NN, YR, YI, TOL) if NW < 0 { goto Eighty } Forty: // ANALYTIC CONTINUATION TO THE LEFT HALF PLANE FOR THE K FUNCTION. ZNR, ZNI, FNU, KODE, _, CYR, CYI, NW, TOL, ELIM, ALIM = Zbknu(ZNR, ZNI, FNU, KODE, 1, CYR, CYI, TOL, ELIM, ALIM) if NW != 0 { goto Eighty } FMR = float64(float32(MR)) SGN = -math.Copysign(PI, FMR) CSGNR = 0.0e0 CSGNI = SGN if KODE == 1 { goto Fifty } YY = -ZNI //sin, cos = math.Sincos(YY) CSGNR = -CSGNI * math.Sin(YY) CSGNI = CSGNI * math.Cos(YY) Fifty: // CALCULATE CSPN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE // WHEN FNU IS LARGE INU = int(float32(FNU)) ARG = (FNU - float64(float32(INU))) * SGN //sin, cos = math.Sincos(ARG) CSPNR = math.Cos(ARG) CSPNI = math.Sin(ARG) if INU%2 == 0 { goto Sixty } CSPNR = -CSPNR CSPNI = -CSPNI Sixty: C1R = CYR[1] C1I = CYI[1] C2R = YR[1] C2I = YI[1] if KODE == 1 { goto Seventy } IUF = 0 ASCLE = 1.0e+3 * dmach[1] / TOL zn = complex(ZNR, ZNI) c1 = complex(C1R, C1I) c2 = complex(C2R, C2I) c1, c2, NW, _ = Zs1s2(zn, c1, c2, ASCLE, ALIM, IUF) C1R = real(c1) C1I = imag(c1) C2R = real(c2) C2I = imag(c2) NZ = NZ + NW Seventy: YR[1] = CSPNR*C1R - CSPNI*C1I + CSGNR*C2R - CSGNI*C2I YI[1] = CSPNR*C1I + CSPNI*C1R + CSGNR*C2I + CSGNI*C2R return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM Eighty: NZ = -1 if NW == -2 { NZ = -2 } return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } // ZASYI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z)>=0.0 BY // MEANS OF THE ASYMPTOTIC EXPANSION FOR LARGE CABS(Z) IN THE // REGION CABS(Z)>MAX(RL,FNU*FNU/2). NZ=0 IS A NORMAL return. // NZ<0 INDICATES AN OVERFLOW ON KODE=1. func Zasyi(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, RL, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, RLout, TOLout, ELIMout, ALIMout float64) { var AA, AEZ, AK, AK1I, AK1R, ARG, ARM, ATOL, AZ, BB, BK, CKI, CKR, CONEI, CONER, CS1I, CS1R, CS2I, CS2R, CZI, CZR, DFNU, DKI, DKR, DNU2, EZI, EZR, FDN, PI, P1I, P1R, RAZ, RTPI, RTR1, RZI, RZR, S, SGN, SQK, STI, STR, S2I, S2R, TZI, TZR, ZEROI, ZEROR float64 var I, IB, IL, INU, J, JL, K, KODED, M, NN int var tmp complex128 // var sin, cos float64 PI = math.Pi RTPI = 0.159154943091895336e0 ZEROR = 0 ZEROI = 0 CONER = 1 CONEI = 0 AZ = cmplx.Abs(complex(ZR, ZI)) ARM = 1.0e3 * dmach[1] RTR1 = math.Sqrt(ARM) IL = min(2, N) DFNU = FNU + float64(float32(N-IL)) // OVERFLOW TEST RAZ = 1.0e0 / AZ STR = ZR * RAZ STI = -ZI * RAZ AK1R = RTPI * STR * RAZ AK1I = RTPI * STI * RAZ tmp = cmplx.Sqrt(complex(AK1R, AK1I)) AK1R = real(tmp) AK1I = imag(tmp) CZR = ZR CZI = ZI if KODE != 2 { goto Ten } CZR = ZEROR CZI = ZI Ten: if math.Abs(CZR) > ELIM { goto OneHundred } DNU2 = DFNU + DFNU KODED = 1 if (math.Abs(CZR) > ALIM) && (N > 2) { goto Twenty } KODED = 0 tmp = cmplx.Exp(complex(CZR, CZI)) STR = real(tmp) STI = imag(tmp) tmp = complex(AK1R, AK1I) * complex(STR, STI) AK1R = real(tmp) AK1I = imag(tmp) Twenty: FDN = 0.0e0 if DNU2 > RTR1 { FDN = DNU2 * DNU2 } EZR = ZR * 8.0e0 EZI = ZI * 8.0e0 // WHEN Z IS IMAGINARY, THE ERROR TEST MUST BE MADE RELATIVE TO THE // FIRST RECIPROCAL POWER SINCE THIS IS THE LEADING TERM OF THE // EXPANSION FOR THE IMAGINARY PART. AEZ = 8.0e0 * AZ S = TOL / AEZ JL = int(float32(RL+RL)) + 2 P1R = ZEROR P1I = ZEROI if ZI == 0.0e0 { goto Thirty } // CALCULATE EXP(PI*(0.5+FNU+N-IL)*I) TO MINIMIZE LOSSES OF // SIGNIFICANCE WHEN FNU OR N IS LARGE INU = int(float32(FNU)) ARG = (FNU - float64(float32(INU))) * PI INU = INU + N - IL //sin, cos = math.Sincos(ARG) AK = -math.Sin(ARG) BK = math.Cos(ARG) if ZI < 0.0e0 { BK = -BK } P1R = AK P1I = BK if INU%2 == 0 { goto Thirty } P1R = -P1R P1I = -P1I Thirty: for K = 1; K <= IL; K++ { SQK = FDN - 1.0e0 ATOL = S * math.Abs(SQK) SGN = 1.0e0 CS1R = CONER CS1I = CONEI CS2R = CONER CS2I = CONEI CKR = CONER CKI = CONEI AK = 0.0e0 AA = 1.0e0 BB = AEZ DKR = EZR DKI = EZI // TODO(btracey): This loop is executed tens of thousands of times. Why? // is that really necessary? for J = 1; J <= JL; J++ { tmp = complex(CKR, CKI) / complex(DKR, DKI) STR = real(tmp) STI = imag(tmp) CKR = STR * SQK CKI = STI * SQK CS2R = CS2R + CKR CS2I = CS2I + CKI SGN = -SGN CS1R = CS1R + CKR*SGN CS1I = CS1I + CKI*SGN DKR = DKR + EZR DKI = DKI + EZI AA = AA * math.Abs(SQK) / BB BB = BB + AEZ AK = AK + 8.0e0 SQK = SQK - AK if AA <= ATOL { goto Fifty } } goto OneTen Fifty: S2R = CS1R S2I = CS1I if ZR+ZR >= ELIM { goto Sixty } TZR = ZR + ZR TZI = ZI + ZI tmp = cmplx.Exp(complex(-TZR, -TZI)) STR = real(tmp) STI = imag(tmp) tmp = complex(STR, STI) * complex(P1R, P1I) STR = real(tmp) STI = imag(tmp) tmp = complex(STR, STI) * complex(CS2R, CS2I) STR = real(tmp) STI = imag(tmp) S2R = S2R + STR S2I = S2I + STI Sixty: FDN = FDN + 8.0e0*DFNU + 4.0e0 P1R = -P1R P1I = -P1I M = N - IL + K YR[M] = S2R*AK1R - S2I*AK1I YI[M] = S2R*AK1I + S2I*AK1R } if N <= 2 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } NN = N K = NN - 2 AK = float64(float32(K)) STR = ZR * RAZ STI = -ZI * RAZ RZR = (STR + STR) * RAZ RZI = (STI + STI) * RAZ IB = 3 for I = IB; I <= NN; I++ { YR[K] = (AK+FNU)*(RZR*YR[K+1]-RZI*YI[K+1]) + YR[K+2] YI[K] = (AK+FNU)*(RZR*YI[K+1]+RZI*YR[K+1]) + YI[K+2] AK = AK - 1.0e0 K = K - 1 } if KODED == 0 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } tmp = cmplx.Exp(complex(CZR, CZI)) CKR = real(tmp) CKI = imag(tmp) for I = 1; I <= NN; I++ { STR = YR[I]*CKR - YI[I]*CKI YI[I] = YR[I]*CKI + YI[I]*CKR YR[I] = STR } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM OneHundred: NZ = -1 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM OneTen: NZ = -2 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } // ZMLRI COMPUTES THE I BESSEL FUNCTION FOR RE(Z)>=0.0 BY THE // MILLER ALGORITHM NORMALIZED BY A NEUMANN SERIES. func Zmlri(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, TOL float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, TOLout float64) { var ACK, AK, AP, AT, AZ, BK, CKI, CKR, CNORMI, CNORMR, CONEI, CONER, FKAP, FKK, FLAM, FNF, PTI, PTR, P1I, P1R, P2I, P2R, RAZ, RHO, RHO2, RZI, RZR, SCLE, STI, STR, SUMI, SUMR, TFNF, TST, ZEROI, ZEROR float64 var I, IAZ, IDUM, IFNU, INU, ITIME, K, KK, KM, M int var tmp complex128 ZEROR = 0 ZEROI = 0 CONER = 1 CONEI = 0 SCLE = dmach[1] / TOL AZ = cmplx.Abs(complex(ZR, ZI)) IAZ = int(float32(AZ)) IFNU = int(float32(FNU)) INU = IFNU + N - 1 AT = float64(float32(IAZ)) + 1.0e0 RAZ = 1.0e0 / AZ STR = ZR * RAZ STI = -ZI * RAZ CKR = STR * AT * RAZ CKI = STI * AT * RAZ RZR = (STR + STR) * RAZ RZI = (STI + STI) * RAZ P1R = ZEROR P1I = ZEROI P2R = CONER P2I = CONEI ACK = (AT + 1.0e0) * RAZ RHO = ACK + math.Sqrt(ACK*ACK-1.0e0) RHO2 = RHO * RHO TST = (RHO2 + RHO2) / ((RHO2 - 1.0e0) * (RHO - 1.0e0)) TST = TST / TOL // COMPUTE RELATIVE TRUNCATION ERROR INDEX FOR SERIES. //fmt.Println("before loop", P2R, P2I, CKR, CKI, RZR, RZI, TST, AK) AK = AT for I = 1; I <= 80; I++ { PTR = P2R PTI = P2I P2R = P1R - (CKR*PTR - CKI*PTI) P2I = P1I - (CKI*PTR + CKR*PTI) P1R = PTR P1I = PTI CKR = CKR + RZR CKI = CKI + RZI AP = cmplx.Abs(complex(P2R, P2I)) if AP > TST*AK*AK { goto Twenty } AK = AK + 1.0e0 } goto OneTen Twenty: I = I + 1 K = 0 if INU < IAZ { goto Forty } // COMPUTE RELATIVE TRUNCATION ERROR FOR RATIOS. P1R = ZEROR P1I = ZEROI P2R = CONER P2I = CONEI AT = float64(float32(INU)) + 1.0e0 STR = ZR * RAZ STI = -ZI * RAZ CKR = STR * AT * RAZ CKI = STI * AT * RAZ ACK = AT * RAZ TST = math.Sqrt(ACK / TOL) ITIME = 1 for K = 1; K <= 80; K++ { PTR = P2R PTI = P2I P2R = P1R - (CKR*PTR - CKI*PTI) P2I = P1I - (CKR*PTI + CKI*PTR) P1R = PTR P1I = PTI CKR = CKR + RZR CKI = CKI + RZI AP = cmplx.Abs(complex(P2R, P2I)) if AP < TST { continue } if ITIME == 2 { goto Forty } ACK = cmplx.Abs(complex(CKR, CKI)) FLAM = ACK + math.Sqrt(ACK*ACK-1.0e0) FKAP = AP / cmplx.Abs(complex(P1R, P1I)) RHO = math.Min(FLAM, FKAP) TST = TST * math.Sqrt(RHO/(RHO*RHO-1.0e0)) ITIME = 2 } goto OneTen Forty: // BACKWARD RECURRENCE AND SUM NORMALIZING RELATION. K = K + 1 KK = max(I+IAZ, K+INU) FKK = float64(float32(KK)) P1R = ZEROR P1I = ZEROI // SCALE P2 AND SUM BY SCLE. P2R = SCLE P2I = ZEROI FNF = FNU - float64(float32(IFNU)) TFNF = FNF + FNF BK = dgamln(FKK+TFNF+1.0e0, IDUM) - dgamln(FKK+1.0e0, IDUM) - dgamln(TFNF+1.0e0, IDUM) BK = math.Exp(BK) SUMR = ZEROR SUMI = ZEROI KM = KK - INU for I = 1; I <= KM; I++ { PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) P1R = PTR P1I = PTI AK = 1.0e0 - TFNF/(FKK+TFNF) ACK = BK * AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0e0 } YR[N] = P2R YI[N] = P2I if N == 1 { goto Seventy } for I = 2; I <= N; I++ { PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) P1R = PTR P1I = PTI AK = 1.0e0 - TFNF/(FKK+TFNF) ACK = BK * AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0e0 M = N - I + 1 YR[M] = P2R YI[M] = P2I } Seventy: if IFNU <= 0 { goto Ninety } for I = 1; I <= IFNU; I++ { PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZR*PTI+RZI*PTR) P1R = PTR P1I = PTI AK = 1.0e0 - TFNF/(FKK+TFNF) ACK = BK * AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0e0 } Ninety: PTR = ZR PTI = ZI if KODE == 2 { PTR = ZEROR } tmp = cmplx.Log(complex(RZR, RZI)) STR = real(tmp) STI = imag(tmp) P1R = -FNF*STR + PTR P1I = -FNF*STI + PTI AP = dgamln(1.0e0+FNF, IDUM) PTR = P1R - AP PTI = P1I // THE DIVISION CEXP(PT)/(SUM+P2) IS ALTERED TO AVOID OVERFLOW // IN THE DENOMINATOR BY SQUARING LARGE QUANTITIES. P2R = P2R + SUMR P2I = P2I + SUMI AP = cmplx.Abs(complex(P2R, P2I)) P1R = 1.0e0 / AP tmp = cmplx.Exp(complex(PTR, PTI)) STR = real(tmp) STI = imag(tmp) CKR = STR * P1R CKI = STI * P1R PTR = P2R * P1R PTI = -P2I * P1R tmp = complex(CKR, CKI) * complex(PTR, PTI) CNORMR = real(tmp) CNORMI = imag(tmp) for I = 1; I <= N; I++ { STR = YR[I]*CNORMR - YI[I]*CNORMI YI[I] = YR[I]*CNORMI + YI[I]*CNORMR YR[I] = STR } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL OneTen: NZ = -2 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL } // Zseri computes the I bessel function for real(z) >= 0 by means of the power // series for large |z| in the region |z| <= 2*sqrt(fnu+1). // // nz = 0 is a normal return. nz > 0 means that the last nz components were set // to zero due to underflow. nz < 0 means that underflow occurred, but the // condition |z| <= 2*sqrt(fnu+1) was violated and the computation must be // completed in another routine with n -= abs(nz). func Zseri(z complex128, fnu float64, kode, n int, y []complex128, tol, elim, alim float64) (nz int) { // TODO(btracey): The original fortran line is "ARM = 1.0D+3*D1MACH(1)". Evidently, in Fortran // this is interpreted as one to the power of +3*D1MACH(1). While it is possible // this was intentional, it seems unlikely. arm := 1000 * dmach[1] az := cmplx.Abs(z) if az < arm { for i := 0; i < n; i++ { y[i] = 0 } if fnu == 0 { y[0] = 1 n-- } if az == 0 { return 0 } return n } hz := 0.5 * z var cz complex128 var acz float64 if az > math.Sqrt(arm) { cz = hz * hz acz = cmplx.Abs(cz) } NN := n ck := cmplx.Log(hz) var ak1 complex128 for { dfnu := fnu + float64(NN-1) // Underflow test. ak1 = ck * complex(dfnu, 0) ak := dgamln(dfnu+1, 0) ak1 -= complex(ak, 0) if kode == 2 { ak1 -= complex(real(z), 0) } if real(ak1) > -elim { break } nz++ y[NN-1] = 0 if acz > dfnu { // Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation // in cbinu with n = n - abs(nz). nz *= -1 return nz } NN-- if NN == 0 { return nz } } crscr := 1.0 var flag int var scale float64 aa := real(ak1) if aa <= -alim { flag = 1 crscr = tol scale = arm / tol aa -= math.Log(tol) } var w [2]complex128 for { coef := cmplx.Exp(complex(aa, imag(ak1))) atol := tol * acz / (fnu + float64(NN)) for i := 0; i < min(2, NN); i++ { FNUP := fnu + float64(NN-i) s1 := 1 + 0i if acz >= tol*FNUP { ak2 := 1 + 0i ak := FNUP + 2 S := FNUP scl := 2.0 first := true for first || scl > atol { ak2 = ak2 * cz * complex(1/S, 0) scl *= acz / S s1 += ak2 S += ak ak += 2 first = false } } s2 := s1 * coef w[i] = s2 if flag == 1 { if Zuchk(s2, scale, tol) != 0 { var full bool var dfnu float64 // This code is similar to the code that exists above. The // code copying is here because the original Fortran used // a goto to solve the loop-and-a-half problem. Removing the // goto makes the behavior of the function and variable scoping // much clearer, but requires copying this code due to Go's // goto rules. for { if full { dfnu = fnu + float64(NN-1) // Underflow test. ak1 = ck * complex(dfnu, 0) ak1 -= complex(dgamln(dfnu+1, 0), 0) if kode == 2 { ak1 -= complex(real(z), 0) } if real(ak1) > -elim { break } } else { full = true } nz++ y[NN-1] = 0 if acz > dfnu { // Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation // in cbinu with n = n - abs(nz). nz *= -1 return nz } NN-- if NN == 0 { return nz } } continue } } y[NN-i-1] = s2 * complex(crscr, 0) coef /= hz coef *= complex(FNUP-1, 0) } break } if NN <= 2 { return nz } rz := complex(2*real(z)/(az*az), -2*imag(z)/(az*az)) if flag == 0 { for i := NN - 3; i >= 0; i-- { y[i] = complex(float64(i+1)+fnu, 0)*rz*y[i+1] + y[i+2] } return nz } // exp(-alim)=exp(-elim)/tol=approximately one digit of precision above the // underflow limit, which equals scale = dmach[1)*SS*1e3. s1 := w[0] s2 := w[1] for K := NN - 3; K >= 0; K-- { s1, s2 = s2, s1+complex(float64(K+1)+fnu, 0)*(rz*s2) ck := s2 * complex(crscr, 0) y[K] = ck if cmplx.Abs(ck) > scale { for ; K >= 0; K-- { y[K] = complex(float64(K+1)+fnu, 0)*rz*y[K+1] + y[K+2] } return nz } } return nz } // Zs1s2 tests for a possible underflow resulting from the addition of the I and // K functions in the analytic continuation formula where s1 == K function and // s2 == I function. // // When kode == 1, the I and K functions are different orders of magnitude. // // When kode == 2, they may both be of the same order of magnitude, but the maximum // must be at least one precision above the underflow limit. func Zs1s2(zr, s1, s2 complex128, scale, lim float64, iuf int) (s1o, s2o complex128, nz, iufo int) { if s1 == 0 || math.Log(cmplx.Abs(s1))-2*real(zr) < -lim { if cmplx.Abs(s2) > scale { return 0, s2, 0, iuf } return 0, 0, 1, 0 } // TODO(btracey): Written like this for numerical rounding reasons. // Fix once we're sure other changes are correct. s1 = cmplx.Exp(cmplx.Log(s1) - zr - zr) if math.Max(cmplx.Abs(s1), cmplx.Abs(s2)) > scale { return s1, s2, 0, iuf + 1 } return 0, 0, 1, 0 } func dgamln(z float64, ierr int) float64 { //return amoslib.DgamlnFort(z) // Go implementation. if z < 0 { return 0 } a2, _ := math.Lgamma(z) return a2 } golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amos_fortran_test.go000066400000000000000000000323111450372207100261430ustar00rootroot00000000000000// Copyright ©2016 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:build fortran // +build fortran package amos import ( "flag" "runtime" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext/internal/amos/amoslib" ) // BUG(kortschak): Some tests here comparing the direct Go translation // of the Fortran code fail. Do not delete these tests or this file until // https://github.com/gonum/gonum/issues/1322 has been satisfactorily // resolved. var runFailing = flag.Bool("failing", false, "run known failing cases") func TestAiryFortran(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zairytestFort(t, in.x, in.kode, in.id) } } func TestZacaiFortran(t *testing.T) { if !*runFailing { t.Skip("fails") } switch runtime.GOARCH { case "arm64": t.Skipf("skipping on GOARCH=%s", runtime.GOARCH) } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zacaitestFort(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZbknuFortran(t *testing.T) { if !*runFailing { t.Skip("fails") } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zbknutestFort(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZasyiFortran(t *testing.T) { if !*runFailing { t.Skip("fails") } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zasyitestFort(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZseriFortran(t *testing.T) { switch runtime.GOARCH { case "arm64": t.Skipf("skipping on GOARCH=%s", runtime.GOARCH) } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zseritestFort(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZmlriFortran(t *testing.T) { if !*runFailing { t.Skip("fails") } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zmlritestFort(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZksclFortran(t *testing.T) { if !*runFailing { t.Skip("fails") } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zkscltestFort(t, in.x, in.is, in.tol, in.n, in.yr, in.yi) } } func TestZuchkFortran(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zuchktestFort(t, in.x, in.is, in.tol) } } func TestZs1s2Fortran(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zs1s2testFort(t, in.x, in.is) } } func zs1s2testFort(t *testing.T, x []float64, is []int) { const tol = 1e-11 type data struct { ZRR, ZRI, S1R, S1I, S2R, S2I float64 NZ int ASCLE, ALIM float64 IUF int } input := data{ x[0], x[1], x[2], x[3], x[4], x[5], is[0], x[6], x[7], is[1], } impl := func(input data) data { zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf := amoslib.Zs1s2Fort(input.ZRR, input.ZRI, input.S1R, input.S1I, input.S2R, input.S2I, input.NZ, input.ASCLE, input.ALIM, input.IUF) return data{zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf} } comp := func(input data) data { zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf := zs1s2Orig(input.ZRR, input.ZRI, input.S1R, input.S1I, input.S2R, input.S2I, input.NZ, input.ASCLE, input.ALIM, input.IUF) return data{zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf} } oi := impl(input) oc := comp(input) sameF64Approx(t, "zs1s2 zrr", oc.ZRR, oi.ZRR, tol) sameF64Approx(t, "zs1s2 zri", oc.ZRI, oi.ZRI, tol) sameF64Approx(t, "zs1s2 s1r", oc.S1R, oi.S1R, tol) sameF64Approx(t, "zs1s2 s1i", oc.S1I, oi.S1I, tol) sameF64Approx(t, "zs1s2 s2r", oc.S2R, oi.S2R, tol) sameF64Approx(t, "zs1s2 s2i", oc.S2I, oi.S2I, tol) sameF64Approx(t, "zs1s2 ascle", oc.ASCLE, oi.ASCLE, tol) sameF64Approx(t, "zs1s2 alim", oc.ALIM, oi.ALIM, tol) sameInt(t, "iuf", oc.IUF, oi.IUF) sameInt(t, "nz", oc.NZ, oi.NZ) } func zuchktestFort(t *testing.T, x []float64, is []int, tol float64) { t.Helper() YR := x[0] YI := x[1] NZ := is[0] ASCLE := x[2] TOL := tol YRfort, YIfort, NZfort, ASCLEfort, TOLfort := zuchkOrig(YR, YI, NZ, ASCLE, TOL) YRamoslib, YIamoslib, NZamoslib, ASCLEamoslib, TOLamoslib := amoslib.ZuchkFort(YR, YI, NZ, ASCLE, TOL) sameF64(t, "zuchk yr", YRfort, YRamoslib) sameF64(t, "zuchk yi", YIfort, YIamoslib) sameInt(t, "zuchk nz", NZfort, NZamoslib) sameF64(t, "zuchk ascle", ASCLEfort, ASCLEamoslib) sameF64(t, "zuchk tol", TOLfort, TOLamoslib) } func zkscltestFort(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64) { t.Helper() ZRR := x[0] ZRI := x[1] FNU := x[2] NZ := is[1] ELIM := x[3] ASCLE := x[4] RZR := x[6] RZI := x[7] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRRfort, ZRIfort, FNUfort, Nfort, YRfort, YIfort, NZfort, RZRfort, RZIfort, ASCLEfort, TOLfort, ELIMfort := zksclOrig(ZRR, ZRI, FNU, n, yrfort, yifort, NZ, RZR, RZI, ASCLE, tol, ELIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRRamoslib, ZRIamoslib, FNUamoslib, Namoslib, YRamoslib, YIamoslib, NZamoslib, RZRamoslib, RZIamoslib, ASCLEamoslib, TOLamoslib, ELIMamoslib := amoslib.ZksclFort(ZRR, ZRI, FNU, n, yramos, yiamos, NZ, RZR, RZI, ASCLE, tol, ELIM) sameF64(t, "zkscl zrr", ZRRfort, ZRRamoslib) sameF64(t, "zkscl zri", ZRIfort, ZRIamoslib) sameF64(t, "zkscl fnu", FNUfort, FNUamoslib) sameInt(t, "zkscl n", Nfort, Namoslib) sameInt(t, "zkscl nz", NZfort, NZamoslib) sameF64(t, "zkscl rzr", RZRfort, RZRamoslib) sameF64(t, "zkscl rzi", RZIfort, RZIamoslib) sameF64(t, "zkscl ascle", ASCLEfort, ASCLEamoslib) sameF64(t, "zkscl tol", TOLfort, TOLamoslib) sameF64(t, "zkscl elim", ELIMfort, ELIMamoslib) sameF64SApprox(t, "zkscl yr", YRfort, YRamoslib, 1e-14) sameF64SApprox(t, "zkscl yi", YIfort, YIamoslib, 1e-14) } func zmlritestFort(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { t.Helper() ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort := zmlriOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamoslib, ZIamoslib, FNUamoslib, KODEamoslib, Namoslib, YRamoslib, YIamoslib, NZamoslib, TOLamoslib := amoslib.ZmlriFort(ZR, ZI, FNU, KODE, n, yramos, yiamos, NZ, tol) sameF64(t, "zmlri zr", ZRfort, ZRamoslib) sameF64(t, "zmlri zi", ZIfort, ZIamoslib) sameF64(t, "zmlri fnu", FNUfort, FNUamoslib) sameInt(t, "zmlri kode", KODEfort, KODEamoslib) sameInt(t, "zmlri n", Nfort, Namoslib) sameInt(t, "zmlri nz", NZfort, NZamoslib) sameF64(t, "zmlri tol", TOLfort, TOLamoslib) sameF64S(t, "zmlri yr", YRfort, YRamoslib) sameF64S(t, "zmlri yi", YIfort, YIamoslib) } func zseritestFort(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { t.Helper() ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] ELIM := x[3] ALIM := x[4] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort, ELIMfort, ALIMfort := zseriOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) y := make([]complex128, len(yramos)) for i, v := range yramos { y[i] = complex(v, yiamos[i]) } ZRamoslib, ZIamoslib, FNUamoslib, KODEamoslib, Namoslib, YRamoslib, YIamoslib, NZamoslib, TOLamoslib, ELIMamoslib, ALIMamoslib := amoslib.ZseriFort(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol, ELIM, ALIM) sameF64(t, "zseri zr", ZRfort, ZRamoslib) sameF64(t, "zseri zi", ZIfort, ZIamoslib) sameF64(t, "zseri fnu", FNUfort, FNUamoslib) sameInt(t, "zseri kode", KODEfort, KODEamoslib) sameInt(t, "zseri n", Nfort, Namoslib) if *runFailing { sameInt(t, "zseri nz", NZfort, NZamoslib) } sameF64(t, "zseri tol", TOLfort, TOLamoslib) sameF64(t, "zseri elim", ELIMfort, ELIMamoslib) sameF64(t, "zseri elim", ALIMfort, ALIMamoslib) sameF64SApprox(t, "zseri yr", YRfort, YRamoslib, 1e-9) sameF64SApprox(t, "zseri yi", YIfort, YIamoslib, 1e-10) } func zasyitestFort(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { t.Helper() ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] ELIM := x[3] ALIM := x[4] RL := x[5] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, RLfort, TOLfort, ELIMfort, ALIMfort := zasyiOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, RL, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamoslib, ZIamoslib, FNUamoslib, KODEamoslib, Namoslib, YRamoslib, YIamoslib, NZamoslib, RLamoslib, TOLamoslib, ELIMamoslib, ALIMamoslib := amoslib.ZasyiFort(ZR, ZI, FNU, KODE, n, yramos, yiamos, NZ, RL, tol, ELIM, ALIM) sameF64(t, "zasyi zr", ZRfort, ZRamoslib) sameF64(t, "zasyi zr", ZIfort, ZIamoslib) sameF64(t, "zasyi fnu", FNUfort, FNUamoslib) sameInt(t, "zasyi kode", KODEfort, KODEamoslib) sameInt(t, "zasyi n", Nfort, Namoslib) sameInt(t, "zasyi nz", NZfort, NZamoslib) sameF64(t, "zasyi rl", RLfort, RLamoslib) sameF64(t, "zasyi tol", TOLfort, TOLamoslib) sameF64(t, "zasyi elim", ELIMfort, ELIMamoslib) sameF64(t, "zasyi alim", ALIMfort, ALIMamoslib) sameF64SApprox(t, "zasyi yr", YRfort, YRamoslib, 1e-12) sameF64SApprox(t, "zasyi yi", YIfort, YIamoslib, 1e-12) } func zbknutestFort(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { t.Helper() ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] ELIM := x[3] ALIM := x[4] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort, ELIMfort, ALIMfort := zbknuOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamoslib, ZIamoslib, FNUamoslib, KODEamoslib, Namoslib, YRamoslib, YIamoslib, NZamoslib, TOLamoslib, ELIMamoslib, ALIMamoslib := amoslib.ZbknuFort(ZR, ZI, FNU, KODE, n, yramos, yiamos, NZ, tol, ELIM, ALIM) sameF64(t, "zbknu zr", ZRfort, ZRamoslib) sameF64(t, "zbknu zr", ZIfort, ZIamoslib) sameF64(t, "zbknu fnu", FNUfort, FNUamoslib) sameInt(t, "zbknu kode", KODEfort, KODEamoslib) sameInt(t, "zbknu n", Nfort, Namoslib) sameInt(t, "zbknu nz", NZfort, NZamoslib) sameF64(t, "zbknu tol", TOLfort, TOLamoslib) sameF64(t, "zbknu elim", ELIMfort, ELIMamoslib) sameF64(t, "zbknu alim", ALIMfort, ALIMamoslib) sameF64SApprox(t, "zbknu yr", YRfort, YRamoslib, 1e-12) sameF64SApprox(t, "zbknu yi", YIfort, YIamoslib, 1e-12) } func zairytestFort(t *testing.T, x []float64, kode, id int) { const tol = 1e-8 t.Helper() ZR := x[0] ZI := x[1] KODE := kode ID := id AIRfort, AIIfort, NZfort, IERRfort := zairyOrig(ZR, ZI, ID, KODE) AIRamos, AIIamos, NZamos, IERRamos := amoslib.ZairyFort(ZR, ZI, ID, KODE) sameF64Approx(t, "zairy air", AIRfort, AIRamos, tol) sameF64Approx(t, "zairy aii", AIIfort, AIIamos, tol) sameInt(t, "zairy nz", NZfort, NZamos) sameInt(t, "zairy ierr", IERRfort, IERRamos) } func zacaitestFort(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { t.Helper() ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] MR := is[2] ELIM := x[3] ALIM := x[4] RL := x[5] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, MRfort, Nfort, YRfort, YIfort, NZfort, RLfort, TOLfort, ELIMfort, ALIMfort := zacaiOrig(ZR, ZI, FNU, KODE, MR, n, yrfort, yifort, NZ, RL, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamoslib, ZIamoslib, FNUamoslib, KODEamoslib, MRamoslib, Namoslib, YRamoslib, YIamoslib, NZamoslib, RLamoslib, TOLamoslib, ELIMamoslib, ALIMamoslib := amoslib.ZacaiFort(ZR, ZI, FNU, KODE, MR, n, yramos, yiamos, NZ, RL, tol, ELIM, ALIM) sameF64(t, "zacai zr", ZRfort, ZRamoslib) sameF64(t, "zacai zi", ZIfort, ZIamoslib) sameF64(t, "zacai fnu", FNUfort, FNUamoslib) sameInt(t, "zacai kode", KODEfort, KODEamoslib) sameInt(t, "zacai mr", MRfort, MRamoslib) sameInt(t, "zacai n", Nfort, Namoslib) sameInt(t, "zacai nz", NZfort, NZamoslib) sameF64(t, "zacai rl", RLfort, RLamoslib) sameF64(t, "zacai tol", TOLfort, TOLamoslib) sameF64(t, "zacai elim", ELIMfort, ELIMamoslib) sameF64(t, "zacai elim", ALIMfort, ALIMamoslib) sameF64SApprox(t, "zacai yr", YRfort, YRamoslib, 1e-12) sameF64SApprox(t, "zacai yi", YIfort, YIamoslib, 1e-12) } golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amos_test.go000066400000000000000000000350211450372207100244110ustar00rootroot00000000000000// Copyright ©2016 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 amos import ( "math" "runtime" "strconv" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) type input struct { x []float64 is []int kode int id int yr []float64 yi []float64 n int tol float64 } func randnum(rnd *rand.Rand) float64 { r := 2e2 // Fortran has infinite loop if this is set higher than 2e3 if rnd.Float64() > 0.99 { return 0 } return rnd.Float64()*r - r/2 } func randInput(rnd *rand.Rand) input { x := make([]float64, 8) for j := range x { x[j] = randnum(rnd) } is := make([]int, 3) for j := range is { is[j] = rnd.Intn(1000) } kode := rnd.Intn(2) + 1 id := rnd.Intn(2) n := rnd.Intn(5) + 1 yr := make([]float64, n+1) yi := make([]float64, n+1) for j := range yr { yr[j] = randnum(rnd) yi[j] = randnum(rnd) } tol := 1e-14 return input{ x, is, kode, id, yr, yi, n, tol, } } const nInputs = 100000 func TestAiry(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zairytest(t, in.x, in.kode, in.id) } } func TestZacai(t *testing.T) { t.Parallel() switch runtime.GOARCH { case "arm64": t.Skipf("skipping on GOARCH=%s", runtime.GOARCH) } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zacaitest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZbknu(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zbknutest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZasyi(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zasyitest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZseri(t *testing.T) { t.Parallel() switch runtime.GOARCH { case "arm64": t.Skipf("skipping on GOARCH=%s", runtime.GOARCH) } rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zseritest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZmlri(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zmlritest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) } } func TestZkscl(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zkscltest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi) } } func TestZuchk(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zuchktest(t, in.x, in.is, in.tol) } } func TestZs1s2(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for i := 0; i < nInputs; i++ { in := randInput(rnd) zs1s2test(t, in.x, in.is) } } func zs1s2test(t *testing.T, x []float64, is []int) { type data struct { ZRR, ZRI, S1R, S1I, S2R, S2I float64 NZ int ASCLE, ALIM float64 IUF int } input := data{ x[0], x[1], x[2], x[3], x[4], x[5], is[0], x[6], x[7], is[1], } zr := complex(input.ZRR, input.ZRI) s1 := complex(input.S1R, input.S1I) s2 := complex(input.S2R, input.S2I) impl := func(input data) data { s1, s2, nz, iuf := Zs1s2(zr, s1, s2, input.ASCLE, input.ALIM, input.IUF) zrr := real(zr) zri := imag(zr) s1r := real(s1) s1i := imag(s1) s2r := real(s2) s2i := imag(s2) alim := input.ALIM ascle := input.ASCLE return data{zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf} } comp := func(input data) data { zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf := zs1s2Orig(input.ZRR, input.ZRI, input.S1R, input.S1I, input.S2R, input.S2I, input.NZ, input.ASCLE, input.ALIM, input.IUF) return data{zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf} } oi := impl(input) oc := comp(input) sameF64(t, "zs1s2 zrr", oc.ZRR, oi.ZRR) sameF64(t, "zs1s2 zri", oc.ZRI, oi.ZRI) sameF64(t, "zs1s2 s1r", oc.S1R, oi.S1R) sameF64(t, "zs1s2 s1i", oc.S1I, oi.S1I) sameF64(t, "zs1s2 s2r", oc.S2R, oi.S2R) sameF64(t, "zs1s2 s2i", oc.S2I, oi.S2I) sameF64(t, "zs1s2 ascle", oc.ASCLE, oi.ASCLE) sameF64(t, "zs1s2 alim", oc.ALIM, oi.ALIM) sameInt(t, "iuf", oc.IUF, oi.IUF) sameInt(t, "nz", oc.NZ, oi.NZ) } func zuchktest(t *testing.T, x []float64, is []int, tol float64) { YR := x[0] YI := x[1] NZ := is[0] ASCLE := x[2] TOL := tol YRfort, YIfort, NZfort, ASCLEfort, TOLfort := zuchkOrig(YR, YI, NZ, ASCLE, TOL) y := complex(YR, YI) NZamos := Zuchk(y, ASCLE, TOL) YRamos := real(y) YIamos := imag(y) ASCLEamos := ASCLE TOLamos := TOL sameF64(t, "zuchk yr", YRfort, YRamos) sameF64(t, "zuchk yi", YIfort, YIamos) sameInt(t, "zuchk nz", NZfort, NZamos) sameF64(t, "zuchk ascle", ASCLEfort, ASCLEamos) sameF64(t, "zuchk tol", TOLfort, TOLamos) } func zkscltest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64) { ZRR := x[0] ZRI := x[1] FNU := x[2] NZ := is[1] ELIM := x[3] ASCLE := x[4] RZR := x[6] RZI := x[7] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRRfort, ZRIfort, FNUfort, Nfort, YRfort, YIfort, NZfort, RZRfort, RZIfort, ASCLEfort, TOLfort, ELIMfort := zksclOrig(ZRR, ZRI, FNU, n, yrfort, yifort, NZ, RZR, RZI, ASCLE, tol, ELIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRRamos, ZRIamos, FNUamos, Namos, YRamos, YIamos, NZamos, RZRamos, RZIamos, ASCLEamos, TOLamos, ELIMamos := Zkscl(ZRR, ZRI, FNU, n, yramos, yiamos, RZR, RZI, ASCLE, tol, ELIM) sameF64(t, "zkscl zrr", ZRRfort, ZRRamos) sameF64(t, "zkscl zri", ZRIfort, ZRIamos) sameF64(t, "zkscl fnu", FNUfort, FNUamos) sameInt(t, "zkscl n", Nfort, Namos) sameInt(t, "zkscl nz", NZfort, NZamos) sameF64(t, "zkscl rzr", RZRfort, RZRamos) sameF64(t, "zkscl rzi", RZIfort, RZIamos) sameF64(t, "zkscl ascle", ASCLEfort, ASCLEamos) sameF64(t, "zkscl tol", TOLfort, TOLamos) sameF64(t, "zkscl elim", ELIMfort, ELIMamos) sameF64SApprox(t, "zkscl yr", YRfort, YRamos, 1e-14) sameF64SApprox(t, "zkscl yi", YIfort, YIamos, 1e-14) } func zmlritest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort := zmlriOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamos, ZIamos, FNUamos, KODEamos, Namos, YRamos, YIamos, NZamos, TOLamos := Zmlri(ZR, ZI, FNU, KODE, n, yramos, yiamos, tol) sameF64(t, "zmlri zr", ZRfort, ZRamos) sameF64(t, "zmlri zi", ZIfort, ZIamos) sameF64(t, "zmlri fnu", FNUfort, FNUamos) sameInt(t, "zmlri kode", KODEfort, KODEamos) sameInt(t, "zmlri n", Nfort, Namos) sameInt(t, "zmlri nz", NZfort, NZamos) sameF64(t, "zmlri tol", TOLfort, TOLamos) sameF64S(t, "zmlri yr", YRfort, YRamos) sameF64S(t, "zmlri yi", YIfort, YIamos) } func zseritest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] ELIM := x[3] ALIM := x[4] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort, ELIMfort, ALIMfort := zseriOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) y := make([]complex128, len(yramos)) for i, v := range yramos { y[i] = complex(v, yiamos[i]) } z := complex(ZR, ZI) NZamos := Zseri(z, FNU, KODE, n, y[1:], tol, ELIM, ALIM) ZRamos := real(z) ZIamos := imag(z) FNUamos := FNU KODEamos := KODE Namos := n TOLamos := tol ELIMamos := ELIM ALIMamos := ALIM YRamos := make([]float64, len(y)) YIamos := make([]float64, len(y)) for i, v := range y { YRamos[i] = real(v) YIamos[i] = imag(v) } sameF64(t, "zseri zr", ZRfort, ZRamos) sameF64(t, "zseri zi", ZIfort, ZIamos) sameF64(t, "zseri fnu", FNUfort, FNUamos) sameInt(t, "zseri kode", KODEfort, KODEamos) sameInt(t, "zseri n", Nfort, Namos) sameInt(t, "zseri nz", NZfort, NZamos) sameF64(t, "zseri tol", TOLfort, TOLamos) sameF64(t, "zseri elim", ELIMfort, ELIMamos) sameF64(t, "zseri elim", ALIMfort, ALIMamos) sameF64SApprox(t, "zseri yr", YRfort, YRamos, 1e-9) sameF64SApprox(t, "zseri yi", YIfort, YIamos, 1e-10) } func zasyitest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] ELIM := x[3] ALIM := x[4] RL := x[5] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, RLfort, TOLfort, ELIMfort, ALIMfort := zasyiOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, RL, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamos, ZIamos, FNUamos, KODEamos, Namos, YRamos, YIamos, NZamos, RLamos, TOLamos, ELIMamos, ALIMamos := Zasyi(ZR, ZI, FNU, KODE, n, yramos, yiamos, RL, tol, ELIM, ALIM) sameF64(t, "zasyi zr", ZRfort, ZRamos) sameF64(t, "zasyi zr", ZIfort, ZIamos) sameF64(t, "zasyi fnu", FNUfort, FNUamos) sameInt(t, "zasyi kode", KODEfort, KODEamos) sameInt(t, "zasyi n", Nfort, Namos) sameInt(t, "zasyi nz", NZfort, NZamos) sameF64(t, "zasyi rl", RLfort, RLamos) sameF64(t, "zasyi tol", TOLfort, TOLamos) sameF64(t, "zasyi elim", ELIMfort, ELIMamos) sameF64(t, "zasyi alim", ALIMfort, ALIMamos) sameF64SApprox(t, "zasyi yr", YRfort, YRamos, 1e-12) sameF64SApprox(t, "zasyi yi", YIfort, YIamos, 1e-12) } func zbknutest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] ELIM := x[3] ALIM := x[4] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort, ELIMfort, ALIMfort := zbknuOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamos, ZIamos, FNUamos, KODEamos, Namos, YRamos, YIamos, NZamos, TOLamos, ELIMamos, ALIMamos := Zbknu(ZR, ZI, FNU, KODE, n, yramos, yiamos, tol, ELIM, ALIM) sameF64(t, "zbknu zr", ZRfort, ZRamos) sameF64(t, "zbknu zr", ZIfort, ZIamos) sameF64(t, "zbknu fnu", FNUfort, FNUamos) sameInt(t, "zbknu kode", KODEfort, KODEamos) sameInt(t, "zbknu n", Nfort, Namos) sameInt(t, "zbknu nz", NZfort, NZamos) sameF64(t, "zbknu tol", TOLfort, TOLamos) sameF64(t, "zbknu elim", ELIMfort, ELIMamos) sameF64(t, "zbknu alim", ALIMfort, ALIMamos) sameF64SApprox(t, "zbknu yr", YRfort, YRamos, 1e-12) sameF64SApprox(t, "zbknu yi", YIfort, YIamos, 1e-12) } func zairytest(t *testing.T, x []float64, kode, id int) { ZR := x[0] ZI := x[1] KODE := kode ID := id AIRfort, AIIfort, NZfort, IERRfort := zairyOrig(ZR, ZI, ID, KODE) AIRamos, AIIamos, NZamos, IERRamos := Zairy(ZR, ZI, ID, KODE) sameF64Approx(t, "zairy air", AIRfort, AIRamos, 1e-12) sameF64Approx(t, "zairy aii", AIIfort, AIIamos, 1e-12) sameInt(t, "zairy nz", NZfort, NZamos) sameInt(t, "zairy ierr", IERRfort, IERRamos) } func zacaitest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { ZR := x[0] ZI := x[1] FNU := x[2] KODE := kode NZ := is[1] MR := is[2] ELIM := x[3] ALIM := x[4] RL := x[5] yrfort := make([]float64, len(yr)) copy(yrfort, yr) yifort := make([]float64, len(yi)) copy(yifort, yi) ZRfort, ZIfort, FNUfort, KODEfort, MRfort, Nfort, YRfort, YIfort, NZfort, RLfort, TOLfort, ELIMfort, ALIMfort := zacaiOrig(ZR, ZI, FNU, KODE, MR, n, yrfort, yifort, NZ, RL, tol, ELIM, ALIM) yramos := make([]float64, len(yr)) copy(yramos, yr) yiamos := make([]float64, len(yi)) copy(yiamos, yi) ZRamos, ZIamos, FNUamos, KODEamos, MRamos, Namos, YRamos, YIamos, NZamos, RLamos, TOLamos, ELIMamos, ALIMamos := Zacai(ZR, ZI, FNU, KODE, MR, n, yramos, yiamos, RL, tol, ELIM, ALIM) sameF64(t, "zacai zr", ZRfort, ZRamos) sameF64(t, "zacai zi", ZIfort, ZIamos) sameF64(t, "zacai fnu", FNUfort, FNUamos) sameInt(t, "zacai kode", KODEfort, KODEamos) sameInt(t, "zacai mr", MRfort, MRamos) sameInt(t, "zacai n", Nfort, Namos) sameInt(t, "zacai nz", NZfort, NZamos) sameF64(t, "zacai rl", RLfort, RLamos) sameF64(t, "zacai tol", TOLfort, TOLamos) sameF64(t, "zacai elim", ELIMfort, ELIMamos) sameF64(t, "zacai elim", ALIMfort, ALIMamos) sameF64SApprox(t, "zacai yr", YRfort, YRamos, 1e-12) sameF64SApprox(t, "zacai yi", YIfort, YIamos, 1e-12) } func sameF64(t *testing.T, str string, c, native float64) { t.Helper() if math.IsNaN(c) && math.IsNaN(native) { return } if c == native { return } cb := math.Float64bits(c) nb := math.Float64bits(native) t.Errorf("Case %s: Float64 mismatch. c = %v, native = %v\n cb: %v, nb: %v\n", str, c, native, cb, nb) } func sameF64Approx(t *testing.T, str string, c, native, tol float64) { t.Helper() if math.IsNaN(c) && math.IsNaN(native) { return } if scalar.EqualWithinAbsOrRel(c, native, tol, tol) { return } // Have a much looser tolerance for correctness when the values are large. // Floating point noise makes the relative tolerance difference greater for // higher values. if c > 1e200 && scalar.EqualWithinAbsOrRel(c, native, 10, 10) { return } cb := math.Float64bits(c) nb := math.Float64bits(native) t.Errorf("Case %s: Float64 mismatch. c = %v, native = %v\n cb: %v, nb: %v\n", str, c, native, cb, nb) } func sameInt(t *testing.T, str string, c, native int) { t.Helper() if c != native { t.Errorf("Case %s: Int mismatch. c = %v, native = %v.", str, c, native) } } func sameF64S(t *testing.T, str string, c, native []float64) { t.Helper() if len(c) != len(native) { panic(str) } for i, v := range c { sameF64(t, str+"_idx_"+strconv.Itoa(i), v, native[i]) } } func sameF64SApprox(t *testing.T, str string, c, native []float64, tol float64) { t.Helper() if len(c) != len(native) { panic(str) } for i, v := range c { sameF64Approx(t, str+"_idx_"+strconv.Itoa(i), v, native[i], tol) } } golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/000077500000000000000000000000001450372207100235115ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/Make.files000066400000000000000000000005651450372207100254200ustar00rootroot00000000000000$(CUR_SRCS) += d1mach.f zabs.f zasyi.f zbesk.f zbknu.f zexp.f zmlt.f zshch.f zuni1.f zunk2.f \ dgamln.f zacai.f zbesh.f zbesy.f zbuni.f zkscl.f zrati.f zsqrt.f zuni2.f zuoik.f \ i1mach.f zacon.f zbesi.f zbinu.f zbunk.f zlog.f zs1s2.f zuchk.f zunik.f zwrsk.f \ xerror.f zairy.f zbesj.f zbiry.f zdiv.f zmlri.f zseri.f zunhj.f zunk1.f golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/d1mach.f000066400000000000000000000064171450372207100250250ustar00rootroot00000000000000*DECK D1MACH DOUBLE PRECISION FUNCTION D1MACH(I) C***BEGIN PROLOGUE D1MACH C***DATE WRITTEN 750101 (YYMMDD) C***REVISION DATE 890213 (YYMMDD) C***CATEGORY NO. R1 C***KEYWORDS LIBRARY=SLATEC,TYPE=DOUBLE PRECISION(R1MACH-S D1MACH-D), C MACHINE CONSTANTS C***AUTHOR FOX, P. A., (BELL LABS) C HALL, A. D., (BELL LABS) C SCHRYER, N. L., (BELL LABS) C***PURPOSE Returns double precision machine dependent constants C***DESCRIPTION C C D1MACH can be used to obtain machine-dependent parameters C for the local machine environment. It is a function C subprogram with one (input) argument, and can be called C as follows, for example C C D = D1MACH(I) C C where I=1,...,5. The (output) value of D above is C determined by the (input) value of I. The results for C various values of I are discussed below. C C D1MACH( 1) = B**(EMIN-1), the smallest positive magnitude. C D1MACH( 2) = B**EMAX*(1 - B**(-T)), the largest magnitude. C D1MACH( 3) = B**(-T), the smallest relative spacing. C D1MACH( 4) = B**(1-T), the largest relative spacing. C D1MACH( 5) = LOG10(B) C C Assume double precision numbers are represented in the T-digit, C base-B form C C sign (B**E)*( (X(1)/B) + ... + (X(T)/B**T) ) C C where 0 .LE. X(I) .LT. B for I=1,...,T, 0 .LT. X(1), and C EMIN .LE. E .LE. EMAX. C C The values of B, T, EMIN and EMAX are provided in I1MACH as C follows: C I1MACH(10) = B, the base. C I1MACH(14) = T, the number of base-B digits. C I1MACH(15) = EMIN, the smallest exponent E. C I1MACH(16) = EMAX, the largest exponent E. C C To alter this function for a particular environment, C the desired set of DATA statements should be activated by C removing the C from column 1. Also, the values of C D1MACH(1) - D1MACH(4) should be checked for consistency C with the local operating system. C C***REFERENCES FOX P.A., HALL A.D., SCHRYER N.L.,*FRAMEWORK FOR A C PORTABLE LIBRARY*, ACM TRANSACTIONS ON MATHEMATICAL C SOFTWARE, VOL. 4, NO. 2, JUNE 1978, PP. 177-188. C***ROUTINES CALLED XERROR C***END PROLOGUE D1MACH C INTEGER SMALL(4) INTEGER LARGE(4) INTEGER RIGHT(4) INTEGER DIVER(4) INTEGER LOG10(4) C DOUBLE PRECISION DMACH(5) SAVE DMACH C C EQUIVALENCE (DMACH(1),SMALL(1)) C EQUIVALENCE (DMACH(2),LARGE(1)) C EQUIVALENCE (DMACH(3),RIGHT(1)) C EQUIVALENCE (DMACH(4),DIVER(1)) C EQUIVALENCE (DMACH(5),LOG10(1)) C C MACHINE CONSTANTS FOR THE IBM PC C ASSUMES THAT ALL ARITHMETIC IS DONE IN DOUBLE PRECISION C ON 8088, I.E., NOT IN 80 BIT FORM FOR THE 8087. C DATA DMACH(1) / 2.23D-308 / C DATA SMALL(1),SMALL(2) / 2002288515, 1050897 / DATA DMACH(2) / 1.79D-308 / C DATA LARGE(1),LARGE(2) / 1487780761, 2146426097 / DATA DMACH(3) / 1.11D-16 / C DATA RIGHT(1),RIGHT(2) / -1209488034, 1017118298 / DATA DMACH(4) / 2.22D-16 / C DATA DIVER(1),DIVER(2) / -1209488034, 1018166874 / DATA DMACH(5) / 0.3010299956639812 / C DATA LOG10(1),LOG10(2) / 1352628735, 1070810131 / C C C***FIRST EXECUTABLE STATEMENT D1MACH IF (I .LT. 1 .OR. I .GT. 5) 1 CALL XERROR ('D1MACH -- I OUT OF BOUNDS', 25, 1, 2) C D1MACH = DMACH(I) RETURN C END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/dgamln.f000066400000000000000000000206251450372207100251270ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION DGAMLN(Z,IERR) C***BEGIN PROLOGUE DGAMLN C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 830501 (YYMMDD) C***CATEGORY NO. B5F C***KEYWORDS GAMMA FUNCTION,LOGARITHM OF GAMMA FUNCTION C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE THE LOGARITHM OF THE GAMMA FUNCTION C***DESCRIPTION C C **** A DOUBLE PRECISION ROUTINE **** C DGAMLN COMPUTES THE NATURAL LOG OF THE GAMMA FUNCTION FOR C Z.GT.0. THE ASYMPTOTIC EXPANSION IS USED TO GENERATE VALUES C GREATER THAN ZMIN WHICH ARE ADJUSTED BY THE RECURSION C G(Z+1)=Z*G(Z) FOR Z.LE.ZMIN. THE FUNCTION WAS MADE AS C PORTABLE AS POSSIBLE BY COMPUTIMG ZMIN FROM THE NUMBER OF BASE C 10 DIGITS IN A WORD, RLN=AMAX1(-ALOG10(R1MACH(4)),0.5E-18) C LIMITED TO 18 DIGITS OF (RELATIVE) ACCURACY. C C SINCE INTEGER ARGUMENTS ARE COMMON, A TABLE LOOK UP ON 100 C VALUES IS USED FOR SPEED OF EXECUTION. C C DESCRIPTION OF ARGUMENTS C C INPUT Z IS D0UBLE PRECISION C Z - ARGUMENT, Z.GT.0.0D0 C C OUTPUT DGAMLN IS DOUBLE PRECISION C DGAMLN - NATURAL LOG OF THE GAMMA FUNCTION AT Z.NE.0.0D0 C IERR - ERROR FLAG C IERR=0, NORMAL RETURN, COMPUTATION COMPLETED C IERR=1, Z.LE.0.0D0, NO COMPUTATION C C C***REFERENCES COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C BY D. E. AMOS, SAND83-0083, MAY, 1983. C***ROUTINES CALLED I1MACH,D1MACH C***END PROLOGUE DGAMLN DOUBLE PRECISION CF, CON, FLN, FZ, GLN, RLN, S, TLG, TRM, TST, * T1, WDTOL, Z, ZDMY, ZINC, ZM, ZMIN, ZP, ZSQ, D1MACH INTEGER I, IERR, I1M, K, MZ, NZ, I1MACH DIMENSION CF(22), GLN(100) C LNGAMMA(N), N=1,100 DATA GLN(1), GLN(2), GLN(3), GLN(4), GLN(5), GLN(6), GLN(7), 1 GLN(8), GLN(9), GLN(10), GLN(11), GLN(12), GLN(13), GLN(14), 2 GLN(15), GLN(16), GLN(17), GLN(18), GLN(19), GLN(20), 3 GLN(21), GLN(22)/ 4 0.00000000000000000D+00, 0.00000000000000000D+00, 5 6.93147180559945309D-01, 1.79175946922805500D+00, 6 3.17805383034794562D+00, 4.78749174278204599D+00, 7 6.57925121201010100D+00, 8.52516136106541430D+00, 8 1.06046029027452502D+01, 1.28018274800814696D+01, 9 1.51044125730755153D+01, 1.75023078458738858D+01, A 1.99872144956618861D+01, 2.25521638531234229D+01, B 2.51912211827386815D+01, 2.78992713838408916D+01, C 3.06718601060806728D+01, 3.35050734501368889D+01, D 3.63954452080330536D+01, 3.93398841871994940D+01, E 4.23356164607534850D+01, 4.53801388984769080D+01/ DATA GLN(23), GLN(24), GLN(25), GLN(26), GLN(27), GLN(28), 1 GLN(29), GLN(30), GLN(31), GLN(32), GLN(33), GLN(34), 2 GLN(35), GLN(36), GLN(37), GLN(38), GLN(39), GLN(40), 3 GLN(41), GLN(42), GLN(43), GLN(44)/ 4 4.84711813518352239D+01, 5.16066755677643736D+01, 5 5.47847293981123192D+01, 5.80036052229805199D+01, 6 6.12617017610020020D+01, 6.45575386270063311D+01, 7 6.78897431371815350D+01, 7.12570389671680090D+01, 8 7.46582363488301644D+01, 7.80922235533153106D+01, 9 8.15579594561150372D+01, 8.50544670175815174D+01, A 8.85808275421976788D+01, 9.21361756036870925D+01, B 9.57196945421432025D+01, 9.93306124547874269D+01, C 1.02968198614513813D+02, 1.06631760260643459D+02, D 1.10320639714757395D+02, 1.14034211781461703D+02, E 1.17771881399745072D+02, 1.21533081515438634D+02/ DATA GLN(45), GLN(46), GLN(47), GLN(48), GLN(49), GLN(50), 1 GLN(51), GLN(52), GLN(53), GLN(54), GLN(55), GLN(56), 2 GLN(57), GLN(58), GLN(59), GLN(60), GLN(61), GLN(62), 3 GLN(63), GLN(64), GLN(65), GLN(66)/ 4 1.25317271149356895D+02, 1.29123933639127215D+02, 5 1.32952575035616310D+02, 1.36802722637326368D+02, 6 1.40673923648234259D+02, 1.44565743946344886D+02, 7 1.48477766951773032D+02, 1.52409592584497358D+02, 8 1.56360836303078785D+02, 1.60331128216630907D+02, 9 1.64320112263195181D+02, 1.68327445448427652D+02, A 1.72352797139162802D+02, 1.76395848406997352D+02, B 1.80456291417543771D+02, 1.84533828861449491D+02, C 1.88628173423671591D+02, 1.92739047287844902D+02, D 1.96866181672889994D+02, 2.01009316399281527D+02, E 2.05168199482641199D+02, 2.09342586752536836D+02/ DATA GLN(67), GLN(68), GLN(69), GLN(70), GLN(71), GLN(72), 1 GLN(73), GLN(74), GLN(75), GLN(76), GLN(77), GLN(78), 2 GLN(79), GLN(80), GLN(81), GLN(82), GLN(83), GLN(84), 3 GLN(85), GLN(86), GLN(87), GLN(88)/ 4 2.13532241494563261D+02, 2.17736934113954227D+02, 5 2.21956441819130334D+02, 2.26190548323727593D+02, 6 2.30439043565776952D+02, 2.34701723442818268D+02, 7 2.38978389561834323D+02, 2.43268849002982714D+02, 8 2.47572914096186884D+02, 2.51890402209723194D+02, 9 2.56221135550009525D+02, 2.60564940971863209D+02, A 2.64921649798552801D+02, 2.69291097651019823D+02, B 2.73673124285693704D+02, 2.78067573440366143D+02, C 2.82474292687630396D+02, 2.86893133295426994D+02, D 2.91323950094270308D+02, 2.95766601350760624D+02, E 3.00220948647014132D+02, 3.04686856765668715D+02/ DATA GLN(89), GLN(90), GLN(91), GLN(92), GLN(93), GLN(94), 1 GLN(95), GLN(96), GLN(97), GLN(98), GLN(99), GLN(100)/ 2 3.09164193580146922D+02, 3.13652829949879062D+02, 3 3.18152639620209327D+02, 3.22663499126726177D+02, 4 3.27185287703775217D+02, 3.31717887196928473D+02, 5 3.36261181979198477D+02, 3.40815058870799018D+02, 6 3.45379407062266854D+02, 3.49954118040770237D+02, 7 3.54539085519440809D+02, 3.59134205369575399D+02/ C COEFFICIENTS OF ASYMPTOTIC EXPANSION DATA CF(1), CF(2), CF(3), CF(4), CF(5), CF(6), CF(7), CF(8), 1 CF(9), CF(10), CF(11), CF(12), CF(13), CF(14), CF(15), 2 CF(16), CF(17), CF(18), CF(19), CF(20), CF(21), CF(22)/ 3 8.33333333333333333D-02, -2.77777777777777778D-03, 4 7.93650793650793651D-04, -5.95238095238095238D-04, 5 8.41750841750841751D-04, -1.91752691752691753D-03, 6 6.41025641025641026D-03, -2.95506535947712418D-02, 7 1.79644372368830573D-01, -1.39243221690590112D+00, 8 1.34028640441683920D+01, -1.56848284626002017D+02, 9 2.19310333333333333D+03, -3.61087712537249894D+04, A 6.91472268851313067D+05, -1.52382215394074162D+07, B 3.82900751391414141D+08, -1.08822660357843911D+10, C 3.47320283765002252D+11, -1.23696021422692745D+13, D 4.88788064793079335D+14, -2.13203339609193739D+16/ C C LN(2*PI) DATA CON / 1.83787706640934548D+00/ C C***FIRST EXECUTABLE STATEMENT DGAMLN IERR=0 IF (Z.LE.0.0D0) GO TO 70 IF (Z.GT.101.0D0) GO TO 10 NZ = INT(SNGL(Z)) FZ = Z - FLOAT(NZ) IF (FZ.GT.0.0D0) GO TO 10 IF (NZ.GT.100) GO TO 10 DGAMLN = GLN(NZ) RETURN 10 CONTINUE WDTOL = D1MACH(4) WDTOL = DMAX1(WDTOL,0.5D-18) I1M = I1MACH(14) RLN = D1MACH(5)*FLOAT(I1M) FLN = DMIN1(RLN,20.0D0) FLN = DMAX1(FLN,3.0D0) FLN = FLN - 3.0D0 ZM = 1.8000D0 + 0.3875D0*FLN MZ = INT(SNGL(ZM)) + 1 ZMIN = FLOAT(MZ) ZDMY = Z ZINC = 0.0D0 IF (Z.GE.ZMIN) GO TO 20 ZINC = ZMIN - FLOAT(NZ) ZDMY = Z + ZINC 20 CONTINUE ZP = 1.0D0/ZDMY T1 = CF(1)*ZP S = T1 IF (ZP.LT.WDTOL) GO TO 40 ZSQ = ZP*ZP TST = T1*WDTOL DO 30 K=2,22 ZP = ZP*ZSQ TRM = CF(K)*ZP IF (DABS(TRM).LT.TST) GO TO 40 S = S + TRM 30 CONTINUE 40 CONTINUE IF (ZINC.NE.0.0D0) GO TO 50 TLG = DLOG(Z) DGAMLN = Z*(TLG-1.0D0) + 0.5D0*(CON-TLG) + S RETURN 50 CONTINUE ZP = 1.0D0 NZ = INT(SNGL(ZINC)) DO 60 I=1,NZ ZP = ZP*(Z+FLOAT(I-1)) 60 CONTINUE TLG = DLOG(ZDMY) DGAMLN = ZDMY*(TLG-1.0D0) - DLOG(ZP) + 0.5D0*(CON-TLG) + S RETURN C C 70 CONTINUE IERR=1 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/fortran.go000066400000000000000000000266661450372207100255330ustar00rootroot00000000000000// Copyright ©2016 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:build fortran // +build fortran // Package amoslib is a wrapper around the Fortran amos library. // // See https://www.netlib.org/amos/. It is included in the Gonum repository // for testing purposes only. // // When using the amoslib package, the "fortran" build tag must be used. // The amoslib package depends on libm.so. package amoslib /* #cgo LDFLAGS: -lm double mzabs_(double * ar, double * ai); void zs1s2_(double * ZRR, double * ZRI, double * S1R, double * S1I, double * S2R, double * S2I, int* NZ, double *ASCLE, double * ALIM, int * IUF); void zacai_(double * ZR, double * ZI, double * FNU, int * KODE, int * N, int * MR, double * YR, double * YI, int * NZ, double * RL, double * tol, double * elim, double * alim); void zseri_(double * ZR, double * ZI, double * FNU, int * KODE, int * N, double * YR, double * YI, int * NZ, double * tol, double * elim, double * alim); void zmlri_(double * ZR, double * ZI, double * FNU, int * KODE, int * N, double * YR, double * YI, int * NZ, double * tol); void zbknu_(double * ZR, double * ZI, double * FNU, int * KODE, int * N, double * YR, double * YI, int * NZ, double * tol, double * elim, double * alim); void zasyi_(double * ZR, double * ZI, double * FNU, int * KODE, int * N, double * YR, double * YI, int * NZ,double * RL, double * tol, double * elim, double * alim); void zkscl_(double * ZRR, double * ZRI, double * FNU, int * N, double * YR, double * YI, int * NZ, double * RZR, double * RZI, double * ASCLE, double * tol, double * elim); void zuchk_(double * YR, double * YI, int * NZ, double * ASCLE, double * TOL); void zairy_(double * ZR, double * ZI, int * ID, int * KODE, double * AIR, double * AII, int * NZ, int * IERR); void zlog_(double * ar, double * ai, double * br, double * bi, int * ierr); void zexp_(double * ar, double * ai, double * br, double * bi); void zsqrt_(double * ar, double * ai, double * br, double * bi); void zdiv_(double * ar, double * ai, double * br, double * bi, double * cr, double * ci); void zmlt_(double * ar, double * ai, double * br, double * bi, double * cr, double * ci); double dgamln_(double *z, int * ierr); void zshch_(double * zr, double * zi, double * cshr, double * cshi, double * cchr, double * cchi); double mysqrt_(double * A); double myexp_(double * A); double mycos_(double * A); double mysin_(double * A); double mylog_(double * A); double mytan_(double * A); double myatan_(double * A); double myabs_(double * A); double mymin_(double * A, double * B); double mymax_(double * A, double * B); */ import "C" import "unsafe" func MinFort(a, b float64) float64 { ans := C.mymin_((*C.double)(&a), (*C.double)(&b)) return float64(ans) } func MaxFort(a, b float64) float64 { ans := C.mymax_((*C.double)(&a), (*C.double)(&b)) return float64(ans) } func AbsFort(a float64) float64 { ans := C.myabs_((*C.double)(&a)) return float64(ans) } func AtanFort(a float64) float64 { ans := C.myatan_((*C.double)(&a)) return float64(ans) } func TanFort(a float64) float64 { ans := C.mytan_((*C.double)(&a)) return float64(ans) } func LogFort(a float64) float64 { ans := C.mylog_((*C.double)(&a)) return float64(ans) } func SinFort(a float64) float64 { ans := C.mysin_((*C.double)(&a)) return float64(ans) } func CosFort(a float64) float64 { ans := C.mycos_((*C.double)(&a)) return float64(ans) } func ExpFort(a float64) float64 { ans := C.myexp_((*C.double)(&a)) return float64(ans) } func SqrtFort(a float64) float64 { ans := C.mysqrt_((*C.double)(&a)) return float64(ans) } func DgamlnFort(a float64) float64 { var ierr int pierr := (*C.int)(unsafe.Pointer(&ierr)) pa := (*C.double)(&a) ans := C.dgamln_(pa, pierr) return (float64)(ans) } func ZmltFort(a, b complex128) complex128 { ar := real(a) ai := imag(a) br := real(b) bi := imag(b) var cr, ci float64 C.zmlt_( (*C.double)(&ar), (*C.double)(&ai), (*C.double)(&br), (*C.double)(&bi), (*C.double)(&cr), (*C.double)(&ci), ) return complex(cr, ci) } func ZdivFort(a, b complex128) complex128 { ar := real(a) ai := imag(a) br := real(b) bi := imag(b) var cr, ci float64 C.zdiv_( (*C.double)(&ar), (*C.double)(&ai), (*C.double)(&br), (*C.double)(&bi), (*C.double)(&cr), (*C.double)(&ci), ) return complex(cr, ci) } func ZabsFort(a complex128) float64 { ar := real(a) ai := imag(a) return float64(C.mzabs_((*C.double)(&ar), (*C.double)(&ai))) } func ZsqrtFort(a complex128) (b complex128) { ar := real(a) ai := imag(a) var br, bi float64 par := (*C.double)(&ar) pai := (*C.double)(&ai) pbr := (*C.double)(&br) pbi := (*C.double)(&bi) C.zsqrt_(par, pai, pbr, pbi) return complex(br, bi) } func ZexpFort(a complex128) (b complex128) { ar := real(a) ai := imag(a) var br, bi float64 par := (*C.double)(&ar) pai := (*C.double)(&ai) pbr := (*C.double)(&br) pbi := (*C.double)(&bi) C.zexp_(par, pai, pbr, pbi) return complex(br, bi) } func ZlogFort(a complex128) (b complex128) { ar := real(a) ai := imag(a) var ierr int var br, bi float64 par := (*C.double)(&ar) pai := (*C.double)(&ai) pbr := (*C.double)(&br) pbi := (*C.double)(&bi) pierr := (*C.int)(unsafe.Pointer(&ierr)) C.zlog_(par, pai, pbr, pbi, pierr) return complex(br, bi) } func Zshch(ZR, ZI, CSHR, CSHI, CCHR, CCHI float64) (ZRout, ZIout, CSHRout, CSHIout, CCHRout, CCHIout float64) { pzr := (*C.double)(&ZR) pzi := (*C.double)(&ZI) pcshr := (*C.double)(&CSHR) pcshi := (*C.double)(&CSHI) pcchr := (*C.double)(&CCHR) pcchi := (*C.double)(&CCHI) C.zshch_(pzr, pzi, pcshr, pcshi, pcchr, pcchi) return ZR, ZI, CSHR, CSHI, CCHR, CCHI } func ZairyFort(ZR, ZI float64, ID, KODE int) (AIR, AII float64, NZ, IERR int) { pzr := (*C.double)(&ZR) pzi := (*C.double)(&ZI) pid := (*C.int)(unsafe.Pointer(&ID)) pkode := (*C.int)(unsafe.Pointer(&KODE)) pair := (*C.double)(&AIR) paii := (*C.double)(&AII) pnz := (*C.int)(unsafe.Pointer(&NZ)) pierr := (*C.int)(unsafe.Pointer(&IERR)) C.zairy_(pzr, pzi, pid, pkode, pair, paii, pnz, pierr) NZ = int(*pnz) IERR = int(*pierr) return AIR, AII, NZ, IERR } func ZksclFort(ZRR, ZRI, FNU float64, N int, YR, YI []float64, NZ int, RZR, RZI, ASCLE, TOL, ELIM float64) ( ZRout, ZIout, FNUout float64, Nout int, YRout, YIout []float64, NZout int, RZRout, RZIout, ASCLEout, TOLout, ELIMout float64) { pzrr := (*C.double)(&ZRR) pzri := (*C.double)(&ZRI) pfnu := (*C.double)(&FNU) pn := (*C.int)(unsafe.Pointer(&N)) pyr := (*C.double)(&YR[0]) pyi := (*C.double)(&YI[0]) pnz := (*C.int)(unsafe.Pointer(&NZ)) przr := (*C.double)(&RZR) przi := (*C.double)(&RZI) pascle := (*C.double)(&ASCLE) ptol := (*C.double)(&TOL) pelim := (*C.double)(&ELIM) C.zkscl_(pzrr, pzri, pfnu, pn, pyr, pyi, pnz, przr, przi, pascle, ptol, pelim) N = int(*pn) NZ = int(*pnz) return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } func ZbknuFort(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout, ELIMout, ALIMout float64) { pzr := (*C.double)(&ZR) pzi := (*C.double)(&ZI) pfnu := (*C.double)(&FNU) pkode := (*C.int)(unsafe.Pointer(&KODE)) pn := (*C.int)(unsafe.Pointer(&N)) pyr := (*C.double)(&YR[0]) pyi := (*C.double)(&YI[0]) pnz := (*C.int)(unsafe.Pointer(&NZ)) ptol := (*C.double)(&TOL) pelim := (*C.double)(&ELIM) palim := (*C.double)(&ALIM) C.zbknu_(pzr, pzi, pfnu, pkode, pn, pyr, pyi, pnz, ptol, pelim, palim) KODE = int(*pkode) N = int(*pn) NZ = int(*pnz) return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } func ZasyiFort(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, RL, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, RLout, TOLout, ELIMout, ALIMout float64) { pzr := (*C.double)(&ZR) pzi := (*C.double)(&ZI) pfnu := (*C.double)(&FNU) pkode := (*C.int)(unsafe.Pointer(&KODE)) pn := (*C.int)(unsafe.Pointer(&N)) pyr := (*C.double)(&YR[0]) pyi := (*C.double)(&YI[0]) pnz := (*C.int)(unsafe.Pointer(&NZ)) prl := (*C.double)(&RL) ptol := (*C.double)(&TOL) pelim := (*C.double)(&ELIM) palim := (*C.double)(&ALIM) C.zasyi_(pzr, pzi, pfnu, pkode, pn, pyr, pyi, pnz, prl, ptol, pelim, palim) KODE = int(*pkode) N = int(*pn) NZ = int(*pnz) return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } func ZuchkFort(YR, YI float64, NZ int, ASCLE, TOL float64) (YRout, YIout float64, NZout int, ASCLEout, TOLout float64) { pyr := (*C.double)(&YR) pyi := (*C.double)(&YI) pnz := (*C.int)(unsafe.Pointer(&NZ)) pascle := (*C.double)(&ASCLE) ptol := (*C.double)(&TOL) C.zuchk_(pyr, pyi, pnz, pascle, ptol) return YR, YI, NZ, ASCLE, TOL } func Zs1s2Fort(ZRR, ZRI, S1R, S1I, S2R, S2I float64, NZ int, ASCLE, ALIM float64, IUF int) ( ZRRout, ZRIout, S1Rout, S1Iout, S2Rout, S2Iout float64, NZout int, ASCLEout, ALIMout float64, IUFout int) { pzrr := (*C.double)(&ZRR) pzri := (*C.double)(&ZRI) ps1r := (*C.double)(&S1R) ps1i := (*C.double)(&S1I) ps2r := (*C.double)(&S2R) ps2i := (*C.double)(&S2I) pnz := (*C.int)(unsafe.Pointer(&NZ)) pascle := (*C.double)(&ASCLE) palim := (*C.double)(&ALIM) piuf := (*C.int)(unsafe.Pointer(&IUF)) C.zs1s2_(pzrr, pzri, ps1r, ps1i, ps2r, ps2i, pnz, pascle, palim, piuf) return ZRR, ZRI, S1R, S1I, S2R, S2I, NZ, ASCLE, ALIM, IUF } func ZacaiFort(ZR, ZI, FNU float64, KODE, MR, N int, YR, YI []float64, NZ int, RL, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, MRout, Nout int, YRout, YIout []float64, NZout int, RLout, TOLout, ELIMout, ALIMout float64) { pzr := (*C.double)(&ZR) pzi := (*C.double)(&ZI) pfnu := (*C.double)(&FNU) pkode := (*C.int)(unsafe.Pointer(&KODE)) pmr := (*C.int)(unsafe.Pointer(&MR)) pn := (*C.int)(unsafe.Pointer(&N)) pyr := (*C.double)(&YR[0]) pyi := (*C.double)(&YI[0]) pnz := (*C.int)(unsafe.Pointer(&NZ)) prl := (*C.double)(&RL) ptol := (*C.double)(&TOL) pelim := (*C.double)(&ELIM) palim := (*C.double)(&ALIM) C.zacai_(pzr, pzi, pfnu, pkode, pmr, pn, pyr, pyi, pnz, prl, ptol, pelim, palim) KODE = int(*pkode) MR = int(*pmr) N = int(*pn) NZ = int(*pnz) return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } func ZseriFort(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout, ELIMout, ALIMout float64) { pzr := (*C.double)(&ZR) pzi := (*C.double)(&ZI) pfnu := (*C.double)(&FNU) pkode := (*C.int)(unsafe.Pointer(&KODE)) pn := (*C.int)(unsafe.Pointer(&N)) pyr := (*C.double)(&YR[0]) pyi := (*C.double)(&YI[0]) pnz := (*C.int)(unsafe.Pointer(&NZ)) ptol := (*C.double)(&TOL) pelim := (*C.double)(&ELIM) palim := (*C.double)(&ALIM) C.zseri_(pzr, pzi, pfnu, pkode, pn, pyr, pyi, pnz, ptol, pelim, palim) KODE = int(*pkode) N = int(*pn) NZ = int(*pnz) return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } func ZmlriFort(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout float64) { pzr := (*C.double)(&ZR) pzi := (*C.double)(&ZI) pfnu := (*C.double)(&FNU) pkode := (*C.int)(unsafe.Pointer(&KODE)) pn := (*C.int)(unsafe.Pointer(&N)) pyr := (*C.double)(&YR[0]) pyi := (*C.double)(&YI[0]) pnz := (*C.int)(unsafe.Pointer(&NZ)) ptol := (*C.double)(&TOL) C.zmlri_(pzr, pzi, pfnu, pkode, pn, pyr, pyi, pnz, ptol) KODE = int(*pkode) N = int(*pn) NZ = int(*pnz) return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL } golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/i1mach.f000066400000000000000000000070431450372207100250260ustar00rootroot00000000000000*DECK I1MACH INTEGER FUNCTION I1MACH(I) C***BEGIN PROLOGUE I1MACH C***DATE WRITTEN 750101 (YYMMDD) C***REVISION DATE 890213 (YYMMDD) C***CATEGORY NO. R1 C***KEYWORDS LIBRARY=SLATEC,TYPE=INTEGER(I1MACH-I),MACHINE CONSTANTS C***AUTHOR FOX, P. A., (BELL LABS) C HALL, A. D., (BELL LABS) C SCHRYER, N. L., (BELL LABS) C***PURPOSE Returns integer machine dependent constants C***DESCRIPTION C C I1MACH can be used to obtain machine-dependent parameters C for the local machine environment. It is a function C subroutine with one (input) argument, and can be called C as follows, for example C C K = I1MACH(I) C C where I=1,...,16. The (output) value of K above is C determined by the (input) value of I. The results for C various values of I are discussed below. C C I/O unit numbers. C I1MACH( 1) = the standard input unit. C I1MACH( 2) = the standard output unit. C I1MACH( 3) = the standard punch unit. C I1MACH( 4) = the standard error message unit. C C Words. C I1MACH( 5) = the number of bits per integer storage unit. C I1MACH( 6) = the number of characters per integer storage unit. C C Integers. C assume integers are represented in the S-digit, base-A form C C sign ( X(S-1)*A**(S-1) + ... + X(1)*A + X(0) ) C C where 0 .LE. X(I) .LT. A for I=0,...,S-1. C I1MACH( 7) = A, the base. C I1MACH( 8) = S, the number of base-A digits. C I1MACH( 9) = A**S - 1, the largest magnitude. C C Floating-Point Numbers. C Assume floating-point numbers are represented in the T-digit, C base-B form C sign (B**E)*( (X(1)/B) + ... + (X(T)/B**T) ) C C where 0 .LE. X(I) .LT. B for I=1,...,T, C 0 .LT. X(1), and EMIN .LE. E .LE. EMAX. C I1MACH(10) = B, the base. C C Single-Precision C I1MACH(11) = T, the number of base-B digits. C I1MACH(12) = EMIN, the smallest exponent E. C I1MACH(13) = EMAX, the largest exponent E. C C Double-Precision C I1MACH(14) = T, the number of base-B digits. C I1MACH(15) = EMIN, the smallest exponent E. C I1MACH(16) = EMAX, the largest exponent E. C C To alter this function for a particular environment, C the desired set of DATA statements should be activated by C removing the C from column 1. Also, the values of C I1MACH(1) - I1MACH(4) should be checked for consistency C with the local operating system. C C***REFERENCES FOX P.A., HALL A.D., SCHRYER N.L.,*FRAMEWORK FOR A C PORTABLE LIBRARY*, ACM TRANSACTIONS ON MATHEMATICAL C SOFTWARE, VOL. 4, NO. 2, JUNE 1978, PP. 177-188. C***ROUTINES CALLED (NONE) C***END PROLOGUE I1MACH C INTEGER IMACH(16),OUTPUT SAVE IMACH EQUIVALENCE (IMACH(4),OUTPUT) C C MACHINE CONSTANTS FOR THE IBM PC C DATA IMACH( 1) / 5 / DATA IMACH( 2) / 6 / DATA IMACH( 3) / 0 / DATA IMACH( 4) / 0 / DATA IMACH( 5) / 32 / DATA IMACH( 6) / 4 / DATA IMACH( 7) / 2 / DATA IMACH( 8) / 31 / DATA IMACH( 9) / 2147483647 / DATA IMACH(10) / 2 / DATA IMACH(11) / 24 / DATA IMACH(12) / -125 / DATA IMACH(13) / 127 / DATA IMACH(14) / 53 / DATA IMACH(15) / -1021 / DATA IMACH(16) / 1023 / C C***FIRST EXECUTABLE STATEMENT I1MACH IF (I .LT. 1 .OR. I .GT. 16) GO TO 10 C I1MACH = IMACH(I) RETURN C 10 CONTINUE WRITE (UNIT = OUTPUT, FMT = 9000) 9000 FORMAT ('1ERROR 1 IN I1MACH - I OUT OF BOUNDS') C C CALL FDUMP C C STOP END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/myabs.f000066400000000000000000000001571450372207100247760ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYABS(A) DOUBLE PRECISION A MYABS = DABS(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/myatan.f000066400000000000000000000001621450372207100251500ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYATAN(A) DOUBLE PRECISION A MYATAN = DATAN(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/mycos.f000066400000000000000000000001571450372207100250150ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYCOS(A) DOUBLE PRECISION A MYCOS = DCOS(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/myexp.f000066400000000000000000000001571450372207100250250ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYEXP(A) DOUBLE PRECISION A MYEXP = DEXP(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/mylog.f000066400000000000000000000001571450372207100250120ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYLOG(A) DOUBLE PRECISION A MYLOG = DLOG(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/mymax.f000066400000000000000000000001701450372207100250110ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYMAX(A, B) DOUBLE PRECISION A, B MYMAX = DMAX1(A,B) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/mymin.f000066400000000000000000000001701450372207100250070ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYMIN(A, B) DOUBLE PRECISION A, B MYMIN = DMIN1(A,B) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/mysin.f000066400000000000000000000001571450372207100250220ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYSIN(A) DOUBLE PRECISION A MYSIN = DSIN(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/mysqrt.f000066400000000000000000000001611450372207100252150ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYSQRT(A) DOUBLE PRECISION A MYSQRT = SQRT(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/mytan.f000066400000000000000000000001571450372207100250130ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MYTAN(A) DOUBLE PRECISION A MYTAN = DTAN(A) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/xerror.f000066400000000000000000000010461450372207100252020ustar00rootroot00000000000000 SUBROUTINE XERROR(MESS,NMESS,L1,L2) C C THIS IS A DUMMY XERROR ROUTINE TO PRINT ERROR MESSAGES WITH NMESS C CHARACTERS. L1 AND L2 ARE DUMMY PARAMETERS TO MAKE THIS CALL C COMPATIBLE WITH THE SLATEC XERROR ROUTINE. THIS IS A FORTRAN 77 C ROUTINE. C CHARACTER*(*) MESS NN=NMESS/70 NR=NMESS-70*NN IF(NR.NE.0) NN=NN+1 K=1 PRINT 900 900 FORMAT(/) DO 10 I=1,NN KMIN=MIN0(K+69,NMESS) PRINT *, MESS(K:KMIN) K=K+70 10 CONTINUE PRINT 900 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zabs.f000066400000000000000000000016751450372207100246300ustar00rootroot00000000000000 DOUBLE PRECISION FUNCTION MZABS(ZR, ZI) C***BEGIN PROLOGUE ZABS C***REFER TO ZBESH,ZBESI,ZBESJ,ZBESK,ZBESY,ZAIRY,ZBIRY C C ZABS COMPUTES THE ABSOLUTE VALUE OR MAGNITUDE OF A DOUBLE C PRECISION COMPLEX VARIABLE CMPLX(ZR,ZI) C C***ROUTINES CALLED (NONE) C***END PROLOGUE ZABS DOUBLE PRECISION ZR, ZI, U, V, Q, S MZABS = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) RETURN END c U = DABS(ZR) c V = DABS(ZI) c S = U + V C----------------------------------------------------------------------- C S*1.0D0 MAKES AN UNNORMALIZED UNDERFLOW ON CDC MACHINES INTO A C TRUE FLOATING ZERO C----------------------------------------------------------------------- c S = S*1.0D+0 c IF (S.EQ.0.0D+0) GO TO 20 c IF (U.GT.V) GO TO 10 c Q = U/V c ZABS = V*DSQRT(1.D+0+Q*Q) c RETURN c 10 Q = V/U c ZABS = U*DSQRT(1.D+0+Q*Q) c RETURN c 20 ZABS = 0.0D+0 c RETURN c END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zacai.f000066400000000000000000000072071450372207100247550ustar00rootroot00000000000000 SUBROUTINE ZACAI(ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, * ELIM, ALIM) C***BEGIN PROLOGUE ZACAI C***REFER TO ZAIRY C C ZACAI APPLIES THE ANALYTIC CONTINUATION FORMULA C C K(FNU,ZN*EXP(MP))=K(FNU,ZN)*EXP(-MP*FNU) - MP*I(FNU,ZN) C MP=PI*MR*CMPLX(0.0,1.0) C C TO CONTINUE THE K FUNCTION FROM THE RIGHT HALF TO THE LEFT C HALF Z PLANE FOR USE WITH ZAIRY WHERE FNU=1/3 OR 2/3 AND N=1. C ZACAI IS THE SAME AS ZACON WITH THE PARTS FOR LARGER ORDERS AND C RECURRENCE REMOVED. A RECURSIVE CALL TO ZACON CAN RESULT IF ZACON C IS CALLED FROM ZAIRY. C C***ROUTINES CALLED ZASYI,ZBKNU,ZMLRI,ZSERI,ZS1S2,D1MACH,ZABS C***END PROLOGUE ZACAI C COMPLEX CSGN,CSPN,C1,C2,Y,Z,ZN,CY DOUBLE PRECISION ALIM, ARG, ASCLE, AZ, CSGNR, CSGNI, CSPNR, * CSPNI, C1R, C1I, C2R, C2I, CYR, CYI, DFNU, ELIM, FMR, FNU, PI, * RL, SGN, TOL, YY, YR, YI, ZR, ZI, ZNR, ZNI, D1MACH, ZABS INTEGER INU, IUF, KODE, MR, N, NN, NW, NZ DIMENSION YR(N), YI(N), CYR(2), CYI(2) DATA PI / 3.14159265358979324D0 / NZ = 0 ZNR = -ZR ZNI = -ZI AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) NN = N DFNU = FNU + DBLE(FLOAT(N-1)) IF (AZ.LE.2.0D0) GO TO 10 IF (AZ*AZ*0.25D0.GT.DFNU+1.0D0) GO TO 20 10 CONTINUE C----------------------------------------------------------------------- C POWER SERIES FOR THE I FUNCTION C----------------------------------------------------------------------- CALL ZSERI(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL, ELIM, ALIM) GO TO 40 20 CONTINUE IF (AZ.LT.RL) GO TO 30 C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR LARGE Z FOR THE I FUNCTION C----------------------------------------------------------------------- CALL ZASYI(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, RL, TOL, ELIM, * ALIM) IF (NW.LT.0) GO TO 80 GO TO 40 30 CONTINUE C----------------------------------------------------------------------- C MILLER ALGORITHM NORMALIZED BY THE SERIES FOR THE I FUNCTION C----------------------------------------------------------------------- CALL ZMLRI(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL) IF(NW.LT.0) GO TO 80 40 CONTINUE C----------------------------------------------------------------------- C ANALYTIC CONTINUATION TO THE LEFT HALF PLANE FOR THE K FUNCTION C----------------------------------------------------------------------- CALL ZBKNU(ZNR, ZNI, FNU, KODE, 1, CYR, CYI, NW, TOL, ELIM, ALIM) IF (NW.NE.0) GO TO 80 FMR = DBLE(FLOAT(MR)) SGN = -DSIGN(PI,FMR) CSGNR = 0.0D0 CSGNI = SGN IF (KODE.EQ.1) GO TO 50 YY = -ZNI CSGNR = -CSGNI*DSIN(YY) CSGNI = CSGNI*DCOS(YY) 50 CONTINUE C----------------------------------------------------------------------- C CALCULATE CSPN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE C WHEN FNU IS LARGE C----------------------------------------------------------------------- INU = INT(SNGL(FNU)) ARG = (FNU-DBLE(FLOAT(INU)))*SGN CSPNR = DCOS(ARG) CSPNI = DSIN(ARG) IF (MOD(INU,2).EQ.0) GO TO 60 CSPNR = -CSPNR CSPNI = -CSPNI 60 CONTINUE C1R = CYR(1) C1I = CYI(1) C2R = YR(1) C2I = YI(1) IF (KODE.EQ.1) GO TO 70 IUF = 0 ASCLE = 1.0D+3*D1MACH(1)/TOL CALL ZS1S2(ZNR, ZNI, C1R, C1I, C2R, C2I, NW, ASCLE, ALIM, IUF) NZ = NZ + NW 70 CONTINUE YR(1) = CSPNR*C1R - CSPNI*C1I + CSGNR*C2R - CSGNI*C2I YI(1) = CSPNR*C1I + CSPNI*C1R + CSGNR*C2I + CSGNI*C2R RETURN 80 CONTINUE NZ = -1 IF(NW.EQ.(-2)) NZ=-2 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zacon.f000066400000000000000000000136121450372207100247750ustar00rootroot00000000000000 SUBROUTINE ZACON(ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, FNUL, * TOL, ELIM, ALIM) C***BEGIN PROLOGUE ZACON C***REFER TO ZBESK,ZBESH C C ZACON APPLIES THE ANALYTIC CONTINUATION FORMULA C C K(FNU,ZN*EXP(MP))=K(FNU,ZN)*EXP(-MP*FNU) - MP*I(FNU,ZN) C MP=PI*MR*CMPLX(0.0,1.0) C C TO CONTINUE THE K FUNCTION FROM THE RIGHT HALF TO THE LEFT C HALF Z PLANE C C***ROUTINES CALLED ZBINU,ZBKNU,ZS1S2,D1MACH,ZABS,ZMLT C***END PROLOGUE ZACON C COMPLEX CK,CONE,CSCL,CSCR,CSGN,CSPN,CY,CZERO,C1,C2,RZ,SC1,SC2,ST, C *S1,S2,Y,Z,ZN DOUBLE PRECISION ALIM, ARG, ASCLE, AS2, AZN, BRY, BSCLE, CKI, * CKR, CONER, CPN, CSCL, CSCR, CSGNI, CSGNR, CSPNI, CSPNR, * CSR, CSRR, CSSR, CYI, CYR, C1I, C1M, C1R, C2I, C2R, ELIM, FMR, * FN, FNU, FNUL, PI, PTI, PTR, RAZN, RL, RZI, RZR, SC1I, SC1R, * SC2I, SC2R, SGN, SPN, STI, STR, S1I, S1R, S2I, S2R, TOL, YI, YR, * YY, ZEROR, ZI, ZNI, ZNR, ZR, D1MACH, ZABS INTEGER I, INU, IUF, KFLAG, KODE, MR, N, NN, NW, NZ DIMENSION YR(N), YI(N), CYR(2), CYI(2), CSSR(3), CSRR(3), BRY(3) DATA PI / 3.14159265358979324D0 / DATA ZEROR,CONER / 0.0D0,1.0D0 / NZ = 0 ZNR = -ZR ZNI = -ZI NN = N CALL ZBINU(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, RL, FNUL, TOL, * ELIM, ALIM) IF (NW.LT.0) GO TO 90 C----------------------------------------------------------------------- C ANALYTIC CONTINUATION TO THE LEFT HALF PLANE FOR THE K FUNCTION C----------------------------------------------------------------------- NN = MIN0(2,N) CALL ZBKNU(ZNR, ZNI, FNU, KODE, NN, CYR, CYI, NW, TOL, ELIM, ALIM) IF (NW.NE.0) GO TO 90 S1R = CYR(1) S1I = CYI(1) FMR = DBLE(FLOAT(MR)) SGN = -DSIGN(PI,FMR) CSGNR = ZEROR CSGNI = SGN IF (KODE.EQ.1) GO TO 10 YY = -ZNI CPN = DCOS(YY) SPN = DSIN(YY) CALL ZMLT(CSGNR, CSGNI, CPN, SPN, CSGNR, CSGNI) 10 CONTINUE C----------------------------------------------------------------------- C CALCULATE CSPN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE C WHEN FNU IS LARGE C----------------------------------------------------------------------- INU = INT(SNGL(FNU)) ARG = (FNU-DBLE(FLOAT(INU)))*SGN CPN = DCOS(ARG) SPN = DSIN(ARG) CSPNR = CPN CSPNI = SPN IF (MOD(INU,2).EQ.0) GO TO 20 CSPNR = -CSPNR CSPNI = -CSPNI 20 CONTINUE IUF = 0 C1R = S1R C1I = S1I C2R = YR(1) C2I = YI(1) ASCLE = 1.0D+3*D1MACH(1)/TOL IF (KODE.EQ.1) GO TO 30 CALL ZS1S2(ZNR, ZNI, C1R, C1I, C2R, C2I, NW, ASCLE, ALIM, IUF) NZ = NZ + NW SC1R = C1R SC1I = C1I 30 CONTINUE CALL ZMLT(CSPNR, CSPNI, C1R, C1I, STR, STI) CALL ZMLT(CSGNR, CSGNI, C2R, C2I, PTR, PTI) YR(1) = STR + PTR YI(1) = STI + PTI IF (N.EQ.1) RETURN CSPNR = -CSPNR CSPNI = -CSPNI S2R = CYR(2) S2I = CYI(2) C1R = S2R C1I = S2I C2R = YR(2) C2I = YI(2) IF (KODE.EQ.1) GO TO 40 CALL ZS1S2(ZNR, ZNI, C1R, C1I, C2R, C2I, NW, ASCLE, ALIM, IUF) NZ = NZ + NW SC2R = C1R SC2I = C1I 40 CONTINUE CALL ZMLT(CSPNR, CSPNI, C1R, C1I, STR, STI) CALL ZMLT(CSGNR, CSGNI, C2R, C2I, PTR, PTI) YR(2) = STR + PTR YI(2) = STI + PTI IF (N.EQ.2) RETURN CSPNR = -CSPNR CSPNI = -CSPNI AZN = ZABS(CMPLX(ZNR,ZNI,kind=KIND(1.0D0))) RAZN = 1.0D0/AZN STR = ZNR*RAZN STI = -ZNI*RAZN RZR = (STR+STR)*RAZN RZI = (STI+STI)*RAZN FN = FNU + 1.0D0 CKR = FN*RZR CKI = FN*RZI C----------------------------------------------------------------------- C SCALE NEAR EXPONENT EXTREMES DURING RECURRENCE ON K FUNCTIONS C----------------------------------------------------------------------- CSCL = 1.0D0/TOL CSCR = TOL CSSR(1) = CSCL CSSR(2) = CONER CSSR(3) = CSCR CSRR(1) = CSCR CSRR(2) = CONER CSRR(3) = CSCL BRY(1) = ASCLE BRY(2) = 1.0D0/ASCLE BRY(3) = D1MACH(2) AS2 = ZABS(CMPLX(S2R,S2I,kind=KIND(1.0D0))) KFLAG = 2 IF (AS2.GT.BRY(1)) GO TO 50 KFLAG = 1 GO TO 60 50 CONTINUE IF (AS2.LT.BRY(2)) GO TO 60 KFLAG = 3 60 CONTINUE BSCLE = BRY(KFLAG) S1R = S1R*CSSR(KFLAG) S1I = S1I*CSSR(KFLAG) S2R = S2R*CSSR(KFLAG) S2I = S2I*CSSR(KFLAG) CSR = CSRR(KFLAG) DO 80 I=3,N STR = S2R STI = S2I S2R = CKR*STR - CKI*STI + S1R S2I = CKR*STI + CKI*STR + S1I S1R = STR S1I = STI C1R = S2R*CSR C1I = S2I*CSR STR = C1R STI = C1I C2R = YR(I) C2I = YI(I) IF (KODE.EQ.1) GO TO 70 IF (IUF.LT.0) GO TO 70 CALL ZS1S2(ZNR, ZNI, C1R, C1I, C2R, C2I, NW, ASCLE, ALIM, IUF) NZ = NZ + NW SC1R = SC2R SC1I = SC2I SC2R = C1R SC2I = C1I IF (IUF.NE.3) GO TO 70 IUF = -4 S1R = SC1R*CSSR(KFLAG) S1I = SC1I*CSSR(KFLAG) S2R = SC2R*CSSR(KFLAG) S2I = SC2I*CSSR(KFLAG) STR = SC2R STI = SC2I 70 CONTINUE PTR = CSPNR*C1R - CSPNI*C1I PTI = CSPNR*C1I + CSPNI*C1R YR(I) = PTR + CSGNR*C2R - CSGNI*C2I YI(I) = PTI + CSGNR*C2I + CSGNI*C2R CKR = CKR + RZR CKI = CKI + RZI CSPNR = -CSPNR CSPNI = -CSPNI IF (KFLAG.GE.3) GO TO 80 PTR = DABS(C1R) PTI = DABS(C1I) C1M = DMAX1(PTR,PTI) IF (C1M.LE.BSCLE) GO TO 80 KFLAG = KFLAG + 1 BSCLE = BRY(KFLAG) S1R = S1R*CSR S1I = S1I*CSR S2R = STR S2I = STI S1R = S1R*CSSR(KFLAG) S1I = S1I*CSSR(KFLAG) S2R = S2R*CSSR(KFLAG) S2I = S2I*CSSR(KFLAG) CSR = CSRR(KFLAG) 80 CONTINUE RETURN 90 CONTINUE NZ = -1 IF(NW.EQ.(-2)) NZ=-2 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zairy.f000066400000000000000000000350531450372207100250240ustar00rootroot00000000000000 SUBROUTINE ZAIRY(ZR, ZI, ID, KODE, AIR, AII, NZ, IERR) C***BEGIN PROLOGUE ZAIRY C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS AIRY FUNCTION,BESSEL FUNCTIONS OF ORDER ONE THIRD C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE AIRY FUNCTIONS AI(Z) AND DAI(Z) FOR COMPLEX Z C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C ON KODE=1, ZAIRY COMPUTES THE COMPLEX AIRY FUNCTION AI(Z) OR C ITS DERIVATIVE DAI(Z)/DZ ON ID=0 OR ID=1 RESPECTIVELY. ON C KODE=2, A SCALING OPTION CEXP(ZTA)*AI(Z) OR CEXP(ZTA)* C DAI(Z)/DZ IS PROVIDED TO REMOVE THE EXPONENTIAL DECAY IN C -PI/3.LT.ARG(Z).LT.PI/3 AND THE EXPONENTIAL GROWTH IN C PI/3.LT.ABS(ARG(Z)).LT.PI WHERE ZTA=(2/3)*Z*CSQRT(Z). C C WHILE THE AIRY FUNCTIONS AI(Z) AND DAI(Z)/DZ ARE ANALYTIC IN C THE WHOLE Z PLANE, THE CORRESPONDING SCALED FUNCTIONS DEFINED C FOR KODE=2 HAVE A CUT ALONG THE NEGATIVE REAL AXIS. C DEFINTIONS AND NOTATION ARE FOUND IN THE NBS HANDBOOK OF C MATHEMATICAL FUNCTIONS (REF. 1). C C INPUT ZR,ZI ARE DOUBLE PRECISION C ZR,ZI - Z=CMPLX(ZR,ZI) C ID - ORDER OF DERIVATIVE, ID=0 OR ID=1 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION C KODE= 1 RETURNS C AI=AI(Z) ON ID=0 OR C AI=DAI(Z)/DZ ON ID=1 C = 2 RETURNS C AI=CEXP(ZTA)*AI(Z) ON ID=0 OR C AI=CEXP(ZTA)*DAI(Z)/DZ ON ID=1 WHERE C ZTA=(2/3)*Z*CSQRT(Z) C C OUTPUT AIR,AII ARE DOUBLE PRECISION C AIR,AII- COMPLEX ANSWER DEPENDING ON THE CHOICES FOR ID AND C KODE C NZ - UNDERFLOW INDICATOR C NZ= 0 , NORMAL RETURN C NZ= 1 , AI=CMPLX(0.0D0,0.0D0) DUE TO UNDERFLOW IN C -PI/3.LT.ARG(Z).LT.PI/3 ON KODE=1 C IERR - ERROR FLAG C IERR=0, NORMAL RETURN - COMPUTATION COMPLETED C IERR=1, INPUT ERROR - NO COMPUTATION C IERR=2, OVERFLOW - NO COMPUTATION, REAL(ZTA) C TOO LARGE ON KODE=1 C IERR=3, CABS(Z) LARGE - COMPUTATION COMPLETED C LOSSES OF SIGNIFCANCE BY ARGUMENT REDUCTION C PRODUCE LESS THAN HALF OF MACHINE ACCURACY C IERR=4, CABS(Z) TOO LARGE - NO COMPUTATION C COMPLETE LOSS OF ACCURACY BY ARGUMENT C REDUCTION C IERR=5, ERROR - NO COMPUTATION, C ALGORITHM TERMINATION CONDITION NOT MET C C***LONG DESCRIPTION C C AI AND DAI ARE COMPUTED FOR CABS(Z).GT.1.0 FROM THE K BESSEL C FUNCTIONS BY C C AI(Z)=C*SQRT(Z)*K(1/3,ZTA) , DAI(Z)=-C*Z*K(2/3,ZTA) C C=1.0/(PI*SQRT(3.0)) C ZTA=(2/3)*Z**(3/2) C C WITH THE POWER SERIES FOR CABS(Z).LE.1.0. C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z IS LARGE, LOSSES C OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. CONSEQUENTLY, IF C THE MAGNITUDE OF ZETA=(2/3)*Z**1.5 EXCEEDS U1=SQRT(0.5/UR), C THEN LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR C FLAG IERR=3 IS TRIGGERED WHERE UR=DMAX1(D1MACH(4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C ALSO, IF THE MAGNITUDE OF ZETA IS LARGER THAN U2=0.5/UR, THEN C ALL SIGNIFICANCE IS LOST AND IERR=4. IN ORDER TO USE THE INT C FUNCTION, ZETA MUST BE FURTHER RESTRICTED NOT TO EXCEED THE C LARGEST INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF ZETA C MUST BE RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, C AND U3 ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE C PRECISION ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE C PRECISION ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMIT- C ING IN THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT THE MAG- C NITUDE OF Z CANNOT EXCEED 3.1E+4 IN SINGLE AND 2.1E+6 IN C DOUBLE PRECISION ARITHMETIC. THIS ALSO MEANS THAT ONE CAN C EXPECT TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, C NO DIGITS IN SINGLE PRECISION AND ONLY 7 DIGITS IN DOUBLE C PRECISION ARITHMETIC. SIMILAR CONSIDERATIONS HOLD FOR OTHER C MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. IF ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 C C***ROUTINES CALLED ZACAI,ZBKNU,ZEXP,ZSQRT,I1MACH,D1MACH C***END PROLOGUE ZAIRY C COMPLEX AI,CONE,CSQ,CY,S1,S2,TRM1,TRM2,Z,ZTA,Z3 DOUBLE PRECISION AA, AD, AII, AIR, AK, ALIM, ATRM, AZ, AZ3, BK, * CC, CK, COEF, CONEI, CONER, CSQI, CSQR, CYI, CYR, C1, C2, DIG, * DK, D1, D2, ELIM, FID, FNU, PTR, RL, R1M5, SFAC, STI, STR, * S1I, S1R, S2I, S2R, TOL, TRM1I, TRM1R, TRM2I, TRM2R, TTH, ZEROI, * ZEROR, ZI, ZR, ZTAI, ZTAR, Z3I, Z3R, D1MACH, ZABS, ALAZ, BB INTEGER ID, IERR, IFLAG, K, KODE, K1, K2, MR, NN, NZ, I1MACH DIMENSION CYR(1), CYI(1) DATA TTH, C1, C2, COEF /6.66666666666666667D-01, * 3.55028053887817240D-01,2.58819403792806799D-01, * 1.83776298473930683D-01/ DATA ZEROR, ZEROI, CONER, CONEI /0.0D0,0.0D0,1.0D0,0.0D0/ C***FIRST EXECUTABLE STATEMENT ZAIRY IERR = 0 NZ=0 IF (ID.LT.0 .OR. ID.GT.1) IERR=1 IF (KODE.LT.1 .OR. KODE.GT.2) IERR=1 IF (IERR.NE.0) RETURN AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) TOL = DMAX1(D1MACH(4),1.0D-18) FID = DBLE(FLOAT(ID)) IF (AZ.GT.1.0D0) GO TO 70 C----------------------------------------------------------------------- C POWER SERIES FOR CABS(Z).LE.1. C----------------------------------------------------------------------- S1R = CONER S1I = CONEI S2R = CONER S2I = CONEI IF (AZ.LT.TOL) GO TO 170 AA = AZ*AZ IF (AA.LT.TOL/AZ) GO TO 40 TRM1R = CONER TRM1I = CONEI TRM2R = CONER TRM2I = CONEI ATRM = 1.0D0 STR = ZR*ZR - ZI*ZI STI = ZR*ZI + ZI*ZR Z3R = STR*ZR - STI*ZI Z3I = STR*ZI + STI*ZR AZ3 = AZ*AA AK = 2.0D0 + FID BK = 3.0D0 - FID - FID CK = 4.0D0 - FID DK = 3.0D0 + FID + FID D1 = AK*DK D2 = BK*CK AD = DMIN1(D1,D2) AK = 24.0D0 + 9.0D0*FID BK = 30.0D0 - 9.0D0*FID DO 30 K=1,25 STR = (TRM1R*Z3R-TRM1I*Z3I)/D1 TRM1I = (TRM1R*Z3I+TRM1I*Z3R)/D1 TRM1R = STR S1R = S1R + TRM1R S1I = S1I + TRM1I STR = (TRM2R*Z3R-TRM2I*Z3I)/D2 TRM2I = (TRM2R*Z3I+TRM2I*Z3R)/D2 TRM2R = STR S2R = S2R + TRM2R S2I = S2I + TRM2I ATRM = ATRM*AZ3/AD D1 = D1 + AK D2 = D2 + BK AD = DMIN1(D1,D2) IF (ATRM.LT.TOL*AD) GO TO 40 AK = AK + 18.0D0 BK = BK + 18.0D0 30 CONTINUE 40 CONTINUE IF (ID.EQ.1) THEN GO TO 50 END IF AIR = S1R*C1 - C2*(ZR*S2R-ZI*S2I) AII = S1I*C1 - C2*(ZR*S2I+ZI*S2R) IF (KODE.EQ.1) RETURN CALL ZSQRT(ZR, ZI, STR, STI) ZTAR = TTH*(ZR*STR-ZI*STI) ZTAI = TTH*(ZR*STI+ZI*STR) CALL ZEXP(ZTAR, ZTAI, STR, STI) PTR = AIR*STR - AII*STI AII = AIR*STI + AII*STR AIR = PTR RETURN 50 CONTINUE AIR = -S2R*C2 AII = -S2I*C2 IF (AZ.LE.TOL) GO TO 60 STR = ZR*S1R - ZI*S1I STI = ZR*S1I + ZI*S1R CC = C1/(1.0D0+FID) AIR = AIR + CC*(STR*ZR-STI*ZI) AII = AII + CC*(STR*ZI+STI*ZR) 60 CONTINUE IF (KODE.EQ.1) RETURN CALL ZSQRT(ZR, ZI, STR, STI) ZTAR = TTH*(ZR*STR-ZI*STI) ZTAI = TTH*(ZR*STI+ZI*STR) CALL ZEXP(ZTAR, ZTAI, STR, STI) PTR = STR*AIR - STI*AII AII = STR*AII + STI*AIR AIR = PTR RETURN C----------------------------------------------------------------------- C CASE FOR CABS(Z).GT.1.0 C----------------------------------------------------------------------- 70 CONTINUE FNU = (1.0D0+FID)/3.0D0 C----------------------------------------------------------------------- C SET PARAMETERS RELATED TO MACHINE CONSTANTS. C TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0D-18. C ELIM IS THE APPROXIMATE EXPONENTIAL OVER- AND UNDERFLOW LIMIT. C EXP(-ELIM).LT.EXP(-ALIM)=EXP(-ELIM)/TOL AND C EXP(ELIM).GT.EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR C UNDERFLOW AND OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. C RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LARGE Z. C DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). C----------------------------------------------------------------------- K1 = I1MACH(15) K2 = I1MACH(16) R1M5 = D1MACH(5) K = MIN0(IABS(K1),IABS(K2)) ELIM = 2.303D0*(DBLE(FLOAT(K))*R1M5-3.0D0) K1 = I1MACH(14) - 1 AA = R1M5*DBLE(FLOAT(K1)) DIG = DMIN1(AA,18.0D0) AA = AA*2.303D0 ALIM = ELIM + DMAX1(-AA,-41.45D0) RL = 1.2D0*DIG + 3.0D0 ALAZ = DLOG(AZ) C-------------------------------------------------------------------------- C TEST FOR PROPER RANGE C----------------------------------------------------------------------- AA=0.5D0/TOL BB=DBLE(FLOAT(I1MACH(9)))*0.5D0 AA=DMIN1(AA,BB) AA=AA**TTH IF (AZ.GT.AA) GO TO 260 AA=DSQRT(AA) IF (AZ.GT.AA) IERR=3 CALL ZSQRT(ZR, ZI, CSQR, CSQI) ZTAR = TTH*(ZR*CSQR-ZI*CSQI) ZTAI = TTH*(ZR*CSQI+ZI*CSQR) C----------------------------------------------------------------------- C RE(ZTA).LE.0 WHEN RE(Z).LT.0, ESPECIALLY WHEN IM(Z) IS SMALL C----------------------------------------------------------------------- IFLAG = 0 SFAC = 1.0D0 AK = ZTAI IF (ZR.GE.0.0D0) GO TO 80 BK = ZTAR CK = -DABS(BK) ZTAR = CK ZTAI = AK 80 CONTINUE IF (ZI.NE.0.0D0) GO TO 90 IF (ZR.GT.0.0D0) GO TO 90 ZTAR = 0.0D0 ZTAI = AK 90 CONTINUE AA = ZTAR IF (AA.GE.0.0D0 .AND. ZR.GT.0.0D0) GO TO 110 IF (KODE.EQ.2) GO TO 100 C----------------------------------------------------------------------- C OVERFLOW TEST C----------------------------------------------------------------------- IF (AA.GT.(-ALIM)) GO TO 100 AA = -AA + 0.25D0*ALAZ IFLAG = 1 SFAC = TOL IF (AA.GT.ELIM) GO TO 270 100 CONTINUE C----------------------------------------------------------------------- C CBKNU AND CACON RETURN EXP(ZTA)*K(FNU,ZTA) ON KODE=2 C----------------------------------------------------------------------- MR = 1 IF (ZI.LT.0.0D0) MR = -1 CALL ZACAI(ZTAR, ZTAI, FNU, KODE, MR, 1, CYR, CYI, NN, RL, TOL, * ELIM, ALIM) IF (NN.LT.0) GO TO 280 NZ = NZ + NN GO TO 130 110 CONTINUE IF (KODE.EQ.2) GO TO 120 C----------------------------------------------------------------------- C UNDERFLOW TEST C----------------------------------------------------------------------- IF (AA.LT.ALIM) GO TO 120 AA = -AA - 0.25D0*ALAZ IFLAG = 2 SFAC = 1.0D0/TOL IF (AA.LT.(-ELIM)) GO TO 210 120 CONTINUE CALL ZBKNU(ZTAR, ZTAI, FNU, KODE, 1, CYR, CYI, NZ, TOL, ELIM, * ALIM) 130 CONTINUE S1R = CYR(1)*COEF S1I = CYI(1)*COEF IF (IFLAG.NE.0) GO TO 150 IF (ID.EQ.1) GO TO 140 AIR = CSQR*S1R - CSQI*S1I AII = CSQR*S1I + CSQI*S1R RETURN 140 CONTINUE AIR = -(ZR*S1R-ZI*S1I) AII = -(ZR*S1I+ZI*S1R) RETURN 150 CONTINUE S1R = S1R*SFAC S1I = S1I*SFAC IF (ID.EQ.1) GO TO 160 STR = S1R*CSQR - S1I*CSQI S1I = S1R*CSQI + S1I*CSQR S1R = STR AIR = S1R/SFAC AII = S1I/SFAC RETURN 160 CONTINUE STR = -(S1R*ZR-S1I*ZI) S1I = -(S1R*ZI+S1I*ZR) S1R = STR AIR = S1R/SFAC AII = S1I/SFAC RETURN 170 CONTINUE AA = 1.0D+3*D1MACH(1) S1R = ZEROR S1I = ZEROI IF (ID.EQ.1) GO TO 190 IF (AZ.LE.AA) GO TO 180 S1R = C2*ZR S1I = C2*ZI 180 CONTINUE AIR = C1 - S1R AII = -S1I RETURN 190 CONTINUE AIR = -C2 AII = 0.0D0 AA = DSQRT(AA) IF (AZ.LE.AA) GO TO 200 S1R = 0.5D0*(ZR*ZR-ZI*ZI) S1I = ZR*ZI 200 CONTINUE AIR = AIR + C1*S1R AII = AII + C1*S1I RETURN 210 CONTINUE NZ = 1 AIR = ZEROR AII = ZEROI RETURN 270 CONTINUE NZ = 0 IERR=2 RETURN 280 CONTINUE IF(NN.EQ.(-1)) GO TO 270 NZ=0 IERR=5 RETURN 260 CONTINUE IERR=4 NZ=0 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zasyi.f000066400000000000000000000117761450372207100250330ustar00rootroot00000000000000 SUBROUTINE ZASYI(ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, * ALIM) C***BEGIN PROLOGUE ZASYI C***REFER TO ZBESI,ZBESK C C ZASYI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z).GE.0.0 BY C MEANS OF THE ASYMPTOTIC EXPANSION FOR LARGE CABS(Z) IN THE C REGION CABS(Z).GT.MAX(RL,FNU*FNU/2). NZ=0 IS A NORMAL RETURN. C NZ.LT.0 INDICATES AN OVERFLOW ON KODE=1. C C***ROUTINES CALLED D1MACH,ZABS,ZDIV,ZEXP,ZMLT,ZSQRT C***END PROLOGUE ZASYI C COMPLEX AK1,CK,CONE,CS1,CS2,CZ,CZERO,DK,EZ,P1,RZ,S2,Y,Z DOUBLE PRECISION AA, AEZ, AK, AK1I, AK1R, ALIM, ARG, ARM, ATOL, * AZ, BB, BK, CKI, CKR, CONEI, CONER, CS1I, CS1R, CS2I, CS2R, CZI, * CZR, DFNU, DKI, DKR, DNU2, ELIM, EZI, EZR, FDN, FNU, PI, P1I, * P1R, RAZ, RL, RTPI, RTR1, RZI, RZR, S, SGN, SQK, STI, STR, S2I, * S2R, TOL, TZI, TZR, YI, YR, ZEROI, ZEROR, ZI, ZR, D1MACH, ZABS INTEGER I, IB, IL, INU, J, JL, K, KODE, KODED, M, N, NN, NZ DIMENSION YR(N), YI(N) DATA PI, RTPI /3.14159265358979324D0 , 0.159154943091895336D0 / DATA ZEROR,ZEROI,CONER,CONEI / 0.0D0, 0.0D0, 1.0D0, 0.0D0 / C NZ = 0 AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) ARM = 1.0D+3*D1MACH(1) RTR1 = DSQRT(ARM) IL = MIN0(2,N) DFNU = FNU + DBLE(FLOAT(N-IL)) C----------------------------------------------------------------------- C OVERFLOW TEST C----------------------------------------------------------------------- RAZ = 1.0D0/AZ STR = ZR*RAZ STI = -ZI*RAZ AK1R = RTPI*STR*RAZ AK1I = RTPI*STI*RAZ CALL ZSQRT(AK1R, AK1I, AK1R, AK1I) CZR = ZR CZI = ZI IF (KODE.NE.2) GO TO 10 CZR = ZEROR CZI = ZI 10 CONTINUE IF (DABS(CZR).GT.ELIM) GO TO 100 DNU2 = DFNU + DFNU KODED = 1 IF ((DABS(CZR).GT.ALIM) .AND. (N.GT.2)) GO TO 20 KODED = 0 CALL ZEXP(CZR, CZI, STR, STI) CALL ZMLT(AK1R, AK1I, STR, STI, AK1R, AK1I) 20 CONTINUE FDN = 0.0D0 IF (DNU2.GT.RTR1) THEN FDN = DNU2*DNU2 END IF EZR = ZR*8.0D0 EZI = ZI*8.0D0 C----------------------------------------------------------------------- C WHEN Z IS IMAGINARY, THE ERROR TEST MUST BE MADE RELATIVE TO THE C FIRST RECIPROCAL POWER SINCE THIS IS THE LEADING TERM OF THE C EXPANSION FOR THE IMAGINARY PART. C----------------------------------------------------------------------- AEZ = 8.0D0*AZ S = TOL/AEZ JL = INT(SNGL(RL+RL)) + 2 P1R = ZEROR P1I = ZEROI IF (ZI.EQ.0.0D0) GO TO 30 C----------------------------------------------------------------------- C CALCULATE EXP(PI*(0.5+FNU+N-IL)*I) TO MINIMIZE LOSSES OF C SIGNIFICANCE WHEN FNU OR N IS LARGE C----------------------------------------------------------------------- INU = INT(SNGL(FNU)) ARG = (FNU-DBLE(FLOAT(INU)))*PI INU = INU + N - IL AK = -DSIN(ARG) BK = DCOS(ARG) IF (ZI.LT.0.0D0) BK = -BK P1R = AK P1I = BK IF (MOD(INU,2).EQ.0) GO TO 30 P1R = -P1R P1I = -P1I 30 CONTINUE DO 70 K=1,IL SQK = FDN - 1.0D0 ATOL = S*DABS(SQK) SGN = 1.0D0 CS1R = CONER CS1I = CONEI CS2R = CONER CS2I = CONEI CKR = CONER CKI = CONEI AK = 0.0D0 AA = 1.0D0 BB = AEZ DKR = EZR DKI = EZI DO 40 J=1,JL CALL ZDIV(CKR, CKI, DKR, DKI, STR, STI) CKR = STR*SQK CKI = STI*SQK CS2R = CS2R + CKR CS2I = CS2I + CKI SGN = -SGN CS1R = CS1R + CKR*SGN CS1I = CS1I + CKI*SGN DKR = DKR + EZR DKI = DKI + EZI AA = AA*DABS(SQK)/BB BB = BB + AEZ AK = AK + 8.0D0 SQK = SQK - AK IF (AA.LE.ATOL) THEN GO TO 50 END IF 40 CONTINUE GO TO 110 50 CONTINUE S2R = CS1R S2I = CS1I IF (ZR+ZR.GE.ELIM) GO TO 60 TZR = ZR + ZR TZI = ZI + ZI CALL ZEXP(-TZR, -TZI, STR, STI) CALL ZMLT(STR, STI, P1R, P1I, STR, STI) CALL ZMLT(STR, STI, CS2R, CS2I, STR, STI) S2R = S2R + STR S2I = S2I + STI 60 CONTINUE FDN = FDN + 8.0D0*DFNU + 4.0D0 P1R = -P1R P1I = -P1I M = N - IL + K YR(M) = S2R*AK1R - S2I*AK1I YI(M) = S2R*AK1I + S2I*AK1R 70 CONTINUE IF (N.LE.2) RETURN NN = N K = NN - 2 AK = DBLE(FLOAT(K)) STR = ZR*RAZ STI = -ZI*RAZ RZR = (STR+STR)*RAZ RZI = (STI+STI)*RAZ IB = 3 DO 80 I=IB,NN YR(K) = (AK+FNU)*(RZR*YR(K+1)-RZI*YI(K+1)) + YR(K+2) YI(K) = (AK+FNU)*(RZR*YI(K+1)+RZI*YR(K+1)) + YI(K+2) AK = AK - 1.0D0 K = K - 1 80 CONTINUE IF (KODED.EQ.0) RETURN CALL ZEXP(CZR, CZI, CKR, CKI) DO 90 I=1,NN STR = YR(I)*CKR - YI(I)*CKI YI(I) = YR(I)*CKI + YI(I)*CKR YR(I) = STR 90 CONTINUE RETURN 100 CONTINUE NZ = -1 RETURN 110 CONTINUE NZ=-2 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbesh.f000066400000000000000000000346051450372207100250030ustar00rootroot00000000000000 SUBROUTINE ZBESH(ZR, ZI, FNU, KODE, M, N, CYR, CYI, NZ, IERR) C***BEGIN PROLOGUE ZBESH C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS H-BESSEL FUNCTIONS,BESSEL FUNCTIONS OF COMPLEX ARGUMENT, C BESSEL FUNCTIONS OF THIRD KIND,HANKEL FUNCTIONS C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE THE H-BESSEL FUNCTIONS OF A COMPLEX ARGUMENT C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C ON KODE=1, ZBESH COMPUTES AN N MEMBER SEQUENCE OF COMPLEX C HANKEL (BESSEL) FUNCTIONS CY(J)=H(M,FNU+J-1,Z) FOR KINDS M=1 C OR 2, REAL, NONNEGATIVE ORDERS FNU+J-1, J=1,...,N, AND COMPLEX C Z.NE.CMPLX(0.0,0.0) IN THE CUT PLANE -PI.LT.ARG(Z).LE.PI. C ON KODE=2, ZBESH RETURNS THE SCALED HANKEL FUNCTIONS C C CY(I)=EXP(-MM*Z*I)*H(M,FNU+J-1,Z) MM=3-2*M, I**2=-1. C C WHICH REMOVES THE EXPONENTIAL BEHAVIOR IN BOTH THE UPPER AND C LOWER HALF PLANES. DEFINITIONS AND NOTATION ARE FOUND IN THE C NBS HANDBOOK OF MATHEMATICAL FUNCTIONS (REF. 1). C C INPUT ZR,ZI,FNU ARE DOUBLE PRECISION C ZR,ZI - Z=CMPLX(ZR,ZI), Z.NE.CMPLX(0.0D0,0.0D0), C -PT.LT.ARG(Z).LE.PI C FNU - ORDER OF INITIAL H FUNCTION, FNU.GE.0.0D0 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION C KODE= 1 RETURNS C CY(J)=H(M,FNU+J-1,Z), J=1,...,N C = 2 RETURNS C CY(J)=H(M,FNU+J-1,Z)*EXP(-I*Z*(3-2M)) C J=1,...,N , I**2=-1 C M - KIND OF HANKEL FUNCTION, M=1 OR 2 C N - NUMBER OF MEMBERS IN THE SEQUENCE, N.GE.1 C C OUTPUT CYR,CYI ARE DOUBLE PRECISION C CYR,CYI- DOUBLE PRECISION VECTORS WHOSE FIRST N COMPONENTS C CONTAIN REAL AND IMAGINARY PARTS FOR THE SEQUENCE C CY(J)=H(M,FNU+J-1,Z) OR C CY(J)=H(M,FNU+J-1,Z)*EXP(-I*Z*(3-2M)) J=1,...,N C DEPENDING ON KODE, I**2=-1. C NZ - NUMBER OF COMPONENTS SET TO ZERO DUE TO UNDERFLOW, C NZ= 0 , NORMAL RETURN C NZ.GT.0 , FIRST NZ COMPONENTS OF CY SET TO ZERO DUE C TO UNDERFLOW, CY(J)=CMPLX(0.0D0,0.0D0) C J=1,...,NZ WHEN Y.GT.0.0 AND M=1 OR C Y.LT.0.0 AND M=2. FOR THE COMPLMENTARY C HALF PLANES, NZ STATES ONLY THE NUMBER C OF UNDERFLOWS. C IERR - ERROR FLAG C IERR=0, NORMAL RETURN - COMPUTATION COMPLETED C IERR=1, INPUT ERROR - NO COMPUTATION C IERR=2, OVERFLOW - NO COMPUTATION, FNU TOO C LARGE OR CABS(Z) TOO SMALL OR BOTH C IERR=3, CABS(Z) OR FNU+N-1 LARGE - COMPUTATION DONE C BUT LOSSES OF SIGNIFCANCE BY ARGUMENT C REDUCTION PRODUCE LESS THAN HALF OF MACHINE C ACCURACY C IERR=4, CABS(Z) OR FNU+N-1 TOO LARGE - NO COMPUTA- C TION BECAUSE OF COMPLETE LOSSES OF SIGNIFI- C CANCE BY ARGUMENT REDUCTION C IERR=5, ERROR - NO COMPUTATION, C ALGORITHM TERMINATION CONDITION NOT MET C C***LONG DESCRIPTION C C THE COMPUTATION IS CARRIED OUT BY THE RELATION C C H(M,FNU,Z)=(1/MP)*EXP(-MP*FNU)*K(FNU,Z*EXP(-MP)) C MP=MM*HPI*I, MM=3-2*M, HPI=PI/2, I**2=-1 C C FOR M=1 OR 2 WHERE THE K BESSEL FUNCTION IS COMPUTED FOR THE C RIGHT HALF PLANE RE(Z).GE.0.0. THE K FUNCTION IS CONTINUED C TO THE LEFT HALF PLANE BY THE RELATION C C K(FNU,Z*EXP(MP)) = EXP(-MP*FNU)*K(FNU,Z)-MP*I(FNU,Z) C MP=MR*PI*I, MR=+1 OR -1, RE(Z).GT.0, I**2=-1 C C WHERE I(FNU,Z) IS THE I BESSEL FUNCTION. C C EXPONENTIAL DECAY OF H(M,FNU,Z) OCCURS IN THE UPPER HALF Z C PLANE FOR M=1 AND THE LOWER HALF Z PLANE FOR M=2. EXPONENTIAL C GROWTH OCCURS IN THE COMPLEMENTARY HALF PLANES. SCALING C BY EXP(-MM*Z*I) REMOVES THE EXPONENTIAL BEHAVIOR IN THE C WHOLE Z PLANE FOR Z TO INFINITY. C C FOR NEGATIVE ORDERS,THE FORMULAE C C H(1,-FNU,Z) = H(1,FNU,Z)*CEXP( PI*FNU*I) C H(2,-FNU,Z) = H(2,FNU,Z)*CEXP(-PI*FNU*I) C I**2=-1 C C CAN BE USED. C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z OR FNU+N-1 IS C LARGE, LOSSES OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. C CONSEQUENTLY, IF EITHER ONE EXCEEDS U1=SQRT(0.5/UR), THEN C LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR FLAG C IERR=3 IS TRIGGERED WHERE UR=DMAX1(D1MACH(4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C IF EITHER IS LARGER THAN U2=0.5/UR, THEN ALL SIGNIFICANCE IS C LOST AND IERR=4. IN ORDER TO USE THE INT FUNCTION, ARGUMENTS C MUST BE FURTHER RESTRICTED NOT TO EXCEED THE LARGEST MACHINE C INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF Z AND FNU+N-1 IS C RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, AND U3 C ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE PRECISION C ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE PRECISION C ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMITING IN C THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT ONE CAN EXPECT C TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, NO DIGITS C IN SINGLE AND ONLY 7 DIGITS IN DOUBLE PRECISION ARITHMETIC. C SIMILAR CONSIDERATIONS HOLD FOR OTHER MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0D-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. IF ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C BY D. E. AMOS, SAND83-0083, MAY, 1983. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 C C***ROUTINES CALLED ZACON,ZBKNU,ZBUNK,ZUOIK,ZABS,I1MACH,D1MACH C***END PROLOGUE ZBESH C C COMPLEX CY,Z,ZN,ZT,CSGN DOUBLE PRECISION AA, ALIM, ALN, ARG, AZ, CYI, CYR, DIG, ELIM, * FMM, FN, FNU, FNUL, HPI, RHPI, RL, R1M5, SGN, STR, TOL, UFL, ZI, * ZNI, ZNR, ZR, ZTI, D1MACH, ZABS, BB, ASCLE, RTOL, ATOL, STI, * CSGNR, CSGNI INTEGER I, IERR, INU, INUH, IR, K, KODE, K1, K2, M, * MM, MR, N, NN, NUF, NW, NZ, I1MACH DIMENSION CYR(N), CYI(N) C DATA HPI /1.57079632679489662D0/ C C***FIRST EXECUTABLE STATEMENT ZBESH IERR = 0 NZ=0 IF (ZR.EQ.0.0D0 .AND. ZI.EQ.0.0D0) IERR=1 IF (FNU.LT.0.0D0) IERR=1 IF (M.LT.1 .OR. M.GT.2) IERR=1 IF (KODE.LT.1 .OR. KODE.GT.2) IERR=1 IF (N.LT.1) IERR=1 IF (IERR.NE.0) RETURN NN = N C----------------------------------------------------------------------- C SET PARAMETERS RELATED TO MACHINE CONSTANTS. C TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0E-18. C ELIM IS THE APPROXIMATE EXPONENTIAL OVER- AND UNDERFLOW LIMIT. C EXP(-ELIM).LT.EXP(-ALIM)=EXP(-ELIM)/TOL AND C EXP(ELIM).GT.EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR C UNDERFLOW AND OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. C RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LARGE Z. C DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). C FNUL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC SERIES FOR LARGE FNU C----------------------------------------------------------------------- TOL = DMAX1(D1MACH(4),1.0D-18) K1 = I1MACH(15) K2 = I1MACH(16) R1M5 = D1MACH(5) K = MIN0(IABS(K1),IABS(K2)) ELIM = 2.303D0*(DBLE(FLOAT(K))*R1M5-3.0D0) K1 = I1MACH(14) - 1 AA = R1M5*DBLE(FLOAT(K1)) DIG = DMIN1(AA,18.0D0) AA = AA*2.303D0 ALIM = ELIM + DMAX1(-AA,-41.45D0) FNUL = 10.0D0 + 6.0D0*(DIG-3.0D0) RL = 1.2D0*DIG + 3.0D0 FN = FNU + DBLE(FLOAT(NN-1)) MM = 3 - M - M FMM = DBLE(FLOAT(MM)) ZNR = FMM*ZI ZNI = -FMM*ZR C----------------------------------------------------------------------- C TEST FOR PROPER RANGE C----------------------------------------------------------------------- AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) AA = 0.5D0/TOL BB=DBLE(FLOAT(I1MACH(9)))*0.5D0 AA = DMIN1(AA,BB) IF (AZ.GT.AA) GO TO 260 IF (FN.GT.AA) GO TO 260 AA = DSQRT(AA) IF (AZ.GT.AA) IERR=3 IF (FN.GT.AA) IERR=3 C----------------------------------------------------------------------- C OVERFLOW TEST ON THE LAST MEMBER OF THE SEQUENCE C----------------------------------------------------------------------- UFL = D1MACH(1)*1.0D+3 IF (AZ.LT.UFL) GO TO 230 IF (FNU.GT.FNUL) GO TO 90 IF (FN.LE.1.0D0) GO TO 70 IF (FN.GT.2.0D0) GO TO 60 IF (AZ.GT.TOL) GO TO 70 ARG = 0.5D0*AZ ALN = -FN*DLOG(ARG) IF (ALN.GT.ELIM) GO TO 230 GO TO 70 60 CONTINUE CALL ZUOIK(ZNR, ZNI, FNU, KODE, 2, NN, CYR, CYI, NUF, TOL, ELIM, * ALIM) IF (NUF.LT.0) GO TO 230 NZ = NZ + NUF NN = NN - NUF C----------------------------------------------------------------------- C HERE NN=N OR NN=0 SINCE NUF=0,NN, OR -1 ON RETURN FROM CUOIK C IF NUF=NN, THEN CY(I)=CZERO FOR ALL I C----------------------------------------------------------------------- IF (NN.EQ.0) GO TO 140 70 CONTINUE IF ((ZNR.LT.0.0D0) .OR. (ZNR.EQ.0.0D0 .AND. ZNI.LT.0.0D0 .AND. * M.EQ.2)) GO TO 80 C----------------------------------------------------------------------- C RIGHT HALF PLANE COMPUTATION, XN.GE.0. .AND. (XN.NE.0. .OR. C YN.GE.0. .OR. M=1) C----------------------------------------------------------------------- CALL ZBKNU(ZNR, ZNI, FNU, KODE, NN, CYR, CYI, NZ, TOL, ELIM, ALIM) GO TO 110 C----------------------------------------------------------------------- C LEFT HALF PLANE COMPUTATION C----------------------------------------------------------------------- 80 CONTINUE MR = -MM CALL ZACON(ZNR, ZNI, FNU, KODE, MR, NN, CYR, CYI, NW, RL, FNUL, * TOL, ELIM, ALIM) IF (NW.LT.0) GO TO 240 NZ=NW GO TO 110 90 CONTINUE C----------------------------------------------------------------------- C UNIFORM ASYMPTOTIC EXPANSIONS FOR FNU.GT.FNUL C----------------------------------------------------------------------- MR = 0 IF ((ZNR.GE.0.0D0) .AND. (ZNR.NE.0.0D0 .OR. ZNI.GE.0.0D0 .OR. * M.NE.2)) GO TO 100 MR = -MM IF (ZNR.NE.0.0D0 .OR. ZNI.GE.0.0D0) GO TO 100 ZNR = -ZNR ZNI = -ZNI 100 CONTINUE CALL ZBUNK(ZNR, ZNI, FNU, KODE, MR, NN, CYR, CYI, NW, TOL, ELIM, * ALIM) IF (NW.LT.0) GO TO 240 NZ = NZ + NW 110 CONTINUE C----------------------------------------------------------------------- C H(M,FNU,Z) = -FMM*(I/HPI)*(ZT**FNU)*K(FNU,-Z*ZT) C C ZT=EXP(-FMM*HPI*I) = CMPLX(0.0,-FMM), FMM=3-2*M, M=1,2 C----------------------------------------------------------------------- SGN = DSIGN(HPI,-FMM) C----------------------------------------------------------------------- C CALCULATE EXP(FNU*HPI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE C WHEN FNU IS LARGE C----------------------------------------------------------------------- INU = INT(SNGL(FNU)) INUH = INU/2 IR = INU - 2*INUH ARG = (FNU-DBLE(FLOAT(INU-IR)))*SGN RHPI = 1.0D0/SGN C ZNI = RHPI*DCOS(ARG) C ZNR = -RHPI*DSIN(ARG) CSGNI = RHPI*DCOS(ARG) CSGNR = -RHPI*DSIN(ARG) IF (MOD(INUH,2).EQ.0) GO TO 120 C ZNR = -ZNR C ZNI = -ZNI CSGNR = -CSGNR CSGNI = -CSGNI 120 CONTINUE ZTI = -FMM RTOL = 1.0D0/TOL ASCLE = UFL*RTOL DO 130 I=1,NN C STR = CYR(I)*ZNR - CYI(I)*ZNI C CYI(I) = CYR(I)*ZNI + CYI(I)*ZNR C CYR(I) = STR C STR = -ZNI*ZTI C ZNI = ZNR*ZTI C ZNR = STR AA = CYR(I) BB = CYI(I) ATOL = 1.0D0 IF (DMAX1(DABS(AA),DABS(BB)).GT.ASCLE) GO TO 135 AA = AA*RTOL BB = BB*RTOL ATOL = TOL 135 CONTINUE STR = AA*CSGNR - BB*CSGNI STI = AA*CSGNI + BB*CSGNR CYR(I) = STR*ATOL CYI(I) = STI*ATOL STR = -CSGNI*ZTI CSGNI = CSGNR*ZTI CSGNR = STR 130 CONTINUE RETURN 140 CONTINUE IF (ZNR.LT.0.0D0) GO TO 230 RETURN 230 CONTINUE NZ=0 IERR=2 RETURN 240 CONTINUE IF(NW.EQ.(-1)) GO TO 230 NZ=0 IERR=5 RETURN 260 CONTINUE NZ=0 IERR=4 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbesi.f000066400000000000000000000273701450372207100250050ustar00rootroot00000000000000 SUBROUTINE ZBESI(ZR, ZI, FNU, KODE, N, CYR, CYI, NZ, IERR) C***BEGIN PROLOGUE ZBESI C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS I-BESSEL FUNCTION,COMPLEX BESSEL FUNCTION, C MODIFIED BESSEL FUNCTION OF THE FIRST KIND C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE I-BESSEL FUNCTIONS OF COMPLEX ARGUMENT C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C ON KODE=1, ZBESI COMPUTES AN N MEMBER SEQUENCE OF COMPLEX C BESSEL FUNCTIONS CY(J)=I(FNU+J-1,Z) FOR REAL, NONNEGATIVE C ORDERS FNU+J-1, J=1,...,N AND COMPLEX Z IN THE CUT PLANE C -PI.LT.ARG(Z).LE.PI. ON KODE=2, ZBESI RETURNS THE SCALED C FUNCTIONS C C CY(J)=EXP(-ABS(X))*I(FNU+J-1,Z) J = 1,...,N , X=REAL(Z) C C WITH THE EXPONENTIAL GROWTH REMOVED IN BOTH THE LEFT AND C RIGHT HALF PLANES FOR Z TO INFINITY. DEFINITIONS AND NOTATION C ARE FOUND IN THE NBS HANDBOOK OF MATHEMATICAL FUNCTIONS C (REF. 1). C C INPUT ZR,ZI,FNU ARE DOUBLE PRECISION C ZR,ZI - Z=CMPLX(ZR,ZI), -PI.LT.ARG(Z).LE.PI C FNU - ORDER OF INITIAL I FUNCTION, FNU.GE.0.0D0 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION C KODE= 1 RETURNS C CY(J)=I(FNU+J-1,Z), J=1,...,N C = 2 RETURNS C CY(J)=I(FNU+J-1,Z)*EXP(-ABS(X)), J=1,...,N C N - NUMBER OF MEMBERS OF THE SEQUENCE, N.GE.1 C C OUTPUT CYR,CYI ARE DOUBLE PRECISION C CYR,CYI- DOUBLE PRECISION VECTORS WHOSE FIRST N COMPONENTS C CONTAIN REAL AND IMAGINARY PARTS FOR THE SEQUENCE C CY(J)=I(FNU+J-1,Z) OR C CY(J)=I(FNU+J-1,Z)*EXP(-ABS(X)) J=1,...,N C DEPENDING ON KODE, X=REAL(Z) C NZ - NUMBER OF COMPONENTS SET TO ZERO DUE TO UNDERFLOW, C NZ= 0 , NORMAL RETURN C NZ.GT.0 , LAST NZ COMPONENTS OF CY SET TO ZERO C TO UNDERFLOW, CY(J)=CMPLX(0.0D0,0.0D0) C J = N-NZ+1,...,N C IERR - ERROR FLAG C IERR=0, NORMAL RETURN - COMPUTATION COMPLETED C IERR=1, INPUT ERROR - NO COMPUTATION C IERR=2, OVERFLOW - NO COMPUTATION, REAL(Z) TOO C LARGE ON KODE=1 C IERR=3, CABS(Z) OR FNU+N-1 LARGE - COMPUTATION DONE C BUT LOSSES OF SIGNIFCANCE BY ARGUMENT C REDUCTION PRODUCE LESS THAN HALF OF MACHINE C ACCURACY C IERR=4, CABS(Z) OR FNU+N-1 TOO LARGE - NO COMPUTA- C TION BECAUSE OF COMPLETE LOSSES OF SIGNIFI- C CANCE BY ARGUMENT REDUCTION C IERR=5, ERROR - NO COMPUTATION, C ALGORITHM TERMINATION CONDITION NOT MET C C***LONG DESCRIPTION C C THE COMPUTATION IS CARRIED OUT BY THE POWER SERIES FOR C SMALL CABS(Z), THE ASYMPTOTIC EXPANSION FOR LARGE CABS(Z), C THE MILLER ALGORITHM NORMALIZED BY THE WRONSKIAN AND A C NEUMANN SERIES FOR IMTERMEDIATE MAGNITUDES, AND THE C UNIFORM ASYMPTOTIC EXPANSIONS FOR I(FNU,Z) AND J(FNU,Z) C FOR LARGE ORDERS. BACKWARD RECURRENCE IS USED TO GENERATE C SEQUENCES OR REDUCE ORDERS WHEN NECESSARY. C C THE CALCULATIONS ABOVE ARE DONE IN THE RIGHT HALF PLANE AND C CONTINUED INTO THE LEFT HALF PLANE BY THE FORMULA C C I(FNU,Z*EXP(M*PI)) = EXP(M*PI*FNU)*I(FNU,Z) REAL(Z).GT.0.0 C M = +I OR -I, I**2=-1 C C FOR NEGATIVE ORDERS,THE FORMULA C C I(-FNU,Z) = I(FNU,Z) + (2/PI)*SIN(PI*FNU)*K(FNU,Z) C C CAN BE USED. HOWEVER,FOR LARGE ORDERS CLOSE TO INTEGERS, THE C THE FUNCTION CHANGES RADICALLY. WHEN FNU IS A LARGE POSITIVE C INTEGER,THE MAGNITUDE OF I(-FNU,Z)=I(FNU,Z) IS A LARGE C NEGATIVE POWER OF TEN. BUT WHEN FNU IS NOT AN INTEGER, C K(FNU,Z) DOMINATES IN MAGNITUDE WITH A LARGE POSITIVE POWER OF C TEN AND THE MOST THAT THE SECOND TERM CAN BE REDUCED IS BY C UNIT ROUNDOFF FROM THE COEFFICIENT. THUS, WIDE CHANGES CAN C OCCUR WITHIN UNIT ROUNDOFF OF A LARGE INTEGER FOR FNU. HERE, C LARGE MEANS FNU.GT.CABS(Z). C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z OR FNU+N-1 IS C LARGE, LOSSES OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. C CONSEQUENTLY, IF EITHER ONE EXCEEDS U1=SQRT(0.5/UR), THEN C LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR FLAG C IERR=3 IS TRIGGERED WHERE UR=DMAX1(D1MACH(4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C IF EITHER IS LARGER THAN U2=0.5/UR, THEN ALL SIGNIFICANCE IS C LOST AND IERR=4. IN ORDER TO USE THE INT FUNCTION, ARGUMENTS C MUST BE FURTHER RESTRICTED NOT TO EXCEED THE LARGEST MACHINE C INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF Z AND FNU+N-1 IS C RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, AND U3 C ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE PRECISION C ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE PRECISION C ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMITING IN C THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT ONE CAN EXPECT C TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, NO DIGITS C IN SINGLE AND ONLY 7 DIGITS IN DOUBLE PRECISION ARITHMETIC. C SIMILAR CONSIDERATIONS HOLD FOR OTHER MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. IF ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C BY D. E. AMOS, SAND83-0083, MAY, 1983. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 C C***ROUTINES CALLED ZBINU,I1MACH,D1MACH C***END PROLOGUE ZBESI C COMPLEX CONE,CSGN,CW,CY,CZERO,Z,ZN DOUBLE PRECISION AA, ALIM, ARG, CONEI, CONER, CSGNI, CSGNR, CYI, * CYR, DIG, ELIM, FNU, FNUL, PI, RL, R1M5, STR, TOL, ZI, ZNI, ZNR, * ZR, D1MACH, AZ, BB, FN, ZABS, ASCLE, RTOL, ATOL, STI INTEGER I, IERR, INU, K, KODE, K1,K2,N,NZ,NN, I1MACH DIMENSION CYR(N), CYI(N) DATA PI /3.14159265358979324D0/ DATA CONER, CONEI /1.0D0,0.0D0/ C C***FIRST EXECUTABLE STATEMENT ZBESI IERR = 0 NZ=0 IF (FNU.LT.0.0D0) IERR=1 IF (KODE.LT.1 .OR. KODE.GT.2) IERR=1 IF (N.LT.1) IERR=1 IF (IERR.NE.0) RETURN C----------------------------------------------------------------------- C SET PARAMETERS RELATED TO MACHINE CONSTANTS. C TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0E-18. C ELIM IS THE APPROXIMATE EXPONENTIAL OVER- AND UNDERFLOW LIMIT. C EXP(-ELIM).LT.EXP(-ALIM)=EXP(-ELIM)/TOL AND C EXP(ELIM).GT.EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR C UNDERFLOW AND OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. C RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LARGE Z. C DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). C FNUL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC SERIES FOR LARGE FNU. C----------------------------------------------------------------------- TOL = DMAX1(D1MACH(4),1.0D-18) K1 = I1MACH(15) K2 = I1MACH(16) R1M5 = D1MACH(5) K = MIN0(IABS(K1),IABS(K2)) ELIM = 2.303D0*(DBLE(FLOAT(K))*R1M5-3.0D0) K1 = I1MACH(14) - 1 AA = R1M5*DBLE(FLOAT(K1)) DIG = DMIN1(AA,18.0D0) AA = AA*2.303D0 ALIM = ELIM + DMAX1(-AA,-41.45D0) RL = 1.2D0*DIG + 3.0D0 FNUL = 10.0D0 + 6.0D0*(DIG-3.0D0) C----------------------------------------------------------------------------- C TEST FOR PROPER RANGE C----------------------------------------------------------------------- AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) FN = FNU+DBLE(FLOAT(N-1)) AA = 0.5D0/TOL BB=DBLE(FLOAT(I1MACH(9)))*0.5D0 AA = DMIN1(AA,BB) IF (AZ.GT.AA) GO TO 260 IF (FN.GT.AA) GO TO 260 AA = DSQRT(AA) IF (AZ.GT.AA) IERR=3 IF (FN.GT.AA) IERR=3 ZNR = ZR ZNI = ZI CSGNR = CONER CSGNI = CONEI IF (ZR.GE.0.0D0) GO TO 40 ZNR = -ZR ZNI = -ZI C----------------------------------------------------------------------- C CALCULATE CSGN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE C WHEN FNU IS LARGE C----------------------------------------------------------------------- INU = INT(SNGL(FNU)) ARG = (FNU-DBLE(FLOAT(INU)))*PI IF (ZI.LT.0.0D0) ARG = -ARG CSGNR = DCOS(ARG) CSGNI = DSIN(ARG) IF (MOD(INU,2).EQ.0) GO TO 40 CSGNR = -CSGNR CSGNI = -CSGNI 40 CONTINUE CALL ZBINU(ZNR, ZNI, FNU, KODE, N, CYR, CYI, NZ, RL, FNUL, TOL, * ELIM, ALIM) IF (NZ.LT.0) GO TO 120 IF (ZR.GE.0.0D0) RETURN C----------------------------------------------------------------------- C ANALYTIC CONTINUATION TO THE LEFT HALF PLANE C----------------------------------------------------------------------- NN = N - NZ IF (NN.EQ.0) RETURN RTOL = 1.0D0/TOL ASCLE = D1MACH(1)*RTOL*1.0D+3 DO 50 I=1,NN C STR = CYR(I)*CSGNR - CYI(I)*CSGNI C CYI(I) = CYR(I)*CSGNI + CYI(I)*CSGNR C CYR(I) = STR AA = CYR(I) BB = CYI(I) ATOL = 1.0D0 IF (DMAX1(DABS(AA),DABS(BB)).GT.ASCLE) GO TO 55 AA = AA*RTOL BB = BB*RTOL ATOL = TOL 55 CONTINUE STR = AA*CSGNR - BB*CSGNI STI = AA*CSGNI + BB*CSGNR CYR(I) = STR*ATOL CYI(I) = STI*ATOL CSGNR = -CSGNR CSGNI = -CSGNI 50 CONTINUE RETURN 120 CONTINUE IF(NZ.EQ.(-2)) GO TO 130 NZ = 0 IERR=2 RETURN 130 CONTINUE NZ=0 IERR=5 RETURN 260 CONTINUE NZ=0 IERR=4 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbesj.f000066400000000000000000000265211450372207100250030ustar00rootroot00000000000000 SUBROUTINE ZBESJ(ZR, ZI, FNU, KODE, N, CYR, CYI, NZ, IERR) C***BEGIN PROLOGUE ZBESJ C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS J-BESSEL FUNCTION,BESSEL FUNCTION OF COMPLEX ARGUMENT, C BESSEL FUNCTION OF FIRST KIND C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE THE J-BESSEL FUNCTION OF A COMPLEX ARGUMENT C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C ON KODE=1, CBESJ COMPUTES AN N MEMBER SEQUENCE OF COMPLEX C BESSEL FUNCTIONS CY(I)=J(FNU+I-1,Z) FOR REAL, NONNEGATIVE C ORDERS FNU+I-1, I=1,...,N AND COMPLEX Z IN THE CUT PLANE C -PI.LT.ARG(Z).LE.PI. ON KODE=2, CBESJ RETURNS THE SCALED C FUNCTIONS C C CY(I)=EXP(-ABS(Y))*J(FNU+I-1,Z) I = 1,...,N , Y=AIMAG(Z) C C WHICH REMOVE THE EXPONENTIAL GROWTH IN BOTH THE UPPER AND C LOWER HALF PLANES FOR Z TO INFINITY. DEFINITIONS AND NOTATION C ARE FOUND IN THE NBS HANDBOOK OF MATHEMATICAL FUNCTIONS C (REF. 1). C C INPUT ZR,ZI,FNU ARE DOUBLE PRECISION C ZR,ZI - Z=CMPLX(ZR,ZI), -PI.LT.ARG(Z).LE.PI C FNU - ORDER OF INITIAL J FUNCTION, FNU.GE.0.0D0 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION C KODE= 1 RETURNS C CY(I)=J(FNU+I-1,Z), I=1,...,N C = 2 RETURNS C CY(I)=J(FNU+I-1,Z)EXP(-ABS(Y)), I=1,...,N C N - NUMBER OF MEMBERS OF THE SEQUENCE, N.GE.1 C C OUTPUT CYR,CYI ARE DOUBLE PRECISION C CYR,CYI- DOUBLE PRECISION VECTORS WHOSE FIRST N COMPONENTS C CONTAIN REAL AND IMAGINARY PARTS FOR THE SEQUENCE C CY(I)=J(FNU+I-1,Z) OR C CY(I)=J(FNU+I-1,Z)EXP(-ABS(Y)) I=1,...,N C DEPENDING ON KODE, Y=AIMAG(Z). C NZ - NUMBER OF COMPONENTS SET TO ZERO DUE TO UNDERFLOW, C NZ= 0 , NORMAL RETURN C NZ.GT.0 , LAST NZ COMPONENTS OF CY SET ZERO DUE C TO UNDERFLOW, CY(I)=CMPLX(0.0D0,0.0D0), C I = N-NZ+1,...,N C IERR - ERROR FLAG C IERR=0, NORMAL RETURN - COMPUTATION COMPLETED C IERR=1, INPUT ERROR - NO COMPUTATION C IERR=2, OVERFLOW - NO COMPUTATION, AIMAG(Z) C TOO LARGE ON KODE=1 C IERR=3, CABS(Z) OR FNU+N-1 LARGE - COMPUTATION DONE C BUT LOSSES OF SIGNIFCANCE BY ARGUMENT C REDUCTION PRODUCE LESS THAN HALF OF MACHINE C ACCURACY C IERR=4, CABS(Z) OR FNU+N-1 TOO LARGE - NO COMPUTA- C TION BECAUSE OF COMPLETE LOSSES OF SIGNIFI- C CANCE BY ARGUMENT REDUCTION C IERR=5, ERROR - NO COMPUTATION, C ALGORITHM TERMINATION CONDITION NOT MET C C***LONG DESCRIPTION C C THE COMPUTATION IS CARRIED OUT BY THE FORMULA C C J(FNU,Z)=EXP( FNU*PI*I/2)*I(FNU,-I*Z) AIMAG(Z).GE.0.0 C C J(FNU,Z)=EXP(-FNU*PI*I/2)*I(FNU, I*Z) AIMAG(Z).LT.0.0 C C WHERE I**2 = -1 AND I(FNU,Z) IS THE I BESSEL FUNCTION. C C FOR NEGATIVE ORDERS,THE FORMULA C C J(-FNU,Z) = J(FNU,Z)*COS(PI*FNU) - Y(FNU,Z)*SIN(PI*FNU) C C CAN BE USED. HOWEVER,FOR LARGE ORDERS CLOSE TO INTEGERS, THE C THE FUNCTION CHANGES RADICALLY. WHEN FNU IS A LARGE POSITIVE C INTEGER,THE MAGNITUDE OF J(-FNU,Z)=J(FNU,Z)*COS(PI*FNU) IS A C LARGE NEGATIVE POWER OF TEN. BUT WHEN FNU IS NOT AN INTEGER, C Y(FNU,Z) DOMINATES IN MAGNITUDE WITH A LARGE POSITIVE POWER OF C TEN AND THE MOST THAT THE SECOND TERM CAN BE REDUCED IS BY C UNIT ROUNDOFF FROM THE COEFFICIENT. THUS, WIDE CHANGES CAN C OCCUR WITHIN UNIT ROUNDOFF OF A LARGE INTEGER FOR FNU. HERE, C LARGE MEANS FNU.GT.CABS(Z). C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z OR FNU+N-1 IS C LARGE, LOSSES OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. C CONSEQUENTLY, IF EITHER ONE EXCEEDS U1=SQRT(0.5/UR), THEN C LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR FLAG C IERR=3 IS TRIGGERED WHERE UR=DMAX1(D1MACH(4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C IF EITHER IS LARGER THAN U2=0.5/UR, THEN ALL SIGNIFICANCE IS C LOST AND IERR=4. IN ORDER TO USE THE INT FUNCTION, ARGUMENTS C MUST BE FURTHER RESTRICTED NOT TO EXCEED THE LARGEST MACHINE C INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF Z AND FNU+N-1 IS C RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, AND U3 C ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE PRECISION C ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE PRECISION C ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMITING IN C THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT ONE CAN EXPECT C TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, NO DIGITS C IN SINGLE AND ONLY 7 DIGITS IN DOUBLE PRECISION ARITHMETIC. C SIMILAR CONSIDERATIONS HOLD FOR OTHER MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. IF ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C BY D. E. AMOS, SAND83-0083, MAY, 1983. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 C C***ROUTINES CALLED ZBINU,I1MACH,D1MACH C***END PROLOGUE ZBESJ C C COMPLEX CI,CSGN,CY,Z,ZN DOUBLE PRECISION AA, ALIM, ARG, CII, CSGNI, CSGNR, CYI, CYR, DIG, * ELIM, FNU, FNUL, HPI, RL, R1M5, STR, TOL, ZI, ZNI, ZNR, ZR, * D1MACH, BB, FN, AZ, ZABS, ASCLE, RTOL, ATOL, STI INTEGER I, IERR, INU, INUH, IR, K, KODE, K1, K2, N, NL, NZ, I1MACH DIMENSION CYR(N), CYI(N) DATA HPI /1.57079632679489662D0/ C C***FIRST EXECUTABLE STATEMENT ZBESJ IERR = 0 NZ=0 IF (FNU.LT.0.0D0) IERR=1 IF (KODE.LT.1 .OR. KODE.GT.2) IERR=1 IF (N.LT.1) IERR=1 IF (IERR.NE.0) RETURN C----------------------------------------------------------------------- C SET PARAMETERS RELATED TO MACHINE CONSTANTS. C TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0E-18. C ELIM IS THE APPROXIMATE EXPONENTIAL OVER- AND UNDERFLOW LIMIT. C EXP(-ELIM).LT.EXP(-ALIM)=EXP(-ELIM)/TOL AND C EXP(ELIM).GT.EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR C UNDERFLOW AND OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. C RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LARGE Z. C DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). C FNUL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC SERIES FOR LARGE FNU. C----------------------------------------------------------------------- TOL = DMAX1(D1MACH(4),1.0D-18) K1 = I1MACH(15) K2 = I1MACH(16) R1M5 = D1MACH(5) K = MIN0(IABS(K1),IABS(K2)) ELIM = 2.303D0*(DBLE(FLOAT(K))*R1M5-3.0D0) K1 = I1MACH(14) - 1 AA = R1M5*DBLE(FLOAT(K1)) DIG = DMIN1(AA,18.0D0) AA = AA*2.303D0 ALIM = ELIM + DMAX1(-AA,-41.45D0) RL = 1.2D0*DIG + 3.0D0 FNUL = 10.0D0 + 6.0D0*(DIG-3.0D0) C----------------------------------------------------------------------- C TEST FOR PROPER RANGE C----------------------------------------------------------------------- AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) FN = FNU+DBLE(FLOAT(N-1)) AA = 0.5D0/TOL BB=DBLE(FLOAT(I1MACH(9)))*0.5D0 AA = DMIN1(AA,BB) IF (AZ.GT.AA) GO TO 260 IF (FN.GT.AA) GO TO 260 AA = DSQRT(AA) IF (AZ.GT.AA) IERR=3 IF (FN.GT.AA) IERR=3 C----------------------------------------------------------------------- C CALCULATE CSGN=EXP(FNU*HPI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE C WHEN FNU IS LARGE C----------------------------------------------------------------------- CII = 1.0D0 INU = INT(SNGL(FNU)) INUH = INU/2 IR = INU - 2*INUH ARG = (FNU-DBLE(FLOAT(INU-IR)))*HPI CSGNR = DCOS(ARG) CSGNI = DSIN(ARG) IF (MOD(INUH,2).EQ.0) GO TO 40 CSGNR = -CSGNR CSGNI = -CSGNI 40 CONTINUE C----------------------------------------------------------------------- C ZN IS IN THE RIGHT HALF PLANE C----------------------------------------------------------------------- ZNR = ZI ZNI = -ZR IF (ZI.GE.0.0D0) GO TO 50 ZNR = -ZNR ZNI = -ZNI CSGNI = -CSGNI CII = -CII 50 CONTINUE CALL ZBINU(ZNR, ZNI, FNU, KODE, N, CYR, CYI, NZ, RL, FNUL, TOL, * ELIM, ALIM) IF (NZ.LT.0) GO TO 130 NL = N - NZ IF (NL.EQ.0) RETURN RTOL = 1.0D0/TOL ASCLE = D1MACH(1)*RTOL*1.0D+3 DO 60 I=1,NL C STR = CYR(I)*CSGNR - CYI(I)*CSGNI C CYI(I) = CYR(I)*CSGNI + CYI(I)*CSGNR C CYR(I) = STR AA = CYR(I) BB = CYI(I) ATOL = 1.0D0 IF (DMAX1(DABS(AA),DABS(BB)).GT.ASCLE) GO TO 55 AA = AA*RTOL BB = BB*RTOL ATOL = TOL 55 CONTINUE STR = AA*CSGNR - BB*CSGNI STI = AA*CSGNI + BB*CSGNR CYR(I) = STR*ATOL CYI(I) = STI*ATOL STR = -CSGNI*CII CSGNI = CSGNR*CII CSGNR = STR 60 CONTINUE RETURN 130 CONTINUE IF(NZ.EQ.(-2)) GO TO 140 NZ = 0 IERR = 2 RETURN 140 CONTINUE NZ=0 IERR=5 RETURN 260 CONTINUE NZ=0 IERR=4 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbesk.f000066400000000000000000000300131450372207100247730ustar00rootroot00000000000000 SUBROUTINE ZBESK(ZR, ZI, FNU, KODE, N, CYR, CYI, NZ, IERR) C***BEGIN PROLOGUE ZBESK C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS K-BESSEL FUNCTION,COMPLEX BESSEL FUNCTION, C MODIFIED BESSEL FUNCTION OF THE SECOND KIND, C BESSEL FUNCTION OF THE THIRD KIND C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE K-BESSEL FUNCTIONS OF COMPLEX ARGUMENT C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C C ON KODE=1, CBESK COMPUTES AN N MEMBER SEQUENCE OF COMPLEX C BESSEL FUNCTIONS CY(J)=K(FNU+J-1,Z) FOR REAL, NONNEGATIVE C ORDERS FNU+J-1, J=1,...,N AND COMPLEX Z.NE.CMPLX(0.0,0.0) C IN THE CUT PLANE -PI.LT.ARG(Z).LE.PI. ON KODE=2, CBESK C RETURNS THE SCALED K FUNCTIONS, C C CY(J)=EXP(Z)*K(FNU+J-1,Z) , J=1,...,N, C C WHICH REMOVE THE EXPONENTIAL BEHAVIOR IN BOTH THE LEFT AND C RIGHT HALF PLANES FOR Z TO INFINITY. DEFINITIONS AND C NOTATION ARE FOUND IN THE NBS HANDBOOK OF MATHEMATICAL C FUNCTIONS (REF. 1). C C INPUT ZR,ZI,FNU ARE DOUBLE PRECISION C ZR,ZI - Z=CMPLX(ZR,ZI), Z.NE.CMPLX(0.0D0,0.0D0), C -PI.LT.ARG(Z).LE.PI C FNU - ORDER OF INITIAL K FUNCTION, FNU.GE.0.0D0 C N - NUMBER OF MEMBERS OF THE SEQUENCE, N.GE.1 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION C KODE= 1 RETURNS C CY(I)=K(FNU+I-1,Z), I=1,...,N C = 2 RETURNS C CY(I)=K(FNU+I-1,Z)*EXP(Z), I=1,...,N C C OUTPUT CYR,CYI ARE DOUBLE PRECISION C CYR,CYI- DOUBLE PRECISION VECTORS WHOSE FIRST N COMPONENTS C CONTAIN REAL AND IMAGINARY PARTS FOR THE SEQUENCE C CY(I)=K(FNU+I-1,Z), I=1,...,N OR C CY(I)=K(FNU+I-1,Z)*EXP(Z), I=1,...,N C DEPENDING ON KODE C NZ - NUMBER OF COMPONENTS SET TO ZERO DUE TO UNDERFLOW. C NZ= 0 , NORMAL RETURN C NZ.GT.0 , FIRST NZ COMPONENTS OF CY SET TO ZERO DUE C TO UNDERFLOW, CY(I)=CMPLX(0.0D0,0.0D0), C I=1,...,N WHEN X.GE.0.0. WHEN X.LT.0.0 C NZ STATES ONLY THE NUMBER OF UNDERFLOWS C IN THE SEQUENCE. C C IERR - ERROR FLAG C IERR=0, NORMAL RETURN - COMPUTATION COMPLETED C IERR=1, INPUT ERROR - NO COMPUTATION C IERR=2, OVERFLOW - NO COMPUTATION, FNU IS C TOO LARGE OR CABS(Z) IS TOO SMALL OR BOTH C IERR=3, CABS(Z) OR FNU+N-1 LARGE - COMPUTATION DONE C BUT LOSSES OF SIGNIFCANCE BY ARGUMENT C REDUCTION PRODUCE LESS THAN HALF OF MACHINE C ACCURACY C IERR=4, CABS(Z) OR FNU+N-1 TOO LARGE - NO COMPUTA- C TION BECAUSE OF COMPLETE LOSSES OF SIGNIFI- C CANCE BY ARGUMENT REDUCTION C IERR=5, ERROR - NO COMPUTATION, C ALGORITHM TERMINATION CONDITION NOT MET C C***LONG DESCRIPTION C C EQUATIONS OF THE REFERENCE ARE IMPLEMENTED FOR SMALL ORDERS C DNU AND DNU+1.0 IN THE RIGHT HALF PLANE X.GE.0.0. FORWARD C RECURRENCE GENERATES HIGHER ORDERS. K IS CONTINUED TO THE LEFT C HALF PLANE BY THE RELATION C C K(FNU,Z*EXP(MP)) = EXP(-MP*FNU)*K(FNU,Z)-MP*I(FNU,Z) C MP=MR*PI*I, MR=+1 OR -1, RE(Z).GT.0, I**2=-1 C C WHERE I(FNU,Z) IS THE I BESSEL FUNCTION. C C FOR LARGE ORDERS, FNU.GT.FNUL, THE K FUNCTION IS COMPUTED C BY MEANS OF ITS UNIFORM ASYMPTOTIC EXPANSIONS. C C FOR NEGATIVE ORDERS, THE FORMULA C C K(-FNU,Z) = K(FNU,Z) C C CAN BE USED. C C CBESK ASSUMES THAT A SIGNIFICANT DIGIT SINH(X) FUNCTION IS C AVAILABLE. C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z OR FNU+N-1 IS C LARGE, LOSSES OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. C CONSEQUENTLY, IF EITHER ONE EXCEEDS U1=SQRT(0.5/UR), THEN C LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR FLAG C IERR=3 IS TRIGGERED WHERE UR=DMAX1(D1MACH(4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C IF EITHER IS LARGER THAN U2=0.5/UR, THEN ALL SIGNIFICANCE IS C LOST AND IERR=4. IN ORDER TO USE THE INT FUNCTION, ARGUMENTS C MUST BE FURTHER RESTRICTED NOT TO EXCEED THE LARGEST MACHINE C INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF Z AND FNU+N-1 IS C RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, AND U3 C ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE PRECISION C ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE PRECISION C ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMITING IN C THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT ONE CAN EXPECT C TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, NO DIGITS C IN SINGLE AND ONLY 7 DIGITS IN DOUBLE PRECISION ARITHMETIC. C SIMILAR CONSIDERATIONS HOLD FOR OTHER MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. IF ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C BY D. E. AMOS, SAND83-0083, MAY, 1983. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983. C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 C C***ROUTINES CALLED ZACON,ZBKNU,ZBUNK,ZUOIK,ZABS,I1MACH,D1MACH C***END PROLOGUE ZBESK C C COMPLEX CY,Z DOUBLE PRECISION AA, ALIM, ALN, ARG, AZ, CYI, CYR, DIG, ELIM, FN, * FNU, FNUL, RL, R1M5, TOL, UFL, ZI, ZR, D1MACH, ZABS, BB INTEGER IERR, K, KODE, K1, K2, MR, N, NN, NUF, NW, NZ, I1MACH DIMENSION CYR(N), CYI(N) C***FIRST EXECUTABLE STATEMENT ZBESK IERR = 0 NZ=0 IF (ZI.EQ.0.0E0 .AND. ZR.EQ.0.0E0) IERR=1 IF (FNU.LT.0.0D0) IERR=1 IF (KODE.LT.1 .OR. KODE.GT.2) IERR=1 IF (N.LT.1) IERR=1 IF (IERR.NE.0) RETURN NN = N C----------------------------------------------------------------------- C SET PARAMETERS RELATED TO MACHINE CONSTANTS. C TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0E-18. C ELIM IS THE APPROXIMATE EXPONENTIAL OVER- AND UNDERFLOW LIMIT. C EXP(-ELIM).LT.EXP(-ALIM)=EXP(-ELIM)/TOL AND C EXP(ELIM).GT.EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR C UNDERFLOW AND OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. C RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LARGE Z. C DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). C FNUL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC SERIES FOR LARGE FNU C----------------------------------------------------------------------- TOL = DMAX1(D1MACH(4),1.0D-18) K1 = I1MACH(15) K2 = I1MACH(16) R1M5 = D1MACH(5) K = MIN0(IABS(K1),IABS(K2)) ELIM = 2.303D0*(DBLE(FLOAT(K))*R1M5-3.0D0) K1 = I1MACH(14) - 1 AA = R1M5*DBLE(FLOAT(K1)) DIG = DMIN1(AA,18.0D0) AA = AA*2.303D0 ALIM = ELIM + DMAX1(-AA,-41.45D0) FNUL = 10.0D0 + 6.0D0*(DIG-3.0D0) RL = 1.2D0*DIG + 3.0D0 C----------------------------------------------------------------------------- C TEST FOR PROPER RANGE C----------------------------------------------------------------------- AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) FN = FNU + DBLE(FLOAT(NN-1)) AA = 0.5D0/TOL BB=DBLE(FLOAT(I1MACH(9)))*0.5D0 AA = DMIN1(AA,BB) IF (AZ.GT.AA) GO TO 260 IF (FN.GT.AA) GO TO 260 AA = DSQRT(AA) IF (AZ.GT.AA) IERR=3 IF (FN.GT.AA) IERR=3 C----------------------------------------------------------------------- C OVERFLOW TEST ON THE LAST MEMBER OF THE SEQUENCE C----------------------------------------------------------------------- C UFL = DEXP(-ELIM) UFL = D1MACH(1)*1.0D+3 IF (AZ.LT.UFL) GO TO 180 IF (FNU.GT.FNUL) GO TO 80 IF (FN.LE.1.0D0) GO TO 60 IF (FN.GT.2.0D0) GO TO 50 IF (AZ.GT.TOL) GO TO 60 ARG = 0.5D0*AZ ALN = -FN*DLOG(ARG) IF (ALN.GT.ELIM) GO TO 180 GO TO 60 50 CONTINUE CALL ZUOIK(ZR, ZI, FNU, KODE, 2, NN, CYR, CYI, NUF, TOL, ELIM, * ALIM) IF (NUF.LT.0) GO TO 180 NZ = NZ + NUF NN = NN - NUF C----------------------------------------------------------------------- C HERE NN=N OR NN=0 SINCE NUF=0,NN, OR -1 ON RETURN FROM CUOIK C IF NUF=NN, THEN CY(I)=CZERO FOR ALL I C----------------------------------------------------------------------- IF (NN.EQ.0) GO TO 100 60 CONTINUE IF (ZR.LT.0.0D0) GO TO 70 C----------------------------------------------------------------------- C RIGHT HALF PLANE COMPUTATION, REAL(Z).GE.0. C----------------------------------------------------------------------- CALL ZBKNU(ZR, ZI, FNU, KODE, NN, CYR, CYI, NW, TOL, ELIM, ALIM) IF (NW.LT.0) GO TO 200 NZ=NW RETURN C----------------------------------------------------------------------- C LEFT HALF PLANE COMPUTATION C PI/2.LT.ARG(Z).LE.PI AND -PI.LT.ARG(Z).LT.-PI/2. C----------------------------------------------------------------------- 70 CONTINUE IF (NZ.NE.0) GO TO 180 MR = 1 IF (ZI.LT.0.0D0) MR = -1 CALL ZACON(ZR, ZI, FNU, KODE, MR, NN, CYR, CYI, NW, RL, FNUL, * TOL, ELIM, ALIM) IF (NW.LT.0) GO TO 200 NZ=NW RETURN C----------------------------------------------------------------------- C UNIFORM ASYMPTOTIC EXPANSIONS FOR FNU.GT.FNUL C----------------------------------------------------------------------- 80 CONTINUE MR = 0 IF (ZR.GE.0.0D0) GO TO 90 MR = 1 IF (ZI.LT.0.0D0) MR = -1 90 CONTINUE CALL ZBUNK(ZR, ZI, FNU, KODE, MR, NN, CYR, CYI, NW, TOL, ELIM, * ALIM) IF (NW.LT.0) GO TO 200 NZ = NZ + NW RETURN 100 CONTINUE IF (ZR.LT.0.0D0) GO TO 180 RETURN 180 CONTINUE NZ = 0 IERR=2 RETURN 200 CONTINUE IF(NW.EQ.(-1)) GO TO 180 NZ=0 IERR=5 RETURN 260 CONTINUE NZ=0 IERR=4 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbesy.f000066400000000000000000000245621450372207100250250ustar00rootroot00000000000000 SUBROUTINE ZBESY(ZR, ZI, FNU, KODE, N, CYR, CYI, NZ, CWRKR, CWRKI, * IERR) C***BEGIN PROLOGUE ZBESY C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS Y-BESSEL FUNCTION,BESSEL FUNCTION OF COMPLEX ARGUMENT, C BESSEL FUNCTION OF SECOND KIND C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE THE Y-BESSEL FUNCTION OF A COMPLEX ARGUMENT C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C C ON KODE=1, CBESY COMPUTES AN N MEMBER SEQUENCE OF COMPLEX C BESSEL FUNCTIONS CY(I)=Y(FNU+I-1,Z) FOR REAL, NONNEGATIVE C ORDERS FNU+I-1, I=1,...,N AND COMPLEX Z IN THE CUT PLANE C -PI.LT.ARG(Z).LE.PI. ON KODE=2, CBESY RETURNS THE SCALED C FUNCTIONS C C CY(I)=EXP(-ABS(Y))*Y(FNU+I-1,Z) I = 1,...,N , Y=AIMAG(Z) C C WHICH REMOVE THE EXPONENTIAL GROWTH IN BOTH THE UPPER AND C LOWER HALF PLANES FOR Z TO INFINITY. DEFINITIONS AND NOTATION C ARE FOUND IN THE NBS HANDBOOK OF MATHEMATICAL FUNCTIONS C (REF. 1). C C INPUT ZR,ZI,FNU ARE DOUBLE PRECISION C ZR,ZI - Z=CMPLX(ZR,ZI), Z.NE.CMPLX(0.0D0,0.0D0), C -PI.LT.ARG(Z).LE.PI C FNU - ORDER OF INITIAL Y FUNCTION, FNU.GE.0.0D0 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION C KODE= 1 RETURNS C CY(I)=Y(FNU+I-1,Z), I=1,...,N C = 2 RETURNS C CY(I)=Y(FNU+I-1,Z)*EXP(-ABS(Y)), I=1,...,N C WHERE Y=AIMAG(Z) C N - NUMBER OF MEMBERS OF THE SEQUENCE, N.GE.1 C CWRKR, - DOUBLE PRECISION WORK VECTORS OF DIMENSION AT C CWRKI AT LEAST N C C OUTPUT CYR,CYI ARE DOUBLE PRECISION C CYR,CYI- DOUBLE PRECISION VECTORS WHOSE FIRST N COMPONENTS C CONTAIN REAL AND IMAGINARY PARTS FOR THE SEQUENCE C CY(I)=Y(FNU+I-1,Z) OR C CY(I)=Y(FNU+I-1,Z)*EXP(-ABS(Y)) I=1,...,N C DEPENDING ON KODE. C NZ - NZ=0 , A NORMAL RETURN C NZ.GT.0 , NZ COMPONENTS OF CY SET TO ZERO DUE TO C UNDERFLOW (GENERALLY ON KODE=2) C IERR - ERROR FLAG C IERR=0, NORMAL RETURN - COMPUTATION COMPLETED C IERR=1, INPUT ERROR - NO COMPUTATION C IERR=2, OVERFLOW - NO COMPUTATION, FNU IS C TOO LARGE OR CABS(Z) IS TOO SMALL OR BOTH C IERR=3, CABS(Z) OR FNU+N-1 LARGE - COMPUTATION DONE C BUT LOSSES OF SIGNIFCANCE BY ARGUMENT C REDUCTION PRODUCE LESS THAN HALF OF MACHINE C ACCURACY C IERR=4, CABS(Z) OR FNU+N-1 TOO LARGE - NO COMPUTA- C TION BECAUSE OF COMPLETE LOSSES OF SIGNIFI- C CANCE BY ARGUMENT REDUCTION C IERR=5, ERROR - NO COMPUTATION, C ALGORITHM TERMINATION CONDITION NOT MET C C***LONG DESCRIPTION C C THE COMPUTATION IS CARRIED OUT BY THE FORMULA C C Y(FNU,Z)=0.5*(H(1,FNU,Z)-H(2,FNU,Z))/I C C WHERE I**2 = -1 AND THE HANKEL BESSEL FUNCTIONS H(1,FNU,Z) C AND H(2,FNU,Z) ARE CALCULATED IN CBESH. C C FOR NEGATIVE ORDERS,THE FORMULA C C Y(-FNU,Z) = Y(FNU,Z)*COS(PI*FNU) + J(FNU,Z)*SIN(PI*FNU) C C CAN BE USED. HOWEVER,FOR LARGE ORDERS CLOSE TO HALF ODD C INTEGERS THE FUNCTION CHANGES RADICALLY. WHEN FNU IS A LARGE C POSITIVE HALF ODD INTEGER,THE MAGNITUDE OF Y(-FNU,Z)=J(FNU,Z)* C SIN(PI*FNU) IS A LARGE NEGATIVE POWER OF TEN. BUT WHEN FNU IS C NOT A HALF ODD INTEGER, Y(FNU,Z) DOMINATES IN MAGNITUDE WITH A C LARGE POSITIVE POWER OF TEN AND THE MOST THAT THE SECOND TERM C CAN BE REDUCED IS BY UNIT ROUNDOFF FROM THE COEFFICIENT. THUS, C WIDE CHANGES CAN OCCUR WITHIN UNIT ROUNDOFF OF A LARGE HALF C ODD INTEGER. HERE, LARGE MEANS FNU.GT.CABS(Z). C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z OR FNU+N-1 IS C LARGE, LOSSES OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. C CONSEQUENTLY, IF EITHER ONE EXCEEDS U1=SQRT(0.5/UR), THEN C LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR FLAG C IERR=3 IS TRIGGERED WHERE UR=DMAX1(D1MACH(4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C IF EITHER IS LARGER THAN U2=0.5/UR, THEN ALL SIGNIFICANCE IS C LOST AND IERR=4. IN ORDER TO USE THE INT FUNCTION, ARGUMENTS C MUST BE FURTHER RESTRICTED NOT TO EXCEED THE LARGEST MACHINE C INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF Z AND FNU+N-1 IS C RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, AND U3 C ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE PRECISION C ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE PRECISION C ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMITING IN C THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT ONE CAN EXPECT C TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, NO DIGITS C IN SINGLE AND ONLY 7 DIGITS IN DOUBLE PRECISION ARITHMETIC. C SIMILAR CONSIDERATIONS HOLD FOR OTHER MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. IF ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C BY D. E. AMOS, SAND83-0083, MAY, 1983. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 C C***ROUTINES CALLED ZBESH,I1MACH,D1MACH C***END PROLOGUE ZBESY C C COMPLEX CWRK,CY,C1,C2,EX,HCI,Z,ZU,ZV DOUBLE PRECISION CWRKI, CWRKR, CYI, CYR, C1I, C1R, C2I, C2R, * ELIM, EXI, EXR, EY, FNU, HCII, STI, STR, TAY, ZI, ZR, DEXP, * D1MACH, ASCLE, RTOL, ATOL, AA, BB, TOL INTEGER I, IERR, K, KODE, K1, K2, N, NZ, NZ1, NZ2, I1MACH DIMENSION CYR(N), CYI(N), CWRKR(N), CWRKI(N) C***FIRST EXECUTABLE STATEMENT ZBESY IERR = 0 NZ=0 IF (ZR.EQ.0.0D0 .AND. ZI.EQ.0.0D0) IERR=1 IF (FNU.LT.0.0D0) IERR=1 IF (KODE.LT.1 .OR. KODE.GT.2) IERR=1 IF (N.LT.1) IERR=1 IF (IERR.NE.0) RETURN HCII = 0.5D0 CALL ZBESH(ZR, ZI, FNU, KODE, 1, N, CYR, CYI, NZ1, IERR) IF (IERR.NE.0.AND.IERR.NE.3) GO TO 170 CALL ZBESH(ZR, ZI, FNU, KODE, 2, N, CWRKR, CWRKI, NZ2, IERR) IF (IERR.NE.0.AND.IERR.NE.3) GO TO 170 NZ = MIN0(NZ1,NZ2) IF (KODE.EQ.2) GO TO 60 DO 50 I=1,N STR = CWRKR(I) - CYR(I) STI = CWRKI(I) - CYI(I) CYR(I) = -STI*HCII CYI(I) = STR*HCII 50 CONTINUE RETURN 60 CONTINUE TOL = DMAX1(D1MACH(4),1.0D-18) K1 = I1MACH(15) K2 = I1MACH(16) K = MIN0(IABS(K1),IABS(K2)) R1M5 = D1MACH(5) C----------------------------------------------------------------------- C ELIM IS THE APPROXIMATE EXPONENTIAL UNDER- AND OVERFLOW LIMIT C----------------------------------------------------------------------- ELIM = 2.303D0*(DBLE(FLOAT(K))*R1M5-3.0D0) EXR = DCOS(ZR) EXI = DSIN(ZR) EY = 0.0D0 TAY = DABS(ZI+ZI) IF (TAY.LT.ELIM) EY = DEXP(-TAY) IF (ZI.LT.0.0D0) GO TO 90 C1R = EXR*EY C1I = EXI*EY C2R = EXR C2I = -EXI 70 CONTINUE NZ = 0 RTOL = 1.0D0/TOL ASCLE = D1MACH(1)*RTOL*1.0D+3 DO 80 I=1,N C STR = C1R*CYR(I) - C1I*CYI(I) C STI = C1R*CYI(I) + C1I*CYR(I) C STR = -STR + C2R*CWRKR(I) - C2I*CWRKI(I) C STI = -STI + C2R*CWRKI(I) + C2I*CWRKR(I) C CYR(I) = -STI*HCII C CYI(I) = STR*HCII AA = CWRKR(I) BB = CWRKI(I) ATOL = 1.0D0 IF (DMAX1(DABS(AA),DABS(BB)).GT.ASCLE) GO TO 75 AA = AA*RTOL BB = BB*RTOL ATOL = TOL 75 CONTINUE STR = (AA*C2R - BB*C2I)*ATOL STI = (AA*C2I + BB*C2R)*ATOL AA = CYR(I) BB = CYI(I) ATOL = 1.0D0 IF (DMAX1(DABS(AA),DABS(BB)).GT.ASCLE) GO TO 85 AA = AA*RTOL BB = BB*RTOL ATOL = TOL 85 CONTINUE STR = STR - (AA*C1R - BB*C1I)*ATOL STI = STI - (AA*C1I + BB*C1R)*ATOL CYR(I) = -STI*HCII CYI(I) = STR*HCII IF (STR.EQ.0.0D0 .AND. STI.EQ.0.0D0 .AND. EY.EQ.0.0D0) NZ = NZ * + 1 80 CONTINUE RETURN 90 CONTINUE C1R = EXR C1I = EXI C2R = EXR*EY C2I = -EXI*EY GO TO 70 170 CONTINUE NZ = 0 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbinu.f000066400000000000000000000075361450372207100250220ustar00rootroot00000000000000 SUBROUTINE ZBINU(ZR, ZI, FNU, KODE, N, CYR, CYI, NZ, RL, FNUL, * TOL, ELIM, ALIM) C***BEGIN PROLOGUE ZBINU C***REFER TO ZBESH,ZBESI,ZBESJ,ZBESK,ZAIRY,ZBIRY C C ZBINU COMPUTES THE I FUNCTION IN THE RIGHT HALF Z PLANE C C***ROUTINES CALLED ZABS,ZASYI,ZBUNI,ZMLRI,ZSERI,ZUOIK,ZWRSK C***END PROLOGUE ZBINU DOUBLE PRECISION ALIM, AZ, CWI, CWR, CYI, CYR, DFNU, ELIM, FNU, * FNUL, RL, TOL, ZEROI, ZEROR, ZI, ZR, ZABS INTEGER I, INW, KODE, N, NLAST, NN, NUI, NW, NZ DIMENSION CYR(N), CYI(N), CWR(2), CWI(2) DATA ZEROR,ZEROI / 0.0D0, 0.0D0 / C NZ = 0 AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) NN = N DFNU = FNU + DBLE(FLOAT(N-1)) IF (AZ.LE.2.0D0) GO TO 10 IF (AZ*AZ*0.25D0.GT.DFNU+1.0D0) GO TO 20 10 CONTINUE C----------------------------------------------------------------------- C POWER SERIES C----------------------------------------------------------------------- CALL ZSERI(ZR, ZI, FNU, KODE, NN, CYR, CYI, NW, TOL, ELIM, ALIM) INW = IABS(NW) NZ = NZ + INW NN = NN - INW IF (NN.EQ.0) RETURN IF (NW.GE.0) GO TO 120 DFNU = FNU + DBLE(FLOAT(NN-1)) 20 CONTINUE IF (AZ.LT.RL) GO TO 40 IF (DFNU.LE.1.0D0) GO TO 30 IF (AZ+AZ.LT.DFNU*DFNU) GO TO 50 C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR LARGE Z C----------------------------------------------------------------------- 30 CONTINUE CALL ZASYI(ZR, ZI, FNU, KODE, NN, CYR, CYI, NW, RL, TOL, ELIM, * ALIM) IF (NW.LT.0) GO TO 130 GO TO 120 40 CONTINUE IF (DFNU.LE.1.0D0) GO TO 70 50 CONTINUE C----------------------------------------------------------------------- C OVERFLOW AND UNDERFLOW TEST ON I SEQUENCE FOR MILLER ALGORITHM C----------------------------------------------------------------------- CALL ZUOIK(ZR, ZI, FNU, KODE, 1, NN, CYR, CYI, NW, TOL, ELIM, * ALIM) IF (NW.LT.0) GO TO 130 NZ = NZ + NW NN = NN - NW IF (NN.EQ.0) RETURN DFNU = FNU+DBLE(FLOAT(NN-1)) IF (DFNU.GT.FNUL) GO TO 110 IF (AZ.GT.FNUL) GO TO 110 60 CONTINUE IF (AZ.GT.RL) GO TO 80 70 CONTINUE C----------------------------------------------------------------------- C MILLER ALGORITHM NORMALIZED BY THE SERIES C----------------------------------------------------------------------- CALL ZMLRI(ZR, ZI, FNU, KODE, NN, CYR, CYI, NW, TOL) IF(NW.LT.0) GO TO 130 GO TO 120 80 CONTINUE C----------------------------------------------------------------------- C MILLER ALGORITHM NORMALIZED BY THE WRONSKIAN C----------------------------------------------------------------------- C----------------------------------------------------------------------- C OVERFLOW TEST ON K FUNCTIONS USED IN WRONSKIAN C----------------------------------------------------------------------- CALL ZUOIK(ZR, ZI, FNU, KODE, 2, 2, CWR, CWI, NW, TOL, ELIM, * ALIM) IF (NW.GE.0) GO TO 100 NZ = NN DO 90 I=1,NN CYR(I) = ZEROR CYI(I) = ZEROI 90 CONTINUE RETURN 100 CONTINUE IF (NW.GT.0) GO TO 130 CALL ZWRSK(ZR, ZI, FNU, KODE, NN, CYR, CYI, NW, CWR, CWI, TOL, * ELIM, ALIM) IF (NW.LT.0) GO TO 130 GO TO 120 110 CONTINUE C----------------------------------------------------------------------- C INCREMENT FNU+NN-1 UP TO FNUL, COMPUTE AND RECUR BACKWARD C----------------------------------------------------------------------- NUI = INT(SNGL(FNUL-DFNU)) + 1 NUI = MAX0(NUI,0) CALL ZBUNI(ZR, ZI, FNU, KODE, NN, CYR, CYI, NW, NUI, NLAST, FNUL, * TOL, ELIM, ALIM) IF (NW.LT.0) GO TO 130 NZ = NZ + NW IF (NLAST.EQ.0) GO TO 120 NN = NLAST GO TO 60 120 CONTINUE RETURN 130 CONTINUE NZ = -1 IF(NW.EQ.(-2)) NZ=-2 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbiry.f000066400000000000000000000337001450372207100250220ustar00rootroot00000000000000 SUBROUTINE ZBIRY(ZR, ZI, ID, KODE, BIR, BII, IERR) C***BEGIN PROLOGUE ZBIRY C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS AIRY FUNCTION,BESSEL FUNCTIONS OF ORDER ONE THIRD C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE AIRY FUNCTIONS BI(Z) AND DBI(Z) FOR COMPLEX Z C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C ON KODE=1, CBIRY COMPUTES THE COMPLEX AIRY FUNCTION BI(Z) OR C ITS DERIVATIVE DBI(Z)/DZ ON ID=0 OR ID=1 RESPECTIVELY. ON C KODE=2, A SCALING OPTION CEXP(-AXZTA)*BI(Z) OR CEXP(-AXZTA)* C DBI(Z)/DZ IS PROVIDED TO REMOVE THE EXPONENTIAL BEHAVIOR IN C BOTH THE LEFT AND RIGHT HALF PLANES WHERE C ZTA=(2/3)*Z*CSQRT(Z)=CMPLX(XZTA,YZTA) AND AXZTA=ABS(XZTA). C DEFINTIONS AND NOTATION ARE FOUND IN THE NBS HANDBOOK OF C MATHEMATICAL FUNCTIONS (REF. 1). C C INPUT ZR,ZI ARE DOUBLE PRECISION C ZR,ZI - Z=CMPLX(ZR,ZI) C ID - ORDER OF DERIVATIVE, ID=0 OR ID=1 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION C KODE= 1 RETURNS C BI=BI(Z) ON ID=0 OR C BI=DBI(Z)/DZ ON ID=1 C = 2 RETURNS C BI=CEXP(-AXZTA)*BI(Z) ON ID=0 OR C BI=CEXP(-AXZTA)*DBI(Z)/DZ ON ID=1 WHERE C ZTA=(2/3)*Z*CSQRT(Z)=CMPLX(XZTA,YZTA) C AND AXZTA=ABS(XZTA) C C OUTPUT BIR,BII ARE DOUBLE PRECISION C BIR,BII- COMPLEX ANSWER DEPENDING ON THE CHOICES FOR ID AND C KODE C IERR - ERROR FLAG C IERR=0, NORMAL RETURN - COMPUTATION COMPLETED C IERR=1, INPUT ERROR - NO COMPUTATION C IERR=2, OVERFLOW - NO COMPUTATION, REAL(Z) C TOO LARGE ON KODE=1 C IERR=3, CABS(Z) LARGE - COMPUTATION COMPLETED C LOSSES OF SIGNIFCANCE BY ARGUMENT REDUCTION C PRODUCE LESS THAN HALF OF MACHINE ACCURACY C IERR=4, CABS(Z) TOO LARGE - NO COMPUTATION C COMPLETE LOSS OF ACCURACY BY ARGUMENT C REDUCTION C IERR=5, ERROR - NO COMPUTATION, C ALGORITHM TERMINATION CONDITION NOT MET C C***LONG DESCRIPTION C C BI AND DBI ARE COMPUTED FOR CABS(Z).GT.1.0 FROM THE I BESSEL C FUNCTIONS BY C C BI(Z)=C*SQRT(Z)*( I(-1/3,ZTA) + I(1/3,ZTA) ) C DBI(Z)=C * Z * ( I(-2/3,ZTA) + I(2/3,ZTA) ) C C=1.0/SQRT(3.0) C ZTA=(2/3)*Z**(3/2) C C WITH THE POWER SERIES FOR CABS(Z).LE.1.0. C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z IS LARGE, LOSSES C OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. CONSEQUENTLY, IF C THE MAGNITUDE OF ZETA=(2/3)*Z**1.5 EXCEEDS U1=SQRT(0.5/UR), C THEN LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR C FLAG IERR=3 IS TRIGGERED WHERE UR=DMAX1(D1MACH(4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C ALSO, IF THE MAGNITUDE OF ZETA IS LARGER THAN U2=0.5/UR, THEN C ALL SIGNIFICANCE IS LOST AND IERR=4. IN ORDER TO USE THE INT C FUNCTION, ZETA MUST BE FURTHER RESTRICTED NOT TO EXCEED THE C LARGEST INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF ZETA C MUST BE RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, C AND U3 ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE C PRECISION ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE C PRECISION ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMIT- C ING IN THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT THE MAG- C NITUDE OF Z CANNOT EXCEED 3.1E+4 IN SINGLE AND 2.1E+6 IN C DOUBLE PRECISION ARITHMETIC. THIS ALSO MEANS THAT ONE CAN C EXPECT TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, C NO DIGITS IN SINGLE PRECISION AND ONLY 7 DIGITS IN DOUBLE C PRECISION ARITHMETIC. SIMILAR CONSIDERATIONS HOLD FOR OTHER C MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. IF ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 C C***ROUTINES CALLED ZBINU,ZABS,ZDIV,ZSQRT,D1MACH,I1MACH C***END PROLOGUE ZBIRY C COMPLEX BI,CONE,CSQ,CY,S1,S2,TRM1,TRM2,Z,ZTA,Z3 DOUBLE PRECISION AA, AD, AK, ALIM, ATRM, AZ, AZ3, BB, BII, BIR, * BK, CC, CK, COEF, CONEI, CONER, CSQI, CSQR, CYI, CYR, C1, C2, * DIG, DK, D1, D2, EAA, ELIM, FID, FMR, FNU, FNUL, PI, RL, R1M5, * SFAC, STI, STR, S1I, S1R, S2I, S2R, TOL, TRM1I, TRM1R, TRM2I, * TRM2R, TTH, ZI, ZR, ZTAI, ZTAR, Z3I, Z3R, D1MACH, ZABS INTEGER ID, IERR, K, KODE, K1, K2, NZ, I1MACH DIMENSION CYR(2), CYI(2) DATA TTH, C1, C2, COEF, PI /6.66666666666666667D-01, * 6.14926627446000736D-01,4.48288357353826359D-01, * 5.77350269189625765D-01,3.14159265358979324D+00/ DATA CONER, CONEI /1.0D0,0.0D0/ C***FIRST EXECUTABLE STATEMENT ZBIRY IERR = 0 NZ=0 IF (ID.LT.0 .OR. ID.GT.1) IERR=1 IF (KODE.LT.1 .OR. KODE.GT.2) IERR=1 IF (IERR.NE.0) RETURN AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) TOL = DMAX1(D1MACH(4),1.0D-18) FID = DBLE(FLOAT(ID)) IF (AZ.GT.1.0E0) GO TO 70 C----------------------------------------------------------------------- C POWER SERIES FOR CABS(Z).LE.1. C----------------------------------------------------------------------- S1R = CONER S1I = CONEI S2R = CONER S2I = CONEI IF (AZ.LT.TOL) GO TO 130 AA = AZ*AZ IF (AA.LT.TOL/AZ) GO TO 40 TRM1R = CONER TRM1I = CONEI TRM2R = CONER TRM2I = CONEI ATRM = 1.0D0 STR = ZR*ZR - ZI*ZI STI = ZR*ZI + ZI*ZR Z3R = STR*ZR - STI*ZI Z3I = STR*ZI + STI*ZR AZ3 = AZ*AA AK = 2.0D0 + FID BK = 3.0D0 - FID - FID CK = 4.0D0 - FID DK = 3.0D0 + FID + FID D1 = AK*DK D2 = BK*CK AD = DMIN1(D1,D2) AK = 24.0D0 + 9.0D0*FID BK = 30.0D0 - 9.0D0*FID DO 30 K=1,25 STR = (TRM1R*Z3R-TRM1I*Z3I)/D1 TRM1I = (TRM1R*Z3I+TRM1I*Z3R)/D1 TRM1R = STR S1R = S1R + TRM1R S1I = S1I + TRM1I STR = (TRM2R*Z3R-TRM2I*Z3I)/D2 TRM2I = (TRM2R*Z3I+TRM2I*Z3R)/D2 TRM2R = STR S2R = S2R + TRM2R S2I = S2I + TRM2I ATRM = ATRM*AZ3/AD D1 = D1 + AK D2 = D2 + BK AD = DMIN1(D1,D2) IF (ATRM.LT.TOL*AD) GO TO 40 AK = AK + 18.0D0 BK = BK + 18.0D0 30 CONTINUE 40 CONTINUE IF (ID.EQ.1) GO TO 50 BIR = C1*S1R + C2*(ZR*S2R-ZI*S2I) BII = C1*S1I + C2*(ZR*S2I+ZI*S2R) IF (KODE.EQ.1) RETURN CALL ZSQRT(ZR, ZI, STR, STI) ZTAR = TTH*(ZR*STR-ZI*STI) ZTAI = TTH*(ZR*STI+ZI*STR) AA = ZTAR AA = -DABS(AA) EAA = DEXP(AA) BIR = BIR*EAA BII = BII*EAA RETURN 50 CONTINUE BIR = S2R*C2 BII = S2I*C2 IF (AZ.LE.TOL) GO TO 60 CC = C1/(1.0D0+FID) STR = S1R*ZR - S1I*ZI STI = S1R*ZI + S1I*ZR BIR = BIR + CC*(STR*ZR-STI*ZI) BII = BII + CC*(STR*ZI+STI*ZR) 60 CONTINUE IF (KODE.EQ.1) RETURN CALL ZSQRT(ZR, ZI, STR, STI) ZTAR = TTH*(ZR*STR-ZI*STI) ZTAI = TTH*(ZR*STI+ZI*STR) AA = ZTAR AA = -DABS(AA) EAA = DEXP(AA) BIR = BIR*EAA BII = BII*EAA RETURN C----------------------------------------------------------------------- C CASE FOR CABS(Z).GT.1.0 C----------------------------------------------------------------------- 70 CONTINUE FNU = (1.0D0+FID)/3.0D0 C----------------------------------------------------------------------- C SET PARAMETERS RELATED TO MACHINE CONSTANTS. C TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0E-18. C ELIM IS THE APPROXIMATE EXPONENTIAL OVER- AND UNDERFLOW LIMIT. C EXP(-ELIM).LT.EXP(-ALIM)=EXP(-ELIM)/TOL AND C EXP(ELIM).GT.EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR C UNDERFLOW AND OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. C RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LARGE Z. C DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). C FNUL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC SERIES FOR LARGE FNU. C----------------------------------------------------------------------- K1 = I1MACH(15) K2 = I1MACH(16) R1M5 = D1MACH(5) K = MIN0(IABS(K1),IABS(K2)) ELIM = 2.303D0*(DBLE(FLOAT(K))*R1M5-3.0D0) K1 = I1MACH(14) - 1 AA = R1M5*DBLE(FLOAT(K1)) DIG = DMIN1(AA,18.0D0) AA = AA*2.303D0 ALIM = ELIM + DMAX1(-AA,-41.45D0) RL = 1.2D0*DIG + 3.0D0 FNUL = 10.0D0 + 6.0D0*(DIG-3.0D0) C----------------------------------------------------------------------- C TEST FOR RANGE C----------------------------------------------------------------------- AA=0.5D0/TOL BB=DBLE(FLOAT(I1MACH(9)))*0.5D0 AA=DMIN1(AA,BB) AA=AA**TTH IF (AZ.GT.AA) GO TO 260 AA=DSQRT(AA) IF (AZ.GT.AA) IERR=3 CALL ZSQRT(ZR, ZI, CSQR, CSQI) ZTAR = TTH*(ZR*CSQR-ZI*CSQI) ZTAI = TTH*(ZR*CSQI+ZI*CSQR) C----------------------------------------------------------------------- C RE(ZTA).LE.0 WHEN RE(Z).LT.0, ESPECIALLY WHEN IM(Z) IS SMALL C----------------------------------------------------------------------- SFAC = 1.0D0 AK = ZTAI IF (ZR.GE.0.0D0) GO TO 80 BK = ZTAR CK = -DABS(BK) ZTAR = CK ZTAI = AK 80 CONTINUE IF (ZI.NE.0.0D0 .OR. ZR.GT.0.0D0) GO TO 90 ZTAR = 0.0D0 ZTAI = AK 90 CONTINUE AA = ZTAR IF (KODE.EQ.2) GO TO 100 C----------------------------------------------------------------------- C OVERFLOW TEST C----------------------------------------------------------------------- BB = DABS(AA) IF (BB.LT.ALIM) GO TO 100 BB = BB + 0.25D0*DLOG(AZ) SFAC = TOL IF (BB.GT.ELIM) GO TO 190 100 CONTINUE FMR = 0.0D0 IF (AA.GE.0.0D0 .AND. ZR.GT.0.0D0) GO TO 110 FMR = PI IF (ZI.LT.0.0D0) FMR = -PI ZTAR = -ZTAR ZTAI = -ZTAI 110 CONTINUE C----------------------------------------------------------------------- C AA=FACTOR FOR ANALYTIC CONTINUATION OF I(FNU,ZTA) C KODE=2 RETURNS EXP(-ABS(XZTA))*I(FNU,ZTA) FROM CBESI C----------------------------------------------------------------------- CALL ZBINU(ZTAR, ZTAI, FNU, KODE, 1, CYR, CYI, NZ, RL, FNUL, TOL, * ELIM, ALIM) IF (NZ.LT.0) GO TO 200 AA = FMR*FNU Z3R = SFAC STR = DCOS(AA) STI = DSIN(AA) S1R = (STR*CYR(1)-STI*CYI(1))*Z3R S1I = (STR*CYI(1)+STI*CYR(1))*Z3R FNU = (2.0D0-FID)/3.0D0 CALL ZBINU(ZTAR, ZTAI, FNU, KODE, 2, CYR, CYI, NZ, RL, FNUL, TOL, * ELIM, ALIM) CYR(1) = CYR(1)*Z3R CYI(1) = CYI(1)*Z3R CYR(2) = CYR(2)*Z3R CYI(2) = CYI(2)*Z3R C----------------------------------------------------------------------- C BACKWARD RECUR ONE STEP FOR ORDERS -1/3 OR -2/3 C----------------------------------------------------------------------- CALL ZDIV(CYR(1), CYI(1), ZTAR, ZTAI, STR, STI) S2R = (FNU+FNU)*STR + CYR(2) S2I = (FNU+FNU)*STI + CYI(2) AA = FMR*(FNU-1.0D0) STR = DCOS(AA) STI = DSIN(AA) S1R = COEF*(S1R+S2R*STR-S2I*STI) S1I = COEF*(S1I+S2R*STI+S2I*STR) IF (ID.EQ.1) GO TO 120 STR = CSQR*S1R - CSQI*S1I S1I = CSQR*S1I + CSQI*S1R S1R = STR BIR = S1R/SFAC BII = S1I/SFAC RETURN 120 CONTINUE STR = ZR*S1R - ZI*S1I S1I = ZR*S1I + ZI*S1R S1R = STR BIR = S1R/SFAC BII = S1I/SFAC RETURN 130 CONTINUE AA = C1*(1.0D0-FID) + FID*C2 BIR = AA BII = 0.0D0 RETURN 190 CONTINUE IERR=2 NZ=0 RETURN 200 CONTINUE IF(NZ.EQ.(-1)) GO TO 190 NZ=0 IERR=5 RETURN 260 CONTINUE IERR=4 NZ=0 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbknu.f000066400000000000000000000413461450372207100250210ustar00rootroot00000000000000 SUBROUTINE ZBKNU(ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, * ALIM) C***BEGIN PROLOGUE ZBKNU C***REFER TO ZBESI,ZBESK,ZAIRY,ZBESH C C ZBKNU COMPUTES THE K BESSEL FUNCTION IN THE RIGHT HALF Z PLANE. C C***ROUTINES CALLED DGAMLN,I1MACH,D1MACH,ZKSCL,ZSHCH,ZUCHK,ZABS,ZDIV, C ZEXP,ZLOG,ZMLT,ZSQRT C***END PROLOGUE ZBKNU C DOUBLE PRECISION AA, AK, ALIM, ASCLE, A1, A2, BB, BK, BRY, CAZ, * CBI, CBR, CC, CCHI, CCHR, CKI, CKR, COEFI, COEFR, CONEI, CONER, * CRSCR, CSCLR, CSHI, CSHR, CSI, CSR, CSRR, CSSR, CTWOR, * CZEROI, CZEROR, CZI, CZR, DNU, DNU2, DPI, ELIM, ETEST, FC, FHS, * FI, FK, FKS, FMUI, FMUR, FNU, FPI, FR, G1, G2, HPI, PI, PR, PTI, * PTR, P1I, P1R, P2I, P2M, P2R, QI, QR, RAK, RCAZ, RTHPI, RZI, * RZR, R1, S, SMUI, SMUR, SPI, STI, STR, S1I, S1R, S2I, S2R, TM, * TOL, TTH, T1, T2, YI, YR, ZI, ZR, DGAMLN, D1MACH, ZABS, ELM, * CELMR, ZDR, ZDI, AS, ALAS, HELIM, CYR, CYI INTEGER I, IFLAG, INU, K, KFLAG, KK, KMAX, KODE, KODED, N, NZ, * IDUM, I1MACH, J, IC, INUB, NW DIMENSION YR(N), YI(N), CC(8), CSSR(3), CSRR(3), BRY(3), CYR(2), * CYI(2) C COMPLEX Z,Y,A,B,RZ,SMU,FU,FMU,F,FLRZ,CZ,S1,S2,CSH,CCH C COMPLEX CK,P,Q,COEF,P1,P2,CBK,PT,CZERO,CONE,CTWO,ST,EZ,CS,DK C DATA KMAX / 30 / DATA CZEROR,CZEROI,CONER,CONEI,CTWOR,R1/ 1 0.0D0 , 0.0D0 , 1.0D0 , 0.0D0 , 2.0D0 , 2.0D0 / DATA DPI, RTHPI, SPI ,HPI, FPI, TTH / 1 3.14159265358979324D0, 1.25331413731550025D0, 2 1.90985931710274403D0, 1.57079632679489662D0, 3 1.89769999331517738D0, 6.66666666666666666D-01/ DATA CC(1), CC(2), CC(3), CC(4), CC(5), CC(6), CC(7), CC(8)/ 1 5.77215664901532861D-01, -4.20026350340952355D-02, 2 -4.21977345555443367D-02, 7.21894324666309954D-03, 3 -2.15241674114950973D-04, -2.01348547807882387D-05, 4 1.13302723198169588D-06, 6.11609510448141582D-09/ C CAZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) CSCLR = 1.0D0/TOL CRSCR = TOL CSSR(1) = CSCLR CSSR(2) = 1.0D0 CSSR(3) = CRSCR CSRR(1) = CRSCR CSRR(2) = 1.0D0 CSRR(3) = CSCLR BRY(1) = 1.0D+3*D1MACH(1)/TOL BRY(2) = 1.0D0/BRY(1) BRY(3) = D1MACH(2) NZ = 0 IFLAG = 0 KODED = KODE RCAZ = 1.0D0/CAZ STR = ZR*RCAZ STI = -ZI*RCAZ RZR = (STR+STR)*RCAZ RZI = (STI+STI)*RCAZ INU = INT(SNGL(FNU+0.5D0)) DNU = FNU - DBLE(FLOAT(INU)) IF (DABS(DNU).EQ.0.5D0) GO TO 110 DNU2 = 0.0D0 IF (DABS(DNU).GT.TOL) DNU2 = DNU*DNU IF (CAZ.GT.R1) GO TO 110 C----------------------------------------------------------------------- C SERIES FOR CABS(Z).LE.R1 C----------------------------------------------------------------------- FC = 1.0D0 CALL ZLOG(RZR, RZI, SMUR, SMUI, IDUM) FMUR = SMUR*DNU FMUI = SMUI*DNU CALL ZSHCH(FMUR, FMUI, CSHR, CSHI, CCHR, CCHI) IF (DNU.EQ.0.0D0) GO TO 10 FC = DNU*DPI FC = FC/DSIN(FC) SMUR = CSHR/DNU SMUI = CSHI/DNU 10 CONTINUE A2 = 1.0D0 + DNU C----------------------------------------------------------------------- C GAM(1-Z)*GAM(1+Z)=PI*Z/SIN(PI*Z), T1=1/GAM(1-DNU), T2=1/GAM(1+DNU) C----------------------------------------------------------------------- T2 = DEXP(-DGAMLN(A2,IDUM)) T1 = 1.0D0/(T2*FC) IF (DABS(DNU).GT.0.1D0) GO TO 40 C----------------------------------------------------------------------- C SERIES FOR F0 TO RESOLVE INDETERMINACY FOR SMALL ABS(DNU) C----------------------------------------------------------------------- AK = 1.0D0 S = CC(1) DO 20 K=2,8 AK = AK*DNU2 TM = CC(K)*AK S = S + TM IF (DABS(TM).LT.TOL) GO TO 30 20 CONTINUE 30 G1 = -S GO TO 50 40 CONTINUE G1 = (T1-T2)/(DNU+DNU) 50 CONTINUE G2 = (T1+T2)*0.5D0 FR = FC*(CCHR*G1+SMUR*G2) FI = FC*(CCHI*G1+SMUI*G2) CALL ZEXP(FMUR, FMUI, STR, STI) PR = 0.5D0*STR/T2 PI = 0.5D0*STI/T2 CALL ZDIV(0.5D0, 0.0D0, STR, STI, PTR, PTI) QR = PTR/T1 QI = PTI/T1 S1R = FR S1I = FI S2R = PR S2I = PI AK = 1.0D0 A1 = 1.0D0 CKR = CONER CKI = CONEI BK = 1.0D0 - DNU2 IF (INU.GT.0 .OR. N.GT.1) GO TO 80 C----------------------------------------------------------------------- C GENERATE K(FNU,Z), 0.0D0 .LE. FNU .LT. 0.5D0 AND N=1 C----------------------------------------------------------------------- IF (CAZ.LT.TOL) GO TO 70 CALL ZMLT(ZR, ZI, ZR, ZI, CZR, CZI) CZR = 0.25D0*CZR CZI = 0.25D0*CZI T1 = 0.25D0*CAZ*CAZ 60 CONTINUE FR = (FR*AK+PR+QR)/BK FI = (FI*AK+PI+QI)/BK STR = 1.0D0/(AK-DNU) PR = PR*STR PI = PI*STR STR = 1.0D0/(AK+DNU) QR = QR*STR QI = QI*STR STR = CKR*CZR - CKI*CZI RAK = 1.0D0/AK CKI = (CKR*CZI+CKI*CZR)*RAK CKR = STR*RAK S1R = CKR*FR - CKI*FI + S1R S1I = CKR*FI + CKI*FR + S1I A1 = A1*T1*RAK BK = BK + AK + AK + 1.0D0 AK = AK + 1.0D0 IF (A1.GT.TOL) GO TO 60 70 CONTINUE YR(1) = S1R YI(1) = S1I IF (KODED.EQ.1) RETURN CALL ZEXP(ZR, ZI, STR, STI) CALL ZMLT(S1R, S1I, STR, STI, YR(1), YI(1)) RETURN C----------------------------------------------------------------------- C GENERATE K(DNU,Z) AND K(DNU+1,Z) FOR FORWARD RECURRENCE C----------------------------------------------------------------------- 80 CONTINUE IF (CAZ.LT.TOL) GO TO 100 CALL ZMLT(ZR, ZI, ZR, ZI, CZR, CZI) CZR = 0.25D0*CZR CZI = 0.25D0*CZI T1 = 0.25D0*CAZ*CAZ 90 CONTINUE FR = (FR*AK+PR+QR)/BK FI = (FI*AK+PI+QI)/BK STR = 1.0D0/(AK-DNU) PR = PR*STR PI = PI*STR STR = 1.0D0/(AK+DNU) QR = QR*STR QI = QI*STR STR = CKR*CZR - CKI*CZI RAK = 1.0D0/AK CKI = (CKR*CZI+CKI*CZR)*RAK CKR = STR*RAK S1R = CKR*FR - CKI*FI + S1R S1I = CKR*FI + CKI*FR + S1I STR = PR - FR*AK STI = PI - FI*AK S2R = CKR*STR - CKI*STI + S2R S2I = CKR*STI + CKI*STR + S2I A1 = A1*T1*RAK BK = BK + AK + AK + 1.0D0 AK = AK + 1.0D0 IF (A1.GT.TOL) GO TO 90 100 CONTINUE KFLAG = 2 A1 = FNU + 1.0D0 AK = A1*DABS(SMUR) IF (AK.GT.ALIM) KFLAG = 3 STR = CSSR(KFLAG) P2R = S2R*STR P2I = S2I*STR CALL ZMLT(P2R, P2I, RZR, RZI, S2R, S2I) S1R = S1R*STR S1I = S1I*STR IF (KODED.EQ.1) GO TO 210 CALL ZEXP(ZR, ZI, FR, FI) CALL ZMLT(S1R, S1I, FR, FI, S1R, S1I) CALL ZMLT(S2R, S2I, FR, FI, S2R, S2I) GO TO 210 C----------------------------------------------------------------------- C IFLAG=0 MEANS NO UNDERFLOW OCCURRED C IFLAG=1 MEANS AN UNDERFLOW OCCURRED- COMPUTATION PROCEEDS WITH C KODED=2 AND A TEST FOR ON SCALE VALUES IS MADE DURING FORWARD C RECURSION C----------------------------------------------------------------------- 110 CONTINUE CALL ZSQRT(ZR, ZI, STR, STI) CALL ZDIV(RTHPI, CZEROI, STR, STI, COEFR, COEFI) KFLAG = 2 IF (KODED.EQ.2) GO TO 120 IF (ZR.GT.ALIM) GO TO 290 C BLANK LINE STR = DEXP(-ZR)*CSSR(KFLAG) STI = -STR*DSIN(ZI) STR = STR*DCOS(ZI) CALL ZMLT(COEFR, COEFI, STR, STI, COEFR, COEFI) 120 CONTINUE IF (DABS(DNU).EQ.0.5D0) GO TO 300 C----------------------------------------------------------------------- C MILLER ALGORITHM FOR CABS(Z).GT.R1 C----------------------------------------------------------------------- AK = DCOS(DPI*DNU) AK = DABS(AK) IF (AK.EQ.CZEROR) GO TO 300 FHS = DABS(0.25D0-DNU2) IF (FHS.EQ.CZEROR) GO TO 300 C----------------------------------------------------------------------- C COMPUTE R2=F(E). IF CABS(Z).GE.R2, USE FORWARD RECURRENCE TO C DETERMINE THE BACKWARD INDEX K. R2=F(E) IS A STRAIGHT LINE ON C 12.LE.E.LE.60. E IS COMPUTED FROM 2**(-E)=B**(1-I1MACH(14))= C TOL WHERE B IS THE BASE OF THE ARITHMETIC. C----------------------------------------------------------------------- T1 = DBLE(FLOAT(I1MACH(14)-1)) T1 = T1*D1MACH(5)*3.321928094D0 T1 = DMAX1(T1,12.0D0) T1 = DMIN1(T1,60.0D0) T2 = TTH*T1 - 6.0D0 IF (ZR.NE.0.0D0) GO TO 130 T1 = HPI GO TO 140 130 CONTINUE T1 = DATAN(ZI/ZR) T1 = DABS(T1) 140 CONTINUE IF (T2.GT.CAZ) GO TO 170 C----------------------------------------------------------------------- C FORWARD RECURRENCE LOOP WHEN CABS(Z).GE.R2 C----------------------------------------------------------------------- ETEST = AK/(DPI*CAZ*TOL) FK = CONER IF (ETEST.LT.CONER) GO TO 180 FKS = CTWOR CKR = CAZ + CAZ + CTWOR P1R = CZEROR P2R = CONER DO 150 I=1,KMAX AK = FHS/FKS CBR = CKR/(FK+CONER) PTR = P2R P2R = CBR*P2R - P1R*AK P1R = PTR CKR = CKR + CTWOR FKS = FKS + FK + FK + CTWOR FHS = FHS + FK + FK FK = FK + CONER STR = DABS(P2R)*FK IF (ETEST.LT.STR) GO TO 160 150 CONTINUE GO TO 310 160 CONTINUE FK = FK + SPI*T1*DSQRT(T2/CAZ) FHS = DABS(0.25D0-DNU2) GO TO 180 170 CONTINUE C----------------------------------------------------------------------- C COMPUTE BACKWARD INDEX K FOR CABS(Z).LT.R2 C----------------------------------------------------------------------- A2 = DSQRT(CAZ) AK = FPI*AK/(TOL*DSQRT(A2)) AA = 3.0D0*T1/(1.0D0+CAZ) BB = 14.7D0*T1/(28.0D0+CAZ) AK = (DLOG(AK)+CAZ*DCOS(AA)/(1.0D0+0.008D0*CAZ))/DCOS(BB) FK = 0.12125D0*AK*AK/CAZ + 1.5D0 180 CONTINUE C----------------------------------------------------------------------- C BACKWARD RECURRENCE LOOP FOR MILLER ALGORITHM C----------------------------------------------------------------------- K = INT(SNGL(FK)) FK = DBLE(FLOAT(K)) FKS = FK*FK P1R = CZEROR P1I = CZEROI P2R = TOL P2I = CZEROI CSR = P2R CSI = P2I DO 190 I=1,K A1 = FKS - FK AK = (FKS+FK)/(A1+FHS) RAK = 2.0D0/(FK+CONER) CBR = (FK+ZR)*RAK CBI = ZI*RAK PTR = P2R PTI = P2I P2R = (PTR*CBR-PTI*CBI-P1R)*AK P2I = (PTI*CBR+PTR*CBI-P1I)*AK P1R = PTR P1I = PTI CSR = CSR + P2R CSI = CSI + P2I FKS = A1 - FK + CONER FK = FK - CONER 190 CONTINUE C----------------------------------------------------------------------- C COMPUTE (P2/CS)=(P2/CABS(CS))*(CONJG(CS)/CABS(CS)) FOR BETTER C SCALING C----------------------------------------------------------------------- TM = ZABS(CMPLX(CSR,CSI,kind=KIND(1.0D0))) PTR = 1.0D0/TM S1R = P2R*PTR S1I = P2I*PTR CSR = CSR*PTR CSI = -CSI*PTR CALL ZMLT(COEFR, COEFI, S1R, S1I, STR, STI) CALL ZMLT(STR, STI, CSR, CSI, S1R, S1I) IF (INU.GT.0 .OR. N.GT.1) GO TO 200 ZDR = ZR ZDI = ZI IF(IFLAG.EQ.1) GO TO 270 GO TO 240 200 CONTINUE C----------------------------------------------------------------------- C COMPUTE P1/P2=(P1/CABS(P2)*CONJG(P2)/CABS(P2) FOR SCALING C----------------------------------------------------------------------- TM = ZABS(CMPLX(P2R,P2I,kind=KIND(1.0D0))) PTR = 1.0D0/TM P1R = P1R*PTR P1I = P1I*PTR P2R = P2R*PTR P2I = -P2I*PTR CALL ZMLT(P1R, P1I, P2R, P2I, PTR, PTI) STR = DNU + 0.5D0 - PTR STI = -PTI CALL ZDIV(STR, STI, ZR, ZI, STR, STI) STR = STR + 1.0D0 CALL ZMLT(STR, STI, S1R, S1I, S2R, S2I) C----------------------------------------------------------------------- C FORWARD RECURSION ON THE THREE TERM RECURSION WITH RELATION WITH C SCALING NEAR EXPONENT EXTREMES ON KFLAG=1 OR KFLAG=3 C----------------------------------------------------------------------- 210 CONTINUE STR = DNU + 1.0D0 CKR = STR*RZR CKI = STR*RZI IF (N.EQ.1) INU = INU - 1 IF (INU.GT.0) GO TO 220 IF (N.GT.1) GO TO 215 S1R = S2R S1I = S2I 215 CONTINUE ZDR = ZR ZDI = ZI IF(IFLAG.EQ.1) GO TO 270 GO TO 240 220 CONTINUE INUB = 1 IF(IFLAG.EQ.1) GO TO 261 225 CONTINUE P1R = CSRR(KFLAG) ASCLE = BRY(KFLAG) DO 230 I=INUB,INU STR = S2R STI = S2I S2R = CKR*STR - CKI*STI + S1R S2I = CKR*STI + CKI*STR + S1I S1R = STR S1I = STI CKR = CKR + RZR CKI = CKI + RZI IF (KFLAG.GE.3) GO TO 230 P2R = S2R*P1R P2I = S2I*P1R STR = DABS(P2R) STI = DABS(P2I) P2M = DMAX1(STR,STI) IF (P2M.LE.ASCLE) GO TO 230 KFLAG = KFLAG + 1 ASCLE = BRY(KFLAG) S1R = S1R*P1R S1I = S1I*P1R S2R = P2R S2I = P2I STR = CSSR(KFLAG) S1R = S1R*STR S1I = S1I*STR S2R = S2R*STR S2I = S2I*STR P1R = CSRR(KFLAG) 230 CONTINUE IF (N.NE.1) GO TO 240 S1R = S2R S1I = S2I 240 CONTINUE STR = CSRR(KFLAG) YR(1) = S1R*STR YI(1) = S1I*STR IF (N.EQ.1) RETURN YR(2) = S2R*STR YI(2) = S2I*STR IF (N.EQ.2) RETURN KK = 2 250 CONTINUE KK = KK + 1 IF (KK.GT.N) RETURN P1R = CSRR(KFLAG) ASCLE = BRY(KFLAG) DO 260 I=KK,N P2R = S2R P2I = S2I S2R = CKR*P2R - CKI*P2I + S1R S2I = CKI*P2R + CKR*P2I + S1I S1R = P2R S1I = P2I CKR = CKR + RZR CKI = CKI + RZI P2R = S2R*P1R P2I = S2I*P1R YR(I) = P2R YI(I) = P2I IF (KFLAG.GE.3) GO TO 260 STR = DABS(P2R) STI = DABS(P2I) P2M = DMAX1(STR,STI) IF (P2M.LE.ASCLE) GO TO 260 KFLAG = KFLAG + 1 ASCLE = BRY(KFLAG) S1R = S1R*P1R S1I = S1I*P1R S2R = P2R S2I = P2I STR = CSSR(KFLAG) S1R = S1R*STR S1I = S1I*STR S2R = S2R*STR S2I = S2I*STR P1R = CSRR(KFLAG) 260 CONTINUE RETURN C----------------------------------------------------------------------- C IFLAG=1 CASES, FORWARD RECURRENCE ON SCALED VALUES ON UNDERFLOW C----------------------------------------------------------------------- 261 CONTINUE HELIM = 0.5D0*ELIM ELM = DEXP(-ELIM) CELMR = ELM ASCLE = BRY(1) ZDR = ZR ZDI = ZI IC = -1 J = 2 DO 262 I=1,INU STR = S2R STI = S2I S2R = STR*CKR-STI*CKI+S1R S2I = STI*CKR+STR*CKI+S1I S1R = STR S1I = STI CKR = CKR+RZR CKI = CKI+RZI AS = ZABS(CMPLX(S2R,S2I,kind=KIND(1.0D0))) ALAS = DLOG(AS) P2R = -ZDR+ALAS IF(P2R.LT.(-ELIM)) GO TO 263 CALL ZLOG(S2R,S2I,STR,STI,IDUM) P2R = -ZDR+STR P2I = -ZDI+STI P2M = DEXP(P2R)/TOL P1R = P2M*DCOS(P2I) P1I = P2M*DSIN(P2I) CALL ZUCHK(P1R,P1I,NW,ASCLE,TOL) IF(NW.NE.0) GO TO 263 J = 3 - J CYR(J) = P1R CYI(J) = P1I IF(IC.EQ.(I-1)) GO TO 264 IC = I GO TO 262 263 CONTINUE IF(ALAS.LT.HELIM) GO TO 262 ZDR = ZDR-ELIM S1R = S1R*CELMR S1I = S1I*CELMR S2R = S2R*CELMR S2I = S2I*CELMR 262 CONTINUE IF(N.NE.1) GO TO 270 S1R = S2R S1I = S2I GO TO 270 264 CONTINUE KFLAG = 1 INUB = I+1 S2R = CYR(J) S2I = CYI(J) J = 3 - J S1R = CYR(J) S1I = CYI(J) IF(INUB.LE.INU) GO TO 225 IF(N.NE.1) GO TO 240 S1R = S2R S1I = S2I GO TO 240 270 CONTINUE YR(1) = S1R YI(1) = S1I IF(N.EQ.1) GO TO 280 YR(2) = S2R YI(2) = S2I 280 CONTINUE ASCLE = BRY(1) CALL ZKSCL(ZDR,ZDI,FNU,N,YR,YI,NZ,RZR,RZI,ASCLE,TOL,ELIM) INU = N - NZ IF (INU.LE.0) RETURN KK = NZ + 1 S1R = YR(KK) S1I = YI(KK) YR(KK) = S1R*CSRR(1) YI(KK) = S1I*CSRR(1) IF (INU.EQ.1) RETURN KK = NZ + 2 S2R = YR(KK) S2I = YI(KK) YR(KK) = S2R*CSRR(1) YI(KK) = S2I*CSRR(1) IF (INU.EQ.2) RETURN T2 = FNU + DBLE(FLOAT(KK-1)) CKR = T2*RZR CKI = T2*RZI KFLAG = 1 GO TO 250 290 CONTINUE C----------------------------------------------------------------------- C SCALE BY DEXP(Z), IFLAG = 1 CASES C----------------------------------------------------------------------- KODED = 2 IFLAG = 1 KFLAG = 2 GO TO 120 C----------------------------------------------------------------------- C FNU=HALF ODD INTEGER CASE, DNU=-0.5 C----------------------------------------------------------------------- 300 CONTINUE S1R = COEFR S1I = COEFI S2R = COEFR S2I = COEFI GO TO 210 C C 310 CONTINUE NZ=-2 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbuni.f000066400000000000000000000125721450372207100250160ustar00rootroot00000000000000 SUBROUTINE ZBUNI(ZR, ZI, FNU, KODE, N, YR, YI, NZ, NUI, NLAST, * FNUL, TOL, ELIM, ALIM) C***BEGIN PROLOGUE ZBUNI C***REFER TO ZBESI,ZBESK C C ZBUNI COMPUTES THE I BESSEL FUNCTION FOR LARGE CABS(Z).GT. C FNUL AND FNU+N-1.LT.FNUL. THE ORDER IS INCREASED FROM C FNU+N-1 GREATER THAN FNUL BY ADDING NUI AND COMPUTING C ACCORDING TO THE UNIFORM ASYMPTOTIC EXPANSION FOR I(FNU,Z) C ON IFORM=1 AND THE EXPANSION FOR J(FNU,Z) ON IFORM=2 C C***ROUTINES CALLED ZUNI1,ZUNI2,ZABS,D1MACH C***END PROLOGUE ZBUNI C COMPLEX CSCL,CSCR,CY,RZ,ST,S1,S2,Y,Z DOUBLE PRECISION ALIM, AX, AY, CSCLR, CSCRR, CYI, CYR, DFNU, * ELIM, FNU, FNUI, FNUL, GNU, RAZ, RZI, RZR, STI, STR, S1I, S1R, * S2I, S2R, TOL, YI, YR, ZI, ZR, ZABS, ASCLE, BRY, C1R, C1I, C1M, * D1MACH INTEGER I, IFLAG, IFORM, K, KODE, N, NL, NLAST, NUI, NW, NZ DIMENSION YR(N), YI(N), CYR(2), CYI(2), BRY(3) NZ = 0 AX = DABS(ZR)*1.7321D0 AY = DABS(ZI) IFORM = 1 IF (AY.GT.AX) IFORM = 2 IF (NUI.EQ.0) GO TO 60 FNUI = DBLE(FLOAT(NUI)) DFNU = FNU + DBLE(FLOAT(N-1)) GNU = DFNU + FNUI IF (IFORM.EQ.2) GO TO 10 C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR I(FNU,Z) FOR LARGE FNU APPLIED IN C -PI/3.LE.ARG(Z).LE.PI/3 C----------------------------------------------------------------------- CALL ZUNI1(ZR, ZI, GNU, KODE, 2, CYR, CYI, NW, NLAST, FNUL, TOL, * ELIM, ALIM) GO TO 20 10 CONTINUE C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR J(FNU,Z*EXP(M*HPI)) FOR LARGE FNU C APPLIED IN PI/3.LT.ABS(ARG(Z)).LE.PI/2 WHERE M=+I OR -I C AND HPI=PI/2 C----------------------------------------------------------------------- CALL ZUNI2(ZR, ZI, GNU, KODE, 2, CYR, CYI, NW, NLAST, FNUL, TOL, * ELIM, ALIM) 20 CONTINUE IF (NW.LT.0) GO TO 50 IF (NW.NE.0) GO TO 90 STR = ZABS(CMPLX(CYR(1),CYI(1),kind=KIND(1.0D0))) C---------------------------------------------------------------------- C SCALE BACKWARD RECURRENCE, BRY(3) IS DEFINED BUT NEVER USED C---------------------------------------------------------------------- BRY(1)=1.0D+3*D1MACH(1)/TOL BRY(2) = 1.0D0/BRY(1) BRY(3) = BRY(2) IFLAG = 2 ASCLE = BRY(2) CSCLR = 1.0D0 IF (STR.GT.BRY(1)) GO TO 21 IFLAG = 1 ASCLE = BRY(1) CSCLR = 1.0D0/TOL GO TO 25 21 CONTINUE IF (STR.LT.BRY(2)) GO TO 25 IFLAG = 3 ASCLE=BRY(3) CSCLR = TOL 25 CONTINUE CSCRR = 1.0D0/CSCLR S1R = CYR(2)*CSCLR S1I = CYI(2)*CSCLR S2R = CYR(1)*CSCLR S2I = CYI(1)*CSCLR RAZ = 1.0D0/ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) STR = ZR*RAZ STI = -ZI*RAZ RZR = (STR+STR)*RAZ RZI = (STI+STI)*RAZ DO 30 I=1,NUI STR = S2R STI = S2I S2R = (DFNU+FNUI)*(RZR*STR-RZI*STI) + S1R S2I = (DFNU+FNUI)*(RZR*STI+RZI*STR) + S1I S1R = STR S1I = STI FNUI = FNUI - 1.0D0 IF (IFLAG.GE.3) GO TO 30 STR = S2R*CSCRR STI = S2I*CSCRR C1R = DABS(STR) C1I = DABS(STI) C1M = DMAX1(C1R,C1I) IF (C1M.LE.ASCLE) GO TO 30 IFLAG = IFLAG+1 ASCLE = BRY(IFLAG) S1R = S1R*CSCRR S1I = S1I*CSCRR S2R = STR S2I = STI CSCLR = CSCLR*TOL CSCRR = 1.0D0/CSCLR S1R = S1R*CSCLR S1I = S1I*CSCLR S2R = S2R*CSCLR S2I = S2I*CSCLR 30 CONTINUE YR(N) = S2R*CSCRR YI(N) = S2I*CSCRR IF (N.EQ.1) RETURN NL = N - 1 FNUI = DBLE(FLOAT(NL)) K = NL DO 40 I=1,NL STR = S2R STI = S2I S2R = (FNU+FNUI)*(RZR*STR-RZI*STI) + S1R S2I = (FNU+FNUI)*(RZR*STI+RZI*STR) + S1I S1R = STR S1I = STI STR = S2R*CSCRR STI = S2I*CSCRR YR(K) = STR YI(K) = STI FNUI = FNUI - 1.0D0 K = K - 1 IF (IFLAG.GE.3) GO TO 40 C1R = DABS(STR) C1I = DABS(STI) C1M = DMAX1(C1R,C1I) IF (C1M.LE.ASCLE) GO TO 40 IFLAG = IFLAG+1 ASCLE = BRY(IFLAG) S1R = S1R*CSCRR S1I = S1I*CSCRR S2R = STR S2I = STI CSCLR = CSCLR*TOL CSCRR = 1.0D0/CSCLR S1R = S1R*CSCLR S1I = S1I*CSCLR S2R = S2R*CSCLR S2I = S2I*CSCLR 40 CONTINUE RETURN 50 CONTINUE NZ = -1 IF(NW.EQ.(-2)) NZ=-2 RETURN 60 CONTINUE IF (IFORM.EQ.2) GO TO 70 C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR I(FNU,Z) FOR LARGE FNU APPLIED IN C -PI/3.LE.ARG(Z).LE.PI/3 C----------------------------------------------------------------------- CALL ZUNI1(ZR, ZI, FNU, KODE, N, YR, YI, NW, NLAST, FNUL, TOL, * ELIM, ALIM) GO TO 80 70 CONTINUE C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR J(FNU,Z*EXP(M*HPI)) FOR LARGE FNU C APPLIED IN PI/3.LT.ABS(ARG(Z)).LE.PI/2 WHERE M=+I OR -I C AND HPI=PI/2 C----------------------------------------------------------------------- CALL ZUNI2(ZR, ZI, FNU, KODE, N, YR, YI, NW, NLAST, FNUL, TOL, * ELIM, ALIM) 80 CONTINUE IF (NW.LT.0) GO TO 50 NZ = NW RETURN 90 CONTINUE NLAST = N RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zbunk.f000066400000000000000000000025231450372207100250130ustar00rootroot00000000000000 SUBROUTINE ZBUNK(ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, TOL, ELIM, * ALIM) C***BEGIN PROLOGUE ZBUNK C***REFER TO ZBESK,ZBESH C C ZBUNK COMPUTES THE K BESSEL FUNCTION FOR FNU.GT.FNUL. C ACCORDING TO THE UNIFORM ASYMPTOTIC EXPANSION FOR K(FNU,Z) C IN ZUNK1 AND THE EXPANSION FOR H(2,FNU,Z) IN ZUNK2 C C***ROUTINES CALLED ZUNK1,ZUNK2 C***END PROLOGUE ZBUNK C COMPLEX Y,Z DOUBLE PRECISION ALIM, AX, AY, ELIM, FNU, TOL, YI, YR, ZI, ZR INTEGER KODE, MR, N, NZ DIMENSION YR(N), YI(N) NZ = 0 AX = DABS(ZR)*1.7321D0 AY = DABS(ZI) IF (AY.GT.AX) GO TO 10 C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR K(FNU,Z) FOR LARGE FNU APPLIED IN C -PI/3.LE.ARG(Z).LE.PI/3 C----------------------------------------------------------------------- CALL ZUNK1(ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, TOL, ELIM, ALIM) GO TO 20 10 CONTINUE C----------------------------------------------------------------------- C ASYMPTOTIC EXPANSION FOR H(2,FNU,Z*EXP(M*HPI)) FOR LARGE FNU C APPLIED IN PI/3.LT.ABS(ARG(Z)).LE.PI/2 WHERE M=+I OR -I C AND HPI=PI/2 C----------------------------------------------------------------------- CALL ZUNK2(ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, TOL, ELIM, ALIM) 20 CONTINUE RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zdiv.f000066400000000000000000000010011450372207100246240ustar00rootroot00000000000000 SUBROUTINE ZDIV(AR, AI, BR, BI, CR, CI) C***BEGIN PROLOGUE ZDIV C***REFER TO ZBESH,ZBESI,ZBESJ,ZBESK,ZBESY,ZAIRY,ZBIRY C C DOUBLE PRECISION COMPLEX DIVIDE C=A/B. C C***ROUTINES CALLED ZABS C***END PROLOGUE ZDIV DOUBLE PRECISION AR, AI, BR, BI, CR, CI, BM, CA, CB, CC, CD DOUBLE PRECISION ZABS BM = 1.0D0/ZABS(CMPLX(BR,BI,kind=KIND(1.0D0))) CC = BR*BM CD = BI*BM CA = (AR*CC+AI*CD)*BM CB = (AI*CC-AR*CD)*BM CR = CA CI = CB RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zexp.f000066400000000000000000000006221450372207100246460ustar00rootroot00000000000000 SUBROUTINE ZEXP(AR, AI, BR, BI) C***BEGIN PROLOGUE ZEXP C***REFER TO ZBESH,ZBESI,ZBESJ,ZBESK,ZBESY,ZAIRY,ZBIRY C C DOUBLE PRECISION COMPLEX EXPONENTIAL FUNCTION B=EXP(A) C C***ROUTINES CALLED (NONE) C***END PROLOGUE ZEXP DOUBLE PRECISION AR, AI, BR, BI, ZM, CA, CB ZM = DEXP(AR) CA = ZM*DCOS(AI) CB = ZM*DSIN(AI) BR = CA BI = CB RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zkscl.f000066400000000000000000000061151450372207100250110ustar00rootroot00000000000000 SUBROUTINE ZKSCL(ZRR,ZRI,FNU,N,YR,YI,NZ,RZR,RZI,ASCLE,TOL,ELIM) C***BEGIN PROLOGUE ZKSCL C***REFER TO ZBESK C C SET K FUNCTIONS TO ZERO ON UNDERFLOW, CONTINUE RECURRENCE C ON SCALED FUNCTIONS UNTIL TWO MEMBERS COME ON SCALE, THEN C RETURN WITH MIN(NZ+2,N) VALUES SCALED BY 1/TOL. C C***ROUTINES CALLED ZUCHK,ZABS,ZLOG C***END PROLOGUE ZKSCL C COMPLEX CK,CS,CY,CZERO,RZ,S1,S2,Y,ZR,ZD,CELM DOUBLE PRECISION ACS, AS, ASCLE, CKI, CKR, CSI, CSR, CYI, * CYR, ELIM, FN, FNU, RZI, RZR, STR, S1I, S1R, S2I, * S2R, TOL, YI, YR, ZEROI, ZEROR, ZRI, ZRR, ZABS, * ZDR, ZDI, CELMR, ELM, HELIM, ALAS INTEGER I, IC, IDUM, KK, N, NN, NW, NZ DIMENSION YR(N), YI(N), CYR(2), CYI(2) DATA ZEROR,ZEROI / 0.0D0 , 0.0D0 / C NZ = 0 IC = 0 NN = MIN0(2,N) DO 10 I=1,NN S1R = YR(I) S1I = YI(I) CYR(I) = S1R CYI(I) = S1I AS = ZABS(CMPLX(S1R,S1I,kind=KIND(1.0D0))) ACS = -ZRR + DLOG(AS) NZ = NZ + 1 YR(I) = ZEROR YI(I) = ZEROI IF (ACS.LT.(-ELIM)) GO TO 10 CALL ZLOG(S1R, S1I, CSR, CSI, IDUM) CSR = CSR - ZRR CSI = CSI - ZRI STR = DEXP(CSR)/TOL CSR = STR*DCOS(CSI) CSI = STR*DSIN(CSI) CALL ZUCHK(CSR, CSI, NW, ASCLE, TOL) IF (NW.NE.0) GO TO 10 YR(I) = CSR YI(I) = CSI IC = I NZ = NZ - 1 10 CONTINUE IF (N.EQ.1) RETURN IF (IC.GT.1) GO TO 20 YR(1) = ZEROR YI(1) = ZEROI NZ = 2 20 CONTINUE IF (N.EQ.2) RETURN IF (NZ.EQ.0) RETURN FN = FNU + 1.0D0 CKR = FN*RZR CKI = FN*RZI S1R = CYR(1) S1I = CYI(1) S2R = CYR(2) S2I = CYI(2) HELIM = 0.5D0*ELIM ELM = DEXP(-ELIM) CELMR = ELM ZDR = ZRR ZDI = ZRI C C FIND TWO CONSECUTIVE Y VALUES ON SCALE. SCALE RECURRENCE IF C S2 GETS LARGER THAN EXP(ELIM/2) C DO 30 I=3,N KK = I CSR = S2R CSI = S2I S2R = CKR*CSR - CKI*CSI + S1R S2I = CKI*CSR + CKR*CSI + S1I S1R = CSR S1I = CSI CKR = CKR + RZR CKI = CKI + RZI AS = ZABS(CMPLX(S2R,S2I,kind=KIND(1.0D0))) ALAS = DLOG(AS) ACS = -ZDR + ALAS NZ = NZ + 1 YR(I) = ZEROR YI(I) = ZEROI IF (ACS.LT.(-ELIM)) GO TO 25 CALL ZLOG(S2R, S2I, CSR, CSI, IDUM) CSR = CSR - ZDR CSI = CSI - ZDI STR = DEXP(CSR)/TOL CSR = STR*DCOS(CSI) CSI = STR*DSIN(CSI) CALL ZUCHK(CSR, CSI, NW, ASCLE, TOL) IF (NW.NE.0) GO TO 25 YR(I) = CSR YI(I) = CSI NZ = NZ - 1 IF (IC.EQ.KK-1) GO TO 40 IC = KK GO TO 30 25 CONTINUE IF(ALAS.LT.HELIM) GO TO 30 ZDR = ZDR - ELIM S1R = S1R*CELMR S1I = S1I*CELMR S2R = S2R*CELMR S2I = S2I*CELMR 30 CONTINUE NZ = N IF(IC.EQ.N) NZ=N-1 GO TO 45 40 CONTINUE NZ = KK - 2 45 CONTINUE DO 50 I=1,NZ YR(I) = ZEROR YI(I) = ZEROI 50 CONTINUE RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zlog.f000066400000000000000000000022001450372207100246250ustar00rootroot00000000000000 SUBROUTINE ZLOG(AR, AI, BR, BI, IERR) C***BEGIN PROLOGUE ZLOG C***REFER TO ZBESH,ZBESI,ZBESJ,ZBESK,ZBESY,ZAIRY,ZBIRY C C DOUBLE PRECISION COMPLEX LOGARITHM B=CLOG(A) C IERR=0,NORMAL RETURN IERR=1, Z=CMPLX(0.0,0.0) C***ROUTINES CALLED ZABS C***END PROLOGUE ZLOG DOUBLE PRECISION AR, AI, BR, BI, ZM, DTHETA, DPI, DHPI DOUBLE PRECISION ZABS DATA DPI , DHPI / 3.141592653589793238462643383D+0, 1 1.570796326794896619231321696D+0/ C IERR=0 IF (AR.EQ.0.0D+0) GO TO 10 IF (AI.EQ.0.0D+0) GO TO 20 DTHETA = DATAN(AI/AR) IF (DTHETA.LE.0.0D+0) GO TO 40 IF (AR.LT.0.0D+0) DTHETA = DTHETA - DPI GO TO 50 10 IF (AI.EQ.0.0D+0) GO TO 60 BI = DHPI BR = DLOG(DABS(AI)) IF (AI.LT.0.0D+0) BI = -BI RETURN 20 IF (AR.GT.0.0D+0) GO TO 30 BR = DLOG(DABS(AR)) BI = DPI RETURN 30 BR = DLOG(AR) BI = 0.0D+0 RETURN 40 IF (AR.LT.0.0D+0) DTHETA = DTHETA + DPI 50 ZM = ZABS(CMPLX(AR,AI,kind=KIND(1.0D0))) BR = DLOG(ZM) BI = DTHETA RETURN 60 CONTINUE IERR=1 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zmlri.f000066400000000000000000000141161450372207100250200ustar00rootroot00000000000000 SUBROUTINE ZMLRI(ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL) C***BEGIN PROLOGUE ZMLRI C***REFER TO ZBESI,ZBESK C C ZMLRI COMPUTES THE I BESSEL FUNCTION FOR RE(Z).GE.0.0 BY THE C MILLER ALGORITHM NORMALIZED BY A NEUMANN SERIES. C C***ROUTINES CALLED DGAMLN,D1MACH,ZABS,ZEXP,ZLOG,ZMLT C***END PROLOGUE ZMLRI C COMPLEX CK,CNORM,CONE,CTWO,CZERO,PT,P1,P2,RZ,SUM,Y,Z DOUBLE PRECISION ACK, AK, AP, AT, AZ, BK, CKI, CKR, CNORMI, * CNORMR, CONEI, CONER, FKAP, FKK, FLAM, FNF, FNU, PTI, PTR, P1I, * P1R, P2I, P2R, RAZ, RHO, RHO2, RZI, RZR, SCLE, STI, STR, SUMI, * SUMR, TFNF, TOL, TST, YI, YR, ZEROI, ZEROR, ZI, ZR, DGAMLN, * D1MACH, ZABS INTEGER I, IAZ, IDUM, IFNU, INU, ITIME, K, KK, KM, KODE, M, N, NZ DIMENSION YR(N), YI(N) DATA ZEROR,ZEROI,CONER,CONEI / 0.0D0, 0.0D0, 1.0D0, 0.0D0 / SCLE = D1MACH(1)/TOL NZ=0 AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) IAZ = INT(SNGL(AZ)) IFNU = INT(SNGL(FNU)) INU = IFNU + N - 1 AT = DBLE(FLOAT(IAZ)) + 1.0D0 RAZ = 1.0D0/AZ STR = ZR*RAZ STI = -ZI*RAZ CKR = STR*AT*RAZ CKI = STI*AT*RAZ RZR = (STR+STR)*RAZ RZI = (STI+STI)*RAZ P1R = ZEROR P1I = ZEROI P2R = CONER P2I = CONEI ACK = (AT+1.0D0)*RAZ RHO = ACK + DSQRT(ACK*ACK-1.0D0) RHO2 = RHO*RHO TST = (RHO2+RHO2)/((RHO2-1.0D0)*(RHO-1.0D0)) TST = TST/TOL C----------------------------------------------------------------------- C COMPUTE RELATIVE TRUNCATION ERROR INDEX FOR SERIES C----------------------------------------------------------------------- AK = AT DO 10 I=1,80 PTR = P2R PTI = P2I P2R = P1R - (CKR*PTR-CKI*PTI) P2I = P1I - (CKI*PTR+CKR*PTI) P1R = PTR P1I = PTI CKR = CKR + RZR CKI = CKI + RZI AP = ZABS(CMPLX(P2R,P2I,kind=KIND(1.0D0))) IF (AP.GT.TST*AK*AK) THEN GO TO 20 END IF AK = AK + 1.0D0 10 CONTINUE GO TO 110 20 CONTINUE I = I + 1 K = 0 IF (INU.LT.IAZ) GO TO 40 C----------------------------------------------------------------------- C COMPUTE RELATIVE TRUNCATION ERROR FOR RATIOS C----------------------------------------------------------------------- P1R = ZEROR P1I = ZEROI P2R = CONER P2I = CONEI AT = DBLE(FLOAT(INU)) + 1.0D0 STR = ZR*RAZ STI = -ZI*RAZ CKR = STR*AT*RAZ CKI = STI*AT*RAZ ACK = AT*RAZ TST = DSQRT(ACK/TOL) ITIME = 1 DO 30 K=1,80 PTR = P2R PTI = P2I P2R = P1R - (CKR*PTR-CKI*PTI) P2I = P1I - (CKR*PTI+CKI*PTR) P1R = PTR P1I = PTI CKR = CKR + RZR CKI = CKI + RZI AP = ZABS(CMPLX(P2R,P2I,kind=KIND(1.0D0))) IF (AP.LT.TST) GO TO 30 IF (ITIME.EQ.2) GO TO 40 ACK = ZABS(CMPLX(CKR,CKI,kind=KIND(1.0D0))) FLAM = ACK + DSQRT(ACK*ACK-1.0D0) FKAP = AP/ZABS(CMPLX(P1R,P1I,kind=KIND(1.0D0))) RHO = DMIN1(FLAM,FKAP) TST = TST*DSQRT(RHO/(RHO*RHO-1.0D0)) ITIME = 2 30 CONTINUE GO TO 110 40 CONTINUE C----------------------------------------------------------------------- C BACKWARD RECURRENCE AND SUM NORMALIZING RELATION C----------------------------------------------------------------------- K = K + 1 KK = MAX0(I+IAZ,K+INU) FKK = DBLE(FLOAT(KK)) P1R = ZEROR P1I = ZEROI C----------------------------------------------------------------------- C SCALE P2 AND SUM BY SCLE C----------------------------------------------------------------------- P2R = SCLE P2I = ZEROI FNF = FNU - DBLE(FLOAT(IFNU)) TFNF = FNF + FNF BK = DGAMLN(FKK+TFNF+1.0D0,IDUM) - DGAMLN(FKK+1.0D0,IDUM) - * DGAMLN(TFNF+1.0D0,IDUM) BK = DEXP(BK) SUMR = ZEROR SUMI = ZEROI KM = KK - INU DO 50 I=1,KM PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) P1R = PTR P1I = PTI AK = 1.0D0 - TFNF/(FKK+TFNF) ACK = BK*AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0D0 50 CONTINUE YR(N) = P2R YI(N) = P2I IF (N.EQ.1) GO TO 70 DO 60 I=2,N PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) P1R = PTR P1I = PTI AK = 1.0D0 - TFNF/(FKK+TFNF) ACK = BK*AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0D0 M = N - I + 1 YR(M) = P2R YI(M) = P2I 60 CONTINUE 70 CONTINUE IF (IFNU.LE.0) GO TO 90 DO 80 I=1,IFNU PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZR*PTI+RZI*PTR) P1R = PTR P1I = PTI AK = 1.0D0 - TFNF/(FKK+TFNF) ACK = BK*AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0D0 80 CONTINUE 90 CONTINUE PTR = ZR PTI = ZI IF (KODE.EQ.2) PTR = ZEROR CALL ZLOG(RZR, RZI, STR, STI, IDUM) P1R = -FNF*STR + PTR P1I = -FNF*STI + PTI AP = DGAMLN(1.0D0+FNF,IDUM) PTR = P1R - AP PTI = P1I C----------------------------------------------------------------------- C THE DIVISION CEXP(PT)/(SUM+P2) IS ALTERED TO AVOID OVERFLOW C IN THE DENOMINATOR BY SQUARING LARGE QUANTITIES C----------------------------------------------------------------------- P2R = P2R + SUMR P2I = P2I + SUMI AP = ZABS(CMPLX(P2R,P2I,kind=KIND(1.0D0))) P1R = 1.0D0/AP CALL ZEXP(PTR, PTI, STR, STI) CKR = STR*P1R CKI = STI*P1R PTR = P2R*P1R PTI = -P2I*P1R CALL ZMLT(CKR, CKI, PTR, PTI, CNORMR, CNORMI) DO 100 I=1,N STR = YR(I)*CNORMR - YI(I)*CNORMI YI(I) = YR(I)*CNORMI + YI(I)*CNORMR YR(I) = STR 100 CONTINUE RETURN 110 CONTINUE NZ=-2 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zmlt.f000066400000000000000000000006011450372207100246430ustar00rootroot00000000000000 SUBROUTINE ZMLT(AR, AI, BR, BI, CR, CI) C***BEGIN PROLOGUE ZMLT C***REFER TO ZBESH,ZBESI,ZBESJ,ZBESK,ZBESY,ZAIRY,ZBIRY C C DOUBLE PRECISION COMPLEX MULTIPLY, C=A*B. C C***ROUTINES CALLED (NONE) C***END PROLOGUE ZMLT DOUBLE PRECISION AR, AI, BR, BI, CR, CI, CA, CB CA = AR*BR - AI*BI CB = AR*BI + AI*BR CR = CA CI = CB RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zrati.f000066400000000000000000000076631450372207100250250ustar00rootroot00000000000000 SUBROUTINE ZRATI(ZR, ZI, FNU, N, CYR, CYI, TOL) C***BEGIN PROLOGUE ZRATI C***REFER TO ZBESI,ZBESK,ZBESH C C ZRATI COMPUTES RATIOS OF I BESSEL FUNCTIONS BY BACKWARD C RECURRENCE. THE STARTING INDEX IS DETERMINED BY FORWARD C RECURRENCE AS DESCRIBED IN J. RES. OF NAT. BUR. OF STANDARDS-B, C MATHEMATICAL SCIENCES, VOL 77B, P111-114, SEPTEMBER, 1973, C BESSEL FUNCTIONS I AND J OF COMPLEX ARGUMENT AND INTEGER ORDER, C BY D. J. SOOKNE. C C***ROUTINES CALLED ZABS,ZDIV C***END PROLOGUE ZRATI C COMPLEX Z,CY(1),CONE,CZERO,P1,P2,T1,RZ,PT,CDFNU DOUBLE PRECISION AK, AMAGZ, AP1, AP2, ARG, AZ, CDFNUI, CDFNUR, * CONEI, CONER, CYI, CYR, CZEROI, CZEROR, DFNU, FDNU, FLAM, FNU, * FNUP, PTI, PTR, P1I, P1R, P2I, P2R, RAK, RAP1, RHO, RT2, RZI, * RZR, TEST, TEST1, TOL, TTI, TTR, T1I, T1R, ZI, ZR, ZABS INTEGER I, ID, IDNU, INU, ITIME, K, KK, MAGZ, N DIMENSION CYR(N), CYI(N) DATA CZEROR,CZEROI,CONER,CONEI,RT2/ 1 0.0D0, 0.0D0, 1.0D0, 0.0D0, 1.41421356237309505D0 / AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) INU = INT(SNGL(FNU)) IDNU = INU + N - 1 MAGZ = INT(SNGL(AZ)) AMAGZ = DBLE(FLOAT(MAGZ+1)) FDNU = DBLE(FLOAT(IDNU)) FNUP = DMAX1(AMAGZ,FDNU) ID = IDNU - MAGZ - 1 ITIME = 1 K = 1 PTR = 1.0D0/AZ RZR = PTR*(ZR+ZR)*PTR RZI = -PTR*(ZI+ZI)*PTR T1R = RZR*FNUP T1I = RZI*FNUP P2R = -T1R P2I = -T1I P1R = CONER P1I = CONEI T1R = T1R + RZR T1I = T1I + RZI IF (ID.GT.0) ID = 0 AP2 = ZABS(CMPLX(P2R,P2I,kind=KIND(1.0D0))) AP1 = ZABS(CMPLX(P1R,P1I,kind=KIND(1.0D0))) C----------------------------------------------------------------------- C THE OVERFLOW TEST ON K(FNU+I-1,Z) BEFORE THE CALL TO CBKNU C GUARANTEES THAT P2 IS ON SCALE. SCALE TEST1 AND ALL SUBSEQUENT C P2 VALUES BY AP1 TO ENSURE THAT AN OVERFLOW DOES NOT OCCUR C PREMATURELY. C----------------------------------------------------------------------- ARG = (AP2+AP2)/(AP1*TOL) TEST1 = DSQRT(ARG) TEST = TEST1 RAP1 = 1.0D0/AP1 P1R = P1R*RAP1 P1I = P1I*RAP1 P2R = P2R*RAP1 P2I = P2I*RAP1 AP2 = AP2*RAP1 10 CONTINUE K = K + 1 AP1 = AP2 PTR = P2R PTI = P2I P2R = P1R - (T1R*PTR-T1I*PTI) P2I = P1I - (T1R*PTI+T1I*PTR) P1R = PTR P1I = PTI T1R = T1R + RZR T1I = T1I + RZI AP2 = ZABS(CMPLX(P2R,P2I,kind=KIND(1.0D0))) IF (AP1.LE.TEST) GO TO 10 IF (ITIME.EQ.2) GO TO 20 AK = ZABS(CMPLX(T1R,T1I,kind=KIND(1.0D0))*0.5D0) FLAM = AK + DSQRT(AK*AK-1.0D0) RHO = DMIN1(AP2/AP1,FLAM) TEST = TEST1*DSQRT(RHO/(RHO*RHO-1.0D0)) ITIME = 2 GO TO 10 20 CONTINUE KK = K + 1 - ID AK = DBLE(FLOAT(KK)) T1R = AK T1I = CZEROI DFNU = FNU + DBLE(FLOAT(N-1)) P1R = 1.0D0/AP2 P1I = CZEROI P2R = CZEROR P2I = CZEROI DO 30 I=1,KK PTR = P1R PTI = P1I RAP1 = DFNU + T1R TTR = RZR*RAP1 TTI = RZI*RAP1 P1R = (PTR*TTR-PTI*TTI) + P2R P1I = (PTR*TTI+PTI*TTR) + P2I P2R = PTR P2I = PTI T1R = T1R - CONER 30 CONTINUE IF (P1R.NE.CZEROR .OR. P1I.NE.CZEROI) GO TO 40 P1R = TOL P1I = TOL 40 CONTINUE CALL ZDIV(P2R, P2I, P1R, P1I, CYR(N), CYI(N)) IF (N.EQ.1) RETURN K = N - 1 AK = DBLE(FLOAT(K)) T1R = AK T1I = CZEROI CDFNUR = FNU*RZR CDFNUI = FNU*RZI DO 60 I=2,N PTR = CDFNUR + (T1R*RZR-T1I*RZI) + CYR(K+1) PTI = CDFNUI + (T1R*RZI+T1I*RZR) + CYI(K+1) AK = ZABS(CMPLX(PTR,PTI,kind=KIND(1.0D0))) IF (AK.NE.CZEROR) GO TO 50 PTR = TOL PTI = TOL AK = TOL*RT2 50 CONTINUE RAK = CONER/AK CYR(K) = RAK*PTR*RAK CYI(K) = -RAK*PTI*RAK T1R = T1R - CONER K = K - 1 60 CONTINUE RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zs1s2.f000066400000000000000000000031331450372207100246420ustar00rootroot00000000000000 SUBROUTINE ZS1S2(ZRR, ZRI, S1R, S1I, S2R, S2I, NZ, ASCLE, ALIM, * IUF) C***BEGIN PROLOGUE ZS1S2 C***REFER TO ZBESK,ZAIRY C C ZS1S2 TESTS FOR A POSSIBLE UNDERFLOW RESULTING FROM THE C ADDITION OF THE I AND K FUNCTIONS IN THE ANALYTIC CON- C TINUATION FORMULA WHERE S1=K FUNCTION AND S2=I FUNCTION. C ON KODE=1 THE I AND K FUNCTIONS ARE DIFFERENT ORDERS OF C MAGNITUDE, BUT FOR KODE=2 THEY CAN BE OF THE SAME ORDER C OF MAGNITUDE AND THE MAXIMUM MUST BE AT LEAST ONE C PRECISION ABOVE THE UNDERFLOW LIMIT. C C***ROUTINES CALLED ZABS,ZEXP,ZLOG C***END PROLOGUE ZS1S2 C COMPLEX CZERO,C1,S1,S1D,S2,ZR DOUBLE PRECISION AA, ALIM, ALN, ASCLE, AS1, AS2, C1I, C1R, S1DI, * S1DR, S1I, S1R, S2I, S2R, ZEROI, ZEROR, ZRI, ZRR, ZABS INTEGER IUF, IDUM, NZ DATA ZEROR,ZEROI / 0.0D0 , 0.0D0 / NZ = 0 AS1 = ZABS(CMPLX(S1R,S1I,kind=KIND(1.0D0))) AS2 = ZABS(CMPLX(S2R,S2I,kind=KIND(1.0D0))) IF (S1R.EQ.0.0D0 .AND. S1I.EQ.0.0D0) GO TO 10 IF (AS1.EQ.0.0D0) GO TO 10 ALN = -ZRR - ZRR + DLOG(AS1) S1DR = S1R S1DI = S1I S1R = ZEROR S1I = ZEROI AS1 = ZEROR IF (ALN.LT.(-ALIM)) GO TO 10 CALL ZLOG(S1DR, S1DI, C1R, C1I, IDUM) C1R = C1R - ZRR - ZRR C1I = C1I - ZRI - ZRI CALL ZEXP(C1R, C1I, S1R, S1I) AS1 = ZABS(CMPLX(S1R,S1I,kind=KIND(1.0D0))) IUF = IUF + 1 10 CONTINUE AA = DMAX1(AS1,AS2) IF (AA.GT.ASCLE) THEN RETURN END IF S1R = ZEROR S1I = ZEROI S2R = ZEROR S2I = ZEROI NZ = 1 IUF = 0 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zseri.f000066400000000000000000000132711450372207100250200ustar00rootroot00000000000000 SUBROUTINE ZSERI(ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, * ALIM) C***BEGIN PROLOGUE ZSERI C***REFER TO ZBESI,ZBESK C C ZSERI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z).GE.0.0 BY C MEANS OF THE POWER SERIES FOR LARGE CABS(Z) IN THE C REGION CABS(Z).LE.2*SQRT(FNU+1). NZ=0 IS A NORMAL RETURN. C NZ.GT.0 MEANS THAT THE LAST NZ COMPONENTS WERE SET TO ZERO C DUE TO UNDERFLOW. NZ.LT.0 MEANS UNDERFLOW OCCURRED, BUT THE C CONDITION CABS(Z).LE.2*SQRT(FNU+1) WAS VIOLATED AND THE C COMPUTATION MUST BE COMPLETED IN ANOTHER ROUTINE WITH N=N-ABS(NZ). C C***ROUTINES CALLED DGAMLN,D1MACH,ZUCHK,ZABS,ZDIV,ZLOG,ZMLT C***END PROLOGUE ZSERI C COMPLEX AK1,CK,COEF,CONE,CRSC,CSCL,CZ,CZERO,HZ,RZ,S1,S2,Y,Z DOUBLE PRECISION AA, ACZ, AK, AK1I, AK1R, ALIM, ARM, ASCLE, ATOL, * AZ, CKI, CKR, COEFI, COEFR, CONEI, CONER, CRSCR, CZI, CZR, DFNU, * ELIM, FNU, FNUP, HZI, HZR, RAZ, RS, RTR1, RZI, RZR, S, SS, STI, * STR, S1I, S1R, S2I, S2R, TOL, YI, YR, WI, WR, ZEROI, ZEROR, ZI, * ZR, DGAMLN, D1MACH, ZABS INTEGER I, IB, IDUM, IFLAG, IL, K, KODE, L, M, N, NN, NZ, NW DIMENSION YR(N), YI(N), WR(2), WI(2) DATA ZEROR,ZEROI,CONER,CONEI / 0.0D0, 0.0D0, 1.0D0, 0.0D0 / C NZ = 0 AZ = ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) IF (AZ.EQ.0.0D0) GO TO 160 ARM = 1.0D+3*D1MACH(1) RTR1 = DSQRT(ARM) CRSCR = 1.0D0 IFLAG = 0 IF (AZ.LT.ARM) THEN GO TO 150 END IF HZR = 0.5D0*ZR HZI = 0.5D0*ZI CZR = ZEROR CZI = ZEROI IF (AZ.LE.RTR1) GO TO 10 CALL ZMLT(HZR, HZI, HZR, HZI, CZR, CZI) 10 CONTINUE ACZ = ZABS(CMPLX(CZR,CZI,kind=KIND(1.0D0))) NN = N CALL ZLOG(HZR, HZI, CKR, CKI, IDUM) 20 CONTINUE DFNU = FNU + DBLE(FLOAT(NN-1)) FNUP = DFNU + 1.0D0 C----------------------------------------------------------------------- C UNDERFLOW TEST C----------------------------------------------------------------------- AK1R = CKR*DFNU AK1I = CKI*DFNU AK = DGAMLN(FNUP,IDUM) AK1R = AK1R - AK IF (KODE.EQ.2) AK1R = AK1R - ZR IF (AK1R.GT.(-ELIM)) GO TO 40 30 CONTINUE NZ = NZ + 1 YR(NN) = ZEROR YI(NN) = ZEROI IF (ACZ.GT.DFNU) GO TO 190 NN = NN - 1 IF (NN.EQ.0) RETURN GO TO 20 40 CONTINUE IF (AK1R.GT.(-ALIM)) GO TO 50 IFLAG = 1 SS = 1.0D0/TOL CRSCR = TOL ASCLE = ARM*SS 50 CONTINUE AA = DEXP(AK1R) IF (IFLAG.EQ.1) AA = AA*SS COEFR = AA*DCOS(AK1I) COEFI = AA*DSIN(AK1I) ATOL = TOL*ACZ/FNUP IL = MIN0(2,NN) DO 90 I=1,IL DFNU = FNU + DBLE(FLOAT(NN-I)) FNUP = DFNU + 1.0D0 S1R = CONER S1I = CONEI IF (ACZ.LT.TOL*FNUP) GO TO 70 AK1R = CONER AK1I = CONEI AK = FNUP + 2.0D0 S = FNUP AA = 2.0D0 60 CONTINUE RS = 1.0D0/S STR = AK1R*CZR - AK1I*CZI STI = AK1R*CZI + AK1I*CZR AK1R = STR*RS AK1I = STI*RS S1R = S1R + AK1R S1I = S1I + AK1I S = S + AK AK = AK + 2.0D0 AA = AA*ACZ*RS IF (AA.GT.ATOL) GO TO 60 70 CONTINUE S2R = S1R*COEFR - S1I*COEFI S2I = S1R*COEFI + S1I*COEFR WR(I) = S2R WI(I) = S2I IF (IFLAG.EQ.0) GO TO 80 CALL ZUCHK(S2R, S2I, NW, ASCLE, TOL) IF (NW.NE.0) GO TO 30 80 CONTINUE M = NN - I + 1 YR(M) = S2R*CRSCR YI(M) = S2I*CRSCR IF (I.EQ.IL) GO TO 90 CALL ZDIV(COEFR, COEFI, HZR, HZI, STR, STI) COEFR = STR*DFNU COEFI = STI*DFNU 90 CONTINUE IF (NN.LE.2) THEN RETURN END IF K = NN - 2 AK = DBLE(FLOAT(K)) RAZ = 1.0D0/AZ STR = ZR*RAZ STI = -ZI*RAZ RZR = (STR+STR)*RAZ RZI = (STI+STI)*RAZ IF (IFLAG.EQ.1) GO TO 120 IB = 3 100 CONTINUE DO 110 I=IB,NN YR(K) = (AK+FNU)*(RZR*YR(K+1)-RZI*YI(K+1)) + YR(K+2) YI(K) = (AK+FNU)*(RZR*YI(K+1)+RZI*YR(K+1)) + YI(K+2) AK = AK - 1.0D0 K = K - 1 110 CONTINUE RETURN C----------------------------------------------------------------------- C RECUR BACKWARD WITH SCALED VALUES C----------------------------------------------------------------------- 120 CONTINUE C----------------------------------------------------------------------- C EXP(-ALIM)=EXP(-ELIM)/TOL=APPROX. ONE PRECISION ABOVE THE C UNDERFLOW LIMIT = ASCLE = D1MACH(1)*SS*1.0D+3 C----------------------------------------------------------------------- S1R = WR(1) S1I = WI(1) S2R = WR(2) S2I = WI(2) DO 130 L=3,NN CKR = S2R CKI = S2I S2R = S1R + (AK+FNU)*(RZR*CKR-RZI*CKI) S2I = S1I + (AK+FNU)*(RZR*CKI+RZI*CKR) S1R = CKR S1I = CKI CKR = S2R*CRSCR CKI = S2I*CRSCR YR(K) = CKR YI(K) = CKI AK = AK - 1.0D0 K = K - 1 IF (ZABS(CMPLX(CKR,CKI,kind=KIND(1.0D0))).GT.ASCLE) GO TO 140 130 CONTINUE RETURN 140 CONTINUE IB = L + 1 IF (IB.GT.NN) RETURN GO TO 100 150 CONTINUE NZ = N IF (FNU.EQ.0.0D0) NZ = NZ - 1 160 CONTINUE YR(1) = ZEROR YI(1) = ZEROI IF (FNU.NE.0.0D0) GO TO 170 YR(1) = CONER YI(1) = CONEI 170 CONTINUE IF (N.EQ.1) RETURN DO 180 I=2,N YR(I) = ZEROR YI(I) = ZEROI 180 CONTINUE RETURN C----------------------------------------------------------------------- C RETURN WITH NZ.LT.0 IF CABS(Z*Z/4).GT.FNU+N-NZ-1 COMPLETE C THE CALCULATION IN CBINU WITH N=N-IABS(NZ) C----------------------------------------------------------------------- 190 CONTINUE NZ = -NZ RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zshch.f000066400000000000000000000010451450372207100247770ustar00rootroot00000000000000 SUBROUTINE ZSHCH(ZR, ZI, CSHR, CSHI, CCHR, CCHI) C***BEGIN PROLOGUE ZSHCH C***REFER TO ZBESK,ZBESH C C ZSHCH COMPUTES THE COMPLEX HYPERBOLIC FUNCTIONS CSH=SINH(X+I*Y) C AND CCH=COSH(X+I*Y), WHERE I**2=-1. C C***ROUTINES CALLED (NONE) C***END PROLOGUE ZSHCH C DOUBLE PRECISION CCHI, CCHR, CH, CN, CSHI, CSHR, SH, SN, ZI, ZR, * DCOSH, DSINH SH = DSINH(ZR) CH = DCOSH(ZR) SN = DSIN(ZI) CN = DCOS(ZI) CSHR = SH*CN CSHI = CH*SN CCHR = CH*CN CCHI = SH*SN RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zsqrt.f000066400000000000000000000022621450372207100250450ustar00rootroot00000000000000 SUBROUTINE ZSQRT(AR, AI, BR, BI) C***BEGIN PROLOGUE ZSQRT C***REFER TO ZBESH,ZBESI,ZBESJ,ZBESK,ZBESY,ZAIRY,ZBIRY C C DOUBLE PRECISION COMPLEX SQUARE ROOT, B=CSQRT(A) C C***ROUTINES CALLED ZABS C***END PROLOGUE ZSQRT DOUBLE PRECISION AR, AI, BR, BI, ZM, DTHETA, DPI, DRT DOUBLE PRECISION ZABS DATA DRT , DPI / 7.071067811865475244008443621D-1, 1 3.141592653589793238462643383D+0/ ZM = ZABS(CMPLX(AR,AI,kind=KIND(1.0D0))) ZM = DSQRT(ZM) IF (AR.EQ.0.0D+0) GO TO 10 IF (AI.EQ.0.0D+0) GO TO 20 DTHETA = DATAN(AI/AR) IF (DTHETA.LE.0.0D+0) GO TO 40 IF (AR.LT.0.0D+0) DTHETA = DTHETA - DPI GO TO 50 10 IF (AI.GT.0.0D+0) GO TO 60 IF (AI.LT.0.0D+0) GO TO 70 BR = 0.0D+0 BI = 0.0D+0 RETURN 20 IF (AR.GT.0.0D+0) GO TO 30 BR = 0.0D+0 BI = DSQRT(DABS(AR)) RETURN 30 BR = DSQRT(AR) BI = 0.0D+0 RETURN 40 IF (AR.LT.0.0D+0) DTHETA = DTHETA + DPI 50 DTHETA = DTHETA*0.5D+0 BR = ZM*DCOS(DTHETA) BI = ZM*DSIN(DTHETA) RETURN 60 BR = ZM*DRT BI = ZM*DRT RETURN 70 BR = ZM*DRT BI = -ZM*DRT RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zuchk.f000066400000000000000000000016661450372207100250150ustar00rootroot00000000000000 SUBROUTINE ZUCHK(YR, YI, NZ, ASCLE, TOL) C***BEGIN PROLOGUE ZUCHK C***REFER TO ZSERI,ZUOIK,ZUNK1,ZUNK2,ZUNI1,ZUNI2,ZKSCL C C Y ENTERS AS A SCALED QUANTITY WHOSE MAGNITUDE IS GREATER THAN C EXP(-ALIM)=ASCLE=1.0E+3*D1MACH(1)/TOL. THE TEST IS MADE TO SEE C IF THE MAGNITUDE OF THE REAL OR IMAGINARY PART WOULD UNDERFLOW C WHEN Y IS SCALED (BY TOL) TO ITS PROPER VALUE. Y IS ACCEPTED C IF THE UNDERFLOW IS AT LEAST ONE PRECISION BELOW THE MAGNITUDE C OF THE LARGEST COMPONENT; OTHERWISE THE PHASE ANGLE DOES NOT HAVE C ABSOLUTE ACCURACY AND AN UNDERFLOW IS ASSUMED. C C***ROUTINES CALLED (NONE) C***END PROLOGUE ZUCHK C C COMPLEX Y DOUBLE PRECISION ASCLE, SS, ST, TOL, WR, WI, YR, YI INTEGER NZ NZ = 0 WR = DABS(YR) WI = DABS(YI) ST = DMIN1(WR,WI) IF (ST.GT.ASCLE) RETURN SS = DMAX1(WR,WI) ST = ST/TOL IF (SS.LT.ST) NZ = 1 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zunhj.f000066400000000000000000001050721450372207100250230ustar00rootroot00000000000000 SUBROUTINE ZUNHJ(ZR, ZI, FNU, IPMTR, TOL, PHIR, PHII, ARGR, ARGI, * ZETA1R, ZETA1I, ZETA2R, ZETA2I, ASUMR, ASUMI, BSUMR, BSUMI) C***BEGIN PROLOGUE ZUNHJ C***REFER TO ZBESI,ZBESK C C REFERENCES C HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ AND I.A. C STEGUN, AMS55, NATIONAL BUREAU OF STANDARDS, 1965, CHAPTER 9. C C ASYMPTOTICS AND SPECIAL FUNCTIONS BY F.W.J. OLVER, ACADEMIC C PRESS, N.Y., 1974, PAGE 420 C C ABSTRACT C ZUNHJ COMPUTES PARAMETERS FOR BESSEL FUNCTIONS C(FNU,Z) = C J(FNU,Z), Y(FNU,Z) OR H(I,FNU,Z) I=1,2 FOR LARGE ORDERS FNU C BY MEANS OF THE UNIFORM ASYMPTOTIC EXPANSION C C C(FNU,Z)=C1*PHI*( ASUM*AIRY(ARG) + C2*BSUM*DAIRY(ARG) ) C C FOR PROPER CHOICES OF C1, C2, AIRY AND DAIRY WHERE AIRY IS C AN AIRY FUNCTION AND DAIRY IS ITS DERIVATIVE. C C (2/3)*FNU*ZETA**1.5 = ZETA1-ZETA2, C C ZETA1=0.5*FNU*CLOG((1+W)/(1-W)), ZETA2=FNU*W FOR SCALING C PURPOSES IN AIRY FUNCTIONS FROM CAIRY OR CBIRY. C C MCONJ=SIGN OF AIMAG(Z), BUT IS AMBIGUOUS WHEN Z IS REAL AND C MUST BE SPECIFIED. IPMTR=0 RETURNS ALL PARAMETERS. IPMTR= C 1 COMPUTES ALL EXCEPT ASUM AND BSUM. C C***ROUTINES CALLED ZABS,ZDIV,ZLOG,ZSQRT,D1MACH C***END PROLOGUE ZUNHJ C COMPLEX ARG,ASUM,BSUM,CFNU,CONE,CR,CZERO,DR,P,PHI,PRZTH,PTFN, C *RFN13,RTZTA,RZTH,SUMA,SUMB,TFN,T2,UP,W,W2,Z,ZA,ZB,ZC,ZETA,ZETA1, C *ZETA2,ZTH DOUBLE PRECISION ALFA, ANG, AP, AR, ARGI, ARGR, ASUMI, ASUMR, * ATOL, AW2, AZTH, BETA, BR, BSUMI, BSUMR, BTOL, C, CONEI, CONER, * CRI, CRR, DRI, DRR, EX1, EX2, FNU, FN13, FN23, GAMA, GPI, HPI, * PHII, PHIR, PI, PP, PR, PRZTHI, PRZTHR, PTFNI, PTFNR, RAW, RAW2, * RAZTH, RFNU, RFNU2, RFN13, RTZTI, RTZTR, RZTHI, RZTHR, STI, STR, * SUMAI, SUMAR, SUMBI, SUMBR, TEST, TFNI, TFNR, THPI, TOL, TZAI, * TZAR, T2I, T2R, UPI, UPR, WI, WR, W2I, W2R, ZAI, ZAR, ZBI, ZBR, * ZCI, ZCR, ZEROI, ZEROR, ZETAI, ZETAR, ZETA1I, ZETA1R, ZETA2I, * ZETA2R, ZI, ZR, ZTHI, ZTHR, ZABS, AC, D1MACH INTEGER IAS, IBS, IPMTR, IS, J, JR, JU, K, KMAX, KP1, KS, L, LR, * LRP1, L1, L2, M, IDUM DIMENSION AR(14), BR(14), C(105), ALFA(180), BETA(210), GAMA(30), * AP(30), PR(30), PI(30), UPR(14), UPI(14), CRR(14), CRI(14), * DRR(14), DRI(14) DATA AR(1), AR(2), AR(3), AR(4), AR(5), AR(6), AR(7), AR(8), 1 AR(9), AR(10), AR(11), AR(12), AR(13), AR(14)/ 2 1.00000000000000000D+00, 1.04166666666666667D-01, 3 8.35503472222222222D-02, 1.28226574556327160D-01, 4 2.91849026464140464D-01, 8.81627267443757652D-01, 5 3.32140828186276754D+00, 1.49957629868625547D+01, 6 7.89230130115865181D+01, 4.74451538868264323D+02, 7 3.20749009089066193D+03, 2.40865496408740049D+04, 8 1.98923119169509794D+05, 1.79190200777534383D+06/ DATA BR(1), BR(2), BR(3), BR(4), BR(5), BR(6), BR(7), BR(8), 1 BR(9), BR(10), BR(11), BR(12), BR(13), BR(14)/ 2 1.00000000000000000D+00, -1.45833333333333333D-01, 3 -9.87413194444444444D-02, -1.43312053915895062D-01, 4 -3.17227202678413548D-01, -9.42429147957120249D-01, 5 -3.51120304082635426D+00, -1.57272636203680451D+01, 6 -8.22814390971859444D+01, -4.92355370523670524D+02, 7 -3.31621856854797251D+03, -2.48276742452085896D+04, 8 -2.04526587315129788D+05, -1.83844491706820990D+06/ DATA C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), C(10), 1 C(11), C(12), C(13), C(14), C(15), C(16), C(17), C(18), 2 C(19), C(20), C(21), C(22), C(23), C(24)/ 3 1.00000000000000000D+00, -2.08333333333333333D-01, 4 1.25000000000000000D-01, 3.34201388888888889D-01, 5 -4.01041666666666667D-01, 7.03125000000000000D-02, 6 -1.02581259645061728D+00, 1.84646267361111111D+00, 7 -8.91210937500000000D-01, 7.32421875000000000D-02, 8 4.66958442342624743D+00, -1.12070026162229938D+01, 9 8.78912353515625000D+00, -2.36408691406250000D+00, A 1.12152099609375000D-01, -2.82120725582002449D+01, B 8.46362176746007346D+01, -9.18182415432400174D+01, C 4.25349987453884549D+01, -7.36879435947963170D+00, D 2.27108001708984375D-01, 2.12570130039217123D+02, E -7.65252468141181642D+02, 1.05999045252799988D+03/ DATA C(25), C(26), C(27), C(28), C(29), C(30), C(31), C(32), 1 C(33), C(34), C(35), C(36), C(37), C(38), C(39), C(40), 2 C(41), C(42), C(43), C(44), C(45), C(46), C(47), C(48)/ 3 -6.99579627376132541D+02, 2.18190511744211590D+02, 4 -2.64914304869515555D+01, 5.72501420974731445D-01, 5 -1.91945766231840700D+03, 8.06172218173730938D+03, 6 -1.35865500064341374D+04, 1.16553933368645332D+04, 7 -5.30564697861340311D+03, 1.20090291321635246D+03, 8 -1.08090919788394656D+02, 1.72772750258445740D+00, 9 2.02042913309661486D+04, -9.69805983886375135D+04, A 1.92547001232531532D+05, -2.03400177280415534D+05, B 1.22200464983017460D+05, -4.11926549688975513D+04, C 7.10951430248936372D+03, -4.93915304773088012D+02, D 6.07404200127348304D+00, -2.42919187900551333D+05, E 1.31176361466297720D+06, -2.99801591853810675D+06/ DATA C(49), C(50), C(51), C(52), C(53), C(54), C(55), C(56), 1 C(57), C(58), C(59), C(60), C(61), C(62), C(63), C(64), 2 C(65), C(66), C(67), C(68), C(69), C(70), C(71), C(72)/ 3 3.76327129765640400D+06, -2.81356322658653411D+06, 4 1.26836527332162478D+06, -3.31645172484563578D+05, 5 4.52187689813627263D+04, -2.49983048181120962D+03, 6 2.43805296995560639D+01, 3.28446985307203782D+06, 7 -1.97068191184322269D+07, 5.09526024926646422D+07, 8 -7.41051482115326577D+07, 6.63445122747290267D+07, 9 -3.75671766607633513D+07, 1.32887671664218183D+07, A -2.78561812808645469D+06, 3.08186404612662398D+05, B -1.38860897537170405D+04, 1.10017140269246738D+02, C -4.93292536645099620D+07, 3.25573074185765749D+08, D -9.39462359681578403D+08, 1.55359689957058006D+09, E -1.62108055210833708D+09, 1.10684281682301447D+09/ DATA C(73), C(74), C(75), C(76), C(77), C(78), C(79), C(80), 1 C(81), C(82), C(83), C(84), C(85), C(86), C(87), C(88), 2 C(89), C(90), C(91), C(92), C(93), C(94), C(95), C(96)/ 3 -4.95889784275030309D+08, 1.42062907797533095D+08, 4 -2.44740627257387285D+07, 2.24376817792244943D+06, 5 -8.40054336030240853D+04, 5.51335896122020586D+02, 6 8.14789096118312115D+08, -5.86648149205184723D+09, 7 1.86882075092958249D+10, -3.46320433881587779D+10, 8 4.12801855797539740D+10, -3.30265997498007231D+10, 9 1.79542137311556001D+10, -6.56329379261928433D+09, A 1.55927986487925751D+09, -2.25105661889415278D+08, B 1.73951075539781645D+07, -5.49842327572288687D+05, C 3.03809051092238427D+03, -1.46792612476956167D+10, D 1.14498237732025810D+11, -3.99096175224466498D+11, E 8.19218669548577329D+11, -1.09837515608122331D+12/ DATA C(97), C(98), C(99), C(100), C(101), C(102), C(103), C(104), 1 C(105)/ 2 1.00815810686538209D+12, -6.45364869245376503D+11, 3 2.87900649906150589D+11, -8.78670721780232657D+10, 4 1.76347306068349694D+10, -2.16716498322379509D+09, 5 1.43157876718888981D+08, -3.87183344257261262D+06, 6 1.82577554742931747D+04/ DATA ALFA(1), ALFA(2), ALFA(3), ALFA(4), ALFA(5), ALFA(6), 1 ALFA(7), ALFA(8), ALFA(9), ALFA(10), ALFA(11), ALFA(12), 2 ALFA(13), ALFA(14), ALFA(15), ALFA(16), ALFA(17), ALFA(18), 3 ALFA(19), ALFA(20), ALFA(21), ALFA(22)/ 4 -4.44444444444444444D-03, -9.22077922077922078D-04, 5 -8.84892884892884893D-05, 1.65927687832449737D-04, 6 2.46691372741792910D-04, 2.65995589346254780D-04, 7 2.61824297061500945D-04, 2.48730437344655609D-04, 8 2.32721040083232098D-04, 2.16362485712365082D-04, 9 2.00738858762752355D-04, 1.86267636637545172D-04, A 1.73060775917876493D-04, 1.61091705929015752D-04, B 1.50274774160908134D-04, 1.40503497391269794D-04, C 1.31668816545922806D-04, 1.23667445598253261D-04, D 1.16405271474737902D-04, 1.09798298372713369D-04, E 1.03772410422992823D-04, 9.82626078369363448D-05/ DATA ALFA(23), ALFA(24), ALFA(25), ALFA(26), ALFA(27), ALFA(28), 1 ALFA(29), ALFA(30), ALFA(31), ALFA(32), ALFA(33), ALFA(34), 2 ALFA(35), ALFA(36), ALFA(37), ALFA(38), ALFA(39), ALFA(40), 3 ALFA(41), ALFA(42), ALFA(43), ALFA(44)/ 4 9.32120517249503256D-05, 8.85710852478711718D-05, 5 8.42963105715700223D-05, 8.03497548407791151D-05, 6 7.66981345359207388D-05, 7.33122157481777809D-05, 7 7.01662625163141333D-05, 6.72375633790160292D-05, 8 6.93735541354588974D-04, 2.32241745182921654D-04, 9 -1.41986273556691197D-05, -1.16444931672048640D-04, A -1.50803558053048762D-04, -1.55121924918096223D-04, B -1.46809756646465549D-04, -1.33815503867491367D-04, C -1.19744975684254051D-04, -1.06184319207974020D-04, D -9.37699549891194492D-05, -8.26923045588193274D-05, E -7.29374348155221211D-05, -6.44042357721016283D-05/ DATA ALFA(45), ALFA(46), ALFA(47), ALFA(48), ALFA(49), ALFA(50), 1 ALFA(51), ALFA(52), ALFA(53), ALFA(54), ALFA(55), ALFA(56), 2 ALFA(57), ALFA(58), ALFA(59), ALFA(60), ALFA(61), ALFA(62), 3 ALFA(63), ALFA(64), ALFA(65), ALFA(66)/ 4 -5.69611566009369048D-05, -5.04731044303561628D-05, 5 -4.48134868008882786D-05, -3.98688727717598864D-05, 6 -3.55400532972042498D-05, -3.17414256609022480D-05, 7 -2.83996793904174811D-05, -2.54522720634870566D-05, 8 -2.28459297164724555D-05, -2.05352753106480604D-05, 9 -1.84816217627666085D-05, -1.66519330021393806D-05, A -1.50179412980119482D-05, -1.35554031379040526D-05, B -1.22434746473858131D-05, -1.10641884811308169D-05, C -3.54211971457743841D-04, -1.56161263945159416D-04, D 3.04465503594936410D-05, 1.30198655773242693D-04, E 1.67471106699712269D-04, 1.70222587683592569D-04/ DATA ALFA(67), ALFA(68), ALFA(69), ALFA(70), ALFA(71), ALFA(72), 1 ALFA(73), ALFA(74), ALFA(75), ALFA(76), ALFA(77), ALFA(78), 2 ALFA(79), ALFA(80), ALFA(81), ALFA(82), ALFA(83), ALFA(84), 3 ALFA(85), ALFA(86), ALFA(87), ALFA(88)/ 4 1.56501427608594704D-04, 1.36339170977445120D-04, 5 1.14886692029825128D-04, 9.45869093034688111D-05, 6 7.64498419250898258D-05, 6.07570334965197354D-05, 7 4.74394299290508799D-05, 3.62757512005344297D-05, 8 2.69939714979224901D-05, 1.93210938247939253D-05, 9 1.30056674793963203D-05, 7.82620866744496661D-06, A 3.59257485819351583D-06, 1.44040049814251817D-07, B -2.65396769697939116D-06, -4.91346867098485910D-06, C -6.72739296091248287D-06, -8.17269379678657923D-06, D -9.31304715093561232D-06, -1.02011418798016441D-05, E -1.08805962510592880D-05, -1.13875481509603555D-05/ DATA ALFA(89), ALFA(90), ALFA(91), ALFA(92), ALFA(93), ALFA(94), 1 ALFA(95), ALFA(96), ALFA(97), ALFA(98), ALFA(99), ALFA(100), 2 ALFA(101), ALFA(102), ALFA(103), ALFA(104), ALFA(105), 3 ALFA(106), ALFA(107), ALFA(108), ALFA(109), ALFA(110)/ 4 -1.17519675674556414D-05, -1.19987364870944141D-05, 5 3.78194199201772914D-04, 2.02471952761816167D-04, 6 -6.37938506318862408D-05, -2.38598230603005903D-04, 7 -3.10916256027361568D-04, -3.13680115247576316D-04, 8 -2.78950273791323387D-04, -2.28564082619141374D-04, 9 -1.75245280340846749D-04, -1.25544063060690348D-04, A -8.22982872820208365D-05, -4.62860730588116458D-05, B -1.72334302366962267D-05, 5.60690482304602267D-06, C 2.31395443148286800D-05, 3.62642745856793957D-05, D 4.58006124490188752D-05, 5.24595294959114050D-05, E 5.68396208545815266D-05, 5.94349820393104052D-05/ DATA ALFA(111), ALFA(112), ALFA(113), ALFA(114), ALFA(115), 1 ALFA(116), ALFA(117), ALFA(118), ALFA(119), ALFA(120), 2 ALFA(121), ALFA(122), ALFA(123), ALFA(124), ALFA(125), 3 ALFA(126), ALFA(127), ALFA(128), ALFA(129), ALFA(130)/ 4 6.06478527578421742D-05, 6.08023907788436497D-05, 5 6.01577894539460388D-05, 5.89199657344698500D-05, 6 5.72515823777593053D-05, 5.52804375585852577D-05, 7 5.31063773802880170D-05, 5.08069302012325706D-05, 8 4.84418647620094842D-05, 4.60568581607475370D-05, 9 -6.91141397288294174D-04, -4.29976633058871912D-04, A 1.83067735980039018D-04, 6.60088147542014144D-04, B 8.75964969951185931D-04, 8.77335235958235514D-04, C 7.49369585378990637D-04, 5.63832329756980918D-04, D 3.68059319971443156D-04, 1.88464535514455599D-04/ DATA ALFA(131), ALFA(132), ALFA(133), ALFA(134), ALFA(135), 1 ALFA(136), ALFA(137), ALFA(138), ALFA(139), ALFA(140), 2 ALFA(141), ALFA(142), ALFA(143), ALFA(144), ALFA(145), 3 ALFA(146), ALFA(147), ALFA(148), ALFA(149), ALFA(150)/ 4 3.70663057664904149D-05, -8.28520220232137023D-05, 5 -1.72751952869172998D-04, -2.36314873605872983D-04, 6 -2.77966150694906658D-04, -3.02079514155456919D-04, 7 -3.12594712643820127D-04, -3.12872558758067163D-04, 8 -3.05678038466324377D-04, -2.93226470614557331D-04, 9 -2.77255655582934777D-04, -2.59103928467031709D-04, A -2.39784014396480342D-04, -2.20048260045422848D-04, B -2.00443911094971498D-04, -1.81358692210970687D-04, C -1.63057674478657464D-04, -1.45712672175205844D-04, D -1.29425421983924587D-04, -1.14245691942445952D-04/ DATA ALFA(151), ALFA(152), ALFA(153), ALFA(154), ALFA(155), 1 ALFA(156), ALFA(157), ALFA(158), ALFA(159), ALFA(160), 2 ALFA(161), ALFA(162), ALFA(163), ALFA(164), ALFA(165), 3 ALFA(166), ALFA(167), ALFA(168), ALFA(169), ALFA(170)/ 4 1.92821964248775885D-03, 1.35592576302022234D-03, 5 -7.17858090421302995D-04, -2.58084802575270346D-03, 6 -3.49271130826168475D-03, -3.46986299340960628D-03, 7 -2.82285233351310182D-03, -1.88103076404891354D-03, 8 -8.89531718383947600D-04, 3.87912102631035228D-06, 9 7.28688540119691412D-04, 1.26566373053457758D-03, A 1.62518158372674427D-03, 1.83203153216373172D-03, B 1.91588388990527909D-03, 1.90588846755546138D-03, C 1.82798982421825727D-03, 1.70389506421121530D-03, D 1.55097127171097686D-03, 1.38261421852276159D-03/ DATA ALFA(171), ALFA(172), ALFA(173), ALFA(174), ALFA(175), 1 ALFA(176), ALFA(177), ALFA(178), ALFA(179), ALFA(180)/ 2 1.20881424230064774D-03, 1.03676532638344962D-03, 3 8.71437918068619115D-04, 7.16080155297701002D-04, 4 5.72637002558129372D-04, 4.42089819465802277D-04, 5 3.24724948503090564D-04, 2.20342042730246599D-04, 6 1.28412898401353882D-04, 4.82005924552095464D-05/ DATA BETA(1), BETA(2), BETA(3), BETA(4), BETA(5), BETA(6), 1 BETA(7), BETA(8), BETA(9), BETA(10), BETA(11), BETA(12), 2 BETA(13), BETA(14), BETA(15), BETA(16), BETA(17), BETA(18), 3 BETA(19), BETA(20), BETA(21), BETA(22)/ 4 1.79988721413553309D-02, 5.59964911064388073D-03, 5 2.88501402231132779D-03, 1.80096606761053941D-03, 6 1.24753110589199202D-03, 9.22878876572938311D-04, 7 7.14430421727287357D-04, 5.71787281789704872D-04, 8 4.69431007606481533D-04, 3.93232835462916638D-04, 9 3.34818889318297664D-04, 2.88952148495751517D-04, A 2.52211615549573284D-04, 2.22280580798883327D-04, B 1.97541838033062524D-04, 1.76836855019718004D-04, C 1.59316899661821081D-04, 1.44347930197333986D-04, D 1.31448068119965379D-04, 1.20245444949302884D-04, E 1.10449144504599392D-04, 1.01828770740567258D-04/ DATA BETA(23), BETA(24), BETA(25), BETA(26), BETA(27), BETA(28), 1 BETA(29), BETA(30), BETA(31), BETA(32), BETA(33), BETA(34), 2 BETA(35), BETA(36), BETA(37), BETA(38), BETA(39), BETA(40), 3 BETA(41), BETA(42), BETA(43), BETA(44)/ 4 9.41998224204237509D-05, 8.74130545753834437D-05, 5 8.13466262162801467D-05, 7.59002269646219339D-05, 6 7.09906300634153481D-05, 6.65482874842468183D-05, 7 6.25146958969275078D-05, 5.88403394426251749D-05, 8 -1.49282953213429172D-03, -8.78204709546389328D-04, 9 -5.02916549572034614D-04, -2.94822138512746025D-04, A -1.75463996970782828D-04, -1.04008550460816434D-04, B -5.96141953046457895D-05, -3.12038929076098340D-05, C -1.26089735980230047D-05, -2.42892608575730389D-07, D 8.05996165414273571D-06, 1.36507009262147391D-05, E 1.73964125472926261D-05, 1.98672978842133780D-05/ DATA BETA(45), BETA(46), BETA(47), BETA(48), BETA(49), BETA(50), 1 BETA(51), BETA(52), BETA(53), BETA(54), BETA(55), BETA(56), 2 BETA(57), BETA(58), BETA(59), BETA(60), BETA(61), BETA(62), 3 BETA(63), BETA(64), BETA(65), BETA(66)/ 4 2.14463263790822639D-05, 2.23954659232456514D-05, 5 2.28967783814712629D-05, 2.30785389811177817D-05, 6 2.30321976080909144D-05, 2.28236073720348722D-05, 7 2.25005881105292418D-05, 2.20981015361991429D-05, 8 2.16418427448103905D-05, 2.11507649256220843D-05, 9 2.06388749782170737D-05, 2.01165241997081666D-05, A 1.95913450141179244D-05, 1.90689367910436740D-05, B 1.85533719641636667D-05, 1.80475722259674218D-05, C 5.52213076721292790D-04, 4.47932581552384646D-04, D 2.79520653992020589D-04, 1.52468156198446602D-04, E 6.93271105657043598D-05, 1.76258683069991397D-05/ DATA BETA(67), BETA(68), BETA(69), BETA(70), BETA(71), BETA(72), 1 BETA(73), BETA(74), BETA(75), BETA(76), BETA(77), BETA(78), 2 BETA(79), BETA(80), BETA(81), BETA(82), BETA(83), BETA(84), 3 BETA(85), BETA(86), BETA(87), BETA(88)/ 4 -1.35744996343269136D-05, -3.17972413350427135D-05, 5 -4.18861861696693365D-05, -4.69004889379141029D-05, 6 -4.87665447413787352D-05, -4.87010031186735069D-05, 7 -4.74755620890086638D-05, -4.55813058138628452D-05, 8 -4.33309644511266036D-05, -4.09230193157750364D-05, 9 -3.84822638603221274D-05, -3.60857167535410501D-05, A -3.37793306123367417D-05, -3.15888560772109621D-05, B -2.95269561750807315D-05, -2.75978914828335759D-05, C -2.58006174666883713D-05, -2.41308356761280200D-05, D -2.25823509518346033D-05, -2.11479656768912971D-05, E -1.98200638885294927D-05, -1.85909870801065077D-05/ DATA BETA(89), BETA(90), BETA(91), BETA(92), BETA(93), BETA(94), 1 BETA(95), BETA(96), BETA(97), BETA(98), BETA(99), BETA(100), 2 BETA(101), BETA(102), BETA(103), BETA(104), BETA(105), 3 BETA(106), BETA(107), BETA(108), BETA(109), BETA(110)/ 4 -1.74532699844210224D-05, -1.63997823854497997D-05, 5 -4.74617796559959808D-04, -4.77864567147321487D-04, 6 -3.20390228067037603D-04, -1.61105016119962282D-04, 7 -4.25778101285435204D-05, 3.44571294294967503D-05, 8 7.97092684075674924D-05, 1.03138236708272200D-04, 9 1.12466775262204158D-04, 1.13103642108481389D-04, A 1.08651634848774268D-04, 1.01437951597661973D-04, B 9.29298396593363896D-05, 8.40293133016089978D-05, C 7.52727991349134062D-05, 6.69632521975730872D-05, D 5.92564547323194704D-05, 5.22169308826975567D-05, E 4.58539485165360646D-05, 4.01445513891486808D-05/ DATA BETA(111), BETA(112), BETA(113), BETA(114), BETA(115), 1 BETA(116), BETA(117), BETA(118), BETA(119), BETA(120), 2 BETA(121), BETA(122), BETA(123), BETA(124), BETA(125), 3 BETA(126), BETA(127), BETA(128), BETA(129), BETA(130)/ 4 3.50481730031328081D-05, 3.05157995034346659D-05, 5 2.64956119950516039D-05, 2.29363633690998152D-05, 6 1.97893056664021636D-05, 1.70091984636412623D-05, 7 1.45547428261524004D-05, 1.23886640995878413D-05, 8 1.04775876076583236D-05, 8.79179954978479373D-06, 9 7.36465810572578444D-04, 8.72790805146193976D-04, A 6.22614862573135066D-04, 2.85998154194304147D-04, B 3.84737672879366102D-06, -1.87906003636971558D-04, C -2.97603646594554535D-04, -3.45998126832656348D-04, D -3.53382470916037712D-04, -3.35715635775048757D-04/ DATA BETA(131), BETA(132), BETA(133), BETA(134), BETA(135), 1 BETA(136), BETA(137), BETA(138), BETA(139), BETA(140), 2 BETA(141), BETA(142), BETA(143), BETA(144), BETA(145), 3 BETA(146), BETA(147), BETA(148), BETA(149), BETA(150)/ 4 -3.04321124789039809D-04, -2.66722723047612821D-04, 5 -2.27654214122819527D-04, -1.89922611854562356D-04, 6 -1.55058918599093870D-04, -1.23778240761873630D-04, 7 -9.62926147717644187D-05, -7.25178327714425337D-05, 8 -5.22070028895633801D-05, -3.50347750511900522D-05, 9 -2.06489761035551757D-05, -8.70106096849767054D-06, A 1.13698686675100290D-06, 9.16426474122778849D-06, B 1.56477785428872620D-05, 2.08223629482466847D-05, C 2.48923381004595156D-05, 2.80340509574146325D-05, D 3.03987774629861915D-05, 3.21156731406700616D-05/ DATA BETA(151), BETA(152), BETA(153), BETA(154), BETA(155), 1 BETA(156), BETA(157), BETA(158), BETA(159), BETA(160), 2 BETA(161), BETA(162), BETA(163), BETA(164), BETA(165), 3 BETA(166), BETA(167), BETA(168), BETA(169), BETA(170)/ 4 -1.80182191963885708D-03, -2.43402962938042533D-03, 5 -1.83422663549856802D-03, -7.62204596354009765D-04, 6 2.39079475256927218D-04, 9.49266117176881141D-04, 7 1.34467449701540359D-03, 1.48457495259449178D-03, 8 1.44732339830617591D-03, 1.30268261285657186D-03, 9 1.10351597375642682D-03, 8.86047440419791759D-04, A 6.73073208165665473D-04, 4.77603872856582378D-04, B 3.05991926358789362D-04, 1.60315694594721630D-04, C 4.00749555270613286D-05, -5.66607461635251611D-05, D -1.32506186772982638D-04, -1.90296187989614057D-04/ DATA BETA(171), BETA(172), BETA(173), BETA(174), BETA(175), 1 BETA(176), BETA(177), BETA(178), BETA(179), BETA(180), 2 BETA(181), BETA(182), BETA(183), BETA(184), BETA(185), 3 BETA(186), BETA(187), BETA(188), BETA(189), BETA(190)/ 4 -2.32811450376937408D-04, -2.62628811464668841D-04, 5 -2.82050469867598672D-04, -2.93081563192861167D-04, 6 -2.97435962176316616D-04, -2.96557334239348078D-04, 7 -2.91647363312090861D-04, -2.83696203837734166D-04, 8 -2.73512317095673346D-04, -2.61750155806768580D-04, 9 6.38585891212050914D-03, 9.62374215806377941D-03, A 7.61878061207001043D-03, 2.83219055545628054D-03, B -2.09841352012720090D-03, -5.73826764216626498D-03, C -7.70804244495414620D-03, -8.21011692264844401D-03, D -7.65824520346905413D-03, -6.47209729391045177D-03/ DATA BETA(191), BETA(192), BETA(193), BETA(194), BETA(195), 1 BETA(196), BETA(197), BETA(198), BETA(199), BETA(200), 2 BETA(201), BETA(202), BETA(203), BETA(204), BETA(205), 3 BETA(206), BETA(207), BETA(208), BETA(209), BETA(210)/ 4 -4.99132412004966473D-03, -3.45612289713133280D-03, 5 -2.01785580014170775D-03, -7.59430686781961401D-04, 6 2.84173631523859138D-04, 1.10891667586337403D-03, 7 1.72901493872728771D-03, 2.16812590802684701D-03, 8 2.45357710494539735D-03, 2.61281821058334862D-03, 9 2.67141039656276912D-03, 2.65203073395980430D-03, A 2.57411652877287315D-03, 2.45389126236094427D-03, B 2.30460058071795494D-03, 2.13684837686712662D-03, C 1.95896528478870911D-03, 1.77737008679454412D-03, D 1.59690280765839059D-03, 1.42111975664438546D-03/ DATA GAMA(1), GAMA(2), GAMA(3), GAMA(4), GAMA(5), GAMA(6), 1 GAMA(7), GAMA(8), GAMA(9), GAMA(10), GAMA(11), GAMA(12), 2 GAMA(13), GAMA(14), GAMA(15), GAMA(16), GAMA(17), GAMA(18), 3 GAMA(19), GAMA(20), GAMA(21), GAMA(22)/ 4 6.29960524947436582D-01, 2.51984209978974633D-01, 5 1.54790300415655846D-01, 1.10713062416159013D-01, 6 8.57309395527394825D-02, 6.97161316958684292D-02, 7 5.86085671893713576D-02, 5.04698873536310685D-02, 8 4.42600580689154809D-02, 3.93720661543509966D-02, 9 3.54283195924455368D-02, 3.21818857502098231D-02, A 2.94646240791157679D-02, 2.71581677112934479D-02, B 2.51768272973861779D-02, 2.34570755306078891D-02, C 2.19508390134907203D-02, 2.06210828235646240D-02, D 1.94388240897880846D-02, 1.83810633800683158D-02, E 1.74293213231963172D-02, 1.65685837786612353D-02/ DATA GAMA(23), GAMA(24), GAMA(25), GAMA(26), GAMA(27), GAMA(28), 1 GAMA(29), GAMA(30)/ 2 1.57865285987918445D-02, 1.50729501494095594D-02, 3 1.44193250839954639D-02, 1.38184805735341786D-02, 4 1.32643378994276568D-02, 1.27517121970498651D-02, 5 1.22761545318762767D-02, 1.18338262398482403D-02/ DATA EX1, EX2, HPI, GPI, THPI / 1 3.33333333333333333D-01, 6.66666666666666667D-01, 2 1.57079632679489662D+00, 3.14159265358979324D+00, 3 4.71238898038468986D+00/ DATA ZEROR,ZEROI,CONER,CONEI / 0.0D0, 0.0D0, 1.0D0, 0.0D0 / C RFNU = 1.0D0/FNU C----------------------------------------------------------------------- C OVERFLOW TEST (Z/FNU TOO SMALL) C----------------------------------------------------------------------- TEST = D1MACH(1)*1.0D+3 AC = FNU*TEST IF (DABS(ZR).GT.AC .OR. DABS(ZI).GT.AC) GO TO 15 ZETA1R = 2.0D0*DABS(DLOG(TEST))+FNU ZETA1I = 0.0D0 ZETA2R = FNU ZETA2I = 0.0D0 PHIR = 1.0D0 PHII = 0.0D0 ARGR = 1.0D0 ARGI = 0.0D0 RETURN 15 CONTINUE ZBR = ZR*RFNU ZBI = ZI*RFNU RFNU2 = RFNU*RFNU C----------------------------------------------------------------------- C COMPUTE IN THE FOURTH QUADRANT C----------------------------------------------------------------------- FN13 = FNU**EX1 FN23 = FN13*FN13 RFN13 = 1.0D0/FN13 W2R = CONER - ZBR*ZBR + ZBI*ZBI W2I = CONEI - ZBR*ZBI - ZBR*ZBI AW2 = ZABS(CMPLX(W2R,W2I,kind=KIND(1.0D0))) IF (AW2.GT.0.25D0) GO TO 130 C----------------------------------------------------------------------- C POWER SERIES FOR CABS(W2).LE.0.25D0 C----------------------------------------------------------------------- K = 1 PR(1) = CONER PI(1) = CONEI SUMAR = GAMA(1) SUMAI = ZEROI AP(1) = 1.0D0 IF (AW2.LT.TOL) GO TO 20 DO 10 K=2,30 PR(K) = PR(K-1)*W2R - PI(K-1)*W2I PI(K) = PR(K-1)*W2I + PI(K-1)*W2R SUMAR = SUMAR + PR(K)*GAMA(K) SUMAI = SUMAI + PI(K)*GAMA(K) AP(K) = AP(K-1)*AW2 IF (AP(K).LT.TOL) GO TO 20 10 CONTINUE K = 30 20 CONTINUE KMAX = K ZETAR = W2R*SUMAR - W2I*SUMAI ZETAI = W2R*SUMAI + W2I*SUMAR ARGR = ZETAR*FN23 ARGI = ZETAI*FN23 CALL ZSQRT(SUMAR, SUMAI, ZAR, ZAI) CALL ZSQRT(W2R, W2I, STR, STI) ZETA2R = STR*FNU ZETA2I = STI*FNU STR = CONER + EX2*(ZETAR*ZAR-ZETAI*ZAI) STI = CONEI + EX2*(ZETAR*ZAI+ZETAI*ZAR) ZETA1R = STR*ZETA2R - STI*ZETA2I ZETA1I = STR*ZETA2I + STI*ZETA2R ZAR = ZAR + ZAR ZAI = ZAI + ZAI CALL ZSQRT(ZAR, ZAI, STR, STI) PHIR = STR*RFN13 PHII = STI*RFN13 IF (IPMTR.EQ.1) GO TO 120 C----------------------------------------------------------------------- C SUM SERIES FOR ASUM AND BSUM C----------------------------------------------------------------------- SUMBR = ZEROR SUMBI = ZEROI DO 30 K=1,KMAX SUMBR = SUMBR + PR(K)*BETA(K) SUMBI = SUMBI + PI(K)*BETA(K) 30 CONTINUE ASUMR = ZEROR ASUMI = ZEROI BSUMR = SUMBR BSUMI = SUMBI L1 = 0 L2 = 30 BTOL = TOL*(DABS(BSUMR)+DABS(BSUMI)) ATOL = TOL PP = 1.0D0 IAS = 0 IBS = 0 IF (RFNU2.LT.TOL) GO TO 110 DO 100 IS=2,7 ATOL = ATOL/RFNU2 PP = PP*RFNU2 IF (IAS.EQ.1) GO TO 60 SUMAR = ZEROR SUMAI = ZEROI DO 40 K=1,KMAX M = L1 + K SUMAR = SUMAR + PR(K)*ALFA(M) SUMAI = SUMAI + PI(K)*ALFA(M) IF (AP(K).LT.ATOL) GO TO 50 40 CONTINUE 50 CONTINUE ASUMR = ASUMR + SUMAR*PP ASUMI = ASUMI + SUMAI*PP IF (PP.LT.TOL) IAS = 1 60 CONTINUE IF (IBS.EQ.1) GO TO 90 SUMBR = ZEROR SUMBI = ZEROI DO 70 K=1,KMAX M = L2 + K SUMBR = SUMBR + PR(K)*BETA(M) SUMBI = SUMBI + PI(K)*BETA(M) IF (AP(K).LT.ATOL) GO TO 80 70 CONTINUE 80 CONTINUE BSUMR = BSUMR + SUMBR*PP BSUMI = BSUMI + SUMBI*PP IF (PP.LT.BTOL) IBS = 1 90 CONTINUE IF (IAS.EQ.1 .AND. IBS.EQ.1) GO TO 110 L1 = L1 + 30 L2 = L2 + 30 100 CONTINUE 110 CONTINUE ASUMR = ASUMR + CONER PP = RFNU*RFN13 BSUMR = BSUMR*PP BSUMI = BSUMI*PP 120 CONTINUE RETURN C----------------------------------------------------------------------- C CABS(W2).GT.0.25D0 C----------------------------------------------------------------------- 130 CONTINUE CALL ZSQRT(W2R, W2I, WR, WI) IF (WR.LT.0.0D0) WR = 0.0D0 IF (WI.LT.0.0D0) WI = 0.0D0 STR = CONER + WR STI = WI CALL ZDIV(STR, STI, ZBR, ZBI, ZAR, ZAI) CALL ZLOG(ZAR, ZAI, ZCR, ZCI, IDUM) IF (ZCI.LT.0.0D0) ZCI = 0.0D0 IF (ZCI.GT.HPI) ZCI = HPI IF (ZCR.LT.0.0D0) ZCR = 0.0D0 ZTHR = (ZCR-WR)*1.5D0 ZTHI = (ZCI-WI)*1.5D0 ZETA1R = ZCR*FNU ZETA1I = ZCI*FNU ZETA2R = WR*FNU ZETA2I = WI*FNU AZTH = ZABS(CMPLX(ZTHR,ZTHI,kind=KIND(1.0D0))) ANG = THPI IF (ZTHR.GE.0.0D0 .AND. ZTHI.LT.0.0D0) GO TO 140 ANG = HPI IF (ZTHR.EQ.0.0D0) GO TO 140 ANG = DATAN(ZTHI/ZTHR) IF (ZTHR.LT.0.0D0) ANG = ANG + GPI 140 CONTINUE PP = AZTH**EX2 ANG = ANG*EX2 ZETAR = PP*DCOS(ANG) ZETAI = PP*DSIN(ANG) IF (ZETAI.LT.0.0D0) ZETAI = 0.0D0 ARGR = ZETAR*FN23 ARGI = ZETAI*FN23 CALL ZDIV(ZTHR, ZTHI, ZETAR, ZETAI, RTZTR, RTZTI) CALL ZDIV(RTZTR, RTZTI, WR, WI, ZAR, ZAI) TZAR = ZAR + ZAR TZAI = ZAI + ZAI CALL ZSQRT(TZAR, TZAI, STR, STI) PHIR = STR*RFN13 PHII = STI*RFN13 IF (IPMTR.EQ.1) GO TO 120 RAW = 1.0D0/DSQRT(AW2) STR = WR*RAW STI = -WI*RAW TFNR = STR*RFNU*RAW TFNI = STI*RFNU*RAW RAZTH = 1.0D0/AZTH STR = ZTHR*RAZTH STI = -ZTHI*RAZTH RZTHR = STR*RAZTH*RFNU RZTHI = STI*RAZTH*RFNU ZCR = RZTHR*AR(2) ZCI = RZTHI*AR(2) RAW2 = 1.0D0/AW2 STR = W2R*RAW2 STI = -W2I*RAW2 T2R = STR*RAW2 T2I = STI*RAW2 STR = T2R*C(2) + C(3) STI = T2I*C(2) UPR(2) = STR*TFNR - STI*TFNI UPI(2) = STR*TFNI + STI*TFNR BSUMR = UPR(2) + ZCR BSUMI = UPI(2) + ZCI ASUMR = ZEROR ASUMI = ZEROI IF (RFNU.LT.TOL) GO TO 220 PRZTHR = RZTHR PRZTHI = RZTHI PTFNR = TFNR PTFNI = TFNI UPR(1) = CONER UPI(1) = CONEI PP = 1.0D0 BTOL = TOL*(DABS(BSUMR)+DABS(BSUMI)) KS = 0 KP1 = 2 L = 3 IAS = 0 IBS = 0 DO 210 LR=2,12,2 LRP1 = LR + 1 C----------------------------------------------------------------------- C COMPUTE TWO ADDITIONAL CR, DR, AND UP FOR TWO MORE TERMS IN C NEXT SUMA AND SUMB C----------------------------------------------------------------------- DO 160 K=LR,LRP1 KS = KS + 1 KP1 = KP1 + 1 L = L + 1 ZAR = C(L) ZAI = ZEROI DO 150 J=2,KP1 L = L + 1 STR = ZAR*T2R - T2I*ZAI + C(L) ZAI = ZAR*T2I + ZAI*T2R ZAR = STR 150 CONTINUE STR = PTFNR*TFNR - PTFNI*TFNI PTFNI = PTFNR*TFNI + PTFNI*TFNR PTFNR = STR UPR(KP1) = PTFNR*ZAR - PTFNI*ZAI UPI(KP1) = PTFNI*ZAR + PTFNR*ZAI CRR(KS) = PRZTHR*BR(KS+1) CRI(KS) = PRZTHI*BR(KS+1) STR = PRZTHR*RZTHR - PRZTHI*RZTHI PRZTHI = PRZTHR*RZTHI + PRZTHI*RZTHR PRZTHR = STR DRR(KS) = PRZTHR*AR(KS+2) DRI(KS) = PRZTHI*AR(KS+2) 160 CONTINUE PP = PP*RFNU2 IF (IAS.EQ.1) GO TO 180 SUMAR = UPR(LRP1) SUMAI = UPI(LRP1) JU = LRP1 DO 170 JR=1,LR JU = JU - 1 SUMAR = SUMAR + CRR(JR)*UPR(JU) - CRI(JR)*UPI(JU) SUMAI = SUMAI + CRR(JR)*UPI(JU) + CRI(JR)*UPR(JU) 170 CONTINUE ASUMR = ASUMR + SUMAR ASUMI = ASUMI + SUMAI TEST = DABS(SUMAR) + DABS(SUMAI) IF (PP.LT.TOL .AND. TEST.LT.TOL) IAS = 1 180 CONTINUE IF (IBS.EQ.1) GO TO 200 SUMBR = UPR(LR+2) + UPR(LRP1)*ZCR - UPI(LRP1)*ZCI SUMBI = UPI(LR+2) + UPR(LRP1)*ZCI + UPI(LRP1)*ZCR JU = LRP1 DO 190 JR=1,LR JU = JU - 1 SUMBR = SUMBR + DRR(JR)*UPR(JU) - DRI(JR)*UPI(JU) SUMBI = SUMBI + DRR(JR)*UPI(JU) + DRI(JR)*UPR(JU) 190 CONTINUE BSUMR = BSUMR + SUMBR BSUMI = BSUMI + SUMBI TEST = DABS(SUMBR) + DABS(SUMBI) IF (PP.LT.BTOL .AND. TEST.LT.BTOL) IBS = 1 200 CONTINUE IF (IAS.EQ.1 .AND. IBS.EQ.1) GO TO 220 210 CONTINUE 220 CONTINUE ASUMR = ASUMR + CONER STR = -BSUMR*RFN13 STI = -BSUMI*RFN13 CALL ZDIV(STR, STI, RTZTR, RTZTI, BSUMR, BSUMI) GO TO 120 END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zuni1.f000066400000000000000000000147551450372207100247420ustar00rootroot00000000000000 SUBROUTINE ZUNI1(ZR, ZI, FNU, KODE, N, YR, YI, NZ, NLAST, FNUL, * TOL, ELIM, ALIM) C***BEGIN PROLOGUE ZUNI1 C***REFER TO ZBESI,ZBESK C C ZUNI1 COMPUTES I(FNU,Z) BY MEANS OF THE UNIFORM ASYMPTOTIC C EXPANSION FOR I(FNU,Z) IN -PI/3.LE.ARG Z.LE.PI/3. C C FNUL IS THE SMALLEST ORDER PERMITTED FOR THE ASYMPTOTIC C EXPANSION. NLAST=0 MEANS ALL OF THE Y VALUES WERE SET. C NLAST.NE.0 IS THE NUMBER LEFT TO BE COMPUTED BY ANOTHER C FORMULA FOR ORDERS FNU TO FNU+NLAST-1 BECAUSE FNU+NLAST-1.LT.FNUL. C Y(I)=CZERO FOR I=NLAST+1,N C C***ROUTINES CALLED ZUCHK,ZUNIK,ZUOIK,D1MACH,ZABS C***END PROLOGUE ZUNI1 C COMPLEX CFN,CONE,CRSC,CSCL,CSR,CSS,CWRK,CZERO,C1,C2,PHI,RZ,SUM,S1, C *S2,Y,Z,ZETA1,ZETA2 DOUBLE PRECISION ALIM, APHI, ASCLE, BRY, CONER, CRSC, * CSCL, CSRR, CSSR, CWRKI, CWRKR, C1R, C2I, C2M, C2R, ELIM, FN, * FNU, FNUL, PHII, PHIR, RAST, RS1, RZI, RZR, STI, STR, SUMI, * SUMR, S1I, S1R, S2I, S2R, TOL, YI, YR, ZEROI, ZEROR, ZETA1I, * ZETA1R, ZETA2I, ZETA2R, ZI, ZR, CYR, CYI, D1MACH, ZABS INTEGER I, IFLAG, INIT, K, KODE, M, N, ND, NLAST, NN, NUF, NW, NZ DIMENSION BRY(3), YR(N), YI(N), CWRKR(16), CWRKI(16), CSSR(3), * CSRR(3), CYR(2), CYI(2) DATA ZEROR,ZEROI,CONER / 0.0D0, 0.0D0, 1.0D0 / C NZ = 0 ND = N NLAST = 0 C----------------------------------------------------------------------- C COMPUTED VALUES WITH EXPONENTS BETWEEN ALIM AND ELIM IN MAG- C NITUDE ARE SCALED TO KEEP INTERMEDIATE ARITHMETIC ON SCALE, C EXP(ALIM)=EXP(ELIM)*TOL C----------------------------------------------------------------------- CSCL = 1.0D0/TOL CRSC = TOL CSSR(1) = CSCL CSSR(2) = CONER CSSR(3) = CRSC CSRR(1) = CRSC CSRR(2) = CONER CSRR(3) = CSCL BRY(1) = 1.0D+3*D1MACH(1)/TOL C----------------------------------------------------------------------- C CHECK FOR UNDERFLOW AND OVERFLOW ON FIRST MEMBER C----------------------------------------------------------------------- FN = DMAX1(FNU,1.0D0) INIT = 0 CALL ZUNIK(ZR, ZI, FN, 1, 1, TOL, INIT, PHIR, PHII, ZETA1R, * ZETA1I, ZETA2R, ZETA2I, SUMR, SUMI, CWRKR, CWRKI) IF (KODE.EQ.1) GO TO 10 STR = ZR + ZETA2R STI = ZI + ZETA2I RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = -ZETA1R + STR S1I = -ZETA1I + STI GO TO 20 10 CONTINUE S1R = -ZETA1R + ZETA2R S1I = -ZETA1I + ZETA2I 20 CONTINUE RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 130 30 CONTINUE NN = MIN0(2,ND) DO 80 I=1,NN FN = FNU + DBLE(FLOAT(ND-I)) INIT = 0 CALL ZUNIK(ZR, ZI, FN, 1, 0, TOL, INIT, PHIR, PHII, ZETA1R, * ZETA1I, ZETA2R, ZETA2I, SUMR, SUMI, CWRKR, CWRKI) IF (KODE.EQ.1) GO TO 40 STR = ZR + ZETA2R STI = ZI + ZETA2I RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = -ZETA1R + STR S1I = -ZETA1I + STI + ZI GO TO 50 40 CONTINUE S1R = -ZETA1R + ZETA2R S1I = -ZETA1I + ZETA2I 50 CONTINUE C----------------------------------------------------------------------- C TEST FOR UNDERFLOW AND OVERFLOW C----------------------------------------------------------------------- RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 110 IF (I.EQ.1) IFLAG = 2 IF (DABS(RS1).LT.ALIM) GO TO 60 C----------------------------------------------------------------------- C REFINE TEST AND SCALE C----------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIR,PHII,kind=KIND(1.0D0))) RS1 = RS1 + DLOG(APHI) IF (DABS(RS1).GT.ELIM) GO TO 110 IF (I.EQ.1) IFLAG = 1 IF (RS1.LT.0.0D0) GO TO 60 IF (I.EQ.1) IFLAG = 3 60 CONTINUE C----------------------------------------------------------------------- C SCALE S1 IF CABS(S1).LT.ASCLE C----------------------------------------------------------------------- S2R = PHIR*SUMR - PHII*SUMI S2I = PHIR*SUMI + PHII*SUMR STR = DEXP(S1R)*CSSR(IFLAG) S1R = STR*DCOS(S1I) S1I = STR*DSIN(S1I) STR = S2R*S1R - S2I*S1I S2I = S2R*S1I + S2I*S1R S2R = STR IF (IFLAG.NE.1) GO TO 70 CALL ZUCHK(S2R, S2I, NW, BRY(1), TOL) IF (NW.NE.0) GO TO 110 70 CONTINUE CYR(I) = S2R CYI(I) = S2I M = ND - I + 1 YR(M) = S2R*CSRR(IFLAG) YI(M) = S2I*CSRR(IFLAG) 80 CONTINUE IF (ND.LE.2) GO TO 100 RAST = 1.0D0/ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) STR = ZR*RAST STI = -ZI*RAST RZR = (STR+STR)*RAST RZI = (STI+STI)*RAST BRY(2) = 1.0D0/BRY(1) BRY(3) = D1MACH(2) S1R = CYR(1) S1I = CYI(1) S2R = CYR(2) S2I = CYI(2) C1R = CSRR(IFLAG) ASCLE = BRY(IFLAG) K = ND - 2 FN = DBLE(FLOAT(K)) DO 90 I=3,ND C2R = S2R C2I = S2I S2R = S1R + (FNU+FN)*(RZR*C2R-RZI*C2I) S2I = S1I + (FNU+FN)*(RZR*C2I+RZI*C2R) S1R = C2R S1I = C2I C2R = S2R*C1R C2I = S2I*C1R YR(K) = C2R YI(K) = C2I K = K - 1 FN = FN - 1.0D0 IF (IFLAG.GE.3) GO TO 90 STR = DABS(C2R) STI = DABS(C2I) C2M = DMAX1(STR,STI) IF (C2M.LE.ASCLE) GO TO 90 IFLAG = IFLAG + 1 ASCLE = BRY(IFLAG) S1R = S1R*C1R S1I = S1I*C1R S2R = C2R S2I = C2I S1R = S1R*CSSR(IFLAG) S1I = S1I*CSSR(IFLAG) S2R = S2R*CSSR(IFLAG) S2I = S2I*CSSR(IFLAG) C1R = CSRR(IFLAG) 90 CONTINUE 100 CONTINUE RETURN C----------------------------------------------------------------------- C SET UNDERFLOW AND UPDATE PARAMETERS C----------------------------------------------------------------------- 110 CONTINUE IF (RS1.GT.0.0D0) GO TO 120 YR(ND) = ZEROR YI(ND) = ZEROI NZ = NZ + 1 ND = ND - 1 IF (ND.EQ.0) GO TO 100 CALL ZUOIK(ZR, ZI, FNU, KODE, 1, ND, YR, YI, NUF, TOL, ELIM, ALIM) IF (NUF.LT.0) GO TO 120 ND = ND - NUF NZ = NZ + NUF IF (ND.EQ.0) GO TO 100 FN = FNU + DBLE(FLOAT(ND-1)) IF (FN.GE.FNUL) GO TO 30 NLAST = ND RETURN 120 CONTINUE NZ = -1 RETURN 130 CONTINUE IF (RS1.GT.0.0D0) GO TO 120 NZ = N DO 140 I=1,N YR(I) = ZEROR YI(I) = ZEROI 140 CONTINUE RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zuni2.f000066400000000000000000000212411450372207100247270ustar00rootroot00000000000000 SUBROUTINE ZUNI2(ZR, ZI, FNU, KODE, N, YR, YI, NZ, NLAST, FNUL, * TOL, ELIM, ALIM) C***BEGIN PROLOGUE ZUNI2 C***REFER TO ZBESI,ZBESK C C ZUNI2 COMPUTES I(FNU,Z) IN THE RIGHT HALF PLANE BY MEANS OF C UNIFORM ASYMPTOTIC EXPANSION FOR J(FNU,ZN) WHERE ZN IS Z*I C OR -Z*I AND ZN IS IN THE RIGHT HALF PLANE ALSO. C C FNUL IS THE SMALLEST ORDER PERMITTED FOR THE ASYMPTOTIC C EXPANSION. NLAST=0 MEANS ALL OF THE Y VALUES WERE SET. C NLAST.NE.0 IS THE NUMBER LEFT TO BE COMPUTED BY ANOTHER C FORMULA FOR ORDERS FNU TO FNU+NLAST-1 BECAUSE FNU+NLAST-1.LT.FNUL. C Y(I)=CZERO FOR I=NLAST+1,N C C***ROUTINES CALLED ZAIRY,ZUCHK,ZUNHJ,ZUOIK,D1MACH,ZABS C***END PROLOGUE ZUNI2 C COMPLEX AI,ARG,ASUM,BSUM,CFN,CI,CID,CIP,CONE,CRSC,CSCL,CSR,CSS, C *CZERO,C1,C2,DAI,PHI,RZ,S1,S2,Y,Z,ZB,ZETA1,ZETA2,ZN DOUBLE PRECISION AARG, AIC, AII, AIR, ALIM, ANG, APHI, ARGI, * ARGR, ASCLE, ASUMI, ASUMR, BRY, BSUMI, BSUMR, CIDI, CIPI, CIPR, * CONER, CRSC, CSCL, CSRR, CSSR, C1R, C2I, C2M, C2R, DAII, * DAIR, ELIM, FN, FNU, FNUL, HPI, PHII, PHIR, RAST, RAZ, RS1, RZI, * RZR, STI, STR, S1I, S1R, S2I, S2R, TOL, YI, YR, ZBI, ZBR, ZEROI, * ZEROR, ZETA1I, ZETA1R, ZETA2I, ZETA2R, ZI, ZNI, ZNR, ZR, CYR, * CYI, D1MACH, ZABS, CAR, SAR INTEGER I, IFLAG, IN, INU, J, K, KODE, N, NAI, ND, NDAI, NLAST, * NN, NUF, NW, NZ, IDUM DIMENSION BRY(3), YR(N), YI(N), CIPR(4), CIPI(4), CSSR(3), * CSRR(3), CYR(2), CYI(2) DATA ZEROR,ZEROI,CONER / 0.0D0, 0.0D0, 1.0D0 / DATA CIPR(1),CIPI(1),CIPR(2),CIPI(2),CIPR(3),CIPI(3),CIPR(4), * CIPI(4)/ 1.0D0,0.0D0, 0.0D0,1.0D0, -1.0D0,0.0D0, 0.0D0,-1.0D0/ DATA HPI, AIC / 1 1.57079632679489662D+00, 1.265512123484645396D+00/ C NZ = 0 ND = N NLAST = 0 C----------------------------------------------------------------------- C COMPUTED VALUES WITH EXPONENTS BETWEEN ALIM AND ELIM IN MAG- C NITUDE ARE SCALED TO KEEP INTERMEDIATE ARITHMETIC ON SCALE, C EXP(ALIM)=EXP(ELIM)*TOL C----------------------------------------------------------------------- CSCL = 1.0D0/TOL CRSC = TOL CSSR(1) = CSCL CSSR(2) = CONER CSSR(3) = CRSC CSRR(1) = CRSC CSRR(2) = CONER CSRR(3) = CSCL BRY(1) = 1.0D+3*D1MACH(1)/TOL C----------------------------------------------------------------------- C ZN IS IN THE RIGHT HALF PLANE AFTER ROTATION BY CI OR -CI C----------------------------------------------------------------------- ZNR = ZI ZNI = -ZR ZBR = ZR ZBI = ZI CIDI = -CONER INU = INT(SNGL(FNU)) ANG = HPI*(FNU-DBLE(FLOAT(INU))) C2R = DCOS(ANG) C2I = DSIN(ANG) CAR = C2R SAR = C2I IN = INU + N - 1 IN = MOD(IN,4) + 1 STR = C2R*CIPR(IN) - C2I*CIPI(IN) C2I = C2R*CIPI(IN) + C2I*CIPR(IN) C2R = STR IF (ZI.GT.0.0D0) GO TO 10 ZNR = -ZNR ZBI = -ZBI CIDI = -CIDI C2I = -C2I 10 CONTINUE C----------------------------------------------------------------------- C CHECK FOR UNDERFLOW AND OVERFLOW ON FIRST MEMBER C----------------------------------------------------------------------- FN = DMAX1(FNU,1.0D0) CALL ZUNHJ(ZNR, ZNI, FN, 1, TOL, PHIR, PHII, ARGR, ARGI, ZETA1R, * ZETA1I, ZETA2R, ZETA2I, ASUMR, ASUMI, BSUMR, BSUMI) IF (KODE.EQ.1) GO TO 20 STR = ZBR + ZETA2R STI = ZBI + ZETA2I RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = -ZETA1R + STR S1I = -ZETA1I + STI GO TO 30 20 CONTINUE S1R = -ZETA1R + ZETA2R S1I = -ZETA1I + ZETA2I 30 CONTINUE RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 150 40 CONTINUE NN = MIN0(2,ND) DO 90 I=1,NN FN = FNU + DBLE(FLOAT(ND-I)) CALL ZUNHJ(ZNR, ZNI, FN, 0, TOL, PHIR, PHII, ARGR, ARGI, * ZETA1R, ZETA1I, ZETA2R, ZETA2I, ASUMR, ASUMI, BSUMR, BSUMI) IF (KODE.EQ.1) GO TO 50 STR = ZBR + ZETA2R STI = ZBI + ZETA2I RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = -ZETA1R + STR S1I = -ZETA1I + STI + DABS(ZI) GO TO 60 50 CONTINUE S1R = -ZETA1R + ZETA2R S1I = -ZETA1I + ZETA2I 60 CONTINUE C----------------------------------------------------------------------- C TEST FOR UNDERFLOW AND OVERFLOW C----------------------------------------------------------------------- RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 120 IF (I.EQ.1) IFLAG = 2 IF (DABS(RS1).LT.ALIM) GO TO 70 C----------------------------------------------------------------------- C REFINE TEST AND SCALE C----------------------------------------------------------------------- C----------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIR,PHII,kind=KIND(1.0D0))) AARG = ZABS(CMPLX(ARGR,ARGI,kind=KIND(1.0D0))) RS1 = RS1 + DLOG(APHI) - 0.25D0*DLOG(AARG) - AIC IF (DABS(RS1).GT.ELIM) GO TO 120 IF (I.EQ.1) IFLAG = 1 IF (RS1.LT.0.0D0) GO TO 70 IF (I.EQ.1) IFLAG = 3 70 CONTINUE C----------------------------------------------------------------------- C SCALE S1 TO KEEP INTERMEDIATE ARITHMETIC ON SCALE NEAR C EXPONENT EXTREMES C----------------------------------------------------------------------- CALL ZAIRY(ARGR, ARGI, 0, 2, AIR, AII, NAI, IDUM) CALL ZAIRY(ARGR, ARGI, 1, 2, DAIR, DAII, NDAI, IDUM) STR = DAIR*BSUMR - DAII*BSUMI STI = DAIR*BSUMI + DAII*BSUMR STR = STR + (AIR*ASUMR-AII*ASUMI) STI = STI + (AIR*ASUMI+AII*ASUMR) S2R = PHIR*STR - PHII*STI S2I = PHIR*STI + PHII*STR STR = DEXP(S1R)*CSSR(IFLAG) S1R = STR*DCOS(S1I) S1I = STR*DSIN(S1I) STR = S2R*S1R - S2I*S1I S2I = S2R*S1I + S2I*S1R S2R = STR IF (IFLAG.NE.1) GO TO 80 CALL ZUCHK(S2R, S2I, NW, BRY(1), TOL) IF (NW.NE.0) GO TO 120 80 CONTINUE IF (ZI.LE.0.0D0) S2I = -S2I STR = S2R*C2R - S2I*C2I S2I = S2R*C2I + S2I*C2R S2R = STR CYR(I) = S2R CYI(I) = S2I J = ND - I + 1 YR(J) = S2R*CSRR(IFLAG) YI(J) = S2I*CSRR(IFLAG) STR = -C2I*CIDI C2I = C2R*CIDI C2R = STR 90 CONTINUE IF (ND.LE.2) GO TO 110 RAZ = 1.0D0/ZABS(CMPLX(ZR,ZI,kind=KIND(1.0D0))) STR = ZR*RAZ STI = -ZI*RAZ RZR = (STR+STR)*RAZ RZI = (STI+STI)*RAZ BRY(2) = 1.0D0/BRY(1) BRY(3) = D1MACH(2) S1R = CYR(1) S1I = CYI(1) S2R = CYR(2) S2I = CYI(2) C1R = CSRR(IFLAG) ASCLE = BRY(IFLAG) K = ND - 2 FN = DBLE(FLOAT(K)) DO 100 I=3,ND C2R = S2R C2I = S2I S2R = S1R + (FNU+FN)*(RZR*C2R-RZI*C2I) S2I = S1I + (FNU+FN)*(RZR*C2I+RZI*C2R) S1R = C2R S1I = C2I C2R = S2R*C1R C2I = S2I*C1R YR(K) = C2R YI(K) = C2I K = K - 1 FN = FN - 1.0D0 IF (IFLAG.GE.3) GO TO 100 STR = DABS(C2R) STI = DABS(C2I) C2M = DMAX1(STR,STI) IF (C2M.LE.ASCLE) GO TO 100 IFLAG = IFLAG + 1 ASCLE = BRY(IFLAG) S1R = S1R*C1R S1I = S1I*C1R S2R = C2R S2I = C2I S1R = S1R*CSSR(IFLAG) S1I = S1I*CSSR(IFLAG) S2R = S2R*CSSR(IFLAG) S2I = S2I*CSSR(IFLAG) C1R = CSRR(IFLAG) 100 CONTINUE 110 CONTINUE RETURN 120 CONTINUE IF (RS1.GT.0.0D0) GO TO 140 C----------------------------------------------------------------------- C SET UNDERFLOW AND UPDATE PARAMETERS C----------------------------------------------------------------------- YR(ND) = ZEROR YI(ND) = ZEROI NZ = NZ + 1 ND = ND - 1 IF (ND.EQ.0) GO TO 110 CALL ZUOIK(ZR, ZI, FNU, KODE, 1, ND, YR, YI, NUF, TOL, ELIM, ALIM) IF (NUF.LT.0) GO TO 140 ND = ND - NUF NZ = NZ + NUF IF (ND.EQ.0) GO TO 110 FN = FNU + DBLE(FLOAT(ND-1)) IF (FN.LT.FNUL) GO TO 130 C FN = CIDI C J = NUF + 1 C K = MOD(J,4) + 1 C S1R = CIPR(K) C S1I = CIPI(K) C IF (FN.LT.0.0D0) S1I = -S1I C STR = C2R*S1R - C2I*S1I C C2I = C2R*S1I + C2I*S1R C C2R = STR IN = INU + ND - 1 IN = MOD(IN,4) + 1 C2R = CAR*CIPR(IN) - SAR*CIPI(IN) C2I = CAR*CIPI(IN) + SAR*CIPR(IN) IF (ZI.LE.0.0D0) C2I = -C2I GO TO 40 130 CONTINUE NLAST = ND RETURN 140 CONTINUE NZ = -1 RETURN 150 CONTINUE IF (RS1.GT.0.0D0) GO TO 140 NZ = N DO 160 I=1,N YR(I) = ZEROR YI(I) = ZEROI 160 CONTINUE RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zunik.f000066400000000000000000000221371450372207100250250ustar00rootroot00000000000000 SUBROUTINE ZUNIK(ZRR, ZRI, FNU, IKFLG, IPMTR, TOL, INIT, PHIR, * PHII, ZETA1R, ZETA1I, ZETA2R, ZETA2I, SUMR, SUMI, CWRKR, CWRKI) C***BEGIN PROLOGUE ZUNIK C***REFER TO ZBESI,ZBESK C C ZUNIK COMPUTES PARAMETERS FOR THE UNIFORM ASYMPTOTIC C EXPANSIONS OF THE I AND K FUNCTIONS ON IKFLG= 1 OR 2 C RESPECTIVELY BY C C W(FNU,ZR) = PHI*EXP(ZETA)*SUM C C WHERE ZETA=-ZETA1 + ZETA2 OR C ZETA1 - ZETA2 C C THE FIRST CALL MUST HAVE INIT=0. SUBSEQUENT CALLS WITH THE C SAME ZR AND FNU WILL RETURN THE I OR K FUNCTION ON IKFLG= C 1 OR 2 WITH NO CHANGE IN INIT. CWRK IS A COMPLEX WORK C ARRAY. IPMTR=0 COMPUTES ALL PARAMETERS. IPMTR=1 COMPUTES PHI, C ZETA1,ZETA2. C C***ROUTINES CALLED ZDIV,ZLOG,ZSQRT,D1MACH C***END PROLOGUE ZUNIK C COMPLEX CFN,CON,CONE,CRFN,CWRK,CZERO,PHI,S,SR,SUM,T,T2,ZETA1, C *ZETA2,ZN,ZR DOUBLE PRECISION AC, C, CON, CONEI, CONER, CRFNI, CRFNR, CWRKI, * CWRKR, FNU, PHII, PHIR, RFN, SI, SR, SRI, SRR, STI, STR, SUMI, * SUMR, TEST, TI, TOL, TR, T2I, T2R, ZEROI, ZEROR, ZETA1I, ZETA1R, * ZETA2I, ZETA2R, ZNI, ZNR, ZRI, ZRR, D1MACH INTEGER I, IDUM, IKFLG, INIT, IPMTR, J, K, L DIMENSION C(120), CWRKR(16), CWRKI(16), CON(2) DATA ZEROR,ZEROI,CONER,CONEI / 0.0D0, 0.0D0, 1.0D0, 0.0D0 / DATA CON(1), CON(2) / 1 3.98942280401432678D-01, 1.25331413731550025D+00 / DATA C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), C(10), 1 C(11), C(12), C(13), C(14), C(15), C(16), C(17), C(18), 2 C(19), C(20), C(21), C(22), C(23), C(24)/ 3 1.00000000000000000D+00, -2.08333333333333333D-01, 4 1.25000000000000000D-01, 3.34201388888888889D-01, 5 -4.01041666666666667D-01, 7.03125000000000000D-02, 6 -1.02581259645061728D+00, 1.84646267361111111D+00, 7 -8.91210937500000000D-01, 7.32421875000000000D-02, 8 4.66958442342624743D+00, -1.12070026162229938D+01, 9 8.78912353515625000D+00, -2.36408691406250000D+00, A 1.12152099609375000D-01, -2.82120725582002449D+01, B 8.46362176746007346D+01, -9.18182415432400174D+01, C 4.25349987453884549D+01, -7.36879435947963170D+00, D 2.27108001708984375D-01, 2.12570130039217123D+02, E -7.65252468141181642D+02, 1.05999045252799988D+03/ DATA C(25), C(26), C(27), C(28), C(29), C(30), C(31), C(32), 1 C(33), C(34), C(35), C(36), C(37), C(38), C(39), C(40), 2 C(41), C(42), C(43), C(44), C(45), C(46), C(47), C(48)/ 3 -6.99579627376132541D+02, 2.18190511744211590D+02, 4 -2.64914304869515555D+01, 5.72501420974731445D-01, 5 -1.91945766231840700D+03, 8.06172218173730938D+03, 6 -1.35865500064341374D+04, 1.16553933368645332D+04, 7 -5.30564697861340311D+03, 1.20090291321635246D+03, 8 -1.08090919788394656D+02, 1.72772750258445740D+00, 9 2.02042913309661486D+04, -9.69805983886375135D+04, A 1.92547001232531532D+05, -2.03400177280415534D+05, B 1.22200464983017460D+05, -4.11926549688975513D+04, C 7.10951430248936372D+03, -4.93915304773088012D+02, D 6.07404200127348304D+00, -2.42919187900551333D+05, E 1.31176361466297720D+06, -2.99801591853810675D+06/ DATA C(49), C(50), C(51), C(52), C(53), C(54), C(55), C(56), 1 C(57), C(58), C(59), C(60), C(61), C(62), C(63), C(64), 2 C(65), C(66), C(67), C(68), C(69), C(70), C(71), C(72)/ 3 3.76327129765640400D+06, -2.81356322658653411D+06, 4 1.26836527332162478D+06, -3.31645172484563578D+05, 5 4.52187689813627263D+04, -2.49983048181120962D+03, 6 2.43805296995560639D+01, 3.28446985307203782D+06, 7 -1.97068191184322269D+07, 5.09526024926646422D+07, 8 -7.41051482115326577D+07, 6.63445122747290267D+07, 9 -3.75671766607633513D+07, 1.32887671664218183D+07, A -2.78561812808645469D+06, 3.08186404612662398D+05, B -1.38860897537170405D+04, 1.10017140269246738D+02, C -4.93292536645099620D+07, 3.25573074185765749D+08, D -9.39462359681578403D+08, 1.55359689957058006D+09, E -1.62108055210833708D+09, 1.10684281682301447D+09/ DATA C(73), C(74), C(75), C(76), C(77), C(78), C(79), C(80), 1 C(81), C(82), C(83), C(84), C(85), C(86), C(87), C(88), 2 C(89), C(90), C(91), C(92), C(93), C(94), C(95), C(96)/ 3 -4.95889784275030309D+08, 1.42062907797533095D+08, 4 -2.44740627257387285D+07, 2.24376817792244943D+06, 5 -8.40054336030240853D+04, 5.51335896122020586D+02, 6 8.14789096118312115D+08, -5.86648149205184723D+09, 7 1.86882075092958249D+10, -3.46320433881587779D+10, 8 4.12801855797539740D+10, -3.30265997498007231D+10, 9 1.79542137311556001D+10, -6.56329379261928433D+09, A 1.55927986487925751D+09, -2.25105661889415278D+08, B 1.73951075539781645D+07, -5.49842327572288687D+05, C 3.03809051092238427D+03, -1.46792612476956167D+10, D 1.14498237732025810D+11, -3.99096175224466498D+11, E 8.19218669548577329D+11, -1.09837515608122331D+12/ DATA C(97), C(98), C(99), C(100), C(101), C(102), C(103), C(104), 1 C(105), C(106), C(107), C(108), C(109), C(110), C(111), 2 C(112), C(113), C(114), C(115), C(116), C(117), C(118)/ 3 1.00815810686538209D+12, -6.45364869245376503D+11, 4 2.87900649906150589D+11, -8.78670721780232657D+10, 5 1.76347306068349694D+10, -2.16716498322379509D+09, 6 1.43157876718888981D+08, -3.87183344257261262D+06, 7 1.82577554742931747D+04, 2.86464035717679043D+11, 8 -2.40629790002850396D+12, 9.10934118523989896D+12, 9 -2.05168994109344374D+13, 3.05651255199353206D+13, A -3.16670885847851584D+13, 2.33483640445818409D+13, B -1.23204913055982872D+13, 4.61272578084913197D+12, C -1.19655288019618160D+12, 2.05914503232410016D+11, D -2.18229277575292237D+10, 1.24700929351271032D+09/ DATA C(119), C(120)/ 1 -2.91883881222208134D+07, 1.18838426256783253D+05/ C IF (INIT.NE.0) GO TO 40 C----------------------------------------------------------------------- C INITIALIZE ALL VARIABLES C----------------------------------------------------------------------- RFN = 1.0D0/FNU C----------------------------------------------------------------------- C OVERFLOW TEST (ZR/FNU TOO SMALL) C----------------------------------------------------------------------- TEST = D1MACH(1)*1.0D+3 AC = FNU*TEST IF (DABS(ZRR).GT.AC .OR. DABS(ZRI).GT.AC) GO TO 15 ZETA1R = 2.0D0*DABS(DLOG(TEST))+FNU ZETA1I = 0.0D0 ZETA2R = FNU ZETA2I = 0.0D0 PHIR = 1.0D0 PHII = 0.0D0 RETURN 15 CONTINUE TR = ZRR*RFN TI = ZRI*RFN SR = CONER + (TR*TR-TI*TI) SI = CONEI + (TR*TI+TI*TR) CALL ZSQRT(SR, SI, SRR, SRI) STR = CONER + SRR STI = CONEI + SRI CALL ZDIV(STR, STI, TR, TI, ZNR, ZNI) CALL ZLOG(ZNR, ZNI, STR, STI, IDUM) ZETA1R = FNU*STR ZETA1I = FNU*STI ZETA2R = FNU*SRR ZETA2I = FNU*SRI CALL ZDIV(CONER, CONEI, SRR, SRI, TR, TI) SRR = TR*RFN SRI = TI*RFN CALL ZSQRT(SRR, SRI, CWRKR(16), CWRKI(16)) PHIR = CWRKR(16)*CON(IKFLG) PHII = CWRKI(16)*CON(IKFLG) IF (IPMTR.NE.0) RETURN CALL ZDIV(CONER, CONEI, SR, SI, T2R, T2I) CWRKR(1) = CONER CWRKI(1) = CONEI CRFNR = CONER CRFNI = CONEI AC = 1.0D0 L = 1 DO 20 K=2,15 SR = ZEROR SI = ZEROI DO 10 J=1,K L = L + 1 STR = SR*T2R - SI*T2I + C(L) SI = SR*T2I + SI*T2R SR = STR 10 CONTINUE STR = CRFNR*SRR - CRFNI*SRI CRFNI = CRFNR*SRI + CRFNI*SRR CRFNR = STR CWRKR(K) = CRFNR*SR - CRFNI*SI CWRKI(K) = CRFNR*SI + CRFNI*SR AC = AC*RFN TEST = DABS(CWRKR(K)) + DABS(CWRKI(K)) IF (AC.LT.TOL .AND. TEST.LT.TOL) GO TO 30 20 CONTINUE K = 15 30 CONTINUE INIT = K 40 CONTINUE IF (IKFLG.EQ.2) GO TO 60 C----------------------------------------------------------------------- C COMPUTE SUM FOR THE I FUNCTION C----------------------------------------------------------------------- SR = ZEROR SI = ZEROI DO 50 I=1,INIT SR = SR + CWRKR(I) SI = SI + CWRKI(I) 50 CONTINUE SUMR = SR SUMI = SI PHIR = CWRKR(16)*CON(1) PHII = CWRKI(16)*CON(1) RETURN 60 CONTINUE C----------------------------------------------------------------------- C COMPUTE SUM FOR THE K FUNCTION C----------------------------------------------------------------------- SR = ZEROR SI = ZEROI TR = CONER DO 70 I=1,INIT SR = SR + TR*CWRKR(I) SI = SI + TR*CWRKI(I) TR = -TR 70 CONTINUE SUMR = SR SUMI = SI PHIR = CWRKR(16)*CON(2) PHII = CWRKI(16)*CON(2) RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zunk1.f000066400000000000000000000335201450372207100247330ustar00rootroot00000000000000 SUBROUTINE ZUNK1(ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, TOL, ELIM, * ALIM) C***BEGIN PROLOGUE ZUNK1 C***REFER TO ZBESK C C ZUNK1 COMPUTES K(FNU,Z) AND ITS ANALYTIC CONTINUATION FROM THE C RIGHT HALF PLANE TO THE LEFT HALF PLANE BY MEANS OF THE C UNIFORM ASYMPTOTIC EXPANSION. C MR INDICATES THE DIRECTION OF ROTATION FOR ANALYTIC CONTINUATION. C NZ=-1 MEANS AN OVERFLOW WILL OCCUR C C***ROUTINES CALLED ZKSCL,ZS1S2,ZUCHK,ZUNIK,D1MACH,ZABS C***END PROLOGUE ZUNK1 C COMPLEX CFN,CK,CONE,CRSC,CS,CSCL,CSGN,CSPN,CSR,CSS,CWRK,CY,CZERO, C *C1,C2,PHI,PHID,RZ,SUM,SUMD,S1,S2,Y,Z,ZETA1,ZETA1D,ZETA2,ZETA2D,ZR DOUBLE PRECISION ALIM, ANG, APHI, ASC, ASCLE, BRY, CKI, CKR, * CONER, CRSC, CSCL, CSGNI, CSPNI, CSPNR, CSR, CSRR, CSSR, * CWRKI, CWRKR, CYI, CYR, C1I, C1R, C2I, C2M, C2R, ELIM, FMR, FN, * FNF, FNU, PHIDI, PHIDR, PHII, PHIR, PI, RAST, RAZR, RS1, RZI, * RZR, SGN, STI, STR, SUMDI, SUMDR, SUMI, SUMR, S1I, S1R, S2I, * S2R, TOL, YI, YR, ZEROI, ZEROR, ZETA1I, ZETA1R, ZETA2I, ZETA2R, * ZET1DI, ZET1DR, ZET2DI, ZET2DR, ZI, ZR, ZRI, ZRR, D1MACH, ZABS INTEGER I, IB, IFLAG, IFN, IL, INIT, INU, IUF, K, KDFLG, KFLAG, * KK, KODE, MR, N, NW, NZ, INITD, IC, IPARD, J DIMENSION BRY(3), INIT(2), YR(N), YI(N), SUMR(2), SUMI(2), * ZETA1R(2), ZETA1I(2), ZETA2R(2), ZETA2I(2), CYR(2), CYI(2), * CWRKR(16,3), CWRKI(16,3), CSSR(3), CSRR(3), PHIR(2), PHII(2) DATA ZEROR,ZEROI,CONER / 0.0D0, 0.0D0, 1.0D0 / DATA PI / 3.14159265358979324D0 / C KDFLG = 1 NZ = 0 C----------------------------------------------------------------------- C EXP(-ALIM)=EXP(-ELIM)/TOL=APPROX. ONE PRECISION GREATER THAN C THE UNDERFLOW LIMIT C----------------------------------------------------------------------- CSCL = 1.0D0/TOL CRSC = TOL CSSR(1) = CSCL CSSR(2) = CONER CSSR(3) = CRSC CSRR(1) = CRSC CSRR(2) = CONER CSRR(3) = CSCL BRY(1) = 1.0D+3*D1MACH(1)/TOL BRY(2) = 1.0D0/BRY(1) BRY(3) = D1MACH(2) ZRR = ZR ZRI = ZI IF (ZR.GE.0.0D0) GO TO 10 ZRR = -ZR ZRI = -ZI 10 CONTINUE J = 2 DO 70 I=1,N C----------------------------------------------------------------------- C J FLIP FLOPS BETWEEN 1 AND 2 IN J = 3 - J C----------------------------------------------------------------------- J = 3 - J FN = FNU + DBLE(FLOAT(I-1)) INIT(J) = 0 CALL ZUNIK(ZRR, ZRI, FN, 2, 0, TOL, INIT(J), PHIR(J), PHII(J), * ZETA1R(J), ZETA1I(J), ZETA2R(J), ZETA2I(J), SUMR(J), SUMI(J), * CWRKR(1,J), CWRKI(1,J)) IF (KODE.EQ.1) GO TO 20 STR = ZRR + ZETA2R(J) STI = ZRI + ZETA2I(J) RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = ZETA1R(J) - STR S1I = ZETA1I(J) - STI GO TO 30 20 CONTINUE S1R = ZETA1R(J) - ZETA2R(J) S1I = ZETA1I(J) - ZETA2I(J) 30 CONTINUE RS1 = S1R C----------------------------------------------------------------------- C TEST FOR UNDERFLOW AND OVERFLOW C----------------------------------------------------------------------- IF (DABS(RS1).GT.ELIM) GO TO 60 IF (KDFLG.EQ.1) KFLAG = 2 IF (DABS(RS1).LT.ALIM) GO TO 40 C----------------------------------------------------------------------- C REFINE TEST AND SCALE C----------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIR(J),PHII(J),kind=KIND(1.0D0))) RS1 = RS1 + DLOG(APHI) IF (DABS(RS1).GT.ELIM) GO TO 60 IF (KDFLG.EQ.1) KFLAG = 1 IF (RS1.LT.0.0D0) GO TO 40 IF (KDFLG.EQ.1) KFLAG = 3 40 CONTINUE C----------------------------------------------------------------------- C SCALE S1 TO KEEP INTERMEDIATE ARITHMETIC ON SCALE NEAR C EXPONENT EXTREMES C----------------------------------------------------------------------- S2R = PHIR(J)*SUMR(J) - PHII(J)*SUMI(J) S2I = PHIR(J)*SUMI(J) + PHII(J)*SUMR(J) STR = DEXP(S1R)*CSSR(KFLAG) S1R = STR*DCOS(S1I) S1I = STR*DSIN(S1I) STR = S2R*S1R - S2I*S1I S2I = S1R*S2I + S2R*S1I S2R = STR IF (KFLAG.NE.1) GO TO 50 CALL ZUCHK(S2R, S2I, NW, BRY(1), TOL) IF (NW.NE.0) GO TO 60 50 CONTINUE CYR(KDFLG) = S2R CYI(KDFLG) = S2I YR(I) = S2R*CSRR(KFLAG) YI(I) = S2I*CSRR(KFLAG) IF (KDFLG.EQ.2) GO TO 75 KDFLG = 2 GO TO 70 60 CONTINUE IF (RS1.GT.0.0D0) GO TO 300 C----------------------------------------------------------------------- C FOR ZR.LT.0.0, THE I FUNCTION TO BE ADDED WILL OVERFLOW C----------------------------------------------------------------------- IF (ZR.LT.0.0D0) GO TO 300 KDFLG = 1 YR(I)=ZEROR YI(I)=ZEROI NZ=NZ+1 IF (I.EQ.1) GO TO 70 IF ((YR(I-1).EQ.ZEROR).AND.(YI(I-1).EQ.ZEROI)) GO TO 70 YR(I-1)=ZEROR YI(I-1)=ZEROI NZ=NZ+1 70 CONTINUE I = N 75 CONTINUE RAZR = 1.0D0/ZABS(CMPLX(ZRR,ZRI,kind=KIND(1.0D0))) STR = ZRR*RAZR STI = -ZRI*RAZR RZR = (STR+STR)*RAZR RZI = (STI+STI)*RAZR CKR = FN*RZR CKI = FN*RZI IB = I + 1 IF (N.LT.IB) GO TO 160 C----------------------------------------------------------------------- C TEST LAST MEMBER FOR UNDERFLOW AND OVERFLOW. SET SEQUENCE TO ZERO C ON UNDERFLOW. C----------------------------------------------------------------------- FN = FNU + DBLE(FLOAT(N-1)) IPARD = 1 IF (MR.NE.0) IPARD = 0 INITD = 0 CALL ZUNIK(ZRR, ZRI, FN, 2, IPARD, TOL, INITD, PHIDR, PHIDI, * ZET1DR, ZET1DI, ZET2DR, ZET2DI, SUMDR, SUMDI, CWRKR(1,3), * CWRKI(1,3)) IF (KODE.EQ.1) GO TO 80 STR = ZRR + ZET2DR STI = ZRI + ZET2DI RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = ZET1DR - STR S1I = ZET1DI - STI GO TO 90 80 CONTINUE S1R = ZET1DR - ZET2DR S1I = ZET1DI - ZET2DI 90 CONTINUE RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 95 IF (DABS(RS1).LT.ALIM) GO TO 100 C---------------------------------------------------------------------------- C REFINE ESTIMATE AND TEST C------------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIDR,PHIDI,kind=KIND(1.0D0))) RS1 = RS1+DLOG(APHI) IF (DABS(RS1).LT.ELIM) GO TO 100 95 CONTINUE IF (DABS(RS1).GT.0.0D0) GO TO 300 C----------------------------------------------------------------------- C FOR ZR.LT.0.0, THE I FUNCTION TO BE ADDED WILL OVERFLOW C----------------------------------------------------------------------- IF (ZR.LT.0.0D0) GO TO 300 NZ = N DO 96 I=1,N YR(I) = ZEROR YI(I) = ZEROI 96 CONTINUE RETURN C--------------------------------------------------------------------------- C FORWARD RECUR FOR REMAINDER OF THE SEQUENCE C---------------------------------------------------------------------------- 100 CONTINUE S1R = CYR(1) S1I = CYI(1) S2R = CYR(2) S2I = CYI(2) C1R = CSRR(KFLAG) ASCLE = BRY(KFLAG) DO 120 I=IB,N C2R = S2R C2I = S2I S2R = CKR*C2R - CKI*C2I + S1R S2I = CKR*C2I + CKI*C2R + S1I S1R = C2R S1I = C2I CKR = CKR + RZR CKI = CKI + RZI C2R = S2R*C1R C2I = S2I*C1R YR(I) = C2R YI(I) = C2I IF (KFLAG.GE.3) GO TO 120 STR = DABS(C2R) STI = DABS(C2I) C2M = DMAX1(STR,STI) IF (C2M.LE.ASCLE) GO TO 120 KFLAG = KFLAG + 1 ASCLE = BRY(KFLAG) S1R = S1R*C1R S1I = S1I*C1R S2R = C2R S2I = C2I S1R = S1R*CSSR(KFLAG) S1I = S1I*CSSR(KFLAG) S2R = S2R*CSSR(KFLAG) S2I = S2I*CSSR(KFLAG) C1R = CSRR(KFLAG) 120 CONTINUE 160 CONTINUE IF (MR.EQ.0) RETURN C----------------------------------------------------------------------- C ANALYTIC CONTINUATION FOR RE(Z).LT.0.0D0 C----------------------------------------------------------------------- NZ = 0 FMR = DBLE(FLOAT(MR)) SGN = -DSIGN(PI,FMR) C----------------------------------------------------------------------- C CSPN AND CSGN ARE COEFF OF K AND I FUNCTIONS RESP. C----------------------------------------------------------------------- CSGNI = SGN INU = INT(SNGL(FNU)) FNF = FNU - DBLE(FLOAT(INU)) IFN = INU + N - 1 ANG = FNF*SGN CSPNR = DCOS(ANG) CSPNI = DSIN(ANG) IF (MOD(IFN,2).EQ.0) GO TO 170 CSPNR = -CSPNR CSPNI = -CSPNI 170 CONTINUE ASC = BRY(1) IUF = 0 KK = N KDFLG = 1 IB = IB - 1 IC = IB - 1 DO 270 K=1,N FN = FNU + DBLE(FLOAT(KK-1)) C----------------------------------------------------------------------- C LOGIC TO SORT OUT CASES WHOSE PARAMETERS WERE SET FOR THE K C FUNCTION ABOVE C----------------------------------------------------------------------- M=3 IF (N.GT.2) GO TO 175 172 CONTINUE INITD = INIT(J) PHIDR = PHIR(J) PHIDI = PHII(J) ZET1DR = ZETA1R(J) ZET1DI = ZETA1I(J) ZET2DR = ZETA2R(J) ZET2DI = ZETA2I(J) SUMDR = SUMR(J) SUMDI = SUMI(J) M = J J = 3 - J GO TO 180 175 CONTINUE IF ((KK.EQ.N).AND.(IB.LT.N)) GO TO 180 IF ((KK.EQ.IB).OR.(KK.EQ.IC)) GO TO 172 INITD = 0 180 CONTINUE CALL ZUNIK(ZRR, ZRI, FN, 1, 0, TOL, INITD, PHIDR, PHIDI, * ZET1DR, ZET1DI, ZET2DR, ZET2DI, SUMDR, SUMDI, * CWRKR(1,M), CWRKI(1,M)) IF (KODE.EQ.1) GO TO 200 STR = ZRR + ZET2DR STI = ZRI + ZET2DI RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = -ZET1DR + STR S1I = -ZET1DI + STI GO TO 210 200 CONTINUE S1R = -ZET1DR + ZET2DR S1I = -ZET1DI + ZET2DI 210 CONTINUE C----------------------------------------------------------------------- C TEST FOR UNDERFLOW AND OVERFLOW C----------------------------------------------------------------------- RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 260 IF (KDFLG.EQ.1) IFLAG = 2 IF (DABS(RS1).LT.ALIM) GO TO 220 C----------------------------------------------------------------------- C REFINE TEST AND SCALE C----------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIDR,PHIDI,kind=KIND(1.0D0))) RS1 = RS1 + DLOG(APHI) IF (DABS(RS1).GT.ELIM) GO TO 260 IF (KDFLG.EQ.1) IFLAG = 1 IF (RS1.LT.0.0D0) GO TO 220 IF (KDFLG.EQ.1) IFLAG = 3 220 CONTINUE STR = PHIDR*SUMDR - PHIDI*SUMDI STI = PHIDR*SUMDI + PHIDI*SUMDR S2R = -CSGNI*STI S2I = CSGNI*STR STR = DEXP(S1R)*CSSR(IFLAG) S1R = STR*DCOS(S1I) S1I = STR*DSIN(S1I) STR = S2R*S1R - S2I*S1I S2I = S2R*S1I + S2I*S1R S2R = STR IF (IFLAG.NE.1) GO TO 230 CALL ZUCHK(S2R, S2I, NW, BRY(1), TOL) IF (NW.EQ.0) GO TO 230 S2R = ZEROR S2I = ZEROI 230 CONTINUE CYR(KDFLG) = S2R CYI(KDFLG) = S2I C2R = S2R C2I = S2I S2R = S2R*CSRR(IFLAG) S2I = S2I*CSRR(IFLAG) C----------------------------------------------------------------------- C ADD I AND K FUNCTIONS, K SEQUENCE IN Y(I), I=1,N C----------------------------------------------------------------------- S1R = YR(KK) S1I = YI(KK) IF (KODE.EQ.1) GO TO 250 CALL ZS1S2(ZRR, ZRI, S1R, S1I, S2R, S2I, NW, ASC, ALIM, IUF) NZ = NZ + NW 250 CONTINUE YR(KK) = S1R*CSPNR - S1I*CSPNI + S2R YI(KK) = CSPNR*S1I + CSPNI*S1R + S2I KK = KK - 1 CSPNR = -CSPNR CSPNI = -CSPNI IF (C2R.NE.0.0D0 .OR. C2I.NE.0.0D0) GO TO 255 KDFLG = 1 GO TO 270 255 CONTINUE IF (KDFLG.EQ.2) GO TO 275 KDFLG = 2 GO TO 270 260 CONTINUE IF (RS1.GT.0.0D0) GO TO 300 S2R = ZEROR S2I = ZEROI GO TO 230 270 CONTINUE K = N 275 CONTINUE IL = N - K IF (IL.EQ.0) RETURN C----------------------------------------------------------------------- C RECUR BACKWARD FOR REMAINDER OF I SEQUENCE AND ADD IN THE C K FUNCTIONS, SCALING THE I SEQUENCE DURING RECURRENCE TO KEEP C INTERMEDIATE ARITHMETIC ON SCALE NEAR EXPONENT EXTREMES. C----------------------------------------------------------------------- S1R = CYR(1) S1I = CYI(1) S2R = CYR(2) S2I = CYI(2) CSR = CSRR(IFLAG) ASCLE = BRY(IFLAG) FN = DBLE(FLOAT(INU+IL)) DO 290 I=1,IL C2R = S2R C2I = S2I S2R = S1R + (FN+FNF)*(RZR*C2R-RZI*C2I) S2I = S1I + (FN+FNF)*(RZR*C2I+RZI*C2R) S1R = C2R S1I = C2I FN = FN - 1.0D0 C2R = S2R*CSR C2I = S2I*CSR CKR = C2R CKI = C2I C1R = YR(KK) C1I = YI(KK) IF (KODE.EQ.1) GO TO 280 CALL ZS1S2(ZRR, ZRI, C1R, C1I, C2R, C2I, NW, ASC, ALIM, IUF) NZ = NZ + NW 280 CONTINUE YR(KK) = C1R*CSPNR - C1I*CSPNI + C2R YI(KK) = C1R*CSPNI + C1I*CSPNR + C2I KK = KK - 1 CSPNR = -CSPNR CSPNI = -CSPNI IF (IFLAG.GE.3) GO TO 290 C2R = DABS(CKR) C2I = DABS(CKI) C2M = DMAX1(C2R,C2I) IF (C2M.LE.ASCLE) GO TO 290 IFLAG = IFLAG + 1 ASCLE = BRY(IFLAG) S1R = S1R*CSR S1I = S1I*CSR S2R = CKR S2I = CKI S1R = S1R*CSSR(IFLAG) S1I = S1I*CSSR(IFLAG) S2R = S2R*CSSR(IFLAG) S2I = S2I*CSSR(IFLAG) CSR = CSRR(IFLAG) 290 CONTINUE RETURN 300 CONTINUE NZ = -1 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zunk2.f000066400000000000000000000420541450372207100247360ustar00rootroot00000000000000 SUBROUTINE ZUNK2(ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, TOL, ELIM, * ALIM) C***BEGIN PROLOGUE ZUNK2 C***REFER TO ZBESK C C ZUNK2 COMPUTES K(FNU,Z) AND ITS ANALYTIC CONTINUATION FROM THE C RIGHT HALF PLANE TO THE LEFT HALF PLANE BY MEANS OF THE C UNIFORM ASYMPTOTIC EXPANSIONS FOR H(KIND,FNU,ZN) AND J(FNU,ZN) C WHERE ZN IS IN THE RIGHT HALF PLANE, KIND=(3-MR)/2, MR=+1 OR C -1. HERE ZN=ZR*I OR -ZR*I WHERE ZR=Z IF Z IS IN THE RIGHT C HALF PLANE OR ZR=-Z IF Z IS IN THE LEFT HALF PLANE. MR INDIC- C ATES THE DIRECTION OF ROTATION FOR ANALYTIC CONTINUATION. C NZ=-1 MEANS AN OVERFLOW WILL OCCUR C C***ROUTINES CALLED ZAIRY,ZKSCL,ZS1S2,ZUCHK,ZUNHJ,D1MACH,ZABS C***END PROLOGUE ZUNK2 C COMPLEX AI,ARG,ARGD,ASUM,ASUMD,BSUM,BSUMD,CFN,CI,CIP,CK,CONE,CRSC, C *CR1,CR2,CS,CSCL,CSGN,CSPN,CSR,CSS,CY,CZERO,C1,C2,DAI,PHI,PHID,RZ, C *S1,S2,Y,Z,ZB,ZETA1,ZETA1D,ZETA2,ZETA2D,ZN,ZR DOUBLE PRECISION AARG, AIC, AII, AIR, ALIM, ANG, APHI, ARGDI, * ARGDR, ARGI, ARGR, ASC, ASCLE, ASUMDI, ASUMDR, ASUMI, ASUMR, * BRY, BSUMDI, BSUMDR, BSUMI, BSUMR, CAR, CIPI, CIPR, CKI, CKR, * CONER, CRSC, CR1I, CR1R, CR2I, CR2R, CSCL, CSGNI, CSI, * CSPNI, CSPNR, CSR, CSRR, CSSR, CYI, CYR, C1I, C1R, C2I, C2M, * C2R, DAII, DAIR, ELIM, FMR, FN, FNF, FNU, HPI, PHIDI, PHIDR, * PHII, PHIR, PI, PTI, PTR, RAST, RAZR, RS1, RZI, RZR, SAR, SGN, * STI, STR, S1I, S1R, S2I, S2R, TOL, YI, YR, YY, ZBI, ZBR, ZEROI, * ZEROR, ZETA1I, ZETA1R, ZETA2I, ZETA2R, ZET1DI, ZET1DR, ZET2DI, * ZET2DR, ZI, ZNI, ZNR, ZR, ZRI, ZRR, D1MACH, ZABS INTEGER I, IB, IFLAG, IFN, IL, IN, INU, IUF, K, KDFLG, KFLAG, KK, * KODE, MR, N, NAI, NDAI, NW, NZ, IDUM, J, IPARD, IC DIMENSION BRY(3), YR(N), YI(N), ASUMR(2), ASUMI(2), BSUMR(2), * BSUMI(2), PHIR(2), PHII(2), ARGR(2), ARGI(2), ZETA1R(2), * ZETA1I(2), ZETA2R(2), ZETA2I(2), CYR(2), CYI(2), CIPR(4), * CIPI(4), CSSR(3), CSRR(3) DATA ZEROR,ZEROI,CONER,CR1R,CR1I,CR2R,CR2I / 1 0.0D0, 0.0D0, 1.0D0, 1 1.0D0,1.73205080756887729D0 , -0.5D0,-8.66025403784438647D-01 / DATA HPI, PI, AIC / 1 1.57079632679489662D+00, 3.14159265358979324D+00, 1 1.26551212348464539D+00/ DATA CIPR(1),CIPI(1),CIPR(2),CIPI(2),CIPR(3),CIPI(3),CIPR(4), * CIPI(4) / 1 1.0D0,0.0D0 , 0.0D0,-1.0D0 , -1.0D0,0.0D0 , 0.0D0,1.0D0 / C KDFLG = 1 NZ = 0 C----------------------------------------------------------------------- C EXP(-ALIM)=EXP(-ELIM)/TOL=APPROX. ONE PRECISION GREATER THAN C THE UNDERFLOW LIMIT C----------------------------------------------------------------------- CSCL = 1.0D0/TOL CRSC = TOL CSSR(1) = CSCL CSSR(2) = CONER CSSR(3) = CRSC CSRR(1) = CRSC CSRR(2) = CONER CSRR(3) = CSCL BRY(1) = 1.0D+3*D1MACH(1)/TOL BRY(2) = 1.0D0/BRY(1) BRY(3) = D1MACH(2) ZRR = ZR ZRI = ZI IF (ZR.GE.0.0D0) GO TO 10 ZRR = -ZR ZRI = -ZI 10 CONTINUE YY = ZRI ZNR = ZRI ZNI = -ZRR ZBR = ZRR ZBI = ZRI INU = INT(SNGL(FNU)) FNF = FNU - DBLE(FLOAT(INU)) ANG = -HPI*FNF CAR = DCOS(ANG) SAR = DSIN(ANG) C2R = HPI*SAR C2I = -HPI*CAR KK = MOD(INU,4) + 1 STR = C2R*CIPR(KK) - C2I*CIPI(KK) STI = C2R*CIPI(KK) + C2I*CIPR(KK) CSR = CR1R*STR - CR1I*STI CSI = CR1R*STI + CR1I*STR IF (YY.GT.0.0D0) GO TO 20 ZNR = -ZNR ZBI = -ZBI 20 CONTINUE C----------------------------------------------------------------------- C K(FNU,Z) IS COMPUTED FROM H(2,FNU,-I*Z) WHERE Z IS IN THE FIRST C QUADRANT. FOURTH QUADRANT VALUES (YY.LE.0.0E0) ARE COMPUTED BY C CONJUGATION SINCE THE K FUNCTION IS REAL ON THE POSITIVE REAL AXIS C----------------------------------------------------------------------- J = 2 DO 80 I=1,N C----------------------------------------------------------------------- C J FLIP FLOPS BETWEEN 1 AND 2 IN J = 3 - J C----------------------------------------------------------------------- J = 3 - J FN = FNU + DBLE(FLOAT(I-1)) CALL ZUNHJ(ZNR, ZNI, FN, 0, TOL, PHIR(J), PHII(J), ARGR(J), * ARGI(J), ZETA1R(J), ZETA1I(J), ZETA2R(J), ZETA2I(J), ASUMR(J), * ASUMI(J), BSUMR(J), BSUMI(J)) IF (KODE.EQ.1) GO TO 30 STR = ZBR + ZETA2R(J) STI = ZBI + ZETA2I(J) RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = ZETA1R(J) - STR S1I = ZETA1I(J) - STI GO TO 40 30 CONTINUE S1R = ZETA1R(J) - ZETA2R(J) S1I = ZETA1I(J) - ZETA2I(J) 40 CONTINUE C----------------------------------------------------------------------- C TEST FOR UNDERFLOW AND OVERFLOW C----------------------------------------------------------------------- RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 70 IF (KDFLG.EQ.1) KFLAG = 2 IF (DABS(RS1).LT.ALIM) GO TO 50 C----------------------------------------------------------------------- C REFINE TEST AND SCALE C----------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIR(J),PHII(J),kind=KIND(1.0D0))) AARG = ZABS(CMPLX(ARGR(J),ARGI(J),kind=KIND(1.0D0))) RS1 = RS1 + DLOG(APHI) - 0.25D0*DLOG(AARG) - AIC IF (DABS(RS1).GT.ELIM) GO TO 70 IF (KDFLG.EQ.1) KFLAG = 1 IF (RS1.LT.0.0D0) GO TO 50 IF (KDFLG.EQ.1) KFLAG = 3 50 CONTINUE C----------------------------------------------------------------------- C SCALE S1 TO KEEP INTERMEDIATE ARITHMETIC ON SCALE NEAR C EXPONENT EXTREMES C----------------------------------------------------------------------- C2R = ARGR(J)*CR2R - ARGI(J)*CR2I C2I = ARGR(J)*CR2I + ARGI(J)*CR2R CALL ZAIRY(C2R, C2I, 0, 2, AIR, AII, NAI, IDUM) CALL ZAIRY(C2R, C2I, 1, 2, DAIR, DAII, NDAI, IDUM) STR = DAIR*BSUMR(J) - DAII*BSUMI(J) STI = DAIR*BSUMI(J) + DAII*BSUMR(J) PTR = STR*CR2R - STI*CR2I PTI = STR*CR2I + STI*CR2R STR = PTR + (AIR*ASUMR(J)-AII*ASUMI(J)) STI = PTI + (AIR*ASUMI(J)+AII*ASUMR(J)) PTR = STR*PHIR(J) - STI*PHII(J) PTI = STR*PHII(J) + STI*PHIR(J) S2R = PTR*CSR - PTI*CSI S2I = PTR*CSI + PTI*CSR STR = DEXP(S1R)*CSSR(KFLAG) S1R = STR*DCOS(S1I) S1I = STR*DSIN(S1I) STR = S2R*S1R - S2I*S1I S2I = S1R*S2I + S2R*S1I S2R = STR IF (KFLAG.NE.1) GO TO 60 CALL ZUCHK(S2R, S2I, NW, BRY(1), TOL) IF (NW.NE.0) GO TO 70 60 CONTINUE IF (YY.LE.0.0D0) S2I = -S2I CYR(KDFLG) = S2R CYI(KDFLG) = S2I YR(I) = S2R*CSRR(KFLAG) YI(I) = S2I*CSRR(KFLAG) STR = CSI CSI = -CSR CSR = STR IF (KDFLG.EQ.2) GO TO 85 KDFLG = 2 GO TO 80 70 CONTINUE IF (RS1.GT.0.0D0) GO TO 320 C----------------------------------------------------------------------- C FOR ZR.LT.0.0, THE I FUNCTION TO BE ADDED WILL OVERFLOW C----------------------------------------------------------------------- IF (ZR.LT.0.0D0) GO TO 320 KDFLG = 1 YR(I)=ZEROR YI(I)=ZEROI NZ=NZ+1 STR = CSI CSI =-CSR CSR = STR IF (I.EQ.1) GO TO 80 IF ((YR(I-1).EQ.ZEROR).AND.(YI(I-1).EQ.ZEROI)) GO TO 80 YR(I-1)=ZEROR YI(I-1)=ZEROI NZ=NZ+1 80 CONTINUE I = N 85 CONTINUE RAZR = 1.0D0/ZABS(CMPLX(ZRR,ZRI,kind=KIND(1.0D0))) STR = ZRR*RAZR STI = -ZRI*RAZR RZR = (STR+STR)*RAZR RZI = (STI+STI)*RAZR CKR = FN*RZR CKI = FN*RZI IB = I + 1 IF (N.LT.IB) GO TO 180 C----------------------------------------------------------------------- C TEST LAST MEMBER FOR UNDERFLOW AND OVERFLOW. SET SEQUENCE TO ZERO C ON UNDERFLOW. C----------------------------------------------------------------------- FN = FNU + DBLE(FLOAT(N-1)) IPARD = 1 IF (MR.NE.0) IPARD = 0 CALL ZUNHJ(ZNR, ZNI, FN, IPARD, TOL, PHIDR, PHIDI, ARGDR, ARGDI, * ZET1DR, ZET1DI, ZET2DR, ZET2DI, ASUMDR, ASUMDI, BSUMDR, BSUMDI) IF (KODE.EQ.1) GO TO 90 STR = ZBR + ZET2DR STI = ZBI + ZET2DI RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = ZET1DR - STR S1I = ZET1DI - STI GO TO 100 90 CONTINUE S1R = ZET1DR - ZET2DR S1I = ZET1DI - ZET2DI 100 CONTINUE RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 105 IF (DABS(RS1).LT.ALIM) GO TO 120 C---------------------------------------------------------------------------- C REFINE ESTIMATE AND TEST C------------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIDR,PHIDI,kind=KIND(1.0D0))) RS1 = RS1+DLOG(APHI) IF (DABS(RS1).LT.ELIM) GO TO 120 105 CONTINUE IF (RS1.GT.0.0D0) GO TO 320 C----------------------------------------------------------------------- C FOR ZR.LT.0.0, THE I FUNCTION TO BE ADDED WILL OVERFLOW C----------------------------------------------------------------------- IF (ZR.LT.0.0D0) GO TO 320 NZ = N DO 106 I=1,N YR(I) = ZEROR YI(I) = ZEROI 106 CONTINUE RETURN 120 CONTINUE S1R = CYR(1) S1I = CYI(1) S2R = CYR(2) S2I = CYI(2) C1R = CSRR(KFLAG) ASCLE = BRY(KFLAG) DO 130 I=IB,N C2R = S2R C2I = S2I S2R = CKR*C2R - CKI*C2I + S1R S2I = CKR*C2I + CKI*C2R + S1I S1R = C2R S1I = C2I CKR = CKR + RZR CKI = CKI + RZI C2R = S2R*C1R C2I = S2I*C1R YR(I) = C2R YI(I) = C2I IF (KFLAG.GE.3) GO TO 130 STR = DABS(C2R) STI = DABS(C2I) C2M = DMAX1(STR,STI) IF (C2M.LE.ASCLE) GO TO 130 KFLAG = KFLAG + 1 ASCLE = BRY(KFLAG) S1R = S1R*C1R S1I = S1I*C1R S2R = C2R S2I = C2I S1R = S1R*CSSR(KFLAG) S1I = S1I*CSSR(KFLAG) S2R = S2R*CSSR(KFLAG) S2I = S2I*CSSR(KFLAG) C1R = CSRR(KFLAG) 130 CONTINUE 180 CONTINUE IF (MR.EQ.0) RETURN C----------------------------------------------------------------------- C ANALYTIC CONTINUATION FOR RE(Z).LT.0.0D0 C----------------------------------------------------------------------- NZ = 0 FMR = DBLE(FLOAT(MR)) SGN = -DSIGN(PI,FMR) C----------------------------------------------------------------------- C CSPN AND CSGN ARE COEFF OF K AND I FUNCIONS RESP. C----------------------------------------------------------------------- CSGNI = SGN IF (YY.LE.0.0D0) CSGNI = -CSGNI IFN = INU + N - 1 ANG = FNF*SGN CSPNR = DCOS(ANG) CSPNI = DSIN(ANG) IF (MOD(IFN,2).EQ.0) GO TO 190 CSPNR = -CSPNR CSPNI = -CSPNI 190 CONTINUE C----------------------------------------------------------------------- C CS=COEFF OF THE J FUNCTION TO GET THE I FUNCTION. I(FNU,Z) IS C COMPUTED FROM EXP(I*FNU*HPI)*J(FNU,-I*Z) WHERE Z IS IN THE FIRST C QUADRANT. FOURTH QUADRANT VALUES (YY.LE.0.0E0) ARE COMPUTED BY C CONJUGATION SINCE THE I FUNCTION IS REAL ON THE POSITIVE REAL AXIS C----------------------------------------------------------------------- CSR = SAR*CSGNI CSI = CAR*CSGNI IN = MOD(IFN,4) + 1 C2R = CIPR(IN) C2I = CIPI(IN) STR = CSR*C2R + CSI*C2I CSI = -CSR*C2I + CSI*C2R CSR = STR ASC = BRY(1) IUF = 0 KK = N KDFLG = 1 IB = IB - 1 IC = IB - 1 DO 290 K=1,N FN = FNU + DBLE(FLOAT(KK-1)) C----------------------------------------------------------------------- C LOGIC TO SORT OUT CASES WHOSE PARAMETERS WERE SET FOR THE K C FUNCTION ABOVE C----------------------------------------------------------------------- IF (N.GT.2) GO TO 175 172 CONTINUE PHIDR = PHIR(J) PHIDI = PHII(J) ARGDR = ARGR(J) ARGDI = ARGI(J) ZET1DR = ZETA1R(J) ZET1DI = ZETA1I(J) ZET2DR = ZETA2R(J) ZET2DI = ZETA2I(J) ASUMDR = ASUMR(J) ASUMDI = ASUMI(J) BSUMDR = BSUMR(J) BSUMDI = BSUMI(J) J = 3 - J GO TO 210 175 CONTINUE IF ((KK.EQ.N).AND.(IB.LT.N)) GO TO 210 IF ((KK.EQ.IB).OR.(KK.EQ.IC)) GO TO 172 CALL ZUNHJ(ZNR, ZNI, FN, 0, TOL, PHIDR, PHIDI, ARGDR, * ARGDI, ZET1DR, ZET1DI, ZET2DR, ZET2DI, ASUMDR, * ASUMDI, BSUMDR, BSUMDI) 210 CONTINUE IF (KODE.EQ.1) GO TO 220 STR = ZBR + ZET2DR STI = ZBI + ZET2DI RAST = FN/ZABS(CMPLX(STR,STI,kind=KIND(1.0D0))) STR = STR*RAST*RAST STI = -STI*RAST*RAST S1R = -ZET1DR + STR S1I = -ZET1DI + STI GO TO 230 220 CONTINUE S1R = -ZET1DR + ZET2DR S1I = -ZET1DI + ZET2DI 230 CONTINUE C----------------------------------------------------------------------- C TEST FOR UNDERFLOW AND OVERFLOW C----------------------------------------------------------------------- RS1 = S1R IF (DABS(RS1).GT.ELIM) GO TO 280 IF (KDFLG.EQ.1) IFLAG = 2 IF (DABS(RS1).LT.ALIM) GO TO 240 C----------------------------------------------------------------------- C REFINE TEST AND SCALE C----------------------------------------------------------------------- APHI = ZABS(CMPLX(PHIDR,PHIDI,kind=KIND(1.0D0))) AARG = ZABS(CMPLX(ARGDR,ARGDI,kind=KIND(1.0D0))) RS1 = RS1 + DLOG(APHI) - 0.25D0*DLOG(AARG) - AIC IF (DABS(RS1).GT.ELIM) GO TO 280 IF (KDFLG.EQ.1) IFLAG = 1 IF (RS1.LT.0.0D0) GO TO 240 IF (KDFLG.EQ.1) IFLAG = 3 240 CONTINUE CALL ZAIRY(ARGDR, ARGDI, 0, 2, AIR, AII, NAI, IDUM) CALL ZAIRY(ARGDR, ARGDI, 1, 2, DAIR, DAII, NDAI, IDUM) STR = DAIR*BSUMDR - DAII*BSUMDI STI = DAIR*BSUMDI + DAII*BSUMDR STR = STR + (AIR*ASUMDR-AII*ASUMDI) STI = STI + (AIR*ASUMDI+AII*ASUMDR) PTR = STR*PHIDR - STI*PHIDI PTI = STR*PHIDI + STI*PHIDR S2R = PTR*CSR - PTI*CSI S2I = PTR*CSI + PTI*CSR STR = DEXP(S1R)*CSSR(IFLAG) S1R = STR*DCOS(S1I) S1I = STR*DSIN(S1I) STR = S2R*S1R - S2I*S1I S2I = S2R*S1I + S2I*S1R S2R = STR IF (IFLAG.NE.1) GO TO 250 CALL ZUCHK(S2R, S2I, NW, BRY(1), TOL) IF (NW.EQ.0) GO TO 250 S2R = ZEROR S2I = ZEROI 250 CONTINUE IF (YY.LE.0.0D0) S2I = -S2I CYR(KDFLG) = S2R CYI(KDFLG) = S2I C2R = S2R C2I = S2I S2R = S2R*CSRR(IFLAG) S2I = S2I*CSRR(IFLAG) C----------------------------------------------------------------------- C ADD I AND K FUNCTIONS, K SEQUENCE IN Y(I), I=1,N C----------------------------------------------------------------------- S1R = YR(KK) S1I = YI(KK) IF (KODE.EQ.1) GO TO 270 CALL ZS1S2(ZRR, ZRI, S1R, S1I, S2R, S2I, NW, ASC, ALIM, IUF) NZ = NZ + NW 270 CONTINUE YR(KK) = S1R*CSPNR - S1I*CSPNI + S2R YI(KK) = S1R*CSPNI + S1I*CSPNR + S2I KK = KK - 1 CSPNR = -CSPNR CSPNI = -CSPNI STR = CSI CSI = -CSR CSR = STR IF (C2R.NE.0.0D0 .OR. C2I.NE.0.0D0) GO TO 255 KDFLG = 1 GO TO 290 255 CONTINUE IF (KDFLG.EQ.2) GO TO 295 KDFLG = 2 GO TO 290 280 CONTINUE IF (RS1.GT.0.0D0) GO TO 320 S2R = ZEROR S2I = ZEROI GO TO 250 290 CONTINUE K = N 295 CONTINUE IL = N - K IF (IL.EQ.0) RETURN C----------------------------------------------------------------------- C RECUR BACKWARD FOR REMAINDER OF I SEQUENCE AND ADD IN THE C K FUNCTIONS, SCALING THE I SEQUENCE DURING RECURRENCE TO KEEP C INTERMEDIATE ARITHMETIC ON SCALE NEAR EXPONENT EXTREMES. C----------------------------------------------------------------------- S1R = CYR(1) S1I = CYI(1) S2R = CYR(2) S2I = CYI(2) CSR = CSRR(IFLAG) ASCLE = BRY(IFLAG) FN = DBLE(FLOAT(INU+IL)) DO 310 I=1,IL C2R = S2R C2I = S2I S2R = S1R + (FN+FNF)*(RZR*C2R-RZI*C2I) S2I = S1I + (FN+FNF)*(RZR*C2I+RZI*C2R) S1R = C2R S1I = C2I FN = FN - 1.0D0 C2R = S2R*CSR C2I = S2I*CSR CKR = C2R CKI = C2I C1R = YR(KK) C1I = YI(KK) IF (KODE.EQ.1) GO TO 300 CALL ZS1S2(ZRR, ZRI, C1R, C1I, C2R, C2I, NW, ASC, ALIM, IUF) NZ = NZ + NW 300 CONTINUE YR(KK) = C1R*CSPNR - C1I*CSPNI + C2R YI(KK) = C1R*CSPNI + C1I*CSPNR + C2I KK = KK - 1 CSPNR = -CSPNR CSPNI = -CSPNI IF (IFLAG.GE.3) GO TO 310 C2R = DABS(CKR) C2I = DABS(CKI) C2M = DMAX1(C2R,C2I) IF (C2M.LE.ASCLE) GO TO 310 IFLAG = IFLAG + 1 ASCLE = BRY(IFLAG) S1R = S1R*CSR S1I = S1I*CSR S2R = CKR S2I = CKI S1R = S1R*CSSR(IFLAG) S1I = S1I*CSSR(IFLAG) S2R = S2R*CSSR(IFLAG) S2I = S2I*CSSR(IFLAG) CSR = CSRR(IFLAG) 310 CONTINUE RETURN 320 CONTINUE NZ = -1 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zuoik.f000066400000000000000000000147551450372207100250350ustar00rootroot00000000000000 SUBROUTINE ZUOIK(ZR, ZI, FNU, KODE, IKFLG, N, YR, YI, NUF, TOL, * ELIM, ALIM) C***BEGIN PROLOGUE ZUOIK C***REFER TO ZBESI,ZBESK,ZBESH C C ZUOIK COMPUTES THE LEADING TERMS OF THE UNIFORM ASYMPTOTIC C EXPANSIONS FOR THE I AND K FUNCTIONS AND COMPARES THEM C (IN LOGARITHMIC FORM) TO ALIM AND ELIM FOR OVER AND UNDERFLOW C WHERE ALIM.LT.ELIM. IF THE MAGNITUDE, BASED ON THE LEADING C EXPONENTIAL, IS LESS THAN ALIM OR GREATER THAN -ALIM, THEN C THE RESULT IS ON SCALE. IF NOT, THEN A REFINED TEST USING OTHER C MULTIPLIERS (IN LOGARITHMIC FORM) IS MADE BASED ON ELIM. HERE C EXP(-ELIM)=SMALLEST MACHINE NUMBER*1.0E+3 AND EXP(-ALIM)= C EXP(-ELIM)/TOL C C IKFLG=1 MEANS THE I SEQUENCE IS TESTED C =2 MEANS THE K SEQUENCE IS TESTED C NUF = 0 MEANS THE LAST MEMBER OF THE SEQUENCE IS ON SCALE C =-1 MEANS AN OVERFLOW WOULD OCCUR C IKFLG=1 AND NUF.GT.0 MEANS THE LAST NUF Y VALUES WERE SET TO ZERO C THE FIRST N-NUF VALUES MUST BE SET BY ANOTHER ROUTINE C IKFLG=2 AND NUF.EQ.N MEANS ALL Y VALUES WERE SET TO ZERO C IKFLG=2 AND 0.LT.NUF.LT.N NOT CONSIDERED. Y MUST BE SET BY C ANOTHER ROUTINE C C***ROUTINES CALLED ZUCHK,ZUNHJ,ZUNIK,D1MACH,ZABS,ZLOG C***END PROLOGUE ZUOIK C COMPLEX ARG,ASUM,BSUM,CWRK,CZ,CZERO,PHI,SUM,Y,Z,ZB,ZETA1,ZETA2,ZN, C *ZR DOUBLE PRECISION AARG, AIC, ALIM, APHI, ARGI, ARGR, ASUMI, ASUMR, * ASCLE, AX, AY, BSUMI, BSUMR, CWRKI, CWRKR, CZI, CZR, ELIM, FNN, * FNU, GNN, GNU, PHII, PHIR, RCZ, STR, STI, SUMI, SUMR, TOL, YI, * YR, ZBI, ZBR, ZEROI, ZEROR, ZETA1I, ZETA1R, ZETA2I, ZETA2R, ZI, * ZNI, ZNR, ZR, ZRI, ZRR, D1MACH, ZABS INTEGER I, IDUM, IFORM, IKFLG, INIT, KODE, N, NN, NUF, NW DIMENSION YR(N), YI(N), CWRKR(16), CWRKI(16) DATA ZEROR,ZEROI / 0.0D0, 0.0D0 / DATA AIC / 1.265512123484645396D+00 / NUF = 0 NN = N ZRR = ZR ZRI = ZI IF (ZR.GE.0.0D0) GO TO 10 ZRR = -ZR ZRI = -ZI 10 CONTINUE ZBR = ZRR ZBI = ZRI AX = DABS(ZR)*1.7321D0 AY = DABS(ZI) IFORM = 1 IF (AY.GT.AX) IFORM = 2 GNU = DMAX1(FNU,1.0D0) IF (IKFLG.EQ.1) GO TO 20 FNN = DBLE(FLOAT(NN)) GNN = FNU + FNN - 1.0D0 GNU = DMAX1(GNN,FNN) 20 CONTINUE C----------------------------------------------------------------------- C ONLY THE MAGNITUDE OF ARG AND PHI ARE NEEDED ALONG WITH THE C REAL PARTS OF ZETA1, ZETA2 AND ZB. NO ATTEMPT IS MADE TO GET C THE SIGN OF THE IMAGINARY PART CORRECT. C----------------------------------------------------------------------- IF (IFORM.EQ.2) GO TO 30 INIT = 0 CALL ZUNIK(ZRR, ZRI, GNU, IKFLG, 1, TOL, INIT, PHIR, PHII, * ZETA1R, ZETA1I, ZETA2R, ZETA2I, SUMR, SUMI, CWRKR, CWRKI) CZR = -ZETA1R + ZETA2R CZI = -ZETA1I + ZETA2I GO TO 50 30 CONTINUE ZNR = ZRI ZNI = -ZRR IF (ZI.GT.0.0D0) GO TO 40 ZNR = -ZNR 40 CONTINUE CALL ZUNHJ(ZNR, ZNI, GNU, 1, TOL, PHIR, PHII, ARGR, ARGI, ZETA1R, * ZETA1I, ZETA2R, ZETA2I, ASUMR, ASUMI, BSUMR, BSUMI) CZR = -ZETA1R + ZETA2R CZI = -ZETA1I + ZETA2I AARG = ZABS(CMPLX(ARGR,ARGI,kind=KIND(1.0D0))) 50 CONTINUE IF (KODE.EQ.1) GO TO 60 CZR = CZR - ZBR CZI = CZI - ZBI 60 CONTINUE IF (IKFLG.EQ.1) GO TO 70 CZR = -CZR CZI = -CZI 70 CONTINUE APHI = ZABS(CMPLX(PHIR,PHII,kind=KIND(1.0D0))) RCZ = CZR C----------------------------------------------------------------------- C OVERFLOW TEST C----------------------------------------------------------------------- IF (RCZ.GT.ELIM) GO TO 210 IF (RCZ.LT.ALIM) GO TO 80 RCZ = RCZ + DLOG(APHI) IF (IFORM.EQ.2) RCZ = RCZ - 0.25D0*DLOG(AARG) - AIC IF (RCZ.GT.ELIM) GO TO 210 GO TO 130 80 CONTINUE C----------------------------------------------------------------------- C UNDERFLOW TEST C----------------------------------------------------------------------- IF (RCZ.LT.(-ELIM)) GO TO 90 IF (RCZ.GT.(-ALIM)) GO TO 130 RCZ = RCZ + DLOG(APHI) IF (IFORM.EQ.2) RCZ = RCZ - 0.25D0*DLOG(AARG) - AIC IF (RCZ.GT.(-ELIM)) GO TO 110 90 CONTINUE DO 100 I=1,NN YR(I) = ZEROR YI(I) = ZEROI 100 CONTINUE NUF = NN RETURN 110 CONTINUE ASCLE = 1.0D+3*D1MACH(1)/TOL CALL ZLOG(PHIR, PHII, STR, STI, IDUM) CZR = CZR + STR CZI = CZI + STI IF (IFORM.EQ.1) GO TO 120 CALL ZLOG(ARGR, ARGI, STR, STI, IDUM) CZR = CZR - 0.25D0*STR - AIC CZI = CZI - 0.25D0*STI 120 CONTINUE AX = DEXP(RCZ)/TOL AY = CZI CZR = AX*DCOS(AY) CZI = AX*DSIN(AY) CALL ZUCHK(CZR, CZI, NW, ASCLE, TOL) IF (NW.NE.0) GO TO 90 130 CONTINUE IF (IKFLG.EQ.2) RETURN IF (N.EQ.1) RETURN C----------------------------------------------------------------------- C SET UNDERFLOWS ON I SEQUENCE C----------------------------------------------------------------------- 140 CONTINUE GNU = FNU + DBLE(FLOAT(NN-1)) IF (IFORM.EQ.2) GO TO 150 INIT = 0 CALL ZUNIK(ZRR, ZRI, GNU, IKFLG, 1, TOL, INIT, PHIR, PHII, * ZETA1R, ZETA1I, ZETA2R, ZETA2I, SUMR, SUMI, CWRKR, CWRKI) CZR = -ZETA1R + ZETA2R CZI = -ZETA1I + ZETA2I GO TO 160 150 CONTINUE CALL ZUNHJ(ZNR, ZNI, GNU, 1, TOL, PHIR, PHII, ARGR, ARGI, ZETA1R, * ZETA1I, ZETA2R, ZETA2I, ASUMR, ASUMI, BSUMR, BSUMI) CZR = -ZETA1R + ZETA2R CZI = -ZETA1I + ZETA2I AARG = ZABS(CMPLX(ARGR,ARGI,kind=KIND(1.0D0))) 160 CONTINUE IF (KODE.EQ.1) GO TO 170 CZR = CZR - ZBR CZI = CZI - ZBI 170 CONTINUE APHI = ZABS(CMPLX(PHIR,PHII,kind=KIND(1.0D0))) RCZ = CZR IF (RCZ.LT.(-ELIM)) GO TO 180 IF (RCZ.GT.(-ALIM)) RETURN RCZ = RCZ + DLOG(APHI) IF (IFORM.EQ.2) RCZ = RCZ - 0.25D0*DLOG(AARG) - AIC IF (RCZ.GT.(-ELIM)) GO TO 190 180 CONTINUE YR(NN) = ZEROR YI(NN) = ZEROI NN = NN - 1 NUF = NUF + 1 IF (NN.EQ.0) RETURN GO TO 140 190 CONTINUE ASCLE = 1.0D+3*D1MACH(1)/TOL CALL ZLOG(PHIR, PHII, STR, STI, IDUM) CZR = CZR + STR CZI = CZI + STI IF (IFORM.EQ.1) GO TO 200 CALL ZLOG(ARGR, ARGI, STR, STI, IDUM) CZR = CZR - 0.25D0*STR - AIC CZI = CZI - 0.25D0*STI 200 CONTINUE AX = DEXP(RCZ)/TOL AY = CZI CZR = AX*DCOS(AY) CZI = AX*DSIN(AY) CALL ZUCHK(CZR, CZI, NW, ASCLE, TOL) IF (NW.NE.0) GO TO 180 RETURN 210 CONTINUE NUF = -1 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/amoslib/zwrsk.f000066400000000000000000000064551450372207100250520ustar00rootroot00000000000000 SUBROUTINE ZWRSK(ZRR, ZRI, FNU, KODE, N, YR, YI, NZ, CWR, CWI, * TOL, ELIM, ALIM) C***BEGIN PROLOGUE ZWRSK C***REFER TO ZBESI,ZBESK C C ZWRSK COMPUTES THE I BESSEL FUNCTION FOR RE(Z).GE.0.0 BY C NORMALIZING THE I FUNCTION RATIOS FROM ZRATI BY THE WRONSKIAN C C***ROUTINES CALLED D1MACH,ZBKNU,ZRATI,ZABS C***END PROLOGUE ZWRSK C COMPLEX CINU,CSCL,CT,CW,C1,C2,RCT,ST,Y,ZR DOUBLE PRECISION ACT, ACW, ALIM, ASCLE, CINUI, CINUR, CSCLR, CTI, * CTR, CWI, CWR, C1I, C1R, C2I, C2R, ELIM, FNU, PTI, PTR, RACT, * STI, STR, TOL, YI, YR, ZRI, ZRR, ZABS, D1MACH INTEGER I, KODE, N, NW, NZ DIMENSION YR(N), YI(N), CWR(2), CWI(2) C----------------------------------------------------------------------- C I(FNU+I-1,Z) BY BACKWARD RECURRENCE FOR RATIOS C Y(I)=I(FNU+I,Z)/I(FNU+I-1,Z) FROM CRATI NORMALIZED BY THE C WRONSKIAN WITH K(FNU,Z) AND K(FNU+1,Z) FROM CBKNU. C----------------------------------------------------------------------- NZ = 0 CALL ZBKNU(ZRR, ZRI, FNU, KODE, 2, CWR, CWI, NW, TOL, ELIM, ALIM) IF (NW.NE.0) GO TO 50 CALL ZRATI(ZRR, ZRI, FNU, N, YR, YI, TOL) C----------------------------------------------------------------------- C RECUR FORWARD ON I(FNU+1,Z) = R(FNU,Z)*I(FNU,Z), C R(FNU+J-1,Z)=Y(J), J=1,...,N C----------------------------------------------------------------------- CINUR = 1.0D0 CINUI = 0.0D0 IF (KODE.EQ.1) GO TO 10 CINUR = DCOS(ZRI) CINUI = DSIN(ZRI) 10 CONTINUE C----------------------------------------------------------------------- C ON LOW EXPONENT MACHINES THE K FUNCTIONS CAN BE CLOSE TO BOTH C THE UNDER AND OVERFLOW LIMITS AND THE NORMALIZATION MUST BE C SCALED TO PREVENT OVER OR UNDERFLOW. CUOIK HAS DETERMINED THAT C THE RESULT IS ON SCALE. C----------------------------------------------------------------------- ACW = ZABS(CMPLX(CWR(2),CWI(2),kind=KIND(1.0D0))) ASCLE = 1.0D+3*D1MACH(1)/TOL CSCLR = 1.0D0 IF (ACW.GT.ASCLE) GO TO 20 CSCLR = 1.0D0/TOL GO TO 30 20 CONTINUE ASCLE = 1.0D0/ASCLE IF (ACW.LT.ASCLE) GO TO 30 CSCLR = TOL 30 CONTINUE C1R = CWR(1)*CSCLR C1I = CWI(1)*CSCLR C2R = CWR(2)*CSCLR C2I = CWI(2)*CSCLR STR = YR(1) STI = YI(1) C----------------------------------------------------------------------- C CINU=CINU*(CONJG(CT)/CABS(CT))*(1.0D0/CABS(CT) PREVENTS C UNDER- OR OVERFLOW PREMATURELY BY SQUARING CABS(CT) C----------------------------------------------------------------------- PTR = STR*C1R - STI*C1I PTI = STR*C1I + STI*C1R PTR = PTR + C2R PTI = PTI + C2I CTR = ZRR*PTR - ZRI*PTI CTI = ZRR*PTI + ZRI*PTR ACT = ZABS(CMPLX(CTR,CTI,kind=KIND(1.0D0))) RACT = 1.0D0/ACT CTR = CTR*RACT CTI = -CTI*RACT PTR = CINUR*RACT PTI = CINUI*RACT CINUR = PTR*CTR - PTI*CTI CINUI = PTR*CTI + PTI*CTR YR(1) = CINUR*CSCLR YI(1) = CINUI*CSCLR IF (N.EQ.1) RETURN DO 40 I=2,N PTR = STR*CINUR - STI*CINUI CINUI = STR*CINUI + STI*CINUR CINUR = PTR STR = YR(I) STI = YI(I) YR(I) = CINUR*CSCLR YI(I) = CINUI*CSCLR 40 CONTINUE RETURN 50 CONTINUE NZ = -1 IF(NW.EQ.(-2)) NZ=-2 RETURN END golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/doc.go000066400000000000000000000004721450372207100231620ustar00rootroot00000000000000// 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 amos implements functions originally in the Netlib code by Donald Amos. package amos // import "gonum.org/v1/gonum/mathext/internal/amos" golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/origcode_test.go000066400000000000000000001457311450372207100252570ustar00rootroot00000000000000// Copyright ©2016 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 amos import ( "math" "math/cmplx" ) // These routines are the versions directly modified from the Fortran code. // They are used to ensure that code style improvements do not change the // code output. func iabs(a int) int { if a >= 0 { return a } return -a } func min0(a, b int) int { if a < b { return a } return b } func max0(a, b int) int { if a > b { return a } return b } func zairyOrig(ZR, ZI float64, ID, KODE int) (AIR, AII float64, NZ, IERR int) { // zairy is adapted from the original Netlib code by Donald Amos. // http://www.netlib.no/netlib/amos/zairy.f // Original comment: /* C***BEGIN PROLOGUE ZAIRY C***DATE WRITTEN 830501 (YYMMDD) C***REVISION DATE 890801 (YYMMDD) C***CATEGORY NO. B5K C***KEYWORDS AIRY FUNCTION,BESSEL FUNCTIONS OF ORDER ONE THIRD C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES C***PURPOSE TO COMPUTE AIRY FUNCTIONS AI(Z) AND DAI(Z) FOR COMPLEX Z C***DESCRIPTION C C ***A DOUBLE PRECISION ROUTINE*** C ON KODE=1, ZAIRY COMPUTES THE COMPLEX AIRY FUNCTION AI(Z) OR C ITS DERIVATIVE DAI(Z)/DZ ON ID=0 OR ID=1 RESPECTIVELY. ON C KODE=2, A SCALING OPTION CEXP(ZTA)*AI(Z) OR CEXP(ZTA)* C DAI(Z)/DZ IS PROVIDED TO REMOVE THE EXPONENTIAL DECAY IN C -PI/31.0 FROM THE K BESSEL C FUNCTIONS BY C C AI(Z)=C*SQRT(Z)*K(1/3,ZTA) , DAI(Z)=-C*Z*K(2/3,ZTA) C C=1.0/(PI*SQRT(3.0)) C ZTA=(2/3)*Z**(3/2) C C WITH THE POWER SERIES FOR CABS(Z)<=1.0. C C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z IS LARGE, LOSSES C OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. CONSEQUENTLY, IF C THE MAGNITUDE OF ZETA=(2/3)*Z**1.5 EXCEEDS U1=SQRT(0.5/UR), C THEN LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR C FLAG IERR=3 IS TRIGGERED WHERE UR=dmax(dmach[4),1.0D-18) IS C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. C ALSO, if THE MAGNITUDE OF ZETA IS LARGER THAN U2=0.5/UR, THEN C ALL SIGNIFICANCE IS LOST AND IERR=4. IN ORDER TO USE THE INT C FUNCTION, ZETA MUST BE FURTHER RESTRICTED NOT TO EXCEED THE C LARGEST INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF ZETA C MUST BE RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, C AND U3 ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE C PRECISION ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE C PRECISION ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMIT- C ING IN THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT THE MAG- C NITUDE OF Z CANNOT EXCEED 3.1E+4 IN SINGLE AND 2.1E+6 IN C DOUBLE PRECISION ARITHMETIC. THIS ALSO MEANS THAT ONE CAN C EXPECT TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, C NO DIGITS IN SINGLE PRECISION AND ONLY 7 DIGITS IN DOUBLE C PRECISION ARITHMETIC. SIMILAR CONSIDERATIONS HOLD FOR OTHER C MACHINES. C C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY C SEVERAL ORDERS OF MAGNITUDE. if ONE COMPONENT IS 10**K LARGER C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, C OR -PI/2+P. C C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF C COMMERCE, 1955. C C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 C C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- C 1018, MAY, 1985 C C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. C MATH. SOFTWARE, 1986 */ var AI, CONE, CSQ, CY, S1, S2, TRM1, TRM2, Z, ZTA, Z3 complex128 var AA, AD, AK, ALIM, ATRM, AZ, AZ3, BK, CC, CK, COEF, CONEI, CONER, CSQI, CSQR, C1, C2, DIG, DK, D1, D2, ELIM, FID, FNU, PTR, RL, R1M5, SFAC, STI, STR, S1I, S1R, S2I, S2R, TOL, TRM1I, TRM1R, TRM2I, TRM2R, TTH, ZEROI, ZEROR, ZTAI, ZTAR, Z3I, Z3R, ALAZ, BB float64 var IFLAG, K, K1, K2, MR, NN int var tmp complex128 // Extra element for padding. CYR := []float64{math.NaN(), 0} CYI := []float64{math.NaN(), 0} _ = AI _ = CONE _ = CSQ _ = CY _ = S1 _ = S2 _ = TRM1 _ = TRM2 _ = Z _ = ZTA _ = Z3 TTH = 6.66666666666666667e-01 C1 = 3.55028053887817240e-01 C2 = 2.58819403792806799e-01 COEF = 1.83776298473930683e-01 ZEROR = 0 ZEROI = 0 CONER = 1 CONEI = 0 NZ = 0 if ID < 0 || ID > 1 { IERR = 1 } if KODE < 1 || KODE > 2 { IERR = 1 } if IERR != 0 { return } AZ = zabs(complex(ZR, ZI)) TOL = dmax(dmach[4], 1.0e-18) FID = float64(ID) if AZ > 1.0e0 { goto Seventy } // POWER SERIES FOR CABS(Z)<=1. S1R = CONER S1I = CONEI S2R = CONER S2I = CONEI if AZ < TOL { goto OneSeventy } AA = AZ * AZ if AA < TOL/AZ { goto Forty } TRM1R = CONER TRM1I = CONEI TRM2R = CONER TRM2I = CONEI ATRM = 1.0e0 STR = ZR*ZR - ZI*ZI STI = ZR*ZI + ZI*ZR Z3R = STR*ZR - STI*ZI Z3I = STR*ZI + STI*ZR AZ3 = AZ * AA AK = 2.0e0 + FID BK = 3.0e0 - FID - FID CK = 4.0e0 - FID DK = 3.0e0 + FID + FID D1 = AK * DK D2 = BK * CK AD = dmin(D1, D2) AK = 24.0e0 + 9.0e0*FID BK = 30.0e0 - 9.0e0*FID for K = 1; K <= 25; K++ { STR = (TRM1R*Z3R - TRM1I*Z3I) / D1 TRM1I = (TRM1R*Z3I + TRM1I*Z3R) / D1 TRM1R = STR S1R = S1R + TRM1R S1I = S1I + TRM1I STR = (TRM2R*Z3R - TRM2I*Z3I) / D2 TRM2I = (TRM2R*Z3I + TRM2I*Z3R) / D2 TRM2R = STR S2R = S2R + TRM2R S2I = S2I + TRM2I ATRM = ATRM * AZ3 / AD D1 = D1 + AK D2 = D2 + BK AD = dmin(D1, D2) if ATRM < TOL*AD { goto Forty } AK = AK + 18.0e0 BK = BK + 18.0e0 } Forty: if ID == 1 { goto Fifty } AIR = S1R*C1 - C2*(ZR*S2R-ZI*S2I) AII = S1I*C1 - C2*(ZR*S2I+ZI*S2R) if KODE == 1 { return } tmp = zsqrt(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) ZTAR = TTH * (ZR*STR - ZI*STI) ZTAI = TTH * (ZR*STI + ZI*STR) tmp = zexp(complex(ZTAR, ZTAI)) STR = real(tmp) STI = imag(tmp) PTR = AIR*STR - AII*STI AII = AIR*STI + AII*STR AIR = PTR return Fifty: AIR = -S2R * C2 AII = -S2I * C2 if AZ <= TOL { goto Sixty } STR = ZR*S1R - ZI*S1I STI = ZR*S1I + ZI*S1R CC = C1 / (1.0e0 + FID) AIR = AIR + CC*(STR*ZR-STI*ZI) AII = AII + CC*(STR*ZI+STI*ZR) Sixty: if KODE == 1 { return } tmp = zsqrt(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) ZTAR = TTH * (ZR*STR - ZI*STI) ZTAI = TTH * (ZR*STI + ZI*STR) tmp = zexp(complex(ZTAR, ZTAI)) STR = real(tmp) STI = imag(tmp) PTR = STR*AIR - STI*AII AII = STR*AII + STI*AIR AIR = PTR return // CASE FOR CABS(Z)>1.0. Seventy: FNU = (1.0e0 + FID) / 3.0e0 /* SET PARAMETERS RELATED TO MACHINE CONSTANTS. TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0D-18. ELIM IS THE APPROXIMATE EXPONENTIAL OVER-&&UNDERFLOW LIMIT. EXP(-ELIM)EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR UNDERFLOW&&OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LA>=Z. DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). */ K1 = imach[15] K2 = imach[16] R1M5 = dmach[5] K = min0(iabs(K1), iabs(K2)) ELIM = 2.303e0 * (float64(K)*R1M5 - 3.0e0) K1 = imach[14] - 1 AA = R1M5 * float64(K1) DIG = dmin(AA, 18.0e0) AA = AA * 2.303e0 ALIM = ELIM + dmax(-AA, -41.45e0) RL = 1.2e0*DIG + 3.0e0 ALAZ = dlog(AZ) // TEST FOR PROPER RANGE. AA = 0.5e0 / TOL BB = float64(float32(imach[9])) * 0.5e0 AA = dmin(AA, BB) AA = math.Pow(AA, TTH) if AZ > AA { goto TwoSixty } AA = dsqrt(AA) if AZ > AA { IERR = 3 } tmp = zsqrt(complex(ZR, ZI)) CSQR = real(tmp) CSQI = imag(tmp) ZTAR = TTH * (ZR*CSQR - ZI*CSQI) ZTAI = TTH * (ZR*CSQI + ZI*CSQR) // RE(ZTA)<=0 WHEN RE(Z)<0, ESPECIALLY WHEN IM(Z) IS SMALL. IFLAG = 0 SFAC = 1.0e0 AK = ZTAI if ZR >= 0.0e0 { goto Eighty } BK = ZTAR CK = -dabs(BK) ZTAR = CK ZTAI = AK Eighty: if ZI != 0.0e0 { goto Ninety } if ZR > 0.0e0 { goto Ninety } ZTAR = 0.0e0 ZTAI = AK Ninety: AA = ZTAR if AA >= 0.0e0 && ZR > 0.0e0 { goto OneTen } if KODE == 2 { goto OneHundred } // OVERFLOW TEST. if AA > (-ALIM) { goto OneHundred } AA = -AA + 0.25e0*ALAZ IFLAG = 1 SFAC = TOL if AA > ELIM { goto TwoSeventy } OneHundred: // CBKNU AND CACON return EXP(ZTA)*K(FNU,ZTA) ON KODE=2. MR = 1 if ZI < 0.0e0 { MR = -1 } ZTAR, ZTAI, FNU, KODE, MR, _, CYR, CYI, NN, RL, TOL, ELIM, ALIM = zacaiOrig(ZTAR, ZTAI, FNU, KODE, MR, 1, CYR, CYI, NN, RL, TOL, ELIM, ALIM) if NN < 0 { goto TwoEighty } NZ = NZ + NN goto OneThirty OneTen: if KODE == 2 { goto OneTwenty } // UNDERFLOW TEST. if AA < ALIM { goto OneTwenty } AA = -AA - 0.25e0*ALAZ IFLAG = 2 SFAC = 1.0e0 / TOL if AA < (-ELIM) { goto TwoTen } OneTwenty: ZTAR, ZTAI, FNU, KODE, _, CYR, CYI, NZ, TOL, ELIM, ALIM = zbknuOrig(ZTAR, ZTAI, FNU, KODE, 1, CYR, CYI, NZ, TOL, ELIM, ALIM) OneThirty: S1R = CYR[1] * COEF S1I = CYI[1] * COEF if IFLAG != 0 { goto OneFifty } if ID == 1 { goto OneFourty } AIR = CSQR*S1R - CSQI*S1I AII = CSQR*S1I + CSQI*S1R return OneFourty: AIR = -(ZR*S1R - ZI*S1I) AII = -(ZR*S1I + ZI*S1R) return OneFifty: S1R = S1R * SFAC S1I = S1I * SFAC if ID == 1 { goto OneSixty } STR = S1R*CSQR - S1I*CSQI S1I = S1R*CSQI + S1I*CSQR S1R = STR AIR = S1R / SFAC AII = S1I / SFAC return OneSixty: STR = -(S1R*ZR - S1I*ZI) S1I = -(S1R*ZI + S1I*ZR) S1R = STR AIR = S1R / SFAC AII = S1I / SFAC return OneSeventy: AA = 1.0e+3 * dmach[1] S1R = ZEROR S1I = ZEROI if ID == 1 { goto OneNinety } if AZ <= AA { goto OneEighty } S1R = C2 * ZR S1I = C2 * ZI OneEighty: AIR = C1 - S1R AII = -S1I return OneNinety: AIR = -C2 AII = 0.0e0 AA = dsqrt(AA) if AZ <= AA { goto TwoHundred } S1R = 0.5e0 * (ZR*ZR - ZI*ZI) S1I = ZR * ZI TwoHundred: AIR = AIR + C1*S1R AII = AII + C1*S1I return TwoTen: NZ = 1 AIR = ZEROR AII = ZEROI return TwoSeventy: NZ = 0 IERR = 2 return TwoEighty: if NN == (-1) { goto TwoSeventy } NZ = 0 IERR = 5 return TwoSixty: IERR = 4 NZ = 0 return } // sbknu computes the k bessel function in the right half z plane. func zbknuOrig(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL, ELIM, ALIM float64) (ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout, ELIMout, ALIMout float64) { /* Old dimension comment. DIMENSION YR(N), YI(N), CC(8), CSSR(3), CSRR(3), BRY(3), CYR(2), * CYI(2) */ // TODO(btracey): Find which of these are inputs/outputs/both and clean up // the function call. // YR and YI have length n (but n+1 with better indexing) var AA, AK, ASCLE, A1, A2, BB, BK, CAZ, CBI, CBR, CCHI, CCHR, CKI, CKR, COEFI, COEFR, CONEI, CONER, CRSCR, CSCLR, CSHI, CSHR, CSI, CSR, CTWOR, CZEROI, CZEROR, CZI, CZR, DNU, DNU2, DPI, ETEST, FC, FHS, FI, FK, FKS, FMUI, FMUR, FPI, FR, G1, G2, HPI, PI, PR, PTI, PTR, P1I, P1R, P2I, P2M, P2R, QI, QR, RAK, RCAZ, RTHPI, RZI, RZR, R1, S, SMUI, SMUR, SPI, STI, STR, S1I, S1R, S2I, S2R, TM, TTH, T1, T2, ELM, CELMR, ZDR, ZDI, AS, ALAS, HELIM float64 var I, IFLAG, INU, K, KFLAG, KK, KMAX, KODED, IDUM, J, IC, INUB, NW int var tmp complex128 var CSSR, CSRR, BRY [4]float64 var CYR, CYI [3]float64 KMAX = 30 CZEROR = 0 CZEROI = 0 CONER = 1 CONEI = 0 CTWOR = 2 R1 = 2 DPI = 3.14159265358979324e0 RTHPI = 1.25331413731550025e0 SPI = 1.90985931710274403e0 HPI = 1.57079632679489662e0 FPI = 1.89769999331517738e0 TTH = 6.66666666666666666e-01 CC := [9]float64{math.NaN(), 5.77215664901532861e-01, -4.20026350340952355e-02, -4.21977345555443367e-02, 7.21894324666309954e-03, -2.15241674114950973e-04, -2.01348547807882387e-05, 1.13302723198169588e-06, 6.11609510448141582e-09} CAZ = zabs(complex(ZR, ZI)) CSCLR = 1.0e0 / TOL CRSCR = TOL CSSR[1] = CSCLR CSSR[2] = 1.0e0 CSSR[3] = CRSCR CSRR[1] = CRSCR CSRR[2] = 1.0e0 CSRR[3] = CSCLR BRY[1] = 1.0e+3 * dmach[1] / TOL BRY[2] = 1.0e0 / BRY[1] BRY[3] = dmach[2] NZ = 0 IFLAG = 0 KODED = KODE RCAZ = 1.0e0 / CAZ STR = ZR * RCAZ STI = -ZI * RCAZ RZR = (STR + STR) * RCAZ RZI = (STI + STI) * RCAZ INU = int(float32(FNU + 0.5)) DNU = FNU - float64(INU) if dabs(DNU) == 0.5e0 { goto OneTen } DNU2 = 0.0e0 if dabs(DNU) > TOL { DNU2 = DNU * DNU } if CAZ > R1 { goto OneTen } // SERIES FOR CABS(Z)<=R1. FC = 1.0e0 tmp = zlog(complex(RZR, RZI)) SMUR = real(tmp) SMUI = imag(tmp) FMUR = SMUR * DNU FMUI = SMUI * DNU FMUR, FMUI, CSHR, CSHI, CCHR, CCHI = zshchOrig(FMUR, FMUI, CSHR, CSHI, CCHR, CCHI) if DNU == 0.0e0 { goto Ten } FC = DNU * DPI FC = FC / dsin(FC) SMUR = CSHR / DNU SMUI = CSHI / DNU Ten: A2 = 1.0e0 + DNU // GAM(1-Z)*GAM(1+Z)=PI*Z/SIN(PI*Z), T1=1/GAM(1-DNU), T2=1/GAM(1+DNU). T2 = dexp(-dgamln(A2, IDUM)) T1 = 1.0e0 / (T2 * FC) if dabs(DNU) > 0.1e0 { goto Forty } // SERIES FOR F0 TO RESOLVE INDETERMINACY FOR SMALL ABS(DNU). AK = 1.0e0 S = CC[1] for K = 2; K <= 8; K++ { AK = AK * DNU2 TM = CC[K] * AK S = S + TM if dabs(TM) < TOL { goto Thirty } } Thirty: G1 = -S goto Fifty Forty: G1 = (T1 - T2) / (DNU + DNU) Fifty: G2 = (T1 + T2) * 0.5e0 FR = FC * (CCHR*G1 + SMUR*G2) FI = FC * (CCHI*G1 + SMUI*G2) tmp = zexp(complex(FMUR, FMUI)) STR = real(tmp) STI = imag(tmp) PR = 0.5e0 * STR / T2 PI = 0.5e0 * STI / T2 tmp = zdiv(complex(0.5, 0), complex(STR, STI)) PTR = real(tmp) PTI = imag(tmp) QR = PTR / T1 QI = PTI / T1 S1R = FR S1I = FI S2R = PR S2I = PI AK = 1.0e0 A1 = 1.0e0 CKR = CONER CKI = CONEI BK = 1.0e0 - DNU2 if INU > 0 || N > 1 { goto Eighty } // GENERATE K(FNU,Z), 0.0E0 <= FNU < 0.5E0 AND N=1. if CAZ < TOL { goto Seventy } tmp = zmlt(complex(ZR, ZI), complex(ZR, ZI)) CZR = real(tmp) CZI = imag(tmp) CZR = 0.25e0 * CZR CZI = 0.25e0 * CZI T1 = 0.25e0 * CAZ * CAZ Sixty: FR = (FR*AK + PR + QR) / BK FI = (FI*AK + PI + QI) / BK STR = 1.0e0 / (AK - DNU) PR = PR * STR PI = PI * STR STR = 1.0e0 / (AK + DNU) QR = QR * STR QI = QI * STR STR = CKR*CZR - CKI*CZI RAK = 1.0e0 / AK CKI = (CKR*CZI + CKI*CZR) * RAK CKR = STR * RAK S1R = CKR*FR - CKI*FI + S1R S1I = CKR*FI + CKI*FR + S1I A1 = A1 * T1 * RAK BK = BK + AK + AK + 1.0e0 AK = AK + 1.0e0 if A1 > TOL { goto Sixty } Seventy: YR[1] = S1R YI[1] = S1I if KODED == 1 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } tmp = zexp(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) tmp = zmlt(complex(S1R, S1I), complex(STR, STI)) YR[1] = real(tmp) YI[1] = imag(tmp) return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM // GENERATE K(DNU,Z) AND K(DNU+1,Z) FOR FORWARD RECURRENCE. Eighty: if CAZ < TOL { goto OneHundred } tmp = zmlt(complex(ZR, ZI), complex(ZR, ZI)) CZR = real(tmp) CZI = imag(tmp) CZR = 0.25e0 * CZR CZI = 0.25e0 * CZI T1 = 0.25e0 * CAZ * CAZ Ninety: FR = (FR*AK + PR + QR) / BK FI = (FI*AK + PI + QI) / BK STR = 1.0e0 / (AK - DNU) PR = PR * STR PI = PI * STR STR = 1.0e0 / (AK + DNU) QR = QR * STR QI = QI * STR STR = CKR*CZR - CKI*CZI RAK = 1.0e0 / AK CKI = (CKR*CZI + CKI*CZR) * RAK CKR = STR * RAK S1R = CKR*FR - CKI*FI + S1R S1I = CKR*FI + CKI*FR + S1I STR = PR - FR*AK STI = PI - FI*AK S2R = CKR*STR - CKI*STI + S2R S2I = CKR*STI + CKI*STR + S2I A1 = A1 * T1 * RAK BK = BK + AK + AK + 1.0e0 AK = AK + 1.0e0 if A1 > TOL { goto Ninety } OneHundred: KFLAG = 2 A1 = FNU + 1.0e0 AK = A1 * dabs(SMUR) if AK > ALIM { KFLAG = 3 } STR = CSSR[KFLAG] P2R = S2R * STR P2I = S2I * STR tmp = zmlt(complex(P2R, P2I), complex(RZR, RZI)) S2R = real(tmp) S2I = imag(tmp) S1R = S1R * STR S1I = S1I * STR if KODED == 1 { goto TwoTen } tmp = zexp(complex(ZR, ZI)) FR = real(tmp) FI = imag(tmp) tmp = zmlt(complex(S1R, S1I), complex(FR, FI)) S1R = real(tmp) S1I = imag(tmp) tmp = zmlt(complex(S2R, S2I), complex(FR, FI)) S2R = real(tmp) S2I = imag(tmp) goto TwoTen // IFLAG=0 MEANS NO UNDERFLOW OCCURRED // IFLAG=1 MEANS AN UNDERFLOW OCCURRED- COMPUTATION PROCEEDS WITH // KODED=2 AND A TEST FOR ON SCALE VALUES IS MADE DURING FORWARD RECURSION OneTen: tmp = zsqrt(complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) tmp = zdiv(complex(RTHPI, CZEROI), complex(STR, STI)) COEFR = real(tmp) COEFI = imag(tmp) KFLAG = 2 if KODED == 2 { goto OneTwenty } if ZR > ALIM { goto TwoNinety } STR = dexp(-ZR) * CSSR[KFLAG] STI = -STR * dsin(ZI) STR = STR * dcos(ZI) tmp = zmlt(complex(COEFR, COEFI), complex(STR, STI)) COEFR = real(tmp) COEFI = imag(tmp) OneTwenty: if dabs(DNU) == 0.5e0 { goto ThreeHundred } // MILLER ALGORITHM FOR CABS(Z)>R1. AK = dcos(DPI * DNU) AK = dabs(AK) if AK == CZEROR { goto ThreeHundred } FHS = dabs(0.25e0 - DNU2) if FHS == CZEROR { goto ThreeHundred } // COMPUTE R2=F(E). if CABS(Z)>=R2, USE FORWARD RECURRENCE TO // DETERMINE THE BACKWARD INDEX K. R2=F(E) IS A STRAIGHT LINE ON // 12<=E<=60. E IS COMPUTED FROM 2**(-E)=B**(1-I1MACH(14))= // TOL WHERE B IS THE BASE OF THE ARITHMETIC. T1 = float64(imach[14] - 1) T1 = T1 * dmach[5] * 3.321928094e0 T1 = dmax(T1, 12.0e0) T1 = dmin(T1, 60.0e0) T2 = TTH*T1 - 6.0e0 if ZR != 0.0e0 { goto OneThirty } T1 = HPI goto OneFourty OneThirty: T1 = datan(ZI / ZR) T1 = dabs(T1) OneFourty: if T2 > CAZ { goto OneSeventy } // FORWARD RECURRENCE LOOP WHEN CABS(Z)>=R2. ETEST = AK / (DPI * CAZ * TOL) FK = CONER if ETEST < CONER { goto OneEighty } FKS = CTWOR CKR = CAZ + CAZ + CTWOR P1R = CZEROR P2R = CONER for I = 1; I <= KMAX; I++ { AK = FHS / FKS CBR = CKR / (FK + CONER) PTR = P2R P2R = CBR*P2R - P1R*AK P1R = PTR CKR = CKR + CTWOR FKS = FKS + FK + FK + CTWOR FHS = FHS + FK + FK FK = FK + CONER STR = dabs(P2R) * FK if ETEST < STR { goto OneSixty } } goto ThreeTen OneSixty: FK = FK + SPI*T1*dsqrt(T2/CAZ) FHS = dabs(0.25 - DNU2) goto OneEighty OneSeventy: // COMPUTE BACKWARD INDEX K FOR CABS(Z) 0 || N > 1 { goto TwoHundred } ZDR = ZR ZDI = ZI if IFLAG == 1 { goto TwoSeventy } goto TwoFourty TwoHundred: // COMPUTE P1/P2=(P1/CABS(P2)*CONJG(P2)/CABS(P2) FOR SCALING. TM = zabs(complex(P2R, P2I)) PTR = 1.0e0 / TM P1R = P1R * PTR P1I = P1I * PTR P2R = P2R * PTR P2I = -P2I * PTR tmp = zmlt(complex(P1R, P1I), complex(P2R, P2I)) PTR = real(tmp) PTI = imag(tmp) STR = DNU + 0.5e0 - PTR STI = -PTI tmp = zdiv(complex(STR, STI), complex(ZR, ZI)) STR = real(tmp) STI = imag(tmp) STR = STR + 1.0e0 tmp = zmlt(complex(STR, STI), complex(S1R, S1I)) S2R = real(tmp) S2I = imag(tmp) // FORWARD RECURSION ON THE THREE TERM RECURSION WITH RELATION WITH // SCALING NEAR EXPONENT EXTREMES ON KFLAG=1 OR KFLAG=3 TwoTen: STR = DNU + 1.0e0 CKR = STR * RZR CKI = STR * RZI if N == 1 { INU = INU - 1 } if INU > 0 { goto TwoTwenty } if N > 1 { goto TwoFifteen } S1R = S2R S1I = S2I TwoFifteen: ZDR = ZR ZDI = ZI if IFLAG == 1 { goto TwoSeventy } goto TwoFourty TwoTwenty: INUB = 1 if IFLAG == 1 { goto TwoSixtyOne } TwoTwentyFive: P1R = CSRR[KFLAG] ASCLE = BRY[KFLAG] for I = INUB; I <= INU; I++ { STR = S2R STI = S2I S2R = CKR*STR - CKI*STI + S1R S2I = CKR*STI + CKI*STR + S1I S1R = STR S1I = STI CKR = CKR + RZR CKI = CKI + RZI if KFLAG >= 3 { continue } P2R = S2R * P1R P2I = S2I * P1R STR = dabs(P2R) STI = dabs(P2I) P2M = dmax(STR, STI) if P2M <= ASCLE { continue } KFLAG = KFLAG + 1 ASCLE = BRY[KFLAG] S1R = S1R * P1R S1I = S1I * P1R S2R = P2R S2I = P2I STR = CSSR[KFLAG] S1R = S1R * STR S1I = S1I * STR S2R = S2R * STR S2I = S2I * STR P1R = CSRR[KFLAG] } if N != 1 { goto TwoFourty } S1R = S2R S1I = S2I TwoFourty: STR = CSRR[KFLAG] YR[1] = S1R * STR YI[1] = S1I * STR if N == 1 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } YR[2] = S2R * STR YI[2] = S2I * STR if N == 2 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } KK = 2 TwoFifty: KK = KK + 1 if KK > N { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } P1R = CSRR[KFLAG] ASCLE = BRY[KFLAG] for I = KK; I <= N; I++ { P2R = S2R P2I = S2I S2R = CKR*P2R - CKI*P2I + S1R S2I = CKI*P2R + CKR*P2I + S1I S1R = P2R S1I = P2I CKR = CKR + RZR CKI = CKI + RZI P2R = S2R * P1R P2I = S2I * P1R YR[I] = P2R YI[I] = P2I if KFLAG >= 3 { continue } STR = dabs(P2R) STI = dabs(P2I) P2M = dmax(STR, STI) if P2M <= ASCLE { continue } KFLAG = KFLAG + 1 ASCLE = BRY[KFLAG] S1R = S1R * P1R S1I = S1I * P1R S2R = P2R S2I = P2I STR = CSSR[KFLAG] S1R = S1R * STR S1I = S1I * STR S2R = S2R * STR S2I = S2I * STR P1R = CSRR[KFLAG] } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM // IFLAG=1 CASES, FORWARD RECURRENCE ON SCALED VALUES ON UNDERFLOW. TwoSixtyOne: HELIM = 0.5e0 * ELIM ELM = dexp(-ELIM) CELMR = ELM ASCLE = BRY[1] ZDR = ZR ZDI = ZI IC = -1 J = 2 for I = 1; I <= INU; I++ { STR = S2R STI = S2I S2R = STR*CKR - STI*CKI + S1R S2I = STI*CKR + STR*CKI + S1I S1R = STR S1I = STI CKR = CKR + RZR CKI = CKI + RZI AS = zabs(complex(S2R, S2I)) ALAS = dlog(AS) P2R = -ZDR + ALAS if P2R < (-ELIM) { goto TwoSixtyThree } tmp = zlog(complex(S2R, S2I)) STR = real(tmp) STI = imag(tmp) P2R = -ZDR + STR P2I = -ZDI + STI P2M = dexp(P2R) / TOL P1R = P2M * dcos(P2I) P1I = P2M * dsin(P2I) P1R, P1I, NW, ASCLE, TOL = zuchkOrig(P1R, P1I, NW, ASCLE, TOL) if NW != 0 { goto TwoSixtyThree } J = 3 - J CYR[J] = P1R CYI[J] = P1I if IC == (I - 1) { goto TwoSixtyFour } IC = I continue TwoSixtyThree: if ALAS < HELIM { continue } ZDR = ZDR - ELIM S1R = S1R * CELMR S1I = S1I * CELMR S2R = S2R * CELMR S2I = S2I * CELMR } if N != 1 { goto TwoSeventy } S1R = S2R S1I = S2I goto TwoSeventy TwoSixtyFour: KFLAG = 1 INUB = I + 1 S2R = CYR[J] S2I = CYI[J] J = 3 - J S1R = CYR[J] S1I = CYI[J] if INUB <= INU { goto TwoTwentyFive } if N != 1 { goto TwoFourty } S1R = S2R S1I = S2I goto TwoFourty TwoSeventy: YR[1] = S1R YI[1] = S1I if N == 1 { goto TwoEighty } YR[2] = S2R YI[2] = S2I TwoEighty: ASCLE = BRY[1] ZDR, ZDI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM = zksclOrig(ZDR, ZDI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM) INU = N - NZ if INU <= 0 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } KK = NZ + 1 S1R = YR[KK] S1I = YI[KK] YR[KK] = S1R * CSRR[1] YI[KK] = S1I * CSRR[1] if INU == 1 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } KK = NZ + 2 S2R = YR[KK] S2I = YI[KK] YR[KK] = S2R * CSRR[1] YI[KK] = S2I * CSRR[1] if INU == 2 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } T2 = FNU + float64(float32(KK-1)) CKR = T2 * RZR CKI = T2 * RZI KFLAG = 1 goto TwoFifty TwoNinety: // SCALE BY dexp(Z), IFLAG = 1 CASES. KODED = 2 IFLAG = 1 KFLAG = 2 goto OneTwenty // FNU=HALF ODD INTEGER CASE, DNU=-0.5 ThreeHundred: S1R = COEFR S1I = COEFI S2R = COEFR S2I = COEFI goto TwoTen ThreeTen: NZ = -2 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } // SET K FUNCTIONS TO ZERO ON UNDERFLOW, CONTINUE RECURRENCE // ON SCALED FUNCTIONS UNTIL TWO MEMBERS COME ON SCALE, THEN // return WITH MIN(NZ+2,N) VALUES SCALED BY 1/TOL. func zksclOrig(ZRR, ZRI, FNU float64, N int, YR, YI []float64, NZ int, RZR, RZI, ASCLE, TOL, ELIM float64) ( ZRRout, ZRIout, FNUout float64, Nout int, YRout, YIout []float64, NZout int, RZRout, RZIout, ASCLEout, TOLout, ELIMout float64) { var ACS, AS, CKI, CKR, CSI, CSR, FN, STR, S1I, S1R, S2I, S2R, ZEROI, ZEROR, ZDR, ZDI, CELMR, ELM, HELIM, ALAS float64 var I, IC, KK, NN, NW int var tmp complex128 var CYR, CYI [3]float64 // DIMENSION YR(N), YI(N), CYR(2), CYI(2) ZEROR = 0 ZEROI = 0 NZ = 0 IC = 0 NN = min0(2, N) for I = 1; I <= NN; I++ { S1R = YR[I] S1I = YI[I] CYR[I] = S1R CYI[I] = S1I AS = zabs(complex(S1R, S1I)) ACS = -ZRR + dlog(AS) NZ = NZ + 1 YR[I] = ZEROR YI[I] = ZEROI if ACS < (-ELIM) { continue } tmp = zlog(complex(S1R, S1I)) CSR = real(tmp) CSI = imag(tmp) CSR = CSR - ZRR CSI = CSI - ZRI STR = dexp(CSR) / TOL CSR = STR * dcos(CSI) CSI = STR * dsin(CSI) CSR, CSI, NW, ASCLE, TOL = zuchkOrig(CSR, CSI, NW, ASCLE, TOL) if NW != 0 { continue } YR[I] = CSR YI[I] = CSI IC = I NZ = NZ - 1 } if N == 1 { return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } if IC > 1 { goto Twenty } YR[1] = ZEROR YI[1] = ZEROI NZ = 2 Twenty: if N == 2 { return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } if NZ == 0 { return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } FN = FNU + 1.0e0 CKR = FN * RZR CKI = FN * RZI S1R = CYR[1] S1I = CYI[1] S2R = CYR[2] S2I = CYI[2] HELIM = 0.5e0 * ELIM ELM = dexp(-ELIM) CELMR = ELM ZDR = ZRR ZDI = ZRI // FIND TWO CONSECUTIVE Y VALUES ON SCALE. SCALE RECURRENCE IF // S2 GETS LARGER THAN EXP(ELIM/2) for I = 3; I <= N; I++ { KK = I CSR = S2R CSI = S2I S2R = CKR*CSR - CKI*CSI + S1R S2I = CKI*CSR + CKR*CSI + S1I S1R = CSR S1I = CSI CKR = CKR + RZR CKI = CKI + RZI AS = zabs(complex(S2R, S2I)) ALAS = dlog(AS) ACS = -ZDR + ALAS NZ = NZ + 1 YR[I] = ZEROR YI[I] = ZEROI if ACS < (-ELIM) { goto TwentyFive } tmp = zlog(complex(S2R, S2I)) CSR = real(tmp) CSI = imag(tmp) CSR = CSR - ZDR CSI = CSI - ZDI STR = dexp(CSR) / TOL CSR = STR * dcos(CSI) CSI = STR * dsin(CSI) CSR, CSI, NW, ASCLE, TOL = zuchkOrig(CSR, CSI, NW, ASCLE, TOL) if NW != 0 { goto TwentyFive } YR[I] = CSR YI[I] = CSI NZ = NZ - 1 if IC == KK-1 { goto Forty } IC = KK continue TwentyFive: if ALAS < HELIM { continue } ZDR = ZDR - ELIM S1R = S1R * CELMR S1I = S1I * CELMR S2R = S2R * CELMR S2I = S2I * CELMR } NZ = N if IC == N { NZ = N - 1 } goto FourtyFive Forty: NZ = KK - 2 FourtyFive: for I = 1; I <= NZ; I++ { YR[I] = ZEROR YI[I] = ZEROI } return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM } // Y ENTERS AS A SCALED QUANTITY WHOSE MAGNITUDE IS GREATER THAN // EXP(-ALIM)=ASCLE=1.0E+3*dmach[1)/TOL. THE TEST IS MADE TO SEE // if THE MAGNITUDE OF THE REAL OR IMAGINARY PART WOULD UNDERFLOW // WHEN Y IS SCALED (BY TOL) TO ITS PROPER VALUE. Y IS ACCEPTED // if THE UNDERFLOW IS AT LEAST ONE PRECISION BELOW THE MAGNITUDE // OF THE LARGEST COMPONENT; OTHERWISE THE PHASE ANGLE DOES NOT HAVE // ABSOLUTE ACCURACY AND AN UNDERFLOW IS ASSUMED. func zuchkOrig(YR, YI float64, NZ int, ASCLE, TOL float64) (YRout, YIout float64, NZout int, ASCLEout, TOLout float64) { var SS, ST, WR, WI float64 NZ = 0 WR = dabs(YR) WI = dabs(YI) ST = dmin(WR, WI) if ST > ASCLE { return YR, YI, NZ, ASCLE, TOL } SS = dmax(WR, WI) ST = ST / TOL if SS < ST { NZ = 1 } return YR, YI, NZ, ASCLE, TOL } // ZACAI APPLIES THE ANALYTIC CONTINUATION FORMULA // // K(FNU,ZN*EXP(MP))=K(FNU,ZN)*EXP(-MP*FNU) - MP*I(FNU,ZN) // MP=PI*MR*CMPLX(0.0,1.0) // // TO CONTINUE THE K FUNCTION FROM THE RIGHT HALF TO THE LEFT // HALF Z PLANE FOR USE WITH ZAIRY WHERE FNU=1/3 OR 2/3 AND N=1. // ZACAI IS THE SAME AS ZACON WITH THE PARTS FOR LARGER ORDERS AND // RECURRENCE REMOVED. A RECURSIVE CALL TO ZACON CAN RESULT if ZACON // IS CALLED FROM ZAIRY. func zacaiOrig(ZR, ZI, FNU float64, KODE, MR, N int, YR, YI []float64, NZ int, RL, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, MRout, Nout int, YRout, YIout []float64, NZout int, RLout, TOLout, ELIMout, ALIMout float64) { var ARG, ASCLE, AZ, CSGNR, CSGNI, CSPNR, CSPNI, C1R, C1I, C2R, C2I, DFNU, FMR, PI, SGN, YY, ZNR, ZNI float64 var INU, IUF, NN, NW int CYR := []float64{math.NaN(), 0, 0} CYI := []float64{math.NaN(), 0, 0} PI = math.Pi NZ = 0 ZNR = -ZR ZNI = -ZI AZ = zabs(complex(ZR, ZI)) NN = N DFNU = FNU + float64(float32(N-1)) if AZ <= 2.0e0 { goto Ten } if AZ*AZ*0.25 > DFNU+1.0e0 { goto Twenty } Ten: // POWER SERIES FOR THE I FUNCTION. ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL, ELIM, ALIM = zseriOrig(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL, ELIM, ALIM) goto Forty Twenty: if AZ < RL { goto Thirty } // ASYMPTOTIC EXPANSION FOR LARGE Z FOR THE I FUNCTION. ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, RL, TOL, ELIM, ALIM = zasyiOrig(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, RL, TOL, ELIM, ALIM) if NW < 0 { goto Eighty } goto Forty Thirty: // MILLER ALGORITHM NORMALIZED BY THE SERIES FOR THE I FUNCTION ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL = zmlriOrig(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL) if NW < 0 { goto Eighty } Forty: // ANALYTIC CONTINUATION TO THE LEFT HALF PLANE FOR THE K FUNCTION. ZNR, ZNI, FNU, KODE, _, CYR, CYI, NW, TOL, ELIM, ALIM = zbknuOrig(ZNR, ZNI, FNU, KODE, 1, CYR, CYI, NW, TOL, ELIM, ALIM) if NW != 0 { goto Eighty } FMR = float64(float32(MR)) SGN = -math.Copysign(PI, FMR) CSGNR = 0.0e0 CSGNI = SGN if KODE == 1 { goto Fifty } YY = -ZNI CSGNR = -CSGNI * dsin(YY) CSGNI = CSGNI * dcos(YY) Fifty: // CALCULATE CSPN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE // WHEN FNU IS LARGE INU = int(float32(FNU)) ARG = (FNU - float64(float32(INU))) * SGN CSPNR = dcos(ARG) CSPNI = dsin(ARG) if INU%2 == 0 { goto Sixty } CSPNR = -CSPNR CSPNI = -CSPNI Sixty: C1R = CYR[1] C1I = CYI[1] C2R = YR[1] C2I = YI[1] if KODE == 1 { goto Seventy } IUF = 0 ASCLE = 1.0e+3 * dmach[1] / TOL ZNR, ZNI, C1R, C1I, C2R, C2I, NW, ASCLE, ALIM, IUF = zs1s2Orig(ZNR, ZNI, C1R, C1I, C2R, C2I, NW, ASCLE, ALIM, IUF) NZ = NZ + NW Seventy: YR[1] = CSPNR*C1R - CSPNI*C1I + CSGNR*C2R - CSGNI*C2I YI[1] = CSPNR*C1I + CSPNI*C1R + CSGNR*C2I + CSGNI*C2R return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM Eighty: NZ = -1 if NW == -2 { NZ = -2 } return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } // ZASYI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z)>=0.0 BY // MEANS OF THE ASYMPTOTIC EXPANSION FOR LARGE CABS(Z) IN THE // REGION CABS(Z)>MAX(RL,FNU*FNU/2). NZ=0 IS A NORMAL return. // NZ<0 INDICATES AN OVERFLOW ON KODE=1. func zasyiOrig(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, RL, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, RLout, TOLout, ELIMout, ALIMout float64) { var AA, AEZ, AK, AK1I, AK1R, ARG, ARM, ATOL, AZ, BB, BK, CKI, CKR, CONEI, CONER, CS1I, CS1R, CS2I, CS2R, CZI, CZR, DFNU, DKI, DKR, DNU2, EZI, EZR, FDN, PI, P1I, P1R, RAZ, RTPI, RTR1, RZI, RZR, S, SGN, SQK, STI, STR, S2I, S2R, TZI, TZR, ZEROI, ZEROR float64 var I, IB, IL, INU, J, JL, K, KODED, M, NN int var tmp complex128 PI = math.Pi RTPI = 0.159154943091895336e0 ZEROR = 0 ZEROI = 0 CONER = 1 CONEI = 0 NZ = 0 AZ = zabs(complex(ZR, ZI)) ARM = 1.0e3 * dmach[1] RTR1 = dsqrt(ARM) IL = min0(2, N) DFNU = FNU + float64(float32(N-IL)) // OVERFLOW TEST RAZ = 1.0e0 / AZ STR = ZR * RAZ STI = -ZI * RAZ AK1R = RTPI * STR * RAZ AK1I = RTPI * STI * RAZ tmp = zsqrt(complex(AK1R, AK1I)) AK1R = real(tmp) AK1I = imag(tmp) CZR = ZR CZI = ZI if KODE != 2 { goto Ten } CZR = ZEROR CZI = ZI Ten: if dabs(CZR) > ELIM { goto OneHundred } DNU2 = DFNU + DFNU KODED = 1 if (dabs(CZR) > ALIM) && (N > 2) { goto Twenty } KODED = 0 tmp = zexp(complex(CZR, CZI)) STR = real(tmp) STI = imag(tmp) tmp = zmlt(complex(AK1R, AK1I), complex(STR, STI)) AK1R = real(tmp) AK1I = imag(tmp) Twenty: FDN = 0.0e0 if DNU2 > RTR1 { FDN = DNU2 * DNU2 } EZR = ZR * 8.0e0 EZI = ZI * 8.0e0 // WHEN Z IS IMAGINARY, THE ERROR TEST MUST BE MADE RELATIVE TO THE // FIRST RECIPROCAL POWER SINCE THIS IS THE LEADING TERM OF THE // EXPANSION FOR THE IMAGINARY PART. AEZ = 8.0e0 * AZ S = TOL / AEZ JL = int(float32(RL+RL)) + 2 P1R = ZEROR P1I = ZEROI if ZI == 0.0e0 { goto Thirty } // CALCULATE EXP(PI*(0.5+FNU+N-IL)*I) TO MINIMIZE LOSSES OF // SIGNIFICANCE WHEN FNU OR N IS LARGE INU = int(float32(FNU)) ARG = (FNU - float64(float32(INU))) * PI INU = INU + N - IL AK = -dsin(ARG) BK = dcos(ARG) if ZI < 0.0e0 { BK = -BK } P1R = AK P1I = BK if INU%2 == 0 { goto Thirty } P1R = -P1R P1I = -P1I Thirty: for K = 1; K <= IL; K++ { SQK = FDN - 1.0e0 ATOL = S * dabs(SQK) SGN = 1.0e0 CS1R = CONER CS1I = CONEI CS2R = CONER CS2I = CONEI CKR = CONER CKI = CONEI AK = 0.0e0 AA = 1.0e0 BB = AEZ DKR = EZR DKI = EZI // TODO(btracey): This loop is executed tens of thousands of times. Why? // is that really necessary? for J = 1; J <= JL; J++ { tmp = zdiv(complex(CKR, CKI), complex(DKR, DKI)) STR = real(tmp) STI = imag(tmp) CKR = STR * SQK CKI = STI * SQK CS2R = CS2R + CKR CS2I = CS2I + CKI SGN = -SGN CS1R = CS1R + CKR*SGN CS1I = CS1I + CKI*SGN DKR = DKR + EZR DKI = DKI + EZI AA = AA * dabs(SQK) / BB BB = BB + AEZ AK = AK + 8.0e0 SQK = SQK - AK if AA <= ATOL { goto Fifty } } goto OneTen Fifty: S2R = CS1R S2I = CS1I if ZR+ZR >= ELIM { goto Sixty } TZR = ZR + ZR TZI = ZI + ZI tmp = zexp(complex(-TZR, -TZI)) STR = real(tmp) STI = imag(tmp) tmp = zmlt(complex(STR, STI), complex(P1R, P1I)) STR = real(tmp) STI = imag(tmp) tmp = zmlt(complex(STR, STI), complex(CS2R, CS2I)) STR = real(tmp) STI = imag(tmp) S2R = S2R + STR S2I = S2I + STI Sixty: FDN = FDN + 8.0e0*DFNU + 4.0e0 P1R = -P1R P1I = -P1I M = N - IL + K YR[M] = S2R*AK1R - S2I*AK1I YI[M] = S2R*AK1I + S2I*AK1R } if N <= 2 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } NN = N K = NN - 2 AK = float64(float32(K)) STR = ZR * RAZ STI = -ZI * RAZ RZR = (STR + STR) * RAZ RZI = (STI + STI) * RAZ IB = 3 for I = IB; I <= NN; I++ { YR[K] = (AK+FNU)*(RZR*YR[K+1]-RZI*YI[K+1]) + YR[K+2] YI[K] = (AK+FNU)*(RZR*YI[K+1]+RZI*YR[K+1]) + YI[K+2] AK = AK - 1.0e0 K = K - 1 } if KODED == 0 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } tmp = zexp(complex(CZR, CZI)) CKR = real(tmp) CKI = imag(tmp) for I = 1; I <= NN; I++ { STR = YR[I]*CKR - YI[I]*CKI YI[I] = YR[I]*CKI + YI[I]*CKR YR[I] = STR } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM OneHundred: NZ = -1 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM OneTen: NZ = -2 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM } // ZMLRI COMPUTES THE I BESSEL FUNCTION FOR RE(Z)>=0.0 BY THE // MILLER ALGORITHM NORMALIZED BY A NEUMANN SERIES. func zmlriOrig(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout float64) { var ACK, AK, AP, AT, AZ, BK, CKI, CKR, CNORMI, CNORMR, CONEI, CONER, FKAP, FKK, FLAM, FNF, PTI, PTR, P1I, P1R, P2I, P2R, RAZ, RHO, RHO2, RZI, RZR, SCLE, STI, STR, SUMI, SUMR, TFNF, TST, ZEROI, ZEROR float64 var I, IAZ, IDUM, IFNU, INU, ITIME, K, KK, KM, M int var tmp complex128 ZEROR = 0 ZEROI = 0 CONER = 1 CONEI = 0 SCLE = dmach[1] / TOL NZ = 0 AZ = zabs(complex(ZR, ZI)) IAZ = int(float32(AZ)) IFNU = int(float32(FNU)) INU = IFNU + N - 1 AT = float64(float32(IAZ)) + 1.0e0 RAZ = 1.0e0 / AZ STR = ZR * RAZ STI = -ZI * RAZ CKR = STR * AT * RAZ CKI = STI * AT * RAZ RZR = (STR + STR) * RAZ RZI = (STI + STI) * RAZ P1R = ZEROR P1I = ZEROI P2R = CONER P2I = CONEI ACK = (AT + 1.0e0) * RAZ RHO = ACK + dsqrt(ACK*ACK-1.0e0) RHO2 = RHO * RHO TST = (RHO2 + RHO2) / ((RHO2 - 1.0e0) * (RHO - 1.0e0)) TST = TST / TOL // COMPUTE RELATIVE TRUNCATION ERROR INDEX FOR SERIES. //fmt.Println("before loop", P2R, P2I, CKR, CKI, RZR, RZI, TST, AK) AK = AT for I = 1; I <= 80; I++ { PTR = P2R PTI = P2I P2R = P1R - (CKR*PTR - CKI*PTI) P2I = P1I - (CKI*PTR + CKR*PTI) P1R = PTR P1I = PTI CKR = CKR + RZR CKI = CKI + RZI AP = zabs(complex(P2R, P2I)) if AP > TST*AK*AK { goto Twenty } AK = AK + 1.0e0 } goto OneTen Twenty: I = I + 1 K = 0 if INU < IAZ { goto Forty } // COMPUTE RELATIVE TRUNCATION ERROR FOR RATIOS. P1R = ZEROR P1I = ZEROI P2R = CONER P2I = CONEI AT = float64(float32(INU)) + 1.0e0 STR = ZR * RAZ STI = -ZI * RAZ CKR = STR * AT * RAZ CKI = STI * AT * RAZ ACK = AT * RAZ TST = dsqrt(ACK / TOL) ITIME = 1 for K = 1; K <= 80; K++ { PTR = P2R PTI = P2I P2R = P1R - (CKR*PTR - CKI*PTI) P2I = P1I - (CKR*PTI + CKI*PTR) P1R = PTR P1I = PTI CKR = CKR + RZR CKI = CKI + RZI AP = zabs(complex(P2R, P2I)) if AP < TST { continue } if ITIME == 2 { goto Forty } ACK = zabs(complex(CKR, CKI)) FLAM = ACK + dsqrt(ACK*ACK-1.0e0) FKAP = AP / zabs(complex(P1R, P1I)) RHO = dmin(FLAM, FKAP) TST = TST * dsqrt(RHO/(RHO*RHO-1.0e0)) ITIME = 2 } goto OneTen Forty: // BACKWARD RECURRENCE AND SUM NORMALIZING RELATION. K = K + 1 KK = max0(I+IAZ, K+INU) FKK = float64(float32(KK)) P1R = ZEROR P1I = ZEROI // SCALE P2 AND SUM BY SCLE. P2R = SCLE P2I = ZEROI FNF = FNU - float64(float32(IFNU)) TFNF = FNF + FNF BK = dgamln(FKK+TFNF+1.0e0, IDUM) - dgamln(FKK+1.0e0, IDUM) - dgamln(TFNF+1.0e0, IDUM) BK = dexp(BK) SUMR = ZEROR SUMI = ZEROI KM = KK - INU for I = 1; I <= KM; I++ { PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) P1R = PTR P1I = PTI AK = 1.0e0 - TFNF/(FKK+TFNF) ACK = BK * AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0e0 } YR[N] = P2R YI[N] = P2I if N == 1 { goto Seventy } for I = 2; I <= N; I++ { PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) P1R = PTR P1I = PTI AK = 1.0e0 - TFNF/(FKK+TFNF) ACK = BK * AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0e0 M = N - I + 1 YR[M] = P2R YI[M] = P2I } Seventy: if IFNU <= 0 { goto Ninety } for I = 1; I <= IFNU; I++ { PTR = P2R PTI = P2I P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) P2I = P1I + (FKK+FNF)*(RZR*PTI+RZI*PTR) P1R = PTR P1I = PTI AK = 1.0e0 - TFNF/(FKK+TFNF) ACK = BK * AK SUMR = SUMR + (ACK+BK)*P1R SUMI = SUMI + (ACK+BK)*P1I BK = ACK FKK = FKK - 1.0e0 } Ninety: PTR = ZR PTI = ZI if KODE == 2 { PTR = ZEROR } tmp = zlog(complex(RZR, RZI)) STR = real(tmp) STI = imag(tmp) P1R = -FNF*STR + PTR P1I = -FNF*STI + PTI AP = dgamln(1.0e0+FNF, IDUM) PTR = P1R - AP PTI = P1I // THE DIVISION CEXP(PT)/(SUM+P2) IS ALTERED TO AVOID OVERFLOW // IN THE DENOMINATOR BY SQUARING LARGE QUANTITIES. P2R = P2R + SUMR P2I = P2I + SUMI AP = zabs(complex(P2R, P2I)) P1R = 1.0e0 / AP tmp = zexp(complex(PTR, PTI)) STR = real(tmp) STI = imag(tmp) CKR = STR * P1R CKI = STI * P1R PTR = P2R * P1R PTI = -P2I * P1R tmp = zmlt(complex(CKR, CKI), complex(PTR, PTI)) CNORMR = real(tmp) CNORMI = imag(tmp) for I = 1; I <= N; I++ { STR = YR[I]*CNORMR - YI[I]*CNORMI YI[I] = YR[I]*CNORMI + YI[I]*CNORMR YR[I] = STR } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL OneTen: NZ = -2 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL } // ZSERI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z)>=0.0 BY // MEANS OF THE POWER SERIES FOR LARGE CABS(Z) IN THE // REGION CABS(Z)<=2*SQRT(FNU+1). NZ=0 IS A NORMAL return. // NZ>0 MEANS THAT THE LAST NZ COMPONENTS WERE SET TO ZERO // DUE TO UNDERFLOW. NZ<0 MEANS UNDERFLOW OCCURRED, BUT THE // CONDITION CABS(Z)<=2*SQRT(FNU+1) WAS VIOLATED AND THE // COMPUTATION MUST BE COMPLETED IN ANOTHER ROUTINE WITH N=N-ABS(NZ). func zseriOrig(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL, ELIM, ALIM float64) ( ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout, ELIMout, ALIMout float64) { var AA, ACZ, AK, AK1I, AK1R, ARM, ASCLE, ATOL, AZ, CKI, CKR, COEFI, COEFR, CONEI, CONER, CRSCR, CZI, CZR, DFNU, FNUP, HZI, HZR, RAZ, RS, RTR1, RZI, RZR, S, SS, STI, STR, S1I, S1R, S2I, S2R, ZEROI, ZEROR float64 var I, IB, IDUM, IFLAG, IL, K, L, M, NN, NW int var WR, WI [3]float64 var tmp complex128 CONER = 1.0 NZ = 0 AZ = zabs(complex(ZR, ZI)) if AZ == 0.0e0 { goto OneSixty } // TODO(btracey) // The original fortran line is "ARM = 1.0D+3*D1MACH(1)". Evidently, in Fortran // this is interpreted as one to the power of +3*D1MACH(1). While it is possible // this was intentional, it seems unlikely. //ARM = 1.0E0 + 3*dmach[1] //math.Pow(1, 3*dmach[1]) ARM = 1000 * dmach[1] RTR1 = dsqrt(ARM) CRSCR = 1.0e0 IFLAG = 0 if AZ < ARM { goto OneFifty } HZR = 0.5e0 * ZR HZI = 0.5e0 * ZI CZR = ZEROR CZI = ZEROI if AZ <= RTR1 { goto Ten } tmp = zmlt(complex(HZR, HZI), complex(HZR, HZI)) CZR = real(tmp) CZI = imag(tmp) Ten: ACZ = zabs(complex(CZR, CZI)) NN = N tmp = zlog(complex(HZR, HZI)) CKR = real(tmp) CKI = imag(tmp) Twenty: DFNU = FNU + float64(float32(NN-1)) FNUP = DFNU + 1.0e0 // UNDERFLOW TEST. AK1R = CKR * DFNU AK1I = CKI * DFNU AK = dgamln(FNUP, IDUM) AK1R = AK1R - AK if KODE == 2 { AK1R = AK1R - ZR } if AK1R > (-ELIM) { goto Forty } Thirty: NZ = NZ + 1 YR[NN] = ZEROR YI[NN] = ZEROI if ACZ > DFNU { goto OneNinety } NN = NN - 1 if NN == 0 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } goto Twenty Forty: if AK1R > (-ALIM) { goto Fifty } IFLAG = 1 SS = 1.0e0 / TOL CRSCR = TOL ASCLE = ARM * SS Fifty: AA = dexp(AK1R) if IFLAG == 1 { AA = AA * SS } COEFR = AA * dcos(AK1I) COEFI = AA * dsin(AK1I) ATOL = TOL * ACZ / FNUP IL = min0(2, NN) for I = 1; I <= IL; I++ { DFNU = FNU + float64(float32(NN-I)) FNUP = DFNU + 1.0e0 S1R = CONER S1I = CONEI if ACZ < TOL*FNUP { goto Seventy } AK1R = CONER AK1I = CONEI AK = FNUP + 2.0e0 S = FNUP AA = 2.0e0 Sixty: RS = 1.0e0 / S STR = AK1R*CZR - AK1I*CZI STI = AK1R*CZI + AK1I*CZR AK1R = STR * RS AK1I = STI * RS S1R = S1R + AK1R S1I = S1I + AK1I S = S + AK AK = AK + 2.0e0 AA = AA * ACZ * RS if AA > ATOL { goto Sixty } Seventy: S2R = S1R*COEFR - S1I*COEFI S2I = S1R*COEFI + S1I*COEFR WR[I] = S2R WI[I] = S2I if IFLAG == 0 { goto Eighty } S2R, S2I, NW, ASCLE, TOL = zuchkOrig(S2R, S2I, NW, ASCLE, TOL) if NW != 0 { goto Thirty } Eighty: M = NN - I + 1 YR[M] = S2R * CRSCR YI[M] = S2I * CRSCR if I == IL { continue } tmp = zdiv(complex(COEFR, COEFI), complex(HZR, HZI)) STR = real(tmp) STI = imag(tmp) COEFR = STR * DFNU COEFI = STI * DFNU } if NN <= 2 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } K = NN - 2 AK = float64(float32(K)) RAZ = 1.0e0 / AZ STR = ZR * RAZ STI = -ZI * RAZ RZR = (STR + STR) * RAZ RZI = (STI + STI) * RAZ if IFLAG == 1 { goto OneTwenty } IB = 3 OneHundred: for I = IB; I <= NN; I++ { YR[K] = (AK+FNU)*(RZR*YR[K+1]-RZI*YI[K+1]) + YR[K+2] YI[K] = (AK+FNU)*(RZR*YI[K+1]+RZI*YR[K+1]) + YI[K+2] AK = AK - 1.0e0 K = K - 1 } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM // RECUR BACKWARD WITH SCALED VALUES. OneTwenty: // EXP(-ALIM)=EXP(-ELIM)/TOL=APPROX. ONE PRECISION ABOVE THE // UNDERFLOW LIMIT = ASCLE = dmach[1)*SS*1.0D+3. S1R = WR[1] S1I = WI[1] S2R = WR[2] S2I = WI[2] for L = 3; L <= NN; L++ { CKR = S2R CKI = S2I S2R = S1R + (AK+FNU)*(RZR*CKR-RZI*CKI) S2I = S1I + (AK+FNU)*(RZR*CKI+RZI*CKR) S1R = CKR S1I = CKI CKR = S2R * CRSCR CKI = S2I * CRSCR YR[K] = CKR YI[K] = CKI AK = AK - 1.0e0 K = K - 1 if zabs(complex(CKR, CKI)) > ASCLE { goto OneFourty } } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM OneFourty: IB = L + 1 if IB > NN { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } goto OneHundred OneFifty: NZ = N if FNU == 0.0e0 { NZ = NZ - 1 } OneSixty: YR[1] = ZEROR YI[1] = ZEROI if FNU != 0.0e0 { goto OneSeventy } YR[1] = CONER YI[1] = CONEI OneSeventy: if N == 1 { return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } for I = 2; I <= N; I++ { YR[I] = ZEROR YI[I] = ZEROI } return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM // return WITH NZ<0 if CABS(Z*Z/4)>FNU+N-NZ-1 COMPLETE // THE CALCULATION IN CBINU WITH N=N-IABS(NZ) OneNinety: NZ = -NZ return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM } // ZS1S2 TESTS FOR A POSSIBLE UNDERFLOW RESULTING FROM THE // ADDITION OF THE I AND K FUNCTIONS IN THE ANALYTIC CON- // TINUATION FORMULA WHERE S1=K FUNCTION AND S2=I FUNCTION. // ON KODE=1 THE I AND K FUNCTIONS ARE DIFFERENT ORDERS OF // MAGNITUDE, BUT FOR KODE=2 THEY CAN BE OF THE SAME ORDER // OF MAGNITUDE AND THE MAXIMUM MUST BE AT LEAST ONE // PRECISION ABOVE THE UNDERFLOW LIMIT. func zs1s2Orig(ZRR, ZRI, S1R, S1I, S2R, S2I float64, NZ int, ASCLE, ALIM float64, IUF int) ( ZRRout, ZRIout, S1Rout, S1Iout, S2Rout, S2Iout float64, NZout int, ASCLEout, ALIMout float64, IUFout int) { var AA, ALN, AS1, AS2, C1I, C1R, S1DI, S1DR, ZEROI, ZEROR float64 var tmp complex128 ZEROR = 0 ZEROI = 0 NZ = 0 AS1 = zabs(complex(S1R, S1I)) AS2 = zabs(complex(S2R, S2I)) if S1R == 0.0e0 && S1I == 0.0e0 { goto Ten } if AS1 == 0.0e0 { goto Ten } ALN = -ZRR - ZRR + dlog(AS1) S1DR = S1R S1DI = S1I S1R = ZEROR S1I = ZEROI AS1 = ZEROR if ALN < (-ALIM) { goto Ten } tmp = zlog(complex(S1DR, S1DI)) C1R = real(tmp) C1I = imag(tmp) C1R = C1R - ZRR - ZRR C1I = C1I - ZRI - ZRI tmp = zexp(complex(C1R, C1I)) S1R = real(tmp) S1I = imag(tmp) AS1 = zabs(complex(S1R, S1I)) IUF = IUF + 1 Ten: AA = dmax(AS1, AS2) if AA > ASCLE { return ZRR, ZRI, S1R, S1I, S2R, S2I, NZ, ASCLE, ALIM, IUF } S1R = ZEROR S1I = ZEROI S2R = ZEROR S2I = ZEROI NZ = 1 IUF = 0 return ZRR, ZRI, S1R, S1I, S2R, S2I, NZ, ASCLE, ALIM, IUF } // ZSHCH COMPUTES THE COMPLEX HYPERBOLIC FUNCTIONS CSH=SINH(X+iY) AND // CCH=COSH(X+I*Y), WHERE I**2=-1. // TODO(btracey): use cmplx.Sinh and cmplx.Cosh. func zshchOrig(ZR, ZI, CSHR, CSHI, CCHR, CCHI float64) (ZRout, ZIout, CSHRout, CSHIout, CCHRout, CCHIout float64) { var CH, CN, SH, SN float64 SH = math.Sinh(ZR) CH = math.Cosh(ZR) SN = dsin(ZI) CN = dcos(ZI) CSHR = SH * CN CSHI = CH * SN CCHR = CH * CN CCHI = SH * SN return ZR, ZI, CSHR, CSHI, CCHR, CCHI } func dmax(a, b float64) float64 { return math.Max(a, b) } func dmin(a, b float64) float64 { return math.Min(a, b) } func dabs(a float64) float64 { return math.Abs(a) } func datan(a float64) float64 { return math.Atan(a) } func dtan(a float64) float64 { return math.Tan(a) } func dlog(a float64) float64 { return math.Log(a) } func dsin(a float64) float64 { return math.Sin(a) } func dcos(a float64) float64 { return math.Cos(a) } func dexp(a float64) float64 { return math.Exp(a) } func dsqrt(a float64) float64 { return math.Sqrt(a) } func zmlt(a, b complex128) complex128 { return a * b } func zdiv(a, b complex128) complex128 { return a / b } func zabs(a complex128) float64 { return cmplx.Abs(a) } func zsqrt(a complex128) complex128 { return cmplx.Sqrt(a) } func zexp(a complex128) complex128 { return cmplx.Exp(a) } func zlog(a complex128) complex128 { return cmplx.Log(a) } // Zshch computes the hyperbolic sin and cosine of the input z. func Zshch(z complex128) (sinh, cosh complex128) { return cmplx.Sinh(z), cmplx.Cosh(z) } golang-gonum-v1-gonum-0.14.0/mathext/internal/amos/staticcheck.conf000066400000000000000000000000141450372207100252120ustar00rootroot00000000000000checks = [] golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/000077500000000000000000000000001450372207100223735ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/cephes.go000066400000000000000000000014261450372207100241740ustar00rootroot00000000000000// Copyright ©2016 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 cephes import "math" /* Additional copyright information: Code in this package is adapted from the Cephes library (http://www.netlib.org/cephes/). There is no explicit licence on Netlib, but the author has agreed to a BSD release. See https://github.com/deepmind/torch-cephes/blob/master/LICENSE.txt and https://lists.debian.org/debian-legal/2004/12/msg00295.html */ const ( paramOutOfBounds = "cephes: parameter out of bounds" errParamFunctionSingularity = "cephes: function singularity" ) const ( machEp = 1.0 / (1 << 53) maxLog = 1024 * math.Ln2 minLog = -1075 * math.Ln2 maxIter = 2000 ) golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/doc.go000066400000000000000000000005031450372207100234650ustar00rootroot00000000000000// 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 cephes implements functions originally in the Netlib code by Stephen Mosher. package cephes // import "gonum.org/v1/gonum/mathext/internal/cephes" golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/igam.go000066400000000000000000000512241450372207100236430ustar00rootroot00000000000000// Derived from SciPy's special/cephes/igam.c and special/cephes/igam.h // https://github.com/scipy/scipy/blob/master/scipy/special/cephes/igam.c // https://github.com/scipy/scipy/blob/master/scipy/special/cephes/igam.h // Made freely available by Stephen L. Moshier without support or guarantee. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©1985, ©1987 by Stephen L. Moshier // Portions Copyright ©2016 The Gonum Authors. All rights reserved. package cephes import "math" const ( igamDimK = 25 igamDimN = 25 igam = 1 igamC = 0 igamSmall = 20 igamLarge = 200 igamSmallRatio = 0.3 igamLargeRatio = 4.5 ) var igamCoefs = [igamDimK][igamDimN]float64{ {-3.3333333333333333e-1, 8.3333333333333333e-2, -1.4814814814814815e-2, 1.1574074074074074e-3, 3.527336860670194e-4, -1.7875514403292181e-4, 3.9192631785224378e-5, -2.1854485106799922e-6, -1.85406221071516e-6, 8.296711340953086e-7, -1.7665952736826079e-7, 6.7078535434014986e-9, 1.0261809784240308e-8, -4.3820360184533532e-9, 9.1476995822367902e-10, -2.551419399494625e-11, -5.8307721325504251e-11, 2.4361948020667416e-11, -5.0276692801141756e-12, 1.1004392031956135e-13, 3.3717632624009854e-13, -1.3923887224181621e-13, 2.8534893807047443e-14, -5.1391118342425726e-16, -1.9752288294349443e-15}, {-1.8518518518518519e-3, -3.4722222222222222e-3, 2.6455026455026455e-3, -9.9022633744855967e-4, 2.0576131687242798e-4, -4.0187757201646091e-7, -1.8098550334489978e-5, 7.6491609160811101e-6, -1.6120900894563446e-6, 4.6471278028074343e-9, 1.378633446915721e-7, -5.752545603517705e-8, 1.1951628599778147e-8, -1.7543241719747648e-11, -1.0091543710600413e-9, 4.1627929918425826e-10, -8.5639070264929806e-11, 6.0672151016047586e-14, 7.1624989648114854e-12, -2.9331866437714371e-12, 5.9966963656836887e-13, -2.1671786527323314e-16, -4.9783399723692616e-14, 2.0291628823713425e-14, -4.13125571381061e-15}, {4.1335978835978836e-3, -2.6813271604938272e-3, 7.7160493827160494e-4, 2.0093878600823045e-6, -1.0736653226365161e-4, 5.2923448829120125e-5, -1.2760635188618728e-5, 3.4235787340961381e-8, 1.3721957309062933e-6, -6.298992138380055e-7, 1.4280614206064242e-7, -2.0477098421990866e-10, -1.4092529910867521e-8, 6.228974084922022e-9, -1.3670488396617113e-9, 9.4283561590146782e-13, 1.2872252400089318e-10, -5.5645956134363321e-11, 1.1975935546366981e-11, -4.1689782251838635e-15, -1.0940640427884594e-12, 4.6622399463901357e-13, -9.905105763906906e-14, 1.8931876768373515e-17, 8.8592218725911273e-15}, {6.4943415637860082e-4, 2.2947209362139918e-4, -4.6918949439525571e-4, 2.6772063206283885e-4, -7.5618016718839764e-5, -2.3965051138672967e-7, 1.1082654115347302e-5, -5.6749528269915966e-6, 1.4230900732435884e-6, -2.7861080291528142e-11, -1.6958404091930277e-7, 8.0994649053880824e-8, -1.9111168485973654e-8, 2.3928620439808118e-12, 2.0620131815488798e-9, -9.4604966618551322e-10, 2.1541049775774908e-10, -1.388823336813903e-14, -2.1894761681963939e-11, 9.7909989511716851e-12, -2.1782191880180962e-12, 6.2088195734079014e-17, 2.126978363279737e-13, -9.3446887915174333e-14, 2.0453671226782849e-14}, {-8.618882909167117e-4, 7.8403922172006663e-4, -2.9907248030319018e-4, -1.4638452578843418e-6, 6.6414982154651222e-5, -3.9683650471794347e-5, 1.1375726970678419e-5, 2.5074972262375328e-10, -1.6954149536558306e-6, 8.9075075322053097e-7, -2.2929348340008049e-7, 2.956794137544049e-11, 2.8865829742708784e-8, -1.4189739437803219e-8, 3.4463580499464897e-9, -2.3024517174528067e-13, -3.9409233028046405e-10, 1.8602338968504502e-10, -4.356323005056618e-11, 1.2786001016296231e-15, 4.6792750266579195e-12, -2.1492464706134829e-12, 4.9088156148096522e-13, -6.3385914848915603e-18, -5.0453320690800944e-14}, {-3.3679855336635815e-4, -6.9728137583658578e-5, 2.7727532449593921e-4, -1.9932570516188848e-4, 6.7977804779372078e-5, 1.419062920643967e-7, -1.3594048189768693e-5, 8.0184702563342015e-6, -2.2914811765080952e-6, -3.252473551298454e-10, 3.4652846491085265e-7, -1.8447187191171343e-7, 4.8240967037894181e-8, -1.7989466721743515e-14, -6.3061945000135234e-9, 3.1624176287745679e-9, -7.8409242536974293e-10, 5.1926791652540407e-15, 9.3589442423067836e-11, -4.5134262161632782e-11, 1.0799129993116827e-11, -3.661886712685252e-17, -1.210902069055155e-12, 5.6807435849905643e-13, -1.3249659916340829e-13}, {5.3130793646399222e-4, -5.9216643735369388e-4, 2.7087820967180448e-4, 7.9023532326603279e-7, -8.1539693675619688e-5, 5.6116827531062497e-5, -1.8329116582843376e-5, -3.0796134506033048e-9, 3.4651553688036091e-6, -2.0291327396058604e-6, 5.7887928631490037e-7, 2.338630673826657e-13, -8.8286007463304835e-8, 4.7435958880408128e-8, -1.2545415020710382e-8, 8.6496488580102925e-14, 1.6846058979264063e-9, -8.5754928235775947e-10, 2.1598224929232125e-10, -7.6132305204761539e-16, -2.6639822008536144e-11, 1.3065700536611057e-11, -3.1799163902367977e-12, 4.7109761213674315e-18, 3.6902800842763467e-13}, {3.4436760689237767e-4, 5.1717909082605922e-5, -3.3493161081142236e-4, 2.812695154763237e-4, -1.0976582244684731e-4, -1.2741009095484485e-7, 2.7744451511563644e-5, -1.8263488805711333e-5, 5.7876949497350524e-6, 4.9387589339362704e-10, -1.0595367014026043e-6, 6.1667143761104075e-7, -1.7562973359060462e-7, -1.2974473287015439e-12, 2.695423606288966e-8, -1.4578352908731271e-8, 3.887645959386175e-9, -3.8810022510194121e-17, -5.3279941738772867e-10, 2.7437977643314845e-10, -6.9957960920705679e-11, 2.5899863874868481e-17, 8.8566890996696381e-12, -4.403168815871311e-12, 1.0865561947091654e-12}, {-6.5262391859530942e-4, 8.3949872067208728e-4, -4.3829709854172101e-4, -6.969091458420552e-7, 1.6644846642067548e-4, -1.2783517679769219e-4, 4.6299532636913043e-5, 4.5579098679227077e-9, -1.0595271125805195e-5, 6.7833429048651666e-6, -2.1075476666258804e-6, -1.7213731432817145e-11, 3.7735877416110979e-7, -2.1867506700122867e-7, 6.2202288040189269e-8, 6.5977038267330006e-16, -9.5903864974256858e-9, 5.2132144922808078e-9, -1.3991589583935709e-9, 5.382058999060575e-16, 1.9484714275467745e-10, -1.0127287556389682e-10, 2.6077347197254926e-11, -5.0904186999932993e-18, -3.3721464474854592e-12}, {-5.9676129019274625e-4, -7.2048954160200106e-5, 6.7823088376673284e-4, -6.4014752602627585e-4, 2.7750107634328704e-4, 1.8197008380465151e-7, -8.4795071170685032e-5, 6.105192082501531e-5, -2.1073920183404862e-5, -8.8585890141255994e-10, 4.5284535953805377e-6, -2.8427815022504408e-6, 8.7082341778646412e-7, 3.6886101871706965e-12, -1.5344695190702061e-7, 8.862466778790695e-8, -2.5184812301826817e-8, -1.0225912098215092e-14, 3.8969470758154777e-9, -2.1267304792235635e-9, 5.7370135528051385e-10, -1.887749850169741e-19, -8.0931538694657866e-11, 4.2382723283449199e-11, -1.1002224534207726e-11}, {1.3324454494800656e-3, -1.9144384985654775e-3, 1.1089369134596637e-3, 9.932404122642299e-7, -5.0874501293093199e-4, 4.2735056665392884e-4, -1.6858853767910799e-4, -8.1301893922784998e-9, 4.5284402370562147e-5, -3.127053674781734e-5, 1.044986828530338e-5, 4.8435226265680926e-11, -2.1482565873456258e-6, 1.329369701097492e-6, -4.0295693092101029e-7, -1.7567877666323291e-13, 7.0145043163668257e-8, -4.040787734999483e-8, 1.1474026743371963e-8, 3.9642746853563325e-18, -1.7804938269892714e-9, 9.7480262548731646e-10, -2.6405338676507616e-10, 5.794875163403742e-18, 3.7647749553543836e-11}, {1.579727660730835e-3, 1.6251626278391582e-4, -2.0633421035543276e-3, 2.1389686185689098e-3, -1.0108559391263003e-3, -3.9912705529919201e-7, 3.6235025084764691e-4, -2.8143901463712154e-4, 1.0449513336495887e-4, 2.1211418491830297e-9, -2.5779417251947842e-5, 1.7281818956040463e-5, -5.6413773872904282e-6, -1.1024320105776174e-11, 1.1223224418895175e-6, -6.8693396379526735e-7, 2.0653236975414887e-7, 4.6714772409838506e-14, -3.5609886164949055e-8, 2.0470855345905963e-8, -5.8091738633283358e-9, -1.332821287582869e-16, 9.0354604391335133e-10, -4.9598782517330834e-10, 1.3481607129399749e-10}, {-4.0725121195140166e-3, 6.4033628338080698e-3, -4.0410161081676618e-3, -2.183732802866233e-6, 2.1740441801254639e-3, -1.9700440518418892e-3, 8.3595469747962458e-4, 1.9445447567109655e-8, -2.5779387120421696e-4, 1.9009987368139304e-4, -6.7696499937438965e-5, -1.4440629666426572e-10, 1.5712512518742269e-5, -1.0304008744776893e-5, 3.304517767401387e-6, 7.9829760242325709e-13, -6.4097794149313004e-7, 3.8894624761300056e-7, -1.1618347644948869e-7, -2.816808630596451e-15, 1.9878012911297093e-8, -1.1407719956357511e-8, 3.2355857064185555e-9, 4.1759468293455945e-20, -5.0423112718105824e-10}, {-5.9475779383993003e-3, -5.4016476789260452e-4, 8.7910413550767898e-3, -9.8576315587856125e-3, 5.0134695031021538e-3, 1.2807521786221875e-6, -2.0626019342754683e-3, 1.7109128573523058e-3, -6.7695312714133799e-4, -6.9011545676562133e-9, 1.8855128143995902e-4, -1.3395215663491969e-4, 4.6263183033528039e-5, 4.0034230613321351e-11, -1.0255652921494033e-5, 6.612086372797651e-6, -2.0913022027253008e-6, -2.0951775649603837e-13, 3.9756029041993247e-7, -2.3956211978815887e-7, 7.1182883382145864e-8, 8.925574873053455e-16, -1.2101547235064676e-8, 6.9350618248334386e-9, -1.9661464453856102e-9}, {1.7402027787522711e-2, -2.9527880945699121e-2, 2.0045875571402799e-2, 7.0289515966903407e-6, -1.2375421071343148e-2, 1.1976293444235254e-2, -5.4156038466518525e-3, -6.3290893396418616e-8, 1.8855118129005065e-3, -1.473473274825001e-3, 5.5515810097708387e-4, 5.2406834412550662e-10, -1.4357913535784836e-4, 9.9181293224943297e-5, -3.3460834749478311e-5, -3.5755837291098993e-12, 7.1560851960630076e-6, -4.5516802628155526e-6, 1.4236576649271475e-6, 1.8803149082089664e-14, -2.6623403898929211e-7, 1.5950642189595716e-7, -4.7187514673841102e-8, -6.5107872958755177e-17, 7.9795091026746235e-9}, {3.0249124160905891e-2, 2.4817436002649977e-3, -4.9939134373457022e-2, 5.9915643009307869e-2, -3.2483207601623391e-2, -5.7212968652103441e-6, 1.5085251778569354e-2, -1.3261324005088445e-2, 5.5515262632426148e-3, 3.0263182257030016e-8, -1.7229548406756723e-3, 1.2893570099929637e-3, -4.6845138348319876e-4, -1.830259937893045e-10, 1.1449739014822654e-4, -7.7378565221244477e-5, 2.5625836246985201e-5, 1.0766165333192814e-12, -5.3246809282422621e-6, 3.349634863064464e-6, -1.0381253128684018e-6, -5.608909920621128e-15, 1.9150821930676591e-7, -1.1418365800203486e-7, 3.3654425209171788e-8}, {-9.9051020880159045e-2, 1.7954011706123486e-1, -1.2989606383463778e-1, -3.1478872752284357e-5, 9.0510635276848131e-2, -9.2828824411184397e-2, 4.4412112839877808e-2, 2.7779236316835888e-7, -1.7229543805449697e-2, 1.4182925050891573e-2, -5.6214161633747336e-3, -2.39598509186381e-9, 1.6029634366079908e-3, -1.1606784674435773e-3, 4.1001337768153873e-4, 1.8365800754090661e-11, -9.5844256563655903e-5, 6.3643062337764708e-5, -2.076250624489065e-5, -1.1806020912804483e-13, 4.2131808239120649e-6, -2.6262241337012467e-6, 8.0770620494930662e-7, 6.0125912123632725e-16, -1.4729737374018841e-7}, {-1.9994542198219728e-1, -1.5056113040026424e-2, 3.6470239469348489e-1, -4.6435192311733545e-1, 2.6640934719197893e-1, 3.4038266027147191e-5, -1.3784338709329624e-1, 1.276467178337056e-1, -5.6213828755200985e-2, -1.753150885483011e-7, 1.9235592956768113e-2, -1.5088821281095315e-2, 5.7401854451350123e-3, 1.0622382710310225e-9, -1.5335082692563998e-3, 1.0819320643228214e-3, -3.7372510193945659e-4, -6.6170909729031985e-12, 8.4263617380909628e-5, -5.5150706827483479e-5, 1.7769536448348069e-5, 3.8827923210205533e-14, -3.53513697488768e-6, 2.1865832130045269e-6, -6.6812849447625594e-7}, {7.2438608504029431e-1, -1.3918010932653375, 1.0654143352413968, 1.876173868950258e-4, -8.2705501176152696e-1, 8.9352433347828414e-1, -4.4971003995291339e-1, -1.6107401567546652e-6, 1.9235590165271091e-1, -1.6597702160042609e-1, 6.8882222681814333e-2, 1.3910091724608687e-8, -2.146911561508663e-2, 1.6228980898865892e-2, -5.9796016172584256e-3, -1.1287469112826745e-10, 1.5167451119784857e-3, -1.0478634293553899e-3, 3.5539072889126421e-4, 8.1704322111801517e-13, -7.7773013442452395e-5, 5.0291413897007722e-5, -1.6035083867000518e-5, 1.2469354315487605e-14, 3.1369106244517615e-6}, {1.6668949727276811, 1.165462765994632e-1, -3.3288393225018906, 4.4692325482864037, -2.6977693045875807, -2.600667859891061e-4, 1.5389017615694539, -1.4937962361134612, 6.8881964633233148e-1, 1.3077482004552385e-6, -2.5762963325596288e-1, 2.1097676102125449e-1, -8.3714408359219882e-2, -7.7920428881354753e-9, 2.4267923064833599e-2, -1.7813678334552311e-2, 6.3970330388900056e-3, 4.9430807090480523e-11, -1.5554602758465635e-3, 1.0561196919903214e-3, -3.5277184460472902e-4, 9.3002334645022459e-14, 7.5285855026557172e-5, -4.8186515569156351e-5, 1.5227271505597605e-5}, {-6.6188298861372935, 1.3397985455142589e+1, -1.0789350606845146e+1, -1.4352254537875018e-3, 9.2333694596189809, -1.0456552819547769e+1, 5.5105526029033471, 1.2024439690716742e-5, -2.5762961164755816, 2.3207442745387179, -1.0045728797216284, -1.0207833290021914e-7, 3.3975092171169466e-1, -2.6720517450757468e-1, 1.0235252851562706e-1, 8.4329730484871625e-10, -2.7998284958442595e-2, 2.0066274144976813e-2, -7.0554368915086242e-3, 1.9402238183698188e-12, 1.6562888105449611e-3, -1.1082898580743683e-3, 3.654545161310169e-4, -5.1290032026971794e-11, -7.6340103696869031e-5}, {-1.7112706061976095e+1, -1.1208044642899116, 3.7131966511885444e+1, -5.2298271025348962e+1, 3.3058589696624618e+1, 2.4791298976200222e-3, -2.061089403411526e+1, 2.088672775145582e+1, -1.0045703956517752e+1, -1.2238783449063012e-5, 4.0770134274221141, -3.473667358470195, 1.4329352617312006, 7.1359914411879712e-8, -4.4797257159115612e-1, 3.4112666080644461e-1, -1.2699786326594923e-1, -2.8953677269081528e-10, 3.3125776278259863e-2, -2.3274087021036101e-2, 8.0399993503648882e-3, -1.177805216235265e-9, -1.8321624891071668e-3, 1.2108282933588665e-3, -3.9479941246822517e-4}, {7.389033153567425e+1, -1.5680141270402273e+2, 1.322177542759164e+2, 1.3692876877324546e-2, -1.2366496885920151e+2, 1.4620689391062729e+2, -8.0365587724865346e+1, -1.1259851148881298e-4, 4.0770132196179938e+1, -3.8210340013273034e+1, 1.719522294277362e+1, 9.3519707955168356e-7, -6.2716159907747034, 5.1168999071852637, -2.0319658112299095, -4.9507215582761543e-9, 5.9626397294332597e-1, -4.4220765337238094e-1, 1.6079998700166273e-1, -2.4733786203223402e-8, -4.0307574759979762e-2, 2.7849050747097869e-2, -9.4751858992054221e-3, 6.419922235909132e-6, 2.1250180774699461e-3}, {2.1216837098382522e+2, 1.3107863022633868e+1, -4.9698285932871748e+2, 7.3121595266969204e+2, -4.8213821720890847e+2, -2.8817248692894889e-2, 3.2616720302947102e+2, -3.4389340280087117e+2, 1.7195193870816232e+2, 1.4038077378096158e-4, -7.52594195897599e+1, 6.651969984520934e+1, -2.8447519748152462e+1, -7.613702615875391e-7, 9.5402237105304373, -7.5175301113311376, 2.8943997568871961, -4.6612194999538201e-7, -8.0615149598794088e-1, 5.8483006570631029e-1, -2.0845408972964956e-1, 1.4765818959305817e-4, 5.1000433863753019e-2, -3.3066252141883665e-2, 1.5109265210467774e-2}, {-9.8959643098322368e+2, 2.1925555360905233e+3, -1.9283586782723356e+3, -1.5925738122215253e-1, 1.9569985945919857e+3, -2.4072514765081556e+3, 1.3756149959336496e+3, 1.2920735237496668e-3, -7.525941715948055e+2, 7.3171668742208716e+2, -3.4137023466220065e+2, -9.9857390260608043e-6, 1.3356313181291573e+2, -1.1276295161252794e+2, 4.6310396098204458e+1, -7.9237387133614756e-6, -1.4510726927018646e+1, 1.1111771248100563e+1, -4.1690817945270892, 3.1008219800117808e-3, 1.1220095449981468, -7.6052379926149916e-1, 3.6262236505085254e-1, 2.216867741940747e-1, 4.8683443692930507e-1}, } // Igam computes the incomplete Gamma integral. // // Igam(a,x) = (1/ Γ(a)) \int_0^x e^{-t} t^{a-1} dt // // The input argument a must be positive and x must be non-negative or Igam // will panic. func Igam(a, x float64) float64 { // The integral is evaluated by either a power series or continued fraction // expansion, depending on the relative values of a and x. // Sources: // [1] "The Digital Library of Mathematical Functions", dlmf.nist.gov // [2] Maddock et. al., "Incomplete Gamma Functions", // http://www.boost.org/doc/libs/1_61_0/libs/math/doc/html/math_toolkit/sf_gamma/igamma.html // Check zero integration limit first if x == 0 { return 0 } if x < 0 || a <= 0 { panic(paramOutOfBounds) } // Asymptotic regime where a ~ x; see [2]. absxmaA := math.Abs(x-a) / a if (igamSmall < a && a < igamLarge && absxmaA < igamSmallRatio) || (igamLarge < a && absxmaA < igamLargeRatio/math.Sqrt(a)) { return asymptoticSeries(a, x, igam) } if x > 1 && x > a { return 1 - IgamC(a, x) } return igamSeries(a, x) } // IgamC computes the complemented incomplete Gamma integral. // // IgamC(a,x) = 1 - Igam(a,x) // = (1/ Γ(a)) \int_0^\infty e^{-t} t^{a-1} dt // // The input argument a must be positive and x must be non-negative or // IgamC will panic. func IgamC(a, x float64) float64 { // The integral is evaluated by either a power series or continued fraction // expansion, depending on the relative values of a and x. // Sources: // [1] "The Digital Library of Mathematical Functions", dlmf.nist.gov // [2] Maddock et. al., "Incomplete Gamma Functions", // http://www.boost.org/doc/libs/1_61_0/libs/math/doc/html/math_toolkit/sf_gamma/igamma.html switch { case x < 0, a <= 0: panic(paramOutOfBounds) case x == 0: return 1 case math.IsInf(x, 0): return 0 } // Asymptotic regime where a ~ x; see [2]. absxmaA := math.Abs(x-a) / a if (igamSmall < a && a < igamLarge && absxmaA < igamSmallRatio) || (igamLarge < a && absxmaA < igamLargeRatio/math.Sqrt(a)) { return asymptoticSeries(a, x, igamC) } // Everywhere else; see [2]. if x > 1.1 { if x < a { return 1 - igamSeries(a, x) } return igamCContinuedFraction(a, x) } else if x <= 0.5 { if -0.4/math.Log(x) < a { return 1 - igamSeries(a, x) } return igamCSeries(a, x) } if x*1.1 < a { return 1 - igamSeries(a, x) } return igamCSeries(a, x) } // igamFac computes // // x^a * e^{-x} / Γ(a) // // corrected from (15) and (16) in [2] by replacing // // e^{x - a} // // with // // e^{a - x} func igamFac(a, x float64) float64 { if math.Abs(a-x) > 0.4*math.Abs(a) { ax := a*math.Log(x) - x - lgam(a) return math.Exp(ax) } fac := a + lanczosG - 0.5 res := math.Sqrt(fac/math.Exp(1)) / lanczosSumExpgScaled(a) if a < 200 && x < 200 { res *= math.Exp(a-x) * math.Pow(x/fac, a) } else { num := x - a - lanczosG + 0.5 res *= math.Exp(a*log1pmx(num/fac) + x*(0.5-lanczosG)/fac) } return res } // igamCContinuedFraction computes IgamC using DLMF 8.9.2. func igamCContinuedFraction(a, x float64) float64 { ax := igamFac(a, x) if ax == 0 { return 0 } // Continued fraction y := 1 - a z := x + y + 1 c := 0.0 pkm2 := 1.0 qkm2 := x pkm1 := x + 1.0 qkm1 := z * x ans := pkm1 / qkm1 for i := 0; i < maxIter; i++ { c += 1.0 y += 1.0 z += 2.0 yc := y * c pk := pkm1*z - pkm2*yc qk := qkm1*z - qkm2*yc var t float64 if qk != 0 { r := pk / qk t = math.Abs((ans - r) / r) ans = r } else { t = 1.0 } pkm2 = pkm1 pkm1 = pk qkm2 = qkm1 qkm1 = qk if math.Abs(pk) > big { pkm2 *= biginv pkm1 *= biginv qkm2 *= biginv qkm1 *= biginv } if t <= machEp { break } } return ans * ax } // igamSeries computes Igam using DLMF 8.11.4. func igamSeries(a, x float64) float64 { ax := igamFac(a, x) if ax == 0 { return 0 } // Power series r := a c := 1.0 ans := 1.0 for i := 0; i < maxIter; i++ { r += 1.0 c *= x / r ans += c if c <= machEp*ans { break } } return ans * ax / a } // igamCSeries computes IgamC using DLMF 8.7.3. This is related to the series // in igamSeries but extra care is taken to avoid cancellation. func igamCSeries(a, x float64) float64 { fac := 1.0 sum := 0.0 for n := 1; n < maxIter; n++ { fac *= -x / float64(n) term := fac / (a + float64(n)) sum += term if math.Abs(term) <= machEp*math.Abs(sum) { break } } logx := math.Log(x) term := -expm1(a*logx - lgam1p(a)) return term - math.Exp(a*logx-lgam(a))*sum } // asymptoticSeries computes Igam/IgamC using DLMF 8.12.3/8.12.4. func asymptoticSeries(a, x float64, fun int) float64 { maxpow := 0 lambda := x / a sigma := (x - a) / a absoldterm := math.MaxFloat64 etapow := [igamDimN]float64{1} sum := 0.0 afac := 1.0 var sgn float64 if fun == igam { sgn = -1 } else { sgn = 1 } var eta float64 if lambda > 1 { eta = math.Sqrt(-2 * log1pmx(sigma)) } else if lambda < 1 { eta = -math.Sqrt(-2 * log1pmx(sigma)) } else { eta = 0 } res := 0.5 * math.Erfc(sgn*eta*math.Sqrt(a/2)) for k := 0; k < igamDimK; k++ { ck := igamCoefs[k][0] for n := 1; n < igamDimN; n++ { if n > maxpow { etapow[n] = eta * etapow[n-1] maxpow++ } ckterm := igamCoefs[k][n] * etapow[n] ck += ckterm if math.Abs(ckterm) < machEp*math.Abs(ck) { break } } term := ck * afac absterm := math.Abs(term) if absterm > absoldterm { break } sum += term if absterm < machEp*math.Abs(sum) { break } absoldterm = absterm afac /= a } res += sgn * math.Exp(-0.5*a*eta*eta) * sum / math.Sqrt(2*math.Pi*a) return res } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/igami.go000066400000000000000000000051571450372207100240200ustar00rootroot00000000000000// Derived from SciPy's special/cephes/igami.c // https://github.com/scipy/scipy/blob/master/scipy/special/cephes/igami.c // Made freely available by Stephen L. Moshier without support or guarantee. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©1984, ©1987, ©1995 by Stephen L. Moshier // Portions Copyright ©2017 The Gonum Authors. All rights reserved. package cephes import "math" // IgamI computes the inverse of the incomplete Gamma function. That is, it // returns the x such that: // // IgamC(a, x) = p // // The input argument a must be positive and p must be between 0 and 1 // inclusive or IgamI will panic. IgamI should return a positive number, but // can return 0 even with non-zero y due to underflow. func IgamI(a, p float64) float64 { // Bound the solution x0 := math.MaxFloat64 yl := 0.0 x1 := 0.0 yh := 1.0 dithresh := 5.0 * machEp if p < 0 || p > 1 || a <= 0 { panic(paramOutOfBounds) } if p == 0 { return math.Inf(1) } if p == 1 { return 0.0 } // Starting with the approximate value // x = a y^3 // where // y = 1 - d - ndtri(p) sqrt(d) // and // d = 1/9a // the routine performs up to 10 Newton iterations to find the root of // IgamC(a, x) - p = 0 d := 1.0 / (9.0 * a) y := 1.0 - d - Ndtri(p)*math.Sqrt(d) x := a * y * y * y lgm := lgam(a) for i := 0; i < 10; i++ { if x > x0 || x < x1 { break } y = IgamC(a, x) if y < yl || y > yh { break } if y < p { x0 = x yl = y } else { x1 = x yh = y } // Compute the derivative of the function at this point d = (a-1)*math.Log(x) - x - lgm if d < -maxLog { break } d = -math.Exp(d) // Compute the step to the next approximation of x d = (y - p) / d if math.Abs(d/x) < machEp { return x } x = x - d } d = 0.0625 if x0 == math.MaxFloat64 { if x <= 0 { x = 1 } for x0 == math.MaxFloat64 { x = (1 + d) * x y = IgamC(a, x) if y < p { x0 = x yl = y break } d = d + d } } d = 0.5 dir := 0 for i := 0; i < 400; i++ { x = x1 + d*(x0-x1) y = IgamC(a, x) lgm = (x0 - x1) / (x1 + x0) if math.Abs(lgm) < dithresh { break } lgm = (y - p) / p if math.Abs(lgm) < dithresh { break } if x <= 0 { break } if y >= p { x1 = x yh = y if dir < 0 { dir = 0 d = 0.5 } else if dir > 1 { d = 0.5*d + 0.5 } else { d = (p - yl) / (yh - yl) } dir++ } else { x0 = x yl = y if dir > 0 { dir = 0 d = 0.5 } else if dir < -1 { d = 0.5 * d } else { d = (p - yl) / (yh - yl) } dir-- } } return x } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/incbeta.go000066400000000000000000000120341450372207100243270ustar00rootroot00000000000000// Copyright ©2016 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. /* * Cephes Math Library, Release 2.3: March, 1995 * Copyright 1984, 1995 by Stephen L. Moshier */ package cephes import ( "math" "gonum.org/v1/gonum/mathext/internal/gonum" ) const ( maxGam = 171.624376956302725 big = 4.503599627370496e15 biginv = 2.22044604925031308085e-16 ) // Incbet computes the regularized incomplete beta function. func Incbet(aa, bb, xx float64) float64 { if aa <= 0 || bb <= 0 { panic(paramOutOfBounds) } if xx <= 0 || xx >= 1 { if xx == 0 { return 0 } if xx == 1 { return 1 } panic(paramOutOfBounds) } var flag int if bb*xx <= 1 && xx <= 0.95 { t := pseries(aa, bb, xx) return transformT(t, flag) } w := 1 - xx // Reverse a and b if x is greater than the mean. var a, b, xc, x float64 if xx > aa/(aa+bb) { flag = 1 a = bb b = aa xc = xx x = w } else { a = aa b = bb xc = w x = xx } if flag == 1 && (b*x) <= 1.0 && x <= 0.95 { t := pseries(a, b, x) return transformT(t, flag) } // Choose expansion for better convergence. y := x*(a+b-2.0) - (a - 1.0) if y < 0.0 { w = incbcf(a, b, x) } else { w = incbd(a, b, x) / xc } // Multiply w by the factor // x^a * (1-x)^b * Γ(a+b) / (a*Γ(a)*Γ(b)) var t float64 y = a * math.Log(x) t = b * math.Log(xc) if (a+b) < maxGam && math.Abs(y) < maxLog && math.Abs(t) < maxLog { t = math.Pow(xc, b) t *= math.Pow(x, a) t /= a t *= w t *= 1.0 / gonum.Beta(a, b) return transformT(t, flag) } // Resort to logarithms. y += t - gonum.Lbeta(a, b) y += math.Log(w / a) if y < minLog { t = 0.0 } else { t = math.Exp(y) } return transformT(t, flag) } func transformT(t float64, flag int) float64 { if flag == 1 { if t <= machEp { t = 1.0 - machEp } else { t = 1.0 - t } } return t } // incbcf returns the incomplete beta integral evaluated by a continued fraction // expansion. func incbcf(a, b, x float64) float64 { var xk, pk, pkm1, pkm2, qk, qkm1, qkm2 float64 var k1, k2, k3, k4, k5, k6, k7, k8 float64 var r, t, ans, thresh float64 var n int k1 = a k2 = a + b k3 = a k4 = a + 1.0 k5 = 1.0 k6 = b - 1.0 k7 = k4 k8 = a + 2.0 pkm2 = 0.0 qkm2 = 1.0 pkm1 = 1.0 qkm1 = 1.0 ans = 1.0 r = 1.0 thresh = 3.0 * machEp for n = 0; n <= 300; n++ { xk = -(x * k1 * k2) / (k3 * k4) pk = pkm1 + pkm2*xk qk = qkm1 + qkm2*xk pkm2 = pkm1 pkm1 = pk qkm2 = qkm1 qkm1 = qk xk = (x * k5 * k6) / (k7 * k8) pk = pkm1 + pkm2*xk qk = qkm1 + qkm2*xk pkm2 = pkm1 pkm1 = pk qkm2 = qkm1 qkm1 = qk if qk != 0 { r = pk / qk } if r != 0 { t = math.Abs((ans - r) / r) ans = r } else { t = 1.0 } if t < thresh { return ans } k1 += 1.0 k2 += 1.0 k3 += 2.0 k4 += 2.0 k5 += 1.0 k6 -= 1.0 k7 += 2.0 k8 += 2.0 if (math.Abs(qk) + math.Abs(pk)) > big { pkm2 *= biginv pkm1 *= biginv qkm2 *= biginv qkm1 *= biginv } if (math.Abs(qk) < biginv) || (math.Abs(pk) < biginv) { pkm2 *= big pkm1 *= big qkm2 *= big qkm1 *= big } } return ans } // incbd returns the incomplete beta integral evaluated by a continued fraction // expansion. func incbd(a, b, x float64) float64 { var xk, pk, pkm1, pkm2, qk, qkm1, qkm2 float64 var k1, k2, k3, k4, k5, k6, k7, k8 float64 var r, t, ans, z, thresh float64 var n int k1 = a k2 = b - 1.0 k3 = a k4 = a + 1.0 k5 = 1.0 k6 = a + b k7 = a + 1.0 k8 = a + 2.0 pkm2 = 0.0 qkm2 = 1.0 pkm1 = 1.0 qkm1 = 1.0 z = x / (1.0 - x) ans = 1.0 r = 1.0 thresh = 3.0 * machEp for n = 0; n <= 300; n++ { xk = -(z * k1 * k2) / (k3 * k4) pk = pkm1 + pkm2*xk qk = qkm1 + qkm2*xk pkm2 = pkm1 pkm1 = pk qkm2 = qkm1 qkm1 = qk xk = (z * k5 * k6) / (k7 * k8) pk = pkm1 + pkm2*xk qk = qkm1 + qkm2*xk pkm2 = pkm1 pkm1 = pk qkm2 = qkm1 qkm1 = qk if qk != 0 { r = pk / qk } if r != 0 { t = math.Abs((ans - r) / r) ans = r } else { t = 1.0 } if t < thresh { return ans } k1 += 1.0 k2 -= 1.0 k3 += 2.0 k4 += 2.0 k5 += 1.0 k6 += 1.0 k7 += 2.0 k8 += 2.0 if (math.Abs(qk) + math.Abs(pk)) > big { pkm2 *= biginv pkm1 *= biginv qkm2 *= biginv qkm1 *= biginv } if (math.Abs(qk) < biginv) || (math.Abs(pk) < biginv) { pkm2 *= big pkm1 *= big qkm2 *= big qkm1 *= big } } return ans } // pseries returns the incomplete beta integral evaluated by a power series. Use // when b*x is small and x not too close to 1. func pseries(a, b, x float64) float64 { var s, t, u, v, n, t1, z, ai float64 ai = 1.0 / a u = (1.0 - b) * x v = u / (a + 1.0) t1 = v t = u n = 2.0 s = 0.0 z = machEp * ai for math.Abs(v) > z { u = (n - b) * x / n t *= u v = t / (a + n) s += v n += 1.0 } s += t1 s += ai u = a * math.Log(x) if (a+b) < maxGam && math.Abs(u) < maxLog { t = 1.0 / gonum.Beta(a, b) s = s * t * math.Pow(x, a) } else { t = -gonum.Lbeta(a, b) + u + math.Log(s) if t < minLog { s = 0.0 } else { s = math.Exp(t) } } return (s) } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/incbi.go000066400000000000000000000076541450372207100240220ustar00rootroot00000000000000// Copyright ©2016 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. /* * Cephes Math Library Release 2.4: March,1996 * Copyright 1984, 1996 by Stephen L. Moshier */ package cephes import "math" // Incbi computes the inverse of the regularized incomplete beta integral. func Incbi(aa, bb, yy0 float64) float64 { var a, b, y0, d, y, x, x0, x1, lgm, yp, di, dithresh, yl, yh, xt float64 var i, rflg, dir, nflg int if yy0 <= 0 { return (0.0) } if yy0 >= 1.0 { return (1.0) } x0 = 0.0 yl = 0.0 x1 = 1.0 yh = 1.0 nflg = 0 if aa <= 1.0 || bb <= 1.0 { dithresh = 1.0e-6 rflg = 0 a = aa b = bb y0 = yy0 x = a / (a + b) y = Incbet(a, b, x) goto ihalve } else { dithresh = 1.0e-4 } // Approximation to inverse function yp = -Ndtri(yy0) if yy0 > 0.5 { rflg = 1 a = bb b = aa y0 = 1.0 - yy0 yp = -yp } else { rflg = 0 a = aa b = bb y0 = yy0 } lgm = (yp*yp - 3.0) / 6.0 x = 2.0 / (1.0/(2.0*a-1.0) + 1.0/(2.0*b-1.0)) d = yp*math.Sqrt(x+lgm)/x - (1.0/(2.0*b-1.0)-1.0/(2.0*a-1.0))*(lgm+5.0/6.0-2.0/(3.0*x)) d = 2.0 * d if d < minLog { // mtherr("incbi", UNDERFLOW) x = 0 goto done } x = a / (a + b*math.Exp(d)) y = Incbet(a, b, x) yp = (y - y0) / y0 if math.Abs(yp) < 0.2 { goto newt } /* Resort to interval halving if not close enough. */ ihalve: dir = 0 di = 0.5 for i = 0; i < 100; i++ { if i != 0 { x = x0 + di*(x1-x0) if x == 1.0 { x = 1.0 - machEp } if x == 0.0 { di = 0.5 x = x0 + di*(x1-x0) if x == 0.0 { // mtherr("incbi", UNDERFLOW) goto done } } y = Incbet(a, b, x) yp = (x1 - x0) / (x1 + x0) if math.Abs(yp) < dithresh { goto newt } yp = (y - y0) / y0 if math.Abs(yp) < dithresh { goto newt } } if y < y0 { x0 = x yl = y if dir < 0 { dir = 0 di = 0.5 } else if dir > 3 { di = 1.0 - (1.0-di)*(1.0-di) } else if dir > 1 { di = 0.5*di + 0.5 } else { di = (y0 - y) / (yh - yl) } dir += 1 if x0 > 0.75 { if rflg == 1 { rflg = 0 a = aa b = bb y0 = yy0 } else { rflg = 1 a = bb b = aa y0 = 1.0 - yy0 } x = 1.0 - x y = Incbet(a, b, x) x0 = 0.0 yl = 0.0 x1 = 1.0 yh = 1.0 goto ihalve } } else { x1 = x if rflg == 1 && x1 < machEp { x = 0.0 goto done } yh = y if dir > 0 { dir = 0 di = 0.5 } else if dir < -3 { di = di * di } else if dir < -1 { di = 0.5 * di } else { di = (y - y0) / (yh - yl) } dir -= 1 } } // mtherr("incbi", PLOSS) if x0 >= 1.0 { x = 1.0 - machEp goto done } if x <= 0.0 { // mtherr("incbi", UNDERFLOW) x = 0.0 goto done } newt: if nflg > 0 { goto done } nflg = 1 lgm = lgam(a+b) - lgam(a) - lgam(b) for i = 0; i < 8; i++ { /* Compute the function at this point. */ if i != 0 { y = Incbet(a, b, x) } if y < yl { x = x0 y = yl } else if y > yh { x = x1 y = yh } else if y < y0 { x0 = x yl = y } else { x1 = x yh = y } if x == 1.0 || x == 0.0 { break } /* Compute the derivative of the function at this point. */ d = (a-1.0)*math.Log(x) + (b-1.0)*math.Log(1.0-x) + lgm if d < minLog { goto done } if d > maxLog { break } d = math.Exp(d) /* Compute the step to the next approximation of x. */ d = (y - y0) / d xt = x - d if xt <= x0 { y = (x - x0) / (x1 - x0) xt = x0 + 0.5*y*(x-x0) if xt <= 0.0 { break } } if xt >= x1 { y = (x1 - x) / (x1 - x0) xt = x1 - 0.5*y*(x1-x) if xt >= 1.0 { break } } x = xt if math.Abs(d/x) < 128.0*machEp { goto done } } /* Did not converge. */ dithresh = 256.0 * machEp goto ihalve done: if rflg > 0 { if x <= machEp { x = 1.0 - machEp } else { x = 1.0 - x } } return (x) } func lgam(a float64) float64 { lg, _ := math.Lgamma(a) return lg } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/lanczos.go000066400000000000000000000102461450372207100243760ustar00rootroot00000000000000// Derived from SciPy's special/cephes/lanczos.c // https://github.com/scipy/scipy/blob/master/scipy/special/cephes/lanczos.c // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©2006 John Maddock // Portions Copyright ©2003 Boost // Portions Copyright ©2016 The Gonum Authors. All rights reserved. package cephes // Optimal values for G for each N are taken from // http://web.mala.bc.ca/pughg/phdThesis/phdThesis.pdf, // as are the theoretical error bounds. // Constants calculated using the method described by Godfrey // http://my.fit.edu/~gabdo/gamma.txt and elaborated by Toth at // http://www.rskey.org/gamma.htm using NTL::RR at 1000 bit precision. var lanczosNum = [...]float64{ 2.506628274631000270164908177133837338626, 210.8242777515793458725097339207133627117, 8071.672002365816210638002902272250613822, 186056.2653952234950402949897160456992822, 2876370.628935372441225409051620849613599, 31426415.58540019438061423162831820536287, 248874557.8620541565114603864132294232163, 1439720407.311721673663223072794912393972, 6039542586.35202800506429164430729792107, 17921034426.03720969991975575445893111267, 35711959237.35566804944018545154716670596, 42919803642.64909876895789904700198885093, 23531376880.41075968857200767445163675473, } var lanczosDenom = [...]float64{ 1, 66, 1925, 32670, 357423, 2637558, 13339535, 45995730, 105258076, 150917976, 120543840, 39916800, 0, } var lanczosSumExpgScaledNum = [...]float64{ 0.006061842346248906525783753964555936883222, 0.5098416655656676188125178644804694509993, 19.51992788247617482847860966235652136208, 449.9445569063168119446858607650988409623, 6955.999602515376140356310115515198987526, 75999.29304014542649875303443598909137092, 601859.6171681098786670226533699352302507, 3481712.15498064590882071018964774556468, 14605578.08768506808414169982791359218571, 43338889.32467613834773723740590533316085, 86363131.28813859145546927288977868422342, 103794043.1163445451906271053616070238554, 56906521.91347156388090791033559122686859, } var lanczosSumExpgScaledDenom = [...]float64{ 1, 66, 1925, 32670, 357423, 2637558, 13339535, 45995730, 105258076, 150917976, 120543840, 39916800, 0, } var lanczosSumNear1D = [...]float64{ 0.3394643171893132535170101292240837927725e-9, -0.2499505151487868335680273909354071938387e-8, 0.8690926181038057039526127422002498960172e-8, -0.1933117898880828348692541394841204288047e-7, 0.3075580174791348492737947340039992829546e-7, -0.2752907702903126466004207345038327818713e-7, -0.1515973019871092388943437623825208095123e-5, 0.004785200610085071473880915854204301886437, -0.1993758927614728757314233026257810172008, 1.483082862367253753040442933770164111678, -3.327150580651624233553677113928873034916, 2.208709979316623790862569924861841433016, } var lanczosSumNear2D = [...]float64{ 0.1009141566987569892221439918230042368112e-8, -0.7430396708998719707642735577238449585822e-8, 0.2583592566524439230844378948704262291927e-7, -0.5746670642147041587497159649318454348117e-7, 0.9142922068165324132060550591210267992072e-7, -0.8183698410724358930823737982119474130069e-7, -0.4506604409707170077136555010018549819192e-5, 0.01422519127192419234315002746252160965831, -0.5926941084905061794445733628891024027949, 4.408830289125943377923077727900630927902, -9.8907772644920670589288081640128194231, 6.565936202082889535528455955485877361223, } const lanczosG = 6.024680040776729583740234375 func lanczosSum(x float64) float64 { return ratevl(x, lanczosNum[:], len(lanczosNum)-1, lanczosDenom[:], len(lanczosDenom)-1) } func lanczosSumExpgScaled(x float64) float64 { return ratevl(x, lanczosSumExpgScaledNum[:], len(lanczosSumExpgScaledNum)-1, lanczosSumExpgScaledDenom[:], len(lanczosSumExpgScaledDenom)-1) } func lanczosSumNear1(dx float64) float64 { var result float64 for i, val := range lanczosSumNear1D { k := float64(i + 1) result += (-val * dx) / (k*dx + k*k) } return result } func lanczosSumNear2(dx float64) float64 { var result float64 x := dx + 2 for i, val := range lanczosSumNear2D { k := float64(i + 1) result += (-val * dx) / (x + k*x + k*k - 1) } return result } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/ndtri.go000066400000000000000000000074551450372207100240550ustar00rootroot00000000000000// Copyright ©2016 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. /* * Cephes Math Library Release 2.1: January, 1989 * Copyright 1984, 1987, 1989 by Stephen L. Moshier * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 */ package cephes import "math" // TODO(btracey): There is currently an implementation of this functionality // in gonum/stat/distuv. Find out which implementation is better, and rectify // by having distuv call this, or moving this implementation into // gonum/mathext/internal/gonum. // math.Sqrt(2*pi) const s2pi = 2.50662827463100050242e0 // approximation for 0 <= |y - 0.5| <= 3/8 var P0 = [5]float64{ -5.99633501014107895267e1, 9.80010754185999661536e1, -5.66762857469070293439e1, 1.39312609387279679503e1, -1.23916583867381258016e0, } var Q0 = [8]float64{ /* 1.00000000000000000000E0, */ 1.95448858338141759834e0, 4.67627912898881538453e0, 8.63602421390890590575e1, -2.25462687854119370527e2, 2.00260212380060660359e2, -8.20372256168333339912e1, 1.59056225126211695515e1, -1.18331621121330003142e0, } // Approximation for interval z = math.Sqrt(-2 log y ) between 2 and 8 // i.e., y between exp(-2) = .135 and exp(-32) = 1.27e-14. var P1 = [9]float64{ 4.05544892305962419923e0, 3.15251094599893866154e1, 5.71628192246421288162e1, 4.40805073893200834700e1, 1.46849561928858024014e1, 2.18663306850790267539e0, -1.40256079171354495875e-1, -3.50424626827848203418e-2, -8.57456785154685413611e-4, } var Q1 = [8]float64{ /* 1.00000000000000000000E0, */ 1.57799883256466749731e1, 4.53907635128879210584e1, 4.13172038254672030440e1, 1.50425385692907503408e1, 2.50464946208309415979e0, -1.42182922854787788574e-1, -3.80806407691578277194e-2, -9.33259480895457427372e-4, } // Approximation for interval z = math.Sqrt(-2 log y ) between 8 and 64 // i.e., y between exp(-32) = 1.27e-14 and exp(-2048) = 3.67e-890. var P2 = [9]float64{ 3.23774891776946035970e0, 6.91522889068984211695e0, 3.93881025292474443415e0, 1.33303460815807542389e0, 2.01485389549179081538e-1, 1.23716634817820021358e-2, 3.01581553508235416007e-4, 2.65806974686737550832e-6, 6.23974539184983293730e-9, } var Q2 = [8]float64{ /* 1.00000000000000000000E0, */ 6.02427039364742014255e0, 3.67983563856160859403e0, 1.37702099489081330271e0, 2.16236993594496635890e-1, 1.34204006088543189037e-2, 3.28014464682127739104e-4, 2.89247864745380683936e-6, 6.79019408009981274425e-9, } // Ndtri returns the argument, x, for which the area under the // Gaussian probability density function (integrated from // minus infinity to x) is equal to y. func Ndtri(y0 float64) float64 { // For small arguments 0 < y < exp(-2), the program computes // z = math.Sqrt( -2.0 * math.Log(y) ); then the approximation is // x = z - math.Log(z)/z - (1/z) P(1/z) / Q(1/z). // There are two rational functions P/Q, one for 0 < y < exp(-32) // and the other for y up to exp(-2). For larger arguments, // w = y - 0.5, and x/math.Sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). var x, y, z, y2, x0, x1 float64 var code int if y0 <= 0.0 { if y0 < 0 { panic(paramOutOfBounds) } return math.Inf(-1) } if y0 >= 1.0 { if y0 > 1 { panic(paramOutOfBounds) } return math.Inf(1) } code = 1 y = y0 if y > (1.0 - 0.13533528323661269189) { /* 0.135... = exp(-2) */ y = 1.0 - y code = 0 } if y > 0.13533528323661269189 { y = y - 0.5 y2 = y * y x = y + y*(y2*polevl(y2, P0[:], 4)/p1evl(y2, Q0[:], 8)) x = x * s2pi return (x) } x = math.Sqrt(-2.0 * math.Log(y)) x0 = x - math.Log(x)/x z = 1.0 / x if x < 8.0 { /* y > exp(-32) = 1.2664165549e-14 */ x1 = z * polevl(z, P1[:], 8) / p1evl(z, Q1[:], 8) } else { x1 = z * polevl(z, P2[:], 8) / p1evl(z, Q2[:], 8) } x = x0 - x1 if code != 0 { x = -x } return (x) } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/polevl.go000066400000000000000000000036321450372207100242270ustar00rootroot00000000000000// Derived from SciPy's special/cephes/polevl.h // https://github.com/scipy/scipy/blob/master/scipy/special/cephes/polevl.h // Made freely available by Stephen L. Moshier without support or guarantee. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©1984, ©1987, ©1988 by Stephen L. Moshier // Portions Copyright ©2016 The Gonum Authors. All rights reserved. package cephes import "math" // polevl evaluates a polynomial of degree N // // y = c_0 + c_1 x_1 + c_2 x_2^2 ... // // where the coefficients are stored in reverse order, i.e. coef[0] = c_n and // coef[n] = c_0. func polevl(x float64, coef []float64, n int) float64 { ans := coef[0] for i := 1; i <= n; i++ { ans = ans*x + coef[i] } return ans } // p1evl is the same as polevl, except c_n is assumed to be 1 and is not included // in the slice. func p1evl(x float64, coef []float64, n int) float64 { ans := x + coef[0] for i := 1; i <= n-1; i++ { ans = ans*x + coef[i] } return ans } // ratevl evaluates a rational function func ratevl(x float64, num []float64, m int, denom []float64, n int) float64 { // Source: Holin et. al., "Polynomial and Rational Function Evaluation", // http://www.boost.org/doc/libs/1_61_0/libs/math/doc/html/math_toolkit/roots/rational.html absx := math.Abs(x) var dir, idx int var y float64 if absx > 1 { // Evaluate as a polynomial in 1/x dir = -1 idx = m y = 1 / x } else { dir = 1 idx = 0 y = x } // Evaluate the numerator numAns := num[idx] idx += dir for i := 0; i < m; i++ { numAns = numAns*y + num[idx] idx += dir } // Evaluate the denominator if absx > 1 { idx = n } else { idx = 0 } denomAns := denom[idx] idx += dir for i := 0; i < n; i++ { denomAns = denomAns*y + denom[idx] idx += dir } if absx > 1 { pow := float64(n - m) return math.Pow(x, pow) * numAns / denomAns } return numAns / denomAns } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/staticcheck.conf000066400000000000000000000000141450372207100255220ustar00rootroot00000000000000checks = [] golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/unity.go000066400000000000000000000071051450372207100240750ustar00rootroot00000000000000// Derived from SciPy's special/cephes/unity.c // https://github.com/scipy/scipy/blob/master/scipy/special/cephes/unity.c // Made freely available by Stephen L. Moshier without support or guarantee. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©1984, ©1996 by Stephen L. Moshier // Portions Copyright ©2016 The Gonum Authors. All rights reserved. package cephes import "math" // Relative error approximations for function arguments near unity. // log1p(x) = log(1+x) // expm1(x) = exp(x) - 1 // cosm1(x) = cos(x) - 1 // lgam1p(x) = lgam(1+x) const ( invSqrt2 = 1 / math.Sqrt2 pi4 = math.Pi / 4 euler = 0.577215664901532860606512090082402431 // Euler constant ) // Coefficients for // // log(1+x) = x - \frac{x^2}{2} + \frac{x^3 lP(x)}{lQ(x)} // // for // // \frac{1}{\sqrt{2}} <= x < \sqrt{2} // // Theoretical peak relative error = 2.32e-20 var lP = [...]float64{ 4.5270000862445199635215e-5, 4.9854102823193375972212e-1, 6.5787325942061044846969e0, 2.9911919328553073277375e1, 6.0949667980987787057556e1, 5.7112963590585538103336e1, 2.0039553499201281259648e1, } var lQ = [...]float64{ 1.5062909083469192043167e1, 8.3047565967967209469434e1, 2.2176239823732856465394e2, 3.0909872225312059774938e2, 2.1642788614495947685003e2, 6.0118660497603843919306e1, } // log1p computes // // log(1 + x) func log1p(x float64) float64 { z := 1 + x if z < invSqrt2 || z > math.Sqrt2 { return math.Log(z) } z = x * x z = -0.5*z + x*(z*polevl(x, lP[:], 6)/p1evl(x, lQ[:], 6)) return x + z } // log1pmx computes // // log(1 + x) - x func log1pmx(x float64) float64 { if math.Abs(x) < 0.5 { xfac := x res := 0.0 var term float64 for n := 2; n < maxIter; n++ { xfac *= -x term = xfac / float64(n) res += term if math.Abs(term) < machEp*math.Abs(res) { break } } return res } return log1p(x) - x } // Coefficients for // // e^x = 1 + \frac{2x eP(x^2)}{eQ(x^2) - eP(x^2)} // // for // // -0.5 <= x <= 0.5 var eP = [...]float64{ 1.2617719307481059087798e-4, 3.0299440770744196129956e-2, 9.9999999999999999991025e-1, } var eQ = [...]float64{ 3.0019850513866445504159e-6, 2.5244834034968410419224e-3, 2.2726554820815502876593e-1, 2.0000000000000000000897e0, } // expm1 computes // // expm1(x) = e^x - 1 func expm1(x float64) float64 { if math.IsInf(x, 0) { if math.IsNaN(x) || x > 0 { return x } return -1 } if x < -0.5 || x > 0.5 { return math.Exp(x) - 1 } xx := x * x r := x * polevl(xx, eP[:], 2) r = r / (polevl(xx, eQ[:], 3) - r) return r + r } var coscof = [...]float64{ 4.7377507964246204691685e-14, -1.1470284843425359765671e-11, 2.0876754287081521758361e-9, -2.7557319214999787979814e-7, 2.4801587301570552304991e-5, -1.3888888888888872993737e-3, 4.1666666666666666609054e-2, } // cosm1 computes // // cosm1(x) = cos(x) - 1 func cosm1(x float64) float64 { if x < -pi4 || x > pi4 { return math.Cos(x) - 1 } xx := x * x xx = -0.5*xx + xx*xx*polevl(xx, coscof[:], 6) return xx } // lgam1pTayler computes // // lgam(x + 1) // // around x = 0 using its Taylor series. func lgam1pTaylor(x float64) float64 { if x == 0 { return 0 } res := -euler * x xfac := -x for n := 2; n < 42; n++ { nf := float64(n) xfac *= -x coeff := Zeta(nf, 1) * xfac / nf res += coeff if math.Abs(coeff) < machEp*math.Abs(res) { break } } return res } // lgam1p computes // // lgam(x + 1) func lgam1p(x float64) float64 { if math.Abs(x) <= 0.5 { return lgam1pTaylor(x) } else if math.Abs(x-1) < 0.5 { return math.Log(x) + lgam1pTaylor(x-1) } return lgam(x + 1) } golang-gonum-v1-gonum-0.14.0/mathext/internal/cephes/zeta.go000066400000000000000000000052011450372207100236630ustar00rootroot00000000000000// Derived from SciPy's special/cephes/zeta.c // https://github.com/scipy/scipy/blob/master/scipy/special/cephes/zeta.c // Made freely available by Stephen L. Moshier without support or guarantee. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright ©1984, ©1987 by Stephen L. Moshier // Portions Copyright ©2016 The Gonum Authors. All rights reserved. package cephes import "math" // zetaCoegs are the expansion coefficients for Euler-Maclaurin summation // formula: // // \frac{(2k)!}{B_{2k}} // // where // // B_{2k} // // are Bernoulli numbers. var zetaCoefs = [...]float64{ 12.0, -720.0, 30240.0, -1209600.0, 47900160.0, -1.307674368e12 / 691, 7.47242496e10, -1.067062284288e16 / 3617, 5.109094217170944e18 / 43867, -8.028576626982912e20 / 174611, 1.5511210043330985984e23 / 854513, -1.6938241367317436694528e27 / 236364091, } // Zeta computes the Riemann zeta function of two arguments. // // Zeta(x,q) = \sum_{k=0}^{\infty} (k+q)^{-x} // // Note that Zeta returns +Inf if x is 1 and will panic if x is less than 1, // q is either zero or a negative integer, or q is negative and x is not an // integer. // // Note that: // // zeta(x,1) = zetac(x) + 1 func Zeta(x, q float64) float64 { // REFERENCE: Gradshteyn, I. S., and I. M. Ryzhik, Tables of Integrals, Series, // and Products, p. 1073; Academic Press, 1980. if x == 1 { return math.Inf(1) } if x < 1 { panic(paramOutOfBounds) } if q <= 0 { if q == math.Floor(q) { panic(errParamFunctionSingularity) } if x != math.Floor(x) { panic(paramOutOfBounds) // Because q^-x not defined } } // Asymptotic expansion: http://dlmf.nist.gov/25.11#E43 if q > 1e8 { return (1/(x-1) + 1/(2*q)) * math.Pow(q, 1-x) } // The Euler-Maclaurin summation formula is used to obtain the expansion: // Zeta(x,q) = \sum_{k=1}^n (k+q)^{-x} + \frac{(n+q)^{1-x}}{x-1} - \frac{1}{2(n+q)^x} + \sum_{j=1}^{\infty} \frac{B_{2j}x(x+1)...(x+2j)}{(2j)! (n+q)^{x+2j+1}} // where // B_{2j} // are Bernoulli numbers. // Permit negative q but continue sum until n+q > 9. This case should be // handled by a reflection formula. If q<0 and x is an integer, there is a // relation to the polyGamma function. s := math.Pow(q, -x) a := q i := 0 b := 0.0 for i < 9 || a <= 9 { i++ a += 1.0 b = math.Pow(a, -x) s += b if math.Abs(b/s) < machEp { return s } } w := a s += b * w / (x - 1) s -= 0.5 * b a = 1.0 k := 0.0 for _, coef := range zetaCoefs { a *= x + k b /= w t := a * b / coef s = s + t t = math.Abs(t / s) if t < machEp { return s } k += 1.0 a *= x + k b /= w k += 1.0 } return s } golang-gonum-v1-gonum-0.14.0/mathext/internal/gonum/000077500000000000000000000000001450372207100222515ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mathext/internal/gonum/beta.go000066400000000000000000000026771450372207100235270ustar00rootroot00000000000000// Copyright ©2016 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" ) // Beta returns the value of the complete beta function B(a, b). It is defined as // // Γ(a)Γ(b) / Γ(a+b) // // Special cases are: // // B(a,b) returns NaN if a or b is Inf // B(a,b) returns NaN if a and b are 0 // B(a,b) returns NaN if a or b is NaN // B(a,b) returns NaN if a or b is < 0 // B(a,b) returns +Inf if a xor b is 0. // // See http://mathworld.wolfram.com/BetaFunction.html for more detailed information. func Beta(a, b float64) float64 { return math.Exp(Lbeta(a, b)) } // Lbeta returns the natural logarithm of the complete beta function B(a,b). // Lbeta is defined as: // // Ln(Γ(a)Γ(b)/Γ(a+b)) // // Special cases are: // // Lbeta(a,b) returns NaN if a or b is Inf // Lbeta(a,b) returns NaN if a and b are 0 // Lbeta(a,b) returns NaN if a or b is NaN // Lbeta(a,b) returns NaN if a or b is < 0 // Lbeta(a,b) returns +Inf if a xor b is 0. func Lbeta(a, b float64) float64 { switch { case math.IsInf(a, +1) || math.IsInf(b, +1): return math.NaN() case a == 0 && b == 0: return math.NaN() case a < 0 || b < 0: return math.NaN() case math.IsNaN(a) || math.IsNaN(b): return math.NaN() case a == 0 || b == 0: return math.Inf(+1) } la, _ := math.Lgamma(a) lb, _ := math.Lgamma(b) lab, _ := math.Lgamma(a + b) return la + lb - lab } golang-gonum-v1-gonum-0.14.0/mathext/internal/gonum/doc.go000066400000000000000000000005671450372207100233550ustar00rootroot00000000000000// 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 contains functions implemented by the gonum team. // It is here to avoid circular imports and/or double coding of functions. package gonum // import "gonum.org/v1/gonum/mathext/internal/gonum" golang-gonum-v1-gonum-0.14.0/mathext/internal/gonum/gonum.go000066400000000000000000000002631450372207100237260ustar00rootroot00000000000000// Copyright ©2016 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 golang-gonum-v1-gonum-0.14.0/mathext/mvgamma.go000066400000000000000000000015011450372207100212610ustar00rootroot00000000000000// Copyright ©2016 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 mathext import "math" const ( logPi = 1.14472988584940017414342735135305871164729481 // http://oeis.org/A053510 ) // MvLgamma returns the log of the multivariate Gamma function. Dim // must be greater than zero, and MvLgamma will return NaN if v < (dim-1)/2. // // See https://en.wikipedia.org/wiki/Multivariate_gamma_function for more // information. func MvLgamma(v float64, dim int) float64 { if dim < 1 { panic("mathext: negative dimension") } df := float64(dim) if v < (df-1)*0.5 { return math.NaN() } ans := df * (df - 1) * 0.25 * logPi for i := 1; i <= dim; i++ { lg, _ := math.Lgamma(v + float64(1-i)*0.5) ans += lg } return ans } golang-gonum-v1-gonum-0.14.0/mathext/mvgamma_test.go000066400000000000000000000010771450372207100223300ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "math" "testing" ) func TestMvLgamma(t *testing.T) { t.Parallel() // Values compared with scipy for i, test := range []struct { v float64 dim int ans float64 }{ {10, 5, 58.893841851237397}, {3, 1, 0.69314718055994529}, } { ans := MvLgamma(test.v, test.dim) if math.Abs(test.ans-ans) > 1e-13 { t.Errorf("Case %v. got=%v want=%v.", i, ans, test.ans) } } } golang-gonum-v1-gonum-0.14.0/mathext/prng/000077500000000000000000000000001450372207100202565ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/mathext/prng/doc.go000066400000000000000000000007311450372207100213530ustar00rootroot00000000000000// Copyright ©2019 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 prng provides random source PRNG implementations. // // PRNG implementations provided in package prng may be used directly as // rand.Source values for the golang.org/x/exp/rand package, and for the // math rand package via a wrapper type. package prng // import "gonum.org/v1/gonum/mathext/prng" golang-gonum-v1-gonum-0.14.0/mathext/prng/mt19937.go000066400000000000000000000103611450372207100216430ustar00rootroot00000000000000// Copyright ©2019 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. // Original C program copyright Takuji Nishimura and Makoto Matsumoto 2002. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c package prng import ( "encoding/binary" "io" ) const ( mt19937N = 624 mt19937M = 397 mt19937matrixA = 0x9908b0df mt19937UpperMask = 0x80000000 mt19937LowerMask = 0x7fffffff ) // MT19937 implements the 32 bit Mersenne Twister PRNG. MT19937 // is the default PRNG for a wide variety of programming systems. // See https://en.wikipedia.org/wiki/Mersenne_Twister. type MT19937 struct { mt [mt19937N]uint32 mti uint32 } // NewMT19937 returns a new MT19937 PRNG. The returned PRNG will // use the default seed 5489 unless the Seed method is called with // another value. func NewMT19937() *MT19937 { return &MT19937{mti: mt19937N + 1} } // Seed uses the provided seed value to initialize the generator to a // deterministic state. Only the lower 32 bits of seed are used to seed // the PRNG. func (src *MT19937) Seed(seed uint64) { src.mt[0] = uint32(seed) for src.mti = 1; src.mti < mt19937N; src.mti++ { src.mt[src.mti] = (1812433253*(src.mt[src.mti-1]^(src.mt[src.mti-1]>>30)) + src.mti) } } // SeedFromKeys uses the provided seed key value to initialize the // generator to a deterministic state. It is provided for compatibility // with C implementations. func (src *MT19937) SeedFromKeys(keys []uint32) { src.Seed(19650218) i := uint32(1) j := uint32(0) k := uint32(mt19937N) if k <= uint32(len(keys)) { k = uint32(len(keys)) } for ; k != 0; k-- { src.mt[i] = (src.mt[i] ^ ((src.mt[i-1] ^ (src.mt[i-1] >> 30)) * 1664525)) + keys[j] + j // Non linear. i++ j++ if i >= mt19937N { src.mt[0] = src.mt[mt19937N-1] i = 1 } if j >= uint32(len(keys)) { j = 0 } } for k = mt19937N - 1; k != 0; k-- { src.mt[i] = (src.mt[i] ^ ((src.mt[i-1] ^ (src.mt[i-1] >> 30)) * 1566083941)) - i // Non linear. i++ if i >= mt19937N { src.mt[0] = src.mt[mt19937N-1] i = 1 } } src.mt[0] = 0x80000000 // MSB is 1; assuring non-zero initial array. } // Uint32 returns a pseudo-random 32-bit unsigned integer as a uint32. func (src *MT19937) Uint32() uint32 { mag01 := [2]uint32{0x0, mt19937matrixA} var y uint32 if src.mti >= mt19937N { // Generate mt19937N words at one time. if src.mti == mt19937N+1 { // If Seed() has not been called // a default initial seed is used. src.Seed(5489) } var kk int for ; kk < mt19937N-mt19937M; kk++ { y = (src.mt[kk] & mt19937UpperMask) | (src.mt[kk+1] & mt19937LowerMask) src.mt[kk] = src.mt[kk+mt19937M] ^ (y >> 1) ^ mag01[y&0x1] } for ; kk < mt19937N-1; kk++ { y = (src.mt[kk] & mt19937UpperMask) | (src.mt[kk+1] & mt19937LowerMask) src.mt[kk] = src.mt[kk+(mt19937M-mt19937N)] ^ (y >> 1) ^ mag01[y&0x1] } y = (src.mt[mt19937N-1] & mt19937UpperMask) | (src.mt[0] & mt19937LowerMask) src.mt[mt19937N-1] = src.mt[mt19937M-1] ^ (y >> 1) ^ mag01[y&0x1] src.mti = 0 } y = src.mt[src.mti] src.mti++ // Tempering. y ^= (y >> 11) y ^= (y << 7) & 0x9d2c5680 y ^= (y << 15) & 0xefc60000 y ^= (y >> 18) return y } // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. // It makes use of two calls to Uint32 placing the first result in the // upper bits and the second result in the lower bits of the returned // value. func (src *MT19937) Uint64() uint64 { h := uint64(src.Uint32()) l := uint64(src.Uint32()) return h<<32 | l } // MarshalBinary returns the binary representation of the current state of the generator. func (src *MT19937) MarshalBinary() ([]byte, error) { var buf [(mt19937N + 1) * 4]byte for i := 0; i < mt19937N; i++ { binary.BigEndian.PutUint32(buf[i*4:(i+1)*4], src.mt[i]) } binary.BigEndian.PutUint32(buf[mt19937N*4:], src.mti) return buf[:], nil } // UnmarshalBinary sets the state of the generator to the state represented in data. func (src *MT19937) UnmarshalBinary(data []byte) error { if len(data) < (mt19937N+1)*4 { return io.ErrUnexpectedEOF } for i := 0; i < mt19937N; i++ { src.mt[i] = binary.BigEndian.Uint32(data[i*4 : (i+1)*4]) } src.mti = binary.BigEndian.Uint32(data[mt19937N*4:]) return nil } golang-gonum-v1-gonum-0.14.0/mathext/prng/mt19937_64.go000066400000000000000000000102311450372207100221500ustar00rootroot00000000000000// Copyright ©2019 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. // Original C program copyright Takuji Nishimura and Makoto Matsumoto 2004. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c package prng import ( "encoding/binary" "io" ) const ( mt19937_64NN = 312 mt19937_64MM = 156 mt19937_64MatrixA = 0xB5026F5AA96619E9 mt19937_64UpperMask = 0xFFFFFFFF80000000 mt19937_64LowerMask = 0x7FFFFFFF ) // MT19937_64 implements the 64 bit Mersenne Twister PRNG. MT19937_64 // is the 64 bit version of MT19937, it has the same sized state, but // generates a different sequence. // See https://en.wikipedia.org/wiki/Mersenne_Twister. type MT19937_64 struct { mt [mt19937_64NN]uint64 mti uint64 } // NewMT19937_64 returns a new MT19937_64 PRNG. The returned PRNG will // use the default seed 5489 unless the Seed method is called with // another value. func NewMT19937_64() *MT19937_64 { return &MT19937_64{mti: mt19937_64NN + 1} } // Seed uses the provided seed value to initialize the generator to a // deterministic state. func (src *MT19937_64) Seed(seed uint64) { src.mt[0] = seed for src.mti = 1; src.mti < mt19937_64NN; src.mti++ { src.mt[src.mti] = (6364136223846793005*(src.mt[src.mti-1]^(src.mt[src.mti-1]>>62)) + src.mti) } } // SeedFromKeys uses the provided seed key value to initialize the // generator to a deterministic state. It is provided for compatibility // with C implementations. func (src *MT19937_64) SeedFromKeys(keys []uint64) { src.Seed(19650218) i := uint64(1) j := uint64(0) k := uint64(mt19937_64NN) if k <= uint64(len(keys)) { k = uint64(len(keys)) } for ; k != 0; k-- { src.mt[i] = (src.mt[i] ^ ((src.mt[i-1] ^ (src.mt[i-1] >> 62)) * 3935559000370003845)) + keys[j] + j // Non linear. i++ j++ if i >= mt19937_64NN { src.mt[0] = src.mt[mt19937_64NN-1] i = 1 } if j >= uint64(len(keys)) { j = 0 } } for k = mt19937_64NN - 1; k != 0; k-- { src.mt[i] = (src.mt[i] ^ ((src.mt[i-1] ^ (src.mt[i-1] >> 62)) * 2862933555777941757)) - i // Non linear. i++ if i >= mt19937_64NN { src.mt[0] = src.mt[mt19937_64NN-1] i = 1 } } src.mt[0] = 1 << 63 /* MSB is 1; assuring non-zero initial array */ } // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. func (src *MT19937_64) Uint64() uint64 { mag01 := [2]uint64{0, mt19937_64MatrixA} var x uint64 if src.mti >= mt19937_64NN { // Generate mt19937_64NN words at one time. if src.mti == mt19937_64NN+1 { // If Seed() has not been called // a default initial seed is used. src.Seed(5489) } var i int for ; i < mt19937_64NN-mt19937_64MM; i++ { x = (src.mt[i] & mt19937_64UpperMask) | (src.mt[i+1] & mt19937_64LowerMask) src.mt[i] = src.mt[i+mt19937_64MM] ^ (x >> 1) ^ mag01[(int)(x&0x1)] } for ; i < mt19937_64NN-1; i++ { x = (src.mt[i] & mt19937_64UpperMask) | (src.mt[i+1] & mt19937_64LowerMask) src.mt[i] = src.mt[i+(mt19937_64MM-mt19937_64NN)] ^ (x >> 1) ^ mag01[(int)(x&0x1)] } x = (src.mt[mt19937_64NN-1] & mt19937_64UpperMask) | (src.mt[0] & mt19937_64LowerMask) src.mt[mt19937_64NN-1] = src.mt[mt19937_64MM-1] ^ (x >> 1) ^ mag01[(int)(x&0x1)] src.mti = 0 } x = src.mt[src.mti] src.mti++ // Tempering. x ^= (x >> 29) & 0x5555555555555555 x ^= (x << 17) & 0x71D67FFFEDA60000 x ^= (x << 37) & 0xFFF7EEE000000000 x ^= (x >> 43) return x } // MarshalBinary returns the binary representation of the current state of the generator. func (src *MT19937_64) MarshalBinary() ([]byte, error) { var buf [(mt19937_64NN + 1) * 8]byte for i := 0; i < mt19937_64NN; i++ { binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], src.mt[i]) } binary.BigEndian.PutUint64(buf[mt19937_64NN*8:], src.mti) return buf[:], nil } // UnmarshalBinary sets the state of the generator to the state represented in data. func (src *MT19937_64) UnmarshalBinary(data []byte) error { if len(data) < (mt19937_64NN+1)*8 { return io.ErrUnexpectedEOF } for i := 0; i < mt19937_64NN; i++ { src.mt[i] = binary.BigEndian.Uint64(data[i*8 : (i+1)*8]) } src.mti = binary.BigEndian.Uint64(data[mt19937_64NN*8:]) return nil } golang-gonum-v1-gonum-0.14.0/mathext/prng/mt19937_64_test.go000066400000000000000000000064241450372207100232200ustar00rootroot00000000000000// Copyright ©2019 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 prng import ( "testing" "time" "golang.org/x/exp/rand" ) var _ rand.Source = (*MT19937_64)(nil) // Random values in tests are produced by 40 iterations of the C code // with or without an initial seed array. func TestMT19937_64(t *testing.T) { t.Parallel() want := []uint64{ 14514284786278117030, 4620546740167642908, 13109570281517897720, 17462938647148434322, 355488278567739596, 7469126240319926998, 4635995468481642529, 418970542659199878, 9604170989252516556, 6358044926049913402, 5058016125798318033, 10349215569089701407, 2583272014892537200, 10032373690199166667, 9627645531742285868, 15810285301089087632, 9219209713614924562, 7736011505917826031, 13729552270962724157, 4596340717661012313, 4413874586873285858, 5904155143473820934, 16795776195466785825, 3040631852046752166, 4529279813148173111, 3658352497551999605, 13205889818278417278, 17853215078830450730, 14193508720503142180, 1488787817663097441, 8484116316263611556, 4745643133208116498, 14333959900198994173, 10770733876927207790, 17529942701849009476, 8081518017574486547, 5945178879512507902, 9821139136195250096, 4728986788662773602, 840062144447779464, } mt := NewMT19937_64() for i := range want { got := mt.Uint64() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestMT19937_64SeedFromKeys(t *testing.T) { t.Parallel() want := []uint64{ 7266447313870364031, 4946485549665804864, 16945909448695747420, 16394063075524226720, 4873882236456199058, 14877448043947020171, 6740343660852211943, 13857871200353263164, 5249110015610582907, 10205081126064480383, 1235879089597390050, 17320312680810499042, 16489141110565194782, 8942268601720066061, 13520575722002588570, 14226945236717732373, 9383926873555417063, 15690281668532552105, 11510704754157191257, 15864264574919463609, 6489677788245343319, 5112602299894754389, 10828930062652518694, 15942305434158995996, 15445717675088218264, 4764500002345775851, 14673753115101942098, 236502320419669032, 13670483975188204088, 14931360615268175698, 8904234204977263924, 12836915408046564963, 12120302420213647524, 15755110976537356441, 5405758943702519480, 10951858968426898805, 17251681303478610375, 4144140664012008120, 18286145806977825275, 13075804672185204371, } mt := NewMT19937_64() mt.SeedFromKeys([]uint64{0x12345, 0x23456, 0x34567, 0x45678}) for i := range want { got := mt.Uint64() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestMT19937_64RoundTrip(t *testing.T) { t.Parallel() var src MT19937_64 src.Seed(uint64(time.Now().Unix())) src.Uint64() // Step PRNG once to makes sure states are mixed. buf, err := src.MarshalBinary() if err != nil { t.Errorf("unexpected error marshaling state: %v", err) } var dst MT19937_64 // Get dst into a non-zero state. dst.Seed(1) for i := 0; i < 10; i++ { dst.Uint64() } err = dst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling state: %v", err) } if dst != src { t.Errorf("mismatch between generator states: got:%+v want:%+v", dst, src) } } golang-gonum-v1-gonum-0.14.0/mathext/prng/mt19937_test.go000066400000000000000000000047531450372207100227120ustar00rootroot00000000000000// Copyright ©2019 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 prng import ( "testing" "time" "golang.org/x/exp/rand" ) var _ rand.Source = (*MT19937)(nil) // Random values in tests are produced by 40 iterations of the C code // with or without an initial seed array. func TestMT19937(t *testing.T) { t.Parallel() want := []uint32{ 3499211612, 581869302, 3890346734, 3586334585, 545404204, 4161255391, 3922919429, 949333985, 2715962298, 1323567403, 418932835, 2350294565, 1196140740, 809094426, 2348838239, 4264392720, 4112460519, 4279768804, 4144164697, 4156218106, 676943009, 3117454609, 4168664243, 4213834039, 4111000746, 471852626, 2084672536, 3427838553, 3437178460, 1275731771, 609397212, 20544909, 1811450929, 483031418, 3933054126, 2747762695, 3402504553, 3772830893, 4120988587, 2163214728, } mt := NewMT19937() for i := range want { got := mt.Uint32() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestMT19937SeedFromKeys(t *testing.T) { t.Parallel() want := []uint32{ 1067595299, 955945823, 477289528, 4107218783, 4228976476, 3344332714, 3355579695, 227628506, 810200273, 2591290167, 2560260675, 3242736208, 646746669, 1479517882, 4245472273, 1143372638, 3863670494, 3221021970, 1773610557, 1138697238, 1421897700, 1269916527, 2859934041, 1764463362, 3874892047, 3965319921, 72549643, 2383988930, 2600218693, 3237492380, 2792901476, 725331109, 605841842, 271258942, 715137098, 3297999536, 1322965544, 4229579109, 1395091102, 3735697720, } mt := NewMT19937() mt.SeedFromKeys([]uint32{0x123, 0x234, 0x345, 0x456}) for i := range want { got := mt.Uint32() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestMT19937RoundTrip(t *testing.T) { t.Parallel() var src MT19937 src.Seed(uint64(time.Now().Unix())) src.Uint64() // Step PRNG once to makes sure states are mixed. buf, err := src.MarshalBinary() if err != nil { t.Errorf("unexpected error marshaling state: %v", err) } var dst MT19937 // Get dst into a non-zero state. dst.Seed(1) for i := 0; i < 10; i++ { dst.Uint64() } err = dst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling state: %v", err) } if dst != src { t.Errorf("mismatch between generator states: got:%+v want:%+v", dst, src) } } golang-gonum-v1-gonum-0.14.0/mathext/prng/prng_di_unimi.go000066400000000000000000000161411450372207100234330ustar00rootroot00000000000000// Copyright ©2019 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. // PRNGs from Dipartimento di Informatica Università degli Studi di Milano. // David Blackman and Sebastiano Vigna licensed under CC0 1.0 // http://creativecommons.org/publicdomain/zero/1.0/ package prng import ( "encoding/binary" "io" "math/bits" ) // SplitMix64 is the splitmix64 PRNG from http://prng.di.unimi.it/splitmix64.c. // The zero value is usable directly. SplitMix64 is primarily provided to support // seeding the xoshiro PRNGs. type SplitMix64 struct { state uint64 } // NewSplitMix64 returns a new pseudo-random splitmix64 source seeded // with the given value. func NewSplitMix64(seed uint64) *SplitMix64 { var src SplitMix64 src.Seed(seed) return &src } // Seed uses the provided seed value to initialize the generator to a // deterministic state. func (src *SplitMix64) Seed(seed uint64) { src.state = seed } // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. func (src *SplitMix64) Uint64() uint64 { src.state += 0x9e3779b97f4a7c15 z := src.state z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9 z = (z ^ (z >> 27)) * 0x94d049bb133111eb return z ^ (z >> 31) } // MarshalBinary returns the binary representation of the current state of the generator. func (src *SplitMix64) MarshalBinary() ([]byte, error) { var buf [8]byte binary.BigEndian.PutUint64(buf[:], src.state) return buf[:], nil } // UnmarshalBinary sets the state of the generator to the state represented in data. func (src *SplitMix64) UnmarshalBinary(data []byte) error { if len(data) < 8 { return io.ErrUnexpectedEOF } src.state = binary.BigEndian.Uint64(data) return nil } // Xoshiro256plus is the xoshiro256+ 1.0 PRNG from http://prng.di.unimi.it/xoshiro256plus.c. // The xoshiro PRNGs are described in http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf // and http://prng.di.unimi.it/. // A Xoshiro256plus value is only valid if returned by NewXoshiro256plus. type Xoshiro256plus struct { state [4]uint64 } // NewXoshiro256plus returns a new pseudo-random xoshiro256+ source // seeded with the given value. func NewXoshiro256plus(seed uint64) *Xoshiro256plus { var src Xoshiro256plus src.Seed(seed) return &src } // Seed uses the provided seed value to initialize the generator to a // deterministic state. func (src *Xoshiro256plus) Seed(seed uint64) { var boot SplitMix64 boot.Seed(seed) for i := range src.state { src.state[i] = boot.Uint64() } } // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. func (src *Xoshiro256plus) Uint64() uint64 { result := src.state[0] + src.state[3] t := src.state[1] << 17 src.state[2] ^= src.state[0] src.state[3] ^= src.state[1] src.state[1] ^= src.state[2] src.state[0] ^= src.state[3] src.state[2] ^= t src.state[3] = bits.RotateLeft64(src.state[3], 45) return result } // MarshalBinary returns the binary representation of the current state of the generator. func (src *Xoshiro256plus) MarshalBinary() ([]byte, error) { var buf [32]byte for i := 0; i < 4; i++ { binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], src.state[i]) } return buf[:], nil } // UnmarshalBinary sets the state of the generator to the state represented in data. func (src *Xoshiro256plus) UnmarshalBinary(data []byte) error { if len(data) < 32 { return io.ErrUnexpectedEOF } for i := 0; i < 4; i++ { src.state[i] = binary.BigEndian.Uint64(data[i*8 : (i+1)*8]) } return nil } // Xoshiro256plusplus is the xoshiro256++ 1.0 PRNG from http://prng.di.unimi.it/xoshiro256plusplus.c. // The xoshiro PRNGs are described in http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf // and http://prng.di.unimi.it/. // A Xoshiro256plusplus value is only valid if returned by NewXoshiro256plusplus. type Xoshiro256plusplus struct { state [4]uint64 } // NewXoshiro256plusplus returns a new pseudo-random xoshiro256++ source // seeded with the given value. func NewXoshiro256plusplus(seed uint64) *Xoshiro256plusplus { var src Xoshiro256plusplus src.Seed(seed) return &src } // Seed uses the provided seed value to initialize the generator to a // deterministic state. func (src *Xoshiro256plusplus) Seed(seed uint64) { var boot SplitMix64 boot.Seed(seed) for i := range src.state { src.state[i] = boot.Uint64() } } // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. func (src *Xoshiro256plusplus) Uint64() uint64 { result := bits.RotateLeft64(src.state[0]+src.state[3], 23) + src.state[0] t := src.state[1] << 17 src.state[2] ^= src.state[0] src.state[3] ^= src.state[1] src.state[1] ^= src.state[2] src.state[0] ^= src.state[3] src.state[2] ^= t src.state[3] = bits.RotateLeft64(src.state[3], 45) return result } // MarshalBinary returns the binary representation of the current state of the generator. func (src *Xoshiro256plusplus) MarshalBinary() ([]byte, error) { var buf [32]byte for i := 0; i < 4; i++ { binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], src.state[i]) } return buf[:], nil } // UnmarshalBinary sets the state of the generator to the state represented in data. func (src *Xoshiro256plusplus) UnmarshalBinary(data []byte) error { if len(data) < 32 { return io.ErrUnexpectedEOF } for i := 0; i < 4; i++ { src.state[i] = binary.BigEndian.Uint64(data[i*8 : (i+1)*8]) } return nil } // Xoshiro256starstar is the xoshiro256** 1.0 PRNG from http://prng.di.unimi.it/xoshiro256starstar.c. // The xoshiro PRNGs are described in http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf // and http://prng.di.unimi.it/. // A Xoshiro256starstar value is only valid if returned by NewXoshiro256starstar. type Xoshiro256starstar struct { state [4]uint64 } // NewXoshiro256starstar returns a new pseudo-random xoshiro256** source // seeded with the given value. func NewXoshiro256starstar(seed uint64) *Xoshiro256starstar { var src Xoshiro256starstar src.Seed(seed) return &src } // Seed uses the provided seed value to initialize the generator to a // deterministic state. func (src *Xoshiro256starstar) Seed(seed uint64) { var boot SplitMix64 boot.Seed(seed) for i := range src.state { src.state[i] = boot.Uint64() } } // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. func (src *Xoshiro256starstar) Uint64() uint64 { result := bits.RotateLeft64(src.state[1]*5, 7) * 9 t := src.state[1] << 17 src.state[2] ^= src.state[0] src.state[3] ^= src.state[1] src.state[1] ^= src.state[2] src.state[0] ^= src.state[3] src.state[2] ^= t src.state[3] = bits.RotateLeft64(src.state[3], 45) return result } // MarshalBinary returns the binary representation of the current state of the generator. func (src *Xoshiro256starstar) MarshalBinary() ([]byte, error) { var buf [32]byte for i := 0; i < 4; i++ { binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], src.state[i]) } return buf[:], nil } // UnmarshalBinary sets the state of the generator to the state represented in data. func (src *Xoshiro256starstar) UnmarshalBinary(data []byte) error { if len(data) < 32 { return io.ErrUnexpectedEOF } for i := 0; i < 4; i++ { src.state[i] = binary.BigEndian.Uint64(data[i*8 : (i+1)*8]) } return nil } golang-gonum-v1-gonum-0.14.0/mathext/prng/prng_di_unimi_test.go000066400000000000000000000165631450372207100245020ustar00rootroot00000000000000// Copyright ©2019 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 prng import ( "testing" "time" "golang.org/x/exp/rand" ) // Random values in tests are produced by 40 iterations of the C code. var _ rand.Source = (*SplitMix64)(nil) func TestSplitMix64(t *testing.T) { t.Parallel() want := []uint64{ 10451216379200822465, 13757245211066428519, 17911839290282890590, 8196980753821780235, 8195237237126968761, 14072917602864530048, 16184226688143867045, 9648886400068060533, 5266705631892356520, 14646652180046636950, 7455107161863376737, 11168034603498703870, 8392123148533390784, 9778231605760336522, 8042142155559163816, 3081251696030599739, 11904322950028659555, 15040563541741120241, 12575237177726700014, 16312908901713405192, 1216750802008901446, 1501835286251455644, 9147370558249537485, 2270958130545493676, 5292580334274787743, 883620860755687159, 9509663594007654709, 13166747327335888811, 807013244984872231, 18405200023706498954, 11028426030083068036, 10820770463232788922, 7326479631639850093, 8097875853865443356, 4672064935750269975, 9772298966463872780, 10028955912863736053, 13802505617680978881, 15090054588401425688, 12333003614474408764, } sm := NewSplitMix64(1) for i := range want { got := sm.Uint64() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestSplitMix64RoundTrip(t *testing.T) { t.Parallel() var src SplitMix64 src.Seed(uint64(time.Now().Unix())) buf, err := src.MarshalBinary() if err != nil { t.Errorf("unexpected error marshaling state: %v", err) } var dst SplitMix64 // Get dst into a non-zero state. dst.Seed(1) for i := 0; i < 10; i++ { dst.Uint64() } err = dst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling state: %v", err) } if dst != src { t.Errorf("mismatch between generator states: got:%+v want:%+v", dst, src) } } var _ rand.Source = (*Xoshiro256plus)(nil) func TestXoshiro256plus(t *testing.T) { t.Parallel() want := []uint64{ 201453059313051084, 16342930563397888806, 2922809869868169223, 13315230553875954649, 6410977891529050008, 2721661332018190285, 3769995280709464022, 17208995829377771030, 16938999919058283733, 8307416726322109393, 13997290115667311691, 5498422487743993519, 13193129985428835789, 17178224140053183722, 3371202013665523682, 6673444001875245482, 11649545741795472859, 4657392542380076879, 8631341306563158492, 16151880809814987639, 15271080878658922261, 6998002807989632655, 11431762507643441726, 136605885039865329, 16072241235209520170, 17064623797431990278, 6319393334343723778, 3599071131527455911, 14678971584471326753, 11566847267978507055, 37242444495476935, 9767625399998905638, 14799351402198708144, 15147234459691564338, 10081976988475685812, 12402022881820243150, 17939631254687971868, 15680836376982110901, 179319489669050051, 16194215847106809765, } xsr := NewXoshiro256plus(1) for i := range want { got := xsr.Uint64() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestXoshiro256plusRoundTrip(t *testing.T) { t.Parallel() var src Xoshiro256plus src.Seed(uint64(time.Now().Unix())) src.Uint64() // Step PRNG once to makes sure states are mixed. buf, err := src.MarshalBinary() if err != nil { t.Errorf("unexpected error marshaling state: %v", err) } var dst Xoshiro256plus // Get dst into a non-zero state. dst.Seed(1) for i := 0; i < 10; i++ { dst.Uint64() } err = dst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling state: %v", err) } if dst != src { t.Errorf("mismatch between generator states: got:%+v want:%+v", dst, src) } } var _ rand.Source = (*Xoshiro256plusplus)(nil) func TestXoshiro256plusplus(t *testing.T) { t.Parallel() want := []uint64{ 14971601782005023387, 13781649495232077965, 1847458086238483744, 13765271635752736470, 3406718355780431780, 10892412867582108485, 18204613561675945223, 9655336933892813345, 1781989159761824720, 2477283028068920342, 16978024111547606601, 6336475467619303347, 1336129645694042326, 7278725533440954441, 1650926874576718010, 2884092293074692283, 10277292511068429730, 8723528388573605619, 17670016435951889822, 11847526622624223050, 4869519043768407819, 14645621260580619786, 2927941368235978475, 7627105703721172900, 4384663367605854827, 11119034730948704880, 3397900810577180010, 18115970067406137490, 11274606161466886392, 13467911786374401590, 10949103424463861935, 11981483663808188895, 9358210361682609782, 11442939244776437245, 17602980262171424054, 5959474180322755185, 1996769245947054333, 13544632058761996522, 16649296193330087156, 12760326241867116135, } xsr := NewXoshiro256plusplus(1) for i := range want { got := xsr.Uint64() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestXoshiro256plusplusRoundTrip(t *testing.T) { t.Parallel() var src Xoshiro256plusplus src.Seed(uint64(time.Now().Unix())) src.Uint64() // Step PRNG once to makes sure states are mixed. buf, err := src.MarshalBinary() if err != nil { t.Errorf("unexpected error marshaling state: %v", err) } var dst Xoshiro256plusplus // Get dst into a non-zero state. dst.Seed(1) for i := 0; i < 10; i++ { dst.Uint64() } err = dst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling state: %v", err) } if dst != src { t.Errorf("mismatch between generator states: got:%+v want:%+v", dst, src) } } var _ rand.Source = (*Xoshiro256starstar)(nil) func TestXoshiro256starstar(t *testing.T) { t.Parallel() want := []uint64{ 12966619160104079557, 9600361134598540522, 10590380919521690900, 7218738570589545383, 12860671823995680371, 2648436617965840162, 1310552918490157286, 7031611932980406429, 15996139959407692321, 10177250653276320208, 17202925169076741841, 17657558547222227110, 17206619296382044401, 12342657103067243573, 11066818095355039191, 16427605434558419749, 1484150211974036615, 9063990983673329711, 845232928428614080, 1176429380546917807, 8545088851120551825, 9158324580728115577, 11267126437916202177, 6452051665337041730, 7460617819096774474, 3909615622106851260, 7148019177890935463, 15761474764570999248, 13856144421012645925, 18119237044791779759, 202581184499657049, 16256128138147959276, 7894450248801719761, 7285265299121834259, 11974578372788407364, 4350246478179107086, 4560570958642824732, 15448532239578831742, 7084622563335324071, 8654072644765974953, } xsr := NewXoshiro256starstar(1) for i := range want { got := xsr.Uint64() if got != want[i] { t.Errorf("unexpected random value at iteration %d: got:%d want:%d", i, got, want[i]) } } } func TestXoshiro256starstarRoundTrip(t *testing.T) { t.Parallel() var src Xoshiro256starstar src.Seed(uint64(time.Now().Unix())) src.Uint64() // Step PRNG once to makes sure states are mixed. buf, err := src.MarshalBinary() if err != nil { t.Errorf("unexpected error marshaling state: %v", err) } var dst Xoshiro256starstar // Get dst into a non-zero state. dst.Seed(1) for i := 0; i < 10; i++ { dst.Uint64() } err = dst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling state: %v", err) } if dst != src { t.Errorf("mismatch between generator states: got:%+v want:%+v", dst, src) } } golang-gonum-v1-gonum-0.14.0/mathext/roots.go000066400000000000000000000107371450372207100210150ustar00rootroot00000000000000// Derived from SciPy's special/c_misc/fsolve.c and special/c_misc/misc.h // https://github.com/scipy/scipy/blob/master/scipy/special/c_misc/fsolve.c // https://github.com/scipy/scipy/blob/master/scipy/special/c_misc/misc.h // 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 mathext import "math" type objectiveFunc func(float64, []float64) float64 type fSolveResult uint8 const ( // An exact solution was found, in which case the first point on the // interval is the value fSolveExact fSolveResult = iota + 1 // Interval width is less than the tolerance fSolveConverged // Root-finding didn't converge in a set number of iterations fSolveMaxIterations ) const ( machEp = 1.0 / (1 << 53) ) // falsePosition uses a combination of bisection and false position to find a // root of a function within a given interval. This is guaranteed to converge, // and always keeps a bounding interval, unlike Newton's method. Inputs are: // // x1, x2: initial bounding interval // f1, f2: value of f() at x1 and x2 // absErr, relErr: absolute and relative errors on the bounding interval // bisectTil: if > 0.0, perform bisection until the width of the bounding // interval is less than this // f, fExtra: function to find root of is f(x, fExtra) // // Returns: // // result: whether an exact root was found, the process converged to a // bounding interval small than the required error, or the max number // of iterations was hit // bestX: best root approximation // bestF: function value at bestX // errEst: error estimation func falsePosition(x1, x2, f1, f2, absErr, relErr, bisectTil float64, f objectiveFunc, fExtra []float64) (fSolveResult, float64, float64, float64) { // The false position steps are either unmodified, or modified with the // Anderson-Bjorck method as appropriate. Theoretically, this has a "speed of // convergence" of 1.7 (bisection is 1, Newton is 2). // Note that this routine was designed initially to work with gammaincinv, so // it may not be tuned right for other problems. Don't use it blindly. if f1*f2 >= 0 { panic("Initial interval is not a bounding interval") } const ( maxIterations = 100 bisectIter = 4 bisectWidth = 4.0 ) const ( bisect = iota + 1 falseP ) var state uint8 if bisectTil > 0 { state = bisect } else { state = falseP } gamma := 1.0 w := math.Abs(x2 - x1) lastBisectWidth := w var nFalseP int var x3, f3, bestX, bestF float64 for i := 0; i < maxIterations; i++ { switch state { case bisect: x3 = 0.5 * (x1 + x2) if x3 == x1 || x3 == x2 { // i.e., x1 and x2 are successive floating-point numbers bestX = x3 if x3 == x1 { bestF = f1 } else { bestF = f2 } return fSolveConverged, bestX, bestF, w } f3 = f(x3, fExtra) if f3 == 0 { return fSolveExact, x3, f3, w } if f3*f2 < 0 { x1 = x2 f1 = f2 } x2 = x3 f2 = f3 w = math.Abs(x2 - x1) lastBisectWidth = w if bisectTil > 0 { if w < bisectTil { bisectTil = -1.0 gamma = 1.0 nFalseP = 0 state = falseP } } else { gamma = 1.0 nFalseP = 0 state = falseP } case falseP: s12 := (f2 - gamma*f1) / (x2 - x1) x3 = x2 - f2/s12 f3 = f(x3, fExtra) if f3 == 0 { return fSolveExact, x3, f3, w } nFalseP++ if f3*f2 < 0 { gamma = 1.0 x1 = x2 f1 = f2 } else { // Anderson-Bjorck method g := 1.0 - f3/f2 if g <= 0 { g = 0.5 } gamma *= g } x2 = x3 f2 = f3 w = math.Abs(x2 - x1) // Sanity check. For every 4 false position checks, see if we really are // decreasing the interval by comparing to what bisection would have // achieved (or, rather, a bit more lenient than that -- interval // decreased by 4 instead of by 16, as the fp could be decreasing gamma // for a bit). Note that this should guarantee convergence, as it makes // sure that we always end up decreasing the interval width with a // bisection. if nFalseP > bisectIter { if w*bisectWidth > lastBisectWidth { state = bisect } nFalseP = 0 lastBisectWidth = w } } tol := absErr + relErr*math.Max(math.Max(math.Abs(x1), math.Abs(x2)), 1.0) if w <= tol { if math.Abs(f1) < math.Abs(f2) { bestX = x1 bestF = f1 } else { bestX = x2 bestF = f2 } return fSolveConverged, bestX, bestF, w } } return fSolveMaxIterations, x3, f3, w } golang-gonum-v1-gonum-0.14.0/mathext/zeta.go000066400000000000000000000013601450372207100206020ustar00rootroot00000000000000// Copyright ©2016 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 mathext import "gonum.org/v1/gonum/mathext/internal/cephes" // Zeta computes the Riemann zeta function of two arguments. // // Zeta(x,q) = \sum_{k=0}^{\infty} (k+q)^{-x} // // Note that Zeta returns +Inf if x is 1 and will panic if x is less than 1, // q is either zero or a negative integer, or q is negative and x is not an // integer. // // See http://mathworld.wolfram.com/HurwitzZetaFunction.html // or https://en.wikipedia.org/wiki/Multiple_zeta_function#Two_parameters_case // for more detailed information. func Zeta(x, q float64) float64 { return cephes.Zeta(x, q) } golang-gonum-v1-gonum-0.14.0/mathext/zeta_test.go000066400000000000000000000022711450372207100216430ustar00rootroot00000000000000// Copyright ©2016 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 mathext import ( "math" "testing" ) func TestZeta(t *testing.T) { t.Parallel() for i, test := range []struct { x, q, want float64 }{ // Results computed using scipy.special.zeta {1, 1, math.Inf(1)}, {1.00001, 0.5, 100001.96352290553}, {1.0001, 25, 9996.8017690244506}, {1.001, 1, 1000.5772884760117}, {1.01, 10, 97.773405639173305}, {1.5, 2, 1.6123753486854886}, {1.5, 20, 0.45287361712938717}, {2, -0.7, 14.28618087263834}, {2.5, 0.5, 6.2471106345688137}, {5, 2.5, 0.013073166646113805}, {7.5, 5, 7.9463377443314306e-06}, {10, -0.5, 2048.0174503557578}, {10, 0.5, 1024.0174503557578}, {10, 7.5, 2.5578265694201971e-9}, {12, 2.5, 1.7089167198843551e-5}, {17, 0.5, 131072.00101513157}, {20, -2.5, 2097152.0006014798}, {20, 0.75, 315.3368689825316}, {25, 0.25, 1125899906842624.0}, {30, 1, 1.0000000009313275}, } { if got := Zeta(test.x, test.q); math.Abs(got-test.want) > 1e-10 { t.Errorf("test %d Zeta(%g, %g) failed: got %g want %g", i, test.x, test.q, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/num/000077500000000000000000000000001450372207100164355ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/num/dual/000077500000000000000000000000001450372207100173625ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/num/dual/doc.go000066400000000000000000000010311450372207100204510ustar00rootroot00000000000000// 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 dual provides the dual numeric type and functions. Dual numbers // are an extension of the real numbers in the form a+bϵ where ϵ^2=0, but ϵ≠0. // // See https://en.wikipedia.org/wiki/Dual_number for details of their properties // and uses. package dual // imports "gonum.org/v1/gonum/num/dual" // TODO(kortschak): Handle special cases properly. // - Pow golang-gonum-v1-gonum-0.14.0/num/dual/dual.go000066400000000000000000000045261450372207100206450ustar00rootroot00000000000000// 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 dual import ( "fmt" "math" "strings" ) // Number is a float64 precision dual number. type Number struct { Real, Emag float64 } // Format implements fmt.Formatter. func (d Number) Format(fs fmt.State, c rune) { prec, pOk := fs.Precision() if !pOk { prec = -1 } width, wOk := fs.Width() if !wOk { width = -1 } switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T{Real:%#v, Emag:%#v}", d, d.Real, d.Emag) return } if fs.Flag('+') { fmt.Fprintf(fs, "{Real:%+v, Emag:%+v}", d.Real, d.Emag) return } c = 'g' prec = -1 fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': fre := fmtString(fs, c, prec, width, false) fim := fmtString(fs, c, prec, width, true) fmt.Fprintf(fs, fmt.Sprintf("(%s%[2]sϵ)", fre, fim), d.Real, d.Emag) default: fmt.Fprintf(fs, "%%!%c(%T=%[2]v)", c, d) return } } // This is horrible, but it's what we have. func fmtString(fs fmt.State, c rune, prec, width int, wantPlus bool) string { var b strings.Builder b.WriteByte('%') for _, f := range "0+- " { if fs.Flag(int(f)) || (f == '+' && wantPlus) { b.WriteByte(byte(f)) } } if width >= 0 { fmt.Fprint(&b, width) } if prec >= 0 { b.WriteByte('.') if prec > 0 { fmt.Fprint(&b, prec) } } b.WriteRune(c) return b.String() } // Add returns the sum of x and y. func Add(x, y Number) Number { return Number{ Real: x.Real + y.Real, Emag: x.Emag + y.Emag, } } // Sub returns the difference of x and y, x-y. func Sub(x, y Number) Number { return Number{ Real: x.Real - y.Real, Emag: x.Emag - y.Emag, } } // Mul returns the dual product of x and y. func Mul(x, y Number) Number { return Number{ Real: x.Real * y.Real, Emag: x.Real*y.Emag + x.Emag*y.Real, } } // Inv returns the dual inverse of d. // // Special cases are: // // Inv(±Inf) = ±0-0ϵ // Inv(±0) = ±Inf-Infϵ func Inv(d Number) Number { d2 := d.Real * d.Real return Number{ Real: 1 / d.Real, Emag: -d.Emag / d2, } } // Scale returns d scaled by f. func Scale(f float64, d Number) Number { return Number{Real: f * d.Real, Emag: f * d.Emag} } // Abs returns the absolute value of d. func Abs(d Number) Number { if !math.Signbit(d.Real) { return d } return Scale(-1, d) } golang-gonum-v1-gonum-0.14.0/num/dual/dual_example_test.go000066400000000000000000000013651450372207100234150ustar00rootroot00000000000000// 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 dual_test import ( "fmt" "gonum.org/v1/gonum/num/dual" ) func ExampleNumber_fike() { // Calculate the value and derivative of the function // e^x/(sqrt(sin(x)^3 + cos(x)^3)). fn := func(x dual.Number) dual.Number { return dual.Mul( dual.Exp(x), dual.Inv(dual.Sqrt( dual.Add( dual.PowReal(dual.Sin(x), 3), dual.PowReal(dual.Cos(x), 3))))) } v := fn(dual.Number{Real: 1.5, Emag: 1}) fmt.Printf("v=%.4f\n", v) fmt.Printf("fn(1.5)=%.4f\nfn'(1.5)=%.4f\n", v.Real, v.Emag) // Output: // // v=(4.4978+4.0534ϵ) // fn(1.5)=4.4978 // fn'(1.5)=4.0534 } golang-gonum-v1-gonum-0.14.0/num/dual/dual_fike.go000066400000000000000000000144561450372207100216460ustar00rootroot00000000000000// 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. // Derived from code by Jeffrey A. Fike at http://adl.stanford.edu/hyperdual/ // The MIT License (MIT) // // Copyright (c) 2006 Jeffrey A. Fike // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package dual import "math" // PowReal returns x**p, the base-x exponential of p. // // Special cases are (in order): // // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x // PowReal(x, ±0) = 1 for any x // PowReal(1+xϵ, y) = 1+xyϵ for any y // PowReal(x, 1) = x for any x // PowReal(NaN+xϵ, y) = NaN+NaNϵ // PowReal(x, NaN) = NaN+NaNϵ // PowReal(±0, y) = ±Inf for y an odd integer < 0 // PowReal(±0, -Inf) = +Inf // PowReal(±0, +Inf) = +0 // PowReal(±0, y) = +Inf for finite y < 0 and not an odd integer // PowReal(±0, y) = ±0 for y an odd integer > 0 // PowReal(±0, y) = +0 for finite y > 0 and not an odd integer // PowReal(-1, ±Inf) = 1 // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 // PowReal(x, +Inf) = +0+NaNϵ for |x| < 1 // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 // PowReal(+Inf, y) = +Inf for y > 0 // PowReal(+Inf, y) = +0 for y < 0 // PowReal(-Inf, y) = Pow(-0, -y) // PowReal(x, y) = NaN+NaNϵ for finite x < 0 and finite non-integer y func PowReal(d Number, p float64) Number { const tol = 1e-15 r := d.Real if math.Abs(r) < tol { if r >= 0 { r = tol } if r < 0 { r = -tol } } deriv := p * math.Pow(r, p-1) return Number{ Real: math.Pow(d.Real, p), Emag: d.Emag * deriv, } } // Pow returns d**r, the base-d exponential of r. func Pow(d, p Number) Number { return Exp(Mul(p, Log(d))) } // Sqrt returns the square root of d. // // Special cases are: // // Sqrt(+Inf) = +Inf // Sqrt(±0) = (±0+Infϵ) // Sqrt(x < 0) = NaN // Sqrt(NaN) = NaN func Sqrt(d Number) Number { if d.Real <= 0 { if d.Real == 0 { return Number{ Real: d.Real, Emag: math.Inf(1), } } return Number{ Real: math.NaN(), Emag: math.NaN(), } } return PowReal(d, 0.5) } // Exp returns e**q, the base-e exponential of d. // // Special cases are: // // Exp(+Inf) = +Inf // Exp(NaN) = NaN // // Very large values overflow to 0 or +Inf. // Very small values underflow to 1. func Exp(d Number) Number { fnDeriv := math.Exp(d.Real) return Number{ Real: fnDeriv, Emag: fnDeriv * d.Emag, } } // Log returns the natural logarithm of d. // // Special cases are: // // Log(+Inf) = (+Inf+0ϵ) // Log(0) = (-Inf±Infϵ) // Log(x < 0) = NaN // Log(NaN) = NaN func Log(d Number) Number { switch d.Real { case 0: return Number{ Real: math.Log(d.Real), Emag: math.Copysign(math.Inf(1), d.Real), } case math.Inf(1): return Number{ Real: math.Log(d.Real), Emag: 0, } } if d.Real < 0 { return Number{ Real: math.NaN(), Emag: math.NaN(), } } return Number{ Real: math.Log(d.Real), Emag: d.Emag / d.Real, } } // Sin returns the sine of d. // // Special cases are: // // Sin(±0) = (±0+Nϵ) // Sin(±Inf) = NaN // Sin(NaN) = NaN func Sin(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, Emag: d.Emag, } } fn := math.Sin(d.Real) deriv := math.Cos(d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Cos returns the cosine of d. // // Special cases are: // // Cos(±Inf) = NaN // Cos(NaN) = NaN func Cos(d Number) Number { fn := math.Cos(d.Real) deriv := -math.Sin(d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Tan returns the tangent of d. // // Special cases are: // // Tan(±0) = (±0+Nϵ) // Tan(±Inf) = NaN // Tan(NaN) = NaN func Tan(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, Emag: d.Emag, } } fn := math.Tan(d.Real) deriv := 1 + fn*fn return Number{ Real: fn, Emag: deriv * d.Emag, } } // Asin returns the inverse sine of d. // // Special cases are: // // Asin(±0) = (±0+Nϵ) // Asin(±1) = (±Inf+Infϵ) // Asin(x) = NaN if x < -1 or x > 1 func Asin(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, Emag: d.Emag, } } else if m := math.Abs(d.Real); m >= 1 { if m == 1 { return Number{ Real: math.Asin(d.Real), Emag: math.Inf(1), } } return Number{ Real: math.NaN(), Emag: math.NaN(), } } fn := math.Asin(d.Real) deriv := 1 / math.Sqrt(1-d.Real*d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Acos returns the inverse cosine of d. // // Special cases are: // // Acos(-1) = (Pi-Infϵ) // Acos(1) = (0-Infϵ) // Acos(x) = NaN if x < -1 or x > 1 func Acos(d Number) Number { if m := math.Abs(d.Real); m >= 1 { if m == 1 { return Number{ Real: math.Acos(d.Real), Emag: math.Inf(-1), } } return Number{ Real: math.NaN(), Emag: math.NaN(), } } fn := math.Acos(d.Real) deriv := -1 / math.Sqrt(1-d.Real*d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Atan returns the inverse tangent of d. // // Special cases are: // // Atan(±0) = (±0+Nϵ) // Atan(±Inf) = (±Pi/2+0ϵ) func Atan(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, Emag: d.Emag, } } fn := math.Atan(d.Real) deriv := 1 / (1 + d.Real*d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } golang-gonum-v1-gonum-0.14.0/num/dual/dual_hyperbolic.go000066400000000000000000000055201450372207100230600ustar00rootroot00000000000000// 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 dual import "math" // Sinh returns the hyperbolic sine of d. // // Special cases are: // // Sinh(±0) = (±0+Nϵ) // Sinh(±Inf) = ±Inf // Sinh(NaN) = NaN func Sinh(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, Emag: d.Emag, } } if math.IsInf(d.Real, 0) { return Number{ Real: d.Real, Emag: math.Inf(1), } } fn := math.Sinh(d.Real) deriv := math.Cosh(d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Cosh returns the hyperbolic cosine of d. // // Special cases are: // // Cosh(±0) = 1 // Cosh(±Inf) = +Inf // Cosh(NaN) = NaN func Cosh(d Number) Number { if math.IsInf(d.Real, 0) { return Number{ Real: math.Inf(1), Emag: d.Real, } } fn := math.Cosh(d.Real) deriv := math.Sinh(d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Tanh returns the hyperbolic tangent of d. // // Special cases are: // // Tanh(±0) = (±0+Nϵ) // Tanh(±Inf) = (±1+0ϵ) // Tanh(NaN) = NaN func Tanh(d Number) Number { switch d.Real { case 0: return Number{ Real: d.Real, Emag: d.Emag, } case math.Inf(1): return Number{ Real: 1, Emag: 0, } case math.Inf(-1): return Number{ Real: -1, Emag: 0, } } fn := math.Tanh(d.Real) deriv := 1 - fn*fn return Number{ Real: fn, Emag: deriv * d.Emag, } } // Asinh returns the inverse hyperbolic sine of d. // // Special cases are: // // Asinh(±0) = (±0+Nϵ) // Asinh(±Inf) = ±Inf // Asinh(NaN) = NaN func Asinh(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, Emag: d.Emag, } } fn := math.Asinh(d.Real) deriv := 1 / math.Sqrt(d.Real*d.Real+1) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Acosh returns the inverse hyperbolic cosine of d. // // Special cases are: // // Acosh(+Inf) = +Inf // Acosh(1) = (0+Infϵ) // Acosh(x) = NaN if x < 1 // Acosh(NaN) = NaN func Acosh(d Number) Number { if d.Real <= 1 { if d.Real == 1 { return Number{ Real: 0, Emag: math.Inf(1), } } return Number{ Real: math.NaN(), Emag: math.NaN(), } } fn := math.Acosh(d.Real) deriv := 1 / math.Sqrt(d.Real*d.Real-1) return Number{ Real: fn, Emag: deriv * d.Emag, } } // Atanh returns the inverse hyperbolic tangent of d. // // Special cases are: // // Atanh(1) = +Inf // Atanh(±0) = (±0+Nϵ) // Atanh(-1) = -Inf // Atanh(x) = NaN if x < -1 or x > 1 // Atanh(NaN) = NaN func Atanh(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, Emag: d.Emag, } } if math.Abs(d.Real) == 1 { return Number{ Real: math.Inf(int(d.Real)), Emag: math.NaN(), } } fn := math.Atanh(d.Real) deriv := 1 / (1 - d.Real*d.Real) return Number{ Real: fn, Emag: deriv * d.Emag, } } golang-gonum-v1-gonum-0.14.0/num/dual/dual_test.go000066400000000000000000000365511450372207100217070ustar00rootroot00000000000000// 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 dual import ( "fmt" "math" "testing" "gonum.org/v1/gonum/floats/scalar" ) var formatTests = []struct { d Number format string want string }{ {d: Number{1.1, 2.1}, format: "%#v", want: "dual.Number{Real:1.1, Emag:2.1}"}, // Bootstrap test. {d: Number{-1.1, -2.1}, format: "%#v", want: "dual.Number{Real:-1.1, Emag:-2.1}"}, // Bootstrap test. {d: Number{1.1, 2.1}, format: "%+v", want: "{Real:1.1, Emag:2.1}"}, {d: Number{-1.1, -2.1}, format: "%+v", want: "{Real:-1.1, Emag:-2.1}"}, {d: Number{1, 2}, format: "%v", want: "(1+2ϵ)"}, {d: Number{-1, -2}, format: "%v", want: "(-1-2ϵ)"}, {d: Number{1, 2}, format: "%g", want: "(1+2ϵ)"}, {d: Number{-1, -2}, format: "%g", want: "(-1-2ϵ)"}, {d: Number{1, 2}, format: "%e", want: "(1.000000e+00+2.000000e+00ϵ)"}, {d: Number{-1, -2}, format: "%e", want: "(-1.000000e+00-2.000000e+00ϵ)"}, {d: Number{1, 2}, format: "%E", want: "(1.000000E+00+2.000000E+00ϵ)"}, {d: Number{-1, -2}, format: "%E", want: "(-1.000000E+00-2.000000E+00ϵ)"}, {d: Number{1, 2}, format: "%f", want: "(1.000000+2.000000ϵ)"}, {d: Number{-1, -2}, format: "%f", want: "(-1.000000-2.000000ϵ)"}, } func TestFormat(t *testing.T) { t.Parallel() for _, test := range formatTests { got := fmt.Sprintf(test.format, test.d) if got != test.want { t.Errorf("unexpected result for fmt.Sprintf(%q, %#v): got:%q, want:%q", test.format, test.d, got, test.want) } } } // First derivatives: func dSin(x float64) float64 { return math.Cos(x) } func dCos(x float64) float64 { return -math.Sin(x) } func dTan(x float64) float64 { return sec(x) * sec(x) } func dAsin(x float64) float64 { return 1 / math.Sqrt(1-x*x) } func dAcos(x float64) float64 { return -1 / math.Sqrt(1-x*x) } func dAtan(x float64) float64 { return 1 / (1 + x*x) } func dSinh(x float64) float64 { return math.Cosh(x) } func dCosh(x float64) float64 { return math.Sinh(x) } func dTanh(x float64) float64 { return sech(x) * sech(x) } func dAsinh(x float64) float64 { return 1 / math.Sqrt(x*x+1) } func dAcosh(x float64) float64 { return 1 / (math.Sqrt(x-1) * math.Sqrt(x+1)) } func dAtanh(x float64) float64 { switch { case math.Abs(x) == 1: return math.NaN() case math.IsInf(x, 0): return negZero } return 1 / (1 - x*x) } func dExp(x float64) float64 { return math.Exp(x) } func dLog(x float64) float64 { if x < 0 { return math.NaN() } return 1 / x } func dSqrt(x float64) float64 { // For whatever reason, math.Sqrt(-0) returns -0. // In this case, that is clearly a wrong approach. if x == 0 { return math.Inf(1) } return 0.5 / math.Sqrt(x) } func dInv(x float64) float64 { return -1 / (x * x) } // Helpers: func sec(x float64) float64 { return 1 / math.Cos(x) } func sech(x float64) float64 { return 1 / math.Cosh(x) } var negZero = math.Float64frombits(1 << 63) var dualTests = []struct { name string x []float64 fnDual func(x Number) Number fn func(x float64) float64 dFn func(x float64) float64 }{ { name: "sin", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Sin, fn: math.Sin, dFn: dSin, }, { name: "cos", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Cos, fn: math.Cos, dFn: dCos, }, { name: "tan", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Tan, fn: math.Tan, dFn: dTan, }, { name: "sinh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Sinh, fn: math.Sinh, dFn: dSinh, }, { name: "cosh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Cosh, fn: math.Cosh, dFn: dCosh, }, { name: "tanh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Tanh, fn: math.Tanh, dFn: dTanh, }, { name: "asin", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Asin, fn: math.Asin, dFn: dAsin, }, { name: "acos", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Acos, fn: math.Acos, dFn: dAcos, }, { name: "atan", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Atan, fn: math.Atan, dFn: dAtan, }, { name: "asinh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Asinh, fn: math.Asinh, dFn: dAsinh, }, { name: "acosh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Acosh, fn: math.Acosh, dFn: dAcosh, }, { name: "atanh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Atanh, fn: math.Atanh, dFn: dAtanh, }, { name: "exp", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Exp, fn: math.Exp, dFn: dExp, }, { name: "log", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Log, fn: math.Log, dFn: dLog, }, { name: "inv", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Inv, fn: func(x float64) float64 { return 1 / x }, dFn: dInv, }, { name: "sqrt", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnDual: Sqrt, fn: math.Sqrt, dFn: dSqrt, }, { name: "Fike example fn", x: []float64{1, 2, 3, 4, 5}, fnDual: func(x Number) Number { return Mul( Exp(x), Inv(Sqrt( Add( PowReal(Sin(x), 3), PowReal(Cos(x), 3))))) }, fn: func(x float64) float64 { return math.Exp(x) / math.Sqrt(math.Pow(math.Sin(x), 3)+math.Pow(math.Cos(x), 3)) }, dFn: func(x float64) float64 { return math.Exp(x) * (3*math.Cos(x) + 5*math.Cos(3*x) + 9*math.Sin(x) + math.Sin(3*x)) / (8 * math.Pow(math.Pow(math.Sin(x), 3)+math.Pow(math.Cos(x), 3), 1.5)) }, }, } func TestDual(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range dualTests { for _, x := range test.x { fxDual := test.fnDual(Number{Real: x, Emag: 1}) fx := test.fn(x) dFx := test.dFn(x) if !same(fxDual.Real, fx, tol) { t.Errorf("unexpected %s(%v): got:%v want:%v", test.name, x, fxDual.Real, fx) } if !same(fxDual.Emag, dFx, tol) { t.Errorf("unexpected %s'(%v): got:%v want:%v", test.name, x, fxDual.Emag, dFx) } } } } var powRealTests = []struct { d Number p float64 want Number }{ // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x {d: Number{Real: math.NaN(), Emag: 0}, p: 0, want: Number{Real: 1, Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 0}, p: negZero, want: Number{Real: 1, Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 1}, p: 0, want: Number{Real: 1, Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 2}, p: negZero, want: Number{Real: 1, Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 3}, p: 0, want: Number{Real: 1, Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 1}, p: negZero, want: Number{Real: 1, Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 2}, p: 0, want: Number{Real: 1, Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 3}, p: negZero, want: Number{Real: 1, Emag: math.NaN()}}, // PowReal(x, ±0) = 1 for any x {d: Number{Real: 0, Emag: 0}, p: 0, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: negZero, Emag: 0}, p: negZero, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: math.Inf(1), Emag: 0}, p: 0, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: math.Inf(-1), Emag: 0}, p: negZero, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: 0, Emag: 1}, p: 0, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: negZero, Emag: 1}, p: negZero, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: math.Inf(1), Emag: 1}, p: 0, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: math.Inf(-1), Emag: 1}, p: negZero, want: Number{Real: 1, Emag: 0}}, // PowReal(1+xϵ, y) = (1+xyϵ) for any y {d: Number{Real: 1, Emag: 0}, p: 0, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: 1, Emag: 0}, p: 1, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: 1, Emag: 0}, p: 2, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: 1, Emag: 0}, p: 3, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: 1, Emag: 1}, p: 0, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: 1, Emag: 1}, p: 1, want: Number{Real: 1, Emag: 1}}, {d: Number{Real: 1, Emag: 1}, p: 2, want: Number{Real: 1, Emag: 2}}, {d: Number{Real: 1, Emag: 1}, p: 3, want: Number{Real: 1, Emag: 3}}, {d: Number{Real: 1, Emag: 2}, p: 0, want: Number{Real: 1, Emag: 0}}, {d: Number{Real: 1, Emag: 2}, p: 1, want: Number{Real: 1, Emag: 2}}, {d: Number{Real: 1, Emag: 2}, p: 2, want: Number{Real: 1, Emag: 4}}, {d: Number{Real: 1, Emag: 2}, p: 3, want: Number{Real: 1, Emag: 6}}, // PowReal(x, 1) = x for any x {d: Number{Real: 0, Emag: 0}, p: 1, want: Number{Real: 0, Emag: 0}}, {d: Number{Real: negZero, Emag: 0}, p: 1, want: Number{Real: negZero, Emag: 0}}, {d: Number{Real: 0, Emag: 1}, p: 1, want: Number{Real: 0, Emag: 1}}, {d: Number{Real: negZero, Emag: 1}, p: 1, want: Number{Real: negZero, Emag: 1}}, {d: Number{Real: math.NaN(), Emag: 0}, p: 1, want: Number{Real: math.NaN(), Emag: 0}}, {d: Number{Real: math.NaN(), Emag: 1}, p: 1, want: Number{Real: math.NaN(), Emag: 1}}, {d: Number{Real: math.NaN(), Emag: 2}, p: 1, want: Number{Real: math.NaN(), Emag: 2}}, // PowReal(NaN+xϵ, y) = NaN+NaNϵ {d: Number{Real: math.NaN(), Emag: 0}, p: 2, want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 0}, p: 3, want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 1}, p: 2, want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 1}, p: 3, want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 2}, p: 2, want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: math.NaN(), Emag: 2}, p: 3, want: Number{Real: math.NaN(), Emag: math.NaN()}}, // PowReal(x, NaN) = NaN+NaNϵ {d: Number{Real: 0, Emag: 0}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 2, Emag: 0}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 3, Emag: 0}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 0, Emag: 1}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 2, Emag: 1}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 3, Emag: 1}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 0, Emag: 2}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 2, Emag: 2}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: 3, Emag: 2}, p: math.NaN(), want: Number{Real: math.NaN(), Emag: math.NaN()}}, // Handled by math.Pow tests: // // Pow(±0, y) = ±Inf for y an odd integer < 0 // Pow(±0, -Inf) = +Inf // Pow(±0, +Inf) = +0 // Pow(±0, y) = +Inf for finite y < 0 and not an odd integer // Pow(±0, y) = ±0 for y an odd integer > 0 // Pow(±0, y) = +0 for finite y > 0 and not an odd integer // Pow(-1, ±Inf) = 1 // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 {d: Number{Real: 2, Emag: 0}, p: math.Inf(1), want: Number{Real: math.Inf(1), Emag: math.NaN()}}, {d: Number{Real: 3, Emag: 0}, p: math.Inf(1), want: Number{Real: math.Inf(1), Emag: math.NaN()}}, // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 {d: Number{Real: 2, Emag: 1}, p: math.Inf(1), want: Number{Real: math.Inf(1), Emag: math.Inf(1)}}, {d: Number{Real: 3, Emag: 1}, p: math.Inf(1), want: Number{Real: math.Inf(1), Emag: math.Inf(1)}}, {d: Number{Real: 2, Emag: 2}, p: math.Inf(1), want: Number{Real: math.Inf(1), Emag: math.Inf(1)}}, {d: Number{Real: 3, Emag: 2}, p: math.Inf(1), want: Number{Real: math.Inf(1), Emag: math.Inf(1)}}, // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 {d: Number{Real: 2, Emag: 0}, p: math.Inf(-1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 3, Emag: 0}, p: math.Inf(-1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 2, Emag: 1}, p: math.Inf(-1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 3, Emag: 1}, p: math.Inf(-1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 2, Emag: 2}, p: math.Inf(-1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 3, Emag: 2}, p: math.Inf(-1), want: Number{Real: 0, Emag: math.NaN()}}, // PowReal(x+yϵ, +Inf) = +0+NaNϵ for |x| < 1 {d: Number{Real: 0.1, Emag: 0}, p: math.Inf(1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 0.1, Emag: 0.1}, p: math.Inf(1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 0.2, Emag: 0.2}, p: math.Inf(1), want: Number{Real: 0, Emag: math.NaN()}}, {d: Number{Real: 0.5, Emag: 0.5}, p: math.Inf(1), want: Number{Real: 0, Emag: math.NaN()}}, // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 {d: Number{Real: 0.1, Emag: 0}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.NaN()}}, {d: Number{Real: 0.2, Emag: 0}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.NaN()}}, // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 {d: Number{Real: 0.1, Emag: 0.1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, {d: Number{Real: 0.2, Emag: 0.1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, {d: Number{Real: 0.1, Emag: 0.2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, {d: Number{Real: 0.2, Emag: 0.2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, {d: Number{Real: 0.1, Emag: 1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, {d: Number{Real: 0.2, Emag: 1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, {d: Number{Real: 0.1, Emag: 2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, {d: Number{Real: 0.2, Emag: 2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), Emag: math.Inf(-1)}}, // Handled by math.Pow tests: // // Pow(+Inf, y) = +Inf for y > 0 // Pow(+Inf, y) = +0 for y < 0 // Pow(-Inf, y) = Pow(-0, -y) // PowReal(x, y) = NaN+NaNϵ for finite x < 0 and finite non-integer y {d: Number{Real: -1, Emag: -1}, p: 0.5, want: Number{Real: math.NaN(), Emag: math.NaN()}}, {d: Number{Real: -1, Emag: 2}, p: 0.5, want: Number{Real: math.NaN(), Emag: math.NaN()}}, } func TestPowReal(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range powRealTests { got := PowReal(test.d, test.p) if !sameDual(got, test.want, tol) { t.Errorf("unexpected PowReal(%v, %v): got:%v want:%v", test.d, test.p, got, test.want) } } } func sameDual(a, b Number, tol float64) bool { return same(a.Real, b.Real, tol) && same(a.Emag, b.Emag, tol) } func same(a, b, tol float64) bool { return (math.IsNaN(a) && math.IsNaN(b)) || scalar.EqualWithinAbsOrRel(a, b, tol, tol) } golang-gonum-v1-gonum-0.14.0/num/dualcmplx/000077500000000000000000000000001450372207100204265ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/num/dualcmplx/doc.go000066400000000000000000000006741450372207100215310ustar00rootroot00000000000000// 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 dualcmplx provides the anti-commutative dual complex numeric // type and functions. // // See https://arxiv.org/abs/1601.01754v1 for details. package dualcmplx // imports "gonum.org/v1/gonum/num/dualcmplx" // TODO(kortschak): Handle special cases properly. // - Pow golang-gonum-v1-gonum-0.14.0/num/dualcmplx/dual.go000066400000000000000000000136631450372207100217130ustar00rootroot00000000000000// 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 dualcmplx import ( "fmt" "math" "math/cmplx" "strings" ) // Number is a float64 precision anti-commutative dual complex number. type Number struct { Real, Dual complex128 } // Format implements fmt.Formatter. func (d Number) Format(fs fmt.State, c rune) { prec, pOk := fs.Precision() if !pOk { prec = -1 } width, wOk := fs.Width() if !wOk { width = -1 } switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T{Real:%#v, Dual:%#v}", d, d.Real, d.Dual) return } if fs.Flag('+') { fmt.Fprintf(fs, "{Real:%+v, Dual:%+v}", d.Real, d.Dual) return } c = 'g' prec = -1 fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': fre := fmtString(fs, c, prec, width, false) fim := fmtString(fs, c, prec, width, true) fmt.Fprintf(fs, fmt.Sprintf("(%s+%[2]sϵ)", fre, fim), d.Real, d.Dual) default: fmt.Fprintf(fs, "%%!%c(%T=%[2]v)", c, d) return } } // This is horrible, but it's what we have. func fmtString(fs fmt.State, c rune, prec, width int, wantPlus bool) string { var b strings.Builder b.WriteByte('%') for _, f := range "0+- " { if fs.Flag(int(f)) || (f == '+' && wantPlus) { b.WriteByte(byte(f)) } } if width >= 0 { fmt.Fprint(&b, width) } if prec >= 0 { b.WriteByte('.') if prec > 0 { fmt.Fprint(&b, prec) } } b.WriteRune(c) return b.String() } // Add returns the sum of x and y. func Add(x, y Number) Number { return Number{ Real: x.Real + y.Real, Dual: x.Dual + y.Dual, } } // Sub returns the difference of x and y, x-y. func Sub(x, y Number) Number { return Number{ Real: x.Real - y.Real, Dual: x.Dual - y.Dual, } } // Mul returns the dual product of x and y, x×y. func Mul(x, y Number) Number { return Number{ Real: x.Real * y.Real, Dual: x.Real*y.Dual + x.Dual*cmplx.Conj(y.Real), } } // Inv returns the dual inverse of d. func Inv(d Number) Number { return Number{ Real: 1 / d.Real, Dual: -d.Dual / (d.Real * cmplx.Conj(d.Real)), } } // Conj returns the conjugate of d₁+d₂ϵ, d̅₁+d₂ϵ. func Conj(d Number) Number { return Number{ Real: cmplx.Conj(d.Real), Dual: d.Dual, } } // Scale returns d scaled by f. func Scale(f float64, d Number) Number { return Number{Real: complex(f, 0) * d.Real, Dual: complex(f, 0) * d.Dual} } // Abs returns the absolute value of d. func Abs(d Number) float64 { return cmplx.Abs(d.Real) } // PowReal returns d**p, the base-d exponential of p. // // Special cases are (in order): // // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x // Pow(0+xϵ, y) = 0+Infϵ for all y < 1. // Pow(0+xϵ, y) = 0 for all y > 1. // PowReal(x, ±0) = 1 for any x // PowReal(1+xϵ, y) = 1+xyϵ for any y // Pow(Inf, y) = +Inf+NaNϵ for y > 0 // Pow(Inf, y) = +0+NaNϵ for y < 0 // PowReal(x, 1) = x for any x // PowReal(NaN+xϵ, y) = NaN+NaNϵ // PowReal(x, NaN) = NaN+NaNϵ // PowReal(-1, ±Inf) = 1 // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 // PowReal(x, +Inf) = +0+NaNϵ for |x| < 1 // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 // PowReal(+Inf, y) = +Inf for y > 0 // PowReal(+Inf, y) = +0 for y < 0 // PowReal(-Inf, y) = Pow(-0, -y) func PowReal(d Number, p float64) Number { switch { case p == 0: switch { case cmplx.IsNaN(d.Real): return Number{Real: 1, Dual: cmplx.NaN()} case d.Real == 0, cmplx.IsInf(d.Real): return Number{Real: 1} } case p == 1: if cmplx.IsInf(d.Real) { d.Dual = cmplx.NaN() } return d case math.IsInf(p, 1): if d.Real == -1 { return Number{Real: 1, Dual: cmplx.NaN()} } if Abs(d) > 1 { if d.Dual == 0 { return Number{Real: cmplx.Inf(), Dual: cmplx.NaN()} } return Number{Real: cmplx.Inf(), Dual: cmplx.Inf()} } return Number{Real: 0, Dual: cmplx.NaN()} case math.IsInf(p, -1): if d.Real == -1 { return Number{Real: 1, Dual: cmplx.NaN()} } if Abs(d) > 1 { return Number{Real: 0, Dual: cmplx.NaN()} } if d.Dual == 0 { return Number{Real: cmplx.Inf(), Dual: cmplx.NaN()} } return Number{Real: cmplx.Inf(), Dual: cmplx.Inf()} case math.IsNaN(p): return Number{Real: cmplx.NaN(), Dual: cmplx.NaN()} case d.Real == 0: if p < 1 { return Number{Real: d.Real, Dual: cmplx.Inf()} } return Number{Real: d.Real} case cmplx.IsInf(d.Real): if p < 0 { return Number{Real: 0, Dual: cmplx.NaN()} } return Number{Real: cmplx.Inf(), Dual: cmplx.NaN()} } return Pow(d, Number{Real: complex(p, 0)}) } // Pow returns d**p, the base-d exponential of p. func Pow(d, p Number) Number { return Exp(Mul(p, Log(d))) } // Sqrt returns the square root of d. // // Special cases are: // // Sqrt(+Inf) = +Inf // Sqrt(±0) = (±0+Infϵ) // Sqrt(x < 0) = NaN // Sqrt(NaN) = NaN func Sqrt(d Number) Number { return PowReal(d, 0.5) } // Exp returns e**q, the base-e exponential of d. // // Special cases are: // // Exp(+Inf) = +Inf // Exp(NaN) = NaN // // Very large values overflow to 0 or +Inf. // Very small values underflow to 1. func Exp(d Number) Number { fn := cmplx.Exp(d.Real) if imag(d.Real) == 0 { return Number{Real: fn, Dual: fn * d.Dual} } conj := cmplx.Conj(d.Real) return Number{ Real: fn, Dual: ((fn - cmplx.Exp(conj)) / (d.Real - conj)) * d.Dual, } } // Log returns the natural logarithm of d. // // Special cases are: // // Log(+Inf) = (+Inf+0ϵ) // Log(0) = (-Inf±Infϵ) // Log(x < 0) = NaN // Log(NaN) = NaN func Log(d Number) Number { fn := cmplx.Log(d.Real) switch { case d.Real == 0: return Number{ Real: fn, Dual: complex(math.Copysign(math.Inf(1), real(d.Real)), math.NaN()), } case imag(d.Real) == 0: return Number{ Real: fn, Dual: d.Dual / d.Real, } case cmplx.IsInf(d.Real): return Number{ Real: fn, Dual: 0, } } conj := cmplx.Conj(d.Real) return Number{ Real: fn, Dual: ((fn - cmplx.Log(conj)) / (d.Real - conj)) * d.Dual, } } golang-gonum-v1-gonum-0.14.0/num/dualcmplx/dual_example_test.go000066400000000000000000000055741450372207100244670ustar00rootroot00000000000000// 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 dualcmplx_test import ( "fmt" "math" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/num/dualcmplx" ) // point is a 2-dimensional point/vector. type point struct { x, y float64 } // raise raises the dimensionality of a point to a complex. func raise(p point) complex128 { return complex(p.x, p.y) } // raiseDual raises the dimensionality of a point to a dual complex number. func raiseDual(p point) dualcmplx.Number { return dualcmplx.Number{ Real: 1, Dual: complex(p.x, p.y), } } // transform performs the transformation of p by the given dual complex numbers. // The transformations are normalized to unit vectors. func transform(p point, by ...dualcmplx.Number) point { if len(by) == 0 { return p } // Ensure the modulus of by is correctly scaled. for i := range by { if len := dualcmplx.Abs(by[i]); len != 1 { by[i].Real *= complex(1/len, 0) } } // Perform the transformations. z := by[0] for _, o := range by[1:] { z = dualcmplx.Mul(o, z) } pp := dualcmplx.Mul(dualcmplx.Mul(z, raiseDual(p)), dualcmplx.Conj(z)) // Extract the point. return point{x: real(pp.Dual), y: imag(pp.Dual)} } func Example() { // Translate a 1×1 square by [3, 4] and rotate it 90° around the // origin. fmt.Println("square:") // Construct a displacement. displace := dualcmplx.Number{ Real: 1, Dual: 0.5 * raise(point{3, 4}), } // Construct a rotation. alpha := math.Pi / 2 rotate := dualcmplx.Number{Real: complex(math.Cos(alpha/2), math.Sin(alpha/2))} for i, p := range []point{ {x: 0, y: 0}, {x: 0, y: 1}, {x: 1, y: 0}, {x: 1, y: 1}, } { pp := transform(p, displace, rotate, ) // Clean up floating point error for clarity. pp.x = scalar.Round(pp.x, 2) pp.y = scalar.Round(pp.y, 2) fmt.Printf(" %d %+v -> %+v\n", i, p, pp) } // Rotate a line segment 90° around its lower end [2, 2]. fmt.Println("\nline segment:") // Construct a displacement to the origin from the lower end... origin := dualcmplx.Number{ Real: 1, Dual: 0.5 * raise(point{-2, -2}), } // ... and back from the origin to the lower end. replace := dualcmplx.Number{ Real: 1, Dual: -origin.Dual, } for i, p := range []point{ {x: 2, y: 2}, {x: 2, y: 3}, } { pp := transform(p, origin, // Displace to origin. rotate, // Rotate around axis. replace, // Displace back to original location. ) // Clean up floating point error for clarity. pp.x = scalar.Round(pp.x, 2) pp.y = scalar.Round(pp.y, 2) fmt.Printf(" %d %+v -> %+v\n", i, p, pp) } // Output: // // square: // 0 {x:0 y:0} -> {x:-4 y:3} // 1 {x:0 y:1} -> {x:-5 y:3} // 2 {x:1 y:0} -> {x:-4 y:4} // 3 {x:1 y:1} -> {x:-5 y:4} // // line segment: // 0 {x:2 y:2} -> {x:2 y:2} // 1 {x:2 y:3} -> {x:1 y:2} } golang-gonum-v1-gonum-0.14.0/num/dualcmplx/dual_simple_example_test.go000066400000000000000000000051311450372207100260250ustar00rootroot00000000000000// 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 dualcmplx_test import ( "fmt" "math" "gonum.org/v1/gonum/num/dualcmplx" ) // Example point, displacement and rotation from Euclidean Space Dual Complex Number page: // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/other/dualComplex/index.htm func Example_displace() { // Displace a point [3, 4] by [4, 3]. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Displacement vector, half [4, 3], in the dual imaginary vector. d := dualcmplx.Number{Real: 1, Dual: 2 + 1.5i} fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(d, p), dualcmplx.Conj(d)).Dual) // Output: // // (7+7i) } func Example_rotate() { // Rotate a point [3, 4] by 90° around the origin. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Half the rotation in the real complex number. r := dualcmplx.Number{Real: complex(math.Cos(math.Pi/4), math.Sin(math.Pi/4))} fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(r, p), dualcmplx.Conj(r)).Dual) // Output: // // (-4+3i) } func Example_displaceAndRotate() { // Displace a point [3, 4] by [4, 3] and then rotate // by 90° around the origin. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Displacement vector, half [4, 3], in the dual imaginary vector. d := dualcmplx.Number{Real: 1, Dual: 2 + 1.5i} // Rotation in the real complex number. r := dualcmplx.Number{Real: complex(math.Cos(math.Pi/4), math.Sin(math.Pi/4))} // Combine the rotation and displacement so // the displacement is performed first. q := dualcmplx.Mul(r, d) fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(q, p), dualcmplx.Conj(q)).Dual) // Output: // // (-7+7i) } func Example_rotateAndDisplace() { // Rotate a point [3, 4] by 90° around the origin and then // displace by [4, 3]. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Displacement vector, half [4, 3], in the dual imaginary vector. d := dualcmplx.Number{Real: 1, Dual: 2 + 1.5i} // Rotation in the real complex number. r := dualcmplx.Number{Real: complex(math.Cos(math.Pi/4), math.Sin(math.Pi/4))} // Combine the rotation and displacement so // the displacement is performed first. q := dualcmplx.Mul(d, r) fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(q, p), dualcmplx.Conj(q)).Dual) // Output: // // (0+6i) } golang-gonum-v1-gonum-0.14.0/num/dualcmplx/dual_test.go000066400000000000000000000447151450372207100227540ustar00rootroot00000000000000// 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 dualcmplx import ( "fmt" "math" "math/cmplx" "testing" "gonum.org/v1/gonum/floats/scalar" ) var formatTests = []struct { d Number format string want string }{ {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%#v", want: "dualcmplx.Number{Real:(1.1+2.1i), Dual:(1.2+2.2i)}"}, // Bootstrap test. {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%#v", want: "dualcmplx.Number{Real:(-1.1-2.1i), Dual:(-1.2-2.2i)}"}, // Bootstrap test. {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%+v", want: "{Real:(1.1+2.1i), Dual:(1.2+2.2i)}"}, {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%+v", want: "{Real:(-1.1-2.1i), Dual:(-1.2-2.2i)}"}, {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%v", want: "((1.1+2.1i)+(+1.2+2.2i)ϵ)"}, {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%v", want: "((-1.1-2.1i)+(-1.2-2.2i)ϵ)"}, {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%g", want: "((1.1+2.1i)+(+1.2+2.2i)ϵ)"}, {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%g", want: "((-1.1-2.1i)+(-1.2-2.2i)ϵ)"}, {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%e", want: "((1.100000e+00+2.100000e+00i)+(+1.200000e+00+2.200000e+00i)ϵ)"}, {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%e", want: "((-1.100000e+00-2.100000e+00i)+(-1.200000e+00-2.200000e+00i)ϵ)"}, {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%E", want: "((1.100000E+00+2.100000E+00i)+(+1.200000E+00+2.200000E+00i)ϵ)"}, {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%E", want: "((-1.100000E+00-2.100000E+00i)+(-1.200000E+00-2.200000E+00i)ϵ)"}, {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%f", want: "((1.100000+2.100000i)+(+1.200000+2.200000i)ϵ)"}, {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%f", want: "((-1.100000-2.100000i)+(-1.200000-2.200000i)ϵ)"}, } func TestFormat(t *testing.T) { t.Parallel() for _, test := range formatTests { got := fmt.Sprintf(test.format, test.d) if got != test.want { t.Errorf("unexpected result for fmt.Sprintf(%q, %#v): got:%q, want:%q", test.format, test.d, got, test.want) } } } // FIXME(kortschak): See golang/go#29320. func sqrt(x complex128) complex128 { switch { case math.IsInf(imag(x), 1): return cmplx.Inf() case math.IsNaN(imag(x)): return cmplx.NaN() case math.IsInf(real(x), -1): if imag(x) >= 0 && !math.IsInf(imag(x), 1) { return complex(0, math.NaN()) } if math.IsNaN(imag(x)) { return complex(math.NaN(), math.Inf(1)) } case math.IsInf(real(x), 1): if imag(x) >= 0 && !math.IsInf(imag(x), 1) { return complex(math.Inf(1), 0) } if math.IsNaN(imag(x)) { return complex(math.Inf(1), math.NaN()) } case math.IsInf(real(x), -1): return complex(0, math.Inf(1)) case math.IsNaN(real(x)): if math.IsNaN(imag(x)) || math.IsInf(imag(x), 0) { return cmplx.NaN() } } return cmplx.Sqrt(x) } // First derivatives: func dExp(x complex128) complex128 { if imag(x) == 0 { return cmplx.Exp(x) } return (cmplx.Exp(x) - cmplx.Exp(cmplx.Conj(x))) / (x - cmplx.Conj(x)) } func dLog(x complex128) complex128 { if cmplx.IsInf(x) { return 0 } if x == 0 { if math.Copysign(1, real(x)) < 0 { return complex(math.Inf(-1), math.NaN()) } return complex(math.Inf(1), math.NaN()) } return (cmplx.Log(x) - cmplx.Log(cmplx.Conj(x))) / (x - cmplx.Conj(x)) } func dInv(x complex128) complex128 { return -1 / (x * cmplx.Conj(x)) } var ( negZero = math.Copysign(0, -1) zeroCmplx = 0 + 0i negZeroCmplx = -1 * zeroCmplx one = 1 + 1i negOne = -1 - 1i half = one / 2 negHalf = negOne / 2 two = 2 + 2i negTwo = -2 - 2i three = 3 + 3i negThree = -3 + 3i ) var dualTests = []struct { name string x []complex128 fnDual func(x Number) Number fn func(x complex128) complex128 dFn func(x complex128) complex128 }{ { name: "exp", x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, fnDual: Exp, fn: cmplx.Exp, dFn: dExp, }, { name: "log", x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, fnDual: Log, fn: cmplx.Log, dFn: dLog, }, { name: "inv", x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, fnDual: Inv, fn: func(x complex128) complex128 { return 1 / x }, dFn: dInv, }, { name: "sqrt", x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, fnDual: Sqrt, fn: sqrt, // TODO(kortschak): Find a concise dSqrt. }, } func TestNumber(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range dualTests { for _, x := range test.x { fxDual := test.fnDual(Number{Real: x, Dual: 1}) fx := test.fn(x) if !same(fxDual.Real, fx, tol) { t.Errorf("unexpected %s(%v): got:%v want:%v", test.name, x, fxDual.Real, fx) } if test.dFn == nil { continue } dFx := test.dFn(x) if !same(fxDual.Dual, dFx, tol) { t.Errorf("unexpected %s'(%v): got:%v want:%v", test.name, x, fxDual.Dual, dFx) } } } } var invTests = []Number{ {Real: 1, Dual: 0}, {Real: 1, Dual: 1}, {Real: 1i, Dual: 1}, {Real: 1, Dual: 1 + 1i}, {Real: 1 + 1i, Dual: 1 + 1i}, {Real: 1 + 10i, Dual: 1 + 5i}, {Real: 10 + 1i, Dual: 5 + 1i}, } func TestInv(t *testing.T) { t.Parallel() const tol = 1e-15 for _, x := range invTests { got := Mul(x, Inv(x)) want := Number{Real: 1} if !sameDual(got, want, tol) { t.Errorf("unexpected Mul(%[1]v, Inv(%[1]v)): got:%v want:%v", x, got, want) } } } var expLogTests = []Number{ {Real: 1i, Dual: 1i}, {Real: 1 + 1i, Dual: 1 + 1i}, {Real: 1 + 1e-1i, Dual: 1 + 1i}, {Real: 1 + 1e-2i, Dual: 1 + 1i}, {Real: 1 + 1e-4i, Dual: 1 + 1i}, {Real: 1 + 1e-6i, Dual: 1 + 1i}, {Real: 1 + 1e-8i, Dual: 1 + 1i}, {Real: 1 + 1e-10i, Dual: 1 + 1i}, {Real: 1 + 1e-12i, Dual: 1 + 1i}, {Real: 1 + 1e-14i, Dual: 1 + 1i}, {Dual: 1 + 1i}, {Dual: 1 + 2i}, {Dual: 2 + 1i}, {Dual: 2 + 2i}, {Dual: 1 + 1i}, {Dual: 1 + 5i}, {Dual: 5 + 1i}, {Real: 1 + 0i, Dual: 1 + 1i}, {Real: 1 + 0i, Dual: 1 + 2i}, {Real: 1 + 0i, Dual: 2 + 1i}, {Real: 1 + 0i, Dual: 2 + 2i}, {Real: 1 + 1i, Dual: 1 + 1i}, {Real: 1 + 3i, Dual: 1 + 5i}, {Real: 2 + 1i, Dual: 5 + 1i}, } func TestExpLog(t *testing.T) { t.Parallel() const tol = 1e-15 for _, x := range expLogTests { got := Log(Exp(x)) want := x if !sameDual(got, want, tol) { t.Errorf("unexpected Log(Exp(%v)): got:%v want:%v", x, got, want) } } } func TestLogExp(t *testing.T) { t.Parallel() const tol = 1e-15 for _, x := range expLogTests { if x.Real == 0 { continue } got := Exp(Log(x)) want := x if !sameDual(got, want, tol) { t.Errorf("unexpected Log(Exp(%v)): got:%v want:%v", x, got, want) } } } var powRealSpecialTests = []struct { d Number p float64 want Number }{ // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 0}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 2}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 3}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 1}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 3}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, // Pow(0+xϵ, y) = 0+Infϵ for all y < 1. {d: Number{Real: 0}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, {d: Number{Real: 0}, p: -1, want: Number{Dual: cmplx.Inf()}}, {d: Number{Dual: 1}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, {d: Number{Dual: 1}, p: -1, want: Number{Dual: cmplx.Inf()}}, {d: Number{Dual: 1 + 1i}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, {d: Number{Dual: 1 + 1i}, p: -1, want: Number{Dual: cmplx.Inf()}}, {d: Number{Dual: 1i}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, {d: Number{Dual: 1i}, p: -1, want: Number{Dual: cmplx.Inf()}}, // Pow(0+xϵ, y) = 0 for all y > 1. {d: Number{Real: 0}, p: 1.1, want: Number{Real: 0}}, {d: Number{Real: 0}, p: 2, want: Number{Real: 0}}, {d: Number{Dual: 1}, p: 1.1, want: Number{Real: 0}}, {d: Number{Dual: 1}, p: 2, want: Number{Real: 0}}, {d: Number{Dual: 1 + 1i}, p: 1.1, want: Number{Real: 0}}, {d: Number{Dual: 1 + 1i}, p: 2, want: Number{Real: 0}}, {d: Number{Dual: 1i}, p: 1.1, want: Number{Real: 0}}, {d: Number{Dual: 1i}, p: 2, want: Number{Real: 0}}, // PowReal(x, ±0) = 1 for any x {d: Number{Real: 0, Dual: 0}, p: 0, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: negZeroCmplx, Dual: 0}, p: negZero, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: cmplx.Inf(), Dual: 0}, p: 0, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: cmplx.Inf(), Dual: 0}, p: negZero, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: 0, Dual: 1}, p: 0, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: negZeroCmplx, Dual: 1}, p: negZero, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: cmplx.Inf(), Dual: 1}, p: 0, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: cmplx.Inf(), Dual: 1}, p: negZero, want: Number{Real: 1, Dual: 0}}, // PowReal(1+xϵ, y) = (1+xyϵ) for any y {d: Number{Real: 1, Dual: 0}, p: 0, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: 1, Dual: 0}, p: 1, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: 1, Dual: 0}, p: 2, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: 1, Dual: 0}, p: 3, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: 1, Dual: 1}, p: 0, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: 1, Dual: 1}, p: 1, want: Number{Real: 1, Dual: 1}}, {d: Number{Real: 1, Dual: 1}, p: 2, want: Number{Real: 1, Dual: 2}}, {d: Number{Real: 1, Dual: 1}, p: 3, want: Number{Real: 1, Dual: 3}}, {d: Number{Real: 1, Dual: 2}, p: 0, want: Number{Real: 1, Dual: 0}}, {d: Number{Real: 1, Dual: 2}, p: 1, want: Number{Real: 1, Dual: 2}}, {d: Number{Real: 1, Dual: 2}, p: 2, want: Number{Real: 1, Dual: 4}}, {d: Number{Real: 1, Dual: 2}, p: 3, want: Number{Real: 1, Dual: 6}}, // Pow(Inf, y) = +Inf+NaNϵ for y > 0 {d: Number{Real: cmplx.Inf()}, p: 0.5, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.Inf()}, p: 1, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.Inf()}, p: 1.1, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.Inf()}, p: 2, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, // Pow(Inf, y) = +0+NaNϵ for y < 0 {d: Number{Real: cmplx.Inf()}, p: -0.5, want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.Inf()}, p: -1, want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.Inf()}, p: -1.1, want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.Inf()}, p: -2, want: Number{Real: 0, Dual: cmplx.NaN()}}, // PowReal(x, 1) = x for any x {d: Number{Real: 0, Dual: 0}, p: 1, want: Number{Real: 0, Dual: 0}}, {d: Number{Real: negZeroCmplx, Dual: 0}, p: 1, want: Number{Real: negZeroCmplx, Dual: 0}}, {d: Number{Real: 0, Dual: 1}, p: 1, want: Number{Real: 0, Dual: 1}}, {d: Number{Real: negZeroCmplx, Dual: 1}, p: 1, want: Number{Real: negZeroCmplx, Dual: 1}}, {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 1, want: Number{Real: cmplx.NaN(), Dual: 0}}, {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 1, want: Number{Real: cmplx.NaN(), Dual: 1}}, {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 1, want: Number{Real: cmplx.NaN(), Dual: 2}}, // PowReal(NaN+xϵ, y) = NaN+NaNϵ {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 2, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 3, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 2, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 3, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 2, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 3, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, // PowReal(x, NaN) = NaN+NaNϵ {d: Number{Real: 0, Dual: 0}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 2, Dual: 0}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 3, Dual: 0}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 0, Dual: 1}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 2, Dual: 1}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 3, Dual: 1}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 0, Dual: 2}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 2, Dual: 2}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, {d: Number{Real: 3, Dual: 2}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, // Pow(-1, ±Inf) = 1 {d: Number{Real: -1}, p: math.Inf(-1), want: Number{Real: 1, Dual: cmplx.NaN()}}, {d: Number{Real: -1}, p: math.Inf(1), want: Number{Real: 1, Dual: cmplx.NaN()}}, // The following tests described for cmplx.Pow ar enot valid for this type and // are handled by the special cases Pow(0+xϵ, y) above. // Pow(±0, y) = ±Inf for y an odd integer < 0 // Pow(±0, -Inf) = +Inf // Pow(±0, +Inf) = +0 // Pow(±0, y) = +Inf for finite y < 0 and not an odd integer // Pow(±0, y) = ±0 for y an odd integer > 0 // Pow(±0, y) = +0 for finite y > 0 and not an odd integer // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 {d: Number{Real: 2, Dual: 0}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, {d: Number{Real: 3, Dual: 0}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 {d: Number{Real: 2, Dual: 1}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 3, Dual: 1}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 2, Dual: 2}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 3, Dual: 2}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 {d: Number{Real: 2, Dual: 0}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 3, Dual: 0}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 2, Dual: 1}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 3, Dual: 1}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 2, Dual: 2}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 3, Dual: 2}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, // PowReal(x+yϵ, +Inf) = +0+NaNϵ for |x| < 1 {d: Number{Real: 0.1, Dual: 0}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 0.1, Dual: 0.1}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 0.2, Dual: 0.2}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, {d: Number{Real: 0.5, Dual: 0.5}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 {d: Number{Real: 0.1, Dual: 0}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, {d: Number{Real: 0.2, Dual: 0}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 {d: Number{Real: 0.1, Dual: 0.1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 0.2, Dual: 0.1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 0.1, Dual: 0.2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 0.2, Dual: 0.2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 0.1, Dual: 1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 0.2, Dual: 1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 0.1, Dual: 2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, {d: Number{Real: 0.2, Dual: 2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, } func TestPowRealSpecial(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range powRealSpecialTests { got := PowReal(test.d, test.p) if !sameDual(got, test.want, tol) { t.Errorf("unexpected PowReal(%v, %v): got:%v want:%v", test.d, test.p, got, test.want) } } } var powRealTests = []struct { d Number p float64 }{ {d: Number{Real: 1e-1, Dual: 2 + 2i}, p: 0.2}, {d: Number{Real: 1e-1, Dual: 2 + 2i}, p: 5}, {d: Number{Real: 1e-2, Dual: 2 + 2i}, p: 0.2}, {d: Number{Real: 1e-2, Dual: 2 + 2i}, p: 5}, {d: Number{Real: 1e-3, Dual: 2 + 2i}, p: 0.2}, {d: Number{Real: 1e-3, Dual: 2 + 2i}, p: 5}, {d: Number{Real: 1e-4, Dual: 2 + 2i}, p: 0.2}, {d: Number{Real: 1e-4, Dual: 2 + 2i}, p: 5}, {d: Number{Real: 2, Dual: 0}, p: 0.5}, {d: Number{Real: 2, Dual: 0}, p: 2}, {d: Number{Real: 4, Dual: 0}, p: 0.5}, {d: Number{Real: 4, Dual: 0}, p: 2}, {d: Number{Real: 8, Dual: 0}, p: 1.0 / 3}, {d: Number{Real: 8, Dual: 0}, p: 3}, } func TestPowReal(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range powRealTests { got := PowReal(PowReal(test.d, test.p), 1/test.p) if !sameDual(got, test.d, tol) { t.Errorf("unexpected PowReal(PowReal(%v, %v), 1/%[2]v): got:%v want:%[1]v", test.d, test.p, got) } if test.p != math.Floor(test.p) { continue } root := PowReal(test.d, 1/test.p) got = Number{Real: 1} for i := 0; i < int(test.p); i++ { got = Mul(got, root) } if !sameDual(got, test.d, tol) { t.Errorf("unexpected PowReal(%v, 1/%v)^%[2]v: got:%v want:%[1]v", test.d, test.p, got) } } } func sameDual(a, b Number, tol float64) bool { return same(a.Real, b.Real, tol) && same(a.Dual, b.Dual, tol) } func same(a, b complex128, tol float64) bool { return ((math.IsNaN(real(a)) && (math.IsNaN(real(b)))) || scalar.EqualWithinAbsOrRel(real(a), real(b), tol, tol)) && ((math.IsNaN(imag(a)) && (math.IsNaN(imag(b)))) || scalar.EqualWithinAbsOrRel(imag(a), imag(b), tol, tol)) } golang-gonum-v1-gonum-0.14.0/num/dualquat/000077500000000000000000000000001450372207100202555ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/num/dualquat/doc.go000066400000000000000000000011451450372207100213520ustar00rootroot00000000000000// 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 dualquat provides the dual quaternion numeric type and functions. // // Dual quaternions provide a system for rigid transformation with interpolation // and blending in ℝ³. See https://www.cs.utah.edu/~ladislav/kavan06dual/kavan06dual.pdf and // https://en.wikipedia.org/wiki/Dual_quaternion for more details. package dualquat // imports "gonum.org/v1/gonum/num/dualquat" // TODO(kortschak): Handle special cases properly. // - Pow golang-gonum-v1-gonum-0.14.0/num/dualquat/dual.go000066400000000000000000000063251450372207100215370ustar00rootroot00000000000000// 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 dualquat import ( "fmt" "strings" "gonum.org/v1/gonum/num/dual" "gonum.org/v1/gonum/num/quat" ) // Number is a float64 precision dual quaternion. A dual quaternion // is a hypercomplex number composed of two quaternions, q₀+q₂ϵ, // where ϵ²=0, but ϵ≠0. Here, q₀ is termed the real and q₂ the dual. type Number struct { Real, Dual quat.Number } var zeroQuat quat.Number // Format implements fmt.Formatter. func (d Number) Format(fs fmt.State, c rune) { prec, pOk := fs.Precision() if !pOk { prec = -1 } width, wOk := fs.Width() if !wOk { width = -1 } switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T{Real:%#v, Dual:%#v}", d, d.Real, d.Dual) return } if fs.Flag('+') { fmt.Fprintf(fs, "{Real:%+v, Dual:%+v}", d.Real, d.Dual) return } c = 'g' prec = -1 fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': fre := fmtString(fs, c, prec, width, false) fim := fmtString(fs, c, prec, width, true) fmt.Fprintf(fs, fmt.Sprintf("(%s+%[2]sϵ)", fre, fim), d.Real, d.Dual) default: fmt.Fprintf(fs, "%%!%c(%T=%[2]v)", c, d) return } } // This is horrible, but it's what we have. func fmtString(fs fmt.State, c rune, prec, width int, wantPlus bool) string { var b strings.Builder b.WriteByte('%') for _, f := range "0+- " { if fs.Flag(int(f)) || (f == '+' && wantPlus) { b.WriteByte(byte(f)) } } if width >= 0 { fmt.Fprint(&b, width) } if prec >= 0 { b.WriteByte('.') if prec > 0 { fmt.Fprint(&b, prec) } } b.WriteRune(c) return b.String() } // Add returns the sum of x and y. func Add(x, y Number) Number { return Number{ Real: quat.Add(x.Real, y.Real), Dual: quat.Add(x.Dual, y.Dual), } } // Sub returns the difference of x and y, x-y. func Sub(x, y Number) Number { return Number{ Real: quat.Sub(x.Real, y.Real), Dual: quat.Sub(x.Dual, y.Dual), } } // Mul returns the dual product of x and y. func Mul(x, y Number) Number { return Number{ Real: quat.Mul(x.Real, y.Real), Dual: quat.Add(quat.Mul(x.Real, y.Dual), quat.Mul(x.Dual, y.Real)), } } // Inv returns the dual inverse of d. func Inv(d Number) Number { return Number{ Real: quat.Inv(d.Real), Dual: quat.Scale(-1, quat.Mul(d.Dual, quat.Inv(quat.Mul(d.Real, d.Real)))), } } // Conj returns the dual quaternion conjugate of d₁+d₂ϵ, d̅₁-d̅₂ϵ. func Conj(d Number) Number { return Number{ Real: quat.Conj(d.Real), Dual: quat.Scale(-1, quat.Conj(d.Dual)), } } // ConjDual returns the dual conjugate of d₁+d₂ϵ, d₁-d₂ϵ. func ConjDual(d Number) Number { return Number{ Real: d.Real, Dual: quat.Scale(-1, d.Dual), } } // ConjQuat returns the quaternion conjugate of d₁+d₂ϵ, d̅₁+d̅₂ϵ. func ConjQuat(d Number) Number { return Number{ Real: quat.Conj(d.Real), Dual: quat.Conj(d.Dual), } } // Scale returns d scaled by f. func Scale(f float64, d Number) Number { return Number{Real: quat.Scale(f, d.Real), Dual: quat.Scale(f, d.Dual)} } // Abs returns the absolute value of d. func Abs(d Number) dual.Number { return dual.Number{ Real: quat.Abs(d.Real), Emag: quat.Abs(d.Dual), } } golang-gonum-v1-gonum-0.14.0/num/dualquat/dual_example_test.go000066400000000000000000000071631450372207100243120ustar00rootroot00000000000000// 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 dualquat_test import ( "fmt" "math" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/num/dualquat" "gonum.org/v1/gonum/num/quat" ) // point is a 3-dimensional point/vector. type point struct { x, y, z float64 } // raise raises the dimensionality of a point to a quaternion. func raise(p point) quat.Number { return quat.Number{Imag: p.x, Jmag: p.y, Kmag: p.z} } // raiseDual raises the dimensionality of a point to a dual quaternion. func raiseDual(p point) dualquat.Number { return dualquat.Number{ Real: quat.Number{Real: 1}, Dual: raise(p), } } // transform performs the transformation of p by the given dual quaternions. // The transformations are normalized to unit vectors. func transform(p point, by ...dualquat.Number) point { if len(by) == 0 { return p } // Ensure the modulus of by is correctly scaled. for i := range by { if len := quat.Abs(by[i].Real); len != 1 { by[i].Real = quat.Scale(1/len, by[i].Real) } } // Perform the transformations. q := by[0] for _, o := range by[1:] { q = dualquat.Mul(o, q) } pp := dualquat.Mul(dualquat.Mul(q, raiseDual(p)), dualquat.Conj(q)) // Extract the point. return point{x: pp.Dual.Imag, y: pp.Dual.Jmag, z: pp.Dual.Kmag} } func Example() { // Translate a 1×1×1 cube by [3, 4, 5] and rotate it 120° around the // diagonal vector [1, 1, 1]. fmt.Println("cube:") // Construct a displacement. displace := dualquat.Number{ Real: quat.Number{Real: 1}, Dual: quat.Scale(0.5, raise(point{3, 4, 5})), } // Construct a rotations. alpha := 2 * math.Pi / 3 axis := raise(point{1, 1, 1}) rotate := dualquat.Number{Real: axis} rotate.Real = quat.Scale(math.Sin(alpha/2)/quat.Abs(rotate.Real), rotate.Real) rotate.Real.Real += math.Cos(alpha / 2) for i, p := range []point{ {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 1}, {x: 0, y: 1, z: 0}, {x: 0, y: 1, z: 1}, {x: 1, y: 0, z: 0}, {x: 1, y: 0, z: 1}, {x: 1, y: 1, z: 0}, {x: 1, y: 1, z: 1}, } { pp := transform(p, displace, rotate, ) // Clean up floating point error for clarity. pp.x = scalar.Round(pp.x, 2) pp.y = scalar.Round(pp.y, 2) pp.z = scalar.Round(pp.z, 2) fmt.Printf(" %d %+v -> %+v\n", i, p, pp) } // Rotate a line segment from {[2, 1, 1], [2, 1, 2]} 120° around // the diagonal vector [1, 1, 1] at its lower end. fmt.Println("\nline segment:") // Construct an displacement to the origin from the lower end... origin := dualquat.Number{ Real: quat.Number{Real: 1}, Dual: quat.Scale(0.5, raise(point{-2, -1, -1})), } // ... and back from the origin to the lower end. replace := dualquat.Number{ Real: quat.Number{Real: 1}, Dual: quat.Scale(-1, origin.Dual), } for i, p := range []point{ {x: 2, y: 1, z: 1}, {x: 2, y: 1, z: 2}, } { pp := transform(p, origin, // Displace to origin. rotate, // Rotate around axis. replace, // Displace back to original location. ) // Clean up floating point error for clarity. pp.x = scalar.Round(pp.x, 2) pp.y = scalar.Round(pp.y, 2) pp.z = scalar.Round(pp.z, 2) fmt.Printf(" %d %+v -> %+v\n", i, p, pp) } // Output: // // cube: // 0 {x:0 y:0 z:0} -> {x:5 y:3 z:4} // 1 {x:0 y:0 z:1} -> {x:6 y:3 z:4} // 2 {x:0 y:1 z:0} -> {x:5 y:3 z:5} // 3 {x:0 y:1 z:1} -> {x:6 y:3 z:5} // 4 {x:1 y:0 z:0} -> {x:5 y:4 z:4} // 5 {x:1 y:0 z:1} -> {x:6 y:4 z:4} // 6 {x:1 y:1 z:0} -> {x:5 y:4 z:5} // 7 {x:1 y:1 z:1} -> {x:6 y:4 z:5} // // line segment: // 0 {x:2 y:1 z:1} -> {x:2 y:1 z:1} // 1 {x:2 y:1 z:2} -> {x:3 y:1 z:1} } golang-gonum-v1-gonum-0.14.0/num/dualquat/dual_fike.go000066400000000000000000000107021450372207100225270ustar00rootroot00000000000000// 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. // Derived from code by Jeffrey A. Fike at http://adl.stanford.edu/hyperdual/ // The MIT License (MIT) // // Copyright (c) 2006 Jeffrey A. Fike // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package dualquat import ( "math" "gonum.org/v1/gonum/num/quat" ) // PowReal returns d**p, the base-d exponential of p. // // Special cases are (in order): // // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x // PowReal(x, ±0) = 1 for any x // PowReal(1+xϵ, y) = 1+xyϵ for any y // PowReal(x, 1) = x for any x // PowReal(NaN+xϵ, y) = NaN+NaNϵ // PowReal(x, NaN) = NaN+NaNϵ // PowReal(±0, y) = ±Inf for y an odd integer < 0 // PowReal(±0, -Inf) = +Inf // PowReal(±0, +Inf) = +0 // PowReal(±0, y) = +Inf for finite y < 0 and not an odd integer // PowReal(±0, y) = ±0 for y an odd integer > 0 // PowReal(±0, y) = +0 for finite y > 0 and not an odd integer // PowReal(-1, ±Inf) = 1 // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 // PowReal(x, +Inf) = +0+NaNϵ for |x| < 1 // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 // PowReal(+Inf, y) = +Inf for y > 0 // PowReal(+Inf, y) = +0 for y < 0 // PowReal(-Inf, y) = Pow(-0, -y) func PowReal(d Number, p float64) Number { switch { case p == 0: switch { case quat.IsNaN(d.Real): return Number{Real: quat.Number{Real: 1}, Dual: quat.NaN()} case d.Real == zeroQuat, quat.IsInf(d.Real): return Number{Real: quat.Number{Real: 1}} } case p == 1: return d case math.IsInf(p, 1): if Abs(d).Real > 1 { if d.Dual == zeroQuat { return Number{Real: quat.Inf(), Dual: quat.NaN()} } return Number{Real: quat.Inf(), Dual: quat.Inf()} } return Number{Real: zeroQuat, Dual: quat.NaN()} case math.IsInf(p, -1): if Abs(d).Real > 1 { return Number{Real: zeroQuat, Dual: quat.NaN()} } if d.Dual == zeroQuat { return Number{Real: quat.Inf(), Dual: quat.NaN()} } return Number{Real: quat.Inf(), Dual: quat.Inf()} } deriv := quat.Mul(quat.Number{Real: p}, quat.Pow(d.Real, quat.Number{Real: p - 1})) return Number{ Real: quat.Pow(d.Real, quat.Number{Real: p}), Dual: quat.Mul(d.Dual, deriv), } } // Pow return d**p, the base-d exponential of p. func Pow(d, p Number) Number { return Exp(Mul(p, Log(d))) } // Sqrt returns the square root of d // // Special cases are: // // Sqrt(+Inf) = +Inf // Sqrt(±0) = (±0+Infϵ) // Sqrt(x < 0) = NaN // Sqrt(NaN) = NaN func Sqrt(d Number) Number { return PowReal(d, 0.5) } // Exp returns e**d, the base-e exponential of d. // // Special cases are: // // Exp(+Inf) = +Inf // Exp(NaN) = NaN // // Very large values overflow to 0 or +Inf. // Very small values underflow to 1. func Exp(d Number) Number { fnDeriv := quat.Exp(d.Real) return Number{ Real: fnDeriv, Dual: quat.Mul(fnDeriv, d.Dual), } } // Log returns the natural logarithm of d. // // Special cases are: // // Log(+Inf) = (+Inf+0ϵ) // Log(0) = (-Inf±Infϵ) // Log(x < 0) = NaN // Log(NaN) = NaN func Log(d Number) Number { switch { case d.Real == zeroQuat: return Number{ Real: quat.Log(d.Real), Dual: quat.Inf(), } case quat.IsInf(d.Real): return Number{ Real: quat.Log(d.Real), Dual: zeroQuat, } } return Number{ Real: quat.Log(d.Real), Dual: quat.Mul(d.Dual, quat.Inv(d.Real)), } } golang-gonum-v1-gonum-0.14.0/num/dualquat/dual_simple_example_test.go000066400000000000000000000057531450372207100256660ustar00rootroot00000000000000// 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 dualquat_test import ( "fmt" "gonum.org/v1/gonum/num/dualquat" "gonum.org/v1/gonum/num/quat" ) func Example_displace() { // Displace a point [3, 4, 5] by [4, 2, 6]. // See http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/other/dualQuaternion/index.htm // Point to be transformed in the dual imaginary vector. p := dualquat.Number{Real: quat.Number{Real: 1}, Dual: quat.Number{Imag: 3, Jmag: 4, Kmag: 5}} // Displacement vector, half [4, 2, 6], in the dual imaginary vector. d := dualquat.Number{Real: quat.Number{Real: 1}, Dual: quat.Number{Imag: 2, Jmag: 1, Kmag: 3}} fmt.Println(dualquat.Mul(dualquat.Mul(d, p), dualquat.Conj(d)).Dual) // Output: // // (0+7i+6j+11k) } func Example_rotate() { // Rotate a point [3, 4, 5] by 180° around the x axis. // See http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/other/dualQuaternion/index.htm // Point to be transformed in the dual imaginary vector. p := dualquat.Number{Real: quat.Number{Real: 1}, Dual: quat.Number{Imag: 3, Jmag: 4, Kmag: 5}} // Rotation in the real quaternion. r := dualquat.Number{Real: quat.Number{Real: 0, Imag: 1}} fmt.Println(dualquat.Mul(dualquat.Mul(r, p), dualquat.Conj(r)).Dual) // Output: // // (0+3i-4j-5k) } func Example_displaceAndRotate() { // Displace a point [3, 4, 5] by [4, 2, 6] and then rotate // by 180° around the x axis. // See http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/other/dualQuaternion/index.htm // Point to be transformed in the dual imaginary vector. p := dualquat.Number{Real: quat.Number{Real: 1}, Dual: quat.Number{Imag: 3, Jmag: 4, Kmag: 5}} // Displacement vector, half [4, 2, 6], in the dual imaginary vector. d := dualquat.Number{Real: quat.Number{Real: 1}, Dual: quat.Number{Imag: 2, Jmag: 1, Kmag: 3}} // Rotation in the real quaternion. r := dualquat.Number{Real: quat.Number{Real: 0, Imag: 1}} // Combine the rotation and displacement so // the displacement is performed first. q := dualquat.Mul(r, d) fmt.Println(dualquat.Mul(dualquat.Mul(q, p), dualquat.Conj(q)).Dual) // Output: // // (0+7i-6j-11k) } func Example_rotateAndDisplace() { // Rotate a point [3, 4, 5] by 180° around the x axis and then // displace by [4, 2, 6] // Point to be transformed in the dual imaginary vector. p := dualquat.Number{Real: quat.Number{Real: 1}, Dual: quat.Number{Imag: 3, Jmag: 4, Kmag: 5}} // Displacement vector, half [4, 2, 6], in the dual imaginary vector. d := dualquat.Number{Real: quat.Number{Real: 1}, Dual: quat.Number{Imag: 2, Jmag: 1, Kmag: 3}} // Rotation in the real quaternion. r := dualquat.Number{Real: quat.Number{Real: 0, Imag: 1}} // Combine the rotation and displacement so // the rotations is performed first. q := dualquat.Mul(d, r) fmt.Println(dualquat.Mul(dualquat.Mul(q, p), dualquat.Conj(q)).Dual) // Output: // // (0+7i-2j+1k) } golang-gonum-v1-gonum-0.14.0/num/dualquat/dual_test.go000066400000000000000000000417611450372207100226010ustar00rootroot00000000000000// 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 dualquat import ( "fmt" "math" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/num/quat" ) var formatTests = []struct { d Number format string want string }{ {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%#v", want: "dualquat.Number{Real:quat.Number{Real:1.1, Imag:2.1, Jmag:3.1, Kmag:4.1}, Dual:quat.Number{Real:1.2, Imag:2.2, Jmag:3.2, Kmag:4.2}}"}, // Bootstrap test. {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%#v", want: "dualquat.Number{Real:quat.Number{Real:-1.1, Imag:-2.1, Jmag:-3.1, Kmag:-4.1}, Dual:quat.Number{Real:-1.2, Imag:-2.2, Jmag:-3.2, Kmag:-4.2}}"}, // Bootstrap test. {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%+v", want: "{Real:{Real:1.1, Imag:2.1, Jmag:3.1, Kmag:4.1}, Dual:{Real:1.2, Imag:2.2, Jmag:3.2, Kmag:4.2}}"}, {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%+v", want: "{Real:{Real:-1.1, Imag:-2.1, Jmag:-3.1, Kmag:-4.1}, Dual:{Real:-1.2, Imag:-2.2, Jmag:-3.2, Kmag:-4.2}}"}, {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%v", want: "((1.1+2.1i+3.1j+4.1k)+(+1.2+2.2i+3.2j+4.2k)ϵ)"}, {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%v", want: "((-1.1-2.1i-3.1j-4.1k)+(-1.2-2.2i-3.2j-4.2k)ϵ)"}, {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%g", want: "((1.1+2.1i+3.1j+4.1k)+(+1.2+2.2i+3.2j+4.2k)ϵ)"}, {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%g", want: "((-1.1-2.1i-3.1j-4.1k)+(-1.2-2.2i-3.2j-4.2k)ϵ)"}, {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%e", want: "((1.100000e+00+2.100000e+00i+3.100000e+00j+4.100000e+00k)+(+1.200000e+00+2.200000e+00i+3.200000e+00j+4.200000e+00k)ϵ)"}, {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%e", want: "((-1.100000e+00-2.100000e+00i-3.100000e+00j-4.100000e+00k)+(-1.200000e+00-2.200000e+00i-3.200000e+00j-4.200000e+00k)ϵ)"}, {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%E", want: "((1.100000E+00+2.100000E+00i+3.100000E+00j+4.100000E+00k)+(+1.200000E+00+2.200000E+00i+3.200000E+00j+4.200000E+00k)ϵ)"}, {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%E", want: "((-1.100000E+00-2.100000E+00i-3.100000E+00j-4.100000E+00k)+(-1.200000E+00-2.200000E+00i-3.200000E+00j-4.200000E+00k)ϵ)"}, {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%f", want: "((1.100000+2.100000i+3.100000j+4.100000k)+(+1.200000+2.200000i+3.200000j+4.200000k)ϵ)"}, {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%f", want: "((-1.100000-2.100000i-3.100000j-4.100000k)+(-1.200000-2.200000i-3.200000j-4.200000k)ϵ)"}, } func TestFormat(t *testing.T) { t.Parallel() for _, test := range formatTests { got := fmt.Sprintf(test.format, test.d) if got != test.want { t.Errorf("unexpected result for fmt.Sprintf(%q, %#v): got:%q, want:%q", test.format, test.d, got, test.want) } } } // First derivatives: func dExp(x quat.Number) quat.Number { return quat.Exp(x) } func dLog(x quat.Number) quat.Number { switch { case x == zeroQuat: return quat.Inf() case quat.IsInf(x): return zeroQuat } return quat.Inv(x) } func dSqrt(x quat.Number) quat.Number { return quat.Scale(0.5, quat.Inv(quat.Sqrt(x))) } func dInv(x quat.Number) quat.Number { return quat.Scale(-1, quat.Inv(quat.Mul(x, x))) } var ( negZero = math.Copysign(0, -1) oneReal = quat.Number{Real: 1} negZeroQuat = quat.Scale(-1, zeroQuat) one = quat.Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1} negOne = quat.Scale(-1, one) half = quat.Scale(0.5, one) negHalf = quat.Scale(-1, half) two = quat.Scale(2, one) negTwo = quat.Scale(-1, two) three = quat.Scale(3, one) negThree = quat.Scale(-1, three) four = quat.Scale(4, one) six = quat.Scale(6, one) ) var dualTests = []struct { name string x []quat.Number fnDual func(x Number) Number fn func(x quat.Number) quat.Number dFn func(x quat.Number) quat.Number }{ { name: "exp", x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, fnDual: Exp, fn: quat.Exp, dFn: dExp, }, { name: "log", x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, fnDual: Log, fn: quat.Log, dFn: dLog, }, { name: "inv", x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, fnDual: Inv, fn: quat.Inv, dFn: dInv, }, { name: "sqrt", x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, fnDual: Sqrt, fn: quat.Sqrt, dFn: dSqrt, }, } func TestNumber(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range dualTests { for _, x := range test.x { fxDual := test.fnDual(Number{Real: x, Dual: oneReal}) fx := test.fn(x) dFx := test.dFn(x) if !same(fxDual.Real, fx, tol) { t.Errorf("unexpected %s(%v): got:%v want:%v", test.name, x, fxDual.Real, fx) } if !same(fxDual.Dual, dFx, tol) { t.Errorf("unexpected %s'(%v): got:%v want:%v", test.name, x, fxDual.Dual, dFx) } } } } var invTests = []Number{ {Real: quat.Number{Real: 1}}, {Real: quat.Number{Real: 1}, Dual: quat.Number{Real: 1}}, {Real: quat.Number{Imag: 1}, Dual: quat.Number{Real: 1}}, {Real: quat.Number{Real: 1}, Dual: quat.Number{Real: 1, Imag: 1}}, {Real: quat.Number{Real: 1, Imag: 1}, Dual: quat.Number{Real: 1, Imag: 1}}, {Real: quat.Number{Real: 1, Imag: 10}, Dual: quat.Number{Real: 1, Imag: 5}}, {Real: quat.Number{Real: 10, Imag: 1}, Dual: quat.Number{Real: 5, Imag: 1}}, {Real: quat.Number{Real: 1}, Dual: quat.Number{Real: 1, Imag: 1, Kmag: 1}}, {Real: quat.Number{Real: 12, Imag: 1}, Dual: quat.Number{Real: 1, Imag: 1}}, {Real: quat.Number{Real: 12, Imag: 1, Jmag: 3}}, } func TestInv(t *testing.T) { t.Parallel() const tol = 1e-15 for _, x := range invTests { got := Mul(x, Inv(x)) want := Number{Real: quat.Number{Real: 1}} if !sameDual(got, want, tol) { t.Errorf("unexpected Mul(%[1]v, Inv(%[1]v)): got:%v want:%v", x, got, want) } } } var powRealTests = []struct { d Number p float64 want Number }{ // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: one}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: two}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: three}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: one}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: two}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: three}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, // PowReal(x, ±0) = 1 for any x {d: Number{Real: zeroQuat, Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: negZeroQuat, Dual: zeroQuat}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: quat.Inf(), Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: quat.Inf(), Dual: zeroQuat}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: zeroQuat, Dual: one}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: negZeroQuat, Dual: one}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: quat.Inf(), Dual: one}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: quat.Inf(), Dual: one}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, // PowReal(1+xϵ, y) = (1+xyϵ) for any y {d: Number{Real: oneReal, Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: oneReal, Dual: zeroQuat}, p: 1, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: oneReal, Dual: zeroQuat}, p: 2, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: oneReal, Dual: zeroQuat}, p: 3, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: oneReal, Dual: one}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: oneReal, Dual: one}, p: 1, want: Number{Real: oneReal, Dual: one}}, {d: Number{Real: oneReal, Dual: one}, p: 2, want: Number{Real: oneReal, Dual: two}}, {d: Number{Real: oneReal, Dual: one}, p: 3, want: Number{Real: oneReal, Dual: three}}, {d: Number{Real: oneReal, Dual: two}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, {d: Number{Real: oneReal, Dual: two}, p: 1, want: Number{Real: oneReal, Dual: two}}, {d: Number{Real: oneReal, Dual: two}, p: 2, want: Number{Real: oneReal, Dual: four}}, {d: Number{Real: oneReal, Dual: two}, p: 3, want: Number{Real: oneReal, Dual: six}}, // PowReal(x, 1) = x for any x {d: Number{Real: zeroQuat, Dual: zeroQuat}, p: 1, want: Number{Real: zeroQuat, Dual: zeroQuat}}, {d: Number{Real: negZeroQuat, Dual: zeroQuat}, p: 1, want: Number{Real: negZeroQuat, Dual: zeroQuat}}, {d: Number{Real: zeroQuat, Dual: one}, p: 1, want: Number{Real: zeroQuat, Dual: one}}, {d: Number{Real: negZeroQuat, Dual: one}, p: 1, want: Number{Real: negZeroQuat, Dual: one}}, {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 1, want: Number{Real: quat.NaN(), Dual: zeroQuat}}, {d: Number{Real: quat.NaN(), Dual: one}, p: 1, want: Number{Real: quat.NaN(), Dual: one}}, {d: Number{Real: quat.NaN(), Dual: two}, p: 1, want: Number{Real: quat.NaN(), Dual: two}}, // PowReal(NaN+xϵ, y) = NaN+NaNϵ {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 2, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 3, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: one}, p: 2, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: one}, p: 3, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: two}, p: 2, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: quat.NaN(), Dual: two}, p: 3, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, // PowReal(x, NaN) = NaN+NaNϵ {d: Number{Real: zeroQuat, Dual: zeroQuat}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: two, Dual: zeroQuat}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: three, Dual: zeroQuat}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: zeroQuat, Dual: one}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: two, Dual: one}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: three, Dual: one}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: zeroQuat, Dual: two}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: two, Dual: two}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, {d: Number{Real: three, Dual: two}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, // Handled by quat.Pow tests: // // Pow(±0, y) = ±Inf for y an odd integer < 0 // Pow(±0, -Inf) = +Inf // Pow(±0, +Inf) = +0 // Pow(±0, y) = +Inf for finite y < 0 and not an odd integer // Pow(±0, y) = ±0 for y an odd integer > 0 // Pow(±0, y) = +0 for finite y > 0 and not an odd integer // Pow(-1, ±Inf) = 1 // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 {d: Number{Real: two, Dual: zeroQuat}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, {d: Number{Real: three, Dual: zeroQuat}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 {d: Number{Real: two, Dual: one}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: three, Dual: one}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: two, Dual: two}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: three, Dual: two}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 {d: Number{Real: two, Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: three, Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: two, Dual: one}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: three, Dual: one}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: two, Dual: two}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: three, Dual: two}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, // PowReal(x+yϵ, +Inf) = +0+NaNϵ for |x| < 1 {d: Number{Real: quat.Scale(0.1, one), Dual: zeroQuat}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: quat.Scale(0.1, one), Dual: quat.Scale(0.1, one)}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: quat.Scale(0.2, one), Dual: quat.Scale(0.2, one)}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, {d: Number{Real: quat.Scale(0.5, one), Dual: quat.Scale(0.5, one)}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 {d: Number{Real: quat.Scale(0.1, one), Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, {d: Number{Real: quat.Scale(0.2, one), Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 {d: Number{Real: quat.Scale(0.1, one), Dual: quat.Scale(0.1, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: quat.Scale(0.2, one), Dual: quat.Scale(0.1, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: quat.Scale(0.1, one), Dual: quat.Scale(0.2, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: quat.Scale(0.2, one), Dual: quat.Scale(0.2, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: quat.Scale(0.1, one), Dual: one}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: quat.Scale(0.2, one), Dual: one}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: quat.Scale(0.1, one), Dual: two}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, {d: Number{Real: quat.Scale(0.2, one), Dual: two}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, // Handled by quat.Pow tests: // // Pow(+Inf, y) = +Inf for y > 0 // Pow(+Inf, y) = +0 for y < 0 // Pow(-Inf, y) = Pow(-0, -y) } func TestPowReal(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range powRealTests { got := PowReal(test.d, test.p) if !sameDual(got, test.want, tol) { t.Errorf("unexpected PowReal(%v, %v): got:%v want:%v", test.d, test.p, got, test.want) } } } func sameDual(a, b Number, tol float64) bool { return same(a.Real, b.Real, tol) && same(a.Dual, b.Dual, tol) } func same(a, b quat.Number, tol float64) bool { return (quat.IsNaN(a) && quat.IsNaN(b)) || (quat.IsInf(a) && quat.IsInf(b)) || equalApprox(a, b, tol) } func equalApprox(a, b quat.Number, tol float64) bool { return scalar.EqualWithinAbsOrRel(a.Real, b.Real, tol, tol) && scalar.EqualWithinAbsOrRel(a.Imag, b.Imag, tol, tol) && scalar.EqualWithinAbsOrRel(a.Jmag, b.Jmag, tol, tol) && scalar.EqualWithinAbsOrRel(a.Kmag, b.Kmag, tol, tol) } golang-gonum-v1-gonum-0.14.0/num/hyperdual/000077500000000000000000000000001450372207100204325ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/num/hyperdual/doc.go000066400000000000000000000012351450372207100215270ustar00rootroot00000000000000// 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 hyperdual provides the hyperdual numeric type and functions. Hyperdual // numbers are an extension of the real numbers in the form a+bϵ₁+bϵ₂+dϵ₁ϵ₂ where // ϵ₁^2=0 and ϵ₂^2=0, but ϵ₁≠0, ϵ₂≠0 and ϵ₁ϵ₂≠0. // // See https://doi.org/10.2514/6.2011-886 and http://adl.stanford.edu/hyperdual/ for // details of their properties and uses. package hyperdual // imports "gonum.org/v1/gonum/num/hyperdual" // TODO(kortschak): Handle special cases properly. // - Pow golang-gonum-v1-gonum-0.14.0/num/hyperdual/hyperdual.go000066400000000000000000000063211450372207100227600ustar00rootroot00000000000000// 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 hyperdual import ( "fmt" "math" "strings" ) // Number is a float64 precision hyperdual number. type Number struct { Real, E1mag, E2mag, E1E2mag float64 } var negZero = math.Float64frombits(1 << 63) // Format implements fmt.Formatter. func (d Number) Format(fs fmt.State, c rune) { prec, pOk := fs.Precision() if !pOk { prec = -1 } width, wOk := fs.Width() if !wOk { width = -1 } switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T{Real:%#v, E1mag:%#v, E2mag:%#v, E1E2mag:%#v}", d, d.Real, d.E1mag, d.E2mag, d.E1E2mag) return } if fs.Flag('+') { fmt.Fprintf(fs, "{Real:%+v, E1mag:%+v, E2mag:%+v, E1E2mag:%+v}", d.Real, d.E1mag, d.E2mag, d.E1E2mag) return } c = 'g' prec = -1 fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': fre := fmtString(fs, c, prec, width, false) fim := fmtString(fs, c, prec, width, true) fmt.Fprintf(fs, fmt.Sprintf("(%s%[2]sϵ₁%[2]sϵ₂%[2]sϵ₁ϵ₂)", fre, fim), d.Real, d.E1mag, d.E2mag, d.E1E2mag) default: fmt.Fprintf(fs, "%%!%c(%T=%[2]v)", c, d) return } } // This is horrible, but it's what we have. func fmtString(fs fmt.State, c rune, prec, width int, wantPlus bool) string { var b strings.Builder b.WriteByte('%') for _, f := range "0+- " { if fs.Flag(int(f)) || (f == '+' && wantPlus) { b.WriteByte(byte(f)) } } if width >= 0 { fmt.Fprint(&b, width) } if prec >= 0 { b.WriteByte('.') if prec > 0 { fmt.Fprint(&b, prec) } } b.WriteRune(c) return b.String() } // Add returns the sum of x and y. func Add(x, y Number) Number { return Number{ Real: x.Real + y.Real, E1mag: x.E1mag + y.E1mag, E2mag: x.E2mag + y.E2mag, E1E2mag: x.E1E2mag + y.E1E2mag, } } // Sub returns the difference of x and y, x-y. func Sub(x, y Number) Number { return Number{ Real: x.Real - y.Real, E1mag: x.E1mag - y.E1mag, E2mag: x.E2mag - y.E2mag, E1E2mag: x.E1E2mag - y.E1E2mag, } } // Mul returns the hyperdual product of x and y. func Mul(x, y Number) Number { return Number{ Real: x.Real * y.Real, E1mag: x.Real*y.E1mag + x.E1mag*y.Real, E2mag: x.Real*y.E2mag + x.E2mag*y.Real, E1E2mag: x.Real*y.E1E2mag + x.E1mag*y.E2mag + x.E2mag*y.E1mag + x.E1E2mag*y.Real, } } // Inv returns the hyperdual inverse of d. // // Special cases are: // // Inv(±Inf) = ±0-0ϵ₁-0ϵ₂±0ϵ₁ϵ₂ // Inv(±0) = ±Inf-Infϵ₁-Infϵ₂±Infϵ₁ϵ₂ func Inv(d Number) Number { if d.Real == 0 { return Number{ Real: 1 / d.Real, E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: 1 / d.Real, // Return a signed inf from a signed zero. } } d2 := d.Real * d.Real return Number{ Real: 1 / d.Real, E1mag: -d.E1mag / d2, E2mag: -d.E2mag / d2, E1E2mag: -d.E1E2mag/d2 + 2*d.E1mag*d.E2mag/(d2*d.Real), } } // Scale returns d scaled by f. func Scale(f float64, d Number) Number { return Number{Real: f * d.Real, E1mag: f * d.E1mag, E2mag: f * d.E2mag, E1E2mag: f * d.E1E2mag} } // Abs returns the absolute value of d. func Abs(d Number) Number { if math.Float64bits(d.Real)&(1<<63) == 0 { return d } return Scale(-1, d) } golang-gonum-v1-gonum-0.14.0/num/hyperdual/hyperdual_example_test.go000066400000000000000000000016651450372207100255400ustar00rootroot00000000000000// 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 hyperdual_test import ( "fmt" "gonum.org/v1/gonum/num/hyperdual" ) func ExampleNumber_fike() { // Calculate the value and first and second derivatives // of the function e^x/(sqrt(sin(x)^3 + cos(x)^3)). fn := func(x hyperdual.Number) hyperdual.Number { return hyperdual.Mul( hyperdual.Exp(x), hyperdual.Inv(hyperdual.Sqrt( hyperdual.Add( hyperdual.PowReal(hyperdual.Sin(x), 3), hyperdual.PowReal(hyperdual.Cos(x), 3))))) } v := fn(hyperdual.Number{Real: 1.5, E1mag: 1, E2mag: 1}) fmt.Printf("v=%.4f\n", v) fmt.Printf("fn(1.5)=%.4f\nfn′(1.5)=%.4f\nfn′′(1.5)=%.4f\n", v.Real, v.E1mag, v.E1E2mag) // Output: // // v=(4.4978+4.0534ϵ₁+4.0534ϵ₂+9.4631ϵ₁ϵ₂) // fn(1.5)=4.4978 // fn′(1.5)=4.0534 // fn′′(1.5)=9.4631 } golang-gonum-v1-gonum-0.14.0/num/hyperdual/hyperdual_fike.go000066400000000000000000000213161450372207100237570ustar00rootroot00000000000000// 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. // Derived from code by Jeffrey A. Fike at http://adl.stanford.edu/hyperdual/ // The MIT License (MIT) // // Copyright (c) 2006 Jeffrey A. Fike // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package hyperdual import "math" // PowReal returns x**p, the base-x exponential of p. // // Special cases are (in order): // // PowReal(NaN+xϵ₁+yϵ₂, ±0) = 1+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for any x and y // PowReal(x, ±0) = 1 for any x // PowReal(1+xϵ₁+yϵ₂, z) = 1+xzϵ₁+yzϵ₂+2xyzϵ₁ϵ₂ for any z // PowReal(NaN+xϵ₁+yϵ₂, 1) = NaN+xϵ₁+yϵ₂+NaNϵ₁ϵ₂ for any x // PowReal(x, 1) = x for any x // PowReal(NaN+xϵ₁+xϵ₂, y) = NaN+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ // PowReal(x, NaN) = NaN+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ // PowReal(±0, y) = ±Inf for y an odd integer < 0 // PowReal(±0, -Inf) = +Inf // PowReal(±0, +Inf) = +0 // PowReal(±0, y) = +Inf for finite y < 0 and not an odd integer // PowReal(±0, y) = ±0 for y an odd integer > 0 // PowReal(±0, y) = +0 for finite y > 0 and not an odd integer // PowReal(-1, ±Inf) = 1 // PowReal(x+0ϵ₁+0ϵ₂, +Inf) = +Inf+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| > 1 // PowReal(x+xϵ₁+yϵ₂, +Inf) = +Inf+Infϵ₁+Infϵ₂+NaNϵ₁ϵ₂ for |x| > 1 // PowReal(x, -Inf) = +0+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| > 1 // PowReal(x+yϵ₁+zϵ₂, +Inf) = +0+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| < 1 // PowReal(x+0ϵ₁+0ϵ₂, -Inf) = +Inf+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| < 1 // PowReal(x, -Inf) = +Inf-Infϵ₁-Infϵ₂+NaNϵ₁ϵ₂ for |x| < 1 // PowReal(+Inf, y) = +Inf for y > 0 // PowReal(+Inf, y) = +0 for y < 0 // PowReal(-Inf, y) = Pow(-0, -y) // PowReal(x, y) = NaN+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for finite x < 0 and finite non-integer y func PowReal(d Number, p float64) Number { const tol = 1e-15 r := d.Real if math.Abs(r) < tol { if r >= 0 { r = tol } if r < 0 { r = -tol } } deriv := p * math.Pow(r, p-1) return Number{ Real: math.Pow(d.Real, p), E1mag: d.E1mag * deriv, E2mag: d.E2mag * deriv, E1E2mag: d.E1E2mag*deriv + p*(p-1)*d.E1mag*d.E2mag*math.Pow(r, (p-2)), } } // Pow returns x**p, the base-x exponential of p. func Pow(d, p Number) Number { return Exp(Mul(p, Log(d))) } // Sqrt returns the square root of d. // // Special cases are: // // Sqrt(+Inf) = +Inf // Sqrt(±0) = (±0+Infϵ₁+Infϵ₂-Infϵ₁ϵ₂) // Sqrt(x < 0) = NaN // Sqrt(NaN) = NaN func Sqrt(d Number) Number { if d.Real <= 0 { if d.Real == 0 { return Number{ Real: d.Real, E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.Inf(-1), } } return Number{ Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN(), } } return PowReal(d, 0.5) } // Exp returns e**q, the base-e exponential of d. // // Special cases are: // // Exp(+Inf) = +Inf // Exp(NaN) = NaN // // Very large values overflow to 0 or +Inf. // Very small values underflow to 1. func Exp(d Number) Number { exp := math.Exp(d.Real) // exp is also the derivative. return Number{ Real: exp, E1mag: exp * d.E1mag, E2mag: exp * d.E2mag, E1E2mag: exp * (d.E1E2mag + d.E1mag*d.E2mag), } } // Log returns the natural logarithm of d. // // Special cases are: // // Log(+Inf) = (+Inf+0ϵ₁+0ϵ₂-0ϵ₁ϵ₂) // Log(0) = (-Inf±Infϵ₁±Infϵ₂-Infϵ₁ϵ₂) // Log(x < 0) = NaN // Log(NaN) = NaN func Log(d Number) Number { switch d.Real { case 0: return Number{ Real: math.Log(d.Real), E1mag: math.Copysign(math.Inf(1), d.Real), E2mag: math.Copysign(math.Inf(1), d.Real), E1E2mag: math.Inf(-1), } case math.Inf(1): return Number{ Real: math.Log(d.Real), E1mag: 0, E2mag: 0, E1E2mag: negZero, } } if d.Real < 0 { return Number{ Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN(), } } deriv1 := d.E1mag / d.Real deriv2 := d.E2mag / d.Real return Number{ Real: math.Log(d.Real), E1mag: deriv1, E2mag: deriv2, E1E2mag: d.E1E2mag/d.Real - (deriv1 * deriv2), } } // Sin returns the sine of d. // // Special cases are: // // Sin(±0) = (±0+Nϵ₁+Nϵ₂∓0ϵ₁ϵ₂) // Sin(±Inf) = NaN // Sin(NaN) = NaN func Sin(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E2mag, E1E2mag: -d.Real, } } fn := math.Sin(d.Real) deriv := math.Cos(d.Real) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag - fn*d.E1mag*d.E2mag, } } // Cos returns the cosine of d. // // Special cases are: // // Cos(±Inf) = NaN // Cos(NaN) = NaN func Cos(d Number) Number { fn := math.Cos(d.Real) deriv := -math.Sin(d.Real) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag - fn*d.E1mag*d.E2mag, } } // Tan returns the tangent of d. // // Special cases are: // // Tan(±0) = (±0+Nϵ₁+Nϵ₂±0ϵ₁ϵ₂) // Tan(±Inf) = NaN // Tan(NaN) = NaN func Tan(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E2mag, E1E2mag: d.Real, } } fn := math.Tan(d.Real) deriv := 1 + fn*fn return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(2*fn*deriv), } } // Asin returns the inverse sine of d. // // Special cases are: // // Asin(±0) = (±0+Nϵ₁+Nϵ₂±0ϵ₁ϵ₂) // Asin(±1) = (±Inf+Infϵ₁+Infϵ₂±Infϵ₁ϵ₂) // Asin(x) = NaN if x < -1 or x > 1 func Asin(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E2mag, E1E2mag: d.Real, } } else if m := math.Abs(d.Real); m >= 1 { if m == 1 { return Number{ Real: math.Asin(d.Real), E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.Copysign(math.Inf(1), d.Real), } } return Number{ Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN(), } } fn := math.Asin(d.Real) deriv1 := 1 - d.Real*d.Real deriv := 1 / math.Sqrt(deriv1) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(d.Real*math.Pow(deriv1, -1.5)), } } // Acos returns the inverse cosine of d. // // Special cases are: // // Acos(-1) = (Pi-Infϵ₁-Infϵ₂+Infϵ₁ϵ₂) // Acos(1) = (0-Infϵ₁-Infϵ₂-Infϵ₁ϵ₂) // Acos(x) = NaN if x < -1 or x > 1 func Acos(d Number) Number { if m := math.Abs(d.Real); m >= 1 { if m == 1 { return Number{ Real: math.Acos(d.Real), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.Copysign(math.Inf(1), -d.Real), } } return Number{ Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN(), } } fn := math.Acos(d.Real) deriv1 := 1 - d.Real*d.Real deriv := -1 / math.Sqrt(deriv1) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(-d.Real*math.Pow(deriv1, -1.5)), } } // Atan returns the inverse tangent of d. // // Special cases are: // // Atan(±0) = (±0+Nϵ₁+Nϵ₂∓0ϵ₁ϵ₂) // Atan(±Inf) = (±Pi/2+0ϵ₁+0ϵ₂∓0ϵ₁ϵ₂) func Atan(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E2mag, E1E2mag: -d.Real, } } fn := math.Atan(d.Real) deriv1 := 1 + d.Real*d.Real deriv := 1 / deriv1 return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(-2*d.Real/(deriv1*deriv1)), } } golang-gonum-v1-gonum-0.14.0/num/hyperdual/hyperdual_hyperbolic.go000066400000000000000000000102131450372207100251730ustar00rootroot00000000000000// 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 hyperdual import "math" // Sinh returns the hyperbolic sine of d. // // Special cases are: // // Sinh(±0) = (±0+Nϵ₁+Nϵ₂±0ϵ₁ϵ₂) // Sinh(±Inf) = ±Inf // Sinh(NaN) = NaN func Sinh(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E1mag, E1E2mag: d.Real, } } if math.IsInf(d.Real, 0) { return Number{ Real: d.Real, E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: d.Real, } } fn := math.Sinh(d.Real) deriv := math.Cosh(d.Real) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + fn*d.E1mag*d.E2mag, } } // Cosh returns the hyperbolic cosine of d. // // Special cases are: // // Cosh(±0) = 1 // Cosh(±Inf) = +Inf // Cosh(NaN) = NaN func Cosh(d Number) Number { if math.IsInf(d.Real, 0) { return Number{ Real: math.Inf(1), E1mag: d.Real, E2mag: d.Real, E1E2mag: math.Inf(1), } } fn := math.Cosh(d.Real) deriv := math.Sinh(d.Real) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + fn*d.E1mag*d.E2mag, } } // Tanh returns the hyperbolic tangent of d. // // Special cases are: // // Tanh(±0) = (±0+Nϵ₁+Nϵ₂∓0ϵ₁ϵ₂) // Tanh(±Inf) = (±1+0ϵ₁+0ϵ₂∓0ϵ₁ϵ₂) // Tanh(NaN) = NaN func Tanh(d Number) Number { switch d.Real { case 0: return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E2mag, E1E2mag: -d.Real, } case math.Inf(1): return Number{ Real: 1, E1mag: 0, E2mag: 0, E1E2mag: negZero, } case math.Inf(-1): return Number{ Real: -1, E1mag: 0, E2mag: 0, E1E2mag: 0, } } fn := math.Tanh(d.Real) deriv := 1 - fn*fn return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag - d.E1mag*d.E2mag*(2*fn*deriv), } } // Asinh returns the inverse hyperbolic sine of d. // // Special cases are: // // Asinh(±0) = (±0+Nϵ₁+Nϵ₂∓0ϵ₁ϵ₂) // Asinh(±Inf) = ±Inf // Asinh(NaN) = NaN func Asinh(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E2mag, E1E2mag: -d.Real, } } fn := math.Asinh(d.Real) deriv1 := d.Real*d.Real + 1 deriv := 1 / math.Sqrt(deriv1) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(-d.Real*(deriv/deriv1)), } } // Acosh returns the inverse hyperbolic cosine of d. // // Special cases are: // // Acosh(+Inf) = +Inf // Acosh(1) = (0+Infϵ₁+Infϵ₂-Infϵ₁ϵ₂) // Acosh(x) = NaN if x < 1 // Acosh(NaN) = NaN func Acosh(d Number) Number { if d.Real <= 1 { if d.Real == 1 { return Number{ Real: 0, E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.Inf(-1), } } return Number{ Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN(), } } fn := math.Acosh(d.Real) deriv1 := d.Real*d.Real - 1 deriv := 1 / math.Sqrt(deriv1) return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(-d.Real*(deriv/deriv1)), } } // Atanh returns the inverse hyperbolic tangent of d. // // Special cases are: // // Atanh(1) = +Inf // Atanh(±0) = (±0+Nϵ₁+Nϵ₂±0ϵ₁ϵ₂) // Atanh(-1) = -Inf // Atanh(x) = NaN if x < -1 or x > 1 // Atanh(NaN) = NaN func Atanh(d Number) Number { if d.Real == 0 { return Number{ Real: d.Real, E1mag: d.E1mag, E2mag: d.E2mag, E1E2mag: d.Real, } } if math.Abs(d.Real) == 1 { return Number{ Real: math.Inf(int(d.Real)), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.Inf(int(d.Real)), } } fn := math.Atanh(d.Real) deriv1 := 1 - d.Real*d.Real deriv := 1 / deriv1 return Number{ Real: fn, E1mag: deriv * d.E1mag, E2mag: deriv * d.E2mag, E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(2*d.Real/(deriv1*deriv1)), } } golang-gonum-v1-gonum-0.14.0/num/hyperdual/hyperdual_test.go000066400000000000000000000604001450372207100240150ustar00rootroot00000000000000// 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 hyperdual import ( "fmt" "math" "testing" "gonum.org/v1/gonum/floats/scalar" ) var formatTests = []struct { h Number format string want string }{ {h: Number{1.1, 2.1, 3.1, 4.1}, format: "%#v", want: "hyperdual.Number{Real:1.1, E1mag:2.1, E2mag:3.1, E1E2mag:4.1}"}, // Bootstrap test. {h: Number{-1.1, -2.1, -3.1, -4.1}, format: "%#v", want: "hyperdual.Number{Real:-1.1, E1mag:-2.1, E2mag:-3.1, E1E2mag:-4.1}"}, // Bootstrap test. {h: Number{1.1, 2.1, 3.1, 4.1}, format: "%+v", want: "{Real:1.1, E1mag:2.1, E2mag:3.1, E1E2mag:4.1}"}, {h: Number{-1.1, -2.1, -3.1, -4.1}, format: "%+v", want: "{Real:-1.1, E1mag:-2.1, E2mag:-3.1, E1E2mag:-4.1}"}, {h: Number{1, 2, 3, 4}, format: "%v", want: "(1+2ϵ₁+3ϵ₂+4ϵ₁ϵ₂)"}, {h: Number{-1, -2, -3, -4}, format: "%v", want: "(-1-2ϵ₁-3ϵ₂-4ϵ₁ϵ₂)"}, {h: Number{1, 2, 3, 4}, format: "%g", want: "(1+2ϵ₁+3ϵ₂+4ϵ₁ϵ₂)"}, {h: Number{-1, -2, -3, -4}, format: "%g", want: "(-1-2ϵ₁-3ϵ₂-4ϵ₁ϵ₂)"}, {h: Number{1, 2, 3, 4}, format: "%e", want: "(1.000000e+00+2.000000e+00ϵ₁+3.000000e+00ϵ₂+4.000000e+00ϵ₁ϵ₂)"}, {h: Number{-1, -2, -3, -4}, format: "%e", want: "(-1.000000e+00-2.000000e+00ϵ₁-3.000000e+00ϵ₂-4.000000e+00ϵ₁ϵ₂)"}, {h: Number{1, 2, 3, 4}, format: "%E", want: "(1.000000E+00+2.000000E+00ϵ₁+3.000000E+00ϵ₂+4.000000E+00ϵ₁ϵ₂)"}, {h: Number{-1, -2, -3, -4}, format: "%E", want: "(-1.000000E+00-2.000000E+00ϵ₁-3.000000E+00ϵ₂-4.000000E+00ϵ₁ϵ₂)"}, {h: Number{1, 2, 3, 4}, format: "%f", want: "(1.000000+2.000000ϵ₁+3.000000ϵ₂+4.000000ϵ₁ϵ₂)"}, {h: Number{-1, -2, -3, -4}, format: "%f", want: "(-1.000000-2.000000ϵ₁-3.000000ϵ₂-4.000000ϵ₁ϵ₂)"}, } func TestFormat(t *testing.T) { t.Parallel() for _, test := range formatTests { got := fmt.Sprintf(test.format, test.h) if got != test.want { t.Errorf("unexpected result for fmt.Sprintf(%q, %#v): got:%q, want:%q", test.format, test.h, got, test.want) } } } // First derivatives: func dSin(x float64) float64 { return math.Cos(x) } func dCos(x float64) float64 { return -math.Sin(x) } func dTan(x float64) float64 { return sec(x) * sec(x) } func dAsin(x float64) float64 { return 1 / math.Sqrt(1-x*x) } func dAcos(x float64) float64 { return -1 / math.Sqrt(1-x*x) } func dAtan(x float64) float64 { return 1 / (1 + x*x) } func dSinh(x float64) float64 { return math.Cosh(x) } func dCosh(x float64) float64 { return math.Sinh(x) } func dTanh(x float64) float64 { return sech(x) * sech(x) } func dAsinh(x float64) float64 { return 1 / math.Sqrt(x*x+1) } func dAcosh(x float64) float64 { return 1 / (math.Sqrt(x-1) * math.Sqrt(x+1)) } func dAtanh(x float64) float64 { switch { case math.Abs(x) == 1: return math.NaN() case math.IsInf(x, 0): return negZero } return 1 / (1 - x*x) } func dExp(x float64) float64 { return math.Exp(x) } func dLog(x float64) float64 { if x < 0 { return math.NaN() } return 1 / x } func dSqrt(x float64) float64 { // For whatever reason, math.Sqrt(-0) returns -0. // In this case, that is clearly a wrong approach. if x == 0 { return math.Inf(1) } return 0.5 / math.Sqrt(x) } func dInv(x float64) float64 { return -1 / (x * x) } // Second derivatives: func d2Sin(x float64) float64 { return -math.Sin(x) } func d2Cos(x float64) float64 { return -math.Cos(x) } func d2Tan(x float64) float64 { return 2 * math.Tan(x) * sec(x) * sec(x) } func d2Asin(x float64) float64 { return x / math.Pow(1-x*x, 1.5) } func d2Acos(x float64) float64 { return -x / math.Pow(1-x*x, 1.5) } func d2Atan(x float64) float64 { return -2 * x / ((x*x + 1) * (x*x + 1)) } func d2Sinh(x float64) float64 { return math.Sinh(x) } func d2Cosh(x float64) float64 { return math.Cosh(x) } func d2Tanh(x float64) float64 { return -2 * math.Tanh(x) * sech(x) * sech(x) } func d2Asinh(x float64) float64 { return -x / math.Pow((x*x+1), 1.5) } func d2Acosh(x float64) float64 { return -x / (math.Pow(x-1, 1.5) * math.Pow(x+1, 1.5)) } func d2Atanh(x float64) float64 { return 2 * x / ((1 - x*x) * (1 - x*x)) } func d2Exp(x float64) float64 { return math.Exp(x) } func d2Log(x float64) float64 { if x < 0 { return math.NaN() } return -1 / (x * x) } func d2Sqrt(x float64) float64 { // Again math.Sqyu, and math.Pow are odd. switch x { case math.Inf(1): return 0 case math.Inf(-1): return math.NaN() } return -0.25 * math.Pow(x, -1.5) } func d2Inv(x float64) float64 { return 2 / (x * x * x) } // Helpers: func sec(x float64) float64 { return 1 / math.Cos(x) } func sech(x float64) float64 { return 1 / math.Cosh(x) } var hyperdualTests = []struct { name string x []float64 fnHyperdual func(x Number) Number fn func(x float64) float64 dFn func(x float64) float64 d2Fn func(x float64) float64 }{ { name: "sin", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Sin, fn: math.Sin, dFn: dSin, d2Fn: d2Sin, }, { name: "cos", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Cos, fn: math.Cos, dFn: dCos, d2Fn: d2Cos, }, { name: "tan", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Tan, fn: math.Tan, dFn: dTan, d2Fn: d2Tan, }, { name: "sinh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Sinh, fn: math.Sinh, dFn: dSinh, d2Fn: d2Sinh, }, { name: "cosh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Cosh, fn: math.Cosh, dFn: dCosh, d2Fn: d2Cosh, }, { name: "tanh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Tanh, fn: math.Tanh, dFn: dTanh, d2Fn: d2Tanh, }, { name: "asin", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Asin, fn: math.Asin, dFn: dAsin, d2Fn: d2Asin, }, { name: "acos", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Acos, fn: math.Acos, dFn: dAcos, d2Fn: d2Acos, }, { name: "atan", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Atan, fn: math.Atan, dFn: dAtan, d2Fn: d2Atan, }, { name: "asinh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Asinh, fn: math.Asinh, dFn: dAsinh, d2Fn: d2Asinh, }, { name: "acosh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Acosh, fn: math.Acosh, dFn: dAcosh, d2Fn: d2Acosh, }, { name: "atanh", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Atanh, fn: math.Atanh, dFn: dAtanh, d2Fn: d2Atanh, }, { name: "exp", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Exp, fn: math.Exp, dFn: dExp, d2Fn: d2Exp, }, { name: "log", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Log, fn: math.Log, dFn: dLog, d2Fn: d2Log, }, { name: "inv", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Inv, fn: func(x float64) float64 { return 1 / x }, dFn: dInv, d2Fn: d2Inv, }, { name: "sqrt", x: []float64{math.NaN(), math.Inf(-1), -3, -2, -1, -0.5, negZero, 0, 0.5, 1, 2, 3, math.Inf(1)}, fnHyperdual: Sqrt, fn: math.Sqrt, dFn: dSqrt, d2Fn: d2Sqrt, }, { name: "Fike example fn", x: []float64{1, 2, 3, 4, 5}, fnHyperdual: func(x Number) Number { return Mul( Exp(x), Inv(Sqrt( Add( PowReal(Sin(x), 3), PowReal(Cos(x), 3))))) }, fn: func(x float64) float64 { return math.Exp(x) / math.Sqrt(math.Pow(math.Sin(x), 3)+math.Pow(math.Cos(x), 3)) }, dFn: func(x float64) float64 { return math.Exp(x) * (3*math.Cos(x) + 5*math.Cos(3*x) + 9*math.Sin(x) + math.Sin(3*x)) / (8 * math.Pow(math.Pow(math.Sin(x), 3)+math.Pow(math.Cos(x), 3), 1.5)) }, d2Fn: func(x float64) float64 { return math.Exp(x) * (130 - 12*math.Cos(2*x) + 30*math.Cos(4*x) + 12*math.Cos(6*x) - 111*math.Sin(2*x) + 48*math.Sin(4*x) + 5*math.Sin(6*x)) / (64 * math.Pow(math.Pow(math.Sin(x), 3)+math.Pow(math.Cos(x), 3), 2.5)) }, }, } func TestHyperdual(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range hyperdualTests { for _, x := range test.x { fxHyperdual := test.fnHyperdual(Number{Real: x, E1mag: 1, E2mag: 1}) fx := test.fn(x) dFx := test.dFn(x) d2Fx := test.d2Fn(x) if !same(fxHyperdual.Real, fx, tol) { t.Errorf("unexpected %s(%v): got:%v want:%v", test.name, x, fxHyperdual.Real, fx) } if !same(fxHyperdual.E1mag, dFx, tol) { t.Errorf("unexpected %s′(%v) (ϵ₁): got:%v want:%v", test.name, x, fxHyperdual.E1mag, dFx) } if !same(fxHyperdual.E1mag, fxHyperdual.E2mag, tol) { t.Errorf("mismatched ϵ₁ and ϵ₂ for %s(%v): ϵ₁:%v ϵ₂:%v", test.name, x, fxHyperdual.E1mag, fxHyperdual.E2mag) } if !same(fxHyperdual.E1E2mag, d2Fx, tol) { t.Errorf("unexpected %s′′(%v): got:%v want:%v", test.name, x, fxHyperdual.E1E2mag, d2Fx) } } } } var powRealTests = []struct { d Number p float64 want Number }{ // PowReal(NaN+xϵ₁+yϵ₂, ±0) = 1+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for any x and y {d: Number{Real: math.NaN(), E1mag: 0, E2mag: 0}, p: 0, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 0, E2mag: 0}, p: negZero, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 1}, p: 0, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 2, E2mag: 2}, p: negZero, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 3, E2mag: 3}, p: 0, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 1}, p: negZero, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 2, E2mag: 2}, p: 0, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 3, E2mag: 3}, p: negZero, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 2, E2mag: 3}, p: 0, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 2, E2mag: 3}, p: negZero, want: Number{Real: 1, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, // PowReal(x, ±0) = 1 for any x {d: Number{Real: 0, E1mag: 0, E2mag: 0}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0}}, {d: Number{Real: math.Inf(1), E1mag: 0, E2mag: 0}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0}}, {d: Number{Real: math.Inf(-1), E1mag: 0, E2mag: 0}, p: negZero, want: Number{Real: 1, E1mag: 0, E2mag: 0}}, {d: Number{Real: 0, E1mag: 1, E2mag: 1}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0}}, {d: Number{Real: math.Inf(1), E1mag: 1, E2mag: 1}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0}}, {d: Number{Real: math.Inf(-1), E1mag: 1, E2mag: 1}, p: negZero, want: Number{Real: 1, E1mag: 0, E2mag: 0}}, // These two satisfy the claim above, but the sign of zero is negative. Do we care? {d: Number{Real: negZero, E1mag: 0, E2mag: 0}, p: negZero, want: Number{Real: 1, E1mag: negZero, E2mag: negZero}}, {d: Number{Real: negZero, E1mag: 1, E2mag: 1}, p: negZero, want: Number{Real: 1, E1mag: negZero, E2mag: negZero}}, // PowReal(1+xϵ₁+yϵ₂, z) = 1+xzϵ₁+yzϵ₂+2xyzϵ₁ϵ₂ for any z {d: Number{Real: 1, E1mag: 0, E2mag: 0}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 0, E2mag: 0}, p: 1, want: Number{Real: 1, E1mag: 0, E2mag: 0, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 0, E2mag: 0}, p: 2, want: Number{Real: 1, E1mag: 0, E2mag: 0, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 0, E2mag: 0}, p: 3, want: Number{Real: 1, E1mag: 0, E2mag: 0, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 1, E2mag: 1}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 1, E2mag: 1}, p: 1, want: Number{Real: 1, E1mag: 1, E2mag: 1, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 1, E2mag: 1}, p: 2, want: Number{Real: 1, E1mag: 2, E2mag: 2, E1E2mag: 2}}, {d: Number{Real: 1, E1mag: 1, E2mag: 1}, p: 3, want: Number{Real: 1, E1mag: 3, E2mag: 3, E1E2mag: 6}}, {d: Number{Real: 1, E1mag: 2, E2mag: 2}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 2, E2mag: 2}, p: 1, want: Number{Real: 1, E1mag: 2, E2mag: 2, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 2, E2mag: 2}, p: 2, want: Number{Real: 1, E1mag: 4, E2mag: 4, E1E2mag: 8}}, {d: Number{Real: 1, E1mag: 2, E2mag: 2}, p: 3, want: Number{Real: 1, E1mag: 6, E2mag: 6, E1E2mag: 24}}, {d: Number{Real: 1, E1mag: 1, E2mag: 2}, p: 0, want: Number{Real: 1, E1mag: 0, E2mag: 0, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 1, E2mag: 2}, p: 1, want: Number{Real: 1, E1mag: 1, E2mag: 2, E1E2mag: 0}}, {d: Number{Real: 1, E1mag: 1, E2mag: 2}, p: 2, want: Number{Real: 1, E1mag: 2, E2mag: 4, E1E2mag: 4}}, {d: Number{Real: 1, E1mag: 1, E2mag: 2}, p: 3, want: Number{Real: 1, E1mag: 3, E2mag: 6, E1E2mag: 12}}, // PowReal(NaN+xϵ₁+yϵ₂, 1) = NaN+xϵ₁+yϵ₂+NaNϵ₁ϵ₂ for any x {d: Number{Real: math.NaN(), E1mag: 0, E2mag: 0}, p: 1, want: Number{Real: math.NaN(), E1mag: 0, E2mag: 0, E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 1}, p: 1, want: Number{Real: math.NaN(), E1mag: 1, E2mag: 1, E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 2, E2mag: 2}, p: 1, want: Number{Real: math.NaN(), E1mag: 2, E2mag: 2, E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 2}, p: 1, want: Number{Real: math.NaN(), E1mag: 1, E2mag: 2, E1E2mag: math.NaN()}}, // PowReal(x, 1) = x for any x {d: Number{Real: 0, E1mag: 0, E2mag: 0}, p: 1, want: Number{Real: 0, E1mag: 0, E2mag: 0}}, {d: Number{Real: negZero, E1mag: 0, E2mag: 0}, p: 1, want: Number{Real: negZero, E1mag: 0, E2mag: 0}}, {d: Number{Real: 0, E1mag: 1, E2mag: 1}, p: 1, want: Number{Real: 0, E1mag: 1, E2mag: 1}}, {d: Number{Real: negZero, E1mag: 1, E2mag: 1}, p: 1, want: Number{Real: negZero, E1mag: 1, E2mag: 1}}, {d: Number{Real: 0, E1mag: 1, E2mag: 2}, p: 1, want: Number{Real: 0, E1mag: 1, E2mag: 2}}, {d: Number{Real: negZero, E1mag: 1, E2mag: 2}, p: 1, want: Number{Real: negZero, E1mag: 1, E2mag: 2}}, // PowReal(NaN+xϵ₁+xϵ₂, y) = NaN+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ {d: Number{Real: math.NaN(), E1mag: 0, E2mag: 0}, p: 2, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 0, E2mag: 0}, p: 3, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 1}, p: 2, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 1}, p: 3, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 2, E2mag: 2}, p: 2, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 2, E2mag: 2}, p: 3, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 2}, p: 2, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: math.NaN(), E1mag: 1, E2mag: 2}, p: 3, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, // PowReal(x, NaN) = NaN+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ {d: Number{Real: 0, E1mag: 0, E2mag: 0}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 2, E1mag: 0, E2mag: 0}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 0, E2mag: 0}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 0, E1mag: 1, E2mag: 1}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 2, E1mag: 1, E2mag: 1}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 1, E2mag: 1}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 0, E1mag: 2, E2mag: 2}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 2, E1mag: 2, E2mag: 2}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 2, E2mag: 2}, p: math.NaN(), want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, // Handled by math.Pow tests: // // Pow(±0, y) = ±Inf for y an odd integer < 0 // Pow(±0, -Inf) = +Inf // Pow(±0, +Inf) = +0 // Pow(±0, y) = +Inf for finite y < 0 and not an odd integer // Pow(±0, y) = ±0 for y an odd integer > 0 // Pow(±0, y) = +0 for finite y > 0 and not an odd integer // Pow(-1, ±Inf) = 1 // PowReal(x+0ϵ₁+0ϵ₂, +Inf) = +Inf+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| > 1 {d: Number{Real: 2, E1mag: 0, E2mag: 0}, p: math.Inf(1), want: Number{Real: math.Inf(1), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 0, E2mag: 0}, p: math.Inf(1), want: Number{Real: math.Inf(1), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, // PowReal(x+xϵ₁+yϵ₂, +Inf) = +Inf+Infϵ₁+Infϵ₂+NaNϵ₁ϵ₂ for |x| > 1 {d: Number{Real: 2, E1mag: 1, E2mag: 1}, p: math.Inf(1), want: Number{Real: math.Inf(1), E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 1, E2mag: 1}, p: math.Inf(1), want: Number{Real: math.Inf(1), E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.NaN()}}, {d: Number{Real: 2, E1mag: 2, E2mag: 2}, p: math.Inf(1), want: Number{Real: math.Inf(1), E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 2, E2mag: 2}, p: math.Inf(1), want: Number{Real: math.Inf(1), E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 2, E2mag: 3}, p: math.Inf(1), want: Number{Real: math.Inf(1), E1mag: math.Inf(1), E2mag: math.Inf(1), E1E2mag: math.NaN()}}, // PowReal(x, -Inf) = +0+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| > 1 {d: Number{Real: 2, E1mag: 0, E2mag: 0}, p: math.Inf(-1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 0, E2mag: 0}, p: math.Inf(-1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 2, E1mag: 1, E2mag: 1}, p: math.Inf(-1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 1, E2mag: 1}, p: math.Inf(-1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 2, E1mag: 2, E2mag: 2}, p: math.Inf(-1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 3, E1mag: 2, E2mag: 2}, p: math.Inf(-1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, // PowReal(x+yϵ₁+zϵ₂, +Inf) = +0+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| < 1 {d: Number{Real: 0.1, E1mag: 0, E2mag: 0}, p: math.Inf(1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 0.1, E1mag: 0.1, E2mag: 0.1}, p: math.Inf(1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 0.2, E1mag: 0.2, E2mag: 0.2}, p: math.Inf(1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 0.5, E1mag: 0.3, E2mag: 0.5}, p: math.Inf(1), want: Number{Real: 0, E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, // PowReal(x+0ϵ₁+0ϵ₂, -Inf) = +Inf+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for |x| < 1 {d: Number{Real: 0.1, E1mag: 0, E2mag: 0}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: 0.2, E1mag: 0, E2mag: 0}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, // PowReal(x, -Inf) = +Inf-Infϵ₁-Infϵ₂+NaNϵ₁ϵ₂ for |x| < 1 {d: Number{Real: 0.1, E1mag: 0.1, E2mag: 0.1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, {d: Number{Real: 0.2, E1mag: 0.1, E2mag: 0.1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, {d: Number{Real: 0.1, E1mag: 0.2, E2mag: 0.2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, {d: Number{Real: 0.2, E1mag: 0.3, E2mag: 0.2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, {d: Number{Real: 0.1, E1mag: 1, E2mag: 1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, {d: Number{Real: 0.2, E1mag: 1, E2mag: 1}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, {d: Number{Real: 0.1, E1mag: 2, E2mag: 2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, {d: Number{Real: 0.2, E1mag: 2, E2mag: 2}, p: math.Inf(-1), want: Number{Real: math.Inf(1), E1mag: math.Inf(-1), E2mag: math.Inf(-1), E1E2mag: math.NaN()}}, // Handled by math.Pow tests: // // Pow(+Inf, y) = +Inf for y > 0 // Pow(+Inf, y) = +0 for y < 0 // Pow(-Inf, y) = Pow(-0, -y) // PowReal(x, y) = NaN+NaNϵ₁+NaNϵ₂+NaNϵ₁ϵ₂ for finite x < 0 and finite non-integer y {d: Number{Real: -1, E1mag: -1, E2mag: -1}, p: 0.5, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: -1, E1mag: 2, E2mag: 2}, p: 0.5, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, {d: Number{Real: -1, E1mag: -1, E2mag: 2}, p: 0.5, want: Number{Real: math.NaN(), E1mag: math.NaN(), E2mag: math.NaN(), E1E2mag: math.NaN()}}, } func TestPowReal(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range powRealTests { got := PowReal(test.d, test.p) if !sameHyperdual(got, test.want, tol) { t.Errorf("unexpected PowReal(%v, %v): got:%v want:%v", test.d, test.p, got, test.want) } } } func sameHyperdual(a, b Number, tol float64) bool { return same(a.Real, b.Real, tol) && same(a.E1mag, b.E1mag, tol) && same(a.E2mag, b.E2mag, tol) && same(a.E1E2mag, b.E1E2mag, tol) } func same(a, b, tol float64) bool { return (math.IsNaN(a) && math.IsNaN(b)) || (scalar.EqualWithinAbsOrRel(a, b, tol, tol) && math.Float64bits(a)&(1<<63) == math.Float64bits(b)&(1<<63)) } golang-gonum-v1-gonum-0.14.0/num/quat/000077500000000000000000000000001450372207100174075ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/num/quat/abs.go000066400000000000000000000015521450372207100205060ustar00rootroot00000000000000// 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. // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package quat import "math" // Abs returns the absolute value (also called the modulus) of q. func Abs(q Number) float64 { // Special cases. switch { case IsInf(q): return math.Inf(1) case IsNaN(q): return math.NaN() } r, i, j, k := q.Real, q.Imag, q.Jmag, q.Kmag if r < 0 { r = -r } if i < 0 { i = -i } if j < 0 { j = -j } if k < 0 { k = -k } if r < i { r, i = i, r } if r < j { r, j = j, r } if r < k { r, k = k, r } if r == 0 { return 0 } i /= r j /= r k /= r return r * math.Sqrt(1+i*i+j*j+k*k) } golang-gonum-v1-gonum-0.14.0/num/quat/abs_test.go000066400000000000000000000017601450372207100215460ustar00rootroot00000000000000// 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 quat import ( "math" "testing" ) var absTests = []struct { q Number want float64 }{ {q: Number{}, want: 0}, {q: NaN(), want: nan}, {q: Inf(), want: inf}, {q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, want: 2}, {q: Number{Real: -1, Imag: 1, Jmag: -1, Kmag: 1}, want: 2}, {q: Number{Real: 1, Imag: 2, Jmag: 3, Kmag: 4}, want: math.Sqrt(1 + 4 + 9 + 16)}, {q: Number{Real: -1, Imag: -2, Jmag: -3, Kmag: -4}, want: math.Sqrt(1 + 4 + 9 + 16)}, } func TestAbs(t *testing.T) { t.Parallel() for _, test := range absTests { got := Abs(test.q) if math.IsNaN(test.want) { if !math.IsNaN(got) { t.Errorf("unexpected result for Abs(%v): got:%v want:%v", test.q, got, test.want) } continue } if got != test.want { t.Errorf("unexpected result for Abs(%v): got:%v want:%v", test.q, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/num/quat/conj.go000066400000000000000000000012031450372207100206630ustar00rootroot00000000000000// 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. // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package quat // Conj returns the quaternion conjugate of q. func Conj(q Number) Number { return Number{Real: q.Real, Imag: -q.Imag, Jmag: -q.Jmag, Kmag: -q.Kmag} } // Inv returns the quaternion inverse of q. func Inv(q Number) Number { if IsInf(q) { return zero } a := Abs(q) return Scale(1/(a*a), Conj(q)) } golang-gonum-v1-gonum-0.14.0/num/quat/conj_test.go000066400000000000000000000022611450372207100217270ustar00rootroot00000000000000// 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 quat import ( "testing" "gonum.org/v1/gonum/floats/scalar" ) var invTests = []struct { q Number wantNaN bool }{ {q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}}, {q: Number{Real: 3, Imag: -1, Jmag: 5, Kmag: -40}}, {q: Number{Real: 1e6, Imag: -1e5, Jmag: 4, Kmag: -10}}, {q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}}, {q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}}, {q: Number{Real: 1, Imag: 1, Jmag: 0, Kmag: 1}}, {q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 0}}, {q: Number{}, wantNaN: true}, } func TestInv(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range invTests { got := Mul(test.q, Inv(test.q)) if test.wantNaN { if !IsNaN(got) { t.Errorf("unexpected result for Mul(%v, Inv(%[1]v)): got:%v want:%v", test.q, got, NaN()) } continue } if !(scalar.EqualWithinAbsOrRel(got.Real, 1, tol, tol) && scalar.EqualWithinAbsOrRel(Abs(got), 1, tol, tol)) { t.Errorf("unexpected result for Mul(%v, Inv(%[1]v)): got:%v want:%v", test.q, got, Number{Real: 1}) } } } golang-gonum-v1-gonum-0.14.0/num/quat/doc.go000066400000000000000000000007061450372207100205060ustar00rootroot00000000000000// 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 quat provides the quaternion numeric type and functions. // // For a good treatment of uses and behaviors of quaternions, see // the interactive videos by Ben Eater and Grant Sanderson here // https://eater.net/quaternions. package quat // imports "gonum.org/v1/gonum/num/quat" golang-gonum-v1-gonum-0.14.0/num/quat/exp.go000066400000000000000000000035201450372207100205320ustar00rootroot00000000000000// 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. // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package quat import "math" // Exp returns e**q, the base-e exponential of q. func Exp(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Exp(w)) } v := Abs(uv) e := math.Exp(w) s, c := math.Sincos(v) return join(e*c, Scale(e*s/v, uv)) } // Log returns the natural logarithm of q. func Log(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Log(w)) } v := Abs(uv) return join(math.Log(Abs(q)), Scale(math.Atan2(v, w)/v, uv)) } // Pow return q**r, the base-q exponential of r. // For generalized compatibility with math.Pow: // // Pow(0, ±0) returns 1+0i+0j+0k // Pow(0, c) for real(c)<0 returns Inf+0i+0j+0k if imag(c), jmag(c), kmag(c) are zero, // otherwise Inf+Inf i+Inf j+Inf k. func Pow(q, r Number) Number { if q == zero { w, uv := split(r) switch { case w == 0: return Number{Real: 1} case w < 0: if uv == zero { return Number{Real: math.Inf(1)} } return Inf() case w > 0: return zero } } return Exp(Mul(Log(q), r)) } // PowReal return q**r, the base-q exponential of r. // For generalized compatibility with math.Pow: // // PowReal(0, ±0) returns 1+0i+0j+0k // PowReal(0, c) for c<0 returns Inf+0i+0j+0k. func PowReal(q Number, r float64) Number { if q == zero { switch { case r == 0: return Number{Real: 1} case r < 0: return Inf() case r > 0: return zero } } return Exp(Scale(r, Log(q))) } // Sqrt returns the square root of q. func Sqrt(q Number) Number { if q == zero { return zero } return PowReal(q, 0.5) } golang-gonum-v1-gonum-0.14.0/num/quat/exp_test.go000066400000000000000000000241211450372207100215710ustar00rootroot00000000000000// 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 quat import ( "math" "testing" ) var expTests = []struct { q Number want Number }{ {q: Number{}, want: Number{Real: 1}}, // Expected velues below are from pyquaternion. { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, want: Number{Real: -0.43643792124786496, Imag: 1.549040352371697, Jmag: 1.549040352371697, Kmag: 1.549040352371697}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, want: Number{Real: 0.42389891174348104, Imag: 0, Jmag: 1.8986002490721081, Kmag: 1.8986002490721081}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, want: Number{Real: 1.4686939399158851, Imag: 0, Jmag: 0, Kmag: 2.2873552871788423}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, want: Number{Real: -0.16055653857469052, Imag: 0.569860099182514, Jmag: 0.569860099182514, Kmag: 0.569860099182514}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, want: Number{Real: 0.15594369476537437, Imag: 0, Jmag: 0.6984559986366083, Kmag: 0.6984559986366083}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, want: Number{Real: 0.5403023058681398, Imag: 0, Jmag: 0, Kmag: 0.8414709848078965}, }, } func TestExp(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range expTests { got := Exp(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Exp(%v): got:%v want:%v", test.q, got, test.want) } } } var logTests = []struct { q Number want Number }{ {q: Number{}, want: Number{Real: -inf}}, // Expected velues below are from pyquaternion. { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, want: Number{Real: 0.6931471805599453, Imag: 0.6045997880780728, Jmag: 0.6045997880780728, Kmag: 0.6045997880780728}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, want: Number{Real: 0.5493061443340548, Imag: 0, Jmag: 0.6755108588560398, Kmag: 0.6755108588560398}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, want: Number{Real: 0.3465735902799727, Imag: 0, Jmag: 0, Kmag: 0.7853981633974484}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, want: Number{Real: 0.5493061443340548, Imag: 0.906899682117109, Jmag: 0.906899682117109, Kmag: 0.906899682117109}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, want: Number{Real: 0.3465735902799727, Imag: 0, Jmag: 1.1107207345395915, Kmag: 1.1107207345395915}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1.5707963267948966}, }, } func TestLog(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range logTests { got := Log(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Log(%v): got:%v want:%v", test.q, got, test.want) } } } var powTests = []struct { q, r Number want Number }{ {q: Number{}, r: Number{}, want: Number{Real: 1}}, // Expected velues below are from pyquaternion. // pyquaternion does not support quaternion powers. // TODO(kortschak): Add non-real r cases. { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, want: Number{Real: -2, Imag: 2, Jmag: 2, Kmag: 2}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, want: Number{Real: -1, Imag: 0, Jmag: 2, Kmag: 2}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 2}, want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 2}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, want: Number{Real: -3, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 2}, want: Number{Real: -1, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, want: Number{Real: -8.728144138959564, Imag: -0.7527136547040768, Jmag: -0.7527136547040768, Kmag: -0.7527136547040768}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, want: Number{Real: -5.561182514695044, Imag: 0, Jmag: 0.5556661490713818, Kmag: 0.5556661490713818}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: math.Pi}, want: Number{Real: -2.320735561810013, Imag: 0, Jmag: 0, Kmag: 1.8544983901925216}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, want: Number{Real: 1.2388947209955585, Imag: -3.162774128856231, Jmag: -3.162774128856231, Kmag: -3.162774128856231}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, want: Number{Real: 0.6552860151073727, Imag: 0, Jmag: -2.0488506614051922, Kmag: -2.0488506614051922}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: math.Pi}, want: Number{Real: 0.22058404074969779, Imag: 0, Jmag: 0, Kmag: -0.9753679720836315}, }, { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, want: Number{Real: -8, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, want: Number{Real: -5, Imag: 0, Jmag: 1, Kmag: 1}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 3}, want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 2}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, want: Number{Real: 0, Imag: -3, Jmag: -3, Kmag: -3}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, want: Number{Real: 0, Imag: 0, Jmag: -2, Kmag: -2}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 3}, want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: -1}, }, } func TestPow(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range powTests { got := Pow(test.q, test.r) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Pow(%v, %v): got:%v want:%v", test.q, test.r, got, test.want) } } } var powRealTests = []struct { q Number r float64 want Number }{ {q: Number{}, r: 0, want: Number{Real: 1}}, { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: 2, want: Number{Real: -2, Imag: 2, Jmag: 2, Kmag: 2}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: 2, want: Number{Real: -1, Imag: 0, Jmag: 2, Kmag: 2}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: 2, want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 2}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: 2, want: Number{Real: -3, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: 2, want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: 2, want: Number{Real: -1, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: math.Pi, want: Number{Real: -8.728144138959564, Imag: -0.7527136547040768, Jmag: -0.7527136547040768, Kmag: -0.7527136547040768}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: math.Pi, want: Number{Real: -5.561182514695044, Imag: 0, Jmag: 0.5556661490713818, Kmag: 0.5556661490713818}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: math.Pi, want: Number{Real: -2.320735561810013, Imag: 0, Jmag: 0, Kmag: 1.8544983901925216}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: math.Pi, want: Number{Real: 1.2388947209955585, Imag: -3.162774128856231, Jmag: -3.162774128856231, Kmag: -3.162774128856231}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: math.Pi, want: Number{Real: 0.6552860151073727, Imag: 0, Jmag: -2.0488506614051922, Kmag: -2.0488506614051922}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: math.Pi, want: Number{Real: 0.22058404074969779, Imag: 0, Jmag: 0, Kmag: -0.9753679720836315}, }, { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: 3, want: Number{Real: -8, Imag: 0, Jmag: 0, Kmag: 0}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: 3, want: Number{Real: -5, Imag: 0, Jmag: 1, Kmag: 1}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: 3, want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 2}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: 3, want: Number{Real: 0, Imag: -3, Jmag: -3, Kmag: -3}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: 3, want: Number{Real: 0, Imag: 0, Jmag: -2, Kmag: -2}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: 3, want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: -1}, }, } func TestRealPow(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range powRealTests { got := PowReal(test.q, test.r) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Pow(%v, %v): got:%v want:%v", test.q, test.r, got, test.want) } } } var sqrtTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, // Expected velues below are from pyquaternion. { q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, want: Number{Real: 1.2247448713915892, Imag: 0.4082482904638631, Jmag: 0.4082482904638631, Kmag: 0.4082482904638631}, }, { q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, want: Number{Real: 1.1687708944803676, Imag: 0, Jmag: 0.42779983858367593, Kmag: 0.42779983858367593}, }, { q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, want: Number{Real: 1.0986841134678098, Imag: 0, Jmag: 0, Kmag: 0.45508986056222733}, }, { q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, want: Number{Real: 0.9306048591020996, Imag: 0.5372849659117709, Jmag: 0.5372849659117709, Kmag: 0.5372849659117709}, }, { q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, want: Number{Real: 0.8408964152537146, Imag: 0, Jmag: 0.5946035575013604, Kmag: 0.5946035575013604}, }, { q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, want: Number{Real: 0.7071067811865476, Imag: 0, Jmag: 0, Kmag: 0.7071067811865475}, }, } func TestSqrt(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range sqrtTests { got := Sqrt(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Sqrt(%v): got:%v want:%v", test.q, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/num/quat/inf.go000066400000000000000000000013571450372207100205200ustar00rootroot00000000000000// 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. // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package quat import "math" // IsInf returns true if any of real(q), imag(q), jmag(q), or kmag(q) is an infinity. func IsInf(q Number) bool { return math.IsInf(q.Real, 0) || math.IsInf(q.Imag, 0) || math.IsInf(q.Jmag, 0) || math.IsInf(q.Kmag, 0) } // Inf returns a quaternion infinity, quaternion(+Inf, +Inf, +Inf, +Inf). func Inf() Number { inf := math.Inf(1) return Number{Real: inf, Imag: inf, Jmag: inf, Kmag: inf} } golang-gonum-v1-gonum-0.14.0/num/quat/inf_test.go000066400000000000000000000030441450372207100215520ustar00rootroot00000000000000// 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 quat import ( "math" "testing" ) var inf = math.Inf(1) var infTests = []struct { q Number want bool }{ {q: Inf(), want: true}, {q: Number{Real: inf, Imag: inf, Jmag: inf, Kmag: inf}, want: true}, {q: Number{Real: -inf, Imag: -inf, Jmag: -inf, Kmag: -inf}, want: true}, {q: Number{Real: inf, Imag: nan, Jmag: nan, Kmag: nan}, want: true}, {q: Number{Real: nan, Imag: inf, Jmag: nan, Kmag: nan}, want: true}, {q: Number{Real: nan, Imag: nan, Jmag: inf, Kmag: nan}, want: true}, {q: Number{Real: nan, Imag: nan, Jmag: nan, Kmag: inf}, want: true}, {q: Number{Real: -inf, Imag: nan, Jmag: nan, Kmag: nan}, want: true}, {q: Number{Real: nan, Imag: -inf, Jmag: nan, Kmag: nan}, want: true}, {q: Number{Real: nan, Imag: nan, Jmag: -inf, Kmag: nan}, want: true}, {q: Number{Real: nan, Imag: nan, Jmag: nan, Kmag: -inf}, want: true}, {q: Number{Real: inf}, want: true}, {q: Number{Imag: inf}, want: true}, {q: Number{Jmag: inf}, want: true}, {q: Number{Kmag: inf}, want: true}, {q: Number{Real: -inf}, want: true}, {q: Number{Imag: -inf}, want: true}, {q: Number{Jmag: -inf}, want: true}, {q: Number{Kmag: -inf}, want: true}, {q: Number{}, want: false}, } func TestIsInf(t *testing.T) { t.Parallel() for _, test := range infTests { got := IsInf(test.q) if got != test.want { t.Errorf("unexpected result for IsInf(%v): got:%t want:%t", test.q, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/num/quat/nan.go000066400000000000000000000015331450372207100205140ustar00rootroot00000000000000// 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. // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package quat import "math" // IsNaN returns true if any of real(q), imag(q), jmag(q), or kmag(q) is NaN // and none are an infinity. func IsNaN(q Number) bool { if math.IsInf(q.Real, 0) || math.IsInf(q.Imag, 0) || math.IsInf(q.Jmag, 0) || math.IsInf(q.Kmag, 0) { return false } return math.IsNaN(q.Real) || math.IsNaN(q.Imag) || math.IsNaN(q.Jmag) || math.IsNaN(q.Kmag) } // NaN returns a quaternion “not-a-number” value. func NaN() Number { nan := math.NaN() return Number{Real: nan, Imag: nan, Jmag: nan, Kmag: nan} } golang-gonum-v1-gonum-0.14.0/num/quat/nan_test.go000066400000000000000000000026651450372207100215620ustar00rootroot00000000000000// 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 quat import ( "math" "testing" ) var nan = math.NaN() var nanTests = []struct { q Number want bool }{ {q: NaN(), want: true}, {q: Number{Real: nan, Imag: nan, Jmag: nan, Kmag: nan}, want: true}, {q: Number{Real: nan, Imag: 0, Jmag: 0, Kmag: 0}, want: true}, {q: Number{Real: 0, Imag: nan, Jmag: 0, Kmag: 0}, want: true}, {q: Number{Real: 0, Imag: 0, Jmag: nan, Kmag: 0}, want: true}, {q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: nan}, want: true}, {q: Number{Real: inf, Imag: nan, Jmag: nan, Kmag: nan}, want: false}, {q: Number{Real: nan, Imag: inf, Jmag: nan, Kmag: nan}, want: false}, {q: Number{Real: nan, Imag: nan, Jmag: inf, Kmag: nan}, want: false}, {q: Number{Real: nan, Imag: nan, Jmag: nan, Kmag: inf}, want: false}, {q: Number{Real: -inf, Imag: nan, Jmag: nan, Kmag: nan}, want: false}, {q: Number{Real: nan, Imag: -inf, Jmag: nan, Kmag: nan}, want: false}, {q: Number{Real: nan, Imag: nan, Jmag: -inf, Kmag: nan}, want: false}, {q: Number{Real: nan, Imag: nan, Jmag: nan, Kmag: -inf}, want: false}, {q: Number{}, want: false}, } func TestIsNaN(t *testing.T) { t.Parallel() for _, test := range nanTests { got := IsNaN(test.q) if got != test.want { t.Errorf("unexpected result for IsNaN(%v): got:%t want:%t", test.q, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/num/quat/quat.go000066400000000000000000000203641450372207100207150ustar00rootroot00000000000000// 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 quat import ( "fmt" "strconv" "strings" ) var zero Number // Number is a float64 precision quaternion. type Number struct { Real, Imag, Jmag, Kmag float64 } // Format implements fmt.Formatter. func (q Number) Format(fs fmt.State, c rune) { prec, pOk := fs.Precision() if !pOk { prec = -1 } width, wOk := fs.Width() if !wOk { width = -1 } switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T{Real:%#v, Imag:%#v, Jmag:%#v, Kmag:%#v}", q, q.Real, q.Imag, q.Jmag, q.Kmag) return } if fs.Flag('+') { fmt.Fprintf(fs, "{Real:%+v, Imag:%+v, Jmag:%+v, Kmag:%+v}", q.Real, q.Imag, q.Jmag, q.Kmag) return } c = 'g' prec = -1 fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': fre := fmtString(fs, c, prec, width, false) fim := fmtString(fs, c, prec, width, true) fmt.Fprintf(fs, fmt.Sprintf("(%s%[2]si%[2]sj%[2]sk)", fre, fim), q.Real, q.Imag, q.Jmag, q.Kmag) default: fmt.Fprintf(fs, "%%!%c(%T=%[2]v)", c, q) return } } // This is horrible, but it's what we have. func fmtString(fs fmt.State, c rune, prec, width int, wantPlus bool) string { var b strings.Builder b.WriteByte('%') for _, f := range "0+- " { if fs.Flag(int(f)) || (f == '+' && wantPlus) { b.WriteByte(byte(f)) } } if width >= 0 { fmt.Fprint(&b, width) } if prec >= 0 { b.WriteByte('.') if prec > 0 { fmt.Fprint(&b, prec) } } b.WriteRune(c) return b.String() } // Add returns the sum of x and y. func Add(x, y Number) Number { return Number{ Real: x.Real + y.Real, Imag: x.Imag + y.Imag, Jmag: x.Jmag + y.Jmag, Kmag: x.Kmag + y.Kmag, } } // Sub returns the difference of x and y, x-y. func Sub(x, y Number) Number { return Number{ Real: x.Real - y.Real, Imag: x.Imag - y.Imag, Jmag: x.Jmag - y.Jmag, Kmag: x.Kmag - y.Kmag, } } // Mul returns the Hamiltonian product of x and y. func Mul(x, y Number) Number { return Number{ Real: x.Real*y.Real - x.Imag*y.Imag - x.Jmag*y.Jmag - x.Kmag*y.Kmag, Imag: x.Real*y.Imag + x.Imag*y.Real + x.Jmag*y.Kmag - x.Kmag*y.Jmag, Jmag: x.Real*y.Jmag - x.Imag*y.Kmag + x.Jmag*y.Real + x.Kmag*y.Imag, Kmag: x.Real*y.Kmag + x.Imag*y.Jmag - x.Jmag*y.Imag + x.Kmag*y.Real, } } // Scale returns q scaled by f. func Scale(f float64, q Number) Number { return Number{Real: f * q.Real, Imag: f * q.Imag, Jmag: f * q.Jmag, Kmag: f * q.Kmag} } // Parse converts the string s to a Number. The string may be parenthesized and // has the format [±]N±Ni±Nj±Nk. The order of the components is not strict. func Parse(s string) (Number, error) { if len(s) == 0 { return Number{}, parseError{state: -1} } orig := s wantClose := s[0] == '(' if wantClose { if s[len(s)-1] != ')' { return Number{}, parseError{string: orig, state: -1} } s = s[1 : len(s)-1] } if len(s) == 0 { return Number{}, parseError{string: orig, state: -1} } switch s[0] { case 'n', 'N': if strings.ToLower(s) == "nan" { return NaN(), nil } case 'i', 'I': if strings.ToLower(s) == "inf" { return Inf(), nil } } var q Number var parts byte for i := 0; i < 4; i++ { beg, end, p, err := floatPart(s) if err != nil { return q, parseError{string: orig, state: -1} } if parts&(1< %+v\n", i, p, pp) } // Output: // // 0 {x:0 y:0 z:0} -> {x:0 y:0 z:0} // 1 {x:0 y:0 z:1} -> {x:1 y:0 z:0} // 2 {x:0 y:1 z:0} -> {x:0 y:0 z:1} // 3 {x:0 y:1 z:1} -> {x:1 y:0 z:1} // 4 {x:1 y:0 z:0} -> {x:0 y:1 z:0} // 5 {x:1 y:0 z:1} -> {x:1 y:1 z:0} // 6 {x:1 y:1 z:0} -> {x:0 y:1 z:1} // 7 {x:1 y:1 z:1} -> {x:1 y:1 z:1} } golang-gonum-v1-gonum-0.14.0/num/quat/quat_test.go000066400000000000000000000203111450372207100217440ustar00rootroot00000000000000// 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 quat import ( "fmt" "math" "testing" "gonum.org/v1/gonum/floats/scalar" ) var arithTests = []struct { x, y Number f float64 wantAdd Number wantSub Number wantMul Number wantScale Number }{ { x: Number{1, 1, 1, 1}, y: Number{1, 1, 1, 1}, f: 2, wantAdd: Number{2, 2, 2, 2}, wantSub: Number{0, 0, 0, 0}, wantMul: Number{-2, 2, 2, 2}, wantScale: Number{2, 2, 2, 2}, }, { x: Number{1, 1, 1, 1}, y: Number{2, -1, 1, -1}, f: -2, wantAdd: Number{3, 0, 2, 0}, wantSub: Number{-1, 2, 0, 2}, wantMul: Number{3, -1, 3, 3}, wantScale: Number{-2, -2, -2, -2}, }, { x: Number{1, 2, 3, 4}, y: Number{4, -3, 2, -1}, f: 2, wantAdd: Number{5, -1, 5, 3}, wantSub: Number{-3, 5, 1, 5}, wantMul: Number{8, -6, 4, 28}, wantScale: Number{2, 4, 6, 8}, }, { x: Number{1, 2, 3, 4}, y: Number{-4, 3, -2, 1}, f: -2, wantAdd: Number{-3, 5, 1, 5}, wantSub: Number{5, -1, 5, 3}, wantMul: Number{-8, 6, -4, -28}, wantScale: Number{-2, -4, -6, -8}, }, { x: Number{-4, 3, -2, 1}, y: Number{1, 2, 3, 4}, f: 0.5, wantAdd: Number{-3, 5, 1, 5}, wantSub: Number{-5, 1, -5, -3}, wantMul: Number{-8, -16, -24, -2}, wantScale: Number{-2, 1.5, -1, 0.5}, }, } func TestArithmetic(t *testing.T) { t.Parallel() for _, test := range arithTests { gotAdd := Add(test.x, test.y) if gotAdd != test.wantAdd { t.Errorf("unexpected result for %v+%v: got:%v, want:%v", test.x, test.y, gotAdd, test.wantAdd) } gotSub := Sub(test.x, test.y) if gotSub != test.wantSub { t.Errorf("unexpected result for %v-%v: got:%v, want:%v", test.x, test.y, gotSub, test.wantSub) } gotMul := Mul(test.x, test.y) if gotMul != test.wantMul { t.Errorf("unexpected result for %v*%v: got:%v, want:%v", test.x, test.y, gotMul, test.wantMul) } gotScale := Scale(test.f, test.x) if gotScale != test.wantScale { t.Errorf("unexpected result for %v*%v: got:%v, want:%v", test.f, test.x, gotScale, test.wantScale) } } } var formatTests = []struct { q Number format string want string }{ {q: Number{1.1, 2.1, 3.1, 4.1}, format: "%#v", want: "quat.Number{Real:1.1, Imag:2.1, Jmag:3.1, Kmag:4.1}"}, // Bootstrap test. {q: Number{-1.1, -2.1, -3.1, -4.1}, format: "%#v", want: "quat.Number{Real:-1.1, Imag:-2.1, Jmag:-3.1, Kmag:-4.1}"}, // Bootstrap test. {q: Number{1.1, 2.1, 3.1, 4.1}, format: "%+v", want: "{Real:1.1, Imag:2.1, Jmag:3.1, Kmag:4.1}"}, {q: Number{-1.1, -2.1, -3.1, -4.1}, format: "%+v", want: "{Real:-1.1, Imag:-2.1, Jmag:-3.1, Kmag:-4.1}"}, {q: Number{1, 2, 3, 4}, format: "%v", want: "(1+2i+3j+4k)"}, {q: Number{-1, -2, -3, -4}, format: "%v", want: "(-1-2i-3j-4k)"}, {q: Number{1, 2, 3, 4}, format: "%g", want: "(1+2i+3j+4k)"}, {q: Number{-1, -2, -3, -4}, format: "%g", want: "(-1-2i-3j-4k)"}, {q: Number{1, 2, 3, 4}, format: "%e", want: "(1.000000e+00+2.000000e+00i+3.000000e+00j+4.000000e+00k)"}, {q: Number{-1, -2, -3, -4}, format: "%e", want: "(-1.000000e+00-2.000000e+00i-3.000000e+00j-4.000000e+00k)"}, {q: Number{1, 2, 3, 4}, format: "%E", want: "(1.000000E+00+2.000000E+00i+3.000000E+00j+4.000000E+00k)"}, {q: Number{-1, -2, -3, -4}, format: "%E", want: "(-1.000000E+00-2.000000E+00i-3.000000E+00j-4.000000E+00k)"}, {q: Number{1, 2, 3, 4}, format: "%f", want: "(1.000000+2.000000i+3.000000j+4.000000k)"}, {q: Number{-1, -2, -3, -4}, format: "%f", want: "(-1.000000-2.000000i-3.000000j-4.000000k)"}, } func TestFormat(t *testing.T) { t.Parallel() for _, test := range formatTests { got := fmt.Sprintf(test.format, test.q) if got != test.want { t.Errorf("unexpected result for fmt.Sprintf(%q, %#v): got:%q, want:%q", test.format, test.q, got, test.want) } } } var parseTests = []struct { s string want Number wantErr error }{ // Simple error states: {s: "", wantErr: parseError{state: -1}}, {s: "()", wantErr: parseError{string: "()", state: -1}}, {s: "(1", wantErr: parseError{string: "(1", state: -1}}, {s: "1)", wantErr: parseError{string: "1)", state: -1}}, // Ambiguous parse error states: {s: "1+2i+3i", wantErr: parseError{string: "1+2i+3i", state: -1}}, {s: "1+2i3j", wantErr: parseError{string: "1+2i3j", state: -1}}, {s: "1e-4i-4k+10.3e6j+", wantErr: parseError{string: "1e-4i-4k+10.3e6j+", state: -1}}, {s: "1e-4i-4k+10.3e6j-", wantErr: parseError{string: "1e-4i-4k+10.3e6j-", state: -1}}, // Valid input: {s: "1+4i", want: Number{Real: 1, Imag: 4}}, {s: "4i+1", want: Number{Real: 1, Imag: 4}}, {s: "+1+4i", want: Number{Real: 1, Imag: 4}}, {s: "+4i+1", want: Number{Real: 1, Imag: 4}}, {s: "1e-4-4k+10.3e6j+1i", want: Number{Real: 1e-4, Imag: 1, Jmag: 10.3e6, Kmag: -4}}, {s: "1e-4-4k+10.3e6j+i", want: Number{Real: 1e-4, Imag: 1, Jmag: 10.3e6, Kmag: -4}}, {s: "1e-4-4k+10.3e6j-i", want: Number{Real: 1e-4, Imag: -1, Jmag: 10.3e6, Kmag: -4}}, {s: "1e-4i-4k+10.3e6j-1", want: Number{Real: -1, Imag: 1e-4, Jmag: 10.3e6, Kmag: -4}}, {s: "1e-4i-4k+10.3e6j+1", want: Number{Real: 1, Imag: 1e-4, Jmag: 10.3e6, Kmag: -4}}, {s: "(1+4i)", want: Number{Real: 1, Imag: 4}}, {s: "(4i+1)", want: Number{Real: 1, Imag: 4}}, {s: "(+1+4i)", want: Number{Real: 1, Imag: 4}}, {s: "(+4i+1)", want: Number{Real: 1, Imag: 4}}, {s: "(1e-4-4k+10.3e6j+1i)", want: Number{Real: 1e-4, Imag: 1, Jmag: 10.3e6, Kmag: -4}}, {s: "(1e-4-4k+10.3e6j+i)", want: Number{Real: 1e-4, Imag: 1, Jmag: 10.3e6, Kmag: -4}}, {s: "(1e-4-4k+10.3e6j-i)", want: Number{Real: 1e-4, Imag: -1, Jmag: 10.3e6, Kmag: -4}}, {s: "(1e-4i-4k+10.3e6j-1)", want: Number{Real: -1, Imag: 1e-4, Jmag: 10.3e6, Kmag: -4}}, {s: "(1e-4i-4k+10.3e6j+1)", want: Number{Real: 1, Imag: 1e-4, Jmag: 10.3e6, Kmag: -4}}, {s: "NaN", want: NaN()}, {s: "nan", want: NaN()}, {s: "Inf", want: Inf()}, {s: "inf", want: Inf()}, {s: "(Inf+Infi)", want: Number{Real: math.Inf(1), Imag: math.Inf(1)}}, {s: "(-Inf+Infi)", want: Number{Real: math.Inf(-1), Imag: math.Inf(1)}}, {s: "(+Inf-Infi)", want: Number{Real: math.Inf(1), Imag: math.Inf(-1)}}, {s: "(inf+infi)", want: Number{Real: math.Inf(1), Imag: math.Inf(1)}}, {s: "(-inf+infi)", want: Number{Real: math.Inf(-1), Imag: math.Inf(1)}}, {s: "(+inf-infi)", want: Number{Real: math.Inf(1), Imag: math.Inf(-1)}}, {s: "(nan+nani)", want: Number{Real: math.NaN(), Imag: math.NaN()}}, {s: "(nan-nani)", want: Number{Real: math.NaN(), Imag: math.NaN()}}, {s: "(nan+nani+1k)", want: Number{Real: math.NaN(), Imag: math.NaN(), Kmag: 1}}, {s: "(nan-nani+1k)", want: Number{Real: math.NaN(), Imag: math.NaN(), Kmag: 1}}, } func TestParse(t *testing.T) { t.Parallel() for _, test := range parseTests { got, err := Parse(test.s) if err != test.wantErr { t.Errorf("unexpected error for Parse(%q): got:%#v, want:%#v", test.s, err, test.wantErr) } if err != nil { continue } if !sameNumber(got, test.want) { t.Errorf("unexpected result for Parse(%q): got:%v, want:%v", test.s, got, test.want) } } } func equalApprox(a, b Number, tol float64) bool { return scalar.EqualWithinAbsOrRel(a.Real, b.Real, tol, tol) && scalar.EqualWithinAbsOrRel(a.Imag, b.Imag, tol, tol) && scalar.EqualWithinAbsOrRel(a.Jmag, b.Jmag, tol, tol) && scalar.EqualWithinAbsOrRel(a.Kmag, b.Kmag, tol, tol) } func sameApprox(a, b Number, tol float64) bool { switch { case a.Real == 0 && b.Real == 0: return math.Signbit(a.Real) == math.Signbit(b.Real) case a.Imag == 0 && b.Imag == 0: return math.Signbit(a.Imag) == math.Signbit(b.Imag) case a.Jmag == 0 && b.Jmag == 0: return math.Signbit(a.Jmag) == math.Signbit(b.Jmag) case a.Kmag == 0 && b.Kmag == 0: return math.Signbit(a.Kmag) == math.Signbit(b.Kmag) } return (sameFloat(a.Real, b.Real) || scalar.EqualWithinAbsOrRel(a.Real, b.Real, tol, tol)) && (sameFloat(a.Imag, b.Imag) || scalar.EqualWithinAbsOrRel(a.Imag, b.Imag, tol, tol)) && (sameFloat(a.Jmag, b.Jmag) || scalar.EqualWithinAbsOrRel(a.Jmag, b.Jmag, tol, tol)) && (sameFloat(a.Kmag, b.Kmag) || scalar.EqualWithinAbsOrRel(a.Kmag, b.Kmag, tol, tol)) } func sameNumber(a, b Number) bool { return sameFloat(a.Real, b.Real) && sameFloat(a.Imag, b.Imag) && sameFloat(a.Jmag, b.Jmag) && sameFloat(a.Kmag, b.Kmag) } func sameFloat(a, b float64) bool { return a == b || (math.IsNaN(a) && math.IsNaN(b)) } golang-gonum-v1-gonum-0.14.0/num/quat/trig.go000066400000000000000000000066141450372207100207120ustar00rootroot00000000000000// 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. // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package quat import "math" // Sin returns the sine of q. func Sin(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Sin(w)) } v := Abs(uv) s, c := math.Sincos(w) sh, ch := sinhcosh(v) return join(s*ch, Scale(c*sh/v, uv)) } // Sinh returns the hyperbolic sine of q. func Sinh(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Sinh(w)) } v := Abs(uv) s, c := math.Sincos(v) sh, ch := sinhcosh(w) return join(c*sh, scale(s*ch/v, uv)) } // Cos returns the cosine of q. func Cos(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Cos(w)) } v := Abs(uv) s, c := math.Sincos(w) sh, ch := sinhcosh(v) return join(c*ch, Scale(-s*sh/v, uv)) } // Cosh returns the hyperbolic cosine of q. func Cosh(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Cosh(w)) } v := Abs(uv) s, c := math.Sincos(v) sh, ch := sinhcosh(w) return join(c*ch, scale(s*sh/v, uv)) } // Tan returns the tangent of q. func Tan(q Number) Number { d := Cos(q) if d == zero { return Inf() } return Mul(Sin(q), Inv(d)) } // Tanh returns the hyperbolic tangent of q. func Tanh(q Number) Number { if math.IsInf(q.Real, 1) { r := Number{Real: 1} // Change signs dependent on imaginary parts. r.Imag *= math.Sin(2 * q.Imag) r.Jmag *= math.Sin(2 * q.Jmag) r.Kmag *= math.Sin(2 * q.Kmag) return r } d := Cosh(q) if d == zero { return Inf() } return Mul(Sinh(q), Inv(d)) } // Asin returns the inverse sine of q. func Asin(q Number) Number { _, uv := split(q) if uv == zero { return lift(math.Asin(q.Real)) } u := unit(uv) return Mul(Scale(-1, u), Log(Add(Mul(u, q), Sqrt(Sub(Number{Real: 1}, Mul(q, q)))))) } // Asinh returns the inverse hyperbolic sine of q. func Asinh(q Number) Number { return Log(Add(q, Sqrt(Add(Number{Real: 1}, Mul(q, q))))) } // Acos returns the inverse cosine of q. func Acos(q Number) Number { w, uv := split(Asin(q)) return join(math.Pi/2-w, Scale(-1, uv)) } // Acosh returns the inverse hyperbolic cosine of q. func Acosh(q Number) Number { w := Acos(q) _, uv := split(w) if uv == zero { return w } w = Mul(w, unit(uv)) if w.Real < 0 { w = Scale(-1, w) } return w } // Atan returns the inverse tangent of q. func Atan(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Atan(w)) } u := unit(uv) return Mul(Mul(lift(0.5), u), Log(Mul(Add(u, q), Inv(Sub(u, q))))) } // Atanh returns the inverse hyperbolic tangent of q. func Atanh(q Number) Number { w, uv := split(q) if uv == zero { return lift(math.Atanh(w)) } u := unit(uv) return Mul(Scale(-1, u), Atan(Mul(u, q))) } // calculate sinh and cosh func sinhcosh(x float64) (sh, ch float64) { if math.Abs(x) <= 0.5 { return math.Sinh(x), math.Cosh(x) } e := math.Exp(x) ei := 0.5 / e e *= 0.5 return e - ei, e + ei } // scale returns q scaled by f, except that inf×0 is 0. func scale(f float64, q Number) Number { if f == 0 { return Number{} } if q.Real != 0 { q.Real *= f } if q.Imag != 0 { q.Imag *= f } if q.Jmag != 0 { q.Jmag *= f } if q.Kmag != 0 { q.Kmag *= f } return q } golang-gonum-v1-gonum-0.14.0/num/quat/trig_test.go000066400000000000000000000333251450372207100217500ustar00rootroot00000000000000// 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 quat import ( "math" "math/cmplx" "testing" ) var sinTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: math.Pi / 2}, want: Number{Real: 1}}, {q: Number{Imag: math.Pi / 2}, want: Number{Imag: imag(cmplx.Sin(complex(0, math.Pi/2)))}}, {q: Number{Jmag: math.Pi / 2}, want: Number{Jmag: imag(cmplx.Sin(complex(0, math.Pi/2)))}}, {q: Number{Kmag: math.Pi / 2}, want: Number{Kmag: imag(cmplx.Sin(complex(0, math.Pi/2)))}}, // Exercises from Real Quaternionic Calculus Handbook doi:10.1007/978-3-0348-0622-0 // Ex 6.159 (a) and (b). {q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, want: func() Number { p := math.Cos(1) * math.Sinh(math.Sqrt(3)) / math.Sqrt(3) // An error exists in the book's given solution for the real part. return Number{Real: math.Sin(1) * math.Cosh(math.Sqrt(3)), Imag: p, Jmag: p, Kmag: p} }()}, {q: Number{Imag: -2, Jmag: 1}, want: func() Number { s := math.Sinh(math.Sqrt(5)) / math.Sqrt(5) return Number{Imag: -2 * s, Jmag: s} }()}, } func TestSin(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range sinTests { got := Sin(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Sin(%v): got:%v want:%v", test.q, got, test.want) } } } var sinhTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: math.Pi / 2}, want: Number{Real: math.Sinh(math.Pi / 2)}}, {q: Number{Imag: math.Pi / 2}, want: Number{Imag: imag(cmplx.Sinh(complex(0, math.Pi/2)))}}, {q: Number{Jmag: math.Pi / 2}, want: Number{Jmag: imag(cmplx.Sinh(complex(0, math.Pi/2)))}}, {q: Number{Kmag: math.Pi / 2}, want: Number{Kmag: imag(cmplx.Sinh(complex(0, math.Pi/2)))}}, {q: Number{Real: 1, Imag: -1, Jmag: -1}, want: func() Number { // This was based on the example on p118, but it too has an error. q := Number{Real: 1, Imag: -1, Jmag: -1} return Scale(0.5, Sub(Exp(q), Exp(Scale(-1, q)))) }()}, {q: Number{1, 1, 1, 1}, want: func() Number { q := Number{1, 1, 1, 1} return Scale(0.5, Sub(Exp(q), Exp(Scale(-1, q)))) }()}, {q: Asinh(Number{1, 1, 1, 1}), want: Number{1, 1, 1, 1}}, {q: Asinh(Number{1, 1, 1, 1}), want: func() Number { q := Asinh(Number{1, 1, 1, 1}) return Scale(0.5, Sub(Exp(q), Exp(Scale(-1, q)))) }()}, {q: Number{Real: math.Inf(1)}, want: Number{Real: math.Inf(1)}}, {q: Number{Real: math.Inf(1), Imag: math.Pi / 2}, want: Number{Real: math.Inf(1), Imag: math.Inf(1)}}, {q: Number{Real: math.Inf(1), Imag: math.Pi}, want: Number{Real: math.Inf(-1), Imag: math.Inf(1)}}, {q: Number{Real: math.Inf(1), Imag: 3 * math.Pi / 2}, want: Number{Real: math.Inf(-1), Imag: math.Inf(-1)}}, {q: Number{Real: math.Inf(1), Imag: 2 * math.Pi}, want: Number{Real: math.Inf(1), Imag: math.Inf(-1)}}, } func TestSinh(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range sinhTests { got := Sinh(test.q) if !sameApprox(got, test.want, tol) { t.Errorf("unexpected result for Sinh(%v): got:%v want:%v", test.q, got, test.want) } } } var cosTests = []struct { q Number want Number }{ {q: Number{}, want: Number{Real: 1}}, {q: Number{Real: math.Pi / 2}, want: Number{Real: 0}}, {q: Number{Imag: math.Pi / 2}, want: Number{Real: real(cmplx.Cos(complex(0, math.Pi/2)))}}, {q: Number{Jmag: math.Pi / 2}, want: Number{Real: real(cmplx.Cos(complex(0, math.Pi/2)))}}, {q: Number{Kmag: math.Pi / 2}, want: Number{Real: real(cmplx.Cos(complex(0, math.Pi/2)))}}, // Example from Real Quaternionic Calculus Handbook doi:10.1007/978-3-0348-0622-0 // p108. {q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, want: func() Number { p := math.Sin(1) * math.Sinh(math.Sqrt(3)) / math.Sqrt(3) return Number{Real: math.Cos(1) * math.Cosh(math.Sqrt(3)), Imag: -p, Jmag: -p, Kmag: -p} }()}, } func TestCos(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range cosTests { got := Cos(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Cos(%v): got:%v want:%v", test.q, got, test.want) } } } var coshTests = []struct { q Number want Number }{ {q: Number{}, want: Number{Real: 1}}, {q: Number{Real: math.Pi / 2}, want: Number{Real: math.Cosh(math.Pi / 2)}}, {q: Number{Imag: math.Pi / 2}, want: Number{Imag: imag(cmplx.Cosh(complex(0, math.Pi/2)))}}, {q: Number{Jmag: math.Pi / 2}, want: Number{Jmag: imag(cmplx.Cosh(complex(0, math.Pi/2)))}}, {q: Number{Kmag: math.Pi / 2}, want: Number{Kmag: imag(cmplx.Cosh(complex(0, math.Pi/2)))}}, {q: Number{Real: 1, Imag: -1, Jmag: -1}, want: func() Number { q := Number{Real: 1, Imag: -1, Jmag: -1} return Scale(0.5, Add(Exp(q), Exp(Scale(-1, q)))) }()}, {q: Number{1, 1, 1, 1}, want: func() Number { q := Number{1, 1, 1, 1} return Scale(0.5, Add(Exp(q), Exp(Scale(-1, q)))) }()}, {q: Number{Real: math.Inf(1)}, want: Number{Real: math.Inf(1)}}, {q: Number{Real: math.Inf(1), Imag: math.Pi / 2}, want: Number{Real: math.Inf(1), Imag: math.Inf(1)}}, {q: Number{Real: math.Inf(1), Imag: math.Pi}, want: Number{Real: math.Inf(-1), Imag: math.Inf(1)}}, {q: Number{Real: math.Inf(1), Imag: 3 * math.Pi / 2}, want: Number{Real: math.Inf(-1), Imag: math.Inf(-1)}}, {q: Number{Real: math.Inf(1), Imag: 2 * math.Pi}, want: Number{Real: math.Inf(1), Imag: math.Inf(-1)}}, } func TestCosh(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range coshTests { got := Cosh(test.q) if !sameApprox(got, test.want, tol) { t.Errorf("unexpected result for Cosh(%v): got:%v want:%v", test.q, got, test.want) } } } var tanTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: math.Pi / 4}, want: Number{Real: math.Tan(math.Pi / 4)}}, {q: Number{Imag: math.Pi / 4}, want: Number{Imag: imag(cmplx.Tan(complex(0, math.Pi/4)))}}, {q: Number{Jmag: math.Pi / 4}, want: Number{Jmag: imag(cmplx.Tan(complex(0, math.Pi/4)))}}, {q: Number{Kmag: math.Pi / 4}, want: Number{Kmag: imag(cmplx.Tan(complex(0, math.Pi/4)))}}, // From exercise from Real Numberernionic Calculus Handbook doi:10.1007/978-3-0348-0622-0 {q: Number{Imag: 1}, want: Mul(Sin(Number{Imag: 1}), Inv(Cos(Number{Imag: 1})))}, {q: Number{1, 1, 1, 1}, want: Mul(Sin(Number{1, 1, 1, 1}), Inv(Cos(Number{1, 1, 1, 1})))}, } func TestTan(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range tanTests { got := Tan(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Tan(%v): got:%v want:%v", test.q, got, test.want) } } } var tanhTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: math.Pi / 4}, want: Number{Real: math.Tanh(math.Pi / 4)}}, {q: Number{Imag: math.Pi / 4}, want: Number{Imag: imag(cmplx.Tanh(complex(0, math.Pi/4)))}}, {q: Number{Jmag: math.Pi / 4}, want: Number{Jmag: imag(cmplx.Tanh(complex(0, math.Pi/4)))}}, {q: Number{Kmag: math.Pi / 4}, want: Number{Kmag: imag(cmplx.Tanh(complex(0, math.Pi/4)))}}, {q: Number{Imag: 1}, want: Mul(Sinh(Number{Imag: 1}), Inv(Cosh(Number{Imag: 1})))}, {q: Number{1, 1, 1, 1}, want: Mul(Sinh(Number{1, 1, 1, 1}), Inv(Cosh(Number{1, 1, 1, 1})))}, {q: Number{Real: math.Inf(1)}, want: Number{Real: 1}}, {q: Number{Real: math.Inf(1), Imag: math.Pi / 4}, want: Number{Real: 1, Imag: 0 * math.Sin(math.Pi/2)}}, {q: Number{Real: math.Inf(1), Imag: math.Pi / 2}, want: Number{Real: 1, Imag: 0 * math.Sin(math.Pi)}}, {q: Number{Real: math.Inf(1), Imag: 3 * math.Pi / 4}, want: Number{Real: 1, Imag: 0 * math.Sin(3*math.Pi/2)}}, {q: Number{Real: math.Inf(1), Imag: math.Pi}, want: Number{Real: 1, Imag: 0 * math.Sin(2*math.Pi)}}, } func TestTanh(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range tanhTests { got := Tanh(test.q) if !sameApprox(got, test.want, tol) { t.Errorf("unexpected result for Tanh(%v): got:%v want:%v", test.q, got, test.want) } } } var asinTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: 1}, want: Number{Real: math.Pi / 2}}, {q: Number{Imag: 1}, want: Number{Imag: real(cmplx.Asinh(1))}}, {q: Number{Jmag: 1}, want: Number{Jmag: real(cmplx.Asinh(1))}}, {q: Number{Kmag: 1}, want: Number{Kmag: real(cmplx.Asinh(1))}}, {q: Sin(Number{1, 1, 1, 1}), want: Number{1, 1, 1, 1}}, } func TestAsin(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range asinTests { got := Asin(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Asin(%v): got:%v want:%v", test.q, got, test.want) } } } var asinhTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: 1}, want: Number{Real: math.Asinh(1)}}, {q: Number{Imag: 1}, want: Number{Imag: math.Pi / 2}}, {q: Number{Jmag: 1}, want: Number{Jmag: math.Pi / 2}}, {q: Number{Kmag: 1}, want: Number{Kmag: math.Pi / 2}}, {q: Number{1, 1, 1, 1}, want: func() Number { q := Number{1, 1, 1, 1} return Log(Add(q, Sqrt(Add(Mul(q, q), Number{Real: 1})))) }()}, {q: Sinh(Number{Real: 1}), want: Number{Real: 1}}, {q: Sinh(Number{Imag: 1}), want: Number{Imag: 1}}, {q: Sinh(Number{Imag: 1, Jmag: 1}), want: Number{Imag: 1, Jmag: 1}}, {q: Sinh(Number{Real: 1, Imag: 1, Jmag: 1}), want: Number{Real: 1, Imag: 1, Jmag: 1}}, // The following fails: // {q: Sinh(Number{1, 1, 1, 1}), want: Number{1, 1, 1, 1}}, // but this passes... {q: Sinh(Number{1, 1, 1, 1}), want: func() Number { q := Sinh(Number{1, 1, 1, 1}) return Log(Add(q, Sqrt(Add(Mul(q, q), Number{Real: 1})))) }()}, // And see the Sinh tests that do the reciprocal operation. } func TestAsinh(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range asinhTests { got := Asinh(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Asinh(%v): got:%v want:%v", test.q, got, test.want) } } } var acosTests = []struct { q Number want Number }{ {q: Number{}, want: Number{Real: math.Pi / 2}}, {q: Number{Real: 1}, want: Number{Real: 0}}, {q: Number{Imag: 1}, want: Number{Real: real(cmplx.Acos(1i)), Imag: imag(cmplx.Acos(1i))}}, {q: Number{Jmag: 1}, want: Number{Real: real(cmplx.Acos(1i)), Jmag: imag(cmplx.Acos(1i))}}, {q: Number{Kmag: 1}, want: Number{Real: real(cmplx.Acos(1i)), Kmag: imag(cmplx.Acos(1i))}}, {q: Cos(Number{1, 1, 1, 1}), want: Number{1, 1, 1, 1}}, } func TestAcos(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range acosTests { got := Acos(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Acos(%v): got:%v want:%v", test.q, got, test.want) } } } var acoshTests = []struct { q Number want Number }{ {q: Number{}, want: Number{Real: math.Pi / 2}}, {q: Number{Real: 1}, want: Number{Real: math.Acosh(1)}}, {q: Number{Imag: 1}, want: Number{Real: real(cmplx.Acosh(1i)), Imag: imag(cmplx.Acosh(1i))}}, {q: Number{Jmag: 1}, want: Number{Real: real(cmplx.Acosh(1i)), Jmag: imag(cmplx.Acosh(1i))}}, {q: Number{Kmag: 1}, want: Number{Real: real(cmplx.Acosh(1i)), Kmag: imag(cmplx.Acosh(1i))}}, {q: Cosh(Number{1, 1, 1, 1}), want: Number{1, 1, 1, 1}}, {q: Number{1, 1, 1, 1}, want: func() Number { q := Number{1, 1, 1, 1} return Log(Add(q, Sqrt(Sub(Mul(q, q), Number{Real: 1})))) }()}, // The following fails by a factor of -1. // {q: Cosh(Number{1, 1, 1, 1}), want: func() Number { // q := Cosh(Number{1, 1, 1, 1}) // return Log(Add(q, Sqrt(Sub(Mul(q, q), Number{Real: 1})))) // }()}, } func TestAcosh(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range acoshTests { got := Acosh(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Acosh(%v): got:%v want:%v", test.q, got, test.want) } } } var atanTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: 1}, want: Number{Real: math.Pi / 4}}, {q: Number{Imag: 0.5}, want: Number{Real: real(cmplx.Atan(0.5i)), Imag: imag(cmplx.Atan(0.5i))}}, {q: Number{Jmag: 0.5}, want: Number{Real: real(cmplx.Atan(0.5i)), Jmag: imag(cmplx.Atan(0.5i))}}, {q: Number{Kmag: 0.5}, want: Number{Real: real(cmplx.Atan(0.5i)), Kmag: imag(cmplx.Atan(0.5i))}}, {q: Tan(Number{1, 1, 1, 1}), want: Number{1, 1, 1, 1}}, } func TestAtan(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range atanTests { got := Atan(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Atan(%v): got:%v want:%v", test.q, got, test.want) } } } var atanhTests = []struct { q Number want Number }{ {q: Number{}, want: Number{}}, {q: Number{Real: 1}, want: Number{Real: math.Atanh(1)}}, {q: Number{Imag: 0.5}, want: Number{Real: real(cmplx.Atanh(0.5i)), Imag: imag(cmplx.Atanh(0.5i))}}, {q: Number{Jmag: 0.5}, want: Number{Real: real(cmplx.Atanh(0.5i)), Jmag: imag(cmplx.Atanh(0.5i))}}, {q: Number{Kmag: 0.5}, want: Number{Real: real(cmplx.Atanh(0.5i)), Kmag: imag(cmplx.Atanh(0.5i))}}, {q: Number{1, 1, 1, 1}, want: func() Number { q := Number{1, 1, 1, 1} return Scale(0.5, Sub(Log(Add(Number{Real: 1}, q)), Log(Sub(Number{Real: 1}, q)))) }()}, {q: Tanh(Number{Real: 1}), want: Number{Real: 1}}, {q: Tanh(Number{Imag: 1}), want: Number{Imag: 1}}, {q: Tanh(Number{Imag: 1, Jmag: 1}), want: Number{Imag: 1, Jmag: 1}}, {q: Tanh(Number{Real: 1, Imag: 1, Jmag: 1}), want: Number{Real: 1, Imag: 1, Jmag: 1}}, // The following fails // {q: Tanh(Number{1, 1, 1, 1}), want: Number{1, 1, 1, 1}}, // but... {q: Tanh(Number{1, 1, 1, 1}), want: func() Number { q := Tanh(Number{1, 1, 1, 1}) return Scale(0.5, Sub(Log(Add(Number{Real: 1}, q)), Log(Sub(Number{Real: 1}, q)))) }()}, } func TestAtanh(t *testing.T) { t.Parallel() const tol = 1e-14 for _, test := range atanhTests { got := Atanh(test.q) if !equalApprox(got, test.want, tol) { t.Errorf("unexpected result for Atanh(%v): got:%v want:%v", test.q, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/num/quat/util.go000066400000000000000000000011671450372207100207200ustar00rootroot00000000000000// 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. // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package quat func lift(v float64) Number { return Number{Real: v} } func split(q Number) (float64, Number) { return q.Real, Number{Imag: q.Imag, Jmag: q.Jmag, Kmag: q.Kmag} } func join(w float64, uv Number) Number { uv.Real = w return uv } func unit(q Number) Number { return Scale(1/Abs(q), q) } golang-gonum-v1-gonum-0.14.0/optimize/000077500000000000000000000000001450372207100174765ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/optimize/README.md000066400000000000000000000005041450372207100207540ustar00rootroot00000000000000# Gonum optimize [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/optimize)](https://pkg.go.dev/gonum.org/v1/gonum/optimize) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/optimize?status.svg)](https://godocs.io/gonum.org/v1/gonum/optimize) Package optimize is an optimization package for the Go language. golang-gonum-v1-gonum-0.14.0/optimize/backtracking.go000066400000000000000000000051761450372207100224610ustar00rootroot00000000000000// 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 optimize const ( defaultBacktrackingContraction = 0.5 defaultBacktrackingDecrease = 1e-4 minimumBacktrackingStepSize = 1e-20 ) var _ Linesearcher = (*Backtracking)(nil) // Backtracking is a Linesearcher that uses backtracking to find a point that // satisfies the Armijo condition with the given decrease factor. If the Armijo // condition has not been met, the step size is decreased by ContractionFactor. // // The Armijo condition only requires the gradient at the beginning of each // major iteration (not at successive step locations), and so Backtracking may // be a good linesearch for functions with expensive gradients. Backtracking is // not appropriate for optimizers that require the Wolfe conditions to be met, // such as BFGS. // // Both DecreaseFactor and ContractionFactor must be between zero and one, and // Backtracking will panic otherwise. If either DecreaseFactor or // ContractionFactor are zero, it will be set to a reasonable default. type Backtracking struct { DecreaseFactor float64 // Constant factor in the sufficient decrease (Armijo) condition. ContractionFactor float64 // Step size multiplier at each iteration (step *= ContractionFactor). stepSize float64 initF float64 initG float64 lastOp Operation } func (b *Backtracking) Init(f, g float64, step float64) Operation { if step <= 0 { panic("backtracking: bad step size") } if g >= 0 { panic("backtracking: initial derivative is non-negative") } if b.ContractionFactor == 0 { b.ContractionFactor = defaultBacktrackingContraction } if b.DecreaseFactor == 0 { b.DecreaseFactor = defaultBacktrackingDecrease } if b.ContractionFactor <= 0 || b.ContractionFactor >= 1 { panic("backtracking: ContractionFactor must be between 0 and 1") } if b.DecreaseFactor <= 0 || b.DecreaseFactor >= 1 { panic("backtracking: DecreaseFactor must be between 0 and 1") } b.stepSize = step b.initF = f b.initG = g b.lastOp = FuncEvaluation return b.lastOp } func (b *Backtracking) Iterate(f, _ float64) (Operation, float64, error) { if b.lastOp != FuncEvaluation { panic("backtracking: Init has not been called") } if ArmijoConditionMet(f, b.initF, b.initG, b.stepSize, b.DecreaseFactor) { b.lastOp = MajorIteration return b.lastOp, b.stepSize, nil } b.stepSize *= b.ContractionFactor if b.stepSize < minimumBacktrackingStepSize { b.lastOp = NoOperation return b.lastOp, b.stepSize, ErrLinesearcherFailure } b.lastOp = FuncEvaluation return b.lastOp, b.stepSize, nil } golang-gonum-v1-gonum-0.14.0/optimize/bfgs.go000066400000000000000000000117571450372207100207610ustar00rootroot00000000000000// 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 optimize import ( "math" "gonum.org/v1/gonum/mat" ) var ( _ Method = (*BFGS)(nil) _ localMethod = (*BFGS)(nil) _ NextDirectioner = (*BFGS)(nil) ) // BFGS implements the Broyden–Fletcher–Goldfarb–Shanno optimization method. It // is a quasi-Newton method that performs successive rank-one updates to an // estimate of the inverse Hessian of the objective function. It exhibits // super-linear convergence when in proximity to a local minimum. It has memory // cost that is O(n^2) relative to the input dimension. type BFGS struct { // Linesearcher selects suitable steps along the descent direction. // Accepted steps should satisfy the strong Wolfe conditions. // If Linesearcher == nil, an appropriate default is chosen. Linesearcher Linesearcher // GradStopThreshold sets the threshold for stopping if the gradient norm // gets too small. If GradStopThreshold is 0 it is defaulted to 1e-12, and // if it is NaN the setting is not used. GradStopThreshold float64 ls *LinesearchMethod status Status err error dim int x mat.VecDense // Location of the last major iteration. grad mat.VecDense // Gradient at the last major iteration. s mat.VecDense // Difference between locations in this and the previous iteration. y mat.VecDense // Difference between gradients in this and the previous iteration. tmp mat.VecDense invHess *mat.SymDense first bool // Indicator of the first iteration. } func (b *BFGS) Status() (Status, error) { return b.status, b.err } func (*BFGS) Uses(has Available) (uses Available, err error) { return has.gradient() } func (b *BFGS) Init(dim, tasks int) int { b.status = NotTerminated b.err = nil return 1 } func (b *BFGS) Run(operation chan<- Task, result <-chan Task, tasks []Task) { b.status, b.err = localOptimizer{}.run(b, b.GradStopThreshold, operation, result, tasks) close(operation) } func (b *BFGS) initLocal(loc *Location) (Operation, error) { if b.Linesearcher == nil { b.Linesearcher = &Bisection{} } if b.ls == nil { b.ls = &LinesearchMethod{} } b.ls.Linesearcher = b.Linesearcher b.ls.NextDirectioner = b return b.ls.Init(loc) } func (b *BFGS) iterateLocal(loc *Location) (Operation, error) { return b.ls.Iterate(loc) } func (b *BFGS) InitDirection(loc *Location, dir []float64) (stepSize float64) { dim := len(loc.X) b.dim = dim b.first = true x := mat.NewVecDense(dim, loc.X) grad := mat.NewVecDense(dim, loc.Gradient) b.x.CloneFromVec(x) b.grad.CloneFromVec(grad) b.y.Reset() b.s.Reset() b.tmp.Reset() if b.invHess == nil || cap(b.invHess.RawSymmetric().Data) < dim*dim { b.invHess = mat.NewSymDense(dim, nil) } else { b.invHess = mat.NewSymDense(dim, b.invHess.RawSymmetric().Data[:dim*dim]) } // The values of the inverse Hessian are initialized in the first call to // NextDirection. // Initial direction is just negative of the gradient because the Hessian // is an identity matrix. d := mat.NewVecDense(dim, dir) d.ScaleVec(-1, grad) return 1 / mat.Norm(d, 2) } func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) { dim := b.dim if len(loc.X) != dim { panic("bfgs: unexpected size mismatch") } if len(loc.Gradient) != dim { panic("bfgs: unexpected size mismatch") } if len(dir) != dim { panic("bfgs: unexpected size mismatch") } x := mat.NewVecDense(dim, loc.X) grad := mat.NewVecDense(dim, loc.Gradient) // s = x_{k+1} - x_{k} b.s.SubVec(x, &b.x) // y = g_{k+1} - g_{k} b.y.SubVec(grad, &b.grad) sDotY := mat.Dot(&b.s, &b.y) if b.first { // Rescale the initial Hessian. // From: Nocedal, J., Wright, S.: Numerical Optimization (2nd ed). // Springer (2006), page 143, eq. 6.20. yDotY := mat.Dot(&b.y, &b.y) scale := sDotY / yDotY for i := 0; i < dim; i++ { for j := i; j < dim; j++ { if i == j { b.invHess.SetSym(i, i, scale) } else { b.invHess.SetSym(i, j, 0) } } } b.first = false } if math.Abs(sDotY) != 0 { // Update the inverse Hessian according to the formula // // B_{k+1}^-1 = B_k^-1 // + (s_kᵀ y_k + y_kᵀ B_k^-1 y_k) / (s_kᵀ y_k)^2 * (s_k s_kᵀ) // - (B_k^-1 y_k s_kᵀ + s_k y_kᵀ B_k^-1) / (s_kᵀ y_k). // // Note that y_kᵀ B_k^-1 y_k is a scalar, and that the third term is a // rank-two update where B_k^-1 y_k is one vector and s_k is the other. yBy := mat.Inner(&b.y, b.invHess, &b.y) b.tmp.MulVec(b.invHess, &b.y) scale := (1 + yBy/sDotY) / sDotY b.invHess.SymRankOne(b.invHess, scale, &b.s) b.invHess.RankTwo(b.invHess, -1/sDotY, &b.tmp, &b.s) } // Update the stored BFGS data. b.x.CopyVec(x) b.grad.CopyVec(grad) // New direction is stored in dir. d := mat.NewVecDense(dim, dir) d.MulVec(b.invHess, grad) d.ScaleVec(-1, d) return 1 } func (*BFGS) needs() struct { Gradient bool Hessian bool } { return struct { Gradient bool Hessian bool }{true, false} } golang-gonum-v1-gonum-0.14.0/optimize/bisection.go000066400000000000000000000076721450372207100220200ustar00rootroot00000000000000// 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 optimize import "math" const defaultBisectionCurvature = 0.9 var _ Linesearcher = (*Bisection)(nil) // Bisection is a Linesearcher that uses a bisection to find a point that // satisfies the strong Wolfe conditions with the given curvature factor and // a decrease factor of zero. type Bisection struct { // CurvatureFactor is the constant factor in the curvature condition. // Smaller values result in a more exact line search. // A set value must be in the interval (0, 1), otherwise Init will panic. // If it is zero, it will be defaulted to 0.9. CurvatureFactor float64 minStep float64 maxStep float64 currStep float64 initF float64 minF float64 maxF float64 lastF float64 initGrad float64 lastOp Operation } func (b *Bisection) Init(f, g float64, step float64) Operation { if step <= 0 { panic("bisection: bad step size") } if g >= 0 { panic("bisection: initial derivative is non-negative") } if b.CurvatureFactor == 0 { b.CurvatureFactor = defaultBisectionCurvature } if b.CurvatureFactor <= 0 || b.CurvatureFactor >= 1 { panic("bisection: CurvatureFactor not between 0 and 1") } b.minStep = 0 b.maxStep = math.Inf(1) b.currStep = step b.initF = f b.minF = f b.maxF = math.NaN() b.initGrad = g // Only evaluate the gradient when necessary. b.lastOp = FuncEvaluation return b.lastOp } func (b *Bisection) Iterate(f, g float64) (Operation, float64, error) { if b.lastOp != FuncEvaluation && b.lastOp != GradEvaluation { panic("bisection: Init has not been called") } minF := b.initF if b.maxF < minF { minF = b.maxF } if b.minF < minF { minF = b.minF } if b.lastOp == FuncEvaluation { // See if the function value is good enough to make progress. If it is, // evaluate the gradient. If not, set it to the upper bound if the bound // has not yet been found, otherwise iterate toward the minimum location. if f <= minF { b.lastF = f b.lastOp = GradEvaluation return b.lastOp, b.currStep, nil } if math.IsInf(b.maxStep, 1) { b.maxStep = b.currStep b.maxF = f return b.nextStep((b.minStep + b.maxStep) / 2) } if b.minF <= b.maxF { b.maxStep = b.currStep b.maxF = f } else { b.minStep = b.currStep b.minF = f } return b.nextStep((b.minStep + b.maxStep) / 2) } f = b.lastF // The function value was lower. Check if this location is sufficient to // converge the linesearch, otherwise iterate. if StrongWolfeConditionsMet(f, g, minF, b.initGrad, b.currStep, 0, b.CurvatureFactor) { b.lastOp = MajorIteration return b.lastOp, b.currStep, nil } if math.IsInf(b.maxStep, 1) { // The function value is lower. If the gradient is positive, an upper bound // of the minimum been found. If the gradient is negative, search farther // in that direction. if g > 0 { b.maxStep = b.currStep b.maxF = f return b.nextStep((b.minStep + b.maxStep) / 2) } b.minStep = b.currStep b.minF = f return b.nextStep(b.currStep * 2) } // The interval has been bounded, and we have found a new lowest value. Use // the gradient to decide which direction. if g < 0 { b.minStep = b.currStep b.minF = f } else { b.maxStep = b.currStep b.maxF = f } return b.nextStep((b.minStep + b.maxStep) / 2) } // nextStep checks if the new step is equal to the old step. // This can happen if min and max are the same, or if the step size is infinity, // both of which indicate the minimization must stop. If the steps are different, // it sets the new step size and returns the evaluation type and the step. If the steps // are the same, it returns an error. func (b *Bisection) nextStep(step float64) (Operation, float64, error) { if b.currStep == step { b.lastOp = NoOperation return b.lastOp, b.currStep, ErrLinesearcherFailure } b.currStep = step b.lastOp = FuncEvaluation return b.lastOp, b.currStep, nil } golang-gonum-v1-gonum-0.14.0/optimize/cg.go000066400000000000000000000271441450372207100204260ustar00rootroot00000000000000// 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 optimize import ( "math" "gonum.org/v1/gonum/floats" ) const ( iterationRestartFactor = 6 angleRestartThreshold = -0.9 ) var ( _ Method = (*CG)(nil) _ localMethod = (*CG)(nil) _ NextDirectioner = (*CG)(nil) ) // CGVariant calculates the scaling parameter, β, used for updating the // conjugate direction in the nonlinear conjugate gradient (CG) method. type CGVariant interface { // Init is called at the first iteration and provides a way to initialize // any internal state. Init(loc *Location) // Beta returns the value of the scaling parameter that is computed // according to the particular variant of the CG method. Beta(grad, gradPrev, dirPrev []float64) float64 } var ( _ CGVariant = (*FletcherReeves)(nil) _ CGVariant = (*PolakRibierePolyak)(nil) _ CGVariant = (*HestenesStiefel)(nil) _ CGVariant = (*DaiYuan)(nil) _ CGVariant = (*HagerZhang)(nil) ) // CG implements the nonlinear conjugate gradient method for solving nonlinear // unconstrained optimization problems. It is a line search method that // generates the search directions d_k according to the formula // // d_{k+1} = -∇f_{k+1} + β_k*d_k, d_0 = -∇f_0. // // Variants of the conjugate gradient method differ in the choice of the // parameter β_k. The conjugate gradient method usually requires fewer function // evaluations than the gradient descent method and no matrix storage, but // L-BFGS is usually more efficient. // // CG implements a restart strategy that takes the steepest descent direction // (i.e., d_{k+1} = -∇f_{k+1}) whenever any of the following conditions holds: // // - A certain number of iterations has elapsed without a restart. This number // is controllable via IterationRestartFactor and if equal to 0, it is set to // a reasonable default based on the problem dimension. // - The angle between the gradients at two consecutive iterations ∇f_k and // ∇f_{k+1} is too large. // - The direction d_{k+1} is not a descent direction. // - β_k returned from CGVariant.Beta is equal to zero. // // The line search for CG must yield step sizes that satisfy the strong Wolfe // conditions at every iteration, otherwise the generated search direction // might fail to be a descent direction. The line search should be more // stringent compared with those for Newton-like methods, which can be achieved // by setting the gradient constant in the strong Wolfe conditions to a small // value. // // See also William Hager, Hongchao Zhang, A survey of nonlinear conjugate // gradient methods. Pacific Journal of Optimization, 2 (2006), pp. 35-58, and // references therein. type CG struct { // Linesearcher must satisfy the strong Wolfe conditions at every iteration. // If Linesearcher == nil, an appropriate default is chosen. Linesearcher Linesearcher // Variant implements the particular CG formula for computing β_k. // If Variant is nil, an appropriate default is chosen. Variant CGVariant // InitialStep estimates the initial line search step size, because the CG // method does not generate well-scaled search directions. // If InitialStep is nil, an appropriate default is chosen. InitialStep StepSizer // IterationRestartFactor determines the frequency of restarts based on the // problem dimension. The negative gradient direction is taken whenever // ceil(IterationRestartFactor*(problem dimension)) iterations have elapsed // without a restart. For medium and large-scale problems // IterationRestartFactor should be set to 1, low-dimensional problems a // larger value should be chosen. Note that if the ceil function returns 1, // CG will be identical to gradient descent. // If IterationRestartFactor is 0, it will be set to 6. // CG will panic if IterationRestartFactor is negative. IterationRestartFactor float64 // AngleRestartThreshold sets the threshold angle for restart. The method // is restarted if the cosine of the angle between two consecutive // gradients is smaller than or equal to AngleRestartThreshold, that is, if // ∇f_k·∇f_{k+1} / (|∇f_k| |∇f_{k+1}|) <= AngleRestartThreshold. // A value of AngleRestartThreshold closer to -1 (successive gradients in // exact opposite directions) will tend to reduce the number of restarts. // If AngleRestartThreshold is 0, it will be set to -0.9. // CG will panic if AngleRestartThreshold is not in the interval [-1, 0]. AngleRestartThreshold float64 // GradStopThreshold sets the threshold for stopping if the gradient norm // gets too small. If GradStopThreshold is 0 it is defaulted to 1e-12, and // if it is NaN the setting is not used. GradStopThreshold float64 ls *LinesearchMethod status Status err error restartAfter int iterFromRestart int dirPrev []float64 gradPrev []float64 gradPrevNorm float64 } func (cg *CG) Status() (Status, error) { return cg.status, cg.err } func (*CG) Uses(has Available) (uses Available, err error) { return has.gradient() } func (cg *CG) Init(dim, tasks int) int { cg.status = NotTerminated cg.err = nil return 1 } func (cg *CG) Run(operation chan<- Task, result <-chan Task, tasks []Task) { cg.status, cg.err = localOptimizer{}.run(cg, cg.GradStopThreshold, operation, result, tasks) close(operation) } func (cg *CG) initLocal(loc *Location) (Operation, error) { if cg.IterationRestartFactor < 0 { panic("cg: IterationRestartFactor is negative") } if cg.AngleRestartThreshold < -1 || cg.AngleRestartThreshold > 0 { panic("cg: AngleRestartThreshold not in [-1, 0]") } if cg.Linesearcher == nil { cg.Linesearcher = &MoreThuente{CurvatureFactor: 0.1} } if cg.Variant == nil { cg.Variant = &HestenesStiefel{} } if cg.InitialStep == nil { cg.InitialStep = &FirstOrderStepSize{} } if cg.IterationRestartFactor == 0 { cg.IterationRestartFactor = iterationRestartFactor } if cg.AngleRestartThreshold == 0 { cg.AngleRestartThreshold = angleRestartThreshold } if cg.ls == nil { cg.ls = &LinesearchMethod{} } cg.ls.Linesearcher = cg.Linesearcher cg.ls.NextDirectioner = cg return cg.ls.Init(loc) } func (cg *CG) iterateLocal(loc *Location) (Operation, error) { return cg.ls.Iterate(loc) } func (cg *CG) InitDirection(loc *Location, dir []float64) (stepSize float64) { dim := len(loc.X) cg.restartAfter = int(math.Ceil(cg.IterationRestartFactor * float64(dim))) cg.iterFromRestart = 0 // The initial direction is always the negative gradient. copy(dir, loc.Gradient) floats.Scale(-1, dir) cg.dirPrev = resize(cg.dirPrev, dim) copy(cg.dirPrev, dir) cg.gradPrev = resize(cg.gradPrev, dim) copy(cg.gradPrev, loc.Gradient) cg.gradPrevNorm = floats.Norm(loc.Gradient, 2) cg.Variant.Init(loc) return cg.InitialStep.Init(loc, dir) } func (cg *CG) NextDirection(loc *Location, dir []float64) (stepSize float64) { copy(dir, loc.Gradient) floats.Scale(-1, dir) cg.iterFromRestart++ var restart bool if cg.iterFromRestart == cg.restartAfter { // Restart because too many iterations have been taken without a restart. restart = true } gDot := floats.Dot(loc.Gradient, cg.gradPrev) gNorm := floats.Norm(loc.Gradient, 2) if gDot <= cg.AngleRestartThreshold*gNorm*cg.gradPrevNorm { // Restart because the angle between the last two gradients is too large. restart = true } // Compute the scaling factor β_k even when restarting, because cg.Variant // may be keeping an inner state that needs to be updated at every iteration. beta := cg.Variant.Beta(loc.Gradient, cg.gradPrev, cg.dirPrev) if beta == 0 { // β_k == 0 means that the steepest descent direction will be taken, so // indicate that the method is in fact being restarted. restart = true } if !restart { // The method is not being restarted, so update the descent direction. floats.AddScaled(dir, beta, cg.dirPrev) if floats.Dot(loc.Gradient, dir) >= 0 { // Restart because the new direction is not a descent direction. restart = true copy(dir, loc.Gradient) floats.Scale(-1, dir) } } // Get the initial line search step size from the StepSizer even if the // method was restarted, because StepSizers need to see every iteration. stepSize = cg.InitialStep.StepSize(loc, dir) if restart { // The method was restarted and since the steepest descent direction is // not related to the previous direction, discard the estimated step // size from cg.InitialStep and use step size of 1 instead. stepSize = 1 // Reset to 0 the counter of iterations taken since the last restart. cg.iterFromRestart = 0 } copy(cg.gradPrev, loc.Gradient) copy(cg.dirPrev, dir) cg.gradPrevNorm = gNorm return stepSize } func (*CG) needs() struct { Gradient bool Hessian bool } { return struct { Gradient bool Hessian bool }{true, false} } // FletcherReeves implements the Fletcher-Reeves variant of the CG method that // computes the scaling parameter β_k according to the formula // // β_k = |∇f_{k+1}|^2 / |∇f_k|^2. type FletcherReeves struct { prevNorm float64 } func (fr *FletcherReeves) Init(loc *Location) { fr.prevNorm = floats.Norm(loc.Gradient, 2) } func (fr *FletcherReeves) Beta(grad, _, _ []float64) (beta float64) { norm := floats.Norm(grad, 2) beta = (norm / fr.prevNorm) * (norm / fr.prevNorm) fr.prevNorm = norm return beta } // PolakRibierePolyak implements the Polak-Ribiere-Polyak variant of the CG // method that computes the scaling parameter β_k according to the formula // // β_k = max(0, ∇f_{k+1}·y_k / |∇f_k|^2), // // where y_k = ∇f_{k+1} - ∇f_k. type PolakRibierePolyak struct { prevNorm float64 } func (pr *PolakRibierePolyak) Init(loc *Location) { pr.prevNorm = floats.Norm(loc.Gradient, 2) } func (pr *PolakRibierePolyak) Beta(grad, gradPrev, _ []float64) (beta float64) { norm := floats.Norm(grad, 2) dot := floats.Dot(grad, gradPrev) beta = (norm*norm - dot) / (pr.prevNorm * pr.prevNorm) pr.prevNorm = norm return math.Max(0, beta) } // HestenesStiefel implements the Hestenes-Stiefel variant of the CG method // that computes the scaling parameter β_k according to the formula // // β_k = max(0, ∇f_{k+1}·y_k / d_k·y_k), // // where y_k = ∇f_{k+1} - ∇f_k. type HestenesStiefel struct { y []float64 } func (hs *HestenesStiefel) Init(loc *Location) { hs.y = resize(hs.y, len(loc.Gradient)) } func (hs *HestenesStiefel) Beta(grad, gradPrev, dirPrev []float64) (beta float64) { floats.SubTo(hs.y, grad, gradPrev) beta = floats.Dot(grad, hs.y) / floats.Dot(dirPrev, hs.y) return math.Max(0, beta) } // DaiYuan implements the Dai-Yuan variant of the CG method that computes the // scaling parameter β_k according to the formula // // β_k = |∇f_{k+1}|^2 / d_k·y_k, // // where y_k = ∇f_{k+1} - ∇f_k. type DaiYuan struct { y []float64 } func (dy *DaiYuan) Init(loc *Location) { dy.y = resize(dy.y, len(loc.Gradient)) } func (dy *DaiYuan) Beta(grad, gradPrev, dirPrev []float64) (beta float64) { floats.SubTo(dy.y, grad, gradPrev) norm := floats.Norm(grad, 2) return norm * norm / floats.Dot(dirPrev, dy.y) } // HagerZhang implements the Hager-Zhang variant of the CG method that computes the // scaling parameter β_k according to the formula // // β_k = (y_k - 2 d_k |y_k|^2/(d_k·y_k))·∇f_{k+1} / (d_k·y_k), // // where y_k = ∇f_{k+1} - ∇f_k. type HagerZhang struct { y []float64 } func (hz *HagerZhang) Init(loc *Location) { hz.y = resize(hz.y, len(loc.Gradient)) } func (hz *HagerZhang) Beta(grad, gradPrev, dirPrev []float64) (beta float64) { floats.SubTo(hz.y, grad, gradPrev) dirDotY := floats.Dot(dirPrev, hz.y) gDotY := floats.Dot(grad, hz.y) gDotDir := floats.Dot(grad, dirPrev) yNorm := floats.Norm(hz.y, 2) return (gDotY - 2*gDotDir*yNorm*yNorm/dirDotY) / dirDotY } golang-gonum-v1-gonum-0.14.0/optimize/cmaes.go000066400000000000000000000341751450372207100211270ustar00rootroot00000000000000// 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 optimize import ( "math" "sort" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distmv" ) var _ Method = (*CmaEsChol)(nil) // TODO(btracey): If we ever implement the traditional CMA-ES algorithm, provide // the base explanation there, and modify this description to just // describe the differences. // CmaEsChol implements the covariance matrix adaptation evolution strategy (CMA-ES) // based on the Cholesky decomposition. The full algorithm is described in // // Krause, Oswin, Dídac Rodríguez Arbonès, and Christian Igel. "CMA-ES with // optimal covariance update and storage complexity." Advances in Neural // Information Processing Systems. 2016. // https://papers.nips.cc/paper/6457-cma-es-with-optimal-covariance-update-and-storage-complexity.pdf // // CMA-ES is a global optimization method that progressively adapts a population // of samples. CMA-ES combines techniques from local optimization with global // optimization. Specifically, the CMA-ES algorithm uses an initial multivariate // normal distribution to generate a population of input locations. The input locations // with the lowest function values are used to update the parameters of the normal // distribution, a new set of input locations are generated, and this procedure // is iterated until convergence. The initial sampling distribution will have // a mean specified by the initial x location, and a covariance specified by // the InitCholesky field. // // As the normal distribution is progressively updated according to the best samples, // it can be that the mean of the distribution is updated in a gradient-descent // like fashion, followed by a shrinking covariance. // It is recommended that the algorithm be run multiple times (with different // InitMean) to have a better chance of finding the global minimum. // // The CMA-ES-Chol algorithm differs from the standard CMA-ES algorithm in that // it directly updates the Cholesky decomposition of the normal distribution. // This changes the runtime from O(dimension^3) to O(dimension^2*population) // The evolution of the multi-variate normal will be similar to the baseline // CMA-ES algorithm, but the covariance update equation is not identical. // // For more information about the CMA-ES algorithm, see // // https://en.wikipedia.org/wiki/CMA-ES // https://arxiv.org/pdf/1604.00772.pdf type CmaEsChol struct { // InitStepSize sets the initial size of the covariance matrix adaptation. // If InitStepSize is 0, a default value of 0.5 is used. InitStepSize cannot // be negative, or CmaEsChol will panic. InitStepSize float64 // Population sets the population size for the algorithm. If Population is // 0, a default value of 4 + math.Floor(3*math.Log(float64(dim))) is used. // Population cannot be negative or CmaEsChol will panic. Population int // InitCholesky specifies the Cholesky decomposition of the covariance // matrix for the initial sampling distribution. If InitCholesky is nil, // a default value of I is used. If it is non-nil, then it must have // InitCholesky.Size() be equal to the problem dimension. InitCholesky *mat.Cholesky // StopLogDet sets the threshold for stopping the optimization if the // distribution becomes too peaked. The log determinant is a measure of the // (log) "volume" of the normal distribution, and when it is too small // the samples are almost the same. If the log determinant of the covariance // matrix becomes less than StopLogDet, the optimization run is concluded. // If StopLogDet is 0, a default value of dim*log(1e-16) is used. // If StopLogDet is NaN, the stopping criterion is not used, though // this can cause numeric instabilities in the algorithm. StopLogDet float64 // ForgetBest, when true, does not track the best overall function value found, // instead returning the new best sample in each iteration. If ForgetBest // is false, then the minimum value returned will be the lowest across all // iterations, regardless of when that sample was generated. ForgetBest bool // Src allows a random number generator to be supplied for generating samples. // If Src is nil the generator in golang.org/x/math/rand is used. Src rand.Source // Fixed algorithm parameters. dim int pop int weights []float64 muEff float64 cc, cs, c1, cmu, ds float64 eChi float64 // Function data. xs *mat.Dense fs []float64 // Adaptive algorithm parameters. invSigma float64 // inverse of the sigma parameter pc, ps []float64 mean []float64 chol mat.Cholesky // Overall best. bestX []float64 bestF float64 // Synchronization. sentIdx int receivedIdx int operation chan<- Task updateErr error } var ( _ Statuser = (*CmaEsChol)(nil) _ Method = (*CmaEsChol)(nil) ) func (cma *CmaEsChol) methodConverged() Status { sd := cma.StopLogDet switch { case math.IsNaN(sd): return NotTerminated case sd == 0: sd = float64(cma.dim) * -36.8413614879 // ln(1e-16) } if cma.chol.LogDet() < sd { return MethodConverge } return NotTerminated } // Status returns the status of the method. func (cma *CmaEsChol) Status() (Status, error) { if cma.updateErr != nil { return Failure, cma.updateErr } return cma.methodConverged(), nil } func (*CmaEsChol) Uses(has Available) (uses Available, err error) { return has.function() } func (cma *CmaEsChol) Init(dim, tasks int) int { if dim <= 0 { panic(nonpositiveDimension) } if tasks < 0 { panic(negativeTasks) } // Set fixed algorithm parameters. // Parameter values are from https://arxiv.org/pdf/1604.00772.pdf . cma.dim = dim cma.pop = cma.Population n := float64(dim) if cma.pop == 0 { cma.pop = 4 + int(3*math.Log(n)) // Note the implicit floor. } else if cma.pop < 0 { panic("cma-es-chol: negative population size") } mu := cma.pop / 2 cma.weights = resize(cma.weights, mu) for i := range cma.weights { v := math.Log(float64(mu)+0.5) - math.Log(float64(i)+1) cma.weights[i] = v } floats.Scale(1/floats.Sum(cma.weights), cma.weights) cma.muEff = 0 for _, v := range cma.weights { cma.muEff += v * v } cma.muEff = 1 / cma.muEff cma.cc = (4 + cma.muEff/n) / (n + 4 + 2*cma.muEff/n) cma.cs = (cma.muEff + 2) / (n + cma.muEff + 5) cma.c1 = 2 / ((n+1.3)*(n+1.3) + cma.muEff) cma.cmu = math.Min(1-cma.c1, 2*(cma.muEff-2+1/cma.muEff)/((n+2)*(n+2)+cma.muEff)) cma.ds = 1 + 2*math.Max(0, math.Sqrt((cma.muEff-1)/(n+1))-1) + cma.cs // E[chi] is taken from https://en.wikipedia.org/wiki/CMA-ES (there // listed as E[||N(0,1)||]). cma.eChi = math.Sqrt(n) * (1 - 1.0/(4*n) + 1/(21*n*n)) // Allocate memory for function data. cma.xs = mat.NewDense(cma.pop, dim, nil) cma.fs = resize(cma.fs, cma.pop) // Allocate and initialize adaptive parameters. cma.invSigma = 1 / cma.InitStepSize if cma.InitStepSize == 0 { cma.invSigma = 10.0 / 3 } else if cma.InitStepSize < 0 { panic("cma-es-chol: negative initial step size") } cma.pc = resize(cma.pc, dim) for i := range cma.pc { cma.pc[i] = 0 } cma.ps = resize(cma.ps, dim) for i := range cma.ps { cma.ps[i] = 0 } cma.mean = resize(cma.mean, dim) // mean location initialized at the start of Run if cma.InitCholesky != nil { if cma.InitCholesky.SymmetricDim() != dim { panic("cma-es-chol: incorrect InitCholesky size") } cma.chol.Clone(cma.InitCholesky) } else { // Set the initial Cholesky to I. b := mat.NewDiagDense(dim, nil) for i := 0; i < dim; i++ { b.SetDiag(i, 1) } var chol mat.Cholesky ok := chol.Factorize(b) if !ok { panic("cma-es-chol: bad cholesky. shouldn't happen") } cma.chol = chol } cma.bestX = resize(cma.bestX, dim) cma.bestF = math.Inf(1) cma.sentIdx = 0 cma.receivedIdx = 0 cma.operation = nil cma.updateErr = nil t := min(tasks, cma.pop) return t } func (cma *CmaEsChol) sendInitTasks(tasks []Task) { for i, task := range tasks { cma.sendTask(i, task) } cma.sentIdx = len(tasks) } // sendTask generates a sample and sends the task. It does not update the cma index. func (cma *CmaEsChol) sendTask(idx int, task Task) { task.ID = idx task.Op = FuncEvaluation distmv.NormalRand(cma.xs.RawRowView(idx), cma.mean, &cma.chol, cma.Src) copy(task.X, cma.xs.RawRowView(idx)) cma.operation <- task } // bestIdx returns the best index in the functions. Returns -1 if all values // are NaN. func (cma *CmaEsChol) bestIdx() int { best := -1 bestVal := math.Inf(1) for i, v := range cma.fs { if math.IsNaN(v) { continue } // Use equality in case somewhere evaluates to +inf. if v <= bestVal { best = i bestVal = v } } return best } // findBestAndUpdateTask finds the best task in the current list, updates the // new best overall, and then stores the best location into task. func (cma *CmaEsChol) findBestAndUpdateTask(task Task) Task { // Find and update the best location. // Don't use floats because there may be NaN values. best := cma.bestIdx() bestF := math.NaN() bestX := cma.xs.RawRowView(0) if best != -1 { bestF = cma.fs[best] bestX = cma.xs.RawRowView(best) } if cma.ForgetBest { task.F = bestF copy(task.X, bestX) } else { if bestF < cma.bestF { cma.bestF = bestF copy(cma.bestX, bestX) } task.F = cma.bestF copy(task.X, cma.bestX) } return task } func (cma *CmaEsChol) Run(operations chan<- Task, results <-chan Task, tasks []Task) { copy(cma.mean, tasks[0].X) cma.operation = operations // Send the initial tasks. We know there are at most as many tasks as elements // of the population. cma.sendInitTasks(tasks) Loop: for { result := <-results switch result.Op { default: panic("unknown operation") case PostIteration: break Loop case MajorIteration: // The last thing we did was update all of the tasks and send the // major iteration. Now we can send a group of tasks again. cma.sendInitTasks(tasks) case FuncEvaluation: cma.receivedIdx++ cma.fs[result.ID] = result.F switch { case cma.sentIdx < cma.pop: // There are still tasks to evaluate. Send the next. cma.sendTask(cma.sentIdx, result) cma.sentIdx++ case cma.receivedIdx < cma.pop: // All the tasks have been sent, but not all of them have been received. // Need to wait until all are back. continue Loop default: // All of the evaluations have been received. if cma.receivedIdx != cma.pop { panic("bad logic") } cma.receivedIdx = 0 cma.sentIdx = 0 task := cma.findBestAndUpdateTask(result) // Update the parameters and send a MajorIteration or a convergence. err := cma.update() // Kill the existing data. for i := range cma.fs { cma.fs[i] = math.NaN() cma.xs.Set(i, 0, math.NaN()) } switch { case err != nil: cma.updateErr = err task.Op = MethodDone case cma.methodConverged() != NotTerminated: task.Op = MethodDone default: task.Op = MajorIteration task.ID = -1 } operations <- task } } } // Been told to stop. Clean up. // Need to see best of our evaluated tasks so far. Should instead just // collect, then see. for task := range results { switch task.Op { case MajorIteration: case FuncEvaluation: cma.fs[task.ID] = task.F default: panic("unknown operation") } } // Send the new best value if the evaluation is better than any we've // found so far. Keep this separate from findBestAndUpdateTask so that // we only send an iteration if we find a better location. if !cma.ForgetBest { best := cma.bestIdx() if best != -1 && cma.fs[best] < cma.bestF { task := tasks[0] task.F = cma.fs[best] copy(task.X, cma.xs.RawRowView(best)) task.Op = MajorIteration task.ID = -1 operations <- task } } close(operations) } // update computes the new parameters (mean, cholesky, etc.). Does not update // any of the synchronization parameters (taskIdx). func (cma *CmaEsChol) update() error { // Sort the function values to find the elite samples. ftmp := make([]float64, cma.pop) copy(ftmp, cma.fs) indexes := make([]int, cma.pop) for i := range indexes { indexes[i] = i } sort.Sort(bestSorter{F: ftmp, Idx: indexes}) meanOld := make([]float64, len(cma.mean)) copy(meanOld, cma.mean) // m_{t+1} = \sum_{i=1}^mu w_i x_i for i := range cma.mean { cma.mean[i] = 0 } for i, w := range cma.weights { idx := indexes[i] // index of teh 1337 sample. floats.AddScaled(cma.mean, w, cma.xs.RawRowView(idx)) } meanDiff := make([]float64, len(cma.mean)) floats.SubTo(meanDiff, cma.mean, meanOld) // p_{c,t+1} = (1-c_c) p_{c,t} + \sqrt(c_c*(2-c_c)*mueff) (m_{t+1}-m_t)/sigma_t floats.Scale(1-cma.cc, cma.pc) scaleC := math.Sqrt(cma.cc*(2-cma.cc)*cma.muEff) * cma.invSigma floats.AddScaled(cma.pc, scaleC, meanDiff) // p_{sigma, t+1} = (1-c_sigma) p_{sigma,t} + \sqrt(c_s*(2-c_s)*mueff) A_t^-1 (m_{t+1}-m_t)/sigma_t floats.Scale(1-cma.cs, cma.ps) // First compute A_t^-1 (m_{t+1}-m_t), then add the scaled vector. tmp := make([]float64, cma.dim) tmpVec := mat.NewVecDense(cma.dim, tmp) diffVec := mat.NewVecDense(cma.dim, meanDiff) err := tmpVec.SolveVec(cma.chol.RawU().T(), diffVec) if err != nil { return err } scaleS := math.Sqrt(cma.cs*(2-cma.cs)*cma.muEff) * cma.invSigma floats.AddScaled(cma.ps, scaleS, tmp) // Compute the update to A. scaleChol := 1 - cma.c1 - cma.cmu if scaleChol == 0 { scaleChol = math.SmallestNonzeroFloat64 // enough to kill the old data, but still non-zero. } cma.chol.Scale(scaleChol, &cma.chol) cma.chol.SymRankOne(&cma.chol, cma.c1, mat.NewVecDense(cma.dim, cma.pc)) for i, w := range cma.weights { idx := indexes[i] floats.SubTo(tmp, cma.xs.RawRowView(idx), meanOld) cma.chol.SymRankOne(&cma.chol, cma.cmu*w*cma.invSigma, tmpVec) } // sigma_{t+1} = sigma_t exp(c_sigma/d_sigma * norm(p_{sigma,t+1}/ E[chi] -1) normPs := floats.Norm(cma.ps, 2) cma.invSigma /= math.Exp(cma.cs / cma.ds * (normPs/cma.eChi - 1)) return nil } type bestSorter struct { F []float64 Idx []int } func (b bestSorter) Len() int { return len(b.F) } func (b bestSorter) Less(i, j int) bool { return b.F[i] < b.F[j] } func (b bestSorter) Swap(i, j int) { b.F[i], b.F[j] = b.F[j], b.F[i] b.Idx[i], b.Idx[j] = b.Idx[j], b.Idx[i] } golang-gonum-v1-gonum-0.14.0/optimize/cmaes_test.go000066400000000000000000000143701450372207100221610ustar00rootroot00000000000000// 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 optimize import ( "errors" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/optimize/functions" ) type functionThresholdConverger struct { Threshold float64 } func (functionThresholdConverger) Init(dim int) {} func (f functionThresholdConverger) Converged(loc *Location) Status { if loc.F < f.Threshold { return FunctionThreshold } return NotTerminated } type cmaTestCase struct { dim int problem Problem method *CmaEsChol initX []float64 settings *Settings good func(result *Result, err error, concurrent int) error } func cmaTestCases() []cmaTestCase { localMinMean := []float64{2.2, -2.2} s := mat.NewSymDense(2, []float64{0.01, 0, 0, 0.01}) var localMinChol mat.Cholesky localMinChol.Factorize(s) return []cmaTestCase{ { // Test that can find a small value. dim: 10, problem: Problem{ Func: functions.ExtendedRosenbrock{}.Func, }, method: &CmaEsChol{ StopLogDet: math.NaN(), }, settings: &Settings{ Converger: functionThresholdConverger{0.01}, }, good: func(result *Result, err error, concurrent int) error { if result.Status != FunctionThreshold { return errors.New("result not function threshold") } if result.F > 0.01 { return errors.New("result not sufficiently small") } return nil }, }, { // Test that can stop when the covariance gets small. // For this case, also test that it is really at a minimum. dim: 2, problem: Problem{ Func: functions.ExtendedRosenbrock{}.Func, }, method: &CmaEsChol{}, settings: &Settings{ Converger: NeverTerminate{}, }, good: func(result *Result, err error, concurrent int) error { if result.Status != MethodConverge { return errors.New("result not method converge") } if result.F > 1e-12 { return errors.New("minimum not found") } return nil }, }, { // Test that population works properly and it stops after a certain // number of iterations. dim: 3, problem: Problem{ Func: functions.ExtendedRosenbrock{}.Func, }, method: &CmaEsChol{ Population: 100, ForgetBest: true, // Otherwise may get an update at the end. }, settings: &Settings{ MajorIterations: 10, Converger: NeverTerminate{}, }, good: func(result *Result, err error, concurrent int) error { if result.Status != IterationLimit { return errors.New("result not iteration limit") } threshLower := 10 threshUpper := 10 if concurrent != 0 { // Could have one more from final update. threshUpper++ } if result.MajorIterations < threshLower || result.MajorIterations > threshUpper { return errors.New("wrong number of iterations") } return nil }, }, { // Test that work stops with some number of function evaluations. dim: 5, problem: Problem{ Func: functions.ExtendedRosenbrock{}.Func, }, method: &CmaEsChol{ Population: 100, }, settings: &Settings{ FuncEvaluations: 250, // Somewhere in the middle of an iteration. Converger: NeverTerminate{}, }, good: func(result *Result, err error, concurrent int) error { if result.Status != FunctionEvaluationLimit { return errors.New("result not function evaluations") } threshLower := 250 threshUpper := 251 if concurrent != 0 { threshUpper = threshLower + concurrent } if result.FuncEvaluations < threshLower { return errors.New("too few function evaluations") } if result.FuncEvaluations > threshUpper { return errors.New("too many function evaluations") } return nil }, }, { // Test that the global minimum is found with the right initialization. dim: 2, problem: Problem{ Func: functions.Rastrigin{}.Func, }, method: &CmaEsChol{ Population: 100, // Increase the population size to reduce noise. }, settings: &Settings{ Converger: NeverTerminate{}, }, good: func(result *Result, err error, concurrent int) error { if result.Status != MethodConverge { return errors.New("result not method converge") } if !floats.EqualApprox(result.X, []float64{0, 0}, 1e-6) { return errors.New("global minimum not found") } return nil }, }, { // Test that a local minimum is found (with a different initialization). dim: 2, problem: Problem{ Func: functions.Rastrigin{}.Func, }, initX: localMinMean, method: &CmaEsChol{ Population: 100, // Increase the population size to reduce noise. InitCholesky: &localMinChol, ForgetBest: true, // So that if it accidentally finds a better place we still converge to the minimum. }, settings: &Settings{ Converger: NeverTerminate{}, }, good: func(result *Result, err error, concurrent int) error { if result.Status != MethodConverge { return errors.New("result not method converge") } if !floats.EqualApprox(result.X, []float64{2, -2}, 3e-2) { return errors.New("local minimum not found") } return nil }, }, } } func TestCmaEsChol(t *testing.T) { t.Parallel() for i, test := range cmaTestCases() { src := rand.New(rand.NewSource(1)) method := test.method method.Src = src initX := test.initX if initX == nil { initX = make([]float64, test.dim) } // Run and check that the expected termination occurs. result, err := Minimize(test.problem, initX, test.settings, method) if testErr := test.good(result, err, test.settings.Concurrent); testErr != nil { t.Errorf("cas %d: %v", i, testErr) } // Run a second time to make sure there are no residual effects result, err = Minimize(test.problem, initX, test.settings, method) if testErr := test.good(result, err, test.settings.Concurrent); testErr != nil { t.Errorf("cas %d second: %v", i, testErr) } // Test the problem in parallel. test.settings.Concurrent = 5 result, err = Minimize(test.problem, initX, test.settings, method) if testErr := test.good(result, err, test.settings.Concurrent); testErr != nil { t.Errorf("cas %d concurrent: %v", i, testErr) } test.settings.Concurrent = 0 } } golang-gonum-v1-gonum-0.14.0/optimize/convex/000077500000000000000000000000001450372207100210005ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/optimize/convex/lp/000077500000000000000000000000001450372207100214135ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/optimize/convex/lp/convert.go000066400000000000000000000065661450372207100234370ustar00rootroot00000000000000// Copyright ©2016 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 lp import ( "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) // TODO(btracey): Have some sort of preprocessing step for helping to fix A to make it // full rank? // TODO(btracey): Reduce rows? Get rid of all zeros, places where only one variable // is there, etc. Could be implemented with a Reduce function. // TODO(btracey): Provide method of artificial variables for help when problem // is infeasible? // TODO(btracey): Add an lp.Solve that solves an LP in non-standard form. // Convert converts a General-form LP into a standard form LP. // The general form of an LP is: // // minimize cᵀ * x // s.t G * x <= h // A * x = b // // And the standard form is: // // minimize cNewᵀ * x // s.t aNew * x = bNew // x >= 0 // // If there are no constraints of the given type, the inputs may be nil. func Convert(c []float64, g mat.Matrix, h []float64, a mat.Matrix, b []float64) (cNew []float64, aNew *mat.Dense, bNew []float64) { nVar := len(c) nIneq := len(h) // Check input sizes. if g == nil { if nIneq != 0 { panic(badShape) } } else { gr, gc := g.Dims() if gr != nIneq { panic(badShape) } if gc != nVar { panic(badShape) } } nEq := len(b) if a == nil { if nEq != 0 { panic(badShape) } } else { ar, ac := a.Dims() if ar != nEq { panic(badShape) } if ac != nVar { panic(badShape) } } // Convert the general form LP. // Derivation: // 0. Start with general form // min. cᵀ * x // s.t. G * x <= h // A * x = b // 1. Introduce slack variables for each constraint // min. cᵀ * x // s.t. G * x + s = h // A * x = b // s >= 0 // 2. Add non-negativity constraints for x by splitting x // into positive and negative components. // x = xp - xn // xp >= 0, xn >= 0 // This makes the LP // min. cᵀ * xp - cᵀ xn // s.t. G * xp - G * xn + s = h // A * xp - A * xn = b // xp >= 0, xn >= 0, s >= 0 // 3. Write the above in standard form: // xt = [xp // xn // s ] // min. [cᵀ, -cᵀ, 0] xt // s.t. [G, -G, I] xt = h // [A, -A, 0] xt = b // x >= 0 // In summary: // Original LP: // min. cᵀ * x // s.t. G * x <= h // A * x = b // Standard Form: // xt = [xp; xn; s] // min. [cᵀ, -cᵀ, 0] xt // s.t. [G, -G, I] xt = h // [A, -A, 0] xt = b // x >= 0 // New size of x is [xp, xn, s] nNewVar := nVar + nVar + nIneq // Construct cNew = [c; -c; 0] cNew = make([]float64, nNewVar) copy(cNew, c) copy(cNew[nVar:], c) floats.Scale(-1, cNew[nVar:2*nVar]) // New number of equality constraints is the number of total constraints. nNewEq := nIneq + nEq // Construct bNew = [h, b]. bNew = make([]float64, nNewEq) copy(bNew, h) copy(bNew[nIneq:], b) // Construct aNew = [G, -G, I; A, -A, 0]. aNew = mat.NewDense(nNewEq, nNewVar, nil) if nIneq != 0 { aNew.Slice(0, nIneq, 0, nVar).(*mat.Dense).Copy(g) aNew.Slice(0, nIneq, nVar, 2*nVar).(*mat.Dense).Scale(-1, g) aView := aNew.Slice(0, nIneq, 2*nVar, 2*nVar+nIneq).(*mat.Dense) for i := 0; i < nIneq; i++ { aView.Set(i, i, 1) } } if nEq != 0 { aNew.Slice(nIneq, nIneq+nEq, 0, nVar).(*mat.Dense).Copy(a) aNew.Slice(nIneq, nIneq+nEq, nVar, 2*nVar).(*mat.Dense).Scale(-1, a) } return cNew, aNew, bNew } golang-gonum-v1-gonum-0.14.0/optimize/convex/lp/doc.go000066400000000000000000000004521450372207100225100ustar00rootroot00000000000000// 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 lp implements routines to solve linear programming problems. package lp // import "gonum.org/v1/gonum/optimize/convex/lp" golang-gonum-v1-gonum-0.14.0/optimize/convex/lp/simplex.go000066400000000000000000000505221450372207100234270ustar00rootroot00000000000000// Copyright ©2016 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 lp implements routines for solving linear programs. package lp import ( "errors" "fmt" "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) // TODO(btracey): Could have a solver structure with an abstract factorizer. With // this transformation the same high-level code could handle both Dense and Sparse. // TODO(btracey): Need to improve error handling. Only want to panic if condition number inf. // TODO(btracey): Performance enhancements. There are currently lots of linear // solves that can be improved by doing rank-one updates. For example, the swap // step is just a rank-one update. // TODO(btracey): Better handling on the linear solve errors. If the condition // number is not inf and the equation solved "well", should keep moving. var ( ErrBland = errors.New("lp: bland: all replacements are negative or cause ill-conditioned ab") ErrInfeasible = errors.New("lp: problem is infeasible") ErrLinSolve = errors.New("lp: linear solve failure") ErrUnbounded = errors.New("lp: problem is unbounded") ErrSingular = errors.New("lp: A is singular") ErrZeroColumn = errors.New("lp: A has a column of all zeros") ErrZeroRow = errors.New("lp: A has a row of all zeros") ) const badShape = "lp: size mismatch" // TODO(btracey): Should these tolerances be part of a settings struct? const ( // initPosTol is the tolerance on the initial condition being feasible. Strictly, // the x should be positive, but instead it must be greater than -initPosTol. initPosTol = 1e-13 // blandNegTol is the tolerance on the value being greater than 0 in the bland test. blandNegTol = 1e-14 // rRoundTol is the tolerance for rounding values to zero when testing if // constraints are met. rRoundTol = 1e-13 // dRoundTol is the tolerance for testing if values are zero for the problem // being unbounded. dRoundTol = 1e-13 // phaseIZeroTol tests if the Phase I problem returned a feasible solution. phaseIZeroTol = 1e-12 // blandZeroTol is the tolerance on testing if the bland solution can move. blandZeroTol = 1e-12 ) // Simplex solves a linear program in standard form using Danzig's Simplex // algorithm. The standard form of a linear program is: // // minimize cᵀ x // s.t. A*x = b // x >= 0 . // // The input tol sets how close to the optimal solution is found (specifically, // when the maximal reduced cost is below tol). An error will be returned if the // problem is infeasible or unbounded. In rare cases, numeric errors can cause // the Simplex to fail. In this case, an error will be returned along with the // most recently found feasible solution. // // The Convert function can be used to transform a general LP into standard form. // // The input matrix A must have at least as many columns as rows, len(c) must // equal the number of columns of A, and len(b) must equal the number of rows of // A or Simplex will panic. A must also have full row rank and may not contain any // columns with all zeros, or Simplex will return an error. // // initialBasic can be used to set the initial set of indices for a feasible // solution to the LP. If an initial feasible solution is not known, initialBasic // may be nil. If initialBasic is non-nil, len(initialBasic) must equal the number // of rows of A and must be an actual feasible solution to the LP, otherwise // Simplex will panic. // // A description of the Simplex algorithm can be found in Ch. 8 of // // Strang, Gilbert. "Linear Algebra and Applications." Academic, New York (1976). // // For a detailed video introduction, see lectures 11-13 of UC Math 352 // // https://www.youtube.com/watch?v=ESzYPFkY3og&index=11&list=PLh464gFUoJWOmBYla3zbZbc4nv2AXez6X. func Simplex(c []float64, A mat.Matrix, b []float64, tol float64, initialBasic []int) (optF float64, optX []float64, err error) { ans, x, _, err := simplex(initialBasic, c, A, b, tol) return ans, x, err } func simplex(initialBasic []int, c []float64, A mat.Matrix, b []float64, tol float64) (float64, []float64, []int, error) { err := verifyInputs(initialBasic, c, A, b) if err != nil { if err == ErrUnbounded { return math.Inf(-1), nil, nil, ErrUnbounded } return math.NaN(), nil, nil, err } m, n := A.Dims() if m == n { // Problem is exactly constrained, perform a linear solve. bVec := mat.NewVecDense(len(b), b) x := make([]float64, n) xVec := mat.NewVecDense(n, x) err := xVec.SolveVec(A, bVec) if err != nil { return math.NaN(), nil, nil, ErrSingular } for _, v := range x { if v < 0 { return math.NaN(), nil, nil, ErrInfeasible } } f := floats.Dot(x, c) return f, x, nil, nil } // There is at least one optimal solution to the LP which is at the intersection // to a set of constraint boundaries. For a standard form LP with m variables // and n equality constraints, at least m-n elements of x must equal zero // at optimality. The Simplex algorithm solves the standard-form LP by starting // at an initial constraint vertex and successively moving to adjacent constraint // vertices. At every vertex, the set of non-zero x values is the "basic // feasible solution". The list of non-zero x's are maintained in basicIdxs, // the respective columns of A are in ab, and the actual non-zero values of // x are in xb. // // The LP is equality constrained such that A * x = b. This can be expanded // to // ab * xb + an * xn = b // where ab are the columns of a in the basic set, and an are all of the // other columns. Since each element of xn is zero by definition, this means // that for all feasible solutions xb = ab^-1 * b. // // Before the simplex algorithm can start, an initial feasible solution must // be found. If initialBasic is non-nil a feasible solution has been supplied. // Otherwise the "Phase I" problem must be solved to find an initial feasible // solution. var basicIdxs []int // The indices of the non-zero x values. var ab *mat.Dense // The subset of columns of A listed in basicIdxs. var xb []float64 // The non-zero elements of x. xb = ab^-1 b if initialBasic != nil { // InitialBasic supplied. Panic if incorrect length or infeasible. if len(initialBasic) != m { panic("lp: incorrect number of initial vectors") } ab = mat.NewDense(m, len(initialBasic), nil) extractColumns(ab, A, initialBasic) xb = make([]float64, m) err = initializeFromBasic(xb, ab, b) if err != nil { panic(err) } basicIdxs = make([]int, len(initialBasic)) copy(basicIdxs, initialBasic) } else { // No initial basis supplied. Solve the PhaseI problem. basicIdxs, ab, xb, err = findInitialBasic(A, b) if err != nil { return math.NaN(), nil, nil, err } } // basicIdxs contains the indexes for an initial feasible solution, // ab contains the extracted columns of A, and xb contains the feasible // solution. All x not in the basic set are 0 by construction. // nonBasicIdx is the set of nonbasic variables. nonBasicIdx := make([]int, 0, n-m) inBasic := make(map[int]struct{}) for _, v := range basicIdxs { inBasic[v] = struct{}{} } for i := 0; i < n; i++ { _, ok := inBasic[i] if !ok { nonBasicIdx = append(nonBasicIdx, i) } } // cb is the subset of c for the basic variables. an and cn // are the equivalents to ab and cb but for the nonbasic variables. cb := make([]float64, len(basicIdxs)) for i, idx := range basicIdxs { cb[i] = c[idx] } cn := make([]float64, len(nonBasicIdx)) for i, idx := range nonBasicIdx { cn[i] = c[idx] } an := mat.NewDense(m, len(nonBasicIdx), nil) extractColumns(an, A, nonBasicIdx) bVec := mat.NewVecDense(len(b), b) cbVec := mat.NewVecDense(len(cb), cb) // Temporary data needed each iteration. (Described later) r := make([]float64, n-m) move := make([]float64, m) // Solve the linear program starting from the initial feasible set. This is // the "Phase 2" problem. // // Algorithm: // 1) Compute the "reduced costs" for the non-basic variables. The reduced // costs are the lagrange multipliers of the constraints. // r = cn - anᵀ * ab¯ᵀ * cb // 2) If all of the reduced costs are positive, no improvement is possible, // and the solution is optimal (xn can only increase because of // non-negativity constraints). Otherwise, the solution can be improved and // one element will be exchanged in the basic set. // 3) Choose the x_n with the most negative value of r. Call this value xe. // This variable will be swapped into the basic set. // 4) Increase xe until the next constraint boundary is met. This will happen // when the first element in xb becomes 0. The distance xe can increase before // a given element in xb becomes negative can be found from // xb = Ab^-1 b - Ab^-1 An xn // = Ab^-1 b - Ab^-1 Ae xe // = bhat + d x_e // xe = bhat_i / - d_i // where Ae is the column of A corresponding to xe. // The constraining basic index is the first index for which this is true, // so remove the element which is min_i (bhat_i / -d_i), assuming d_i is negative. // If no d_i is less than 0, then the problem is unbounded. // 5) If the new xe is 0 (that is, bhat_i == 0), then this location is at // the intersection of several constraints. Use the Bland rule instead // of the rule in step 4 to avoid cycling. for { // Compute reduced costs -- r = cn - anᵀ ab¯ᵀ cb var tmp mat.VecDense err = tmp.SolveVec(ab.T(), cbVec) if err != nil { break } data := make([]float64, n-m) tmp2 := mat.NewVecDense(n-m, data) tmp2.MulVec(an.T(), &tmp) floats.SubTo(r, cn, data) // Replace the most negative element in the simplex. If there are no // negative entries then the optimal solution has been found. minIdx := floats.MinIdx(r) if r[minIdx] >= -tol { break } for i, v := range r { if math.Abs(v) < rRoundTol { r[i] = 0 } } // Compute the moving distance. err = computeMove(move, minIdx, A, ab, xb, nonBasicIdx) if err != nil { if err == ErrUnbounded { return math.Inf(-1), nil, nil, ErrUnbounded } break } // Replace the basic index along the tightest constraint. replace := floats.MinIdx(move) if move[replace] <= 0 { replace, minIdx, err = replaceBland(A, ab, xb, basicIdxs, nonBasicIdx, r, move) if err != nil { if err == ErrUnbounded { return math.Inf(-1), nil, nil, ErrUnbounded } break } } // Replace the constrained basicIdx with the newIdx. basicIdxs[replace], nonBasicIdx[minIdx] = nonBasicIdx[minIdx], basicIdxs[replace] cb[replace], cn[minIdx] = cn[minIdx], cb[replace] tmpCol1 := mat.Col(nil, replace, ab) tmpCol2 := mat.Col(nil, minIdx, an) ab.SetCol(replace, tmpCol2) an.SetCol(minIdx, tmpCol1) // Compute the new xb. xbVec := mat.NewVecDense(len(xb), xb) err = xbVec.SolveVec(ab, bVec) if err != nil { break } } // Found the optimum successfully or died trying. The basic variables get // their values, and the non-basic variables are all zero. opt := floats.Dot(cb, xb) xopt := make([]float64, n) for i, v := range basicIdxs { xopt[v] = xb[i] } return opt, xopt, basicIdxs, err } // computeMove computes how far can be moved replacing each index. The results // are stored into move. func computeMove(move []float64, minIdx int, A mat.Matrix, ab *mat.Dense, xb []float64, nonBasicIdx []int) error { // Find ae. col := mat.Col(nil, nonBasicIdx[minIdx], A) aCol := mat.NewVecDense(len(col), col) // d = - Ab^-1 Ae nb, _ := ab.Dims() d := make([]float64, nb) dVec := mat.NewVecDense(nb, d) err := dVec.SolveVec(ab, aCol) if err != nil { return ErrLinSolve } floats.Scale(-1, d) for i, v := range d { if math.Abs(v) < dRoundTol { d[i] = 0 } } // If no di < 0, then problem is unbounded. if floats.Min(d) >= 0 { return ErrUnbounded } // move = bhat_i / - d_i, assuming d is negative. bHat := xb // ab^-1 b for i, v := range d { if v >= 0 { move[i] = math.Inf(1) } else { move[i] = bHat[i] / math.Abs(v) } } return nil } // replaceBland uses the Bland rule to find the indices to swap if the minimum // move is 0. The indices to be swapped are replace and minIdx (following the // nomenclature in the main routine). func replaceBland(A mat.Matrix, ab *mat.Dense, xb []float64, basicIdxs, nonBasicIdx []int, r, move []float64) (replace, minIdx int, err error) { m, _ := A.Dims() // Use the traditional bland rule, except don't replace a constraint which // causes the new ab to be singular. for i, v := range r { if v > -blandNegTol { continue } minIdx = i err = computeMove(move, minIdx, A, ab, xb, nonBasicIdx) if err != nil { // Either unbounded or something went wrong. return -1, -1, err } replace = floats.MinIdx(move) if math.Abs(move[replace]) > blandZeroTol { // Large enough that it shouldn't be a problem return replace, minIdx, nil } // Find a zero index where replacement is non-singular. biCopy := make([]int, len(basicIdxs)) for replace, v := range move { if v > blandZeroTol { continue } copy(biCopy, basicIdxs) biCopy[replace] = nonBasicIdx[minIdx] abTmp := mat.NewDense(m, len(biCopy), nil) extractColumns(abTmp, A, biCopy) // If the condition number is reasonable, use this index. if mat.Cond(abTmp, 1) < 1e16 { return replace, minIdx, nil } } } return -1, -1, ErrBland } func verifyInputs(initialBasic []int, c []float64, A mat.Matrix, b []float64) error { m, n := A.Dims() if m > n { panic("lp: more equality constraints than variables") } if len(c) != n { panic("lp: c vector incorrect length") } if len(b) != m { panic("lp: b vector incorrect length") } if len(c) != n { panic("lp: c vector incorrect length") } if len(initialBasic) != 0 && len(initialBasic) != m { panic("lp: initialBasic incorrect length") } // Do some sanity checks so that ab does not become singular during the // simplex solution. If the ZeroRow checks are removed then the code for // finding a set of linearly independent columns must be improved. // Check that if a row of A only has zero elements that corresponding // element in b is zero, otherwise the problem is infeasible. // Otherwise return ErrZeroRow. for i := 0; i < m; i++ { isZero := true for j := 0; j < n; j++ { if A.At(i, j) != 0 { isZero = false break } } if isZero && b[i] != 0 { // Infeasible return ErrInfeasible } else if isZero { return ErrZeroRow } } // Check that if a column only has zero elements that the respective C vector // is positive (otherwise unbounded). Otherwise return ErrZeroColumn. for j := 0; j < n; j++ { isZero := true for i := 0; i < m; i++ { if A.At(i, j) != 0 { isZero = false break } } if isZero && c[j] < 0 { return ErrUnbounded } else if isZero { return ErrZeroColumn } } return nil } // initializeFromBasic initializes the basic feasible solution given a set of // basic indices. It extracts the columns of A specified by basicIdxs and finds // the x values at that location. These are stored into xb. // // If the columns of A are not linearly independent or if the initial set is not // feasible, an error is returned. func initializeFromBasic(xb []float64, ab *mat.Dense, b []float64) error { m, _ := ab.Dims() if len(xb) != m { panic("simplex: bad xb length") } xbMat := mat.NewVecDense(m, xb) err := xbMat.SolveVec(ab, mat.NewVecDense(m, b)) if err != nil { return errors.New("lp: subcolumns of A for supplied initial basic singular") } // The solve ensures that the equality constraints are met (ab * xb = b). // Thus, the solution is feasible if and only if all of the x's are positive. allPos := true for _, v := range xb { if v < -initPosTol { allPos = false break } } if !allPos { return errors.New("lp: supplied subcolumns not a feasible solution") } return nil } // extractColumns copies the columns specified by cols into the columns of dst. func extractColumns(dst *mat.Dense, A mat.Matrix, cols []int) { r, c := dst.Dims() ra, _ := A.Dims() if ra != r { panic("simplex: row mismatch") } if c != len(cols) { panic("simplex: column mismatch") } col := make([]float64, r) for j, idx := range cols { mat.Col(col, idx, A) dst.SetCol(j, col) } } // findInitialBasic finds an initial basic solution, and returns the basic // indices, ab, and xb. func findInitialBasic(A mat.Matrix, b []float64) ([]int, *mat.Dense, []float64, error) { m, n := A.Dims() basicIdxs := findLinearlyIndependent(A) if len(basicIdxs) != m { return nil, nil, nil, ErrSingular } // It may be that this linearly independent basis is also a feasible set. If // so, the Phase I problem can be avoided. ab := mat.NewDense(m, len(basicIdxs), nil) extractColumns(ab, A, basicIdxs) xb := make([]float64, m) err := initializeFromBasic(xb, ab, b) if err == nil { return basicIdxs, ab, xb, nil } // This set was not feasible. Instead the "Phase I" problem must be solved // to find an initial feasible set of basis. // // Method: Construct an LP whose optimal solution is a feasible solution // to the original LP. // 1) Introduce an artificial variable x_{n+1}. // 2) Let x_j be the most negative element of x_b (largest constraint violation). // 3) Add the artificial variable to A with: // a_{n+1} = b - \sum_{i in basicIdxs} a_i + a_j // swap j with n+1 in the basicIdxs. // 4) Define a new LP: // minimize x_{n+1} // subject to [A A_{n+1}][x_1 ... x_{n+1}] = b // x, x_{n+1} >= 0 // 5) Solve this LP. If x_{n+1} != 0, then the problem is infeasible, otherwise // the found basis can be used as an initial basis for phase II. // // The extra column in Step 3 is defined such that the vector of 1s is an // initial feasible solution. // Find the largest constraint violator. // Compute a_{n+1} = b - \sum{i in basicIdxs}a_i + a_j. j is in basicIDx, so // instead just subtract the basicIdx columns that are not minIDx. minIdx := floats.MinIdx(xb) aX1 := make([]float64, m) copy(aX1, b) col := make([]float64, m) for i, v := range basicIdxs { if i == minIdx { continue } mat.Col(col, v, A) floats.Sub(aX1, col) } // Construct the new LP. // aNew = [A, a_{n+1}] // bNew = b // cNew = 1 for x_{n+1} aNew := mat.NewDense(m, n+1, nil) aNew.Copy(A) aNew.SetCol(n, aX1) basicIdxs[minIdx] = n // swap minIdx with n in the basic set. c := make([]float64, n+1) c[n] = 1 // Solve the Phase I linear program. _, xOpt, newBasic, err := simplex(basicIdxs, c, aNew, b, 1e-10) if err != nil { return nil, nil, nil, fmt.Errorf("lp: error finding feasible basis: %s", err) } // The original LP is infeasible if the added variable has non-zero value // in the optimal solution to the Phase I problem. if math.Abs(xOpt[n]) > phaseIZeroTol { return nil, nil, nil, ErrInfeasible } // The basis found in Phase I is a feasible solution to the original LP if // the added variable is not in the basis. addedIdx := -1 for i, v := range newBasic { if v == n { addedIdx = i } xb[i] = xOpt[v] } if addedIdx == -1 { extractColumns(ab, A, newBasic) return newBasic, ab, xb, nil } // The value of the added variable is in the basis, but it has a zero value. // See if exchanging another variable into the basic set finds a feasible // solution. basicMap := make(map[int]struct{}) for _, v := range newBasic { basicMap[v] = struct{}{} } var set bool for i := range xOpt { if _, inBasic := basicMap[i]; inBasic { continue } newBasic[addedIdx] = i if set { mat.Col(col, i, A) ab.SetCol(addedIdx, col) } else { extractColumns(ab, A, newBasic) set = true } err := initializeFromBasic(xb, ab, b) if err == nil { return newBasic, ab, xb, nil } } return nil, nil, nil, ErrInfeasible } // findLinearlyIndependent finds a set of linearly independent columns of A, and // returns the column indexes of the linearly independent columns. func findLinearlyIndependent(A mat.Matrix) []int { m, n := A.Dims() idxs := make([]int, 0, m) columns := mat.NewDense(m, m, nil) newCol := make([]float64, m) // Walk in reverse order because slack variables are typically the last columns // of A. for i := n - 1; i >= 0; i-- { if len(idxs) == m { break } mat.Col(newCol, i, A) columns.SetCol(len(idxs), newCol) if len(idxs) == 0 { // A column is linearly independent from the null set. // If all-zero column of A are allowed, this code needs to be adjusted. idxs = append(idxs, i) continue } if mat.Cond(columns.Slice(0, m, 0, len(idxs)+1), 1) > 1e12 { // Not linearly independent. continue } idxs = append(idxs, i) } return idxs } golang-gonum-v1-gonum-0.14.0/optimize/convex/lp/simplex_test.go000066400000000000000000000665051450372207100244760ustar00rootroot00000000000000// Copyright ©2016 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 lp import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) const convergenceTol = 1e-10 func TestSimplex(t *testing.T) { t.Parallel() // First test specific inputs. These were collected from failures // during randomized testing. // TODO(btracey): Test specific problems with known solutions. for _, test := range []struct { A mat.Matrix b []float64 c []float64 tol float64 initialBasic []int }{ { // Basic feasible LP A: mat.NewDense(2, 4, []float64{ -1, 2, 1, 0, 3, 1, 0, 1, }), b: []float64{4, 9}, c: []float64{-1, -2, 0, 0}, //initialBasic: nil, tol: 0, }, { // Zero row that caused linear solver failure A: mat.NewDense(3, 5, []float64{0.09917822373225804, 0, 0, -0.2588175087223661, -0.5935518220870567, 1.301111422556007, 0.12220247487326946, 0, 0, -1.9194869979254463, 0, 0, 0, 0, -0.8588221231396473}), b: []float64{0, 0, 0}, c: []float64{0, 0.598992624019304, 0, 0, 0}, }, { // Case that caused linear solver failure A: mat.NewDense(13, 26, []float64{-0.7001209024399848, -0.7027502615621812, -0, 0.7354444798695736, -0, 0.476457578966189, 0.7001209024399848, 0.7027502615621812, 0, -0.7354444798695736, 0, -0.476457578966189, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.8446087238391438, -0, -0, 0.7705609478497938, -0, -0, -2.7311218710244463, 0, 0, -0.7705609478497938, 0, 0, 2.7311218710244463, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -0, 0.8332519091897401, 0.7762132098737671, -0, -0, -0.052470638647269585, 0, -0.8332519091897401, -0.7762132098737671, 0, 0, 0.052470638647269585, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.9898577208292023, 0.31653724289408824, -0, -0, 0.17797227766447388, 1.2702427184954932, -0.7998764021535656, -0.31653724289408824, 0, 0, -0.17797227766447388, -1.2702427184954932, 0.7998764021535656, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -0, -0, -0, -0, 0.4206278126213235, -0.7253374879437113, 0, 0, 0, 0, -0.4206278126213235, 0.7253374879437113, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, -0, -0.7567988418466963, 0.3304567624749696, 0.8385927625193501, -0.0021606686026376387, -0, 0, 0.7567988418466963, -0.3304567624749696, -0.8385927625193501, 0.0021606686026376387, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -2.230107839590404, -0.9897104202085316, -0, 0.24703471683023603, -0, -2.382860345431941, 0.6206871648345162, 0.9897104202085316, 0, -0.24703471683023603, 0, 2.382860345431941, -0.6206871648345162, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 1.4350469221322282, -0.9730343818431852, -0, 2.326429855201535, -0, -0.14347849887004038, -1.4350469221322282, 0.9730343818431852, 0, -2.326429855201535, 0, 0.14347849887004038, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -0.7943912888763849, -0.13735037357335078, -0.5101161104860161, -0, -0, -1.4790634590370297, 0.050911195996747316, 0.13735037357335078, 0.5101161104860161, 0, 0, 1.4790634590370297, -0.050911195996747316, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, -0, -0.2515400440591492, 0.2058339272568599, -0, -0, -1.314023802253438, 0, 0.2515400440591492, -0.2058339272568599, 0, 0, 1.314023802253438, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0.08279503413614919, -0.16669071891829756, -0, -0.6208413721884664, -0, -0.6348258970402827, -0.08279503413614919, 0.16669071891829756, 0, 0.6208413721884664, 0, 0.6348258970402827, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, -0, -0, 0.49634739711260845, -0, -0, -0, 0, 0, -0.49634739711260845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, -0.2797437186631715, -0.8356683570259136, 1.8970426594969672, -0.4095711945594497, 0.45831284820623924, -0.6109615338552246, 0.2797437186631715, 0.8356683570259136, -1.8970426594969672, 0.4095711945594497, -0.45831284820623924, 0.6109615338552246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1}), b: []float64{-0.8446087238391436, 0, 1.9898577208292023, 0, 0, -2.230107839590404, 0, 0.20560871112361512, 0, 0, 0, 0, 0}, c: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, }, { // Phase 1 of the above that panicked A: mat.NewDense(26, 52, []float64{0.7001209024399848, -0, -0, -0.31653724289408824, -0, -0, 0.9897104202085316, -1.4350469221322282, 0.13735037357335078, -0, -0.08279503413614919, -0, 0.2797437186631715, -0.7001209024399848, 0, 0, 0.31653724289408824, 0, 0, -0.9897104202085316, 1.4350469221322282, -0.13735037357335078, 0, 0.08279503413614919, 0, -0.2797437186631715, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.7027502615621812, -0, -0.8332519091897401, -0, -0, 0.7567988418466963, -0, 0.9730343818431852, 0.5101161104860161, 0.2515400440591492, 0.16669071891829756, -0, 0.8356683570259136, -0.7027502615621812, 0, 0.8332519091897401, 0, 0, -0.7567988418466963, 0, -0.9730343818431852, -0.5101161104860161, -0.2515400440591492, -0.16669071891829756, 0, -0.8356683570259136, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0.7705609478497938, -0.7762132098737671, -0, -0, -0.3304567624749696, -0.24703471683023603, -0, -0, -0.2058339272568599, -0, -0.49634739711260845, -1.8970426594969672, 0, 0.7705609478497938, 0.7762132098737671, 0, 0, 0.3304567624749696, 0.24703471683023603, 0, 0, 0.2058339272568599, 0, 0.49634739711260845, 1.8970426594969672, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.7354444798695736, -0, -0, -0.17797227766447388, -0, -0.8385927625193501, -0, -2.326429855201535, -0, -0, 0.6208413721884664, -0, 0.4095711945594497, 0.7354444798695736, 0, 0, 0.17797227766447388, 0, 0.8385927625193501, 0, 2.326429855201535, 0, 0, -0.6208413721884664, 0, -0.4095711945594497, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0, -0, -1.2702427184954932, -0.4206278126213235, 0.0021606686026376387, 2.382860345431941, -0, 1.4790634590370297, -0, -0, -0, -0.45831284820623924, 0, 0, 0, 1.2702427184954932, 0.4206278126213235, -0.0021606686026376387, -2.382860345431941, 0, -1.4790634590370297, 0, 0, 0, 0.45831284820623924, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.476457578966189, 2.7311218710244463, 0.052470638647269585, 0.7998764021535656, 0.7253374879437113, -0, -0.6206871648345162, 0.14347849887004038, -0.050911195996747316, 1.314023802253438, 0.6348258970402827, -0, 0.6109615338552246, 0.476457578966189, -2.7311218710244463, -0.052470638647269585, -0.7998764021535656, -0.7253374879437113, 0, 0.6206871648345162, -0.14347849887004038, 0.050911195996747316, -1.314023802253438, -0.6348258970402827, 0, -0.6109615338552246, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.7001209024399848, -0, -0, 0.31653724289408824, -0, -0, -0.9897104202085316, 1.4350469221322282, -0.13735037357335078, -0, 0.08279503413614919, -0, -0.2797437186631715, 0.7001209024399848, 0, 0, -0.31653724289408824, 0, 0, 0.9897104202085316, -1.4350469221322282, 0.13735037357335078, 0, -0.08279503413614919, 0, 0.2797437186631715, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.7027502615621812, -0, 0.8332519091897401, -0, -0, -0.7567988418466963, -0, -0.9730343818431852, -0.5101161104860161, -0.2515400440591492, -0.16669071891829756, -0, -0.8356683570259136, 0.7027502615621812, 0, -0.8332519091897401, 0, 0, 0.7567988418466963, 0, 0.9730343818431852, 0.5101161104860161, 0.2515400440591492, 0.16669071891829756, 0, 0.8356683570259136, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, 0.7705609478497938, 0.7762132098737671, -0, -0, 0.3304567624749696, 0.24703471683023603, -0, -0, 0.2058339272568599, -0, 0.49634739711260845, 1.8970426594969672, 0, -0.7705609478497938, -0.7762132098737671, 0, 0, -0.3304567624749696, -0.24703471683023603, 0, 0, -0.2058339272568599, 0, -0.49634739711260845, -1.8970426594969672, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.7354444798695736, -0, -0, 0.17797227766447388, -0, 0.8385927625193501, -0, 2.326429855201535, -0, -0, -0.6208413721884664, -0, -0.4095711945594497, -0.7354444798695736, 0, 0, -0.17797227766447388, 0, -0.8385927625193501, 0, -2.326429855201535, 0, 0, 0.6208413721884664, 0, 0.4095711945594497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0, -0, 1.2702427184954932, 0.4206278126213235, -0.0021606686026376387, -2.382860345431941, -0, -1.4790634590370297, -0, -0, -0, 0.45831284820623924, 0, 0, 0, -1.2702427184954932, -0.4206278126213235, 0.0021606686026376387, 2.382860345431941, 0, 1.4790634590370297, 0, 0, 0, -0.45831284820623924, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.476457578966189, -2.7311218710244463, -0.052470638647269585, -0.7998764021535656, -0.7253374879437113, -0, 0.6206871648345162, -0.14347849887004038, 0.050911195996747316, -1.314023802253438, -0.6348258970402827, -0, -0.6109615338552246, -0.476457578966189, 2.7311218710244463, 0.052470638647269585, 0.7998764021535656, 0.7253374879437113, 0, -0.6206871648345162, 0.14347849887004038, -0.050911195996747316, 1.314023802253438, 0.6348258970402827, 0, 0.6109615338552246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0, -0, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0, -0, -0, -1, -0, -0, -0, -0, -0, -0, -0, -0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0, -0, -0, -0, -1, -0, -0, -0, -0, -0, -0, -0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0, -0, -0, -0, -0, -1, -0, -0, -0, -0, -0, -0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -0, -0, -0, -0, -0, -0, -0, -1, -0, -0, -0, -0, -0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -0, -0, -0, -0, -0, -0, -0, -0, -1, -0, -0, -0, -0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -1, -0, -0, -0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -1, -0, -0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -1, -0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1.8446087238391438, 1, -0.9898577208292023, 1, 1, 2.230107839590404, 1, 0.7943912888763849, 1, 1, 1, 1, 1, -1.8446087238391438, -1, 0.9898577208292023, -1, -1, -2.230107839590404, -1, -0.7943912888763849, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), b: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, c: []float64{-0.8446087238391436, 0, 1.9898577208292023, 0, 0, -2.230107839590404, 0, 0.20560871112361512, 0, 0, 0, 0, 0, 0.8446087238391436, -0, -1.9898577208292023, -0, -0, 2.230107839590404, -0, -0.20560871112361512, -0, -0, -0, -0, -0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { // Dense case that panicked. A: mat.NewDense(6, 15, []float64{0.3279477313560112, 0.04126296122557327, 0.24121743535067522, -0.8676933623438741, -0.3279477313560112, -0.04126296122557327, -0.24121743535067522, 0.8676933623438741, 1, 0, 0, 0, 0, 0, 1.3702148909442915, 0.43713186538468607, 0.8613818492485417, -0.9298615442657688, -0.037784779008231184, -0.43713186538468607, -0.8613818492485417, 0.9298615442657688, 0.037784779008231184, 0, 1, 0, 0, 0, 0, 0.3478112701177931, -0, 0.748352668598051, -0.4294796840343912, -0, 0, -0.748352668598051, 0.4294796840343912, 0, 0, 0, 1, 0, 0, 0, -1, -0, 1.1913912184457485, 1.732132186658447, 0.4026384828544584, 0, -1.1913912184457485, -1.732132186658447, -0.4026384828544584, 0, 0, 0, 1, 0, 0, -0.4598555419763902, -0, 1.2088959976921831, -0.7297794575275871, 1.9835614149566971, 0, -1.2088959976921831, 0.7297794575275871, -1.9835614149566971, 0, 0, 0, 0, 1, 0, 0.5986809560819324, 0.19738159369304414, -1.0647198575836367, -0, -0.7264943883762761, -0.19738159369304414, 1.0647198575836367, 0, 0.7264943883762761, 0, 0, 0, 0, 0, 1, 0.36269644970561576}), b: []float64{2.3702148909442915, 1.3478112701177931, 0, -0.4598555419763902, 1.5986809560819324, 1.3626964497056158}, c: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, }, { A: mat.NewDense(6, 11, []float64{-0.036551083288733854, -0.8967234664797694, 0.036551083288733854, 0.8967234664797694, 1, 0, 0, 0, 0, 0, -0.719908817815329, -1.9043311904524263, -0, 1.9043311904524263, 0, 0, 1, 0, 0, 0, 0, -1.142213296802784, -0, 0.17584914855696687, 0, -0.17584914855696687, 0, 0, 1, 0, 0, 0, -0.5423586338987796, -0.21663357118058713, -0.4815354890024489, 0.21663357118058713, 0.4815354890024489, 0, 0, 0, 1, 0, 0, -0.6864090947259134, -0, -0, 0, 0, 0, 0, 0, 0, 1, 0, 0.4091621839837596, -1.1853040616164046, -0.11374085137543871, 1.1853040616164046, 0.11374085137543871, 0, 0, 0, 0, 0, 1, -1.7416078575675549}), b: []float64{0.28009118218467105, -0.14221329680278405, 0.4576413661012204, 0.3135909052740866, 1.4091621839837596, -1.7416078575675549}, c: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, initialBasic: []int{10, 8, 7, 6, 5, 4}, }, { A: mat.NewDense(6, 10, []float64{-0.036551083288733854, -0.8967234664797694, 0.036551083288733854, 0.8967234664797694, 1, 0, 0, 0, 0, 0, -1.9043311904524263, -0, 1.9043311904524263, 0, 0, 1, 0, 0, 0, 0, -0, 0.17584914855696687, 0, -0.17584914855696687, 0, 0, 1, 0, 0, 0, -0.21663357118058713, -0.4815354890024489, 0.21663357118058713, 0.4815354890024489, 0, 0, 0, 1, 0, 0, -0, -0, 0, 0, 0, 0, 0, 0, 1, 0, -1.1853040616164046, -0.11374085137543871, 1.1853040616164046, 0.11374085137543871, 0, 0, 0, 0, 0, 1}), b: []float64{0.28009118218467105, -0.14221329680278405, 0.4576413661012204, 0.3135909052740866, 1.4091621839837596, -1.7416078575675549}, c: []float64{-1.1951160054922971, -1.354633418345746, 1.1951160054922971, 1.354633418345746, 0, 0, 0, 0, 0, 0}, initialBasic: []int{0, 8, 7, 6, 5, 4}, }, { A: mat.NewDense(6, 14, []float64{-0.4398035705048233, -0, -1.1190414559968929, -0, 0.4398035705048233, 0, 1.1190414559968929, 0, 1, 0, 0, 0, 0, 0, -0, 0.45892918156139395, -0, -0, 0, -0.45892918156139395, 0, 0, 0, 1, 0, 0, 0, 0, -0, -0, -0.3163051515958635, -0, 0, 0, 0.3163051515958635, 0, 0, 0, 1, 0, 0, 0, -0, -0, -1.8226051692445888, -0.8154477101733032, 0, 0, 1.8226051692445888, 0.8154477101733032, 0, 0, 0, 1, 0, 0, -0, 1.0020104354806922, -2.80863692523519, -0.8493721031516384, 0, -1.0020104354806922, 2.80863692523519, 0.8493721031516384, 0, 0, 0, 0, 1, 0, -0.8292937871394104, -1.4615144665021647, -0, -0, 0.8292937871394104, 1.4615144665021647, 0, 0, 0, 0, 0, 0, 0, 1}), b: []float64{0, -1.0154749704172474, 0, 0, 0, -1.5002324315812783}, c: []float64{1.0665389045026794, 0.097366273706136, 0, 2.7928153636989954, -1.0665389045026794, -0.097366273706136, -0, -2.7928153636989954, 0, 0, 0, 0, 0, 0}, initialBasic: []int{5, 12, 11, 10, 0, 8}, }, { // Bad Phase I setup. A: mat.NewDense(6, 7, []float64{1.4009742075419371, 0, 0.05737255493210325, -2.5954004393412915, 0, 1.561789236911904, 0, 0.17152506517602673, 0, 0, 0, 0, 0, -0.3458126550149948, 1.900744052464951, -0.32773164134097343, -0.9648201331251137, 0, 0, 0, 0, -1.3229549190526497, 0.0692227703722903, 0, 0, -0.1024297720479933, 0.4550740188869777, 0, 0.013599438965679167, 0, 0, 0, 0, 0, -0.1164365105021209, 0, 0, 0.4077091957443405, 1.5682816151954875, 0.8411734682369051, 0.22379142247562167, 1.2206581060250778}), b: []float64{0.3293809220378252, 0, -0.5688424847664554, 0, 0, 1.4832526082339592}, c: []float64{0.5246370956983506, -0.36608819899109946, 1.5854141981237713, 0.5170486527020665, 0, 1.4006819866163691, 0.7733814538809437}, }, { // The problem is feasible, but the PhaseI problem keeps the last // variable in the basis. A: mat.NewDense(2, 3, []float64{0.7171320440380402, 0, 0.22818288617480836, 0, -0.10030202006494793, -0.3282372661549324}), b: []float64{0.8913013436978257, 0}, c: []float64{0, 0, 1.16796158316812}, initialBasic: nil, }, { // Case where primal was returned as feasible, but the dual was returned // as infeasible. This is the dual. // Here, the phase I problem returns the value in the basis but equal // to epsilon and not 0. A: mat.NewDense(5, 11, []float64{0.48619717875196006, 0.5089083769874058, 1.4064796473022745, -0.48619717875196006, -0.5089083769874058, -1.4064796473022745, 1, 0, 0, 0, 0, 1.5169837857318682, -0, -0, -1.5169837857318682, 0, 0, 0, 1, 0, 0, 0, -1.3096160896447528, 0.12600426735917414, 0.296082394213142, 1.3096160896447528, -0.12600426735917414, -0.296082394213142, 0, 0, 1, 0, 0, -0, -0, 1.9870800277141467, 0, 0, -1.9870800277141467, 0, 0, 0, 1, 0, -0.3822356988571877, -0, -0.1793908926957139, 0.3822356988571877, 0, 0.1793908926957139, 0, 0, 0, 0, 1}), b: []float64{0.6015865977347667, 0, -1.5648780993757594, 0, 0}, c: []float64{-0.642801659201449, -0.5412741400343285, -1.4634460998530177, 0.642801659201449, 0.5412741400343285, 1.4634460998530177, 0, 0, 0, 0, 0}, }, { // Caused linear solve error. The error is because replacing the minimum // index in Bland causes the new basis to be singular. This // necessitates the ending loop in bland over possible moves. A: mat.NewDense(9, 23, []float64{-0.898219823758102, -0, -0, -0, 1.067555075209233, 1.581598470243863, -1.0656096883610071, 0.898219823758102, 0, 0, 0, -1.067555075209233, -1.581598470243863, 1.0656096883610071, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1.5657353278668433, 0.5798888118401012, -0, 0.14560553520321928, -0, -0, -0, 1.5657353278668433, -0.5798888118401012, 0, -0.14560553520321928, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -0, -0, -1.5572250142582087, -0, -0, -0, -0, 0, 0, 1.5572250142582087, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -0, -0, -0, -1.1266215512973428, -0, 1.0661059397023553, -0, 0, 0, 0, 1.1266215512973428, 0, -1.0661059397023553, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -0, -2.060232129551813, 1.756900609902372, -0, -0, -0, -0, 0, 2.060232129551813, -1.756900609902372, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1.0628806512935949, -0, -0, 0.3306985942820342, -0, 0.5013194822231914, -0, -1.0628806512935949, 0, 0, -0.3306985942820342, 0, -0.5013194822231914, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -0.02053916418367785, 2.0967009672108627, -0, 1.276296057052031, -0, -0.8396554873675388, -0, 0.02053916418367785, -2.0967009672108627, 0, -1.276296057052031, 0, 0.8396554873675388, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1.5173172721095745, -0, -0, -0, -0, -0.7781977786718928, -0.08927683907374018, 1.5173172721095745, 0, 0, 0, 0, 0.7781977786718928, 0.08927683907374018, 0, 0, 0, 0, 0, 0, 0, 1, 0, -0, -0, -0, -0, -0, 0.39773149008355624, -0, 0, 0, 0, 0, 0, -0.39773149008355624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), b: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0}, c: []float64{0.24547850255842107, -0.9373919913433648, 0, 0, 0, 0.2961224049153204, 0, -0.24547850255842107, 0.9373919913433648, -0, -0, -0, -0.2961224049153204, -0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { // Caused error because ALL of the possible replacements in Bland cause. // ab to be singular. This necessitates outer loop in bland over possible // moves. A: mat.NewDense(9, 23, []float64{0.6595219196440785, -0, -0, -1.8259394918781682, -0, -0, 0.005457361044175046, -0.6595219196440785, 0, 0, 1.8259394918781682, 0, 0, -0.005457361044175046, 1, 0, 0, 0, 0, 0, 0, 0, 0, -0, -0.10352878714214864, -0, -0, -0, -0, 0.5945016966696087, 0, 0.10352878714214864, 0, 0, 0, 0, -0.5945016966696087, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0.31734882842876444, -0, -0, -0, -0, -0, -0.716633126367685, -0.31734882842876444, 0, 0, 0, 0, 0, 0.716633126367685, 0, 0, 1, 0, 0, 0, 0, 0, 0, -0.7769812182932578, -0, -0.17370050158829553, 0.19405062263734607, -0, 1.1472330031002533, -0.6776631768730962, 0.7769812182932578, 0, 0.17370050158829553, -0.19405062263734607, 0, -1.1472330031002533, 0.6776631768730962, 0, 0, 0, 1, 0, 0, 0, 0, 0, -0, 0.8285611486611473, -0, -0, -0, -0, -0, 0, -0.8285611486611473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -2.088953453647358, 1.3286488791152795, -0, -0, -0, -0, 0.9147833235021142, 2.088953453647358, -1.3286488791152795, 0, 0, 0, 0, -0.9147833235021142, 0, 0, 0, 0, 0, 1, 0, 0, 0, -0, -0, -0, -0, 0.6560365621262937, -0, -0, 0, 0, 0, 0, -0.6560365621262937, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0.8957188338098074, -0, -0, -0, -0, -0, -0, -0.8957188338098074, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -0.2761381891117365, -0, -0, -0, 1.1154921426237823, 0.06429872020552618, -0, 0.2761381891117365, 0, 0, 0, -1.1154921426237823, -0.06429872020552618, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), b: []float64{0, 0, 0, 0, 0.5046208538522362, 1.0859412982429362, -2.066283584195025, 0, -0.2604305274353169}, c: []float64{0, 0, 0, 0, 0, 0, -0.05793762969330718, -0, -0, -0, -0, -0, -0, 0.05793762969330718, 0, 0, 0, 0, 0, 0, 0, 0, 0}, initialBasic: []int{22, 11, 7, 19, 18, 17, 16, 15, 14}, }, { // Caused initial supplied basis of Phase I to be singular. A: mat.NewDense(7, 11, []float64{0, 0, 0, 0, 0, 0.6667874223914787, -0.04779440888372957, -0.810020924434026, 0, 1.4190243477163373, 0, 0, 1.0452496826112936, 1.1966134226828076, 0, 0, 0, 0, -0.676136041089015, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.123232807871834, 0.2795467733707712, 0.21997115467272987, 0, -0.1572003980840453, 0, 0, 0, 0, 0.5130196002804861, 0, -0.005957174211761673, 0.3262874931735277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.5582052881594286, 0, 0.3544026193217651, 0, -1.0761986709145068, 0, 0.2438593072108347, 0, 0, 0, 0, 1.387509848081664, 0, 0, 0.3958750570508226, 1.6281679612990678, 0, 0, -0.24638311667922103, 0, 0, 0, 0, 0, 0, -0.628850893994423}), b: []float64{0.4135281763629115, 0, 0, 0, 0, 0, 0}, c: []float64{0.5586772876113472, 0, 0.14261332948424457, 0, -0.016394076753000086, -0.506087285562544, 0, 0.37619482505459145, 1.2943822852419233, 0.5887960293578207, 0}, }, } { testSimplex(t, test.initialBasic, test.c, test.A, test.b, convergenceTol) } rnd := rand.New(rand.NewSource(1)) // Randomized tests testRandomSimplex(t, 20000, 0.7, 10, rnd) testRandomSimplex(t, 20000, 0, 10, rnd) testRandomSimplex(t, 200, 0, 100, rnd) testRandomSimplex(t, 2, 0, 400, rnd) } func testRandomSimplex(t *testing.T, nTest int, pZero float64, maxN int, rnd *rand.Rand) { // Try a bunch of random LPs for i := 0; i < nTest; i++ { n := rnd.Intn(maxN) + 2 // n must be at least two. m := rnd.Intn(n-1) + 1 // m must be between 1 and n if m == 0 || n == 0 { continue } randValue := func() float64 { //var pZero float64 v := rnd.Float64() if v < pZero { return 0 } return rnd.NormFloat64() } a := mat.NewDense(m, n, nil) for i := 0; i < m; i++ { for j := 0; j < n; j++ { a.Set(i, j, randValue()) } } b := make([]float64, m) for i := range b { b[i] = randValue() } c := make([]float64, n) for i := range c { c[i] = randValue() } testSimplex(t, nil, c, a, b, convergenceTol) } } func testSimplex(t *testing.T, initialBasic []int, c []float64, a mat.Matrix, b []float64, convergenceTol float64) { primalOpt, primalX, _, errPrimal := simplex(initialBasic, c, a, b, convergenceTol) if errPrimal == nil { // No error solving the simplex, check that the solution is feasible. var bCheck mat.VecDense bCheck.MulVec(a, mat.NewVecDense(len(primalX), primalX)) if !mat.EqualApprox(&bCheck, mat.NewVecDense(len(b), b), 1e-10) { t.Errorf("No error in primal but solution infeasible") } } primalInfeasible := errPrimal == ErrInfeasible primalUnbounded := errPrimal == ErrUnbounded primalBounded := errPrimal == nil primalASingular := errPrimal == ErrSingular primalZeroRow := errPrimal == ErrZeroRow primalZeroCol := errPrimal == ErrZeroColumn primalBad := !primalInfeasible && !primalUnbounded && !primalBounded && !primalASingular && !primalZeroRow && !primalZeroCol // It's an error if it's not one of the known returned errors. If it's // singular the problem is undefined and so the result cannot be compared // to the dual. if errPrimal == ErrSingular || primalBad { if primalBad { t.Errorf("non-known error returned: %s", errPrimal) } return } // Compare the result to the answer found from solving the dual LP. // Construct and solve the dual LP. // Standard Form: // minimize cᵀ * x // subject to A * x = b, x >= 0 // The dual of this problem is // maximize -bᵀ * nu // subject to Aᵀ * nu + c >= 0 // Which is // minimize bᵀ * nu // subject to -Aᵀ * nu <= c negAT := &mat.Dense{} negAT.CloneFrom(a.T()) negAT.Scale(-1, negAT) cNew, aNew, bNew := Convert(b, negAT, c, nil, nil) dualOpt, dualX, _, errDual := simplex(nil, cNew, aNew, bNew, convergenceTol) if errDual == nil { // Check that the dual is feasible var bCheck mat.VecDense bCheck.MulVec(aNew, mat.NewVecDense(len(dualX), dualX)) if !mat.EqualApprox(&bCheck, mat.NewVecDense(len(bNew), bNew), 1e-10) { t.Errorf("No error in dual but solution infeasible") } } // Check about the zero status. if errPrimal == ErrZeroRow || errPrimal == ErrZeroColumn { return } // If the primal problem is feasible, then the primal and the dual should // be the same answer. We have flopped the sign in the dual (minimizing // bᵀ * nu instead of maximizing -bᵀ * nu), so flip it back. if errPrimal == nil { if errDual != nil { t.Errorf("Primal feasible but dual errored: %s", errDual) } dualOpt *= -1 if !scalar.EqualWithinAbsOrRel(dualOpt, primalOpt, convergenceTol, convergenceTol) { t.Errorf("Primal and dual value mismatch. Primal %v, dual %v.", primalOpt, dualOpt) } } // If the primal problem is unbounded, then the dual should be infeasible. if errPrimal == ErrUnbounded && errDual != ErrInfeasible { t.Errorf("Primal unbounded but dual not infeasible. ErrDual = %s", errDual) } // If the dual is unbounded, then the primal should be infeasible. if errDual == ErrUnbounded && errPrimal != ErrInfeasible { t.Errorf("Dual unbounded but primal not infeasible. ErrDual = %s", errPrimal) } // If the primal is infeasible, then the dual should be either infeasible // or unbounded. if errPrimal == ErrInfeasible { if errDual != ErrUnbounded && errDual != ErrInfeasible && errDual != ErrZeroColumn { t.Errorf("Primal infeasible but dual not infeasible or unbounded: %s", errDual) } } } golang-gonum-v1-gonum-0.14.0/optimize/convex/lp/simplexexample_test.go000066400000000000000000000011221450372207100260320ustar00rootroot00000000000000// Copyright ©2016 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 lp_test import ( "fmt" "log" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/optimize/convex/lp" ) func ExampleSimplex() { c := []float64{-1, -2, 0, 0} A := mat.NewDense(2, 4, []float64{-1, 2, 1, 0, 3, 1, 0, 1}) b := []float64{4, 9} opt, x, err := lp.Simplex(c, A, b, 0, nil) if err != nil { log.Fatal(err) } fmt.Printf("opt: %v\n", opt) fmt.Printf("x: %v\n", x) // Output: // opt: -8 // x: [2 3 0 0] } golang-gonum-v1-gonum-0.14.0/optimize/doc.go000066400000000000000000000004641450372207100205760ustar00rootroot00000000000000// 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 optimize implements algorithms for finding the optimum value of functions. package optimize // import "gonum.org/v1/gonum/optimize" golang-gonum-v1-gonum-0.14.0/optimize/errors.go000066400000000000000000000054641450372207100213520ustar00rootroot00000000000000// 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 optimize import ( "errors" "fmt" "math" ) var ( // ErrZeroDimensional signifies an optimization was called with an input of length 0. ErrZeroDimensional = errors.New("optimize: zero dimensional input") // ErrLinesearcherFailure signifies that a Linesearcher has iterated too // many times. This may occur if the gradient tolerance is set too low. ErrLinesearcherFailure = errors.New("linesearch: failed to converge") // ErrNonDescentDirection signifies that LinesearchMethod has received a // search direction from a NextDirectioner in which the function is not // decreasing. ErrNonDescentDirection = errors.New("linesearch: non-descent search direction") // ErrNoProgress signifies that LinesearchMethod cannot make further // progress because there is no change in location after Linesearcher step // due to floating-point arithmetic. ErrNoProgress = errors.New("linesearch: no change in location after Linesearcher step") // ErrLinesearcherBound signifies that a Linesearcher reached a step that // lies out of allowed bounds. ErrLinesearcherBound = errors.New("linesearch: step out of bounds") // ErrMissingGrad signifies that a Method requires a Gradient function that // is not supplied by Problem. ErrMissingGrad = errors.New("optimize: problem does not provide needed Grad function") // ErrMissingHess signifies that a Method requires a Hessian function that // is not supplied by Problem. ErrMissingHess = errors.New("optimize: problem does not provide needed Hess function") ) // ErrFunc is returned when an initial function value is invalid. The error // state may be either +Inf or NaN. ErrFunc satisfies the error interface. type ErrFunc float64 func (err ErrFunc) Error() string { switch { case math.IsInf(float64(err), 1): return "optimize: initial function value is infinite" case math.IsNaN(float64(err)): return "optimize: initial function value is NaN" default: panic("optimize: bad ErrFunc") } } // ErrGrad is returned when an initial gradient is invalid. The error gradient // may be either ±Inf or NaN. ErrGrad satisfies the error interface. type ErrGrad struct { Grad float64 // Grad is the invalid gradient value. Index int // Index is the position at which the invalid gradient was found. } func (err ErrGrad) Error() string { switch { case math.IsInf(err.Grad, 0): return fmt.Sprintf("optimize: initial gradient is infinite at position %d", err.Index) case math.IsNaN(err.Grad): return fmt.Sprintf("optimize: initial gradient is NaN at position %d", err.Index) default: panic("optimize: bad ErrGrad") } } // List of shared panic strings const badProblem = "optimize: objective function is undefined" golang-gonum-v1-gonum-0.14.0/optimize/functionconvergence.go000066400000000000000000000037211450372207100240740ustar00rootroot00000000000000// 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 optimize import ( "math" ) // Converger returns the convergence of the optimization based on // locations found during optimization. Converger must not modify the value of // the provided Location in any of the methods. type Converger interface { Init(dim int) Converged(loc *Location) Status } var ( _ Converger = NeverTerminate{} _ Converger = (*FunctionConverge)(nil) ) // NeverTerminate implements Converger, always reporting NotTerminated. type NeverTerminate struct{} func (NeverTerminate) Init(dim int) {} func (NeverTerminate) Converged(loc *Location) Status { return NotTerminated } // FunctionConverge tests for insufficient improvement in the optimum value // over the last iterations. A FunctionConvergence status is returned if // there is no significant decrease for FunctionConverge.Iterations. A // significant decrease is considered if // // f < f_best // // and // // f_best - f > FunctionConverge.Relative * maxabs(f, f_best) + FunctionConverge.Absolute // // If the decrease is significant, then the iteration counter is reset and // f_best is updated. // // If FunctionConverge.Iterations == 0, it has no effect. type FunctionConverge struct { Absolute float64 Relative float64 Iterations int first bool best float64 iter int } func (fc *FunctionConverge) Init(dim int) { fc.first = true fc.best = 0 fc.iter = 0 } func (fc *FunctionConverge) Converged(l *Location) Status { f := l.F if fc.first { fc.best = f fc.first = false return NotTerminated } if fc.Iterations == 0 { return NotTerminated } maxAbs := math.Max(math.Abs(f), math.Abs(fc.best)) if f < fc.best && fc.best-f > fc.Relative*maxAbs+fc.Absolute { fc.best = f fc.iter = 0 return NotTerminated } fc.iter++ if fc.iter < fc.Iterations { return NotTerminated } return FunctionConvergence } golang-gonum-v1-gonum-0.14.0/optimize/functions/000077500000000000000000000000001450372207100215065ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/optimize/functions/doc.go000066400000000000000000000011071450372207100226010ustar00rootroot00000000000000// 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 functions provides objective functions for testing optimization // algorithms. // // We encourage outside contributions of additional test functions that exhibit // properties not already covered in the testing suite or that have // significance due to prior use as benchmark cases. package functions // import "gonum.org/v1/gonum/optimize/functions" const badInputDim = "functions: wrong input dimension" golang-gonum-v1-gonum-0.14.0/optimize/functions/functions.go000066400000000000000000001257721450372207100240630ustar00rootroot00000000000000// 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 functions import ( "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) // Beale implements the Beale's function. // // Standard starting points: // // Easy: [1, 1] // Hard: [1, 4] // // References: // - Beale, E.: On an Iterative Method for Finding a Local Minimum of a // Function of More than One Variable. Technical Report 25, Statistical // Techniques Research Group, Princeton University (1958) // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type Beale struct{} func (Beale) Func(x []float64) float64 { if len(x) != 2 { panic("dimension of the problem must be 2") } f1 := 1.5 - x[0]*(1-x[1]) f2 := 2.25 - x[0]*(1-x[1]*x[1]) f3 := 2.625 - x[0]*(1-x[1]*x[1]*x[1]) return f1*f1 + f2*f2 + f3*f3 } func (Beale) Grad(grad, x []float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } if len(x) != len(grad) { panic("incorrect size of the gradient") } t1 := 1 - x[1] t2 := 1 - x[1]*x[1] t3 := 1 - x[1]*x[1]*x[1] f1 := 1.5 - x[0]*t1 f2 := 2.25 - x[0]*t2 f3 := 2.625 - x[0]*t3 grad[0] = -2 * (f1*t1 + f2*t2 + f3*t3) grad[1] = 2 * x[0] * (f1 + 2*f2*x[1] + 3*f3*x[1]*x[1]) } func (Beale) Hess(dst *mat.SymDense, x []float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } if len(x) != dst.SymmetricDim() { panic("incorrect size of the Hessian") } t1 := 1 - x[1] t2 := 1 - x[1]*x[1] t3 := 1 - x[1]*x[1]*x[1] f1 := 1.5 - x[1]*t1 f2 := 2.25 - x[1]*t2 f3 := 2.625 - x[1]*t3 h00 := 2 * (t1*t1 + t2*t2 + t3*t3) h01 := 2 * (f1 + x[1]*(2*f2+3*x[1]*f3) - x[0]*(t1+x[1]*(2*t2+3*x[1]*t3))) h11 := 2 * x[0] * (x[0] + 2*f2 + x[1]*(6*f3+x[0]*x[1]*(4+9*x[1]*x[1]))) dst.SetSym(0, 0, h00) dst.SetSym(0, 1, h01) dst.SetSym(1, 1, h11) } func (Beale) Minima() []Minimum { return []Minimum{ { X: []float64{3, 0.5}, F: 0, Global: true, }, } } // BiggsEXP2 implements the Biggs' EXP2 function. // // Standard starting point: // // [1, 2] // // Reference: // // Biggs, M.C.: Minimization algorithms making use of non-quadratic properties // of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315 type BiggsEXP2 struct{} func (BiggsEXP2) Func(x []float64) (sum float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } for i := 1; i <= 10; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) f := math.Exp(-x[0]*z) - 5*math.Exp(-x[1]*z) - y sum += f * f } return sum } func (BiggsEXP2) Grad(grad, x []float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 10; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) f := math.Exp(-x[0]*z) - 5*math.Exp(-x[1]*z) - y dfdx0 := -z * math.Exp(-x[0]*z) dfdx1 := 5 * z * math.Exp(-x[1]*z) grad[0] += 2 * f * dfdx0 grad[1] += 2 * f * dfdx1 } } func (BiggsEXP2) Minima() []Minimum { return []Minimum{ { X: []float64{1, 10}, F: 0, Global: true, }, } } // BiggsEXP3 implements the Biggs' EXP3 function. // // Standard starting point: // // [1, 2, 1] // // Reference: // // Biggs, M.C.: Minimization algorithms making use of non-quadratic properties // of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315 type BiggsEXP3 struct{} func (BiggsEXP3) Func(x []float64) (sum float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } for i := 1; i <= 10; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) f := math.Exp(-x[0]*z) - x[2]*math.Exp(-x[1]*z) - y sum += f * f } return sum } func (BiggsEXP3) Grad(grad, x []float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 10; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) f := math.Exp(-x[0]*z) - x[2]*math.Exp(-x[1]*z) - y dfdx0 := -z * math.Exp(-x[0]*z) dfdx1 := x[2] * z * math.Exp(-x[1]*z) dfdx2 := -math.Exp(-x[1] * z) grad[0] += 2 * f * dfdx0 grad[1] += 2 * f * dfdx1 grad[2] += 2 * f * dfdx2 } } func (BiggsEXP3) Minima() []Minimum { return []Minimum{ { X: []float64{1, 10, 5}, F: 0, Global: true, }, } } // BiggsEXP4 implements the Biggs' EXP4 function. // // Standard starting point: // // [1, 2, 1, 1] // // Reference: // // Biggs, M.C.: Minimization algorithms making use of non-quadratic properties // of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315 type BiggsEXP4 struct{} func (BiggsEXP4) Func(x []float64) (sum float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } for i := 1; i <= 10; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) - y sum += f * f } return sum } func (BiggsEXP4) Grad(grad, x []float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 10; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) - y dfdx0 := -z * x[2] * math.Exp(-x[0]*z) dfdx1 := z * x[3] * math.Exp(-x[1]*z) dfdx2 := math.Exp(-x[0] * z) dfdx3 := -math.Exp(-x[1] * z) grad[0] += 2 * f * dfdx0 grad[1] += 2 * f * dfdx1 grad[2] += 2 * f * dfdx2 grad[3] += 2 * f * dfdx3 } } func (BiggsEXP4) Minima() []Minimum { return []Minimum{ { X: []float64{1, 10, 1, 5}, F: 0, Global: true, }, } } // BiggsEXP5 implements the Biggs' EXP5 function. // // Standard starting point: // // [1, 2, 1, 1, 1] // // Reference: // // Biggs, M.C.: Minimization algorithms making use of non-quadratic properties // of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315 type BiggsEXP5 struct{} func (BiggsEXP5) Func(x []float64) (sum float64) { if len(x) != 5 { panic("dimension of the problem must be 5") } for i := 1; i <= 11; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z) f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + 3*math.Exp(-x[4]*z) - y sum += f * f } return sum } func (BiggsEXP5) Grad(grad, x []float64) { if len(x) != 5 { panic("dimension of the problem must be 5") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 11; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z) f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + 3*math.Exp(-x[4]*z) - y dfdx0 := -z * x[2] * math.Exp(-x[0]*z) dfdx1 := z * x[3] * math.Exp(-x[1]*z) dfdx2 := math.Exp(-x[0] * z) dfdx3 := -math.Exp(-x[1] * z) dfdx4 := -3 * z * math.Exp(-x[4]*z) grad[0] += 2 * f * dfdx0 grad[1] += 2 * f * dfdx1 grad[2] += 2 * f * dfdx2 grad[3] += 2 * f * dfdx3 grad[4] += 2 * f * dfdx4 } } func (BiggsEXP5) Minima() []Minimum { return []Minimum{ { X: []float64{1, 10, 1, 5, 4}, F: 0, Global: true, }, } } // BiggsEXP6 implements the Biggs' EXP6 function. // // Standard starting point: // // [1, 2, 1, 1, 1, 1] // // References: // - Biggs, M.C.: Minimization algorithms making use of non-quadratic // properties of the objective function. IMA J Appl Math 8 (1971), 315-327; // doi:10.1093/imamat/8.3.315 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type BiggsEXP6 struct{} func (BiggsEXP6) Func(x []float64) (sum float64) { if len(x) != 6 { panic("dimension of the problem must be 6") } for i := 1; i <= 13; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z) f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + x[5]*math.Exp(-x[4]*z) - y sum += f * f } return sum } func (BiggsEXP6) Grad(grad, x []float64) { if len(x) != 6 { panic("dimension of the problem must be 6") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 13; i++ { z := float64(i) / 10 y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z) f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + x[5]*math.Exp(-x[4]*z) - y dfdx0 := -z * x[2] * math.Exp(-x[0]*z) dfdx1 := z * x[3] * math.Exp(-x[1]*z) dfdx2 := math.Exp(-x[0] * z) dfdx3 := -math.Exp(-x[1] * z) dfdx4 := -z * x[5] * math.Exp(-x[4]*z) dfdx5 := math.Exp(-x[4] * z) grad[0] += 2 * f * dfdx0 grad[1] += 2 * f * dfdx1 grad[2] += 2 * f * dfdx2 grad[3] += 2 * f * dfdx3 grad[4] += 2 * f * dfdx4 grad[5] += 2 * f * dfdx5 } } func (BiggsEXP6) Minima() []Minimum { return []Minimum{ { X: []float64{1, 10, 1, 5, 4, 3}, F: 0, Global: true, }, { X: []float64{1.7114159947956764, 17.68319817846745, 1.1631436609697268, 5.1865615510738605, 1.7114159947949301, 1.1631436609697998}, F: 0.005655649925499929, Global: false, }, { // X: []float64{1.22755594752403, X[1] >> 0, 0.83270306333466, X[3] << 0, X[4] = X[0], X[5] = X[2]}, X: []float64{1.22755594752403, 1000, 0.83270306333466, -1000, 1.22755594752403, 0.83270306333466}, F: 0.306366772624790, Global: false, }, } } // Box3D implements the Box' three-dimensional function. // // Standard starting point: // // [0, 10, 20] // // References: // - Box, M.J.: A comparison of several current optimization methods, and the // use of transformations in constrained problems. Comput J 9 (1966), 67-77 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type Box3D struct{} func (Box3D) Func(x []float64) (sum float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } for i := 1; i <= 10; i++ { c := -float64(i) / 10 y := math.Exp(c) - math.Exp(10*c) f := math.Exp(c*x[0]) - math.Exp(c*x[1]) - x[2]*y sum += f * f } return sum } func (Box3D) Grad(grad, x []float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } if len(x) != len(grad) { panic("incorrect size of the gradient") } grad[0] = 0 grad[1] = 0 grad[2] = 0 for i := 1; i <= 10; i++ { c := -float64(i) / 10 y := math.Exp(c) - math.Exp(10*c) f := math.Exp(c*x[0]) - math.Exp(c*x[1]) - x[2]*y grad[0] += 2 * f * c * math.Exp(c*x[0]) grad[1] += -2 * f * c * math.Exp(c*x[1]) grad[2] += -2 * f * y } } func (Box3D) Minima() []Minimum { return []Minimum{ { X: []float64{1, 10, 1}, F: 0, Global: true, }, { X: []float64{10, 1, -1}, F: 0, Global: true, }, { // Any point at the line {a, a, 0}. X: []float64{1, 1, 0}, F: 0, Global: true, }, } } // BraninHoo implements the Branin-Hoo function. BraninHoo is a 2-dimensional // test function with three global minima. It is typically evaluated in the domain // x_0 ∈ [-5, 10], x_1 ∈ [0, 15]. // // f(x) = (x_1 - (5.1/(4π^2))*x_0^2 + (5/π)*x_0 - 6)^2 + 10*(1-1/(8π))cos(x_0) + 10 // // It has a minimum value of 0.397887 at x^* = {(-π, 12.275), (π, 2.275), (9.424778, 2.475)} // // Reference: // // https://www.sfu.ca/~ssurjano/branin.html (obtained June 2017) type BraninHoo struct{} func (BraninHoo) Func(x []float64) float64 { if len(x) != 2 { panic("functions: dimension of the problem must be 2") } a, b, c, r, s, t := 1.0, 5.1/(4*math.Pi*math.Pi), 5/math.Pi, 6.0, 10.0, 1/(8*math.Pi) term := x[1] - b*x[0]*x[0] + c*x[0] - r return a*term*term + s*(1-t)*math.Cos(x[0]) + s } func (BraninHoo) Minima() []Minimum { return []Minimum{ { X: []float64{-math.Pi, 12.275}, F: 0.397887, Global: true, }, { X: []float64{math.Pi, 2.275}, F: 0.397887, Global: true, }, { X: []float64{9.424778, 2.475}, F: 0.397887, Global: true, }, } } // BrownBadlyScaled implements the Brown's badly scaled function. // // Standard starting point: // // [1, 1] // // References: // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type BrownBadlyScaled struct{} func (BrownBadlyScaled) Func(x []float64) float64 { if len(x) != 2 { panic("dimension of the problem must be 2") } f1 := x[0] - 1e6 f2 := x[1] - 2e-6 f3 := x[0]*x[1] - 2 return f1*f1 + f2*f2 + f3*f3 } func (BrownBadlyScaled) Grad(grad, x []float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } if len(x) != len(grad) { panic("incorrect size of the gradient") } f1 := x[0] - 1e6 f2 := x[1] - 2e-6 f3 := float64(x[0]*x[1]) - 2 // Prevent fused multiply subtract. grad[0] = 2*f1 + 2*f3*x[1] grad[1] = 2*f2 + 2*f3*x[0] } func (BrownBadlyScaled) Hess(dst *mat.SymDense, x []float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } if len(x) != dst.SymmetricDim() { panic("incorrect size of the Hessian") } h00 := 2 + 2*x[1]*x[1] h01 := 4*x[0]*x[1] - 4 h11 := 2 + 2*x[0]*x[0] dst.SetSym(0, 0, h00) dst.SetSym(0, 1, h01) dst.SetSym(1, 1, h11) } func (BrownBadlyScaled) Minima() []Minimum { return []Minimum{ { X: []float64{1e6, 2e-6}, F: 0, Global: true, }, } } // BrownAndDennis implements the Brown and Dennis function. // // Standard starting point: // // [25, 5, -5, -1] // // References: // - Brown, K.M., Dennis, J.E.: New computational algorithms for minimizing a // sum of squares of nonlinear functions. Research Report Number 71-6, Yale // University (1971) // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type BrownAndDennis struct{} func (BrownAndDennis) Func(x []float64) (sum float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } for i := 1; i <= 20; i++ { c := float64(i) / 5 f1 := x[0] + c*x[1] - math.Exp(c) f2 := x[2] + x[3]*math.Sin(c) - math.Cos(c) f := f1*f1 + f2*f2 sum += f * f } return sum } func (BrownAndDennis) Grad(grad, x []float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 20; i++ { c := float64(i) / 5 f1 := x[0] + c*x[1] - math.Exp(c) f2 := x[2] + x[3]*math.Sin(c) - math.Cos(c) f := f1*f1 + f2*f2 grad[0] += 4 * f * f1 grad[1] += 4 * f * f1 * c grad[2] += 4 * f * f2 grad[3] += 4 * f * f2 * math.Sin(c) } } func (BrownAndDennis) Hess(dst *mat.SymDense, x []float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } if len(x) != dst.SymmetricDim() { panic("incorrect size of the Hessian") } for i := 0; i < 4; i++ { for j := i; j < 4; j++ { dst.SetSym(i, j, 0) } } for i := 1; i <= 20; i++ { d1 := float64(i) / 5 d2 := math.Sin(d1) t1 := x[0] + d1*x[1] - math.Exp(d1) t2 := x[2] + d2*x[3] - math.Cos(d1) t := t1*t1 + t2*t2 s3 := 2 * t1 * t2 r1 := t + 2*t1*t1 r2 := t + 2*t2*t2 dst.SetSym(0, 0, dst.At(0, 0)+r1) dst.SetSym(0, 1, dst.At(0, 1)+d1*r1) dst.SetSym(1, 1, dst.At(1, 1)+d1*d1*r1) dst.SetSym(0, 2, dst.At(0, 2)+s3) dst.SetSym(1, 2, dst.At(1, 2)+d1*s3) dst.SetSym(2, 2, dst.At(2, 2)+r2) dst.SetSym(0, 3, dst.At(0, 3)+d2*s3) dst.SetSym(1, 3, dst.At(1, 3)+d1*d2*s3) dst.SetSym(2, 3, dst.At(2, 3)+d2*r2) dst.SetSym(3, 3, dst.At(3, 3)+d2*d2*r2) } for i := 0; i < 4; i++ { for j := i; j < 4; j++ { dst.SetSym(i, j, 4*dst.At(i, j)) } } } func (BrownAndDennis) Minima() []Minimum { return []Minimum{ { X: []float64{-11.594439904762162, 13.203630051207202, -0.4034394881768612, 0.2367787744557347}, F: 85822.20162635634, Global: true, }, } } // ExtendedPowellSingular implements the extended Powell's function. // Its Hessian matrix is singular at the minimizer. // // Standard starting point: // // [3, -1, 0, 3, 3, -1, 0, 3, ..., 3, -1, 0, 3] // // References: // - Spedicato E.: Computational experience with quasi-Newton algorithms for // minimization problems of moderatly large size. Towards Global // Optimization 2 (1978), 209-219 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type ExtendedPowellSingular struct{} func (ExtendedPowellSingular) Func(x []float64) (sum float64) { if len(x)%4 != 0 { panic("dimension of the problem must be a multiple of 4") } for i := 0; i < len(x); i += 4 { f1 := x[i] + 10*x[i+1] f2 := x[i+2] - x[i+3] t := x[i+1] - 2*x[i+2] f3 := t * t t = x[i] - x[i+3] f4 := t * t sum += f1*f1 + 5*f2*f2 + f3*f3 + 10*f4*f4 } return sum } func (ExtendedPowellSingular) Grad(grad, x []float64) { if len(x)%4 != 0 { panic("dimension of the problem must be a multiple of 4") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := 0; i < len(x); i += 4 { f1 := x[i] + 10*x[i+1] f2 := x[i+2] - x[i+3] t1 := x[i+1] - 2*x[i+2] f3 := t1 * t1 t2 := x[i] - x[i+3] f4 := t2 * t2 grad[i] = 2*f1 + 40*f4*t2 grad[i+1] = 20*f1 + 4*f3*t1 grad[i+2] = 10*f2 - 8*f3*t1 grad[i+3] = -10*f2 - 40*f4*t2 } } func (ExtendedPowellSingular) Minima() []Minimum { return []Minimum{ { X: []float64{0, 0, 0, 0}, F: 0, Global: true, }, { X: []float64{0, 0, 0, 0, 0, 0, 0, 0}, F: 0, Global: true, }, { X: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, F: 0, Global: true, }, } } // ExtendedRosenbrock implements the extended, multidimensional Rosenbrock // function. // // Standard starting point: // // Easy: [-1.2, 1, -1.2, 1, ...] // Hard: any point far from the minimum // // References: // - Rosenbrock, H.H.: An Automatic Method for Finding the Greatest or Least // Value of a Function. Computer J 3 (1960), 175-184 // - http://en.wikipedia.org/wiki/Rosenbrock_function type ExtendedRosenbrock struct{} func (ExtendedRosenbrock) Func(x []float64) (sum float64) { for i := 0; i < len(x)-1; i++ { a := 1 - x[i] b := x[i+1] - x[i]*x[i] sum += a*a + 100*b*b } return sum } func (ExtendedRosenbrock) Grad(grad, x []float64) { if len(x) != len(grad) { panic("incorrect size of the gradient") } dim := len(x) for i := range grad { grad[i] = 0 } // Prevent fused multiply add and fused multiply subtract. for i := 0; i < dim-1; i++ { grad[i] -= float64(2 * (1 - x[i])) grad[i] -= float64(400 * (x[i+1] - float64(x[i]*x[i])) * x[i]) } for i := 1; i < dim; i++ { grad[i] += float64(200 * (x[i] - float64(x[i-1]*x[i-1]))) } } func (ExtendedRosenbrock) Minima() []Minimum { return []Minimum{ { X: []float64{1, 1}, F: 0, Global: true, }, { X: []float64{1, 1, 1}, F: 0, Global: true, }, { X: []float64{1, 1, 1, 1}, F: 0, Global: true, }, { X: []float64{-0.7756592265653526, 0.6130933654850433, 0.38206284633839305, 0.14597201855219452}, F: 3.701428610430017, Global: false, }, { X: []float64{1, 1, 1, 1, 1}, F: 0, Global: true, }, { X: []float64{-0.9620510206947502, 0.9357393959767103, 0.8807136041943204, 0.7778776758544063, 0.6050936785926526}, F: 3.930839434133027, Global: false, }, { X: []float64{-0.9865749795709938, 0.9833982288361819, 0.972106670053092, 0.9474374368264362, 0.8986511848517299, 0.8075739520354182}, F: 3.973940500930295, Global: false, }, { X: []float64{-0.9917225725614055, 0.9935553935033712, 0.992173321594692, 0.9868987626903134, 0.975164756608872, 0.9514319827049906, 0.9052228177139495}, F: 3.9836005364248543, Global: false, }, { X: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, F: 0, Global: true, }, } } // Gaussian implements the Gaussian function. // The function has one global minimum and a number of false local minima // caused by the finite floating point precision. // // Standard starting point: // // [0.4, 1, 0] // // Reference: // // More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained optimization // software. ACM Trans Math Softw 7 (1981), 17-41 type Gaussian struct{} func (Gaussian) y(i int) (yi float64) { switch i { case 1, 15: yi = 0.0009 case 2, 14: yi = 0.0044 case 3, 13: yi = 0.0175 case 4, 12: yi = 0.0540 case 5, 11: yi = 0.1295 case 6, 10: yi = 0.2420 case 7, 9: yi = 0.3521 case 8: yi = 0.3989 } return yi } func (g Gaussian) Func(x []float64) (sum float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } for i := 1; i <= 15; i++ { c := 0.5 * float64(8-i) b := c - x[2] d := b * b e := math.Exp(-0.5 * x[1] * d) f := x[0]*e - g.y(i) sum += f * f } return sum } func (g Gaussian) Grad(grad, x []float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } if len(x) != len(grad) { panic("incorrect size of the gradient") } grad[0] = 0 grad[1] = 0 grad[2] = 0 for i := 1; i <= 15; i++ { c := 0.5 * float64(8-i) b := c - x[2] d := b * b e := math.Exp(-0.5 * x[1] * d) f := x[0]*e - g.y(i) grad[0] += 2 * f * e grad[1] -= f * e * d * x[0] grad[2] += 2 * f * e * x[0] * x[1] * b } } func (Gaussian) Minima() []Minimum { return []Minimum{ { X: []float64{0.398956137837997, 1.0000190844805048, 0}, F: 1.12793276961912e-08, Global: true, }, } } // GulfResearchAndDevelopment implements the Gulf Research and Development function. // // Standard starting point: // // [5, 2.5, 0.15] // // References: // - Cox, R.A.: Comparison of the performance of seven optimization algorithms // on twelve unconstrained minimization problems. Ref. 1335CNO4, Gulf // Research and Development Company, Pittsburg (1969) // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type GulfResearchAndDevelopment struct{} func (GulfResearchAndDevelopment) Func(x []float64) (sum float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } for i := 1; i <= 99; i++ { arg := float64(i) / 100 r := math.Pow(-50*math.Log(arg), 2.0/3.0) + 25 - x[1] t1 := math.Pow(math.Abs(r), x[2]) / x[0] t2 := math.Exp(-t1) t := t2 - arg sum += t * t } return sum } func (GulfResearchAndDevelopment) Grad(grad, x []float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 99; i++ { arg := float64(i) / 100 r := math.Pow(-50*math.Log(arg), 2.0/3.0) + 25 - x[1] t1 := math.Pow(math.Abs(r), x[2]) / x[0] t2 := math.Exp(-t1) t := t2 - arg s1 := t1 * t2 * t grad[0] += s1 grad[1] += s1 / r grad[2] -= s1 * math.Log(math.Abs(r)) } grad[0] *= 2 / x[0] grad[1] *= 2 * x[2] grad[2] *= 2 } func (GulfResearchAndDevelopment) Minima() []Minimum { return []Minimum{ { X: []float64{50, 25, 1.5}, F: 0, Global: true, }, { X: []float64{99.89529935174151, 60.61453902799833, 9.161242695144592}, F: 32.8345, Global: false, }, { X: []float64{201.662589489426, 60.61633150468155, 10.224891158488965}, F: 32.8345, Global: false, }, } } // HelicalValley implements the helical valley function of Fletcher and Powell. // Function is not defined at x[0] = 0. // // Standard starting point: // // [-1, 0, 0] // // References: // - Fletcher, R., Powell, M.J.D.: A rapidly convergent descent method for // minimization. Comput J 6 (1963), 163-168 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type HelicalValley struct{} func (HelicalValley) Func(x []float64) float64 { if len(x) != 3 { panic("dimension of the problem must be 3") } if x[0] == 0 { panic("function not defined at x[0] = 0") } theta := 0.5 * math.Atan(x[1]/x[0]) / math.Pi if x[0] < 0 { theta += 0.5 } f1 := 10 * (x[2] - 10*theta) f2 := 10 * (math.Hypot(x[0], x[1]) - 1) f3 := x[2] return f1*f1 + f2*f2 + f3*f3 } func (HelicalValley) Grad(grad, x []float64) { if len(x) != 3 { panic("dimension of the problem must be 3") } if len(x) != len(grad) { panic("incorrect size of the gradient") } if x[0] == 0 { panic("function not defined at x[0] = 0") } theta := 0.5 * math.Atan(x[1]/x[0]) / math.Pi if x[0] < 0 { theta += 0.5 } h := math.Hypot(x[0], x[1]) r := 1 / h q := r * r / math.Pi s := x[2] - 10*theta grad[0] = 200 * (5*s*q*x[1] + (h-1)*r*x[0]) grad[1] = 200 * (-5*s*q*x[0] + (h-1)*r*x[1]) grad[2] = 2 * (100*s + x[2]) } func (HelicalValley) Minima() []Minimum { return []Minimum{ { X: []float64{1, 0, 0}, F: 0, Global: true, }, } } // Linear implements a linear function. type Linear struct{} func (Linear) Func(x []float64) float64 { return floats.Sum(x) } func (Linear) Grad(grad, x []float64) []float64 { if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 1 } return grad } // PenaltyI implements the first penalty function by Gill, Murray and Pitfield. // // Standard starting point: // // [1, ..., n] // // References: // - Gill, P.E., Murray, W., Pitfield, R.A.: The implementation of two revised // quasi-Newton algorithms for unconstrained optimization. Report NAC 11, // National Phys Lab (1972), 82-83 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type PenaltyI struct{} func (PenaltyI) Func(x []float64) (sum float64) { for _, v := range x { sum += (v - 1) * (v - 1) } sum *= 1e-5 var s float64 for _, v := range x { s += v * v } sum += (s - 0.25) * (s - 0.25) return sum } func (PenaltyI) Grad(grad, x []float64) { if len(x) != len(grad) { panic("incorrect size of the gradient") } s := -0.25 for _, v := range x { s += v * v } for i, v := range x { grad[i] = 2 * (2*s*v + 1e-5*(v-1)) } } func (PenaltyI) Minima() []Minimum { return []Minimum{ { X: []float64{0.2500074995875379, 0.2500074995875379, 0.2500074995875379, 0.2500074995875379}, F: 2.2499775008999372e-05, Global: true, }, { X: []float64{0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634}, F: 7.087651467090369e-05, Global: true, }, } } // PenaltyII implements the second penalty function by Gill, Murray and Pitfield. // // Standard starting point: // // [0.5, ..., 0.5] // // References: // - Gill, P.E., Murray, W., Pitfield, R.A.: The implementation of two revised // quasi-Newton algorithms for unconstrained optimization. Report NAC 11, // National Phys Lab (1972), 82-83 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type PenaltyII struct{} func (PenaltyII) Func(x []float64) (sum float64) { dim := len(x) s := -1.0 for i, v := range x { s += float64(dim-i) * v * v } for i := 1; i < dim; i++ { yi := math.Exp(float64(i+1)/10) + math.Exp(float64(i)/10) f := math.Exp(x[i]/10) + math.Exp(x[i-1]/10) - yi sum += f * f } for i := 1; i < dim; i++ { f := math.Exp(x[i]/10) - math.Exp(-1.0/10) sum += f * f } sum *= 1e-5 sum += (x[0] - 0.2) * (x[0] - 0.2) sum += s * s return sum } func (PenaltyII) Grad(grad, x []float64) { if len(x) != len(grad) { panic("incorrect size of the gradient") } dim := len(x) s := -1.0 for i, v := range x { s += float64(dim-i) * v * v } for i, v := range x { grad[i] = 4 * s * float64(dim-i) * v } for i := 1; i < dim; i++ { yi := math.Exp(float64(i+1)/10) + math.Exp(float64(i)/10) f := math.Exp(x[i]/10) + math.Exp(x[i-1]/10) - yi grad[i] += 1e-5 * f * math.Exp(x[i]/10) / 5 grad[i-1] += 1e-5 * f * math.Exp(x[i-1]/10) / 5 } for i := 1; i < dim; i++ { f := math.Exp(x[i]/10) - math.Exp(-1.0/10) grad[i] += 1e-5 * f * math.Exp(x[i]/10) / 5 } grad[0] += 2 * (x[0] - 0.2) } func (PenaltyII) Minima() []Minimum { return []Minimum{ { X: []float64{0.19999933335, 0.19131670128566283, 0.4801014860897, 0.5188454026659}, F: 9.376293007355449e-06, Global: true, }, { X: []float64{0.19998360520892217, 0.010350644318663525, 0.01960493546891094, 0.03208906550305253, 0.04993267593895693, 0.07651399534454084, 0.11862407118600789, 0.1921448731780023, 0.3473205862372022, 0.36916437893066273}, F: 0.00029366053745674594, Global: true, }, } } // PowellBadlyScaled implements the Powell's badly scaled function. // The function is very flat near the minimum. A satisfactory solution is one // that gives f(x) ≅ 1e-13. // // Standard starting point: // // [0, 1] // // References: // - Powell, M.J.D.: A Hybrid Method for Nonlinear Equations. Numerical // Methods for Nonlinear Algebraic Equations, P. Rabinowitz (ed.), Gordon // and Breach (1970) // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type PowellBadlyScaled struct{} func (PowellBadlyScaled) Func(x []float64) float64 { if len(x) != 2 { panic("dimension of the problem must be 2") } f1 := 1e4*x[0]*x[1] - 1 f2 := math.Exp(-x[0]) + math.Exp(-x[1]) - 1.0001 return f1*f1 + f2*f2 } func (PowellBadlyScaled) Grad(grad, x []float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } if len(x) != len(grad) { panic("incorrect size of the gradient") } f1 := 1e4*x[0]*x[1] - 1 f2 := math.Exp(-x[0]) + math.Exp(-x[1]) - 1.0001 grad[0] = 2 * (1e4*f1*x[1] - f2*math.Exp(-x[0])) grad[1] = 2 * (1e4*f1*x[0] - f2*math.Exp(-x[1])) } func (PowellBadlyScaled) Hess(dst *mat.SymDense, x []float64) { if len(x) != 2 { panic("dimension of the problem must be 2") } if len(x) != dst.SymmetricDim() { panic("incorrect size of the Hessian") } t1 := 1e4*x[0]*x[1] - 1 s1 := math.Exp(-x[0]) s2 := math.Exp(-x[1]) t2 := s1 + s2 - 1.0001 h00 := 2 * (1e8*x[1]*x[1] + s1*(s1+t2)) h01 := 2 * (1e4*(1+2*t1) + s1*s2) h11 := 2 * (1e8*x[0]*x[0] + s2*(s2+t2)) dst.SetSym(0, 0, h00) dst.SetSym(0, 1, h01) dst.SetSym(1, 1, h11) } func (PowellBadlyScaled) Minima() []Minimum { return []Minimum{ { X: []float64{1.0981593296997149e-05, 9.106146739867375}, F: 0, Global: true, }, } } // Trigonometric implements the trigonometric function. // // Standard starting point: // // [1/dim, ..., 1/dim] // // References: // - Spedicato E.: Computational experience with quasi-Newton algorithms for // minimization problems of moderatly large size. Towards Global // Optimization 2 (1978), 209-219 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type Trigonometric struct{} func (Trigonometric) Func(x []float64) (sum float64) { var s1 float64 for _, v := range x { s1 += math.Cos(v) } for i, v := range x { f := float64(len(x)+i+1) - float64(i+1)*math.Cos(v) - math.Sin(v) - s1 sum += f * f } return sum } func (Trigonometric) Grad(grad, x []float64) { if len(x) != len(grad) { panic("incorrect size of the gradient") } var s1 float64 for _, v := range x { s1 += math.Cos(v) } var s2 float64 for i, v := range x { f := float64(len(x)+i+1) - float64(i+1)*math.Cos(v) - math.Sin(v) - s1 s2 += f grad[i] = 2 * f * (float64(i+1)*math.Sin(v) - math.Cos(v)) } for i, v := range x { grad[i] += 2 * s2 * math.Sin(v) } } func (Trigonometric) Minima() []Minimum { return []Minimum{ { X: []float64{0.04296456438227447, 0.043976287478192246, 0.045093397949095684, 0.04633891624617569, 0.047744381782831, 0.04935473251330618, 0.05123734850076505, 0.19520946391410446, 0.1649776652761741, 0.06014857783799575}, F: 0, Global: true, }, { // TODO(vladimir-ch): If we knew the location of this minimum more // accurately, we could decrease defaultGradTol. X: []float64{0.05515090434047145, 0.05684061730812344, 0.05876400231100774, 0.060990608903034337, 0.06362621381044778, 0.06684318087364617, 0.2081615177172172, 0.16436309604419047, 0.08500689695564931, 0.09143145386293675}, F: 2.795056121876575e-05, Global: false, }, } } // VariablyDimensioned implements a variably dimensioned function. // // Standard starting point: // // [..., (dim-i)/dim, ...], i=1,...,dim // // References: // // More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained optimization // software. ACM Trans Math Softw 7 (1981), 17-41 type VariablyDimensioned struct{} func (VariablyDimensioned) Func(x []float64) (sum float64) { for _, v := range x { t := v - 1 sum += t * t } var s float64 for i, v := range x { s += float64(i+1) * (v - 1) } s *= s sum += s s *= s sum += s return sum } func (VariablyDimensioned) Grad(grad, x []float64) { if len(x) != len(grad) { panic("incorrect size of the gradient") } var s float64 for i, v := range x { s += float64(i+1) * (v - 1) } for i, v := range x { grad[i] = 2 * (v - 1 + s*float64(i+1)*(1+2*s*s)) } } func (VariablyDimensioned) Minima() []Minimum { return []Minimum{ { X: []float64{1, 1}, F: 0, Global: true, }, { X: []float64{1, 1, 1}, F: 0, Global: true, }, { X: []float64{1, 1, 1, 1}, F: 0, Global: true, }, { X: []float64{1, 1, 1, 1, 1}, F: 0, Global: true, }, { X: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, F: 0, Global: true, }, } } // Watson implements the Watson's function. // Dimension of the problem should be 2 <= dim <= 31. For dim == 9, the problem // of minimizing the function is very ill conditioned. // // Standard starting point: // // [0, ..., 0] // // References: // - Kowalik, J.S., Osborne, M.R.: Methods for Unconstrained Optimization // Problems. Elsevier North-Holland, New York, 1968 // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type Watson struct{} func (Watson) Func(x []float64) (sum float64) { for i := 1; i <= 29; i++ { d1 := float64(i) / 29 d2 := 1.0 var s1 float64 for j := 1; j < len(x); j++ { s1 += float64(j) * d2 * x[j] d2 *= d1 } d2 = 1.0 var s2 float64 for _, v := range x { s2 += d2 * v d2 *= d1 } t := s1 - s2*s2 - 1 sum += t * t } t := x[1] - x[0]*x[0] - 1 sum += x[0]*x[0] + t*t return sum } func (Watson) Grad(grad, x []float64) { if len(x) != len(grad) { panic("incorrect size of the gradient") } for i := range grad { grad[i] = 0 } for i := 1; i <= 29; i++ { d1 := float64(i) / 29 d2 := 1.0 var s1 float64 for j := 1; j < len(x); j++ { s1 += float64(j) * d2 * x[j] d2 *= d1 } d2 = 1.0 var s2 float64 for _, v := range x { s2 += d2 * v d2 *= d1 } t := s1 - s2*s2 - 1 s3 := 2 * d1 * s2 d2 = 2 / d1 for j := range x { grad[j] += d2 * (float64(j) - s3) * t d2 *= d1 } } t := x[1] - x[0]*x[0] - 1 grad[0] += x[0] * (2 - 4*t) grad[1] += 2 * t } func (Watson) Hess(dst *mat.SymDense, x []float64) { dim := len(x) if len(x) != dst.SymmetricDim() { panic("incorrect size of the Hessian") } for j := 0; j < dim; j++ { for k := j; k < dim; k++ { dst.SetSym(j, k, 0) } } for i := 1; i <= 29; i++ { d1 := float64(i) / 29 d2 := 1.0 var s1 float64 for j := 1; j < dim; j++ { s1 += float64(j) * d2 * x[j] d2 *= d1 } d2 = 1.0 var s2 float64 for _, v := range x { s2 += d2 * v d2 *= d1 } t := s1 - s2*s2 - 1 s3 := 2 * d1 * s2 d2 = 2 / d1 th := 2 * d1 * d1 * t for j := 0; j < dim; j++ { v := float64(j) - s3 d3 := 1 / d1 for k := 0; k <= j; k++ { dst.SetSym(k, j, dst.At(k, j)+d2*d3*(v*(float64(k)-s3)-th)) d3 *= d1 } d2 *= d1 } } t1 := x[1] - x[0]*x[0] - 1 dst.SetSym(0, 0, dst.At(0, 0)+8*x[0]*x[0]+2-4*t1) dst.SetSym(0, 1, dst.At(0, 1)-4*x[0]) dst.SetSym(1, 1, dst.At(1, 1)+2) } func (Watson) Minima() []Minimum { return []Minimum{ { X: []float64{-0.01572508644590686, 1.012434869244884, -0.23299162372002916, 1.2604300800978554, -1.51372891341701, 0.9929964286340117}, F: 0.0022876700535523838, Global: true, }, { X: []float64{-1.5307036521992127e-05, 0.9997897039319495, 0.01476396369355022, 0.14634232829939883, 1.0008211030046426, -2.617731140519101, 4.104403164479245, -3.1436122785568514, 1.0526264080103074}, F: 1.399760138096796e-06, Global: true, }, // TODO(vladimir-ch): More, Garbow, Hillstrom list just the value, but // not the location. Our minimizers find a minimum, but the value is // different. // { // // For dim == 12 // F: 4.72238e-10, // Global: true, // }, // TODO(vladimir-ch): netlib/uncon report a value of 2.48631d-20 for dim == 20. } } // Wood implements the Wood's function. // // Standard starting point: // // [-3, -1, -3, -1] // // References: // - Colville, A.R.: A comparative study of nonlinear programming codes. // Report 320-2949, IBM New York Scientific Center (1968) // - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained // optimization software. ACM Trans Math Softw 7 (1981), 17-41 type Wood struct{} func (Wood) Func(x []float64) (sum float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } f1 := x[1] - x[0]*x[0] f2 := 1 - x[0] f3 := x[3] - x[2]*x[2] f4 := 1 - x[2] f5 := x[1] + x[3] - 2 f6 := x[1] - x[3] return 100*f1*f1 + f2*f2 + 90*f3*f3 + f4*f4 + 10*f5*f5 + 0.1*f6*f6 } func (Wood) Grad(grad, x []float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } if len(x) != len(grad) { panic("incorrect size of the gradient") } f1 := x[1] - x[0]*x[0] f2 := 1 - x[0] f3 := x[3] - x[2]*x[2] f4 := 1 - x[2] f5 := x[1] + x[3] - 2 f6 := x[1] - x[3] grad[0] = -2 * (200*f1*x[0] + f2) grad[1] = 2 * (100*f1 + 10*f5 + 0.1*f6) grad[2] = -2 * (180*f3*x[2] + f4) grad[3] = 2 * (90*f3 + 10*f5 - 0.1*f6) } func (Wood) Hess(dst *mat.SymDense, x []float64) { if len(x) != 4 { panic("dimension of the problem must be 4") } if len(x) != dst.SymmetricDim() { panic("incorrect size of the Hessian") } dst.SetSym(0, 0, 400*(3*x[0]*x[0]-x[1])+2) dst.SetSym(0, 1, -400*x[0]) dst.SetSym(1, 1, 220.2) dst.SetSym(0, 2, 0) dst.SetSym(1, 2, 0) dst.SetSym(2, 2, 360*(3*x[2]*x[2]-x[3])+2) dst.SetSym(0, 3, 0) dst.SetSym(1, 3, 19.8) dst.SetSym(2, 3, -360*x[2]) dst.SetSym(3, 3, 200.2) } func (Wood) Minima() []Minimum { return []Minimum{ { X: []float64{1, 1, 1, 1}, F: 0, Global: true, }, } } // ConcaveRight implements an univariate function that is concave to the right // of the minimizer which is located at x=sqrt(2). // // References: // // More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease. // ACM Transactions on Mathematical Software 20(3) (1994), 286–307, eq. (5.1) type ConcaveRight struct{} func (ConcaveRight) Func(x []float64) float64 { if len(x) != 1 { panic("dimension of the problem must be 1") } return -x[0] / (x[0]*x[0] + 2) } func (ConcaveRight) Grad(grad, x []float64) { if len(x) != 1 { panic("dimension of the problem must be 1") } if len(x) != len(grad) { panic("incorrect size of the gradient") } xSqr := x[0] * x[0] grad[0] = (xSqr - 2) / (xSqr + 2) / (xSqr + 2) } // ConcaveLeft implements an univariate function that is concave to the left of // the minimizer which is located at x=399/250=1.596. // // References: // // More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease. // ACM Transactions on Mathematical Software 20(3) (1994), 286–307, eq. (5.2) type ConcaveLeft struct{} func (ConcaveLeft) Func(x []float64) float64 { if len(x) != 1 { panic("dimension of the problem must be 1") } return math.Pow(x[0]+0.004, 4) * (x[0] - 1.996) } func (ConcaveLeft) Grad(grad, x []float64) { if len(x) != 1 { panic("dimension of the problem must be 1") } if len(x) != len(grad) { panic("incorrect size of the gradient") } grad[0] = math.Pow(x[0]+0.004, 3) * (5*x[0] - 7.98) } // Plassmann implements an univariate oscillatory function where the value of L // controls the number of oscillations. The value of Beta controls the size of // the derivative at zero and the size of the interval where the strong Wolfe // conditions can hold. For small values of Beta this function represents a // difficult test problem for linesearchers also because the information based // on the derivative is unreliable due to the oscillations. // // References: // // More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease. // ACM Transactions on Mathematical Software 20(3) (1994), 286–307, eq. (5.3) type Plassmann struct { L float64 // Number of oscillations for |x-1| ≥ Beta. Beta float64 // Size of the derivative at zero, f'(0) = -Beta. } func (f Plassmann) Func(x []float64) float64 { if len(x) != 1 { panic("dimension of the problem must be 1") } a := x[0] b := f.Beta l := f.L r := 2 * (1 - b) / l / math.Pi * math.Sin(l*math.Pi/2*a) switch { case a <= 1-b: r += 1 - a case 1-b < a && a <= 1+b: r += 0.5 * ((a-1)*(a-1)/b + b) default: // a > 1+b r += a - 1 } return r } func (f Plassmann) Grad(grad, x []float64) { if len(x) != 1 { panic("dimension of the problem must be 1") } if len(x) != len(grad) { panic("incorrect size of the gradient") } a := x[0] b := f.Beta l := f.L grad[0] = (1 - b) * math.Cos(l*math.Pi/2*a) switch { case a <= 1-b: grad[0]-- case 1-b < a && a <= 1+b: grad[0] += (a - 1) / b default: // a > 1+b grad[0]++ } } // YanaiOzawaKaneko is an univariate convex function where the values of Beta1 // and Beta2 control the curvature around the minimum. Far away from the // minimum the function approximates an absolute value function. Near the // minimum, the function can either be sharply curved or flat, controlled by // the parameter values. // // References: // - More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease. // ACM Transactions on Mathematical Software 20(3) (1994), 286–307, eq. (5.4) // - Yanai, H., Ozawa, M., and Kaneko, S.: Interpolation methods in one dimensional // optimization. Computing 27 (1981), 155–163 type YanaiOzawaKaneko struct { Beta1 float64 Beta2 float64 } func (f YanaiOzawaKaneko) Func(x []float64) float64 { if len(x) != 1 { panic("dimension of the problem must be 1") } a := x[0] b1 := f.Beta1 b2 := f.Beta2 g1 := math.Sqrt(1+b1*b1) - b1 g2 := math.Sqrt(1+b2*b2) - b2 return g1*math.Sqrt((a-1)*(a-1)+b2*b2) + g2*math.Sqrt(a*a+b1*b1) } func (f YanaiOzawaKaneko) Grad(grad, x []float64) { if len(x) != 1 { panic("dimension of the problem must be 1") } if len(x) != len(grad) { panic("incorrect size of the gradient") } a := x[0] b1 := f.Beta1 b2 := f.Beta2 g1 := math.Sqrt(1+b1*b1) - b1 g2 := math.Sqrt(1+b2*b2) - b2 grad[0] = g1*(a-1)/math.Sqrt(b2*b2+(a-1)*(a-1)) + g2*a/math.Sqrt(b1*b1+a*a) } golang-gonum-v1-gonum-0.14.0/optimize/functions/functions_test.go000066400000000000000000000206051450372207100251070ustar00rootroot00000000000000// 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 functions import "testing" func TestBeale(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 1}, F: 14.203125, Gradient: []float64{0, 27.75}, }, { X: []float64{1, 4}, F: 4624.453125, Gradient: []float64{8813.25, 6585}, }, } testFunction(Beale{}, tests, t) } func TestBiggsEXP2(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 2}, F: 32.26255055084012, Gradient: []float64{8.308203800550878, -25.32607145221645}, }, } testFunction(BiggsEXP2{}, tests, t) } func TestBiggsEXP3(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 2, 1}, F: 1.598844540607779, Gradient: []float64{1.0633795027631927, -0.5196392672262664, -0.3180919155433357}, }, } testFunction(BiggsEXP3{}, tests, t) } func TestBiggsEXP4(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 2, 1, 1}, F: 1.598844540607779, Gradient: []float64{1.0633795027631927, -0.5196392672262664, -0.44245622408151464, -0.3180919155433357}, }, } testFunction(BiggsEXP4{}, tests, t) } func TestBiggsEXP5(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 2, 1, 1, 1}, F: 13.386420552801937, Gradient: []float64{-6.54665204477596, 3.5259856535515293, 14.36984212995392, -9.522506150695783, -19.639956134327882}, }, } testFunction(BiggsEXP5{}, tests, t) } func TestBiggsEXP6(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 2, 1, 1, 1, 1}, F: 0.77907007565597, Gradient: []float64{-0.149371887533426, -0.183163468182936, -1.483958013575642, 1.428277503849742, -0.149371887533426, -1.483958013575642}, }, } testFunction(BiggsEXP6{}, tests, t) } func TestBox3D(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{0, 10, 20}, F: 1031.1538106093985, Gradient: []float64{98.22343149849218, -2.11937420675874, 112.38817362220350}, }, } testFunction(Box3D{}, tests, t) } func TestBrownBadlyScaled(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 1}, F: 999998000003, Gradient: []float64{-2e+6, -4e-6}, }, } testFunction(BrownBadlyScaled{}, tests, t) } // TODO(vladimir-ch): The minimum of BrownAndDennis is not known accurately // enough, which would force defaultGradTol to be unnecessarily large for the // tests to pass. This is the only function that causes problems, so disable // this test until the minimum is more accurate. // func TestBrownAndDennis(t *testing.T) { // tests := []funcTest{ // { // X: []float64{25, 5, -5, -1}, // F: 7926693.33699744, // Gradient: []float64{1149322.836365895, 1779291.674339785, -254579.585463521, -173400.429253115}, // }, // } // testFunction(BrownAndDennis{}, tests, t) // } func TestExtendedPowellSingular(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{3, -1, 0, 3}, F: 95, Gradient: []float64{-14, -144, -22, 30}, }, { X: []float64{3, -1, 0, 3, 3, -1, 0, 3}, F: 190, Gradient: []float64{-14, -144, -22, 30, -14, -144, -22, 30}, }, } testFunction(ExtendedPowellSingular{}, tests, t) } func TestExtendedRosenbrock(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{-1.2, 1}, F: 24.2, Gradient: []float64{-215.6, -88}, }, { X: []float64{-1.2, 1, -1.2}, F: 508.2, Gradient: []float64{-215.6, 792, -440}, }, { X: []float64{-1.2, 1, -1.2, 1}, F: 532.4, Gradient: []float64{-215.6, 792, -655.6, -88}, }, } testFunction(ExtendedRosenbrock{}, tests, t) } func TestGaussian(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{0.4, 1, 0}, F: 3.88810699116688e-06, Gradient: []float64{7.41428466839991e-03, -7.44126392165149e-04, -5.30189685421989e-20}, }, } testFunction(Gaussian{}, tests, t) } func TestGulfResearchAndDevelopment(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{5, 2.5, 0.15}, F: 12.11070582556949, Gradient: []float64{2.0879783574289799, 0.0345792619697154, -39.6766801029386400}, }, } testFunction(GulfResearchAndDevelopment{}, tests, t) } func TestHelicalValley(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{-1, 0, 0}, F: 2500, Gradient: []float64{0, -1.59154943091895e+03, -1e+03}, }, } testFunction(HelicalValley{}, tests, t) } func TestPenaltyI(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{1, 2, 3, 4}, F: 885.06264, Gradient: []float64{119, 238.00002, 357.00004, 476.00006}, }, { X: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, F: 148032.56535, Gradient: []float64{1539, 3078.00002, 4617.00004, 6156.00006, 7695.00008, 9234.0001, 10773.00012, 12312.00014, 13851.00016, 15390.00018}, }, } testFunction(PenaltyI{}, tests, t) } func TestPenaltyII(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{0.5, 0.5, 0.5, 0.5}, F: 2.34000880546302, Gradient: []float64{12.59999952896435, 8.99999885134508, 5.99999776830493, 2.99999875380719}, }, { X: []float64{0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5}, F: 162.65277656596712, Gradient: []float64{255.5999995289644, 229.4999988513451, 203.9999977683049, 178.4999965713605, 152.9999952485322, 127.4999937865809, 101.9999921708749, 76.4999903852436, 50.9999884118158, 25.4999938418451}, }, } testFunction(PenaltyII{}, tests, t) } func TestPowelBadlyScaled(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{0, 1}, F: 1.13526171734838, Gradient: []float64{-2.00007355588823e+04, -2.70596990584991e-01}, }, } testFunction(PowellBadlyScaled{}, tests, t) } func TestTrigonometric(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{0.5, 0.5}, F: 0.0126877761614045, Gradient: []float64{-0.00840962732040673, -0.09606967736232540}, }, { X: []float64{0.2, 0.2, 0.2, 0.2, 0.2}, F: 0.0116573789904718, Gradient: []float64{0.04568602319608119, -0.00896259022885634, -0.04777056509084983, -0.07073790138989976, -0.07786459912600564}, }, { X: []float64{0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1}, F: 0.00707575946622261, Gradient: []float64{0.03562782195259399, 0.01872017956076182, 0.00380754216611998, -0.00911009023133202, -0.02003271763159338, -0.02896034003466506, -0.03589295744054654, -0.04083056984923782, -0.04377317726073873, -0.04472077967504980}, }, } testFunction(Trigonometric{}, tests, t) } func TestVariablyDimensioned(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{0.5, 0}, F: 46.5625, Gradient: []float64{-68.5, -137}, }, { X: []float64{2.0 / 3, 1.0 / 3, 0}, F: 497.60493827160514, Gradient: []float64{-416.518518518519, -833.037037037037, -1249.555555555556}, }, { X: []float64{0.75, 0.5, 0.25, 0}, F: 3222.1875, Gradient: []float64{-1703, -3406, -5109, -6812}, }, } testFunction(VariablyDimensioned{}, tests, t) } func TestWatson(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{0, 0}, F: 30, Gradient: []float64{0, -60}, }, { X: []float64{0, 0, 0, 0, 0, 0}, F: 30, Gradient: []float64{0, -60, -60, -61.034482758620697, -62.068965517241381, -63.114928861371936}, }, { X: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0}, F: 30, Gradient: []float64{0, -60, -60, -61.034482758620697, -62.068965517241381, -63.114928861371936, -64.172372791012350, -65.241283655050239, -66.321647802373235}, }, { X: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, F: 30, Gradient: []float64{0, -60, -60, -61.034482758620697, -62.068965517241381, -63.114928861371936, -64.172372791012350, -65.241283655050239, -66.321647802373235, -67.413448880864095, -68.516667837400661, -69.631282933991471}, }, } testFunction(Watson{}, tests, t) } func TestWood(t *testing.T) { t.Parallel() tests := []funcTest{ { X: []float64{-3, -1, -3, -1}, F: 19192, Gradient: []float64{-12008, -2080, -10808, -1880}, }, } testFunction(Wood{}, tests, t) } golang-gonum-v1-gonum-0.14.0/optimize/functions/minsurf.go000066400000000000000000000155271450372207100235320ustar00rootroot00000000000000// 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 functions import ( "fmt" "math" ) // MinimalSurface implements a finite element approximation to a minimal // surface problem: determine the surface with minimal area and given boundary // values in a unit square centered at the origin. // // References: // // Averick, M.B., Carter, R.G., Moré, J.J., Xue, G.-L.: The Minpack-2 Test // Problem Collection. Preprint MCS-P153-0692, Argonne National Laboratory (1992) type MinimalSurface struct { bottom, top []float64 left, right []float64 origin, step [2]float64 } // NewMinimalSurface creates a new discrete minimal surface problem and // precomputes its boundary values. The problem is discretized on a rectilinear // grid with nx×ny nodes which means that the problem dimension is (nx-2)(ny-2). func NewMinimalSurface(nx, ny int) *MinimalSurface { ms := &MinimalSurface{ bottom: make([]float64, nx), top: make([]float64, nx), left: make([]float64, ny), right: make([]float64, ny), origin: [2]float64{-0.5, -0.5}, step: [2]float64{1 / float64(nx-1), 1 / float64(ny-1)}, } ms.initBoundary(ms.bottom, ms.origin[0], ms.origin[1], ms.step[0], 0) startY := ms.origin[1] + float64(ny-1)*ms.step[1] ms.initBoundary(ms.top, ms.origin[0], startY, ms.step[0], 0) ms.initBoundary(ms.left, ms.origin[0], ms.origin[1], 0, ms.step[1]) startX := ms.origin[0] + float64(nx-1)*ms.step[0] ms.initBoundary(ms.right, startX, ms.origin[1], 0, ms.step[1]) return ms } // Func returns the area of the surface represented by the vector x. func (ms *MinimalSurface) Func(x []float64) (area float64) { nx, ny := ms.Dims() if len(x) != (nx-2)*(ny-2) { panic("functions: problem size mismatch") } hx, hy := ms.Steps() for j := 0; j < ny-1; j++ { for i := 0; i < nx-1; i++ { vLL := ms.at(i, j, x) vLR := ms.at(i+1, j, x) vUL := ms.at(i, j+1, x) vUR := ms.at(i+1, j+1, x) dvLdx := (vLR - vLL) / hx dvLdy := (vUL - vLL) / hy dvUdx := (vUR - vUL) / hx dvUdy := (vUR - vLR) / hy fL := math.Sqrt(1 + dvLdx*dvLdx + dvLdy*dvLdy) fU := math.Sqrt(1 + dvUdx*dvUdx + dvUdy*dvUdy) area += fL + fU } } area *= 0.5 * hx * hy return area } // Grad evaluates the area gradient of the surface represented by the vector. func (ms *MinimalSurface) Grad(grad, x []float64) []float64 { nx, ny := ms.Dims() if len(x) != (nx-2)*(ny-2) { panic("functions: problem size mismatch") } if grad == nil { grad = make([]float64, len(x)) } if len(x) != len(grad) { panic("functions: unexpected size mismatch") } for i := range grad { grad[i] = 0 } hx, hy := ms.Steps() for j := 0; j < ny-1; j++ { for i := 0; i < nx-1; i++ { vLL := ms.at(i, j, x) vLR := ms.at(i+1, j, x) vUL := ms.at(i, j+1, x) vUR := ms.at(i+1, j+1, x) dvLdx := (vLR - vLL) / hx dvLdy := (vUL - vLL) / hy dvUdx := (vUR - vUL) / hx dvUdy := (vUR - vLR) / hy fL := math.Sqrt(1 + dvLdx*dvLdx + dvLdy*dvLdy) fU := math.Sqrt(1 + dvUdx*dvUdx + dvUdy*dvUdy) if grad != nil { if i > 0 { if j > 0 { grad[ms.index(i, j)] -= (dvLdx/hx + dvLdy/hy) / fL } if j < ny-2 { grad[ms.index(i, j+1)] += (dvLdy/hy)/fL - (dvUdx/hx)/fU } } if i < nx-2 { if j > 0 { grad[ms.index(i+1, j)] += (dvLdx/hx)/fL - (dvUdy/hy)/fU } if j < ny-2 { grad[ms.index(i+1, j+1)] += (dvUdx/hx + dvUdy/hy) / fU } } } } } cellSize := 0.5 * hx * hy for i := range grad { grad[i] *= cellSize } return grad } // InitX returns a starting location for the minimization problem. Length of // the returned slice is (nx-2)(ny-2). func (ms *MinimalSurface) InitX() []float64 { nx, ny := ms.Dims() x := make([]float64, (nx-2)*(ny-2)) for j := 1; j < ny-1; j++ { for i := 1; i < nx-1; i++ { x[ms.index(i, j)] = (ms.left[j] + ms.bottom[i]) / 2 } } return x } // ExactX returns the exact solution to the _continuous_ minimization problem // projected on the interior nodes of the grid. Length of the returned slice is // (nx-2)(ny-2). func (ms *MinimalSurface) ExactX() []float64 { nx, ny := ms.Dims() v := make([]float64, (nx-2)*(ny-2)) for j := 1; j < ny-1; j++ { for i := 1; i < nx-1; i++ { v[ms.index(i, j)] = ms.ExactSolution(ms.x(i), ms.y(j)) } } return v } // ExactSolution returns the value of the exact solution to the minimal surface // problem at (x,y). The exact solution is // // F_exact(x,y) = U^2(x,y) - V^2(x,y), // // where U and V are the unique solutions to the equations // // x = u + uv^2 - u^3/3, // y = -v - u^2v + v^3/3. func (ms *MinimalSurface) ExactSolution(x, y float64) float64 { var u = [2]float64{x, -y} var f [2]float64 var jac [2][2]float64 for k := 0; k < 100; k++ { f[0] = u[0] + u[0]*u[1]*u[1] - u[0]*u[0]*u[0]/3 - x f[1] = -u[1] - u[0]*u[0]*u[1] + u[1]*u[1]*u[1]/3 - y fNorm := math.Hypot(f[0], f[1]) if fNorm < 1e-13 { break } jac[0][0] = 1 + u[1]*u[1] - u[0]*u[0] jac[0][1] = 2 * u[0] * u[1] jac[1][0] = -2 * u[0] * u[1] jac[1][1] = -1 - u[0]*u[0] + u[1]*u[1] det := jac[0][0]*jac[1][1] - jac[0][1]*jac[1][0] u[0] -= (jac[1][1]*f[0] - jac[0][1]*f[1]) / det u[1] -= (jac[0][0]*f[1] - jac[1][0]*f[0]) / det } return u[0]*u[0] - u[1]*u[1] } // Dims returns the size of the underlying rectilinear grid. func (ms *MinimalSurface) Dims() (nx, ny int) { return len(ms.bottom), len(ms.left) } // Steps returns the spatial step sizes of the underlying rectilinear grid. func (ms *MinimalSurface) Steps() (hx, hy float64) { return ms.step[0], ms.step[1] } func (ms *MinimalSurface) x(i int) float64 { return ms.origin[0] + float64(i)*ms.step[0] } func (ms *MinimalSurface) y(j int) float64 { return ms.origin[1] + float64(j)*ms.step[1] } func (ms *MinimalSurface) at(i, j int, x []float64) float64 { nx, ny := ms.Dims() if i < 0 || i >= nx { panic(fmt.Sprintf("node [%v,%v] not on grid", i, j)) } if j < 0 || j >= ny { panic(fmt.Sprintf("node [%v,%v] not on grid", i, j)) } if i == 0 { return ms.left[j] } if j == 0 { return ms.bottom[i] } if i == nx-1 { return ms.right[j] } if j == ny-1 { return ms.top[i] } return x[ms.index(i, j)] } // index maps an interior grid node (i, j) to a one-dimensional index and // returns it. func (ms *MinimalSurface) index(i, j int) int { nx, ny := ms.Dims() if i <= 0 || i >= nx-1 { panic(fmt.Sprintf("[%v,%v] is not an interior node", i, j)) } if j <= 0 || j >= ny-1 { panic(fmt.Sprintf("[%v,%v] is not an interior node", i, j)) } return i - 1 + (j-1)*(nx-2) } // initBoundary initializes with the exact solution the boundary b whose i-th // element b[i] is located at [startX+i×hx, startY+i×hy]. func (ms *MinimalSurface) initBoundary(b []float64, startX, startY, hx, hy float64) { for i := range b { x := startX + float64(i)*hx y := startY + float64(i)*hy b[i] = ms.ExactSolution(x, y) } } golang-gonum-v1-gonum-0.14.0/optimize/functions/minsurf_test.go000066400000000000000000000026561450372207100245700ustar00rootroot00000000000000// 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 functions import ( "math" "testing" "gonum.org/v1/gonum/diff/fd" "gonum.org/v1/gonum/floats" ) func TestMinimalSurface(t *testing.T) { t.Parallel() for _, size := range [][2]int{ {20, 30}, {30, 30}, {50, 40}, } { f := NewMinimalSurface(size[0], size[1]) x0 := f.InitX() grad := make([]float64, len(x0)) f.Grad(grad, x0) fdGrad := fd.Gradient(nil, f.Func, x0, &fd.Settings{Formula: fd.Central}) // Test that the numerical and analytical gradients agree. dist := floats.Distance(grad, fdGrad, math.Inf(1)) if dist > 1e-9 { t.Errorf("grid %v x %v: numerical and analytical gradient do not match. |fdGrad - grad|_∞ = %v", size[0], size[1], dist) } // Test that the gradient at the minimum is small enough. // In some sense this test is not completely correct because ExactX // returns the exact solution to the continuous problem projected on the // grid, not the exact solution to the discrete problem which we are // solving. This is the reason why a relatively loose tolerance 1e-4 // must be used. xSol := f.ExactX() f.Grad(grad, xSol) norm := floats.Norm(grad, math.Inf(1)) if norm > 1e-4 { t.Errorf("grid %v x %v: gradient at the minimum not small enough. |grad|_∞ = %v", size[0], size[1], norm) } } } golang-gonum-v1-gonum-0.14.0/optimize/functions/validate.go000066400000000000000000000064061450372207100236340ustar00rootroot00000000000000// 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 functions import ( "math" "testing" "gonum.org/v1/gonum/diff/fd" "gonum.org/v1/gonum/floats" ) // function represents an objective function. type function interface { Func(x []float64) float64 } type gradient interface { Grad(grad, x []float64) []float64 } // minimumer is an objective function that can also provide information about // its minima. type minimumer interface { function // Minima returns _known_ minima of the function. Minima() []Minimum } // Minimum represents information about an optimal location of a function. type Minimum struct { // X is the location of the minimum. X may not be nil. X []float64 // F is the value of the objective function at X. F float64 // Global indicates if the location is a global minimum. Global bool } type funcTest struct { X []float64 // F is the expected function value at X. F float64 // Gradient is the expected gradient at X. If nil, it is not evaluated. Gradient []float64 } // TODO(vladimir-ch): Decide and implement an exported testing function: // func Test(f Function, ??? ) ??? { // } const ( defaultTol = 1e-12 defaultGradTol = 1e-9 defaultFDGradTol = 1e-5 ) // testFunction checks that the function can evaluate itself (and its gradient) // correctly. func testFunction(f function, ftests []funcTest, t *testing.T) { // Make a copy of tests because we may append to the slice. tests := make([]funcTest, len(ftests)) copy(tests, ftests) // Get information about the function. fMinima, isMinimumer := f.(minimumer) fGradient, isGradient := f.(gradient) // If the function is a Minimumer, append its minima to the tests. if isMinimumer { for _, minimum := range fMinima.Minima() { // Allocate gradient only if the function can evaluate it. var grad []float64 if isGradient { grad = make([]float64, len(minimum.X)) } tests = append(tests, funcTest{ X: minimum.X, F: minimum.F, Gradient: grad, }) } } for i, test := range tests { F := f.Func(test.X) // Check that the function value is as expected. if math.Abs(F-test.F) > defaultTol { t.Errorf("Test #%d: function value given by Func is incorrect. Want: %v, Got: %v", i, test.F, F) } if test.Gradient == nil { continue } // Evaluate the finite difference gradient. fdGrad := fd.Gradient(nil, f.Func, test.X, &fd.Settings{ Formula: fd.Central, Step: 1e-6, }) // Check that the finite difference and expected gradients match. if !floats.EqualApprox(fdGrad, test.Gradient, defaultFDGradTol) { dist := floats.Distance(fdGrad, test.Gradient, math.Inf(1)) t.Errorf("Test #%d: numerical and expected gradients do not match. |fdGrad - WantGrad|_∞ = %v", i, dist) } // If the function is a Gradient, check that it computes the gradient correctly. if isGradient { grad := make([]float64, len(test.Gradient)) fGradient.Grad(grad, test.X) if !floats.EqualApprox(grad, test.Gradient, defaultGradTol) { dist := floats.Distance(grad, test.Gradient, math.Inf(1)) t.Errorf("Test #%d: gradient given by Grad is incorrect. |grad - WantGrad|_∞ = %v", i, dist) } } } } golang-gonum-v1-gonum-0.14.0/optimize/functions/vlse.go000066400000000000000000000310361450372207100230110ustar00rootroot00000000000000// 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 functions import "math" // This file implements functions from the Virtual Library of Simulation Experiments. // https://www.sfu.ca/~ssurjano/optimization.html // In many cases gradients and Hessians have been added. In some cases, these // are not defined at certain points or manifolds. The gradient in these locations // has been set to 0. // Ackley implements the Ackley function, a function of arbitrary dimension that // has many local minima. It has a single global minimum of 0 at 0. Its typical // domain is the hypercube of [-32.768, 32.768]^d. // // f(x) = -20 * exp(-0.2 sqrt(1/d sum_i x_i^2)) - exp(1/d sum_i cos(2π x_i)) + 20 + exp(1) // // where d is the input dimension. // // Reference: // // https://www.sfu.ca/~ssurjano/ackley.html (obtained June 2017) type Ackley struct{} func (Ackley) Func(x []float64) float64 { var ss, sc float64 for _, v := range x { ss += v * v sc += math.Cos(2 * math.Pi * v) } id := 1 / float64(len(x)) return -20*math.Exp(-0.2*math.Sqrt(id*ss)) - math.Exp(id*sc) + 20 + math.E } // Bukin6 implements Bukin's 6th function. The function is two-dimensional, with // the typical domain as x_0 ∈ [-15, -5], x_1 ∈ [-3, 3]. The function has a unique // global minimum at [-10, 1], and many local minima. // // f(x) = 100 * sqrt(|x_1 - 0.01*x_0^2|) + 0.01*|x_0+10| // // Reference: // // https://www.sfu.ca/~ssurjano/bukin6.html (obtained June 2017) type Bukin6 struct{} func (Bukin6) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } return 100*math.Sqrt(math.Abs(x[1]-0.01*x[0]*x[0])) + 0.01*math.Abs(x[0]+10) } // CamelThree implements the three-hump camel function, a two-dimensional function // with three local minima, one of which is global. // The function is given by // // f(x) = 2*x_0^2 - 1.05*x_0^4 + x_0^6/6 + x_0*x_1 + x_1^2 // // with the global minimum at // // x^* = (0, 0) // f(x^*) = 0 // // The typical domain is x_i ∈ [-5, 5] for all i. // Reference: // // https://www.sfu.ca/~ssurjano/camel3.html (obtained December 2017) type CamelThree struct{} func (c CamelThree) Func(x []float64) float64 { if len(x) != 2 { panic("camelthree: dimension must be 2") } x0 := x[0] x1 := x[1] x02 := x0 * x0 x04 := x02 * x02 return 2*x02 - 1.05*x04 + x04*x02/6 + x0*x1 + x1*x1 } // CamelSix implements the six-hump camel function, a two-dimensional function. // with six local minima, two of which are global. // The function is given by // // f(x) = (4 - 2.1*x_0^2 + x_0^4/3)*x_0^2 + x_0*x_1 + (-4 + 4*x_1^2)*x_1^2 // // with the global minima at // // x^* = (0.0898, -0.7126), (-0.0898, 0.7126) // f(x^*) = -1.0316 // // The typical domain is x_0 ∈ [-3, 3], x_1 ∈ [-2, 2]. // Reference: // // https://www.sfu.ca/~ssurjano/camel6.html (obtained December 2017) type CamelSix struct{} func (c CamelSix) Func(x []float64) float64 { if len(x) != 2 { panic("camelsix: dimension must be 2") } x0 := x[0] x1 := x[1] x02 := x0 * x0 x12 := x1 * x1 return (4-2.1*x02+x02*x02/3)*x02 + x0*x1 + (-4+4*x12)*x12 } // CrossInTray implements the cross-in-tray function. The cross-in-tray function // is a two-dimensional function with many local minima, and four global minima // at (±1.3491, ±1.3491). The function is typically evaluated in the square // [-10,10]^2. // // f(x) = -0.001(|sin(x_0)sin(x_1)exp(|100-sqrt((x_0^2+x_1^2)/π)|)|+1)^0.1 // // Reference: // // https://www.sfu.ca/~ssurjano/crossit.html (obtained June 2017) type CrossInTray struct{} func (CrossInTray) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] exp := math.Abs(100 - math.Sqrt((x0*x0+x1*x1)/math.Pi)) return -0.0001 * math.Pow(math.Abs(math.Sin(x0)*math.Sin(x1)*math.Exp(exp))+1, 0.1) } // DixonPrice implements the DixonPrice function, a function of arbitrary dimension // Its typical domain is the hypercube of [-10, 10]^d. // The function is given by // // f(x) = (x_0-1)^2 + \sum_{i=1}^{d-1} (i+1) * (2*x_i^2-x_{i-1})^2 // // where d is the input dimension. There is a single global minimum, which has // a location and value of // // x_i^* = 2^{-(2^{i+1}-2)/(2^{i+1})} for i = 0, ..., d-1. // f(x^*) = 0 // // Reference: // // https://www.sfu.ca/~ssurjano/dixonpr.html (obtained June 2017) type DixonPrice struct{} func (DixonPrice) Func(x []float64) float64 { xp := x[0] v := (xp - 1) * (xp - 1) for i := 1; i < len(x); i++ { xn := x[i] tmp := (2*xn*xn - xp) v += float64(i+1) * tmp * tmp xp = xn } return v } // DropWave implements the drop-wave function, a two-dimensional function with // many local minima and one global minimum at 0. The function is typically evaluated // in the square [-5.12, 5.12]^2. // // f(x) = - (1+cos(12*sqrt(x0^2+x1^2))) / (0.5*(x0^2+x1^2)+2) // // Reference: // // https://www.sfu.ca/~ssurjano/drop.html (obtained June 2017) type DropWave struct{} func (DropWave) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] num := 1 + math.Cos(12*math.Sqrt(x0*x0+x1*x1)) den := 0.5*(x0*x0+x1*x1) + 2 return -num / den } // Eggholder implements the Eggholder function, a two-dimensional function with // many local minima and one global minimum at [512, 404.2319]. The function // is typically evaluated in the square [-512, 512]^2. // // f(x) = -(x_1+47)*sin(sqrt(|x_1+x_0/2+47|))-x_1*sin(sqrt(|x_0-(x_1+47)|)) // // Reference: // // https://www.sfu.ca/~ssurjano/egg.html (obtained June 2017) type Eggholder struct{} func (Eggholder) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] return -(x1+47)*math.Sin(math.Sqrt(math.Abs(x1+x0/2+47))) - x0*math.Sin(math.Sqrt(math.Abs(x0-x1-47))) } // GramacyLee implements the Gramacy-Lee function, a one-dimensional function // with many local minima. The function is typically evaluated on the domain [0.5, 2.5]. // // f(x) = sin(10πx)/(2x) + (x-1)^4 // // Reference: // // https://www.sfu.ca/~ssurjano/grlee12.html (obtained June 2017) type GramacyLee struct{} func (GramacyLee) Func(x []float64) float64 { if len(x) != 1 { panic(badInputDim) } x0 := x[0] return math.Sin(10*math.Pi*x0)/(2*x0) + math.Pow(x0-1, 4) } // Griewank implements the Griewank function, a function of arbitrary dimension that // has many local minima. It has a single global minimum of 0 at 0. Its typical // domain is the hypercube of [-600, 600]^d. // // f(x) = \sum_i x_i^2/4000 - \prod_i cos(x_i/sqrt(i)) + 1 // // where d is the input dimension. // // Reference: // // https://www.sfu.ca/~ssurjano/griewank.html (obtained June 2017) type Griewank struct{} func (Griewank) Func(x []float64) float64 { var ss float64 pc := 1.0 for i, v := range x { ss += v * v pc *= math.Cos(v / math.Sqrt(float64(i+1))) } return ss/4000 - pc + 1 } // HolderTable implements the Holder table function. The Holder table function // is a two-dimensional function with many local minima, and four global minima // at (±8.05502, ±9.66459). The function is typically evaluated in the square [-10,10]^2. // // f(x) = -|sin(x_0)cos(x1)exp(|1-sqrt(x_0^2+x1^2)/π|)| // // Reference: // // https://www.sfu.ca/~ssurjano/holder.html (obtained June 2017) type HolderTable struct{} func (HolderTable) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] return -math.Abs(math.Sin(x0) * math.Cos(x1) * math.Exp(math.Abs(1-math.Sqrt(x0*x0+x1*x1)/math.Pi))) } // Langermann2 implements the two-dimensional version of the Langermann function. // The Langermann function has many local minima. The function is typically // evaluated in the square [0,10]^2. // // f(x) = \sum_1^5 c_i exp(-(1/π)\sum_{j=1}^2(x_j-A_{ij})^2) * cos(π\sum_{j=1}^2 (x_j - A_{ij})^2) // c = [5]float64{1,2,5,2,3} // A = [5][2]float64{{3,5},{5,2},{2,1},{1,4},{7,9}} // // Reference: // // https://www.sfu.ca/~ssurjano/langer.html (obtained June 2017) type Langermann2 struct{} func (Langermann2) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } var ( c = [5]float64{1, 2, 5, 2, 3} A = [5][2]float64{{3, 5}, {5, 2}, {2, 1}, {1, 4}, {7, 9}} ) var f float64 for i, cv := range c { var ss float64 for j, av := range A[i] { xja := x[j] - av ss += xja * xja } f += cv * math.Exp(-(1/math.Pi)*ss) * math.Cos(math.Pi*ss) } return f } // Levy implements the Levy function, a function of arbitrary dimension that // has many local minima. It has a single global minimum of 0 at 1. Its typical // domain is the hypercube of [-10, 10]^d. // // f(x) = sin^2(π*w_0) + \sum_{i=0}^{d-2}(w_i-1)^2*[1+10sin^2(π*w_i+1)] + // (w_{d-1}-1)^2*[1+sin^2(2π*w_{d-1})] // w_i = 1 + (x_i-1)/4 // // where d is the input dimension. // // Reference: // // https://www.sfu.ca/~ssurjano/levy.html (obtained June 2017) type Levy struct{} func (Levy) Func(x []float64) float64 { w1 := 1 + (x[0]-1)/4 s1 := math.Sin(math.Pi * w1) sum := s1 * s1 for i := 0; i < len(x)-1; i++ { wi := 1 + (x[i]-1)/4 s := math.Sin(math.Pi*wi + 1) sum += (wi - 1) * (wi - 1) * (1 + 10*s*s) } wd := 1 + (x[len(x)-1]-1)/4 sd := math.Sin(2 * math.Pi * wd) return sum + (wd-1)*(wd-1)*(1+sd*sd) } // Levy13 implements the Levy-13 function, a two-dimensional function // with many local minima. It has a single global minimum of 0 at 1. Its typical // domain is the square [-10, 10]^2. // // f(x) = sin^2(3π*x_0) + (x_0-1)^2*[1+sin^2(3π*x_1)] + (x_1-1)^2*[1+sin^2(2π*x_1)] // // Reference: // // https://www.sfu.ca/~ssurjano/levy13.html (obtained June 2017) type Levy13 struct{} func (Levy13) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] s0 := math.Sin(3 * math.Pi * x0) s1 := math.Sin(3 * math.Pi * x1) s2 := math.Sin(2 * math.Pi * x1) return s0*s0 + (x0-1)*(x0-1)*(1+s1*s1) + (x1-1)*(x1-1)*(1+s2*s2) } // Rastrigin implements the Rastrigen function, a function of arbitrary dimension // that has many local minima. It has a single global minimum of 0 at 0. Its typical // domain is the hypercube of [-5.12, 5.12]^d. // // f(x) = 10d + \sum_i [x_i^2 - 10cos(2π*x_i)] // // where d is the input dimension. // // Reference: // // https://www.sfu.ca/~ssurjano/rastr.html (obtained June 2017) type Rastrigin struct{} func (Rastrigin) Func(x []float64) float64 { sum := 10 * float64(len(x)) for _, v := range x { sum += v*v - 10*math.Cos(2*math.Pi*v) } return sum } // Schaffer2 implements the second Schaffer function, a two-dimensional function // with many local minima. It has a single global minimum of 0 at 0. Its typical // domain is the square [-100, 100]^2. // // f(x) = 0.5 + (sin^2(x_0^2-x_1^2)-0.5) / (1+0.001*(x_0^2+x_1^2))^2 // // Reference: // // https://www.sfu.ca/~ssurjano/schaffer2.html (obtained June 2017) type Schaffer2 struct{} func (Schaffer2) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] s := math.Sin(x0*x0 - x1*x1) den := 1 + 0.001*(x0*x0+x1*x1) return 0.5 + (s*s-0.5)/(den*den) } // Schaffer4 implements the fourth Schaffer function, a two-dimensional function // with many local minima. Its typical domain is the square [-100, 100]^2. // // f(x) = 0.5 + (cos(sin(|x_0^2-x_1^2|))-0.5) / (1+0.001*(x_0^2+x_1^2))^2 // // Reference: // // https://www.sfu.ca/~ssurjano/schaffer4.html (obtained June 2017) type Schaffer4 struct{} func (Schaffer4) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] den := 1 + 0.001*(x0*x0+x1*x1) return 0.5 + (math.Cos(math.Sin(math.Abs(x0*x0-x1*x1)))-0.5)/(den*den) } // Schwefel implements the Schwefel function, a function of arbitrary dimension // that has many local minima. Its typical domain is the hypercube of [-500, 500]^d. // // f(x) = 418.9829*d - \sum_i x_i*sin(sqrt(|x_i|)) // // where d is the input dimension. // // Reference: // // https://www.sfu.ca/~ssurjano/schwef.html (obtained June 2017) type Schwefel struct{} func (Schwefel) Func(x []float64) float64 { var sum float64 for _, v := range x { sum += v * math.Sin(math.Sqrt(math.Abs(v))) } return 418.9829*float64(len(x)) - sum } // Shubert implements the Shubert function, a two-dimensional function // with many local minima and many global minima. Its typical domain is the // square [-10, 10]^2. // // f(x) = (sum_{i=1}^5 i cos((i+1)*x_0+i)) * (\sum_{i=1}^5 i cos((i+1)*x_1+i)) // // Reference: // // https://www.sfu.ca/~ssurjano/shubert.html (obtained June 2017) type Shubert struct{} func (Shubert) Func(x []float64) float64 { if len(x) != 2 { panic(badInputDim) } x0 := x[0] x1 := x[1] var s0, s1 float64 for i := 1.0; i <= 5.0; i++ { s0 += i * math.Cos((i+1)*x0+i) s1 += i * math.Cos((i+1)*x1+i) } return s0 * s1 } golang-gonum-v1-gonum-0.14.0/optimize/gradientdescent.go000066400000000000000000000050051450372207100231700ustar00rootroot00000000000000// 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 optimize import "gonum.org/v1/gonum/floats" var ( _ Method = (*GradientDescent)(nil) _ localMethod = (*GradientDescent)(nil) _ NextDirectioner = (*GradientDescent)(nil) ) // GradientDescent implements the steepest descent optimization method that // performs successive steps along the direction of the negative gradient. type GradientDescent struct { // Linesearcher selects suitable steps along the descent direction. // If Linesearcher is nil, a reasonable default will be chosen. Linesearcher Linesearcher // StepSizer determines the initial step size along each direction. // If StepSizer is nil, a reasonable default will be chosen. StepSizer StepSizer // GradStopThreshold sets the threshold for stopping if the gradient norm // gets too small. If GradStopThreshold is 0 it is defaulted to 1e-12, and // if it is NaN the setting is not used. GradStopThreshold float64 ls *LinesearchMethod status Status err error } func (g *GradientDescent) Status() (Status, error) { return g.status, g.err } func (*GradientDescent) Uses(has Available) (uses Available, err error) { return has.gradient() } func (g *GradientDescent) Init(dim, tasks int) int { g.status = NotTerminated g.err = nil return 1 } func (g *GradientDescent) Run(operation chan<- Task, result <-chan Task, tasks []Task) { g.status, g.err = localOptimizer{}.run(g, g.GradStopThreshold, operation, result, tasks) close(operation) } func (g *GradientDescent) initLocal(loc *Location) (Operation, error) { if g.Linesearcher == nil { g.Linesearcher = &Backtracking{} } if g.StepSizer == nil { g.StepSizer = &QuadraticStepSize{} } if g.ls == nil { g.ls = &LinesearchMethod{} } g.ls.Linesearcher = g.Linesearcher g.ls.NextDirectioner = g return g.ls.Init(loc) } func (g *GradientDescent) iterateLocal(loc *Location) (Operation, error) { return g.ls.Iterate(loc) } func (g *GradientDescent) InitDirection(loc *Location, dir []float64) (stepSize float64) { copy(dir, loc.Gradient) floats.Scale(-1, dir) return g.StepSizer.Init(loc, dir) } func (g *GradientDescent) NextDirection(loc *Location, dir []float64) (stepSize float64) { copy(dir, loc.Gradient) floats.Scale(-1, dir) return g.StepSizer.StepSize(loc, dir) } func (*GradientDescent) needs() struct { Gradient bool Hessian bool } { return struct { Gradient bool Hessian bool }{true, false} } golang-gonum-v1-gonum-0.14.0/optimize/guessandcheck.go000066400000000000000000000037441450372207100226440ustar00rootroot00000000000000// Copyright ©2016 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 optimize import ( "math" "gonum.org/v1/gonum/stat/distmv" ) var _ Method = (*GuessAndCheck)(nil) // GuessAndCheck is a global optimizer that evaluates the function at random // locations. Not a good optimizer, but useful for comparison and debugging. type GuessAndCheck struct { Rander distmv.Rander bestF float64 bestX []float64 } func (*GuessAndCheck) Uses(has Available) (uses Available, err error) { return has.function() } func (g *GuessAndCheck) Init(dim, tasks int) int { if dim <= 0 { panic(nonpositiveDimension) } if tasks < 0 { panic(negativeTasks) } g.bestF = math.Inf(1) g.bestX = resize(g.bestX, dim) return tasks } func (g *GuessAndCheck) sendNewLoc(operation chan<- Task, task Task) { g.Rander.Rand(task.X) task.Op = FuncEvaluation operation <- task } func (g *GuessAndCheck) updateMajor(operation chan<- Task, task Task) { // Update the best value seen so far, and send a MajorIteration. if task.F < g.bestF { g.bestF = task.F copy(g.bestX, task.X) } else { task.F = g.bestF copy(task.X, g.bestX) } task.Op = MajorIteration operation <- task } func (g *GuessAndCheck) Run(operation chan<- Task, result <-chan Task, tasks []Task) { // Send initial tasks to evaluate for _, task := range tasks { g.sendNewLoc(operation, task) } // Read from the channel until PostIteration is sent. Loop: for { task := <-result switch task.Op { default: panic("unknown operation") case PostIteration: break Loop case MajorIteration: g.sendNewLoc(operation, task) case FuncEvaluation: g.updateMajor(operation, task) } } // PostIteration was sent. Update the best new values. for task := range result { switch task.Op { default: panic("unknown operation") case MajorIteration: case FuncEvaluation: g.updateMajor(operation, task) } } close(operation) } golang-gonum-v1-gonum-0.14.0/optimize/guessandcheck_test.go000066400000000000000000000021031450372207100236670ustar00rootroot00000000000000// Copyright ©2016 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 optimize import ( "testing" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/optimize/functions" "gonum.org/v1/gonum/stat/distmv" ) func TestGuessAndCheck(t *testing.T) { t.Parallel() dim := 30 problem := Problem{ Func: functions.ExtendedRosenbrock{}.Func, } mu := make([]float64, dim) sigma := mat.NewSymDense(dim, nil) for i := 0; i < dim; i++ { sigma.SetSym(i, i, 1) } d, ok := distmv.NewNormal(mu, sigma, nil) if !ok { panic("bad test") } initX := make([]float64, dim) _, err := Minimize(problem, initX, nil, &GuessAndCheck{Rander: d}) if err != nil { t.Errorf("unexpected error running Minimize with nil settings: %v", err) } settings := &Settings{} settings.Concurrent = 5 settings.MajorIterations = 15 _, err = Minimize(problem, initX, settings, &GuessAndCheck{Rander: d}) if err != nil { t.Errorf("unexpected error running Minimize with settings %+v: %v", settings, err) } } golang-gonum-v1-gonum-0.14.0/optimize/interfaces.go000066400000000000000000000142371450372207100221570ustar00rootroot00000000000000// 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 optimize // A localMethod can optimize an objective function. // // It uses a reverse-communication interface between the optimization method // and the caller. Method acts as a client that asks the caller to perform // needed operations via Operation returned from Init and Iterate methods. // This provides independence of the optimization algorithm on user-supplied // data and their representation, and enables automation of common operations // like checking for (various types of) convergence and maintaining statistics. // // A Method can command an Evaluation, a MajorIteration or NoOperation operations. // // An evaluation operation is one or more of the Evaluation operations // (FuncEvaluation, GradEvaluation, etc.) which can be combined with // the bitwise or operator. In an evaluation operation, the requested fields of // Problem will be evaluated at the point specified in Location.X. // The corresponding fields of Location will be filled with the results that // can be retrieved upon the next call to Iterate. The Method interface // requires that entries of Location are not modified aside from the commanded // evaluations. Thus, the type implementing Method may use multiple Operations // to set the Location fields at a particular x value. // // Instead of an Evaluation, a Method may declare MajorIteration. In // a MajorIteration, the values in the fields of Location are treated as // a potential optimizer. The convergence of the optimization routine // (GradientThreshold, etc.) is checked at this new best point. In // a MajorIteration, the fields of Location must be valid and consistent. // // A Method must not return InitIteration and PostIteration operations. These are // reserved for the clients to be passed to Recorders. A Method must also not // combine the Evaluation operations with the Iteration operations. type localMethod interface { // Init initializes the method based on the initial data in loc, updates it // and returns the first operation to be carried out by the caller. // The initial location must be valid as specified by Needs. initLocal(loc *Location) (Operation, error) // Iterate retrieves data from loc, performs one iteration of the method, // updates loc and returns the next operation. iterateLocal(loc *Location) (Operation, error) needser } type needser interface { // needs specifies information about the objective function needed by the // optimizer beyond just the function value. The information is used // internally for initialization and must match evaluation types returned // by Init and Iterate during the optimization process. needs() struct { Gradient bool Hessian bool } } // Statuser can report the status and any error. It is intended for methods as // an additional error reporting mechanism apart from the errors returned from // Init and Iterate. type Statuser interface { Status() (Status, error) } // Linesearcher is a type that can perform a line search. It tries to find an // (approximate) minimum of the objective function along the search direction // dir_k starting at the most recent location x_k, i.e., it tries to minimize // the function // // φ(step) := f(x_k + step * dir_k) where step > 0. // // Typically, a Linesearcher will be used in conjunction with LinesearchMethod // for performing gradient-based optimization through sequential line searches. type Linesearcher interface { // Init initializes the Linesearcher and a new line search. Value and // derivative contain φ(0) and φ'(0), respectively, and step contains the // first trial step length. It returns an Operation that must be one of // FuncEvaluation, GradEvaluation, FuncEvaluation|GradEvaluation. The // caller must evaluate φ(step), φ'(step), or both, respectively, and pass // the result to Linesearcher in value and derivative arguments to Iterate. Init(value, derivative float64, step float64) Operation // Iterate takes in the values of φ and φ' evaluated at the previous step // and returns the next operation. // // If op is one of FuncEvaluation, GradEvaluation, // FuncEvaluation|GradEvaluation, the caller must evaluate φ(step), // φ'(step), or both, respectively, and pass the result to Linesearcher in // value and derivative arguments on the next call to Iterate. // // If op is MajorIteration, a sufficiently accurate minimum of φ has been // found at the previous step and the line search has concluded. Init must // be called again to initialize a new line search. // // If err is nil, op must not specify another operation. If err is not nil, // the values of op and step are undefined. Iterate(value, derivative float64) (op Operation, step float64, err error) } // NextDirectioner implements a strategy for computing a new line search // direction at each major iteration. Typically, a NextDirectioner will be // used in conjunction with LinesearchMethod for performing gradient-based // optimization through sequential line searches. type NextDirectioner interface { // InitDirection initializes the NextDirectioner at the given starting location, // putting the initial direction in place into dir, and returning the initial // step size. InitDirection must not modify Location. InitDirection(loc *Location, dir []float64) (step float64) // NextDirection updates the search direction and step size. Location is // the location seen at the conclusion of the most recent linesearch. The // next search direction is put in place into dir, and the next step size // is returned. NextDirection must not modify Location. NextDirection(loc *Location, dir []float64) (step float64) } // StepSizer can set the next step size of the optimization given the last Location. // Returned step size must be positive. type StepSizer interface { Init(loc *Location, dir []float64) float64 StepSize(loc *Location, dir []float64) float64 } // A Recorder can record the progress of the optimization, for example to print // the progress to StdOut or to a log file. A Recorder must not modify any data. type Recorder interface { Init() error Record(*Location, Operation, *Stats) error } golang-gonum-v1-gonum-0.14.0/optimize/lbfgs.go000066400000000000000000000120011450372207100211140ustar00rootroot00000000000000// 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 optimize import ( "gonum.org/v1/gonum/floats" ) var ( _ Method = (*LBFGS)(nil) _ localMethod = (*LBFGS)(nil) _ NextDirectioner = (*LBFGS)(nil) ) // LBFGS implements the limited-memory BFGS method for gradient-based // unconstrained minimization. // // It stores a modified version of the inverse Hessian approximation H // implicitly from the last Store iterations while the normal BFGS method // stores and manipulates H directly as a dense matrix. Therefore LBFGS is more // appropriate than BFGS for large problems as the cost of LBFGS scales as // O(Store * dim) while BFGS scales as O(dim^2). The "forgetful" nature of // LBFGS may also make it perform better than BFGS for functions with Hessians // that vary rapidly spatially. type LBFGS struct { // Linesearcher selects suitable steps along the descent direction. // Accepted steps should satisfy the strong Wolfe conditions. // If Linesearcher is nil, a reasonable default will be chosen. Linesearcher Linesearcher // Store is the size of the limited-memory storage. // If Store is 0, it will be defaulted to 15. Store int // GradStopThreshold sets the threshold for stopping if the gradient norm // gets too small. If GradStopThreshold is 0 it is defaulted to 1e-12, and // if it is NaN the setting is not used. GradStopThreshold float64 status Status err error ls *LinesearchMethod dim int // Dimension of the problem x []float64 // Location at the last major iteration grad []float64 // Gradient at the last major iteration // History oldest int // Index of the oldest element of the history y [][]float64 // Last Store values of y s [][]float64 // Last Store values of s rho []float64 // Last Store values of rho a []float64 // Cache of Hessian updates } func (l *LBFGS) Status() (Status, error) { return l.status, l.err } func (*LBFGS) Uses(has Available) (uses Available, err error) { return has.gradient() } func (l *LBFGS) Init(dim, tasks int) int { l.status = NotTerminated l.err = nil return 1 } func (l *LBFGS) Run(operation chan<- Task, result <-chan Task, tasks []Task) { l.status, l.err = localOptimizer{}.run(l, l.GradStopThreshold, operation, result, tasks) close(operation) } func (l *LBFGS) initLocal(loc *Location) (Operation, error) { if l.Linesearcher == nil { l.Linesearcher = &Bisection{} } if l.Store == 0 { l.Store = 15 } if l.ls == nil { l.ls = &LinesearchMethod{} } l.ls.Linesearcher = l.Linesearcher l.ls.NextDirectioner = l return l.ls.Init(loc) } func (l *LBFGS) iterateLocal(loc *Location) (Operation, error) { return l.ls.Iterate(loc) } func (l *LBFGS) InitDirection(loc *Location, dir []float64) (stepSize float64) { dim := len(loc.X) l.dim = dim l.oldest = 0 l.a = resize(l.a, l.Store) l.rho = resize(l.rho, l.Store) l.y = l.initHistory(l.y) l.s = l.initHistory(l.s) l.x = resize(l.x, dim) copy(l.x, loc.X) l.grad = resize(l.grad, dim) copy(l.grad, loc.Gradient) copy(dir, loc.Gradient) floats.Scale(-1, dir) return 1 / floats.Norm(dir, 2) } func (l *LBFGS) initHistory(hist [][]float64) [][]float64 { c := cap(hist) if c < l.Store { n := make([][]float64, l.Store-c) hist = append(hist[:c], n...) } hist = hist[:l.Store] for i := range hist { hist[i] = resize(hist[i], l.dim) for j := range hist[i] { hist[i][j] = 0 } } return hist } func (l *LBFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) { // Uses two-loop correction as described in // Nocedal, J., Wright, S.: Numerical Optimization (2nd ed). Springer (2006), chapter 7, page 178. if len(loc.X) != l.dim { panic("lbfgs: unexpected size mismatch") } if len(loc.Gradient) != l.dim { panic("lbfgs: unexpected size mismatch") } if len(dir) != l.dim { panic("lbfgs: unexpected size mismatch") } y := l.y[l.oldest] floats.SubTo(y, loc.Gradient, l.grad) s := l.s[l.oldest] floats.SubTo(s, loc.X, l.x) sDotY := floats.Dot(s, y) l.rho[l.oldest] = 1 / sDotY l.oldest = (l.oldest + 1) % l.Store copy(l.x, loc.X) copy(l.grad, loc.Gradient) copy(dir, loc.Gradient) // Start with the most recent element and go backward, for i := 0; i < l.Store; i++ { idx := l.oldest - i - 1 if idx < 0 { idx += l.Store } l.a[idx] = l.rho[idx] * floats.Dot(l.s[idx], dir) floats.AddScaled(dir, -l.a[idx], l.y[idx]) } // Scale the initial Hessian. gamma := sDotY / floats.Dot(y, y) floats.Scale(gamma, dir) // Start with the oldest element and go forward. for i := 0; i < l.Store; i++ { idx := i + l.oldest if idx >= l.Store { idx -= l.Store } beta := l.rho[idx] * floats.Dot(l.y[idx], dir) floats.AddScaled(dir, l.a[idx]-beta, l.s[idx]) } // dir contains H^{-1} * g, so flip the direction for minimization. floats.Scale(-1, dir) return 1 } func (*LBFGS) needs() struct { Gradient bool Hessian bool } { return struct { Gradient bool Hessian bool }{true, false} } golang-gonum-v1-gonum-0.14.0/optimize/linesearch.go000066400000000000000000000151611450372207100221460ustar00rootroot00000000000000// 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 optimize import ( "math" "gonum.org/v1/gonum/floats" ) // LinesearchMethod represents an abstract optimization method in which a // function is optimized through successive line search optimizations. type LinesearchMethod struct { // NextDirectioner specifies the search direction of each linesearch. NextDirectioner NextDirectioner // Linesearcher performs a linesearch along the search direction. Linesearcher Linesearcher x []float64 // Starting point for the current iteration. dir []float64 // Search direction for the current iteration. first bool // Indicator of the first iteration. nextMajor bool // Indicates that MajorIteration must be commanded at the next call to Iterate. eval Operation // Indicator of valid fields in Location. lastStep float64 // Step taken from x in the previous call to Iterate. lastOp Operation // Operation returned from the previous call to Iterate. } func (ls *LinesearchMethod) Init(loc *Location) (Operation, error) { if loc.Gradient == nil { panic("linesearch: gradient is nil") } dim := len(loc.X) ls.x = resize(ls.x, dim) ls.dir = resize(ls.dir, dim) ls.first = true ls.nextMajor = false // Indicate that all fields of loc are valid. ls.eval = FuncEvaluation | GradEvaluation if loc.Hessian != nil { ls.eval |= HessEvaluation } ls.lastStep = math.NaN() ls.lastOp = NoOperation return ls.initNextLinesearch(loc) } func (ls *LinesearchMethod) Iterate(loc *Location) (Operation, error) { switch ls.lastOp { case NoOperation: // TODO(vladimir-ch): Either Init has not been called, or the caller is // trying to resume the optimization run after Iterate previously // returned with an error. Decide what is the proper thing to do. See also #125. case MajorIteration: // The previous updated location did not converge the full // optimization. Initialize a new Linesearch. return ls.initNextLinesearch(loc) default: // Update the indicator of valid fields of loc. ls.eval |= ls.lastOp if ls.nextMajor { ls.nextMajor = false // Linesearcher previously finished, and the invalid fields of loc // have now been validated. Announce MajorIteration. ls.lastOp = MajorIteration return ls.lastOp, nil } } // Continue the linesearch. f := math.NaN() if ls.eval&FuncEvaluation != 0 { f = loc.F } projGrad := math.NaN() if ls.eval&GradEvaluation != 0 { projGrad = floats.Dot(loc.Gradient, ls.dir) } op, step, err := ls.Linesearcher.Iterate(f, projGrad) if err != nil { return ls.error(err) } switch op { case MajorIteration: // Linesearch has been finished. ls.lastOp = complementEval(loc, ls.eval) if ls.lastOp == NoOperation { // loc is complete, MajorIteration can be declared directly. ls.lastOp = MajorIteration } else { // Declare MajorIteration on the next call to Iterate. ls.nextMajor = true } case FuncEvaluation, GradEvaluation, FuncEvaluation | GradEvaluation: if step != ls.lastStep { // We are moving to a new location, and not, say, evaluating extra // information at the current location. // Compute the next evaluation point and store it in loc.X. floats.AddScaledTo(loc.X, ls.x, step, ls.dir) if floats.Equal(ls.x, loc.X) { // Step size has become so small that the next evaluation point is // indistinguishable from the starting point for the current // iteration due to rounding errors. return ls.error(ErrNoProgress) } ls.lastStep = step ls.eval = NoOperation // Indicate all invalid fields of loc. } ls.lastOp = op default: panic("linesearch: Linesearcher returned invalid operation") } return ls.lastOp, nil } func (ls *LinesearchMethod) error(err error) (Operation, error) { ls.lastOp = NoOperation return ls.lastOp, err } // initNextLinesearch initializes the next linesearch using the previous // complete location stored in loc. It fills loc.X and returns an evaluation // to be performed at loc.X. func (ls *LinesearchMethod) initNextLinesearch(loc *Location) (Operation, error) { copy(ls.x, loc.X) var step float64 if ls.first { ls.first = false step = ls.NextDirectioner.InitDirection(loc, ls.dir) } else { step = ls.NextDirectioner.NextDirection(loc, ls.dir) } projGrad := floats.Dot(loc.Gradient, ls.dir) if projGrad >= 0 { return ls.error(ErrNonDescentDirection) } op := ls.Linesearcher.Init(loc.F, projGrad, step) switch op { case FuncEvaluation, GradEvaluation, FuncEvaluation | GradEvaluation: default: panic("linesearch: Linesearcher returned invalid operation") } floats.AddScaledTo(loc.X, ls.x, step, ls.dir) if floats.Equal(ls.x, loc.X) { // Step size is so small that the next evaluation point is // indistinguishable from the starting point for the current iteration // due to rounding errors. return ls.error(ErrNoProgress) } ls.lastStep = step ls.eval = NoOperation // Invalidate all fields of loc. ls.lastOp = op return ls.lastOp, nil } // ArmijoConditionMet returns true if the Armijo condition (aka sufficient // decrease) has been met. Under normal conditions, the following should be // true, though this is not enforced: // - initGrad < 0 // - step > 0 // - 0 < decrease < 1 func ArmijoConditionMet(currObj, initObj, initGrad, step, decrease float64) bool { return currObj <= initObj+decrease*step*initGrad } // StrongWolfeConditionsMet returns true if the strong Wolfe conditions have been met. // The strong Wolfe conditions ensure sufficient decrease in the function // value, and sufficient decrease in the magnitude of the projected gradient. // Under normal conditions, the following should be true, though this is not // enforced: // - initGrad < 0 // - step > 0 // - 0 <= decrease < curvature < 1 func StrongWolfeConditionsMet(currObj, currGrad, initObj, initGrad, step, decrease, curvature float64) bool { if currObj > initObj+decrease*step*initGrad { return false } return math.Abs(currGrad) < curvature*math.Abs(initGrad) } // WeakWolfeConditionsMet returns true if the weak Wolfe conditions have been met. // The weak Wolfe conditions ensure sufficient decrease in the function value, // and sufficient decrease in the value of the projected gradient. Under normal // conditions, the following should be true, though this is not enforced: // - initGrad < 0 // - step > 0 // - 0 <= decrease < curvature< 1 func WeakWolfeConditionsMet(currObj, currGrad, initObj, initGrad, step, decrease, curvature float64) bool { if currObj > initObj+decrease*step*initGrad { return false } return currGrad >= curvature*initGrad } golang-gonum-v1-gonum-0.14.0/optimize/linesearcher_test.go000066400000000000000000000067611450372207100235420ustar00rootroot00000000000000// 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 optimize import ( "fmt" "math" "reflect" "testing" "gonum.org/v1/gonum/optimize/functions" ) func TestMoreThuente(t *testing.T) { t.Parallel() d := 0.001 c := 0.001 ls := &MoreThuente{ DecreaseFactor: d, CurvatureFactor: c, } testLinesearcher(t, ls, d, c, true) } func TestBisection(t *testing.T) { t.Parallel() c := 0.1 ls := &Bisection{ CurvatureFactor: c, } testLinesearcher(t, ls, 0, c, true) } func TestBacktracking(t *testing.T) { t.Parallel() d := 0.001 ls := &Backtracking{ DecreaseFactor: d, } testLinesearcher(t, ls, d, 0, false) } type funcGrader interface { Func([]float64) float64 Grad([]float64, []float64) } type linesearcherTest struct { name string f func(float64) float64 g func(float64) float64 } func newLinesearcherTest(name string, fg funcGrader) linesearcherTest { grad := make([]float64, 1) return linesearcherTest{ name: name, f: func(x float64) float64 { return fg.Func([]float64{x}) }, g: func(x float64) float64 { fg.Grad(grad, []float64{x}) return grad[0] }, } } func testLinesearcher(t *testing.T, ls Linesearcher, decrease, curvature float64, strongWolfe bool) { for i, prob := range []linesearcherTest{ newLinesearcherTest("Concave-to-the-right function", functions.ConcaveRight{}), newLinesearcherTest("Concave-to-the-left function", functions.ConcaveLeft{}), newLinesearcherTest("Plassmann wiggly function (l=39, beta=0.01)", functions.Plassmann{L: 39, Beta: 0.01}), newLinesearcherTest("Yanai-Ozawa-Kaneko function (beta1=0.001, beta2=0.001)", functions.YanaiOzawaKaneko{Beta1: 0.001, Beta2: 0.001}), newLinesearcherTest("Yanai-Ozawa-Kaneko function (beta1=0.01, beta2=0.001)", functions.YanaiOzawaKaneko{Beta1: 0.01, Beta2: 0.001}), newLinesearcherTest("Yanai-Ozawa-Kaneko function (beta1=0.001, beta2=0.01)", functions.YanaiOzawaKaneko{Beta1: 0.001, Beta2: 0.01}), } { for _, initStep := range []float64{0.001, 0.1, 1, 10, 1000} { prefix := fmt.Sprintf("test %d (%v started from %v)", i, prob.name, initStep) f0 := prob.f(0) g0 := prob.g(0) if g0 >= 0 { panic("bad test function") } op := ls.Init(f0, g0, initStep) if !op.isEvaluation() { t.Errorf("%v: Linesearcher.Init returned non-evaluating operation %v", prefix, op) continue } var ( err error k int f, g float64 step float64 ) loop: for { switch op { case MajorIteration: if f > f0+step*decrease*g0 { t.Errorf("%v: %v found step %v that does not satisfy the sufficient decrease condition", prefix, reflect.TypeOf(ls), step) } if strongWolfe && math.Abs(g) > curvature*(-g0) { t.Errorf("%v: %v found step %v that does not satisfy the curvature condition", prefix, reflect.TypeOf(ls), step) } break loop case FuncEvaluation: f = prob.f(step) case GradEvaluation: g = prob.g(step) case FuncEvaluation | GradEvaluation: f = prob.f(step) g = prob.g(step) default: t.Errorf("%v: Linesearcher returned an invalid operation %v", prefix, op) break loop } k++ if k == 1000 { t.Errorf("%v: %v did not finish", prefix, reflect.TypeOf(ls)) break } op, step, err = ls.Iterate(f, g) if err != nil { t.Errorf("%v: %v failed at step %v with %v", prefix, reflect.TypeOf(ls), step, err) break } } } } } golang-gonum-v1-gonum-0.14.0/optimize/listsearch.go000066400000000000000000000054131450372207100221710ustar00rootroot00000000000000// 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 optimize import ( "math" "gonum.org/v1/gonum/mat" ) var _ Method = (*ListSearch)(nil) // ListSearch finds the optimum location from a specified list of possible // optimum locations. type ListSearch struct { // Locs is the list of locations to optimize. Each row of Locs is a location // to optimize. The number of columns of Locs must match the dimensions // passed to InitGlobal, and Locs must have at least one row. Locs mat.Matrix eval int rows int bestF float64 bestIdx int } func (*ListSearch) Uses(has Available) (uses Available, err error) { return has.function() } // Init initializes the method for optimization. The input dimension // must match the number of columns of Locs. func (l *ListSearch) Init(dim, tasks int) int { if dim <= 0 { panic(nonpositiveDimension) } if tasks < 0 { panic(negativeTasks) } r, c := l.Locs.Dims() if r == 0 { panic("listsearch: list matrix has no rows") } if c != dim { panic("listsearch: supplied dimension does not match list columns") } l.eval = 0 l.rows = r l.bestF = math.Inf(1) l.bestIdx = -1 return min(r, tasks) } func (l *ListSearch) sendNewLoc(operation chan<- Task, task Task) { task.Op = FuncEvaluation task.ID = l.eval mat.Row(task.X, l.eval, l.Locs) l.eval++ operation <- task } func (l *ListSearch) updateMajor(operation chan<- Task, task Task) { // Update the best value seen so far, and send a MajorIteration. if task.F < l.bestF { l.bestF = task.F l.bestIdx = task.ID } else { task.F = l.bestF mat.Row(task.X, l.bestIdx, l.Locs) } task.Op = MajorIteration operation <- task } func (l *ListSearch) Status() (Status, error) { if l.eval < l.rows { return NotTerminated, nil } return MethodConverge, nil } func (l *ListSearch) Run(operation chan<- Task, result <-chan Task, tasks []Task) { // Send initial tasks to evaluate for _, task := range tasks { l.sendNewLoc(operation, task) } // Read from the channel until PostIteration is sent or until the list of // tasks is exhausted. Loop: for { task := <-result switch task.Op { default: panic("unknown operation") case PostIteration: break Loop case MajorIteration: if l.eval == l.rows { task.Op = MethodDone operation <- task continue } l.sendNewLoc(operation, task) case FuncEvaluation: l.updateMajor(operation, task) } } // Post iteration was sent, or the list has been completed. Read in the final // list of tasks. for task := range result { switch task.Op { default: panic("unknown operation") case MajorIteration: case FuncEvaluation: l.updateMajor(operation, task) } } close(operation) } golang-gonum-v1-gonum-0.14.0/optimize/listsearch_test.go000066400000000000000000000116211450372207100232260ustar00rootroot00000000000000// 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 optimize import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/optimize/functions" ) func TestListSearch(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { r, c int shortEvals int fun func([]float64) float64 }{ { r: 100, c: 10, fun: functions.ExtendedRosenbrock{}.Func, }, } { // Generate a random list of items. r, c := test.r, test.c locs := mat.NewDense(r, c, nil) for i := 0; i < r; i++ { for j := 0; j < c; j++ { locs.Set(i, j, rnd.NormFloat64()) } } // Evaluate all of the items in the list and find the minimum value. fs := make([]float64, r) for i := 0; i < r; i++ { fs[i] = test.fun(locs.RawRowView(i)) } minIdx := floats.MinIdx(fs) // Check that the global minimum is found under normal conditions. p := Problem{Func: test.fun} method := &ListSearch{ Locs: locs, } settings := &Settings{ Converger: NeverTerminate{}, } initX := make([]float64, c) result, err := Minimize(p, initX, settings, method) if err != nil { t.Errorf("cas %v: error optimizing: %s", cas, err) } if result.Status != MethodConverge { t.Errorf("cas %v: status should be MethodConverge", cas) } if !floats.Equal(result.X, locs.RawRowView(minIdx)) { t.Errorf("cas %v: did not find minimum of whole list", cas) } // Check that the optimization works concurrently. concurrent := 6 settings.Concurrent = concurrent result, err = Minimize(p, initX, settings, method) if err != nil { t.Errorf("cas %v: error optimizing: %s", cas, err) } if result.Status != MethodConverge { t.Errorf("cas %v: status should be MethodConverge", cas) } if !floats.Equal(result.X, locs.RawRowView(minIdx)) { t.Errorf("cas %v: did not find minimum of whole list concurrent", cas) } // Check that the optimization works concurrently with more than the number of samples. settings.Concurrent = test.r + concurrent result, err = Minimize(p, initX, settings, method) if err != nil { t.Errorf("cas %v: error optimizing: %s", cas, err) } if result.Status != MethodConverge { t.Errorf("cas %v: status should be MethodConverge", cas) } if !floats.Equal(result.X, locs.RawRowView(minIdx)) { t.Errorf("cas %v: did not find minimum of whole list concurrent", cas) } // Check that cleanup happens properly by setting the minimum location // to the last sample. swapSamples(locs, fs, minIdx, test.r-1) minIdx = test.r - 1 settings.Concurrent = concurrent result, err = Minimize(p, initX, settings, method) if err != nil { t.Errorf("cas %v: error optimizing: %s", cas, err) } if result.Status != MethodConverge { t.Errorf("cas %v: status should be MethodConverge", cas) } if !floats.Equal(result.X, locs.RawRowView(minIdx)) { t.Errorf("cas %v: did not find minimum of whole list last sample", cas) } // Test that the correct optimum is found when the optimization ends early. // Note that the above test swapped the list minimum to the last sample, // so it's guaranteed that the minimum of the shortened list is not the // same as the minimum of the whole list. evals := test.r / 3 minIdxFirst := floats.MinIdx(fs[:evals]) settings.Concurrent = 0 settings.FuncEvaluations = evals result, err = Minimize(p, initX, settings, method) if err != nil { t.Errorf("cas %v: error optimizing: %s", cas, err) } if result.Status != FunctionEvaluationLimit { t.Errorf("cas %v: status was not FunctionEvaluationLimit", cas) } if !floats.Equal(result.X, locs.RawRowView(minIdxFirst)) { t.Errorf("cas %v: did not find minimum of shortened list serial", cas) } // Test the same but concurrently. We can't guarantee a specific number // of function evaluations concurrently, so make sure that the list optimum // is not between [evals:evals+concurrent] for floats.MinIdx(fs[:evals]) != floats.MinIdx(fs[:evals+concurrent]) { // Swap the minimum index with a random element. minIdxFirst := floats.MinIdx(fs[:evals+concurrent]) new := rnd.Intn(evals) swapSamples(locs, fs, minIdxFirst, new) } minIdxFirst = floats.MinIdx(fs[:evals]) settings.Concurrent = concurrent result, err = Minimize(p, initX, settings, method) if err != nil { t.Errorf("cas %v: error optimizing: %s", cas, err) } if result.Status != FunctionEvaluationLimit { t.Errorf("cas %v: status was not FunctionEvaluationLimit", cas) } if !floats.Equal(result.X, locs.RawRowView(minIdxFirst)) { t.Errorf("cas %v: did not find minimum of shortened list concurrent", cas) } } } func swapSamples(m *mat.Dense, f []float64, i, j int) { f[i], f[j] = f[j], f[i] row := mat.Row(nil, i, m) m.SetRow(i, m.RawRowView(j)) m.SetRow(j, row) } golang-gonum-v1-gonum-0.14.0/optimize/local.go000066400000000000000000000105731450372207100211250ustar00rootroot00000000000000// 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 optimize import ( "math" "gonum.org/v1/gonum/floats" ) // localOptimizer is a helper type for running an optimization using a LocalMethod. type localOptimizer struct{} // run controls the optimization run for a localMethod. The calling method // must close the operation channel at the conclusion of the optimization. This // provides a happens before relationship between the return of status and the // closure of operation, and thus a call to method.Status (if necessary). func (l localOptimizer) run(method localMethod, gradThresh float64, operation chan<- Task, result <-chan Task, tasks []Task) (Status, error) { // Local methods start with a fully-specified initial location. task := tasks[0] task = l.initialLocation(operation, result, task, method) if task.Op == PostIteration { l.finish(operation, result) return NotTerminated, nil } status, err := l.checkStartingLocation(task, gradThresh) if err != nil { l.finishMethodDone(operation, result, task) return status, err } // Send a major iteration with the starting location. task.Op = MajorIteration operation <- task task = <-result if task.Op == PostIteration { l.finish(operation, result) return NotTerminated, nil } op, err := method.initLocal(task.Location) if err != nil { l.finishMethodDone(operation, result, task) return Failure, err } task.Op = op operation <- task Loop: for { r := <-result switch r.Op { case PostIteration: break Loop case MajorIteration: // The last operation was a MajorIteration. Check if the gradient // is below the threshold. if status := l.checkGradientConvergence(r.Gradient, gradThresh); status != NotTerminated { l.finishMethodDone(operation, result, task) return GradientThreshold, nil } fallthrough default: op, err := method.iterateLocal(r.Location) if err != nil { l.finishMethodDone(operation, result, r) return Failure, err } r.Op = op operation <- r } } l.finish(operation, result) return NotTerminated, nil } // initialOperation returns the Operation needed to fill the initial location // based on the needs of the method and the values already supplied. func (localOptimizer) initialOperation(task Task, n needser) Operation { var newOp Operation op := task.Op if op&FuncEvaluation == 0 { newOp |= FuncEvaluation } needs := n.needs() if needs.Gradient && op&GradEvaluation == 0 { newOp |= GradEvaluation } if needs.Hessian && op&HessEvaluation == 0 { newOp |= HessEvaluation } return newOp } // initialLocation fills the initial location based on the needs of the method. // The task passed to initialLocation should be the first task sent in RunGlobal. func (l localOptimizer) initialLocation(operation chan<- Task, result <-chan Task, task Task, needs needser) Task { task.Op = l.initialOperation(task, needs) operation <- task return <-result } func (l localOptimizer) checkStartingLocation(task Task, gradThresh float64) (Status, error) { if math.IsInf(task.F, 1) || math.IsNaN(task.F) { return Failure, ErrFunc(task.F) } for i, v := range task.Gradient { if math.IsInf(v, 0) || math.IsNaN(v) { return Failure, ErrGrad{Grad: v, Index: i} } } status := l.checkGradientConvergence(task.Gradient, gradThresh) return status, nil } func (localOptimizer) checkGradientConvergence(gradient []float64, gradThresh float64) Status { if gradient == nil || math.IsNaN(gradThresh) { return NotTerminated } if gradThresh == 0 { gradThresh = defaultGradientAbsTol } if norm := floats.Norm(gradient, math.Inf(1)); norm < gradThresh { return GradientThreshold } return NotTerminated } // finish completes the channel operations to finish an optimization. func (localOptimizer) finish(operation chan<- Task, result <-chan Task) { // Guarantee that result is closed before operation is closed. for range result { } } // finishMethodDone sends a MethodDone signal on operation, reads the result, // and completes the channel operations to finish an optimization. func (l localOptimizer) finishMethodDone(operation chan<- Task, result <-chan Task, task Task) { task.Op = MethodDone operation <- task task = <-result if task.Op != PostIteration { panic("optimize: task should have returned post iteration") } l.finish(operation, result) } golang-gonum-v1-gonum-0.14.0/optimize/local_example_test.go000066400000000000000000000017171450372207100236770ustar00rootroot00000000000000// Copyright ©2016 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 optimize_test import ( "fmt" "log" "gonum.org/v1/gonum/optimize" "gonum.org/v1/gonum/optimize/functions" ) func ExampleMinimize() { p := optimize.Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, } x := []float64{1.3, 0.7, 0.8, 1.9, 1.2} result, err := optimize.Minimize(p, x, nil, nil) if err != nil { log.Fatal(err) } if err = result.Status.Err(); err != nil { log.Fatal(err) } fmt.Printf("result.Status: %v\n", result.Status) fmt.Printf("result.X: %0.4g\n", result.X) fmt.Printf("result.F: %0.4g\n", result.F) fmt.Printf("result.Stats.FuncEvaluations: %d\n", result.Stats.FuncEvaluations) // Output: // result.Status: GradientThreshold // result.X: [1 1 1 1 1] // result.F: 4.98e-30 // result.Stats.FuncEvaluations: 31 } golang-gonum-v1-gonum-0.14.0/optimize/minimize.go000066400000000000000000000507301450372207100216530ustar00rootroot00000000000000// Copyright ©2016 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 optimize import ( "fmt" "math" "time" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) const ( nonpositiveDimension string = "optimize: non-positive input dimension" negativeTasks string = "optimize: negative input number of tasks" ) func min(a, b int) int { if a < b { return a } return b } // Task is a type to communicate between the Method and the outer // calling script. type Task struct { ID int Op Operation *Location } // Location represents a location in the optimization procedure. type Location struct { // X is the function input for the location. X []float64 // F is the result of evaluating the function at X. F float64 // Gradient holds the first-order partial derivatives // of the function at X. // The length of Gradient must match the length of X // or be zero. If the capacity of Gradient is less // than the length of X, a new slice will be allocated. Gradient []float64 // Hessian holds the second-order partial derivatives // of the function at X. // The dimensions of Hessian must match the length of X // or Hessian must be nil or empty. If Hessian is nil // a new mat.SymDense will be allocated, if it is empty // it will be resized to match the length of X. Hessian *mat.SymDense } // Method is a type which can search for an optimum of an objective function. type Method interface { // Init initializes the method for optimization. The inputs are // the problem dimension and number of available concurrent tasks. // // Init returns the number of concurrent processes to use, which must be // less than or equal to tasks. Init(dim, tasks int) (concurrent int) // Run runs an optimization. The method sends Tasks on // the operation channel (for performing function evaluations, major // iterations, etc.). The result of the tasks will be returned on Result. // See the documentation for Operation types for the possible operations. // // The caller of Run will signal the termination of the optimization // (i.e. convergence from user settings) by sending a task with a PostIteration // Op field on result. More tasks may still be sent on operation after this // occurs, but only MajorIteration operations will still be conducted // appropriately. Thus, it can not be guaranteed that all Evaluations sent // on operation will be evaluated, however if an Evaluation is started, // the results of that evaluation will be sent on results. // // The Method must read from the result channel until it is closed. // During this, the Method may want to send new MajorIteration(s) on // operation. Method then must close operation, and return from Run. // These steps must establish a "happens-before" relationship between result // being closed (externally) and Run closing operation, for example // by using a range loop to read from result even if no results are expected. // // The last parameter to Run is a slice of tasks with length equal to // the return from Init. Task has an ID field which may be // set and modified by Method, and must not be modified by the caller. // The first element of tasks contains information about the initial location. // The Location.X field is always valid. The Operation field specifies which // other values of Location are known. If Operation == NoOperation, none of // the values should be used, otherwise the Evaluation operations will be // composed to specify the valid fields. Methods are free to use or // ignore these values. // // Successful execution of an Operation may require the Method to modify // fields a Location. MajorIteration calls will not modify the values in // the Location, but Evaluation operations will. Methods are encouraged to // leave Location fields untouched to allow memory re-use. If data needs to // be stored, the respective field should be set to nil -- Methods should // not allocate Location memory themselves. // // Method may have its own specific convergence criteria, which can // be communicated using a MethodDone operation. This will trigger a // PostIteration to be sent on result, and the MethodDone task will not be // returned on result. The Method must implement Statuser, and the // call to Status must return a Status other than NotTerminated. // // The operation and result tasks are guaranteed to have a buffer length // equal to the return from Init. Run(operation chan<- Task, result <-chan Task, tasks []Task) // Uses checks if the Method is suited to the optimization problem. The // input is the available functions in Problem to call, and the returns are // the functions which may be used and an error if there is a mismatch // between the Problem and the Method's capabilities. Uses(has Available) (uses Available, err error) } // Minimize uses an optimizer to search for a minimum of a function. A // maximization problem can be transformed into a minimization problem by // multiplying the function by -1. // // The first argument represents the problem to be minimized. Its fields are // routines that evaluate the objective function, gradient, and other // quantities related to the problem. The objective function, p.Func, must not // be nil. The optimization method used may require other fields to be non-nil // as specified by method.Needs. Minimize will panic if these are not met. The // method can be determined automatically from the supplied problem which is // described below. // // If p.Status is not nil, it is called before every evaluation. If the // returned Status is other than NotTerminated or if the error is not nil, the // optimization run is terminated. // // The second argument specifies the initial location for the optimization. // Some Methods do not require an initial location, but initX must still be // specified for the dimension of the optimization problem. // // The third argument contains the settings for the minimization. If settings // is nil, the zero value will be used, see the documentation of the Settings // type for more information, and see the warning below. All settings will be // honored for all Methods, even if that setting is counter-productive to the // method. Minimize cannot guarantee strict adherence to the evaluation bounds // specified when performing concurrent evaluations and updates. // // The final argument is the optimization method to use. If method == nil, then // an appropriate default is chosen based on the properties of the other arguments // (dimension, gradient-free or gradient-based, etc.). If method is not nil, // Minimize panics if the Problem is not consistent with the Method (Uses // returns an error). // // Minimize returns a Result struct and any error that occurred. See the // documentation of Result for more information. // // See the documentation for Method for the details on implementing a method. // // Be aware that the default settings of Minimize are to accurately find the // minimum. For certain functions and optimization methods, this can take many // function evaluations. The Settings input struct can be used to limit this, // for example by modifying the maximum function evaluations or gradient tolerance. func Minimize(p Problem, initX []float64, settings *Settings, method Method) (*Result, error) { startTime := time.Now() if method == nil { method = getDefaultMethod(&p) } if settings == nil { settings = &Settings{} } stats := &Stats{} dim := len(initX) err := checkOptimization(p, dim, settings.Recorder) if err != nil { return nil, err } optLoc := newLocation(dim) // This must have an allocated X field. optLoc.F = math.Inf(1) initOp, initLoc := getInitLocation(dim, initX, settings.InitValues) converger := settings.Converger if converger == nil { converger = defaultFunctionConverge() } converger.Init(dim) stats.Runtime = time.Since(startTime) // Send initial location to Recorder if settings.Recorder != nil { err = settings.Recorder.Record(optLoc, InitIteration, stats) if err != nil { return nil, err } } // Run optimization var status Status status, err = minimize(&p, method, settings, converger, stats, initOp, initLoc, optLoc, startTime) // Cleanup and collect results if settings.Recorder != nil && err == nil { err = settings.Recorder.Record(optLoc, PostIteration, stats) } stats.Runtime = time.Since(startTime) return &Result{ Location: *optLoc, Stats: *stats, Status: status, }, err } func getDefaultMethod(p *Problem) Method { if p.Grad != nil { return &LBFGS{} } return &NelderMead{} } // minimize performs an optimization. minimize updates the settings and optLoc, // and returns the final Status and error. func minimize(prob *Problem, method Method, settings *Settings, converger Converger, stats *Stats, initOp Operation, initLoc, optLoc *Location, startTime time.Time) (Status, error) { dim := len(optLoc.X) nTasks := settings.Concurrent if nTasks == 0 { nTasks = 1 } has := availFromProblem(*prob) _, initErr := method.Uses(has) if initErr != nil { panic(fmt.Sprintf("optimize: specified method inconsistent with Problem: %v", initErr)) } newNTasks := method.Init(dim, nTasks) if newNTasks > nTasks { panic("optimize: too many tasks returned by Method") } nTasks = newNTasks // Launch the method. The method communicates tasks using the operations // channel, and results is used to return the evaluated results. operations := make(chan Task, nTasks) results := make(chan Task, nTasks) go func() { tasks := make([]Task, nTasks) tasks[0].Location = initLoc tasks[0].Op = initOp for i := 1; i < len(tasks); i++ { tasks[i].Location = newLocation(dim) } method.Run(operations, results, tasks) }() // Algorithmic Overview: // There are three pieces to performing a concurrent optimization, // the distributor, the workers, and the stats combiner. At a high level, // the distributor reads in tasks sent by method, sending evaluations to the // workers, and forwarding other operations to the statsCombiner. The workers // read these forwarded evaluation tasks, evaluate the relevant parts of Problem // and forward the results on to the stats combiner. The stats combiner reads // in results from the workers, as well as tasks from the distributor, and // uses them to update optimization statistics (function evaluations, etc.) // and to check optimization convergence. // // The complicated part is correctly shutting down the optimization. The // procedure is as follows. First, the stats combiner closes done and sends // a PostIteration to the method. The distributor then reads that done has // been closed, and closes the channel with the workers. At this point, no // more evaluation operations will be executed. As the workers finish their // evaluations, they forward the results onto the stats combiner, and then // signal their shutdown to the stats combiner. When all workers have successfully // finished, the stats combiner closes the results channel, signaling to the // method that all results have been collected. At this point, the method // may send MajorIteration(s) to update an optimum location based on these // last returned results, and then the method will close the operations channel. // The Method must ensure that the closing of results happens before the // closing of operations in order to ensure proper shutdown order. // Now that no more tasks will be commanded by the method, the distributor // closes statsChan, and with no more statistics to update the optimization // concludes. workerChan := make(chan Task) // Delegate tasks to the workers. statsChan := make(chan Task) // Send evaluation updates. done := make(chan struct{}) // Communicate the optimization is done. // Read tasks from the method and distribute as appropriate. distributor := func() { for { select { case task := <-operations: switch task.Op { case InitIteration: panic("optimize: Method returned InitIteration") case PostIteration: panic("optimize: Method returned PostIteration") case NoOperation, MajorIteration, MethodDone: statsChan <- task default: if !task.Op.isEvaluation() { panic("optimize: expecting evaluation operation") } workerChan <- task } case <-done: // No more evaluations will be sent, shut down the workers, and // read the final tasks. close(workerChan) for task := range operations { if task.Op == MajorIteration { statsChan <- task } } close(statsChan) return } } } go distributor() // Evaluate the Problem concurrently. worker := func() { x := make([]float64, dim) for task := range workerChan { evaluate(prob, task.Location, task.Op, x) statsChan <- task } // Signal successful worker completion. statsChan <- Task{Op: signalDone} } for i := 0; i < nTasks; i++ { go worker() } var ( workersDone int // effective wg for the workers status Status err error finalStatus Status finalError error ) // Update optimization statistics and check convergence. var methodDone bool for task := range statsChan { switch task.Op { default: if !task.Op.isEvaluation() { panic("minimize: evaluation task expected") } updateEvaluationStats(stats, task.Op) status, err = checkEvaluationLimits(prob, stats, settings) case signalDone: workersDone++ if workersDone == nTasks { close(results) } continue case NoOperation: // Just send the task back. case MajorIteration: status = performMajorIteration(optLoc, task.Location, stats, converger, startTime, settings) case MethodDone: methodDone = true status = MethodConverge } if settings.Recorder != nil && status == NotTerminated && err == nil { stats.Runtime = time.Since(startTime) // Allow err to be overloaded if the Recorder fails. err = settings.Recorder.Record(task.Location, task.Op, stats) if err != nil { status = Failure } } // If this is the first termination status, trigger the conclusion of // the optimization. if status != NotTerminated || err != nil { select { case <-done: default: finalStatus = status finalError = err results <- Task{ Op: PostIteration, } close(done) } } // Send the result back to the Problem if there are still active workers. if workersDone != nTasks && task.Op != MethodDone { results <- task } } // This code block is here rather than above to ensure Status() is not called // before Method.Run closes operations. if methodDone { statuser, ok := method.(Statuser) if !ok { panic("optimize: method returned MethodDone but is not a Statuser") } finalStatus, finalError = statuser.Status() if finalStatus == NotTerminated { panic("optimize: method returned MethodDone but a NotTerminated status") } } return finalStatus, finalError } func defaultFunctionConverge() *FunctionConverge { return &FunctionConverge{ Absolute: 1e-10, Iterations: 100, } } // newLocation allocates a new location structure with an X field of the // appropriate size. func newLocation(dim int) *Location { return &Location{ X: make([]float64, dim), } } // getInitLocation checks the validity of initLocation and initOperation and // returns the initial values as a *Location. func getInitLocation(dim int, initX []float64, initValues *Location) (Operation, *Location) { loc := newLocation(dim) if initX == nil { if initValues != nil { panic("optimize: initValues is non-nil but no initial location specified") } return NoOperation, loc } copy(loc.X, initX) if initValues == nil { return NoOperation, loc } else { if initValues.X != nil { panic("optimize: location specified in InitValues (only use InitX)") } } loc.F = initValues.F op := FuncEvaluation if initValues.Gradient != nil { if len(initValues.Gradient) != dim { panic("optimize: initial gradient does not match problem dimension") } loc.Gradient = initValues.Gradient op |= GradEvaluation } if initValues.Hessian != nil { if initValues.Hessian.SymmetricDim() != dim { panic("optimize: initial Hessian does not match problem dimension") } loc.Hessian = initValues.Hessian op |= HessEvaluation } return op, loc } func checkOptimization(p Problem, dim int, recorder Recorder) error { if p.Func == nil { panic(badProblem) } if dim <= 0 { panic("optimize: impossible problem dimension") } if p.Status != nil { _, err := p.Status() if err != nil { return err } } if recorder != nil { err := recorder.Init() if err != nil { return err } } return nil } // evaluate evaluates the routines specified by the Operation at loc.X, and stores // the answer into loc. loc.X is copied into x before evaluating in order to // prevent the routines from modifying it. func evaluate(p *Problem, loc *Location, op Operation, x []float64) { if !op.isEvaluation() { panic(fmt.Sprintf("optimize: invalid evaluation %v", op)) } copy(x, loc.X) if op&FuncEvaluation != 0 { loc.F = p.Func(x) } if op&GradEvaluation != 0 { // Make sure we have a destination in which to place the gradient. if len(loc.Gradient) == 0 { if cap(loc.Gradient) < len(x) { loc.Gradient = make([]float64, len(x)) } else { loc.Gradient = loc.Gradient[:len(x)] } } p.Grad(loc.Gradient, x) } if op&HessEvaluation != 0 { // Make sure we have a destination in which to place the Hessian. switch { case loc.Hessian == nil: loc.Hessian = mat.NewSymDense(len(x), nil) case loc.Hessian.IsEmpty(): loc.Hessian.ReuseAsSym(len(x)) } p.Hess(loc.Hessian, x) } } // updateEvaluationStats updates the statistics based on the operation. func updateEvaluationStats(stats *Stats, op Operation) { if op&FuncEvaluation != 0 { stats.FuncEvaluations++ } if op&GradEvaluation != 0 { stats.GradEvaluations++ } if op&HessEvaluation != 0 { stats.HessEvaluations++ } } // checkLocationConvergence checks if the current optimal location satisfies // any of the convergence criteria based on the function location. // // checkLocationConvergence returns NotTerminated if the Location does not satisfy // the convergence criteria given by settings. Otherwise a corresponding status is // returned. // Unlike checkLimits, checkConvergence is called only at MajorIterations. func checkLocationConvergence(loc *Location, settings *Settings, converger Converger) Status { if math.IsInf(loc.F, -1) { return FunctionNegativeInfinity } if loc.Gradient != nil && settings.GradientThreshold > 0 { norm := floats.Norm(loc.Gradient, math.Inf(1)) if norm < settings.GradientThreshold { return GradientThreshold } } return converger.Converged(loc) } // checkEvaluationLimits checks the optimization limits after an evaluation // Operation. It checks the number of evaluations (of various kinds) and checks // the status of the Problem, if applicable. func checkEvaluationLimits(p *Problem, stats *Stats, settings *Settings) (Status, error) { if p.Status != nil { status, err := p.Status() if err != nil || status != NotTerminated { return status, err } } if settings.FuncEvaluations > 0 && stats.FuncEvaluations >= settings.FuncEvaluations { return FunctionEvaluationLimit, nil } if settings.GradEvaluations > 0 && stats.GradEvaluations >= settings.GradEvaluations { return GradientEvaluationLimit, nil } if settings.HessEvaluations > 0 && stats.HessEvaluations >= settings.HessEvaluations { return HessianEvaluationLimit, nil } return NotTerminated, nil } // checkIterationLimits checks the limits on iterations affected by MajorIteration. func checkIterationLimits(loc *Location, stats *Stats, settings *Settings) Status { if settings.MajorIterations > 0 && stats.MajorIterations >= settings.MajorIterations { return IterationLimit } if settings.Runtime > 0 && stats.Runtime >= settings.Runtime { return RuntimeLimit } return NotTerminated } // performMajorIteration does all of the steps needed to perform a MajorIteration. // It increments the iteration count, updates the optimal location, and checks // the necessary convergence criteria. func performMajorIteration(optLoc, loc *Location, stats *Stats, converger Converger, startTime time.Time, settings *Settings) Status { optLoc.F = loc.F copy(optLoc.X, loc.X) if loc.Gradient == nil { optLoc.Gradient = nil } else { if optLoc.Gradient == nil { optLoc.Gradient = make([]float64, len(loc.Gradient)) } copy(optLoc.Gradient, loc.Gradient) } stats.MajorIterations++ stats.Runtime = time.Since(startTime) status := checkLocationConvergence(optLoc, settings, converger) if status != NotTerminated { return status } return checkIterationLimits(optLoc, stats, settings) } golang-gonum-v1-gonum-0.14.0/optimize/morethuente.go000066400000000000000000000256031450372207100223720ustar00rootroot00000000000000// 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 optimize import "math" var _ Linesearcher = (*MoreThuente)(nil) // MoreThuente is a Linesearcher that finds steps that satisfy both the // sufficient decrease and curvature conditions (the strong Wolfe conditions). // // References: // - More, J.J. and D.J. Thuente: Line Search Algorithms with Guaranteed Sufficient // Decrease. ACM Transactions on Mathematical Software 20(3) (1994), 286-307 type MoreThuente struct { // DecreaseFactor is the constant factor in the sufficient decrease // (Armijo) condition. // It must be in the interval [0, 1). The default value is 0. DecreaseFactor float64 // CurvatureFactor is the constant factor in the Wolfe conditions. Smaller // values result in a more exact line search. // A set value must be in the interval (0, 1). If it is zero, it will be // defaulted to 0.9. CurvatureFactor float64 // StepTolerance sets the minimum acceptable width for the linesearch // interval. If the relative interval length is less than this value, // ErrLinesearcherFailure is returned. // It must be non-negative. If it is zero, it will be defaulted to 1e-10. StepTolerance float64 // MinimumStep is the minimum step that the linesearcher will take. // It must be non-negative and less than MaximumStep. Defaults to no // minimum (a value of 0). MinimumStep float64 // MaximumStep is the maximum step that the linesearcher will take. // It must be greater than MinimumStep. If it is zero, it will be defaulted // to 1e20. MaximumStep float64 bracketed bool // Indicates if a minimum has been bracketed. fInit float64 // Function value at step = 0. gInit float64 // Derivative value at step = 0. // When stage is 1, the algorithm updates the interval given by x and y // so that it contains a minimizer of the modified function // psi(step) = f(step) - f(0) - DecreaseFactor * step * f'(0). // When stage is 2, the interval is updated so that it contains a minimizer // of f. stage int step float64 // Current step. lower, upper float64 // Lower and upper bounds on the next step. x float64 // Endpoint of the interval with a lower function value. fx, gx float64 // Data at x. y float64 // The other endpoint. fy, gy float64 // Data at y. width [2]float64 // Width of the interval at two previous iterations. } const ( mtMinGrowthFactor float64 = 1.1 mtMaxGrowthFactor float64 = 4 ) func (mt *MoreThuente) Init(f, g float64, step float64) Operation { // Based on the original Fortran code that is available, for example, from // http://ftp.mcs.anl.gov/pub/MINPACK-2/csrch/ // as part of // MINPACK-2 Project. November 1993. // Argonne National Laboratory and University of Minnesota. // Brett M. Averick, Richard G. Carter, and Jorge J. Moré. if g >= 0 { panic("morethuente: initial derivative is non-negative") } if step <= 0 { panic("morethuente: invalid initial step") } if mt.CurvatureFactor == 0 { mt.CurvatureFactor = 0.9 } if mt.StepTolerance == 0 { mt.StepTolerance = 1e-10 } if mt.MaximumStep == 0 { mt.MaximumStep = 1e20 } if mt.MinimumStep < 0 { panic("morethuente: minimum step is negative") } if mt.MaximumStep <= mt.MinimumStep { panic("morethuente: maximum step is not greater than minimum step") } if mt.DecreaseFactor < 0 || mt.DecreaseFactor >= 1 { panic("morethuente: invalid decrease factor") } if mt.CurvatureFactor <= 0 || mt.CurvatureFactor >= 1 { panic("morethuente: invalid curvature factor") } if mt.StepTolerance <= 0 { panic("morethuente: step tolerance is not positive") } if step < mt.MinimumStep { step = mt.MinimumStep } if step > mt.MaximumStep { step = mt.MaximumStep } mt.bracketed = false mt.stage = 1 mt.fInit = f mt.gInit = g mt.x, mt.fx, mt.gx = 0, f, g mt.y, mt.fy, mt.gy = 0, f, g mt.lower = 0 mt.upper = step + mtMaxGrowthFactor*step mt.width[0] = mt.MaximumStep - mt.MinimumStep mt.width[1] = 2 * mt.width[0] mt.step = step return FuncEvaluation | GradEvaluation } func (mt *MoreThuente) Iterate(f, g float64) (Operation, float64, error) { if mt.stage == 0 { panic("morethuente: Init has not been called") } gTest := mt.DecreaseFactor * mt.gInit fTest := mt.fInit + mt.step*gTest if mt.bracketed { if mt.step <= mt.lower || mt.step >= mt.upper || mt.upper-mt.lower <= mt.StepTolerance*mt.upper { // step contains the best step found (see below). return NoOperation, mt.step, ErrLinesearcherFailure } } if mt.step == mt.MaximumStep && f <= fTest && g <= gTest { return NoOperation, mt.step, ErrLinesearcherBound } if mt.step == mt.MinimumStep && (f > fTest || g >= gTest) { return NoOperation, mt.step, ErrLinesearcherFailure } // Test for convergence. if f <= fTest && math.Abs(g) <= mt.CurvatureFactor*(-mt.gInit) { mt.stage = 0 return MajorIteration, mt.step, nil } if mt.stage == 1 && f <= fTest && g >= 0 { mt.stage = 2 } if mt.stage == 1 && f <= mt.fx && f > fTest { // Lower function value but the decrease is not sufficient . // Compute values and derivatives of the modified function at step, x, y. fm := f - mt.step*gTest fxm := mt.fx - mt.x*gTest fym := mt.fy - mt.y*gTest gm := g - gTest gxm := mt.gx - gTest gym := mt.gy - gTest // Update x, y and step. mt.nextStep(fxm, gxm, fym, gym, fm, gm) // Recover values and derivates of the non-modified function at x and y. mt.fx = fxm + mt.x*gTest mt.fy = fym + mt.y*gTest mt.gx = gxm + gTest mt.gy = gym + gTest } else { // Update x, y and step. mt.nextStep(mt.fx, mt.gx, mt.fy, mt.gy, f, g) } if mt.bracketed { // Monitor the length of the bracketing interval. If the interval has // not been reduced sufficiently after two steps, use bisection to // force its length to zero. width := mt.y - mt.x if math.Abs(width) >= 2.0/3*mt.width[1] { mt.step = mt.x + 0.5*width } mt.width[0], mt.width[1] = math.Abs(width), mt.width[0] } if mt.bracketed { mt.lower = math.Min(mt.x, mt.y) mt.upper = math.Max(mt.x, mt.y) } else { mt.lower = mt.step + mtMinGrowthFactor*(mt.step-mt.x) mt.upper = mt.step + mtMaxGrowthFactor*(mt.step-mt.x) } // Force the step to be in [MinimumStep, MaximumStep]. mt.step = math.Max(mt.MinimumStep, math.Min(mt.step, mt.MaximumStep)) if mt.bracketed { if mt.step <= mt.lower || mt.step >= mt.upper || mt.upper-mt.lower <= mt.StepTolerance*mt.upper { // If further progress is not possible, set step to the best step // obtained during the search. mt.step = mt.x } } return FuncEvaluation | GradEvaluation, mt.step, nil } // nextStep computes the next safeguarded step and updates the interval that // contains a step that satisfies the sufficient decrease and curvature // conditions. func (mt *MoreThuente) nextStep(fx, gx, fy, gy, f, g float64) { x := mt.x y := mt.y step := mt.step gNeg := g < 0 if gx < 0 { gNeg = !gNeg } var next float64 var bracketed bool switch { case f > fx: // A higher function value. The minimum is bracketed between x and step. // We want the next step to be closer to x because the function value // there is lower. theta := 3*(fx-f)/(step-x) + gx + g s := math.Max(math.Abs(gx), math.Abs(g)) s = math.Max(s, math.Abs(theta)) gamma := s * math.Sqrt((theta/s)*(theta/s)-(gx/s)*(g/s)) if step < x { gamma *= -1 } p := gamma - gx + theta q := gamma - gx + gamma + g r := p / q stpc := x + r*(step-x) stpq := x + gx/((fx-f)/(step-x)+gx)/2*(step-x) if math.Abs(stpc-x) < math.Abs(stpq-x) { // The cubic step is closer to x than the quadratic step. // Take the cubic step. next = stpc } else { // If f is much larger than fx, then the quadratic step may be too // close to x. Therefore heuristically take the average of the // cubic and quadratic steps. next = stpc + (stpq-stpc)/2 } bracketed = true case gNeg: // A lower function value and derivatives of opposite sign. The minimum // is bracketed between x and step. If we choose a step that is far // from step, the next iteration will also likely fall in this case. theta := 3*(fx-f)/(step-x) + gx + g s := math.Max(math.Abs(gx), math.Abs(g)) s = math.Max(s, math.Abs(theta)) gamma := s * math.Sqrt((theta/s)*(theta/s)-(gx/s)*(g/s)) if step > x { gamma *= -1 } p := gamma - g + theta q := gamma - g + gamma + gx r := p / q stpc := step + r*(x-step) stpq := step + g/(g-gx)*(x-step) if math.Abs(stpc-step) > math.Abs(stpq-step) { // The cubic step is farther from x than the quadratic step. // Take the cubic step. next = stpc } else { // Take the quadratic step. next = stpq } bracketed = true case math.Abs(g) < math.Abs(gx): // A lower function value, derivatives of the same sign, and the // magnitude of the derivative decreases. Extrapolate function values // at x and step so that the next step lies between step and y. theta := 3*(fx-f)/(step-x) + gx + g s := math.Max(math.Abs(gx), math.Abs(g)) s = math.Max(s, math.Abs(theta)) gamma := s * math.Sqrt(math.Max(0, (theta/s)*(theta/s)-(gx/s)*(g/s))) if step > x { gamma *= -1 } p := gamma - g + theta q := gamma + gx - g + gamma r := p / q var stpc float64 switch { case r < 0 && gamma != 0: stpc = step + r*(x-step) case step > x: stpc = mt.upper default: stpc = mt.lower } stpq := step + g/(g-gx)*(x-step) if mt.bracketed { // We are extrapolating so be cautious and take the step that // is closer to step. if math.Abs(stpc-step) < math.Abs(stpq-step) { next = stpc } else { next = stpq } // Modify next if it is close to or beyond y. if step > x { next = math.Min(step+2.0/3*(y-step), next) } else { next = math.Max(step+2.0/3*(y-step), next) } } else { // Minimum has not been bracketed so take the larger step... if math.Abs(stpc-step) > math.Abs(stpq-step) { next = stpc } else { next = stpq } // ...but within reason. next = math.Max(mt.lower, math.Min(next, mt.upper)) } default: // A lower function value, derivatives of the same sign, and the // magnitude of the derivative does not decrease. The function seems to // decrease rapidly in the direction of the step. switch { case mt.bracketed: theta := 3*(f-fy)/(y-step) + gy + g s := math.Max(math.Abs(gy), math.Abs(g)) s = math.Max(s, math.Abs(theta)) gamma := s * math.Sqrt((theta/s)*(theta/s)-(gy/s)*(g/s)) if step > y { gamma *= -1 } p := gamma - g + theta q := gamma - g + gamma + gy r := p / q next = step + r*(y-step) case step > x: next = mt.upper default: next = mt.lower } } if f > fx { // x is still the best step. mt.y = step mt.fy = f mt.gy = g } else { // step is the new best step. if gNeg { mt.y = x mt.fy = fx mt.gy = gx } mt.x = step mt.fx = f mt.gx = g } mt.bracketed = bracketed mt.step = next } golang-gonum-v1-gonum-0.14.0/optimize/neldermead.go000066400000000000000000000226621450372207100221350ustar00rootroot00000000000000// 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 optimize import ( "math" "sort" "gonum.org/v1/gonum/floats" ) // nmIterType is a Nelder-Mead evaluation kind type nmIterType int const ( nmReflected = iota nmExpanded nmContractedInside nmContractedOutside nmInitialize nmShrink nmMajor ) type nmVertexSorter struct { vertices [][]float64 values []float64 } func (n nmVertexSorter) Len() int { return len(n.values) } func (n nmVertexSorter) Less(i, j int) bool { return n.values[i] < n.values[j] } func (n nmVertexSorter) Swap(i, j int) { n.values[i], n.values[j] = n.values[j], n.values[i] n.vertices[i], n.vertices[j] = n.vertices[j], n.vertices[i] } var _ Method = (*NelderMead)(nil) // NelderMead is an implementation of the Nelder-Mead simplex algorithm for // gradient-free nonlinear optimization (not to be confused with Danzig's // simplex algorithm for linear programming). The implementation follows the // algorithm described in // // http://epubs.siam.org/doi/pdf/10.1137/S1052623496303470 // // If an initial simplex is provided, it is used and initLoc is ignored. If // InitialVertices and InitialValues are both nil, an initial simplex will be // generated automatically using the initial location as one vertex, and each // additional vertex as SimplexSize away in one dimension. // // If the simplex update parameters (Reflection, etc.) // are zero, they will be set automatically based on the dimension according to // the recommendations in // // http://www.webpages.uidaho.edu/~fuchang/res/ANMS.pdf type NelderMead struct { InitialVertices [][]float64 InitialValues []float64 Reflection float64 // Reflection parameter (>0) Expansion float64 // Expansion parameter (>1) Contraction float64 // Contraction parameter (>0, <1) Shrink float64 // Shrink parameter (>0, <1) SimplexSize float64 // size of auto-constructed initial simplex status Status err error reflection float64 expansion float64 contraction float64 shrink float64 vertices [][]float64 // location of the vertices sorted in ascending f values []float64 // function values at the vertices sorted in ascending f centroid []float64 // centroid of all but the worst vertex fillIdx int // index for filling the simplex during initialization and shrinking lastIter nmIterType // Last iteration reflectedPoint []float64 // Storage of the reflected point location reflectedValue float64 // Value at the last reflection point } func (n *NelderMead) Status() (Status, error) { return n.status, n.err } func (*NelderMead) Uses(has Available) (uses Available, err error) { return has.function() } func (n *NelderMead) Init(dim, tasks int) int { n.status = NotTerminated n.err = nil return 1 } func (n *NelderMead) Run(operation chan<- Task, result <-chan Task, tasks []Task) { n.status, n.err = localOptimizer{}.run(n, math.NaN(), operation, result, tasks) close(operation) } func (n *NelderMead) initLocal(loc *Location) (Operation, error) { dim := len(loc.X) if cap(n.vertices) < dim+1 { n.vertices = make([][]float64, dim+1) } n.vertices = n.vertices[:dim+1] for i := range n.vertices { n.vertices[i] = resize(n.vertices[i], dim) } n.values = resize(n.values, dim+1) n.centroid = resize(n.centroid, dim) n.reflectedPoint = resize(n.reflectedPoint, dim) if n.SimplexSize == 0 { n.SimplexSize = 0.05 } // Default parameter choices are chosen in a dimension-dependent way // from http://www.webpages.uidaho.edu/~fuchang/res/ANMS.pdf n.reflection = n.Reflection if n.reflection == 0 { n.reflection = 1 } n.expansion = n.Expansion if n.expansion == 0 { n.expansion = 1 + 2/float64(dim) if dim == 1 { n.expansion = 2 } } n.contraction = n.Contraction if n.contraction == 0 { n.contraction = 0.75 - 1/(2*float64(dim)) if dim == 1 { n.contraction = 0.5 } } n.shrink = n.Shrink if n.shrink == 0 { n.shrink = 1 - 1/float64(dim) if dim == 1 { n.shrink = 0.5 } } if n.InitialVertices != nil { // Initial simplex provided. Copy the locations and values, and sort them. if len(n.InitialVertices) != dim+1 { panic("neldermead: incorrect number of vertices in initial simplex") } if len(n.InitialValues) != dim+1 { panic("neldermead: incorrect number of values in initial simplex") } for i := range n.InitialVertices { if len(n.InitialVertices[i]) != dim { panic("neldermead: vertex size mismatch") } copy(n.vertices[i], n.InitialVertices[i]) } copy(n.values, n.InitialValues) sort.Sort(nmVertexSorter{n.vertices, n.values}) computeCentroid(n.vertices, n.centroid) return n.returnNext(nmMajor, loc) } // No simplex provided. Begin initializing initial simplex. First simplex // entry is the initial location, then step 1 in every direction. copy(n.vertices[dim], loc.X) n.values[dim] = loc.F n.fillIdx = 0 loc.X[n.fillIdx] += n.SimplexSize n.lastIter = nmInitialize return FuncEvaluation, nil } // computeCentroid computes the centroid of all the simplex vertices except the // final one func computeCentroid(vertices [][]float64, centroid []float64) { dim := len(centroid) for i := range centroid { centroid[i] = 0 } for i := 0; i < dim; i++ { vertex := vertices[i] for j, v := range vertex { centroid[j] += v } } for i := range centroid { centroid[i] /= float64(dim) } } func (n *NelderMead) iterateLocal(loc *Location) (Operation, error) { dim := len(loc.X) switch n.lastIter { case nmInitialize: n.values[n.fillIdx] = loc.F copy(n.vertices[n.fillIdx], loc.X) n.fillIdx++ if n.fillIdx == dim { // Successfully finished building initial simplex. sort.Sort(nmVertexSorter{n.vertices, n.values}) computeCentroid(n.vertices, n.centroid) return n.returnNext(nmMajor, loc) } copy(loc.X, n.vertices[dim]) loc.X[n.fillIdx] += n.SimplexSize return FuncEvaluation, nil case nmMajor: // Nelder Mead iterations start with Reflection step return n.returnNext(nmReflected, loc) case nmReflected: n.reflectedValue = loc.F switch { case loc.F >= n.values[0] && loc.F < n.values[dim-1]: n.replaceWorst(loc.X, loc.F) return n.returnNext(nmMajor, loc) case loc.F < n.values[0]: return n.returnNext(nmExpanded, loc) default: if loc.F < n.values[dim] { return n.returnNext(nmContractedOutside, loc) } return n.returnNext(nmContractedInside, loc) } case nmExpanded: if loc.F < n.reflectedValue { n.replaceWorst(loc.X, loc.F) } else { n.replaceWorst(n.reflectedPoint, n.reflectedValue) } return n.returnNext(nmMajor, loc) case nmContractedOutside: if loc.F <= n.reflectedValue { n.replaceWorst(loc.X, loc.F) return n.returnNext(nmMajor, loc) } n.fillIdx = 1 return n.returnNext(nmShrink, loc) case nmContractedInside: if loc.F < n.values[dim] { n.replaceWorst(loc.X, loc.F) return n.returnNext(nmMajor, loc) } n.fillIdx = 1 return n.returnNext(nmShrink, loc) case nmShrink: copy(n.vertices[n.fillIdx], loc.X) n.values[n.fillIdx] = loc.F n.fillIdx++ if n.fillIdx != dim+1 { return n.returnNext(nmShrink, loc) } sort.Sort(nmVertexSorter{n.vertices, n.values}) computeCentroid(n.vertices, n.centroid) return n.returnNext(nmMajor, loc) default: panic("unreachable") } } // returnNext updates the location based on the iteration type and the current // simplex, and returns the next operation. func (n *NelderMead) returnNext(iter nmIterType, loc *Location) (Operation, error) { n.lastIter = iter switch iter { case nmMajor: // Fill loc with the current best point and value, // and command a convergence check. copy(loc.X, n.vertices[0]) loc.F = n.values[0] return MajorIteration, nil case nmReflected, nmExpanded, nmContractedOutside, nmContractedInside: // x_new = x_centroid + scale * (x_centroid - x_worst) var scale float64 switch iter { case nmReflected: scale = n.reflection case nmExpanded: scale = n.reflection * n.expansion case nmContractedOutside: scale = n.reflection * n.contraction case nmContractedInside: scale = -n.contraction } dim := len(loc.X) floats.SubTo(loc.X, n.centroid, n.vertices[dim]) floats.Scale(scale, loc.X) floats.Add(loc.X, n.centroid) if iter == nmReflected { copy(n.reflectedPoint, loc.X) } return FuncEvaluation, nil case nmShrink: // x_shrink = x_best + delta * (x_i + x_best) floats.SubTo(loc.X, n.vertices[n.fillIdx], n.vertices[0]) floats.Scale(n.shrink, loc.X) floats.Add(loc.X, n.vertices[0]) return FuncEvaluation, nil default: panic("unreachable") } } // replaceWorst removes the worst location in the simplex and adds the new // {x, f} pair maintaining sorting. func (n *NelderMead) replaceWorst(x []float64, f float64) { dim := len(x) if f >= n.values[dim] { panic("increase in simplex value") } copy(n.vertices[dim], x) n.values[dim] = f // Sort the newly-added value. for i := dim - 1; i >= 0; i-- { if n.values[i] < f { break } n.vertices[i], n.vertices[i+1] = n.vertices[i+1], n.vertices[i] n.values[i], n.values[i+1] = n.values[i+1], n.values[i] } // Update the location of the centroid. Only one point has been replaced, so // subtract the worst point and add the new one. floats.AddScaled(n.centroid, -1/float64(dim), n.vertices[dim]) floats.AddScaled(n.centroid, 1/float64(dim), x) } func (*NelderMead) needs() struct { Gradient bool Hessian bool } { return struct { Gradient bool Hessian bool }{false, false} } golang-gonum-v1-gonum-0.14.0/optimize/newton.go000066400000000000000000000125171450372207100213450ustar00rootroot00000000000000// 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 optimize import ( "math" "gonum.org/v1/gonum/mat" ) const maxNewtonModifications = 20 var ( _ Method = (*Newton)(nil) _ localMethod = (*Newton)(nil) _ NextDirectioner = (*Newton)(nil) ) // Newton implements a modified Newton's method for Hessian-based unconstrained // minimization. It applies regularization when the Hessian is not positive // definite, and it can converge to a local minimum from any starting point. // // Newton iteratively forms a quadratic model to the objective function f and // tries to minimize this approximate model. It generates a sequence of // locations x_k by means of // // solve H_k d_k = -∇f_k for d_k, // x_{k+1} = x_k + α_k d_k, // // where H_k is the Hessian matrix of f at x_k and α_k is a step size found by // a line search. // // Away from a minimizer H_k may not be positive definite and d_k may not be a // descent direction. Newton implements a Hessian modification strategy that // adds successively larger multiples of identity to H_k until it becomes // positive definite. Note that the repeated trial factorization of the // modified Hessian involved in this process can be computationally expensive. // // If the Hessian matrix cannot be formed explicitly or if the computational // cost of its factorization is prohibitive, BFGS or L-BFGS quasi-Newton method // can be used instead. type Newton struct { // Linesearcher is used for selecting suitable steps along the descent // direction d. Accepted steps should satisfy at least one of the Wolfe, // Goldstein or Armijo conditions. // If Linesearcher == nil, an appropriate default is chosen. Linesearcher Linesearcher // Increase is the factor by which a scalar tau is successively increased // so that (H + tau*I) is positive definite. Larger values reduce the // number of trial Hessian factorizations, but also reduce the second-order // information in H. // Increase must be greater than 1. If Increase is 0, it is defaulted to 5. Increase float64 // GradStopThreshold sets the threshold for stopping if the gradient norm // gets too small. If GradStopThreshold is 0 it is defaulted to 1e-12, and // if it is NaN the setting is not used. GradStopThreshold float64 status Status err error ls *LinesearchMethod hess *mat.SymDense // Storage for a copy of the Hessian matrix. chol mat.Cholesky // Storage for the Cholesky factorization. tau float64 } func (n *Newton) Status() (Status, error) { return n.status, n.err } func (*Newton) Uses(has Available) (uses Available, err error) { return has.hessian() } func (n *Newton) Init(dim, tasks int) int { n.status = NotTerminated n.err = nil return 1 } func (n *Newton) Run(operation chan<- Task, result <-chan Task, tasks []Task) { n.status, n.err = localOptimizer{}.run(n, n.GradStopThreshold, operation, result, tasks) close(operation) } func (n *Newton) initLocal(loc *Location) (Operation, error) { if n.Increase == 0 { n.Increase = 5 } if n.Increase <= 1 { panic("optimize: Newton.Increase must be greater than 1") } if n.Linesearcher == nil { n.Linesearcher = &Bisection{} } if n.ls == nil { n.ls = &LinesearchMethod{} } n.ls.Linesearcher = n.Linesearcher n.ls.NextDirectioner = n return n.ls.Init(loc) } func (n *Newton) iterateLocal(loc *Location) (Operation, error) { return n.ls.Iterate(loc) } func (n *Newton) InitDirection(loc *Location, dir []float64) (stepSize float64) { dim := len(loc.X) n.hess = resizeSymDense(n.hess, dim) n.tau = 0 return n.NextDirection(loc, dir) } func (n *Newton) NextDirection(loc *Location, dir []float64) (stepSize float64) { // This method implements Algorithm 3.3 (Cholesky with Added Multiple of // the Identity) from Nocedal, Wright (2006), 2nd edition. dim := len(loc.X) d := mat.NewVecDense(dim, dir) grad := mat.NewVecDense(dim, loc.Gradient) n.hess.CopySym(loc.Hessian) // Find the smallest diagonal entry of the Hessian. minA := n.hess.At(0, 0) for i := 1; i < dim; i++ { a := n.hess.At(i, i) if a < minA { minA = a } } // If the smallest diagonal entry is positive, the Hessian may be positive // definite, and so first attempt to apply the Cholesky factorization to // the un-modified Hessian. If the smallest entry is negative, use the // final tau from the last iteration if regularization was needed, // otherwise guess an appropriate value for tau. if minA > 0 { n.tau = 0 } else if n.tau == 0 { n.tau = -minA + 0.001 } for k := 0; k < maxNewtonModifications; k++ { if n.tau != 0 { // Add a multiple of identity to the Hessian. for i := 0; i < dim; i++ { n.hess.SetSym(i, i, loc.Hessian.At(i, i)+n.tau) } } // Try to apply the Cholesky factorization. pd := n.chol.Factorize(n.hess) if pd { // Store the solution in d's backing array, dir. err := n.chol.SolveVecTo(d, grad) if err == nil { d.ScaleVec(-1, d) return 1 } } // Modified Hessian is not PD, so increase tau. n.tau = math.Max(n.Increase*n.tau, 0.001) } // Hessian modification failed to get a PD matrix. Return the negative // gradient as the descent direction. d.ScaleVec(-1, grad) return 1 } func (n *Newton) needs() struct { Gradient bool Hessian bool } { return struct { Gradient bool Hessian bool }{true, true} } golang-gonum-v1-gonum-0.14.0/optimize/printer.go000066400000000000000000000055631450372207100215210ustar00rootroot00000000000000// 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 optimize import ( "fmt" "io" "math" "os" "time" "gonum.org/v1/gonum/floats" ) var printerHeadings = [...]string{ "Iter", "Runtime", "FuncEvals", "Func", "GradEvals", "|Gradient|∞", "HessEvals", } const ( printerBaseTmpl = "%9v %16v %9v %22v" // Base template for headings and values that are always printed. printerGradTmpl = " %9v %22v" // Appended to base template when loc.Gradient != nil. printerHessTmpl = " %9v" // Appended to base template when loc.Hessian != nil. ) var _ Recorder = (*Printer)(nil) // Printer writes column-format output to the specified writer as the optimization // progresses. By default, it writes to os.Stdout. type Printer struct { Writer io.Writer HeadingInterval int ValueInterval time.Duration lastHeading int lastValue time.Time } func NewPrinter() *Printer { return &Printer{ Writer: os.Stdout, HeadingInterval: 30, ValueInterval: 500 * time.Millisecond, } } func (p *Printer) Init() error { p.lastHeading = p.HeadingInterval // So the headings are printed the first time. p.lastValue = time.Now().Add(-p.ValueInterval) // So the values are printed the first time. return nil } func (p *Printer) Record(loc *Location, op Operation, stats *Stats) error { if op != MajorIteration && op != InitIteration && op != PostIteration { return nil } // Print values always on PostIteration or when ValueInterval has elapsed. printValues := time.Since(p.lastValue) > p.ValueInterval || op == PostIteration if !printValues { // Return early if not printing anything. return nil } // Print heading when HeadingInterval lines have been printed, but never on PostIteration. printHeading := p.lastHeading >= p.HeadingInterval && op != PostIteration if printHeading { p.lastHeading = 1 } else { p.lastHeading++ } if printHeading { headings := "\n" + fmt.Sprintf(printerBaseTmpl, printerHeadings[0], printerHeadings[1], printerHeadings[2], printerHeadings[3]) if loc.Gradient != nil { headings += fmt.Sprintf(printerGradTmpl, printerHeadings[4], printerHeadings[5]) } if loc.Hessian != nil { headings += fmt.Sprintf(printerHessTmpl, printerHeadings[6]) } _, err := fmt.Fprintln(p.Writer, headings) if err != nil { return err } } values := fmt.Sprintf(printerBaseTmpl, stats.MajorIterations, stats.Runtime, stats.FuncEvaluations, loc.F) if loc.Gradient != nil { values += fmt.Sprintf(printerGradTmpl, stats.GradEvaluations, floats.Norm(loc.Gradient, math.Inf(1))) } if loc.Hessian != nil { values += fmt.Sprintf(printerHessTmpl, stats.HessEvaluations) } _, err := fmt.Fprintln(p.Writer, values) if err != nil { return err } p.lastValue = time.Now() return nil } golang-gonum-v1-gonum-0.14.0/optimize/stepsizers.go000066400000000000000000000145771450372207100222560ustar00rootroot00000000000000// 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 optimize import ( "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) const ( initialStepFactor = 1 quadraticMinimumStepSize = 1e-3 quadraticMaximumStepSize = 1 quadraticThreshold = 1e-12 firstOrderMinimumStepSize = quadraticMinimumStepSize firstOrderMaximumStepSize = quadraticMaximumStepSize ) var ( _ StepSizer = ConstantStepSize{} _ StepSizer = (*QuadraticStepSize)(nil) _ StepSizer = (*FirstOrderStepSize)(nil) ) // ConstantStepSize is a StepSizer that returns the same step size for // every iteration. type ConstantStepSize struct { Size float64 } func (c ConstantStepSize) Init(_ *Location, _ []float64) float64 { return c.Size } func (c ConstantStepSize) StepSize(_ *Location, _ []float64) float64 { return c.Size } // QuadraticStepSize estimates the initial line search step size as the minimum // of a quadratic that interpolates f(x_{k-1}), f(x_k) and ∇f_k⋅p_k. // This is useful for line search methods that do not produce well-scaled // descent directions, such as gradient descent or conjugate gradient methods. // The step size is bounded away from zero. type QuadraticStepSize struct { // Threshold determines that the initial step size should be estimated by // quadratic interpolation when the relative change in the objective // function is larger than Threshold. Otherwise the initial step size is // set to 2*previous step size. // If Threshold is zero, it will be set to 1e-12. Threshold float64 // InitialStepFactor sets the step size for the first iteration to be InitialStepFactor / |g|_∞. // If InitialStepFactor is zero, it will be set to one. InitialStepFactor float64 // MinStepSize is the lower bound on the estimated step size. // MinStepSize times GradientAbsTol should always be greater than machine epsilon. // If MinStepSize is zero, it will be set to 1e-3. MinStepSize float64 // MaxStepSize is the upper bound on the estimated step size. // If MaxStepSize is zero, it will be set to 1. MaxStepSize float64 fPrev float64 dirPrevNorm float64 projGradPrev float64 xPrev []float64 } func (q *QuadraticStepSize) Init(loc *Location, dir []float64) (stepSize float64) { if q.Threshold == 0 { q.Threshold = quadraticThreshold } if q.InitialStepFactor == 0 { q.InitialStepFactor = initialStepFactor } if q.MinStepSize == 0 { q.MinStepSize = quadraticMinimumStepSize } if q.MaxStepSize == 0 { q.MaxStepSize = quadraticMaximumStepSize } if q.MaxStepSize <= q.MinStepSize { panic("optimize: MinStepSize not smaller than MaxStepSize") } gNorm := floats.Norm(loc.Gradient, math.Inf(1)) stepSize = math.Max(q.MinStepSize, math.Min(q.InitialStepFactor/gNorm, q.MaxStepSize)) q.fPrev = loc.F q.dirPrevNorm = floats.Norm(dir, 2) q.projGradPrev = floats.Dot(loc.Gradient, dir) q.xPrev = resize(q.xPrev, len(loc.X)) copy(q.xPrev, loc.X) return stepSize } func (q *QuadraticStepSize) StepSize(loc *Location, dir []float64) (stepSize float64) { stepSizePrev := floats.Distance(loc.X, q.xPrev, 2) / q.dirPrevNorm projGrad := floats.Dot(loc.Gradient, dir) stepSize = 2 * stepSizePrev if !scalar.EqualWithinRel(q.fPrev, loc.F, q.Threshold) { // Two consecutive function values are not relatively equal, so // computing the minimum of a quadratic interpolant might make sense df := (loc.F - q.fPrev) / stepSizePrev quadTest := df - q.projGradPrev if quadTest > 0 { // There is a chance of approximating the function well by a // quadratic only if the finite difference (f_k-f_{k-1})/stepSizePrev // is larger than ∇f_{k-1}⋅p_{k-1} // Set the step size to the minimizer of the quadratic function that // interpolates f_{k-1}, ∇f_{k-1}⋅p_{k-1} and f_k stepSize = -q.projGradPrev * stepSizePrev / quadTest / 2 } } // Bound the step size to lie in [MinStepSize, MaxStepSize] stepSize = math.Max(q.MinStepSize, math.Min(stepSize, q.MaxStepSize)) q.fPrev = loc.F q.dirPrevNorm = floats.Norm(dir, 2) q.projGradPrev = projGrad copy(q.xPrev, loc.X) return stepSize } // FirstOrderStepSize estimates the initial line search step size based on the // assumption that the first-order change in the function will be the same as // that obtained at the previous iteration. That is, the initial step size s^0_k // is chosen so that // // s^0_k ∇f_k⋅p_k = s_{k-1} ∇f_{k-1}⋅p_{k-1} // // This is useful for line search methods that do not produce well-scaled // descent directions, such as gradient descent or conjugate gradient methods. type FirstOrderStepSize struct { // InitialStepFactor sets the step size for the first iteration to be InitialStepFactor / |g|_∞. // If InitialStepFactor is zero, it will be set to one. InitialStepFactor float64 // MinStepSize is the lower bound on the estimated step size. // MinStepSize times GradientAbsTol should always be greater than machine epsilon. // If MinStepSize is zero, it will be set to 1e-3. MinStepSize float64 // MaxStepSize is the upper bound on the estimated step size. // If MaxStepSize is zero, it will be set to 1. MaxStepSize float64 dirPrevNorm float64 projGradPrev float64 xPrev []float64 } func (fo *FirstOrderStepSize) Init(loc *Location, dir []float64) (stepSize float64) { if fo.InitialStepFactor == 0 { fo.InitialStepFactor = initialStepFactor } if fo.MinStepSize == 0 { fo.MinStepSize = firstOrderMinimumStepSize } if fo.MaxStepSize == 0 { fo.MaxStepSize = firstOrderMaximumStepSize } if fo.MaxStepSize <= fo.MinStepSize { panic("optimize: MinStepSize not smaller than MaxStepSize") } gNorm := floats.Norm(loc.Gradient, math.Inf(1)) stepSize = math.Max(fo.MinStepSize, math.Min(fo.InitialStepFactor/gNorm, fo.MaxStepSize)) fo.dirPrevNorm = floats.Norm(dir, 2) fo.projGradPrev = floats.Dot(loc.Gradient, dir) fo.xPrev = resize(fo.xPrev, len(loc.X)) copy(fo.xPrev, loc.X) return stepSize } func (fo *FirstOrderStepSize) StepSize(loc *Location, dir []float64) (stepSize float64) { stepSizePrev := floats.Distance(loc.X, fo.xPrev, 2) / fo.dirPrevNorm projGrad := floats.Dot(loc.Gradient, dir) stepSize = stepSizePrev * fo.projGradPrev / projGrad stepSize = math.Max(fo.MinStepSize, math.Min(stepSize, fo.MaxStepSize)) fo.dirPrevNorm = floats.Norm(dir, 2) fo.projGradPrev = floats.Dot(loc.Gradient, dir) copy(fo.xPrev, loc.X) return stepSize } golang-gonum-v1-gonum-0.14.0/optimize/termination.go000066400000000000000000000055211450372207100223610ustar00rootroot00000000000000// 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 optimize import "errors" // Status represents the status of the optimization. Programs // should not rely on the underlying numeric value of the Status being constant. type Status int const ( NotTerminated Status = iota Success FunctionThreshold FunctionConvergence GradientThreshold StepConvergence FunctionNegativeInfinity MethodConverge Failure IterationLimit RuntimeLimit FunctionEvaluationLimit GradientEvaluationLimit HessianEvaluationLimit ) func (s Status) String() string { return statuses[s].name } // Early returns true if the status indicates the optimization ended before a // minimum was found. As an example, if the maximum iterations was reached, a // minimum was not found, but if the gradient norm was reached then a minimum // was found. func (s Status) Early() bool { return statuses[s].early } // Err returns the error associated with an early ending to the minimization. If // Early returns false, Err will return nil. func (s Status) Err() error { return statuses[s].err } var statuses = []struct { name string early bool err error }{ { name: "NotTerminated", }, { name: "Success", }, { name: "FunctionThreshold", }, { name: "FunctionConvergence", }, { name: "GradientThreshold", }, { name: "StepConvergence", }, { name: "FunctionNegativeInfinity", }, { name: "MethodConverge", }, { name: "Failure", early: true, err: errors.New("optimize: termination ended in failure"), }, { name: "IterationLimit", early: true, err: errors.New("optimize: maximum number of major iterations reached"), }, { name: "RuntimeLimit", early: true, err: errors.New("optimize: maximum runtime reached"), }, { name: "FunctionEvaluationLimit", early: true, err: errors.New("optimize: maximum number of function evaluations reached"), }, { name: "GradientEvaluationLimit", early: true, err: errors.New("optimize: maximum number of gradient evaluations reached"), }, { name: "HessianEvaluationLimit", early: true, err: errors.New("optimize: maximum number of Hessian evaluations reached"), }, } // NewStatus returns a unique Status variable to represent a custom status. // NewStatus is intended to be called only during package initialization, and // calls to NewStatus are not thread safe. // // NewStatus takes in three arguments, the string that should be output from // Status.String, a boolean if the status indicates early optimization conclusion, // and the error to return from Err (if any). func NewStatus(name string, early bool, err error) Status { statuses = append(statuses, struct { name string early bool err error }{name, early, err}) return Status(len(statuses) - 1) } golang-gonum-v1-gonum-0.14.0/optimize/types.go000066400000000000000000000230611450372207100211730ustar00rootroot00000000000000// 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 optimize import ( "fmt" "time" "gonum.org/v1/gonum/mat" ) const defaultGradientAbsTol = 1e-12 // Operation represents the set of operations commanded by Method at each // iteration. It is a bitmap of various Iteration and Evaluation constants. // Individual constants must NOT be combined together by the binary OR operator // except for the Evaluation operations. type Operation uint64 // Supported Operations. const ( // NoOperation specifies that no evaluation or convergence check should // take place. NoOperation Operation = 0 // InitIteration is sent to Recorder to indicate the initial location. // All fields of the location to record must be valid. // Method must not return it. InitIteration Operation = 1 << (iota - 1) // PostIteration is sent to Recorder to indicate the final location // reached during an optimization run. // All fields of the location to record must be valid. // Method must not return it. PostIteration // MajorIteration indicates that the next candidate location for // an optimum has been found and convergence should be checked. MajorIteration // MethodDone declares that the method is done running. A method must // be a Statuser in order to use this iteration, and after returning // MethodDone, the Status must return other than NotTerminated. MethodDone // FuncEvaluation specifies that the objective function // should be evaluated. FuncEvaluation // GradEvaluation specifies that the gradient // of the objective function should be evaluated. GradEvaluation // HessEvaluation specifies that the Hessian // of the objective function should be evaluated. HessEvaluation // signalDone is used internally to signal completion. signalDone // Mask for the evaluating operations. evalMask = FuncEvaluation | GradEvaluation | HessEvaluation ) func (op Operation) isEvaluation() bool { return op&evalMask != 0 && op&^evalMask == 0 } func (op Operation) String() string { if op&evalMask != 0 { return fmt.Sprintf("Evaluation(Func: %t, Grad: %t, Hess: %t, Extra: 0b%b)", op&FuncEvaluation != 0, op&GradEvaluation != 0, op&HessEvaluation != 0, op&^(evalMask)) } s, ok := operationNames[op] if ok { return s } return fmt.Sprintf("Operation(%d)", op) } var operationNames = map[Operation]string{ NoOperation: "NoOperation", InitIteration: "InitIteration", MajorIteration: "MajorIteration", PostIteration: "PostIteration", MethodDone: "MethodDone", signalDone: "signalDone", } // Result represents the answer of an optimization run. It contains the optimum // function value, X location, and gradient as well as the Status at convergence // and Statistics taken during the run. type Result struct { Location Stats Status Status } // Stats contains the statistics of the run. type Stats struct { MajorIterations int // Total number of major iterations FuncEvaluations int // Number of evaluations of Func GradEvaluations int // Number of evaluations of Grad HessEvaluations int // Number of evaluations of Hess Runtime time.Duration // Total runtime of the optimization } // complementEval returns an evaluating operation that evaluates fields of loc // not evaluated by eval. func complementEval(loc *Location, eval Operation) (complEval Operation) { if eval&FuncEvaluation == 0 { complEval = FuncEvaluation } if loc.Gradient != nil && eval&GradEvaluation == 0 { complEval |= GradEvaluation } if loc.Hessian != nil && eval&HessEvaluation == 0 { complEval |= HessEvaluation } return complEval } // Problem describes the optimization problem to be solved. type Problem struct { // Func evaluates the objective function at the given location. Func // must not modify x. Func func(x []float64) float64 // Grad evaluates the gradient at x and stores the result in grad which will // be the same length as x. Grad must not modify x. Grad func(grad, x []float64) // Hess evaluates the Hessian at x and stores the result in-place in hess which // will have dimensions matching the length of x. Hess must not modify x. Hess func(hess *mat.SymDense, x []float64) // Status reports the status of the objective function being optimized and any // error. This can be used to terminate early, for example when the function is // not able to evaluate itself. The user can use one of the pre-provided Status // constants, or may call NewStatus to create a custom Status value. Status func() (Status, error) } // Available describes the functions available to call in Problem. type Available struct { Grad bool Hess bool } func availFromProblem(prob Problem) Available { return Available{Grad: prob.Grad != nil, Hess: prob.Hess != nil} } // function tests if the Problem described by the receiver is suitable for an // unconstrained Method that only calls the function, and returns the result. func (has Available) function() (uses Available, err error) { // TODO(btracey): This needs to be modified when optimize supports // constrained optimization. return Available{}, nil } // gradient tests if the Problem described by the receiver is suitable for an // unconstrained gradient-based Method, and returns the result. func (has Available) gradient() (uses Available, err error) { // TODO(btracey): This needs to be modified when optimize supports // constrained optimization. if !has.Grad { return Available{}, ErrMissingGrad } return Available{Grad: true}, nil } // hessian tests if the Problem described by the receiver is suitable for an // unconstrained Hessian-based Method, and returns the result. func (has Available) hessian() (uses Available, err error) { // TODO(btracey): This needs to be modified when optimize supports // constrained optimization. if !has.Grad { return Available{}, ErrMissingGrad } if !has.Hess { return Available{}, ErrMissingHess } return Available{Grad: true, Hess: true}, nil } // Settings represents settings of the optimization run. It contains initial // settings, convergence information, and Recorder information. Convergence // settings are only checked at MajorIterations, while Evaluation thresholds // are checked at every Operation. See the field comments for default values. type Settings struct { // InitValues specifies properties (function value, gradient, etc.) known // at the initial location passed to Minimize. If InitValues is non-nil, then // the function value F must be provided, the location X must not be specified // and other fields may be specified. The values in Location may be modified // during the call to Minimize. InitValues *Location // GradientThreshold stops optimization with GradientThreshold status if the // infinity norm of the gradient is less than this value. This defaults to // a value of 0 (and so gradient convergence is not checked), however note // that many Methods (LBFGS, CG, etc.) will converge with a small value of // the gradient, and so to fully disable this setting the Method may need to // be modified. // This setting has no effect if the gradient is not used by the Method. GradientThreshold float64 // Converger checks if the optimization has converged based on the (history // of) locations found during the optimization. Minimize will pass the // Location at every MajorIteration to the Converger. // // If the Converger is nil, a default value of // FunctionConverge { // Absolute: 1e-10, // Iterations: 100, // } // will be used. NeverTerminated can be used to always return a // NotTerminated status. Converger Converger // MajorIterations is the maximum number of iterations allowed. // IterationLimit status is returned if the number of major iterations // equals or exceeds this value. // If it equals zero, this setting has no effect. // The default value is 0. MajorIterations int // Runtime is the maximum runtime allowed. RuntimeLimit status is returned // if the duration of the run is longer than this value. Runtime is only // checked at MajorIterations of the Method. // If it equals zero, this setting has no effect. // The default value is 0. Runtime time.Duration // FuncEvaluations is the maximum allowed number of function evaluations. // FunctionEvaluationLimit status is returned if the total number of calls // to Func equals or exceeds this number. // If it equals zero, this setting has no effect. // The default value is 0. FuncEvaluations int // GradEvaluations is the maximum allowed number of gradient evaluations. // GradientEvaluationLimit status is returned if the total number of calls // to Grad equals or exceeds this number. // If it equals zero, this setting has no effect. // The default value is 0. GradEvaluations int // HessEvaluations is the maximum allowed number of Hessian evaluations. // HessianEvaluationLimit status is returned if the total number of calls // to Hess equals or exceeds this number. // If it equals zero, this setting has no effect. // The default value is 0. HessEvaluations int Recorder Recorder // Concurrent represents how many concurrent evaluations are possible. Concurrent int } // resize takes x and returns a slice of length dim. It returns a resliced x // if cap(x) >= dim, and a new slice otherwise. func resize(x []float64, dim int) []float64 { if dim > cap(x) { return make([]float64, dim) } return x[:dim] } func resizeSymDense(m *mat.SymDense, dim int) *mat.SymDense { if m == nil || cap(m.RawSymmetric().Data) < dim*dim { return mat.NewSymDense(dim, nil) } return mat.NewSymDense(dim, m.RawSymmetric().Data[:dim*dim]) } golang-gonum-v1-gonum-0.14.0/optimize/unconstrained_test.go000066400000000000000000000772151450372207100237540ustar00rootroot00000000000000// 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 optimize import ( "fmt" "math" "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/optimize/functions" ) type unconstrainedTest struct { // name is the name of the test. name string // p is the optimization problem to be solved. p Problem // x is the initial guess. x []float64 // gradTol is the absolute gradient tolerance for the test. If gradTol == 0, // the default value of 1e-12 will be used. gradTol float64 // fAbsTol is the absolute function convergence for the test. If fAbsTol == 0, // the default value of 1e-12 will be used. fAbsTol float64 // fIter is the number of iterations for function convergence. If fIter == 0, // the default value of 20 will be used. fIter int // long indicates that the test takes long time to finish and will be // excluded if testing.Short returns true. long bool } func (t unconstrainedTest) String() string { dim := len(t.x) if dim <= 10 { // Print the initial X only for small-dimensional problems. return fmt.Sprintf("F: %v\nDim: %v\nInitial X: %v\nGradientThreshold: %v", t.name, dim, t.x, t.gradTol) } return fmt.Sprintf("F: %v\nDim: %v\nGradientThreshold: %v", t.name, dim, t.gradTol) } var gradFreeTests = []unconstrainedTest{ { name: "Beale", p: Problem{ Func: functions.Beale{}.Func, }, x: []float64{1, 1}, }, { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, }, x: []float64{1, 2, 1, 1, 1, 1}, }, { name: "BrownAndDennis", p: Problem{ Func: functions.BrownAndDennis{}.Func, }, x: []float64{25, 5, -5, -1}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, }, x: []float64{-10, 10}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, }, x: []float64{-5, 4, 16, 3}, }, } var gradientDescentTests = []unconstrainedTest{ { name: "Beale", p: Problem{ Func: functions.Beale{}.Func, Grad: functions.Beale{}.Grad, }, x: []float64{1, 1}, }, { name: "Beale", p: Problem{ Func: functions.Beale{}.Func, Grad: functions.Beale{}.Grad, }, x: []float64{3.00001, 0.50001}, }, { name: "BiggsEXP2", p: Problem{ Func: functions.BiggsEXP2{}.Func, Grad: functions.BiggsEXP2{}.Grad, }, x: []float64{1, 2}, }, { name: "BiggsEXP2", p: Problem{ Func: functions.BiggsEXP2{}.Func, Grad: functions.BiggsEXP2{}.Grad, }, x: []float64{1.00001, 10.00001}, }, { name: "BiggsEXP3", p: Problem{ Func: functions.BiggsEXP3{}.Func, Grad: functions.BiggsEXP3{}.Grad, }, x: []float64{1, 2, 1}, }, { name: "BiggsEXP3", p: Problem{ Func: functions.BiggsEXP3{}.Func, Grad: functions.BiggsEXP3{}.Grad, }, x: []float64{1.00001, 10.00001, 3.00001}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{-1.2, 1}, gradTol: 1e-10, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1.00001, 1.00001}, gradTol: 1e-10, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{-1.2, 1, -1.2}, gradTol: 1e-10, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{-120, 100, 50}, long: true, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1, 1, 1}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1.00001, 1.00001, 1.00001}, gradTol: 1e-8, }, { name: "Gaussian", p: Problem{ Func: functions.Gaussian{}.Func, Grad: functions.Gaussian{}.Grad, }, x: []float64{0.4, 1, 0}, gradTol: 1e-9, }, { name: "Gaussian", p: Problem{ Func: functions.Gaussian{}.Func, Grad: functions.Gaussian{}.Grad, }, x: []float64{0.3989561, 1.0000191, 0}, gradTol: 1e-9, }, { name: "HelicalValley", p: Problem{ Func: functions.HelicalValley{}.Func, Grad: functions.HelicalValley{}.Grad, }, x: []float64{-1, 0, 0}, }, { name: "HelicalValley", p: Problem{ Func: functions.HelicalValley{}.Func, Grad: functions.HelicalValley{}.Grad, }, x: []float64{1.00001, 0.00001, 0.00001}, }, { name: "Trigonometric", p: Problem{ Func: functions.Trigonometric{}.Func, Grad: functions.Trigonometric{}.Grad, }, x: []float64{0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1}, gradTol: 1e-7, }, { name: "Trigonometric", p: Problem{ Func: functions.Trigonometric{}.Func, Grad: functions.Trigonometric{}.Grad, }, x: []float64{0.042964, 0.043976, 0.045093, 0.046338, 0.047744, 0.049354, 0.051237, 0.195209, 0.164977, 0.060148}, gradTol: 1e-8, }, newVariablyDimensioned(2, 0), { name: "VariablyDimensioned", p: Problem{ Func: functions.VariablyDimensioned{}.Func, Grad: functions.VariablyDimensioned{}.Grad, }, x: []float64{1.00001, 1.00001}, }, newVariablyDimensioned(10, 0), { name: "VariablyDimensioned", p: Problem{ Func: functions.VariablyDimensioned{}.Func, Grad: functions.VariablyDimensioned{}.Grad, }, x: []float64{1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001}, }, } var cgTests = []unconstrainedTest{ { name: "BiggsEXP4", p: Problem{ Func: functions.BiggsEXP4{}.Func, Grad: functions.BiggsEXP4{}.Grad, }, x: []float64{1, 2, 1, 1}, }, { name: "BiggsEXP4", p: Problem{ Func: functions.BiggsEXP4{}.Func, Grad: functions.BiggsEXP4{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001}, }, { name: "BiggsEXP5", p: Problem{ Func: functions.BiggsEXP5{}.Func, Grad: functions.BiggsEXP5{}.Grad, }, x: []float64{1, 2, 1, 1, 1}, gradTol: 1e-7, }, { name: "BiggsEXP5", p: Problem{ Func: functions.BiggsEXP5{}.Func, Grad: functions.BiggsEXP5{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001, 4.00001}, }, { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1, 2, 1, 1, 1, 1}, gradTol: 1e-7, }, { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001, 4.00001, 3.00001}, gradTol: 1e-8, }, { name: "Box3D", p: Problem{ Func: functions.Box3D{}.Func, Grad: functions.Box3D{}.Grad, }, x: []float64{0, 10, 20}, }, { name: "Box3D", p: Problem{ Func: functions.Box3D{}.Func, Grad: functions.Box3D{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001}, }, { name: "Box3D", p: Problem{ Func: functions.Box3D{}.Func, Grad: functions.Box3D{}.Grad, }, x: []float64{100.00001, 100.00001, 0.00001}, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{3, -1, 0, 3}, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{0.00001, 0.00001, 0.00001, 0.00001}, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{3, -1, 0, 3, 3, -1, 0, 3}, gradTol: 1e-8, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{0.00001, 0.00001, 0.00001, 0.00001, 0.00001, 0.00001, 0.00001, 0.00001}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{-1.2, 1, -1.2, 1}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1e4, 1e4}, gradTol: 1e-10, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1.00001, 1.00001, 1.00001, 1.00001}, gradTol: 1e-10, }, { name: "PenaltyI", p: Problem{ Func: functions.PenaltyI{}.Func, Grad: functions.PenaltyI{}.Grad, }, x: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, gradTol: 1e-9, }, { name: "PenaltyI", p: Problem{ Func: functions.PenaltyI{}.Func, Grad: functions.PenaltyI{}.Grad, }, x: []float64{0.250007, 0.250007, 0.250007, 0.250007}, gradTol: 1e-10, }, { name: "PenaltyI", p: Problem{ Func: functions.PenaltyI{}.Func, Grad: functions.PenaltyI{}.Grad, }, x: []float64{0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581}, gradTol: 1e-10, }, { name: "PenaltyII", p: Problem{ Func: functions.PenaltyII{}.Func, Grad: functions.PenaltyII{}.Grad, }, x: []float64{0.5, 0.5, 0.5, 0.5}, gradTol: 1e-8, }, { name: "PenaltyII", p: Problem{ Func: functions.PenaltyII{}.Func, Grad: functions.PenaltyII{}.Grad, }, x: []float64{0.19999, 0.19131, 0.4801, 0.51884}, gradTol: 1e-8, }, { name: "PenaltyII", p: Problem{ Func: functions.PenaltyII{}.Func, Grad: functions.PenaltyII{}.Grad, }, x: []float64{0.19998, 0.01035, 0.01960, 0.03208, 0.04993, 0.07651, 0.11862, 0.19214, 0.34732, 0.36916}, gradTol: 1e-6, }, { name: "PowellBadlyScaled", p: Problem{ Func: functions.PowellBadlyScaled{}.Func, Grad: functions.PowellBadlyScaled{}.Grad, }, x: []float64{1.09815e-05, 9.10614}, gradTol: 1e-8, }, newVariablyDimensioned(100, 1e-10), newVariablyDimensioned(1000, 1e-7), newVariablyDimensioned(10000, 1e-4), { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{0, 0, 0, 0, 0, 0}, gradTol: 1e-6, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{-0.01572, 1.01243, -0.23299, 1.26043, -1.51372, 0.99299}, gradTol: 1e-6, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, gradTol: 1e-6, long: true, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{-1.53070e-05, 0.99978, 0.01476, 0.14634, 1.00082, -2.61773, 4.10440, -3.14361, 1.05262}, gradTol: 1e-6, }, { name: "Wood", p: Problem{ Func: functions.Wood{}.Func, Grad: functions.Wood{}.Grad, }, x: []float64{-3, -1, -3, -1}, gradTol: 1e-6, }, } var quasiNewtonTests = []unconstrainedTest{ { name: "BiggsEXP4", p: Problem{ Func: functions.BiggsEXP4{}.Func, Grad: functions.BiggsEXP4{}.Grad, }, x: []float64{1, 2, 1, 1}, }, { name: "BiggsEXP4", p: Problem{ Func: functions.BiggsEXP4{}.Func, Grad: functions.BiggsEXP4{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001}, }, { name: "BiggsEXP5", p: Problem{ Func: functions.BiggsEXP5{}.Func, Grad: functions.BiggsEXP5{}.Grad, }, x: []float64{1, 2, 1, 1, 1}, gradTol: 1e-10, }, { name: "BiggsEXP5", p: Problem{ Func: functions.BiggsEXP5{}.Func, Grad: functions.BiggsEXP5{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001, 4.00001}, }, { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1, 2, 1, 1, 1, 1}, gradTol: 1e-8, }, { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001, 4.00001, 3.00001}, gradTol: 1e-8, }, { name: "Box3D", p: Problem{ Func: functions.Box3D{}.Func, Grad: functions.Box3D{}.Grad, }, x: []float64{0, 10, 20}, }, { name: "Box3D", p: Problem{ Func: functions.Box3D{}.Func, Grad: functions.Box3D{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001}, }, { name: "Box3D", p: Problem{ Func: functions.Box3D{}.Func, Grad: functions.Box3D{}.Grad, }, x: []float64{100.00001, 100.00001, 0.00001}, }, { name: "BrownBadlyScaled", p: Problem{ Func: functions.BrownBadlyScaled{}.Func, Grad: functions.BrownBadlyScaled{}.Grad, }, x: []float64{1, 1}, gradTol: 1e-9, }, { name: "BrownBadlyScaled", p: Problem{ Func: functions.BrownBadlyScaled{}.Func, Grad: functions.BrownBadlyScaled{}.Grad, }, x: []float64{1.000001e6, 2.01e-6}, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{3, -1, 0, 3}, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{0.00001, 0.00001, 0.00001, 0.00001}, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{3, -1, 0, 3, 3, -1, 0, 3}, }, { name: "ExtendedPowellSingular", p: Problem{ Func: functions.ExtendedPowellSingular{}.Func, Grad: functions.ExtendedPowellSingular{}.Grad, }, x: []float64{0.00001, 0.00001, 0.00001, 0.00001, 0.00001, 0.00001, 0.00001, 0.00001}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{-1.2, 1, -1.2, 1}, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1.00001, 1.00001, 1.00001, 1.00001}, }, { name: "Gaussian", p: Problem{ Func: functions.Gaussian{}.Func, Grad: functions.Gaussian{}.Grad, }, x: []float64{0.4, 1, 0}, gradTol: 1e-11, }, { name: "GulfResearchAndDevelopment", p: Problem{ Func: functions.GulfResearchAndDevelopment{}.Func, Grad: functions.GulfResearchAndDevelopment{}.Grad, }, x: []float64{5, 2.5, 0.15}, }, { name: "GulfResearchAndDevelopment", p: Problem{ Func: functions.GulfResearchAndDevelopment{}.Func, Grad: functions.GulfResearchAndDevelopment{}.Grad, }, x: []float64{50.00001, 25.00001, 1.50001}, }, { name: "GulfResearchAndDevelopment", p: Problem{ Func: functions.GulfResearchAndDevelopment{}.Func, Grad: functions.GulfResearchAndDevelopment{}.Grad, }, x: []float64{99.89529, 60.61453, 9.16124}, }, { name: "GulfResearchAndDevelopment", p: Problem{ Func: functions.GulfResearchAndDevelopment{}.Func, Grad: functions.GulfResearchAndDevelopment{}.Grad, }, x: []float64{201.66258, 60.61633, 10.22489}, }, { name: "PenaltyI", p: Problem{ Func: functions.PenaltyI{}.Func, Grad: functions.PenaltyI{}.Grad, }, x: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, }, { name: "PenaltyI", p: Problem{ Func: functions.PenaltyI{}.Func, Grad: functions.PenaltyI{}.Grad, }, x: []float64{0.250007, 0.250007, 0.250007, 0.250007}, gradTol: 1e-9, }, { name: "PenaltyI", p: Problem{ Func: functions.PenaltyI{}.Func, Grad: functions.PenaltyI{}.Grad, }, x: []float64{0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581, 0.1581}, }, { name: "PenaltyII", p: Problem{ Func: functions.PenaltyII{}.Func, Grad: functions.PenaltyII{}.Grad, }, x: []float64{0.5, 0.5, 0.5, 0.5}, gradTol: 1e-10, }, { name: "PenaltyII", p: Problem{ Func: functions.PenaltyII{}.Func, Grad: functions.PenaltyII{}.Grad, }, x: []float64{0.19999, 0.19131, 0.4801, 0.51884}, gradTol: 1e-10, }, { name: "PenaltyII", p: Problem{ Func: functions.PenaltyII{}.Func, Grad: functions.PenaltyII{}.Grad, }, x: []float64{0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5}, gradTol: 1e-9, }, { name: "PenaltyII", p: Problem{ Func: functions.PenaltyII{}.Func, Grad: functions.PenaltyII{}.Grad, }, x: []float64{0.19998, 0.01035, 0.01960, 0.03208, 0.04993, 0.07651, 0.11862, 0.19214, 0.34732, 0.36916}, gradTol: 1e-9, }, { name: "PowellBadlyScaled", p: Problem{ Func: functions.PowellBadlyScaled{}.Func, Grad: functions.PowellBadlyScaled{}.Grad, }, x: []float64{0, 1}, gradTol: 1e-10, }, { name: "PowellBadlyScaled", p: Problem{ Func: functions.PowellBadlyScaled{}.Func, Grad: functions.PowellBadlyScaled{}.Grad, }, x: []float64{1.09815e-05, 9.10614}, gradTol: 1e-10, }, newVariablyDimensioned(100, 1e-10), { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{0, 0, 0, 0, 0, 0}, gradTol: 1e-7, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{-0.01572, 1.01243, -0.23299, 1.26043, -1.51372, 0.99299}, gradTol: 1e-7, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0}, gradTol: 1e-8, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, }, x: []float64{-1.53070e-05, 0.99978, 0.01476, 0.14634, 1.00082, -2.61773, 4.10440, -3.14361, 1.05262}, gradTol: 1e-8, }, } var bfgsTests = []unconstrainedTest{ { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1, 2, 1, 1, 1, 1}, gradTol: 1e-10, }, { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001, 4.00001, 3.00001}, gradTol: 1e-10, }, { name: "BrownAndDennis", p: Problem{ Func: functions.BrownAndDennis{}.Func, Grad: functions.BrownAndDennis{}.Grad, }, x: []float64{25, 5, -5, -1}, gradTol: 1e-3, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1e5, 1e5}, gradTol: 1e-10, }, { name: "Gaussian", p: Problem{ Func: functions.Gaussian{}.Func, Grad: functions.Gaussian{}.Grad, }, x: []float64{0.398, 1, 0}, gradTol: 1e-11, }, { name: "Wood", p: Problem{ Func: functions.Wood{}.Func, Grad: functions.Wood{}.Grad, }, x: []float64{-3, -1, -3, -1}, }, } var lbfgsTests = []unconstrainedTest{ { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1, 2, 1, 1, 1, 1}, gradTol: 1e-8, }, { name: "BiggsEXP6", p: Problem{ Func: functions.BiggsEXP6{}.Func, Grad: functions.BiggsEXP6{}.Grad, }, x: []float64{1.00001, 10.00001, 1.00001, 5.00001, 4.00001, 3.00001}, gradTol: 1e-8, }, { name: "ExtendedRosenbrock", p: Problem{ Func: functions.ExtendedRosenbrock{}.Func, Grad: functions.ExtendedRosenbrock{}.Grad, }, x: []float64{1e7, 1e6}, gradTol: 1e-10, }, { name: "Gaussian", p: Problem{ Func: functions.Gaussian{}.Func, Grad: functions.Gaussian{}.Grad, }, x: []float64{0.398, 1, 0}, gradTol: 1e-10, }, newVariablyDimensioned(1000, 1e-8), newVariablyDimensioned(10000, 1e-5), } var newtonTests = []unconstrainedTest{ { name: "Beale", p: Problem{ Func: functions.Beale{}.Func, Grad: functions.Beale{}.Grad, Hess: functions.Beale{}.Hess, }, x: []float64{1, 1}, }, { name: "BrownAndDennis", p: Problem{ Func: functions.BrownAndDennis{}.Func, Grad: functions.BrownAndDennis{}.Grad, Hess: functions.BrownAndDennis{}.Hess, }, x: []float64{25, 5, -5, -1}, gradTol: 1e-10, }, { name: "BrownBadlyScaled", p: Problem{ Func: functions.BrownBadlyScaled{}.Func, Grad: functions.BrownBadlyScaled{}.Grad, Hess: functions.BrownBadlyScaled{}.Hess, }, x: []float64{1, 1}, gradTol: 1e-9, }, { name: "PowellBadlyScaled", p: Problem{ Func: functions.PowellBadlyScaled{}.Func, Grad: functions.PowellBadlyScaled{}.Grad, Hess: functions.PowellBadlyScaled{}.Hess, }, x: []float64{0, 1}, gradTol: 1e-10, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, Hess: functions.Watson{}.Hess, }, x: []float64{0, 0, 0, 0, 0, 0}, }, { name: "Watson", p: Problem{ Func: functions.Watson{}.Func, Grad: functions.Watson{}.Grad, Hess: functions.Watson{}.Hess, }, x: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "Wood", p: Problem{ Func: functions.Wood{}.Func, Grad: functions.Wood{}.Grad, Hess: functions.Wood{}.Hess, }, x: []float64{-3, -1, -3, -1}, }, } func newVariablyDimensioned(dim int, gradTol float64) unconstrainedTest { x := make([]float64, dim) for i := range x { x[i] = float64(dim-i-1) / float64(dim) } return unconstrainedTest{ name: "VariablyDimensioned", p: Problem{ Func: functions.VariablyDimensioned{}.Func, Grad: functions.VariablyDimensioned{}.Grad, }, x: x, gradTol: gradTol, } } func TestLocal(t *testing.T) { t.Parallel() var tests []unconstrainedTest // Mix of functions with and without Grad method. tests = append(tests, gradFreeTests...) tests = append(tests, gradientDescentTests...) testLocal(t, tests, nil) } func TestNelderMead(t *testing.T) { t.Parallel() var tests []unconstrainedTest // Mix of functions with and without Grad method. tests = append(tests, gradFreeTests...) tests = append(tests, gradientDescentTests...) testLocal(t, tests, &NelderMead{}) } func TestGradientDescent(t *testing.T) { t.Parallel() testLocal(t, gradientDescentTests, &GradientDescent{}) } func TestGradientDescentBacktracking(t *testing.T) { t.Parallel() testLocal(t, gradientDescentTests, &GradientDescent{ Linesearcher: &Backtracking{ DecreaseFactor: 0.1, }, }) } func TestGradientDescentBisection(t *testing.T) { t.Parallel() testLocal(t, gradientDescentTests, &GradientDescent{ Linesearcher: &Bisection{}, }) } func TestCG(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{}) } func TestFletcherReevesQuadStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &FletcherReeves{}, InitialStep: &QuadraticStepSize{}, }) } func TestFletcherReevesFirstOrderStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &FletcherReeves{}, InitialStep: &FirstOrderStepSize{}, }) } func TestHestenesStiefelQuadStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &HestenesStiefel{}, InitialStep: &QuadraticStepSize{}, }) } func TestHestenesStiefelFirstOrderStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &HestenesStiefel{}, InitialStep: &FirstOrderStepSize{}, }) } func TestPolakRibiereQuadStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &PolakRibierePolyak{}, InitialStep: &QuadraticStepSize{}, }) } func TestPolakRibiereFirstOrderStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &PolakRibierePolyak{}, InitialStep: &FirstOrderStepSize{}, }) } func TestDaiYuanQuadStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &DaiYuan{}, InitialStep: &QuadraticStepSize{}, }) } func TestDaiYuanFirstOrderStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &DaiYuan{}, InitialStep: &FirstOrderStepSize{}, }) } func TestHagerZhangQuadStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &HagerZhang{}, InitialStep: &QuadraticStepSize{}, }) } func TestHagerZhangFirstOrderStep(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, cgTests...) testLocal(t, tests, &CG{ Variant: &HagerZhang{}, InitialStep: &FirstOrderStepSize{}, }) } func TestBFGS(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, quasiNewtonTests...) tests = append(tests, bfgsTests...) testLocal(t, tests, &BFGS{}) } func TestLBFGS(t *testing.T) { t.Parallel() var tests []unconstrainedTest tests = append(tests, gradientDescentTests...) tests = append(tests, quasiNewtonTests...) tests = append(tests, lbfgsTests...) testLocal(t, tests, &LBFGS{}) } func TestNewton(t *testing.T) { t.Parallel() testLocal(t, newtonTests, &Newton{}) } func testLocal(t *testing.T, tests []unconstrainedTest, method Method) { for cas, test := range tests { if test.long && testing.Short() { continue } settings := &Settings{} settings.Converger = defaultFunctionConverge() var uses Available if method != nil { var err error has := availFromProblem(test.p) uses, err = method.Uses(has) if err != nil { t.Errorf("problem and method mismatch: %v", err) continue } } if method != nil { // Turn off function convergence checks for gradient-based methods. if uses.Grad { settings.Converger = NeverTerminate{} } } else { if test.fIter == 0 { test.fIter = 20 } c := settings.Converger.(*FunctionConverge) c.Iterations = test.fIter if test.fAbsTol == 0 { test.fAbsTol = 1e-12 } c.Absolute = test.fAbsTol settings.Converger = c } if test.gradTol == 0 { test.gradTol = 1e-12 } settings.GradientThreshold = test.gradTol result, err := Minimize(test.p, test.x, settings, method) if err != nil { t.Errorf("Case %d: error finding minimum (%v) for:\n%v", cas, err, test) continue } if result == nil { t.Errorf("Case %d: nil result without error for:\n%v", cas, test) continue } // Check that the function value at the found optimum location is // equal to result.F. optF := test.p.Func(result.X) if optF != result.F { t.Errorf("Case %d: Function value at the optimum location %v not equal to the returned value %v for:\n%v", cas, optF, result.F, test) } if result.Gradient != nil { // Evaluate the norm of the gradient at the found optimum location. g := make([]float64, len(test.x)) test.p.Grad(g, result.X) if !floats.Equal(result.Gradient, g) { t.Errorf("Case %d: Gradient at the optimum location not equal to the returned value for:\n%v", cas, test) } optNorm := floats.Norm(g, math.Inf(1)) // Check that the norm of the gradient at the found optimum location is // smaller than the tolerance. if optNorm >= settings.GradientThreshold { t.Errorf("Case %d: Norm of the gradient at the optimum location %v not smaller than tolerance %v for:\n%v", cas, optNorm, settings.GradientThreshold, test) } } if method == nil { // The tests below make sense only if the method used is known. continue } if !uses.Grad && !uses.Hess { // Gradient-free tests can correctly terminate only with // FunctionConvergence status. if result.Status != FunctionConvergence { t.Errorf("Status not %v, %v instead", FunctionConvergence, result.Status) } } // We are going to restart the solution using known initial data, so // evaluate them. settings.InitValues = &Location{} settings.InitValues.F = test.p.Func(test.x) if uses.Grad { settings.InitValues.Gradient = resize(settings.InitValues.Gradient, len(test.x)) test.p.Grad(settings.InitValues.Gradient, test.x) } if uses.Hess { settings.InitValues.Hessian = mat.NewSymDense(len(test.x), nil) test.p.Hess(settings.InitValues.Hessian, test.x) } // Rerun the test again to make sure that it gets the same answer with // the same starting condition. Moreover, we are using the initial data. result2, err2 := Minimize(test.p, test.x, settings, method) if err2 != nil { t.Errorf("error finding minimum second time (%v) for:\n%v", err2, test) continue } if result2 == nil { t.Errorf("second time nil result without error for:\n%v", test) continue } // At the moment all the optimizers are deterministic, so check that we // get _exactly_ the same answer second time as well. if result.F != result2.F || !floats.Equal(result.X, result2.X) { t.Errorf("Different minimum second time for:\n%v", test) } // Check that providing initial data reduces the number of evaluations exactly by one. if result.FuncEvaluations != result2.FuncEvaluations+1 { t.Errorf("Providing initial data does not reduce the number of Func calls for:\n%v", test) continue } if uses.Grad { if result.GradEvaluations != result2.GradEvaluations+1 { t.Errorf("Providing initial data does not reduce the number of Grad calls for:\n%v", test) continue } } if uses.Hess { if result.HessEvaluations != result2.HessEvaluations+1 { t.Errorf("Providing initial data does not reduce the number of Hess calls for:\n%v", test) continue } } } } func TestIssue76(t *testing.T) { t.Parallel() p := Problem{ Func: functions.BrownAndDennis{}.Func, Grad: functions.BrownAndDennis{}.Grad, } // Location very close to the minimum. x := []float64{-11.594439904886773, 13.203630051265385, -0.40343948776868443, 0.2367787746745986} s := &Settings{ MajorIterations: 1000000, } m := &GradientDescent{ GradStopThreshold: 1e-14, Linesearcher: &Backtracking{}, } // We are not interested in the error, only in the returned status. r, _ := Minimize(p, x, s, m) // With the above stringent tolerance, the optimizer will never // successfully reach the minimum. Check if it terminated in a finite // number of steps. if r.Status == IterationLimit { t.Error("Issue https://github.com/gonum/optimize/issues/76 not fixed") } } func TestNelderMeadOneD(t *testing.T) { t.Parallel() p := Problem{ Func: func(x []float64) float64 { return x[0] * x[0] }, } x := []float64{10} m := &NelderMead{} var s *Settings result, err := Minimize(p, x, s, m) if err != nil { t.Errorf(err.Error()) } if !floats.EqualApprox(result.X, []float64{0}, 1e-10) { t.Errorf("Minimum not found") } if m.reflection != 1 { t.Errorf("Wrong value of reflection") } if m.expansion != 2 { t.Errorf("Wrong value of expansion") } if m.contraction != 0.5 { t.Errorf("Wrong value of contraction") } if m.shrink != 0.5 { t.Errorf("Wrong value of shrink") } } golang-gonum-v1-gonum-0.14.0/spatial/000077500000000000000000000000001450372207100172735ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/spatial/barneshut/000077500000000000000000000000001450372207100212665ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/spatial/barneshut/barneshut2.go000066400000000000000000000150441450372207100236760ustar00rootroot00000000000000// Copyright ©2019 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 barneshut import ( "errors" "fmt" "math" "gonum.org/v1/gonum/spatial/r2" ) // Particle2 is a particle in a plane. type Particle2 interface { Coord2() r2.Vec Mass() float64 } // Force2 is a force modeling function for interactions between p1 and p2, // m1 is the mass of p1 and m2 of p2. The vector v is the vector from p1 to // p2. The returned value is the force vector acting on p1. // // In models where the identity of particles must be known, p1 and p2 may be // compared. Force2 may be passed nil for p2 when the Barnes-Hut approximation // is being used. A nil p2 indicates that the second mass center is an // aggregate. type Force2 func(p1, p2 Particle2, m1, m2 float64, v r2.Vec) r2.Vec // Gravity2 returns a vector force on m1 by m2, equal to (m1⋅m2)/‖v‖² // in the directions of v. Gravity2 ignores the identity of the interacting // particles and returns a zero vector when the two particles are // coincident, but performs no other sanity checks. func Gravity2(_, _ Particle2, m1, m2 float64, v r2.Vec) r2.Vec { d2 := v.X*v.X + v.Y*v.Y if d2 == 0 { return r2.Vec{} } return r2.Scale((m1*m2)/(d2*math.Sqrt(d2)), v) } // Plane implements Barnes-Hut force approximation calculations. type Plane struct { root tile Particles []Particle2 } // NewPlane returns a new Plane. If the plane is too large to allow // particle coordinates to be distinguished due to floating point // precision limits, NewPlane will return a non-nil error. func NewPlane(p []Particle2) (*Plane, error) { q := Plane{Particles: p} err := q.Reset() if err != nil { return nil, err } return &q, nil } // Reset reconstructs the Barnes-Hut tree. Reset must be called if the // Particles field or elements of Particles have been altered, unless // ForceOn is called with theta=0 or no data structures have been // previously built. If the plane is too large to allow particle // coordinates to be distinguished due to floating point precision // limits, Reset will return a non-nil error. func (q *Plane) Reset() (err error) { if len(q.Particles) == 0 { q.root = tile{} return nil } q.root = tile{ particle: q.Particles[0], center: q.Particles[0].Coord2(), mass: q.Particles[0].Mass(), } q.root.bounds.Min = q.root.center q.root.bounds.Max = q.root.center for _, e := range q.Particles[1:] { c := e.Coord2() if c.X < q.root.bounds.Min.X { q.root.bounds.Min.X = c.X } if c.X > q.root.bounds.Max.X { q.root.bounds.Max.X = c.X } if c.Y < q.root.bounds.Min.Y { q.root.bounds.Min.Y = c.Y } if c.Y > q.root.bounds.Max.Y { q.root.bounds.Max.Y = c.Y } } defer func() { switch r := recover(); r { case nil: case planeTooBig: err = planeTooBig default: panic(r) } }() // TODO(kortschak): Partially parallelise this by // choosing the direction and using one of four // goroutines to work on each root quadrant. for _, e := range q.Particles[1:] { q.root.insert(e) } q.root.summarize() return nil } var planeTooBig = errors.New("barneshut: plane too big") // ForceOn returns a force vector on p given p's mass and the force function, f, // using the Barnes-Hut theta approximation parameter. // // Calls to f will include p in the p1 position and a non-nil p2 if the force // interaction is with a non-aggregate mass center, otherwise p2 will be nil. // // It is safe to call ForceOn concurrently. func (q *Plane) ForceOn(p Particle2, theta float64, f Force2) (force r2.Vec) { var empty tile if theta > 0 && q.root != empty { return q.root.forceOn(p, p.Coord2(), p.Mass(), theta, f) } // For the degenerate case, just iterate over the // slice of particles rather than walking the tree. var v r2.Vec m := p.Mass() pv := p.Coord2() for _, e := range q.Particles { v = r2.Add(v, f(p, e, m, e.Mass(), r2.Sub(e.Coord2(), pv))) } return v } // tile is a quad tree quadrant with Barnes-Hut extensions. type tile struct { particle Particle2 bounds r2.Box nodes [4]*tile center r2.Vec mass float64 } // insert inserts p into the subtree rooted at t. func (t *tile) insert(p Particle2) { if t.particle == nil { for _, q := range t.nodes { if q != nil { t.passDown(p) return } } t.particle = p t.center = p.Coord2() t.mass = p.Mass() return } t.passDown(p) t.passDown(t.particle) t.particle = nil t.center = r2.Vec{} t.mass = 0 } func (t *tile) passDown(p Particle2) { dir := quadrantOf(t.bounds, p) if t.nodes[dir] == nil { t.nodes[dir] = &tile{bounds: splitPlane(t.bounds, dir)} } t.nodes[dir].insert(p) } const ( ne = iota se sw nw ) // quadrantOf returns which quadrant of b that p should be placed in. func quadrantOf(b r2.Box, p Particle2) int { center := r2.Vec{ X: (b.Min.X + b.Max.X) / 2, Y: (b.Min.Y + b.Max.Y) / 2, } c := p.Coord2() if checkBounds && (c.X < b.Min.X || b.Max.X < c.X || c.Y < b.Min.Y || b.Max.Y < c.Y) { panic(fmt.Sprintf("p out of range %+v: %#v", b, p)) } if c.X < center.X { if c.Y < center.Y { return nw } else { return sw } } else { if c.Y < center.Y { return ne } else { return se } } } // splitPlane returns a quadrant subdivision of b in the given direction. func splitPlane(b r2.Box, dir int) r2.Box { old := b halfX := (b.Max.X - b.Min.X) / 2 halfY := (b.Max.Y - b.Min.Y) / 2 switch dir { case ne: b.Min.X += halfX b.Max.Y -= halfY case se: b.Min.X += halfX b.Min.Y += halfY case sw: b.Max.X -= halfX b.Min.Y += halfY case nw: b.Max.X -= halfX b.Max.Y -= halfY } if b == old { panic(planeTooBig) } return b } // summarize updates node masses and centers of mass. func (t *tile) summarize() (center r2.Vec, mass float64) { for _, d := range &t.nodes { if d == nil { continue } c, m := d.summarize() t.center.X += c.X * m t.center.Y += c.Y * m t.mass += m } t.center.X /= t.mass t.center.Y /= t.mass return t.center, t.mass } // forceOn returns a force vector on p given p's mass m and the force // calculation function, using the Barnes-Hut theta approximation parameter. func (t *tile) forceOn(p Particle2, pt r2.Vec, m, theta float64, f Force2) (vector r2.Vec) { s := ((t.bounds.Max.X - t.bounds.Min.X) + (t.bounds.Max.Y - t.bounds.Min.Y)) / 2 d := math.Hypot(pt.X-t.center.X, pt.Y-t.center.Y) if s/d < theta || t.particle != nil { return f(p, t.particle, m, t.mass, r2.Sub(t.center, pt)) } var v r2.Vec for _, d := range &t.nodes { if d == nil { continue } v = r2.Add(v, d.forceOn(p, pt, m, theta, f)) } return v } golang-gonum-v1-gonum-0.14.0/spatial/barneshut/barneshut2_test.go000066400000000000000000000360721450372207100247410ustar00rootroot00000000000000// Copyright ©2019 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 barneshut import ( "fmt" "math" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/spatial/r2" ) type particle2 struct { x, y, m float64 name string } func (p particle2) Coord2() r2.Vec { return r2.Vec{X: p.x, Y: p.y} } func (p particle2) Mass() float64 { return p.m } var planeTests = []struct { name string particles []particle2 want *Plane }{ { name: "nil", particles: nil, want: &Plane{}, }, { name: "empty", particles: []particle2{}, want: &Plane{Particles: []Particle2{}}, }, { name: "one", particles: []particle2{{m: 1}}, // Must have a mass to avoid vacuum decay. want: &Plane{ root: tile{ particle: particle2{x: 0, y: 0, m: 1}, bounds: r2.Box{Min: r2.Vec{X: 0, Y: 0}, Max: r2.Vec{X: 0, Y: 0}}, center: r2.Vec{X: 0, Y: 0}, mass: 1, }, Particles: []Particle2{ particle2{m: 1}, }, }, }, { name: "3 corners", particles: []particle2{ {x: 1, y: 1, m: 1}, {x: -1, y: 1, m: 1}, {x: -1, y: -1, m: 1}, }, want: &Plane{ root: tile{ bounds: r2.Box{Min: r2.Vec{X: -1, Y: -1}, Max: r2.Vec{X: 1, Y: 1}}, nodes: [4]*tile{ se: { particle: particle2{x: 1, y: 1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: 0, Y: 0}, Max: r2.Vec{X: 1, Y: 1}}, center: r2.Vec{X: 1, Y: 1}, mass: 1, }, sw: { particle: particle2{x: -1, y: 1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -1, Y: 0}, Max: r2.Vec{X: 0, Y: 1}}, center: r2.Vec{X: -1, Y: 1}, mass: 1, }, nw: { particle: particle2{x: -1, y: -1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -1, Y: -1}, Max: r2.Vec{X: 0, Y: 0}}, center: r2.Vec{X: -1, Y: -1}, mass: 1, }, }, center: r2.Vec{X: -0.3333333333333333, Y: 0.3333333333333333}, mass: 3, }, Particles: []Particle2{ particle2{x: 1, y: 1, m: 1}, particle2{x: -1, y: 1, m: 1}, particle2{x: -1, y: -1, m: 1}, }, }, }, { name: "4 corners", particles: []particle2{ {x: 1, y: 1, m: 1}, {x: -1, y: 1, m: 1}, {x: 1, y: -1, m: 1}, {x: -1, y: -1, m: 1}, }, want: &Plane{ root: tile{ bounds: r2.Box{Min: r2.Vec{X: -1, Y: -1}, Max: r2.Vec{X: 1, Y: 1}}, nodes: [4]*tile{ { particle: particle2{x: 1, y: -1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: 0, Y: -1}, Max: r2.Vec{X: 1, Y: 0}}, center: r2.Vec{X: 1, Y: -1}, mass: 1, }, { particle: particle2{x: 1, y: 1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: 0, Y: 0}, Max: r2.Vec{X: 1, Y: 1}}, center: r2.Vec{X: 1, Y: 1}, mass: 1, }, { particle: particle2{x: -1, y: 1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -1, Y: 0}, Max: r2.Vec{X: 0, Y: 1}}, center: r2.Vec{X: -1, Y: 1}, mass: 1, }, { particle: particle2{x: -1, y: -1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -1, Y: -1}, Max: r2.Vec{X: 0, Y: 0}}, center: r2.Vec{X: -1, Y: -1}, mass: 1, }, }, center: r2.Vec{X: 0, Y: 0}, mass: 4, }, Particles: []Particle2{ particle2{x: 1, y: 1, m: 1}, particle2{x: -1, y: 1, m: 1}, particle2{x: 1, y: -1, m: 1}, particle2{x: -1, y: -1, m: 1}, }, }, }, { name: "5 corners", particles: []particle2{ {x: 1, y: 1, m: 1}, {x: -1, y: 1, m: 1}, {x: 1, y: -1, m: 1}, {x: -1, y: -1, m: 1}, {x: -1.1, y: -1, m: 1}, }, want: &Plane{ root: tile{ bounds: r2.Box{Min: r2.Vec{X: -1.1, Y: -1}, Max: r2.Vec{X: 1, Y: 1}}, nodes: [4]*tile{ { particle: particle2{x: 1, y: -1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -0.050000000000000044, Y: -1}, Max: r2.Vec{X: 1, Y: 0}}, center: r2.Vec{X: 1, Y: -1}, mass: 1, }, { particle: particle2{x: 1, y: 1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -0.050000000000000044, Y: 0}, Max: r2.Vec{X: 1, Y: 1}}, center: r2.Vec{X: 1, Y: 1}, mass: 1, }, { particle: particle2{x: -1, y: 1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -1.1, Y: 0}, Max: r2.Vec{X: -0.050000000000000044, Y: 1}}, center: r2.Vec{X: -1, Y: 1}, mass: 1, }, { bounds: r2.Box{Min: r2.Vec{X: -1.1, Y: -1}, Max: r2.Vec{X: -0.050000000000000044, Y: 0}}, nodes: [4]*tile{ nw: { bounds: r2.Box{Min: r2.Vec{X: -1.1, Y: -1}, Max: r2.Vec{X: -0.5750000000000001, Y: -0.5}}, nodes: [4]*tile{ nw: { bounds: r2.Box{Min: r2.Vec{X: -1.1, Y: -1}, Max: r2.Vec{X: -0.8375000000000001, Y: -0.75}}, nodes: [4]*tile{ nw: { bounds: r2.Box{Min: r2.Vec{X: -1.1, Y: -1}, Max: r2.Vec{X: -0.9687500000000001, Y: -0.875}}, nodes: [4]*tile{ ne: { particle: particle2{x: -1, y: -1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -1.034375, Y: -1}, Max: r2.Vec{X: -0.9687500000000001, Y: -0.9375}}, center: r2.Vec{X: -1, Y: -1}, mass: 1, }, nw: { particle: particle2{x: -1.1, y: -1, m: 1}, bounds: r2.Box{Min: r2.Vec{X: -1.1, Y: -1}, Max: r2.Vec{X: -1.034375, Y: -0.9375}}, center: r2.Vec{X: -1.1, Y: -1}, mass: 1, }, }, center: r2.Vec{X: -1.05, Y: -1}, mass: 2, }, }, center: r2.Vec{X: -1.05, Y: -1}, mass: 2, }, }, center: r2.Vec{X: -1.05, Y: -1}, mass: 2, }, }, center: r2.Vec{X: -1.05, Y: -1}, mass: 2, }, }, center: r2.Vec{X: -0.22000000000000003, Y: -0.2}, mass: 5, }, Particles: []Particle2{ particle2{x: 1, y: 1, m: 1}, particle2{x: -1, y: 1, m: 1}, particle2{x: 1, y: -1, m: 1}, particle2{x: -1, y: -1, m: 1}, particle2{x: -1.1, y: -1, m: 1}, }, }, }, { // Note that the code here subdivides the space differently to // how it is split in the example, since Plane makes a minimum // bounding box based on the data, while the example does not. name: "http://arborjs.org/docs/barnes-hut example", particles: []particle2{ {x: 64.5, y: 81.5, m: 1, name: "A"}, {x: 242, y: 34, m: 1, name: "B"}, {x: 199, y: 69, m: 1, name: "C"}, {x: 285, y: 106.5, m: 1, name: "D"}, {x: 170, y: 194.5, m: 1, name: "E"}, {x: 42.5, y: 334.5, m: 1, name: "F"}, {x: 147, y: 309, m: 1, name: "G"}, {x: 236.5, y: 324, m: 1, name: "H"}, }, want: &Plane{ root: tile{ bounds: r2.Box{Min: r2.Vec{X: 42.5, Y: 34}, Max: r2.Vec{X: 285, Y: 334.5}}, nodes: [4]*tile{ { bounds: r2.Box{Min: r2.Vec{X: 163.75, Y: 34}, Max: r2.Vec{X: 285, Y: 184.25}}, nodes: [4]*tile{ ne: { bounds: r2.Box{Min: r2.Vec{X: 224.375, Y: 34}, Max: r2.Vec{X: 285, Y: 109.125}}, nodes: [4]*tile{ se: { particle: particle2{x: 285, y: 106.5, m: 1, name: "D"}, bounds: r2.Box{Min: r2.Vec{X: 254.6875, Y: 71.5625}, Max: r2.Vec{X: 285, Y: 109.125}}, center: r2.Vec{X: 285, Y: 106.5}, mass: 1, }, nw: { particle: particle2{x: 242, y: 34, m: 1, name: "B"}, bounds: r2.Box{Min: r2.Vec{X: 224.375, Y: 34}, Max: r2.Vec{X: 254.6875, Y: 71.5625}}, center: r2.Vec{X: 242, Y: 34}, mass: 1, }, }, center: r2.Vec{X: 263.5, Y: 70.25}, mass: 2, }, nw: { particle: particle2{x: 199, y: 69, m: 1, name: "C"}, bounds: r2.Box{Min: r2.Vec{X: 163.75, Y: 34}, Max: r2.Vec{X: 224.375, Y: 109.125}}, center: r2.Vec{X: 199, Y: 69}, mass: 1, }, }, center: r2.Vec{X: 242, Y: 69.83333333333333}, mass: 3, }, { bounds: r2.Box{Min: r2.Vec{X: 163.75, Y: 184.25}, Max: r2.Vec{X: 285, Y: 334.5}}, nodes: [4]*tile{ se: { particle: particle2{x: 236.5, y: 324, m: 1, name: "H"}, bounds: r2.Box{Min: r2.Vec{X: 224.375, Y: 259.375}, Max: r2.Vec{X: 285, Y: 334.5}}, center: r2.Vec{X: 236.5, Y: 324}, mass: 1, }, nw: { particle: particle2{x: 170, y: 194.5, m: 1, name: "E"}, bounds: r2.Box{Min: r2.Vec{X: 163.75, Y: 184.25}, Max: r2.Vec{X: 224.375, Y: 259.375}}, center: r2.Vec{X: 170, Y: 194.5}, mass: 1, }, }, center: r2.Vec{X: 203.25, Y: 259.25}, mass: 2, }, { bounds: r2.Box{Min: r2.Vec{X: 42.5, Y: 184.25}, Max: r2.Vec{X: 163.75, Y: 334.5}}, nodes: [4]*tile{ se: { particle: particle2{x: 147, y: 309, m: 1, name: "G"}, bounds: r2.Box{Min: r2.Vec{X: 103.125, Y: 259.375}, Max: r2.Vec{X: 163.75, Y: 334.5}}, center: r2.Vec{X: 147, Y: 309}, mass: 1, }, sw: { particle: particle2{x: 42.5, y: 334.5, m: 1, name: "F"}, bounds: r2.Box{Min: r2.Vec{X: 42.5, Y: 259.375}, Max: r2.Vec{X: 103.125, Y: 334.5}}, center: r2.Vec{X: 42.5, Y: 334.5}, mass: 1, }, }, center: r2.Vec{X: 94.75, Y: 321.75}, mass: 2, }, { particle: particle2{x: 64.5, y: 81.5, m: 1, name: "A"}, bounds: r2.Box{Min: r2.Vec{X: 42.5, Y: 34}, Max: r2.Vec{X: 163.75, Y: 184.25}}, center: r2.Vec{X: 64.5, Y: 81.5}, mass: 1, }, }, center: r2.Vec{X: 173.3125, Y: 181.625}, mass: 8, }, Particles: []Particle2{ particle2{x: 64.5, y: 81.5, m: 1, name: "A"}, particle2{x: 242, y: 34, m: 1, name: "B"}, particle2{x: 199, y: 69, m: 1, name: "C"}, particle2{x: 285, y: 106.5, m: 1, name: "D"}, particle2{x: 170, y: 194.5, m: 1, name: "E"}, particle2{x: 42.5, y: 334.5, m: 1, name: "F"}, particle2{x: 147, y: 309, m: 1, name: "G"}, particle2{x: 236.5, y: 324, m: 1, name: "H"}, }, }, }, } func TestPlane(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range planeTests { var particles []Particle2 if test.particles != nil { particles = make([]Particle2, len(test.particles)) } for i, p := range test.particles { particles[i] = p } got, err := NewPlane(particles) if err != nil { t.Errorf("unexpected error: %v", err) continue } if test.want != nil && !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %q: got:%v want:%v", test.name, got, test.want) } // Recursively check all internal centers of mass. walkPlane(&got.root, func(tl *tile) { var sub []Particle2 walkPlane(tl, func(tl *tile) { if tl.particle != nil { sub = append(sub, tl.particle) } }) center, mass := centerOfMass2(sub) if !scalar.EqualWithinAbsOrRel(center.X, tl.center.X, tol, tol) || !scalar.EqualWithinAbsOrRel(center.Y, tl.center.Y, tol, tol) { t.Errorf("unexpected result for %q for center of mass: got:%f want:%f", test.name, tl.center, center) } if !scalar.EqualWithinAbsOrRel(mass, tl.mass, tol, tol) { t.Errorf("unexpected result for %q for total mass: got:%f want:%f", test.name, tl.mass, mass) } }) } } func centerOfMass2(particles []Particle2) (center r2.Vec, mass float64) { for _, p := range particles { m := p.Mass() mass += m c := p.Coord2() center.X += c.X * m center.Y += c.Y * m } if mass != 0 { center.X /= mass center.Y /= mass } return center, mass } func walkPlane(t *tile, fn func(*tile)) { if t == nil { return } fn(t) for _, q := range t.nodes { walkPlane(q, fn) } } func TestPlaneForceOn(t *testing.T) { t.Parallel() const ( size = 1000 tol = 0.07 ) for _, n := range []int{3e3, 1e4, 3e4} { rnd := rand.New(rand.NewSource(1)) particles := make([]Particle2, n) for i := range particles { particles[i] = particle2{x: size * rnd.Float64(), y: size * rnd.Float64(), m: 1} } moved := make([]r2.Vec, n) for i, p := range particles { var v r2.Vec m := p.Mass() pv := p.Coord2() for _, e := range particles { v = r2.Add(v, Gravity2(p, e, m, e.Mass(), r2.Sub(e.Coord2(), pv))) } moved[i] = r2.Add(p.Coord2(), v) } plane, err := NewPlane(particles) if err != nil { t.Errorf("unexpected error: %v", err) continue } for _, theta := range []float64{0, 0.3, 0.6, 0.9} { theta := theta t.Run(fmt.Sprintf("%d-body/theta=%v", len(particles), theta), func(t *testing.T) { t.Parallel() var ssd, sd float64 var calls int for i, p := range particles { v := plane.ForceOn(p, theta, func(p1, p2 Particle2, m1, m2 float64, v r2.Vec) r2.Vec { calls++ return Gravity2(p1, p2, m1, m2, v) }) pos := r2.Add(p.Coord2(), v) d := r2.Sub(moved[i], pos) ssd += d.X*d.X + d.Y*d.Y sd += math.Hypot(d.X, d.Y) } rmsd := math.Sqrt(ssd / float64(len(particles))) if rmsd > tol { t.Error("RMSD for approximation too high") } t.Logf("rmsd=%.4v md=%.4v calls/particle=%.5v", rmsd, sd/float64(len(particles)), float64(calls)/float64(len(particles))) }) } } } var ( fv2sink r2.Vec planeSink *Plane ) func BenchmarkNewPlane(b *testing.B) { for _, n := range []int{1e3, 1e4, 1e5, 1e6} { rnd := rand.New(rand.NewSource(1)) particles := make([]Particle2, n) for i := range particles { particles[i] = particle2{x: rnd.Float64(), y: rnd.Float64(), m: 1} } b.ResetTimer() var err error b.Run(fmt.Sprintf("%d-body", len(particles)), func(b *testing.B) { for i := 0; i < b.N; i++ { planeSink, err = NewPlane(particles) if err != nil { b.Fatalf("unexpected error: %v", err) } } }) } } func BenchmarkPlaneForceOn(b *testing.B) { for _, n := range []int{1e3, 1e4, 1e5} { for _, theta := range []float64{0, 0.1, 0.5, 1, 1.5} { if n > 1e4 && theta < 0.5 { // Don't run unreasonably long benchmarks. continue } rnd := rand.New(rand.NewSource(1)) particles := make([]Particle2, n) for i := range particles { particles[i] = particle2{x: rnd.Float64(), y: rnd.Float64(), m: 1} } plane, err := NewPlane(particles) if err != nil { b.Fatalf("unexpected error: %v", err) } b.ResetTimer() b.Run(fmt.Sprintf("%d-body/theta=%v", len(particles), theta), func(b *testing.B) { for i := 0; i < b.N; i++ { for _, p := range particles { fv2sink = plane.ForceOn(p, theta, Gravity2) } } }) } } } func BenchmarkPlaneFull(b *testing.B) { for _, n := range []int{1e3, 1e4, 1e5} { for _, theta := range []float64{0, 0.1, 0.5, 1, 1.5} { if n > 1e4 && theta < 0.5 { // Don't run unreasonably long benchmarks. continue } rnd := rand.New(rand.NewSource(1)) particles := make([]Particle2, n) for i := range particles { particles[i] = particle2{x: rnd.Float64(), y: rnd.Float64(), m: 1} } b.ResetTimer() b.Run(fmt.Sprintf("%d-body/theta=%v", len(particles), theta), func(b *testing.B) { for i := 0; i < b.N; i++ { plane, err := NewPlane(particles) if err != nil { b.Fatalf("unexpected error: %v", err) } for _, p := range particles { fv2sink = plane.ForceOn(p, theta, Gravity2) } } }) } } } golang-gonum-v1-gonum-0.14.0/spatial/barneshut/barneshut3.go000066400000000000000000000170011450372207100236720ustar00rootroot00000000000000// Copyright ©2019 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 barneshut import ( "errors" "fmt" "math" "gonum.org/v1/gonum/spatial/r3" ) // Particle3 is a particle in a volume. type Particle3 interface { Coord3() r3.Vec Mass() float64 } // Force3 is a force modeling function for interactions between p1 and p2, // m1 is the mass of p1 and m2 of p2. The vector v is the vector from p1 to // p2. The returned value is the force vector acting on p1. // // In models where the identity of particles must be known, p1 and p2 may be // compared. Force3 may be passed nil for p2 when the Barnes-Hut approximation // is being used. A nil p2 indicates that the second mass center is an // aggregate. type Force3 func(p1, p2 Particle3, m1, m2 float64, v r3.Vec) r3.Vec // Gravity3 returns a vector force on m1 by m2, equal to (m1⋅m2)/‖v‖² // in the directions of v. Gravity3 ignores the identity of the interacting // particles and returns a zero vector when the two particles are // coincident, but performs no other sanity checks. func Gravity3(_, _ Particle3, m1, m2 float64, v r3.Vec) r3.Vec { d2 := v.X*v.X + v.Y*v.Y + v.Z*v.Z if d2 == 0 { return r3.Vec{} } return r3.Scale((m1*m2)/(d2*math.Sqrt(d2)), v) } // Volume implements Barnes-Hut force approximation calculations. type Volume struct { root bucket Particles []Particle3 } // NewVolume returns a new Volume. If the volume is too large to allow // particle coordinates to be distinguished due to floating point // precision limits, NewVolume will return a non-nil error. func NewVolume(p []Particle3) (*Volume, error) { q := Volume{Particles: p} err := q.Reset() if err != nil { return nil, err } return &q, nil } // Reset reconstructs the Barnes-Hut tree. Reset must be called if the // Particles field or elements of Particles have been altered, unless // ForceOn is called with theta=0 or no data structures have been // previously built. If the volume is too large to allow particle // coordinates to be distinguished due to floating point precision // limits, Reset will return a non-nil error. func (q *Volume) Reset() (err error) { if len(q.Particles) == 0 { q.root = bucket{} return nil } q.root = bucket{ particle: q.Particles[0], center: q.Particles[0].Coord3(), mass: q.Particles[0].Mass(), } q.root.bounds.Min = q.root.center q.root.bounds.Max = q.root.center for _, e := range q.Particles[1:] { c := e.Coord3() if c.X < q.root.bounds.Min.X { q.root.bounds.Min.X = c.X } if c.X > q.root.bounds.Max.X { q.root.bounds.Max.X = c.X } if c.Y < q.root.bounds.Min.Y { q.root.bounds.Min.Y = c.Y } if c.Y > q.root.bounds.Max.Y { q.root.bounds.Max.Y = c.Y } if c.Z < q.root.bounds.Min.Z { q.root.bounds.Min.Z = c.Z } if c.Z > q.root.bounds.Max.Z { q.root.bounds.Max.Z = c.Z } } defer func() { switch r := recover(); r { case nil: case volumeTooBig: err = volumeTooBig default: panic(r) } }() // TODO(kortschak): Partially parallelise this by // choosing the direction and using one of eight // goroutines to work on each root octant. for _, e := range q.Particles[1:] { q.root.insert(e) } q.root.summarize() return nil } var volumeTooBig = errors.New("barneshut: volume too big") // ForceOn returns a force vector on p given p's mass and the force function, f, // using the Barnes-Hut theta approximation parameter. // // Calls to f will include p in the p1 position and a non-nil p2 if the force // interaction is with a non-aggregate mass center, otherwise p2 will be nil. // // It is safe to call ForceOn concurrently. func (q *Volume) ForceOn(p Particle3, theta float64, f Force3) (force r3.Vec) { var empty bucket if theta > 0 && q.root != empty { return q.root.forceOn(p, p.Coord3(), p.Mass(), theta, f) } // For the degenerate case, just iterate over the // slice of particles rather than walking the tree. var v r3.Vec m := p.Mass() pv := p.Coord3() for _, e := range q.Particles { v = r3.Add(v, f(p, e, m, e.Mass(), r3.Sub(e.Coord3(), pv))) } return v } // bucket is an oct tree octant with Barnes-Hut extensions. type bucket struct { particle Particle3 bounds r3.Box nodes [8]*bucket center r3.Vec mass float64 } // insert inserts p into the subtree rooted at b. func (b *bucket) insert(p Particle3) { if b.particle == nil { for _, q := range b.nodes { if q != nil { b.passDown(p) return } } b.particle = p b.center = p.Coord3() b.mass = p.Mass() return } b.passDown(p) b.passDown(b.particle) b.particle = nil b.center = r3.Vec{} b.mass = 0 } func (b *bucket) passDown(p Particle3) { dir := octantOf(b.bounds, p) if b.nodes[dir] == nil { b.nodes[dir] = &bucket{bounds: splitVolume(b.bounds, dir)} } b.nodes[dir].insert(p) } const ( lne = iota lse lsw lnw une use usw unw ) // octantOf returns which octant of b that p should be placed in. func octantOf(b r3.Box, p Particle3) int { center := r3.Vec{ X: (b.Min.X + b.Max.X) / 2, Y: (b.Min.Y + b.Max.Y) / 2, Z: (b.Min.Z + b.Max.Z) / 2, } c := p.Coord3() if checkBounds && (c.X < b.Min.X || b.Max.X < c.X || c.Y < b.Min.Y || b.Max.Y < c.Y || c.Z < b.Min.Z || b.Max.Z < c.Z) { panic(fmt.Sprintf("p out of range %+v: %#v", b, p)) } if c.X < center.X { if c.Y < center.Y { if c.Z < center.Z { return lnw } else { return unw } } else { if c.Z < center.Z { return lsw } else { return usw } } } else { if c.Y < center.Y { if c.Z < center.Z { return lne } else { return une } } else { if c.Z < center.Z { return lse } else { return use } } } } // splitVolume returns an octant subdivision of b in the given direction. func splitVolume(b r3.Box, dir int) r3.Box { old := b halfX := (b.Max.X - b.Min.X) / 2 halfY := (b.Max.Y - b.Min.Y) / 2 halfZ := (b.Max.Z - b.Min.Z) / 2 switch dir { case lne: b.Min.X += halfX b.Max.Y -= halfY b.Max.Z -= halfZ case lse: b.Min.X += halfX b.Min.Y += halfY b.Max.Z -= halfZ case lsw: b.Max.X -= halfX b.Min.Y += halfY b.Max.Z -= halfZ case lnw: b.Max.X -= halfX b.Max.Y -= halfY b.Max.Z -= halfZ case une: b.Min.X += halfX b.Max.Y -= halfY b.Min.Z += halfZ case use: b.Min.X += halfX b.Min.Y += halfY b.Min.Z += halfZ case usw: b.Max.X -= halfX b.Min.Y += halfY b.Min.Z += halfZ case unw: b.Max.X -= halfX b.Max.Y -= halfY b.Min.Z += halfZ } if b == old { panic(volumeTooBig) } return b } // summarize updates node masses and centers of mass. func (b *bucket) summarize() (center r3.Vec, mass float64) { for _, d := range &b.nodes { if d == nil { continue } c, m := d.summarize() b.center.X += c.X * m b.center.Y += c.Y * m b.center.Z += c.Z * m b.mass += m } b.center.X /= b.mass b.center.Y /= b.mass b.center.Z /= b.mass return b.center, b.mass } // forceOn returns a force vector on p given p's mass m and the force // calculation function, using the Barnes-Hut theta approximation parameter. func (b *bucket) forceOn(p Particle3, pt r3.Vec, m, theta float64, f Force3) (vector r3.Vec) { s := ((b.bounds.Max.X - b.bounds.Min.X) + (b.bounds.Max.Y - b.bounds.Min.Y) + (b.bounds.Max.Z - b.bounds.Min.Z)) / 3 d := math.Hypot(math.Hypot(pt.X-b.center.X, pt.Y-b.center.Y), pt.Z-b.center.Z) if s/d < theta || b.particle != nil { return f(p, b.particle, m, b.mass, r3.Sub(b.center, pt)) } var v r3.Vec for _, d := range &b.nodes { if d == nil { continue } v = r3.Add(v, d.forceOn(p, pt, m, theta, f)) } return v } golang-gonum-v1-gonum-0.14.0/spatial/barneshut/barneshut3_test.go000066400000000000000000000407031450372207100247360ustar00rootroot00000000000000// Copyright ©2019 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 barneshut import ( "fmt" "math" "reflect" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/spatial/r3" ) type particle3 struct { x, y, z, m float64 name string } func (p particle3) Coord3() r3.Vec { return r3.Vec{X: p.x, Y: p.y, Z: p.z} } func (p particle3) Mass() float64 { return p.m } var volumeTests = []struct { name string particles []particle3 want *Volume }{ { name: "nil", particles: nil, want: &Volume{}, }, { name: "empty", particles: []particle3{}, want: &Volume{Particles: []Particle3{}}, }, { name: "one", particles: []particle3{{m: 1}}, // Must have a mass to avoid vacuum decay. want: &Volume{ root: bucket{ particle: particle3{x: 0, y: 0, z: 0, m: 1}, bounds: r3.Box{Min: r3.Vec{X: 0, Y: 0, Z: 0}, Max: r3.Vec{X: 0, Y: 0, Z: 0}}, center: r3.Vec{X: 0, Y: 0, Z: 0}, mass: 1, }, Particles: []Particle3{ particle3{x: 0, y: 0, z: 0, m: 1}, }, }, }, { name: "3 corners", particles: []particle3{ {x: 1, y: 1, z: 1, m: 1}, {x: -1, y: 1, z: 0, m: 1}, {x: -1, y: -1, z: -1, m: 1}, }, want: &Volume{ root: bucket{ bounds: r3.Box{Min: r3.Vec{X: -1, Y: -1, Z: -1}, Max: r3.Vec{X: 1, Y: 1, Z: 1}}, nodes: [8]*bucket{ lnw: { particle: particle3{x: -1, y: -1, z: -1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -1, Y: -1, Z: -1}, Max: r3.Vec{X: 0, Y: 0, Z: 0}}, center: r3.Vec{X: -1, Y: -1, Z: -1}, mass: 1, }, use: { particle: particle3{x: 1, y: 1, z: 1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: 0, Y: 0, Z: 0}, Max: r3.Vec{X: 1, Y: 1, Z: 1}}, center: r3.Vec{X: 1, Y: 1, Z: 1}, mass: 1, }, usw: { particle: particle3{x: -1, y: 1, z: 0, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -1, Y: 0, Z: 0}, Max: r3.Vec{X: 0, Y: 1, Z: 1}}, center: r3.Vec{X: -1, Y: 1, Z: 0}, mass: 1, }, }, center: r3.Vec{X: -0.3333333333333333, Y: 0.3333333333333333, Z: 0}, mass: 3, }, Particles: []Particle3{ particle3{x: 1, y: 1, z: 1, m: 1}, particle3{x: -1, y: 1, z: 0, m: 1}, particle3{x: -1, y: -1, z: -1, m: 1}, }, }, }, { name: "4 corners", particles: []particle3{ {x: 1, y: 1, z: -1, m: 1}, {x: -1, y: 1, z: 1, m: 1}, {x: 1, y: -1, z: 1, m: 1}, {x: -1, y: -1, z: -1, m: 1}, }, want: &Volume{ root: bucket{ bounds: r3.Box{Min: r3.Vec{X: -1, Y: -1, Z: -1}, Max: r3.Vec{X: 1, Y: 1, Z: 1}}, nodes: [8]*bucket{ lse: { particle: particle3{x: 1, y: 1, z: -1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: 0, Y: 0, Z: -1}, Max: r3.Vec{X: 1, Y: 1, Z: 0}}, center: r3.Vec{X: 1, Y: 1, Z: -1}, mass: 1, }, lnw: { particle: particle3{x: -1, y: -1, z: -1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -1, Y: -1, Z: -1}, Max: r3.Vec{X: 0, Y: 0, Z: 0}}, center: r3.Vec{X: -1, Y: -1, Z: -1}, mass: 1, }, une: { particle: particle3{x: 1, y: -1, z: 1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: 0, Y: -1, Z: 0}, Max: r3.Vec{X: 1, Y: 0, Z: 1}}, center: r3.Vec{X: 1, Y: -1, Z: 1}, mass: 1, }, usw: { particle: particle3{x: -1, y: 1, z: 1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -1, Y: 0, Z: 0}, Max: r3.Vec{X: 0, Y: 1, Z: 1}}, center: r3.Vec{X: -1, Y: 1, Z: 1}, mass: 1, }, }, center: r3.Vec{X: 0, Y: 0, Z: 0}, mass: 4, }, Particles: []Particle3{ particle3{x: 1, y: 1, z: -1, m: 1}, particle3{x: -1, y: 1, z: 1, m: 1}, particle3{x: 1, y: -1, z: 1, m: 1}, particle3{x: -1, y: -1, z: -1, m: 1}, }, }, }, { name: "5 corners", particles: []particle3{ {x: 1, y: 1, z: -1, m: 1}, {x: -1, y: 1, z: 1, m: 1}, {x: 1, y: -1, z: 1, m: 1}, {x: -1, y: -1, z: -1, m: 1}, {x: -1.1, y: -1, z: -1.1, m: 1}, }, want: &Volume{ root: bucket{ bounds: r3.Box{Min: r3.Vec{X: -1.1, Y: -1, Z: -1.1}, Max: r3.Vec{X: 1, Y: 1, Z: 1}}, nodes: [8]*bucket{ lse: { particle: particle3{x: 1, y: 1, z: -1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -0.050000000000000044, Y: 0, Z: -1.1}, Max: r3.Vec{X: 1, Y: 1, Z: -0.050000000000000044}}, center: r3.Vec{X: 1, Y: 1, Z: -1}, mass: 1, }, lnw: { bounds: r3.Box{Min: r3.Vec{X: -1.1, Y: -1, Z: -1.1}, Max: r3.Vec{X: -0.050000000000000044, Y: 0, Z: -0.050000000000000044}}, nodes: [8]*bucket{ lnw: { bounds: r3.Box{Min: r3.Vec{X: -1.1, Y: -1, Z: -1.1}, Max: r3.Vec{X: -0.5750000000000001, Y: -0.5, Z: -0.5750000000000001}}, nodes: [8]*bucket{ lnw: { bounds: r3.Box{Min: r3.Vec{X: -1.1, Y: -1, Z: -1.1}, Max: r3.Vec{X: -0.8375000000000001, Y: -0.75, Z: -0.8375000000000001}}, nodes: [8]*bucket{ lnw: { bounds: r3.Box{Min: r3.Vec{X: -1.1, Y: -1, Z: -1.1}, Max: r3.Vec{X: -0.9687500000000001, Y: -0.875, Z: -0.9687500000000001}}, nodes: [8]*bucket{ lnw: { particle: particle3{x: -1.1, y: -1, z: -1.1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -1.1, Y: -1, Z: -1.1}, Max: r3.Vec{X: -1.034375, Y: -0.9375, Z: -1.034375}}, center: r3.Vec{X: -1.1, Y: -1, Z: -1.1}, mass: 1, }, une: { particle: particle3{x: -1, y: -1, z: -1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -1.034375, Y: -1, Z: -1.034375}, Max: r3.Vec{X: -0.9687500000000001, Y: -0.9375, Z: -0.9687500000000001}}, center: r3.Vec{X: -1, Y: -1, Z: -1}, mass: 1, }, }, center: r3.Vec{X: -1.05, Y: -1, Z: -1.05}, mass: 2, }, }, center: r3.Vec{X: -1.05, Y: -1, Z: -1.05}, mass: 2, }, }, center: r3.Vec{X: -1.05, Y: -1, Z: -1.05}, mass: 2, }, }, center: r3.Vec{X: -1.05, Y: -1, Z: -1.05}, mass: 2, }, une: { particle: particle3{x: 1, y: -1, z: 1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -0.050000000000000044, Y: -1, Z: -0.050000000000000044}, Max: r3.Vec{X: 1, Y: 0, Z: 1}}, center: r3.Vec{X: 1, Y: -1, Z: 1}, mass: 1, }, usw: { particle: particle3{x: -1, y: 1, z: 1, m: 1}, bounds: r3.Box{Min: r3.Vec{X: -1.1, Y: 0, Z: -0.050000000000000044}, Max: r3.Vec{X: -0.050000000000000044, Y: 1, Z: 1}}, center: r3.Vec{X: -1, Y: 1, Z: 1}, mass: 1, }, }, center: r3.Vec{X: -0.22000000000000003, Y: -0.2, Z: -0.22000000000000003}, mass: 5, }, Particles: []Particle3{ particle3{x: 1, y: 1, z: -1, m: 1}, particle3{x: -1, y: 1, z: 1, m: 1}, particle3{x: 1, y: -1, z: 1, m: 1}, particle3{x: -1, y: -1, z: -1, m: 1}, particle3{x: -1.1, y: -1, z: -1.1, m: 1}, }, }, }, { // This case is derived from the 2D example of the same name, // but with a monotonic increase in Z position according to name. name: "http://arborjs.org/docs/barnes-hut example", particles: []particle3{ {x: 64.5, y: 81.5, z: 0, m: 1, name: "A"}, {x: 242, y: 34, z: 40, m: 1, name: "B"}, {x: 199, y: 69, z: 80, m: 1, name: "C"}, {x: 285, y: 106.5, z: 120, m: 1, name: "D"}, {x: 170, y: 194.5, z: 160, m: 1, name: "E"}, {x: 42.5, y: 334.5, z: 200, m: 1, name: "F"}, {x: 147, y: 309, z: 240, m: 1, name: "G"}, {x: 236.5, y: 324, z: 280, m: 1, name: "H"}, }, want: &Volume{ root: bucket{ bounds: r3.Box{Min: r3.Vec{X: 42.5, Y: 34, Z: 0}, Max: r3.Vec{X: 285, Y: 334.5, Z: 280}}, nodes: [8]*bucket{ lne: { bounds: r3.Box{Min: r3.Vec{X: 163.75, Y: 34, Z: 0}, Max: r3.Vec{X: 285, Y: 184.25, Z: 140}}, nodes: [8]*bucket{ lne: { particle: particle3{x: 242, y: 34, z: 40, m: 1, name: "B"}, bounds: r3.Box{Min: r3.Vec{X: 224.375, Y: 34, Z: 0}, Max: r3.Vec{X: 285, Y: 109.125, Z: 70}}, center: r3.Vec{X: 242, Y: 34, Z: 40}, mass: 1, }, une: { particle: particle3{x: 285, y: 106.5, z: 120, m: 1, name: "D"}, bounds: r3.Box{Min: r3.Vec{X: 224.375, Y: 34, Z: 70}, Max: r3.Vec{X: 285, Y: 109.125, Z: 140}}, center: r3.Vec{X: 285, Y: 106.5, Z: 120}, mass: 1, }, unw: { particle: particle3{x: 199, y: 69, z: 80, m: 1, name: "C"}, bounds: r3.Box{Min: r3.Vec{X: 163.75, Y: 34, Z: 70}, Max: r3.Vec{X: 224.375, Y: 109.125, Z: 140}}, center: r3.Vec{X: 199, Y: 69, Z: 80}, mass: 1, }, }, center: r3.Vec{X: 242, Y: 69.83333333333333, Z: 80}, mass: 3, }, lnw: { particle: particle3{x: 64.5, y: 81.5, z: 0, m: 1, name: "A"}, bounds: r3.Box{Min: r3.Vec{X: 42.5, Y: 34, Z: 0}, Max: r3.Vec{X: 163.75, Y: 184.25, Z: 140}}, center: r3.Vec{X: 64.5, Y: 81.5, Z: 0}, mass: 1, }, (*bucket)(nil), use: { bounds: r3.Box{Min: r3.Vec{X: 163.75, Y: 184.25, Z: 140}, Max: r3.Vec{X: 285, Y: 334.5, Z: 280}}, nodes: [8]*bucket{ lnw: { particle: particle3{x: 170, y: 194.5, z: 160, m: 1, name: "E"}, bounds: r3.Box{Min: r3.Vec{X: 163.75, Y: 184.25, Z: 140}, Max: r3.Vec{X: 224.375, Y: 259.375, Z: 210}}, center: r3.Vec{X: 170, Y: 194.5, Z: 160}, mass: 1, }, use: { particle: particle3{x: 236.5, y: 324, z: 280, m: 1, name: "H"}, bounds: r3.Box{Min: r3.Vec{X: 224.375, Y: 259.375, Z: 210}, Max: r3.Vec{X: 285, Y: 334.5, Z: 280}}, center: r3.Vec{X: 236.5, Y: 324, Z: 280}, mass: 1, }, }, center: r3.Vec{X: 203.25, Y: 259.25, Z: 220}, mass: 2, }, usw: { bounds: r3.Box{Min: r3.Vec{X: 42.5, Y: 184.25, Z: 140}, Max: r3.Vec{X: 163.75, Y: 334.5, Z: 280}}, nodes: [8]*bucket{ lsw: { particle: particle3{x: 42.5, y: 334.5, z: 200, m: 1, name: "F"}, bounds: r3.Box{Min: r3.Vec{X: 42.5, Y: 259.375, Z: 140}, Max: r3.Vec{X: 103.125, Y: 334.5, Z: 210}}, center: r3.Vec{X: 42.5, Y: 334.5, Z: 200}, mass: 1, }, use: { particle: particle3{x: 147, y: 309, z: 240, m: 1, name: "G"}, bounds: r3.Box{Min: r3.Vec{X: 103.125, Y: 259.375, Z: 210}, Max: r3.Vec{X: 163.75, Y: 334.5, Z: 280}}, center: r3.Vec{X: 147, Y: 309, Z: 240}, mass: 1, }, }, center: r3.Vec{X: 94.75, Y: 321.75, Z: 220}, mass: 2, }, }, center: r3.Vec{X: 173.3125, Y: 181.625, Z: 140}, mass: 8, }, Particles: []Particle3{ particle3{x: 64.5, y: 81.5, z: 0, m: 1, name: "A"}, particle3{x: 242, y: 34, z: 40, m: 1, name: "B"}, particle3{x: 199, y: 69, z: 80, m: 1, name: "C"}, particle3{x: 285, y: 106.5, z: 120, m: 1, name: "D"}, particle3{x: 170, y: 194.5, z: 160, m: 1, name: "E"}, particle3{x: 42.5, y: 334.5, z: 200, m: 1, name: "F"}, particle3{x: 147, y: 309, z: 240, m: 1, name: "G"}, particle3{x: 236.5, y: 324, z: 280, m: 1, name: "H"}, }, }, }, } func TestVolume(t *testing.T) { t.Parallel() const tol = 1e-15 for _, test := range volumeTests { var particles []Particle3 if test.particles != nil { particles = make([]Particle3, len(test.particles)) } for i, p := range test.particles { particles[i] = p } got, err := NewVolume(particles) if err != nil { t.Errorf("unexpected error: %v", err) continue } if test.want != nil && !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result for %q: got:%v want:%v", test.name, got, test.want) } // Recursively check all internal centers of mass. walkVolume(&got.root, func(b *bucket) { var sub []Particle3 walkVolume(b, func(b *bucket) { if b.particle != nil { sub = append(sub, b.particle) } }) center, mass := centerOfMass3(sub) if !scalar.EqualWithinAbsOrRel(center.X, b.center.X, tol, tol) || !scalar.EqualWithinAbsOrRel(center.Y, b.center.Y, tol, tol) || !scalar.EqualWithinAbsOrRel(center.Z, b.center.Z, tol, tol) { t.Errorf("unexpected result for %q for center of mass: got:%f want:%f", test.name, b.center, center) } if !scalar.EqualWithinAbsOrRel(mass, b.mass, tol, tol) { t.Errorf("unexpected result for %q for total mass: got:%f want:%f", test.name, b.mass, mass) } }) } } func centerOfMass3(particles []Particle3) (center r3.Vec, mass float64) { for _, p := range particles { m := p.Mass() mass += m c := p.Coord3() center.X += c.X * m center.Y += c.Y * m center.Z += c.Z * m } if mass != 0 { center.X /= mass center.Y /= mass center.Z /= mass } return center, mass } func walkVolume(t *bucket, fn func(*bucket)) { if t == nil { return } fn(t) for _, q := range t.nodes { walkVolume(q, fn) } } func TestVolumeForceOn(t *testing.T) { t.Parallel() const ( size = 1000 tol = 1e-3 ) for _, n := range []int{3e3, 1e4, 3e4} { rnd := rand.New(rand.NewSource(1)) particles := make([]Particle3, n) for i := range particles { particles[i] = particle3{x: size * rnd.Float64(), y: size * rnd.Float64(), z: size * rnd.Float64(), m: 1} } moved := make([]r3.Vec, n) for i, p := range particles { var v r3.Vec m := p.Mass() pv := p.Coord3() for _, e := range particles { v = r3.Add(v, Gravity3(p, e, m, e.Mass(), r3.Sub(e.Coord3(), pv))) } moved[i] = r3.Add(p.Coord3(), v) } volume, err := NewVolume(particles) if err != nil { t.Errorf("unexpected error: %v", err) continue } for _, theta := range []float64{0, 0.3, 0.6, 0.9} { theta := theta t.Run(fmt.Sprintf("%d-body/theta=%v", len(particles), theta), func(t *testing.T) { t.Parallel() var ssd, sd float64 var calls int for i, p := range particles { v := volume.ForceOn(p, theta, func(p1, p2 Particle3, m1, m2 float64, v r3.Vec) r3.Vec { calls++ return Gravity3(p1, p2, m1, m2, v) }) pos := r3.Add(p.Coord3(), v) d := r3.Sub(moved[i], pos) ssd += d.X*d.X + d.Y*d.Y + d.Z*d.Z sd += math.Hypot(math.Hypot(d.X, d.Y), d.Z) } rmsd := math.Sqrt(ssd / float64(len(particles))) if rmsd > tol { t.Error("RMSD for approximation too high") } t.Logf("rmsd=%.4v md=%.4v calls/particle=%.5v", rmsd, sd/float64(len(particles)), float64(calls)/float64(len(particles))) }) } } } var ( fv3sink r3.Vec volumeSink *Volume ) func BenchmarkNewVolume(b *testing.B) { for _, n := range []int{1e3, 1e4, 1e5, 1e6} { rnd := rand.New(rand.NewSource(1)) particles := make([]Particle3, n) for i := range particles { particles[i] = particle3{x: rnd.Float64(), y: rnd.Float64(), z: rnd.Float64(), m: 1} } b.ResetTimer() var err error b.Run(fmt.Sprintf("%d-body", len(particles)), func(b *testing.B) { for i := 0; i < b.N; i++ { volumeSink, err = NewVolume(particles) if err != nil { b.Fatalf("unexpected error: %v", err) } } }) } } func BenchmarkVolumeForceOn(b *testing.B) { for _, n := range []int{1e3, 1e4, 1e5} { for _, theta := range []float64{0, 0.1, 0.5, 1, 1.5} { if n > 1e4 && theta < 0.5 { // Don't run unreasonably long benchmarks. continue } rnd := rand.New(rand.NewSource(1)) particles := make([]Particle3, n) for i := range particles { particles[i] = particle3{x: rnd.Float64(), y: rnd.Float64(), z: rnd.Float64(), m: 1} } volume, err := NewVolume(particles) if err != nil { b.Fatalf("unexpected error: %v", err) } b.ResetTimer() b.Run(fmt.Sprintf("%d-body/theta=%v", len(particles), theta), func(b *testing.B) { for i := 0; i < b.N; i++ { for _, p := range particles { fv3sink = volume.ForceOn(p, theta, Gravity3) } } }) } } } func BenchmarkVolumeFull(b *testing.B) { for _, n := range []int{1e3, 1e4, 1e5} { for _, theta := range []float64{0, 0.1, 0.5, 1, 1.5} { if n > 1e4 && theta < 0.5 { // Don't run unreasonably long benchmarks. continue } rnd := rand.New(rand.NewSource(1)) particles := make([]Particle3, n) for i := range particles { particles[i] = particle3{x: rnd.Float64(), y: rnd.Float64(), z: rnd.Float64(), m: 1} } b.ResetTimer() b.Run(fmt.Sprintf("%d-body/theta=%v", len(particles), theta), func(b *testing.B) { for i := 0; i < b.N; i++ { volume, err := NewVolume(particles) if err != nil { b.Fatalf("unexpected error: %v", err) } for _, p := range particles { fv3sink = volume.ForceOn(p, theta, Gravity3) } } }) } } } golang-gonum-v1-gonum-0.14.0/spatial/barneshut/bounds.go000066400000000000000000000003651450372207100231130ustar00rootroot00000000000000// Copyright ©2019 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:build bounds // +build bounds package barneshut const checkBounds = true golang-gonum-v1-gonum-0.14.0/spatial/barneshut/doc.go000066400000000000000000000007721450372207100223700ustar00rootroot00000000000000// Copyright ©2019 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 barneshut provides routines for calculating n-body force approximations // using the Barnes-Hut algorithm. // // See https://en.wikipedia.org/wiki/Barnes–Hut_simulation, http://arborjs.org/docs/barnes-hut // and https://jheer.github.io/barnes-hut/ for details. package barneshut // import "gonum.org/v1/gonum/spatial/barneshut" golang-gonum-v1-gonum-0.14.0/spatial/barneshut/galaxy_example_test.go000066400000000000000000000034341450372207100256600ustar00rootroot00000000000000// Copyright ©2019 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 barneshut_test import ( "log" "golang.org/x/exp/rand" "gonum.org/v1/gonum/spatial/barneshut" "gonum.org/v1/gonum/spatial/r2" ) type mass struct { d r2.Vec v r2.Vec m float64 } func (m *mass) Coord2() r2.Vec { return m.d } func (m *mass) Mass() float64 { return m.m } func (m *mass) move(f r2.Vec) { m.v = r2.Add(m.v, r2.Scale(1/m.m, f)) m.d = r2.Add(m.d, m.v) } func Example_galaxy() { rnd := rand.New(rand.NewSource(1)) // Make 1000 stars in random locations. stars := make([]*mass, 1000) p := make([]barneshut.Particle2, len(stars)) for i := range stars { s := &mass{ d: r2.Vec{ X: 100 * rnd.Float64(), Y: 100 * rnd.Float64(), }, v: r2.Vec{ X: rnd.NormFloat64(), Y: rnd.NormFloat64(), }, m: 10 * rnd.Float64(), } stars[i] = s p[i] = s } vectors := make([]r2.Vec, len(stars)) // Make a plane to calculate approximate forces plane := barneshut.Plane{Particles: p} // Run a simulation for 100 updates. for i := 0; i < 1000; i++ { // Build the data structure. For small systems // this step may be omitted and ForceOn will // perform the naive quadratic calculation // without building the data structure. err := plane.Reset() if err != nil { log.Fatal(err) } // Calculate the force vectors using the theta // parameter... const theta = 0.5 // and an imaginary gravitational constant. const G = 10 for j, s := range stars { vectors[j] = r2.Scale(G, plane.ForceOn(s, theta, barneshut.Gravity2)) } // Update positions. for j, s := range stars { s.move(vectors[j]) } // Rendering stars is left as an exercise for // the reader. } } golang-gonum-v1-gonum-0.14.0/spatial/barneshut/no_bounds.go000066400000000000000000000003701450372207100236030ustar00rootroot00000000000000// Copyright ©2019 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:build !bounds // +build !bounds package barneshut const checkBounds = false golang-gonum-v1-gonum-0.14.0/spatial/kdtree/000077500000000000000000000000001450372207100205515ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/spatial/kdtree/doc.go000066400000000000000000000005501450372207100216450ustar00rootroot00000000000000// Copyright ©2019 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 kdtree implements a k-d tree. // // See https://en.wikipedia.org/wiki/K-d_tree for more details of k-d tree functionality. package kdtree // import "gonum.org/v1/gonum/spatial/kdtree" golang-gonum-v1-gonum-0.14.0/spatial/kdtree/kdtree.go000066400000000000000000000277521450372207100223730ustar00rootroot00000000000000// Copyright ©2019 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 kdtree import ( "container/heap" "fmt" "math" "sort" ) // Interface is the set of methods required for construction of efficiently // searchable k-d trees. A k-d tree may be constructed without using the // Interface type, but it is likely to have reduced search performance. type Interface interface { // Index returns the ith element of the list of points. Index(i int) Comparable // Len returns the length of the list. Len() int // Pivot partitions the list based on the dimension specified. Pivot(Dim) int // Slice returns a slice of the list using zero-based half // open indexing equivalent to built-in slice indexing. Slice(start, end int) Interface } // Bounder returns a bounding volume containing the list of points. Bounds may return nil. type Bounder interface { Bounds() *Bounding } type bounder interface { Interface Bounder } // Dim is an index into a point's coordinates. type Dim int // Comparable is the element interface for values stored in a k-d tree. type Comparable interface { // Compare returns the signed distance of a from the plane passing through // b and perpendicular to the dimension d. // // Given c = a.Compare(b, d): // c = a_d - b_d // Compare(Comparable, Dim) float64 // Dims returns the number of dimensions described in the Comparable. Dims() int // Distance returns the squared Euclidean distance between the receiver and // the parameter. Distance(Comparable) float64 } // Extender is a Comparable that can increase a bounding volume to include the // point represented by the Comparable. type Extender interface { Comparable // Extend returns a bounding box that has been extended to include the // receiver. Extend may return nil. Extend(*Bounding) *Bounding } // Bounding represents a volume bounding box. type Bounding struct { Min, Max Comparable } // Contains returns whether c is within the volume of the Bounding. A nil Bounding // returns true. func (b *Bounding) Contains(c Comparable) bool { if b == nil { return true } for d := Dim(0); d < Dim(c.Dims()); d++ { if c.Compare(b.Min, d) < 0 || 0 < c.Compare(b.Max, d) { return false } } return true } // Node holds a single point value in a k-d tree. type Node struct { Point Comparable Plane Dim Left, Right *Node *Bounding } func (n *Node) String() string { if n == nil { return "" } return fmt.Sprintf("%.3f %d", n.Point, n.Plane) } // Tree implements a k-d tree creation and nearest neighbor search. type Tree struct { Root *Node Count int } // New returns a k-d tree constructed from the values in p. If p is a Bounder and // bounding is true, bounds are determined for each node. // The ordering of elements in p may be altered after New returns. func New(p Interface, bounding bool) *Tree { if p, ok := p.(bounder); ok && bounding { return &Tree{ Root: buildBounded(p, 0, bounding), Count: p.Len(), } } return &Tree{ Root: build(p, 0), Count: p.Len(), } } func build(p Interface, plane Dim) *Node { if p.Len() == 0 { return nil } piv := p.Pivot(plane) d := p.Index(piv) np := (plane + 1) % Dim(d.Dims()) return &Node{ Point: d, Plane: plane, Left: build(p.Slice(0, piv), np), Right: build(p.Slice(piv+1, p.Len()), np), Bounding: nil, } } func buildBounded(p bounder, plane Dim, bounding bool) *Node { if p.Len() == 0 { return nil } piv := p.Pivot(plane) d := p.Index(piv) np := (plane + 1) % Dim(d.Dims()) b := p.Bounds() return &Node{ Point: d, Plane: plane, Left: buildBounded(p.Slice(0, piv).(bounder), np, bounding), Right: buildBounded(p.Slice(piv+1, p.Len()).(bounder), np, bounding), Bounding: b, } } // Insert adds a point to the tree, updating the bounding volumes if bounding is // true, and the tree is empty or the tree already has bounding volumes stored, // and c is an Extender. No rebalancing of the tree is performed. func (t *Tree) Insert(c Comparable, bounding bool) { t.Count++ if t.Root != nil { bounding = t.Root.Bounding != nil } if c, ok := c.(Extender); ok && bounding { t.Root = t.Root.insertBounded(c, 0, bounding) return } else if !ok && t.Root != nil { // If we are not rebounding, mark the tree as non-bounded. t.Root.Bounding = nil } t.Root = t.Root.insert(c, 0) } func (n *Node) insert(c Comparable, d Dim) *Node { if n == nil { return &Node{ Point: c, Plane: d, Bounding: nil, } } d = (n.Plane + 1) % Dim(c.Dims()) if c.Compare(n.Point, n.Plane) <= 0 { n.Left = n.Left.insert(c, d) } else { n.Right = n.Right.insert(c, d) } return n } func (n *Node) insertBounded(c Extender, d Dim, bounding bool) *Node { if n == nil { var b *Bounding if bounding { b = c.Extend(b) } return &Node{ Point: c, Plane: d, Bounding: b, } } if bounding { n.Bounding = c.Extend(n.Bounding) } d = (n.Plane + 1) % Dim(c.Dims()) if c.Compare(n.Point, n.Plane) <= 0 { n.Left = n.Left.insertBounded(c, d, bounding) } else { n.Right = n.Right.insertBounded(c, d, bounding) } return n } // Len returns the number of elements in the tree. func (t *Tree) Len() int { return t.Count } // Contains returns whether a Comparable is in the bounds of the tree. If no bounding has // been constructed Contains returns true. func (t *Tree) Contains(c Comparable) bool { if t.Root.Bounding == nil { return true } return t.Root.Contains(c) } var inf = math.Inf(1) // Nearest returns the nearest value to the query and the distance between them. func (t *Tree) Nearest(q Comparable) (Comparable, float64) { if t.Root == nil { return nil, inf } n, dist := t.Root.search(q, inf) if n == nil { return nil, inf } return n.Point, dist } func (n *Node) search(q Comparable, dist float64) (*Node, float64) { if n == nil { return nil, inf } c := q.Compare(n.Point, n.Plane) dist = math.Min(dist, q.Distance(n.Point)) bn := n if c <= 0 { ln, ld := n.Left.search(q, dist) if ld < dist { bn, dist = ln, ld } if c*c < dist { rn, rd := n.Right.search(q, dist) if rd < dist { bn, dist = rn, rd } } return bn, dist } rn, rd := n.Right.search(q, dist) if rd < dist { bn, dist = rn, rd } if c*c < dist { ln, ld := n.Left.search(q, dist) if ld < dist { bn, dist = ln, ld } } return bn, dist } // ComparableDist holds a Comparable and a distance to a specific query. A nil Comparable // is used to mark the end of the heap, so clients should not store nil values except for // this purpose. type ComparableDist struct { Comparable Comparable Dist float64 } // Heap is a max heap sorted on Dist. type Heap []ComparableDist func (h *Heap) Max() ComparableDist { return (*h)[0] } func (h *Heap) Len() int { return len(*h) } func (h *Heap) Less(i, j int) bool { return (*h)[i].Comparable == nil || (*h)[i].Dist > (*h)[j].Dist } func (h *Heap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } func (h *Heap) Push(x interface{}) { (*h) = append(*h, x.(ComparableDist)) } func (h *Heap) Pop() (i interface{}) { i, *h = (*h)[len(*h)-1], (*h)[:len(*h)-1]; return i } // NKeeper is a Keeper that retains the n best ComparableDists that have been passed to Keep. type NKeeper struct { Heap } // NewNKeeper returns an NKeeper with the max value of the heap set to infinite distance. The // returned NKeeper is able to retain at most n values. func NewNKeeper(n int) *NKeeper { k := NKeeper{make(Heap, 1, n)} k.Heap[0].Dist = inf return &k } // Keep adds c to the heap if its distance is less than the maximum value of the heap. If adding // c would increase the size of the heap beyond the initial maximum length, the maximum value of // the heap is dropped. func (k *NKeeper) Keep(c ComparableDist) { if c.Dist <= k.Heap[0].Dist { // Favour later finds to displace sentinel. if len(k.Heap) == cap(k.Heap) { heap.Pop(k) } heap.Push(k, c) } } // DistKeeper is a Keeper that retains the ComparableDists within the specified distance of the // query that it is called to Keep. type DistKeeper struct { Heap } // NewDistKeeper returns an DistKeeper with the maximum value of the heap set to d. func NewDistKeeper(d float64) *DistKeeper { return &DistKeeper{Heap{{Dist: d}}} } // Keep adds c to the heap if its distance is less than or equal to the max value of the heap. func (k *DistKeeper) Keep(c ComparableDist) { if c.Dist <= k.Heap[0].Dist { heap.Push(k, c) } } // Keeper implements a conditional max heap sorted on the Dist field of the ComparableDist type. // kd search is guided by the distance stored in the max value of the heap. type Keeper interface { Keep(ComparableDist) // Keep conditionally pushes the provided ComparableDist onto the heap. Max() ComparableDist // Max returns the maximum element of the Keeper. heap.Interface } // NearestSet finds the nearest values to the query accepted by the provided Keeper, k. // k must be able to return a ComparableDist specifying the maximum acceptable distance // when Max() is called, and retains the results of the search in min sorted order after // the call to NearestSet returns. // If a sentinel ComparableDist with a nil Comparable is used by the Keeper to mark the // maximum distance, NearestSet will remove it before returning. func (t *Tree) NearestSet(k Keeper, q Comparable) { if t.Root == nil { return } t.Root.searchSet(q, k) // Check whether we have retained a sentinel // and flag removal if we have. removeSentinel := k.Len() != 0 && k.Max().Comparable == nil sort.Sort(sort.Reverse(k)) // This abuses the interface to drop the max. // It is reasonable to do this because we know // that the maximum value will now be at element // zero, which is removed by the Pop method. if removeSentinel { k.Pop() } } func (n *Node) searchSet(q Comparable, k Keeper) { if n == nil { return } c := q.Compare(n.Point, n.Plane) k.Keep(ComparableDist{Comparable: n.Point, Dist: q.Distance(n.Point)}) if c <= 0 { n.Left.searchSet(q, k) if c*c <= k.Max().Dist { n.Right.searchSet(q, k) } return } n.Right.searchSet(q, k) if c*c <= k.Max().Dist { n.Left.searchSet(q, k) } } // Operation is a function that operates on a Comparable. The bounding volume and tree depth // of the point is also provided. If done is returned true, the Operation is indicating that no // further work needs to be done and so the Do function should traverse no further. type Operation func(Comparable, *Bounding, int) (done bool) // Do performs fn on all values stored in the tree. A boolean is returned indicating whether the // Do traversal was interrupted by an Operation returning true. If fn alters stored values' sort // relationships, future tree operation behaviors are undefined. func (t *Tree) Do(fn Operation) bool { if t.Root == nil { return false } return t.Root.do(fn, 0) } func (n *Node) do(fn Operation, depth int) (done bool) { if n.Left != nil { done = n.Left.do(fn, depth+1) if done { return } } done = fn(n.Point, n.Bounding, depth) if done { return } if n.Right != nil { done = n.Right.do(fn, depth+1) } return } // DoBounded performs fn on all values stored in the tree that are within the specified bound. // If b is nil, the result is the same as a Do. A boolean is returned indicating whether the // DoBounded traversal was interrupted by an Operation returning true. If fn alters stored // values' sort relationships future tree operation behaviors are undefined. func (t *Tree) DoBounded(b *Bounding, fn Operation) bool { if t.Root == nil { return false } if b == nil { return t.Root.do(fn, 0) } return t.Root.doBounded(fn, b, 0) } func (n *Node) doBounded(fn Operation, b *Bounding, depth int) (done bool) { if n.Left != nil && b.Min.Compare(n.Point, n.Plane) < 0 { done = n.Left.doBounded(fn, b, depth+1) if done { return } } if b.Contains(n.Point) { done = fn(n.Point, n.Bounding, depth) if done { return } } if n.Right != nil && 0 < b.Max.Compare(n.Point, n.Plane) { done = n.Right.doBounded(fn, b, depth+1) } return } golang-gonum-v1-gonum-0.14.0/spatial/kdtree/kdtree_simple_example_test.go000066400000000000000000000043631450372207100265070ustar00rootroot00000000000000// Copyright ©2019 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 kdtree_test import ( "fmt" "math" "gonum.org/v1/gonum/spatial/kdtree" ) func ExampleTree() { // Example data from https://en.wikipedia.org/wiki/K-d_tree points := kdtree.Points{{2, 3}, {5, 4}, {9, 6}, {4, 7}, {8, 1}, {7, 2}} t := kdtree.New(points, false) q := kdtree.Point{8, 7} p, d := t.Nearest(q) fmt.Printf("%v is closest point to %v, d=%f\n", p, q, math.Sqrt(d)) // Output: // [9 6] is closest point to [8 7], d=1.414214 } func ExampleTree_bounds() { // Example data from https://en.wikipedia.org/wiki/K-d_tree points := kdtree.Points{{2, 3}, {5, 4}, {9, 6}, {4, 7}, {8, 1}, {7, 2}} t := kdtree.New(points, true) fmt.Printf("Bounding box of points is %+v\n", t.Root.Bounding) // Output: // Bounding box of points is &{Min:[2 1] Max:[9 7]} } func ExampleTree_Do() { // Example data from https://en.wikipedia.org/wiki/K-d_tree points := kdtree.Points{{2, 3}, {5, 4}, {9, 6}, {4, 7}, {8, 1}, {7, 2}} // Print all points in the data set within 3 of (3, 5). t := kdtree.New(points, false) q := kdtree.Point{3, 5} t.Do(func(c kdtree.Comparable, _ *kdtree.Bounding, _ int) (done bool) { // Compare each distance and output points // with a Euclidean distance less than 3. // Distance returns the square of the // Euclidean distance between points. if q.Distance(c) <= 3*3 { fmt.Println(c) } return }) // Unordered output: // [2 3] // [4 7] // [5 4] } func ExampleTree_DoBounded() { // Example data from https://en.wikipedia.org/wiki/K-d_tree points := kdtree.Points{{2, 3}, {5, 4}, {9, 6}, {4, 7}, {8, 1}, {7, 2}} // Find all points within the bounding box ((3, 3), (6, 8)) // and print them with their bounding boxes and tree depth. t := kdtree.New(points, true) // Construct tree with bounding boxes. b := &kdtree.Bounding{ Min: kdtree.Point{3, 3}, Max: kdtree.Point{6, 8}, } t.DoBounded(b, func(c kdtree.Comparable, bound *kdtree.Bounding, depth int) (done bool) { fmt.Printf("p=%v bound=%+v depth=%d\n", c, bound, depth) return }) // Output: // p=[5 4] bound=&{Min:[2 3] Max:[5 7]} depth=1 // p=[4 7] bound=&{Min:[4 7] Max:[4 7]} depth=2 } golang-gonum-v1-gonum-0.14.0/spatial/kdtree/kdtree_test.go000066400000000000000000000362231450372207100234230ustar00rootroot00000000000000// Copyright ©2019 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 kdtree import ( "flag" "fmt" "math" "os" "reflect" "sort" "strings" "testing" "unsafe" "golang.org/x/exp/rand" ) var ( genDot = flag.Bool("dot", false, "generate dot code for failing trees") dotLimit = flag.Int("dotmax", 100, "specify maximum size for tree output for dot format") ) var ( // Using example from WP article: https://en.wikipedia.org/w/index.php?title=K-d_tree&oldid=887573572. wpData = Points{{2, 3}, {5, 4}, {9, 6}, {4, 7}, {8, 1}, {7, 2}} nbWpData = nbPoints{{2, 3}, {5, 4}, {9, 6}, {4, 7}, {8, 1}, {7, 2}} wpBound = &Bounding{Point{2, 1}, Point{9, 7}} ) var newTests = []struct { data Interface bounding bool wantBounds *Bounding }{ {data: wpData, bounding: false, wantBounds: nil}, {data: nbWpData, bounding: false, wantBounds: nil}, {data: wpData, bounding: true, wantBounds: wpBound}, {data: nbWpData, bounding: true, wantBounds: nil}, } func TestNew(t *testing.T) { for i, test := range newTests { var tree *Tree var panicked bool func() { defer func() { if r := recover(); r != nil { panicked = true } }() tree = New(test.data, test.bounding) }() if panicked { t.Errorf("unexpected panic for test %d", i) continue } if !tree.Root.isKDTree() { t.Errorf("tree %d is not k-d tree", i) } switch data := test.data.(type) { case Points: for _, p := range data { if !tree.Contains(p) { t.Errorf("failed to find point %.3f in test %d", p, i) } } case nbPoints: for _, p := range data { if !tree.Contains(p) { t.Errorf("failed to find point %.3f in test %d", p, i) } } default: t.Fatalf("bad test: unknown data type: %T", test.data) } if !reflect.DeepEqual(tree.Root.Bounding, test.wantBounds) { t.Errorf("unexpected bounding box for test %d with data type %T: got:%v want:%v", i, test.data, tree.Root.Bounding, test.wantBounds) } if t.Failed() && *genDot && tree.Len() <= *dotLimit { err := dotFile(tree, fmt.Sprintf("TestNew%T", test.data), "") if err != nil { t.Fatalf("failed to write DOT file: %v", err) } } } } var insertTests = []struct { data Interface insert []Comparable wantBounds *Bounding }{ { data: wpData, insert: []Comparable{Point{0, 0}, Point{10, 10}}, wantBounds: &Bounding{Point{0, 0}, Point{10, 10}}, }, { data: nbWpData, insert: []Comparable{nbPoint{0, 0}, nbPoint{10, 10}}, wantBounds: nil, }, } func TestInsert(t *testing.T) { for i, test := range insertTests { tree := New(test.data, true) for _, v := range test.insert { tree.Insert(v, true) } if !tree.Root.isKDTree() { t.Errorf("tree %d is not k-d tree", i) } if !reflect.DeepEqual(tree.Root.Bounding, test.wantBounds) { t.Errorf("unexpected bounding box for test %d with data type %T: got:%v want:%v", i, test.data, tree.Root.Bounding, test.wantBounds) } if t.Failed() && *genDot && tree.Len() <= *dotLimit { err := dotFile(tree, fmt.Sprintf("TestInsert%T", test.data), "") if err != nil { t.Fatalf("failed to write DOT file: %v", err) } } } } type compFn func(float64) bool func left(v float64) bool { return v <= 0 } func right(v float64) bool { return !left(v) } func (n *Node) isKDTree() bool { if n == nil { return true } d := n.Point.Dims() // Together these define the property of minimal orthogonal bounding. if !(n.isContainedBy(n.Bounding) && n.Bounding.planesHaveCoincidentPointsIn(n, [2][]bool{make([]bool, d), make([]bool, d)})) { return false } if !n.Left.isPartitioned(n.Point, left, n.Plane) { return false } if !n.Right.isPartitioned(n.Point, right, n.Plane) { return false } return n.Left.isKDTree() && n.Right.isKDTree() } func (n *Node) isPartitioned(pivot Comparable, fn compFn, plane Dim) bool { if n == nil { return true } if n.Left != nil && fn(pivot.Compare(n.Left.Point, plane)) { return false } if n.Right != nil && fn(pivot.Compare(n.Right.Point, plane)) { return false } return n.Left.isPartitioned(pivot, fn, plane) && n.Right.isPartitioned(pivot, fn, plane) } func (n *Node) isContainedBy(b *Bounding) bool { if n == nil { return true } if !b.Contains(n.Point) { return false } return n.Left.isContainedBy(b) && n.Right.isContainedBy(b) } func (b *Bounding) planesHaveCoincidentPointsIn(n *Node, tight [2][]bool) bool { if b == nil { return true } if n == nil { return true } b.planesHaveCoincidentPointsIn(n.Left, tight) b.planesHaveCoincidentPointsIn(n.Right, tight) var ok = true for i := range tight { for d := 0; d < n.Point.Dims(); d++ { if c := n.Point.Compare(b.Min, Dim(d)); c == 0 { tight[i][d] = true } ok = ok && tight[i][d] } } return ok } func nearest(q Point, p Points) (Point, float64) { min := q.Distance(p[0]) var r int for i := 1; i < p.Len(); i++ { d := q.Distance(p[i]) if d < min { min = d r = i } } return p[r], min } func TestNearestRandom(t *testing.T) { rnd := rand.New(rand.NewSource(1)) const ( min = 0.0 max = 1000.0 dims = 4 setSize = 10000 ) var randData Points for i := 0; i < setSize; i++ { p := make(Point, dims) for j := 0; j < dims; j++ { p[j] = (max-min)*rnd.Float64() + min } randData = append(randData, p) } tree := New(randData, false) for i := 0; i < setSize; i++ { q := make(Point, dims) for j := 0; j < dims; j++ { q[j] = (max-min)*rnd.Float64() + min } got, _ := tree.Nearest(q) want, _ := nearest(q, randData) if !reflect.DeepEqual(got, want) { t.Fatalf("unexpected result from query %d %.3f: got:%.3f want:%.3f", i, q, got, want) } } } func TestNearest(t *testing.T) { tree := New(wpData, false) for _, q := range append([]Point{ {4, 6}, {7, 5}, {8, 7}, {6, -5}, {1e5, 1e5}, {1e5, -1e5}, {-1e5, 1e5}, {-1e5, -1e5}, {1e5, 0}, {0, -1e5}, {0, 1e5}, {-1e5, 0}, }, wpData...) { gotP, gotD := tree.Nearest(q) wantP, wantD := nearest(q, wpData) if !reflect.DeepEqual(gotP, wantP) { t.Errorf("unexpected result for query %.3f: got:%.3f want:%.3f", q, gotP, wantP) } if gotD != wantD { t.Errorf("unexpected distance for query %.3f : got:%v want:%v", q, gotD, wantD) } } } func nearestN(n int, q Point, p Points) []ComparableDist { nk := NewNKeeper(n) for i := 0; i < p.Len(); i++ { nk.Keep(ComparableDist{Comparable: p[i], Dist: q.Distance(p[i])}) } if len(nk.Heap) == 1 { return nk.Heap } sort.Sort(nk) for i, j := 0, len(nk.Heap)-1; i < j; i, j = i+1, j-1 { nk.Heap[i], nk.Heap[j] = nk.Heap[j], nk.Heap[i] } return nk.Heap } func TestNearestSetN(t *testing.T) { data := append([]Point{ {4, 6}, {7, 5}, {8, 7}, {6, -5}, {1e5, 1e5}, {1e5, -1e5}, {-1e5, 1e5}, {-1e5, -1e5}, {1e5, 0}, {0, -1e5}, {0, 1e5}, {-1e5, 0}}, wpData[:len(wpData)-1]...) tree := New(wpData, false) for k := 1; k <= len(wpData); k++ { for _, q := range data { wantP := nearestN(k, q, wpData) nk := NewNKeeper(k) tree.NearestSet(nk, q) var max float64 wantD := make(map[float64]map[string]struct{}) for _, p := range wantP { if p.Dist > max { max = p.Dist } d, ok := wantD[p.Dist] if !ok { d = make(map[string]struct{}) } d[fmt.Sprint(p.Comparable)] = struct{}{} wantD[p.Dist] = d } gotD := make(map[float64]map[string]struct{}) for _, p := range nk.Heap { if p.Dist > max { t.Errorf("unexpected distance for point %.3f: got:%v want:<=%v", p.Comparable, p.Dist, max) } d, ok := gotD[p.Dist] if !ok { d = make(map[string]struct{}) } d[fmt.Sprint(p.Comparable)] = struct{}{} gotD[p.Dist] = d } // If the available number of slots does not fit all the coequal furthest points // we will fail the check. So remove, but check them minimally here. if !reflect.DeepEqual(wantD[max], gotD[max]) { // The best we can do at this stage is confirm that there are an equal number of matches at this distance. if len(gotD[max]) != len(wantD[max]) { t.Errorf("unexpected number of maximal distance points: got:%d want:%d", len(gotD[max]), len(wantD[max])) } delete(wantD, max) delete(gotD, max) } if !reflect.DeepEqual(gotD, wantD) { t.Errorf("unexpected result for k=%d query %.3f: got:%v want:%v", k, q, gotD, wantD) } } } } var nearestSetDistTests = []Point{ {4, 6}, {7, 5}, {8, 7}, {6, -5}, } func TestNearestSetDist(t *testing.T) { tree := New(wpData, false) for i, q := range nearestSetDistTests { for d := 1.0; d < 100; d += 0.1 { dk := NewDistKeeper(d) tree.NearestSet(dk, q) hits := make(map[string]float64) for _, p := range wpData { hits[fmt.Sprint(p)] = p.Distance(q) } for _, p := range dk.Heap { var done bool if p.Comparable == nil { done = true continue } delete(hits, fmt.Sprint(p.Comparable)) if done { t.Error("expectedly finished heap iteration") break } dist := p.Comparable.Distance(q) if dist > d { t.Errorf("Test %d: query %v found %v expect %.3f <= %.3f", i, q, p, dist, d) } } for p, dist := range hits { if dist <= d { t.Errorf("Test %d: query %v missed %v expect %.3f > %.3f", i, q, p, dist, d) } } } } } func TestDo(t *testing.T) { tree := New(wpData, false) var got Points fn := func(c Comparable, _ *Bounding, _ int) (done bool) { got = append(got, c.(Point)) return } killed := tree.Do(fn) if !reflect.DeepEqual(got, wpData) { t.Errorf("unexpected result from tree iteration: got:%v want:%v", got, wpData) } if killed { t.Error("tree iteration unexpectedly killed") } } var doBoundedTests = []struct { bounds *Bounding want Points }{ { bounds: nil, want: wpData, }, { bounds: &Bounding{Point{0, 0}, Point{10, 10}}, want: wpData, }, { bounds: &Bounding{Point{3, 4}, Point{10, 10}}, want: Points{Point{5, 4}, Point{4, 7}, Point{9, 6}}, }, { bounds: &Bounding{Point{3, 3}, Point{10, 10}}, want: Points{Point{5, 4}, Point{4, 7}, Point{9, 6}}, }, { bounds: &Bounding{Point{0, 0}, Point{6, 5}}, want: Points{Point{2, 3}, Point{5, 4}}, }, { bounds: &Bounding{Point{5, 2}, Point{7, 4}}, want: Points{Point{5, 4}, Point{7, 2}}, }, { bounds: &Bounding{Point{2, 2}, Point{7, 4}}, want: Points{Point{2, 3}, Point{5, 4}, Point{7, 2}}, }, { bounds: &Bounding{Point{2, 3}, Point{9, 6}}, want: Points{Point{2, 3}, Point{5, 4}, Point{9, 6}}, }, { bounds: &Bounding{Point{7, 2}, Point{7, 2}}, want: Points{Point{7, 2}}, }, } func TestDoBounded(t *testing.T) { for _, test := range doBoundedTests { tree := New(wpData, false) var got Points fn := func(c Comparable, _ *Bounding, _ int) (done bool) { got = append(got, c.(Point)) return } killed := tree.DoBounded(test.bounds, fn) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected result from bounded tree iteration: got:%v want:%v", got, test.want) } if killed { t.Error("tree iteration unexpectedly killed") } } } func BenchmarkNew(b *testing.B) { rnd := rand.New(rand.NewSource(1)) p := make(Points, 1e5) for i := range p { p[i] = Point{rnd.Float64(), rnd.Float64(), rnd.Float64()} } b.ResetTimer() for i := 0; i < b.N; i++ { _ = New(p, false) } } func BenchmarkNewBounds(b *testing.B) { rnd := rand.New(rand.NewSource(1)) p := make(Points, 1e5) for i := range p { p[i] = Point{rnd.Float64(), rnd.Float64(), rnd.Float64()} } b.ResetTimer() for i := 0; i < b.N; i++ { _ = New(p, true) } } func BenchmarkInsert(b *testing.B) { rnd := rand.New(rand.NewSource(1)) t := &Tree{} for i := 0; i < b.N; i++ { t.Insert(Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}, false) } } func BenchmarkInsertBounds(b *testing.B) { rnd := rand.New(rand.NewSource(1)) t := &Tree{} for i := 0; i < b.N; i++ { t.Insert(Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}, true) } } func Benchmark(b *testing.B) { rnd := rand.New(rand.NewSource(1)) data := make(Points, 1e2) for i := range data { data[i] = Point{rnd.Float64(), rnd.Float64(), rnd.Float64()} } tree := New(data, true) if !tree.Root.isKDTree() { b.Fatal("tree is not k-d tree") } for i := 0; i < 1e3; i++ { q := Point{rnd.Float64(), rnd.Float64(), rnd.Float64()} gotP, gotD := tree.Nearest(q) wantP, wantD := nearest(q, data) if !reflect.DeepEqual(gotP, wantP) { b.Errorf("unexpected result for query %.3f: got:%.3f want:%.3f", q, gotP, wantP) } if gotD != wantD { b.Errorf("unexpected distance for query %.3f : got:%v want:%v", q, gotD, wantD) } } if b.Failed() && *genDot && tree.Len() <= *dotLimit { err := dotFile(tree, "TestBenches", "") if err != nil { b.Fatalf("failed to write DOT file: %v", err) } return } var r Comparable var d float64 queryBenchmarks := []struct { name string fn func(*testing.B) }{ { name: "Nearest", fn: func(b *testing.B) { for i := 0; i < b.N; i++ { r, d = tree.Nearest(Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}) } if r == nil { b.Error("unexpected nil result") } if math.IsNaN(d) { b.Error("unexpected NaN result") } }, }, { name: "NearestBrute", fn: func(b *testing.B) { for i := 0; i < b.N; i++ { r, d = nearest(Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}, data) } if r == nil { b.Error("unexpected nil result") } if math.IsNaN(d) { b.Error("unexpected NaN result") } }, }, { name: "NearestSetN10", fn: func(b *testing.B) { nk := NewNKeeper(10) for i := 0; i < b.N; i++ { tree.NearestSet(nk, Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}) if nk.Len() != 10 { b.Error("unexpected result length") } nk.Heap = nk.Heap[:1] nk.Heap[0] = ComparableDist{Dist: inf} } }, }, { name: "NearestBruteN10", fn: func(b *testing.B) { var r []ComparableDist for i := 0; i < b.N; i++ { r = nearestN(10, Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}, data) } if len(r) != 10 { b.Error("unexpected result length", len(r)) } }, }, } for _, bench := range queryBenchmarks { b.Run(bench.name, bench.fn) } } func dot(t *Tree, label string) string { if t == nil { return "" } var ( s []string follow func(*Node) ) follow = func(n *Node) { id := uintptr(unsafe.Pointer(n)) c := fmt.Sprintf("%d[label = \" | %s/%.3f\\n%.3f|\"];", id, n, n.Point.(Point)[n.Plane], *n.Bounding) if n.Left != nil { c += fmt.Sprintf("\n\t\tedge [arrowhead=normal]; \"%d\":Left -> \"%d\":Elem;", id, uintptr(unsafe.Pointer(n.Left))) follow(n.Left) } if n.Right != nil { c += fmt.Sprintf("\n\t\tedge [arrowhead=normal]; \"%d\":Right -> \"%d\":Elem;", id, uintptr(unsafe.Pointer(n.Right))) follow(n.Right) } s = append(s, c) } if t.Root != nil { follow(t.Root) } return fmt.Sprintf("digraph %s {\n\tnode [shape=record,height=0.1];\n\t%s\n}\n", label, strings.Join(s, "\n\t"), ) } func dotFile(t *Tree, label, dotString string) (err error) { if t == nil && dotString == "" { return } f, err := os.Create(label + ".dot") if err != nil { return } defer f.Close() if dotString == "" { fmt.Fprint(f, dot(t, label)) } else { fmt.Fprint(f, dotString) } return } golang-gonum-v1-gonum-0.14.0/spatial/kdtree/kdtree_user_type_example_test.go000066400000000000000000000114021450372207100272250ustar00rootroot00000000000000// Copyright ©2019 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 kdtree_test import ( "fmt" "math" "gonum.org/v1/gonum/spatial/kdtree" ) func Example_accessiblePublicTransport() { // Construct a k-d tree of train station locations // to identify accessible public transport for the // elderly. t := kdtree.New(stations, false) // Residence. q := place{lat: 51.501476, lon: -0.140634} var keep kdtree.Keeper // Find all stations within 0.75 of the residence. keep = kdtree.NewDistKeeper(0.75 * 0.75) // Distances are squared. t.NearestSet(keep, q) fmt.Println(`Stations within 750 m of 51.501476N 0.140634W.`) for _, c := range keep.(*kdtree.DistKeeper).Heap { p := c.Comparable.(place) fmt.Printf("%s: %0.3f km\n", p.name, math.Sqrt(p.Distance(q))) } fmt.Println() // Find the five closest stations to the residence. keep = kdtree.NewNKeeper(5) t.NearestSet(keep, q) fmt.Println(`5 closest stations to 51.501476N 0.140634W.`) for _, c := range keep.(*kdtree.NKeeper).Heap { p := c.Comparable.(place) fmt.Printf("%s: %0.3f km\n", p.name, math.Sqrt(p.Distance(q))) } // Output: // // Stations within 750 m of 51.501476N 0.140634W. // St. James's Park: 0.545 km // Green Park: 0.600 km // Victoria: 0.621 km // // 5 closest stations to 51.501476N 0.140634W. // St. James's Park: 0.545 km // Green Park: 0.600 km // Victoria: 0.621 km // Hyde Park Corner: 0.846 km // Picadilly Circus: 1.027 km } // stations is a list of railways stations satisfying the // kdtree.Interface. var stations = places{ {name: "Bond Street", lat: 51.5142, lon: -0.1494}, {name: "Charing Cross", lat: 51.508, lon: -0.1247}, {name: "Covent Garden", lat: 51.5129, lon: -0.1243}, {name: "Embankment", lat: 51.5074, lon: -0.1223}, {name: "Green Park", lat: 51.5067, lon: -0.1428}, {name: "Hyde Park Corner", lat: 51.5027, lon: -0.1527}, {name: "Leicester Square", lat: 51.5113, lon: -0.1281}, {name: "Marble Arch", lat: 51.5136, lon: -0.1586}, {name: "Oxford Circus", lat: 51.515, lon: -0.1415}, {name: "Picadilly Circus", lat: 51.5098, lon: -0.1342}, {name: "Pimlico", lat: 51.4893, lon: -0.1334}, {name: "Sloane Square", lat: 51.4924, lon: -0.1565}, {name: "South Kensington", lat: 51.4941, lon: -0.1738}, {name: "St. James's Park", lat: 51.4994, lon: -0.1335}, {name: "Temple", lat: 51.5111, lon: -0.1141}, {name: "Tottenham Court Road", lat: 51.5165, lon: -0.131}, {name: "Vauxhall", lat: 51.4861, lon: -0.1253}, {name: "Victoria", lat: 51.4965, lon: -0.1447}, {name: "Waterloo", lat: 51.5036, lon: -0.1143}, {name: "Westminster", lat: 51.501, lon: -0.1254}, } // place is a kdtree.Comparable implementations. type place struct { name string lat, lon float64 } // Compare satisfies the axis comparisons method of the kdtree.Comparable interface. // The dimensions are: // // 0 = lat // 1 = lon func (p place) Compare(c kdtree.Comparable, d kdtree.Dim) float64 { q := c.(place) switch d { case 0: return p.lat - q.lat case 1: return p.lon - q.lon default: panic("illegal dimension") } } // Dims returns the number of dimensions to be considered. func (p place) Dims() int { return 2 } // Distance returns the distance between the receiver and c. func (p place) Distance(c kdtree.Comparable) float64 { q := c.(place) d := haversine(p.lat, p.lon, q.lat, q.lon) return d * d } // haversine returns the distance between two geographic coordinates. func haversine(lat1, lon1, lat2, lon2 float64) float64 { const r = 6371 // km sdLat := math.Sin(radians(lat2-lat1) / 2) sdLon := math.Sin(radians(lon2-lon1) / 2) a := sdLat*sdLat + math.Cos(radians(lat1))*math.Cos(radians(lat2))*sdLon*sdLon d := 2 * r * math.Asin(math.Sqrt(a)) return d // km } func radians(d float64) float64 { return d * math.Pi / 180 } // places is a collection of the place type that satisfies kdtree.Interface. type places []place func (p places) Index(i int) kdtree.Comparable { return p[i] } func (p places) Len() int { return len(p) } func (p places) Pivot(d kdtree.Dim) int { return plane{places: p, Dim: d}.Pivot() } func (p places) Slice(start, end int) kdtree.Interface { return p[start:end] } // plane is required to help places. type plane struct { kdtree.Dim places } func (p plane) Less(i, j int) bool { switch p.Dim { case 0: return p.places[i].lat < p.places[j].lat case 1: return p.places[i].lon < p.places[j].lon default: panic("illegal dimension") } } func (p plane) Pivot() int { return kdtree.Partition(p, kdtree.MedianOfMedians(p)) } func (p plane) Slice(start, end int) kdtree.SortSlicer { p.places = p.places[start:end] return p } func (p plane) Swap(i, j int) { p.places[i], p.places[j] = p.places[j], p.places[i] } golang-gonum-v1-gonum-0.14.0/spatial/kdtree/medians.go000066400000000000000000000045401450372207100225230ustar00rootroot00000000000000// Copyright ©2019 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 kdtree import ( "sort" "golang.org/x/exp/rand" ) // Partition partitions list such that all elements less than the value at // pivot prior to the call are placed before that element and all elements // greater than that value are placed after it. The final location of the // element at pivot prior to the call is returned. func Partition(list sort.Interface, pivot int) int { var index, last int if last = list.Len() - 1; last < 0 { return -1 } list.Swap(pivot, last) for i := 0; i < last; i++ { if !list.Less(last, i) { list.Swap(index, i) index++ } } list.Swap(last, index) return index } // SortSlicer satisfies the sort.Interface and is able to slice itself. type SortSlicer interface { sort.Interface Slice(start, end int) SortSlicer } // Select partitions list such that all elements less than the kth element // are placed before k in the resulting list and all elements greater than // it are placed after the position k. func Select(list SortSlicer, k int) int { var ( start int end = list.Len() ) if k >= end { if k == 0 { return 0 } panic("kdtree: index out of range") } if start == end-1 { return k } for { if start == end { panic("kdtree: internal inconsistency") } sub := list.Slice(start, end) pivot := Partition(sub, rand.Intn(sub.Len())) switch { case pivot == k: return k case k < pivot: end = pivot + start default: k -= pivot start += pivot } } } func min(a, b int) int { if a < b { return a } return b } // MedianOfMedians returns the index to the median value of the medians // of groups of 5 consecutive elements. func MedianOfMedians(list SortSlicer) int { n := list.Len() / 5 for i := 0; i < n; i++ { left := i * 5 sub := list.Slice(left, min(left+5, list.Len()-1)) Select(sub, 2) list.Swap(i, left+2) } Select(list.Slice(0, min(n, list.Len()-1)), min(list.Len(), n/2)) return n / 2 } // MedianOfRandoms returns the index to the median value of up to n randomly // chosen elements in list. func MedianOfRandoms(list SortSlicer, n int) int { if l := list.Len(); l < n { n = l } else { rand.Shuffle(n, func(i, j int) { list.Swap(i, j) }) } Select(list.Slice(0, n), n/2) return n / 2 } golang-gonum-v1-gonum-0.14.0/spatial/kdtree/medians_test.go000066400000000000000000000077031450372207100235660ustar00rootroot00000000000000// Copyright ©2019 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 kdtree import ( "sort" "testing" "golang.org/x/exp/rand" ) type ints []int func (a ints) Len() int { return len(a) } func (a ints) Less(i, j int) bool { return a[i] < a[j] } func (a ints) Slice(s, e int) SortSlicer { return a[s:e] } func (a ints) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func TestPartition(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for p := 0; p < 100; p++ { list := make(ints, 1e5) for i := range list { list[i] = rnd.Int() } pi := Partition(list, rnd.Intn(list.Len())) for i := 0; i < pi; i++ { if list[i] > list[pi] { t.Errorf("unexpected partition sort order p[%d] > p[%d]: %d > %d", i, pi, list[i], list[pi]) } } for i := pi + 1; i < len(list); i++ { if list[i] <= list[pi] { t.Errorf("unexpected partition sort order p[%d] <= p[%d]: %d <= %d", i, pi, list[i], list[pi]) } } } } func TestPartitionCollision(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for p := 0; p < 10; p++ { list := make(ints, 10) for i := range list { list[i] = rnd.Intn(5) } pi := Partition(list, p) for i := 0; i < pi; i++ { if list[i] > list[pi] { t.Errorf("unexpected partition sort order p[%d] > p[%d]: %d > %d", i, pi, list[i], list[pi]) } } for i := pi + 1; i < len(list); i++ { if list[i] <= list[pi] { t.Errorf("unexpected partition sort order p[%d] <= p[%d]: %d <= %d", i, pi, list[i], list[pi]) } } } } func sortSelection(list ints, k int) int { sort.Sort(list) return list[k] } func TestSelect(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for k := 0; k < 2121; k++ { list := make(ints, 2121) for i := range list { list[i] = rnd.Intn(1000) } Select(list, k) sorted := append(ints(nil), list...) want := sortSelection(sorted, k) if list[k] != want { t.Errorf("unexpected result from Select(..., %d): got:%v want:%d", k, list[k], want) } } } func TestMedianOfMedians(t *testing.T) { rnd := rand.New(rand.NewSource(1)) list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } p := MedianOfMedians(list) med := list[p] sort.Sort(list) var found bool for _, v := range list[len(list)*3/10 : len(list)*7/10+1] { if v == med { found = true break } } if !found { t.Error("failed to find median") } } func TestMedianOfRandoms(t *testing.T) { rnd := rand.New(rand.NewSource(1)) list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } p := MedianOfRandoms(list, randoms) med := list[p] sort.Sort(list) var found bool for _, v := range list[len(list)*3/10 : len(list)*7/10+1] { if v == med { found = true break } } if !found { t.Error("failed to find median") } } var benchSink int func BenchmarkMedianOfMedians(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() benchSink = MedianOfMedians(list) } } func BenchmarkPartitionMedianOfMedians(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() benchSink = Partition(list, MedianOfMedians(list)) } } func BenchmarkMedianOfRandoms(b *testing.B) { rnd := rand.New(rand.NewSource(1)) b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() for i := 0; i < b.N; i++ { benchSink = MedianOfRandoms(list, list.Len()/1e3) } } func BenchmarkPartitionMedianOfRandoms(b *testing.B) { rnd := rand.New(rand.NewSource(1)) b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() for i := 0; i < b.N; i++ { benchSink = Partition(list, MedianOfRandoms(list, list.Len()/1e3)) } } golang-gonum-v1-gonum-0.14.0/spatial/kdtree/nbpoints_test.go000066400000000000000000000033201450372207100237710ustar00rootroot00000000000000// Copyright ©2019 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 kdtree var ( _ Interface = nbPoints{} _ Comparable = nbPoint{} ) // nbRandoms is the maximum number of random values to sample for calculation of median of // random elements. var nbRandoms = 100 // nbPoint represents a point in a k-d space that satisfies the Comparable interface. type nbPoint Point func (p nbPoint) Compare(c Comparable, d Dim) float64 { q := c.(nbPoint); return p[d] - q[d] } func (p nbPoint) Dims() int { return len(p) } func (p nbPoint) Distance(c Comparable) float64 { q := c.(nbPoint) var sum float64 for dim, c := range p { d := c - q[dim] sum += d * d } return sum } // nbPoints is a collection of point values that satisfies the Interface. type nbPoints []nbPoint func (p nbPoints) Index(i int) Comparable { return p[i] } func (p nbPoints) Len() int { return len(p) } func (p nbPoints) Pivot(d Dim) int { return nbPlane{nbPoints: p, Dim: d}.Pivot() } func (p nbPoints) Slice(start, end int) Interface { return p[start:end] } // nbPlane is a wrapping type that allows a Points type be pivoted on a dimension. type nbPlane struct { Dim nbPoints } func (p nbPlane) Less(i, j int) bool { return p.nbPoints[i][p.Dim] < p.nbPoints[j][p.Dim] } func (p nbPlane) Pivot() int { return Partition(p, MedianOfRandoms(p, nbRandoms)) } func (p nbPlane) Slice(start, end int) SortSlicer { p.nbPoints = p.nbPoints[start:end]; return p } func (p nbPlane) Swap(i, j int) { p.nbPoints[i], p.nbPoints[j] = p.nbPoints[j], p.nbPoints[i] } golang-gonum-v1-gonum-0.14.0/spatial/kdtree/points.go000066400000000000000000000054341450372207100224220ustar00rootroot00000000000000// Copyright ©2019 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 kdtree import "math" var ( _ Interface = Points(nil) _ Comparable = Point(nil) ) // Point represents a point in a k-d space that satisfies the Comparable interface. type Point []float64 // Compare returns the signed distance of p from the plane passing through c and // perpendicular to the dimension d. The concrete type of c must be Point. func (p Point) Compare(c Comparable, d Dim) float64 { q := c.(Point); return p[d] - q[d] } // Dims returns the number of dimensions described by the receiver. func (p Point) Dims() int { return len(p) } // Distance returns the squared Euclidean distance between c and the receiver. The // concrete type of c must be Point. func (p Point) Distance(c Comparable) float64 { q := c.(Point) var sum float64 for dim, c := range p { d := c - q[dim] sum += d * d } return sum } // Extend returns a bounding box that has been extended to include the receiver. func (p Point) Extend(b *Bounding) *Bounding { if b == nil { b = &Bounding{append(Point(nil), p...), append(Point(nil), p...)} } min := b.Min.(Point) max := b.Max.(Point) for d, v := range p { min[d] = math.Min(min[d], v) max[d] = math.Max(max[d], v) } *b = Bounding{Min: min, Max: max} return b } // Points is a collection of point values that satisfies the Interface. type Points []Point func (p Points) Bounds() *Bounding { if p.Len() == 0 { return nil } min := append(Point(nil), p[0]...) max := append(Point(nil), p[0]...) for _, e := range p[1:] { for d, v := range e { min[d] = math.Min(min[d], v) max[d] = math.Max(max[d], v) } } return &Bounding{Min: min, Max: max} } func (p Points) Index(i int) Comparable { return p[i] } func (p Points) Len() int { return len(p) } func (p Points) Pivot(d Dim) int { return Plane{Points: p, Dim: d}.Pivot() } func (p Points) Slice(start, end int) Interface { return p[start:end] } // Plane is a wrapping type that allows a Points type be pivoted on a dimension. // The Pivot method of Plane uses MedianOfRandoms sampling at most 100 elements // to find a pivot element. type Plane struct { Dim Points } // randoms is the maximum number of random values to sample for calculation of // median of random elements. const randoms = 100 func (p Plane) Less(i, j int) bool { return p.Points[i][p.Dim] < p.Points[j][p.Dim] } func (p Plane) Pivot() int { return Partition(p, MedianOfRandoms(p, randoms)) } func (p Plane) Slice(start, end int) SortSlicer { p.Points = p.Points[start:end]; return p } func (p Plane) Swap(i, j int) { p.Points[i], p.Points[j] = p.Points[j], p.Points[i] } golang-gonum-v1-gonum-0.14.0/spatial/r1/000077500000000000000000000000001450372207100176155ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/spatial/r1/doc.go000066400000000000000000000004421450372207100207110ustar00rootroot00000000000000// Copyright ©2019 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 r1 provides 1D vectors and intervals and operations on them. package r1 // import "gonum.org/v1/gonum/spatial/r1" golang-gonum-v1-gonum-0.14.0/spatial/r1/interval.go000066400000000000000000000004001450372207100217620ustar00rootroot00000000000000// Copyright ©2019 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 r1 // Interval represents an interval. type Interval struct { Min, Max float64 } golang-gonum-v1-gonum-0.14.0/spatial/r2/000077500000000000000000000000001450372207100176165ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/spatial/r2/box.go000066400000000000000000000057751450372207100207530ustar00rootroot00000000000000// Copyright ©2022 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 r2 import "math" // Box is a 2D bounding box. Well formed Boxes have // Min components smaller than Max components. type Box struct { Min, Max Vec } // NewBox is shorthand for Box{Min:Vec{x0,y0}, Max:Vec{x1,y1}}. // The sides are swapped so that the resulting Box is well formed. func NewBox(x0, y0, x1, y1 float64) Box { return Box{ Min: Vec{X: math.Min(x0, x1), Y: math.Min(y0, y1)}, Max: Vec{X: math.Max(x0, x1), Y: math.Max(y0, y1)}, } } // Size returns the size of the Box. func (a Box) Size() Vec { return Sub(a.Max, a.Min) } // Center returns the center of the Box. func (a Box) Center() Vec { return Scale(0.5, Add(a.Min, a.Max)) } // IsEmpty returns true if a Box's volume is zero // or if a Min component is greater than its Max component. func (a Box) Empty() bool { return a.Min.X >= a.Max.X || a.Min.Y >= a.Max.Y } // Vertices returns a slice of the 4 vertices // corresponding to each of the Box's corners. // // The order of the vertices is CCW in the XY plane starting at the box minimum. // If viewing box from +Z position the ordering is as follows: // 1. Bottom left. // 2. Bottom right. // 3. Top right. // 4. Top left. func (a Box) Vertices() []Vec { return []Vec{ 0: a.Min, 1: {a.Max.X, a.Min.Y}, 2: a.Max, 3: {a.Min.X, a.Max.Y}, } } // Union returns a box enclosing both the receiver and argument Boxes. func (a Box) Union(b Box) Box { if a.Empty() { return b } if b.Empty() { return a } return Box{ Min: minElem(a.Min, b.Min), Max: maxElem(a.Max, b.Max), } } // Add adds v to the bounding box components. // It is the equivalent of translating the Box by v. func (a Box) Add(v Vec) Box { return Box{Add(a.Min, v), Add(a.Max, v)} } // Scale returns a new Box scaled by a size vector around its center. // The scaling is done element wise, which is to say the Box's X size is // scaled by v.X. Negative components of v are interpreted as zero. func (a Box) Scale(v Vec) Box { v = maxElem(v, Vec{}) // TODO(soypat): Probably a better way to do this. return centeredBox(a.Center(), mulElem(v, a.Size())) } // centeredBox creates a Box with a given center and size. Size's negative // components are interpreted as zero so that resulting box is well formed. func centeredBox(center, size Vec) Box { size = maxElem(size, Vec{}) half := Scale(0.5, absElem(size)) return Box{Min: Sub(center, half), Max: Add(center, half)} } // Contains returns true if v is contained within the bounds of the Box. func (a Box) Contains(v Vec) bool { if a.Empty() { return v == a.Min && v == a.Max } return a.Min.X <= v.X && v.X <= a.Max.X && a.Min.Y <= v.Y && v.Y <= a.Max.Y } // Canon returns the canonical version of b. The returned Box has minimum // and maximum coordinates swapped if necessary so that it is well-formed. func (b Box) Canon() Box { return Box{ Min: minElem(b.Min, b.Max), Max: maxElem(b.Min, b.Max), } } golang-gonum-v1-gonum-0.14.0/spatial/r2/box_test.go000066400000000000000000000121571450372207100220020ustar00rootroot00000000000000// Copyright ©2022 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 r2 import ( "testing" "golang.org/x/exp/rand" ) func TestBoxContains(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 200; i++ { b := randomBox(rnd) for j := 0; j < 10; j++ { contained := b.random(rnd) if !b.Contains(contained) { t.Error("bounding box should contain Vec") } } uncontained := [4]Vec{ Add(b.Max, Vec{1, 0}), Add(b.Max, Vec{0, 1}), Sub(b.Min, Vec{1, 0}), Sub(b.Min, Vec{0, 1}), } for _, unc := range uncontained { if b.Contains(unc) { t.Error("box should not contain vec") } } } } func TestBoxUnion(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 200; i++ { b1 := randomBox(rnd) b2 := randomBox(rnd) u := b1.Union(b2) for j := 0; j < 10; j++ { contained := b1.random(rnd) if !u.Contains(contained) { t.Error("union should contain b1's Vec") } contained = b2.random(rnd) if !u.Contains(contained) { t.Error("union should contain b2's Vec") } } uncontained := [4]Vec{ Add(maxElem(b1.Max, b2.Max), Vec{1, 0}), Add(maxElem(b1.Max, b2.Max), Vec{0, 1}), Sub(minElem(b1.Min, b2.Min), Vec{1, 0}), Sub(minElem(b1.Min, b2.Min), Vec{0, 1}), } for _, unc := range uncontained { if !b1.Contains(unc) && !b2.Contains(unc) && u.Contains(unc) { t.Error("union should not contain Vec") } } } } func TestBoxCenter(t *testing.T) { const tol = 1e-11 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) center := b.Center() size := b.Size() newBox := centeredBox(center, size) if b.Empty() { t.Fatal("random box result must be well formed") } if !vecApproxEqual(b.Min, newBox.Min, tol) { t.Errorf("min values of box not equal. got %g, expected %g", newBox.Min, b.Min) } if !vecApproxEqual(b.Max, newBox.Max, tol) { t.Errorf("max values of box not equal. got %g, expected %g", newBox.Max, b.Max) } } } func TestBoxAdd(t *testing.T) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 12; i++ { b := randomBox(rnd) v := randomVec(rnd) got := b.Add(v) want := Box{Min: Add(b.Min, v), Max: Add(b.Max, v)} if !vecApproxEqual(got.Min, want.Min, tol) { t.Error("box min incorrect result") } if !vecApproxEqual(got.Max, want.Max, tol) { t.Error("box max incorrect result") } } } func TestBoxScale(t *testing.T) { const tol = 1e-11 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) size := b.Size() scaler := absElem(randomVec(rnd)) scaled := b.Scale(scaler) gotScaler := divElem(scaled.Size(), size) if !vecApproxEqual(scaler, gotScaler, tol) { t.Errorf("got scaled %g, expected %g", gotScaler, scaler) } center := b.Center() scaledCenter := scaled.Center() if !vecApproxEqual(center, scaledCenter, tol) { t.Error("scale modified center") } } } func TestBoxEmpty(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { v := absElem(randomVec(rnd)) b := randomBox(rnd) min := b.Min max := b.Max if !(Box{Min: min, Max: min}).Empty() { t.Error("Box{min,min} should be empty") } if !(Box{Min: max, Max: max}).Empty() { t.Error("Box{max,max} should be empty") } bmm := Box{Min: min, Max: Sub(min, v)} if !bmm.Empty() { t.Error("Box{min,min-v} should be empty") } else if bmm.Canon().Empty() { t.Error("Canonical box of Box{min,min-v} is not empty") } bMM := Box{Min: Add(max, v), Max: max} if !bMM.Empty() { t.Error("Box{max+v,max} should be empty") } else if bmm.Canon().Empty() { t.Error("Canonical box of Box{max+v,max} is not empty") } } } func TestBoxCanon(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) badBox := Box{Min: b.Max, Max: b.Min} canon := badBox.Canon() if canon != b { t.Error("swapped box canon should be equal to original box") } } } func TestBoxVertices(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) gots := b.Vertices() wants := goldenVertices(b) if len(gots) != len(wants) { t.Fatalf("bad length of vertices. expect 4, got %d", len(gots)) } for j, want := range wants { got := gots[j] if !vecEqual(want, got) { t.Errorf("%dth vertex not equal", j) } } } } // randomBox returns a random valid bounding Box. func randomBox(rnd *rand.Rand) Box { spatialScale := randomRange(0, 2000) boxScale := randomRange(0.01, 1000) return centeredBox(Scale(spatialScale, randomVec(rnd)), Scale(boxScale, absElem(randomVec(rnd)))) } // Random returns a random point within the Box. // used to facilitate testing func (b Box) random(rnd *rand.Rand) Vec { return Vec{ X: randomRange(b.Min.X, b.Max.X), Y: randomRange(b.Min.Y, b.Max.Y), } } // randomRange returns a random float64 [a,b) func randomRange(a, b float64) float64 { return a + (b-a)*rand.Float64() } func goldenVertices(a Box) []Vec { return []Vec{ 0: a.Min, 1: {a.Max.X, a.Min.Y}, 2: a.Max, 3: {a.Min.X, a.Max.Y}, } } golang-gonum-v1-gonum-0.14.0/spatial/r2/doc.go000066400000000000000000000004361450372207100207150ustar00rootroot00000000000000// Copyright ©2019 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 r2 provides 2D vectors and boxes and operations on them. package r2 // import "gonum.org/v1/gonum/spatial/r2" golang-gonum-v1-gonum-0.14.0/spatial/r2/triangle.go000066400000000000000000000053511450372207100217560ustar00rootroot00000000000000// Copyright ©2022 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 r2 import "math" // Triangle represents a triangle in 2D space and // is composed by 3 vectors corresponding to the position // of each of the vertices. type Triangle [3]Vec // Centroid returns the intersection of the three medians of the triangle // as a point in space. func (t Triangle) Centroid() Vec { return Scale(1.0/3.0, Add(Add(t[0], t[1]), t[2])) } // Area returns the surface area of the triangle. func (t Triangle) Area() float64 { // Heron's Formula, see https://en.wikipedia.org/wiki/Heron%27s_formula. // Also see William M. Kahan (24 March 2000). "Miscalculating Area and Angles of a Needle-like Triangle" // for more discussion. https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf. a, b, c := t.orderedLengths() A := (c + (b + a)) * (a - (c - b)) A *= (a + (c - b)) * (c + (b - a)) return math.Sqrt(A) / 4 } // orderedLengths returns the lengths of the sides of the triangle such that // a ≤ b ≤ c. func (t Triangle) orderedLengths() (a, b, c float64) { s1, s2, s3 := t.sides() l1 := Norm(s1) l2 := Norm(s2) l3 := Norm(s3) // sort-3 if l2 < l1 { l1, l2 = l2, l1 } if l3 < l2 { l2, l3 = l3, l2 if l2 < l1 { l1, l2 = l2, l1 } } return l1, l2, l3 } // sides returns vectors for each of the sides of t. func (t Triangle) sides() (Vec, Vec, Vec) { return Sub(t[1], t[0]), Sub(t[2], t[1]), Sub(t[0], t[2]) } // IsDegenerate returns true if all of triangle's vertices are // within tol distance of its longest side. func (t Triangle) IsDegenerate(tol float64) bool { sides := [3]Vec{Sub(t[1], t[0]), Sub(t[2], t[1]), Sub(t[0], t[2])} len2 := [3]float64{Norm2(sides[0]), Norm2(sides[1]), Norm2(sides[2])} longLen := len2[0] longIdx := 0 if len2[1] > longLen { longLen = len2[1] longIdx = 1 } if len2[2] > longLen { longIdx = 2 } // calculate vertex distance from longest side ln := line{t[longIdx], t[(longIdx+1)%3]} dist := ln.distance(t[(longIdx+2)%3]) return dist <= tol } // line is an infinite 3D line // defined by two points on the line. type line [2]Vec // vecOnLine takes a value between 0 and 1 to linearly // interpolate a point on the line. // // vecOnLine(0) returns l[0] // vecOnLine(1) returns l[1] func (l line) vecOnLine(t float64) Vec { lineDir := Sub(l[1], l[0]) return Add(l[0], Scale(t, lineDir)) } // distance returns the minimum euclidean distance of point p to the line. func (l line) distance(p Vec) float64 { // https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html p1 := l[0] p2 := l[1] num := math.Abs((p2.X-p1.X)*(p1.Y-p.Y) - (p1.X-p.X)*(p2.Y-p1.Y)) return num / math.Hypot(p2.X-p1.X, p2.Y-p1.Y) } golang-gonum-v1-gonum-0.14.0/spatial/r2/triangle_test.go000066400000000000000000000101731450372207100230130ustar00rootroot00000000000000// Copyright ©2022 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 r2 import ( "math" "testing" "golang.org/x/exp/rand" ) func TestTriangleDegenerate(t *testing.T) { const ( // tol is how much closer the problematic // vertex is placed to avoid floating point error // for degeneracy calculation. tol = 1e-12 // This is the argument to Degenerate and represents // the minimum permissible distance between the triangle // longest edge and the opposite vertex. spatialTol = 1e-2 ) rnd := rand.New(rand.NewSource(1)) randVec := func() Vec { return Vec{X: 20 * (rnd.Float64() - 0.5), Y: 20 * (rnd.Float64() - 0.5)} } for i := 0; i < 200; i++ { // Generate a random line for the longest triangle side. ln := line{randVec(), randVec()} lineDir := Sub(ln[1], ln[0]) perpendicular := Unit(Vec{X: lineDir.X, Y: -lineDir.Y}) // generate 3 permutations of needle triangles for // each vertex. A needle triangle has two vertices // very close to eachother an its third vertex far away. var needle Triangle for j := 0; j < 3; j++ { needle[j] = ln[0] needle[(j+1)%3] = ln[1] needle[(j+2)%3] = Add(ln[1], Scale((1-tol)*spatialTol, perpendicular)) if !needle.IsDegenerate(spatialTol) { t.Error("needle triangle not degenerate") } } midpoint := ln.vecOnLine(0.5) // cap triangles are characterized by having two sides // of similar lengths and whose sum is approximately equal // to the remaining longest side. var cap Triangle for j := 0; j < 3; j++ { cap[j] = ln[0] cap[(j+1)%3] = ln[1] cap[(j+2)%3] = Add(midpoint, Scale((1-tol)*spatialTol, perpendicular)) if !cap.IsDegenerate(spatialTol) { t.Error("cap triangle not degenerate") } } var degenerate Triangle for j := 0; j < 3; j++ { degenerate[j] = ln[0] degenerate[(j+1)%3] = ln[1] // vertex perpendicular to some random point on longest side. degenerate[(j+2)%3] = Add(ln.vecOnLine(rnd.Float64()), Scale((1-tol)*spatialTol, perpendicular)) if !degenerate.IsDegenerate(spatialTol) { t.Error("random degenerate triangle not degenerate") } // vertex about longest side 0 vertex degenerate[(j+2)%3] = Add(ln[0], Scale((1-tol)*spatialTol, Unit(randVec()))) if !degenerate.IsDegenerate(spatialTol) { t.Error("needle-like degenerate triangle not degenerate") } // vertex about longest side 1 vertex degenerate[(j+2)%3] = Add(ln[1], Scale((1-tol)*spatialTol, Unit(randVec()))) if !degenerate.IsDegenerate(spatialTol) { t.Error("needle-like degenerate triangle not degenerate") } } } } func TestTriangleArea(t *testing.T) { const tol = 1e-16 for _, test := range []struct { T Triangle Expect float64 }{ { T: Triangle{ {0, 0}, {1, 0}, {0, 1}, }, Expect: 0.5, }, { T: Triangle{ {1, 0}, {0, 1}, {0, 0}, }, Expect: 0.5, }, { T: Triangle{ {0, 0}, {0, 20}, {20, 0}, }, Expect: 20 * 20 / 2, }, } { got := test.T.Area() if math.Abs(got-test.Expect) > tol { t.Errorf("got area %g, expected %g", got, test.Expect) } const tol2 = 1e-11 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 100; i++ { tri := Triangle{ {rnd.Float64() * 20, rnd.Float64() * 20}, {rand.Float64() * 20, rnd.Float64() * 20}, {rnd.Float64() * 20, rnd.Float64() * 20}, } got := tri.Area() want := math.Abs(Cross(Sub(tri[1], tri[0]), Sub(tri[1], tri[2]))) / 2 if math.Abs(got-want) > tol2 { t.Errorf("got area %g not match half norm of cross product %g", got, want) } } } } func TestTriangleCentroid(t *testing.T) { const tol = 1e-12 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 100; i++ { tri := Triangle{ {rnd.Float64() * 20, rnd.Float64() * 20}, {rand.Float64() * 20, rnd.Float64() * 20}, {rnd.Float64() * 20, rnd.Float64() * 20}, } got := tri.Centroid() want := Vec{ X: (tri[0].X + tri[1].X + tri[2].X) / 3, Y: (tri[0].Y + tri[1].Y + tri[2].Y) / 3, } if math.Abs(got.X-want.X) > tol || math.Abs(got.Y-want.Y) > tol { t.Fatalf("got %.6g, want %.6g", got, want) } } } golang-gonum-v1-gonum-0.14.0/spatial/r2/vector.go000066400000000000000000000062321450372207100214520ustar00rootroot00000000000000// Copyright ©2019 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 r2 import "math" // Vec is a 2D vector. type Vec struct { X, Y float64 } // Add returns the vector sum of p and q. func Add(p, q Vec) Vec { return Vec{ X: p.X + q.X, Y: p.Y + q.Y, } } // Sub returns the vector sum of p and -q. func Sub(p, q Vec) Vec { return Vec{ X: p.X - q.X, Y: p.Y - q.Y, } } // Scale returns the vector p scaled by f. func Scale(f float64, p Vec) Vec { return Vec{ X: f * p.X, Y: f * p.Y, } } // Dot returns the dot product p·q. func Dot(p, q Vec) float64 { return p.X*q.X + p.Y*q.Y } // Cross returns the cross product p×q. func Cross(p, q Vec) float64 { return p.X*q.Y - p.Y*q.X } // Rotate returns a new vector, rotated by alpha around the provided point, q. func Rotate(p Vec, alpha float64, q Vec) Vec { return NewRotation(alpha, q).Rotate(p) } // Norm returns the Euclidean norm of p // // |p| = sqrt(p_x^2 + p_y^2). func Norm(p Vec) float64 { return math.Hypot(p.X, p.Y) } // Norm2 returns the Euclidean squared norm of p // // |p|^2 = p_x^2 + p_y^2. func Norm2(p Vec) float64 { return p.X*p.X + p.Y*p.Y } // Unit returns the unit vector colinear to p. // Unit returns {NaN,NaN} for the zero vector. func Unit(p Vec) Vec { if p.X == 0 && p.Y == 0 { return Vec{X: math.NaN(), Y: math.NaN()} } return Scale(1/Norm(p), p) } // Cos returns the cosine of the opening angle between p and q. func Cos(p, q Vec) float64 { return Dot(p, q) / (Norm(p) * Norm(q)) } // Rotation describes a rotation in 2D. type Rotation struct { sin, cos float64 p Vec } // NewRotation creates a rotation by alpha, around p. func NewRotation(alpha float64, p Vec) Rotation { if alpha == 0 { return Rotation{sin: 0, cos: 1, p: p} } sin, cos := math.Sincos(alpha) return Rotation{sin: sin, cos: cos, p: p} } // Rotate returns p rotated according to the parameters used to construct // the receiver. func (r Rotation) Rotate(p Vec) Vec { if r.isIdentity() { return p } o := Sub(p, r.p) return Add(Vec{ X: (o.X*r.cos - o.Y*r.sin), Y: (o.X*r.sin + o.Y*r.cos), }, r.p) } func (r Rotation) isIdentity() bool { return r.sin == 0 && r.cos == 1 } // minElem returns a vector with the element-wise // minimum components of vectors a and b. func minElem(a, b Vec) Vec { return Vec{ X: math.Min(a.X, b.X), Y: math.Min(a.Y, b.Y), } } // maxElem returns a vector with the element-wise // maximum components of vectors a and b. func maxElem(a, b Vec) Vec { return Vec{ X: math.Max(a.X, b.X), Y: math.Max(a.Y, b.Y), } } // absElem returns the vector with components set to their absolute value. func absElem(a Vec) Vec { return Vec{ X: math.Abs(a.X), Y: math.Abs(a.Y), } } // mulElem returns the Hadamard product between vectors a and b. // // v = {a.X*b.X, a.Y*b.Y, a.Z*b.Z} func mulElem(a, b Vec) Vec { return Vec{ X: a.X * b.X, Y: a.Y * b.Y, } } // divElem returns the Hadamard product between vector a // and the inverse components of vector b. // // v = {a.X/b.X, a.Y/b.Y, a.Z/b.Z} func divElem(a, b Vec) Vec { return Vec{ X: a.X / b.X, Y: a.Y / b.Y, } } golang-gonum-v1-gonum-0.14.0/spatial/r2/vector_test.go000066400000000000000000000141221450372207100225060ustar00rootroot00000000000000// Copyright ©2020 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 r2 import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestAdd(t *testing.T) { for _, test := range []struct { v1, v2 Vec want Vec }{ {Vec{0, 0}, Vec{0, 0}, Vec{0, 0}}, {Vec{1, 0}, Vec{0, 0}, Vec{1, 0}}, {Vec{1, 2}, Vec{3, 4}, Vec{4, 6}}, {Vec{1, -3}, Vec{1, -6}, Vec{2, -9}}, {Vec{1, 2}, Vec{-1, -2}, Vec{}}, } { got := Add(test.v1, test.v2) if got != test.want { t.Errorf( "error: %v + %v: got=%v, want=%v", test.v1, test.v2, got, test.want, ) } } } func TestSub(t *testing.T) { for _, test := range []struct { v1, v2 Vec want Vec }{ {Vec{0, 0}, Vec{0, 0}, Vec{0, 0}}, {Vec{1, 0}, Vec{0, 0}, Vec{1, 0}}, {Vec{1, 2}, Vec{3, 4}, Vec{-2, -2}}, {Vec{1, -3}, Vec{1, -6}, Vec{0, 3}}, {Vec{1, 2}, Vec{1, 2}, Vec{}}, } { got := Sub(test.v1, test.v2) if got != test.want { t.Errorf( "error: %v - %v: got=%v, want=%v", test.v1, test.v2, got, test.want, ) } } } func TestScale(t *testing.T) { for _, test := range []struct { a float64 v Vec want Vec }{ {3, Vec{0, 0}, Vec{0, 0}}, {1, Vec{1, 0}, Vec{1, 0}}, {0, Vec{1, 0}, Vec{0, 0}}, {3, Vec{1, 0}, Vec{3, 0}}, {-1, Vec{1, -3}, Vec{-1, 3}}, {2, Vec{1, -3}, Vec{2, -6}}, {10, Vec{1, 2}, Vec{10, 20}}, } { got := Scale(test.a, test.v) if got != test.want { t.Errorf( "error: %v * %v: got=%v, want=%v", test.a, test.v, got, test.want) } } } func TestDot(t *testing.T) { for _, test := range []struct { u, v Vec want float64 }{ {Vec{1, 2}, Vec{1, 2}, 5}, {Vec{1, 0}, Vec{1, 0}, 1}, {Vec{1, 0}, Vec{0, 1}, 0}, {Vec{1, 0}, Vec{0, 1}, 0}, {Vec{1, 1}, Vec{-1, -1}, -2}, {Vec{1, 2}, Vec{-0.3, 0.4}, 0.5}, } { { got := Dot(test.u, test.v) if got != test.want { t.Errorf( "error: %v · %v: got=%v, want=%v", test.u, test.v, got, test.want, ) } } { got := Dot(test.v, test.u) if got != test.want { t.Errorf( "error: %v · %v: got=%v, want=%v", test.v, test.u, got, test.want, ) } } } } func TestCross(t *testing.T) { for _, test := range []struct { v1, v2 Vec want float64 }{ {Vec{1, 0}, Vec{1, 0}, 0}, {Vec{1, 0}, Vec{0, 1}, 1}, {Vec{0, 1}, Vec{1, 0}, -1}, {Vec{1, 2}, Vec{-4, 5}, 13}, {Vec{1, 2}, Vec{2, 3}, -1}, } { got := Cross(test.v1, test.v2) if got != test.want { t.Errorf( "error: %v × %v = %v, want %v", test.v1, test.v2, got, test.want, ) } } } func TestNorm(t *testing.T) { for _, test := range []struct { v Vec want float64 }{ {Vec{0, 0}, 0}, {Vec{0, 1}, 1}, {Vec{1, 1}, math.Sqrt2}, {Vec{1, 2}, math.Sqrt(5)}, {Vec{3, -4}, 5}, {Vec{1, 1e-16}, 1}, {Vec{4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 6.101625315155041e-196}, } { if got, want := Norm(test.v), test.want; got != want { t.Errorf("|%v| = %v, want %v", test.v, got, want) } } } func TestNorm2(t *testing.T) { for _, test := range []struct { v Vec want float64 }{ {Vec{0, 0}, 0}, {Vec{0, 1}, 1}, {Vec{1, 1}, 2}, {Vec{1, 2}, 5}, {Vec{3, -4}, 25}, {Vec{1, 1e-16}, 1}, // This will underflow and return zero. {Vec{4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 0}, } { if got, want := Norm2(test.v), test.want; got != want { t.Errorf("|%v|^2 = %v, want %v", test.v, got, want) } } } func TestUnit(t *testing.T) { const tol = 1e-14 for _, test := range []struct { v, want Vec }{ {Vec{}, Vec{math.NaN(), math.NaN()}}, {Vec{1, 0}, Vec{1, 0}}, {Vec{0, 1}, Vec{0, 1}}, {Vec{-1, 0}, Vec{-1, 0}}, {Vec{3, 4}, Vec{0.6, 0.8}}, {Vec{3, -4}, Vec{0.6, -0.8}}, {Vec{1, 1}, Vec{1. / math.Sqrt(2), 1. / math.Sqrt(2)}}, {Vec{1, 1e-16}, Vec{1, 1e-16}}, {Vec{1, 1e16}, Vec{1e-16, 1}}, {Vec{1e4, math.MaxFloat32 - 1}, Vec{0, 1}}, } { got := Unit(test.v) if !vecApproxEqual(got, test.want, tol) { t.Errorf( "Unit(%v) = %v, want %v", test.v, got, test.want, ) } if vecIsNaN(got) { return } if n, want := Norm(got), 1.0; n != want { t.Errorf("|%v| = %v, want 1", got, n) } } } func TestCos(t *testing.T) { const tol = 1e-14 for _, test := range []struct { v1, v2 Vec want float64 }{ {Vec{1, 1}, Vec{1, 1}, 1}, {Vec{1, 1}, Vec{-1, -1}, -1}, {Vec{1, 0}, Vec{1, 0}, 1}, {Vec{1, 0}, Vec{0, 1}, 0}, {Vec{1, 0}, Vec{-1, 0}, -1}, } { got := Cos(test.v1, test.v2) if !scalar.EqualWithinAbs(got, test.want, tol) { t.Errorf("cos(%v, %v)= %v, want %v", test.v1, test.v2, got, test.want, ) } } } func TestRotate(t *testing.T) { const tol = 1e-14 for _, test := range []struct { v, q Vec alpha float64 want Vec }{ {Vec{1, 0}, Vec{0, 0}, math.Pi / 2, Vec{0, 1}}, {Vec{1, 0}, Vec{0, 0}, 3 * math.Pi / 2, Vec{0, -1}}, {Vec{1, 0}, Vec{0, 1}, 0, Vec{1, 0}}, {Vec{1, 0}, Vec{0, 1}, 2 * math.Pi, Vec{1, 0}}, {Vec{1, 1}, Vec{0, 0}, math.Pi, Vec{-1, -1}}, {Vec{2, 2}, Vec{1, 1}, math.Pi / 2, Vec{0, 2}}, {Vec{2, 2}, Vec{1, 1}, math.Pi, Vec{0, 0}}, {Vec{2, 2}, Vec{2, 0}, math.Pi, Vec{2, -2}}, } { got := Rotate(test.v, test.alpha, test.q) if !vecApproxEqual(got, test.want, tol) { t.Errorf( "rotate(%v, %v, %v)= %v, want=%v", test.v, test.alpha, test.q, got, test.want, ) } } } func vecIsNaN(v Vec) bool { return math.IsNaN(v.X) && math.IsNaN(v.Y) } func vecIsNaNAny(v Vec) bool { return math.IsNaN(v.X) || math.IsNaN(v.Y) } func vecApproxEqual(a, b Vec, tol float64) bool { if tol == 0 { return vecEqual(a, b) } if vecIsNaNAny(a) || vecIsNaNAny(b) { return vecIsNaN(a) && vecIsNaN(b) } return scalar.EqualWithinAbs(a.X, b.X, tol) && scalar.EqualWithinAbs(a.Y, b.Y, tol) } func randomVec(rnd *rand.Rand) (v Vec) { v.X = (rnd.Float64() - 0.5) * 20 v.Y = (rnd.Float64() - 0.5) * 20 return v } func vecEqual(a, b Vec) bool { if vecIsNaNAny(a) || vecIsNaNAny(b) { return vecIsNaN(a) && vecIsNaN(b) } return a == b } golang-gonum-v1-gonum-0.14.0/spatial/r3/000077500000000000000000000000001450372207100176175ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/spatial/r3/box.go000066400000000000000000000070121450372207100207360ustar00rootroot00000000000000// Copyright ©2022 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 r3 import "math" // Box is a 3D bounding box. Well formed Boxes Min components // are smaller than Max components. type Box struct { Min, Max Vec } // NewBox is shorthand for Box{Min:Vec{x0,y0,z0}, Max:Vec{x1,y1,z1}}. // The sides are swapped so that the resulting Box is well formed. func NewBox(x0, y0, z0, x1, y1, z1 float64) Box { return Box{ Min: Vec{X: math.Min(x0, x1), Y: math.Min(y0, y1), Z: math.Min(z0, z1)}, Max: Vec{X: math.Max(x0, x1), Y: math.Max(y0, y1), Z: math.Max(z0, z1)}, } } // IsEmpty returns true if a Box's volume is zero // or if a Min component is greater than its Max component. func (a Box) Empty() bool { return a.Min.X >= a.Max.X || a.Min.Y >= a.Max.Y || a.Min.Z >= a.Max.Z } // Size returns the size of the Box. func (a Box) Size() Vec { return Sub(a.Max, a.Min) } // Center returns the center of the Box. func (a Box) Center() Vec { return Scale(0.5, Add(a.Min, a.Max)) } // Vertices returns a slice of the 8 vertices // corresponding to each of the Box's corners. // // Ordering of vertices 0-3 is CCW in the XY plane starting at box minimum. // Ordering of vertices 4-7 is CCW in the XY plane starting at box minimum // for X and Y values and maximum Z value. // // Edges for the box can be constructed with the following indices: // // edges := [12][2]int{ // {0, 1}, {1, 2}, {2, 3}, {3, 0}, // {4, 5}, {5, 6}, {6, 7}, {7, 4}, // {0, 4}, {1, 5}, {2, 6}, {3, 7}, // } func (a Box) Vertices() []Vec { return []Vec{ 0: a.Min, 1: {X: a.Max.X, Y: a.Min.Y, Z: a.Min.Z}, 2: {X: a.Max.X, Y: a.Max.Y, Z: a.Min.Z}, 3: {X: a.Min.X, Y: a.Max.Y, Z: a.Min.Z}, 4: {X: a.Min.X, Y: a.Min.Y, Z: a.Max.Z}, 5: {X: a.Max.X, Y: a.Min.Y, Z: a.Max.Z}, 6: a.Max, 7: {X: a.Min.X, Y: a.Max.Y, Z: a.Max.Z}, } } // Union returns a box enclosing both the receiver and argument Boxes. func (a Box) Union(b Box) Box { if a.Empty() { return b } if b.Empty() { return a } return Box{ Min: minElem(a.Min, b.Min), Max: maxElem(a.Max, b.Max), } } // Add adds v to the bounding box components. // It is the equivalent of translating the Box by v. func (a Box) Add(v Vec) Box { return Box{Add(a.Min, v), Add(a.Max, v)} } // Scale returns a new Box scaled by a size vector around its center. // The scaling is done element wise which is to say the Box's X dimension // is scaled by scale.X. Negative elements of scale are interpreted as zero. func (a Box) Scale(scale Vec) Box { scale = maxElem(scale, Vec{}) // TODO(soypat): Probably a better way to do this. return centeredBox(a.Center(), mulElem(scale, a.Size())) } // centeredBox creates a Box with a given center and size. // Negative components of size will be interpreted as zero. func centeredBox(center, size Vec) Box { size = maxElem(size, Vec{}) // set negative values to zero. half := Scale(0.5, size) return Box{Min: Sub(center, half), Max: Add(center, half)} } // Contains returns true if v is contained within the bounds of the Box. func (a Box) Contains(v Vec) bool { if a.Empty() { return v == a.Min && v == a.Max } return a.Min.X <= v.X && v.X <= a.Max.X && a.Min.Y <= v.Y && v.Y <= a.Max.Y && a.Min.Z <= v.Z && v.Z <= a.Max.Z } // Canon returns the canonical version of a. The returned Box has minimum // and maximum coordinates swapped if necessary so that it is well-formed. func (a Box) Canon() Box { return Box{ Min: minElem(a.Min, a.Max), Max: maxElem(a.Min, a.Max), } } golang-gonum-v1-gonum-0.14.0/spatial/r3/box_test.go000066400000000000000000000120531450372207100217760ustar00rootroot00000000000000// Copyright ©2022 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 r3 import ( "testing" "golang.org/x/exp/rand" ) func TestBoxContains(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 200; i++ { b := randomBox(rnd) for j := 0; j < 10; j++ { contained := b.random(rnd) if !b.Contains(contained) { t.Error("bounding box should contain Vec") } } uncontained := [6]Vec{ Add(b.Max, Vec{1, 0, 0}), Add(b.Max, Vec{0, 1, 0}), Add(b.Max, Vec{0, 0, 1}), Sub(b.Min, Vec{1, 0, 0}), Sub(b.Min, Vec{0, 1, 0}), Sub(b.Min, Vec{0, 0, 1}), } for _, unc := range uncontained { if b.Contains(unc) { t.Error("box should not contain vec") } } } } func TestBoxUnion(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 200; i++ { b1 := randomBox(rnd) b2 := randomBox(rnd) u := b1.Union(b2) for j := 0; j < 10; j++ { contained := b1.random(rnd) if !u.Contains(contained) { t.Error("union should contain b1's Vec") } contained = b2.random(rnd) if !u.Contains(contained) { t.Error("union should contain b2's Vec") } } uncontained := [6]Vec{ Add(maxElem(b1.Max, b2.Max), Vec{1, 0, 0}), Add(maxElem(b1.Max, b2.Max), Vec{0, 1, 0}), Add(maxElem(b1.Max, b2.Max), Vec{0, 0, 1}), Sub(minElem(b1.Min, b2.Min), Vec{1, 0, 0}), Sub(minElem(b1.Min, b2.Min), Vec{0, 1, 0}), Sub(minElem(b1.Min, b2.Min), Vec{0, 0, 1}), } for _, unc := range uncontained { if !b1.Contains(unc) && !b2.Contains(unc) && u.Contains(unc) { t.Error("union should not contain Vec") } } } } func TestBoxCenter(t *testing.T) { const tol = 1e-11 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) center := b.Center() size := b.Size() newBox := centeredBox(center, size) if !vecApproxEqual(b.Min, newBox.Min, tol) { t.Errorf("min values of box not equal. got %g, expected %g", newBox.Min, b.Min) } if !vecApproxEqual(b.Max, newBox.Max, tol) { t.Errorf("max values of box not equal. got %g, expected %g", newBox.Max, b.Max) } } } func TestBoxScale(t *testing.T) { const tol = 1e-11 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) size := b.Size() scaler := absElem(randomVec(rnd)) scaled := b.Scale(scaler) gotScaler := divElem(scaled.Size(), size) if !vecApproxEqual(scaler, gotScaler, tol) { t.Errorf("got scaled %g, expected %g", gotScaler, scaler) } center := b.Center() scaledCenter := scaled.Center() if !vecApproxEqual(center, scaledCenter, tol) { t.Error("scale modified center") } } } func TestBoxVertices(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) gots := b.Vertices() wants := goldenVertices(b) if len(gots) != len(wants) { t.Fatalf("bad length of vertices. expect 8, got %d", len(gots)) } for j, want := range wants { got := gots[j] if !vecEqual(want, got) { t.Errorf("%dth vertex not equal", j) } } } } func TestBoxEmpty(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { v := absElem(randomVec(rnd)) b := randomBox(rnd) min := b.Min max := b.Max if !(Box{Min: min, Max: min}).Empty() { t.Error("Box{min,min} should be empty") } if !(Box{Min: max, Max: max}).Empty() { t.Error("Box{max,max} should be empty") } bmm := Box{Min: min, Max: Sub(min, v)} if !bmm.Empty() { t.Error("Box{min,min-v} should be empty") } else if bmm.Canon().Empty() { t.Error("Canonical box of Box{min,min-v} is not empty") } bMM := Box{Min: Add(max, v), Max: max} if !bMM.Empty() { t.Error("Box{max+v,max} should be empty") } else if bmm.Canon().Empty() { t.Error("Canonical box of Box{max+v,max} is not empty") } } } func TestBoxCanon(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 300; i++ { b := randomBox(rnd) badBox := Box{Min: b.Max, Max: b.Min} canon := badBox.Canon() if canon != b { t.Error("swapped box canon should be equal to original box") } } } // randomBox returns a random valid bounding Box. func randomBox(rnd *rand.Rand) Box { spatialScale := randomRange(0, 2000) boxScale := randomRange(0.01, 1000) return centeredBox(Scale(spatialScale, randomVec(rnd)), Scale(boxScale, absElem(randomVec(rnd)))) } // Random returns a random point within the Box. // used to facilitate testing func (b Box) random(rnd *rand.Rand) Vec { return Vec{ X: randomRange(b.Min.X, b.Max.X), Y: randomRange(b.Min.Y, b.Max.Y), Z: randomRange(b.Min.Z, b.Max.Z), } } // randomRange returns a random float64 [a,b) func randomRange(a, b float64) float64 { return a + (b-a)*rand.Float64() } func goldenVertices(a Box) []Vec { return []Vec{ 0: a.Min, 1: {X: a.Max.X, Y: a.Min.Y, Z: a.Min.Z}, 2: {X: a.Max.X, Y: a.Max.Y, Z: a.Min.Z}, 3: {X: a.Min.X, Y: a.Max.Y, Z: a.Min.Z}, 4: {X: a.Min.X, Y: a.Min.Y, Z: a.Max.Z}, 5: {X: a.Max.X, Y: a.Min.Y, Z: a.Max.Z}, 6: a.Max, 7: {X: a.Min.X, Y: a.Max.Y, Z: a.Max.Z}, } } golang-gonum-v1-gonum-0.14.0/spatial/r3/doc.go000066400000000000000000000004361450372207100207160ustar00rootroot00000000000000// Copyright ©2019 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 r3 provides 3D vectors and boxes and operations on them. package r3 // import "gonum.org/v1/gonum/spatial/r3" golang-gonum-v1-gonum-0.14.0/spatial/r3/euler_example_test.go000066400000000000000000000063771450372207100240510ustar00rootroot00000000000000// Copyright ©2021 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 r3_test import ( "fmt" "math" "gonum.org/v1/gonum/num/quat" "gonum.org/v1/gonum/spatial/r3" ) // euler returns an r3.Rotation that corresponds to the Euler // angles alpha, beta and gamma which are rotations around the x, // y and z axes respectively. The order of rotations is x, y, z; // there are many conventions for this ordering. func euler(alpha, beta, gamma float64) r3.Rotation { // Note that this function can be algebraically simplified // to reduce floating point operations, but is left in this // form for clarity. var rot1, rot2, rot3 quat.Number rot1.Imag, rot1.Real = math.Sincos(alpha / 2) // x-axis rotation rot2.Jmag, rot2.Real = math.Sincos(beta / 2) // y-axis rotation rot3.Kmag, rot3.Real = math.Sincos(gamma / 2) // z-axis rotation return r3.Rotation(quat.Mul(rot3, quat.Mul(rot2, rot1))) // order of rotations } func ExampleRotation_eulerAngles() { // It is possible to interconvert between the quaternion representation // of a rotation and Euler angles, but this leads to problems. // // The first of these is that there are a variety of conventions for // application of the rotations. // // The more serious consequence of using Euler angles is that it is // possible to put the rotation system into a singularity which results // in loss of degrees of freedom and so causes gimbal lock. This happens // when the second axis to be rotated around is rotated to 𝝿/2. // // See https://en.wikipedia.org/wiki/Euler_angles for more details. pt := r3.Vec{1, 0, 0} // For the Euler conversion function in this example, the second rotation // is around the y-axis. const singularY = math.Pi / 2 arb := math.Pi / 4 fmt.Printf("rotate around x-axis: %.2f\n", euler(arb, 0, 0).Rotate(pt)) fmt.Printf("rotate around y-axis: %.2f\n", euler(0, arb, 0).Rotate(pt)) fmt.Printf("rotate around z-axis: %.2f\n", euler(0, 0, arb).Rotate(pt)) fmt.Printf("rotate around x+y-axes: %.2f\n", euler(arb, arb, 0).Rotate(pt)) fmt.Printf("rotate around x+z-axes: %.2f\n", euler(arb, 0, arb).Rotate(pt)) fmt.Printf("rotate around y+z-axes: %.2f\n", euler(0, arb, arb).Rotate(pt)) fmt.Printf("rotate around y-axis to singularity: %.2f\n", euler(0, singularY, 0).Rotate(pt)) fmt.Printf("rotate around x+y-axes with singularity → gimbal lock: %.2f\n", euler(arb, singularY, 0).Rotate(pt)) fmt.Printf("rotate around z+y-axes with singularity → gimbal lock: %.2f\n", euler(0, singularY, arb).Rotate(pt)) fmt.Printf("rotate around all-axes with singularity → gimbal lock: %.2f\n", euler(arb, singularY, arb).Rotate(pt)) // Output: // // rotate around x-axis: {1.00 0.00 0.00} // rotate around y-axis: {0.71 0.00 -0.71} // rotate around z-axis: {0.71 0.71 0.00} // rotate around x+y-axes: {0.71 0.00 -0.71} // rotate around x+z-axes: {0.71 0.71 0.00} // rotate around y+z-axes: {0.50 0.50 -0.71} // rotate around y-axis to singularity: {0.00 0.00 -1.00} // rotate around x+y-axes with singularity → gimbal lock: {0.00 0.00 -1.00} // rotate around z+y-axes with singularity → gimbal lock: {0.00 0.00 -1.00} // rotate around all-axes with singularity → gimbal lock: {0.00 0.00 -1.00} } golang-gonum-v1-gonum-0.14.0/spatial/r3/icosahedron_example_test.go000066400000000000000000000065001450372207100252170ustar00rootroot00000000000000// Copyright ©2022 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 r3_test import ( "fmt" "gonum.org/v1/gonum/spatial/r3" ) func ExampleTriangle_icosphere() { // This example generates a 3D icosphere from // a starting icosahedron by subdividing surfaces. // See https://schneide.blog/2016/07/15/generating-an-icosphere-in-c/. const subdivisions = 5 // vertices is a slice of r3.Vec // triangles is a slice of [3]int indices // referencing the vertices. vertices, triangles := icosahedron() for i := 0; i < subdivisions; i++ { vertices, triangles = subdivide(vertices, triangles) } var faces []r3.Triangle for _, t := range triangles { var face r3.Triangle for i := 0; i < 3; i++ { face[i] = vertices[t[i]] } faces = append(faces, face) } fmt.Println(faces) // The 3D rendering of the icosphere is left as an exercise to the reader. } // edgeIdx represents an edge of the icosahedron type edgeIdx [2]int func subdivide(vertices []r3.Vec, triangles [][3]int) ([]r3.Vec, [][3]int) { // We generate a lookup table of all newly generated vertices so as to not // duplicate new vertices. edgeIdx has lower index first. lookup := make(map[edgeIdx]int) var result [][3]int for _, triangle := range triangles { var mid [3]int for edge := 0; edge < 3; edge++ { lookup, mid[edge], vertices = subdivideEdge(lookup, vertices, triangle[edge], triangle[(edge+1)%3]) } newTriangles := [][3]int{ {triangle[0], mid[0], mid[2]}, {triangle[1], mid[1], mid[0]}, {triangle[2], mid[2], mid[1]}, {mid[0], mid[1], mid[2]}, } result = append(result, newTriangles...) } return vertices, result } // subdivideEdge takes the vertices list and indices first and second which // refer to the edge that will be subdivided. // lookup is a table of all newly generated vertices from // previous calls to subdivideEdge so as to not duplicate vertices. func subdivideEdge(lookup map[edgeIdx]int, vertices []r3.Vec, first, second int) (map[edgeIdx]int, int, []r3.Vec) { key := edgeIdx{first, second} if first > second { // Swap to ensure edgeIdx always has lower index first. key[0], key[1] = key[1], key[0] } vertIdx, vertExists := lookup[key] if !vertExists { // If edge not already subdivided add // new dividing vertex to lookup table. edge0 := vertices[first] edge1 := vertices[second] point := r3.Unit(r3.Add(edge0, edge1)) // vertex at a normalized position. vertices = append(vertices, point) vertIdx = len(vertices) - 1 lookup[key] = vertIdx } return lookup, vertIdx, vertices } // icosahedron returns an icosahedron mesh. func icosahedron() (vertices []r3.Vec, triangles [][3]int) { const ( radiusSqrt = 1.0 // Example designed for unit sphere generation. X = radiusSqrt * .525731112119133606 Z = radiusSqrt * .850650808352039932 N = 0.0 ) return []r3.Vec{ {-X, N, Z}, {X, N, Z}, {-X, N, -Z}, {X, N, -Z}, {N, Z, X}, {N, Z, -X}, {N, -Z, X}, {N, -Z, -X}, {Z, X, N}, {-Z, X, N}, {Z, -X, N}, {-Z, -X, N}, }, [][3]int{ {0, 1, 4}, {0, 4, 9}, {9, 4, 5}, {4, 8, 5}, {4, 1, 8}, {8, 1, 10}, {8, 10, 3}, {5, 8, 3}, {5, 3, 2}, {2, 3, 7}, {7, 3, 10}, {7, 10, 6}, {7, 6, 11}, {11, 6, 0}, {0, 6, 1}, {6, 10, 1}, {9, 11, 0}, {9, 2, 11}, {9, 5, 2}, {7, 11, 2}, } } golang-gonum-v1-gonum-0.14.0/spatial/r3/mat.go000066400000000000000000000200771450372207100207350ustar00rootroot00000000000000// Copyright ©2021 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 r3 import "gonum.org/v1/gonum/mat" // Mat represents a 3×3 matrix. Useful for rotation matrices and such. // The zero value is usable as the 3×3 zero matrix. type Mat struct { data *array } var _ mat.Matrix = (*Mat)(nil) // NewMat returns a new 3×3 matrix Mat type and populates its elements // with values passed as argument in row-major form. If val argument // is nil then NewMat returns a matrix filled with zeros. func NewMat(val []float64) *Mat { if len(val) == 9 { return &Mat{arrayFrom(val)} } if val == nil { return &Mat{new(array)} } panic(mat.ErrShape) } // Dims returns the number of rows and columns of this matrix. // This method will always return 3×3 for a Mat. func (m *Mat) Dims() (r, c int) { return 3, 3 } // T returns the transpose of Mat. Changes in the receiver will be reflected in the returned matrix. func (m *Mat) T() mat.Matrix { return mat.Transpose{Matrix: m} } // Scale multiplies the elements of a by f, placing the result in the receiver. // // See the mat.Scaler interface for more information. func (m *Mat) Scale(f float64, a mat.Matrix) { r, c := a.Dims() if r != 3 || c != 3 { panic(mat.ErrShape) } if m.data == nil { m.data = new(array) } for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { m.Set(i, j, f*a.At(i, j)) } } } // MulVec returns the matrix-vector product M⋅v. func (m *Mat) MulVec(v Vec) Vec { if m.data == nil { return Vec{} } return Vec{ X: v.X*m.At(0, 0) + v.Y*m.At(0, 1) + v.Z*m.At(0, 2), Y: v.X*m.At(1, 0) + v.Y*m.At(1, 1) + v.Z*m.At(1, 2), Z: v.X*m.At(2, 0) + v.Y*m.At(2, 1) + v.Z*m.At(2, 2), } } // MulVecTrans returns the matrix-vector product Mᵀ⋅v. func (m *Mat) MulVecTrans(v Vec) Vec { if m.data == nil { return Vec{} } return Vec{ X: v.X*m.At(0, 0) + v.Y*m.At(1, 0) + v.Z*m.At(2, 0), Y: v.X*m.At(0, 1) + v.Y*m.At(1, 1) + v.Z*m.At(2, 1), Z: v.X*m.At(0, 2) + v.Y*m.At(1, 2) + v.Z*m.At(2, 2), } } // CloneFrom makes a copy of a into the receiver m. // Mat expects a 3×3 input matrix. func (m *Mat) CloneFrom(a mat.Matrix) { r, c := a.Dims() if r != 3 || c != 3 { panic(mat.ErrShape) } if m.data == nil { m.data = new(array) } for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { m.Set(i, j, a.At(i, j)) } } } // Sub subtracts the matrix b from a, placing the result in the receiver. // Sub will panic if the two matrices do not have the same shape. func (m *Mat) Sub(a, b mat.Matrix) { if r, c := a.Dims(); r != 3 || c != 3 { panic(mat.ErrShape) } if r, c := b.Dims(); r != 3 || c != 3 { panic(mat.ErrShape) } if m.data == nil { m.data = new(array) } m.Set(0, 0, a.At(0, 0)-b.At(0, 0)) m.Set(0, 1, a.At(0, 1)-b.At(0, 1)) m.Set(0, 2, a.At(0, 2)-b.At(0, 2)) m.Set(1, 0, a.At(1, 0)-b.At(1, 0)) m.Set(1, 1, a.At(1, 1)-b.At(1, 1)) m.Set(1, 2, a.At(1, 2)-b.At(1, 2)) m.Set(2, 0, a.At(2, 0)-b.At(2, 0)) m.Set(2, 1, a.At(2, 1)-b.At(2, 1)) m.Set(2, 2, a.At(2, 2)-b.At(2, 2)) } // Add adds a and b element-wise, placing the result in the receiver. Add will panic if the two matrices do not have the same shape. func (m *Mat) Add(a, b mat.Matrix) { if r, c := a.Dims(); r != 3 || c != 3 { panic(mat.ErrShape) } if r, c := b.Dims(); r != 3 || c != 3 { panic(mat.ErrShape) } if m.data == nil { m.data = new(array) } m.Set(0, 0, a.At(0, 0)+b.At(0, 0)) m.Set(0, 1, a.At(0, 1)+b.At(0, 1)) m.Set(0, 2, a.At(0, 2)+b.At(0, 2)) m.Set(1, 0, a.At(1, 0)+b.At(1, 0)) m.Set(1, 1, a.At(1, 1)+b.At(1, 1)) m.Set(1, 2, a.At(1, 2)+b.At(1, 2)) m.Set(2, 0, a.At(2, 0)+b.At(2, 0)) m.Set(2, 1, a.At(2, 1)+b.At(2, 1)) m.Set(2, 2, a.At(2, 2)+b.At(2, 2)) } // VecRow returns the elements in the ith row of the receiver. func (m *Mat) VecRow(i int) Vec { if i > 2 { panic(mat.ErrRowAccess) } if m.data == nil { return Vec{} } return Vec{X: m.At(i, 0), Y: m.At(i, 1), Z: m.At(i, 2)} } // VecCol returns the elements in the jth column of the receiver. func (m *Mat) VecCol(j int) Vec { if j > 2 { panic(mat.ErrColAccess) } if m.data == nil { return Vec{} } return Vec{X: m.At(0, j), Y: m.At(1, j), Z: m.At(2, j)} } // Outer calculates the outer product of the vectors x and y, // where x and y are treated as column vectors, and stores the result in the receiver. // // m = alpha * x * yᵀ func (m *Mat) Outer(alpha float64, x, y Vec) { ax := alpha * x.X ay := alpha * x.Y az := alpha * x.Z m.Set(0, 0, ax*y.X) m.Set(0, 1, ax*y.Y) m.Set(0, 2, ax*y.Z) m.Set(1, 0, ay*y.X) m.Set(1, 1, ay*y.Y) m.Set(1, 2, ay*y.Z) m.Set(2, 0, az*y.X) m.Set(2, 1, az*y.Y) m.Set(2, 2, az*y.Z) } // Det calculates the determinant of the receiver using the following formula // // ⎡a b c⎤ // m = ⎢d e f⎥ // ⎣g h i⎦ // det(m) = a(ei − fh) − b(di − fg) + c(dh − eg) func (m *Mat) Det() float64 { a := m.At(0, 0) b := m.At(0, 1) c := m.At(0, 2) deta := m.At(1, 1)*m.At(2, 2) - m.At(1, 2)*m.At(2, 1) detb := m.At(1, 0)*m.At(2, 2) - m.At(1, 2)*m.At(2, 0) detc := m.At(1, 0)*m.At(2, 1) - m.At(1, 1)*m.At(2, 0) return a*deta - b*detb + c*detc } // Skew sets the receiver to the 3×3 skew symmetric matrix // (right hand system) of v. // // ⎡ 0 -z y⎤ // Skew({x,y,z}) = ⎢ z 0 -x⎥ // ⎣-y x 0⎦ func (m *Mat) Skew(v Vec) { m.Set(0, 0, 0) m.Set(0, 1, -v.Z) m.Set(0, 2, v.Y) m.Set(1, 0, v.Z) m.Set(1, 1, 0) m.Set(1, 2, -v.X) m.Set(2, 0, -v.Y) m.Set(2, 1, v.X) m.Set(2, 2, 0) } // Hessian sets the receiver to the Hessian matrix of the scalar field at the point p, // approximated using finite differences with the given step sizes. // The field is evaluated at points in the area surrounding p by adding // at most 2 components of step to p. Hessian expects the field's second partial // derivatives are all continuous for correct results. func (m *Mat) Hessian(p, step Vec, field func(Vec) float64) { dx := Vec{X: step.X} dy := Vec{Y: step.Y} dz := Vec{Z: step.Z} fp := field(p) fxp := field(Add(p, dx)) fxm := field(Sub(p, dx)) fxx := (fxp - 2*fp + fxm) / (step.X * step.X) fyp := field(Add(p, dy)) fym := field(Sub(p, dy)) fyy := (fyp - 2*fp + fym) / (step.Y * step.Y) aux := Add(dx, dy) fxyp := field(Add(p, aux)) fxym := field(Sub(p, aux)) fxy := (fxyp - fxp - fyp + 2*fp - fxm - fym + fxym) / (2 * step.X * step.Y) fzp := field(Add(p, dz)) fzm := field(Sub(p, dz)) fzz := (fzp - 2*fp + fzm) / (step.Z * step.Z) aux = Add(dx, dz) fxzp := field(Add(p, aux)) fxzm := field(Sub(p, aux)) fxz := (fxzp - fxp - fzp + 2*fp - fxm - fzm + fxzm) / (2 * step.X * step.Z) aux = Add(dy, dz) fyzp := field(Add(p, aux)) fyzm := field(Sub(p, aux)) fyz := (fyzp - fyp - fzp + 2*fp - fym - fzm + fyzm) / (2 * step.Y * step.Z) m.Set(0, 0, fxx) m.Set(0, 1, fxy) m.Set(0, 2, fxz) m.Set(1, 0, fxy) m.Set(1, 1, fyy) m.Set(1, 2, fyz) m.Set(2, 0, fxz) m.Set(2, 1, fyz) m.Set(2, 2, fzz) } // Jacobian sets the receiver to the Jacobian matrix of the vector field at // the point p, approximated using finite differences with the given step sizes. // // The Jacobian matrix J is the matrix of all first-order partial derivatives of f. // If f maps an 3-dimensional vector x to an 3-dimensional vector y = f(x), J is // a 3×3 matrix whose elements are given as // // J_{i,j} = ∂f_i/∂x_j, // // or expanded out // // [ ∂f_1/∂x_1 ∂f_1/∂x_2 ∂f_1/∂x_3 ] // J = [ ∂f_2/∂x_1 ∂f_2/∂x_2 ∂f_2/∂x_3 ] // [ ∂f_3/∂x_1 ∂f_3/∂x_2 ∂f_3/∂x_3 ] // // Jacobian expects the field's first order partial derivatives are all // continuous for correct results. func (m *Mat) Jacobian(p, step Vec, field func(Vec) Vec) { dx := Vec{X: step.X} dy := Vec{Y: step.Y} dz := Vec{Z: step.Z} dfdx := Scale(0.5/step.X, Sub(field(Add(p, dx)), field(Sub(p, dx)))) dfdy := Scale(0.5/step.Y, Sub(field(Add(p, dy)), field(Sub(p, dy)))) dfdz := Scale(0.5/step.Z, Sub(field(Add(p, dz)), field(Sub(p, dz)))) m.Set(0, 0, dfdx.X) m.Set(0, 1, dfdy.X) m.Set(0, 2, dfdz.X) m.Set(1, 0, dfdx.Y) m.Set(1, 1, dfdy.Y) m.Set(1, 2, dfdz.Y) m.Set(2, 0, dfdx.Z) m.Set(2, 1, dfdy.Z) m.Set(2, 2, dfdz.Z) } golang-gonum-v1-gonum-0.14.0/spatial/r3/mat_safe.go000066400000000000000000000071771450372207100217410ustar00rootroot00000000000000// Copyright ©2021 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:build safe // +build safe // TODO(kortschak): Get rid of this rigmarole if https://golang.org/issue/50118 // is accepted. package r3 import ( "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/mat" ) type array [9]float64 // At returns the value of a matrix element at row i, column j. // At expects indices in the range [0,2]. // It will panic if i or j are out of bounds for the matrix. func (m *Mat) At(i, j int) float64 { if uint(i) > 2 { panic(mat.ErrRowAccess) } if uint(j) > 2 { panic(mat.ErrColAccess) } if m.data == nil { m.data = new(array) } return m.data[i*3+j] } // Set sets the element at row i, column j to the value v. func (m *Mat) Set(i, j int, v float64) { if uint(i) > 2 { panic(mat.ErrRowAccess) } if uint(j) > 2 { panic(mat.ErrColAccess) } if m.data == nil { m.data = new(array) } m.data[i*3+j] = v } // Eye returns the 3×3 Identity matrix func Eye() *Mat { return &Mat{&array{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }} } // Skew returns the 3×3 skew symmetric matrix (right hand system) of v. // // ⎡ 0 -z y⎤ // Skew({x,y,z}) = ⎢ z 0 -x⎥ // ⎣-y x 0⎦ // // Deprecated: use Mat.Skew() func Skew(v Vec) (M *Mat) { return &Mat{&array{ 0, -v.Z, v.Y, v.Z, 0, -v.X, -v.Y, v.X, 0, }} } // Mul takes the matrix product of a and b, placing the result in the receiver. // If the number of columns in a does not equal 3, Mul will panic. func (m *Mat) Mul(a, b mat.Matrix) { ra, ca := a.Dims() rb, cb := b.Dims() switch { case ra != 3: panic(mat.ErrShape) case cb != 3: panic(mat.ErrShape) case ca != rb: panic(mat.ErrShape) } if m.data == nil { m.data = new(array) } if ca != 3 { // General matrix multiplication for the case where the inner dimension is not 3. var t mat.Dense t.Mul(a, b) copy(m.data[:], t.RawMatrix().Data) return } a00 := a.At(0, 0) b00 := b.At(0, 0) a01 := a.At(0, 1) b01 := b.At(0, 1) a02 := a.At(0, 2) b02 := b.At(0, 2) a10 := a.At(1, 0) b10 := b.At(1, 0) a11 := a.At(1, 1) b11 := b.At(1, 1) a12 := a.At(1, 2) b12 := b.At(1, 2) a20 := a.At(2, 0) b20 := b.At(2, 0) a21 := a.At(2, 1) b21 := b.At(2, 1) a22 := a.At(2, 2) b22 := b.At(2, 2) *(m.data) = array{ a00*b00 + a01*b10 + a02*b20, a00*b01 + a01*b11 + a02*b21, a00*b02 + a01*b12 + a02*b22, a10*b00 + a11*b10 + a12*b20, a10*b01 + a11*b11 + a12*b21, a10*b02 + a11*b12 + a12*b22, a20*b00 + a21*b10 + a22*b20, a20*b01 + a21*b11 + a22*b21, a20*b02 + a21*b12 + a22*b22, } } // RawMatrix returns the blas representation of the matrix with the backing // data of this matrix. Changes to the returned matrix will be reflected in // the receiver. func (m *Mat) RawMatrix() blas64.General { if m.data == nil { m.data = new(array) } return blas64.General{Rows: 3, Cols: 3, Data: m.data[:], Stride: 3} } func arrayFrom(vals []float64) *array { return (*array)(vals) } // Mat returns a 3×3 rotation matrix corresponding to the receiver. It // may be used to perform rotations on a 3-vector or to apply the rotation // to a 3×n matrix of column vectors. If the receiver is not a unit // quaternion, the returned matrix will not be a pure rotation. func (r Rotation) Mat() *Mat { w, i, j, k := r.Real, r.Imag, r.Jmag, r.Kmag ii := 2 * i * i jj := 2 * j * j kk := 2 * k * k wi := 2 * w * i wj := 2 * w * j wk := 2 * w * k ij := 2 * i * j jk := 2 * j * k ki := 2 * k * i return &Mat{&array{ 1 - (jj + kk), ij - wk, ki + wj, ij + wk, 1 - (ii + kk), jk - wi, ki - wj, jk + wi, 1 - (ii + jj), }} } golang-gonum-v1-gonum-0.14.0/spatial/r3/mat_test.go000066400000000000000000000174511450372207100217760ustar00rootroot00000000000000// Copyright ©2021 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 r3 import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/num/quat" ) func TestMatAdd(t *testing.T) { const tol = 1e-16 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { a := randomMat(rnd) b := randomMat(rnd) var ( want mat.Dense got Mat ) want.Add(a, b) got.Add(a, b) if !mat.EqualApprox(&got, &want, tol) { t.Errorf("unexpected result for matrix add:\ngot:\n%v\nwant:\n%v", mat.Formatted(&got), mat.Formatted(&want)) } } } func TestMatSub(t *testing.T) { const tol = 1e-16 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { a := randomMat(rnd) b := randomMat(rnd) var ( want mat.Dense got Mat ) want.Sub(a, b) got.Sub(a, b) if !mat.EqualApprox(&got, &want, tol) { t.Errorf("unexpected result for matrix subtract:\ngot:\n%v\nwant:\n%v", mat.Formatted(&got), mat.Formatted(&want)) } } } func TestMatMul(t *testing.T) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { a := randomMat(rnd) b := randomMat(rnd) var ( want mat.Dense got Mat ) want.Mul(a, b) got.Mul(a, b) if !mat.EqualApprox(&got, &want, tol) { t.Errorf("unexpected result for matrix multiply:\ngot:\n%v\nwant:\n%v", mat.Formatted(&got), mat.Formatted(&want)) } } } func TestMatScale(t *testing.T) { const tol = 1e-16 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { v := rnd.Float64() a := randomMat(rnd) var ( want mat.Dense got Mat ) want.Scale(v, a) got.Scale(v, a) if !mat.EqualApprox(&got, &want, tol) { t.Errorf("unexpected result for matrix scale:\ngot:\n%v\nwant:\n%v", mat.Formatted(&got), mat.Formatted(&want)) } } } func TestMatCloneFrom(t *testing.T) { const tol = 1e-16 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { want := randomMat(rnd) got := NewMat(nil) got.CloneFrom(want) if !mat.EqualApprox(got, want, tol) { t.Errorf("unexpected result from CloneFrom:\ngot:\n%v\nwant:\n%v", mat.Formatted(got), mat.Formatted(want)) } } } func TestSkew(t *testing.T) { const tol = 1e-16 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { sk := NewMat(nil) v1 := randomVec(rnd) v2 := randomVec(rnd) sk.Skew(v1) want := Cross(v1, v2) got := sk.MulVec(v2) if d := Sub(want, got); Dot(d, d) > tol { t.Errorf("r3.Cross(v1,v2) does not agree with r3.Skew(v1)*v2: got:%v want:%v", got, want) } } } func TestTranspose(t *testing.T) { const tol = 1e-16 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { d := mat.NewDense(3, 3, nil) m := randomMat(rnd) d.CloneFrom(m) mt := m.T() dt := d.T() if !mat.Equal(mt, dt) { t.Errorf("Dense.T() not equal to r3.Mat.T():\ngot:\n%v\nwant:\n%v", mat.Formatted(mt), mat.Formatted(dt)) } vd := mat.NewVecDense(3, nil) v := randomVec(rnd) vd.SetVec(0, v.X) vd.SetVec(1, v.Y) vd.SetVec(2, v.Z) vd.MulVec(dt, vd) want := Vec{X: vd.AtVec(0), Y: vd.AtVec(1), Z: vd.AtVec(2)} got := m.MulVecTrans(v) if d := Sub(want, got); Dot(d, d) > tol { t.Errorf("VecDense.MulVec(dense.T()) not agree with r3.Mat.MulVec(r3.Vec): got:%v want:%v", got, want) } } } func randomMat(rnd *rand.Rand) *Mat { m := Mat{new(array)} for iv := 0; iv < 9; iv++ { i := iv / 3 j := iv % 3 m.Set(i, j, (rnd.Float64()-0.5)*20) } return &m } func randomVec(rnd *rand.Rand) (v Vec) { v.X = (rnd.Float64() - 0.5) * 20 v.Y = (rnd.Float64() - 0.5) * 20 v.Z = (rnd.Float64() - 0.5) * 20 return v } func TestDet(t *testing.T) { const tol = 1e-11 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { m := randomMat(rnd) got := m.Det() want := mat.Det(m) if math.Abs(got-want) > tol { t.Errorf("r3.Mat.Det() not equal to mat.Det(). got %f, want %f", got, want) } } } func TestOuter(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { alpha := rnd.Float64() d := mat.NewDense(3, 3, nil) n := NewMat(nil) v1 := randomVec(rnd) v2 := randomVec(rnd) d1 := mat.NewVecDense(3, []float64{v1.X, v1.Y, v1.Z}) d2 := mat.NewVecDense(3, []float64{v2.X, v2.Y, v2.Z}) d.Outer(alpha, d1, d2) n.Outer(alpha, v1, v2) if !mat.Equal(d, n) { t.Error("matrices not equal") } } } func TestRotationMat(t *testing.T) { const tol = 1e-14 rnd := rand.New(rand.NewSource(1)) for tc := 0; tc < 20; tc++ { // Generate a random unit quaternion. q := quat.Number{Real: rnd.NormFloat64(), Imag: rnd.NormFloat64(), Jmag: rnd.NormFloat64(), Kmag: rnd.NormFloat64()} q = quat.Scale(1/quat.Abs(q), q) // Convert it to a rotation matrix R. r := Rotation(q).Mat() // Check that the matrix has the determinant approximately equal to 1. diff := math.Abs(r.Det() - 1) if diff > tol { t.Errorf("case %d: unexpected determinant of R; got=%f, want=1 (diff=%v)", tc, r.Det(), diff) continue } // Generate a random point. v := Vec{X: rnd.NormFloat64(), Y: rnd.NormFloat64(), Z: rnd.NormFloat64()} // Rotate it using the formula q*v*conj(q). want := Rotation(q).Rotate(v) // Rotate it using the rotation matrix R. got := r.MulVec(v) // Check that |got-want| is small. diff = Norm(Sub(got, want)) if diff > tol { t.Errorf("case %d: unexpected result; got=%f, want=%f, (diff=%v)", tc, got, want, diff) } } } func BenchmarkQuat(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { q := quat.Number{Real: rnd.Float64(), Imag: rnd.Float64(), Jmag: rnd.Float64(), Kmag: rnd.Float64()} if Rotation(q).Mat() == nil { b.Fatal("nil return") } } } var scalarFields = []struct { // This is the scalar field function. field func(p Vec) float64 gradient func(p Vec) Vec hessian func(p Vec) *Mat }{ { field: func(p Vec) float64 { // 4*x^3 + 5*y^2 + 3*z^4 z2 := p.Z * p.Z return 4*p.X*p.X*p.X + 5*p.Y*p.Y + 3*z2*z2 }, gradient: func(p Vec) Vec { return Vec{X: 12 * p.X * p.X, Y: 10 * p.Y, Z: 12 * p.Z * p.Z * p.Z} }, hessian: func(p Vec) *Mat { return NewMat([]float64{ 24 * p.X, 0, 0, 0, 10, 0, 0, 0, 36 * p.Z * p.Z, }) }, }, { field: func(p Vec) float64 { // cos(x) * sin(z) * y^4 y2 := p.Y * p.Y return math.Cos(p.X) * math.Sin(p.Z) * y2 * y2 }, gradient: func(p Vec) Vec { y3 := p.Y * p.Y * p.Y y4 := p.Y * y3 sx, cx := math.Sincos(p.X) sz, cz := math.Sincos(p.Z) return Vec{X: -y4 * sx * sz, Y: 4 * y3 * cx * sz, Z: y4 * cx * cz} }, hessian: func(p Vec) *Mat { y3 := p.Y * p.Y * p.Y y4 := y3 * p.Y sx, cx := math.Sincos(p.X) sz, cz := math.Sincos(p.Z) return NewMat([]float64{ -y4 * cx * sz, -4 * y3 * sx * sz, -y4 * sx * cz, -4 * y3 * sx * sz, 12 * p.Y * p.Y * cx * sz, 4 * y3 * cx * cz, -y4 * sx * cz, 4 * y3 * cx * cz, -y4 * cx * sz, }) }, }, } func TestMatHessian(t *testing.T) { const ( tol = 1e-5 h = 8e-4 ) step := Vec{X: h, Y: h, Z: h} rnd := rand.New(rand.NewSource(1)) for _, test := range scalarFields { for i := 0; i < 30; i++ { p := randomVec(rnd) got := NewMat(nil) got.Hessian(p, step, test.field) want := test.hessian(p) if !mat.EqualApprox(got, want, tol) { t.Errorf("matrices not equal within tol\ngot: %v\nwant: %v", mat.Formatted(got), mat.Formatted(want)) } } } } func TestMatJacobian(t *testing.T) { const ( tol = 1e-5 h = 8e-4 ) step := Vec{X: h, Y: h, Z: h} rnd := rand.New(rand.NewSource(1)) for _, test := range vectorFields { for i := 0; i < 1; i++ { p := randomVec(rnd) got := NewMat(nil) got.Jacobian(p, step, test.field) want := test.jacobian(p) if !mat.EqualApprox(got, want, tol) { t.Errorf("matrices not equal within tol\ngot: %v\nwant: %v", mat.Formatted(got), mat.Formatted(want)) } } } } golang-gonum-v1-gonum-0.14.0/spatial/r3/mat_unsafe.go000066400000000000000000000071031450372207100222710ustar00rootroot00000000000000// Copyright ©2021 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:build !safe // +build !safe package r3 import ( "unsafe" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/mat" ) type array [3][3]float64 // At returns the value of a matrix element at row i, column j. // At expects indices in the range [0,2]. // It will panic if i or j are out of bounds for the matrix. func (m *Mat) At(i, j int) float64 { if m.data == nil { m.data = new(array) } return m.data[i][j] } // Set sets the element at row i, column j to the value v. func (m *Mat) Set(i, j int, v float64) { if m.data == nil { m.data = new(array) } m.data[i][j] = v } // Eye returns the 3×3 Identity matrix func Eye() *Mat { return &Mat{&array{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, }} } // Skew returns the 3×3 skew symmetric matrix (right hand system) of v. // // ⎡ 0 -z y⎤ // Skew({x,y,z}) = ⎢ z 0 -x⎥ // ⎣-y x 0⎦ // // Deprecated: use Mat.Skew() func Skew(v Vec) (M *Mat) { return &Mat{&array{ {0, -v.Z, v.Y}, {v.Z, 0, -v.X}, {-v.Y, v.X, 0}, }} } // Mul takes the matrix product of a and b, placing the result in the receiver. // If the number of columns in a does not equal 3, Mul will panic. func (m *Mat) Mul(a, b mat.Matrix) { ra, ca := a.Dims() rb, cb := b.Dims() switch { case ra != 3: panic(mat.ErrShape) case cb != 3: panic(mat.ErrShape) case ca != rb: panic(mat.ErrShape) } if m.data == nil { m.data = new(array) } if ca != 3 { // General matrix multiplication for the case where the inner dimension is not 3. t := mat.NewDense(3, 3, m.slice()) t.Mul(a, b) return } a00 := a.At(0, 0) b00 := b.At(0, 0) a01 := a.At(0, 1) b01 := b.At(0, 1) a02 := a.At(0, 2) b02 := b.At(0, 2) a10 := a.At(1, 0) b10 := b.At(1, 0) a11 := a.At(1, 1) b11 := b.At(1, 1) a12 := a.At(1, 2) b12 := b.At(1, 2) a20 := a.At(2, 0) b20 := b.At(2, 0) a21 := a.At(2, 1) b21 := b.At(2, 1) a22 := a.At(2, 2) b22 := b.At(2, 2) m.data[0][0] = a00*b00 + a01*b10 + a02*b20 m.data[0][1] = a00*b01 + a01*b11 + a02*b21 m.data[0][2] = a00*b02 + a01*b12 + a02*b22 m.data[1][0] = a10*b00 + a11*b10 + a12*b20 m.data[1][1] = a10*b01 + a11*b11 + a12*b21 m.data[1][2] = a10*b02 + a11*b12 + a12*b22 m.data[2][0] = a20*b00 + a21*b10 + a22*b20 m.data[2][1] = a20*b01 + a21*b11 + a22*b21 m.data[2][2] = a20*b02 + a21*b12 + a22*b22 } // RawMatrix returns the blas representation of the matrix with the backing // data of this matrix. Changes to the returned matrix will be reflected in // the receiver. func (m *Mat) RawMatrix() blas64.General { if m.data == nil { m.data = new(array) } return blas64.General{Rows: 3, Cols: 3, Data: m.slice(), Stride: 3} } // Mat returns a 3×3 rotation matrix corresponding to the receiver. It // may be used to perform rotations on a 3-vector or to apply the rotation // to a 3×n matrix of column vectors. If the receiver is not a unit // quaternion, the returned matrix will not be a pure rotation. func (r Rotation) Mat() *Mat { w, i, j, k := r.Real, r.Imag, r.Jmag, r.Kmag ii := 2 * i * i jj := 2 * j * j kk := 2 * k * k wi := 2 * w * i wj := 2 * w * j wk := 2 * w * k ij := 2 * i * j jk := 2 * j * k ki := 2 * k * i return &Mat{&array{ {1 - (jj + kk), ij - wk, ki + wj}, {ij + wk, 1 - (ii + kk), jk - wi}, {ki - wj, jk + wi, 1 - (ii + jj)}, }} } func arrayFrom(vals []float64) *array { return (*array)(unsafe.Pointer(&vals[0])) } func (m *Mat) slice() []float64 { return (*[9]float64)(unsafe.Pointer(m.data))[:] } golang-gonum-v1-gonum-0.14.0/spatial/r3/rotation.go000066400000000000000000000030361450372207100220070ustar00rootroot00000000000000// Copyright ©2021 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 r3 import ( "math" "gonum.org/v1/gonum/num/quat" ) // TODO: possibly useful additions to the current rotation API: // - create rotations from Euler angles (NewRotationFromEuler?) // - create rotations from rotation matrices (NewRotationFromMatrix?) // - return the equivalent Euler angles from a Rotation // // Euler angles have issues (see [1] for a discussion). // We should think carefully before adding them in. // [1]: http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ // Rotation describes a rotation in space. type Rotation quat.Number // NewRotation creates a rotation by alpha, around axis. func NewRotation(alpha float64, axis Vec) Rotation { if alpha == 0 { return Rotation{Real: 1} } q := raise(axis) sin, cos := math.Sincos(0.5 * alpha) q = quat.Scale(sin/quat.Abs(q), q) q.Real += cos if len := quat.Abs(q); len != 1 { q = quat.Scale(1/len, q) } return Rotation(q) } // Rotate returns p rotated according to the parameters used to construct // the receiver. func (r Rotation) Rotate(p Vec) Vec { if r.isIdentity() { return p } qq := quat.Number(r) pp := quat.Mul(quat.Mul(qq, raise(p)), quat.Conj(qq)) return Vec{X: pp.Imag, Y: pp.Jmag, Z: pp.Kmag} } func (r Rotation) isIdentity() bool { return r == Rotation{Real: 1} } func raise(p Vec) quat.Number { return quat.Number{Imag: p.X, Jmag: p.Y, Kmag: p.Z} } golang-gonum-v1-gonum-0.14.0/spatial/r3/triangle.go000066400000000000000000000066731450372207100217670ustar00rootroot00000000000000// Copyright ©2022 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 r3 import "math" // Triangle represents a triangle in 3D space and // is composed by 3 vectors corresponding to the position // of each of the vertices. Ordering of these vertices // decides the "normal" direction. // Inverting ordering of two vertices inverts the resulting direction. type Triangle [3]Vec // Centroid returns the intersection of the three medians of the triangle // as a point in space. func (t Triangle) Centroid() Vec { return Scale(1.0/3.0, Add(Add(t[0], t[1]), t[2])) } // Normal returns the vector with direction // perpendicular to the Triangle's face and magnitude // twice that of the Triangle's area. The ordering // of the triangle vertices decides the normal's resulting // direction. The returned vector is not normalized. func (t Triangle) Normal() Vec { s1, s2, _ := t.sides() return Cross(s1, s2) } // IsDegenerate returns true if all of triangle's vertices are // within tol distance of its longest side. func (t Triangle) IsDegenerate(tol float64) bool { longIdx := t.longIdx() // calculate vertex distance from longest side ln := line{t[longIdx], t[(longIdx+1)%3]} dist := ln.distance(t[(longIdx+2)%3]) return dist <= tol } // longIdx returns index of the longest side. The sides // of the triangles are are as follows: // - Side 0 formed by vertices 0 and 1 // - Side 1 formed by vertices 1 and 2 // - Side 2 formed by vertices 0 and 2 func (t Triangle) longIdx() int { sides := [3]Vec{Sub(t[1], t[0]), Sub(t[2], t[1]), Sub(t[0], t[2])} len2 := [3]float64{Norm2(sides[0]), Norm2(sides[1]), Norm2(sides[2])} longLen := len2[0] longIdx := 0 if len2[1] > longLen { longLen = len2[1] longIdx = 1 } if len2[2] > longLen { longIdx = 2 } return longIdx } // Area returns the surface area of the triangle. func (t Triangle) Area() float64 { // Heron's Formula, see https://en.wikipedia.org/wiki/Heron%27s_formula. // Also see William M. Kahan (24 March 2000). "Miscalculating Area and Angles of a Needle-like Triangle" // for more discussion. https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf. a, b, c := t.orderedLengths() A := (c + (b + a)) * (a - (c - b)) A *= (a + (c - b)) * (c + (b - a)) return math.Sqrt(A) / 4 } // orderedLengths returns the lengths of the sides of the triangle such that // a ≤ b ≤ c. func (t Triangle) orderedLengths() (a, b, c float64) { s1, s2, s3 := t.sides() l1 := Norm(s1) l2 := Norm(s2) l3 := Norm(s3) // sort-3 if l2 < l1 { l1, l2 = l2, l1 } if l3 < l2 { l2, l3 = l3, l2 if l2 < l1 { l1, l2 = l2, l1 } } return l1, l2, l3 } // sides returns vectors for each of the sides of t. func (t Triangle) sides() (Vec, Vec, Vec) { return Sub(t[1], t[0]), Sub(t[2], t[1]), Sub(t[0], t[2]) } // line is an infinite 3D line // defined by two points on the line. type line [2]Vec // vecOnLine takes a value between 0 and 1 to linearly // interpolate a point on the line. // // vecOnLine(0) returns l[0] // vecOnLine(1) returns l[1] func (l line) vecOnLine(t float64) Vec { lineDir := Sub(l[1], l[0]) return Add(l[0], Scale(t, lineDir)) } // distance returns the minimum euclidean distance of point p // to the line. func (l line) distance(p Vec) float64 { // https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html num := Norm(Cross(Sub(p, l[0]), Sub(p, l[1]))) return num / Norm(Sub(l[1], l[0])) } golang-gonum-v1-gonum-0.14.0/spatial/r3/triangle_test.go000066400000000000000000000123051450372207100230130ustar00rootroot00000000000000// Copyright ©2022 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 r3 import ( "math" "testing" "golang.org/x/exp/rand" ) func TestTriangleDegenerate(t *testing.T) { const ( // tol is how much closer the problematic // vertex is placed to avoid floating point error // for degeneracy calculation. tol = 1e-12 // This is the argument to Degenerate and represents // the minimum permissible distance between the triangle // longest edge and the opposite vertex. spatialTol = 1e-2 ) rnd := rand.New(rand.NewSource(1)) for i := 0; i < 200; i++ { // Generate a random line for the longest triangle side. ln := line{randomVec(rnd), randomVec(rnd)} lineDir := Sub(ln[1], ln[0]) perpendicular := Unit(Cross(lineDir, randomVec(rnd))) // generate 3 permutations of needle triangles for // each vertex. A needle triangle has two vertices // very close to eachother an its third vertex far away. var needle Triangle for j := 0; j < 3; j++ { needle[j] = ln[0] needle[(j+1)%3] = ln[1] needle[(j+2)%3] = Add(ln[1], Scale((1-tol)*spatialTol, perpendicular)) if !needle.IsDegenerate(spatialTol) { t.Error("needle triangle not degenerate") } } midpoint := ln.vecOnLine(0.5) // cap triangles are characterized by having two sides // of similar lengths and whose sum is approximately equal // to the remaining longest side. var cap Triangle for j := 0; j < 3; j++ { cap[j] = ln[0] cap[(j+1)%3] = ln[1] cap[(j+2)%3] = Add(midpoint, Scale((1-tol)*spatialTol, perpendicular)) if !cap.IsDegenerate(spatialTol) { t.Error("cap triangle not degenerate") } } var degenerate Triangle for j := 0; j < 3; j++ { degenerate[j] = ln[0] degenerate[(j+1)%3] = ln[1] // vertex perpendicular to some random point on longest side. degenerate[(j+2)%3] = Add(ln.vecOnLine(rnd.Float64()), Scale((1-tol)*spatialTol, perpendicular)) if !degenerate.IsDegenerate(spatialTol) { t.Error("random degenerate triangle not degenerate") } // vertex about longest side 0 vertex degenerate[(j+2)%3] = Add(ln[0], Scale((1-tol)*spatialTol, Unit(randomVec(rnd)))) if !degenerate.IsDegenerate(spatialTol) { t.Error("needle-like degenerate triangle not degenerate") } // vertex about longest side 1 vertex degenerate[(j+2)%3] = Add(ln[1], Scale((1-tol)*spatialTol, Unit(randomVec(rnd)))) if !degenerate.IsDegenerate(spatialTol) { t.Error("needle-like degenerate triangle not degenerate") } } } } func TestTriangleCentroid(t *testing.T) { const tol = 1e-12 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 100; i++ { tri := randomTriangle(rnd) got := tri.Centroid() want := Vec{ X: (tri[0].X + tri[1].X + tri[2].X) / 3, Y: (tri[0].Y + tri[1].Y + tri[2].Y) / 3, Z: (tri[0].Z + tri[1].Z + tri[2].Z) / 3, } if !vecApproxEqual(got, want, tol) { t.Fatalf("got %.6g, want %.6g", got, want) } } } func TestTriangleNormal(t *testing.T) { const tol = 1e-12 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 100; i++ { tri := randomTriangle(rnd) got := tri.Normal() expect := goldenNormal(tri) if !vecApproxEqual(got, expect, tol) { t.Fatalf("got %.6g, want %.6g", got, expect) } } } func TestTriangleArea(t *testing.T) { const tol = 1e-16 for _, test := range []struct { T Triangle Expect float64 }{ { T: Triangle{ {0, 0, 0}, {1, 0, 0}, {0, 1, 0}, }, Expect: 0.5, }, { T: Triangle{ {1, 0, 0}, {0, 1, 0}, {0, 0, 0}, }, Expect: 0.5, }, { T: Triangle{ {20, 0, 0}, {0, 0, 20}, {0, 0, 0}, }, Expect: 20 * 20 / 2, }, } { got := test.T.Area() if math.Abs(got-test.Expect) > tol { t.Errorf("got area %g, expected %g", got, test.Expect) } if test.T.IsDegenerate(tol) { t.Error("well-formed triangle is degenerate") } } const tol2 = 1e-12 rnd := rand.New(rand.NewSource(1)) for i := 0; i < 100; i++ { tri := randomTriangle(rnd) got := tri.Area() want := Norm(Cross(Sub(tri[1], tri[0]), Sub(tri[2], tri[0]))) / 2 if math.Abs(got-want) > tol2 { t.Errorf("got area %g not match half norm of cross product %g", got, want) } } } func TestTriangleOrderedLengths(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < 200; i++ { tri := randomTriangle(rnd) s1, s2, s3 := tri.sides() l1 := Norm(s1) l2 := Norm(s2) l3 := Norm(s3) a, b, c := tri.orderedLengths() if a != l1 && a != l2 && a != l3 { t.Error("shortest ordered length not a side of the triangle") } if b != l1 && b != l2 && b != l3 { t.Error("middle ordered length not a side of the triangle") } if c != l1 && c != l2 && c != l3 { t.Error("longest ordered length not a side of the triangle") } if a > b || a > c { t.Error("ordered short side not shortest side") } if c < b { t.Error("ordered long side not longest side") } } } // taken from soypat/sdf library where it has been thoroughly tested empirically. func goldenNormal(t Triangle) Vec { e1 := Sub(t[1], t[0]) e2 := Sub(t[2], t[0]) return Cross(e1, e2) } func randomTriangle(rnd *rand.Rand) Triangle { return Triangle{ randomVec(rnd), randomVec(rnd), randomVec(rnd), } } golang-gonum-v1-gonum-0.14.0/spatial/r3/vector.go000066400000000000000000000072331450372207100214550ustar00rootroot00000000000000// Copyright ©2019 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 r3 import "math" // Vec is a 3D vector. type Vec struct { X, Y, Z float64 } // Add returns the vector sum of p and q. func Add(p, q Vec) Vec { return Vec{ X: p.X + q.X, Y: p.Y + q.Y, Z: p.Z + q.Z, } } // Sub returns the vector sum of p and -q. func Sub(p, q Vec) Vec { return Vec{ X: p.X - q.X, Y: p.Y - q.Y, Z: p.Z - q.Z, } } // Scale returns the vector p scaled by f. func Scale(f float64, p Vec) Vec { return Vec{ X: f * p.X, Y: f * p.Y, Z: f * p.Z, } } // Dot returns the dot product p·q. func Dot(p, q Vec) float64 { return p.X*q.X + p.Y*q.Y + p.Z*q.Z } // Cross returns the cross product p×q. func Cross(p, q Vec) Vec { return Vec{ p.Y*q.Z - p.Z*q.Y, p.Z*q.X - p.X*q.Z, p.X*q.Y - p.Y*q.X, } } // Rotate returns a new vector, rotated by alpha around the provided axis. func Rotate(p Vec, alpha float64, axis Vec) Vec { return NewRotation(alpha, axis).Rotate(p) } // Norm returns the Euclidean norm of p // // |p| = sqrt(p_x^2 + p_y^2 + p_z^2). func Norm(p Vec) float64 { return math.Hypot(p.X, math.Hypot(p.Y, p.Z)) } // Norm2 returns the Euclidean squared norm of p // // |p|^2 = p_x^2 + p_y^2 + p_z^2. func Norm2(p Vec) float64 { return p.X*p.X + p.Y*p.Y + p.Z*p.Z } // Unit returns the unit vector colinear to p. // Unit returns {NaN,NaN,NaN} for the zero vector. func Unit(p Vec) Vec { if p.X == 0 && p.Y == 0 && p.Z == 0 { return Vec{X: math.NaN(), Y: math.NaN(), Z: math.NaN()} } return Scale(1/Norm(p), p) } // Cos returns the cosine of the opening angle between p and q. func Cos(p, q Vec) float64 { return Dot(p, q) / (Norm(p) * Norm(q)) } // Divergence returns the divergence of the vector field at the point p, // approximated using finite differences with the given step sizes. func Divergence(p, step Vec, field func(Vec) Vec) float64 { sx := Vec{X: step.X} divx := (field(Add(p, sx)).X - field(Sub(p, sx)).X) / step.X sy := Vec{Y: step.Y} divy := (field(Add(p, sy)).Y - field(Sub(p, sy)).Y) / step.Y sz := Vec{Z: step.Z} divz := (field(Add(p, sz)).Z - field(Sub(p, sz)).Z) / step.Z return 0.5 * (divx + divy + divz) } // Gradient returns the gradient of the scalar field at the point p, // approximated using finite differences with the given step sizes. func Gradient(p, step Vec, field func(Vec) float64) Vec { dx := Vec{X: step.X} dy := Vec{Y: step.Y} dz := Vec{Z: step.Z} return Vec{ X: (field(Add(p, dx)) - field(Sub(p, dx))) / (2 * step.X), Y: (field(Add(p, dy)) - field(Sub(p, dy))) / (2 * step.Y), Z: (field(Add(p, dz)) - field(Sub(p, dz))) / (2 * step.Z), } } // minElem return a vector with the minimum components of two vectors. func minElem(a, b Vec) Vec { return Vec{ X: math.Min(a.X, b.X), Y: math.Min(a.Y, b.Y), Z: math.Min(a.Z, b.Z), } } // maxElem return a vector with the maximum components of two vectors. func maxElem(a, b Vec) Vec { return Vec{ X: math.Max(a.X, b.X), Y: math.Max(a.Y, b.Y), Z: math.Max(a.Z, b.Z), } } // absElem returns the vector with components set to their absolute value. func absElem(a Vec) Vec { return Vec{ X: math.Abs(a.X), Y: math.Abs(a.Y), Z: math.Abs(a.Z), } } // mulElem returns the Hadamard product between vectors a and b. // // v = {a.X*b.X, a.Y*b.Y, a.Z*b.Z} func mulElem(a, b Vec) Vec { return Vec{ X: a.X * b.X, Y: a.Y * b.Y, Z: a.Z * b.Z, } } // divElem returns the Hadamard product between vector a // and the inverse components of vector b. // // v = {a.X/b.X, a.Y/b.Y, a.Z/b.Z} func divElem(a, b Vec) Vec { return Vec{ X: a.X / b.X, Y: a.Y / b.Y, Z: a.Z / b.Z, } } golang-gonum-v1-gonum-0.14.0/spatial/r3/vector_test.go000066400000000000000000000214011450372207100225050ustar00rootroot00000000000000// Copyright ©2020 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 r3 import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func TestAdd(t *testing.T) { for _, test := range []struct { v1, v2 Vec want Vec }{ {Vec{0, 0, 0}, Vec{0, 0, 0}, Vec{0, 0, 0}}, {Vec{1, 0, 0}, Vec{0, 0, 0}, Vec{1, 0, 0}}, {Vec{1, 2, 3}, Vec{4, 5, 7}, Vec{5, 7, 10}}, {Vec{1, -3, 5}, Vec{1, -6, -6}, Vec{2, -9, -1}}, {Vec{1, 2, 3}, Vec{-1, -2, -3}, Vec{}}, } { got := Add(test.v1, test.v2) if got != test.want { t.Errorf( "error: %v + %v: got=%v, want=%v", test.v1, test.v2, got, test.want, ) } } } func TestSub(t *testing.T) { for _, test := range []struct { v1, v2 Vec want Vec }{ {Vec{0, 0, 0}, Vec{0, 0, 0}, Vec{0, 0, 0}}, {Vec{1, 0, 0}, Vec{0, 0, 0}, Vec{1, 0, 0}}, {Vec{1, 2, 3}, Vec{4, 5, 7}, Vec{-3, -3, -4}}, {Vec{1, -3, 5}, Vec{1, -6, -6}, Vec{0, 3, 11}}, {Vec{1, 2, 3}, Vec{1, 2, 3}, Vec{}}, } { got := Sub(test.v1, test.v2) if got != test.want { t.Errorf( "error: %v - %v: got=%v, want=%v", test.v1, test.v2, got, test.want, ) } } } func TestScale(t *testing.T) { for _, test := range []struct { a float64 v Vec want Vec }{ {3, Vec{0, 0, 0}, Vec{0, 0, 0}}, {1, Vec{1, 0, 0}, Vec{1, 0, 0}}, {0, Vec{1, 0, 0}, Vec{0, 0, 0}}, {3, Vec{1, 0, 0}, Vec{3, 0, 0}}, {-1, Vec{1, -3, 5}, Vec{-1, 3, -5}}, {2, Vec{1, -3, 5}, Vec{2, -6, 10}}, {10, Vec{1, 2, 3}, Vec{10, 20, 30}}, } { got := Scale(test.a, test.v) if got != test.want { t.Errorf( "error: %v * %v: got=%v, want=%v", test.a, test.v, got, test.want) } } } func TestDot(t *testing.T) { for _, test := range []struct { u, v Vec want float64 }{ {Vec{1, 2, 3}, Vec{1, 2, 3}, 14}, {Vec{1, 0, 0}, Vec{1, 0, 0}, 1}, {Vec{1, 0, 0}, Vec{0, 1, 0}, 0}, {Vec{1, 0, 0}, Vec{0, 1, 1}, 0}, {Vec{1, 1, 1}, Vec{-1, -1, -1}, -3}, {Vec{1, 2, 2}, Vec{-0.3, 0.4, -1.2}, -1.9}, } { { got := Dot(test.u, test.v) if got != test.want { t.Errorf( "error: %v · %v: got=%v, want=%v", test.u, test.v, got, test.want, ) } } { got := Dot(test.v, test.u) if got != test.want { t.Errorf( "error: %v · %v: got=%v, want=%v", test.v, test.u, got, test.want, ) } } } } func TestCross(t *testing.T) { for _, test := range []struct { v1, v2, want Vec }{ {Vec{1, 0, 0}, Vec{1, 0, 0}, Vec{0, 0, 0}}, {Vec{1, 0, 0}, Vec{0, 1, 0}, Vec{0, 0, 1}}, {Vec{0, 1, 0}, Vec{1, 0, 0}, Vec{0, 0, -1}}, {Vec{1, 2, 3}, Vec{-4, 5, -6}, Vec{-27, -6, 13}}, {Vec{1, 2, 3}, Vec{1, 2, 3}, Vec{}}, {Vec{1, 2, 3}, Vec{2, 3, 4}, Vec{-1, 2, -1}}, } { got := Cross(test.v1, test.v2) if got != test.want { t.Errorf( "error: %v × %v = %v, want %v", test.v1, test.v2, got, test.want, ) } } } func TestNorm(t *testing.T) { for _, test := range []struct { v Vec want float64 }{ {Vec{0, 0, 0}, 0}, {Vec{0, 1, 0}, 1}, {Vec{3, -4, 12}, 13}, {Vec{1, 1e-16, 1e-32}, 1}, {Vec{-0, 4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 6.101625315155041e-196}, } { if got, want := Norm(test.v), test.want; got != want { t.Errorf("|%v| = %v, want %v", test.v, got, want) } } } func TestNorm2(t *testing.T) { for _, test := range []struct { v Vec want float64 }{ {Vec{0, 0, 0}, 0}, {Vec{0, 1, 0}, 1}, {Vec{1, 1, 1}, 3}, {Vec{1, 2, 3}, 14}, {Vec{3, -4, 12}, 169}, {Vec{1, 1e-16, 1e-32}, 1}, // This will underflow and return zero. {Vec{-0, 4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 0}, } { if got, want := Norm2(test.v), test.want; got != want { t.Errorf("|%v|^2 = %v, want %v", test.v, got, want) } } } func TestUnit(t *testing.T) { for _, test := range []struct { v, want Vec }{ {Vec{}, Vec{math.NaN(), math.NaN(), math.NaN()}}, {Vec{1, 0, 0}, Vec{1, 0, 0}}, {Vec{0, 1, 0}, Vec{0, 1, 0}}, {Vec{0, 0, 1}, Vec{0, 0, 1}}, {Vec{1, 1, 1}, Vec{1. / math.Sqrt(3), 1. / math.Sqrt(3), 1. / math.Sqrt(3)}}, {Vec{1, 1e-16, 1e-32}, Vec{1, 1e-16, 1e-32}}, } { got := Unit(test.v) if !vecEqual(got, test.want) { t.Errorf( "Normalize(%v) = %v, want %v", test.v, got, test.want, ) } if test.v == (Vec{}) { return } if n, want := Norm(got), 1.0; n != want { t.Errorf("|%v| = %v, want 1", got, n) } } } func TestCos(t *testing.T) { for _, test := range []struct { v1, v2 Vec want float64 }{ {Vec{1, 1, 1}, Vec{1, 1, 1}, 1}, {Vec{1, 1, 1}, Vec{-1, -1, -1}, -1}, {Vec{1, 1, 1}, Vec{1, -1, 1}, 1.0 / 3}, {Vec{1, 0, 0}, Vec{1, 0, 0}, 1}, {Vec{1, 0, 0}, Vec{0, 1, 0}, 0}, {Vec{1, 0, 0}, Vec{0, 1, 1}, 0}, {Vec{1, 0, 0}, Vec{-1, 0, 0}, -1}, } { tol := 1e-14 got := Cos(test.v1, test.v2) if !scalar.EqualWithinAbs(got, test.want, tol) { t.Errorf("cos(%v, %v)= %v, want %v", test.v1, test.v2, got, test.want, ) } } } func TestRotate(t *testing.T) { const tol = 1e-14 for _, test := range []struct { v, axis Vec alpha float64 want Vec }{ {Vec{1, 0, 0}, Vec{1, 0, 0}, math.Pi / 2, Vec{1, 0, 0}}, {Vec{1, 0, 0}, Vec{1, 0, 0}, 0, Vec{1, 0, 0}}, {Vec{1, 0, 0}, Vec{1, 0, 0}, 2 * math.Pi, Vec{1, 0, 0}}, {Vec{1, 0, 0}, Vec{0, 0, 0}, math.Pi / 2, Vec{math.NaN(), math.NaN(), math.NaN()}}, {Vec{1, 0, 0}, Vec{0, 1, 0}, math.Pi / 2, Vec{0, 0, -1}}, {Vec{1, 0, 0}, Vec{0, 1, 0}, math.Pi, Vec{-1, 0, 0}}, {Vec{2, 0, 0}, Vec{0, 1, 0}, math.Pi, Vec{-2, 0, 0}}, {Vec{1, 2, 3}, Vec{1, 1, 1}, 2. / 3. * math.Pi, Vec{3, 1, 2}}, } { got := Rotate(test.v, test.alpha, test.axis) if !vecApproxEqual(got, test.want, tol) { t.Errorf( "quat rotate(%v, %v, %v)= %v, want=%v", test.v, test.alpha, test.axis, got, test.want, ) } var gotv mat.VecDense gotv.MulVec(NewRotation(test.alpha, test.axis).Mat(), vecDense(test.v)) got = vec(gotv) if !vecApproxEqual(got, test.want, tol) { t.Errorf( "matrix rotate(%v, %v, %v)= %v, want=%v", test.v, test.alpha, test.axis, got, test.want, ) } } } var vectorFields = []struct { field func(Vec) Vec divergence func(Vec) float64 jacobian func(Vec) *Mat }{ { field: func(v Vec) Vec { // (x*y*z, y*z, z*x) return Vec{X: v.X * v.Y * v.Z, Y: v.Y * v.Z, Z: v.Z * v.X} }, divergence: func(v Vec) float64 { return v.X + v.Y*v.Z + v.Z }, jacobian: func(v Vec) *Mat { return NewMat([]float64{ v.Y * v.Z, v.X * v.Z, v.X * v.Y, 0, v.Z, v.Y, v.Z, 0, v.X, }) }, }, { field: func(v Vec) Vec { // (x*y*z*cos(y), y*z+sin(x), z*x*sin(y)) sx := math.Sin(v.X) sy, cy := math.Sincos(v.Y) return Vec{ X: v.X * v.Y * v.Z * cy, Y: v.Y*v.Z + sx, Z: v.Z * v.X * sy, } }, divergence: func(v Vec) float64 { sy, cy := math.Sincos(v.Y) return v.X*sy + v.Y*v.Z*cy + v.Z }, jacobian: func(v Vec) *Mat { cx := math.Cos(v.X) sy, cy := math.Sincos(v.Y) return NewMat([]float64{ v.Y * v.Z * cy, v.X*v.Z*cy - v.X*v.Y*v.Z*sy, v.X * v.Y * cy, cx, v.Z, v.Y, v.Z * sy, v.X * v.Z * cy, v.X * sy, }) }, }, } func TestDivergence(t *testing.T) { const ( tol = 1e-10 h = 1e-2 ) step := Vec{X: h, Y: h, Z: h} rnd := rand.New(rand.NewSource(1)) for _, test := range vectorFields { for i := 0; i < 30; i++ { p := randomVec(rnd) got := Divergence(p, step, test.field) want := test.divergence(p) if math.Abs(got-want) > tol { t.Errorf("result out of tolerance. got %v, want %v", got, want) } } } } func TestGradient(t *testing.T) { const ( tol = 1e-6 h = 1e-5 ) step := Vec{X: h, Y: h, Z: h} rnd := rand.New(rand.NewSource(1)) for _, test := range scalarFields { for i := 0; i < 30; i++ { p := randomVec(rnd) got := Gradient(p, step, test.field) want := test.gradient(p) if !vecApproxEqual(got, want, tol) { t.Errorf("result out of tolerance. got %v, want %v", got, want) } } } } func vecDense(v Vec) *mat.VecDense { return mat.NewVecDense(3, []float64{v.X, v.Y, v.Z}) } func vec(v mat.VecDense) Vec { if v.Len() != 3 { panic(mat.ErrShape) } return Vec{v.AtVec(0), v.AtVec(1), v.AtVec(2)} } func vecIsNaN(v Vec) bool { return math.IsNaN(v.X) && math.IsNaN(v.Y) && math.IsNaN(v.Z) } func vecIsNaNAny(v Vec) bool { return math.IsNaN(v.X) || math.IsNaN(v.Y) || math.IsNaN(v.Z) } func vecEqual(a, b Vec) bool { if vecIsNaNAny(a) || vecIsNaNAny(b) { return vecIsNaN(a) && vecIsNaN(b) } return a == b } func vecApproxEqual(a, b Vec, tol float64) bool { if vecIsNaNAny(a) || vecIsNaNAny(b) { return vecIsNaN(a) && vecIsNaN(b) } return scalar.EqualWithinAbs(a.X, b.X, tol) && scalar.EqualWithinAbs(a.Y, b.Y, tol) && scalar.EqualWithinAbs(a.Z, b.Z, tol) } golang-gonum-v1-gonum-0.14.0/spatial/vptree/000077500000000000000000000000001450372207100206005ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/spatial/vptree/doc.go000066400000000000000000000007021450372207100216730ustar00rootroot00000000000000// Copyright ©2019 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 vptree implements a vantage point tree. Vantage point // trees provide an efficient search for nearest neighbors in a // metric space. // // See http://pnylab.com/papers/vptree/vptree.pdf for details of vp-trees. package vptree // import "gonum.org/v1/gonum/spatial/vptree" golang-gonum-v1-gonum-0.14.0/spatial/vptree/vptree.go000066400000000000000000000254171450372207100224450ustar00rootroot00000000000000// Copyright ©2019 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 vptree import ( "container/heap" "errors" "math" "sort" "golang.org/x/exp/rand" "gonum.org/v1/gonum/stat" ) // Comparable is the element interface for values stored in a vp-tree. type Comparable interface { // Distance returns the distance between the receiver and the // parameter. The returned distance must satisfy the properties // of distances in a metric space. // // - a.Distance(a) == 0 // - a.Distance(b) >= 0 // - a.Distance(b) == b.Distance(a) // - a.Distance(b) <= a.Distance(c)+c.Distance(b) // Distance(Comparable) float64 } // Point represents a point in a Euclidean k-d space that satisfies the Comparable // interface. type Point []float64 // Distance returns the Euclidean distance between c and the receiver. The concrete // type of c must be Point. func (p Point) Distance(c Comparable) float64 { q := c.(Point) var sum float64 for dim, c := range p { d := c - q[dim] sum += d * d } return math.Sqrt(sum) } // Node holds a single point value in a vantage point tree. type Node struct { Point Comparable Radius float64 Closer *Node Further *Node } // Tree implements a vantage point tree creation and nearest neighbor search. type Tree struct { Root *Node Count int } // New returns a vantage point tree constructed from the values in p. The effort // parameter specifies how much work should be put into optimizing the choice of // vantage point. If effort is one or less, random vantage points are chosen. // The order of elements in p will be altered after New returns. The src parameter // provides the source of randomness for vantage point selection. If src is nil // global rand package functions are used. Points in p must not be infinitely // distant. func New(p []Comparable, effort int, src rand.Source) (t *Tree, err error) { var intn func(int) int var shuf func(n int, swap func(i, j int)) if src == nil { intn = rand.Intn shuf = rand.Shuffle } else { rnd := rand.New(src) intn = rnd.Intn shuf = rnd.Shuffle } b := builder{work: make([]float64, len(p)), intn: intn, shuf: shuf} defer func() { switch r := recover(); r { case nil: case pointAtInfinity: t = nil err = pointAtInfinity default: panic(r) } }() t = &Tree{ Root: b.build(p, effort), Count: len(p), } return t, nil } var pointAtInfinity = errors.New("vptree: point at infinity") // builder performs vp-tree construction as described for the simple vp-tree // algorithm in http://pnylab.com/papers/vptree/vptree.pdf. type builder struct { work []float64 intn func(n int) int shuf func(n int, swap func(i, j int)) } func (b *builder) build(s []Comparable, effort int) *Node { if len(s) <= 1 { if len(s) == 0 { return nil } return &Node{Point: s[0]} } n := Node{Point: b.selectVantage(s, effort)} radius, closer, further := b.partition(n.Point, s) n.Radius = radius n.Closer = b.build(closer, effort) n.Further = b.build(further, effort) return &n } func (b *builder) selectVantage(s []Comparable, effort int) Comparable { if effort <= 1 { return s[b.intn(len(s))] } if effort > len(s) { effort = len(s) } var best Comparable bestVar := -1.0 b.work = b.work[:effort] choices := b.random(effort, s) for _, p := range choices { for i, q := range choices { d := p.Distance(q) if math.IsInf(d, 0) { panic(pointAtInfinity) } b.work[i] = d } variance := stat.Variance(b.work, nil) if variance > bestVar { best, bestVar = p, variance } } if best == nil { // This should never be reached. panic("vptree: could not find vantage point") } return best } func (b *builder) random(n int, s []Comparable) []Comparable { if n >= len(s) { n = len(s) } b.shuf(len(s), func(i, j int) { s[i], s[j] = s[j], s[i] }) return s[:n] } func (b *builder) partition(v Comparable, s []Comparable) (radius float64, closer, further []Comparable) { b.work = b.work[:len(s)] for i, p := range s { d := v.Distance(p) if math.IsInf(d, 0) { panic(pointAtInfinity) } b.work[i] = d } sort.Sort(byDist{dists: b.work, points: s}) // Note that this does not conform exactly to the description // in the paper which specifies d(p, s) < mu for L; in cases // where the median element has a lower indexed element with // the same distance from the vantage point, L will include a // d(p, s) == mu. // The additional work required to satisfy the algorithm is // not worth doing as it has no effect on the correctness or // performance of the algorithm. radius = b.work[len(b.work)/2] if len(b.work) > 1 { // Remove vantage if it is present. closer = s[1 : len(b.work)/2] } further = s[len(b.work)/2:] return radius, closer, further } type byDist struct { dists []float64 points []Comparable } func (c byDist) Len() int { return len(c.dists) } func (c byDist) Less(i, j int) bool { return c.dists[i] < c.dists[j] } func (c byDist) Swap(i, j int) { c.dists[i], c.dists[j] = c.dists[j], c.dists[i] c.points[i], c.points[j] = c.points[j], c.points[i] } // Len returns the number of elements in the tree. func (t *Tree) Len() int { return t.Count } var inf = math.Inf(1) // Nearest returns the nearest value to the query and the distance between them. func (t *Tree) Nearest(q Comparable) (Comparable, float64) { if t.Root == nil { return nil, inf } n, dist := t.Root.search(q, inf) if n == nil { return nil, inf } return n.Point, dist } func (n *Node) search(q Comparable, dist float64) (*Node, float64) { if n == nil { return nil, inf } d := q.Distance(n.Point) dist = math.Min(dist, d) bn := n if d < n.Radius { cn, cd := n.Closer.search(q, dist) if cd < dist { bn, dist = cn, cd } if d+dist >= n.Radius { fn, fd := n.Further.search(q, dist) if fd < dist { bn, dist = fn, fd } } } else { fn, fd := n.Further.search(q, dist) if fd < dist { bn, dist = fn, fd } if d-dist <= n.Radius { cn, cd := n.Closer.search(q, dist) if cd < dist { bn, dist = cn, cd } } } return bn, dist } // ComparableDist holds a Comparable and a distance to a specific query. A nil Comparable // is used to mark the end of the heap, so clients should not store nil values except for // this purpose. type ComparableDist struct { Comparable Comparable Dist float64 } // Heap is a max heap sorted on Dist. type Heap []ComparableDist func (h *Heap) Max() ComparableDist { return (*h)[0] } func (h *Heap) Len() int { return len(*h) } func (h *Heap) Less(i, j int) bool { return (*h)[i].Comparable == nil || (*h)[i].Dist > (*h)[j].Dist } func (h *Heap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } func (h *Heap) Push(x interface{}) { (*h) = append(*h, x.(ComparableDist)) } func (h *Heap) Pop() (i interface{}) { i, *h = (*h)[len(*h)-1], (*h)[:len(*h)-1]; return i } // NKeeper is a Keeper that retains the n best ComparableDists that have been passed to Keep. type NKeeper struct { Heap } // NewNKeeper returns an NKeeper with the max value of the heap set to infinite distance. The // returned NKeeper is able to retain at most n values. func NewNKeeper(n int) *NKeeper { k := NKeeper{make(Heap, 1, n)} k.Heap[0].Dist = inf return &k } // Keep adds c to the heap if its distance is less than the maximum value of the heap. If adding // c would increase the size of the heap beyond the initial maximum length, the maximum value of // the heap is dropped. func (k *NKeeper) Keep(c ComparableDist) { if c.Dist <= k.Heap[0].Dist { // Favour later finds to displace sentinel. if len(k.Heap) == cap(k.Heap) { heap.Pop(k) } heap.Push(k, c) } } // DistKeeper is a Keeper that retains the ComparableDists within the specified distance of the // query that it is called to Keep. type DistKeeper struct { Heap } // NewDistKeeper returns an DistKeeper with the maximum value of the heap set to d. func NewDistKeeper(d float64) *DistKeeper { return &DistKeeper{Heap{{Dist: d}}} } // Keep adds c to the heap if its distance is less than or equal to the max value of the heap. func (k *DistKeeper) Keep(c ComparableDist) { if c.Dist <= k.Heap[0].Dist { heap.Push(k, c) } } // Keeper implements a conditional max heap sorted on the Dist field of the ComparableDist type. // vantage point search is guided by the distance stored in the max value of the heap. type Keeper interface { Keep(ComparableDist) // Keep conditionally pushes the provided ComparableDist onto the heap. Max() ComparableDist // Max returns the maximum element of the Keeper. heap.Interface } // NearestSet finds the nearest values to the query accepted by the provided Keeper, k. // k must be able to return a ComparableDist specifying the maximum acceptable distance // when Max() is called, and retains the results of the search in min sorted order after // the call to NearestSet returns. // If a sentinel ComparableDist with a nil Comparable is used by the Keeper to mark the // maximum distance, NearestSet will remove it before returning. func (t *Tree) NearestSet(k Keeper, q Comparable) { if t.Root == nil { return } t.Root.searchSet(q, k) // Check whether we have retained a sentinel // and flag removal if we have. removeSentinel := k.Len() != 0 && k.Max().Comparable == nil sort.Sort(sort.Reverse(k)) // This abuses the interface to drop the max. // It is reasonable to do this because we know // that the maximum value will now be at element // zero, which is removed by the Pop method. if removeSentinel { k.Pop() } } func (n *Node) searchSet(q Comparable, k Keeper) { if n == nil { return } k.Keep(ComparableDist{Comparable: n.Point, Dist: q.Distance(n.Point)}) d := q.Distance(n.Point) if d < n.Radius { n.Closer.searchSet(q, k) if d+k.Max().Dist >= n.Radius { n.Further.searchSet(q, k) } } else { n.Further.searchSet(q, k) if d-k.Max().Dist <= n.Radius { n.Closer.searchSet(q, k) } } } // Operation is a function that operates on a Comparable. The bounding volume and tree depth // of the point is also provided. If done is returned true, the Operation is indicating that no // further work needs to be done and so the Do function should traverse no further. type Operation func(Comparable, int) (done bool) // Do performs fn on all values stored in the tree. A boolean is returned indicating whether the // Do traversal was interrupted by an Operation returning true. If fn alters stored values' sort // relationships, future tree operation behaviors are undefined. func (t *Tree) Do(fn Operation) bool { if t.Root == nil { return false } return t.Root.do(fn, 0) } func (n *Node) do(fn Operation, depth int) (done bool) { if n.Closer != nil { done = n.Closer.do(fn, depth+1) if done { return } } done = fn(n.Point, depth) if done { return } if n.Further != nil { done = n.Further.do(fn, depth+1) } return } golang-gonum-v1-gonum-0.14.0/spatial/vptree/vptree_simple_example_test.go000066400000000000000000000027201450372207100265600ustar00rootroot00000000000000// Copyright ©2019 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 vptree_test import ( "fmt" "log" "gonum.org/v1/gonum/spatial/vptree" ) func ExampleTree() { // Example data from https://en.wikipedia.org/wiki/K-d_tree points := []vptree.Comparable{ vptree.Point{2, 3}, vptree.Point{5, 4}, vptree.Point{9, 6}, vptree.Point{4, 7}, vptree.Point{8, 1}, vptree.Point{7, 2}, } t, err := vptree.New(points, 3, nil) if err != nil { log.Fatal(err) } q := vptree.Point{8, 7} p, d := t.Nearest(q) fmt.Printf("%v is closest point to %v, d=%f\n", p, q, d) // Output: // [9 6] is closest point to [8 7], d=1.414214 } func ExampleTree_Do() { // Example data from https://en.wikipedia.org/wiki/K-d_tree points := []vptree.Comparable{ vptree.Point{2, 3}, vptree.Point{5, 4}, vptree.Point{9, 6}, vptree.Point{4, 7}, vptree.Point{8, 1}, vptree.Point{7, 2}, } // Print all points in the data set within 3 of (3, 5). t, err := vptree.New(points, 0, nil) if err != nil { log.Fatal(err) } q := vptree.Point{3, 5} t.Do(func(c vptree.Comparable, _ int) (done bool) { // Compare each distance and output points // with a Euclidean distance less than or // equal to 3. Distance returns the // Euclidean distance between points. if q.Distance(c) <= 3 { fmt.Println(c) } return }) // Unordered output: // [2 3] // [4 7] // [5 4] } golang-gonum-v1-gonum-0.14.0/spatial/vptree/vptree_test.go000066400000000000000000000322051450372207100234750ustar00rootroot00000000000000// Copyright ©2019 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 vptree import ( "flag" "fmt" "math" "os" "reflect" "sort" "strings" "testing" "unsafe" "golang.org/x/exp/rand" ) var ( genDot = flag.Bool("dot", false, "generate dot code for failing trees") dotLimit = flag.Int("dotmax", 100, "specify maximum size for tree output for dot format") ) var ( // Using example from WP article: https://en.wikipedia.org/w/index.php?title=K-d_tree&oldid=887573572. wpData = []Comparable{ Point{2, 3}, Point{5, 4}, Point{9, 6}, Point{4, 7}, Point{8, 1}, Point{7, 2}, } ) var newTests = []struct { data []Comparable effort int seed uint64 }{ {data: wpData, effort: 0, seed: 1}, {data: wpData, effort: 1, seed: 1}, {data: wpData, effort: 2, seed: 1}, {data: wpData, effort: 4, seed: 1}, {data: wpData, effort: 8, seed: 1}, {data: []Comparable{Point{2, 3}, Point{5, 4}, Point{9, 6}, Point{5, 4}, Point{8, 1}, Point{7, 2}}, effort: 3, seed: 5555}, } func TestNew(t *testing.T) { for i, test := range newTests { var tree *Tree var err error var panicked bool func() { defer func() { if r := recover(); r != nil { panicked = true } }() tree, err = New(test.data, test.effort, rand.NewSource(test.seed)) }() if panicked { t.Errorf("unexpected panic for test %d", i) continue } if err != nil { t.Errorf("unexpected error for test %d: %v", i, err) continue } if !tree.Root.isVPTree() { t.Errorf("tree %d is not vp-tree", i) } if t.Failed() && *genDot && tree.Len() <= *dotLimit { err := dotFile(tree, fmt.Sprintf("TestNew%d", i), "") if err != nil { t.Fatalf("failed to write DOT file: %v", err) } } } } type compFn func(v, radius float64) bool func closer(v, radius float64) bool { return v <= radius } func further(v, radius float64) bool { return v >= radius } func (n *Node) isVPTree() bool { if n == nil { return true } if !n.Closer.isPartitioned(n.Point, closer, n.Radius) { return false } if !n.Further.isPartitioned(n.Point, further, n.Radius) { return false } return n.Closer.isVPTree() && n.Further.isVPTree() } func (n *Node) isPartitioned(vp Comparable, fn compFn, radius float64) bool { if n == nil { return true } if n.Closer != nil && !fn(vp.Distance(n.Closer.Point), radius) { return false } if n.Further != nil && !fn(vp.Distance(n.Further.Point), radius) { return false } return n.Closer.isPartitioned(vp, fn, radius) && n.Further.isPartitioned(vp, fn, radius) } func nearest(q Comparable, p []Comparable) (Comparable, float64) { min := q.Distance(p[0]) var r int for i := 1; i < len(p); i++ { d := q.Distance(p[i]) if d < min { min = d r = i } } return p[r], min } func TestNearestRandom(t *testing.T) { rnd := rand.New(rand.NewSource(1)) const ( min = 0.0 max = 1000.0 dims = 4 setSize = 10000 ) var randData []Comparable for i := 0; i < setSize; i++ { p := make(Point, dims) for j := 0; j < dims; j++ { p[j] = (max-min)*rnd.Float64() + min } randData = append(randData, p) } tree, err := New(randData, 10, rand.NewSource(1)) if err != nil { t.Fatalf("unexpected error: %v", err) } for i := 0; i < setSize; i++ { q := make(Point, dims) for j := 0; j < dims; j++ { q[j] = (max-min)*rnd.Float64() + min } got, _ := tree.Nearest(q) want, _ := nearest(q, randData) if !reflect.DeepEqual(got, want) { t.Fatalf("unexpected result from query %d %.3f: got:%.3f want:%.3f", i, q, got, want) } } } func TestNearest(t *testing.T) { tree, err := New(wpData, 3, rand.NewSource(1)) if err != nil { t.Fatalf("unexpected error: %v", err) } for _, q := range append([]Comparable{ Point{4, 6}, // Point{7, 5}, // Omitted because it is ambiguously finds [9 6] or [5 4]. Point{8, 7}, Point{6, -5}, Point{1e5, 1e5}, Point{1e5, -1e5}, Point{-1e5, 1e5}, Point{-1e5, -1e5}, Point{1e5, 0}, Point{0, -1e5}, Point{0, 1e5}, Point{-1e5, 0}, }, wpData...) { gotP, gotD := tree.Nearest(q) wantP, wantD := nearest(q, wpData) if !reflect.DeepEqual(gotP, wantP) { t.Errorf("unexpected result for query %.3f: got:%.3f want:%.3f", q, gotP, wantP) } if gotD != wantD { t.Errorf("unexpected distance for query %.3f : got:%v want:%v", q, gotD, wantD) } } } func nearestN(n int, q Comparable, p []Comparable) []ComparableDist { nk := NewNKeeper(n) for i := 0; i < len(p); i++ { nk.Keep(ComparableDist{Comparable: p[i], Dist: q.Distance(p[i])}) } if len(nk.Heap) == 1 { return nk.Heap } sort.Sort(nk) for i, j := 0, len(nk.Heap)-1; i < j; i, j = i+1, j-1 { nk.Heap[i], nk.Heap[j] = nk.Heap[j], nk.Heap[i] } return nk.Heap } func TestNearestSetN(t *testing.T) { data := append([]Comparable{ Point{4, 6}, Point{7, 5}, // OK here because we collect N. Point{8, 7}, Point{6, -5}, Point{1e5, 1e5}, Point{1e5, -1e5}, Point{-1e5, 1e5}, Point{-1e5, -1e5}, Point{1e5, 0}, Point{0, -1e5}, Point{0, 1e5}, Point{-1e5, 0}}, wpData[:len(wpData)-1]...) tree, err := New(wpData, 3, rand.NewSource(1)) if err != nil { t.Fatalf("unexpected error: %v", err) } for k := 1; k <= len(wpData); k++ { for _, q := range data { wantP := nearestN(k, q, wpData) nk := NewNKeeper(k) tree.NearestSet(nk, q) var max float64 wantD := make(map[float64]map[string]struct{}) for _, p := range wantP { if p.Dist > max { max = p.Dist } d, ok := wantD[p.Dist] if !ok { d = make(map[string]struct{}) } d[fmt.Sprint(p.Comparable)] = struct{}{} wantD[p.Dist] = d } gotD := make(map[float64]map[string]struct{}) for _, p := range nk.Heap { if p.Dist > max { t.Errorf("unexpected distance for point %.3f: got:%v want:<=%v", p.Comparable, p.Dist, max) } d, ok := gotD[p.Dist] if !ok { d = make(map[string]struct{}) } d[fmt.Sprint(p.Comparable)] = struct{}{} gotD[p.Dist] = d } // If the available number of slots does not fit all the coequal furthest points // we will fail the check. So remove, but check them minimally here. if !reflect.DeepEqual(wantD[max], gotD[max]) { // The best we can do at this stage is confirm that there are an equal number of matches at this distance. if len(gotD[max]) != len(wantD[max]) { t.Errorf("unexpected number of maximal distance points: got:%d want:%d", len(gotD[max]), len(wantD[max])) } delete(wantD, max) delete(gotD, max) } if !reflect.DeepEqual(gotD, wantD) { t.Errorf("unexpected result for k=%d query %.3f: got:%v want:%v", k, q, gotD, wantD) } } } } var nearestSetDistTests = []Point{ {4, 6}, {7, 5}, {8, 7}, {6, -5}, } func TestNearestSetDist(t *testing.T) { tree, err := New(wpData, 3, rand.NewSource(1)) if err != nil { t.Fatalf("unexpected error: %v", err) } for i, q := range nearestSetDistTests { for d := 1.0; d < 100; d += 0.1 { dk := NewDistKeeper(d) tree.NearestSet(dk, q) hits := make(map[string]float64) for _, p := range wpData { hits[fmt.Sprint(p)] = p.Distance(q) } for _, p := range dk.Heap { var done bool if p.Comparable == nil { done = true continue } delete(hits, fmt.Sprint(p.Comparable)) if done { t.Error("expectedly finished heap iteration") break } dist := p.Comparable.Distance(q) if dist > d { t.Errorf("Test %d: query %v found %v expect %.3f <= %.3f", i, q, p, dist, d) } } for p, dist := range hits { if dist <= d { t.Errorf("Test %d: query %v missed %v expect %.3f > %.3f", i, q, p, dist, d) } } } } } func TestDo(t *testing.T) { tree, err := New(wpData, 3, rand.NewSource(1)) if err != nil { t.Fatalf("unexpected error: %v", err) } var got []Point fn := func(c Comparable, _ int) (done bool) { got = append(got, c.(Point)) return } killed := tree.Do(fn) want := make([]Point, len(wpData)) for i, p := range wpData { want[i] = p.(Point) } sort.Sort(lexical(got)) sort.Sort(lexical(want)) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected result from tree iteration: got:%v want:%v", got, want) } if killed { t.Error("tree iteration unexpectedly killed") } } type lexical []Point func (c lexical) Len() int { return len(c) } func (c lexical) 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 lexical) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func BenchmarkNew(b *testing.B) { for _, effort := range []int{0, 10, 100} { b.Run(fmt.Sprintf("New:%d", effort), func(b *testing.B) { rnd := rand.New(rand.NewSource(1)) p := make([]Comparable, 1e5) for i := range p { p[i] = Point{rnd.Float64(), rnd.Float64(), rnd.Float64()} } b.ResetTimer() for i := 0; i < b.N; i++ { _, err := New(p, effort, rand.NewSource(1)) if err != nil { b.Fatalf("unexpected error: %v", err) } } }) } } func Benchmark(b *testing.B) { var r Comparable var d float64 queryBenchmarks := []struct { name string fn func(data []Comparable, tree *Tree, rnd *rand.Rand) func(*testing.B) }{ { name: "NearestBrute", fn: func(data []Comparable, _ *Tree, rnd *rand.Rand) func(b *testing.B) { return func(b *testing.B) { for i := 0; i < b.N; i++ { r, d = nearest(Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}, data) } if r == nil { b.Error("unexpected nil result") } if math.IsNaN(d) { b.Error("unexpected NaN result") } } }, }, { name: "NearestBruteN10", fn: func(data []Comparable, _ *Tree, rnd *rand.Rand) func(b *testing.B) { return func(b *testing.B) { var r []ComparableDist for i := 0; i < b.N; i++ { r = nearestN(10, Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}, data) } if len(r) != 10 { b.Error("unexpected result length", len(r)) } } }, }, { name: "Nearest", fn: func(_ []Comparable, tree *Tree, rnd *rand.Rand) func(b *testing.B) { return func(b *testing.B) { for i := 0; i < b.N; i++ { r, d = tree.Nearest(Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}) } if r == nil { b.Error("unexpected nil result") } if math.IsNaN(d) { b.Error("unexpected NaN result") } } }, }, { name: "NearestSetN10", fn: func(_ []Comparable, tree *Tree, rnd *rand.Rand) func(b *testing.B) { return func(b *testing.B) { nk := NewNKeeper(10) for i := 0; i < b.N; i++ { tree.NearestSet(nk, Point{rnd.Float64(), rnd.Float64(), rnd.Float64()}) if nk.Len() != 10 { b.Error("unexpected result length") } nk.Heap = nk.Heap[:1] nk.Heap[0] = ComparableDist{Dist: inf} } } }, }, } for _, effort := range []int{0, 3, 10, 30, 100, 300} { rnd := rand.New(rand.NewSource(1)) data := make([]Comparable, 1e5) for i := range data { data[i] = Point{rnd.Float64(), rnd.Float64(), rnd.Float64()} } tree, err := New(data, effort, rand.NewSource(1)) if err != nil { b.Errorf("unexpected error for effort=%d: %v", effort, err) continue } if !tree.Root.isVPTree() { b.Fatal("tree is not vantage point tree") } for i := 0; i < 1e3; i++ { q := Point{rnd.Float64(), rnd.Float64(), rnd.Float64()} gotP, gotD := tree.Nearest(q) wantP, wantD := nearest(q, data) if !reflect.DeepEqual(gotP, wantP) { b.Errorf("unexpected result for query %.3f: got:%.3f want:%.3f", q, gotP, wantP) } if gotD != wantD { b.Errorf("unexpected distance for query %.3f: got:%v want:%v", q, gotD, wantD) } } if b.Failed() && *genDot && tree.Len() <= *dotLimit { err := dotFile(tree, "TestBenches", "") if err != nil { b.Fatalf("failed to write DOT file: %v", err) } return } for _, bench := range queryBenchmarks { if strings.Contains(bench.name, "Brute") && effort != 0 { continue } b.Run(fmt.Sprintf("%s:%d", bench.name, effort), bench.fn(data, tree, rnd)) } } } func dot(t *Tree, label string) string { if t == nil { return "" } var ( s []string follow func(*Node) ) follow = func(n *Node) { id := uintptr(unsafe.Pointer(n)) c := fmt.Sprintf("%d[label = \" | %.3f/%.3f|\"];", id, n.Point, n.Radius) if n.Closer != nil { c += fmt.Sprintf("\n\t\tedge [arrowhead=normal]; \"%d\":Closer -> \"%d\":Elem [label=%.3f];", id, uintptr(unsafe.Pointer(n.Closer)), n.Point.Distance(n.Closer.Point)) follow(n.Closer) } if n.Further != nil { c += fmt.Sprintf("\n\t\tedge [arrowhead=normal]; \"%d\":Further -> \"%d\":Elem [label=%.3f];", id, uintptr(unsafe.Pointer(n.Further)), n.Point.Distance(n.Further.Point)) follow(n.Further) } s = append(s, c) } if t.Root != nil { follow(t.Root) } return fmt.Sprintf("digraph %s {\n\tnode [shape=record,height=0.1];\n\t%s\n}\n", label, strings.Join(s, "\n\t"), ) } func dotFile(t *Tree, label, dotString string) (err error) { if t == nil && dotString == "" { return } f, err := os.Create(label + ".dot") if err != nil { return } defer f.Close() if dotString == "" { fmt.Fprint(f, dot(t, label)) } else { fmt.Fprint(f, dotString) } return } golang-gonum-v1-gonum-0.14.0/spatial/vptree/vptree_user_type_example_test.go000066400000000000000000000066711450372207100273170ustar00rootroot00000000000000// Copyright ©2019 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 vptree_test import ( "fmt" "log" "math" "gonum.org/v1/gonum/spatial/vptree" ) func Example_accessiblePublicTransport() { // Construct a vp tree of train station locations // to identify accessible public transport for the // elderly. t, err := vptree.New(stations, 5, nil) if err != nil { log.Fatal(err) } // Residence. q := place{lat: 51.501476, lon: -0.140634} var keep vptree.Keeper // Find all stations within 0.75 of the residence. keep = vptree.NewDistKeeper(0.75) t.NearestSet(keep, q) fmt.Println(`Stations within 750 m of 51.501476N 0.140634W.`) for _, c := range keep.(*vptree.DistKeeper).Heap { p := c.Comparable.(place) fmt.Printf("%s: %0.3f km\n", p.name, p.Distance(q)) } fmt.Println() // Find the five closest stations to the residence. keep = vptree.NewNKeeper(5) t.NearestSet(keep, q) fmt.Println(`5 closest stations to 51.501476N 0.140634W.`) for _, c := range keep.(*vptree.NKeeper).Heap { p := c.Comparable.(place) fmt.Printf("%s: %0.3f km\n", p.name, p.Distance(q)) } // Output: // // Stations within 750 m of 51.501476N 0.140634W. // St. James's Park: 0.545 km // Green Park: 0.600 km // Victoria: 0.621 km // // 5 closest stations to 51.501476N 0.140634W. // St. James's Park: 0.545 km // Green Park: 0.600 km // Victoria: 0.621 km // Hyde Park Corner: 0.846 km // Picadilly Circus: 1.027 km } // stations is a list of railways stations. var stations = []vptree.Comparable{ place{name: "Bond Street", lat: 51.5142, lon: -0.1494}, place{name: "Charing Cross", lat: 51.508, lon: -0.1247}, place{name: "Covent Garden", lat: 51.5129, lon: -0.1243}, place{name: "Embankment", lat: 51.5074, lon: -0.1223}, place{name: "Green Park", lat: 51.5067, lon: -0.1428}, place{name: "Hyde Park Corner", lat: 51.5027, lon: -0.1527}, place{name: "Leicester Square", lat: 51.5113, lon: -0.1281}, place{name: "Marble Arch", lat: 51.5136, lon: -0.1586}, place{name: "Oxford Circus", lat: 51.515, lon: -0.1415}, place{name: "Picadilly Circus", lat: 51.5098, lon: -0.1342}, place{name: "Pimlico", lat: 51.4893, lon: -0.1334}, place{name: "Sloane Square", lat: 51.4924, lon: -0.1565}, place{name: "South Kensington", lat: 51.4941, lon: -0.1738}, place{name: "St. James's Park", lat: 51.4994, lon: -0.1335}, place{name: "Temple", lat: 51.5111, lon: -0.1141}, place{name: "Tottenham Court Road", lat: 51.5165, lon: -0.131}, place{name: "Vauxhall", lat: 51.4861, lon: -0.1253}, place{name: "Victoria", lat: 51.4965, lon: -0.1447}, place{name: "Waterloo", lat: 51.5036, lon: -0.1143}, place{name: "Westminster", lat: 51.501, lon: -0.1254}, } // place is a vptree.Comparable implementations. type place struct { name string lat, lon float64 } // Distance returns the distance between the receiver and c. func (p place) Distance(c vptree.Comparable) float64 { q := c.(place) return haversine(p.lat, p.lon, q.lat, q.lon) } // haversine returns the distance between two geographic coordinates. func haversine(lat1, lon1, lat2, lon2 float64) float64 { const r = 6371 // km sdLat := math.Sin(radians(lat2-lat1) / 2) sdLon := math.Sin(radians(lon2-lon1) / 2) a := sdLat*sdLat + math.Cos(radians(lat1))*math.Cos(radians(lat2))*sdLon*sdLon d := 2 * r * math.Asin(math.Sqrt(a)) return d // km } func radians(d float64) float64 { return d * math.Pi / 180 } golang-gonum-v1-gonum-0.14.0/stat/000077500000000000000000000000001450372207100166115ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/README.md000066400000000000000000000004511450372207100200700ustar00rootroot00000000000000# Gonum stat [![go.dev reference](https://pkg.go.dev/badge/gonum.org/v1/gonum/stat)](https://pkg.go.dev/gonum.org/v1/gonum/stat) [![GoDoc](https://godocs.io/gonum.org/v1/gonum/stat?status.svg)](https://godocs.io/gonum.org/v1/gonum/stat) Package stat is a statistics package for the Go language. golang-gonum-v1-gonum-0.14.0/stat/boston_data_test.go000066400000000000000000001542611450372207100225050ustar00rootroot00000000000000// Copyright ©2016 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 stat_test import "gonum.org/v1/gonum/mat" // Boston Housing Data of Harrison and Rubinfeld (1978) // http://dx.doi.org/10.1016/0095-0696(78)90006-2 // http://lib.stat.cmu.edu/datasets/boston // Columns are; // // per capita crime rate by town, // proportion of non-retail business acres per town, // nitric oxide concentration (parts per 10 million), // weighted distances to Boston employment centers, // index of accessibility to radial highways, // pupil-teacher ratio by town, // proportion of blacks by town, // average number of rooms per dwelling, // proportion of owner-occupied units built prior to 1940, // full-value property-tax rate per $10000, // median value of owner-occupied homes in $1000s. var bostonData = mat.NewDense(506, 11, []float64{ 0.00632, 2.31000, 0.53800, 4.09000, 1.00000, 15.30000, 396.90000, 6.57500, 65.20000, 296.00000, 24.00000, 0.02731, 7.07000, 0.46900, 4.96710, 2.00000, 17.80000, 396.90000, 6.42100, 78.90000, 242.00000, 21.60000, 0.02729, 7.07000, 0.46900, 4.96710, 2.00000, 17.80000, 392.83000, 7.18500, 61.10000, 242.00000, 34.70000, 0.03237, 2.18000, 0.45800, 6.06220, 3.00000, 18.70000, 394.63000, 6.99800, 45.80000, 222.00000, 33.40000, 0.06905, 2.18000, 0.45800, 6.06220, 3.00000, 18.70000, 396.90000, 7.14700, 54.20000, 222.00000, 36.20000, 0.02985, 2.18000, 0.45800, 6.06220, 3.00000, 18.70000, 394.12000, 6.43000, 58.70000, 222.00000, 28.70000, 0.08829, 7.87000, 0.52400, 5.56050, 5.00000, 15.20000, 395.60000, 6.01200, 66.60000, 311.00000, 22.90000, 0.14455, 7.87000, 0.52400, 5.95050, 5.00000, 15.20000, 396.90000, 6.17200, 96.10000, 311.00000, 27.10000, 0.21124, 7.87000, 0.52400, 6.08210, 5.00000, 15.20000, 386.63000, 5.63100, 100.00000, 311.00000, 16.50000, 0.17004, 7.87000, 0.52400, 6.59210, 5.00000, 15.20000, 386.71000, 6.00400, 85.90000, 311.00000, 18.90000, 0.22489, 7.87000, 0.52400, 6.34670, 5.00000, 15.20000, 392.52000, 6.37700, 94.30000, 311.00000, 15.00000, 0.11747, 7.87000, 0.52400, 6.22670, 5.00000, 15.20000, 396.90000, 6.00900, 82.90000, 311.00000, 18.90000, 0.09378, 7.87000, 0.52400, 5.45090, 5.00000, 15.20000, 390.50000, 5.88900, 39.00000, 311.00000, 21.70000, 0.62976, 8.14000, 0.53800, 4.70750, 4.00000, 21.00000, 396.90000, 5.94900, 61.80000, 307.00000, 20.40000, 0.63796, 8.14000, 0.53800, 4.46190, 4.00000, 21.00000, 380.02000, 6.09600, 84.50000, 307.00000, 18.20000, 0.62739, 8.14000, 0.53800, 4.49860, 4.00000, 21.00000, 395.62000, 5.83400, 56.50000, 307.00000, 19.90000, 1.05393, 8.14000, 0.53800, 4.49860, 4.00000, 21.00000, 386.85000, 5.93500, 29.30000, 307.00000, 23.10000, 0.78420, 8.14000, 0.53800, 4.25790, 4.00000, 21.00000, 386.75000, 5.99000, 81.70000, 307.00000, 17.50000, 0.80271, 8.14000, 0.53800, 3.79650, 4.00000, 21.00000, 288.99000, 5.45600, 36.60000, 307.00000, 20.20000, 0.72580, 8.14000, 0.53800, 3.79650, 4.00000, 21.00000, 390.95000, 5.72700, 69.50000, 307.00000, 18.20000, 1.25179, 8.14000, 0.53800, 3.79790, 4.00000, 21.00000, 376.57000, 5.57000, 98.10000, 307.00000, 13.60000, 0.85204, 8.14000, 0.53800, 4.01230, 4.00000, 21.00000, 392.53000, 5.96500, 89.20000, 307.00000, 19.60000, 1.23247, 8.14000, 0.53800, 3.97690, 4.00000, 21.00000, 396.90000, 6.14200, 91.70000, 307.00000, 15.20000, 0.98843, 8.14000, 0.53800, 4.09520, 4.00000, 21.00000, 394.54000, 5.81300, 100.00000, 307.00000, 14.50000, 0.75026, 8.14000, 0.53800, 4.39960, 4.00000, 21.00000, 394.33000, 5.92400, 94.10000, 307.00000, 15.60000, 0.84054, 8.14000, 0.53800, 4.45460, 4.00000, 21.00000, 303.42000, 5.59900, 85.70000, 307.00000, 13.90000, 0.67191, 8.14000, 0.53800, 4.68200, 4.00000, 21.00000, 376.88000, 5.81300, 90.30000, 307.00000, 16.60000, 0.95577, 8.14000, 0.53800, 4.45340, 4.00000, 21.00000, 306.38000, 6.04700, 88.80000, 307.00000, 14.80000, 0.77299, 8.14000, 0.53800, 4.45470, 4.00000, 21.00000, 387.94000, 6.49500, 94.40000, 307.00000, 18.40000, 1.00245, 8.14000, 0.53800, 4.23900, 4.00000, 21.00000, 380.23000, 6.67400, 87.30000, 307.00000, 21.00000, 1.13081, 8.14000, 0.53800, 4.23300, 4.00000, 21.00000, 360.17000, 5.71300, 94.10000, 307.00000, 12.70000, 1.35472, 8.14000, 0.53800, 4.17500, 4.00000, 21.00000, 376.73000, 6.07200, 100.00000, 307.00000, 14.50000, 1.38799, 8.14000, 0.53800, 3.99000, 4.00000, 21.00000, 232.60000, 5.95000, 82.00000, 307.00000, 13.20000, 1.15172, 8.14000, 0.53800, 3.78720, 4.00000, 21.00000, 358.77000, 5.70100, 95.00000, 307.00000, 13.10000, 1.61282, 8.14000, 0.53800, 3.75980, 4.00000, 21.00000, 248.31000, 6.09600, 96.90000, 307.00000, 13.50000, 0.06417, 5.96000, 0.49900, 3.36030, 5.00000, 19.20000, 396.90000, 5.93300, 68.20000, 279.00000, 18.90000, 0.09744, 5.96000, 0.49900, 3.37790, 5.00000, 19.20000, 377.56000, 5.84100, 61.40000, 279.00000, 20.00000, 0.08014, 5.96000, 0.49900, 3.93420, 5.00000, 19.20000, 396.90000, 5.85000, 41.50000, 279.00000, 21.00000, 0.17505, 5.96000, 0.49900, 3.84730, 5.00000, 19.20000, 393.43000, 5.96600, 30.20000, 279.00000, 24.70000, 0.02763, 2.95000, 0.42800, 5.40110, 3.00000, 18.30000, 395.63000, 6.59500, 21.80000, 252.00000, 30.80000, 0.03359, 2.95000, 0.42800, 5.40110, 3.00000, 18.30000, 395.62000, 7.02400, 15.80000, 252.00000, 34.90000, 0.12744, 6.91000, 0.44800, 5.72090, 3.00000, 17.90000, 385.41000, 6.77000, 2.90000, 233.00000, 26.60000, 0.14150, 6.91000, 0.44800, 5.72090, 3.00000, 17.90000, 383.37000, 6.16900, 6.60000, 233.00000, 25.30000, 0.15936, 6.91000, 0.44800, 5.72090, 3.00000, 17.90000, 394.46000, 6.21100, 6.50000, 233.00000, 24.70000, 0.12269, 6.91000, 0.44800, 5.72090, 3.00000, 17.90000, 389.39000, 6.06900, 40.00000, 233.00000, 21.20000, 0.17142, 6.91000, 0.44800, 5.10040, 3.00000, 17.90000, 396.90000, 5.68200, 33.80000, 233.00000, 19.30000, 0.18836, 6.91000, 0.44800, 5.10040, 3.00000, 17.90000, 396.90000, 5.78600, 33.30000, 233.00000, 20.00000, 0.22927, 6.91000, 0.44800, 5.68940, 3.00000, 17.90000, 392.74000, 6.03000, 85.50000, 233.00000, 16.60000, 0.25387, 6.91000, 0.44800, 5.87000, 3.00000, 17.90000, 396.90000, 5.39900, 95.30000, 233.00000, 14.40000, 0.21977, 6.91000, 0.44800, 6.08770, 3.00000, 17.90000, 396.90000, 5.60200, 62.00000, 233.00000, 19.40000, 0.08873, 5.64000, 0.43900, 6.81470, 4.00000, 16.80000, 395.56000, 5.96300, 45.70000, 243.00000, 19.70000, 0.04337, 5.64000, 0.43900, 6.81470, 4.00000, 16.80000, 393.97000, 6.11500, 63.00000, 243.00000, 20.50000, 0.05360, 5.64000, 0.43900, 6.81470, 4.00000, 16.80000, 396.90000, 6.51100, 21.10000, 243.00000, 25.00000, 0.04981, 5.64000, 0.43900, 6.81470, 4.00000, 16.80000, 396.90000, 5.99800, 21.40000, 243.00000, 23.40000, 0.01360, 4.00000, 0.41000, 7.31970, 3.00000, 21.10000, 396.90000, 5.88800, 47.60000, 469.00000, 18.90000, 0.01311, 1.22000, 0.40300, 8.69660, 5.00000, 17.90000, 395.93000, 7.24900, 21.90000, 226.00000, 35.40000, 0.02055, 0.74000, 0.41000, 9.18760, 2.00000, 17.30000, 396.90000, 6.38300, 35.70000, 313.00000, 24.70000, 0.01432, 1.32000, 0.41100, 8.32480, 5.00000, 15.10000, 392.90000, 6.81600, 40.50000, 256.00000, 31.60000, 0.15445, 5.13000, 0.45300, 7.81480, 8.00000, 19.70000, 390.68000, 6.14500, 29.20000, 284.00000, 23.30000, 0.10328, 5.13000, 0.45300, 6.93200, 8.00000, 19.70000, 396.90000, 5.92700, 47.20000, 284.00000, 19.60000, 0.14932, 5.13000, 0.45300, 7.22540, 8.00000, 19.70000, 395.11000, 5.74100, 66.20000, 284.00000, 18.70000, 0.17171, 5.13000, 0.45300, 6.81850, 8.00000, 19.70000, 378.08000, 5.96600, 93.40000, 284.00000, 16.00000, 0.11027, 5.13000, 0.45300, 7.22550, 8.00000, 19.70000, 396.90000, 6.45600, 67.80000, 284.00000, 22.20000, 0.12650, 5.13000, 0.45300, 7.98090, 8.00000, 19.70000, 395.58000, 6.76200, 43.40000, 284.00000, 25.00000, 0.01951, 1.38000, 0.41610, 9.22290, 3.00000, 18.60000, 393.24000, 7.10400, 59.50000, 216.00000, 33.00000, 0.03584, 3.37000, 0.39800, 6.61150, 4.00000, 16.10000, 396.90000, 6.29000, 17.80000, 337.00000, 23.50000, 0.04379, 3.37000, 0.39800, 6.61150, 4.00000, 16.10000, 396.90000, 5.78700, 31.10000, 337.00000, 19.40000, 0.05789, 6.07000, 0.40900, 6.49800, 4.00000, 18.90000, 396.21000, 5.87800, 21.40000, 345.00000, 22.00000, 0.13554, 6.07000, 0.40900, 6.49800, 4.00000, 18.90000, 396.90000, 5.59400, 36.80000, 345.00000, 17.40000, 0.12816, 6.07000, 0.40900, 6.49800, 4.00000, 18.90000, 396.90000, 5.88500, 33.00000, 345.00000, 20.90000, 0.08826, 10.81000, 0.41300, 5.28730, 4.00000, 19.20000, 383.73000, 6.41700, 6.60000, 305.00000, 24.20000, 0.15876, 10.81000, 0.41300, 5.28730, 4.00000, 19.20000, 376.94000, 5.96100, 17.50000, 305.00000, 21.70000, 0.09164, 10.81000, 0.41300, 5.28730, 4.00000, 19.20000, 390.91000, 6.06500, 7.80000, 305.00000, 22.80000, 0.19539, 10.81000, 0.41300, 5.28730, 4.00000, 19.20000, 377.17000, 6.24500, 6.20000, 305.00000, 23.40000, 0.07896, 12.83000, 0.43700, 4.25150, 5.00000, 18.70000, 394.92000, 6.27300, 6.00000, 398.00000, 24.10000, 0.09512, 12.83000, 0.43700, 4.50260, 5.00000, 18.70000, 383.23000, 6.28600, 45.00000, 398.00000, 21.40000, 0.10153, 12.83000, 0.43700, 4.05220, 5.00000, 18.70000, 373.66000, 6.27900, 74.50000, 398.00000, 20.00000, 0.08707, 12.83000, 0.43700, 4.09050, 5.00000, 18.70000, 386.96000, 6.14000, 45.80000, 398.00000, 20.80000, 0.05646, 12.83000, 0.43700, 5.01410, 5.00000, 18.70000, 386.40000, 6.23200, 53.70000, 398.00000, 21.20000, 0.08387, 12.83000, 0.43700, 4.50260, 5.00000, 18.70000, 396.06000, 5.87400, 36.60000, 398.00000, 20.30000, 0.04113, 4.86000, 0.42600, 5.40070, 4.00000, 19.00000, 396.90000, 6.72700, 33.50000, 281.00000, 28.00000, 0.04462, 4.86000, 0.42600, 5.40070, 4.00000, 19.00000, 395.63000, 6.61900, 70.40000, 281.00000, 23.90000, 0.03659, 4.86000, 0.42600, 5.40070, 4.00000, 19.00000, 396.90000, 6.30200, 32.20000, 281.00000, 24.80000, 0.03551, 4.86000, 0.42600, 5.40070, 4.00000, 19.00000, 390.64000, 6.16700, 46.70000, 281.00000, 22.90000, 0.05059, 4.49000, 0.44900, 4.77940, 3.00000, 18.50000, 396.90000, 6.38900, 48.00000, 247.00000, 23.90000, 0.05735, 4.49000, 0.44900, 4.43770, 3.00000, 18.50000, 392.30000, 6.63000, 56.10000, 247.00000, 26.60000, 0.05188, 4.49000, 0.44900, 4.42720, 3.00000, 18.50000, 395.99000, 6.01500, 45.10000, 247.00000, 22.50000, 0.07151, 4.49000, 0.44900, 3.74760, 3.00000, 18.50000, 395.15000, 6.12100, 56.80000, 247.00000, 22.20000, 0.05660, 3.41000, 0.48900, 3.42170, 2.00000, 17.80000, 396.90000, 7.00700, 86.30000, 270.00000, 23.60000, 0.05302, 3.41000, 0.48900, 3.41450, 2.00000, 17.80000, 396.06000, 7.07900, 63.10000, 270.00000, 28.70000, 0.04684, 3.41000, 0.48900, 3.09230, 2.00000, 17.80000, 392.18000, 6.41700, 66.10000, 270.00000, 22.60000, 0.03932, 3.41000, 0.48900, 3.09210, 2.00000, 17.80000, 393.55000, 6.40500, 73.90000, 270.00000, 22.00000, 0.04203, 15.04000, 0.46400, 3.66590, 4.00000, 18.20000, 395.01000, 6.44200, 53.60000, 270.00000, 22.90000, 0.02875, 15.04000, 0.46400, 3.66590, 4.00000, 18.20000, 396.33000, 6.21100, 28.90000, 270.00000, 25.00000, 0.04294, 15.04000, 0.46400, 3.61500, 4.00000, 18.20000, 396.90000, 6.24900, 77.30000, 270.00000, 20.60000, 0.12204, 2.89000, 0.44500, 3.49520, 2.00000, 18.00000, 357.98000, 6.62500, 57.80000, 276.00000, 28.40000, 0.11504, 2.89000, 0.44500, 3.49520, 2.00000, 18.00000, 391.83000, 6.16300, 69.60000, 276.00000, 21.40000, 0.12083, 2.89000, 0.44500, 3.49520, 2.00000, 18.00000, 396.90000, 8.06900, 76.00000, 276.00000, 38.70000, 0.08187, 2.89000, 0.44500, 3.49520, 2.00000, 18.00000, 393.53000, 7.82000, 36.90000, 276.00000, 43.80000, 0.06860, 2.89000, 0.44500, 3.49520, 2.00000, 18.00000, 396.90000, 7.41600, 62.50000, 276.00000, 33.20000, 0.14866, 8.56000, 0.52000, 2.77780, 5.00000, 20.90000, 394.76000, 6.72700, 79.90000, 384.00000, 27.50000, 0.11432, 8.56000, 0.52000, 2.85610, 5.00000, 20.90000, 395.58000, 6.78100, 71.30000, 384.00000, 26.50000, 0.22876, 8.56000, 0.52000, 2.71470, 5.00000, 20.90000, 70.80000, 6.40500, 85.40000, 384.00000, 18.60000, 0.21161, 8.56000, 0.52000, 2.71470, 5.00000, 20.90000, 394.47000, 6.13700, 87.40000, 384.00000, 19.30000, 0.13960, 8.56000, 0.52000, 2.42100, 5.00000, 20.90000, 392.69000, 6.16700, 90.00000, 384.00000, 20.10000, 0.13262, 8.56000, 0.52000, 2.10690, 5.00000, 20.90000, 394.05000, 5.85100, 96.70000, 384.00000, 19.50000, 0.17120, 8.56000, 0.52000, 2.21100, 5.00000, 20.90000, 395.67000, 5.83600, 91.90000, 384.00000, 19.50000, 0.13117, 8.56000, 0.52000, 2.12240, 5.00000, 20.90000, 387.69000, 6.12700, 85.20000, 384.00000, 20.40000, 0.12802, 8.56000, 0.52000, 2.43290, 5.00000, 20.90000, 395.24000, 6.47400, 97.10000, 384.00000, 19.80000, 0.26363, 8.56000, 0.52000, 2.54510, 5.00000, 20.90000, 391.23000, 6.22900, 91.20000, 384.00000, 19.40000, 0.10793, 8.56000, 0.52000, 2.77780, 5.00000, 20.90000, 393.49000, 6.19500, 54.40000, 384.00000, 21.70000, 0.10084, 10.01000, 0.54700, 2.67750, 6.00000, 17.80000, 395.59000, 6.71500, 81.60000, 432.00000, 22.80000, 0.12329, 10.01000, 0.54700, 2.35340, 6.00000, 17.80000, 394.95000, 5.91300, 92.90000, 432.00000, 18.80000, 0.22212, 10.01000, 0.54700, 2.54800, 6.00000, 17.80000, 396.90000, 6.09200, 95.40000, 432.00000, 18.70000, 0.14231, 10.01000, 0.54700, 2.25650, 6.00000, 17.80000, 388.74000, 6.25400, 84.20000, 432.00000, 18.50000, 0.17134, 10.01000, 0.54700, 2.46310, 6.00000, 17.80000, 344.91000, 5.92800, 88.20000, 432.00000, 18.30000, 0.13158, 10.01000, 0.54700, 2.73010, 6.00000, 17.80000, 393.30000, 6.17600, 72.50000, 432.00000, 21.20000, 0.15098, 10.01000, 0.54700, 2.74740, 6.00000, 17.80000, 394.51000, 6.02100, 82.60000, 432.00000, 19.20000, 0.13058, 10.01000, 0.54700, 2.47750, 6.00000, 17.80000, 338.63000, 5.87200, 73.10000, 432.00000, 20.40000, 0.14476, 10.01000, 0.54700, 2.75920, 6.00000, 17.80000, 391.50000, 5.73100, 65.20000, 432.00000, 19.30000, 0.06899, 25.65000, 0.58100, 2.25770, 2.00000, 19.10000, 389.15000, 5.87000, 69.70000, 188.00000, 22.00000, 0.07165, 25.65000, 0.58100, 2.19740, 2.00000, 19.10000, 377.67000, 6.00400, 84.10000, 188.00000, 20.30000, 0.09299, 25.65000, 0.58100, 2.08690, 2.00000, 19.10000, 378.09000, 5.96100, 92.90000, 188.00000, 20.50000, 0.15038, 25.65000, 0.58100, 1.94440, 2.00000, 19.10000, 370.31000, 5.85600, 97.00000, 188.00000, 17.30000, 0.09849, 25.65000, 0.58100, 2.00630, 2.00000, 19.10000, 379.38000, 5.87900, 95.80000, 188.00000, 18.80000, 0.16902, 25.65000, 0.58100, 1.99290, 2.00000, 19.10000, 385.02000, 5.98600, 88.40000, 188.00000, 21.40000, 0.38735, 25.65000, 0.58100, 1.75720, 2.00000, 19.10000, 359.29000, 5.61300, 95.60000, 188.00000, 15.70000, 0.25915, 21.89000, 0.62400, 1.78830, 4.00000, 21.20000, 392.11000, 5.69300, 96.00000, 437.00000, 16.20000, 0.32543, 21.89000, 0.62400, 1.81250, 4.00000, 21.20000, 396.90000, 6.43100, 98.80000, 437.00000, 18.00000, 0.88125, 21.89000, 0.62400, 1.97990, 4.00000, 21.20000, 396.90000, 5.63700, 94.70000, 437.00000, 14.30000, 0.34006, 21.89000, 0.62400, 2.11850, 4.00000, 21.20000, 395.04000, 6.45800, 98.90000, 437.00000, 19.20000, 1.19294, 21.89000, 0.62400, 2.27100, 4.00000, 21.20000, 396.90000, 6.32600, 97.70000, 437.00000, 19.60000, 0.59005, 21.89000, 0.62400, 2.32740, 4.00000, 21.20000, 385.76000, 6.37200, 97.90000, 437.00000, 23.00000, 0.32982, 21.89000, 0.62400, 2.46990, 4.00000, 21.20000, 388.69000, 5.82200, 95.40000, 437.00000, 18.40000, 0.97617, 21.89000, 0.62400, 2.34600, 4.00000, 21.20000, 262.76000, 5.75700, 98.40000, 437.00000, 15.60000, 0.55778, 21.89000, 0.62400, 2.11070, 4.00000, 21.20000, 394.67000, 6.33500, 98.20000, 437.00000, 18.10000, 0.32264, 21.89000, 0.62400, 1.96690, 4.00000, 21.20000, 378.25000, 5.94200, 93.50000, 437.00000, 17.40000, 0.35233, 21.89000, 0.62400, 1.84980, 4.00000, 21.20000, 394.08000, 6.45400, 98.40000, 437.00000, 17.10000, 0.24980, 21.89000, 0.62400, 1.66860, 4.00000, 21.20000, 392.04000, 5.85700, 98.20000, 437.00000, 13.30000, 0.54452, 21.89000, 0.62400, 1.66870, 4.00000, 21.20000, 396.90000, 6.15100, 97.90000, 437.00000, 17.80000, 0.29090, 21.89000, 0.62400, 1.61190, 4.00000, 21.20000, 388.08000, 6.17400, 93.60000, 437.00000, 14.00000, 1.62864, 21.89000, 0.62400, 1.43940, 4.00000, 21.20000, 396.90000, 5.01900, 100.00000, 437.00000, 14.40000, 3.32105, 19.58000, 0.87100, 1.32160, 5.00000, 14.70000, 396.90000, 5.40300, 100.00000, 403.00000, 13.40000, 4.09740, 19.58000, 0.87100, 1.41180, 5.00000, 14.70000, 396.90000, 5.46800, 100.00000, 403.00000, 15.60000, 2.77974, 19.58000, 0.87100, 1.34590, 5.00000, 14.70000, 396.90000, 4.90300, 97.80000, 403.00000, 11.80000, 2.37934, 19.58000, 0.87100, 1.41910, 5.00000, 14.70000, 172.91000, 6.13000, 100.00000, 403.00000, 13.80000, 2.15505, 19.58000, 0.87100, 1.51660, 5.00000, 14.70000, 169.27000, 5.62800, 100.00000, 403.00000, 15.60000, 2.36862, 19.58000, 0.87100, 1.46080, 5.00000, 14.70000, 391.71000, 4.92600, 95.70000, 403.00000, 14.60000, 2.33099, 19.58000, 0.87100, 1.52960, 5.00000, 14.70000, 356.99000, 5.18600, 93.80000, 403.00000, 17.80000, 2.73397, 19.58000, 0.87100, 1.52570, 5.00000, 14.70000, 351.85000, 5.59700, 94.90000, 403.00000, 15.40000, 1.65660, 19.58000, 0.87100, 1.61800, 5.00000, 14.70000, 372.80000, 6.12200, 97.30000, 403.00000, 21.50000, 1.49632, 19.58000, 0.87100, 1.59160, 5.00000, 14.70000, 341.60000, 5.40400, 100.00000, 403.00000, 19.60000, 1.12658, 19.58000, 0.87100, 1.61020, 5.00000, 14.70000, 343.28000, 5.01200, 88.00000, 403.00000, 15.30000, 2.14918, 19.58000, 0.87100, 1.62320, 5.00000, 14.70000, 261.95000, 5.70900, 98.50000, 403.00000, 19.40000, 1.41385, 19.58000, 0.87100, 1.74940, 5.00000, 14.70000, 321.02000, 6.12900, 96.00000, 403.00000, 17.00000, 3.53501, 19.58000, 0.87100, 1.74550, 5.00000, 14.70000, 88.01000, 6.15200, 82.60000, 403.00000, 15.60000, 2.44668, 19.58000, 0.87100, 1.73640, 5.00000, 14.70000, 88.63000, 5.27200, 94.00000, 403.00000, 13.10000, 1.22358, 19.58000, 0.60500, 1.87730, 5.00000, 14.70000, 363.43000, 6.94300, 97.40000, 403.00000, 41.30000, 1.34284, 19.58000, 0.60500, 1.75730, 5.00000, 14.70000, 353.89000, 6.06600, 100.00000, 403.00000, 24.30000, 1.42502, 19.58000, 0.87100, 1.76590, 5.00000, 14.70000, 364.31000, 6.51000, 100.00000, 403.00000, 23.30000, 1.27346, 19.58000, 0.60500, 1.79840, 5.00000, 14.70000, 338.92000, 6.25000, 92.60000, 403.00000, 27.00000, 1.46336, 19.58000, 0.60500, 1.97090, 5.00000, 14.70000, 374.43000, 7.48900, 90.80000, 403.00000, 50.00000, 1.83377, 19.58000, 0.60500, 2.04070, 5.00000, 14.70000, 389.61000, 7.80200, 98.20000, 403.00000, 50.00000, 1.51902, 19.58000, 0.60500, 2.16200, 5.00000, 14.70000, 388.45000, 8.37500, 93.90000, 403.00000, 50.00000, 2.24236, 19.58000, 0.60500, 2.42200, 5.00000, 14.70000, 395.11000, 5.85400, 91.80000, 403.00000, 22.70000, 2.92400, 19.58000, 0.60500, 2.28340, 5.00000, 14.70000, 240.16000, 6.10100, 93.00000, 403.00000, 25.00000, 2.01019, 19.58000, 0.60500, 2.04590, 5.00000, 14.70000, 369.30000, 7.92900, 96.20000, 403.00000, 50.00000, 1.80028, 19.58000, 0.60500, 2.42590, 5.00000, 14.70000, 227.61000, 5.87700, 79.20000, 403.00000, 23.80000, 2.30040, 19.58000, 0.60500, 2.10000, 5.00000, 14.70000, 297.09000, 6.31900, 96.10000, 403.00000, 23.80000, 2.44953, 19.58000, 0.60500, 2.26250, 5.00000, 14.70000, 330.04000, 6.40200, 95.20000, 403.00000, 22.30000, 1.20742, 19.58000, 0.60500, 2.42590, 5.00000, 14.70000, 292.29000, 5.87500, 94.60000, 403.00000, 17.40000, 2.31390, 19.58000, 0.60500, 2.38870, 5.00000, 14.70000, 348.13000, 5.88000, 97.30000, 403.00000, 19.10000, 0.13914, 4.05000, 0.51000, 2.59610, 5.00000, 16.60000, 396.90000, 5.57200, 88.50000, 296.00000, 23.10000, 0.09178, 4.05000, 0.51000, 2.64630, 5.00000, 16.60000, 395.50000, 6.41600, 84.10000, 296.00000, 23.60000, 0.08447, 4.05000, 0.51000, 2.70190, 5.00000, 16.60000, 393.23000, 5.85900, 68.70000, 296.00000, 22.60000, 0.06664, 4.05000, 0.51000, 3.13230, 5.00000, 16.60000, 390.96000, 6.54600, 33.10000, 296.00000, 29.40000, 0.07022, 4.05000, 0.51000, 3.55490, 5.00000, 16.60000, 393.23000, 6.02000, 47.20000, 296.00000, 23.20000, 0.05425, 4.05000, 0.51000, 3.31750, 5.00000, 16.60000, 395.60000, 6.31500, 73.40000, 296.00000, 24.60000, 0.06642, 4.05000, 0.51000, 2.91530, 5.00000, 16.60000, 391.27000, 6.86000, 74.40000, 296.00000, 29.90000, 0.05780, 2.46000, 0.48800, 2.82900, 3.00000, 17.80000, 396.90000, 6.98000, 58.40000, 193.00000, 37.20000, 0.06588, 2.46000, 0.48800, 2.74100, 3.00000, 17.80000, 395.56000, 7.76500, 83.30000, 193.00000, 39.80000, 0.06888, 2.46000, 0.48800, 2.59790, 3.00000, 17.80000, 396.90000, 6.14400, 62.20000, 193.00000, 36.20000, 0.09103, 2.46000, 0.48800, 2.70060, 3.00000, 17.80000, 394.12000, 7.15500, 92.20000, 193.00000, 37.90000, 0.10008, 2.46000, 0.48800, 2.84700, 3.00000, 17.80000, 396.90000, 6.56300, 95.60000, 193.00000, 32.50000, 0.08308, 2.46000, 0.48800, 2.98790, 3.00000, 17.80000, 391.00000, 5.60400, 89.80000, 193.00000, 26.40000, 0.06047, 2.46000, 0.48800, 3.27970, 3.00000, 17.80000, 387.11000, 6.15300, 68.80000, 193.00000, 29.60000, 0.05602, 2.46000, 0.48800, 3.19920, 3.00000, 17.80000, 392.63000, 7.83100, 53.60000, 193.00000, 50.00000, 0.07875, 3.44000, 0.43700, 3.78860, 5.00000, 15.20000, 393.87000, 6.78200, 41.10000, 398.00000, 32.00000, 0.12579, 3.44000, 0.43700, 4.56670, 5.00000, 15.20000, 382.84000, 6.55600, 29.10000, 398.00000, 29.80000, 0.08370, 3.44000, 0.43700, 4.56670, 5.00000, 15.20000, 396.90000, 7.18500, 38.90000, 398.00000, 34.90000, 0.09068, 3.44000, 0.43700, 6.47980, 5.00000, 15.20000, 377.68000, 6.95100, 21.50000, 398.00000, 37.00000, 0.06911, 3.44000, 0.43700, 6.47980, 5.00000, 15.20000, 389.71000, 6.73900, 30.80000, 398.00000, 30.50000, 0.08664, 3.44000, 0.43700, 6.47980, 5.00000, 15.20000, 390.49000, 7.17800, 26.30000, 398.00000, 36.40000, 0.02187, 2.93000, 0.40100, 6.21960, 1.00000, 15.60000, 393.37000, 6.80000, 9.90000, 265.00000, 31.10000, 0.01439, 2.93000, 0.40100, 6.21960, 1.00000, 15.60000, 376.70000, 6.60400, 18.80000, 265.00000, 29.10000, 0.01381, 0.46000, 0.42200, 5.64840, 4.00000, 14.40000, 394.23000, 7.87500, 32.00000, 255.00000, 50.00000, 0.04011, 1.52000, 0.40400, 7.30900, 2.00000, 12.60000, 396.90000, 7.28700, 34.10000, 329.00000, 33.30000, 0.04666, 1.52000, 0.40400, 7.30900, 2.00000, 12.60000, 354.31000, 7.10700, 36.60000, 329.00000, 30.30000, 0.03768, 1.52000, 0.40400, 7.30900, 2.00000, 12.60000, 392.20000, 7.27400, 38.30000, 329.00000, 34.60000, 0.03150, 1.47000, 0.40300, 7.65340, 3.00000, 17.00000, 396.90000, 6.97500, 15.30000, 402.00000, 34.90000, 0.01778, 1.47000, 0.40300, 7.65340, 3.00000, 17.00000, 384.30000, 7.13500, 13.90000, 402.00000, 32.90000, 0.03445, 2.03000, 0.41500, 6.27000, 2.00000, 14.70000, 393.77000, 6.16200, 38.40000, 348.00000, 24.10000, 0.02177, 2.03000, 0.41500, 6.27000, 2.00000, 14.70000, 395.38000, 7.61000, 15.70000, 348.00000, 42.30000, 0.03510, 2.68000, 0.41610, 5.11800, 4.00000, 14.70000, 392.78000, 7.85300, 33.20000, 224.00000, 48.50000, 0.02009, 2.68000, 0.41610, 5.11800, 4.00000, 14.70000, 390.55000, 8.03400, 31.90000, 224.00000, 50.00000, 0.13642, 10.59000, 0.48900, 3.94540, 4.00000, 18.60000, 396.90000, 5.89100, 22.30000, 277.00000, 22.60000, 0.22969, 10.59000, 0.48900, 4.35490, 4.00000, 18.60000, 394.87000, 6.32600, 52.50000, 277.00000, 24.40000, 0.25199, 10.59000, 0.48900, 4.35490, 4.00000, 18.60000, 389.43000, 5.78300, 72.70000, 277.00000, 22.50000, 0.13587, 10.59000, 0.48900, 4.23920, 4.00000, 18.60000, 381.32000, 6.06400, 59.10000, 277.00000, 24.40000, 0.43571, 10.59000, 0.48900, 3.87500, 4.00000, 18.60000, 396.90000, 5.34400, 100.00000, 277.00000, 20.00000, 0.17446, 10.59000, 0.48900, 3.87710, 4.00000, 18.60000, 393.25000, 5.96000, 92.10000, 277.00000, 21.70000, 0.37578, 10.59000, 0.48900, 3.66500, 4.00000, 18.60000, 395.24000, 5.40400, 88.60000, 277.00000, 19.30000, 0.21719, 10.59000, 0.48900, 3.65260, 4.00000, 18.60000, 390.94000, 5.80700, 53.80000, 277.00000, 22.40000, 0.14052, 10.59000, 0.48900, 3.94540, 4.00000, 18.60000, 385.81000, 6.37500, 32.30000, 277.00000, 28.10000, 0.28955, 10.59000, 0.48900, 3.58750, 4.00000, 18.60000, 348.93000, 5.41200, 9.80000, 277.00000, 23.70000, 0.19802, 10.59000, 0.48900, 3.94540, 4.00000, 18.60000, 393.63000, 6.18200, 42.40000, 277.00000, 25.00000, 0.04560, 13.89000, 0.55000, 3.11210, 5.00000, 16.40000, 392.80000, 5.88800, 56.00000, 276.00000, 23.30000, 0.07013, 13.89000, 0.55000, 3.42110, 5.00000, 16.40000, 392.78000, 6.64200, 85.10000, 276.00000, 28.70000, 0.11069, 13.89000, 0.55000, 2.88930, 5.00000, 16.40000, 396.90000, 5.95100, 93.80000, 276.00000, 21.50000, 0.11425, 13.89000, 0.55000, 3.36330, 5.00000, 16.40000, 393.74000, 6.37300, 92.40000, 276.00000, 23.00000, 0.35809, 6.20000, 0.50700, 2.86170, 8.00000, 17.40000, 391.70000, 6.95100, 88.50000, 307.00000, 26.70000, 0.40771, 6.20000, 0.50700, 3.04800, 8.00000, 17.40000, 395.24000, 6.16400, 91.30000, 307.00000, 21.70000, 0.62356, 6.20000, 0.50700, 3.27210, 8.00000, 17.40000, 390.39000, 6.87900, 77.70000, 307.00000, 27.50000, 0.61470, 6.20000, 0.50700, 3.27210, 8.00000, 17.40000, 396.90000, 6.61800, 80.80000, 307.00000, 30.10000, 0.31533, 6.20000, 0.50400, 2.89440, 8.00000, 17.40000, 385.05000, 8.26600, 78.30000, 307.00000, 44.80000, 0.52693, 6.20000, 0.50400, 2.89440, 8.00000, 17.40000, 382.00000, 8.72500, 83.00000, 307.00000, 50.00000, 0.38214, 6.20000, 0.50400, 3.21570, 8.00000, 17.40000, 387.38000, 8.04000, 86.50000, 307.00000, 37.60000, 0.41238, 6.20000, 0.50400, 3.21570, 8.00000, 17.40000, 372.08000, 7.16300, 79.90000, 307.00000, 31.60000, 0.29819, 6.20000, 0.50400, 3.37510, 8.00000, 17.40000, 377.51000, 7.68600, 17.00000, 307.00000, 46.70000, 0.44178, 6.20000, 0.50400, 3.37510, 8.00000, 17.40000, 380.34000, 6.55200, 21.40000, 307.00000, 31.50000, 0.53700, 6.20000, 0.50400, 3.67150, 8.00000, 17.40000, 378.35000, 5.98100, 68.10000, 307.00000, 24.30000, 0.46296, 6.20000, 0.50400, 3.67150, 8.00000, 17.40000, 376.14000, 7.41200, 76.90000, 307.00000, 31.70000, 0.57529, 6.20000, 0.50700, 3.83840, 8.00000, 17.40000, 385.91000, 8.33700, 73.30000, 307.00000, 41.70000, 0.33147, 6.20000, 0.50700, 3.65190, 8.00000, 17.40000, 378.95000, 8.24700, 70.40000, 307.00000, 48.30000, 0.44791, 6.20000, 0.50700, 3.65190, 8.00000, 17.40000, 360.20000, 6.72600, 66.50000, 307.00000, 29.00000, 0.33045, 6.20000, 0.50700, 3.65190, 8.00000, 17.40000, 376.75000, 6.08600, 61.50000, 307.00000, 24.00000, 0.52058, 6.20000, 0.50700, 4.14800, 8.00000, 17.40000, 388.45000, 6.63100, 76.50000, 307.00000, 25.10000, 0.51183, 6.20000, 0.50700, 4.14800, 8.00000, 17.40000, 390.07000, 7.35800, 71.60000, 307.00000, 31.50000, 0.08244, 4.93000, 0.42800, 6.18990, 6.00000, 16.60000, 379.41000, 6.48100, 18.50000, 300.00000, 23.70000, 0.09252, 4.93000, 0.42800, 6.18990, 6.00000, 16.60000, 383.78000, 6.60600, 42.20000, 300.00000, 23.30000, 0.11329, 4.93000, 0.42800, 6.33610, 6.00000, 16.60000, 391.25000, 6.89700, 54.30000, 300.00000, 22.00000, 0.10612, 4.93000, 0.42800, 6.33610, 6.00000, 16.60000, 394.62000, 6.09500, 65.10000, 300.00000, 20.10000, 0.10290, 4.93000, 0.42800, 7.03550, 6.00000, 16.60000, 372.75000, 6.35800, 52.90000, 300.00000, 22.20000, 0.12757, 4.93000, 0.42800, 7.03550, 6.00000, 16.60000, 374.71000, 6.39300, 7.80000, 300.00000, 23.70000, 0.20608, 5.86000, 0.43100, 7.95490, 7.00000, 19.10000, 372.49000, 5.59300, 76.50000, 330.00000, 17.60000, 0.19133, 5.86000, 0.43100, 7.95490, 7.00000, 19.10000, 389.13000, 5.60500, 70.20000, 330.00000, 18.50000, 0.33983, 5.86000, 0.43100, 8.05550, 7.00000, 19.10000, 390.18000, 6.10800, 34.90000, 330.00000, 24.30000, 0.19657, 5.86000, 0.43100, 8.05550, 7.00000, 19.10000, 376.14000, 6.22600, 79.20000, 330.00000, 20.50000, 0.16439, 5.86000, 0.43100, 7.82650, 7.00000, 19.10000, 374.71000, 6.43300, 49.10000, 330.00000, 24.50000, 0.19073, 5.86000, 0.43100, 7.82650, 7.00000, 19.10000, 393.74000, 6.71800, 17.50000, 330.00000, 26.20000, 0.14030, 5.86000, 0.43100, 7.39670, 7.00000, 19.10000, 396.28000, 6.48700, 13.00000, 330.00000, 24.40000, 0.21409, 5.86000, 0.43100, 7.39670, 7.00000, 19.10000, 377.07000, 6.43800, 8.90000, 330.00000, 24.80000, 0.08221, 5.86000, 0.43100, 8.90670, 7.00000, 19.10000, 386.09000, 6.95700, 6.80000, 330.00000, 29.60000, 0.36894, 5.86000, 0.43100, 8.90670, 7.00000, 19.10000, 396.90000, 8.25900, 8.40000, 330.00000, 42.80000, 0.04819, 3.64000, 0.39200, 9.22030, 1.00000, 16.40000, 392.89000, 6.10800, 32.00000, 315.00000, 21.90000, 0.03548, 3.64000, 0.39200, 9.22030, 1.00000, 16.40000, 395.18000, 5.87600, 19.10000, 315.00000, 20.90000, 0.01538, 3.75000, 0.39400, 6.33610, 3.00000, 15.90000, 386.34000, 7.45400, 34.20000, 244.00000, 44.00000, 0.61154, 3.97000, 0.64700, 1.80100, 5.00000, 13.00000, 389.70000, 8.70400, 86.90000, 264.00000, 50.00000, 0.66351, 3.97000, 0.64700, 1.89460, 5.00000, 13.00000, 383.29000, 7.33300, 100.00000, 264.00000, 36.00000, 0.65665, 3.97000, 0.64700, 2.01070, 5.00000, 13.00000, 391.93000, 6.84200, 100.00000, 264.00000, 30.10000, 0.54011, 3.97000, 0.64700, 2.11210, 5.00000, 13.00000, 392.80000, 7.20300, 81.80000, 264.00000, 33.80000, 0.53412, 3.97000, 0.64700, 2.13980, 5.00000, 13.00000, 388.37000, 7.52000, 89.40000, 264.00000, 43.10000, 0.52014, 3.97000, 0.64700, 2.28850, 5.00000, 13.00000, 386.86000, 8.39800, 91.50000, 264.00000, 48.80000, 0.82526, 3.97000, 0.64700, 2.07880, 5.00000, 13.00000, 393.42000, 7.32700, 94.50000, 264.00000, 31.00000, 0.55007, 3.97000, 0.64700, 1.93010, 5.00000, 13.00000, 387.89000, 7.20600, 91.60000, 264.00000, 36.50000, 0.76162, 3.97000, 0.64700, 1.98650, 5.00000, 13.00000, 392.40000, 5.56000, 62.80000, 264.00000, 22.80000, 0.78570, 3.97000, 0.64700, 2.13290, 5.00000, 13.00000, 384.07000, 7.01400, 84.60000, 264.00000, 30.70000, 0.57834, 3.97000, 0.57500, 2.42160, 5.00000, 13.00000, 384.54000, 8.29700, 67.00000, 264.00000, 50.00000, 0.54050, 3.97000, 0.57500, 2.87200, 5.00000, 13.00000, 390.30000, 7.47000, 52.60000, 264.00000, 43.50000, 0.09065, 6.96000, 0.46400, 3.91750, 3.00000, 18.60000, 391.34000, 5.92000, 61.50000, 223.00000, 20.70000, 0.29916, 6.96000, 0.46400, 4.42900, 3.00000, 18.60000, 388.65000, 5.85600, 42.10000, 223.00000, 21.10000, 0.16211, 6.96000, 0.46400, 4.42900, 3.00000, 18.60000, 396.90000, 6.24000, 16.30000, 223.00000, 25.20000, 0.11460, 6.96000, 0.46400, 3.91750, 3.00000, 18.60000, 394.96000, 6.53800, 58.70000, 223.00000, 24.40000, 0.22188, 6.96000, 0.46400, 4.36650, 3.00000, 18.60000, 390.77000, 7.69100, 51.80000, 223.00000, 35.20000, 0.05644, 6.41000, 0.44700, 4.07760, 4.00000, 17.60000, 396.90000, 6.75800, 32.90000, 254.00000, 32.40000, 0.09604, 6.41000, 0.44700, 4.26730, 4.00000, 17.60000, 396.90000, 6.85400, 42.80000, 254.00000, 32.00000, 0.10469, 6.41000, 0.44700, 4.78720, 4.00000, 17.60000, 389.25000, 7.26700, 49.00000, 254.00000, 33.20000, 0.06127, 6.41000, 0.44700, 4.86280, 4.00000, 17.60000, 393.45000, 6.82600, 27.60000, 254.00000, 33.10000, 0.07978, 6.41000, 0.44700, 4.14030, 4.00000, 17.60000, 396.90000, 6.48200, 32.10000, 254.00000, 29.10000, 0.21038, 3.33000, 0.44290, 4.10070, 5.00000, 14.90000, 396.90000, 6.81200, 32.20000, 216.00000, 35.10000, 0.03578, 3.33000, 0.44290, 4.69470, 5.00000, 14.90000, 387.31000, 7.82000, 64.50000, 216.00000, 45.40000, 0.03705, 3.33000, 0.44290, 5.24470, 5.00000, 14.90000, 392.23000, 6.96800, 37.20000, 216.00000, 35.40000, 0.06129, 3.33000, 0.44290, 5.21190, 5.00000, 14.90000, 377.07000, 7.64500, 49.70000, 216.00000, 46.00000, 0.01501, 1.21000, 0.40100, 5.88500, 1.00000, 13.60000, 395.52000, 7.92300, 24.80000, 198.00000, 50.00000, 0.00906, 2.97000, 0.40000, 7.30730, 1.00000, 15.30000, 394.72000, 7.08800, 20.80000, 285.00000, 32.20000, 0.01096, 2.25000, 0.38900, 7.30730, 1.00000, 15.30000, 394.72000, 6.45300, 31.90000, 300.00000, 22.00000, 0.01965, 1.76000, 0.38500, 9.08920, 1.00000, 18.20000, 341.60000, 6.23000, 31.50000, 241.00000, 20.10000, 0.03871, 5.32000, 0.40500, 7.31720, 6.00000, 16.60000, 396.90000, 6.20900, 31.30000, 293.00000, 23.20000, 0.04590, 5.32000, 0.40500, 7.31720, 6.00000, 16.60000, 396.90000, 6.31500, 45.60000, 293.00000, 22.30000, 0.04297, 5.32000, 0.40500, 7.31720, 6.00000, 16.60000, 371.72000, 6.56500, 22.90000, 293.00000, 24.80000, 0.03502, 4.95000, 0.41100, 5.11670, 4.00000, 19.20000, 396.90000, 6.86100, 27.90000, 245.00000, 28.50000, 0.07886, 4.95000, 0.41100, 5.11670, 4.00000, 19.20000, 396.90000, 7.14800, 27.70000, 245.00000, 37.30000, 0.03615, 4.95000, 0.41100, 5.11670, 4.00000, 19.20000, 396.90000, 6.63000, 23.40000, 245.00000, 27.90000, 0.08265, 13.92000, 0.43700, 5.50270, 4.00000, 16.00000, 396.90000, 6.12700, 18.40000, 289.00000, 23.90000, 0.08199, 13.92000, 0.43700, 5.50270, 4.00000, 16.00000, 396.90000, 6.00900, 42.30000, 289.00000, 21.70000, 0.12932, 13.92000, 0.43700, 5.96040, 4.00000, 16.00000, 396.90000, 6.67800, 31.10000, 289.00000, 28.60000, 0.05372, 13.92000, 0.43700, 5.96040, 4.00000, 16.00000, 392.85000, 6.54900, 51.00000, 289.00000, 27.10000, 0.14103, 13.92000, 0.43700, 6.32000, 4.00000, 16.00000, 396.90000, 5.79000, 58.00000, 289.00000, 20.30000, 0.06466, 2.24000, 0.40000, 7.82780, 5.00000, 14.80000, 368.24000, 6.34500, 20.10000, 358.00000, 22.50000, 0.05561, 2.24000, 0.40000, 7.82780, 5.00000, 14.80000, 371.58000, 7.04100, 10.00000, 358.00000, 29.00000, 0.04417, 2.24000, 0.40000, 7.82780, 5.00000, 14.80000, 390.86000, 6.87100, 47.40000, 358.00000, 24.80000, 0.03537, 6.09000, 0.43300, 5.49170, 7.00000, 16.10000, 395.75000, 6.59000, 40.40000, 329.00000, 22.00000, 0.09266, 6.09000, 0.43300, 5.49170, 7.00000, 16.10000, 383.61000, 6.49500, 18.40000, 329.00000, 26.40000, 0.10000, 6.09000, 0.43300, 5.49170, 7.00000, 16.10000, 390.43000, 6.98200, 17.70000, 329.00000, 33.10000, 0.05515, 2.18000, 0.47200, 4.02200, 7.00000, 18.40000, 393.68000, 7.23600, 41.10000, 222.00000, 36.10000, 0.05479, 2.18000, 0.47200, 3.37000, 7.00000, 18.40000, 393.36000, 6.61600, 58.10000, 222.00000, 28.40000, 0.07503, 2.18000, 0.47200, 3.09920, 7.00000, 18.40000, 396.90000, 7.42000, 71.90000, 222.00000, 33.40000, 0.04932, 2.18000, 0.47200, 3.18270, 7.00000, 18.40000, 396.90000, 6.84900, 70.30000, 222.00000, 28.20000, 0.49298, 9.90000, 0.54400, 3.31750, 4.00000, 18.40000, 396.90000, 6.63500, 82.50000, 304.00000, 22.80000, 0.34940, 9.90000, 0.54400, 3.10250, 4.00000, 18.40000, 396.24000, 5.97200, 76.70000, 304.00000, 20.30000, 2.63548, 9.90000, 0.54400, 2.51940, 4.00000, 18.40000, 350.45000, 4.97300, 37.80000, 304.00000, 16.10000, 0.79041, 9.90000, 0.54400, 2.64030, 4.00000, 18.40000, 396.90000, 6.12200, 52.80000, 304.00000, 22.10000, 0.26169, 9.90000, 0.54400, 2.83400, 4.00000, 18.40000, 396.30000, 6.02300, 90.40000, 304.00000, 19.40000, 0.26938, 9.90000, 0.54400, 3.26280, 4.00000, 18.40000, 393.39000, 6.26600, 82.80000, 304.00000, 21.60000, 0.36920, 9.90000, 0.54400, 3.60230, 4.00000, 18.40000, 395.69000, 6.56700, 87.30000, 304.00000, 23.80000, 0.25356, 9.90000, 0.54400, 3.94500, 4.00000, 18.40000, 396.42000, 5.70500, 77.70000, 304.00000, 16.20000, 0.31827, 9.90000, 0.54400, 3.99860, 4.00000, 18.40000, 390.70000, 5.91400, 83.20000, 304.00000, 17.80000, 0.24522, 9.90000, 0.54400, 4.03170, 4.00000, 18.40000, 396.90000, 5.78200, 71.70000, 304.00000, 19.80000, 0.40202, 9.90000, 0.54400, 3.53250, 4.00000, 18.40000, 395.21000, 6.38200, 67.20000, 304.00000, 23.10000, 0.47547, 9.90000, 0.54400, 4.00190, 4.00000, 18.40000, 396.23000, 6.11300, 58.80000, 304.00000, 21.00000, 0.16760, 7.38000, 0.49300, 4.54040, 5.00000, 19.60000, 396.90000, 6.42600, 52.30000, 287.00000, 23.80000, 0.18159, 7.38000, 0.49300, 4.54040, 5.00000, 19.60000, 396.90000, 6.37600, 54.30000, 287.00000, 23.10000, 0.35114, 7.38000, 0.49300, 4.72110, 5.00000, 19.60000, 396.90000, 6.04100, 49.90000, 287.00000, 20.40000, 0.28392, 7.38000, 0.49300, 4.72110, 5.00000, 19.60000, 391.13000, 5.70800, 74.30000, 287.00000, 18.50000, 0.34109, 7.38000, 0.49300, 4.72110, 5.00000, 19.60000, 396.90000, 6.41500, 40.10000, 287.00000, 25.00000, 0.19186, 7.38000, 0.49300, 5.41590, 5.00000, 19.60000, 393.68000, 6.43100, 14.70000, 287.00000, 24.60000, 0.30347, 7.38000, 0.49300, 5.41590, 5.00000, 19.60000, 396.90000, 6.31200, 28.90000, 287.00000, 23.00000, 0.24103, 7.38000, 0.49300, 5.41590, 5.00000, 19.60000, 396.90000, 6.08300, 43.70000, 287.00000, 22.20000, 0.06617, 3.24000, 0.46000, 5.21460, 4.00000, 16.90000, 382.44000, 5.86800, 25.80000, 430.00000, 19.30000, 0.06724, 3.24000, 0.46000, 5.21460, 4.00000, 16.90000, 375.21000, 6.33300, 17.20000, 430.00000, 22.60000, 0.04544, 3.24000, 0.46000, 5.87360, 4.00000, 16.90000, 368.57000, 6.14400, 32.20000, 430.00000, 19.80000, 0.05023, 6.06000, 0.43790, 6.64070, 1.00000, 16.90000, 394.02000, 5.70600, 28.40000, 304.00000, 17.10000, 0.03466, 6.06000, 0.43790, 6.64070, 1.00000, 16.90000, 362.25000, 6.03100, 23.30000, 304.00000, 19.40000, 0.05083, 5.19000, 0.51500, 6.45840, 5.00000, 20.20000, 389.71000, 6.31600, 38.10000, 224.00000, 22.20000, 0.03738, 5.19000, 0.51500, 6.45840, 5.00000, 20.20000, 389.40000, 6.31000, 38.50000, 224.00000, 20.70000, 0.03961, 5.19000, 0.51500, 5.98530, 5.00000, 20.20000, 396.90000, 6.03700, 34.50000, 224.00000, 21.10000, 0.03427, 5.19000, 0.51500, 5.23110, 5.00000, 20.20000, 396.90000, 5.86900, 46.30000, 224.00000, 19.50000, 0.03041, 5.19000, 0.51500, 5.61500, 5.00000, 20.20000, 394.81000, 5.89500, 59.60000, 224.00000, 18.50000, 0.03306, 5.19000, 0.51500, 4.81220, 5.00000, 20.20000, 396.14000, 6.05900, 37.30000, 224.00000, 20.60000, 0.05497, 5.19000, 0.51500, 4.81220, 5.00000, 20.20000, 396.90000, 5.98500, 45.40000, 224.00000, 19.00000, 0.06151, 5.19000, 0.51500, 4.81220, 5.00000, 20.20000, 396.90000, 5.96800, 58.50000, 224.00000, 18.70000, 0.01301, 1.52000, 0.44200, 7.03790, 1.00000, 15.50000, 394.74000, 7.24100, 49.30000, 284.00000, 32.70000, 0.02498, 1.89000, 0.51800, 6.26690, 1.00000, 15.90000, 389.96000, 6.54000, 59.70000, 422.00000, 16.50000, 0.02543, 3.78000, 0.48400, 5.73210, 5.00000, 17.60000, 396.90000, 6.69600, 56.40000, 370.00000, 23.90000, 0.03049, 3.78000, 0.48400, 6.46540, 5.00000, 17.60000, 387.97000, 6.87400, 28.10000, 370.00000, 31.20000, 0.03113, 4.39000, 0.44200, 8.01360, 3.00000, 18.80000, 385.64000, 6.01400, 48.50000, 352.00000, 17.50000, 0.06162, 4.39000, 0.44200, 8.01360, 3.00000, 18.80000, 364.61000, 5.89800, 52.30000, 352.00000, 17.20000, 0.01870, 4.15000, 0.42900, 8.53530, 4.00000, 17.90000, 392.43000, 6.51600, 27.70000, 351.00000, 23.10000, 0.01501, 2.01000, 0.43500, 8.34400, 4.00000, 17.00000, 390.94000, 6.63500, 29.70000, 280.00000, 24.50000, 0.02899, 1.25000, 0.42900, 8.79210, 1.00000, 19.70000, 389.85000, 6.93900, 34.50000, 335.00000, 26.60000, 0.06211, 1.25000, 0.42900, 8.79210, 1.00000, 19.70000, 396.90000, 6.49000, 44.40000, 335.00000, 22.90000, 0.07950, 1.69000, 0.41100, 10.71030, 4.00000, 18.30000, 370.78000, 6.57900, 35.90000, 411.00000, 24.10000, 0.07244, 1.69000, 0.41100, 10.71030, 4.00000, 18.30000, 392.33000, 5.88400, 18.50000, 411.00000, 18.60000, 0.01709, 2.02000, 0.41000, 12.12650, 5.00000, 17.00000, 384.46000, 6.72800, 36.10000, 187.00000, 30.10000, 0.04301, 1.91000, 0.41300, 10.58570, 4.00000, 22.00000, 382.80000, 5.66300, 21.90000, 334.00000, 18.20000, 0.10659, 1.91000, 0.41300, 10.58570, 4.00000, 22.00000, 376.04000, 5.93600, 19.50000, 334.00000, 20.60000, 8.98296, 18.10000, 0.77000, 2.12220, 24.00000, 20.20000, 377.73000, 6.21200, 97.40000, 666.00000, 17.80000, 3.84970, 18.10000, 0.77000, 2.50520, 24.00000, 20.20000, 391.34000, 6.39500, 91.00000, 666.00000, 21.70000, 5.20177, 18.10000, 0.77000, 2.72270, 24.00000, 20.20000, 395.43000, 6.12700, 83.40000, 666.00000, 22.70000, 4.26131, 18.10000, 0.77000, 2.50910, 24.00000, 20.20000, 390.74000, 6.11200, 81.30000, 666.00000, 22.60000, 4.54192, 18.10000, 0.77000, 2.51820, 24.00000, 20.20000, 374.56000, 6.39800, 88.00000, 666.00000, 25.00000, 3.83684, 18.10000, 0.77000, 2.29550, 24.00000, 20.20000, 350.65000, 6.25100, 91.10000, 666.00000, 19.90000, 3.67822, 18.10000, 0.77000, 2.10360, 24.00000, 20.20000, 380.79000, 5.36200, 96.20000, 666.00000, 20.80000, 4.22239, 18.10000, 0.77000, 1.90470, 24.00000, 20.20000, 353.04000, 5.80300, 89.00000, 666.00000, 16.80000, 3.47428, 18.10000, 0.71800, 1.90470, 24.00000, 20.20000, 354.55000, 8.78000, 82.90000, 666.00000, 21.90000, 4.55587, 18.10000, 0.71800, 1.61320, 24.00000, 20.20000, 354.70000, 3.56100, 87.90000, 666.00000, 27.50000, 3.69695, 18.10000, 0.71800, 1.75230, 24.00000, 20.20000, 316.03000, 4.96300, 91.40000, 666.00000, 21.90000, 13.52220, 18.10000, 0.63100, 1.51060, 24.00000, 20.20000, 131.42000, 3.86300, 100.00000, 666.00000, 23.10000, 4.89822, 18.10000, 0.63100, 1.33250, 24.00000, 20.20000, 375.52000, 4.97000, 100.00000, 666.00000, 50.00000, 5.66998, 18.10000, 0.63100, 1.35670, 24.00000, 20.20000, 375.33000, 6.68300, 96.80000, 666.00000, 50.00000, 6.53876, 18.10000, 0.63100, 1.20240, 24.00000, 20.20000, 392.05000, 7.01600, 97.50000, 666.00000, 50.00000, 9.23230, 18.10000, 0.63100, 1.16910, 24.00000, 20.20000, 366.15000, 6.21600, 100.00000, 666.00000, 50.00000, 8.26725, 18.10000, 0.66800, 1.12960, 24.00000, 20.20000, 347.88000, 5.87500, 89.60000, 666.00000, 50.00000, 11.10810, 18.10000, 0.66800, 1.17420, 24.00000, 20.20000, 396.90000, 4.90600, 100.00000, 666.00000, 13.80000, 18.49820, 18.10000, 0.66800, 1.13700, 24.00000, 20.20000, 396.90000, 4.13800, 100.00000, 666.00000, 13.80000, 19.60910, 18.10000, 0.67100, 1.31630, 24.00000, 20.20000, 396.90000, 7.31300, 97.90000, 666.00000, 15.00000, 15.28800, 18.10000, 0.67100, 1.34490, 24.00000, 20.20000, 363.02000, 6.64900, 93.30000, 666.00000, 13.90000, 9.82349, 18.10000, 0.67100, 1.35800, 24.00000, 20.20000, 396.90000, 6.79400, 98.80000, 666.00000, 13.30000, 23.64820, 18.10000, 0.67100, 1.38610, 24.00000, 20.20000, 396.90000, 6.38000, 96.20000, 666.00000, 13.10000, 17.86670, 18.10000, 0.67100, 1.38610, 24.00000, 20.20000, 393.74000, 6.22300, 100.00000, 666.00000, 10.20000, 88.97620, 18.10000, 0.67100, 1.41650, 24.00000, 20.20000, 396.90000, 6.96800, 91.90000, 666.00000, 10.40000, 15.87440, 18.10000, 0.67100, 1.51920, 24.00000, 20.20000, 396.90000, 6.54500, 99.10000, 666.00000, 10.90000, 9.18702, 18.10000, 0.70000, 1.58040, 24.00000, 20.20000, 396.90000, 5.53600, 100.00000, 666.00000, 11.30000, 7.99248, 18.10000, 0.70000, 1.53310, 24.00000, 20.20000, 396.90000, 5.52000, 100.00000, 666.00000, 12.30000, 20.08490, 18.10000, 0.70000, 1.43950, 24.00000, 20.20000, 285.83000, 4.36800, 91.20000, 666.00000, 8.80000, 16.81180, 18.10000, 0.70000, 1.42610, 24.00000, 20.20000, 396.90000, 5.27700, 98.10000, 666.00000, 7.20000, 24.39380, 18.10000, 0.70000, 1.46720, 24.00000, 20.20000, 396.90000, 4.65200, 100.00000, 666.00000, 10.50000, 22.59710, 18.10000, 0.70000, 1.51840, 24.00000, 20.20000, 396.90000, 5.00000, 89.50000, 666.00000, 7.40000, 14.33370, 18.10000, 0.70000, 1.58950, 24.00000, 20.20000, 372.92000, 4.88000, 100.00000, 666.00000, 10.20000, 8.15174, 18.10000, 0.70000, 1.72810, 24.00000, 20.20000, 396.90000, 5.39000, 98.90000, 666.00000, 11.50000, 6.96215, 18.10000, 0.70000, 1.92650, 24.00000, 20.20000, 394.43000, 5.71300, 97.00000, 666.00000, 15.10000, 5.29305, 18.10000, 0.70000, 2.16780, 24.00000, 20.20000, 378.38000, 6.05100, 82.50000, 666.00000, 23.20000, 11.57790, 18.10000, 0.70000, 1.77000, 24.00000, 20.20000, 396.90000, 5.03600, 97.00000, 666.00000, 9.70000, 8.64476, 18.10000, 0.69300, 1.79120, 24.00000, 20.20000, 396.90000, 6.19300, 92.60000, 666.00000, 13.80000, 13.35980, 18.10000, 0.69300, 1.78210, 24.00000, 20.20000, 396.90000, 5.88700, 94.70000, 666.00000, 12.70000, 8.71675, 18.10000, 0.69300, 1.72570, 24.00000, 20.20000, 391.98000, 6.47100, 98.80000, 666.00000, 13.10000, 5.87205, 18.10000, 0.69300, 1.67680, 24.00000, 20.20000, 396.90000, 6.40500, 96.00000, 666.00000, 12.50000, 7.67202, 18.10000, 0.69300, 1.63340, 24.00000, 20.20000, 393.10000, 5.74700, 98.90000, 666.00000, 8.50000, 38.35180, 18.10000, 0.69300, 1.48960, 24.00000, 20.20000, 396.90000, 5.45300, 100.00000, 666.00000, 5.00000, 9.91655, 18.10000, 0.69300, 1.50040, 24.00000, 20.20000, 338.16000, 5.85200, 77.80000, 666.00000, 6.30000, 25.04610, 18.10000, 0.69300, 1.58880, 24.00000, 20.20000, 396.90000, 5.98700, 100.00000, 666.00000, 5.60000, 14.23620, 18.10000, 0.69300, 1.57410, 24.00000, 20.20000, 396.90000, 6.34300, 100.00000, 666.00000, 7.20000, 9.59571, 18.10000, 0.69300, 1.63900, 24.00000, 20.20000, 376.11000, 6.40400, 100.00000, 666.00000, 12.10000, 24.80170, 18.10000, 0.69300, 1.70280, 24.00000, 20.20000, 396.90000, 5.34900, 96.00000, 666.00000, 8.30000, 41.52920, 18.10000, 0.69300, 1.60740, 24.00000, 20.20000, 329.46000, 5.53100, 85.40000, 666.00000, 8.50000, 67.92080, 18.10000, 0.69300, 1.42540, 24.00000, 20.20000, 384.97000, 5.68300, 100.00000, 666.00000, 5.00000, 20.71620, 18.10000, 0.65900, 1.17810, 24.00000, 20.20000, 370.22000, 4.13800, 100.00000, 666.00000, 11.90000, 11.95110, 18.10000, 0.65900, 1.28520, 24.00000, 20.20000, 332.09000, 5.60800, 100.00000, 666.00000, 27.90000, 7.40389, 18.10000, 0.59700, 1.45470, 24.00000, 20.20000, 314.64000, 5.61700, 97.90000, 666.00000, 17.20000, 14.43830, 18.10000, 0.59700, 1.46550, 24.00000, 20.20000, 179.36000, 6.85200, 100.00000, 666.00000, 27.50000, 51.13580, 18.10000, 0.59700, 1.41300, 24.00000, 20.20000, 2.60000, 5.75700, 100.00000, 666.00000, 15.00000, 14.05070, 18.10000, 0.59700, 1.52750, 24.00000, 20.20000, 35.05000, 6.65700, 100.00000, 666.00000, 17.20000, 18.81100, 18.10000, 0.59700, 1.55390, 24.00000, 20.20000, 28.79000, 4.62800, 100.00000, 666.00000, 17.90000, 28.65580, 18.10000, 0.59700, 1.58940, 24.00000, 20.20000, 210.97000, 5.15500, 100.00000, 666.00000, 16.30000, 45.74610, 18.10000, 0.69300, 1.65820, 24.00000, 20.20000, 88.27000, 4.51900, 100.00000, 666.00000, 7.00000, 18.08460, 18.10000, 0.67900, 1.83470, 24.00000, 20.20000, 27.25000, 6.43400, 100.00000, 666.00000, 7.20000, 10.83420, 18.10000, 0.67900, 1.81950, 24.00000, 20.20000, 21.57000, 6.78200, 90.80000, 666.00000, 7.50000, 25.94060, 18.10000, 0.67900, 1.64750, 24.00000, 20.20000, 127.36000, 5.30400, 89.10000, 666.00000, 10.40000, 73.53410, 18.10000, 0.67900, 1.80260, 24.00000, 20.20000, 16.45000, 5.95700, 100.00000, 666.00000, 8.80000, 11.81230, 18.10000, 0.71800, 1.79400, 24.00000, 20.20000, 48.45000, 6.82400, 76.50000, 666.00000, 8.40000, 11.08740, 18.10000, 0.71800, 1.85890, 24.00000, 20.20000, 318.75000, 6.41100, 100.00000, 666.00000, 16.70000, 7.02259, 18.10000, 0.71800, 1.87460, 24.00000, 20.20000, 319.98000, 6.00600, 95.30000, 666.00000, 14.20000, 12.04820, 18.10000, 0.61400, 1.95120, 24.00000, 20.20000, 291.55000, 5.64800, 87.60000, 666.00000, 20.80000, 7.05042, 18.10000, 0.61400, 2.02180, 24.00000, 20.20000, 2.52000, 6.10300, 85.10000, 666.00000, 13.40000, 8.79212, 18.10000, 0.58400, 2.06350, 24.00000, 20.20000, 3.65000, 5.56500, 70.60000, 666.00000, 11.70000, 15.86030, 18.10000, 0.67900, 1.90960, 24.00000, 20.20000, 7.68000, 5.89600, 95.40000, 666.00000, 8.30000, 12.24720, 18.10000, 0.58400, 1.99760, 24.00000, 20.20000, 24.65000, 5.83700, 59.70000, 666.00000, 10.20000, 37.66190, 18.10000, 0.67900, 1.86290, 24.00000, 20.20000, 18.82000, 6.20200, 78.70000, 666.00000, 10.90000, 7.36711, 18.10000, 0.67900, 1.93560, 24.00000, 20.20000, 96.73000, 6.19300, 78.10000, 666.00000, 11.00000, 9.33889, 18.10000, 0.67900, 1.96820, 24.00000, 20.20000, 60.72000, 6.38000, 95.60000, 666.00000, 9.50000, 8.49213, 18.10000, 0.58400, 2.05270, 24.00000, 20.20000, 83.45000, 6.34800, 86.10000, 666.00000, 14.50000, 10.06230, 18.10000, 0.58400, 2.08820, 24.00000, 20.20000, 81.33000, 6.83300, 94.30000, 666.00000, 14.10000, 6.44405, 18.10000, 0.58400, 2.20040, 24.00000, 20.20000, 97.95000, 6.42500, 74.80000, 666.00000, 16.10000, 5.58107, 18.10000, 0.71300, 2.31580, 24.00000, 20.20000, 100.19000, 6.43600, 87.90000, 666.00000, 14.30000, 13.91340, 18.10000, 0.71300, 2.22220, 24.00000, 20.20000, 100.63000, 6.20800, 95.00000, 666.00000, 11.70000, 11.16040, 18.10000, 0.74000, 2.12470, 24.00000, 20.20000, 109.85000, 6.62900, 94.60000, 666.00000, 13.40000, 14.42080, 18.10000, 0.74000, 2.00260, 24.00000, 20.20000, 27.49000, 6.46100, 93.30000, 666.00000, 9.60000, 15.17720, 18.10000, 0.74000, 1.91420, 24.00000, 20.20000, 9.32000, 6.15200, 100.00000, 666.00000, 8.70000, 13.67810, 18.10000, 0.74000, 1.82060, 24.00000, 20.20000, 68.95000, 5.93500, 87.90000, 666.00000, 8.40000, 9.39063, 18.10000, 0.74000, 1.81720, 24.00000, 20.20000, 396.90000, 5.62700, 93.90000, 666.00000, 12.80000, 22.05110, 18.10000, 0.74000, 1.86620, 24.00000, 20.20000, 391.45000, 5.81800, 92.40000, 666.00000, 10.50000, 9.72418, 18.10000, 0.74000, 2.06510, 24.00000, 20.20000, 385.96000, 6.40600, 97.20000, 666.00000, 17.10000, 5.66637, 18.10000, 0.74000, 2.00480, 24.00000, 20.20000, 395.69000, 6.21900, 100.00000, 666.00000, 18.40000, 9.96654, 18.10000, 0.74000, 1.97840, 24.00000, 20.20000, 386.73000, 6.48500, 100.00000, 666.00000, 15.40000, 12.80230, 18.10000, 0.74000, 1.89560, 24.00000, 20.20000, 240.52000, 5.85400, 96.60000, 666.00000, 10.80000, 10.67180, 18.10000, 0.74000, 1.98790, 24.00000, 20.20000, 43.06000, 6.45900, 94.80000, 666.00000, 11.80000, 6.28807, 18.10000, 0.74000, 2.07200, 24.00000, 20.20000, 318.01000, 6.34100, 96.40000, 666.00000, 14.90000, 9.92485, 18.10000, 0.74000, 2.19800, 24.00000, 20.20000, 388.52000, 6.25100, 96.60000, 666.00000, 12.60000, 9.32909, 18.10000, 0.71300, 2.26160, 24.00000, 20.20000, 396.90000, 6.18500, 98.70000, 666.00000, 14.10000, 7.52601, 18.10000, 0.71300, 2.18500, 24.00000, 20.20000, 304.21000, 6.41700, 98.30000, 666.00000, 13.00000, 6.71772, 18.10000, 0.71300, 2.32360, 24.00000, 20.20000, 0.32000, 6.74900, 92.60000, 666.00000, 13.40000, 5.44114, 18.10000, 0.71300, 2.35520, 24.00000, 20.20000, 355.29000, 6.65500, 98.20000, 666.00000, 15.20000, 5.09017, 18.10000, 0.71300, 2.36820, 24.00000, 20.20000, 385.09000, 6.29700, 91.80000, 666.00000, 16.10000, 8.24809, 18.10000, 0.71300, 2.45270, 24.00000, 20.20000, 375.87000, 7.39300, 99.30000, 666.00000, 17.80000, 9.51363, 18.10000, 0.71300, 2.49610, 24.00000, 20.20000, 6.68000, 6.72800, 94.10000, 666.00000, 14.90000, 4.75237, 18.10000, 0.71300, 2.43580, 24.00000, 20.20000, 50.92000, 6.52500, 86.50000, 666.00000, 14.10000, 4.66883, 18.10000, 0.71300, 2.58060, 24.00000, 20.20000, 10.48000, 5.97600, 87.90000, 666.00000, 12.70000, 8.20058, 18.10000, 0.71300, 2.77920, 24.00000, 20.20000, 3.50000, 5.93600, 80.30000, 666.00000, 13.50000, 7.75223, 18.10000, 0.71300, 2.78310, 24.00000, 20.20000, 272.21000, 6.30100, 83.70000, 666.00000, 14.90000, 6.80117, 18.10000, 0.71300, 2.71750, 24.00000, 20.20000, 396.90000, 6.08100, 84.40000, 666.00000, 20.00000, 4.81213, 18.10000, 0.71300, 2.59750, 24.00000, 20.20000, 255.23000, 6.70100, 90.00000, 666.00000, 16.40000, 3.69311, 18.10000, 0.71300, 2.56710, 24.00000, 20.20000, 391.43000, 6.37600, 88.40000, 666.00000, 17.70000, 6.65492, 18.10000, 0.71300, 2.73440, 24.00000, 20.20000, 396.90000, 6.31700, 83.00000, 666.00000, 19.50000, 5.82115, 18.10000, 0.71300, 2.80160, 24.00000, 20.20000, 393.82000, 6.51300, 89.90000, 666.00000, 20.20000, 7.83932, 18.10000, 0.65500, 2.96340, 24.00000, 20.20000, 396.90000, 6.20900, 65.40000, 666.00000, 21.40000, 3.16360, 18.10000, 0.65500, 3.06650, 24.00000, 20.20000, 334.40000, 5.75900, 48.20000, 666.00000, 19.90000, 3.77498, 18.10000, 0.65500, 2.87150, 24.00000, 20.20000, 22.01000, 5.95200, 84.70000, 666.00000, 19.00000, 4.42228, 18.10000, 0.58400, 2.54030, 24.00000, 20.20000, 331.29000, 6.00300, 94.50000, 666.00000, 19.10000, 15.57570, 18.10000, 0.58000, 2.90840, 24.00000, 20.20000, 368.74000, 5.92600, 71.00000, 666.00000, 19.10000, 13.07510, 18.10000, 0.58000, 2.82370, 24.00000, 20.20000, 396.90000, 5.71300, 56.70000, 666.00000, 20.10000, 4.34879, 18.10000, 0.58000, 3.03340, 24.00000, 20.20000, 396.90000, 6.16700, 84.00000, 666.00000, 19.90000, 4.03841, 18.10000, 0.53200, 3.09930, 24.00000, 20.20000, 395.33000, 6.22900, 90.70000, 666.00000, 19.60000, 3.56868, 18.10000, 0.58000, 2.89650, 24.00000, 20.20000, 393.37000, 6.43700, 75.00000, 666.00000, 23.20000, 4.64689, 18.10000, 0.61400, 2.53290, 24.00000, 20.20000, 374.68000, 6.98000, 67.60000, 666.00000, 29.80000, 8.05579, 18.10000, 0.58400, 2.42980, 24.00000, 20.20000, 352.58000, 5.42700, 95.40000, 666.00000, 13.80000, 6.39312, 18.10000, 0.58400, 2.20600, 24.00000, 20.20000, 302.76000, 6.16200, 97.40000, 666.00000, 13.30000, 4.87141, 18.10000, 0.61400, 2.30530, 24.00000, 20.20000, 396.21000, 6.48400, 93.60000, 666.00000, 16.70000, 15.02340, 18.10000, 0.61400, 2.10070, 24.00000, 20.20000, 349.48000, 5.30400, 97.30000, 666.00000, 12.00000, 10.23300, 18.10000, 0.61400, 2.17050, 24.00000, 20.20000, 379.70000, 6.18500, 96.70000, 666.00000, 14.60000, 14.33370, 18.10000, 0.61400, 1.95120, 24.00000, 20.20000, 383.32000, 6.22900, 88.00000, 666.00000, 21.40000, 5.82401, 18.10000, 0.53200, 3.42420, 24.00000, 20.20000, 396.90000, 6.24200, 64.70000, 666.00000, 23.00000, 5.70818, 18.10000, 0.53200, 3.33170, 24.00000, 20.20000, 393.07000, 6.75000, 74.90000, 666.00000, 23.70000, 5.73116, 18.10000, 0.53200, 3.41060, 24.00000, 20.20000, 395.28000, 7.06100, 77.00000, 666.00000, 25.00000, 2.81838, 18.10000, 0.53200, 4.09830, 24.00000, 20.20000, 392.92000, 5.76200, 40.30000, 666.00000, 21.80000, 2.37857, 18.10000, 0.58300, 3.72400, 24.00000, 20.20000, 370.73000, 5.87100, 41.90000, 666.00000, 20.60000, 3.67367, 18.10000, 0.58300, 3.99170, 24.00000, 20.20000, 388.62000, 6.31200, 51.90000, 666.00000, 21.20000, 5.69175, 18.10000, 0.58300, 3.54590, 24.00000, 20.20000, 392.68000, 6.11400, 79.80000, 666.00000, 19.10000, 4.83567, 18.10000, 0.58300, 3.15230, 24.00000, 20.20000, 388.22000, 5.90500, 53.20000, 666.00000, 20.60000, 0.15086, 27.74000, 0.60900, 1.82090, 4.00000, 20.10000, 395.09000, 5.45400, 92.70000, 711.00000, 15.20000, 0.18337, 27.74000, 0.60900, 1.75540, 4.00000, 20.10000, 344.05000, 5.41400, 98.30000, 711.00000, 7.00000, 0.20746, 27.74000, 0.60900, 1.82260, 4.00000, 20.10000, 318.43000, 5.09300, 98.00000, 711.00000, 8.10000, 0.10574, 27.74000, 0.60900, 1.86810, 4.00000, 20.10000, 390.11000, 5.98300, 98.80000, 711.00000, 13.60000, 0.11132, 27.74000, 0.60900, 2.10990, 4.00000, 20.10000, 396.90000, 5.98300, 83.50000, 711.00000, 20.10000, 0.17331, 9.69000, 0.58500, 2.38170, 6.00000, 19.20000, 396.90000, 5.70700, 54.00000, 391.00000, 21.80000, 0.27957, 9.69000, 0.58500, 2.38170, 6.00000, 19.20000, 396.90000, 5.92600, 42.60000, 391.00000, 24.50000, 0.17899, 9.69000, 0.58500, 2.79860, 6.00000, 19.20000, 393.29000, 5.67000, 28.80000, 391.00000, 23.10000, 0.28960, 9.69000, 0.58500, 2.79860, 6.00000, 19.20000, 396.90000, 5.39000, 72.90000, 391.00000, 19.70000, 0.26838, 9.69000, 0.58500, 2.89270, 6.00000, 19.20000, 396.90000, 5.79400, 70.60000, 391.00000, 18.30000, 0.23912, 9.69000, 0.58500, 2.40910, 6.00000, 19.20000, 396.90000, 6.01900, 65.30000, 391.00000, 21.20000, 0.17783, 9.69000, 0.58500, 2.39990, 6.00000, 19.20000, 395.77000, 5.56900, 73.50000, 391.00000, 17.50000, 0.22438, 9.69000, 0.58500, 2.49820, 6.00000, 19.20000, 396.90000, 6.02700, 79.70000, 391.00000, 16.80000, 0.06263, 11.93000, 0.57300, 2.47860, 1.00000, 21.00000, 391.99000, 6.59300, 69.10000, 273.00000, 22.40000, 0.04527, 11.93000, 0.57300, 2.28750, 1.00000, 21.00000, 396.90000, 6.12000, 76.70000, 273.00000, 20.60000, 0.06076, 11.93000, 0.57300, 2.16750, 1.00000, 21.00000, 396.90000, 6.97600, 91.00000, 273.00000, 23.90000, 0.10959, 11.93000, 0.57300, 2.38890, 1.00000, 21.00000, 393.45000, 6.79400, 89.30000, 273.00000, 22.00000, 0.04741, 11.93000, 0.57300, 2.50500, 1.00000, 21.00000, 396.90000, 6.03000, 80.80000, 273.00000, 11.90000, }) golang-gonum-v1-gonum-0.14.0/stat/car_data_test.go000066400000000000000000000330621450372207100217410ustar00rootroot00000000000000// Copyright ©2016 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 stat_test import "gonum.org/v1/gonum/mat" // ASA Car Exposition Data of Ramos and Donoho (1983) // http://lib.stat.cmu.edu/datasets/cars.desc // http://lib.stat.cmu.edu/datasets/cars.data // Columns are: displacement, horsepower, weight, acceleration, MPG. var carData = mat.NewDense(392, 5, []float64{ 307.0, 130.0, 3504.0, 12.0, 18.0, 350.0, 165.0, 3693.0, 11.5, 15.0, 318.0, 150.0, 3436.0, 11.0, 18.0, 304.0, 150.0, 3433.0, 12.0, 16.0, 302.0, 140.0, 3449.0, 10.5, 17.0, 429.0, 198.0, 4341.0, 10.0, 15.0, 454.0, 220.0, 4354.0, 9.0, 14.0, 440.0, 215.0, 4312.0, 8.5, 14.0, 455.0, 225.0, 4425.0, 10.0, 14.0, 390.0, 190.0, 3850.0, 8.5, 15.0, 383.0, 170.0, 3563.0, 10.0, 15.0, 340.0, 160.0, 3609.0, 8.0, 14.0, 400.0, 150.0, 3761.0, 9.5, 15.0, 455.0, 225.0, 3086.0, 10.0, 14.0, 113.0, 95.0, 2372.0, 15.0, 24.0, 198.0, 95.0, 2833.0, 15.5, 22.0, 199.0, 97.0, 2774.0, 15.5, 18.0, 200.0, 85.0, 2587.0, 16.0, 21.0, 97.0, 88.0, 2130.0, 14.5, 27.0, 97.0, 46.0, 1835.0, 20.5, 26.0, 110.0, 87.0, 2672.0, 17.5, 25.0, 107.0, 90.0, 2430.0, 14.5, 24.0, 104.0, 95.0, 2375.0, 17.5, 25.0, 121.0, 113.0, 2234.0, 12.5, 26.0, 199.0, 90.0, 2648.0, 15.0, 21.0, 360.0, 215.0, 4615.0, 14.0, 10.0, 307.0, 200.0, 4376.0, 15.0, 10.0, 318.0, 210.0, 4382.0, 13.5, 11.0, 304.0, 193.0, 4732.0, 18.5, 9.0, 97.0, 88.0, 2130.0, 14.5, 27.0, 140.0, 90.0, 2264.0, 15.5, 28.0, 113.0, 95.0, 2228.0, 14.0, 25.0, 232.0, 100.0, 2634.0, 13.0, 19.0, 225.0, 105.0, 3439.0, 15.5, 16.0, 250.0, 100.0, 3329.0, 15.5, 17.0, 250.0, 88.0, 3302.0, 15.5, 19.0, 232.0, 100.0, 3288.0, 15.5, 18.0, 350.0, 165.0, 4209.0, 12.0, 14.0, 400.0, 175.0, 4464.0, 11.5, 14.0, 351.0, 153.0, 4154.0, 13.5, 14.0, 318.0, 150.0, 4096.0, 13.0, 14.0, 383.0, 180.0, 4955.0, 11.5, 12.0, 400.0, 170.0, 4746.0, 12.0, 13.0, 400.0, 175.0, 5140.0, 12.0, 13.0, 258.0, 110.0, 2962.0, 13.5, 18.0, 140.0, 72.0, 2408.0, 19.0, 22.0, 250.0, 100.0, 3282.0, 15.0, 19.0, 250.0, 88.0, 3139.0, 14.5, 18.0, 122.0, 86.0, 2220.0, 14.0, 23.0, 116.0, 90.0, 2123.0, 14.0, 28.0, 79.0, 70.0, 2074.0, 19.5, 30.0, 88.0, 76.0, 2065.0, 14.5, 30.0, 71.0, 65.0, 1773.0, 19.0, 31.0, 72.0, 69.0, 1613.0, 18.0, 35.0, 97.0, 60.0, 1834.0, 19.0, 27.0, 91.0, 70.0, 1955.0, 20.5, 26.0, 113.0, 95.0, 2278.0, 15.5, 24.0, 97.5, 80.0, 2126.0, 17.0, 25.0, 97.0, 54.0, 2254.0, 23.5, 23.0, 140.0, 90.0, 2408.0, 19.5, 20.0, 122.0, 86.0, 2226.0, 16.5, 21.0, 350.0, 165.0, 4274.0, 12.0, 13.0, 400.0, 175.0, 4385.0, 12.0, 14.0, 318.0, 150.0, 4135.0, 13.5, 15.0, 351.0, 153.0, 4129.0, 13.0, 14.0, 304.0, 150.0, 3672.0, 11.5, 17.0, 429.0, 208.0, 4633.0, 11.0, 11.0, 350.0, 155.0, 4502.0, 13.5, 13.0, 350.0, 160.0, 4456.0, 13.5, 12.0, 400.0, 190.0, 4422.0, 12.5, 13.0, 70.0, 97.0, 2330.0, 13.5, 19.0, 304.0, 150.0, 3892.0, 12.5, 15.0, 307.0, 130.0, 4098.0, 14.0, 13.0, 302.0, 140.0, 4294.0, 16.0, 13.0, 318.0, 150.0, 4077.0, 14.0, 14.0, 121.0, 112.0, 2933.0, 14.5, 18.0, 121.0, 76.0, 2511.0, 18.0, 22.0, 120.0, 87.0, 2979.0, 19.5, 21.0, 96.0, 69.0, 2189.0, 18.0, 26.0, 122.0, 86.0, 2395.0, 16.0, 22.0, 97.0, 92.0, 2288.0, 17.0, 28.0, 120.0, 97.0, 2506.0, 14.5, 23.0, 98.0, 80.0, 2164.0, 15.0, 28.0, 97.0, 88.0, 2100.0, 16.5, 27.0, 350.0, 175.0, 4100.0, 13.0, 13.0, 304.0, 150.0, 3672.0, 11.5, 14.0, 350.0, 145.0, 3988.0, 13.0, 13.0, 302.0, 137.0, 4042.0, 14.5, 14.0, 318.0, 150.0, 3777.0, 12.5, 15.0, 429.0, 198.0, 4952.0, 11.5, 12.0, 400.0, 150.0, 4464.0, 12.0, 13.0, 351.0, 158.0, 4363.0, 13.0, 13.0, 318.0, 150.0, 4237.0, 14.5, 14.0, 440.0, 215.0, 4735.0, 11.0, 13.0, 455.0, 225.0, 4951.0, 11.0, 12.0, 360.0, 175.0, 3821.0, 11.0, 13.0, 225.0, 105.0, 3121.0, 16.5, 18.0, 250.0, 100.0, 3278.0, 18.0, 16.0, 232.0, 100.0, 2945.0, 16.0, 18.0, 250.0, 88.0, 3021.0, 16.5, 18.0, 198.0, 95.0, 2904.0, 16.0, 23.0, 97.0, 46.0, 1950.0, 21.0, 26.0, 400.0, 150.0, 4997.0, 14.0, 11.0, 400.0, 167.0, 4906.0, 12.5, 12.0, 360.0, 170.0, 4654.0, 13.0, 13.0, 350.0, 180.0, 4499.0, 12.5, 12.0, 232.0, 100.0, 2789.0, 15.0, 18.0, 97.0, 88.0, 2279.0, 19.0, 20.0, 140.0, 72.0, 2401.0, 19.5, 21.0, 108.0, 94.0, 2379.0, 16.5, 22.0, 70.0, 90.0, 2124.0, 13.5, 18.0, 122.0, 85.0, 2310.0, 18.5, 19.0, 155.0, 107.0, 2472.0, 14.0, 21.0, 98.0, 90.0, 2265.0, 15.5, 26.0, 350.0, 145.0, 4082.0, 13.0, 15.0, 400.0, 230.0, 4278.0, 9.5, 16.0, 68.0, 49.0, 1867.0, 19.5, 29.0, 116.0, 75.0, 2158.0, 15.5, 24.0, 114.0, 91.0, 2582.0, 14.0, 20.0, 121.0, 112.0, 2868.0, 15.5, 19.0, 318.0, 150.0, 3399.0, 11.0, 15.0, 121.0, 110.0, 2660.0, 14.0, 24.0, 156.0, 122.0, 2807.0, 13.5, 20.0, 350.0, 180.0, 3664.0, 11.0, 11.0, 198.0, 95.0, 3102.0, 16.5, 20.0, 232.0, 100.0, 2901.0, 16.0, 19.0, 250.0, 100.0, 3336.0, 17.0, 15.0, 79.0, 67.0, 1950.0, 19.0, 31.0, 122.0, 80.0, 2451.0, 16.5, 26.0, 71.0, 65.0, 1836.0, 21.0, 32.0, 140.0, 75.0, 2542.0, 17.0, 25.0, 250.0, 100.0, 3781.0, 17.0, 16.0, 258.0, 110.0, 3632.0, 18.0, 16.0, 225.0, 105.0, 3613.0, 16.5, 18.0, 302.0, 140.0, 4141.0, 14.0, 16.0, 350.0, 150.0, 4699.0, 14.5, 13.0, 318.0, 150.0, 4457.0, 13.5, 14.0, 302.0, 140.0, 4638.0, 16.0, 14.0, 304.0, 150.0, 4257.0, 15.5, 14.0, 98.0, 83.0, 2219.0, 16.5, 29.0, 79.0, 67.0, 1963.0, 15.5, 26.0, 97.0, 78.0, 2300.0, 14.5, 26.0, 76.0, 52.0, 1649.0, 16.5, 31.0, 83.0, 61.0, 2003.0, 19.0, 32.0, 90.0, 75.0, 2125.0, 14.5, 28.0, 90.0, 75.0, 2108.0, 15.5, 24.0, 116.0, 75.0, 2246.0, 14.0, 26.0, 120.0, 97.0, 2489.0, 15.0, 24.0, 108.0, 93.0, 2391.0, 15.5, 26.0, 79.0, 67.0, 2000.0, 16.0, 31.0, 225.0, 95.0, 3264.0, 16.0, 19.0, 250.0, 105.0, 3459.0, 16.0, 18.0, 250.0, 72.0, 3432.0, 21.0, 15.0, 250.0, 72.0, 3158.0, 19.5, 15.0, 400.0, 170.0, 4668.0, 11.5, 16.0, 350.0, 145.0, 4440.0, 14.0, 15.0, 318.0, 150.0, 4498.0, 14.5, 16.0, 351.0, 148.0, 4657.0, 13.5, 14.0, 231.0, 110.0, 3907.0, 21.0, 17.0, 250.0, 105.0, 3897.0, 18.5, 16.0, 258.0, 110.0, 3730.0, 19.0, 15.0, 225.0, 95.0, 3785.0, 19.0, 18.0, 231.0, 110.0, 3039.0, 15.0, 21.0, 262.0, 110.0, 3221.0, 13.5, 20.0, 302.0, 129.0, 3169.0, 12.0, 13.0, 97.0, 75.0, 2171.0, 16.0, 29.0, 140.0, 83.0, 2639.0, 17.0, 23.0, 232.0, 100.0, 2914.0, 16.0, 20.0, 140.0, 78.0, 2592.0, 18.5, 23.0, 134.0, 96.0, 2702.0, 13.5, 24.0, 90.0, 71.0, 2223.0, 16.5, 25.0, 119.0, 97.0, 2545.0, 17.0, 24.0, 171.0, 97.0, 2984.0, 14.5, 18.0, 90.0, 70.0, 1937.0, 14.0, 29.0, 232.0, 90.0, 3211.0, 17.0, 19.0, 115.0, 95.0, 2694.0, 15.0, 23.0, 120.0, 88.0, 2957.0, 17.0, 23.0, 121.0, 98.0, 2945.0, 14.5, 22.0, 121.0, 115.0, 2671.0, 13.5, 25.0, 91.0, 53.0, 1795.0, 17.5, 33.0, 107.0, 86.0, 2464.0, 15.5, 28.0, 116.0, 81.0, 2220.0, 16.9, 25.0, 140.0, 92.0, 2572.0, 14.9, 25.0, 98.0, 79.0, 2255.0, 17.7, 26.0, 101.0, 83.0, 2202.0, 15.3, 27.0, 305.0, 140.0, 4215.0, 13.0, 17.5, 318.0, 150.0, 4190.0, 13.0, 16.0, 304.0, 120.0, 3962.0, 13.9, 15.5, 351.0, 152.0, 4215.0, 12.8, 14.5, 225.0, 100.0, 3233.0, 15.4, 22.0, 250.0, 105.0, 3353.0, 14.5, 22.0, 200.0, 81.0, 3012.0, 17.6, 24.0, 232.0, 90.0, 3085.0, 17.6, 22.5, 85.0, 52.0, 2035.0, 22.2, 29.0, 98.0, 60.0, 2164.0, 22.1, 24.5, 90.0, 70.0, 1937.0, 14.2, 29.0, 91.0, 53.0, 1795.0, 17.4, 33.0, 225.0, 100.0, 3651.0, 17.7, 20.0, 250.0, 78.0, 3574.0, 21.0, 18.0, 250.0, 110.0, 3645.0, 16.2, 18.5, 258.0, 95.0, 3193.0, 17.8, 17.5, 97.0, 71.0, 1825.0, 12.2, 29.5, 85.0, 70.0, 1990.0, 17.0, 32.0, 97.0, 75.0, 2155.0, 16.4, 28.0, 140.0, 72.0, 2565.0, 13.6, 26.5, 130.0, 102.0, 3150.0, 15.7, 20.0, 318.0, 150.0, 3940.0, 13.2, 13.0, 120.0, 88.0, 3270.0, 21.9, 19.0, 156.0, 108.0, 2930.0, 15.5, 19.0, 168.0, 120.0, 3820.0, 16.7, 16.5, 350.0, 180.0, 4380.0, 12.1, 16.5, 350.0, 145.0, 4055.0, 12.0, 13.0, 302.0, 130.0, 3870.0, 15.0, 13.0, 318.0, 150.0, 3755.0, 14.0, 13.0, 98.0, 68.0, 2045.0, 18.5, 31.5, 111.0, 80.0, 2155.0, 14.8, 30.0, 79.0, 58.0, 1825.0, 18.6, 36.0, 122.0, 96.0, 2300.0, 15.5, 25.5, 85.0, 70.0, 1945.0, 16.8, 33.5, 305.0, 145.0, 3880.0, 12.5, 17.5, 260.0, 110.0, 4060.0, 19.0, 17.0, 318.0, 145.0, 4140.0, 13.7, 15.5, 302.0, 130.0, 4295.0, 14.9, 15.0, 250.0, 110.0, 3520.0, 16.4, 17.5, 231.0, 105.0, 3425.0, 16.9, 20.5, 225.0, 100.0, 3630.0, 17.7, 19.0, 250.0, 98.0, 3525.0, 19.0, 18.5, 400.0, 180.0, 4220.0, 11.1, 16.0, 350.0, 170.0, 4165.0, 11.4, 15.5, 400.0, 190.0, 4325.0, 12.2, 15.5, 351.0, 149.0, 4335.0, 14.5, 16.0, 97.0, 78.0, 1940.0, 14.5, 29.0, 151.0, 88.0, 2740.0, 16.0, 24.5, 97.0, 75.0, 2265.0, 18.2, 26.0, 140.0, 89.0, 2755.0, 15.8, 25.5, 98.0, 63.0, 2051.0, 17.0, 30.5, 98.0, 83.0, 2075.0, 15.9, 33.5, 97.0, 67.0, 1985.0, 16.4, 30.0, 97.0, 78.0, 2190.0, 14.1, 30.5, 146.0, 97.0, 2815.0, 14.5, 22.0, 121.0, 110.0, 2600.0, 12.8, 21.5, 80.0, 110.0, 2720.0, 13.5, 21.5, 90.0, 48.0, 1985.0, 21.5, 43.1, 98.0, 66.0, 1800.0, 14.4, 36.1, 78.0, 52.0, 1985.0, 19.4, 32.8, 85.0, 70.0, 2070.0, 18.6, 39.4, 91.0, 60.0, 1800.0, 16.4, 36.1, 260.0, 110.0, 3365.0, 15.5, 19.9, 318.0, 140.0, 3735.0, 13.2, 19.4, 302.0, 139.0, 3570.0, 12.8, 20.2, 231.0, 105.0, 3535.0, 19.2, 19.2, 200.0, 95.0, 3155.0, 18.2, 20.5, 200.0, 85.0, 2965.0, 15.8, 20.2, 140.0, 88.0, 2720.0, 15.4, 25.1, 225.0, 100.0, 3430.0, 17.2, 20.5, 232.0, 90.0, 3210.0, 17.2, 19.4, 231.0, 105.0, 3380.0, 15.8, 20.6, 200.0, 85.0, 3070.0, 16.7, 20.8, 225.0, 110.0, 3620.0, 18.7, 18.6, 258.0, 120.0, 3410.0, 15.1, 18.1, 305.0, 145.0, 3425.0, 13.2, 19.2, 231.0, 165.0, 3445.0, 13.4, 17.7, 302.0, 139.0, 3205.0, 11.2, 18.1, 318.0, 140.0, 4080.0, 13.7, 17.5, 98.0, 68.0, 2155.0, 16.5, 30.0, 134.0, 95.0, 2560.0, 14.2, 27.5, 119.0, 97.0, 2300.0, 14.7, 27.2, 105.0, 75.0, 2230.0, 14.5, 30.9, 134.0, 95.0, 2515.0, 14.8, 21.1, 156.0, 105.0, 2745.0, 16.7, 23.2, 151.0, 85.0, 2855.0, 17.6, 23.8, 119.0, 97.0, 2405.0, 14.9, 23.9, 131.0, 103.0, 2830.0, 15.9, 20.3, 163.0, 125.0, 3140.0, 13.6, 17.0, 121.0, 115.0, 2795.0, 15.7, 21.6, 163.0, 133.0, 3410.0, 15.8, 16.2, 89.0, 71.0, 1990.0, 14.9, 31.5, 98.0, 68.0, 2135.0, 16.6, 29.5, 231.0, 115.0, 3245.0, 15.4, 21.5, 200.0, 85.0, 2990.0, 18.2, 19.8, 140.0, 88.0, 2890.0, 17.3, 22.3, 232.0, 90.0, 3265.0, 18.2, 20.2, 225.0, 110.0, 3360.0, 16.6, 20.6, 305.0, 130.0, 3840.0, 15.4, 17.0, 302.0, 129.0, 3725.0, 13.4, 17.6, 351.0, 138.0, 3955.0, 13.2, 16.5, 318.0, 135.0, 3830.0, 15.2, 18.2, 350.0, 155.0, 4360.0, 14.9, 16.9, 351.0, 142.0, 4054.0, 14.3, 15.5, 267.0, 125.0, 3605.0, 15.0, 19.2, 360.0, 150.0, 3940.0, 13.0, 18.5, 89.0, 71.0, 1925.0, 14.0, 31.9, 86.0, 65.0, 1975.0, 15.2, 34.1, 98.0, 80.0, 1915.0, 14.4, 35.7, 121.0, 80.0, 2670.0, 15.0, 27.4, 183.0, 77.0, 3530.0, 20.1, 25.4, 350.0, 125.0, 3900.0, 17.4, 23.0, 141.0, 71.0, 3190.0, 24.8, 27.2, 260.0, 90.0, 3420.0, 22.2, 23.9, 105.0, 70.0, 2200.0, 13.2, 34.2, 105.0, 70.0, 2150.0, 14.9, 34.5, 85.0, 65.0, 2020.0, 19.2, 31.8, 91.0, 69.0, 2130.0, 14.7, 37.3, 151.0, 90.0, 2670.0, 16.0, 28.4, 173.0, 115.0, 2595.0, 11.3, 28.8, 173.0, 115.0, 2700.0, 12.9, 26.8, 151.0, 90.0, 2556.0, 13.2, 33.5, 98.0, 76.0, 2144.0, 14.7, 41.5, 89.0, 60.0, 1968.0, 18.8, 38.1, 98.0, 70.0, 2120.0, 15.5, 32.1, 86.0, 65.0, 2019.0, 16.4, 37.2, 151.0, 90.0, 2678.0, 16.5, 28.0, 140.0, 88.0, 2870.0, 18.1, 26.4, 151.0, 90.0, 3003.0, 20.1, 24.3, 225.0, 90.0, 3381.0, 18.7, 19.1, 97.0, 78.0, 2188.0, 15.8, 34.3, 134.0, 90.0, 2711.0, 15.5, 29.8, 120.0, 75.0, 2542.0, 17.5, 31.3, 119.0, 92.0, 2434.0, 15.0, 37.0, 108.0, 75.0, 2265.0, 15.2, 32.2, 86.0, 65.0, 2110.0, 17.9, 46.6, 156.0, 105.0, 2800.0, 14.4, 27.9, 85.0, 65.0, 2110.0, 19.2, 40.8, 90.0, 48.0, 2085.0, 21.7, 44.3, 90.0, 48.0, 2335.0, 23.7, 43.4, 121.0, 67.0, 2950.0, 19.9, 36.4, 146.0, 67.0, 3250.0, 21.8, 30.0, 91.0, 67.0, 1850.0, 13.8, 44.6, 97.0, 67.0, 2145.0, 18.0, 33.8, 89.0, 62.0, 1845.0, 15.3, 29.8, 168.0, 132.0, 2910.0, 11.4, 32.7, 70.0, 100.0, 2420.0, 12.5, 23.7, 122.0, 88.0, 2500.0, 15.1, 35.0, 107.0, 72.0, 2290.0, 17.0, 32.4, 135.0, 84.0, 2490.0, 15.7, 27.2, 151.0, 84.0, 2635.0, 16.4, 26.6, 156.0, 92.0, 2620.0, 14.4, 25.8, 173.0, 110.0, 2725.0, 12.6, 23.5, 135.0, 84.0, 2385.0, 12.9, 30.0, 79.0, 58.0, 1755.0, 16.9, 39.1, 86.0, 64.0, 1875.0, 16.4, 39.0, 81.0, 60.0, 1760.0, 16.1, 35.1, 97.0, 67.0, 2065.0, 17.8, 32.3, 85.0, 65.0, 1975.0, 19.4, 37.0, 89.0, 62.0, 2050.0, 17.3, 37.7, 91.0, 68.0, 1985.0, 16.0, 34.1, 105.0, 63.0, 2215.0, 14.9, 34.7, 98.0, 65.0, 2045.0, 16.2, 34.4, 98.0, 65.0, 2380.0, 20.7, 29.9, 105.0, 74.0, 2190.0, 14.2, 33.0, 107.0, 75.0, 2210.0, 14.4, 33.7, 108.0, 75.0, 2350.0, 16.8, 32.4, 119.0, 100.0, 2615.0, 14.8, 32.9, 120.0, 74.0, 2635.0, 18.3, 31.6, 141.0, 80.0, 3230.0, 20.4, 28.1, 145.0, 76.0, 3160.0, 19.6, 30.7, 168.0, 116.0, 2900.0, 12.6, 25.4, 146.0, 120.0, 2930.0, 13.8, 24.2, 231.0, 110.0, 3415.0, 15.8, 22.4, 350.0, 105.0, 3725.0, 19.0, 26.6, 200.0, 88.0, 3060.0, 17.1, 20.2, 225.0, 85.0, 3465.0, 16.6, 17.6, 112.0, 88.0, 2605.0, 19.6, 28.0, 112.0, 88.0, 2640.0, 18.6, 27.0, 112.0, 88.0, 2395.0, 18.0, 34.0, 112.0, 85.0, 2575.0, 16.2, 31.0, 135.0, 84.0, 2525.0, 16.0, 29.0, 151.0, 90.0, 2735.0, 18.0, 27.0, 140.0, 92.0, 2865.0, 16.4, 24.0, 105.0, 74.0, 1980.0, 15.3, 36.0, 91.0, 68.0, 2025.0, 18.2, 37.0, 91.0, 68.0, 1970.0, 17.6, 31.0, 105.0, 63.0, 2125.0, 14.7, 38.0, 98.0, 70.0, 2125.0, 17.3, 36.0, 120.0, 88.0, 2160.0, 14.5, 36.0, 107.0, 75.0, 2205.0, 14.5, 36.0, 108.0, 70.0, 2245.0, 16.9, 34.0, 91.0, 67.0, 1965.0, 15.0, 38.0, 91.0, 67.0, 1965.0, 15.7, 32.0, 91.0, 67.0, 1995.0, 16.2, 38.0, 181.0, 110.0, 2945.0, 16.4, 25.0, 262.0, 85.0, 3015.0, 17.0, 38.0, 156.0, 92.0, 2585.0, 14.5, 26.0, 232.0, 112.0, 2835.0, 14.7, 22.0, 144.0, 96.0, 2665.0, 13.9, 32.0, 135.0, 84.0, 2370.0, 13.0, 36.0, 151.0, 90.0, 2950.0, 17.3, 27.0, 140.0, 86.0, 2790.0, 15.6, 27.0, 97.0, 52.0, 2130.0, 24.6, 44.0, 135.0, 84.0, 2295.0, 11.6, 32.0, 120.0, 79.0, 2625.0, 18.6, 28.0, 119.0, 82.0, 2720.0, 19.4, 31.0, }) golang-gonum-v1-gonum-0.14.0/stat/card/000077500000000000000000000000001450372207100175225ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/card/card.go000066400000000000000000000044451450372207100207710ustar00rootroot00000000000000// Copyright ©2019 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 ./generate_64bit.sh package card import ( "fmt" "hash" "math" "reflect" "sync" ) const ( w32 = 32 w64 = 64 ) func alpha(m uint64) float64 { if m < 128 { return alphaValues[m] } return 0.7213 / (1 + 1.079/float64(m)) } var alphaValues = [...]float64{ 16: 0.673, 32: 0.697, 64: 0.709, } func linearCounting(m, v float64) float64 { return m * (math.Log(m) - math.Log(v)) } func max(a, b uint8) uint8 { if a > b { return a } return b } func min(a, b uint8) uint8 { if a < b { return a } return b } func typeNameOf(v interface{}) string { t := reflect.TypeOf(v) var prefix string if t.Kind() == reflect.Ptr { t = t.Elem() prefix = "*" } if t.PkgPath() == "" { return prefix + t.Name() } return prefix + t.PkgPath() + "." + t.Name() } // hashes holds registered hashes. var hashes sync.Map // map[string]userType type userType struct { fn reflect.Value // Holds a func() hash.Hash{32,64}. typ reflect.Type // Type of the returned hash implementation. } // RegisterHash registers a function that returns a new hash.Hash32 or hash.Hash64 // to the name of the type implementing the interface. The value of fn must be a // func() hash.Hash32 or func() hash.Hash64, otherwise RegisterHash will panic. // RegisterHash will panic if there is not a unique mapping from the name to the // returned type. func RegisterHash(fn interface{}) { const invalidType = "card: must register func() hash.Hash32 or func() hash.Hash64" rf := reflect.ValueOf(fn) rt := rf.Type() if rf.Kind() != reflect.Func { panic(invalidType) } if rt.NumIn() != 0 { panic(invalidType) } if rt.NumOut() != 1 { panic(invalidType) } h := rf.Call(nil)[0].Interface() var name string var h32 hash.Hash32 var h64 hash.Hash64 switch rf.Type().Out(0) { case reflect.TypeOf(&h32).Elem(), reflect.TypeOf(&h64).Elem(): name = typeNameOf(h) default: panic(invalidType) } user := userType{fn: rf, typ: reflect.TypeOf(h)} ut, dup := hashes.LoadOrStore(name, user) stored := ut.(userType) if dup && stored.typ != user.typ { panic(fmt.Sprintf("card: registering duplicate types for %q: %s != %s", name, stored.typ, user.typ)) } } golang-gonum-v1-gonum-0.14.0/stat/card/card_test.go000066400000000000000000000323521450372207100220260ustar00rootroot00000000000000// Copyright ©2019 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 card import ( "encoding" "fmt" "hash" "hash/fnv" "io" "strconv" "strings" "sync" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) // exact is an exact cardinality accumulator. type exact map[string]struct{} func (e exact) Write(b []byte) (int, error) { if _, exists := e[string(b)]; exists { return len(b), nil } e[string(b)] = struct{}{} return len(b), nil } func (e exact) Count() float64 { return float64(len(e)) } type counter interface { io.Writer Count() float64 } var counterTests = []struct { name string count float64 counter func() counter tol float64 }{ {name: "exact-1e5", count: 1e5, counter: func() counter { return make(exact) }, tol: 0}, {name: "HyperLogLog32-0-10-FNV-1a", count: 0, counter: func() counter { return mustCounter(NewHyperLogLog32(10, fnv.New32a())) }, tol: 0}, {name: "HyperLogLog64-0-10-FNV-1a", count: 0, counter: func() counter { return mustCounter(NewHyperLogLog64(10, fnv.New64a())) }, tol: 0}, {name: "HyperLogLog32-10-14-FNV-1a", count: 10, counter: func() counter { return mustCounter(NewHyperLogLog32(14, fnv.New32a())) }, tol: 0.0005}, {name: "HyperLogLog32-1e3-4-FNV-1a", count: 1e3, counter: func() counter { return mustCounter(NewHyperLogLog32(4, fnv.New32a())) }, tol: 0.1}, {name: "HyperLogLog32-1e4-6-FNV-1a", count: 1e4, counter: func() counter { return mustCounter(NewHyperLogLog32(6, fnv.New32a())) }, tol: 0.06}, {name: "HyperLogLog32-1e7-8-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog32(8, fnv.New32a())) }, tol: 0.03}, {name: "HyperLogLog64-1e7-8-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog64(8, fnv.New64a())) }, tol: 0.07}, {name: "HyperLogLog32-1e7-10-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog32(10, fnv.New32a())) }, tol: 0.06}, {name: "HyperLogLog64-1e7-10-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog64(10, fnv.New64a())) }, tol: 0.02}, {name: "HyperLogLog32-1e7-14-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog32(14, fnv.New32a())) }, tol: 0.005}, {name: "HyperLogLog64-1e7-14-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog64(14, fnv.New64a())) }, tol: 0.002}, {name: "HyperLogLog32-1e7-16-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog32(16, fnv.New32a())) }, tol: 0.005}, {name: "HyperLogLog64-1e7-16-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog64(16, fnv.New64a())) }, tol: 0.002}, {name: "HyperLogLog64-1e7-20-FNV-1a", count: 1e7, counter: func() counter { return mustCounter(NewHyperLogLog64(20, fnv.New64a())) }, tol: 0.001}, {name: "HyperLogLog64-1e3-20-FNV-1a", count: 1e3, counter: func() counter { return mustCounter(NewHyperLogLog64(20, fnv.New64a())) }, tol: 0.001}, } func mustCounter(c counter, err error) counter { if err != nil { panic(fmt.Sprintf("bad test: %v", err)) } return c } func TestCounters(t *testing.T) { t.Parallel() for _, test := range counterTests { test := test t.Run(test.name, func(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) var dst []byte c := test.counter() for i := 0; i < int(test.count); i++ { dst = strconv.AppendUint(dst[:0], rnd.Uint64(), 16) dst = append(dst, '-') dst = strconv.AppendUint(dst, uint64(i), 16) n, err := c.Write(dst) if n != len(dst) { t.Errorf("unexpected number of bytes written for %s: got:%d want:%d", test.name, n, len(dst)) break } if err != nil { t.Errorf("unexpected error for %s: %v", test.name, err) break } } if got := c.Count(); !scalar.EqualWithinRel(got, test.count, test.tol) { t.Errorf("unexpected count for %s: got:%.0f want:%.0f", test.name, got, test.count) } }) } } func TestUnion(t *testing.T) { t.Parallel() for _, test := range counterTests { if strings.HasPrefix(test.name, "exact") { continue } test := test t.Run(test.name, func(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) var dst []byte var cs [2]counter for j := range cs { cs[j] = test.counter() for i := 0; i < int(test.count); i++ { dst = strconv.AppendUint(dst[:0], rnd.Uint64(), 16) dst = append(dst, '-') dst = strconv.AppendUint(dst, uint64(i), 16) n, err := cs[j].Write(dst) if n != len(dst) { t.Errorf("unexpected number of bytes written for %s: got:%d want:%d", test.name, n, len(dst)) break } if err != nil { t.Errorf("unexpected error for %s: %v", test.name, err) break } } } u := test.counter() var err error switch u := u.(type) { case *HyperLogLog32: err = u.Union(cs[0].(*HyperLogLog32), cs[1].(*HyperLogLog32)) case *HyperLogLog64: err = u.Union(cs[0].(*HyperLogLog64), cs[1].(*HyperLogLog64)) } if err != nil { t.Errorf("unexpected error from Union call: %v", err) } if got := u.Count(); !scalar.EqualWithinRel(got, 2*test.count, 2*test.tol) { t.Errorf("unexpected count for %s: got:%.0f want:%.0f", test.name, got, 2*test.count) } }) } } type resetCounter interface { counter Reset() } var counterResetTests = []struct { name string count int resetCounter func() resetCounter }{ {name: "HyperLogLog32-1e3-4-FNV-1a", count: 1e3, resetCounter: func() resetCounter { return mustResetCounter(NewHyperLogLog32(4, fnv.New32a())) }}, {name: "HyperLogLog64-1e3-4-FNV-1a", count: 1e3, resetCounter: func() resetCounter { return mustResetCounter(NewHyperLogLog64(4, fnv.New64a())) }}, {name: "HyperLogLog32-1e4-6-FNV-1a", count: 1e4, resetCounter: func() resetCounter { return mustResetCounter(NewHyperLogLog32(6, fnv.New32a())) }}, {name: "HyperLogLog64-1e4-6-FNV-1a", count: 1e4, resetCounter: func() resetCounter { return mustResetCounter(NewHyperLogLog64(6, fnv.New64a())) }}, } func mustResetCounter(c resetCounter, err error) resetCounter { if err != nil { panic(fmt.Sprintf("bad test: %v", err)) } return c } func TestResetCounters(t *testing.T) { t.Parallel() var dst []byte for _, test := range counterResetTests { c := test.resetCounter() var counts [2]float64 for k := range counts { rnd := rand.New(rand.NewSource(1)) for i := 0; i < test.count; i++ { dst = strconv.AppendUint(dst[:0], rnd.Uint64(), 16) dst = append(dst, '-') dst = strconv.AppendUint(dst, uint64(i), 16) n, err := c.Write(dst) if n != len(dst) { t.Errorf("unexpected number of bytes written for %s: got:%d want:%d", test.name, n, len(dst)) break } if err != nil { t.Errorf("unexpected error for %s: %v", test.name, err) break } } counts[k] = c.Count() c.Reset() } if counts[0] != counts[1] { t.Errorf("unexpected counts for %s after reset: got:%.0f", test.name, counts) } } } type counterEncoder interface { counter encoding.BinaryMarshaler encoding.BinaryUnmarshaler } var counterEncoderTests = []struct { name string count int src, dst, zdst func() counterEncoder }{ { name: "HyperLogLog32-4-4-FNV-1a", count: 1e3, src: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog32(4, fnv.New32a())) }, dst: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog32(4, fnv.New32a())) }, zdst: func() counterEncoder { return &HyperLogLog32{} }, }, { name: "HyperLogLog32-4-8-FNV-1a", count: 1e3, src: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog32(4, fnv.New32a())) }, dst: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog32(8, fnv.New32a())) }, zdst: func() counterEncoder { return &HyperLogLog32{} }, }, { name: "HyperLogLog32-8-4-FNV-1a", count: 1e3, src: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog32(8, fnv.New32a())) }, dst: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog32(4, fnv.New32a())) }, zdst: func() counterEncoder { return &HyperLogLog32{} }, }, { name: "HyperLogLog64-4-4-FNV-1a", count: 1e3, src: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog64(4, fnv.New64a())) }, dst: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog64(4, fnv.New64a())) }, zdst: func() counterEncoder { return &HyperLogLog64{} }, }, { name: "HyperLogLog64-4-8-FNV-1a", count: 1e3, src: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog64(4, fnv.New64a())) }, dst: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog64(8, fnv.New64a())) }, zdst: func() counterEncoder { return &HyperLogLog64{} }, }, { name: "HyperLogLog64-8-4-FNV-1a", count: 1e3, src: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog64(8, fnv.New64a())) }, dst: func() counterEncoder { return mustCounterEncoder(NewHyperLogLog64(4, fnv.New64a())) }, zdst: func() counterEncoder { return &HyperLogLog64{} }, }, } func mustCounterEncoder(c counterEncoder, err error) counterEncoder { if err != nil { panic(fmt.Sprintf("bad test: %v", err)) } return c } func TestBinaryEncoding(t *testing.T) { t.Parallel() RegisterHash(fnv.New32a) RegisterHash(fnv.New64a) defer func() { hashes = sync.Map{} }() for _, test := range counterEncoderTests { rnd := rand.New(rand.NewSource(1)) src := test.src() for i := 0; i < test.count; i++ { buf := strconv.AppendUint(nil, rnd.Uint64(), 16) buf = append(buf, '-') buf = strconv.AppendUint(buf, uint64(i), 16) n, err := src.Write(buf) if n != len(buf) { t.Errorf("unexpected number of bytes written for %s: got:%d want:%d", test.name, n, len(buf)) break } if err != nil { t.Errorf("unexpected error for %s: %v", test.name, err) break } } buf, err := src.MarshalBinary() if err != nil { t.Errorf("unexpected error marshaling binary for %s: %v", test.name, err) continue } dst := test.dst() err = dst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling binary for %s: %v", test.name, err) continue } zdst := test.zdst() err = zdst.UnmarshalBinary(buf) if err != nil { t.Errorf("unexpected error unmarshaling binary into zero receiver for %s: %v", test.name, err) continue } gotSrc := src.Count() gotDst := dst.Count() gotZdst := zdst.Count() if gotSrc != gotDst { t.Errorf("unexpected count for %s: got:%.0f want:%.0f", test.name, gotDst, gotSrc) } if gotSrc != gotZdst { t.Errorf("unexpected count for %s into zero receiver: got:%.0f want:%.0f", test.name, gotZdst, gotSrc) } } } var invalidRegisterTests = []struct { fn interface{} panics bool }{ {fn: int(0), panics: true}, {fn: func() {}, panics: true}, {fn: func(int) {}, panics: true}, {fn: func() int { return 0 }, panics: true}, {fn: func() hash.Hash { return fnv.New32a() }, panics: true}, {fn: func() hash.Hash32 { return fnv.New32a() }, panics: false}, {fn: func() hash.Hash { return fnv.New64a() }, panics: true}, {fn: func() hash.Hash64 { return fnv.New64a() }, panics: false}, } func TestRegisterInvalid(t *testing.T) { t.Parallel() for _, test := range invalidRegisterTests { var r interface{} func() { defer func() { r = recover() }() RegisterHash(test.fn) }() panicked := r != nil if panicked != test.panics { if panicked { t.Errorf("unexpected panic for %T", test.fn) } else { t.Errorf("expected panic for %T", test.fn) } } } } var rhoQTests = []struct { bits uint q uint8 want uint8 }{ {bits: 0xff, q: 8, want: 1}, {bits: 0xfe, q: 8, want: 1}, {bits: 0x0f, q: 8, want: 5}, {bits: 0x1f, q: 8, want: 4}, {bits: 0x00, q: 8, want: 9}, } func TestRhoQ(t *testing.T) { t.Parallel() for _, test := range rhoQTests { got := rho32q(uint32(test.bits), test.q) if got != test.want { t.Errorf("unexpected rho32q for %0*b: got:%d want:%d", test.q, test.bits, got, test.want) } got = rho64q(uint64(test.bits), test.q) if got != test.want { t.Errorf("unexpected rho64q for %0*b: got:%d want:%d", test.q, test.bits, got, test.want) } } } var counterBenchmarks = []struct { name string count int counter func() counter }{ {name: "exact-1e6", count: 1e6, counter: func() counter { return make(exact) }}, {name: "HyperLogLog32-1e6-8-FNV-1a", count: 1e6, counter: func() counter { return mustCounter(NewHyperLogLog32(8, fnv.New32a())) }}, {name: "HyperLogLog64-1e6-8-FNV-1a", count: 1e6, counter: func() counter { return mustCounter(NewHyperLogLog64(8, fnv.New64a())) }}, {name: "HyperLogLog32-1e6-16-FNV-1a", count: 1e6, counter: func() counter { return mustCounter(NewHyperLogLog32(16, fnv.New32a())) }}, {name: "HyperLogLog64-1e6-16-FNV-1a", count: 1e6, counter: func() counter { return mustCounter(NewHyperLogLog64(16, fnv.New64a())) }}, } func BenchmarkCounters(b *testing.B) { for _, bench := range counterBenchmarks { c := bench.counter() rnd := rand.New(rand.NewSource(1)) var dst []byte b.Run(bench.name, func(b *testing.B) { for i := 0; i < b.N; i++ { for j := 0; j < bench.count; j++ { dst = strconv.AppendUint(dst[:0], rnd.Uint64(), 16) dst = append(dst, '-') dst = strconv.AppendUint(dst, uint64(j), 16) _, _ = c.Write(dst) } } _ = c.Count() }) } } golang-gonum-v1-gonum-0.14.0/stat/card/doc.go000066400000000000000000000004261450372207100206200ustar00rootroot00000000000000// Copyright ©2019 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 card provides cardinality estimation functions. package card // import "gonum.org/v1/gonum/stat/card" golang-gonum-v1-gonum-0.14.0/stat/card/generate_64bit.sh000077500000000000000000000010361450372207100226630ustar00rootroot00000000000000#!/bin/bash echo -e '// Code generated by "go generate gonum.org/v1/gonum/stat/card"; DO NOT EDIT.\n' > hll64.go < hll32.go cat \ | gofmt -r 'HyperLogLog32 -> HyperLogLog64' \ | gofmt -r 'Hash32 -> Hash64' \ | gofmt -r 'Sum32 -> Sum64' \ | gofmt -r 'rho32 -> rho64' \ | gofmt -r 'uint32 -> uint64' \ | gofmt -r 'bits.LeadingZeros32 -> bits.LeadingZeros64' \ \ | sed \ -e 's/\[4, 32\]/[4, 64]/' \ -e 's/rho32/rho64/' \ -e 's/HyperLogLog32/HyperLogLog64/g' \ -e 's/Hash32/Hash64/' \ -e 's/hash32/hash64/' \ -e 's/w32/w64/g' \ >> hll64.gogolang-gonum-v1-gonum-0.14.0/stat/card/hll32.go000066400000000000000000000135601450372207100210020ustar00rootroot00000000000000// Copyright ©2019 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 card import ( "bytes" "encoding/gob" "errors" "fmt" "hash" "math" "math/bits" "reflect" ) // HyperLogLog32 is implements cardinality estimation according to the // HyperLogLog algorithm described in Analysis of Algorithms, pp127–146. type HyperLogLog32 struct { p uint8 m uint32 hash hash.Hash32 register []uint8 } // NewHyperLogLog32 returns a new HyperLogLog32 sketch. The value of prec // must be in the range [4, 32]. NewHyperLogLog32 will allocate a byte slice // that is 2^prec long. func NewHyperLogLog32(prec int, h hash.Hash32) (*HyperLogLog32, error) { // The implementation here is based on the pseudo-code in // "HyperLogLog: the analysis of a near-optimal cardinality // estimation algorithm", figure 3. if prec < 4 || w32 < prec { return nil, errors.New("card: precision out of range") } p := uint8(prec) m := uint32(1) << p return &HyperLogLog32{ p: p, m: m, hash: h, register: make([]byte, m), }, nil } // Write notes the data in b as a single observation into the sketch held by // the receiver. // // Write satisfies the io.Writer interface. If the hash.Hash32 type passed to // NewHyperLogLog32 or SetHash satisfies the hash.Hash contract, Write will always // return a nil error. func (h *HyperLogLog32) Write(b []byte) (int, error) { n, err := h.hash.Write(b) x := h.hash.Sum32() h.hash.Reset() q := w32 - h.p idx := x >> q r := rho32q(x, q) if r > h.register[idx] { h.register[idx] = r } return n, err } // Union places the union of the sketches in a and b into the receiver. // Union will return an error if the precisions or hash functions of a // and b do not match or if the receiver has a hash function that is set // and does not match those of a and b. Hash functions provided by hash.Hash32 // implementations x and y match when reflect.TypeOf(x) == reflect.TypeOf(y). // // If the receiver does not have a set hash function, it can be set after // a call to Union with the SetHash method. func (h *HyperLogLog32) Union(a, b *HyperLogLog32) error { if a.p != b.p { return errors.New("card: mismatched precision") } ta := reflect.TypeOf(b.hash) if reflect.TypeOf(b.hash) != ta { return errors.New("card: mismatched hash function") } if h.hash != nil && reflect.TypeOf(h.hash) != ta { return errors.New("card: mismatched hash function") } if h != a && h != b { *h = HyperLogLog32{p: a.p, m: a.m, hash: h.hash, register: make([]uint8, a.m)} } for i, r := range a.register { h.register[i] = max(r, b.register[i]) } return nil } // SetHash sets the hash function of the receiver if it is nil. SetHash // will return an error if it is called on a receiver with a non-nil // hash function. func (h *HyperLogLog32) SetHash(fn hash.Hash32) error { if h.hash == nil { return errors.New("card: hash function already set") } h.hash = fn return nil } // Count returns an estimate of the cardinality of the set of items written // the receiver. func (h *HyperLogLog32) Count() float64 { var s float64 for _, v := range h.register { s += 1 / float64(uint64(1)<> q r := rho64q(x, q) if r > h.register[idx] { h.register[idx] = r } return n, err } // Union places the union of the sketches in a and b into the receiver. // Union will return an error if the precisions or hash functions of a // and b do not match or if the receiver has a hash function that is set // and does not match those of a and b. Hash functions provided by hash.Hash64 // implementations x and y match when reflect.TypeOf(x) == reflect.TypeOf(y). // // If the receiver does not have a set hash function, it can be set after // a call to Union with the SetHash method. func (h *HyperLogLog64) Union(a, b *HyperLogLog64) error { if a.p != b.p { return errors.New("card: mismatched precision") } ta := reflect.TypeOf(b.hash) if reflect.TypeOf(b.hash) != ta { return errors.New("card: mismatched hash function") } if h.hash != nil && reflect.TypeOf(h.hash) != ta { return errors.New("card: mismatched hash function") } if h != a && h != b { *h = HyperLogLog64{p: a.p, m: a.m, hash: h.hash, register: make([]uint8, a.m)} } for i, r := range a.register { h.register[i] = max(r, b.register[i]) } return nil } // SetHash sets the hash function of the receiver if it is nil. SetHash // will return an error if it is called on a receiver with a non-nil // hash function. func (h *HyperLogLog64) SetHash(fn hash.Hash64) error { if h.hash == nil { return errors.New("card: hash function already set") } h.hash = fn return nil } // Count returns an estimate of the cardinality of the set of items written // the receiver. func (h *HyperLogLog64) Count() float64 { var s float64 for _, v := range h.register { s += 1 / float64(uint64(1)<= k, otherwise Binomial will panic. // No check is made for overflow. func Binomial(n, k int) int { if n < 0 || k < 0 { panic(errNegInput) } if n < k { panic(badSetSize) } // (n,k) = (n, n-k) if k > n/2 { k = n - k } b := 1 for i := 1; i <= k; i++ { b = (n - k + i) * b / i } return b } // GeneralizedBinomial returns the generalized binomial coefficient of (n, k), // defined as // // Γ(n+1) / (Γ(k+1) Γ(n-k+1)) // // where Γ is the Gamma function. GeneralizedBinomial is useful for continuous // relaxations of the binomial coefficient, or when the binomial coefficient value // may overflow int. In the latter case, one may use math/big for an exact // computation. // // n and k must be non-negative with n >= k, otherwise GeneralizedBinomial will panic. func GeneralizedBinomial(n, k float64) float64 { return math.Exp(LogGeneralizedBinomial(n, k)) } // LogGeneralizedBinomial returns the log of the generalized binomial coefficient. // See GeneralizedBinomial for more information. func LogGeneralizedBinomial(n, k float64) float64 { if n < 0 || k < 0 { panic(errNegInput) } if n < k { panic(badSetSize) } a, _ := math.Lgamma(n + 1) b, _ := math.Lgamma(k + 1) c, _ := math.Lgamma(n - k + 1) return a - b - c } // CombinationGenerator generates combinations iteratively. The Combinations // function may be called to generate all combinations collectively. type CombinationGenerator struct { n int k int previous []int remaining int } // NewCombinationGenerator returns a CombinationGenerator for generating the // combinations of k elements from a set of size n. // // n and k must be non-negative with n >= k, otherwise NewCombinationGenerator // will panic. func NewCombinationGenerator(n, k int) *CombinationGenerator { return &CombinationGenerator{ n: n, k: k, remaining: Binomial(n, k), } } // Next advances the iterator if there are combinations remaining to be generated, // and returns false if all combinations have been generated. Next must be called // to initialize the first value before calling Combination or Combination will // panic. The value returned by Combination is only changed during calls to Next. func (c *CombinationGenerator) Next() bool { if c.remaining <= 0 { // Next is called before combination, so c.remaining is set to zero before // Combination is called. Thus, Combination cannot panic on zero, and a // second sentinel value is needed. c.remaining = -1 return false } if c.previous == nil { c.previous = make([]int, c.k) for i := range c.previous { c.previous[i] = i } } else { nextCombination(c.previous, c.n, c.k) } c.remaining-- return true } // Combination returns the current combination. If dst is non-nil, it must have // length k and the result will be stored in-place into dst. If dst // is nil a new slice will be allocated and returned. If all of the combinations // have already been constructed (Next() returns false), Combination will panic. // // Next must be called to initialize the first value before calling Combination // or Combination will panic. The value returned by Combination is only changed // during calls to Next. func (c *CombinationGenerator) Combination(dst []int) []int { if c.remaining == -1 { panic("combin: all combinations have been generated") } if c.previous == nil { panic("combin: Combination called before Next") } if dst == nil { dst = make([]int, c.k) } else if len(dst) != c.k { panic(badInput) } copy(dst, c.previous) return dst } // Combinations generates all of the combinations of k elements from a // set of size n. The returned slice has length Binomial(n,k) and each inner slice // has length k. // // n and k must be non-negative with n >= k, otherwise Combinations will panic. // // CombinationGenerator may alternatively be used to generate the combinations // iteratively instead of collectively, or IndexToCombination for random access. func Combinations(n, k int) [][]int { combins := Binomial(n, k) data := make([][]int, combins) if len(data) == 0 { return data } data[0] = make([]int, k) for i := range data[0] { data[0][i] = i } for i := 1; i < combins; i++ { next := make([]int, k) copy(next, data[i-1]) nextCombination(next, n, k) data[i] = next } return data } // nextCombination generates the combination after s, overwriting the input value. func nextCombination(s []int, n, k int) { for j := k - 1; j >= 0; j-- { if s[j] == n+j-k { continue } s[j]++ for l := j + 1; l < k; l++ { s[l] = s[j] + l - j } break } } // CombinationIndex returns the index of the given combination. // // The functions CombinationIndex and IndexToCombination define a bijection // between the integers and the Binomial(n, k) number of possible combinations. // CombinationIndex returns the inverse of IndexToCombination. // // CombinationIndex panics if comb is not a sorted combination of the first // [0,n) integers, if n or k are negative, or if k is greater than n. func CombinationIndex(comb []int, n, k int) int { if n < 0 || k < 0 { panic(errNegInput) } if n < k { panic(badSetSize) } if len(comb) != k { panic("combin: bad length combination") } if !sort.IntsAreSorted(comb) { panic("combin: input combination is not sorted") } contains := make(map[int]struct{}, k) for _, v := range comb { contains[v] = struct{}{} } if len(contains) != k { panic("combin: comb contains non-unique elements") } // This algorithm iterates in reverse lexicograhpic order. // Flip the index and values to swap the order. rev := make([]int, k) for i, v := range comb { rev[len(comb)-i-1] = n - v - 1 } idx := 0 for i, v := range rev { if v >= i+1 { idx += Binomial(v, i+1) } } return Binomial(n, k) - 1 - idx } // IndexToCombination returns the combination corresponding to the given index. // // The functions CombinationIndex and IndexToCombination define a bijection // between the integers and the Binomial(n, k) number of possible combinations. // IndexToCombination returns the inverse of CombinationIndex (up to the order // of the elements). // // The combination is stored in-place into dst if dst is non-nil, otherwise // a new slice is allocated and returned. // // IndexToCombination panics if n or k are negative, if k is greater than n, // or if idx is not in [0, Binomial(n,k)-1]. IndexToCombination will also panic // if dst is non-nil and len(dst) is not k. func IndexToCombination(dst []int, idx, n, k int) []int { if idx < 0 || idx >= Binomial(n, k) { panic("combin: invalid index") } if dst == nil { dst = make([]int, k) } else if len(dst) != k { panic(badInput) } // The base algorithm indexes in reverse lexicographic order // flip the values and the index. idx = Binomial(n, k) - 1 - idx for i := range dst { // Find the largest number m such that Binomial(m, k-i) <= idx. // This is one less than the first number such that it is larger. m := sort.Search(n, func(m int) bool { if m < k-i { return false } return Binomial(m, k-i) > idx }) m-- // Normally this is put m into the last free spot, but we // reverse the index and the value. dst[i] = n - m - 1 if m >= k-i { idx -= Binomial(m, k-i) } } return dst } // Cartesian returns the Cartesian product of the slices in data. The Cartesian // product of two sets is the set of all combinations of the items. For example, // given the input // // []int{2, 3, 1} // // the returned matrix will be // // [ 0 0 0 ] // [ 0 1 0 ] // [ 0 2 0 ] // [ 1 0 0 ] // [ 1 1 0 ] // [ 1 2 0 ] // // Cartesian panics if any of the provided lengths are less than 1. func Cartesian(lens []int) [][]int { rows := Card(lens) if rows == 0 { panic("combin: empty lengths") } out := make([][]int, rows) for i := 0; i < rows; i++ { out[i] = SubFor(nil, i, lens) } return out } // Card computes the cardinality of the multi-dimensional space whose dimensions have size specified by dims // All length values must be positive, otherwise this will panic. func Card(dims []int) int { if len(dims) == 0 { return 0 } card := 1 for _, v := range dims { if v < 0 { panic("combin: length less than zero") } card *= v } return card } // NewCartesianGenerator returns a CartesianGenerator for iterating over Cartesian products which are generated on the fly. // All values in lens must be positive, otherwise this will panic. func NewCartesianGenerator(lens []int) *CartesianGenerator { return &CartesianGenerator{ lens: lens, rows: Card(lens), idx: -1, } } // CartesianGenerator iterates over a Cartesian product set. type CartesianGenerator struct { lens []int rows int idx int } // Next moves to the next product of the Cartesian set. // It returns false if the generator reached the end of the Cartesian set end. func (g *CartesianGenerator) Next() bool { if g.idx+1 < g.rows { g.idx++ return true } g.idx = g.rows return false } // Product generates one product of the Cartesian set according to the current index which is increased by Next(). // Next needs to be called at least one time before this method, otherwise it will panic. func (g *CartesianGenerator) Product(dst []int) []int { return SubFor(dst, g.idx, g.lens) } // IdxFor converts a multi-dimensional index into a linear index for a // multi-dimensional space. sub specifies the index for each dimension, and dims // specifies the size of each dimension. IdxFor is the inverse of SubFor. // IdxFor panics if any of the entries of sub are negative, any of the entries // of dim are non-positive, or if sub[i] >= dims[i] for any i. func IdxFor(sub, dims []int) int { // The index returned is "row-major", that is the last index of sub is // continuous. var idx int stride := 1 for i := len(dims) - 1; i >= 0; i-- { v := sub[i] d := dims[i] if d <= 0 { panic(errNonpositiveDimension) } if v < 0 || v >= d { panic("combin: invalid subscript") } idx += v * stride stride *= d } return idx } // SubFor returns the multi-dimensional subscript for the input linear index to // the multi-dimensional space. dims specifies the size of each dimension, and // idx specifies the linear index. SubFor is the inverse of IdxFor. // // If sub is non-nil the result is stored in-place into sub, and SubFor will panic // if len(sub) != len(dims). If sub is nil a new slice of the appropriate length // is allocated. SubFor panics if idx < 0 or if idx is greater than or equal to // the product of the dimensions. func SubFor(sub []int, idx int, dims []int) []int { if sub == nil { sub = make([]int, len(dims)) } if len(sub) != len(dims) { panic(badInput) } if idx < 0 { panic(errNegInput) } stride := 1 for i := len(dims) - 1; i >= 1; i-- { stride *= dims[i] } for i := 0; i < len(dims)-1; i++ { v := idx / stride d := dims[i] if d < 0 { panic(errNonpositiveDimension) } if v >= dims[i] { panic("combin: index too large") } sub[i] = v idx -= v * stride stride /= dims[i+1] } if idx > dims[len(sub)-1] { panic("combin: index too large") } sub[len(sub)-1] = idx return sub } // NumPermutations returns the number of permutations when selecting k // objects from a set of n objects when the selection order matters. // No check is made for overflow. // // NumPermutations panics if either n or k is negative, or if k is // greater than n. func NumPermutations(n, k int) int { if n < 0 { panic("combin: n is negative") } if k < 0 { panic("combin: k is negative") } if k > n { panic("combin: k is greater than n") } p := 1 for i := n - k + 1; i <= n; i++ { p *= i } return p } // Permutations generates all of the permutations of k elements from a // set of size n. The returned slice has length NumPermutations(n, k) // and each inner slice has length k. // // n and k must be non-negative with n >= k, otherwise Permutations will panic. // // PermutationGenerator may alternatively be used to generate the permutations // iteratively instead of collectively, or IndexToPermutation for random access. func Permutations(n, k int) [][]int { nPerms := NumPermutations(n, k) data := make([][]int, nPerms) if len(data) == 0 { return data } for i := 0; i < nPerms; i++ { data[i] = IndexToPermutation(nil, i, n, k) } return data } // PermutationGenerator generates permutations iteratively. The Permutations // function may be called to generate all permutations collectively. type PermutationGenerator struct { n int k int nPerm int idx int permutation []int } // NewPermutationGenerator returns a PermutationGenerator for generating the // permutations of k elements from a set of size n. // // n and k must be non-negative with n >= k, otherwise NewPermutationGenerator // will panic. func NewPermutationGenerator(n, k int) *PermutationGenerator { return &PermutationGenerator{ n: n, k: k, nPerm: NumPermutations(n, k), idx: -1, permutation: make([]int, k), } } // Next advances the iterator if there are permutations remaining to be generated, // and returns false if all permutations have been generated. Next must be called // to initialize the first value before calling Permutation or Permutation will // panic. The value returned by Permutation is only changed during calls to Next. func (p *PermutationGenerator) Next() bool { if p.idx >= p.nPerm-1 { p.idx = p.nPerm // so Permutation can panic. return false } p.idx++ IndexToPermutation(p.permutation, p.idx, p.n, p.k) return true } // Permutation returns the current permutation. If dst is non-nil, it must have // length k and the result will be stored in-place into dst. If dst // is nil a new slice will be allocated and returned. If all of the permutations // have already been constructed (Next() returns false), Permutation will panic. // // Next must be called to initialize the first value before calling Permutation // or Permutation will panic. The value returned by Permutation is only changed // during calls to Next. func (p *PermutationGenerator) Permutation(dst []int) []int { if p.idx == p.nPerm { panic("combin: all permutations have been generated") } if p.idx == -1 { panic("combin: Permutation called before Next") } if dst == nil { dst = make([]int, p.k) } else if len(dst) != p.k { panic(badInput) } copy(dst, p.permutation) return dst } // PermutationIndex returns the index of the given permutation. // // The functions PermutationIndex and IndexToPermutation define a bijection // between the integers and the NumPermutations(n, k) number of possible permutations. // PermutationIndex returns the inverse of IndexToPermutation. // // PermutationIndex panics if perm is not a permutation of k of the first // [0,n) integers, if n or k are negative, or if k is greater than n. func PermutationIndex(perm []int, n, k int) int { if n < 0 || k < 0 { panic(errNegInput) } if n < k { panic(badSetSize) } if len(perm) != k { panic("combin: bad length permutation") } contains := make(map[int]struct{}, k) for _, v := range perm { if v < 0 || v >= n { panic("combin: bad element") } contains[v] = struct{}{} } if len(contains) != k { panic("combin: perm contains non-unique elements") } if n == k { // The permutation is the ordering of the elements. return equalPermutationIndex(perm) } // The permutation index is found by finding the combination index and the // equalPermutation index. The combination index is found by just sorting // the elements, and the permutation index is the ordering of the size // of the elements. tmp := make([]int, len(perm)) copy(tmp, perm) idx := make([]int, len(perm)) for i := range idx { idx[i] = i } s := sortInts{tmp, idx} sort.Sort(s) order := make([]int, len(perm)) for i, v := range idx { order[v] = i } combIdx := CombinationIndex(tmp, n, k) permIdx := equalPermutationIndex(order) return combIdx*NumPermutations(k, k) + permIdx } type sortInts struct { data []int idx []int } func (s sortInts) Len() int { return len(s.data) } func (s sortInts) Less(i, j int) bool { return s.data[i] < s.data[j] } func (s sortInts) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] s.idx[i], s.idx[j] = s.idx[j], s.idx[i] } // IndexToPermutation returns the permutation corresponding to the given index. // // The functions PermutationIndex and IndexToPermutation define a bijection // between the integers and the NumPermutations(n, k) number of possible permutations. // IndexToPermutation returns the inverse of PermutationIndex. // // The permutation is stored in-place into dst if dst is non-nil, otherwise // a new slice is allocated and returned. // // IndexToPermutation panics if n or k are negative, if k is greater than n, // or if idx is not in [0, NumPermutations(n,k)-1]. IndexToPermutation will also panic // if dst is non-nil and len(dst) is not k. func IndexToPermutation(dst []int, idx, n, k int) []int { nPerm := NumPermutations(n, k) if idx < 0 || idx >= nPerm { panic("combin: invalid index") } if dst == nil { dst = make([]int, k) } else if len(dst) != k { panic(badInput) } if n == k { indexToEqualPermutation(dst, idx) return dst } // First, we index into the combination (which of the k items to choose) // and then we index into the n == k permutation of those k items. The // indexing acts like a matrix with nComb rows and factorial(k) columns. kPerm := NumPermutations(k, k) combIdx := idx / kPerm permIdx := idx % kPerm comb := IndexToCombination(nil, combIdx, n, k) // Gives us the set of integers. perm := make([]int, len(dst)) indexToEqualPermutation(perm, permIdx) // Gives their order. for i, v := range perm { dst[i] = comb[v] } return dst } // equalPermutationIndex returns the index of the given permutation of the // first k integers. func equalPermutationIndex(perm []int) int { // Note(btracey): This is an n^2 algorithm, but factorial increases // very quickly (25! overflows int64) so this is not a problem in // practice. idx := 0 for i, u := range perm { less := 0 for _, v := range perm[i:] { if v < u { less++ } } idx += less * factorial(len(perm)-i-1) } return idx } // indexToEqualPermutation returns the permutation for the first len(dst) // integers for the given index. func indexToEqualPermutation(dst []int, idx int) { for i := range dst { dst[i] = i } for i := range dst { f := factorial(len(dst) - i - 1) r := idx / f v := dst[i+r] copy(dst[i+1:i+r+1], dst[i:i+r]) dst[i] = v idx %= f } } // factorial returns a!. func factorial(a int) int { f := 1 for i := 2; i <= a; i++ { f *= i } return f } golang-gonum-v1-gonum-0.14.0/stat/combin/combin_test.go000066400000000000000000000174621450372207100227270ustar00rootroot00000000000000// Copyright ©2016 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 combin import ( "math/big" "reflect" "strconv" "testing" "unsafe" "gonum.org/v1/gonum/floats/scalar" ) // intSosMatch returns true if the two slices of slices are equal. func intSosMatch(a, b [][]int) bool { if len(a) != len(b) { return false } for i, s := range a { if len(s) != len(b[i]) { return false } for j, v := range s { if v != b[i][j] { return false } } } return true } var binomialTests = []struct { n, k, ans int }{ {0, 0, 1}, {5, 0, 1}, {5, 1, 5}, {5, 2, 10}, {5, 3, 10}, {5, 4, 5}, {5, 5, 1}, {6, 0, 1}, {6, 1, 6}, {6, 2, 15}, {6, 3, 20}, {6, 4, 15}, {6, 5, 6}, {6, 6, 1}, {20, 0, 1}, {20, 1, 20}, {20, 2, 190}, {20, 3, 1140}, {20, 4, 4845}, {20, 5, 15504}, {20, 6, 38760}, {20, 7, 77520}, {20, 8, 125970}, {20, 9, 167960}, {20, 10, 184756}, {20, 11, 167960}, {20, 12, 125970}, {20, 13, 77520}, {20, 14, 38760}, {20, 15, 15504}, {20, 16, 4845}, {20, 17, 1140}, {20, 18, 190}, {20, 19, 20}, {20, 20, 1}, } func TestBinomial(t *testing.T) { for cas, test := range binomialTests { ans := Binomial(test.n, test.k) if ans != test.ans { t.Errorf("Case %v: Binomial mismatch. Got %v, want %v.", cas, ans, test.ans) } } var ( // Ensure that we have enough space to represent results. // TODO(kortschak): Replace the unsafe.Sizeof(int(0)) expression with // sizeof.Int if https://github.com/golang/go/issues/29982 is // implemented. See also https://github.com/golang/go/issues/40168. n = int(unsafe.Sizeof(int(0))*8 - 3) want big.Int got big.Int ) for k := 0; k <= n; k++ { want.Binomial(int64(n), int64(k)) got.SetInt64(int64(Binomial(n, k))) if want.Cmp(&got) != 0 { t.Errorf("Case n=%v,k=%v: Binomial mismatch for large n. Got %v, want %v.", n, k, got, want) } } } func TestGeneralizedBinomial(t *testing.T) { for cas, test := range binomialTests { ans := GeneralizedBinomial(float64(test.n), float64(test.k)) if !scalar.EqualWithinAbsOrRel(ans, float64(test.ans), 1e-14, 1e-14) { t.Errorf("Case %v: Binomial mismatch. Got %v, want %v.", cas, ans, test.ans) } } } func TestCombinations(t *testing.T) { for cas, test := range []struct { n, k int data [][]int }{ { n: 1, k: 1, data: [][]int{{0}}, }, { n: 2, k: 1, data: [][]int{{0}, {1}}, }, { n: 2, k: 2, data: [][]int{{0, 1}}, }, { n: 3, k: 1, data: [][]int{{0}, {1}, {2}}, }, { n: 3, k: 2, data: [][]int{{0, 1}, {0, 2}, {1, 2}}, }, { n: 3, k: 3, data: [][]int{{0, 1, 2}}, }, { n: 4, k: 1, data: [][]int{{0}, {1}, {2}, {3}}, }, { n: 4, k: 2, data: [][]int{{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}}, }, { n: 4, k: 3, data: [][]int{{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}}, }, { n: 4, k: 4, data: [][]int{{0, 1, 2, 3}}, }, } { data := Combinations(test.n, test.k) if !intSosMatch(data, test.data) { t.Errorf("Cas %v: Generated combinations mismatch. Got %v, want %v.", cas, data, test.data) } } } func TestCombinationGenerator(t *testing.T) { for n := 0; n <= 10; n++ { for k := 1; k <= n; k++ { combinations := Combinations(n, k) cg := NewCombinationGenerator(n, k) genCombs := make([][]int, 0, len(combinations)) for cg.Next() { genCombs = append(genCombs, cg.Combination(nil)) } if !intSosMatch(combinations, genCombs) { t.Errorf("Combinations and generated combinations do not match. n = %v, k = %v", n, k) } } } } func TestCombinationIndex(t *testing.T) { for cas, s := range []struct { n, k int }{ {6, 3}, {4, 4}, {10, 1}, {8, 2}, } { n := s.n k := s.k combs := make(map[string]struct{}) for i := 0; i < Binomial(n, k); i++ { comb := IndexToCombination(nil, i, n, k) idx := CombinationIndex(comb, n, k) if idx != i { t.Errorf("Cas %d: combination mismatch. Want %d, got %d", cas, i, idx) } combs[intSliceToKey(comb)] = struct{}{} } if len(combs) != Binomial(n, k) { t.Errorf("Case %d: not all generated combinations were unique", cas) } } } func intSliceToKey(s []int) string { var str string for _, v := range s { str += strconv.Itoa(v) + "_" } return str } // TestCombinationOrder tests that the different Combinations methods // agree on the iteration order. func TestCombinationOrder(t *testing.T) { n := 7 k := 3 list := Combinations(n, k) for i, v := range list { idx := CombinationIndex(v, n, k) if idx != i { t.Errorf("Combinations and CombinationIndex mismatch") break } } } func TestIdxSubFor(t *testing.T) { for cas, dims := range [][]int{ {2, 2}, {3, 1, 6}, {2, 4, 6, 7}, } { // Loop over all of the indexes. Confirm that the subscripts make sense // and that IdxFor is the converse of SubFor. maxIdx := 1 for _, v := range dims { maxIdx *= v } into := make([]int, len(dims)) for idx := 0; idx < maxIdx; idx++ { sub := SubFor(nil, idx, dims) for i := range sub { if sub[i] < 0 || sub[i] >= dims[i] { t.Errorf("cas %v: bad subscript. dims: %v, sub: %v", cas, dims, sub) } } SubFor(into, idx, dims) if !reflect.DeepEqual(sub, into) { t.Errorf("cas %v: subscript mismatch with supplied slice. Got %v, want %v", cas, into, sub) } idxOut := IdxFor(sub, dims) if idxOut != idx { t.Errorf("cas %v: returned index mismatch. Got %v, want %v", cas, idxOut, idx) } } } } func TestCartesian(t *testing.T) { // First, test with a known return. lens := []int{2, 3, 4} want := [][]int{ {0, 0, 0}, {0, 0, 1}, {0, 0, 2}, {0, 0, 3}, {0, 1, 0}, {0, 1, 1}, {0, 1, 2}, {0, 1, 3}, {0, 2, 0}, {0, 2, 1}, {0, 2, 2}, {0, 2, 3}, {1, 0, 0}, {1, 0, 1}, {1, 0, 2}, {1, 0, 3}, {1, 1, 0}, {1, 1, 1}, {1, 1, 2}, {1, 1, 3}, {1, 2, 0}, {1, 2, 1}, {1, 2, 2}, {1, 2, 3}, } got := Cartesian(lens) if !intSosMatch(want, got) { t.Errorf("Cartesian data mismatch.\nwant:\n%v\ngot:\n%v", want, got) } } func TestNumCartesianProducts(t *testing.T) { want := 6 got := Card([]int{1, 2, 3}) if want != got { t.Errorf("number of Cartesian products mismatch.\nwant:\n%v\ngot:\n%v", want, got) } } func TestCartesianGenerator(t *testing.T) { want := [][]int{ {0, 0, 0}, {0, 0, 1}, {0, 0, 2}, {0, 1, 0}, {0, 1, 1}, {0, 1, 2}, } gen := NewCartesianGenerator([]int{1, 2, 3}) iterations := 0 for gen.Next() { got := gen.Product(nil) if !reflect.DeepEqual(got, want[iterations]) { t.Errorf("Cartesian product does not match. want: %v got: %v", want[iterations], got) } iterations++ } if iterations != len(want) { t.Errorf("Number of products does not match. want: %v got: %v", len(want), iterations) } } func TestPermutationIndex(t *testing.T) { for cas, s := range []struct { n, k int }{ {6, 3}, {4, 4}, {10, 1}, {8, 2}, } { n := s.n k := s.k perms := make(map[string]struct{}) for i := 0; i < NumPermutations(n, k); i++ { perm := IndexToPermutation(nil, i, n, k) idx := PermutationIndex(perm, n, k) if idx != i { t.Errorf("Cas %d: permutation mismatch. Want %d, got %d", cas, i, idx) } perms[intSliceToKey(perm)] = struct{}{} } if len(perms) != NumPermutations(n, k) { t.Errorf("Case %d: not all generated combinations were unique", cas) } } } func TestPermutationGenerator(t *testing.T) { for n := 0; n <= 7; n++ { for k := 1; k <= n; k++ { permutations := Permutations(n, k) pg := NewPermutationGenerator(n, k) genPerms := make([][]int, 0, len(permutations)) for pg.Next() { genPerms = append(genPerms, pg.Permutation(nil)) } if !intSosMatch(permutations, genPerms) { t.Errorf("Permutations and generated permutations do not match. n = %v, k = %v", n, k) } } } } golang-gonum-v1-gonum-0.14.0/stat/combin/combinations_example_test.go000066400000000000000000000141271450372207100256530ustar00rootroot00000000000000// Copyright ©2019 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 combin_test import ( "fmt" "gonum.org/v1/gonum/stat/combin" ) func ExampleCartesian() { fmt.Println("Generate Cartesian products for given lengths:") lens := []int{1, 2, 3} list := combin.Cartesian(lens) for i, v := range list { fmt.Println(i, v) } // This is easy, but the number of combinations can be very large, // and generating all at once can use a lot of memory. // For big data sets, consider using CartesianGenerator instead. // Output: // Generate Cartesian products for given lengths: // 0 [0 0 0] // 1 [0 0 1] // 2 [0 0 2] // 3 [0 1 0] // 4 [0 1 1] // 5 [0 1 2] } func ExampleCartesianGenerator() { fmt.Println("Generate products for given lengths:") lens := []int{1, 2, 3} gen := combin.NewCartesianGenerator(lens) // Now loop over all products. var i int for gen.Next() { fmt.Println(i, gen.Product(nil)) i++ } // Output: // Generate products for given lengths: // 0 [0 0 0] // 1 [0 0 1] // 2 [0 0 2] // 3 [0 1 0] // 4 [0 1 1] // 5 [0 1 2] } func ExampleCombinations() { // combin provides several ways to work with the combinations of // different objects. Combinations generates them directly. fmt.Println("Generate list:") n := 5 k := 3 list := combin.Combinations(n, k) for i, v := range list { fmt.Println(i, v) } // This is easy, but the number of combinations can be very large, // and generating all at once can use a lot of memory. // Output: // Generate list: // 0 [0 1 2] // 1 [0 1 3] // 2 [0 1 4] // 3 [0 2 3] // 4 [0 2 4] // 5 [0 3 4] // 6 [1 2 3] // 7 [1 2 4] // 8 [1 3 4] // 9 [2 3 4] } func ExampleCombinations_index() { // The integer slices returned from Combinations can be used to index // into a data structure. data := []string{"a", "b", "c", "d", "e"} cs := combin.Combinations(len(data), 2) for _, c := range cs { fmt.Printf("%s%s\n", data[c[0]], data[c[1]]) } // Output: // ab // ac // ad // ae // bc // bd // be // cd // ce // de } func ExampleCombinationGenerator() { // combin provides several ways to work with the combinations of // different objects. CombinationGenerator constructs an iterator // for the combinations. n := 5 k := 3 gen := combin.NewCombinationGenerator(n, k) idx := 0 for gen.Next() { fmt.Println(idx, gen.Combination(nil)) // can also store in-place. idx++ } // Output: // 0 [0 1 2] // 1 [0 1 3] // 2 [0 1 4] // 3 [0 2 3] // 4 [0 2 4] // 5 [0 3 4] // 6 [1 2 3] // 7 [1 2 4] // 8 [1 3 4] // 9 [2 3 4] } func ExampleIndexToCombination() { // combin provides several ways to work with the combinations of // different objects. IndexToCombination allows random access into // the combination order. Combined with CombinationIndex this // provides a correspondence between integers and combinations. n := 5 k := 3 comb := make([]int, k) for i := 0; i < combin.Binomial(n, k); i++ { combin.IndexToCombination(comb, i, n, k) // can also use nil. idx := combin.CombinationIndex(comb, n, k) fmt.Println(i, comb, idx) } // Output: // 0 [0 1 2] 0 // 1 [0 1 3] 1 // 2 [0 1 4] 2 // 3 [0 2 3] 3 // 4 [0 2 4] 4 // 5 [0 3 4] 5 // 6 [1 2 3] 6 // 7 [1 2 4] 7 // 8 [1 3 4] 8 // 9 [2 3 4] 9 } func ExamplePermutations() { // combin provides several ways to work with the permutations of // different objects. Permutations generates them directly. fmt.Println("Generate list:") n := 4 k := 3 list := combin.Permutations(n, k) for i, v := range list { fmt.Println(i, v) } // This is easy, but the number of permutations can be very large, // and generating all at once can use a lot of memory. // Output: // Generate list: // 0 [0 1 2] // 1 [0 2 1] // 2 [1 0 2] // 3 [1 2 0] // 4 [2 0 1] // 5 [2 1 0] // 6 [0 1 3] // 7 [0 3 1] // 8 [1 0 3] // 9 [1 3 0] // 10 [3 0 1] // 11 [3 1 0] // 12 [0 2 3] // 13 [0 3 2] // 14 [2 0 3] // 15 [2 3 0] // 16 [3 0 2] // 17 [3 2 0] // 18 [1 2 3] // 19 [1 3 2] // 20 [2 1 3] // 21 [2 3 1] // 22 [3 1 2] // 23 [3 2 1] } func ExamplePermutations_index() { // The integer slices returned from Permutations can be used to index // into a data structure. data := []string{"a", "b", "c", "d"} cs := combin.Permutations(len(data), 2) for _, c := range cs { fmt.Printf("%s%s\n", data[c[0]], data[c[1]]) } // Output: // ab // ba // ac // ca // ad // da // bc // cb // bd // db // cd // dc } func ExamplePermutationGenerator() { // combin provides several ways to work with the permutations of // different objects. PermutationGenerator constructs an iterator // for the permutations. n := 4 k := 3 gen := combin.NewPermutationGenerator(n, k) idx := 0 for gen.Next() { fmt.Println(idx, gen.Permutation(nil)) // can also store in-place. idx++ } // Output: // 0 [0 1 2] // 1 [0 2 1] // 2 [1 0 2] // 3 [1 2 0] // 4 [2 0 1] // 5 [2 1 0] // 6 [0 1 3] // 7 [0 3 1] // 8 [1 0 3] // 9 [1 3 0] // 10 [3 0 1] // 11 [3 1 0] // 12 [0 2 3] // 13 [0 3 2] // 14 [2 0 3] // 15 [2 3 0] // 16 [3 0 2] // 17 [3 2 0] // 18 [1 2 3] // 19 [1 3 2] // 20 [2 1 3] // 21 [2 3 1] // 22 [3 1 2] // 23 [3 2 1] } func ExampleIndexToPermutation() { // combin provides several ways to work with the permutations of // different objects. IndexToPermutation allows random access into // the permutation order. Combined with PermutationIndex this // provides a correspondence between integers and permutations. n := 4 k := 3 comb := make([]int, k) for i := 0; i < combin.NumPermutations(n, k); i++ { combin.IndexToPermutation(comb, i, n, k) // can also use nil. idx := combin.PermutationIndex(comb, n, k) fmt.Println(i, comb, idx) } // Output: // 0 [0 1 2] 0 // 1 [0 2 1] 1 // 2 [1 0 2] 2 // 3 [1 2 0] 3 // 4 [2 0 1] 4 // 5 [2 1 0] 5 // 6 [0 1 3] 6 // 7 [0 3 1] 7 // 8 [1 0 3] 8 // 9 [1 3 0] 9 // 10 [3 0 1] 10 // 11 [3 1 0] 11 // 12 [0 2 3] 12 // 13 [0 3 2] 13 // 14 [2 0 3] 14 // 15 [2 3 0] 15 // 16 [3 0 2] 16 // 17 [3 2 0] 17 // 18 [1 2 3] 18 // 19 [1 3 2] 19 // 20 [2 1 3] 20 // 21 [2 3 1] 21 // 22 [3 1 2] 22 // 23 [3 2 1] 23 } golang-gonum-v1-gonum-0.14.0/stat/combin/doc.go000066400000000000000000000005041450372207100211530ustar00rootroot00000000000000// 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 combin implements routines involving combinatorics (permutations, // combinations, etc.). package combin // import "gonum.org/v1/gonum/stat/combin" golang-gonum-v1-gonum-0.14.0/stat/distmat/000077500000000000000000000000001450372207100202565ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/distmat/doc.go000066400000000000000000000004461450372207100213560ustar00rootroot00000000000000// 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 distmat provides probability distributions over matrices. package distmat // import "gonum.org/v1/gonum/stat/distmat" golang-gonum-v1-gonum-0.14.0/stat/distmat/general.go000066400000000000000000000004161450372207100222230ustar00rootroot00000000000000// Copyright ©2016 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 distmat const ( badDim = "distmat: dimension mismatch" zeroDim = "distmat: zero dimension" ) golang-gonum-v1-gonum-0.14.0/stat/distmat/permutation.go000066400000000000000000000024331450372207100231560ustar00rootroot00000000000000// Copyright ©2020 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 distmat import ( "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" ) // UniformPermutation is a uniform distribution over the n! // permutation matrices of size n×n for a given n. type UniformPermutation struct { rnd *rand.Rand indices []int } // NewUniformPermutation constructs a new permutation matrix // generator using the given random source. func NewUniformPermutation(src rand.Source) *UniformPermutation { return &UniformPermutation{rnd: rand.New(src)} } // PermTo sets the given matrix to be a random permutation matrix. // It does not zero the destination's elements, so it is the responsibility // of the caller to ensure it is correctly conditioned prior to the call. // // PermTo panics if dst is not square. func (p *UniformPermutation) PermTo(dst *mat.Dense) { r, c := dst.Dims() if r != c { panic(mat.ErrShape) } if r == 0 { return } if len(p.indices) != r { p.indices = make([]int, r) for k := range p.indices { p.indices[k] = k } } p.rnd.Shuffle(r, func(i, j int) { p.indices[i], p.indices[j] = p.indices[j], p.indices[i] }) for i, j := range p.indices { dst.Set(i, j, 1) } } golang-gonum-v1-gonum-0.14.0/stat/distmat/permutation_test.go000066400000000000000000000021321450372207100242110ustar00rootroot00000000000000// Copyright ©2020 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 distmat import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" ) func TestUniformPermutation(t *testing.T) { up := NewUniformPermutation(rand.NewSource(1)) for _, n := range []int{10, 32, 64, 100} { m := mat.NewDense(n, n, nil) up.PermTo(m) // Test that each row and column satisfies the permutation matrix // invariant that all rows and columns have a single unit element // and the remaining elements are zero. for i := 0; i < n; i++ { checkHasSingleUnitElement(t, "row", i, mat.Row(nil, i, m)) checkHasSingleUnitElement(t, "col", i, mat.Col(nil, i, m)) } } } func checkHasSingleUnitElement(t *testing.T, dir string, n int, v []float64) { t.Helper() var sum float64 for i, x := range v { switch x { case 0, 1: sum += x default: t.Errorf("unexpected value in %s %d position %d: %v", dir, n, i, v) } } if sum != 1 { t.Errorf("%s %d is not a valid vector: %v", dir, n, v) } } golang-gonum-v1-gonum-0.14.0/stat/distmat/unit_vector.go000066400000000000000000000022601450372207100231460ustar00rootroot00000000000000// Copyright ©2020 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 distmat import ( "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distuv" ) // UnitVector is a uniform distribution over the surface of a sphere. type UnitVector struct { norm distuv.Normal } // NewUnitVector constructs a unit vector generator. func NewUnitVector(src rand.Source) *UnitVector { return &UnitVector{norm: distuv.Normal{Mu: 0, Sigma: 1, Src: src}} } // UnitVecTo sets dst to be a random unit-length vector. // // This uses the algorithm of Mueller from: // https://dl.acm.org/doi/10.1145/377939.377946 // and summarized at: // https://mathworld.wolfram.com/HyperspherePointPicking.html // // UnitVecTo panics if dst has 0 length. func (u *UnitVector) UnitVecTo(dst *mat.VecDense) { r := dst.Len() if r == 0 { panic(zeroDim) } for { for i := 0; i < r; i++ { dst.SetVec(i, u.norm.Rand()) } l := mat.Norm(dst, 2) // Use l only if it is not too short. Otherwise try again. const minLength = 1e-5 if l > minLength { dst.ScaleVec(1/l, dst) return } } } golang-gonum-v1-gonum-0.14.0/stat/distmat/unit_vector_example_test.go000066400000000000000000000023201450372207100257150ustar00rootroot00000000000000// Copyright ©2020 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 distmat_test import ( "fmt" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distmat" ) // ExampleUnitVector uses the UnitVector distribution to take // a random walk in n-space. At the end it computes how far // from the origin the walk finished. func ExampleUnitVector() { src := rand.NewSource(1) rnd := rand.New(src) dist := distmat.NewUnitVector(src) // Draw a random dimension for the space to walk through. nDim := 1 + rnd.Intn(100) // Vectors to hold the current position and next step. position := mat.NewVecDense(nDim, nil) step := mat.NewVecDense(nDim, nil) // Draw a random number of steps to take. nSteps := 1 + rnd.Intn(100) for i := 0; i < nSteps; i++ { // Draw a random step and update the position. dist.UnitVecTo(step) position.AddVec(position, step) } // Finally compute distance from the origin. distance := mat.Norm(position, 2) fmt.Printf("took %d steps in %d-space, walked %1.1f in total", nSteps, nDim, distance) // Output: // took 22 steps in 52-space, walked 5.3 in total } golang-gonum-v1-gonum-0.14.0/stat/distmat/unit_vector_test.go000066400000000000000000000023241450372207100242060ustar00rootroot00000000000000// Copyright ©2020 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 distmat import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func TestUnitVector(t *testing.T) { u := NewUnitVector(rand.NewSource(1)) for _, d := range []int{10, 32, 64, 100} { v := mat.NewVecDense(d, nil) u.UnitVecTo(v) l := mat.Norm(v, 2) if !scalar.EqualWithinAbs(l, 1.0, 1e-12) { t.Errorf("expected length 1 but got %f", l) } } } func TestUnitVectorStats(t *testing.T) { n := 1e7 u := NewUnitVector(rand.NewSource(1)) for _, d := range []int{1, 2, 3} { v := mat.NewVecDense(d, nil) tot := mat.NewVecDense(d, nil) for i := 0; i < int(n); i++ { u.UnitVecTo(v) tot.AddVec(tot, v) } tot.ScaleVec(1/n, tot) // Each dimension should average out to 0. for i := 0; i < d; i++ { if !scalar.EqualWithinAbs(tot.AtVec(i), 0.0, 1e-3) { t.Errorf("expected average entry 0 but got %f", tot.AtVec(i)) } } l := mat.Norm(tot, 2) // And the length should be 0. if !scalar.EqualWithinAbs(l, 0.0, 1e-3) { t.Errorf("expected length 0 but got %f", l) } } } golang-gonum-v1-gonum-0.14.0/stat/distmat/wishart.go000066400000000000000000000133441450372207100222730ustar00rootroot00000000000000// Copyright ©2016 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 distmat import ( "math" "sync" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/mathext" "gonum.org/v1/gonum/stat/distuv" ) // Wishart is a distribution over d×d positive symmetric definite matrices. It // is parametrized by a scalar degrees of freedom parameter ν and a d×d positive // definite matrix V. // // The Wishart PDF is given by // // p(X) = [|X|^((ν-d-1)/2) * exp(-tr(V^-1 * X)/2)] / [2^(ν*d/2) * |V|^(ν/2) * Γ_d(ν/2)] // // where X is a d×d PSD matrix, ν > d-1, |·| denotes the determinant, tr is the // trace and Γ_d is the multivariate gamma function. // // See https://en.wikipedia.org/wiki/Wishart_distribution for more information. type Wishart struct { nu float64 src rand.Source dim int cholv mat.Cholesky logdetv float64 upper mat.TriDense once sync.Once v *mat.SymDense // only stored if needed } // NewWishart returns a new Wishart distribution with the given shape matrix and // degrees of freedom parameter. NewWishart returns whether the creation was // successful. // // NewWishart panics if nu <= d - 1 where d is the order of v. func NewWishart(v mat.Symmetric, nu float64, src rand.Source) (*Wishart, bool) { dim := v.SymmetricDim() if nu <= float64(dim-1) { panic("wishart: nu must be greater than dim-1") } var chol mat.Cholesky ok := chol.Factorize(v) if !ok { return nil, false } var u mat.TriDense chol.UTo(&u) w := &Wishart{ nu: nu, src: src, dim: dim, cholv: chol, logdetv: chol.LogDet(), upper: u, } return w, true } // MeanSymTo calculates the mean matrix of the distribution in and stores it in dst. // If dst is empty, it is resized to be an d×d symmetric matrix where d is the order // of the receiver. When dst is non-empty, MeanSymTo panics if dst is not d×d. func (w *Wishart) MeanSymTo(dst *mat.SymDense) { if dst.IsEmpty() { dst.ReuseAsSym(w.dim) } else if dst.SymmetricDim() != w.dim { panic(badDim) } w.setV() dst.CopySym(w.v) dst.ScaleSym(w.nu, dst) } // ProbSym returns the probability of the symmetric matrix x. If x is not positive // definite (the Cholesky decomposition fails), it has 0 probability. func (w *Wishart) ProbSym(x mat.Symmetric) float64 { return math.Exp(w.LogProbSym(x)) } // LogProbSym returns the log of the probability of the input symmetric matrix. // // LogProbSym returns -∞ if the input matrix is not positive definite (the Cholesky // decomposition fails). func (w *Wishart) LogProbSym(x mat.Symmetric) float64 { dim := x.SymmetricDim() if dim != w.dim { panic(badDim) } var chol mat.Cholesky ok := chol.Factorize(x) if !ok { return math.Inf(-1) } return w.logProbSymChol(&chol) } // LogProbSymChol returns the log of the probability of the input symmetric matrix // given its Cholesky decomposition. func (w *Wishart) LogProbSymChol(cholX *mat.Cholesky) float64 { dim := cholX.SymmetricDim() if dim != w.dim { panic(badDim) } return w.logProbSymChol(cholX) } func (w *Wishart) logProbSymChol(cholX *mat.Cholesky) float64 { // The PDF is // p(X) = [|X|^((ν-d-1)/2) * exp(-tr(V^-1 * X)/2)] / [2^(ν*d/2) * |V|^(ν/2) * Γ_d(ν/2)] // The LogPDF is thus // (ν-d-1)/2 * log(|X|) - tr(V^-1 * X)/2 - (ν*d/2)*log(2) - ν/2 * log(|V|) - log(Γ_d(ν/2)) logdetx := cholX.LogDet() // Compute tr(V^-1 * X), using the fact that X = Uᵀ * U. var u mat.TriDense cholX.UTo(&u) var vinvx mat.Dense err := w.cholv.SolveTo(&vinvx, u.T()) if err != nil { return math.Inf(-1) } vinvx.Mul(&vinvx, &u) tr := mat.Trace(&vinvx) fnu := float64(w.nu) fdim := float64(w.dim) return 0.5*((fnu-fdim-1)*logdetx-tr-fnu*fdim*math.Ln2-fnu*w.logdetv) - mathext.MvLgamma(0.5*fnu, w.dim) } // RandSymTo generates a random symmetric matrix from the distribution. // If dst is empty, it is resized to be an d×d symmetric matrix where d is the order // of the receiver. When dst is non-empty, RandSymTo panics if dst is not d×d. func (w *Wishart) RandSymTo(dst *mat.SymDense) { var c mat.Cholesky w.RandCholTo(&c) c.ToSym(dst) } // RandCholTo generates the Cholesky decomposition of a random matrix from the distribution. // If dst is empty, it is resized to be an d×d symmetric matrix where d is the order // of the receiver. When dst is non-empty, RandCholTo panics if dst is not d×d. func (w *Wishart) RandCholTo(dst *mat.Cholesky) { // TODO(btracey): Modify the code if the underlying data from dst is exposed // to avoid the dim^2 allocation here. // Use the Bartlett Decomposition, which says that // X ~ L A Aᵀ Lᵀ // Where A is a lower triangular matrix in which the diagonal of A is // generated from the square roots of χ^2 random variables, and the // off-diagonals are generated from standard normal variables. // The above gives the cholesky decomposition of X, where L_x = L A. // // mat works with the upper triagular decomposition, so we would like to do // the same. We can instead say that // U_x = L_xᵀ = (L * A)ᵀ = Aᵀ * Lᵀ = Aᵀ * U // Instead, generate Aᵀ, by using the procedure above, except as an upper // triangular matrix. norm := distuv.Normal{ Mu: 0, Sigma: 1, Src: w.src, } t := mat.NewTriDense(w.dim, mat.Upper, nil) for i := 0; i < w.dim; i++ { v := distuv.ChiSquared{ K: w.nu - float64(i), Src: w.src, }.Rand() t.SetTri(i, i, math.Sqrt(v)) } for i := 0; i < w.dim; i++ { for j := i + 1; j < w.dim; j++ { t.SetTri(i, j, norm.Rand()) } } t.MulTri(t, &w.upper) dst.SetFromU(t) } // setV computes and stores the covariance matrix of the distribution. func (w *Wishart) setV() { w.once.Do(func() { w.v = mat.NewSymDense(w.dim, nil) w.cholv.ToSym(w.v) }) } golang-gonum-v1-gonum-0.14.0/stat/distmat/wishart_test.go000066400000000000000000000060241450372207100233270ustar00rootroot00000000000000// Copyright ©2016 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 distmat import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func TestWishart(t *testing.T) { for c, test := range []struct { v *mat.SymDense nu float64 xs []*mat.SymDense lps []float64 }{ // Logprob data compared with scipy. { v: mat.NewSymDense(2, []float64{1, 0, 0, 1}), nu: 4, xs: []*mat.SymDense{ mat.NewSymDense(2, []float64{0.9, 0.1, 0.1, 0.9}), }, lps: []float64{-4.2357432031863409}, }, { v: mat.NewSymDense(2, []float64{0.8, -0.2, -0.2, 0.7}), nu: 5, xs: []*mat.SymDense{ mat.NewSymDense(2, []float64{0.9, 0.1, 0.1, 0.9}), mat.NewSymDense(2, []float64{0.3, -0.1, -0.1, 0.7}), }, lps: []float64{-4.2476495605333575, -4.9993285370378633}, }, { v: mat.NewSymDense(3, []float64{0.8, 0.3, 0.1, 0.3, 0.7, -0.1, 0.1, -0.1, 7}), nu: 5, xs: []*mat.SymDense{ mat.NewSymDense(3, []float64{1, 0.2, -0.3, 0.2, 0.6, -0.2, -0.3, -0.2, 6}), }, lps: []float64{-11.010982249229421}, }, } { w, ok := NewWishart(test.v, test.nu, nil) if !ok { panic("bad test") } for i, x := range test.xs { lp := w.LogProbSym(x) var chol mat.Cholesky ok := chol.Factorize(x) if !ok { panic("bad test") } lpc := w.LogProbSymChol(&chol) if math.Abs(lp-lpc) > 1e-14 { t.Errorf("Case %d, test %d: probability mismatch between chol and not", c, i) } if !scalar.EqualWithinAbsOrRel(lp, test.lps[i], 1e-14, 1e-14) { t.Errorf("Case %d, test %d: got %v, want %v", c, i, lp, test.lps[i]) } } var ch mat.Cholesky w.RandCholTo(&ch) w.RandCholTo(&ch) var s mat.SymDense w.RandSymTo(&s) w.RandSymTo(&s) } } func TestWishartRand(t *testing.T) { for c, test := range []struct { v *mat.SymDense nu float64 samples int tol float64 }{ { v: mat.NewSymDense(2, []float64{0.8, -0.2, -0.2, 0.7}), nu: 5, samples: 30000, tol: 3e-2, }, { v: mat.NewSymDense(3, []float64{0.8, 0.3, 0.1, 0.3, 0.7, -0.1, 0.1, -0.1, 7}), nu: 5, samples: 30000, tol: 3e-1, }, { v: mat.NewSymDense(4, []float64{ 0.8, 0.3, 0.1, -0.2, 0.3, 0.7, -0.1, 0.4, 0.1, -0.1, 7, 1, -0.2, -0.1, 1, 6}), nu: 6, samples: 30000, tol: 1e-1, }, } { rnd := rand.New(rand.NewSource(1)) dim := test.v.SymmetricDim() w, ok := NewWishart(test.v, test.nu, rnd) if !ok { panic("bad test") } mean := mat.NewSymDense(dim, nil) x := mat.NewSymDense(dim, nil) for i := 0; i < test.samples; i++ { w.RandSymTo(x) x.ScaleSym(1/float64(test.samples), x) mean.AddSym(mean, x) } var trueMean mat.SymDense w.MeanSymTo(&trueMean) if !mat.EqualApprox(&trueMean, mean, test.tol) { t.Errorf("Case %d: Mismatch between estimated and true mean. Got\n%0.4v\nWant\n%0.4v\n", c, mat.Formatted(mean), mat.Formatted(&trueMean)) } } } golang-gonum-v1-gonum-0.14.0/stat/distmv/000077500000000000000000000000001450372207100201175ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/distmv/dirichlet.go000066400000000000000000000100111450372207100224060ustar00rootroot00000000000000// Copyright ©2016 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 distmv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distuv" ) // Dirichlet implements the Dirichlet probability distribution. // // The Dirichlet distribution is a continuous probability distribution that // generates elements over the probability simplex, i.e. ||x||_1 = 1. The Dirichlet // distribution is the conjugate prior to the categorical distribution and the // multivariate version of the beta distribution. The probability of a point x is // // 1/Beta(α) \prod_i x_i^(α_i - 1) // // where Beta(α) is the multivariate Beta function (see the mathext package). // // For more information see https://en.wikipedia.org/wiki/Dirichlet_distribution type Dirichlet struct { alpha []float64 dim int src rand.Source lbeta float64 sumAlpha float64 } // NewDirichlet creates a new dirichlet distribution with the given parameters alpha. // NewDirichlet will panic if len(alpha) == 0, or if any alpha is <= 0. func NewDirichlet(alpha []float64, src rand.Source) *Dirichlet { dim := len(alpha) if dim == 0 { panic(badZeroDimension) } for _, v := range alpha { if v <= 0 { panic("dirichlet: non-positive alpha") } } a := make([]float64, len(alpha)) copy(a, alpha) d := &Dirichlet{ alpha: a, dim: dim, src: src, } d.lbeta, d.sumAlpha = d.genLBeta(a) return d } // CovarianceMatrix calculates the covariance matrix of the distribution, // storing the result in dst. Upon return, the value at element {i, j} of the // covariance matrix is equal to the covariance of the i^th and j^th variables. // // covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])] // // If the dst matrix is empty it will be resized to the correct dimensions, // otherwise dst must match the dimension of the receiver or CovarianceMatrix // will panic. func (d *Dirichlet) CovarianceMatrix(dst *mat.SymDense) { if dst.IsEmpty() { *dst = *(dst.GrowSym(d.dim).(*mat.SymDense)) } else if dst.SymmetricDim() != d.dim { panic("dirichelet: input matrix size mismatch") } scale := 1 / (d.sumAlpha * d.sumAlpha * (d.sumAlpha + 1)) for i := 0; i < d.dim; i++ { ai := d.alpha[i] v := ai * (d.sumAlpha - ai) * scale dst.SetSym(i, i, v) for j := i + 1; j < d.dim; j++ { aj := d.alpha[j] v := -ai * aj * scale dst.SetSym(i, j, v) } } } // genLBeta computes the generalized LBeta function. func (d *Dirichlet) genLBeta(alpha []float64) (lbeta, sumAlpha float64) { for _, alpha := range d.alpha { lg, _ := math.Lgamma(alpha) lbeta += lg sumAlpha += alpha } lg, _ := math.Lgamma(sumAlpha) return lbeta - lg, sumAlpha } // Dim returns the dimension of the distribution. func (d *Dirichlet) Dim() int { return d.dim } // LogProb computes the log of the pdf of the point x. // // It does not check that ||x||_1 = 1. func (d *Dirichlet) LogProb(x []float64) float64 { dim := d.dim if len(x) != dim { panic(badSizeMismatch) } var lprob float64 for i, x := range x { lprob += (d.alpha[i] - 1) * math.Log(x) } lprob -= d.lbeta return lprob } // Mean returns the mean of the probability distribution at x. If the // input argument is nil, a new slice will be allocated, otherwise the result // will be put in-place into the receiver. func (d *Dirichlet) Mean(x []float64) []float64 { x = reuseAs(x, d.dim) copy(x, d.alpha) floats.Scale(1/d.sumAlpha, x) return x } // Prob computes the value of the probability density function at x. func (d *Dirichlet) Prob(x []float64) float64 { return math.Exp(d.LogProb(x)) } // Rand generates a random number according to the distributon. // If the input slice is nil, new memory is allocated, otherwise the result is stored // in place. func (d *Dirichlet) Rand(x []float64) []float64 { x = reuseAs(x, d.dim) for i := range x { x[i] = distuv.Gamma{Alpha: d.alpha[i], Beta: 1, Src: d.src}.Rand() } sum := floats.Sum(x) floats.Scale(1/sum, x) return x } golang-gonum-v1-gonum-0.14.0/stat/distmv/dirichlet_test.go000066400000000000000000000024161450372207100234570ustar00rootroot00000000000000// Copyright ©2016 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 distmv import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" ) func TestDirichlet(t *testing.T) { // Data from Scipy. for cas, test := range []struct { Dir *Dirichlet x []float64 prob float64 }{ { NewDirichlet([]float64{1, 1, 1}, nil), []float64{0.2, 0.3, 0.5}, 2.0, }, { NewDirichlet([]float64{0.6, 10, 8.7}, nil), []float64{0.2, 0.3, 0.5}, 0.24079612737071665, }, } { p := test.Dir.Prob(test.x) if math.Abs(p-test.prob) > 1e-14 { t.Errorf("Probablility mismatch. Case %v. Got %v, want %v", cas, p, test.prob) } } rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { Dir *Dirichlet }{ { NewDirichlet([]float64{1, 1, 1}, rnd), }, { NewDirichlet([]float64{2, 3}, rnd), }, { NewDirichlet([]float64{0.2, 0.3}, rnd), }, { NewDirichlet([]float64{0.2, 4}, rnd), }, { NewDirichlet([]float64{0.1, 4, 20}, rnd), }, } { const n = 1e5 d := test.Dir dim := d.Dim() x := mat.NewDense(n, dim, nil) generateSamples(x, d) checkMean(t, cas, x, d, 1e-2) checkCov(t, cas, x, d, 1e-2) } } golang-gonum-v1-gonum-0.14.0/stat/distmv/doc.go000066400000000000000000000004421450372207100212130ustar00rootroot00000000000000// 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 distmv provides multivariate random distribution types. package distmv // import "gonum.org/v1/gonum/stat/distmv" golang-gonum-v1-gonum-0.14.0/stat/distmv/general.go000066400000000000000000000015361450372207100220700ustar00rootroot00000000000000// 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 distmv const ( badQuantile = "distmv: quantile not between 0 and 1" badReceiver = "distmv: input slice is not nil or the correct length" badSizeMismatch = "distmv: size mismatch" badZeroDimension = "distmv: zero dimensional input" nonPosDimension = "distmv: non-positive dimension input" ) const logTwoPi = 1.8378770664093454835606594728112352797227949472755668 // useAs gets a slice of size n. If len(x) == n, x is returned, if len(x) == 0 // then a slice is returned of length n. func reuseAs(x []float64, n int) []float64 { if len(x) == n { return x } if len(x) == 0 { if cap(x) >= n { return x[:n] } return make([]float64, n) } panic(badReceiver) } golang-gonum-v1-gonum-0.14.0/stat/distmv/general_test.go000066400000000000000000000050241450372207100231230ustar00rootroot00000000000000// 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 distmv import ( "math" "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat" ) type prober interface { Prob(x []float64) float64 LogProb(x []float64) float64 } type probCase struct { dist prober loc []float64 logProb float64 } func testProbability(t *testing.T, cases []probCase) { for _, test := range cases { logProb := test.dist.LogProb(test.loc) if math.Abs(logProb-test.logProb) > 1e-14 { t.Errorf("LogProb mismatch: want: %v, got: %v", test.logProb, logProb) } prob := test.dist.Prob(test.loc) if math.Abs(prob-math.Exp(test.logProb)) > 1e-14 { t.Errorf("Prob mismatch: want: %v, got: %v", math.Exp(test.logProb), prob) } } } func generateSamples(x *mat.Dense, r Rander) { n, _ := x.Dims() for i := 0; i < n; i++ { r.Rand(x.RawRowView(i)) } } type Meaner interface { Mean([]float64) []float64 } func checkMean(t *testing.T, cas int, x *mat.Dense, m Meaner, tol float64) { mean := m.Mean(nil) // Check that the answer is identical when using nil or non-nil. mean2 := make([]float64, len(mean)) m.Mean(mean2) if !floats.Equal(mean, mean2) { t.Errorf("Mean mismatch when providing nil and slice. Case %v", cas) } // Check that the mean matches the samples. r, _ := x.Dims() col := make([]float64, r) meanEst := make([]float64, len(mean)) for i := range meanEst { meanEst[i] = stat.Mean(mat.Col(col, i, x), nil) } if !floats.EqualApprox(mean, meanEst, tol) { t.Errorf("Returned mean and sample mean mismatch. Case %v. Empirical %v, returned %v", cas, meanEst, mean) } } type Cover interface { CovarianceMatrix(*mat.SymDense) } func checkCov(t *testing.T, cas int, x *mat.Dense, c Cover, tol float64) { var cov mat.SymDense c.CovarianceMatrix(&cov) n := cov.SymmetricDim() cov2 := mat.NewSymDense(n, nil) c.CovarianceMatrix(cov2) if !mat.Equal(&cov, cov2) { t.Errorf("Cov mismatch when providing nil and matrix. Case %v", cas) } var cov3 mat.SymDense c.CovarianceMatrix(&cov3) if !mat.Equal(&cov, &cov3) { t.Errorf("Cov mismatch when providing zero matrix. Case %v", cas) } // Check that the covariance matrix matches the samples var covEst mat.SymDense stat.CovarianceMatrix(&covEst, x, nil) if !mat.EqualApprox(&covEst, &cov, tol) { t.Errorf("Return cov and sample cov mismatch. Cas %v.\nGot:\n%0.4v\nWant:\n%0.4v", cas, mat.Formatted(&cov), mat.Formatted(&covEst)) } } golang-gonum-v1-gonum-0.14.0/stat/distmv/interfaces.go000066400000000000000000000021761450372207100225770ustar00rootroot00000000000000// Copyright ©2016 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 distmv // Quantiler returns the multi-dimensional inverse cumulative distribution function. // len(x) must equal len(p), and if x is non-nil, len(x) must also equal len(p). // If x is nil, a new slice will be allocated and returned, otherwise the quantile // will be stored in-place into x. All of the values of p must be between 0 and 1, // or Quantile will panic. type Quantiler interface { Quantile(x, p []float64) []float64 } // LogProber computes the log of the probability of the point x. type LogProber interface { LogProb(x []float64) float64 } // Rander generates a random number according to the distributon. // If the input is non-nil, len(x) must equal len(p) and the dimension of the distribution, // otherwise Quantile will panic. // If the input is nil, a new slice will be allocated and returned. type Rander interface { Rand(x []float64) []float64 } // RandLogProber is both a Rander and a LogProber. type RandLogProber interface { Rander LogProber } golang-gonum-v1-gonum-0.14.0/stat/distmv/normal.go000066400000000000000000000315201450372207100217370ustar00rootroot00000000000000// 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 distmv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat" "gonum.org/v1/gonum/stat/distuv" ) const badInputLength = "distmv: input slice length mismatch" // Normal is a multivariate normal distribution (also known as the multivariate // Gaussian distribution). Its pdf in k dimensions is given by // // (2 π)^(-k/2) |Σ|^(-1/2) exp(-1/2 (x-μ)'Σ^-1(x-μ)) // // where μ is the mean vector and Σ the covariance matrix. Σ must be symmetric // and positive definite. Use NewNormal to construct. type Normal struct { mu []float64 sigma mat.SymDense chol mat.Cholesky logSqrtDet float64 dim int // If src is altered, rnd must be updated. src rand.Source rnd *rand.Rand } // NewNormal creates a new Normal with the given mean and covariance matrix. // NewNormal panics if len(mu) == 0, or if len(mu) != sigma.N. If the covariance // matrix is not positive-definite, the returned boolean is false. func NewNormal(mu []float64, sigma mat.Symmetric, src rand.Source) (*Normal, bool) { if len(mu) == 0 { panic(badZeroDimension) } dim := sigma.SymmetricDim() if dim != len(mu) { panic(badSizeMismatch) } n := &Normal{ src: src, rnd: rand.New(src), dim: dim, mu: make([]float64, dim), } copy(n.mu, mu) ok := n.chol.Factorize(sigma) if !ok { return nil, false } n.sigma = *mat.NewSymDense(dim, nil) n.sigma.CopySym(sigma) n.logSqrtDet = 0.5 * n.chol.LogDet() return n, true } // NewNormalChol creates a new Normal distribution with the given mean and // covariance matrix represented by its Cholesky decomposition. NewNormalChol // panics if len(mu) is not equal to chol.Size(). func NewNormalChol(mu []float64, chol *mat.Cholesky, src rand.Source) *Normal { dim := len(mu) if dim != chol.SymmetricDim() { panic(badSizeMismatch) } n := &Normal{ src: src, rnd: rand.New(src), dim: dim, mu: make([]float64, dim), } n.chol.Clone(chol) copy(n.mu, mu) n.logSqrtDet = 0.5 * n.chol.LogDet() return n } // NewNormalPrecision creates a new Normal distribution with the given mean and // precision matrix (inverse of the covariance matrix). NewNormalPrecision // panics if len(mu) is not equal to prec.SymmetricDim(). If the precision matrix // is not positive-definite, NewNormalPrecision returns nil for norm and false // for ok. func NewNormalPrecision(mu []float64, prec *mat.SymDense, src rand.Source) (norm *Normal, ok bool) { if len(mu) == 0 { panic(badZeroDimension) } dim := prec.SymmetricDim() if dim != len(mu) { panic(badSizeMismatch) } // TODO(btracey): Computing a matrix inverse is generally numerically unstable. // This only has to compute the inverse of a positive definite matrix, which // is much better, but this still loses precision. It is worth considering if // instead the precision matrix should be stored explicitly and used instead // of the Cholesky decomposition of the covariance matrix where appropriate. var chol mat.Cholesky ok = chol.Factorize(prec) if !ok { return nil, false } var sigma mat.SymDense err := chol.InverseTo(&sigma) if err != nil { return nil, false } return NewNormal(mu, &sigma, src) } // ConditionNormal returns the Normal distribution that is the receiver conditioned // on the input evidence. The returned multivariate normal has dimension // n - len(observed), where n is the dimension of the original receiver. The updated // mean and covariance are // // mu = mu_un + sigma_{ob,un}ᵀ * sigma_{ob,ob}^-1 (v - mu_ob) // sigma = sigma_{un,un} - sigma_{ob,un}ᵀ * sigma_{ob,ob}^-1 * sigma_{ob,un} // // where mu_un and mu_ob are the original means of the unobserved and observed // variables respectively, sigma_{un,un} is the unobserved subset of the covariance // matrix, sigma_{ob,ob} is the observed subset of the covariance matrix, and // sigma_{un,ob} are the cross terms. The elements of x_2 have been observed with // values v. The dimension order is preserved during conditioning, so if the value // of dimension 1 is observed, the returned normal represents dimensions {0, 2, ...} // of the original Normal distribution. // // ConditionNormal returns {nil, false} if there is a failure during the update. // Mathematically this is impossible, but can occur with finite precision arithmetic. func (n *Normal) ConditionNormal(observed []int, values []float64, src rand.Source) (*Normal, bool) { if len(observed) == 0 { panic("normal: no observed value") } if len(observed) != len(values) { panic(badInputLength) } for _, v := range observed { if v < 0 || v >= n.Dim() { panic("normal: observed value out of bounds") } } _, mu1, sigma11 := studentsTConditional(observed, values, math.Inf(1), n.mu, &n.sigma) if mu1 == nil { return nil, false } return NewNormal(mu1, sigma11, src) } // CovarianceMatrix stores the covariance matrix of the distribution in dst. // Upon return, the value at element {i, j} of the covariance matrix is equal // to the covariance of the i^th and j^th variables. // // covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])] // // If the dst matrix is empty it will be resized to the correct dimensions, // otherwise dst must match the dimension of the receiver or CovarianceMatrix // will panic. func (n *Normal) CovarianceMatrix(dst *mat.SymDense) { if dst.IsEmpty() { *dst = *(dst.GrowSym(n.dim).(*mat.SymDense)) } else if dst.SymmetricDim() != n.dim { panic("normal: input matrix size mismatch") } dst.CopySym(&n.sigma) } // Dim returns the dimension of the distribution. func (n *Normal) Dim() int { return n.dim } // Entropy returns the differential entropy of the distribution. func (n *Normal) Entropy() float64 { return float64(n.dim)/2*(1+logTwoPi) + n.logSqrtDet } // LogProb computes the log of the pdf of the point x. func (n *Normal) LogProb(x []float64) float64 { dim := n.dim if len(x) != dim { panic(badSizeMismatch) } return normalLogProb(x, n.mu, &n.chol, n.logSqrtDet) } // NormalLogProb computes the log probability of the location x for a Normal // distribution the given mean and Cholesky decomposition of the covariance matrix. // NormalLogProb panics if len(x) is not equal to len(mu), or if len(mu) != chol.Size(). // // This function saves time and memory if the Cholesky decomposition is already // available. Otherwise, the NewNormal function should be used. func NormalLogProb(x, mu []float64, chol *mat.Cholesky) float64 { dim := len(mu) if len(x) != dim { panic(badSizeMismatch) } if chol.SymmetricDim() != dim { panic(badSizeMismatch) } logSqrtDet := 0.5 * chol.LogDet() return normalLogProb(x, mu, chol, logSqrtDet) } // normalLogProb is the same as NormalLogProb, but does not make size checks and // additionally requires log(|Σ|^-0.5) func normalLogProb(x, mu []float64, chol *mat.Cholesky, logSqrtDet float64) float64 { dim := len(mu) c := -0.5*float64(dim)*logTwoPi - logSqrtDet dst := stat.Mahalanobis(mat.NewVecDense(dim, x), mat.NewVecDense(dim, mu), chol) return c - 0.5*dst*dst } // MarginalNormal returns the marginal distribution of the given input variables. // That is, MarginalNormal returns // // p(x_i) = \int_{x_o} p(x_i | x_o) p(x_o) dx_o // // where x_i are the dimensions in the input, and x_o are the remaining dimensions. // See https://en.wikipedia.org/wiki/Marginal_distribution for more information. // // The input src is passed to the call to NewNormal. func (n *Normal) MarginalNormal(vars []int, src rand.Source) (*Normal, bool) { newMean := make([]float64, len(vars)) for i, v := range vars { newMean[i] = n.mu[v] } var s mat.SymDense s.SubsetSym(&n.sigma, vars) return NewNormal(newMean, &s, src) } // MarginalNormalSingle returns the marginal of the given input variable. // That is, MarginalNormal returns // // p(x_i) = \int_{x_¬i} p(x_i | x_¬i) p(x_¬i) dx_¬i // // where i is the input index. // See https://en.wikipedia.org/wiki/Marginal_distribution for more information. // // The input src is passed to the constructed distuv.Normal. func (n *Normal) MarginalNormalSingle(i int, src rand.Source) distuv.Normal { return distuv.Normal{ Mu: n.mu[i], Sigma: math.Sqrt(n.sigma.At(i, i)), Src: src, } } // Mean returns the mean of the probability distribution at x. If the // input argument is nil, a new slice will be allocated, otherwise the result // will be put in-place into the receiver. func (n *Normal) Mean(x []float64) []float64 { x = reuseAs(x, n.dim) copy(x, n.mu) return x } // Prob computes the value of the probability density function at x. func (n *Normal) Prob(x []float64) float64 { return math.Exp(n.LogProb(x)) } // Quantile returns the multi-dimensional inverse cumulative distribution function. // If x is nil, a new slice will be allocated and returned. If x is non-nil, // len(x) must equal len(p) and the quantile will be stored in-place into x. // All of the values of p must be between 0 and 1, inclusive, or Quantile will panic. func (n *Normal) Quantile(x, p []float64) []float64 { dim := n.Dim() if len(p) != dim { panic(badInputLength) } if x == nil { x = make([]float64, dim) } if len(x) != len(p) { panic(badInputLength) } // Transform to a standard normal and then transform to a multivariate Gaussian. tmp := make([]float64, len(x)) for i, v := range p { tmp[i] = distuv.UnitNormal.Quantile(v) } n.TransformNormal(x, tmp) return x } // Rand generates a random number according to the distributon. // If the input slice is nil, new memory is allocated, otherwise the result is stored // in place. func (n *Normal) Rand(x []float64) []float64 { return NormalRand(x, n.mu, &n.chol, n.src) } // NormalRand generates a random number with the given mean and Cholesky // decomposition of the covariance matrix. // If x is nil, new memory is allocated and returned, otherwise the result is stored // in place into x. NormalRand panics if x is non-nil and not equal to len(mu), // or if len(mu) != chol.Size(). // // This function saves time and memory if the Cholesky decomposition is already // available. Otherwise, the NewNormal function should be used. func NormalRand(x, mean []float64, chol *mat.Cholesky, src rand.Source) []float64 { x = reuseAs(x, len(mean)) if len(mean) != chol.SymmetricDim() { panic(badInputLength) } if src == nil { for i := range x { x[i] = rand.NormFloat64() } } else { rnd := rand.New(src) for i := range x { x[i] = rnd.NormFloat64() } } transformNormal(x, x, mean, chol) return x } // ScoreInput returns the gradient of the log-probability with respect to the // input x. That is, ScoreInput computes // // ∇_x log(p(x)) // // If score is nil, a new slice will be allocated and returned. If score is of // length the dimension of Normal, then the result will be put in-place into score. // If neither of these is true, ScoreInput will panic. func (n *Normal) ScoreInput(score, x []float64) []float64 { // Normal log probability is // c - 0.5*(x-μ)' Σ^-1 (x-μ). // So the derivative is just // -Σ^-1 (x-μ). if len(x) != n.Dim() { panic(badInputLength) } if score == nil { score = make([]float64, len(x)) } if len(score) != len(x) { panic(badSizeMismatch) } tmp := make([]float64, len(x)) copy(tmp, x) floats.Sub(tmp, n.mu) err := n.chol.SolveVecTo(mat.NewVecDense(len(score), score), mat.NewVecDense(len(tmp), tmp)) if err != nil { panic(err) } floats.Scale(-1, score) return score } // SetMean changes the mean of the normal distribution. SetMean panics if len(mu) // does not equal the dimension of the normal distribution. func (n *Normal) SetMean(mu []float64) { if len(mu) != n.Dim() { panic(badSizeMismatch) } copy(n.mu, mu) } // TransformNormal transforms the vector, normal, generated from a standard // multidimensional normal into a vector that has been generated under the // distribution of the receiver. // // If dst is non-nil, the result will be stored into dst, otherwise a new slice // will be allocated. TransformNormal will panic if the length of normal is not // the dimension of the receiver, or if dst is non-nil and len(dist) != len(normal). func (n *Normal) TransformNormal(dst, normal []float64) []float64 { if len(normal) != n.dim { panic(badInputLength) } dst = reuseAs(dst, n.dim) if len(dst) != len(normal) { panic(badInputLength) } transformNormal(dst, normal, n.mu, &n.chol) return dst } // transformNormal performs the same operation as Normal.TransformNormal except // no safety checks are performed and all memory must be provided. func transformNormal(dst, normal, mu []float64, chol *mat.Cholesky) []float64 { dim := len(mu) dstVec := mat.NewVecDense(dim, dst) srcVec := mat.NewVecDense(dim, normal) // If dst and normal are the same slice, make them the same Vector otherwise // mat complains about being tricky. if &normal[0] == &dst[0] { srcVec = dstVec } dstVec.MulVec(chol.RawU().T(), srcVec) floats.Add(dst, mu) return dst } golang-gonum-v1-gonum-0.14.0/stat/distmv/normal_test.go000066400000000000000000000344721450372207100230070ustar00rootroot00000000000000// 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 distmv import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/diff/fd" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat" ) func TestNormProbs(t *testing.T) { dist1, ok := NewNormal([]float64{0, 0}, mat.NewSymDense(2, []float64{1, 0, 0, 1}), nil) if !ok { t.Errorf("bad test") } dist2, ok := NewNormal([]float64{6, 7}, mat.NewSymDense(2, []float64{8, 2, 0, 4}), nil) if !ok { t.Errorf("bad test") } testProbability(t, []probCase{ { dist: dist1, loc: []float64{0, 0}, logProb: -1.837877066409345, }, { dist: dist2, loc: []float64{6, 7}, logProb: -3.503979321496947, }, { dist: dist2, loc: []float64{1, 2}, logProb: -7.075407892925519, }, }) } func TestNewNormalChol(t *testing.T) { for _, test := range []struct { mean []float64 cov *mat.SymDense }{ { mean: []float64{2, 3}, cov: mat.NewSymDense(2, []float64{1, 0.1, 0.1, 1}), }, } { var chol mat.Cholesky ok := chol.Factorize(test.cov) if !ok { panic("bad test") } n := NewNormalChol(test.mean, &chol, nil) // Generate a random number and calculate probability to ensure things // have been set properly. See issue #426. x := n.Rand(nil) _ = n.Prob(x) } } func TestNormRand(t *testing.T) { for _, test := range []struct { mean []float64 cov []float64 }{ { mean: []float64{0, 0}, cov: []float64{ 1, 0, 0, 1, }, }, { mean: []float64{0, 0}, cov: []float64{ 1, 0.9, 0.9, 1, }, }, { mean: []float64{6, 7}, cov: []float64{ 5, 0.9, 0.9, 2, }, }, } { dim := len(test.mean) cov := mat.NewSymDense(dim, test.cov) n, ok := NewNormal(test.mean, cov, nil) if !ok { t.Errorf("bad covariance matrix") } nSamples := 1000000 samps := mat.NewDense(nSamples, dim, nil) for i := 0; i < nSamples; i++ { n.Rand(samps.RawRowView(i)) } estMean := make([]float64, dim) for i := range estMean { estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil) } if !floats.EqualApprox(estMean, test.mean, 1e-2) { t.Errorf("Mean mismatch: want: %v, got %v", test.mean, estMean) } var estCov mat.SymDense stat.CovarianceMatrix(&estCov, samps, nil) if !mat.EqualApprox(&estCov, cov, 1e-2) { t.Errorf("Cov mismatch: want: %v, got %v", cov, &estCov) } } } func TestNormalQuantile(t *testing.T) { for _, test := range []struct { mean []float64 cov []float64 }{ { mean: []float64{6, 7}, cov: []float64{ 5, 0.9, 0.9, 2, }, }, } { dim := len(test.mean) cov := mat.NewSymDense(dim, test.cov) n, ok := NewNormal(test.mean, cov, nil) if !ok { t.Errorf("bad covariance matrix") } nSamples := 1000000 rnd := rand.New(rand.NewSource(1)) samps := mat.NewDense(nSamples, dim, nil) tmp := make([]float64, dim) for i := 0; i < nSamples; i++ { for j := range tmp { tmp[j] = rnd.Float64() } n.Quantile(samps.RawRowView(i), tmp) } estMean := make([]float64, dim) for i := range estMean { estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil) } if !floats.EqualApprox(estMean, test.mean, 1e-2) { t.Errorf("Mean mismatch: want: %v, got %v", test.mean, estMean) } var estCov mat.SymDense stat.CovarianceMatrix(&estCov, samps, nil) if !mat.EqualApprox(&estCov, cov, 1e-2) { t.Errorf("Cov mismatch: want: %v, got %v", cov, &estCov) } } } func TestConditionNormal(t *testing.T) { // Uncorrelated values shouldn't influence the updated values. for _, test := range []struct { mu []float64 sigma *mat.SymDense observed []int values []float64 newMu []float64 newSigma *mat.SymDense }{ { mu: []float64{2, 3}, sigma: mat.NewSymDense(2, []float64{2, 0, 0, 5}), observed: []int{0}, values: []float64{10}, newMu: []float64{3}, newSigma: mat.NewSymDense(1, []float64{5}), }, { mu: []float64{2, 3}, sigma: mat.NewSymDense(2, []float64{2, 0, 0, 5}), observed: []int{1}, values: []float64{10}, newMu: []float64{2}, newSigma: mat.NewSymDense(1, []float64{2}), }, { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0, 0, 0, 5, 0, 0, 0, 10}), observed: []int{1}, values: []float64{10}, newMu: []float64{2, 4}, newSigma: mat.NewSymDense(2, []float64{2, 0, 0, 10}), }, { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0, 0, 0, 5, 0, 0, 0, 10}), observed: []int{0, 1}, values: []float64{10, 15}, newMu: []float64{4}, newSigma: mat.NewSymDense(1, []float64{10}), }, { mu: []float64{2, 3, 4, 5}, sigma: mat.NewSymDense(4, []float64{2, 0.5, 0, 0, 0.5, 5, 0, 0, 0, 0, 10, 2, 0, 0, 2, 3}), observed: []int{0, 1}, values: []float64{10, 15}, newMu: []float64{4, 5}, newSigma: mat.NewSymDense(2, []float64{10, 2, 2, 3}), }, } { normal, ok := NewNormal(test.mu, test.sigma, nil) if !ok { t.Fatalf("Bad test, original sigma not positive definite") } newNormal, ok := normal.ConditionNormal(test.observed, test.values, nil) if !ok { t.Fatalf("Bad test, update failure") } if !floats.EqualApprox(test.newMu, newNormal.mu, 1e-12) { t.Errorf("Updated mean mismatch. Want %v, got %v.", test.newMu, newNormal.mu) } var sigma mat.SymDense newNormal.chol.ToSym(&sigma) if !mat.EqualApprox(test.newSigma, &sigma, 1e-12) { t.Errorf("Updated sigma mismatch\n.Want:\n% v\nGot:\n% v\n", test.newSigma, sigma) } } // Test bivariate case where the update rule is analytic for _, test := range []struct { mu []float64 std []float64 rho float64 value float64 }{ { mu: []float64{2, 3}, std: []float64{3, 5}, rho: 0.9, value: 1000, }, { mu: []float64{2, 3}, std: []float64{3, 5}, rho: -0.9, value: 1000, }, } { std := test.std rho := test.rho sigma := mat.NewSymDense(2, []float64{std[0] * std[0], std[0] * std[1] * rho, std[0] * std[1] * rho, std[1] * std[1]}) normal, ok := NewNormal(test.mu, sigma, nil) if !ok { t.Fatalf("Bad test, original sigma not positive definite") } newNormal, ok := normal.ConditionNormal([]int{1}, []float64{test.value}, nil) if !ok { t.Fatalf("Bad test, update failed") } var newSigma mat.SymDense newNormal.chol.ToSym(&newSigma) trueMean := test.mu[0] + rho*(std[0]/std[1])*(test.value-test.mu[1]) if math.Abs(trueMean-newNormal.mu[0]) > 1e-14 { t.Errorf("Mean mismatch. Want %v, got %v", trueMean, newNormal.mu[0]) } trueVar := (1 - rho*rho) * std[0] * std[0] if math.Abs(trueVar-newSigma.At(0, 0)) > 1e-14 { t.Errorf("Std mismatch. Want %v, got %v", trueMean, newNormal.mu[0]) } } // Test via sampling. for _, test := range []struct { mu []float64 sigma *mat.SymDense observed []int unobserved []int value []float64 }{ // The indices in unobserved must be in ascending order for this test. { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}), observed: []int{0}, unobserved: []int{1, 2}, value: []float64{1.9}, }, { mu: []float64{2, 3, 4, 5}, sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}), observed: []int{0, 3}, unobserved: []int{1, 2}, value: []float64{1.9, 2.9}, }, } { totalSamp := 4000000 var nSamp int samples := mat.NewDense(totalSamp, len(test.mu), nil) normal, ok := NewNormal(test.mu, test.sigma, nil) if !ok { t.Errorf("bad test") } sample := make([]float64, len(test.mu)) for i := 0; i < totalSamp; i++ { normal.Rand(sample) isClose := true for i, v := range test.observed { if math.Abs(sample[v]-test.value[i]) > 1e-1 { isClose = false break } } if isClose { samples.SetRow(nSamp, sample) nSamp++ } } if nSamp < 100 { t.Errorf("bad test, not enough samples") continue } samples = samples.Slice(0, nSamp, 0, len(test.mu)).(*mat.Dense) // Compute mean and covariance matrix. estMean := make([]float64, len(test.mu)) for i := range estMean { estMean[i] = stat.Mean(mat.Col(nil, i, samples), nil) } var estCov mat.SymDense stat.CovarianceMatrix(&estCov, samples, nil) // Compute update rule. newNormal, ok := normal.ConditionNormal(test.observed, test.value, nil) if !ok { t.Fatalf("Bad test, update failure") } var subEstMean []float64 for _, v := range test.unobserved { subEstMean = append(subEstMean, estMean[v]) } subEstCov := mat.NewSymDense(len(test.unobserved), nil) for i := 0; i < len(test.unobserved); i++ { for j := i; j < len(test.unobserved); j++ { subEstCov.SetSym(i, j, estCov.At(test.unobserved[i], test.unobserved[j])) } } for i, v := range subEstMean { if math.Abs(newNormal.mu[i]-v) > 5e-2 { t.Errorf("Mean mismatch. Want %v, got %v.", newNormal.mu[i], v) } } var sigma mat.SymDense newNormal.chol.ToSym(&sigma) if !mat.EqualApprox(&sigma, subEstCov, 1e-1) { t.Errorf("Covariance mismatch. Want:\n%0.8v\nGot:\n%0.8v\n", subEstCov, sigma) } } } func TestCovarianceMatrix(t *testing.T) { for _, test := range []struct { mu []float64 sigma *mat.SymDense }{ { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{1, 0.5, 3, 0.5, 8, -1, 3, -1, 15}), }, } { normal, ok := NewNormal(test.mu, test.sigma, nil) if !ok { t.Fatalf("Bad test, covariance matrix not positive definite") } var cov mat.SymDense normal.CovarianceMatrix(&cov) if !mat.EqualApprox(&cov, test.sigma, 1e-14) { t.Errorf("Covariance mismatch with nil input") } dim := test.sigma.SymmetricDim() cov = *mat.NewSymDense(dim, nil) normal.CovarianceMatrix(&cov) if !mat.EqualApprox(&cov, test.sigma, 1e-14) { t.Errorf("Covariance mismatch with supplied input") } } } func TestMarginal(t *testing.T) { for _, test := range []struct { mu []float64 sigma *mat.SymDense marginal []int }{ { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}), marginal: []int{0}, }, { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}), marginal: []int{0, 2}, }, { mu: []float64{2, 3, 4, 5}, sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}), marginal: []int{0, 3}, }, } { normal, ok := NewNormal(test.mu, test.sigma, nil) if !ok { t.Fatalf("Bad test, covariance matrix not positive definite") } marginal, ok := normal.MarginalNormal(test.marginal, nil) if !ok { t.Fatalf("Bad test, marginal matrix not positive definite") } dim := normal.Dim() nSamples := 1000000 samps := mat.NewDense(nSamples, dim, nil) for i := 0; i < nSamples; i++ { normal.Rand(samps.RawRowView(i)) } estMean := make([]float64, dim) for i := range estMean { estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil) } for i, v := range test.marginal { if math.Abs(marginal.mu[i]-estMean[v]) > 1e-2 { t.Errorf("Mean mismatch: want: %v, got %v", estMean[v], marginal.mu[i]) } } var marginalCov mat.SymDense marginal.CovarianceMatrix(&marginalCov) var estCov mat.SymDense stat.CovarianceMatrix(&estCov, samps, nil) for i, v1 := range test.marginal { for j, v2 := range test.marginal { c := marginalCov.At(i, j) ec := estCov.At(v1, v2) if math.Abs(c-ec) > 5e-2 { t.Errorf("Cov mismatch element i = %d, j = %d: want: %v, got %v", i, j, c, ec) } } } } } func TestMarginalSingle(t *testing.T) { for _, test := range []struct { mu []float64 sigma *mat.SymDense }{ { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}), }, { mu: []float64{2, 3, 4, 5}, sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}), }, } { normal, ok := NewNormal(test.mu, test.sigma, nil) if !ok { t.Fatalf("Bad test, covariance matrix not positive definite") } for i, mean := range test.mu { norm := normal.MarginalNormalSingle(i, nil) if norm.Mean() != mean { t.Errorf("Mean mismatch nil Sigma, idx %v: want %v, got %v.", i, mean, norm.Mean()) } std := math.Sqrt(test.sigma.At(i, i)) if math.Abs(norm.StdDev()-std) > 1e-14 { t.Errorf("StdDev mismatch nil Sigma, idx %v: want %v, got %v.", i, std, norm.StdDev()) } } } // Test matching with TestMarginal. rnd := rand.New(rand.NewSource(1)) for cas := 0; cas < 10; cas++ { dim := rnd.Intn(10) + 1 mu := make([]float64, dim) for i := range mu { mu[i] = rnd.Float64() } x := make([]float64, dim*dim) for i := range x { x[i] = rnd.Float64() } matrix := mat.NewDense(dim, dim, x) var sigma mat.SymDense sigma.SymOuterK(1, matrix) normal, ok := NewNormal(mu, &sigma, nil) if !ok { t.Fatal("bad test") } for i := 0; i < dim; i++ { single := normal.MarginalNormalSingle(i, nil) mult, ok := normal.MarginalNormal([]int{i}, nil) if !ok { t.Fatal("bad test") } if math.Abs(single.Mean()-mult.Mean(nil)[0]) > 1e-14 { t.Errorf("Mean mismatch") } var cov mat.SymDense mult.CovarianceMatrix(&cov) if math.Abs(single.Variance()-cov.At(0, 0)) > 1e-14 { t.Errorf("Variance mismatch") } } } } func TestNormalScoreInput(t *testing.T) { for cas, test := range []struct { mu []float64 sigma *mat.SymDense x []float64 }{ { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}), x: []float64{1, 3.1, -2}, }, { mu: []float64{2, 3, 4, 5}, sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}), x: []float64{1, 3.1, -2, 5}, }, } { normal, ok := NewNormal(test.mu, test.sigma, nil) if !ok { t.Fatalf("Bad test, covariance matrix not positive definite") } x := make([]float64, len(test.x)) copy(x, test.x) score := normal.ScoreInput(nil, x) if !floats.Equal(x, test.x) { t.Errorf("x modified during call to ScoreInput") } scoreFD := fd.Gradient(nil, normal.LogProb, x, nil) if !floats.EqualApprox(score, scoreFD, 1e-4) { t.Errorf("Case %d: derivative mismatch. Got %v, want %v", cas, score, scoreFD) } } } golang-gonum-v1-gonum-0.14.0/stat/distmv/normalbench_test.go000066400000000000000000000027661450372207100240100ustar00rootroot00000000000000// Copyright ©2016 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 distmv import ( "log" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" ) func BenchmarkMarginalNormal10(b *testing.B) { sz := 10 rnd := rand.New(rand.NewSource(1)) normal := randomNormal(sz, rnd) normal.CovarianceMatrix(&mat.SymDense{}) // pre-compute sigma b.ResetTimer() for i := 0; i < b.N; i++ { marg, ok := normal.MarginalNormal([]int{1}, nil) if !ok { b.Error("bad test") } _ = marg } } func BenchmarkMarginalNormalReset10(b *testing.B) { sz := 10 rnd := rand.New(rand.NewSource(1)) normal := randomNormal(sz, rnd) b.ResetTimer() for i := 0; i < b.N; i++ { marg, ok := normal.MarginalNormal([]int{1}, nil) if !ok { b.Error("bad test") } _ = marg } } func BenchmarkMarginalNormalSingle10(b *testing.B) { sz := 10 rnd := rand.New(rand.NewSource(1)) normal := randomNormal(sz, rnd) b.ResetTimer() for i := 0; i < b.N; i++ { marg := normal.MarginalNormalSingle(1, nil) _ = marg } } func randomNormal(sz int, rnd *rand.Rand) *Normal { mu := make([]float64, sz) for i := range mu { mu[i] = rnd.Float64() } data := make([]float64, sz*sz) for i := range data { data[i] = rnd.Float64() } dM := mat.NewDense(sz, sz, data) var sigma mat.SymDense sigma.SymOuterK(1, dM) normal, ok := NewNormal(mu, &sigma, nil) if !ok { log.Fatal("bad test, not pos def") } return normal } golang-gonum-v1-gonum-0.14.0/stat/distmv/statdist.go000066400000000000000000000276751450372207100223260ustar00rootroot00000000000000// Copyright ©2016 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 distmv import ( "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/mathext" "gonum.org/v1/gonum/spatial/r1" "gonum.org/v1/gonum/stat" ) // Bhattacharyya is a type for computing the Bhattacharyya distance between // probability distributions. // // The Bhattacharyya distance is defined as // // D_B = -ln(BC(l,r)) // BC = \int_-∞^∞ (p(x)q(x))^(1/2) dx // // Where BC is known as the Bhattacharyya coefficient. // The Bhattacharyya distance is related to the Hellinger distance by // // H(l,r) = sqrt(1-BC(l,r)) // // For more information, see // // https://en.wikipedia.org/wiki/Bhattacharyya_distance type Bhattacharyya struct{} // DistNormal computes the Bhattacharyya distance between normal distributions l and r. // The dimensions of the input distributions must match or DistNormal will panic. // // For Normal distributions, the Bhattacharyya distance is // // Σ = (Σ_l + Σ_r)/2 // D_B = (1/8)*(μ_l - μ_r)ᵀ*Σ^-1*(μ_l - μ_r) + (1/2)*ln(det(Σ)/(det(Σ_l)*det(Σ_r))^(1/2)) func (Bhattacharyya) DistNormal(l, r *Normal) float64 { dim := l.Dim() if dim != r.Dim() { panic(badSizeMismatch) } var sigma mat.SymDense sigma.AddSym(&l.sigma, &r.sigma) sigma.ScaleSym(0.5, &sigma) var chol mat.Cholesky chol.Factorize(&sigma) mahalanobis := stat.Mahalanobis(mat.NewVecDense(dim, l.mu), mat.NewVecDense(dim, r.mu), &chol) mahalanobisSq := mahalanobis * mahalanobis dl := l.chol.LogDet() dr := r.chol.LogDet() ds := chol.LogDet() return 0.125*mahalanobisSq + 0.5*ds - 0.25*dl - 0.25*dr } // DistUniform computes the Bhattacharyya distance between uniform distributions l and r. // The dimensions of the input distributions must match or DistUniform will panic. func (Bhattacharyya) DistUniform(l, r *Uniform) float64 { if len(l.bounds) != len(r.bounds) { panic(badSizeMismatch) } // BC = \int \sqrt(p(x)q(x)), which for uniform distributions is a constant // over the volume where both distributions have positive probability. // Compute the overlap and the value of sqrt(p(x)q(x)). The entropy is the // negative log probability of the distribution (use instead of LogProb so // it is not necessary to construct an x value). // // BC = volume * sqrt(p(x)q(x)) // logBC = log(volume) + 0.5*(logP + logQ) // D_B = -logBC return -unifLogVolOverlap(l.bounds, r.bounds) + 0.5*(l.Entropy()+r.Entropy()) } // unifLogVolOverlap computes the log of the volume of the hyper-rectangle where // both uniform distributions have positive probability. func unifLogVolOverlap(b1, b2 []r1.Interval) float64 { var logVolOverlap float64 for dim, v1 := range b1 { v2 := b2[dim] // If the surfaces don't overlap, then the volume is 0 if v1.Max <= v2.Min || v2.Max <= v1.Min { return math.Inf(-1) } vol := math.Min(v1.Max, v2.Max) - math.Max(v1.Min, v2.Min) logVolOverlap += math.Log(vol) } return logVolOverlap } // CrossEntropy is a type for computing the cross-entropy between probability // distributions. // // The cross-entropy is defined as // - \int_x l(x) log(r(x)) dx = KL(l || r) + H(l) // // where KL is the Kullback-Leibler divergence and H is the entropy. // For more information, see // // https://en.wikipedia.org/wiki/Cross_entropy type CrossEntropy struct{} // DistNormal returns the cross-entropy between normal distributions l and r. // The dimensions of the input distributions must match or DistNormal will panic. func (CrossEntropy) DistNormal(l, r *Normal) float64 { if l.Dim() != r.Dim() { panic(badSizeMismatch) } kl := KullbackLeibler{}.DistNormal(l, r) return kl + l.Entropy() } // Hellinger is a type for computing the Hellinger distance between probability // distributions. // // The Hellinger distance is defined as // // H^2(l,r) = 1/2 * int_x (\sqrt(l(x)) - \sqrt(r(x)))^2 dx // // and is bounded between 0 and 1. Note the above formula defines the squared // Hellinger distance, while this returns the Hellinger distance itself. // The Hellinger distance is related to the Bhattacharyya distance by // // H^2 = 1 - exp(-D_B) // // For more information, see // // https://en.wikipedia.org/wiki/Hellinger_distance type Hellinger struct{} // DistNormal returns the Hellinger distance between normal distributions l and r. // The dimensions of the input distributions must match or DistNormal will panic. // // See the documentation of Bhattacharyya.DistNormal for the formula for Normal // distributions. func (Hellinger) DistNormal(l, r *Normal) float64 { if l.Dim() != r.Dim() { panic(badSizeMismatch) } db := Bhattacharyya{}.DistNormal(l, r) bc := math.Exp(-db) return math.Sqrt(1 - bc) } // KullbackLeibler is a type for computing the Kullback-Leibler divergence from l to r. // // The Kullback-Leibler divergence is defined as // // D_KL(l || r ) = \int_x p(x) log(p(x)/q(x)) dx // // Note that the Kullback-Leibler divergence is not symmetric with respect to // the order of the input arguments. type KullbackLeibler struct{} // DistDirichlet returns the Kullback-Leibler divergence between Dirichlet // distributions l and r. The dimensions of the input distributions must match // or DistDirichlet will panic. // // For two Dirichlet distributions, the KL divergence is computed as // // D_KL(l || r) = log Γ(α_0_l) - \sum_i log Γ(α_i_l) - log Γ(α_0_r) + \sum_i log Γ(α_i_r) // + \sum_i (α_i_l - α_i_r)(ψ(α_i_l)- ψ(α_0_l)) // // Where Γ is the gamma function, ψ is the digamma function, and α_0 is the // sum of the Dirichlet parameters. func (KullbackLeibler) DistDirichlet(l, r *Dirichlet) float64 { // http://bariskurt.com/kullback-leibler-divergence-between-two-dirichlet-and-beta-distributions/ if l.Dim() != r.Dim() { panic(badSizeMismatch) } l0, _ := math.Lgamma(l.sumAlpha) r0, _ := math.Lgamma(r.sumAlpha) dl := mathext.Digamma(l.sumAlpha) var l1, r1, c float64 for i, al := range l.alpha { ar := r.alpha[i] vl, _ := math.Lgamma(al) l1 += vl vr, _ := math.Lgamma(ar) r1 += vr c += (al - ar) * (mathext.Digamma(al) - dl) } return l0 - l1 - r0 + r1 + c } // DistNormal returns the KullbackLeibler divergence between normal distributions l and r. // The dimensions of the input distributions must match or DistNormal will panic. // // For two normal distributions, the KL divergence is computed as // // D_KL(l || r) = 0.5*[ln(|Σ_r|) - ln(|Σ_l|) + (μ_l - μ_r)ᵀ*Σ_r^-1*(μ_l - μ_r) + tr(Σ_r^-1*Σ_l)-d] func (KullbackLeibler) DistNormal(l, r *Normal) float64 { dim := l.Dim() if dim != r.Dim() { panic(badSizeMismatch) } mahalanobis := stat.Mahalanobis(mat.NewVecDense(dim, l.mu), mat.NewVecDense(dim, r.mu), &r.chol) mahalanobisSq := mahalanobis * mahalanobis // TODO(btracey): Optimize where there is a SolveCholeskySym // TODO(btracey): There may be a more efficient way to just compute the trace // Compute tr(Σ_r^-1*Σ_l) using the fact that Σ_l = Uᵀ * U var u mat.TriDense l.chol.UTo(&u) var m mat.Dense err := r.chol.SolveTo(&m, u.T()) if err != nil { return math.NaN() } m.Mul(&m, &u) tr := mat.Trace(&m) return r.logSqrtDet - l.logSqrtDet + 0.5*(mahalanobisSq+tr-float64(l.dim)) } // DistUniform returns the KullbackLeibler divergence between uniform distributions // l and r. The dimensions of the input distributions must match or DistUniform // will panic. func (KullbackLeibler) DistUniform(l, r *Uniform) float64 { bl := l.Bounds(nil) br := r.Bounds(nil) if len(bl) != len(br) { panic(badSizeMismatch) } // The KL is ∞ if l is not completely contained within r, because then // r(x) is zero when l(x) is non-zero for some x. contained := true for i, v := range bl { if v.Min < br[i].Min || br[i].Max < v.Max { contained = false break } } if !contained { return math.Inf(1) } // The KL divergence is finite. // // KL defines 0*ln(0) = 0, so there is no contribution to KL where l(x) = 0. // Inside the region, l(x) and r(x) are constant (uniform distribution), and // this constant is integrated over l(x), which integrates out to one. // The entropy is -log(p(x)). logPx := -l.Entropy() logQx := -r.Entropy() return logPx - logQx } // Renyi is a type for computing the Rényi divergence of order α from l to r. // // The Rényi divergence with α > 0, α ≠ 1 is defined as // // D_α(l || r) = 1/(α-1) log(\int_-∞^∞ l(x)^α r(x)^(1-α)dx) // // The Rényi divergence has special forms for α = 0 and α = 1. This type does // not implement α = ∞. For α = 0, // // D_0(l || r) = -log \int_-∞^∞ r(x)1{p(x)>0} dx // // that is, the negative log probability under r(x) that l(x) > 0. // When α = 1, the Rényi divergence is equal to the Kullback-Leibler divergence. // The Rényi divergence is also equal to half the Bhattacharyya distance when α = 0.5. // // The parameter α must be in 0 ≤ α < ∞ or the distance functions will panic. type Renyi struct { Alpha float64 } // DistNormal returns the Rényi divergence between normal distributions l and r. // The dimensions of the input distributions must match or DistNormal will panic. // // For two normal distributions, the Rényi divergence is computed as // // Σ_α = (1-α) Σ_l + αΣ_r // D_α(l||r) = α/2 * (μ_l - μ_r)'*Σ_α^-1*(μ_l - μ_r) + 1/(2(α-1))*ln(|Σ_λ|/(|Σ_l|^(1-α)*|Σ_r|^α)) // // For a more nicely formatted version of the formula, see Eq. 15 of // // Kolchinsky, Artemy, and Brendan D. Tracey. "Estimating Mixture Entropy // with Pairwise Distances." arXiv preprint arXiv:1706.02419 (2017). // // Note that the this formula is for Chernoff divergence, which differs from // Rényi divergence by a factor of 1-α. Also be aware that most sources in // the literature report this formula incorrectly. func (renyi Renyi) DistNormal(l, r *Normal) float64 { if renyi.Alpha < 0 { panic("renyi: alpha < 0") } dim := l.Dim() if dim != r.Dim() { panic(badSizeMismatch) } if renyi.Alpha == 0 { return 0 } if renyi.Alpha == 1 { return KullbackLeibler{}.DistNormal(l, r) } logDetL := l.chol.LogDet() logDetR := r.chol.LogDet() // Σ_α = (1-α)Σ_l + αΣ_r. sigA := mat.NewSymDense(dim, nil) for i := 0; i < dim; i++ { for j := i; j < dim; j++ { v := (1-renyi.Alpha)*l.sigma.At(i, j) + renyi.Alpha*r.sigma.At(i, j) sigA.SetSym(i, j, v) } } var chol mat.Cholesky ok := chol.Factorize(sigA) if !ok { return math.NaN() } logDetA := chol.LogDet() mahalanobis := stat.Mahalanobis(mat.NewVecDense(dim, l.mu), mat.NewVecDense(dim, r.mu), &chol) mahalanobisSq := mahalanobis * mahalanobis return (renyi.Alpha/2)*mahalanobisSq + 1/(2*(1-renyi.Alpha))*(logDetA-(1-renyi.Alpha)*logDetL-renyi.Alpha*logDetR) } // Wasserstein is a type for computing the Wasserstein distance between two // probability distributions. // // The Wasserstein distance is defined as // // W(l,r) := inf 𝔼(||X-Y||_2^2)^1/2 // // For more information, see // // https://en.wikipedia.org/wiki/Wasserstein_metric type Wasserstein struct{} // DistNormal returns the Wasserstein distance between normal distributions l and r. // The dimensions of the input distributions must match or DistNormal will panic. // // The Wasserstein distance for Normal distributions is // // d^2 = ||m_l - m_r||_2^2 + Tr(Σ_l + Σ_r - 2(Σ_l^(1/2)*Σ_r*Σ_l^(1/2))^(1/2)) // // For more information, see // // http://djalil.chafai.net/blog/2010/04/30/wasserstein-distance-between-two-gaussians/ func (Wasserstein) DistNormal(l, r *Normal) float64 { dim := l.Dim() if dim != r.Dim() { panic(badSizeMismatch) } d := floats.Distance(l.mu, r.mu, 2) d = d * d // Compute Σ_l^(1/2) var ssl mat.SymDense err := ssl.PowPSD(&l.sigma, 0.5) if err != nil { panic(err) } // Compute Σ_l^(1/2)*Σ_r*Σ_l^(1/2) var mean mat.Dense mean.Mul(&ssl, &r.sigma) mean.Mul(&mean, &ssl) // Reinterpret as symdense, and take Σ^(1/2) meanSym := mat.NewSymDense(dim, mean.RawMatrix().Data) err = ssl.PowPSD(meanSym, 0.5) if err != nil { panic(err) } tr := mat.Trace(&r.sigma) tl := mat.Trace(&l.sigma) tm := mat.Trace(&ssl) return d + tl + tr - 2*tm } golang-gonum-v1-gonum-0.14.0/stat/distmv/statdist_test.go000066400000000000000000000240111450372207100233420ustar00rootroot00000000000000// Copyright ©2016 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 distmv import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/spatial/r1" ) func TestBhattacharyyaNormal(t *testing.T) { for cas, test := range []struct { am, bm []float64 ac, bc *mat.SymDense samples int tol float64 }{ { am: []float64{2, 3}, ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}), bm: []float64{-1, 1}, bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}), samples: 100000, tol: 3e-1, }, } { rnd := rand.New(rand.NewSource(1)) a, ok := NewNormal(test.am, test.ac, rnd) if !ok { panic("bad test") } b, ok := NewNormal(test.bm, test.bc, rnd) if !ok { panic("bad test") } want := bhattacharyyaSample(a.Dim(), test.samples, a, b) got := Bhattacharyya{}.DistNormal(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Bhattacharyya mismatch, case %d: got %v, want %v", cas, got, want) } // Bhattacharyya should by symmetric got2 := Bhattacharyya{}.DistNormal(b, a) if math.Abs(got-got2) > 1e-14 { t.Errorf("Bhattacharyya distance not symmetric") } } } func TestBhattacharyyaUniform(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { a, b *Uniform samples int tol float64 }{ { a: NewUniform([]r1.Interval{{Min: -3, Max: 2}, {Min: -5, Max: 8}}, rnd), b: NewUniform([]r1.Interval{{Min: -4, Max: 1}, {Min: -7, Max: 10}}, rnd), samples: 100000, tol: 1e-2, }, { a: NewUniform([]r1.Interval{{Min: -3, Max: 2}, {Min: -5, Max: 8}}, rnd), b: NewUniform([]r1.Interval{{Min: -5, Max: -4}, {Min: -7, Max: 10}}, rnd), samples: 100000, tol: 1e-2, }, } { a, b := test.a, test.b want := bhattacharyyaSample(a.Dim(), test.samples, a, b) got := Bhattacharyya{}.DistUniform(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Bhattacharyya mismatch, case %d: got %v, want %v", cas, got, want) } // Bhattacharyya should by symmetric got2 := Bhattacharyya{}.DistUniform(b, a) if math.Abs(got-got2) > 1e-14 { t.Errorf("Bhattacharyya distance not symmetric") } } } // bhattacharyyaSample finds an estimate of the Bhattacharyya coefficient through // sampling. func bhattacharyyaSample(dim, samples int, l RandLogProber, r LogProber) float64 { lBhatt := make([]float64, samples) x := make([]float64, dim) for i := 0; i < samples; i++ { // Do importance sampling over a: \int sqrt(a*b)/a * a dx l.Rand(x) pa := l.LogProb(x) pb := r.LogProb(x) lBhatt[i] = 0.5*pb - 0.5*pa } logBc := floats.LogSumExp(lBhatt) - math.Log(float64(samples)) return -logBc } func TestCrossEntropyNormal(t *testing.T) { for cas, test := range []struct { am, bm []float64 ac, bc *mat.SymDense samples int tol float64 }{ { am: []float64{2, 3}, ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}), bm: []float64{-1, 1}, bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}), samples: 100000, tol: 1e-2, }, } { rnd := rand.New(rand.NewSource(1)) a, ok := NewNormal(test.am, test.ac, rnd) if !ok { panic("bad test") } b, ok := NewNormal(test.bm, test.bc, rnd) if !ok { panic("bad test") } var ce float64 x := make([]float64, a.Dim()) for i := 0; i < test.samples; i++ { a.Rand(x) ce -= b.LogProb(x) } ce /= float64(test.samples) got := CrossEntropy{}.DistNormal(a, b) if !scalar.EqualWithinAbsOrRel(ce, got, test.tol, test.tol) { t.Errorf("CrossEntropy mismatch, case %d: got %v, want %v", cas, got, ce) } } } func TestHellingerNormal(t *testing.T) { for cas, test := range []struct { am, bm []float64 ac, bc *mat.SymDense samples int tol float64 }{ { am: []float64{2, 3}, ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}), bm: []float64{-1, 1}, bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}), samples: 100000, tol: 5e-1, }, } { rnd := rand.New(rand.NewSource(1)) a, ok := NewNormal(test.am, test.ac, rnd) if !ok { panic("bad test") } b, ok := NewNormal(test.bm, test.bc, rnd) if !ok { panic("bad test") } lAitchEDoubleHockeySticks := make([]float64, test.samples) x := make([]float64, a.Dim()) for i := 0; i < test.samples; i++ { // Do importance sampling over a: \int (\sqrt(a)-\sqrt(b))^2/a * a dx a.Rand(x) pa := a.LogProb(x) pb := b.LogProb(x) d := math.Exp(0.5*pa) - math.Exp(0.5*pb) d = d * d lAitchEDoubleHockeySticks[i] = math.Log(d) - pa } want := math.Sqrt(0.5 * math.Exp(floats.LogSumExp(lAitchEDoubleHockeySticks)-math.Log(float64(test.samples)))) got := Hellinger{}.DistNormal(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Hellinger mismatch, case %d: got %v, want %v", cas, got, want) } } } func TestKullbackLeiblerDirichlet(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { a, b *Dirichlet samples int tol float64 }{ { a: NewDirichlet([]float64{2, 3, 4}, rnd), b: NewDirichlet([]float64{4, 2, 1.1}, rnd), samples: 100000, tol: 1e-2, }, { a: NewDirichlet([]float64{2, 3, 4, 0.1, 8}, rnd), b: NewDirichlet([]float64{2, 2, 6, 0.5, 9}, rnd), samples: 100000, tol: 1e-2, }, } { a, b := test.a, test.b want := klSample(a.Dim(), test.samples, a, b) got := KullbackLeibler{}.DistDirichlet(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Kullback-Leibler mismatch, case %d: got %v, want %v", cas, got, want) } } } func TestKullbackLeiblerNormal(t *testing.T) { for cas, test := range []struct { am, bm []float64 ac, bc *mat.SymDense samples int tol float64 }{ { am: []float64{2, 3}, ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}), bm: []float64{-1, 1}, bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}), samples: 10000, tol: 1e-2, }, } { rnd := rand.New(rand.NewSource(1)) a, ok := NewNormal(test.am, test.ac, rnd) if !ok { panic("bad test") } b, ok := NewNormal(test.bm, test.bc, rnd) if !ok { panic("bad test") } want := klSample(a.Dim(), test.samples, a, b) got := KullbackLeibler{}.DistNormal(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Case %d, KL mismatch: got %v, want %v", cas, got, want) } } } func TestKullbackLeiblerUniform(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { a, b *Uniform samples int tol float64 }{ { a: NewUniform([]r1.Interval{{Min: -5, Max: 2}, {Min: -7, Max: 12}}, rnd), b: NewUniform([]r1.Interval{{Min: -4, Max: 1}, {Min: -7, Max: 10}}, rnd), samples: 100000, tol: 1e-2, }, { a: NewUniform([]r1.Interval{{Min: -5, Max: 2}, {Min: -7, Max: 12}}, rnd), b: NewUniform([]r1.Interval{{Min: -9, Max: -6}, {Min: -7, Max: 10}}, rnd), samples: 100000, tol: 1e-2, }, } { a, b := test.a, test.b want := klSample(a.Dim(), test.samples, a, b) got := KullbackLeibler{}.DistUniform(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Kullback-Leibler mismatch, case %d: got %v, want %v", cas, got, want) } } } // klSample finds an estimate of the Kullback-Leibler divergence through sampling. func klSample(dim, samples int, l RandLogProber, r LogProber) float64 { var klmc float64 x := make([]float64, dim) for i := 0; i < samples; i++ { l.Rand(x) pa := l.LogProb(x) pb := r.LogProb(x) klmc += pa - pb } return klmc / float64(samples) } func TestRenyiNormal(t *testing.T) { for cas, test := range []struct { am, bm []float64 ac, bc *mat.SymDense alpha float64 samples int tol float64 }{ { am: []float64{2, 3}, ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}), bm: []float64{-1, 1}, bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}), alpha: 0.3, samples: 10000, tol: 3e-1, }, } { rnd := rand.New(rand.NewSource(1)) a, ok := NewNormal(test.am, test.ac, rnd) if !ok { panic("bad test") } b, ok := NewNormal(test.bm, test.bc, rnd) if !ok { panic("bad test") } want := renyiSample(a.Dim(), test.samples, test.alpha, a, b) got := Renyi{Alpha: test.alpha}.DistNormal(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Case %d: Renyi sampling mismatch: got %v, want %v", cas, got, want) } // Compare with Bhattacharyya. want = 2 * Bhattacharyya{}.DistNormal(a, b) got = Renyi{Alpha: 0.5}.DistNormal(a, b) if !scalar.EqualWithinAbsOrRel(want, got, 1e-10, 1e-10) { t.Errorf("Case %d: Renyi mismatch with Bhattacharyya: got %v, want %v", cas, got, want) } // Compare with KL in both directions. want = KullbackLeibler{}.DistNormal(a, b) got = Renyi{Alpha: 0.9999999}.DistNormal(a, b) // very close to 1 but not equal to 1. if !scalar.EqualWithinAbsOrRel(want, got, 1e-6, 1e-6) { t.Errorf("Case %d: Renyi mismatch with KL(a||b): got %v, want %v", cas, got, want) } want = KullbackLeibler{}.DistNormal(b, a) got = Renyi{Alpha: 0.9999999}.DistNormal(b, a) // very close to 1 but not equal to 1. if !scalar.EqualWithinAbsOrRel(want, got, 1e-6, 1e-6) { t.Errorf("Case %d: Renyi mismatch with KL(b||a): got %v, want %v", cas, got, want) } } } // renyiSample finds an estimate of the Rényi divergence through sampling. // Note that this sampling procedure only works if l has broader support than r. func renyiSample(dim, samples int, alpha float64, l RandLogProber, r LogProber) float64 { rmcs := make([]float64, samples) x := make([]float64, dim) for i := 0; i < samples; i++ { l.Rand(x) pa := l.LogProb(x) pb := r.LogProb(x) rmcs[i] = (alpha-1)*pa + (1-alpha)*pb } return 1 / (alpha - 1) * (floats.LogSumExp(rmcs) - math.Log(float64(samples))) } golang-gonum-v1-gonum-0.14.0/stat/distmv/studentst.go000066400000000000000000000250031450372207100225030ustar00rootroot00000000000000// Copyright ©2016 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 distmv import ( "math" "sort" "golang.org/x/exp/rand" "golang.org/x/tools/container/intsets" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat" "gonum.org/v1/gonum/stat/distuv" ) // StudentsT is a multivariate Student's T distribution. It is a distribution over // ℝ^n with the probability density // // p(y) = (Γ((ν+n)/2) / Γ(ν/2)) * (νπ)^(-n/2) * |Ʃ|^(-1/2) * // (1 + 1/ν * (y-μ)ᵀ * Ʃ^-1 * (y-μ))^(-(ν+n)/2) // // where ν is a scalar greater than 2, μ is a vector in ℝ^n, and Ʃ is an n×n // symmetric positive definite matrix. // // In this distribution, ν sets the spread of the distribution, similar to // the degrees of freedom in a univariate Student's T distribution. As ν → ∞, // the distribution approaches a multi-variate normal distribution. // μ is the mean of the distribution, and the covariance is ν/(ν-2)*Ʃ. // // See https://en.wikipedia.org/wiki/Student%27s_t-distribution and // http://users.isy.liu.se/en/rt/roth/student.pdf for more information. type StudentsT struct { nu float64 mu []float64 // If src is altered, rnd must be updated. src rand.Source rnd *rand.Rand sigma mat.SymDense // only stored if needed chol mat.Cholesky lower mat.TriDense logSqrtDet float64 dim int } // NewStudentsT creates a new StudentsT with the given nu, mu, and sigma // parameters. // // NewStudentsT panics if len(mu) == 0, or if len(mu) != sigma.SymmetricDim(). If // the covariance matrix is not positive-definite, nil is returned and ok is false. func NewStudentsT(mu []float64, sigma mat.Symmetric, nu float64, src rand.Source) (dist *StudentsT, ok bool) { if len(mu) == 0 { panic(badZeroDimension) } dim := sigma.SymmetricDim() if dim != len(mu) { panic(badSizeMismatch) } s := &StudentsT{ nu: nu, mu: make([]float64, dim), dim: dim, src: src, } if src != nil { s.rnd = rand.New(src) } copy(s.mu, mu) ok = s.chol.Factorize(sigma) if !ok { return nil, false } s.sigma = *mat.NewSymDense(dim, nil) s.sigma.CopySym(sigma) s.chol.LTo(&s.lower) s.logSqrtDet = 0.5 * s.chol.LogDet() return s, true } // ConditionStudentsT returns the Student's T distribution that is the receiver // conditioned on the input evidence, and the success of the operation. // The returned Student's T has dimension // n - len(observed), where n is the dimension of the original receiver. // The dimension order is preserved during conditioning, so if the value // of dimension 1 is observed, the returned normal represents dimensions {0, 2, ...} // of the original Student's T distribution. // // ok indicates whether there was a failure during the update. If ok is false // the operation failed and dist is not usable. // Mathematically this is impossible, but can occur with finite precision arithmetic. func (s *StudentsT) ConditionStudentsT(observed []int, values []float64, src rand.Source) (dist *StudentsT, ok bool) { if len(observed) == 0 { panic("studentst: no observed value") } if len(observed) != len(values) { panic(badInputLength) } for _, v := range observed { if v < 0 || v >= s.dim { panic("studentst: observed value out of bounds") } } newNu, newMean, newSigma := studentsTConditional(observed, values, s.nu, s.mu, &s.sigma) if newMean == nil { return nil, false } return NewStudentsT(newMean, newSigma, newNu, src) } // studentsTConditional updates a Student's T distribution based on the observed samples // (see documentation for the public function). The Gaussian conditional update // is treated as a special case when nu == math.Inf(1). func studentsTConditional(observed []int, values []float64, nu float64, mu []float64, sigma mat.Symmetric) (newNu float64, newMean []float64, newSigma *mat.SymDense) { dim := len(mu) ob := len(observed) unobserved := findUnob(observed, dim) unob := len(unobserved) if unob == 0 { panic("stat: all dimensions observed") } mu1 := make([]float64, unob) for i, v := range unobserved { mu1[i] = mu[v] } mu2 := make([]float64, ob) // really v - mu2 for i, v := range observed { mu2[i] = values[i] - mu[v] } var sigma11, sigma22 mat.SymDense sigma11.SubsetSym(sigma, unobserved) sigma22.SubsetSym(sigma, observed) sigma21 := mat.NewDense(ob, unob, nil) for i, r := range observed { for j, c := range unobserved { v := sigma.At(r, c) sigma21.Set(i, j, v) } } var chol mat.Cholesky ok := chol.Factorize(&sigma22) if !ok { return math.NaN(), nil, nil } // Compute mu_1 + sigma_{2,1}ᵀ * sigma_{2,2}^-1 (v - mu_2). v := mat.NewVecDense(ob, mu2) var tmp, tmp2 mat.VecDense err := chol.SolveVecTo(&tmp, v) if err != nil { return math.NaN(), nil, nil } tmp2.MulVec(sigma21.T(), &tmp) for i := range mu1 { mu1[i] += tmp2.At(i, 0) } // Compute tmp4 = sigma_{2,1}ᵀ * sigma_{2,2}^-1 * sigma_{2,1}. // TODO(btracey): Should this be a method of SymDense? var tmp3, tmp4 mat.Dense err = chol.SolveTo(&tmp3, sigma21) if err != nil { return math.NaN(), nil, nil } tmp4.Mul(sigma21.T(), &tmp3) // Compute sigma_{1,1} - tmp4 // TODO(btracey): If tmp4 can constructed with a method, then this can be // replaced with SubSym. for i := 0; i < len(unobserved); i++ { for j := i; j < len(unobserved); j++ { v := sigma11.At(i, j) sigma11.SetSym(i, j, v-tmp4.At(i, j)) } } // The computed variables are accurate for a Normal. if math.IsInf(nu, 1) { return nu, mu1, &sigma11 } // Compute beta = (v - mu_2)ᵀ * sigma_{2,2}^-1 * (v - mu_2)ᵀ beta := mat.Dot(v, &tmp) // Scale the covariance matrix sigma11.ScaleSym((nu+beta)/(nu+float64(ob)), &sigma11) return nu + float64(ob), mu1, &sigma11 } // findUnob returns the unobserved variables (the complementary set to observed). // findUnob panics if any value repeated in observed. func findUnob(observed []int, dim int) (unobserved []int) { var setOb intsets.Sparse for _, v := range observed { setOb.Insert(v) } var setAll intsets.Sparse for i := 0; i < dim; i++ { setAll.Insert(i) } var setUnob intsets.Sparse setUnob.Difference(&setAll, &setOb) unobserved = setUnob.AppendTo(nil) sort.Ints(unobserved) return unobserved } // CovarianceMatrix calculates the covariance matrix of the distribution, // storing the result in dst. Upon return, the value at element {i, j} of the // covariance matrix is equal to the covariance of the i^th and j^th variables. // // covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])] // // If the dst matrix is empty it will be resized to the correct dimensions, // otherwise dst must match the dimension of the receiver or CovarianceMatrix // will panic. func (st *StudentsT) CovarianceMatrix(dst *mat.SymDense) { if dst.IsEmpty() { *dst = *(dst.GrowSym(st.dim).(*mat.SymDense)) } else if dst.SymmetricDim() != st.dim { panic("studentst: input matrix size mismatch") } dst.CopySym(&st.sigma) dst.ScaleSym(st.nu/(st.nu-2), dst) } // Dim returns the dimension of the distribution. func (s *StudentsT) Dim() int { return s.dim } // LogProb computes the log of the pdf of the point x. func (s *StudentsT) LogProb(y []float64) float64 { if len(y) != s.dim { panic(badInputLength) } nu := s.nu n := float64(s.dim) lg1, _ := math.Lgamma((nu + n) / 2) lg2, _ := math.Lgamma(nu / 2) t1 := lg1 - lg2 - n/2*math.Log(nu*math.Pi) - s.logSqrtDet mahal := stat.Mahalanobis(mat.NewVecDense(len(y), y), mat.NewVecDense(len(s.mu), s.mu), &s.chol) mahal *= mahal return t1 - ((nu+n)/2)*math.Log(1+mahal/nu) } // MarginalStudentsT returns the marginal distribution of the given input variables, // and the success of the operation. // That is, MarginalStudentsT returns // // p(x_i) = \int_{x_o} p(x_i | x_o) p(x_o) dx_o // // where x_i are the dimensions in the input, and x_o are the remaining dimensions. // See https://en.wikipedia.org/wiki/Marginal_distribution for more information. // // The input src is passed to the created StudentsT. // // ok indicates whether there was a failure during the marginalization. If ok is false // the operation failed and dist is not usable. // Mathematically this is impossible, but can occur with finite precision arithmetic. func (s *StudentsT) MarginalStudentsT(vars []int, src rand.Source) (dist *StudentsT, ok bool) { newMean := make([]float64, len(vars)) for i, v := range vars { newMean[i] = s.mu[v] } var newSigma mat.SymDense newSigma.SubsetSym(&s.sigma, vars) return NewStudentsT(newMean, &newSigma, s.nu, src) } // MarginalStudentsTSingle returns the marginal distribution of the given input variable. // That is, MarginalStudentsTSingle returns // // p(x_i) = \int_{x_o} p(x_i | x_o) p(x_o) dx_o // // where i is the input index, and x_o are the remaining dimensions. // See https://en.wikipedia.org/wiki/Marginal_distribution for more information. // // The input src is passed to the call to NewStudentsT. func (s *StudentsT) MarginalStudentsTSingle(i int, src rand.Source) distuv.StudentsT { return distuv.StudentsT{ Mu: s.mu[i], Sigma: math.Sqrt(s.sigma.At(i, i)), Nu: s.nu, Src: src, } } // TODO(btracey): Implement marginal single. Need to modify univariate StudentsT // to be three-parameter. // Mean returns the mean of the probability distribution at x. If the // input argument is nil, a new slice will be allocated, otherwise the result // will be put in-place into the receiver. func (s *StudentsT) Mean(x []float64) []float64 { x = reuseAs(x, s.dim) copy(x, s.mu) return x } // Nu returns the degrees of freedom parameter of the distribution. func (s *StudentsT) Nu() float64 { return s.nu } // Prob computes the value of the probability density function at x. func (s *StudentsT) Prob(y []float64) float64 { return math.Exp(s.LogProb(y)) } // Rand generates a random number according to the distributon. // If the input slice is nil, new memory is allocated, otherwise the result is stored // in place. func (s *StudentsT) Rand(x []float64) []float64 { // If Y is distributed according to N(0,Sigma), and U is chi^2 with // parameter ν, then // X = mu + Y * sqrt(nu / U) // X is distributed according to this distribution. // Generate Y. x = reuseAs(x, s.dim) tmp := make([]float64, s.dim) if s.rnd == nil { for i := range x { tmp[i] = rand.NormFloat64() } } else { for i := range x { tmp[i] = s.rnd.NormFloat64() } } xVec := mat.NewVecDense(s.dim, x) tmpVec := mat.NewVecDense(s.dim, tmp) xVec.MulVec(&s.lower, tmpVec) u := distuv.ChiSquared{K: s.nu, Src: s.src}.Rand() floats.Scale(math.Sqrt(s.nu/u), x) floats.Add(x, s.mu) return x } golang-gonum-v1-gonum-0.14.0/stat/distmv/studentst_test.go000066400000000000000000000150061450372207100235440ustar00rootroot00000000000000// Copyright ©2016 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 distmv import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat" ) func TestStudentTProbs(t *testing.T) { src := rand.New(rand.NewSource(1)) for _, test := range []struct { nu float64 mu []float64 sigma *mat.SymDense x [][]float64 probs []float64 }{ { nu: 3, mu: []float64{0, 0}, sigma: mat.NewSymDense(2, []float64{1, 0, 0, 1}), x: [][]float64{ {0, 0}, {1, -1}, {3, 4}, {-1, -2}, }, // Outputs compared with WolframAlpha. probs: []float64{ 0.159154943091895335768883, 0.0443811199724279860006777747927, 0.0005980371870904696541052658, 0.01370560783418571283428283, }, }, { nu: 4, mu: []float64{2, -3}, sigma: mat.NewSymDense(2, []float64{8, -1, -1, 5}), x: [][]float64{ {0, 0}, {1, -1}, {3, 4}, {-1, -2}, {2, -3}, }, // Outputs compared with WolframAlpha. probs: []float64{ 0.007360810111491788657953608191001, 0.0143309905845607117740440592999, 0.0005307774290578041397794096037035009801668903, 0.0115657422475668739943625904793879, 0.0254851872062589062995305736215, }, }, } { s, ok := NewStudentsT(test.mu, test.sigma, test.nu, src) if !ok { t.Fatal("bad test") } for i, x := range test.x { xcpy := make([]float64, len(x)) copy(xcpy, x) p := s.Prob(x) if !floats.Same(x, xcpy) { t.Errorf("X modified during call to prob, %v, %v", x, xcpy) } if !scalar.EqualWithinAbsOrRel(p, test.probs[i], 1e-10, 1e-10) { t.Errorf("Probability mismatch. X = %v. Got %v, want %v.", x, p, test.probs[i]) } } } } func TestStudentsTRand(t *testing.T) { src := rand.New(rand.NewSource(1)) for cas, test := range []struct { mean []float64 cov *mat.SymDense nu float64 tolcov float64 }{ { mean: []float64{0, 0}, cov: mat.NewSymDense(2, []float64{1, 0, 0, 1}), nu: 4, tolcov: 1e-2, }, { mean: []float64{3, 4}, cov: mat.NewSymDense(2, []float64{5, 1.2, 1.2, 6}), nu: 8, tolcov: 1e-2, }, { mean: []float64{3, 4, -2}, cov: mat.NewSymDense(3, []float64{5, 1.2, -0.8, 1.2, 6, 0.4, -0.8, 0.4, 2}), nu: 8, tolcov: 1e-2, }, } { s, ok := NewStudentsT(test.mean, test.cov, test.nu, src) if !ok { t.Fatal("bad test") } const nSamples = 1e6 dim := len(test.mean) samps := mat.NewDense(nSamples, dim, nil) for i := 0; i < nSamples; i++ { s.Rand(samps.RawRowView(i)) } estMean := make([]float64, dim) for i := range estMean { estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil) } mean := s.Mean(nil) if !floats.EqualApprox(estMean, mean, 1e-2) { t.Errorf("Mean mismatch: want: %v, got %v", test.mean, estMean) } var cov, estCov mat.SymDense s.CovarianceMatrix(&cov) stat.CovarianceMatrix(&estCov, samps, nil) if !mat.EqualApprox(&estCov, &cov, test.tolcov) { t.Errorf("Case %d: Cov mismatch: want: %v, got %v", cas, &cov, &estCov) } } } func TestStudentsTConditional(t *testing.T) { src := rand.New(rand.NewSource(1)) for _, test := range []struct { mean []float64 cov *mat.SymDense nu float64 idx []int value []float64 tolcov float64 }{ { mean: []float64{3, 4, -2}, cov: mat.NewSymDense(3, []float64{5, 1.2, -0.8, 1.2, 6, 0.4, -0.8, 0.4, 2}), nu: 8, idx: []int{0}, value: []float64{6}, tolcov: 1e-2, }, } { s, ok := NewStudentsT(test.mean, test.cov, test.nu, src) if !ok { t.Fatal("bad test") } sUp, ok := s.ConditionStudentsT(test.idx, test.value, src) if !ok { t.Error("unexpected failure of ConditionStudentsT") } // Compute the other values by hand the inefficient way to compare newNu := test.nu + float64(len(test.idx)) if newNu != sUp.nu { t.Errorf("Updated nu mismatch. Got %v, want %v", s.nu, newNu) } dim := len(test.mean) unob := findUnob(test.idx, dim) ob := test.idx muUnob := make([]float64, len(unob)) for i, v := range unob { muUnob[i] = test.mean[v] } muOb := make([]float64, len(ob)) for i, v := range ob { muOb[i] = test.mean[v] } var sig11, sig22 mat.SymDense sig11.SubsetSym(&s.sigma, unob) sig22.SubsetSym(&s.sigma, ob) sig12 := mat.NewDense(len(unob), len(ob), nil) for i := range unob { for j := range ob { sig12.Set(i, j, s.sigma.At(unob[i], ob[j])) } } shift := make([]float64, len(ob)) copy(shift, test.value) floats.Sub(shift, muOb) newMu := make([]float64, len(muUnob)) newMuVec := mat.NewVecDense(len(muUnob), newMu) shiftVec := mat.NewVecDense(len(shift), shift) var tmp mat.VecDense err := tmp.SolveVec(&sig22, shiftVec) if err != nil { t.Errorf("unexpected error from vector solve: %v", err) } newMuVec.MulVec(sig12, &tmp) floats.Add(newMu, muUnob) if !floats.EqualApprox(newMu, sUp.mu, 1e-10) { t.Errorf("Mu mismatch. Got %v, want %v", sUp.mu, newMu) } var tmp2 mat.Dense err = tmp2.Solve(&sig22, sig12.T()) if err != nil { t.Errorf("unexpected error from dense solve: %v", err) } var tmp3 mat.Dense tmp3.Mul(sig12, &tmp2) tmp3.Sub(&sig11, &tmp3) dot := mat.Dot(shiftVec, &tmp) tmp3.Scale((test.nu+dot)/(test.nu+float64(len(ob))), &tmp3) if !mat.EqualApprox(&tmp3, &sUp.sigma, 1e-10) { t.Errorf("Sigma mismatch") } } } func TestStudentsTMarginalSingle(t *testing.T) { for _, test := range []struct { mu []float64 sigma *mat.SymDense nu float64 }{ { mu: []float64{2, 3, 4}, sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}), nu: 5, }, { mu: []float64{2, 3, 4, 5}, sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}), nu: 6, }, } { studentst, ok := NewStudentsT(test.mu, test.sigma, test.nu, nil) if !ok { t.Fatalf("Bad test, covariance matrix not positive definite") } for i, mean := range test.mu { st := studentst.MarginalStudentsTSingle(i, nil) if st.Mean() != mean { t.Errorf("Mean mismatch nil Sigma, idx %v: want %v, got %v.", i, mean, st.Mean()) } std := math.Sqrt(test.sigma.At(i, i)) if math.Abs(st.Sigma-std) > 1e-14 { t.Errorf("StdDev mismatch nil Sigma, idx %v: want %v, got %v.", i, std, st.StdDev()) } if st.Nu != test.nu { t.Errorf("Nu mismatch nil Sigma, idx %v: want %v, got %v ", i, test.nu, st.Nu) } } } } golang-gonum-v1-gonum-0.14.0/stat/distmv/uniform.go000066400000000000000000000116371450372207100221350ustar00rootroot00000000000000// 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 distmv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/spatial/r1" ) // Uniform represents a multivariate uniform distribution. type Uniform struct { bounds []r1.Interval dim int rnd *rand.Rand } // NewUniform creates a new uniform distribution with the given bounds. func NewUniform(bnds []r1.Interval, src rand.Source) *Uniform { dim := len(bnds) if dim == 0 { panic(badZeroDimension) } for _, b := range bnds { if b.Max < b.Min { panic("uniform: maximum less than minimum") } } u := &Uniform{ bounds: make([]r1.Interval, dim), dim: dim, } if src != nil { u.rnd = rand.New(src) } for i, b := range bnds { u.bounds[i].Min = b.Min u.bounds[i].Max = b.Max } return u } // NewUnitUniform creates a new Uniform distribution over the dim-dimensional // unit hypercube. That is, a uniform distribution where each dimension has // Min = 0 and Max = 1. func NewUnitUniform(dim int, src rand.Source) *Uniform { if dim <= 0 { panic(nonPosDimension) } bounds := make([]r1.Interval, dim) for i := range bounds { bounds[i].Min = 0 bounds[i].Max = 1 } u := Uniform{ bounds: bounds, dim: dim, } if src != nil { u.rnd = rand.New(src) } return &u } // Bounds returns the bounds on the variables of the distribution. If the input // is nil, a new slice is allocated and returned. If the input is non-nil, then // the bounds are stored in-place into the input argument, and Bounds will panic // if len(bounds) != u.Dim(). func (u *Uniform) Bounds(bounds []r1.Interval) []r1.Interval { if bounds == nil { bounds = make([]r1.Interval, u.Dim()) } if len(bounds) != u.Dim() { panic(badInputLength) } copy(bounds, u.bounds) return bounds } // CDF returns the multidimensional cumulative distribution function of the // probability distribution at the point x. If p is non-nil, the CDF is stored // in-place into the first argument, otherwise a new slice is allocated and // returned. // // CDF will panic if len(x) is not equal to the dimension of the distribution, // or if p is non-nil and len(p) is not equal to the dimension of the distribution. func (u *Uniform) CDF(p, x []float64) []float64 { if len(x) != u.dim { panic(badSizeMismatch) } if p == nil { p = make([]float64, u.dim) } if len(p) != u.dim { panic(badSizeMismatch) } for i, v := range x { if v < u.bounds[i].Min { p[i] = 0 } else if v > u.bounds[i].Max { p[i] = 1 } else { p[i] = (v - u.bounds[i].Min) / (u.bounds[i].Max - u.bounds[i].Min) } } return p } // Dim returns the dimension of the distribution. func (u *Uniform) Dim() int { return u.dim } // Entropy returns the differential entropy of the distribution. func (u *Uniform) Entropy() float64 { // Entropy is log of the volume. var logVol float64 for _, b := range u.bounds { logVol += math.Log(b.Max - b.Min) } return logVol } // LogProb computes the log of the pdf of the point x. func (u *Uniform) LogProb(x []float64) float64 { dim := u.dim if len(x) != dim { panic(badSizeMismatch) } var logprob float64 for i, b := range u.bounds { if x[i] < b.Min || x[i] > b.Max { return math.Inf(-1) } logprob -= math.Log(b.Max - b.Min) } return logprob } // Mean returns the mean of the probability distribution at x. If the // input argument is nil, a new slice will be allocated, otherwise the result // will be put in-place into the receiver. func (u *Uniform) Mean(x []float64) []float64 { x = reuseAs(x, u.dim) for i, b := range u.bounds { x[i] = (b.Max + b.Min) / 2 } return x } // Prob computes the value of the probability density function at x. func (u *Uniform) Prob(x []float64) float64 { return math.Exp(u.LogProb(x)) } // Rand generates a random number according to the distributon. // If the input slice is nil, new memory is allocated, otherwise the result is stored // in place. func (u *Uniform) Rand(x []float64) []float64 { x = reuseAs(x, u.dim) if u.rnd == nil { for i, b := range u.bounds { x[i] = rand.Float64()*(b.Max-b.Min) + b.Min } return x } for i, b := range u.bounds { x[i] = u.rnd.Float64()*(b.Max-b.Min) + b.Min } return x } // Quantile returns the multi-dimensional inverse cumulative distribution function. // len(x) must equal len(p), and if x is non-nil, len(x) must also equal len(p). // If x is nil, a new slice will be allocated and returned, otherwise the quantile // will be stored in-place into x. All of the values of p must be between 0 and 1, // or Quantile will panic. func (u *Uniform) Quantile(x, p []float64) []float64 { if len(p) != u.dim { panic(badSizeMismatch) } if x == nil { x = make([]float64, u.dim) } if len(x) != u.dim { panic(badSizeMismatch) } for i, v := range p { if v < 0 || v > 1 { panic(badQuantile) } x[i] = v*(u.bounds[i].Max-u.bounds[i].Min) + u.bounds[i].Min } return x } golang-gonum-v1-gonum-0.14.0/stat/distmv/uniform_test.go000066400000000000000000000013201450372207100231600ustar00rootroot00000000000000// 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 distmv import ( "math" "testing" "gonum.org/v1/gonum/spatial/r1" ) func TestUniformEntropy(t *testing.T) { for _, test := range []struct { Uniform *Uniform Entropy float64 }{ { NewUniform([]r1.Interval{{Min: 0, Max: 1}, {Min: 0, Max: 1}}, nil), 0, }, { NewUniform([]r1.Interval{{Min: -1, Max: 3}, {Min: 2, Max: 8}, {Min: -5, Max: -3}}, nil), math.Log(48), }, } { ent := test.Uniform.Entropy() if math.Abs(ent-test.Entropy) > 1e-14 { t.Errorf("Entropy mismatch. Got %v, want %v", ent, test.Entropy) } } } golang-gonum-v1-gonum-0.14.0/stat/distuv/000077500000000000000000000000001450372207100201275ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/distuv/alphastable.go000066400000000000000000000060131450372207100227360ustar00rootroot00000000000000// Copyright ©2020 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 distuv import ( "math" "golang.org/x/exp/rand" ) // AlphaStable represents an α-stable distribution with four parameters. // See https://en.wikipedia.org/wiki/Stable_distribution for more information. type AlphaStable struct { // Alpha is the stability parameter. // It is valid within the range 0 < α ≤ 2. Alpha float64 // Beta is the skewness parameter. // It is valid within the range -1 ≤ β ≤ 1. Beta float64 // C is the scale parameter. // It is valid when positive. C float64 // Mu is the location parameter. Mu float64 Src rand.Source } // ExKurtosis returns the excess kurtosis of the distribution. // ExKurtosis returns NaN when Alpha != 2. func (a AlphaStable) ExKurtosis() float64 { if a.Alpha == 2 { return 0 } return math.NaN() } // Mean returns the mean of the probability distribution. // Mean returns NaN when Alpha <= 1. func (a AlphaStable) Mean() float64 { if a.Alpha > 1 { return a.Mu } return math.NaN() } // Median returns the median of the distribution. // Median panics when Beta != 0, because then the mode is not analytically // expressible. func (a AlphaStable) Median() float64 { if a.Beta == 0 { return a.Mu } panic("distuv: cannot compute Median for Beta != 0") } // Mode returns the mode of the distribution. // Mode panics when Beta != 0, because then the mode is not analytically // expressible. func (a AlphaStable) Mode() float64 { if a.Beta == 0 { return a.Mu } panic("distuv: cannot compute Mode for Beta != 0") } // NumParameters returns the number of parameters in the distribution. func (a AlphaStable) NumParameters() int { return 4 } // Rand returns a random sample drawn from the distribution. func (a AlphaStable) Rand() float64 { // From https://en.wikipedia.org/wiki/Stable_distribution#Simulation_of_stable_variables const halfPi = math.Pi / 2 u := Uniform{-halfPi, halfPi, a.Src}.Rand() w := Exponential{1, a.Src}.Rand() if a.Alpha == 1 { f := halfPi + a.Beta*u x := (f*math.Tan(u) - a.Beta*math.Log(halfPi*w*math.Cos(u)/f)) / halfPi return a.C*(x+a.Beta*math.Log(a.C)/halfPi) + a.Mu } zeta := -a.Beta * math.Tan(halfPi*a.Alpha) xi := math.Atan(-zeta) / a.Alpha f := a.Alpha * (u + xi) g := math.Sqrt(1+zeta*zeta) * math.Pow(math.Cos(u-f)/w, 1-a.Alpha) / math.Cos(u) x := math.Pow(g, 1/a.Alpha) * math.Sin(f) return a.C*x + a.Mu } // Skewness returns the skewness of the distribution. // Skewness returns NaN when Alpha != 2. func (a AlphaStable) Skewness() float64 { if a.Alpha == 2 { return 0 } return math.NaN() } // StdDev returns the standard deviation of the probability distribution. func (a AlphaStable) StdDev() float64 { return math.Sqrt(a.Variance()) } // Variance returns the variance of the probability distribution. // Variance returns +Inf when Alpha != 2. func (a AlphaStable) Variance() float64 { if a.Alpha == 2 { return 2 * a.C * a.C } return math.Inf(1) } golang-gonum-v1-gonum-0.14.0/stat/distuv/alphastable_test.go000066400000000000000000000125001450372207100237730ustar00rootroot00000000000000// Copyright ©2020 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/stat" ) func TestAlphaStable(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, dist := range []AlphaStable{ {Alpha: 0.5, Beta: 0, C: 1, Mu: 0, Src: src}, {Alpha: 1, Beta: 0, C: 1, Mu: 0, Src: src}, {Alpha: 2, Beta: 0, C: 1, Mu: 0, Src: src}, {Alpha: 0.5, Beta: 1, C: 1, Mu: 0, Src: src}, {Alpha: 1, Beta: 1, C: 1, Mu: 0, Src: src}, {Alpha: 2, Beta: 1, C: 1, Mu: 0, Src: src}, {Alpha: 0.5, Beta: 0, C: 1, Mu: 1, Src: src}, {Alpha: 1, Beta: 0, C: 1, Mu: 1, Src: src}, {Alpha: 2, Beta: 0, C: 1, Mu: 1, Src: src}, {Alpha: 0.5, Beta: 0.5, C: 1, Mu: 1, Src: src}, {Alpha: 1, Beta: 0.5, C: 1, Mu: 1, Src: src}, {Alpha: 1.1, Beta: 0.5, C: 1, Mu: 1, Src: src}, {Alpha: 2, Beta: 0.5, C: 1, Mu: 1, Src: src}, } { testAlphaStableAnalytic(t, i, dist) } } func TestAlphaStability(t *testing.T) { t.Parallel() const ( n = 10000 ksTol = 2e-2 ) for i, test := range []struct { alpha, beta1, beta2, c1, c2, mu1, mu2 float64 }{ {2, 0, 0, 1, 2, 0.5, 0.25}, {2, 0.9, -0.4, 1, 2, 0.5, 0.25}, {1.9, 0, 0, 1, 2, 0.5, 0.25}, {1, 0, 0, 1, 2, 0.5, 0.25}, {1, -0.5, 0.5, 1, 2, 0.5, 0.25}, {0.5, 0, 0, 1, 2, 0.5, 0.25}, {0.5, -0.5, 0.5, 1, 2, 0.5, 0.25}, } { testStability(t, i, n, test.alpha, test.beta1, test.beta2, test.c1, test.c2, test.mu1, test.mu2, ksTol) } } func TestAlphaStableGaussian(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) d := AlphaStable{Alpha: 2, Beta: 0, C: 1.5, Mu: -0.4, Src: src} n := 100000 x := make([]float64, n) for i := 0; i < n; i++ { x[i] = d.Rand() } checkSkewness(t, 0, x, d, 1e-2) checkExKurtosis(t, 0, x, d, 1e-2) checkMean(t, 0, x, d, 1e-2) checkVarAndStd(t, 0, x, d, 1e-2) checkMode(t, 0, x, d, 5e-2, 1e-1) } func TestAlphaStableMean(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) d := AlphaStable{Alpha: 1.75, Beta: 0.2, C: 1.2, Mu: 0.3, Src: src} n := 100000 x := make([]float64, n) for i := 0; i < n; i++ { x[i] = d.Rand() } checkMean(t, 0, x, d, 1e-2) } func TestAlphaStableCauchy(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) d := AlphaStable{Alpha: 1, Beta: 0, C: 1, Mu: 0, Src: src} n := 1000000 x := make([]float64, n) for i := 0; i < n; i++ { x[i] = d.Rand() } checkMode(t, 0, x, d, 1e-2, 5e-2) } func testAlphaStableAnalytic(t *testing.T, i int, dist AlphaStable) { if dist.NumParameters() != 4 { t.Errorf("%d: expected NumParameters == 4, got %v", i, dist.NumParameters()) } if dist.Beta == 0 { if dist.Mode() != dist.Mu { t.Errorf("%d: expected Mode == Mu for Beta == 0, got %v", i, dist.Mode()) } if dist.Median() != dist.Mu { t.Errorf("%d: expected Median == Mu for Beta == 0, got %v", i, dist.Median()) } } else { if !panics(func() { dist.Mode() }) { t.Errorf("%d: expected Mode to panic for Beta != 0", i) } if !panics(func() { dist.Median() }) { t.Errorf("%d: expected Median to panic for Beta != 0", i) } } if dist.Alpha > 1 { if dist.Mean() != dist.Mu { t.Errorf("%d: expected Mean == Mu for Alpha > 1, got %v", i, dist.Mean()) } } else { if !math.IsNaN(dist.Mean()) { t.Errorf("%d: expected NaN Mean for Alpha <= 1, got %v", i, dist.Mean()) } } if dist.Alpha == 2 { got := dist.Variance() want := 2 * dist.C * dist.C if got != want { t.Errorf("%d: mismatch in Variance for Alpha == 2: got %v, want %g", i, got, want) } got = dist.StdDev() want = math.Sqrt(2) * dist.C if got != want { t.Errorf("%d: mismatch in StdDev for Alpha == 2: got %v, want %g", i, got, want) } got = dist.Skewness() want = 0 if got != want { t.Errorf("%d: mismatch in Skewness for Alpha == 2: got %v, want %g", i, got, want) } got = dist.ExKurtosis() want = 0 if got != want { t.Errorf("%d: mismatch in ExKurtosis for Alpha == 2: got %v, want %g", i, got, want) } } else { got := dist.Variance() if !math.IsInf(got, 1) { t.Errorf("%d: Variance is not +Inf for Alpha != 2: got %v", i, got) } got = dist.StdDev() if !math.IsInf(got, 1) { t.Errorf("%d: StdDev is not +Inf for Alpha != 2: got %v", i, got) } got = dist.Skewness() if !math.IsNaN(got) { t.Errorf("%d: Skewness is not NaN for Alpha != 2: got %v", i, got) } got = dist.ExKurtosis() if !math.IsNaN(got) { t.Errorf("%d: ExKurtosis is not NaN for Alpha != 2: got %v", i, got) } } } func testStability(t *testing.T, i, n int, alpha, beta1, beta2, c1, c2, mu1, mu2, ksTol float64) { src := rand.New(rand.NewSource(1)) d1 := AlphaStable{alpha, beta1, c1, mu1, src} d2 := AlphaStable{alpha, beta2, c2, mu2, src} c := math.Pow(math.Pow(c1, alpha)+math.Pow(c2, alpha), 1/alpha) beta := (beta1*math.Pow(c1, alpha) + beta2*math.Pow(c2, alpha)) / math.Pow(c, alpha) // Sum of d1 and d2. d := AlphaStable{alpha, beta, c, mu1 + mu2, src} sample1 := make([]float64, n) sample2 := make([]float64, n) for i := 0; i < n; i++ { sample1[i] = d1.Rand() + d2.Rand() sample2[i] = d.Rand() } sort.Float64s(sample1) sort.Float64s(sample2) ks := stat.KolmogorovSmirnov(sample1, nil, sample2, nil) if ks > ksTol { t.Errorf("%d: Kolmogorov-Smirnov distance %g exceeding tolerance %g", i, ks, ksTol) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/bernoulli.go000066400000000000000000000057151450372207100224610ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "golang.org/x/exp/rand" ) // Bernoulli represents a random variable whose value is 1 with probability p and // value of zero with probability 1-P. The value of P must be between 0 and 1. // More information at https://en.wikipedia.org/wiki/Bernoulli_distribution. type Bernoulli struct { P float64 Src rand.Source } // CDF computes the value of the cumulative density function at x. func (b Bernoulli) CDF(x float64) float64 { if x < 0 { return 0 } if x < 1 { return 1 - b.P } return 1 } // Entropy returns the entropy of the distribution. func (b Bernoulli) Entropy() float64 { if b.P == 0 || b.P == 1 { return 0 } q := 1 - b.P return -b.P*math.Log(b.P) - q*math.Log(q) } // ExKurtosis returns the excess kurtosis of the distribution. func (b Bernoulli) ExKurtosis() float64 { pq := b.P * (1 - b.P) return (1 - 6*pq) / pq } // LogProb computes the natural logarithm of the value of the probability density function at x. func (b Bernoulli) LogProb(x float64) float64 { if x == 0 { return math.Log(1 - b.P) } if x == 1 { return math.Log(b.P) } return math.Inf(-1) } // Mean returns the mean of the probability distribution. func (b Bernoulli) Mean() float64 { return b.P } // Median returns the median of the probability distribution. func (b Bernoulli) Median() float64 { p := b.P switch { case p < 0.5: return 0 case p > 0.5: return 1 default: return 0.5 } } // NumParameters returns the number of parameters in the distribution. func (Bernoulli) NumParameters() int { return 1 } // Prob computes the value of the probability distribution at x. func (b Bernoulli) Prob(x float64) float64 { if x == 0 { return 1 - b.P } if x == 1 { return b.P } return 0 } // Quantile returns the minimum value of x from amongst all those values whose CDF value exceeds or equals p. func (b Bernoulli) Quantile(p float64) float64 { if p < 0 || 1 < p { panic(badPercentile) } if p <= 1-b.P { return 0 } return 1 } // Rand returns a random sample drawn from the distribution. func (b Bernoulli) Rand() float64 { var rnd float64 if b.Src == nil { rnd = rand.Float64() } else { rnd = rand.New(b.Src).Float64() } if rnd < b.P { return 1 } return 0 } // Skewness returns the skewness of the distribution. func (b Bernoulli) Skewness() float64 { return (1 - 2*b.P) / math.Sqrt(b.P*(1-b.P)) } // StdDev returns the standard deviation of the probability distribution. func (b Bernoulli) StdDev() float64 { return math.Sqrt(b.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (b Bernoulli) Survival(x float64) float64 { if x < 0 { return 1 } if x < 1 { return b.P } return 0 } // Variance returns the variance of the probability distribution. func (b Bernoulli) Variance() float64 { return b.P * (1 - b.P) } golang-gonum-v1-gonum-0.14.0/stat/distuv/bernoulli_test.go000066400000000000000000000103171450372207100235120ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" ) func TestBernoulli(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, dist := range []Bernoulli{ {P: 0.5, Src: src}, {P: 0.9, Src: src}, {P: 0.2, Src: src}, {P: 0.0, Src: src}, {P: 1.0, Src: src}, } { testBernoulli(t, dist, i) testBernoulliCDF(t, dist) testBernoulliSurvival(t, dist) testBernoulliQuantile(t, dist) if dist.P == 0 || dist.P == 1 { entropy := dist.Entropy() if entropy != 0 { t.Errorf("Entropy of a Bernoulli distribution with P = %g is not zero, got: %g", dist.P, entropy) } } if dist.NumParameters() != 1 { t.Errorf("Wrong number of parameters") } for _, x := range []float64{-0.2, 0.5, 1.1} { logP := dist.LogProb(x) p := dist.Prob(x) if !math.IsInf(logP, -1) { t.Errorf("Log-probability for x = %g is not -Inf, got: %g", x, logP) } if p != 0 { t.Errorf("Probability for x = %g is not 0, got: %g", x, p) } } } } func testBernoulli(t *testing.T, dist Bernoulli, i int) { const ( tol = 1e-2 n = 3e6 bins = 50 ) x := make([]float64, n) generateSamples(x, dist) sort.Float64s(x) checkMean(t, i, x, dist, tol) checkVarAndStd(t, i, x, dist, tol) checkEntropy(t, i, x, dist, tol) checkProbDiscrete(t, i, x, dist, tol) if dist.P != 0 && dist.P != 1 { // Sample kurtosis and skewness are going to be NaN for P = 0 or 1. checkExKurtosis(t, i, x, dist, tol) checkSkewness(t, i, x, dist, tol) } else { if !math.IsInf(dist.ExKurtosis(), 1) { t.Errorf("Excess kurtosis for P == 0 or 1 is not +Inf") } skewness := dist.Skewness() if dist.P == 0 { if !math.IsInf(skewness, 1) { t.Errorf("Skewness for P == 0 is not +Inf") } } else { if !math.IsInf(skewness, -1) { t.Errorf("Skewness for P == 1 is not -Inf") } } } if dist.P != 0.5 { checkMedian(t, i, x, dist, tol) } else if dist.Median() != 0.5 { t.Errorf("Median for P == 0.5 is not 0.5") } } func testBernoulliCDF(t *testing.T, dist Bernoulli) { if dist.CDF(-0.000001) != 0 { t.Errorf("Bernoulli CDF below zero is not zero") } if dist.CDF(0) != 1-dist.P { t.Errorf("Bernoulli CDF at zero is not 1 - P(1)") } if dist.CDF(0.0001) != 1-dist.P { t.Errorf("Bernoulli CDF between zero and one is not 1 - P(1)") } if dist.CDF(0.9999) != 1-dist.P { t.Errorf("Bernoulli CDF between zero and one is not 1 - P(1)") } if dist.CDF(1) != 1 { t.Errorf("Bernoulli CDF at one is not one") } if dist.CDF(1.00001) != 1 { t.Errorf("Bernoulli CDF above one is not one") } } func testBernoulliSurvival(t *testing.T, dist Bernoulli) { if dist.Survival(-0.000001) != 1 { t.Errorf("Bernoulli Survival below zero is not one") } if dist.Survival(0) != dist.P { t.Errorf("Bernoulli Survival at zero is not P(1)") } if dist.Survival(0.0001) != dist.P { t.Errorf("Bernoulli Survival between zero and one is not P(1)") } if dist.Survival(1) != 0 { t.Errorf("Bernoulli Survival at one is not zero") } if dist.Survival(1.00001) != 0 { t.Errorf("Bernoulli Survival above one is not zero") } } func testBernoulliQuantile(t *testing.T, dist Bernoulli) { if !panics(func() { dist.Quantile(-0.0001) }) { t.Errorf("Expected panic with negative argument") } if !panics(func() { dist.Quantile(1.0001) }) { t.Errorf("Expected panic with argument above 1") } for _, x := range []float64{0., 1.} { want := x if dist.P == 0 { want = 0 } if dist.Quantile(dist.CDF(x)) != want { t.Errorf("Quantile(CDF(x)) not equal to %g for x = %g for P = %g", want, x, dist.P) } } expectedQuantile1 := 1. if dist.P == 0 { expectedQuantile1 = 0. } if dist.Quantile(1) != expectedQuantile1 { t.Errorf("Quantile at 1 not equal to 1 for P = %g", dist.P) } eps := 1e-12 if dist.P > eps && dist.P < 1-eps { if dist.Quantile(1-dist.P-eps) != 0 { t.Errorf("Quantile slightly below 0 < 1-P < 1 is not zero") } if dist.Quantile(1-dist.P+eps) != 1 { t.Errorf("Quantile slightly above 0 < 1-P < 1 is not one") } if dist.Quantile(1-dist.P) != 0 { t.Errorf("Quantile at 0 < 1-P < 1 is not zero") } } } golang-gonum-v1-gonum-0.14.0/stat/distuv/beta.go000066400000000000000000000076521450372207100214030ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) // Beta implements the Beta distribution, a two-parameter continuous distribution // with support between 0 and 1. // // The beta distribution has density function // // x^(α-1) * (1-x)^(β-1) * Γ(α+β) / (Γ(α)*Γ(β)) // // For more information, see https://en.wikipedia.org/wiki/Beta_distribution type Beta struct { // Alpha is the left shape parameter of the distribution. Alpha must be greater // than 0. Alpha float64 // Beta is the right shape parameter of the distribution. Beta must be greater // than 0. Beta float64 Src rand.Source } // CDF computes the value of the cumulative distribution function at x. func (b Beta) CDF(x float64) float64 { if x <= 0 { return 0 } if x >= 1 { return 1 } return mathext.RegIncBeta(b.Alpha, b.Beta, x) } // Entropy returns the differential entropy of the distribution. func (b Beta) Entropy() float64 { if b.Alpha <= 0 || b.Beta <= 0 { panic("beta: negative parameters") } return mathext.Lbeta(b.Alpha, b.Beta) - (b.Alpha-1)*mathext.Digamma(b.Alpha) - (b.Beta-1)*mathext.Digamma(b.Beta) + (b.Alpha+b.Beta-2)*mathext.Digamma(b.Alpha+b.Beta) } // ExKurtosis returns the excess kurtosis of the distribution. func (b Beta) ExKurtosis() float64 { num := 6 * ((b.Alpha-b.Beta)*(b.Alpha-b.Beta)*(b.Alpha+b.Beta+1) - b.Alpha*b.Beta*(b.Alpha+b.Beta+2)) den := b.Alpha * b.Beta * (b.Alpha + b.Beta + 2) * (b.Alpha + b.Beta + 3) return num / den } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (b Beta) LogProb(x float64) float64 { if x < 0 || x > 1 { return math.Inf(-1) } if b.Alpha <= 0 || b.Beta <= 0 { panic("beta: negative parameters") } lab, _ := math.Lgamma(b.Alpha + b.Beta) la, _ := math.Lgamma(b.Alpha) lb, _ := math.Lgamma(b.Beta) var lx float64 if b.Alpha != 1 { lx = (b.Alpha - 1) * math.Log(x) } var l1mx float64 if b.Beta != 1 { l1mx = (b.Beta - 1) * math.Log(1-x) } return lab - la - lb + lx + l1mx } // Mean returns the mean of the probability distribution. func (b Beta) Mean() float64 { return b.Alpha / (b.Alpha + b.Beta) } // Mode returns the mode of the distribution. // // Mode returns NaN if both parameters are less than or equal to 1 as a special case, // 0 if only Alpha <= 1 and 1 if only Beta <= 1. func (b Beta) Mode() float64 { if b.Alpha <= 1 { if b.Beta <= 1 { return math.NaN() } return 0 } if b.Beta <= 1 { return 1 } return (b.Alpha - 1) / (b.Alpha + b.Beta - 2) } // NumParameters returns the number of parameters in the distribution. func (b Beta) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (b Beta) Prob(x float64) float64 { return math.Exp(b.LogProb(x)) } // Quantile returns the inverse of the cumulative distribution function. func (b Beta) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } return mathext.InvRegIncBeta(b.Alpha, b.Beta, p) } // Rand returns a random sample drawn from the distribution. func (b Beta) Rand() float64 { ga := Gamma{Alpha: b.Alpha, Beta: 1, Src: b.Src}.Rand() gb := Gamma{Alpha: b.Beta, Beta: 1, Src: b.Src}.Rand() return ga / (ga + gb) } // StdDev returns the standard deviation of the probability distribution. func (b Beta) StdDev() float64 { return math.Sqrt(b.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (b Beta) Survival(x float64) float64 { switch { case x <= 0: return 1 case x >= 1: return 0 } return mathext.RegIncBeta(b.Beta, b.Alpha, 1-x) } // Variance returns the variance of the probability distribution. func (b Beta) Variance() float64 { return b.Alpha * b.Beta / ((b.Alpha + b.Beta) * (b.Alpha + b.Beta) * (b.Alpha + b.Beta + 1)) } golang-gonum-v1-gonum-0.14.0/stat/distuv/beta_test.go000066400000000000000000000101071450372207100224270ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestBetaProb(t *testing.T) { t.Parallel() // Values a comparison with scipy for _, test := range []struct { x, alpha, beta, want float64 }{ {0.1, 2, 0.5, 0.079056941504209499}, {0.5, 1, 5.1, 0.29740426605235754}, {0.1, 0.5, 0.5, 1.0610329539459691}, {1, 0.5, 0.5, math.Inf(1)}, {-1, 0.5, 0.5, 0}, } { pdf := Beta{Alpha: test.alpha, Beta: test.beta}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Pdf mismatch. Got %v, want %v", pdf, test.want) } } } func TestBetaRand(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []Beta{ {Alpha: 0.5, Beta: 0.5, Src: src}, {Alpha: 5, Beta: 1, Src: src}, {Alpha: 2, Beta: 2, Src: src}, {Alpha: 2, Beta: 5, Src: src}, } { testBeta(t, b, i) } } func testBeta(t *testing.T, b Beta, i int) { const ( tol = 1e-2 n = 1e5 bins = 10 ) x := make([]float64, n) generateSamples(x, b) sort.Float64s(x) testRandLogProbContinuous(t, i, 0, x, b, tol, bins) checkMean(t, i, x, b, tol) checkVarAndStd(t, i, x, b, tol) checkExKurtosis(t, i, x, b, 5e-2) checkEntropy(t, i, x, b, 5e-3) checkProbContinuous(t, i, x, 0, 1, b, 1e-6) checkQuantileCDFSurvival(t, i, x, b, tol) checkProbQuantContinuous(t, i, x, b, tol) if b.NumParameters() != 2 { t.Errorf("Wrong number of parameters") } if b.CDF(-0.01) != 0 { t.Errorf("CDF below 0 is not 0") } if b.CDF(0) != 0 { t.Errorf("CDF at 0 is not 0") } if b.CDF(1) != 1 { t.Errorf("CDF at 1 is not 1") } if b.CDF(1.01) != 1 { t.Errorf("CDF above 1 is not 1") } if b.Survival(-0.01) != 1 { t.Errorf("Survival below 0 is not 1") } if b.Survival(0) != 1 { t.Errorf("Survival at 0 is not 1") } if b.Survival(1) != 0 { t.Errorf("Survival at 1 is not 0") } if b.Survival(1.01) != 0 { t.Errorf("Survival above 1 is not 0") } } func TestBetaBadParams(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for _, alpha := range []float64{0, -0.1} { testBetaBadParams(t, alpha, 1, src) testBetaBadParams(t, 1, alpha, src) for _, beta := range []float64{0, -0.1} { testBetaBadParams(t, alpha, beta, src) } } } func testBetaBadParams(t *testing.T, alpha float64, beta float64, src rand.Source) { b := Beta{alpha, beta, src} if !panics(func() { b.Entropy() }) { t.Errorf("Entropy did not panic for Beta(%g, %g)", alpha, beta) } if !panics(func() { b.LogProb(0.5) }) { t.Errorf("LogProb did not panic for Beta(%g, %g)", alpha, beta) } } func TestBetaMode(t *testing.T) { t.Parallel() for _, test := range []struct { alpha, beta, want float64 }{ {1, 2, 0}, {0.5, 2, 0}, {2, 1, 1}, {2, 0.5, 1}, {4, 5, 3. / 7.}, } { mode := Beta{Alpha: test.alpha, Beta: test.beta}.Mode() if !scalar.EqualWithinAbsOrRel(mode, test.want, 1e-10, 1e-10) { t.Errorf("Mode mismatch for Beta(%g, %g). Got %v, want %g", test.alpha, test.beta, mode, test.want) } } for _, test := range []struct { alpha, beta float64 }{ {1, 1}, {0.5, 0.5}, {1, 0.5}, {0.5, 1}, } { mode := Beta{Alpha: test.alpha, Beta: test.beta}.Mode() if !math.IsNaN(mode) { t.Errorf("Mode is not NaN for Beta(%g, %g). Got: %v", test.alpha, test.beta, mode) } } } // See https://github.com/gonum/gonum/issues/1377 for details. func TestBetaIssue1377(t *testing.T) { t.Parallel() b := Beta{Alpha: 1, Beta: 1} p0 := b.Prob(0) if p0 != 1 { t.Errorf("Mismatch in PDF value at x == 0 for Alpha == 1 and Beta == 1: got %v, want 1", p0) } p1 := b.Prob(1) if p1 != 1 { t.Errorf("Mismatch in PDF value at x == 1 for Alpha == 1 and Beta == 1: got %v, want 1", p1) } b = Beta{Alpha: 1, Beta: 10} p0 = b.Prob(0) if math.IsNaN(p0) { t.Errorf("NaN PDF at x == 0 for Alpha == 1 and Beta > 10") } b = Beta{Alpha: 10, Beta: 1} p1 = b.Prob(1) if math.IsNaN(p1) { t.Errorf("NaN PDF at x == 1 for Alpha > 1 and Beta == 1") } } golang-gonum-v1-gonum-0.14.0/stat/distuv/binomial.go000066400000000000000000000112711450372207100222520ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" "gonum.org/v1/gonum/stat/combin" ) // Binomial implements the binomial distribution, a discrete probability distribution // that expresses the probability of a given number of successful Bernoulli trials // out of a total of n, each with success probability p. // The binomial distribution has the density function: // // f(k) = (n choose k) p^k (1-p)^(n-k) // // For more information, see https://en.wikipedia.org/wiki/Binomial_distribution. type Binomial struct { // N is the total number of Bernoulli trials. N must be greater than 0. N float64 // P is the probability of success in any given trial. P must be in [0, 1]. P float64 Src rand.Source } // CDF computes the value of the cumulative distribution function at x. func (b Binomial) CDF(x float64) float64 { if x < 0 { return 0 } if x >= b.N { return 1 } x = math.Floor(x) return mathext.RegIncBeta(b.N-x, x+1, 1-b.P) } // ExKurtosis returns the excess kurtosis of the distribution. func (b Binomial) ExKurtosis() float64 { v := b.P * (1 - b.P) return (1 - 6*v) / (b.N * v) } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (b Binomial) LogProb(x float64) float64 { if x < 0 || x > b.N || math.Floor(x) != x { return math.Inf(-1) } lb := combin.LogGeneralizedBinomial(b.N, x) return lb + x*math.Log(b.P) + (b.N-x)*math.Log(1-b.P) } // Mean returns the mean of the probability distribution. func (b Binomial) Mean() float64 { return b.N * b.P } // NumParameters returns the number of parameters in the distribution. func (Binomial) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (b Binomial) Prob(x float64) float64 { return math.Exp(b.LogProb(x)) } // Rand returns a random sample drawn from the distribution. func (b Binomial) Rand() float64 { // NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5) // p. 295-6 // http://www.aip.de/groups/soe/local/numres/bookcpdf/c7-3.pdf runif := rand.Float64 rexp := rand.ExpFloat64 if b.Src != nil { rnd := rand.New(b.Src) runif = rnd.Float64 rexp = rnd.ExpFloat64 } p := b.P if p > 0.5 { p = 1 - p } am := b.N * p if b.N < 25 { // Use direct method. bnl := 0.0 for i := 0; i < int(b.N); i++ { if runif() < p { bnl++ } } if p != b.P { return b.N - bnl } return bnl } if am < 1 { // Use rejection method with Poisson proposal. const logM = 2.6e-2 // constant for rejection sampling (https://en.wikipedia.org/wiki/Rejection_sampling) var bnl float64 z := -p pclog := (1 + 0.5*z) * z / (1 + (1+1.0/6*z)*z) // Padé approximant of log(1 + x) for { bnl = 0.0 t := 0.0 for i := 0; i < int(b.N); i++ { t += rexp() if t >= am { break } bnl++ } bnlc := b.N - bnl z = -bnl / b.N log1p := (1 + 0.5*z) * z / (1 + (1+1.0/6*z)*z) t = (bnlc+0.5)*log1p + bnl - bnlc*pclog + 1/(12*bnlc) - am + logM // Uses Stirling's expansion of log(n!) if rexp() >= t { break } } if p != b.P { return b.N - bnl } return bnl } // Original algorithm samples from a Poisson distribution with the // appropriate expected value. However, the Poisson approximation is // asymptotic such that the absolute deviation in probability is O(1/n). // Rejection sampling produces exact variates with at worst less than 3% // rejection with minimal additional computation. // Use rejection method with Cauchy proposal. g, _ := math.Lgamma(b.N + 1) plog := math.Log(p) pclog := math.Log1p(-p) sq := math.Sqrt(2 * am * (1 - p)) for { var em, y float64 for { y = math.Tan(math.Pi * runif()) em = sq*y + am if em >= 0 && em < b.N+1 { break } } em = math.Floor(em) lg1, _ := math.Lgamma(em + 1) lg2, _ := math.Lgamma(b.N - em + 1) t := 1.2 * sq * (1 + y*y) * math.Exp(g-lg1-lg2+em*plog+(b.N-em)*pclog) if runif() <= t { if p != b.P { return b.N - em } return em } } } // Skewness returns the skewness of the distribution. func (b Binomial) Skewness() float64 { return (1 - 2*b.P) / b.StdDev() } // StdDev returns the standard deviation of the probability distribution. func (b Binomial) StdDev() float64 { return math.Sqrt(b.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (b Binomial) Survival(x float64) float64 { return 1 - b.CDF(x) } // Variance returns the variance of the probability distribution. func (b Binomial) Variance() float64 { return b.N * b.P * (1 - b.P) } golang-gonum-v1-gonum-0.14.0/stat/distuv/binomial_test.go000066400000000000000000000074121450372207100233130ustar00rootroot00000000000000// 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 distuv import ( "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestBinomialProb(t *testing.T) { t.Parallel() const tol = 1e-10 for i, tt := range []struct { k float64 n float64 p float64 want float64 }{ // Probabilities computed with Wolfram|Alpha (http://wwww.wolframalpha.com) {0, 10, 0.5, 0.0009765625}, {1, 10, 0.5, 0.009765625}, {2, 10, 0.5, 0.0439453125}, {3, 10, 0.5, 0.1171875}, {4, 10, 0.5, 0.205078125}, {5, 10, 0.75, 5.839920043945313e-02}, {6, 10, 0.75, 0.1459980010986328}, {7, 10, 0.75, 0.2502822875976563}, {8, 10, 0.75, 0.2815675735473633}, {9, 10, 0.75, 0.1877117156982422}, {10, 10, 0.75, 5.6313514709472656e-02}, {0, 25, 0.25, 7.525434581650003e-04}, {2, 25, 0.25, 2.508478193883334e-02}, {5, 25, 0.25, 0.1645375881987921}, {7, 25, 0.25, 0.1654081574485211}, {10, 25, 0.25, 4.165835076481272e-02}, {12, 25, 0.01, 4.563372575901533e-18}, {15, 25, 0.01, 2.956207951505780e-24}, {17, 25, 0.01, 9.980175928758777e-29}, {20, 25, 0.99, 4.345539559454088e-06}, {22, 25, 0.99, 1.843750355939806e-03}, {25, 25, 0.99, 0.7778213593991468}, {0.5, 25, 0.5, 0}, {1.5, 25, 0.5, 0}, {2.5, 25, 0.5, 0}, {3.5, 25, 0.5, 0}, {4.5, 25, 0.5, 0}, {5.5, 25, 0.5, 0}, {6.5, 25, 0.5, 0}, {7.5, 25, 0.5, 0}, {8.5, 25, 0.5, 0}, {9.5, 25, 0.5, 0}, } { b := Binomial{N: tt.n, P: tt.p} got := b.Prob(tt.k) if !scalar.EqualWithinRel(got, tt.want, tol) { t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want) } } } func TestBinomialCDF(t *testing.T) { t.Parallel() const tol = 1e-10 for i, tt := range []struct { k float64 n float64 p float64 want float64 }{ // Cumulative probabilities computed with SciPy {-1, 10, 0.5, 0}, {0, 10, 0.5, 9.765625e-04}, {1, 10, 0.5, 1.0742187499999998e-02}, {2, 10, 0.5, 5.468749999999999e-02}, {3, 10, 0.5, 1.7187499999999994e-01}, {4, 10, 0.5, 3.769531249999999e-01}, {5, 10, 0.25, 9.802722930908203e-01}, {6, 10, 0.25, 9.964942932128906e-01}, {7, 10, 0.25, 9.995841979980469e-01}, {8, 10, 0.25, 9.999704360961914e-01}, {9, 10, 0.25, 9.999990463256836e-01}, {10, 10, 0.25, 1.0}, {0, 25, 0.75, 8.881784197001252e-16}, {2.5, 25, 0.75, 2.4655832930875472e-12}, {5, 25, 0.75, 1.243460090449844e-08}, {7.5, 25, 0.75, 1.060837565347583e-06}, {10, 25, 0.75, 2.1451240486669576e-04}, {12.5, 25, 0.01, 9.999999999999999e-01}, {15, 25, 0.01, 9.999999999999999e-01}, {17.5, 25, 0.01, 9.999999999999999e-01}, {20, 25, 0.99, 4.495958469027147e-06}, {22.5, 25, 0.99, 1.9506768897388268e-03}, {25, 25, 0.99, 1.0}, } { b := Binomial{N: tt.n, P: tt.p} got := b.CDF(tt.k) if !scalar.EqualWithinRel(got, tt.want, tol) { t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want) } got = b.Survival(tt.k) want := 1 - tt.want if !scalar.EqualWithinRel(got, want, tol) { t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want) } } } func TestBinomial(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []Binomial{ {100, 0.5, src}, {15, 0.25, src}, {10, 0.75, src}, {9000, 0.102, src}, {1e6, 0.001, src}, {25, 0.02, src}, {25, 0.99, src}, {25, 0.46, src}, {25, 0.55, src}, {3, 0.8, src}, } { testBinomial(t, b, i) } } func testBinomial(t *testing.T, b Binomial, i int) { const ( tol = 1e-2 n = 1e6 ) x := make([]float64, n) generateSamples(x, b) sort.Float64s(x) checkMean(t, i, x, b, tol) checkVarAndStd(t, i, x, b, tol) checkExKurtosis(t, i, x, b, 7e-2) checkSkewness(t, i, x, b, tol) if b.NumParameters() != 2 { t.Errorf("Wrong number of parameters") } } golang-gonum-v1-gonum-0.14.0/stat/distuv/categorical.go000066400000000000000000000107131450372207100227350ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" ) // Categorical is an extension of the Bernoulli distribution where x takes // values {0, 1, ..., len(w)-1} where w is the weight vector. Categorical must // be initialized with NewCategorical. type Categorical struct { weights []float64 // heap is a weight heap. // // It keeps a heap-organised sum of remaining // index weights that are available to be taken // from. // // Each element holds the sum of weights for // the corresponding index, plus the sum of // its children's weights; the children of // an element i can be found at positions // 2*(i+1)-1 and 2*(i+1). The root of the // weight heap is at element 0. // // See comments in container/heap for an // explanation of the layout of a heap. heap []float64 src rand.Source } // NewCategorical constructs a new categorical distribution where the probability // that x equals i is proportional to w[i]. All of the weights must be // nonnegative, and at least one of the weights must be positive. func NewCategorical(w []float64, src rand.Source) Categorical { c := Categorical{ weights: make([]float64, len(w)), heap: make([]float64, len(w)), src: src, } c.ReweightAll(w) return c } // CDF computes the value of the cumulative density function at x. func (c Categorical) CDF(x float64) float64 { var cdf float64 for i, w := range c.weights { if x < float64(i) { break } cdf += w } return cdf / c.heap[0] } // Entropy returns the entropy of the distribution. func (c Categorical) Entropy() float64 { var ent float64 for _, w := range c.weights { if w == 0 { continue } p := w / c.heap[0] ent += p * math.Log(p) } return -ent } // Len returns the number of values x could possibly take (the length of the // initial supplied weight vector). func (c Categorical) Len() int { return len(c.weights) } // Mean returns the mean of the probability distribution. func (c Categorical) Mean() float64 { var mean float64 for i, v := range c.weights { mean += float64(i) * v } return mean / c.heap[0] } // Prob computes the value of the probability density function at x. func (c Categorical) Prob(x float64) float64 { xi := int(x) if float64(xi) != x { return 0 } if xi < 0 || xi > len(c.weights)-1 { return 0 } return c.weights[xi] / c.heap[0] } // LogProb computes the natural logarithm of the value of the probability density function at x. func (c Categorical) LogProb(x float64) float64 { return math.Log(c.Prob(x)) } // Rand returns a random draw from the categorical distribution. func (c Categorical) Rand() float64 { var r float64 if c.src == nil { r = c.heap[0] * rand.Float64() } else { r = c.heap[0] * rand.New(c.src).Float64() } i := 1 last := -1 left := len(c.weights) for { if r -= c.weights[i-1]; r <= 0 { break // Fall within item i-1. } i <<= 1 // Move to left child. if d := c.heap[i-1]; r > d { r -= d // If enough r to pass left child, // move to right child state will // be caught at break above. i++ } if i == last || left < 0 { panic("categorical: bad sample") } last = i left-- } return float64(i - 1) } // Reweight sets the weight of item idx to w. The input weight must be // non-negative, and after reweighting at least one of the weights must be // positive. func (c Categorical) Reweight(idx int, w float64) { if w < 0 { panic("categorical: negative weight") } w, c.weights[idx] = c.weights[idx]-w, w idx++ for idx > 0 { c.heap[idx-1] -= w idx >>= 1 } if c.heap[0] <= 0 { panic("categorical: sum of the weights non-positive") } } // ReweightAll resets the weights of the distribution. ReweightAll panics if // len(w) != c.Len. All of the weights must be nonnegative, and at least one of // the weights must be positive. func (c Categorical) ReweightAll(w []float64) { if len(w) != c.Len() { panic("categorical: length of the slices do not match") } for _, v := range w { if v < 0 { panic("categorical: negative weight") } } copy(c.weights, w) c.reset() } func (c Categorical) reset() { copy(c.heap, c.weights) for i := len(c.heap) - 1; i > 0; i-- { // Sometimes 1-based counting makes sense. c.heap[((i+1)>>1)-1] += c.heap[i] } // TODO(btracey): Renormalization for weird weights? if c.heap[0] <= 0 { panic("categorical: sum of the weights non-positive") } } golang-gonum-v1-gonum-0.14.0/stat/distuv/categorical_test.go000066400000000000000000000153111450372207100237730ustar00rootroot00000000000000// 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 distuv import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) const ( Tiny = 2 Small = 5 Medium = 10 Large = 100 Huge = 1000 ) func TestCategoricalProb(t *testing.T) { t.Parallel() for _, test := range [][]float64{ {1, 2, 3, 0}, } { dist := NewCategorical(test, nil) norm := make([]float64, len(test)) floats.Scale(1/floats.Sum(norm), norm) for i, v := range norm { p := dist.Prob(float64(i)) if math.Abs(p-v) > 1e-14 { t.Errorf("Probability mismatch element %d", i) } logP := dist.LogProb(float64(i)) if math.Abs(logP-math.Log(v)) > 1e-14 { t.Errorf("Log-probability mismatch element %d", i) } p = dist.Prob(float64(i) + 0.5) if p != 0 { t.Errorf("Non-zero probability for non-integer x") } logP = dist.LogProb(float64(i) + 0.5) if !math.IsInf(logP, -1) { t.Errorf("Log-probability for non-integer x is not -Inf") } } p := dist.Prob(-1) if p != 0 { t.Errorf("Non-zero probability for -1") } logP := dist.LogProb(-1) if !math.IsInf(logP, -1) { t.Errorf("Log-probability for -1 is not -Inf") } p = dist.Prob(float64(len(test))) if p != 0 { t.Errorf("Non-zero probability for len(test)") } logP = dist.LogProb(float64(len(test))) if !math.IsInf(logP, -1) { t.Errorf("Log-probability for len(test) is not -Inf") } } } func TestCategoricalRand(t *testing.T) { t.Parallel() for _, test := range [][]float64{ {1, 2, 3, 0}, } { dist := NewCategorical(test, nil) nSamples := 2000000 counts := sampleCategorical(t, dist, nSamples) probs := make([]float64, len(test)) for i := range probs { probs[i] = dist.Prob(float64(i)) } same := samedDistCategorical(dist, counts, probs, 1e-2) if !same { t.Errorf("Probability mismatch. Want %v, got %v", probs, counts) } dist.Reweight(len(test)-1, 10) counts = sampleCategorical(t, dist, nSamples) probs = make([]float64, len(test)) for i := range probs { probs[i] = dist.Prob(float64(i)) } same = samedDistCategorical(dist, counts, probs, 1e-2) if !same { t.Errorf("Probability mismatch after Reweight. Want %v, got %v", probs, counts) } w := make([]float64, len(test)) for i := range w { w[i] = rand.Float64() } dist.ReweightAll(w) counts = sampleCategorical(t, dist, nSamples) probs = make([]float64, len(test)) for i := range probs { probs[i] = dist.Prob(float64(i)) } same = samedDistCategorical(dist, counts, probs, 1e-2) if !same { t.Errorf("Probability mismatch after ReweightAll. Want %v, got %v", probs, counts) } } } func TestCategoricalReweight(t *testing.T) { t.Parallel() dist := NewCategorical([]float64{1, 1}, nil) if !panics(func() { dist.Reweight(0, -1) }) { t.Errorf("Reweight did not panic for negative weight") } dist.Reweight(0, 0) if !panics(func() { dist.Reweight(1, 0) }) { t.Errorf("Reweight did not panic when trying to set the last positive weight to zero") } } func TestCategoricalReweightAll(t *testing.T) { t.Parallel() w := []float64{0, 1, 2, 1} dist := NewCategorical(w, nil) if !panics(func() { dist.ReweightAll([]float64{1, 1}) }) { t.Errorf("ReweightAll did not panic for different number of weights") } w[0] = -1 if !panics(func() { dist.ReweightAll(w) }) { t.Errorf("ReweightAll did not panic for a negative weight") } w = []float64{0, 0, 0, 0} if !panics(func() { dist.ReweightAll(w) }) { t.Errorf("ReweightAll did not panic for weights which are all zero") } } func sampleCategorical(t *testing.T, dist Categorical, nSamples int) []float64 { counts := make([]float64, dist.Len()) for i := 0; i < nSamples; i++ { v := dist.Rand() if float64(int(v)) != v { t.Fatalf("Random number is not an integer") } counts[int(v)]++ } sum := floats.Sum(counts) floats.Scale(1/sum, counts) return counts } func samedDistCategorical(dist Categorical, counts, probs []float64, tol float64) bool { same := true for i, prob := range probs { if prob == 0 && counts[i] != 0 { same = false break } if !scalar.EqualWithinAbsOrRel(prob, counts[i], tol, tol) { same = false break } } return same } func TestCategoricalCDF(t *testing.T) { t.Parallel() for _, test := range [][]float64{ {1, 2, 3, 0, 4}, } { c := make([]float64, len(test)) copy(c, test) floats.Scale(1/floats.Sum(c), c) sum := make([]float64, len(test)) floats.CumSum(sum, c) dist := NewCategorical(test, nil) cdf := dist.CDF(-0.5) if cdf != 0 { t.Errorf("CDF of negative number not zero") } for i := range c { cdf := dist.CDF(float64(i)) if math.Abs(cdf-sum[i]) > 1e-14 { t.Errorf("CDF mismatch %v. Want %v, got %v.", float64(i), sum[i], cdf) } cdfp := dist.CDF(float64(i) + 0.5) if cdfp != cdf { t.Errorf("CDF mismatch for non-integer input") } } } } func TestCategoricalEntropy(t *testing.T) { t.Parallel() for _, test := range []struct { weights []float64 entropy float64 }{ { weights: []float64{1, 1}, entropy: math.Ln2, }, { weights: []float64{1, 1, 1, 1}, entropy: math.Log(4), }, { weights: []float64{0, 0, 1, 1, 0, 0}, entropy: math.Ln2, }, } { dist := NewCategorical(test.weights, nil) entropy := dist.Entropy() if math.IsNaN(entropy) || math.Abs(entropy-test.entropy) > 1e-14 { t.Errorf("Entropy mismatch. Want %v, got %v.", test.entropy, entropy) } } } func TestCategoricalMean(t *testing.T) { t.Parallel() for _, test := range []struct { weights []float64 mean float64 }{ { weights: []float64{10, 0, 0, 0}, mean: 0, }, { weights: []float64{0, 10, 0, 0}, mean: 1, }, { weights: []float64{1, 2, 3, 4}, mean: 2, }, } { dist := NewCategorical(test.weights, nil) mean := dist.Mean() if math.IsNaN(mean) || math.Abs(mean-test.mean) > 1e-14 { t.Errorf("Entropy mismatch. Want %v, got %v.", test.mean, mean) } } } func BenchmarkCategoricalRandTiny(b *testing.B) { benchmarkCategoricalRand(b, Tiny) } func BenchmarkCategoricalRandSmall(b *testing.B) { benchmarkCategoricalRand(b, Small) } func BenchmarkCategoricalRandMedium(b *testing.B) { benchmarkCategoricalRand(b, Medium) } func BenchmarkCategoricalRandLarge(b *testing.B) { benchmarkCategoricalRand(b, Large) } func BenchmarkCategoricalRandHuge(b *testing.B) { benchmarkCategoricalRand(b, Huge) } func benchmarkCategoricalRand(b *testing.B, size int) { src := rand.NewSource(1) rng := rand.New(src) weights := make([]float64, size) for i := 0; i < size; i++ { weights[i] = rng.Float64() + 0.001 } dist := NewCategorical(weights, src) for i := 0; i < b.N; i++ { dist.Rand() } } golang-gonum-v1-gonum-0.14.0/stat/distuv/chi.go000066400000000000000000000062521450372207100212260ustar00rootroot00000000000000// Copyright ©2021 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) // Chi implements the χ distribution, a one parameter distribution // with support on the positive numbers. // // The density function is given by // // 1/(2^{k/2-1} * Γ(k/2)) * x^{k - 1} * e^{-x^2/2} // // For more information, see https://en.wikipedia.org/wiki/Chi_distribution. type Chi struct { // K is the shape parameter, corresponding to the degrees of freedom. Must // be greater than 0. K float64 Src rand.Source } // CDF computes the value of the cumulative density function at x. func (c Chi) CDF(x float64) float64 { return mathext.GammaIncReg(c.K/2, (x*x)/2) } // Entropy returns the differential entropy of the distribution. func (c Chi) Entropy() float64 { lg, _ := math.Lgamma(c.K / 2) return lg + 0.5*(c.K-math.Ln2-(c.K-1)*mathext.Digamma(c.K/2)) } // ExKurtosis returns the excess kurtosis of the distribution. func (c Chi) ExKurtosis() float64 { v := c.Variance() s := math.Sqrt(v) return 2 / v * (1 - c.Mean()*s*c.Skewness() - v) } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (c Chi) LogProb(x float64) float64 { if x < 0 { return math.Inf(-1) } lg, _ := math.Lgamma(c.K / 2) return (c.K-1)*math.Log(x) - (x*x)/2 - (c.K/2-1)*math.Ln2 - lg } // Mean returns the mean of the probability distribution. func (c Chi) Mean() float64 { lg1, _ := math.Lgamma((c.K + 1) / 2) lg, _ := math.Lgamma(c.K / 2) return math.Sqrt2 * math.Exp(lg1-lg) } // Median returns the median of the distribution. func (c Chi) Median() float64 { return c.Quantile(0.5) } // Mode returns the mode of the distribution. // // Mode returns NaN if K is less than one. func (c Chi) Mode() float64 { return math.Sqrt(c.K - 1) } // NumParameters returns the number of parameters in the distribution. func (c Chi) NumParameters() int { return 1 } // Prob computes the value of the probability density function at x. func (c Chi) Prob(x float64) float64 { return math.Exp(c.LogProb(x)) } // Rand returns a random sample drawn from the distribution. func (c Chi) Rand() float64 { return math.Sqrt(Gamma{c.K / 2, 0.5, c.Src}.Rand()) } // Quantile returns the inverse of the cumulative distribution function. func (c Chi) Quantile(p float64) float64 { if p < 0 || 1 < p { panic(badPercentile) } return math.Sqrt(2 * mathext.GammaIncRegInv(0.5*c.K, p)) } // Skewness returns the skewness of the distribution. func (c Chi) Skewness() float64 { v := c.Variance() s := math.Sqrt(v) return c.Mean() / (s * v) * (1 - 2*v) } // StdDev returns the standard deviation of the probability distribution. func (c Chi) StdDev() float64 { return math.Sqrt(c.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (c Chi) Survival(x float64) float64 { if x < 0 { return 1 } return mathext.GammaIncRegComp(0.5*c.K, 0.5*(x*x)) } // Variance returns the variance of the probability distribution. func (c Chi) Variance() float64 { m := c.Mean() return math.Max(0, c.K-m*m) } golang-gonum-v1-gonum-0.14.0/stat/distuv/chi_test.go000066400000000000000000000045211450372207100222620ustar00rootroot00000000000000// Copyright ©2021 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestChiProb(t *testing.T) { t.Parallel() for _, test := range []struct { x, k, want float64 }{ {10, 3, 1.538919725341288e-20}, {2.3, 3, 0.2997000593061405}, {0.8, 0.2, 0.1702707693447167}, } { pdf := Chi{test.k, nil}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Pdf mismatch, x = %v, K = %v. Got %v, want %v", test.x, test.k, pdf, test.want) } } } func TestChiCDF(t *testing.T) { t.Parallel() for _, test := range []struct { x, k, want float64 }{ // Values calculated with scipy.stats.chi.cdf {0, 1, 0}, {0.01, 5, 5.319040436531812e-12}, {0.05, 3, 3.3220267268523235e-05}, {0.5, 2, 0.1175030974154046}, {0.95, 3, 0.17517554009157732}, {0.99, 5, 0.035845177452671864}, {1, 1, 0.6826894921370859}, {1.5, 4, 0.3101135068635068}, {10, 10, 1}, {25, 15, 1}, } { cdf := Chi{test.k, nil}.CDF(test.x) if !scalar.EqualWithinAbsOrRel(cdf, test.want, 1e-10, 1e-10) { t.Errorf("CDF mismatch, x = %v, K = %v. Got %v, want %v", test.x, test.k, cdf, test.want) } } } func TestChi(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []Chi{ {3, src}, {1.5, src}, {0.9, src}, } { testChi(t, b, i) } } func testChi(t *testing.T, c Chi, i int) { const ( tol = 1e-2 n = 1e6 bins = 50 ) x := make([]float64, n) generateSamples(x, c) sort.Float64s(x) testRandLogProbContinuous(t, i, 0, x, c, tol, bins) checkMean(t, i, x, c, tol) checkMedian(t, i, x, c, tol) checkVarAndStd(t, i, x, c, tol) checkEntropy(t, i, x, c, tol) checkExKurtosis(t, i, x, c, 7e-2) checkProbContinuous(t, i, x, 0, math.Inf(1), c, 1e-5) checkQuantileCDFSurvival(t, i, x, c, 1e-2) expectedMode := math.Sqrt(c.K - 1) if !scalar.Same(c.Mode(), expectedMode) { t.Errorf("Mode is not equal to sqrt(k - 1). Got %v, want %v", c.Mode(), expectedMode) } if c.NumParameters() != 1 { t.Errorf("NumParameters is not 1. Got %v", c.NumParameters()) } survival := c.Survival(-0.00001) if survival != 1 { t.Errorf("Survival is not 1 for negative argument. Got %v", survival) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/chisquared.go000066400000000000000000000051561450372207100226150ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) // ChiSquared implements the χ² distribution, a one parameter distribution // with support on the positive numbers. // // The density function is given by // // 1/(2^{k/2} * Γ(k/2)) * x^{k/2 - 1} * e^{-x/2} // // It is a special case of the Gamma distribution, Γ(k/2, 1/2). // // For more information, see https://en.wikipedia.org/wiki/Chi-squared_distribution. type ChiSquared struct { // K is the shape parameter, corresponding to the degrees of freedom. Must // be greater than 0. K float64 Src rand.Source } // CDF computes the value of the cumulative density function at x. func (c ChiSquared) CDF(x float64) float64 { return mathext.GammaIncReg(c.K/2, x/2) } // ExKurtosis returns the excess kurtosis of the distribution. func (c ChiSquared) ExKurtosis() float64 { return 12 / c.K } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (c ChiSquared) LogProb(x float64) float64 { if x < 0 { return math.Inf(-1) } lg, _ := math.Lgamma(c.K / 2) return (c.K/2-1)*math.Log(x) - x/2 - (c.K/2)*math.Ln2 - lg } // Mean returns the mean of the probability distribution. func (c ChiSquared) Mean() float64 { return c.K } // Mode returns the mode of the distribution. func (c ChiSquared) Mode() float64 { return math.Max(c.K-2, 0) } // NumParameters returns the number of parameters in the distribution. func (c ChiSquared) NumParameters() int { return 1 } // Prob computes the value of the probability density function at x. func (c ChiSquared) Prob(x float64) float64 { return math.Exp(c.LogProb(x)) } // Rand returns a random sample drawn from the distribution. func (c ChiSquared) Rand() float64 { return Gamma{c.K / 2, 0.5, c.Src}.Rand() } // Quantile returns the inverse of the cumulative distribution function. func (c ChiSquared) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } return mathext.GammaIncRegInv(0.5*c.K, p) * 2 } // StdDev returns the standard deviation of the probability distribution. func (c ChiSquared) StdDev() float64 { return math.Sqrt(c.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (c ChiSquared) Survival(x float64) float64 { if x < 0 { return 1 } return mathext.GammaIncRegComp(0.5*c.K, 0.5*x) } // Variance returns the variance of the probability distribution. func (c ChiSquared) Variance() float64 { return 2 * c.K } golang-gonum-v1-gonum-0.14.0/stat/distuv/chisquared_test.go000066400000000000000000000045621450372207100236540ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestChiSquaredProb(t *testing.T) { t.Parallel() for _, test := range []struct { x, k, want float64 }{ {10, 3, 0.0085003666025203432}, {2.3, 3, 0.19157345407042367}, {0.8, 0.2, 0.080363259903912673}, } { pdf := ChiSquared{test.k, nil}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Pdf mismatch, x = %v, K = %v. Got %v, want %v", test.x, test.k, pdf, test.want) } } } func TestChiSquaredCDF(t *testing.T) { t.Parallel() for _, test := range []struct { x, k, want float64 }{ // Values calculated with scipy.stats.chi2.cdf {0, 1, 0}, {0.01, 5, 5.3002700426865167e-07}, {0.05, 3, 0.002929332764619924}, {0.5, 2, 0.22119921692859512}, {0.95, 3, 0.1866520918701263}, {0.99, 5, 0.036631697220869196}, {1, 1, 0.68268949213708596}, {1.5, 4, 0.17335853270322427}, {10, 10, 0.55950671493478743}, {25, 15, 0.95005656637357172}, } { cdf := ChiSquared{test.k, nil}.CDF(test.x) if !scalar.EqualWithinAbsOrRel(cdf, test.want, 1e-10, 1e-10) { t.Errorf("CDF mismatch, x = %v, K = %v. Got %v, want %v", test.x, test.k, cdf, test.want) } } } func TestChiSquared(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []ChiSquared{ {3, src}, {1.5, src}, {0.9, src}, } { testChiSquared(t, b, i) } } func testChiSquared(t *testing.T, c ChiSquared, i int) { const ( tol = 1e-2 n = 1e6 bins = 50 ) x := make([]float64, n) generateSamples(x, c) sort.Float64s(x) testRandLogProbContinuous(t, i, 0, x, c, tol, bins) checkMean(t, i, x, c, tol) checkVarAndStd(t, i, x, c, tol) checkExKurtosis(t, i, x, c, 7e-2) checkProbContinuous(t, i, x, 0, math.Inf(1), c, 1e-5) checkQuantileCDFSurvival(t, i, x, c, 1e-2) expectedMode := math.Max(c.K-2, 0) if c.Mode() != expectedMode { t.Errorf("Mode is not equal to max(k - 2, 0). Got %v, want %v", c.Mode(), expectedMode) } if c.NumParameters() != 1 { t.Errorf("NumParameters is not 1. Got %v", c.NumParameters()) } survival := c.Survival(-0.00001) if survival != 1 { t.Errorf("Survival is not 1 for negative argument. Got %v", survival) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/constants.go000066400000000000000000000025041450372207100224730ustar00rootroot00000000000000// 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 distuv const ( // oneOverRoot2Pi is the value of 1/(2Pi)^(1/2) // http://www.wolframalpha.com/input/?i=1%2F%282+*+pi%29%5E%281%2F2%29 oneOverRoot2Pi = 0.39894228040143267793994605993438186847585863116493465766592582967065792589930183850125233390730693643030255886263518268 //LogRoot2Pi is the value of log(sqrt(2*Pi)) logRoot2Pi = 0.91893853320467274178032973640561763986139747363778341281715154048276569592726039769474329863595419762200564662463433744 negLogRoot2Pi = -logRoot2Pi log2Pi = 1.8378770664093454835606594728112352797227949472755668 ln2 = 0.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641868754200148102057068573368552023 // Euler–Mascheroni constant. eulerGamma = 0.5772156649015328606065120900824024310421593359399235988057672348848677267776646709369470632917467495146314472498070824809605 // sqrt3 is the value of sqrt(3) // https://www.wolframalpha.com/input/?i=sqrt%283%29 sqrt3 = 1.7320508075688772935274463415058723669428052538103806280558069794519330169088000370811461867572485756756261414154067030299699450 ) const ( panicNameMismatch = "parameter name mismatch" ) golang-gonum-v1-gonum-0.14.0/stat/distuv/distribution_test.go000066400000000000000000000202671450372207100242430ustar00rootroot00000000000000// 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 distuv import ( "math" "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/integrate/quad" "gonum.org/v1/gonum/stat" ) type meaner interface { Mean() float64 } type quantiler interface { Quantile(float64) float64 } type medianer interface { quantiler Median() float64 } type varStder interface { StdDev() float64 Variance() float64 } type entropyer interface { LogProber Entropy() float64 } type exKurtosiser interface { ExKurtosis() float64 Mean() float64 } type skewnesser interface { StdDev() float64 Mean() float64 Skewness() float64 } type cumulanter interface { Quantiler CDF(x float64) float64 Survival(x float64) float64 } func generateSamples(x []float64, r Rander) { for i := range x { x[i] = r.Rand() } } type probLogprober interface { Prob(x float64) float64 LogProb(x float64) float64 } type cumulantProber interface { cumulanter probLogprober } func checkMean(t *testing.T, cas int, x []float64, m meaner, tol float64) { t.Helper() mean := stat.Mean(x, nil) if !scalar.EqualWithinAbsOrRel(mean, m.Mean(), tol, tol) { t.Errorf("Mean mismatch case %v: want: %v, got: %v", cas, mean, m.Mean()) } } func checkMedian(t *testing.T, cas int, x []float64, m medianer, tol float64) { t.Helper() median := stat.Quantile(0.5, stat.Empirical, x, nil) if !scalar.EqualWithinAbsOrRel(median, m.Median(), tol, tol) { t.Errorf("Median mismatch case %v: want: %v, got: %v", cas, median, m.Median()) } } func checkVarAndStd(t *testing.T, cas int, x []float64, v varStder, tol float64) { t.Helper() variance := stat.Variance(x, nil) if !scalar.EqualWithinAbsOrRel(variance, v.Variance(), tol, tol) { t.Errorf("Variance mismatch case %v: want: %v, got: %v", cas, variance, v.Variance()) } std := math.Sqrt(variance) if !scalar.EqualWithinAbsOrRel(std, v.StdDev(), tol, tol) { t.Errorf("StdDev mismatch case %v: want: %v, got: %v", cas, std, v.StdDev()) } } func checkEntropy(t *testing.T, cas int, x []float64, e entropyer, tol float64) { t.Helper() tmp := make([]float64, len(x)) for i, v := range x { tmp[i] = -e.LogProb(v) } entropy := stat.Mean(tmp, nil) if !scalar.EqualWithinAbsOrRel(entropy, e.Entropy(), tol, tol) { t.Errorf("Entropy mismatch case %v: want: %v, got: %v", cas, entropy, e.Entropy()) } } func checkExKurtosis(t *testing.T, cas int, x []float64, e exKurtosiser, tol float64) { t.Helper() mean := e.Mean() tmp := make([]float64, len(x)) for i, x := range x { tmp[i] = math.Pow(x-mean, 4) } variance := stat.Variance(x, nil) mu4 := stat.Mean(tmp, nil) kurtosis := mu4/(variance*variance) - 3 if !scalar.EqualWithinAbsOrRel(kurtosis, e.ExKurtosis(), tol, tol) { t.Errorf("ExKurtosis mismatch case %v: want: %v, got: %v", cas, kurtosis, e.ExKurtosis()) } } func checkSkewness(t *testing.T, cas int, x []float64, s skewnesser, tol float64) { t.Helper() mean := s.Mean() std := s.StdDev() tmp := make([]float64, len(x)) for i, v := range x { tmp[i] = math.Pow(v-mean, 3) } mu3 := stat.Mean(tmp, nil) skewness := mu3 / math.Pow(std, 3) if !scalar.EqualWithinAbsOrRel(skewness, s.Skewness(), tol, tol) { t.Errorf("Skewness mismatch case %v: want: %v, got: %v", cas, skewness, s.Skewness()) } } func checkQuantileCDFSurvival(t *testing.T, cas int, xs []float64, c cumulanter, tol float64) { t.Helper() // Quantile, CDF, and survival check. for _, p := range []float64{0.1, 0.25, 0.5, 0.75, 0.9} { x := c.Quantile(p) cdf := c.CDF(x) estCDF := stat.CDF(x, stat.Empirical, xs, nil) if !scalar.EqualWithinAbsOrRel(cdf, estCDF, tol, tol) { t.Errorf("CDF mismatch case %v: want: %v, got: %v", cas, estCDF, cdf) } if !scalar.EqualWithinAbsOrRel(cdf, p, tol, tol) { t.Errorf("Quantile/CDF mismatch case %v: want: %v, got: %v", cas, p, cdf) } if math.Abs(1-cdf-c.Survival(x)) > 1e-14 { t.Errorf("Survival/CDF mismatch case %v: want: %v, got: %v", cas, 1-cdf, c.Survival(x)) } } if !panics(func() { c.Quantile(-0.0001) }) { t.Errorf("Expected panic with negative argument to Quantile") } if !panics(func() { c.Quantile(1.0001) }) { t.Errorf("Expected panic with Quantile argument above 1") } } // checkProbContinuous checks that the PDF is consistent with LogPDF // and integrates to 1 from the lower to upper bound. func checkProbContinuous(t *testing.T, cas int, x []float64, lower float64, upper float64, p probLogprober, tol float64) { t.Helper() q := quad.Fixed(p.Prob, lower, upper, 1000000, nil, 0) if math.Abs(q-1) > tol { t.Errorf("Probability distribution doesn't integrate to 1. Case %v: Got %v", cas, q) } // Check that PDF and LogPDF are consistent. for _, v := range x { if math.Abs(math.Log(p.Prob(v))-p.LogProb(v)) > 1e-14 { t.Errorf("Prob and LogProb mismatch case %v at %v: want %v, got %v", cas, v, math.Log(v), p.LogProb(v)) break } } } // checkProbQuantContinuous checks that the Prob, Rand, and Quantile are all consistent. // checkProbContinuous only checks that Prob is a valid distribution (integrates // to 1 and greater than 0). However, this is also true if the PDF of a different // distribution is used. This checks that PDF is also consistent with the // CDF implementation and the random samples. func checkProbQuantContinuous(t *testing.T, cas int, xs []float64, c cumulantProber, tol float64) { t.Helper() ps := make([]float64, 101) floats.Span(ps, 0, 1) var xp, x float64 for i, p := range ps { x = c.Quantile(p) if p == 0 { xp = x if floats.Min(xs) < x { t.Errorf("Sample of x less than Quantile(0). Case %v.", cas) break } continue } if p == 1 { if floats.Max(xs) > x { t.Errorf("Sample of x greater than Quantile(1). Case %v.", cas) break } } // The integral of the PDF between xp and x should be the difference in // the quantiles. q := quad.Fixed(c.Prob, xp, x, 1000, nil, 0) if math.Abs(q-(p-ps[i-1])) > 1e-5 { t.Errorf("Integral of PDF doesn't match quantile. Case %v. Want %v, got %v.", cas, p-ps[i-1], q) break } pEst := stat.CDF(x, stat.Empirical, xs, nil) if math.Abs(pEst-p) > tol { t.Errorf("Empirical CDF doesn't match quantile. Case %v.", cas) } xp = x } } type moder interface { Mode() float64 } func checkMode(t *testing.T, cas int, xs []float64, m moder, dx float64, tol float64) { t.Helper() rXs := make([]float64, len(xs)) for j, x := range xs { rXs[j] = math.RoundToEven(x/dx) * dx } want, _ := stat.Mode(rXs, nil) got := m.Mode() if !scalar.EqualWithinAbs(want, got, tol) { t.Errorf("Mode mismatch case %d: want %g, got %v", cas, want, got) } } // checkProbDiscrete confirms that PDF and Rand are consistent for discrete distributions. func checkProbDiscrete(t *testing.T, cas int, xs []float64, p probLogprober, tol float64) { t.Helper() // Make a map of all of the unique samples. m := make(map[float64]int) for _, v := range xs { m[v]++ } for x, count := range m { prob := float64(count) / float64(len(xs)) if math.Abs(prob-p.Prob(x)) > tol { t.Errorf("PDF mismatch case %v at %v: want %v, got %v", cas, x, prob, p.Prob(x)) } if math.Abs(math.Log(p.Prob(x))-p.LogProb(x)) > 1e-14 { t.Errorf("Prob and LogProb mismatch case %v at %v: want %v, got %v", cas, x, math.Log(x), p.LogProb(x)) } } } // testRandLogProb tests that LogProb and Rand give consistent results. This // can be used when the distribution does not implement CDF. func testRandLogProbContinuous(t *testing.T, cas int, min float64, x []float64, f LogProber, tol float64, bins int) { t.Helper() for cdf := 1 / float64(bins); cdf <= 1-1/float64(bins); cdf += 1 / float64(bins) { // Get the estimated CDF from the samples pt := stat.Quantile(cdf, stat.Empirical, x, nil) prob := func(x float64) float64 { return math.Exp(f.LogProb(x)) } // Integrate the PDF to find the CDF estCDF := quad.Fixed(prob, min, pt, 10000, nil, 0) if !scalar.EqualWithinAbsOrRel(cdf, estCDF, tol, tol) { t.Errorf("Mismatch between integral of PDF and empirical CDF. Case %v. Want %v, got %v", cas, cdf, estCDF) } } } func panics(fun func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() fun() return } golang-gonum-v1-gonum-0.14.0/stat/distuv/doc.go000066400000000000000000000004401450372207100212210ustar00rootroot00000000000000// 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 distuv provides univariate random distribution types. package distuv // import "gonum.org/v1/gonum/stat/distuv" golang-gonum-v1-gonum-0.14.0/stat/distuv/exponential.go000066400000000000000000000166111450372207100230110ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/stat" ) // Exponential represents the exponential distribution (https://en.wikipedia.org/wiki/Exponential_distribution). type Exponential struct { Rate float64 Src rand.Source } // CDF computes the value of the cumulative density function at x. func (e Exponential) CDF(x float64) float64 { if x < 0 { return 0 } return -math.Expm1(-e.Rate * x) } // ConjugateUpdate updates the parameters of the distribution from the sufficient // statistics of a set of samples. The sufficient statistics, suffStat, have been // observed with nSamples observations. The prior values of the distribution are those // currently in the distribution, and have been observed with priorStrength samples. // // For the exponential distribution, the sufficient statistic is the inverse of // the mean of the samples. // The prior is having seen priorStrength[0] samples with inverse mean Exponential.Rate // As a result of this function, Exponential.Rate is updated based on the weighted // samples, and priorStrength is modified to include the new number of samples observed. // // This function panics if len(suffStat) != e.NumSuffStat() or // len(priorStrength) != e.NumSuffStat(). func (e *Exponential) ConjugateUpdate(suffStat []float64, nSamples float64, priorStrength []float64) { if len(suffStat) != e.NumSuffStat() { panic("exponential: incorrect suffStat length") } if len(priorStrength) != e.NumSuffStat() { panic("exponential: incorrect priorStrength length") } totalSamples := nSamples + priorStrength[0] totalSum := nSamples / suffStat[0] if !(priorStrength[0] == 0) { totalSum += priorStrength[0] / e.Rate } e.Rate = totalSamples / totalSum priorStrength[0] = totalSamples } // Entropy returns the entropy of the distribution. func (e Exponential) Entropy() float64 { return 1 - math.Log(e.Rate) } // ExKurtosis returns the excess kurtosis of the distribution. func (Exponential) ExKurtosis() float64 { return 6 } // Fit sets the parameters of the probability distribution from the // data samples x with relative weights w. // If weights is nil, then all the weights are 1. // If weights is not nil, then the len(weights) must equal len(samples). func (e *Exponential) Fit(samples, weights []float64) { suffStat := make([]float64, e.NumSuffStat()) nSamples := e.SuffStat(suffStat, samples, weights) e.ConjugateUpdate(suffStat, nSamples, make([]float64, e.NumSuffStat())) } // LogProb computes the natural logarithm of the value of the probability density function at x. func (e Exponential) LogProb(x float64) float64 { if x < 0 { return math.Inf(-1) } return math.Log(e.Rate) - e.Rate*x } // Mean returns the mean of the probability distribution. func (e Exponential) Mean() float64 { return 1 / e.Rate } // Median returns the median of the probability distribution. func (e Exponential) Median() float64 { return math.Ln2 / e.Rate } // Mode returns the mode of the probability distribution. func (Exponential) Mode() float64 { return 0 } // NumParameters returns the number of parameters in the distribution. func (Exponential) NumParameters() int { return 1 } // NumSuffStat returns the number of sufficient statistics for the distribution. func (Exponential) NumSuffStat() int { return 1 } // Prob computes the value of the probability density function at x. func (e Exponential) Prob(x float64) float64 { return math.Exp(e.LogProb(x)) } // Quantile returns the inverse of the cumulative probability distribution. func (e Exponential) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } return -math.Log(1-p) / e.Rate } // Rand returns a random sample drawn from the distribution. func (e Exponential) Rand() float64 { var rnd float64 if e.Src == nil { rnd = rand.ExpFloat64() } else { rnd = rand.New(e.Src).ExpFloat64() } return rnd / e.Rate } // Score returns the score function with respect to the parameters of the // distribution at the input location x. The score function is the derivative // of the log-likelihood at x with respect to the parameters // // (∂/∂θ) log(p(x;θ)) // // If deriv is non-nil, len(deriv) must equal the number of parameters otherwise // Score will panic, and the derivative is stored in-place into deriv. If deriv // is nil a new slice will be allocated and returned. // // The order is [∂LogProb / ∂Rate]. // // For more information, see https://en.wikipedia.org/wiki/Score_%28statistics%29. // // Special cases: // // Score(0) = [NaN] func (e Exponential) Score(deriv []float64, x float64) []float64 { if deriv == nil { deriv = make([]float64, e.NumParameters()) } if len(deriv) != e.NumParameters() { panic(badLength) } if x > 0 { deriv[0] = 1/e.Rate - x return deriv } if x < 0 { deriv[0] = 0 return deriv } deriv[0] = math.NaN() return deriv } // ScoreInput returns the score function with respect to the input of the // distribution at the input location specified by x. The score function is the // derivative of the log-likelihood // // (d/dx) log(p(x)) . // // Special cases: // // ScoreInput(0) = NaN func (e Exponential) ScoreInput(x float64) float64 { if x > 0 { return -e.Rate } if x < 0 { return 0 } return math.NaN() } // Skewness returns the skewness of the distribution. func (Exponential) Skewness() float64 { return 2 } // StdDev returns the standard deviation of the probability distribution. func (e Exponential) StdDev() float64 { return 1 / e.Rate } // SuffStat computes the sufficient statistics of set of samples to update // the distribution. The sufficient statistics are stored in place, and the // effective number of samples are returned. // // The exponential distribution has one sufficient statistic, the average rate // of the samples. // // If weights is nil, the weights are assumed to be 1, otherwise panics if // len(samples) != len(weights). Panics if len(suffStat) != NumSuffStat(). func (Exponential) SuffStat(suffStat, samples, weights []float64) (nSamples float64) { if len(weights) != 0 && len(samples) != len(weights) { panic(badLength) } if len(suffStat) != (Exponential{}).NumSuffStat() { panic(badSuffStat) } if len(weights) == 0 { nSamples = float64(len(samples)) } else { nSamples = floats.Sum(weights) } mean := stat.Mean(samples, weights) suffStat[0] = 1 / mean return nSamples } // Survival returns the survival function (complementary CDF) at x. func (e Exponential) Survival(x float64) float64 { if x < 0 { return 1 } return math.Exp(-e.Rate * x) } // setParameters modifies the parameters of the distribution. func (e *Exponential) setParameters(p []Parameter) { if len(p) != e.NumParameters() { panic("exponential: incorrect number of parameters to set") } if p[0].Name != "Rate" { panic("exponential: " + panicNameMismatch) } e.Rate = p[0].Value } // Variance returns the variance of the probability distribution. func (e Exponential) Variance() float64 { return 1 / (e.Rate * e.Rate) } // parameters returns the parameters of the distribution. func (e Exponential) parameters(p []Parameter) []Parameter { nParam := e.NumParameters() if p == nil { p = make([]Parameter, nParam) } else if len(p) != nParam { panic("exponential: improper parameter length") } p[0].Name = "Rate" p[0].Value = e.Rate return p } golang-gonum-v1-gonum-0.14.0/stat/distuv/exponential_test.go000066400000000000000000000072271450372207100240530ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" ) func TestExponentialProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: 1, cumProb: 0, logProb: 0, }, { loc: -1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 1 / (math.E), cumProb: 0.6321205588285576784044762298385391325541888689682321654921631983025385042551001966428527256540803563, logProb: -1, }, { loc: 20, prob: math.Exp(-20), cumProb: 0.999999997938846377561442172034059619844179023624192724400896307027755338370835976215440646720089072, logProb: -20, }, } testDistributionProbs(t, Exponential{Rate: 1}, "Exponential", pts) } func TestExponentialFitPrior(t *testing.T) { t.Parallel() testConjugateUpdate(t, func() ConjugateUpdater { return &Exponential{Rate: 13.7, Src: rand.NewSource(1)} }) } func TestExponential(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, dist := range []Exponential{ {Rate: 3, Src: src}, {Rate: 1.5, Src: src}, {Rate: 0.9, Src: src}, } { testExponential(t, dist, i) } } func testExponential(t *testing.T, dist Exponential, i int) { const ( tol = 1e-2 n = 3e6 bins = 50 ) x := make([]float64, n) generateSamples(x, dist) sort.Float64s(x) checkMean(t, i, x, dist, tol) checkVarAndStd(t, i, x, dist, tol) checkEntropy(t, i, x, dist, tol) checkExKurtosis(t, i, x, dist, tol) checkSkewness(t, i, x, dist, tol) checkMedian(t, i, x, dist, tol) checkQuantileCDFSurvival(t, i, x, dist, tol) checkProbContinuous(t, i, x, 0, math.Inf(1), dist, 1e-10) checkProbQuantContinuous(t, i, x, dist, tol) if dist.Mode() != 0 { t.Errorf("Mode is not 0. Got %v", dist.Mode()) } if dist.NumParameters() != 1 { t.Errorf("NumParameters is not 1. Got %v", dist.NumParameters()) } if dist.NumSuffStat() != 1 { t.Errorf("NumSuffStat is not 1. Got %v", dist.NumSuffStat()) } scoreInput := dist.ScoreInput(-0.0001) if scoreInput != 0 { t.Errorf("ScoreInput is not 0 for a negative argument. Got %v", scoreInput) } scoreInput = dist.ScoreInput(0) if !math.IsNaN(scoreInput) { t.Errorf("ScoreInput is not NaN at 0. Got %v", scoreInput) } scoreInput = dist.ScoreInput(1) if scoreInput != -dist.Rate { t.Errorf("ScoreInput mismatch for a positive argument. Got %v, want %g", scoreInput, dist.Rate) } deriv := make([]float64, 1) dist.Score(deriv, -0.0001) if deriv[0] != 0 { t.Errorf("Score is not 0 for a negative argument. Got %v", deriv[0]) } dist.Score(deriv, 0) if !math.IsNaN(deriv[0]) { t.Errorf("Score is not NaN at 0. Got %v", deriv[0]) } if !panics(func() { dist.Quantile(-0.0001) }) { t.Errorf("Expected panic with negative argument to Quantile") } if !panics(func() { dist.Quantile(1.0001) }) { t.Errorf("Expected panic with argument to Quantile above 1") } } func TestExponentialScore(t *testing.T) { t.Parallel() for _, test := range []*Exponential{ { Rate: 1, }, { Rate: 0.35, }, { Rate: 4.6, }, } { testDerivParam(t, test) } } func TestExponentialFitPanic(t *testing.T) { t.Parallel() e := Exponential{Rate: 2} defer func() { r := recover() if r != nil { t.Errorf("unexpected panic for Fit call: %v", r) } }() e.Fit(make([]float64, 10), nil) } func TestExponentialCDFSmallArgument(t *testing.T) { t.Parallel() e := Exponential{Rate: 1} x := 1e-17 p := e.CDF(x) if math.Abs(p-x) > 1e-20 { t.Errorf("Wrong CDF value for small argument. Got: %v, want: %g", p, x) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/f.go000066400000000000000000000072371450372207100207140ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) // F implements the F-distribution, a two-parameter continuous distribution // with support over the positive real numbers. // // The F-distribution has density function // // sqrt(((d1*x)^d1) * d2^d2 / ((d1*x+d2)^(d1+d2))) / (x * B(d1/2,d2/2)) // // where B is the beta function. // // For more information, see https://en.wikipedia.org/wiki/F-distribution type F struct { D1 float64 // Degrees of freedom for the numerator D2 float64 // Degrees of freedom for the denominator Src rand.Source } // CDF computes the value of the cumulative density function at x. func (f F) CDF(x float64) float64 { return mathext.RegIncBeta(f.D1/2, f.D2/2, f.D1*x/(f.D1*x+f.D2)) } // ExKurtosis returns the excess kurtosis of the distribution. // // ExKurtosis returns NaN if the D2 parameter is less or equal to 8. func (f F) ExKurtosis() float64 { if f.D2 <= 8 { return math.NaN() } return (12 / (f.D2 - 6)) * ((5*f.D2-22)/(f.D2-8) + ((f.D2-4)/f.D1)*((f.D2-2)/(f.D2-8))*((f.D2-2)/(f.D1+f.D2-2))) } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (f F) LogProb(x float64) float64 { return 0.5*(f.D1*math.Log(f.D1*x)+f.D2*math.Log(f.D2)-(f.D1+f.D2)*math.Log(f.D1*x+f.D2)) - math.Log(x) - mathext.Lbeta(f.D1/2, f.D2/2) } // Mean returns the mean of the probability distribution. // // Mean returns NaN if the D2 parameter is less than or equal to 2. func (f F) Mean() float64 { if f.D2 <= 2 { return math.NaN() } return f.D2 / (f.D2 - 2) } // Mode returns the mode of the distribution. // // Mode returns NaN if the D1 parameter is less than or equal to 2. func (f F) Mode() float64 { if f.D1 <= 2 { return math.NaN() } return ((f.D1 - 2) / f.D1) * (f.D2 / (f.D2 + 2)) } // NumParameters returns the number of parameters in the distribution. func (f F) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (f F) Prob(x float64) float64 { return math.Exp(f.LogProb(x)) } // Quantile returns the inverse of the cumulative distribution function. func (f F) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } y := mathext.InvRegIncBeta(0.5*f.D1, 0.5*f.D2, p) return f.D2 * y / (f.D1 * (1 - y)) } // Rand returns a random sample drawn from the distribution. func (f F) Rand() float64 { u1 := ChiSquared{f.D1, f.Src}.Rand() u2 := ChiSquared{f.D2, f.Src}.Rand() return (u1 / f.D1) / (u2 / f.D2) } // Skewness returns the skewness of the distribution. // // Skewness returns NaN if the D2 parameter is less than or equal to 6. func (f F) Skewness() float64 { if f.D2 <= 6 { return math.NaN() } num := (2*f.D1 + f.D2 - 2) * math.Sqrt(8*(f.D2-4)) den := (f.D2 - 6) * math.Sqrt(f.D1*(f.D1+f.D2-2)) return num / den } // StdDev returns the standard deviation of the probability distribution. // // StdDev returns NaN if the D2 parameter is less than or equal to 4. func (f F) StdDev() float64 { if f.D2 <= 4 { return math.NaN() } return math.Sqrt(f.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (f F) Survival(x float64) float64 { return 1 - f.CDF(x) } // Variance returns the variance of the probability distribution. // // Variance returns NaN if the D2 parameter is less than or equal to 4. func (f F) Variance() float64 { if f.D2 <= 4 { return math.NaN() } num := 2 * f.D2 * f.D2 * (f.D1 + f.D2 - 2) den := f.D1 * (f.D2 - 2) * (f.D2 - 2) * (f.D2 - 4) return num / den } golang-gonum-v1-gonum-0.14.0/stat/distuv/f_test.go000066400000000000000000000077041450372207100217520ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestFProb(t *testing.T) { t.Parallel() for _, test := range []struct { x, d1, d2, want float64 }{ // Values calculated with scipy.stats.f {0.0001, 4, 6, 0.00053315559110558126}, {0.1, 1, 1, 0.91507658371794609}, {0.5, 11, 7, 0.66644660411410883}, {0.9, 20, 15, 0.88293424959522437}, {1, 1, 1, 0.15915494309189535}, {2, 15, 12, 0.16611971273429088}, {5, 4, 8, 0.013599775603702537}, {10, 12, 9, 0.00032922887567957289}, {100, 7, 7, 6.08037637806889e-08}, {1000, 2, 1, 1.1171959870312232e-05}, } { pdf := F{test.d1, test.d2, nil}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Prob mismatch, x = %v, d1 = %v, d2 = %v. Got %v, want %v", test.x, test.d1, test.d2, pdf, test.want) } } } func TestFCDF(t *testing.T) { t.Parallel() for _, test := range []struct { x, d1, d2, want float64 }{ // Values calculated with scipy.stats.f {0.0001, 4, 6, 2.6660741629519019e-08}, {0.1, 1, 1, 0.19498222904213672}, {0.5, 11, 7, 0.14625028471336987}, {0.9, 20, 15, 0.40567939897287852}, {1, 1, 1, 0.50000000000000011}, {2, 15, 12, 0.8839384428956264}, {5, 4, 8, 0.97429642410900219}, {10, 12, 9, 0.99915733385467187}, {100, 7, 7, 0.99999823560259171}, {1000, 2, 1, 0.97764490829950534}, } { cdf := F{test.d1, test.d2, nil}.CDF(test.x) if !scalar.EqualWithinAbsOrRel(cdf, test.want, 1e-10, 1e-10) { t.Errorf("CDF mismatch, x = %v, d1 = %v, d2 = %v. Got %v, want %v", test.x, test.d1, test.d2, cdf, test.want) } } } func TestF(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, f := range []F{ {13, 16, src}, {42, 31, src}, {77, 92, src}, } { testF(t, f, i) } } func testF(t *testing.T, f F, i int) { const ( tol = 1e-2 n = 1e6 bins = 50 ) x := make([]float64, n) generateSamples(x, f) sort.Float64s(x) testRandLogProbContinuous(t, i, 0, x, f, tol, bins) checkProbContinuous(t, i, x, 0, math.Inf(1), f, 1e-4) checkMean(t, i, x, f, tol) checkVarAndStd(t, i, x, f, tol) checkExKurtosis(t, i, x, f, 1e-1) checkSkewness(t, i, x, f, 5e-2) checkQuantileCDFSurvival(t, i, x, f, 5e-3) checkMode(t, i, x, f, 2e-2, 3e-2) if f.NumParameters() != 2 { t.Errorf("Wrong number of parameters. Got %v, want 2", f.NumParameters()) } } func TestFUndefined(t *testing.T) { t.Parallel() for _, d1 := range []float64{1, 100} { for _, d2 := range []float64{4, 8} { f := F{d1, d2, nil} exKurt := f.ExKurtosis() if !math.IsNaN(exKurt) { t.Errorf("Expected NaN excess kurtosis for D1 = %g and D2 = %g, got %v", d1, d2, exKurt) } } } for _, d1 := range []float64{1, 100} { for _, d2 := range []float64{1, 2} { f := F{d1, d2, nil} mean := f.Mean() if !math.IsNaN(mean) { t.Errorf("Expected NaN mean for D1 = %g and D2 = %g, got %v", d1, d2, mean) } } } for _, d1 := range []float64{1, 2} { for _, d2 := range []float64{1, 100} { f := F{d1, d2, nil} mode := f.Mode() if !math.IsNaN(mode) { t.Errorf("Expected NaN mode for D1 = %g and D2 = %g, got %v", d1, d2, mode) } } } for _, d1 := range []float64{1, 100} { for _, d2 := range []float64{3, 6} { f := F{d1, d2, nil} skewness := f.Skewness() if !math.IsNaN(skewness) { t.Errorf("Expected NaN skewness for D1 = %g and D2 = %g, got %v", d1, d2, skewness) } } } for _, d1 := range []float64{1, 100} { for _, d2 := range []float64{2, 4} { f := F{d1, d2, nil} variance := f.Variance() if !math.IsNaN(variance) { t.Errorf("Expected NaN variance for D1 = %g and D2 = %g, got %v", d1, d2, variance) } stdDev := f.StdDev() if !math.IsNaN(stdDev) { t.Errorf("Expected NaN standard deviation for D1 = %g and D2 = %g, got %v", d1, d2, variance) } } } } golang-gonum-v1-gonum-0.14.0/stat/distuv/gamma.go000066400000000000000000000115451450372207100215460ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) // Gamma implements the Gamma distribution, a two-parameter continuous distribution // with support over the positive real numbers. // // The gamma distribution has density function // // β^α / Γ(α) x^(α-1)e^(-βx) // // For more information, see https://en.wikipedia.org/wiki/Gamma_distribution type Gamma struct { // Alpha is the shape parameter of the distribution. Alpha must be greater // than 0. If Alpha == 1, this is equivalent to an exponential distribution. Alpha float64 // Beta is the rate parameter of the distribution. Beta must be greater than 0. // If Beta == 2, this is equivalent to a Chi-Squared distribution. Beta float64 Src rand.Source } // CDF computes the value of the cumulative distribution function at x. func (g Gamma) CDF(x float64) float64 { if x < 0 { return 0 } return mathext.GammaIncReg(g.Alpha, g.Beta*x) } // ExKurtosis returns the excess kurtosis of the distribution. func (g Gamma) ExKurtosis() float64 { return 6 / g.Alpha } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (g Gamma) LogProb(x float64) float64 { if x <= 0 { return math.Inf(-1) } a := g.Alpha b := g.Beta lg, _ := math.Lgamma(a) return a*math.Log(b) - lg + (a-1)*math.Log(x) - b*x } // Mean returns the mean of the probability distribution. func (g Gamma) Mean() float64 { return g.Alpha / g.Beta } // Mode returns the mode of the normal distribution. // // The mode is NaN in the special case where the Alpha (shape) parameter // is less than 1. func (g Gamma) Mode() float64 { if g.Alpha < 1 { return math.NaN() } return (g.Alpha - 1) / g.Beta } // NumParameters returns the number of parameters in the distribution. func (Gamma) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (g Gamma) Prob(x float64) float64 { return math.Exp(g.LogProb(x)) } // Quantile returns the inverse of the cumulative distribution function. func (g Gamma) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } return mathext.GammaIncRegInv(g.Alpha, p) / g.Beta } // Rand returns a random sample drawn from the distribution. // // Rand panics if either alpha or beta is <= 0. func (g Gamma) Rand() float64 { const ( // The 0.2 threshold is from https://www4.stat.ncsu.edu/~rmartin/Codes/rgamss.R // described in detail in https://arxiv.org/abs/1302.1884. smallAlphaThresh = 0.2 ) if g.Beta <= 0 { panic("gamma: beta <= 0") } unifrnd := rand.Float64 exprnd := rand.ExpFloat64 normrnd := rand.NormFloat64 if g.Src != nil { rnd := rand.New(g.Src) unifrnd = rnd.Float64 exprnd = rnd.ExpFloat64 normrnd = rnd.NormFloat64 } a := g.Alpha b := g.Beta switch { case a <= 0: panic("gamma: alpha <= 0") case a == 1: // Generate from exponential return exprnd() / b case a < smallAlphaThresh: // Generate using // Liu, Chuanhai, Martin, Ryan and Syring, Nick. "Simulating from a // gamma distribution with small shape parameter" // https://arxiv.org/abs/1302.1884 // use this reference: http://link.springer.com/article/10.1007/s00180-016-0692-0 // Algorithm adjusted to work in log space as much as possible. lambda := 1/a - 1 lr := -math.Log1p(1 / lambda / math.E) for { e := exprnd() var z float64 if e >= -lr { z = e + lr } else { z = -exprnd() / lambda } eza := math.Exp(-z / a) lh := -z - eza var lEta float64 if z >= 0 { lEta = -z } else { lEta = -1 + lambda*z } if lh-lEta > -exprnd() { return eza / b } } case a >= smallAlphaThresh: // Generate using: // Marsaglia, George, and Wai Wan Tsang. "A simple method for generating // gamma variables." ACM Transactions on Mathematical Software (TOMS) // 26.3 (2000): 363-372. d := a - 1.0/3 m := 1.0 if a < 1 { d += 1.0 m = math.Pow(unifrnd(), 1/a) } c := 1 / (3 * math.Sqrt(d)) for { x := normrnd() v := 1 + x*c if v <= 0.0 { continue } v = v * v * v u := unifrnd() if u < 1.0-0.0331*(x*x)*(x*x) { return m * d * v / b } if math.Log(u) < 0.5*x*x+d*(1-v+math.Log(v)) { return m * d * v / b } } } panic("unreachable") } // Survival returns the survival function (complementary CDF) at x. func (g Gamma) Survival(x float64) float64 { if x < 0 { return 1 } return mathext.GammaIncRegComp(g.Alpha, g.Beta*x) } // StdDev returns the standard deviation of the probability distribution. func (g Gamma) StdDev() float64 { return math.Sqrt(g.Alpha) / g.Beta } // Variance returns the variance of the probability distribution. func (g Gamma) Variance() float64 { return g.Alpha / g.Beta / g.Beta } golang-gonum-v1-gonum-0.14.0/stat/distuv/gamma_test.go000066400000000000000000000064451450372207100226100ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "fmt" "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestGamma(t *testing.T) { t.Parallel() // Values a comparison with scipy for _, test := range []struct { x, alpha, want float64 }{ {0.9, 0.1, 0.046986817861555757}, {0.9, 0.01, 0.0045384353289090401}, {0.45, 0.01, 0.014137035997241795}, } { pdf := Gamma{Alpha: test.alpha, Beta: 1}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Pdf mismatch. Got %v, want %v", pdf, test.want) } } src := rand.New(rand.NewSource(1)) for i, g := range []Gamma{ {Alpha: 0.1, Beta: 0.8, Src: src}, {Alpha: 0.3, Beta: 0.8, Src: src}, {Alpha: 0.5, Beta: 0.8, Src: src}, {Alpha: 0.9, Beta: 6, Src: src}, {Alpha: 0.9, Beta: 500, Src: src}, {Alpha: 1, Beta: 1, Src: src}, {Alpha: 1.6, Beta: 0.4, Src: src}, {Alpha: 2.6, Beta: 1.5, Src: src}, {Alpha: 5.6, Beta: 0.5, Src: src}, {Alpha: 30, Beta: 1.7, Src: src}, {Alpha: 30.2, Beta: 1.7, Src: src}, } { testGamma(t, g, i) } } func testGamma(t *testing.T, f Gamma, i int) { // TODO(btracey): Replace this when Gamma implements FullDist. const ( tol = 1e-2 n = 1e5 bins = 50 ) x := make([]float64, n) generateSamples(x, f) sort.Float64s(x) var quadTol float64 if f.Alpha < 0.3 { // Gamma PDF has a singularity at 0 for alpha < 1, // which gets sharper as alpha -> 0. quadTol = 0.2 } else { quadTol = tol } testRandLogProbContinuous(t, i, 0, x, f, quadTol, bins) checkMean(t, i, x, f, tol) checkVarAndStd(t, i, x, f, 2e-2) checkExKurtosis(t, i, x, f, 2e-1) switch { case f.Alpha < 0.3: quadTol = 0.1 case f.Alpha < 1: quadTol = 1e-3 default: quadTol = 1e-10 } checkProbContinuous(t, i, x, 0, math.Inf(1), f, quadTol) checkQuantileCDFSurvival(t, i, x, f, 5e-2) if f.Alpha < 1 { if !math.IsNaN(f.Mode()) { t.Errorf("Expected NaN mode for alpha < 1, got %v", f.Mode()) } } else { checkMode(t, i, x, f, 2e-1, 1) } cdfNegX := f.CDF(-0.0001) if cdfNegX != 0 { t.Errorf("Expected zero CDF for negative argument, got %v", cdfNegX) } survNegX := f.Survival(-0.0001) if survNegX != 1 { t.Errorf("Expected survival function of 1 for negative argument, got %v", survNegX) } if f.NumParameters() != 2 { t.Errorf("Mismatch in NumParameters: got %v, want 2", f.NumParameters()) } lPdf := f.LogProb(-0.0001) if !math.IsInf(lPdf, -1) { t.Errorf("Expected log(CDF) to be -Infinity for negative argument, got %v", lPdf) } } func TestGammaPanics(t *testing.T) { t.Parallel() g := Gamma{1, 0, nil} if !panics(func() { g.Rand() }) { t.Errorf("Expected Rand panic for Beta <= 0") } g = Gamma{0, 1, nil} if !panics(func() { g.Rand() }) { t.Errorf("Expected Rand panic for Alpha <= 0") } } func BenchmarkGammaRand(b *testing.B) { src := rand.New(rand.NewSource(1)) for i, g := range []Gamma{ {Alpha: 0.1, Beta: 0.8, Src: src}, {Alpha: 0.5, Beta: 0.8, Src: src}, {Alpha: 1, Beta: 1, Src: src}, {Alpha: 1.6, Beta: 0.4, Src: src}, {Alpha: 30, Beta: 1.7, Src: src}, } { b.Run(fmt.Sprintf("case %d", i), func(b *testing.B) { for i := 0; i < b.N; i++ { g.Rand() } }) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/general.go000066400000000000000000000014411450372207100220730ustar00rootroot00000000000000// 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 distuv // Parameter represents a parameter of a probability distribution type Parameter struct { Name string Value float64 } const ( badPercentile = "distuv: percentile out of bounds" badLength = "distuv: slice length mismatch" badSuffStat = "distuv: wrong suffStat length" errNoSamples = "distuv: must have at least one sample" ) const ( expNegOneHalf = 0.6065306597126334236037995349911804534419 // https://oeis.org/A092605 eulerMascheroni = 0.5772156649015328606065120900824024310421 // https://oeis.org/A001620 apery = 1.2020569031595942853997381615114499907649 // https://oeis.org/A002117 ) golang-gonum-v1-gonum-0.14.0/stat/distuv/general_test.go000066400000000000000000000206211450372207100231330ustar00rootroot00000000000000// 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 distuv import ( "fmt" "math" "testing" "gonum.org/v1/gonum/diff/fd" "gonum.org/v1/gonum/floats" ) type univariateProbPoint struct { loc float64 logProb float64 cumProb float64 prob float64 } type UniProbDist interface { Prob(float64) float64 CDF(float64) float64 LogProb(float64) float64 Quantile(float64) float64 Survival(float64) float64 } func absEq(a, b float64) bool { return absEqTol(a, b, 1e-14) } func absEqTol(a, b, tol float64) bool { if math.IsNaN(a) || math.IsNaN(b) { // NaN is not equal to anything. return false } // This is expressed as the inverse to catch the // case a = Inf and b = Inf of the same sign. return !(math.Abs(a-b) > tol) } // TODO: Implement a better test for Quantile func testDistributionProbs(t *testing.T, dist UniProbDist, name string, pts []univariateProbPoint) { for _, pt := range pts { logProb := dist.LogProb(pt.loc) if !absEq(logProb, pt.logProb) { t.Errorf("Log probability doesnt match for "+name+" at %v. Expected %v. Found %v", pt.loc, pt.logProb, logProb) } prob := dist.Prob(pt.loc) if !absEq(prob, pt.prob) { t.Errorf("Probability doesn't match for "+name+" at %v. Expected %v. Found %v", pt.loc, pt.prob, prob) } cumProb := dist.CDF(pt.loc) if !absEq(cumProb, pt.cumProb) { t.Errorf("Cumulative Probability doesn't match for "+name+". Expected %v. Found %v", pt.cumProb, cumProb) } if !absEq(dist.Survival(pt.loc), 1-pt.cumProb) { t.Errorf("Survival doesn't match for %v. Expected %v, Found %v", name, 1-pt.cumProb, dist.Survival(pt.loc)) } if pt.prob != 0 { if math.Abs(dist.Quantile(pt.cumProb)-pt.loc) > 1e-4 { fmt.Println("true =", pt.loc) fmt.Println("calculated=", dist.Quantile(pt.cumProb)) t.Errorf("Quantile doesn't match for "+name+", loc = %v", pt.loc) } } } } type ConjugateUpdater interface { NumParameters() int parameters([]Parameter) []Parameter NumSuffStat() int SuffStat([]float64, []float64, []float64) float64 ConjugateUpdate([]float64, float64, []float64) Rand() float64 } func testConjugateUpdate(t *testing.T, newFittable func() ConjugateUpdater) { for i, test := range []struct { samps []float64 weights []float64 }{ { samps: randn(newFittable(), 10), weights: nil, }, { samps: randn(newFittable(), 10), weights: ones(10), }, { samps: randn(newFittable(), 10), weights: randn(&Exponential{Rate: 1}, 10), }, } { // ensure that conjugate produces the same result both incrementally and all at once incDist := newFittable() stats := make([]float64, incDist.NumSuffStat()) prior := make([]float64, incDist.NumParameters()) for j := range test.samps { var incWeights, allWeights []float64 if test.weights != nil { incWeights = test.weights[j : j+1] allWeights = test.weights[0 : j+1] } nsInc := incDist.SuffStat(stats, test.samps[j:j+1], incWeights) incDist.ConjugateUpdate(stats, nsInc, prior) allDist := newFittable() nsAll := allDist.SuffStat(stats, test.samps[0:j+1], allWeights) allDist.ConjugateUpdate(stats, nsAll, make([]float64, allDist.NumParameters())) if !parametersEqual(incDist.parameters(nil), allDist.parameters(nil), 1e-12) { t.Errorf("prior doesn't match after incremental update for (%d, %d). Incremental is %v, all at once is %v", i, j, incDist, allDist) } if test.weights == nil { onesDist := newFittable() nsOnes := onesDist.SuffStat(stats, test.samps[0:j+1], ones(j+1)) onesDist.ConjugateUpdate(stats, nsOnes, make([]float64, onesDist.NumParameters())) if !parametersEqual(onesDist.parameters(nil), incDist.parameters(nil), 1e-14) { t.Errorf("nil and uniform weighted prior doesn't match for incremental update for (%d, %d). Uniform weighted is %v, nil is %v", i, j, onesDist, incDist) } if !parametersEqual(onesDist.parameters(nil), allDist.parameters(nil), 1e-14) { t.Errorf("nil and uniform weighted prior doesn't match for all at once update for (%d, %d). Uniform weighted is %v, nil is %v", i, j, onesDist, incDist) } } } } testSuffStatPanics(t, newFittable) testConjugateUpdatePanics(t, newFittable) } func testSuffStatPanics(t *testing.T, newFittable func() ConjugateUpdater) { dist := newFittable() sample := randn(dist, 10) if !panics(func() { dist.SuffStat(make([]float64, dist.NumSuffStat()), sample, make([]float64, len(sample)+1)) }) { t.Errorf("Expected panic for mismatch between samples and weights lengths") } if !panics(func() { dist.SuffStat(make([]float64, dist.NumSuffStat()+1), sample, nil) }) { t.Errorf("Expected panic for wrong sufficient statistic length") } } func testConjugateUpdatePanics(t *testing.T, newFittable func() ConjugateUpdater) { dist := newFittable() if !panics(func() { dist.ConjugateUpdate(make([]float64, dist.NumSuffStat()+1), 100, make([]float64, dist.NumParameters())) }) { t.Errorf("Expected panic for wrong sufficient statistic length") } if !panics(func() { dist.ConjugateUpdate(make([]float64, dist.NumSuffStat()), 100, make([]float64, dist.NumParameters()+1)) }) { t.Errorf("Expected panic for wrong prior strength length") } } // randn generates a specified number of random samples func randn(dist Rander, n int) []float64 { x := make([]float64, n) for i := range x { x[i] = dist.Rand() } return x } func ones(n int) []float64 { x := make([]float64, n) for i := range x { x[i] = 1 } return x } func parametersEqual(p1, p2 []Parameter, tol float64) bool { for i, p := range p1 { if p.Name != p2[i].Name { return false } if math.Abs(p.Value-p2[i].Value) > tol { return false } } return true } type derivParamTester interface { LogProb(x float64) float64 Score(deriv []float64, x float64) []float64 ScoreInput(x float64) float64 Quantile(p float64) float64 NumParameters() int parameters([]Parameter) []Parameter setParameters([]Parameter) } func testDerivParam(t *testing.T, d derivParamTester) { // Tests that the derivative matches for a number of different quantiles // along the distribution. nTest := 10 quantiles := make([]float64, nTest) floats.Span(quantiles, 0.1, 0.9) scoreInPlace := make([]float64, d.NumParameters()) fdDerivParam := make([]float64, d.NumParameters()) if !panics(func() { d.Score(make([]float64, d.NumParameters()+1), 0) }) { t.Errorf("Expected panic for wrong derivative slice length") } if !panics(func() { d.parameters(make([]Parameter, d.NumParameters()+1)) }) { t.Errorf("Expected panic for wrong parameter slice length") } initParams := d.parameters(nil) tooLongParams := make([]Parameter, len(initParams)+1) copy(tooLongParams, initParams) if !panics(func() { d.setParameters(tooLongParams) }) { t.Errorf("Expected panic for wrong parameter slice length") } badNameParams := make([]Parameter, len(initParams)) copy(badNameParams, initParams) const badName = "__badName__" for i := 0; i < len(initParams); i++ { badNameParams[i].Name = badName if !panics(func() { d.setParameters(badNameParams) }) { t.Errorf("Expected panic for wrong %d-th parameter name", i) } badNameParams[i].Name = initParams[i].Name } init := make([]float64, d.NumParameters()) for i, v := range initParams { init[i] = v.Value } for _, v := range quantiles { d.setParameters(initParams) x := d.Quantile(v) score := d.Score(scoreInPlace, x) if &score[0] != &scoreInPlace[0] { t.Errorf("Returned a different derivative slice than passed in. Got %v, want %v", score, scoreInPlace) } logProbParams := func(p []float64) float64 { params := d.parameters(nil) for i, v := range p { params[i].Value = v } d.setParameters(params) return d.LogProb(x) } fd.Gradient(fdDerivParam, logProbParams, init, nil) if !floats.EqualApprox(scoreInPlace, fdDerivParam, 1e-6) { t.Errorf("Score mismatch at x = %g. Want %v, got %v", x, fdDerivParam, scoreInPlace) } d.setParameters(initParams) score2 := d.Score(nil, x) if !floats.EqualApprox(score2, scoreInPlace, 1e-14) { t.Errorf("Score mismatch when input nil Want %v, got %v", score2, scoreInPlace) } logProbInput := func(x2 float64) float64 { return d.LogProb(x2) } scoreInput := d.ScoreInput(x) fdDerivInput := fd.Derivative(logProbInput, x, nil) if !absEqTol(scoreInput, fdDerivInput, 1e-6) { t.Errorf("ScoreInput mismatch at x = %g. Want %v, got %v", x, fdDerivInput, scoreInput) } } } golang-gonum-v1-gonum-0.14.0/stat/distuv/gumbel.go000066400000000000000000000063001450372207100217300ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" ) // GumbelRight implements the right-skewed Gumbel distribution, a two-parameter // continuous distribution with support over the real numbers. The right-skewed // Gumbel distribution is also sometimes known as the Extreme Value distribution. // // The right-skewed Gumbel distribution has density function // // 1/beta * exp(-(z + exp(-z))) // z = (x - mu)/beta // // Beta must be greater than 0. // // For more information, see https://en.wikipedia.org/wiki/Gumbel_distribution. type GumbelRight struct { Mu float64 Beta float64 Src rand.Source } func (g GumbelRight) z(x float64) float64 { return (x - g.Mu) / g.Beta } // CDF computes the value of the cumulative density function at x. func (g GumbelRight) CDF(x float64) float64 { z := g.z(x) return math.Exp(-math.Exp(-z)) } // Entropy returns the differential entropy of the distribution. func (g GumbelRight) Entropy() float64 { return math.Log(g.Beta) + eulerMascheroni + 1 } // ExKurtosis returns the excess kurtosis of the distribution. func (g GumbelRight) ExKurtosis() float64 { return 12.0 / 5 } // LogProb computes the natural logarithm of the value of the probability density function at x. func (g GumbelRight) LogProb(x float64) float64 { z := g.z(x) return -math.Log(g.Beta) - z - math.Exp(-z) } // Mean returns the mean of the probability distribution. func (g GumbelRight) Mean() float64 { return g.Mu + g.Beta*eulerMascheroni } // Median returns the median of the Gumbel distribution. func (g GumbelRight) Median() float64 { return g.Mu - g.Beta*math.Log(math.Ln2) } // Mode returns the mode of the normal distribution. func (g GumbelRight) Mode() float64 { return g.Mu } // NumParameters returns the number of parameters in the distribution. func (GumbelRight) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (g GumbelRight) Prob(x float64) float64 { return math.Exp(g.LogProb(x)) } // Quantile returns the inverse of the cumulative probability distribution. func (g GumbelRight) Quantile(p float64) float64 { if p < 0 || 1 < p { panic(badPercentile) } return g.Mu - g.Beta*math.Log(-math.Log(p)) } // Rand returns a random sample drawn from the distribution. func (g GumbelRight) Rand() float64 { var rnd float64 if g.Src == nil { rnd = rand.ExpFloat64() } else { rnd = rand.New(g.Src).ExpFloat64() } return g.Mu - g.Beta*math.Log(rnd) } // Skewness returns the skewness of the distribution. func (GumbelRight) Skewness() float64 { return 12 * math.Sqrt(6) * apery / (math.Pi * math.Pi * math.Pi) } // StdDev returns the standard deviation of the probability distribution. func (g GumbelRight) StdDev() float64 { return (math.Pi / math.Sqrt(6)) * g.Beta } // Survival returns the survival function (complementary CDF) at x. func (g GumbelRight) Survival(x float64) float64 { return 1 - g.CDF(x) } // Variance returns the variance of the probability distribution. func (g GumbelRight) Variance() float64 { return math.Pi * math.Pi * g.Beta * g.Beta / 6 } golang-gonum-v1-gonum-0.14.0/stat/distuv/gumbel_test.go000066400000000000000000000044531450372207100227760ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestGumbelRightProbCDF(t *testing.T) { t.Parallel() for _, test := range []struct { x, mu, beta, wantProb, wantCDF float64 }{ // Values calculated with scipy.stats.gumbel_r . {-2, 0, 1, 0.0045662814201279153, 0.00061797898933109343}, {0.01, 0, 1, 0.36786110881643569, 0.37155817442380817}, {6, 0, 1, 0.0024726155730149077, 0.99752431739275249}, // Values calculated with Wolfram Alpha's ExtremeValueDistribution. {0.1, 2, 5, 0.06776411497087929, 0.231706315790068}, {0.1, -2, 5, 0.06811997894673336, 0.5183799456323944}, {-2.1, -2, 0.1, 1.793740787340169, 0.06598803584531238}, } { g := GumbelRight{Mu: test.mu, Beta: test.beta} pdf := g.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.wantProb, 1e-12, 1e-12) { t.Errorf("Prob mismatch, x = %v, mu = %v, beta = %v. Got %v, want %v", test.x, test.mu, test.beta, pdf, test.wantProb) } cdf := g.CDF(test.x) if !scalar.EqualWithinAbsOrRel(cdf, test.wantCDF, 1e-12, 1e-12) { t.Errorf("CDF mismatch, x = %v, mu = %v, beta = %v. Got %v, want %v", test.x, test.mu, test.beta, cdf, test.wantCDF) } } } func TestGumbelRight(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []GumbelRight{ {0, 1, src}, {-5, 6, src}, {3, 0.1, src}, } { testGumbelRight(t, b, i) } } func testGumbelRight(t *testing.T, g GumbelRight, i int) { const ( tol = 1e-2 n = 5e5 bins = 50 ) x := make([]float64, n) generateSamples(x, g) sort.Float64s(x) min := math.Inf(-1) testRandLogProbContinuous(t, i, min, x, g, tol, bins) checkProbContinuous(t, i, x, math.Inf(-1), math.Inf(1), g, 1e-10) checkEntropy(t, i, x, g, tol) checkMean(t, i, x, g, tol) checkMedian(t, i, x, g, tol) checkVarAndStd(t, i, x, g, tol) checkExKurtosis(t, i, x, g, 1e-1) checkSkewness(t, i, x, g, 5e-2) checkQuantileCDFSurvival(t, i, x, g, 5e-3) if g.Mu != g.Mode() { t.Errorf("Mismatch in mode value: got %v, want %g", g.Mode(), g.Mu) } if g.NumParameters() != 2 { t.Errorf("Mismatch in NumParameters: got %v, want 2", g.NumParameters()) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/interfaces.go000066400000000000000000000015671450372207100226120ustar00rootroot00000000000000// 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 distuv // LogProber wraps the LogProb method. type LogProber interface { // LogProb returns the natural logarithm of the // value of the probability density or probability // mass function at x. LogProb(x float64) float64 } // Rander wraps the Rand method. type Rander interface { // Rand returns a random sample drawn from the distribution. Rand() float64 } // RandLogProber is the interface that groups the Rander and LogProber methods. type RandLogProber interface { Rander LogProber } // Quantiler wraps the Quantile method. type Quantiler interface { // Quantile returns the minimum value of x from amongst // all those values whose CDF value exceeds or equals p. Quantile(p float64) float64 } golang-gonum-v1-gonum-0.14.0/stat/distuv/inversegamma.go000066400000000000000000000065721450372207100231460ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) // InverseGamma implements the inverse gamma distribution, a two-parameter // continuous distribution with support over the positive real numbers. The // inverse gamma distribution is the same as the distribution of the reciprocal // of a gamma distributed random variable. // // The inverse gamma distribution has density function // // β^α / Γ(α) x^(-α-1)e^(-β/x) // // For more information, see https://en.wikipedia.org/wiki/Inverse-gamma_distribution type InverseGamma struct { // Alpha is the shape parameter of the distribution. Alpha must be greater than 0. Alpha float64 // Beta is the scale parameter of the distribution. Beta must be greater than 0. Beta float64 Src rand.Source } // CDF computes the value of the cumulative distribution function at x. func (g InverseGamma) CDF(x float64) float64 { if x < 0 { return 0 } // TODO(btracey): Replace this with a direct call to the upper regularized // gamma function if mathext gets it. //return 1 - mathext.GammaInc(g.Alpha, g.Beta/x) return mathext.GammaIncRegComp(g.Alpha, g.Beta/x) } // ExKurtosis returns the excess kurtosis of the distribution. func (g InverseGamma) ExKurtosis() float64 { if g.Alpha <= 4 { return math.Inf(1) } return (30*g.Alpha - 66) / (g.Alpha - 3) / (g.Alpha - 4) } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (g InverseGamma) LogProb(x float64) float64 { if x <= 0 { return math.Inf(-1) } a := g.Alpha b := g.Beta lg, _ := math.Lgamma(a) return a*math.Log(b) - lg + (-a-1)*math.Log(x) - b/x } // Mean returns the mean of the probability distribution. func (g InverseGamma) Mean() float64 { if g.Alpha <= 1 { return math.Inf(1) } return g.Beta / (g.Alpha - 1) } // Mode returns the mode of the distribution. func (g InverseGamma) Mode() float64 { return g.Beta / (g.Alpha + 1) } // NumParameters returns the number of parameters in the distribution. func (InverseGamma) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (g InverseGamma) Prob(x float64) float64 { return math.Exp(g.LogProb(x)) } // Quantile returns the inverse of the cumulative distribution function. func (g InverseGamma) Quantile(p float64) float64 { if p < 0 || 1 < p { panic(badPercentile) } return (1 / (mathext.GammaIncRegCompInv(g.Alpha, p))) * g.Beta } // Rand returns a random sample drawn from the distribution. // // Rand panics if either alpha or beta is <= 0. func (g InverseGamma) Rand() float64 { // TODO(btracey): See if there is a more direct way to sample. return 1 / Gamma(g).Rand() } // Survival returns the survival function (complementary CDF) at x. func (g InverseGamma) Survival(x float64) float64 { if x < 0 { return 1 } return mathext.GammaIncReg(g.Alpha, g.Beta/x) } // StdDev returns the standard deviation of the probability distribution. func (g InverseGamma) StdDev() float64 { return math.Sqrt(g.Variance()) } // Variance returns the variance of the probability distribution. func (g InverseGamma) Variance() float64 { if g.Alpha <= 2 { return math.Inf(1) } v := g.Beta / (g.Alpha - 1) return v * v / (g.Alpha - 2) } golang-gonum-v1-gonum-0.14.0/stat/distuv/inversegamma_test.go000066400000000000000000000055251450372207100242020ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestInverseGamma(t *testing.T) { t.Parallel() // Values extracted from a comparison with scipy for _, test := range []struct { x, alpha, want float64 }{ {0.9, 4.5, 0.050521067785046482}, {0.04, 45, 0.10550644842525572}, {20, 0.4, 0.0064691988681571536}, } { pdf := InverseGamma{Alpha: test.alpha, Beta: 1}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Pdf mismatch. Got %v, want %v", pdf, test.want) } } src := rand.NewSource(1) for i, g := range []InverseGamma{ {Alpha: 5.6, Beta: 0.5, Src: src}, {Alpha: 30, Beta: 1.7, Src: src}, {Alpha: 30.2, Beta: 1.7, Src: src}, } { testInverseGamma(t, g, i) } } func testInverseGamma(t *testing.T, f InverseGamma, i int) { const ( tol = 1e-2 n = 2e6 bins = 50 ) x := make([]float64, n) generateSamples(x, f) sort.Float64s(x) testRandLogProbContinuous(t, i, 0, x, f, tol, bins) checkMean(t, i, x, f, tol) checkVarAndStd(t, i, x, f, 2e-2) checkExKurtosis(t, i, x, f, 2e-1) checkProbContinuous(t, i, x, 0, math.Inf(1), f, 1e-10) checkQuantileCDFSurvival(t, i, x, f, 5e-2) checkMode(t, i, x, f, 1e-2, 1e-2) cdf0 := f.CDF(0) if cdf0 != 0 { t.Errorf("Expected zero CDF at 0, but got: %v", cdf0) } cdfNeg := f.CDF(-0.0001) if cdfNeg != 0 { t.Errorf("Expected zero CDF for a negative argument, but got: %v", cdfNeg) } surv0 := f.Survival(0) if surv0 != 1 { t.Errorf("Mismatch in Survival at 0. Got %v, want 1", surv0) } survNeg := f.Survival(-0.0001) if survNeg != 1 { t.Errorf("Mismatch in Survival for a negative argument. Got %v, want 1", survNeg) } if f.NumParameters() != 2 { t.Errorf("Mismatch in NumParameters. Got %v, want 2", f.NumParameters()) } pdf0 := f.Prob(0) if pdf0 != 0 { t.Errorf("Expected zero PDF at 0, but got: %v", pdf0) } pdfNeg := f.Prob(-0.0001) if pdfNeg != 0 { t.Errorf("Expected zero PDF for a negative argument, but got: %v", pdfNeg) } } func TestInverseGammaLowAlpha(t *testing.T) { t.Parallel() f := InverseGamma{Alpha: 1, Beta: 1} mean := f.Mean() if !math.IsInf(mean, 1) { t.Errorf("Expected +Inf mean for alpha <= 1, got %v", mean) } f = InverseGamma{Alpha: 2, Beta: 1} stdDev := f.StdDev() if !math.IsInf(stdDev, 1) { t.Errorf("Expected +Inf standard deviation for alpha <= 2, got %v", stdDev) } variance := f.Variance() if !math.IsInf(variance, 1) { t.Errorf("Expected +Inf variance for alpha <= 2, got %v", variance) } f = InverseGamma{Alpha: 4, Beta: 1} exKurt := f.ExKurtosis() if !math.IsInf(exKurt, 1) { t.Errorf("Expected +Inf excess kurtosis for alpha <= 4, got %v", exKurt) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/laplace.go000066400000000000000000000153271450372207100220670ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "golang.org/x/exp/rand" "gonum.org/v1/gonum/stat" ) // Laplace represents the Laplace distribution (https://en.wikipedia.org/wiki/Laplace_distribution). type Laplace struct { Mu float64 // Mean of the Laplace distribution Scale float64 // Scale of the Laplace distribution Src rand.Source } // CDF computes the value of the cumulative density function at x. func (l Laplace) CDF(x float64) float64 { if x < l.Mu { return 0.5 * math.Exp((x-l.Mu)/l.Scale) } return 1 - 0.5*math.Exp(-(x-l.Mu)/l.Scale) } // Entropy returns the entropy of the distribution. func (l Laplace) Entropy() float64 { return 1 + math.Log(2*l.Scale) } // ExKurtosis returns the excess kurtosis of the distribution. func (l Laplace) ExKurtosis() float64 { return 3 } // Fit sets the parameters of the probability distribution from the // data samples x with relative weights w. // If weights is nil, then all the weights are 1. // If weights is not nil, then the len(weights) must equal len(samples). // // Note: Laplace distribution has no FitPrior because it has no sufficient // statistics. func (l *Laplace) Fit(samples, weights []float64) { if weights != nil && len(samples) != len(weights) { panic(badLength) } if len(samples) == 0 { panic(errNoSamples) } if len(samples) == 1 { l.Mu = samples[0] l.Scale = 0 return } var ( sortedSamples []float64 sortedWeights []float64 ) if sort.Float64sAreSorted(samples) { sortedSamples = samples sortedWeights = weights } else { // Need to copy variables so the input variables aren't effected by the sorting sortedSamples = make([]float64, len(samples)) copy(sortedSamples, samples) sortedWeights := make([]float64, len(samples)) copy(sortedWeights, weights) stat.SortWeighted(sortedSamples, sortedWeights) } // The (weighted) median of the samples is the maximum likelihood estimate // of the mean parameter // TODO: Rethink quantile type when stat has more options l.Mu = stat.Quantile(0.5, stat.Empirical, sortedSamples, sortedWeights) // The scale parameter is the average absolute distance // between the sample and the mean var absError float64 var sumWeights float64 if weights != nil { for i, v := range samples { absError += weights[i] * math.Abs(l.Mu-v) sumWeights += weights[i] } l.Scale = absError / sumWeights } else { for _, v := range samples { absError += math.Abs(l.Mu - v) } l.Scale = absError / float64(len(samples)) } } // LogProb computes the natural logarithm of the value of the probability density // function at x. func (l Laplace) LogProb(x float64) float64 { return -math.Ln2 - math.Log(l.Scale) - math.Abs(x-l.Mu)/l.Scale } // parameters returns the parameters of the distribution. func (l Laplace) parameters(p []Parameter) []Parameter { nParam := l.NumParameters() if p == nil { p = make([]Parameter, nParam) } else if len(p) != nParam { panic(badLength) } p[0].Name = "Mu" p[0].Value = l.Mu p[1].Name = "Scale" p[1].Value = l.Scale return p } // Mean returns the mean of the probability distribution. func (l Laplace) Mean() float64 { return l.Mu } // Median returns the median of the LaPlace distribution. func (l Laplace) Median() float64 { return l.Mu } // Mode returns the mode of the LaPlace distribution. func (l Laplace) Mode() float64 { return l.Mu } // NumParameters returns the number of parameters in the distribution. func (l Laplace) NumParameters() int { return 2 } // Quantile returns the inverse of the cumulative probability distribution. func (l Laplace) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } if p < 0.5 { return l.Mu + l.Scale*math.Log(1+2*(p-0.5)) } return l.Mu - l.Scale*math.Log(1-2*(p-0.5)) } // Prob computes the value of the probability density function at x. func (l Laplace) Prob(x float64) float64 { return math.Exp(l.LogProb(x)) } // Rand returns a random sample drawn from the distribution. func (l Laplace) Rand() float64 { var rnd float64 if l.Src == nil { rnd = rand.Float64() } else { rnd = rand.New(l.Src).Float64() } u := rnd - 0.5 if u < 0 { return l.Mu + l.Scale*math.Log(1+2*u) } return l.Mu - l.Scale*math.Log(1-2*u) } // Score returns the score function with respect to the parameters of the // distribution at the input location x. The score function is the derivative // of the log-likelihood at x with respect to the parameters // // (∂/∂θ) log(p(x;θ)) // // If deriv is non-nil, len(deriv) must equal the number of parameters otherwise // Score will panic, and the derivative is stored in-place into deriv. If deriv // is nil a new slice will be allocated and returned. // // The order is [∂LogProb / ∂Mu, ∂LogProb / ∂Scale]. // // For more information, see https://en.wikipedia.org/wiki/Score_%28statistics%29. // // Special cases: // // Score(l.Mu) = [NaN, -1/l.Scale] func (l Laplace) Score(deriv []float64, x float64) []float64 { if deriv == nil { deriv = make([]float64, l.NumParameters()) } if len(deriv) != l.NumParameters() { panic(badLength) } diff := x - l.Mu if diff > 0 { deriv[0] = 1 / l.Scale } else if diff < 0 { deriv[0] = -1 / l.Scale } else { // must be NaN deriv[0] = math.NaN() } deriv[1] = math.Abs(diff)/(l.Scale*l.Scale) - 1/l.Scale return deriv } // ScoreInput returns the score function with respect to the input of the // distribution at the input location specified by x. The score function is the // derivative of the log-likelihood // // (d/dx) log(p(x)) . // // Special cases: // // ScoreInput(l.Mu) = NaN func (l Laplace) ScoreInput(x float64) float64 { diff := x - l.Mu if diff == 0 { return math.NaN() } if diff > 0 { return -1 / l.Scale } return 1 / l.Scale } // Skewness returns the skewness of the distribution. func (Laplace) Skewness() float64 { return 0 } // StdDev returns the standard deviation of the distribution. func (l Laplace) StdDev() float64 { return math.Sqrt2 * l.Scale } // Survival returns the survival function (complementary CDF) at x. func (l Laplace) Survival(x float64) float64 { if x < l.Mu { return 1 - 0.5*math.Exp((x-l.Mu)/l.Scale) } return 0.5 * math.Exp(-(x-l.Mu)/l.Scale) } // setParameters modifies the parameters of the distribution. func (l *Laplace) setParameters(p []Parameter) { if len(p) != l.NumParameters() { panic(badLength) } if p[0].Name != "Mu" { panic("laplace: " + panicNameMismatch) } if p[1].Name != "Scale" { panic("laplace: " + panicNameMismatch) } l.Mu = p[0].Value l.Scale = p[1].Value } // Variance returns the variance of the probability distribution. func (l Laplace) Variance() float64 { return 2 * l.Scale * l.Scale } golang-gonum-v1-gonum-0.14.0/stat/distuv/laplace_test.go000066400000000000000000000130161450372207100231170ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestLaplaceProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: 0.5, cumProb: 0.5, logProb: math.Log(0.5), }, { loc: -1, prob: 1 / (2 * math.E), cumProb: 0.1839397205857211607977618850807304337229055655158839172539184008487307478724499016785736371729598219, logProb: math.Log(1 / (2 * math.E)), }, { loc: 1, prob: 1 / (2 * math.E), cumProb: 0.8160602794142788392022381149192695662770944344841160827460815991512692521275500983214263628270401781, logProb: math.Log(1 / (2 * math.E)), }, { loc: -7, prob: 1 / (2 * math.Pow(math.E, 7)), cumProb: 0.0004559409827772581040015680422046413132368622637180269204080667109447399446551532646631395032324502210, logProb: math.Log(1 / (2 * math.Pow(math.E, 7))), }, { loc: 7, prob: 1 / (2 * math.Pow(math.E, 7)), cumProb: 0.9995440590172227418959984319577953586867631377362819730795919332890552600553448467353368604967675498, logProb: math.Log(1 / (2 * math.Pow(math.E, 7))), }, { loc: -20, prob: math.Exp(-20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869), cumProb: 1.030576811219278913982970190077910488187903637799551846486122330814582011892279676639955463952790684 * 1e-9, logProb: -20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869, }, { loc: 20, prob: math.Exp(-20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869), cumProb: 0.999999998969423188780721086017029809922089511812096362200448153513877669185417988107720323360044536, logProb: -20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869, }, } testDistributionProbs(t, Laplace{Mu: 0, Scale: 1}, "Laplace", pts) } func TestLaplace(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, dist := range []Laplace{ {Mu: 0, Scale: 3, Src: src}, {Mu: 1, Scale: 1.5, Src: src}, {Mu: -1, Scale: 0.9, Src: src}, } { testLaplace(t, dist, i) } } func testLaplace(t *testing.T, dist Laplace, i int) { const ( tol = 1e-2 n = 3e6 bins = 50 ) x := make([]float64, n) generateSamples(x, dist) sort.Float64s(x) checkMean(t, i, x, dist, tol) checkVarAndStd(t, i, x, dist, tol) checkEntropy(t, i, x, dist, tol) checkExKurtosis(t, i, x, dist, tol) checkSkewness(t, i, x, dist, tol) checkMedian(t, i, x, dist, tol) checkQuantileCDFSurvival(t, i, x, dist, tol) checkProbContinuous(t, i, x, math.Inf(-1), math.Inf(1), dist, 1e-10) checkProbQuantContinuous(t, i, x, dist, tol) testDerivParam(t, &dist) if dist.Mu != dist.Mode() { t.Errorf("Mismatch in mode value, got: %v, want: %g", dist.Mode(), dist.Mu) } score := dist.Score(nil, dist.Mu) if !math.IsNaN(score[0]) { t.Errorf("Expected NaN score over Mu for x == Mu, got %v", score[0]) } if score[1] != -1/dist.Scale { t.Errorf("Mismatch in score over Scale value for x == Mu, got: %v, want: %g", score[1], -1/dist.Scale) } scoreInput := dist.ScoreInput(dist.Mu) if !math.IsNaN(scoreInput) { t.Errorf("Expected NaN input score for x == Mu, got %v", scoreInput) } } func TestLaplaceFit(t *testing.T) { t.Parallel() cases := []struct { samples []float64 weights []float64 wantMu float64 wantScale float64 }{ { samples: []float64{10, 1, 1}, weights: nil, wantMu: 1, wantScale: 3, }, { samples: []float64{10, 1, 1}, weights: []float64{10, 10, 10}, wantMu: 1, wantScale: 3, }, { samples: []float64{10, 1, 1}, weights: []float64{0, 1, 1}, wantMu: 1, wantScale: 0, }, { samples: []float64{1, 1, 10}, weights: []float64{1, 1, 0}, wantMu: 1, wantScale: 0, }, { samples: []float64{10}, weights: nil, wantMu: 10, wantScale: 0, }, } for i, test := range cases { d := Laplace{} d.Fit(test.samples, test.weights) if !scalar.EqualWithinAbsOrRel(d.Mu, test.wantMu, 1e-10, 1e-10) { t.Errorf("unexpected location result for test %d: got:%f, want:%f", i, d.Mu, test.wantMu) } if !scalar.EqualWithinAbsOrRel(d.Scale, test.wantScale, 1e-10, 1e-10) { t.Errorf("unexpected scale result for test %d: got:%f, want:%f", i, d.Scale, test.wantScale) } } } func TestLaplaceFitRandomSamples(t *testing.T) { t.Parallel() nSamples := 100000 src := rand.New(rand.NewSource(1)) l := Laplace{ Mu: 3, Scale: 5, Src: src, } samples := make([]float64, nSamples) for i := range samples { samples[i] = l.Rand() } le := Laplace{} le.Fit(samples, nil) if !scalar.EqualWithinAbsOrRel(le.Mu, l.Mu, 1e-2, 1e-2) { t.Errorf("unexpected location result for random test got:%f, want:%f", le.Mu, l.Mu) } if !scalar.EqualWithinAbsOrRel(le.Scale, l.Scale, 1e-2, 1e-2) { t.Errorf("unexpected scale result for random test got:%f, want:%f", le.Scale, l.Scale) } } func TestLaplaceFitPanic(t *testing.T) { t.Parallel() l := Laplace{ Mu: 3, Scale: 5, Src: nil, } if !panics(func() { l.Fit([]float64{1, 1, 1}, []float64{0.4, 0.4}) }) { t.Errorf("Expected panic in Fit for len(sample) != len(weights)") } if !panics(func() { l.Fit([]float64{}, nil) }) { t.Errorf("Expected panic in Fit for len(sample) == 0") } } golang-gonum-v1-gonum-0.14.0/stat/distuv/logistic.go000066400000000000000000000051711450372207100222770ustar00rootroot00000000000000// Copyright ©2021 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 distuv import ( "math" ) // Logistic implements the Logistic distribution, a two-parameter distribution with support on the real axis. // Its cumulative distribution function is the logistic function. // // General form of probability density function for Logistic distribution is // // E(x) / (s * (1 + E(x))^2) // where E(x) = exp(-(x-μ)/s) // // For more information, see https://en.wikipedia.org/wiki/Logistic_distribution. type Logistic struct { Mu float64 // Mean value S float64 // Scale parameter proportional to standard deviation } // CDF computes the value of the cumulative density function at x. func (l Logistic) CDF(x float64) float64 { return 1 / (1 + math.Exp(-(x-l.Mu)/l.S)) } // ExKurtosis returns the excess kurtosis of the distribution. func (l Logistic) ExKurtosis() float64 { return 6.0 / 5.0 } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (l Logistic) LogProb(x float64) float64 { return x - 2*math.Log(math.Exp(x)+1) } // Mean returns the mean of the probability distribution. func (l Logistic) Mean() float64 { return l.Mu } // Mode returns the mode of the distribution. // // It is same as Mean for Logistic distribution. func (l Logistic) Mode() float64 { return l.Mu } // Median returns the median of the distribution. // // It is same as Mean for Logistic distribution. func (l Logistic) Median() float64 { return l.Mu } // NumParameters returns the number of parameters in the distribution. // // Always returns 2. func (l Logistic) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (l Logistic) Prob(x float64) float64 { E := math.Exp(-(x - l.Mu) / l.S) return E / (l.S * math.Pow(1+E, 2)) } // Quantile returns the inverse of the cumulative distribution function. func (l Logistic) Quantile(p float64) float64 { return l.Mu + l.S*math.Log(p/(1-p)) } // Skewness returns the skewness of the distribution. // // Always 0 for Logistic distribution. func (l Logistic) Skewness() float64 { return 0 } // StdDev returns the standard deviation of the probability distribution. func (l Logistic) StdDev() float64 { return l.S * math.Pi / sqrt3 } // Survival returns the survival function (complementary CDF) at x. func (l Logistic) Survival(x float64) float64 { return 1 - l.CDF(x) } // Variance returns the variance of the probability distribution. func (l Logistic) Variance() float64 { return l.S * l.S * math.Pi * math.Pi / 3 } golang-gonum-v1-gonum-0.14.0/stat/distuv/logistic_test.go000066400000000000000000000105341450372207100233350ustar00rootroot00000000000000// Copyright ©2021 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 distuv import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" ) func TestLogisticParameters(t *testing.T) { t.Parallel() var want float64 l := Logistic{Mu: 1, S: 0} want = 2 if result := l.NumParameters(); result != int(want) { t.Errorf("Wrong number of parameters: %d != %.0f", result, want) } want = 6.0 / 5.0 if result := l.ExKurtosis(); result != want { t.Errorf("Wrong excess kurtosis: %f != %f", result, want) } want = 0.0 if result := l.Skewness(); result != want { t.Errorf("Wrong skewness: %f != %f", result, want) } want = l.Mu if result := l.Mean(); result != want { t.Errorf("Wrong mean value: %f != %f", result, want) } want = l.Mu if result := l.Median(); result != want { t.Errorf("Wrong median value: %f != %f", result, want) } want = l.Mu if result := l.Mode(); result != want { t.Errorf("Wrong mode value: %f != %f", result, want) } } func TestLogisticStdDev(t *testing.T) { t.Parallel() l := Logistic{Mu: 0, S: sqrt3 / math.Pi} want := 1.0 if result := l.StdDev(); !scalar.EqualWithinAbs(result, want, 1e-10) { t.Errorf("Wrong StdDev with Mu=%f, S=%f: %f != %f", l.Mu, l.S, result, want) } want = 1.0 if result := l.Variance(); !scalar.EqualWithinAbs(result, want, 1e-10) { t.Errorf("Wrong Variance with Mu=%f, S=%f: %f != %f", l.Mu, l.S, result, want) } } func TestLogisticCDF(t *testing.T) { t.Parallel() // Values for "want" are taken from WolframAlpha: CDF[LogisticDistribution[mu,s], input] to 10 digits. for _, v := range []struct { mu, s, input, want float64 }{ {0.0, 0.0, 1.0, 1.0}, {0.0, 1.0, 0.0, 0.5}, {-0.5, 1.0, 0.0, 0.6224593312}, {69.0, 420.0, 42.0, 0.4839341039}, } { l := Logistic{Mu: v.mu, S: v.s} if result := l.CDF(v.input); !scalar.EqualWithinAbs(result, v.want, 1e-10) { t.Errorf("Wrong CDF(%f) with Mu=%f, S=%f: %f != %f", v.input, l.Mu, l.S, result, v.want) } } // Edge case of zero in denominator. l := Logistic{Mu: 0, S: 0} input := 0.0 if result := l.CDF(input); !math.IsNaN(result) { t.Errorf("Wrong CDF(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) } } // TestLogisticSurvival doesn't need excessive testing since it's just 1-CDF. func TestLogisticSurvival(t *testing.T) { t.Parallel() l := Logistic{Mu: 0, S: 1} input, want := 0.0, 0.5 if result := l.Survival(input); result != want { t.Errorf("Wrong Survival(%f) with Mu=%f, S=%f: %f != %f", input, l.Mu, l.S, result, want) } } func TestLogisticProb(t *testing.T) { t.Parallel() // Values for "want" are taken from WolframAlpha: PDF[LogisticDistribution[mu,s], input] to 10 digits. for _, v := range []struct { mu, s, input, want float64 }{ {0.0, 1.0, 0.0, 0.25}, {-0.5, 1.0, 0.0, 0.2350037122}, {69.0, 420.0, 42.0, 0.0005946235404}, } { l := Logistic{Mu: v.mu, S: v.s} if result := l.Prob(v.input); !scalar.EqualWithinAbs(result, v.want, 1e-10) { t.Errorf("Wrong Prob(%f) with Mu=%f, S=%f: %.09f != %.09f", v.input, l.Mu, l.S, result, v.want) } } // Edge case of zero in denominator. l := Logistic{Mu: 0, S: 0} input := 0.0 if result := l.Prob(input); !math.IsNaN(result) { t.Errorf("Wrong Prob(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) } input = 1.0 if result := l.Prob(input); !math.IsNaN(result) { t.Errorf("Wrong Prob(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) } } func TestLogisticLogProb(t *testing.T) { t.Parallel() l := Logistic{Mu: 0, S: 1} input, want := 0.0, -math.Log(4) if result := l.LogProb(input); result != want { t.Errorf("Wrong LogProb(%f) with Mu=%f, S=%f: %f != %f", input, l.Mu, l.S, result, want) } } func TestQuantile(t *testing.T) { t.Parallel() for _, v := range []struct { mu, s, input, want float64 }{ {0.0, 1.0, 0.5, 0.0}, {0.0, 1.0, 0.0, math.Inf(-1)}, {0.0, 1.0, 1.0, math.Inf(+1)}, } { l := Logistic{Mu: v.mu, S: v.s} if result := l.Quantile(v.input); result != v.want { t.Errorf("Wrong Quantile(%f) with Mu=%f, S=%f: %f != %f", v.input, l.Mu, l.S, result, v.want) } } // Edge case with NaN. l := Logistic{Mu: 0, S: 0} input := 0.0 if result := l.Quantile(input); !math.IsNaN(result) { t.Errorf("Wrong Quantile(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/lognormal.go000066400000000000000000000062771450372207100224640ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" ) // LogNormal represents a random variable whose log is normally distributed. // The probability density function is given by // // 1/(x σ √2π) exp(-(ln(x)-μ)^2)/(2σ^2)) type LogNormal struct { Mu float64 Sigma float64 Src rand.Source } // CDF computes the value of the cumulative density function at x. func (l LogNormal) CDF(x float64) float64 { return 0.5 * math.Erfc(-(math.Log(x)-l.Mu)/(math.Sqrt2*l.Sigma)) } // Entropy returns the differential entropy of the distribution. func (l LogNormal) Entropy() float64 { return 0.5 + 0.5*math.Log(2*math.Pi*l.Sigma*l.Sigma) + l.Mu } // ExKurtosis returns the excess kurtosis of the distribution. func (l LogNormal) ExKurtosis() float64 { s2 := l.Sigma * l.Sigma return math.Exp(4*s2) + 2*math.Exp(3*s2) + 3*math.Exp(2*s2) - 6 } // LogProb computes the natural logarithm of the value of the probability density function at x. func (l LogNormal) LogProb(x float64) float64 { if x < 0 { return math.Inf(-1) } logx := math.Log(x) normdiff := (logx - l.Mu) / l.Sigma return -0.5*normdiff*normdiff - logx - math.Log(l.Sigma) - logRoot2Pi } // Mean returns the mean of the probability distribution. func (l LogNormal) Mean() float64 { return math.Exp(l.Mu + 0.5*l.Sigma*l.Sigma) } // Median returns the median of the probability distribution. func (l LogNormal) Median() float64 { return math.Exp(l.Mu) } // Mode returns the mode of the probability distribution. func (l LogNormal) Mode() float64 { return math.Exp(l.Mu - l.Sigma*l.Sigma) } // NumParameters returns the number of parameters in the distribution. func (LogNormal) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (l LogNormal) Prob(x float64) float64 { return math.Exp(l.LogProb(x)) } // Quantile returns the inverse of the cumulative probability distribution. func (l LogNormal) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } // Formula from http://www.math.uah.edu/stat/special/LogNormal.html. return math.Exp(l.Mu + l.Sigma*UnitNormal.Quantile(p)) } // Rand returns a random sample drawn from the distribution. func (l LogNormal) Rand() float64 { var rnd float64 if l.Src == nil { rnd = rand.NormFloat64() } else { rnd = rand.New(l.Src).NormFloat64() } return math.Exp(rnd*l.Sigma + l.Mu) } // Skewness returns the skewness of the distribution. func (l LogNormal) Skewness() float64 { s2 := l.Sigma * l.Sigma return (math.Exp(s2) + 2) * math.Sqrt(math.Exp(s2)-1) } // StdDev returns the standard deviation of the probability distribution. func (l LogNormal) StdDev() float64 { return math.Sqrt(l.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (l LogNormal) Survival(x float64) float64 { return 0.5 * (1 - math.Erf((math.Log(x)-l.Mu)/(math.Sqrt2*l.Sigma))) } // Variance returns the variance of the probability distribution. func (l LogNormal) Variance() float64 { s2 := l.Sigma * l.Sigma return (math.Exp(s2) - 1) * math.Exp(2*l.Mu+s2) } golang-gonum-v1-gonum-0.14.0/stat/distuv/lognormal_test.go000066400000000000000000000031511450372207100235070ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" ) func TestLognormal(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, dist := range []LogNormal{ {Mu: 0.1, Sigma: 0.3, Src: src}, {Mu: 0.01, Sigma: 0.01, Src: src}, {Mu: 2, Sigma: 0.01, Src: src}, } { const ( tol = 1e-2 n = 1e5 ) x := make([]float64, n) generateSamples(x, dist) sort.Float64s(x) checkMean(t, i, x, dist, tol) checkVarAndStd(t, i, x, dist, tol) checkEntropy(t, i, x, dist, tol) checkExKurtosis(t, i, x, dist, 2e-1) checkSkewness(t, i, x, dist, 5e-2) checkMedian(t, i, x, dist, tol) checkQuantileCDFSurvival(t, i, x, dist, tol) checkProbContinuous(t, i, x, 0, math.Inf(1), dist, 1e-10) checkProbQuantContinuous(t, i, x, dist, tol) checkMode(t, i, x, dist, 1e-2, 1e-2) logProb := dist.LogProb(-0.0001) if !math.IsInf(logProb, -1) { t.Errorf("Expected LogProb == -Inf for x < 0, got %v", logProb) } if dist.NumParameters() != 2 { t.Errorf("Mismatch in NumParameters: got %v, want 2", dist.NumParameters()) } } } // See https://github.com/gonum/gonum/issues/577 for details. func TestLognormalIssue577(t *testing.T) { t.Parallel() x := 1.0e-16 max := 1.0e-295 cdf := LogNormal{Mu: 0, Sigma: 1}.CDF(x) if cdf <= 0 { t.Errorf("LogNormal{0,1}.CDF(%e) should be positive. got: %e", x, cdf) } if cdf > max { t.Errorf("LogNormal{0,1}.CDF(%e) is greater than %e. got: %e", x, max, cdf) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/norm.go000066400000000000000000000206511450372207100214350ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mathext" "gonum.org/v1/gonum/stat" ) // UnitNormal is an instantiation of the normal distribution with Mu = 0 and Sigma = 1. var UnitNormal = Normal{Mu: 0, Sigma: 1} // Normal represents a normal (Gaussian) distribution (https://en.wikipedia.org/wiki/Normal_distribution). type Normal struct { Mu float64 // Mean of the normal distribution Sigma float64 // Standard deviation of the normal distribution Src rand.Source // Needs to be Mu and Sigma and not Mean and StdDev because Normal has functions // Mean and StdDev } // CDF computes the value of the cumulative density function at x. func (n Normal) CDF(x float64) float64 { return 0.5 * math.Erfc(-(x-n.Mu)/(n.Sigma*math.Sqrt2)) } // ConjugateUpdate updates the parameters of the distribution from the sufficient // statistics of a set of samples. The sufficient statistics, suffStat, have been // observed with nSamples observations. The prior values of the distribution are those // currently in the distribution, and have been observed with priorStrength samples. // // For the normal distribution, the sufficient statistics are the mean and // uncorrected standard deviation of the samples. // The prior is having seen strength[0] samples with mean Normal.Mu // and strength[1] samples with standard deviation Normal.Sigma. As a result of // this function, Normal.Mu and Normal.Sigma are updated based on the weighted // samples, and strength is modified to include the new number of samples observed. // // This function panics if len(suffStat) != n.NumSuffStat() or // len(priorStrength) != n.NumSuffStat(). func (n *Normal) ConjugateUpdate(suffStat []float64, nSamples float64, priorStrength []float64) { // TODO: Support prior strength with math.Inf(1) to allow updating with // a known mean/standard deviation if len(suffStat) != n.NumSuffStat() { panic("norm: incorrect suffStat length") } if len(priorStrength) != n.NumSuffStat() { panic("norm: incorrect priorStrength length") } totalMeanSamples := nSamples + priorStrength[0] totalSum := suffStat[0]*nSamples + n.Mu*priorStrength[0] totalVarianceSamples := nSamples + priorStrength[1] // sample variance totalVariance := nSamples * suffStat[1] * suffStat[1] // add prior variance totalVariance += priorStrength[1] * n.Sigma * n.Sigma // add cross variance from the difference of the means meanDiff := (suffStat[0] - n.Mu) totalVariance += priorStrength[0] * nSamples * meanDiff * meanDiff / totalMeanSamples n.Mu = totalSum / totalMeanSamples n.Sigma = math.Sqrt(totalVariance / totalVarianceSamples) floats.AddConst(nSamples, priorStrength) } // Entropy returns the differential entropy of the distribution. func (n Normal) Entropy() float64 { return 0.5 * (log2Pi + 1 + 2*math.Log(n.Sigma)) } // ExKurtosis returns the excess kurtosis of the distribution. func (Normal) ExKurtosis() float64 { return 0 } // Fit sets the parameters of the probability distribution from the // data samples x with relative weights w. If weights is nil, then all the weights // are 1. If weights is not nil, then the len(weights) must equal len(samples). func (n *Normal) Fit(samples, weights []float64) { suffStat := make([]float64, n.NumSuffStat()) nSamples := n.SuffStat(suffStat, samples, weights) n.ConjugateUpdate(suffStat, nSamples, make([]float64, n.NumSuffStat())) } // LogProb computes the natural logarithm of the value of the probability density function at x. func (n Normal) LogProb(x float64) float64 { return negLogRoot2Pi - math.Log(n.Sigma) - (x-n.Mu)*(x-n.Mu)/(2*n.Sigma*n.Sigma) } // Mean returns the mean of the probability distribution. func (n Normal) Mean() float64 { return n.Mu } // Median returns the median of the normal distribution. func (n Normal) Median() float64 { return n.Mu } // Mode returns the mode of the normal distribution. func (n Normal) Mode() float64 { return n.Mu } // NumParameters returns the number of parameters in the distribution. func (Normal) NumParameters() int { return 2 } // NumSuffStat returns the number of sufficient statistics for the distribution. func (Normal) NumSuffStat() int { return 2 } // Prob computes the value of the probability density function at x. func (n Normal) Prob(x float64) float64 { return math.Exp(n.LogProb(x)) } // Quantile returns the inverse of the cumulative probability distribution. func (n Normal) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } return n.Mu + n.Sigma*mathext.NormalQuantile(p) } // Rand returns a random sample drawn from the distribution. func (n Normal) Rand() float64 { var rnd float64 if n.Src == nil { rnd = rand.NormFloat64() } else { rnd = rand.New(n.Src).NormFloat64() } return rnd*n.Sigma + n.Mu } // Score returns the score function with respect to the parameters of the // distribution at the input location x. The score function is the derivative // of the log-likelihood at x with respect to the parameters // // (∂/∂θ) log(p(x;θ)) // // If deriv is non-nil, len(deriv) must equal the number of parameters otherwise // Score will panic, and the derivative is stored in-place into deriv. If deriv // is nil a new slice will be allocated and returned. // // The order is [∂LogProb / ∂Mu, ∂LogProb / ∂Sigma]. // // For more information, see https://en.wikipedia.org/wiki/Score_%28statistics%29. func (n Normal) Score(deriv []float64, x float64) []float64 { if deriv == nil { deriv = make([]float64, n.NumParameters()) } if len(deriv) != n.NumParameters() { panic(badLength) } deriv[0] = (x - n.Mu) / (n.Sigma * n.Sigma) deriv[1] = 1 / n.Sigma * (-1 + ((x-n.Mu)/n.Sigma)*((x-n.Mu)/n.Sigma)) return deriv } // ScoreInput returns the score function with respect to the input of the // distribution at the input location specified by x. The score function is the // derivative of the log-likelihood // // (d/dx) log(p(x)) . func (n Normal) ScoreInput(x float64) float64 { return -(1 / (2 * n.Sigma * n.Sigma)) * 2 * (x - n.Mu) } // Skewness returns the skewness of the distribution. func (Normal) Skewness() float64 { return 0 } // StdDev returns the standard deviation of the probability distribution. func (n Normal) StdDev() float64 { return n.Sigma } // SuffStat computes the sufficient statistics of a set of samples to update // the distribution. The sufficient statistics are stored in place, and the // effective number of samples are returned. // // The normal distribution has two sufficient statistics, the mean of the samples // and the standard deviation of the samples. // // If weights is nil, the weights are assumed to be 1, otherwise panics if // len(samples) != len(weights). Panics if len(suffStat) != NumSuffStat(). func (Normal) SuffStat(suffStat, samples, weights []float64) (nSamples float64) { lenSamp := len(samples) if len(weights) != 0 && len(samples) != len(weights) { panic(badLength) } if len(suffStat) != (Normal{}).NumSuffStat() { panic(badSuffStat) } if len(weights) == 0 { nSamples = float64(lenSamp) } else { nSamples = floats.Sum(weights) } mean := stat.Mean(samples, weights) suffStat[0] = mean // Use Moment and not StdDev because we want it to be uncorrected variance := stat.MomentAbout(2, samples, mean, weights) suffStat[1] = math.Sqrt(variance) return nSamples } // Survival returns the survival function (complementary CDF) at x. func (n Normal) Survival(x float64) float64 { return 0.5 * (1 - math.Erf((x-n.Mu)/(n.Sigma*math.Sqrt2))) } // setParameters modifies the parameters of the distribution. func (n *Normal) setParameters(p []Parameter) { if len(p) != n.NumParameters() { panic("normal: incorrect number of parameters to set") } if p[0].Name != "Mu" { panic("normal: " + panicNameMismatch) } if p[1].Name != "Sigma" { panic("normal: " + panicNameMismatch) } n.Mu = p[0].Value n.Sigma = p[1].Value } // Variance returns the variance of the probability distribution. func (n Normal) Variance() float64 { return n.Sigma * n.Sigma } // parameters returns the parameters of the distribution. func (n Normal) parameters(p []Parameter) []Parameter { nParam := n.NumParameters() if p == nil { p = make([]Parameter, nParam) } else if len(p) != nParam { panic("normal: improper parameter length") } p[0].Name = "Mu" p[0].Value = n.Mu p[1].Name = "Sigma" p[1].Value = n.Sigma return p } golang-gonum-v1-gonum-0.14.0/stat/distuv/norm_example_test.go000066400000000000000000000013001450372207100241750ustar00rootroot00000000000000// 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 distuv_test import ( "fmt" "gonum.org/v1/gonum/stat" "gonum.org/v1/gonum/stat/distuv" ) func ExampleNormal() { // Create a normal distribution dist := distuv.Normal{ Mu: 2, Sigma: 5, } data := make([]float64, 1e5) // Draw some random values from the standard normal distribution for i := range data { data[i] = dist.Rand() } mean, std := stat.MeanStdDev(data, nil) meanErr := stat.StdErr(std, float64(len(data))) fmt.Printf("mean= %1.1f ± %0.1v\n", mean, meanErr) // Output: // mean= 2.0 ± 0.02 } golang-gonum-v1-gonum-0.14.0/stat/distuv/norm_test.go000066400000000000000000000152021450372207100224700ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) // TestNormalProbs tests LogProb, Prob, CumProb, and Quantile func TestNormalProbs(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: oneOverRoot2Pi, cumProb: 0.5, logProb: -0.91893853320467274178032973640561763986139747363778341281715, }, { loc: -1, prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047, cumProb: 0.158655253931457051414767454367962077522087033273395609012605, logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047), }, { loc: 1, prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047, cumProb: 0.841344746068542948585232545632037922477912966726604390987394, logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047), }, { loc: -7, prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12, cumProb: 1.279812543885835004383623690780832998032844154198717929e-12, logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12), }, { loc: 7, prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12, cumProb: 0.99999999999872018745611416499561637630921916700196715584580, logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12), }, } testDistributionProbs(t, Normal{Mu: 0, Sigma: 1}, "normal", pts) pts = []univariateProbPoint{ { loc: 2, prob: 0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729, cumProb: 0.5, logProb: math.Log(0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729), }, { loc: -3, prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095, cumProb: 0.158655253931457051414767454367962077522087033273395609012605, logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095), }, { loc: 7, prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095, cumProb: 0.841344746068542948585232545632037922477912966726604390987394, logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095), }, { loc: -33, prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12, cumProb: 1.279812543885835004383623690780832998032844154198717929e-12, logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12), }, { loc: 37, prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12, cumProb: 0.99999999999872018745611416499561637630921916700196715584580, logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12), }, } testDistributionProbs(t, Normal{Mu: 2, Sigma: 5}, "normal", pts) } func TestNormal(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, dist := range []Normal{ {Mu: 0, Sigma: 3, Src: src}, {Mu: 1, Sigma: 1.5, Src: src}, {Mu: -1, Sigma: 0.9, Src: src}, } { testNormal(t, dist, i) } } func testNormal(t *testing.T, dist Normal, i int) { const ( tol = 1e-2 n = 3e6 bins = 50 ) x := make([]float64, n) generateSamples(x, dist) sort.Float64s(x) checkMean(t, i, x, dist, tol) checkVarAndStd(t, i, x, dist, tol) checkEntropy(t, i, x, dist, tol) checkExKurtosis(t, i, x, dist, tol) checkSkewness(t, i, x, dist, tol) checkMedian(t, i, x, dist, tol) checkQuantileCDFSurvival(t, i, x, dist, tol) checkProbContinuous(t, i, x, math.Inf(-1), math.Inf(1), dist, 1e-10) checkProbQuantContinuous(t, i, x, dist, tol) if dist.Mu != dist.Mode() { t.Errorf("Mismatch in mode value: got %v, want %g", dist.Mode(), dist.Mu) } } func TestNormFitPrior(t *testing.T) { t.Parallel() testConjugateUpdate(t, func() ConjugateUpdater { return &Normal{Mu: -10, Sigma: 6} }) } func TestNormScore(t *testing.T) { t.Parallel() for _, test := range []*Normal{ { Mu: 0, Sigma: 1, }, { Mu: 0.32238, Sigma: 13.69, }, } { testDerivParam(t, test) } } func TestNormalQuantile(t *testing.T) { t.Parallel() // Values from https://www.johndcook.com/blog/normal_cdf_inverse/ p := []float64{ 0.0000001, 0.00001, 0.001, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95, 0.999, 0.99999, 0.9999999, } ans := []float64{ -5.199337582187471, -4.264890793922602, -3.090232306167813, -1.6448536269514729, -1.0364333894937896, -0.6744897501960817, -0.38532046640756773, -0.12566134685507402, 0.12566134685507402, 0.38532046640756773, 0.6744897501960817, 1.0364333894937896, 1.6448536269514729, 3.090232306167813, 4.264890793922602, 5.199337582187471, } for i, v := range p { got := UnitNormal.Quantile(v) if !scalar.EqualWithinAbsOrRel(got, ans[i], 1e-10, 1e-10) { t.Errorf("Quantile mismatch. Case %d, want: %v, got: %v", i, ans[i], got) } } } func TestNormFitPanic(t *testing.T) { t.Parallel() n := Normal{Mu: 0, Sigma: 1} defer func() { r := recover() if r != nil { t.Errorf("unexpected panic for Fit call: %v", r) } }() n.Fit(make([]float64, 10), nil) } func BenchmarkNormalQuantile(b *testing.B) { n := Normal{Mu: 2, Sigma: 3.1} ps := make([]float64, 1000) // ensure there are small values floats.Span(ps, 0, 1) for i := 0; i < b.N; i++ { for _, v := range ps { x := n.Quantile(v) _ = x } } } // See https://github.com/gonum/gonum/issues/577 for details. func TestNormalIssue577(t *testing.T) { t.Parallel() x := -36.0 max := 1.e-282 cdf := Normal{Mu: 0, Sigma: 1}.CDF(x) if cdf <= 0 { t.Errorf("Normal{0,1}.CDF(%e) should be positive. got: %e", x, cdf) } if cdf > max { t.Errorf("Normal{0,1}.CDF(%e) is greater than %e. got: %e", x, max, cdf) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/pareto.go000066400000000000000000000063221450372207100217530ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" ) // Pareto implements the Pareto (Type I) distribution, a one parameter distribution // with support above the scale parameter. // // The density function is given by // // (α x_m^{α})/(x^{α+1}) for x >= x_m. // // For more information, see https://en.wikipedia.org/wiki/Pareto_distribution. type Pareto struct { // Xm is the scale parameter. // Xm must be greater than 0. Xm float64 // Alpha is the shape parameter. // Alpha must be greater than 0. Alpha float64 Src rand.Source } // CDF computes the value of the cumulative density function at x. func (p Pareto) CDF(x float64) float64 { if x < p.Xm { return 0 } return -math.Expm1(p.Alpha * math.Log(p.Xm/x)) } // Entropy returns the differential entropy of the distribution. func (p Pareto) Entropy() float64 { return math.Log(p.Xm) - math.Log(p.Alpha) + (1 + 1/p.Alpha) } // ExKurtosis returns the excess kurtosis of the distribution. func (p Pareto) ExKurtosis() float64 { if p.Alpha <= 4 { return math.NaN() } return 6 * (p.Alpha*p.Alpha*p.Alpha + p.Alpha*p.Alpha - 6*p.Alpha - 2) / (p.Alpha * (p.Alpha - 3) * (p.Alpha - 4)) } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (p Pareto) LogProb(x float64) float64 { if x < p.Xm { return math.Inf(-1) } return math.Log(p.Alpha) + p.Alpha*math.Log(p.Xm) - (p.Alpha+1)*math.Log(x) } // Mean returns the mean of the probability distribution. func (p Pareto) Mean() float64 { if p.Alpha <= 1 { return math.Inf(1) } return p.Alpha * p.Xm / (p.Alpha - 1) } // Median returns the median of the pareto distribution. func (p Pareto) Median() float64 { return p.Quantile(0.5) } // Mode returns the mode of the distribution. func (p Pareto) Mode() float64 { return p.Xm } // NumParameters returns the number of parameters in the distribution. func (p Pareto) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (p Pareto) Prob(x float64) float64 { return math.Exp(p.LogProb(x)) } // Quantile returns the inverse of the cumulative probability distribution. func (p Pareto) Quantile(prob float64) float64 { if prob < 0 || 1 < prob { panic(badPercentile) } return p.Xm / math.Pow(1-prob, 1/p.Alpha) } // Rand returns a random sample drawn from the distribution. func (p Pareto) Rand() float64 { var rnd float64 if p.Src == nil { rnd = rand.ExpFloat64() } else { rnd = rand.New(p.Src).ExpFloat64() } return p.Xm * math.Exp(rnd/p.Alpha) } // StdDev returns the standard deviation of the probability distribution. func (p Pareto) StdDev() float64 { return math.Sqrt(p.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (p Pareto) Survival(x float64) float64 { if x < p.Xm { return 1 } return math.Pow(p.Xm/x, p.Alpha) } // Variance returns the variance of the probability distribution. func (p Pareto) Variance() float64 { if p.Alpha <= 2 { return math.Inf(1) } am1 := p.Alpha - 1 return p.Xm * p.Xm * p.Alpha / (am1 * am1 * (p.Alpha - 2)) } golang-gonum-v1-gonum-0.14.0/stat/distuv/pareto_test.go000066400000000000000000000123531450372207100230130ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestParetoProb(t *testing.T) { t.Parallel() for _, test := range []struct { x, xm, alpha, want float64 }{ {0, 1, 1, 0}, {0.5, 1, 1, 0}, {1, 1, 1, 1.0}, {1.5, 1, 1, 0.444444444444444}, {2, 1, 1, 0.25}, {2.5, 1, 1, 0.16}, {3, 1, 1, 0.1111111111111111}, {3.5, 1, 1, 0.081632653061224}, {4, 1, 1, 0.0625}, {4.5, 1, 1, 0.049382716049383}, {5, 1, 1, 0.04}, {0, 1, 2, 0}, {0.5, 1, 2, 0}, {1, 1, 2, 2}, {1.5, 1, 2, 0.592592592592593}, {2, 1, 2, 0.25}, {2.5, 1, 2, 0.128}, {3, 1, 2, 0.074074074074074}, {3.5, 1, 2, 0.046647230320700}, {4, 1, 2, 0.03125}, {4.5, 1, 2, 0.021947873799726}, {5, 1, 2, 0.016}, {0, 1, 3, 0}, {0.5, 1, 3, 0}, {1, 1, 3, 3.0}, {1.5, 1, 3, 0.592592592592593}, {2, 1, 3, 0.1875}, {2.5, 1, 3, 0.0768}, {3, 1, 3, 0.037037037037037}, {3.5, 1, 3, 0.019991670137443}, {4, 1, 3, 0.011718750000000}, {4.5, 1, 3, 0.007315957933242}, {5, 1, 3, 0.0048}, } { pdf := Pareto{test.xm, test.alpha, nil}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Pdf mismatch, x = %v, xm = %v, alpha = %v. Got %v, want %v", test.x, test.xm, test.alpha, pdf, test.want) } } } func TestParetoCDF(t *testing.T) { t.Parallel() for _, test := range []struct { x, xm, alpha, want float64 }{ {0, 1, 1, 0}, {0.5, 1, 1, 0}, {1, 1, 1, 0}, {1.5, 1, 1, 0.333333333333333}, {2, 1, 1, 0.5}, {2.5, 1, 1, 0.6}, {3, 1, 1, 0.666666666666667}, {3.5, 1, 1, 0.714285714285714}, {4, 1, 1, 0.75}, {4.5, 1, 1, 0.777777777777778}, {5, 1, 1, 0.80}, {5.5, 1, 1, 0.818181818181818}, {6, 1, 1, 0.833333333333333}, {6.5, 1, 1, 0.846153846153846}, {7, 1, 1, 0.857142857142857}, {7.5, 1, 1, 0.866666666666667}, {8, 1, 1, 0.875}, {8.5, 1, 1, 0.882352941176471}, {9, 1, 1, 0.888888888888889}, {9.5, 1, 1, 0.894736842105263}, {10, 1, 1, 0.90}, {0, 1, 2, 0}, {0.5, 1, 2, 0}, {1, 1, 2, 0}, {1.5, 1, 2, 0.555555555555556}, {2, 1, 2, 0.75}, {2.5, 1, 2, 0.84}, {3, 1, 2, 0.888888888888889}, {3.5, 1, 2, 0.918367346938776}, {4, 1, 2, 0.9375}, {4.5, 1, 2, 0.950617283950617}, {5, 1, 2, 0.96}, {5.5, 1, 2, 0.966942148760331}, {6, 1, 2, 0.972222222222222}, {6.5, 1, 2, 0.976331360946746}, {7, 1, 2, 0.979591836734694}, {7.5, 1, 2, 0.982222222222222}, {8, 1, 2, 0.984375000000000}, {8.5, 1, 2, 0.986159169550173}, {9, 1, 2, 0.987654320987654}, {9.5, 1, 2, 0.988919667590028}, {10, 1, 2, 0.99}, {0, 1, 3, 0}, {0.5, 1, 3, 0}, {1, 1, 3, 0}, {1.5, 1, 3, 0.703703703703704}, {2, 1, 3, 0.875}, {2.5, 1, 3, 0.936}, {3, 1, 3, 0.962962962962963}, {3.5, 1, 3, 0.976676384839650}, {4, 1, 3, 0.984375000000000}, {4.5, 1, 3, 0.989026063100137}, {5, 1, 3, 0.992}, {5.5, 1, 3, 0.993989481592787}, {6, 1, 3, 0.995370370370370}, {6.5, 1, 3, 0.996358670914884}, {7, 1, 3, 0.997084548104956}, {7.5, 1, 3, 0.997629629629630}, {8, 1, 3, 0.998046875000000}, {8.5, 1, 3, 0.998371667005903}, {9, 1, 3, 0.998628257887517}, {9.5, 1, 3, 0.998833649220003}, {10, 1, 3, 0.999}, } { cdf := Pareto{test.xm, test.alpha, nil}.CDF(test.x) if !scalar.EqualWithinAbsOrRel(cdf, test.want, 1e-10, 1e-10) { t.Errorf("CDF mismatch, x = %v, xm = %v, alpha = %v. Got %v, want %v", test.x, test.xm, test.alpha, cdf, test.want) } } } func TestPareto(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, p := range []Pareto{ {1, 10, src}, {1, 20, src}, } { testPareto(t, p, i) } } func testPareto(t *testing.T, p Pareto, i int) { const ( tol = 1e-2 n = 1e6 bins = 50 ) x := make([]float64, n) generateSamples(x, p) sort.Float64s(x) checkQuantileCDFSurvival(t, i, x, p, 1e-3) testRandLogProbContinuous(t, i, 0, x, p, tol, bins) checkMean(t, i, x, p, tol) checkVarAndStd(t, i, x, p, tol) checkExKurtosis(t, i, x, p, 7e-2) checkProbContinuous(t, i, x, p.Xm, math.Inf(1), p, 1e-10) checkEntropy(t, i, x, p, 1e-2) checkMedian(t, i, x, p, 1e-3) if p.Xm != p.Mode() { t.Errorf("Mismatch in mode value: got %v, want %g", p.Mode(), p.Xm) } if p.NumParameters() != 2 { t.Errorf("Mismatch in NumParameters: got %v, want 2", p.NumParameters()) } surv := p.Survival(p.Xm - 0.0001) if surv != 1 { t.Errorf("Mismatch in Survival below Xm: got %v, want 1", surv) } } func TestParetoNotExists(t *testing.T) { t.Parallel() p := Pareto{0, 4, nil} exKurt := p.ExKurtosis() if !math.IsNaN(exKurt) { t.Errorf("Expected NaN excess kurtosis for Alpha == 4, got %v", exKurt) } p = Pareto{0, 1, nil} mean := p.Mean() if !math.IsInf(mean, 1) { t.Errorf("Expected mean == +Inf for Alpha == 1, got %v", mean) } p = Pareto{0, 2, nil} variance := p.Variance() if !math.IsInf(variance, 1) { t.Errorf("Expected variance == +Inf for Alpha == 1, got %v", variance) } stdDev := p.StdDev() if !math.IsInf(stdDev, 1) { t.Errorf("Expected standard deviation == +Inf for Alpha == 1, got %v", stdDev) } } func BenchmarkParetoRand(b *testing.B) { src := rand.New(rand.NewSource(1)) p := Pareto{1, 1, src} for i := 0; i < b.N; i++ { p.Rand() } } golang-gonum-v1-gonum-0.14.0/stat/distuv/poisson.go000066400000000000000000000067451450372207100221640ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) // Poisson implements the Poisson distribution, a discrete probability distribution // that expresses the probability of a given number of events occurring in a fixed // interval. // The poisson distribution has density function: // // f(k) = λ^k / k! e^(-λ) // // For more information, see https://en.wikipedia.org/wiki/Poisson_distribution. type Poisson struct { // Lambda is the average number of events in an interval. // Lambda must be greater than 0. Lambda float64 Src rand.Source } // CDF computes the value of the cumulative distribution function at x. func (p Poisson) CDF(x float64) float64 { if x < 0 { return 0 } return mathext.GammaIncRegComp(math.Floor(x+1), p.Lambda) } // ExKurtosis returns the excess kurtosis of the distribution. func (p Poisson) ExKurtosis() float64 { return 1 / p.Lambda } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (p Poisson) LogProb(x float64) float64 { if x < 0 || math.Floor(x) != x { return math.Inf(-1) } lg, _ := math.Lgamma(math.Floor(x) + 1) return x*math.Log(p.Lambda) - p.Lambda - lg } // Mean returns the mean of the probability distribution. func (p Poisson) Mean() float64 { return p.Lambda } // NumParameters returns the number of parameters in the distribution. func (Poisson) NumParameters() int { return 1 } // Prob computes the value of the probability density function at x. func (p Poisson) Prob(x float64) float64 { return math.Exp(p.LogProb(x)) } // Rand returns a random sample drawn from the distribution. func (p Poisson) Rand() float64 { // NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5) // p. 294 // rnd := rand.ExpFloat64 var rng *rand.Rand if p.Src != nil { rng = rand.New(p.Src) rnd = rng.ExpFloat64 } if p.Lambda < 10.0 { // Use direct method. var em float64 t := 0.0 for { t += rnd() if t >= p.Lambda { break } em++ } return em } // Generate using: // W. Hörmann. "The transformed rejection method for generating Poisson // random variables." Insurance: Mathematics and Economics // 12.1 (1993): 39-45. // Algorithm PTRS rnd = rand.Float64 if rng != nil { rnd = rng.Float64 } b := 0.931 + 2.53*math.Sqrt(p.Lambda) a := -0.059 + 0.02483*b invalpha := 1.1239 + 1.1328/(b-3.4) vr := 0.9277 - 3.6224/(b-2) for { U := rnd() - 0.5 V := rnd() us := 0.5 - math.Abs(U) k := math.Floor((2*a/us+b)*U + p.Lambda + 0.43) if us >= 0.07 && V <= vr { return k } if k <= 0 || (us < 0.013 && V > us) { continue } lg, _ := math.Lgamma(k + 1) if math.Log(V*invalpha/(a/(us*us)+b)) <= k*math.Log(p.Lambda)-p.Lambda-lg { return k } } } // Skewness returns the skewness of the distribution. func (p Poisson) Skewness() float64 { return 1 / math.Sqrt(p.Lambda) } // StdDev returns the standard deviation of the probability distribution. func (p Poisson) StdDev() float64 { return math.Sqrt(p.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (p Poisson) Survival(x float64) float64 { return 1 - p.CDF(x) } // Variance returns the variance of the probability distribution. func (p Poisson) Variance() float64 { return p.Lambda } golang-gonum-v1-gonum-0.14.0/stat/distuv/poisson_test.go000066400000000000000000000077421450372207100232210ustar00rootroot00000000000000// 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 distuv import ( "fmt" "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestPoissonProb(t *testing.T) { t.Parallel() const tol = 1e-10 for i, tt := range []struct { k float64 lambda float64 want float64 }{ {0, 1, 3.678794411714423e-01}, {1, 1, 3.678794411714423e-01}, {2, 1, 1.839397205857211e-01}, {3, 1, 6.131324019524039e-02}, {4, 1, 1.532831004881010e-02}, {5, 1, 3.065662009762020e-03}, {6, 1, 5.109436682936698e-04}, {7, 1, 7.299195261338139e-05}, {8, 1, 9.123994076672672e-06}, {9, 1, 1.013777119630298e-06}, {0, 2.5, 8.208499862389880e-02}, {1, 2.5, 2.052124965597470e-01}, {2, 2.5, 2.565156206996838e-01}, {3, 2.5, 2.137630172497365e-01}, {4, 2.5, 1.336018857810853e-01}, {5, 2.5, 6.680094289054267e-02}, {6, 2.5, 2.783372620439277e-02}, {7, 2.5, 9.940616501568845e-03}, {8, 2.5, 3.106442656740263e-03}, {9, 2.5, 8.629007379834082e-04}, {0.5, 2.5, 0}, {1.5, 2.5, 0}, {2.5, 2.5, 0}, {3.5, 2.5, 0}, {4.5, 2.5, 0}, {5.5, 2.5, 0}, {6.5, 2.5, 0}, {7.5, 2.5, 0}, {8.5, 2.5, 0}, {9.5, 2.5, 0}, } { p := Poisson{Lambda: tt.lambda} got := p.Prob(tt.k) if !scalar.EqualWithinAbs(got, tt.want, tol) { t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want) } } } func TestPoissonCDF(t *testing.T) { t.Parallel() const tol = 1e-10 for i, tt := range []struct { k float64 lambda float64 want float64 }{ {0, 1, 0.367879441171442}, {1, 1, 0.735758882342885}, {2, 1, 0.919698602928606}, {3, 1, 0.981011843123846}, {4, 1, 0.996340153172656}, {5, 1, 0.999405815182418}, {6, 1, 0.999916758850712}, {7, 1, 0.999989750803325}, {8, 1, 0.999998874797402}, {9, 1, 0.999999888574522}, {0, 2.5, 0.082084998623899}, {1, 2.5, 0.287297495183646}, {2, 2.5, 0.543813115883329}, {3, 2.5, 0.757576133133066}, {4, 2.5, 0.891178018914151}, {5, 2.5, 0.957978961804694}, {6, 2.5, 0.985812688009087}, {7, 2.5, 0.995753304510655}, {8, 2.5, 0.998859747167396}, {9, 2.5, 0.999722647905379}, } { p := Poisson{Lambda: tt.lambda} got := p.CDF(tt.k) if !scalar.EqualWithinAbs(got, tt.want, tol) { t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want) } } } func TestPoisson(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []Poisson{ {100, src}, {15, src}, {10, src}, {9.9, src}, {3, src}, {1.5, src}, {0.9, src}, } { testPoisson(t, b, i) } } func testPoisson(t *testing.T, p Poisson, i int) { const ( tol = 1e-2 n = 2e6 ) x := make([]float64, n) generateSamples(x, p) sort.Float64s(x) checkProbDiscrete(t, i, x, p, 2e-3) checkMean(t, i, x, p, tol) checkVarAndStd(t, i, x, p, tol) checkExKurtosis(t, i, x, p, 7e-2) checkSkewness(t, i, x, p, tol) if p.NumParameters() != 1 { t.Errorf("Mismatch in NumParameters: got %v, want 1", p.NumParameters()) } cdf := p.CDF(-0.0001) if cdf != 0 { t.Errorf("Mismatch in CDF for x < 0: got %v, want 0", cdf) } surv := p.Survival(-0.0001) if surv != 1 { t.Errorf("Mismatch in Survival for x < 0: got %v, want 1", surv) } logProb := p.LogProb(-0.0001) if !math.IsInf(logProb, -1) { t.Errorf("Mismatch in LogProb for x < 0: got %v, want -Inf", logProb) } logProb = p.LogProb(1.5) if !math.IsInf(logProb, -1) { t.Errorf("Mismatch in LogProb for non-integer x: got %v, want -Inf", logProb) } for _, xx := range x { cdf = p.CDF(xx) surv = p.Survival(xx) if math.Abs(cdf+surv-1) > 1e-10 { t.Errorf("Mismatch between CDF and Survival at %g", xx) } } } func BenchmarkPoissonRand(b *testing.B) { src := rand.New(rand.NewSource(1)) for i, p := range []Poisson{ {100, src}, {15, src}, {10, src}, {9.9, src}, {3, src}, {1.5, src}, {0.9, src}, } { b.Run(fmt.Sprintf("case %d", i), func(b *testing.B) { for i := 0; i < b.N; i++ { p.Rand() } }) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/statdist.go000066400000000000000000000114521450372207100223200ustar00rootroot00000000000000// 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 distuv import ( "math" "gonum.org/v1/gonum/mathext" ) // Bhattacharyya is a type for computing the Bhattacharyya distance between // probability distributions. // // The Bhattacharyya distance is defined as // // D_B = -ln(BC(l,r)) // BC = \int_-∞^∞ (p(x)q(x))^(1/2) dx // // Where BC is known as the Bhattacharyya coefficient. // The Bhattacharyya distance is related to the Hellinger distance by // // H(l,r) = sqrt(1-BC(l,r)) // // For more information, see // // https://en.wikipedia.org/wiki/Bhattacharyya_distance type Bhattacharyya struct{} // DistBeta returns the Bhattacharyya distance between Beta distributions l and r. // For Beta distributions, the Bhattacharyya distance is given by // // -ln(B((α_l + α_r)/2, (β_l + β_r)/2) / (B(α_l,β_l), B(α_r,β_r))) // // Where B is the Beta function. func (Bhattacharyya) DistBeta(l, r Beta) float64 { // Reference: https://en.wikipedia.org/wiki/Hellinger_distance#Examples return -mathext.Lbeta((l.Alpha+r.Alpha)/2, (l.Beta+r.Beta)/2) + 0.5*mathext.Lbeta(l.Alpha, l.Beta) + 0.5*mathext.Lbeta(r.Alpha, r.Beta) } // DistNormal returns the Bhattacharyya distance Normal distributions l and r. // For Normal distributions, the Bhattacharyya distance is given by // // s = (σ_l^2 + σ_r^2)/2 // BC = 1/8 (μ_l-μ_r)^2/s + 1/2 ln(s/(σ_l*σ_r)) func (Bhattacharyya) DistNormal(l, r Normal) float64 { // Reference: https://en.wikipedia.org/wiki/Bhattacharyya_distance m := l.Mu - r.Mu s := (l.Sigma*l.Sigma + r.Sigma*r.Sigma) / 2 return 0.125*m*m/s + 0.5*math.Log(s) - 0.5*math.Log(l.Sigma) - 0.5*math.Log(r.Sigma) } // Hellinger is a type for computing the Hellinger distance between probability // distributions. // // The Hellinger distance is defined as // // H^2(l,r) = 1/2 * int_x (\sqrt(l(x)) - \sqrt(r(x)))^2 dx // // and is bounded between 0 and 1. Note the above formula defines the squared // Hellinger distance, while this returns the Hellinger distance itself. // The Hellinger distance is related to the Bhattacharyya distance by // // H^2 = 1 - exp(-D_B) // // For more information, see // // https://en.wikipedia.org/wiki/Hellinger_distance type Hellinger struct{} // DistBeta computes the Hellinger distance between Beta distributions l and r. // See the documentation of Bhattacharyya.DistBeta for the distance formula. func (Hellinger) DistBeta(l, r Beta) float64 { db := Bhattacharyya{}.DistBeta(l, r) return math.Sqrt(-math.Expm1(-db)) } // DistNormal computes the Hellinger distance between Normal distributions l and r. // See the documentation of Bhattacharyya.DistNormal for the distance formula. func (Hellinger) DistNormal(l, r Normal) float64 { db := Bhattacharyya{}.DistNormal(l, r) return math.Sqrt(-math.Expm1(-db)) } // KullbackLeibler is a type for computing the Kullback-Leibler divergence from l to r. // // The Kullback-Leibler divergence is defined as // // D_KL(l || r ) = \int_x p(x) log(p(x)/q(x)) dx // // Note that the Kullback-Leibler divergence is not symmetric with respect to // the order of the input arguments. type KullbackLeibler struct{} // DistBeta returns the Kullback-Leibler divergence between Beta distributions // l and r. // // For two Beta distributions, the KL divergence is computed as // // D_KL(l || r) = log Γ(α_l+β_l) - log Γ(α_l) - log Γ(β_l) // - log Γ(α_r+β_r) + log Γ(α_r) + log Γ(β_r) // + (α_l-α_r)(ψ(α_l)-ψ(α_l+β_l)) + (β_l-β_r)(ψ(β_l)-ψ(α_l+β_l)) // // Where Γ is the gamma function and ψ is the digamma function. func (KullbackLeibler) DistBeta(l, r Beta) float64 { // http://bariskurt.com/kullback-leibler-divergence-between-two-dirichlet-and-beta-distributions/ if l.Alpha <= 0 || l.Beta <= 0 { panic("distuv: bad parameters for left distribution") } if r.Alpha <= 0 || r.Beta <= 0 { panic("distuv: bad parameters for right distribution") } lab := l.Alpha + l.Beta l1, _ := math.Lgamma(lab) l2, _ := math.Lgamma(l.Alpha) l3, _ := math.Lgamma(l.Beta) lt := l1 - l2 - l3 r1, _ := math.Lgamma(r.Alpha + r.Beta) r2, _ := math.Lgamma(r.Alpha) r3, _ := math.Lgamma(r.Beta) rt := r1 - r2 - r3 d0 := mathext.Digamma(l.Alpha + l.Beta) ct := (l.Alpha-r.Alpha)*(mathext.Digamma(l.Alpha)-d0) + (l.Beta-r.Beta)*(mathext.Digamma(l.Beta)-d0) return lt - rt + ct } // DistNormal returns the Kullback-Leibler divergence between Normal distributions // l and r. // // For two Normal distributions, the KL divergence is computed as // // D_KL(l || r) = log(σ_r / σ_l) + (σ_l^2 + (μ_l-μ_r)^2)/(2 * σ_r^2) - 0.5 func (KullbackLeibler) DistNormal(l, r Normal) float64 { d := l.Mu - r.Mu v := (l.Sigma*l.Sigma + d*d) / (2 * r.Sigma * r.Sigma) return math.Log(r.Sigma) - math.Log(l.Sigma) + v - 0.5 } golang-gonum-v1-gonum-0.14.0/stat/distuv/statdist_test.go000066400000000000000000000157411450372207100233640ustar00rootroot00000000000000// 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 distuv import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestBhattacharyyaBeta(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { a, b Beta samples int tol float64 }{ { a: Beta{Alpha: 1, Beta: 2, Src: rnd}, b: Beta{Alpha: 1, Beta: 4, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Beta{Alpha: 0.5, Beta: 0.4, Src: rnd}, b: Beta{Alpha: 0.7, Beta: 0.2, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Beta{Alpha: 3, Beta: 5, Src: rnd}, b: Beta{Alpha: 5, Beta: 3, Src: rnd}, samples: 100000, tol: 1e-2, }, } { want := bhattacharyyaSample(test.samples, test.a, test.b) got := Bhattacharyya{}.DistBeta(test.a, test.b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Bhattacharyya mismatch, case %d: got %v, want %v", cas, got, want) } // Bhattacharyya should be symmetric got2 := Bhattacharyya{}.DistBeta(test.b, test.a) if math.Abs(got-got2) > 1e-14 { t.Errorf("Bhattacharyya distance not symmetric") } } } func TestBhattacharyyaNormal(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { a, b Normal samples int tol float64 }{ { a: Normal{Mu: 1, Sigma: 2, Src: rnd}, b: Normal{Mu: 1, Sigma: 4, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Normal{Mu: 0, Sigma: 2, Src: rnd}, b: Normal{Mu: 2, Sigma: 2, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Normal{Mu: 0, Sigma: 5, Src: rnd}, b: Normal{Mu: 2, Sigma: 0.1, Src: rnd}, samples: 200000, tol: 1e-2, }, } { want := bhattacharyyaSample(test.samples, test.a, test.b) got := Bhattacharyya{}.DistNormal(test.a, test.b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Bhattacharyya mismatch, case %d: got %v, want %v", cas, got, want) } // Bhattacharyya should be symmetric got2 := Bhattacharyya{}.DistNormal(test.b, test.a) if math.Abs(got-got2) > 1e-14 { t.Errorf("Bhattacharyya distance not symmetric") } } } // bhattacharyyaSample finds an estimate of the Bhattacharyya coefficient through // sampling. func bhattacharyyaSample(samples int, l RandLogProber, r LogProber) float64 { lBhatt := make([]float64, samples) for i := 0; i < samples; i++ { // Do importance sampling over a: \int sqrt(a*b)/a * a dx x := l.Rand() pa := l.LogProb(x) pb := r.LogProb(x) lBhatt[i] = 0.5*pb - 0.5*pa } logBc := floats.LogSumExp(lBhatt) - math.Log(float64(samples)) return -logBc } func TestKullbackLeiblerBeta(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { a, b Beta samples int tol float64 }{ { a: Beta{Alpha: 1, Beta: 2, Src: rnd}, b: Beta{Alpha: 1, Beta: 4, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Beta{Alpha: 0.5, Beta: 0.4, Src: rnd}, b: Beta{Alpha: 0.7, Beta: 0.2, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Beta{Alpha: 3, Beta: 5, Src: rnd}, b: Beta{Alpha: 5, Beta: 3, Src: rnd}, samples: 100000, tol: 1e-2, }, } { a, b := test.a, test.b want := klSample(test.samples, a, b) got := KullbackLeibler{}.DistBeta(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Kullback-Leibler mismatch, case %d: got %v, want %v", cas, got, want) } } good := Beta{0.5, 0.5, nil} bad := Beta{0, 1, nil} if !panics(func() { KullbackLeibler{}.DistBeta(bad, good) }) { t.Errorf("Expected Kullback-Leibler to panic when called with invalid left Beta distribution") } if !panics(func() { KullbackLeibler{}.DistBeta(good, bad) }) { t.Errorf("Expected Kullback-Leibler to panic when called with invalid right Beta distribution") } bad = Beta{1, 0, nil} if !panics(func() { KullbackLeibler{}.DistBeta(bad, good) }) { t.Errorf("Expected Kullback-Leibler to panic when called with invalid left Beta distribution") } if !panics(func() { KullbackLeibler{}.DistBeta(good, bad) }) { t.Errorf("Expected Kullback-Leibler to panic when called with invalid right Beta distribution") } } func TestKullbackLeiblerNormal(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) for cas, test := range []struct { a, b Normal samples int tol float64 }{ { a: Normal{Mu: 1, Sigma: 2, Src: rnd}, b: Normal{Mu: 1, Sigma: 4, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Normal{Mu: 0, Sigma: 2, Src: rnd}, b: Normal{Mu: 2, Sigma: 2, Src: rnd}, samples: 100000, tol: 1e-2, }, { a: Normal{Mu: 0, Sigma: 5, Src: rnd}, b: Normal{Mu: 2, Sigma: 0.1, Src: rnd}, samples: 100000, tol: 1e-2, }, } { a, b := test.a, test.b want := klSample(test.samples, a, b) got := KullbackLeibler{}.DistNormal(a, b) if !scalar.EqualWithinAbsOrRel(want, got, test.tol, test.tol) { t.Errorf("Kullback-Leibler mismatch, case %d: got %v, want %v", cas, got, want) } } } // klSample finds an estimate of the Kullback-Leibler divergence through sampling. func klSample(samples int, l RandLogProber, r LogProber) float64 { var klmc float64 for i := 0; i < samples; i++ { x := l.Rand() pa := l.LogProb(x) pb := r.LogProb(x) klmc += pa - pb } return klmc / float64(samples) } func TestHellingerBeta(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) const tol = 1e-15 for cas, test := range []struct { a, b Beta }{ { a: Beta{Alpha: 1, Beta: 2, Src: rnd}, b: Beta{Alpha: 1, Beta: 4, Src: rnd}, }, { a: Beta{Alpha: 0.5, Beta: 0.4, Src: rnd}, b: Beta{Alpha: 0.7, Beta: 0.2, Src: rnd}, }, { a: Beta{Alpha: 3, Beta: 5, Src: rnd}, b: Beta{Alpha: 5, Beta: 3, Src: rnd}, }, } { got := Hellinger{}.DistBeta(test.a, test.b) want := math.Sqrt(1 - math.Exp(-Bhattacharyya{}.DistBeta(test.a, test.b))) if !scalar.EqualWithinAbsOrRel(got, want, tol, tol) { t.Errorf("Hellinger mismatch, case %d: got %v, want %v", cas, got, want) } } } func TestHellingerNormal(t *testing.T) { t.Parallel() rnd := rand.New(rand.NewSource(1)) const tol = 1e-15 for cas, test := range []struct { a, b Normal }{ { a: Normal{Mu: 1, Sigma: 2, Src: rnd}, b: Normal{Mu: 1, Sigma: 4, Src: rnd}, }, { a: Normal{Mu: 0, Sigma: 2, Src: rnd}, b: Normal{Mu: 2, Sigma: 2, Src: rnd}, }, { a: Normal{Mu: 0, Sigma: 5, Src: rnd}, b: Normal{Mu: 2, Sigma: 0.1, Src: rnd}, }, } { got := Hellinger{}.DistNormal(test.a, test.b) want := math.Sqrt(1 - math.Exp(-Bhattacharyya{}.DistNormal(test.a, test.b))) if !scalar.EqualWithinAbsOrRel(got, want, tol, tol) { t.Errorf("Hellinger mismatch, case %d: got %v, want %v", cas, got, want) } } } golang-gonum-v1-gonum-0.14.0/stat/distuv/studentst.go000066400000000000000000000107201450372207100225130ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mathext" ) const logPi = 1.1447298858494001741 // http://oeis.org/A053510 // StudentsT implements the three-parameter Student's T distribution, a distribution // over the real numbers. // // The Student's T distribution has density function // // Γ((ν+1)/2) / (sqrt(νπ) Γ(ν/2) σ) (1 + 1/ν * ((x-μ)/σ)^2)^(-(ν+1)/2) // // The Student's T distribution approaches the normal distribution as ν → ∞. // // For more information, see https://en.wikipedia.org/wiki/Student%27s_t-distribution, // specifically https://en.wikipedia.org/wiki/Student%27s_t-distribution#Non-standardized_Student.27s_t-distribution . // // The standard Student's T distribution is with Mu = 0, and Sigma = 1. type StudentsT struct { // Mu is the location parameter of the distribution, and the mean of the // distribution Mu float64 // Sigma is the scale parameter of the distribution. It is related to the // standard deviation by std = Sigma * sqrt(Nu/(Nu-2)) Sigma float64 // Nu is the shape parameter of the distribution, representing the number of // degrees of the distribution, and one less than the number of observations // from a Normal distribution. Nu float64 Src rand.Source } // CDF computes the value of the cumulative distribution function at x. func (s StudentsT) CDF(x float64) float64 { // transform to standard normal y := (x - s.Mu) / s.Sigma if y == 0 { return 0.5 } // For t > 0 // F(y) = 1 - 0.5 * I_t(y)(nu/2, 1/2) // t(y) = nu/(y^2 + nu) // and 1 - F(y) for t < 0 t := s.Nu / (y*y + s.Nu) if y > 0 { return 1 - 0.5*mathext.RegIncBeta(0.5*s.Nu, 0.5, t) } return 0.5 * mathext.RegIncBeta(s.Nu/2, 0.5, t) } // LogProb computes the natural logarithm of the value of the probability // density function at x. func (s StudentsT) LogProb(x float64) float64 { g1, _ := math.Lgamma((s.Nu + 1) / 2) g2, _ := math.Lgamma(s.Nu / 2) z := (x - s.Mu) / s.Sigma return g1 - g2 - 0.5*math.Log(s.Nu) - 0.5*logPi - math.Log(s.Sigma) - ((s.Nu+1)/2)*math.Log(1+z*z/s.Nu) } // Mean returns the mean of the probability distribution. func (s StudentsT) Mean() float64 { return s.Mu } // Mode returns the mode of the distribution. func (s StudentsT) Mode() float64 { return s.Mu } // NumParameters returns the number of parameters in the distribution. func (StudentsT) NumParameters() int { return 3 } // Prob computes the value of the probability density function at x. func (s StudentsT) Prob(x float64) float64 { return math.Exp(s.LogProb(x)) } // Quantile returns the inverse of the cumulative distribution function. func (s StudentsT) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } // F(x) = 1 - 0.5 * I_t(x)(nu/2, 1/2) // t(x) = nu/(t^2 + nu) if p == 0.5 { return s.Mu } var y float64 if p > 0.5 { // Know t > 0 t := mathext.InvRegIncBeta(s.Nu/2, 0.5, 2*(1-p)) y = math.Sqrt(s.Nu * (1 - t) / t) } else { t := mathext.InvRegIncBeta(s.Nu/2, 0.5, 2*p) y = -math.Sqrt(s.Nu * (1 - t) / t) } // Convert out of standard normal return y*s.Sigma + s.Mu } // Rand returns a random sample drawn from the distribution. func (s StudentsT) Rand() float64 { // http://www.math.uah.edu/stat/special/Student.html n := Normal{0, 1, s.Src}.Rand() c := Gamma{s.Nu / 2, 0.5, s.Src}.Rand() z := n / math.Sqrt(c/s.Nu) return z*s.Sigma + s.Mu } // StdDev returns the standard deviation of the probability distribution. // // The standard deviation is undefined for ν <= 1, and this returns math.NaN(). func (s StudentsT) StdDev() float64 { return math.Sqrt(s.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (s StudentsT) Survival(x float64) float64 { // transform to standard normal y := (x - s.Mu) / s.Sigma if y == 0 { return 0.5 } // For t > 0 // F(y) = 1 - 0.5 * I_t(y)(nu/2, 1/2) // t(y) = nu/(y^2 + nu) // and 1 - F(y) for t < 0 t := s.Nu / (y*y + s.Nu) if y > 0 { return 0.5 * mathext.RegIncBeta(s.Nu/2, 0.5, t) } return 1 - 0.5*mathext.RegIncBeta(s.Nu/2, 0.5, t) } // Variance returns the variance of the probability distribution. // // The variance is undefined for ν <= 1, and this returns math.NaN(). func (s StudentsT) Variance() float64 { if s.Nu <= 1 { return math.NaN() } if s.Nu <= 2 { return math.Inf(1) } return s.Sigma * s.Sigma * s.Nu / (s.Nu - 2) } golang-gonum-v1-gonum-0.14.0/stat/distuv/studentst_test.go000066400000000000000000000052231450372207100235540ustar00rootroot00000000000000// Copyright ©2016 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func TestStudentsTProb(t *testing.T) { t.Parallel() for _, test := range []struct { x, mu, sigma, nu, want float64 }{ // Values comparison with scipy. {0.01, 0, 1, 2.74, 0.364778548181318}, {-0.01, 0, 1, 2.74, 0.364778548181318}, {0.4, 0, 1, 1.6, 0.30376391362582678}, {-0.4, 0, 1, 1.6, 0.30376391362582678}, {0.2, 15, 5, 10, 0.0024440848858034393}, } { pdf := StudentsT{test.mu, test.sigma, test.nu, nil}.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { t.Errorf("Pdf mismatch, x = %v, Nu = %v. Got %v, want %v", test.x, test.nu, pdf, test.want) } } } func TestStudentsT(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []StudentsT{ {0, 1, 3.3, src}, {0, 1, 7.2, src}, {0, 1, 12, src}, {0.9, 0.8, 6, src}, } { testStudentsT(t, b, i) } } func testStudentsT(t *testing.T, c StudentsT, i int) { const ( tol = 1e-2 n = 3e5 bins = 50 ) x := make([]float64, n) generateSamples(x, c) sort.Float64s(x) testRandLogProbContinuous(t, i, math.Inf(-1), x, c, tol, bins) checkMean(t, i, x, c, tol) if c.Nu > 2 { checkVarAndStd(t, i, x, c, 5e-2) } checkProbContinuous(t, i, x, math.Inf(-1), math.Inf(1), c, 1e-10) checkQuantileCDFSurvival(t, i, x, c, tol) checkProbQuantContinuous(t, i, x, c, tol) if c.Mu != c.Mode() { t.Errorf("Mismatch in mode value: got %v, want %g", c.Mode(), c.Mu) } if c.NumParameters() != 3 { t.Errorf("Mismatch in NumParameters: got %v, want 3", c.NumParameters()) } } func TestStudentsTQuantile(t *testing.T) { t.Parallel() nSteps := 101 probs := make([]float64, nSteps) floats.Span(probs, 0, 1) for i, b := range []StudentsT{ {0, 1, 3.3, nil}, {0, 1, 7.2, nil}, {0, 1, 12, nil}, {0.9, 0.8, 6, nil}, } { for _, p := range probs { x := b.Quantile(p) p2 := b.CDF(x) if !scalar.EqualWithinAbsOrRel(p, p2, 1e-10, 1e-10) { t.Errorf("mismatch between CDF and Quantile. Case %v. Want %v, got %v", i, p, p2) break } } } } func TestStudentsVarianceSpecial(t *testing.T) { t.Parallel() dist := StudentsT{0, 1, 1, nil} variance := dist.Variance() if !math.IsNaN(variance) { t.Errorf("Expected NaN variance for Nu <= 1, got %v", variance) } dist = StudentsT{0, 1, 2, nil} variance = dist.Variance() if !math.IsInf(variance, 1) { t.Errorf("Expected +Inf variance for 1 < Nu <= 2, got %v", variance) } } golang-gonum-v1-gonum-0.14.0/stat/distuv/triangle.go000066400000000000000000000157411450372207100222730ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" ) // Triangle represents a triangle distribution (https://en.wikipedia.org/wiki/Triangular_distribution). type Triangle struct { a, b, c float64 src rand.Source } // NewTriangle constructs a new triangle distribution with lower limit a, upper limit b, and mode c. // Constraints are a < b and a ≤ c ≤ b. // This distribution is uncommon in nature, but may be useful for simulation. func NewTriangle(a, b, c float64, src rand.Source) Triangle { checkTriangleParameters(a, b, c) return Triangle{a: a, b: b, c: c, src: src} } func checkTriangleParameters(a, b, c float64) { if a >= b { panic("triangle: constraint of a < b violated") } if a > c { panic("triangle: constraint of a <= c violated") } if c > b { panic("triangle: constraint of c <= b violated") } } // CDF computes the value of the cumulative density function at x. func (t Triangle) CDF(x float64) float64 { switch { case x <= t.a: return 0 case x <= t.c: d := x - t.a return (d * d) / ((t.b - t.a) * (t.c - t.a)) case x < t.b: d := t.b - x return 1 - (d*d)/((t.b-t.a)*(t.b-t.c)) default: return 1 } } // Entropy returns the entropy of the distribution. func (t Triangle) Entropy() float64 { return 0.5 + math.Log(t.b-t.a) - math.Ln2 } // ExKurtosis returns the excess kurtosis of the distribution. func (Triangle) ExKurtosis() float64 { return -3.0 / 5.0 } // Fit is not appropriate for Triangle, because the distribution is generally used when there is little data. // LogProb computes the natural logarithm of the value of the probability density function at x. func (t Triangle) LogProb(x float64) float64 { return math.Log(t.Prob(x)) } // Mean returns the mean of the probability distribution. func (t Triangle) Mean() float64 { return (t.a + t.b + t.c) / 3 } // Median returns the median of the probability distribution. func (t Triangle) Median() float64 { if t.c >= (t.a+t.b)/2 { return t.a + math.Sqrt((t.b-t.a)*(t.c-t.a)/2) } return t.b - math.Sqrt((t.b-t.a)*(t.b-t.c)/2) } // Mode returns the mode of the probability distribution. func (t Triangle) Mode() float64 { return t.c } // NumParameters returns the number of parameters in the distribution. func (Triangle) NumParameters() int { return 3 } // Prob computes the value of the probability density function at x. func (t Triangle) Prob(x float64) float64 { switch { case x < t.a: return 0 case x < t.c: return 2 * (x - t.a) / ((t.b - t.a) * (t.c - t.a)) case x == t.c: return 2 / (t.b - t.a) case x <= t.b: return 2 * (t.b - x) / ((t.b - t.a) * (t.b - t.c)) default: return 0 } } // Quantile returns the inverse of the cumulative probability distribution. func (t Triangle) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } f := (t.c - t.a) / (t.b - t.a) if p < f { return t.a + math.Sqrt(p*(t.b-t.a)*(t.c-t.a)) } return t.b - math.Sqrt((1-p)*(t.b-t.a)*(t.b-t.c)) } // Rand returns a random sample drawn from the distribution. func (t Triangle) Rand() float64 { var rnd float64 if t.src == nil { rnd = rand.Float64() } else { rnd = rand.New(t.src).Float64() } return t.Quantile(rnd) } // Score returns the score function with respect to the parameters of the // distribution at the input location x. The score function is the derivative // of the log-likelihood at x with respect to the parameters // // (∂/∂θ) log(p(x;θ)) // // If deriv is non-nil, len(deriv) must equal the number of parameters otherwise // Score will panic, and the derivative is stored in-place into deriv. If deriv // is nil a new slice will be allocated and returned. // // The order is [∂LogProb / ∂Mu, ∂LogProb / ∂Sigma]. // // For more information, see https://en.wikipedia.org/wiki/Score_%28statistics%29. func (t Triangle) Score(deriv []float64, x float64) []float64 { if deriv == nil { deriv = make([]float64, t.NumParameters()) } if len(deriv) != t.NumParameters() { panic(badLength) } if (x < t.a) || (x > t.b) { deriv[0] = math.NaN() deriv[1] = math.NaN() deriv[2] = math.NaN() } else { invBA := 1 / (t.b - t.a) invCA := 1 / (t.c - t.a) invBC := 1 / (t.b - t.c) switch { case x < t.c: deriv[0] = -1/(x-t.a) + invBA + invCA deriv[1] = -invBA deriv[2] = -invCA case x > t.c: deriv[0] = invBA deriv[1] = 1/(t.b-x) - invBA - invBC deriv[2] = invBC default: deriv[0] = invBA deriv[1] = -invBA deriv[2] = 0 } switch { case x == t.a: deriv[0] = math.NaN() case x == t.b: deriv[1] = math.NaN() case x == t.c: deriv[2] = math.NaN() } switch { case t.a == t.c: deriv[0] = math.NaN() deriv[2] = math.NaN() case t.b == t.c: deriv[1] = math.NaN() deriv[2] = math.NaN() } } return deriv } // ScoreInput returns the score function with respect to the input of the // distribution at the input location specified by x. The score function is the // derivative of the log-likelihood // // (d/dx) log(p(x)) . // // Special cases (c is the mode of the distribution): // // ScoreInput(c) = NaN // ScoreInput(x) = NaN for x not in (a, b) func (t Triangle) ScoreInput(x float64) float64 { if (x <= t.a) || (x >= t.b) || (x == t.c) { return math.NaN() } if x < t.c { return 1 / (x - t.a) } return 1 / (x - t.b) } // Skewness returns the skewness of the distribution. func (t Triangle) Skewness() float64 { n := math.Sqrt2 * (t.a + t.b - 2*t.c) * (2*t.a - t.b - t.c) * (t.a - 2*t.b + t.c) d := 5 * math.Pow(t.a*t.a+t.b*t.b+t.c*t.c-t.a*t.b-t.a*t.c-t.b*t.c, 3.0/2.0) return n / d } // StdDev returns the standard deviation of the probability distribution. func (t Triangle) StdDev() float64 { return math.Sqrt(t.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (t Triangle) Survival(x float64) float64 { return 1 - t.CDF(x) } // parameters returns the parameters of the distribution. func (t Triangle) parameters(p []Parameter) []Parameter { nParam := t.NumParameters() if p == nil { p = make([]Parameter, nParam) } else if len(p) != nParam { panic("triangle: improper parameter length") } p[0].Name = "A" p[0].Value = t.a p[1].Name = "B" p[1].Value = t.b p[2].Name = "C" p[2].Value = t.c return p } // setParameters modifies the parameters of the distribution. func (t *Triangle) setParameters(p []Parameter) { if len(p) != t.NumParameters() { panic("triangle: incorrect number of parameters to set") } if p[0].Name != "A" { panic("triangle: " + panicNameMismatch) } if p[1].Name != "B" { panic("triangle: " + panicNameMismatch) } if p[2].Name != "C" { panic("triangle: " + panicNameMismatch) } checkTriangleParameters(p[0].Value, p[1].Value, p[2].Value) t.a = p[0].Value t.b = p[1].Value t.c = p[2].Value } // Variance returns the variance of the probability distribution. func (t Triangle) Variance() float64 { return (t.a*t.a + t.b*t.b + t.c*t.c - t.a*t.b - t.a*t.c - t.b*t.c) / 18 } golang-gonum-v1-gonum-0.14.0/stat/distuv/triangle_test.go000066400000000000000000000117611450372207100233300ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" ) func TestTriangleConstraint(t *testing.T) { t.Parallel() for _, test := range []struct{ a, b, c float64 }{ {a: 1, b: 1, c: 1}, {a: 1, b: 1, c: 0}, {a: 1, b: 2, c: 3}, {a: 1, b: 2, c: 0}, } { if !panics(func() { NewTriangle(test.a, test.b, test.c, nil) }) { t.Errorf("expected panic for NewTriangle(%f, %f, %f, nil)", test.a, test.b, test.c) } } } func TestTriangle(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, test := range []struct { a, b, c float64 }{ { a: 0.0, b: 1.0, c: 0.5, }, { a: 0.1, b: 0.3, c: 0.2, }, { a: 1.0, b: 2.0, c: 1.5, }, { a: 0.0, b: 1.0, c: 0.0, }, { a: 0.0, b: 1.2, c: 1.2, }, } { f := NewTriangle(test.a, test.b, test.c, src) const ( tol = 1e-2 n = 1e6 ) x := make([]float64, n) generateSamples(x, f) sort.Float64s(x) checkMean(t, i, x, f, tol) checkVarAndStd(t, i, x, f, tol) checkEntropy(t, i, x, f, tol) checkExKurtosis(t, i, x, f, tol) checkSkewness(t, i, x, f, 5e-2) checkMedian(t, i, x, f, tol) checkQuantileCDFSurvival(t, i, x, f, tol) checkProbContinuous(t, i, x, f.a, f.b, f, 1e-10) checkProbQuantContinuous(t, i, x, f, tol) if f.c != f.Mode() { t.Errorf("Mismatch in mode value: got %v, want %g", f.Mode(), f.c) } } } func TestTriangleProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0.5, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 2, prob: 1.0, cumProb: 0.5, logProb: 0, }, { loc: 3, prob: 0, cumProb: 1, logProb: math.Inf(-1), }, { loc: 3.5, prob: 0, cumProb: 1, logProb: math.Inf(-1), }, } testDistributionProbs(t, NewTriangle(1, 3, 2, nil), "Standard 1,2,3 Triangle", pts) } func TestTriangleScore(t *testing.T) { const ( h = 1e-6 tol = 1e-6 ) t.Parallel() f := Triangle{a: -0.5, b: 0.7, c: 0.1} testDerivParam(t, &f) f = Triangle{a: 0, b: 1, c: 0} x := 0.5 score := f.Score(nil, x) if !math.IsNaN(score[0]) { t.Errorf("Expected score over A to be NaN for A == C, got %v", score[0]) } if !math.IsNaN(score[2]) { t.Errorf("Expected score over C to be NaN for A == C, got %v", score[2]) } expectedScore := logProbDerivative(f, x, 1, h) if math.Abs(expectedScore-score[1]) > tol { t.Errorf("Mismatch in score over B for A == C: want %g, got %v", expectedScore, score[1]) } f = Triangle{a: 0, b: 1, c: 1} score = f.Score(nil, x) if !math.IsNaN(score[1]) { t.Errorf("Expected score over B to be NaN for B == C, got %v", score[1]) } if !math.IsNaN(score[2]) { t.Errorf("Expected score over C to be NaN for B == C, got %v", score[2]) } expectedScore = logProbDerivative(f, x, 0, h) if math.Abs(expectedScore-score[0]) > tol { t.Errorf("Mismatch in score over A for B == C: want %g, got %v", expectedScore, score[0]) } f = Triangle{a: 0, b: 1, c: 0.5} score = f.Score(nil, f.a-0.01) if !math.IsNaN(score[0]) { t.Errorf("Expected score over B to be NaN for x < A, got %v", score[0]) } if !math.IsNaN(score[1]) { t.Errorf("Expected score over B to be NaN for x < A, got %v", score[1]) } if !math.IsNaN(score[2]) { t.Errorf("Expected score over C to be NaN for x < A, got %v", score[2]) } score = f.Score(nil, f.b+0.01) if !math.IsNaN(score[0]) { t.Errorf("Expected score over B to be NaN for x > B, got %v", score[0]) } if !math.IsNaN(score[1]) { t.Errorf("Expected score over B to be NaN for x > B, got %v", score[1]) } if !math.IsNaN(score[2]) { t.Errorf("Expected score over C to be NaN for x > B, got %v", score[2]) } score = f.Score(nil, f.a) if !math.IsNaN(score[0]) { t.Errorf("Expected score over C to be NaN for x == A, got %v", score[0]) } score = f.Score(nil, f.b) if !math.IsNaN(score[1]) { t.Errorf("Expected score over C to be NaN for x == B, got %v", score[1]) } score = f.Score(nil, f.c) if !math.IsNaN(score[2]) { t.Errorf("Expected score over C to be NaN for x == C, got %v", score[2]) } } func logProbDerivative(t Triangle, x float64, i int, h float64) float64 { origParams := t.parameters(nil) params := make([]Parameter, len(origParams)) copy(params, origParams) params[i].Value = origParams[i].Value + h t.setParameters(params) lpUp := t.LogProb(x) params[i].Value = origParams[i].Value - h t.setParameters(params) lpDown := t.LogProb(x) t.setParameters(origParams) return (lpUp - lpDown) / (2 * h) } func TestTriangleScoreInput(t *testing.T) { t.Parallel() f := Triangle{a: -0.5, b: 0.7, c: 0.1} xs := []float64{f.a, f.b, f.c, f.a - 0.0001, f.b + 0.0001} for _, x := range xs { scoreInput := f.ScoreInput(x) if !math.IsNaN(scoreInput) { t.Errorf("Expected NaN input score for x == %g, got %v", x, scoreInput) } } } golang-gonum-v1-gonum-0.14.0/stat/distuv/uniform.go000066400000000000000000000123331450372207100221370ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" ) // UnitUniform is an instantiation of the uniform distribution with Min = 0 // and Max = 1. var UnitUniform = Uniform{Min: 0, Max: 1} // Uniform represents a continuous uniform distribution (https://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29). type Uniform struct { Min float64 Max float64 Src rand.Source } // CDF computes the value of the cumulative density function at x. func (u Uniform) CDF(x float64) float64 { if x < u.Min { return 0 } if x > u.Max { return 1 } return (x - u.Min) / (u.Max - u.Min) } // Uniform doesn't have any of the DLogProbD? because the derivative is 0 everywhere // except where it's undefined // Entropy returns the entropy of the distribution. func (u Uniform) Entropy() float64 { return math.Log(u.Max - u.Min) } // ExKurtosis returns the excess kurtosis of the distribution. func (Uniform) ExKurtosis() float64 { return -6.0 / 5.0 } // Uniform doesn't have Fit because it's a bad idea to fit a uniform from data. // LogProb computes the natural logarithm of the value of the probability density function at x. func (u Uniform) LogProb(x float64) float64 { if x < u.Min { return math.Inf(-1) } if x > u.Max { return math.Inf(-1) } return -math.Log(u.Max - u.Min) } // parameters returns the parameters of the distribution. func (u Uniform) parameters(p []Parameter) []Parameter { nParam := u.NumParameters() if p == nil { p = make([]Parameter, nParam) } else if len(p) != nParam { panic("uniform: improper parameter length") } p[0].Name = "Min" p[0].Value = u.Min p[1].Name = "Max" p[1].Value = u.Max return p } // Mean returns the mean of the probability distribution. func (u Uniform) Mean() float64 { return (u.Max + u.Min) / 2 } // Median returns the median of the probability distribution. func (u Uniform) Median() float64 { return (u.Max + u.Min) / 2 } // Uniform doesn't have a mode because it's any value in the distribution // NumParameters returns the number of parameters in the distribution. func (Uniform) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (u Uniform) Prob(x float64) float64 { if x < u.Min { return 0 } if x > u.Max { return 0 } return 1 / (u.Max - u.Min) } // Quantile returns the inverse of the cumulative probability distribution. func (u Uniform) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } return p*(u.Max-u.Min) + u.Min } // Rand returns a random sample drawn from the distribution. func (u Uniform) Rand() float64 { var rnd float64 if u.Src == nil { rnd = rand.Float64() } else { rnd = rand.New(u.Src).Float64() } return rnd*(u.Max-u.Min) + u.Min } // Score returns the score function with respect to the parameters of the // distribution at the input location x. The score function is the derivative // of the log-likelihood at x with respect to the parameters // // (∂/∂θ) log(p(x;θ)) // // If deriv is non-nil, len(deriv) must equal the number of parameters otherwise // Score will panic, and the derivative is stored in-place into deriv. If deriv // is nil a new slice will be allocated and returned. // // The order is [∂LogProb / ∂Mu, ∂LogProb / ∂Sigma]. // // For more information, see https://en.wikipedia.org/wiki/Score_%28statistics%29. func (u Uniform) Score(deriv []float64, x float64) []float64 { if deriv == nil { deriv = make([]float64, u.NumParameters()) } if len(deriv) != u.NumParameters() { panic(badLength) } if (x < u.Min) || (x > u.Max) { deriv[0] = math.NaN() deriv[1] = math.NaN() } else { deriv[0] = 1 / (u.Max - u.Min) deriv[1] = -deriv[0] if x == u.Min { deriv[0] = math.NaN() } if x == u.Max { deriv[1] = math.NaN() } } return deriv } // ScoreInput returns the score function with respect to the input of the // distribution at the input location specified by x. The score function is the // derivative of the log-likelihood // // (d/dx) log(p(x)) . func (u Uniform) ScoreInput(x float64) float64 { if (x <= u.Min) || (x >= u.Max) { return math.NaN() } return 0 } // Skewness returns the skewness of the distribution. func (Uniform) Skewness() float64 { return 0 } // StdDev returns the standard deviation of the probability distribution. func (u Uniform) StdDev() float64 { return math.Sqrt(u.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (u Uniform) Survival(x float64) float64 { if x < u.Min { return 1 } if x > u.Max { return 0 } return (u.Max - x) / (u.Max - u.Min) } // setParameters modifies the parameters of the distribution. func (u *Uniform) setParameters(p []Parameter) { if len(p) != u.NumParameters() { panic("uniform: incorrect number of parameters to set") } if p[0].Name != "Min" { panic("uniform: " + panicNameMismatch) } if p[1].Name != "Max" { panic("uniform: " + panicNameMismatch) } u.Min = p[0].Value u.Max = p[1].Value } // Variance returns the variance of the probability distribution. func (u Uniform) Variance() float64 { return 1.0 / 12.0 * (u.Max - u.Min) * (u.Max - u.Min) } golang-gonum-v1-gonum-0.14.0/stat/distuv/uniform_test.go000066400000000000000000000067441450372207100232070ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" ) func TestUniformProb(t *testing.T) { t.Parallel() for _, test := range []struct { min, max, x, want float64 }{ {0, 1, 1, 1}, {2, 4, 0, 0}, {2, 4, 5, 0}, {2, 4, 3, 0.5}, {0, 100, 1, 0.01}, {-1, 1, -1.5, 0}, {-1, 1, 1.5, 0}, } { u := Uniform{test.min, test.max, nil} pdf := u.Prob(test.x) if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-15, 1e-15) { t.Errorf("PDF mismatch, x = %v, min = %v, max = %v. Got %v, want %v", test.x, test.min, test.max, pdf, test.want) } logWant := math.Log(test.want) logPdf := u.LogProb(test.x) if !scalar.EqualWithinAbsOrRel(logPdf, logWant, 1e-15, 1e-15) { t.Errorf("Log PDF mismatch, x = %v, min = %v, max = %v. Got %v, want %v", test.x, test.min, test.max, logPdf, logWant) } } } func TestUniformCDFSurvival(t *testing.T) { t.Parallel() for _, test := range []struct { min, max, x, want float64 }{ {0, 1, 1, 1}, {0, 100, 100, 1}, {0, 100, 0, 0}, {0, 100, 50, 0.5}, {0, 50, 10, 0.2}, {-1, 1, -1.5, 0}, {-1, 1, 1.5, 1}, } { u := Uniform{test.min, test.max, nil} cdf := u.CDF(test.x) if !scalar.EqualWithinAbsOrRel(cdf, test.want, 1e-15, 1e-15) { t.Errorf("CDF mismatch, x = %v, min = %v, max = %v. Got %v, want %v", test.x, test.min, test.max, cdf, test.want) } survival := u.Survival(test.x) if !scalar.EqualWithinAbsOrRel(survival, 1-test.want, 1e-15, 1e-15) { t.Errorf("CDF mismatch, x = %v, min = %v, max = %v. Got %v, want %v", test.x, test.min, test.max, survival, 1-test.want) } } } func TestUniform(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, b := range []Uniform{ {1, 2, src}, {0, 100, src}, {50, 60, src}, } { testUniform(t, b, i) } } func testUniform(t *testing.T, u Uniform, i int) { const ( tol = 1e-2 n = 1e5 bins = 50 ) x := make([]float64, n) generateSamples(x, u) sort.Float64s(x) testRandLogProbContinuous(t, i, 0, x, u, tol, bins) checkMean(t, i, x, u, tol) checkVarAndStd(t, i, x, u, tol) checkExKurtosis(t, i, x, u, 7e-2) checkProbContinuous(t, i, x, u.Min, u.Max, u, 1e-10) checkQuantileCDFSurvival(t, i, x, u, 1e-2) checkEntropy(t, i, x, u, tol) checkSkewness(t, i, x, u, tol) checkMedian(t, i, x, u, tol) testDerivParam(t, &u) } func TestUniformScore(t *testing.T) { t.Parallel() u := Uniform{0, 1, nil} for _, test := range []struct { x, wantMin, wantMax float64 }{ {-0.001, math.NaN(), math.NaN()}, {0, math.NaN(), -1}, {1, 1, math.NaN()}, {1.001, math.NaN(), math.NaN()}, } { score := u.Score(nil, test.x) if !scalar.Same(score[0], test.wantMin) { t.Errorf("Score[0] mismatch for at %g: got %v, want %g", test.x, score[0], test.wantMin) } if !scalar.Same(score[1], test.wantMax) { t.Errorf("Score[1] mismatch for at %g: got %v, want %g", test.x, score[1], test.wantMax) } } } func TestUniformScoreInput(t *testing.T) { t.Parallel() u := Uniform{0, 1, nil} scoreInput := u.ScoreInput(0.5) if scoreInput != 0 { t.Errorf("Mismatch in input score for U(0, 1) at x == 0.5: got %v, want 0", scoreInput) } xs := []float64{-0.0001, 0, 1, 1.0001} for _, x := range xs { scoreInput = u.ScoreInput(x) if !math.IsNaN(scoreInput) { t.Errorf("Expected NaN score input for U(0, 1) at x == %g, got %v", x, scoreInput) } } } golang-gonum-v1-gonum-0.14.0/stat/distuv/weibull.go000066400000000000000000000151441450372207100221260ustar00rootroot00000000000000// 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 distuv import ( "math" "golang.org/x/exp/rand" ) // Weibull distribution. Valid range for x is [0,+∞). type Weibull struct { // Shape parameter of the distribution. A value of 1 represents // the exponential distribution. A value of 2 represents the // Rayleigh distribution. Valid range is (0,+∞). K float64 // Scale parameter of the distribution. Valid range is (0,+∞). Lambda float64 // Source of random numbers Src rand.Source } // CDF computes the value of the cumulative density function at x. func (w Weibull) CDF(x float64) float64 { if x < 0 { return 0 } return -math.Expm1(-math.Pow(x/w.Lambda, w.K)) } // Entropy returns the entropy of the distribution. func (w Weibull) Entropy() float64 { return eulerGamma*(1-1/w.K) + math.Log(w.Lambda/w.K) + 1 } // ExKurtosis returns the excess kurtosis of the distribution. func (w Weibull) ExKurtosis() float64 { return (-6*w.gammaIPow(1, 4) + 12*w.gammaIPow(1, 2)*math.Gamma(1+2/w.K) - 3*w.gammaIPow(2, 2) - 4*math.Gamma(1+1/w.K)*math.Gamma(1+3/w.K) + math.Gamma(1+4/w.K)) / math.Pow(math.Gamma(1+2/w.K)-w.gammaIPow(1, 2), 2) } // gammIPow is a shortcut for computing the gamma function to a power. func (w Weibull) gammaIPow(i, pow float64) float64 { return math.Pow(math.Gamma(1+i/w.K), pow) } // LogProb computes the natural logarithm of the value of the probability // density function at x. -Inf is returned if x is less than zero. // // Special cases occur when x == 0, and the result depends on the shape // parameter as follows: // // If 0 < K < 1, LogProb returns +Inf. // If K == 1, LogProb returns 0. // If K > 1, LogProb returns -Inf. func (w Weibull) LogProb(x float64) float64 { if x < 0 { return math.Inf(-1) } if x == 0 && w.K == 1 { return 0 } return math.Log(w.K) - math.Log(w.Lambda) + (w.K-1)*(math.Log(x)-math.Log(w.Lambda)) - math.Pow(x/w.Lambda, w.K) } // LogSurvival returns the log of the survival function (complementary CDF) at x. func (w Weibull) LogSurvival(x float64) float64 { if x < 0 { return 0 } return -math.Pow(x/w.Lambda, w.K) } // Mean returns the mean of the probability distribution. func (w Weibull) Mean() float64 { return w.Lambda * math.Gamma(1+1/w.K) } // Median returns the median of the normal distribution. func (w Weibull) Median() float64 { return w.Lambda * math.Pow(ln2, 1/w.K) } // Mode returns the mode of the normal distribution. // // The mode is NaN in the special case where the K (shape) parameter // is less than 1. func (w Weibull) Mode() float64 { if w.K > 1 { return w.Lambda * math.Pow((w.K-1)/w.K, 1/w.K) } return 0 } // NumParameters returns the number of parameters in the distribution. func (Weibull) NumParameters() int { return 2 } // Prob computes the value of the probability density function at x. func (w Weibull) Prob(x float64) float64 { if x < 0 { return 0 } return math.Exp(w.LogProb(x)) } // Quantile returns the inverse of the cumulative probability distribution. func (w Weibull) Quantile(p float64) float64 { if p < 0 || p > 1 { panic(badPercentile) } return w.Lambda * math.Pow(-math.Log(1-p), 1/w.K) } // Rand returns a random sample drawn from the distribution. func (w Weibull) Rand() float64 { var rnd float64 if w.Src == nil { rnd = rand.Float64() } else { rnd = rand.New(w.Src).Float64() } return w.Quantile(rnd) } // Score returns the score function with respect to the parameters of the // distribution at the input location x. The score function is the derivative // of the log-likelihood at x with respect to the parameters // // (∂/∂θ) log(p(x;θ)) // // If deriv is non-nil, len(deriv) must equal the number of parameters otherwise // Score will panic, and the derivative is stored in-place into deriv. If deriv // is nil a new slice will be allocated and returned. // // The order is [∂LogProb / ∂K, ∂LogProb / ∂λ]. // // For more information, see https://en.wikipedia.org/wiki/Score_%28statistics%29. // // Special cases: // // Score(x) = [NaN, NaN] for x <= 0 func (w Weibull) Score(deriv []float64, x float64) []float64 { if deriv == nil { deriv = make([]float64, w.NumParameters()) } if len(deriv) != w.NumParameters() { panic(badLength) } if x > 0 { deriv[0] = 1/w.K + math.Log(x) - math.Log(w.Lambda) - (math.Log(x)-math.Log(w.Lambda))*math.Pow(x/w.Lambda, w.K) deriv[1] = (w.K * (math.Pow(x/w.Lambda, w.K) - 1)) / w.Lambda return deriv } deriv[0] = math.NaN() deriv[1] = math.NaN() return deriv } // ScoreInput returns the score function with respect to the input of the // distribution at the input location specified by x. The score function is the // derivative of the log-likelihood // // (d/dx) log(p(x)) . // // Special cases: // // ScoreInput(x) = NaN for x <= 0 func (w Weibull) ScoreInput(x float64) float64 { if x > 0 { return (-w.K*math.Pow(x/w.Lambda, w.K) + w.K - 1) / x } return math.NaN() } // Skewness returns the skewness of the distribution. func (w Weibull) Skewness() float64 { stdDev := w.StdDev() firstGamma, firstGammaSign := math.Lgamma(1 + 3/w.K) logFirst := firstGamma + 3*(math.Log(w.Lambda)-math.Log(stdDev)) logSecond := math.Log(3) + math.Log(w.Mean()) + 2*math.Log(stdDev) - 3*math.Log(stdDev) logThird := 3 * (math.Log(w.Mean()) - math.Log(stdDev)) return float64(firstGammaSign)*math.Exp(logFirst) - math.Exp(logSecond) - math.Exp(logThird) } // StdDev returns the standard deviation of the probability distribution. func (w Weibull) StdDev() float64 { return math.Sqrt(w.Variance()) } // Survival returns the survival function (complementary CDF) at x. func (w Weibull) Survival(x float64) float64 { return math.Exp(w.LogSurvival(x)) } // setParameters modifies the parameters of the distribution. func (w *Weibull) setParameters(p []Parameter) { if len(p) != w.NumParameters() { panic("weibull: incorrect number of parameters to set") } if p[0].Name != "K" { panic("weibull: " + panicNameMismatch) } if p[1].Name != "λ" { panic("weibull: " + panicNameMismatch) } w.K = p[0].Value w.Lambda = p[1].Value } // Variance returns the variance of the probability distribution. func (w Weibull) Variance() float64 { return math.Pow(w.Lambda, 2) * (math.Gamma(1+2/w.K) - w.gammaIPow(1, 2)) } // parameters returns the parameters of the distribution. func (w Weibull) parameters(p []Parameter) []Parameter { nParam := w.NumParameters() if p == nil { p = make([]Parameter, nParam) } else if len(p) != nParam { panic("weibull: improper parameter length") } p[0].Name = "K" p[0].Value = w.K p[1].Name = "λ" p[1].Value = w.Lambda return p } golang-gonum-v1-gonum-0.14.0/stat/distuv/weibull_test.go000066400000000000000000000124101450372207100231560ustar00rootroot00000000000000// 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 distuv import ( "math" "sort" "testing" "golang.org/x/exp/rand" ) func TestHalfKStandardWeibullProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: math.Inf(1), cumProb: 0, logProb: math.Inf(1), }, { loc: -1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 0.183939720585721, cumProb: 0.632120558828558, logProb: -1.693147180559950, }, { loc: 20, prob: 0.001277118038048, cumProb: 0.988577109006533, logProb: -6.663149272336520, }, } testDistributionProbs(t, Weibull{K: 0.5, Lambda: 1}, "0.5K Standard Weibull", pts) } func TestExponentialStandardWeibullProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: 1, cumProb: 0, logProb: 0, }, { loc: -1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 0.367879441171442, cumProb: 0.632120558828558, logProb: -1.0, }, { loc: 20, prob: 0.000000002061154, cumProb: 0.999999997938846, logProb: -20.0, }, } testDistributionProbs(t, Weibull{K: 1, Lambda: 1}, "1K (Exponential) Standard Weibull", pts) } func TestRayleighStandardWeibullProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: -1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 0.735758882342885, cumProb: 0.632120558828558, logProb: -0.306852819440055, }, { loc: 20, prob: 0, cumProb: 1, logProb: -396.31112054588607, }, } testDistributionProbs(t, Weibull{K: 2, Lambda: 1}, "2K (Rayleigh) Standard Weibull", pts) } func TestFiveKStandardWeibullProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: -1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 1.839397205857210, cumProb: 0.632120558828558, logProb: 0.609437912434100, }, { loc: 20, prob: 0, cumProb: 1, logProb: -3199986.4076329935, }, } testDistributionProbs(t, Weibull{K: 5, Lambda: 1}, "5K Standard Weibull", pts) } func TestScaledUpHalfKStandardWeibullProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: math.Inf(1), cumProb: 0, logProb: math.Inf(1), }, { loc: -1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 0.180436508682207, cumProb: 0.558022622759326, logProb: -1.712376315541750, }, { loc: 20, prob: 0.002369136850928, cumProb: 0.974047406098605, logProb: -6.045229588092130, }, } testDistributionProbs(t, Weibull{K: 0.5, Lambda: 1.5}, "0.5K 1.5λ Weibull", pts) } func TestScaledDownHalfKStandardWeibullProb(t *testing.T) { t.Parallel() pts := []univariateProbPoint{ { loc: 0, prob: math.Inf(1), cumProb: 0, logProb: math.Inf(1), }, { loc: -1, prob: 0, cumProb: 0, logProb: math.Inf(-1), }, { loc: 1, prob: 0.171909491538362, cumProb: 0.756883265565786, logProb: -1.760787152653070, }, { loc: 20, prob: 0.000283302579100, cumProb: 0.998208237166091, logProb: -8.168995047393730, }, } testDistributionProbs(t, Weibull{K: 0.5, Lambda: 0.5}, "0.5K 0.5λ Weibull", pts) } func TestWeibullScores(t *testing.T) { t.Parallel() for i, test := range []*Weibull{ { K: 1, Lambda: 1, }, { K: 2, Lambda: 3.6, }, { K: 3.4, Lambda: 8, }, } { testDerivParam(t, test) for _, x := range []float64{0, -0.0001} { score := test.Score(nil, 0) if !math.IsNaN(score[0]) || !math.IsNaN(score[1]) { t.Errorf("Score mismatch for case %d and x == %g: got %v, want [NaN, NaN]", i, x, score) } scoreInput := test.ScoreInput(0) if !math.IsNaN(scoreInput) { t.Errorf("ScoreInput mismatch for case %d and x == %g: got %v, want NaN", i, x, score) } } } } func TestWeibull(t *testing.T) { t.Parallel() src := rand.New(rand.NewSource(1)) for i, dist := range []Weibull{ {K: 0.75, Lambda: 1, Src: src}, {K: 1, Lambda: 1, Src: src}, {K: 2, Lambda: 3.6, Src: src}, {K: 3.4, Lambda: 8, Src: src}, } { testWeibull(t, dist, i) } } func testWeibull(t *testing.T, dist Weibull, i int) { const ( tol = 1e-2 n = 3e6 bins = 50 ) x := make([]float64, n) generateSamples(x, dist) sort.Float64s(x) checkMean(t, i, x, dist, tol) checkVarAndStd(t, i, x, dist, tol) checkEntropy(t, i, x, dist, tol) checkExKurtosis(t, i, x, dist, tol) checkSkewness(t, i, x, dist, tol) checkMedian(t, i, x, dist, tol) checkQuantileCDFSurvival(t, i, x, dist, tol) // Weibull distribution PDF has a singularity at 0 for K < 1, // so we need higher tolerance. var probTol float64 if dist.K >= 1 { probTol = 1e-10 } else { probTol = 1e-8 } checkProbContinuous(t, i, x, 0, math.Inf(1), dist, probTol) checkProbQuantContinuous(t, i, x, dist, tol) checkMode(t, i, x, dist, 1e-1, 2e-1) } golang-gonum-v1-gonum-0.14.0/stat/doc.go000066400000000000000000000004221450372207100177030ustar00rootroot00000000000000// 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 stat provides generalized statistical functions. package stat // import "gonum.org/v1/gonum/stat" golang-gonum-v1-gonum-0.14.0/stat/faithful_test.go000066400000000000000000000066051450372207100220100ustar00rootroot00000000000000// Copyright ©2016 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 stat // faithful is the faithful data set from R. var faithful = struct{ waiting, eruptions []float64 }{ waiting: []float64{ 79, 54, 74, 62, 85, 55, 88, 85, 51, 85, 54, 84, 78, 47, 83, 52, 62, 84, 52, 79, 51, 47, 78, 69, 74, 83, 55, 76, 78, 79, 73, 77, 66, 80, 74, 52, 48, 80, 59, 90, 80, 58, 84, 58, 73, 83, 64, 53, 82, 59, 75, 90, 54, 80, 54, 83, 71, 64, 77, 81, 59, 84, 48, 82, 60, 92, 78, 78, 65, 73, 82, 56, 79, 71, 62, 76, 60, 78, 76, 83, 75, 82, 70, 65, 73, 88, 76, 80, 48, 86, 60, 90, 50, 78, 63, 72, 84, 75, 51, 82, 62, 88, 49, 83, 81, 47, 84, 52, 86, 81, 75, 59, 89, 79, 59, 81, 50, 85, 59, 87, 53, 69, 77, 56, 88, 81, 45, 82, 55, 90, 45, 83, 56, 89, 46, 82, 51, 86, 53, 79, 81, 60, 82, 77, 76, 59, 80, 49, 96, 53, 77, 77, 65, 81, 71, 70, 81, 93, 53, 89, 45, 86, 58, 78, 66, 76, 63, 88, 52, 93, 49, 57, 77, 68, 81, 81, 73, 50, 85, 74, 55, 77, 83, 83, 51, 78, 84, 46, 83, 55, 81, 57, 76, 84, 77, 81, 87, 77, 51, 78, 60, 82, 91, 53, 78, 46, 77, 84, 49, 83, 71, 80, 49, 75, 64, 76, 53, 94, 55, 76, 50, 82, 54, 75, 78, 79, 78, 78, 70, 79, 70, 54, 86, 50, 90, 54, 54, 77, 79, 64, 75, 47, 86, 63, 85, 82, 57, 82, 67, 74, 54, 83, 73, 73, 88, 80, 71, 83, 56, 79, 78, 84, 58, 83, 43, 60, 75, 81, 46, 90, 46, 74, }, eruptions: []float64{ 3.600, 1.800, 3.333, 2.283, 4.533, 2.883, 4.700, 3.600, 1.950, 4.350, 1.833, 3.917, 4.200, 1.750, 4.700, 2.167, 1.750, 4.800, 1.600, 4.250, 1.800, 1.750, 3.450, 3.067, 4.533, 3.600, 1.967, 4.083, 3.850, 4.433, 4.300, 4.467, 3.367, 4.033, 3.833, 2.017, 1.867, 4.833, 1.833, 4.783, 4.350, 1.883, 4.567, 1.750, 4.533, 3.317, 3.833, 2.100, 4.633, 2.000, 4.800, 4.716, 1.833, 4.833, 1.733, 4.883, 3.717, 1.667, 4.567, 4.317, 2.233, 4.500, 1.750, 4.800, 1.817, 4.400, 4.167, 4.700, 2.067, 4.700, 4.033, 1.967, 4.500, 4.000, 1.983, 5.067, 2.017, 4.567, 3.883, 3.600, 4.133, 4.333, 4.100, 2.633, 4.067, 4.933, 3.950, 4.517, 2.167, 4.000, 2.200, 4.333, 1.867, 4.817, 1.833, 4.300, 4.667, 3.750, 1.867, 4.900, 2.483, 4.367, 2.100, 4.500, 4.050, 1.867, 4.700, 1.783, 4.850, 3.683, 4.733, 2.300, 4.900, 4.417, 1.700, 4.633, 2.317, 4.600, 1.817, 4.417, 2.617, 4.067, 4.250, 1.967, 4.600, 3.767, 1.917, 4.500, 2.267, 4.650, 1.867, 4.167, 2.800, 4.333, 1.833, 4.383, 1.883, 4.933, 2.033, 3.733, 4.233, 2.233, 4.533, 4.817, 4.333, 1.983, 4.633, 2.017, 5.100, 1.800, 5.033, 4.000, 2.400, 4.600, 3.567, 4.000, 4.500, 4.083, 1.800, 3.967, 2.200, 4.150, 2.000, 3.833, 3.500, 4.583, 2.367, 5.000, 1.933, 4.617, 1.917, 2.083, 4.583, 3.333, 4.167, 4.333, 4.500, 2.417, 4.000, 4.167, 1.883, 4.583, 4.250, 3.767, 2.033, 4.433, 4.083, 1.833, 4.417, 2.183, 4.800, 1.833, 4.800, 4.100, 3.966, 4.233, 3.500, 4.366, 2.250, 4.667, 2.100, 4.350, 4.133, 1.867, 4.600, 1.783, 4.367, 3.850, 1.933, 4.500, 2.383, 4.700, 1.867, 3.833, 3.417, 4.233, 2.400, 4.800, 2.000, 4.150, 1.867, 4.267, 1.750, 4.483, 4.000, 4.117, 4.083, 4.267, 3.917, 4.550, 4.083, 2.417, 4.183, 2.217, 4.450, 1.883, 1.850, 4.283, 3.950, 2.333, 4.150, 2.350, 4.933, 2.900, 4.583, 3.833, 2.083, 4.367, 2.133, 4.350, 2.200, 4.450, 3.567, 4.500, 4.150, 3.817, 3.917, 4.450, 2.000, 4.283, 4.767, 4.533, 1.850, 4.250, 1.983, 2.250, 4.750, 4.117, 2.150, 4.417, 1.817, 4.467, }, } golang-gonum-v1-gonum-0.14.0/stat/mds/000077500000000000000000000000001450372207100173745ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/mds/doc.go000066400000000000000000000004251450372207100204710ustar00rootroot00000000000000// 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 mds provides multidimensional scaling functions. package mds // import "gonum.org/v1/gonum/stat/mds" golang-gonum-v1-gonum-0.14.0/stat/mds/mds.go000066400000000000000000000045101450372207100205060ustar00rootroot00000000000000// 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 mds import ( "math" "gonum.org/v1/gonum/blas/blas64" "gonum.org/v1/gonum/mat" ) // TorgersonScaling converts a dissimilarity matrix to a matrix containing // Euclidean coordinates. TorgersonScaling places the coordinates in dst and // returns it and the number of positive Eigenvalues if successful. // Note that Eigen Decomposition is numerically unstable and so Eigenvalues // near zero should be examined and the value returned for k is advisory only. // If the scaling is not successful, dst will be empty upon return. // When the scaling is successful, dst will be resized to k columns wide. // Eigenvalues will be copied into eigdst and returned as eig if it is provided. // // TorgersonScaling will panic if dst is not empty. func TorgersonScaling(dst *mat.Dense, eigdst []float64, dis mat.Symmetric) (k int, eig []float64) { // https://doi.org/10.1007/0-387-28981-X_12 n := dis.SymmetricDim() if dst.IsEmpty() { dst.ReuseAs(n, n) } else { panic("mds: receiver matrix not empty") } b := mat.NewSymDense(n, nil) for i := 0; i < n; i++ { for j := i; j < n; j++ { v := dis.At(i, j) v *= v b.SetSym(i, j, v) } } c := mat.NewSymDense(n, nil) s := -1 / float64(n) for i := 0; i < n; i++ { c.SetSym(i, i, 1+s) for j := i + 1; j < n; j++ { c.SetSym(i, j, s) } } dst.Product(c, b, c) for i := 0; i < n; i++ { for j := i; j < n; j++ { b.SetSym(i, j, -0.5*dst.At(i, j)) } } var ed mat.EigenSym ok := ed.Factorize(b, true) if !ok { return 0, eigdst } ed.VectorsTo(dst) vals := ed.Values(nil) reverse(vals, dst.RawMatrix()) copy(eigdst, vals) for i, v := range vals { if v < 0 { vals[i] = 0 continue } k = i + 1 vals[i] = math.Sqrt(v) } var tmp mat.Dense tmp.Mul(dst, mat.NewDiagonalRect(n, k, vals[:k])) *dst = *dst.Slice(0, n, 0, k).(*mat.Dense) dst.Copy(&tmp) return k, eigdst } func reverse(values []float64, vectors blas64.General) { for i, j := 0, len(values)-1; i < j; i, j = i+1, j-1 { values[i], values[j] = values[j], values[i] blas64.Swap(blas64.Vector{N: vectors.Rows, Inc: vectors.Stride, Data: vectors.Data[i:]}, blas64.Vector{N: vectors.Rows, Inc: vectors.Stride, Data: vectors.Data[j:]}) } } golang-gonum-v1-gonum-0.14.0/stat/mds/mds_test.go000066400000000000000000000216431450372207100215530ustar00rootroot00000000000000// 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 mds import ( "math" "testing" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) var torgersonScalingTests = []struct { dis mat.Symmetric wantK int want *mat.Dense wantVals []float64 tol float64 }{ // All expected values obtained from running R cmdscale with the input here. { // Data from http://rosetta.reltech.org/TC/v15/Mapping/data/dist-Aus.csv dis: mat.NewSymDense(8, []float64{ 0, 1328, 1600, 2616, 1161, 653, 2130, 1161, 1328, 0, 1962, 1289, 2463, 1889, 1991, 2026, 1600, 1962, 0, 2846, 1788, 1374, 3604, 732, 2616, 1289, 2846, 0, 3734, 3146, 2652, 3146, 1161, 2463, 1788, 3734, 0, 598, 3008, 1057, 653, 1889, 1374, 3146, 598, 0, 2720, 713, 2130, 1991, 3604, 2652, 3008, 2720, 0, 3288, 1161, 2026, 732, 3146, 1057, 713, 3288, 0, }), wantK: 4, want: mat.NewDense(8, 4, []float64{ -208.3266, 369.5373, 80.544010, 7.078974, 904.8449, -356.0745, 92.309541, -19.077511, -925.9941, -1067.8589, -38.585847, -6.696700, 1933.8035, -1129.8610, -50.099688, 7.344750, -1318.6333, 704.3759, -56.673300, -17.419249, -858.3951, 319.5948, 24.186572, 18.138426, 1591.6571, 1511.3688, -43.308441, 1.043611, -1118.9564, -351.0825, -8.372847, 9.587699, }), wantVals: []float64{ 1.172027697614e+07, 5.686036184502e+06, 2.474981412369e+04, 1.238300279584e+03, 0, -2.471028925712e+02, -2.412961483429e+03, -8.452858567111e+04, }, tol: 1e-9, }, { // R eurodist dataset. dis: mat.NewSymDense(21, []float64{ 0, 3313, 2963, 3175, 3339, 2762, 3276, 2610, 4485, 2977, 3030, 4532, 2753, 3949, 2865, 2282, 2179, 3000, 817, 3927, 1991, 3313, 0, 1318, 1326, 1294, 1498, 2218, 803, 1172, 2018, 1490, 1305, 645, 636, 521, 1014, 1365, 1033, 1460, 2868, 1802, 2963, 1318, 0, 204, 583, 206, 966, 677, 2256, 597, 172, 2084, 690, 1558, 1011, 925, 747, 285, 1511, 1616, 1175, 3175, 1326, 204, 0, 460, 409, 1136, 747, 2224, 714, 330, 2052, 739, 1550, 1059, 1077, 977, 280, 1662, 1786, 1381, 3339, 1294, 583, 460, 0, 785, 1545, 853, 2047, 1115, 731, 1827, 789, 1347, 1101, 1209, 1160, 340, 1794, 2196, 1588, 2762, 1498, 206, 409, 785, 0, 760, 1662, 2436, 460, 269, 2290, 714, 1764, 1035, 911, 583, 465, 1497, 1403, 937, 3276, 2218, 966, 1136, 1545, 760, 0, 1418, 3196, 460, 269, 2971, 1458, 2498, 1778, 1537, 1104, 1176, 2050, 650, 1455, 2610, 803, 677, 747, 853, 1662, 1418, 0, 1975, 1118, 895, 1936, 158, 1439, 425, 328, 591, 513, 995, 2068, 1019, 4485, 1172, 2256, 2224, 2047, 2436, 3196, 1975, 0, 2897, 2428, 676, 1817, 698, 1693, 2185, 2565, 1971, 2631, 3886, 2974, 2977, 2018, 597, 714, 1115, 460, 460, 1118, 2897, 0, 550, 2671, 1159, 2198, 1479, 1238, 805, 877, 1751, 949, 1155, 3030, 1490, 172, 330, 731, 269, 269, 895, 2428, 550, 0, 2280, 863, 1730, 1183, 1098, 851, 457, 1683, 1500, 1205, 4532, 1305, 2084, 2052, 1827, 2290, 2971, 1936, 676, 2671, 2280, 0, 1178, 668, 1762, 2250, 2507, 1799, 2700, 3231, 2937, 2753, 645, 690, 739, 789, 714, 1458, 158, 1817, 1159, 863, 1178, 0, 1281, 320, 328, 724, 471, 1048, 2108, 1157, 3949, 636, 1558, 1550, 1347, 1764, 2498, 1439, 698, 2198, 1730, 668, 1281, 0, 1157, 1724, 2010, 1273, 2097, 3188, 2409, 2865, 521, 1011, 1059, 1101, 1035, 1778, 425, 1693, 1479, 1183, 1762, 320, 1157, 0, 618, 1109, 792, 1011, 2428, 1363, 2282, 1014, 925, 1077, 1209, 911, 1537, 328, 2185, 1238, 1098, 2250, 328, 1724, 618, 0, 331, 856, 586, 2187, 898, 2179, 1365, 747, 977, 1160, 583, 1104, 591, 2565, 805, 851, 2507, 724, 2010, 1109, 331, 0, 821, 946, 1754, 428, 3000, 1033, 285, 280, 340, 465, 1176, 513, 1971, 877, 457, 1799, 471, 1273, 792, 856, 821, 0, 1476, 1827, 1249, 817, 1460, 1511, 1662, 1794, 1497, 2050, 995, 2631, 1751, 1683, 2700, 1048, 2097, 1011, 586, 946, 1476, 0, 2707, 1209, 3927, 2868, 1616, 1786, 2196, 1403, 650, 2068, 3886, 949, 1500, 3231, 2108, 3188, 2428, 2187, 1754, 1827, 2707, 0, 2105, 1991, 1802, 1175, 1381, 1588, 937, 1455, 1019, 2974, 1155, 1205, 2937, 1157, 2409, 1363, 898, 428, 1249, 1209, 2105, 0, }), // Note that k here is 12 despite the result from R's cmdscale. // This is due to disparity between the ED performed by R and Gonum. // See https://github.com/gonum/gonum/issues/768 wantK: 12, want: mat.NewDense(21, 12, []float64{ 2290.274680, 1798.80293, 53.79314, -103.826958, -156.955115, 54.755434, -47.6768205, 1.241284, -14.893196, -6.366664, 4.818373, 0, -825.382790, 546.81148, -113.85842, 84.585831, 291.440759, -33.046236, -74.5267190, 3.766233, 225.620420, -21.270973, 22.050484, 0, 59.183341, -367.08135, 177.55291, 38.797514, -95.620447, 40.058268, 2.3212184, 34.351715, -2.262151, -129.298820, 75.568686, 0, -82.845973, -429.91466, 300.19274, 106.353695, -180.446140, 31.336985, 88.6540176, 5.102633, 87.657362, 86.867202, 156.097411, 0, -352.499435, -290.90843, 457.35294, 111.449150, -417.496682, -138.972847, 46.7759317, 23.806769, 108.307203, 99.578699, -103.623270, 0, 293.689633, -405.31194, 360.09323, -636.202379, 159.392662, -9.560652, 33.1089500, 9.193680, 19.417287, 7.925230, -1.272483, 0, 681.931545, -1108.64478, 26.09257, 151.693056, 254.114892, 197.254208, -176.0359152, -6.508596, -59.829991, 64.904841, -26.466935, 0, -9.423364, 240.40600, -344.20659, 656.121110, -138.082259, -19.891841, -0.3128244, -20.167733, -18.250209, -11.175662, 2.160076, 0, -2048.449113, 642.45854, 167.86631, 78.621423, 239.881353, -51.009028, 60.7527717, 125.492010, -144.940590, 35.754867, 13.633563, 0, 561.108970, -773.36929, 80.91722, 48.548472, -129.512374, 20.426493, 207.7920058, 23.646986, -166.184382, -64.027105, -5.187863, 0, 164.921799, -549.36704, 270.82327, 116.886334, 62.711250, 117.489888, -252.4906676, -47.193881, -62.053055, 75.466644, 4.907670, 0, -1935.040811, 49.12514, -483.02056, -315.241752, -277.696589, -92.444183, -76.2549266, -28.529861, -26.279840, -2.503630, 7.050184, 0, -226.423236, 187.08779, -358.43234, -257.737009, -190.609088, -110.666015, -119.7638108, -43.118326, -76.066370, 89.289877, 18.820576, 0, -1423.353697, 305.87513, 253.26763, 2.478812, 5.366334, 205.060613, -45.8020725, -75.244576, -4.303057, -150.778068, -23.118399, 0, -299.498710, 388.80726, -109.17417, 12.651217, 231.405239, 154.749482, 237.4507512, -227.372584, 25.449825, 71.404170, -35.167507, 0, 260.878046, 416.67381, -171.52428, 20.926369, 194.345825, -19.740272, 121.3353507, 184.415363, -5.563374, 90.507909, -22.562758, 0, 587.675679, 81.18224, -75.88485, 13.080496, 114.688714, -185.462926, -47.4707495, 209.170525, 39.452744, -65.352092, -23.127035, 0, -156.836257, -211.13911, 131.30852, 27.089432, -100.800743, 6.794791, -25.6913210, -7.904762, 39.731234, -79.091817, -75.116800, 0, 709.413282, 1109.36665, -179.83052, -109.895049, -90.243055, 316.665218, 9.9070412, 9.976867, 6.316941, -13.285987, 1.496742, 0, 839.445911, -1836.79055, -541.35188, -108.755016, 25.155430, 41.399927, 71.8793196, 9.438407, 73.554358, -35.415426, -6.021569, 0, 911.230500, 205.93020, 98.02313, 62.375253, 198.960032, -525.197308, -13.9515306, -183.562155, -44.881159, -43.133195, 15.060856, 0, }), wantVals: []float64{ 1.953837708954e+07, 1.185655533400e+07, 1.528844467987e+06, 1.118741950509e+06, 7.893472026801e+05, 5.816552067198e+05, 2.623192077011e+05, 1.925975616762e+05, 1.450845349644e+05, 1.079673069262e+05, 5.139484110774e+04, 7.598368987955e-11, -9.496124219168e+03, -5.305819566947e+04, -1.322165749977e+05, -2.573360255637e+05, -3.326719007160e+05, -5.162522542344e+05, -9.191490984121e+05, -1.006503960172e+06, -2.251844331736e+06, }, tol: 1e-9, }, } func TestTorgersonScaling(t *testing.T) { for i, test := range torgersonScalingTests { r, c := test.dis.Dims() var got mat.Dense gotK, gotVals := TorgersonScaling(&got, make([]float64, c), test.dis) if gotK == 0 { t.Error("unexpected scaling failure") continue } if gotK != test.wantK { var derivedK int for derivedK = range gotVals { if math.Abs(gotVals[derivedK]) < test.tol { got = *got.Slice(0, r, 0, derivedK).(*mat.Dense) break } } if derivedK != test.wantK { t.Errorf("unexpected k for test %d: got:%d want:%d", i, gotK, test.wantK) } else { t.Logf("low precision (tol=%.0e) k for test %d: gotK:%d derived=want:%d", test.tol, i, gotK, test.wantK) } } if !mat.EqualApprox(colAbs{&got}, colAbs{test.want}, math.Sqrt(test.tol)) { t.Errorf("unexpected result for test %d:\ngot:\n%.5f\nwant:\n%.5f", i, mat.Formatted(&got), mat.Formatted(test.want)) } if !floats.EqualApprox(gotVals, test.wantVals, test.tol) { t.Errorf("unexpected Eigenvalues for test %d:\ngot: %.12e\nwant:%.12e", i, gotVals, test.wantVals) } } } // colAbs returns the value of columns reflected // such that the first row is positive. type colAbs struct { mat.Matrix } func (m colAbs) At(i, j int) float64 { if m.Matrix.At(0, j) < 0 { return -m.Matrix.At(i, j) } return m.Matrix.At(i, j) } golang-gonum-v1-gonum-0.14.0/stat/moments_bench_test.go000066400000000000000000000321151450372207100230220ustar00rootroot00000000000000// 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. // a set of benchmarks to evaluate the performance of the various // moment statistics: Mean, Variance, StdDev, MeanVariance, MeanStdDev, // Covariance, Correlation, Skew, ExKurtosis, Moment, MomentAbout, ... // // It tests both weighted and unweighted versions by using a slice of // all ones. package stat import ( "testing" "golang.org/x/exp/rand" ) const ( small = 10 medium = 1000 large = 100000 huge = 10000000 ) // tests for unweighted versions func RandomSlice(l int) []float64 { s := make([]float64, l) for i := range s { s[i] = rand.Float64() } return s } func benchmarkMean(b *testing.B, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { Mean(s, wts) } } func BenchmarkMeanSmall(b *testing.B) { s := RandomSlice(small) benchmarkMean(b, s, nil) } func BenchmarkMeanMedium(b *testing.B) { s := RandomSlice(medium) benchmarkMean(b, s, nil) } func BenchmarkMeanLarge(b *testing.B) { s := RandomSlice(large) benchmarkMean(b, s, nil) } func BenchmarkMeanHuge(b *testing.B) { s := RandomSlice(huge) benchmarkMean(b, s, nil) } func BenchmarkMeanSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkMean(b, s, wts) } func BenchmarkMeanMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkMean(b, s, wts) } func BenchmarkMeanLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkMean(b, s, wts) } func BenchmarkMeanHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkMean(b, s, wts) } func benchmarkVariance(b *testing.B, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { Variance(s, wts) } } func BenchmarkVarianceSmall(b *testing.B) { s := RandomSlice(small) benchmarkVariance(b, s, nil) } func BenchmarkVarianceMedium(b *testing.B) { s := RandomSlice(medium) benchmarkVariance(b, s, nil) } func BenchmarkVarianceLarge(b *testing.B) { s := RandomSlice(large) benchmarkVariance(b, s, nil) } func BenchmarkVarianceHuge(b *testing.B) { s := RandomSlice(huge) benchmarkVariance(b, s, nil) } func BenchmarkVarianceSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkVariance(b, s, wts) } func BenchmarkVarianceMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkVariance(b, s, wts) } func BenchmarkVarianceLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkVariance(b, s, wts) } func BenchmarkVarianceHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkVariance(b, s, wts) } func benchmarkStdDev(b *testing.B, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { StdDev(s, wts) } } func BenchmarkStdDevSmall(b *testing.B) { s := RandomSlice(small) benchmarkStdDev(b, s, nil) } func BenchmarkStdDevMedium(b *testing.B) { s := RandomSlice(medium) benchmarkStdDev(b, s, nil) } func BenchmarkStdDevLarge(b *testing.B) { s := RandomSlice(large) benchmarkStdDev(b, s, nil) } func BenchmarkStdDevHuge(b *testing.B) { s := RandomSlice(huge) benchmarkStdDev(b, s, nil) } func BenchmarkStdDevSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkStdDev(b, s, wts) } func BenchmarkStdDevMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkStdDev(b, s, wts) } func BenchmarkStdDevLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkStdDev(b, s, wts) } func BenchmarkStdDevHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkStdDev(b, s, wts) } func benchmarkMeanVariance(b *testing.B, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { MeanVariance(s, wts) } } func BenchmarkMeanVarianceSmall(b *testing.B) { s := RandomSlice(small) benchmarkMeanVariance(b, s, nil) } func BenchmarkMeanVarianceMedium(b *testing.B) { s := RandomSlice(medium) benchmarkMeanVariance(b, s, nil) } func BenchmarkMeanVarianceLarge(b *testing.B) { s := RandomSlice(large) benchmarkMeanVariance(b, s, nil) } func BenchmarkMeanVarianceHuge(b *testing.B) { s := RandomSlice(huge) benchmarkMeanVariance(b, s, nil) } func BenchmarkMeanVarianceSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkMeanVariance(b, s, wts) } func BenchmarkMeanVarianceMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkMeanVariance(b, s, wts) } func BenchmarkMeanVarianceLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkMeanVariance(b, s, wts) } func BenchmarkMeanVarianceHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkMeanVariance(b, s, wts) } func benchmarkMeanStdDev(b *testing.B, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { MeanStdDev(s, wts) } } func BenchmarkMeanStdDevSmall(b *testing.B) { s := RandomSlice(small) benchmarkMeanStdDev(b, s, nil) } func BenchmarkMeanStdDevMedium(b *testing.B) { s := RandomSlice(medium) benchmarkMeanStdDev(b, s, nil) } func BenchmarkMeanStdDevLarge(b *testing.B) { s := RandomSlice(large) benchmarkMeanStdDev(b, s, nil) } func BenchmarkMeanStdDevHuge(b *testing.B) { s := RandomSlice(huge) benchmarkMeanStdDev(b, s, nil) } func BenchmarkMeanStdDevSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkMeanStdDev(b, s, wts) } func BenchmarkMeanStdDevMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkMeanStdDev(b, s, wts) } func BenchmarkMeanStdDevLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkMeanStdDev(b, s, wts) } func BenchmarkMeanStdDevHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkMeanStdDev(b, s, wts) } func benchmarkCovariance(b *testing.B, s1, s2, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { Covariance(s1, s2, wts) } } func BenchmarkCovarianceSmall(b *testing.B) { s1 := RandomSlice(small) s2 := RandomSlice(small) benchmarkCovariance(b, s1, s2, nil) } func BenchmarkCovarianceMedium(b *testing.B) { s1 := RandomSlice(medium) s2 := RandomSlice(medium) benchmarkCovariance(b, s1, s2, nil) } func BenchmarkCovarianceLarge(b *testing.B) { s1 := RandomSlice(large) s2 := RandomSlice(large) benchmarkCovariance(b, s1, s2, nil) } func BenchmarkCovarianceHuge(b *testing.B) { s1 := RandomSlice(huge) s2 := RandomSlice(huge) benchmarkCovariance(b, s1, s2, nil) } func BenchmarkCovarianceSmallWeighted(b *testing.B) { s1 := RandomSlice(small) s2 := RandomSlice(small) wts := RandomSlice(small) benchmarkCovariance(b, s1, s2, wts) } func BenchmarkCovarianceMediumWeighted(b *testing.B) { s1 := RandomSlice(medium) s2 := RandomSlice(medium) wts := RandomSlice(medium) benchmarkCovariance(b, s1, s2, wts) } func BenchmarkCovarianceLargeWeighted(b *testing.B) { s1 := RandomSlice(large) s2 := RandomSlice(large) wts := RandomSlice(large) benchmarkCovariance(b, s1, s2, wts) } func BenchmarkCovarianceHugeWeighted(b *testing.B) { s1 := RandomSlice(huge) s2 := RandomSlice(huge) wts := RandomSlice(huge) benchmarkCovariance(b, s1, s2, wts) } func benchmarkCorrelation(b *testing.B, s1, s2, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { Correlation(s1, s2, wts) } } func BenchmarkCorrelationSmall(b *testing.B) { s1 := RandomSlice(small) s2 := RandomSlice(small) benchmarkCorrelation(b, s1, s2, nil) } func BenchmarkCorrelationMedium(b *testing.B) { s1 := RandomSlice(medium) s2 := RandomSlice(medium) benchmarkCorrelation(b, s1, s2, nil) } func BenchmarkCorrelationLarge(b *testing.B) { s1 := RandomSlice(large) s2 := RandomSlice(large) benchmarkCorrelation(b, s1, s2, nil) } func BenchmarkCorrelationHuge(b *testing.B) { s1 := RandomSlice(huge) s2 := RandomSlice(huge) benchmarkCorrelation(b, s1, s2, nil) } func BenchmarkCorrelationSmallWeighted(b *testing.B) { s1 := RandomSlice(small) s2 := RandomSlice(small) wts := RandomSlice(small) benchmarkCorrelation(b, s1, s2, wts) } func BenchmarkCorrelationMediumWeighted(b *testing.B) { s1 := RandomSlice(medium) s2 := RandomSlice(medium) wts := RandomSlice(medium) benchmarkCorrelation(b, s1, s2, wts) } func BenchmarkCorrelationLargeWeighted(b *testing.B) { s1 := RandomSlice(large) s2 := RandomSlice(large) wts := RandomSlice(large) benchmarkCorrelation(b, s1, s2, wts) } func BenchmarkCorrelationHugeWeighted(b *testing.B) { s1 := RandomSlice(huge) s2 := RandomSlice(huge) wts := RandomSlice(huge) benchmarkCorrelation(b, s1, s2, wts) } func benchmarkSkew(b *testing.B, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { Skew(s, wts) } } func BenchmarkSkewSmall(b *testing.B) { s := RandomSlice(small) benchmarkSkew(b, s, nil) } func BenchmarkSkewMedium(b *testing.B) { s := RandomSlice(medium) benchmarkSkew(b, s, nil) } func BenchmarkSkewLarge(b *testing.B) { s := RandomSlice(large) benchmarkSkew(b, s, nil) } func BenchmarkSkewHuge(b *testing.B) { s := RandomSlice(huge) benchmarkSkew(b, s, nil) } func BenchmarkSkewSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkSkew(b, s, wts) } func BenchmarkSkewMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkSkew(b, s, wts) } func BenchmarkSkewLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkSkew(b, s, wts) } func BenchmarkSkewHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkSkew(b, s, wts) } func benchmarkExKurtosis(b *testing.B, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { ExKurtosis(s, wts) } } func BenchmarkExKurtosisSmall(b *testing.B) { s := RandomSlice(small) benchmarkExKurtosis(b, s, nil) } func BenchmarkExKurtosisMedium(b *testing.B) { s := RandomSlice(medium) benchmarkExKurtosis(b, s, nil) } func BenchmarkExKurtosisLarge(b *testing.B) { s := RandomSlice(large) benchmarkExKurtosis(b, s, nil) } func BenchmarkExKurtosisHuge(b *testing.B) { s := RandomSlice(huge) benchmarkExKurtosis(b, s, nil) } func BenchmarkExKurtosisSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkExKurtosis(b, s, wts) } func BenchmarkExKurtosisMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkExKurtosis(b, s, wts) } func BenchmarkExKurtosisLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkExKurtosis(b, s, wts) } func BenchmarkExKurtosisHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkExKurtosis(b, s, wts) } func benchmarkMoment(b *testing.B, n float64, s, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { Moment(n, s, wts) } } func BenchmarkMomentSmall(b *testing.B) { s := RandomSlice(small) benchmarkMoment(b, 5, s, nil) } func BenchmarkMomentMedium(b *testing.B) { s := RandomSlice(medium) benchmarkMoment(b, 5, s, nil) } func BenchmarkMomentLarge(b *testing.B) { s := RandomSlice(large) benchmarkMoment(b, 5, s, nil) } func BenchmarkMomentHuge(b *testing.B) { s := RandomSlice(huge) benchmarkMoment(b, 5, s, nil) } func BenchmarkMomentSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkMoment(b, 5, s, wts) } func BenchmarkMomentMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkMoment(b, 5, s, wts) } func BenchmarkMomentLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkMoment(b, 5, s, wts) } func BenchmarkMomentHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkMoment(b, 5, s, wts) } func benchmarkMomentAbout(b *testing.B, n float64, s []float64, mean float64, wts []float64) { b.ResetTimer() for i := 0; i < b.N; i++ { MomentAbout(n, s, mean, wts) } } func BenchmarkMomentAboutSmall(b *testing.B) { s := RandomSlice(small) benchmarkMomentAbout(b, 5, s, 0, nil) } func BenchmarkMomentAboutMedium(b *testing.B) { s := RandomSlice(medium) benchmarkMomentAbout(b, 5, s, 0, nil) } func BenchmarkMomentAboutLarge(b *testing.B) { s := RandomSlice(large) benchmarkMomentAbout(b, 5, s, 0, nil) } func BenchmarkMomentAboutHuge(b *testing.B) { s := RandomSlice(huge) benchmarkMomentAbout(b, 5, s, 0, nil) } func BenchmarkMomentAboutSmallWeighted(b *testing.B) { s := RandomSlice(small) wts := RandomSlice(small) benchmarkMomentAbout(b, 5, s, 0, wts) } func BenchmarkMomentAboutMediumWeighted(b *testing.B) { s := RandomSlice(medium) wts := RandomSlice(medium) benchmarkMomentAbout(b, 5, s, 0, wts) } func BenchmarkMomentAboutLargeWeighted(b *testing.B) { s := RandomSlice(large) wts := RandomSlice(large) benchmarkMomentAbout(b, 5, s, 0, wts) } func BenchmarkMomentAboutHugeWeighted(b *testing.B) { s := RandomSlice(huge) wts := RandomSlice(huge) benchmarkMomentAbout(b, 5, s, 0, wts) } golang-gonum-v1-gonum-0.14.0/stat/pca_cca.go000066400000000000000000000243251450372207100205170ustar00rootroot00000000000000// Copyright ©2016 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 stat import ( "errors" "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) // PC is a type for computing and extracting the principal components of a // matrix. The results of the principal components analysis are only valid // if the call to PrincipalComponents was successful. type PC struct { n, d int weights []float64 svd *mat.SVD ok bool } // PrincipalComponents performs a weighted principal components analysis on the // matrix of the input data which is represented as an n×d matrix a where each // row is an observation and each column is a variable. // // PrincipalComponents centers the variables but does not scale the variance. // // The weights slice is used to weight the observations. If weights is nil, each // weight is considered to have a value of one, otherwise the length of weights // must match the number of observations or PrincipalComponents will panic. // // PrincipalComponents returns whether the analysis was successful. func (c *PC) PrincipalComponents(a mat.Matrix, weights []float64) (ok bool) { c.n, c.d = a.Dims() if weights != nil && len(weights) != c.n { panic("stat: len(weights) != observations") } c.svd, c.ok = svdFactorizeCentered(c.svd, a, weights) if c.ok { c.weights = append(c.weights[:0], weights...) } return c.ok } // VectorsTo returns the component direction vectors of a principal components // analysis. The vectors are returned in the columns of a d×min(n, d) matrix. // // If dst is empty, VectorsTo will resize dst to be d×min(n, d). When dst is // non-empty, VectorsTo will panic if dst is not d×min(n, d). VectorsTo will also // panic if the receiver does not contain a successful PC. func (c *PC) VectorsTo(dst *mat.Dense) { if !c.ok { panic("stat: use of unsuccessful principal components analysis") } if dst.IsEmpty() { dst.ReuseAs(c.d, min(c.n, c.d)) } else { if d, n := dst.Dims(); d != c.d || n != min(c.n, c.d) { panic(mat.ErrShape) } } c.svd.VTo(dst) } // VarsTo returns the column variances of the principal component scores, // b * vecs, where b is a matrix with centered columns. Variances are returned // in descending order. // If dst is not nil it is used to store the variances and returned. // Vars will panic if the receiver has not successfully performed a principal // components analysis or dst is not nil and the length of dst is not min(n, d). func (c *PC) VarsTo(dst []float64) []float64 { if !c.ok { panic("stat: use of unsuccessful principal components analysis") } if dst != nil && len(dst) != min(c.n, c.d) { panic("stat: length of slice does not match analysis") } dst = c.svd.Values(dst) var f float64 if c.weights == nil { f = 1 / float64(c.n-1) } else { f = 1 / (floats.Sum(c.weights) - 1) } for i, v := range dst { dst[i] = f * v * v } return dst } func min(a, b int) int { if a < b { return a } return b } // CC is a type for computing the canonical correlations of a pair of matrices. // The results of the canonical correlation analysis are only valid // if the call to CanonicalCorrelations was successful. type CC struct { // n is the number of observations used to // construct the canonical correlations. n int // xd and yd are used for size checks. xd, yd int x, y, c *mat.SVD ok bool } // CanonicalCorrelations performs a canonical correlation analysis of the // input data x and y, columns of which should be interpretable as two sets // of measurements on the same observations (rows). These observations are // optionally weighted by weights. The result of the analysis is stored in // the receiver if the analysis is successful. // // Canonical correlation analysis finds associations between two sets of // variables on the same observations by finding linear combinations of the two // sphered datasets that maximize the correlation between them. // // Some notation: let Xc and Yc denote the centered input data matrices x // and y (column means subtracted from each column), let Sx and Sy denote the // sample covariance matrices within x and y respectively, and let Sxy denote // the covariance matrix between x and y. The sphered data can then be expressed // as Xc * Sx^{-1/2} and Yc * Sy^{-1/2} respectively, and the correlation matrix // between the sphered data is called the canonical correlation matrix, // Sx^{-1/2} * Sxy * Sy^{-1/2}. In cases where S^{-1/2} is ambiguous for some // covariance matrix S, S^{-1/2} is taken to be E * D^{-1/2} * Eᵀ where S can // be eigendecomposed as S = E * D * Eᵀ. // // The canonical correlations are the correlations between the corresponding // pairs of canonical variables and can be obtained with c.Corrs(). Canonical // variables can be obtained by projecting the sphered data into the left and // right eigenvectors of the canonical correlation matrix, and these // eigenvectors can be obtained with c.Left(m, true) and c.Right(m, true) // respectively. The canonical variables can also be obtained directly from the // centered raw data by using the back-transformed eigenvectors which can be // obtained with c.Left(m, false) and c.Right(m, false) respectively. // // The first pair of left and right eigenvectors of the canonical correlation // matrix can be interpreted as directions into which the respective sphered // data can be projected such that the correlation between the two projections // is maximized. The second pair and onwards solve the same optimization but // under the constraint that they are uncorrelated (orthogonal in sphered space) // to previous projections. // // CanonicalCorrelations will panic if the inputs x and y do not have the same // number of rows. // // The slice weights is used to weight the observations. If weights is nil, each // weight is considered to have a value of one, otherwise the length of weights // must match the number of observations (rows of both x and y) or // CanonicalCorrelations will panic. // // More details can be found at // https://en.wikipedia.org/wiki/Canonical_correlation // or in Chapter 3 of // Koch, Inge. Analysis of multivariate and high-dimensional data. // Vol. 32. Cambridge University Press, 2013. ISBN: 9780521887939 func (c *CC) CanonicalCorrelations(x, y mat.Matrix, weights []float64) error { var yn int c.n, c.xd = x.Dims() yn, c.yd = y.Dims() if c.n != yn { panic("stat: unequal number of observations") } if weights != nil && len(weights) != c.n { panic("stat: len(weights) != observations") } // Center and factorize x and y. c.x, c.ok = svdFactorizeCentered(c.x, x, weights) if !c.ok { return errors.New("stat: failed to factorize x") } c.y, c.ok = svdFactorizeCentered(c.y, y, weights) if !c.ok { return errors.New("stat: failed to factorize y") } var xu, xv, yu, yv mat.Dense c.x.UTo(&xu) c.x.VTo(&xv) c.y.UTo(&yu) c.y.VTo(&yv) // Calculate and factorise the canonical correlation matrix. var ccor mat.Dense ccor.Product(&xv, xu.T(), &yu, yv.T()) if c.c == nil { c.c = &mat.SVD{} } c.ok = c.c.Factorize(&ccor, mat.SVDThin) if !c.ok { return errors.New("stat: failed to factorize ccor") } return nil } // CorrsTo returns the canonical correlations, using dst if it is not nil. // If dst is not nil and len(dst) does not match the number of columns in // the y input matrix, Corrs will panic. func (c *CC) CorrsTo(dst []float64) []float64 { if !c.ok { panic("stat: canonical correlations missing or invalid") } if dst != nil && len(dst) != c.yd { panic("stat: length of destination does not match input dimension") } return c.c.Values(dst) } // LeftTo returns the left eigenvectors of the canonical correlation matrix if // spheredSpace is true. If spheredSpace is false it returns these eigenvectors // back-transformed to the original data space. // // If dst is empty, LeftTo will resize dst to be xd×yd. When dst is // non-empty, LeftTo will panic if dst is not xd×yd. LeftTo will also // panic if the receiver does not contain a successful CC. func (c *CC) LeftTo(dst *mat.Dense, spheredSpace bool) { if !c.ok || c.n < 2 { panic("stat: canonical correlations missing or invalid") } if dst.IsEmpty() { dst.ReuseAs(c.xd, c.yd) } else { if d, n := dst.Dims(); d != c.xd || n != c.yd { panic(mat.ErrShape) } } c.c.UTo(dst) if spheredSpace { return } xs := c.x.Values(nil) xv := &mat.Dense{} c.x.VTo(xv) scaleColsReciSqrt(xv, xs) dst.Product(xv, xv.T(), dst) dst.Scale(math.Sqrt(float64(c.n-1)), dst) } // RightTo returns the right eigenvectors of the canonical correlation matrix if // spheredSpace is true. If spheredSpace is false it returns these eigenvectors // back-transformed to the original data space. // // If dst is empty, RightTo will resize dst to be yd×yd. When dst is // non-empty, RightTo will panic if dst is not yd×yd. RightTo will also // panic if the receiver does not contain a successful CC. func (c *CC) RightTo(dst *mat.Dense, spheredSpace bool) { if !c.ok || c.n < 2 { panic("stat: canonical correlations missing or invalid") } if dst.IsEmpty() { dst.ReuseAs(c.yd, c.yd) } else { if d, n := dst.Dims(); d != c.yd || n != c.yd { panic(mat.ErrShape) } } c.c.VTo(dst) if spheredSpace { return } ys := c.y.Values(nil) yv := &mat.Dense{} c.y.VTo(yv) scaleColsReciSqrt(yv, ys) dst.Product(yv, yv.T(), dst) dst.Scale(math.Sqrt(float64(c.n-1)), dst) } func svdFactorizeCentered(work *mat.SVD, m mat.Matrix, weights []float64) (svd *mat.SVD, ok bool) { n, d := m.Dims() centered := mat.NewDense(n, d, nil) col := make([]float64, n) for j := 0; j < d; j++ { mat.Col(col, j, m) floats.AddConst(-Mean(col, weights), col) centered.SetCol(j, col) } for i, w := range weights { floats.Scale(math.Sqrt(w), centered.RawRowView(i)) } if work == nil { work = &mat.SVD{} } ok = work.Factorize(centered, mat.SVDThin) return work, ok } // scaleColsReciSqrt scales the columns of cols // by the reciprocal square-root of vals. func scaleColsReciSqrt(cols *mat.Dense, vals []float64) { if cols == nil { panic("stat: input nil") } n, d := cols.Dims() if len(vals) != d { panic("stat: input length mismatch") } col := make([]float64, n) for j := 0; j < d; j++ { mat.Col(col, j, cols) floats.Scale(math.Sqrt(1/vals[j]), col) cols.SetCol(j, col) } } golang-gonum-v1-gonum-0.14.0/stat/pca_example_test.go000066400000000000000000000026751450372207100224670ustar00rootroot00000000000000// Copyright ©2016 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 stat_test import ( "fmt" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat" ) func ExamplePC() { // iris is a truncated sample of the Fisher's Iris dataset. n := 10 d := 4 iris := mat.NewDense(n, d, []float64{ 5.1, 3.5, 1.4, 0.2, 4.9, 3.0, 1.4, 0.2, 4.7, 3.2, 1.3, 0.2, 4.6, 3.1, 1.5, 0.2, 5.0, 3.6, 1.4, 0.2, 5.4, 3.9, 1.7, 0.4, 4.6, 3.4, 1.4, 0.3, 5.0, 3.4, 1.5, 0.2, 4.4, 2.9, 1.4, 0.2, 4.9, 3.1, 1.5, 0.1, }) // Calculate the principal component direction vectors // and variances. var pc stat.PC ok := pc.PrincipalComponents(iris, nil) if !ok { return } fmt.Printf("variances = %.4f\n\n", pc.VarsTo(nil)) // Project the data onto the first 2 principal components. k := 2 var proj mat.Dense var vec mat.Dense pc.VectorsTo(&vec) proj.Mul(iris, vec.Slice(0, d, 0, k)) fmt.Printf("proj = %.4f", mat.Formatted(&proj, mat.Prefix(" "))) // Output: // variances = [0.1666 0.0207 0.0079 0.0019] // // proj = ⎡-6.1686 1.4659⎤ // ⎢-5.6767 1.6459⎥ // ⎢-5.6699 1.3642⎥ // ⎢-5.5643 1.3816⎥ // ⎢-6.1734 1.3309⎥ // ⎢-6.7278 1.4021⎥ // ⎢-5.7743 1.1498⎥ // ⎢-6.0466 1.4714⎥ // ⎢-5.2709 1.3570⎥ // ⎣-5.7533 1.6207⎦ } golang-gonum-v1-gonum-0.14.0/stat/pca_test.go000066400000000000000000000157111450372207100207470ustar00rootroot00000000000000// Copyright ©2016 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 stat import ( "math" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func TestPrincipalComponents(t *testing.T) { // Threshold for detecting zero variances. const epsilon = 1e-15 tests: for i, test := range []struct { data mat.Matrix weights []float64 wantVecs *mat.Dense wantVars []float64 epsilon float64 }{ // Test results verified using R. { data: mat.NewDense(3, 3, []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }), wantVecs: mat.NewDense(3, 3, []float64{ 0.5773502691896258, 0.8164965809277261, 0, 0.577350269189626, -0.4082482904638632, -0.7071067811865476, 0.5773502691896258, -0.4082482904638631, 0.7071067811865475, }), wantVars: []float64{27, 0, 0}, epsilon: 1e-12, }, { // Truncated iris data. data: mat.NewDense(10, 4, []float64{ 5.1, 3.5, 1.4, 0.2, 4.9, 3.0, 1.4, 0.2, 4.7, 3.2, 1.3, 0.2, 4.6, 3.1, 1.5, 0.2, 5.0, 3.6, 1.4, 0.2, 5.4, 3.9, 1.7, 0.4, 4.6, 3.4, 1.4, 0.3, 5.0, 3.4, 1.5, 0.2, 4.4, 2.9, 1.4, 0.2, 4.9, 3.1, 1.5, 0.1, }), wantVecs: mat.NewDense(4, 4, []float64{ -0.6681110197952723, 0.706476485753953, 0.14026590216895127, 0.18666578956412122, -0.7166344774801547, -0.6427036135482663, 0.13565028590525394, -0.23444848208629923, -0.16441127516630702, 0.11898477441068217, -0.9136367900709544, -0.35224901970831735, -0.11415613655453066, -0.27141419208874273, -0.3566402843922649, 0.8866286823515032, }), wantVars: []float64{0.1665786313282786, 0.02065509475412993, 0.007944620317765855, 0.0019327647109368329}, epsilon: 1e-12, }, { // Truncated iris data to form wide matrix. data: mat.NewDense(3, 4, []float64{ 5.1, 3.5, 1.4, 0.2, 4.9, 3.0, 1.4, 0.2, 4.7, 3.2, 1.3, 0.2, }), wantVecs: mat.NewDense(4, 3, []float64{ -0.5705187254552365, -0.7505979435049239, 0.08084520834544455, -0.8166537769529318, 0.5615147645527523, -0.032338083338177705, -0.08709186238359454, -0.3482870890450082, -0.22636658336724505, 0, 0, -0.9701425001453315, }), wantVars: []float64{0.0844692361537822, 0.022197430512884326, 0}, epsilon: 1e-12, }, { // Truncated iris data transposed to check for operation on fat input. data: mat.NewDense(10, 4, []float64{ 5.1, 3.5, 1.4, 0.2, 4.9, 3.0, 1.4, 0.2, 4.7, 3.2, 1.3, 0.2, 4.6, 3.1, 1.5, 0.2, 5.0, 3.6, 1.4, 0.2, 5.4, 3.9, 1.7, 0.4, 4.6, 3.4, 1.4, 0.3, 5.0, 3.4, 1.5, 0.2, 4.4, 2.9, 1.4, 0.2, 4.9, 3.1, 1.5, 0.1, }).T(), wantVecs: mat.NewDense(10, 4, []float64{ -0.3366602459946619, -0.1373634006401213, 0.3465102523547623, -0.10290179303893479, -0.31381852053861975, 0.5197145790632827, 0.5567296129086686, -0.15923062170153618, -0.30857197637565165, -0.07670930360819002, 0.36159923003337235, 0.3342301027853355, -0.29527124351656137, 0.16885455995353074, -0.5056204762881208, 0.32580913261444344, -0.3327611073694004, -0.39365834489416474, 0.04900050959307464, 0.46812879383236555, -0.34445484362044815, -0.2985206914561878, -0.1009714701361799, -0.16803618186050803, -0.2986246350957691, -0.4222037823717799, -0.11838613462182519, -0.580283530375069, -0.325911246223126, 0.024366468758217238, -0.12082035131864265, 0.16756027181337868, -0.2814284432361538, 0.240812316260054, -0.24061437569068145, -0.365034616264623, -0.31906138507685167, 0.4423912824105986, -0.2906412122303604, 0.027551046870337714, }), wantVars: []float64{41.8851906634233, 0.07762619213464989, 0.010516477775373585, 0}, epsilon: 1e-12, }, { // Truncated iris data unitary weights. data: mat.NewDense(10, 4, []float64{ 5.1, 3.5, 1.4, 0.2, 4.9, 3.0, 1.4, 0.2, 4.7, 3.2, 1.3, 0.2, 4.6, 3.1, 1.5, 0.2, 5.0, 3.6, 1.4, 0.2, 5.4, 3.9, 1.7, 0.4, 4.6, 3.4, 1.4, 0.3, 5.0, 3.4, 1.5, 0.2, 4.4, 2.9, 1.4, 0.2, 4.9, 3.1, 1.5, 0.1, }), weights: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, wantVecs: mat.NewDense(4, 4, []float64{ -0.6681110197952723, 0.706476485753953, 0.14026590216895127, 0.18666578956412122, -0.7166344774801547, -0.6427036135482663, 0.13565028590525394, -0.23444848208629923, -0.16441127516630702, 0.11898477441068217, -0.9136367900709544, -0.35224901970831735, -0.11415613655453066, -0.27141419208874273, -0.3566402843922649, 0.8866286823515032, }), wantVars: []float64{0.1665786313282786, 0.02065509475412993, 0.007944620317765855, 0.0019327647109368329}, epsilon: 1e-12, }, { // Truncated iris data non-unitary weights. data: mat.NewDense(10, 4, []float64{ 5.1, 3.5, 1.4, 0.2, 4.9, 3.0, 1.4, 0.2, 4.7, 3.2, 1.3, 0.2, 4.6, 3.1, 1.5, 0.2, 5.0, 3.6, 1.4, 0.2, 5.4, 3.9, 1.7, 0.4, 4.6, 3.4, 1.4, 0.3, 5.0, 3.4, 1.5, 0.2, 4.4, 2.9, 1.4, 0.2, 4.9, 3.1, 1.5, 0.1, }), weights: []float64{2, 3, 1, 1, 1, 1, 1, 1, 1, 2}, wantVecs: mat.NewDense(4, 4, []float64{ -0.618936145422414, 0.763069301531647, 0.124857741232537, 0.138035623677211, -0.763958271606519, -0.603881770702898, 0.118267155321333, -0.194184052457746, -0.143552119754944, 0.090014599564871, -0.942209377020044, -0.289018426115945, -0.112599271966947, -0.212012782487076, -0.287515067921680, 0.927203898682805, }), wantVars: []float64{0.129621985550623, 0.022417487771598, 0.006454461065715, 0.002495076601075}, epsilon: 1e-12, }, } { var pc PC vecs := &mat.Dense{} var vars []float64 for j := 0; j < 2; j++ { ok := pc.PrincipalComponents(test.data, test.weights) pc.VectorsTo(vecs) vars = pc.VarsTo(vars) if !ok { t.Errorf("unexpected SVD failure for test %d use %d", i, j) continue tests } // Find the number of non-zero variances to handle // non-uniqueness in SVD result (issue #21). nnz := len(vars) for k, v := range vars { if math.Abs(v) < epsilon { nnz = k break } } r, c := vecs.Dims() if !mat.EqualApprox(vecs.Slice(0, r, 0, nnz), test.wantVecs.Slice(0, r, 0, nnz), test.epsilon) { t.Errorf("%d use %d: unexpected PCA result got:\n%v\nwant:\n%v", i, j, mat.Formatted(vecs), mat.Formatted(test.wantVecs)) } if !approxEqual(vars, test.wantVars, test.epsilon) { t.Errorf("%d use %d: unexpected variance result got:%v, want:%v", i, j, vars, test.wantVars) } // Check that the set of principal vectors is // orthonormal by comparing Vᵀ*V to the identity matrix. I := mat.NewDiagDense(c, nil) for k := 0; k < c; k++ { I.SetDiag(k, 1) } var vv mat.Dense vv.Mul(vecs.T(), vecs) if !mat.EqualApprox(&vv, I, test.epsilon) { t.Errorf("%d use %d: vectors not orthonormal\n%v", i, j, mat.Formatted(I)) } } } } func approxEqual(a, b []float64, epsilon float64) bool { if len(a) != len(b) { return false } for i, v := range a { if !scalar.EqualWithinAbsOrRel(v, b[i], epsilon, epsilon) { return false } } return true } golang-gonum-v1-gonum-0.14.0/stat/roc.go000066400000000000000000000150071450372207100177260ustar00rootroot00000000000000// Copyright ©2016 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 stat import ( "math" "sort" ) // ROC returns paired false positive rate (FPR) and true positive rate // (TPR) values corresponding to cutoff points on the receiver operator // characteristic (ROC) curve obtained when y is treated as a binary // classifier for classes with weights. The cutoff thresholds used to // calculate the ROC are returned in thresh such that tpr[i] and fpr[i] // are the true and false positive rates for y >= thresh[i]. // // The input y and cutoffs must be sorted, and values in y must correspond // to values in classes and weights. SortWeightedLabeled can be used to // sort y together with classes and weights. // // For a given cutoff value, observations corresponding to entries in y // greater than the cutoff value are classified as true, while those // less than or equal to the cutoff value are classified as false. These // assigned class labels are compared with the true values in the classes // slice and used to calculate the FPR and TPR. // // If weights is nil, all weights are treated as 1. If weights is not nil // it must have the same length as y and classes, otherwise ROC will panic. // // If cutoffs is nil or empty, all possible cutoffs are calculated, // resulting in fpr and tpr having length one greater than the number of // unique values in y. Otherwise fpr and tpr will be returned with the // same length as cutoffs. floats.Span can be used to generate equally // spaced cutoffs. // // More details about ROC curves are available at // https://en.wikipedia.org/wiki/Receiver_operating_characteristic func ROC(cutoffs, y []float64, classes []bool, weights []float64) (tpr, fpr, thresh []float64) { if len(y) != len(classes) { panic("stat: slice length mismatch") } if weights != nil && len(y) != len(weights) { panic("stat: slice length mismatch") } if !sort.Float64sAreSorted(y) { panic("stat: input must be sorted ascending") } if !sort.Float64sAreSorted(cutoffs) { panic("stat: cutoff values must be sorted ascending") } if len(y) == 0 { return nil, nil, nil } if len(cutoffs) == 0 { if cutoffs == nil || cap(cutoffs) < len(y)+1 { cutoffs = make([]float64, len(y)+1) } else { cutoffs = cutoffs[:len(y)+1] } // Choose all possible cutoffs for unique values in y. bin := 0 cutoffs[bin] = y[0] for i, u := range y[1:] { if u == y[i] { continue } bin++ cutoffs[bin] = u } cutoffs[bin+1] = math.Inf(1) cutoffs = cutoffs[:bin+2] } else { // Don't mutate the provided cutoffs. tmp := cutoffs cutoffs = make([]float64, len(cutoffs)) copy(cutoffs, tmp) } tpr = make([]float64, len(cutoffs)) fpr = make([]float64, len(cutoffs)) var bin int var nPos, nNeg float64 for i, u := range classes { // Update the bin until it matches the next y value // skipping empty bins. for bin < len(cutoffs)-1 && y[i] >= cutoffs[bin] { bin++ tpr[bin] = tpr[bin-1] fpr[bin] = fpr[bin-1] } posWeight, negWeight := 1.0, 0.0 if weights != nil { posWeight = weights[i] } if !u { posWeight, negWeight = negWeight, posWeight } nPos += posWeight nNeg += negWeight // Count false negatives (in tpr) and true negatives (in fpr). if y[i] < cutoffs[bin] { tpr[bin] += posWeight fpr[bin] += negWeight } } invNeg := 1 / nNeg invPos := 1 / nPos // Convert negative counts to TPR and FPR. // Bins beyond the maximum value in y are skipped // leaving these fpr and tpr elements as zero. for i := range tpr[:bin+1] { // Prevent fused float operations by // making explicit float64 conversions. tpr[i] = 1 - float64(tpr[i]*invPos) fpr[i] = 1 - float64(fpr[i]*invNeg) } for i, j := 0, len(tpr)-1; i < j; i, j = i+1, j-1 { tpr[i], tpr[j] = tpr[j], tpr[i] fpr[i], fpr[j] = fpr[j], fpr[i] } for i, j := 0, len(cutoffs)-1; i < j; i, j = i+1, j-1 { cutoffs[i], cutoffs[j] = cutoffs[j], cutoffs[i] } return tpr, fpr, cutoffs } // TOC returns the Total Operating Characteristic for the classes provided // and the minimum and maximum bounds for the TOC. // // The input y values that correspond to classes and weights must be sorted // in ascending order. classes[i] is the class of value y[i] and weights[i] // is the weight of y[i]. SortWeightedLabeled can be used to sort classes // together with weights by the rank variable, i+1. // // The returned ntp values can be interpreted as the number of true positives // where values above the given rank are assigned class true for each given // rank from 1 to len(classes). // // ntp_i = sum_{j ≥ len(ntp)-1 - i} [ classes_j ] * weights_j, where [x] = 1 if x else 0. // // The values of min and max provide the minimum and maximum possible number // of false values for the set of classes. The first element of ntp, min and // max are always zero as this corresponds to assigning all data class false // and the last elements are always weighted sum of classes as this corresponds // to assigning every data class true. For len(classes) != 0, the lengths of // min, ntp and max are len(classes)+1. // // If weights is nil, all weights are treated as 1. When weights are not nil, // the calculation of min and max allows for partial assignment of single data // points. If weights is not nil it must have the same length as classes, // otherwise TOC will panic. // // More details about TOC curves are available at // https://en.wikipedia.org/wiki/Total_operating_characteristic func TOC(classes []bool, weights []float64) (min, ntp, max []float64) { if weights != nil && len(classes) != len(weights) { panic("stat: slice length mismatch") } if len(classes) == 0 { return nil, nil, nil } ntp = make([]float64, len(classes)+1) min = make([]float64, len(ntp)) max = make([]float64, len(ntp)) if weights == nil { for i := range ntp[1:] { ntp[i+1] = ntp[i] if classes[len(classes)-i-1] { ntp[i+1]++ } } totalPositive := ntp[len(ntp)-1] for i := range ntp { min[i] = math.Max(0, totalPositive-float64(len(classes)-i)) max[i] = math.Min(totalPositive, float64(i)) } return min, ntp, max } cumw := max // Reuse max for cumulative weight. Update its elements last. for i := range ntp[1:] { ntp[i+1] = ntp[i] w := weights[len(weights)-i-1] cumw[i+1] = cumw[i] + w if classes[len(classes)-i-1] { ntp[i+1] += w } } totw := cumw[len(cumw)-1] totalPositive := ntp[len(ntp)-1] for i := range ntp { min[i] = math.Max(0, totalPositive-(totw-cumw[i])) max[i] = math.Min(totalPositive, cumw[i]) } return min, ntp, max } golang-gonum-v1-gonum-0.14.0/stat/roc_example_test.go000066400000000000000000000155111450372207100225000ustar00rootroot00000000000000// Copyright ©2016 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 stat_test import ( "fmt" "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/integrate" "gonum.org/v1/gonum/stat" ) func ExampleROC_weighted() { y := []float64{0, 3, 5, 6, 7.5, 8} classes := []bool{false, true, false, true, true, true} weights := []float64{4, 1, 6, 3, 2, 2} tpr, fpr, _ := stat.ROC(nil, y, classes, weights) fmt.Printf("true positive rate: %v\n", tpr) fmt.Printf("false positive rate: %v\n", fpr) // Output: // true positive rate: [0 0.25 0.5 0.875 0.875 1 1] // false positive rate: [0 0 0 0 0.6 0.6 1] } func ExampleROC_unweighted() { y := []float64{0, 3, 5, 6, 7.5, 8} classes := []bool{false, true, false, true, true, true} tpr, fpr, _ := stat.ROC(nil, y, classes, nil) fmt.Printf("true positive rate: %v\n", tpr) fmt.Printf("false positive rate: %v\n", fpr) // Output: // true positive rate: [0 0.25 0.5 0.75 0.75 1 1] // false positive rate: [0 0 0 0 0.5 0.5 1] } func ExampleROC_threshold() { y := []float64{0.1, 0.4, 0.35, 0.8} classes := []bool{false, false, true, true} stat.SortWeightedLabeled(y, classes, nil) tpr, fpr, thresh := stat.ROC(nil, y, classes, nil) fmt.Printf("true positive rate: %v\n", tpr) fmt.Printf("false positive rate: %v\n", fpr) fmt.Printf("cutoff thresholds: %v\n", thresh) // Output: // true positive rate: [0 0.5 0.5 1 1] // false positive rate: [0 0 0.5 0.5 1] // cutoff thresholds: [+Inf 0.8 0.4 0.35 0.1] } func ExampleROC_unsorted() { y := []float64{8, 7.5, 6, 5, 3, 0} classes := []bool{true, true, true, false, true, false} weights := []float64{2, 2, 3, 6, 1, 4} stat.SortWeightedLabeled(y, classes, weights) tpr, fpr, _ := stat.ROC(nil, y, classes, weights) fmt.Printf("true positive rate: %v\n", tpr) fmt.Printf("false positive rate: %v\n", fpr) // Output: // true positive rate: [0 0.25 0.5 0.875 0.875 1 1] // false positive rate: [0 0 0 0 0.6 0.6 1] } func ExampleROC_knownCutoffs() { y := []float64{8, 7.5, 6, 5, 3, 0} classes := []bool{true, true, true, false, true, false} weights := []float64{2, 2, 3, 6, 1, 4} cutoffs := []float64{-1, 3, 4} stat.SortWeightedLabeled(y, classes, weights) tpr, fpr, _ := stat.ROC(cutoffs, y, classes, weights) fmt.Printf("true positive rate: %v\n", tpr) fmt.Printf("false positive rate: %v\n", fpr) // Output: // true positive rate: [0.875 1 1] // false positive rate: [0.6 0.6 1] } func ExampleROC_equallySpacedCutoffs() { y := []float64{8, 7.5, 6, 5, 3, 0} classes := []bool{true, true, true, false, true, true} weights := []float64{2, 2, 3, 6, 1, 4} n := 9 stat.SortWeightedLabeled(y, classes, weights) cutoffs := make([]float64, n) floats.Span(cutoffs, math.Nextafter(y[0], y[0]-1), y[len(y)-1]) tpr, fpr, _ := stat.ROC(cutoffs, y, classes, weights) fmt.Printf("true positive rate: %.3v\n", tpr) fmt.Printf("false positive rate: %.3v\n", fpr) // Output: // true positive rate: [0.167 0.333 0.583 0.583 0.583 0.667 0.667 0.667 1] // false positive rate: [0 0 0 1 1 1 1 1 1] } func ExampleROC_aUC_unweighted() { y := []float64{0.1, 0.35, 0.4, 0.8} classes := []bool{true, false, true, false} tpr, fpr, _ := stat.ROC(nil, y, classes, nil) // Compute Area Under Curve. auc := integrate.Trapezoidal(fpr, tpr) fmt.Printf("true positive rate: %v\n", tpr) fmt.Printf("false positive rate: %v\n", fpr) fmt.Printf("auc: %v\n", auc) // Output: // true positive rate: [0 0 0.5 0.5 1] // false positive rate: [0 0.5 0.5 1 1] // auc: 0.25 } func ExampleROC_aUC_weighted() { y := []float64{0.1, 0.35, 0.4, 0.8} classes := []bool{true, false, true, false} weights := []float64{1, 2, 2, 1} tpr, fpr, _ := stat.ROC(nil, y, classes, weights) // Compute Area Under Curve. auc := integrate.Trapezoidal(fpr, tpr) fmt.Printf("auc: %f\n", auc) // Output: // auc: 0.444444 } func ExampleTOC() { classes := []bool{ false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, false, false, true, false, true, false, false, true, false, } min, ntp, max := stat.TOC(classes, nil) fmt.Printf("minimum bound: %v\n", min) fmt.Printf("TOC: %v\n", ntp) fmt.Printf("maximum bound: %v\n", max) // Output: // minimum bound: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10] // TOC: [0 0 1 1 1 2 2 3 3 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10] // maximum bound: [0 1 2 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10] } func ExampleTOC_unsorted() { y := []float64{8, 7.5, 6, 5, 3, 0} classes := []bool{true, false, true, false, false, false} weights := []float64{4, 1, 6, 3, 2, 2} stat.SortWeightedLabeled(y, classes, weights) min, ntp, max := stat.TOC(classes, weights) fmt.Printf("minimum bound: %v\n", min) fmt.Printf("TOC: %v\n", ntp) fmt.Printf("maximum bound: %v\n", max) // Output: // minimum bound: [0 0 0 3 6 8 10] // TOC: [0 4 4 10 10 10 10] // maximum bound: [0 4 5 10 10 10 10] } func ExampleTOC_aUC_unweighted() { classes := []bool{true, false, true, false} _, ntp, _ := stat.TOC(classes, nil) pos := ntp[len(ntp)-1] base := float64(len(classes)) - pos // Compute the area under ntp and under the // minimum bound. x := floats.Span(make([]float64, len(classes)+1), 0, float64(len(classes))) aucNTP := integrate.Trapezoidal(x, ntp) aucMin := pos * pos / 2 // Calculate the the area under the curve // within the bounding parallelogram. auc := aucNTP - aucMin // Calculate the area within the bounding // parallelogram. par := pos * base // The AUC is the ratio of the area under // the curve within the bounding parallelogram // and the total parallelogram bound. auc /= par fmt.Printf("number of true positives: %v\n", ntp) fmt.Printf("auc: %v\n", auc) // Output: // number of true positives: [0 0 1 1 2] // auc: 0.25 } func ExampleTOC_aUC_weighted() { classes := []bool{true, false, true, false} weights := []float64{1, 2, 2, 1} min, ntp, max := stat.TOC(classes, weights) // Compute the area under ntp and under the // minimum and maximum bounds. x := make([]float64, len(classes)+1) floats.CumSum(x[1:], weights) aucNTP := integrate.Trapezoidal(x, ntp) aucMin := integrate.Trapezoidal(x, min) aucMax := integrate.Trapezoidal(x, max) // Calculate the the area under the curve // within the bounding parallelogram. auc := aucNTP - aucMin // Calculate the area within the bounding // parallelogram. par := aucMax - aucMin // The AUC is the ratio of the area under // the curve within the bounding parallelogram // and the total parallelogram bound. auc /= par fmt.Printf("number of true positives: %v\n", ntp) fmt.Printf("auc: %f\n", auc) // Output: // number of true positives: [0 0 2 2 3] // auc: 0.444444 } golang-gonum-v1-gonum-0.14.0/stat/roc_test.go000066400000000000000000000265641450372207100207770ustar00rootroot00000000000000// Copyright ©2016 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 stat import ( "math" "testing" "gonum.org/v1/gonum/floats" ) func TestROC(t *testing.T) { const tol = 1e-14 cases := []struct { y []float64 c []bool w []float64 cutoffs []float64 wantTPR []float64 wantFPR []float64 wantThresh []float64 }{ // Test cases were informed by using sklearn metrics.roc_curve when // cutoffs is nil, but all test cases (including when cutoffs is not // nil) were calculated manually. // Some differences exist between unweighted ROCs from our function // and metrics.roc_curve which appears to use integer cutoffs in that // case. sklearn also appears to do some magic that trims leading zeros // sometimes. { // 0 y: []float64{0, 3, 5, 6, 7.5, 8}, c: []bool{false, true, false, true, true, true}, wantTPR: []float64{0, 0.25, 0.5, 0.75, 0.75, 1, 1}, wantFPR: []float64{0, 0, 0, 0, 0.5, 0.5, 1}, wantThresh: []float64{math.Inf(1), 8, 7.5, 6, 5, 3, 0}, }, { // 1 y: []float64{0, 3, 5, 6, 7.5, 8}, c: []bool{false, true, false, true, true, true}, w: []float64{4, 1, 6, 3, 2, 2}, wantTPR: []float64{0, 0.25, 0.5, 0.875, 0.875, 1, 1}, wantFPR: []float64{0, 0, 0, 0, 0.6, 0.6, 1}, wantThresh: []float64{math.Inf(1), 8, 7.5, 6, 5, 3, 0}, }, { // 2 y: []float64{0, 3, 5, 6, 7.5, 8}, c: []bool{false, true, false, true, true, true}, cutoffs: []float64{-1, 2, 4, 6, 8}, wantTPR: []float64{0.25, 0.75, 0.75, 1, 1}, wantFPR: []float64{0, 0, 0.5, 0.5, 1}, wantThresh: []float64{8, 6, 4, 2, -1}, }, { // 3 y: []float64{0, 3, 5, 6, 7.5, 8}, c: []bool{false, true, false, true, true, true}, cutoffs: []float64{-1, 1, 2, 3, 4, 5, 6, 7, 8}, wantTPR: []float64{0.25, 0.5, 0.75, 0.75, 0.75, 1, 1, 1, 1}, wantFPR: []float64{0, 0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 1}, wantThresh: []float64{8, 7, 6, 5, 4, 3, 2, 1, -1}, }, { // 4 y: []float64{0, 3, 5, 6, 7.5, 8}, c: []bool{false, true, false, true, true, true}, w: []float64{4, 1, 6, 3, 2, 2}, cutoffs: []float64{-1, 2, 4, 6, 8}, wantTPR: []float64{0.25, 0.875, 0.875, 1, 1}, wantFPR: []float64{0, 0, 0.6, 0.6, 1}, wantThresh: []float64{8, 6, 4, 2, -1}, }, { // 5 y: []float64{0, 3, 5, 6, 7.5, 8}, c: []bool{false, true, false, true, true, true}, w: []float64{4, 1, 6, 3, 2, 2}, cutoffs: []float64{-1, 1, 2, 3, 4, 5, 6, 7, 8}, wantTPR: []float64{0.25, 0.5, 0.875, 0.875, 0.875, 1, 1, 1, 1}, wantFPR: []float64{0, 0, 0, 0.6, 0.6, 0.6, 0.6, 0.6, 1}, wantThresh: []float64{8, 7, 6, 5, 4, 3, 2, 1, -1}, }, { // 6 y: []float64{0, 3, 6, 6, 6, 8}, c: []bool{false, true, false, true, true, true}, wantTPR: []float64{0, 0.25, 0.75, 1, 1}, wantFPR: []float64{0, 0, 0.5, 0.5, 1}, wantThresh: []float64{math.Inf(1), 8, 6, 3, 0}, }, { // 7 y: []float64{0, 3, 6, 6, 6, 8}, c: []bool{false, true, false, true, true, true}, w: []float64{4, 1, 6, 3, 2, 2}, wantTPR: []float64{0, 0.25, 0.875, 1, 1}, wantFPR: []float64{0, 0, 0.6, 0.6, 1}, wantThresh: []float64{math.Inf(1), 8, 6, 3, 0}, }, { // 8 y: []float64{0, 3, 6, 6, 6, 8}, c: []bool{false, true, false, true, true, true}, cutoffs: []float64{-1, 2, 4, 6, 8}, wantTPR: []float64{0.25, 0.75, 0.75, 1, 1}, wantFPR: []float64{0, 0.5, 0.5, 0.5, 1}, wantThresh: []float64{8, 6, 4, 2, -1}, }, { // 9 y: []float64{0, 3, 6, 6, 6, 8}, c: []bool{false, true, false, true, true, true}, cutoffs: []float64{-1, 1, 2, 3, 4, 5, 6, 7, 8}, wantTPR: []float64{0.25, 0.25, 0.75, 0.75, 0.75, 1, 1, 1, 1}, wantFPR: []float64{0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1}, wantThresh: []float64{8, 7, 6, 5, 4, 3, 2, 1, -1}, }, { // 10 y: []float64{0, 3, 6, 6, 6, 8}, c: []bool{false, true, false, true, true, true}, w: []float64{4, 1, 6, 3, 2, 2}, cutoffs: []float64{-1, 2, 4, 6, 8}, wantTPR: []float64{0.25, 0.875, 0.875, 1, 1}, wantFPR: []float64{0, 0.6, 0.6, 0.6, 1}, wantThresh: []float64{8, 6, 4, 2, -1}, }, { // 11 y: []float64{0, 3, 6, 6, 6, 8}, c: []bool{false, true, false, true, true, true}, w: []float64{4, 1, 6, 3, 2, 2}, cutoffs: []float64{-1, 1, 2, 3, 4, 5, 6, 7, 8}, wantTPR: []float64{0.25, 0.25, 0.875, 0.875, 0.875, 1, 1, 1, 1}, wantFPR: []float64{0, 0, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 1}, wantThresh: []float64{8, 7, 6, 5, 4, 3, 2, 1, -1}, }, { // 12 y: []float64{0.1, 0.35, 0.4, 0.8}, c: []bool{true, false, true, false}, wantTPR: []float64{0, 0, 0.5, 0.5, 1}, wantFPR: []float64{0, 0.5, 0.5, 1, 1}, wantThresh: []float64{math.Inf(1), 0.8, 0.4, 0.35, 0.1}, }, { // 13 y: []float64{0.1, 0.35, 0.4, 0.8}, c: []bool{false, false, true, true}, wantTPR: []float64{0, 0.5, 1, 1, 1}, wantFPR: []float64{0, 0, 0, 0.5, 1}, wantThresh: []float64{math.Inf(1), 0.8, 0.4, 0.35, 0.1}, }, { // 14 y: []float64{0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 10}, c: []bool{false, true, false, false, true, true, false}, cutoffs: []float64{-1, 2.5, 5, 7.5, 10}, wantTPR: []float64{0, 0, 0, 0, 1}, wantFPR: []float64{0.25, 0.25, 0.25, 0.25, 1}, wantThresh: []float64{10, 7.5, 5, 2.5, -1}, }, { // 15 y: []float64{1, 2}, c: []bool{false, false}, wantTPR: []float64{math.NaN(), math.NaN(), math.NaN()}, wantFPR: []float64{0, 0.5, 1}, wantThresh: []float64{math.Inf(1), 2, 1}, }, { // 16 y: []float64{1, 2}, c: []bool{false, false}, cutoffs: []float64{-1, 2}, wantTPR: []float64{math.NaN(), math.NaN()}, wantFPR: []float64{0.5, 1}, wantThresh: []float64{2, -1}, }, { // 17 y: []float64{1, 2}, c: []bool{false, false}, cutoffs: []float64{0, 1.2, 1.4, 1.6, 1.8, 2}, wantTPR: []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, wantFPR: []float64{0.5, 0.5, 0.5, 0.5, 0.5, 1}, wantThresh: []float64{2, 1.8, 1.6, 1.4, 1.2, 0}, }, { // 18 y: []float64{1}, c: []bool{false}, wantTPR: []float64{math.NaN(), math.NaN()}, wantFPR: []float64{0, 1}, wantThresh: []float64{math.Inf(1), 1}, }, { // 19 y: []float64{1}, c: []bool{false}, cutoffs: []float64{-1, 1}, wantTPR: []float64{math.NaN(), math.NaN()}, wantFPR: []float64{1, 1}, wantThresh: []float64{1, -1}, }, { // 20 y: []float64{1}, c: []bool{true}, wantTPR: []float64{0, 1}, wantFPR: []float64{math.NaN(), math.NaN()}, wantThresh: []float64{math.Inf(1), 1}, }, { // 21 y: []float64{}, c: []bool{}, wantTPR: nil, wantFPR: nil, wantThresh: nil, }, { // 22 y: []float64{}, c: []bool{}, cutoffs: []float64{-1, 2.5, 5, 7.5, 10}, wantTPR: nil, wantFPR: nil, wantThresh: nil, }, { // 23 y: []float64{0.1, 0.35, 0.4, 0.8}, c: []bool{true, false, true, false}, cutoffs: []float64{-1, 0.1, 0.35, 0.4, 0.8, 0.9, 1}, wantTPR: []float64{0, 0, 0, 0.5, 0.5, 1, 1}, wantFPR: []float64{0, 0, 0.5, 0.5, 1, 1, 1}, wantThresh: []float64{1, 0.9, 0.8, 0.4, 0.35, 0.1, -1}, }, { // 24 y: []float64{0.1, 0.35, 0.4, 0.8}, c: []bool{true, false, true, false}, cutoffs: []float64{math.Inf(-1), 0.1, 0.36, 0.8}, wantTPR: []float64{0, 0.5, 1, 1}, wantFPR: []float64{0.5, 0.5, 1, 1}, wantThresh: []float64{0.8, 0.36, 0.1, math.Inf(-1)}, }, { // 25 y: []float64{0, 3, 5, 6, 7.5, 8}, c: []bool{false, true, false, true, true, true}, cutoffs: make([]float64, 0, 10), wantTPR: []float64{0, 0.25, 0.5, 0.75, 0.75, 1, 1}, wantFPR: []float64{0, 0, 0, 0, 0.5, 0.5, 1}, wantThresh: []float64{math.Inf(1), 8, 7.5, 6, 5, 3, 0}, }, { // 26 y: []float64{0.1, 0.35, 0.4, 0.8}, c: []bool{true, false, true, false}, cutoffs: []float64{-1, 0.1, 0.35, 0.4, 0.8, 0.9, 1, 1.1, 1.2}, wantTPR: []float64{0, 0, 0, 0, 0, 0.5, 0.5, 1, 1}, wantFPR: []float64{0, 0, 0, 0, 0.5, 0.5, 1, 1, 1}, wantThresh: []float64{1.2, 1.1, 1, 0.9, 0.8, 0.4, 0.35, 0.1, -1}, }, } for i, test := range cases { gotTPR, gotFPR, gotThresh := ROC(test.cutoffs, test.y, test.c, test.w) if !floats.Same(gotTPR, test.wantTPR) && !floats.EqualApprox(gotTPR, test.wantTPR, tol) { t.Errorf("%d: unexpected TPR got:%v want:%v", i, gotTPR, test.wantTPR) } if !floats.Same(gotFPR, test.wantFPR) && !floats.EqualApprox(gotFPR, test.wantFPR, tol) { t.Errorf("%d: unexpected FPR got:%v want:%v", i, gotFPR, test.wantFPR) } if !floats.Same(gotThresh, test.wantThresh) { t.Errorf("%d: unexpected thresholds got:%#v want:%v", i, gotThresh, test.wantThresh) } } } func TestTOC(t *testing.T) { cases := []struct { c []bool w []float64 wantMin []float64 wantMax []float64 wantTOC []float64 }{ { // 0 // This is the example given in the paper's supplement. // http://www2.clarku.edu/~rpontius/TOCexample2.xlsx // It is also shown in the WP article. // https://en.wikipedia.org/wiki/Total_operating_characteristic#/media/File:TOC_labeled.png c: []bool{ false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, false, false, true, false, true, false, false, true, false, }, wantMin: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, wantMax: []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, wantTOC: []float64{0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, }, { // 1 c: []bool{}, wantMin: nil, wantMax: nil, wantTOC: nil, }, { // 2 c: []bool{ true, true, true, true, true, }, wantMin: []float64{0, 1, 2, 3, 4, 5}, wantMax: []float64{0, 1, 2, 3, 4, 5}, wantTOC: []float64{0, 1, 2, 3, 4, 5}, }, { // 3 c: []bool{ false, false, false, false, false, }, wantMin: []float64{0, 0, 0, 0, 0, 0}, wantMax: []float64{0, 0, 0, 0, 0, 0}, wantTOC: []float64{0, 0, 0, 0, 0, 0}, }, { // 4 c: []bool{false, false, false, true, false, true}, w: []float64{2, 2, 3, 6, 1, 4}, wantMin: []float64{0, 0, 0, 3, 6, 8, 10}, wantMax: []float64{0, 4, 5, 10, 10, 10, 10}, wantTOC: []float64{0, 4, 4, 10, 10, 10, 10}, }, } for i, test := range cases { gotMin, gotTOC, gotMax := TOC(test.c, test.w) if !floats.Same(gotMin, test.wantMin) { t.Errorf("%d: unexpected minimum bound got:%v want:%v", i, gotMin, test.wantMin) } if !floats.Same(gotMax, test.wantMax) { t.Errorf("%d: unexpected maximum bound got:%v want:%v", i, gotMax, test.wantMax) } if !floats.Same(gotTOC, test.wantTOC) { t.Errorf("%d: unexpected TOC got:%v want:%v", i, gotTOC, test.wantTOC) } } } golang-gonum-v1-gonum-0.14.0/stat/samplemv/000077500000000000000000000000001450372207100204355ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/samplemv/doc.go000066400000000000000000000005261450372207100215340ustar00rootroot00000000000000// 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 samplemv implements advanced sampling routines from explicit and implicit // probability distributions. package samplemv // import "gonum.org/v1/gonum/stat/samplemv" golang-gonum-v1-gonum-0.14.0/stat/samplemv/halton.go000066400000000000000000000206601450372207100222550ustar00rootroot00000000000000// 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 samplemv import ( "fmt" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distmv" ) // Halton is a type for sampling using the Halton sequence from // the given distribution. The specific method for scrambling (or lack thereof) // is specified by the HaltonKind. If src is not nil, it will be used to generate // the randomness needed to scramble the sequence (if necessary), otherwise // the rand package will be used. Halton panics if the HaltonKind is unrecognized // or if q is nil. // // Halton sequence random number generation is a quasi-Monte Carlo procedure // where the samples are generated to be evenly spaced out across the distribution. // Note that this means the sample locations are correlated with one another. // The distmv.NewUnitUniform function can be used for easy sampling from the unit hypercube. type Halton struct { Kind HaltonKind Q distmv.Quantiler Src rand.Source } // Sample generates rows(batch) samples using the Halton generation procedure. func (h Halton) Sample(batch *mat.Dense) { halton(batch, h.Kind, h.Q, h.Src) } // HaltonKind specifies the type of algorithm used to generate Halton samples. type HaltonKind int const ( // Owen generates (scrambled) Halton samples using the Randomized van der Corput // algorithm described in // A randomized Halton algorithm // Art Owen // https://arxiv.org/pdf/1706.02808.pdf // Currently limited to 1000 dimensional inputs. Owen = iota + 1 ) func halton(batch *mat.Dense, kind HaltonKind, q distmv.Quantiler, src rand.Source) { // Code based from https://arxiv.org/pdf/1706.02808.pdf . perm := rand.Perm if src != nil { perm = rand.New(src).Perm } n, d := batch.Dims() // Each case should generate random numbers over the unit cube. switch kind { default: panic("halton: unknown HaltonKind") case Owen: for j := 0; j < d; j++ { b := nthPrime(j) div := int64(1) b2r := 1 / float64(b) for 1-b2r < 1 { p := perm(b) for i := 0; i < n; i++ { dig := (int64(i) / div) % int64(b) pdig := float64(p[dig]) v := batch.At(i, j) v += pdig * b2r batch.Set(i, j, v) } div *= int64(b) b2r /= float64(b) } } } p := make([]float64, d) for i := 0; i < n; i++ { copy(p, batch.RawRowView(i)) q.Quantile(batch.RawRowView(i), p) } } // nthPrime returns the nth prime number (0 indexed). func nthPrime(n int) int { if n > len(firstPrimes) { panic(fmt.Sprintf("halton: dimension must be less than %d", len(firstPrimes))) } return firstPrimes[n] } var firstPrimes = []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, } golang-gonum-v1-gonum-0.14.0/stat/samplemv/halton_test.go000066400000000000000000000023021450372207100233050ustar00rootroot00000000000000// 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 samplemv import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distmv" ) func TestHalton(t *testing.T) { for cas, test := range []struct { n int d int }{ {10, 1}, {100, 2}, {1000, 3}, } { src := rand.New(rand.NewSource(1)) // Generate the samples. batch := mat.NewDense(test.n, test.d, nil) Halton{Kind: Owen, Q: distmv.NewUnitUniform(test.d, nil), Src: src}.Sample(batch) // In each dimension, the samples should be stratefied according to the // prime for that dimension. There should be at most 1 sample per // 1/b^k block, where k is log(n)/log(b). for d := 0; d < test.d; d++ { b := float64(nthPrime(d)) fk := math.Log(float64(test.n)) / math.Log(b) k := math.Ceil(fk) den := math.Pow(b, k) m := make(map[int]int) for i := 0; i < test.n; i++ { bucket := int(batch.At(i, d) * den) m[bucket]++ } for bucket, n := range m { if n > 1 { t.Errorf("case %d: bucket %v has %v samples", cas, bucket, n) } } } } } golang-gonum-v1-gonum-0.14.0/stat/samplemv/metropolishastings.go000066400000000000000000000170371450372207100247320ustar00rootroot00000000000000// Copyright ©2016 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 samplemv import ( "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distmv" ) var _ Sampler = MetropolisHastingser{} // MHProposal defines a proposal distribution for Metropolis Hastings. type MHProposal interface { // ConditionalLogProb returns the probability of the first argument // conditioned on being at the second argument. // p(x|y) // ConditionalLogProb panics if the input slices are not the same length. ConditionalLogProb(x, y []float64) (prob float64) // ConditionalRand generates a new random location conditioned being at the // location y. If the first argument is nil, a new slice is allocated and // returned. Otherwise, the random location is stored in-place into the first // argument, and ConditionalRand will panic if the input slice lengths differ. ConditionalRand(x, y []float64) []float64 } // MetropolisHastingser is a type for generating samples using the Metropolis Hastings // algorithm (http://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm), // with the given target and proposal distributions, starting at the location // specified by Initial. If src != nil, it will be used to generate random // numbers, otherwise rand.Float64 will be used. // // Metropolis-Hastings is a Markov-chain Monte Carlo algorithm that generates // samples according to the distribution specified by target using the Markov // chain implicitly defined by the proposal distribution. At each // iteration, a proposal point is generated randomly from the current location. // This proposal point is accepted with probability // // p = min(1, (target(new) * proposal(current|new)) / (target(current) * proposal(new|current))) // // If the new location is accepted, it becomes the new current location. // If it is rejected, the current location remains. This is the sample stored in // batch, ignoring BurnIn and Rate (discussed below). // // The samples in Metropolis Hastings are correlated with one another through the // Markov chain. As a result, the initial value can have a significant influence // on the early samples, and so, typically, the first samples generated by the chain // are ignored. This is known as "burn-in", and the number of samples ignored // at the beginning is specified by BurnIn. The proper BurnIn value will depend // on the mixing time of the Markov chain defined by the target and proposal // distributions. // // Many choose to have a sampling "rate" where a number of samples // are ignored in between each kept sample. This helps decorrelate // the samples from one another, but also reduces the number of available samples. // This value is specified by Rate. If Rate is 0 it is defaulted to 1 (keep // every sample). // // The initial value is NOT changed during calls to Sample. type MetropolisHastingser struct { Initial []float64 Target distmv.LogProber Proposal MHProposal Src rand.Source BurnIn int Rate int } // Sample generates rows(batch) samples using the Metropolis Hastings sample // generation method. The initial location is NOT updated during the call to Sample. // // The number of columns in batch must equal len(m.Initial), otherwise Sample // will panic. func (m MetropolisHastingser) Sample(batch *mat.Dense) { burnIn := m.BurnIn rate := m.Rate if rate == 0 { rate = 1 } r, c := batch.Dims() if len(m.Initial) != c { panic("metropolishastings: length mismatch") } // Use the optimal size for the temporary memory to allow the fewest calls // to MetropolisHastings. The case where tmp shadows samples must be // aligned with the logic after burn-in so that tmp does not shadow samples // during the rate portion. tmp := batch if rate > r { tmp = mat.NewDense(rate, c, nil) } rTmp, _ := tmp.Dims() // Perform burn-in. remaining := burnIn initial := make([]float64, c) copy(initial, m.Initial) for remaining != 0 { newSamp := min(rTmp, remaining) metropolisHastings(tmp.Slice(0, newSamp, 0, c).(*mat.Dense), initial, m.Target, m.Proposal, m.Src) copy(initial, tmp.RawRowView(newSamp-1)) remaining -= newSamp } if rate == 1 { metropolisHastings(batch, initial, m.Target, m.Proposal, m.Src) return } if rTmp <= r { tmp = mat.NewDense(rate, c, nil) } // Take a single sample from the chain. metropolisHastings(batch.Slice(0, 1, 0, c).(*mat.Dense), initial, m.Target, m.Proposal, m.Src) copy(initial, batch.RawRowView(0)) // For all of the other samples, first generate Rate samples and then actually // accept the last one. for i := 1; i < r; i++ { metropolisHastings(tmp, initial, m.Target, m.Proposal, m.Src) v := tmp.RawRowView(rate - 1) batch.SetRow(i, v) copy(initial, v) } } func metropolisHastings(batch *mat.Dense, initial []float64, target distmv.LogProber, proposal MHProposal, src rand.Source) { f64 := rand.Float64 if src != nil { f64 = rand.New(src).Float64 } if len(initial) == 0 { panic("metropolishastings: zero length initial") } r, _ := batch.Dims() current := make([]float64, len(initial)) copy(current, initial) proposed := make([]float64, len(initial)) currentLogProb := target.LogProb(initial) for i := 0; i < r; i++ { proposal.ConditionalRand(proposed, current) proposedLogProb := target.LogProb(proposed) probTo := proposal.ConditionalLogProb(proposed, current) probBack := proposal.ConditionalLogProb(current, proposed) accept := math.Exp(proposedLogProb + probBack - probTo - currentLogProb) if accept > f64() { copy(current, proposed) currentLogProb = proposedLogProb } batch.SetRow(i, current) } } // ProposalNormal is a sampling distribution for Metropolis-Hastings. It has a // fixed covariance matrix and changes the mean based on the current sampling // location. type ProposalNormal struct { normal *distmv.Normal } // NewProposalNormal constructs a new ProposalNormal for use as a proposal // distribution for Metropolis-Hastings. ProposalNormal is a multivariate normal // distribution (implemented by distmv.Normal) where the covariance matrix is fixed // and the mean of the distribution changes. // // NewProposalNormal returns {nil, false} if the covariance matrix is not positive-definite. func NewProposalNormal(sigma *mat.SymDense, src rand.Source) (*ProposalNormal, bool) { mu := make([]float64, sigma.SymmetricDim()) normal, ok := distmv.NewNormal(mu, sigma, src) if !ok { return nil, false } p := &ProposalNormal{ normal: normal, } return p, true } // ConditionalLogProb returns the probability of the first argument conditioned on // being at the second argument. // // p(x|y) // // ConditionalLogProb panics if the input slices are not the same length or // are not equal to the dimension of the covariance matrix. func (p *ProposalNormal) ConditionalLogProb(x, y []float64) (prob float64) { // Either SetMean or LogProb will panic if the slice lengths are inaccurate. p.normal.SetMean(y) return p.normal.LogProb(x) } // ConditionalRand generates a new random location conditioned being at the // location y. If the first argument is nil, a new slice is allocated and // returned. Otherwise, the random location is stored in-place into the first // argument, and ConditionalRand will panic if the input slice lengths differ or // if they are not equal to the dimension of the covariance matrix. func (p *ProposalNormal) ConditionalRand(x, y []float64) []float64 { if x == nil { x = make([]float64, p.normal.Dim()) } if len(x) != len(y) { panic(errLengthMismatch) } p.normal.SetMean(y) p.normal.Rand(x) return x } golang-gonum-v1-gonum-0.14.0/stat/samplemv/sample_test.go000066400000000000000000000162061450372207100233110ustar00rootroot00000000000000// Copyright ©2016 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 samplemv import ( "fmt" "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/spatial/r1" "gonum.org/v1/gonum/stat" "gonum.org/v1/gonum/stat/distmv" ) type lhDist interface { Quantile(x, p []float64) []float64 CDF(p, x []float64) []float64 Dim() int } func TestLatinHypercube(t *testing.T) { src := rand.New(rand.NewSource(1)) for _, nSamples := range []int{1, 2, 5, 10, 20} { for _, dist := range []lhDist{ distmv.NewUniform([]r1.Interval{{Min: 0, Max: 3}}, src), distmv.NewUniform([]r1.Interval{{Min: 0, Max: 3}, {Min: -1, Max: 5}, {Min: -4, Max: -1}}, src), } { dim := dist.Dim() batch := mat.NewDense(nSamples, dim, nil) LatinHypercube{Src: src, Q: dist}.Sample(batch) // Latin hypercube should have one entry per hyperrow. present := make([][]bool, nSamples) for i := range present { present[i] = make([]bool, dim) } cdf := make([]float64, dim) for i := 0; i < nSamples; i++ { dist.CDF(cdf, batch.RawRowView(i)) for j := 0; j < dim; j++ { p := cdf[j] quadrant := int(math.Floor(p * float64(nSamples))) present[quadrant][j] = true } } allPresent := true for i := 0; i < nSamples; i++ { for j := 0; j < dim; j++ { if !present[i][j] { allPresent = false } } } if !allPresent { t.Errorf("All quadrants not present") } } } } func TestImportance(t *testing.T) { src := rand.New(rand.NewSource(1)) // Test by finding the expected value of a multi-variate normal. dim := 3 target, ok := randomNormal(dim, src) if !ok { t.Fatal("bad test, sigma not pos def") } muImp := make([]float64, dim) sigmaImp := mat.NewSymDense(dim, nil) for i := 0; i < dim; i++ { sigmaImp.SetSym(i, i, 3) } proposal, ok := distmv.NewNormal(muImp, sigmaImp, src) if !ok { t.Fatal("bad test, sigma not pos def") } nSamples := 200000 batch := mat.NewDense(nSamples, dim, nil) weights := make([]float64, nSamples) Importance{Target: target, Proposal: proposal}.SampleWeighted(batch, weights) compareNormal(t, target, batch, weights, 5e-2, 5e-2) } func TestRejection(t *testing.T) { src := rand.New(rand.NewSource(1)) // Test by finding the expected value of a uniform. dim := 3 bounds := make([]r1.Interval, dim) for i := 0; i < dim; i++ { min := src.NormFloat64() max := src.NormFloat64() if min > max { min, max = max, min } bounds[i].Min = min bounds[i].Max = max } target := distmv.NewUniform(bounds, src) mu := target.Mean(nil) muImp := make([]float64, dim) sigmaImp := mat.NewSymDense(dim, nil) for i := 0; i < dim; i++ { sigmaImp.SetSym(i, i, 6) } proposal, ok := distmv.NewNormal(muImp, sigmaImp, src) if !ok { t.Fatal("bad test, sigma not pos def") } nSamples := 1000 batch := mat.NewDense(nSamples, dim, nil) weights := make([]float64, nSamples) rej := Rejection{Target: target, Proposal: proposal, C: 1000, Src: src} rej.Sample(batch) err := rej.Err() if err != nil { t.Error("Bad test, nan samples") } for i := 0; i < dim; i++ { col := mat.Col(nil, i, batch) ev := stat.Mean(col, weights) if math.Abs(ev-mu[i]) > 1e-2 { t.Errorf("Mean mismatch: Want %v, got %v", mu[i], ev) } } } func TestMetropolisHastings(t *testing.T) { src := rand.New(rand.NewSource(1)) // Test by finding the expected value of a normal distribution. dim := 3 target, ok := randomNormal(dim, src) if !ok { t.Fatal("bad test, sigma not pos def") } sigmaImp := mat.NewSymDense(dim, nil) for i := 0; i < dim; i++ { sigmaImp.SetSym(i, i, 0.25) } proposal, ok := NewProposalNormal(sigmaImp, src) if !ok { t.Fatal("bad test, sigma not pos def") } nSamples := 100000 burnin := 5000 batch := mat.NewDense(nSamples, dim, nil) initial := make([]float64, dim) metropolisHastings(batch, initial, target, proposal, src) batch = batch.Slice(burnin, nSamples, 0, dim).(*mat.Dense) compareNormal(t, target, batch, nil, 5e-1, 5e-1) } // randomNormal constructs a random Normal distribution using the provided // random source. func randomNormal(dim int, src *rand.Rand) (*distmv.Normal, bool) { data := make([]float64, dim*dim) for i := range data { data[i] = src.Float64() } a := mat.NewDense(dim, dim, data) var sigma mat.SymDense sigma.SymOuterK(1, a) mu := make([]float64, dim) for i := range mu { mu[i] = rand.NormFloat64() } return distmv.NewNormal(mu, &sigma, src) } func compareNormal(t *testing.T, want *distmv.Normal, batch *mat.Dense, weights []float64, meanTol, covTol float64) { t.Helper() dim := want.Dim() mu := want.Mean(nil) var sigma mat.SymDense want.CovarianceMatrix(&sigma) n, _ := batch.Dims() if weights == nil { weights = make([]float64, n) for i := range weights { weights[i] = 1 } } for i := 0; i < dim; i++ { col := mat.Col(nil, i, batch) ev := stat.Mean(col, weights) if math.Abs(ev-mu[i]) > meanTol { t.Errorf("Mean mismatch: Want %v, got %v", mu[i], ev) } } var cov mat.SymDense stat.CovarianceMatrix(&cov, batch, weights) if !mat.EqualApprox(&cov, &sigma, covTol) { t.Errorf("Covariance matrix mismatch") } } func TestMetropolisHastingser(t *testing.T) { for _, test := range []struct { dim, burnin, rate, samples int }{ {3, 10, 1, 1}, {3, 10, 2, 1}, {3, 10, 1, 2}, {3, 10, 3, 2}, {3, 10, 7, 4}, {3, 10, 7, 4}, {3, 11, 51, 103}, {3, 11, 103, 51}, {3, 51, 11, 103}, {3, 51, 103, 11}, {3, 103, 11, 51}, {3, 103, 51, 11}, } { src := rand.New(rand.NewSource(1)) dim := test.dim initial := make([]float64, dim) target, ok := randomNormal(dim, src) if !ok { t.Fatal("bad test, sigma not pos def") } sigmaImp := mat.NewSymDense(dim, nil) for i := 0; i < dim; i++ { sigmaImp.SetSym(i, i, 0.25) } // Test the Metropolis Hastingser by generating all the samples, then generating // the same samples with a burnin and rate. src = rand.New(rand.NewSource(1)) proposal, ok := NewProposalNormal(sigmaImp, src) if !ok { t.Fatal("bad test, sigma not pos def") } mh := MetropolisHastingser{ Initial: initial, Target: target, Proposal: proposal, Src: src, BurnIn: 0, Rate: 0, } samples := test.samples burnin := test.burnin rate := test.rate fullBatch := mat.NewDense(1+burnin+rate*(samples-1), dim, nil) mh.Sample(fullBatch) src = rand.New(rand.NewSource(1)) proposal, _ = NewProposalNormal(sigmaImp, src) mh = MetropolisHastingser{ Initial: initial, Target: target, Proposal: proposal, Src: src, BurnIn: burnin, Rate: rate, } batch := mat.NewDense(samples, dim, nil) mh.Sample(batch) same := true count := burnin for i := 0; i < samples; i++ { if !floats.Equal(batch.RawRowView(i), fullBatch.RawRowView(count)) { fmt.Println("sample ", i, "is different") same = false break } count += rate } if !same { fmt.Printf("%v\n", mat.Formatted(batch)) fmt.Printf("%v\n", mat.Formatted(fullBatch)) t.Errorf("sampling mismatch: dim = %v, burnin = %v, rate = %v, samples = %v", dim, burnin, rate, samples) } } } golang-gonum-v1-gonum-0.14.0/stat/samplemv/samplemv.go000066400000000000000000000177021450372207100226170ustar00rootroot00000000000000// Copyright ©2016 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 samplemv import ( "errors" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distmv" ) const errLengthMismatch = "samplemv: slice length mismatch" var ( _ Sampler = LatinHypercube{} _ Sampler = (*Rejection)(nil) _ Sampler = IID{} _ WeightedSampler = SampleUniformWeighted{} _ WeightedSampler = Importance{} ) func min(a, b int) int { if a < b { return a } return b } // Sampler generates a batch of samples according to the rule specified by the // implementing type. The number of samples generated is equal to rows(batch), // and the samples are stored in-place into the input. type Sampler interface { Sample(batch *mat.Dense) } // WeightedSampler generates a batch of samples and their relative weights // according to the rule specified by the implementing type. The number of samples // generated is equal to rows(batch), and the samples and weights // are stored in-place into the inputs. The length of weights must equal // rows(batch), otherwise SampleWeighted will panic. type WeightedSampler interface { SampleWeighted(batch *mat.Dense, weights []float64) } // SampleUniformWeighted wraps a Sampler type to create a WeightedSampler where all // weights are equal. type SampleUniformWeighted struct { Sampler } // SampleWeighted generates rows(batch) samples from the embedded Sampler type // and sets all of the weights equal to 1. If rows(batch) and len(weights) // of weights are not equal, SampleWeighted will panic. func (w SampleUniformWeighted) SampleWeighted(batch *mat.Dense, weights []float64) { r, _ := batch.Dims() if r != len(weights) { panic(errLengthMismatch) } w.Sample(batch) for i := range weights { weights[i] = 1 } } // LatinHypercube is a type for sampling using Latin hypercube sampling // from the given distribution. If src is not nil, it will be used to generate // random numbers, otherwise rand.Float64 will be used. // // Latin hypercube sampling divides the cumulative distribution function into equally // spaced bins and guarantees that one sample is generated per bin. Within each bin, // the location is randomly sampled. The distmv.NewUnitUniform function can be used // for easy sampling from the unit hypercube. type LatinHypercube struct { Q distmv.Quantiler Src rand.Source } // Sample generates rows(batch) samples using the LatinHypercube generation // procedure. func (l LatinHypercube) Sample(batch *mat.Dense) { latinHypercube(batch, l.Q, l.Src) } func latinHypercube(batch *mat.Dense, q distmv.Quantiler, src rand.Source) { r, c := batch.Dims() var f64 func() float64 var perm func(int) []int if src != nil { r := rand.New(src) f64 = r.Float64 perm = r.Perm } else { f64 = rand.Float64 perm = rand.Perm } r64 := float64(r) for i := 0; i < c; i++ { p := perm(r) for j := 0; j < r; j++ { v := f64()/r64 + float64(j)/r64 batch.Set(p[j], i, v) } } p := make([]float64, c) for i := 0; i < r; i++ { copy(p, batch.RawRowView(i)) q.Quantile(batch.RawRowView(i), p) } } // Importance is a type for performing importance sampling using the given // Target and Proposal distributions. // // Importance sampling is a variance reduction technique where samples are // generated from a proposal distribution, q(x), instead of the target distribution // p(x). This allows relatively unlikely samples in p(x) to be generated more frequently. // // The importance sampling weight at x is given by p(x)/q(x). To reduce variance, // a good proposal distribution will bound this sampling weight. This implies the // support of q(x) should be at least as broad as p(x), and q(x) should be "fatter tailed" // than p(x). type Importance struct { Target distmv.LogProber Proposal distmv.RandLogProber } // SampleWeighted generates rows(batch) samples using the Importance sampling // generation procedure. // // The length of weights must equal the length of batch, otherwise Importance will panic. func (l Importance) SampleWeighted(batch *mat.Dense, weights []float64) { importance(batch, weights, l.Target, l.Proposal) } func importance(batch *mat.Dense, weights []float64, target distmv.LogProber, proposal distmv.RandLogProber) { r, _ := batch.Dims() if r != len(weights) { panic(errLengthMismatch) } for i := 0; i < r; i++ { v := batch.RawRowView(i) proposal.Rand(v) weights[i] = math.Exp(target.LogProb(v) - proposal.LogProb(v)) } } // ErrRejection is returned when the constant in Rejection is not sufficiently high. var ErrRejection = errors.New("rejection: acceptance ratio above 1") // Rejection is a type for sampling using the rejection sampling algorithm. // // Rejection sampling generates points from the target distribution by using // the proposal distribution. At each step of the algorithm, the proposed point // is accepted with probability // // p = target(x) / (proposal(x) * c) // // where target(x) is the probability of the point according to the target distribution // and proposal(x) is the probability according to the proposal distribution. // The constant c must be chosen such that target(x) < proposal(x) * c for all x. // The expected number of proposed samples is len(samples) * c. // // The number of proposed locations during sampling can be found with a call to // Proposed. If there was an error during sampling, all elements of samples are // set to NaN and the error can be accessed with the Err method. If src != nil, // it will be used to generate random numbers, otherwise rand.Float64 will be used. // // Target may return the true (log of) the probability of the location, or it may return // a value that is proportional to the probability (logprob + constant). This is // useful for cases where the probability distribution is only known up to a normalization // constant. type Rejection struct { C float64 Target distmv.LogProber Proposal distmv.RandLogProber Src rand.Source err error proposed int } // Err returns nil if the most recent call to sample was successful, and returns // ErrRejection if it was not. func (r *Rejection) Err() error { return r.err } // Proposed returns the number of samples proposed during the most recent call to // Sample. func (r *Rejection) Proposed() int { return r.proposed } // Sample generates rows(batch) using the Rejection sampling generation procedure. // Rejection sampling may fail if the constant is insufficiently high, as described // in the type comment for Rejection. If the generation fails, the samples // are set to math.NaN(), and a call to Err will return a non-nil value. func (r *Rejection) Sample(batch *mat.Dense) { r.err = nil r.proposed = 0 proposed, ok := rejection(batch, r.Target, r.Proposal, r.C, r.Src) if !ok { r.err = ErrRejection } r.proposed = proposed } func rejection(batch *mat.Dense, target distmv.LogProber, proposal distmv.RandLogProber, c float64, src rand.Source) (nProposed int, ok bool) { if c < 1 { panic("rejection: acceptance constant must be greater than 1") } f64 := rand.Float64 if src != nil { f64 = rand.New(src).Float64 } r, dim := batch.Dims() v := make([]float64, dim) var idx int for { nProposed++ proposal.Rand(v) qx := proposal.LogProb(v) px := target.LogProb(v) accept := math.Exp(px-qx) / c if accept > 1 { // Invalidate the whole result and return a failure. for i := 0; i < r; i++ { for j := 0; j < dim; j++ { batch.Set(i, j, math.NaN()) } } return nProposed, false } if accept > f64() { batch.SetRow(idx, v) idx++ if idx == r { break } } } return nProposed, true } // IID generates a set of independently and identically distributed samples from // the input distribution. type IID struct { Dist distmv.Rander } // Sample generates a set of identically and independently distributed samples. func (iid IID) Sample(batch *mat.Dense) { r, _ := batch.Dims() for i := 0; i < r; i++ { iid.Dist.Rand(batch.RawRowView(i)) } } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/000077500000000000000000000000001450372207100204455ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/sampleuv/doc.go000066400000000000000000000010111450372207100215320ustar00rootroot00000000000000// 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 sampleuv implements advanced sampling routines from explicit and implicit // probability distributions. // // Each sampling routine is implemented as a stateless function with a // complementary wrapper type. The wrapper types allow the sampling routines // to implement interfaces. package sampleuv // import "gonum.org/v1/gonum/stat/sampleuv" golang-gonum-v1-gonum-0.14.0/stat/sampleuv/example_burnin_test.go000066400000000000000000000025011450372207100250410ustar00rootroot00000000000000// 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 sampleuv_test import ( "gonum.org/v1/gonum/stat/distuv" "gonum.org/v1/gonum/stat/sampleuv" ) type ProposalDist struct { Sigma float64 } func (p ProposalDist) ConditionalRand(y float64) float64 { return distuv.Normal{Mu: y, Sigma: p.Sigma}.Rand() } func (p ProposalDist) ConditionalLogProb(x, y float64) float64 { return distuv.Normal{Mu: y, Sigma: p.Sigma}.LogProb(x) } func ExampleMetropolisHastings_burnin() { n := 1000 // The number of samples to generate. burnin := 50 // Number of samples to ignore at the start. var initial float64 // target is the distribution from which we would like to sample. target := distuv.Weibull{K: 5, Lambda: 0.5} // proposal is the proposal distribution. Here, we are choosing // a tight Gaussian distribution around the current location. In // typical problems, if Sigma is too small, it takes a lot of samples // to move around the distribution. If Sigma is too large, it can be hard // to find acceptable samples. proposal := ProposalDist{Sigma: 0.2} samples := make([]float64, n) mh := sampleuv.MetropolisHastings{Initial: initial, Target: target, Proposal: proposal, BurnIn: burnin} mh.Sample(samples) } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/example_rate_test.go000066400000000000000000000021141450372207100244770ustar00rootroot00000000000000// 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 sampleuv_test import ( "gonum.org/v1/gonum/stat/distuv" "gonum.org/v1/gonum/stat/sampleuv" ) func ExampleMetropolisHastings_samplingRate() { // See Burnin example for a description of these quantities. n := 1000 burnin := 300 var initial float64 target := distuv.Weibull{K: 5, Lambda: 0.5} proposal := ProposalDist{Sigma: 0.2} // Successive samples are correlated with one another through the // Markov Chain defined by the proposal distribution. One may use // a sampling rate to decrease the correlation in the samples for // an increase in computation cost. The rate parameter specifies // that for every accepted sample stored in `samples`, rate - 1 accepted // samples are not stored in `samples`. rate := 50 mh := sampleuv.MetropolisHastings{ Initial: initial, Target: target, Proposal: proposal, BurnIn: burnin, Rate: rate, } samples := make([]float64, n) mh.Sample(samples) } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/sample.go000066400000000000000000000300171450372207100222560ustar00rootroot00000000000000// 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 sampleuv import ( "errors" "math" "golang.org/x/exp/rand" "gonum.org/v1/gonum/stat/distuv" ) const badLengthMismatch = "sample: slice length mismatch" var ( _ Sampler = LatinHypercube{} _ Sampler = MetropolisHastings{} _ Sampler = (*Rejection)(nil) _ Sampler = IIDer{} _ WeightedSampler = SampleUniformWeighted{} _ WeightedSampler = Importance{} ) func min(a, b int) int { if a < b { return a } return b } // Sampler generates a batch of samples according to the rule specified by the // implementing type. The number of samples generated is equal to len(batch), // and the samples are stored in-place into the input. type Sampler interface { Sample(batch []float64) } // WeightedSampler generates a batch of samples and their relative weights // according to the rule specified by the implementing type. The number of samples // generated is equal to len(batch), and the samples and weights // are stored in-place into the inputs. The length of weights must equal // len(batch), otherwise SampleWeighted will panic. type WeightedSampler interface { SampleWeighted(batch, weights []float64) } // SampleUniformWeighted wraps a Sampler type to create a WeightedSampler where all // weights are equal. type SampleUniformWeighted struct { Sampler } // SampleWeighted generates len(batch) samples from the embedded Sampler type // and sets all of the weights equal to 1. If len(batch) and len(weights) // are not equal, SampleWeighted will panic. func (w SampleUniformWeighted) SampleWeighted(batch, weights []float64) { if len(batch) != len(weights) { panic(badLengthMismatch) } w.Sample(batch) for i := range weights { weights[i] = 1 } } // LatinHypercube is a type for sampling using Latin hypercube sampling // from the given distribution. If src is not nil, it will be used to generate // random numbers, otherwise rand.Float64 will be used. // // Latin hypercube sampling divides the cumulative distribution function into equally // spaced bins and guarantees that one sample is generated per bin. Within each bin, // the location is randomly sampled. The distuv.UnitUniform variable can be used // for easy sampling from the unit hypercube. type LatinHypercube struct { Q distuv.Quantiler Src rand.Source } // Sample generates len(batch) samples using the LatinHypercube generation // procedure. func (l LatinHypercube) Sample(batch []float64) { latinHypercube(batch, l.Q, l.Src) } func latinHypercube(batch []float64, q distuv.Quantiler, src rand.Source) { n := len(batch) var perm []int var f64 func() float64 if src != nil { r := rand.New(src) f64 = r.Float64 perm = r.Perm(n) } else { f64 = rand.Float64 perm = rand.Perm(n) } for i := range batch { v := f64()/float64(n) + float64(i)/float64(n) batch[perm[i]] = q.Quantile(v) } } // Importance is a type for performing importance sampling using the given // Target and Proposal distributions. // // Importance sampling is a variance reduction technique where samples are // generated from a proposal distribution, q(x), instead of the target distribution // p(x). This allows relatively unlikely samples in p(x) to be generated more frequently. // // The importance sampling weight at x is given by p(x)/q(x). To reduce variance, // a good proposal distribution will bound this sampling weight. This implies the // support of q(x) should be at least as broad as p(x), and q(x) should be "fatter tailed" // than p(x). type Importance struct { Target distuv.LogProber Proposal distuv.RandLogProber } // SampleWeighted generates len(batch) samples using the Importance sampling // generation procedure. // // The length of weights must equal the length of batch, otherwise Importance will panic. func (l Importance) SampleWeighted(batch, weights []float64) { importance(batch, weights, l.Target, l.Proposal) } func importance(batch, weights []float64, target distuv.LogProber, proposal distuv.RandLogProber) { if len(batch) != len(weights) { panic(badLengthMismatch) } for i := range batch { v := proposal.Rand() batch[i] = v weights[i] = math.Exp(target.LogProb(v) - proposal.LogProb(v)) } } // ErrRejection is returned when the constant in Rejection is not sufficiently high. var ErrRejection = errors.New("rejection: acceptance ratio above 1") // Rejection is a type for sampling using the rejection sampling algorithm. // // Rejection sampling generates points from the target distribution by using // the proposal distribution. At each step of the algorithm, the proposed point // is accepted with probability // // p = target(x) / (proposal(x) * c) // // where target(x) is the probability of the point according to the target distribution // and proposal(x) is the probability according to the proposal distribution. // The constant c must be chosen such that target(x) < proposal(x) * c for all x. // The expected number of proposed samples is len(samples) * c. // // The number of proposed locations during sampling can be found with a call to // Proposed. If there was an error during sampling, all elements of samples are // set to NaN and the error can be accessed with the Err method. If src != nil, // it will be used to generate random numbers, otherwise rand.Float64 will be used. // // Target may return the true (log of) the probability of the location, or it may return // a value that is proportional to the probability (logprob + constant). This is // useful for cases where the probability distribution is only known up to a normalization // constant. type Rejection struct { C float64 Target distuv.LogProber Proposal distuv.RandLogProber Src rand.Source err error proposed int } // Err returns nil if the most recent call to sample was successful, and returns // ErrRejection if it was not. func (r *Rejection) Err() error { return r.err } // Proposed returns the number of samples proposed during the most recent call to // Sample. func (r *Rejection) Proposed() int { return r.proposed } // Sample generates len(batch) using the Rejection sampling generation procedure. // Rejection sampling may fail if the constant is insufficiently high, as described // in the type comment for Rejection. If the generation fails, the samples // are set to math.NaN(), and a call to Err will return a non-nil value. func (r *Rejection) Sample(batch []float64) { r.err = nil r.proposed = 0 proposed, ok := rejection(batch, r.Target, r.Proposal, r.C, r.Src) if !ok { r.err = ErrRejection } r.proposed = proposed } func rejection(batch []float64, target distuv.LogProber, proposal distuv.RandLogProber, c float64, src rand.Source) (nProposed int, ok bool) { if c < 1 { panic("rejection: acceptance constant must be greater than 1") } f64 := rand.Float64 if src != nil { f64 = rand.New(src).Float64 } var idx int for { nProposed++ v := proposal.Rand() qx := proposal.LogProb(v) px := target.LogProb(v) accept := math.Exp(px-qx) / c if accept > 1 { // Invalidate the whole result and return a failure. for i := range batch { batch[i] = math.NaN() } return nProposed, false } if accept > f64() { batch[idx] = v idx++ if idx == len(batch) { break } } } return nProposed, true } // MHProposal defines a proposal distribution for Metropolis Hastings. type MHProposal interface { // ConditionalDist returns the probability of the first argument conditioned on // being at the second argument // p(x|y) ConditionalLogProb(x, y float64) (prob float64) // ConditionalRand generates a new random location conditioned being at the // location y. ConditionalRand(y float64) (x float64) } // MetropolisHastings is a type for generating samples using the Metropolis Hastings // algorithm (http://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm), // with the given target and proposal distributions, starting at the location // specified by Initial. If src != nil, it will be used to generate random // numbers, otherwise rand.Float64 will be used. // // Metropolis-Hastings is a Markov-chain Monte Carlo algorithm that generates // samples according to the distribution specified by target using the Markov // chain implicitly defined by the proposal distribution. At each // iteration, a proposal point is generated randomly from the current location. // This proposal point is accepted with probability // // p = min(1, (target(new) * proposal(current|new)) / (target(current) * proposal(new|current))) // // If the new location is accepted, it becomes the new current location. // If it is rejected, the current location remains. This is the sample stored in // batch, ignoring BurnIn and Rate (discussed below). // // The samples in Metropolis Hastings are correlated with one another through the // Markov chain. As a result, the initial value can have a significant influence // on the early samples, and so, typically, the first samples generated by the chain // are ignored. This is known as "burn-in", and the number of samples ignored // at the beginning is specified by BurnIn. The proper BurnIn value will depend // on the mixing time of the Markov chain defined by the target and proposal // distributions. // // Many choose to have a sampling "rate" where a number of samples // are ignored in between each kept sample. This helps decorrelate // the samples from one another, but also reduces the number of available samples. // This value is specified by Rate. If Rate is 0 it is defaulted to 1 (keep // every sample). // // The initial value is NOT changed during calls to Sample. type MetropolisHastings struct { Initial float64 Target distuv.LogProber Proposal MHProposal Src rand.Source BurnIn int Rate int } // Sample generates len(batch) samples using the Metropolis Hastings sample // generation method. The initial location is NOT updated during the call to Sample. func (m MetropolisHastings) Sample(batch []float64) { burnIn := m.BurnIn rate := m.Rate if rate == 0 { rate = 1 } // Use the optimal size for the temporary memory to allow the fewest calls // to MetropolisHastings. The case where tmp shadows samples must be // aligned with the logic after burn-in so that tmp does not shadow samples // during the rate portion. tmp := batch if rate > len(batch) { tmp = make([]float64, rate) } // Perform burn-in. remaining := burnIn initial := m.Initial for remaining != 0 { newSamp := min(len(tmp), remaining) metropolisHastings(tmp[newSamp:], initial, m.Target, m.Proposal, m.Src) initial = tmp[newSamp-1] remaining -= newSamp } if rate == 1 { metropolisHastings(batch, initial, m.Target, m.Proposal, m.Src) return } if len(tmp) <= len(batch) { tmp = make([]float64, rate) } // Take a single sample from the chain metropolisHastings(batch[0:1], initial, m.Target, m.Proposal, m.Src) initial = batch[0] // For all of the other samples, first generate Rate samples and then actually // accept the last one. for i := 1; i < len(batch); i++ { metropolisHastings(tmp, initial, m.Target, m.Proposal, m.Src) v := tmp[rate-1] batch[i] = v initial = v } } func metropolisHastings(batch []float64, initial float64, target distuv.LogProber, proposal MHProposal, src rand.Source) { f64 := rand.Float64 if src != nil { f64 = rand.New(src).Float64 } current := initial currentLogProb := target.LogProb(initial) for i := range batch { proposed := proposal.ConditionalRand(current) proposedLogProb := target.LogProb(proposed) probTo := proposal.ConditionalLogProb(proposed, current) probBack := proposal.ConditionalLogProb(current, proposed) accept := math.Exp(proposedLogProb + probBack - probTo - currentLogProb) if accept > f64() { current = proposed currentLogProb = proposedLogProb } batch[i] = current } } // IIDer generates a set of independently and identically distributed samples from // the input distribution. type IIDer struct { Dist distuv.Rander } // Sample generates a set of identically and independently distributed samples. func (iid IIDer) Sample(batch []float64) { for i := range batch { batch[i] = iid.Dist.Rand() } } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/sample_test.go000066400000000000000000000052701450372207100233200ustar00rootroot00000000000000// 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 sampleuv import ( "sort" "testing" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/stat" "gonum.org/v1/gonum/stat/distuv" ) const tol = 1e-2 type lhDist interface { Quantile(float64) float64 CDF(float64) float64 } func TestLatinHypercube(t *testing.T) { for _, nSamples := range []int{1, 2, 5, 10, 20} { samples := make([]float64, nSamples) for _, dist := range []lhDist{ distuv.Uniform{Min: 0, Max: 1}, distuv.Uniform{Min: 0, Max: 10}, distuv.Normal{Mu: 5, Sigma: 3}, } { LatinHypercube{Q: dist}.Sample(samples) sort.Float64s(samples) for i, v := range samples { p := dist.CDF(v) if p < float64(i)/float64(nSamples) || p > float64(i+1)/float64(nSamples) { t.Errorf("probability out of bounds") } } } } } func TestImportance(t *testing.T) { // Test by finding the expected value of a Normal. trueMean := 3.0 target := distuv.Normal{Mu: trueMean, Sigma: 2} proposal := distuv.Normal{Mu: 0, Sigma: 5} nSamples := 100000 x := make([]float64, nSamples) weights := make([]float64, nSamples) Importance{Target: target, Proposal: proposal}.SampleWeighted(x, weights) ev := stat.Mean(x, weights) if !scalar.EqualWithinAbsOrRel(ev, trueMean, tol, tol) { t.Errorf("Mean mismatch: Want %v, got %v", trueMean, ev) } } func TestRejection(t *testing.T) { // Test by finding the expected value of a Normal. trueMean := 3.0 target := distuv.Normal{Mu: trueMean, Sigma: 2} proposal := distuv.Normal{Mu: 0, Sigma: 5} nSamples := 20000 x := make([]float64, nSamples) r := &Rejection{Target: target, Proposal: proposal, C: 100} r.Sample(x) ev := stat.Mean(x, nil) if !scalar.EqualWithinAbsOrRel(ev, trueMean, tol, tol) { t.Errorf("Mean mismatch: Want %v, got %v", trueMean, ev) } } type condNorm struct { Sigma float64 } func (c condNorm) ConditionalRand(y float64) float64 { return distuv.Normal{Mu: y, Sigma: c.Sigma}.Rand() } func (c condNorm) ConditionalLogProb(x, y float64) float64 { return distuv.Normal{Mu: y, Sigma: c.Sigma}.LogProb(x) } func TestMetropolisHastings(t *testing.T) { // Test by finding the expected value of a Normal. trueMean := 3.0 target := distuv.Normal{Mu: trueMean, Sigma: 2} proposal := condNorm{Sigma: 5} burnin := 500 nSamples := 100000 + burnin x := make([]float64, nSamples) mh := MetropolisHastings{ Initial: 100, Target: target, Proposal: proposal, BurnIn: burnin, } mh.Sample(x) ev := stat.Mean(x, nil) if !scalar.EqualWithinAbsOrRel(ev, trueMean, tol, tol) { t.Errorf("Mean mismatch: Want %v, got %v", trueMean, ev) } } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/weighted.go000066400000000000000000000065551450372207100226070ustar00rootroot00000000000000// Copyright ©2015 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 sampleuv import "golang.org/x/exp/rand" // Weighted provides sampling without replacement from a collection of items with // non-uniform probability. type Weighted struct { weights []float64 // heap is a weight heap. // // It keeps a heap-organised sum of remaining // index weights that are available to be taken // from. // // Each element holds the sum of weights for // the corresponding index, plus the sum of // its children's weights; the children of // an element i can be found at positions // 2*(i+1)-1 and 2*(i+1). The root of the // weight heap is at element 0. // // See comments in container/heap for an // explanation of the layout of a heap. heap []float64 rnd *rand.Rand } // NewWeighted returns a Weighted for the weights w. If src is nil, rand.Rand is // used as the random number generator. // // Note that sampling from weights with a high variance or overall low absolute // value sum may result in problems with numerical stability. func NewWeighted(w []float64, src rand.Source) Weighted { s := Weighted{ weights: make([]float64, len(w)), heap: make([]float64, len(w)), } if src != nil { s.rnd = rand.New(src) } s.ReweightAll(w) return s } // Len returns the number of items held by the Weighted, including items // already taken. func (s Weighted) Len() int { return len(s.weights) } // Take returns an index from the Weighted with probability proportional // to the weight of the item. The weight of the item is then set to zero. // Take returns false if there are no items remaining. func (s Weighted) Take() (idx int, ok bool) { if s.heap[0] == 0 { return -1, false } var r float64 if s.rnd == nil { r = rand.Float64() } else { r = s.rnd.Float64() } r *= s.heap[0] i := 0 for { r -= s.weights[i] if r < 0 { break // Fall within item i. } li := i*2 + 1 // Move to left child. // Left node should exist, because r is non-negative, // but there could be floating point errors, so we // check index explicitly. if li >= len(s.heap) { break } i = li d := s.heap[i] if r >= d { // If there is enough r to pass left child try to // move to the right child. r -= d ri := i + 1 if ri >= len(s.heap) { break } i = ri } } s.Reweight(i, 0) return i, true } // Reweight sets the weight of item idx to w. func (s Weighted) Reweight(idx int, w float64) { s.weights[idx] = w // We want to keep the heap state here consistent // with the result of a reset call. So we sum // weights in the same order, since floating point // addition is not associative. for { w = s.weights[idx] ri := idx*2 + 2 if ri < len(s.heap) { w += s.heap[ri] } li := ri - 1 if li < len(s.heap) { w += s.heap[li] } s.heap[idx] = w if idx == 0 { break } idx = (idx - 1) / 2 } } // ReweightAll sets the weight of all items in the Weighted. ReweightAll // panics if len(w) != s.Len. func (s Weighted) ReweightAll(w []float64) { if len(w) != s.Len() { panic("floats: length of the slices do not match") } copy(s.weights, w) s.reset() } func (s Weighted) reset() { copy(s.heap, s.weights) for i := len(s.heap) - 1; i > 0; i-- { // Sometimes 1-based counting makes sense. s.heap[((i+1)>>1)-1] += s.heap[i] } } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/weighted_test.go000066400000000000000000000170751450372207100236450ustar00rootroot00000000000000// Copyright ©2015 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 sampleuv import ( "flag" "reflect" "testing" "time" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) var prob = flag.Bool("prob", false, "enables probabilistic testing of the random weighted sampler") const sigChi2 = 16.92 // p = 0.05 df = 9 var ( newExp = func() []float64 { return []float64{1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7, 1 << 8, 1 << 9} } exp = newExp() obt = []float64{1020, 1909, 3937, 7881, 15687, 31486, 62310, 124632, 250453, 500685} ) func newTestWeighted() Weighted { weights := make([]float64, len(obt)) for i := range weights { weights[i] = float64(int(1) << uint(i)) } return NewWeighted(weights, nil) } func TestWeightedUnseeded(t *testing.T) { rand.Seed(0) want := Weighted{ weights: []float64{1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7, 1 << 8, 1 << 9}, heap: []float64{ exp[0] + exp[1] + exp[3] + exp[4] + exp[7] + exp[8] + exp[9] + exp[2] + exp[5] + exp[6], exp[1] + exp[3] + exp[4] + exp[7] + exp[8] + exp[9], exp[2] + exp[5] + exp[6], exp[3] + exp[7] + exp[8], exp[4] + exp[9], exp[5], exp[6], exp[7], exp[8], exp[9], }, } ts := newTestWeighted() if !reflect.DeepEqual(ts, want) { t.Fatalf("unexpected new Weighted value:\ngot: %#v\nwant:%#v", ts, want) } f := make([]float64, len(obt)) for i := 0; i < 1e6; i++ { item, ok := newTestWeighted().Take() if !ok { t.Fatal("Weighted unexpectedly empty") } f[item]++ } exp := newExp() fac := floats.Sum(f) / floats.Sum(exp) for i := range f { exp[i] *= fac } if !reflect.DeepEqual(f, obt) { t.Fatalf("unexpected selection:\ngot: %#v\nwant:%#v", f, obt) } // Check that this is within statistical expectations - we know this is true for this set. X := chi2(f, exp) if X >= sigChi2 { t.Errorf("H₀: d(Sample) = d(Expect), H₁: d(S) ≠ d(Expect). df = %d, p = 0.05, X² threshold = %.2f, X² = %f", len(f)-1, sigChi2, X) } } func TestWeightedTimeSeeded(t *testing.T) { if !*prob { t.Skip("probabilistic testing not requested") } t.Log("Note: This test is stochastic and is expected to fail with probability ≈ 0.05.") rand.Seed(uint64(time.Now().Unix())) f := make([]float64, len(obt)) for i := 0; i < 1e6; i++ { item, ok := newTestWeighted().Take() if !ok { t.Fatal("Weighted unexpectedly empty") } f[item]++ } exp := newExp() fac := floats.Sum(f) / floats.Sum(exp) for i := range f { exp[i] *= fac } // Check that our obtained values are within statistical expectations for p = 0.05. // This will not be true approximately 1 in 20 tests. X := chi2(f, exp) if X >= sigChi2 { t.Errorf("H₀: d(Sample) = d(Expect), H₁: d(S) ≠ d(Expect). df = %d, p = 0.05, X² threshold = %.2f, X² = %f", len(f)-1, sigChi2, X) } } func TestWeightZero(t *testing.T) { rand.Seed(0) want := Weighted{ weights: []float64{1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 0, 1 << 7, 1 << 8, 1 << 9}, heap: []float64{ exp[0] + exp[1] + exp[3] + exp[4] + exp[7] + exp[8] + exp[9] + exp[2] + exp[5], exp[1] + exp[3] + exp[4] + exp[7] + exp[8] + exp[9], exp[2] + exp[5], exp[3] + exp[7] + exp[8], exp[4] + exp[9], exp[5], 0, exp[7], exp[8], exp[9], }, } ts := newTestWeighted() ts.Reweight(6, 0) if !reflect.DeepEqual(ts, want) { t.Fatalf("unexpected new Weighted value:\ngot: %#v\nwant:%#v", ts, want) } f := make([]float64, len(obt)) for i := 0; i < 1e6; i++ { ts := newTestWeighted() ts.Reweight(6, 0) item, ok := ts.Take() if !ok { t.Fatal("Weighted unexpectedly empty") } f[item]++ } exp := newExp() fac := floats.Sum(f) / floats.Sum(exp) for i := range f { exp[i] *= fac } if f[6] != 0 { t.Errorf("unexpected selection rate for zero-weighted item: got: %v want:%v", f[6], 0) } if reflect.DeepEqual(f[:6], obt[:6]) { t.Fatalf("unexpected selection: too few elements chosen in range:\ngot: %v\nwant:%v", f[:6], obt[:6]) } if reflect.DeepEqual(f[7:], obt[7:]) { t.Fatalf("unexpected selection: too few elements chosen in range:\ngot: %v\nwant:%v", f[7:], obt[7:]) } } func TestWeightIncrease(t *testing.T) { rand.Seed(0) want := Weighted{ weights: []float64{1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 9 * 2, 1 << 7, 1 << 8, 1 << 9}, heap: []float64{ exp[0] + exp[1] + exp[3] + exp[4] + exp[7] + exp[8] + exp[9] + exp[2] + exp[5] + exp[9]*2, exp[1] + exp[3] + exp[4] + exp[7] + exp[8] + exp[9], exp[2] + exp[5] + exp[9]*2, exp[3] + exp[7] + exp[8], exp[4] + exp[9], exp[5], exp[9] * 2, exp[7], exp[8], exp[9], }, } ts := newTestWeighted() ts.Reweight(6, ts.weights[len(ts.weights)-1]*2) if !reflect.DeepEqual(ts, want) { t.Fatalf("unexpected new Weighted value:\ngot: %#v\nwant:%#v", ts, want) } f := make([]float64, len(obt)) for i := 0; i < 1e6; i++ { ts := newTestWeighted() ts.Reweight(6, ts.weights[len(ts.weights)-1]*2) item, ok := ts.Take() if !ok { t.Fatal("Weighted unexpectedly empty") } f[item]++ } exp := newExp() fac := floats.Sum(f) / floats.Sum(exp) for i := range f { exp[i] *= fac } if f[6] < f[9] { t.Errorf("unexpected selection rate for re-weighted item: got: %v want:%v", f[6], f[9]) } if reflect.DeepEqual(f[:6], obt[:6]) { t.Fatalf("unexpected selection: too many elements chosen in range:\ngot: %v\nwant:%v", f[:6], obt[:6]) } if reflect.DeepEqual(f[7:], obt[7:]) { t.Fatalf("unexpected selection: too many elements chosen in range:\ngot: %v\nwant:%v", f[7:], obt[7:]) } } func chi2(ob, ex []float64) (sum float64) { for i := range ob { x := ob[i] - ex[i] sum += (x * x) / ex[i] } return sum } func TestWeightedNoResample(t *testing.T) { const ( tries = 10 n = 10e4 ) ts := NewWeighted(make([]float64, n), nil) w := make([]float64, n) for i := 0; i < tries; i++ { for j := range w { w[j] = rand.Float64() * n } ts.ReweightAll(w) taken := make(map[int]struct{}) var c int for { item, ok := ts.Take() if !ok { if c != n { t.Errorf("unexpected number of items: got: %d want: %d", c, int(n)) } break } c++ if _, exists := taken[item]; exists { t.Errorf("unexpected duplicate sample for item: %d", item) } taken[item] = struct{}{} } } } var issue1866Tests = []struct { weights []float64 seed uint64 }{ {weights: []float64{72000, 166.66666666666666}, seed: 202}, {weights: []float64{0.6666666666666666, 20412, 0}, seed: 0}, } // See https://github.com/gonum/gonum/issues/1866 func TestIssue1866(t *testing.T) { for i, test := range issue1866Tests { w := NewWeighted(test.weights, rand.NewSource(test.seed)) for j := 0; j < len(test.weights)+1; j++ { if panicked(func() { w.Take() }) { t.Errorf("unexpected panic for test %d iteration %d", i, j) } } } } func panicked(fn func()) (yes bool) { defer func() { if recover() != nil { yes = true } }() fn() return false } func FuzzWeightedTake(f *testing.F) { f.Add(0.000001, 0.000000012) f.Fuzz(func(t *testing.T, w1 float64, w2 float64) { if w1 < 0 || w2 < 0 { t.Skip() } weights := []float64{w1, w2} weighted := NewWeighted(weights, rand.NewSource(0)) want := calculateNonZeroWeights(weights) var got int for { _, ok := weighted.Take() if !ok { break } got++ } if got != want { t.Errorf("unexpected taken set size: got=%d, want=%d", got, want) } }) } func calculateNonZeroWeights(weights []float64) int { count := 0 for _, w := range weights { if w != 0 { count++ } } return count } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/withoutreplacement.go000066400000000000000000000031261450372207100247210ustar00rootroot00000000000000// 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 sampleuv import ( "sort" "golang.org/x/exp/rand" ) // WithoutReplacement samples len(idxs) integers from [0, n) without replacement. // That is, upon return the elements of idxs will be unique integers. If source // is non-nil it will be used to generate random numbers, otherwise the default // source from the math/rand package will be used. // // WithoutReplacement will panic if len(idxs) > n. func WithoutReplacement(idxs []int, n int, src rand.Source) { if len(idxs) == 0 { panic("withoutreplacement: zero length input") } if len(idxs) > n { panic("withoutreplacement: impossible size inputs") } // There are two algorithms. One is to generate a random permutation // and take the first len(idxs) elements. The second is to generate // individual random numbers for each element and check uniqueness. The first // method scales as O(n), and the second scales as O(len(idxs)^2). Choose // the algorithm accordingly. if n < len(idxs)*len(idxs) { var perm []int if src != nil { perm = rand.New(src).Perm(n) } else { perm = rand.Perm(n) } copy(idxs, perm) return } // Instead, generate the random numbers directly. sorted := make([]int, 0, len(idxs)) for i := range idxs { var r int if src != nil { r = rand.New(src).Intn(n - i) } else { r = rand.Intn(n - i) } for _, v := range sorted { if r >= v { r++ } } idxs[i] = r sorted = append(sorted, r) sort.Ints(sorted) } } golang-gonum-v1-gonum-0.14.0/stat/sampleuv/withoutreplacement_test.go000066400000000000000000000027021450372207100257570ustar00rootroot00000000000000// 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 sampleuv import ( "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" ) func TestWithoutReplacement(t *testing.T) { for cas, test := range []struct { N int K int Src *rand.Rand Trials int Tol float64 }{ { // Test with perm and source. N: 10, K: 5, Src: rand.New(rand.NewSource(1)), Trials: 100000, Tol: 1e-3, }, { // Test without perm and with source. N: 10, K: 3, Src: rand.New(rand.NewSource(1)), Trials: 100000, Tol: 1e-3, }, } { dist := make([]float64, test.N) for trial := 0; trial < test.Trials; trial++ { idxs := make([]int, test.K) WithoutReplacement(idxs, test.N, test.Src) allDiff := true for i := 0; i < len(idxs); i++ { v := idxs[i] for j := i + 1; j < len(idxs); j++ { if v == idxs[j] { allDiff = false break } } } if !allDiff { t.Errorf("Cas %d: Repeat in sampling. Idxs =%v", cas, idxs) } for _, v := range idxs { dist[v]++ } } div := 1 / (float64(test.Trials) * float64(test.K)) floats.Scale(div, dist) want := make([]float64, test.N) for i := range want { want[i] = 1 / float64(test.N) } if !floats.EqualApprox(want, dist, test.Tol) { t.Errorf("Cas %d: biased sampling. Want = %v, got = %v", cas, want, dist) } } } golang-gonum-v1-gonum-0.14.0/stat/spatial/000077500000000000000000000000001450372207100202465ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/stat/spatial/doc.go000066400000000000000000000004341450372207100213430ustar00rootroot00000000000000// 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 spatial provides spatial statistical functions. package spatial // import "gonum.org/v1/gonum/stat/spatial" golang-gonum-v1-gonum-0.14.0/stat/spatial/spatial.go000066400000000000000000000102211450372207100222260ustar00rootroot00000000000000// 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 spatial import ( "math" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat" ) // TODO(kortschak): Implement weighted routines. // GetisOrdGStar returns the Local Getis-Ord G*i statistic for element of the // weighted data using the provided locality matrix. The returned value is a z-score. // // G^*_i = num_i / den_i // // num_i = \sum_j (w_{ij} x_j) - \bar X \sum_j w_{ij} // den_i = S \sqrt(((n \sum_j w_{ij}^2 - (\sum_j w_{ij})^2))/(n - 1)) // \bar X = (\sum_j x_j) / n // S = \sqrt((\sum_j x_j^2)/n - (\bar X)^2) // // GetisOrdGStar will panic if locality is not a square matrix with dimensions the // same as the length of data or if i is not a valid index into data. // // See doi.org/10.1111%2Fj.1538-4632.1995.tb00912.x. // // Weighted Getis-Ord G*i is not currently implemented and GetisOrdGStar will // panic if weights is not nil. func GetisOrdGStar(i int, data, weights []float64, locality mat.Matrix) float64 { if weights != nil { panic("spatial: weighted data not yet implemented") } r, c := locality.Dims() if r != len(data) || c != len(data) { panic("spatial: data length mismatch") } n := float64(len(data)) mean, std := stat.MeanStdDev(data, weights) var dwd, dww, sw float64 if doer, ok := locality.(mat.RowNonZeroDoer); ok { doer.DoRowNonZero(i, func(_, j int, w float64) { sw += w dwd += w * data[j] dww += w * w }) } else { for j, v := range data { w := locality.At(i, j) sw += w dwd += w * v dww += w * w } } s := std * math.Sqrt((n-1)/n) return (dwd - mean*sw) / (s * math.Sqrt((n*dww-sw*sw)/(n-1))) } // GlobalMoransI performs Global Moran's I calculation of spatial autocorrelation // for the given data using the provided locality matrix. GlobalMoransI returns // Moran's I, Var(I) and the z-score associated with those values. // GlobalMoransI will panic if locality is not a square matrix with dimensions the // same as the length of data. // // See https://doi.org/10.1111%2Fj.1538-4632.2007.00708.x. // // Weighted Global Moran's I is not currently implemented and GlobalMoransI will // panic if weights is not nil. func GlobalMoransI(data, weights []float64, locality mat.Matrix) (i, v, z float64) { if weights != nil { panic("spatial: weighted data not yet implemented") } if r, c := locality.Dims(); r != len(data) || c != len(data) { panic("spatial: data length mismatch") } mean := stat.Mean(data, nil) doer, isDoer := locality.(mat.RowNonZeroDoer) // Calculate Moran's I for the data. var num, den, sum float64 for i, xi := range data { zi := xi - mean den += zi * zi if isDoer { doer.DoRowNonZero(i, func(_, j int, w float64) { sum += w zj := data[j] - mean num += w * zi * zj }) } else { for j, xj := range data { w := locality.At(i, j) sum += w zj := xj - mean num += w * zi * zj } } } i = (float64(len(data)) / sum) * (num / den) // Calculate Moran's E(I) for the data. e := -1 / float64(len(data)-1) // Calculate Moran's Var(I) for the data. // http://pro.arcgis.com/en/pro-app/tool-reference/spatial-statistics/h-how-spatial-autocorrelation-moran-s-i-spatial-st.htm // http://pro.arcgis.com/en/pro-app/tool-reference/spatial-statistics/h-global-morans-i-additional-math.htm var s0, s1, s2 float64 var var2, var4 float64 for i, v := range data { v -= mean v *= v var2 += v var4 += v * v var p2 float64 if isDoer { doer.DoRowNonZero(i, func(i, j int, wij float64) { wji := locality.At(j, i) s0 += wij v := wij + wji s1 += v * v p2 += v }) } else { for j := range data { wij := locality.At(i, j) wji := locality.At(j, i) s0 += wij v := wij + wji s1 += v * v p2 += v } } s2 += p2 * p2 } s1 *= 0.5 n := float64(len(data)) a := n * ((n*n-3*n+3)*s1 - n*s2 + 3*s0*s0) c := (n - 1) * (n - 2) * (n - 3) * s0 * s0 d := var4 / (var2 * var2) b := d * ((n*n-n)*s1 - 2*n*s2 + 6*s0*s0) v = (a-b)/c - e*e // Calculate z-score associated with Moran's I for the data. z = (i - e) / math.Sqrt(v) return i, v, z } golang-gonum-v1-gonum-0.14.0/stat/spatial/spatial_areal_example_test.go000066400000000000000000000040151450372207100261500ustar00rootroot00000000000000// 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 spatial_test import ( "fmt" "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/spatial" ) // Euclid is a mat.Matrix whose elements reflects the Euclidean // distance between a series of unit-separated points strided // to be arranged in an x by y grid. type Euclid struct{ x, y int } func (e Euclid) Dims() (r, c int) { return e.x * e.y, e.x * e.y } func (e Euclid) At(i, j int) float64 { d := e.x * e.y if i < 0 || d <= i || j < 0 || d <= j { panic("bounds error") } if i == j { return 0 } x := float64(j%e.x - i%e.x) y := float64(j/e.x - i/e.x) return 1 / math.Hypot(x, y) } func (e Euclid) T() mat.Matrix { return mat.Transpose{Matrix: e} } func ExampleGlobalMoransI_areal() { locality := Euclid{10, 10} data1 := []float64{ 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, } i1, _, z1 := spatial.GlobalMoransI(data1, nil, locality) data2 := []float64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, } i2, _, z2 := spatial.GlobalMoransI(data2, nil, locality) fmt.Printf("%v scattered points Moran's I=%.4v z-score=%.4v\n", floats.Sum(data1), i1, z1) fmt.Printf("%v clustered points Moran's I=%.4v z-score=%.4v\n", floats.Sum(data2), i2, z2) // Output: // // 24 scattered points Moran's I=-0.02999 z-score=-1.913 // 24 clustered points Moran's I=0.09922 z-score=10.52 } golang-gonum-v1-gonum-0.14.0/stat/spatial/spatial_example_test.go000066400000000000000000000061241450372207100250070ustar00rootroot00000000000000// 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 spatial_test import ( "fmt" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/spatial" ) func ExampleGlobalMoransI_linear() { data := []float64{0, 0, 0, 1, 1, 1, 0, 1, 0, 0} // The locality here describes spatial neighbor // relationships. locality := mat.NewDense(10, 10, []float64{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, }) i, _, z := spatial.GlobalMoransI(data, nil, locality) fmt.Printf("Moran's I=%.4v z-score=%.4v\n", i, z) // Output: // // Moran's I=0.1111 z-score=0.6335 } func ExampleGlobalMoransI_banded() { data := []float64{0, 0, 0, 1, 1, 1, 0, 1, 0, 0} // The locality here describes spatial neighbor // relationships. // This example uses the band matrix representation // to improve time and space efficiency. locality := mat.NewBandDense(10, 10, 1, 1, []float64{ 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, }) i, _, z := spatial.GlobalMoransI(data, nil, locality) fmt.Printf("Moran's I=%.4v z-score=%.4v\n", i, z) // Output: // // Moran's I=0.1111 z-score=0.6335 } func ExampleGetisOrdGStar() { data := []float64{0, 0, 0, 1, 1, 1, 0, 1, 0, 0} // The locality here describes spatial neighbor // relationships including self. locality := mat.NewDense(10, 10, []float64{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, }) for i, v := range data { fmt.Printf("v=%v G*i=% .4v\n", v, spatial.GetisOrdGStar(i, data, nil, locality)) } // Output: // // v=0 G*i=-1.225 // v=0 G*i=-1.604 // v=0 G*i=-0.2673 // v=1 G*i= 1.069 // v=1 G*i= 2.405 // v=1 G*i= 1.069 // v=0 G*i= 1.069 // v=1 G*i=-0.2673 // v=0 G*i=-0.2673 // v=0 G*i=-1.225 } func ExampleGetisOrdGStar_banded() { data := []float64{0, 0, 0, 1, 1, 1, 0, 1, 0, 0} // The locality here describes spatial neighbor // relationships including self. // This example uses the band matrix representation // to improve time and space efficiency. locality := mat.NewBandDense(10, 10, 1, 1, []float64{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, }) for i, v := range data { fmt.Printf("v=%v G*i=% .4v\n", v, spatial.GetisOrdGStar(i, data, nil, locality)) } // Output: // // v=0 G*i=-1.225 // v=0 G*i=-1.604 // v=0 G*i=-0.2673 // v=1 G*i= 1.069 // v=1 G*i= 2.405 // v=1 G*i= 1.069 // v=0 G*i= 1.069 // v=1 G*i=-0.2673 // v=0 G*i=-0.2673 // v=0 G*i=-1.225 } golang-gonum-v1-gonum-0.14.0/stat/spatial/spatial_test.go000066400000000000000000000151141450372207100232730ustar00rootroot00000000000000// 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 spatial import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/mat" ) func simpleAdjacency(n, wide int, diag bool) mat.Matrix { m := mat.NewDense(n, n, nil) for i := 0; i < n; i++ { for j := 1; j <= wide; j++ { if j > i { continue } m.Set(i-j, i, 1) m.Set(i, i-j, 1) } if diag { m.Set(i, i, 1) } } return m } func simpleAdjacencyBand(n, wide int, diag bool) mat.Matrix { m := mat.NewBandDense(n, n, wide, wide, nil) for i := 0; i < n; i++ { for j := 1; j <= wide; j++ { if j > i { continue } m.SetBand(i-j, i, 1) m.SetBand(i, i-j, 1) } if diag { m.SetBand(i, i, 1) } } return m } var spatialTests = []struct { from, to float64 n, wide int fn func(float64, int, *rand.Rand) float64 locality func(n, wide int, diag bool) mat.Matrix // Values for MoranI and z-score are obtained from // an R reference implementation. wantMoranI float64 wantZ float64 // The value for expected number of significant // segments is obtained from visual inspection // of the plotted data. wantSegs int }{ // Dense matrix locality. { from: 0, to: 1, n: 1000, wide: 1, fn: func(_ float64, _ int, rnd *rand.Rand) float64 { return rnd.Float64() }, locality: simpleAdjacency, wantMoranI: -0.04387221370785312, wantZ: -1.3543515772206267, wantSegs: 0, }, { from: -math.Pi / 2, to: 3 * math.Pi / 2, n: 1000, wide: 1, fn: func(x float64, _ int, _ *rand.Rand) float64 { y := math.Sin(x) if math.Abs(y) > 0.5 { y *= 1/math.Abs(y) - 1 } return y * math.Sin(x*2) }, locality: simpleAdjacency, wantMoranI: 1.0008149537991464, wantZ: 31.648547078779092, wantSegs: 4, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(_ float64, _ int, rnd *rand.Rand) float64 { return rnd.NormFloat64() }, locality: simpleAdjacency, wantMoranI: 0.0259414094549987, wantZ: 0.8511426395944303, wantSegs: 0, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(x float64, _ int, rnd *rand.Rand) float64 { if rnd.Float64() < 0.5 { return rnd.NormFloat64() + 5 } return rnd.NormFloat64() }, locality: simpleAdjacency, wantMoranI: -0.0003533345592575677, wantZ: 0.0204605353504713, wantSegs: 0, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(x float64, i int, rnd *rand.Rand) float64 { if i%2 == 0 { return rnd.NormFloat64() + 5 } return rnd.NormFloat64() }, locality: simpleAdjacency, wantMoranI: -0.8587138204405251, wantZ: -27.09614459007475, wantSegs: 0, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(_ float64, i int, _ *rand.Rand) float64 { return float64(i % 2) }, locality: simpleAdjacency, wantMoranI: -1, wantZ: -31.559531064275987, wantSegs: 0, }, // Band matrix locality. { from: 0, to: 1, n: 1000, wide: 1, fn: func(_ float64, _ int, rnd *rand.Rand) float64 { return rnd.Float64() }, locality: simpleAdjacencyBand, wantMoranI: -0.04387221370785312, wantZ: -1.3543515772206267, wantSegs: 0, }, { from: -math.Pi / 2, to: 3 * math.Pi / 2, n: 1000, wide: 1, fn: func(x float64, _ int, _ *rand.Rand) float64 { y := math.Sin(x) if math.Abs(y) > 0.5 { y *= 1/math.Abs(y) - 1 } return y * math.Sin(x*2) }, locality: simpleAdjacencyBand, wantMoranI: 1.0008149537991464, wantZ: 31.648547078779092, wantSegs: 4, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(_ float64, _ int, rnd *rand.Rand) float64 { return rnd.NormFloat64() }, locality: simpleAdjacencyBand, wantMoranI: 0.0259414094549987, wantZ: 0.8511426395944303, wantSegs: 0, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(x float64, _ int, rnd *rand.Rand) float64 { if rnd.Float64() < 0.5 { return rnd.NormFloat64() + 5 } return rnd.NormFloat64() }, locality: simpleAdjacencyBand, wantMoranI: -0.0003533345592575677, wantZ: 0.0204605353504713, wantSegs: 0, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(x float64, i int, rnd *rand.Rand) float64 { if i%2 == 0 { return rnd.NormFloat64() + 5 } return rnd.NormFloat64() }, locality: simpleAdjacencyBand, wantMoranI: -0.8587138204405251, wantZ: -27.09614459007475, wantSegs: 0, }, { from: 0, to: 1, n: 1000, wide: 1, fn: func(_ float64, i int, _ *rand.Rand) float64 { return float64(i % 2) }, locality: simpleAdjacencyBand, wantMoranI: -1, wantZ: -31.559531064275987, wantSegs: 0, }, } func TestGetisOrd(t *testing.T) { for ti, test := range spatialTests { rnd := rand.New(rand.NewSource(1)) data := make([]float64, test.n) step := (test.to - test.from) / float64(test.n) for i := range data { data[i] = test.fn(test.from+step*float64(i), i, rnd) } locality := test.locality(test.n, test.wide, true) nseg := getisOrdSegments(data, nil, locality) if nseg != test.wantSegs { t.Errorf("unexpected number of significant segments for test %d: got:%d want:%d", ti, nseg, test.wantSegs) } } } // getisOrdSegments returns the number of contiguously significant G*i segemtns in // data. This allows an intuitive validation of the function in lieu of a reference // implementation. func getisOrdSegments(data, weight []float64, locality mat.Matrix) int { const thresh = 2 var nseg int segstart := -1 for i := range data { gi := GetisOrdGStar(i, data, weight, locality) if segstart != -1 { if math.Abs(gi) < thresh { // Filter short segments. if i-segstart < 5 { segstart = -1 continue } segstart = -1 nseg++ } continue } if math.Abs(gi) >= thresh { segstart = i } } if segstart != -1 && len(data)-segstart >= 5 { nseg++ } return nseg } func TestGlobalMoransI(t *testing.T) { const tol = 1e-14 for ti, test := range spatialTests { rnd := rand.New(rand.NewSource(1)) data := make([]float64, test.n) step := (test.to - test.from) / float64(test.n) for i := range data { data[i] = test.fn(test.from+step*float64(i), i, rnd) } locality := test.locality(test.n, test.wide, false) gotI, _, gotZ := GlobalMoransI(data, nil, locality) if !scalar.EqualWithinAbsOrRel(gotI, test.wantMoranI, tol, tol) { t.Errorf("unexpected Moran's I value for test %d: got:%v want:%v", ti, gotI, test.wantMoranI) } if !scalar.EqualWithinAbsOrRel(gotZ, test.wantZ, tol, tol) { t.Errorf("unexpected Moran's I z-score for test %d: got:%v want:%v", ti, gotZ, test.wantZ) } } } golang-gonum-v1-gonum-0.14.0/stat/stat.go000066400000000000000000001117121450372207100201160ustar00rootroot00000000000000// 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 stat import ( "math" "sort" "gonum.org/v1/gonum/floats" ) // CumulantKind specifies the behavior for calculating the empirical CDF or Quantile type CumulantKind int // List of supported CumulantKind values for the Quantile function. // Constant values should match the R nomenclature. See // https://en.wikipedia.org/wiki/Quantile#Estimating_the_quantiles_of_a_population const ( // Empirical treats the distribution as the actual empirical distribution. Empirical CumulantKind = 1 // LinInterp linearly interpolates the empirical distribution between sample values, with a flat extrapolation. LinInterp CumulantKind = 4 ) // bhattacharyyaCoeff computes the Bhattacharyya Coefficient for probability distributions given by: // // \sum_i \sqrt{p_i q_i} // // It is assumed that p and q have equal length. func bhattacharyyaCoeff(p, q []float64) float64 { var bc float64 for i, a := range p { bc += math.Sqrt(a * q[i]) } return bc } // Bhattacharyya computes the distance between the probability distributions p and q given by: // // -\ln ( \sum_i \sqrt{p_i q_i} ) // // The lengths of p and q must be equal. It is assumed that p and q sum to 1. func Bhattacharyya(p, q []float64) float64 { if len(p) != len(q) { panic("stat: slice length mismatch") } bc := bhattacharyyaCoeff(p, q) return -math.Log(bc) } // CDF returns the empirical cumulative distribution function value of x, that is // the fraction of the samples less than or equal to q. The // exact behavior is determined by the CumulantKind. CDF is theoretically // the inverse of the Quantile function, though it may not be the actual inverse // for all values q and CumulantKinds. // // The x data must be sorted in increasing order. If weights is nil then all // of the weights are 1. If weights is not nil, then len(x) must equal len(weights). // CDF will panic if the length of x is zero. // // CumulantKind behaviors: // - Empirical: Returns the lowest fraction for which q is greater than or equal // to that fraction of samples func CDF(q float64, c CumulantKind, x, weights []float64) float64 { if weights != nil && len(x) != len(weights) { panic("stat: slice length mismatch") } if floats.HasNaN(x) { return math.NaN() } if len(x) == 0 { panic("stat: zero length slice") } if !sort.Float64sAreSorted(x) { panic("x data are not sorted") } if q < x[0] { return 0 } if q >= x[len(x)-1] { return 1 } var sumWeights float64 if weights == nil { sumWeights = float64(len(x)) } else { sumWeights = floats.Sum(weights) } // Calculate the index switch c { case Empirical: // Find the smallest value that is greater than that percent of the samples var w float64 for i, v := range x { if v > q { return w / sumWeights } if weights == nil { w++ } else { w += weights[i] } } panic("impossible") default: panic("stat: bad cumulant kind") } } // ChiSquare computes the chi-square distance between the observed frequencies 'obs' and // expected frequencies 'exp' given by: // // \sum_i (obs_i-exp_i)^2 / exp_i // // The lengths of obs and exp must be equal. func ChiSquare(obs, exp []float64) float64 { if len(obs) != len(exp) { panic("stat: slice length mismatch") } var result float64 for i, a := range obs { b := exp[i] if a == 0 && b == 0 { continue } result += (a - b) * (a - b) / b } return result } // CircularMean returns the circular mean of the dataset. // // atan2(\sum_i w_i * sin(alpha_i), \sum_i w_i * cos(alpha_i)) // // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func CircularMean(x, weights []float64) float64 { if weights != nil && len(x) != len(weights) { panic("stat: slice length mismatch") } var aX, aY float64 if weights != nil { for i, v := range x { aX += weights[i] * math.Cos(v) aY += weights[i] * math.Sin(v) } } else { for _, v := range x { aX += math.Cos(v) aY += math.Sin(v) } } return math.Atan2(aY, aX) } // Correlation returns the weighted correlation between the samples of x and y // with the given means. // // sum_i {w_i (x_i - meanX) * (y_i - meanY)} / (stdX * stdY) // // The lengths of x and y must be equal. If weights is nil then all of the // weights are 1. If weights is not nil, then len(x) must equal len(weights). func Correlation(x, y, weights []float64) float64 { // This is a two-pass corrected implementation. It is an adaptation of the // algorithm used in the MeanVariance function, which applies a correction // to the typical two pass approach. if len(x) != len(y) { panic("stat: slice length mismatch") } xu := Mean(x, weights) yu := Mean(y, weights) var ( sxx float64 syy float64 sxy float64 xcompensation float64 ycompensation float64 ) if weights == nil { for i, xv := range x { yv := y[i] xd := xv - xu yd := yv - yu sxx += xd * xd syy += yd * yd sxy += xd * yd xcompensation += xd ycompensation += yd } // xcompensation and ycompensation are from Chan, et. al. // referenced in the MeanVariance function. They are analogous // to the second term in (1.7) in that paper. sxx -= xcompensation * xcompensation / float64(len(x)) syy -= ycompensation * ycompensation / float64(len(x)) return (sxy - xcompensation*ycompensation/float64(len(x))) / math.Sqrt(sxx*syy) } var sumWeights float64 for i, xv := range x { w := weights[i] yv := y[i] xd := xv - xu wxd := w * xd yd := yv - yu wyd := w * yd sxx += wxd * xd syy += wyd * yd sxy += wxd * yd xcompensation += wxd ycompensation += wyd sumWeights += w } // xcompensation and ycompensation are from Chan, et. al. // referenced in the MeanVariance function. They are analogous // to the second term in (1.7) in that paper, except they use // the sumWeights instead of the sample count. sxx -= xcompensation * xcompensation / sumWeights syy -= ycompensation * ycompensation / sumWeights return (sxy - xcompensation*ycompensation/sumWeights) / math.Sqrt(sxx*syy) } // Kendall returns the weighted Tau-a Kendall correlation between the // samples of x and y. The Kendall correlation measures the quantity of // concordant and discordant pairs of numbers. If weights are specified then // each pair is weighted by weights[i] * weights[j] and the final sum is // normalized to stay between -1 and 1. // The lengths of x and y must be equal. If weights is nil then all of the // weights are 1. If weights is not nil, then len(x) must equal len(weights). func Kendall(x, y, weights []float64) float64 { if len(x) != len(y) { panic("stat: slice length mismatch") } var ( cc float64 // number of concordant pairs dc float64 // number of discordant pairs n = len(x) ) if weights == nil { for i := 0; i < n; i++ { for j := i; j < n; j++ { if i == j { continue } if math.Signbit(x[j]-x[i]) == math.Signbit(y[j]-y[i]) { cc++ } else { dc++ } } } return (cc - dc) / float64(n*(n-1)/2) } var sumWeights float64 for i := 0; i < n; i++ { for j := i; j < n; j++ { if i == j { continue } weight := weights[i] * weights[j] if math.Signbit(x[j]-x[i]) == math.Signbit(y[j]-y[i]) { cc += weight } else { dc += weight } sumWeights += weight } } return float64(cc-dc) / sumWeights } // Covariance returns the weighted covariance between the samples of x and y. // // sum_i {w_i (x_i - meanX) * (y_i - meanY)} / (sum_j {w_j} - 1) // // The lengths of x and y must be equal. If weights is nil then all of the // weights are 1. If weights is not nil, then len(x) must equal len(weights). func Covariance(x, y, weights []float64) float64 { // This is a two-pass corrected implementation. It is an adaptation of the // algorithm used in the MeanVariance function, which applies a correction // to the typical two pass approach. if len(x) != len(y) { panic("stat: slice length mismatch") } xu := Mean(x, weights) yu := Mean(y, weights) return covarianceMeans(x, y, weights, xu, yu) } // covarianceMeans returns the weighted covariance between x and y with the mean // of x and y already specified. See the documentation of Covariance for more // information. func covarianceMeans(x, y, weights []float64, xu, yu float64) float64 { var ( ss float64 xcompensation float64 ycompensation float64 ) if weights == nil { for i, xv := range x { yv := y[i] xd := xv - xu yd := yv - yu ss += xd * yd xcompensation += xd ycompensation += yd } // xcompensation and ycompensation are from Chan, et. al. // referenced in the MeanVariance function. They are analogous // to the second term in (1.7) in that paper. return (ss - xcompensation*ycompensation/float64(len(x))) / float64(len(x)-1) } var sumWeights float64 for i, xv := range x { w := weights[i] yv := y[i] wxd := w * (xv - xu) yd := (yv - yu) ss += wxd * yd xcompensation += wxd ycompensation += w * yd sumWeights += w } // xcompensation and ycompensation are from Chan, et. al. // referenced in the MeanVariance function. They are analogous // to the second term in (1.7) in that paper, except they use // the sumWeights instead of the sample count. return (ss - xcompensation*ycompensation/sumWeights) / (sumWeights - 1) } // CrossEntropy computes the cross-entropy between the two distributions specified // in p and q. func CrossEntropy(p, q []float64) float64 { if len(p) != len(q) { panic("stat: slice length mismatch") } var ce float64 for i, v := range p { if v != 0 { ce -= v * math.Log(q[i]) } } return ce } // Entropy computes the Shannon entropy of a distribution or the distance between // two distributions. The natural logarithm is used. // - sum_i (p_i * log_e(p_i)) func Entropy(p []float64) float64 { var e float64 for _, v := range p { if v != 0 { // Entropy needs 0 * log(0) == 0. e -= v * math.Log(v) } } return e } // ExKurtosis returns the population excess kurtosis of the sample. // The kurtosis is defined by the 4th moment of the mean divided by the squared // variance. The excess kurtosis subtracts 3.0 so that the excess kurtosis of // the normal distribution is zero. // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func ExKurtosis(x, weights []float64) float64 { mean, std := MeanStdDev(x, weights) if weights == nil { var e float64 for _, v := range x { z := (v - mean) / std e += z * z * z * z } mul, offset := kurtosisCorrection(float64(len(x))) return e*mul - offset } var ( e float64 sumWeights float64 ) for i, v := range x { z := (v - mean) / std e += weights[i] * z * z * z * z sumWeights += weights[i] } mul, offset := kurtosisCorrection(sumWeights) return e*mul - offset } // n is the number of samples // see https://en.wikipedia.org/wiki/Kurtosis func kurtosisCorrection(n float64) (mul, offset float64) { return ((n + 1) / (n - 1)) * (n / (n - 2)) * (1 / (n - 3)), 3 * ((n - 1) / (n - 2)) * ((n - 1) / (n - 3)) } // GeometricMean returns the weighted geometric mean of the dataset // // \prod_i {x_i ^ w_i} // // This only applies with positive x and positive weights. If weights is nil // then all of the weights are 1. If weights is not nil, then len(x) must equal // len(weights). func GeometricMean(x, weights []float64) float64 { if weights == nil { var s float64 for _, v := range x { s += math.Log(v) } s /= float64(len(x)) return math.Exp(s) } if len(x) != len(weights) { panic("stat: slice length mismatch") } var ( s float64 sumWeights float64 ) for i, v := range x { s += weights[i] * math.Log(v) sumWeights += weights[i] } s /= sumWeights return math.Exp(s) } // HarmonicMean returns the weighted harmonic mean of the dataset // // \sum_i {w_i} / ( sum_i {w_i / x_i} ) // // This only applies with positive x and positive weights. // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func HarmonicMean(x, weights []float64) float64 { if weights != nil && len(x) != len(weights) { panic("stat: slice length mismatch") } // TODO(btracey): Fix this to make it more efficient and avoid allocation. // This can be numerically unstable (for example if x is very small). // W = \sum_i {w_i} // hm = exp(log(W) - log(\sum_i w_i / x_i)) logs := make([]float64, len(x)) var W float64 for i := range x { if weights == nil { logs[i] = -math.Log(x[i]) W++ continue } logs[i] = math.Log(weights[i]) - math.Log(x[i]) W += weights[i] } // Sum all of the logs v := floats.LogSumExp(logs) // This computes log(\sum_i { w_i / x_i}). return math.Exp(math.Log(W) - v) } // Hellinger computes the distance between the probability distributions p and q given by: // // \sqrt{ 1 - \sum_i \sqrt{p_i q_i} } // // The lengths of p and q must be equal. It is assumed that p and q sum to 1. func Hellinger(p, q []float64) float64 { if len(p) != len(q) { panic("stat: slice length mismatch") } bc := bhattacharyyaCoeff(p, q) return math.Sqrt(1 - bc) } // Histogram sums up the weighted number of data points in each bin. // The weight of data point x[i] will be placed into count[j] if // dividers[j] <= x < dividers[j+1]. The "span" function in the floats package can assist // with bin creation. // // The following conditions on the inputs apply: // - The count variable must either be nil or have length of one less than dividers. // - The values in dividers must be sorted (use the sort package). // - The x values must be sorted. // - If weights is nil then all of the weights are 1. // - If weights is not nil, then len(x) must equal len(weights). func Histogram(count, dividers, x, weights []float64) []float64 { if weights != nil && len(x) != len(weights) { panic("stat: slice length mismatch") } if count == nil { count = make([]float64, len(dividers)-1) } if len(dividers) < 2 { panic("histogram: fewer than two dividers") } if len(count) != len(dividers)-1 { panic("histogram: bin count mismatch") } if !sort.Float64sAreSorted(dividers) { panic("histogram: dividers are not sorted") } if !sort.Float64sAreSorted(x) { panic("histogram: x data are not sorted") } for i := range count { count[i] = 0 } if len(x) == 0 { return count } if x[0] < dividers[0] { panic("histogram: minimum x value is less than lowest divider") } if dividers[len(dividers)-1] <= x[len(x)-1] { panic("histogram: maximum x value is greater than or equal to highest divider") } idx := 0 comp := dividers[idx+1] if weights == nil { for _, v := range x { if v < comp { // Still in the current bucket. count[idx]++ continue } // Find the next divider where v is less than the divider. for j := idx + 1; j < len(dividers); j++ { if v < dividers[j+1] { idx = j comp = dividers[j+1] break } } count[idx]++ } return count } for i, v := range x { if v < comp { // Still in the current bucket. count[idx] += weights[i] continue } // Need to find the next divider where v is less than the divider. for j := idx + 1; j < len(count); j++ { if v < dividers[j+1] { idx = j comp = dividers[j+1] break } } count[idx] += weights[i] } return count } // JensenShannon computes the JensenShannon divergence between the distributions // p and q. The Jensen-Shannon divergence is defined as // // m = 0.5 * (p + q) // JS(p, q) = 0.5 ( KL(p, m) + KL(q, m) ) // // Unlike Kullback-Leibler, the Jensen-Shannon distance is symmetric. The value // is between 0 and ln(2). func JensenShannon(p, q []float64) float64 { if len(p) != len(q) { panic("stat: slice length mismatch") } var js float64 for i, v := range p { qi := q[i] m := 0.5 * (v + qi) if v != 0 { // add kl from p to m js += 0.5 * v * (math.Log(v) - math.Log(m)) } if qi != 0 { // add kl from q to m js += 0.5 * qi * (math.Log(qi) - math.Log(m)) } } return js } // KolmogorovSmirnov computes the largest distance between two empirical CDFs. // Each dataset x and y consists of sample locations and counts, xWeights and // yWeights, respectively. // // x and y may have different lengths, though len(x) must equal len(xWeights), and // len(y) must equal len(yWeights). Both x and y must be sorted. // // Special cases are: // // = 0 if len(x) == len(y) == 0 // = 1 if len(x) == 0, len(y) != 0 or len(x) != 0 and len(y) == 0 func KolmogorovSmirnov(x, xWeights, y, yWeights []float64) float64 { if xWeights != nil && len(x) != len(xWeights) { panic("stat: slice length mismatch") } if yWeights != nil && len(y) != len(yWeights) { panic("stat: slice length mismatch") } if len(x) == 0 || len(y) == 0 { if len(x) == 0 && len(y) == 0 { return 0 } return 1 } if floats.HasNaN(x) { return math.NaN() } if floats.HasNaN(y) { return math.NaN() } if !sort.Float64sAreSorted(x) { panic("x data are not sorted") } if !sort.Float64sAreSorted(y) { panic("y data are not sorted") } xWeightsNil := xWeights == nil yWeightsNil := yWeights == nil var ( maxDist float64 xSum, ySum float64 xCdf, yCdf float64 xIdx, yIdx int ) if xWeightsNil { xSum = float64(len(x)) } else { xSum = floats.Sum(xWeights) } if yWeightsNil { ySum = float64(len(y)) } else { ySum = floats.Sum(yWeights) } xVal := x[0] yVal := y[0] // Algorithm description: // The goal is to find the maximum difference in the empirical CDFs for the // two datasets. The CDFs are piecewise-constant, and thus the distance // between the CDFs will only change at the values themselves. // // To find the maximum distance, step through the data in ascending order // of value between the two datasets. At each step, compute the empirical CDF // and compare the local distance with the maximum distance. // Due to some corner cases, equal data entries must be tallied simultaneously. for { switch { case xVal < yVal: xVal, xCdf, xIdx = updateKS(xIdx, xCdf, xSum, x, xWeights, xWeightsNil) case yVal < xVal: yVal, yCdf, yIdx = updateKS(yIdx, yCdf, ySum, y, yWeights, yWeightsNil) case xVal == yVal: newX := x[xIdx] newY := y[yIdx] if newX < newY { xVal, xCdf, xIdx = updateKS(xIdx, xCdf, xSum, x, xWeights, xWeightsNil) } else if newY < newX { yVal, yCdf, yIdx = updateKS(yIdx, yCdf, ySum, y, yWeights, yWeightsNil) } else { // Update them both, they'll be equal next time and the right // thing will happen. xVal, xCdf, xIdx = updateKS(xIdx, xCdf, xSum, x, xWeights, xWeightsNil) yVal, yCdf, yIdx = updateKS(yIdx, yCdf, ySum, y, yWeights, yWeightsNil) } default: panic("unreachable") } dist := math.Abs(xCdf - yCdf) if dist > maxDist { maxDist = dist } // Both xCdf and yCdf will equal 1 at the end, so if we have reached the // end of either sample list, the distance is as large as it can be. if xIdx == len(x) || yIdx == len(y) { return maxDist } } } // updateKS gets the next data point from one of the set. In doing so, it combines // the weight of all the data points of equal value. Upon return, val is the new // value of the data set, newCdf is the total combined CDF up until this point, // and newIdx is the index of the next location in that sample to examine. func updateKS(idx int, cdf, sum float64, values, weights []float64, isNil bool) (val, newCdf float64, newIdx int) { // Sum up all the weights of consecutive values that are equal. if isNil { newCdf = cdf + 1/sum } else { newCdf = cdf + weights[idx]/sum } newIdx = idx + 1 for { if newIdx == len(values) { return values[newIdx-1], newCdf, newIdx } if values[newIdx-1] != values[newIdx] { return values[newIdx], newCdf, newIdx } if isNil { newCdf += 1 / sum } else { newCdf += weights[newIdx] / sum } newIdx++ } } // KullbackLeibler computes the Kullback-Leibler distance between the // distributions p and q. The natural logarithm is used. // // sum_i(p_i * log(p_i / q_i)) // // Note that the Kullback-Leibler distance is not symmetric; // KullbackLeibler(p,q) != KullbackLeibler(q,p) func KullbackLeibler(p, q []float64) float64 { if len(p) != len(q) { panic("stat: slice length mismatch") } var kl float64 for i, v := range p { if v != 0 { // Entropy needs 0 * log(0) == 0. kl += v * (math.Log(v) - math.Log(q[i])) } } return kl } // LinearRegression computes the best-fit line // // y = alpha + beta*x // // to the data in x and y with the given weights. If origin is true, the // regression is forced to pass through the origin. // // Specifically, LinearRegression computes the values of alpha and // beta such that the total residual // // \sum_i w[i]*(y[i] - alpha - beta*x[i])^2 // // is minimized. If origin is true, then alpha is forced to be zero. // // The lengths of x and y must be equal. If weights is nil then all of the // weights are 1. If weights is not nil, then len(x) must equal len(weights). func LinearRegression(x, y, weights []float64, origin bool) (alpha, beta float64) { if len(x) != len(y) { panic("stat: slice length mismatch") } if weights != nil && len(weights) != len(x) { panic("stat: slice length mismatch") } w := 1.0 if origin { var x2Sum, xySum float64 for i, xi := range x { if weights != nil { w = weights[i] } yi := y[i] xySum += w * xi * yi x2Sum += w * xi * xi } beta = xySum / x2Sum return 0, beta } xu, xv := MeanVariance(x, weights) yu := Mean(y, weights) cov := covarianceMeans(x, y, weights, xu, yu) beta = cov / xv alpha = yu - beta*xu return alpha, beta } // RSquared returns the coefficient of determination defined as // // R^2 = 1 - \sum_i w[i]*(y[i] - alpha - beta*x[i])^2 / \sum_i w[i]*(y[i] - mean(y))^2 // // for the line // // y = alpha + beta*x // // and the data in x and y with the given weights. // // The lengths of x and y must be equal. If weights is nil then all of the // weights are 1. If weights is not nil, then len(x) must equal len(weights). func RSquared(x, y, weights []float64, alpha, beta float64) float64 { if len(x) != len(y) { panic("stat: slice length mismatch") } if weights != nil && len(weights) != len(x) { panic("stat: slice length mismatch") } w := 1.0 yMean := Mean(y, weights) var res, tot, d float64 for i, xi := range x { if weights != nil { w = weights[i] } yi := y[i] fi := alpha + beta*xi d = yi - fi res += w * d * d d = yi - yMean tot += w * d * d } return 1 - res/tot } // RSquaredFrom returns the coefficient of determination defined as // // R^2 = 1 - \sum_i w[i]*(estimate[i] - value[i])^2 / \sum_i w[i]*(value[i] - mean(values))^2 // // and the data in estimates and values with the given weights. // // The lengths of estimates and values must be equal. If weights is nil then // all of the weights are 1. If weights is not nil, then len(values) must // equal len(weights). func RSquaredFrom(estimates, values, weights []float64) float64 { if len(estimates) != len(values) { panic("stat: slice length mismatch") } if weights != nil && len(weights) != len(values) { panic("stat: slice length mismatch") } w := 1.0 mean := Mean(values, weights) var res, tot, d float64 for i, val := range values { if weights != nil { w = weights[i] } d = val - estimates[i] res += w * d * d d = val - mean tot += w * d * d } return 1 - res/tot } // RNoughtSquared returns the coefficient of determination defined as // // R₀^2 = \sum_i w[i]*(beta*x[i])^2 / \sum_i w[i]*y[i]^2 // // for the line // // y = beta*x // // and the data in x and y with the given weights. RNoughtSquared should // only be used for best-fit lines regressed through the origin. // // The lengths of x and y must be equal. If weights is nil then all of the // weights are 1. If weights is not nil, then len(x) must equal len(weights). func RNoughtSquared(x, y, weights []float64, beta float64) float64 { if len(x) != len(y) { panic("stat: slice length mismatch") } if weights != nil && len(weights) != len(x) { panic("stat: slice length mismatch") } w := 1.0 var ssr, tot float64 for i, xi := range x { if weights != nil { w = weights[i] } fi := beta * xi ssr += w * fi * fi yi := y[i] tot += w * yi * yi } return ssr / tot } // Mean computes the weighted mean of the data set. // // sum_i {w_i * x_i} / sum_i {w_i} // // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func Mean(x, weights []float64) float64 { if weights == nil { return floats.Sum(x) / float64(len(x)) } if len(x) != len(weights) { panic("stat: slice length mismatch") } var ( sumValues float64 sumWeights float64 ) for i, w := range weights { sumValues += w * x[i] sumWeights += w } return sumValues / sumWeights } // Mode returns the most common value in the dataset specified by x and the // given weights. Strict float64 equality is used when comparing values, so users // should take caution. If several values are the mode, any of them may be returned. func Mode(x, weights []float64) (val float64, count float64) { if weights != nil && len(x) != len(weights) { panic("stat: slice length mismatch") } if len(x) == 0 { return 0, 0 } m := make(map[float64]float64) if weights == nil { for _, v := range x { m[v]++ } } else { for i, v := range x { m[v] += weights[i] } } var ( maxCount float64 max float64 ) for val, count := range m { if count > maxCount { maxCount = count max = val } } return max, maxCount } // BivariateMoment computes the weighted mixed moment between the samples x and y. // // E[(x - μ_x)^r*(y - μ_y)^s] // // No degrees of freedom correction is done. // The lengths of x and y must be equal. If weights is nil then all of the // weights are 1. If weights is not nil, then len(x) must equal len(weights). func BivariateMoment(r, s float64, x, y, weights []float64) float64 { meanX := Mean(x, weights) meanY := Mean(y, weights) if len(x) != len(y) { panic("stat: slice length mismatch") } if weights == nil { var m float64 for i, vx := range x { vy := y[i] m += math.Pow(vx-meanX, r) * math.Pow(vy-meanY, s) } return m / float64(len(x)) } if len(weights) != len(x) { panic("stat: slice length mismatch") } var ( m float64 sumWeights float64 ) for i, vx := range x { vy := y[i] w := weights[i] m += w * math.Pow(vx-meanX, r) * math.Pow(vy-meanY, s) sumWeights += w } return m / sumWeights } // Moment computes the weighted n^th moment of the samples, // // E[(x - μ)^N] // // No degrees of freedom correction is done. // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func Moment(moment float64, x, weights []float64) float64 { // This also checks that x and weights have the same length. mean := Mean(x, weights) if weights == nil { var m float64 for _, v := range x { m += math.Pow(v-mean, moment) } return m / float64(len(x)) } var ( m float64 sumWeights float64 ) for i, v := range x { w := weights[i] m += w * math.Pow(v-mean, moment) sumWeights += w } return m / sumWeights } // MomentAbout computes the weighted n^th weighted moment of the samples about // the given mean \mu, // // E[(x - μ)^N] // // No degrees of freedom correction is done. // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func MomentAbout(moment float64, x []float64, mean float64, weights []float64) float64 { if weights == nil { var m float64 for _, v := range x { m += math.Pow(v-mean, moment) } m /= float64(len(x)) return m } if len(weights) != len(x) { panic("stat: slice length mismatch") } var ( m float64 sumWeights float64 ) for i, v := range x { m += weights[i] * math.Pow(v-mean, moment) sumWeights += weights[i] } return m / sumWeights } // Quantile returns the sample of x such that x is greater than or // equal to the fraction p of samples. The exact behavior is determined by the // CumulantKind, and p should be a number between 0 and 1. Quantile is theoretically // the inverse of the CDF function, though it may not be the actual inverse // for all values p and CumulantKinds. // // The x data must be sorted in increasing order. If weights is nil then all // of the weights are 1. If weights is not nil, then len(x) must equal len(weights). // Quantile will panic if the length of x is zero. // // CumulantKind behaviors: // - Empirical: Returns the lowest value q for which q is greater than or equal // to the fraction p of samples // - LinInterp: Returns the linearly interpolated value func Quantile(p float64, c CumulantKind, x, weights []float64) float64 { if !(p >= 0 && p <= 1) { panic("stat: percentile out of bounds") } if weights != nil && len(x) != len(weights) { panic("stat: slice length mismatch") } if len(x) == 0 { panic("stat: zero length slice") } if floats.HasNaN(x) { return math.NaN() // This is needed because the algorithm breaks otherwise. } if !sort.Float64sAreSorted(x) { panic("x data are not sorted") } var sumWeights float64 if weights == nil { sumWeights = float64(len(x)) } else { sumWeights = floats.Sum(weights) } switch c { case Empirical: return empiricalQuantile(p, x, weights, sumWeights) case LinInterp: return linInterpQuantile(p, x, weights, sumWeights) default: panic("stat: bad cumulant kind") } } func empiricalQuantile(p float64, x, weights []float64, sumWeights float64) float64 { var cumsum float64 fidx := p * sumWeights for i := range x { if weights == nil { cumsum++ } else { cumsum += weights[i] } if cumsum >= fidx { return x[i] } } panic("impossible") } func linInterpQuantile(p float64, x, weights []float64, sumWeights float64) float64 { var cumsum float64 fidx := p * sumWeights for i := range x { if weights == nil { cumsum++ } else { cumsum += weights[i] } if cumsum >= fidx { if i == 0 { return x[0] } t := cumsum - fidx if weights != nil { t /= weights[i] } return t*x[i-1] + (1-t)*x[i] } } panic("impossible") } // Skew computes the skewness of the sample data. // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). // When weights sum to 1 or less, a biased variance estimator should be used. func Skew(x, weights []float64) float64 { mean, std := MeanStdDev(x, weights) if weights == nil { var s float64 for _, v := range x { z := (v - mean) / std s += z * z * z } return s * skewCorrection(float64(len(x))) } var ( s float64 sumWeights float64 ) for i, v := range x { z := (v - mean) / std s += weights[i] * z * z * z sumWeights += weights[i] } return s * skewCorrection(sumWeights) } // From: http://www.amstat.org/publications/jse/v19n2/doane.pdf page 7 func skewCorrection(n float64) float64 { return (n / (n - 1)) * (1 / (n - 2)) } // SortWeighted rearranges the data in x along with their corresponding // weights so that the x data are sorted. The data is sorted in place. // Weights may be nil, but if weights is non-nil then it must have the same // length as x. func SortWeighted(x, weights []float64) { if weights == nil { sort.Float64s(x) return } if len(x) != len(weights) { panic("stat: slice length mismatch") } sort.Sort(weightSorter{ x: x, w: weights, }) } type weightSorter struct { x []float64 w []float64 } func (w weightSorter) Len() int { return len(w.x) } func (w weightSorter) Less(i, j int) bool { return w.x[i] < w.x[j] } func (w weightSorter) Swap(i, j int) { w.x[i], w.x[j] = w.x[j], w.x[i] w.w[i], w.w[j] = w.w[j], w.w[i] } // SortWeightedLabeled rearranges the data in x along with their // corresponding weights and boolean labels so that the x data are sorted. // The data is sorted in place. Weights and labels may be nil, if either // is non-nil it must have the same length as x. func SortWeightedLabeled(x []float64, labels []bool, weights []float64) { if labels == nil { SortWeighted(x, weights) return } if weights == nil { if len(x) != len(labels) { panic("stat: slice length mismatch") } sort.Sort(labelSorter{ x: x, l: labels, }) return } if len(x) != len(labels) || len(x) != len(weights) { panic("stat: slice length mismatch") } sort.Sort(weightLabelSorter{ x: x, l: labels, w: weights, }) } type labelSorter struct { x []float64 l []bool } func (a labelSorter) Len() int { return len(a.x) } func (a labelSorter) Less(i, j int) bool { return a.x[i] < a.x[j] } func (a labelSorter) Swap(i, j int) { a.x[i], a.x[j] = a.x[j], a.x[i] a.l[i], a.l[j] = a.l[j], a.l[i] } type weightLabelSorter struct { x []float64 l []bool w []float64 } func (a weightLabelSorter) Len() int { return len(a.x) } func (a weightLabelSorter) Less(i, j int) bool { return a.x[i] < a.x[j] } func (a weightLabelSorter) Swap(i, j int) { a.x[i], a.x[j] = a.x[j], a.x[i] a.l[i], a.l[j] = a.l[j], a.l[i] a.w[i], a.w[j] = a.w[j], a.w[i] } // StdDev returns the sample standard deviation. func StdDev(x, weights []float64) float64 { _, std := MeanStdDev(x, weights) return std } // MeanStdDev returns the sample mean and unbiased standard deviation // When weights sum to 1 or less, a biased variance estimator should be used. func MeanStdDev(x, weights []float64) (mean, std float64) { mean, variance := MeanVariance(x, weights) return mean, math.Sqrt(variance) } // StdErr returns the standard error in the mean with the given values. func StdErr(std, sampleSize float64) float64 { return std / math.Sqrt(sampleSize) } // StdScore returns the standard score (a.k.a. z-score, z-value) for the value x // with the given mean and standard deviation, i.e. // // (x - mean) / std func StdScore(x, mean, std float64) float64 { return (x - mean) / std } // Variance computes the unbiased weighted sample variance: // // \sum_i w_i (x_i - mean)^2 / (sum_i w_i - 1) // // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). // When weights sum to 1 or less, a biased variance estimator should be used. func Variance(x, weights []float64) float64 { _, variance := MeanVariance(x, weights) return variance } // MeanVariance computes the sample mean and unbiased variance, where the mean and variance are // // \sum_i w_i * x_i / (sum_i w_i) // \sum_i w_i (x_i - mean)^2 / (sum_i w_i - 1) // // respectively. // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). // When weights sum to 1 or less, a biased variance estimator should be used. func MeanVariance(x, weights []float64) (mean, variance float64) { var ( unnormalisedVariance float64 sumWeights float64 ) mean, unnormalisedVariance, sumWeights = meanUnnormalisedVarianceSumWeights(x, weights) return mean, unnormalisedVariance / (sumWeights - 1) } // PopMeanVariance computes the sample mean and biased variance (also known as // "population variance"), where the mean and variance are // // \sum_i w_i * x_i / (sum_i w_i) // \sum_i w_i (x_i - mean)^2 / (sum_i w_i) // // respectively. // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func PopMeanVariance(x, weights []float64) (mean, variance float64) { var ( unnormalisedVariance float64 sumWeights float64 ) mean, unnormalisedVariance, sumWeights = meanUnnormalisedVarianceSumWeights(x, weights) return mean, unnormalisedVariance / sumWeights } // PopMeanStdDev returns the sample mean and biased standard deviation // (also known as "population standard deviation"). func PopMeanStdDev(x, weights []float64) (mean, std float64) { mean, variance := PopMeanVariance(x, weights) return mean, math.Sqrt(variance) } // PopStdDev returns the population standard deviation, i.e., a square root // of the biased variance estimate. func PopStdDev(x, weights []float64) float64 { _, stDev := PopMeanStdDev(x, weights) return stDev } // PopVariance computes the unbiased weighted sample variance: // // \sum_i w_i (x_i - mean)^2 / (sum_i w_i) // // If weights is nil then all of the weights are 1. If weights is not nil, then // len(x) must equal len(weights). func PopVariance(x, weights []float64) float64 { _, variance := PopMeanVariance(x, weights) return variance } func meanUnnormalisedVarianceSumWeights(x, weights []float64) (mean, unnormalisedVariance, sumWeights float64) { // This uses the corrected two-pass algorithm (1.7), from "Algorithms for computing // the sample variance: Analysis and recommendations" by Chan, Tony F., Gene H. Golub, // and Randall J. LeVeque. // Note that this will panic if the slice lengths do not match. mean = Mean(x, weights) var ( ss float64 compensation float64 ) if weights == nil { for _, v := range x { d := v - mean ss += d * d compensation += d } unnormalisedVariance = (ss - compensation*compensation/float64(len(x))) return mean, unnormalisedVariance, float64(len(x)) } for i, v := range x { w := weights[i] d := v - mean wd := w * d ss += wd * d compensation += wd sumWeights += w } unnormalisedVariance = (ss - compensation*compensation/sumWeights) return mean, unnormalisedVariance, sumWeights } golang-gonum-v1-gonum-0.14.0/stat/stat_example_test.go000066400000000000000000000017051450372207100226700ustar00rootroot00000000000000// 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 stat_test import ( "fmt" "golang.org/x/exp/rand" "gonum.org/v1/gonum/stat" ) func ExampleLinearRegression() { var ( xs = make([]float64, 100) ys = make([]float64, 100) weights []float64 ) line := func(x float64) float64 { return 1 + 3*x } for i := range xs { xs[i] = float64(i) ys[i] = line(xs[i]) + 0.1*rand.NormFloat64() } // Do not force the regression line to pass through the origin. origin := false alpha, beta := stat.LinearRegression(xs, ys, weights, origin) r2 := stat.RSquared(xs, ys, weights, alpha, beta) fmt.Printf("Estimated offset is: %.6f\n", alpha) fmt.Printf("Estimated slope is: %.6f\n", beta) fmt.Printf("R^2: %.6f\n", r2) // Output: // Estimated offset is: 0.988572 // Estimated slope is: 3.000154 // R^2: 0.999999 } golang-gonum-v1-gonum-0.14.0/stat/stat_test.go000066400000000000000000001376421450372207100211670ustar00rootroot00000000000000// 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 stat import ( "fmt" "math" "reflect" "strconv" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/floats/scalar" ) func ExampleCircularMean() { x := []float64{0, 0.25 * math.Pi, 0.75 * math.Pi} weights := []float64{1, 2, 2.5} cmean := CircularMean(x, weights) fmt.Printf("The circular mean is %.5f.\n", cmean) // Output: // The circular mean is 1.37037. } func TestCircularMean(t *testing.T) { for i, test := range []struct { x []float64 wts []float64 ans float64 }{ // Values compared against scipy. { x: []float64{0, 2 * math.Pi}, ans: 0, }, { x: []float64{0, 0.5 * math.Pi}, ans: 0.78539816339744, }, { x: []float64{-1.5 * math.Pi, 0.5 * math.Pi, 2.5 * math.Pi}, wts: []float64{1, 2, 3}, ans: 0.5 * math.Pi, }, { x: []float64{0, 0.5 * math.Pi}, wts: []float64{1, 2}, ans: 1.10714871779409, }, } { c := CircularMean(test.x, test.wts) if math.Abs(c-test.ans) > 1e-14 { t.Errorf("Circular mean mismatch case %d: Expected %v, Found %v", i, test.ans, c) } } if !panics(func() { CircularMean(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("CircularMean did not panic with x, wts length mismatch") } } func ExampleCorrelation() { x := []float64{8, -3, 7, 8, -4} y := []float64{10, 5, 6, 3, -1} w := []float64{2, 1.5, 3, 3, 2} fmt.Println("Correlation computes the degree to which two datasets move together") fmt.Println("about their mean. For example, x and y above move similarly.") c := Correlation(x, y, w) fmt.Printf("Correlation is %.5f\n", c) // Output: // Correlation computes the degree to which two datasets move together // about their mean. For example, x and y above move similarly. // Correlation is 0.59915 } func TestCorrelation(t *testing.T) { for i, test := range []struct { x []float64 y []float64 w []float64 ans float64 }{ { x: []float64{8, -3, 7, 8, -4}, y: []float64{8, -3, 7, 8, -4}, w: nil, ans: 1, }, { x: []float64{8, -3, 7, 8, -4}, y: []float64{8, -3, 7, 8, -4}, w: []float64{1, 1, 1, 1, 1}, ans: 1, }, { x: []float64{8, -3, 7, 8, -4}, y: []float64{8, -3, 7, 8, -4}, w: []float64{1, 6, 7, 0.8, 2.1}, ans: 1, }, { x: []float64{8, -3, 7, 8, -4}, y: []float64{10, 15, 4, 5, -1}, w: nil, ans: 0.0093334660769059, }, { x: []float64{8, -3, 7, 8, -4}, y: []float64{10, 15, 4, 5, -1}, w: nil, ans: 0.0093334660769059, }, { x: []float64{8, -3, 7, 8, -4}, y: []float64{10, 15, 4, 5, -1}, w: []float64{1, 3, 1, 2, 2}, ans: -0.13966633352689, }, } { c := Correlation(test.x, test.y, test.w) if math.Abs(test.ans-c) > 1e-14 { t.Errorf("Correlation mismatch case %d. Expected %v, Found %v", i, test.ans, c) } } if !panics(func() { Correlation(make([]float64, 2), make([]float64, 3), make([]float64, 3)) }) { t.Errorf("Correlation did not panic with length mismatch") } if !panics(func() { Correlation(make([]float64, 2), make([]float64, 3), nil) }) { t.Errorf("Correlation did not panic with length mismatch") } if !panics(func() { Correlation(make([]float64, 3), make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Correlation did not panic with weights length mismatch") } } func ExampleKendall() { x := []float64{8, -3, 7, 8, -4} y := []float64{10, 5, 6, 3, -1} w := []float64{2, 1.5, 3, 3, 2} fmt.Println("Kendall correlation computes the number of ordered pairs") fmt.Println("between two datasets.") c := Kendall(x, y, w) fmt.Printf("Kendall correlation is %.5f\n", c) // Output: // Kendall correlation computes the number of ordered pairs // between two datasets. // Kendall correlation is 0.25000 } func TestKendall(t *testing.T) { for i, test := range []struct { x []float64 y []float64 weights []float64 ans float64 }{ { x: []float64{0, 1, 2, 3}, y: []float64{0, 1, 2, 3}, weights: nil, ans: 1, }, { x: []float64{0, 1}, y: []float64{1, 0}, weights: nil, ans: -1, }, { x: []float64{8, -3, 7, 8, -4}, y: []float64{10, 15, 4, 5, -1}, weights: nil, ans: 0.2, }, { x: []float64{8, -3, 7, 8, -4}, y: []float64{10, 5, 6, 3, -1}, weights: nil, ans: 0.4, }, { x: []float64{1, 2, 3, 4, 5}, y: []float64{2, 3, 4, 5, 6}, weights: []float64{1, 1, 1, 1, 1}, ans: 1, }, { x: []float64{1, 2, 3, 2, 1}, y: []float64{2, 3, 2, 1, 0}, weights: []float64{1, 1, 0, 0, 0}, ans: 1, }, } { c := Kendall(test.x, test.y, test.weights) if math.Abs(test.ans-c) > 1e-14 { t.Errorf("Correlation mismatch case %d. Expected %v, Found %v", i, test.ans, c) } } if !panics(func() { Kendall(make([]float64, 2), make([]float64, 3), make([]float64, 3)) }) { t.Errorf("Kendall did not panic with length mismatch") } if !panics(func() { Kendall(make([]float64, 2), make([]float64, 3), nil) }) { t.Errorf("Kendall did not panic with length mismatch") } if !panics(func() { Kendall(make([]float64, 3), make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Kendall did not panic with weights length mismatch") } } func ExampleCovariance() { fmt.Println("Covariance computes the degree to which datasets move together") fmt.Println("about their mean.") x := []float64{8, -3, 7, 8, -4} y := []float64{10, 2, 2, 4, 1} cov := Covariance(x, y, nil) fmt.Printf("Cov = %.4f\n", cov) fmt.Println("If datasets move perfectly together, the variance equals the covariance") y2 := []float64{12, 1, 11, 12, 0} cov2 := Covariance(x, y2, nil) varX := Variance(x, nil) fmt.Printf("Cov2 is %.4f, VarX is %.4f", cov2, varX) // Output: // Covariance computes the degree to which datasets move together // about their mean. // Cov = 13.8000 // If datasets move perfectly together, the variance equals the covariance // Cov2 is 37.7000, VarX is 37.7000 } func TestCovariance(t *testing.T) { for i, test := range []struct { p []float64 q []float64 weights []float64 ans float64 }{ { p: []float64{0.75, 0.1, 0.05}, q: []float64{0.5, 0.25, 0.25}, ans: 0.05625, }, { p: []float64{1, 2, 3}, q: []float64{2, 4, 6}, ans: 2, }, { p: []float64{1, 2, 3}, q: []float64{1, 4, 9}, ans: 4, }, { p: []float64{1, 2, 3}, q: []float64{1, 4, 9}, weights: []float64{1, 1.5, 1}, ans: 3.2, }, { p: []float64{1, 4, 9}, q: []float64{1, 4, 9}, weights: []float64{1, 1.5, 1}, ans: 13.142857142857146, }, } { c := Covariance(test.p, test.q, test.weights) if math.Abs(c-test.ans) > 1e-14 { t.Errorf("Covariance mismatch case %d: Expected %v, Found %v", i, test.ans, c) } } // test the panic states if !panics(func() { Covariance(make([]float64, 2), make([]float64, 3), nil) }) { t.Errorf("Covariance did not panic with x, y length mismatch") } if !panics(func() { Covariance(make([]float64, 3), make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Covariance did not panic with x, weights length mismatch") } } func TestCrossEntropy(t *testing.T) { for i, test := range []struct { p []float64 q []float64 ans float64 }{ { p: []float64{0.75, 0.1, 0.05}, q: []float64{0.5, 0.25, 0.25}, ans: 0.7278045395879426, }, { p: []float64{0.75, 0.1, 0.05, 0, 0, 0}, q: []float64{0.5, 0.25, 0.25, 0, 0, 0}, ans: 0.7278045395879426, }, { p: []float64{0.75, 0.1, 0.05, 0, 0, 0.1}, q: []float64{0.5, 0.25, 0.25, 0, 0, 0}, ans: math.Inf(1), }, { p: nil, q: nil, ans: 0, }, } { c := CrossEntropy(test.p, test.q) if math.Abs(c-test.ans) > 1e-14 { t.Errorf("Cross entropy mismatch case %d: Expected %v, Found %v", i, test.ans, c) } } if !panics(func() { CrossEntropy(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("CrossEntropy did not panic with p, q length mismatch") } } func ExampleEntropy() { p := []float64{0.05, 0.1, 0.9, 0.05} entP := Entropy(p) q := []float64{0.2, 0.4, 0.25, 0.15} entQ := Entropy(q) r := []float64{0.2, 0, 0, 0.5, 0, 0.2, 0.1, 0, 0, 0} entR := Entropy(r) s := []float64{0, 0, 1, 0} entS := Entropy(s) fmt.Println("Entropy is a measure of the amount of uncertainty in a distribution") fmt.Printf("The second bin of p is very likely to occur. It's entropy is %.4f\n", entP) fmt.Printf("The distribution of q is more spread out. It's entropy is %.4f\n", entQ) fmt.Println("Adding buckets with zero probability does not change the entropy.") fmt.Printf("The entropy of r is: %.4f\n", entR) fmt.Printf("A distribution with no uncertainty has entropy %.4f\n", entS) // Output: // Entropy is a measure of the amount of uncertainty in a distribution // The second bin of p is very likely to occur. It's entropy is 0.6247 // The distribution of q is more spread out. It's entropy is 1.3195 // Adding buckets with zero probability does not change the entropy. // The entropy of r is: 1.2206 // A distribution with no uncertainty has entropy 0.0000 } func ExampleExKurtosis() { fmt.Println(`Kurtosis is a measure of the 'peakedness' of a distribution, and the excess kurtosis is the kurtosis above or below that of the standard normal distribution`) x := []float64{5, 4, -3, -2} kurt := ExKurtosis(x, nil) fmt.Printf("ExKurtosis = %.5f\n", kurt) weights := []float64{1, 2, 3, 5} wKurt := ExKurtosis(x, weights) fmt.Printf("Weighted ExKurtosis is %.4f", wKurt) // Output: // Kurtosis is a measure of the 'peakedness' of a distribution, and the // excess kurtosis is the kurtosis above or below that of the standard normal // distribution // ExKurtosis = -5.41200 // Weighted ExKurtosis is -0.6779 } func TestExKurtosis(t *testing.T) { // the example does a good job, this just has to cover the panic if !panics(func() { ExKurtosis(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("ExKurtosis did not panic with x, weights length mismatch") } } func ExampleGeometricMean() { x := []float64{8, 2, 9, 15, 4} weights := []float64{2, 2, 6, 7, 1} mean := Mean(x, weights) gmean := GeometricMean(x, weights) logx := make([]float64, len(x)) for i, v := range x { logx[i] = math.Log(v) } expMeanLog := math.Exp(Mean(logx, weights)) fmt.Printf("The arithmetic mean is %.4f, but the geometric mean is %.4f.\n", mean, gmean) fmt.Printf("The exponential of the mean of the logs is %.4f\n", expMeanLog) // Output: // The arithmetic mean is 10.1667, but the geometric mean is 8.7637. // The exponential of the mean of the logs is 8.7637 } func TestGeometricMean(t *testing.T) { for i, test := range []struct { x []float64 wts []float64 ans float64 }{ { x: []float64{2, 8}, ans: 4, }, { x: []float64{3, 81}, wts: []float64{2, 1}, ans: 9, }, } { c := GeometricMean(test.x, test.wts) if math.Abs(c-test.ans) > 1e-14 { t.Errorf("Geometric mean mismatch case %d: Expected %v, Found %v", i, test.ans, c) } } if !panics(func() { GeometricMean(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("GeometricMean did not panic with x, wts length mismatch") } } func ExampleHarmonicMean() { x := []float64{8, 2, 9, 15, 4} weights := []float64{2, 2, 6, 7, 1} mean := Mean(x, weights) hmean := HarmonicMean(x, weights) fmt.Printf("The arithmetic mean is %.5f, but the harmonic mean is %.4f.\n", mean, hmean) // Output: // The arithmetic mean is 10.16667, but the harmonic mean is 6.8354. } func TestHarmonicMean(t *testing.T) { for i, test := range []struct { x []float64 wts []float64 ans float64 }{ { x: []float64{.5, .125}, ans: .2, }, { x: []float64{.5, .125}, wts: []float64{2, 1}, ans: .25, }, } { c := HarmonicMean(test.x, test.wts) if math.Abs(c-test.ans) > 1e-14 { t.Errorf("Harmonic mean mismatch case %d: Expected %v, Found %v", i, test.ans, c) } } if !panics(func() { HarmonicMean(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("HarmonicMean did not panic with x, wts length mismatch") } } func TestHistogram(t *testing.T) { for i, test := range []struct { x []float64 weights []float64 dividers []float64 ans []float64 }{ { x: []float64{1, 3, 5, 6, 7, 8}, dividers: []float64{0, 2, 4, 6, 7, 9}, ans: []float64{1, 1, 1, 1, 2}, }, { x: []float64{1, 3, 5, 6, 7, 8}, dividers: []float64{1, 2, 4, 6, 7, 9}, weights: []float64{1, 2, 1, 1, 1, 2}, ans: []float64{1, 2, 1, 1, 3}, }, { x: []float64{1, 8}, dividers: []float64{0, 2, 4, 6, 7, 9}, weights: []float64{1, 2}, ans: []float64{1, 0, 0, 0, 2}, }, { x: []float64{1, 8}, dividers: []float64{0, 2, 4, 6, 7, 9}, ans: []float64{1, 0, 0, 0, 1}, }, { x: []float64{}, dividers: []float64{1, 3}, ans: []float64{0}, }, } { hist := Histogram(nil, test.dividers, test.x, test.weights) if !floats.Equal(hist, test.ans) { t.Errorf("Hist mismatch case %d. Expected %v, Found %v", i, test.ans, hist) } // Test with non-zero values Histogram(hist, test.dividers, test.x, test.weights) if !floats.Equal(hist, test.ans) { t.Errorf("Hist mismatch case %d. Expected %v, Found %v", i, test.ans, hist) } } // panic cases for _, test := range []struct { name string x []float64 weights []float64 dividers []float64 count []float64 }{ { name: "len(x) != len(weights)", x: []float64{1, 3, 5, 6, 7, 8}, weights: []float64{1, 1, 1, 1}, }, { name: "len(count) != len(dividers) - 1", x: []float64{1, 3, 5, 6, 7, 8}, dividers: []float64{1, 4, 9}, count: make([]float64, 6), }, { name: "dividers not sorted", x: []float64{1, 3, 5, 6, 7, 8}, dividers: []float64{0, -1, 0}, }, { name: "x not sorted", x: []float64{1, 5, 2, 9, 7, 8}, dividers: []float64{1, 4, 9}, }, { name: "fewer than 2 dividers", x: []float64{1, 2, 3}, dividers: []float64{5}, }, { name: "x too large", x: []float64{1, 2, 3}, dividers: []float64{1, 3}, }, { name: "x too small", x: []float64{1, 2, 3}, dividers: []float64{2, 3}, }, } { if !panics(func() { Histogram(test.count, test.dividers, test.x, test.weights) }) { t.Errorf("Histogram did not panic when %s", test.name) } } } func ExampleHistogram() { x := make([]float64, 101) for i := range x { x[i] = 1.1 * float64(i) // x data ranges from 0 to 110 } dividers := []float64{0, 7, 20, 100, 1000} fmt.Println(`Histogram counts the amount of data in the bins specified by the dividers. In this data set, there are 7 data points less than 7 (between dividers[0] and dividers[1]), 12 data points between 7 and 20 (dividers[1] and dividers[2]), and 0 data points above 1000. Since dividers has length 5, there will be 4 bins.`) hist := Histogram(nil, dividers, x, nil) fmt.Printf("Hist = %v\n", hist) fmt.Println() fmt.Println("For ease, the floats Span function can be used to set the dividers") nBins := 10 dividers = make([]float64, nBins+1) min := floats.Min(x) max := floats.Max(x) // Increase the maximum divider so that the maximum value of x is contained // within the last bucket. max++ floats.Span(dividers, min, max) // Span includes the min and the max. Trim the dividers to create 10 buckets hist = Histogram(nil, dividers, x, nil) fmt.Printf("Hist = %v\n", hist) fmt.Println() fmt.Println(`Histogram also works with weighted data, and allows reusing of the count field in order to avoid extra garbage`) weights := make([]float64, len(x)) for i := range weights { weights[i] = float64(i + 1) } Histogram(hist, dividers, x, weights) fmt.Printf("Weighted Hist = %v\n", hist) // Output: // Histogram counts the amount of data in the bins specified by // the dividers. In this data set, there are 7 data points less than 7 (between dividers[0] // and dividers[1]), 12 data points between 7 and 20 (dividers[1] and dividers[2]), // and 0 data points above 1000. Since dividers has length 5, there will be 4 bins. // Hist = [7 12 72 10] // // For ease, the floats Span function can be used to set the dividers // Hist = [11 10 10 10 10 10 10 10 10 10] // // Histogram also works with weighted data, and allows reusing of // the count field in order to avoid extra garbage // Weighted Hist = [66 165 265 365 465 565 665 765 865 965] } func TestJensenShannon(t *testing.T) { for i, test := range []struct { p []float64 q []float64 }{ { p: []float64{0.5, 0.1, 0.3, 0.1}, q: []float64{0.1, 0.4, 0.25, 0.25}, }, { p: []float64{0.4, 0.6, 0.0}, q: []float64{0.2, 0.2, 0.6}, }, { p: []float64{0.1, 0.1, 0.0, 0.8}, q: []float64{0.6, 0.3, 0.0, 0.1}, }, { p: []float64{0.5, 0.1, 0.3, 0.1}, q: []float64{0.5, 0, 0.25, 0.25}, }, { p: []float64{0.5, 0.1, 0, 0.4}, q: []float64{0.1, 0.4, 0.25, 0.25}, }, } { m := make([]float64, len(test.p)) p := test.p q := test.q floats.Add(m, p) floats.Add(m, q) floats.Scale(0.5, m) js1 := 0.5*KullbackLeibler(p, m) + 0.5*KullbackLeibler(q, m) js2 := JensenShannon(p, q) if math.IsNaN(js2) { t.Errorf("In case %v, JS distance is NaN", i) } if math.Abs(js1-js2) > 1e-14 { t.Errorf("JS mismatch case %v. Expected %v, found %v.", i, js1, js2) } } if !panics(func() { JensenShannon(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("JensenShannon did not panic with p, q length mismatch") } } func TestKolmogorovSmirnov(t *testing.T) { for i, test := range []struct { x []float64 xWeights []float64 y []float64 yWeights []float64 dist float64 }{ { dist: 0, }, { x: []float64{1}, dist: 1, }, { y: []float64{1}, dist: 1, }, { x: []float64{1}, xWeights: []float64{8}, dist: 1, }, { y: []float64{1}, yWeights: []float64{8}, dist: 1, }, { x: []float64{1}, xWeights: []float64{8}, y: []float64{1}, yWeights: []float64{8}, dist: 0, }, { x: []float64{1, 1, 1}, xWeights: []float64{2, 3, 7}, y: []float64{1}, yWeights: []float64{8}, dist: 0, }, { x: []float64{1, 1, 1, 1, 1}, y: []float64{1, 1, 1}, yWeights: []float64{2, 5, 2}, dist: 0, }, { x: []float64{1, 2, 3}, y: []float64{1, 2, 3}, dist: 0, }, { x: []float64{1, 2, 3}, y: []float64{1, 2, 3}, yWeights: []float64{1, 1, 1}, dist: 0, }, { x: []float64{1, 2, 3}, xWeights: []float64{1, 1, 1}, y: []float64{1, 2, 3}, yWeights: []float64{1, 1, 1}, dist: 0, }, { x: []float64{1, 2}, xWeights: []float64{2, 5}, y: []float64{1, 1, 2, 2, 2, 2, 2}, dist: 0, }, { x: []float64{1, 1, 2, 2, 2, 2, 2}, y: []float64{1, 2}, yWeights: []float64{2, 5}, dist: 0, }, { x: []float64{1, 1, 2, 2, 2}, xWeights: []float64{0.5, 1.5, 1, 2, 2}, y: []float64{1, 2}, yWeights: []float64{2, 5}, dist: 0, }, { x: []float64{1, 2, 3, 4}, y: []float64{5, 6}, dist: 1, }, { x: []float64{5, 6}, y: []float64{1, 2, 3, 4}, dist: 1, }, { x: []float64{5, 6}, xWeights: []float64{8, 7}, y: []float64{1, 2, 3, 4}, dist: 1, }, { x: []float64{5, 6}, xWeights: []float64{8, 7}, y: []float64{1, 2, 3, 4}, yWeights: []float64{9, 2, 1, 6}, dist: 1, }, { x: []float64{-4, 5, 6}, xWeights: []float64{0, 8, 7}, y: []float64{1, 2, 3, 4}, yWeights: []float64{9, 2, 1, 6}, dist: 1, }, { x: []float64{-4, -2, -2, 5, 6}, xWeights: []float64{0, 0, 0, 8, 7}, y: []float64{1, 2, 3, 4}, yWeights: []float64{9, 2, 1, 6}, dist: 1, }, { x: []float64{1, 2, 3}, y: []float64{1, 1, 3}, dist: 1.0 / 3.0, }, { x: []float64{1, 2, 3}, y: []float64{1, 3}, yWeights: []float64{2, 1}, dist: 1.0 / 3.0, }, { x: []float64{1, 2, 3}, xWeights: []float64{2, 2, 2}, y: []float64{1, 3}, yWeights: []float64{2, 1}, dist: 1.0 / 3.0, }, { x: []float64{2, 3, 4}, y: []float64{1, 5}, dist: 1.0 / 2.0, }, { x: []float64{1, 2, math.NaN()}, y: []float64{1, 1, 3}, dist: math.NaN(), }, { x: []float64{1, 2, 3}, y: []float64{1, 1, math.NaN()}, dist: math.NaN(), }, } { dist := KolmogorovSmirnov(test.x, test.xWeights, test.y, test.yWeights) if math.Abs(dist-test.dist) > 1e-14 && !(math.IsNaN(test.dist) && math.IsNaN(dist)) { t.Errorf("Distance mismatch case %v: Expected: %v, Found: %v", i, test.dist, dist) } } // panic cases for _, test := range []struct { name string x []float64 xWeights []float64 y []float64 yWeights []float64 }{ { name: "len(x) != len(xWeights)", x: []float64{1, 3, 5, 6, 7, 8}, xWeights: []float64{1, 1, 1, 1}, }, { name: "len(y) != len(yWeights)", x: []float64{1, 3, 5, 6, 7, 8}, y: []float64{1, 3, 5, 6, 7, 8}, yWeights: []float64{1, 1, 1, 1}, }, { name: "x not sorted", x: []float64{10, 3, 5, 6, 7, 8}, y: []float64{1, 3, 5, 6, 7, 8}, }, { name: "y not sorted", x: []float64{1, 3, 5, 6, 7, 8}, y: []float64{10, 3, 5, 6, 7, 8}, }, } { if !panics(func() { KolmogorovSmirnov(test.x, test.xWeights, test.y, test.yWeights) }) { t.Errorf("KolmogorovSmirnov did not panic when %s", test.name) } } } func ExampleKullbackLeibler() { p := []float64{0.05, 0.1, 0.9, 0.05} q := []float64{0.2, 0.4, 0.25, 0.15} s := []float64{0, 0, 1, 0} klPQ := KullbackLeibler(p, q) klPS := KullbackLeibler(p, s) klPP := KullbackLeibler(p, p) fmt.Println("Kullback-Leibler is one measure of the difference between two distributions") fmt.Printf("The K-L distance between p and q is %.4f\n", klPQ) fmt.Println("It is impossible for s and p to be the same distribution, because") fmt.Println("the first bucket has zero probability in s and non-zero in p. Thus,") fmt.Printf("the K-L distance between them is %.4f\n", klPS) fmt.Printf("The K-L distance between identical distributions is %.4f\n", klPP) // Kullback-Leibler is one measure of the difference between two distributions // The K-L distance between p and q is 0.8900 // It is impossible for s and p to be the same distribution, because // the first bucket has zero probability in s and non-zero in p. Thus, // the K-L distance between them is +Inf // The K-L distance between identical distributions is 0.0000 } func TestKullbackLeibler(t *testing.T) { if !panics(func() { KullbackLeibler(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("KullbackLeibler did not panic with p, q length mismatch") } } var linearRegressionTests = []struct { name string x, y []float64 weights []float64 origin bool alpha float64 beta float64 r float64 tol float64 }{ { name: "faithful", x: faithful.waiting, y: faithful.eruptions, // Values calculated by R using lm(eruptions ~ waiting, data=faithful). alpha: -1.87402, beta: 0.07563, r: 0.8114608, tol: 1e-5, }, { name: "faithful through origin", x: faithful.waiting, y: faithful.eruptions, origin: true, // Values calculated by R using lm(eruptions ~ waiting - 1, data=faithful). alpha: 0, beta: 0.05013, r: 0.9726036, tol: 1e-5, }, { name: "faithful explicit weights", x: faithful.waiting, y: faithful.eruptions, weights: func() []float64 { w := make([]float64, len(faithful.eruptions)) for i := range w { w[i] = 1 } return w }(), // Values calculated by R using lm(eruptions ~ waiting, data=faithful). alpha: -1.87402, beta: 0.07563, r: 0.8114608, tol: 1e-5, }, { name: "faithful non-uniform weights", x: faithful.waiting, y: faithful.eruptions, weights: faithful.waiting, // Just an arbitrary set of non-uniform weights. // Values calculated by R using lm(eruptions ~ waiting, data=faithful, weights=faithful$waiting). alpha: -1.79268, beta: 0.07452, r: 0.7840372, tol: 1e-5, }, } func TestLinearRegression(t *testing.T) { for _, test := range linearRegressionTests { alpha, beta := LinearRegression(test.x, test.y, test.weights, test.origin) var r float64 if test.origin { r = RNoughtSquared(test.x, test.y, test.weights, beta) } else { r = RSquared(test.x, test.y, test.weights, alpha, beta) ests := make([]float64, len(test.y)) for i, x := range test.x { ests[i] = alpha + beta*x } rvals := RSquaredFrom(ests, test.y, test.weights) if r != rvals { t.Errorf("%s: RSquared and RSquaredFrom mismatch: %v != %v", test.name, r, rvals) } } if !scalar.EqualWithinAbsOrRel(alpha, test.alpha, test.tol, test.tol) { t.Errorf("%s: unexpected alpha estimate: want:%v got:%v", test.name, test.alpha, alpha) } if !scalar.EqualWithinAbsOrRel(beta, test.beta, test.tol, test.tol) { t.Errorf("%s: unexpected beta estimate: want:%v got:%v", test.name, test.beta, beta) } if !scalar.EqualWithinAbsOrRel(r, test.r, test.tol, test.tol) { t.Errorf("%s: unexpected r estimate: want:%v got:%v", test.name, test.r, r) } } } func BenchmarkLinearRegression(b *testing.B) { rnd := rand.New(rand.NewSource(1)) slope, offset := 2.0, 3.0 maxn := 10000 xs := make([]float64, maxn) ys := make([]float64, maxn) weights := make([]float64, maxn) for i := range xs { x := rnd.Float64() xs[i] = x ys[i] = slope*x + offset weights[i] = rnd.Float64() } for _, n := range []int{10, 100, 1000, maxn} { for _, weighted := range []bool{true, false} { for _, origin := range []bool{true, false} { name := "n" + strconv.Itoa(n) if weighted { name += "wt" } else { name += "wf" } if origin { name += "ot" } else { name += "of" } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { var ws []float64 if weighted { ws = weights[:n] } LinearRegression(xs[:n], ys[:n], ws, origin) } }) } } } } func TestChiSquare(t *testing.T) { for i, test := range []struct { p []float64 q []float64 res float64 }{ { p: []float64{16, 18, 16, 14, 12, 12}, q: []float64{16, 16, 16, 16, 16, 8}, res: 3.5, }, { p: []float64{16, 18, 16, 14, 12, 12}, q: []float64{8, 20, 20, 16, 12, 12}, res: 9.25, }, { p: []float64{40, 60, 30, 45}, q: []float64{50, 50, 50, 50}, res: 12.5, }, { p: []float64{40, 60, 30, 45, 0, 0}, q: []float64{50, 50, 50, 50, 0, 0}, res: 12.5, }, } { resultpq := ChiSquare(test.p, test.q) if math.Abs(resultpq-test.res) > 1e-10 { t.Errorf("ChiSquare distance mismatch in case %d. Expected %v, Found %v", i, test.res, resultpq) } } if !panics(func() { ChiSquare(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("ChiSquare did not panic with length mismatch") } } // panics returns true if the called function panics during evaluation. func panics(fun func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() fun() return } func TestBhattacharyya(t *testing.T) { for i, test := range []struct { p []float64 q []float64 res float64 }{ { p: []float64{0.5, 0.1, 0.3, 0.1}, q: []float64{0.1, 0.4, 0.25, 0.25}, res: 0.15597338718671386, }, { p: []float64{0.4, 0.6, 0.0}, q: []float64{0.2, 0.2, 0.6}, res: 0.46322207765351153, }, { p: []float64{0.1, 0.1, 0.0, 0.8}, q: []float64{0.6, 0.3, 0.0, 0.1}, res: 0.3552520032137785, }, } { resultpq := Bhattacharyya(test.p, test.q) resultqp := Bhattacharyya(test.q, test.p) if math.Abs(resultpq-test.res) > 1e-10 { t.Errorf("Bhattacharyya distance mismatch in case %d. Expected %v, Found %v", i, test.res, resultpq) } if math.Abs(resultpq-resultqp) > 1e-10 { t.Errorf("Bhattacharyya distance is asymmetric in case %d.", i) } } // Bhattacharyya should panic if the inputs have different length if !panics(func() { Bhattacharyya(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Bhattacharyya did not panic with length mismatch") } } func TestHellinger(t *testing.T) { for i, test := range []struct { p []float64 q []float64 res float64 }{ { p: []float64{0.5, 0.1, 0.3, 0.1}, q: []float64{0.1, 0.4, 0.25, 0.25}, res: 0.3800237367441919, }, { p: []float64{0.4, 0.6, 0.0}, q: []float64{0.2, 0.2, 0.6}, res: 0.6088900771170487, }, { p: []float64{0.1, 0.1, 0.0, 0.8}, q: []float64{0.6, 0.3, 0.0, 0.1}, res: 0.5468118803484205, }, } { resultpq := Hellinger(test.p, test.q) resultqp := Hellinger(test.q, test.p) if math.Abs(resultpq-test.res) > 1e-10 { t.Errorf("Hellinger distance mismatch in case %d. Expected %v, Found %v", i, test.res, resultpq) } if math.Abs(resultpq-resultqp) > 1e-10 { t.Errorf("Hellinger distance is asymmetric in case %d.", i) } } if !panics(func() { Hellinger(make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Hellinger did not panic with length mismatch") } } func ExampleMean() { x := []float64{8.2, -6, 5, 7} mean := Mean(x, nil) fmt.Printf("The mean of the samples is %.4f\n", mean) w := []float64{2, 6, 3, 5} weightedMean := Mean(x, w) fmt.Printf("The weighted mean of the samples is %.4f\n", weightedMean) x2 := []float64{8.2, 8.2, -6, -6, -6, -6, -6, -6, 5, 5, 5, 7, 7, 7, 7, 7} mean2 := Mean(x2, nil) fmt.Printf("The mean of x2 is %.4f\n", mean2) fmt.Println("The weights act as if there were more samples of that number") // Output: // The mean of the samples is 3.5500 // The weighted mean of the samples is 1.9000 // The mean of x2 is 1.9000 // The weights act as if there were more samples of that number } func TestMean(t *testing.T) { if !panics(func() { Mean(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Mean did not panic with x, weights length mismatch") } } func TestMode(t *testing.T) { for i, test := range []struct { x []float64 weights []float64 ans float64 count float64 }{ {}, { x: []float64{1, 6, 1, 9, -2}, ans: 1, count: 2, }, { x: []float64{1, 6, 1, 9, -2}, weights: []float64{1, 7, 3, 5, 0}, ans: 6, count: 7, }, } { m, count := Mode(test.x, test.weights) if test.ans != m { t.Errorf("Mode mismatch case %d. Expected %v, found %v", i, test.ans, m) } if test.count != count { t.Errorf("Mode count mismatch case %d. Expected %v, found %v", i, test.count, count) } } if !panics(func() { Mode(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Mode did not panic with x, weights length mismatch") } } func TestMixedMoment(t *testing.T) { for i, test := range []struct { x, y, weights []float64 r, s float64 ans float64 }{ { x: []float64{10, 2, 1, 8, 5}, y: []float64{8, 15, 1, 6, 3}, r: 1, s: 1, ans: 0.48, }, { x: []float64{10, 2, 1, 8, 5}, y: []float64{8, 15, 1, 6, 3}, weights: []float64{1, 1, 1, 1, 1}, r: 1, s: 1, ans: 0.48, }, { x: []float64{10, 2, 1, 8, 5}, y: []float64{8, 15, 1, 6, 3}, weights: []float64{2, 3, 0.2, 8, 4}, r: 1, s: 1, ans: -4.786371011357490, }, { x: []float64{10, 2, 1, 8, 5}, y: []float64{8, 15, 1, 6, 3}, weights: []float64{2, 3, 0.2, 8, 4}, r: 2, s: 3, ans: 1.598600579313326e+03, }, } { m := BivariateMoment(test.r, test.s, test.x, test.y, test.weights) if math.Abs(test.ans-m) > 1e-14 { t.Errorf("Moment mismatch case %d. Expected %v, found %v", i, test.ans, m) } } if !panics(func() { BivariateMoment(1, 1, make([]float64, 3), make([]float64, 2), nil) }) { t.Errorf("Moment did not panic with x, y length mismatch") } if !panics(func() { BivariateMoment(1, 1, make([]float64, 2), make([]float64, 3), nil) }) { t.Errorf("Moment did not panic with x, y length mismatch") } if !panics(func() { BivariateMoment(1, 1, make([]float64, 2), make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Moment did not panic with x, weights length mismatch") } if !panics(func() { BivariateMoment(1, 1, make([]float64, 2), make([]float64, 2), make([]float64, 1)) }) { t.Errorf("Moment did not panic with x, weights length mismatch") } } func TestMoment(t *testing.T) { for i, test := range []struct { x []float64 weights []float64 moment float64 ans float64 }{ { x: []float64{6, 2, 4, 8, 10}, moment: 5, ans: 0, }, { x: []float64{6, 2, 4, 8, 10}, weights: []float64{1, 2, 2, 2, 1}, moment: 5, ans: 121.875, }, } { m := Moment(test.moment, test.x, test.weights) if math.Abs(test.ans-m) > 1e-14 { t.Errorf("Moment mismatch case %d. Expected %v, found %v", i, test.ans, m) } } if !panics(func() { Moment(1, make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Moment did not panic with x, weights length mismatch") } if !panics(func() { Moment(1, make([]float64, 2), make([]float64, 3)) }) { t.Errorf("Moment did not panic with x, weights length mismatch") } } func TestMomentAbout(t *testing.T) { for i, test := range []struct { x []float64 weights []float64 moment float64 mean float64 ans float64 }{ { x: []float64{6, 2, 4, 8, 9}, mean: 3, moment: 5, ans: 2.2288e3, }, { x: []float64{6, 2, 4, 8, 9}, weights: []float64{1, 2, 2, 2, 1}, mean: 3, moment: 5, ans: 1.783625e3, }, } { m := MomentAbout(test.moment, test.x, test.mean, test.weights) if math.Abs(test.ans-m) > 1e-14 { t.Errorf("MomentAbout mismatch case %d. Expected %v, found %v", i, test.ans, m) } } if !panics(func() { MomentAbout(1, make([]float64, 3), 0, make([]float64, 2)) }) { t.Errorf("MomentAbout did not panic with x, weights length mismatch") } } func TestCDF(t *testing.T) { cumulantKinds := []CumulantKind{Empirical} for i, test := range []struct { q []float64 x []float64 weights []float64 ans [][]float64 }{ {}, { q: []float64{0, 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1}, x: []float64{1, 2, 3, 4, 5}, ans: [][]float64{{0, 0, 0.2, 0.2, 0.4, 0.6, 0.6, 0.8, 1, 1}}, }, { q: []float64{0, 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1}, x: []float64{1, 2, 3, 4, 5}, weights: []float64{1, 1, 1, 1, 1}, ans: [][]float64{{0, 0, 0.2, 0.2, 0.4, 0.6, 0.6, 0.8, 1, 1}}, }, { q: []float64{0, 0.9, 1}, x: []float64{math.NaN()}, ans: [][]float64{{math.NaN(), math.NaN(), math.NaN()}}, }, } { copyX := make([]float64, len(test.x)) copy(copyX, test.x) var copyW []float64 if test.weights != nil { copyW = make([]float64, len(test.weights)) copy(copyW, test.weights) } for j, q := range test.q { for k, kind := range cumulantKinds { v := CDF(q, kind, test.x, test.weights) if !floats.Equal(copyX, test.x) && !math.IsNaN(v) { t.Errorf("x changed for case %d kind %d percentile %v", i, k, q) } if !floats.Equal(copyW, test.weights) { t.Errorf("x changed for case %d kind %d percentile %v", i, k, q) } if v != test.ans[k][j] && !(math.IsNaN(v) && math.IsNaN(test.ans[k][j])) { t.Errorf("mismatch case %d kind %d percentile %v. Expected: %v, found: %v", i, k, q, test.ans[k][j], v) } } } } // these test cases should all result in a panic for i, test := range []struct { name string q float64 kind CumulantKind x []float64 weights []float64 }{ { name: "x == nil", kind: Empirical, x: nil, }, { name: "len(x) == 0", kind: Empirical, x: []float64{}, }, { name: "len(x) != len(weights)", q: 1.5, kind: Empirical, x: []float64{1, 2, 3, 4, 5}, weights: []float64{1, 2, 3}, }, { name: "unsorted x", q: 1.5, kind: Empirical, x: []float64{3, 2, 1}, }, { name: "unknown CumulantKind", q: 1.5, kind: CumulantKind(1000), // bogus x: []float64{1, 2, 3}, }, } { if !panics(func() { CDF(test.q, test.kind, test.x, test.weights) }) { t.Errorf("did not panic as expected with %s for case %d kind %d percentile %v x %v weights %v", test.name, i, test.kind, test.q, test.x, test.weights) } } } func TestQuantile(t *testing.T) { cumulantKinds := []CumulantKind{ Empirical, LinInterp, } for i, test := range []struct { p []float64 x []float64 w []float64 ans [][]float64 panics bool }{ { p: []float64{0, 0.05, 0.1, 0.15, 0.45, 0.5, 0.55, 0.85, 0.9, 0.95, 1}, x: nil, w: nil, panics: true, }, { p: []float64{0, 0.05, 0.1, 0.15, 0.45, 0.5, 0.55, 0.85, 0.9, 0.95, 1}, x: []float64{}, w: nil, panics: true, }, { p: []float64{0, 0.05, 0.1, 0.15, 0.45, 0.5, 0.55, 0.85, 0.9, 0.95, 1}, x: []float64{1}, w: nil, ans: [][]float64{ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, }, }, { p: []float64{0, 0.05, 0.1, 0.15, 0.45, 0.5, 0.55, 0.85, 0.9, 0.95, 1}, x: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, w: nil, ans: [][]float64{ {1, 1, 1, 2, 5, 5, 6, 9, 9, 10, 10}, {1, 1, 1, 1.5, 4.5, 5, 5.5, 8.5, 9, 9.5, 10}, }, }, { p: []float64{0, 0.05, 0.1, 0.15, 0.45, 0.5, 0.55, 0.85, 0.9, 0.95, 1}, x: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, w: []float64{3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, ans: [][]float64{ {1, 1, 1, 2, 5, 5, 6, 9, 9, 10, 10}, {1, 1, 1, 1.5, 4.5, 5, 5.5, 8.5, 9, 9.5, 10}, }, }, { p: []float64{0, 0.05, 0.1, 0.15, 0.45, 0.5, 0.55, 0.85, 0.9, 0.95, 1}, x: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, w: []float64{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, ans: [][]float64{ {1, 2, 3, 4, 7, 7, 8, 10, 10, 10, 10}, {1, 1.875, 2.833333333333333, 3.5625, 6.535714285714286, 6.928571428571429, 7.281250000000001, 9.175, 9.45, 9.725, 10}, }, }, { p: []float64{0.5}, x: []float64{1, 2, 3, 4, 5, 6, 7, 8, math.NaN(), 10}, ans: [][]float64{ {math.NaN()}, {math.NaN()}, }, }, } { copyX := make([]float64, len(test.x)) copy(copyX, test.x) var copyW []float64 if test.w != nil { copyW = make([]float64, len(test.w)) copy(copyW, test.w) } for j, p := range test.p { for k, kind := range cumulantKinds { var v float64 if test.panics != panics(func() { v = Quantile(p, kind, test.x, test.w) }) { t.Errorf("Quantile did not panic when expected: test %d", j) } if !floats.Same(copyX, test.x) { t.Errorf("x changed for case %d kind %d percentile %v", i, k, p) } if !floats.Same(copyW, test.w) { t.Errorf("x changed for case %d kind %d percentile %v", i, k, p) } if test.panics { continue } if v != test.ans[k][j] && !(math.IsNaN(v) && math.IsNaN(test.ans[k][j])) { t.Errorf("mismatch case %d kind %d percentile %v. Expected: %v, found: %v", i, k, p, test.ans[k][j], v) } } } } } func TestQuantileInvalidInput(t *testing.T) { cumulantKinds := []CumulantKind{ Empirical, LinInterp, } for _, test := range []struct { name string p float64 x []float64 w []float64 }{ { name: "p < 0", p: -1, }, { name: "p > 1", p: 2, }, { name: "p is NaN", p: math.NaN(), }, { name: "len(x) != len(weights)", p: .5, x: make([]float64, 4), w: make([]float64, 2), }, { name: "x not sorted", p: .5, x: []float64{3, 2, 1}, }, } { for _, kind := range cumulantKinds { if !panics(func() { Quantile(test.p, kind, test.x, test.w) }) { t.Errorf("Quantile did not panic when %s", test.name) } } } } func TestQuantileInvalidCumulantKind(t *testing.T) { if !panics(func() { Quantile(0.5, CumulantKind(1000), []float64{1, 2, 3}, nil) }) { t.Errorf("Quantile did not panic when CumulantKind is unknown") } } func ExampleStdDev() { x := []float64{8, 2, -9, 15, 4} stdev := StdDev(x, nil) fmt.Printf("The standard deviation of the samples is %.4f\n", stdev) weights := []float64{2, 2, 6, 7, 1} weightedStdev := StdDev(x, weights) fmt.Printf("The weighted standard deviation of the samples is %.4f\n", weightedStdev) // Output: // The standard deviation of the samples is 8.8034 // The weighted standard deviation of the samples is 10.5733 } func ExamplePopStdDev() { x := []float64{8, 2, -9, 15, 4} stdev := PopStdDev(x, nil) fmt.Printf("The standard deviation of the population is %.4f\n", stdev) weights := []float64{2, 2, 6, 7, 1} weightedStdev := PopStdDev(x, weights) fmt.Printf("The weighted standard deviation of the population is %.4f\n", weightedStdev) // Output: // The standard deviation of the population is 7.8740 // The weighted standard deviation of the population is 10.2754 } func ExampleStdErr() { x := []float64{8, 2, -9, 15, 4} weights := []float64{2, 2, 6, 7, 1} mean := Mean(x, weights) stdev := StdDev(x, weights) nSamples := floats.Sum(weights) stdErr := StdErr(stdev, nSamples) fmt.Printf("The standard deviation is %.4f and there are %g samples, so the mean\nis likely %.4f ± %.4f.", stdev, nSamples, mean, stdErr) // Output: // The standard deviation is 10.5733 and there are 18 samples, so the mean // is likely 4.1667 ± 2.4921. } func TestSkew(t *testing.T) { for i, test := range []struct { x []float64 weights []float64 ans float64 }{ { x: []float64{8, 3, 7, 8, 4}, weights: nil, ans: -0.581456499151665, }, { x: []float64{8, 3, 7, 8, 4}, weights: []float64{1, 1, 1, 1, 1}, ans: -0.581456499151665, }, { x: []float64{8, 3, 7, 8, 4}, weights: []float64{2, 1, 2, 1, 1}, ans: -1.12066646837198, }, } { skew := Skew(test.x, test.weights) if math.Abs(skew-test.ans) > 1e-14 { t.Errorf("Skew mismatch case %d. Expected %v, Found %v", i, test.ans, skew) } } if !panics(func() { Skew(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Skew did not panic with x, weights length mismatch") } } func TestSortWeighted(t *testing.T) { for i, test := range []struct { x []float64 w []float64 ansx []float64 answ []float64 }{ { x: []float64{8, 3, 7, 8, 4}, ansx: []float64{3, 4, 7, 8, 8}, }, { x: []float64{8, 3, 7, 8, 4}, w: []float64{.5, 1, 1, .5, 1}, ansx: []float64{3, 4, 7, 8, 8}, answ: []float64{1, 1, 1, .5, .5}, }, } { SortWeighted(test.x, test.w) if !floats.Same(test.x, test.ansx) { t.Errorf("SortWeighted mismatch case %d. Expected x %v, Found x %v", i, test.ansx, test.x) } if !(test.w == nil) && !floats.Same(test.w, test.answ) { t.Errorf("SortWeighted mismatch case %d. Expected w %v, Found w %v", i, test.answ, test.w) } } if !panics(func() { SortWeighted(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("SortWeighted did not panic with x, weights length mismatch") } } func TestSortWeightedLabeled(t *testing.T) { for i, test := range []struct { x []float64 l []bool w []float64 ansx []float64 ansl []bool answ []float64 }{ { x: []float64{8, 3, 7, 8, 4}, ansx: []float64{3, 4, 7, 8, 8}, }, { x: []float64{8, 3, 7, 8, 4}, w: []float64{.5, 1, 1, .5, 1}, ansx: []float64{3, 4, 7, 8, 8}, answ: []float64{1, 1, 1, .5, .5}, }, { x: []float64{8, 3, 7, 8, 4}, l: []bool{false, false, true, false, true}, ansx: []float64{3, 4, 7, 8, 8}, ansl: []bool{false, true, true, false, false}, }, { x: []float64{8, 3, 7, 8, 4}, l: []bool{false, false, true, false, true}, w: []float64{.5, 1, 1, .5, 1}, ansx: []float64{3, 4, 7, 8, 8}, ansl: []bool{false, true, true, false, false}, answ: []float64{1, 1, 1, .5, .5}, }, } { SortWeightedLabeled(test.x, test.l, test.w) if !floats.Same(test.x, test.ansx) { t.Errorf("SortWeightedLabelled mismatch case %d. Expected x %v, Found x %v", i, test.ansx, test.x) } if (test.l != nil) && !reflect.DeepEqual(test.l, test.ansl) { t.Errorf("SortWeightedLabelled mismatch case %d. Expected l %v, Found l %v", i, test.ansl, test.l) } if (test.w != nil) && !floats.Same(test.w, test.answ) { t.Errorf("SortWeightedLabelled mismatch case %d. Expected w %v, Found w %v", i, test.answ, test.w) } } if !panics(func() { SortWeightedLabeled(make([]float64, 3), make([]bool, 2), make([]float64, 3)) }) { t.Errorf("SortWeighted did not panic with x, labels length mismatch") } if !panics(func() { SortWeightedLabeled(make([]float64, 3), make([]bool, 2), nil) }) { t.Errorf("SortWeighted did not panic with x, labels length mismatch") } if !panics(func() { SortWeightedLabeled(make([]float64, 3), make([]bool, 3), make([]float64, 2)) }) { t.Errorf("SortWeighted did not panic with x, weights length mismatch") } if !panics(func() { SortWeightedLabeled(make([]float64, 3), nil, make([]float64, 2)) }) { t.Errorf("SortWeighted did not panic with x, weights length mismatch") } } func TestVariance(t *testing.T) { for i, test := range []struct { x []float64 weights []float64 ans float64 }{ { x: []float64{8, -3, 7, 8, -4}, weights: nil, ans: 37.7, }, { x: []float64{8, -3, 7, 8, -4}, weights: []float64{1, 1, 1, 1, 1}, ans: 37.7, }, { x: []float64{8, 3, 7, 8, 4}, weights: []float64{2, 1, 2, 1, 1}, ans: 4.2857142857142865, }, { x: []float64{1, 4, 9}, weights: []float64{1, 1.5, 1}, ans: 13.142857142857146, }, { x: []float64{1, 2, 3}, weights: []float64{1, 1.5, 1}, ans: .8, }, } { variance := Variance(test.x, test.weights) if math.Abs(variance-test.ans) > 1e-14 { t.Errorf("Variance mismatch case %d. Expected %v, Found %v", i, test.ans, variance) } } if !panics(func() { Variance(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("Variance did not panic with x, weights length mismatch") } } func TestPopVariance(t *testing.T) { for i, test := range []struct { x []float64 weights []float64 ans float64 }{ { x: []float64{8, -3, 7, 8, -4}, weights: nil, ans: 30.16, }, { x: []float64{8, -3, 7, 8, -4}, weights: []float64{1, 1, 1, 1, 1}, ans: 30.16, }, { x: []float64{8, 3, 7, 8, 4}, weights: []float64{2, 1, 2, 1, 1}, ans: 3.6734693877551026, }, { x: []float64{1, 4, 9}, weights: []float64{1, 1.5, 1}, ans: 9.387755102040817, }, { x: []float64{1, 2, 3}, weights: []float64{1, 1.5, 1}, ans: 0.5714285714285714, }, { x: []float64{2}, weights: nil, ans: 0, }, { x: []float64{2}, weights: []float64{2}, ans: 0, }, } { variance := PopVariance(test.x, test.weights) if math.Abs(variance-test.ans) > 1e-14 { t.Errorf("PopVariance mismatch case %d. Expected %v, Found %v", i, test.ans, variance) } } if !panics(func() { PopVariance(make([]float64, 3), make([]float64, 2)) }) { t.Errorf("PopVariance did not panic with x, weights length mismatch") } } func ExampleVariance() { x := []float64{8, 2, -9, 15, 4} variance := Variance(x, nil) fmt.Printf("The variance of the samples is %.4f\n", variance) weights := []float64{2, 2, 6, 7, 1} weightedVariance := Variance(x, weights) fmt.Printf("The weighted variance of the samples is %.4f\n", weightedVariance) // Output: // The variance of the samples is 77.5000 // The weighted variance of the samples is 111.7941 } func ExamplePopVariance() { x := []float64{8, 2, -9, 15, 4} variance := PopVariance(x, nil) fmt.Printf("The biased variance of the samples is %.4f\n", variance) weights := []float64{2, 2, 6, 7, 1} weightedVariance := PopVariance(x, weights) fmt.Printf("The weighted biased variance of the samples is %.4f\n", weightedVariance) // Output: // The biased variance of the samples is 62.0000 // The weighted biased variance of the samples is 105.5833 } func TestStdScore(t *testing.T) { for i, test := range []struct { x float64 u float64 s float64 z float64 }{ { x: 4, u: -6, s: 5, z: 2, }, { x: 1, u: 0, s: 1, z: 1, }, } { z := StdScore(test.x, test.u, test.s) if math.Abs(z-test.z) > 1e-14 { t.Errorf("StdScore mismatch case %d. Expected %v, Found %v", i, test.z, z) } } } golang-gonum-v1-gonum-0.14.0/stat/statmat.go000066400000000000000000000103011450372207100206100ustar00rootroot00000000000000// 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 stat import ( "math" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) // CovarianceMatrix calculates the covariance matrix (also known as the // variance-covariance matrix) calculated from a matrix of data, x, using // a two-pass algorithm. The result is stored in dst. // // If weights is not nil the weighted covariance of x is calculated. weights // must have length equal to the number of rows in input data matrix and // must not contain negative elements. // The dst matrix must either be empty or have the same number of // columns as the input data matrix. func CovarianceMatrix(dst *mat.SymDense, x mat.Matrix, weights []float64) { // This is the matrix version of the two-pass algorithm. It doesn't use the // additional floating point error correction that the Covariance function uses // to reduce the impact of rounding during centering. r, c := x.Dims() if dst.IsEmpty() { *dst = *(dst.GrowSym(c).(*mat.SymDense)) } else if n := dst.SymmetricDim(); n != c { panic(mat.ErrShape) } var xt mat.Dense xt.CloneFrom(x.T()) // Subtract the mean of each of the columns. for i := 0; i < c; i++ { v := xt.RawRowView(i) // This will panic with ErrShape if len(weights) != len(v), so // we don't have to check the size later. mean := Mean(v, weights) floats.AddConst(-mean, v) } if weights == nil { // Calculate the normalization factor // scaled by the sample size. dst.SymOuterK(1/(float64(r)-1), &xt) return } // Multiply by the sqrt of the weights, so that multiplication is symmetric. sqrtwts := make([]float64, r) for i, w := range weights { if w < 0 { panic("stat: negative covariance matrix weights") } sqrtwts[i] = math.Sqrt(w) } // Weight the rows. for i := 0; i < c; i++ { v := xt.RawRowView(i) floats.Mul(v, sqrtwts) } // Calculate the normalization factor // scaled by the weighted sample size. dst.SymOuterK(1/(floats.Sum(weights)-1), &xt) } // CorrelationMatrix returns the correlation matrix calculated from a matrix // of data, x, using a two-pass algorithm. The result is stored in dst. // // If weights is not nil the weighted correlation of x is calculated. weights // must have length equal to the number of rows in input data matrix and // must not contain negative elements. // The dst matrix must either be empty or have the same number of // columns as the input data matrix. func CorrelationMatrix(dst *mat.SymDense, x mat.Matrix, weights []float64) { // This will panic if the sizes don't match, or if weights is the wrong size. CovarianceMatrix(dst, x, weights) covToCorr(dst) } // covToCorr converts a covariance matrix to a correlation matrix. func covToCorr(c *mat.SymDense) { r := c.SymmetricDim() s := make([]float64, r) for i := 0; i < r; i++ { s[i] = 1 / math.Sqrt(c.At(i, i)) } for i, sx := range s { // Ensure that the diagonal has exactly ones. c.SetSym(i, i, 1) for j := i + 1; j < r; j++ { v := c.At(i, j) c.SetSym(i, j, v*sx*s[j]) } } } // corrToCov converts a correlation matrix to a covariance matrix. // The input sigma should be vector of standard deviations corresponding // to the covariance. It will panic if len(sigma) is not equal to the // number of rows in the correlation matrix. func corrToCov(c *mat.SymDense, sigma []float64) { r, _ := c.Dims() if r != len(sigma) { panic(mat.ErrShape) } for i, sx := range sigma { // Ensure that the diagonal has exactly sigma squared. c.SetSym(i, i, sx*sx) for j := i + 1; j < r; j++ { v := c.At(i, j) c.SetSym(i, j, v*sx*sigma[j]) } } } // Mahalanobis computes the Mahalanobis distance // // D = sqrt((x-y)ᵀ * Σ^-1 * (x-y)) // // between the column vectors x and y given the cholesky decomposition of Σ. // Mahalanobis returns NaN if the linear solve fails. // // See https://en.wikipedia.org/wiki/Mahalanobis_distance for more information. func Mahalanobis(x, y mat.Vector, chol *mat.Cholesky) float64 { var diff mat.VecDense diff.SubVec(x, y) var tmp mat.VecDense err := chol.SolveVecTo(&tmp, &diff) if err != nil { return math.NaN() } return math.Sqrt(mat.Dot(&tmp, &diff)) } golang-gonum-v1-gonum-0.14.0/stat/statmat_test.go000066400000000000000000000266411450372207100216650ustar00rootroot00000000000000// 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 stat import ( "math" "testing" "golang.org/x/exp/rand" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/mat" ) func TestCovarianceMatrix(t *testing.T) { const tol = 1e-15 // An alternative way to test this is to call the Variance and // Covariance functions and ensure that the results are identical. for i, test := range []struct { data *mat.Dense weights []float64 ans *mat.Dense }{ { data: mat.NewDense(5, 2, []float64{ -2, -4, -1, 2, 0, 0, 1, -2, 2, 4, }), weights: nil, ans: mat.NewDense(2, 2, []float64{ 2.5, 3, 3, 10, }), }, { data: mat.NewDense(3, 2, []float64{ 1, 1, 2, 4, 3, 9, }), weights: []float64{ 1, 1.5, 1, }, ans: mat.NewDense(2, 2, []float64{ 0.8, 3.2, 3.2, 13.142857142857146, }), }, } { // Make a copy of the data to check that it isn't changing. r := test.data.RawMatrix() d := make([]float64, len(r.Data)) copy(d, r.Data) w := make([]float64, len(test.weights)) if test.weights != nil { copy(w, test.weights) } var cov mat.SymDense CovarianceMatrix(&cov, test.data, test.weights) if !mat.EqualApprox(&cov, test.ans, tol) { t.Errorf("%d: expected cov %v, found %v", i, test.ans, &cov) } if !floats.Equal(d, r.Data) { t.Errorf("%d: data was modified during execution", i) } if !floats.Equal(w, test.weights) { t.Errorf("%d: weights was modified during execution", i) } // compare with call to Covariance _, cols := cov.Dims() for ci := 0; ci < cols; ci++ { for cj := 0; cj < cols; cj++ { x := mat.Col(nil, ci, test.data) y := mat.Col(nil, cj, test.data) wc := Covariance(x, y, test.weights) if math.Abs(wc-cov.At(ci, cj)) > 1e-14 { t.Errorf("CovMat does not match at (%v, %v). Want %v, got %v.", ci, cj, wc, cov.At(ci, cj)) } } } } if !panics(func() { CovarianceMatrix(nil, mat.NewDense(5, 2, nil), []float64{}) }) { t.Errorf("CovarianceMatrix did not panic with weight size mismatch") } if !panics(func() { CovarianceMatrix(mat.NewSymDense(1, nil), mat.NewDense(5, 2, nil), nil) }) { t.Errorf("CovarianceMatrix did not panic with preallocation size mismatch") } if !panics(func() { CovarianceMatrix(nil, mat.NewDense(2, 2, []float64{1, 2, 3, 4}), []float64{1, -1}) }) { t.Errorf("CovarianceMatrix did not panic with negative weights") } if panics(func() { dst := mat.NewSymDense(4, nil) dst.Reset() CovarianceMatrix(dst, mat.NewDense(2, 2, []float64{1, 2, 3, 4}), nil) }) { t.Errorf("CovarianceMatrix panics with reset destination") } } func TestCorrelationMatrix(t *testing.T) { for i, test := range []struct { data *mat.Dense weights []float64 ans *mat.Dense }{ { data: mat.NewDense(3, 3, []float64{ 1, 2, 3, 3, 4, 5, 5, 6, 7, }), weights: nil, ans: mat.NewDense(3, 3, []float64{ 1, 1, 1, 1, 1, 1, 1, 1, 1, }), }, { data: mat.NewDense(5, 2, []float64{ -2, -4, -1, 2, 0, 0, 1, -2, 2, 4, }), weights: nil, ans: mat.NewDense(2, 2, []float64{ 1, 0.6, 0.6, 1, }), }, { data: mat.NewDense(3, 2, []float64{ 1, 1, 2, 4, 3, 9, }), weights: []float64{ 1, 1.5, 1, }, ans: mat.NewDense(2, 2, []float64{ 1, 0.9868703275903379, 0.9868703275903379, 1, }), }, } { // Make a copy of the data to check that it isn't changing. r := test.data.RawMatrix() d := make([]float64, len(r.Data)) copy(d, r.Data) w := make([]float64, len(test.weights)) if test.weights != nil { copy(w, test.weights) } var corr mat.SymDense CorrelationMatrix(&corr, test.data, test.weights) if !mat.Equal(&corr, test.ans) { t.Errorf("%d: expected corr %v, found %v", i, test.ans, &corr) } if !floats.Equal(d, r.Data) { t.Errorf("%d: data was modified during execution", i) } if !floats.Equal(w, test.weights) { t.Errorf("%d: weights was modified during execution", i) } // compare with call to Covariance _, cols := corr.Dims() for ci := 0; ci < cols; ci++ { for cj := 0; cj < cols; cj++ { x := mat.Col(nil, ci, test.data) y := mat.Col(nil, cj, test.data) wc := Correlation(x, y, test.weights) if math.Abs(wc-corr.At(ci, cj)) > 1e-14 { t.Errorf("CorrMat does not match at (%v, %v). Want %v, got %v.", ci, cj, wc, corr.At(ci, cj)) } } } } if !panics(func() { CorrelationMatrix(nil, mat.NewDense(5, 2, nil), []float64{}) }) { t.Errorf("CorrelationMatrix did not panic with weight size mismatch") } if !panics(func() { CorrelationMatrix(mat.NewSymDense(1, nil), mat.NewDense(5, 2, nil), nil) }) { t.Errorf("CorrelationMatrix did not panic with preallocation size mismatch") } if !panics(func() { CorrelationMatrix(nil, mat.NewDense(2, 2, []float64{1, 2, 3, 4}), []float64{1, -1}) }) { t.Errorf("CorrelationMatrix did not panic with negative weights") } } func TestCorrCov(t *testing.T) { // test both Cov2Corr and Cov2Corr for i, test := range []struct { data *mat.Dense weights []float64 }{ { data: mat.NewDense(3, 3, []float64{ 1, 2, 3, 3, 4, 5, 5, 6, 7, }), weights: nil, }, { data: mat.NewDense(5, 2, []float64{ -2, -4, -1, 2, 0, 0, 1, -2, 2, 4, }), weights: nil, }, { data: mat.NewDense(3, 2, []float64{ 1, 1, 2, 4, 3, 9, }), weights: []float64{ 1, 1.5, 1, }, }, } { var corr, cov mat.SymDense CorrelationMatrix(&corr, test.data, test.weights) CovarianceMatrix(&cov, test.data, test.weights) r := cov.SymmetricDim() // Get the diagonal elements from cov to determine the sigmas. sigmas := make([]float64, r) for i := range sigmas { sigmas[i] = math.Sqrt(cov.At(i, i)) } covFromCorr := mat.NewSymDense(corr.SymmetricDim(), nil) covFromCorr.CopySym(&corr) corrToCov(covFromCorr, sigmas) corrFromCov := mat.NewSymDense(cov.SymmetricDim(), nil) corrFromCov.CopySym(&cov) covToCorr(corrFromCov) if !mat.EqualApprox(&corr, corrFromCov, 1e-14) { t.Errorf("%d: corrToCov did not match direct Correlation calculation. Want: %v, got: %v. ", i, corr, corrFromCov) } if !mat.EqualApprox(&cov, covFromCorr, 1e-14) { t.Errorf("%d: covToCorr did not match direct Covariance calculation. Want: %v, got: %v. ", i, cov, covFromCorr) } if !panics(func() { corrToCov(mat.NewSymDense(2, nil), []float64{}) }) { t.Errorf("CorrelationMatrix did not panic with sigma size mismatch") } } } func TestMahalanobis(t *testing.T) { // Comparison with scipy. for cas, test := range []struct { x, y *mat.VecDense Sigma *mat.SymDense ans float64 }{ { x: mat.NewVecDense(3, []float64{1, 2, 3}), y: mat.NewVecDense(3, []float64{0.8, 1.1, -1}), Sigma: mat.NewSymDense(3, []float64{ 0.8, 0.3, 0.1, 0.3, 0.7, -0.1, 0.1, -0.1, 7}), ans: 1.9251757377680914, }, } { var chol mat.Cholesky ok := chol.Factorize(test.Sigma) if !ok { panic("bad test") } ans := Mahalanobis(test.x, test.y, &chol) if math.Abs(ans-test.ans) > 1e-14 { t.Errorf("Cas %d: got %v, want %v", cas, ans, test.ans) } } } // benchmarks func randMat(r, c int) mat.Matrix { x := make([]float64, r*c) for i := range x { x[i] = rand.Float64() } return mat.NewDense(r, c, x) } func benchmarkCovarianceMatrix(b *testing.B, m mat.Matrix) { var res mat.SymDense b.ResetTimer() for i := 0; i < b.N; i++ { res.Reset() CovarianceMatrix(&res, m, nil) } } func benchmarkCovarianceMatrixWeighted(b *testing.B, m mat.Matrix) { r, _ := m.Dims() wts := make([]float64, r) for i := range wts { wts[i] = 0.5 } var res mat.SymDense b.ResetTimer() for i := 0; i < b.N; i++ { res.Reset() CovarianceMatrix(&res, m, wts) } } func benchmarkCovarianceMatrixInPlace(b *testing.B, m mat.Matrix) { _, c := m.Dims() res := mat.NewSymDense(c, nil) b.ResetTimer() for i := 0; i < b.N; i++ { CovarianceMatrix(res, m, nil) } } func BenchmarkCovarianceMatrixSmallxSmall(b *testing.B) { // 10 * 10 elements x := randMat(small, small) benchmarkCovarianceMatrix(b, x) } func BenchmarkCovarianceMatrixSmallxMedium(b *testing.B) { // 10 * 1000 elements x := randMat(small, medium) benchmarkCovarianceMatrix(b, x) } func BenchmarkCovarianceMatrixMediumxSmall(b *testing.B) { // 1000 * 10 elements x := randMat(medium, small) benchmarkCovarianceMatrix(b, x) } func BenchmarkCovarianceMatrixMediumxMedium(b *testing.B) { // 1000 * 1000 elements x := randMat(medium, medium) benchmarkCovarianceMatrix(b, x) } func BenchmarkCovarianceMatrixLargexSmall(b *testing.B) { // 1e5 * 10 elements x := randMat(large, small) benchmarkCovarianceMatrix(b, x) } func BenchmarkCovarianceMatrixHugexSmall(b *testing.B) { // 1e7 * 10 elements x := randMat(huge, small) benchmarkCovarianceMatrix(b, x) } func BenchmarkCovarianceMatrixSmallxSmallWeighted(b *testing.B) { // 10 * 10 elements x := randMat(small, small) benchmarkCovarianceMatrixWeighted(b, x) } func BenchmarkCovarianceMatrixSmallxMediumWeighted(b *testing.B) { // 10 * 1000 elements x := randMat(small, medium) benchmarkCovarianceMatrixWeighted(b, x) } func BenchmarkCovarianceMatrixMediumxSmallWeighted(b *testing.B) { // 1000 * 10 elements x := randMat(medium, small) benchmarkCovarianceMatrixWeighted(b, x) } func BenchmarkCovarianceMatrixMediumxMediumWeighted(b *testing.B) { // 1000 * 1000 elements x := randMat(medium, medium) benchmarkCovarianceMatrixWeighted(b, x) } func BenchmarkCovarianceMatrixLargexSmallWeighted(b *testing.B) { // 1e5 * 10 elements x := randMat(large, small) benchmarkCovarianceMatrixWeighted(b, x) } func BenchmarkCovarianceMatrixHugexSmallWeighted(b *testing.B) { // 1e7 * 10 elements x := randMat(huge, small) benchmarkCovarianceMatrixWeighted(b, x) } func BenchmarkCovarianceMatrixSmallxSmallInPlace(b *testing.B) { // 10 * 10 elements x := randMat(small, small) benchmarkCovarianceMatrixInPlace(b, x) } func BenchmarkCovarianceMatrixSmallxMediumInPlace(b *testing.B) { // 10 * 1000 elements x := randMat(small, medium) benchmarkCovarianceMatrixInPlace(b, x) } func BenchmarkCovarianceMatrixMediumxSmallInPlace(b *testing.B) { // 1000 * 10 elements x := randMat(medium, small) benchmarkCovarianceMatrixInPlace(b, x) } func BenchmarkCovarianceMatrixMediumxMediumInPlace(b *testing.B) { // 1000 * 1000 elements x := randMat(medium, medium) benchmarkCovarianceMatrixInPlace(b, x) } func BenchmarkCovarianceMatrixLargexSmallInPlace(b *testing.B) { // 1e5 * 10 elements x := randMat(large, small) benchmarkCovarianceMatrixInPlace(b, x) } func BenchmarkCovarianceMatrixHugexSmallInPlace(b *testing.B) { // 1e7 * 10 elements x := randMat(huge, small) benchmarkCovarianceMatrixInPlace(b, x) } func BenchmarkCovToCorr(b *testing.B) { // generate a 10x10 covariance matrix m := randMat(small, small) var cov mat.SymDense CovarianceMatrix(&cov, m, nil) cc := mat.NewSymDense(cov.SymmetricDim(), nil) b.ResetTimer() for i := 0; i < b.N; i++ { b.StopTimer() cc.CopySym(&cov) b.StartTimer() covToCorr(cc) } } func BenchmarkCorrToCov(b *testing.B) { // generate a 10x10 correlation matrix m := randMat(small, small) var corr mat.SymDense CorrelationMatrix(&corr, m, nil) cc := mat.NewSymDense(corr.SymmetricDim(), nil) sigma := make([]float64, small) for i := range sigma { sigma[i] = 2 } b.ResetTimer() for i := 0; i < b.N; i++ { b.StopTimer() cc.CopySym(&corr) b.StartTimer() corrToCov(cc, sigma) } } golang-gonum-v1-gonum-0.14.0/staticcheck.conf000066400000000000000000000000401450372207100207640ustar00rootroot00000000000000checks = ["inherit", "-ST1012"] golang-gonum-v1-gonum-0.14.0/unit/000077500000000000000000000000001450372207100166155ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/unit/absorbedradioactivedose.go000066400000000000000000000036171450372207100240220ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // AbsorbedRadioactiveDose is a measure of absorbed dose of ionizing radiation in grays. type AbsorbedRadioactiveDose float64 const Gray AbsorbedRadioactiveDose = 1 // Unit converts the AbsorbedRadioactiveDose to a *Unit. func (a AbsorbedRadioactiveDose) Unit() *Unit { return New(float64(a), Dimensions{ LengthDim: 2, TimeDim: -2, }) } // AbsorbedRadioactiveDose allows AbsorbedRadioactiveDose to implement a AbsorbedRadioactiveDoseer interface. func (a AbsorbedRadioactiveDose) AbsorbedRadioactiveDose() AbsorbedRadioactiveDose { return a } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (a *AbsorbedRadioactiveDose) From(u Uniter) error { if !DimensionsMatch(u, Gray) { *a = AbsorbedRadioactiveDose(math.NaN()) return errors.New("unit: dimension mismatch") } *a = AbsorbedRadioactiveDose(u.Unit().Value()) return nil } func (a AbsorbedRadioactiveDose) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", a, float64(a)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " Gy" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(a)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(a)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(a)) default: fmt.Fprintf(fs, "%"+string(c), float64(a)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g Gy)", c, a, float64(a)) } } golang-gonum-v1-gonum-0.14.0/unit/absorbedradioactivedose_test.go000066400000000000000000000032061450372207100250530ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestAbsorbedRadioactiveDose(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got AbsorbedRadioactiveDose err := got.From(AbsorbedRadioactiveDose(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != AbsorbedRadioactiveDose(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.AbsorbedRadioactiveDose() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestAbsorbedRadioactiveDoseFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value AbsorbedRadioactiveDose format string want string }{ {1.23456789, "%v", "1.23456789 Gy"}, {1.23456789, "%.1v", "1 Gy"}, {1.23456789, "%20.1v", " 1 Gy"}, {1.23456789, "%20v", " 1.23456789 Gy"}, {1.23456789, "%1v", "1.23456789 Gy"}, {1.23456789, "%#v", "unit.AbsorbedRadioactiveDose(1.23456789)"}, {1.23456789, "%s", "%!s(unit.AbsorbedRadioactiveDose=1.23456789 Gy)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/acceleration.go000066400000000000000000000033331450372207100215770ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Acceleration represents an acceleration in metres per second squared. type Acceleration float64 // Unit converts the Acceleration to a *Unit. func (a Acceleration) Unit() *Unit { return New(float64(a), Dimensions{ LengthDim: 1, TimeDim: -2, }) } // Acceleration allows Acceleration to implement a Accelerationer interface. func (a Acceleration) Acceleration() Acceleration { return a } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (a *Acceleration) From(u Uniter) error { if !DimensionsMatch(u, Acceleration(0)) { *a = Acceleration(math.NaN()) return errors.New("unit: dimension mismatch") } *a = Acceleration(u.Unit().Value()) return nil } func (a Acceleration) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", a, float64(a)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " m s^-2" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(a)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(a)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(a)) default: fmt.Fprintf(fs, "%"+string(c), float64(a)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g m s^-2)", c, a, float64(a)) } } golang-gonum-v1-gonum-0.14.0/unit/acceleration_test.go000066400000000000000000000030631450372207100226360ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestAcceleration(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Acceleration err := got.From(Acceleration(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Acceleration(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Acceleration() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestAccelerationFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Acceleration format string want string }{ {1.23456789, "%v", "1.23456789 m s^-2"}, {1.23456789, "%.1v", "1 m s^-2"}, {1.23456789, "%20.1v", " 1 m s^-2"}, {1.23456789, "%20v", " 1.23456789 m s^-2"}, {1.23456789, "%1v", "1.23456789 m s^-2"}, {1.23456789, "%#v", "unit.Acceleration(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Acceleration=1.23456789 m s^-2)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/angle.go000066400000000000000000000031211450372207100202270ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Angle represents an angle in radians. type Angle float64 const Rad Angle = 1 // Unit converts the Angle to a *Unit. func (a Angle) Unit() *Unit { return New(float64(a), Dimensions{ AngleDim: 1, }) } // Angle allows Angle to implement a Angleer interface. func (a Angle) Angle() Angle { return a } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (a *Angle) From(u Uniter) error { if !DimensionsMatch(u, Rad) { *a = Angle(math.NaN()) return errors.New("unit: dimension mismatch") } *a = Angle(u.Unit().Value()) return nil } func (a Angle) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", a, float64(a)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " rad" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(a)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(a)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(a)) default: fmt.Fprintf(fs, "%"+string(c), float64(a)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g rad)", c, a, float64(a)) } } golang-gonum-v1-gonum-0.14.0/unit/angle_test.go000066400000000000000000000027501450372207100212750ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestAngle(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Angle err := got.From(Angle(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Angle(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Angle() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestAngleFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Angle format string want string }{ {1.23456789, "%v", "1.23456789 rad"}, {1.23456789, "%.1v", "1 rad"}, {1.23456789, "%20.1v", " 1 rad"}, {1.23456789, "%20v", " 1.23456789 rad"}, {1.23456789, "%1v", "1.23456789 rad"}, {1.23456789, "%#v", "unit.Angle(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Angle=1.23456789 rad)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/area.go000066400000000000000000000030701450372207100200540ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Area represents an area in square metres. type Area float64 // Unit converts the Area to a *Unit. func (a Area) Unit() *Unit { return New(float64(a), Dimensions{ LengthDim: 2, }) } // Area allows Area to implement a Areaer interface. func (a Area) Area() Area { return a } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (a *Area) From(u Uniter) error { if !DimensionsMatch(u, Area(0)) { *a = Area(math.NaN()) return errors.New("unit: dimension mismatch") } *a = Area(u.Unit().Value()) return nil } func (a Area) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", a, float64(a)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " m^2" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(a)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(a)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(a)) default: fmt.Fprintf(fs, "%"+string(c), float64(a)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g m^2)", c, a, float64(a)) } } golang-gonum-v1-gonum-0.14.0/unit/area_test.go000066400000000000000000000027371450372207100211240ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestArea(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Area err := got.From(Area(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Area(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Area() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestAreaFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Area format string want string }{ {1.23456789, "%v", "1.23456789 m^2"}, {1.23456789, "%.1v", "1 m^2"}, {1.23456789, "%20.1v", " 1 m^2"}, {1.23456789, "%20v", " 1.23456789 m^2"}, {1.23456789, "%1v", "1.23456789 m^2"}, {1.23456789, "%#v", "unit.Area(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Area=1.23456789 m^2)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/capacitance.go000066400000000000000000000034011450372207100213750ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Capacitance represents an electrical capacitance in Farads. type Capacitance float64 const Farad Capacitance = 1 // Unit converts the Capacitance to a *Unit. func (cp Capacitance) Unit() *Unit { return New(float64(cp), Dimensions{ CurrentDim: 2, LengthDim: -2, MassDim: -1, TimeDim: 4, }) } // Capacitance allows Capacitance to implement a Capacitancer interface. func (cp Capacitance) Capacitance() Capacitance { return cp } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (cp *Capacitance) From(u Uniter) error { if !DimensionsMatch(u, Farad) { *cp = Capacitance(math.NaN()) return errors.New("unit: dimension mismatch") } *cp = Capacitance(u.Unit().Value()) return nil } func (cp Capacitance) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cp, float64(cp)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " F" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(cp)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(cp)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(cp)) default: fmt.Fprintf(fs, "%"+string(c), float64(cp)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g F)", c, cp, float64(cp)) } } golang-gonum-v1-gonum-0.14.0/unit/capacitance_test.go000066400000000000000000000030261450372207100224370ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestCapacitance(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Capacitance err := got.From(Capacitance(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Capacitance(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Capacitance() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestCapacitanceFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Capacitance format string want string }{ {1.23456789, "%v", "1.23456789 F"}, {1.23456789, "%.1v", "1 F"}, {1.23456789, "%20.1v", " 1 F"}, {1.23456789, "%20v", " 1.23456789 F"}, {1.23456789, "%1v", "1.23456789 F"}, {1.23456789, "%#v", "unit.Capacitance(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Capacitance=1.23456789 F)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/charge.go000066400000000000000000000032211450372207100203730ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Charge represents an electric charge in Coulombs. type Charge float64 const Coulomb Charge = 1 // Unit converts the Charge to a *Unit. func (ch Charge) Unit() *Unit { return New(float64(ch), Dimensions{ CurrentDim: 1, TimeDim: 1, }) } // Charge allows Charge to implement a Charger interface. func (ch Charge) Charge() Charge { return ch } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (ch *Charge) From(u Uniter) error { if !DimensionsMatch(u, Coulomb) { *ch = Charge(math.NaN()) return errors.New("unit: dimension mismatch") } *ch = Charge(u.Unit().Value()) return nil } func (ch Charge) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", ch, float64(ch)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " C" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(ch)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(ch)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(ch)) default: fmt.Fprintf(fs, "%"+string(c), float64(ch)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g C)", c, ch, float64(ch)) } } golang-gonum-v1-gonum-0.14.0/unit/charge_test.go000066400000000000000000000027511450372207100214410ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestCharge(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Charge err := got.From(Charge(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Charge(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Charge() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestChargeFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Charge format string want string }{ {1.23456789, "%v", "1.23456789 C"}, {1.23456789, "%.1v", "1 C"}, {1.23456789, "%20.1v", " 1 C"}, {1.23456789, "%20v", " 1.23456789 C"}, {1.23456789, "%1v", "1.23456789 C"}, {1.23456789, "%#v", "unit.Charge(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Charge=1.23456789 C)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/conductance.go000066400000000000000000000034061450372207100214350ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Conductance represents an electrical conductance in Siemens. type Conductance float64 const Siemens Conductance = 1 // Unit converts the Conductance to a *Unit. func (co Conductance) Unit() *Unit { return New(float64(co), Dimensions{ CurrentDim: 2, LengthDim: -2, MassDim: -1, TimeDim: 3, }) } // Conductance allows Conductance to implement a Conductancer interface. func (co Conductance) Conductance() Conductance { return co } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (co *Conductance) From(u Uniter) error { if !DimensionsMatch(u, Siemens) { *co = Conductance(math.NaN()) return errors.New("unit: dimension mismatch") } *co = Conductance(u.Unit().Value()) return nil } func (co Conductance) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", co, float64(co)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " S" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(co)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(co)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(co)) default: fmt.Fprintf(fs, "%"+string(c), float64(co)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g S)", c, co, float64(co)) } } golang-gonum-v1-gonum-0.14.0/unit/conductance_test.go000066400000000000000000000030261450372207100224720ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestConductance(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Conductance err := got.From(Conductance(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Conductance(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Conductance() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestConductanceFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Conductance format string want string }{ {1.23456789, "%v", "1.23456789 S"}, {1.23456789, "%.1v", "1 S"}, {1.23456789, "%20.1v", " 1 S"}, {1.23456789, "%20v", " 1.23456789 S"}, {1.23456789, "%1v", "1.23456789 S"}, {1.23456789, "%#v", "unit.Conductance(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Conductance=1.23456789 S)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/000077500000000000000000000000001450372207100204465ustar00rootroot00000000000000golang-gonum-v1-gonum-0.14.0/unit/constant/atomicmass.go000066400000000000000000000011041450372207100231310ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import "gonum.org/v1/gonum/unit" // AtomicMass is the atomic mass constant (mᵤ), one twelfth of the mass of an unbound atom of carbon-12 at rest and in its ground state. // The dimension of AtomicMass is kg. The standard uncertainty of the constant is 5e-37 kg. const AtomicMass = unit.Mass(1.6605390666e-27) golang-gonum-v1-gonum-0.14.0/unit/constant/avogadro.go000066400000000000000000000025501450372207100226010ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // Avogadro is the Avogadro constant (A), the number of constituent particles contained in one mole of a substance. // The dimension of Avogadro is mol^-1. The constant is exact. const Avogadro = avogadroUnits(6.02214076e+23) type avogadroUnits float64 // Unit converts the avogadroUnits to a *unit.Unit func (cnst avogadroUnits) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ unit.MoleDim: -1, }) } func (cnst avogadroUnits) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.avogadroUnits=%v mol^-1)", float64(cnst)) } } golang-gonum-v1-gonum-0.14.0/unit/constant/avogadro_test.go000066400000000000000000000016341450372207100236420ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func TestAvogadroFormat(t *testing.T) { t.Parallel() for _, test := range []struct { format string want string }{ {"%v", "6.02214076e+23 mol^-1"}, {"%.1v", "6e+23 mol^-1"}, {"%50.1v", " 6e+23 mol^-1"}, {"%50v", " 6.02214076e+23 mol^-1"}, {"%1v", "6.02214076e+23 mol^-1"}, {"%#v", "constant.avogadroUnits(6.02214076e+23)"}, {"%s", "%!s(constant.avogadroUnits=6.02214076e+23 mol^-1)"}, } { got := fmt.Sprintf(test.format, Avogadro) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/boltzmann.go000066400000000000000000000027701450372207100230070ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // Boltzmann is the Boltzmann constant (k), it relates the average relative kinetic energy of particles in a gas with the temperature of the gas. // The dimensions of Boltzmann are kg m^2 K^-1 s^-2. The constant is exact. const Boltzmann = boltzmannUnits(1.380649e-23) type boltzmannUnits float64 // Unit converts the boltzmannUnits to a *unit.Unit func (cnst boltzmannUnits) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ unit.MassDim: 1, unit.LengthDim: 2, unit.TimeDim: -2, unit.TemperatureDim: -1, }) } func (cnst boltzmannUnits) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.boltzmannUnits=%v kg m^2 K^-1 s^-2)", float64(cnst)) } } golang-gonum-v1-gonum-0.14.0/unit/constant/boltzmann_test.go000066400000000000000000000017001450372207100240360ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func TestBoltzmannFormat(t *testing.T) { t.Parallel() for _, test := range []struct { format string want string }{ {"%v", "1.380649e-23 kg m^2 K^-1 s^-2"}, {"%.1v", "1e-23 kg m^2 K^-1 s^-2"}, {"%50.1v", " 1e-23 kg m^2 K^-1 s^-2"}, {"%50v", " 1.380649e-23 kg m^2 K^-1 s^-2"}, {"%1v", "1.380649e-23 kg m^2 K^-1 s^-2"}, {"%#v", "constant.boltzmannUnits(1.380649e-23)"}, {"%s", "%!s(constant.boltzmannUnits=1.380649e-23 kg m^2 K^-1 s^-2)"}, } { got := fmt.Sprintf(test.format, Boltzmann) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/defined_types.go000066400000000000000000000041361450372207100236230ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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:build ignore // +build ignore package main import "gonum.org/v1/gonum/unit" var definedTypes = []struct { unit unit.Uniter name string }{ {unit: unit.AbsorbedRadioactiveDose(1), name: "unit.AbsorbedRadioactiveDose"}, {unit: unit.Acceleration(1), name: "unit.Acceleration"}, {unit: unit.Angle(1), name: "unit.Angle"}, {unit: unit.Area(1), name: "unit.Area"}, {unit: unit.Capacitance(1), name: "unit.Capacitance"}, {unit: unit.Charge(1), name: "unit.Charge"}, {unit: unit.Conductance(1), name: "unit.Conductance"}, {unit: unit.Current(1), name: "unit.Current"}, {unit: unit.Dimless(1), name: "unit.Dimless"}, {unit: unit.Energy(1), name: "unit.Energy"}, {unit: unit.EquivalentRadioactiveDose(1), name: "unit.EquivalentRadioactiveDose"}, {unit: unit.Force(1), name: "unit.Force"}, {unit: unit.Frequency(1), name: "unit.Frequency"}, {unit: unit.Inductance(1), name: "unit.Inductance"}, {unit: unit.Length(1), name: "unit.Length"}, {unit: unit.LuminousIntensity(1), name: "unit.LuminousIntensity"}, {unit: unit.MagneticFlux(1), name: "unit.MagneticFlux"}, {unit: unit.MagneticFluxDensity(1), name: "unit.MagneticFluxDensity"}, {unit: unit.Mass(1), name: "unit.Mass"}, {unit: unit.Mole(1), name: "unit.Mole"}, {unit: unit.Power(1), name: "unit.Power"}, {unit: unit.Pressure(1), name: "unit.Pressure"}, {unit: unit.Radioactivity(1), name: "unit.Radioactivity"}, {unit: unit.Resistance(1), name: "unit.Resistance"}, {unit: unit.Temperature(1), name: "unit.Temperature"}, {unit: unit.Time(1), name: "unit.Time"}, {unit: unit.Torque(1), name: "unit.Torque"}, {unit: unit.Velocity(1), name: "unit.Velocity"}, {unit: unit.Voltage(1), name: "unit.Voltage"}, {unit: unit.Volume(1), name: "unit.Volume"}, } func definedEquivalentOf(q unit.Uniter) string { for _, u := range definedTypes { if unit.DimensionsMatch(q, u.unit) { return u.name } } return "" } golang-gonum-v1-gonum-0.14.0/unit/constant/doc.go000066400000000000000000000010171450372207100215410ustar00rootroot00000000000000// Copyright ©2019 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 go run generate_defined_types.go //go:generate go run generate_constants.go defined_types.go // Package constant provides fundamental constants satisfying unit.Uniter. // // Constant values reflect the values published at https://physics.nist.gov/cuu/index.html // and are subject to change when the published values are updated. package constant golang-gonum-v1-gonum-0.14.0/unit/constant/electricconstant.go000066400000000000000000000031111450372207100243350ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // ElectricConstant is the electric constant (ε₀), the value of the absolute dielectric permittivity of classical vacuum. // The dimensions of ElectricConstant are A^2 s^4 kg^-1 m^-3. The standard uncertainty of the constant is 1.3e-21 A^2 s^4 kg^-1 m^-3. const ElectricConstant = electricConstantUnits(8.854187817620389e-12) type electricConstantUnits float64 // Unit converts the electricConstantUnits to a *unit.Unit func (cnst electricConstantUnits) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ unit.CurrentDim: 2, unit.TimeDim: 4, unit.MassDim: -1, unit.LengthDim: -3, }) } func (cnst electricConstantUnits) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.electricConstantUnits=%v A^2 s^4 kg^-1 m^-3)", float64(cnst)) } } golang-gonum-v1-gonum-0.14.0/unit/constant/electricconstant_test.go000066400000000000000000000020101450372207100253710ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func TestElectricConstantFormat(t *testing.T) { t.Parallel() for _, test := range []struct { format string want string }{ {"%v", "8.854187817620389e-12 A^2 s^4 kg^-1 m^-3"}, {"%.1v", "9e-12 A^2 s^4 kg^-1 m^-3"}, {"%50.1v", " 9e-12 A^2 s^4 kg^-1 m^-3"}, {"%50v", " 8.854187817620389e-12 A^2 s^4 kg^-1 m^-3"}, {"%1v", "8.854187817620389e-12 A^2 s^4 kg^-1 m^-3"}, {"%#v", "constant.electricConstantUnits(8.854187817620389e-12)"}, {"%s", "%!s(constant.electricConstantUnits=8.854187817620389e-12 A^2 s^4 kg^-1 m^-3)"}, } { got := fmt.Sprintf(test.format, ElectricConstant) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/elementarycharge.go000066400000000000000000000010571450372207100243170ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import "gonum.org/v1/gonum/unit" // ElementaryCharge, is the elementary charge constant (e), the magnitude of electric charge carried by a single proton or electron. // The dimensions of ElementaryCharge are A s. The constant is exact. const ElementaryCharge = unit.Charge(1.602176634e-19) golang-gonum-v1-gonum-0.14.0/unit/constant/faraday.go000066400000000000000000000025761450372207100224160ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // Faraday is the Faraday constant, the magnitude of electric charge per mole of electrons. // The dimensions of Faraday are A s mol^-1. The constant is exact. const Faraday = faradayUnits(96485.33212) type faradayUnits float64 // Unit converts the faradayUnits to a *unit.Unit func (cnst faradayUnits) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ unit.CurrentDim: 1, unit.TimeDim: 1, unit.MoleDim: -1, }) } func (cnst faradayUnits) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.faradayUnits=%v A s mol^-1)", float64(cnst)) } } golang-gonum-v1-gonum-0.14.0/unit/constant/faraday_test.go000066400000000000000000000016341450372207100234470ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func TestFaradayFormat(t *testing.T) { t.Parallel() for _, test := range []struct { format string want string }{ {"%v", "96485.33212 A s mol^-1"}, {"%.1v", "1e+05 A s mol^-1"}, {"%50.1v", " 1e+05 A s mol^-1"}, {"%50v", " 96485.33212 A s mol^-1"}, {"%1v", "96485.33212 A s mol^-1"}, {"%#v", "constant.faradayUnits(96485.33212)"}, {"%s", "%!s(constant.faradayUnits=96485.33212 A s mol^-1)"}, } { got := fmt.Sprintf(test.format, Faraday) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/finestructure.go000066400000000000000000000010611450372207100236750ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import "gonum.org/v1/gonum/unit" // FineStructure is the fine structure constant (α), it describes the strength of the electromagnetic interaction between elementary charged particles. The standard uncertainty of the constant is 1.1e-12 . const FineStructure = unit.Dimless(0.0072973525693) golang-gonum-v1-gonum-0.14.0/unit/constant/generate_constants.go000066400000000000000000000231621450372207100246670ustar00rootroot00000000000000// 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. //go:build ignore // +build ignore package main import ( "bytes" "go/format" "log" "math" "os" "strings" "text/template" "gonum.org/v1/gonum/unit" ) const ( elementaryCharge = 1.602176634e-19 fineStructure = 7.2973525693e-3 lightSpeed = 2.99792458e8 planck = 6.62607015e-34 ) var constants = []Constant{ { Name: "AtomicMass", Value: 1.66053906660e-27, Dimensions: []Dimension{{massName, 1}}, Comment: "AtomicMass is the atomic mass constant (mᵤ), one twelfth of the mass of an unbound atom of carbon-12 at rest and in its ground state.", Uncertainty: 0.00000000050e-27, }, { Name: "Avogadro", Value: 6.02214076e23, Dimensions: []Dimension{{moleName, -1}}, Comment: "Avogadro is the Avogadro constant (A), the number of constituent particles contained in one mole of a substance.", }, { Name: "Boltzmann", Value: 1.380649e-23, Dimensions: []Dimension{{massName, 1}, {lengthName, 2}, {timeName, -2}, {temperatureName, -1}}, Comment: "Boltzmann is the Boltzmann constant (k), it relates the average relative kinetic energy of particles in a gas with the temperature of the gas.", }, { Name: "ElectricConstant", Value: 1 / (4 * math.Pi * 1e-7 * lightSpeed * lightSpeed), Dimensions: []Dimension{{currentName, 2}, {timeName, 4}, {massName, -1}, {lengthName, -3}}, Comment: "ElectricConstant is the electric constant (ε₀), the value of the absolute dielectric permittivity of classical vacuum.", Uncertainty: 0.0000000013e-12, }, { Name: "ElementaryCharge", Value: elementaryCharge, Dimensions: []Dimension{{currentName, 1}, {timeName, 1}}, Comment: "ElementaryCharge, is the elementary charge constant (e), the magnitude of electric charge carried by a single proton or electron.", }, { Name: "Faraday", Value: 96485.33212, Dimensions: []Dimension{{currentName, 1}, {timeName, 1}, {moleName, -1}}, Comment: "Faraday is the Faraday constant, the magnitude of electric charge per mole of electrons.", }, { Name: "FineStructure", Value: fineStructure, Comment: "FineStructure is the fine structure constant (α), it describes the strength of the electromagnetic interaction between elementary charged particles.", Uncertainty: 0.0000000011e-3, }, { Name: "Gravitational", Value: 6.67430e-11, Dimensions: []Dimension{{massName, -1}, {lengthName, 3}, {timeName, -2}}, Comment: "Gravitational is the universal gravitational constant (G), the proportionality constant connecting the gravitational force between two bodies.", Uncertainty: 0.00015e-11, }, { Name: "LightSpeedInVacuum", Value: lightSpeed, Dimensions: []Dimension{{lengthName, 1}, {timeName, -1}}, Comment: "LightSpeedInVacuum is the c constant, the speed of light in a vacuum.", }, { Name: "MagneticConstant", Value: 2 * fineStructure * planck / (elementaryCharge * elementaryCharge * lightSpeed), Dimensions: []Dimension{{currentName, 2}, {timeName, 4}, {massName, -1}, {lengthName, -3}}, Comment: "MagneticConstant is the magnetic constant (μ₀), the magnetic permeability in a classical vacuum.", Uncertainty: 0.00000000019e-6, }, { Name: "Planck", Value: planck, Dimensions: []Dimension{{massName, 1}, {lengthName, 2}, {timeName, -1}}, Comment: "Planck is the Planck constant (h), it relates the energy carried by a photon to its frequency.", }, { Name: "StandardGravity", Value: 9.80665, Dimensions: []Dimension{{lengthName, 1}, {timeName, -2}}, Comment: "StandardGravity is the standard gravity constant (g₀), the nominal gravitational acceleration of an object in a vacuum near the surface of the Earth", }, } const ( angleName = "AngleDim" currentName = "CurrentDim" lengthName = "LengthDim" luminousIntensityName = "LuminousIntensityDim" massName = "MassDim" moleName = "MoleDim" temperatureName = "TemperatureDim" timeName = "TimeDim" ) var dimOf = map[string]unit.Dimension{ "AngleDim": unit.AngleDim, "CurrentDim": unit.CurrentDim, "LengthDim": unit.LengthDim, "LuminousIntensityDim": unit.LuminousIntensityDim, "MassDim": unit.MassDim, "MoleDim": unit.MoleDim, "TemperatureDim": unit.TemperatureDim, "TimeDim": unit.TimeDim, } type Constant struct { Name string Value float64 Dimensions []Dimension Comment string Uncertainty float64 } type Dimension struct { Name string Power int } func (c Constant) IsDefined() bool { return definedEquivalentOf(unit.New(1, c.dimensions())) != "" } func (c Constant) Type() string { typ := definedEquivalentOf(unit.New(1, c.dimensions())) if typ == "" { return strings.ToLower(c.Name[:1]) + c.Name[1:] + "Units" } return typ } func (c Constant) Units() string { return c.dimensions().String() } func (c Constant) dimensions() unit.Dimensions { dims := make(unit.Dimensions) for _, d := range c.Dimensions { dims[dimOf[d.Name]] = d.Power } return dims } // Generate a file for each of the constants. func main() { for _, c := range constants { generate(c) generateTest(c) } } const baseUnitTemplate = `// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import "gonum.org/v1/gonum/unit" // {{.Comment}}{{if .Dimensions}} // {{$n := len .Dimensions}}The dimension{{if gt $n 1}}s{{end}} of {{.Name}} {{if eq $n 1}}is{{else}}are{{end}} {{.Units}}.{{end}} {{if not .Uncertainty}}The constant is exact.{{else}}The standard uncertainty of the constant is {{.Uncertainty}} {{.Units}}.{{end}} const {{.Name}} = {{.Type}}({{.Value}}) ` var baseUnit = template.Must(template.New("base").Parse(baseUnitTemplate)) const methodTemplate = `// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // {{.Comment}} // {{$n := len .Dimensions}}The dimension{{if gt $n 1}}s{{end}} of {{.Name}} {{if eq $n 1}}is{{else}}are{{end}} {{.Units}}. {{if not .Uncertainty}}The constant is exact.{{else}}The standard uncertainty of the constant is {{.Uncertainty}} {{.Units}}.{{end}} const {{.Name}} = {{.Type}}({{.Value}}) type {{.Type}} float64 // Unit converts the {{.Type}} to a *unit.Unit func (cnst {{.Type}}) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ {{range .Dimensions}} unit.{{.Name}}: {{.Power}}, {{end}} }) } func (cnst {{.Type}}) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.{{.Type}}=%v {{.Units}})", float64(cnst)) } } ` var methods = template.Must(template.New("methods").Parse(methodTemplate)) func generate(c Constant) { lowerName := strings.ToLower(c.Name) filename := lowerName + ".go" f, err := os.Create(filename) if err != nil { log.Fatal(err) } defer f.Close() var buf bytes.Buffer if c.IsDefined() { err = baseUnit.Execute(&buf, c) if err != nil { log.Fatal(err) } } else { err = methods.Execute(&buf, c) if err != nil { log.Fatal(err) } } b, err := format.Source(buf.Bytes()) if err != nil { f.Write(buf.Bytes()) // This is here to debug bad format. log.Fatalf("error formatting %q: %s", c.Name, err) } f.Write(b) } const testTemplate = `// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func Test{{.Name}}Format(t *testing.T) { t.Parallel() for _, test := range []struct{ format string want string }{ {"%v", "{{.Value}} {{.Units}}"}, {"%.1v", "{{printf "%.1v" .Value}} {{.Units}}"}, {"%50.1v", "{{$s := printf "%.1v %s" .Value .Units}}{{printf "%50s" $s}}"}, {"%50v", "{{$s := printf "%v %s" .Value .Units}}{{printf "%50s" $s}}"}, {"%1v", "{{.Value}} {{.Units}}"}, {"%#v", "constant.{{.Type}}({{.Value}})"}, {"%s", "%!s(constant.{{.Type}}={{.Value}} {{.Units}})"}, } { got := fmt.Sprintf(test.format, {{.Name}}) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } ` var tests = template.Must(template.New("test").Parse(testTemplate)) func generateTest(c Constant) { if c.IsDefined() { return } lowerName := strings.ToLower(c.Name) filename := lowerName + "_test.go" f, err := os.Create(filename) if err != nil { log.Fatal(err) } defer f.Close() var buf bytes.Buffer err = tests.Execute(&buf, c) if err != nil { log.Fatal(err) } b, err := format.Source(buf.Bytes()) if err != nil { f.Write(buf.Bytes()) // This is here to debug bad format. log.Fatalf("error formatting test for %q: %s", c.Name, err) } f.Write(b) } golang-gonum-v1-gonum-0.14.0/unit/constant/generate_defined_types.go000066400000000000000000000044011450372207100254700ustar00rootroot00000000000000// Copyright ©2019 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:build ignore // +build ignore package main import ( "bytes" "go/ast" "go/format" "go/parser" "go/token" "log" "os" "path/filepath" "strings" "text/template" ) const definedTemplate = `// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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:build ignore // +build ignore package main import "gonum.org/v1/gonum/unit" var definedTypes = []struct{ unit unit.Uniter name string }{ {{range .}} {unit: unit.{{.}}(1), name: "unit.{{.}}"{{"}"}}, {{end}}} func definedEquivalentOf(q unit.Uniter) string { for _, u := range definedTypes { if unit.DimensionsMatch(q, u.unit) { return u.name } } return "" } ` var defined = template.Must(template.New("defined").Parse(definedTemplate)) func main() { names, err := filepath.Glob("../*.go") if err != nil { log.Fatal(err) } var units []string fset := token.NewFileSet() for _, fn := range names { if strings.Contains(fn, "_test") { continue } b, err := os.ReadFile(fn) if bytes.Contains(b, []byte("+build ignore")) { continue } f, err := parser.ParseFile(fset, fn, nil, 0) if err != nil { log.Fatalf("failed to parse %q: %v", fn, err) // parse error } if f.Name.Name != "unit" { log.Fatalf("not parsing unit package: %q", f.Name.Name) } for _, d := range f.Decls { if decl, ok := d.(*ast.GenDecl); ok { for _, s := range decl.Specs { if ts, ok := s.(*ast.TypeSpec); ok { if id, ok := ts.Type.(*ast.Ident); !ok || id.Name != "float64" { continue } units = append(units, ts.Name.Name) } } } } } f, err := os.Create("defined_types.go") if err != nil { log.Fatal(err) } defer f.Close() var buf bytes.Buffer err = defined.Execute(&buf, units) if err != nil { log.Fatal(err) } b, err := format.Source(buf.Bytes()) if err != nil { f.Write(buf.Bytes()) // This is here to debug bad format. log.Fatalf("error formatting %q: %s", f.Name(), err) } f.Write(b) } golang-gonum-v1-gonum-0.14.0/unit/constant/gravitational.go000066400000000000000000000030261450372207100236420ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // Gravitational is the universal gravitational constant (G), the proportionality constant connecting the gravitational force between two bodies. // The dimensions of Gravitational are m^3 kg^-1 s^-2. The standard uncertainty of the constant is 1.5e-15 m^3 kg^-1 s^-2. const Gravitational = gravitationalUnits(6.6743e-11) type gravitationalUnits float64 // Unit converts the gravitationalUnits to a *unit.Unit func (cnst gravitationalUnits) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ unit.MassDim: -1, unit.LengthDim: 3, unit.TimeDim: -2, }) } func (cnst gravitationalUnits) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.gravitationalUnits=%v m^3 kg^-1 s^-2)", float64(cnst)) } } golang-gonum-v1-gonum-0.14.0/unit/constant/gravitational_test.go000066400000000000000000000017001450372207100246760ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func TestGravitationalFormat(t *testing.T) { t.Parallel() for _, test := range []struct { format string want string }{ {"%v", "6.6743e-11 m^3 kg^-1 s^-2"}, {"%.1v", "7e-11 m^3 kg^-1 s^-2"}, {"%50.1v", " 7e-11 m^3 kg^-1 s^-2"}, {"%50v", " 6.6743e-11 m^3 kg^-1 s^-2"}, {"%1v", "6.6743e-11 m^3 kg^-1 s^-2"}, {"%#v", "constant.gravitationalUnits(6.6743e-11)"}, {"%s", "%!s(constant.gravitationalUnits=6.6743e-11 m^3 kg^-1 s^-2)"}, } { got := fmt.Sprintf(test.format, Gravitational) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/lightspeedinvacuum.go000066400000000000000000000007731450372207100247040ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import "gonum.org/v1/gonum/unit" // LightSpeedInVacuum is the c constant, the speed of light in a vacuum. // The dimensions of LightSpeedInVacuum are m s^-1. The constant is exact. const LightSpeedInVacuum = unit.Velocity(2.99792458e+08) golang-gonum-v1-gonum-0.14.0/unit/constant/magneticconstant.go000066400000000000000000000030641450372207100243410ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // MagneticConstant is the magnetic constant (μ₀), the magnetic permeability in a classical vacuum. // The dimensions of MagneticConstant are A^2 s^4 kg^-1 m^-3. The standard uncertainty of the constant is 1.9e-16 A^2 s^4 kg^-1 m^-3. const MagneticConstant = magneticConstantUnits(1.2566370621238374e-06) type magneticConstantUnits float64 // Unit converts the magneticConstantUnits to a *unit.Unit func (cnst magneticConstantUnits) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ unit.CurrentDim: 2, unit.TimeDim: 4, unit.MassDim: -1, unit.LengthDim: -3, }) } func (cnst magneticConstantUnits) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.magneticConstantUnits=%v A^2 s^4 kg^-1 m^-3)", float64(cnst)) } } golang-gonum-v1-gonum-0.14.0/unit/constant/magneticconstant_test.go000066400000000000000000000020141450372207100253720ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func TestMagneticConstantFormat(t *testing.T) { t.Parallel() for _, test := range []struct { format string want string }{ {"%v", "1.2566370621238374e-06 A^2 s^4 kg^-1 m^-3"}, {"%.1v", "1e-06 A^2 s^4 kg^-1 m^-3"}, {"%50.1v", " 1e-06 A^2 s^4 kg^-1 m^-3"}, {"%50v", " 1.2566370621238374e-06 A^2 s^4 kg^-1 m^-3"}, {"%1v", "1.2566370621238374e-06 A^2 s^4 kg^-1 m^-3"}, {"%#v", "constant.magneticConstantUnits(1.2566370621238374e-06)"}, {"%s", "%!s(constant.magneticConstantUnits=1.2566370621238374e-06 A^2 s^4 kg^-1 m^-3)"}, } { got := fmt.Sprintf(test.format, MagneticConstant) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/planck.go000066400000000000000000000025761450372207100222570ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "gonum.org/v1/gonum/unit" ) // Planck is the Planck constant (h), it relates the energy carried by a photon to its frequency. // The dimensions of Planck are kg m^2 s^-1. The constant is exact. const Planck = planckUnits(6.62607015e-34) type planckUnits float64 // Unit converts the planckUnits to a *unit.Unit func (cnst planckUnits) Unit() *unit.Unit { return unit.New(float64(cnst), unit.Dimensions{ unit.MassDim: 1, unit.LengthDim: 2, unit.TimeDim: -1, }) } func (cnst planckUnits) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) default: fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) } default: fmt.Fprintf(fs, "%%!"+string(c)+"(constant.planckUnits=%v kg m^2 s^-1)", float64(cnst)) } } golang-gonum-v1-gonum-0.14.0/unit/constant/planck_test.go000066400000000000000000000016501450372207100233060ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import ( "fmt" "testing" ) func TestPlanckFormat(t *testing.T) { t.Parallel() for _, test := range []struct { format string want string }{ {"%v", "6.62607015e-34 kg m^2 s^-1"}, {"%.1v", "7e-34 kg m^2 s^-1"}, {"%50.1v", " 7e-34 kg m^2 s^-1"}, {"%50v", " 6.62607015e-34 kg m^2 s^-1"}, {"%1v", "6.62607015e-34 kg m^2 s^-1"}, {"%#v", "constant.planckUnits(6.62607015e-34)"}, {"%s", "%!s(constant.planckUnits=6.62607015e-34 kg m^2 s^-1)"}, } { got := fmt.Sprintf(test.format, Planck) if got != test.want { t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/constant/standardgravity.go000066400000000000000000000011031450372207100241760ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit/constant”; DO NOT EDIT. // Copyright ©2019 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 constant import "gonum.org/v1/gonum/unit" // StandardGravity is the standard gravity constant (g₀), the nominal gravitational acceleration of an object in a vacuum near the surface of the Earth // The dimensions of StandardGravity are m s^-2. The constant is exact. const StandardGravity = unit.Acceleration(9.80665) golang-gonum-v1-gonum-0.14.0/unit/current.go000066400000000000000000000031641450372207100206320ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Current represents a current in Amperes. type Current float64 const Ampere Current = 1 // Unit converts the Current to a *Unit. func (i Current) Unit() *Unit { return New(float64(i), Dimensions{ CurrentDim: 1, }) } // Current allows Current to implement a Currenter interface. func (i Current) Current() Current { return i } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (i *Current) From(u Uniter) error { if !DimensionsMatch(u, Ampere) { *i = Current(math.NaN()) return errors.New("unit: dimension mismatch") } *i = Current(u.Unit().Value()) return nil } func (i Current) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", i, float64(i)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " A" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(i)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(i)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(i)) default: fmt.Fprintf(fs, "%"+string(c), float64(i)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g A)", c, i, float64(i)) } } golang-gonum-v1-gonum-0.14.0/unit/current_test.go000066400000000000000000000027621450372207100216740ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestCurrent(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Current err := got.From(Current(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Current(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Current() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestCurrentFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Current format string want string }{ {1.23456789, "%v", "1.23456789 A"}, {1.23456789, "%.1v", "1 A"}, {1.23456789, "%20.1v", " 1 A"}, {1.23456789, "%20v", " 1.23456789 A"}, {1.23456789, "%1v", "1.23456789 A"}, {1.23456789, "%#v", "unit.Current(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Current=1.23456789 A)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/dimless.go000066400000000000000000000027161450372207100206120ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" ) // Dimless represents a dimensionless constant. type Dimless float64 // Unit converts the Dimless to a *Unit. func (d Dimless) Unit() *Unit { return New(float64(d), Dimensions{}) } // Dimless allows Dimless to implement a Dimlesser interface. func (d Dimless) Dimless() Dimless { return d } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (d *Dimless) From(u Uniter) error { if !DimensionsMatch(u, Dimless(0)) { *d = Dimless(math.NaN()) return errors.New("unit: dimension mismatch") } *d = Dimless(u.Unit().Value()) return nil } func (d Dimless) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", d, float64(d)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, float64(d)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(d)) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, float64(d)) default: fmt.Fprintf(fs, "%"+string(c), float64(d)) } default: fmt.Fprintf(fs, "%%!%c(%T=%g)", c, d, float64(d)) } } golang-gonum-v1-gonum-0.14.0/unit/dimless_test.go000066400000000000000000000027521450372207100216510ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestDimless(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Dimless err := got.From(Dimless(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Dimless(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Dimless() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestDimlessFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Dimless format string want string }{ {1.23456789, "%v", "1.23456789"}, {1.23456789, "%.1v", "1"}, {1.23456789, "%20.1v", " 1"}, {1.23456789, "%20v", " 1.23456789"}, {1.23456789, "%1v", "1.23456789"}, {1.23456789, "%#v", "unit.Dimless(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Dimless=1.23456789)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/doc.go000066400000000000000000000113421450372207100177120ustar00rootroot00000000000000// 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 go run generate_unit.go // Package unit provides a set of types and constants that facilitate // the use of the International System of Units (SI). // // The unit package provides two main functionalities: compile-time type-safe // base SI units and common derived units; and a system for dynamically // extensible user-defined units. // // # Static SI units // // This package provides a number of types representing either an SI base // unit or a common combination of base units, named for the physical quantity // it represents (Length, Mass, Pressure, etc.). Each type is defined from // float64. The value of the float64 represents the quantity of that unit as // expressed in SI base units (kilogram, metre, Pascal, etc.). For example, // // height := 1.6 * unit.Metre // acc := unit.Acceleration(9.8) // // creates a variable named 'height' with a value of 1.6 metres, and // a variable named 'acc' with a value of 9.8 metres per second squared. // These types can be used to add compile-time safety to code. For // example, // // func unitVolume(t unit.Temperature, p unit.Pressure) unit.Volume { // ... // } // // func main(){ // t := 300 * unit.Kelvin // p := 500 * unit.Kilo * unit.Pascal // v := unitVolume(p, t) // compile-time error // } // // gives a compile-time error (temperature type does not match pressure type) // while the corresponding code using float64 runs without error. // // func float64Volume(temperature, pressure float64) float64 { // ... // } // // func main(){ // t := 300.0 // Kelvin // p := 500000.0 // Pascals // v := float64Volume(p, t) // no error // } // // Many types have constants defined representing named SI units (Metre, // Kilogram, etc. ) or SI derived units (Pascal, Hz, etc.). The unit package // additionally provides untyped constants for SI prefixes, so the following // are all equivalent. // // l := 0.001 * unit.Metre // k := 1 * unit.Milli * unit.Metre // j := unit.Length(0.001) // // Additional SI-derived static units can also be defined by adding types that // satisfy the Uniter interface described below. // // # Dynamic user-extensible unit system // // The unit package also provides the Unit type, a representation of a general // dimensional value. Unit can be used to help prevent errors of dimensionality // when multiplying or dividing dimensional numbers defined at run time. New // variables of type Unit can be created with the New function and the // Dimensions map. For example, the code // // rate := unit.New(1 * unit.Milli, Dimensions{MoleDim: 1, TimeDim: -1}) // // creates a variable "rate" which has a value of 1e-3 mol/s. Methods of // unit can be used to modify this value, for example: // // rate.Mul(1 * unit.Centi * unit.Metre).Div(1 * unit.Milli * unit.Volt) // // To convert the unit back into a typed float64 value, the From methods // of the dimensional types should be used. From will return an error if the // dimensions do not match. // // var energy unit.Energy // err := energy.From(acc) // // Domain-specific problems may need custom dimensions, and for this purpose // NewDimension should be used to help avoid accidental overlap between // packages. For example, results from a blood test may be measured in // "White blood cells per slide". In this case, NewDimension should be // used to create a 'WhiteBloodCell' dimension. NewDimension takes in a // string which will be used for printing that dimension, and will return // a unique dimension number. // // wbc := unit.NewDimension("WhiteBloodCell") // // NewDimension should not be used, however, to create the unit of 'Slide', // because in this case slide is just a measurement of liquid volume. Instead, // a constant could be defined. // // const Slide unit.Volume = 0.1 * unit.Micro * unit.Litre // // Note that unit cannot catch all errors related to dimensionality. // Different physical ideas are sometimes expressed with the same dimensions // and unit is incapable of catching these mismatches. For example, energy and // torque are both expressed as force times distance (Newton-metres in SI), // but it is wrong to say that a torque of 10 N·m is the same as 10 J, even // though the dimensions agree. Despite this, using the defined types to // represent units can help to catch errors at compile-time. For example, // using unit.Torque allows you to define a statically typed function like so // // func LeverLength(apply unit.Force, want unit.Torque) unit.Length { // return unit.Length(float64(want)/float64(apply)) // } // // This will prevent an energy value being provided to LeverLength in place // of a torque value. package unit // import "gonum.org/v1/gonum/unit" golang-gonum-v1-gonum-0.14.0/unit/energy.go000066400000000000000000000032151450372207100204360ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Energy represents a quantity of energy in Joules. type Energy float64 const Joule Energy = 1 // Unit converts the Energy to a *Unit. func (e Energy) Unit() *Unit { return New(float64(e), Dimensions{ LengthDim: 2, MassDim: 1, TimeDim: -2, }) } // Energy allows Energy to implement a Energyer interface. func (e Energy) Energy() Energy { return e } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (e *Energy) From(u Uniter) error { if !DimensionsMatch(u, Joule) { *e = Energy(math.NaN()) return errors.New("unit: dimension mismatch") } *e = Energy(u.Unit().Value()) return nil } func (e Energy) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", e, float64(e)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " J" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(e)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(e)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(e)) default: fmt.Fprintf(fs, "%"+string(c), float64(e)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g J)", c, e, float64(e)) } } golang-gonum-v1-gonum-0.14.0/unit/energy_test.go000066400000000000000000000027511450372207100215010ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestEnergy(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Energy err := got.From(Energy(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Energy(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Energy() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestEnergyFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Energy format string want string }{ {1.23456789, "%v", "1.23456789 J"}, {1.23456789, "%.1v", "1 J"}, {1.23456789, "%20.1v", " 1 J"}, {1.23456789, "%20v", " 1.23456789 J"}, {1.23456789, "%1v", "1.23456789 J"}, {1.23456789, "%#v", "unit.Energy(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Energy=1.23456789 J)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/equivalentradioactivedose.go000066400000000000000000000036701450372207100244150ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // EquivalentRadioactiveDose is a measure of equivalent dose of ionizing radiation in sieverts. type EquivalentRadioactiveDose float64 const Sievert EquivalentRadioactiveDose = 1 // Unit converts the EquivalentRadioactiveDose to a *Unit. func (a EquivalentRadioactiveDose) Unit() *Unit { return New(float64(a), Dimensions{ LengthDim: 2, TimeDim: -2, }) } // EquivalentRadioactiveDose allows EquivalentRadioactiveDose to implement a EquivalentRadioactiveDoseer interface. func (a EquivalentRadioactiveDose) EquivalentRadioactiveDose() EquivalentRadioactiveDose { return a } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (a *EquivalentRadioactiveDose) From(u Uniter) error { if !DimensionsMatch(u, Sievert) { *a = EquivalentRadioactiveDose(math.NaN()) return errors.New("unit: dimension mismatch") } *a = EquivalentRadioactiveDose(u.Unit().Value()) return nil } func (a EquivalentRadioactiveDose) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", a, float64(a)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " Sy" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(a)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(a)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(a)) default: fmt.Fprintf(fs, "%"+string(c), float64(a)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g Sy)", c, a, float64(a)) } } golang-gonum-v1-gonum-0.14.0/unit/equivalentradioactivedose_test.go000066400000000000000000000032301450372207100254440ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestEquivalentRadioactiveDose(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got EquivalentRadioactiveDose err := got.From(EquivalentRadioactiveDose(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != EquivalentRadioactiveDose(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.EquivalentRadioactiveDose() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestEquivalentRadioactiveDoseFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value EquivalentRadioactiveDose format string want string }{ {1.23456789, "%v", "1.23456789 Sy"}, {1.23456789, "%.1v", "1 Sy"}, {1.23456789, "%20.1v", " 1 Sy"}, {1.23456789, "%20v", " 1.23456789 Sy"}, {1.23456789, "%1v", "1.23456789 Sy"}, {1.23456789, "%#v", "unit.EquivalentRadioactiveDose(1.23456789)"}, {1.23456789, "%s", "%!s(unit.EquivalentRadioactiveDose=1.23456789 Sy)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/force.go000066400000000000000000000031631450372207100202450ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Force represents a force in Newtons. type Force float64 const Newton Force = 1 // Unit converts the Force to a *Unit. func (f Force) Unit() *Unit { return New(float64(f), Dimensions{ LengthDim: 1, MassDim: 1, TimeDim: -2, }) } // Force allows Force to implement a Forcer interface. func (f Force) Force() Force { return f } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (f *Force) From(u Uniter) error { if !DimensionsMatch(u, Newton) { *f = Force(math.NaN()) return errors.New("unit: dimension mismatch") } *f = Force(u.Unit().Value()) return nil } func (f Force) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", f, float64(f)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " N" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(f)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(f)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(f)) default: fmt.Fprintf(fs, "%"+string(c), float64(f)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g N)", c, f, float64(f)) } } golang-gonum-v1-gonum-0.14.0/unit/force_test.go000066400000000000000000000027401450372207100213040ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestForce(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Force err := got.From(Force(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Force(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Force() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestForceFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Force format string want string }{ {1.23456789, "%v", "1.23456789 N"}, {1.23456789, "%.1v", "1 N"}, {1.23456789, "%20.1v", " 1 N"}, {1.23456789, "%20v", " 1.23456789 N"}, {1.23456789, "%1v", "1.23456789 N"}, {1.23456789, "%#v", "unit.Force(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Force=1.23456789 N)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/frequency.go000066400000000000000000000032201450372207100211420ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Frequency represents a frequency in Hertz. type Frequency float64 const Hertz Frequency = 1 // Unit converts the Frequency to a *Unit. func (f Frequency) Unit() *Unit { return New(float64(f), Dimensions{ TimeDim: -1, }) } // Frequency allows Frequency to implement a Frequencyer interface. func (f Frequency) Frequency() Frequency { return f } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (f *Frequency) From(u Uniter) error { if !DimensionsMatch(u, Hertz) { *f = Frequency(math.NaN()) return errors.New("unit: dimension mismatch") } *f = Frequency(u.Unit().Value()) return nil } func (f Frequency) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", f, float64(f)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " Hz" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(f)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(f)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(f)) default: fmt.Fprintf(fs, "%"+string(c), float64(f)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g Hz)", c, f, float64(f)) } } golang-gonum-v1-gonum-0.14.0/unit/frequency_test.go000066400000000000000000000030101450372207100221760ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestFrequency(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Frequency err := got.From(Frequency(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Frequency(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Frequency() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestFrequencyFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Frequency format string want string }{ {1.23456789, "%v", "1.23456789 Hz"}, {1.23456789, "%.1v", "1 Hz"}, {1.23456789, "%20.1v", " 1 Hz"}, {1.23456789, "%20v", " 1.23456789 Hz"}, {1.23456789, "%1v", "1.23456789 Hz"}, {1.23456789, "%#v", "unit.Frequency(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Frequency=1.23456789 Hz)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/generate_unit.go000066400000000000000000000415321450372207100220020ustar00rootroot00000000000000// 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. //go:build ignore // +build ignore package main import ( "bytes" "go/format" "log" "os" "strings" "text/template" "gonum.org/v1/gonum/unit" ) type Unit struct { DimensionName string Receiver string PowerOffset int // from normal (for example, mass base unit is kg, not g) PrintString string // print string for the unit (kg for mass) ExtraConstant []Constant Name string TypeComment string // text to comment the type Dimensions []Dimension ErForm string // for Xxxer interface } type Dimension struct { Name string Power int } func (u Unit) Units() string { dims := make(unit.Dimensions) for _, d := range u.Dimensions { dims[dimOf[d.Name]] = d.Power } return dims.String() } const ( AngleName string = "AngleDim" CurrentName string = "CurrentDim" LengthName string = "LengthDim" LuminousIntensityName string = "LuminousIntensityDim" MassName string = "MassDim" MoleName string = "MoleDim" TemperatureName string = "TemperatureDim" TimeName string = "TimeDim" ) var dimOf = map[string]unit.Dimension{ "AngleDim": unit.AngleDim, "CurrentDim": unit.CurrentDim, "LengthDim": unit.LengthDim, "LuminousIntensityDim": unit.LuminousIntensityDim, "MassDim": unit.MassDim, "MoleDim": unit.MoleDim, "TemperatureDim": unit.TemperatureDim, "TimeDim": unit.TimeDim, } type Constant struct { Name string Value string } type Prefix struct { Name string Power int } var Units = []Unit{ // Base units. { DimensionName: "Dimless", Receiver: "d", TypeComment: "Dimless represents a dimensionless constant", Dimensions: []Dimension{}, }, { DimensionName: "Angle", Receiver: "a", PrintString: "rad", Name: "Rad", TypeComment: "Angle represents an angle in radians", Dimensions: []Dimension{ {Name: AngleName, Power: 1}, }, }, { DimensionName: "Current", Receiver: "i", PrintString: "A", Name: "Ampere", TypeComment: "Current represents a current in Amperes", Dimensions: []Dimension{ {Name: CurrentName, Power: 1}, }, }, { DimensionName: "Length", Receiver: "l", PrintString: "m", Name: "Metre", TypeComment: "Length represents a length in metres", Dimensions: []Dimension{ {Name: LengthName, Power: 1}, }, }, { DimensionName: "LuminousIntensity", Receiver: "j", PrintString: "cd", Name: "Candela", TypeComment: "Candela represents a luminous intensity in candela", Dimensions: []Dimension{ {Name: LuminousIntensityName, Power: 1}, }, }, { DimensionName: "Mass", Receiver: "m", PowerOffset: -3, PrintString: "kg", Name: "Gram", TypeComment: "Mass represents a mass in kilograms", ExtraConstant: []Constant{ {Name: "Kilogram", Value: "Kilo * Gram"}, }, Dimensions: []Dimension{ {Name: MassName, Power: 1}, }, }, { DimensionName: "Mole", Receiver: "n", PrintString: "mol", Name: "Mol", TypeComment: "Mole represents an amount in moles", Dimensions: []Dimension{ {Name: MoleName, Power: 1}, }, }, { DimensionName: "Temperature", Receiver: "t", PrintString: "K", Name: "Kelvin", TypeComment: "Temperature represents a temperature in Kelvin", Dimensions: []Dimension{ {Name: TemperatureName, Power: 1}, }, ErForm: "Temperaturer", }, { DimensionName: "Time", Receiver: "t", PrintString: "s", Name: "Second", TypeComment: "Time represents a duration in seconds", ExtraConstant: []Constant{ {Name: "Minute", Value: "60 * Second"}, {Name: "Hour", Value: "60 * Minute"}, }, Dimensions: []Dimension{ {Name: TimeName, Power: 1}, }, ErForm: "Timer", }, // Derived units. { DimensionName: "AbsorbedRadioactiveDose", Receiver: "a", PrintString: "Gy", Name: "Gray", TypeComment: "AbsorbedRadioactiveDose is a measure of absorbed dose of ionizing radiation in grays", Dimensions: []Dimension{ {Name: LengthName, Power: 2}, {Name: TimeName, Power: -2}, }, }, { DimensionName: "Acceleration", Receiver: "a", PrintString: "m s^-2", TypeComment: "Acceleration represents an acceleration in metres per second squared", Dimensions: []Dimension{ {Name: LengthName, Power: 1}, {Name: TimeName, Power: -2}, }, }, { DimensionName: "Area", Receiver: "a", PrintString: "m^2", TypeComment: "Area represents an area in square metres", Dimensions: []Dimension{ {Name: LengthName, Power: 2}, }, }, { DimensionName: "Radioactivity", Receiver: "r", PrintString: "Bq", Name: "Becquerel", TypeComment: "Radioactivity represents a rate of radioactive decay in becquerels", Dimensions: []Dimension{ {Name: TimeName, Power: -1}, }, }, { DimensionName: "Capacitance", Receiver: "cp", PrintString: "F", Name: "Farad", TypeComment: "Capacitance represents an electrical capacitance in Farads", Dimensions: []Dimension{ {Name: CurrentName, Power: 2}, {Name: LengthName, Power: -2}, {Name: MassName, Power: -1}, {Name: TimeName, Power: 4}, }, ErForm: "Capacitancer", }, { DimensionName: "Charge", Receiver: "ch", PrintString: "C", Name: "Coulomb", TypeComment: "Charge represents an electric charge in Coulombs", Dimensions: []Dimension{ {Name: CurrentName, Power: 1}, {Name: TimeName, Power: 1}, }, ErForm: "Charger", }, { DimensionName: "Conductance", Receiver: "co", PrintString: "S", Name: "Siemens", TypeComment: "Conductance represents an electrical conductance in Siemens", Dimensions: []Dimension{ {Name: CurrentName, Power: 2}, {Name: LengthName, Power: -2}, {Name: MassName, Power: -1}, {Name: TimeName, Power: 3}, }, ErForm: "Conductancer", }, { DimensionName: "EquivalentRadioactiveDose", Receiver: "a", PrintString: "Sy", Name: "Sievert", TypeComment: "EquivalentRadioactiveDose is a measure of equivalent dose of ionizing radiation in sieverts", Dimensions: []Dimension{ {Name: LengthName, Power: 2}, {Name: TimeName, Power: -2}, }, }, { DimensionName: "Energy", Receiver: "e", PrintString: "J", Name: "Joule", TypeComment: "Energy represents a quantity of energy in Joules", Dimensions: []Dimension{ {Name: LengthName, Power: 2}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -2}, }, }, { DimensionName: "Frequency", Receiver: "f", PrintString: "Hz", Name: "Hertz", TypeComment: "Frequency represents a frequency in Hertz", Dimensions: []Dimension{ {Name: TimeName, Power: -1}, }, }, { DimensionName: "Force", Receiver: "f", PrintString: "N", Name: "Newton", TypeComment: "Force represents a force in Newtons", Dimensions: []Dimension{ {Name: LengthName, Power: 1}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -2}, }, ErForm: "Forcer", }, { DimensionName: "Inductance", Receiver: "i", PrintString: "H", Name: "Henry", TypeComment: "Inductance represents an electrical inductance in Henry", Dimensions: []Dimension{ {Name: CurrentName, Power: -2}, {Name: LengthName, Power: 2}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -2}, }, ErForm: "Inductancer", }, { DimensionName: "Power", Receiver: "pw", PrintString: "W", Name: "Watt", TypeComment: "Power represents a power in Watts", Dimensions: []Dimension{ {Name: LengthName, Power: 2}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -3}, }, }, { DimensionName: "Resistance", Receiver: "r", PrintString: "Ω", Name: "Ohm", TypeComment: "Resistance represents an electrical resistance, impedance or reactance in Ohms", Dimensions: []Dimension{ {Name: CurrentName, Power: -2}, {Name: LengthName, Power: 2}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -3}, }, ErForm: "Resistancer", }, { DimensionName: "MagneticFlux", Receiver: "m", PrintString: "Wb", Name: "Weber", TypeComment: "MagneticFlux represents a magnetic flux in Weber", Dimensions: []Dimension{ {Name: CurrentName, Power: -1}, {Name: LengthName, Power: 2}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -2}, }, }, { DimensionName: "MagneticFluxDensity", Receiver: "m", PrintString: "T", Name: "Tesla", TypeComment: "MagneticFluxDensity represents a magnetic flux density in Tesla", Dimensions: []Dimension{ {Name: CurrentName, Power: -1}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -2}, }, }, { DimensionName: "Pressure", Receiver: "pr", PrintString: "Pa", Name: "Pascal", TypeComment: "Pressure represents a pressure in Pascals", Dimensions: []Dimension{ {Name: LengthName, Power: -1}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -2}, }, ErForm: "Pressurer", }, { DimensionName: "Torque", Receiver: "t", PrintString: "N m", Name: "Newtonmetre", TypeComment: "Torque represents a torque in Newton metres", Dimensions: []Dimension{ {Name: LengthName, Power: 2}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -2}, }, ErForm: "Torquer", }, { DimensionName: "Velocity", Receiver: "v", PrintString: "m s^-1", TypeComment: "Velocity represents a velocity in metres per second", Dimensions: []Dimension{ {Name: LengthName, Power: 1}, {Name: TimeName, Power: -1}, }, }, { DimensionName: "Voltage", Receiver: "v", PrintString: "V", Name: "Volt", TypeComment: "Voltage represents a voltage in Volts", Dimensions: []Dimension{ {Name: CurrentName, Power: -1}, {Name: LengthName, Power: 2}, {Name: MassName, Power: 1}, {Name: TimeName, Power: -3}, }, ErForm: "Voltager", }, { DimensionName: "Volume", Receiver: "v", PowerOffset: -3, PrintString: "m^3", Name: "Litre", TypeComment: "Volume represents a volume in cubic metres", Dimensions: []Dimension{ {Name: LengthName, Power: 3}, }, }, } // Generate generates a file for each of the units func main() { for _, unit := range Units { generate(unit) generateTest(unit) } } const headerTemplate = `// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" {{if .PrintString}}"unicode/utf8"{{end}} ) // {{.TypeComment}}. type {{.DimensionName}} float64 ` var header = template.Must(template.New("header").Parse(headerTemplate)) const constTemplate = ` const {{if .ExtraConstant}}({{end}} {{.Name}} {{.DimensionName}} = {{if .PowerOffset}} 1e{{.PowerOffset}} {{else}} 1 {{end}} {{$name := .Name}} {{range .ExtraConstant}} {{.Name}} = {{.Value}} {{end}} {{if .ExtraConstant}}){{end}} ` var prefix = template.Must(template.New("prefix").Parse(constTemplate)) const methodTemplate = ` // Unit converts the {{.DimensionName}} to a *Unit. func ({{.Receiver}} {{.DimensionName}}) Unit() *Unit { return New(float64({{.Receiver}}), Dimensions{ {{range .Dimensions}} {{.Name}}: {{.Power}}, {{end}} }) } // {{.DimensionName}} allows {{.DimensionName}} to implement a {{if .ErForm}}{{.ErForm}}{{else}}{{.DimensionName}}er{{end}} interface. func ({{.Receiver}} {{.DimensionName}}) {{.DimensionName}}() {{.DimensionName}} { return {{.Receiver}} } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func ({{.Receiver}} *{{.DimensionName}}) From(u Uniter) error { if !DimensionsMatch(u, {{if .Name}}{{.Name}}{{else}}{{.DimensionName}}(0){{end}}){ *{{.Receiver}} = {{.DimensionName}}(math.NaN()) return errors.New("unit: dimension mismatch") } *{{.Receiver}} = {{.DimensionName}}(u.Unit().Value()) return nil } ` var methods = template.Must(template.New("methods").Parse(methodTemplate)) const formatTemplate = ` func ({{.Receiver}} {{.DimensionName}}) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", {{.Receiver}}, float64({{.Receiver}})) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() {{if .PrintString}}const unit = " {{.PrintString}}" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64({{.Receiver}})) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64({{.Receiver}})) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64({{.Receiver}})) default: fmt.Fprintf(fs, "%"+string(c), float64({{.Receiver}})) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g {{.PrintString}})", c, {{.Receiver}}, float64({{.Receiver}})) {{else}} switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), w, p, float64({{.Receiver}})) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64({{.Receiver}})) case wOk: fmt.Fprintf(fs, "%*"+string(c), w, float64({{.Receiver}})) default: fmt.Fprintf(fs, "%"+string(c), float64({{.Receiver}})) } default: fmt.Fprintf(fs, "%%!%c(%T=%g)", c, {{.Receiver}}, float64({{.Receiver}})) {{end}} } } ` var form = template.Must(template.New("format").Parse(formatTemplate)) func generate(unit Unit) { lowerName := strings.ToLower(unit.DimensionName) filename := lowerName + ".go" f, err := os.Create(filename) if err != nil { log.Fatal(err) } defer f.Close() var buf bytes.Buffer err = header.Execute(&buf, unit) if err != nil { log.Fatal(err) } if unit.Name != "" { err = prefix.Execute(&buf, unit) if err != nil { log.Fatal(err) } } err = methods.Execute(&buf, unit) if err != nil { log.Fatal(err) } err = form.Execute(&buf, unit) if err != nil { log.Fatal(err) } b, err := format.Source(buf.Bytes()) if err != nil { f.Write(buf.Bytes()) // This is here to debug bad format log.Fatalf("error formatting %q: %s", unit.DimensionName, err) } f.Write(b) } const testTemplate = `// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func Test{{.DimensionName}}(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got {{.DimensionName}} err := got.From({{.DimensionName}}(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != {{.DimensionName}}(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.{{.DimensionName}}() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func Test{{.DimensionName}}Format(t *testing.T) { t.Parallel() for _, test := range []struct{ value {{.DimensionName}} format string want string }{ {1.23456789, "%v", "1.23456789{{with .PrintString}} {{.}}{{end}}"}, {1.23456789, "%.1v", "1{{with .PrintString}} {{.}}{{end}}"}, {1.23456789, "%20.1v", "{{if .PrintString}}{{$s := printf "1 %s" .PrintString}}{{printf "%20s" $s}}{{else}}{{printf "%20s" "1"}}{{end}}"}, {1.23456789, "%20v", "{{if .PrintString}}{{$s := printf "1.23456789 %s" .PrintString}}{{printf "%20s" $s}}{{else}}{{printf "%20s" "1.23456789"}}{{end}}"}, {1.23456789, "%1v", "1.23456789{{with .PrintString}} {{.}}{{end}}"}, {1.23456789, "%#v", "unit.{{.DimensionName}}(1.23456789)"}, {1.23456789, "%s", "%!s(unit.{{.DimensionName}}=1.23456789{{with .PrintString}} {{.}}{{end}})"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } ` var tests = template.Must(template.New("test").Parse(testTemplate)) func generateTest(unit Unit) { lowerName := strings.ToLower(unit.DimensionName) filename := lowerName + "_test.go" f, err := os.Create(filename) if err != nil { log.Fatal(err) } defer f.Close() var buf bytes.Buffer err = tests.Execute(&buf, unit) if err != nil { log.Fatal(err) } b, err := format.Source(buf.Bytes()) if err != nil { f.Write(buf.Bytes()) // This is here to debug bad format. log.Fatalf("error formatting test for %q: %s", unit.DimensionName, err) } f.Write(b) } golang-gonum-v1-gonum-0.14.0/unit/inductance.go000066400000000000000000000033401450372207100212610ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Inductance represents an electrical inductance in Henry. type Inductance float64 const Henry Inductance = 1 // Unit converts the Inductance to a *Unit. func (i Inductance) Unit() *Unit { return New(float64(i), Dimensions{ CurrentDim: -2, LengthDim: 2, MassDim: 1, TimeDim: -2, }) } // Inductance allows Inductance to implement a Inductancer interface. func (i Inductance) Inductance() Inductance { return i } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (i *Inductance) From(u Uniter) error { if !DimensionsMatch(u, Henry) { *i = Inductance(math.NaN()) return errors.New("unit: dimension mismatch") } *i = Inductance(u.Unit().Value()) return nil } func (i Inductance) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", i, float64(i)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " H" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(i)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(i)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(i)) default: fmt.Fprintf(fs, "%"+string(c), float64(i)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g H)", c, i, float64(i)) } } golang-gonum-v1-gonum-0.14.0/unit/inductance_test.go000066400000000000000000000030151450372207100223170ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestInductance(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Inductance err := got.From(Inductance(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Inductance(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Inductance() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestInductanceFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Inductance format string want string }{ {1.23456789, "%v", "1.23456789 H"}, {1.23456789, "%.1v", "1 H"}, {1.23456789, "%20.1v", " 1 H"}, {1.23456789, "%20v", " 1.23456789 H"}, {1.23456789, "%1v", "1.23456789 H"}, {1.23456789, "%#v", "unit.Inductance(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Inductance=1.23456789 H)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/length.go000066400000000000000000000031401450372207100204230ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Length represents a length in metres. type Length float64 const Metre Length = 1 // Unit converts the Length to a *Unit. func (l Length) Unit() *Unit { return New(float64(l), Dimensions{ LengthDim: 1, }) } // Length allows Length to implement a Lengther interface. func (l Length) Length() Length { return l } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (l *Length) From(u Uniter) error { if !DimensionsMatch(u, Metre) { *l = Length(math.NaN()) return errors.New("unit: dimension mismatch") } *l = Length(u.Unit().Value()) return nil } func (l Length) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", l, float64(l)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " m" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(l)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(l)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(l)) default: fmt.Fprintf(fs, "%"+string(c), float64(l)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g m)", c, l, float64(l)) } } golang-gonum-v1-gonum-0.14.0/unit/length_test.go000066400000000000000000000027511450372207100214710ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestLength(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Length err := got.From(Length(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Length(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Length() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestLengthFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Length format string want string }{ {1.23456789, "%v", "1.23456789 m"}, {1.23456789, "%.1v", "1 m"}, {1.23456789, "%20.1v", " 1 m"}, {1.23456789, "%20v", " 1.23456789 m"}, {1.23456789, "%1v", "1.23456789 m"}, {1.23456789, "%#v", "unit.Length(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Length=1.23456789 m)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/luminousintensity.go000066400000000000000000000034311450372207100227670ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Candela represents a luminous intensity in candela. type LuminousIntensity float64 const Candela LuminousIntensity = 1 // Unit converts the LuminousIntensity to a *Unit. func (j LuminousIntensity) Unit() *Unit { return New(float64(j), Dimensions{ LuminousIntensityDim: 1, }) } // LuminousIntensity allows LuminousIntensity to implement a LuminousIntensityer interface. func (j LuminousIntensity) LuminousIntensity() LuminousIntensity { return j } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (j *LuminousIntensity) From(u Uniter) error { if !DimensionsMatch(u, Candela) { *j = LuminousIntensity(math.NaN()) return errors.New("unit: dimension mismatch") } *j = LuminousIntensity(u.Unit().Value()) return nil } func (j LuminousIntensity) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", j, float64(j)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " cd" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(j)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(j)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(j)) default: fmt.Fprintf(fs, "%"+string(c), float64(j)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g cd)", c, j, float64(j)) } } golang-gonum-v1-gonum-0.14.0/unit/luminousintensity_test.go000066400000000000000000000031201450372207100240210ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestLuminousIntensity(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got LuminousIntensity err := got.From(LuminousIntensity(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != LuminousIntensity(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.LuminousIntensity() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestLuminousIntensityFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value LuminousIntensity format string want string }{ {1.23456789, "%v", "1.23456789 cd"}, {1.23456789, "%.1v", "1 cd"}, {1.23456789, "%20.1v", " 1 cd"}, {1.23456789, "%20v", " 1.23456789 cd"}, {1.23456789, "%1v", "1.23456789 cd"}, {1.23456789, "%#v", "unit.LuminousIntensity(1.23456789)"}, {1.23456789, "%s", "%!s(unit.LuminousIntensity=1.23456789 cd)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/magneticflux.go000066400000000000000000000033701450372207100216350ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // MagneticFlux represents a magnetic flux in Weber. type MagneticFlux float64 const Weber MagneticFlux = 1 // Unit converts the MagneticFlux to a *Unit. func (m MagneticFlux) Unit() *Unit { return New(float64(m), Dimensions{ CurrentDim: -1, LengthDim: 2, MassDim: 1, TimeDim: -2, }) } // MagneticFlux allows MagneticFlux to implement a MagneticFluxer interface. func (m MagneticFlux) MagneticFlux() MagneticFlux { return m } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (m *MagneticFlux) From(u Uniter) error { if !DimensionsMatch(u, Weber) { *m = MagneticFlux(math.NaN()) return errors.New("unit: dimension mismatch") } *m = MagneticFlux(u.Unit().Value()) return nil } func (m MagneticFlux) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", m, float64(m)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " Wb" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(m)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(m)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(m)) default: fmt.Fprintf(fs, "%"+string(c), float64(m)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g Wb)", c, m, float64(m)) } } golang-gonum-v1-gonum-0.14.0/unit/magneticflux_test.go000066400000000000000000000030431450372207100226710ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestMagneticFlux(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got MagneticFlux err := got.From(MagneticFlux(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != MagneticFlux(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.MagneticFlux() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestMagneticFluxFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value MagneticFlux format string want string }{ {1.23456789, "%v", "1.23456789 Wb"}, {1.23456789, "%.1v", "1 Wb"}, {1.23456789, "%20.1v", " 1 Wb"}, {1.23456789, "%20v", " 1.23456789 Wb"}, {1.23456789, "%1v", "1.23456789 Wb"}, {1.23456789, "%#v", "unit.MagneticFlux(1.23456789)"}, {1.23456789, "%s", "%!s(unit.MagneticFlux=1.23456789 Wb)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/magneticfluxdensity.go000066400000000000000000000035261450372207100232400ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // MagneticFluxDensity represents a magnetic flux density in Tesla. type MagneticFluxDensity float64 const Tesla MagneticFluxDensity = 1 // Unit converts the MagneticFluxDensity to a *Unit. func (m MagneticFluxDensity) Unit() *Unit { return New(float64(m), Dimensions{ CurrentDim: -1, MassDim: 1, TimeDim: -2, }) } // MagneticFluxDensity allows MagneticFluxDensity to implement a MagneticFluxDensityer interface. func (m MagneticFluxDensity) MagneticFluxDensity() MagneticFluxDensity { return m } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (m *MagneticFluxDensity) From(u Uniter) error { if !DimensionsMatch(u, Tesla) { *m = MagneticFluxDensity(math.NaN()) return errors.New("unit: dimension mismatch") } *m = MagneticFluxDensity(u.Unit().Value()) return nil } func (m MagneticFluxDensity) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", m, float64(m)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " T" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(m)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(m)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(m)) default: fmt.Fprintf(fs, "%"+string(c), float64(m)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g T)", c, m, float64(m)) } } golang-gonum-v1-gonum-0.14.0/unit/magneticfluxdensity_test.go000066400000000000000000000031361450372207100242740ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestMagneticFluxDensity(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got MagneticFluxDensity err := got.From(MagneticFluxDensity(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != MagneticFluxDensity(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.MagneticFluxDensity() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestMagneticFluxDensityFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value MagneticFluxDensity format string want string }{ {1.23456789, "%v", "1.23456789 T"}, {1.23456789, "%.1v", "1 T"}, {1.23456789, "%20.1v", " 1 T"}, {1.23456789, "%20v", " 1.23456789 T"}, {1.23456789, "%1v", "1.23456789 T"}, {1.23456789, "%#v", "unit.MagneticFluxDensity(1.23456789)"}, {1.23456789, "%s", "%!s(unit.MagneticFluxDensity=1.23456789 T)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/mass.go000066400000000000000000000031421450372207100201070ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Mass represents a mass in kilograms. type Mass float64 const ( Gram Mass = 1e-3 Kilogram = Kilo * Gram ) // Unit converts the Mass to a *Unit. func (m Mass) Unit() *Unit { return New(float64(m), Dimensions{ MassDim: 1, }) } // Mass allows Mass to implement a Masser interface. func (m Mass) Mass() Mass { return m } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (m *Mass) From(u Uniter) error { if !DimensionsMatch(u, Gram) { *m = Mass(math.NaN()) return errors.New("unit: dimension mismatch") } *m = Mass(u.Unit().Value()) return nil } func (m Mass) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", m, float64(m)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " kg" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(m)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(m)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(m)) default: fmt.Fprintf(fs, "%"+string(c), float64(m)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g kg)", c, m, float64(m)) } } golang-gonum-v1-gonum-0.14.0/unit/mass_test.go000066400000000000000000000027331450372207100211530ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestMass(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Mass err := got.From(Mass(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Mass(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Mass() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestMassFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Mass format string want string }{ {1.23456789, "%v", "1.23456789 kg"}, {1.23456789, "%.1v", "1 kg"}, {1.23456789, "%20.1v", " 1 kg"}, {1.23456789, "%20v", " 1.23456789 kg"}, {1.23456789, "%1v", "1.23456789 kg"}, {1.23456789, "%#v", "unit.Mass(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Mass=1.23456789 kg)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/mole.go000066400000000000000000000031001450372207100200720ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Mole represents an amount in moles. type Mole float64 const Mol Mole = 1 // Unit converts the Mole to a *Unit. func (n Mole) Unit() *Unit { return New(float64(n), Dimensions{ MoleDim: 1, }) } // Mole allows Mole to implement a Moleer interface. func (n Mole) Mole() Mole { return n } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (n *Mole) From(u Uniter) error { if !DimensionsMatch(u, Mol) { *n = Mole(math.NaN()) return errors.New("unit: dimension mismatch") } *n = Mole(u.Unit().Value()) return nil } func (n Mole) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", n, float64(n)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " mol" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(n)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(n)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(n)) default: fmt.Fprintf(fs, "%"+string(c), float64(n)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g mol)", c, n, float64(n)) } } golang-gonum-v1-gonum-0.14.0/unit/mole_test.go000066400000000000000000000027371450372207100211500ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestMole(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Mole err := got.From(Mole(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Mole(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Mole() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestMoleFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Mole format string want string }{ {1.23456789, "%v", "1.23456789 mol"}, {1.23456789, "%.1v", "1 mol"}, {1.23456789, "%20.1v", " 1 mol"}, {1.23456789, "%20v", " 1.23456789 mol"}, {1.23456789, "%1v", "1.23456789 mol"}, {1.23456789, "%#v", "unit.Mole(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Mole=1.23456789 mol)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/power.go000066400000000000000000000031761450372207100203070ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Power represents a power in Watts. type Power float64 const Watt Power = 1 // Unit converts the Power to a *Unit. func (pw Power) Unit() *Unit { return New(float64(pw), Dimensions{ LengthDim: 2, MassDim: 1, TimeDim: -3, }) } // Power allows Power to implement a Powerer interface. func (pw Power) Power() Power { return pw } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (pw *Power) From(u Uniter) error { if !DimensionsMatch(u, Watt) { *pw = Power(math.NaN()) return errors.New("unit: dimension mismatch") } *pw = Power(u.Unit().Value()) return nil } func (pw Power) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", pw, float64(pw)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " W" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(pw)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(pw)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(pw)) default: fmt.Fprintf(fs, "%"+string(c), float64(pw)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g W)", c, pw, float64(pw)) } } golang-gonum-v1-gonum-0.14.0/unit/power_test.go000066400000000000000000000027401450372207100213420ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestPower(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Power err := got.From(Power(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Power(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Power() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestPowerFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Power format string want string }{ {1.23456789, "%v", "1.23456789 W"}, {1.23456789, "%.1v", "1 W"}, {1.23456789, "%20.1v", " 1 W"}, {1.23456789, "%20v", " 1.23456789 W"}, {1.23456789, "%1v", "1.23456789 W"}, {1.23456789, "%#v", "unit.Power(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Power=1.23456789 W)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/prefixes.go000066400000000000000000000007261450372207100207760ustar00rootroot00000000000000// 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 unit const ( Yotta = 1e24 Zetta = 1e21 Exa = 1e18 Peta = 1e15 Tera = 1e12 Giga = 1e9 Mega = 1e6 Kilo = 1e3 Hecto = 1e2 Deca = 1e1 Deci = 1e-1 Centi = 1e-2 Milli = 1e-3 Micro = 1e-6 Nano = 1e-9 Pico = 1e-12 Femto = 1e-15 Atto = 1e-18 Zepto = 1e-21 Yocto = 1e-24 ) golang-gonum-v1-gonum-0.14.0/unit/pressure.go000066400000000000000000000032661450372207100210230ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Pressure represents a pressure in Pascals. type Pressure float64 const Pascal Pressure = 1 // Unit converts the Pressure to a *Unit. func (pr Pressure) Unit() *Unit { return New(float64(pr), Dimensions{ LengthDim: -1, MassDim: 1, TimeDim: -2, }) } // Pressure allows Pressure to implement a Pressurer interface. func (pr Pressure) Pressure() Pressure { return pr } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (pr *Pressure) From(u Uniter) error { if !DimensionsMatch(u, Pascal) { *pr = Pressure(math.NaN()) return errors.New("unit: dimension mismatch") } *pr = Pressure(u.Unit().Value()) return nil } func (pr Pressure) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", pr, float64(pr)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " Pa" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(pr)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(pr)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(pr)) default: fmt.Fprintf(fs, "%"+string(c), float64(pr)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g Pa)", c, pr, float64(pr)) } } golang-gonum-v1-gonum-0.14.0/unit/pressure_test.go000066400000000000000000000027771450372207100220700ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestPressure(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Pressure err := got.From(Pressure(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Pressure(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Pressure() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestPressureFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Pressure format string want string }{ {1.23456789, "%v", "1.23456789 Pa"}, {1.23456789, "%.1v", "1 Pa"}, {1.23456789, "%20.1v", " 1 Pa"}, {1.23456789, "%20v", " 1.23456789 Pa"}, {1.23456789, "%1v", "1.23456789 Pa"}, {1.23456789, "%#v", "unit.Pressure(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Pressure=1.23456789 Pa)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/radioactivity.go000066400000000000000000000033511450372207100220210ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Radioactivity represents a rate of radioactive decay in becquerels. type Radioactivity float64 const Becquerel Radioactivity = 1 // Unit converts the Radioactivity to a *Unit. func (r Radioactivity) Unit() *Unit { return New(float64(r), Dimensions{ TimeDim: -1, }) } // Radioactivity allows Radioactivity to implement a Radioactivityer interface. func (r Radioactivity) Radioactivity() Radioactivity { return r } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (r *Radioactivity) From(u Uniter) error { if !DimensionsMatch(u, Becquerel) { *r = Radioactivity(math.NaN()) return errors.New("unit: dimension mismatch") } *r = Radioactivity(u.Unit().Value()) return nil } func (r Radioactivity) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", r, float64(r)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " Bq" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(r)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(r)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(r)) default: fmt.Fprintf(fs, "%"+string(c), float64(r)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g Bq)", c, r, float64(r)) } } golang-gonum-v1-gonum-0.14.0/unit/radioactivity_test.go000066400000000000000000000030541450372207100230600ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestRadioactivity(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Radioactivity err := got.From(Radioactivity(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Radioactivity(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Radioactivity() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestRadioactivityFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Radioactivity format string want string }{ {1.23456789, "%v", "1.23456789 Bq"}, {1.23456789, "%.1v", "1 Bq"}, {1.23456789, "%20.1v", " 1 Bq"}, {1.23456789, "%20v", " 1.23456789 Bq"}, {1.23456789, "%1v", "1.23456789 Bq"}, {1.23456789, "%#v", "unit.Radioactivity(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Radioactivity=1.23456789 Bq)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/resistance.go000066400000000000000000000033651450372207100213130ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Resistance represents an electrical resistance, impedance or reactance in Ohms. type Resistance float64 const Ohm Resistance = 1 // Unit converts the Resistance to a *Unit. func (r Resistance) Unit() *Unit { return New(float64(r), Dimensions{ CurrentDim: -2, LengthDim: 2, MassDim: 1, TimeDim: -3, }) } // Resistance allows Resistance to implement a Resistancer interface. func (r Resistance) Resistance() Resistance { return r } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (r *Resistance) From(u Uniter) error { if !DimensionsMatch(u, Ohm) { *r = Resistance(math.NaN()) return errors.New("unit: dimension mismatch") } *r = Resistance(u.Unit().Value()) return nil } func (r Resistance) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", r, float64(r)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " Ω" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(r)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(r)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(r)) default: fmt.Fprintf(fs, "%"+string(c), float64(r)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g Ω)", c, r, float64(r)) } } golang-gonum-v1-gonum-0.14.0/unit/resistance_test.go000066400000000000000000000030231450372207100223410ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestResistance(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Resistance err := got.From(Resistance(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Resistance(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Resistance() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestResistanceFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Resistance format string want string }{ {1.23456789, "%v", "1.23456789 Ω"}, {1.23456789, "%.1v", "1 Ω"}, {1.23456789, "%20.1v", " 1 Ω"}, {1.23456789, "%20v", " 1.23456789 Ω"}, {1.23456789, "%1v", "1.23456789 Ω"}, {1.23456789, "%#v", "unit.Resistance(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Resistance=1.23456789 Ω)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/temperature.go000066400000000000000000000032661450372207100215100ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Temperature represents a temperature in Kelvin. type Temperature float64 const Kelvin Temperature = 1 // Unit converts the Temperature to a *Unit. func (t Temperature) Unit() *Unit { return New(float64(t), Dimensions{ TemperatureDim: 1, }) } // Temperature allows Temperature to implement a Temperaturer interface. func (t Temperature) Temperature() Temperature { return t } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (t *Temperature) From(u Uniter) error { if !DimensionsMatch(u, Kelvin) { *t = Temperature(math.NaN()) return errors.New("unit: dimension mismatch") } *t = Temperature(u.Unit().Value()) return nil } func (t Temperature) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", t, float64(t)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " K" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(t)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(t)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(t)) default: fmt.Fprintf(fs, "%"+string(c), float64(t)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g K)", c, t, float64(t)) } } golang-gonum-v1-gonum-0.14.0/unit/temperature_test.go000066400000000000000000000030261450372207100225410ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestTemperature(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Temperature err := got.From(Temperature(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Temperature(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Temperature() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestTemperatureFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Temperature format string want string }{ {1.23456789, "%v", "1.23456789 K"}, {1.23456789, "%.1v", "1 K"}, {1.23456789, "%20.1v", " 1 K"}, {1.23456789, "%20v", " 1.23456789 K"}, {1.23456789, "%1v", "1.23456789 K"}, {1.23456789, "%#v", "unit.Temperature(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Temperature=1.23456789 K)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/time.go000066400000000000000000000031661450372207100201100ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Time represents a duration in seconds. type Time float64 const ( Second Time = 1 Minute = 60 * Second Hour = 60 * Minute ) // Unit converts the Time to a *Unit. func (t Time) Unit() *Unit { return New(float64(t), Dimensions{ TimeDim: 1, }) } // Time allows Time to implement a Timer interface. func (t Time) Time() Time { return t } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (t *Time) From(u Uniter) error { if !DimensionsMatch(u, Second) { *t = Time(math.NaN()) return errors.New("unit: dimension mismatch") } *t = Time(u.Unit().Value()) return nil } func (t Time) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", t, float64(t)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " s" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(t)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(t)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(t)) default: fmt.Fprintf(fs, "%"+string(c), float64(t)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g s)", c, t, float64(t)) } } golang-gonum-v1-gonum-0.14.0/unit/time_test.go000066400000000000000000000027271450372207100211510ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestTime(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Time err := got.From(Time(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Time(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Time() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestTimeFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Time format string want string }{ {1.23456789, "%v", "1.23456789 s"}, {1.23456789, "%.1v", "1 s"}, {1.23456789, "%20.1v", " 1 s"}, {1.23456789, "%20v", " 1.23456789 s"}, {1.23456789, "%1v", "1.23456789 s"}, {1.23456789, "%#v", "unit.Time(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Time=1.23456789 s)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/torque.go000066400000000000000000000032271450372207100204670ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Torque represents a torque in Newton metres. type Torque float64 const Newtonmetre Torque = 1 // Unit converts the Torque to a *Unit. func (t Torque) Unit() *Unit { return New(float64(t), Dimensions{ LengthDim: 2, MassDim: 1, TimeDim: -2, }) } // Torque allows Torque to implement a Torquer interface. func (t Torque) Torque() Torque { return t } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (t *Torque) From(u Uniter) error { if !DimensionsMatch(u, Newtonmetre) { *t = Torque(math.NaN()) return errors.New("unit: dimension mismatch") } *t = Torque(u.Unit().Value()) return nil } func (t Torque) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", t, float64(t)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " N m" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(t)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(t)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(t)) default: fmt.Fprintf(fs, "%"+string(c), float64(t)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g N m)", c, t, float64(t)) } } golang-gonum-v1-gonum-0.14.0/unit/torque_test.go000066400000000000000000000027611450372207100215300ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestTorque(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Torque err := got.From(Torque(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Torque(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Torque() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestTorqueFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Torque format string want string }{ {1.23456789, "%v", "1.23456789 N m"}, {1.23456789, "%.1v", "1 N m"}, {1.23456789, "%20.1v", " 1 N m"}, {1.23456789, "%20v", " 1.23456789 N m"}, {1.23456789, "%1v", "1.23456789 N m"}, {1.23456789, "%#v", "unit.Torque(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Torque=1.23456789 N m)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/unit_test.go000066400000000000000000000321211450372207100211610ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package unit import ( "fmt" "math" "testing" ) // ether is a non-existent unit used for testing. type ether float64 func (e ether) Unit() *Unit { return New(float64(e), Dimensions{reserved: 1}) } var formatTests = []struct { unit Uniter format string expect string }{ {New(9.81, Dimensions{MassDim: 1, TimeDim: -2}), "%f", "9.810000 kg s^-2"}, {New(9.81, Dimensions{MassDim: 1, TimeDim: -2}), "%1.f", "10 kg s^-2"}, {New(9.81, Dimensions{MassDim: 1, TimeDim: -2}), "%10.f", "10 kg s^-2"}, {New(9.81, Dimensions{MassDim: 1, TimeDim: -2}), "%.1f", "9.8 kg s^-2"}, {New(9.81, Dimensions{MassDim: 1, TimeDim: -2}), "%20f", " 9.810000 kg s^-2"}, {New(9.81, Dimensions{MassDim: 1, TimeDim: -2}), "%1f", "9.810000 kg s^-2"}, {New(9.81, Dimensions{MassDim: 1, TimeDim: -2, LengthDim: 0}), "%f", "9.810000 kg s^-2"}, {New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1}), "%e", "6.626070e-34 kg^2 s^-1"}, {New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1}), "%20.3e", " 6.626e-34 kg^2 s^-1"}, {New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1}), "%.3e", "6.626e-34 kg^2 s^-1"}, {New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1}), "%25e", " 6.626070e-34 kg^2 s^-1"}, {New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1}), "%1e", "6.626070e-34 kg^2 s^-1"}, {New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1}), "%v", "6.62606957e-34 kg^2 s^-1"}, {New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1}), "%s", "%!s(*Unit=6.62606957e-34 kg^2 s^-1)"}, {Dimless(math.E), "%v", "2.718281828459045"}, {Dimless(math.E), "%.2v", "2.7"}, {Dimless(math.E), "%6.2v", " 2.7"}, {Dimless(math.E), "%20v", " 2.718281828459045"}, {Dimless(math.E), "%1v", "2.718281828459045"}, {Dimless(math.E), "%#v", "unit.Dimless(2.718281828459045)"}, {Dimless(math.E), "%s", "%!s(unit.Dimless=2.718281828459045)"}, {Angle(1), "%v", "1 rad"}, {Angle(0.45), "%.1v", "0.5 rad"}, {Angle(0.45), "%10.1v", " 0.5 rad"}, {Angle(0.45), "%10v", " 0.45 rad"}, {Angle(0.45), "%1v", "0.45 rad"}, {Angle(1), "%#v", "unit.Angle(1)"}, {Angle(1), "%s", "%!s(unit.Angle=1 rad)"}, {Current(1), "%v", "1 A"}, {Current(0.45), "%.1v", "0.5 A"}, {Current(0.45), "%10.1v", " 0.5 A"}, {Current(0.45), "%10v", " 0.45 A"}, {Current(0.45), "%1v", "0.45 A"}, {Current(1), "%#v", "unit.Current(1)"}, {Current(1), "%s", "%!s(unit.Current=1 A)"}, {LuminousIntensity(1), "%v", "1 cd"}, {LuminousIntensity(0.45), "%.1v", "0.5 cd"}, {LuminousIntensity(0.45), "%10.1v", " 0.5 cd"}, {LuminousIntensity(0.45), "%10v", " 0.45 cd"}, {LuminousIntensity(0.45), "%1v", "0.45 cd"}, {LuminousIntensity(1), "%#v", "unit.LuminousIntensity(1)"}, {LuminousIntensity(1), "%s", "%!s(unit.LuminousIntensity=1 cd)"}, {Mass(1), "%v", "1 kg"}, {Mass(0.45), "%.1v", "0.5 kg"}, {Mass(0.45), "%10.1v", " 0.5 kg"}, {Mass(0.45), "%10v", " 0.45 kg"}, {Mass(0.45), "%1v", "0.45 kg"}, {Mass(1), "%#v", "unit.Mass(1)"}, {Mass(1), "%s", "%!s(unit.Mass=1 kg)"}, {Mole(1), "%v", "1 mol"}, {Mole(0.45), "%.1v", "0.5 mol"}, {Mole(0.45), "%10.1v", " 0.5 mol"}, {Mole(0.45), "%10v", " 0.45 mol"}, {Mole(0.45), "%1v", "0.45 mol"}, {Mole(1), "%#v", "unit.Mole(1)"}, {Mole(1), "%s", "%!s(unit.Mole=1 mol)"}, {Length(1.61619926e-35), "%v", "1.61619926e-35 m"}, {Length(1.61619926e-35), "%.2v", "1.6e-35 m"}, {Length(1.61619926e-35), "%10.2v", " 1.6e-35 m"}, {Length(1.61619926e-35), "%20v", " 1.61619926e-35 m"}, {Length(1.61619926e-35), "%1v", "1.61619926e-35 m"}, {Length(1.61619926e-35), "%#v", "unit.Length(1.61619926e-35)"}, {Length(1.61619926e-35), "%s", "%!s(unit.Length=1.61619926e-35 m)"}, {Temperature(15.2), "%v", "15.2 K"}, {Temperature(15.2), "%.2v", "15 K"}, {Temperature(15.2), "%6.2v", " 15 K"}, {Temperature(15.2), "%10v", " 15.2 K"}, {Temperature(15.2), "%1v", "15.2 K"}, {Temperature(15.2), "%#v", "unit.Temperature(15.2)"}, {Temperature(15.2), "%s", "%!s(unit.Temperature=15.2 K)"}, {Time(15.2), "%v", "15.2 s"}, {Time(15.2), "%.2v", "15 s"}, {Time(15.2), "%6.2v", " 15 s"}, {Time(15.2), "%10v", " 15.2 s"}, {Time(15.2), "%1v", "15.2 s"}, {Time(15.2), "%#v", "unit.Time(15.2)"}, {Time(15.2), "%s", "%!s(unit.Time=15.2 s)"}, } func TestFormat(t *testing.T) { t.Parallel() for _, ts := range formatTests { if r := fmt.Sprintf(ts.format, ts.unit); r != ts.expect { t.Errorf("Format %q: got: %q expected: %q", ts.format, r, ts.expect) } } } func TestCopy(t *testing.T) { t.Parallel() for _, ts := range formatTests { u := ts.unit.Unit() if len(u.Dimensions()) == 0 { continue } c := u.Copy() c.Mul(c) if DimensionsMatch(u, c) { t.Errorf("dimensions match after mutating copy of %v: %v == %v", u, u.Dimensions(), c.Dimensions()) } } } func TestGoStringFormat(t *testing.T) { t.Parallel() expect1 := `&unit.Unit{dimensions:unit.Dimensions{4:2, 7:-1}, value:6.62606957e-34}` expect2 := `&unit.Unit{dimensions:unit.Dimensions{7:-1, 4:2}, value:6.62606957e-34}` if r := fmt.Sprintf("%#v", New(6.62606957e-34, Dimensions{MassDim: 2, TimeDim: -1})); r != expect1 && r != expect2 { t.Errorf("Format %q: got: %q expected: %q", "%#v", r, expect1) } } var initializationTests = []struct { unit *Unit expValue float64 expMap map[Dimension]int }{ {New(9.81, Dimensions{MassDim: 1, TimeDim: -2}), 9.81, Dimensions{MassDim: 1, TimeDim: -2}}, {New(9.81, Dimensions{MassDim: 1, TimeDim: -2, LengthDim: 0, CurrentDim: 0}), 9.81, Dimensions{MassDim: 1, TimeDim: -2}}, } func TestInitialization(t *testing.T) { t.Parallel() for _, ts := range initializationTests { if ts.expValue != ts.unit.value { t.Errorf("Value wrong on initialization: got: %v expected: %v", ts.unit.value, ts.expValue) } if len(ts.expMap) != len(ts.unit.dimensions) { t.Errorf("Map mismatch: got: %#v expected: %#v", ts.unit.dimensions, ts.expMap) } for key, val := range ts.expMap { if ts.unit.dimensions[key] != val { t.Errorf("Map mismatch: got: %#v expected: %#v", ts.unit.dimensions, ts.expMap) } } } } var dimensionEqualityTests = []struct { name string a Uniter b Uniter shouldMatch bool }{ {"same_empty", New(1.0, Dimensions{}), New(1.0, Dimensions{}), true}, {"same_one", New(1.0, Dimensions{TimeDim: 1}), New(1.0, Dimensions{TimeDim: 1}), true}, {"same_mult", New(1.0, Dimensions{TimeDim: 1, LengthDim: -2}), New(1.0, Dimensions{TimeDim: 1, LengthDim: -2}), true}, {"diff_one_empty", New(1.0, Dimensions{}), New(1.0, Dimensions{TimeDim: 1, LengthDim: -2}), false}, {"diff_same_dim", New(1.0, Dimensions{TimeDim: 1}), New(1.0, Dimensions{TimeDim: 2}), false}, {"diff_same_pow", New(1.0, Dimensions{LengthDim: 1}), New(1.0, Dimensions{TimeDim: 1}), false}, {"diff_numdim", New(1.0, Dimensions{TimeDim: 1, LengthDim: 2}), New(1.0, Dimensions{TimeDim: 2}), false}, {"diff_one_same_dim", New(1.0, Dimensions{LengthDim: 1, TimeDim: 1}), New(1.0, Dimensions{LengthDim: 1, TimeDim: 2}), false}, } func TestDimensionEquality(t *testing.T) { t.Parallel() for _, ts := range dimensionEqualityTests { if DimensionsMatch(ts.a, ts.b) != ts.shouldMatch { t.Errorf("Dimension comparison incorrect for case %s. got: %v, expected: %v", ts.name, !ts.shouldMatch, ts.shouldMatch) } } } func TestOperations(t *testing.T) { operationTests := []struct { recvOp func(Uniter) *Unit param Uniter want Uniter }{ {Dimless(1).Unit().Add, Dimless(2), Dimless(3)}, {Dimless(1).Unit().Mul, Dimless(2), Dimless(2)}, {Dimless(1).Unit().Mul, Length(2), Length(2)}, {Length(1).Unit().Mul, Dimless(2), Length(2)}, {Dimless(1).Unit().Div, Length(2), New(0.5, Dimensions{LengthDim: -1})}, {Length(1).Unit().Div, Dimless(2), Length(0.5)}, } t.Parallel() for i, test := range operationTests { var got Uniter if panics(func() { got = test.recvOp(test.param) }) { t.Errorf("unexpected panic for test %d", i) continue } if !DimensionsMatch(got, test.want) { t.Errorf("dimension mismatch for test %d: got=%v want=%v", i, got.Unit(), test.want.Unit()) } if got.Unit().Value() != test.want.Unit().Value() { t.Errorf("value mismatch for test %d: got=%v want=%v", i, got.Unit().Value(), test.want.Unit().Value()) } } } // panics returns true if the function panics. func panics(f func()) (b bool) { defer func() { err := recover() if err != nil { b = true } }() f() return } type UnitStructer interface { UnitStruct() *UnitStruct } type UnitStruct struct { current int length int luminosity int mass int temperature int time int chemamt int // For mol value float64 } // Check if the dimensions of two units are the same func DimensionsMatchStruct(aU, bU UnitStructer) bool { a := aU.UnitStruct() b := bU.UnitStruct() if a.length != b.length { return false } if a.time != b.time { return false } if a.mass != b.mass { return false } if a.current != b.current { return false } if a.temperature != b.temperature { return false } if a.luminosity != b.luminosity { return false } if a.chemamt != b.chemamt { return false } return true } func (u *UnitStruct) UnitStruct() *UnitStruct { return u } func (u *UnitStruct) Add(aU UnitStructer) *UnitStruct { a := aU.UnitStruct() if !DimensionsMatchStruct(a, u) { panic("dimension mismatch") } u.value += a.value return u } func (u *UnitStruct) Mul(aU UnitStructer) *UnitStruct { a := aU.UnitStruct() u.length += a.length u.time += a.time u.mass += a.mass u.current += a.current u.temperature += a.temperature u.luminosity += a.luminosity u.chemamt += a.chemamt u.value *= a.value return u } func BenchmarkAddStruct(b *testing.B) { u1 := &UnitStruct{current: 1, chemamt: 5, value: 10} u2 := &UnitStruct{current: 1, chemamt: 5, value: 100} for i := 0; i < b.N; i++ { u2.Add(u1) } } func BenchmarkMulStruct(b *testing.B) { u1 := &UnitStruct{current: 1, chemamt: 5, value: 10} u2 := &UnitStruct{mass: 1, time: 1, value: 100} for i := 0; i < b.N; i++ { u2.Mul(u1) } } type UnitMapper interface { UnitMap() *UnitMap } type dimensionMap int const ( LengthB dimensionMap = iota TimeB MassB CurrentB TemperatureB LuminosityB ChemAmtB ) type UnitMap struct { dimension map[dimensionMap]int value float64 } // Check if the dimensions of two units are the same func DimensionsMatchMap(aU, bU UnitMapper) bool { a := aU.UnitMap() b := bU.UnitMap() if len(a.dimension) != len(b.dimension) { panic("Unequal dimension") } for key, dimA := range a.dimension { dimB, ok := b.dimension[key] if !ok || dimA != dimB { panic("Unequal dimension") } } return true } func (u *UnitMap) UnitMap() *UnitMap { return u } func (u *UnitMap) Add(aU UnitMapper) *UnitMap { a := aU.UnitMap() if !DimensionsMatchMap(a, u) { panic("dimension mismatch") } u.value += a.value return u } func (u *UnitMap) Mul(aU UnitMapper) *UnitMap { a := aU.UnitMap() for key, val := range a.dimension { u.dimension[key] += val } u.value *= a.value return u } var sink float64 func BenchmarkAddFloat(b *testing.B) { sink = 0 c := 10.0 for i := 0; i < b.N; i++ { sink += c } } func BenchmarkMulFloat(b *testing.B) { sink = 0 c := 10.0 for i := 0; i < b.N; i++ { sink *= c } } func BenchmarkAddMapSmall(b *testing.B) { u1 := &UnitMap{value: 10} u1.dimension = make(map[dimensionMap]int) u1.dimension[CurrentB] = 1 u1.dimension[ChemAmtB] = 5 u2 := &UnitMap{value: 10} u2.dimension = make(map[dimensionMap]int) u2.dimension[CurrentB] = 1 u2.dimension[ChemAmtB] = 5 for i := 0; i < b.N; i++ { u2.Add(u1) } } func BenchmarkMulMapSmallDiff(b *testing.B) { u1 := &UnitMap{value: 10} u1.dimension = make(map[dimensionMap]int) u1.dimension[LengthB] = 1 u2 := &UnitMap{value: 10} u2.dimension = make(map[dimensionMap]int) u2.dimension[MassB] = 1 for i := 0; i < b.N; i++ { u2.Mul(u1) } } func BenchmarkMulMapSmallSame(b *testing.B) { u1 := &UnitMap{value: 10} u1.dimension = make(map[dimensionMap]int) u1.dimension[LengthB] = 1 u2 := &UnitMap{value: 10} u2.dimension = make(map[dimensionMap]int) u2.dimension[LengthB] = 2 for i := 0; i < b.N; i++ { u2.Mul(u1) } } func BenchmarkMulMapLargeDiff(b *testing.B) { u1 := &UnitMap{value: 10} u1.dimension = make(map[dimensionMap]int) u1.dimension[LengthB] = 1 u1.dimension[MassB] = 1 u1.dimension[ChemAmtB] = 1 u1.dimension[TemperatureB] = 1 u1.dimension[LuminosityB] = 1 u1.dimension[TimeB] = 1 u1.dimension[CurrentB] = 1 u2 := &UnitMap{value: 10} u2.dimension = make(map[dimensionMap]int) u2.dimension[MassB] = 1 for i := 0; i < b.N; i++ { u2.Mul(u1) } } func BenchmarkMulMapLargeSame(b *testing.B) { u1 := &UnitMap{value: 10} u1.dimension = make(map[dimensionMap]int) u1.dimension[LengthB] = 2 u1.dimension[MassB] = 2 u1.dimension[ChemAmtB] = 2 u1.dimension[TemperatureB] = 2 u1.dimension[LuminosityB] = 2 u1.dimension[TimeB] = 2 u1.dimension[CurrentB] = 2 u2 := &UnitMap{value: 10} u2.dimension = make(map[dimensionMap]int) u2.dimension[LengthB] = 3 u2.dimension[MassB] = 3 u2.dimension[ChemAmtB] = 3 u2.dimension[TemperatureB] = 3 u2.dimension[LuminosityB] = 3 u2.dimension[TimeB] = 3 u2.dimension[CurrentB] = 3 for i := 0; i < b.N; i++ { u2.Mul(u1) } } golang-gonum-v1-gonum-0.14.0/unit/unitexample_test.go000066400000000000000000000023031450372207100225340ustar00rootroot00000000000000// 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 unit_test import ( "fmt" "gonum.org/v1/gonum/unit" ) func ExampleNew() { // Create an angular acceleration of 3 rad/s^2 accel := unit.New(3.0, unit.Dimensions{unit.AngleDim: 1, unit.TimeDim: -2}) fmt.Println(accel) // Output: 3 rad s^-2 } func ExampleNewDimension() { // Create a "trees" dimension // Typically, this should be used within an init function treeDim := unit.NewDimension("tree") countPerArea := unit.New(0.1, unit.Dimensions{treeDim: 1, unit.LengthDim: -2}) fmt.Println(countPerArea) // Output: 0.1 tree m^-2 } func Example_horsepower() { // One mechanical horsepower ≡ 33,000 ft-lbf/min. foot := unit.Length(0.3048) pound := unit.Mass(0.45359237) gravity := unit.Acceleration(9.80665) poundforce := pound.Unit().Mul(gravity) hp := ((33000 * foot).Unit().Mul(poundforce)).Div(unit.Minute) fmt.Println("1 hp =", hp) watt := unit.Power(1) fmt.Println("W is equivalent to hp?", unit.DimensionsMatch(hp, watt)) // Output: // // 1 hp = 745.6998715822701 kg m^2 s^-3 // W is equivalent to hp? true } golang-gonum-v1-gonum-0.14.0/unit/unittype.go000066400000000000000000000226601450372207100210330ustar00rootroot00000000000000// Copyright ©2013 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package unit import ( "bytes" "fmt" "sort" "sync" "unicode/utf8" ) // Uniter is a type that can be converted to a Unit. type Uniter interface { Unit() *Unit } // Dimension is a type representing an SI base dimension or a distinct // orthogonal dimension. Non-SI dimensions can be created using the NewDimension // function, typically within an init function. type Dimension int // NewDimension creates a new orthogonal dimension with the given symbol, and // returns the value of that dimension. The input symbol must not overlap with // any of the any of the SI base units or other symbols of common use in SI ("kg", // "J", etc.), and must not overlap with any other dimensions created by calls // to NewDimension. The SymbolExists function can check if the symbol exists. // NewDimension will panic if the input symbol matches an existing symbol. // // NewDimension should only be called for unit types that are actually orthogonal // to the base dimensions defined in this package. See the package-level // documentation for further explanation. func NewDimension(symbol string) Dimension { defer mu.Unlock() mu.Lock() _, ok := dimensions[symbol] if ok { panic("unit: dimension string \"" + symbol + "\" already used") } d := Dimension(len(symbols)) symbols = append(symbols, symbol) dimensions[symbol] = d return d } // String returns the string for the dimension. func (d Dimension) String() string { if d == reserved { return "reserved" } defer mu.RUnlock() mu.RLock() if int(d) < len(symbols) { return symbols[d] } panic("unit: illegal dimension") } // SymbolExists returns whether the given symbol is already in use. func SymbolExists(symbol string) bool { mu.RLock() _, ok := dimensions[symbol] mu.RUnlock() return ok } const ( // SI Base Units reserved Dimension = iota CurrentDim LengthDim LuminousIntensityDim MassDim MoleDim TemperatureDim TimeDim // Other common SI Dimensions AngleDim // e.g. radians ) var ( // mu protects symbols and dimensions for concurrent use. mu sync.RWMutex symbols = []string{ CurrentDim: "A", LengthDim: "m", LuminousIntensityDim: "cd", MassDim: "kg", MoleDim: "mol", TemperatureDim: "K", TimeDim: "s", AngleDim: "rad", } // dimensions guarantees there aren't two identical symbols // SI symbol list from http://lamar.colostate.edu/~hillger/basic.htm dimensions = map[string]Dimension{ "A": CurrentDim, "m": LengthDim, "cd": LuminousIntensityDim, "kg": MassDim, "mol": MoleDim, "K": TemperatureDim, "s": TimeDim, "rad": AngleDim, // Reserve common SI symbols // prefixes "Y": reserved, "Z": reserved, "E": reserved, "P": reserved, "T": reserved, "G": reserved, "M": reserved, "k": reserved, "h": reserved, "da": reserved, "d": reserved, "c": reserved, "μ": reserved, "n": reserved, "p": reserved, "f": reserved, "a": reserved, "z": reserved, "y": reserved, // SI Derived units with special symbols "sr": reserved, "F": reserved, "C": reserved, "S": reserved, "H": reserved, "V": reserved, "Ω": reserved, "J": reserved, "N": reserved, "Hz": reserved, "lx": reserved, "lm": reserved, "Wb": reserved, "W": reserved, "Pa": reserved, "Bq": reserved, "Gy": reserved, "Sv": reserved, "kat": reserved, // Units in use with SI "ha": reserved, "L": reserved, "l": reserved, // Units in Use Temporarily with SI "bar": reserved, "b": reserved, "Ci": reserved, "R": reserved, "rd": reserved, "rem": reserved, } ) // Dimensions represent the dimensionality of the unit in powers // of that dimension. If a key is not present, the power of that // dimension is zero. Dimensions is used in conjunction with New. type Dimensions map[Dimension]int func (d Dimensions) clone() Dimensions { if d == nil { return nil } c := make(Dimensions, len(d)) for dim, pow := range d { if pow != 0 { c[dim] = pow } } return c } // matches reports whether the dimensions of d and o match. Zero power // dimensions in d an o must be removed, otherwise matches may incorrectly // report a mismatch. func (d Dimensions) matches(o Dimensions) bool { if len(d) != len(o) { return false } for dim, pow := range d { if o[dim] != pow { return false } } return true } func (d Dimensions) String() string { // Map iterates randomly, but print should be in a fixed order. Can't use // dimension number, because for user-defined dimension that number may // not be fixed from run to run. atoms := make(unitPrinters, 0, len(d)) for dimension, power := range d { if power != 0 { atoms = append(atoms, atom{dimension, power}) } } sort.Sort(atoms) var b bytes.Buffer for i, a := range atoms { if i > 0 { b.WriteByte(' ') } fmt.Fprintf(&b, "%s", a.Dimension) if a.pow != 1 { fmt.Fprintf(&b, "^%d", a.pow) } } return b.String() } type atom struct { Dimension pow int } type unitPrinters []atom func (u unitPrinters) Len() int { return len(u) } func (u unitPrinters) Less(i, j int) bool { // Order first by positive powers, then by name. if u[i].pow*u[j].pow < 0 { return u[i].pow > 0 } return u[i].String() < u[j].String() } func (u unitPrinters) Swap(i, j int) { u[i], u[j] = u[j], u[i] } // Unit represents a dimensional value. The dimensions will typically be in SI // units, but can also include dimensions created with NewDimension. The Unit type // is most useful for ensuring dimensional consistency when manipulating types // with different units, for example, by multiplying an acceleration with a // mass to get a force. See the package documentation for further explanation. type Unit struct { dimensions Dimensions value float64 } // New creates a new variable of type Unit which has the value and dimensions // specified by the inputs. The built-in dimensions are always in SI units // (metres, kilograms, etc.). func New(value float64, d Dimensions) *Unit { return &Unit{ dimensions: d.clone(), value: value, } } // DimensionsMatch checks if the dimensions of two Uniters are the same. func DimensionsMatch(a, b Uniter) bool { return a.Unit().dimensions.matches(b.Unit().dimensions) } // Dimensions returns a copy of the dimensions of the unit. func (u *Unit) Dimensions() Dimensions { return u.dimensions.clone() } // Add adds the function argument to the receiver. Panics if the units of // the receiver and the argument don't match. func (u *Unit) Add(uniter Uniter) *Unit { a := uniter.Unit() if !DimensionsMatch(u, a) { panic("unit: mismatched dimensions in addition") } u.value += a.value return u } // Unit implements the Uniter interface, returning the receiver. If a // copy of the receiver is required, use the Copy method. func (u *Unit) Unit() *Unit { return u } // Copy returns a copy of the Unit that can be mutated without the change // being reflected in the original value. func (u *Unit) Copy() *Unit { return &Unit{ dimensions: u.dimensions.clone(), value: u.value, } } // Mul multiply the receiver by the input changing the dimensions // of the receiver as appropriate. The input is not changed. func (u *Unit) Mul(uniter Uniter) *Unit { a := uniter.Unit() for key, val := range a.dimensions { if d := u.dimensions[key]; d == -val { delete(u.dimensions, key) } else { u.dimensions[key] = d + val } } u.value *= a.value return u } // Div divides the receiver by the argument changing the // dimensions of the receiver as appropriate. func (u *Unit) Div(uniter Uniter) *Unit { a := uniter.Unit() u.value /= a.value for key, val := range a.dimensions { if d := u.dimensions[key]; d == val { delete(u.dimensions, key) } else { u.dimensions[key] = d - val } } return u } // Value return the raw value of the unit as a float64. Use of this // method is, in general, not recommended, though it can be useful // for printing. Instead, the From method of a specific dimension // should be used to guarantee dimension consistency. func (u *Unit) Value() float64 { return u.value } // SetValue sets the value of the unit. func (u *Unit) SetValue(v float64) { u.value = v } // Format makes Unit satisfy the fmt.Formatter interface. The unit is formatted // with dimensions appended. If the power of the dimension is not zero or one, // symbol^power is appended, if the power is one, just the symbol is appended // and if the power is zero, nothing is appended. Dimensions are appended // in order by symbol name with positive powers ahead of negative powers. func (u *Unit) Format(fs fmt.State, c rune) { if u == nil { fmt.Fprint(fs, "") } switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "&%#v", *u) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() units := u.dimensions.String() switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(units))-1), p, u.value) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, u.value) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(units))-1), u.value) default: fmt.Fprintf(fs, "%"+string(c), u.value) } fmt.Fprintf(fs, " %s", units) default: fmt.Fprintf(fs, "%%!%c(*Unit=%g)", c, u) } } func pos(a int) int { if a < 0 { return 0 } return a } golang-gonum-v1-gonum-0.14.0/unit/velocity.go000066400000000000000000000032221450372207100210010ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Velocity represents a velocity in metres per second. type Velocity float64 // Unit converts the Velocity to a *Unit. func (v Velocity) Unit() *Unit { return New(float64(v), Dimensions{ LengthDim: 1, TimeDim: -1, }) } // Velocity allows Velocity to implement a Velocityer interface. func (v Velocity) Velocity() Velocity { return v } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (v *Velocity) From(u Uniter) error { if !DimensionsMatch(u, Velocity(0)) { *v = Velocity(math.NaN()) return errors.New("unit: dimension mismatch") } *v = Velocity(u.Unit().Value()) return nil } func (v Velocity) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", v, float64(v)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " m s^-1" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(v)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(v)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(v)) default: fmt.Fprintf(fs, "%"+string(c), float64(v)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g m s^-1)", c, v, float64(v)) } } golang-gonum-v1-gonum-0.14.0/unit/velocity_test.go000066400000000000000000000030171450372207100220420ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestVelocity(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Velocity err := got.From(Velocity(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Velocity(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Velocity() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestVelocityFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Velocity format string want string }{ {1.23456789, "%v", "1.23456789 m s^-1"}, {1.23456789, "%.1v", "1 m s^-1"}, {1.23456789, "%20.1v", " 1 m s^-1"}, {1.23456789, "%20v", " 1.23456789 m s^-1"}, {1.23456789, "%1v", "1.23456789 m s^-1"}, {1.23456789, "%#v", "unit.Velocity(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Velocity=1.23456789 m s^-1)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/voltage.go000066400000000000000000000032421450372207100206060ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Voltage represents a voltage in Volts. type Voltage float64 const Volt Voltage = 1 // Unit converts the Voltage to a *Unit. func (v Voltage) Unit() *Unit { return New(float64(v), Dimensions{ CurrentDim: -1, LengthDim: 2, MassDim: 1, TimeDim: -3, }) } // Voltage allows Voltage to implement a Voltager interface. func (v Voltage) Voltage() Voltage { return v } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (v *Voltage) From(u Uniter) error { if !DimensionsMatch(u, Volt) { *v = Voltage(math.NaN()) return errors.New("unit: dimension mismatch") } *v = Voltage(u.Unit().Value()) return nil } func (v Voltage) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", v, float64(v)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " V" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(v)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(v)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(v)) default: fmt.Fprintf(fs, "%"+string(c), float64(v)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g V)", c, v, float64(v)) } } golang-gonum-v1-gonum-0.14.0/unit/voltage_test.go000066400000000000000000000027621450372207100216530ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestVoltage(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Voltage err := got.From(Voltage(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Voltage(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Voltage() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestVoltageFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Voltage format string want string }{ {1.23456789, "%v", "1.23456789 V"}, {1.23456789, "%.1v", "1 V"}, {1.23456789, "%20.1v", " 1 V"}, {1.23456789, "%20v", " 1.23456789 V"}, {1.23456789, "%1v", "1.23456789 V"}, {1.23456789, "%#v", "unit.Voltage(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Voltage=1.23456789 V)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/unit/volume.go000066400000000000000000000031551450372207100204570ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit”; 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 unit import ( "errors" "fmt" "math" "unicode/utf8" ) // Volume represents a volume in cubic metres. type Volume float64 const Litre Volume = 1e-3 // Unit converts the Volume to a *Unit. func (v Volume) Unit() *Unit { return New(float64(v), Dimensions{ LengthDim: 3, }) } // Volume allows Volume to implement a Volumeer interface. func (v Volume) Volume() Volume { return v } // From converts the unit into the receiver. From returns an // error if there is a mismatch in dimension. func (v *Volume) From(u Uniter) error { if !DimensionsMatch(u, Litre) { *v = Volume(math.NaN()) return errors.New("unit: dimension mismatch") } *v = Volume(u.Unit().Value()) return nil } func (v Volume) Format(fs fmt.State, c rune) { switch c { case 'v': if fs.Flag('#') { fmt.Fprintf(fs, "%T(%v)", v, float64(v)) return } fallthrough case 'e', 'E', 'f', 'F', 'g', 'G': p, pOk := fs.Precision() w, wOk := fs.Width() const unit = " m^3" switch { case pOk && wOk: fmt.Fprintf(fs, "%*.*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), p, float64(v)) case pOk: fmt.Fprintf(fs, "%.*"+string(c), p, float64(v)) case wOk: fmt.Fprintf(fs, "%*"+string(c), pos(w-utf8.RuneCount([]byte(unit))), float64(v)) default: fmt.Fprintf(fs, "%"+string(c), float64(v)) } fmt.Fprint(fs, unit) default: fmt.Fprintf(fs, "%%!%c(%T=%g m^3)", c, v, float64(v)) } } golang-gonum-v1-gonum-0.14.0/unit/volume_test.go000066400000000000000000000027611450372207100215200ustar00rootroot00000000000000// Code generated by "go generate gonum.org/v1/gonum/unit; DO NOT EDIT. // Copyright ©2019 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 unit import ( "fmt" "testing" ) func TestVolume(t *testing.T) { t.Parallel() for _, value := range []float64{-1, 0, 1} { var got Volume err := got.From(Volume(value).Unit()) if err != nil { t.Errorf("unexpected error for %T conversion: %v", got, err) } if got != Volume(value) { t.Errorf("unexpected result from round trip of %T(%v): got: %v want: %v", got, value, got, value) } if got != got.Volume() { t.Errorf("unexpected result from self interface method call: got: %#v want: %#v", got, value) } err = got.From(ether(1)) if err == nil { t.Errorf("expected error for ether to %T conversion", got) } } } func TestVolumeFormat(t *testing.T) { t.Parallel() for _, test := range []struct { value Volume format string want string }{ {1.23456789, "%v", "1.23456789 m^3"}, {1.23456789, "%.1v", "1 m^3"}, {1.23456789, "%20.1v", " 1 m^3"}, {1.23456789, "%20v", " 1.23456789 m^3"}, {1.23456789, "%1v", "1.23456789 m^3"}, {1.23456789, "%#v", "unit.Volume(1.23456789)"}, {1.23456789, "%s", "%!s(unit.Volume=1.23456789 m^3)"}, } { got := fmt.Sprintf(test.format, test.value) if got != test.want { t.Errorf("Format %q %v: got: %q want: %q", test.format, test.value, got, test.want) } } } golang-gonum-v1-gonum-0.14.0/version.go000066400000000000000000000025571450372207100176630ustar00rootroot00000000000000// Copyright ©2019 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 ( "fmt" "runtime/debug" ) const root = "gonum.org/v1/gonum" // Version returns the version of Gonum and its checksum. The returned // values are only valid in binaries built with module support. // // If a replace directive exists in the Gonum go.mod, the replace will // be reported in the version in the following format: // // "version=>[replace-path] [replace-version]" // // and the replace sum will be returned in place of the original sum. // // The exact version format returned by Version may change in future. func Version() (version, sum string) { b, ok := debug.ReadBuildInfo() if !ok { return "", "" } for _, m := range b.Deps { if m.Path == root { if m.Replace != nil { switch { case m.Replace.Version != "" && m.Replace.Path != "": return fmt.Sprintf("%s=>%s %s", m.Version, m.Replace.Path, m.Replace.Version), m.Replace.Sum case m.Replace.Version != "": return fmt.Sprintf("%s=>%s", m.Version, m.Replace.Version), m.Replace.Sum case m.Replace.Path != "": return fmt.Sprintf("%s=>%s", m.Version, m.Replace.Path), m.Replace.Sum default: return m.Version + "*", m.Sum + "*" } } return m.Version, m.Sum } } return "", "" }